]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/commitdiff
Merge branch 'CVE-2014-7970' of git://git.kernel.org/pub/scm/linux/kernel/git/luto...
authorLinus Torvalds <torvalds@linux-foundation.org>
Wed, 15 Oct 2014 04:43:27 +0000 (06:43 +0200)
committerLinus Torvalds <torvalds@linux-foundation.org>
Wed, 15 Oct 2014 04:43:27 +0000 (06:43 +0200)
Pull pivot_root() fix from Andy Lutomirski.

Prevent a leak of unreachable mounts.

* 'CVE-2014-7970' of git://git.kernel.org/pub/scm/linux/kernel/git/luto/linux:
  mnt: Prevent pivot_root from creating a loop in the mount tree

2881 files changed:
Documentation/00-INDEX
Documentation/ABI/testing/sysfs-bus-event_source-devices-hv_24x7
Documentation/ABI/testing/sysfs-bus-event_source-devices-hv_gpci
Documentation/ABI/testing/sysfs-class-cxl [new file with mode: 0644]
Documentation/DocBook/drm.tmpl
Documentation/DocBook/kernel-locking.tmpl
Documentation/DocBook/media/v4l/compat.xml
Documentation/DocBook/media/v4l/controls.xml
Documentation/DocBook/media/v4l/pixfmt-packed-rgb.xml
Documentation/DocBook/media/v4l/vidioc-dqevent.xml
Documentation/DocBook/media/v4l/vidioc-g-edid.xml
Documentation/DocBook/media/v4l/vidioc-subscribe-event.xml
Documentation/DocBook/writing-an-alsa-driver.tmpl
Documentation/RCU/stallwarn.txt
Documentation/binfmt_misc.txt
Documentation/devicetree/bindings/drm/tilcdc/panel.txt
Documentation/devicetree/bindings/hwmon/ntc_thermistor.txt
Documentation/devicetree/bindings/i2c/ti,bq32k.txt [new file with mode: 0644]
Documentation/devicetree/bindings/i2c/trivial-devices.txt
Documentation/devicetree/bindings/media/hix5hd2-ir.txt [new file with mode: 0644]
Documentation/devicetree/bindings/mmc/mmc.txt
Documentation/devicetree/bindings/mmc/rockchip-dw-mshc.txt
Documentation/devicetree/bindings/mmc/tmio_mmc.txt
Documentation/devicetree/bindings/net/apm-xgene-enet.txt
Documentation/devicetree/bindings/net/micrel.txt
Documentation/devicetree/bindings/panel/auo,b101xtn01.txt [new file with mode: 0644]
Documentation/devicetree/bindings/pci/fsl,pci.txt [new file with mode: 0644]
Documentation/devicetree/bindings/rtc/dallas,ds1339.txt [new file with mode: 0644]
Documentation/devicetree/bindings/rtc/s3c-rtc.txt
Documentation/devicetree/bindings/sound/adi,ssm2602.txt [new file with mode: 0644]
Documentation/devicetree/bindings/sound/cs35l32.txt [new file with mode: 0644]
Documentation/devicetree/bindings/sound/es8328.txt [new file with mode: 0644]
Documentation/devicetree/bindings/sound/fsl,esai.txt
Documentation/devicetree/bindings/sound/fsl,ssi.txt
Documentation/devicetree/bindings/sound/fsl-asoc-card.txt [new file with mode: 0644]
Documentation/devicetree/bindings/sound/fsl-sai.txt
Documentation/devicetree/bindings/sound/imx-audio-es8328.txt [new file with mode: 0644]
Documentation/devicetree/bindings/sound/nvidia,tegra-audio-max98090.txt
Documentation/devicetree/bindings/sound/rt5677.txt [new file with mode: 0644]
Documentation/devicetree/bindings/sound/simple-card.txt
Documentation/devicetree/bindings/sound/ssm4567.txt [new file with mode: 0644]
Documentation/devicetree/bindings/vendor-prefixes.txt
Documentation/devicetree/bindings/video/adi,adv7123.txt [new file with mode: 0644]
Documentation/devicetree/bindings/video/exynos_dsim.txt
Documentation/devicetree/bindings/video/renesas,du.txt [new file with mode: 0644]
Documentation/devicetree/bindings/video/samsung-fimd.txt
Documentation/devicetree/bindings/video/thine,thc63lvdm83d [new file with mode: 0644]
Documentation/devicetree/bindings/video/vga-connector.txt [new file with mode: 0644]
Documentation/devicetree/booting-without-of.txt
Documentation/devicetree/dynamic-resolution-notes.txt [new file with mode: 0644]
Documentation/devicetree/of_selftest.txt
Documentation/dvb/get_dvb_firmware
Documentation/filesystems/Locking
Documentation/filesystems/autofs4.txt [new file with mode: 0644]
Documentation/filesystems/vfs.txt
Documentation/hwmon/k10temp
Documentation/hwmon/menf21bmc [new file with mode: 0644]
Documentation/ioctl/ioctl-number.txt
Documentation/kbuild/makefiles.txt
Documentation/kernel-parameters.txt
Documentation/kprobes.txt
Documentation/lockdep-design.txt [deleted file]
Documentation/locking/lockdep-design.txt [new file with mode: 0644]
Documentation/locking/lockstat.txt [new file with mode: 0644]
Documentation/locking/locktorture.txt [new file with mode: 0644]
Documentation/locking/mutex-design.txt [new file with mode: 0644]
Documentation/locking/rt-mutex-design.txt [new file with mode: 0644]
Documentation/locking/rt-mutex.txt [new file with mode: 0644]
Documentation/locking/spinlocks.txt [new file with mode: 0644]
Documentation/locking/ww-mutex-design.txt [new file with mode: 0644]
Documentation/lockstat.txt [deleted file]
Documentation/memory-barriers.txt
Documentation/mutex-design.txt [deleted file]
Documentation/networking/filter.txt
Documentation/powerpc/00-INDEX
Documentation/powerpc/cxl.txt [new file with mode: 0644]
Documentation/printk-formats.txt
Documentation/rt-mutex-design.txt [deleted file]
Documentation/rt-mutex.txt [deleted file]
Documentation/scheduler/sched-deadline.txt
Documentation/security/keys.txt
Documentation/spinlocks.txt [deleted file]
Documentation/sysctl/kernel.txt
Documentation/video4linux/vivid.txt [new file with mode: 0644]
Documentation/ww-mutex-design.txt [deleted file]
Documentation/x86/x86_64/mm.txt
MAINTAINERS
Makefile
arch/Kconfig
arch/alpha/include/asm/atomic.h
arch/alpha/kernel/osf_sys.c
arch/arc/include/asm/atomic.h
arch/arm/Kconfig
arch/arm/Makefile
arch/arm/boot/dts/exynos3250.dtsi
arch/arm/boot/dts/exynos5420-arndale-octa.dts
arch/arm/include/asm/atomic.h
arch/arm/include/asm/dma-mapping.h
arch/arm/kernel/process.c
arch/arm/kernel/ptrace.c
arch/arm/kernel/topology.c
arch/arm/mach-at91/Makefile
arch/arm/mach-ebsa110/Makefile
arch/arm/mach-ep93xx/Makefile
arch/arm/mach-exynos/Makefile
arch/arm/mach-footbridge/Makefile
arch/arm/mach-iop13xx/Makefile
arch/arm/mach-iop32x/Makefile
arch/arm/mach-iop33x/Makefile
arch/arm/mach-ks8695/Makefile
arch/arm/mach-pxa/lpd270.c
arch/arm/mach-rpc/Makefile
arch/arm/mach-s3c24xx/Makefile
arch/arm/mach-s3c64xx/Makefile
arch/arm/mach-s5pv210/Makefile
arch/arm/mach-sa1100/Makefile
arch/arm/mach-shmobile/board-koelsch-reference.c
arch/arm/mach-shmobile/board-koelsch.c
arch/arm/mach-shmobile/board-lager-reference.c
arch/arm/mach-shmobile/board-lager.c
arch/arm/mach-shmobile/board-marzen.c
arch/arm/mach-u300/Makefile
arch/arm/plat-iop/Makefile
arch/arm/plat-omap/Makefile
arch/arm/plat-samsung/Makefile
arch/arm64/Kconfig
arch/arm64/Makefile
arch/arm64/boot/dts/apm-mustang.dts
arch/arm64/boot/dts/apm-storm.dtsi
arch/arm64/include/asm/atomic.h
arch/arm64/kernel/process.c
arch/avr32/include/asm/atomic.h
arch/cris/arch-v10/drivers/sync_serial.c
arch/cris/arch-v32/drivers/sync_serial.c
arch/cris/include/asm/atomic.h
arch/frv/include/asm/atomic.h
arch/frv/mm/extable.c
arch/hexagon/include/asm/atomic.h
arch/ia64/include/asm/atomic.h
arch/ia64/include/asm/processor.h
arch/ia64/include/asm/sections.h
arch/ia64/include/asm/unistd.h
arch/ia64/include/uapi/asm/unistd.h
arch/ia64/kernel/entry.S
arch/m32r/include/asm/atomic.h
arch/m68k/68000/Makefile [new file with mode: 0644]
arch/m68k/68000/bootlogo-vz.h [new file with mode: 0644]
arch/m68k/68000/bootlogo.h [new file with mode: 0644]
arch/m68k/68000/entry.S [new file with mode: 0644]
arch/m68k/68000/head.S [new file with mode: 0644]
arch/m68k/68000/ints.c [new file with mode: 0644]
arch/m68k/68000/m68328.c [new file with mode: 0644]
arch/m68k/68000/m68EZ328.c [new file with mode: 0644]
arch/m68k/68000/m68VZ328.c [new file with mode: 0644]
arch/m68k/68000/romvec.S [new file with mode: 0644]
arch/m68k/68000/timers.c [new file with mode: 0644]
arch/m68k/68360/Makefile [new file with mode: 0644]
arch/m68k/68360/commproc.c [new file with mode: 0644]
arch/m68k/68360/config.c [new file with mode: 0644]
arch/m68k/68360/entry.S [new file with mode: 0644]
arch/m68k/68360/head-ram.S [new file with mode: 0644]
arch/m68k/68360/head-rom.S [new file with mode: 0644]
arch/m68k/68360/ints.c [new file with mode: 0644]
arch/m68k/Makefile
arch/m68k/coldfire/Makefile [new file with mode: 0644]
arch/m68k/coldfire/cache.c [new file with mode: 0644]
arch/m68k/coldfire/clk.c [new file with mode: 0644]
arch/m68k/coldfire/device.c [new file with mode: 0644]
arch/m68k/coldfire/dma.c [new file with mode: 0644]
arch/m68k/coldfire/dma_timer.c [new file with mode: 0644]
arch/m68k/coldfire/entry.S [new file with mode: 0644]
arch/m68k/coldfire/firebee.c [new file with mode: 0644]
arch/m68k/coldfire/gpio.c [new file with mode: 0644]
arch/m68k/coldfire/head.S [new file with mode: 0644]
arch/m68k/coldfire/intc-2.c [new file with mode: 0644]
arch/m68k/coldfire/intc-5249.c [new file with mode: 0644]
arch/m68k/coldfire/intc-525x.c [new file with mode: 0644]
arch/m68k/coldfire/intc-5272.c [new file with mode: 0644]
arch/m68k/coldfire/intc-simr.c [new file with mode: 0644]
arch/m68k/coldfire/intc.c [new file with mode: 0644]
arch/m68k/coldfire/m5206.c [new file with mode: 0644]
arch/m68k/coldfire/m520x.c [new file with mode: 0644]
arch/m68k/coldfire/m523x.c [new file with mode: 0644]
arch/m68k/coldfire/m5249.c [new file with mode: 0644]
arch/m68k/coldfire/m525x.c [new file with mode: 0644]
arch/m68k/coldfire/m5272.c [new file with mode: 0644]
arch/m68k/coldfire/m527x.c [new file with mode: 0644]
arch/m68k/coldfire/m528x.c [new file with mode: 0644]
arch/m68k/coldfire/m5307.c [new file with mode: 0644]
arch/m68k/coldfire/m53xx.c [new file with mode: 0644]
arch/m68k/coldfire/m5407.c [new file with mode: 0644]
arch/m68k/coldfire/m5441x.c [new file with mode: 0644]
arch/m68k/coldfire/m54xx.c [new file with mode: 0644]
arch/m68k/coldfire/mcf8390.c [new file with mode: 0644]
arch/m68k/coldfire/nettel.c [new file with mode: 0644]
arch/m68k/coldfire/pci.c [new file with mode: 0644]
arch/m68k/coldfire/pit.c [new file with mode: 0644]
arch/m68k/coldfire/reset.c [new file with mode: 0644]
arch/m68k/coldfire/sltimers.c [new file with mode: 0644]
arch/m68k/coldfire/timers.c [new file with mode: 0644]
arch/m68k/coldfire/vectors.c [new file with mode: 0644]
arch/m68k/include/asm/atomic.h
arch/m68k/include/asm/io_no.h
arch/m68k/include/asm/m54xxpci.h
arch/m68k/platform/68000/Makefile [deleted file]
arch/m68k/platform/68000/bootlogo-vz.h [deleted file]
arch/m68k/platform/68000/bootlogo.h [deleted file]
arch/m68k/platform/68000/entry.S [deleted file]
arch/m68k/platform/68000/head.S [deleted file]
arch/m68k/platform/68000/ints.c [deleted file]
arch/m68k/platform/68000/m68328.c [deleted file]
arch/m68k/platform/68000/m68EZ328.c [deleted file]
arch/m68k/platform/68000/m68VZ328.c [deleted file]
arch/m68k/platform/68000/romvec.S [deleted file]
arch/m68k/platform/68000/timers.c [deleted file]
arch/m68k/platform/68360/Makefile [deleted file]
arch/m68k/platform/68360/commproc.c [deleted file]
arch/m68k/platform/68360/config.c [deleted file]
arch/m68k/platform/68360/entry.S [deleted file]
arch/m68k/platform/68360/head-ram.S [deleted file]
arch/m68k/platform/68360/head-rom.S [deleted file]
arch/m68k/platform/68360/ints.c [deleted file]
arch/m68k/platform/Makefile [deleted file]
arch/m68k/platform/coldfire/Makefile [deleted file]
arch/m68k/platform/coldfire/cache.c [deleted file]
arch/m68k/platform/coldfire/clk.c [deleted file]
arch/m68k/platform/coldfire/device.c [deleted file]
arch/m68k/platform/coldfire/dma.c [deleted file]
arch/m68k/platform/coldfire/dma_timer.c [deleted file]
arch/m68k/platform/coldfire/entry.S [deleted file]
arch/m68k/platform/coldfire/firebee.c [deleted file]
arch/m68k/platform/coldfire/gpio.c [deleted file]
arch/m68k/platform/coldfire/head.S [deleted file]
arch/m68k/platform/coldfire/intc-2.c [deleted file]
arch/m68k/platform/coldfire/intc-5249.c [deleted file]
arch/m68k/platform/coldfire/intc-525x.c [deleted file]
arch/m68k/platform/coldfire/intc-5272.c [deleted file]
arch/m68k/platform/coldfire/intc-simr.c [deleted file]
arch/m68k/platform/coldfire/intc.c [deleted file]
arch/m68k/platform/coldfire/m5206.c [deleted file]
arch/m68k/platform/coldfire/m520x.c [deleted file]
arch/m68k/platform/coldfire/m523x.c [deleted file]
arch/m68k/platform/coldfire/m5249.c [deleted file]
arch/m68k/platform/coldfire/m525x.c [deleted file]
arch/m68k/platform/coldfire/m5272.c [deleted file]
arch/m68k/platform/coldfire/m527x.c [deleted file]
arch/m68k/platform/coldfire/m528x.c [deleted file]
arch/m68k/platform/coldfire/m5307.c [deleted file]
arch/m68k/platform/coldfire/m53xx.c [deleted file]
arch/m68k/platform/coldfire/m5407.c [deleted file]
arch/m68k/platform/coldfire/m5441x.c [deleted file]
arch/m68k/platform/coldfire/m54xx.c [deleted file]
arch/m68k/platform/coldfire/mcf8390.c [deleted file]
arch/m68k/platform/coldfire/nettel.c [deleted file]
arch/m68k/platform/coldfire/pci.c [deleted file]
arch/m68k/platform/coldfire/pit.c [deleted file]
arch/m68k/platform/coldfire/reset.c [deleted file]
arch/m68k/platform/coldfire/sltimers.c [deleted file]
arch/m68k/platform/coldfire/timers.c [deleted file]
arch/m68k/platform/coldfire/vectors.c [deleted file]
arch/metag/include/asm/atomic_lnkget.h
arch/metag/include/asm/atomic_lock1.h
arch/mips/include/asm/atomic.h
arch/mips/include/asm/processor.h
arch/mips/kernel/ptrace.c
arch/mn10300/include/asm/atomic.h
arch/parisc/include/asm/atomic.h
arch/parisc/include/uapi/asm/signal.h
arch/powerpc/Kconfig
arch/powerpc/Makefile
arch/powerpc/boot/Makefile
arch/powerpc/boot/dts/fsl/t2081si-post.dtsi
arch/powerpc/boot/dts/fsl/t4240si-post.dtsi
arch/powerpc/boot/dts/t1040rdb.dts [new file with mode: 0644]
arch/powerpc/boot/dts/t1042rdb.dts [new file with mode: 0644]
arch/powerpc/boot/dts/t1042rdb_pi.dts [new file with mode: 0644]
arch/powerpc/boot/dts/t104xrdb.dtsi [new file with mode: 0644]
arch/powerpc/configs/cell_defconfig
arch/powerpc/configs/celleb_defconfig
arch/powerpc/configs/corenet32_smp_defconfig
arch/powerpc/configs/corenet64_smp_defconfig
arch/powerpc/configs/g5_defconfig
arch/powerpc/configs/maple_defconfig
arch/powerpc/configs/mpc85xx_defconfig
arch/powerpc/configs/mpc85xx_smp_defconfig
arch/powerpc/configs/mpc86xx_defconfig
arch/powerpc/configs/pasemi_defconfig
arch/powerpc/configs/ppc64_defconfig
arch/powerpc/include/asm/atomic.h
arch/powerpc/include/asm/bug.h
arch/powerpc/include/asm/copro.h [new file with mode: 0644]
arch/powerpc/include/asm/cputime.h
arch/powerpc/include/asm/dma-mapping.h
arch/powerpc/include/asm/eeh.h
arch/powerpc/include/asm/hydra.h
arch/powerpc/include/asm/irq.h
arch/powerpc/include/asm/kexec.h
arch/powerpc/include/asm/machdep.h
arch/powerpc/include/asm/mmu-hash64.h
arch/powerpc/include/asm/opal.h
arch/powerpc/include/asm/page_64.h
arch/powerpc/include/asm/pgtable-ppc32.h
arch/powerpc/include/asm/pgtable-ppc64-4k.h
arch/powerpc/include/asm/pgtable-ppc64.h
arch/powerpc/include/asm/pgtable.h
arch/powerpc/include/asm/plpar_wrappers.h
arch/powerpc/include/asm/pnv-pci.h [new file with mode: 0644]
arch/powerpc/include/asm/prom.h
arch/powerpc/include/asm/reg.h
arch/powerpc/include/asm/rio.h
arch/powerpc/include/asm/spu.h
arch/powerpc/include/asm/sstep.h
arch/powerpc/include/asm/tsi108.h
arch/powerpc/include/asm/udbg.h
arch/powerpc/include/asm/word-at-a-time.h
arch/powerpc/include/asm/xics.h
arch/powerpc/kernel/Makefile
arch/powerpc/kernel/crash_dump.c
arch/powerpc/kernel/dma-swiotlb.c
arch/powerpc/kernel/dma.c
arch/powerpc/kernel/eeh.c
arch/powerpc/kernel/eeh_driver.c
arch/powerpc/kernel/eeh_pe.c
arch/powerpc/kernel/eeh_sysfs.c
arch/powerpc/kernel/head_8xx.S
arch/powerpc/kernel/hw_breakpoint.c
arch/powerpc/kernel/ibmebus.c
arch/powerpc/kernel/idle_power7.S
arch/powerpc/kernel/irq.c
arch/powerpc/kernel/legacy_serial.c
arch/powerpc/kernel/module_32.c
arch/powerpc/kernel/module_64.c
arch/powerpc/kernel/nvram_64.c
arch/powerpc/kernel/of_platform.c
arch/powerpc/kernel/pci-common.c
arch/powerpc/kernel/pci_of_scan.c
arch/powerpc/kernel/ppc_ksyms.c
arch/powerpc/kernel/ppc_ksyms_32.c [new file with mode: 0644]
arch/powerpc/kernel/process.c
arch/powerpc/kernel/prom.c
arch/powerpc/kernel/prom_init_check.sh
arch/powerpc/kernel/ptrace.c
arch/powerpc/kernel/rtasd.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/lib/Makefile
arch/powerpc/lib/feature-fixups.c
arch/powerpc/lib/ppc_ksyms.c [new file with mode: 0644]
arch/powerpc/lib/sstep.c
arch/powerpc/mm/Makefile
arch/powerpc/mm/copro_fault.c [new file with mode: 0644]
arch/powerpc/mm/fault.c
arch/powerpc/mm/hash_native_64.c
arch/powerpc/mm/hash_utils_64.c
arch/powerpc/mm/init_32.c
arch/powerpc/mm/init_64.c
arch/powerpc/mm/mem.c
arch/powerpc/mm/numa.c
arch/powerpc/mm/pgtable.c
arch/powerpc/mm/slb.c
arch/powerpc/mm/slice.c
arch/powerpc/oprofile/backtrace.c
arch/powerpc/perf/core-book3s.c
arch/powerpc/perf/hv-24x7.c
arch/powerpc/platforms/40x/ep405.c
arch/powerpc/platforms/40x/ppc40x_simple.c
arch/powerpc/platforms/40x/virtex.c
arch/powerpc/platforms/40x/walnut.c
arch/powerpc/platforms/44x/Kconfig
arch/powerpc/platforms/44x/canyonlands.c
arch/powerpc/platforms/44x/ebony.c
arch/powerpc/platforms/44x/iss4xx.c
arch/powerpc/platforms/44x/ppc44x_simple.c
arch/powerpc/platforms/44x/ppc476.c
arch/powerpc/platforms/44x/sam440ep.c
arch/powerpc/platforms/44x/virtex.c
arch/powerpc/platforms/44x/warp.c
arch/powerpc/platforms/512x/mpc512x_shared.c
arch/powerpc/platforms/52xx/lite5200.c
arch/powerpc/platforms/52xx/media5200.c
arch/powerpc/platforms/52xx/mpc52xx_common.c
arch/powerpc/platforms/52xx/mpc52xx_lpbfifo.c
arch/powerpc/platforms/52xx/mpc52xx_pic.c
arch/powerpc/platforms/82xx/ep8248e.c
arch/powerpc/platforms/82xx/km82xx.c
arch/powerpc/platforms/82xx/mpc8272_ads.c
arch/powerpc/platforms/82xx/pq2fads.c
arch/powerpc/platforms/83xx/mcu_mpc8349emitx.c
arch/powerpc/platforms/83xx/misc.c
arch/powerpc/platforms/83xx/mpc834x_itx.c
arch/powerpc/platforms/83xx/suspend.c
arch/powerpc/platforms/85xx/Kconfig
arch/powerpc/platforms/85xx/common.c
arch/powerpc/platforms/85xx/corenet_generic.c
arch/powerpc/platforms/85xx/ppa8548.c
arch/powerpc/platforms/85xx/qemu_e500.c
arch/powerpc/platforms/85xx/sgy_cts1000.c
arch/powerpc/platforms/86xx/gef_ppc9a.c
arch/powerpc/platforms/86xx/gef_sbc310.c
arch/powerpc/platforms/86xx/gef_sbc610.c
arch/powerpc/platforms/86xx/mpc8610_hpcd.c
arch/powerpc/platforms/86xx/mpc86xx_hpcn.c
arch/powerpc/platforms/86xx/sbc8641d.c
arch/powerpc/platforms/8xx/adder875.c
arch/powerpc/platforms/8xx/ep88xc.c
arch/powerpc/platforms/8xx/mpc86xads_setup.c
arch/powerpc/platforms/8xx/mpc885ads_setup.c
arch/powerpc/platforms/8xx/tqm8xx_setup.c
arch/powerpc/platforms/Kconfig.cputype
arch/powerpc/platforms/cell/Kconfig
arch/powerpc/platforms/cell/Makefile
arch/powerpc/platforms/cell/celleb_pci.c
arch/powerpc/platforms/cell/celleb_setup.c
arch/powerpc/platforms/cell/spu_base.c
arch/powerpc/platforms/cell/spu_fault.c [deleted file]
arch/powerpc/platforms/cell/spufs/fault.c
arch/powerpc/platforms/chrp/setup.c
arch/powerpc/platforms/embedded6xx/gamecube.c
arch/powerpc/platforms/embedded6xx/linkstation.c
arch/powerpc/platforms/embedded6xx/mvme5100.c
arch/powerpc/platforms/embedded6xx/storcenter.c
arch/powerpc/platforms/embedded6xx/wii.c
arch/powerpc/platforms/pasemi/gpio_mdio.c
arch/powerpc/platforms/pasemi/setup.c
arch/powerpc/platforms/powermac/setup.c
arch/powerpc/platforms/powernv/eeh-ioda.c
arch/powerpc/platforms/powernv/eeh-powernv.c
arch/powerpc/platforms/powernv/opal-dump.c
arch/powerpc/platforms/powernv/opal-elog.c
arch/powerpc/platforms/powernv/opal-lpc.c
arch/powerpc/platforms/powernv/opal-nvram.c
arch/powerpc/platforms/powernv/opal-rtc.c
arch/powerpc/platforms/powernv/opal-tracepoints.c
arch/powerpc/platforms/powernv/opal-wrappers.S
arch/powerpc/platforms/powernv/opal.c
arch/powerpc/platforms/powernv/pci-ioda.c
arch/powerpc/platforms/powernv/pci.c
arch/powerpc/platforms/powernv/pci.h
arch/powerpc/platforms/powernv/powernv.h
arch/powerpc/platforms/powernv/setup.c
arch/powerpc/platforms/powernv/smp.c
arch/powerpc/platforms/powernv/subcore.c
arch/powerpc/platforms/pseries/cmm.c
arch/powerpc/platforms/pseries/dlpar.c
arch/powerpc/platforms/pseries/eeh_pseries.c
arch/powerpc/platforms/pseries/hotplug-cpu.c
arch/powerpc/platforms/pseries/hotplug-memory.c
arch/powerpc/platforms/pseries/iommu.c
arch/powerpc/platforms/pseries/lpar.c
arch/powerpc/platforms/pseries/nvram.c
arch/powerpc/platforms/pseries/pci.c
arch/powerpc/platforms/pseries/ras.c
arch/powerpc/platforms/pseries/setup.c
arch/powerpc/sysdev/axonram.c
arch/powerpc/sysdev/dcr.c
arch/powerpc/sysdev/fsl_85xx_l2ctlr.c
arch/powerpc/sysdev/fsl_msi.c
arch/powerpc/sysdev/fsl_msi.h
arch/powerpc/sysdev/fsl_pci.c
arch/powerpc/sysdev/mpic.c
arch/powerpc/sysdev/msi_bitmap.c
arch/powerpc/sysdev/mv64x60_dev.c
arch/powerpc/sysdev/pmi.c
arch/powerpc/sysdev/xics/icp-native.c
arch/powerpc/sysdev/xilinx_intc.c
arch/powerpc/sysdev/xilinx_pci.c
arch/s390/Kconfig
arch/s390/Makefile
arch/s390/include/asm/barrier.h
arch/s390/include/asm/cputime.h
arch/s390/include/asm/dis.h
arch/s390/include/asm/dma-mapping.h
arch/s390/include/asm/elf.h
arch/s390/include/asm/ftrace.h
arch/s390/include/asm/idle.h [new file with mode: 0644]
arch/s390/include/asm/ipl.h
arch/s390/include/asm/irq.h
arch/s390/include/asm/kprobes.h
arch/s390/include/asm/lowcore.h
arch/s390/include/asm/nmi.h
arch/s390/include/asm/pgtable.h
arch/s390/include/asm/processor.h
arch/s390/include/asm/ptrace.h
arch/s390/include/asm/setup.h
arch/s390/include/asm/sigp.h
arch/s390/include/asm/smp.h
arch/s390/include/asm/spinlock.h
arch/s390/include/asm/spinlock_types.h
arch/s390/include/asm/switch_to.h
arch/s390/include/asm/thread_info.h
arch/s390/include/asm/uprobes.h [new file with mode: 0644]
arch/s390/include/asm/vdso.h
arch/s390/include/asm/vtimer.h
arch/s390/include/uapi/asm/sigcontext.h
arch/s390/include/uapi/asm/types.h
arch/s390/include/uapi/asm/ucontext.h
arch/s390/kernel/Makefile
arch/s390/kernel/asm-offsets.c
arch/s390/kernel/compat_linux.h
arch/s390/kernel/compat_signal.c
arch/s390/kernel/crash_dump.c
arch/s390/kernel/dis.c
arch/s390/kernel/early.c
arch/s390/kernel/entry.h
arch/s390/kernel/entry64.S
arch/s390/kernel/ftrace.c
arch/s390/kernel/head.S
arch/s390/kernel/idle.c [new file with mode: 0644]
arch/s390/kernel/irq.c
arch/s390/kernel/kprobes.c
arch/s390/kernel/machine_kexec.c
arch/s390/kernel/mcount.S
arch/s390/kernel/mcount64.S [deleted file]
arch/s390/kernel/nmi.c
arch/s390/kernel/pgm_check.S
arch/s390/kernel/process.c
arch/s390/kernel/processor.c
arch/s390/kernel/ptrace.c
arch/s390/kernel/setup.c
arch/s390/kernel/signal.c
arch/s390/kernel/smp.c
arch/s390/kernel/time.c
arch/s390/kernel/topology.c
arch/s390/kernel/traps.c
arch/s390/kernel/uprobes.c [new file with mode: 0644]
arch/s390/kernel/vdso32/clock_getres.S
arch/s390/kernel/vdso32/clock_gettime.S
arch/s390/kernel/vdso32/gettimeofday.S
arch/s390/kernel/vdso64/clock_getres.S
arch/s390/kernel/vdso64/clock_gettime.S
arch/s390/kernel/vdso64/gettimeofday.S
arch/s390/kernel/vtime.c
arch/s390/lib/Makefile
arch/s390/lib/delay.c
arch/s390/lib/probes.c [new file with mode: 0644]
arch/s390/lib/spinlock.c
arch/s390/mm/dump_pagetables.c
arch/s390/mm/hugetlbpage.c
arch/s390/mm/pageattr.c
arch/s390/mm/vmem.c
arch/sh/include/asm/atomic-grb.h
arch/sh/include/asm/atomic-irq.h
arch/sh/include/asm/atomic-llsc.h
arch/sh/include/asm/atomic.h
arch/sparc/Kconfig
arch/sparc/include/asm/atomic_32.h
arch/sparc/include/asm/atomic_64.h
arch/sparc/include/asm/dma-mapping.h
arch/sparc/include/asm/hypervisor.h
arch/sparc/include/asm/irq_64.h
arch/sparc/include/asm/ldc.h
arch/sparc/include/asm/page_64.h
arch/sparc/include/asm/pgalloc_64.h
arch/sparc/include/asm/pgtable_64.h
arch/sparc/include/asm/spitfire.h
arch/sparc/include/asm/thread_info_64.h
arch/sparc/include/asm/tsb.h
arch/sparc/include/asm/vio.h
arch/sparc/kernel/cpu.c
arch/sparc/kernel/cpumap.c
arch/sparc/kernel/ds.c
arch/sparc/kernel/head_64.S
arch/sparc/kernel/hvapi.c
arch/sparc/kernel/hvcalls.S
arch/sparc/kernel/ioport.c
arch/sparc/kernel/irq_64.c
arch/sparc/kernel/ktlb.S
arch/sparc/kernel/ldc.c
arch/sparc/kernel/leon_kernel.c
arch/sparc/kernel/pcr.c
arch/sparc/kernel/perf_event.c
arch/sparc/kernel/setup_64.c
arch/sparc/kernel/smp_64.c
arch/sparc/kernel/sun4v_tlb_miss.S
arch/sparc/kernel/traps_64.c
arch/sparc/kernel/vio.c
arch/sparc/kernel/viohs.c
arch/sparc/kernel/vmlinux.lds.S
arch/sparc/lib/atomic32.c
arch/sparc/lib/atomic_64.S
arch/sparc/lib/ksyms.c
arch/sparc/lib/memset.S
arch/sparc/mm/fault_64.c
arch/sparc/mm/init_64.c
arch/sparc/mm/init_64.h
arch/sparc/power/hibernate_asm.S
arch/sparc/prom/bootstr_64.c
arch/sparc/prom/p1275.c
arch/um/Kconfig.common
arch/um/drivers/net_kern.c
arch/um/drivers/random.c
arch/um/drivers/ubd_kern.c
arch/um/include/asm/stacktrace.h [new file with mode: 0644]
arch/um/include/shared/mem_user.h
arch/um/kernel/Makefile
arch/um/kernel/physmem.c
arch/um/kernel/stacktrace.c [new file with mode: 0644]
arch/um/kernel/sysrq.c
arch/um/kernel/um_arch.c
arch/x86/.gitignore
arch/x86/Kconfig
arch/x86/Makefile
arch/x86/boot/compressed/aslr.c
arch/x86/boot/mkcpustr.c
arch/x86/ia32/ia32_aout.c
arch/x86/ia32/ia32entry.S
arch/x86/include/asm/atomic.h
arch/x86/include/asm/atomic64_64.h
arch/x86/include/asm/calling.h
arch/x86/include/asm/cpufeature.h
arch/x86/include/asm/disabled-features.h [new file with mode: 0644]
arch/x86/include/asm/elf.h
arch/x86/include/asm/fpu-internal.h
arch/x86/include/asm/microcode_intel.h
arch/x86/include/asm/numa.h
arch/x86/include/asm/perf_event.h
arch/x86/include/asm/pgtable_32.h
arch/x86/include/asm/pgtable_64.h
arch/x86/include/asm/pgtable_types.h
arch/x86/include/asm/ptrace.h
arch/x86/include/asm/rwlock.h [deleted file]
arch/x86/include/asm/serial.h
arch/x86/include/asm/spinlock.h
arch/x86/include/asm/spinlock_types.h
arch/x86/include/uapi/asm/e820.h
arch/x86/kernel/Makefile
arch/x86/kernel/apic/apic_numachip.c
arch/x86/kernel/apic/x2apic_uv_x.c
arch/x86/kernel/cpu/Makefile
arch/x86/kernel/cpu/common.c
arch/x86/kernel/cpu/intel.c
arch/x86/kernel/cpu/mcheck/therm_throt.c
arch/x86/kernel/cpu/microcode/amd_early.c
arch/x86/kernel/cpu/microcode/intel.c
arch/x86/kernel/cpu/microcode/intel_early.c
arch/x86/kernel/cpu/mtrr/main.c
arch/x86/kernel/cpu/perf_event.c
arch/x86/kernel/cpu/perf_event.h
arch/x86/kernel/cpu/perf_event_intel.c
arch/x86/kernel/cpu/perf_event_intel_ds.c
arch/x86/kernel/cpu/perf_event_intel_lbr.c
arch/x86/kernel/cpu/perf_event_intel_uncore.c
arch/x86/kernel/cpu/perf_event_intel_uncore.h
arch/x86/kernel/cpu/perf_event_intel_uncore_nhmex.c [new file with mode: 0644]
arch/x86/kernel/cpu/perf_event_intel_uncore_snb.c [new file with mode: 0644]
arch/x86/kernel/cpu/perf_event_intel_uncore_snbep.c [new file with mode: 0644]
arch/x86/kernel/crash.c
arch/x86/kernel/e820.c
arch/x86/kernel/entry_64.S
arch/x86/kernel/iosf_mbi.c
arch/x86/kernel/kexec-bzimage64.c
arch/x86/kernel/kvm.c
arch/x86/kernel/machine_kexec_32.c
arch/x86/kernel/pmc_atom.c
arch/x86/kernel/preempt.S [deleted file]
arch/x86/kernel/process.c
arch/x86/kernel/process_32.c
arch/x86/kernel/process_64.c
arch/x86/kernel/ptrace.c
arch/x86/kernel/quirks.c
arch/x86/kernel/setup.c
arch/x86/kernel/signal.c
arch/x86/kernel/smpboot.c
arch/x86/kernel/vsyscall_64.c
arch/x86/kernel/xsave.c
arch/x86/lib/Makefile
arch/x86/lib/cmpxchg16b_emu.S
arch/x86/lib/cmpxchg8b_emu.S
arch/x86/lib/rwlock.S [deleted file]
arch/x86/lib/thunk_32.S
arch/x86/lib/thunk_64.S
arch/x86/mm/fault.c
arch/x86/mm/init_32.c
arch/x86/mm/init_64.c
arch/x86/mm/ioremap.c
arch/x86/mm/numa.c
arch/x86/mm/pgtable_32.c
arch/x86/pci/i386.c
arch/x86/purgatory/Makefile
arch/x86/tools/relocs.c
arch/x86/um/checksum_32.S
arch/x86/vdso/vdso2c.h
arch/x86/xen/efi.c
arch/x86/xen/enlighten.c
arch/x86/xen/mmu.c
arch/x86/xen/p2m.c
arch/x86/xen/p2m.h [new file with mode: 0644]
arch/x86/xen/setup.c
arch/x86/xen/smp.c
arch/x86/xen/smp.h
arch/x86/xen/xen-head.S
arch/xtensa/include/asm/atomic.h
crypto/asymmetric_keys/asymmetric_keys.h
crypto/asymmetric_keys/asymmetric_type.c
crypto/asymmetric_keys/pkcs7_key_type.c
crypto/asymmetric_keys/pkcs7_parser.c
crypto/asymmetric_keys/pkcs7_parser.h
crypto/asymmetric_keys/pkcs7_trust.c
crypto/asymmetric_keys/pkcs7_verify.c
crypto/asymmetric_keys/signature.c
crypto/asymmetric_keys/x509_cert_parser.c
crypto/asymmetric_keys/x509_parser.h
crypto/asymmetric_keys/x509_public_key.c
drivers/base/dma-coherent.c
drivers/base/dma-contiguous.c
drivers/block/rsxx/core.c
drivers/block/sunvdc.c
drivers/block/xen-blkback/xenbus.c
drivers/block/xen-blkfront.c
drivers/bluetooth/hci_vhci.c
drivers/char/mem.c
drivers/char/tpm/xen-tpmfront.c
drivers/clk/Kconfig
drivers/clk/Makefile
drivers/clk/clk-rk808.c [new file with mode: 0644]
drivers/clk/shmobile/Makefile
drivers/cpufreq/pmac32-cpufreq.c
drivers/cpuidle/cpuidle.c
drivers/dma-buf/dma-buf.c
drivers/edac/sb_edac.c
drivers/gpu/drm/Kconfig
drivers/gpu/drm/Makefile
drivers/gpu/drm/armada/armada_drv.c
drivers/gpu/drm/armada/armada_gem.h
drivers/gpu/drm/ast/ast_dp501.c
drivers/gpu/drm/ast/ast_drv.c
drivers/gpu/drm/ast/ast_drv.h
drivers/gpu/drm/ast/ast_fb.c
drivers/gpu/drm/ast/ast_main.c
drivers/gpu/drm/ast/ast_mode.c
drivers/gpu/drm/ast/ast_post.c
drivers/gpu/drm/ast/ast_tables.h
drivers/gpu/drm/ast/ast_ttm.c
drivers/gpu/drm/ati_pcigart.c
drivers/gpu/drm/bochs/bochs.h
drivers/gpu/drm/bochs/bochs_drv.c
drivers/gpu/drm/bochs/bochs_mm.c
drivers/gpu/drm/cirrus/cirrus_drv.c
drivers/gpu/drm/cirrus/cirrus_drv.h
drivers/gpu/drm/cirrus/cirrus_fbdev.c
drivers/gpu/drm/cirrus/cirrus_ttm.c
drivers/gpu/drm/drm_agpsupport.c
drivers/gpu/drm/drm_auth.c
drivers/gpu/drm/drm_buffer.c [deleted file]
drivers/gpu/drm/drm_bufs.c
drivers/gpu/drm/drm_crtc.c
drivers/gpu/drm/drm_debugfs.c
drivers/gpu/drm/drm_dma.c
drivers/gpu/drm/drm_dp_mst_topology.c
drivers/gpu/drm/drm_drv.c
drivers/gpu/drm/drm_edid.c
drivers/gpu/drm/drm_fb_helper.c
drivers/gpu/drm/drm_fops.c
drivers/gpu/drm/drm_gem.c
drivers/gpu/drm/drm_gem_cma_helper.c
drivers/gpu/drm/drm_info.c
drivers/gpu/drm/drm_internal.h [new file with mode: 0644]
drivers/gpu/drm/drm_ioctl.c
drivers/gpu/drm/drm_irq.c
drivers/gpu/drm/drm_legacy.h
drivers/gpu/drm/drm_lock.c
drivers/gpu/drm/drm_memory.c
drivers/gpu/drm/drm_mipi_dsi.c
drivers/gpu/drm/drm_modes.c
drivers/gpu/drm/drm_modeset_lock.c
drivers/gpu/drm/drm_pci.c
drivers/gpu/drm/drm_platform.c
drivers/gpu/drm/drm_prime.c
drivers/gpu/drm/drm_probe_helper.c
drivers/gpu/drm/drm_scatter.c
drivers/gpu/drm/drm_sysfs.c
drivers/gpu/drm/drm_usb.c [deleted file]
drivers/gpu/drm/drm_vm.c
drivers/gpu/drm/exynos/exynos_dp_core.c
drivers/gpu/drm/exynos/exynos_drm_crtc.c
drivers/gpu/drm/exynos/exynos_drm_dpi.c
drivers/gpu/drm/exynos/exynos_drm_drv.c
drivers/gpu/drm/exynos/exynos_drm_drv.h
drivers/gpu/drm/exynos/exynos_drm_dsi.c
drivers/gpu/drm/exynos/exynos_drm_fb.c
drivers/gpu/drm/exynos/exynos_drm_fbdev.c
drivers/gpu/drm/exynos/exynos_drm_fimc.c
drivers/gpu/drm/exynos/exynos_drm_fimd.c
drivers/gpu/drm/exynos/exynos_drm_gem.c
drivers/gpu/drm/exynos/exynos_drm_gem.h
drivers/gpu/drm/exynos/exynos_drm_gsc.c
drivers/gpu/drm/exynos/exynos_drm_ipp.c
drivers/gpu/drm/exynos/exynos_drm_ipp.h
drivers/gpu/drm/exynos/exynos_drm_plane.c
drivers/gpu/drm/exynos/exynos_drm_plane.h
drivers/gpu/drm/exynos/exynos_drm_rotator.c
drivers/gpu/drm/exynos/exynos_drm_vidi.c
drivers/gpu/drm/exynos/exynos_hdmi.c
drivers/gpu/drm/exynos/exynos_mixer.c
drivers/gpu/drm/gma500/cdv_intel_dp.c
drivers/gpu/drm/gma500/framebuffer.c
drivers/gpu/drm/gma500/gtt.h
drivers/gpu/drm/gma500/intel_bios.c
drivers/gpu/drm/gma500/psb_drv.c
drivers/gpu/drm/i810/i810_dma.c
drivers/gpu/drm/i810/i810_drv.c
drivers/gpu/drm/i810/i810_drv.h
drivers/gpu/drm/i915/Makefile
drivers/gpu/drm/i915/dvo_ns2501.c
drivers/gpu/drm/i915/i915_cmd_parser.c
drivers/gpu/drm/i915/i915_debugfs.c
drivers/gpu/drm/i915/i915_dma.c
drivers/gpu/drm/i915/i915_drv.c
drivers/gpu/drm/i915/i915_drv.h
drivers/gpu/drm/i915/i915_gem.c
drivers/gpu/drm/i915/i915_gem_context.c
drivers/gpu/drm/i915/i915_gem_evict.c
drivers/gpu/drm/i915/i915_gem_execbuffer.c
drivers/gpu/drm/i915/i915_gem_gtt.c
drivers/gpu/drm/i915/i915_gem_gtt.h
drivers/gpu/drm/i915/i915_gem_render_state.c
drivers/gpu/drm/i915/i915_gem_render_state.h [new file with mode: 0644]
drivers/gpu/drm/i915/i915_gem_stolen.c
drivers/gpu/drm/i915/i915_gem_tiling.c
drivers/gpu/drm/i915/i915_gem_userptr.c
drivers/gpu/drm/i915/i915_gpu_error.c
drivers/gpu/drm/i915/i915_irq.c
drivers/gpu/drm/i915/i915_params.c
drivers/gpu/drm/i915/i915_reg.h
drivers/gpu/drm/i915/i915_sysfs.c
drivers/gpu/drm/i915/intel_bios.c
drivers/gpu/drm/i915/intel_bios.h
drivers/gpu/drm/i915/intel_ddi.c
drivers/gpu/drm/i915/intel_display.c
drivers/gpu/drm/i915/intel_dp.c
drivers/gpu/drm/i915/intel_drv.h
drivers/gpu/drm/i915/intel_dsi.c
drivers/gpu/drm/i915/intel_dsi.h
drivers/gpu/drm/i915/intel_dsi_cmd.c
drivers/gpu/drm/i915/intel_dsi_panel_vbt.c
drivers/gpu/drm/i915/intel_dsi_pll.c
drivers/gpu/drm/i915/intel_dvo.c
drivers/gpu/drm/i915/intel_fbdev.c
drivers/gpu/drm/i915/intel_hdmi.c
drivers/gpu/drm/i915/intel_lrc.c [new file with mode: 0644]
drivers/gpu/drm/i915/intel_lrc.h [new file with mode: 0644]
drivers/gpu/drm/i915/intel_lvds.c
drivers/gpu/drm/i915/intel_panel.c
drivers/gpu/drm/i915/intel_pm.c
drivers/gpu/drm/i915/intel_renderstate.h
drivers/gpu/drm/i915/intel_ringbuffer.c
drivers/gpu/drm/i915/intel_ringbuffer.h
drivers/gpu/drm/i915/intel_sprite.c
drivers/gpu/drm/i915/intel_uncore.c
drivers/gpu/drm/mga/mga_dma.c
drivers/gpu/drm/mga/mga_drv.c
drivers/gpu/drm/mga/mga_drv.h
drivers/gpu/drm/mgag200/mgag200_drv.c
drivers/gpu/drm/mgag200/mgag200_drv.h
drivers/gpu/drm/mgag200/mgag200_fb.c
drivers/gpu/drm/mgag200/mgag200_mode.c
drivers/gpu/drm/mgag200/mgag200_ttm.c
drivers/gpu/drm/msm/Kconfig
drivers/gpu/drm/msm/Makefile
drivers/gpu/drm/msm/adreno/a2xx.xml.h
drivers/gpu/drm/msm/adreno/a3xx.xml.h
drivers/gpu/drm/msm/adreno/a3xx_gpu.c
drivers/gpu/drm/msm/adreno/adreno_common.xml.h
drivers/gpu/drm/msm/adreno/adreno_device.c [new file with mode: 0644]
drivers/gpu/drm/msm/adreno/adreno_gpu.c
drivers/gpu/drm/msm/adreno/adreno_gpu.h
drivers/gpu/drm/msm/adreno/adreno_pm4.xml.h
drivers/gpu/drm/msm/dsi/dsi.xml.h
drivers/gpu/drm/msm/dsi/mmss_cc.xml.h
drivers/gpu/drm/msm/dsi/sfpb.xml.h
drivers/gpu/drm/msm/hdmi/hdmi.c
drivers/gpu/drm/msm/hdmi/hdmi.xml.h
drivers/gpu/drm/msm/hdmi/qfprom.xml.h
drivers/gpu/drm/msm/mdp/mdp4/mdp4.xml.h
drivers/gpu/drm/msm/mdp/mdp4/mdp4_crtc.c
drivers/gpu/drm/msm/mdp/mdp4/mdp4_dtv_encoder.c
drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.c
drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.h
drivers/gpu/drm/msm/mdp/mdp4/mdp4_lcdc_encoder.c [new file with mode: 0644]
drivers/gpu/drm/msm/mdp/mdp4/mdp4_lvds_connector.c [new file with mode: 0644]
drivers/gpu/drm/msm/mdp/mdp4/mdp4_lvds_pll.c [new file with mode: 0644]
drivers/gpu/drm/msm/msm_drv.c
drivers/gpu/drm/msm/msm_drv.h
drivers/gpu/drm/msm/msm_gem_prime.c
drivers/gpu/drm/msm/msm_gpu.h
drivers/gpu/drm/nouveau/Makefile
drivers/gpu/drm/nouveau/core/core/client.c
drivers/gpu/drm/nouveau/core/core/event.c
drivers/gpu/drm/nouveau/core/core/gpuobj.c
drivers/gpu/drm/nouveau/core/core/ioctl.c
drivers/gpu/drm/nouveau/core/core/mm.c
drivers/gpu/drm/nouveau/core/core/notify.c
drivers/gpu/drm/nouveau/core/engine/device/base.c
drivers/gpu/drm/nouveau/core/engine/device/gm100.c
drivers/gpu/drm/nouveau/core/engine/device/nv50.c
drivers/gpu/drm/nouveau/core/engine/device/nvc0.c
drivers/gpu/drm/nouveau/core/engine/device/nve0.c
drivers/gpu/drm/nouveau/core/engine/disp/base.c
drivers/gpu/drm/nouveau/core/engine/disp/conn.c
drivers/gpu/drm/nouveau/core/engine/disp/gm107.c
drivers/gpu/drm/nouveau/core/engine/disp/hdanva3.c
drivers/gpu/drm/nouveau/core/engine/disp/hdanvd0.c
drivers/gpu/drm/nouveau/core/engine/disp/hdminvd0.c
drivers/gpu/drm/nouveau/core/engine/disp/hdminve0.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/core/engine/disp/nv50.c
drivers/gpu/drm/nouveau/core/engine/disp/nv50.h
drivers/gpu/drm/nouveau/core/engine/disp/nv84.c
drivers/gpu/drm/nouveau/core/engine/disp/nv94.c
drivers/gpu/drm/nouveau/core/engine/disp/nva0.c
drivers/gpu/drm/nouveau/core/engine/disp/nva3.c
drivers/gpu/drm/nouveau/core/engine/disp/nvd0.c
drivers/gpu/drm/nouveau/core/engine/disp/nve0.c
drivers/gpu/drm/nouveau/core/engine/disp/nvf0.c
drivers/gpu/drm/nouveau/core/engine/disp/outpdp.c
drivers/gpu/drm/nouveau/core/engine/disp/priv.h
drivers/gpu/drm/nouveau/core/engine/fifo/base.c
drivers/gpu/drm/nouveau/core/engine/software/nv50.c
drivers/gpu/drm/nouveau/core/include/core/client.h
drivers/gpu/drm/nouveau/core/include/core/device.h
drivers/gpu/drm/nouveau/core/include/core/event.h
drivers/gpu/drm/nouveau/core/include/core/mm.h
drivers/gpu/drm/nouveau/core/include/core/notify.h
drivers/gpu/drm/nouveau/core/include/engine/fifo.h
drivers/gpu/drm/nouveau/core/include/subdev/bar.h
drivers/gpu/drm/nouveau/core/include/subdev/bios/M0205.h [new file with mode: 0644]
drivers/gpu/drm/nouveau/core/include/subdev/bios/M0209.h [new file with mode: 0644]
drivers/gpu/drm/nouveau/core/include/subdev/bios/fan.h [new file with mode: 0644]
drivers/gpu/drm/nouveau/core/include/subdev/bios/ramcfg.h
drivers/gpu/drm/nouveau/core/include/subdev/bios/rammap.h
drivers/gpu/drm/nouveau/core/include/subdev/bios/therm.h
drivers/gpu/drm/nouveau/core/include/subdev/clock.h
drivers/gpu/drm/nouveau/core/include/subdev/fb.h
drivers/gpu/drm/nouveau/core/include/subdev/fb/regsnv04.h [new file with mode: 0644]
drivers/gpu/drm/nouveau/core/include/subdev/fuse.h [new file with mode: 0644]
drivers/gpu/drm/nouveau/core/include/subdev/gpio.h
drivers/gpu/drm/nouveau/core/include/subdev/pwr.h
drivers/gpu/drm/nouveau/core/include/subdev/therm.h
drivers/gpu/drm/nouveau/core/subdev/bar/base.c
drivers/gpu/drm/nouveau/core/subdev/bios/M0205.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/core/subdev/bios/M0209.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/core/subdev/bios/dcb.c
drivers/gpu/drm/nouveau/core/subdev/bios/fan.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/core/subdev/bios/rammap.c
drivers/gpu/drm/nouveau/core/subdev/bios/timing.c
drivers/gpu/drm/nouveau/core/subdev/clock/base.c
drivers/gpu/drm/nouveau/core/subdev/clock/nva3.c
drivers/gpu/drm/nouveau/core/subdev/clock/nva3.h
drivers/gpu/drm/nouveau/core/subdev/clock/nvaa.c
drivers/gpu/drm/nouveau/core/subdev/devinit/fbmem.h
drivers/gpu/drm/nouveau/core/subdev/fb/gddr5.c
drivers/gpu/drm/nouveau/core/subdev/fb/nv20.c
drivers/gpu/drm/nouveau/core/subdev/fb/nv25.c
drivers/gpu/drm/nouveau/core/subdev/fb/nv30.c
drivers/gpu/drm/nouveau/core/subdev/fb/nv35.c
drivers/gpu/drm/nouveau/core/subdev/fb/nv36.c
drivers/gpu/drm/nouveau/core/subdev/fb/nv40.c
drivers/gpu/drm/nouveau/core/subdev/fb/priv.h
drivers/gpu/drm/nouveau/core/subdev/fb/ramfuc.h
drivers/gpu/drm/nouveau/core/subdev/fb/ramnv04.c
drivers/gpu/drm/nouveau/core/subdev/fb/ramnv50.c
drivers/gpu/drm/nouveau/core/subdev/fb/ramnva3.c
drivers/gpu/drm/nouveau/core/subdev/fb/ramnvc0.c
drivers/gpu/drm/nouveau/core/subdev/fb/ramnve0.c
drivers/gpu/drm/nouveau/core/subdev/fb/sddr2.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/core/subdev/fb/sddr3.c
drivers/gpu/drm/nouveau/core/subdev/fuse/base.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/core/subdev/fuse/g80.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/core/subdev/fuse/gf100.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/core/subdev/fuse/gm107.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/core/subdev/fuse/priv.h [new file with mode: 0644]
drivers/gpu/drm/nouveau/core/subdev/gpio/base.c
drivers/gpu/drm/nouveau/core/subdev/gpio/nv92.c [deleted file]
drivers/gpu/drm/nouveau/core/subdev/gpio/nv94.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/core/subdev/gpio/nvd0.c
drivers/gpu/drm/nouveau/core/subdev/gpio/priv.h
drivers/gpu/drm/nouveau/core/subdev/i2c/base.c
drivers/gpu/drm/nouveau/core/subdev/instmem/nv04.c
drivers/gpu/drm/nouveau/core/subdev/ltc/base.c
drivers/gpu/drm/nouveau/core/subdev/ltc/gf100.c
drivers/gpu/drm/nouveau/core/subdev/ltc/gm107.c
drivers/gpu/drm/nouveau/core/subdev/ltc/priv.h
drivers/gpu/drm/nouveau/core/subdev/pwr/base.c
drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/arith.fuc [new file with mode: 0644]
drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/kernel.fuc
drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/macros.fuc
drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/memx.fuc
drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/nv108.fuc
drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/nv108.fuc.h
drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/nva3.fuc
drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/nva3.fuc.h
drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/nvc0.fuc
drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/nvc0.fuc.h
drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/nvd0.fuc
drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/nvd0.fuc.h
drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/os.h
drivers/gpu/drm/nouveau/core/subdev/pwr/memx.c
drivers/gpu/drm/nouveau/core/subdev/therm/fan.c
drivers/gpu/drm/nouveau/core/subdev/therm/fanpwm.c
drivers/gpu/drm/nouveau/core/subdev/therm/gm107.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/core/subdev/therm/nv84.c
drivers/gpu/drm/nouveau/core/subdev/therm/nva3.c
drivers/gpu/drm/nouveau/core/subdev/therm/nvd0.c
drivers/gpu/drm/nouveau/core/subdev/therm/priv.h
drivers/gpu/drm/nouveau/core/subdev/vm/base.c
drivers/gpu/drm/nouveau/dispnv04/crtc.c
drivers/gpu/drm/nouveau/dispnv04/overlay.c
drivers/gpu/drm/nouveau/nouveau_abi16.c
drivers/gpu/drm/nouveau/nouveau_bo.c
drivers/gpu/drm/nouveau/nouveau_bo.h
drivers/gpu/drm/nouveau/nouveau_chan.c
drivers/gpu/drm/nouveau/nouveau_chan.h
drivers/gpu/drm/nouveau/nouveau_connector.c
drivers/gpu/drm/nouveau/nouveau_connector.h
drivers/gpu/drm/nouveau/nouveau_display.c
drivers/gpu/drm/nouveau/nouveau_drm.c
drivers/gpu/drm/nouveau/nouveau_drm.h
drivers/gpu/drm/nouveau/nouveau_fbcon.c
drivers/gpu/drm/nouveau/nouveau_fbcon.h
drivers/gpu/drm/nouveau/nouveau_fence.c
drivers/gpu/drm/nouveau/nouveau_fence.h
drivers/gpu/drm/nouveau/nouveau_gem.c
drivers/gpu/drm/nouveau/nouveau_gem.h
drivers/gpu/drm/nouveau/nouveau_nvif.c
drivers/gpu/drm/nouveau/nouveau_prime.c
drivers/gpu/drm/nouveau/nouveau_sysfs.c
drivers/gpu/drm/nouveau/nouveau_sysfs.h
drivers/gpu/drm/nouveau/nouveau_ttm.c
drivers/gpu/drm/nouveau/nv04_fence.c
drivers/gpu/drm/nouveau/nv10_fence.c
drivers/gpu/drm/nouveau/nv17_fence.c
drivers/gpu/drm/nouveau/nv50_display.c
drivers/gpu/drm/nouveau/nv50_fence.c
drivers/gpu/drm/nouveau/nv84_fence.c
drivers/gpu/drm/nouveau/nvif/class.h
drivers/gpu/drm/nouveau/nvif/driver.h
drivers/gpu/drm/nouveau/nvif/object.h
drivers/gpu/drm/omapdrm/omap_drv.c
drivers/gpu/drm/omapdrm/omap_drv.h
drivers/gpu/drm/panel/panel-simple.c
drivers/gpu/drm/qxl/Makefile
drivers/gpu/drm/qxl/qxl_cmd.c
drivers/gpu/drm/qxl/qxl_debugfs.c
drivers/gpu/drm/qxl/qxl_display.c
drivers/gpu/drm/qxl/qxl_drv.c
drivers/gpu/drm/qxl/qxl_drv.h
drivers/gpu/drm/qxl/qxl_fb.c
drivers/gpu/drm/qxl/qxl_fence.c [deleted file]
drivers/gpu/drm/qxl/qxl_kms.c
drivers/gpu/drm/qxl/qxl_object.c
drivers/gpu/drm/qxl/qxl_object.h
drivers/gpu/drm/qxl/qxl_prime.c [new file with mode: 0644]
drivers/gpu/drm/qxl/qxl_release.c
drivers/gpu/drm/qxl/qxl_ttm.c
drivers/gpu/drm/r128/r128_cce.c
drivers/gpu/drm/r128/r128_drv.c
drivers/gpu/drm/r128/r128_drv.h
drivers/gpu/drm/radeon/Makefile
drivers/gpu/drm/radeon/atombios_dp.c
drivers/gpu/drm/radeon/atombios_encoders.c
drivers/gpu/drm/radeon/btc_dpm.c
drivers/gpu/drm/radeon/btc_dpm.h
drivers/gpu/drm/radeon/ci_dpm.c
drivers/gpu/drm/radeon/cik.c
drivers/gpu/drm/radeon/cik_sdma.c
drivers/gpu/drm/radeon/dce3_1_afmt.c
drivers/gpu/drm/radeon/dce6_afmt.c
drivers/gpu/drm/radeon/drm_buffer.c [new file with mode: 0644]
drivers/gpu/drm/radeon/drm_buffer.h [new file with mode: 0644]
drivers/gpu/drm/radeon/evergreen.c
drivers/gpu/drm/radeon/evergreen_dma.c
drivers/gpu/drm/radeon/evergreen_hdmi.c
drivers/gpu/drm/radeon/kv_dpm.c
drivers/gpu/drm/radeon/ni_dpm.c
drivers/gpu/drm/radeon/r100.c
drivers/gpu/drm/radeon/r200.c
drivers/gpu/drm/radeon/r300_cmdbuf.c
drivers/gpu/drm/radeon/r600.c
drivers/gpu/drm/radeon/r600_audio.c [deleted file]
drivers/gpu/drm/radeon/r600_cp.c
drivers/gpu/drm/radeon/r600_dma.c
drivers/gpu/drm/radeon/r600_hdmi.c
drivers/gpu/drm/radeon/r600d.h
drivers/gpu/drm/radeon/radeon.h
drivers/gpu/drm/radeon/radeon_asic.c
drivers/gpu/drm/radeon/radeon_asic.h
drivers/gpu/drm/radeon/radeon_atombios.c
drivers/gpu/drm/radeon/radeon_benchmark.c
drivers/gpu/drm/radeon/radeon_combios.c
drivers/gpu/drm/radeon/radeon_cp.c
drivers/gpu/drm/radeon/radeon_cs.c
drivers/gpu/drm/radeon/radeon_device.c
drivers/gpu/drm/radeon/radeon_display.c
drivers/gpu/drm/radeon/radeon_drv.c
drivers/gpu/drm/radeon/radeon_drv.h
drivers/gpu/drm/radeon/radeon_encoders.c
drivers/gpu/drm/radeon/radeon_fb.c
drivers/gpu/drm/radeon/radeon_fence.c
drivers/gpu/drm/radeon/radeon_gart.c
drivers/gpu/drm/radeon/radeon_gem.c
drivers/gpu/drm/radeon/radeon_ib.c
drivers/gpu/drm/radeon/radeon_irq_kms.c
drivers/gpu/drm/radeon/radeon_kms.c
drivers/gpu/drm/radeon/radeon_mn.c [new file with mode: 0644]
drivers/gpu/drm/radeon/radeon_mode.h
drivers/gpu/drm/radeon/radeon_object.c
drivers/gpu/drm/radeon/radeon_object.h
drivers/gpu/drm/radeon/radeon_pm.c
drivers/gpu/drm/radeon/radeon_prime.c
drivers/gpu/drm/radeon/radeon_ring.c
drivers/gpu/drm/radeon/radeon_sa.c
drivers/gpu/drm/radeon/radeon_semaphore.c
drivers/gpu/drm/radeon/radeon_state.c
drivers/gpu/drm/radeon/radeon_test.c
drivers/gpu/drm/radeon/radeon_ttm.c
drivers/gpu/drm/radeon/radeon_uvd.c
drivers/gpu/drm/radeon/radeon_vce.c
drivers/gpu/drm/radeon/radeon_vm.c
drivers/gpu/drm/radeon/rv770.c
drivers/gpu/drm/radeon/rv770_dma.c
drivers/gpu/drm/radeon/si.c
drivers/gpu/drm/radeon/si_dma.c
drivers/gpu/drm/radeon/si_dpm.c
drivers/gpu/drm/radeon/sid.h
drivers/gpu/drm/radeon/uvd_v1_0.c
drivers/gpu/drm/radeon/uvd_v2_2.c
drivers/gpu/drm/rcar-du/Kconfig
drivers/gpu/drm/rcar-du/rcar_du_crtc.c
drivers/gpu/drm/rcar-du/rcar_du_crtc.h
drivers/gpu/drm/rcar-du/rcar_du_drv.c
drivers/gpu/drm/rcar-du/rcar_du_drv.h
drivers/gpu/drm/rcar-du/rcar_du_encoder.c
drivers/gpu/drm/rcar-du/rcar_du_encoder.h
drivers/gpu/drm/rcar-du/rcar_du_group.c
drivers/gpu/drm/rcar-du/rcar_du_group.h
drivers/gpu/drm/rcar-du/rcar_du_kms.c
drivers/gpu/drm/rcar-du/rcar_du_kms.h
drivers/gpu/drm/rcar-du/rcar_du_lvdscon.c
drivers/gpu/drm/rcar-du/rcar_du_lvdscon.h
drivers/gpu/drm/rcar-du/rcar_du_lvdsenc.c
drivers/gpu/drm/rcar-du/rcar_du_lvdsenc.h
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_vgacon.c
drivers/gpu/drm/rcar-du/rcar_du_vgacon.h
drivers/gpu/drm/savage/savage_bci.c
drivers/gpu/drm/savage/savage_drv.c
drivers/gpu/drm/savage/savage_drv.h
drivers/gpu/drm/shmobile/shmob_drm_backlight.c
drivers/gpu/drm/shmobile/shmob_drm_backlight.h
drivers/gpu/drm/shmobile/shmob_drm_crtc.c
drivers/gpu/drm/shmobile/shmob_drm_crtc.h
drivers/gpu/drm/shmobile/shmob_drm_drv.c
drivers/gpu/drm/shmobile/shmob_drm_drv.h
drivers/gpu/drm/shmobile/shmob_drm_kms.c
drivers/gpu/drm/shmobile/shmob_drm_kms.h
drivers/gpu/drm/shmobile/shmob_drm_plane.c
drivers/gpu/drm/shmobile/shmob_drm_plane.h
drivers/gpu/drm/shmobile/shmob_drm_regs.h
drivers/gpu/drm/sis/sis_drv.c
drivers/gpu/drm/sis/sis_drv.h
drivers/gpu/drm/sis/sis_mm.c
drivers/gpu/drm/sti/sti_vtac.c
drivers/gpu/drm/tdfx/tdfx_drv.c
drivers/gpu/drm/tegra/dpaux.c
drivers/gpu/drm/tegra/gem.h
drivers/gpu/drm/tilcdc/tilcdc_drv.c
drivers/gpu/drm/tilcdc/tilcdc_panel.c
drivers/gpu/drm/ttm/ttm_bo.c
drivers/gpu/drm/ttm/ttm_bo_manager.c
drivers/gpu/drm/ttm/ttm_bo_util.c
drivers/gpu/drm/ttm/ttm_bo_vm.c
drivers/gpu/drm/ttm/ttm_execbuf_util.c
drivers/gpu/drm/ttm/ttm_memory.c
drivers/gpu/drm/udl/Kconfig
drivers/gpu/drm/udl/udl_connector.c
drivers/gpu/drm/udl/udl_drv.c
drivers/gpu/drm/udl/udl_drv.h
drivers/gpu/drm/udl/udl_fb.c
drivers/gpu/drm/udl/udl_main.c
drivers/gpu/drm/via/via_dma.c
drivers/gpu/drm/via/via_drv.c
drivers/gpu/drm/via/via_drv.h
drivers/gpu/drm/via/via_map.c
drivers/gpu/drm/via/via_mm.c
drivers/gpu/drm/via/via_verifier.c
drivers/gpu/drm/vmwgfx/vmwgfx_buffer.c
drivers/gpu/drm/vmwgfx/vmwgfx_dmabuf.c
drivers/gpu/drm/vmwgfx/vmwgfx_drv.c
drivers/gpu/drm/vmwgfx/vmwgfx_drv.h
drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c
drivers/gpu/drm/vmwgfx/vmwgfx_fb.c
drivers/gpu/drm/vmwgfx/vmwgfx_fence.c
drivers/gpu/drm/vmwgfx/vmwgfx_fence.h
drivers/gpu/drm/vmwgfx/vmwgfx_fifo.c
drivers/gpu/drm/vmwgfx/vmwgfx_gmrid_manager.c
drivers/gpu/drm/vmwgfx/vmwgfx_resource.c
drivers/gpu/ipu-v3/Kconfig
drivers/gpu/ipu-v3/Makefile
drivers/gpu/ipu-v3/ipu-common.c
drivers/gpu/ipu-v3/ipu-cpmem.c
drivers/gpu/ipu-v3/ipu-csi.c [new file with mode: 0644]
drivers/gpu/ipu-v3/ipu-ic.c [new file with mode: 0644]
drivers/gpu/ipu-v3/ipu-prv.h
drivers/gpu/ipu-v3/ipu-smfc.c
drivers/gpu/vga/vgaarb.c
drivers/hwmon/Kconfig
drivers/hwmon/Makefile
drivers/hwmon/ab8500.c
drivers/hwmon/ads1015.c
drivers/hwmon/da9052-hwmon.c
drivers/hwmon/da9055-hwmon.c
drivers/hwmon/k10temp.c
drivers/hwmon/menf21bmc_hwmon.c [new file with mode: 0644]
drivers/hwmon/ntc_thermistor.c
drivers/hwmon/smsc47b397.c
drivers/infiniband/hw/ipath/ipath_fs.c
drivers/infiniband/hw/qib/qib_fs.c
drivers/infiniband/ulp/srpt/ib_srpt.c
drivers/input/misc/xen-kbdfront.c
drivers/input/touchscreen/edt-ft5x06.c
drivers/leds/Kconfig
drivers/leds/Makefile
drivers/leds/leds-menf21bmc.c [new file with mode: 0644]
drivers/macintosh/adb.c
drivers/macintosh/via-cuda.c
drivers/md/dm-bufio.c
drivers/media/common/b2c2/flexcop.h
drivers/media/common/saa7146/saa7146_fops.c
drivers/media/common/siano/sms-cards.c
drivers/media/common/siano/sms-cards.h
drivers/media/common/siano/smscoreapi.c
drivers/media/dvb-core/dmxdev.c
drivers/media/dvb-core/dvb-usb-ids.h
drivers/media/dvb-core/dvb_frontend.c
drivers/media/dvb-core/dvb_frontend.h
drivers/media/dvb-core/dvb_ringbuffer.c
drivers/media/dvb-core/dvb_ringbuffer.h
drivers/media/dvb-frontends/Kconfig
drivers/media/dvb-frontends/Makefile
drivers/media/dvb-frontends/af9013.c
drivers/media/dvb-frontends/af9033.c
drivers/media/dvb-frontends/af9033.h
drivers/media/dvb-frontends/af9033_priv.h
drivers/media/dvb-frontends/as102_fe.c [new file with mode: 0644]
drivers/media/dvb-frontends/as102_fe.h [new file with mode: 0644]
drivers/media/dvb-frontends/as102_fe_types.h [new file with mode: 0644]
drivers/media/dvb-frontends/bcm3510.c
drivers/media/dvb-frontends/cxd2820r_c.c
drivers/media/dvb-frontends/cxd2820r_core.c
drivers/media/dvb-frontends/cxd2820r_t.c
drivers/media/dvb-frontends/dib7000p.c
drivers/media/dvb-frontends/drx39xyj/drxj.c
drivers/media/dvb-frontends/drxd_hard.c
drivers/media/dvb-frontends/drxk_hard.c
drivers/media/dvb-frontends/m88ds3103.c
drivers/media/dvb-frontends/m88ds3103.h
drivers/media/dvb-frontends/mb86a16.c
drivers/media/dvb-frontends/mb86a20s.c
drivers/media/dvb-frontends/mt312.c
drivers/media/dvb-frontends/or51211.c
drivers/media/dvb-frontends/rtl2832.c
drivers/media/dvb-frontends/rtl2832_sdr.c
drivers/media/dvb-frontends/si2165.c
drivers/media/dvb-frontends/si2165_priv.h
drivers/media/dvb-frontends/si2168.c
drivers/media/dvb-frontends/si2168.h
drivers/media/dvb-frontends/si2168_priv.h
drivers/media/dvb-frontends/si21xx.c
drivers/media/dvb-frontends/sp2.c [new file with mode: 0644]
drivers/media/dvb-frontends/sp2.h [new file with mode: 0644]
drivers/media/dvb-frontends/sp2_priv.h [new file with mode: 0644]
drivers/media/dvb-frontends/sp8870.c
drivers/media/dvb-frontends/stv0367.c
drivers/media/dvb-frontends/stv0900_core.c
drivers/media/dvb-frontends/stv0900_sw.c
drivers/media/dvb-frontends/tc90522.c [new file with mode: 0644]
drivers/media/dvb-frontends/tc90522.h [new file with mode: 0644]
drivers/media/dvb-frontends/tda10071.c
drivers/media/dvb-frontends/zl10039.c
drivers/media/firewire/firedtv-avc.c
drivers/media/i2c/adv7343_regs.h
drivers/media/i2c/adv7604.c
drivers/media/i2c/adv7842.c
drivers/media/i2c/lm3560.c
drivers/media/i2c/ov7670.c
drivers/media/i2c/s5k5baf.c
drivers/media/i2c/saa6752hs.c
drivers/media/i2c/smiapp/smiapp-core.c
drivers/media/i2c/smiapp/smiapp.h
drivers/media/i2c/soc_camera/mt9t112.c
drivers/media/i2c/soc_camera/ov772x.c
drivers/media/i2c/soc_camera/ov9740.c
drivers/media/i2c/tda7432.c
drivers/media/i2c/tvp7002.c
drivers/media/i2c/vs6624.c
drivers/media/media-device.c
drivers/media/media-devnode.c
drivers/media/parport/pms.c
drivers/media/pci/Kconfig
drivers/media/pci/Makefile
drivers/media/pci/bt8xx/bttv-driver.c
drivers/media/pci/bt8xx/dst_ca.c
drivers/media/pci/cx18/cx18-alsa-pcm.c
drivers/media/pci/cx18/cx18-firmware.c
drivers/media/pci/cx18/cx18-queue.c
drivers/media/pci/cx23885/Kconfig
drivers/media/pci/cx23885/Makefile
drivers/media/pci/cx23885/altera-ci.c
drivers/media/pci/cx23885/altera-ci.h
drivers/media/pci/cx23885/cimax2.c
drivers/media/pci/cx23885/cimax2.h
drivers/media/pci/cx23885/cx23885-417.c
drivers/media/pci/cx23885/cx23885-alsa.c
drivers/media/pci/cx23885/cx23885-av.c
drivers/media/pci/cx23885/cx23885-av.h
drivers/media/pci/cx23885/cx23885-cards.c
drivers/media/pci/cx23885/cx23885-core.c
drivers/media/pci/cx23885/cx23885-dvb.c
drivers/media/pci/cx23885/cx23885-f300.c
drivers/media/pci/cx23885/cx23885-i2c.c
drivers/media/pci/cx23885/cx23885-input.c
drivers/media/pci/cx23885/cx23885-input.h
drivers/media/pci/cx23885/cx23885-ioctl.c
drivers/media/pci/cx23885/cx23885-ioctl.h
drivers/media/pci/cx23885/cx23885-ir.c
drivers/media/pci/cx23885/cx23885-ir.h
drivers/media/pci/cx23885/cx23885-reg.h
drivers/media/pci/cx23885/cx23885-vbi.c
drivers/media/pci/cx23885/cx23885-video.c
drivers/media/pci/cx23885/cx23885-video.h
drivers/media/pci/cx23885/cx23885.h
drivers/media/pci/cx23885/cx23888-ir.c
drivers/media/pci/cx23885/cx23888-ir.h
drivers/media/pci/cx23885/netup-eeprom.c
drivers/media/pci/cx23885/netup-eeprom.h
drivers/media/pci/cx23885/netup-init.c
drivers/media/pci/cx23885/netup-init.h
drivers/media/pci/cx25821/cx25821-video-upstream.c
drivers/media/pci/cx88/cx88-cards.c
drivers/media/pci/cx88/cx88-video.c
drivers/media/pci/ddbridge/ddbridge-core.c
drivers/media/pci/ddbridge/ddbridge.h
drivers/media/pci/dm1105/dm1105.c
drivers/media/pci/ivtv/ivtv-alsa-pcm.c
drivers/media/pci/ivtv/ivtv-firmware.c
drivers/media/pci/ivtv/ivtv-irq.c
drivers/media/pci/mantis/hopper_vp3028.c
drivers/media/pci/mantis/mantis_common.h
drivers/media/pci/mantis/mantis_vp1033.c
drivers/media/pci/mantis/mantis_vp1034.c
drivers/media/pci/mantis/mantis_vp1041.c
drivers/media/pci/mantis/mantis_vp2033.c
drivers/media/pci/mantis/mantis_vp2040.c
drivers/media/pci/mantis/mantis_vp3030.c
drivers/media/pci/ngene/ngene-cards.c
drivers/media/pci/ngene/ngene-core.c
drivers/media/pci/ngene/ngene-dvb.c
drivers/media/pci/ngene/ngene.h
drivers/media/pci/pt3/Kconfig [new file with mode: 0644]
drivers/media/pci/pt3/Makefile [new file with mode: 0644]
drivers/media/pci/pt3/pt3.c [new file with mode: 0644]
drivers/media/pci/pt3/pt3.h [new file with mode: 0644]
drivers/media/pci/pt3/pt3_dma.c [new file with mode: 0644]
drivers/media/pci/pt3/pt3_i2c.c [new file with mode: 0644]
drivers/media/pci/saa7134/Kconfig
drivers/media/pci/saa7134/Makefile
drivers/media/pci/saa7134/saa7134-cards.c
drivers/media/pci/saa7134/saa7134-core.c
drivers/media/pci/saa7134/saa7134-go7007.c [new file with mode: 0644]
drivers/media/pci/saa7134/saa7134-vbi.c
drivers/media/pci/saa7134/saa7134-video.c
drivers/media/pci/saa7134/saa7134.h
drivers/media/pci/saa7164/saa7164-api.c
drivers/media/pci/saa7164/saa7164-core.c
drivers/media/pci/solo6x10/Kconfig
drivers/media/pci/solo6x10/solo6x10-disp.c
drivers/media/pci/solo6x10/solo6x10-eeprom.c
drivers/media/pci/solo6x10/solo6x10.h
drivers/media/pci/sta2x11/Kconfig
drivers/media/pci/sta2x11/sta2x11_vip.c
drivers/media/pci/ttpci/Kconfig
drivers/media/pci/ttpci/Makefile
drivers/media/pci/ttpci/av7110.c
drivers/media/pci/tw68/Kconfig [new file with mode: 0644]
drivers/media/pci/tw68/Makefile [new file with mode: 0644]
drivers/media/pci/tw68/tw68-core.c [new file with mode: 0644]
drivers/media/pci/tw68/tw68-reg.h [new file with mode: 0644]
drivers/media/pci/tw68/tw68-risc.c [new file with mode: 0644]
drivers/media/pci/tw68/tw68-video.c [new file with mode: 0644]
drivers/media/pci/tw68/tw68.h [new file with mode: 0644]
drivers/media/pci/zoran/zoran_device.c
drivers/media/platform/Kconfig
drivers/media/platform/Makefile
drivers/media/platform/blackfin/Kconfig
drivers/media/platform/coda.c [deleted file]
drivers/media/platform/coda.h [deleted file]
drivers/media/platform/coda/Makefile [new file with mode: 0644]
drivers/media/platform/coda/coda-bit.c [new file with mode: 0644]
drivers/media/platform/coda/coda-common.c [new file with mode: 0644]
drivers/media/platform/coda/coda-h264.c [new file with mode: 0644]
drivers/media/platform/coda/coda.h [new file with mode: 0644]
drivers/media/platform/coda/coda_regs.h [new file with mode: 0644]
drivers/media/platform/davinci/Kconfig
drivers/media/platform/davinci/dm355_ccdc.c
drivers/media/platform/davinci/dm644x_ccdc.c
drivers/media/platform/davinci/vpfe_capture.c
drivers/media/platform/davinci/vpif.c
drivers/media/platform/davinci/vpif_capture.c
drivers/media/platform/davinci/vpif_display.c
drivers/media/platform/exynos-gsc/gsc-core.c
drivers/media/platform/exynos-gsc/gsc-m2m.c
drivers/media/platform/exynos-gsc/gsc-regs.c
drivers/media/platform/exynos4-is/Kconfig
drivers/media/platform/exynos4-is/fimc-is-errno.c
drivers/media/platform/exynos4-is/fimc-is-errno.h
drivers/media/platform/exynos4-is/fimc-is-param.c
drivers/media/platform/exynos4-is/fimc-is.c
drivers/media/platform/exynos4-is/fimc-isp-video.c
drivers/media/platform/exynos4-is/media-dev.c
drivers/media/platform/exynos4-is/mipi-csis.c
drivers/media/platform/marvell-ccic/Kconfig
drivers/media/platform/marvell-ccic/mcam-core.c
drivers/media/platform/mx2_emmaprp.c
drivers/media/platform/omap/Kconfig
drivers/media/platform/omap/omap_vout.c
drivers/media/platform/omap/omap_vout_vrfb.c
drivers/media/platform/omap/omap_vout_vrfb.h
drivers/media/platform/omap3isp/cfa_coef_table.h
drivers/media/platform/omap3isp/gamma_table.h
drivers/media/platform/omap3isp/isp.c
drivers/media/platform/omap3isp/isp.h
drivers/media/platform/omap3isp/ispccdc.c
drivers/media/platform/omap3isp/ispccdc.h
drivers/media/platform/omap3isp/ispccp2.c
drivers/media/platform/omap3isp/ispccp2.h
drivers/media/platform/omap3isp/ispcsi2.c
drivers/media/platform/omap3isp/ispcsi2.h
drivers/media/platform/omap3isp/ispcsiphy.c
drivers/media/platform/omap3isp/ispcsiphy.h
drivers/media/platform/omap3isp/isph3a.h
drivers/media/platform/omap3isp/isph3a_aewb.c
drivers/media/platform/omap3isp/isph3a_af.c
drivers/media/platform/omap3isp/isphist.c
drivers/media/platform/omap3isp/isphist.h
drivers/media/platform/omap3isp/isppreview.c
drivers/media/platform/omap3isp/isppreview.h
drivers/media/platform/omap3isp/ispreg.h
drivers/media/platform/omap3isp/ispresizer.c
drivers/media/platform/omap3isp/ispresizer.h
drivers/media/platform/omap3isp/ispstat.c
drivers/media/platform/omap3isp/ispstat.h
drivers/media/platform/omap3isp/ispvideo.c
drivers/media/platform/omap3isp/ispvideo.h
drivers/media/platform/omap3isp/luma_enhance_table.h
drivers/media/platform/omap3isp/noise_filter_table.h
drivers/media/platform/s3c-camif/camif-capture.c
drivers/media/platform/s3c-camif/camif-regs.c
drivers/media/platform/s5p-g2d/g2d.c
drivers/media/platform/s5p-jpeg/jpeg-core.c
drivers/media/platform/s5p-jpeg/jpeg-hw-exynos3250.c
drivers/media/platform/s5p-jpeg/jpeg-hw-exynos4.c
drivers/media/platform/s5p-jpeg/jpeg-hw-s5p.c
drivers/media/platform/s5p-mfc/s5p_mfc.c
drivers/media/platform/s5p-mfc/s5p_mfc_cmd_v5.c
drivers/media/platform/s5p-mfc/s5p_mfc_cmd_v6.c
drivers/media/platform/s5p-mfc/s5p_mfc_common.h
drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c
drivers/media/platform/s5p-mfc/s5p_mfc_debug.h
drivers/media/platform/s5p-mfc/s5p_mfc_dec.c
drivers/media/platform/s5p-mfc/s5p_mfc_enc.c
drivers/media/platform/s5p-mfc/s5p_mfc_opr.c
drivers/media/platform/s5p-mfc/s5p_mfc_opr.h
drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.c
drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c
drivers/media/platform/s5p-mfc/s5p_mfc_pm.c
drivers/media/platform/s5p-tv/Kconfig
drivers/media/platform/s5p-tv/hdmi_drv.c
drivers/media/platform/s5p-tv/sdo_drv.c
drivers/media/platform/s5p-tv/sii9234_drv.c
drivers/media/platform/sh_veu.c
drivers/media/platform/soc_camera/Kconfig
drivers/media/platform/soc_camera/atmel-isi.c
drivers/media/platform/soc_camera/mx2_camera.c
drivers/media/platform/soc_camera/pxa_camera.c
drivers/media/platform/soc_camera/rcar_vin.c
drivers/media/platform/soc_camera/soc_camera.c
drivers/media/platform/ti-vpe/vpdma.c
drivers/media/platform/ti-vpe/vpe.c
drivers/media/platform/via-camera.c
drivers/media/platform/vivi.c [deleted file]
drivers/media/platform/vivid/Kconfig [new file with mode: 0644]
drivers/media/platform/vivid/Makefile [new file with mode: 0644]
drivers/media/platform/vivid/vivid-core.c [new file with mode: 0644]
drivers/media/platform/vivid/vivid-core.h [new file with mode: 0644]
drivers/media/platform/vivid/vivid-ctrls.c [new file with mode: 0644]
drivers/media/platform/vivid/vivid-ctrls.h [new file with mode: 0644]
drivers/media/platform/vivid/vivid-kthread-cap.c [new file with mode: 0644]
drivers/media/platform/vivid/vivid-kthread-cap.h [new file with mode: 0644]
drivers/media/platform/vivid/vivid-kthread-out.c [new file with mode: 0644]
drivers/media/platform/vivid/vivid-kthread-out.h [new file with mode: 0644]
drivers/media/platform/vivid/vivid-osd.c [new file with mode: 0644]
drivers/media/platform/vivid/vivid-osd.h [new file with mode: 0644]
drivers/media/platform/vivid/vivid-radio-common.c [new file with mode: 0644]
drivers/media/platform/vivid/vivid-radio-common.h [new file with mode: 0644]
drivers/media/platform/vivid/vivid-radio-rx.c [new file with mode: 0644]
drivers/media/platform/vivid/vivid-radio-rx.h [new file with mode: 0644]
drivers/media/platform/vivid/vivid-radio-tx.c [new file with mode: 0644]
drivers/media/platform/vivid/vivid-radio-tx.h [new file with mode: 0644]
drivers/media/platform/vivid/vivid-rds-gen.c [new file with mode: 0644]
drivers/media/platform/vivid/vivid-rds-gen.h [new file with mode: 0644]
drivers/media/platform/vivid/vivid-sdr-cap.c [new file with mode: 0644]
drivers/media/platform/vivid/vivid-sdr-cap.h [new file with mode: 0644]
drivers/media/platform/vivid/vivid-tpg-colors.c [new file with mode: 0644]
drivers/media/platform/vivid/vivid-tpg-colors.h [new file with mode: 0644]
drivers/media/platform/vivid/vivid-tpg.c [new file with mode: 0644]
drivers/media/platform/vivid/vivid-tpg.h [new file with mode: 0644]
drivers/media/platform/vivid/vivid-vbi-cap.c [new file with mode: 0644]
drivers/media/platform/vivid/vivid-vbi-cap.h [new file with mode: 0644]
drivers/media/platform/vivid/vivid-vbi-gen.c [new file with mode: 0644]
drivers/media/platform/vivid/vivid-vbi-gen.h [new file with mode: 0644]
drivers/media/platform/vivid/vivid-vbi-out.c [new file with mode: 0644]
drivers/media/platform/vivid/vivid-vbi-out.h [new file with mode: 0644]
drivers/media/platform/vivid/vivid-vid-cap.c [new file with mode: 0644]
drivers/media/platform/vivid/vivid-vid-cap.h [new file with mode: 0644]
drivers/media/platform/vivid/vivid-vid-common.c [new file with mode: 0644]
drivers/media/platform/vivid/vivid-vid-common.h [new file with mode: 0644]
drivers/media/platform/vivid/vivid-vid-out.c [new file with mode: 0644]
drivers/media/platform/vivid/vivid-vid-out.h [new file with mode: 0644]
drivers/media/radio/radio-gemtek.c
drivers/media/radio/radio-sf16fmi.c
drivers/media/radio/radio-sf16fmr2.c
drivers/media/radio/radio-tea5764.c
drivers/media/radio/si470x/radio-si470x-common.c
drivers/media/radio/si470x/radio-si470x-usb.c
drivers/media/radio/wl128x/fmdrv_common.c
drivers/media/radio/wl128x/fmdrv_rx.c
drivers/media/radio/wl128x/fmdrv_tx.c
drivers/media/rc/Kconfig
drivers/media/rc/Makefile
drivers/media/rc/ene_ir.c
drivers/media/rc/fintek-cir.c
drivers/media/rc/img-ir/img-ir-hw.c
drivers/media/rc/img-ir/img-ir-hw.h
drivers/media/rc/imon.c
drivers/media/rc/ir-hix5hd2.c [new file with mode: 0644]
drivers/media/rc/ite-cir.c
drivers/media/rc/keymaps/Makefile
drivers/media/rc/keymaps/rc-dvbsky.c [new file with mode: 0644]
drivers/media/rc/lirc_dev.c
drivers/media/rc/mceusb.c
drivers/media/rc/nuvoton-cir.c
drivers/media/rc/st_rc.c
drivers/media/rc/streamzap.c
drivers/media/tuners/Kconfig
drivers/media/tuners/Makefile
drivers/media/tuners/e4000.c
drivers/media/tuners/it913x.c [new file with mode: 0644]
drivers/media/tuners/it913x.h [new file with mode: 0644]
drivers/media/tuners/m88ts2022.c
drivers/media/tuners/m88ts2022_priv.h
drivers/media/tuners/msi001.c
drivers/media/tuners/mt2060.c
drivers/media/tuners/mt2063.c
drivers/media/tuners/mxl301rf.c [new file with mode: 0644]
drivers/media/tuners/mxl301rf.h [new file with mode: 0644]
drivers/media/tuners/mxl5005s.c
drivers/media/tuners/qm1d1c0042.c [new file with mode: 0644]
drivers/media/tuners/qm1d1c0042.h [new file with mode: 0644]
drivers/media/tuners/si2157.c
drivers/media/tuners/si2157.h
drivers/media/tuners/si2157_priv.h
drivers/media/tuners/tda18212.c
drivers/media/tuners/tda18212.h
drivers/media/tuners/tda18271-common.c
drivers/media/tuners/tda18271-priv.h
drivers/media/tuners/tuner-xc2028.c
drivers/media/tuners/tuner_it913x.c [deleted file]
drivers/media/tuners/tuner_it913x.h [deleted file]
drivers/media/tuners/tuner_it913x_priv.h [deleted file]
drivers/media/tuners/xc4000.c
drivers/media/tuners/xc5000.c
drivers/media/usb/Kconfig
drivers/media/usb/Makefile
drivers/media/usb/airspy/airspy.c
drivers/media/usb/as102/Kconfig [new file with mode: 0644]
drivers/media/usb/as102/Makefile [new file with mode: 0644]
drivers/media/usb/as102/as102_drv.c [new file with mode: 0644]
drivers/media/usb/as102/as102_drv.h [new file with mode: 0644]
drivers/media/usb/as102/as102_fw.c [new file with mode: 0644]
drivers/media/usb/as102/as102_fw.h [new file with mode: 0644]
drivers/media/usb/as102/as102_usb_drv.c [new file with mode: 0644]
drivers/media/usb/as102/as102_usb_drv.h [new file with mode: 0644]
drivers/media/usb/as102/as10x_cmd.c [new file with mode: 0644]
drivers/media/usb/as102/as10x_cmd.h [new file with mode: 0644]
drivers/media/usb/as102/as10x_cmd_cfg.c [new file with mode: 0644]
drivers/media/usb/as102/as10x_cmd_stream.c [new file with mode: 0644]
drivers/media/usb/as102/as10x_handle.h [new file with mode: 0644]
drivers/media/usb/au0828/au0828-cards.c
drivers/media/usb/au0828/au0828-core.c
drivers/media/usb/au0828/au0828-dvb.c
drivers/media/usb/au0828/au0828-i2c.c
drivers/media/usb/au0828/au0828-input.c
drivers/media/usb/au0828/au0828-vbi.c
drivers/media/usb/au0828/au0828-video.c
drivers/media/usb/au0828/au0828.h
drivers/media/usb/cx231xx/cx231xx-avcore.c
drivers/media/usb/cx231xx/cx231xx-cards.c
drivers/media/usb/cx231xx/cx231xx-core.c
drivers/media/usb/cx231xx/cx231xx-dvb.c
drivers/media/usb/dvb-usb-v2/Kconfig
drivers/media/usb/dvb-usb-v2/Makefile
drivers/media/usb/dvb-usb-v2/af9015.c
drivers/media/usb/dvb-usb-v2/af9035.c
drivers/media/usb/dvb-usb-v2/af9035.h
drivers/media/usb/dvb-usb-v2/anysee.c
drivers/media/usb/dvb-usb-v2/anysee.h
drivers/media/usb/dvb-usb-v2/dvb_usb.h
drivers/media/usb/dvb-usb-v2/dvb_usb_core.c
drivers/media/usb/dvb-usb-v2/dvb_usb_urb.c
drivers/media/usb/dvb-usb-v2/dvbsky.c [new file with mode: 0644]
drivers/media/usb/dvb-usb-v2/lmedm04.c
drivers/media/usb/dvb-usb-v2/mxl111sf.c
drivers/media/usb/dvb-usb/Kconfig
drivers/media/usb/dvb-usb/af9005.c
drivers/media/usb/dvb-usb/cxusb.c
drivers/media/usb/dvb-usb/cxusb.h
drivers/media/usb/dvb-usb/dib0700_devices.c
drivers/media/usb/dvb-usb/dibusb-common.c
drivers/media/usb/dvb-usb/dw2102.c
drivers/media/usb/dvb-usb/opera1.c
drivers/media/usb/dvb-usb/pctv452e.c
drivers/media/usb/em28xx/em28xx-audio.c
drivers/media/usb/em28xx/em28xx-cards.c
drivers/media/usb/em28xx/em28xx-core.c
drivers/media/usb/em28xx/em28xx-dvb.c
drivers/media/usb/em28xx/em28xx-input.c
drivers/media/usb/em28xx/em28xx-vbi.c
drivers/media/usb/em28xx/em28xx-video.c
drivers/media/usb/em28xx/em28xx.h
drivers/media/usb/go7007/go7007-usb.c
drivers/media/usb/gspca/gspca.c
drivers/media/usb/gspca/gspca.h
drivers/media/usb/gspca/kinect.c
drivers/media/usb/gspca/sn9c20x.c
drivers/media/usb/hackrf/Kconfig [new file with mode: 0644]
drivers/media/usb/hackrf/Makefile [new file with mode: 0644]
drivers/media/usb/hackrf/hackrf.c [new file with mode: 0644]
drivers/media/usb/hdpvr/hdpvr-control.c
drivers/media/usb/hdpvr/hdpvr-core.c
drivers/media/usb/msi2500/msi2500.c
drivers/media/usb/pwc/pwc-v4l.c
drivers/media/usb/s2255/s2255drv.c
drivers/media/usb/siano/smsusb.c
drivers/media/usb/ttusb-dec/ttusbdecfe.c
drivers/media/usb/usbtv/Kconfig
drivers/media/usb/usbtv/Makefile
drivers/media/usb/usbtv/usbtv-audio.c [new file with mode: 0644]
drivers/media/usb/usbtv/usbtv-core.c
drivers/media/usb/usbtv/usbtv-video.c
drivers/media/usb/usbtv/usbtv.h
drivers/media/usb/uvc/uvc_ctrl.c
drivers/media/usb/uvc/uvc_driver.c
drivers/media/usb/uvc/uvc_v4l2.c
drivers/media/usb/uvc/uvc_video.c
drivers/media/usb/uvc/uvcvideo.h
drivers/media/v4l2-core/tuner-core.c
drivers/media/v4l2-core/v4l2-common.c
drivers/media/v4l2-core/v4l2-compat-ioctl32.c
drivers/media/v4l2-core/v4l2-ctrls.c
drivers/media/v4l2-core/v4l2-dv-timings.c
drivers/media/v4l2-core/v4l2-ioctl.c
drivers/media/v4l2-core/v4l2-subdev.c
drivers/media/v4l2-core/videobuf-core.c
drivers/media/v4l2-core/videobuf-dma-sg.c
drivers/media/v4l2-core/videobuf2-core.c
drivers/memstick/host/r592.c
drivers/mfd/Kconfig
drivers/mfd/Makefile
drivers/mfd/menf21bmc.c [new file with mode: 0644]
drivers/misc/Kconfig
drivers/misc/Makefile
drivers/misc/altera-stapl/altera.c
drivers/misc/carma/carma-fpga-program.c
drivers/misc/cxl/Kconfig [new file with mode: 0644]
drivers/misc/cxl/Makefile [new file with mode: 0644]
drivers/misc/cxl/base.c [new file with mode: 0644]
drivers/misc/cxl/context.c [new file with mode: 0644]
drivers/misc/cxl/cxl.h [new file with mode: 0644]
drivers/misc/cxl/debugfs.c [new file with mode: 0644]
drivers/misc/cxl/fault.c [new file with mode: 0644]
drivers/misc/cxl/file.c [new file with mode: 0644]
drivers/misc/cxl/irq.c [new file with mode: 0644]
drivers/misc/cxl/main.c [new file with mode: 0644]
drivers/misc/cxl/native.c [new file with mode: 0644]
drivers/misc/cxl/pci.c [new file with mode: 0644]
drivers/misc/cxl/sysfs.c [new file with mode: 0644]
drivers/mmc/card/block.c
drivers/mmc/card/queue.c
drivers/mmc/card/sdio_uart.c
drivers/mmc/core/core.c
drivers/mmc/core/host.c
drivers/mmc/core/mmc.c
drivers/mmc/core/mmc_ops.c
drivers/mmc/core/mmc_ops.h
drivers/mmc/core/sd.c
drivers/mmc/core/sdio.c
drivers/mmc/core/sdio_bus.c
drivers/mmc/core/sdio_irq.c
drivers/mmc/core/slot-gpio.c
drivers/mmc/host/Kconfig
drivers/mmc/host/Makefile
drivers/mmc/host/atmel-mci.c
drivers/mmc/host/au1xmmc.c
drivers/mmc/host/dw_mmc-pci.c
drivers/mmc/host/dw_mmc-pltfm.c
drivers/mmc/host/dw_mmc-rockchip.c [new file with mode: 0644]
drivers/mmc/host/dw_mmc.c
drivers/mmc/host/dw_mmc.h
drivers/mmc/host/jz4740_mmc.c
drivers/mmc/host/mmc_spi.c
drivers/mmc/host/mmci.c
drivers/mmc/host/mmci_qcom_dml.c [new file with mode: 0644]
drivers/mmc/host/mmci_qcom_dml.h [new file with mode: 0644]
drivers/mmc/host/moxart-mmc.c
drivers/mmc/host/mxcmmc.c
drivers/mmc/host/mxs-mmc.c
drivers/mmc/host/omap.c
drivers/mmc/host/omap_hsmmc.c
drivers/mmc/host/pxamci.c
drivers/mmc/host/rtsx_pci_sdmmc.c
drivers/mmc/host/rtsx_usb_sdmmc.c
drivers/mmc/host/s3cmci.c
drivers/mmc/host/sdhci-acpi.c
drivers/mmc/host/sdhci-bcm-kona.c
drivers/mmc/host/sdhci-bcm2835.c
drivers/mmc/host/sdhci-cns3xxx.c
drivers/mmc/host/sdhci-dove.c
drivers/mmc/host/sdhci-esdhc-imx.c
drivers/mmc/host/sdhci-msm.c
drivers/mmc/host/sdhci-of-arasan.c
drivers/mmc/host/sdhci-of-esdhc.c
drivers/mmc/host/sdhci-of-hlwd.c
drivers/mmc/host/sdhci-pci.c
drivers/mmc/host/sdhci-pci.h
drivers/mmc/host/sdhci-pltfm.c
drivers/mmc/host/sdhci-pxav2.c
drivers/mmc/host/sdhci-pxav3.c
drivers/mmc/host/sdhci-s3c.c
drivers/mmc/host/sdhci-sirf.c
drivers/mmc/host/sdhci-spear.c
drivers/mmc/host/sdhci-tegra.c
drivers/mmc/host/sdhci.c
drivers/mmc/host/sdhci.h
drivers/mmc/host/sh_mmcif.c
drivers/mmc/host/sh_mobile_sdhi.c
drivers/mmc/host/sunxi-mmc.c
drivers/mmc/host/tifm_sd.c
drivers/mmc/host/tmio_mmc.c
drivers/mmc/host/tmio_mmc.h
drivers/mmc/host/tmio_mmc_dma.c
drivers/mmc/host/tmio_mmc_pio.c
drivers/mmc/host/wbsd.c
drivers/mtd/ubi/block.c
drivers/mtd/ubi/cdev.c
drivers/mtd/ubi/eba.c
drivers/mtd/ubi/fastmap.c
drivers/mtd/ubi/ubi.h
drivers/mtd/ubi/wl.c
drivers/net/ethernet/apm/xgene/Makefile
drivers/net/ethernet/apm/xgene/xgene_enet_ethtool.c
drivers/net/ethernet/apm/xgene/xgene_enet_hw.c
drivers/net/ethernet/apm/xgene/xgene_enet_hw.h
drivers/net/ethernet/apm/xgene/xgene_enet_main.c
drivers/net/ethernet/apm/xgene/xgene_enet_main.h
drivers/net/ethernet/apm/xgene/xgene_enet_xgmac.c [new file with mode: 0644]
drivers/net/ethernet/apm/xgene/xgene_enet_xgmac.h [new file with mode: 0644]
drivers/net/ethernet/broadcom/bcmsysport.c
drivers/net/ethernet/broadcom/genet/bcmgenet.c
drivers/net/ethernet/broadcom/genet/bcmgenet_wol.c
drivers/net/ethernet/chelsio/cxgb4/cxgb4.h
drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
drivers/net/ethernet/chelsio/cxgb4/sge.c
drivers/net/ethernet/chelsio/cxgb4/t4_hw.c
drivers/net/ethernet/chelsio/cxgb4/t4_msg.h
drivers/net/ethernet/chelsio/cxgb4/t4_regs.h
drivers/net/ethernet/chelsio/cxgb4vf/cxgb4vf_main.c
drivers/net/ethernet/chelsio/cxgb4vf/sge.c
drivers/net/ethernet/chelsio/cxgb4vf/t4vf_common.h
drivers/net/ethernet/chelsio/cxgb4vf/t4vf_hw.c
drivers/net/ethernet/freescale/fs_enet/mac-fcc.c
drivers/net/ethernet/freescale/fs_enet/mac-scc.c
drivers/net/ethernet/freescale/fsl_pq_mdio.c
drivers/net/ethernet/freescale/gianfar.c
drivers/net/ethernet/freescale/gianfar.h
drivers/net/ethernet/intel/Kconfig
drivers/net/ethernet/intel/fm10k/fm10k_main.c
drivers/net/ethernet/intel/igb/igb_main.c
drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
drivers/net/ethernet/marvell/Kconfig
drivers/net/ethernet/mellanox/mlx4/en_rx.c
drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c
drivers/net/ethernet/sun/sunvnet.c
drivers/net/macvlan.c
drivers/net/phy/micrel.c
drivers/net/ppp/ppp_generic.c
drivers/net/tun.c
drivers/net/usb/r8152.c
drivers/net/wimax/Makefile
drivers/net/wireless/ath/ath9k/ath9k.h
drivers/net/wireless/ath/ath9k/beacon.c
drivers/net/wireless/ath/ath9k/htc_drv_init.c
drivers/net/wireless/ath/ath9k/main.c
drivers/net/wireless/ath/ath9k/tx99.c
drivers/net/wireless/ath/ath9k/xmit.c
drivers/net/wireless/ath/main.c
drivers/net/wireless/hostap/hostap_proc.c
drivers/net/wireless/ipw2x00/ipw2100.c
drivers/net/wireless/ipw2x00/ipw2200.c
drivers/net/wireless/ipw2x00/libipw_rx.c
drivers/net/wireless/ipw2x00/libipw_wx.c
drivers/net/wireless/libertas/cfg.c
drivers/net/wireless/libertas/mesh.c
drivers/net/wireless/rtl818x/rtl8180/dev.c
drivers/net/wireless/rtlwifi/wifi.h
drivers/net/xen-netback/xenbus.c
drivers/net/xen-netfront.c
drivers/of/Kconfig
drivers/of/Makefile
drivers/of/base.c
drivers/of/resolver.c [new file with mode: 0644]
drivers/of/selftest.c
drivers/of/testcase-data/testcases.dts
drivers/parisc/power.c
drivers/pci/msi.c
drivers/pci/xen-pcifront.c
drivers/platform/x86/dell-wmi.c
drivers/platform/x86/eeepc-laptop.c
drivers/platform/x86/intel-rst.c
drivers/platform/x86/thinkpad_acpi.c
drivers/platform/x86/toshiba_acpi.c
drivers/pnp/interface.c
drivers/power/reset/restart-poweroff.c
drivers/rtc/Kconfig
drivers/rtc/Makefile
drivers/rtc/rtc-bq32k.c
drivers/rtc/rtc-cmos.c
drivers/rtc/rtc-ds1307.c
drivers/rtc/rtc-isl12022.c
drivers/rtc/rtc-max77686.c
drivers/rtc/rtc-max77802.c [new file with mode: 0644]
drivers/rtc/rtc-mpc5121.c
drivers/rtc/rtc-pcf8563.c
drivers/rtc/rtc-pcf8583.c
drivers/rtc/rtc-rk808.c [new file with mode: 0644]
drivers/rtc/rtc-rs5c372.c
drivers/rtc/rtc-s3c.c
drivers/s390/block/dasd.c
drivers/s390/block/dasd_devmap.c
drivers/s390/block/dasd_eckd.c
drivers/s390/block/dasd_eckd.h
drivers/s390/block/dasd_int.h
drivers/s390/char/Kconfig
drivers/s390/char/Makefile
drivers/s390/char/diag_ftp.c [new file with mode: 0644]
drivers/s390/char/diag_ftp.h [new file with mode: 0644]
drivers/s390/char/hmcdrv_cache.c [new file with mode: 0644]
drivers/s390/char/hmcdrv_cache.h [new file with mode: 0644]
drivers/s390/char/hmcdrv_dev.c [new file with mode: 0644]
drivers/s390/char/hmcdrv_dev.h [new file with mode: 0644]
drivers/s390/char/hmcdrv_ftp.c [new file with mode: 0644]
drivers/s390/char/hmcdrv_ftp.h [new file with mode: 0644]
drivers/s390/char/hmcdrv_mod.c [new file with mode: 0644]
drivers/s390/char/sclp.h
drivers/s390/char/sclp_diag.h [new file with mode: 0644]
drivers/s390/char/sclp_early.c
drivers/s390/char/sclp_ftp.c [new file with mode: 0644]
drivers/s390/char/sclp_ftp.h [new file with mode: 0644]
drivers/s390/char/sclp_rw.c
drivers/s390/char/sclp_vt220.c
drivers/s390/char/tape_char.c
drivers/s390/char/vmlogrdr.c
drivers/s390/char/zcore.c
drivers/s390/cio/airq.c
drivers/s390/cio/chp.c
drivers/s390/cio/cio.c
drivers/s390/crypto/ap_bus.c
drivers/s390/crypto/ap_bus.h
drivers/s390/crypto/zcrypt_api.c
drivers/s390/net/claw.c
drivers/scsi/Kconfig
drivers/scsi/Makefile
drivers/scsi/fcoe/fcoe.c
drivers/scsi/ips.c
drivers/scsi/qla2xxx/qla_os.c
drivers/scsi/scsi_debug.c
drivers/scsi/xen-scsifront.c [new file with mode: 0644]
drivers/staging/android/ashmem.c
drivers/staging/android/ion/compat_ion.c
drivers/staging/android/logger.c
drivers/staging/imx-drm/imx-drm-core.c
drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd_cb.c
drivers/staging/lustre/lnet/klnds/socklnd/socklnd_cb.c
drivers/staging/lustre/lustre/libcfs/fail.c
drivers/staging/media/Kconfig
drivers/staging/media/Makefile
drivers/staging/media/as102/Kconfig [deleted file]
drivers/staging/media/as102/Makefile [deleted file]
drivers/staging/media/as102/as102_drv.c [deleted file]
drivers/staging/media/as102/as102_drv.h [deleted file]
drivers/staging/media/as102/as102_fe.c [deleted file]
drivers/staging/media/as102/as102_fw.c [deleted file]
drivers/staging/media/as102/as102_fw.h [deleted file]
drivers/staging/media/as102/as102_usb_drv.c [deleted file]
drivers/staging/media/as102/as102_usb_drv.h [deleted file]
drivers/staging/media/as102/as10x_cmd.c [deleted file]
drivers/staging/media/as102/as10x_cmd.h [deleted file]
drivers/staging/media/as102/as10x_cmd_cfg.c [deleted file]
drivers/staging/media/as102/as10x_cmd_stream.c [deleted file]
drivers/staging/media/as102/as10x_handle.h [deleted file]
drivers/staging/media/as102/as10x_types.h [deleted file]
drivers/staging/media/davinci_vpfe/Kconfig
drivers/staging/media/dt3155v4l/Kconfig
drivers/staging/media/lirc/lirc_imon.c
drivers/staging/media/lirc/lirc_sasem.c
drivers/staging/media/omap4iss/Kconfig
drivers/staging/rtl8188eu/os_dep/rtw_android.c
drivers/staging/rtl8192e/rtllib.h
drivers/staging/rtl8192u/ieee80211/ieee80211.h
drivers/staging/vme/devices/vme_user.c
drivers/staging/wlan-ng/prism2sta.c
drivers/thermal/thermal_core.c
drivers/tty/bfin_jtag_comm.c
drivers/tty/hvc/hvc_vio.c
drivers/tty/hvc/hvc_xen.c
drivers/tty/tty_io.c
drivers/usb/gadget/function/f_fs.c
drivers/usb/gadget/legacy/inode.c
drivers/vfio/pci/vfio_pci.c
drivers/vfio/pci/vfio_pci_intrs.c
drivers/vfio/vfio_iommu_type1.c
drivers/vfio/vfio_spapr_eeh.c
drivers/video/backlight/88pm860x_bl.c
drivers/video/backlight/aat2870_bl.c
drivers/video/backlight/adp5520_bl.c
drivers/video/backlight/adp8860_bl.c
drivers/video/backlight/adp8870_bl.c
drivers/video/backlight/ams369fg06.c
drivers/video/backlight/as3711_bl.c
drivers/video/backlight/corgi_lcd.c
drivers/video/backlight/cr_bllcd.c
drivers/video/backlight/da903x_bl.c
drivers/video/backlight/da9052_bl.c
drivers/video/backlight/ep93xx_bl.c
drivers/video/backlight/generic_bl.c
drivers/video/backlight/gpio_backlight.c
drivers/video/backlight/ili922x.c
drivers/video/backlight/jornada720_bl.c
drivers/video/backlight/jornada720_lcd.c
drivers/video/backlight/ld9040.c
drivers/video/backlight/lm3533_bl.c
drivers/video/backlight/lm3639_bl.c
drivers/video/backlight/lms501kf03.c
drivers/video/backlight/lp855x_bl.c
drivers/video/backlight/lp8788_bl.c
drivers/video/backlight/max8925_bl.c
drivers/video/backlight/omap1_bl.c
drivers/video/backlight/ot200_bl.c
drivers/video/backlight/pandora_bl.c
drivers/video/backlight/pcf50633-backlight.c
drivers/video/backlight/platform_lcd.c
drivers/video/backlight/pwm_bl.c
drivers/video/backlight/s6e63m0.c
drivers/video/backlight/tdo24m.c
drivers/video/backlight/tps65217_bl.c
drivers/video/backlight/wm831x_bl.c
drivers/video/fbdev/Kconfig
drivers/video/fbdev/core/Makefile
drivers/video/fbdev/core/fb_cmdline.c [new file with mode: 0644]
drivers/video/fbdev/core/fbmem.c
drivers/video/fbdev/core/modedb.c
drivers/video/fbdev/pvr2fb.c
drivers/video/fbdev/s3c2410fb.c
drivers/video/fbdev/sis/sis_main.c
drivers/video/fbdev/sm501fb.c
drivers/video/fbdev/xen-fbfront.c
drivers/watchdog/Kconfig
drivers/watchdog/Makefile
drivers/watchdog/alim7101_wdt.c
drivers/watchdog/menf21bmc_wdt.c [new file with mode: 0644]
drivers/watchdog/moxart_wdt.c
drivers/watchdog/sunxi_wdt.c
drivers/xen/Kconfig
drivers/xen/Makefile
drivers/xen/efi.c
drivers/xen/events/events_base.c
drivers/xen/grant-table.c
drivers/xen/xen-pciback/xenbus.c
drivers/xen/xen-scsiback.c [new file with mode: 0644]
drivers/xen/xenbus/xenbus_client.c
drivers/xen/xenbus/xenbus_probe.c
drivers/xen/xenbus/xenbus_probe.h
drivers/xen/xenbus/xenbus_probe_backend.c
drivers/xen/xenbus/xenbus_probe_frontend.c
firmware/Makefile
fs/9p/fid.c
fs/9p/vfs_addr.c
fs/9p/vfs_dentry.c
fs/9p/vfs_dir.c
fs/9p/vfs_file.c
fs/9p/vfs_inode.c
fs/9p/vfs_inode_dotl.c
fs/affs/amigaffs.c
fs/affs/file.c
fs/affs/inode.c
fs/affs/super.c
fs/afs/dir.c
fs/afs/vlocation.c
fs/autofs4/autofs_i.h
fs/autofs4/dev-ioctl.c
fs/autofs4/expire.c
fs/autofs4/root.c
fs/befs/btree.c
fs/binfmt_aout.c
fs/binfmt_elf.c
fs/binfmt_elf_fdpic.c
fs/binfmt_misc.c
fs/btrfs/async-thread.c
fs/btrfs/async-thread.h
fs/btrfs/backref.c
fs/btrfs/backref.h
fs/btrfs/btrfs_inode.h
fs/btrfs/check-integrity.c
fs/btrfs/compression.c
fs/btrfs/ctree.c
fs/btrfs/ctree.h
fs/btrfs/delayed-inode.c
fs/btrfs/dev-replace.c
fs/btrfs/dir-item.c
fs/btrfs/disk-io.c
fs/btrfs/disk-io.h
fs/btrfs/export.c
fs/btrfs/extent-tree.c
fs/btrfs/extent_io.c
fs/btrfs/extent_io.h
fs/btrfs/file-item.c
fs/btrfs/file.c
fs/btrfs/free-space-cache.c
fs/btrfs/hash.c
fs/btrfs/inode-item.c
fs/btrfs/inode-map.c
fs/btrfs/inode.c
fs/btrfs/ioctl.c
fs/btrfs/lzo.c
fs/btrfs/orphan.c
fs/btrfs/print-tree.c
fs/btrfs/qgroup.c
fs/btrfs/raid56.c
fs/btrfs/reada.c
fs/btrfs/relocation.c
fs/btrfs/scrub.c
fs/btrfs/send.c
fs/btrfs/super.c
fs/btrfs/sysfs.c
fs/btrfs/sysfs.h
fs/btrfs/tests/free-space-tests.c
fs/btrfs/transaction.c
fs/btrfs/transaction.h
fs/btrfs/tree-log.c
fs/btrfs/tree-log.h
fs/btrfs/uuid-tree.c
fs/btrfs/volumes.c
fs/btrfs/volumes.h
fs/btrfs/xattr.c
fs/btrfs/zlib.c
fs/buffer.c
fs/cachefiles/interface.c
fs/cachefiles/namei.c
fs/cachefiles/rdwr.c
fs/ceph/dir.c
fs/cifs/cifs_dfs_ref.c
fs/cifs/cifs_spnego.c
fs/cifs/cifsacl.c
fs/cifs/cifsfs.c
fs/cifs/connect.c
fs/cifs/dir.c
fs/cifs/file.c
fs/cifs/inode.c
fs/cifs/readdir.c
fs/compat.c
fs/coredump.c
fs/dcache.c
fs/dlm/plock.c
fs/ecryptfs/file.c
fs/ecryptfs/inode.c
fs/ecryptfs/keystore.c
fs/ecryptfs/messaging.c
fs/exec.c
fs/ext3/ext3.h
fs/ext3/super.c
fs/fat/misc.c
fs/fcntl.c
fs/file.c
fs/file_table.c
fs/fscache/object-list.c
fs/fuse/dir.c
fs/gfs2/dentry.c
fs/gfs2/dir.c
fs/gfs2/dir.h
fs/gfs2/file.c
fs/gfs2/glock.c
fs/gfs2/glops.c
fs/gfs2/inode.c
fs/gfs2/rgrp.c
fs/gfs2/rgrp.h
fs/gfs2/trans.c
fs/hfs/hfs_fs.h
fs/internal.h
fs/isofs/inode.c
fs/jffs2/jffs2_fs_sb.h
fs/jffs2/wbuf.c
fs/jfs/jfs_logmgr.c
fs/jfs/jfs_txnmgr.c
fs/jfs/super.c
fs/kernfs/dir.c
fs/libfs.c
fs/lockd/svclock.c
fs/locks.c
fs/mount.h
fs/namei.c
fs/namespace.c
fs/ncpfs/dir.c
fs/ncpfs/ncplib_kernel.h
fs/nfs/blocklayout/rpc_pipefs.c
fs/nfs/dir.c
fs/nfs/file.c
fs/nfs/idmap.c
fs/nfs/internal.h
fs/nfs/nfs4file.c
fs/nfsd/nfs4recover.c
fs/nfsd/nfs4state.c
fs/nfsd/state.h
fs/nfsd/vfs.c
fs/nilfs2/file.c
fs/nilfs2/inode.c
fs/nilfs2/ioctl.c
fs/nilfs2/nilfs.h
fs/nilfs2/segment.c
fs/nilfs2/super.c
fs/nilfs2/the_nilfs.h
fs/notify/dnotify/dnotify.c
fs/ocfs2/cluster/heartbeat.c
fs/ocfs2/cluster/masklog.c
fs/ocfs2/file.c
fs/ocfs2/quota.h
fs/ocfs2/quota_global.c
fs/ocfs2/quota_local.c
fs/ocfs2/super.c
fs/omfs/inode.c
fs/omfs/omfs_fs.h
fs/proc/base.c
fs/proc/fd.c
fs/proc/task_mmu.c
fs/read_write.c
fs/reiserfs/journal.c
fs/reiserfs/reiserfs.h
fs/reiserfs/super.c
fs/reiserfs/xattr.h
fs/super.c
fs/ubifs/commit.c
fs/ubifs/debug.c
fs/ubifs/journal.c
fs/ubifs/log.c
fs/udf/file.c
fs/udf/inode.c
fs/udf/super.c
fs/udf/udfdecl.h
fs/udf/udftime.c
fs/ufs/balloc.c
fs/xattr.c
fs/xfs/kmem.c
fs/xfs/libxfs/xfs_alloc.c
fs/xfs/libxfs/xfs_bmap.c
fs/xfs/libxfs/xfs_bmap.h
fs/xfs/libxfs/xfs_da_btree.c
fs/xfs/libxfs/xfs_da_format.c
fs/xfs/libxfs/xfs_dir2.c
fs/xfs/libxfs/xfs_dir2.h
fs/xfs/libxfs/xfs_ialloc.c
fs/xfs/libxfs/xfs_rtbitmap.c
fs/xfs/libxfs/xfs_sb.c
fs/xfs/time.h [deleted file]
fs/xfs/xfs_aops.c
fs/xfs/xfs_bmap_util.c
fs/xfs/xfs_buf.c
fs/xfs/xfs_buf.h
fs/xfs/xfs_buf_item.c
fs/xfs/xfs_file.c
fs/xfs/xfs_fsops.c
fs/xfs/xfs_globals.c
fs/xfs/xfs_icache.c
fs/xfs/xfs_inode.c
fs/xfs/xfs_inode.h
fs/xfs/xfs_inode_item.c
fs/xfs/xfs_ioctl.c
fs/xfs/xfs_ioctl32.c
fs/xfs/xfs_ioctl32.h
fs/xfs/xfs_iomap.c
fs/xfs/xfs_iops.c
fs/xfs/xfs_itable.c
fs/xfs/xfs_linux.h
fs/xfs/xfs_log.c
fs/xfs/xfs_log_cil.c
fs/xfs/xfs_log_recover.c
fs/xfs/xfs_mount.c
fs/xfs/xfs_mru_cache.c
fs/xfs/xfs_qm.c
fs/xfs/xfs_rtalloc.c
fs/xfs/xfs_rtalloc.h
fs/xfs/xfs_super.c
fs/xfs/xfs_symlink.c
fs/xfs/xfs_sysctl.h
fs/xfs/xfs_sysfs.c
fs/xfs/xfs_sysfs.h
fs/xfs/xfs_trace.h
fs/xfs/xfs_trans_buf.c
fs/xfs/xfs_trans_inode.c
include/asm-generic/atomic.h
include/asm-generic/atomic64.h
include/asm-generic/cputime_jiffies.h
include/asm-generic/cputime_nsecs.h
include/asm-generic/dma-mapping-common.h
include/asm-generic/pgtable.h
include/crypto/public_key.h
include/drm/ati_pcigart.h [new file with mode: 0644]
include/drm/drmP.h
include/drm/drm_agpsupport.h
include/drm/drm_buffer.h [deleted file]
include/drm/drm_crtc.h
include/drm/drm_dp_helper.h
include/drm/drm_dp_mst_helper.h
include/drm/drm_fb_helper.h
include/drm/drm_gem.h [new file with mode: 0644]
include/drm/drm_gem_cma_helper.h
include/drm/drm_legacy.h [new file with mode: 0644]
include/drm/drm_memory.h [deleted file]
include/drm/drm_mipi_dsi.h
include/drm/drm_modeset_lock.h
include/drm/drm_usb.h [deleted file]
include/drm/ttm/ttm_bo_api.h
include/drm/ttm/ttm_bo_driver.h
include/drm/ttm/ttm_execbuf_util.h
include/dt-bindings/sound/cs35l32.h [new file with mode: 0644]
include/keys/asymmetric-type.h
include/keys/user-type.h
include/linux/atmel-mci.h
include/linux/atomic.h
include/linux/bitops.h
include/linux/cma.h
include/linux/compiler-gcc5.h [new file with mode: 0644]
include/linux/cpu.h
include/linux/dcache.h
include/linux/dma-mapping.h
include/linux/fs.h
include/linux/fsl_ifc.h
include/linux/ftrace.h
include/linux/ima.h
include/linux/init_task.h
include/linux/iommu.h
include/linux/jump_label.h
include/linux/kernel.h
include/linux/kexec.h
include/linux/key-type.h
include/linux/list.h
include/linux/lockd/lockd.h
include/linux/lockdep.h
include/linux/mfd/tmio.h
include/linux/micrel_phy.h
include/linux/mm.h
include/linux/mmc/card.h
include/linux/mmc/dw_mmc.h
include/linux/mmc/host.h
include/linux/mmc/mmc.h
include/linux/mmc/sdhci.h
include/linux/mmc/slot-gpio.h
include/linux/moduleparam.h
include/linux/mutex.h
include/linux/nmi.h
include/linux/of.h
include/linux/pci_ids.h
include/linux/perf_event.h
include/linux/platform_data/rcar-du.h
include/linux/prio_heap.h [deleted file]
include/linux/rbtree_augmented.h
include/linux/rcupdate.h
include/linux/rcutiny.h
include/linux/reboot.h
include/linux/rwsem.h
include/linux/sched.h
include/linux/seccomp.h
include/linux/security.h
include/linux/seqlock.h
include/linux/signal.h
include/linux/smp.h
include/linux/spinlock.h
include/linux/string.h
include/linux/string_helpers.h
include/linux/tick.h
include/linux/torture.h
include/linux/tracepoint.h
include/linux/uio.h
include/linux/wait.h
include/media/davinci/dm644x_ccdc.h
include/media/omap3isp.h
include/media/rc-map.h
include/media/videobuf2-core.h
include/misc/cxl.h [new file with mode: 0644]
include/net/lib80211.h
include/net/netfilter/ipv6/nf_reject.h
include/sound/pcm.h
include/sound/rt5645.h
include/sound/rt5677.h
include/sound/soc-dapm.h
include/sound/soc.h
include/sound/vx_core.h
include/trace/events/asoc.h
include/trace/events/btrfs.h
include/trace/events/filelock.h
include/trace/events/rcu.h
include/uapi/Kbuild
include/uapi/drm/exynos_drm.h
include/uapi/drm/radeon_drm.h
include/uapi/drm/vmwgfx_drm.h
include/uapi/linux/Kbuild
include/uapi/linux/elf.h
include/uapi/linux/netfilter/nf_tables.h
include/uapi/linux/smiapp.h [new file with mode: 0644]
include/uapi/linux/v4l2-controls.h
include/uapi/linux/v4l2-dv-timings.h
include/uapi/linux/vfio.h
include/uapi/linux/videodev2.h
include/uapi/misc/Kbuild [new file with mode: 0644]
include/uapi/misc/cxl.h [new file with mode: 0644]
include/uapi/sound/asound.h
include/video/imx-ipu-v3.h
include/xen/events.h
include/xen/interface/elfnote.h
include/xen/interface/io/vscsiif.h [new file with mode: 0644]
include/xen/interface/xen.h
include/xen/xenbus.h
init/Kconfig
init/initramfs.c
init/main.c
ipc/compat.c
ipc/ipc_sysctl.c
ipc/shm.c
ipc/util.c
kernel/cpu.c
kernel/debug/kdb/kdb_bp.c
kernel/events/callchain.c
kernel/events/core.c
kernel/exit.c
kernel/fork.c
kernel/kallsyms.c
kernel/kexec.c
kernel/locking/locktorture.c
kernel/locking/mcs_spinlock.h
kernel/locking/mutex.c
kernel/locking/mutex.h
kernel/locking/rtmutex.c
kernel/locking/rwsem-xadd.c
kernel/locking/semaphore.c
kernel/params.c
kernel/printk/printk.c
kernel/rcu/rcutorture.c
kernel/rcu/tiny.c
kernel/rcu/tree.c
kernel/rcu/tree.h
kernel/rcu/tree_plugin.h
kernel/rcu/update.c
kernel/reboot.c
kernel/resource.c
kernel/sched/auto_group.c
kernel/sched/core.c
kernel/sched/cpudeadline.c
kernel/sched/cputime.c
kernel/sched/deadline.c
kernel/sched/debug.c
kernel/sched/fair.c
kernel/sched/idle.c
kernel/sched/rt.c
kernel/sched/sched.h
kernel/sched/stop_task.c
kernel/seccomp.c
kernel/smp.c
kernel/softirq.c
kernel/sys.c
kernel/sysctl.c
kernel/time/hrtimer.c
kernel/time/posix-cpu-timers.c
kernel/time/tick-sched.c
kernel/torture.c
kernel/trace/ftrace.c
kernel/trace/ring_buffer_benchmark.c
kernel/trace/trace_events.c
kernel/trace/trace_selftest.c
kernel/trace/trace_stack.c
kernel/trace/trace_syscalls.c
kernel/watchdog.c
kernel/workqueue.c
lib/Kconfig.debug
lib/Makefile
lib/atomic64.c
lib/dynamic_debug.c
lib/hexdump.c
lib/prio_heap.c [deleted file]
lib/string.c
lib/string_helpers.c
lib/test-string_helpers.c
lib/textsearch.c
lib/vsprintf.c
mm/Makefile
mm/cma.c
mm/iov_iter.c
mm/memory.c
mm/mlock.c
mm/mmap.c
mm/mprotect.c
mm/page_alloc.c
mm/slab.c
net/Kconfig
net/batman-adv/gateway_common.c
net/ceph/crypto.c
net/core/filter.c
net/core/flow_dissector.c
net/core/skbuff.c
net/dns_resolver/dns_key.c
net/netfilter/ipvs/ip_vs_ftp.c
net/netfilter/nf_conntrack_ftp.c
net/netfilter/nf_conntrack_sip.c
net/netfilter/nf_log.c
net/netfilter/nf_nat_sip.c
net/netfilter/nft_reject.c
net/netlabel/netlabel_kapi.c
net/netlink/af_netlink.c
net/rfkill/core.c
net/rxrpc/ar-key.c
net/sched/sch_generic.c
net/socket.c
net/wireless/lib80211.c
scripts/Kbuild.include
scripts/Makefile.build
scripts/Makefile.clean
scripts/Makefile.fwinst
scripts/Makefile.host
scripts/Makefile.lib
scripts/bootgraph.pl [changed mode: 0644->0755]
scripts/checkpatch.pl
scripts/coccinelle/misc/simple_return.cocci [new file with mode: 0644]
scripts/export_report.pl [changed mode: 0644->0755]
scripts/gcc-goto.sh [changed mode: 0644->0755]
scripts/gcc-ld [changed mode: 0644->0755]
scripts/gcc-version.sh [changed mode: 0644->0755]
scripts/gcc-x86_32-has-stack-protector.sh [changed mode: 0644->0755]
scripts/gcc-x86_64-has-stack-protector.sh [changed mode: 0644->0755]
scripts/gen_initramfs_list.sh [changed mode: 0644->0755]
scripts/headers_check.pl [changed mode: 0644->0755]
scripts/headers_install.sh [changed mode: 0644->0755]
scripts/kconfig/Makefile
scripts/kconfig/lxdialog/check-lxdialog.sh [changed mode: 0644->0755]
scripts/kconfig/lxdialog/dialog.h
scripts/kconfig/streamline_config.pl [changed mode: 0644->0755]
scripts/link-vmlinux.sh [changed mode: 0644->0755]
scripts/markup_oops.pl [changed mode: 0644->0755]
scripts/mkmakefile [changed mode: 0644->0755]
scripts/mksysmap [changed mode: 0644->0755]
scripts/package/builddeb [changed mode: 0644->0755]
scripts/package/buildtar [changed mode: 0644->0755]
scripts/profile2linkerlist.pl [changed mode: 0644->0755]
scripts/recordmcount.c
scripts/recordmcount.pl
scripts/rt-tester/rt-tester.py [changed mode: 0644->0755]
scripts/selinux/install_policy.sh [changed mode: 0644->0755]
scripts/sortextable.h
scripts/spelling.txt [new file with mode: 0644]
scripts/tags.sh
scripts/tracing/draw_functrace.py [changed mode: 0644->0755]
scripts/xz_wrap.sh [changed mode: 0644->0755]
security/capability.c
security/integrity/Kconfig
security/integrity/Makefile
security/integrity/digsig_asymmetric.c
security/integrity/evm/Kconfig
security/integrity/evm/evm_main.c
security/integrity/ima/Kconfig
security/integrity/ima/ima.h
security/integrity/ima/ima_api.c
security/integrity/ima/ima_appraise.c
security/integrity/ima/ima_crypto.c
security/integrity/ima/ima_init.c
security/integrity/ima/ima_main.c
security/integrity/ima/ima_policy.c
security/integrity/ima/ima_template.c
security/integrity/integrity.h
security/keys/big_key.c
security/keys/encrypted-keys/encrypted.c
security/keys/internal.h
security/keys/key.c
security/keys/keyctl.c
security/keys/keyring.c
security/keys/proc.c
security/keys/process_keys.c
security/keys/request_key.c
security/keys/request_key_auth.c
security/keys/trusted.c
security/keys/user_defined.c
security/security.c
security/selinux/hooks.c
security/selinux/include/netif.h
security/selinux/include/objsec.h
security/selinux/netif.c
security/selinux/ss/services.c
security/smack/Kconfig
security/smack/smack.h
security/smack/smack_access.c
security/smack/smack_lsm.c
security/smack/smackfs.c
sound/core/misc.c
sound/core/pcm.c
sound/core/pcm_lib.c
sound/core/pcm_misc.c
sound/core/pcm_native.c
sound/drivers/vx/vx_core.c
sound/drivers/vx/vx_mixer.c
sound/drivers/vx/vx_pcm.c
sound/drivers/vx/vx_uer.c
sound/pci/au88x0/au88x0.c
sound/pci/au88x0/au88x0_a3d.c
sound/pci/au88x0/au88x0_core.c
sound/pci/au88x0/au88x0_eq.c
sound/pci/au88x0/au88x0_game.c
sound/pci/au88x0/au88x0_mpu401.c
sound/pci/au88x0/au88x0_pcm.c
sound/pci/au88x0/au88x0_synth.c
sound/pci/ctxfi/ctamixer.c
sound/pci/ctxfi/ctamixer.h
sound/pci/ctxfi/ctatc.c
sound/pci/ctxfi/ctatc.h
sound/pci/ctxfi/ctdaio.c
sound/pci/ctxfi/ctdaio.h
sound/pci/ctxfi/cthardware.h
sound/pci/ctxfi/cthw20k1.c
sound/pci/ctxfi/cthw20k2.c
sound/pci/ctxfi/ctmixer.c
sound/pci/ctxfi/ctpcm.c
sound/pci/ctxfi/ctresource.c
sound/pci/ctxfi/ctresource.h
sound/pci/ctxfi/ctsrc.c
sound/pci/ctxfi/ctsrc.h
sound/pci/ctxfi/ctvmem.c
sound/pci/ctxfi/xfi.c
sound/pci/hda/hda_auto_parser.c
sound/pci/hda/hda_auto_parser.h
sound/pci/hda/hda_codec.c
sound/pci/hda/hda_codec.h
sound/pci/hda/hda_generic.c
sound/pci/hda/hda_generic.h
sound/pci/hda/hda_jack.c
sound/pci/hda/hda_jack.h
sound/pci/hda/hda_local.h
sound/pci/hda/hda_sysfs.c
sound/pci/hda/patch_ca0132.c
sound/pci/hda/patch_cirrus.c
sound/pci/hda/patch_conexant.c
sound/pci/hda/patch_hdmi.c
sound/pci/hda/patch_realtek.c
sound/pci/hda/patch_sigmatel.c
sound/pci/hda/patch_via.c
sound/pci/ice1712/ice1712.c
sound/pci/lx6464es/lx6464es.c
sound/pci/lx6464es/lx6464es.h
sound/pci/lx6464es/lx_core.c
sound/pci/lx6464es/lx_core.h
sound/pci/mixart/mixart.c
sound/pci/mixart/mixart.h
sound/pci/mixart/mixart_core.c
sound/pci/mixart/mixart_core.h
sound/pci/oxygen/oxygen_pcm.c
sound/pci/oxygen/virtuoso.c
sound/pci/oxygen/xonar_pcm179x.c
sound/pci/pcxhr/pcxhr.c
sound/pci/pcxhr/pcxhr.h
sound/pci/pcxhr/pcxhr_core.c
sound/pci/pcxhr/pcxhr_core.h
sound/pci/vx222/vx222.c
sound/pcmcia/pdaudiocf/pdaudiocf.c
sound/pcmcia/pdaudiocf/pdaudiocf.h
sound/pcmcia/pdaudiocf/pdaudiocf_core.c
sound/pcmcia/pdaudiocf/pdaudiocf_irq.c
sound/pcmcia/pdaudiocf/pdaudiocf_pcm.c
sound/pcmcia/vx/vxp_ops.c
sound/pcmcia/vx/vxpocket.c
sound/soc/codecs/88pm860x-codec.c
sound/soc/codecs/Kconfig
sound/soc/codecs/Makefile
sound/soc/codecs/ab8500-codec.c
sound/soc/codecs/ac97.c
sound/soc/codecs/adau1373.c
sound/soc/codecs/adau1761.c
sound/soc/codecs/adau1781.c
sound/soc/codecs/adau17x1.c
sound/soc/codecs/adau17x1.h
sound/soc/codecs/adav80x.c
sound/soc/codecs/cs35l32.c [new file with mode: 0644]
sound/soc/codecs/cs35l32.h [new file with mode: 0644]
sound/soc/codecs/cs4265.c
sound/soc/codecs/cs42l52.c
sound/soc/codecs/cs42l56.c
sound/soc/codecs/cs42l73.c
sound/soc/codecs/da732x.c
sound/soc/codecs/es8328-i2c.c [new file with mode: 0644]
sound/soc/codecs/es8328-spi.c [new file with mode: 0644]
sound/soc/codecs/es8328.c [new file with mode: 0644]
sound/soc/codecs/es8328.h [new file with mode: 0644]
sound/soc/codecs/jz4740.c
sound/soc/codecs/lm49453.c
sound/soc/codecs/max98090.c
sound/soc/codecs/max98090.h
sound/soc/codecs/mc13783.c
sound/soc/codecs/ml26124.c
sound/soc/codecs/rt286.c
sound/soc/codecs/rt5640.c
sound/soc/codecs/rt5640.h
sound/soc/codecs/rt5645.c
sound/soc/codecs/rt5645.h
sound/soc/codecs/rt5677.c
sound/soc/codecs/rt5677.h
sound/soc/codecs/sgtl5000.c
sound/soc/codecs/ssm2518.c
sound/soc/codecs/ssm2602-i2c.c
sound/soc/codecs/ssm2602-spi.c
sound/soc/codecs/ssm2602.c
sound/soc/codecs/ssm4567.c [new file with mode: 0644]
sound/soc/codecs/tas2552.c
sound/soc/codecs/tlv320aic31xx.c
sound/soc/codecs/tlv320aic31xx.h
sound/soc/codecs/tlv320aic3x.c
sound/soc/codecs/wm8350.c
sound/soc/codecs/wm8741.c
sound/soc/codecs/wm8753.c
sound/soc/codecs/wm8804.c
sound/soc/codecs/wm8971.c
sound/soc/codecs/wm8994.c
sound/soc/codecs/wm8995.c
sound/soc/davinci/Kconfig
sound/soc/davinci/davinci-mcasp.c
sound/soc/davinci/edma-pcm.c
sound/soc/fsl/Kconfig
sound/soc/fsl/Makefile
sound/soc/fsl/fsl-asoc-card.c [new file with mode: 0644]
sound/soc/fsl/fsl_asrc.c
sound/soc/fsl/fsl_esai.c
sound/soc/fsl/fsl_esai.h
sound/soc/fsl/fsl_sai.c
sound/soc/fsl/fsl_sai.h
sound/soc/fsl/fsl_spdif.c
sound/soc/fsl/fsl_ssi.c
sound/soc/fsl/imx-es8328.c [new file with mode: 0644]
sound/soc/generic/simple-card.c
sound/soc/intel/Makefile
sound/soc/intel/byt-max98090.c
sound/soc/intel/byt-rt5640.c
sound/soc/intel/sst-atom-controls.c [new file with mode: 0644]
sound/soc/intel/sst-atom-controls.h
sound/soc/intel/sst-haswell-pcm.c
sound/soc/intel/sst-mfld-platform-compress.c
sound/soc/intel/sst-mfld-platform-pcm.c
sound/soc/intel/sst-mfld-platform.h
sound/soc/omap/rx51.c
sound/soc/rockchip/Kconfig
sound/soc/rockchip/Makefile
sound/soc/rockchip/rockchip_i2s.c
sound/soc/samsung/idma.c
sound/soc/samsung/odroidx2_max98090.c
sound/soc/samsung/speyside.c
sound/soc/sh/fsi.c
sound/soc/sh/rcar/core.c
sound/soc/sh/siu_pcm.c
sound/soc/sirf/sirf-usp.c
sound/soc/soc-core.c
sound/soc/soc-dapm.c
sound/soc/soc-generic-dmaengine-pcm.c
sound/soc/soc-io.c
sound/soc/soc-pcm.c
sound/soc/tegra/tegra_max98090.c
sound/soc/txx9/txx9aclc.c
sound/usb/caiaq/audio.c
sound/usb/midi.c
sound/usb/quirks.c
tools/lib/api/Makefile
tools/lib/api/fd/array.c [new file with mode: 0644]
tools/lib/api/fd/array.h [new file with mode: 0644]
tools/perf/.gitignore
tools/perf/Documentation/perf-probe.txt
tools/perf/Documentation/perf-report.txt
tools/perf/Documentation/perf-top.txt
tools/perf/Makefile.perf
tools/perf/arch/arm/tests/dwarf-unwind.c
tools/perf/arch/arm/util/unwind-libunwind.c
tools/perf/arch/arm64/include/perf_regs.h
tools/perf/arch/arm64/util/unwind-libunwind.c
tools/perf/arch/common.c
tools/perf/arch/powerpc/Makefile
tools/perf/arch/powerpc/util/skip-callchain-idx.c
tools/perf/bench/futex-hash.c
tools/perf/bench/futex-requeue.c
tools/perf/bench/futex-wake.c
tools/perf/bench/sched-messaging.c
tools/perf/builtin-annotate.c
tools/perf/builtin-buildid-cache.c
tools/perf/builtin-diff.c
tools/perf/builtin-evlist.c
tools/perf/builtin-help.c
tools/perf/builtin-inject.c
tools/perf/builtin-kmem.c
tools/perf/builtin-kvm.c
tools/perf/builtin-lock.c
tools/perf/builtin-mem.c
tools/perf/builtin-probe.c
tools/perf/builtin-record.c
tools/perf/builtin-report.c
tools/perf/builtin-sched.c
tools/perf/builtin-script.c
tools/perf/builtin-stat.c
tools/perf/builtin-timechart.c
tools/perf/builtin-top.c
tools/perf/builtin-trace.c
tools/perf/config/Makefile
tools/perf/config/feature-checks/Makefile
tools/perf/config/utilities.mak
tools/perf/perf-with-kcore.sh [new file with mode: 0644]
tools/perf/perf.c
tools/perf/perf.h
tools/perf/tests/builtin-test.c
tools/perf/tests/fdarray.c [new file with mode: 0644]
tools/perf/tests/mmap-basic.c
tools/perf/tests/open-syscall-all-cpus.c
tools/perf/tests/open-syscall-tp-fields.c
tools/perf/tests/open-syscall.c
tools/perf/tests/perf-record.c
tools/perf/tests/pmu.c
tools/perf/tests/rdpmc.c
tools/perf/tests/sw-clock.c
tools/perf/tests/switch-tracking.c [new file with mode: 0644]
tools/perf/tests/task-exit.c
tools/perf/tests/tests.h
tools/perf/ui/browsers/hists.c
tools/perf/ui/gtk/hists.c
tools/perf/ui/hist.c
tools/perf/ui/stdio/hist.c
tools/perf/util/annotate.c
tools/perf/util/cache.h
tools/perf/util/callchain.c
tools/perf/util/callchain.h
tools/perf/util/cloexec.c
tools/perf/util/color.c
tools/perf/util/color.h
tools/perf/util/comm.c
tools/perf/util/comm.h
tools/perf/util/config.c
tools/perf/util/data.c
tools/perf/util/debug.c
tools/perf/util/debug.h
tools/perf/util/dso.c
tools/perf/util/dso.h
tools/perf/util/event.c
tools/perf/util/event.h
tools/perf/util/evlist.c
tools/perf/util/evlist.h
tools/perf/util/evsel.c
tools/perf/util/evsel.h
tools/perf/util/header.c
tools/perf/util/hist.c
tools/perf/util/hist.h
tools/perf/util/kvm-stat.h
tools/perf/util/machine.c
tools/perf/util/machine.h
tools/perf/util/map.c
tools/perf/util/ordered-events.c [new file with mode: 0644]
tools/perf/util/ordered-events.h [new file with mode: 0644]
tools/perf/util/parse-events.c
tools/perf/util/parse-events.y
tools/perf/util/pmu.c
tools/perf/util/pmu.h
tools/perf/util/probe-event.c
tools/perf/util/probe-event.h
tools/perf/util/probe-finder.c
tools/perf/util/python.c
tools/perf/util/record.c
tools/perf/util/run-command.c
tools/perf/util/scripting-engines/trace-event-perl.c
tools/perf/util/scripting-engines/trace-event-python.c
tools/perf/util/session.c
tools/perf/util/session.h
tools/perf/util/sort.c
tools/perf/util/sort.h
tools/perf/util/string.c
tools/perf/util/symbol-elf.c
tools/perf/util/symbol.c
tools/perf/util/symbol.h
tools/perf/util/thread.c
tools/perf/util/thread.h
tools/perf/util/tool.h
tools/perf/util/trace-event-scripting.c
tools/perf/util/trace-event.h
tools/perf/util/util.c
tools/perf/util/util.h
tools/testing/ktest/ktest.pl
tools/testing/ktest/sample.conf
tools/testing/selftests/Makefile
tools/testing/selftests/ftrace/Makefile [new file with mode: 0644]
tools/testing/selftests/ftrace/README [new file with mode: 0644]
tools/testing/selftests/ftrace/ftracetest [new file with mode: 0755]
tools/testing/selftests/ftrace/samples/fail.tc [new file with mode: 0644]
tools/testing/selftests/ftrace/samples/pass.tc [new file with mode: 0644]
tools/testing/selftests/ftrace/samples/unresolved.tc [new file with mode: 0644]
tools/testing/selftests/ftrace/samples/unsupported.tc [new file with mode: 0644]
tools/testing/selftests/ftrace/samples/untested.tc [new file with mode: 0644]
tools/testing/selftests/ftrace/samples/xfail.tc [new file with mode: 0644]
tools/testing/selftests/ftrace/test.d/00basic/basic1.tc [new file with mode: 0644]
tools/testing/selftests/ftrace/test.d/00basic/basic2.tc [new file with mode: 0644]
tools/testing/selftests/ftrace/test.d/00basic/basic3.tc [new file with mode: 0644]
tools/testing/selftests/ftrace/test.d/kprobe/add_and_remove.tc [new file with mode: 0644]
tools/testing/selftests/ftrace/test.d/kprobe/busy_check.tc [new file with mode: 0644]
tools/testing/selftests/ftrace/test.d/kprobe/kprobe_args.tc [new file with mode: 0644]
tools/testing/selftests/ftrace/test.d/kprobe/kretprobe_args.tc [new file with mode: 0644]
tools/testing/selftests/ftrace/test.d/template [new file with mode: 0644]
tools/testing/selftests/memfd/Makefile
tools/testing/selftests/memfd/memfd_test.c
tools/testing/selftests/powerpc/Makefile
tools/testing/selftests/powerpc/primitives/Makefile [new file with mode: 0644]
tools/testing/selftests/powerpc/primitives/asm/asm-compat.h [new symlink]
tools/testing/selftests/powerpc/primitives/asm/ppc-opcode.h [new file with mode: 0644]
tools/testing/selftests/powerpc/primitives/load_unaligned_zeropad.c [new file with mode: 0644]
tools/testing/selftests/powerpc/primitives/word-at-a-time.h [new symlink]
tools/testing/selftests/rcutorture/bin/config2frag.sh [changed mode: 0644->0755]
tools/testing/selftests/rcutorture/bin/configcheck.sh
tools/testing/selftests/rcutorture/bin/configinit.sh
tools/testing/selftests/rcutorture/bin/functions.sh
tools/testing/selftests/rcutorture/bin/kvm-build.sh
tools/testing/selftests/rcutorture/bin/kvm-recheck-lock.sh
tools/testing/selftests/rcutorture/bin/kvm-recheck-rcu.sh
tools/testing/selftests/rcutorture/bin/kvm-recheck.sh
tools/testing/selftests/rcutorture/bin/kvm-test-1-run.sh
tools/testing/selftests/rcutorture/bin/kvm.sh [changed mode: 0644->0755]
tools/testing/selftests/rcutorture/bin/parse-build.sh
tools/testing/selftests/rcutorture/bin/parse-console.sh
tools/testing/selftests/rcutorture/bin/parse-torture.sh
tools/testing/selftests/rcutorture/configs/lock/CFLIST
tools/testing/selftests/rcutorture/configs/lock/LOCK02 [new file with mode: 0644]
tools/testing/selftests/rcutorture/configs/lock/LOCK02.boot [new file with mode: 0644]
tools/testing/selftests/rcutorture/configs/lock/LOCK03 [new file with mode: 0644]
tools/testing/selftests/rcutorture/configs/lock/LOCK03.boot [new file with mode: 0644]
tools/testing/selftests/rcutorture/configs/lock/LOCK04 [new file with mode: 0644]
tools/testing/selftests/rcutorture/configs/lock/LOCK04.boot [new file with mode: 0644]
tools/testing/selftests/rcutorture/configs/lock/ver_functions.sh
tools/testing/selftests/rcutorture/configs/rcu/CFLIST
tools/testing/selftests/rcutorture/configs/rcu/TASKS01 [new file with mode: 0644]
tools/testing/selftests/rcutorture/configs/rcu/TASKS01.boot [new file with mode: 0644]
tools/testing/selftests/rcutorture/configs/rcu/TASKS02 [new file with mode: 0644]
tools/testing/selftests/rcutorture/configs/rcu/TASKS02.boot [new file with mode: 0644]
tools/testing/selftests/rcutorture/configs/rcu/TASKS03 [new file with mode: 0644]
tools/testing/selftests/rcutorture/configs/rcu/TASKS03.boot [new file with mode: 0644]
tools/testing/selftests/rcutorture/configs/rcu/TREE01
tools/testing/selftests/rcutorture/configs/rcu/TREE01.boot
tools/testing/selftests/rcutorture/configs/rcu/TREE07
tools/testing/selftests/rcutorture/configs/rcu/TREE07.boot [new file with mode: 0644]
tools/testing/selftests/rcutorture/configs/rcu/ver_functions.sh
tools/testing/selftests/rcutorture/doc/initrd.txt

index 27e67a98b7be21c8457daef9e6921e6a7d17e7a4..1750fcef1ab4d524dfc126ab50874dde2e03a21b 100644 (file)
@@ -287,6 +287,8 @@ local_ops.txt
        - semantics and behavior of local atomic operations.
 lockdep-design.txt
        - documentation on the runtime locking correctness validator.
+locking/
+       - directory with info about kernel locking primitives
 lockstat.txt
        - info on collecting statistics on locks (and contention).
 lockup-watchdogs.txt
index e78ee798d7bd2c1fb7e0fe7aff56683370ecaf05..32f3f5f8bba21100d0d59a70da25501bfe62c619 100644 (file)
@@ -1,6 +1,6 @@
 What:          /sys/bus/event_source/devices/hv_24x7/interface/catalog
 Date:          February 2014
-Contact:       Cody P Schafer <cody@linux.vnet.ibm.com>
+Contact:       Linux on PowerPC Developer List <linuxppc-dev@lists.ozlabs.org>
 Description:
                Provides access to the binary "24x7 catalog" provided by the
                hypervisor on POWER7 and 8 systems. This catalog lists events
@@ -10,14 +10,14 @@ Description:
 
 What:          /sys/bus/event_source/devices/hv_24x7/interface/catalog_length
 Date:          February 2014
-Contact:       Cody P Schafer <cody@linux.vnet.ibm.com>
+Contact:       Linux on PowerPC Developer List <linuxppc-dev@lists.ozlabs.org>
 Description:
                A number equal to the length in bytes of the catalog. This is
                also extractable from the provided binary "catalog" sysfs entry.
 
 What:          /sys/bus/event_source/devices/hv_24x7/interface/catalog_version
 Date:          February 2014
-Contact:       Cody P Schafer <cody@linux.vnet.ibm.com>
+Contact:       Linux on PowerPC Developer List <linuxppc-dev@lists.ozlabs.org>
 Description:
                Exposes the "version" field of the 24x7 catalog. This is also
                extractable from the provided binary "catalog" sysfs entry.
index 3fa58c23f13b2083ad84f47c0452a1717fef7f5f..3ca4e554d2f92dc43f4d7c2cd57c24ba22ffb93a 100644 (file)
@@ -1,6 +1,6 @@
 What:          /sys/bus/event_source/devices/hv_gpci/interface/collect_privileged
 Date:          February 2014
-Contact:       Cody P Schafer <cody@linux.vnet.ibm.com>
+Contact:       Linux on PowerPC Developer List <linuxppc-dev@lists.ozlabs.org>
 Description:
                '0' if the hypervisor is configured to forbid access to event
                counters being accumulated by other guests and to physical
@@ -9,35 +9,35 @@ Description:
 
 What:          /sys/bus/event_source/devices/hv_gpci/interface/ga
 Date:          February 2014
-Contact:       Cody P Schafer <cody@linux.vnet.ibm.com>
+Contact:       Linux on PowerPC Developer List <linuxppc-dev@lists.ozlabs.org>
 Description:
                0 or 1. Indicates whether we have access to "GA" events (listed
                in arch/powerpc/perf/hv-gpci.h).
 
 What:          /sys/bus/event_source/devices/hv_gpci/interface/expanded
 Date:          February 2014
-Contact:       Cody P Schafer <cody@linux.vnet.ibm.com>
+Contact:       Linux on PowerPC Developer List <linuxppc-dev@lists.ozlabs.org>
 Description:
                0 or 1. Indicates whether we have access to "EXPANDED" events (listed
                in arch/powerpc/perf/hv-gpci.h).
 
 What:          /sys/bus/event_source/devices/hv_gpci/interface/lab
 Date:          February 2014
-Contact:       Cody P Schafer <cody@linux.vnet.ibm.com>
+Contact:       Linux on PowerPC Developer List <linuxppc-dev@lists.ozlabs.org>
 Description:
                0 or 1. Indicates whether we have access to "LAB" events (listed
                in arch/powerpc/perf/hv-gpci.h).
 
 What:          /sys/bus/event_source/devices/hv_gpci/interface/version
 Date:          February 2014
-Contact:       Cody P Schafer <cody@linux.vnet.ibm.com>
+Contact:       Linux on PowerPC Developer List <linuxppc-dev@lists.ozlabs.org>
 Description:
                A number indicating the version of the gpci interface that the
                hypervisor reports supporting.
 
 What:          /sys/bus/event_source/devices/hv_gpci/interface/kernel_version
 Date:          February 2014
-Contact:       Cody P Schafer <cody@linux.vnet.ibm.com>
+Contact:       Linux on PowerPC Developer List <linuxppc-dev@lists.ozlabs.org>
 Description:
                A number indicating the latest version of the gpci interface
                that the kernel is aware of.
diff --git a/Documentation/ABI/testing/sysfs-class-cxl b/Documentation/ABI/testing/sysfs-class-cxl
new file mode 100644 (file)
index 0000000..554405e
--- /dev/null
@@ -0,0 +1,129 @@
+Slave contexts (eg. /sys/class/cxl/afu0.0s):
+
+What:           /sys/class/cxl/<afu>/irqs_max
+Date:           September 2014
+Contact:        linuxppc-dev@lists.ozlabs.org
+Description:    read/write
+                Decimal value of maximum number of interrupts that can be
+                requested by userspace.  The default on probe is the maximum
+                that hardware can support (eg. 2037). Write values will limit
+                userspace applications to that many userspace interrupts. Must
+                be >= irqs_min.
+
+What:           /sys/class/cxl/<afu>/irqs_min
+Date:           September 2014
+Contact:        linuxppc-dev@lists.ozlabs.org
+Description:    read only
+                Decimal value of the minimum number of interrupts that
+                userspace must request on a CXL_START_WORK ioctl. Userspace may
+                omit the num_interrupts field in the START_WORK IOCTL to get
+                this minimum automatically.
+
+What:           /sys/class/cxl/<afu>/mmio_size
+Date:           September 2014
+Contact:        linuxppc-dev@lists.ozlabs.org
+Description:    read only
+                Decimal value of the size of the MMIO space that may be mmaped
+                by userspace.
+
+What:           /sys/class/cxl/<afu>/modes_supported
+Date:           September 2014
+Contact:        linuxppc-dev@lists.ozlabs.org
+Description:    read only
+                List of the modes this AFU supports. One per line.
+                Valid entries are: "dedicated_process" and "afu_directed"
+
+What:           /sys/class/cxl/<afu>/mode
+Date:           September 2014
+Contact:        linuxppc-dev@lists.ozlabs.org
+Description:    read/write
+                The current mode the AFU is using. Will be one of the modes
+                given in modes_supported. Writing will change the mode
+                provided that no user contexts are attached.
+
+
+What:           /sys/class/cxl/<afu>/prefault_mode
+Date:           September 2014
+Contact:        linuxppc-dev@lists.ozlabs.org
+Description:    read/write
+                Set the mode for prefaulting in segments into the segment table
+                when performing the START_WORK ioctl. Possible values:
+                        none: No prefaulting (default)
+                        work_element_descriptor: Treat the work element
+                                 descriptor as an effective address and
+                                 prefault what it points to.
+                        all: all segments process calling START_WORK maps.
+
+What:           /sys/class/cxl/<afu>/reset
+Date:           September 2014
+Contact:        linuxppc-dev@lists.ozlabs.org
+Description:    write only
+                Writing 1 here will reset the AFU provided there are not
+                contexts active on the AFU.
+
+What:           /sys/class/cxl/<afu>/api_version
+Date:           September 2014
+Contact:        linuxppc-dev@lists.ozlabs.org
+Description:    read only
+                Decimal value of the current version of the kernel/user API.
+
+What:           /sys/class/cxl/<afu>/api_version_com
+Date:           September 2014
+Contact:        linuxppc-dev@lists.ozlabs.org
+Description:    read only
+                Decimal value of the the lowest version of the userspace API
+                this this kernel supports.
+
+
+
+Master contexts (eg. /sys/class/cxl/afu0.0m)
+
+What:           /sys/class/cxl/<afu>m/mmio_size
+Date:           September 2014
+Contact:        linuxppc-dev@lists.ozlabs.org
+Description:    read only
+                Decimal value of the size of the MMIO space that may be mmaped
+                by userspace. This includes all slave contexts space also.
+
+What:           /sys/class/cxl/<afu>m/pp_mmio_len
+Date:           September 2014
+Contact:        linuxppc-dev@lists.ozlabs.org
+Description:    read only
+                Decimal value of the Per Process MMIO space length.
+
+What:           /sys/class/cxl/<afu>m/pp_mmio_off
+Date:           September 2014
+Contact:        linuxppc-dev@lists.ozlabs.org
+Description:    read only
+                Decimal value of the Per Process MMIO space offset.
+
+
+Card info (eg. /sys/class/cxl/card0)
+
+What:           /sys/class/cxl/<card>/caia_version
+Date:           September 2014
+Contact:        linuxppc-dev@lists.ozlabs.org
+Description:    read only
+                Identifies the CAIA Version the card implements.
+
+What:           /sys/class/cxl/<card>/psl_version
+Date:           September 2014
+Contact:        linuxppc-dev@lists.ozlabs.org
+Description:    read only
+                Identifies the revision level of the PSL.
+
+What:           /sys/class/cxl/<card>/base_image
+Date:           September 2014
+Contact:        linuxppc-dev@lists.ozlabs.org
+Description:    read only
+                Identifies the revision level of the base image for devices
+                that support loadable PSLs. For FPGAs this field identifies
+                the image contained in the on-adapter flash which is loaded
+                during the initial program load.
+
+What:           /sys/class/cxl/<card>/image_loaded
+Date:           September 2014
+Contact:        linuxppc-dev@lists.ozlabs.org
+Description:    read only
+                Will return "user" or "factory" depending on the image loaded
+                onto the card.
index bacefc5b222ec0dff365e83c63191859d5803a22..be35bc328b775948cd10d1c2cf3f8df76256aeb2 100644 (file)
@@ -291,10 +291,9 @@ char *date;</synopsis>
       <title>Device Registration</title>
       <para>
         A number of functions are provided to help with device registration.
-        The functions deal with PCI, USB and platform devices, respectively.
+        The functions deal with PCI and platform devices, respectively.
       </para>
 !Edrivers/gpu/drm/drm_pci.c
-!Edrivers/gpu/drm/drm_usb.c
 !Edrivers/gpu/drm/drm_platform.c
       <para>
         New drivers that no longer rely on the services provided by the
@@ -3386,6 +3385,13 @@ void (*disable_vblank) (struct drm_device *dev, int crtc);</synopsis>
       by scheduling a timer. The delay is accessible through the vblankoffdelay
       module parameter or the <varname>drm_vblank_offdelay</varname> global
       variable and expressed in milliseconds. Its default value is 5000 ms.
+      Zero means never disable, and a negative value means disable immediately.
+      Drivers may override the behaviour by setting the
+      <structname>drm_device</structname>
+      <structfield>vblank_disable_immediate</structfield> flag, which when set
+      causes vblank interrupts to be disabled immediately regardless of the
+      drm_vblank_offdelay value. The flag should only be set if there's a
+      properly working hardware vblank counter present.
     </para>
     <para>
       When a vertical blanking interrupt occurs drivers only need to call the
@@ -3400,6 +3406,7 @@ void (*disable_vblank) (struct drm_device *dev, int crtc);</synopsis>
     <sect2>
       <title>Vertical Blanking and Interrupt Handling Functions Reference</title>
 !Edrivers/gpu/drm/drm_irq.c
+!Finclude/drm/drmP.h drm_crtc_vblank_waitqueue
     </sect2>
   </sect1>
 
@@ -3918,6 +3925,11 @@ int num_ioctls;</synopsis>
 !Pdrivers/gpu/drm/i915/i915_cmd_parser.c batch buffer command parser
 !Idrivers/gpu/drm/i915/i915_cmd_parser.c
       </sect2>
+      <sect2>
+        <title>Logical Rings, Logical Ring Contexts and Execlists</title>
+!Pdrivers/gpu/drm/i915/intel_lrc.c Logical Rings, Logical Ring Contexts and Execlists
+!Idrivers/gpu/drm/i915/intel_lrc.c
+      </sect2>
     </sect1>
   </chapter>
 </part>
index e584ee12a1e76fc3242711eb0407c32b12f2fef3..7c9cc4846cb67144c9d5f864f018cfd8b3efb9b6 100644 (file)
@@ -1972,7 +1972,7 @@ machines due to caching.
    <itemizedlist>
     <listitem>
      <para>
-       <filename>Documentation/spinlocks.txt</filename>: 
+       <filename>Documentation/locking/spinlocks.txt</filename>:
        Linus Torvalds' spinlocking tutorial in the kernel sources.
      </para>
     </listitem>
index 3a626d1b8f2e4d8022831f0961fbb83bc359b487..07ffc76553ba098490cbba874f6f513f8981222e 100644 (file)
@@ -2566,6 +2566,12 @@ fields changed from _s32 to _u32.
          <para>Added compound control types and &VIDIOC-QUERY-EXT-CTRL;.
          </para>
         </listitem>
+      <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>
 
index 9f5ffd85560b58b3032867b57ec095153e7bfd07..e013e4bf244c509fef7477cd8ae182bcded29693 100644 (file)
@@ -3965,6 +3965,27 @@ 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>
@@ -4790,6 +4811,40 @@ interface and may change in the future.</para>
            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>
index 2aae8e9452a42dd41656f9692e78122343957d21..6ab4f0f3db64abdc9de76ff3ccf458881f9b49e2 100644 (file)
@@ -237,9 +237,9 @@ for a pixel lie next to each other in memory.</para>
            <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>
+         <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>
@@ -259,6 +259,28 @@ for a pixel lie next to each other in memory.</para>
            <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>
@@ -464,7 +486,7 @@ for a pixel lie next to each other in memory.</para>
          </row>
          <row id="V4L2-PIX-FMT-ARGB32">
            <entry><constant>V4L2_PIX_FMT_ARGB32</constant></entry>
-           <entry>'AX24'</entry>
+           <entry>'BA24'</entry>
            <entry></entry>
            <entry>a<subscript>7</subscript></entry>
            <entry>a<subscript>6</subscript></entry>
@@ -800,6 +822,28 @@ image</title>
            <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>
index cb7732582f0365861ccf14f25a3a83ecfdb5d05e..b036f8963353a2a2f88c336855da9282e7d68fb6 100644 (file)
            <entry></entry>
            <entry>&v4l2-event-vsync;</entry>
             <entry><structfield>vsync</structfield></entry>
-           <entry>Event data for event V4L2_EVENT_VSYNC.
+           <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 V4L2_EVENT_CTRL.
+           <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 V4L2_EVENT_FRAME_SYNC.</entry>
+           <entry>Event data for event
+           <constant>V4L2_EVENT_FRAME_SYNC</constant>.</entry>
          </row>
          <row>
            <entry></entry>
index ce4563b87131c5ad384a22cf63fadcd95d85206d..6df40db4c8ba9f7674dda280e914a365ed3abe7d 100644 (file)
@@ -24,7 +24,7 @@
        <funcdef>int <function>ioctl</function></funcdef>
        <paramdef>int <parameter>fd</parameter></paramdef>
        <paramdef>int <parameter>request</parameter></paramdef>
-       <paramdef>const struct v4l2_edid *<parameter>argp</parameter></paramdef>
+       <paramdef>struct v4l2_edid *<parameter>argp</parameter></paramdef>
       </funcprototype>
     </funcsynopsis>
   </refsynopsisdiv>
            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>__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>
          <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>
index 9f6095608837b29085aa49171f544474801d3c6e..d7c9365ecdbe245e05aee3875ee09ab5b8fa0199 100644 (file)
          </row>
          <row>
            <entry><constant>V4L2_EVENT_MOTION_DET</constant></entry>
-           <entry>5</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>
index 6f639d9530b51b69394a83c1d29e9ee2a42bce32..784793df81ed12933ebbb76682d8ec39597603d8 100644 (file)
@@ -2742,7 +2742,9 @@ struct _snd_pcm_runtime {
 
         <para>
           Another note is that this callback is non-atomic
-        (schedulable). This is important, because the
+        (schedulable) as default, i.e. when no
+       <structfield>nonatomic</structfield> flag set.
+       This is important, because the
         <structfield>trigger</structfield> callback 
         is atomic (non-schedulable). That is, mutexes or any
         schedule-related functions are not available in
@@ -2900,8 +2902,9 @@ struct _snd_pcm_runtime {
         </para>
 
         <para>
-          As mentioned, this callback is atomic.  You cannot call
-         functions which may sleep.
+          As mentioned, this callback is atomic as default unless
+         <structfield>nonatomic</structfield> flag set, and
+         you cannot call functions which may sleep.
          The trigger callback should be as minimal as possible,
          just really triggering the DMA.  The other stuff should be
          initialized hw_params and prepare callbacks properly
@@ -2936,7 +2939,7 @@ struct _snd_pcm_runtime {
         </para>
 
         <para>
-          This callback is also atomic.
+          This callback is also atomic as default.
         </para>
       </section>
 
@@ -2972,7 +2975,7 @@ struct _snd_pcm_runtime {
        is useful only for such a purpose.
        </para>
        <para>
-         This callback is atomic.
+         This callback is atomic as default.
        </para>
       </section>
 
@@ -3175,6 +3178,21 @@ struct _snd_pcm_runtime {
       called with local interrupts disabled.
       </para>
 
+      <para>
+      The recent changes in PCM core code, however, allow all PCM
+      operations to be non-atomic.  This assumes that the all caller
+      sides are in non-atomic contexts.  For example, the function
+      <function>snd_pcm_period_elapsed()</function> is called
+      typically from the interrupt handler.  But, if you set up the
+      driver to use a threaded interrupt handler, this call can be in
+      non-atomic context, too.  In such a case, you can set
+      <structfield>nonatomic</structfield> filed of
+      <structname>snd_pcm</structname> object after creating it.
+      When this flag is set, mutex and rwsem are used internally in
+      the PCM core instead of spin and rwlocks, so that you can call
+      all PCM functions safely in a non-atomic context.
+      </para>
+
     </section>
     <section id="pcm-interface-constraints">
       <title>Constraints</title>
index 68fe3ad27015927662d621a265397308f1d44d1b..ef5a2fd4ff70dabe66f8688d3bdca27d179429b6 100644 (file)
@@ -56,8 +56,20 @@ RCU_STALL_RAT_DELAY
        two jiffies.  (This is a cpp macro, not a kernel configuration
        parameter.)
 
-When a CPU detects that it is stalling, it will print a message similar
-to the following:
+rcupdate.rcu_task_stall_timeout
+
+       This boot/sysfs parameter controls the RCU-tasks stall warning
+       interval.  A value of zero or less suppresses RCU-tasks stall
+       warnings.  A positive value sets the stall-warning interval
+       in jiffies.  An RCU-tasks stall warning starts wtih the line:
+
+               INFO: rcu_tasks detected stalls on tasks:
+
+       And continues with the output of sched_show_task() for each
+       task stalling the current RCU-tasks grace period.
+
+For non-RCU-tasks flavors of RCU, when a CPU detects that it is stalling,
+it will print a message similar to the following:
 
 INFO: rcu_sched_state detected stall on CPU 5 (t=2500 jiffies)
 
@@ -174,8 +186,12 @@ o  A CPU looping with preemption disabled.  This condition can
 o      A CPU looping with bottom halves disabled.  This condition can
        result in RCU-sched and RCU-bh stalls.
 
-o      For !CONFIG_PREEMPT kernels, a CPU looping anywhere in the kernel
-       without invoking schedule().
+o      For !CONFIG_PREEMPT kernels, a CPU looping anywhere in the
+       kernel without invoking schedule().  Note that cond_resched()
+       does not necessarily prevent RCU CPU stall warnings.  Therefore,
+       if the looping in the kernel is really expected and desirable
+       behavior, you might need to replace some of the cond_resched()
+       calls with calls to cond_resched_rcu_qs().
 
 o      A CPU-bound real-time task in a CONFIG_PREEMPT kernel, which might
        happen to preempt a low-priority task in the middle of an RCU
@@ -208,11 +224,10 @@ o A hardware failure.  This is quite unlikely, but has occurred
        This resulted in a series of RCU CPU stall warnings, eventually
        leading the realization that the CPU had failed.
 
-The RCU, RCU-sched, and RCU-bh implementations have CPU stall warning.
-SRCU does not have its own CPU stall warnings, but its calls to
-synchronize_sched() will result in RCU-sched detecting RCU-sched-related
-CPU stalls.  Please note that RCU only detects CPU stalls when there is
-a grace period in progress.  No grace period, no CPU stall warnings.
+The RCU, RCU-sched, RCU-bh, and RCU-tasks implementations have CPU stall
+warning.  Note that SRCU does -not- have CPU stall warnings.  Please note
+that RCU only detects CPU stalls when there is a grace period in progress.
+No grace period, no CPU stall warnings.
 
 To diagnose the cause of the stall, inspect the stack traces.
 The offending function will usually be near the top of the stack.
index c1ed6948ba80e7f16fd313b9bab431118e18f31e..6b1de70583715d7728a7a31b4612564b0178679b 100644 (file)
@@ -15,39 +15,50 @@ First you must mount binfmt_misc:
        mount binfmt_misc -t binfmt_misc /proc/sys/fs/binfmt_misc 
 
 To actually register a new binary type, you have to set up a string looking like
-:name:type:offset:magic:mask:interpreter:flags (where you can choose the ':' upon
-your needs) and echo it to /proc/sys/fs/binfmt_misc/register.
+:name:type:offset:magic:mask:interpreter:flags (where you can choose the ':'
+upon your needs) and echo it to /proc/sys/fs/binfmt_misc/register.
+
 Here is what the fields mean:
  - 'name' is an identifier string. A new /proc file will be created with this
-   name below /proc/sys/fs/binfmt_misc
+   name below /proc/sys/fs/binfmt_misc; cannot contain slashes '/' for obvious
+   reasons.
  - 'type' is the type of recognition. Give 'M' for magic and 'E' for extension.
  - 'offset' is the offset of the magic/mask in the file, counted in bytes. This
-   defaults to 0 if you omit it (i.e. you write ':name:type::magic...')
+   defaults to 0 if you omit it (i.e. you write ':name:type::magic...'). Ignored
+   when using filename extension matching.
  - 'magic' is the byte sequence binfmt_misc is matching for. The magic string
-   may contain hex-encoded characters like \x0a or \xA4. In a shell environment
-   you will have to write \\x0a to prevent the shell from eating your \.
+   may contain hex-encoded characters like \x0a or \xA4. Note that you must
+   escape any NUL bytes; parsing halts at the first one. In a shell environment
+   you might have to write \\x0a to prevent the shell from eating your \.
    If you chose filename extension matching, this is the extension to be
    recognised (without the '.', the \x0a specials are not allowed). Extension
-   matching is case sensitive!
+   matching is case sensitive, and slashes '/' are not allowed!
  - 'mask' is an (optional, defaults to all 0xff) mask. You can mask out some
    bits from matching by supplying a string like magic and as long as magic.
-   The mask is anded with the byte sequence of the file.
+   The mask is anded with the byte sequence of the file. Note that you must
+   escape any NUL bytes; parsing halts at the first one. Ignored when using
+   filename extension matching.
  - 'interpreter' is the program that should be invoked with the binary as first
    argument (specify the full path)
  - 'flags' is an optional field that controls several aspects of the invocation
-   of the interpreter. It is a string of capital letters, each controls a certain
-   aspect. The following flags are supported -
-      'P' - preserve-argv[0].  Legacy behavior of binfmt_misc is to overwrite the
-            original argv[0] with the full path to the binary.  When this flag is
-            included, binfmt_misc will add an argument to the argument vector for
-            this purpose, thus preserving the original argv[0].
+   of the interpreter. It is a string of capital letters, each controls a
+   certain aspect. The following flags are supported -
+      'P' - preserve-argv[0]. Legacy behavior of binfmt_misc is to overwrite
+            the original argv[0] with the full path to the binary. When this
+            flag is included, binfmt_misc will add an argument to the argument
+            vector for this purpose, thus preserving the original argv[0].
+            e.g. If your interp is set to /bin/foo and you run `blah` (which is
+            in /usr/local/bin), then the kernel will execute /bin/foo with
+            argv[] set to ["/bin/foo", "/usr/local/bin/blah", "blah"].  The
+            interp has to be aware of this so it can execute /usr/local/bin/blah
+            with argv[] set to ["blah"].
       'O' - open-binary. Legacy behavior of binfmt_misc is to pass the full path
             of the binary to the interpreter as an argument. When this flag is
             included, binfmt_misc will open the file for reading and pass its
             descriptor as an argument, instead of the full path, thus allowing
-            the interpreter to execute non-readable binaries. This feature should
-            be used with care - the interpreter has to be trusted not to emit
-            the contents of the non-readable binary.
+            the interpreter to execute non-readable binaries. This feature
+            should be used with care - the interpreter has to be trusted not to
+            emit the contents of the non-readable binary.
       'C' - credentials. Currently, the behavior of binfmt_misc is to calculate
             the credentials and security token of the new process according to
             the interpreter. When this flag is included, these attributes are
@@ -58,7 +69,7 @@ Here is what the fields mean:
 
 
 There are some restrictions:
- - the whole register string may not exceed 255 characters
+ - the whole register string may not exceed 1920 characters
  - the magic must reside in the first 128 bytes of the file, i.e.
    offset+size(magic) has to be less than 128
  - the interpreter string may not exceed 127 characters
@@ -110,7 +121,4 @@ passes it the full filename (or the file descriptor) to use.  Using $PATH can
 cause unexpected behaviour and can be a security hazard.
 
 
-There is a web page about binfmt_misc at
-http://www.tat.physik.uni-tuebingen.de
-
 Richard Günther <rguenth@tat.physik.uni-tuebingen.de>
index 9301c330d1a64513116e43c6e010a7de17b74ce7..4ab9e230090793b4fc11519ed00494f9fad93e1b 100644 (file)
@@ -18,6 +18,10 @@ Required properties:
    Documentation/devicetree/bindings/video/display-timing.txt for display
    timing binding details.
 
+Optional properties:
+- backlight: phandle of the backlight device attached to the panel
+- enable-gpios: GPIO pin to enable or disable the panel
+
 Recommended properties:
  - pinctrl-names, pinctrl-0: the pincontrol settings to configure
    muxing properly for pins that connect to TFP410 device
@@ -29,6 +33,9 @@ Example:
                compatible = "ti,tilcdc,panel";
                pinctrl-names = "default";
                pinctrl-0 = <&bone_lcd3_cape_lcd_pins>;
+               backlight = <&backlight>;
+               enable-gpios = <&gpio3 19 0>;
+
                panel-info {
                        ac-bias           = <255>;
                        ac-bias-intrpt    = <0>;
index 2391e5c41999afd69df9feafc1f70b15accfefe0..fcca8e744f41f9c4692b3b8915d120dcbd0f0768 100644 (file)
@@ -25,6 +25,9 @@ Requires node properties:
 - "io-channels"        Channel node of ADC to be used for
                conversion.
 
+Optional node properties:
+- "#thermal-sensor-cells" Used to expose itself to thermal fw.
+
 Read more about iio bindings at
        Documentation/devicetree/bindings/iio/iio-bindings.txt
 
diff --git a/Documentation/devicetree/bindings/i2c/ti,bq32k.txt b/Documentation/devicetree/bindings/i2c/ti,bq32k.txt
new file mode 100644 (file)
index 0000000..e204906
--- /dev/null
@@ -0,0 +1,18 @@
+* TI BQ32000                I2C Serial Real-Time Clock
+
+Required properties:
+- compatible: Should contain "ti,bq32000".
+- reg: I2C address for chip
+
+Optional properties:
+- trickle-resistor-ohms : Selected resistor for trickle charger
+       Values usable are 1120 and 20180
+       Should be given if trickle charger should be enabled
+- trickle-diode-disable : Do not use internal trickle charger diode
+       Should be given if internal trickle charger diode should be disabled
+Example:
+       bq32000: rtc@68 {
+               compatible = "ti,bq32000";
+               trickle-resistor-ohms = <1120>;
+               reg = <0x68>;
+       };
index 5af3d9df6ecb05c5da5dbeff969bcfba18a09a9a..fbde415078e6845cc5ff862a758959d64810c316 100644 (file)
@@ -35,7 +35,6 @@ catalyst,24c32                i2c serial eeprom
 cirrus,cs42l51         Cirrus Logic CS42L51 audio codec
 dallas,ds1307          64 x 8, Serial, I2C Real-Time Clock
 dallas,ds1338          I2C RTC with 56-Byte NV RAM
-dallas,ds1339          I2C Serial Real-Time Clock
 dallas,ds1340          I2C RTC with Trickle Charger
 dallas,ds1374          I2C, 32-Bit Binary Counter Watchdog RTC with Trickle Charger and Reset Input/Output
 dallas,ds1631          High-Precision Digital Thermometer
diff --git a/Documentation/devicetree/bindings/media/hix5hd2-ir.txt b/Documentation/devicetree/bindings/media/hix5hd2-ir.txt
new file mode 100644 (file)
index 0000000..fb5e760
--- /dev/null
@@ -0,0 +1,25 @@
+Device-Tree bindings for hix5hd2 ir IP
+
+Required properties:
+       - compatible: Should contain "hisilicon,hix5hd2-ir".
+       - reg: Base physical address of the controller and length of memory
+         mapped region.
+       - interrupts: interrupt-specifier for the sole interrupt generated by
+         the device. The interrupt specifier format depends on the interrupt
+         controller parent.
+       - clocks: clock phandle and specifier pair.
+       - hisilicon,power-syscon: phandle of syscon used to control power.
+
+Optional properties:
+       - linux,rc-map-name : Remote control map name.
+
+Example node:
+
+       ir: ir@f8001000 {
+               compatible = "hisilicon,hix5hd2-ir";
+               reg = <0xf8001000 0x1000>;
+               interrupts = <0 47 4>;
+               clocks = <&clock HIX5HD2_FIXED_24M>;
+               hisilicon,power-syscon = <&sysctrl>;
+               linux,rc-map-name = "rc-tivo";
+       };
index 431716e37a3964638245b2905badff16128b9495..b52628b18a537af7dac6be18150efe7a95adf78b 100644 (file)
@@ -40,6 +40,8 @@ Optional properties:
 - mmc-hs200-1_2v: eMMC HS200 mode(1.2V I/O) is supported
 - mmc-hs400-1_8v: eMMC HS400 mode(1.8V I/O) is supported
 - mmc-hs400-1_2v: eMMC HS400 mode(1.2V I/O) is supported
+- dsr: Value the card's (optional) Driver Stage Register (DSR) should be
+  programmed with. Valid range: [0 .. 0xffff].
 
 *NOTE* on CD and WP polarity. To use common for all SD/MMC host controllers line
 polarity properties, we have to fix the meaning of the "normal" and "inverted"
index c559f3f36309e57f1eccda86e926771047960cbb..c327c2d6f23d7f043799fd9bd4e1e9d94a7b4322 100644 (file)
@@ -10,12 +10,14 @@ extensions to the Synopsys Designware Mobile Storage Host Controller.
 Required Properties:
 
 * compatible: should be
-       - "rockchip,rk2928-dw-mshc": for Rockchip RK2928 and following
+       - "rockchip,rk2928-dw-mshc": for Rockchip RK2928 and following,
+                                                       before RK3288
+       - "rockchip,rk3288-dw-mshc": for Rockchip RK3288
 
 Example:
 
        rkdwmmc0@12200000 {
-               compatible = "rockchip,rk2928-dw-mshc";
+               compatible = "rockchip,rk3288-dw-mshc";
                reg = <0x12200000 0x1000>;
                interrupts = <0 75 0>;
                #address-cells = <1>;
index fa0f327cde01417339f8e3618f075e6ef51db12e..400b640fabc768642f3c4b7f8ac9314067af5836 100644 (file)
@@ -19,6 +19,9 @@ Required properties:
                "renesas,sdhi-r8a7779" - SDHI IP on R8A7779 SoC
                "renesas,sdhi-r8a7790" - SDHI IP on R8A7790 SoC
                "renesas,sdhi-r8a7791" - SDHI IP on R8A7791 SoC
+               "renesas,sdhi-r8a7792" - SDHI IP on R8A7792 SoC
+               "renesas,sdhi-r8a7793" - SDHI IP on R8A7793 SoC
+               "renesas,sdhi-r8a7794" - SDHI IP on R8A7794 SoC
 
 Optional properties:
 - toshiba,mmc-wrprotect-disable: write-protect detection is unavailable
index ebcad25efd0a8559ef038dfb1a60f1df3cd22b37..cfcc52705ed8093ba11b4f549dd1b02a8949fb40 100644 (file)
@@ -3,7 +3,7 @@ APM X-Gene SoC Ethernet nodes
 Ethernet nodes are defined to describe on-chip ethernet interfaces in
 APM X-Gene SoC.
 
-Required properties:
+Required properties for all the ethernet interfaces:
 - compatible: Should be "apm,xgene-enet"
 - reg: Address and length of the register set for the device. It contains the
   information of registers in the same order as described by reg-names
@@ -15,6 +15,8 @@ Required properties:
 - clocks: Reference to the clock entry.
 - local-mac-address: MAC address assigned to this device
 - phy-connection-type: Interface type between ethernet device and PHY device
+
+Required properties for ethernet interfaces that have external PHY:
 - phy-handle: Reference to a PHY node connected to this device
 
 - mdio: Device tree subnode with the following required properties:
index 98a3e61f9ee825c3d37e7a0d1a848151b92dc468..e1d99b95c4ec984e2adbf80b808a4bb0f0f90f05 100644 (file)
@@ -16,3 +16,9 @@ Optional properties:
              KSZ8051: register 0x1f, bits 5..4
 
               See the respective PHY datasheet for the mode values.
+
+ - clocks, clock-names: contains clocks according to the common clock bindings.
+
+              supported clocks:
+             - KSZ8021, KSZ8031: "rmii-ref": The RMII refence input clock. Used
+               to determine the XI input clock.
diff --git a/Documentation/devicetree/bindings/panel/auo,b101xtn01.txt b/Documentation/devicetree/bindings/panel/auo,b101xtn01.txt
new file mode 100644 (file)
index 0000000..889d511
--- /dev/null
@@ -0,0 +1,7 @@
+AU Optronics Corporation 10.1" WXGA TFT LCD panel
+
+Required properties:
+- compatible: should be "auo,b101xtn01"
+
+This binding is compatible with the simple-panel binding, which is specified
+in simple-panel.txt in this directory.
diff --git a/Documentation/devicetree/bindings/pci/fsl,pci.txt b/Documentation/devicetree/bindings/pci/fsl,pci.txt
new file mode 100644 (file)
index 0000000..d8ac4a7
--- /dev/null
@@ -0,0 +1,27 @@
+* Bus Enumeration by Freescale PCI-X Agent
+
+Typically any Freescale PCI-X bridge hardware strapped into Agent mode
+is prevented from enumerating the bus. The PrPMC form-factor requires
+all mezzanines to be PCI-X Agents, but one per system may still
+enumerate the bus.
+
+The property defined below will allow a PCI-X bridge to be used for bus
+enumeration despite being strapped into Agent mode.
+
+Required properties:
+- fsl,pci-agent-force-enum : There is no value associated with this
+  property. The property itself is treated as a boolean.
+
+Example:
+
+       /* PCI-X bridge known to be PrPMC Monarch */
+       pci0: pci@ef008000 {
+               fsl,pci-agent-force-enum;
+               #interrupt-cells = <1>;
+               #size-cells = <2>;
+               #address-cells = <3>;
+               compatible = "fsl,mpc8540-pcix", "fsl,mpc8540-pci";
+               device_type = "pci";
+               ...
+               ...
+       };
diff --git a/Documentation/devicetree/bindings/rtc/dallas,ds1339.txt b/Documentation/devicetree/bindings/rtc/dallas,ds1339.txt
new file mode 100644 (file)
index 0000000..916f576
--- /dev/null
@@ -0,0 +1,18 @@
+* Dallas DS1339                I2C Serial Real-Time Clock
+
+Required properties:
+- compatible: Should contain "dallas,ds1339".
+- reg: I2C address for chip
+
+Optional properties:
+- trickle-resistor-ohms : Selected resistor for trickle charger
+       Values usable for ds1339 are 250, 2000, 4000
+       Should be given if trickle charger should be enabled
+- trickle-diode-disable : Do not use internal trickle charger diode
+       Should be given if internal trickle charger diode should be disabled
+Example:
+       ds1339: rtc@68 {
+               compatible = "dallas,ds1339";
+               trickle-resistor-ohms = <250>;
+               reg = <0x68>;
+       };
index 7ac7259fe9ea9d61eb208064c364b0998221aa11..ab757b84daa7edab473d2ec907cb0da3386d0b0a 100644 (file)
@@ -3,7 +3,10 @@
 Required properties:
 - compatible: should be one of the following.
     * "samsung,s3c2410-rtc" - for controllers compatible with s3c2410 rtc.
+    * "samsung,s3c2416-rtc" - for controllers compatible with s3c2416 rtc.
+    * "samsung,s3c2443-rtc" - for controllers compatible with s3c2443 rtc.
     * "samsung,s3c6410-rtc" - for controllers compatible with s3c6410 rtc.
+    * "samsung,exynos3250-rtc" - for controllers compatible with exynos3250 rtc.
 - reg: physical base address of the controller and length of memory mapped
   region.
 - interrupts: Two interrupt numbers to the cpu should be specified. First
diff --git a/Documentation/devicetree/bindings/sound/adi,ssm2602.txt b/Documentation/devicetree/bindings/sound/adi,ssm2602.txt
new file mode 100644 (file)
index 0000000..3b3302f
--- /dev/null
@@ -0,0 +1,19 @@
+Analog Devices SSM2602, SSM2603 and SSM2604 I2S audio CODEC devices
+
+SSM2602 support both I2C and SPI as the configuration interface,
+the selection is made by the MODE strap-in pin.
+SSM2603 and SSM2604 only support I2C as the configuration interface.
+
+Required properties:
+
+  - compatible : One of "adi,ssm2602", "adi,ssm2603" or "adi,ssm2604"
+
+  - reg : the I2C address of the device for I2C, the chip select
+          number for SPI.
+
+ Example:
+
+       ssm2602: ssm2602@1a {
+               compatible = "adi,ssm2602";
+               reg = <0x1a>;
+       };
diff --git a/Documentation/devicetree/bindings/sound/cs35l32.txt b/Documentation/devicetree/bindings/sound/cs35l32.txt
new file mode 100644 (file)
index 0000000..1417d3f
--- /dev/null
@@ -0,0 +1,62 @@
+CS35L32 audio CODEC
+
+Required properties:
+
+  - compatible : "cirrus,cs35l32"
+
+  - reg : the I2C address of the device for I2C. Address is determined by the level
+  of the AD0 pin. Level 0 is 0x40 while Level 1 is 0x41.
+
+  - VA-supply, VP-supply : power supplies for the device,
+  as covered in Documentation/devicetree/bindings/regulator/regulator.txt.
+
+Optional properties:
+
+  - reset-gpios : a GPIO spec for the reset pin. If specified, it will be
+  deasserted before communication to the codec starts.
+
+  - cirrus,boost-manager : Boost voltage control.
+  0 = Automatically managed.  Boost-converter output voltage is the higher
+  of the two: Class G or adaptive LED voltage.
+  1 = Automatically managed irrespective of audio, adapting for low-power
+  dissipation when LEDs are ON, and operating in Fixed-Boost Bypass Mode
+  if LEDs are OFF (VBST = VP).
+  2 = (Default) Boost voltage fixed in Bypass Mode (VBST = VP).
+  3 = Boost voltage fixed at 5 V.
+
+  - cirrus,sdout-datacfg : Data configuration for dual CS35L32 applications only.
+  Determines the data packed in a two-CS35L32 configuration.
+  0 = Left/right channels VMON[11:0], IMON[11:0], VPMON[7:0].
+  1 = Left/right channels VMON[11:0], IMON[11:0], STATUS.
+  2 = (Default) left/right channels VMON[15:0], IMON [15:0].
+  3 = Left/right channels VPMON[7:0], STATUS.
+
+  - cirrus,sdout-share : SDOUT sharing. Determines whether one or two CS35L32
+  devices are on board sharing SDOUT.
+  0 = (Default) One IC.
+  1 = Two IC's.
+
+  - cirrus,battery-recovery : Low battery nominal recovery threshold, rising VP.
+  0 = 3.1V
+  1 = 3.2V
+  2 = 3.3V (Default)
+  3 = 3.4V
+
+  - cirrus,battery-threshold : Low battery nominal threshold, falling VP.
+  0 = 3.1V
+  1 = 3.2V
+  2 = 3.3V
+  3 = 3.4V (Default)
+  4 = 3.5V
+  5 = 3.6V
+
+Example:
+
+codec: codec@40 {
+       compatible = "cirrus,cs35l32";
+       reg = <0x40>;
+       reset-gpios = <&gpio 10 0>;
+       cirrus,boost-manager = <0x03>;
+       cirrus,sdout-datacfg = <0x02>;
+       VA-supply = <&reg_audio>;
+};
diff --git a/Documentation/devicetree/bindings/sound/es8328.txt b/Documentation/devicetree/bindings/sound/es8328.txt
new file mode 100644 (file)
index 0000000..30ea8a3
--- /dev/null
@@ -0,0 +1,38 @@
+Everest ES8328 audio CODEC
+
+This device supports both I2C and SPI.
+
+Required properties:
+
+  - compatible : "everest,es8328"
+  - DVDD-supply : Regulator providing digital core supply voltage 1.8 - 3.6V
+  - AVDD-supply : Regulator providing analog supply voltage 3.3V
+  - PVDD-supply : Regulator providing digital IO supply voltage 1.8 - 3.6V
+  - IPVDD-supply : Regulator providing analog output voltage 3.3V
+  - clocks : A 22.5792 or 11.2896 MHz clock
+  - reg : the I2C address of the device for I2C, the chip select number for SPI
+
+Pins on the device (for linking into audio routes):
+
+  * LOUT1
+  * LOUT2
+  * ROUT1
+  * ROUT2
+  * LINPUT1
+  * RINPUT1
+  * LINPUT2
+  * RINPUT2
+  * Mic Bias
+
+
+Example:
+
+codec: es8328@11 {
+       compatible = "everest,es8328";
+       DVDD-supply = <&reg_3p3v>;
+       AVDD-supply = <&reg_3p3v>;
+       PVDD-supply = <&reg_3p3v>;
+       HPVDD-supply = <&reg_3p3v>;
+       clocks = <&clks 169>;
+       reg = <0x11>;
+};
index aeb8c4a0b88d4de37d17e97238d6beb16c6fd20e..52f5b6bf3e8ed7323e7c5da7998731a0ae1c495c 100644 (file)
@@ -7,7 +7,8 @@ other DSPs. It has up to six transmitters and four receivers.
 
 Required properties:
 
-  - compatible : Compatible list, must contain "fsl,imx35-esai".
+  - compatible : Compatible list, must contain "fsl,imx35-esai" or
+                "fsl,vf610-esai"
 
   - reg : Offset and length of the register set for the device.
 
index 3aa4a8f528f486b1b647e3720adbfef6068bbf6c..5b76be45d18bfecce403bf4b1f09730bb74a3c0c 100644 (file)
@@ -58,13 +58,7 @@ Optional properties:
                    Documentation/devicetree/bindings/dma/dma.txt.
 - dma-names:       Two dmas have to be defined, "tx" and "rx", if fsl,imx-fiq
                    is not defined.
-- fsl,mode:         The operating mode for the SSI interface.
-                    "i2s-slave" - I2S mode, SSI is clock slave
-                    "i2s-master" - I2S mode, SSI is clock master
-                    "lj-slave" - left-justified mode, SSI is clock slave
-                    "lj-master" - l.j. mode, SSI is clock master
-                    "rj-slave" - right-justified mode, SSI is clock slave
-                    "rj-master" - r.j., SSI is clock master
+- fsl,mode:         The operating mode for the AC97 interface only.
                     "ac97-slave" - AC97 mode, SSI is clock slave
                     "ac97-master" - AC97 mode, SSI is clock master
 
diff --git a/Documentation/devicetree/bindings/sound/fsl-asoc-card.txt b/Documentation/devicetree/bindings/sound/fsl-asoc-card.txt
new file mode 100644 (file)
index 0000000..a96774c
--- /dev/null
@@ -0,0 +1,82 @@
+Freescale Generic ASoC Sound Card with ASRC support
+
+The Freescale Generic ASoC Sound Card can be used, ideally, for all Freescale
+SoCs connecting with external CODECs.
+
+The idea of this generic sound card is a bit like ASoC Simple Card. However,
+for Freescale SoCs (especially those released in recent years), most of them
+have ASRC (Documentation/devicetree/bindings/sound/fsl,asrc.txt) inside. And
+this is a specific feature that might be painstakingly controlled and merged
+into the Simple Card.
+
+So having this generic sound card allows all Freescale SoC users to benefit
+from the simplification of a new card support and the capability of the wide
+sample rates support through ASRC.
+
+Note: The card is initially designed for those sound cards who use I2S and
+      PCM DAI formats. However, it'll be also possible to support those non
+      I2S/PCM type sound cards, such as S/PDIF audio and HDMI audio, as long
+      as the driver has been properly upgraded.
+
+
+The compatible list for this generic sound card currently:
+ "fsl,imx-audio-cs42888"
+
+ "fsl,imx-audio-wm8962"
+ (compatible with Documentation/devicetree/bindings/sound/imx-audio-wm8962.txt)
+
+ "fsl,imx-audio-sgtl5000"
+ (compatible with Documentation/devicetree/bindings/sound/imx-audio-sgtl5000.txt)
+
+Required properties:
+
+  - compatible         : Contains one of entries in the compatible list.
+
+  - model              : The user-visible name of this sound complex
+
+  - audio-cpu          : The phandle of an CPU DAI controller
+
+  - audio-codec                : The phandle of an audio codec
+
+  - audio-routing      : A list of the connections between audio components.
+                         Each entry is a pair of strings, the first being the
+                         connection's sink, the second being the connection's
+                         source. There're a few pre-designed board connectors:
+                          * Line Out Jack
+                          * Line In Jack
+                          * Headphone Jack
+                          * Mic Jack
+                          * Ext Spk
+                          * AMIC (stands for Analog Microphone Jack)
+                          * DMIC (stands for Digital Microphone Jack)
+
+                         Note: The "Mic Jack" and "AMIC" are redundant while
+                               coexsiting in order to support the old bindings
+                               of wm8962 and sgtl5000.
+
+Optional properties:
+
+  - audio-asrc         : The phandle of ASRC. It can be absent if there's no
+                         need to add ASRC support via DPCM.
+
+Example:
+sound-cs42888 {
+       compatible = "fsl,imx-audio-cs42888";
+       model = "cs42888-audio";
+       audio-cpu = <&esai>;
+       audio-asrc = <&asrc>;
+       audio-codec = <&cs42888>;
+       audio-routing =
+               "Line Out Jack", "AOUT1L",
+               "Line Out Jack", "AOUT1R",
+               "Line Out Jack", "AOUT2L",
+               "Line Out Jack", "AOUT2R",
+               "Line Out Jack", "AOUT3L",
+               "Line Out Jack", "AOUT3R",
+               "Line Out Jack", "AOUT4L",
+               "Line Out Jack", "AOUT4R",
+               "AIN1L", "Line In Jack",
+               "AIN1R", "Line In Jack",
+               "AIN2L", "Line In Jack",
+               "AIN2R", "Line In Jack";
+};
index 0f4e23828190f7bda8d9b829ab7410276b2ead5f..4956b14d4b06175a1d9ba5df9cdb9f72b0813ec5 100644 (file)
@@ -18,12 +18,26 @@ Required properties:
 - pinctrl-names: Must contain a "default" entry.
 - pinctrl-NNN: One property must exist for each entry in pinctrl-names.
   See ../pinctrl/pinctrl-bindings.txt for details of the property values.
-- big-endian-regs: If this property is absent, the little endian mode will
-  be in use as default, or the big endian mode will be in use for all the
-  device registers.
-- big-endian-data: If this property is absent, the little endian mode will
-  be in use as default, or the big endian mode will be in use for all the
-  fifo data.
+- big-endian: Boolean property, required if all the FTM_PWM registers
+  are big-endian rather than little-endian.
+- lsb-first: Configures whether the LSB or the MSB is transmitted first for
+  the fifo data. If this property is absent, the MSB is transmitted first as
+  default, or the LSB is transmitted first.
+- fsl,sai-synchronous-rx: This is a boolean property. If present, indicating
+  that SAI will work in the synchronous mode (sync Tx with Rx) which means
+  both the transimitter and receiver will send and receive data by following
+  receiver's bit clocks and frame sync clocks.
+- fsl,sai-asynchronous: This is a boolean property. If present, indicating
+  that SAI will work in the asynchronous mode, which means both transimitter
+  and receiver will send and receive data by following their own bit clocks
+  and frame sync clocks separately.
+
+Note:
+- If both fsl,sai-asynchronous and fsl,sai-synchronous-rx are absent, the
+  default synchronous mode (sync Rx with Tx) will be used, which means both
+  transimitter and receiver will send and receive data by following clocks
+  of transimitter.
+- fsl,sai-asynchronous and fsl,sai-synchronous-rx are exclusive.
 
 Example:
 sai2: sai@40031000 {
@@ -38,6 +52,6 @@ sai2: sai@40031000 {
              dma-names = "tx", "rx";
              dmas = <&edma0 0 VF610_EDMA_MUXID0_SAI2_TX>,
                   <&edma0 0 VF610_EDMA_MUXID0_SAI2_RX>;
-             big-endian-regs;
-             big-endian-data;
+             big-endian;
+             lsb-first;
 };
diff --git a/Documentation/devicetree/bindings/sound/imx-audio-es8328.txt b/Documentation/devicetree/bindings/sound/imx-audio-es8328.txt
new file mode 100644 (file)
index 0000000..07b68ab
--- /dev/null
@@ -0,0 +1,60 @@
+Freescale i.MX audio complex with ES8328 codec
+
+Required properties:
+- compatible       : "fsl,imx-audio-es8328"
+- model            : The user-visible name of this sound complex
+- ssi-controller   : The phandle of the i.MX SSI controller
+- jack-gpio        : Optional GPIO for headphone jack
+- audio-amp-supply : Power regulator for speaker amps
+- audio-codec      : The phandle of the ES8328 audio codec
+- audio-routing    : A list of the connections between audio components.
+                     Each entry is a pair of strings, the first being the
+                    connection's sink, the second being the connection's
+                    source. Valid names could be power supplies, ES8328
+                    pins, and the jacks on the board:
+
+                       Power supplies:
+                          * audio-amp
+
+                       ES8328 pins:
+                          * LOUT1
+                          * LOUT2
+                          * ROUT1
+                          * ROUT2
+                          * LINPUT1
+                          * LINPUT2
+                          * RINPUT1
+                          * RINPUT2
+                          * Mic PGA
+
+                       Board connectors:
+                          * Headphone
+                          * Speaker
+                          * Mic Jack
+- mux-int-port     : The internal port of the i.MX audio muxer (AUDMUX)
+- mux-ext-port     : The external port of the i.MX audio muxer (AUDMIX)
+
+Note: The AUDMUX port numbering should start at 1, which is consistent with
+hardware manual.
+
+Example:
+
+sound {
+       compatible = "fsl,imx-audio-es8328";
+       model = "imx-audio-es8328";
+       ssi-controller = <&ssi1>;
+       audio-codec = <&codec>;
+       jack-gpio = <&gpio5 15 0>;
+       audio-amp-supply = <&reg_audio_amp>;
+       audio-routing =
+               "Speaker", "LOUT2",
+               "Speaker", "ROUT2",
+               "Speaker", "audio-amp",
+               "Headphone", "ROUT1",
+               "Headphone", "LOUT1",
+               "LINPUT1", "Mic Jack",
+               "RINPUT1", "Mic Jack",
+               "Mic Jack", "Mic Bias";
+       mux-int-port = <1>;
+       mux-ext-port = <3>;
+};
index 9c7c55c7137046f0a539d5df15a8febe56e32a56..c949abc2992f5fd1d8c2e1fcb2eb5a75521037a6 100644 (file)
@@ -25,6 +25,7 @@ Required properties:
 
 Optional properties:
 - nvidia,hp-det-gpios : The GPIO that detect headphones are plugged in
+- nvidia,mic-det-gpios : The GPIO that detect microphones are plugged in
 
 Example:
 
diff --git a/Documentation/devicetree/bindings/sound/rt5677.txt b/Documentation/devicetree/bindings/sound/rt5677.txt
new file mode 100644 (file)
index 0000000..0701b83
--- /dev/null
@@ -0,0 +1,59 @@
+RT5677 audio CODEC
+
+This device supports I2C only.
+
+Required properties:
+
+- compatible : "realtek,rt5677".
+
+- reg : The I2C address of the device.
+
+- interrupts : The CODEC's interrupt output.
+
+- gpio-controller : Indicates this device is a GPIO controller.
+
+- #gpio-cells : Should be two. The first cell is the pin number and the
+  second cell is used to specify optional parameters (currently unused).
+
+Optional properties:
+
+- realtek,pow-ldo2-gpio : The GPIO that controls the CODEC's POW_LDO2 pin.
+
+- realtek,in1-differential
+- realtek,in2-differential
+- realtek,lout1-differential
+- realtek,lout2-differential
+- realtek,lout3-differential
+  Boolean. Indicate MIC1/2 input and LOUT1/2/3 outputs are differential,
+  rather than single-ended.
+
+Pins on the device (for linking into audio routes):
+
+  * IN1P
+  * IN1N
+  * IN2P
+  * IN2N
+  * MICBIAS1
+  * DMIC1
+  * DMIC2
+  * DMIC3
+  * DMIC4
+  * LOUT1
+  * LOUT2
+  * LOUT3
+
+Example:
+
+rt5677 {
+       compatible = "realtek,rt5677";
+       reg = <0x2c>;
+       interrupt-parent = <&gpio>;
+       interrupts = <TEGRA_GPIO(W, 3) GPIO_ACTIVE_HIGH>;
+
+       gpio-controller;
+       #gpio-cells = <2>;
+
+       realtek,pow-ldo2-gpio =
+               <&gpio TEGRA_GPIO(V, 3) GPIO_ACTIVE_HIGH>;
+       realtek,in1-differential = "true";
+};
index c2e9841dfce4e2c258bc85a0f37d4934aa7cf14f..c3cba600bf112b70b4667e2001fe6c02ccb8da93 100644 (file)
@@ -17,6 +17,10 @@ Optional properties:
                                          source.
 - simple-audio-card,mclk-fs             : Multiplication factor between stream rate and codec
                                          mclk.
+- simple-audio-card,hp-det-gpio                : Reference to GPIO that signals when
+                                         headphones are attached.
+- simple-audio-card,mic-det-gpio       : Reference to GPIO that signals when
+                                         a microphone is attached.
 
 Optional subnodes:
 
diff --git a/Documentation/devicetree/bindings/sound/ssm4567.txt b/Documentation/devicetree/bindings/sound/ssm4567.txt
new file mode 100644 (file)
index 0000000..ec3d9e7
--- /dev/null
@@ -0,0 +1,15 @@
+Analog Devices SSM4567 audio amplifier
+
+This device supports I2C only.
+
+Required properties:
+  - compatible : Must be "adi,ssm4567"
+  - reg : the I2C address of the device. This will either be 0x34 (LR_SEL/ADDR connected to AGND),
+       0x35 (LR_SEL/ADDR connected to IOVDD) or 0x36 (LR_SEL/ADDR open).
+
+Example:
+
+       ssm4567: ssm4567@34 {
+               compatible = "adi,ssm4567";
+               reg = <0x34>;
+       };
index 653beaa392dc0495e9db612f775d386ab5014dbc..c7bb11be15a38ce36482bd68e93427293b064d18 100644 (file)
@@ -46,11 +46,13 @@ dmo Data Modul AG
 ebv    EBV Elektronik
 edt    Emerging Display Technologies
 emmicro        EM Microelectronic
+energymicro    Silicon Laboratories (formerly Energy Micro AS)
 epcos  EPCOS AG
 epfl   Ecole Polytechnique Fédérale de Lausanne
 epson  Seiko Epson Corp.
 est    ESTeem Wireless Modems
 eukrea  Eukréa Electromatique
+everest        Everest Semiconductor Co. Ltd.
 excito Excito
 fcs    Fairchild Semiconductor
 fsl    Freescale Semiconductor
@@ -61,6 +63,7 @@ globalscale   Globalscale Technologies, Inc.
 gmt    Global Mixed-mode Technology, Inc.
 google Google, Inc.
 gumstix        Gumstix, Inc.
+gw     Gateworks Corporation
 haoyu  Haoyu Microelectronic Co. Ltd.
 hisilicon      Hisilicon Limited.
 honeywell      Honeywell
@@ -70,6 +73,7 @@ ibm   International Business Machines (IBM)
 idt    Integrated Device Technologies, Inc.
 iom    Iomega Corporation
 img    Imagination Technologies Ltd.
+innolux        Innolux Corporation
 intel  Intel Corporation
 intercontrol   Inter Control Group
 isee   ISEE 2007 S.L.
@@ -88,6 +92,7 @@ maxim Maxim Integrated Products
 mediatek       MediaTek Inc.
 micrel Micrel Inc.
 microchip      Microchip Technology Inc.
+mitsubishi     Mitsubishi Electric Corporation
 mosaixtech     Mosaix Technologies, Inc.
 moxa   Moxa
 mpl    MPL AG
@@ -131,6 +136,7 @@ simtek
 sii    Seiko Instruments, Inc.
 silergy        Silergy Corp.
 sirf   SiRF Technology, Inc.
+sitronix       Sitronix Technology Corporation
 smsc   Standard Microsystems Corporation
 snps   Synopsys, Inc.
 solidrun       SolidRun
@@ -139,6 +145,7 @@ st  STMicroelectronics
 ste    ST-Ericsson
 stericsson     ST-Ericsson
 synology       Synology, Inc.
+thine  THine Electronics, Inc.
 ti     Texas Instruments
 tlm    Trusted Logic Mobility
 toradex        Toradex AG
diff --git a/Documentation/devicetree/bindings/video/adi,adv7123.txt b/Documentation/devicetree/bindings/video/adi,adv7123.txt
new file mode 100644 (file)
index 0000000..a6b2b2b
--- /dev/null
@@ -0,0 +1,50 @@
+Analog Device ADV7123 Video DAC
+-------------------------------
+
+The ADV7123 is a digital-to-analog converter that outputs VGA signals from a
+parallel video input.
+
+Required properties:
+
+- compatible: Should be "adi,adv7123"
+
+Optional properties:
+
+- psave-gpios: Power save control GPIO
+
+Required nodes:
+
+The ADV7123 has two video ports. Their connections are modeled using the OF
+graph bindings specified in Documentation/devicetree/bindings/graph.txt.
+
+- Video port 0 for DPI input
+- Video port 1 for VGA output
+
+
+Example
+-------
+
+       adv7123: encoder@0 {
+               compatible = "adi,adv7123";
+
+               ports {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+
+                       port@0 {
+                               reg = <0>;
+
+                               adv7123_in: endpoint@0 {
+                                       remote-endpoint = <&dpi_out>;
+                               };
+                       };
+
+                       port@1 {
+                               reg = <1>;
+
+                               adv7123_out: endpoint@0 {
+                                       remote-endpoint = <&vga_connector_in>;
+                               };
+                       };
+               };
+       };
index 31036c667d541a8057111915afc5b6c7eb0d6e9f..e74243b4b317ff74728c50b09e66b5f9347f6d69 100644 (file)
@@ -2,6 +2,7 @@ Exynos MIPI DSI Master
 
 Required properties:
   - compatible: value should be one of the following
+               "samsung,exynos3250-mipi-dsi" /* for Exynos3250/3472 SoCs */
                "samsung,exynos4210-mipi-dsi" /* for Exynos4 SoCs */
                "samsung,exynos5410-mipi-dsi" /* for Exynos5410/5420/5440 SoCs */
   - reg: physical base address and length of the registers set for the device
diff --git a/Documentation/devicetree/bindings/video/renesas,du.txt b/Documentation/devicetree/bindings/video/renesas,du.txt
new file mode 100644 (file)
index 0000000..5102830
--- /dev/null
@@ -0,0 +1,84 @@
+* Renesas R-Car Display Unit (DU)
+
+Required Properties:
+
+  - compatible: must be one of the following.
+    - "renesas,du-r8a7779" for R8A7779 (R-Car H1) compatible DU
+    - "renesas,du-r8a7790" for R8A7790 (R-Car H2) compatible DU
+    - "renesas,du-r8a7791" for R8A7791 (R-Car M2) compatible DU
+
+  - reg: A list of base address and length of each memory resource, one for
+    each entry in the reg-names property.
+  - reg-names: Name of the memory resources. The DU requires one memory
+    resource for the DU core (named "du") and one memory resource for each
+    LVDS encoder (named "lvds.x" with "x" being the LVDS controller numerical
+    index).
+
+  - interrupt-parent: phandle of the parent interrupt controller.
+  - interrupts: Interrupt specifiers for the DU interrupts.
+
+  - clocks: A list of phandles + clock-specifier pairs, one for each entry in
+    the clock-names property.
+  - clock-names: Name of the clocks. This property is model-dependent.
+    - R8A7779 uses a single functional clock. The clock doesn't need to be
+      named.
+    - R8A7790 and R8A7791 use one functional clock per channel and one clock
+      per LVDS encoder. The functional clocks must be named "du.x" with "x"
+      being the channel numerical index. The LVDS clocks must be named
+      "lvds.x" with "x" being the LVDS encoder numerical index.
+
+Required nodes:
+
+The connections to the DU output video ports are modeled using the OF graph
+bindings specified in Documentation/devicetree/bindings/graph.txt.
+
+The following table lists for each supported model the port number
+corresponding to each DU output.
+
+               Port 0          Port1           Port2
+-----------------------------------------------------------------------------
+ R8A7779 (H1)  DPAD 0          DPAD 1          -
+ R8A7790 (H2)  DPAD            LVDS 0          LVDS 1
+ R8A7791 (M2)  DPAD            LVDS 0          -
+
+
+Example: R8A7790 (R-Car H2) DU
+
+       du: du@feb00000 {
+               compatible = "renesas,du-r8a7790";
+               reg = <0 0xfeb00000 0 0x70000>,
+                     <0 0xfeb90000 0 0x1c>,
+                     <0 0xfeb94000 0 0x1c>;
+               reg-names = "du", "lvds.0", "lvds.1";
+               interrupt-parent = <&gic>;
+               interrupts = <0 256 IRQ_TYPE_LEVEL_HIGH>,
+                            <0 268 IRQ_TYPE_LEVEL_HIGH>,
+                            <0 269 IRQ_TYPE_LEVEL_HIGH>;
+               clocks = <&mstp7_clks R8A7790_CLK_DU0>,
+                        <&mstp7_clks R8A7790_CLK_DU1>,
+                        <&mstp7_clks R8A7790_CLK_DU2>,
+                        <&mstp7_clks R8A7790_CLK_LVDS0>,
+                        <&mstp7_clks R8A7790_CLK_LVDS1>;
+               clock-names = "du.0", "du.1", "du.2", "lvds.0", "lvds.1";
+
+               ports {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+
+                       port@0 {
+                               reg = <0>;
+                               du_out_rgb: endpoint {
+                               };
+                       };
+                       port@1 {
+                               reg = <1>;
+                               du_out_lvds0: endpoint {
+                               };
+                       };
+                       port@2 {
+                               reg = <2>;
+                               du_out_lvds1: endpoint {
+                               };
+                       };
+               };
+       };
index ecc899b9817b23718a2e321ed58bc6a28209a750..4e6c77c85546790bbb8b85c6528e31287ac9e81a 100644 (file)
@@ -9,6 +9,7 @@ Required properties:
                "samsung,s3c2443-fimd"; /* for S3C24XX SoCs */
                "samsung,s3c6400-fimd"; /* for S3C64XX SoCs */
                "samsung,s5pv210-fimd"; /* for S5PV210 SoC */
+               "samsung,exynos3250-fimd"; /* for Exynos3250/3472 SoCs */
                "samsung,exynos4210-fimd"; /* for Exynos4 SoCs */
                "samsung,exynos5250-fimd"; /* for Exynos5 SoCs */
 
diff --git a/Documentation/devicetree/bindings/video/thine,thc63lvdm83d b/Documentation/devicetree/bindings/video/thine,thc63lvdm83d
new file mode 100644 (file)
index 0000000..527e236
--- /dev/null
@@ -0,0 +1,50 @@
+THine Electronics THC63LVDM83D LVDS serializer
+----------------------------------------------
+
+The THC63LVDM83D is an LVDS serializer designed to support pixel data
+transmission between a host and a flat panel.
+
+Required properties:
+
+- compatible: Should be "thine,thc63lvdm83d"
+
+Optional properties:
+
+- pwdn-gpios: Power down control GPIO
+
+Required nodes:
+
+The THC63LVDM83D has two video ports. Their connections are modeled using the
+OFgraph bindings specified in Documentation/devicetree/bindings/graph.txt.
+
+- Video port 0 for CMOS/TTL input
+- Video port 1 for LVDS output
+
+
+Example
+-------
+
+       lvds_enc: encoder@0 {
+               compatible = "thine,thc63lvdm83d";
+
+               ports {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+
+                       port@0 {
+                               reg = <0>;
+
+                               lvds_enc_in: endpoint@0 {
+                                       remote-endpoint = <&rgb_out>;
+                               };
+                       };
+
+                       port@1 {
+                               reg = <1>;
+
+                               lvds_enc_out: endpoint@0 {
+                                       remote-endpoint = <&panel_in>;
+                               };
+                       };
+               };
+       };
diff --git a/Documentation/devicetree/bindings/video/vga-connector.txt b/Documentation/devicetree/bindings/video/vga-connector.txt
new file mode 100644 (file)
index 0000000..c727f29
--- /dev/null
@@ -0,0 +1,36 @@
+VGA Connector
+=============
+
+Required properties:
+
+- compatible: "vga-connector"
+
+Optional properties:
+
+- label: a symbolic name for the connector corresponding to a hardware label
+- ddc-i2c-bus: phandle to the I2C bus that is connected to VGA DDC
+
+Required nodes:
+
+The VGA connector internal connections are modeled using the OF graph bindings
+specified in Documentation/devicetree/bindings/graph.txt.
+
+The VGA connector has a single port that must be connected to a video source
+port.
+
+
+Example
+-------
+
+vga0: connector@0 {
+       compatible = "vga-connector";
+       label = "vga";
+
+       ddc-i2c-bus = <&i2c3>;
+
+       port {
+               vga_connector_in: endpoint {
+                       remote-endpoint = <&adv7123_out>;
+               };
+       };
+};
index 1f013bd0d32026f92e72351469dff05903d233b0..77685185cf3b77d465a63dd667b794cb57eea7a9 100644 (file)
@@ -51,6 +51,8 @@ Table of Contents
 
   VIII - Specifying device power management information (sleep property)
 
+  IX - Specifying dma bus information
+
   Appendix A - Sample SOC node for MPC8540
 
 
@@ -1332,6 +1334,57 @@ reasonably grouped in this manner, then create a virtual sleep controller
 (similar to an interrupt nexus, except that defining a standardized
 sleep-map should wait until its necessity is demonstrated).
 
+IX - Specifying dma bus information
+
+Some devices may have DMA memory range shifted relatively to the beginning of
+RAM, or even placed outside of kernel RAM. For example, the Keystone 2 SoC
+worked in LPAE mode with 4G memory has:
+- RAM range: [0x8 0000 0000, 0x8 FFFF FFFF]
+- DMA range: [  0x8000 0000,   0xFFFF FFFF]
+and DMA range is aliased into first 2G of RAM in HW.
+
+In such cases, DMA addresses translation should be performed between CPU phys
+and DMA addresses. The "dma-ranges" property is intended to be used
+for describing the configuration of such system in DT.
+
+In addition, each DMA master device on the DMA bus may or may not support
+coherent DMA operations. The "dma-coherent" property is intended to be used
+for identifying devices supported coherent DMA operations in DT.
+
+* DMA Bus master
+Optional property:
+- dma-ranges: <prop-encoded-array> encoded as arbitrary number of triplets of
+       (child-bus-address, parent-bus-address, length). Each triplet specified
+       describes a contiguous DMA address range.
+       The dma-ranges property is used to describe the direct memory access (DMA)
+       structure of a memory-mapped bus whose device tree parent can be accessed
+       from DMA operations originating from the bus. It provides a means of
+       defining a mapping or translation between the physical address space of
+       the bus and the physical address space of the parent of the bus.
+       (for more information see ePAPR specification)
+
+* DMA Bus child
+Optional property:
+- dma-ranges: <empty> value. if present - It means that DMA addresses
+       translation has to be enabled for this device.
+- dma-coherent: Present if dma operations are coherent
+
+Example:
+soc {
+               compatible = "ti,keystone","simple-bus";
+               ranges = <0x0 0x0 0x0 0xc0000000>;
+               dma-ranges = <0x80000000 0x8 0x00000000 0x80000000>;
+
+               [...]
+
+               usb: usb@2680000 {
+                       compatible = "ti,keystone-dwc3";
+
+                       [...]
+                       dma-coherent;
+               };
+};
+
 Appendix A - Sample SOC node for MPC8540
 ========================================
 
diff --git a/Documentation/devicetree/dynamic-resolution-notes.txt b/Documentation/devicetree/dynamic-resolution-notes.txt
new file mode 100644 (file)
index 0000000..083d232
--- /dev/null
@@ -0,0 +1,25 @@
+Device Tree Dynamic Resolver Notes
+----------------------------------
+
+This document describes the implementation of the in-kernel
+Device Tree resolver, residing in drivers/of/resolver.c and is a
+companion document to Documentation/devicetree/dt-object-internal.txt[1]
+
+How the resolver works
+----------------------
+
+The resolver is given as an input an arbitrary tree compiled with the
+proper dtc option and having a /plugin/ tag. This generates the
+appropriate __fixups__ & __local_fixups__ nodes as described in [1].
+
+In sequence the resolver works by the following steps:
+
+1. Get the maximum device tree phandle value from the live tree + 1.
+2. Adjust all the local phandles of the tree to resolve by that amount.
+3. Using the __local__fixups__ node information adjust all local references
+   by the same amount.
+4. For each property in the __fixups__ node locate the node it references
+   in the live tree. This is the label used to tag the node.
+5. Retrieve the phandle of the target of the fixup.
+6. For each fixup in the property locate the node:property:offset location
+   and replace it with the phandle value.
index 3a2f54d07fc52c7903d02a650e07cca161542582..1e3d5c92b5e3b5b8a90ee49612f0417ed335336c 100644 (file)
@@ -67,14 +67,14 @@ struct device_node {
     ...
  };
 
-Figure 1, describes a generic structure of machine’s un-flattened device tree
+Figure 1, describes a generic structure of machine's un-flattened device tree
 considering only child and sibling pointers. There exists another pointer,
 *parent, that is used to traverse the tree in the reverse direction. So, at
 a particular level the child node and all the sibling nodes will have a parent
-pointer pointing to a common node (e.g. child1, sibling2, sibling3, sibling4’s
+pointer pointing to a common node (e.g. child1, sibling2, sibling3, sibling4's
 parent points to root node)
 
-root (‘/’)
+root ('/')
    |
 child1 -> sibling2 -> sibling3 -> sibling4 -> null
    |         |           |           |
@@ -113,8 +113,8 @@ via the following kernel symbols:
 __dtb_testcases_begin - address marking the start of test data blob
 __dtb_testcases_end   - address marking the end of test data blob
 
-Secondly, it calls of_fdt_unflatten_device_tree() to unflatten the flattened
-blob. And finally, if the machine’s device tree (i.e live tree) is present,
+Secondly, it calls of_fdt_unflatten_tree() to unflatten the flattened
+blob. And finally, if the machine's device tree (i.e live tree) is present,
 then it attaches the unflattened test data tree to the live tree, else it
 attaches itself as a live device tree.
 
@@ -122,7 +122,7 @@ attach_node_and_children() uses of_attach_node() to attach the nodes into the
 live tree as explained below. To explain the same, the test data tree described
  in Figure 2 is attached to the live tree described in Figure 1.
 
-root (‘/’)
+root ('/')
     |
  testcase-data
     |
@@ -138,8 +138,8 @@ root->testcase-data->test-child0->test-child01->test-sibling1->test-sibling2
 
 Figure 2: Example test data tree to be attached to live tree.
 
-According to the scenario above, the live tree is already present so it isn’t
-required to attach the root(‘/’) node. All other nodes are attached by calling
+According to the scenario above, the live tree is already present so it isn't
+required to attach the root('/') node. All other nodes are attached by calling
 of_attach_node() on each node.
 
 In the function of_attach_node(), the new node is attached as the child of the
@@ -148,7 +148,7 @@ replaces the current child and turns it into its sibling. So, when the testcase
 data node is attached to the live tree above (Figure 1), the final structure is
  as shown in Figure 3.
 
-root (‘/’)
+root ('/')
    |
 testcase-data -> child1 -> sibling2 -> sibling3 -> sibling4 -> null
    |               |          |           |           |
@@ -170,7 +170,7 @@ testcase-data -> child1 -> sibling2 -> sibling3 -> sibling4 -> null
                                           null
 -----------------------------------------------------------------------
 
-root (‘/’)
+root ('/')
    |
 testcase-data -> child1 -> sibling2 -> sibling3 -> sibling4 -> null
    |               |          |           |           |
@@ -191,8 +191,8 @@ test-child0 the test-sibling1 is attached that pushes the child node
  as mentioned above.
 
 If a duplicate node is found (i.e. if a node with same full_name property is
-already present in the live tree), then the node isn’t attached rather its
-properties are updated to the live tree’s node by calling the function
+already present in the live tree), then the node isn't attached rather its
+properties are updated to the live tree's node by calling the function
 update_node_properties().
 
 
@@ -205,7 +205,7 @@ whole tree). selftest_data_remove() calls detach_node_and_children() that uses
 of_detach_node() to detach the nodes from the live device tree.
 
 To detach a node, of_detach_node() first updates all_next linked list, by
-attaching the previous node’s allnext to current node’s allnext pointer. And
-then, it either updates the child pointer of given node’s parent to its
-sibling or attaches the previous sibling to the given node’s sibling, as
+attaching the previous node's allnext to current node's allnext pointer. And
+then, it either updates the child pointer of given node's parent to its
+sibling or attaches the previous sibling to the given node's sibling, as
 appropriate. That is it :)
index 26c623dd3aa34699561a5cbbeeab4592ff161e97..91b43d2738c7935d8a919a6655b52fc95add8541 100755 (executable)
@@ -708,23 +708,25 @@ sub drxk_terratec_htc_stick {
 }
 
 sub it9135 {
-       my $sourcefile = "dvb-usb-it9135.zip";
-       my $url = "http://www.ite.com.tw/uploads/firmware/v3.6.0.0/$sourcefile";
-       my $hash = "1e55f6c8833f1d0ae067c2bb2953e6a9";
-       my $tmpdir = tempdir(DIR => "/tmp", CLEANUP => 0);
-       my $outfile = "dvb-usb-it9135.fw";
+       my $url = "http://www.ite.com.tw/uploads/firmware/v3.25.0.0/";
+       my $file1 = "dvb-usb-it9135-01.zip";
        my $fwfile1 = "dvb-usb-it9135-01.fw";
+       my $hash1 = "02fcf11174eda84745dae7e61c5ff9ba";
+       my $file2 = "dvb-usb-it9135-02.zip";
        my $fwfile2 = "dvb-usb-it9135-02.fw";
+       my $hash2 = "d5e1437dc24358578e07999475d4cac9";
 
        checkstandard();
 
-       wgetfile($sourcefile, $url);
-       unzip($sourcefile, $tmpdir);
-       verify("$tmpdir/$outfile", $hash);
-       extract("$tmpdir/$outfile", 64, 8128, "$fwfile1");
-       extract("$tmpdir/$outfile", 12866, 5817, "$fwfile2");
+       wgetfile($file1, $url . $file1);
+       unzip($file1, "");
+       verify("$fwfile1", $hash1);
+
+       wgetfile($file2, $url . $file2);
+       unzip($file2, "");
+       verify("$fwfile2", $hash2);
 
-       "$fwfile1 $fwfile2"
+       "$file1 $file2"
 }
 
 sub tda10071 {
index f1997e9da61f1cb2fbb122b610c648c537520185..94d93b1f8b530d44ab3855cdbbdc220fa8a8c60f 100644 (file)
@@ -464,15 +464,12 @@ prototypes:
                        size_t, unsigned int);
        ssize_t (*splice_read)(struct file *, loff_t *, struct pipe_inode_info *,
                        size_t, unsigned int);
-       int (*setlease)(struct file *, long, struct file_lock **);
+       int (*setlease)(struct file *, long, struct file_lock **, void **);
        long (*fallocate)(struct file *, int, loff_t, loff_t);
 };
 
 locking rules:
-       All may block except for ->setlease.
-       No VFS locks held on entry except for ->setlease.
-
-->setlease has the file_list_lock held and must not sleep.
+       All may block.
 
 ->llseek() locking has moved from llseek to the individual llseek
 implementations.  If your fs is not using generic_file_llseek, you
@@ -496,6 +493,10 @@ components. And there are other reasons why the current interface is a mess...
 ->read on directories probably must go away - we should just enforce -EISDIR
 in sys_read() and friends.
 
+->setlease operations should call generic_setlease() before or after setting
+the lease within the individual filesystem to record the result of the
+operation
+
 --------------------------- dquot_operations -------------------------------
 prototypes:
        int (*write_dquot) (struct dquot *);
diff --git a/Documentation/filesystems/autofs4.txt b/Documentation/filesystems/autofs4.txt
new file mode 100644 (file)
index 0000000..39d02e1
--- /dev/null
@@ -0,0 +1,520 @@
+<head>
+<style> p { max-width:50em} ol, ul {max-width: 40em}</style>
+</head>
+
+autofs - how it works
+=====================
+
+Purpose
+-------
+
+The goal of autofs is to provide on-demand mounting and race free
+automatic unmounting of various other filesystems.  This provides two
+key advantages:
+
+1. There is no need to delay boot until all filesystems that
+   might be needed are mounted.  Processes that try to access those
+   slow filesystems might be delayed but other processes can
+   continue freely.  This is particularly important for
+   network filesystems (e.g. NFS) or filesystems stored on
+   media with a media-changing robot.
+
+2. The names and locations of filesystems can be stored in
+   a remote database and can change at any time.  The content
+   in that data base at the time of access will be used to provide
+   a target for the access.  The interpretation of names in the
+   filesystem can even be programmatic rather than database-backed,
+   allowing wildcards for example, and can vary based on the user who
+   first accessed a name.
+
+Context
+-------
+
+The "autofs4" filesystem module is only one part of an autofs system.
+There also needs to be a user-space program which looks up names
+and mounts filesystems.  This will often be the "automount" program,
+though other tools including "systemd" can make use of "autofs4".
+This document describes only the kernel module and the interactions
+required with any user-space program.  Subsequent text refers to this
+as the "automount daemon" or simply "the daemon".
+
+"autofs4" is a Linux kernel module with provides the "autofs"
+filesystem type.  Several "autofs" filesystems can be mounted and they
+can each be managed separately, or all managed by the same daemon.
+
+Content
+-------
+
+An autofs filesystem can contain 3 sorts of objects: directories,
+symbolic links and mount traps.  Mount traps are directories with
+extra properties as described in the next section.
+
+Objects can only be created by the automount daemon: symlinks are
+created with a regular `symlink` system call, while directories and
+mount traps are created with `mkdir`.  The determination of whether a
+directory should be a mount trap or not is quite _ad hoc_, largely for
+historical reasons, and is determined in part by the
+*direct*/*indirect*/*offset* mount options, and the *maxproto* mount option.
+
+If neither the *direct* or *offset* mount options are given (so the
+mount is considered to be *indirect*), then the root directory is
+always a regular directory, otherwise it is a mount trap when it is
+empty and a regular directory when not empty.  Note that *direct* and
+*offset* are treated identically so a concise summary is that the root
+directory is a mount trap only if the filesystem is mounted *direct*
+and the root is empty.
+
+Directories created in the root directory are mount traps only if the
+filesystem is mounted  *indirect* and they are empty.
+
+Directories further down the tree depend on the *maxproto* mount
+option and particularly whether it is less than five or not.
+When *maxproto* is five, no directories further down the
+tree are ever mount traps, they are always regular directories.  When
+the *maxproto* is four (or three), these directories are mount traps
+precisely when they are empty.
+
+So: non-empty (i.e. non-leaf) directories are never mount traps. Empty
+directories are sometimes mount traps, and sometimes not depending on
+where in the tree they are (root, top level, or lower), the *maxproto*,
+and whether the mount was *indirect* or not.
+
+Mount Traps
+---------------
+
+A core element of the implementation of autofs is the Mount Traps
+which are provided by the Linux VFS.  Any directory provided by a
+filesystem can be designated as a trap.  This involves two separate
+features that work together to allow autofs to do its job.
+
+**DCACHE_NEED_AUTOMOUNT**
+
+If a dentry has the DCACHE_NEED_AUTOMOUNT flag set (which gets set if
+the inode has S_AUTOMOUNT set, or can be set directly) then it is
+(potentially) a mount trap.  Any access to this directory beyond a
+"`stat`" will (normally) cause the `d_op->d_automount()` dentry operation
+to be called. The task of this method is to find the filesystem that
+should be mounted on the directory and to return it.  The VFS is
+responsible for actually mounting the root of this filesystem on the
+directory.
+
+autofs doesn't find the filesystem itself but sends a message to the
+automount daemon asking it to find and mount the filesystem.  The
+autofs `d_automount` method then waits for the daemon to report that
+everything is ready.  It will then return "`NULL`" indicating that the
+mount has already happened.  The VFS doesn't try to mount anything but
+follows down the mount that is already there.
+
+This functionality is sufficient for some users of mount traps such
+as NFS which creates traps so that mountpoints on the server can be
+reflected on the client.  However it is not sufficient for autofs.  As
+mounting onto a directory is considered to be "beyond a `stat`", the
+automount daemon would not be able to mount a filesystem on the 'trap'
+directory without some way to avoid getting caught in the trap.  For
+that purpose there is another flag.
+
+**DCACHE_MANAGE_TRANSIT**
+
+If a dentry has DCACHE_MANAGE_TRANSIT set then two very different but
+related behaviors are invoked, both using the `d_op->d_manage()`
+dentry operation.
+
+Firstly, before checking to see if any filesystem is mounted on the
+directory, d_manage() will be called with the `rcu_walk` parameter set
+to `false`.  It may return one of three things:
+
+-  A return value of zero indicates that there is nothing special
+   about this dentry and normal checks for mounts and automounts
+   should proceed.
+
+   autofs normally returns zero, but first waits for any
+   expiry (automatic unmounting of the mounted filesystem) to
+   complete.  This avoids races.
+
+-  A return value of `-EISDIR` tells the VFS to ignore any mounts
+   on the directory and to not consider calling `->d_automount()`.
+   This effectively disables the **DCACHE_NEED_AUTOMOUNT** flag
+   causing the directory not be a mount trap after all.
+
+   autofs returns this if it detects that the process performing the
+   lookup is the automount daemon and that the mount has been
+   requested but has not yet completed.  How it determines this is
+   discussed later.  This allows the automount daemon not to get
+   caught in the mount trap.
+
+   There is a subtlety here.  It is possible that a second autofs
+   filesystem can be mounted below the first and for both of them to
+   be managed by the same daemon.  For the daemon to be able to mount
+   something on the second it must be able to "walk" down past the
+   first.  This means that d_manage cannot *always* return -EISDIR for
+   the automount daemon.  It must only return it when a mount has
+   been requested, but has not yet completed.
+
+   `d_manage` also returns `-EISDIR` if the dentry shouldn't be a
+   mount trap, either because it is a symbolic link or because it is
+   not empty.
+
+-  Any other negative value is treated as an error and returned
+   to the caller.
+
+   autofs can return
+
+   - -ENOENT if the automount daemon failed to mount anything,
+   - -ENOMEM if it ran out of memory,
+   - -EINTR if a signal arrived while waiting for expiry to
+     complete
+   - or any other error sent down by the automount daemon.
+
+
+The second use case only occurs during an "RCU-walk" and so `rcu_walk`
+will be set.
+
+An RCU-walk is a fast and lightweight process for walking down a
+filename path (i.e. it is like running on tip-toes).  RCU-walk cannot
+cope with all situations so when it finds a difficulty it falls back
+to "REF-walk", which is slower but more robust.
+
+RCU-walk will never call `->d_automount`; the filesystems must already
+be mounted or RCU-walk cannot handle the path.
+To determine if a mount-trap is safe for RCU-walk mode it calls
+`->d_manage()` with `rcu_walk` set to `true`.
+
+In this case `d_manage()` must avoid blocking and should avoid taking
+spinlocks if at all possible.  Its sole purpose is to determine if it
+would be safe to follow down into any mounted directory and the only
+reason that it might not be is if an expiry of the mount is
+underway.
+
+In the `rcu_walk` case, `d_manage()` cannot return -EISDIR to tell the
+VFS that this is a directory that doesn't require d_automount.  If
+`rcu_walk` sees a dentry with DCACHE_NEED_AUTOMOUNT set but nothing
+mounted, it *will* fall back to REF-walk.  `d_manage()` cannot make the
+VFS remain in RCU-walk mode, but can only tell it to get out of
+RCU-walk mode by returning `-ECHILD`.
+
+So `d_manage()`, when called with `rcu_walk` set, should either return
+-ECHILD if there is any reason to believe it is unsafe to end the
+mounted filesystem, and otherwise should return 0.
+
+autofs will return `-ECHILD` if an expiry of the filesystem has been
+initiated or is being considered, otherwise it returns 0.
+
+
+Mountpoint expiry
+-----------------
+
+The VFS has a mechansim for automatically expiring unused mounts,
+much as it can expire any unused dentry information from the dcache.
+This is guided by the MNT_SHRINKABLE flag.  This  only applies to
+mounts that were created by `d_automount()` returning a filesystem to be
+mounted.  As autofs doesn't return such a filesystem but leaves the
+mounting to the automount daemon, it must involve the automount daemon
+in unmounting as well.  This also means that autofs has more control
+of expiry.
+
+The VFS also supports "expiry" of mounts using the MNT_EXPIRE flag to
+the `umount` system call.  Unmounting with MNT_EXPIRE will fail unless
+a previous attempt had been made, and the filesystem has been inactive
+and untouched since that previous attempt.  autofs4 does not depend on
+this but has its own internal tracking of whether filesystems were
+recently used.  This allows individual names in the autofs directory
+to expire separately.
+
+With version 4 of the protocol, the automount daemon can try to
+unmount any filesystems mounted on the autofs filesystem or remove any
+symbolic links or empty directories any time it likes.  If the unmount
+or removal is successful the filesystem will be returned to the state
+it was before the mount or creation, so that any access of the name
+will trigger normal auto-mount processing.  In particlar, `rmdir` and
+`unlink` do not leave negative entries in the dcache as a normal
+filesystem would, so an attempt to access a recently-removed object is
+passed to autofs for handling.
+
+With version 5, this is not safe except for unmounting from top-level
+directories.  As lower-level directories are never mount traps, other
+processes will see an empty directory as soon as the filesystem is
+unmounted.  So it is generally safest to use the autofs expiry
+protocol described below.
+
+Normally the daemon only wants to remove entries which haven't been
+used for a while.  For this purpose autofs maintains a "`last_used`"
+time stamp on each directory or symlink.  For symlinks it genuinely
+does record the last time the symlink was "used" or followed to find
+out where it points to.  For directories the field is a slight
+misnomer.  It actually records the last time that autofs checked if
+the directory or one of its descendents was busy and found that it
+was.  This is just as useful and doesn't require updating the field so
+often.
+
+The daemon is able to ask autofs if anything is due to be expired,
+using an `ioctl` as discussed later.  For a *direct* mount, autofs
+considers if the entire mount-tree can be unmounted or not.  For an
+*indirect* mount, autofs considers each of the names in the top level
+directory to determine if any of those can be unmounted and cleaned
+up.
+
+There is an option with indirect mounts to consider each of the leaves
+that has been mounted on instead of considering the top-level names.
+This is intended for compatability with version 4 of autofs and should
+be considered as deprecated.
+
+When autofs considers a directory it checks the `last_used` time and
+compares it with the "timeout" value set when the filesystem was
+mounted, though this check is ignored in some cases. It also checks if
+the directory or anything below it is in use.  For symbolic links,
+only the `last_used` time is ever considered.
+
+If both appear to support expiring the directory or symlink, an action
+is taken.
+
+There are two ways to ask autofs to consider expiry.  The first is to
+use the **AUTOFS_IOC_EXPIRE** ioctl.  This only works for indirect
+mounts.  If it finds something in the root directory to expire it will
+return the name of that thing.  Once a name has been returned the
+automount daemon needs to unmount any filesystems mounted below the
+name normally.  As described above, this is unsafe for non-toplevel
+mounts in a version-5 autofs.  For this reason the current `automountd`
+does not use this ioctl.
+
+The second mechanism uses either the **AUTOFS_DEV_IOCTL_EXPIRE_CMD** or
+the **AUTOFS_IOC_EXPIRE_MULTI** ioctl.  This will work for both direct and
+indirect mounts.  If it selects an object to expire, it will notify
+the daemon using the notification mechanism described below.  This
+will block until the daemon acknowledges the expiry notification.
+This implies that the "`EXPIRE`" ioctl must be sent from a different
+thread than the one which handles notification.
+
+While the ioctl is blocking, the entry is marked as "expiring" and
+`d_manage` will block until the daemon affirms that the unmount has
+completed (together with removing any directories that might have been
+necessary), or has been aborted.
+
+Communicating with autofs: detecting the daemon
+-----------------------------------------------
+
+There are several forms of communication between the automount daemon
+and the filesystem.  As we have already seen, the daemon can create and
+remove directories and symlinks using normal filesystem operations.
+autofs knows whether a process requesting some operation is the daemon
+or not based on its process-group id number (see getpgid(1)).
+
+When an autofs filesystem it mounted the pgid of the mounting
+processes is recorded unless the "pgrp=" option is given, in which
+case that number is recorded instead.  Any request arriving from a
+process in that process group is considered to come from the daemon.
+If the daemon ever has to be stopped and restarted a new pgid can be
+provided through an ioctl as will be described below.
+
+Communicating with autofs: the event pipe
+-----------------------------------------
+
+When an autofs filesystem is mounted, the 'write' end of a pipe must
+be passed using the 'fd=' mount option.  autofs will write
+notification messages to this pipe for the daemon to respond to.
+For version 5, the format of the message is:
+
+        struct autofs_v5_packet {
+                int proto_version;                /* Protocol version */
+                int type;                        /* Type of packet */
+                autofs_wqt_t wait_queue_token;
+                __u32 dev;
+                __u64 ino;
+                __u32 uid;
+                __u32 gid;
+                __u32 pid;
+                __u32 tgid;
+                __u32 len;
+                char name[NAME_MAX+1];
+        };
+
+where the type is one of
+
+        autofs_ptype_missing_indirect
+        autofs_ptype_expire_indirect
+        autofs_ptype_missing_direct
+        autofs_ptype_expire_direct
+
+so messages can indicate that a name is missing (something tried to
+access it but it isn't there) or that it has been selected for expiry.
+
+The pipe will be set to "packet mode" (equivalent to passing
+`O_DIRECT`) to _pipe2(2)_ so that a read from the pipe will return at
+most one packet, and any unread portion of a packet will be discarded.
+
+The `wait_queue_token` is a unique number which can identify a
+particular request to be acknowledged.  When a message is sent over
+the pipe the affected dentry is marked as either "active" or
+"expiring" and other accesses to it block until the message is
+acknowledged using one of the ioctls below and the relevant
+`wait_queue_token`.
+
+Communicating with autofs: root directory ioctls
+------------------------------------------------
+
+The root directory of an autofs filesystem will respond to a number of
+ioctls.   The process issuing the ioctl must have the CAP_SYS_ADMIN
+capability, or must be the automount daemon.
+
+The available ioctl commands are:
+
+- **AUTOFS_IOC_READY**: a notification has been handled.  The argument
+    to the ioctl command is the "wait_queue_token" number
+    corresponding to the notification being acknowledged.
+- **AUTOFS_IOC_FAIL**: similar to above, but indicates failure with
+    the error code `ENOENT`.
+- **AUTOFS_IOC_CATATONIC**: Causes the autofs to enter "catatonic"
+    mode meaning that it stops sending notifications to the daemon.
+    This mode is also entered if a write to the pipe fails.
+- **AUTOFS_IOC_PROTOVER**:  This returns the protocol version in use.
+- **AUTOFS_IOC_PROTOSUBVER**: Returns the protocol sub-version which
+    is really a version number for the implementation.  It is
+    currently 2.
+- **AUTOFS_IOC_SETTIMEOUT**:  This passes a pointer to an unsigned
+    long.  The value is used to set the timeout for expiry, and
+    the current timeout value is stored back through the pointer.
+- **AUTOFS_IOC_ASKUMOUNT**:  Returns, in the pointed-to `int`, 1 if
+    the filesystem could be unmounted.  This is only a hint as
+    the situation could change at any instant.  This call can be
+    use to avoid a more expensive full unmount attempt.
+- **AUTOFS_IOC_EXPIRE**: as described above, this asks if there is
+    anything suitable to expire.  A pointer to a packet:
+
+        struct autofs_packet_expire_multi {
+                int proto_version;              /* Protocol version */
+                int type;                       /* Type of packet */
+                autofs_wqt_t wait_queue_token;
+                int len;
+                char name[NAME_MAX+1];
+        };
+
+     is required.  This is filled in with the name of something
+     that can be unmounted or removed.  If nothing can be expired,
+     `errno` is set to `EAGAIN`.  Even though a `wait_queue_token`
+     is present in the structure, no "wait queue" is established
+     and no acknowledgment is needed.
+- **AUTOFS_IOC_EXPIRE_MULTI**:  This is similar to
+     **AUTOFS_IOC_EXPIRE** except that it causes notification to be
+     sent to the daemon, and it blocks until the daemon acknowledges.
+     The argument is an integer which can contain two different flags.
+
+     **AUTOFS_EXP_IMMEDIATE** causes `last_used` time to be ignored
+     and objects are expired if the are not in use.
+
+     **AUTOFS_EXP_LEAVES** will select a leaf rather than a top-level
+     name to expire.  This is only safe when *maxproto* is 4.
+
+Communicating with autofs: char-device ioctls
+---------------------------------------------
+
+It is not always possible to open the root of an autofs filesystem,
+particularly a *direct* mounted filesystem.  If the automount daemon
+is restarted there is no way for it to regain control of existing
+mounts using any of the above communication channels.  To address this
+need there is a "miscellaneous" character device (major 10, minor 235)
+which can be used to communicate directly with the autofs filesystem.
+It requires CAP_SYS_ADMIN for access.
+
+The `ioctl`s that can be used on this device are described in a separate
+document `autofs4-mount-control.txt`, and are summarized briefly here.
+Each ioctl is passed a pointer to an `autofs_dev_ioctl` structure:
+
+        struct autofs_dev_ioctl {
+                __u32 ver_major;
+                __u32 ver_minor;
+                __u32 size;             /* total size of data passed in
+                                         * including this struct */
+                __s32 ioctlfd;          /* automount command fd */
+
+                __u32 arg1;             /* Command parameters */
+                __u32 arg2;
+
+                char path[0];
+        };
+
+For the **OPEN_MOUNT** and **IS_MOUNTPOINT** commands, the target
+filesystem is identified by the `path`.  All other commands identify
+the filesystem by the `ioctlfd` which is a file descriptor open on the
+root, and which can be returned by **OPEN_MOUNT**.
+
+The `ver_major` and `ver_minor` are in/out parameters which check that
+the requested version is supported, and report the maximum version
+that the kernel module can support.
+
+Commands are:
+
+- **AUTOFS_DEV_IOCTL_VERSION_CMD**: does nothing, except validate and
+    set version numbers.
+- **AUTOFS_DEV_IOCTL_OPENMOUNT_CMD**: return an open file descriptor
+    on the root of an autofs filesystem.  The filesystem is identified
+    by name and device number, which is stored in `arg1`.  Device
+    numbers for existing filesystems can be found in
+    `/proc/self/mountinfo`.
+- **AUTOFS_DEV_IOCTL_CLOSEMOUNT_CMD**: same as `close(ioctlfd)`.
+- **AUTOFS_DEV_IOCTL_SETPIPEFD_CMD**: if the  filesystem is in
+    catatonic mode, this can provide the write end of a new pipe
+    in `arg1` to re-establish communication with a daemon.  The
+    process group of the calling process is used to identify the
+    daemon.
+- **AUTOFS_DEV_IOCTL_REQUESTER_CMD**: `path` should be a
+    name within the filesystem that has been auto-mounted on.
+    arg1 is the dev number of the underlying autofs.  On successful
+    return, `arg1` and `arg2` will be the UID and GID of the process
+    which triggered that mount.
+
+- **AUTOFS_DEV_IOCTL_ISMOUNTPOINT_CMD**: Check if path is a
+    mountpoint of a particular type - see separate documentation for
+    details.
+
+- **AUTOFS_DEV_IOCTL_PROTOVER_CMD**:
+- **AUTOFS_DEV_IOCTL_PROTOSUBVER_CMD**:
+- **AUTOFS_DEV_IOCTL_READY_CMD**:
+- **AUTOFS_DEV_IOCTL_FAIL_CMD**:
+- **AUTOFS_DEV_IOCTL_CATATONIC_CMD**:
+- **AUTOFS_DEV_IOCTL_TIMEOUT_CMD**:
+- **AUTOFS_DEV_IOCTL_EXPIRE_CMD**:
+- **AUTOFS_DEV_IOCTL_ASKUMOUNT_CMD**:  These all have the same
+    function as the similarly named **AUTOFS_IOC** ioctls, except
+    that **FAIL** can be given an explicit error number in `arg1`
+    instead of assuming `ENOENT`, and this **EXPIRE** command
+    corresponds to **AUTOFS_IOC_EXPIRE_MULTI**.
+
+Catatonic mode
+--------------
+
+As mentioned, an autofs mount can enter "catatonic" mode.  This
+happens if a write to the notification pipe fails, or if it is
+explicitly requested by an `ioctl`.
+
+When entering catatonic mode, the pipe is closed and any pending
+notifications are acknowledged with the error `ENOENT`.
+
+Once in catatonic mode attempts to access non-existing names will
+result in `ENOENT` while attempts to access existing directories will
+be treated in the same way as if they came from the daemon, so mount
+traps will not fire.
+
+When the filesystem is mounted a _uid_ and _gid_ can be given which
+set the ownership of directories and symbolic links.  When the
+filesystem is in catatonic mode, any process with a matching UID can
+create directories or symlinks in the root directory, but not in other
+directories.
+
+Catatonic mode can only be left via the
+**AUTOFS_DEV_IOCTL_OPENMOUNT_CMD** ioctl on the `/dev/autofs`.
+
+autofs, name spaces, and shared mounts
+--------------------------------------
+
+With bind mounts and name spaces it is possible for an autofs
+filesystem to appear at multiple places in one or more filesystem
+name spaces.  For this to work sensibly, the autofs filesystem should
+always be mounted "shared". e.g.
+
+> `mount --make-shared /autofs/mount/point`
+
+The automount daemon is only able to mange a single mount location for
+an autofs filesystem and if mounts on that are not 'shared', other
+locations will not behave as expected.  In particular access to those
+other locations will likely result in the `ELOOP` error
+
+> Too many levels of symbolic links
index 61d65cc65c54a333bef994fc49f881ece37032c5..fceff7c00a3c8eb48517cf72d9e9eb1fb3ecc750 100644 (file)
@@ -237,7 +237,7 @@ noted. This means that most methods can block safely. All methods are
 only called from a process context (i.e. not from an interrupt handler
 or bottom half).
 
-  alloc_inode: this method is called by inode_alloc() to allocate memory
+  alloc_inode: this method is called by alloc_inode() to allocate memory
        for struct inode and initialize it.  If this function is not
        defined, a simple 'struct inode' is allocated.  Normally
        alloc_inode will be used to allocate a larger structure which
@@ -826,7 +826,7 @@ struct file_operations {
        int (*flock) (struct file *, int, struct file_lock *);
        ssize_t (*splice_write)(struct pipe_inode_info *, struct file *, size_t, unsigned int);
        ssize_t (*splice_read)(struct file *, struct pipe_inode_info *, size_t, unsigned int);
-       int (*setlease)(struct file *, long arg, struct file_lock **);
+       int (*setlease)(struct file *, long arg, struct file_lock **, void **);
        long (*fallocate)(struct file *, int mode, loff_t offset, loff_t len);
        int (*show_fdinfo)(struct seq_file *m, struct file *f);
 };
@@ -895,8 +895,9 @@ otherwise noted.
   splice_read: called by the VFS to splice data from file to a pipe. This
               method is used by the splice(2) system call
 
-  setlease: called by the VFS to set or release a file lock lease.
-           setlease has the file_lock_lock held and must not sleep.
+  setlease: called by the VFS to set or release a file lock lease. setlease
+           implementations should call generic_setlease to record or remove
+           the lease in the inode after setting it.
 
   fallocate: called by the VFS to preallocate blocks or punch a hole.
 
index ee6d30ec152217a20d6e5fea30d790467eae8720..254d2f55345a2786773eacbc60fb100c96400cd5 100644 (file)
@@ -11,7 +11,7 @@ Supported chips:
   Socket S1G2: Athlon (X2), Sempron (X2), Turion X2 (Ultra)
 * AMD Family 12h processors: "Llano" (E2/A4/A6/A8-Series)
 * AMD Family 14h processors: "Brazos" (C/E/G/Z-Series)
-* AMD Family 15h processors: "Bulldozer" (FX-Series), "Trinity", "Kaveri"
+* AMD Family 15h processors: "Bulldozer" (FX-Series), "Trinity", "Kaveri", "Carrizo"
 * AMD Family 16h processors: "Kabini", "Mullins"
 
   Prefix: 'k10temp'
diff --git a/Documentation/hwmon/menf21bmc b/Documentation/hwmon/menf21bmc
new file mode 100644 (file)
index 0000000..2a273a0
--- /dev/null
@@ -0,0 +1,50 @@
+Kernel driver menf21bmc_hwmon
+=============================
+
+Supported chips:
+       * MEN 14F021P00
+         Prefix: 'menf21bmc_hwmon'
+         Adresses scanned: -
+
+Author: Andreas Werner <andreas.werner@men.de>
+
+Description
+-----------
+
+The menf21bmc is a Board Management Controller (BMC) which provides an I2C
+interface to the host to access the features implemented in the BMC.
+
+This driver gives access to the voltage monitoring feature of the main
+voltages of the board.
+The voltage sensors are connected to the ADC inputs of the BMC which is
+a PIC16F917 Mikrocontroller.
+
+Usage Notes
+-----------
+
+This driver is part of the MFD driver named "menf21bmc" and does
+not auto-detect devices.
+You will have to instantiate the MFD driver explicitly.
+Please see Documentation/i2c/instantiating-devices for
+details.
+
+Sysfs entries
+-------------
+
+The following attributes are supported. All attributes are read only
+The Limits are read once by the driver.
+
+in0_input      +3.3V input voltage
+in1_input      +5.0V input voltage
+in2_input      +12.0V input voltage
+in3_input      +5V Standby input voltage
+in4_input      VBAT (on board battery)
+
+in[0-4]_min    Minimum voltage limit
+in[0-4]_max    Maximum voltage limit
+
+in0_label      "MON_3_3V"
+in1_label      "MON_5V"
+in2_label      "MON_12V"
+in3_label      "5V_STANDBY"
+in4_label      "VBAT"
index 7e240a7c9ab1bff49a57bbb97904f64cf9c63b9e..8136e1fd30fdede7141d70bc00f5c6b8097ed981 100644 (file)
@@ -313,6 +313,7 @@ Code  Seq#(hex)     Include File            Comments
 0xB1   00-1F   PPPoX                   <mailto:mostrows@styx.uwaterloo.ca>
 0xB3   00      linux/mmc/ioctl.h
 0xC0   00-0F   linux/usb/iowarrior.h
+0xCA   00-0F   uapi/misc/cxl.h
 0xCB   00-1F   CBM serial IEC bus      in development:
                                        <mailto:michael.klein@puffin.lb.shuttle.de>
 0xCD   01      linux/reiserfs_fs.h
index 764f5991a3fc74c32d9f218be85b5c977ea4efde..a311db829e9bb6a819bc293404d65d5c3584a741 100644 (file)
@@ -174,7 +174,7 @@ more details, with real examples.
 
 --- 3.3 Loadable module goals - obj-m
 
-       $(obj-m) specify object files which are built as loadable
+       $(obj-m) specifies object files which are built as loadable
        kernel modules.
 
        A module may be built from one source file or several source
@@ -277,7 +277,7 @@ more details, with real examples.
        down in the ext2 directory.
        Kbuild only uses this information to decide that it needs to visit
        the directory, it is the Makefile in the subdirectory that
-       specifies what is modules and what is built-in.
+       specifies what is modular and what is built-in.
 
        It is good practice to use a CONFIG_ variable when assigning directory
        names. This allows kbuild to totally skip the directory if the
@@ -403,7 +403,7 @@ more details, with real examples.
        echoing information to user in a rule is often a good practice
        but when execution "make -s" one does not expect to see any output
        except for warnings/errors.
-       To support this kbuild define $(kecho) which will echo out the
+       To support this kbuild defines $(kecho) which will echo out the
        text following $(kecho) to stdout except if "make -s" is used.
 
        Example:
@@ -417,7 +417,7 @@ more details, with real examples.
 
        The kernel may be built with several different versions of
        $(CC), each supporting a unique set of features and options.
-       kbuild provide basic support to check for valid options for $(CC).
+       kbuild provides basic support to check for valid options for $(CC).
        $(CC) is usually the gcc compiler, but other alternatives are
        available.
 
@@ -456,8 +456,8 @@ more details, with real examples.
        Note: as-instr-option uses KBUILD_AFLAGS for $(AS) options
 
     cc-option
-       cc-option is used to check if $(CC) supports a given option, and not
-       supported to use an optional second option.
+       cc-option is used to check if $(CC) supports a given option, and if
+       not supported to use an optional second option.
 
        Example:
                #arch/x86/Makefile
@@ -557,8 +557,8 @@ more details, with real examples.
                        false ; \
                fi
 
-       In this example for a specific GCC version the build will error out explaining
-       to the user why it stops.
+       In this example for a specific GCC version the build will error out
+       explaining to the user why it stops.
 
     cc-cross-prefix
        cc-cross-prefix is used to check if there exists a $(CC) in path with
@@ -656,7 +656,7 @@ Both possibilities are described in the following.
        In the example above the executable is composed of the C++ file
        qconf.cc - identified by $(qconf-cxxobjs).
 
-       If qconf is composed by a mixture of .c and .cc files, then an
+       If qconf is composed of a mixture of .c and .cc files, then an
        additional line can be used to identify this.
 
        Example:
@@ -733,7 +733,7 @@ Both possibilities are described in the following.
                hostprogs-$(CONFIG_KALLSYMS) += kallsyms
 
        Kbuild knows about both 'y' for built-in and 'm' for module.
-       So if a config symbol evaluate to 'm', kbuild will still build
+       So if a config symbol evaluates to 'm', kbuild will still build
        the binary. In other words, Kbuild handles hostprogs-m exactly
        like hostprogs-y. But only hostprogs-y is recommended to be used
        when no CONFIG symbols are involved.
@@ -754,8 +754,8 @@ Additional files can be specified in kbuild makefiles by use of $(clean-files).
                #drivers/pci/Makefile
                clean-files := devlist.h classlist.h
 
-When executing "make clean", the two files "devlist.h classlist.h" will
-be deleted. Kbuild will assume files to be in same relative directory as the
+When executing "make clean", the two files "devlist.h classlist.h" will be
+deleted. Kbuild will assume files to be in the same relative directory as the
 Makefile except if an absolute path is specified (path starting with '/').
 
 To delete a directory hierarchy use:
@@ -786,7 +786,7 @@ is not sufficient this sometimes needs to be explicit.
 The above assignment instructs kbuild to descend down in the
 directory compressed/ when "make clean" is executed.
 
-To support the clean infrastructure in the Makefiles that builds the
+To support the clean infrastructure in the Makefiles that build the
 final bootimage there is an optional target named archclean:
 
        Example:
@@ -818,17 +818,16 @@ a few targets.
 When kbuild executes, the following steps are followed (roughly):
 1) Configuration of the kernel => produce .config
 2) Store kernel version in include/linux/version.h
-3) Symlink include/asm to include/asm-$(ARCH)
-4) Updating all other prerequisites to the target prepare:
+3) Updating all other prerequisites to the target prepare:
    - Additional prerequisites are specified in arch/$(ARCH)/Makefile
-5) Recursively descend down in all directories listed in
+4) Recursively descend down in all directories listed in
    init-* core* drivers-* net-* libs-* and build all targets.
    - The values of the above variables are expanded in arch/$(ARCH)/Makefile.
-6) All object files are then linked and the resulting file vmlinux is
+5) All object files are then linked and the resulting file vmlinux is
    located at the root of the obj tree.
    The very first objects linked are listed in head-y, assigned by
    arch/$(ARCH)/Makefile.
-7) Finally, the architecture-specific part does any required post processing
+6) Finally, the architecture-specific part does any required post processing
    and builds the final bootimage.
    - This includes building boot records
    - Preparing initrd images and the like
@@ -927,7 +926,7 @@ When kbuild executes, the following steps are followed (roughly):
 
     KBUILD_AFLAGS_MODULE   Options for $(AS) when building modules
 
-       $(KBUILD_AFLAGS_MODULE) is used to add arch specific options that
+       $(KBUILD_AFLAGS_MODULE) is used to add arch-specific options that
        are used for $(AS).
        From commandline AFLAGS_MODULE shall be used (see kbuild.txt).
 
@@ -938,13 +937,13 @@ When kbuild executes, the following steps are followed (roughly):
 
     KBUILD_CFLAGS_MODULE   Options for $(CC) when building modules
 
-       $(KBUILD_CFLAGS_MODULE) is used to add arch specific options that
+       $(KBUILD_CFLAGS_MODULE) is used to add arch-specific options that
        are used for $(CC).
        From commandline CFLAGS_MODULE shall be used (see kbuild.txt).
 
     KBUILD_LDFLAGS_MODULE   Options for $(LD) when linking modules
 
-       $(KBUILD_LDFLAGS_MODULE) is used to add arch specific options
+       $(KBUILD_LDFLAGS_MODULE) is used to add arch-specific options
        used when linking modules. This is often a linker script.
        From commandline LDFLAGS_MODULE shall be used (see kbuild.txt).
 
@@ -1066,7 +1065,7 @@ When kbuild executes, the following steps are followed (roughly):
 
     extra-y
 
-       extra-y specify additional targets created in the current
+       extra-y specifies additional targets created in the current
        directory, in addition to any targets specified by obj-*.
 
        Listing all targets in extra-y is required for two purposes:
@@ -1093,7 +1092,7 @@ When kbuild executes, the following steps are followed (roughly):
 
        Usage:
                target: source(s) FORCE
-                       $(call if_changed,ld/objcopy/gzip)
+                       $(call if_changed,ld/objcopy/gzip/...)
 
        When the rule is evaluated, it is checked to see if any files
        need an update, or the command line has changed since the last
@@ -1111,7 +1110,7 @@ When kbuild executes, the following steps are followed (roughly):
        significant; for instance, the below will fail (note the extra space
        after the comma):
                target: source(s) FORCE
-       #WRONG!#        $(call if_changed, ld/objcopy/gzip)
+       #WRONG!#        $(call if_changed, ld/objcopy/gzip/...)
 
     ld
        Link target. Often, LDFLAGS_$@ is used to set specific options to ld.
@@ -1142,8 +1141,8 @@ When kbuild executes, the following steps are followed (roughly):
                2) delete target during make clean
 
        The ": %: %.o" part of the prerequisite is a shorthand that
-       free us from listing the setup.o and bootsect.o files.
-       Note: It is a common mistake to forget the "target :=" assignment,
+       frees us from listing the setup.o and bootsect.o files.
+       Note: It is a common mistake to forget the "targets :=" assignment,
              resulting in the target file being recompiled for no
              obvious reason.
 
@@ -1164,29 +1163,6 @@ When kbuild executes, the following steps are followed (roughly):
                clean-files += *.dtb
                DTC_FLAGS ?= -p 1024
 
-    dtc_cpp
-       This is just like dtc as describe above, except that the C pre-
-       processor is invoked upon the .dtsp file before compiling the result
-       with dtc.
-
-       In order for build dependencies to work, all files compiled using
-       dtc_cpp must use the C pre-processor's #include functionality and not
-       dtc's /include/ functionality.
-
-       Using the C pre-processor allows use of #define to create named
-       constants. In turn, the #defines will typically appear in a header
-       file, which may be shared with regular C code. Since the dtc language
-       represents a data structure rather than code in C syntax, similar
-       restrictions are placed on a header file included by a device tree
-       file as for a header file included by an assembly language file.
-       In particular, the C pre-processor is passed -x assembler-with-cpp,
-       which sets macro __ASSEMBLY__. __DTS__ is also set. These allow header
-       files to restrict their content to that compatible with device tree
-       source.
-
-       A central rule exists to create $(obj)/%.dtb from $(src)/%.dtsp;
-       architecture Makefiles do no need to explicitly write out that rule.
-
 --- 6.8 Custom kbuild commands
 
        When kbuild is executing with KBUILD_VERBOSE=0, then only a shorthand
@@ -1237,11 +1213,11 @@ When kbuild executes, the following steps are followed (roughly):
        When building the *.lds target, kbuild uses the variables:
        KBUILD_CPPFLAGS : Set in top-level Makefile
        cppflags-y      : May be set in the kbuild makefile
-       CPPFLAGS_$(@F)  : Target specific flags.
+       CPPFLAGS_$(@F)  : Target-specific flags.
                          Note that the full filename is used in this
                          assignment.
 
-       The kbuild infrastructure for *lds file are used in several
+       The kbuild infrastructure for *lds files is used in several
        architecture-specific files.
 
 --- 6.10 Generic header files
@@ -1254,11 +1230,11 @@ When kbuild executes, the following steps are followed (roughly):
 
 === 7 Kbuild syntax for exported headers
 
-The kernel include a set of headers that is exported to userspace.
+The kernel includes a set of headers that is exported to userspace.
 Many headers can be exported as-is but other headers require a
 minimal pre-processing before they are ready for user-space.
 The pre-processing does:
-- drop kernel specific annotations
+- drop kernel-specific annotations
 - drop include of compiler.h
 - drop all sections that are kernel internal (guarded by ifdef __KERNEL__)
 
@@ -1268,7 +1244,7 @@ See subsequent chapter for the syntax of the Kbuild file.
 
        --- 7.1 header-y
 
-       header-y specify header files to be exported.
+       header-y specifies header files to be exported.
 
                Example:
                        #include/linux/Kbuild
@@ -1278,7 +1254,7 @@ See subsequent chapter for the syntax of the Kbuild file.
        The convention is to list one file per line and
        preferably in alphabetic order.
 
-       header-y also specify which subdirectories to visit.
+       header-y also specifies which subdirectories to visit.
        A subdirectory is identified by a trailing '/' which
        can be seen in the example above for the usb subdirectory.
 
@@ -1296,9 +1272,9 @@ See subsequent chapter for the syntax of the Kbuild file.
 
        --- 7.3 destination-y
 
-       When an architecture have a set of exported headers that needs to be
+       When an architecture has a set of exported headers that needs to be
        exported to a different directory destination-y is used.
-       destination-y specify the destination directory for all exported
+       destination-y specifies the destination directory for all exported
        headers in the file where it is present.
 
                Example:
@@ -1391,9 +1367,9 @@ The top Makefile exports the following variables:
 
     INSTALL_MOD_STRIP
 
-       If this variable is specified, will cause modules to be stripped
+       If this variable is specified, it will cause modules to be stripped
        after they are installed.  If INSTALL_MOD_STRIP is '1', then the
-       default option --strip-debug will be used.  Otherwise,
+       default option --strip-debug will be used.  Otherwise, the
        INSTALL_MOD_STRIP value will be used as the option(s) to the strip
        command.
 
index 41f7ec1fcf6137af6c07ff71a22ac98cbc52beaa..04e9f5505faa8fa4133c198a946cdefab241824d 100644 (file)
@@ -1323,7 +1323,7 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
                        Set number of hash buckets for inode cache.
 
        ima_appraise=   [IMA] appraise integrity measurements
-                       Format: { "off" | "enforce" | "fix" }
+                       Format: { "off" | "enforce" | "fix" | "log" }
                        default: "enforce"
 
        ima_appraise_tcb [IMA]
@@ -1723,6 +1723,49 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
        lockd.nlm_udpport=M     [NFS] Assign UDP port.
                        Format: <integer>
 
+       locktorture.nreaders_stress= [KNL]
+                       Set the number of locking read-acquisition kthreads.
+                       Defaults to being automatically set based on the
+                       number of online CPUs.
+
+       locktorture.nwriters_stress= [KNL]
+                       Set the number of locking write-acquisition kthreads.
+
+       locktorture.onoff_holdoff= [KNL]
+                       Set time (s) after boot for CPU-hotplug testing.
+
+       locktorture.onoff_interval= [KNL]
+                       Set time (s) between CPU-hotplug operations, or
+                       zero to disable CPU-hotplug testing.
+
+       locktorture.shuffle_interval= [KNL]
+                       Set task-shuffle interval (jiffies).  Shuffling
+                       tasks allows some CPUs to go into dyntick-idle
+                       mode during the locktorture test.
+
+       locktorture.shutdown_secs= [KNL]
+                       Set time (s) after boot system shutdown.  This
+                       is useful for hands-off automated testing.
+
+       locktorture.stat_interval= [KNL]
+                       Time (s) between statistics printk()s.
+
+       locktorture.stutter= [KNL]
+                       Time (s) to stutter testing, for example,
+                       specifying five seconds causes the test to run for
+                       five seconds, wait for five seconds, and so on.
+                       This tests the locking primitive's ability to
+                       transition abruptly to and from idle.
+
+       locktorture.torture_runnable= [BOOT]
+                       Start locktorture running at boot time.
+
+       locktorture.torture_type= [KNL]
+                       Specify the locking implementation to test.
+
+       locktorture.verbose= [KNL]
+                       Enable additional printk() statements.
+
        logibm.irq=     [HW,MOUSE] Logitech Bus Mouse Driver
                        Format: <irq>
 
@@ -2900,6 +2943,24 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
                        Lazy RCU callbacks are those which RCU can
                        prove do nothing more than free memory.
 
+       rcutorture.cbflood_inter_holdoff= [KNL]
+                       Set holdoff time (jiffies) between successive
+                       callback-flood tests.
+
+       rcutorture.cbflood_intra_holdoff= [KNL]
+                       Set holdoff time (jiffies) between successive
+                       bursts of callbacks within a given callback-flood
+                       test.
+
+       rcutorture.cbflood_n_burst= [KNL]
+                       Set the number of bursts making up a given
+                       callback-flood test.  Set this to zero to
+                       disable callback-flood testing.
+
+       rcutorture.cbflood_n_per_burst= [KNL]
+                       Set the number of callbacks to be registered
+                       in a given burst of a callback-flood test.
+
        rcutorture.fqs_duration= [KNL]
                        Set duration of force_quiescent_state bursts.
 
@@ -2939,7 +3000,7 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
                        Set time (s) between CPU-hotplug operations, or
                        zero to disable CPU-hotplug testing.
 
-       rcutorture.rcutorture_runnable= [BOOT]
+       rcutorture.torture_runnable= [BOOT]
                        Start rcutorture running at boot time.
 
        rcutorture.shuffle_interval= [KNL]
@@ -3001,6 +3062,11 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
        rcupdate.rcu_cpu_stall_timeout= [KNL]
                        Set timeout for RCU CPU stall warning messages.
 
+       rcupdate.rcu_task_stall_timeout= [KNL]
+                       Set timeout in jiffies for RCU task stall warning
+                       messages.  Disable with a value less than or equal
+                       to zero.
+
        rdinit=         [KNL]
                        Format: <full_path>
                        Run specified binary instead of /init from the ramdisk,
index 4bbeca8483ed339f7efd5b6314da77f9b4a99f0d..4227ec2e3ab21c13dd6e07342e264e257005a2a0 100644 (file)
@@ -300,6 +300,7 @@ architectures:
 - arm
 - ppc
 - mips
+- s390
 
 3. Configuring Kprobes
 
diff --git a/Documentation/lockdep-design.txt b/Documentation/lockdep-design.txt
deleted file mode 100644 (file)
index 5dbc99c..0000000
+++ /dev/null
@@ -1,286 +0,0 @@
-Runtime locking correctness validator
-=====================================
-
-started by Ingo Molnar <mingo@redhat.com>
-additions by Arjan van de Ven <arjan@linux.intel.com>
-
-Lock-class
-----------
-
-The basic object the validator operates upon is a 'class' of locks.
-
-A class of locks is a group of locks that are logically the same with
-respect to locking rules, even if the locks may have multiple (possibly
-tens of thousands of) instantiations. For example a lock in the inode
-struct is one class, while each inode has its own instantiation of that
-lock class.
-
-The validator tracks the 'state' of lock-classes, and it tracks
-dependencies between different lock-classes. The validator maintains a
-rolling proof that the state and the dependencies are correct.
-
-Unlike an lock instantiation, the lock-class itself never goes away: when
-a lock-class is used for the first time after bootup it gets registered,
-and all subsequent uses of that lock-class will be attached to this
-lock-class.
-
-State
------
-
-The validator tracks lock-class usage history into 4n + 1 separate state bits:
-
-- 'ever held in STATE context'
-- 'ever held as readlock in STATE context'
-- 'ever held with STATE enabled'
-- 'ever held as readlock with STATE enabled'
-
-Where STATE can be either one of (kernel/lockdep_states.h)
- - hardirq
- - softirq
- - reclaim_fs
-
-- 'ever used'                                       [ == !unused        ]
-
-When locking rules are violated, these state bits are presented in the
-locking error messages, inside curlies. A contrived example:
-
-   modprobe/2287 is trying to acquire lock:
-    (&sio_locks[i].lock){-.-...}, at: [<c02867fd>] mutex_lock+0x21/0x24
-
-   but task is already holding lock:
-    (&sio_locks[i].lock){-.-...}, at: [<c02867fd>] mutex_lock+0x21/0x24
-
-
-The bit position indicates STATE, STATE-read, for each of the states listed
-above, and the character displayed in each indicates:
-
-   '.'  acquired while irqs disabled and not in irq context
-   '-'  acquired in irq context
-   '+'  acquired with irqs enabled
-   '?'  acquired in irq context with irqs enabled.
-
-Unused mutexes cannot be part of the cause of an error.
-
-
-Single-lock state rules:
-------------------------
-
-A softirq-unsafe lock-class is automatically hardirq-unsafe as well. The
-following states are exclusive, and only one of them is allowed to be
-set for any lock-class:
-
- <hardirq-safe> and <hardirq-unsafe>
- <softirq-safe> and <softirq-unsafe>
-
-The validator detects and reports lock usage that violate these
-single-lock state rules.
-
-Multi-lock dependency rules:
-----------------------------
-
-The same lock-class must not be acquired twice, because this could lead
-to lock recursion deadlocks.
-
-Furthermore, two locks may not be taken in different order:
-
- <L1> -> <L2>
- <L2> -> <L1>
-
-because this could lead to lock inversion deadlocks. (The validator
-finds such dependencies in arbitrary complexity, i.e. there can be any
-other locking sequence between the acquire-lock operations, the
-validator will still track all dependencies between locks.)
-
-Furthermore, the following usage based lock dependencies are not allowed
-between any two lock-classes:
-
-   <hardirq-safe>   ->  <hardirq-unsafe>
-   <softirq-safe>   ->  <softirq-unsafe>
-
-The first rule comes from the fact the a hardirq-safe lock could be
-taken by a hardirq context, interrupting a hardirq-unsafe lock - and
-thus could result in a lock inversion deadlock. Likewise, a softirq-safe
-lock could be taken by an softirq context, interrupting a softirq-unsafe
-lock.
-
-The above rules are enforced for any locking sequence that occurs in the
-kernel: when acquiring a new lock, the validator checks whether there is
-any rule violation between the new lock and any of the held locks.
-
-When a lock-class changes its state, the following aspects of the above
-dependency rules are enforced:
-
-- if a new hardirq-safe lock is discovered, we check whether it
-  took any hardirq-unsafe lock in the past.
-
-- if a new softirq-safe lock is discovered, we check whether it took
-  any softirq-unsafe lock in the past.
-
-- if a new hardirq-unsafe lock is discovered, we check whether any
-  hardirq-safe lock took it in the past.
-
-- if a new softirq-unsafe lock is discovered, we check whether any
-  softirq-safe lock took it in the past.
-
-(Again, we do these checks too on the basis that an interrupt context
-could interrupt _any_ of the irq-unsafe or hardirq-unsafe locks, which
-could lead to a lock inversion deadlock - even if that lock scenario did
-not trigger in practice yet.)
-
-Exception: Nested data dependencies leading to nested locking
--------------------------------------------------------------
-
-There are a few cases where the Linux kernel acquires more than one
-instance of the same lock-class. Such cases typically happen when there
-is some sort of hierarchy within objects of the same type. In these
-cases there is an inherent "natural" ordering between the two objects
-(defined by the properties of the hierarchy), and the kernel grabs the
-locks in this fixed order on each of the objects.
-
-An example of such an object hierarchy that results in "nested locking"
-is that of a "whole disk" block-dev object and a "partition" block-dev
-object; the partition is "part of" the whole device and as long as one
-always takes the whole disk lock as a higher lock than the partition
-lock, the lock ordering is fully correct. The validator does not
-automatically detect this natural ordering, as the locking rule behind
-the ordering is not static.
-
-In order to teach the validator about this correct usage model, new
-versions of the various locking primitives were added that allow you to
-specify a "nesting level". An example call, for the block device mutex,
-looks like this:
-
-enum bdev_bd_mutex_lock_class
-{
-       BD_MUTEX_NORMAL,
-       BD_MUTEX_WHOLE,
-       BD_MUTEX_PARTITION
-};
-
- mutex_lock_nested(&bdev->bd_contains->bd_mutex, BD_MUTEX_PARTITION);
-
-In this case the locking is done on a bdev object that is known to be a
-partition.
-
-The validator treats a lock that is taken in such a nested fashion as a
-separate (sub)class for the purposes of validation.
-
-Note: When changing code to use the _nested() primitives, be careful and
-check really thoroughly that the hierarchy is correctly mapped; otherwise
-you can get false positives or false negatives.
-
-Proof of 100% correctness:
---------------------------
-
-The validator achieves perfect, mathematical 'closure' (proof of locking
-correctness) in the sense that for every simple, standalone single-task
-locking sequence that occurred at least once during the lifetime of the
-kernel, the validator proves it with a 100% certainty that no
-combination and timing of these locking sequences can cause any class of
-lock related deadlock. [*]
-
-I.e. complex multi-CPU and multi-task locking scenarios do not have to
-occur in practice to prove a deadlock: only the simple 'component'
-locking chains have to occur at least once (anytime, in any
-task/context) for the validator to be able to prove correctness. (For
-example, complex deadlocks that would normally need more than 3 CPUs and
-a very unlikely constellation of tasks, irq-contexts and timings to
-occur, can be detected on a plain, lightly loaded single-CPU system as
-well!)
-
-This radically decreases the complexity of locking related QA of the
-kernel: what has to be done during QA is to trigger as many "simple"
-single-task locking dependencies in the kernel as possible, at least
-once, to prove locking correctness - instead of having to trigger every
-possible combination of locking interaction between CPUs, combined with
-every possible hardirq and softirq nesting scenario (which is impossible
-to do in practice).
-
-[*] assuming that the validator itself is 100% correct, and no other
-    part of the system corrupts the state of the validator in any way.
-    We also assume that all NMI/SMM paths [which could interrupt
-    even hardirq-disabled codepaths] are correct and do not interfere
-    with the validator. We also assume that the 64-bit 'chain hash'
-    value is unique for every lock-chain in the system. Also, lock
-    recursion must not be higher than 20.
-
-Performance:
-------------
-
-The above rules require _massive_ amounts of runtime checking. If we did
-that for every lock taken and for every irqs-enable event, it would
-render the system practically unusably slow. The complexity of checking
-is O(N^2), so even with just a few hundred lock-classes we'd have to do
-tens of thousands of checks for every event.
-
-This problem is solved by checking any given 'locking scenario' (unique
-sequence of locks taken after each other) only once. A simple stack of
-held locks is maintained, and a lightweight 64-bit hash value is
-calculated, which hash is unique for every lock chain. The hash value,
-when the chain is validated for the first time, is then put into a hash
-table, which hash-table can be checked in a lockfree manner. If the
-locking chain occurs again later on, the hash table tells us that we
-dont have to validate the chain again.
-
-Troubleshooting:
-----------------
-
-The validator tracks a maximum of MAX_LOCKDEP_KEYS number of lock classes.
-Exceeding this number will trigger the following lockdep warning:
-
-       (DEBUG_LOCKS_WARN_ON(id >= MAX_LOCKDEP_KEYS))
-
-By default, MAX_LOCKDEP_KEYS is currently set to 8191, and typical
-desktop systems have less than 1,000 lock classes, so this warning
-normally results from lock-class leakage or failure to properly
-initialize locks.  These two problems are illustrated below:
-
-1.     Repeated module loading and unloading while running the validator
-       will result in lock-class leakage.  The issue here is that each
-       load of the module will create a new set of lock classes for
-       that module's locks, but module unloading does not remove old
-       classes (see below discussion of reuse of lock classes for why).
-       Therefore, if that module is loaded and unloaded repeatedly,
-       the number of lock classes will eventually reach the maximum.
-
-2.     Using structures such as arrays that have large numbers of
-       locks that are not explicitly initialized.  For example,
-       a hash table with 8192 buckets where each bucket has its own
-       spinlock_t will consume 8192 lock classes -unless- each spinlock
-       is explicitly initialized at runtime, for example, using the
-       run-time spin_lock_init() as opposed to compile-time initializers
-       such as __SPIN_LOCK_UNLOCKED().  Failure to properly initialize
-       the per-bucket spinlocks would guarantee lock-class overflow.
-       In contrast, a loop that called spin_lock_init() on each lock
-       would place all 8192 locks into a single lock class.
-
-       The moral of this story is that you should always explicitly
-       initialize your locks.
-
-One might argue that the validator should be modified to allow
-lock classes to be reused.  However, if you are tempted to make this
-argument, first review the code and think through the changes that would
-be required, keeping in mind that the lock classes to be removed are
-likely to be linked into the lock-dependency graph.  This turns out to
-be harder to do than to say.
-
-Of course, if you do run out of lock classes, the next thing to do is
-to find the offending lock classes.  First, the following command gives
-you the number of lock classes currently in use along with the maximum:
-
-       grep "lock-classes" /proc/lockdep_stats
-
-This command produces the following output on a modest system:
-
-        lock-classes:                          748 [max: 8191]
-
-If the number allocated (748 above) increases continually over time,
-then there is likely a leak.  The following command can be used to
-identify the leaking lock classes:
-
-       grep "BD" /proc/lockdep
-
-Run the command and save the output, then compare against the output from
-a later run of this command to identify the leakers.  This same output
-can also help you find situations where runtime lock initialization has
-been omitted.
diff --git a/Documentation/locking/lockdep-design.txt b/Documentation/locking/lockdep-design.txt
new file mode 100644 (file)
index 0000000..5dbc99c
--- /dev/null
@@ -0,0 +1,286 @@
+Runtime locking correctness validator
+=====================================
+
+started by Ingo Molnar <mingo@redhat.com>
+additions by Arjan van de Ven <arjan@linux.intel.com>
+
+Lock-class
+----------
+
+The basic object the validator operates upon is a 'class' of locks.
+
+A class of locks is a group of locks that are logically the same with
+respect to locking rules, even if the locks may have multiple (possibly
+tens of thousands of) instantiations. For example a lock in the inode
+struct is one class, while each inode has its own instantiation of that
+lock class.
+
+The validator tracks the 'state' of lock-classes, and it tracks
+dependencies between different lock-classes. The validator maintains a
+rolling proof that the state and the dependencies are correct.
+
+Unlike an lock instantiation, the lock-class itself never goes away: when
+a lock-class is used for the first time after bootup it gets registered,
+and all subsequent uses of that lock-class will be attached to this
+lock-class.
+
+State
+-----
+
+The validator tracks lock-class usage history into 4n + 1 separate state bits:
+
+- 'ever held in STATE context'
+- 'ever held as readlock in STATE context'
+- 'ever held with STATE enabled'
+- 'ever held as readlock with STATE enabled'
+
+Where STATE can be either one of (kernel/lockdep_states.h)
+ - hardirq
+ - softirq
+ - reclaim_fs
+
+- 'ever used'                                       [ == !unused        ]
+
+When locking rules are violated, these state bits are presented in the
+locking error messages, inside curlies. A contrived example:
+
+   modprobe/2287 is trying to acquire lock:
+    (&sio_locks[i].lock){-.-...}, at: [<c02867fd>] mutex_lock+0x21/0x24
+
+   but task is already holding lock:
+    (&sio_locks[i].lock){-.-...}, at: [<c02867fd>] mutex_lock+0x21/0x24
+
+
+The bit position indicates STATE, STATE-read, for each of the states listed
+above, and the character displayed in each indicates:
+
+   '.'  acquired while irqs disabled and not in irq context
+   '-'  acquired in irq context
+   '+'  acquired with irqs enabled
+   '?'  acquired in irq context with irqs enabled.
+
+Unused mutexes cannot be part of the cause of an error.
+
+
+Single-lock state rules:
+------------------------
+
+A softirq-unsafe lock-class is automatically hardirq-unsafe as well. The
+following states are exclusive, and only one of them is allowed to be
+set for any lock-class:
+
+ <hardirq-safe> and <hardirq-unsafe>
+ <softirq-safe> and <softirq-unsafe>
+
+The validator detects and reports lock usage that violate these
+single-lock state rules.
+
+Multi-lock dependency rules:
+----------------------------
+
+The same lock-class must not be acquired twice, because this could lead
+to lock recursion deadlocks.
+
+Furthermore, two locks may not be taken in different order:
+
+ <L1> -> <L2>
+ <L2> -> <L1>
+
+because this could lead to lock inversion deadlocks. (The validator
+finds such dependencies in arbitrary complexity, i.e. there can be any
+other locking sequence between the acquire-lock operations, the
+validator will still track all dependencies between locks.)
+
+Furthermore, the following usage based lock dependencies are not allowed
+between any two lock-classes:
+
+   <hardirq-safe>   ->  <hardirq-unsafe>
+   <softirq-safe>   ->  <softirq-unsafe>
+
+The first rule comes from the fact the a hardirq-safe lock could be
+taken by a hardirq context, interrupting a hardirq-unsafe lock - and
+thus could result in a lock inversion deadlock. Likewise, a softirq-safe
+lock could be taken by an softirq context, interrupting a softirq-unsafe
+lock.
+
+The above rules are enforced for any locking sequence that occurs in the
+kernel: when acquiring a new lock, the validator checks whether there is
+any rule violation between the new lock and any of the held locks.
+
+When a lock-class changes its state, the following aspects of the above
+dependency rules are enforced:
+
+- if a new hardirq-safe lock is discovered, we check whether it
+  took any hardirq-unsafe lock in the past.
+
+- if a new softirq-safe lock is discovered, we check whether it took
+  any softirq-unsafe lock in the past.
+
+- if a new hardirq-unsafe lock is discovered, we check whether any
+  hardirq-safe lock took it in the past.
+
+- if a new softirq-unsafe lock is discovered, we check whether any
+  softirq-safe lock took it in the past.
+
+(Again, we do these checks too on the basis that an interrupt context
+could interrupt _any_ of the irq-unsafe or hardirq-unsafe locks, which
+could lead to a lock inversion deadlock - even if that lock scenario did
+not trigger in practice yet.)
+
+Exception: Nested data dependencies leading to nested locking
+-------------------------------------------------------------
+
+There are a few cases where the Linux kernel acquires more than one
+instance of the same lock-class. Such cases typically happen when there
+is some sort of hierarchy within objects of the same type. In these
+cases there is an inherent "natural" ordering between the two objects
+(defined by the properties of the hierarchy), and the kernel grabs the
+locks in this fixed order on each of the objects.
+
+An example of such an object hierarchy that results in "nested locking"
+is that of a "whole disk" block-dev object and a "partition" block-dev
+object; the partition is "part of" the whole device and as long as one
+always takes the whole disk lock as a higher lock than the partition
+lock, the lock ordering is fully correct. The validator does not
+automatically detect this natural ordering, as the locking rule behind
+the ordering is not static.
+
+In order to teach the validator about this correct usage model, new
+versions of the various locking primitives were added that allow you to
+specify a "nesting level". An example call, for the block device mutex,
+looks like this:
+
+enum bdev_bd_mutex_lock_class
+{
+       BD_MUTEX_NORMAL,
+       BD_MUTEX_WHOLE,
+       BD_MUTEX_PARTITION
+};
+
+ mutex_lock_nested(&bdev->bd_contains->bd_mutex, BD_MUTEX_PARTITION);
+
+In this case the locking is done on a bdev object that is known to be a
+partition.
+
+The validator treats a lock that is taken in such a nested fashion as a
+separate (sub)class for the purposes of validation.
+
+Note: When changing code to use the _nested() primitives, be careful and
+check really thoroughly that the hierarchy is correctly mapped; otherwise
+you can get false positives or false negatives.
+
+Proof of 100% correctness:
+--------------------------
+
+The validator achieves perfect, mathematical 'closure' (proof of locking
+correctness) in the sense that for every simple, standalone single-task
+locking sequence that occurred at least once during the lifetime of the
+kernel, the validator proves it with a 100% certainty that no
+combination and timing of these locking sequences can cause any class of
+lock related deadlock. [*]
+
+I.e. complex multi-CPU and multi-task locking scenarios do not have to
+occur in practice to prove a deadlock: only the simple 'component'
+locking chains have to occur at least once (anytime, in any
+task/context) for the validator to be able to prove correctness. (For
+example, complex deadlocks that would normally need more than 3 CPUs and
+a very unlikely constellation of tasks, irq-contexts and timings to
+occur, can be detected on a plain, lightly loaded single-CPU system as
+well!)
+
+This radically decreases the complexity of locking related QA of the
+kernel: what has to be done during QA is to trigger as many "simple"
+single-task locking dependencies in the kernel as possible, at least
+once, to prove locking correctness - instead of having to trigger every
+possible combination of locking interaction between CPUs, combined with
+every possible hardirq and softirq nesting scenario (which is impossible
+to do in practice).
+
+[*] assuming that the validator itself is 100% correct, and no other
+    part of the system corrupts the state of the validator in any way.
+    We also assume that all NMI/SMM paths [which could interrupt
+    even hardirq-disabled codepaths] are correct and do not interfere
+    with the validator. We also assume that the 64-bit 'chain hash'
+    value is unique for every lock-chain in the system. Also, lock
+    recursion must not be higher than 20.
+
+Performance:
+------------
+
+The above rules require _massive_ amounts of runtime checking. If we did
+that for every lock taken and for every irqs-enable event, it would
+render the system practically unusably slow. The complexity of checking
+is O(N^2), so even with just a few hundred lock-classes we'd have to do
+tens of thousands of checks for every event.
+
+This problem is solved by checking any given 'locking scenario' (unique
+sequence of locks taken after each other) only once. A simple stack of
+held locks is maintained, and a lightweight 64-bit hash value is
+calculated, which hash is unique for every lock chain. The hash value,
+when the chain is validated for the first time, is then put into a hash
+table, which hash-table can be checked in a lockfree manner. If the
+locking chain occurs again later on, the hash table tells us that we
+dont have to validate the chain again.
+
+Troubleshooting:
+----------------
+
+The validator tracks a maximum of MAX_LOCKDEP_KEYS number of lock classes.
+Exceeding this number will trigger the following lockdep warning:
+
+       (DEBUG_LOCKS_WARN_ON(id >= MAX_LOCKDEP_KEYS))
+
+By default, MAX_LOCKDEP_KEYS is currently set to 8191, and typical
+desktop systems have less than 1,000 lock classes, so this warning
+normally results from lock-class leakage or failure to properly
+initialize locks.  These two problems are illustrated below:
+
+1.     Repeated module loading and unloading while running the validator
+       will result in lock-class leakage.  The issue here is that each
+       load of the module will create a new set of lock classes for
+       that module's locks, but module unloading does not remove old
+       classes (see below discussion of reuse of lock classes for why).
+       Therefore, if that module is loaded and unloaded repeatedly,
+       the number of lock classes will eventually reach the maximum.
+
+2.     Using structures such as arrays that have large numbers of
+       locks that are not explicitly initialized.  For example,
+       a hash table with 8192 buckets where each bucket has its own
+       spinlock_t will consume 8192 lock classes -unless- each spinlock
+       is explicitly initialized at runtime, for example, using the
+       run-time spin_lock_init() as opposed to compile-time initializers
+       such as __SPIN_LOCK_UNLOCKED().  Failure to properly initialize
+       the per-bucket spinlocks would guarantee lock-class overflow.
+       In contrast, a loop that called spin_lock_init() on each lock
+       would place all 8192 locks into a single lock class.
+
+       The moral of this story is that you should always explicitly
+       initialize your locks.
+
+One might argue that the validator should be modified to allow
+lock classes to be reused.  However, if you are tempted to make this
+argument, first review the code and think through the changes that would
+be required, keeping in mind that the lock classes to be removed are
+likely to be linked into the lock-dependency graph.  This turns out to
+be harder to do than to say.
+
+Of course, if you do run out of lock classes, the next thing to do is
+to find the offending lock classes.  First, the following command gives
+you the number of lock classes currently in use along with the maximum:
+
+       grep "lock-classes" /proc/lockdep_stats
+
+This command produces the following output on a modest system:
+
+        lock-classes:                          748 [max: 8191]
+
+If the number allocated (748 above) increases continually over time,
+then there is likely a leak.  The following command can be used to
+identify the leaking lock classes:
+
+       grep "BD" /proc/lockdep
+
+Run the command and save the output, then compare against the output from
+a later run of this command to identify the leakers.  This same output
+can also help you find situations where runtime lock initialization has
+been omitted.
diff --git a/Documentation/locking/lockstat.txt b/Documentation/locking/lockstat.txt
new file mode 100644 (file)
index 0000000..7428773
--- /dev/null
@@ -0,0 +1,178 @@
+
+LOCK STATISTICS
+
+- WHAT
+
+As the name suggests, it provides statistics on locks.
+
+- WHY
+
+Because things like lock contention can severely impact performance.
+
+- HOW
+
+Lockdep already has hooks in the lock functions and maps lock instances to
+lock classes. We build on that (see Documentation/lokcing/lockdep-design.txt).
+The graph below shows the relation between the lock functions and the various
+hooks therein.
+
+        __acquire
+            |
+           lock _____
+            |        \
+            |    __contended
+            |         |
+            |       <wait>
+            | _______/
+            |/
+            |
+       __acquired
+            |
+            .
+          <hold>
+            .
+            |
+       __release
+            |
+         unlock
+
+lock, unlock   - the regular lock functions
+__*            - the hooks
+<>             - states
+
+With these hooks we provide the following statistics:
+
+ con-bounces       - number of lock contention that involved x-cpu data
+ contentions       - number of lock acquisitions that had to wait
+ wait time min     - shortest (non-0) time we ever had to wait for a lock
+           max     - longest time we ever had to wait for a lock
+          total   - total time we spend waiting on this lock
+          avg     - average time spent waiting on this lock
+ acq-bounces       - number of lock acquisitions that involved x-cpu data
+ acquisitions      - number of times we took the lock
+ hold time min     - shortest (non-0) time we ever held the lock
+          max     - longest time we ever held the lock
+          total   - total time this lock was held
+          avg     - average time this lock was held
+
+These numbers are gathered per lock class, per read/write state (when
+applicable).
+
+It also tracks 4 contention points per class. A contention point is a call site
+that had to wait on lock acquisition.
+
+ - CONFIGURATION
+
+Lock statistics are enabled via CONFIG_LOCK_STAT.
+
+ - USAGE
+
+Enable collection of statistics:
+
+# echo 1 >/proc/sys/kernel/lock_stat
+
+Disable collection of statistics:
+
+# echo 0 >/proc/sys/kernel/lock_stat
+
+Look at the current lock statistics:
+
+( line numbers not part of actual output, done for clarity in the explanation
+  below )
+
+# less /proc/lock_stat
+
+01 lock_stat version 0.4
+02-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+03                              class name    con-bounces    contentions   waittime-min   waittime-max waittime-total   waittime-avg    acq-bounces   acquisitions   holdtime-min   holdtime-max holdtime-total   holdtime-avg
+04-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+05
+06                         &mm->mmap_sem-W:            46             84           0.26         939.10       16371.53         194.90          47291        2922365           0.16     2220301.69 17464026916.32        5975.99
+07                         &mm->mmap_sem-R:            37            100           1.31      299502.61      325629.52        3256.30         212344       34316685           0.10        7744.91    95016910.20           2.77
+08                         ---------------
+09                           &mm->mmap_sem              1          [<ffffffff811502a7>] khugepaged_scan_mm_slot+0x57/0x280
+19                           &mm->mmap_sem             96          [<ffffffff815351c4>] __do_page_fault+0x1d4/0x510
+11                           &mm->mmap_sem             34          [<ffffffff81113d77>] vm_mmap_pgoff+0x87/0xd0
+12                           &mm->mmap_sem             17          [<ffffffff81127e71>] vm_munmap+0x41/0x80
+13                         ---------------
+14                           &mm->mmap_sem              1          [<ffffffff81046fda>] dup_mmap+0x2a/0x3f0
+15                           &mm->mmap_sem             60          [<ffffffff81129e29>] SyS_mprotect+0xe9/0x250
+16                           &mm->mmap_sem             41          [<ffffffff815351c4>] __do_page_fault+0x1d4/0x510
+17                           &mm->mmap_sem             68          [<ffffffff81113d77>] vm_mmap_pgoff+0x87/0xd0
+18
+19.............................................................................................................................................................................................................................
+20
+21                         unix_table_lock:           110            112           0.21          49.24         163.91           1.46          21094          66312           0.12         624.42       31589.81           0.48
+22                         ---------------
+23                         unix_table_lock             45          [<ffffffff8150ad8e>] unix_create1+0x16e/0x1b0
+24                         unix_table_lock             47          [<ffffffff8150b111>] unix_release_sock+0x31/0x250
+25                         unix_table_lock             15          [<ffffffff8150ca37>] unix_find_other+0x117/0x230
+26                         unix_table_lock              5          [<ffffffff8150a09f>] unix_autobind+0x11f/0x1b0
+27                         ---------------
+28                         unix_table_lock             39          [<ffffffff8150b111>] unix_release_sock+0x31/0x250
+29                         unix_table_lock             49          [<ffffffff8150ad8e>] unix_create1+0x16e/0x1b0
+30                         unix_table_lock             20          [<ffffffff8150ca37>] unix_find_other+0x117/0x230
+31                         unix_table_lock              4          [<ffffffff8150a09f>] unix_autobind+0x11f/0x1b0
+
+
+This excerpt shows the first two lock class statistics. Line 01 shows the
+output version - each time the format changes this will be updated. Line 02-04
+show the header with column descriptions. Lines 05-18 and 20-31 show the actual
+statistics. These statistics come in two parts; the actual stats separated by a
+short separator (line 08, 13) from the contention points.
+
+The first lock (05-18) is a read/write lock, and shows two lines above the
+short separator. The contention points don't match the column descriptors,
+they have two: contentions and [<IP>] symbol. The second set of contention
+points are the points we're contending with.
+
+The integer part of the time values is in us.
+
+Dealing with nested locks, subclasses may appear:
+
+32...........................................................................................................................................................................................................................
+33
+34                               &rq->lock:       13128          13128           0.43         190.53      103881.26           7.91          97454        3453404           0.00         401.11    13224683.11           3.82
+35                               ---------
+36                               &rq->lock          645          [<ffffffff8103bfc4>] task_rq_lock+0x43/0x75
+37                               &rq->lock          297          [<ffffffff8104ba65>] try_to_wake_up+0x127/0x25a
+38                               &rq->lock          360          [<ffffffff8103c4c5>] select_task_rq_fair+0x1f0/0x74a
+39                               &rq->lock          428          [<ffffffff81045f98>] scheduler_tick+0x46/0x1fb
+40                               ---------
+41                               &rq->lock           77          [<ffffffff8103bfc4>] task_rq_lock+0x43/0x75
+42                               &rq->lock          174          [<ffffffff8104ba65>] try_to_wake_up+0x127/0x25a
+43                               &rq->lock         4715          [<ffffffff8103ed4b>] double_rq_lock+0x42/0x54
+44                               &rq->lock          893          [<ffffffff81340524>] schedule+0x157/0x7b8
+45
+46...........................................................................................................................................................................................................................
+47
+48                             &rq->lock/1:        1526          11488           0.33         388.73      136294.31          11.86          21461          38404           0.00          37.93      109388.53           2.84
+49                             -----------
+50                             &rq->lock/1        11526          [<ffffffff8103ed58>] double_rq_lock+0x4f/0x54
+51                             -----------
+52                             &rq->lock/1         5645          [<ffffffff8103ed4b>] double_rq_lock+0x42/0x54
+53                             &rq->lock/1         1224          [<ffffffff81340524>] schedule+0x157/0x7b8
+54                             &rq->lock/1         4336          [<ffffffff8103ed58>] double_rq_lock+0x4f/0x54
+55                             &rq->lock/1          181          [<ffffffff8104ba65>] try_to_wake_up+0x127/0x25a
+
+Line 48 shows statistics for the second subclass (/1) of &rq->lock class
+(subclass starts from 0), since in this case, as line 50 suggests,
+double_rq_lock actually acquires a nested lock of two spinlocks.
+
+View the top contending locks:
+
+# grep : /proc/lock_stat | head
+                       clockevents_lock:       2926159        2947636           0.15       46882.81  1784540466.34         605.41        3381345        3879161           0.00        2260.97    53178395.68          13.71
+                    tick_broadcast_lock:        346460         346717           0.18        2257.43    39364622.71         113.54        3642919        4242696           0.00        2263.79    49173646.60          11.59
+                 &mapping->i_mmap_mutex:        203896         203899           3.36      645530.05 31767507988.39      155800.21        3361776        8893984           0.17        2254.15    14110121.02           1.59
+                              &rq->lock:        135014         136909           0.18         606.09      842160.68           6.15        1540728       10436146           0.00         728.72    17606683.41           1.69
+              &(&zone->lru_lock)->rlock:         93000          94934           0.16          59.18      188253.78           1.98        1199912        3809894           0.15         391.40     3559518.81           0.93
+                        tasklist_lock-W:         40667          41130           0.23        1189.42      428980.51          10.43         270278         510106           0.16         653.51     3939674.91           7.72
+                        tasklist_lock-R:         21298          21305           0.20        1310.05      215511.12          10.12         186204         241258           0.14        1162.33     1179779.23           4.89
+                             rcu_node_1:         47656          49022           0.16         635.41      193616.41           3.95         844888        1865423           0.00         764.26     1656226.96           0.89
+       &(&dentry->d_lockref.lock)->rlock:         39791          40179           0.15        1302.08       88851.96           2.21        2790851       12527025           0.10        1910.75     3379714.27           0.27
+                             rcu_node_0:         29203          30064           0.16         786.55     1555573.00          51.74          88963         244254           0.00         398.87      428872.51           1.76
+
+Clear the statistics:
+
+# echo 0 > /proc/lock_stat
diff --git a/Documentation/locking/locktorture.txt b/Documentation/locking/locktorture.txt
new file mode 100644 (file)
index 0000000..619f2bb
--- /dev/null
@@ -0,0 +1,147 @@
+Kernel Lock Torture Test Operation
+
+CONFIG_LOCK_TORTURE_TEST
+
+The CONFIG LOCK_TORTURE_TEST config option provides a kernel module
+that runs torture tests on core kernel locking primitives. The kernel
+module, 'locktorture', may be built after the fact on the running
+kernel to be tested, if desired. The tests periodically output status
+messages via printk(), which can be examined via the dmesg (perhaps
+grepping for "torture").  The test is started when the module is loaded,
+and stops when the module is unloaded. This program is based on how RCU
+is tortured, via rcutorture.
+
+This torture test consists of creating a number of kernel threads which
+acquire the lock and hold it for specific amount of time, thus simulating
+different critical region behaviors. The amount of contention on the lock
+can be simulated by either enlarging this critical region hold time and/or
+creating more kthreads.
+
+
+MODULE PARAMETERS
+
+This module has the following parameters:
+
+
+           ** Locktorture-specific **
+
+nwriters_stress   Number of kernel threads that will stress exclusive lock
+                 ownership (writers). The default value is twice the number
+                 of online CPUs.
+
+nreaders_stress   Number of kernel threads that will stress shared lock
+                 ownership (readers). The default is the same amount of writer
+                 locks. If the user did not specify nwriters_stress, then
+                 both readers and writers be the amount of online CPUs.
+
+torture_type     Type of lock to torture. By default, only spinlocks will
+                 be tortured. This module can torture the following locks,
+                 with string values as follows:
+
+                    o "lock_busted": Simulates a buggy lock implementation.
+
+                    o "spin_lock": spin_lock() and spin_unlock() pairs.
+
+                    o "spin_lock_irq": spin_lock_irq() and spin_unlock_irq()
+                                       pairs.
+
+                    o "rw_lock": read/write lock() and unlock() rwlock pairs.
+
+                    o "rw_lock_irq": read/write lock_irq() and unlock_irq()
+                                     rwlock pairs.
+
+                    o "mutex_lock": mutex_lock() and mutex_unlock() pairs.
+
+                    o "rwsem_lock": read/write down() and up() semaphore pairs.
+
+torture_runnable  Start locktorture at boot time in the case where the
+                 module is built into the kernel, otherwise wait for
+                 torture_runnable to be set via sysfs before starting.
+                 By default it will begin once the module is loaded.
+
+
+           ** Torture-framework (RCU + locking) **
+
+shutdown_secs    The number of seconds to run the test before terminating
+                 the test and powering off the system.  The default is
+                 zero, which disables test termination and system shutdown.
+                 This capability is useful for automated testing.
+
+onoff_interval   The number of seconds between each attempt to execute a
+                 randomly selected CPU-hotplug operation.  Defaults
+                 to zero, which disables CPU hotplugging.  In
+                 CONFIG_HOTPLUG_CPU=n kernels, locktorture will silently
+                 refuse to do any CPU-hotplug operations regardless of
+                 what value is specified for onoff_interval.
+
+onoff_holdoff    The number of seconds to wait until starting CPU-hotplug
+                 operations.  This would normally only be used when
+                 locktorture was built into the kernel and started
+                 automatically at boot time, in which case it is useful
+                 in order to avoid confusing boot-time code with CPUs
+                 coming and going. This parameter is only useful if
+                 CONFIG_HOTPLUG_CPU is enabled.
+
+stat_interval    Number of seconds between statistics-related printk()s.
+                 By default, locktorture will report stats every 60 seconds.
+                 Setting the interval to zero causes the statistics to
+                 be printed -only- when the module is unloaded, and this
+                 is the default.
+
+stutter                  The length of time to run the test before pausing for this
+                 same period of time.  Defaults to "stutter=5", so as
+                 to run and pause for (roughly) five-second intervals.
+                 Specifying "stutter=0" causes the test to run continuously
+                 without pausing, which is the old default behavior.
+
+shuffle_interval  The number of seconds to keep the test threads affinitied
+                 to a particular subset of the CPUs, defaults to 3 seconds.
+                 Used in conjunction with test_no_idle_hz.
+
+verbose                  Enable verbose debugging printing, via printk(). Enabled
+                 by default. This extra information is mostly related to
+                 high-level errors and reports from the main 'torture'
+                 framework.
+
+
+STATISTICS
+
+Statistics are printed in the following format:
+
+spin_lock-torture: Writes:  Total: 93746064  Max/Min: 0/0   Fail: 0
+   (A)             (B)            (C)            (D)          (E)
+
+(A): Lock type that is being tortured -- torture_type parameter.
+
+(B): Number of writer lock acquisitions. If dealing with a read/write primitive
+     a second "Reads" statistics line is printed.
+
+(C): Number of times the lock was acquired.
+
+(D): Min and max number of times threads failed to acquire the lock.
+
+(E): true/false values if there were errors acquiring the lock. This should
+     -only- be positive if there is a bug in the locking primitive's
+     implementation. Otherwise a lock should never fail (i.e., spin_lock()).
+     Of course, the same applies for (C), above. A dummy example of this is
+     the "lock_busted" type.
+
+USAGE
+
+The following script may be used to torture locks:
+
+       #!/bin/sh
+
+       modprobe locktorture
+       sleep 3600
+       rmmod locktorture
+       dmesg | grep torture:
+
+The output can be manually inspected for the error flag of "!!!".
+One could of course create a more elaborate script that automatically
+checked for such errors.  The "rmmod" command forces a "SUCCESS",
+"FAILURE", or "RCU_HOTPLUG" indication to be printk()ed.  The first
+two are self-explanatory, while the last indicates that while there
+were no locking failures, CPU-hotplug problems were detected.
+
+Also see: Documentation/RCU/torture.txt
diff --git a/Documentation/locking/mutex-design.txt b/Documentation/locking/mutex-design.txt
new file mode 100644 (file)
index 0000000..60c482d
--- /dev/null
@@ -0,0 +1,157 @@
+Generic Mutex Subsystem
+
+started by Ingo Molnar <mingo@redhat.com>
+updated by Davidlohr Bueso <davidlohr@hp.com>
+
+What are mutexes?
+-----------------
+
+In the Linux kernel, mutexes refer to a particular locking primitive
+that enforces serialization on shared memory systems, and not only to
+the generic term referring to 'mutual exclusion' found in academia
+or similar theoretical text books. Mutexes are sleeping locks which
+behave similarly to binary semaphores, and were introduced in 2006[1]
+as an alternative to these. This new data structure provided a number
+of advantages, including simpler interfaces, and at that time smaller
+code (see Disadvantages).
+
+[1] http://lwn.net/Articles/164802/
+
+Implementation
+--------------
+
+Mutexes are represented by 'struct mutex', defined in include/linux/mutex.h
+and implemented in kernel/locking/mutex.c. These locks use a three
+state atomic counter (->count) to represent the different possible
+transitions that can occur during the lifetime of a lock:
+
+         1: unlocked
+         0: locked, no waiters
+   negative: locked, with potential waiters
+
+In its most basic form it also includes a wait-queue and a spinlock
+that serializes access to it. CONFIG_SMP systems can also include
+a pointer to the lock task owner (->owner) as well as a spinner MCS
+lock (->osq), both described below in (ii).
+
+When acquiring a mutex, there are three possible paths that can be
+taken, depending on the state of the lock:
+
+(i) fastpath: tries to atomically acquire the lock by decrementing the
+    counter. If it was already taken by another task it goes to the next
+    possible path. This logic is architecture specific. On x86-64, the
+    locking fastpath is 2 instructions:
+
+    0000000000000e10 <mutex_lock>:
+    e21:   f0 ff 0b                lock decl (%rbx)
+    e24:   79 08                   jns    e2e <mutex_lock+0x1e>
+
+   the unlocking fastpath is equally tight:
+
+    0000000000000bc0 <mutex_unlock>:
+    bc8:   f0 ff 07                lock incl (%rdi)
+    bcb:   7f 0a                   jg     bd7 <mutex_unlock+0x17>
+
+
+(ii) midpath: aka optimistic spinning, tries to spin for acquisition
+     while the lock owner is running and there are no other tasks ready
+     to run that have higher priority (need_resched). The rationale is
+     that if the lock owner is running, it is likely to release the lock
+     soon. The mutex spinners are queued up using MCS lock so that only
+     one spinner can compete for the mutex.
+
+     The MCS lock (proposed by Mellor-Crummey and Scott) is a simple spinlock
+     with the desirable properties of being fair and with each cpu trying
+     to acquire the lock spinning on a local variable. It avoids expensive
+     cacheline bouncing that common test-and-set spinlock implementations
+     incur. An MCS-like lock is specially tailored for optimistic spinning
+     for sleeping lock implementation. An important feature of the customized
+     MCS lock is that it has the extra property that spinners are able to exit
+     the MCS spinlock queue when they need to reschedule. This further helps
+     avoid situations where MCS spinners that need to reschedule would continue
+     waiting to spin on mutex owner, only to go directly to slowpath upon
+     obtaining the MCS lock.
+
+
+(iii) slowpath: last resort, if the lock is still unable to be acquired,
+      the task is added to the wait-queue and sleeps until woken up by the
+      unlock path. Under normal circumstances it blocks as TASK_UNINTERRUPTIBLE.
+
+While formally kernel mutexes are sleepable locks, it is path (ii) that
+makes them more practically a hybrid type. By simply not interrupting a
+task and busy-waiting for a few cycles instead of immediately sleeping,
+the performance of this lock has been seen to significantly improve a
+number of workloads. Note that this technique is also used for rw-semaphores.
+
+Semantics
+---------
+
+The mutex subsystem checks and enforces the following rules:
+
+    - Only one task can hold the mutex at a time.
+    - Only the owner can unlock the mutex.
+    - Multiple unlocks are not permitted.
+    - Recursive locking/unlocking is not permitted.
+    - A mutex must only be initialized via the API (see below).
+    - A task may not exit with a mutex held.
+    - Memory areas where held locks reside must not be freed.
+    - Held mutexes must not be reinitialized.
+    - Mutexes may not be used in hardware or software interrupt
+      contexts such as tasklets and timers.
+
+These semantics are fully enforced when CONFIG DEBUG_MUTEXES is enabled.
+In addition, the mutex debugging code also implements a number of other
+features that make lock debugging easier and faster:
+
+    - Uses symbolic names of mutexes, whenever they are printed
+      in debug output.
+    - Point-of-acquire tracking, symbolic lookup of function names,
+      list of all locks held in the system, printout of them.
+    - Owner tracking.
+    - Detects self-recursing locks and prints out all relevant info.
+    - Detects multi-task circular deadlocks and prints out all affected
+      locks and tasks (and only those tasks).
+
+
+Interfaces
+----------
+Statically define the mutex:
+   DEFINE_MUTEX(name);
+
+Dynamically initialize the mutex:
+   mutex_init(mutex);
+
+Acquire the mutex, uninterruptible:
+   void mutex_lock(struct mutex *lock);
+   void mutex_lock_nested(struct mutex *lock, unsigned int subclass);
+   int  mutex_trylock(struct mutex *lock);
+
+Acquire the mutex, interruptible:
+   int mutex_lock_interruptible_nested(struct mutex *lock,
+                                      unsigned int subclass);
+   int mutex_lock_interruptible(struct mutex *lock);
+
+Acquire the mutex, interruptible, if dec to 0:
+   int atomic_dec_and_mutex_lock(atomic_t *cnt, struct mutex *lock);
+
+Unlock the mutex:
+   void mutex_unlock(struct mutex *lock);
+
+Test if the mutex is taken:
+   int mutex_is_locked(struct mutex *lock);
+
+Disadvantages
+-------------
+
+Unlike its original design and purpose, 'struct mutex' is larger than
+most locks in the kernel. E.g: on x86-64 it is 40 bytes, almost twice
+as large as 'struct semaphore' (24 bytes) and tied, along with rwsems,
+for the largest lock in the kernel. Larger structure sizes mean more
+CPU cache and memory footprint.
+
+When to use mutexes
+-------------------
+
+Unless the strict semantics of mutexes are unsuitable and/or the critical
+region prevents the lock from being shared, always prefer them to any other
+locking primitive.
diff --git a/Documentation/locking/rt-mutex-design.txt b/Documentation/locking/rt-mutex-design.txt
new file mode 100644 (file)
index 0000000..8666070
--- /dev/null
@@ -0,0 +1,781 @@
+#
+# Copyright (c) 2006 Steven Rostedt
+# Licensed under the GNU Free Documentation License, Version 1.2
+#
+
+RT-mutex implementation design
+------------------------------
+
+This document tries to describe the design of the rtmutex.c implementation.
+It doesn't describe the reasons why rtmutex.c exists. For that please see
+Documentation/rt-mutex.txt.  Although this document does explain problems
+that happen without this code, but that is in the concept to understand
+what the code actually is doing.
+
+The goal of this document is to help others understand the priority
+inheritance (PI) algorithm that is used, as well as reasons for the
+decisions that were made to implement PI in the manner that was done.
+
+
+Unbounded Priority Inversion
+----------------------------
+
+Priority inversion is when a lower priority process executes while a higher
+priority process wants to run.  This happens for several reasons, and
+most of the time it can't be helped.  Anytime a high priority process wants
+to use a resource that a lower priority process has (a mutex for example),
+the high priority process must wait until the lower priority process is done
+with the resource.  This is a priority inversion.  What we want to prevent
+is something called unbounded priority inversion.  That is when the high
+priority process is prevented from running by a lower priority process for
+an undetermined amount of time.
+
+The classic example of unbounded priority inversion is where you have three
+processes, let's call them processes A, B, and C, where A is the highest
+priority process, C is the lowest, and B is in between. A tries to grab a lock
+that C owns and must wait and lets C run to release the lock. But in the
+meantime, B executes, and since B is of a higher priority than C, it preempts C,
+but by doing so, it is in fact preempting A which is a higher priority process.
+Now there's no way of knowing how long A will be sleeping waiting for C
+to release the lock, because for all we know, B is a CPU hog and will
+never give C a chance to release the lock.  This is called unbounded priority
+inversion.
+
+Here's a little ASCII art to show the problem.
+
+   grab lock L1 (owned by C)
+     |
+A ---+
+        C preempted by B
+          |
+C    +----+
+
+B         +-------->
+                B now keeps A from running.
+
+
+Priority Inheritance (PI)
+-------------------------
+
+There are several ways to solve this issue, but other ways are out of scope
+for this document.  Here we only discuss PI.
+
+PI is where a process inherits the priority of another process if the other
+process blocks on a lock owned by the current process.  To make this easier
+to understand, let's use the previous example, with processes A, B, and C again.
+
+This time, when A blocks on the lock owned by C, C would inherit the priority
+of A.  So now if B becomes runnable, it would not preempt C, since C now has
+the high priority of A.  As soon as C releases the lock, it loses its
+inherited priority, and A then can continue with the resource that C had.
+
+Terminology
+-----------
+
+Here I explain some terminology that is used in this document to help describe
+the design that is used to implement PI.
+
+PI chain - The PI chain is an ordered series of locks and processes that cause
+           processes to inherit priorities from a previous process that is
+           blocked on one of its locks.  This is described in more detail
+           later in this document.
+
+mutex    - In this document, to differentiate from locks that implement
+           PI and spin locks that are used in the PI code, from now on
+           the PI locks will be called a mutex.
+
+lock     - In this document from now on, I will use the term lock when
+           referring to spin locks that are used to protect parts of the PI
+           algorithm.  These locks disable preemption for UP (when
+           CONFIG_PREEMPT is enabled) and on SMP prevents multiple CPUs from
+           entering critical sections simultaneously.
+
+spin lock - Same as lock above.
+
+waiter   - A waiter is a struct that is stored on the stack of a blocked
+           process.  Since the scope of the waiter is within the code for
+           a process being blocked on the mutex, it is fine to allocate
+           the waiter on the process's stack (local variable).  This
+           structure holds a pointer to the task, as well as the mutex that
+           the task is blocked on.  It also has the plist node structures to
+           place the task in the waiter_list of a mutex as well as the
+           pi_list of a mutex owner task (described below).
+
+           waiter is sometimes used in reference to the task that is waiting
+           on a mutex. This is the same as waiter->task.
+
+waiters  - A list of processes that are blocked on a mutex.
+
+top waiter - The highest priority process waiting on a specific mutex.
+
+top pi waiter - The highest priority process waiting on one of the mutexes
+                that a specific process owns.
+
+Note:  task and process are used interchangeably in this document, mostly to
+       differentiate between two processes that are being described together.
+
+
+PI chain
+--------
+
+The PI chain is a list of processes and mutexes that may cause priority
+inheritance to take place.  Multiple chains may converge, but a chain
+would never diverge, since a process can't be blocked on more than one
+mutex at a time.
+
+Example:
+
+   Process:  A, B, C, D, E
+   Mutexes:  L1, L2, L3, L4
+
+   A owns: L1
+           B blocked on L1
+           B owns L2
+                  C blocked on L2
+                  C owns L3
+                         D blocked on L3
+                         D owns L4
+                                E blocked on L4
+
+The chain would be:
+
+   E->L4->D->L3->C->L2->B->L1->A
+
+To show where two chains merge, we could add another process F and
+another mutex L5 where B owns L5 and F is blocked on mutex L5.
+
+The chain for F would be:
+
+   F->L5->B->L1->A
+
+Since a process may own more than one mutex, but never be blocked on more than
+one, the chains merge.
+
+Here we show both chains:
+
+   E->L4->D->L3->C->L2-+
+                       |
+                       +->B->L1->A
+                       |
+                 F->L5-+
+
+For PI to work, the processes at the right end of these chains (or we may
+also call it the Top of the chain) must be equal to or higher in priority
+than the processes to the left or below in the chain.
+
+Also since a mutex may have more than one process blocked on it, we can
+have multiple chains merge at mutexes.  If we add another process G that is
+blocked on mutex L2:
+
+  G->L2->B->L1->A
+
+And once again, to show how this can grow I will show the merging chains
+again.
+
+   E->L4->D->L3->C-+
+                   +->L2-+
+                   |     |
+                 G-+     +->B->L1->A
+                         |
+                   F->L5-+
+
+
+Plist
+-----
+
+Before I go further and talk about how the PI chain is stored through lists
+on both mutexes and processes, I'll explain the plist.  This is similar to
+the struct list_head functionality that is already in the kernel.
+The implementation of plist is out of scope for this document, but it is
+very important to understand what it does.
+
+There are a few differences between plist and list, the most important one
+being that plist is a priority sorted linked list.  This means that the
+priorities of the plist are sorted, such that it takes O(1) to retrieve the
+highest priority item in the list.  Obviously this is useful to store processes
+based on their priorities.
+
+Another difference, which is important for implementation, is that, unlike
+list, the head of the list is a different element than the nodes of a list.
+So the head of the list is declared as struct plist_head and nodes that will
+be added to the list are declared as struct plist_node.
+
+
+Mutex Waiter List
+-----------------
+
+Every mutex keeps track of all the waiters that are blocked on itself. The mutex
+has a plist to store these waiters by priority.  This list is protected by
+a spin lock that is located in the struct of the mutex. This lock is called
+wait_lock.  Since the modification of the waiter list is never done in
+interrupt context, the wait_lock can be taken without disabling interrupts.
+
+
+Task PI List
+------------
+
+To keep track of the PI chains, each process has its own PI list.  This is
+a list of all top waiters of the mutexes that are owned by the process.
+Note that this list only holds the top waiters and not all waiters that are
+blocked on mutexes owned by the process.
+
+The top of the task's PI list is always the highest priority task that
+is waiting on a mutex that is owned by the task.  So if the task has
+inherited a priority, it will always be the priority of the task that is
+at the top of this list.
+
+This list is stored in the task structure of a process as a plist called
+pi_list.  This list is protected by a spin lock also in the task structure,
+called pi_lock.  This lock may also be taken in interrupt context, so when
+locking the pi_lock, interrupts must be disabled.
+
+
+Depth of the PI Chain
+---------------------
+
+The maximum depth of the PI chain is not dynamic, and could actually be
+defined.  But is very complex to figure it out, since it depends on all
+the nesting of mutexes.  Let's look at the example where we have 3 mutexes,
+L1, L2, and L3, and four separate functions func1, func2, func3 and func4.
+The following shows a locking order of L1->L2->L3, but may not actually
+be directly nested that way.
+
+void func1(void)
+{
+       mutex_lock(L1);
+
+       /* do anything */
+
+       mutex_unlock(L1);
+}
+
+void func2(void)
+{
+       mutex_lock(L1);
+       mutex_lock(L2);
+
+       /* do something */
+
+       mutex_unlock(L2);
+       mutex_unlock(L1);
+}
+
+void func3(void)
+{
+       mutex_lock(L2);
+       mutex_lock(L3);
+
+       /* do something else */
+
+       mutex_unlock(L3);
+       mutex_unlock(L2);
+}
+
+void func4(void)
+{
+       mutex_lock(L3);
+
+       /* do something again */
+
+       mutex_unlock(L3);
+}
+
+Now we add 4 processes that run each of these functions separately.
+Processes A, B, C, and D which run functions func1, func2, func3 and func4
+respectively, and such that D runs first and A last.  With D being preempted
+in func4 in the "do something again" area, we have a locking that follows:
+
+D owns L3
+       C blocked on L3
+       C owns L2
+              B blocked on L2
+              B owns L1
+                     A blocked on L1
+
+And thus we have the chain A->L1->B->L2->C->L3->D.
+
+This gives us a PI depth of 4 (four processes), but looking at any of the
+functions individually, it seems as though they only have at most a locking
+depth of two.  So, although the locking depth is defined at compile time,
+it still is very difficult to find the possibilities of that depth.
+
+Now since mutexes can be defined by user-land applications, we don't want a DOS
+type of application that nests large amounts of mutexes to create a large
+PI chain, and have the code holding spin locks while looking at a large
+amount of data.  So to prevent this, the implementation not only implements
+a maximum lock depth, but also only holds at most two different locks at a
+time, as it walks the PI chain.  More about this below.
+
+
+Mutex owner and flags
+---------------------
+
+The mutex structure contains a pointer to the owner of the mutex.  If the
+mutex is not owned, this owner is set to NULL.  Since all architectures
+have the task structure on at least a four byte alignment (and if this is
+not true, the rtmutex.c code will be broken!), this allows for the two
+least significant bits to be used as flags.  This part is also described
+in Documentation/rt-mutex.txt, but will also be briefly described here.
+
+Bit 0 is used as the "Pending Owner" flag.  This is described later.
+Bit 1 is used as the "Has Waiters" flags.  This is also described later
+  in more detail, but is set whenever there are waiters on a mutex.
+
+
+cmpxchg Tricks
+--------------
+
+Some architectures implement an atomic cmpxchg (Compare and Exchange).  This
+is used (when applicable) to keep the fast path of grabbing and releasing
+mutexes short.
+
+cmpxchg is basically the following function performed atomically:
+
+unsigned long _cmpxchg(unsigned long *A, unsigned long *B, unsigned long *C)
+{
+       unsigned long T = *A;
+       if (*A == *B) {
+               *A = *C;
+       }
+       return T;
+}
+#define cmpxchg(a,b,c) _cmpxchg(&a,&b,&c)
+
+This is really nice to have, since it allows you to only update a variable
+if the variable is what you expect it to be.  You know if it succeeded if
+the return value (the old value of A) is equal to B.
+
+The macro rt_mutex_cmpxchg is used to try to lock and unlock mutexes. If
+the architecture does not support CMPXCHG, then this macro is simply set
+to fail every time.  But if CMPXCHG is supported, then this will
+help out extremely to keep the fast path short.
+
+The use of rt_mutex_cmpxchg with the flags in the owner field help optimize
+the system for architectures that support it.  This will also be explained
+later in this document.
+
+
+Priority adjustments
+--------------------
+
+The implementation of the PI code in rtmutex.c has several places that a
+process must adjust its priority.  With the help of the pi_list of a
+process this is rather easy to know what needs to be adjusted.
+
+The functions implementing the task adjustments are rt_mutex_adjust_prio,
+__rt_mutex_adjust_prio (same as the former, but expects the task pi_lock
+to already be taken), rt_mutex_getprio, and rt_mutex_setprio.
+
+rt_mutex_getprio and rt_mutex_setprio are only used in __rt_mutex_adjust_prio.
+
+rt_mutex_getprio returns the priority that the task should have.  Either the
+task's own normal priority, or if a process of a higher priority is waiting on
+a mutex owned by the task, then that higher priority should be returned.
+Since the pi_list of a task holds an order by priority list of all the top
+waiters of all the mutexes that the task owns, rt_mutex_getprio simply needs
+to compare the top pi waiter to its own normal priority, and return the higher
+priority back.
+
+(Note:  if looking at the code, you will notice that the lower number of
+        prio is returned.  This is because the prio field in the task structure
+        is an inverse order of the actual priority.  So a "prio" of 5 is
+        of higher priority than a "prio" of 10.)
+
+__rt_mutex_adjust_prio examines the result of rt_mutex_getprio, and if the
+result does not equal the task's current priority, then rt_mutex_setprio
+is called to adjust the priority of the task to the new priority.
+Note that rt_mutex_setprio is defined in kernel/sched/core.c to implement the
+actual change in priority.
+
+It is interesting to note that __rt_mutex_adjust_prio can either increase
+or decrease the priority of the task.  In the case that a higher priority
+process has just blocked on a mutex owned by the task, __rt_mutex_adjust_prio
+would increase/boost the task's priority.  But if a higher priority task
+were for some reason to leave the mutex (timeout or signal), this same function
+would decrease/unboost the priority of the task.  That is because the pi_list
+always contains the highest priority task that is waiting on a mutex owned
+by the task, so we only need to compare the priority of that top pi waiter
+to the normal priority of the given task.
+
+
+High level overview of the PI chain walk
+----------------------------------------
+
+The PI chain walk is implemented by the function rt_mutex_adjust_prio_chain.
+
+The implementation has gone through several iterations, and has ended up
+with what we believe is the best.  It walks the PI chain by only grabbing
+at most two locks at a time, and is very efficient.
+
+The rt_mutex_adjust_prio_chain can be used either to boost or lower process
+priorities.
+
+rt_mutex_adjust_prio_chain is called with a task to be checked for PI
+(de)boosting (the owner of a mutex that a process is blocking on), a flag to
+check for deadlocking, the mutex that the task owns, and a pointer to a waiter
+that is the process's waiter struct that is blocked on the mutex (although this
+parameter may be NULL for deboosting).
+
+For this explanation, I will not mention deadlock detection. This explanation
+will try to stay at a high level.
+
+When this function is called, there are no locks held.  That also means
+that the state of the owner and lock can change when entered into this function.
+
+Before this function is called, the task has already had rt_mutex_adjust_prio
+performed on it.  This means that the task is set to the priority that it
+should be at, but the plist nodes of the task's waiter have not been updated
+with the new priorities, and that this task may not be in the proper locations
+in the pi_lists and wait_lists that the task is blocked on.  This function
+solves all that.
+
+A loop is entered, where task is the owner to be checked for PI changes that
+was passed by parameter (for the first iteration).  The pi_lock of this task is
+taken to prevent any more changes to the pi_list of the task.  This also
+prevents new tasks from completing the blocking on a mutex that is owned by this
+task.
+
+If the task is not blocked on a mutex then the loop is exited.  We are at
+the top of the PI chain.
+
+A check is now done to see if the original waiter (the process that is blocked
+on the current mutex) is the top pi waiter of the task.  That is, is this
+waiter on the top of the task's pi_list.  If it is not, it either means that
+there is another process higher in priority that is blocked on one of the
+mutexes that the task owns, or that the waiter has just woken up via a signal
+or timeout and has left the PI chain.  In either case, the loop is exited, since
+we don't need to do any more changes to the priority of the current task, or any
+task that owns a mutex that this current task is waiting on.  A priority chain
+walk is only needed when a new top pi waiter is made to a task.
+
+The next check sees if the task's waiter plist node has the priority equal to
+the priority the task is set at.  If they are equal, then we are done with
+the loop.  Remember that the function started with the priority of the
+task adjusted, but the plist nodes that hold the task in other processes
+pi_lists have not been adjusted.
+
+Next, we look at the mutex that the task is blocked on. The mutex's wait_lock
+is taken.  This is done by a spin_trylock, because the locking order of the
+pi_lock and wait_lock goes in the opposite direction. If we fail to grab the
+lock, the pi_lock is released, and we restart the loop.
+
+Now that we have both the pi_lock of the task as well as the wait_lock of
+the mutex the task is blocked on, we update the task's waiter's plist node
+that is located on the mutex's wait_list.
+
+Now we release the pi_lock of the task.
+
+Next the owner of the mutex has its pi_lock taken, so we can update the
+task's entry in the owner's pi_list.  If the task is the highest priority
+process on the mutex's wait_list, then we remove the previous top waiter
+from the owner's pi_list, and replace it with the task.
+
+Note: It is possible that the task was the current top waiter on the mutex,
+      in which case the task is not yet on the pi_list of the waiter.  This
+      is OK, since plist_del does nothing if the plist node is not on any
+      list.
+
+If the task was not the top waiter of the mutex, but it was before we
+did the priority updates, that means we are deboosting/lowering the
+task.  In this case, the task is removed from the pi_list of the owner,
+and the new top waiter is added.
+
+Lastly, we unlock both the pi_lock of the task, as well as the mutex's
+wait_lock, and continue the loop again.  On the next iteration of the
+loop, the previous owner of the mutex will be the task that will be
+processed.
+
+Note: One might think that the owner of this mutex might have changed
+      since we just grab the mutex's wait_lock. And one could be right.
+      The important thing to remember is that the owner could not have
+      become the task that is being processed in the PI chain, since
+      we have taken that task's pi_lock at the beginning of the loop.
+      So as long as there is an owner of this mutex that is not the same
+      process as the tasked being worked on, we are OK.
+
+      Looking closely at the code, one might be confused.  The check for the
+      end of the PI chain is when the task isn't blocked on anything or the
+      task's waiter structure "task" element is NULL.  This check is
+      protected only by the task's pi_lock.  But the code to unlock the mutex
+      sets the task's waiter structure "task" element to NULL with only
+      the protection of the mutex's wait_lock, which was not taken yet.
+      Isn't this a race condition if the task becomes the new owner?
+
+      The answer is No!  The trick is the spin_trylock of the mutex's
+      wait_lock.  If we fail that lock, we release the pi_lock of the
+      task and continue the loop, doing the end of PI chain check again.
+
+      In the code to release the lock, the wait_lock of the mutex is held
+      the entire time, and it is not let go when we grab the pi_lock of the
+      new owner of the mutex.  So if the switch of a new owner were to happen
+      after the check for end of the PI chain and the grabbing of the
+      wait_lock, the unlocking code would spin on the new owner's pi_lock
+      but never give up the wait_lock.  So the PI chain loop is guaranteed to
+      fail the spin_trylock on the wait_lock, release the pi_lock, and
+      try again.
+
+      If you don't quite understand the above, that's OK. You don't have to,
+      unless you really want to make a proof out of it ;)
+
+
+Pending Owners and Lock stealing
+--------------------------------
+
+One of the flags in the owner field of the mutex structure is "Pending Owner".
+What this means is that an owner was chosen by the process releasing the
+mutex, but that owner has yet to wake up and actually take the mutex.
+
+Why is this important?  Why can't we just give the mutex to another process
+and be done with it?
+
+The PI code is to help with real-time processes, and to let the highest
+priority process run as long as possible with little latencies and delays.
+If a high priority process owns a mutex that a lower priority process is
+blocked on, when the mutex is released it would be given to the lower priority
+process.  What if the higher priority process wants to take that mutex again.
+The high priority process would fail to take that mutex that it just gave up
+and it would need to boost the lower priority process to run with full
+latency of that critical section (since the low priority process just entered
+it).
+
+There's no reason a high priority process that gives up a mutex should be
+penalized if it tries to take that mutex again.  If the new owner of the
+mutex has not woken up yet, there's no reason that the higher priority process
+could not take that mutex away.
+
+To solve this, we introduced Pending Ownership and Lock Stealing.  When a
+new process is given a mutex that it was blocked on, it is only given
+pending ownership.  This means that it's the new owner, unless a higher
+priority process comes in and tries to grab that mutex.  If a higher priority
+process does come along and wants that mutex, we let the higher priority
+process "steal" the mutex from the pending owner (only if it is still pending)
+and continue with the mutex.
+
+
+Taking of a mutex (The walk through)
+------------------------------------
+
+OK, now let's take a look at the detailed walk through of what happens when
+taking a mutex.
+
+The first thing that is tried is the fast taking of the mutex.  This is
+done when we have CMPXCHG enabled (otherwise the fast taking automatically
+fails).  Only when the owner field of the mutex is NULL can the lock be
+taken with the CMPXCHG and nothing else needs to be done.
+
+If there is contention on the lock, whether it is owned or pending owner
+we go about the slow path (rt_mutex_slowlock).
+
+The slow path function is where the task's waiter structure is created on
+the stack.  This is because the waiter structure is only needed for the
+scope of this function.  The waiter structure holds the nodes to store
+the task on the wait_list of the mutex, and if need be, the pi_list of
+the owner.
+
+The wait_lock of the mutex is taken since the slow path of unlocking the
+mutex also takes this lock.
+
+We then call try_to_take_rt_mutex.  This is where the architecture that
+does not implement CMPXCHG would always grab the lock (if there's no
+contention).
+
+try_to_take_rt_mutex is used every time the task tries to grab a mutex in the
+slow path.  The first thing that is done here is an atomic setting of
+the "Has Waiters" flag of the mutex's owner field.  Yes, this could really
+be false, because if the mutex has no owner, there are no waiters and
+the current task also won't have any waiters.  But we don't have the lock
+yet, so we assume we are going to be a waiter.  The reason for this is to
+play nice for those architectures that do have CMPXCHG.  By setting this flag
+now, the owner of the mutex can't release the mutex without going into the
+slow unlock path, and it would then need to grab the wait_lock, which this
+code currently holds.  So setting the "Has Waiters" flag forces the owner
+to synchronize with this code.
+
+Now that we know that we can't have any races with the owner releasing the
+mutex, we check to see if we can take the ownership.  This is done if the
+mutex doesn't have a owner, or if we can steal the mutex from a pending
+owner.  Let's look at the situations we have here.
+
+  1) Has owner that is pending
+  ----------------------------
+
+  The mutex has a owner, but it hasn't woken up and the mutex flag
+  "Pending Owner" is set.  The first check is to see if the owner isn't the
+  current task.  This is because this function is also used for the pending
+  owner to grab the mutex.  When a pending owner wakes up, it checks to see
+  if it can take the mutex, and this is done if the owner is already set to
+  itself.  If so, we succeed and leave the function, clearing the "Pending
+  Owner" bit.
+
+  If the pending owner is not current, we check to see if the current priority is
+  higher than the pending owner.  If not, we fail the function and return.
+
+  There's also something special about a pending owner.  That is a pending owner
+  is never blocked on a mutex.  So there is no PI chain to worry about.  It also
+  means that if the mutex doesn't have any waiters, there's no accounting needed
+  to update the pending owner's pi_list, since we only worry about processes
+  blocked on the current mutex.
+
+  If there are waiters on this mutex, and we just stole the ownership, we need
+  to take the top waiter, remove it from the pi_list of the pending owner, and
+  add it to the current pi_list.  Note that at this moment, the pending owner
+  is no longer on the list of waiters.  This is fine, since the pending owner
+  would add itself back when it realizes that it had the ownership stolen
+  from itself.  When the pending owner tries to grab the mutex, it will fail
+  in try_to_take_rt_mutex if the owner field points to another process.
+
+  2) No owner
+  -----------
+
+  If there is no owner (or we successfully stole the lock), we set the owner
+  of the mutex to current, and set the flag of "Has Waiters" if the current
+  mutex actually has waiters, or we clear the flag if it doesn't.  See, it was
+  OK that we set that flag early, since now it is cleared.
+
+  3) Failed to grab ownership
+  ---------------------------
+
+  The most interesting case is when we fail to take ownership. This means that
+  there exists an owner, or there's a pending owner with equal or higher
+  priority than the current task.
+
+We'll continue on the failed case.
+
+If the mutex has a timeout, we set up a timer to go off to break us out
+of this mutex if we failed to get it after a specified amount of time.
+
+Now we enter a loop that will continue to try to take ownership of the mutex, or
+fail from a timeout or signal.
+
+Once again we try to take the mutex.  This will usually fail the first time
+in the loop, since it had just failed to get the mutex.  But the second time
+in the loop, this would likely succeed, since the task would likely be
+the pending owner.
+
+If the mutex is TASK_INTERRUPTIBLE a check for signals and timeout is done
+here.
+
+The waiter structure has a "task" field that points to the task that is blocked
+on the mutex.  This field can be NULL the first time it goes through the loop
+or if the task is a pending owner and had its mutex stolen.  If the "task"
+field is NULL then we need to set up the accounting for it.
+
+Task blocks on mutex
+--------------------
+
+The accounting of a mutex and process is done with the waiter structure of
+the process.  The "task" field is set to the process, and the "lock" field
+to the mutex.  The plist nodes are initialized to the processes current
+priority.
+
+Since the wait_lock was taken at the entry of the slow lock, we can safely
+add the waiter to the wait_list.  If the current process is the highest
+priority process currently waiting on this mutex, then we remove the
+previous top waiter process (if it exists) from the pi_list of the owner,
+and add the current process to that list.  Since the pi_list of the owner
+has changed, we call rt_mutex_adjust_prio on the owner to see if the owner
+should adjust its priority accordingly.
+
+If the owner is also blocked on a lock, and had its pi_list changed
+(or deadlock checking is on), we unlock the wait_lock of the mutex and go ahead
+and run rt_mutex_adjust_prio_chain on the owner, as described earlier.
+
+Now all locks are released, and if the current process is still blocked on a
+mutex (waiter "task" field is not NULL), then we go to sleep (call schedule).
+
+Waking up in the loop
+---------------------
+
+The schedule can then wake up for a few reasons.
+  1) we were given pending ownership of the mutex.
+  2) we received a signal and was TASK_INTERRUPTIBLE
+  3) we had a timeout and was TASK_INTERRUPTIBLE
+
+In any of these cases, we continue the loop and once again try to grab the
+ownership of the mutex.  If we succeed, we exit the loop, otherwise we continue
+and on signal and timeout, will exit the loop, or if we had the mutex stolen
+we just simply add ourselves back on the lists and go back to sleep.
+
+Note: For various reasons, because of timeout and signals, the steal mutex
+      algorithm needs to be careful. This is because the current process is
+      still on the wait_list. And because of dynamic changing of priorities,
+      especially on SCHED_OTHER tasks, the current process can be the
+      highest priority task on the wait_list.
+
+Failed to get mutex on Timeout or Signal
+----------------------------------------
+
+If a timeout or signal occurred, the waiter's "task" field would not be
+NULL and the task needs to be taken off the wait_list of the mutex and perhaps
+pi_list of the owner.  If this process was a high priority process, then
+the rt_mutex_adjust_prio_chain needs to be executed again on the owner,
+but this time it will be lowering the priorities.
+
+
+Unlocking the Mutex
+-------------------
+
+The unlocking of a mutex also has a fast path for those architectures with
+CMPXCHG.  Since the taking of a mutex on contention always sets the
+"Has Waiters" flag of the mutex's owner, we use this to know if we need to
+take the slow path when unlocking the mutex.  If the mutex doesn't have any
+waiters, the owner field of the mutex would equal the current process and
+the mutex can be unlocked by just replacing the owner field with NULL.
+
+If the owner field has the "Has Waiters" bit set (or CMPXCHG is not available),
+the slow unlock path is taken.
+
+The first thing done in the slow unlock path is to take the wait_lock of the
+mutex.  This synchronizes the locking and unlocking of the mutex.
+
+A check is made to see if the mutex has waiters or not.  On architectures that
+do not have CMPXCHG, this is the location that the owner of the mutex will
+determine if a waiter needs to be awoken or not.  On architectures that
+do have CMPXCHG, that check is done in the fast path, but it is still needed
+in the slow path too.  If a waiter of a mutex woke up because of a signal
+or timeout between the time the owner failed the fast path CMPXCHG check and
+the grabbing of the wait_lock, the mutex may not have any waiters, thus the
+owner still needs to make this check. If there are no waiters then the mutex
+owner field is set to NULL, the wait_lock is released and nothing more is
+needed.
+
+If there are waiters, then we need to wake one up and give that waiter
+pending ownership.
+
+On the wake up code, the pi_lock of the current owner is taken.  The top
+waiter of the lock is found and removed from the wait_list of the mutex
+as well as the pi_list of the current owner.  The task field of the new
+pending owner's waiter structure is set to NULL, and the owner field of the
+mutex is set to the new owner with the "Pending Owner" bit set, as well
+as the "Has Waiters" bit if there still are other processes blocked on the
+mutex.
+
+The pi_lock of the previous owner is released, and the new pending owner's
+pi_lock is taken.  Remember that this is the trick to prevent the race
+condition in rt_mutex_adjust_prio_chain from adding itself as a waiter
+on the mutex.
+
+We now clear the "pi_blocked_on" field of the new pending owner, and if
+the mutex still has waiters pending, we add the new top waiter to the pi_list
+of the pending owner.
+
+Finally we unlock the pi_lock of the pending owner and wake it up.
+
+
+Contact
+-------
+
+For updates on this document, please email Steven Rostedt <rostedt@goodmis.org>
+
+
+Credits
+-------
+
+Author:  Steven Rostedt <rostedt@goodmis.org>
+
+Reviewers:  Ingo Molnar, Thomas Gleixner, Thomas Duetsch, and Randy Dunlap
+
+Updates
+-------
+
+This document was originally written for 2.6.17-rc3-mm1
diff --git a/Documentation/locking/rt-mutex.txt b/Documentation/locking/rt-mutex.txt
new file mode 100644 (file)
index 0000000..243393d
--- /dev/null
@@ -0,0 +1,79 @@
+RT-mutex subsystem with PI support
+----------------------------------
+
+RT-mutexes with priority inheritance are used to support PI-futexes,
+which enable pthread_mutex_t priority inheritance attributes
+(PTHREAD_PRIO_INHERIT). [See Documentation/pi-futex.txt for more details
+about PI-futexes.]
+
+This technology was developed in the -rt tree and streamlined for
+pthread_mutex support.
+
+Basic principles:
+-----------------
+
+RT-mutexes extend the semantics of simple mutexes by the priority
+inheritance protocol.
+
+A low priority owner of a rt-mutex inherits the priority of a higher
+priority waiter until the rt-mutex is released. If the temporarily
+boosted owner blocks on a rt-mutex itself it propagates the priority
+boosting to the owner of the other rt_mutex it gets blocked on. The
+priority boosting is immediately removed once the rt_mutex has been
+unlocked.
+
+This approach allows us to shorten the block of high-prio tasks on
+mutexes which protect shared resources. Priority inheritance is not a
+magic bullet for poorly designed applications, but it allows
+well-designed applications to use userspace locks in critical parts of
+an high priority thread, without losing determinism.
+
+The enqueueing of the waiters into the rtmutex waiter list is done in
+priority order. For same priorities FIFO order is chosen. For each
+rtmutex, only the top priority waiter is enqueued into the owner's
+priority waiters list. This list too queues in priority order. Whenever
+the top priority waiter of a task changes (for example it timed out or
+got a signal), the priority of the owner task is readjusted. [The
+priority enqueueing is handled by "plists", see include/linux/plist.h
+for more details.]
+
+RT-mutexes are optimized for fastpath operations and have no internal
+locking overhead when locking an uncontended mutex or unlocking a mutex
+without waiters. The optimized fastpath operations require cmpxchg
+support. [If that is not available then the rt-mutex internal spinlock
+is used]
+
+The state of the rt-mutex is tracked via the owner field of the rt-mutex
+structure:
+
+rt_mutex->owner holds the task_struct pointer of the owner. Bit 0 and 1
+are used to keep track of the "owner is pending" and "rtmutex has
+waiters" state.
+
+ owner         bit1    bit0
+ NULL          0       0       mutex is free (fast acquire possible)
+ NULL          0       1       invalid state
+ NULL          1       0       Transitional state*
+ NULL          1       1       invalid state
+ taskpointer   0       0       mutex is held (fast release possible)
+ taskpointer   0       1       task is pending owner
+ taskpointer   1       0       mutex is held and has waiters
+ taskpointer   1       1       task is pending owner and mutex has waiters
+
+Pending-ownership handling is a performance optimization:
+pending-ownership is assigned to the first (highest priority) waiter of
+the mutex, when the mutex is released. The thread is woken up and once
+it starts executing it can acquire the mutex. Until the mutex is taken
+by it (bit 0 is cleared) a competing higher priority thread can "steal"
+the mutex which puts the woken up thread back on the waiters list.
+
+The pending-ownership optimization is especially important for the
+uninterrupted workflow of high-prio tasks which repeatedly
+takes/releases locks that have lower-prio waiters. Without this
+optimization the higher-prio thread would ping-pong to the lower-prio
+task [because at unlock time we always assign a new owner].
+
+(*) The "mutex has waiters" bit gets set to take the lock. If the lock
+doesn't already have an owner, this bit is quickly cleared if there are
+no waiters.  So this is a transitional state to synchronize with looking
+at the owner field of the mutex and the mutex owner releasing the lock.
diff --git a/Documentation/locking/spinlocks.txt b/Documentation/locking/spinlocks.txt
new file mode 100644 (file)
index 0000000..ff35e40
--- /dev/null
@@ -0,0 +1,167 @@
+Lesson 1: Spin locks
+
+The most basic primitive for locking is spinlock.
+
+static DEFINE_SPINLOCK(xxx_lock);
+
+       unsigned long flags;
+
+       spin_lock_irqsave(&xxx_lock, flags);
+       ... critical section here ..
+       spin_unlock_irqrestore(&xxx_lock, flags);
+
+The above is always safe. It will disable interrupts _locally_, but the
+spinlock itself will guarantee the global lock, so it will guarantee that
+there is only one thread-of-control within the region(s) protected by that
+lock. This works well even under UP also, so the code does _not_ need to
+worry about UP vs SMP issues: the spinlocks work correctly under both.
+
+   NOTE! Implications of spin_locks for memory are further described in:
+
+     Documentation/memory-barriers.txt
+       (5) LOCK operations.
+       (6) UNLOCK operations.
+
+The above is usually pretty simple (you usually need and want only one
+spinlock for most things - using more than one spinlock can make things a
+lot more complex and even slower and is usually worth it only for
+sequences that you _know_ need to be split up: avoid it at all cost if you
+aren't sure).
+
+This is really the only really hard part about spinlocks: once you start
+using spinlocks they tend to expand to areas you might not have noticed
+before, because you have to make sure the spinlocks correctly protect the
+shared data structures _everywhere_ they are used. The spinlocks are most
+easily added to places that are completely independent of other code (for
+example, internal driver data structures that nobody else ever touches).
+
+   NOTE! The spin-lock is safe only when you _also_ use the lock itself
+   to do locking across CPU's, which implies that EVERYTHING that
+   touches a shared variable has to agree about the spinlock they want
+   to use.
+
+----
+
+Lesson 2: reader-writer spinlocks.
+
+If your data accesses have a very natural pattern where you usually tend
+to mostly read from the shared variables, the reader-writer locks
+(rw_lock) versions of the spinlocks are sometimes useful. They allow multiple
+readers to be in the same critical region at once, but if somebody wants
+to change the variables it has to get an exclusive write lock.
+
+   NOTE! reader-writer locks require more atomic memory operations than
+   simple spinlocks.  Unless the reader critical section is long, you
+   are better off just using spinlocks.
+
+The routines look the same as above:
+
+   rwlock_t xxx_lock = __RW_LOCK_UNLOCKED(xxx_lock);
+
+       unsigned long flags;
+
+       read_lock_irqsave(&xxx_lock, flags);
+       .. critical section that only reads the info ...
+       read_unlock_irqrestore(&xxx_lock, flags);
+
+       write_lock_irqsave(&xxx_lock, flags);
+       .. read and write exclusive access to the info ...
+       write_unlock_irqrestore(&xxx_lock, flags);
+
+The above kind of lock may be useful for complex data structures like
+linked lists, especially searching for entries without changing the list
+itself.  The read lock allows many concurrent readers.  Anything that
+_changes_ the list will have to get the write lock.
+
+   NOTE! RCU is better for list traversal, but requires careful
+   attention to design detail (see Documentation/RCU/listRCU.txt).
+
+Also, you cannot "upgrade" a read-lock to a write-lock, so if you at _any_
+time need to do any changes (even if you don't do it every time), you have
+to get the write-lock at the very beginning.
+
+   NOTE! We are working hard to remove reader-writer spinlocks in most
+   cases, so please don't add a new one without consensus.  (Instead, see
+   Documentation/RCU/rcu.txt for complete information.)
+
+----
+
+Lesson 3: spinlocks revisited.
+
+The single spin-lock primitives above are by no means the only ones. They
+are the most safe ones, and the ones that work under all circumstances,
+but partly _because_ they are safe they are also fairly slow. They are slower
+than they'd need to be, because they do have to disable interrupts
+(which is just a single instruction on a x86, but it's an expensive one -
+and on other architectures it can be worse).
+
+If you have a case where you have to protect a data structure across
+several CPU's and you want to use spinlocks you can potentially use
+cheaper versions of the spinlocks. IFF you know that the spinlocks are
+never used in interrupt handlers, you can use the non-irq versions:
+
+       spin_lock(&lock);
+       ...
+       spin_unlock(&lock);
+
+(and the equivalent read-write versions too, of course). The spinlock will
+guarantee the same kind of exclusive access, and it will be much faster.
+This is useful if you know that the data in question is only ever
+manipulated from a "process context", ie no interrupts involved.
+
+The reasons you mustn't use these versions if you have interrupts that
+play with the spinlock is that you can get deadlocks:
+
+       spin_lock(&lock);
+       ...
+               <- interrupt comes in:
+                       spin_lock(&lock);
+
+where an interrupt tries to lock an already locked variable. This is ok if
+the other interrupt happens on another CPU, but it is _not_ ok if the
+interrupt happens on the same CPU that already holds the lock, because the
+lock will obviously never be released (because the interrupt is waiting
+for the lock, and the lock-holder is interrupted by the interrupt and will
+not continue until the interrupt has been processed).
+
+(This is also the reason why the irq-versions of the spinlocks only need
+to disable the _local_ interrupts - it's ok to use spinlocks in interrupts
+on other CPU's, because an interrupt on another CPU doesn't interrupt the
+CPU that holds the lock, so the lock-holder can continue and eventually
+releases the lock).
+
+Note that you can be clever with read-write locks and interrupts. For
+example, if you know that the interrupt only ever gets a read-lock, then
+you can use a non-irq version of read locks everywhere - because they
+don't block on each other (and thus there is no dead-lock wrt interrupts.
+But when you do the write-lock, you have to use the irq-safe version.
+
+For an example of being clever with rw-locks, see the "waitqueue_lock"
+handling in kernel/sched/core.c - nothing ever _changes_ a wait-queue from
+within an interrupt, they only read the queue in order to know whom to
+wake up. So read-locks are safe (which is good: they are very common
+indeed), while write-locks need to protect themselves against interrupts.
+
+               Linus
+
+----
+
+Reference information:
+
+For dynamic initialization, use spin_lock_init() or rwlock_init() as
+appropriate:
+
+   spinlock_t xxx_lock;
+   rwlock_t xxx_rw_lock;
+
+   static int __init xxx_init(void)
+   {
+       spin_lock_init(&xxx_lock);
+       rwlock_init(&xxx_rw_lock);
+       ...
+   }
+
+   module_init(xxx_init);
+
+For static initialization, use DEFINE_SPINLOCK() / DEFINE_RWLOCK() or
+__SPIN_LOCK_UNLOCKED() / __RW_LOCK_UNLOCKED() as appropriate.
diff --git a/Documentation/locking/ww-mutex-design.txt b/Documentation/locking/ww-mutex-design.txt
new file mode 100644 (file)
index 0000000..8a112dc
--- /dev/null
@@ -0,0 +1,344 @@
+Wait/Wound Deadlock-Proof Mutex Design
+======================================
+
+Please read mutex-design.txt first, as it applies to wait/wound mutexes too.
+
+Motivation for WW-Mutexes
+-------------------------
+
+GPU's do operations that commonly involve many buffers.  Those buffers
+can be shared across contexts/processes, exist in different memory
+domains (for example VRAM vs system memory), and so on.  And with
+PRIME / dmabuf, they can even be shared across devices.  So there are
+a handful of situations where the driver needs to wait for buffers to
+become ready.  If you think about this in terms of waiting on a buffer
+mutex for it to become available, this presents a problem because
+there is no way to guarantee that buffers appear in a execbuf/batch in
+the same order in all contexts.  That is directly under control of
+userspace, and a result of the sequence of GL calls that an application
+makes. Which results in the potential for deadlock.  The problem gets
+more complex when you consider that the kernel may need to migrate the
+buffer(s) into VRAM before the GPU operates on the buffer(s), which
+may in turn require evicting some other buffers (and you don't want to
+evict other buffers which are already queued up to the GPU), but for a
+simplified understanding of the problem you can ignore this.
+
+The algorithm that the TTM graphics subsystem came up with for dealing with
+this problem is quite simple.  For each group of buffers (execbuf) that need
+to be locked, the caller would be assigned a unique reservation id/ticket,
+from a global counter.  In case of deadlock while locking all the buffers
+associated with a execbuf, the one with the lowest reservation ticket (i.e.
+the oldest task) wins, and the one with the higher reservation id (i.e. the
+younger task) unlocks all of the buffers that it has already locked, and then
+tries again.
+
+In the RDBMS literature this deadlock handling approach is called wait/wound:
+The older tasks waits until it can acquire the contended lock. The younger tasks
+needs to back off and drop all the locks it is currently holding, i.e. the
+younger task is wounded.
+
+Concepts
+--------
+
+Compared to normal mutexes two additional concepts/objects show up in the lock
+interface for w/w mutexes:
+
+Acquire context: To ensure eventual forward progress it is important the a task
+trying to acquire locks doesn't grab a new reservation id, but keeps the one it
+acquired when starting the lock acquisition. This ticket is stored in the
+acquire context. Furthermore the acquire context keeps track of debugging state
+to catch w/w mutex interface abuse.
+
+W/w class: In contrast to normal mutexes the lock class needs to be explicit for
+w/w mutexes, since it is required to initialize the acquire context.
+
+Furthermore there are three different class of w/w lock acquire functions:
+
+* Normal lock acquisition with a context, using ww_mutex_lock.
+
+* Slowpath lock acquisition on the contending lock, used by the wounded task
+  after having dropped all already acquired locks. These functions have the
+  _slow postfix.
+
+  From a simple semantics point-of-view the _slow functions are not strictly
+  required, since simply calling the normal ww_mutex_lock functions on the
+  contending lock (after having dropped all other already acquired locks) will
+  work correctly. After all if no other ww mutex has been acquired yet there's
+  no deadlock potential and hence the ww_mutex_lock call will block and not
+  prematurely return -EDEADLK. The advantage of the _slow functions is in
+  interface safety:
+  - ww_mutex_lock has a __must_check int return type, whereas ww_mutex_lock_slow
+    has a void return type. Note that since ww mutex code needs loops/retries
+    anyway the __must_check doesn't result in spurious warnings, even though the
+    very first lock operation can never fail.
+  - When full debugging is enabled ww_mutex_lock_slow checks that all acquired
+    ww mutex have been released (preventing deadlocks) and makes sure that we
+    block on the contending lock (preventing spinning through the -EDEADLK
+    slowpath until the contended lock can be acquired).
+
+* Functions to only acquire a single w/w mutex, which results in the exact same
+  semantics as a normal mutex. This is done by calling ww_mutex_lock with a NULL
+  context.
+
+  Again this is not strictly required. But often you only want to acquire a
+  single lock in which case it's pointless to set up an acquire context (and so
+  better to avoid grabbing a deadlock avoidance ticket).
+
+Of course, all the usual variants for handling wake-ups due to signals are also
+provided.
+
+Usage
+-----
+
+Three different ways to acquire locks within the same w/w class. Common
+definitions for methods #1 and #2:
+
+static DEFINE_WW_CLASS(ww_class);
+
+struct obj {
+       struct ww_mutex lock;
+       /* obj data */
+};
+
+struct obj_entry {
+       struct list_head head;
+       struct obj *obj;
+};
+
+Method 1, using a list in execbuf->buffers that's not allowed to be reordered.
+This is useful if a list of required objects is already tracked somewhere.
+Furthermore the lock helper can use propagate the -EALREADY return code back to
+the caller as a signal that an object is twice on the list. This is useful if
+the list is constructed from userspace input and the ABI requires userspace to
+not have duplicate entries (e.g. for a gpu commandbuffer submission ioctl).
+
+int lock_objs(struct list_head *list, struct ww_acquire_ctx *ctx)
+{
+       struct obj *res_obj = NULL;
+       struct obj_entry *contended_entry = NULL;
+       struct obj_entry *entry;
+
+       ww_acquire_init(ctx, &ww_class);
+
+retry:
+       list_for_each_entry (entry, list, head) {
+               if (entry->obj == res_obj) {
+                       res_obj = NULL;
+                       continue;
+               }
+               ret = ww_mutex_lock(&entry->obj->lock, ctx);
+               if (ret < 0) {
+                       contended_entry = entry;
+                       goto err;
+               }
+       }
+
+       ww_acquire_done(ctx);
+       return 0;
+
+err:
+       list_for_each_entry_continue_reverse (entry, list, head)
+               ww_mutex_unlock(&entry->obj->lock);
+
+       if (res_obj)
+               ww_mutex_unlock(&res_obj->lock);
+
+       if (ret == -EDEADLK) {
+               /* we lost out in a seqno race, lock and retry.. */
+               ww_mutex_lock_slow(&contended_entry->obj->lock, ctx);
+               res_obj = contended_entry->obj;
+               goto retry;
+       }
+       ww_acquire_fini(ctx);
+
+       return ret;
+}
+
+Method 2, using a list in execbuf->buffers that can be reordered. Same semantics
+of duplicate entry detection using -EALREADY as method 1 above. But the
+list-reordering allows for a bit more idiomatic code.
+
+int lock_objs(struct list_head *list, struct ww_acquire_ctx *ctx)
+{
+       struct obj_entry *entry, *entry2;
+
+       ww_acquire_init(ctx, &ww_class);
+
+       list_for_each_entry (entry, list, head) {
+               ret = ww_mutex_lock(&entry->obj->lock, ctx);
+               if (ret < 0) {
+                       entry2 = entry;
+
+                       list_for_each_entry_continue_reverse (entry2, list, head)
+                               ww_mutex_unlock(&entry2->obj->lock);
+
+                       if (ret != -EDEADLK) {
+                               ww_acquire_fini(ctx);
+                               return ret;
+                       }
+
+                       /* we lost out in a seqno race, lock and retry.. */
+                       ww_mutex_lock_slow(&entry->obj->lock, ctx);
+
+                       /*
+                        * Move buf to head of the list, this will point
+                        * buf->next to the first unlocked entry,
+                        * restarting the for loop.
+                        */
+                       list_del(&entry->head);
+                       list_add(&entry->head, list);
+               }
+       }
+
+       ww_acquire_done(ctx);
+       return 0;
+}
+
+Unlocking works the same way for both methods #1 and #2:
+
+void unlock_objs(struct list_head *list, struct ww_acquire_ctx *ctx)
+{
+       struct obj_entry *entry;
+
+       list_for_each_entry (entry, list, head)
+               ww_mutex_unlock(&entry->obj->lock);
+
+       ww_acquire_fini(ctx);
+}
+
+Method 3 is useful if the list of objects is constructed ad-hoc and not upfront,
+e.g. when adjusting edges in a graph where each node has its own ww_mutex lock,
+and edges can only be changed when holding the locks of all involved nodes. w/w
+mutexes are a natural fit for such a case for two reasons:
+- They can handle lock-acquisition in any order which allows us to start walking
+  a graph from a starting point and then iteratively discovering new edges and
+  locking down the nodes those edges connect to.
+- Due to the -EALREADY return code signalling that a given objects is already
+  held there's no need for additional book-keeping to break cycles in the graph
+  or keep track off which looks are already held (when using more than one node
+  as a starting point).
+
+Note that this approach differs in two important ways from the above methods:
+- Since the list of objects is dynamically constructed (and might very well be
+  different when retrying due to hitting the -EDEADLK wound condition) there's
+  no need to keep any object on a persistent list when it's not locked. We can
+  therefore move the list_head into the object itself.
+- On the other hand the dynamic object list construction also means that the -EALREADY return
+  code can't be propagated.
+
+Note also that methods #1 and #2 and method #3 can be combined, e.g. to first lock a
+list of starting nodes (passed in from userspace) using one of the above
+methods. And then lock any additional objects affected by the operations using
+method #3 below. The backoff/retry procedure will be a bit more involved, since
+when the dynamic locking step hits -EDEADLK we also need to unlock all the
+objects acquired with the fixed list. But the w/w mutex debug checks will catch
+any interface misuse for these cases.
+
+Also, method 3 can't fail the lock acquisition step since it doesn't return
+-EALREADY. Of course this would be different when using the _interruptible
+variants, but that's outside of the scope of these examples here.
+
+struct obj {
+       struct ww_mutex ww_mutex;
+       struct list_head locked_list;
+};
+
+static DEFINE_WW_CLASS(ww_class);
+
+void __unlock_objs(struct list_head *list)
+{
+       struct obj *entry, *temp;
+
+       list_for_each_entry_safe (entry, temp, list, locked_list) {
+               /* need to do that before unlocking, since only the current lock holder is
+               allowed to use object */
+               list_del(&entry->locked_list);
+               ww_mutex_unlock(entry->ww_mutex)
+       }
+}
+
+void lock_objs(struct list_head *list, struct ww_acquire_ctx *ctx)
+{
+       struct obj *obj;
+
+       ww_acquire_init(ctx, &ww_class);
+
+retry:
+       /* re-init loop start state */
+       loop {
+               /* magic code which walks over a graph and decides which objects
+                * to lock */
+
+               ret = ww_mutex_lock(obj->ww_mutex, ctx);
+               if (ret == -EALREADY) {
+                       /* we have that one already, get to the next object */
+                       continue;
+               }
+               if (ret == -EDEADLK) {
+                       __unlock_objs(list);
+
+                       ww_mutex_lock_slow(obj, ctx);
+                       list_add(&entry->locked_list, list);
+                       goto retry;
+               }
+
+               /* locked a new object, add it to the list */
+               list_add_tail(&entry->locked_list, list);
+       }
+
+       ww_acquire_done(ctx);
+       return 0;
+}
+
+void unlock_objs(struct list_head *list, struct ww_acquire_ctx *ctx)
+{
+       __unlock_objs(list);
+       ww_acquire_fini(ctx);
+}
+
+Method 4: Only lock one single objects. In that case deadlock detection and
+prevention is obviously overkill, since with grabbing just one lock you can't
+produce a deadlock within just one class. To simplify this case the w/w mutex
+api can be used with a NULL context.
+
+Implementation Details
+----------------------
+
+Design:
+  ww_mutex currently encapsulates a struct mutex, this means no extra overhead for
+  normal mutex locks, which are far more common. As such there is only a small
+  increase in code size if wait/wound mutexes are not used.
+
+  In general, not much contention is expected. The locks are typically used to
+  serialize access to resources for devices. The only way to make wakeups
+  smarter would be at the cost of adding a field to struct mutex_waiter. This
+  would add overhead to all cases where normal mutexes are used, and
+  ww_mutexes are generally less performance sensitive.
+
+Lockdep:
+  Special care has been taken to warn for as many cases of api abuse
+  as possible. Some common api abuses will be caught with
+  CONFIG_DEBUG_MUTEXES, but CONFIG_PROVE_LOCKING is recommended.
+
+  Some of the errors which will be warned about:
+   - Forgetting to call ww_acquire_fini or ww_acquire_init.
+   - Attempting to lock more mutexes after ww_acquire_done.
+   - Attempting to lock the wrong mutex after -EDEADLK and
+     unlocking all mutexes.
+   - Attempting to lock the right mutex after -EDEADLK,
+     before unlocking all mutexes.
+
+   - Calling ww_mutex_lock_slow before -EDEADLK was returned.
+
+   - Unlocking mutexes with the wrong unlock function.
+   - Calling one of the ww_acquire_* twice on the same context.
+   - Using a different ww_class for the mutex than for the ww_acquire_ctx.
+   - Normal lockdep errors that can result in deadlocks.
+
+  Some of the lockdep errors that can result in deadlocks:
+   - Calling ww_acquire_init to initialize a second ww_acquire_ctx before
+     having called ww_acquire_fini on the first.
+   - 'normal' deadlocks that can occur.
+
+FIXME: Update this section once we have the TASK_DEADLOCK task state flag magic
+implemented.
diff --git a/Documentation/lockstat.txt b/Documentation/lockstat.txt
deleted file mode 100644 (file)
index 72d0106..0000000
+++ /dev/null
@@ -1,178 +0,0 @@
-
-LOCK STATISTICS
-
-- WHAT
-
-As the name suggests, it provides statistics on locks.
-
-- WHY
-
-Because things like lock contention can severely impact performance.
-
-- HOW
-
-Lockdep already has hooks in the lock functions and maps lock instances to
-lock classes. We build on that (see Documentation/lockdep-design.txt).
-The graph below shows the relation between the lock functions and the various
-hooks therein.
-
-        __acquire
-            |
-           lock _____
-            |        \
-            |    __contended
-            |         |
-            |       <wait>
-            | _______/
-            |/
-            |
-       __acquired
-            |
-            .
-          <hold>
-            .
-            |
-       __release
-            |
-         unlock
-
-lock, unlock   - the regular lock functions
-__*            - the hooks
-<>             - states
-
-With these hooks we provide the following statistics:
-
- con-bounces       - number of lock contention that involved x-cpu data
- contentions       - number of lock acquisitions that had to wait
- wait time min     - shortest (non-0) time we ever had to wait for a lock
-           max     - longest time we ever had to wait for a lock
-          total   - total time we spend waiting on this lock
-          avg     - average time spent waiting on this lock
- acq-bounces       - number of lock acquisitions that involved x-cpu data
- acquisitions      - number of times we took the lock
- hold time min     - shortest (non-0) time we ever held the lock
-          max     - longest time we ever held the lock
-          total   - total time this lock was held
-          avg     - average time this lock was held
-
-These numbers are gathered per lock class, per read/write state (when
-applicable).
-
-It also tracks 4 contention points per class. A contention point is a call site
-that had to wait on lock acquisition.
-
- - CONFIGURATION
-
-Lock statistics are enabled via CONFIG_LOCK_STAT.
-
- - USAGE
-
-Enable collection of statistics:
-
-# echo 1 >/proc/sys/kernel/lock_stat
-
-Disable collection of statistics:
-
-# echo 0 >/proc/sys/kernel/lock_stat
-
-Look at the current lock statistics:
-
-( line numbers not part of actual output, done for clarity in the explanation
-  below )
-
-# less /proc/lock_stat
-
-01 lock_stat version 0.4
-02-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-03                              class name    con-bounces    contentions   waittime-min   waittime-max waittime-total   waittime-avg    acq-bounces   acquisitions   holdtime-min   holdtime-max holdtime-total   holdtime-avg
-04-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-05
-06                         &mm->mmap_sem-W:            46             84           0.26         939.10       16371.53         194.90          47291        2922365           0.16     2220301.69 17464026916.32        5975.99
-07                         &mm->mmap_sem-R:            37            100           1.31      299502.61      325629.52        3256.30         212344       34316685           0.10        7744.91    95016910.20           2.77
-08                         ---------------
-09                           &mm->mmap_sem              1          [<ffffffff811502a7>] khugepaged_scan_mm_slot+0x57/0x280
-19                           &mm->mmap_sem             96          [<ffffffff815351c4>] __do_page_fault+0x1d4/0x510
-11                           &mm->mmap_sem             34          [<ffffffff81113d77>] vm_mmap_pgoff+0x87/0xd0
-12                           &mm->mmap_sem             17          [<ffffffff81127e71>] vm_munmap+0x41/0x80
-13                         ---------------
-14                           &mm->mmap_sem              1          [<ffffffff81046fda>] dup_mmap+0x2a/0x3f0
-15                           &mm->mmap_sem             60          [<ffffffff81129e29>] SyS_mprotect+0xe9/0x250
-16                           &mm->mmap_sem             41          [<ffffffff815351c4>] __do_page_fault+0x1d4/0x510
-17                           &mm->mmap_sem             68          [<ffffffff81113d77>] vm_mmap_pgoff+0x87/0xd0
-18
-19.............................................................................................................................................................................................................................
-20
-21                         unix_table_lock:           110            112           0.21          49.24         163.91           1.46          21094          66312           0.12         624.42       31589.81           0.48
-22                         ---------------
-23                         unix_table_lock             45          [<ffffffff8150ad8e>] unix_create1+0x16e/0x1b0
-24                         unix_table_lock             47          [<ffffffff8150b111>] unix_release_sock+0x31/0x250
-25                         unix_table_lock             15          [<ffffffff8150ca37>] unix_find_other+0x117/0x230
-26                         unix_table_lock              5          [<ffffffff8150a09f>] unix_autobind+0x11f/0x1b0
-27                         ---------------
-28                         unix_table_lock             39          [<ffffffff8150b111>] unix_release_sock+0x31/0x250
-29                         unix_table_lock             49          [<ffffffff8150ad8e>] unix_create1+0x16e/0x1b0
-30                         unix_table_lock             20          [<ffffffff8150ca37>] unix_find_other+0x117/0x230
-31                         unix_table_lock              4          [<ffffffff8150a09f>] unix_autobind+0x11f/0x1b0
-
-
-This excerpt shows the first two lock class statistics. Line 01 shows the
-output version - each time the format changes this will be updated. Line 02-04
-show the header with column descriptions. Lines 05-18 and 20-31 show the actual
-statistics. These statistics come in two parts; the actual stats separated by a
-short separator (line 08, 13) from the contention points.
-
-The first lock (05-18) is a read/write lock, and shows two lines above the
-short separator. The contention points don't match the column descriptors,
-they have two: contentions and [<IP>] symbol. The second set of contention
-points are the points we're contending with.
-
-The integer part of the time values is in us.
-
-Dealing with nested locks, subclasses may appear:
-
-32...........................................................................................................................................................................................................................
-33
-34                               &rq->lock:       13128          13128           0.43         190.53      103881.26           7.91          97454        3453404           0.00         401.11    13224683.11           3.82
-35                               ---------
-36                               &rq->lock          645          [<ffffffff8103bfc4>] task_rq_lock+0x43/0x75
-37                               &rq->lock          297          [<ffffffff8104ba65>] try_to_wake_up+0x127/0x25a
-38                               &rq->lock          360          [<ffffffff8103c4c5>] select_task_rq_fair+0x1f0/0x74a
-39                               &rq->lock          428          [<ffffffff81045f98>] scheduler_tick+0x46/0x1fb
-40                               ---------
-41                               &rq->lock           77          [<ffffffff8103bfc4>] task_rq_lock+0x43/0x75
-42                               &rq->lock          174          [<ffffffff8104ba65>] try_to_wake_up+0x127/0x25a
-43                               &rq->lock         4715          [<ffffffff8103ed4b>] double_rq_lock+0x42/0x54
-44                               &rq->lock          893          [<ffffffff81340524>] schedule+0x157/0x7b8
-45
-46...........................................................................................................................................................................................................................
-47
-48                             &rq->lock/1:        1526          11488           0.33         388.73      136294.31          11.86          21461          38404           0.00          37.93      109388.53           2.84
-49                             -----------
-50                             &rq->lock/1        11526          [<ffffffff8103ed58>] double_rq_lock+0x4f/0x54
-51                             -----------
-52                             &rq->lock/1         5645          [<ffffffff8103ed4b>] double_rq_lock+0x42/0x54
-53                             &rq->lock/1         1224          [<ffffffff81340524>] schedule+0x157/0x7b8
-54                             &rq->lock/1         4336          [<ffffffff8103ed58>] double_rq_lock+0x4f/0x54
-55                             &rq->lock/1          181          [<ffffffff8104ba65>] try_to_wake_up+0x127/0x25a
-
-Line 48 shows statistics for the second subclass (/1) of &rq->lock class
-(subclass starts from 0), since in this case, as line 50 suggests,
-double_rq_lock actually acquires a nested lock of two spinlocks.
-
-View the top contending locks:
-
-# grep : /proc/lock_stat | head
-                       clockevents_lock:       2926159        2947636           0.15       46882.81  1784540466.34         605.41        3381345        3879161           0.00        2260.97    53178395.68          13.71
-                    tick_broadcast_lock:        346460         346717           0.18        2257.43    39364622.71         113.54        3642919        4242696           0.00        2263.79    49173646.60          11.59
-                 &mapping->i_mmap_mutex:        203896         203899           3.36      645530.05 31767507988.39      155800.21        3361776        8893984           0.17        2254.15    14110121.02           1.59
-                              &rq->lock:        135014         136909           0.18         606.09      842160.68           6.15        1540728       10436146           0.00         728.72    17606683.41           1.69
-              &(&zone->lru_lock)->rlock:         93000          94934           0.16          59.18      188253.78           1.98        1199912        3809894           0.15         391.40     3559518.81           0.93
-                        tasklist_lock-W:         40667          41130           0.23        1189.42      428980.51          10.43         270278         510106           0.16         653.51     3939674.91           7.72
-                        tasklist_lock-R:         21298          21305           0.20        1310.05      215511.12          10.12         186204         241258           0.14        1162.33     1179779.23           4.89
-                             rcu_node_1:         47656          49022           0.16         635.41      193616.41           3.95         844888        1865423           0.00         764.26     1656226.96           0.89
-       &(&dentry->d_lockref.lock)->rlock:         39791          40179           0.15        1302.08       88851.96           2.21        2790851       12527025           0.10        1910.75     3379714.27           0.27
-                             rcu_node_0:         29203          30064           0.16         786.55     1555573.00          51.74          88963         244254           0.00         398.87      428872.51           1.76
-
-Clear the statistics:
-
-# echo 0 > /proc/lock_stat
index a4de88fb55f087451cf97955a6ab419b74935c4e..22a969cdd4766a2f4f3651d359cd81defdb3bd21 100644 (file)
@@ -574,30 +574,14 @@ However, stores are not speculated.  This means that ordering -is- provided
 in the following example:
 
        q = ACCESS_ONCE(a);
-       if (ACCESS_ONCE(q)) {
-               ACCESS_ONCE(b) = p;
-       }
-
-Please note that ACCESS_ONCE() is not optional!  Without the ACCESS_ONCE(),
-the compiler is within its rights to transform this example:
-
-       q = a;
        if (q) {
-               b = p;  /* BUG: Compiler can reorder!!! */
-               do_something();
-       } else {
-               b = p;  /* BUG: Compiler can reorder!!! */
-               do_something_else();
+               ACCESS_ONCE(b) = p;
        }
 
-into this, which of course defeats the ordering:
-
-       b = p;
-       q = a;
-       if (q)
-               do_something();
-       else
-               do_something_else();
+Please note that ACCESS_ONCE() is not optional!  Without the
+ACCESS_ONCE(), might combine the load from 'a' with other loads from
+'a', and the store to 'b' with other stores to 'b', with possible highly
+counterintuitive effects on ordering.
 
 Worse yet, if the compiler is able to prove (say) that the value of
 variable 'a' is always non-zero, it would be well within its rights
@@ -605,11 +589,12 @@ to optimize the original example by eliminating the "if" statement
 as follows:
 
        q = a;
-       b = p;  /* BUG: Compiler can reorder!!! */
-       do_something();
+       b = p;  /* BUG: Compiler and CPU can both reorder!!! */
+
+So don't leave out the ACCESS_ONCE().
 
-The solution is again ACCESS_ONCE() and barrier(), which preserves the
-ordering between the load from variable 'a' and the store to variable 'b':
+It is tempting to try to enforce ordering on identical stores on both
+branches of the "if" statement as follows:
 
        q = ACCESS_ONCE(a);
        if (q) {
@@ -622,18 +607,11 @@ ordering between the load from variable 'a' and the store to variable 'b':
                do_something_else();
        }
 
-The initial ACCESS_ONCE() is required to prevent the compiler from
-proving the value of 'a', and the pair of barrier() invocations are
-required to prevent the compiler from pulling the two identical stores
-to 'b' out from the legs of the "if" statement.
-
-It is important to note that control dependencies absolutely require a
-a conditional.  For example, the following "optimized" version of
-the above example breaks ordering, which is why the barrier() invocations
-are absolutely required if you have identical stores in both legs of
-the "if" statement:
+Unfortunately, current compilers will transform this as follows at high
+optimization levels:
 
        q = ACCESS_ONCE(a);
+       barrier();
        ACCESS_ONCE(b) = p;  /* BUG: No ordering vs. load from a!!! */
        if (q) {
                /* ACCESS_ONCE(b) = p; -- moved up, BUG!!! */
@@ -643,21 +621,36 @@ the "if" statement:
                do_something_else();
        }
 
-It is of course legal for the prior load to be part of the conditional,
-for example, as follows:
+Now there is no conditional between the load from 'a' and the store to
+'b', which means that the CPU is within its rights to reorder them:
+The conditional is absolutely required, and must be present in the
+assembly code even after all compiler optimizations have been applied.
+Therefore, if you need ordering in this example, you need explicit
+memory barriers, for example, smp_store_release():
 
-       if (ACCESS_ONCE(a) > 0) {
-               barrier();
-               ACCESS_ONCE(b) = q / 2;
+       q = ACCESS_ONCE(a);
+       if (q) {
+               smp_store_release(&b, p);
                do_something();
        } else {
-               barrier();
-               ACCESS_ONCE(b) = q / 3;
+               smp_store_release(&b, p);
+               do_something_else();
+       }
+
+In contrast, without explicit memory barriers, two-legged-if control
+ordering is guaranteed only when the stores differ, for example:
+
+       q = ACCESS_ONCE(a);
+       if (q) {
+               ACCESS_ONCE(b) = p;
+               do_something();
+       } else {
+               ACCESS_ONCE(b) = r;
                do_something_else();
        }
 
-This will again ensure that the load from variable 'a' is ordered before the
-stores to variable 'b'.
+The initial ACCESS_ONCE() is still required to prevent the compiler from
+proving the value of 'a'.
 
 In addition, you need to be careful what you do with the local variable 'q',
 otherwise the compiler might be able to guess the value and again remove
@@ -665,12 +658,10 @@ the needed conditional.  For example:
 
        q = ACCESS_ONCE(a);
        if (q % MAX) {
-               barrier();
                ACCESS_ONCE(b) = p;
                do_something();
        } else {
-               barrier();
-               ACCESS_ONCE(b) = p;
+               ACCESS_ONCE(b) = r;
                do_something_else();
        }
 
@@ -682,9 +673,12 @@ transform the above code into the following:
        ACCESS_ONCE(b) = p;
        do_something_else();
 
-This transformation loses the ordering between the load from variable 'a'
-and the store to variable 'b'.  If you are relying on this ordering, you
-should do something like the following:
+Given this transformation, the CPU is not required to respect the ordering
+between the load from variable 'a' and the store to variable 'b'.  It is
+tempting to add a barrier(), but this does not help.  The conditional
+is gone, and the barrier won't bring it back.  Therefore, if you are
+relying on this ordering, you should make sure that MAX is greater than
+one, perhaps as follows:
 
        q = ACCESS_ONCE(a);
        BUILD_BUG_ON(MAX <= 1); /* Order load from a with store to b. */
@@ -692,35 +686,45 @@ should do something like the following:
                ACCESS_ONCE(b) = p;
                do_something();
        } else {
-               ACCESS_ONCE(b) = p;
+               ACCESS_ONCE(b) = r;
                do_something_else();
        }
 
+Please note once again that the stores to 'b' differ.  If they were
+identical, as noted earlier, the compiler could pull this store outside
+of the 'if' statement.
+
 Finally, control dependencies do -not- provide transitivity.  This is
-demonstrated by two related examples:
+demonstrated by two related examples, with the initial values of
+x and y both being zero:
 
        CPU 0                     CPU 1
        =====================     =====================
        r1 = ACCESS_ONCE(x);      r2 = ACCESS_ONCE(y);
-       if (r1 >= 0)              if (r2 >= 0)
+       if (r1 > 0)               if (r2 > 0)
          ACCESS_ONCE(y) = 1;       ACCESS_ONCE(x) = 1;
 
        assert(!(r1 == 1 && r2 == 1));
 
 The above two-CPU example will never trigger the assert().  However,
 if control dependencies guaranteed transitivity (which they do not),
-then adding the following two CPUs would guarantee a related assertion:
+then adding the following CPU would guarantee a related assertion:
 
-       CPU 2                     CPU 3
-       =====================     =====================
-       ACCESS_ONCE(x) = 2;       ACCESS_ONCE(y) = 2;
+       CPU 2
+       =====================
+       ACCESS_ONCE(x) = 2;
+
+       assert(!(r1 == 2 && r2 == 1 && x == 2)); /* FAILS!!! */
 
-       assert(!(r1 == 2 && r2 == 2 && x == 1 && y == 1)); /* FAILS!!! */
+But because control dependencies do -not- provide transitivity, the above
+assertion can fail after the combined three-CPU example completes.  If you
+need the three-CPU example to provide ordering, you will need smp_mb()
+between the loads and stores in the CPU 0 and CPU 1 code fragments,
+that is, just before or just after the "if" statements.
 
-But because control dependencies do -not- provide transitivity, the
-above assertion can fail after the combined four-CPU example completes.
-If you need the four-CPU example to provide ordering, you will need
-smp_mb() between the loads and stores in the CPU 0 and CPU 1 code fragments.
+These two examples are the LB and WWC litmus tests from this paper:
+http://www.cl.cam.ac.uk/users/pes20/ppc-supplemental/test6.pdf and this
+site: https://www.cl.cam.ac.uk/~pes20/ppcmem/index.html.
 
 In summary:
 
diff --git a/Documentation/mutex-design.txt b/Documentation/mutex-design.txt
deleted file mode 100644 (file)
index ee231ed..0000000
+++ /dev/null
@@ -1,157 +0,0 @@
-Generic Mutex Subsystem
-
-started by Ingo Molnar <mingo@redhat.com>
-updated by Davidlohr Bueso <davidlohr@hp.com>
-
-What are mutexes?
------------------
-
-In the Linux kernel, mutexes refer to a particular locking primitive
-that enforces serialization on shared memory systems, and not only to
-the generic term referring to 'mutual exclusion' found in academia
-or similar theoretical text books. Mutexes are sleeping locks which
-behave similarly to binary semaphores, and were introduced in 2006[1]
-as an alternative to these. This new data structure provided a number
-of advantages, including simpler interfaces, and at that time smaller
-code (see Disadvantages).
-
-[1] http://lwn.net/Articles/164802/
-
-Implementation
---------------
-
-Mutexes are represented by 'struct mutex', defined in include/linux/mutex.h
-and implemented in kernel/locking/mutex.c. These locks use a three
-state atomic counter (->count) to represent the different possible
-transitions that can occur during the lifetime of a lock:
-
-         1: unlocked
-         0: locked, no waiters
-   negative: locked, with potential waiters
-
-In its most basic form it also includes a wait-queue and a spinlock
-that serializes access to it. CONFIG_SMP systems can also include
-a pointer to the lock task owner (->owner) as well as a spinner MCS
-lock (->osq), both described below in (ii).
-
-When acquiring a mutex, there are three possible paths that can be
-taken, depending on the state of the lock:
-
-(i) fastpath: tries to atomically acquire the lock by decrementing the
-    counter. If it was already taken by another task it goes to the next
-    possible path. This logic is architecture specific. On x86-64, the
-    locking fastpath is 2 instructions:
-
-    0000000000000e10 <mutex_lock>:
-    e21:   f0 ff 0b                lock decl (%rbx)
-    e24:   79 08                   jns    e2e <mutex_lock+0x1e>
-
-   the unlocking fastpath is equally tight:
-
-    0000000000000bc0 <mutex_unlock>:
-    bc8:   f0 ff 07                lock incl (%rdi)
-    bcb:   7f 0a                   jg     bd7 <mutex_unlock+0x17>
-
-
-(ii) midpath: aka optimistic spinning, tries to spin for acquisition
-     while the lock owner is running and there are no other tasks ready
-     to run that have higher priority (need_resched). The rationale is
-     that if the lock owner is running, it is likely to release the lock
-     soon. The mutex spinners are queued up using MCS lock so that only
-     one spinner can compete for the mutex.
-
-     The MCS lock (proposed by Mellor-Crummey and Scott) is a simple spinlock
-     with the desirable properties of being fair and with each cpu trying
-     to acquire the lock spinning on a local variable. It avoids expensive
-     cacheline bouncing that common test-and-set spinlock implementations
-     incur. An MCS-like lock is specially tailored for optimistic spinning
-     for sleeping lock implementation. An important feature of the customized
-     MCS lock is that it has the extra property that spinners are able to exit
-     the MCS spinlock queue when they need to reschedule. This further helps
-     avoid situations where MCS spinners that need to reschedule would continue
-     waiting to spin on mutex owner, only to go directly to slowpath upon
-     obtaining the MCS lock.
-
-
-(iii) slowpath: last resort, if the lock is still unable to be acquired,
-      the task is added to the wait-queue and sleeps until woken up by the
-      unlock path. Under normal circumstances it blocks as TASK_UNINTERRUPTIBLE.
-
-While formally kernel mutexes are sleepable locks, it is path (ii) that
-makes them more practically a hybrid type. By simply not interrupting a
-task and busy-waiting for a few cycles instead of immediately sleeping,
-the performance of this lock has been seen to significantly improve a
-number of workloads. Note that this technique is also used for rw-semaphores.
-
-Semantics
----------
-
-The mutex subsystem checks and enforces the following rules:
-
-    - Only one task can hold the mutex at a time.
-    - Only the owner can unlock the mutex.
-    - Multiple unlocks are not permitted.
-    - Recursive locking/unlocking is not permitted.
-    - A mutex must only be initialized via the API (see below).
-    - A task may not exit with a mutex held.
-    - Memory areas where held locks reside must not be freed.
-    - Held mutexes must not be reinitialized.
-    - Mutexes may not be used in hardware or software interrupt
-      contexts such as tasklets and timers.
-
-These semantics are fully enforced when CONFIG DEBUG_MUTEXES is enabled.
-In addition, the mutex debugging code also implements a number of other
-features that make lock debugging easier and faster:
-
-    - Uses symbolic names of mutexes, whenever they are printed
-      in debug output.
-    - Point-of-acquire tracking, symbolic lookup of function names,
-      list of all locks held in the system, printout of them.
-    - Owner tracking.
-    - Detects self-recursing locks and prints out all relevant info.
-    - Detects multi-task circular deadlocks and prints out all affected
-      locks and tasks (and only those tasks).
-
-
-Interfaces
-----------
-Statically define the mutex:
-   DEFINE_MUTEX(name);
-
-Dynamically initialize the mutex:
-   mutex_init(mutex);
-
-Acquire the mutex, uninterruptible:
-   void mutex_lock(struct mutex *lock);
-   void mutex_lock_nested(struct mutex *lock, unsigned int subclass);
-   int  mutex_trylock(struct mutex *lock);
-
-Acquire the mutex, interruptible:
-   int mutex_lock_interruptible_nested(struct mutex *lock,
-                                      unsigned int subclass);
-   int mutex_lock_interruptible(struct mutex *lock);
-
-Acquire the mutex, interruptible, if dec to 0:
-   int atomic_dec_and_mutex_lock(atomic_t *cnt, struct mutex *lock);
-
-Unlock the mutex:
-   void mutex_unlock(struct mutex *lock);
-
-Test if the mutex is taken:
-   int mutex_is_locked(struct mutex *lock);
-
-Disadvantages
--------------
-
-Unlike its original design and purpose, 'struct mutex' is larger than
-most locks in the kernel. E.g: on x86-64 it is 40 bytes, almost twice
-as large as 'struct semaphore' (24 bytes) and 8 bytes shy of the
-'struct rw_semaphore' variant. Larger structure sizes mean more CPU
-cache and memory footprint.
-
-When to use mutexes
--------------------
-
-Unless the strict semantics of mutexes are unsuitable and/or the critical
-region prevents the lock from being shared, always prefer them to any other
-locking primitive.
index b1935f9ce081237634e67cfd8ea39012e7ccd6a3..58d08f8d8d8025dbe83481daa0fe76889216910e 100644 (file)
@@ -700,11 +700,11 @@ Some core changes of the new internal format:
     bpf_exit
 
   If f2 is JITed and the pointer stored to '_f2'. The calls f1 -> f2 -> f3 and
-  returns will be seamless. Without JIT, __sk_run_filter() interpreter needs to
+  returns will be seamless. Without JIT, __bpf_prog_run() interpreter needs to
   be used to call into f2.
 
   For practical reasons all eBPF programs have only one argument 'ctx' which is
-  already placed into R1 (e.g. on __sk_run_filter() startup) and the programs
+  already placed into R1 (e.g. on __bpf_prog_run() startup) and the programs
   can call kernel functions with up to 5 arguments. Calls with 6 or more arguments
   are currently not supported, but these restrictions can be lifted if necessary
   in the future.
index a68784d0a1ee1a99c432d1dd984c1f9bf9ae7406..6fd0e8bb814097233280897b9916190a429eda22 100644 (file)
@@ -11,6 +11,8 @@ bootwrapper.txt
 cpu_features.txt
        - info on how we support a variety of CPUs with minimal compile-time
        options.
+cxl.txt
+       - Overview of the CXL driver.
 eeh-pci-error-recovery.txt
        - info on PCI Bus EEH Error Recovery
 firmware-assisted-dump.txt
diff --git a/Documentation/powerpc/cxl.txt b/Documentation/powerpc/cxl.txt
new file mode 100644 (file)
index 0000000..2c71ecc
--- /dev/null
@@ -0,0 +1,379 @@
+Coherent Accelerator Interface (CXL)
+====================================
+
+Introduction
+============
+
+    The coherent accelerator interface is designed to allow the
+    coherent connection of accelerators (FPGAs and other devices) to a
+    POWER system. These devices need to adhere to the Coherent
+    Accelerator Interface Architecture (CAIA).
+
+    IBM refers to this as the Coherent Accelerator Processor Interface
+    or CAPI. In the kernel it's referred to by the name CXL to avoid
+    confusion with the ISDN CAPI subsystem.
+
+    Coherent in this context means that the accelerator and CPUs can
+    both access system memory directly and with the same effective
+    addresses.
+
+
+Hardware overview
+=================
+
+          POWER8               FPGA
+       +----------+        +---------+
+       |          |        |         |
+       |   CPU    |        |   AFU   |
+       |          |        |         |
+       |          |        |         |
+       |          |        |         |
+       +----------+        +---------+
+       |   PHB    |        |         |
+       |   +------+        |   PSL   |
+       |   | CAPP |<------>|         |
+       +---+------+  PCIE  +---------+
+
+    The POWER8 chip has a Coherently Attached Processor Proxy (CAPP)
+    unit which is part of the PCIe Host Bridge (PHB). This is managed
+    by Linux by calls into OPAL. Linux doesn't directly program the
+    CAPP.
+
+    The FPGA (or coherently attached device) consists of two parts.
+    The POWER Service Layer (PSL) and the Accelerator Function Unit
+    (AFU). The AFU is used to implement specific functionality behind
+    the PSL. The PSL, among other things, provides memory address
+    translation services to allow each AFU direct access to userspace
+    memory.
+
+    The AFU is the core part of the accelerator (eg. the compression,
+    crypto etc function). The kernel has no knowledge of the function
+    of the AFU. Only userspace interacts directly with the AFU.
+
+    The PSL provides the translation and interrupt services that the
+    AFU needs. This is what the kernel interacts with. For example, if
+    the AFU needs to read a particular effective address, it sends
+    that address to the PSL, the PSL then translates it, fetches the
+    data from memory and returns it to the AFU. If the PSL has a
+    translation miss, it interrupts the kernel and the kernel services
+    the fault. The context to which this fault is serviced is based on
+    who owns that acceleration function.
+
+
+AFU Modes
+=========
+
+    There are two programming modes supported by the AFU. Dedicated
+    and AFU directed. AFU may support one or both modes.
+
+    When using dedicated mode only one MMU context is supported. In
+    this mode, only one userspace process can use the accelerator at
+    time.
+
+    When using AFU directed mode, up to 16K simultaneous contexts can
+    be supported. This means up to 16K simultaneous userspace
+    applications may use the accelerator (although specific AFUs may
+    support fewer). In this mode, the AFU sends a 16 bit context ID
+    with each of its requests. This tells the PSL which context is
+    associated with each operation. If the PSL can't translate an
+    operation, the ID can also be accessed by the kernel so it can
+    determine the userspace context associated with an operation.
+
+
+MMIO space
+==========
+
+    A portion of the accelerator MMIO space can be directly mapped
+    from the AFU to userspace. Either the whole space can be mapped or
+    just a per context portion. The hardware is self describing, hence
+    the kernel can determine the offset and size of the per context
+    portion.
+
+
+Interrupts
+==========
+
+    AFUs may generate interrupts that are destined for userspace. These
+    are received by the kernel as hardware interrupts and passed onto
+    userspace by a read syscall documented below.
+
+    Data storage faults and error interrupts are handled by the kernel
+    driver.
+
+
+Work Element Descriptor (WED)
+=============================
+
+    The WED is a 64-bit parameter passed to the AFU when a context is
+    started. Its format is up to the AFU hence the kernel has no
+    knowledge of what it represents. Typically it will be the
+    effective address of a work queue or status block where the AFU
+    and userspace can share control and status information.
+
+
+
+
+User API
+========
+
+    For AFUs operating in AFU directed mode, two character device
+    files will be created. /dev/cxl/afu0.0m will correspond to a
+    master context and /dev/cxl/afu0.0s will correspond to a slave
+    context. Master contexts have access to the full MMIO space an
+    AFU provides. Slave contexts have access to only the per process
+    MMIO space an AFU provides.
+
+    For AFUs operating in dedicated process mode, the driver will
+    only create a single character device per AFU called
+    /dev/cxl/afu0.0d. This will have access to the entire MMIO space
+    that the AFU provides (like master contexts in AFU directed).
+
+    The types described below are defined in include/uapi/misc/cxl.h
+
+    The following file operations are supported on both slave and
+    master devices.
+
+
+open
+----
+
+    Opens the device and allocates a file descriptor to be used with
+    the rest of the API.
+
+    A dedicated mode AFU only has one context and only allows the
+    device to be opened once.
+
+    An AFU directed mode AFU can have many contexts, the device can be
+    opened once for each context that is available.
+
+    When all available contexts are allocated the open call will fail
+    and return -ENOSPC.
+
+    Note: IRQs need to be allocated for each context, which may limit
+          the number of contexts that can be created, and therefore
+          how many times the device can be opened. The POWER8 CAPP
+          supports 2040 IRQs and 3 are used by the kernel, so 2037 are
+          left. If 1 IRQ is needed per context, then only 2037
+          contexts can be allocated. If 4 IRQs are needed per context,
+          then only 2037/4 = 509 contexts can be allocated.
+
+
+ioctl
+-----
+
+    CXL_IOCTL_START_WORK:
+        Starts the AFU context and associates it with the current
+        process. Once this ioctl is successfully executed, all memory
+        mapped into this process is accessible to this AFU context
+        using the same effective addresses. No additional calls are
+        required to map/unmap memory. The AFU memory context will be
+        updated as userspace allocates and frees memory. This ioctl
+        returns once the AFU context is started.
+
+        Takes a pointer to a struct cxl_ioctl_start_work:
+
+                struct cxl_ioctl_start_work {
+                        __u64 flags;
+                        __u64 work_element_descriptor;
+                        __u64 amr;
+                        __s16 num_interrupts;
+                        __s16 reserved1;
+                        __s32 reserved2;
+                        __u64 reserved3;
+                        __u64 reserved4;
+                        __u64 reserved5;
+                        __u64 reserved6;
+                };
+
+            flags:
+                Indicates which optional fields in the structure are
+                valid.
+
+            work_element_descriptor:
+                The Work Element Descriptor (WED) is a 64-bit argument
+                defined by the AFU. Typically this is an effective
+                address pointing to an AFU specific structure
+                describing what work to perform.
+
+            amr:
+                Authority Mask Register (AMR), same as the powerpc
+                AMR. This field is only used by the kernel when the
+                corresponding CXL_START_WORK_AMR value is specified in
+                flags. If not specified the kernel will use a default
+                value of 0.
+
+            num_interrupts:
+                Number of userspace interrupts to request. This field
+                is only used by the kernel when the corresponding
+                CXL_START_WORK_NUM_IRQS value is specified in flags.
+                If not specified the minimum number required by the
+                AFU will be allocated. The min and max number can be
+                obtained from sysfs.
+
+            reserved fields:
+                For ABI padding and future extensions
+
+    CXL_IOCTL_GET_PROCESS_ELEMENT:
+        Get the current context id, also known as the process element.
+        The value is returned from the kernel as a __u32.
+
+
+mmap
+----
+
+    An AFU may have an MMIO space to facilitate communication with the
+    AFU. If it does, the MMIO space can be accessed via mmap. The size
+    and contents of this area are specific to the particular AFU. The
+    size can be discovered via sysfs.
+
+    In AFU directed mode, master contexts are allowed to map all of
+    the MMIO space and slave contexts are allowed to only map the per
+    process MMIO space associated with the context. In dedicated
+    process mode the entire MMIO space can always be mapped.
+
+    This mmap call must be done after the START_WORK ioctl.
+
+    Care should be taken when accessing MMIO space. Only 32 and 64-bit
+    accesses are supported by POWER8. Also, the AFU will be designed
+    with a specific endianness, so all MMIO accesses should consider
+    endianness (recommend endian(3) variants like: le64toh(),
+    be64toh() etc). These endian issues equally apply to shared memory
+    queues the WED may describe.
+
+
+read
+----
+
+    Reads events from the AFU. Blocks if no events are pending
+    (unless O_NONBLOCK is supplied). Returns -EIO in the case of an
+    unrecoverable error or if the card is removed.
+
+    read() will always return an integral number of events.
+
+    The buffer passed to read() must be at least 4K bytes.
+
+    The result of the read will be a buffer of one or more events,
+    each event is of type struct cxl_event, of varying size.
+
+            struct cxl_event {
+                    struct cxl_event_header header;
+                    union {
+                            struct cxl_event_afu_interrupt irq;
+                            struct cxl_event_data_storage fault;
+                            struct cxl_event_afu_error afu_error;
+                    };
+            };
+
+    The struct cxl_event_header is defined as:
+
+            struct cxl_event_header {
+                    __u16 type;
+                    __u16 size;
+                    __u16 process_element;
+                    __u16 reserved1;
+            };
+
+        type:
+            This defines the type of event. The type determines how
+            the rest of the event is structured. These types are
+            described below and defined by enum cxl_event_type.
+
+        size:
+            This is the size of the event in bytes including the
+            struct cxl_event_header. The start of the next event can
+            be found at this offset from the start of the current
+            event.
+
+        process_element:
+            Context ID of the event.
+
+        reserved field:
+            For future extensions and padding.
+
+    If the event type is CXL_EVENT_AFU_INTERRUPT then the event
+    structure is defined as:
+
+            struct cxl_event_afu_interrupt {
+                    __u16 flags;
+                    __u16 irq; /* Raised AFU interrupt number */
+                    __u32 reserved1;
+            };
+
+        flags:
+            These flags indicate which optional fields are present
+            in this struct. Currently all fields are mandatory.
+
+        irq:
+            The IRQ number sent by the AFU.
+
+        reserved field:
+            For future extensions and padding.
+
+    If the event type is CXL_EVENT_DATA_STORAGE then the event
+    structure is defined as:
+
+            struct cxl_event_data_storage {
+                    __u16 flags;
+                    __u16 reserved1;
+                    __u32 reserved2;
+                    __u64 addr;
+                    __u64 dsisr;
+                    __u64 reserved3;
+            };
+
+        flags:
+            These flags indicate which optional fields are present in
+            this struct. Currently all fields are mandatory.
+
+        address:
+            The address that the AFU unsuccessfully attempted to
+            access. Valid accesses will be handled transparently by the
+            kernel but invalid accesses will generate this event.
+
+        dsisr:
+            This field gives information on the type of fault. It is a
+            copy of the DSISR from the PSL hardware when the address
+            fault occurred. The form of the DSISR is as defined in the
+            CAIA.
+
+        reserved fields:
+            For future extensions
+
+    If the event type is CXL_EVENT_AFU_ERROR then the event structure
+    is defined as:
+
+            struct cxl_event_afu_error {
+                    __u16 flags;
+                    __u16 reserved1;
+                    __u32 reserved2;
+                    __u64 error;
+            };
+
+        flags:
+            These flags indicate which optional fields are present in
+            this struct. Currently all fields are Mandatory.
+
+        error:
+            Error status from the AFU. Defined by the AFU.
+
+        reserved fields:
+            For future extensions and padding
+
+Sysfs Class
+===========
+
+    A cxl sysfs class is added under /sys/class/cxl to facilitate
+    enumeration and tuning of the accelerators. Its layout is
+    described in Documentation/ABI/testing/sysfs-class-cxl
+
+Udev rules
+==========
+
+    The following udev rules could be used to create a symlink to the
+    most logical chardev to use in any programming mode (afuX.Yd for
+    dedicated, afuX.Ys for afu directed), since the API is virtually
+    identical for each:
+
+       SUBSYSTEM=="cxl", ATTRS{mode}=="dedicated_process", SYMLINK="cxl/%b"
+       SUBSYSTEM=="cxl", ATTRS{mode}=="afu_directed", \
+                         KERNEL=="afu[0-9]*.[0-9]*s", SYMLINK="cxl/%b"
index b4498218c4744213bbe57609c7532fa4bd64bd54..5a615c14f75da79133db306179ccdd355bb0b4c4 100644 (file)
@@ -70,6 +70,38 @@ DMA addresses types dma_addr_t:
        For printing a dma_addr_t type which can vary based on build options,
        regardless of the width of the CPU data path. Passed by reference.
 
+Raw buffer as an escaped string:
+
+       %*pE[achnops]
+
+       For printing raw buffer as an escaped string. For the following buffer
+
+               1b 62 20 5c 43 07 22 90 0d 5d
+
+       few examples show how the conversion would be done (the result string
+       without surrounding quotes):
+
+               %*pE            "\eb \C\a"\220\r]"
+               %*pEhp          "\x1bb \C\x07"\x90\x0d]"
+               %*pEa           "\e\142\040\\\103\a\042\220\r\135"
+
+       The conversion rules are applied according to an optional combination
+       of flags (see string_escape_mem() kernel documentation for the
+       details):
+               a - ESCAPE_ANY
+               c - ESCAPE_SPECIAL
+               h - ESCAPE_HEX
+               n - ESCAPE_NULL
+               o - ESCAPE_OCTAL
+               p - ESCAPE_NP
+               s - ESCAPE_SPACE
+       By default ESCAPE_ANY_NP is used.
+
+       ESCAPE_ANY_NP is the sane choice for many cases, in particularly for
+       printing SSIDs.
+
+       If field width is omitted the 1 byte only will be escaped.
+
 Raw buffer as a hex string:
        %*ph    00 01 02  ...  3f
        %*phC   00:01:02: ... :3f
diff --git a/Documentation/rt-mutex-design.txt b/Documentation/rt-mutex-design.txt
deleted file mode 100644 (file)
index 8666070..0000000
+++ /dev/null
@@ -1,781 +0,0 @@
-#
-# Copyright (c) 2006 Steven Rostedt
-# Licensed under the GNU Free Documentation License, Version 1.2
-#
-
-RT-mutex implementation design
-------------------------------
-
-This document tries to describe the design of the rtmutex.c implementation.
-It doesn't describe the reasons why rtmutex.c exists. For that please see
-Documentation/rt-mutex.txt.  Although this document does explain problems
-that happen without this code, but that is in the concept to understand
-what the code actually is doing.
-
-The goal of this document is to help others understand the priority
-inheritance (PI) algorithm that is used, as well as reasons for the
-decisions that were made to implement PI in the manner that was done.
-
-
-Unbounded Priority Inversion
-----------------------------
-
-Priority inversion is when a lower priority process executes while a higher
-priority process wants to run.  This happens for several reasons, and
-most of the time it can't be helped.  Anytime a high priority process wants
-to use a resource that a lower priority process has (a mutex for example),
-the high priority process must wait until the lower priority process is done
-with the resource.  This is a priority inversion.  What we want to prevent
-is something called unbounded priority inversion.  That is when the high
-priority process is prevented from running by a lower priority process for
-an undetermined amount of time.
-
-The classic example of unbounded priority inversion is where you have three
-processes, let's call them processes A, B, and C, where A is the highest
-priority process, C is the lowest, and B is in between. A tries to grab a lock
-that C owns and must wait and lets C run to release the lock. But in the
-meantime, B executes, and since B is of a higher priority than C, it preempts C,
-but by doing so, it is in fact preempting A which is a higher priority process.
-Now there's no way of knowing how long A will be sleeping waiting for C
-to release the lock, because for all we know, B is a CPU hog and will
-never give C a chance to release the lock.  This is called unbounded priority
-inversion.
-
-Here's a little ASCII art to show the problem.
-
-   grab lock L1 (owned by C)
-     |
-A ---+
-        C preempted by B
-          |
-C    +----+
-
-B         +-------->
-                B now keeps A from running.
-
-
-Priority Inheritance (PI)
--------------------------
-
-There are several ways to solve this issue, but other ways are out of scope
-for this document.  Here we only discuss PI.
-
-PI is where a process inherits the priority of another process if the other
-process blocks on a lock owned by the current process.  To make this easier
-to understand, let's use the previous example, with processes A, B, and C again.
-
-This time, when A blocks on the lock owned by C, C would inherit the priority
-of A.  So now if B becomes runnable, it would not preempt C, since C now has
-the high priority of A.  As soon as C releases the lock, it loses its
-inherited priority, and A then can continue with the resource that C had.
-
-Terminology
------------
-
-Here I explain some terminology that is used in this document to help describe
-the design that is used to implement PI.
-
-PI chain - The PI chain is an ordered series of locks and processes that cause
-           processes to inherit priorities from a previous process that is
-           blocked on one of its locks.  This is described in more detail
-           later in this document.
-
-mutex    - In this document, to differentiate from locks that implement
-           PI and spin locks that are used in the PI code, from now on
-           the PI locks will be called a mutex.
-
-lock     - In this document from now on, I will use the term lock when
-           referring to spin locks that are used to protect parts of the PI
-           algorithm.  These locks disable preemption for UP (when
-           CONFIG_PREEMPT is enabled) and on SMP prevents multiple CPUs from
-           entering critical sections simultaneously.
-
-spin lock - Same as lock above.
-
-waiter   - A waiter is a struct that is stored on the stack of a blocked
-           process.  Since the scope of the waiter is within the code for
-           a process being blocked on the mutex, it is fine to allocate
-           the waiter on the process's stack (local variable).  This
-           structure holds a pointer to the task, as well as the mutex that
-           the task is blocked on.  It also has the plist node structures to
-           place the task in the waiter_list of a mutex as well as the
-           pi_list of a mutex owner task (described below).
-
-           waiter is sometimes used in reference to the task that is waiting
-           on a mutex. This is the same as waiter->task.
-
-waiters  - A list of processes that are blocked on a mutex.
-
-top waiter - The highest priority process waiting on a specific mutex.
-
-top pi waiter - The highest priority process waiting on one of the mutexes
-                that a specific process owns.
-
-Note:  task and process are used interchangeably in this document, mostly to
-       differentiate between two processes that are being described together.
-
-
-PI chain
---------
-
-The PI chain is a list of processes and mutexes that may cause priority
-inheritance to take place.  Multiple chains may converge, but a chain
-would never diverge, since a process can't be blocked on more than one
-mutex at a time.
-
-Example:
-
-   Process:  A, B, C, D, E
-   Mutexes:  L1, L2, L3, L4
-
-   A owns: L1
-           B blocked on L1
-           B owns L2
-                  C blocked on L2
-                  C owns L3
-                         D blocked on L3
-                         D owns L4
-                                E blocked on L4
-
-The chain would be:
-
-   E->L4->D->L3->C->L2->B->L1->A
-
-To show where two chains merge, we could add another process F and
-another mutex L5 where B owns L5 and F is blocked on mutex L5.
-
-The chain for F would be:
-
-   F->L5->B->L1->A
-
-Since a process may own more than one mutex, but never be blocked on more than
-one, the chains merge.
-
-Here we show both chains:
-
-   E->L4->D->L3->C->L2-+
-                       |
-                       +->B->L1->A
-                       |
-                 F->L5-+
-
-For PI to work, the processes at the right end of these chains (or we may
-also call it the Top of the chain) must be equal to or higher in priority
-than the processes to the left or below in the chain.
-
-Also since a mutex may have more than one process blocked on it, we can
-have multiple chains merge at mutexes.  If we add another process G that is
-blocked on mutex L2:
-
-  G->L2->B->L1->A
-
-And once again, to show how this can grow I will show the merging chains
-again.
-
-   E->L4->D->L3->C-+
-                   +->L2-+
-                   |     |
-                 G-+     +->B->L1->A
-                         |
-                   F->L5-+
-
-
-Plist
------
-
-Before I go further and talk about how the PI chain is stored through lists
-on both mutexes and processes, I'll explain the plist.  This is similar to
-the struct list_head functionality that is already in the kernel.
-The implementation of plist is out of scope for this document, but it is
-very important to understand what it does.
-
-There are a few differences between plist and list, the most important one
-being that plist is a priority sorted linked list.  This means that the
-priorities of the plist are sorted, such that it takes O(1) to retrieve the
-highest priority item in the list.  Obviously this is useful to store processes
-based on their priorities.
-
-Another difference, which is important for implementation, is that, unlike
-list, the head of the list is a different element than the nodes of a list.
-So the head of the list is declared as struct plist_head and nodes that will
-be added to the list are declared as struct plist_node.
-
-
-Mutex Waiter List
------------------
-
-Every mutex keeps track of all the waiters that are blocked on itself. The mutex
-has a plist to store these waiters by priority.  This list is protected by
-a spin lock that is located in the struct of the mutex. This lock is called
-wait_lock.  Since the modification of the waiter list is never done in
-interrupt context, the wait_lock can be taken without disabling interrupts.
-
-
-Task PI List
-------------
-
-To keep track of the PI chains, each process has its own PI list.  This is
-a list of all top waiters of the mutexes that are owned by the process.
-Note that this list only holds the top waiters and not all waiters that are
-blocked on mutexes owned by the process.
-
-The top of the task's PI list is always the highest priority task that
-is waiting on a mutex that is owned by the task.  So if the task has
-inherited a priority, it will always be the priority of the task that is
-at the top of this list.
-
-This list is stored in the task structure of a process as a plist called
-pi_list.  This list is protected by a spin lock also in the task structure,
-called pi_lock.  This lock may also be taken in interrupt context, so when
-locking the pi_lock, interrupts must be disabled.
-
-
-Depth of the PI Chain
----------------------
-
-The maximum depth of the PI chain is not dynamic, and could actually be
-defined.  But is very complex to figure it out, since it depends on all
-the nesting of mutexes.  Let's look at the example where we have 3 mutexes,
-L1, L2, and L3, and four separate functions func1, func2, func3 and func4.
-The following shows a locking order of L1->L2->L3, but may not actually
-be directly nested that way.
-
-void func1(void)
-{
-       mutex_lock(L1);
-
-       /* do anything */
-
-       mutex_unlock(L1);
-}
-
-void func2(void)
-{
-       mutex_lock(L1);
-       mutex_lock(L2);
-
-       /* do something */
-
-       mutex_unlock(L2);
-       mutex_unlock(L1);
-}
-
-void func3(void)
-{
-       mutex_lock(L2);
-       mutex_lock(L3);
-
-       /* do something else */
-
-       mutex_unlock(L3);
-       mutex_unlock(L2);
-}
-
-void func4(void)
-{
-       mutex_lock(L3);
-
-       /* do something again */
-
-       mutex_unlock(L3);
-}
-
-Now we add 4 processes that run each of these functions separately.
-Processes A, B, C, and D which run functions func1, func2, func3 and func4
-respectively, and such that D runs first and A last.  With D being preempted
-in func4 in the "do something again" area, we have a locking that follows:
-
-D owns L3
-       C blocked on L3
-       C owns L2
-              B blocked on L2
-              B owns L1
-                     A blocked on L1
-
-And thus we have the chain A->L1->B->L2->C->L3->D.
-
-This gives us a PI depth of 4 (four processes), but looking at any of the
-functions individually, it seems as though they only have at most a locking
-depth of two.  So, although the locking depth is defined at compile time,
-it still is very difficult to find the possibilities of that depth.
-
-Now since mutexes can be defined by user-land applications, we don't want a DOS
-type of application that nests large amounts of mutexes to create a large
-PI chain, and have the code holding spin locks while looking at a large
-amount of data.  So to prevent this, the implementation not only implements
-a maximum lock depth, but also only holds at most two different locks at a
-time, as it walks the PI chain.  More about this below.
-
-
-Mutex owner and flags
----------------------
-
-The mutex structure contains a pointer to the owner of the mutex.  If the
-mutex is not owned, this owner is set to NULL.  Since all architectures
-have the task structure on at least a four byte alignment (and if this is
-not true, the rtmutex.c code will be broken!), this allows for the two
-least significant bits to be used as flags.  This part is also described
-in Documentation/rt-mutex.txt, but will also be briefly described here.
-
-Bit 0 is used as the "Pending Owner" flag.  This is described later.
-Bit 1 is used as the "Has Waiters" flags.  This is also described later
-  in more detail, but is set whenever there are waiters on a mutex.
-
-
-cmpxchg Tricks
---------------
-
-Some architectures implement an atomic cmpxchg (Compare and Exchange).  This
-is used (when applicable) to keep the fast path of grabbing and releasing
-mutexes short.
-
-cmpxchg is basically the following function performed atomically:
-
-unsigned long _cmpxchg(unsigned long *A, unsigned long *B, unsigned long *C)
-{
-       unsigned long T = *A;
-       if (*A == *B) {
-               *A = *C;
-       }
-       return T;
-}
-#define cmpxchg(a,b,c) _cmpxchg(&a,&b,&c)
-
-This is really nice to have, since it allows you to only update a variable
-if the variable is what you expect it to be.  You know if it succeeded if
-the return value (the old value of A) is equal to B.
-
-The macro rt_mutex_cmpxchg is used to try to lock and unlock mutexes. If
-the architecture does not support CMPXCHG, then this macro is simply set
-to fail every time.  But if CMPXCHG is supported, then this will
-help out extremely to keep the fast path short.
-
-The use of rt_mutex_cmpxchg with the flags in the owner field help optimize
-the system for architectures that support it.  This will also be explained
-later in this document.
-
-
-Priority adjustments
---------------------
-
-The implementation of the PI code in rtmutex.c has several places that a
-process must adjust its priority.  With the help of the pi_list of a
-process this is rather easy to know what needs to be adjusted.
-
-The functions implementing the task adjustments are rt_mutex_adjust_prio,
-__rt_mutex_adjust_prio (same as the former, but expects the task pi_lock
-to already be taken), rt_mutex_getprio, and rt_mutex_setprio.
-
-rt_mutex_getprio and rt_mutex_setprio are only used in __rt_mutex_adjust_prio.
-
-rt_mutex_getprio returns the priority that the task should have.  Either the
-task's own normal priority, or if a process of a higher priority is waiting on
-a mutex owned by the task, then that higher priority should be returned.
-Since the pi_list of a task holds an order by priority list of all the top
-waiters of all the mutexes that the task owns, rt_mutex_getprio simply needs
-to compare the top pi waiter to its own normal priority, and return the higher
-priority back.
-
-(Note:  if looking at the code, you will notice that the lower number of
-        prio is returned.  This is because the prio field in the task structure
-        is an inverse order of the actual priority.  So a "prio" of 5 is
-        of higher priority than a "prio" of 10.)
-
-__rt_mutex_adjust_prio examines the result of rt_mutex_getprio, and if the
-result does not equal the task's current priority, then rt_mutex_setprio
-is called to adjust the priority of the task to the new priority.
-Note that rt_mutex_setprio is defined in kernel/sched/core.c to implement the
-actual change in priority.
-
-It is interesting to note that __rt_mutex_adjust_prio can either increase
-or decrease the priority of the task.  In the case that a higher priority
-process has just blocked on a mutex owned by the task, __rt_mutex_adjust_prio
-would increase/boost the task's priority.  But if a higher priority task
-were for some reason to leave the mutex (timeout or signal), this same function
-would decrease/unboost the priority of the task.  That is because the pi_list
-always contains the highest priority task that is waiting on a mutex owned
-by the task, so we only need to compare the priority of that top pi waiter
-to the normal priority of the given task.
-
-
-High level overview of the PI chain walk
-----------------------------------------
-
-The PI chain walk is implemented by the function rt_mutex_adjust_prio_chain.
-
-The implementation has gone through several iterations, and has ended up
-with what we believe is the best.  It walks the PI chain by only grabbing
-at most two locks at a time, and is very efficient.
-
-The rt_mutex_adjust_prio_chain can be used either to boost or lower process
-priorities.
-
-rt_mutex_adjust_prio_chain is called with a task to be checked for PI
-(de)boosting (the owner of a mutex that a process is blocking on), a flag to
-check for deadlocking, the mutex that the task owns, and a pointer to a waiter
-that is the process's waiter struct that is blocked on the mutex (although this
-parameter may be NULL for deboosting).
-
-For this explanation, I will not mention deadlock detection. This explanation
-will try to stay at a high level.
-
-When this function is called, there are no locks held.  That also means
-that the state of the owner and lock can change when entered into this function.
-
-Before this function is called, the task has already had rt_mutex_adjust_prio
-performed on it.  This means that the task is set to the priority that it
-should be at, but the plist nodes of the task's waiter have not been updated
-with the new priorities, and that this task may not be in the proper locations
-in the pi_lists and wait_lists that the task is blocked on.  This function
-solves all that.
-
-A loop is entered, where task is the owner to be checked for PI changes that
-was passed by parameter (for the first iteration).  The pi_lock of this task is
-taken to prevent any more changes to the pi_list of the task.  This also
-prevents new tasks from completing the blocking on a mutex that is owned by this
-task.
-
-If the task is not blocked on a mutex then the loop is exited.  We are at
-the top of the PI chain.
-
-A check is now done to see if the original waiter (the process that is blocked
-on the current mutex) is the top pi waiter of the task.  That is, is this
-waiter on the top of the task's pi_list.  If it is not, it either means that
-there is another process higher in priority that is blocked on one of the
-mutexes that the task owns, or that the waiter has just woken up via a signal
-or timeout and has left the PI chain.  In either case, the loop is exited, since
-we don't need to do any more changes to the priority of the current task, or any
-task that owns a mutex that this current task is waiting on.  A priority chain
-walk is only needed when a new top pi waiter is made to a task.
-
-The next check sees if the task's waiter plist node has the priority equal to
-the priority the task is set at.  If they are equal, then we are done with
-the loop.  Remember that the function started with the priority of the
-task adjusted, but the plist nodes that hold the task in other processes
-pi_lists have not been adjusted.
-
-Next, we look at the mutex that the task is blocked on. The mutex's wait_lock
-is taken.  This is done by a spin_trylock, because the locking order of the
-pi_lock and wait_lock goes in the opposite direction. If we fail to grab the
-lock, the pi_lock is released, and we restart the loop.
-
-Now that we have both the pi_lock of the task as well as the wait_lock of
-the mutex the task is blocked on, we update the task's waiter's plist node
-that is located on the mutex's wait_list.
-
-Now we release the pi_lock of the task.
-
-Next the owner of the mutex has its pi_lock taken, so we can update the
-task's entry in the owner's pi_list.  If the task is the highest priority
-process on the mutex's wait_list, then we remove the previous top waiter
-from the owner's pi_list, and replace it with the task.
-
-Note: It is possible that the task was the current top waiter on the mutex,
-      in which case the task is not yet on the pi_list of the waiter.  This
-      is OK, since plist_del does nothing if the plist node is not on any
-      list.
-
-If the task was not the top waiter of the mutex, but it was before we
-did the priority updates, that means we are deboosting/lowering the
-task.  In this case, the task is removed from the pi_list of the owner,
-and the new top waiter is added.
-
-Lastly, we unlock both the pi_lock of the task, as well as the mutex's
-wait_lock, and continue the loop again.  On the next iteration of the
-loop, the previous owner of the mutex will be the task that will be
-processed.
-
-Note: One might think that the owner of this mutex might have changed
-      since we just grab the mutex's wait_lock. And one could be right.
-      The important thing to remember is that the owner could not have
-      become the task that is being processed in the PI chain, since
-      we have taken that task's pi_lock at the beginning of the loop.
-      So as long as there is an owner of this mutex that is not the same
-      process as the tasked being worked on, we are OK.
-
-      Looking closely at the code, one might be confused.  The check for the
-      end of the PI chain is when the task isn't blocked on anything or the
-      task's waiter structure "task" element is NULL.  This check is
-      protected only by the task's pi_lock.  But the code to unlock the mutex
-      sets the task's waiter structure "task" element to NULL with only
-      the protection of the mutex's wait_lock, which was not taken yet.
-      Isn't this a race condition if the task becomes the new owner?
-
-      The answer is No!  The trick is the spin_trylock of the mutex's
-      wait_lock.  If we fail that lock, we release the pi_lock of the
-      task and continue the loop, doing the end of PI chain check again.
-
-      In the code to release the lock, the wait_lock of the mutex is held
-      the entire time, and it is not let go when we grab the pi_lock of the
-      new owner of the mutex.  So if the switch of a new owner were to happen
-      after the check for end of the PI chain and the grabbing of the
-      wait_lock, the unlocking code would spin on the new owner's pi_lock
-      but never give up the wait_lock.  So the PI chain loop is guaranteed to
-      fail the spin_trylock on the wait_lock, release the pi_lock, and
-      try again.
-
-      If you don't quite understand the above, that's OK. You don't have to,
-      unless you really want to make a proof out of it ;)
-
-
-Pending Owners and Lock stealing
---------------------------------
-
-One of the flags in the owner field of the mutex structure is "Pending Owner".
-What this means is that an owner was chosen by the process releasing the
-mutex, but that owner has yet to wake up and actually take the mutex.
-
-Why is this important?  Why can't we just give the mutex to another process
-and be done with it?
-
-The PI code is to help with real-time processes, and to let the highest
-priority process run as long as possible with little latencies and delays.
-If a high priority process owns a mutex that a lower priority process is
-blocked on, when the mutex is released it would be given to the lower priority
-process.  What if the higher priority process wants to take that mutex again.
-The high priority process would fail to take that mutex that it just gave up
-and it would need to boost the lower priority process to run with full
-latency of that critical section (since the low priority process just entered
-it).
-
-There's no reason a high priority process that gives up a mutex should be
-penalized if it tries to take that mutex again.  If the new owner of the
-mutex has not woken up yet, there's no reason that the higher priority process
-could not take that mutex away.
-
-To solve this, we introduced Pending Ownership and Lock Stealing.  When a
-new process is given a mutex that it was blocked on, it is only given
-pending ownership.  This means that it's the new owner, unless a higher
-priority process comes in and tries to grab that mutex.  If a higher priority
-process does come along and wants that mutex, we let the higher priority
-process "steal" the mutex from the pending owner (only if it is still pending)
-and continue with the mutex.
-
-
-Taking of a mutex (The walk through)
-------------------------------------
-
-OK, now let's take a look at the detailed walk through of what happens when
-taking a mutex.
-
-The first thing that is tried is the fast taking of the mutex.  This is
-done when we have CMPXCHG enabled (otherwise the fast taking automatically
-fails).  Only when the owner field of the mutex is NULL can the lock be
-taken with the CMPXCHG and nothing else needs to be done.
-
-If there is contention on the lock, whether it is owned or pending owner
-we go about the slow path (rt_mutex_slowlock).
-
-The slow path function is where the task's waiter structure is created on
-the stack.  This is because the waiter structure is only needed for the
-scope of this function.  The waiter structure holds the nodes to store
-the task on the wait_list of the mutex, and if need be, the pi_list of
-the owner.
-
-The wait_lock of the mutex is taken since the slow path of unlocking the
-mutex also takes this lock.
-
-We then call try_to_take_rt_mutex.  This is where the architecture that
-does not implement CMPXCHG would always grab the lock (if there's no
-contention).
-
-try_to_take_rt_mutex is used every time the task tries to grab a mutex in the
-slow path.  The first thing that is done here is an atomic setting of
-the "Has Waiters" flag of the mutex's owner field.  Yes, this could really
-be false, because if the mutex has no owner, there are no waiters and
-the current task also won't have any waiters.  But we don't have the lock
-yet, so we assume we are going to be a waiter.  The reason for this is to
-play nice for those architectures that do have CMPXCHG.  By setting this flag
-now, the owner of the mutex can't release the mutex without going into the
-slow unlock path, and it would then need to grab the wait_lock, which this
-code currently holds.  So setting the "Has Waiters" flag forces the owner
-to synchronize with this code.
-
-Now that we know that we can't have any races with the owner releasing the
-mutex, we check to see if we can take the ownership.  This is done if the
-mutex doesn't have a owner, or if we can steal the mutex from a pending
-owner.  Let's look at the situations we have here.
-
-  1) Has owner that is pending
-  ----------------------------
-
-  The mutex has a owner, but it hasn't woken up and the mutex flag
-  "Pending Owner" is set.  The first check is to see if the owner isn't the
-  current task.  This is because this function is also used for the pending
-  owner to grab the mutex.  When a pending owner wakes up, it checks to see
-  if it can take the mutex, and this is done if the owner is already set to
-  itself.  If so, we succeed and leave the function, clearing the "Pending
-  Owner" bit.
-
-  If the pending owner is not current, we check to see if the current priority is
-  higher than the pending owner.  If not, we fail the function and return.
-
-  There's also something special about a pending owner.  That is a pending owner
-  is never blocked on a mutex.  So there is no PI chain to worry about.  It also
-  means that if the mutex doesn't have any waiters, there's no accounting needed
-  to update the pending owner's pi_list, since we only worry about processes
-  blocked on the current mutex.
-
-  If there are waiters on this mutex, and we just stole the ownership, we need
-  to take the top waiter, remove it from the pi_list of the pending owner, and
-  add it to the current pi_list.  Note that at this moment, the pending owner
-  is no longer on the list of waiters.  This is fine, since the pending owner
-  would add itself back when it realizes that it had the ownership stolen
-  from itself.  When the pending owner tries to grab the mutex, it will fail
-  in try_to_take_rt_mutex if the owner field points to another process.
-
-  2) No owner
-  -----------
-
-  If there is no owner (or we successfully stole the lock), we set the owner
-  of the mutex to current, and set the flag of "Has Waiters" if the current
-  mutex actually has waiters, or we clear the flag if it doesn't.  See, it was
-  OK that we set that flag early, since now it is cleared.
-
-  3) Failed to grab ownership
-  ---------------------------
-
-  The most interesting case is when we fail to take ownership. This means that
-  there exists an owner, or there's a pending owner with equal or higher
-  priority than the current task.
-
-We'll continue on the failed case.
-
-If the mutex has a timeout, we set up a timer to go off to break us out
-of this mutex if we failed to get it after a specified amount of time.
-
-Now we enter a loop that will continue to try to take ownership of the mutex, or
-fail from a timeout or signal.
-
-Once again we try to take the mutex.  This will usually fail the first time
-in the loop, since it had just failed to get the mutex.  But the second time
-in the loop, this would likely succeed, since the task would likely be
-the pending owner.
-
-If the mutex is TASK_INTERRUPTIBLE a check for signals and timeout is done
-here.
-
-The waiter structure has a "task" field that points to the task that is blocked
-on the mutex.  This field can be NULL the first time it goes through the loop
-or if the task is a pending owner and had its mutex stolen.  If the "task"
-field is NULL then we need to set up the accounting for it.
-
-Task blocks on mutex
---------------------
-
-The accounting of a mutex and process is done with the waiter structure of
-the process.  The "task" field is set to the process, and the "lock" field
-to the mutex.  The plist nodes are initialized to the processes current
-priority.
-
-Since the wait_lock was taken at the entry of the slow lock, we can safely
-add the waiter to the wait_list.  If the current process is the highest
-priority process currently waiting on this mutex, then we remove the
-previous top waiter process (if it exists) from the pi_list of the owner,
-and add the current process to that list.  Since the pi_list of the owner
-has changed, we call rt_mutex_adjust_prio on the owner to see if the owner
-should adjust its priority accordingly.
-
-If the owner is also blocked on a lock, and had its pi_list changed
-(or deadlock checking is on), we unlock the wait_lock of the mutex and go ahead
-and run rt_mutex_adjust_prio_chain on the owner, as described earlier.
-
-Now all locks are released, and if the current process is still blocked on a
-mutex (waiter "task" field is not NULL), then we go to sleep (call schedule).
-
-Waking up in the loop
----------------------
-
-The schedule can then wake up for a few reasons.
-  1) we were given pending ownership of the mutex.
-  2) we received a signal and was TASK_INTERRUPTIBLE
-  3) we had a timeout and was TASK_INTERRUPTIBLE
-
-In any of these cases, we continue the loop and once again try to grab the
-ownership of the mutex.  If we succeed, we exit the loop, otherwise we continue
-and on signal and timeout, will exit the loop, or if we had the mutex stolen
-we just simply add ourselves back on the lists and go back to sleep.
-
-Note: For various reasons, because of timeout and signals, the steal mutex
-      algorithm needs to be careful. This is because the current process is
-      still on the wait_list. And because of dynamic changing of priorities,
-      especially on SCHED_OTHER tasks, the current process can be the
-      highest priority task on the wait_list.
-
-Failed to get mutex on Timeout or Signal
-----------------------------------------
-
-If a timeout or signal occurred, the waiter's "task" field would not be
-NULL and the task needs to be taken off the wait_list of the mutex and perhaps
-pi_list of the owner.  If this process was a high priority process, then
-the rt_mutex_adjust_prio_chain needs to be executed again on the owner,
-but this time it will be lowering the priorities.
-
-
-Unlocking the Mutex
--------------------
-
-The unlocking of a mutex also has a fast path for those architectures with
-CMPXCHG.  Since the taking of a mutex on contention always sets the
-"Has Waiters" flag of the mutex's owner, we use this to know if we need to
-take the slow path when unlocking the mutex.  If the mutex doesn't have any
-waiters, the owner field of the mutex would equal the current process and
-the mutex can be unlocked by just replacing the owner field with NULL.
-
-If the owner field has the "Has Waiters" bit set (or CMPXCHG is not available),
-the slow unlock path is taken.
-
-The first thing done in the slow unlock path is to take the wait_lock of the
-mutex.  This synchronizes the locking and unlocking of the mutex.
-
-A check is made to see if the mutex has waiters or not.  On architectures that
-do not have CMPXCHG, this is the location that the owner of the mutex will
-determine if a waiter needs to be awoken or not.  On architectures that
-do have CMPXCHG, that check is done in the fast path, but it is still needed
-in the slow path too.  If a waiter of a mutex woke up because of a signal
-or timeout between the time the owner failed the fast path CMPXCHG check and
-the grabbing of the wait_lock, the mutex may not have any waiters, thus the
-owner still needs to make this check. If there are no waiters then the mutex
-owner field is set to NULL, the wait_lock is released and nothing more is
-needed.
-
-If there are waiters, then we need to wake one up and give that waiter
-pending ownership.
-
-On the wake up code, the pi_lock of the current owner is taken.  The top
-waiter of the lock is found and removed from the wait_list of the mutex
-as well as the pi_list of the current owner.  The task field of the new
-pending owner's waiter structure is set to NULL, and the owner field of the
-mutex is set to the new owner with the "Pending Owner" bit set, as well
-as the "Has Waiters" bit if there still are other processes blocked on the
-mutex.
-
-The pi_lock of the previous owner is released, and the new pending owner's
-pi_lock is taken.  Remember that this is the trick to prevent the race
-condition in rt_mutex_adjust_prio_chain from adding itself as a waiter
-on the mutex.
-
-We now clear the "pi_blocked_on" field of the new pending owner, and if
-the mutex still has waiters pending, we add the new top waiter to the pi_list
-of the pending owner.
-
-Finally we unlock the pi_lock of the pending owner and wake it up.
-
-
-Contact
--------
-
-For updates on this document, please email Steven Rostedt <rostedt@goodmis.org>
-
-
-Credits
--------
-
-Author:  Steven Rostedt <rostedt@goodmis.org>
-
-Reviewers:  Ingo Molnar, Thomas Gleixner, Thomas Duetsch, and Randy Dunlap
-
-Updates
--------
-
-This document was originally written for 2.6.17-rc3-mm1
diff --git a/Documentation/rt-mutex.txt b/Documentation/rt-mutex.txt
deleted file mode 100644 (file)
index 243393d..0000000
+++ /dev/null
@@ -1,79 +0,0 @@
-RT-mutex subsystem with PI support
-----------------------------------
-
-RT-mutexes with priority inheritance are used to support PI-futexes,
-which enable pthread_mutex_t priority inheritance attributes
-(PTHREAD_PRIO_INHERIT). [See Documentation/pi-futex.txt for more details
-about PI-futexes.]
-
-This technology was developed in the -rt tree and streamlined for
-pthread_mutex support.
-
-Basic principles:
------------------
-
-RT-mutexes extend the semantics of simple mutexes by the priority
-inheritance protocol.
-
-A low priority owner of a rt-mutex inherits the priority of a higher
-priority waiter until the rt-mutex is released. If the temporarily
-boosted owner blocks on a rt-mutex itself it propagates the priority
-boosting to the owner of the other rt_mutex it gets blocked on. The
-priority boosting is immediately removed once the rt_mutex has been
-unlocked.
-
-This approach allows us to shorten the block of high-prio tasks on
-mutexes which protect shared resources. Priority inheritance is not a
-magic bullet for poorly designed applications, but it allows
-well-designed applications to use userspace locks in critical parts of
-an high priority thread, without losing determinism.
-
-The enqueueing of the waiters into the rtmutex waiter list is done in
-priority order. For same priorities FIFO order is chosen. For each
-rtmutex, only the top priority waiter is enqueued into the owner's
-priority waiters list. This list too queues in priority order. Whenever
-the top priority waiter of a task changes (for example it timed out or
-got a signal), the priority of the owner task is readjusted. [The
-priority enqueueing is handled by "plists", see include/linux/plist.h
-for more details.]
-
-RT-mutexes are optimized for fastpath operations and have no internal
-locking overhead when locking an uncontended mutex or unlocking a mutex
-without waiters. The optimized fastpath operations require cmpxchg
-support. [If that is not available then the rt-mutex internal spinlock
-is used]
-
-The state of the rt-mutex is tracked via the owner field of the rt-mutex
-structure:
-
-rt_mutex->owner holds the task_struct pointer of the owner. Bit 0 and 1
-are used to keep track of the "owner is pending" and "rtmutex has
-waiters" state.
-
- owner         bit1    bit0
- NULL          0       0       mutex is free (fast acquire possible)
- NULL          0       1       invalid state
- NULL          1       0       Transitional state*
- NULL          1       1       invalid state
- taskpointer   0       0       mutex is held (fast release possible)
- taskpointer   0       1       task is pending owner
- taskpointer   1       0       mutex is held and has waiters
- taskpointer   1       1       task is pending owner and mutex has waiters
-
-Pending-ownership handling is a performance optimization:
-pending-ownership is assigned to the first (highest priority) waiter of
-the mutex, when the mutex is released. The thread is woken up and once
-it starts executing it can acquire the mutex. Until the mutex is taken
-by it (bit 0 is cleared) a competing higher priority thread can "steal"
-the mutex which puts the woken up thread back on the waiters list.
-
-The pending-ownership optimization is especially important for the
-uninterrupted workflow of high-prio tasks which repeatedly
-takes/releases locks that have lower-prio waiters. Without this
-optimization the higher-prio thread would ping-pong to the lower-prio
-task [because at unlock time we always assign a new owner].
-
-(*) The "mutex has waiters" bit gets set to take the lock. If the lock
-doesn't already have an owner, this bit is quickly cleared if there are
-no waiters.  So this is a transitional state to synchronize with looking
-at the owner field of the mutex and the mutex owner releasing the lock.
index 18adc92a6b3b9ecac115965443d622128f2467e4..21461a0441c12990d1564caffa48f9a7482aaf58 100644 (file)
@@ -15,6 +15,8 @@ CONTENTS
  5. Tasks CPU affinity
    5.1 SCHED_DEADLINE and cpusets HOWTO
  6. Future plans
+ A. Test suite
+ B. Minimal main()
 
 
 0. WARNING
@@ -38,24 +40,25 @@ CONTENTS
 ==================
 
  SCHED_DEADLINE uses three parameters, named "runtime", "period", and
- "deadline" to schedule tasks. A SCHED_DEADLINE task is guaranteed to receive
+ "deadline", to schedule tasks. A SCHED_DEADLINE task should receive
  "runtime" microseconds of execution time every "period" microseconds, and
  these "runtime" microseconds are available within "deadline" microseconds
  from the beginning of the period.  In order to implement this behaviour,
  every time the task wakes up, the scheduler computes a "scheduling deadline"
  consistent with the guarantee (using the CBS[2,3] algorithm). Tasks are then
  scheduled using EDF[1] on these scheduling deadlines (the task with the
- smallest scheduling deadline is selected for execution). Notice that this
- guaranteed is respected if a proper "admission control" strategy (see Section
- "4. Bandwidth management") is used.
+ earliest scheduling deadline is selected for execution). Notice that the
+ task actually receives "runtime" time units within "deadline" if a proper
+ "admission control" strategy (see Section "4. Bandwidth management") is used
+ (clearly, if the system is overloaded this guarantee cannot be respected).
 
  Summing up, the CBS[2,3] algorithms assigns scheduling deadlines to tasks so
  that each task runs for at most its runtime every period, avoiding any
  interference between different tasks (bandwidth isolation), while the EDF[1]
- algorithm selects the task with the smallest scheduling deadline as the one
- to be executed first.  Thanks to this feature, also tasks that do not
- strictly comply with the "traditional" real-time task model (see Section 3)
can effectively use the new policy.
+ algorithm selects the task with the earliest scheduling deadline as the one
+ to be executed next. Thanks to this feature, tasks that do not strictly comply
+ with the "traditional" real-time task model (see Section 3) can effectively
+ use the new policy.
 
  In more details, the CBS algorithm assigns scheduling deadlines to
  tasks in the following way:
@@ -64,45 +67,45 @@ CONTENTS
     "deadline", and "period" parameters;
 
   - The state of the task is described by a "scheduling deadline", and
-    a "current runtime". These two parameters are initially set to 0;
+    a "remaining runtime". These two parameters are initially set to 0;
 
   - When a SCHED_DEADLINE task wakes up (becomes ready for execution),
     the scheduler checks if
 
-                    current runtime                runtime
-         ---------------------------------- > ----------------
-         scheduling deadline - current time         period
+                 remaining runtime                  runtime
+        ----------------------------------    >    ---------
+        scheduling deadline - current time           period
 
     then, if the scheduling deadline is smaller than the current time, or
     this condition is verified, the scheduling deadline and the
-    current budget are re-initialised as
+    remaining runtime are re-initialised as
 
          scheduling deadline = current time + deadline
-         current runtime = runtime
+         remaining runtime = runtime
 
-    otherwise, the scheduling deadline and the current runtime are
+    otherwise, the scheduling deadline and the remaining runtime are
     left unchanged;
 
   - When a SCHED_DEADLINE task executes for an amount of time t, its
-    current runtime is decreased as
+    remaining runtime is decreased as
 
-         current runtime = current runtime - t
+         remaining runtime = remaining runtime - t
 
     (technically, the runtime is decreased at every tick, or when the
     task is descheduled / preempted);
 
-  - When the current runtime becomes less or equal than 0, the task is
+  - When the remaining runtime becomes less or equal than 0, the task is
     said to be "throttled" (also known as "depleted" in real-time literature)
     and cannot be scheduled until its scheduling deadline. The "replenishment
     time" for this task (see next item) is set to be equal to the current
     value of the scheduling deadline;
 
   - When the current time is equal to the replenishment time of a
-    throttled task, the scheduling deadline and the current runtime are
+    throttled task, the scheduling deadline and the remaining runtime are
     updated as
 
          scheduling deadline = scheduling deadline + period
-         current runtime = current runtime + runtime
+         remaining runtime = remaining runtime + runtime
 
 
 3. Scheduling Real-Time Tasks
@@ -134,6 +137,50 @@ CONTENTS
  A real-time task can be periodic with period P if r_{j+1} = r_j + P, or
  sporadic with minimum inter-arrival time P is r_{j+1} >= r_j + P. Finally,
  d_j = r_j + D, where D is the task's relative deadline.
+ The utilisation of a real-time task is defined as the ratio between its
+ WCET and its period (or minimum inter-arrival time), and represents
+ the fraction of CPU time needed to execute the task.
+
+ If the total utilisation sum_i(WCET_i/P_i) is larger than M (with M equal
+ to the number of CPUs), then the scheduler is unable to respect all the
+ deadlines.
+ Note that total utilisation is defined as the sum of the utilisations
+ WCET_i/P_i over all the real-time tasks in the system. When considering
+ multiple real-time tasks, the parameters of the i-th task are indicated
+ with the "_i" suffix.
+ Moreover, if the total utilisation is larger than M, then we risk starving
+ non- real-time tasks by real-time tasks.
+ If, instead, the total utilisation is smaller than M, then non real-time
+ tasks will not be starved and the system might be able to respect all the
+ deadlines.
+ As a matter of fact, in this case it is possible to provide an upper bound
+ for tardiness (defined as the maximum between 0 and the difference
+ between the finishing time of a job and its absolute deadline).
+ More precisely, it can be proven that using a global EDF scheduler the
+ maximum tardiness of each task is smaller or equal than
+       ((M âˆ’ 1) Â· WCET_max âˆ’ WCET_min)/(M âˆ’ (M âˆ’ 2) Â· U_max) + WCET_max
+ where WCET_max = max_i{WCET_i} is the maximum WCET, WCET_min=min_i{WCET_i}
+ is the minimum WCET, and U_max = max_i{WCET_i/P_i} is the maximum utilisation.
+
+ If M=1 (uniprocessor system), or in case of partitioned scheduling (each
+ real-time task is statically assigned to one and only one CPU), it is
+ possible to formally check if all the deadlines are respected.
+ If D_i = P_i for all tasks, then EDF is able to respect all the deadlines
+ of all the tasks executing on a CPU if and only if the total utilisation
+ of the tasks running on such a CPU is smaller or equal than 1.
+ If D_i != P_i for some task, then it is possible to define the density of
+ a task as C_i/min{D_i,T_i}, and EDF is able to respect all the deadlines
+ of all the tasks running on a CPU if the sum sum_i C_i/min{D_i,T_i} of the
+ densities of the tasks running on such a CPU is smaller or equal than 1
+ (notice that this condition is only sufficient, and not necessary).
+
+ On multiprocessor systems with global EDF scheduling (non partitioned
+ systems), a sufficient test for schedulability can not be based on the
+ utilisations (it can be shown that task sets with utilisations slightly
+ larger than 1 can miss deadlines regardless of the number of CPUs M).
+ However, as previously stated, enforcing that the total utilisation is smaller
+ than M is enough to guarantee that non real-time tasks are not starved and
+ that the tardiness of real-time tasks has an upper bound.
 
  SCHED_DEADLINE can be used to schedule real-time tasks guaranteeing that
  the jobs' deadlines of a task are respected. In order to do this, a task
@@ -147,6 +194,8 @@ CONTENTS
  and the absolute deadlines (d_j) coincide, so a proper admission control
  allows to respect the jobs' absolute deadlines for this task (this is what is
  called "hard schedulability property" and is an extension of Lemma 1 of [2]).
+ Notice that if runtime > deadline the admission control will surely reject
+ this task, as it is not possible to respect its temporal constraints.
 
  References:
   1 - C. L. Liu and J. W. Layland. Scheduling algorithms for multiprogram-
@@ -156,46 +205,57 @@ CONTENTS
       Real-Time Systems. Proceedings of the 19th IEEE Real-time Systems
       Symposium, 1998. http://retis.sssup.it/~giorgio/paps/1998/rtss98-cbs.pdf
   3 - L. Abeni. Server Mechanisms for Multimedia Applications. ReTiS Lab
-      Technical Report. http://xoomer.virgilio.it/lucabe72/pubs/tr-98-01.ps
+      Technical Report. http://disi.unitn.it/~abeni/tr-98-01.pdf
 
 4. Bandwidth management
 =======================
 
- In order for the -deadline scheduling to be effective and useful, it is
- important to have some method to keep the allocation of the available CPU
- bandwidth to the tasks under control.
- This is usually called "admission control" and if it is not performed at all,
+ As previously mentioned, in order for -deadline scheduling to be
+ effective and useful (that is, to be able to provide "runtime" time units
+ within "deadline"), it is important to have some method to keep the allocation
+ of the available fractions of CPU time to the various tasks under control.
+ This is usually called "admission control" and if it is not performed, then
  no guarantee can be given on the actual scheduling of the -deadline tasks.
 
- Since when RT-throttling has been introduced each task group has a bandwidth
- associated, calculated as a certain amount of runtime over a period.
- Moreover, to make it possible to manipulate such bandwidth, readable/writable
- controls have been added to both procfs (for system wide settings) and cgroupfs
- (for per-group settings).
- Therefore, the same interface is being used for controlling the bandwidth
- distrubution to -deadline tasks.
-
- However, more discussion is needed in order to figure out how we want to manage
- SCHED_DEADLINE bandwidth at the task group level. Therefore, SCHED_DEADLINE
- uses (for now) a less sophisticated, but actually very sensible, mechanism to
- ensure that a certain utilization cap is not overcome per each root_domain.
-
- Another main difference between deadline bandwidth management and RT-throttling
+ As already stated in Section 3, a necessary condition to be respected to
+ correctly schedule a set of real-time tasks is that the total utilisation
+ is smaller than M. When talking about -deadline tasks, this requires that
+ the sum of the ratio between runtime and period for all tasks is smaller
+ than M. Notice that the ratio runtime/period is equivalent to the utilisation
+ of a "traditional" real-time task, and is also often referred to as
+ "bandwidth".
+ The interface used to control the CPU bandwidth that can be allocated
+ to -deadline tasks is similar to the one already used for -rt
+ tasks with real-time group scheduling (a.k.a. RT-throttling - see
+ Documentation/scheduler/sched-rt-group.txt), and is based on readable/
+ writable control files located in procfs (for system wide settings).
+ Notice that per-group settings (controlled through cgroupfs) are still not
+ defined for -deadline tasks, because more discussion is needed in order to
+ figure out how we want to manage SCHED_DEADLINE bandwidth at the task group
+ level.
+
+ A main difference between deadline bandwidth management and RT-throttling
  is that -deadline tasks have bandwidth on their own (while -rt ones don't!),
- and thus we don't need an higher level throttling mechanism to enforce the
- desired bandwidth.
+ and thus we don't need a higher level throttling mechanism to enforce the
+ desired bandwidth. In other words, this means that interface parameters are
+ only used at admission control time (i.e., when the user calls
+ sched_setattr()). Scheduling is then performed considering actual tasks'
+ parameters, so that CPU bandwidth is allocated to SCHED_DEADLINE tasks
+ respecting their needs in terms of granularity. Therefore, using this simple
+ interface we can put a cap on total utilization of -deadline tasks (i.e.,
+ \Sum (runtime_i / period_i) < global_dl_utilization_cap).
 
 4.1 System wide settings
 ------------------------
 
  The system wide settings are configured under the /proc virtual file system.
 
- For now the -rt knobs are used for dl admission control and the -deadline
- runtime is accounted against the -rt runtime. We realise that this isn't
- entirely desirable; however, it is better to have a small interface for now,
- and be able to change it easily later. The ideal situation (see 5.) is to run
- -rt tasks from a -deadline server; in which case the -rt bandwidth is a direct
- subset of dl_bw.
+ For now the -rt knobs are used for -deadline admission control and the
+ -deadline runtime is accounted against the -rt runtime. We realise that this
+ isn't entirely desirable; however, it is better to have a small interface for
+ now, and be able to change it easily later. The ideal situation (see 5.) is to
+ run -rt tasks from a -deadline server; in which case the -rt bandwidth is a
direct subset of dl_bw.
 
  This means that, for a root_domain comprising M CPUs, -deadline tasks
  can be created while the sum of their bandwidths stays below:
@@ -231,8 +291,16 @@ CONTENTS
  950000. With rt_period equal to 1000000, by default, it means that -deadline
  tasks can use at most 95%, multiplied by the number of CPUs that compose the
  root_domain, for each root_domain.
+ This means that non -deadline tasks will receive at least 5% of the CPU time,
+ and that -deadline tasks will receive their runtime with a guaranteed
+ worst-case delay respect to the "deadline" parameter. If "deadline" = "period"
+ and the cpuset mechanism is used to implement partitioned scheduling (see
+ Section 5), then this simple setting of the bandwidth management is able to
+ deterministically guarantee that -deadline tasks will receive their runtime
+ in a period.
 
- A -deadline task cannot fork.
+ Finally, notice that in order not to jeopardize the admission control a
+ -deadline task cannot fork.
 
 5. Tasks CPU affinity
 =====================
@@ -279,3 +347,179 @@ CONTENTS
  throttling patches [https://lkml.org/lkml/2010/2/23/239] but we still are in
  the preliminary phases of the merge and we really seek feedback that would
  help us decide on the direction it should take.
+
+Appendix A. Test suite
+======================
+
+ The SCHED_DEADLINE policy can be easily tested using two applications that
+ are part of a wider Linux Scheduler validation suite. The suite is
+ available as a GitHub repository: https://github.com/scheduler-tools.
+
+ The first testing application is called rt-app and can be used to
+ start multiple threads with specific parameters. rt-app supports
+ SCHED_{OTHER,FIFO,RR,DEADLINE} scheduling policies and their related
+ parameters (e.g., niceness, priority, runtime/deadline/period). rt-app
+ is a valuable tool, as it can be used to synthetically recreate certain
+ workloads (maybe mimicking real use-cases) and evaluate how the scheduler
+ behaves under such workloads. In this way, results are easily reproducible.
+ rt-app is available at: https://github.com/scheduler-tools/rt-app.
+
+ Thread parameters can be specified from the command line, with something like
+ this:
+
+  # rt-app -t 100000:10000:d -t 150000:20000:f:10 -D5
+
+ The above creates 2 threads. The first one, scheduled by SCHED_DEADLINE,
+ executes for 10ms every 100ms. The second one, scheduled at SCHED_FIFO
+ priority 10, executes for 20ms every 150ms. The test will run for a total
+ of 5 seconds.
+
+ More interestingly, configurations can be described with a json file that
+ can be passed as input to rt-app with something like this:
+
+  # rt-app my_config.json
+
+ The parameters that can be specified with the second method are a superset
+ of the command line options. Please refer to rt-app documentation for more
+ details (<rt-app-sources>/doc/*.json).
+
+ The second testing application is a modification of schedtool, called
+ schedtool-dl, which can be used to setup SCHED_DEADLINE parameters for a
+ certain pid/application. schedtool-dl is available at:
+ https://github.com/scheduler-tools/schedtool-dl.git.
+
+ The usage is straightforward:
+
+  # schedtool -E -t 10000000:100000000 -e ./my_cpuhog_app
+
+ With this, my_cpuhog_app is put to run inside a SCHED_DEADLINE reservation
+ of 10ms every 100ms (note that parameters are expressed in microseconds).
+ You can also use schedtool to create a reservation for an already running
+ application, given that you know its pid:
+
+  # schedtool -E -t 10000000:100000000 my_app_pid
+
+Appendix B. Minimal main()
+==========================
+
+ We provide in what follows a simple (ugly) self-contained code snippet
+ showing how SCHED_DEADLINE reservations can be created by a real-time
+ application developer.
+
+ #define _GNU_SOURCE
+ #include <unistd.h>
+ #include <stdio.h>
+ #include <stdlib.h>
+ #include <string.h>
+ #include <time.h>
+ #include <linux/unistd.h>
+ #include <linux/kernel.h>
+ #include <linux/types.h>
+ #include <sys/syscall.h>
+ #include <pthread.h>
+
+ #define gettid() syscall(__NR_gettid)
+
+ #define SCHED_DEADLINE        6
+
+ /* XXX use the proper syscall numbers */
+ #ifdef __x86_64__
+ #define __NR_sched_setattr            314
+ #define __NR_sched_getattr            315
+ #endif
+
+ #ifdef __i386__
+ #define __NR_sched_setattr            351
+ #define __NR_sched_getattr            352
+ #endif
+
+ #ifdef __arm__
+ #define __NR_sched_setattr            380
+ #define __NR_sched_getattr            381
+ #endif
+
+ static volatile int done;
+
+ struct sched_attr {
+       __u32 size;
+
+       __u32 sched_policy;
+       __u64 sched_flags;
+
+       /* SCHED_NORMAL, SCHED_BATCH */
+       __s32 sched_nice;
+
+       /* SCHED_FIFO, SCHED_RR */
+       __u32 sched_priority;
+
+       /* SCHED_DEADLINE (nsec) */
+       __u64 sched_runtime;
+       __u64 sched_deadline;
+       __u64 sched_period;
+ };
+
+ int sched_setattr(pid_t pid,
+                 const struct sched_attr *attr,
+                 unsigned int flags)
+ {
+       return syscall(__NR_sched_setattr, pid, attr, flags);
+ }
+
+ int sched_getattr(pid_t pid,
+                 struct sched_attr *attr,
+                 unsigned int size,
+                 unsigned int flags)
+ {
+       return syscall(__NR_sched_getattr, pid, attr, size, flags);
+ }
+
+ void *run_deadline(void *data)
+ {
+       struct sched_attr attr;
+       int x = 0;
+       int ret;
+       unsigned int flags = 0;
+
+       printf("deadline thread started [%ld]\n", gettid());
+
+       attr.size = sizeof(attr);
+       attr.sched_flags = 0;
+       attr.sched_nice = 0;
+       attr.sched_priority = 0;
+
+       /* This creates a 10ms/30ms reservation */
+       attr.sched_policy = SCHED_DEADLINE;
+       attr.sched_runtime = 10 * 1000 * 1000;
+       attr.sched_period = attr.sched_deadline = 30 * 1000 * 1000;
+
+       ret = sched_setattr(0, &attr, flags);
+       if (ret < 0) {
+               done = 0;
+               perror("sched_setattr");
+               exit(-1);
+       }
+
+       while (!done) {
+               x++;
+       }
+
+       printf("deadline thread dies [%ld]\n", gettid());
+       return NULL;
+ }
+
+ int main (int argc, char **argv)
+ {
+       pthread_t thread;
+
+       printf("main thread [%ld]\n", gettid());
+
+       pthread_create(&thread, NULL, run_deadline, NULL);
+
+       sleep(10);
+
+       done = 1;
+       pthread_join(thread, NULL);
+
+       printf("main dies [%ld]\n", gettid());
+       return 0;
+ }
index 8727c194ca16a56f483b2f0cd2712654c0b948b4..821c936e1a634f0cb2cb6e4774177c2364c2e75d 100644 (file)
@@ -888,11 +888,11 @@ payload contents" for more information.
                                const char *callout_info);
 
     This is used to request a key or keyring with a description that matches
-    the description specified according to the key type's match function. This
-    permits approximate matching to occur. If callout_string is not NULL, then
-    /sbin/request-key will be invoked in an attempt to obtain the key from
-    userspace. In that case, callout_string will be passed as an argument to
-    the program.
+    the description specified according to the key type's match_preparse()
+    method. This permits approximate matching to occur. If callout_string is
+    not NULL, then /sbin/request-key will be invoked in an attempt to obtain
+    the key from userspace. In that case, callout_string will be passed as an
+    argument to the program.
 
     Should the function fail error ENOKEY, EKEYEXPIRED or EKEYREVOKED will be
     returned.
@@ -1170,7 +1170,7 @@ The structure has a number of fields, some of which are mandatory:
      The method should return 0 if successful or a negative error code
      otherwise.
 
-     
+
  (*) void (*free_preparse)(struct key_preparsed_payload *prep);
 
      This method is only required if the preparse() method is provided,
@@ -1225,16 +1225,55 @@ The structure has a number of fields, some of which are mandatory:
      It is safe to sleep in this method.
 
 
- (*) int (*match)(const struct key *key, const void *desc);
+ (*) int (*match_preparse)(struct key_match_data *match_data);
+
+     This method is optional.  It is called when a key search is about to be
+     performed.  It is given the following structure:
 
-     This method is called to match a key against a description. It should
-     return non-zero if the two match, zero if they don't.
+       struct key_match_data {
+               bool (*cmp)(const struct key *key,
+                           const struct key_match_data *match_data);
+               const void      *raw_data;
+               void            *preparsed;
+               unsigned        lookup_type;
+       };
 
-     This method should not need to lock the key in any way. The type and
-     description can be considered invariant, and the payload should not be
-     accessed (the key may not yet be instantiated).
+     On entry, raw_data will be pointing to the criteria to be used in matching
+     a key by the caller and should not be modified.  (*cmp)() will be pointing
+     to the default matcher function (which does an exact description match
+     against raw_data) and lookup_type will be set to indicate a direct lookup.
 
-     It is not safe to sleep in this method; the caller may hold spinlocks.
+     The following lookup_type values are available:
+
+      [*] KEYRING_SEARCH_LOOKUP_DIRECT - A direct lookup hashes the type and
+         description to narrow down the search to a small number of keys.
+
+      [*] KEYRING_SEARCH_LOOKUP_ITERATE - An iterative lookup walks all the
+         keys in the keyring until one is matched.  This must be used for any
+         search that's not doing a simple direct match on the key description.
+
+     The method may set cmp to point to a function of its choice that does some
+     other form of match, may set lookup_type to KEYRING_SEARCH_LOOKUP_ITERATE
+     and may attach something to the preparsed pointer for use by (*cmp)().
+     (*cmp)() should return true if a key matches and false otherwise.
+
+     If preparsed is set, it may be necessary to use the match_free() method to
+     clean it up.
+
+     The method should return 0 if successful or a negative error code
+     otherwise.
+
+     It is permitted to sleep in this method, but (*cmp)() may not sleep as
+     locks will be held over it.
+
+     If match_preparse() is not provided, keys of this type will be matched
+     exactly by their description.
+
+
+ (*) void (*match_free)(struct key_match_data *match_data);
+
+     This method is optional.  If given, it called to clean up
+     match_data->preparsed after a successful call to match_preparse().
 
 
  (*) void (*revoke)(struct key *key);
diff --git a/Documentation/spinlocks.txt b/Documentation/spinlocks.txt
deleted file mode 100644 (file)
index 97eaf57..0000000
+++ /dev/null
@@ -1,167 +0,0 @@
-Lesson 1: Spin locks
-
-The most basic primitive for locking is spinlock.
-
-static DEFINE_SPINLOCK(xxx_lock);
-
-       unsigned long flags;
-
-       spin_lock_irqsave(&xxx_lock, flags);
-       ... critical section here ..
-       spin_unlock_irqrestore(&xxx_lock, flags);
-
-The above is always safe. It will disable interrupts _locally_, but the
-spinlock itself will guarantee the global lock, so it will guarantee that
-there is only one thread-of-control within the region(s) protected by that
-lock. This works well even under UP also, so the code does _not_ need to
-worry about UP vs SMP issues: the spinlocks work correctly under both.
-
-   NOTE! Implications of spin_locks for memory are further described in:
-
-     Documentation/memory-barriers.txt
-       (5) LOCK operations.
-       (6) UNLOCK operations.
-
-The above is usually pretty simple (you usually need and want only one
-spinlock for most things - using more than one spinlock can make things a
-lot more complex and even slower and is usually worth it only for
-sequences that you _know_ need to be split up: avoid it at all cost if you
-aren't sure).
-
-This is really the only really hard part about spinlocks: once you start
-using spinlocks they tend to expand to areas you might not have noticed
-before, because you have to make sure the spinlocks correctly protect the
-shared data structures _everywhere_ they are used. The spinlocks are most
-easily added to places that are completely independent of other code (for
-example, internal driver data structures that nobody else ever touches).
-
-   NOTE! The spin-lock is safe only when you _also_ use the lock itself
-   to do locking across CPU's, which implies that EVERYTHING that
-   touches a shared variable has to agree about the spinlock they want
-   to use.
-
-----
-
-Lesson 2: reader-writer spinlocks.
-
-If your data accesses have a very natural pattern where you usually tend
-to mostly read from the shared variables, the reader-writer locks
-(rw_lock) versions of the spinlocks are sometimes useful. They allow multiple
-readers to be in the same critical region at once, but if somebody wants
-to change the variables it has to get an exclusive write lock.
-
-   NOTE! reader-writer locks require more atomic memory operations than
-   simple spinlocks.  Unless the reader critical section is long, you
-   are better off just using spinlocks.
-
-The routines look the same as above:
-
-   rwlock_t xxx_lock = __RW_LOCK_UNLOCKED(xxx_lock);
-
-       unsigned long flags;
-
-       read_lock_irqsave(&xxx_lock, flags);
-       .. critical section that only reads the info ...
-       read_unlock_irqrestore(&xxx_lock, flags);
-
-       write_lock_irqsave(&xxx_lock, flags);
-       .. read and write exclusive access to the info ...
-       write_unlock_irqrestore(&xxx_lock, flags);
-
-The above kind of lock may be useful for complex data structures like
-linked lists, especially searching for entries without changing the list
-itself.  The read lock allows many concurrent readers.  Anything that
-_changes_ the list will have to get the write lock.
-
-   NOTE! RCU is better for list traversal, but requires careful
-   attention to design detail (see Documentation/RCU/listRCU.txt).
-
-Also, you cannot "upgrade" a read-lock to a write-lock, so if you at _any_
-time need to do any changes (even if you don't do it every time), you have
-to get the write-lock at the very beginning.
-
-   NOTE! We are working hard to remove reader-writer spinlocks in most
-   cases, so please don't add a new one without consensus.  (Instead, see
-   Documentation/RCU/rcu.txt for complete information.)
-
-----
-
-Lesson 3: spinlocks revisited.
-
-The single spin-lock primitives above are by no means the only ones. They
-are the most safe ones, and the ones that work under all circumstances,
-but partly _because_ they are safe they are also fairly slow. They are slower
-than they'd need to be, because they do have to disable interrupts
-(which is just a single instruction on a x86, but it's an expensive one -
-and on other architectures it can be worse).
-
-If you have a case where you have to protect a data structure across
-several CPU's and you want to use spinlocks you can potentially use
-cheaper versions of the spinlocks. IFF you know that the spinlocks are
-never used in interrupt handlers, you can use the non-irq versions:
-
-       spin_lock(&lock);
-       ...
-       spin_unlock(&lock);
-
-(and the equivalent read-write versions too, of course). The spinlock will
-guarantee the same kind of exclusive access, and it will be much faster. 
-This is useful if you know that the data in question is only ever
-manipulated from a "process context", ie no interrupts involved. 
-
-The reasons you mustn't use these versions if you have interrupts that
-play with the spinlock is that you can get deadlocks:
-
-       spin_lock(&lock);
-       ...
-               <- interrupt comes in:
-                       spin_lock(&lock);
-
-where an interrupt tries to lock an already locked variable. This is ok if
-the other interrupt happens on another CPU, but it is _not_ ok if the
-interrupt happens on the same CPU that already holds the lock, because the
-lock will obviously never be released (because the interrupt is waiting
-for the lock, and the lock-holder is interrupted by the interrupt and will
-not continue until the interrupt has been processed). 
-
-(This is also the reason why the irq-versions of the spinlocks only need
-to disable the _local_ interrupts - it's ok to use spinlocks in interrupts
-on other CPU's, because an interrupt on another CPU doesn't interrupt the
-CPU that holds the lock, so the lock-holder can continue and eventually
-releases the lock). 
-
-Note that you can be clever with read-write locks and interrupts. For
-example, if you know that the interrupt only ever gets a read-lock, then
-you can use a non-irq version of read locks everywhere - because they
-don't block on each other (and thus there is no dead-lock wrt interrupts. 
-But when you do the write-lock, you have to use the irq-safe version. 
-
-For an example of being clever with rw-locks, see the "waitqueue_lock" 
-handling in kernel/sched/core.c - nothing ever _changes_ a wait-queue from
-within an interrupt, they only read the queue in order to know whom to
-wake up. So read-locks are safe (which is good: they are very common
-indeed), while write-locks need to protect themselves against interrupts.
-
-               Linus
-
-----
-
-Reference information:
-
-For dynamic initialization, use spin_lock_init() or rwlock_init() as
-appropriate:
-
-   spinlock_t xxx_lock;
-   rwlock_t xxx_rw_lock;
-
-   static int __init xxx_init(void)
-   {
-       spin_lock_init(&xxx_lock);
-       rwlock_init(&xxx_rw_lock);
-       ...
-   }
-
-   module_init(xxx_init);
-
-For static initialization, use DEFINE_SPINLOCK() / DEFINE_RWLOCK() or
-__SPIN_LOCK_UNLOCKED() / __RW_LOCK_UNLOCKED() as appropriate.
index f79eb96663790f1c116f6a44d706af048bdedc88..57baff5bdb806b3b725bdc7859c385fbdc1cac54 100644 (file)
@@ -190,6 +190,8 @@ core_pattern is used to specify a core dumpfile pattern name.
        %%      output one '%'
        %p      pid
        %P      global pid (init PID namespace)
+       %i      tid
+       %I      global tid (init PID namespace)
        %u      uid
        %g      gid
        %d      dump mode, matches PR_SET_DUMPABLE and
diff --git a/Documentation/video4linux/vivid.txt b/Documentation/video4linux/vivid.txt
new file mode 100644 (file)
index 0000000..eeb11a2
--- /dev/null
@@ -0,0 +1,1111 @@
+vivid: Virtual Video Test Driver
+================================
+
+This driver emulates video4linux hardware of various types: video capture, video
+output, vbi capture and output, radio receivers and transmitters and a software
+defined radio receiver. In addition a simple framebuffer device is available for
+testing capture and output overlays.
+
+Up to 64 vivid instances can be created, each with up to 16 inputs and 16 outputs.
+
+Each input can be a webcam, TV capture device, S-Video capture device or an HDMI
+capture device. Each output can be an S-Video output device or an HDMI output
+device.
+
+These inputs and outputs act exactly as a real hardware device would behave. This
+allows you to use this driver as a test input for application development, since
+you can test the various features without requiring special hardware.
+
+This document describes the features implemented by this driver:
+
+- Support for read()/write(), MMAP, USERPTR and DMABUF streaming I/O.
+- A large list of test patterns and variations thereof
+- Working brightness, contrast, saturation and hue controls
+- Support for the alpha color component
+- Full colorspace support, including limited/full RGB range
+- All possible control types are present
+- Support for various pixel aspect ratios and video aspect ratios
+- Error injection to test what happens if errors occur
+- Supports crop/compose/scale in any combination for both input and output
+- Can emulate up to 4K resolutions
+- All Field settings are supported for testing interlaced capturing
+- Supports all standard YUV and RGB formats, including two multiplanar YUV formats
+- Raw and Sliced VBI capture and output support
+- Radio receiver and transmitter support, including RDS support
+- Software defined radio (SDR) support
+- Capture and output overlay support
+
+These features will be described in more detail below.
+
+
+Table of Contents
+-----------------
+
+Section 1: Configuring the driver
+Section 2: Video Capture
+Section 2.1: Webcam Input
+Section 2.2: TV and S-Video Inputs
+Section 2.3: HDMI Input
+Section 3: Video Output
+Section 3.1: S-Video Output
+Section 3.2: HDMI Output
+Section 4: VBI Capture
+Section 5: VBI Output
+Section 6: Radio Receiver
+Section 7: Radio Transmitter
+Section 8: Software Defined Radio Receiver
+Section 9: Controls
+Section 9.1: User Controls - Test Controls
+Section 9.2: User Controls - Video Capture
+Section 9.3: User Controls - Audio
+Section 9.4: Vivid Controls
+Section 9.4.1: Test Pattern Controls
+Section 9.4.2: Capture Feature Selection Controls
+Section 9.4.3: Output Feature Selection Controls
+Section 9.4.4: Error Injection Controls
+Section 9.4.5: VBI Raw Capture Controls
+Section 9.5: Digital Video Controls
+Section 9.6: FM Radio Receiver Controls
+Section 9.7: FM Radio Modulator
+Section 10: Video, VBI and RDS Looping
+Section 10.1: Video and Sliced VBI looping
+Section 10.2: Radio & RDS Looping
+Section 11: Cropping, Composing, Scaling
+Section 12: Formats
+Section 13: Capture Overlay
+Section 14: Output Overlay
+Section 15: Some Future Improvements
+
+
+Section 1: Configuring the driver
+---------------------------------
+
+By default the driver will create a single instance that has a video capture
+device with webcam, TV, S-Video and HDMI inputs, a video output device with
+S-Video and HDMI outputs, one vbi capture device, one vbi output device, one
+radio receiver device, one radio transmitter device and one SDR device.
+
+The number of instances, devices, video inputs and outputs and their types are
+all configurable using the following module options:
+
+n_devs: number of driver instances to create. By default set to 1. Up to 64
+       instances can be created.
+
+node_types: which devices should each driver instance create. An array of
+       hexadecimal values, one for each instance. The default is 0x1d3d.
+       Each value is a bitmask with the following meaning:
+               bit 0: Video Capture node
+               bit 2-3: VBI Capture node: 0 = none, 1 = raw vbi, 2 = sliced vbi, 3 = both
+               bit 4: Radio Receiver node
+               bit 5: Software Defined Radio Receiver node
+               bit 8: Video Output node
+               bit 10-11: VBI Output node: 0 = none, 1 = raw vbi, 2 = sliced vbi, 3 = both
+               bit 12: Radio Transmitter node
+               bit 16: Framebuffer for testing overlays
+
+       So to create four instances, the first two with just one video capture
+       device, the second two with just one video output device you would pass
+       these module options to vivid:
+
+               n_devs=4 node_types=0x1,0x1,0x100,0x100
+
+num_inputs: the number of inputs, one for each instance. By default 4 inputs
+       are created for each video capture device. At most 16 inputs can be created,
+       and there must be at least one.
+
+input_types: the input types for each instance, the default is 0xe4. This defines
+       what the type of each input is when the inputs are created for each driver
+       instance. This is a hexadecimal value with up to 16 pairs of bits, each
+       pair gives the type and bits 0-1 map to input 0, bits 2-3 map to input 1,
+       30-31 map to input 15. Each pair of bits has the following meaning:
+
+               00: this is a webcam input
+               01: this is a TV tuner input
+               10: this is an S-Video input
+               11: this is an HDMI input
+
+       So to create a video capture device with 8 inputs where input 0 is a TV
+       tuner, inputs 1-3 are S-Video inputs and inputs 4-7 are HDMI inputs you
+       would use the following module options:
+
+               num_inputs=8 input_types=0xffa9
+
+num_outputs: the number of outputs, one for each instance. By default 2 outputs
+       are created for each video output device. At most 16 outputs can be
+       created, and there must be at least one.
+
+output_types: the output types for each instance, the default is 0x02. This defines
+       what the type of each output is when the outputs are created for each
+       driver instance. This is a hexadecimal value with up to 16 bits, each bit
+       gives the type and bit 0 maps to output 0, bit 1 maps to output 1, bit
+       15 maps to output 15. The meaning of each bit is as follows:
+
+               0: this is an S-Video output
+               1: this is an HDMI output
+
+       So to create a video output device with 8 outputs where outputs 0-3 are
+       S-Video outputs and outputs 4-7 are HDMI outputs you would use the
+       following module options:
+
+               num_outputs=8 output_types=0xf0
+
+vid_cap_nr: give the desired videoX start number for each video capture device.
+       The default is -1 which will just take the first free number. This allows
+       you to map capture video nodes to specific videoX device nodes. Example:
+
+               n_devs=4 vid_cap_nr=2,4,6,8
+
+       This will attempt to assign /dev/video2 for the video capture device of
+       the first vivid instance, video4 for the next up to video8 for the last
+       instance. If it can't succeed, then it will just take the next free
+       number.
+
+vid_out_nr: give the desired videoX start number for each video output device.
+        The default is -1 which will just take the first free number.
+
+vbi_cap_nr: give the desired vbiX start number for each vbi capture device.
+        The default is -1 which will just take the first free number.
+
+vbi_out_nr: give the desired vbiX start number for each vbi output device.
+        The default is -1 which will just take the first free number.
+
+radio_rx_nr: give the desired radioX start number for each radio receiver device.
+        The default is -1 which will just take the first free number.
+
+radio_tx_nr: give the desired radioX start number for each radio transmitter
+       device. The default is -1 which will just take the first free number.
+
+sdr_cap_nr: give the desired swradioX start number for each SDR capture device.
+        The default is -1 which will just take the first free number.
+
+ccs_cap_mode: specify the allowed video capture crop/compose/scaling combination
+       for each driver instance. Video capture devices can have any combination
+       of cropping, composing and scaling capabilities and this will tell the
+       vivid driver which of those is should emulate. By default the user can
+       select this through controls.
+
+       The value is either -1 (controlled by the user) or a set of three bits,
+       each enabling (1) or disabling (0) one of the features:
+
+               bit 0: Enable crop support. Cropping will take only part of the
+                      incoming picture.
+               bit 1: Enable compose support. Composing will copy the incoming
+                      picture into a larger buffer.
+               bit 2: Enable scaling support. Scaling can scale the incoming
+                      picture. The scaler of the vivid driver can enlarge up
+                      or down to four times the original size. The scaler is
+                      very simple and low-quality. Simplicity and speed were
+                      key, not quality.
+
+       Note that this value is ignored by webcam inputs: those enumerate
+       discrete framesizes and that is incompatible with cropping, composing
+       or scaling.
+
+ccs_out_mode: specify the allowed video output crop/compose/scaling combination
+       for each driver instance. Video output devices can have any combination
+       of cropping, composing and scaling capabilities and this will tell the
+       vivid driver which of those is should emulate. By default the user can
+       select this through controls.
+
+       The value is either -1 (controlled by the user) or a set of three bits,
+       each enabling (1) or disabling (0) one of the features:
+
+               bit 0: Enable crop support. Cropping will take only part of the
+                      outgoing buffer.
+               bit 1: Enable compose support. Composing will copy the incoming
+                      buffer into a larger picture frame.
+               bit 2: Enable scaling support. Scaling can scale the incoming
+                      buffer. The scaler of the vivid driver can enlarge up
+                      or down to four times the original size. The scaler is
+                      very simple and low-quality. Simplicity and speed were
+                      key, not quality.
+
+multiplanar: select whether each device instance supports multi-planar formats,
+       and thus the V4L2 multi-planar API. By default the first device instance
+       is single-planar, the second multi-planar, and it keeps alternating.
+
+       This module option can override that for each instance. Values are:
+
+               0: use alternating single and multi-planar devices.
+               1: this is a single-planar instance.
+               2: this is a multi-planar instance.
+
+vivid_debug: enable driver debugging info
+
+no_error_inj: if set disable the error injecting controls. This option is
+       needed in order to run a tool like v4l2-compliance. Tools like that
+       exercise all controls including a control like 'Disconnect' which
+       emulates a USB disconnect, making the device inaccessible and so
+       all tests that v4l2-compliance is doing will fail afterwards.
+
+       There may be other situations as well where you want to disable the
+       error injection support of vivid. When this option is set, then the
+       controls that select crop, compose and scale behavior are also
+       removed. Unless overridden by ccs_cap_mode and/or ccs_out_mode the
+       will default to enabling crop, compose and scaling.
+
+Taken together, all these module options allow you to precisely customize
+the driver behavior and test your application with all sorts of permutations.
+It is also very suitable to emulate hardware that is not yet available, e.g.
+when developing software for a new upcoming device.
+
+
+Section 2: Video Capture
+------------------------
+
+This is probably the most frequently used feature. The video capture device
+can be configured by using the module options num_inputs, input_types and
+ccs_cap_mode (see section 1 for more detailed information), but by default
+four inputs are configured: a webcam, a TV tuner, an S-Video and an HDMI
+input, one input for each input type. Those are described in more detail
+below.
+
+Special attention has been given to the rate at which new frames become
+available. The jitter will be around 1 jiffie (that depends on the HZ
+configuration of your kernel, so usually 1/100, 1/250 or 1/1000 of a second),
+but the long-term behavior is exactly following the framerate. So a
+framerate of 59.94 Hz is really different from 60 Hz. If the framerate
+exceeds your kernel's HZ value, then you will get dropped frames, but the
+frame/field sequence counting will keep track of that so the sequence
+count will skip whenever frames are dropped.
+
+
+Section 2.1: Webcam Input
+-------------------------
+
+The webcam input supports three framesizes: 320x180, 640x360 and 1280x720. It
+supports frames per second settings of 10, 15, 25, 30, 50 and 60 fps. Which ones
+are available depends on the chosen framesize: the larger the framesize, the
+lower the maximum frames per second.
+
+The initially selected colorspace when you switch to the webcam input will be
+sRGB.
+
+
+Section 2.2: TV and S-Video Inputs
+----------------------------------
+
+The only difference between the TV and S-Video input is that the TV has a
+tuner. Otherwise they behave identically.
+
+These inputs support audio inputs as well: one TV and one Line-In. They
+both support all TV standards. If the standard is queried, then the Vivid
+controls 'Standard Signal Mode' and 'Standard' determine what
+the result will be.
+
+These inputs support all combinations of the field setting. Special care has
+been taken to faithfully reproduce how fields are handled for the different
+TV standards. This is particularly noticable when generating a horizontally
+moving image so the temporal effect of using interlaced formats becomes clearly
+visible. For 50 Hz standards the top field is the oldest and the bottom field
+is the newest in time. For 60 Hz standards that is reversed: the bottom field
+is the oldest and the top field is the newest in time.
+
+When you start capturing in V4L2_FIELD_ALTERNATE mode the first buffer will
+contain the top field for 50 Hz standards and the bottom field for 60 Hz
+standards. This is what capture hardware does as well.
+
+Finally, for PAL/SECAM standards the first half of the top line contains noise.
+This simulates the Wide Screen Signal that is commonly placed there.
+
+The initially selected colorspace when you switch to the TV or S-Video input
+will be SMPTE-170M.
+
+The pixel aspect ratio will depend on the TV standard. The video aspect ratio
+can be selected through the 'Standard Aspect Ratio' Vivid control.
+Choices are '4x3', '16x9' which will give letterboxed widescreen video and
+'16x9 Anomorphic' which will give full screen squashed anamorphic widescreen
+video that will need to be scaled accordingly.
+
+The TV 'tuner' supports a frequency range of 44-958 MHz. Channels are available
+every 6 MHz, starting from 49.25 MHz. For each channel the generated image
+will be in color for the +/- 0.25 MHz around it, and in grayscale for
++/- 1 MHz around the channel. Beyond that it is just noise. The VIDIOC_G_TUNER
+ioctl will return 100% signal strength for +/- 0.25 MHz and 50% for +/- 1 MHz.
+It will also return correct afc values to show whether the frequency is too
+low or too high.
+
+The audio subchannels that are returned are MONO for the +/- 1 MHz range around
+a valid channel frequency. When the frequency is within +/- 0.25 MHz of the
+channel it will return either MONO, STEREO, either MONO | SAP (for NTSC) or
+LANG1 | LANG2 (for others), or STEREO | SAP.
+
+Which one is returned depends on the chosen channel, each next valid channel
+will cycle through the possible audio subchannel combinations. This allows
+you to test the various combinations by just switching channels..
+
+Finally, for these inputs the v4l2_timecode struct is filled in in the
+dequeued v4l2_buffer struct.
+
+
+Section 2.3: HDMI Input
+-----------------------
+
+The HDMI inputs supports all CEA-861 and DMT timings, both progressive and
+interlaced, for pixelclock frequencies between 25 and 600 MHz. The field
+mode for interlaced formats is always V4L2_FIELD_ALTERNATE. For HDMI the
+field order is always top field first, and when you start capturing an
+interlaced format you will receive the top field first.
+
+The initially selected colorspace when you switch to the HDMI input or
+select an HDMI timing is based on the format resolution: for resolutions
+less than or equal to 720x576 the colorspace is set to SMPTE-170M, for
+others it is set to REC-709 (CEA-861 timings) or sRGB (VESA DMT timings).
+
+The pixel aspect ratio will depend on the HDMI timing: for 720x480 is it
+set as for the NTSC TV standard, for 720x576 it is set as for the PAL TV
+standard, and for all others a 1:1 pixel aspect ratio is returned.
+
+The video aspect ratio can be selected through the 'DV Timings Aspect Ratio'
+Vivid control. Choices are 'Source Width x Height' (just use the
+same ratio as the chosen format), '4x3' or '16x9', either of which can
+result in pillarboxed or letterboxed video.
+
+For HDMI inputs it is possible to set the EDID. By default a simple EDID
+is provided. You can only set the EDID for HDMI inputs. Internally, however,
+the EDID is shared between all HDMI inputs.
+
+No interpretation is done of the EDID data.
+
+
+Section 3: Video Output
+-----------------------
+
+The video output device can be configured by using the module options
+num_outputs, output_types and ccs_out_mode (see section 1 for more detailed
+information), but by default two outputs are configured: an S-Video and an
+HDMI input, one output for each output type. Those are described in more detail
+below.
+
+Like with video capture the framerate is also exact in the long term.
+
+
+Section 3.1: S-Video Output
+---------------------------
+
+This output supports audio outputs as well: "Line-Out 1" and "Line-Out 2".
+The S-Video output supports all TV standards.
+
+This output supports all combinations of the field setting.
+
+The initially selected colorspace when you switch to the TV or S-Video input
+will be SMPTE-170M.
+
+
+Section 3.2: HDMI Output
+------------------------
+
+The HDMI output supports all CEA-861 and DMT timings, both progressive and
+interlaced, for pixelclock frequencies between 25 and 600 MHz. The field
+mode for interlaced formats is always V4L2_FIELD_ALTERNATE.
+
+The initially selected colorspace when you switch to the HDMI output or
+select an HDMI timing is based on the format resolution: for resolutions
+less than or equal to 720x576 the colorspace is set to SMPTE-170M, for
+others it is set to REC-709 (CEA-861 timings) or sRGB (VESA DMT timings).
+
+The pixel aspect ratio will depend on the HDMI timing: for 720x480 is it
+set as for the NTSC TV standard, for 720x576 it is set as for the PAL TV
+standard, and for all others a 1:1 pixel aspect ratio is returned.
+
+An HDMI output has a valid EDID which can be obtained through VIDIOC_G_EDID.
+
+
+Section 4: VBI Capture
+----------------------
+
+There are three types of VBI capture devices: those that only support raw
+(undecoded) VBI, those that only support sliced (decoded) VBI and those that
+support both. This is determined by the node_types module option. In all
+cases the driver will generate valid VBI data: for 60 Hz standards it will
+generate Closed Caption and XDS data. The closed caption stream will
+alternate between "Hello world!" and "Closed captions test" every second.
+The XDS stream will give the current time once a minute. For 50 Hz standards
+it will generate the Wide Screen Signal which is based on the actual Video
+Aspect Ratio control setting and teletext pages 100-159, one page per frame.
+
+The VBI device will only work for the S-Video and TV inputs, it will give
+back an error if the current input is a webcam or HDMI.
+
+
+Section 5: VBI Output
+---------------------
+
+There are three types of VBI output devices: those that only support raw
+(undecoded) VBI, those that only support sliced (decoded) VBI and those that
+support both. This is determined by the node_types module option.
+
+The sliced VBI output supports the Wide Screen Signal and the teletext signal
+for 50 Hz standards and Closed Captioning + XDS for 60 Hz standards.
+
+The VBI device will only work for the S-Video output, it will give
+back an error if the current output is HDMI.
+
+
+Section 6: Radio Receiver
+-------------------------
+
+The radio receiver emulates an FM/AM/SW receiver. The FM band also supports RDS.
+The frequency ranges are:
+
+       FM: 64 MHz - 108 MHz
+       AM: 520 kHz - 1710 kHz
+       SW: 2300 kHz - 26.1 MHz
+
+Valid channels are emulated every 1 MHz for FM and every 100 kHz for AM and SW.
+The signal strength decreases the further the frequency is from the valid
+frequency until it becomes 0% at +/- 50 kHz (FM) or 5 kHz (AM/SW) from the
+ideal frequency. The initial frequency when the driver is loaded is set to
+95 MHz.
+
+The FM receiver supports RDS as well, both using 'Block I/O' and 'Controls'
+modes. In the 'Controls' mode the RDS information is stored in read-only
+controls. These controls are updated every time the frequency is changed,
+or when the tuner status is requested. The Block I/O method uses the read()
+interface to pass the RDS blocks on to the application for decoding.
+
+The RDS signal is 'detected' for +/- 12.5 kHz around the channel frequency,
+and the further the frequency is away from the valid frequency the more RDS
+errors are randomly introduced into the block I/O stream, up to 50% of all
+blocks if you are +/- 12.5 kHz from the channel frequency. All four errors
+can occur in equal proportions: blocks marked 'CORRECTED', blocks marked
+'ERROR', blocks marked 'INVALID' and dropped blocks.
+
+The generated RDS stream contains all the standard fields contained in a
+0B group, and also radio text and the current time.
+
+The receiver supports HW frequency seek, either in Bounded mode, Wrap Around
+mode or both, which is configurable with the "Radio HW Seek Mode" control.
+
+
+Section 7: Radio Transmitter
+----------------------------
+
+The radio transmitter emulates an FM/AM/SW transmitter. The FM band also supports RDS.
+The frequency ranges are:
+
+       FM: 64 MHz - 108 MHz
+       AM: 520 kHz - 1710 kHz
+       SW: 2300 kHz - 26.1 MHz
+
+The initial frequency when the driver is loaded is 95.5 MHz.
+
+The FM transmitter supports RDS as well, both using 'Block I/O' and 'Controls'
+modes. In the 'Controls' mode the transmitted RDS information is configured
+using controls, and in 'Block I/O' mode the blocks are passed to the driver
+using write().
+
+
+Section 8: Software Defined Radio Receiver
+------------------------------------------
+
+The SDR receiver has three frequency bands for the ADC tuner:
+
+       - 300 kHz
+       - 900 kHz - 2800 kHz
+       - 3200 kHz
+
+The RF tuner supports 50 MHz - 2000 MHz.
+
+The generated data contains the In-phase and Quadrature components of a
+1 kHz tone that has an amplitude of sqrt(2).
+
+
+Section 9: Controls
+-------------------
+
+Different devices support different controls. The sections below will describe
+each control and which devices support them.
+
+
+Section 9.1: User Controls - Test Controls
+------------------------------------------
+
+The Button, Boolean, Integer 32 Bits, Integer 64 Bits, Menu, String, Bitmask and
+Integer Menu are controls that represent all possible control types. The Menu
+control and the Integer Menu control both have 'holes' in their menu list,
+meaning that one or more menu items return EINVAL when VIDIOC_QUERYMENU is called.
+Both menu controls also have a non-zero minimum control value.  These features
+allow you to check if your application can handle such things correctly.
+These controls are supported for every device type.
+
+
+Section 9.2: User Controls - Video Capture
+------------------------------------------
+
+The following controls are specific to video capture.
+
+The Brightness, Contrast, Saturation and Hue controls actually work and are
+standard. There is one special feature with the Brightness control: each
+video input has its own brightness value, so changing input will restore
+the brightness for that input. In addition, each video input uses a different
+brightness range (minimum and maximum control values). Switching inputs will
+cause a control event to be sent with the V4L2_EVENT_CTRL_CH_RANGE flag set.
+This allows you to test controls that can change their range.
+
+The 'Gain, Automatic' and Gain controls can be used to test volatile controls:
+if 'Gain, Automatic' is set, then the Gain control is volatile and changes
+constantly. If 'Gain, Automatic' is cleared, then the Gain control is a normal
+control.
+
+The 'Horizontal Flip' and 'Vertical Flip' controls can be used to flip the
+image. These combine with the 'Sensor Flipped Horizontally/Vertically' Vivid
+controls.
+
+The 'Alpha Component' control can be used to set the alpha component for
+formats containing an alpha channel.
+
+
+Section 9.3: User Controls - Audio
+----------------------------------
+
+The following controls are specific to video capture and output and radio
+receivers and transmitters.
+
+The 'Volume' and 'Mute' audio controls are typical for such devices to
+control the volume and mute the audio. They don't actually do anything in
+the vivid driver.
+
+
+Section 9.4: Vivid Controls
+---------------------------
+
+These vivid custom controls control the image generation, error injection, etc.
+
+
+Section 9.4.1: Test Pattern Controls
+------------------------------------
+
+The Test Pattern Controls are all specific to video capture.
+
+Test Pattern: selects which test pattern to use. Use the CSC Colorbar for
+       testing colorspace conversions: the colors used in that test pattern
+       map to valid colors in all colorspaces. The colorspace conversion
+       is disabled for the other test patterns.
+
+OSD Text Mode: selects whether the text superimposed on the
+       test pattern should be shown, and if so, whether only counters should
+       be displayed or the full text.
+
+Horizontal Movement: selects whether the test pattern should
+       move to the left or right and at what speed.
+
+Vertical Movement: does the same for the vertical direction.
+
+Show Border: show a two-pixel wide border at the edge of the actual image,
+       excluding letter or pillarboxing.
+
+Show Square: show a square in the middle of the image. If the image is
+       displayed with the correct pixel and image aspect ratio corrections,
+       then the width and height of the square on the monitor should be
+       the same.
+
+Insert SAV Code in Image: adds a SAV (Start of Active Video) code to the image.
+       This can be used to check if such codes in the image are inadvertently
+       interpreted instead of being ignored.
+
+Insert EAV Code in Image: does the same for the EAV (End of Active Video) code.
+
+
+Section 9.4.2: Capture Feature Selection Controls
+-------------------------------------------------
+
+These controls are all specific to video capture.
+
+Sensor Flipped Horizontally: the image is flipped horizontally and the
+       V4L2_IN_ST_HFLIP input status flag is set. This emulates the case where
+       a sensor is for example mounted upside down.
+
+Sensor Flipped Vertically: the image is flipped vertically and the
+       V4L2_IN_ST_VFLIP input status flag is set. This emulates the case where
+        a sensor is for example mounted upside down.
+
+Standard Aspect Ratio: selects if the image aspect ratio as used for the TV or
+       S-Video input should be 4x3, 16x9 or anamorphic widescreen. This may
+       introduce letterboxing.
+
+DV Timings Aspect Ratio: selects if the image aspect ratio as used for the HDMI
+       input should be the same as the source width and height ratio, or if
+       it should be 4x3 or 16x9. This may introduce letter or pillarboxing.
+
+Timestamp Source: selects when the timestamp for each buffer is taken.
+
+Colorspace: selects which colorspace should be used when generating the image.
+       This only applies if the CSC Colorbar test pattern is selected,
+       otherwise the test pattern will go through unconverted (except for
+       the so-called 'Transfer Function' corrections and the R'G'B' to Y'CbCr
+       conversion). This behavior is also what you want, since a 75% Colorbar
+       should really have 75% signal intensity and should not be affected
+       by colorspace conversions.
+
+       Changing the colorspace will result in the V4L2_EVENT_SOURCE_CHANGE
+       to be sent since it emulates a detected colorspace change.
+
+Limited RGB Range (16-235): selects if the RGB range of the HDMI source should
+       be limited or full range. This combines with the Digital Video 'Rx RGB
+       Quantization Range' control and can be used to test what happens if
+       a source provides you with the wrong quantization range information.
+       See the description of that control for more details.
+
+Apply Alpha To Red Only: apply the alpha channel as set by the 'Alpha Component'
+       user control to the red color of the test pattern only.
+
+Enable Capture Cropping: enables crop support. This control is only present if
+       the ccs_cap_mode module option is set to the default value of -1 and if
+       the no_error_inj module option is set to 0 (the default).
+
+Enable Capture Composing: enables composing support. This control is only
+       present if the ccs_cap_mode module option is set to the default value of
+       -1 and if the no_error_inj module option is set to 0 (the default).
+
+Enable Capture Scaler: enables support for a scaler (maximum 4 times upscaling
+       and downscaling). This control is only present if the ccs_cap_mode
+       module option is set to the default value of -1 and if the no_error_inj
+       module option is set to 0 (the default).
+
+Maximum EDID Blocks: determines how many EDID blocks the driver supports.
+       Note that the vivid driver does not actually interpret new EDID
+       data, it just stores it. It allows for up to 256 EDID blocks
+       which is the maximum supported by the standard.
+
+Fill Percentage of Frame: can be used to draw only the top X percent
+       of the image. Since each frame has to be drawn by the driver, this
+       demands a lot of the CPU. For large resolutions this becomes
+       problematic. By drawing only part of the image this CPU load can
+       be reduced.
+
+
+Section 9.4.3: Output Feature Selection Controls
+------------------------------------------------
+
+These controls are all specific to video output.
+
+Enable Output Cropping: enables crop support. This control is only present if
+       the ccs_out_mode module option is set to the default value of -1 and if
+       the no_error_inj module option is set to 0 (the default).
+
+Enable Output Composing: enables composing support. This control is only
+       present if the ccs_out_mode module option is set to the default value of
+       -1 and if the no_error_inj module option is set to 0 (the default).
+
+Enable Output Scaler: enables support for a scaler (maximum 4 times upscaling
+       and downscaling). This control is only present if the ccs_out_mode
+       module option is set to the default value of -1 and if the no_error_inj
+       module option is set to 0 (the default).
+
+
+Section 9.4.4: Error Injection Controls
+---------------------------------------
+
+The following two controls are only valid for video and vbi capture.
+
+Standard Signal Mode: selects the behavior of VIDIOC_QUERYSTD: what should
+       it return?
+
+       Changing this control will result in the V4L2_EVENT_SOURCE_CHANGE
+       to be sent since it emulates a changed input condition (e.g. a cable
+       was plugged in or out).
+
+Standard: selects the standard that VIDIOC_QUERYSTD should return if the
+       previous control is set to "Selected Standard".
+
+       Changing this control will result in the V4L2_EVENT_SOURCE_CHANGE
+       to be sent since it emulates a changed input standard.
+
+
+The following two controls are only valid for video capture.
+
+DV Timings Signal Mode: selects the behavior of VIDIOC_QUERY_DV_TIMINGS: what
+       should it return?
+
+       Changing this control will result in the V4L2_EVENT_SOURCE_CHANGE
+       to be sent since it emulates a changed input condition (e.g. a cable
+       was plugged in or out).
+
+DV Timings: selects the timings the VIDIOC_QUERY_DV_TIMINGS should return
+       if the previous control is set to "Selected DV Timings".
+
+       Changing this control will result in the V4L2_EVENT_SOURCE_CHANGE
+       to be sent since it emulates changed input timings.
+
+
+The following controls are only present if the no_error_inj module option
+is set to 0 (the default). These controls are valid for video and vbi
+capture and output streams and for the SDR capture device except for the
+Disconnect control which is valid for all devices.
+
+Wrap Sequence Number: test what happens when you wrap the sequence number in
+       struct v4l2_buffer around.
+
+Wrap Timestamp: test what happens when you wrap the timestamp in struct
+       v4l2_buffer around.
+
+Percentage of Dropped Buffers: sets the percentage of buffers that
+       are never returned by the driver (i.e., they are dropped).
+
+Disconnect: emulates a USB disconnect. The device will act as if it has
+       been disconnected. Only after all open filehandles to the device
+       node have been closed will the device become 'connected' again.
+
+Inject V4L2_BUF_FLAG_ERROR: when pressed, the next frame returned by
+       the driver will have the error flag set (i.e. the frame is marked
+       corrupt).
+
+Inject VIDIOC_REQBUFS Error: when pressed, the next REQBUFS or CREATE_BUFS
+       ioctl call will fail with an error. To be precise: the videobuf2
+       queue_setup() op will return -EINVAL.
+
+Inject VIDIOC_QBUF Error: when pressed, the next VIDIOC_QBUF or
+       VIDIOC_PREPARE_BUFFER ioctl call will fail with an error. To be
+       precise: the videobuf2 buf_prepare() op will return -EINVAL.
+
+Inject VIDIOC_STREAMON Error: when pressed, the next VIDIOC_STREAMON ioctl
+       call will fail with an error. To be precise: the videobuf2
+       start_streaming() op will return -EINVAL.
+
+Inject Fatal Streaming Error: when pressed, the streaming core will be
+       marked as having suffered a fatal error, the only way to recover
+       from that is to stop streaming. To be precise: the videobuf2
+       vb2_queue_error() function is called.
+
+
+Section 9.4.5: VBI Raw Capture Controls
+---------------------------------------
+
+Interlaced VBI Format: if set, then the raw VBI data will be interlaced instead
+       of providing it grouped by field.
+
+
+Section 9.5: Digital Video Controls
+-----------------------------------
+
+Rx RGB Quantization Range: sets the RGB quantization detection of the HDMI
+       input. This combines with the Vivid 'Limited RGB Range (16-235)'
+       control and can be used to test what happens if a source provides
+       you with the wrong quantization range information. This can be tested
+       by selecting an HDMI input, setting this control to Full or Limited
+       range and selecting the opposite in the 'Limited RGB Range (16-235)'
+       control. The effect is easy to see if the 'Gray Ramp' test pattern
+       is selected.
+
+Tx RGB Quantization Range: sets the RGB quantization detection of the HDMI
+       output. It is currently not used for anything in vivid, but most HDMI
+       transmitters would typically have this control.
+
+Transmit Mode: sets the transmit mode of the HDMI output to HDMI or DVI-D. This
+       affects the reported colorspace since DVI_D outputs will always use
+       sRGB.
+
+
+Section 9.6: FM Radio Receiver Controls
+---------------------------------------
+
+RDS Reception: set if the RDS receiver should be enabled.
+
+RDS Program Type:
+RDS PS Name:
+RDS Radio Text:
+RDS Traffic Announcement:
+RDS Traffic Program:
+RDS Music: these are all read-only controls. If RDS Rx I/O Mode is set to
+       "Block I/O", then they are inactive as well. If RDS Rx I/O Mode is set
+       to "Controls", then these controls report the received RDS data. Note
+       that the vivid implementation of this is pretty basic: they are only
+       updated when you set a new frequency or when you get the tuner status
+       (VIDIOC_G_TUNER).
+
+Radio HW Seek Mode: can be one of "Bounded", "Wrap Around" or "Both". This
+       determines if VIDIOC_S_HW_FREQ_SEEK will be bounded by the frequency
+       range or wrap-around or if it is selectable by the user.
+
+Radio Programmable HW Seek: if set, then the user can provide the lower and
+       upper bound of the HW Seek. Otherwise the frequency range boundaries
+       will be used.
+
+Generate RBDS Instead of RDS: if set, then generate RBDS (the US variant of
+       RDS) data instead of RDS (European-style RDS). This affects only the
+       PICODE and PTY codes.
+
+RDS Rx I/O Mode: this can be "Block I/O" where the RDS blocks have to be read()
+       by the application, or "Controls" where the RDS data is provided by
+       the RDS controls mentioned above.
+
+
+Section 9.7: FM Radio Modulator Controls
+----------------------------------------
+
+RDS Program ID:
+RDS Program Type:
+RDS PS Name:
+RDS Radio Text:
+RDS Stereo:
+RDS Artificial Head:
+RDS Compressed:
+RDS Dymanic PTY:
+RDS Traffic Announcement:
+RDS Traffic Program:
+RDS Music: these are all controls that set the RDS data that is transmitted by
+       the FM modulator.
+
+RDS Tx I/O Mode: this can be "Block I/O" where the application has to use write()
+       to pass the RDS blocks to the driver, or "Controls" where the RDS data is
+       provided by the RDS controls mentioned above.
+
+
+Section 10: Video, VBI and RDS Looping
+--------------------------------------
+
+The vivid driver supports looping of video output to video input, VBI output
+to VBI input and RDS output to RDS input. For video/VBI looping this emulates
+as if a cable was hooked up between the output and input connector. So video
+and VBI looping is only supported between S-Video and HDMI inputs and outputs.
+VBI is only valid for S-Video as it makes no sense for HDMI.
+
+Since radio is wireless this looping always happens if the radio receiver
+frequency is close to the radio transmitter frequency. In that case the radio
+transmitter will 'override' the emulated radio stations.
+
+Looping is currently supported only between devices created by the same
+vivid driver instance.
+
+
+Section 10.1: Video and Sliced VBI looping
+------------------------------------------
+
+The way to enable video/VBI looping is currently fairly crude. A 'Loop Video'
+control is available in the "Vivid" control class of the video
+output and VBI output devices. When checked the video looping will be enabled.
+Once enabled any video S-Video or HDMI input will show a static test pattern
+until the video output has started. At that time the video output will be
+looped to the video input provided that:
+
+- the input type matches the output type. So the HDMI input cannot receive
+  video from the S-Video output.
+
+- the video resolution of the video input must match that of the video output.
+  So it is not possible to loop a 50 Hz (720x576) S-Video output to a 60 Hz
+  (720x480) S-Video input, or a 720p60 HDMI output to a 1080p30 input.
+
+- the pixel formats must be identical on both sides. Otherwise the driver would
+  have to do pixel format conversion as well, and that's taking things too far.
+
+- the field settings must be identical on both sides. Same reason as above:
+  requiring the driver to convert from one field format to another complicated
+  matters too much. This also prohibits capturing with 'Field Top' or 'Field
+  Bottom' when the output video is set to 'Field Alternate'. This combination,
+  while legal, became too complicated to support. Both sides have to be 'Field
+  Alternate' for this to work. Also note that for this specific case the
+  sequence and field counting in struct v4l2_buffer on the capture side may not
+  be 100% accurate.
+
+- on the input side the "Standard Signal Mode" for the S-Video input or the
+  "DV Timings Signal Mode" for the HDMI input should be configured so that a
+  valid signal is passed to the video input.
+
+The framerates do not have to match, although this might change in the future.
+
+By default you will see the OSD text superimposed on top of the looped video.
+This can be turned off by changing the "OSD Text Mode" control of the video
+capture device.
+
+For VBI looping to work all of the above must be valid and in addition the vbi
+output must be configured for sliced VBI. The VBI capture side can be configured
+for either raw or sliced VBI. Note that at the moment only CC/XDS (60 Hz formats)
+and WSS (50 Hz formats) VBI data is looped. Teletext VBI data is not looped.
+
+
+Section 10.2: Radio & RDS Looping
+---------------------------------
+
+As mentioned in section 6 the radio receiver emulates stations are regular
+frequency intervals. Depending on the frequency of the radio receiver a
+signal strength value is calculated (this is returned by VIDIOC_G_TUNER).
+However, it will also look at the frequency set by the radio transmitter and
+if that results in a higher signal strength than the settings of the radio
+transmitter will be used as if it was a valid station. This also includes
+the RDS data (if any) that the transmitter 'transmits'. This is received
+faithfully on the receiver side. Note that when the driver is loaded the
+frequencies of the radio receiver and transmitter are not identical, so
+initially no looping takes place.
+
+
+Section 11: Cropping, Composing, Scaling
+----------------------------------------
+
+This driver supports cropping, composing and scaling in any combination. Normally
+which features are supported can be selected through the Vivid controls,
+but it is also possible to hardcode it when the module is loaded through the
+ccs_cap_mode and ccs_out_mode module options. See section 1 on the details of
+these module options.
+
+This allows you to test your application for all these variations.
+
+Note that the webcam input never supports cropping, composing or scaling. That
+only applies to the TV/S-Video/HDMI inputs and outputs. The reason is that
+webcams, including this virtual implementation, normally use
+VIDIOC_ENUM_FRAMESIZES to list a set of discrete framesizes that it supports.
+And that does not combine with cropping, composing or scaling. This is
+primarily a limitation of the V4L2 API which is carefully reproduced here.
+
+The minimum and maximum resolutions that the scaler can achieve are 16x16 and
+(4096 * 4) x (2160 x 4), but it can only scale up or down by a factor of 4 or
+less. So for a source resolution of 1280x720 the minimum the scaler can do is
+320x180 and the maximum is 5120x2880. You can play around with this using the
+qv4l2 test tool and you will see these dependencies.
+
+This driver also supports larger 'bytesperline' settings, something that
+VIDIOC_S_FMT allows but that few drivers implement.
+
+The scaler is a simple scaler that uses the Coarse Bresenham algorithm. It's
+designed for speed and simplicity, not quality.
+
+If the combination of crop, compose and scaling allows it, then it is possible
+to change crop and compose rectangles on the fly.
+
+
+Section 12: Formats
+-------------------
+
+The driver supports all the regular packed YUYV formats, 16, 24 and 32 RGB
+packed formats and two multiplanar formats (one luma and one chroma plane).
+
+The alpha component can be set through the 'Alpha Component' User control
+for those formats that support it. If the 'Apply Alpha To Red Only' control
+is set, then the alpha component is only used for the color red and set to
+0 otherwise.
+
+The driver has to be configured to support the multiplanar formats. By default
+the first driver instance is single-planar, the second is multi-planar, and it
+keeps alternating. This can be changed by setting the multiplanar module option,
+see section 1 for more details on that option.
+
+If the driver instance is using the multiplanar formats/API, then the first
+single planar format (YUYV) and the multiplanar NV16M and NV61M formats the
+will have a plane that has a non-zero data_offset of 128 bytes. It is rare for
+data_offset to be non-zero, so this is a useful feature for testing applications.
+
+Video output will also honor any data_offset that the application set.
+
+
+Section 13: Capture Overlay
+---------------------------
+
+Note: capture overlay support is implemented primarily to test the existing
+V4L2 capture overlay API. In practice few if any GPUs support such overlays
+anymore, and neither are they generally needed anymore since modern hardware
+is so much more capable. By setting flag 0x10000 in the node_types module
+option the vivid driver will create a simple framebuffer device that can be
+used for testing this API. Whether this API should be used for new drivers is
+questionable.
+
+This driver has support for a destructive capture overlay with bitmap clipping
+and list clipping (up to 16 rectangles) capabilities. Overlays are not
+supported for multiplanar formats. It also honors the struct v4l2_window field
+setting: if it is set to FIELD_TOP or FIELD_BOTTOM and the capture setting is
+FIELD_ALTERNATE, then only the top or bottom fields will be copied to the overlay.
+
+The overlay only works if you are also capturing at that same time. This is a
+vivid limitation since it copies from a buffer to the overlay instead of
+filling the overlay directly. And if you are not capturing, then no buffers
+are available to fill.
+
+In addition, the pixelformat of the capture format and that of the framebuffer
+must be the same for the overlay to work. Otherwise VIDIOC_OVERLAY will return
+an error.
+
+In order to really see what it going on you will need to create two vivid
+instances: the first with a framebuffer enabled. You configure the capture
+overlay of the second instance to use the framebuffer of the first, then
+you start capturing in the second instance. For the first instance you setup
+the output overlay for the video output, turn on video looping and capture
+to see the blended framebuffer overlay that's being written to by the second
+instance. This setup would require the following commands:
+
+       $ sudo modprobe vivid n_devs=2 node_types=0x10101,0x1 multiplanar=1,1
+       $ v4l2-ctl -d1 --find-fb
+       /dev/fb1 is the framebuffer associated with base address 0x12800000
+       $ sudo v4l2-ctl -d2 --set-fbuf fb=1
+       $ v4l2-ctl -d1 --set-fbuf fb=1
+       $ v4l2-ctl -d0 --set-fmt-video=pixelformat='AR15'
+       $ v4l2-ctl -d1 --set-fmt-video-out=pixelformat='AR15'
+       $ v4l2-ctl -d2 --set-fmt-video=pixelformat='AR15'
+       $ v4l2-ctl -d0 -i2
+       $ v4l2-ctl -d2 -i2
+       $ v4l2-ctl -d2 -c horizontal_movement=4
+       $ v4l2-ctl -d1 --overlay=1
+       $ v4l2-ctl -d1 -c loop_video=1
+       $ v4l2-ctl -d2 --stream-mmap --overlay=1
+
+And from another console:
+
+       $ v4l2-ctl -d1 --stream-out-mmap
+
+And yet another console:
+
+       $ qv4l2
+
+and start streaming.
+
+As you can see, this is not for the faint of heart...
+
+
+Section 14: Output Overlay
+--------------------------
+
+Note: output overlays are primarily implemented in order to test the existing
+V4L2 output overlay API. Whether this API should be used for new drivers is
+questionable.
+
+This driver has support for an output overlay and is capable of:
+
+       - bitmap clipping,
+       - list clipping (up to 16 rectangles)
+       - chromakey
+       - source chromakey
+       - global alpha
+       - local alpha
+       - local inverse alpha
+
+Output overlays are not supported for multiplanar formats. In addition, the
+pixelformat of the capture format and that of the framebuffer must be the
+same for the overlay to work. Otherwise VIDIOC_OVERLAY will return an error.
+
+Output overlays only work if the driver has been configured to create a
+framebuffer by setting flag 0x10000 in the node_types module option. The
+created framebuffer has a size of 720x576 and supports ARGB 1:5:5:5 and
+RGB 5:6:5.
+
+In order to see the effects of the various clipping, chromakeying or alpha
+processing capabilities you need to turn on video looping and see the results
+on the capture side. The use of the clipping, chromakeying or alpha processing
+capabilities will slow down the video loop considerably as a lot of checks have
+to be done per pixel.
+
+
+Section 15: Some Future Improvements
+------------------------------------
+
+Just as a reminder and in no particular order:
+
+- Add a virtual alsa driver to test audio
+- Add virtual sub-devices and media controller support
+- Some support for testing compressed video
+- Add support to loop raw VBI output to raw VBI input
+- Add support to loop teletext sliced VBI output to VBI input
+- Fix sequence/field numbering when looping of video with alternate fields
+- Add support for V4L2_CID_BG_COLOR for video outputs
+- Add ARGB888 overlay support: better testing of the alpha channel
+- Add custom DV timings support
+- Add support for V4L2_DV_FL_REDUCED_FPS
+- Improve pixel aspect support in the tpg code by passing a real v4l2_fract
+- Use per-queue locks and/or per-device locks to improve throughput
+- Add support to loop from a specific output to a specific input across
+  vivid instances
+- Add support for VIDIOC_EXPBUF once support for that has been added to vb2
+- The SDR radio should use the same 'frequencies' for stations as the normal
+  radio receiver, and give back noise if the frequency doesn't match up with
+  a station frequency
+- Improve the sine generation of the SDR radio.
+- Make a thread for the RDS generation, that would help in particular for the
+  "Controls" RDS Rx I/O Mode as the read-only RDS controls could be updated
+  in real-time.
diff --git a/Documentation/ww-mutex-design.txt b/Documentation/ww-mutex-design.txt
deleted file mode 100644 (file)
index 8a112dc..0000000
+++ /dev/null
@@ -1,344 +0,0 @@
-Wait/Wound Deadlock-Proof Mutex Design
-======================================
-
-Please read mutex-design.txt first, as it applies to wait/wound mutexes too.
-
-Motivation for WW-Mutexes
--------------------------
-
-GPU's do operations that commonly involve many buffers.  Those buffers
-can be shared across contexts/processes, exist in different memory
-domains (for example VRAM vs system memory), and so on.  And with
-PRIME / dmabuf, they can even be shared across devices.  So there are
-a handful of situations where the driver needs to wait for buffers to
-become ready.  If you think about this in terms of waiting on a buffer
-mutex for it to become available, this presents a problem because
-there is no way to guarantee that buffers appear in a execbuf/batch in
-the same order in all contexts.  That is directly under control of
-userspace, and a result of the sequence of GL calls that an application
-makes. Which results in the potential for deadlock.  The problem gets
-more complex when you consider that the kernel may need to migrate the
-buffer(s) into VRAM before the GPU operates on the buffer(s), which
-may in turn require evicting some other buffers (and you don't want to
-evict other buffers which are already queued up to the GPU), but for a
-simplified understanding of the problem you can ignore this.
-
-The algorithm that the TTM graphics subsystem came up with for dealing with
-this problem is quite simple.  For each group of buffers (execbuf) that need
-to be locked, the caller would be assigned a unique reservation id/ticket,
-from a global counter.  In case of deadlock while locking all the buffers
-associated with a execbuf, the one with the lowest reservation ticket (i.e.
-the oldest task) wins, and the one with the higher reservation id (i.e. the
-younger task) unlocks all of the buffers that it has already locked, and then
-tries again.
-
-In the RDBMS literature this deadlock handling approach is called wait/wound:
-The older tasks waits until it can acquire the contended lock. The younger tasks
-needs to back off and drop all the locks it is currently holding, i.e. the
-younger task is wounded.
-
-Concepts
---------
-
-Compared to normal mutexes two additional concepts/objects show up in the lock
-interface for w/w mutexes:
-
-Acquire context: To ensure eventual forward progress it is important the a task
-trying to acquire locks doesn't grab a new reservation id, but keeps the one it
-acquired when starting the lock acquisition. This ticket is stored in the
-acquire context. Furthermore the acquire context keeps track of debugging state
-to catch w/w mutex interface abuse.
-
-W/w class: In contrast to normal mutexes the lock class needs to be explicit for
-w/w mutexes, since it is required to initialize the acquire context.
-
-Furthermore there are three different class of w/w lock acquire functions:
-
-* Normal lock acquisition with a context, using ww_mutex_lock.
-
-* Slowpath lock acquisition on the contending lock, used by the wounded task
-  after having dropped all already acquired locks. These functions have the
-  _slow postfix.
-
-  From a simple semantics point-of-view the _slow functions are not strictly
-  required, since simply calling the normal ww_mutex_lock functions on the
-  contending lock (after having dropped all other already acquired locks) will
-  work correctly. After all if no other ww mutex has been acquired yet there's
-  no deadlock potential and hence the ww_mutex_lock call will block and not
-  prematurely return -EDEADLK. The advantage of the _slow functions is in
-  interface safety:
-  - ww_mutex_lock has a __must_check int return type, whereas ww_mutex_lock_slow
-    has a void return type. Note that since ww mutex code needs loops/retries
-    anyway the __must_check doesn't result in spurious warnings, even though the
-    very first lock operation can never fail.
-  - When full debugging is enabled ww_mutex_lock_slow checks that all acquired
-    ww mutex have been released (preventing deadlocks) and makes sure that we
-    block on the contending lock (preventing spinning through the -EDEADLK
-    slowpath until the contended lock can be acquired).
-
-* Functions to only acquire a single w/w mutex, which results in the exact same
-  semantics as a normal mutex. This is done by calling ww_mutex_lock with a NULL
-  context.
-
-  Again this is not strictly required. But often you only want to acquire a
-  single lock in which case it's pointless to set up an acquire context (and so
-  better to avoid grabbing a deadlock avoidance ticket).
-
-Of course, all the usual variants for handling wake-ups due to signals are also
-provided.
-
-Usage
------
-
-Three different ways to acquire locks within the same w/w class. Common
-definitions for methods #1 and #2:
-
-static DEFINE_WW_CLASS(ww_class);
-
-struct obj {
-       struct ww_mutex lock;
-       /* obj data */
-};
-
-struct obj_entry {
-       struct list_head head;
-       struct obj *obj;
-};
-
-Method 1, using a list in execbuf->buffers that's not allowed to be reordered.
-This is useful if a list of required objects is already tracked somewhere.
-Furthermore the lock helper can use propagate the -EALREADY return code back to
-the caller as a signal that an object is twice on the list. This is useful if
-the list is constructed from userspace input and the ABI requires userspace to
-not have duplicate entries (e.g. for a gpu commandbuffer submission ioctl).
-
-int lock_objs(struct list_head *list, struct ww_acquire_ctx *ctx)
-{
-       struct obj *res_obj = NULL;
-       struct obj_entry *contended_entry = NULL;
-       struct obj_entry *entry;
-
-       ww_acquire_init(ctx, &ww_class);
-
-retry:
-       list_for_each_entry (entry, list, head) {
-               if (entry->obj == res_obj) {
-                       res_obj = NULL;
-                       continue;
-               }
-               ret = ww_mutex_lock(&entry->obj->lock, ctx);
-               if (ret < 0) {
-                       contended_entry = entry;
-                       goto err;
-               }
-       }
-
-       ww_acquire_done(ctx);
-       return 0;
-
-err:
-       list_for_each_entry_continue_reverse (entry, list, head)
-               ww_mutex_unlock(&entry->obj->lock);
-
-       if (res_obj)
-               ww_mutex_unlock(&res_obj->lock);
-
-       if (ret == -EDEADLK) {
-               /* we lost out in a seqno race, lock and retry.. */
-               ww_mutex_lock_slow(&contended_entry->obj->lock, ctx);
-               res_obj = contended_entry->obj;
-               goto retry;
-       }
-       ww_acquire_fini(ctx);
-
-       return ret;
-}
-
-Method 2, using a list in execbuf->buffers that can be reordered. Same semantics
-of duplicate entry detection using -EALREADY as method 1 above. But the
-list-reordering allows for a bit more idiomatic code.
-
-int lock_objs(struct list_head *list, struct ww_acquire_ctx *ctx)
-{
-       struct obj_entry *entry, *entry2;
-
-       ww_acquire_init(ctx, &ww_class);
-
-       list_for_each_entry (entry, list, head) {
-               ret = ww_mutex_lock(&entry->obj->lock, ctx);
-               if (ret < 0) {
-                       entry2 = entry;
-
-                       list_for_each_entry_continue_reverse (entry2, list, head)
-                               ww_mutex_unlock(&entry2->obj->lock);
-
-                       if (ret != -EDEADLK) {
-                               ww_acquire_fini(ctx);
-                               return ret;
-                       }
-
-                       /* we lost out in a seqno race, lock and retry.. */
-                       ww_mutex_lock_slow(&entry->obj->lock, ctx);
-
-                       /*
-                        * Move buf to head of the list, this will point
-                        * buf->next to the first unlocked entry,
-                        * restarting the for loop.
-                        */
-                       list_del(&entry->head);
-                       list_add(&entry->head, list);
-               }
-       }
-
-       ww_acquire_done(ctx);
-       return 0;
-}
-
-Unlocking works the same way for both methods #1 and #2:
-
-void unlock_objs(struct list_head *list, struct ww_acquire_ctx *ctx)
-{
-       struct obj_entry *entry;
-
-       list_for_each_entry (entry, list, head)
-               ww_mutex_unlock(&entry->obj->lock);
-
-       ww_acquire_fini(ctx);
-}
-
-Method 3 is useful if the list of objects is constructed ad-hoc and not upfront,
-e.g. when adjusting edges in a graph where each node has its own ww_mutex lock,
-and edges can only be changed when holding the locks of all involved nodes. w/w
-mutexes are a natural fit for such a case for two reasons:
-- They can handle lock-acquisition in any order which allows us to start walking
-  a graph from a starting point and then iteratively discovering new edges and
-  locking down the nodes those edges connect to.
-- Due to the -EALREADY return code signalling that a given objects is already
-  held there's no need for additional book-keeping to break cycles in the graph
-  or keep track off which looks are already held (when using more than one node
-  as a starting point).
-
-Note that this approach differs in two important ways from the above methods:
-- Since the list of objects is dynamically constructed (and might very well be
-  different when retrying due to hitting the -EDEADLK wound condition) there's
-  no need to keep any object on a persistent list when it's not locked. We can
-  therefore move the list_head into the object itself.
-- On the other hand the dynamic object list construction also means that the -EALREADY return
-  code can't be propagated.
-
-Note also that methods #1 and #2 and method #3 can be combined, e.g. to first lock a
-list of starting nodes (passed in from userspace) using one of the above
-methods. And then lock any additional objects affected by the operations using
-method #3 below. The backoff/retry procedure will be a bit more involved, since
-when the dynamic locking step hits -EDEADLK we also need to unlock all the
-objects acquired with the fixed list. But the w/w mutex debug checks will catch
-any interface misuse for these cases.
-
-Also, method 3 can't fail the lock acquisition step since it doesn't return
--EALREADY. Of course this would be different when using the _interruptible
-variants, but that's outside of the scope of these examples here.
-
-struct obj {
-       struct ww_mutex ww_mutex;
-       struct list_head locked_list;
-};
-
-static DEFINE_WW_CLASS(ww_class);
-
-void __unlock_objs(struct list_head *list)
-{
-       struct obj *entry, *temp;
-
-       list_for_each_entry_safe (entry, temp, list, locked_list) {
-               /* need to do that before unlocking, since only the current lock holder is
-               allowed to use object */
-               list_del(&entry->locked_list);
-               ww_mutex_unlock(entry->ww_mutex)
-       }
-}
-
-void lock_objs(struct list_head *list, struct ww_acquire_ctx *ctx)
-{
-       struct obj *obj;
-
-       ww_acquire_init(ctx, &ww_class);
-
-retry:
-       /* re-init loop start state */
-       loop {
-               /* magic code which walks over a graph and decides which objects
-                * to lock */
-
-               ret = ww_mutex_lock(obj->ww_mutex, ctx);
-               if (ret == -EALREADY) {
-                       /* we have that one already, get to the next object */
-                       continue;
-               }
-               if (ret == -EDEADLK) {
-                       __unlock_objs(list);
-
-                       ww_mutex_lock_slow(obj, ctx);
-                       list_add(&entry->locked_list, list);
-                       goto retry;
-               }
-
-               /* locked a new object, add it to the list */
-               list_add_tail(&entry->locked_list, list);
-       }
-
-       ww_acquire_done(ctx);
-       return 0;
-}
-
-void unlock_objs(struct list_head *list, struct ww_acquire_ctx *ctx)
-{
-       __unlock_objs(list);
-       ww_acquire_fini(ctx);
-}
-
-Method 4: Only lock one single objects. In that case deadlock detection and
-prevention is obviously overkill, since with grabbing just one lock you can't
-produce a deadlock within just one class. To simplify this case the w/w mutex
-api can be used with a NULL context.
-
-Implementation Details
-----------------------
-
-Design:
-  ww_mutex currently encapsulates a struct mutex, this means no extra overhead for
-  normal mutex locks, which are far more common. As such there is only a small
-  increase in code size if wait/wound mutexes are not used.
-
-  In general, not much contention is expected. The locks are typically used to
-  serialize access to resources for devices. The only way to make wakeups
-  smarter would be at the cost of adding a field to struct mutex_waiter. This
-  would add overhead to all cases where normal mutexes are used, and
-  ww_mutexes are generally less performance sensitive.
-
-Lockdep:
-  Special care has been taken to warn for as many cases of api abuse
-  as possible. Some common api abuses will be caught with
-  CONFIG_DEBUG_MUTEXES, but CONFIG_PROVE_LOCKING is recommended.
-
-  Some of the errors which will be warned about:
-   - Forgetting to call ww_acquire_fini or ww_acquire_init.
-   - Attempting to lock more mutexes after ww_acquire_done.
-   - Attempting to lock the wrong mutex after -EDEADLK and
-     unlocking all mutexes.
-   - Attempting to lock the right mutex after -EDEADLK,
-     before unlocking all mutexes.
-
-   - Calling ww_mutex_lock_slow before -EDEADLK was returned.
-
-   - Unlocking mutexes with the wrong unlock function.
-   - Calling one of the ww_acquire_* twice on the same context.
-   - Using a different ww_class for the mutex than for the ww_acquire_ctx.
-   - Normal lockdep errors that can result in deadlocks.
-
-  Some of the lockdep errors that can result in deadlocks:
-   - Calling ww_acquire_init to initialize a second ww_acquire_ctx before
-     having called ww_acquire_fini on the first.
-   - 'normal' deadlocks that can occur.
-
-FIXME: Update this section once we have the TASK_DEADLOCK task state flag magic
-implemented.
index afe68ddbe6a474667aac1684367274754a0189fd..052ee643a32ee2c9c44cc75af6abeb9bd97040d5 100644 (file)
@@ -5,7 +5,7 @@ Virtual memory map with 4 level page tables:
 
 0000000000000000 - 00007fffffffffff (=47 bits) user space, different per mm
 hole caused by [48:63] sign extension
-ffff800000000000 - ffff80ffffffffff (=40 bits) guard hole
+ffff800000000000 - ffff87ffffffffff (=43 bits) guard hole, reserved for hypervisor
 ffff880000000000 - ffffc7ffffffffff (=64 TB) direct mapping of all phys. memory
 ffffc80000000000 - ffffc8ffffffffff (=40 bits) hole
 ffffc90000000000 - ffffe8ffffffffff (=45 bits) vmalloc/ioremap space
index 40d4796886c9ba7f5225701286dc4c37970f6b0b..ee1bc5bc20ad221d3d2af470ae2b55f2daf76db0 100644 (file)
@@ -734,7 +734,6 @@ F:  net/appletalk/
 APPLIED MICRO (APM) X-GENE SOC ETHERNET DRIVER
 M:     Iyappan Subramanian <isubramanian@apm.com>
 M:     Keyur Chudgar <kchudgar@apm.com>
-M:     Ravi Patel <rapatel@apm.com>
 S:     Supported
 F:     drivers/net/ethernet/apm/xgene/
 F:     Documentation/devicetree/bindings/net/apm-xgene-enet.txt
@@ -1339,8 +1338,7 @@ ARM/SAMSUNG MOBILE MACHINE SUPPORT
 M:     Kyungmin Park <kyungmin.park@samsung.com>
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 S:     Maintained
-F:     arch/arm/mach-s5pv210/mach-aquila.c
-F:     arch/arm/mach-s5pv210/mach-goni.c
+F:     arch/arm/mach-s5pv210/
 
 ARM/SAMSUNG S5P SERIES 2D GRAPHICS ACCELERATION (G2D) SUPPORT
 M:     Kyungmin Park <kyungmin.park@samsung.com>
@@ -1551,6 +1549,7 @@ T:        git git://git.xilinx.com/linux-xlnx.git
 S:     Supported
 F:     arch/arm/mach-zynq/
 F:     drivers/cpuidle/cpuidle-zynq.c
+F:     drivers/block/xsysace.c
 N:     zynq
 N:     xilinx
 F:     drivers/clocksource/cadence_ttc_timer.c
@@ -1739,6 +1738,12 @@ M:       Nicolas Ferre <nicolas.ferre@atmel.com>
 S:     Supported
 F:     drivers/net/ethernet/cadence/
 
+ATMEL NAND DRIVER
+M:     Josh Wu <josh.wu@atmel.com>
+L:     linux-mtd@lists.infradead.org
+S:     Supported
+F:     drivers/mtd/nand/atmel_nand*
+
 ATMEL SPI DRIVER
 M:     Nicolas Ferre <nicolas.ferre@atmel.com>
 S:     Supported
@@ -2761,6 +2766,18 @@ W:       http://www.chelsio.com
 S:     Supported
 F:     drivers/net/ethernet/chelsio/cxgb4vf/
 
+CXL (IBM Coherent Accelerator Processor Interface CAPI) DRIVER
+M:     Ian Munsie <imunsie@au1.ibm.com>
+M:     Michael Neuling <mikey@neuling.org>
+L:     linuxppc-dev@lists.ozlabs.org
+S:     Supported
+F:     drivers/misc/cxl/
+F:     include/misc/cxl.h
+F:     include/uapi/misc/cxl.h
+F:     Documentation/powerpc/cxl.txt
+F:     Documentation/powerpc/cxl.txt
+F:     Documentation/ABI/testing/sysfs-class-cxl
+
 STMMAC ETHERNET DRIVER
 M:     Giuseppe Cavallaro <peppe.cavallaro@st.com>
 L:     netdev@vger.kernel.org
@@ -3037,7 +3054,7 @@ M:        Sumit Semwal <sumit.semwal@linaro.org>
 S:     Maintained
 L:     linux-media@vger.kernel.org
 L:     dri-devel@lists.freedesktop.org
-L:     linaro-mm-sig@lists.linaro.org
+L:     linaro-mm-sig@lists.linaro.org (moderated for non-subscribers)
 F:     drivers/dma-buf/
 F:     include/linux/dma-buf*
 F:     include/linux/reservation.h
@@ -3147,7 +3164,7 @@ F:        include/drm/drm_panel.h
 F:     Documentation/devicetree/bindings/panel/
 
 INTEL DRM DRIVERS (excluding Poulsbo, Moorestown and derivative chipsets)
-M:     Daniel Vetter <daniel.vetter@ffwll.ch>
+M:     Daniel Vetter <daniel.vetter@intel.com>
 M:     Jani Nikula <jani.nikula@linux.intel.com>
 L:     intel-gfx@lists.freedesktop.org
 L:     dri-devel@lists.freedesktop.org
@@ -4233,6 +4250,16 @@ L:       linuxppc-dev@lists.ozlabs.org
 S:     Odd Fixes
 F:     drivers/tty/hvc/
 
+HACKRF MEDIA DRIVER
+M:     Antti Palosaari <crope@iki.fi>
+L:     linux-media@vger.kernel.org
+W:     http://linuxtv.org/
+W:     http://palosaari.fi/linux/
+Q:     http://patchwork.linuxtv.org/project/linux-media/list/
+T:     git git://linuxtv.org/anttip/media_tree.git
+S:     Maintained
+F:     drivers/media/usb/hackrf/
+
 HARDWARE MONITORING
 M:     Jean Delvare <jdelvare@suse.de>
 M:     Guenter Roeck <linux@roeck-us.net>
@@ -4276,9 +4303,8 @@ S:        Maintained
 F:     drivers/media/dvb-frontends/hd29l2*
 
 HEWLETT-PACKARD SMART2 RAID DRIVER
-M:     Chirag Kantharia <chirag.kantharia@hp.com>
 L:     iss_storagedev@hp.com
-S:     Maintained
+S:     Orphan
 F:     Documentation/blockdev/cpqarray.txt
 F:     drivers/block/cpqarray.*
 
@@ -5131,7 +5157,7 @@ W:        http://palosaari.fi/linux/
 Q:     http://patchwork.linuxtv.org/project/linux-media/list/
 T:     git git://linuxtv.org/anttip/media_tree.git
 S:     Maintained
-F:     drivers/media/tuners/tuner_it913x*
+F:     drivers/media/tuners/it913x*
 
 IVTV VIDEO4LINUX DRIVER
 M:     Andy Walls <awalls@md.metrocast.net>
@@ -5279,6 +5305,13 @@ F:       include/linux/lockd/
 F:     include/linux/sunrpc/
 F:     include/uapi/linux/sunrpc/
 
+KERNEL SELFTEST FRAMEWORK
+M:     Shuah Khan <shuahkh@osg.samsung.com>
+L:     linux-api@vger.kernel.org
+T:     git git://git.kernel.org/pub/scm/shuah/linux-kselftest
+S:     Maintained
+F:     tools/testing/selftests
+
 KERNEL VIRTUAL MACHINE (KVM)
 M:     Gleb Natapov <gleb@kernel.org>
 M:     Paolo Bonzini <pbonzini@redhat.com>
@@ -5659,8 +5692,8 @@ M:        Ingo Molnar <mingo@redhat.com>
 L:     linux-kernel@vger.kernel.org
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git core/locking
 S:     Maintained
-F:     Documentation/lockdep*.txt
-F:     Documentation/lockstat.txt
+F:     Documentation/locking/lockdep*.txt
+F:     Documentation/locking/lockstat.txt
 F:     include/linux/lockdep.h
 F:     kernel/locking/
 
@@ -5725,11 +5758,8 @@ T:       git git://github.com/linux-test-project/ltp.git
 S:     Maintained
 
 M32R ARCHITECTURE
-M:     Hirokazu Takata <takata@linux-m32r.org>
-L:     linux-m32r@ml.linux-m32r.org (moderated for non-subscribers)
-L:     linux-m32r-ja@ml.linux-m32r.org (in Japanese)
 W:     http://www.linux-m32r.org/
-S:     Maintained
+S:     Orphan
 F:     arch/m32r/
 
 M68K ARCHITECTURE
@@ -6606,10 +6636,9 @@ S:       Maintained
 F:     drivers/mmc/host/omap.c
 
 OMAP HS MMC SUPPORT
-M:     Balaji T K <balajitk@ti.com>
 L:     linux-mmc@vger.kernel.org
 L:     linux-omap@vger.kernel.org
-S:     Maintained
+S:     Orphan
 F:     drivers/mmc/host/omap_hsmmc.c
 
 OMAP RANDOM NUMBER GENERATOR SUPPORT
@@ -7364,6 +7393,14 @@ T:       git git://linuxtv.org/media_tree.git
 S:     Maintained
 F:     drivers/media/usb/pwc/*
 
+PWM FAN DRIVER
+M:     Kamil Debski <k.debski@samsung.com>
+L:     lm-sensors@lm-sensors.org
+S:     Supported
+F:     Documentation/devicetree/bindings/hwmon/pwm-fan.txt
+F:     Documentation/hwmon/pwm-fan
+F:     drivers/hwmon/pwm-fan.c
+
 PWM SUBSYSTEM
 M:     Thierry Reding <thierry.reding@gmail.com>
 L:     linux-pwm@vger.kernel.org
@@ -7946,7 +7983,6 @@ S:        Supported
 F:     drivers/mfd/sec*.c
 F:     drivers/regulator/s2m*.c
 F:     drivers/regulator/s5m*.c
-F:     drivers/rtc/rtc-sec.c
 F:     include/linux/mfd/samsung/
 
 SAMSUNG S5P/EXYNOS4 SOC SERIES CAMERA SUBSYSTEM DRIVERS
@@ -8170,6 +8206,8 @@ F:        drivers/mmc/host/sdhci-pltfm.[ch]
 
 SECURE COMPUTING
 M:     Kees Cook <keescook@chromium.org>
+R:     Andy Lutomirski <luto@amacapital.net>
+R:     Will Drewry <wad@chromium.org>
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/kees/linux.git seccomp
 S:     Supported
 F:     kernel/seccomp.c
@@ -8664,6 +8702,14 @@ F:       include/sound/dmaengine_pcm.h
 F:     sound/core/pcm_dmaengine.c
 F:     sound/soc/soc-generic-dmaengine-pcm.c
 
+SP2 MEDIA DRIVER
+M:     Olli Salonen <olli.salonen@iki.fi>
+L:     linux-media@vger.kernel.org
+W:     http://linuxtv.org/
+Q:     http://patchwork.linuxtv.org/project/linux-media/list/
+S:     Maintained
+F:     drivers/media/dvb-frontends/sp2*
+
 SPARC + UltraSPARC (sparc/sparc64)
 M:     "David S. Miller" <davem@davemloft.net>
 L:     sparclinux@vger.kernel.org
@@ -9367,6 +9413,14 @@ T:       git git://linuxtv.org/media_tree.git
 S:     Odd fixes
 F:     drivers/media/usb/tm6000/
 
+TW68 VIDEO4LINUX DRIVER
+M:     Hans Verkuil <hverkuil@xs4all.nl>
+L:     linux-media@vger.kernel.org
+T:     git git://linuxtv.org/media_tree.git
+W:     http://linuxtv.org
+S:     Odd Fixes
+F:     drivers/media/pci/tw68/
+
 TPM DEVICE DRIVER
 M:     Peter Huewe <peterhuewe@gmx.de>
 M:     Ashley Lai <ashley@ashleylai.com>
@@ -9388,6 +9442,7 @@ F:        include/*/ftrace.h
 F:     include/linux/trace*.h
 F:     include/trace/
 F:     kernel/trace/
+F:     tools/testing/selftests/ftrace/
 
 TRIVIAL PATCHES
 M:     Jiri Kosina <trivial@kernel.org>
@@ -10235,6 +10290,15 @@ S:     Supported
 F:     drivers/block/xen-blkback/*
 F:     drivers/block/xen*
 
+XEN PVSCSI DRIVERS
+M:     Juergen Gross <jgross@suse.com>
+L:     xen-devel@lists.xenproject.org (moderated for non-subscribers)
+L:     linux-scsi@vger.kernel.org
+S:     Supported
+F:     drivers/scsi/xen-scsifront.c
+F:     drivers/xen/xen-scsiback.c
+F:     include/xen/interface/io/vscsiif.h
+
 XEN SWIOTLB SUBSYSTEM
 M:     Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
 L:     xen-devel@lists.xenproject.org (moderated for non-subscribers)
@@ -10259,10 +10323,6 @@ M:     John Linn <John.Linn@xilinx.com>
 S:     Maintained
 F:     drivers/net/ethernet/xilinx/xilinx_axienet*
 
-XILINX SYSTEMACE DRIVER
-S:     Orphan
-F:     drivers/block/xsysace.c
-
 XILINX UARTLITE SERIAL DRIVER
 M:     Peter Korsgaard <jacmet@sunsite.dk>
 L:     linux-serial@vger.kernel.org
index 6127ca66ed981600ca738a43b3d558be43415c56..36a77a3d156ce87dd0103a2a092a50482e01dd61 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -10,11 +10,9 @@ NAME = Shuffling Zombie Juror
 # Comments in this file are targeted only to the developer, do not
 # expect to learn how to build the kernel reading this file.
 
-# Do not:
-# o  use make's built-in rules and variables
-#    (this increases performance and avoids hard-to-debug behaviour);
-# o  print "Entering directory ...";
-MAKEFLAGS += -rR --no-print-directory
+# Do not use make's built-in rules and variables
+# (this increases performance and avoids hard-to-debug behaviour);
+MAKEFLAGS += -rR
 
 # Avoid funny character set dependencies
 unexport LC_ALL
@@ -97,34 +95,6 @@ endif
 
 export quiet Q KBUILD_VERBOSE
 
-# Call a source code checker (by default, "sparse") as part of the
-# C compilation.
-#
-# Use 'make C=1' to enable checking of only re-compiled files.
-# Use 'make C=2' to enable checking of *all* source files, regardless
-# of whether they are re-compiled or not.
-#
-# See the file "Documentation/sparse.txt" for more details, including
-# where to get the "sparse" utility.
-
-ifeq ("$(origin C)", "command line")
-  KBUILD_CHECKSRC = $(C)
-endif
-ifndef KBUILD_CHECKSRC
-  KBUILD_CHECKSRC = 0
-endif
-
-# Use make M=dir to specify directory of external module to build
-# Old syntax make ... SUBDIRS=$PWD is still supported
-# Setting the environment variable KBUILD_EXTMOD take precedence
-ifdef SUBDIRS
-  KBUILD_EXTMOD ?= $(SUBDIRS)
-endif
-
-ifeq ("$(origin M)", "command line")
-  KBUILD_EXTMOD := $(M)
-endif
-
 # kbuild supports saving output files in a separate directory.
 # To locate output files in a separate directory two syntaxes are supported.
 # In both cases the working directory must be the root of the kernel src.
@@ -140,7 +110,6 @@ endif
 # The O= assignment takes precedence over the KBUILD_OUTPUT environment
 # variable.
 
-
 # KBUILD_SRC is set on invocation of make in OBJ directory
 # KBUILD_SRC is not intended to be used by the regular user (for now)
 ifeq ($(KBUILD_SRC),)
@@ -172,17 +141,9 @@ PHONY += $(MAKECMDGOALS) sub-make
 $(filter-out _all sub-make $(CURDIR)/Makefile, $(MAKECMDGOALS)) _all: sub-make
        @:
 
-# Fake the "Entering directory" message once, so that IDEs/editors are
-# able to understand relative filenames.
-       echodir := @echo
- quiet_echodir := @echo
-silent_echodir := @:
 sub-make: FORCE
-       $($(quiet)echodir) "make[1]: Entering directory \`$(KBUILD_OUTPUT)'"
-       $(if $(KBUILD_VERBOSE:1=),@)$(MAKE) -C $(KBUILD_OUTPUT) \
-       KBUILD_SRC=$(CURDIR) \
-       KBUILD_EXTMOD="$(KBUILD_EXTMOD)" -f $(CURDIR)/Makefile \
-       $(filter-out _all sub-make,$(MAKECMDGOALS))
+       $(Q)$(MAKE) -C $(KBUILD_OUTPUT) KBUILD_SRC=$(CURDIR) \
+       -f $(CURDIR)/Makefile $(filter-out _all sub-make,$(MAKECMDGOALS))
 
 # Leave processing to above invocation of make
 skip-makefile := 1
@@ -192,6 +153,39 @@ endif # ifeq ($(KBUILD_SRC),)
 # We process the rest of the Makefile if this is the final invocation of make
 ifeq ($(skip-makefile),)
 
+# Do not print "Entering directory ...",
+# but we want to display it when entering to the output directory
+# so that IDEs/editors are able to understand relative filenames.
+MAKEFLAGS += --no-print-directory
+
+# Call a source code checker (by default, "sparse") as part of the
+# C compilation.
+#
+# Use 'make C=1' to enable checking of only re-compiled files.
+# Use 'make C=2' to enable checking of *all* source files, regardless
+# of whether they are re-compiled or not.
+#
+# See the file "Documentation/sparse.txt" for more details, including
+# where to get the "sparse" utility.
+
+ifeq ("$(origin C)", "command line")
+  KBUILD_CHECKSRC = $(C)
+endif
+ifndef KBUILD_CHECKSRC
+  KBUILD_CHECKSRC = 0
+endif
+
+# Use make M=dir to specify directory of external module to build
+# Old syntax make ... SUBDIRS=$PWD is still supported
+# Setting the environment variable KBUILD_EXTMOD take precedence
+ifdef SUBDIRS
+  KBUILD_EXTMOD ?= $(SUBDIRS)
+endif
+
+ifeq ("$(origin M)", "command line")
+  KBUILD_EXTMOD := $(M)
+endif
+
 # If building an external module we do not care about the all: rule
 # but instead _all depend on modules
 PHONY += all
@@ -889,9 +883,7 @@ vmlinux-dirs        := $(patsubst %/,%,$(filter %/, $(init-y) $(init-m) \
                     $(net-y) $(net-m) $(libs-y) $(libs-m)))
 
 vmlinux-alldirs        := $(sort $(vmlinux-dirs) $(patsubst %/,%,$(filter %/, \
-                    $(init-n) $(init-) \
-                    $(core-n) $(core-) $(drivers-n) $(drivers-) \
-                    $(net-n)  $(net-)  $(libs-n)    $(libs-))))
+                    $(init-) $(core-) $(drivers-) $(net-) $(libs-))))
 
 init-y         := $(patsubst %/, %/built-in.o, $(init-y))
 core-y         := $(patsubst %/, %/built-in.o, $(core-y))
@@ -1591,7 +1583,7 @@ endif
 # Shorthand for $(Q)$(MAKE) -f scripts/Makefile.clean obj=dir
 # Usage:
 # $(Q)$(MAKE) $(clean)=dir
-clean := -f $(if $(KBUILD_SRC),$(srctree)/)scripts/Makefile.clean obj
+clean := -f $(srctree)/scripts/Makefile.clean obj
 
 endif  # skip-makefile
 
index 0eae9df35b884190f7f988702c64158b9a66cda0..05d7a8a458d5850c181e527c2039904c66239de5 100644 (file)
@@ -323,6 +323,17 @@ config HAVE_ARCH_SECCOMP_FILTER
            results in the system call being skipped immediately.
          - seccomp syscall wired up
 
+         For best performance, an arch should use seccomp_phase1 and
+         seccomp_phase2 directly.  It should call seccomp_phase1 for all
+         syscalls if TIF_SECCOMP is set, but seccomp_phase1 does not
+         need to be called from a ptrace-safe context.  It must then
+         call seccomp_phase2 if seccomp_phase1 returns anything other
+         than SECCOMP_PHASE1_OK or SECCOMP_PHASE1_SKIP.
+
+         As an additional optimization, an arch may provide seccomp_data
+         directly to seccomp_phase1; this avoids multiple calls
+         to the syscall_xyz helpers for every syscall.
+
 config SECCOMP_FILTER
        def_bool y
        depends on HAVE_ARCH_SECCOMP_FILTER && SECCOMP && NET
index ed60a1ee1ed3813e4ad873d4dab3ea5a0eb19702..8f8eafbedd7c2970ec1dbd403ec2e3d135079927 100644 (file)
@@ -17,8 +17,8 @@
 #define ATOMIC_INIT(i)         { (i) }
 #define ATOMIC64_INIT(i)       { (i) }
 
-#define atomic_read(v)         (*(volatile int *)&(v)->counter)
-#define atomic64_read(v)       (*(volatile long *)&(v)->counter)
+#define atomic_read(v)         ACCESS_ONCE((v)->counter)
+#define atomic64_read(v)       ACCESS_ONCE((v)->counter)
 
 #define atomic_set(v,i)                ((v)->counter = (i))
 #define atomic64_set(v,i)      ((v)->counter = (i))
  * branch back to restart the operation.
  */
 
-static __inline__ void atomic_add(int i, atomic_t * v)
-{
-       unsigned long temp;
-       __asm__ __volatile__(
-       "1:     ldl_l %0,%1\n"
-       "       addl %0,%2,%0\n"
-       "       stl_c %0,%1\n"
-       "       beq %0,2f\n"
-       ".subsection 2\n"
-       "2:     br 1b\n"
-       ".previous"
-       :"=&r" (temp), "=m" (v->counter)
-       :"Ir" (i), "m" (v->counter));
-}
-
-static __inline__ void atomic64_add(long i, atomic64_t * v)
-{
-       unsigned long temp;
-       __asm__ __volatile__(
-       "1:     ldq_l %0,%1\n"
-       "       addq %0,%2,%0\n"
-       "       stq_c %0,%1\n"
-       "       beq %0,2f\n"
-       ".subsection 2\n"
-       "2:     br 1b\n"
-       ".previous"
-       :"=&r" (temp), "=m" (v->counter)
-       :"Ir" (i), "m" (v->counter));
-}
-
-static __inline__ void atomic_sub(int i, atomic_t * v)
-{
-       unsigned long temp;
-       __asm__ __volatile__(
-       "1:     ldl_l %0,%1\n"
-       "       subl %0,%2,%0\n"
-       "       stl_c %0,%1\n"
-       "       beq %0,2f\n"
-       ".subsection 2\n"
-       "2:     br 1b\n"
-       ".previous"
-       :"=&r" (temp), "=m" (v->counter)
-       :"Ir" (i), "m" (v->counter));
+#define ATOMIC_OP(op)                                                  \
+static __inline__ void atomic_##op(int i, atomic_t * v)                        \
+{                                                                      \
+       unsigned long temp;                                             \
+       __asm__ __volatile__(                                           \
+       "1:     ldl_l %0,%1\n"                                          \
+       "       " #op "l %0,%2,%0\n"                                    \
+       "       stl_c %0,%1\n"                                          \
+       "       beq %0,2f\n"                                            \
+       ".subsection 2\n"                                               \
+       "2:     br 1b\n"                                                \
+       ".previous"                                                     \
+       :"=&r" (temp), "=m" (v->counter)                                \
+       :"Ir" (i), "m" (v->counter));                                   \
+}                                                                      \
+
+#define ATOMIC_OP_RETURN(op)                                           \
+static inline int atomic_##op##_return(int i, atomic_t *v)             \
+{                                                                      \
+       long temp, result;                                              \
+       smp_mb();                                                       \
+       __asm__ __volatile__(                                           \
+       "1:     ldl_l %0,%1\n"                                          \
+       "       " #op "l %0,%3,%2\n"                                    \
+       "       " #op "l %0,%3,%0\n"                                    \
+       "       stl_c %0,%1\n"                                          \
+       "       beq %0,2f\n"                                            \
+       ".subsection 2\n"                                               \
+       "2:     br 1b\n"                                                \
+       ".previous"                                                     \
+       :"=&r" (temp), "=m" (v->counter), "=&r" (result)                \
+       :"Ir" (i), "m" (v->counter) : "memory");                        \
+       smp_mb();                                                       \
+       return result;                                                  \
 }
 
-static __inline__ void atomic64_sub(long i, atomic64_t * v)
-{
-       unsigned long temp;
-       __asm__ __volatile__(
-       "1:     ldq_l %0,%1\n"
-       "       subq %0,%2,%0\n"
-       "       stq_c %0,%1\n"
-       "       beq %0,2f\n"
-       ".subsection 2\n"
-       "2:     br 1b\n"
-       ".previous"
-       :"=&r" (temp), "=m" (v->counter)
-       :"Ir" (i), "m" (v->counter));
-}
-
-
-/*
- * Same as above, but return the result value
- */
-static inline int atomic_add_return(int i, atomic_t *v)
-{
-       long temp, result;
-       smp_mb();
-       __asm__ __volatile__(
-       "1:     ldl_l %0,%1\n"
-       "       addl %0,%3,%2\n"
-       "       addl %0,%3,%0\n"
-       "       stl_c %0,%1\n"
-       "       beq %0,2f\n"
-       ".subsection 2\n"
-       "2:     br 1b\n"
-       ".previous"
-       :"=&r" (temp), "=m" (v->counter), "=&r" (result)
-       :"Ir" (i), "m" (v->counter) : "memory");
-       smp_mb();
-       return result;
+#define ATOMIC64_OP(op)                                                        \
+static __inline__ void atomic64_##op(long i, atomic64_t * v)           \
+{                                                                      \
+       unsigned long temp;                                             \
+       __asm__ __volatile__(                                           \
+       "1:     ldq_l %0,%1\n"                                          \
+       "       " #op "q %0,%2,%0\n"                                    \
+       "       stq_c %0,%1\n"                                          \
+       "       beq %0,2f\n"                                            \
+       ".subsection 2\n"                                               \
+       "2:     br 1b\n"                                                \
+       ".previous"                                                     \
+       :"=&r" (temp), "=m" (v->counter)                                \
+       :"Ir" (i), "m" (v->counter));                                   \
+}                                                                      \
+
+#define ATOMIC64_OP_RETURN(op)                                         \
+static __inline__ long atomic64_##op##_return(long i, atomic64_t * v)  \
+{                                                                      \
+       long temp, result;                                              \
+       smp_mb();                                                       \
+       __asm__ __volatile__(                                           \
+       "1:     ldq_l %0,%1\n"                                          \
+       "       " #op "q %0,%3,%2\n"                                    \
+       "       " #op "q %0,%3,%0\n"                                    \
+       "       stq_c %0,%1\n"                                          \
+       "       beq %0,2f\n"                                            \
+       ".subsection 2\n"                                               \
+       "2:     br 1b\n"                                                \
+       ".previous"                                                     \
+       :"=&r" (temp), "=m" (v->counter), "=&r" (result)                \
+       :"Ir" (i), "m" (v->counter) : "memory");                        \
+       smp_mb();                                                       \
+       return result;                                                  \
 }
 
-static __inline__ long atomic64_add_return(long i, atomic64_t * v)
-{
-       long temp, result;
-       smp_mb();
-       __asm__ __volatile__(
-       "1:     ldq_l %0,%1\n"
-       "       addq %0,%3,%2\n"
-       "       addq %0,%3,%0\n"
-       "       stq_c %0,%1\n"
-       "       beq %0,2f\n"
-       ".subsection 2\n"
-       "2:     br 1b\n"
-       ".previous"
-       :"=&r" (temp), "=m" (v->counter), "=&r" (result)
-       :"Ir" (i), "m" (v->counter) : "memory");
-       smp_mb();
-       return result;
-}
+#define ATOMIC_OPS(opg)                                                        \
+       ATOMIC_OP(opg)                                                  \
+       ATOMIC_OP_RETURN(opg)                                           \
+       ATOMIC64_OP(opg)                                                \
+       ATOMIC64_OP_RETURN(opg)
 
-static __inline__ long atomic_sub_return(int i, atomic_t * v)
-{
-       long temp, result;
-       smp_mb();
-       __asm__ __volatile__(
-       "1:     ldl_l %0,%1\n"
-       "       subl %0,%3,%2\n"
-       "       subl %0,%3,%0\n"
-       "       stl_c %0,%1\n"
-       "       beq %0,2f\n"
-       ".subsection 2\n"
-       "2:     br 1b\n"
-       ".previous"
-       :"=&r" (temp), "=m" (v->counter), "=&r" (result)
-       :"Ir" (i), "m" (v->counter) : "memory");
-       smp_mb();
-       return result;
-}
+ATOMIC_OPS(add)
+ATOMIC_OPS(sub)
 
-static __inline__ long atomic64_sub_return(long i, atomic64_t * v)
-{
-       long temp, result;
-       smp_mb();
-       __asm__ __volatile__(
-       "1:     ldq_l %0,%1\n"
-       "       subq %0,%3,%2\n"
-       "       subq %0,%3,%0\n"
-       "       stq_c %0,%1\n"
-       "       beq %0,2f\n"
-       ".subsection 2\n"
-       "2:     br 1b\n"
-       ".previous"
-       :"=&r" (temp), "=m" (v->counter), "=&r" (result)
-       :"Ir" (i), "m" (v->counter) : "memory");
-       smp_mb();
-       return result;
-}
+#undef ATOMIC_OPS
+#undef ATOMIC64_OP_RETURN
+#undef ATOMIC64_OP
+#undef ATOMIC_OP_RETURN
+#undef ATOMIC_OP
 
 #define atomic64_cmpxchg(v, old, new) (cmpxchg(&((v)->counter), old, new))
 #define atomic64_xchg(v, new) (xchg(&((v)->counter), new))
index 1402fcc11c2c0443d18d59e21192f5af50ecb1c2..f9c732e1828405d4ed487795eb9442b623709ea9 100644 (file)
@@ -446,7 +446,8 @@ struct procfs_args {
  * unhappy with OSF UFS. [CHECKME]
  */
 static int
-osf_ufs_mount(const char *dirname, struct ufs_args __user *args, int flags)
+osf_ufs_mount(const char __user *dirname,
+             struct ufs_args __user *args, int flags)
 {
        int retval;
        struct cdfs_args tmp;
@@ -466,7 +467,8 @@ osf_ufs_mount(const char *dirname, struct ufs_args __user *args, int flags)
 }
 
 static int
-osf_cdfs_mount(const char *dirname, struct cdfs_args __user *args, int flags)
+osf_cdfs_mount(const char __user *dirname,
+              struct cdfs_args __user *args, int flags)
 {
        int retval;
        struct cdfs_args tmp;
@@ -486,7 +488,8 @@ osf_cdfs_mount(const char *dirname, struct cdfs_args __user *args, int flags)
 }
 
 static int
-osf_procfs_mount(const char *dirname, struct procfs_args __user *args, int flags)
+osf_procfs_mount(const char __user *dirname,
+                struct procfs_args __user *args, int flags)
 {
        struct procfs_args tmp;
 
@@ -500,28 +503,22 @@ SYSCALL_DEFINE4(osf_mount, unsigned long, typenr, const char __user *, path,
                int, flag, void __user *, data)
 {
        int retval;
-       struct filename *name;
 
-       name = getname(path);
-       retval = PTR_ERR(name);
-       if (IS_ERR(name))
-               goto out;
        switch (typenr) {
        case 1:
-               retval = osf_ufs_mount(name->name, data, flag);
+               retval = osf_ufs_mount(path, data, flag);
                break;
        case 6:
-               retval = osf_cdfs_mount(name->name, data, flag);
+               retval = osf_cdfs_mount(path, data, flag);
                break;
        case 9:
-               retval = osf_procfs_mount(name->name, data, flag);
+               retval = osf_procfs_mount(path, data, flag);
                break;
        default:
                retval = -EINVAL;
                printk("osf_mount(%ld, %x)\n", typenr, flag);
        }
-       putname(name);
- out:
+
        return retval;
 }
 
index 83f03ca6caf6c7f09f171a66581d062a7333ccdd..173f303a868f20854cbdcc598cf991e4f6d6d0e5 100644 (file)
 
 #define atomic_set(v, i) (((v)->counter) = (i))
 
-static inline void atomic_add(int i, atomic_t *v)
-{
-       unsigned int temp;
-
-       __asm__ __volatile__(
-       "1:     llock   %0, [%1]        \n"
-       "       add     %0, %0, %2      \n"
-       "       scond   %0, [%1]        \n"
-       "       bnz     1b              \n"
-       : "=&r"(temp)   /* Early clobber, to prevent reg reuse */
-       : "r"(&v->counter), "ir"(i)
-       : "cc");
-}
-
-static inline void atomic_sub(int i, atomic_t *v)
-{
-       unsigned int temp;
-
-       __asm__ __volatile__(
-       "1:     llock   %0, [%1]        \n"
-       "       sub     %0, %0, %2      \n"
-       "       scond   %0, [%1]        \n"
-       "       bnz     1b              \n"
-       : "=&r"(temp)
-       : "r"(&v->counter), "ir"(i)
-       : "cc");
-}
-
-/* add and also return the new value */
-static inline int atomic_add_return(int i, atomic_t *v)
-{
-       unsigned int temp;
-
-       __asm__ __volatile__(
-       "1:     llock   %0, [%1]        \n"
-       "       add     %0, %0, %2      \n"
-       "       scond   %0, [%1]        \n"
-       "       bnz     1b              \n"
-       : "=&r"(temp)
-       : "r"(&v->counter), "ir"(i)
-       : "cc");
-
-       return temp;
-}
-
-static inline int atomic_sub_return(int i, atomic_t *v)
-{
-       unsigned int temp;
-
-       __asm__ __volatile__(
-       "1:     llock   %0, [%1]        \n"
-       "       sub     %0, %0, %2      \n"
-       "       scond   %0, [%1]        \n"
-       "       bnz     1b              \n"
-       : "=&r"(temp)
-       : "r"(&v->counter), "ir"(i)
-       : "cc");
-
-       return temp;
-}
-
-static inline void atomic_clear_mask(unsigned long mask, unsigned long *addr)
-{
-       unsigned int temp;
-
-       __asm__ __volatile__(
-       "1:     llock   %0, [%1]        \n"
-       "       bic     %0, %0, %2      \n"
-       "       scond   %0, [%1]        \n"
-       "       bnz     1b              \n"
-       : "=&r"(temp)
-       : "r"(addr), "ir"(mask)
-       : "cc");
+#define ATOMIC_OP(op, c_op, asm_op)                                    \
+static inline void atomic_##op(int i, atomic_t *v)                     \
+{                                                                      \
+       unsigned int temp;                                              \
+                                                                       \
+       __asm__ __volatile__(                                           \
+       "1:     llock   %0, [%1]        \n"                             \
+       "       " #asm_op " %0, %0, %2  \n"                             \
+       "       scond   %0, [%1]        \n"                             \
+       "       bnz     1b              \n"                             \
+       : "=&r"(temp)   /* Early clobber, to prevent reg reuse */       \
+       : "r"(&v->counter), "ir"(i)                                     \
+       : "cc");                                                        \
+}                                                                      \
+
+#define ATOMIC_OP_RETURN(op, c_op, asm_op)                             \
+static inline int atomic_##op##_return(int i, atomic_t *v)             \
+{                                                                      \
+       unsigned int temp;                                              \
+                                                                       \
+       __asm__ __volatile__(                                           \
+       "1:     llock   %0, [%1]        \n"                             \
+       "       " #asm_op " %0, %0, %2  \n"                             \
+       "       scond   %0, [%1]        \n"                             \
+       "       bnz     1b              \n"                             \
+       : "=&r"(temp)                                                   \
+       : "r"(&v->counter), "ir"(i)                                     \
+       : "cc");                                                        \
+                                                                       \
+       return temp;                                                    \
 }
 
 #else  /* !CONFIG_ARC_HAS_LLSC */
@@ -126,6 +83,7 @@ static inline void atomic_set(atomic_t *v, int i)
        v->counter = i;
        atomic_ops_unlock(flags);
 }
+
 #endif
 
 /*
@@ -133,62 +91,46 @@ static inline void atomic_set(atomic_t *v, int i)
  * Locking would change to irq-disabling only (UP) and spinlocks (SMP)
  */
 
-static inline void atomic_add(int i, atomic_t *v)
-{
-       unsigned long flags;
-
-       atomic_ops_lock(flags);
-       v->counter += i;
-       atomic_ops_unlock(flags);
+#define ATOMIC_OP(op, c_op, asm_op)                                    \
+static inline void atomic_##op(int i, atomic_t *v)                     \
+{                                                                      \
+       unsigned long flags;                                            \
+                                                                       \
+       atomic_ops_lock(flags);                                         \
+       v->counter c_op i;                                              \
+       atomic_ops_unlock(flags);                                       \
 }
 
-static inline void atomic_sub(int i, atomic_t *v)
-{
-       unsigned long flags;
-
-       atomic_ops_lock(flags);
-       v->counter -= i;
-       atomic_ops_unlock(flags);
+#define ATOMIC_OP_RETURN(op, c_op)                                     \
+static inline int atomic_##op##_return(int i, atomic_t *v)             \
+{                                                                      \
+       unsigned long flags;                                            \
+       unsigned long temp;                                             \
+                                                                       \
+       atomic_ops_lock(flags);                                         \
+       temp = v->counter;                                              \
+       temp c_op i;                                                    \
+       v->counter = temp;                                              \
+       atomic_ops_unlock(flags);                                       \
+                                                                       \
+       return temp;                                                    \
 }
 
-static inline int atomic_add_return(int i, atomic_t *v)
-{
-       unsigned long flags;
-       unsigned long temp;
-
-       atomic_ops_lock(flags);
-       temp = v->counter;
-       temp += i;
-       v->counter = temp;
-       atomic_ops_unlock(flags);
-
-       return temp;
-}
-
-static inline int atomic_sub_return(int i, atomic_t *v)
-{
-       unsigned long flags;
-       unsigned long temp;
-
-       atomic_ops_lock(flags);
-       temp = v->counter;
-       temp -= i;
-       v->counter = temp;
-       atomic_ops_unlock(flags);
+#endif /* !CONFIG_ARC_HAS_LLSC */
 
-       return temp;
-}
+#define ATOMIC_OPS(op, c_op, asm_op)                                   \
+       ATOMIC_OP(op, c_op, asm_op)                                     \
+       ATOMIC_OP_RETURN(op, c_op, asm_op)
 
-static inline void atomic_clear_mask(unsigned long mask, unsigned long *addr)
-{
-       unsigned long flags;
+ATOMIC_OPS(add, +=, add)
+ATOMIC_OPS(sub, -=, sub)
+ATOMIC_OP(and, &=, and)
 
-       atomic_ops_lock(flags);
-       *addr &= ~mask;
-       atomic_ops_unlock(flags);
-}
+#define atomic_clear_mask(mask, v) atomic_and(~(mask), (v))
 
-#endif /* !CONFIG_ARC_HAS_LLSC */
+#undef ATOMIC_OPS
+#undef ATOMIC_OP_RETURN
+#undef ATOMIC_OP
 
 /**
  * __atomic_add_unless - add unless the number is a given value
index 18f392f8b74457712f09e42eab6f8ee96197b82f..89c4b5ccc68df8200aeff85bf89adaf87ce24e12 100644 (file)
@@ -1779,7 +1779,7 @@ config XEN_DOM0
        depends on XEN
 
 config XEN
-       bool "Xen guest support on ARM (EXPERIMENTAL)"
+       bool "Xen guest support on ARM"
        depends on ARM && AEABI && OF
        depends on CPU_V7 && !CPU_V6
        depends on !GENERIC_ATOMIC64
index dceb0441b1a6de111eb5cc3e9b96e1bbb5e69f34..034a94904d69e5578e3792408368ebc6c1d08a77 100644 (file)
@@ -50,8 +50,6 @@ AS            += -EL
 LD             += -EL
 endif
 
-comma = ,
-
 # This selects which instruction set is used.
 # Note that GCC does not numerically define an architecture version
 # macro, but instead defines a whole series of macros which makes
index 1d52de6370d58a65022b0bc59bf2f07516066308..8831c48c2bc93b260d15a0cbb255d64467eb3a4d 100644 (file)
                        reg = <0x10020000 0x4000>;
                };
 
+               mipi_phy: video-phy@10020710 {
+                       compatible = "samsung,s5pv210-mipi-video-phy";
+                       reg = <0x10020710 8>;
+                       #phy-cells = <1>;
+               };
+
                pd_cam: cam-power-domain@10023C00 {
                        compatible = "samsung,exynos4210-pd";
                        reg = <0x10023C00 0x20>;
                };
 
                rtc: rtc@10070000 {
-                       compatible = "samsung,s3c6410-rtc";
+                       compatible = "samsung,exynos3250-rtc";
                        reg = <0x10070000 0x100>;
                        interrupts = <0 73 0>, <0 74 0>;
                        status = "disabled";
                        interrupts = <0 240 0>;
                };
 
+               fimd: fimd@11c00000 {
+                       compatible = "samsung,exynos3250-fimd";
+                       reg = <0x11c00000 0x30000>;
+                       interrupt-names = "fifo", "vsync", "lcd_sys";
+                       interrupts = <0 84 0>, <0 85 0>, <0 86 0>;
+                       clocks = <&cmu CLK_SCLK_FIMD0>, <&cmu CLK_FIMD0>;
+                       clock-names = "sclk_fimd", "fimd";
+                       samsung,power-domain = <&pd_lcd0>;
+                       samsung,sysreg = <&sys_reg>;
+                       status = "disabled";
+               };
+
+               dsi_0: dsi@11C80000 {
+                       compatible = "samsung,exynos3250-mipi-dsi";
+                       reg = <0x11C80000 0x10000>;
+                       interrupts = <0 83 0>;
+                       samsung,phy-type = <0>;
+                       samsung,power-domain = <&pd_lcd0>;
+                       phys = <&mipi_phy 1>;
+                       phy-names = "dsim";
+                       clocks = <&cmu CLK_DSIM0>, <&cmu CLK_SCLK_MIPI0>;
+                       clock-names = "bus_clk", "pll_clk";
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       status = "disabled";
+               };
+
                mshc_0: mshc@12510000 {
                        compatible = "samsung,exynos5250-dw-mshc";
                        reg = <0x12510000 0x1000>;
index 70a559cf1a3d11b0d191fedcbe15779011560fc8..4f2df61c1cfc6fde03a39968d6c8d5666ba5e834 100644 (file)
@@ -69,7 +69,8 @@
                samsung,dw-mshc-ddr-timing = <1 2>;
                pinctrl-names = "default";
                pinctrl-0 = <&sd2_clk &sd2_cmd &sd2_cd &sd2_bus4>;
-               vmmc-supply = <&ldo10_reg>;
+               vmmc-supply = <&ldo19_reg>;
+               vqmmc-supply = <&ldo13_reg>;
                bus-width = <4>;
                cap-sd-highspeed;
        };
index 3040359094d93a5d4f21bc517f997ef5a6d0b277..e22c11970b7bd278e5a030a364c2b66ba3572e6f 100644 (file)
@@ -27,7 +27,7 @@
  * strex/ldrex monitor on some implementations. The reason we can use it for
  * atomic_set() is the clrex or dummy strex done on every exception return.
  */
-#define atomic_read(v) (*(volatile int *)&(v)->counter)
+#define atomic_read(v) ACCESS_ONCE((v)->counter)
 #define atomic_set(v,i)        (((v)->counter) = (i))
 
 #if __LINUX_ARM_ARCH__ >= 6
  * store exclusive to ensure that these are atomic.  We may loop
  * to ensure that the update happens.
  */
-static inline void atomic_add(int i, atomic_t *v)
-{
-       unsigned long tmp;
-       int result;
-
-       prefetchw(&v->counter);
-       __asm__ __volatile__("@ atomic_add\n"
-"1:    ldrex   %0, [%3]\n"
-"      add     %0, %0, %4\n"
-"      strex   %1, %0, [%3]\n"
-"      teq     %1, #0\n"
-"      bne     1b"
-       : "=&r" (result), "=&r" (tmp), "+Qo" (v->counter)
-       : "r" (&v->counter), "Ir" (i)
-       : "cc");
-}
 
-static inline int atomic_add_return(int i, atomic_t *v)
-{
-       unsigned long tmp;
-       int result;
-
-       smp_mb();
-       prefetchw(&v->counter);
-
-       __asm__ __volatile__("@ atomic_add_return\n"
-"1:    ldrex   %0, [%3]\n"
-"      add     %0, %0, %4\n"
-"      strex   %1, %0, [%3]\n"
-"      teq     %1, #0\n"
-"      bne     1b"
-       : "=&r" (result), "=&r" (tmp), "+Qo" (v->counter)
-       : "r" (&v->counter), "Ir" (i)
-       : "cc");
-
-       smp_mb();
-
-       return result;
-}
-
-static inline void atomic_sub(int i, atomic_t *v)
-{
-       unsigned long tmp;
-       int result;
-
-       prefetchw(&v->counter);
-       __asm__ __volatile__("@ atomic_sub\n"
-"1:    ldrex   %0, [%3]\n"
-"      sub     %0, %0, %4\n"
-"      strex   %1, %0, [%3]\n"
-"      teq     %1, #0\n"
-"      bne     1b"
-       : "=&r" (result), "=&r" (tmp), "+Qo" (v->counter)
-       : "r" (&v->counter), "Ir" (i)
-       : "cc");
-}
-
-static inline int atomic_sub_return(int i, atomic_t *v)
-{
-       unsigned long tmp;
-       int result;
-
-       smp_mb();
-       prefetchw(&v->counter);
-
-       __asm__ __volatile__("@ atomic_sub_return\n"
-"1:    ldrex   %0, [%3]\n"
-"      sub     %0, %0, %4\n"
-"      strex   %1, %0, [%3]\n"
-"      teq     %1, #0\n"
-"      bne     1b"
-       : "=&r" (result), "=&r" (tmp), "+Qo" (v->counter)
-       : "r" (&v->counter), "Ir" (i)
-       : "cc");
-
-       smp_mb();
-
-       return result;
+#define ATOMIC_OP(op, c_op, asm_op)                                    \
+static inline void atomic_##op(int i, atomic_t *v)                     \
+{                                                                      \
+       unsigned long tmp;                                              \
+       int result;                                                     \
+                                                                       \
+       prefetchw(&v->counter);                                         \
+       __asm__ __volatile__("@ atomic_" #op "\n"                       \
+"1:    ldrex   %0, [%3]\n"                                             \
+"      " #asm_op "     %0, %0, %4\n"                                   \
+"      strex   %1, %0, [%3]\n"                                         \
+"      teq     %1, #0\n"                                               \
+"      bne     1b"                                                     \
+       : "=&r" (result), "=&r" (tmp), "+Qo" (v->counter)               \
+       : "r" (&v->counter), "Ir" (i)                                   \
+       : "cc");                                                        \
+}                                                                      \
+
+#define ATOMIC_OP_RETURN(op, c_op, asm_op)                             \
+static inline int atomic_##op##_return(int i, atomic_t *v)             \
+{                                                                      \
+       unsigned long tmp;                                              \
+       int result;                                                     \
+                                                                       \
+       smp_mb();                                                       \
+       prefetchw(&v->counter);                                         \
+                                                                       \
+       __asm__ __volatile__("@ atomic_" #op "_return\n"                \
+"1:    ldrex   %0, [%3]\n"                                             \
+"      " #asm_op "     %0, %0, %4\n"                                   \
+"      strex   %1, %0, [%3]\n"                                         \
+"      teq     %1, #0\n"                                               \
+"      bne     1b"                                                     \
+       : "=&r" (result), "=&r" (tmp), "+Qo" (v->counter)               \
+       : "r" (&v->counter), "Ir" (i)                                   \
+       : "cc");                                                        \
+                                                                       \
+       smp_mb();                                                       \
+                                                                       \
+       return result;                                                  \
 }
 
 static inline int atomic_cmpxchg(atomic_t *ptr, int old, int new)
@@ -174,33 +137,29 @@ static inline int __atomic_add_unless(atomic_t *v, int a, int u)
 #error SMP not supported on pre-ARMv6 CPUs
 #endif
 
-static inline int atomic_add_return(int i, atomic_t *v)
-{
-       unsigned long flags;
-       int val;
-
-       raw_local_irq_save(flags);
-       val = v->counter;
-       v->counter = val += i;
-       raw_local_irq_restore(flags);
-
-       return val;
-}
-#define atomic_add(i, v)       (void) atomic_add_return(i, v)
-
-static inline int atomic_sub_return(int i, atomic_t *v)
-{
-       unsigned long flags;
-       int val;
-
-       raw_local_irq_save(flags);
-       val = v->counter;
-       v->counter = val -= i;
-       raw_local_irq_restore(flags);
-
-       return val;
+#define ATOMIC_OP(op, c_op, asm_op)                                    \
+static inline void atomic_##op(int i, atomic_t *v)                     \
+{                                                                      \
+       unsigned long flags;                                            \
+                                                                       \
+       raw_local_irq_save(flags);                                      \
+       v->counter c_op i;                                              \
+       raw_local_irq_restore(flags);                                   \
+}                                                                      \
+
+#define ATOMIC_OP_RETURN(op, c_op, asm_op)                             \
+static inline int atomic_##op##_return(int i, atomic_t *v)             \
+{                                                                      \
+       unsigned long flags;                                            \
+       int val;                                                        \
+                                                                       \
+       raw_local_irq_save(flags);                                      \
+       v->counter c_op i;                                              \
+       val = v->counter;                                               \
+       raw_local_irq_restore(flags);                                   \
+                                                                       \
+       return val;                                                     \
 }
-#define atomic_sub(i, v)       (void) atomic_sub_return(i, v)
 
 static inline int atomic_cmpxchg(atomic_t *v, int old, int new)
 {
@@ -228,6 +187,17 @@ static inline int __atomic_add_unless(atomic_t *v, int a, int u)
 
 #endif /* __LINUX_ARM_ARCH__ */
 
+#define ATOMIC_OPS(op, c_op, asm_op)                                   \
+       ATOMIC_OP(op, c_op, asm_op)                                     \
+       ATOMIC_OP_RETURN(op, c_op, asm_op)
+
+ATOMIC_OPS(add, +=, add)
+ATOMIC_OPS(sub, -=, sub)
+
+#undef ATOMIC_OPS
+#undef ATOMIC_OP_RETURN
+#undef ATOMIC_OP
+
 #define atomic_xchg(v, new) (xchg(&((v)->counter), new))
 
 #define atomic_inc(v)          atomic_add(1, v)
@@ -300,89 +270,60 @@ static inline void atomic64_set(atomic64_t *v, long long i)
 }
 #endif
 
-static inline void atomic64_add(long long i, atomic64_t *v)
-{
-       long long result;
-       unsigned long tmp;
-
-       prefetchw(&v->counter);
-       __asm__ __volatile__("@ atomic64_add\n"
-"1:    ldrexd  %0, %H0, [%3]\n"
-"      adds    %Q0, %Q0, %Q4\n"
-"      adc     %R0, %R0, %R4\n"
-"      strexd  %1, %0, %H0, [%3]\n"
-"      teq     %1, #0\n"
-"      bne     1b"
-       : "=&r" (result), "=&r" (tmp), "+Qo" (v->counter)
-       : "r" (&v->counter), "r" (i)
-       : "cc");
-}
-
-static inline long long atomic64_add_return(long long i, atomic64_t *v)
-{
-       long long result;
-       unsigned long tmp;
-
-       smp_mb();
-       prefetchw(&v->counter);
-
-       __asm__ __volatile__("@ atomic64_add_return\n"
-"1:    ldrexd  %0, %H0, [%3]\n"
-"      adds    %Q0, %Q0, %Q4\n"
-"      adc     %R0, %R0, %R4\n"
-"      strexd  %1, %0, %H0, [%3]\n"
-"      teq     %1, #0\n"
-"      bne     1b"
-       : "=&r" (result), "=&r" (tmp), "+Qo" (v->counter)
-       : "r" (&v->counter), "r" (i)
-       : "cc");
-
-       smp_mb();
-
-       return result;
-}
-
-static inline void atomic64_sub(long long i, atomic64_t *v)
-{
-       long long result;
-       unsigned long tmp;
-
-       prefetchw(&v->counter);
-       __asm__ __volatile__("@ atomic64_sub\n"
-"1:    ldrexd  %0, %H0, [%3]\n"
-"      subs    %Q0, %Q0, %Q4\n"
-"      sbc     %R0, %R0, %R4\n"
-"      strexd  %1, %0, %H0, [%3]\n"
-"      teq     %1, #0\n"
-"      bne     1b"
-       : "=&r" (result), "=&r" (tmp), "+Qo" (v->counter)
-       : "r" (&v->counter), "r" (i)
-       : "cc");
+#define ATOMIC64_OP(op, op1, op2)                                      \
+static inline void atomic64_##op(long long i, atomic64_t *v)           \
+{                                                                      \
+       long long result;                                               \
+       unsigned long tmp;                                              \
+                                                                       \
+       prefetchw(&v->counter);                                         \
+       __asm__ __volatile__("@ atomic64_" #op "\n"                     \
+"1:    ldrexd  %0, %H0, [%3]\n"                                        \
+"      " #op1 " %Q0, %Q0, %Q4\n"                                       \
+"      " #op2 " %R0, %R0, %R4\n"                                       \
+"      strexd  %1, %0, %H0, [%3]\n"                                    \
+"      teq     %1, #0\n"                                               \
+"      bne     1b"                                                     \
+       : "=&r" (result), "=&r" (tmp), "+Qo" (v->counter)               \
+       : "r" (&v->counter), "r" (i)                                    \
+       : "cc");                                                        \
+}                                                                      \
+
+#define ATOMIC64_OP_RETURN(op, op1, op2)                               \
+static inline long long atomic64_##op##_return(long long i, atomic64_t *v) \
+{                                                                      \
+       long long result;                                               \
+       unsigned long tmp;                                              \
+                                                                       \
+       smp_mb();                                                       \
+       prefetchw(&v->counter);                                         \
+                                                                       \
+       __asm__ __volatile__("@ atomic64_" #op "_return\n"              \
+"1:    ldrexd  %0, %H0, [%3]\n"                                        \
+"      " #op1 " %Q0, %Q0, %Q4\n"                                       \
+"      " #op2 " %R0, %R0, %R4\n"                                       \
+"      strexd  %1, %0, %H0, [%3]\n"                                    \
+"      teq     %1, #0\n"                                               \
+"      bne     1b"                                                     \
+       : "=&r" (result), "=&r" (tmp), "+Qo" (v->counter)               \
+       : "r" (&v->counter), "r" (i)                                    \
+       : "cc");                                                        \
+                                                                       \
+       smp_mb();                                                       \
+                                                                       \
+       return result;                                                  \
 }
 
-static inline long long atomic64_sub_return(long long i, atomic64_t *v)
-{
-       long long result;
-       unsigned long tmp;
-
-       smp_mb();
-       prefetchw(&v->counter);
-
-       __asm__ __volatile__("@ atomic64_sub_return\n"
-"1:    ldrexd  %0, %H0, [%3]\n"
-"      subs    %Q0, %Q0, %Q4\n"
-"      sbc     %R0, %R0, %R4\n"
-"      strexd  %1, %0, %H0, [%3]\n"
-"      teq     %1, #0\n"
-"      bne     1b"
-       : "=&r" (result), "=&r" (tmp), "+Qo" (v->counter)
-       : "r" (&v->counter), "r" (i)
-       : "cc");
+#define ATOMIC64_OPS(op, op1, op2)                                     \
+       ATOMIC64_OP(op, op1, op2)                                       \
+       ATOMIC64_OP_RETURN(op, op1, op2)
 
-       smp_mb();
+ATOMIC64_OPS(add, adds, adc)
+ATOMIC64_OPS(sub, subs, sbc)
 
-       return result;
-}
+#undef ATOMIC64_OPS
+#undef ATOMIC64_OP_RETURN
+#undef ATOMIC64_OP
 
 static inline long long atomic64_cmpxchg(atomic64_t *ptr, long long old,
                                        long long new)
index c45b61a4b4a5250e66908038be02203f9880ebec..85738b200023a4d09243175eb023040cd50a0527 100644 (file)
@@ -265,22 +265,6 @@ 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);
 
-static inline void *dma_alloc_writecombine(struct device *dev, size_t size,
-                                      dma_addr_t *dma_handle, gfp_t flag)
-{
-       DEFINE_DMA_ATTRS(attrs);
-       dma_set_attr(DMA_ATTR_WRITE_COMBINE, &attrs);
-       return dma_alloc_attrs(dev, size, dma_handle, flag, &attrs);
-}
-
-static inline void dma_free_writecombine(struct device *dev, size_t size,
-                                    void *cpu_addr, dma_addr_t dma_handle)
-{
-       DEFINE_DMA_ATTRS(attrs);
-       dma_set_attr(DMA_ATTR_WRITE_COMBINE, &attrs);
-       return dma_free_attrs(dev, size, cpu_addr, dma_handle, &attrs);
-}
-
 /*
  * This can be called during early boot to increase the size of the atomic
  * coherent DMA pool above the default value of 256KiB. It must be called
index a0a691d1cbeee0e675e3d18674b15fc1f1224342..fe972a2f3df398f9eddbf02b25d4edff987b442d 100644 (file)
@@ -114,18 +114,13 @@ void soft_restart(unsigned long addr)
        BUG();
 }
 
-static void null_restart(enum reboot_mode reboot_mode, const char *cmd)
-{
-}
-
 /*
  * Function pointers to optional machine specific functions
  */
 void (*pm_power_off)(void);
 EXPORT_SYMBOL(pm_power_off);
 
-void (*arm_pm_restart)(enum reboot_mode reboot_mode, const char *cmd) = null_restart;
-EXPORT_SYMBOL_GPL(arm_pm_restart);
+void (*arm_pm_restart)(enum reboot_mode reboot_mode, const char *cmd);
 
 /*
  * This is our default idle handler.
@@ -230,7 +225,10 @@ void machine_restart(char *cmd)
        local_irq_disable();
        smp_send_stop();
 
-       arm_pm_restart(reboot_mode, cmd);
+       if (arm_pm_restart)
+               arm_pm_restart(reboot_mode, cmd);
+       else
+               do_kernel_restart(cmd);
 
        /* Give a grace period for failure to restart of 1s */
        mdelay(1000);
index 0c27ed6f3f2346e9bd9c13a8cea1265536572ba5..5e772a21ab9707916b82cb4d2a42d24fcb1bf878 100644 (file)
@@ -933,8 +933,13 @@ asmlinkage int syscall_trace_enter(struct pt_regs *regs, int scno)
        current_thread_info()->syscall = scno;
 
        /* Do the secure computing check first; failures should be fast. */
-       if (secure_computing(scno) == -1)
+#ifdef CONFIG_HAVE_ARCH_SECCOMP_FILTER
+       if (secure_computing() == -1)
                return -1;
+#else
+       /* XXX: remove this once OABI gets fixed */
+       secure_computing_strict(scno);
+#endif
 
        if (test_thread_flag(TIF_SYSCALL_TRACE))
                tracehook_report_syscall(regs, PTRACE_SYSCALL_ENTER);
index e35d880f9773e675805ad27c830d4124839c7bfc..89cfdd6e50cb1c8024998600f07c85945828bfd6 100644 (file)
@@ -42,7 +42,7 @@
  */
 static DEFINE_PER_CPU(unsigned long, cpu_scale);
 
-unsigned long arch_scale_freq_capacity(struct sched_domain *sd, int cpu)
+unsigned long arch_scale_cpu_capacity(struct sched_domain *sd, int cpu)
 {
        return per_cpu(cpu_scale, cpu);
 }
@@ -166,7 +166,7 @@ static void update_cpu_capacity(unsigned int cpu)
        set_capacity_scale(cpu, cpu_capacity(cpu) / middle_capacity);
 
        printk(KERN_INFO "CPU%u: update cpu_capacity %lu\n",
-               cpu, arch_scale_freq_capacity(NULL, cpu));
+               cpu, arch_scale_cpu_capacity(NULL, cpu));
 }
 
 #else
index ac99d87ffefea5562346f454ae145c1f3e94200e..1b9ae0257a6eac6321c94bea9ccde88a286731fd 100644 (file)
@@ -3,9 +3,6 @@
 #
 
 obj-y          := gpio.o setup.o sysirq_mask.o
-obj-m          :=
-obj-n          :=
-obj-           :=
 
 obj-$(CONFIG_OLD_IRQ_AT91)     += irq.o
 obj-$(CONFIG_OLD_CLK_AT91)     += clock.o
index 935e4af01a2769a7ab83282bda801389f36a4d50..a7d68c13c1d16fb53ef40d4f3633915ba3b2448f 100644 (file)
@@ -5,6 +5,3 @@
 # Object file lists.
 
 obj-y                  := core.o io.o leds.o
-obj-m                  :=
-obj-n                  :=
-obj-                   :=
index 0dc51f9462ded5223839c8172d887da5b01fb063..78d427b34b1f2953c391af495d8e4f479ba6e811 100644 (file)
@@ -2,9 +2,6 @@
 # Makefile for the linux kernel.
 #
 obj-y                  := core.o clock.o
-obj-m                  :=
-obj-n                  :=
-obj-                   :=
 
 obj-$(CONFIG_EP93XX_DMA)       += dma.o
 
index 788f26d21141df6c67c0511e51d9a72d4b02c86e..27ae6144679c6a369087420836bf7210b728f116 100644 (file)
@@ -7,11 +7,6 @@
 
 ccflags-$(CONFIG_ARCH_MULTIPLATFORM) += -I$(srctree)/$(src)/include -I$(srctree)/arch/arm/plat-samsung/include
 
-obj-y                          :=
-obj-m                          :=
-obj-n                          :=
-obj-                           :=
-
 # Core
 
 obj-$(CONFIG_ARCH_EXYNOS)      += exynos.o pmu.o exynos-smc.o firmware.o
index c3faa3bc84dd3ea49321d06ae997132dabd12c7b..e83d5c8396ff720a9c1cb8a3e9095fe4d9166f3c 100644 (file)
@@ -5,9 +5,6 @@
 # Object file lists.
 
 obj-y                  := common.o dma.o isa-irq.o
-obj-m                  :=
-obj-n                  :=
-obj-                   :=
 
 pci-y                  += dc21285.o
 pci-$(CONFIG_ARCH_CATS) += cats-pci.o
index cad015fee12febbefa2e43fb5dbaaa3d39cfafcc..a3d9260e335f2f1e5f5e24119fc2e3cb247f00bd 100644 (file)
@@ -1,8 +1,3 @@
-obj-y                  :=
-obj-m                  :=
-obj-n                  :=
-obj-                   :=
-
 obj-$(CONFIG_ARCH_IOP13XX) += setup.o
 obj-$(CONFIG_ARCH_IOP13XX) += irq.o
 obj-$(CONFIG_ARCH_IOP13XX) += pci.o
index cfdf8a137c2b9f8911771d87859b0edb4934019b..2d4010abb82fb7e9bcd4e00199f14766d67a353b 100644 (file)
@@ -3,9 +3,6 @@
 #
 
 obj-y                  := irq.o
-obj-m                  :=
-obj-n                  :=
-obj-                   :=
 
 obj-$(CONFIG_MACH_GLANTANK) += glantank.o
 obj-$(CONFIG_ARCH_IQ80321) += iq80321.o
index 90081d8c9d16c862da18602d851d7aa92cbea5e5..e95db30d81d5ba74d34551a86020c66a0a40c431 100644 (file)
@@ -3,9 +3,6 @@
 #
 
 obj-y                  := irq.o uart.o
-obj-m                  :=
-obj-n                  :=
-obj-                   :=
 
 obj-$(CONFIG_ARCH_IQ80331) += iq80331.o
 obj-$(CONFIG_MACH_IQ80332) += iq80332.o
index e370caf0c91beacf86ba38305e97f7182f3e4730..8ecb7973ae542c4fa8f89a8f29e9f1ccb6d95c72 100644 (file)
@@ -4,9 +4,6 @@
 #
 
 obj-y                          := cpu.o irq.o time.o devices.o
-obj-m                          :=
-obj-n                          :=
-obj-                           :=
 
 # PCI support is optional
 obj-$(CONFIG_PCI)              += pci.o
index 9f6ec167902a6bc1c2db823d257e006550a3c3b0..ad777b353bd5234797d93031ab6815747b65e363 100644 (file)
@@ -416,17 +416,17 @@ static struct pxafb_mach_info *lpd270_lcd_to_use;
 
 static int __init lpd270_set_lcd(char *str)
 {
-       if (!strnicmp(str, "lq057q3dc02", 11)) {
+       if (!strncasecmp(str, "lq057q3dc02", 11)) {
                lpd270_lcd_to_use = &sharp_lq057q3dc02;
-       } else if (!strnicmp(str, "lq121s1dg31", 11)) {
+       } else if (!strncasecmp(str, "lq121s1dg31", 11)) {
                lpd270_lcd_to_use = &sharp_lq121s1dg31;
-       } else if (!strnicmp(str, "lq036q1da01", 11)) {
+       } else if (!strncasecmp(str, "lq036q1da01", 11)) {
                lpd270_lcd_to_use = &sharp_lq036q1da01;
-       } else if (!strnicmp(str, "lq64d343", 8)) {
+       } else if (!strncasecmp(str, "lq64d343", 8)) {
                lpd270_lcd_to_use = &sharp_lq64d343;
-       } else if (!strnicmp(str, "lq10d368", 8)) {
+       } else if (!strncasecmp(str, "lq10d368", 8)) {
                lpd270_lcd_to_use = &sharp_lq10d368;
-       } else if (!strnicmp(str, "lq035q7db02-20", 14)) {
+       } else if (!strncasecmp(str, "lq035q7db02-20", 14)) {
                lpd270_lcd_to_use = &sharp_lq035q7db02_20;
        } else {
                printk(KERN_INFO "lpd270: unknown lcd panel [%s]\n", str);
index 992e28b4ae9a54ddab9ea92b2d0c92d6b303964e..2ebc6875aeb8f69dc4e27fd1bc3f636e8b2125f2 100644 (file)
@@ -5,7 +5,3 @@
 # Object file lists.
 
 obj-y                  := dma.o ecard.o fiq.o irq.o riscpc.o time.o
-obj-m                  :=
-obj-n                  :=
-obj-                   :=
-
index 2235d0d3b38dd933b81687bcc681001a2a44d8d8..b92071638733badcd7f69d65c685e35d731773a8 100644 (file)
@@ -7,11 +7,6 @@
 #
 # Licensed under GPLv2
 
-obj-y                          :=
-obj-m                          :=
-obj-n                          :=
-obj-                           :=
-
 # core
 
 obj-y                          += common.o
index 58069a702a435046ae627bff9ab4e8c689b1aa3c..12f67b61ca5f7e7340821f21744530bef0ec844d 100644 (file)
@@ -5,11 +5,6 @@
 #
 # Licensed under GPLv2
 
-obj-y                          :=
-obj-m                          :=
-obj-n                          :=
-obj-                           :=
-
 # Core
 
 obj-y                          += common.o
index 7dc2d0e25a83363e337e5e6e8433ee66ae1527cc..72b9e96715070f2c47b13b7f7aade101abb9586e 100644 (file)
@@ -7,11 +7,6 @@
 
 ccflags-$(CONFIG_ARCH_MULTIPLATFORM) += -I$(srctree)/$(src)/include -I$(srctree)/arch/arm/plat-samsung/include
 
-obj-y                          :=
-obj-m                          :=
-obj-n                          :=
-obj-                           :=
-
 # Core
 
 obj-$(CONFIG_PM_SLEEP)         += pm.o sleep.o
index 2732eef48966bfa337d34f32fb806f4e604d515c..f1114d11fe13eb21dfe51af7af00f0fb0c0e242a 100644 (file)
@@ -4,9 +4,6 @@
 
 # Common support
 obj-y := clock.o generic.o irq.o time.o #nmi-oopser.o
-obj-m :=
-obj-n :=
-obj-  :=
 
 # Specific board support
 obj-$(CONFIG_SA1100_ASSABET)           += assabet.o
index 9db5e6774fb75753d3a8199301d75887132f5640..46aa540133d6b81cb05053ffaab7a1a28aa21553 100644 (file)
@@ -41,16 +41,15 @@ static struct rcar_du_encoder_data koelsch_du_encoders[] = {
                        .width_mm = 210,
                        .height_mm = 158,
                        .mode = {
-                               .clock = 65000,
-                               .hdisplay = 1024,
-                               .hsync_start = 1048,
-                               .hsync_end = 1184,
-                               .htotal = 1344,
-                               .vdisplay = 768,
-                               .vsync_start = 771,
-                               .vsync_end = 777,
-                               .vtotal = 806,
-                               .flags = 0,
+                               .pixelclock = 65000000,
+                               .hactive = 1024,
+                               .hfront_porch = 20,
+                               .hback_porch = 160,
+                               .hsync_len = 136,
+                               .vactive = 768,
+                               .vfront_porch = 3,
+                               .vback_porch = 29,
+                               .vsync_len = 6,
                        },
                },
        },
index b7d5bc7659cda13537707ecbb4e39f43f6e76c61..7111b5c1d67b764f79daec420390fea7f408c92c 100644 (file)
@@ -63,16 +63,15 @@ static struct rcar_du_encoder_data koelsch_du_encoders[] = {
                        .width_mm = 210,
                        .height_mm = 158,
                        .mode = {
-                               .clock = 65000,
-                               .hdisplay = 1024,
-                               .hsync_start = 1048,
-                               .hsync_end = 1184,
-                               .htotal = 1344,
-                               .vdisplay = 768,
-                               .vsync_start = 771,
-                               .vsync_end = 777,
-                               .vtotal = 806,
-                               .flags = 0,
+                               .pixelclock = 65000000,
+                               .hactive = 1024,
+                               .hfront_porch = 20,
+                               .hback_porch = 160,
+                               .hsync_len = 136,
+                               .vactive = 768,
+                               .vfront_porch = 3,
+                               .vback_porch = 29,
+                               .vsync_len = 6,
                        },
                },
        },
@@ -331,7 +330,6 @@ SDHI_REGULATOR(2, RCAR_GP_PIN(7, 19), RCAR_GP_PIN(2, 26));
 static struct sh_mobile_sdhi_info sdhi0_info __initdata = {
        .tmio_caps      = MMC_CAP_SD_HIGHSPEED | MMC_CAP_SDIO_IRQ |
                          MMC_CAP_POWER_OFF_CARD,
-       .tmio_caps2     = MMC_CAP2_NO_MULTI_READ,
        .tmio_flags     = TMIO_MMC_HAS_IDLE_WAIT,
 };
 
@@ -344,7 +342,6 @@ static struct resource sdhi0_resources[] __initdata = {
 static struct sh_mobile_sdhi_info sdhi1_info __initdata = {
        .tmio_caps      = MMC_CAP_SD_HIGHSPEED | MMC_CAP_SDIO_IRQ |
                          MMC_CAP_POWER_OFF_CARD,
-       .tmio_caps2     = MMC_CAP2_NO_MULTI_READ,
        .tmio_flags     = TMIO_MMC_HAS_IDLE_WAIT,
 };
 
@@ -357,7 +354,6 @@ static struct resource sdhi1_resources[] __initdata = {
 static struct sh_mobile_sdhi_info sdhi2_info __initdata = {
        .tmio_caps      = MMC_CAP_SD_HIGHSPEED | MMC_CAP_SDIO_IRQ |
                          MMC_CAP_POWER_OFF_CARD,
-       .tmio_caps2     = MMC_CAP2_NO_MULTI_READ,
        .tmio_flags     = TMIO_MMC_HAS_IDLE_WAIT |
                          TMIO_MMC_WRPROTECT_DISABLE,
 };
index 2a05c02bec3965f4f1dc4493b5d7fdaea40af275..bc4b48357ddea891ccb0365ba267325adff374d8 100644 (file)
@@ -43,16 +43,15 @@ static struct rcar_du_encoder_data lager_du_encoders[] = {
                        .width_mm = 210,
                        .height_mm = 158,
                        .mode = {
-                               .clock = 65000,
-                               .hdisplay = 1024,
-                               .hsync_start = 1048,
-                               .hsync_end = 1184,
-                               .htotal = 1344,
-                               .vdisplay = 768,
-                               .vsync_start = 771,
-                               .vsync_end = 777,
-                               .vtotal = 806,
-                               .flags = 0,
+                               .pixelclock = 65000000,
+                               .hactive = 1024,
+                               .hfront_porch = 20,
+                               .hback_porch = 160,
+                               .hsync_len = 136,
+                               .vactive = 768,
+                               .vfront_porch = 3,
+                               .vback_porch = 29,
+                               .vsync_len = 6,
                        },
                },
        },
index e1d8215da0b050cb47512bbcdb24818ec8750674..571327b1c942c138fbba5cfe8e5ea03d7896ccb1 100644 (file)
@@ -99,16 +99,15 @@ static struct rcar_du_encoder_data lager_du_encoders[] = {
                        .width_mm = 210,
                        .height_mm = 158,
                        .mode = {
-                               .clock = 65000,
-                               .hdisplay = 1024,
-                               .hsync_start = 1048,
-                               .hsync_end = 1184,
-                               .htotal = 1344,
-                               .vdisplay = 768,
-                               .vsync_start = 771,
-                               .vsync_end = 777,
-                               .vtotal = 806,
-                               .flags = 0,
+                               .pixelclock = 65000000,
+                               .hactive = 1024,
+                               .hfront_porch = 20,
+                               .hback_porch = 160,
+                               .hsync_len = 136,
+                               .vactive = 768,
+                               .vfront_porch = 3,
+                               .vback_porch = 29,
+                               .vsync_len = 6,
                        },
                },
        },
@@ -630,7 +629,6 @@ static void __init lager_add_rsnd_device(void)
 static struct sh_mobile_sdhi_info sdhi0_info __initdata = {
        .tmio_caps      = MMC_CAP_SD_HIGHSPEED | MMC_CAP_SDIO_IRQ |
                          MMC_CAP_POWER_OFF_CARD,
-       .tmio_caps2     = MMC_CAP2_NO_MULTI_READ,
        .tmio_flags     = TMIO_MMC_HAS_IDLE_WAIT |
                          TMIO_MMC_WRPROTECT_DISABLE,
 };
@@ -644,7 +642,6 @@ static struct resource sdhi0_resources[] __initdata = {
 static struct sh_mobile_sdhi_info sdhi2_info __initdata = {
        .tmio_caps      = MMC_CAP_SD_HIGHSPEED | MMC_CAP_SDIO_IRQ |
                          MMC_CAP_POWER_OFF_CARD,
-       .tmio_caps2     = MMC_CAP2_NO_MULTI_READ,
        .tmio_flags     = TMIO_MMC_HAS_IDLE_WAIT |
                          TMIO_MMC_WRPROTECT_DISABLE,
 };
index e5cf4201e769645829a6c78b1c28b35b55a65085..ce33d7825c49a818a2bb1927299be684a7196544 100644 (file)
@@ -192,16 +192,15 @@ static struct rcar_du_encoder_data du_encoders[] = {
                        .width_mm = 210,
                        .height_mm = 158,
                        .mode = {
-                               .clock = 65000,
-                               .hdisplay = 1024,
-                               .hsync_start = 1048,
-                               .hsync_end = 1184,
-                               .htotal = 1344,
-                               .vdisplay = 768,
-                               .vsync_start = 771,
-                               .vsync_end = 777,
-                               .vtotal = 806,
-                               .flags = 0,
+                               .pixelclock = 65000000,
+                               .hactive = 1024,
+                               .hfront_porch = 20,
+                               .hback_porch = 160,
+                               .hsync_len = 136,
+                               .vactive = 768,
+                               .vfront_porch = 3,
+                               .vback_porch = 29,
+                               .vsync_len = 6,
                        },
                },
        },
index 3ec74ac95bc1c1087c04776c0c1b2e6176273f4f..87d37de054b65b5d273dddd29d97ac5fc0912c8b 100644 (file)
@@ -3,9 +3,6 @@
 #
 
 obj-y          := core.o
-obj-m          :=
-obj-n          :=
-obj-           :=
 
 obj-$(CONFIG_MACH_U300_SPIDUMMY)  += dummyspichip.o
 obj-$(CONFIG_REGULATOR_AB3100)    += regulator.o
index 224e56c6049b04f35579e385fd0a7bed83899b1c..f2af203d601f2bb057921e3277f489797dc77fc4 100644 (file)
@@ -2,8 +2,6 @@
 # Makefile for the linux kernel.
 #
 
-obj-y :=
-
 # IOP32X
 obj-$(CONFIG_ARCH_IOP32X) += i2c.o
 obj-$(CONFIG_ARCH_IOP32X) += pci.o
@@ -27,7 +25,3 @@ obj-$(CONFIG_ARCH_IOP33X) += restart.o
 # IOP13XX
 obj-$(CONFIG_ARCH_IOP13XX) += cp6.o
 obj-$(CONFIG_ARCH_IOP13XX) += time.o
-
-obj-m                  :=
-obj-n                  :=
-obj-                   :=
index 0b01b68fd033072c818de997bd07536feb2ca64b..97a50e8883f949726912263af5075db15c4d61e8 100644 (file)
@@ -6,9 +6,6 @@ ccflags-$(CONFIG_ARCH_MULTIPLATFORM) := -I$(srctree)/arch/arm/plat-omap/include
 
 # Common support
 obj-y := sram.o dma.o counter_32k.o
-obj-m :=
-obj-n :=
-obj-  :=
 
 # omap_device support (OMAP2+ only at the moment)
 
index 5fe175017f07bad4d698ad226e38b2c41cec0bb4..f0a008496993ec1a5fc1625068ffb69aa510a3f1 100644 (file)
@@ -6,11 +6,6 @@
 
 ccflags-$(CONFIG_ARCH_MULTI_V7) += -I$(srctree)/$(src)/include
 
-obj-y                          :=
-obj-m                          :=
-obj-n                          := dummy.o
-obj-                           :=
-
 # Objects we always build independent of SoC choice
 
 obj-y                          += init.o cpu.o
index c49ca4c738bb2ede8664d7ac6bcb70bfa994a993..ac9afde76dead843ed4a53b2e0da97e4a7a0bd72 100644 (file)
@@ -349,7 +349,7 @@ config XEN_DOM0
        depends on XEN
 
 config XEN
-       bool "Xen guest support on ARM64 (EXPERIMENTAL)"
+       bool "Xen guest support on ARM64"
        depends on ARM64 && OF
        select SWIOTLB_XEN
        help
index 59c86b6b30520444d77f061d677049acb8e694b7..20901ffed182a6d1b1f41c08f91109e1ac2047ef 100644 (file)
@@ -30,8 +30,6 @@ AS            += -EL
 LD             += -EL
 endif
 
-comma = ,
-
 CHECKFLAGS     += -D__aarch64__
 
 # Default value
index f64900052f4ec1c60bb3e70a385f779254ee4fae..8eb6d94c785154cb3c29dba770cde5fed6eaec50 100644 (file)
@@ -40,3 +40,7 @@
 &menet {
        status = "ok";
 };
+
+&xgenet {
+       status = "ok";
+};
index 4f6d04d52cca604fe5040f6f7de514b25768f88b..87d3205e98d545fefb72d17f84ba51efef35a5b5 100644 (file)
                                clock-output-names = "menetclk";
                        };
 
+                       xge0clk: xge0clk@1f61c000 {
+                               compatible = "apm,xgene-device-clock";
+                               #clock-cells = <1>;
+                               clocks = <&socplldiv2 0>;
+                               reg = <0x0 0x1f61c000 0x0 0x1000>;
+                               reg-names = "csr-reg";
+                               csr-mask = <0x3>;
+                               clock-output-names = "xge0clk";
+                       };
+
                        sataphy1clk: sataphy1clk@1f21c000 {
                                compatible = "apm,xgene-device-clock";
                                #clock-cells = <1>;
                        interrupts = <0x0 0x3c 0x4>;
                        dma-coherent;
                        clocks = <&menetclk 0>;
-                       local-mac-address = [00 01 73 00 00 01];
+                       /* mac address will be overwritten by the bootloader */
+                       local-mac-address = [00 00 00 00 00 00];
                        phy-connection-type = "rgmii";
                        phy-handle = <&menetphy>;
                        mdio {
                        };
                };
 
+               xgenet: ethernet@1f610000 {
+                       compatible = "apm,xgene-enet";
+                       status = "disabled";
+                       reg = <0x0 0x1f610000 0x0 0xd100>,
+                             <0x0 0x1f600000 0x0 0X400>,
+                             <0x0 0x18000000 0x0 0X200>;
+                       reg-names = "enet_csr", "ring_csr", "ring_cmd";
+                       interrupts = <0x0 0x60 0x4>;
+                       dma-coherent;
+                       clocks = <&xge0clk 0>;
+                       /* mac address will be overwritten by the bootloader */
+                       local-mac-address = [00 00 00 00 00 00];
+                       phy-connection-type = "xgmii";
+               };
+
                rng: rng@10520000 {
                        compatible = "apm,xgene-rng";
                        reg = <0x0 0x10520000 0x0 0x100>;
                        interrupts = <0x0 0x41 0x4>;
                        clocks = <&rngpkaclk 0>;
                };
-
        };
 };
index 65f1569ac96e5e2772548f20e6f172c8ee2ad0b4..7047051ded40e3e9c3cc944fe0ce456bb6eaf897 100644 (file)
@@ -35,7 +35,7 @@
  * strex/ldrex monitor on some implementations. The reason we can use it for
  * atomic_set() is the clrex or dummy strex done on every exception return.
  */
-#define atomic_read(v) (*(volatile int *)&(v)->counter)
+#define atomic_read(v) ACCESS_ONCE((v)->counter)
 #define atomic_set(v,i)        (((v)->counter) = (i))
 
 /*
  * store exclusive to ensure that these are atomic.  We may loop
  * to ensure that the update happens.
  */
-static inline void atomic_add(int i, atomic_t *v)
-{
-       unsigned long tmp;
-       int result;
-
-       asm volatile("// atomic_add\n"
-"1:    ldxr    %w0, %2\n"
-"      add     %w0, %w0, %w3\n"
-"      stxr    %w1, %w0, %2\n"
-"      cbnz    %w1, 1b"
-       : "=&r" (result), "=&r" (tmp), "+Q" (v->counter)
-       : "Ir" (i));
-}
-
-static inline int atomic_add_return(int i, atomic_t *v)
-{
-       unsigned long tmp;
-       int result;
-
-       asm volatile("// atomic_add_return\n"
-"1:    ldxr    %w0, %2\n"
-"      add     %w0, %w0, %w3\n"
-"      stlxr   %w1, %w0, %2\n"
-"      cbnz    %w1, 1b"
-       : "=&r" (result), "=&r" (tmp), "+Q" (v->counter)
-       : "Ir" (i)
-       : "memory");
-
-       smp_mb();
-       return result;
-}
-
-static inline void atomic_sub(int i, atomic_t *v)
-{
-       unsigned long tmp;
-       int result;
 
-       asm volatile("// atomic_sub\n"
-"1:    ldxr    %w0, %2\n"
-"      sub     %w0, %w0, %w3\n"
-"      stxr    %w1, %w0, %2\n"
-"      cbnz    %w1, 1b"
-       : "=&r" (result), "=&r" (tmp), "+Q" (v->counter)
-       : "Ir" (i));
+#define ATOMIC_OP(op, asm_op)                                          \
+static inline void atomic_##op(int i, atomic_t *v)                     \
+{                                                                      \
+       unsigned long tmp;                                              \
+       int result;                                                     \
+                                                                       \
+       asm volatile("// atomic_" #op "\n"                              \
+"1:    ldxr    %w0, %2\n"                                              \
+"      " #asm_op "     %w0, %w0, %w3\n"                                \
+"      stxr    %w1, %w0, %2\n"                                         \
+"      cbnz    %w1, 1b"                                                \
+       : "=&r" (result), "=&r" (tmp), "+Q" (v->counter)                \
+       : "Ir" (i));                                                    \
+}                                                                      \
+
+#define ATOMIC_OP_RETURN(op, asm_op)                                   \
+static inline int atomic_##op##_return(int i, atomic_t *v)             \
+{                                                                      \
+       unsigned long tmp;                                              \
+       int result;                                                     \
+                                                                       \
+       asm volatile("// atomic_" #op "_return\n"                       \
+"1:    ldxr    %w0, %2\n"                                              \
+"      " #asm_op "     %w0, %w0, %w3\n"                                \
+"      stlxr   %w1, %w0, %2\n"                                         \
+"      cbnz    %w1, 1b"                                                \
+       : "=&r" (result), "=&r" (tmp), "+Q" (v->counter)                \
+       : "Ir" (i)                                                      \
+       : "memory");                                                    \
+                                                                       \
+       smp_mb();                                                       \
+       return result;                                                  \
 }
 
-static inline int atomic_sub_return(int i, atomic_t *v)
-{
-       unsigned long tmp;
-       int result;
+#define ATOMIC_OPS(op, asm_op)                                         \
+       ATOMIC_OP(op, asm_op)                                           \
+       ATOMIC_OP_RETURN(op, asm_op)
 
-       asm volatile("// atomic_sub_return\n"
-"1:    ldxr    %w0, %2\n"
-"      sub     %w0, %w0, %w3\n"
-"      stlxr   %w1, %w0, %2\n"
-"      cbnz    %w1, 1b"
-       : "=&r" (result), "=&r" (tmp), "+Q" (v->counter)
-       : "Ir" (i)
-       : "memory");
+ATOMIC_OPS(add, add)
+ATOMIC_OPS(sub, sub)
 
-       smp_mb();
-       return result;
-}
+#undef ATOMIC_OPS
+#undef ATOMIC_OP_RETURN
+#undef ATOMIC_OP
 
 static inline int atomic_cmpxchg(atomic_t *ptr, int old, int new)
 {
@@ -157,72 +139,53 @@ static inline int __atomic_add_unless(atomic_t *v, int a, int u)
  */
 #define ATOMIC64_INIT(i) { (i) }
 
-#define atomic64_read(v)       (*(volatile long *)&(v)->counter)
+#define atomic64_read(v)       ACCESS_ONCE((v)->counter)
 #define atomic64_set(v,i)      (((v)->counter) = (i))
 
-static inline void atomic64_add(u64 i, atomic64_t *v)
-{
-       long result;
-       unsigned long tmp;
-
-       asm volatile("// atomic64_add\n"
-"1:    ldxr    %0, %2\n"
-"      add     %0, %0, %3\n"
-"      stxr    %w1, %0, %2\n"
-"      cbnz    %w1, 1b"
-       : "=&r" (result), "=&r" (tmp), "+Q" (v->counter)
-       : "Ir" (i));
+#define ATOMIC64_OP(op, asm_op)                                                \
+static inline void atomic64_##op(long i, atomic64_t *v)                        \
+{                                                                      \
+       long result;                                                    \
+       unsigned long tmp;                                              \
+                                                                       \
+       asm volatile("// atomic64_" #op "\n"                            \
+"1:    ldxr    %0, %2\n"                                               \
+"      " #asm_op "     %0, %0, %3\n"                                   \
+"      stxr    %w1, %0, %2\n"                                          \
+"      cbnz    %w1, 1b"                                                \
+       : "=&r" (result), "=&r" (tmp), "+Q" (v->counter)                \
+       : "Ir" (i));                                                    \
+}                                                                      \
+
+#define ATOMIC64_OP_RETURN(op, asm_op)                                 \
+static inline long atomic64_##op##_return(long i, atomic64_t *v)       \
+{                                                                      \
+       long result;                                                    \
+       unsigned long tmp;                                              \
+                                                                       \
+       asm volatile("// atomic64_" #op "_return\n"                     \
+"1:    ldxr    %0, %2\n"                                               \
+"      " #asm_op "     %0, %0, %3\n"                                   \
+"      stlxr   %w1, %0, %2\n"                                          \
+"      cbnz    %w1, 1b"                                                \
+       : "=&r" (result), "=&r" (tmp), "+Q" (v->counter)                \
+       : "Ir" (i)                                                      \
+       : "memory");                                                    \
+                                                                       \
+       smp_mb();                                                       \
+       return result;                                                  \
 }
 
-static inline long atomic64_add_return(long i, atomic64_t *v)
-{
-       long result;
-       unsigned long tmp;
+#define ATOMIC64_OPS(op, asm_op)                                       \
+       ATOMIC64_OP(op, asm_op)                                         \
+       ATOMIC64_OP_RETURN(op, asm_op)
 
-       asm volatile("// atomic64_add_return\n"
-"1:    ldxr    %0, %2\n"
-"      add     %0, %0, %3\n"
-"      stlxr   %w1, %0, %2\n"
-"      cbnz    %w1, 1b"
-       : "=&r" (result), "=&r" (tmp), "+Q" (v->counter)
-       : "Ir" (i)
-       : "memory");
+ATOMIC64_OPS(add, add)
+ATOMIC64_OPS(sub, sub)
 
-       smp_mb();
-       return result;
-}
-
-static inline void atomic64_sub(u64 i, atomic64_t *v)
-{
-       long result;
-       unsigned long tmp;
-
-       asm volatile("// atomic64_sub\n"
-"1:    ldxr    %0, %2\n"
-"      sub     %0, %0, %3\n"
-"      stxr    %w1, %0, %2\n"
-"      cbnz    %w1, 1b"
-       : "=&r" (result), "=&r" (tmp), "+Q" (v->counter)
-       : "Ir" (i));
-}
-
-static inline long atomic64_sub_return(long i, atomic64_t *v)
-{
-       long result;
-       unsigned long tmp;
-
-       asm volatile("// atomic64_sub_return\n"
-"1:    ldxr    %0, %2\n"
-"      sub     %0, %0, %3\n"
-"      stlxr   %w1, %0, %2\n"
-"      cbnz    %w1, 1b"
-       : "=&r" (result), "=&r" (tmp), "+Q" (v->counter)
-       : "Ir" (i)
-       : "memory");
-
-       smp_mb();
-       return result;
-}
+#undef ATOMIC64_OPS
+#undef ATOMIC64_OP_RETURN
+#undef ATOMIC64_OP
 
 static inline long atomic64_cmpxchg(atomic64_t *ptr, long old, long new)
 {
index 89f41f7d27dd2bc54da37bd850f5437f86b19630..c3065dbc4fa269bafbb0b93f5a458d0534ae2bc5 100644 (file)
@@ -72,7 +72,6 @@ void (*pm_power_off)(void);
 EXPORT_SYMBOL_GPL(pm_power_off);
 
 void (*arm_pm_restart)(enum reboot_mode reboot_mode, const char *cmd);
-EXPORT_SYMBOL_GPL(arm_pm_restart);
 
 /*
  * This is our default idle handler.
@@ -154,6 +153,8 @@ void machine_restart(char *cmd)
        /* Now call the architecture specific reboot code. */
        if (arm_pm_restart)
                arm_pm_restart(reboot_mode, cmd);
+       else
+               do_kernel_restart(cmd);
 
        /*
         * Whoops - the architecture was unable to reboot.
index 0780f3f2415becf5eb957d611514e7deaf44af55..2d07ce1c5327cae2f0428714757ecf0163b8605d 100644 (file)
 
 #define ATOMIC_INIT(i)  { (i) }
 
-#define atomic_read(v)         (*(volatile int *)&(v)->counter)
+#define atomic_read(v)         ACCESS_ONCE((v)->counter)
 #define atomic_set(v, i)       (((v)->counter) = i)
 
+#define ATOMIC_OP_RETURN(op, asm_op, asm_con)                          \
+static inline int __atomic_##op##_return(int i, atomic_t *v)           \
+{                                                                      \
+       int result;                                                     \
+                                                                       \
+       asm volatile(                                                   \
+               "/* atomic_" #op "_return */\n"                         \
+               "1:     ssrf    5\n"                                    \
+               "       ld.w    %0, %2\n"                               \
+               "       " #asm_op "     %0, %3\n"                       \
+               "       stcond  %1, %0\n"                               \
+               "       brne    1b"                                     \
+               : "=&r" (result), "=o" (v->counter)                     \
+               : "m" (v->counter), #asm_con (i)                        \
+               : "cc");                                                \
+                                                                       \
+       return result;                                                  \
+}
+
+ATOMIC_OP_RETURN(sub, sub, rKs21)
+ATOMIC_OP_RETURN(add, add, r)
+
+#undef ATOMIC_OP_RETURN
+
 /*
- * atomic_sub_return - subtract the atomic variable
- * @i: integer value to subtract
- * @v: pointer of type atomic_t
+ * Probably found the reason why we want to use sub with the signed 21-bit
+ * limit, it uses one less register than the add instruction that can add up to
+ * 32-bit values.
  *
- * Atomically subtracts @i from @v. Returns the resulting value.
+ * Both instructions are 32-bit, to use a 16-bit instruction the immediate is
+ * very small; 4 bit.
+ *
+ * sub 32-bit, type IV, takes a register and subtracts a 21-bit immediate.
+ * add 32-bit, type II, adds two register values together.
  */
-static inline int atomic_sub_return(int i, atomic_t *v)
-{
-       int result;
-
-       asm volatile(
-               "/* atomic_sub_return */\n"
-               "1:     ssrf    5\n"
-               "       ld.w    %0, %2\n"
-               "       sub     %0, %3\n"
-               "       stcond  %1, %0\n"
-               "       brne    1b"
-               : "=&r"(result), "=o"(v->counter)
-               : "m"(v->counter), "rKs21"(i)
-               : "cc");
-
-       return result;
-}
+#define IS_21BIT_CONST(i)                                              \
+       (__builtin_constant_p(i) && ((i) >= -1048575) && ((i) <= 1048576))
 
 /*
  * atomic_add_return - add integer to atomic variable
@@ -56,51 +69,25 @@ static inline int atomic_sub_return(int i, atomic_t *v)
  */
 static inline int atomic_add_return(int i, atomic_t *v)
 {
-       int result;
-
-       if (__builtin_constant_p(i) && (i >= -1048575) && (i <= 1048576))
-               result = atomic_sub_return(-i, v);
-       else
-               asm volatile(
-                       "/* atomic_add_return */\n"
-                       "1:     ssrf    5\n"
-                       "       ld.w    %0, %1\n"
-                       "       add     %0, %3\n"
-                       "       stcond  %2, %0\n"
-                       "       brne    1b"
-                       : "=&r"(result), "=o"(v->counter)
-                       : "m"(v->counter), "r"(i)
-                       : "cc", "memory");
+       if (IS_21BIT_CONST(i))
+               return __atomic_sub_return(-i, v);
 
-       return result;
+       return __atomic_add_return(i, v);
 }
 
 /*
- * atomic_sub_unless - sub unless the number is a given value
+ * atomic_sub_return - subtract the atomic variable
+ * @i: integer value to subtract
  * @v: pointer of type atomic_t
- * @a: the amount to subtract from v...
- * @u: ...unless v is equal to u.
  *
- * Atomically subtract @a from @v, so long as it was not @u.
- * Returns the old value of @v.
-*/
-static inline void atomic_sub_unless(atomic_t *v, int a, int u)
+ * Atomically subtracts @i from @v. Returns the resulting value.
+ */
+static inline int atomic_sub_return(int i, atomic_t *v)
 {
-       int tmp;
+       if (IS_21BIT_CONST(i))
+               return __atomic_sub_return(i, v);
 
-       asm volatile(
-               "/* atomic_sub_unless */\n"
-               "1:     ssrf    5\n"
-               "       ld.w    %0, %2\n"
-               "       cp.w    %0, %4\n"
-               "       breq    1f\n"
-               "       sub     %0, %3\n"
-               "       stcond  %1, %0\n"
-               "       brne    1b\n"
-               "1:"
-               : "=&r"(tmp), "=o"(v->counter)
-               : "m"(v->counter), "rKs21"(a), "rKs21"(u)
-               : "cc", "memory");
+       return __atomic_add_return(-i, v);
 }
 
 /*
@@ -116,9 +103,21 @@ static inline int __atomic_add_unless(atomic_t *v, int a, int u)
 {
        int tmp, old = atomic_read(v);
 
-       if (__builtin_constant_p(a) && (a >= -1048575) && (a <= 1048576))
-               atomic_sub_unless(v, -a, u);
-       else {
+       if (IS_21BIT_CONST(a)) {
+               asm volatile(
+                       "/* __atomic_sub_unless */\n"
+                       "1:     ssrf    5\n"
+                       "       ld.w    %0, %2\n"
+                       "       cp.w    %0, %4\n"
+                       "       breq    1f\n"
+                       "       sub     %0, %3\n"
+                       "       stcond  %1, %0\n"
+                       "       brne    1b\n"
+                       "1:"
+                       : "=&r"(tmp), "=o"(v->counter)
+                       : "m"(v->counter), "rKs21"(-a), "rKs21"(u)
+                       : "cc", "memory");
+       } else {
                asm volatile(
                        "/* __atomic_add_unless */\n"
                        "1:     ssrf    5\n"
@@ -137,6 +136,8 @@ static inline int __atomic_add_unless(atomic_t *v, int a, int u)
        return old;
 }
 
+#undef IS_21BIT_CONST
+
 /*
  * atomic_sub_if_positive - conditionally subtract integer from atomic variable
  * @i: integer value to subtract
index 29eb02ab3f259fa0317986400f25c3ede747a6c1..0f3983241e606fa6e9f1d0ac4ee113ee58d5c75c 100644 (file)
@@ -1086,7 +1086,6 @@ static ssize_t sync_serial_write(struct file *file, const char *buf,
        }
        local_irq_restore(flags);
        schedule();
-       set_current_state(TASK_RUNNING);
        remove_wait_queue(&port->out_wait_q, &wait);
        if (signal_pending(current))
                return -EINTR;
index bbb806b68838e074660c830931955ff355502c7e..5a149134cfb58267bfee6e38121ed4fe7b9de76c 100644 (file)
@@ -1089,7 +1089,6 @@ static ssize_t sync_serial_write(struct file *file, const char *buf,
        }
 
        schedule();
-       set_current_state(TASK_RUNNING);
        remove_wait_queue(&port->out_wait_q, &wait);
 
        if (signal_pending(current))
index aa429baebaf91a1eec8697f1e86750474ae3f3e7..279766a70664f6fdc0544397afe302d3f8052761 100644 (file)
 
 #define ATOMIC_INIT(i)  { (i) }
 
-#define atomic_read(v) (*(volatile int *)&(v)->counter)
+#define atomic_read(v) ACCESS_ONCE((v)->counter)
 #define atomic_set(v,i) (((v)->counter) = (i))
 
 /* These should be written in asm but we do it in C for now. */
 
-static inline void atomic_add(int i, volatile atomic_t *v)
-{
-       unsigned long flags;
-       cris_atomic_save(v, flags);
-       v->counter += i;
-       cris_atomic_restore(v, flags);
+#define ATOMIC_OP(op, c_op)                                            \
+static inline void atomic_##op(int i, volatile atomic_t *v)            \
+{                                                                      \
+       unsigned long flags;                                            \
+       cris_atomic_save(v, flags);                                     \
+       v->counter c_op i;                                              \
+       cris_atomic_restore(v, flags);                                  \
+}                                                                      \
+
+#define ATOMIC_OP_RETURN(op, c_op)                                     \
+static inline int atomic_##op##_return(int i, volatile atomic_t *v)    \
+{                                                                      \
+       unsigned long flags;                                            \
+       int retval;                                                     \
+       cris_atomic_save(v, flags);                                     \
+       retval = (v->counter c_op i);                                   \
+       cris_atomic_restore(v, flags);                                  \
+       return retval;                                                  \
 }
 
-static inline void atomic_sub(int i, volatile atomic_t *v)
-{
-       unsigned long flags;
-       cris_atomic_save(v, flags);
-       v->counter -= i;
-       cris_atomic_restore(v, flags);
-}
+#define ATOMIC_OPS(op, c_op) ATOMIC_OP(op, c_op) ATOMIC_OP_RETURN(op, c_op)
 
-static inline int atomic_add_return(int i, volatile atomic_t *v)
-{
-       unsigned long flags;
-       int retval;
-       cris_atomic_save(v, flags);
-       retval = (v->counter += i);
-       cris_atomic_restore(v, flags);
-       return retval;
-}
+ATOMIC_OPS(add, +=)
+ATOMIC_OPS(sub, -=)
 
-#define atomic_add_negative(a, v)      (atomic_add_return((a), (v)) < 0)
+#undef ATOMIC_OPS
+#undef ATOMIC_OP_RETURN
+#undef ATOMIC_OP
 
-static inline int atomic_sub_return(int i, volatile atomic_t *v)
-{
-       unsigned long flags;
-       int retval;
-       cris_atomic_save(v, flags);
-       retval = (v->counter -= i);
-       cris_atomic_restore(v, flags);
-       return retval;
-}
+#define atomic_add_negative(a, v)      (atomic_add_return((a), (v)) < 0)
 
 static inline int atomic_sub_and_test(int i, volatile atomic_t *v)
 {
index f6c3a16901011b9fc6600a6a5c26ae42b004c2a8..102190a61d65a1fb28f4775309a167355cebcca7 100644 (file)
@@ -31,7 +31,7 @@
  */
 
 #define ATOMIC_INIT(i)         { (i) }
-#define atomic_read(v)         (*(volatile int *)&(v)->counter)
+#define atomic_read(v)         ACCESS_ONCE((v)->counter)
 #define atomic_set(v, i)       (((v)->counter) = (i))
 
 #ifndef CONFIG_FRV_OUTOFLINE_ATOMIC_OPS
index 6aea124f574db5a19d6dac8ec3aafff8d4df7246..2fb9b3ab57b9d624883fb5dd8d53944b12bb1556 100644 (file)
@@ -6,8 +6,6 @@
 #include <linux/spinlock.h>
 #include <asm/uaccess.h>
 
-extern const struct exception_table_entry __attribute__((aligned(8))) __start___ex_table[];
-extern const struct exception_table_entry __attribute__((aligned(8))) __stop___ex_table[];
 extern const void __memset_end, __memset_user_error_lr, __memset_user_error_handler;
 extern const void __memcpy_end, __memcpy_user_error_lr, __memcpy_user_error_handler;
 extern spinlock_t modlist_lock;
index de916b11bff520ccadbc8d885787aff053514c62..93d07025f183d65becd620aba67a2d4f9bf34563 100644 (file)
@@ -94,41 +94,47 @@ static inline int atomic_cmpxchg(atomic_t *v, int old, int new)
        return __oldval;
 }
 
-static inline int atomic_add_return(int i, atomic_t *v)
-{
-       int output;
-
-       __asm__ __volatile__ (
-               "1:     %0 = memw_locked(%1);\n"
-               "       %0 = add(%0,%2);\n"
-               "       memw_locked(%1,P3)=%0;\n"
-               "       if !P3 jump 1b;\n"
-               : "=&r" (output)
-               : "r" (&v->counter), "r" (i)
-               : "memory", "p3"
-       );
-       return output;
-
+#define ATOMIC_OP(op)                                                  \
+static inline void atomic_##op(int i, atomic_t *v)                     \
+{                                                                      \
+       int output;                                                     \
+                                                                       \
+       __asm__ __volatile__ (                                          \
+               "1:     %0 = memw_locked(%1);\n"                        \
+               "       %0 = "#op "(%0,%2);\n"                          \
+               "       memw_locked(%1,P3)=%0;\n"                       \
+               "       if !P3 jump 1b;\n"                              \
+               : "=&r" (output)                                        \
+               : "r" (&v->counter), "r" (i)                            \
+               : "memory", "p3"                                        \
+       );                                                              \
+}                                                                      \
+
+#define ATOMIC_OP_RETURN(op)                                                   \
+static inline int atomic_##op##_return(int i, atomic_t *v)             \
+{                                                                      \
+       int output;                                                     \
+                                                                       \
+       __asm__ __volatile__ (                                          \
+               "1:     %0 = memw_locked(%1);\n"                        \
+               "       %0 = "#op "(%0,%2);\n"                          \
+               "       memw_locked(%1,P3)=%0;\n"                       \
+               "       if !P3 jump 1b;\n"                              \
+               : "=&r" (output)                                        \
+               : "r" (&v->counter), "r" (i)                            \
+               : "memory", "p3"                                        \
+       );                                                              \
+       return output;                                                  \
 }
 
-#define atomic_add(i, v) atomic_add_return(i, (v))
+#define ATOMIC_OPS(op) ATOMIC_OP(op) ATOMIC_OP_RETURN(op)
 
-static inline int atomic_sub_return(int i, atomic_t *v)
-{
-       int output;
-       __asm__ __volatile__ (
-               "1:     %0 = memw_locked(%1);\n"
-               "       %0 = sub(%0,%2);\n"
-               "       memw_locked(%1,P3)=%0\n"
-               "       if !P3 jump 1b;\n"
-               : "=&r" (output)
-               : "r" (&v->counter), "r" (i)
-               : "memory", "p3"
-       );
-       return output;
-}
+ATOMIC_OPS(add)
+ATOMIC_OPS(sub)
 
-#define atomic_sub(i, v) atomic_sub_return(i, (v))
+#undef ATOMIC_OPS
+#undef ATOMIC_OP_RETURN
+#undef ATOMIC_OP
 
 /**
  * __atomic_add_unless - add unless the number is a given value
index 0f8bf48dadf3cee5c20c518a0bd3aa5e44d7055f..0bf03501fe5ca6af6d63173743ad52164cb099b5 100644 (file)
 #define ATOMIC_INIT(i)         { (i) }
 #define ATOMIC64_INIT(i)       { (i) }
 
-#define atomic_read(v)         (*(volatile int *)&(v)->counter)
-#define atomic64_read(v)       (*(volatile long *)&(v)->counter)
+#define atomic_read(v)         ACCESS_ONCE((v)->counter)
+#define atomic64_read(v)       ACCESS_ONCE((v)->counter)
 
 #define atomic_set(v,i)                (((v)->counter) = (i))
 #define atomic64_set(v,i)      (((v)->counter) = (i))
 
-static __inline__ int
-ia64_atomic_add (int i, atomic_t *v)
-{
-       __s32 old, new;
-       CMPXCHG_BUGCHECK_DECL
-
-       do {
-               CMPXCHG_BUGCHECK(v);
-               old = atomic_read(v);
-               new = old + i;
-       } while (ia64_cmpxchg(acq, v, old, new, sizeof(atomic_t)) != old);
-       return new;
+#define ATOMIC_OP(op, c_op)                                            \
+static __inline__ int                                                  \
+ia64_atomic_##op (int i, atomic_t *v)                                  \
+{                                                                      \
+       __s32 old, new;                                                 \
+       CMPXCHG_BUGCHECK_DECL                                           \
+                                                                       \
+       do {                                                            \
+               CMPXCHG_BUGCHECK(v);                                    \
+               old = atomic_read(v);                                   \
+               new = old c_op i;                                       \
+       } while (ia64_cmpxchg(acq, v, old, new, sizeof(atomic_t)) != old); \
+       return new;                                                     \
 }
 
-static __inline__ long
-ia64_atomic64_add (__s64 i, atomic64_t *v)
-{
-       __s64 old, new;
-       CMPXCHG_BUGCHECK_DECL
-
-       do {
-               CMPXCHG_BUGCHECK(v);
-               old = atomic64_read(v);
-               new = old + i;
-       } while (ia64_cmpxchg(acq, v, old, new, sizeof(atomic64_t)) != old);
-       return new;
-}
+ATOMIC_OP(add, +)
+ATOMIC_OP(sub, -)
 
-static __inline__ int
-ia64_atomic_sub (int i, atomic_t *v)
-{
-       __s32 old, new;
-       CMPXCHG_BUGCHECK_DECL
-
-       do {
-               CMPXCHG_BUGCHECK(v);
-               old = atomic_read(v);
-               new = old - i;
-       } while (ia64_cmpxchg(acq, v, old, new, sizeof(atomic_t)) != old);
-       return new;
-}
+#undef ATOMIC_OP
 
-static __inline__ long
-ia64_atomic64_sub (__s64 i, atomic64_t *v)
-{
-       __s64 old, new;
-       CMPXCHG_BUGCHECK_DECL
-
-       do {
-               CMPXCHG_BUGCHECK(v);
-               old = atomic64_read(v);
-               new = old - i;
-       } while (ia64_cmpxchg(acq, v, old, new, sizeof(atomic64_t)) != old);
-       return new;
+#define atomic_add_return(i,v)                                         \
+({                                                                     \
+       int __ia64_aar_i = (i);                                         \
+       (__builtin_constant_p(i)                                        \
+        && (   (__ia64_aar_i ==  1) || (__ia64_aar_i ==   4)           \
+            || (__ia64_aar_i ==  8) || (__ia64_aar_i ==  16)           \
+            || (__ia64_aar_i == -1) || (__ia64_aar_i ==  -4)           \
+            || (__ia64_aar_i == -8) || (__ia64_aar_i == -16)))         \
+               ? ia64_fetch_and_add(__ia64_aar_i, &(v)->counter)       \
+               : ia64_atomic_add(__ia64_aar_i, v);                     \
+})
+
+#define atomic_sub_return(i,v)                                         \
+({                                                                     \
+       int __ia64_asr_i = (i);                                         \
+       (__builtin_constant_p(i)                                        \
+        && (   (__ia64_asr_i ==   1) || (__ia64_asr_i ==   4)          \
+            || (__ia64_asr_i ==   8) || (__ia64_asr_i ==  16)          \
+            || (__ia64_asr_i ==  -1) || (__ia64_asr_i ==  -4)          \
+            || (__ia64_asr_i ==  -8) || (__ia64_asr_i == -16)))        \
+               ? ia64_fetch_and_add(-__ia64_asr_i, &(v)->counter)      \
+               : ia64_atomic_sub(__ia64_asr_i, v);                     \
+})
+
+#define ATOMIC64_OP(op, c_op)                                          \
+static __inline__ long                                                 \
+ia64_atomic64_##op (__s64 i, atomic64_t *v)                            \
+{                                                                      \
+       __s64 old, new;                                                 \
+       CMPXCHG_BUGCHECK_DECL                                           \
+                                                                       \
+       do {                                                            \
+               CMPXCHG_BUGCHECK(v);                                    \
+               old = atomic64_read(v);                                 \
+               new = old c_op i;                                       \
+       } while (ia64_cmpxchg(acq, v, old, new, sizeof(atomic64_t)) != old); \
+       return new;                                                     \
 }
 
+ATOMIC64_OP(add, +)
+ATOMIC64_OP(sub, -)
+
+#undef ATOMIC64_OP
+
+#define atomic64_add_return(i,v)                                       \
+({                                                                     \
+       long __ia64_aar_i = (i);                                        \
+       (__builtin_constant_p(i)                                        \
+        && (   (__ia64_aar_i ==  1) || (__ia64_aar_i ==   4)           \
+            || (__ia64_aar_i ==  8) || (__ia64_aar_i ==  16)           \
+            || (__ia64_aar_i == -1) || (__ia64_aar_i ==  -4)           \
+            || (__ia64_aar_i == -8) || (__ia64_aar_i == -16)))         \
+               ? ia64_fetch_and_add(__ia64_aar_i, &(v)->counter)       \
+               : ia64_atomic64_add(__ia64_aar_i, v);                   \
+})
+
+#define atomic64_sub_return(i,v)                                       \
+({                                                                     \
+       long __ia64_asr_i = (i);                                        \
+       (__builtin_constant_p(i)                                        \
+        && (   (__ia64_asr_i ==   1) || (__ia64_asr_i ==   4)          \
+            || (__ia64_asr_i ==   8) || (__ia64_asr_i ==  16)          \
+            || (__ia64_asr_i ==  -1) || (__ia64_asr_i ==  -4)          \
+            || (__ia64_asr_i ==  -8) || (__ia64_asr_i == -16)))        \
+               ? ia64_fetch_and_add(-__ia64_asr_i, &(v)->counter)      \
+               : ia64_atomic64_sub(__ia64_asr_i, v);                   \
+})
+
 #define atomic_cmpxchg(v, old, new) (cmpxchg(&((v)->counter), old, new))
 #define atomic_xchg(v, new) (xchg(&((v)->counter), new))
 
@@ -123,30 +155,6 @@ static __inline__ long atomic64_add_unless(atomic64_t *v, long a, long u)
 
 #define atomic64_inc_not_zero(v) atomic64_add_unless((v), 1, 0)
 
-#define atomic_add_return(i,v)                                         \
-({                                                                     \
-       int __ia64_aar_i = (i);                                         \
-       (__builtin_constant_p(i)                                        \
-        && (   (__ia64_aar_i ==  1) || (__ia64_aar_i ==   4)           \
-            || (__ia64_aar_i ==  8) || (__ia64_aar_i ==  16)           \
-            || (__ia64_aar_i == -1) || (__ia64_aar_i ==  -4)           \
-            || (__ia64_aar_i == -8) || (__ia64_aar_i == -16)))         \
-               ? ia64_fetch_and_add(__ia64_aar_i, &(v)->counter)       \
-               : ia64_atomic_add(__ia64_aar_i, v);                     \
-})
-
-#define atomic64_add_return(i,v)                                       \
-({                                                                     \
-       long __ia64_aar_i = (i);                                        \
-       (__builtin_constant_p(i)                                        \
-        && (   (__ia64_aar_i ==  1) || (__ia64_aar_i ==   4)           \
-            || (__ia64_aar_i ==  8) || (__ia64_aar_i ==  16)           \
-            || (__ia64_aar_i == -1) || (__ia64_aar_i ==  -4)           \
-            || (__ia64_aar_i == -8) || (__ia64_aar_i == -16)))         \
-               ? ia64_fetch_and_add(__ia64_aar_i, &(v)->counter)       \
-               : ia64_atomic64_add(__ia64_aar_i, v);                   \
-})
-
 /*
  * Atomically add I to V and return TRUE if the resulting value is
  * negative.
@@ -163,30 +171,6 @@ atomic64_add_negative (__s64 i, atomic64_t *v)
        return atomic64_add_return(i, v) < 0;
 }
 
-#define atomic_sub_return(i,v)                                         \
-({                                                                     \
-       int __ia64_asr_i = (i);                                         \
-       (__builtin_constant_p(i)                                        \
-        && (   (__ia64_asr_i ==   1) || (__ia64_asr_i ==   4)          \
-            || (__ia64_asr_i ==   8) || (__ia64_asr_i ==  16)          \
-            || (__ia64_asr_i ==  -1) || (__ia64_asr_i ==  -4)          \
-            || (__ia64_asr_i ==  -8) || (__ia64_asr_i == -16)))        \
-               ? ia64_fetch_and_add(-__ia64_asr_i, &(v)->counter)      \
-               : ia64_atomic_sub(__ia64_asr_i, v);                     \
-})
-
-#define atomic64_sub_return(i,v)                                       \
-({                                                                     \
-       long __ia64_asr_i = (i);                                        \
-       (__builtin_constant_p(i)                                        \
-        && (   (__ia64_asr_i ==   1) || (__ia64_asr_i ==   4)          \
-            || (__ia64_asr_i ==   8) || (__ia64_asr_i ==  16)          \
-            || (__ia64_asr_i ==  -1) || (__ia64_asr_i ==  -4)          \
-            || (__ia64_asr_i ==  -8) || (__ia64_asr_i == -16)))        \
-               ? ia64_fetch_and_add(-__ia64_asr_i, &(v)->counter)      \
-               : ia64_atomic64_sub(__ia64_asr_i, v);                   \
-})
-
 #define atomic_dec_return(v)           atomic_sub_return(1, (v))
 #define atomic_inc_return(v)           atomic_add_return(1, (v))
 #define atomic64_dec_return(v)         atomic64_sub_return(1, (v))
@@ -199,13 +183,13 @@ atomic64_add_negative (__s64 i, atomic64_t *v)
 #define atomic64_dec_and_test(v)       (atomic64_sub_return(1, (v)) == 0)
 #define atomic64_inc_and_test(v)       (atomic64_add_return(1, (v)) == 0)
 
-#define atomic_add(i,v)                        atomic_add_return((i), (v))
-#define atomic_sub(i,v)                        atomic_sub_return((i), (v))
+#define atomic_add(i,v)                        (void)atomic_add_return((i), (v))
+#define atomic_sub(i,v)                        (void)atomic_sub_return((i), (v))
 #define atomic_inc(v)                  atomic_add(1, (v))
 #define atomic_dec(v)                  atomic_sub(1, (v))
 
-#define atomic64_add(i,v)              atomic64_add_return((i), (v))
-#define atomic64_sub(i,v)              atomic64_sub_return((i), (v))
+#define atomic64_add(i,v)              (void)atomic64_add_return((i), (v))
+#define atomic64_sub(i,v)              (void)atomic64_sub_return((i), (v))
 #define atomic64_inc(v)                        atomic64_add(1, (v))
 #define atomic64_dec(v)                        atomic64_sub(1, (v))
 
index c7367130ab14c07c1f643ac867154e01efd80114..ce53c50d0ba443f6e3f925b0c1e0e17e5d385ebe 100644 (file)
@@ -19,7 +19,6 @@
 #include <asm/ptrace.h>
 #include <asm/ustack.h>
 
-#define __ARCH_WANT_UNLOCKED_CTXSW
 #define ARCH_HAS_PREFETCH_SWITCH_STACK
 
 #define IA64_NUM_PHYS_STACK_REG        96
index 1a873b36a4a1cd75f94bb196f1a7997d9ef621f3..2ab2003698ef6acd2fa7e5ffd5cabb31be3317b4 100644 (file)
@@ -10,7 +10,7 @@
 #include <linux/uaccess.h>
 #include <asm-generic/sections.h>
 
-extern char __per_cpu_start[], __per_cpu_end[], __phys_per_cpu_start[];
+extern char __phys_per_cpu_start[];
 #ifdef CONFIG_SMP
 extern char __cpu0_per_cpu[];
 #endif
index 10a14ead70b9d9fd627b416c8567008d1aebc606..f3b51b57740af91e097a7b4b37b4067b5873cd44 100644 (file)
@@ -11,7 +11,7 @@
 
 
 
-#define NR_syscalls                    317 /* length of syscall table */
+#define NR_syscalls                    318 /* length of syscall table */
 
 /*
  * The following defines stop scripts/checksyscalls.sh from complaining about
index 18026b2eb5823c86ab0455088e9b3b1b0c409393..4c2240c1b0cb4b81e219631750c4e61f82ffb750 100644 (file)
 #define __NR_renameat2                 1338
 #define __NR_getrandom                 1339
 #define __NR_memfd_create              1340
+#define __NR_bpf                       1341
 
 #endif /* _UAPI_ASM_IA64_UNISTD_H */
index 01edf242eb296443293fc8b1ee178d72d0a89f55..f5e96dffc63c3d0ce54399759ceb9a5fefacde15 100644 (file)
@@ -1778,6 +1778,7 @@ sys_call_table:
        data8 sys_renameat2
        data8 sys_getrandom
        data8 sys_memfd_create                  // 1340
+       data8 sys_bpf
 
        .org sys_call_table + 8*NR_syscalls     // guard against failures to increase NR_syscalls
 #endif /* __IA64_ASM_PARAVIRTUALIZED_NATIVE */
index 8ad0ed4182a5407d1ace08505dfc805b7e05b24f..31bb74adba082a03bcd121dfa97ac70037a2653d 100644 (file)
@@ -28,7 +28,7 @@
  *
  * Atomically reads the value of @v.
  */
-#define atomic_read(v) (*(volatile int *)&(v)->counter)
+#define atomic_read(v) ACCESS_ONCE((v)->counter)
 
 /**
  * atomic_set - set atomic variable
  */
 #define atomic_set(v,i)        (((v)->counter) = (i))
 
-/**
- * atomic_add_return - add integer to atomic variable and return it
- * @i: integer value to add
- * @v: pointer of type atomic_t
- *
- * Atomically adds @i to @v and return (@i + @v).
- */
-static __inline__ int atomic_add_return(int i, atomic_t *v)
-{
-       unsigned long flags;
-       int result;
-
-       local_irq_save(flags);
-       __asm__ __volatile__ (
-               "# atomic_add_return            \n\t"
-               DCACHE_CLEAR("%0", "r4", "%1")
-               M32R_LOCK" %0, @%1;             \n\t"
-               "add    %0, %2;                 \n\t"
-               M32R_UNLOCK" %0, @%1;           \n\t"
-               : "=&r" (result)
-               : "r" (&v->counter), "r" (i)
-               : "memory"
 #ifdef CONFIG_CHIP_M32700_TS1
-               , "r4"
-#endif /* CONFIG_CHIP_M32700_TS1 */
-       );
-       local_irq_restore(flags);
-
-       return result;
+#define __ATOMIC_CLOBBER       , "r4"
+#else
+#define __ATOMIC_CLOBBER
+#endif
+
+#define ATOMIC_OP(op)                                                  \
+static __inline__ void atomic_##op(int i, atomic_t *v)                 \
+{                                                                      \
+       unsigned long flags;                                            \
+       int result;                                                     \
+                                                                       \
+       local_irq_save(flags);                                          \
+       __asm__ __volatile__ (                                          \
+               "# atomic_" #op "               \n\t"                   \
+               DCACHE_CLEAR("%0", "r4", "%1")                          \
+               M32R_LOCK" %0, @%1;             \n\t"                   \
+               #op " %0, %2;                   \n\t"                   \
+               M32R_UNLOCK" %0, @%1;           \n\t"                   \
+               : "=&r" (result)                                        \
+               : "r" (&v->counter), "r" (i)                            \
+               : "memory"                                              \
+               __ATOMIC_CLOBBER                                        \
+       );                                                              \
+       local_irq_restore(flags);                                       \
+}                                                                      \
+
+#define ATOMIC_OP_RETURN(op)                                           \
+static __inline__ int atomic_##op##_return(int i, atomic_t *v)         \
+{                                                                      \
+       unsigned long flags;                                            \
+       int result;                                                     \
+                                                                       \
+       local_irq_save(flags);                                          \
+       __asm__ __volatile__ (                                          \
+               "# atomic_" #op "_return        \n\t"                   \
+               DCACHE_CLEAR("%0", "r4", "%1")                          \
+               M32R_LOCK" %0, @%1;             \n\t"                   \
+               #op " %0, %2;                   \n\t"                   \
+               M32R_UNLOCK" %0, @%1;           \n\t"                   \
+               : "=&r" (result)                                        \
+               : "r" (&v->counter), "r" (i)                            \
+               : "memory"                                              \
+               __ATOMIC_CLOBBER                                        \
+       );                                                              \
+       local_irq_restore(flags);                                       \
+                                                                       \
+       return result;                                                  \
 }
 
-/**
- * atomic_sub_return - subtract integer from atomic variable and return it
- * @i: integer value to subtract
- * @v: pointer of type atomic_t
- *
- * Atomically subtracts @i from @v and return (@v - @i).
- */
-static __inline__ int atomic_sub_return(int i, atomic_t *v)
-{
-       unsigned long flags;
-       int result;
-
-       local_irq_save(flags);
-       __asm__ __volatile__ (
-               "# atomic_sub_return            \n\t"
-               DCACHE_CLEAR("%0", "r4", "%1")
-               M32R_LOCK" %0, @%1;             \n\t"
-               "sub    %0, %2;                 \n\t"
-               M32R_UNLOCK" %0, @%1;           \n\t"
-               : "=&r" (result)
-               : "r" (&v->counter), "r" (i)
-               : "memory"
-#ifdef CONFIG_CHIP_M32700_TS1
-               , "r4"
-#endif /* CONFIG_CHIP_M32700_TS1 */
-       );
-       local_irq_restore(flags);
-
-       return result;
-}
+#define ATOMIC_OPS(op) ATOMIC_OP(op) ATOMIC_OP_RETURN(op)
 
-/**
- * atomic_add - add integer to atomic variable
- * @i: integer value to add
- * @v: pointer of type atomic_t
- *
- * Atomically adds @i to @v.
- */
-#define atomic_add(i,v) ((void) atomic_add_return((i), (v)))
+ATOMIC_OPS(add)
+ATOMIC_OPS(sub)
 
-/**
- * atomic_sub - subtract the atomic variable
- * @i: integer value to subtract
- * @v: pointer of type atomic_t
- *
- * Atomically subtracts @i from @v.
- */
-#define atomic_sub(i,v) ((void) atomic_sub_return((i), (v)))
+#undef ATOMIC_OPS
+#undef ATOMIC_OP_RETURN
+#undef ATOMIC_OP
 
 /**
  * atomic_sub_and_test - subtract value from variable and test result
@@ -151,9 +130,7 @@ static __inline__ int atomic_inc_return(atomic_t *v)
                : "=&r" (result)
                : "r" (&v->counter)
                : "memory"
-#ifdef CONFIG_CHIP_M32700_TS1
-               , "r4"
-#endif /* CONFIG_CHIP_M32700_TS1 */
+               __ATOMIC_CLOBBER
        );
        local_irq_restore(flags);
 
@@ -181,9 +158,7 @@ static __inline__ int atomic_dec_return(atomic_t *v)
                : "=&r" (result)
                : "r" (&v->counter)
                : "memory"
-#ifdef CONFIG_CHIP_M32700_TS1
-               , "r4"
-#endif /* CONFIG_CHIP_M32700_TS1 */
+               __ATOMIC_CLOBBER
        );
        local_irq_restore(flags);
 
@@ -280,9 +255,7 @@ static __inline__ void atomic_clear_mask(unsigned long  mask, atomic_t *addr)
                : "=&r" (tmp)
                : "r" (addr), "r" (~mask)
                : "memory"
-#ifdef CONFIG_CHIP_M32700_TS1
-               , "r5"
-#endif /* CONFIG_CHIP_M32700_TS1 */
+               __ATOMIC_CLOBBER
        );
        local_irq_restore(flags);
 }
@@ -302,9 +275,7 @@ static __inline__ void atomic_set_mask(unsigned long  mask, atomic_t *addr)
                : "=&r" (tmp)
                : "r" (addr), "r" (mask)
                : "memory"
-#ifdef CONFIG_CHIP_M32700_TS1
-               , "r5"
-#endif /* CONFIG_CHIP_M32700_TS1 */
+               __ATOMIC_CLOBBER
        );
        local_irq_restore(flags);
 }
diff --git a/arch/m68k/68000/Makefile b/arch/m68k/68000/Makefile
new file mode 100644 (file)
index 0000000..1eab70c
--- /dev/null
@@ -0,0 +1,18 @@
+##################################################
+#
+# Makefile for 68000 core based cpus
+#
+# 2012.10.21, Luis Alves <ljalvs@gmail.com>
+#             Merged all 68000 based cpu's config
+#             files into a single directory.
+#
+
+# 68328, 68EZ328, 68VZ328
+
+obj-y                  += entry.o ints.o timers.o
+obj-$(CONFIG_M68328)   += m68328.o
+obj-$(CONFIG_M68EZ328) += m68EZ328.o
+obj-$(CONFIG_M68VZ328) += m68VZ328.o
+obj-$(CONFIG_ROM)      += romvec.o
+
+extra-y                := head.o
diff --git a/arch/m68k/68000/bootlogo-vz.h b/arch/m68k/68000/bootlogo-vz.h
new file mode 100644 (file)
index 0000000..b38e2b2
--- /dev/null
@@ -0,0 +1,3204 @@
+#define splash_width 640
+#define splash_height 480
+unsigned char __attribute__ ((aligned(16))) bootlogo_bits[] = {
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x80, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0xff,
+  0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0xf8, 0xff, 0xff, 0xff, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff,
+  0xff, 0xff, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0xc0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x03, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0xff, 0xff, 0xff,
+  0xff, 0xff, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0xf8, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xff, 0xff,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
+  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x0f, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xff, 0xff, 0xff, 0xff,
+  0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0xe0, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+  0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8,
+  0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8,
+  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x07, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xff, 0x7f, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0xff, 0xff, 0xff, 0xff,
+  0xff, 0xff, 0xff, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0xe0, 0xff, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+  0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0,
+  0x03, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xff,
+  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x00, 0xfe, 0xff, 0x1f,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xff, 0xff, 0xff, 0xff, 0xff,
+  0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x7c, 0x00, 0xe0, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0xe0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+  0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c,
+  0x00, 0x00, 0xf8, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xff,
+  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0xe0, 0x7f,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xff,
+  0xff, 0xff, 0xff, 0xff, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0xfc, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+  0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xff,
+  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff,
+  0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+  0xff, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xff, 0xff,
+  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0xc0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+  0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xff, 0xff,
+  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+  0xff, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xff, 0xff,
+  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x07, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x01, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0xe0, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0xfc, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+  0xff, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0,
+  0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0xff, 0xff,
+  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0f, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x7f, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0xfc, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+  0xff, 0xff, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe,
+  0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff,
+  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0x3f, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x3e, 0xf8, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x80, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+  0xff, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e,
+  0x00, 0xfe, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xff, 0xff, 0xff,
+  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x00, 0xfe, 0xff, 0x1f,
+  0x00, 0x00, 0x00, 0x00, 0x80, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00,
+  0xc0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+  0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0xfc, 0x7f, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xff, 0xff, 0xff,
+  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x7f,
+  0x00, 0x00, 0x00, 0x00, 0xc0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x00,
+  0xe0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+  0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xff, 0x7f, 0xe0,
+  0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0xe0, 0xff, 0xff, 0xff, 0xff, 0x01,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0xe0, 0xff, 0x7f, 0xe0, 0xff, 0xff, 0xff, 0xff,
+  0xff, 0x7f, 0xe0, 0xff, 0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0xe0, 0xff, 0x7f, 0xe0, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0xe0, 0xff,
+  0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0xe0, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xff, 0x7f, 0xe0,
+  0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0xe0, 0xff, 0xff, 0xff, 0xff, 0x03,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xff, 0x1f,
+  0x00, 0x00, 0x00, 0x00, 0xf0, 0xff, 0x7f, 0xe0, 0xff, 0xff, 0xff, 0xff,
+  0xff, 0x7f, 0xe0, 0xff, 0xff, 0xff, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00,
+  0xf0, 0xff, 0x7f, 0xe0, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0xe0, 0xff,
+  0xff, 0xff, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0xf0, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xff, 0x7f, 0xe0,
+  0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0xe0, 0xff, 0x07, 0xfe, 0xff, 0x03,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0xff, 0xff,
+  0x03, 0x00, 0x00, 0x00, 0xf0, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0xe0, 0xff, 0x01, 0xf8, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x80, 0xff, 0xff, 0xff, 0xff, 0x0f, 0x00, 0x00, 0x00,
+  0xf8, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xff,
+  0x00, 0xf0, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
+  0xff, 0xff, 0xff, 0xff, 0x1f, 0x00, 0x00, 0x00, 0xf8, 0xff, 0x7f, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x7f, 0x00, 0xe0, 0xff, 0x07,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xff, 0xff, 0xff, 0x03,
+  0x3f, 0x00, 0x00, 0x00, 0xf8, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0xe0, 0x3f, 0x00, 0xc0, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0xf8, 0xff, 0xff, 0xff, 0x0f, 0xfc, 0x00, 0x00, 0x00,
+  0xf8, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x1f,
+  0x00, 0x80, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8,
+  0xff, 0xff, 0xff, 0x3f, 0xf0, 0x01, 0x00, 0x00, 0xf8, 0xff, 0x7f, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x1f, 0x00, 0x80, 0xff, 0x07,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x3f, 0x00, 0xc0, 0xff,
+  0xc1, 0x03, 0x00, 0x00, 0xf8, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0xe0, 0x0f, 0x00, 0x00, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0xfe, 0x0f, 0x00, 0x00, 0xfc, 0x07, 0x07, 0x00, 0x00,
+  0xf8, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x0f,
+  0x00, 0x00, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe,
+  0x07, 0x00, 0x00, 0xe0, 0x07, 0x0e, 0x00, 0x00, 0xf8, 0xff, 0x7f, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x0f, 0x00, 0x00, 0xff, 0x07,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x01, 0x00, 0x00, 0x00,
+  0x3f, 0x1c, 0x00, 0x00, 0xf8, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0xe0, 0x0f, 0x00, 0x00, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x38, 0x00, 0x00,
+  0xf8, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x0f,
+  0x00, 0x00, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e,
+  0x00, 0x00, 0x00, 0x00, 0x78, 0x70, 0x00, 0x00, 0xf8, 0xff, 0x7f, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x0f, 0x00, 0x00, 0xff, 0x07,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00,
+  0xf0, 0xe0, 0x00, 0x00, 0xf8, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0xe0, 0x0f, 0x00, 0x00, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xc3, 0x01, 0x00,
+  0xf8, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x1f,
+  0x00, 0x80, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f,
+  0x00, 0x00, 0x00, 0x00, 0x80, 0xc7, 0x03, 0x00, 0xf8, 0xff, 0x7f, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x1f, 0x00, 0x80, 0xff, 0x07,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x87, 0x03, 0x00, 0xf8, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0xe0, 0x3f, 0x00, 0xc0, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x07, 0x00,
+  0xf8, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x7f,
+  0x00, 0xe0, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x1f,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x0e, 0x00, 0xf0, 0xff, 0x7f, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xff, 0x00, 0xf0, 0xff, 0x03,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x1f, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x30, 0x0c, 0x00, 0xf0, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0xe0, 0xff, 0x01, 0xf8, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x1c, 0x00,
+  0xf0, 0xff, 0x7f, 0xe0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+  0x07, 0xfe, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x38, 0x00, 0xf0, 0xff, 0x7f, 0xe0,
+  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x80, 0x38, 0x00, 0xf0, 0xff, 0x7f, 0xe0, 0xff, 0xff, 0xff, 0xff,
+  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x71, 0x00,
+  0xe0, 0xff, 0x7f, 0xe0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+  0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x72, 0x00, 0xe0, 0xff, 0x7f, 0xe0,
+  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0xe2, 0x00, 0xe0, 0xff, 0x7f, 0xe0, 0xff, 0xff, 0xff, 0xff,
+  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x00,
+  0xe0, 0xff, 0x7f, 0xe0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+  0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x01, 0xc0, 0xff, 0xff, 0xff,
+  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0xe0, 0x01, 0xc0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x01,
+  0xc0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+  0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x03, 0x80, 0xff, 0xff, 0xff,
+  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0xc0, 0x03, 0x80, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x03,
+  0x80, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+  0xff, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x07, 0x00, 0xff, 0xff, 0xff,
+  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x01, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0xc0, 0x07, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0xe0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x07,
+  0x00, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+  0xff, 0xff, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
+  0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x07, 0x00, 0xfe, 0xff, 0xff,
+  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x03, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0xc0, 0x07, 0x00, 0xfc, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x07,
+  0x00, 0xfc, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+  0xff, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x07, 0x00, 0xf8, 0xff, 0xff,
+  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x07, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0xc0, 0x07, 0x00, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x07,
+  0x00, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+  0xff, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x07, 0x00, 0xf0, 0xff, 0xff,
+  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x07, 0x00, 0xe0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07,
+  0x00, 0xc0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+  0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xff, 0xff,
+  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+  0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x10, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+  0xff, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc,
+  0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xff,
+  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0f, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x9f, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff,
+  0xff, 0xff, 0xff, 0xff, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0xfe, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0xfc, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+  0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe,
+  0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xff,
+  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0x0f, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff,
+  0xff, 0xff, 0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x1c, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0xe0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+  0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c,
+  0xf8, 0xff, 0x1f, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xff,
+  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x80, 0xff, 0xff, 0x00,
+  0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xff, 0xff, 0xff, 0xff, 0xff,
+  0xff, 0xff, 0xff, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x38, 0x00, 0xfe, 0xff, 0x0f, 0x20, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+  0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70,
+  0x00, 0xf8, 0xff, 0xff, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc,
+  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0f, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x00, 0xc0, 0xff, 0xff,
+  0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xff, 0xff, 0xff, 0xff,
+  0xff, 0xff, 0xff, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x80, 0x03, 0x00, 0xfc, 0xff, 0x7f, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+  0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x03, 0x00, 0xe0, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
+  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe,
+  0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xff, 0xff, 0xff, 0xff,
+  0xff, 0xff, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x7f, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0xfc, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xff, 0xff, 0xff,
+  0xff, 0xff, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0xc0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x07, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xff, 0xff,
+  0xff, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0xfe, 0x3f, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe,
+  0xff, 0x03, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0xfc, 0xff, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0x1f, 0xc0, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xff,
+  0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0xfe, 0xff, 0xff, 0xc1, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c,
+  0xfe, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0xf0, 0xff, 0xff, 0x01,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x38, 0x00, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70,
+  0x00, 0xf8, 0xff, 0x01, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x00, 0xc0, 0xff, 0x01,
+  0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0xc0, 0x01, 0x00, 0xfc, 0x01, 0xff, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x80, 0x41, 0x08, 0x04, 0xb3, 0x07, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x01, 0x00, 0xe0, 0x03, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
+  0x41, 0x08, 0x04, 0xb3, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02,
+  0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x18, 0x8e, 0x31, 0x7b, 0x30,
+  0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x08, 0x00, 0x00, 0x18, 0x8e, 0x31, 0x7b, 0x30, 0x30, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0xf8,
+  0x41, 0xc6, 0x84, 0x0c, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x80, 0x0f, 0x00, 0x00, 0xf8, 0x41, 0xc6, 0x84, 0x0c,
+  0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0,
+  0x0f, 0x00, 0x00, 0x18, 0x0c, 0x08, 0x00, 0x40, 0xc0, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x0f, 0x00, 0x00, 0xe4,
+  0xb1, 0xc1, 0x98, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x03, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0xff, 0x09, 0x00, 0x00, 0xe4, 0xb1, 0xc1, 0x98, 0x00,
+  0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0xfc, 0x3f, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f,
+  0x08, 0x00, 0x00, 0x1c, 0x02, 0x08, 0x04, 0x4c, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc,
+  0xff, 0x01, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x10, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x1c,
+  0x02, 0x08, 0x04, 0x4c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0xff, 0x1f, 0xc0, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x10, 0x80,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x64, 0x4c, 0x00, 0x00, 0x00,
+  0x36, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0xf0, 0xff, 0xff, 0xc1, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0xf0, 0xff, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
+  0x09, 0x00, 0x00, 0x64, 0x4c, 0x00, 0x00, 0x00, 0x36, 0x01, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
+  0xff, 0x03, 0xf0, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x9c,
+  0x01, 0x08, 0x83, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xff, 0xff, 0x01,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x03, 0xf0, 0xff,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x80, 0x0f, 0x00, 0x00, 0x64, 0x8c, 0x01, 0x18, 0x40,
+  0x30, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0xe0, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0xff, 0xff, 0x03, 0xf0, 0xff, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0,
+  0x0f, 0x00, 0x00, 0x64, 0x8c, 0x01, 0x18, 0x40, 0x30, 0x01, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
+  0xff, 0x03, 0x10, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x0f, 0x00, 0x00, 0x9b,
+  0x01, 0xc0, 0x00, 0x00, 0xc6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbc, 0xff, 0x01,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x02, 0x00, 0x40,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0xff, 0x09, 0x00, 0x00, 0x9b, 0x01, 0xc0, 0x00, 0x00,
+  0xc6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0xc0, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0xf8, 0x01, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x01, 0x02, 0x02, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f,
+  0x00, 0x00, 0x00, 0x07, 0x32, 0x06, 0x18, 0x43, 0x00, 0x06, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0,
+  0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0xf0, 0xc1, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+  0x02, 0x02, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x07,
+  0x32, 0x06, 0x18, 0x43, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xff, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x03, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x02, 0x10, 0xe0,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x70, 0x08, 0x00, 0x00, 0x7b, 0x00, 0x30, 0x03, 0x0c,
+  0x08, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0xf0, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0xe0, 0x07, 0x03, 0xf0, 0xff, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
+  0x09, 0x00, 0xc0, 0x84, 0x8d, 0x01, 0x80, 0x00, 0xc0, 0x06, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8,
+  0xfd, 0x03, 0xf0, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0xc0, 0x84,
+  0x8d, 0x01, 0x80, 0x00, 0xc0, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xfd, 0x03, 0xf0, 0x7f,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0xc0, 0x1b, 0x00, 0x30, 0x00, 0x40,
+  0x08, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0xff, 0xfc, 0x01, 0xf0, 0x3f, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x08, 0x00, 0xc0, 0x1b, 0x00, 0x30, 0x00, 0x40, 0x08, 0x18, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc,
+  0x07, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f,
+  0xf8, 0x01, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0xc0, 0x64,
+  0x42, 0x06, 0x1b, 0x03, 0x00, 0x61, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x80, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x7f, 0x00, 0xc0, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xf0, 0x00, 0x10, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0xc0, 0x64, 0x42, 0x06, 0x1b, 0x03,
+  0x00, 0x61, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0xf0, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0xfe, 0xff, 0x03, 0xe0, 0x01, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
+  0x0f, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x80, 0x30, 0x08, 0x86, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0,
+  0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe,
+  0xff, 0x3f, 0xc0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x0f, 0x00, 0x00, 0x1b,
+  0x00, 0x00, 0x80, 0x30, 0x08, 0x86, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xff, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0xff, 0xff, 0xc3, 0x03,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0xfc, 0x0f, 0x00, 0xe0, 0x84, 0x31, 0x30, 0x04, 0x80,
+  0xc1, 0x18, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0xf0, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x1c, 0xff, 0xff, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
+  0x09, 0x00, 0xc0, 0x63, 0x02, 0x06, 0x00, 0x00, 0x00, 0x60, 0x6c, 0xfc,
+  0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18,
+  0xe0, 0xff, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x08, 0x00, 0xc0, 0x63,
+  0x02, 0x06, 0x00, 0x00, 0x00, 0x60, 0x6c, 0xfc, 0xff, 0x03, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0xff, 0xff, 0x03,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0xe0, 0x1c, 0x40, 0x00, 0x1b, 0x4c,
+  0x06, 0x81, 0x80, 0xfd, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x70, 0x00, 0xf0, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70,
+  0x00, 0x00, 0xe0, 0x1c, 0x40, 0x00, 0x1b, 0x4c, 0x06, 0x81, 0x80, 0xfd,
+  0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0,
+  0x00, 0x80, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x09, 0x00, 0x20, 0x63,
+  0x0c, 0x08, 0x80, 0x00, 0x30, 0x06, 0x0c, 0xfc, 0xff, 0x7f, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x30, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x20, 0x63, 0x0c, 0x08, 0x80, 0x00,
+  0x30, 0x06, 0x0c, 0xfc, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x3f, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
+  0x0f, 0x00, 0xd8, 0x84, 0x01, 0xc0, 0x00, 0x00, 0x06, 0x00, 0x80, 0xf1,
+  0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
+  0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0xe0, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x0f, 0x00, 0xf8, 0x1b,
+  0x40, 0x08, 0x84, 0x0c, 0xc0, 0x18, 0x13, 0xcc, 0xff, 0xff, 0x0f, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xff, 0x0f, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x00, 0xe0, 0x7f,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0xfc, 0x0f, 0x00, 0xf8, 0x1b, 0x40, 0x08, 0x84, 0x0c,
+  0xc0, 0x18, 0x13, 0xcc, 0xff, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0xe0, 0xff, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0xfc, 0x03, 0x00, 0xf0, 0xe4, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
+  0x09, 0x00, 0x38, 0x80, 0x01, 0x00, 0x18, 0x30, 0x06, 0x01, 0x00, 0xc0,
+  0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30,
+  0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe,
+  0x07, 0x00, 0x30, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x38, 0x80,
+  0x01, 0x00, 0x18, 0x30, 0x06, 0x01, 0x00, 0xc0, 0xff, 0xff, 0xff, 0x01,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x30, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x07, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x07, 0x00, 0x10, 0x84,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0xd8, 0x1f, 0x30, 0x36, 0x80, 0x00,
+  0x00, 0x00, 0x03, 0xf2, 0xff, 0xff, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x10, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0xfc, 0x3f, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x4f, 0x0e, 0x00, 0x10, 0x84, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70,
+  0x08, 0x00, 0xd8, 0x1f, 0x30, 0x36, 0x80, 0x00, 0x00, 0x00, 0x03, 0xf2,
+  0xff, 0xff, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10,
+  0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe,
+  0xff, 0x03, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x43,
+  0x08, 0x00, 0x10, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x09, 0x00, 0x3e, 0x00,
+  0x82, 0x01, 0x03, 0x40, 0x30, 0x98, 0x10, 0xf0, 0xe7, 0xff, 0xff, 0xff,
+  0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x20, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0x1f, 0xc0, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x08, 0x00, 0x10, 0xe4,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0xe6, 0x1b, 0x00, 0x00, 0x18, 0x0c,
+  0x00, 0x00, 0x00, 0xfc, 0xff, 0xfb, 0xff, 0xff, 0x1f, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x10, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0xfe, 0xff, 0xff, 0xc1, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x41, 0x08, 0x00, 0x30, 0x7c, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x08, 0x00, 0xe6, 0x1b, 0x00, 0x00, 0x18, 0x0c, 0x00, 0x00, 0x00, 0xfc,
+  0xff, 0xfb, 0xff, 0xff, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10,
+  0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9e,
+  0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41,
+  0x08, 0x00, 0x20, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x1e, 0x64,
+  0x30, 0xc6, 0x80, 0x80, 0x09, 0x06, 0x63, 0xfe, 0xf9, 0xff, 0xff, 0xff,
+  0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x30, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0xf8, 0xff, 0xff, 0x01,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x0e, 0x00, 0xc0, 0x3c,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x1e, 0x64, 0x30, 0xc6, 0x80, 0x80,
+  0x09, 0x06, 0x63, 0xfe, 0xf9, 0xff, 0xff, 0xff, 0xff, 0x03, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x20, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x1c, 0x80, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0xc3, 0x07, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x0e, 0x00, 0x39, 0x03, 0x00, 0x00, 0x04, 0x0c, 0xc0, 0x60, 0x80, 0x3f,
+  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
+  0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c,
+  0x00, 0xfc, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc2,
+  0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x0f, 0x00, 0x39, 0x03,
+  0x00, 0x00, 0x04, 0x0c, 0xc0, 0x60, 0x80, 0x3f, 0xff, 0xff, 0xff, 0xff,
+  0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x3e, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0x80, 0xff, 0x01,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xcc, 0x03, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0xe0, 0x0f, 0x00, 0xe7, 0x04, 0x42, 0xc6, 0x00, 0x00,
+  0x00, 0x00, 0xec, 0xcf, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0x0f, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x80, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0xe0, 0x00, 0x00, 0xfc, 0x01, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc,
+  0x0f, 0xc0, 0x1f, 0x80, 0x01, 0x00, 0x98, 0x4c, 0x06, 0x06, 0xf0, 0x01,
+  0x00, 0xe0, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0,
+  0x01, 0x00, 0xc0, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x09, 0xc0, 0x1f, 0x80,
+  0x01, 0x00, 0x98, 0x4c, 0x06, 0x06, 0xf0, 0x01, 0x00, 0xe0, 0xff, 0xff,
+  0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x20, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x07, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x3f, 0x08, 0xc0, 0xe6, 0x04, 0x0c, 0x08, 0x00, 0x00,
+  0xc0, 0x60, 0x7c, 0x00, 0x00, 0x00, 0xc0, 0xff, 0xff, 0xff, 0xff, 0x01,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0xf0, 0x1f, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c,
+  0x00, 0xc0, 0xe6, 0x04, 0x0c, 0x08, 0x00, 0x00, 0xc0, 0x60, 0x7c, 0x00,
+  0x00, 0x00, 0xc0, 0xff, 0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0,
+  0xff, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0xc0, 0x19, 0x60,
+  0x40, 0x00, 0x63, 0x30, 0x08, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x00, 0xf8,
+  0xff, 0xf3, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xff, 0x3f, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0xc0, 0x09, 0xc0, 0x19, 0x60, 0x40, 0x00, 0x63, 0x30,
+  0x08, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xff, 0xf3, 0xff, 0x07,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0xf0, 0xff, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x78, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x0f, 0xc0, 0x27, 0x03, 0x00, 0x30, 0x00, 0x03, 0x00, 0xe6, 0x1f, 0x00,
+  0x00, 0x00, 0x00, 0xc0, 0xff, 0xff, 0xff, 0x1f, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10,
+  0xe0, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc,
+  0xcf, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0xe0, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x0f, 0xc0, 0x27, 0x03,
+  0x00, 0x30, 0x00, 0x03, 0x00, 0xe6, 0x1f, 0x00, 0x00, 0x00, 0x00, 0xc0,
+  0xff, 0xff, 0xff, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0x0f, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xff,
+  0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0xf0, 0x0f, 0xc0, 0xde, 0x04, 0x0c, 0x06, 0x03, 0x80,
+  0xc1, 0xf8, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0xff, 0xff, 0x7f,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0xfe, 0xff, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x0f, 0x03, 0x00, 0xf8, 0xff, 0x07, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc,
+  0x0f, 0xc0, 0x19, 0x00, 0x32, 0x00, 0x60, 0x30, 0x08, 0xff, 0x03, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0xe0, 0xff, 0xff, 0xff, 0x03, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe,
+  0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x9f,
+  0x07, 0x00, 0xf8, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x09, 0xc0, 0x19, 0x00,
+  0x32, 0x00, 0x60, 0x30, 0x08, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0xe0, 0xff, 0xff, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x80, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0xff, 0x07, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x9f, 0x07, 0x00, 0x18, 0x40,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x3f, 0x00, 0xc0, 0x27, 0x63, 0x80, 0x31, 0x04, 0x03,
+  0xf0, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff,
+  0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0xf8, 0x5f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x1c, 0xfe, 0xff, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x80, 0x1f, 0x07, 0x00, 0x18, 0x40, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c,
+  0x00, 0xc0, 0x27, 0x63, 0x80, 0x31, 0x04, 0x03, 0xf0, 0xff, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x1f, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8,
+  0x7f, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c,
+  0xe0, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x31,
+  0x04, 0x00, 0x10, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x08, 0x00, 0xd9, 0x04,
+  0x00, 0x08, 0x00, 0x80, 0xf9, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0xf0, 0xff, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x7f, 0x1e, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0xfe, 0xff, 0x01,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x20, 0x04, 0x00, 0x60, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0xc0, 0x09, 0x00, 0xd9, 0x04, 0x00, 0x08, 0x00, 0x80,
+  0xf9, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xff, 0xff,
+  0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0xf8, 0x7f, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x78, 0x00, 0xf0, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x80, 0x20, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x0f, 0xc0, 0x27, 0x00, 0x30, 0xc0, 0x60, 0xb0, 0xff, 0x7f, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xff, 0xff, 0xff, 0x01, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08,
+  0x60, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
+  0x00, 0x00, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41,
+  0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0xc0, 0xde, 0x9b,
+  0x8d, 0x01, 0x04, 0xc3, 0xff, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x80, 0xf1, 0xff, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbc, 0x03, 0x00, 0xf0, 0x01,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x07, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x08, 0xc0, 0xde, 0x9b, 0x8d, 0x01, 0x04, 0xc3,
+  0xff, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xf1, 0xff,
+  0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x3e, 0x03, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0xc0, 0x39, 0x04, 0x00, 0xc8, 0x00, 0xfc, 0xff, 0x07, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0xf8, 0xff, 0x3f, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xff,
+  0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0xc0, 0x39, 0x04,
+  0x00, 0xc8, 0x00, 0xfc, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0xc6, 0xf8, 0xff, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x40, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xff, 0x01, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x1f, 0x00, 0xc0, 0xc7, 0x60, 0x42, 0x00, 0x60, 0xff,
+  0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+  0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0xf8, 0x5f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f,
+  0x00, 0xc0, 0xc7, 0x60, 0x42, 0x00, 0x60, 0xff, 0xff, 0x01, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xff, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8,
+  0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0xc0, 0xff, 0x07,
+  0xb0, 0x09, 0xe4, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x30, 0x00, 0xfc, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x7f, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x0e, 0x00, 0xc0, 0xde, 0x78, 0x02, 0x00, 0xfb, 0xff,
+  0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x80, 0xff, 0x1f, 0xf8, 0xff, 0xff, 0x1f, 0xf0, 0xff, 0xff, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0xf8, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0xc0, 0xde, 0x78, 0x02, 0x00, 0xfb, 0xff, 0xff, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xff, 0x1f, 0xf8,
+  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x08,
+  0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70,
+  0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0xc0, 0x3f, 0x07,
+  0xb0, 0xc9, 0xf8, 0xff, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+  0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x00, 0xc0, 0x01,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x08, 0xc0, 0x3f, 0x07, 0xb0, 0xc9, 0xf8, 0xff,
+  0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0f,
+  0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x80, 0x03, 0x00, 0xc0, 0x01, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc,
+  0x0f, 0x00, 0xe7, 0xfb, 0x43, 0x30, 0xf8, 0xff, 0x0f, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0xff, 0xff,
+  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00,
+  0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x07, 0x00, 0xc0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x0f, 0x00, 0xe7, 0xfb,
+  0x43, 0x30, 0xf8, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+  0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x08, 0x70, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0xe0, 0x01,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0xff, 0x0f, 0x00, 0xfe, 0x1c, 0xb2, 0x0f, 0xe0, 0xff,
+  0x07, 0x00, 0xe0, 0xff, 0xff, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0xc0, 0xff, 0xff, 0xcf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+  0x00, 0x00, 0x00, 0xf8, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x78, 0x00, 0xfc, 0x03, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
+  0x0f, 0x00, 0xf8, 0xe7, 0xfd, 0x01, 0xe0, 0xff, 0x07, 0x00, 0xe0, 0xff,
+  0xff, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc1, 0xe0,
+  0xb1, 0x3f, 0x00, 0xe0, 0xff, 0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0xf8,
+  0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0xf0, 0xc0, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0xf8, 0xe7,
+  0xfd, 0x01, 0xe0, 0xff, 0x07, 0x00, 0xe0, 0xff, 0xff, 0xff, 0x0f, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc1, 0xe0, 0xb1, 0x3f, 0x00, 0x00,
+  0xf8, 0xff, 0xff, 0xff, 0x07, 0x00, 0x00, 0xf8, 0x7f, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xff, 0xff, 0x03,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x01, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0xf8, 0xff, 0x7f, 0x00, 0x80, 0xff,
+  0x01, 0x00, 0xe0, 0x03, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x98, 0x4f, 0x0e, 0x18, 0x00, 0xf8, 0xff, 0xff, 0xff,
+  0x07, 0x00, 0x00, 0xf8, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0xf8, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03,
+  0x00, 0x00, 0xf8, 0xff, 0x7f, 0x00, 0x80, 0xff, 0x01, 0x00, 0xe0, 0x03,
+  0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x98,
+  0x4f, 0x0e, 0xf8, 0x1f, 0xf6, 0xff, 0xff, 0xff, 0x1f, 0x00, 0x00, 0x08,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
+  0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
+  0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0xf8, 0xff,
+  0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xb1, 0x01, 0xff, 0x1f,
+  0xf6, 0xff, 0xff, 0xff, 0x1f, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xff, 0xff, 0x1f, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x03, 0x07, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x04, 0x08, 0x00, 0xf8, 0xff, 0x7f, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0xf8, 0xb1, 0x01, 0xff, 0x7f, 0xc0, 0xff, 0xff, 0xff,
+  0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0xfc, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x80, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
+  0x0f, 0x00, 0xe0, 0xff, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
+  0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f,
+  0x00, 0xce, 0xff, 0x7f, 0xc0, 0xff, 0xff, 0xff, 0x3f, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe,
+  0xff, 0xe3, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00,
+  0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x0f, 0x00, 0xe0, 0xff,
+  0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x00, 0xce, 0xff, 0x7f,
+  0x00, 0xff, 0xff, 0xff, 0x3f, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x1f, 0x00, 0x07, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x04, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0xff, 0x0f, 0x00, 0xc0, 0xff, 0x3f, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x20, 0x1b, 0xb2, 0x31, 0xff, 0x7f, 0x00, 0xff, 0xff, 0xff,
+  0x3f, 0x00, 0x00, 0xe0, 0x5f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0xfe, 0x03, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x80, 0x01, 0x06, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
+  0x0f, 0x00, 0xc0, 0xff, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
+  0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xc0, 0x1c,
+  0x00, 0xc0, 0xff, 0x73, 0xc0, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xf0,
+  0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e,
+  0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03,
+  0x03, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0xc0, 0xff,
+  0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x07, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xc0, 0x1c, 0x00, 0xc0, 0x7f, 0x1c,
+  0x30, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xf8, 0x7f, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x78, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xff, 0xff, 0x01, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0xc0, 0xff, 0x0f, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x38, 0x87, 0x31, 0x06, 0x7c, 0x1c, 0x30, 0xff, 0xff, 0xff,
+  0xff, 0x00, 0x00, 0xf8, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x80, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0xc0, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0xff, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x87,
+  0x31, 0x06, 0xfc, 0x0f, 0xc8, 0xff, 0xff, 0xff, 0xff, 0x03, 0x00, 0x38,
+  0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30,
+  0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xff,
+  0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x00, 0xc0, 0xff,
+  0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x0f, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0xe6, 0x04, 0x00, 0x30, 0xe3, 0x0f,
+  0xc8, 0xff, 0xff, 0xff, 0xff, 0x03, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0xe0, 0x01,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xff, 0xff, 0x01, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0xfc, 0x03, 0x00, 0xc0, 0xff, 0x0f, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x30, 0xe6, 0x04, 0x00, 0x30, 0x03, 0x00, 0xf0, 0xff, 0xff, 0xff,
+  0xff, 0x03, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0xc0, 0x01, 0x00, 0xe0, 0x03, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe,
+  0x07, 0x00, 0xc0, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
+  0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x1b,
+  0x4c, 0x00, 0x04, 0x00, 0xf0, 0xff, 0xff, 0xff, 0xff, 0x03, 0x00, 0x10,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x01, 0x00, 0xf0, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x07, 0x00, 0xc0, 0xff,
+  0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x07, 0x04, 0x00, 0x06, 0x18, 0x80,
+  0xff, 0xff, 0xff, 0xff, 0xff, 0x03, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x03,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x0f, 0x0e, 0x00, 0xc0, 0xff, 0x0f, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x02, 0x07, 0x04, 0x00, 0x06, 0x78, 0xf3, 0xff, 0xff, 0xff, 0xff,
+  0xff, 0x07, 0x00, 0xf8, 0x5f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x01, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03,
+  0x08, 0x00, 0xc0, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x3e, 0x04,
+  0x02, 0x30, 0x60, 0xf3, 0xff, 0xff, 0xff, 0xff, 0xff, 0x07, 0x00, 0xf8,
+  0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0xc0, 0xff,
+  0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x3e, 0x04, 0x02, 0x30, 0xe0, 0xff,
+  0xff, 0xff, 0xff, 0xff, 0xff, 0x07, 0x00, 0xf8, 0x7f, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0xff, 0x0f, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0xc6, 0x04, 0x40, 0x00, 0xfb, 0xff, 0xff, 0xff, 0xff, 0xff,
+  0xff, 0x07, 0x00, 0xf8, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+  0x08, 0x00, 0x00, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0x04,
+  0x40, 0x00, 0xfb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x07, 0x00, 0x08,
+  0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x0e, 0x00, 0x00, 0xff,
+  0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xff, 0x03, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x39, 0x67, 0x00, 0x06, 0xe0, 0xff,
+  0xff, 0xff, 0xff, 0xff, 0xff, 0x07, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x03, 0x0f, 0x00, 0x00, 0xff, 0x0f, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x06, 0x04, 0x30, 0x00, 0xfb, 0xff, 0xff, 0xff, 0xff, 0xff,
+  0xff, 0x3f, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x18, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02,
+  0x0f, 0x00, 0x00, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0xff, 0xff, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x04,
+  0x30, 0x00, 0xfb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x00, 0x08,
+  0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x00,
+  0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x06, 0x00, 0x00, 0xff,
+  0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x1f, 0x00, 0x7e, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x3e, 0x9b, 0x01, 0x30, 0xe0, 0xff,
+  0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x00, 0x08, 0x60, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x06, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x0f, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0xc0, 0x1f, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x30, 0x3e, 0x9b, 0x01, 0x30, 0xe0, 0xff, 0xff, 0xff, 0xff, 0xff,
+  0xff, 0x3f, 0x00, 0x18, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x1c, 0x80, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+  0x00, 0x02, 0x00, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0,
+  0x01, 0x00, 0xf0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0x1c,
+  0x0c, 0x06, 0xfb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x00, 0x38,
+  0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0xe0,
+  0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0xff,
+  0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x01, 0x00, 0xf0, 0x01,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0x1c, 0x0c, 0x06, 0xfb, 0xff,
+  0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x00, 0x68, 0x7c, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0xf8, 0x07, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0xff, 0xff, 0x03, 0x00, 0xff, 0x3f, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0xf0, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x38, 0x18, 0x00, 0x00, 0xfb, 0xff, 0xff, 0xff, 0xff, 0xff,
+  0xff, 0x3f, 0x00, 0xc0, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x18, 0xfe, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
+  0xff, 0x03, 0x00, 0xff, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc,
+  0x00, 0x00, 0xc0, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xc6, 0x9b,
+  0x81, 0x01, 0x60, 0x00, 0xfe, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x00, 0x80,
+  0x5f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x7f,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x03, 0x00, 0xff,
+  0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0xc0, 0x07,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xc6, 0x9b, 0x81, 0x01, 0x00, 0x00,
+  0xf6, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x00, 0xc0, 0x0f, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x1f, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0xff, 0xff, 0x03, 0x00, 0xff, 0x3f, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x80, 0x07, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x38, 0x78, 0x0c, 0x30, 0x04, 0x00, 0xf6, 0xff, 0xff, 0xff,
+  0xff, 0x3f, 0x00, 0xe8, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+  0x00, 0x00, 0x00, 0xff, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c,
+  0x00, 0x00, 0x80, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x78,
+  0x0c, 0x30, 0x04, 0x00, 0xc8, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x00, 0xf8,
+  0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38,
+  0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xff,
+  0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x80, 0x07,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x64, 0x40, 0x00, 0x1c, 0x00,
+  0xc8, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x00, 0xf8, 0x58, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x04, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x3f, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x80, 0x07, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0xc0, 0x64, 0x40, 0x00, 0xfc, 0x03, 0xc0, 0xff, 0xff, 0xff,
+  0xff, 0x3f, 0x00, 0x78, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x80, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+  0x08, 0x00, 0x00, 0xff, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c,
+  0x00, 0x00, 0x80, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0xe0,
+  0x01, 0x36, 0xfc, 0x03, 0xc0, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x00, 0x38,
+  0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0xff,
+  0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x80, 0x07,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0xe0, 0x01, 0x36, 0xfc, 0x1f,
+  0x30, 0xff, 0xff, 0xff, 0xff, 0x07, 0x00, 0x18, 0x40, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0xff, 0x8f, 0x01, 0x00, 0xff, 0x3f, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x80, 0x07, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0xc6, 0x87, 0x0f, 0x00, 0xff, 0x1f, 0x30, 0xff, 0xff, 0xff,
+  0xff, 0x07, 0x00, 0x08, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0xfe, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
+  0xcf, 0x03, 0x00, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc,
+  0x00, 0x00, 0xc0, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18,
+  0x40, 0xc0, 0xff, 0x7f, 0xc0, 0xfe, 0xff, 0xff, 0xff, 0x07, 0x00, 0x08,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0xff, 0x0f, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xcf, 0x03, 0x00, 0xff,
+  0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0xc0, 0x07,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x40, 0xc0, 0xff, 0x7f,
+  0x00, 0xff, 0xff, 0xff, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0xfc, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0xff, 0x8f, 0x01, 0x00, 0xff, 0x7f, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0xf0, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x03, 0x0e, 0xc6, 0xff, 0x7f, 0x00, 0xff, 0xff, 0xff,
+  0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0xfe, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+  0x00, 0x00, 0x00, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0,
+  0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03,
+  0x0e, 0xc6, 0xff, 0x7f, 0x00, 0xfe, 0xff, 0xff, 0xff, 0x07, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x0c, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xff,
+  0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x01, 0x00, 0xf0, 0x01,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x9c, 0x01, 0x30, 0xff, 0x7f,
+  0x00, 0xfe, 0xff, 0xff, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x02, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x7f, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0xf0, 0x01, 0x00, 0xf0, 0x01, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x20, 0x9c, 0x01, 0x30, 0xff, 0x63, 0x30, 0xff, 0xff, 0xff,
+  0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x02, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+  0x08, 0x00, 0x00, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
+  0x07, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60,
+  0x4c, 0x00, 0xff, 0x63, 0x30, 0xff, 0xff, 0xff, 0xff, 0x07, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x10, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0xff,
+  0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x3e, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb2, 0x31, 0xfc, 0x1f,
+  0x00, 0xff, 0xff, 0xfd, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x02, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0xff, 0x0f, 0x00, 0x00, 0xff, 0xff, 0x01, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0xb2, 0x31, 0xfc, 0x0f, 0x00, 0xff, 0xff, 0x03,
+  0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x0e, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
+  0x0f, 0x00, 0x00, 0xff, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x98,
+  0x41, 0x00, 0xe0, 0x0f, 0x00, 0xff, 0xff, 0x03, 0xff, 0x03, 0x00, 0x38,
+  0x80, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x0f, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x0f, 0x00, 0x00, 0xff,
+  0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x98, 0x41, 0x00, 0x00, 0x80,
+  0xc9, 0xf9, 0xff, 0x3d, 0xff, 0x03, 0x00, 0x78, 0xc0, 0x0f, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0xfc, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0xff, 0x0f, 0x00, 0x00, 0xff, 0xff, 0x07, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x60, 0x32, 0x08, 0x00, 0x80, 0xc9, 0xf9, 0xff, 0x3d,
+  0xff, 0x03, 0x00, 0xf8, 0xc0, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0xf8, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+  0x02, 0x00, 0x00, 0xff, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60,
+  0x32, 0x08, 0x00, 0x00, 0xf0, 0xff, 0xff, 0xcf, 0xff, 0x00, 0x00, 0xf8,
+  0x81, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x01, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0xff,
+  0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0xe0, 0x01, 0xf8, 0x00, 0x00,
+  0xf0, 0xff, 0xff, 0xcf, 0xff, 0x00, 0x00, 0x38, 0x03, 0x10, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x60, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0xff, 0xff, 0x3f, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0xf8, 0xff, 0xff, 0x03, 0x80, 0xff, 0xff, 0xff, 0xff,
+  0x3f, 0x00, 0x00, 0x38, 0x06, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0,
+  0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x0c, 0x00, 0x00, 0xff, 0xff, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8,
+  0xff, 0xff, 0x03, 0xfc, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x00, 0x00, 0x38,
+  0x1e, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x18, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x0e, 0x00, 0x00, 0xff,
+  0xff, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xff, 0xff, 0x03, 0xfc,
+  0xff, 0xff, 0xff, 0xff, 0x3f, 0x00, 0x00, 0x38, 0xfc, 0x1f, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x70, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0xff, 0x0f, 0x00, 0x00, 0xff, 0xff, 0x3f, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+  0x1f, 0x00, 0x00, 0x38, 0xf8, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30,
+  0x80, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
+  0x0f, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
+  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0x00, 0x00, 0x78,
+  0xf0, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0xe0, 0x1f, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x07, 0x00, 0x00, 0xff,
+  0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xff,
+  0xff, 0xff, 0xff, 0xff, 0x07, 0x00, 0x00, 0xf8, 0xc1, 0x07, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x60, 0xf8, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0xff, 0x03, 0x00, 0xc0, 0xff, 0xff, 0xff, 0x03, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00,
+  0x00, 0x00, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+  0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
+  0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+  0x00, 0x00, 0xc0, 0xff, 0xff, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0xff, 0xff,
+  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x07, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0xc0, 0xff,
+  0xff, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+  0xff, 0xff, 0xff, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xff, 0xff, 0xff, 0x1f, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+  0x01, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0xe0, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x08, 0x00, 0xc0, 0xff, 0xff, 0xff, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0x67,
+  0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0xf8,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x13, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0xc0, 0xff,
+  0xff, 0xff, 0x1f, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0xf0, 0xff, 0xff, 0x67, 0xfe, 0xff, 0xff, 0xff,
+  0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0xfc, 0x0f, 0x00, 0xc0, 0xff, 0xff, 0xff, 0x1f, 0x03,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0xf0, 0xff, 0xff, 0x98, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0f,
+  0x00, 0x00, 0x00, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe,
+  0x0f, 0x00, 0xf8, 0xff, 0xff, 0xff, 0x7f, 0x00, 0x08, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xff, 0xff, 0xff, 0x98,
+  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x70,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x0f, 0x00, 0xf8, 0xff,
+  0xff, 0xff, 0x7f, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x80, 0xff, 0xff, 0x3f, 0xe7, 0xff, 0xff, 0xff, 0xff,
+  0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0xff, 0x0f, 0x00, 0xff, 0xfc, 0xff, 0xff, 0xff, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe,
+  0xff, 0xff, 0x3f, 0xe7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07,
+  0x00, 0xc0, 0xff, 0x67, 0x8c, 0xf9, 0xfb, 0x73, 0x00, 0x67, 0x10, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xff, 0xff, 0xff, 0xff, 0xf8,
+  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x80,
+  0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0xc0, 0xff, 0x67,
+  0x8c, 0xf9, 0xfb, 0x73, 0x00, 0x67, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0xc0, 0xff, 0xff, 0xff, 0x1f, 0xe7, 0xff, 0xff, 0xff, 0xff,
+  0xff, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xff, 0x07, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x03, 0x00, 0xc0, 0x27, 0xfc, 0x73, 0xc6, 0x1c, 0x8c,
+  0x37, 0x80, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xff,
+  0xff, 0xff, 0x1f, 0xe7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0f, 0x00,
+  0x00, 0x00, 0x00, 0xf0, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02,
+  0x00, 0xc0, 0x27, 0xfc, 0x73, 0xc6, 0x1c, 0x8c, 0x37, 0x80, 0x0c, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xfc,
+  0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0,
+  0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x08, 0xc0, 0xfe, 0x03,
+  0x8c, 0x09, 0xe3, 0x73, 0xc8, 0x06, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x80, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xff,
+  0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x18, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0xff, 0x0f, 0xc0, 0xfe, 0x03, 0x8c, 0x09, 0xe3, 0x73,
+  0xc8, 0x06, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xff, 0xff,
+  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x07, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x08, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
+  0x0f, 0xc0, 0x27, 0xe7, 0x31, 0x36, 0x04, 0x8c, 0x01, 0x60, 0x03, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+  0xff, 0xff, 0xff, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08,
+  0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x0f, 0xc0, 0xde, 0x18,
+  0x42, 0xc0, 0x98, 0x30, 0x08, 0x01, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x07, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x18, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0xff, 0x0f, 0xc0, 0xde, 0x18, 0x42, 0xc0, 0x98, 0x30,
+  0x08, 0x01, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff,
+  0xff, 0xff, 0xff, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0xf0, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x02, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+  0x00, 0xc0, 0x27, 0x63, 0x00, 0x08, 0x63, 0x03, 0x06, 0x60, 0x10, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0xe0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+  0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0,
+  0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0x07, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0xc0, 0x27, 0x63,
+  0x00, 0x08, 0x63, 0x03, 0x06, 0x60, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0xe0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xff, 0x07, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x08, 0xc0, 0xd9, 0x04, 0xb2, 0x01, 0x00, 0xb0,
+  0x31, 0x19, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xf9, 0xff,
+  0xff, 0xff, 0xff, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x80, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0xfe, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+  0x08, 0xc0, 0xd9, 0x04, 0xb2, 0x01, 0x00, 0xb0, 0x31, 0x19, 0x03, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xf9, 0xff, 0xff, 0xff, 0xff, 0x07,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0x07, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x0c, 0xc0, 0x1e, 0x63,
+  0x00, 0x30, 0x04, 0x03, 0xc8, 0x60, 0x00, 0x0e, 0x00, 0x00, 0xfc, 0xff,
+  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x02, 0x04, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x03, 0x0e, 0xc0, 0xe1, 0x18, 0x80, 0x01, 0x60, 0xb0,
+  0x01, 0xe7, 0xf3, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+  0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x02, 0x04, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07,
+  0x0f, 0xc0, 0xe1, 0x18, 0x80, 0x01, 0x60, 0xb0, 0x01, 0xe7, 0xf3, 0xff,
+  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x07, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x04, 0x04, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8d, 0x0f, 0xc0, 0x1e, 0x03,
+  0x02, 0x08, 0x04, 0x00, 0xc8, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0xd8, 0x0f, 0xc0, 0x1e, 0x03, 0x02, 0x08, 0x04, 0x00,
+  0xc8, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+  0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0xc0, 0x0f, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0,
+  0x0b, 0x00, 0x21, 0x64, 0x40, 0xc0, 0x00, 0xb3, 0xf1, 0xfe, 0xff, 0xff,
+  0xff, 0xff, 0xff, 0xff, 0xfb, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xfb, 0x07, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x01, 0x00, 0x21, 0x64,
+  0x40, 0xc0, 0x00, 0xb3, 0xf1, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+  0xfb, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0xfc, 0xfb, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0xfd, 0x00, 0xc0, 0xdf, 0x00, 0x00, 0x06, 0x60, 0x00,
+  0x0e, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+  0xff, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0xfe, 0xf9, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbf,
+  0x01, 0xc0, 0xdf, 0x00, 0x00, 0x06, 0x60, 0x00, 0x0e, 0xff, 0xff, 0xff,
+  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0f, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0,
+  0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0xf0, 0x03, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x0b, 0xc0, 0xc0, 0x84,
+  0x31, 0xc0, 0x00, 0x4c, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+  0xff, 0xff, 0xff, 0xff, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x83, 0x07, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x1e, 0xe0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x0f, 0x0e, 0xc0, 0x3f, 0x18, 0x00, 0x06, 0x84, 0x80,
+  0x09, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+  0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0xf0, 0xc3, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07,
+  0x0c, 0xc0, 0x3f, 0x18, 0x00, 0x06, 0x84, 0x80, 0x09, 0xff, 0xff, 0x3f,
+  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc8,
+  0xc1, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x08, 0xc0, 0xc1, 0x03,
+  0x4c, 0x00, 0x00, 0x30, 0xf6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+  0xff, 0xff, 0xff, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x90, 0x13, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x01, 0x08, 0xc0, 0xc1, 0x03, 0x4c, 0x00, 0x00, 0x30,
+  0xf6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+  0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x08, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+  0x00, 0xc0, 0x3f, 0x98, 0x01, 0x08, 0x1b, 0x43, 0xc8, 0xff, 0xff, 0xff,
+  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0f, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08,
+  0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x3f, 0x98,
+  0x01, 0x08, 0x1b, 0x43, 0xc8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+  0xff, 0xff, 0xff, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x38, 0x18, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x0e, 0x00, 0xc0, 0xc6, 0x03, 0x40, 0x00, 0x00, 0x80,
+  0x31, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf7, 0xff, 0xff, 0xff, 0xff,
+  0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0xf8, 0xef, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f,
+  0x00, 0x00, 0x3f, 0x18, 0x0c, 0x30, 0x60, 0x0c, 0xce, 0xff, 0xff, 0xff,
+  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0,
+  0xef, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x3f, 0x18,
+  0x0c, 0x30, 0x60, 0x0c, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+  0xff, 0xff, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xc7, 0x0f, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0xde, 0x63, 0x40, 0x06, 0x03, 0x30,
+  0x30, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0xc0, 0x83, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x02, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e,
+  0x00, 0x00, 0xde, 0x63, 0x40, 0x06, 0x03, 0x30, 0x30, 0xff, 0xff, 0xff,
+  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x04, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x04,
+  0x02, 0x00, 0x00, 0x83, 0xc9, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+  0xff, 0xff, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0xf0, 0x00, 0x00, 0x38, 0x04, 0x02, 0x00, 0x00, 0x83,
+  0xc9, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0xc0, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0xfe, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc,
+  0x03, 0x00, 0xe0, 0x1b, 0x0c, 0x08, 0x18, 0x40, 0x30, 0xfe, 0xff, 0xff,
+  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0,
+  0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0x07, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x07, 0x00, 0xc0, 0x84,
+  0x81, 0x01, 0x03, 0x0c, 0xc6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+  0xff, 0xff, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xff, 0x0f, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0xfe, 0x07, 0x00, 0xc0, 0x84, 0x81, 0x01, 0x03, 0x0c,
+  0xc6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0f, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0xf8, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x02, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07,
+  0x0e, 0x00, 0x00, 0x1b, 0x0c, 0x30, 0x80, 0x00, 0x30, 0xf8, 0xff, 0xff,
+  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18,
+  0x10, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x04, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x1b,
+  0x0c, 0x30, 0x80, 0x00, 0x30, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+  0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x20, 0x10, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x67, 0xc0, 0x01, 0x04, 0x40,
+  0x00, 0xe1, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x08, 0x20, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+  0x08, 0x00, 0x00, 0x67, 0xc0, 0x01, 0x04, 0x40, 0x00, 0xe1, 0xff, 0xff,
+  0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18,
+  0x30, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x9c,
+  0x01, 0x08, 0x60, 0x0c, 0x06, 0x86, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xff,
+  0xff, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xbf, 0x1f, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x07, 0x0e, 0x00, 0x00, 0x18, 0x0c, 0xc0, 0x00, 0x00,
+  0xc0, 0x00, 0xfc, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0xf0, 0x9f, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe,
+  0x07, 0x00, 0x00, 0x18, 0x0c, 0xc0, 0x00, 0x00, 0xc0, 0x00, 0xfc, 0xff,
+  0xff, 0xff, 0xff, 0xff, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0,
+  0x1f, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x07, 0x00, 0x00, 0xe0,
+  0x01, 0x06, 0x00, 0x30, 0x06, 0x86, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff,
+  0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x07, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0xfc, 0x03, 0x00, 0x00, 0xe0, 0x01, 0x06, 0x00, 0x30,
+  0x06, 0x86, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0,
+  0x00, 0x00, 0x00, 0x60, 0x30, 0x00, 0x63, 0x03, 0x30, 0x00, 0xe0, 0xff,
+  0xff, 0xff, 0xff, 0x8f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60,
+  0x30, 0x00, 0x63, 0x03, 0x30, 0x00, 0xe0, 0xff, 0xff, 0xff, 0xff, 0x0f,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x80, 0x83, 0x09, 0x18, 0x00,
+  0x00, 0x06, 0x83, 0xff, 0xff, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+  0x08, 0x00, 0x00, 0x80, 0x83, 0x09, 0x18, 0x00, 0x00, 0x06, 0x83, 0xff,
+  0xff, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x0f, 0x00, 0x00, 0x00,
+  0x00, 0xc0, 0x00, 0x8c, 0xc9, 0x60, 0x00, 0xfe, 0xff, 0xff, 0x01, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x8e, 0x01, 0x84, 0x40,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
+  0x0f, 0x00, 0x00, 0x00, 0x8e, 0x01, 0x84, 0x40, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x0f, 0x00, 0x00, 0x00,
+  0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+  0x04, 0x00, 0x00, 0x00, 0x00, 0xc8, 0x60, 0x83, 0x01, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00,
+  0x00, 0xc8, 0x60, 0x83, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x30, 0x06, 0x00, 0x0c,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x0f, 0x00, 0x00, 0x00, 0x80, 0xc1, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x1f, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,
+  0x80, 0xc1, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0xe0, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x08, 0x60, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0xf8, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0xc6,
+  0x03, 0x00, 0x00, 0x00, 0x40, 0x08, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xff, 0x01, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xef, 0x07, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0xfc, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0xd8, 0xef, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x1c, 0x80, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0xf3,
+  0x0f, 0x00, 0x00, 0x00, 0x80, 0x09, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x06, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0x33, 0x0c, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x88, 0x13, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x02, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0x13,
+  0x08, 0x00, 0x00, 0x00, 0x00, 0x18, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x04, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0x33, 0x0c, 0x00, 0x00, 0x00,
+  0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x88, 0xf3, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x02, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0xe3,
+  0x0f, 0x00, 0x00, 0x00, 0x00, 0x86, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x06, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd8, 0xe1, 0x1f, 0x00, 0x00, 0x00,
+  0x00, 0x86, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0xf0, 0xc1, 0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x04, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x00,
+  0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0xc0, 0x07, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x60, 0xf0, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x01, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0xf8, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0xfc, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x0f, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x0e, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x02, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x10, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x02, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x02, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x1c, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0xfc, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0xfc, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x07, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0xe0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x10, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x02, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0xfe, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x1f, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0xfe, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0xfe, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x04, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x02, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0xfe, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x1f, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0xfe, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0xfe, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0xf8, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0xfc, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0x01, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x06, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x10, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x04, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x02, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x02, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x1f, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0xfe, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0xfe, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x1f, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x02, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x02, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0xe0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0xf8, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x0f, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0xfc, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x0e, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x10, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x02, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x02, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x10, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x0e, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0xfc, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x0f, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0xf8, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0xe0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x02, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0x07, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0xfe, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0x07, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  };
diff --git a/arch/m68k/68000/bootlogo.h b/arch/m68k/68000/bootlogo.h
new file mode 100644 (file)
index 0000000..b896c93
--- /dev/null
@@ -0,0 +1,270 @@
+#define bootlogo_width 160
+#define bootlogo_height 160
+unsigned char __attribute__ ((aligned(16))) bootlogo_bits[] = {
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x01, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x40, 0x55, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x55,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xac, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x10, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x01, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x82, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x20, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x80, 0x08, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x08, 0x00, 0x00,
+  0x00, 0xff, 0x80, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x20, 0x04, 0x00, 0x00, 0x00, 0xf8, 0x80, 0x0f,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x50, 0x04, 0x00, 0x00, 0x00, 0x78, 0x80, 0x0f, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x03, 0x00, 0x00,
+  0x00, 0x78, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x90, 0x00, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x40,
+  0xa8, 0x02, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x70, 0x28, 0x01, 0x00, 0x00,
+  0x00, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x20, 0x00, 0x00, 0xaa, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x70,
+  0x54, 0x01, 0x00, 0x00, 0x00, 0x3e, 0x80, 0x01, 0x3a, 0x78, 0x80, 0x0e,
+  0x50, 0xc0, 0x03, 0x0e, 0x00, 0x20, 0x00, 0x00, 0xaa, 0x00, 0x00, 0x00,
+  0x00, 0x3e, 0xf0, 0x83, 0x1f, 0xfc, 0xe0, 0x0f, 0x78, 0xf8, 0x87, 0x1f,
+  0x00, 0x18, 0x00, 0x30, 0xaa, 0x00, 0x00, 0x00, 0x00, 0x1e, 0xf8, 0xc3,
+  0x1f, 0xfc, 0xe0, 0x0f, 0x78, 0xf8, 0x87, 0x0f, 0x00, 0x20, 0x00, 0x10,
+  0x55, 0x00, 0x00, 0x00, 0x00, 0x1e, 0xc0, 0x03, 0x9f, 0xf3, 0x80, 0x0f,
+  0x78, 0x80, 0xc7, 0x0e, 0x00, 0x18, 0x00, 0x20, 0xaa, 0x00, 0x00, 0x00,
+  0x00, 0x1e, 0xe0, 0x03, 0x9f, 0xf1, 0x80, 0x07, 0x78, 0x80, 0x67, 0x00,
+  0x00, 0x24, 0x00, 0x18, 0x55, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xe0, 0x01,
+  0x5e, 0xf0, 0x80, 0x07, 0x3c, 0x00, 0x2f, 0x00, 0x00, 0x14, 0x00, 0x20,
+  0xaa, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xe0, 0x01, 0x7f, 0xf0, 0x80, 0x07,
+  0x3c, 0x00, 0x3f, 0x00, 0x00, 0x08, 0x00, 0x18, 0x55, 0x00, 0x00, 0x00,
+  0x00, 0x0f, 0xe0, 0x00, 0x3f, 0xf0, 0xc0, 0x03, 0x1e, 0x00, 0x1f, 0x00,
+  0x00, 0x14, 0x00, 0x28, 0xaa, 0x00, 0x00, 0x00, 0x80, 0x0f, 0xf0, 0x00,
+  0x1f, 0xf0, 0xc0, 0x03, 0x1f, 0x00, 0x1f, 0x00, 0x00, 0x04, 0x00, 0x0c,
+  0x54, 0x00, 0x00, 0x00, 0x80, 0x07, 0x78, 0x00, 0x1f, 0x78, 0xc0, 0x03,
+  0x1f, 0x00, 0x1e, 0x00, 0x00, 0x0a, 0x00, 0x12, 0xa8, 0x00, 0x00, 0x00,
+  0x80, 0x07, 0x78, 0x00, 0x1f, 0x78, 0xe0, 0x03, 0x1f, 0x00, 0x1f, 0x00,
+  0x00, 0x04, 0x00, 0x0a, 0x54, 0x00, 0x00, 0x00, 0x80, 0x07, 0x78, 0x80,
+  0x0f, 0x78, 0xe0, 0x03, 0x1f, 0x00, 0x1e, 0x00, 0x00, 0x0a, 0x00, 0x08,
+  0x50, 0x01, 0x00, 0x00, 0x84, 0x03, 0x78, 0x80, 0x07, 0x3c, 0xe0, 0xc1,
+  0x0f, 0x00, 0x1f, 0x00, 0x00, 0x04, 0x00, 0x06, 0xa8, 0x00, 0x00, 0x00,
+  0xc0, 0x03, 0x78, 0xc0, 0x07, 0x3c, 0xe0, 0xc1, 0x0f, 0x00, 0x1f, 0x00,
+  0x00, 0x0a, 0x00, 0x08, 0x50, 0x01, 0x00, 0x00, 0xc2, 0x01, 0x38, 0xc0,
+  0x07, 0x3c, 0xe0, 0x60, 0x0f, 0x80, 0x1e, 0x00, 0x00, 0x05, 0x00, 0x07,
+  0xa0, 0x00, 0x00, 0x80, 0xe0, 0x01, 0x3c, 0xc0, 0x07, 0x3c, 0xf0, 0xa0,
+  0x07, 0xc0, 0x1c, 0x00, 0x00, 0x0a, 0x80, 0x08, 0xa0, 0x02, 0x00, 0xa0,
+  0xe0, 0x21, 0x1c, 0xc0, 0x03, 0x1c, 0x71, 0x90, 0x47, 0x40, 0x3c, 0x04,
+  0x00, 0x05, 0x80, 0x06, 0xa0, 0x02, 0x00, 0x20, 0xe0, 0x31, 0x1e, 0xc3,
+  0x03, 0x1e, 0x79, 0x98, 0x47, 0x60, 0x38, 0x04, 0x00, 0x15, 0x40, 0x0a,
+  0xa0, 0x0a, 0x00, 0x1a, 0xe0, 0x19, 0x9e, 0xe1, 0x01, 0x9e, 0x78, 0xcc,
+  0xa7, 0x32, 0x78, 0x02, 0x80, 0x2a, 0x40, 0x05, 0x80, 0x2a, 0x00, 0x05,
+  0xe0, 0x0d, 0x9e, 0xe0, 0x01, 0xde, 0x78, 0xc6, 0x97, 0x1b, 0x78, 0x03,
+  0x80, 0x52, 0x30, 0x0a, 0x00, 0x95, 0xd2, 0x0a, 0xe0, 0x0f, 0xfe, 0xe0,
+  0x00, 0x7e, 0xf8, 0x87, 0x9f, 0x0f, 0xf8, 0x01, 0x00, 0xa1, 0x0e, 0x15,
+  0x80, 0x55, 0x55, 0x01, 0xe0, 0x01, 0x3c, 0xf0, 0x00, 0x3c, 0xf0, 0x80,
+  0x8f, 0x0f, 0x70, 0x00, 0x00, 0x81, 0x02, 0x14, 0x00, 0x54, 0x55, 0x00,
+  0xc0, 0x01, 0x3c, 0x00, 0x00, 0x0c, 0x60, 0x00, 0x07, 0x03, 0x70, 0x00,
+  0x80, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x40, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x40, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x40, 0x01, 0x00, 0x11, 0x09, 0x00, 0x04, 0x00, 0x01, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00,
+  0x00, 0x20, 0x01, 0x00, 0x04, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x49, 0x32, 0x49, 0x49, 0x91,
+  0x24, 0x86, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x20, 0x49, 0x0a, 0x09, 0xc9, 0x92, 0x14, 0x81, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x49,
+  0x18, 0x01, 0x49, 0x92, 0x0c, 0x43, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x49, 0x30, 0x01, 0x49, 0x92,
+  0x14, 0x26, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x08, 0x69, 0x22, 0x09, 0x49, 0xd2, 0x24, 0x24, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x51,
+  0x1a, 0x09, 0x49, 0xa2, 0x44, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x01, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
+  0x08, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x87, 0x08, 0x00, 0x00, 0x00,
+  0xf2, 0xf0, 0xf0, 0xf0, 0xf0, 0x00, 0xf0, 0x00, 0x08, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x40, 0x88, 0x00, 0x00, 0x00, 0x00, 0x09, 0x09, 0x09, 0x09,
+  0x09, 0x01, 0x10, 0x01, 0x08, 0x00, 0x00, 0x00, 0x00, 0x40, 0x24, 0x80,
+  0x88, 0x86, 0x48, 0x04, 0x09, 0x08, 0x01, 0x01, 0x09, 0x01, 0x10, 0x71,
+  0x88, 0x66, 0x00, 0x00, 0x00, 0x40, 0x24, 0x80, 0x88, 0x89, 0x48, 0x84,
+  0x08, 0x08, 0x01, 0x01, 0x09, 0x01, 0x10, 0x89, 0x88, 0x99, 0x00, 0x00,
+  0x00, 0x40, 0x24, 0x80, 0x88, 0x88, 0x88, 0x82, 0xf8, 0xf0, 0xe0, 0x80,
+  0xf0, 0xf8, 0x13, 0x81, 0x88, 0x88, 0x00, 0x00, 0x00, 0x40, 0x24, 0x80,
+  0x88, 0x88, 0x08, 0x81, 0x08, 0x09, 0x01, 0x41, 0x08, 0x01, 0xf0, 0xf0,
+  0x88, 0x88, 0x00, 0x00, 0x00, 0x40, 0x24, 0x80, 0x88, 0x88, 0x88, 0x42,
+  0x08, 0x09, 0x01, 0x21, 0x08, 0x01, 0x10, 0x88, 0x88, 0x88, 0x00, 0x00,
+  0x00, 0x40, 0x46, 0x88, 0x88, 0x88, 0x4c, 0x44, 0x08, 0x09, 0x09, 0x11,
+  0x08, 0x01, 0x10, 0x88, 0x88, 0x88, 0x00, 0x00, 0x00, 0x80, 0x85, 0x87,
+  0x88, 0x08, 0x4b, 0x24, 0xf0, 0xf0, 0xf0, 0xf8, 0xf1, 0x00, 0x10, 0x70,
+  0x89, 0x88, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x7f, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0xf8, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc,
+  0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0x0f, 0x00, 0x00,
+  0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0xff, 0x3f, 0x0f, 0x00, 0x00, 0x08, 0x02, 0x04, 0x00,
+  0x00, 0x00, 0x08, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
+  0xff, 0x1f, 0x00, 0x00, 0x48, 0x62, 0xc4, 0x31, 0x4a, 0x18, 0x3c, 0x03,
+  0x21, 0x45, 0x92, 0x00, 0x00, 0x00, 0x80, 0xff, 0xff, 0x1f, 0x00, 0x00,
+  0x48, 0x92, 0x24, 0x48, 0xb6, 0x24, 0x88, 0x04, 0x21, 0x4b, 0x92, 0x00,
+  0x00, 0x00, 0x80, 0xff, 0xff, 0x3f, 0x00, 0x00, 0xa8, 0xf2, 0x24, 0x48,
+  0x92, 0x3c, 0x88, 0x04, 0x21, 0x49, 0x62, 0x00, 0x00, 0x00, 0x80, 0xff,
+  0xff, 0x3f, 0x00, 0x00, 0x10, 0x11, 0x24, 0x48, 0x92, 0x04, 0x88, 0x04,
+  0x21, 0x49, 0x62, 0x00, 0x00, 0x00, 0x80, 0xff, 0xff, 0x3f, 0x00, 0x00,
+  0x10, 0x11, 0x24, 0x48, 0x92, 0x04, 0x88, 0x04, 0x21, 0x49, 0x93, 0x00,
+  0x00, 0x00, 0x80, 0xff, 0xcf, 0x7e, 0x00, 0x00, 0x10, 0xe1, 0xc4, 0x31,
+  0x92, 0x38, 0x30, 0x03, 0x2f, 0x89, 0x92, 0x00, 0x00, 0x00, 0x80, 0xe3,
+  0x07, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xc1, 0x03, 0x7e, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x80, 0xc9, 0x23, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x95,
+  0x33, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xdd, 0xfb, 0x7e, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x80, 0x1d, 0xf8, 0x7e, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00,
+  0x02, 0x00, 0x40, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x9b,
+  0x70, 0x7e, 0x00, 0x00, 0x08, 0x00, 0xe0, 0x00, 0x02, 0x00, 0x47, 0x80,
+  0x08, 0x00, 0x00, 0x08, 0x00, 0x00, 0x80, 0x03, 0x00, 0x7e, 0x00, 0x00,
+  0x3c, 0xa3, 0x20, 0x31, 0x52, 0x02, 0x49, 0xcc, 0x3f, 0xa3, 0x94, 0x08,
+  0x00, 0x00, 0x00, 0x27, 0x02, 0x7e, 0x00, 0x00, 0x88, 0xe4, 0x20, 0x41,
+  0xb2, 0x05, 0x49, 0x90, 0x88, 0xe4, 0x6c, 0x09, 0x00, 0x00, 0x00, 0x01,
+  0x00, 0x7e, 0x00, 0x00, 0x88, 0x24, 0xe0, 0x70, 0x92, 0x04, 0x47, 0x9c,
+  0x88, 0x24, 0x24, 0x09, 0x00, 0x00, 0x00, 0x13, 0x48, 0x7e, 0x00, 0x00,
+  0x88, 0x24, 0x20, 0x48, 0x92, 0x04, 0x41, 0x92, 0x88, 0x24, 0x24, 0x01,
+  0x00, 0x00, 0x00, 0x43, 0x00, 0xfe, 0x00, 0x00, 0x88, 0x24, 0x20, 0x48,
+  0x92, 0x04, 0x41, 0x92, 0x88, 0x24, 0x24, 0x09, 0x00, 0x00, 0x00, 0x07,
+  0x94, 0xce, 0x00, 0x00, 0x08, 0x23, 0x20, 0xb0, 0x92, 0x04, 0x41, 0x2c,
+  0x0b, 0x23, 0x24, 0x09, 0x00, 0x00, 0x00, 0x49, 0x02, 0xce, 0x01, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x11, 0x08, 0xdc, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41,
+  0x01, 0xfc, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0xf8, 0x07, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0xc0, 0x01, 0x00, 0xf8, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x01,
+  0x00, 0xf0, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x00, 0x00, 0xf0, 0x1f, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x70, 0x00, 0x00, 0xe0, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x00,
+  0x00, 0xe0, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0xe0, 0x7f, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x3c, 0x00, 0x00, 0xe0, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x00,
+  0x00, 0xc0, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0xc0, 0xff, 0x01,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x1f, 0x00, 0x00, 0x80, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00,
+  0x00, 0x80, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x0f, 0x00, 0x00, 0x00, 0xff, 0x07,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x80, 0x07, 0x00, 0x00, 0x00, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x07, 0x00,
+  0x00, 0x00, 0xfe, 0x07, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x07, 0x00, 0x00, 0x00, 0xfe, 0x0f,
+  0x00, 0x00, 0x80, 0x08, 0x00, 0x00, 0x05, 0x00, 0x00, 0x80, 0x08, 0x00,
+  0x00, 0xc0, 0x03, 0x00, 0x78, 0x00, 0xfe, 0x0f, 0x00, 0x00, 0x40, 0x10,
+  0x12, 0x10, 0x05, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0xe0, 0x03, 0x00,
+  0x84, 0x00, 0xfe, 0x0f, 0x00, 0x00, 0x20, 0x26, 0x0a, 0x10, 0x9d, 0x39,
+  0xa6, 0xb2, 0x0a, 0x00, 0x00, 0xe0, 0x01, 0x00, 0x02, 0x00, 0xfe, 0x0f,
+  0x00, 0x00, 0x20, 0x21, 0x06, 0x28, 0x25, 0x4a, 0xa9, 0x8a, 0x09, 0x00,
+  0x00, 0xe0, 0x01, 0x22, 0x02, 0x00, 0xfc, 0x1f, 0x00, 0x00, 0x20, 0x21,
+  0x0e, 0x38, 0xa5, 0x4b, 0xa9, 0xb2, 0x09, 0x00, 0x00, 0xf0, 0x01, 0x22,
+  0x02, 0x00, 0xfc, 0x1f, 0x00, 0x00, 0x20, 0x21, 0x12, 0x44, 0xa5, 0x4a,
+  0x49, 0xa1, 0x0a, 0x00, 0x00, 0xf8, 0x01, 0x22, 0x02, 0x00, 0xfc, 0x1f,
+  0x00, 0x00, 0x20, 0x26, 0x52, 0x44, 0x9d, 0x4d, 0x46, 0x99, 0x0a, 0x00,
+  0x00, 0xfc, 0x01, 0x22, 0x02, 0x00, 0xfc, 0x1f, 0x00, 0x00, 0x40, 0x10,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x01, 0xb2,
+  0x84, 0x00, 0xfc, 0x1f, 0x00, 0x00, 0x80, 0x08, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x01, 0x6e, 0x78, 0x00, 0xfc, 0x1f,
+  0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0xfc, 0x01, 0x02, 0x00, 0x00, 0xfc, 0x1f, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0x01, 0x02,
+  0x00, 0x00, 0xfe, 0x1f, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x06, 0x00, 0x00, 0xfc, 0x0f,
+  0x00, 0x00, 0x80, 0x08, 0x00, 0x00, 0x20, 0x01, 0x02, 0x00, 0x00, 0x00,
+  0x00, 0x24, 0x06, 0x00, 0x00, 0x00, 0xfc, 0x07, 0x00, 0x00, 0x40, 0x10,
+  0x1e, 0x20, 0x90, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00,
+  0x00, 0x80, 0xfc, 0x03, 0x00, 0x00, 0x20, 0x26, 0x22, 0x20, 0xf9, 0x89,
+  0x32, 0xe7, 0x08, 0x00, 0x00, 0x92, 0x38, 0x00, 0x00, 0x00, 0xfc, 0x01,
+  0x00, 0x00, 0x20, 0x21, 0x22, 0xa0, 0x92, 0x88, 0x4a, 0x29, 0x15, 0x00,
+  0x00, 0x00, 0x78, 0x00, 0x00, 0x40, 0xfa, 0x04, 0x00, 0x00, 0x20, 0x21,
+  0x22, 0xa0, 0x93, 0x88, 0x4a, 0x29, 0x1d, 0x00, 0x00, 0x11, 0xf2, 0x00,
+  0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x20, 0x21, 0x22, 0xa8, 0x90, 0x88,
+  0x4a, 0x29, 0x05, 0x00, 0x48, 0x40, 0xf0, 0x01, 0x00, 0x80, 0x14, 0x04,
+  0x00, 0x00, 0x20, 0x26, 0x9e, 0x10, 0x93, 0x78, 0x32, 0x29, 0x19, 0x00,
+  0x00, 0x09, 0xe0, 0x03, 0x00, 0x00, 0x80, 0x10, 0x00, 0x00, 0x40, 0x10,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0xc5, 0x03,
+  0x00, 0x40, 0x22, 0x00, 0x00, 0x00, 0x80, 0x08, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x40, 0x04, 0xc0, 0x07, 0x00, 0x20, 0x08, 0x04,
+  0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x08, 0x50, 0x90, 0x03, 0x00, 0xb0, 0x00, 0x41, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00,
+  0x00, 0x38, 0x22, 0x08, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x48, 0x04, 0x44, 0x00, 0x00, 0x3c, 0x08, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x20, 0x00, 0x00, 0x00, 0xbf, 0x40, 0x42, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x40, 0x02, 0x00, 0x00, 0x00, 0x00, 0x24, 0x80, 0x48, 0x02,
+  0xc0, 0x1f, 0x00, 0x08, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4e, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x05, 0xf0, 0x3f, 0x09, 0x00,
+  0x00, 0x10, 0x24, 0x48, 0x10, 0x12, 0x41, 0x52, 0x24, 0x09, 0x46, 0x71,
+  0x90, 0x20, 0x02, 0xfc, 0xff, 0x1f, 0x80, 0x22, 0x00, 0x90, 0x24, 0x49,
+  0x12, 0x92, 0x40, 0xb2, 0x24, 0x09, 0xc9, 0x49, 0x04, 0x80, 0x90, 0xfc,
+  0xff, 0xbf, 0x24, 0x00, 0x00, 0x90, 0x24, 0x49, 0x12, 0x92, 0x40, 0x92,
+  0x24, 0x06, 0x49, 0x48, 0x50, 0x0a, 0x02, 0xfe, 0xff, 0x3f, 0x00, 0x05,
+  0x00, 0x50, 0xa5, 0x4a, 0x15, 0x92, 0x40, 0x92, 0x24, 0x06, 0x49, 0x48,
+  0x80, 0x40, 0x48, 0xfe, 0xff, 0x3f, 0x49, 0x00, 0x00, 0x20, 0x42, 0x84,
+  0x88, 0x1a, 0x41, 0x92, 0x34, 0x49, 0x49, 0x68, 0x00, 0x38, 0x10, 0x07,
+  0x00, 0x60, 0x80, 0x00, 0x00, 0x20, 0x42, 0x84, 0x88, 0x14, 0x4e, 0x92,
+  0x28, 0x49, 0x46, 0x50, 0x00, 0x80, 0x83, 0x01, 0x00, 0xa0, 0x6a, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40,
+  0x00, 0x00, 0xfc, 0x00, 0x00, 0xc0, 0x3b, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, };
diff --git a/arch/m68k/68000/entry.S b/arch/m68k/68000/entry.S
new file mode 100644 (file)
index 0000000..259b366
--- /dev/null
@@ -0,0 +1,244 @@
+/*
+ *  entry.S -- non-mmu 68000 interrupt and exception entry points
+ *
+ *  Copyright (C) 1991, 1992  Linus Torvalds
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file README.legal in the main directory of this archive
+ * for more details.
+ *
+ * Linux/m68k support by Hamish Macdonald
+ */
+
+#include <linux/linkage.h>
+#include <asm/thread_info.h>
+#include <asm/unistd.h>
+#include <asm/errno.h>
+#include <asm/setup.h>
+#include <asm/segment.h>
+#include <asm/traps.h>
+#include <asm/asm-offsets.h>
+#include <asm/entry.h>
+
+.text
+
+.globl system_call
+.globl resume
+.globl ret_from_exception
+.globl ret_from_signal
+.globl sys_call_table
+.globl bad_interrupt
+.globl inthandler1
+.globl inthandler2
+.globl inthandler3
+.globl inthandler4
+.globl inthandler5
+.globl inthandler6
+.globl inthandler7
+
+badsys:
+       movel   #-ENOSYS,%sp@(PT_OFF_D0)
+       jra     ret_from_exception
+
+do_trace:
+       movel   #-ENOSYS,%sp@(PT_OFF_D0) /* needed for strace*/
+       subql   #4,%sp
+       SAVE_SWITCH_STACK
+       jbsr    syscall_trace_enter
+       RESTORE_SWITCH_STACK
+       addql   #4,%sp
+       movel   %sp@(PT_OFF_ORIG_D0),%d1
+       movel   #-ENOSYS,%d0
+       cmpl    #NR_syscalls,%d1
+       jcc     1f
+       lsl     #2,%d1
+       lea     sys_call_table, %a0
+       jbsr    %a0@(%d1)
+
+1:     movel   %d0,%sp@(PT_OFF_D0)     /* save the return value */
+       subql   #4,%sp                  /* dummy return address */
+       SAVE_SWITCH_STACK
+       jbsr    syscall_trace_leave
+
+ret_from_signal:
+       RESTORE_SWITCH_STACK
+       addql   #4,%sp
+       jra     ret_from_exception
+
+ENTRY(system_call)
+       SAVE_ALL_SYS
+
+       /* save top of frame*/
+       pea     %sp@
+       jbsr    set_esp0
+       addql   #4,%sp
+
+       movel   %sp@(PT_OFF_ORIG_D0),%d0
+
+       movel   %sp,%d1                 /* get thread_info pointer */
+       andl    #-THREAD_SIZE,%d1
+       movel   %d1,%a2
+       btst    #(TIF_SYSCALL_TRACE%8),%a2@(TINFO_FLAGS+(31-TIF_SYSCALL_TRACE)/8)
+       jne     do_trace
+       cmpl    #NR_syscalls,%d0
+       jcc     badsys
+       lsl     #2,%d0
+       lea     sys_call_table,%a0
+       movel   %a0@(%d0), %a0
+       jbsr    %a0@
+       movel   %d0,%sp@(PT_OFF_D0)     /* save the return value*/
+
+ret_from_exception:
+       btst    #5,%sp@(PT_OFF_SR)      /* check if returning to kernel*/
+       jeq     Luser_return            /* if so, skip resched, signals*/
+
+Lkernel_return:
+       RESTORE_ALL
+
+Luser_return:
+       /* only allow interrupts when we are really the last one on the*/
+       /* kernel stack, otherwise stack overflow can occur during*/
+       /* heavy interrupt load*/
+       andw    #ALLOWINT,%sr
+
+       movel   %sp,%d1                 /* get thread_info pointer */
+       andl    #-THREAD_SIZE,%d1
+       movel   %d1,%a2
+1:
+       move    %a2@(TINFO_FLAGS),%d1   /* thread_info->flags */
+       jne     Lwork_to_do
+       RESTORE_ALL
+
+Lwork_to_do:
+       movel   %a2@(TINFO_FLAGS),%d1   /* thread_info->flags */
+       btst    #TIF_NEED_RESCHED,%d1
+       jne     reschedule
+
+Lsignal_return:
+       subql   #4,%sp                  /* dummy return address*/
+       SAVE_SWITCH_STACK
+       pea     %sp@(SWITCH_STACK_SIZE)
+       bsrw    do_notify_resume
+       addql   #4,%sp
+       RESTORE_SWITCH_STACK
+       addql   #4,%sp
+       jra     1b
+
+/*
+ * This is the main interrupt handler, responsible for calling process_int()
+ */
+inthandler1:
+       SAVE_ALL_INT
+       movew   %sp@(PT_OFF_FORMATVEC), %d0
+       and     #0x3ff, %d0
+
+       movel   %sp,%sp@-
+       movel   #65,%sp@-               /*  put vector # on stack*/
+       jbsr    process_int             /*  process the IRQ*/
+3:             addql   #8,%sp                  /*  pop parameters off stack*/
+       bra     ret_from_exception
+
+inthandler2:
+       SAVE_ALL_INT
+       movew   %sp@(PT_OFF_FORMATVEC), %d0
+       and     #0x3ff, %d0
+
+       movel   %sp,%sp@-
+       movel   #66,%sp@-               /*  put vector # on stack*/
+       jbsr    process_int             /*  process the IRQ*/
+3:             addql   #8,%sp                  /*  pop parameters off stack*/
+       bra     ret_from_exception
+
+inthandler3:
+       SAVE_ALL_INT
+       movew   %sp@(PT_OFF_FORMATVEC), %d0
+       and     #0x3ff, %d0
+
+       movel   %sp,%sp@-
+       movel   #67,%sp@-               /*  put vector # on stack*/
+       jbsr    process_int             /*  process the IRQ*/
+3:             addql   #8,%sp                  /*  pop parameters off stack*/
+       bra     ret_from_exception
+
+inthandler4:
+       SAVE_ALL_INT
+       movew   %sp@(PT_OFF_FORMATVEC), %d0
+       and     #0x3ff, %d0
+
+       movel   %sp,%sp@-
+       movel   #68,%sp@-               /*  put vector # on stack*/
+       jbsr    process_int             /*  process the IRQ*/
+3:             addql   #8,%sp                  /*  pop parameters off stack*/
+       bra     ret_from_exception
+
+inthandler5:
+       SAVE_ALL_INT
+       movew   %sp@(PT_OFF_FORMATVEC), %d0
+       and     #0x3ff, %d0
+
+       movel   %sp,%sp@-
+       movel   #69,%sp@-               /*  put vector # on stack*/
+       jbsr    process_int             /*  process the IRQ*/
+3:             addql   #8,%sp                  /*  pop parameters off stack*/
+       bra     ret_from_exception
+
+inthandler6:
+       SAVE_ALL_INT
+       movew   %sp@(PT_OFF_FORMATVEC), %d0
+       and     #0x3ff, %d0
+
+       movel   %sp,%sp@-
+       movel   #70,%sp@-               /*  put vector # on stack*/
+       jbsr    process_int             /*  process the IRQ*/
+3:             addql   #8,%sp                  /*  pop parameters off stack*/
+       bra     ret_from_exception
+
+inthandler7:
+       SAVE_ALL_INT
+       movew   %sp@(PT_OFF_FORMATVEC), %d0
+       and     #0x3ff, %d0
+
+       movel   %sp,%sp@-
+       movel   #71,%sp@-               /*  put vector # on stack*/
+       jbsr    process_int             /*  process the IRQ*/
+3:             addql   #8,%sp                  /*  pop parameters off stack*/
+       bra     ret_from_exception
+
+inthandler:
+       SAVE_ALL_INT
+       movew   %sp@(PT_OFF_FORMATVEC), %d0
+       and     #0x3ff, %d0
+
+       movel   %sp,%sp@-
+       movel   %d0,%sp@-               /*  put vector # on stack*/
+       jbsr    process_int             /*  process the IRQ*/
+3:             addql   #8,%sp                  /*  pop parameters off stack*/
+       bra     ret_from_exception
+
+/*
+ * Handler for uninitialized and spurious interrupts.
+ */
+ENTRY(bad_interrupt)
+       addql   #1,irq_err_count
+       rte
+
+/*
+ * Beware - when entering resume, prev (the current task) is
+ * in a0, next (the new task) is in a1, so don't change these
+ * registers until their contents are no longer needed.
+ */
+ENTRY(resume)
+       movel   %a0,%d1                         /* save prev thread in d1 */
+       movew   %sr,%a0@(TASK_THREAD+THREAD_SR) /* save sr */
+       SAVE_SWITCH_STACK
+       movel   %sp,%a0@(TASK_THREAD+THREAD_KSP) /* save kernel stack */
+       movel   %usp,%a3                        /* save usp */
+       movel   %a3,%a0@(TASK_THREAD+THREAD_USP)
+
+       movel   %a1@(TASK_THREAD+THREAD_USP),%a3 /* restore user stack */
+       movel   %a3,%usp
+       movel   %a1@(TASK_THREAD+THREAD_KSP),%sp /* restore new thread stack */
+       RESTORE_SWITCH_STACK
+       movew   %a1@(TASK_THREAD+THREAD_SR),%sr /* restore thread status reg */
+       rts
+
diff --git a/arch/m68k/68000/head.S b/arch/m68k/68000/head.S
new file mode 100644 (file)
index 0000000..536ef96
--- /dev/null
@@ -0,0 +1,240 @@
+/*
+ * head.S - Common startup code for 68000 core based CPU's
+ *
+ * 2012.10.21, Luis Alves <ljalvs@gmail.com>, Single head.S file for all
+ *             68000 core based CPU's. Based on the sources from:
+ *             Coldfire by Greg Ungerer <gerg@snapgear.com>
+ *             68328 by D. Jeff Dionne <jeff@ryeham.ee.ryerson.ca>,
+ *                      Kenneth Albanowski <kjahds@kjahds.com>,
+ *                      The Silver Hammer Group, Ltd.
+ *
+ */
+
+#include <linux/linkage.h>
+#include <linux/init.h>
+#include <asm/asm-offsets.h>
+#include <asm/thread_info.h>
+
+
+/*****************************************************************************
+ * UCSIMM and UCDIMM use CONFIG_MEMORY_RESERVE to reserve some RAM
+ *****************************************************************************/
+#ifdef CONFIG_MEMORY_RESERVE
+#define RAMEND (CONFIG_RAMBASE+CONFIG_RAMSIZE)-(CONFIG_MEMORY_RESERVE*0x100000)
+#else
+#define RAMEND (CONFIG_RAMBASE+CONFIG_RAMSIZE)
+#endif
+/*****************************************************************************/
+
+.global _start
+.global _rambase
+.global _ramvec
+.global _ramstart
+.global _ramend
+
+#if defined(CONFIG_PILOT) || defined(CONFIG_INIT_LCD)
+.global bootlogo_bits
+#endif
+
+/* Defining DEBUG_HEAD_CODE, serial port in 68x328 is inited */
+/* #define DEBUG_HEAD_CODE */
+#undef DEBUG_HEAD_CODE
+
+.data
+
+/*****************************************************************************
+ * RAM setup pointers. Used by the kernel to determine RAM location and size.
+ *****************************************************************************/
+
+_rambase:
+       .long   0
+_ramvec:
+       .long   0
+_ramstart:
+       .long   0
+_ramend:
+       .long   0
+
+__HEAD
+
+/*****************************************************************************
+ * Entry point, where all begins!
+ *****************************************************************************/
+
+_start:
+
+/* Pilot need this specific signature at the start of ROM */
+#ifdef CONFIG_PILOT
+       .byte   0x4e, 0xfa, 0x00, 0x0a          /* bra opcode (jmp 10 bytes) */
+       .byte   'b', 'o', 'o', 't'
+       .word   10000
+       nop
+       moveq   #0, %d0
+       movew   %d0, 0xfffff618                 /* Watchdog off */
+       movel   #0x00011f07, 0xfffff114         /* CS A1 Mask */
+#endif /* CONFIG_PILOT */
+
+       movew   #0x2700, %sr                    /* disable all interrupts */
+
+/*****************************************************************************
+ * Setup PLL and wait for it to settle (in 68x328 cpu's).
+ * Also, if enabled, init serial port.
+ *****************************************************************************/
+#if defined(CONFIG_M68328) || \
+    defined(CONFIG_M68EZ328) || \
+    defined(CONFIG_M68VZ328)
+
+/* Serial port setup. Should only be needed if debugging this startup code. */
+#ifdef DEBUG_HEAD_CODE
+       movew   #0x0800, 0xfffff906             /* Ignore CTS */
+       movew   #0x010b, 0xfffff902             /* BAUD to 9600 */
+       movew   #0xe100, 0xfffff900             /* enable */
+#endif /* DEBUG_HEAD */
+
+#ifdef CONFIG_PILOT
+       movew   #0x2410, 0xfffff200             /* PLLCR */
+#else
+       movew   #0x2400, 0xfffff200             /* PLLCR */
+#endif
+       movew   #0x0123, 0xfffff202             /* PLLFSR */
+       moveq   #0, %d0
+       movew   #16384, %d0                     /* PLL settle wait loop */
+_pll_settle:
+       subw    #1, %d0
+       bne     _pll_settle
+#endif /* CONFIG_M68x328 */
+
+
+/*****************************************************************************
+ * If running kernel from ROM some specific initialization has to be done.
+ * (Assuming that everything is already init'ed when running from RAM)
+ *****************************************************************************/
+#ifdef CONFIG_ROMKERNEL
+
+/*****************************************************************************
+ * Init chip registers (uCsimm specific)
+ *****************************************************************************/
+#ifdef CONFIG_UCSIMM
+       moveb   #0x00, 0xfffffb0b       /* Watchdog off */
+       moveb   #0x10, 0xfffff000       /* SCR */
+       moveb   #0x00, 0xfffff40b       /* enable chip select */
+       moveb   #0x00, 0xfffff423       /* enable /DWE */
+       moveb   #0x08, 0xfffffd0d       /* disable hardmap */
+       moveb   #0x07, 0xfffffd0e       /* level 7 interrupt clear */
+       movew   #0x8600, 0xfffff100     /* FLASH at 0x10c00000 */
+       movew   #0x018b, 0xfffff110     /* 2Meg, enable, 0ws */
+       movew   #0x8f00, 0xfffffc00     /* DRAM configuration */
+       movew   #0x9667, 0xfffffc02     /* DRAM control */
+       movew   #0x0000, 0xfffff106     /* DRAM at 0x00000000 */
+       movew   #0x068f, 0xfffff116     /* 8Meg, enable, 0ws */
+       moveb   #0x40, 0xfffff300       /* IVR */
+       movel   #0x007FFFFF, %d0        /* IMR */
+       movel   %d0, 0xfffff304
+       moveb   0xfffff42b, %d0
+       andb    #0xe0, %d0
+       moveb   %d0, 0xfffff42b
+#endif
+
+/*****************************************************************************
+ * Init LCD controller.
+ * (Assuming that LCD controller is already init'ed when running from RAM)
+ *****************************************************************************/
+#ifdef CONFIG_INIT_LCD
+#ifdef CONFIG_PILOT
+       moveb   #0, 0xfffffA27                  /* LCKCON */
+       movel   #_start, 0xfffffA00             /* LSSA */
+       moveb   #0xa, 0xfffffA05                /* LVPW */
+       movew   #0x9f, 0xFFFFFa08               /* LXMAX */
+       movew   #0x9f, 0xFFFFFa0a               /* LYMAX */
+       moveb   #9, 0xfffffa29                  /* LBAR */
+       moveb   #0, 0xfffffa25                  /* LPXCD */
+       moveb   #0x04, 0xFFFFFa20               /* LPICF */
+       moveb   #0x58, 0xfffffA27               /* LCKCON */
+       moveb   #0x85, 0xfffff429               /* PFDATA */
+       moveb   #0xd8, 0xfffffA27               /* LCKCON */
+       moveb   #0xc5, 0xfffff429               /* PFDATA */
+       moveb   #0xd5, 0xfffff429               /* PFDATA */
+       movel   #bootlogo_bits, 0xFFFFFA00      /* LSSA */
+       moveb   #10, 0xFFFFFA05                 /* LVPW */
+       movew   #160, 0xFFFFFA08                /* LXMAX */
+       movew   #160, 0xFFFFFA0A                /* LYMAX */
+#else /* CONFIG_PILOT */
+       movel   #bootlogo_bits, 0xfffffA00      /* LSSA */
+       moveb   #0x28, 0xfffffA05               /* LVPW */
+       movew   #0x280, 0xFFFFFa08              /* LXMAX */
+       movew   #0x1df, 0xFFFFFa0a              /* LYMAX */
+       moveb   #0, 0xfffffa29                  /* LBAR */
+       moveb   #0, 0xfffffa25                  /* LPXCD */
+       moveb   #0x08, 0xFFFFFa20               /* LPICF */
+       moveb   #0x01, 0xFFFFFA21               /* -ve pol */
+       moveb   #0x81, 0xfffffA27               /* LCKCON */
+       movew   #0xff00, 0xfffff412             /* LCD pins */
+#endif /* CONFIG_PILOT */
+#endif /* CONFIG_INIT_LCD */
+
+/*****************************************************************************
+ * Kernel is running from FLASH/ROM (XIP)
+ * Copy init text & data to RAM
+ *****************************************************************************/
+       moveal  #_etext, %a0
+       moveal  #_sdata, %a1
+       moveal  #__bss_start, %a2
+_copy_initmem:
+       movel   %a0@+, %a1@+
+       cmpal   %a1, %a2
+       bhi     _copy_initmem
+#endif /* CONFIG_ROMKERNEL */
+
+/*****************************************************************************
+ * Setup basic memory information for kernel
+ *****************************************************************************/
+       movel   #CONFIG_VECTORBASE,_ramvec      /* set vector base location */
+       movel   #CONFIG_RAMBASE,_rambase        /* set the base of RAM */
+       movel   #RAMEND, _ramend                /* set end ram addr */
+       lea     __bss_stop,%a1
+       movel   %a1,_ramstart
+
+/*****************************************************************************
+ * If the kernel is in RAM, move romfs to right above bss and
+ * adjust _ramstart to where romfs ends.
+ *
+ * (Do this only if CONFIG_MTD_UCLINUX is true)
+ *****************************************************************************/
+
+#if defined(CONFIG_ROMFS_FS) && defined(CONFIG_RAMKERNEL) && \
+    defined(CONFIG_MTD_UCLINUX)
+       lea     __bss_start, %a0                /* get start of bss */
+       lea     __bss_stop, %a1                 /* set up destination  */
+       movel   %a0, %a2                        /* copy of bss start */
+
+       movel   8(%a0), %d0                     /* get size of ROMFS */
+       addql   #8, %d0                         /* allow for rounding */
+       andl    #0xfffffffc, %d0                /* whole words */
+
+       addl    %d0, %a0                        /* copy from end */
+       addl    %d0, %a1                        /* copy from end */
+       movel   %a1, _ramstart                  /* set start of ram */
+_copy_romfs:
+       movel   -(%a0), -(%a1)                  /* copy dword */
+       cmpl    %a0, %a2                        /* check if at end */
+       bne     _copy_romfs
+#endif /* CONFIG_ROMFS_FS && CONFIG_RAMKERNEL && CONFIG_MTD_UCLINUX */
+
+/*****************************************************************************
+ * Clear bss region
+ *****************************************************************************/
+       lea     __bss_start, %a0                /* get start of bss */
+       lea     __bss_stop, %a1                 /* get end of bss */
+_clear_bss:
+       movel   #0, (%a0)+                      /* clear each word */
+       cmpl    %a0, %a1                        /* check if at end */
+       bne     _clear_bss
+
+/*****************************************************************************
+ * Load the current task pointer and stack.
+ *****************************************************************************/
+       lea     init_thread_union,%a0
+       lea     THREAD_SIZE(%a0),%sp
+       jsr     start_kernel                    /* start Linux kernel */
+_exit:
+       jmp     _exit                           /* should never get here */
diff --git a/arch/m68k/68000/ints.c b/arch/m68k/68000/ints.c
new file mode 100644 (file)
index 0000000..cda49b1
--- /dev/null
@@ -0,0 +1,186 @@
+/*
+ * ints.c - Generic interrupt controller support
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file COPYING in the main directory of this archive
+ * for more details.
+ *
+ * Copyright 1996 Roman Zippel
+ * Copyright 1999 D. Jeff Dionne <jeff@rt-control.com>
+ */
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <asm/traps.h>
+#include <asm/io.h>
+#include <asm/machdep.h>
+
+#if defined(CONFIG_M68328)
+#include <asm/MC68328.h>
+#elif defined(CONFIG_M68EZ328)
+#include <asm/MC68EZ328.h>
+#elif defined(CONFIG_M68VZ328)
+#include <asm/MC68VZ328.h>
+#endif
+
+/* assembler routines */
+asmlinkage void system_call(void);
+asmlinkage void buserr(void);
+asmlinkage void trap(void);
+asmlinkage void trap3(void);
+asmlinkage void trap4(void);
+asmlinkage void trap5(void);
+asmlinkage void trap6(void);
+asmlinkage void trap7(void);
+asmlinkage void trap8(void);
+asmlinkage void trap9(void);
+asmlinkage void trap10(void);
+asmlinkage void trap11(void);
+asmlinkage void trap12(void);
+asmlinkage void trap13(void);
+asmlinkage void trap14(void);
+asmlinkage void trap15(void);
+asmlinkage void trap33(void);
+asmlinkage void trap34(void);
+asmlinkage void trap35(void);
+asmlinkage void trap36(void);
+asmlinkage void trap37(void);
+asmlinkage void trap38(void);
+asmlinkage void trap39(void);
+asmlinkage void trap40(void);
+asmlinkage void trap41(void);
+asmlinkage void trap42(void);
+asmlinkage void trap43(void);
+asmlinkage void trap44(void);
+asmlinkage void trap45(void);
+asmlinkage void trap46(void);
+asmlinkage void trap47(void);
+asmlinkage irqreturn_t bad_interrupt(int, void *);
+asmlinkage irqreturn_t inthandler(void);
+asmlinkage irqreturn_t inthandler1(void);
+asmlinkage irqreturn_t inthandler2(void);
+asmlinkage irqreturn_t inthandler3(void);
+asmlinkage irqreturn_t inthandler4(void);
+asmlinkage irqreturn_t inthandler5(void);
+asmlinkage irqreturn_t inthandler6(void);
+asmlinkage irqreturn_t inthandler7(void);
+
+/* The 68k family did not have a good way to determine the source
+ * of interrupts until later in the family.  The EC000 core does
+ * not provide the vector number on the stack, we vector everything
+ * into one vector and look in the blasted mask register...
+ * This code is designed to be fast, almost constant time, not clean!
+ */
+void process_int(int vec, struct pt_regs *fp)
+{
+       int irq;
+       int mask;
+
+       unsigned long pend = ISR;
+
+       while (pend) {
+               if (pend & 0x0000ffff) {
+                       if (pend & 0x000000ff) {
+                               if (pend & 0x0000000f) {
+                                       mask = 0x00000001;
+                                       irq = 0;
+                               } else {
+                                       mask = 0x00000010;
+                                       irq = 4;
+                               }
+                       } else {
+                               if (pend & 0x00000f00) {
+                                       mask = 0x00000100;
+                                       irq = 8;
+                               } else {
+                                       mask = 0x00001000;
+                                       irq = 12;
+                               }
+                       }
+               } else {
+                       if (pend & 0x00ff0000) {
+                               if (pend & 0x000f0000) {
+                                       mask = 0x00010000;
+                                       irq = 16;
+                               } else {
+                                       mask = 0x00100000;
+                                       irq = 20;
+                               }
+                       } else {
+                               if (pend & 0x0f000000) {
+                                       mask = 0x01000000;
+                                       irq = 24;
+                               } else {
+                                       mask = 0x10000000;
+                                       irq = 28;
+                               }
+                       }
+               }
+
+               while (! (mask & pend)) {
+                       mask <<=1;
+                       irq++;
+               }
+
+               do_IRQ(irq, fp);
+               pend &= ~mask;
+       }
+}
+
+static void intc_irq_unmask(struct irq_data *d)
+{
+       IMR &= ~(1 << d->irq);
+}
+
+static void intc_irq_mask(struct irq_data *d)
+{
+       IMR |= (1 << d->irq);
+}
+
+static struct irq_chip intc_irq_chip = {
+       .name           = "M68K-INTC",
+       .irq_mask       = intc_irq_mask,
+       .irq_unmask     = intc_irq_unmask,
+};
+
+/*
+ * This function should be called during kernel startup to initialize
+ * the machine vector table.
+ */
+void __init trap_init(void)
+{
+       int i;
+
+       /* set up the vectors */
+       for (i = 72; i < 256; ++i)
+               _ramvec[i] = (e_vector) bad_interrupt;
+
+       _ramvec[32] = system_call;
+
+       _ramvec[65] = (e_vector) inthandler1;
+       _ramvec[66] = (e_vector) inthandler2;
+       _ramvec[67] = (e_vector) inthandler3;
+       _ramvec[68] = (e_vector) inthandler4;
+       _ramvec[69] = (e_vector) inthandler5;
+       _ramvec[70] = (e_vector) inthandler6;
+       _ramvec[71] = (e_vector) inthandler7;
+}
+
+void __init init_IRQ(void)
+{
+       int i;
+
+       IVR = 0x40; /* Set DragonBall IVR (interrupt base) to 64 */
+
+       /* turn off all interrupts */
+       IMR = ~0;
+
+       for (i = 0; (i < NR_IRQS); i++) {
+               irq_set_chip(i, &intc_irq_chip);
+               irq_set_handler(i, handle_level_irq);
+       }
+}
+
diff --git a/arch/m68k/68000/m68328.c b/arch/m68k/68000/m68328.c
new file mode 100644 (file)
index 0000000..e53caf4
--- /dev/null
@@ -0,0 +1,56 @@
+/***************************************************************************/
+
+/*
+ *  m68328.c - 68328 specific config
+ *
+ *  Copyright (C) 1993 Hamish Macdonald
+ *  Copyright (C) 1999 D. Jeff Dionne
+ *
+ * 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.
+ *
+ * VZ Support/Fixes             Evan Stawnyczy <e@lineo.ca>
+ */
+
+/***************************************************************************/
+
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/rtc.h>
+#include <asm/machdep.h>
+#include <asm/MC68328.h>
+#if defined(CONFIG_PILOT) || defined(CONFIG_INIT_LCD)
+#include "bootlogo.h"
+#endif
+
+/***************************************************************************/
+
+int m68328_hwclk(int set, struct rtc_time *t);
+
+/***************************************************************************/
+
+void m68328_reset (void)
+{
+  local_irq_disable();
+  asm volatile ("moveal #0x10c00000, %a0;\n\t"
+               "moveb #0, 0xFFFFF300;\n\t"
+               "moveal 0(%a0), %sp;\n\t"
+               "moveal 4(%a0), %a0;\n\t"
+               "jmp (%a0);");
+}
+
+/***************************************************************************/
+
+void __init config_BSP(char *command, int len)
+{
+  printk(KERN_INFO "\n68328 support D. Jeff Dionne <jeff@uclinux.org>\n");
+  printk(KERN_INFO "68328 support Kenneth Albanowski <kjahds@kjshds.com>\n");
+  printk(KERN_INFO "68328/Pilot support Bernhard Kuhn <kuhn@lpr.e-technik.tu-muenchen.de>\n");
+
+  mach_hwclk = m68328_hwclk;
+  mach_reset = m68328_reset;
+}
+
+/***************************************************************************/
diff --git a/arch/m68k/68000/m68EZ328.c b/arch/m68k/68000/m68EZ328.c
new file mode 100644 (file)
index 0000000..2195290
--- /dev/null
@@ -0,0 +1,78 @@
+/***************************************************************************/
+
+/*
+ *  m68EZ328.c - 68EZ328 specific config
+ *
+ *  Copyright (C) 1993 Hamish Macdonald
+ *  Copyright (C) 1999 D. Jeff Dionne
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file COPYING in the main directory of this archive
+ * for more details.
+ */
+
+/***************************************************************************/
+
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/rtc.h>
+#include <asm/pgtable.h>
+#include <asm/machdep.h>
+#include <asm/MC68EZ328.h>
+#ifdef CONFIG_UCSIMM
+#include <asm/bootstd.h>
+#endif
+
+/***************************************************************************/
+
+int m68328_hwclk(int set, struct rtc_time *t);
+
+/***************************************************************************/
+
+void m68ez328_reset(void)
+{
+  local_irq_disable();
+  asm volatile (
+    "moveal #0x10c00000, %a0;\n"
+    "moveb #0, 0xFFFFF300;\n"
+    "moveal 0(%a0), %sp;\n"
+    "moveal 4(%a0), %a0;\n"
+    "jmp (%a0);\n"
+    );
+}
+
+/***************************************************************************/
+
+unsigned char *cs8900a_hwaddr;
+static int errno;
+
+#ifdef CONFIG_UCSIMM
+_bsc0(char *, getserialnum)
+_bsc1(unsigned char *, gethwaddr, int, a)
+_bsc1(char *, getbenv, char *, a)
+#endif
+
+void __init config_BSP(char *command, int len)
+{
+  unsigned char *p;
+
+  printk(KERN_INFO "\n68EZ328 DragonBallEZ support (C) 1999 Rt-Control, Inc\n");
+
+#ifdef CONFIG_UCSIMM
+  printk(KERN_INFO "uCsimm serial string [%s]\n",getserialnum());
+  p = cs8900a_hwaddr = gethwaddr(0);
+  printk(KERN_INFO "uCsimm hwaddr %.2x:%.2x:%.2x:%.2x:%.2x:%.2x\n",
+         p[0], p[1], p[2], p[3], p[4], p[5]);
+
+  p = getbenv("APPEND");
+  if (p) strcpy(p,command);
+  else command[0] = 0;
+#endif
+
+  mach_sched_init = hw_timer_init;
+  mach_hwclk = m68328_hwclk;
+  mach_reset = m68ez328_reset;
+}
+
+/***************************************************************************/
diff --git a/arch/m68k/68000/m68VZ328.c b/arch/m68k/68000/m68VZ328.c
new file mode 100644 (file)
index 0000000..0e5e5a1
--- /dev/null
@@ -0,0 +1,190 @@
+/***************************************************************************/
+
+/*
+ *  m68VZ328.c - 68VZ328 specific config
+ *
+ *  Copyright (C) 1993 Hamish Macdonald
+ *  Copyright (C) 1999 D. Jeff Dionne
+ *  Copyright (C) 2001 Georges Menie, Ken Desmet
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file COPYING in the main directory of this archive
+ * for more details.
+ */
+
+/***************************************************************************/
+
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/kd.h>
+#include <linux/netdevice.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/rtc.h>
+
+#include <asm/pgtable.h>
+#include <asm/machdep.h>
+#include <asm/MC68VZ328.h>
+#include <asm/bootstd.h>
+
+#ifdef CONFIG_INIT_LCD
+#include "bootlogo-vz.h"
+#endif
+
+/***************************************************************************/
+
+int m68328_hwclk(int set, struct rtc_time *t);
+
+/***************************************************************************/
+/*                        Init Drangon Engine hardware                     */
+/***************************************************************************/
+#if defined(CONFIG_DRAGEN2)
+
+static void m68vz328_reset(void)
+{
+       local_irq_disable();
+
+#ifdef CONFIG_INIT_LCD
+       PBDATA |= 0x20;                         /* disable CCFL light */
+       PKDATA |= 0x4;                          /* disable LCD controller */
+       LCKCON = 0;
+#endif
+
+       __asm__ __volatile__(
+               "reset\n\t"
+               "moveal #0x04000000, %a0\n\t"
+               "moveal 0(%a0), %sp\n\t"
+               "moveal 4(%a0), %a0\n\t"
+               "jmp (%a0)"
+       );
+}
+
+static void __init init_hardware(char *command, int size)
+{
+#ifdef CONFIG_DIRECT_IO_ACCESS
+       SCR = 0x10;                                     /* allow user access to internal registers */
+#endif
+
+       /* CSGB Init */
+       CSGBB = 0x4000;
+       CSB = 0x1a1;
+
+       /* CS8900 init */
+       /* PK3: hardware sleep function pin, active low */
+       PKSEL |= PK(3);                         /* select pin as I/O */
+       PKDIR |= PK(3);                         /* select pin as output */
+       PKDATA |= PK(3);                        /* set pin high */
+
+       /* PF5: hardware reset function pin, active high */
+       PFSEL |= PF(5);                         /* select pin as I/O */
+       PFDIR |= PF(5);                         /* select pin as output */
+       PFDATA &= ~PF(5);                       /* set pin low */
+
+       /* cs8900 hardware reset */
+       PFDATA |= PF(5);
+       { int i; for (i = 0; i < 32000; ++i); }
+       PFDATA &= ~PF(5);
+
+       /* INT1 enable (cs8900 IRQ) */
+       PDPOL &= ~PD(1);                        /* active high signal */
+       PDIQEG &= ~PD(1);
+       PDIRQEN |= PD(1);                       /* IRQ enabled */
+
+#ifdef CONFIG_INIT_LCD
+       /* initialize LCD controller */
+       LSSA = (long) screen_bits;
+       LVPW = 0x14;
+       LXMAX = 0x140;
+       LYMAX = 0xef;
+       LRRA = 0;
+       LPXCD = 3;
+       LPICF = 0x08;
+       LPOLCF = 0;
+       LCKCON = 0x80;
+       PCPDEN = 0xff;
+       PCSEL = 0;
+
+       /* Enable LCD controller */
+       PKDIR |= 0x4;
+       PKSEL |= 0x4;
+       PKDATA &= ~0x4;
+
+       /* Enable CCFL backlighting circuit */
+       PBDIR |= 0x20;
+       PBSEL |= 0x20;
+       PBDATA &= ~0x20;
+
+       /* contrast control register */
+       PFDIR |= 0x1;
+       PFSEL &= ~0x1;
+       PWMR = 0x037F;
+#endif
+}
+
+/***************************************************************************/
+/*                      Init RT-Control uCdimm hardware                    */
+/***************************************************************************/
+#elif defined(CONFIG_UCDIMM)
+
+static void m68vz328_reset(void)
+{
+       local_irq_disable();
+       asm volatile (
+               "moveal #0x10c00000, %a0;\n\t"
+               "moveb #0, 0xFFFFF300;\n\t"
+               "moveal 0(%a0), %sp;\n\t"
+               "moveal 4(%a0), %a0;\n\t"
+               "jmp (%a0);\n"
+       );
+}
+
+unsigned char *cs8900a_hwaddr;
+static int errno;
+
+_bsc0(char *, getserialnum)
+_bsc1(unsigned char *, gethwaddr, int, a)
+_bsc1(char *, getbenv, char *, a)
+
+static void __init init_hardware(char *command, int size)
+{
+       char *p;
+
+       printk(KERN_INFO "uCdimm serial string [%s]\n", getserialnum());
+       p = cs8900a_hwaddr = gethwaddr(0);
+       printk(KERN_INFO "uCdimm hwaddr %.2x:%.2x:%.2x:%.2x:%.2x:%.2x\n",
+               p[0], p[1], p[2], p[3], p[4], p[5]);
+       p = getbenv("APPEND");
+       if (p)
+               strcpy(p, command);
+       else
+               command[0] = 0;
+}
+
+/***************************************************************************/
+#else
+
+static void m68vz328_reset(void)
+{
+}
+
+static void __init init_hardware(char *command, int size)
+{
+}
+
+/***************************************************************************/
+#endif
+/***************************************************************************/
+
+void __init config_BSP(char *command, int size)
+{
+       printk(KERN_INFO "68VZ328 DragonBallVZ support (c) 2001 Lineo, Inc.\n");
+
+       init_hardware(command, size);
+
+       mach_sched_init = hw_timer_init;
+       mach_hwclk = m68328_hwclk;
+       mach_reset = m68vz328_reset;
+}
+
+/***************************************************************************/
diff --git a/arch/m68k/68000/romvec.S b/arch/m68k/68000/romvec.S
new file mode 100644 (file)
index 0000000..15c70cd
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * romvec.S - Vector table for 68000 cpus
+ *
+ * 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 1996 Roman Zippel
+ * Copyright 1999 D. Jeff Dionne <jeff@rt-control.com>
+ * Copyright 2006 Greg Ungerer <gerg@snapgear.com>
+ */
+
+.global _start
+.global _buserr
+.global trap
+.global system_call
+
+.section .romvec
+
+e_vectors:
+.long CONFIG_RAMBASE+CONFIG_RAMSIZE-4, _start, buserr, trap
+.long trap, trap, trap, trap
+.long trap, trap, trap, trap
+.long trap, trap, trap, trap
+.long trap, trap, trap, trap
+.long trap, trap, trap, trap
+.long trap, trap, trap, trap
+.long trap, trap, trap, trap
+/* TRAP #0-15 */
+.long system_call, trap, trap, trap
+.long trap, trap, trap, trap
+.long trap, trap, trap, trap
+.long trap, trap, trap, trap
+.long 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
+
diff --git a/arch/m68k/68000/timers.c b/arch/m68k/68000/timers.c
new file mode 100644 (file)
index 0000000..99a9869
--- /dev/null
@@ -0,0 +1,137 @@
+/***************************************************************************/
+
+/*
+ *  timers.c - Generic hardware timer support.
+ *
+ *  Copyright (C) 1993 Hamish Macdonald
+ *  Copyright (C) 1999 D. Jeff Dionne
+ *  Copyright (C) 2001 Georges Menie, Ken Desmet
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file COPYING in the main directory of this archive
+ * for more details.
+ */
+
+/***************************************************************************/
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/clocksource.h>
+#include <linux/rtc.h>
+#include <asm/setup.h>
+#include <asm/pgtable.h>
+#include <asm/machdep.h>
+#include <asm/MC68VZ328.h>
+
+/***************************************************************************/
+
+#if defined(CONFIG_DRAGEN2)
+/* with a 33.16 MHz clock, this will give usec resolution to the time functions */
+#define CLOCK_SOURCE   TCTL_CLKSOURCE_SYSCLK
+#define CLOCK_PRE      7
+#define TICKS_PER_JIFFY        41450
+
+#elif defined(CONFIG_XCOPILOT_BUGS)
+/*
+ * The only thing I know is that CLK32 is not available on Xcopilot
+ * I have little idea about what frequency SYSCLK has on Xcopilot.
+ * The values for prescaler and compare registers were simply
+ * taken from the original source
+ */
+#define CLOCK_SOURCE   TCTL_CLKSOURCE_SYSCLK
+#define CLOCK_PRE      2
+#define TICKS_PER_JIFFY        0xd7e4
+
+#else
+/* default to using the 32Khz clock */
+#define CLOCK_SOURCE   TCTL_CLKSOURCE_32KHZ
+#define CLOCK_PRE      31
+#define TICKS_PER_JIFFY        10
+#endif
+
+static u32 m68328_tick_cnt;
+static irq_handler_t timer_interrupt;
+
+/***************************************************************************/
+
+static irqreturn_t hw_tick(int irq, void *dummy)
+{
+       /* Reset Timer1 */
+       TSTAT &= 0;
+
+       m68328_tick_cnt += TICKS_PER_JIFFY;
+       return timer_interrupt(irq, dummy);
+}
+
+/***************************************************************************/
+
+static struct irqaction m68328_timer_irq = {
+       .name    = "timer",
+       .flags   = IRQF_TIMER,
+       .handler = hw_tick,
+};
+
+/***************************************************************************/
+
+static cycle_t m68328_read_clk(struct clocksource *cs)
+{
+       unsigned long flags;
+       u32 cycles;
+
+       local_irq_save(flags);
+       cycles = m68328_tick_cnt + TCN;
+       local_irq_restore(flags);
+
+       return cycles;
+}
+
+/***************************************************************************/
+
+static struct clocksource m68328_clk = {
+       .name   = "timer",
+       .rating = 250,
+       .read   = m68328_read_clk,
+       .mask   = CLOCKSOURCE_MASK(32),
+       .flags  = CLOCK_SOURCE_IS_CONTINUOUS,
+};
+
+/***************************************************************************/
+
+void hw_timer_init(irq_handler_t handler)
+{
+       /* disable timer 1 */
+       TCTL = 0;
+
+       /* set ISR */
+       setup_irq(TMR_IRQ_NUM, &m68328_timer_irq);
+
+       /* Restart mode, Enable int, Set clock source */
+       TCTL = TCTL_OM | TCTL_IRQEN | CLOCK_SOURCE;
+       TPRER = CLOCK_PRE;
+       TCMP = TICKS_PER_JIFFY;
+
+       /* Enable timer 1 */
+       TCTL |= TCTL_TEN;
+       clocksource_register_hz(&m68328_clk, TICKS_PER_JIFFY*HZ);
+       timer_interrupt = handler;
+}
+
+/***************************************************************************/
+
+int m68328_hwclk(int set, struct rtc_time *t)
+{
+       if (!set) {
+               long now = RTCTIME;
+               t->tm_year = t->tm_mon = t->tm_mday = 1;
+               t->tm_hour = (now >> 24) % 24;
+               t->tm_min = (now >> 16) % 60;
+               t->tm_sec = now % 60;
+       }
+
+       return 0;
+}
+
+/***************************************************************************/
diff --git a/arch/m68k/68360/Makefile b/arch/m68k/68360/Makefile
new file mode 100644 (file)
index 0000000..591ce42
--- /dev/null
@@ -0,0 +1,12 @@
+#
+# Makefile for 68360 machines.
+#
+model-y                          := ram
+model-$(CONFIG_ROMKERNEL) := rom
+
+obj-y := config.o commproc.o entry.o ints.o
+
+extra-y := head.o
+
+$(obj)/head.o: $(obj)/head-$(model-y).o
+       ln -sf head-$(model-y).o $(obj)/head.o
diff --git a/arch/m68k/68360/commproc.c b/arch/m68k/68360/commproc.c
new file mode 100644 (file)
index 0000000..315727b
--- /dev/null
@@ -0,0 +1,309 @@
+/*
+ * General Purpose functions for the global management of the
+ * Communication Processor Module.
+ *
+ * Copyright (c) 2000 Michael Leslie <mleslie@lineo.com>
+ * Copyright (c) 1997 Dan Malek (dmalek@jlc.net)
+ *
+ * In addition to the individual control of the communication
+ * channels, there are a few functions that globally affect the
+ * communication processor.
+ *
+ * Buffer descriptors must be allocated from the dual ported memory
+ * space.  The allocator for that is here.  When the communication
+ * process is reset, we reclaim the memory available.  There is
+ * currently no deallocator for this memory.
+ * The amount of space available is platform dependent.  On the
+ * MBX, the EPPC software loads additional microcode into the
+ * communication processor, and uses some of the DP ram for this
+ * purpose.  Current, the first 512 bytes and the last 256 bytes of
+ * memory are used.  Right now I am conservative and only use the
+ * memory that can never be used for microcode.  If there are
+ * applications that require more DP ram, we can expand the boundaries
+ * but then we have to be careful of any downloaded microcode.
+ *
+ */
+
+/*
+ * Michael Leslie <mleslie@lineo.com>
+ * adapted Dan Malek's ppc8xx drivers to M68360
+ *
+ */
+
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/param.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <asm/irq.h>
+#include <asm/m68360.h>
+#include <asm/commproc.h>
+
+/* #include <asm/page.h> */
+/* #include <asm/pgtable.h> */
+extern void *_quicc_base;
+extern unsigned int system_clock;
+
+
+static uint dp_alloc_base;     /* Starting offset in DP ram */
+static uint dp_alloc_top;      /* Max offset + 1 */
+
+#if 0
+static void    *host_buffer;   /* One page of host buffer */
+static void    *host_end;          /* end + 1 */
+#endif
+
+/* struct  cpm360_t *cpmp; */         /* Pointer to comm processor space */
+
+QUICC  *pquicc;
+/* QUICC  *quicc_dpram; */ /* mleslie - temporary; use extern pquicc elsewhere instead */
+
+
+/* CPM interrupt vector functions. */
+struct cpm_action {
+       void    (*handler)(void *);
+       void    *dev_id;
+};
+static struct  cpm_action cpm_vecs[CPMVEC_NR];
+static void    cpm_interrupt(int irq, void * dev, struct pt_regs * regs);
+static void    cpm_error_interrupt(void *);
+
+/* prototypes: */
+void cpm_install_handler(int vec, void (*handler)(), void *dev_id);
+void m360_cpm_reset(void);
+
+
+
+
+void __init m360_cpm_reset()
+{
+/*     pte_t              *pte; */
+
+       pquicc = (struct quicc *)(_quicc_base); /* initialized in crt0_rXm.S */
+
+       /* Perform a CPM reset. */
+       pquicc->cp_cr = (SOFTWARE_RESET | CMD_FLAG);
+
+       /* Wait for CPM to become ready (should be 2 clocks). */
+       while (pquicc->cp_cr & CMD_FLAG);
+
+       /* On the recommendation of the 68360 manual, p. 7-60
+        * - Set sdma interrupt service mask to 7
+        * - Set sdma arbitration ID to 4
+        */
+       pquicc->sdma_sdcr = 0x0740;
+
+
+       /* Claim the DP memory for our use.
+        */
+       dp_alloc_base = CPM_DATAONLY_BASE;
+       dp_alloc_top = dp_alloc_base + CPM_DATAONLY_SIZE;
+
+
+       /* Set the host page for allocation.
+        */
+       /*      host_buffer = host_page_addr; */
+       /*      host_end = host_page_addr + PAGE_SIZE; */
+
+       /*      pte = find_pte(&init_mm, host_page_addr); */
+       /*      pte_val(*pte) |= _PAGE_NO_CACHE; */
+       /*      flush_tlb_page(current->mm->mmap, host_buffer); */
+
+       /* Tell everyone where the comm processor resides.
+       */
+/*     cpmp = (cpm360_t *)commproc; */
+}
+
+
+/* This is called during init_IRQ.  We used to do it above, but this
+ * was too early since init_IRQ was not yet called.
+ */
+void
+cpm_interrupt_init(void)
+{
+       /* Initialize the CPM interrupt controller.
+        * NOTE THAT pquicc had better have been initialized!
+        * reference: MC68360UM p. 7-377
+        */
+       pquicc->intr_cicr =
+               (CICR_SCD_SCC4 | CICR_SCC_SCC3 | CICR_SCB_SCC2 | CICR_SCA_SCC1) |
+               (CPM_INTERRUPT << 13) |
+               CICR_HP_MASK |
+               (CPM_VECTOR_BASE << 5) |
+               CICR_SPS;
+
+       /* mask all CPM interrupts from reaching the cpu32 core: */
+       pquicc->intr_cimr = 0;
+
+
+       /* mles - If I understand correctly, the 360 just pops over to the CPM
+        * specific vector, obviating the necessity to vector through the IRQ
+        * whose priority the CPM is set to. This needs a closer look, though.
+        */
+
+       /* Set our interrupt handler with the core CPU. */
+/*     if (request_irq(CPM_INTERRUPT, cpm_interrupt, 0, "cpm", NULL) != 0) */
+/*             panic("Could not allocate CPM IRQ!"); */
+
+       /* Install our own error handler.
+        */
+       /* I think we want to hold off on this one for the moment - mles */
+       /* cpm_install_handler(CPMVEC_ERROR, cpm_error_interrupt, NULL); */
+
+       /* master CPM interrupt enable */
+       /* pquicc->intr_cicr |= CICR_IEN; */ /* no such animal for 360 */
+}
+
+
+
+/* CPM interrupt controller interrupt.
+*/
+static void
+cpm_interrupt(int irq, void * dev, struct pt_regs * regs)
+{
+       /* uint vec; */
+
+       /* mles: Note that this stuff is currently being performed by
+        * M68360_do_irq(int vec, struct pt_regs *fp), in ../ints.c  */
+
+       /* figure out the vector */
+       /* call that vector's handler */
+       /* clear the irq's bit in the service register */
+
+#if 0 /* old 860 stuff: */
+       /* Get the vector by setting the ACK bit and then reading
+        * the register.
+        */
+       ((volatile immap_t *)IMAP_ADDR)->im_cpic.cpic_civr = 1;
+       vec = ((volatile immap_t *)IMAP_ADDR)->im_cpic.cpic_civr;
+       vec >>= 11;
+
+
+       if (cpm_vecs[vec].handler != 0)
+               (*cpm_vecs[vec].handler)(cpm_vecs[vec].dev_id);
+       else
+               ((immap_t *)IMAP_ADDR)->im_cpic.cpic_cimr &= ~(1 << vec);
+
+       /* After servicing the interrupt, we have to remove the status
+        * indicator.
+        */
+       ((immap_t *)IMAP_ADDR)->im_cpic.cpic_cisr |= (1 << vec);
+#endif
+
+}
+
+/* The CPM can generate the error interrupt when there is a race condition
+ * between generating and masking interrupts.  All we have to do is ACK it
+ * and return.  This is a no-op function so we don't need any special
+ * tests in the interrupt handler.
+ */
+static void
+cpm_error_interrupt(void *dev)
+{
+}
+
+/* Install a CPM interrupt handler.
+*/
+void
+cpm_install_handler(int vec, void (*handler)(), void *dev_id)
+{
+
+       request_irq(vec, handler, 0, "timer", dev_id);
+
+/*     if (cpm_vecs[vec].handler != 0) */
+/*             printk(KERN_INFO "CPM interrupt %x replacing %x\n", */
+/*                     (uint)handler, (uint)cpm_vecs[vec].handler); */
+/*     cpm_vecs[vec].handler = handler; */
+/*     cpm_vecs[vec].dev_id = dev_id; */
+
+       /*              ((immap_t *)IMAP_ADDR)->im_cpic.cpic_cimr |= (1 << vec); */
+/*     pquicc->intr_cimr |= (1 << vec); */
+
+}
+
+/* Free a CPM interrupt handler.
+*/
+void
+cpm_free_handler(int vec)
+{
+       cpm_vecs[vec].handler = NULL;
+       cpm_vecs[vec].dev_id = NULL;
+       /* ((immap_t *)IMAP_ADDR)->im_cpic.cpic_cimr &= ~(1 << vec); */
+       pquicc->intr_cimr &= ~(1 << vec);
+}
+
+
+
+
+/* Allocate some memory from the dual ported ram.  We may want to
+ * enforce alignment restrictions, but right now everyone is a good
+ * citizen.
+ */
+uint
+m360_cpm_dpalloc(uint size)
+{
+        uint    retloc;
+
+        if ((dp_alloc_base + size) >= dp_alloc_top)
+                return(CPM_DP_NOSPACE);
+
+        retloc = dp_alloc_base;
+        dp_alloc_base += size;
+
+        return(retloc);
+}
+
+
+#if 0 /* mleslie - for now these are simply kmalloc'd */
+/* We also own one page of host buffer space for the allocation of
+ * UART "fifos" and the like.
+ */
+uint
+m360_cpm_hostalloc(uint size)
+{
+       uint    retloc;
+
+       if ((host_buffer + size) >= host_end)
+               return(0);
+
+       retloc = host_buffer;
+       host_buffer += size;
+
+       return(retloc);
+}
+#endif
+
+
+/* Set a baud rate generator.  This needs lots of work.  There are
+ * four BRGs, any of which can be wired to any channel.
+ * The internal baud rate clock is the system clock divided by 16.
+ * This assumes the baudrate is 16x oversampled by the uart.
+ */
+/* #define BRG_INT_CLK (((bd_t *)__res)->bi_intfreq * 1000000) */
+#define BRG_INT_CLK            system_clock
+#define BRG_UART_CLK   (BRG_INT_CLK/16)
+
+void
+m360_cpm_setbrg(uint brg, uint rate)
+{
+       volatile uint   *bp;
+
+       /* This is good enough to get SMCs running.....
+        */
+       /* bp = (uint *)&cpmp->cp_brgc1; */
+       bp = (volatile uint *)(&pquicc->brgc[0].l);
+       bp += brg;
+       *bp = ((BRG_UART_CLK / rate - 1) << 1) | CPM_BRG_EN;
+}
+
+
+/*
+ * Local variables:
+ *  c-indent-level: 4
+ *  c-basic-offset: 4
+ *  tab-width: 4
+ * End:
+ */
diff --git a/arch/m68k/68360/config.c b/arch/m68k/68360/config.c
new file mode 100644 (file)
index 0000000..17ec416
--- /dev/null
@@ -0,0 +1,183 @@
+/*
+ *  config.c - non-mmu 68360 platform initialization code
+ *
+ *  Copyright (c) 2000 Michael Leslie <mleslie@lineo.com>
+ *  Copyright (C) 1993 Hamish Macdonald
+ *  Copyright (C) 1999 D. Jeff Dionne <jeff@uclinux.org>
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file COPYING in the main directory of this archive
+ * for more details.
+ */
+
+#include <stdarg.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+
+#include <asm/setup.h>
+#include <asm/pgtable.h>
+#include <asm/machdep.h>
+#include <asm/m68360.h>
+
+#ifdef CONFIG_UCQUICC
+#include <asm/bootstd.h>
+#endif
+
+extern void m360_cpm_reset(void);
+
+// Mask to select if the PLL prescaler is enabled.
+#define MCU_PREEN   ((unsigned short)(0x0001 << 13))
+
+#if defined(CONFIG_UCQUICC)
+#define OSCILLATOR  (unsigned long int)33000000
+#endif
+
+static irq_handler_t timer_interrupt;
+unsigned long int system_clock;
+
+extern QUICC *pquicc;
+
+/* TODO  DON"T Hard Code this */
+/* calculate properly using the right PLL and prescaller */
+// unsigned int system_clock = 33000000l;
+extern unsigned long int system_clock; //In kernel setup.c
+
+
+static irqreturn_t hw_tick(int irq, void *dummy)
+{
+  /* Reset Timer1 */
+  /* TSTAT &= 0; */
+
+  pquicc->timer_ter1 = 0x0002; /* clear timer event */
+
+  return timer_interrupt(irq, dummy);
+}
+
+static struct irqaction m68360_timer_irq = {
+       .name    = "timer",
+       .flags   = IRQF_TIMER,
+       .handler = hw_tick,
+};
+
+void hw_timer_init(irq_handler_t handler)
+{
+  unsigned char prescaler;
+  unsigned short tgcr_save;
+
+#if 0
+  /* Restart mode, Enable int, 32KHz, Enable timer */
+  TCTL = TCTL_OM | TCTL_IRQEN | TCTL_CLKSOURCE_32KHZ | TCTL_TEN;
+  /* Set prescaler (Divide 32KHz by 32)*/
+  TPRER = 31;
+  /* Set compare register  32Khz / 32 / 10 = 100 */
+  TCMP = 10;                                                              
+
+  request_irq(IRQ_MACHSPEC | 1, timer_routine, 0, "timer", NULL);
+#endif
+
+  /* General purpose quicc timers: MC68360UM p7-20 */
+
+  /* Set up timer 1 (in [1..4]) to do 100Hz */
+  tgcr_save = pquicc->timer_tgcr & 0xfff0;
+  pquicc->timer_tgcr  = tgcr_save; /* stop and reset timer 1 */
+  /* pquicc->timer_tgcr |= 0x4444; */ /* halt timers when FREEZE (ie bdm freeze) */
+
+  prescaler = 8;
+  pquicc->timer_tmr1 = 0x001a | /* or=1, frr=1, iclk=01b */
+                           (unsigned short)((prescaler - 1) << 8);
+    
+  pquicc->timer_tcn1 = 0x0000; /* initial count */
+  /* calculate interval for 100Hz based on the _system_clock: */
+  pquicc->timer_trr1 = (system_clock/ prescaler) / HZ; /* reference count */
+
+  pquicc->timer_ter1 = 0x0003; /* clear timer events */
+
+  timer_interrupt = handler;
+
+  /* enable timer 1 interrupt in CIMR */
+  setup_irq(CPMVEC_TIMER1, &m68360_timer_irq);
+
+  /* Start timer 1: */
+  tgcr_save = (pquicc->timer_tgcr & 0xfff0) | 0x0001;
+  pquicc->timer_tgcr  = tgcr_save;
+}
+
+int BSP_set_clock_mmss(unsigned long nowtime)
+{
+#if 0
+  short real_seconds = nowtime % 60, real_minutes = (nowtime / 60) % 60;
+
+  tod->second1 = real_seconds / 10;
+  tod->second2 = real_seconds % 10;
+  tod->minute1 = real_minutes / 10;
+  tod->minute2 = real_minutes % 10;
+#endif
+  return 0;
+}
+
+void BSP_reset (void)
+{
+  local_irq_disable();
+  asm volatile (
+    "moveal #_start, %a0;\n"
+    "moveb #0, 0xFFFFF300;\n"
+    "moveal 0(%a0), %sp;\n"
+    "moveal 4(%a0), %a0;\n"
+    "jmp (%a0);\n"
+    );
+}
+
+unsigned char *scc1_hwaddr;
+static int errno;
+
+#if defined (CONFIG_UCQUICC)
+_bsc0(char *, getserialnum)
+_bsc1(unsigned char *, gethwaddr, int, a)
+_bsc1(char *, getbenv, char *, a)
+#endif
+
+
+void __init config_BSP(char *command, int len)
+{
+  unsigned char *p;
+
+  m360_cpm_reset();
+
+  /* Calculate the real system clock value. */
+  {
+     unsigned int local_pllcr = (unsigned int)(pquicc->sim_pllcr);
+     if( local_pllcr & MCU_PREEN ) // If the prescaler is dividing by 128
+     {
+         int mf = (int)(pquicc->sim_pllcr & 0x0fff);
+         system_clock = (OSCILLATOR / 128) * (mf + 1);
+     }
+     else
+     {
+         int mf = (int)(pquicc->sim_pllcr & 0x0fff);
+         system_clock = (OSCILLATOR) * (mf + 1);
+     }
+  }
+
+  printk(KERN_INFO "\n68360 QUICC support (C) 2000 Lineo Inc.\n");
+
+#if defined(CONFIG_UCQUICC) && 0
+  printk(KERN_INFO "uCquicc serial string [%s]\n",getserialnum());
+  p = scc1_hwaddr = gethwaddr(0);
+  printk(KERN_INFO "uCquicc hwaddr %.2x:%.2x:%.2x:%.2x:%.2x:%.2x\n",
+         p[0], p[1], p[2], p[3], p[4], p[5]);
+
+  p = getbenv("APPEND");
+  if (p)
+    strcpy(p,command);
+  else
+    command[0] = 0;
+#else
+  scc1_hwaddr = "\00\01\02\03\04\05";
+#endif
+  mach_reset = BSP_reset;
+}
diff --git a/arch/m68k/68360/entry.S b/arch/m68k/68360/entry.S
new file mode 100644 (file)
index 0000000..22eb302
--- /dev/null
@@ -0,0 +1,164 @@
+/*
+ *  entry.S - non-mmu 68360 interrupt and exceptions entry points
+ *
+ *  Copyright (C) 1991, 1992  Linus Torvalds
+ *  Copyright (C) 2001 SED Systems, a Division of Calian Ltd.
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file README.legal in the main directory of this archive
+ * for more details.
+ *
+ * Linux/m68k support by Hamish Macdonald
+ * M68360 Port by SED Systems, and Lineo.
+ */
+
+#include <linux/linkage.h>
+#include <asm/thread_info.h>
+#include <asm/unistd.h>
+#include <asm/errno.h>
+#include <asm/setup.h>
+#include <asm/segment.h>
+#include <asm/traps.h>
+#include <asm/asm-offsets.h>
+#include <asm/entry.h>
+
+.text
+
+.globl system_call
+.globl resume
+.globl ret_from_exception
+.globl ret_from_signal
+.globl sys_call_table
+.globl bad_interrupt
+.globl inthandler
+
+badsys:
+       movel   #-ENOSYS,%sp@(PT_OFF_D0)
+       jra     ret_from_exception
+
+do_trace:
+       movel   #-ENOSYS,%sp@(PT_OFF_D0) /* needed for strace*/
+       subql   #4,%sp
+       SAVE_SWITCH_STACK
+       jbsr    syscall_trace_enter
+       RESTORE_SWITCH_STACK
+       addql   #4,%sp
+       movel   %sp@(PT_OFF_ORIG_D0),%d1
+       movel   #-ENOSYS,%d0
+       cmpl    #NR_syscalls,%d1
+       jcc     1f
+       lsl     #2,%d1
+       lea     sys_call_table, %a0
+       jbsr    %a0@(%d1)
+
+1:     movel   %d0,%sp@(PT_OFF_D0)     /* save the return value */
+       subql   #4,%sp                  /* dummy return address */
+       SAVE_SWITCH_STACK
+       jbsr    syscall_trace_leave
+
+ret_from_signal:
+       RESTORE_SWITCH_STACK
+       addql   #4,%sp
+       jra     ret_from_exception
+
+ENTRY(system_call)
+       SAVE_ALL_SYS
+
+       /* save top of frame*/
+       pea     %sp@
+       jbsr    set_esp0
+       addql   #4,%sp
+
+       movel   %sp@(PT_OFF_ORIG_D0),%d0
+
+       movel   %sp,%d1                 /* get thread_info pointer */
+       andl    #-THREAD_SIZE,%d1
+       movel   %d1,%a2
+       btst    #(TIF_SYSCALL_TRACE%8),%a2@(TINFO_FLAGS+(31-TIF_SYSCALL_TRACE)/8)
+       jne     do_trace
+       cmpl    #NR_syscalls,%d0
+       jcc     badsys
+       lsl     #2,%d0
+       lea     sys_call_table,%a0
+       movel   %a0@(%d0), %a0
+       jbsr    %a0@
+       movel   %d0,%sp@(PT_OFF_D0)     /* save the return value*/
+
+ret_from_exception:
+       btst    #5,%sp@(PT_OFF_SR)      /* check if returning to kernel*/
+       jeq     Luser_return            /* if so, skip resched, signals*/
+
+Lkernel_return:
+       RESTORE_ALL
+
+Luser_return:
+       /* only allow interrupts when we are really the last one on the*/
+       /* kernel stack, otherwise stack overflow can occur during*/
+       /* heavy interrupt load*/
+       andw    #ALLOWINT,%sr
+
+       movel   %sp,%d1                 /* get thread_info pointer */
+       andl    #-THREAD_SIZE,%d1
+       movel   %d1,%a2
+1:
+       move    %a2@(TINFO_FLAGS),%d1   /* thread_info->flags */
+       jne     Lwork_to_do
+       RESTORE_ALL
+
+Lwork_to_do:
+       movel   %a2@(TINFO_FLAGS),%d1   /* thread_info->flags */
+       btst    #TIF_NEED_RESCHED,%d1
+       jne     reschedule
+
+Lsignal_return:
+       subql   #4,%sp                  /* dummy return address*/
+       SAVE_SWITCH_STACK
+       pea     %sp@(SWITCH_STACK_SIZE)
+       bsrw    do_notify_resume
+       addql   #4,%sp
+       RESTORE_SWITCH_STACK
+       addql   #4,%sp
+       jra     1b
+
+/*
+ * This is the main interrupt handler, responsible for calling do_IRQ()
+ */
+inthandler:
+       SAVE_ALL_INT
+       movew   %sp@(PT_OFF_FORMATVEC), %d0
+       and.l   #0x3ff, %d0
+       lsr.l   #0x02,  %d0
+
+       movel   %sp,%sp@-
+       movel   %d0,%sp@-               /*  put vector # on stack*/
+       jbsr    do_IRQ                  /*  process the IRQ */
+       addql   #8,%sp                  /*  pop parameters off stack*/
+       jra     ret_from_exception
+
+/*
+ * Handler for uninitialized and spurious interrupts.
+ */
+bad_interrupt:
+       addql   #1,irq_err_count
+       rte
+
+/*
+ * Beware - when entering resume, prev (the current task) is
+ * in a0, next (the new task) is in a1, so don't change these
+ * registers until their contents are no longer needed.
+ */
+ENTRY(resume)
+       movel   %a0,%d1                         /* save prev thread in d1 */
+       movew   %sr,%a0@(TASK_THREAD+THREAD_SR) /* save sr */
+       SAVE_SWITCH_STACK
+       movel   %sp,%a0@(TASK_THREAD+THREAD_KSP) /* save kernel stack */
+       movel   %usp,%a3                        /* save usp */
+       movel   %a3,%a0@(TASK_THREAD+THREAD_USP)
+
+       movel   %a1@(TASK_THREAD+THREAD_USP),%a3 /* restore user stack */
+       movel   %a3,%usp
+       movel   %a1@(TASK_THREAD+THREAD_KSP),%sp /* restore new thread stack */
+       RESTORE_SWITCH_STACK
+       movew   %a1@(TASK_THREAD+THREAD_SR),%sr /* restore thread status reg */
+       rts
+
diff --git a/arch/m68k/68360/head-ram.S b/arch/m68k/68360/head-ram.S
new file mode 100644 (file)
index 0000000..62bc56f
--- /dev/null
@@ -0,0 +1,402 @@
+/*
+ * head-ram.S - startup code for Motorola 68360
+ *
+ * Copyright 2001 (C) SED Systems, a Division of Calian Ltd.
+ * Based on: arch/m68knommu/platform/68328/pilot/crt0_rom.S
+ * Based on: arch/m68knommu/platform/68360/uCquicc/crt0_rom.S, 2.0.38.1.pre7
+ *           uClinux Kernel
+ * Copyright (C) Michael Leslie <mleslie@lineo.com>
+ * Based on: arch/m68knommu/platform/68EZ328/ucsimm/crt0_rom.S
+ * Copyright (C) 1998  D. Jeff Dionne <jeff@uclinux.org>,
+ *
+ */
+#define ASSEMBLY
+
+.global _stext
+.global _start
+
+.global _rambase
+.global _ramvec
+.global _ramstart
+.global _ramend
+
+.global _quicc_base
+.global _periph_base
+
+#define        RAMEND                      (CONFIG_RAMBASE + CONFIG_RAMSIZE)
+#define        ROMEND                      (CONFIG_ROMBASE + CONFIG_ROMSIZE)
+
+#define REGB                        0x1000
+#define PEPAR                       (_dprbase + REGB + 0x0016)
+#define GMR                         (_dprbase + REGB + 0x0040)
+#define OR0                         (_dprbase + REGB + 0x0054)
+#define BR0                         (_dprbase + REGB + 0x0050)
+#define OR1                         (_dprbase + REGB + 0x0064)
+#define BR1                         (_dprbase + REGB + 0x0060)
+#define OR4                         (_dprbase + REGB + 0x0094)
+#define BR4                         (_dprbase + REGB + 0x0090)
+#define OR6                         (_dprbase + REGB + 0x00b4)
+#define BR6                         (_dprbase + REGB + 0x00b0)
+#define OR7                         (_dprbase + REGB + 0x00c4)
+#define BR7                         (_dprbase + REGB + 0x00c0)
+
+#define MCR                         (_dprbase + REGB + 0x0000)
+#define AVR                         (_dprbase + REGB + 0x0008)
+
+#define SYPCR                       (_dprbase + REGB + 0x0022)
+
+#define PLLCR                       (_dprbase + REGB + 0x0010)
+#define CLKOCR                      (_dprbase + REGB + 0x000C)
+#define CDVCR                       (_dprbase + REGB + 0x0014)
+
+#define BKAR                        (_dprbase + REGB + 0x0030)
+#define BKCR                        (_dprbase + REGB + 0x0034)
+#define SWIV                        (_dprbase + REGB + 0x0023)
+#define PICR                        (_dprbase + REGB + 0x0026)
+#define PITR                        (_dprbase + REGB + 0x002A)
+
+/* Define for all memory configuration */
+#define MCU_SIM_GMR                 0x00000000
+#define SIM_OR_MASK                 0x0fffffff
+
+/* Defines for chip select zero - the flash */
+#define SIM_OR0_MASK                0x20000002
+#define SIM_BR0_MASK                0x00000001
+
+
+/* Defines for chip select one - the RAM */
+#define SIM_OR1_MASK                0x10000000
+#define SIM_BR1_MASK                0x00000001
+
+#define MCU_SIM_MBAR_ADRS           0x0003ff00
+#define MCU_SIM_MBAR_BA_MASK        0xfffff000
+#define MCU_SIM_MBAR_AS_MASK        0x00000001
+
+#define MCU_SIM_PEPAR               0x00B4
+    
+#define MCU_DISABLE_INTRPTS         0x2700
+#define MCU_SIM_AVR                 0x00
+    
+#define MCU_SIM_MCR                 0x00005cff
+
+#define MCU_SIM_CLKOCR              0x00
+#define MCU_SIM_PLLCR               0x8000
+#define MCU_SIM_CDVCR               0x0000
+
+#define MCU_SIM_SYPCR               0x0000
+#define MCU_SIM_SWIV                0x00
+#define MCU_SIM_PICR                0x0000
+#define MCU_SIM_PITR                0x0000
+
+
+#include <asm/m68360_regs.h>
+
+       
+/*
+ * By the time this RAM specific code begins to execute, DPRAM
+ * and DRAM should already be mapped and accessible.
+ */
+
+       .text
+_start:
+_stext:
+       nop
+       ori.w   #MCU_DISABLE_INTRPTS, %sr       /* disable interrupts: */
+       /* We should not need to setup the boot stack the reset should do it. */
+       movea.l #RAMEND, %sp                    /*set up stack at the end of DRAM:*/
+
+set_mbar_register:
+       moveq.l #0x07, %d1                      /* Setup MBAR */
+       movec   %d1, %dfc
+
+       lea.l   MCU_SIM_MBAR_ADRS, %a0
+       move.l  #_dprbase, %d0
+       andi.l  #MCU_SIM_MBAR_BA_MASK, %d0
+       ori.l   #MCU_SIM_MBAR_AS_MASK, %d0
+       moves.l %d0, %a0@
+
+       moveq.l #0x05, %d1
+       movec.l %d1, %dfc
+
+       /* Now we can begin to access registers in DPRAM */
+
+set_sim_mcr:
+       /* Set Module Configuration Register */
+       move.l  #MCU_SIM_MCR, MCR
+
+       /* to do:       Determine cause of reset */
+
+       /*
+        *       configure system clock MC68360 p. 6-40
+        *       (value +1)*osc/128 = system clock
+        */
+set_sim_clock:
+       move.w  #MCU_SIM_PLLCR, PLLCR
+       move.b  #MCU_SIM_CLKOCR, CLKOCR
+       move.w  #MCU_SIM_CDVCR, CDVCR
+
+       /* Wait for the PLL to settle */
+       move.w  #16384, %d0
+pll_settle_wait:
+       subi.w  #1, %d0
+       bne     pll_settle_wait
+
+       /* Setup the system protection register, and watchdog timer register */
+       move.b  #MCU_SIM_SWIV, SWIV
+       move.w  #MCU_SIM_PICR, PICR
+       move.w  #MCU_SIM_PITR, PITR
+       move.w  #MCU_SIM_SYPCR, SYPCR
+
+       /* Clear DPRAM - system + parameter */
+       movea.l #_dprbase, %a0
+       movea.l #_dprbase+0x2000, %a1
+
+       /* Copy 0 to %a0 until %a0 == %a1 */
+clear_dpram:
+       movel   #0, %a0@+
+       cmpal   %a0, %a1
+       bhi     clear_dpram
+
+configure_memory_controller:    
+       /* Set up Global Memory Register (GMR) */
+       move.l  #MCU_SIM_GMR, %d0
+       move.l  %d0, GMR
+
+configure_chip_select_0:
+       move.l  #RAMEND, %d0
+       subi.l  #__ramstart, %d0
+       subq.l  #0x01, %d0
+       eori.l  #SIM_OR_MASK, %d0
+       ori.l   #SIM_OR0_MASK, %d0
+       move.l  %d0, OR0
+
+       move.l  #__ramstart, %d0
+       ori.l   #SIM_BR0_MASK, %d0
+       move.l  %d0, BR0
+
+configure_chip_select_1:
+       move.l  #ROMEND, %d0
+       subi.l  #__rom_start, %d0
+       subq.l  #0x01, %d0
+       eori.l  #SIM_OR_MASK, %d0
+       ori.l   #SIM_OR1_MASK, %d0
+       move.l  %d0, OR1
+
+       move.l  #__rom_start, %d0
+       ori.l   #SIM_BR1_MASK, %d0
+       move.l  %d0, BR1
+
+       move.w  #MCU_SIM_PEPAR, PEPAR 
+
+       /* point to vector table: */
+       move.l  #_romvec, %a0
+       move.l  #_ramvec, %a1
+copy_vectors:
+       move.l  %a0@, %d0
+       move.l  %d0, %a1@
+       move.l  %a0@, %a1@
+       addq.l  #0x04, %a0
+       addq.l  #0x04, %a1
+       cmp.l   #_start, %a0
+       blt     copy_vectors
+
+       move.l  #_ramvec, %a1
+       movec   %a1, %vbr
+
+
+       /* Copy data segment from ROM to RAM */
+       moveal  #_stext, %a0
+       moveal  #_sdata, %a1
+       moveal  #_edata, %a2
+
+       /* Copy %a0 to %a1 until %a1 == %a2 */
+LD1:
+       move.l  %a0@, %d0
+       addq.l  #0x04, %a0
+       move.l  %d0, %a1@
+       addq.l  #0x04, %a1
+       cmp.l   #_edata, %a1
+       blt     LD1
+
+       moveal  #__bss_start, %a0
+       moveal  #__bss_stop, %a1
+
+       /* Copy 0 to %a0 until %a0 == %a1 */
+L1:
+       movel   #0, %a0@+
+       cmpal   %a0, %a1
+       bhi     L1
+
+load_quicc:
+       move.l  #_dprbase, _quicc_base
+
+store_ram_size:
+       /* Set ram size information */
+       move.l  #_sdata, _rambase
+       move.l  #__bss_stop, _ramstart
+       move.l  #RAMEND, %d0
+       sub.l   #0x1000, %d0                    /* Reserve 4K for stack space.*/
+       move.l  %d0, _ramend                    /* Different from RAMEND.*/
+
+       pea     0
+       pea     env
+       pea     %sp@(4)
+       pea     0
+
+       lea     init_thread_union, %a2
+       lea     0x2000(%a2), %sp
+
+lp:
+       jsr     start_kernel
+
+_exit:
+       jmp     _exit
+
+
+       .data
+       .align 4
+env:
+       .long   0
+_quicc_base:
+       .long   0
+_periph_base:
+       .long   0
+_ramvec:
+       .long   0
+_rambase:
+       .long   0
+_ramstart:
+       .long   0
+_ramend:
+       .long   0
+_dprbase:
+       .long   0xffffe000
+
+       .text
+
+    /*
+     * These are the exception vectors at boot up, they are copied into RAM
+     * and then overwritten as needed.
+     */
+.section ".data..initvect","awx"
+    .long   RAMEND     /* Reset: Initial Stack Pointer                 - 0.  */
+    .long   _start      /* Reset: Initial Program Counter               - 1.  */
+    .long   buserr      /* Bus Error                                    - 2.  */
+    .long   trap        /* Address Error                                - 3.  */
+    .long   trap        /* Illegal Instruction                          - 4.  */
+    .long   trap        /* Divide by zero                               - 5.  */
+    .long   trap        /* CHK, CHK2 Instructions                       - 6.  */
+    .long   trap        /* TRAPcc, TRAPV Instructions                   - 7.  */
+    .long   trap        /* Privilege Violation                          - 8.  */
+    .long   trap        /* Trace                                        - 9.  */
+    .long   trap        /* Line 1010 Emulator                           - 10. */
+    .long   trap        /* Line 1111 Emualtor                           - 11. */
+    .long   trap        /* Harware Breakpoint                           - 12. */
+    .long   trap        /* (Reserved for Coprocessor Protocol Violation)- 13. */
+    .long   trap        /* Format Error                                 - 14. */
+    .long   trap        /* Uninitialized Interrupt                      - 15. */
+    .long   trap        /* (Unassigned, Reserver)                       - 16. */
+    .long   trap        /* (Unassigned, Reserver)                       - 17. */
+    .long   trap        /* (Unassigned, Reserver)                       - 18. */
+    .long   trap        /* (Unassigned, Reserver)                       - 19. */
+    .long   trap        /* (Unassigned, Reserver)                       - 20. */
+    .long   trap        /* (Unassigned, Reserver)                       - 21. */
+    .long   trap        /* (Unassigned, Reserver)                       - 22. */
+    .long   trap        /* (Unassigned, Reserver)                       - 23. */
+    .long   trap        /* Spurious Interrupt                           - 24. */
+    .long   trap        /* Level 1 Interrupt Autovector                 - 25. */
+    .long   trap        /* Level 2 Interrupt Autovector                 - 26. */
+    .long   trap        /* Level 3 Interrupt Autovector                 - 27. */
+    .long   trap        /* Level 4 Interrupt Autovector                 - 28. */
+    .long   trap        /* Level 5 Interrupt Autovector                 - 29. */
+    .long   trap        /* Level 6 Interrupt Autovector                 - 30. */
+    .long   trap        /* Level 7 Interrupt Autovector                 - 31. */
+    .long   system_call /* Trap Instruction Vectors 0                   - 32. */
+    .long   trap        /* Trap Instruction Vectors 1                   - 33. */
+    .long   trap        /* Trap Instruction Vectors 2                   - 34. */
+    .long   trap        /* Trap Instruction Vectors 3                   - 35. */
+    .long   trap        /* Trap Instruction Vectors 4                   - 36. */
+    .long   trap        /* Trap Instruction Vectors 5                   - 37. */
+    .long   trap        /* Trap Instruction Vectors 6                   - 38. */
+    .long   trap        /* Trap Instruction Vectors 7                   - 39. */
+    .long   trap        /* Trap Instruction Vectors 8                   - 40. */
+    .long   trap        /* Trap Instruction Vectors 9                   - 41. */
+    .long   trap        /* Trap Instruction Vectors 10                  - 42. */
+    .long   trap        /* Trap Instruction Vectors 11                  - 43. */
+    .long   trap        /* Trap Instruction Vectors 12                  - 44. */
+    .long   trap        /* Trap Instruction Vectors 13                  - 45. */
+    .long   trap        /* Trap Instruction Vectors 14                  - 46. */
+    .long   trap        /* Trap Instruction Vectors 15                  - 47. */
+    .long   0           /* (Reserved for Coprocessor)                   - 48. */
+    .long   0           /* (Reserved for Coprocessor)                   - 49. */
+    .long   0           /* (Reserved for Coprocessor)                   - 50. */
+    .long   0           /* (Reserved for Coprocessor)                   - 51. */
+    .long   0           /* (Reserved for Coprocessor)                   - 52. */
+    .long   0           /* (Reserved for Coprocessor)                   - 53. */
+    .long   0           /* (Reserved for Coprocessor)                   - 54. */
+    .long   0           /* (Reserved for Coprocessor)                   - 55. */
+    .long   0           /* (Reserved for Coprocessor)                   - 56. */
+    .long   0           /* (Reserved for Coprocessor)                   - 57. */
+    .long   0           /* (Reserved for Coprocessor)                   - 58. */
+    .long   0           /* (Unassigned, Reserved)                       - 59. */
+    .long   0           /* (Unassigned, Reserved)                       - 60. */
+    .long   0           /* (Unassigned, Reserved)                       - 61. */
+    .long   0           /* (Unassigned, Reserved)                       - 62. */
+    .long   0           /* (Unassigned, Reserved)                       - 63. */
+    /*                  The assignment of these vectors to the CPM is         */
+    /*                  dependent on the configuration of the CPM vba         */
+    /*                          fields.                                       */
+    .long   0           /* (User-Defined Vectors 1) CPM Error           - 64. */
+    .long   0           /* (User-Defined Vectors 2) CPM Parallel IO PC11- 65. */
+    .long   0           /* (User-Defined Vectors 3) CPM Parallel IO PC10- 66. */
+    .long   0           /* (User-Defined Vectors 4) CPM SMC2 / PIP      - 67. */
+    .long   0           /* (User-Defined Vectors 5) CPM SMC1            - 68. */
+    .long   0           /* (User-Defined Vectors 6) CPM SPI             - 69. */
+    .long   0           /* (User-Defined Vectors 7) CPM Parallel IO PC9 - 70. */
+    .long   0           /* (User-Defined Vectors 8) CPM Timer 4         - 71. */
+    .long   0           /* (User-Defined Vectors 9) CPM Reserved        - 72. */
+    .long   0           /* (User-Defined Vectors 10) CPM Parallel IO PC8- 73. */
+    .long   0           /* (User-Defined Vectors 11) CPM Parallel IO PC7- 74. */
+    .long   0           /* (User-Defined Vectors 12) CPM Parallel IO PC6- 75. */
+    .long   0           /* (User-Defined Vectors 13) CPM Timer 3        - 76. */
+    .long   0           /* (User-Defined Vectors 14) CPM Reserved       - 77. */
+    .long   0           /* (User-Defined Vectors 15) CPM Parallel IO PC5- 78. */
+    .long   0           /* (User-Defined Vectors 16) CPM Parallel IO PC4- 79. */
+    .long   0           /* (User-Defined Vectors 17) CPM Reserved       - 80. */
+    .long   0           /* (User-Defined Vectors 18) CPM RISC Timer Tbl - 81. */
+    .long   0           /* (User-Defined Vectors 19) CPM Timer 2        - 82. */
+    .long   0           /* (User-Defined Vectors 21) CPM Reserved       - 83. */
+    .long   0           /* (User-Defined Vectors 22) CPM IDMA2          - 84. */
+    .long   0           /* (User-Defined Vectors 23) CPM IDMA1          - 85. */
+    .long   0           /* (User-Defined Vectors 24) CPM SDMA Bus Err   - 86. */
+    .long   0           /* (User-Defined Vectors 25) CPM Parallel IO PC3- 87. */
+    .long   0           /* (User-Defined Vectors 26) CPM Parallel IO PC2- 88. */
+    .long   0           /* (User-Defined Vectors 27) CPM Timer 1        - 89. */
+    .long   0           /* (User-Defined Vectors 28) CPM Parallel IO PC1- 90. */
+    .long   0           /* (User-Defined Vectors 29) CPM SCC 4          - 91. */
+    .long   0           /* (User-Defined Vectors 30) CPM SCC 3          - 92. */
+    .long   0           /* (User-Defined Vectors 31) CPM SCC 2          - 93. */
+    .long   0           /* (User-Defined Vectors 32) CPM SCC 1          - 94. */
+    .long   0           /* (User-Defined Vectors 33) CPM Parallel IO PC0- 95. */
+    /*                  I don't think anything uses the vectors after here.   */
+    .long   0           /* (User-Defined Vectors 34)                    - 96. */
+    .long   0,0,0,0,0               /* (User-Defined Vectors 35  -  39). */
+    .long   0,0,0,0,0,0,0,0,0,0     /* (User-Defined Vectors 40  -  49). */
+    .long   0,0,0,0,0,0,0,0,0,0     /* (User-Defined Vectors 50  -  59). */
+    .long   0,0,0,0,0,0,0,0,0,0     /* (User-Defined Vectors 60  -  69). */
+    .long   0,0,0,0,0,0,0,0,0,0     /* (User-Defined Vectors 70  -  79). */
+    .long   0,0,0,0,0,0,0,0,0,0     /* (User-Defined Vectors 80  -  89). */
+    .long   0,0,0,0,0,0,0,0,0,0     /* (User-Defined Vectors 90  -  99). */
+    .long   0,0,0,0,0,0,0,0,0,0     /* (User-Defined Vectors 100 - 109). */
+    .long   0,0,0,0,0,0,0,0,0,0     /* (User-Defined Vectors 110 - 119). */
+    .long   0,0,0,0,0,0,0,0,0,0     /* (User-Defined Vectors 120 - 129). */
+    .long   0,0,0,0,0,0,0,0,0,0     /* (User-Defined Vectors 130 - 139). */
+    .long   0,0,0,0,0,0,0,0,0,0     /* (User-Defined Vectors 140 - 149). */
+    .long   0,0,0,0,0,0,0,0,0,0     /* (User-Defined Vectors 150 - 159). */
+    .long   0,0,0,0,0,0,0,0,0,0     /* (User-Defined Vectors 160 - 169). */
+    .long   0,0,0,0,0,0,0,0,0,0     /* (User-Defined Vectors 170 - 179). */
+    .long   0,0,0,0,0,0,0,0,0,0     /* (User-Defined Vectors 180 - 189). */
+    .long   0,0,0                   /* (User-Defined Vectors 190 - 192). */
+.text
+ignore: rte
diff --git a/arch/m68k/68360/head-rom.S b/arch/m68k/68360/head-rom.S
new file mode 100644 (file)
index 0000000..b3a7e40
--- /dev/null
@@ -0,0 +1,413 @@
+/*
+ * head-rom.S - startup code for Motorola 68360
+ *
+ * Copyright (C) SED Systems, a Division of Calian Ltd.
+ * Based on: arch/m68knommu/platform/68328/pilot/crt0_rom.S
+ * Based on: arch/m68knommu/platform/68360/uCquicc/crt0_rom.S, 2.0.38.1.pre7
+ *           uClinux Kernel
+ * Copyright (C) Michael Leslie <mleslie@lineo.com>
+ * Based on: arch/m68knommu/platform/68EZ328/ucsimm/crt0_rom.S
+ * Copyright (C) 1998  D. Jeff Dionne <jeff@uclinux.org>,
+ *
+ */
+
+.global _stext
+.global __bss_start
+.global _start
+
+.global _rambase
+.global _ramvec
+.global _ramstart
+.global _ramend
+
+.global _quicc_base
+.global _periph_base
+
+#define        RAMEND                      (CONFIG_RAMBASE + CONFIG_RAMSIZE)
+
+#define REGB                        0x1000
+#define PEPAR                       (_dprbase + REGB + 0x0016)
+#define GMR                         (_dprbase + REGB + 0x0040)
+#define OR0                         (_dprbase + REGB + 0x0054)
+#define BR0                         (_dprbase + REGB + 0x0050)
+
+#define OR1                         (_dprbase + REGB + 0x0064)
+#define BR1                         (_dprbase + REGB + 0x0060)
+
+#define OR2                         (_dprbase + REGB + 0x0074)
+#define BR2                         (_dprbase + REGB + 0x0070)
+
+#define OR3                         (_dprbase + REGB + 0x0084)
+#define BR3                         (_dprbase + REGB + 0x0080)
+
+#define OR4                         (_dprbase + REGB + 0x0094)
+#define BR4                         (_dprbase + REGB + 0x0090)
+
+#define OR5                         (_dprbase + REGB + 0x00A4)
+#define BR5                         (_dprbase + REGB + 0x00A0)
+
+#define OR6                         (_dprbase + REGB + 0x00b4)
+#define BR6                         (_dprbase + REGB + 0x00b0)
+
+#define OR7                         (_dprbase + REGB + 0x00c4)
+#define BR7                         (_dprbase + REGB + 0x00c0)
+
+#define MCR                         (_dprbase + REGB + 0x0000)
+#define AVR                         (_dprbase + REGB + 0x0008)
+
+#define SYPCR                       (_dprbase + REGB + 0x0022)
+
+#define PLLCR                       (_dprbase + REGB + 0x0010)
+#define CLKOCR                      (_dprbase + REGB + 0x000C)
+#define CDVCR                       (_dprbase + REGB + 0x0014)
+
+#define BKAR                        (_dprbase + REGB + 0x0030)
+#define BKCR                        (_dprbase + REGB + 0x0034)
+#define SWIV                        (_dprbase + REGB + 0x0023)
+#define PICR                        (_dprbase + REGB + 0x0026)
+#define PITR                        (_dprbase + REGB + 0x002A)
+
+/* Define for all memory configuration */
+#define MCU_SIM_GMR                 0x00000000
+#define SIM_OR_MASK                 0x0fffffff
+
+/* Defines for chip select zero - the flash */
+#define SIM_OR0_MASK                0x20000000
+#define SIM_BR0_MASK                0x00000001
+
+/* Defines for chip select one - the RAM */
+#define SIM_OR1_MASK                0x10000000
+#define SIM_BR1_MASK                0x00000001
+
+#define MCU_SIM_MBAR_ADRS           0x0003ff00
+#define MCU_SIM_MBAR_BA_MASK        0xfffff000
+#define MCU_SIM_MBAR_AS_MASK        0x00000001
+
+#define MCU_SIM_PEPAR               0x00B4
+    
+#define MCU_DISABLE_INTRPTS         0x2700
+#define MCU_SIM_AVR                 0x00
+    
+#define MCU_SIM_MCR                 0x00005cff
+
+#define MCU_SIM_CLKOCR              0x00
+#define MCU_SIM_PLLCR               0x8000
+#define MCU_SIM_CDVCR               0x0000
+
+#define MCU_SIM_SYPCR               0x0000
+#define MCU_SIM_SWIV                0x00
+#define MCU_SIM_PICR                0x0000
+#define MCU_SIM_PITR                0x0000
+
+
+#include <asm/m68360_regs.h>
+
+       
+/*
+ * By the time this RAM specific code begins to execute, DPRAM
+ * and DRAM should already be mapped and accessible.
+ */
+
+       .text
+_start:
+_stext:
+       nop
+       ori.w   #MCU_DISABLE_INTRPTS, %sr       /* disable interrupts: */
+       /* We should not need to setup the boot stack the reset should do it. */
+       movea.l #RAMEND, %sp            /* set up stack at the end of DRAM:*/
+
+
+set_mbar_register:
+       moveq.l #0x07, %d1                      /* Setup MBAR */
+       movec   %d1, %dfc
+
+       lea.l   MCU_SIM_MBAR_ADRS, %a0
+       move.l  #_dprbase, %d0
+       andi.l  #MCU_SIM_MBAR_BA_MASK, %d0
+       ori.l   #MCU_SIM_MBAR_AS_MASK, %d0
+       moves.l %d0, %a0@
+
+       moveq.l #0x05, %d1
+       movec.l %d1, %dfc
+
+       /* Now we can begin to access registers in DPRAM */
+
+set_sim_mcr:
+       /* Set Module Configuration Register */
+       move.l  #MCU_SIM_MCR, MCR
+
+       /* to do:       Determine cause of reset */
+
+       /*
+        *      configure system clock MC68360 p. 6-40
+        *      (value +1)*osc/128 = system clock
+        *                    or
+        *      (value + 1)*osc = system clock
+        *      You do not need to divide the oscillator by 128 unless you want to.
+        */
+set_sim_clock:
+       move.w  #MCU_SIM_PLLCR, PLLCR
+       move.b  #MCU_SIM_CLKOCR, CLKOCR
+       move.w  #MCU_SIM_CDVCR, CDVCR
+
+       /* Wait for the PLL to settle */
+       move.w  #16384, %d0
+pll_settle_wait:
+       subi.w  #1, %d0
+       bne     pll_settle_wait
+
+       /* Setup the system protection register, and watchdog timer register */
+       move.b  #MCU_SIM_SWIV, SWIV
+       move.w  #MCU_SIM_PICR, PICR
+       move.w  #MCU_SIM_PITR, PITR
+       move.w  #MCU_SIM_SYPCR, SYPCR
+
+       /* Clear DPRAM - system + parameter */
+       movea.l #_dprbase, %a0
+       movea.l #_dprbase+0x2000, %a1
+
+       /* Copy 0 to %a0 until %a0 == %a1 */
+clear_dpram:
+       movel   #0, %a0@+
+       cmpal   %a0, %a1
+       bhi     clear_dpram
+
+configure_memory_controller:    
+       /* Set up Global Memory Register (GMR) */
+       move.l  #MCU_SIM_GMR, %d0
+       move.l  %d0, GMR
+
+configure_chip_select_0:
+       move.l  #0x00400000, %d0
+       subq.l  #0x01, %d0
+       eori.l  #SIM_OR_MASK, %d0
+       ori.l   #SIM_OR0_MASK, %d0
+       move.l  %d0, OR0
+
+       move.l  #__rom_start, %d0
+       ori.l   #SIM_BR0_MASK, %d0
+       move.l  %d0, BR0
+
+       move.l  #0x0, BR1
+       move.l  #0x0, BR2
+       move.l  #0x0, BR3
+       move.l  #0x0, BR4
+       move.l  #0x0, BR5
+       move.l  #0x0, BR6
+       move.l  #0x0, BR7
+
+       move.w  #MCU_SIM_PEPAR, PEPAR 
+
+       /* point to vector table: */
+       move.l  #_romvec, %a0
+       move.l  #_ramvec, %a1
+copy_vectors:
+       move.l  %a0@, %d0
+       move.l  %d0, %a1@
+       move.l  %a0@, %a1@
+       addq.l  #0x04, %a0
+       addq.l  #0x04, %a1
+       cmp.l   #_start, %a0
+       blt     copy_vectors
+
+       move.l  #_ramvec, %a1
+       movec   %a1, %vbr
+
+
+       /* Copy data segment from ROM to RAM */
+       moveal  #_etext, %a0
+       moveal  #_sdata, %a1
+       moveal  #_edata, %a2
+
+       /* Copy %a0 to %a1 until %a1 == %a2 */
+LD1:
+       move.l  %a0@, %d0
+       addq.l  #0x04, %a0
+       move.l  %d0, %a1@
+       addq.l  #0x04, %a1
+       cmp.l   #_edata, %a1
+       blt     LD1
+
+       moveal  #__bss_start, %a0
+       moveal  #__bss_stop, %a1
+
+       /* Copy 0 to %a0 until %a0 == %a1 */
+L1:
+       movel   #0, %a0@+
+       cmpal   %a0, %a1
+       bhi     L1
+
+load_quicc:
+       move.l  #_dprbase, _quicc_base
+
+store_ram_size:
+       /* Set ram size information */
+       move.l  #_sdata, _rambase
+       move.l  #__bss_stop, _ramstart
+       move.l  #RAMEND, %d0
+       sub.l   #0x1000, %d0                    /* Reserve 4K for stack space.*/
+       move.l  %d0, _ramend                    /* Different from RAMEND.*/
+
+       pea     0
+       pea     env
+       pea     %sp@(4)
+       pea     0
+
+       lea     init_thread_union, %a2
+       lea     0x2000(%a2), %sp
+
+lp:
+       jsr     start_kernel
+
+_exit:
+       jmp     _exit
+
+
+       .data
+       .align 4
+env:
+       .long   0
+_quicc_base:
+       .long   0
+_periph_base:
+       .long   0
+_ramvec:
+       .long   0
+_rambase:
+       .long   0
+_ramstart:
+       .long   0
+_ramend:
+       .long   0
+_dprbase:
+       .long   0xffffe000
+
+
+       .text
+
+    /*
+     * These are the exception vectors at boot up, they are copied into RAM
+     * and then overwritten as needed.
+     */
+.section ".data..initvect","awx"
+    .long   RAMEND     /* Reset: Initial Stack Pointer                 - 0.  */
+    .long   _start      /* Reset: Initial Program Counter               - 1.  */
+    .long   buserr      /* Bus Error                                    - 2.  */
+    .long   trap        /* Address Error                                - 3.  */
+    .long   trap        /* Illegal Instruction                          - 4.  */
+    .long   trap        /* Divide by zero                               - 5.  */
+    .long   trap        /* CHK, CHK2 Instructions                       - 6.  */
+    .long   trap        /* TRAPcc, TRAPV Instructions                   - 7.  */
+    .long   trap        /* Privilege Violation                          - 8.  */
+    .long   trap        /* Trace                                        - 9.  */
+    .long   trap        /* Line 1010 Emulator                           - 10. */
+    .long   trap        /* Line 1111 Emualtor                           - 11. */
+    .long   trap        /* Harware Breakpoint                           - 12. */
+    .long   trap        /* (Reserved for Coprocessor Protocol Violation)- 13. */
+    .long   trap        /* Format Error                                 - 14. */
+    .long   trap        /* Uninitialized Interrupt                      - 15. */
+    .long   trap        /* (Unassigned, Reserver)                       - 16. */
+    .long   trap        /* (Unassigned, Reserver)                       - 17. */
+    .long   trap        /* (Unassigned, Reserver)                       - 18. */
+    .long   trap        /* (Unassigned, Reserver)                       - 19. */
+    .long   trap        /* (Unassigned, Reserver)                       - 20. */
+    .long   trap        /* (Unassigned, Reserver)                       - 21. */
+    .long   trap        /* (Unassigned, Reserver)                       - 22. */
+    .long   trap        /* (Unassigned, Reserver)                       - 23. */
+    .long   trap        /* Spurious Interrupt                           - 24. */
+    .long   trap        /* Level 1 Interrupt Autovector                 - 25. */
+    .long   trap        /* Level 2 Interrupt Autovector                 - 26. */
+    .long   trap        /* Level 3 Interrupt Autovector                 - 27. */
+    .long   trap        /* Level 4 Interrupt Autovector                 - 28. */
+    .long   trap        /* Level 5 Interrupt Autovector                 - 29. */
+    .long   trap        /* Level 6 Interrupt Autovector                 - 30. */
+    .long   trap        /* Level 7 Interrupt Autovector                 - 31. */
+    .long   system_call /* Trap Instruction Vectors 0                   - 32. */
+    .long   trap        /* Trap Instruction Vectors 1                   - 33. */
+    .long   trap        /* Trap Instruction Vectors 2                   - 34. */
+    .long   trap        /* Trap Instruction Vectors 3                   - 35. */
+    .long   trap        /* Trap Instruction Vectors 4                   - 36. */
+    .long   trap        /* Trap Instruction Vectors 5                   - 37. */
+    .long   trap        /* Trap Instruction Vectors 6                   - 38. */
+    .long   trap        /* Trap Instruction Vectors 7                   - 39. */
+    .long   trap        /* Trap Instruction Vectors 8                   - 40. */
+    .long   trap        /* Trap Instruction Vectors 9                   - 41. */
+    .long   trap        /* Trap Instruction Vectors 10                  - 42. */
+    .long   trap        /* Trap Instruction Vectors 11                  - 43. */
+    .long   trap        /* Trap Instruction Vectors 12                  - 44. */
+    .long   trap        /* Trap Instruction Vectors 13                  - 45. */
+    .long   trap        /* Trap Instruction Vectors 14                  - 46. */
+    .long   trap        /* Trap Instruction Vectors 15                  - 47. */
+    .long   0           /* (Reserved for Coprocessor)                   - 48. */
+    .long   0           /* (Reserved for Coprocessor)                   - 49. */
+    .long   0           /* (Reserved for Coprocessor)                   - 50. */
+    .long   0           /* (Reserved for Coprocessor)                   - 51. */
+    .long   0           /* (Reserved for Coprocessor)                   - 52. */
+    .long   0           /* (Reserved for Coprocessor)                   - 53. */
+    .long   0           /* (Reserved for Coprocessor)                   - 54. */
+    .long   0           /* (Reserved for Coprocessor)                   - 55. */
+    .long   0           /* (Reserved for Coprocessor)                   - 56. */
+    .long   0           /* (Reserved for Coprocessor)                   - 57. */
+    .long   0           /* (Reserved for Coprocessor)                   - 58. */
+    .long   0           /* (Unassigned, Reserved)                       - 59. */
+    .long   0           /* (Unassigned, Reserved)                       - 60. */
+    .long   0           /* (Unassigned, Reserved)                       - 61. */
+    .long   0           /* (Unassigned, Reserved)                       - 62. */
+    .long   0           /* (Unassigned, Reserved)                       - 63. */
+    /*                  The assignment of these vectors to the CPM is         */
+    /*                  dependent on the configuration of the CPM vba         */
+    /*                          fields.                                       */
+    .long   0           /* (User-Defined Vectors 1) CPM Error           - 64. */
+    .long   0           /* (User-Defined Vectors 2) CPM Parallel IO PC11- 65. */
+    .long   0           /* (User-Defined Vectors 3) CPM Parallel IO PC10- 66. */
+    .long   0           /* (User-Defined Vectors 4) CPM SMC2 / PIP      - 67. */
+    .long   0           /* (User-Defined Vectors 5) CPM SMC1            - 68. */
+    .long   0           /* (User-Defined Vectors 6) CPM SPI             - 69. */
+    .long   0           /* (User-Defined Vectors 7) CPM Parallel IO PC9 - 70. */
+    .long   0           /* (User-Defined Vectors 8) CPM Timer 4         - 71. */
+    .long   0           /* (User-Defined Vectors 9) CPM Reserved        - 72. */
+    .long   0           /* (User-Defined Vectors 10) CPM Parallel IO PC8- 73. */
+    .long   0           /* (User-Defined Vectors 11) CPM Parallel IO PC7- 74. */
+    .long   0           /* (User-Defined Vectors 12) CPM Parallel IO PC6- 75. */
+    .long   0           /* (User-Defined Vectors 13) CPM Timer 3        - 76. */
+    .long   0           /* (User-Defined Vectors 14) CPM Reserved       - 77. */
+    .long   0           /* (User-Defined Vectors 15) CPM Parallel IO PC5- 78. */
+    .long   0           /* (User-Defined Vectors 16) CPM Parallel IO PC4- 79. */
+    .long   0           /* (User-Defined Vectors 17) CPM Reserved       - 80. */
+    .long   0           /* (User-Defined Vectors 18) CPM RISC Timer Tbl - 81. */
+    .long   0           /* (User-Defined Vectors 19) CPM Timer 2        - 82. */
+    .long   0           /* (User-Defined Vectors 21) CPM Reserved       - 83. */
+    .long   0           /* (User-Defined Vectors 22) CPM IDMA2          - 84. */
+    .long   0           /* (User-Defined Vectors 23) CPM IDMA1          - 85. */
+    .long   0           /* (User-Defined Vectors 24) CPM SDMA Bus Err   - 86. */
+    .long   0           /* (User-Defined Vectors 25) CPM Parallel IO PC3- 87. */
+    .long   0           /* (User-Defined Vectors 26) CPM Parallel IO PC2- 88. */
+    .long   0           /* (User-Defined Vectors 27) CPM Timer 1        - 89. */
+    .long   0           /* (User-Defined Vectors 28) CPM Parallel IO PC1- 90. */
+    .long   0           /* (User-Defined Vectors 29) CPM SCC 4          - 91. */
+    .long   0           /* (User-Defined Vectors 30) CPM SCC 3          - 92. */
+    .long   0           /* (User-Defined Vectors 31) CPM SCC 2          - 93. */
+    .long   0           /* (User-Defined Vectors 32) CPM SCC 1          - 94. */
+    .long   0           /* (User-Defined Vectors 33) CPM Parallel IO PC0- 95. */
+    /*                  I don't think anything uses the vectors after here.   */
+    .long   0           /* (User-Defined Vectors 34)                    - 96. */
+    .long   0,0,0,0,0               /* (User-Defined Vectors 35  -  39). */
+    .long   0,0,0,0,0,0,0,0,0,0     /* (User-Defined Vectors 40  -  49). */
+    .long   0,0,0,0,0,0,0,0,0,0     /* (User-Defined Vectors 50  -  59). */
+    .long   0,0,0,0,0,0,0,0,0,0     /* (User-Defined Vectors 60  -  69). */
+    .long   0,0,0,0,0,0,0,0,0,0     /* (User-Defined Vectors 70  -  79). */
+    .long   0,0,0,0,0,0,0,0,0,0     /* (User-Defined Vectors 80  -  89). */
+    .long   0,0,0,0,0,0,0,0,0,0     /* (User-Defined Vectors 90  -  99). */
+    .long   0,0,0,0,0,0,0,0,0,0     /* (User-Defined Vectors 100 - 109). */
+    .long   0,0,0,0,0,0,0,0,0,0     /* (User-Defined Vectors 110 - 119). */
+    .long   0,0,0,0,0,0,0,0,0,0     /* (User-Defined Vectors 120 - 129). */
+    .long   0,0,0,0,0,0,0,0,0,0     /* (User-Defined Vectors 130 - 139). */
+    .long   0,0,0,0,0,0,0,0,0,0     /* (User-Defined Vectors 140 - 149). */
+    .long   0,0,0,0,0,0,0,0,0,0     /* (User-Defined Vectors 150 - 159). */
+    .long   0,0,0,0,0,0,0,0,0,0     /* (User-Defined Vectors 160 - 169). */
+    .long   0,0,0,0,0,0,0,0,0,0     /* (User-Defined Vectors 170 - 179). */
+    .long   0,0,0,0,0,0,0,0,0,0     /* (User-Defined Vectors 180 - 189). */
+    .long   0,0,0                   /* (User-Defined Vectors 190 - 192). */
+.text
+ignore: rte
diff --git a/arch/m68k/68360/ints.c b/arch/m68k/68360/ints.c
new file mode 100644 (file)
index 0000000..2360fc0
--- /dev/null
@@ -0,0 +1,138 @@
+/*
+ * ints.c - first level interrupt handlers
+ *
+ * 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) 2000  Michael Leslie <mleslie@lineo.com>
+ * Copyright (c) 1996 Roman Zippel
+ * Copyright (c) 1999 D. Jeff Dionne <jeff@uclinux.org>
+ */
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <asm/traps.h>
+#include <asm/machdep.h>
+#include <asm/m68360.h>
+
+/* from quicc/commproc.c: */
+extern QUICC *pquicc;
+extern void cpm_interrupt_init(void);
+
+#define INTERNAL_IRQS (96)
+
+/* assembler routines */
+asmlinkage void system_call(void);
+asmlinkage void buserr(void);
+asmlinkage void trap(void);
+asmlinkage void bad_interrupt(void);
+asmlinkage void inthandler(void);
+
+static void intc_irq_unmask(struct irq_data *d)
+{
+       pquicc->intr_cimr |= (1 << d->irq);
+}
+
+static void intc_irq_mask(struct irq_data *d)
+{
+       pquicc->intr_cimr &= ~(1 << d->irq);
+}
+
+static void intc_irq_ack(struct irq_data *d)
+{
+       pquicc->intr_cisr = (1 << d->irq);
+}
+
+static struct irq_chip intc_irq_chip = {
+       .name           = "M68K-INTC",
+       .irq_mask       = intc_irq_mask,
+       .irq_unmask     = intc_irq_unmask,
+       .irq_ack        = intc_irq_ack,
+};
+
+/*
+ * This function should be called during kernel startup to initialize
+ * the vector table.
+ */
+void __init trap_init(void)
+{
+       int vba = (CPM_VECTOR_BASE<<4);
+
+       /* set up the vectors */
+       _ramvec[2] = buserr;
+       _ramvec[3] = trap;
+       _ramvec[4] = trap;
+       _ramvec[5] = trap;
+       _ramvec[6] = trap;
+       _ramvec[7] = trap;
+       _ramvec[8] = trap;
+       _ramvec[9] = trap;
+       _ramvec[10] = trap;
+       _ramvec[11] = trap;
+       _ramvec[12] = trap;
+       _ramvec[13] = trap;
+       _ramvec[14] = trap;
+       _ramvec[15] = trap;
+
+       _ramvec[32] = system_call;
+       _ramvec[33] = trap;
+
+       cpm_interrupt_init();
+
+       /* set up CICR for vector base address and irq level */
+       /* irl = 4, hp = 1f - see MC68360UM p 7-377 */
+       pquicc->intr_cicr = 0x00e49f00 | vba;
+
+       /* CPM interrupt vectors: (p 7-376) */
+       _ramvec[vba+CPMVEC_ERROR]       = bad_interrupt; /* Error */
+       _ramvec[vba+CPMVEC_PIO_PC11]    = inthandler;   /* pio - pc11 */
+       _ramvec[vba+CPMVEC_PIO_PC10]    = inthandler;   /* pio - pc10 */
+       _ramvec[vba+CPMVEC_SMC2]        = inthandler;   /* smc2/pip */
+       _ramvec[vba+CPMVEC_SMC1]        = inthandler;   /* smc1 */
+       _ramvec[vba+CPMVEC_SPI]         = inthandler;   /* spi */
+       _ramvec[vba+CPMVEC_PIO_PC9]     = inthandler;   /* pio - pc9 */
+       _ramvec[vba+CPMVEC_TIMER4]      = inthandler;   /* timer 4 */
+       _ramvec[vba+CPMVEC_RESERVED1]   = inthandler;   /* reserved */
+       _ramvec[vba+CPMVEC_PIO_PC8]     = inthandler;   /* pio - pc8 */
+       _ramvec[vba+CPMVEC_PIO_PC7]     = inthandler;  /* pio - pc7 */
+       _ramvec[vba+CPMVEC_PIO_PC6]     = inthandler;  /* pio - pc6 */
+       _ramvec[vba+CPMVEC_TIMER3]      = inthandler;  /* timer 3 */
+       _ramvec[vba+CPMVEC_PIO_PC5]     = inthandler;  /* pio - pc5 */
+       _ramvec[vba+CPMVEC_PIO_PC4]     = inthandler;  /* pio - pc4 */
+       _ramvec[vba+CPMVEC_RESERVED2]   = inthandler;  /* reserved */
+       _ramvec[vba+CPMVEC_RISCTIMER]   = inthandler;  /* timer table */
+       _ramvec[vba+CPMVEC_TIMER2]      = inthandler;  /* timer 2 */
+       _ramvec[vba+CPMVEC_RESERVED3]   = inthandler;  /* reserved */
+       _ramvec[vba+CPMVEC_IDMA2]       = inthandler;  /* idma 2 */
+       _ramvec[vba+CPMVEC_IDMA1]       = inthandler;  /* idma 1 */
+       _ramvec[vba+CPMVEC_SDMA_CB_ERR] = inthandler;  /* sdma channel bus error */
+       _ramvec[vba+CPMVEC_PIO_PC3]     = inthandler;  /* pio - pc3 */
+       _ramvec[vba+CPMVEC_PIO_PC2]     = inthandler;  /* pio - pc2 */
+       /* _ramvec[vba+CPMVEC_TIMER1]      = cpm_isr_timer1; */  /* timer 1 */
+       _ramvec[vba+CPMVEC_TIMER1]      = inthandler;  /* timer 1 */
+       _ramvec[vba+CPMVEC_PIO_PC1]     = inthandler;  /* pio - pc1 */
+       _ramvec[vba+CPMVEC_SCC4]        = inthandler;  /* scc 4 */
+       _ramvec[vba+CPMVEC_SCC3]        = inthandler;  /* scc 3 */
+       _ramvec[vba+CPMVEC_SCC2]        = inthandler;  /* scc 2 */
+       _ramvec[vba+CPMVEC_SCC1]        = inthandler;  /* scc 1 */
+       _ramvec[vba+CPMVEC_PIO_PC0]     = inthandler;  /* pio - pc0 */
+
+
+       /* turn off all CPM interrupts */
+       pquicc->intr_cimr = 0x00000000;
+}
+
+void init_IRQ(void)
+{
+       int i;
+
+       for (i = 0; (i < NR_IRQS); i++) {
+               irq_set_chip(i, &intc_irq_chip);
+               irq_set_handler(i, handle_level_irq);
+       }
+}
+
index 7f7830f2c5bcb488745c0326e36a1889a733e04b..0b29dcfef69f339407880ac42d42d5d873d2e032 100644 (file)
@@ -92,9 +92,9 @@ endif
 #
 head-y                         := arch/m68k/kernel/head.o
 head-$(CONFIG_SUN3)            := arch/m68k/kernel/sun3-head.o
-head-$(CONFIG_M68360)          := arch/m68k/platform/68360/head.o
-head-$(CONFIG_M68000)          := arch/m68k/platform/68000/head.o
-head-$(CONFIG_COLDFIRE)                := arch/m68k/platform/coldfire/head.o
+head-$(CONFIG_M68360)          := arch/m68k/68360/head.o
+head-$(CONFIG_M68000)          := arch/m68k/68000/head.o
+head-$(CONFIG_COLDFIRE)                := arch/m68k/coldfire/head.o
 
 core-y                         += arch/m68k/kernel/    arch/m68k/mm/
 libs-y                         += arch/m68k/lib/
@@ -114,9 +114,9 @@ core-$(CONFIG_NATFEAT)              += arch/m68k/emu/
 core-$(CONFIG_M68040)          += arch/m68k/fpsp040/
 core-$(CONFIG_M68060)          += arch/m68k/ifpsp060/
 core-$(CONFIG_M68KFPU_EMU)     += arch/m68k/math-emu/
-core-$(CONFIG_M68360)          += arch/m68k/platform/68360/
-core-$(CONFIG_M68000)          += arch/m68k/platform/68000/
-core-$(CONFIG_COLDFIRE)                += arch/m68k/platform/coldfire/
+core-$(CONFIG_M68360)          += arch/m68k/68360/
+core-$(CONFIG_M68000)          += arch/m68k/68000/
+core-$(CONFIG_COLDFIRE)                += arch/m68k/coldfire/
 
 
 all:   zImage
diff --git a/arch/m68k/coldfire/Makefile b/arch/m68k/coldfire/Makefile
new file mode 100644 (file)
index 0000000..68f0fac
--- /dev/null
@@ -0,0 +1,41 @@
+#
+# Makefile for the m68knommu kernel.
+#
+
+#
+# If you want to play with the HW breakpoints then you will
+# need to add define this,  which will give you a stack backtrace
+# on the console port whenever a DBG interrupt occurs. You have to
+# set up you HW breakpoints to trigger a DBG interrupt:
+#
+# ccflags-y := -DTRAP_DBG_INTERRUPT
+# asflags-y := -DTRAP_DBG_INTERRUPT
+#
+
+asflags-$(CONFIG_FULLDEBUG) := -DDEBUGGER_COMPATIBLE_CACHE=1
+
+obj-$(CONFIG_COLDFIRE) += cache.o clk.o device.o dma.o entry.o vectors.o
+obj-$(CONFIG_M5206)    += m5206.o timers.o intc.o reset.o
+obj-$(CONFIG_M5206e)   += m5206.o timers.o intc.o reset.o
+obj-$(CONFIG_M520x)    += m520x.o pit.o intc-simr.o reset.o
+obj-$(CONFIG_M523x)    += m523x.o pit.o dma_timer.o intc-2.o reset.o
+obj-$(CONFIG_M5249)    += m5249.o timers.o intc.o intc-5249.o reset.o
+obj-$(CONFIG_M525x)    += m525x.o timers.o intc.o intc-525x.o reset.o
+obj-$(CONFIG_M527x)    += m527x.o pit.o intc-2.o reset.o
+obj-$(CONFIG_M5272)    += m5272.o intc-5272.o timers.o
+obj-$(CONFIG_M528x)    += m528x.o pit.o intc-2.o reset.o
+obj-$(CONFIG_M5307)    += m5307.o timers.o intc.o reset.o
+obj-$(CONFIG_M53xx)    += m53xx.o timers.o intc-simr.o reset.o
+obj-$(CONFIG_M5407)    += m5407.o timers.o intc.o reset.o
+obj-$(CONFIG_M54xx)    += m54xx.o sltimers.o intc-2.o
+obj-$(CONFIG_M5441x)   += m5441x.o pit.o intc-simr.o reset.o
+
+obj-$(CONFIG_NETtel)   += nettel.o
+obj-$(CONFIG_CLEOPATRA)        += nettel.o
+obj-$(CONFIG_FIREBEE)  += firebee.o
+obj-$(CONFIG_MCF8390)  += mcf8390.o
+
+obj-$(CONFIG_PCI)      += pci.o
+
+obj-y                  += gpio.o
+extra-y := head.o
diff --git a/arch/m68k/coldfire/cache.c b/arch/m68k/coldfire/cache.c
new file mode 100644 (file)
index 0000000..71beeaf
--- /dev/null
@@ -0,0 +1,48 @@
+/***************************************************************************/
+
+/*
+ *     cache.c -- general ColdFire Cache maintenance code
+ *
+ *     Copyright (C) 2010, Greg Ungerer (gerg@snapgear.com)
+ */
+
+/***************************************************************************/
+
+#include <linux/kernel.h>
+#include <asm/coldfire.h>
+#include <asm/mcfsim.h>
+
+/***************************************************************************/
+#ifdef CACHE_PUSH
+/***************************************************************************/
+
+/*
+ *     Use cpushl to push all dirty cache lines back to memory.
+ *     Older versions of GAS don't seem to know how to generate the
+ *     ColdFire cpushl instruction... Oh well, bit stuff it for now.
+ */
+
+void mcf_cache_push(void)
+{
+       __asm__ __volatile__ (
+               "clrl   %%d0\n\t"
+               "1:\n\t"
+               "movel  %%d0,%%a0\n\t"
+               "2:\n\t"
+               ".word  0xf468\n\t"
+               "addl   %0,%%a0\n\t"
+               "cmpl   %1,%%a0\n\t"
+               "blt    2b\n\t"
+               "addql  #1,%%d0\n\t"
+               "cmpil  %2,%%d0\n\t"
+               "bne    1b\n\t"
+               : /* No output */
+               : "i" (CACHE_LINE_SIZE),
+                 "i" (DCACHE_SIZE / CACHE_WAYS),
+                 "i" (CACHE_WAYS)
+               : "d0", "a0" );
+}
+
+/***************************************************************************/
+#endif /* CACHE_PUSH */
+/***************************************************************************/
diff --git a/arch/m68k/coldfire/clk.c b/arch/m68k/coldfire/clk.c
new file mode 100644 (file)
index 0000000..fddfdcc
--- /dev/null
@@ -0,0 +1,124 @@
+/***************************************************************************/
+
+/*
+ *     clk.c -- general ColdFire CPU kernel clk handling
+ *
+ *     Copyright (C) 2009, Greg Ungerer (gerg@snapgear.com)
+ */
+
+/***************************************************************************/
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/mutex.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/err.h>
+#include <asm/coldfire.h>
+#include <asm/mcfsim.h>
+#include <asm/mcfclk.h>
+
+static DEFINE_SPINLOCK(clk_lock);
+
+#ifdef MCFPM_PPMCR0
+/*
+ *     For more advanced ColdFire parts that have clocks that can be enabled
+ *     we supply enable/disable functions. These must properly define their
+ *     clocks in their platform specific code.
+ */
+void __clk_init_enabled(struct clk *clk)
+{
+       clk->enabled = 1;
+       clk->clk_ops->enable(clk);
+}
+
+void __clk_init_disabled(struct clk *clk)
+{
+       clk->enabled = 0;
+       clk->clk_ops->disable(clk);
+}
+
+static void __clk_enable0(struct clk *clk)
+{
+       __raw_writeb(clk->slot, MCFPM_PPMCR0);
+}
+
+static void __clk_disable0(struct clk *clk)
+{
+       __raw_writeb(clk->slot, MCFPM_PPMSR0);
+}
+
+struct clk_ops clk_ops0 = {
+       .enable         = __clk_enable0,
+       .disable        = __clk_disable0,
+};
+
+#ifdef MCFPM_PPMCR1
+static void __clk_enable1(struct clk *clk)
+{
+       __raw_writeb(clk->slot, MCFPM_PPMCR1);
+}
+
+static void __clk_disable1(struct clk *clk)
+{
+       __raw_writeb(clk->slot, MCFPM_PPMSR1);
+}
+
+struct clk_ops clk_ops1 = {
+       .enable         = __clk_enable1,
+       .disable        = __clk_disable1,
+};
+#endif /* MCFPM_PPMCR1 */
+#endif /* MCFPM_PPMCR0 */
+
+struct clk *clk_get(struct device *dev, const char *id)
+{
+       const char *clk_name = dev ? dev_name(dev) : id ? id : NULL;
+       struct clk *clk;
+       unsigned i;
+
+       for (i = 0; (clk = mcf_clks[i]) != NULL; ++i)
+               if (!strcmp(clk->name, clk_name))
+                       return clk;
+       pr_warn("clk_get: didn't find clock %s\n", clk_name);
+       return ERR_PTR(-ENOENT);
+}
+EXPORT_SYMBOL(clk_get);
+
+int clk_enable(struct clk *clk)
+{
+       unsigned long flags;
+       spin_lock_irqsave(&clk_lock, flags);
+       if ((clk->enabled++ == 0) && clk->clk_ops)
+               clk->clk_ops->enable(clk);
+       spin_unlock_irqrestore(&clk_lock, flags);
+
+       return 0;
+}
+EXPORT_SYMBOL(clk_enable);
+
+void clk_disable(struct clk *clk)
+{
+       unsigned long flags;
+       spin_lock_irqsave(&clk_lock, flags);
+       if ((--clk->enabled == 0) && clk->clk_ops)
+               clk->clk_ops->disable(clk);
+       spin_unlock_irqrestore(&clk_lock, flags);
+}
+EXPORT_SYMBOL(clk_disable);
+
+void clk_put(struct clk *clk)
+{
+       if (clk->enabled != 0)
+               pr_warn("clk_put %s still enabled\n", clk->name);
+}
+EXPORT_SYMBOL(clk_put);
+
+unsigned long clk_get_rate(struct clk *clk)
+{
+       return clk->rate;
+}
+EXPORT_SYMBOL(clk_get_rate);
+
+/***************************************************************************/
diff --git a/arch/m68k/coldfire/device.c b/arch/m68k/coldfire/device.c
new file mode 100644 (file)
index 0000000..71ea4c0
--- /dev/null
@@ -0,0 +1,369 @@
+/*
+ * device.c  -- common ColdFire SoC device support
+ *
+ * (C) Copyright 2011, Greg Ungerer <gerg@uclinux.org>
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file COPYING in the main directory of this archive
+ * for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/spi/spi.h>
+#include <linux/gpio.h>
+#include <linux/fec.h>
+#include <asm/traps.h>
+#include <asm/coldfire.h>
+#include <asm/mcfsim.h>
+#include <asm/mcfuart.h>
+#include <asm/mcfqspi.h>
+
+/*
+ *     All current ColdFire parts contain from 2, 3, 4 or 10 UARTS.
+ */
+static struct mcf_platform_uart mcf_uart_platform_data[] = {
+       {
+               .mapbase        = MCFUART_BASE0,
+               .irq            = MCF_IRQ_UART0,
+       },
+       {
+               .mapbase        = MCFUART_BASE1,
+               .irq            = MCF_IRQ_UART1,
+       },
+#ifdef MCFUART_BASE2
+       {
+               .mapbase        = MCFUART_BASE2,
+               .irq            = MCF_IRQ_UART2,
+       },
+#endif
+#ifdef MCFUART_BASE3
+       {
+               .mapbase        = MCFUART_BASE3,
+               .irq            = MCF_IRQ_UART3,
+       },
+#endif
+#ifdef MCFUART_BASE4
+       {
+               .mapbase        = MCFUART_BASE4,
+               .irq            = MCF_IRQ_UART4,
+       },
+#endif
+#ifdef MCFUART_BASE5
+       {
+               .mapbase        = MCFUART_BASE5,
+               .irq            = MCF_IRQ_UART5,
+       },
+#endif
+#ifdef MCFUART_BASE6
+       {
+               .mapbase        = MCFUART_BASE6,
+               .irq            = MCF_IRQ_UART6,
+       },
+#endif
+#ifdef MCFUART_BASE7
+       {
+               .mapbase        = MCFUART_BASE7,
+               .irq            = MCF_IRQ_UART7,
+       },
+#endif
+#ifdef MCFUART_BASE8
+       {
+               .mapbase        = MCFUART_BASE8,
+               .irq            = MCF_IRQ_UART8,
+       },
+#endif
+#ifdef MCFUART_BASE9
+       {
+               .mapbase        = MCFUART_BASE9,
+               .irq            = MCF_IRQ_UART9,
+       },
+#endif
+       { },
+};
+
+static struct platform_device mcf_uart = {
+       .name                   = "mcfuart",
+       .id                     = 0,
+       .dev.platform_data      = mcf_uart_platform_data,
+};
+
+#ifdef CONFIG_FEC
+
+#ifdef CONFIG_M5441x
+#define FEC_NAME       "enet-fec"
+static struct fec_platform_data fec_pdata = {
+       .phy            = PHY_INTERFACE_MODE_RMII,
+};
+#define FEC_PDATA      (&fec_pdata)
+#else
+#define FEC_NAME       "fec"
+#define FEC_PDATA      NULL
+#endif
+
+/*
+ *     Some ColdFire cores contain the Fast Ethernet Controller (FEC)
+ *     block. It is Freescale's own hardware block. Some ColdFires
+ *     have 2 of these.
+ */
+static struct resource mcf_fec0_resources[] = {
+       {
+               .start          = MCFFEC_BASE0,
+               .end            = MCFFEC_BASE0 + MCFFEC_SIZE0 - 1,
+               .flags          = IORESOURCE_MEM,
+       },
+       {
+               .start          = MCF_IRQ_FECRX0,
+               .end            = MCF_IRQ_FECRX0,
+               .flags          = IORESOURCE_IRQ,
+       },
+       {
+               .start          = MCF_IRQ_FECTX0,
+               .end            = MCF_IRQ_FECTX0,
+               .flags          = IORESOURCE_IRQ,
+       },
+       {
+               .start          = MCF_IRQ_FECENTC0,
+               .end            = MCF_IRQ_FECENTC0,
+               .flags          = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device mcf_fec0 = {
+       .name                   = FEC_NAME,
+       .id                     = 0,
+       .num_resources          = ARRAY_SIZE(mcf_fec0_resources),
+       .resource               = mcf_fec0_resources,
+       .dev.platform_data      = FEC_PDATA,
+};
+
+#ifdef MCFFEC_BASE1
+static struct resource mcf_fec1_resources[] = {
+       {
+               .start          = MCFFEC_BASE1,
+               .end            = MCFFEC_BASE1 + MCFFEC_SIZE1 - 1,
+               .flags          = IORESOURCE_MEM,
+       },
+       {
+               .start          = MCF_IRQ_FECRX1,
+               .end            = MCF_IRQ_FECRX1,
+               .flags          = IORESOURCE_IRQ,
+       },
+       {
+               .start          = MCF_IRQ_FECTX1,
+               .end            = MCF_IRQ_FECTX1,
+               .flags          = IORESOURCE_IRQ,
+       },
+       {
+               .start          = MCF_IRQ_FECENTC1,
+               .end            = MCF_IRQ_FECENTC1,
+               .flags          = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device mcf_fec1 = {
+       .name                   = FEC_NAME,
+       .id                     = 1,
+       .num_resources          = ARRAY_SIZE(mcf_fec1_resources),
+       .resource               = mcf_fec1_resources,
+       .dev.platform_data      = FEC_PDATA,
+};
+#endif /* MCFFEC_BASE1 */
+#endif /* CONFIG_FEC */
+
+#if IS_ENABLED(CONFIG_SPI_COLDFIRE_QSPI)
+/*
+ *     The ColdFire QSPI module is an SPI protocol hardware block used
+ *     on a number of different ColdFire CPUs.
+ */
+static struct resource mcf_qspi_resources[] = {
+       {
+               .start          = MCFQSPI_BASE,
+               .end            = MCFQSPI_BASE + MCFQSPI_SIZE - 1,
+               .flags          = IORESOURCE_MEM,
+       },
+       {
+               .start          = MCF_IRQ_QSPI,
+               .end            = MCF_IRQ_QSPI,
+               .flags          = IORESOURCE_IRQ,
+       },
+};
+
+static int mcf_cs_setup(struct mcfqspi_cs_control *cs_control)
+{
+       int status;
+
+       status = gpio_request(MCFQSPI_CS0, "MCFQSPI_CS0");
+       if (status) {
+               pr_debug("gpio_request for MCFQSPI_CS0 failed\n");
+               goto fail0;
+       }
+       status = gpio_direction_output(MCFQSPI_CS0, 1);
+       if (status) {
+               pr_debug("gpio_direction_output for MCFQSPI_CS0 failed\n");
+               goto fail1;
+       }
+
+       status = gpio_request(MCFQSPI_CS1, "MCFQSPI_CS1");
+       if (status) {
+               pr_debug("gpio_request for MCFQSPI_CS1 failed\n");
+               goto fail1;
+       }
+       status = gpio_direction_output(MCFQSPI_CS1, 1);
+       if (status) {
+               pr_debug("gpio_direction_output for MCFQSPI_CS1 failed\n");
+               goto fail2;
+       }
+
+       status = gpio_request(MCFQSPI_CS2, "MCFQSPI_CS2");
+       if (status) {
+               pr_debug("gpio_request for MCFQSPI_CS2 failed\n");
+               goto fail2;
+       }
+       status = gpio_direction_output(MCFQSPI_CS2, 1);
+       if (status) {
+               pr_debug("gpio_direction_output for MCFQSPI_CS2 failed\n");
+               goto fail3;
+       }
+
+#ifdef MCFQSPI_CS3
+       status = gpio_request(MCFQSPI_CS3, "MCFQSPI_CS3");
+       if (status) {
+               pr_debug("gpio_request for MCFQSPI_CS3 failed\n");
+               goto fail3;
+       }
+       status = gpio_direction_output(MCFQSPI_CS3, 1);
+       if (status) {
+               pr_debug("gpio_direction_output for MCFQSPI_CS3 failed\n");
+               gpio_free(MCFQSPI_CS3);
+               goto fail3;
+       }
+#endif
+
+       return 0;
+
+fail3:
+       gpio_free(MCFQSPI_CS2);
+fail2:
+       gpio_free(MCFQSPI_CS1);
+fail1:
+       gpio_free(MCFQSPI_CS0);
+fail0:
+       return status;
+}
+
+static void mcf_cs_teardown(struct mcfqspi_cs_control *cs_control)
+{
+#ifdef MCFQSPI_CS3
+       gpio_free(MCFQSPI_CS3);
+#endif
+       gpio_free(MCFQSPI_CS2);
+       gpio_free(MCFQSPI_CS1);
+       gpio_free(MCFQSPI_CS0);
+}
+
+static void mcf_cs_select(struct mcfqspi_cs_control *cs_control,
+                         u8 chip_select, bool cs_high)
+{
+       switch (chip_select) {
+       case 0:
+               gpio_set_value(MCFQSPI_CS0, cs_high);
+               break;
+       case 1:
+               gpio_set_value(MCFQSPI_CS1, cs_high);
+               break;
+       case 2:
+               gpio_set_value(MCFQSPI_CS2, cs_high);
+               break;
+#ifdef MCFQSPI_CS3
+       case 3:
+               gpio_set_value(MCFQSPI_CS3, cs_high);
+               break;
+#endif
+       }
+}
+
+static void mcf_cs_deselect(struct mcfqspi_cs_control *cs_control,
+                           u8 chip_select, bool cs_high)
+{
+       switch (chip_select) {
+       case 0:
+               gpio_set_value(MCFQSPI_CS0, !cs_high);
+               break;
+       case 1:
+               gpio_set_value(MCFQSPI_CS1, !cs_high);
+               break;
+       case 2:
+               gpio_set_value(MCFQSPI_CS2, !cs_high);
+               break;
+#ifdef MCFQSPI_CS3
+       case 3:
+               gpio_set_value(MCFQSPI_CS3, !cs_high);
+               break;
+#endif
+       }
+}
+
+static struct mcfqspi_cs_control mcf_cs_control = {
+       .setup                  = mcf_cs_setup,
+       .teardown               = mcf_cs_teardown,
+       .select                 = mcf_cs_select,
+       .deselect               = mcf_cs_deselect,
+};
+
+static struct mcfqspi_platform_data mcf_qspi_data = {
+       .bus_num                = 0,
+       .num_chipselect         = 4,
+       .cs_control             = &mcf_cs_control,
+};
+
+static struct platform_device mcf_qspi = {
+       .name                   = "mcfqspi",
+       .id                     = 0,
+       .num_resources          = ARRAY_SIZE(mcf_qspi_resources),
+       .resource               = mcf_qspi_resources,
+       .dev.platform_data      = &mcf_qspi_data,
+};
+#endif /* IS_ENABLED(CONFIG_SPI_COLDFIRE_QSPI) */
+
+static struct platform_device *mcf_devices[] __initdata = {
+       &mcf_uart,
+#ifdef CONFIG_FEC
+       &mcf_fec0,
+#ifdef MCFFEC_BASE1
+       &mcf_fec1,
+#endif
+#endif
+#if IS_ENABLED(CONFIG_SPI_COLDFIRE_QSPI)
+       &mcf_qspi,
+#endif
+};
+
+/*
+ *     Some ColdFire UARTs let you set the IRQ line to use.
+ */
+static void __init mcf_uart_set_irq(void)
+{
+#ifdef MCFUART_UIVR
+       /* UART0 interrupt setup */
+       writeb(MCFSIM_ICR_LEVEL6 | MCFSIM_ICR_PRI1, MCFSIM_UART1ICR);
+       writeb(MCF_IRQ_UART0, MCFUART_BASE0 + MCFUART_UIVR);
+       mcf_mapirq2imr(MCF_IRQ_UART0, MCFINTC_UART0);
+
+       /* UART1 interrupt setup */
+       writeb(MCFSIM_ICR_LEVEL6 | MCFSIM_ICR_PRI2, MCFSIM_UART2ICR);
+       writeb(MCF_IRQ_UART1, MCFUART_BASE1 + MCFUART_UIVR);
+       mcf_mapirq2imr(MCF_IRQ_UART1, MCFINTC_UART1);
+#endif
+}
+
+static int __init mcf_init_devices(void)
+{
+       mcf_uart_set_irq();
+       platform_add_devices(mcf_devices, ARRAY_SIZE(mcf_devices));
+       return 0;
+}
+
+arch_initcall(mcf_init_devices);
+
diff --git a/arch/m68k/coldfire/dma.c b/arch/m68k/coldfire/dma.c
new file mode 100644 (file)
index 0000000..df5ce20
--- /dev/null
@@ -0,0 +1,42 @@
+/***************************************************************************/
+
+/*
+ *     dma.c -- Freescale ColdFire DMA support
+ *
+ *     Copyright (C) 2007, Greg Ungerer (gerg@snapgear.com)
+ */
+
+/***************************************************************************/
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <asm/dma.h>
+#include <asm/coldfire.h>
+#include <asm/mcfsim.h>
+#include <asm/mcfdma.h>
+
+/***************************************************************************/
+
+/*
+ *      DMA channel base address table.
+ */
+unsigned int dma_base_addr[MAX_M68K_DMA_CHANNELS] = {
+#ifdef MCFDMA_BASE0
+       MCFDMA_BASE0,
+#endif
+#ifdef MCFDMA_BASE1
+       MCFDMA_BASE1,
+#endif
+#ifdef MCFDMA_BASE2
+       MCFDMA_BASE2,
+#endif
+#ifdef MCFDMA_BASE3
+       MCFDMA_BASE3,
+#endif
+};
+EXPORT_SYMBOL(dma_base_addr);
+
+unsigned int dma_device_address[MAX_M68K_DMA_CHANNELS];
+EXPORT_SYMBOL(dma_device_address);
+
+/***************************************************************************/
diff --git a/arch/m68k/coldfire/dma_timer.c b/arch/m68k/coldfire/dma_timer.c
new file mode 100644 (file)
index 0000000..235ad57
--- /dev/null
@@ -0,0 +1,81 @@
+/*
+ * dma_timer.c -- Freescale ColdFire DMA Timer.
+ *
+ * Copyright (C) 2007, Benedikt Spranger <b.spranger@linutronix.de>
+ * Copyright (C) 2008. Sebastian Siewior, Linutronix
+ *
+ */
+
+#include <linux/clocksource.h>
+#include <linux/io.h>
+
+#include <asm/machdep.h>
+#include <asm/coldfire.h>
+#include <asm/mcfpit.h>
+#include <asm/mcfsim.h>
+
+#define DMA_TIMER_0    (0x00)
+#define DMA_TIMER_1    (0x40)
+#define DMA_TIMER_2    (0x80)
+#define DMA_TIMER_3    (0xc0)
+
+#define DTMR0  (MCF_IPSBAR + DMA_TIMER_0 + 0x400)
+#define DTXMR0 (MCF_IPSBAR + DMA_TIMER_0 + 0x402)
+#define DTER0  (MCF_IPSBAR + DMA_TIMER_0 + 0x403)
+#define DTRR0  (MCF_IPSBAR + DMA_TIMER_0 + 0x404)
+#define DTCR0  (MCF_IPSBAR + DMA_TIMER_0 + 0x408)
+#define DTCN0  (MCF_IPSBAR + DMA_TIMER_0 + 0x40c)
+
+#define DMA_FREQ    ((MCF_CLK / 2) / 16)
+
+/* DTMR */
+#define DMA_DTMR_RESTART       (1 << 3)
+#define DMA_DTMR_CLK_DIV_1     (1 << 1)
+#define DMA_DTMR_CLK_DIV_16    (2 << 1)
+#define DMA_DTMR_ENABLE                (1 << 0)
+
+static cycle_t cf_dt_get_cycles(struct clocksource *cs)
+{
+       return __raw_readl(DTCN0);
+}
+
+static struct clocksource clocksource_cf_dt = {
+       .name           = "coldfire_dma_timer",
+       .rating         = 200,
+       .read           = cf_dt_get_cycles,
+       .mask           = CLOCKSOURCE_MASK(32),
+       .flags          = CLOCK_SOURCE_IS_CONTINUOUS,
+};
+
+static int __init  init_cf_dt_clocksource(void)
+{
+       /*
+        * We setup DMA timer 0 in free run mode. This incrementing counter is
+        * used as a highly precious clock source. With MCF_CLOCK = 150 MHz we
+        * get a ~213 ns resolution and the 32bit register will overflow almost
+        * every 15 minutes.
+        */
+       __raw_writeb(0x00, DTXMR0);
+       __raw_writeb(0x00, DTER0);
+       __raw_writel(0x00000000, DTRR0);
+       __raw_writew(DMA_DTMR_CLK_DIV_16 | DMA_DTMR_ENABLE, DTMR0);
+       return clocksource_register_hz(&clocksource_cf_dt, DMA_FREQ);
+}
+
+arch_initcall(init_cf_dt_clocksource);
+
+#define CYC2NS_SCALE_FACTOR 10 /* 2^10, carefully chosen */
+#define CYC2NS_SCALE   ((1000000 << CYC2NS_SCALE_FACTOR) / (DMA_FREQ / 1000))
+
+static unsigned long long cycles2ns(unsigned long cycl)
+{
+       return (unsigned long long) ((unsigned long long)cycl *
+                       CYC2NS_SCALE) >> CYC2NS_SCALE_FACTOR;
+}
+
+unsigned long long sched_clock(void)
+{
+       unsigned long cycl = __raw_readl(DTCN0);
+
+       return cycles2ns(cycl);
+}
diff --git a/arch/m68k/coldfire/entry.S b/arch/m68k/coldfire/entry.S
new file mode 100644 (file)
index 0000000..52d312d
--- /dev/null
@@ -0,0 +1,203 @@
+/*
+ *  entry.S  -- interrupt and exception processing for ColdFire
+ *
+ *  Copyright (C) 1999-2007, Greg Ungerer (gerg@snapgear.com)
+ *  Copyright (C) 1998  D. Jeff Dionne <jeff@lineo.ca>,
+ *                      Kenneth Albanowski <kjahds@kjahds.com>,
+ *  Copyright (C) 2000  Lineo Inc. (www.lineo.com)
+ *  Copyright (C) 2004-2006  Macq Electronique SA. (www.macqel.com)
+ *
+ * Based on:
+ *
+ *  linux/arch/m68k/kernel/entry.S
+ *
+ *  Copyright (C) 1991, 1992  Linus Torvalds
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file README.legal in the main directory of this archive
+ * for more details.
+ *
+ * Linux/m68k support by Hamish Macdonald
+ *
+ * 68060 fixes by Jesper Skov
+ * ColdFire support by Greg Ungerer (gerg@snapgear.com)
+ * 5307 fixes by David W. Miller
+ * linux 2.4 support David McCullough <davidm@snapgear.com>
+ * Bug, speed and maintainability fixes by Philippe De Muyter <phdm@macqel.be>
+ */
+
+#include <linux/linkage.h>
+#include <asm/unistd.h>
+#include <asm/thread_info.h>
+#include <asm/errno.h>
+#include <asm/setup.h>
+#include <asm/segment.h>
+#include <asm/asm-offsets.h>
+#include <asm/entry.h>
+
+#ifdef CONFIG_COLDFIRE_SW_A7
+/*
+ *     Define software copies of the supervisor and user stack pointers.
+ */
+.bss
+sw_ksp:
+.long  0
+sw_usp:
+.long  0
+#endif /* CONFIG_COLDFIRE_SW_A7 */
+
+.text
+
+.globl system_call
+.globl resume
+.globl ret_from_exception
+.globl ret_from_signal
+.globl sys_call_table
+.globl inthandler
+
+enosys:
+       mov.l   #sys_ni_syscall,%d3
+       bra     1f
+
+ENTRY(system_call)
+       SAVE_ALL_SYS
+       move    #0x2000,%sr             /* enable intrs again */
+       GET_CURRENT(%d2)
+
+       cmpl    #NR_syscalls,%d0
+       jcc     enosys
+       lea     sys_call_table,%a0
+       lsll    #2,%d0                  /* movel %a0@(%d0:l:4),%d3 */
+       movel   %a0@(%d0),%d3
+       jeq     enosys
+
+1:
+       movel   %sp,%d2                 /* get thread_info pointer */
+       andl    #-THREAD_SIZE,%d2       /* at start of kernel stack */
+       movel   %d2,%a0
+       movel   %a0@,%a1                /* save top of frame */
+       movel   %sp,%a1@(TASK_THREAD+THREAD_ESP0)
+       btst    #(TIF_SYSCALL_TRACE%8),%a0@(TINFO_FLAGS+(31-TIF_SYSCALL_TRACE)/8)
+       bnes    1f
+
+       movel   %d3,%a0
+       jbsr    %a0@
+       movel   %d0,%sp@(PT_OFF_D0)     /* save the return value */
+       jra     ret_from_exception
+1:
+       movel   #-ENOSYS,%d2            /* strace needs -ENOSYS in PT_OFF_D0 */
+       movel   %d2,PT_OFF_D0(%sp)      /* on syscall entry */
+       subql   #4,%sp
+       SAVE_SWITCH_STACK
+       jbsr    syscall_trace_enter
+       RESTORE_SWITCH_STACK
+       addql   #4,%sp
+       movel   %d3,%a0
+       jbsr    %a0@
+       movel   %d0,%sp@(PT_OFF_D0)             /* save the return value */
+       subql   #4,%sp                  /* dummy return address */
+       SAVE_SWITCH_STACK
+       jbsr    syscall_trace_leave
+
+ret_from_signal:
+       RESTORE_SWITCH_STACK
+       addql   #4,%sp
+
+ret_from_exception:
+       move    #0x2700,%sr             /* disable intrs */
+       btst    #5,%sp@(PT_OFF_SR)      /* check if returning to kernel */
+       jeq     Luser_return            /* if so, skip resched, signals */
+
+#ifdef CONFIG_PREEMPT
+       movel   %sp,%d1                 /* get thread_info pointer */
+       andl    #-THREAD_SIZE,%d1       /* at base of kernel stack */
+       movel   %d1,%a0
+       movel   %a0@(TINFO_FLAGS),%d1   /* get thread_info->flags */
+       andl    #(1<<TIF_NEED_RESCHED),%d1
+       jeq     Lkernel_return
+
+       movel   %a0@(TINFO_PREEMPT),%d1
+       cmpl    #0,%d1
+       jne     Lkernel_return
+
+       pea     Lkernel_return
+       jmp     preempt_schedule_irq    /* preempt the kernel */
+#endif
+
+Lkernel_return:
+       moveml  %sp@,%d1-%d5/%a0-%a2
+       lea     %sp@(32),%sp            /* space for 8 regs */
+       movel   %sp@+,%d0
+       addql   #4,%sp                  /* orig d0 */
+       addl    %sp@+,%sp               /* stk adj */
+       rte
+
+Luser_return:
+       movel   %sp,%d1                 /* get thread_info pointer */
+       andl    #-THREAD_SIZE,%d1       /* at base of kernel stack */
+       movel   %d1,%a0
+       moveb   %a0@(TINFO_FLAGS+3),%d1 /* thread_info->flags (low 8 bits) */
+       jne     Lwork_to_do             /* still work to do */
+
+Lreturn:
+       RESTORE_USER
+
+Lwork_to_do:
+       movel   %a0@(TINFO_FLAGS),%d1   /* get thread_info->flags */
+       move    #0x2000,%sr             /* enable intrs again */
+       btst    #TIF_NEED_RESCHED,%d1
+       jne     reschedule
+
+Lsignal_return:
+       subql   #4,%sp                  /* dummy return address */
+       SAVE_SWITCH_STACK
+       pea     %sp@(SWITCH_STACK_SIZE)
+       jsr     do_notify_resume
+       addql   #4,%sp
+       RESTORE_SWITCH_STACK
+       addql   #4,%sp
+       jmp     Luser_return
+
+/*
+ * This is the generic interrupt handler (for all hardware interrupt
+ * sources). Calls up to high level code to do all the work.
+ */
+ENTRY(inthandler)
+       SAVE_ALL_INT
+       GET_CURRENT(%d2)
+
+       movew   %sp@(PT_OFF_FORMATVEC),%d0 /* put exception # in d0 */
+       andl    #0x03fc,%d0             /* mask out vector only */
+
+       movel   %sp,%sp@-               /* push regs arg */
+       lsrl    #2,%d0                  /* calculate real vector # */
+       movel   %d0,%sp@-               /* push vector number */
+       jbsr    do_IRQ                  /* call high level irq handler */
+       lea     %sp@(8),%sp             /* pop args off stack */
+
+       bra     ret_from_exception
+
+/*
+ * Beware - when entering resume, prev (the current task) is
+ * in a0, next (the new task) is in a1, so don't change these
+ * registers until their contents are no longer needed.
+ */
+ENTRY(resume)
+       movew   %sr,%d1                          /* save current status */
+       movew   %d1,%a0@(TASK_THREAD+THREAD_SR)
+       movel   %a0,%d1                          /* get prev thread in d1 */
+       SAVE_SWITCH_STACK
+       movel   %sp,%a0@(TASK_THREAD+THREAD_KSP) /* save kernel stack pointer */
+       RDUSP                                    /* movel %usp,%a3 */
+       movel   %a3,%a0@(TASK_THREAD+THREAD_USP) /* save thread user stack */
+#ifdef CONFIG_MMU
+       movel   %a1,%a2                          /* set new current */
+#endif
+       movel   %a1@(TASK_THREAD+THREAD_USP),%a3 /* restore thread user stack */
+       WRUSP                                    /* movel %a3,%usp */
+       movel   %a1@(TASK_THREAD+THREAD_KSP),%sp /* restore new kernel stack */
+       movew   %a1@(TASK_THREAD+THREAD_SR),%d7  /* restore new status */
+       movew   %d7,%sr
+       RESTORE_SWITCH_STACK
+       rts
+
diff --git a/arch/m68k/coldfire/firebee.c b/arch/m68k/coldfire/firebee.c
new file mode 100644 (file)
index 0000000..46d5053
--- /dev/null
@@ -0,0 +1,86 @@
+/***************************************************************************/
+
+/*
+ *     firebee.c -- extra startup code support for the FireBee boards
+ *
+ *     Copyright (C) 2011, Greg Ungerer (gerg@snapgear.com)
+ */
+
+/***************************************************************************/
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <linux/mtd/physmap.h>
+#include <asm/coldfire.h>
+#include <asm/mcfsim.h>
+
+/***************************************************************************/
+
+/*
+ *     8MB of NOR flash fitted to the FireBee board.
+ */
+#define        FLASH_PHYS_ADDR         0xe0000000      /* Physical address of flash */
+#define        FLASH_PHYS_SIZE         0x00800000      /* Size of flash */
+
+#define        PART_BOOT_START         0x00000000      /* Start at bottom of flash */
+#define        PART_BOOT_SIZE          0x00040000      /* 256k in size */
+#define        PART_IMAGE_START        0x00040000      /* Start after boot loader */
+#define        PART_IMAGE_SIZE         0x006c0000      /* Most of flash */
+#define        PART_FPGA_START         0x00700000      /* Start at offset 7MB */
+#define        PART_FPGA_SIZE          0x00100000      /* 1MB in size */
+
+static struct mtd_partition firebee_flash_parts[] = {
+       {
+               .name   = "dBUG",
+               .offset = PART_BOOT_START,
+               .size   = PART_BOOT_SIZE,
+       },
+       {
+               .name   = "FPGA",
+               .offset = PART_FPGA_START,
+               .size   = PART_FPGA_SIZE,
+       },
+       {
+               .name   = "image",
+               .offset = PART_IMAGE_START,
+               .size   = PART_IMAGE_SIZE,
+       },
+};
+
+static struct physmap_flash_data firebee_flash_data = {
+       .width          = 2,
+       .nr_parts       = ARRAY_SIZE(firebee_flash_parts),
+       .parts          = firebee_flash_parts,
+};
+
+static struct resource firebee_flash_resource = {
+       .start          = FLASH_PHYS_ADDR,
+       .end            = FLASH_PHYS_ADDR + FLASH_PHYS_SIZE,
+       .flags          = IORESOURCE_MEM,
+};
+
+static struct platform_device firebee_flash = {
+       .name           = "physmap-flash",
+       .id             = 0,
+       .dev            = {
+               .platform_data = &firebee_flash_data,
+       },
+       .num_resources  = 1,
+       .resource       = &firebee_flash_resource,
+};
+
+/***************************************************************************/
+
+static int __init init_firebee(void)
+{
+       platform_device_register(&firebee_flash);
+       return 0;
+}
+
+arch_initcall(init_firebee);
+
+/***************************************************************************/
diff --git a/arch/m68k/coldfire/gpio.c b/arch/m68k/coldfire/gpio.c
new file mode 100644 (file)
index 0000000..e7e4286
--- /dev/null
@@ -0,0 +1,186 @@
+/*
+ * Coldfire generic GPIO support.
+ *
+ * (C) Copyright 2009, Steven King <sfking@fdwdc.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/device.h>
+
+#include <linux/io.h>
+#include <asm/coldfire.h>
+#include <asm/mcfsim.h>
+#include <asm/mcfgpio.h>
+
+int __mcfgpio_get_value(unsigned gpio)
+{
+       return mcfgpio_read(__mcfgpio_ppdr(gpio)) & mcfgpio_bit(gpio);
+}
+EXPORT_SYMBOL(__mcfgpio_get_value);
+
+void __mcfgpio_set_value(unsigned gpio, int value)
+{
+       if (gpio < MCFGPIO_SCR_START) {
+               unsigned long flags;
+               MCFGPIO_PORTTYPE data;
+
+               local_irq_save(flags);
+               data = mcfgpio_read(__mcfgpio_podr(gpio));
+               if (value)
+                       data |= mcfgpio_bit(gpio);
+               else
+                       data &= ~mcfgpio_bit(gpio);
+               mcfgpio_write(data, __mcfgpio_podr(gpio));
+               local_irq_restore(flags);
+       } else {
+               if (value)
+                       mcfgpio_write(mcfgpio_bit(gpio),
+                                       MCFGPIO_SETR_PORT(gpio));
+               else
+                       mcfgpio_write(~mcfgpio_bit(gpio),
+                                       MCFGPIO_CLRR_PORT(gpio));
+       }
+}
+EXPORT_SYMBOL(__mcfgpio_set_value);
+
+int __mcfgpio_direction_input(unsigned gpio)
+{
+       unsigned long flags;
+       MCFGPIO_PORTTYPE dir;
+
+       local_irq_save(flags);
+       dir = mcfgpio_read(__mcfgpio_pddr(gpio));
+       dir &= ~mcfgpio_bit(gpio);
+       mcfgpio_write(dir, __mcfgpio_pddr(gpio));
+       local_irq_restore(flags);
+
+       return 0;
+}
+EXPORT_SYMBOL(__mcfgpio_direction_input);
+
+int __mcfgpio_direction_output(unsigned gpio, int value)
+{
+       unsigned long flags;
+       MCFGPIO_PORTTYPE data;
+
+       local_irq_save(flags);
+       data = mcfgpio_read(__mcfgpio_pddr(gpio));
+       data |= mcfgpio_bit(gpio);
+       mcfgpio_write(data, __mcfgpio_pddr(gpio));
+
+       /* now set the data to output */
+       if (gpio < MCFGPIO_SCR_START) {
+               data = mcfgpio_read(__mcfgpio_podr(gpio));
+               if (value)
+                       data |= mcfgpio_bit(gpio);
+               else
+                       data &= ~mcfgpio_bit(gpio);
+               mcfgpio_write(data, __mcfgpio_podr(gpio));
+       } else {
+                if (value)
+                       mcfgpio_write(mcfgpio_bit(gpio),
+                                       MCFGPIO_SETR_PORT(gpio));
+                else
+                        mcfgpio_write(~mcfgpio_bit(gpio),
+                                        MCFGPIO_CLRR_PORT(gpio));
+       }
+       local_irq_restore(flags);
+       return 0;
+}
+EXPORT_SYMBOL(__mcfgpio_direction_output);
+
+int __mcfgpio_request(unsigned gpio)
+{
+       return 0;
+}
+EXPORT_SYMBOL(__mcfgpio_request);
+
+void __mcfgpio_free(unsigned gpio)
+{
+       __mcfgpio_direction_input(gpio);
+}
+EXPORT_SYMBOL(__mcfgpio_free);
+
+#ifdef CONFIG_GPIOLIB
+
+static int mcfgpio_direction_input(struct gpio_chip *chip, unsigned offset)
+{
+       return __mcfgpio_direction_input(offset);
+}
+
+static int mcfgpio_get_value(struct gpio_chip *chip, unsigned offset)
+{
+       return __mcfgpio_get_value(offset);
+}
+
+static int mcfgpio_direction_output(struct gpio_chip *chip, unsigned offset,
+                                   int value)
+{
+       return __mcfgpio_direction_output(offset, value);
+}
+
+static void mcfgpio_set_value(struct gpio_chip *chip, unsigned offset,
+                             int value)
+{
+       __mcfgpio_set_value(offset, value);
+}
+
+static int mcfgpio_request(struct gpio_chip *chip, unsigned offset)
+{
+       return __mcfgpio_request(offset);
+}
+
+static void mcfgpio_free(struct gpio_chip *chip, unsigned offset)
+{
+       __mcfgpio_free(offset);
+}
+
+static int mcfgpio_to_irq(struct gpio_chip *chip, unsigned offset)
+{
+#if defined(MCFGPIO_IRQ_MIN)
+       if ((offset >= MCFGPIO_IRQ_MIN) && (offset < MCFGPIO_IRQ_MAX))
+#else
+       if (offset < MCFGPIO_IRQ_MAX)
+#endif
+               return MCFGPIO_IRQ_VECBASE + offset;
+       else
+               return -EINVAL;
+}
+
+static struct bus_type mcfgpio_subsys = {
+       .name           = "gpio",
+       .dev_name       = "gpio",
+};
+
+static struct gpio_chip mcfgpio_chip = {
+       .label                  = "mcfgpio",
+       .request                = mcfgpio_request,
+       .free                   = mcfgpio_free,
+       .direction_input        = mcfgpio_direction_input,
+       .direction_output       = mcfgpio_direction_output,
+       .get                    = mcfgpio_get_value,
+       .set                    = mcfgpio_set_value,
+       .to_irq                 = mcfgpio_to_irq,
+       .base                   = 0,
+       .ngpio                  = MCFGPIO_PIN_MAX,
+};
+
+static int __init mcfgpio_sysinit(void)
+{
+       gpiochip_add(&mcfgpio_chip);
+       return subsys_system_register(&mcfgpio_subsys, NULL);
+}
+
+core_initcall(mcfgpio_sysinit);
+#endif
diff --git a/arch/m68k/coldfire/head.S b/arch/m68k/coldfire/head.S
new file mode 100644 (file)
index 0000000..fa31be2
--- /dev/null
@@ -0,0 +1,298 @@
+/*****************************************************************************/
+
+/*
+ *     head.S -- common startup code for ColdFire CPUs.
+ *
+ *     (C) Copyright 1999-2011, Greg Ungerer <gerg@snapgear.com>.
+ */
+
+/*****************************************************************************/
+
+#include <linux/linkage.h>
+#include <linux/init.h>
+#include <asm/asm-offsets.h>
+#include <asm/coldfire.h>
+#include <asm/mcfsim.h>
+#include <asm/mcfmmu.h>
+#include <asm/thread_info.h>
+
+/*****************************************************************************/
+
+/*
+ *     If we don't have a fixed memory size, then lets build in code
+ *     to auto detect the DRAM size. Obviously this is the preferred
+ *     method, and should work for most boards. It won't work for those
+ *     that do not have their RAM starting at address 0, and it only
+ *     works on SDRAM (not boards fitted with SRAM).
+ */
+#if CONFIG_RAMSIZE != 0
+.macro GET_MEM_SIZE
+       movel   #CONFIG_RAMSIZE,%d0     /* hard coded memory size */
+.endm
+
+#elif defined(CONFIG_M5206) || defined(CONFIG_M5206e) || \
+      defined(CONFIG_M5249) || defined(CONFIG_M525x) || \
+      defined(CONFIG_M527x) || defined(CONFIG_M528x) || \
+      defined(CONFIG_M5307) || defined(CONFIG_M5407)
+/*
+ *     Not all these devices have exactly the same DRAM controller,
+ *     but the DCMR register is virtually identical - give or take
+ *     a couple of bits. The only exception is the 5272 devices, their
+ *     DRAM controller is quite different.
+ */
+.macro GET_MEM_SIZE
+       movel   MCFSIM_DMR0,%d0         /* get mask for 1st bank */
+       btst    #0,%d0                  /* check if region enabled */
+       beq     1f
+       andl    #0xfffc0000,%d0
+       beq     1f
+       addl    #0x00040000,%d0         /* convert mask to size */
+1:
+       movel   MCFSIM_DMR1,%d1         /* get mask for 2nd bank */
+       btst    #0,%d1                  /* check if region enabled */
+       beq     2f
+       andl    #0xfffc0000,%d1
+       beq     2f
+       addl    #0x00040000,%d1
+       addl    %d1,%d0                 /* total mem size in d0 */
+2:
+.endm
+
+#elif defined(CONFIG_M5272)
+.macro GET_MEM_SIZE
+       movel   MCFSIM_CSOR7,%d0        /* get SDRAM address mask */
+       andil   #0xfffff000,%d0         /* mask out chip select options */
+       negl    %d0                     /* negate bits */
+.endm
+
+#elif defined(CONFIG_M520x)
+.macro GET_MEM_SIZE
+       clrl    %d0
+       movel   MCFSIM_SDCS0, %d2       /* Get SDRAM chip select 0 config */
+       andl    #0x1f, %d2              /* Get only the chip select size */
+       beq     3f                      /* Check if it is enabled */
+       addql   #1, %d2                 /* Form exponent */
+       moveql  #1, %d0
+       lsll    %d2, %d0                /* 2 ^ exponent */
+3:
+       movel   MCFSIM_SDCS1, %d2       /* Get SDRAM chip select 1 config */
+       andl    #0x1f, %d2              /* Get only the chip select size */
+       beq     4f                      /* Check if it is enabled */
+       addql   #1, %d2                 /* Form exponent */
+       moveql  #1, %d1
+       lsll    %d2, %d1                /* 2 ^ exponent */
+       addl    %d1, %d0                /* Total size of SDRAM in d0 */
+4:
+.endm
+
+#else
+#error "ERROR: I don't know how to probe your boards memory size?"
+#endif
+
+/*****************************************************************************/
+
+/*
+ *     Boards and platforms can do specific early hardware setup if
+ *     they need to. Most don't need this, define away if not required.
+ */
+#ifndef PLATFORM_SETUP
+#define        PLATFORM_SETUP
+#endif
+
+/*****************************************************************************/
+
+.global        _start
+.global _rambase
+.global _ramvec
+.global        _ramstart
+.global        _ramend
+#if defined(CONFIG_UBOOT)
+.global        _init_sp
+#endif
+
+/*****************************************************************************/
+
+.data
+
+/*
+ *     During startup we store away the RAM setup. These are not in the
+ *     bss, since their values are determined and written before the bss
+ *     has been cleared.
+ */
+_rambase:
+.long  0
+_ramvec:
+.long  0
+_ramstart:
+.long  0
+_ramend:
+.long  0
+#if defined(CONFIG_UBOOT)
+_init_sp:
+.long  0
+#endif
+
+/*****************************************************************************/
+
+__HEAD
+
+#ifdef CONFIG_MMU
+_start0:
+       jmp     _start
+.global kernel_pg_dir
+.equ   kernel_pg_dir,_start0
+.equ   .,_start0+0x1000
+#endif
+
+/*
+ *     This is the codes first entry point. This is where it all
+ *     begins...
+ */
+
+_start:
+       nop                                     /* filler */
+       movew   #0x2700, %sr                    /* no interrupts */
+       movel   #CACHE_INIT,%d0                 /* disable cache */
+       movec   %d0,%CACR
+       nop
+#if defined(CONFIG_UBOOT)
+       movel   %sp,_init_sp                    /* save initial stack pointer */
+#endif
+#ifdef CONFIG_MBAR
+       movel   #CONFIG_MBAR+1,%d0              /* configured MBAR address */
+       movec   %d0,%MBAR                       /* set it */
+#endif
+
+       /*
+        *      Do any platform or board specific setup now. Most boards
+        *      don't need anything. Those exceptions are define this in
+        *      their board specific includes.
+        */
+       PLATFORM_SETUP
+
+       /*
+        *      Create basic memory configuration. Set VBR accordingly,
+        *      and size memory.
+        */
+       movel   #CONFIG_VECTORBASE,%a7
+       movec   %a7,%VBR                        /* set vectors addr */
+       movel   %a7,_ramvec
+
+       movel   #CONFIG_RAMBASE,%a7             /* mark the base of RAM */
+       movel   %a7,_rambase
+
+       GET_MEM_SIZE                            /* macro code determines size */
+       addl    %a7,%d0
+       movel   %d0,_ramend                     /* set end ram addr */
+
+       /*
+        *      Now that we know what the memory is, lets enable cache
+        *      and get things moving. This is Coldfire CPU specific. Not
+        *      all version cores have identical cache register setup. But
+        *      it is very similar. Define the exact settings in the headers
+        *      then the code here is the same for all.
+        */
+       movel   #ACR0_MODE,%d0                  /* set RAM region for caching */
+       movec   %d0,%ACR0
+       movel   #ACR1_MODE,%d0                  /* anything else to cache? */
+       movec   %d0,%ACR1
+#ifdef ACR2_MODE
+       movel   #ACR2_MODE,%d0
+       movec   %d0,%ACR2
+       movel   #ACR3_MODE,%d0
+       movec   %d0,%ACR3
+#endif
+       movel   #CACHE_MODE,%d0                 /* enable cache */
+       movec   %d0,%CACR
+       nop
+
+#ifdef CONFIG_MMU
+       /*
+        *      Identity mapping for the kernel region.
+        */
+       movel   #(MMUBASE+1),%d0                /* enable MMUBAR registers */
+       movec   %d0,%MMUBAR
+       movel   #MMUOR_CA,%d0                   /* clear TLB entries */
+       movel   %d0,MMUOR
+       movel   #0,%d0                          /* set ASID to 0 */
+       movec   %d0,%asid
+
+       movel   #MMUCR_EN,%d0                   /* Enable the identity map */
+       movel   %d0,MMUCR
+       nop                                     /* sync i-pipeline */
+
+       movel   #_vstart,%a0                    /* jump to "virtual" space */
+       jmp     %a0@
+_vstart:
+#endif /* CONFIG_MMU */
+
+#ifdef CONFIG_ROMFS_FS
+       /*
+        *      Move ROM filesystem above bss :-)
+        */
+       lea     __bss_start,%a0                 /* get start of bss */
+       lea     __bss_stop,%a1                  /* set up destination  */
+       movel   %a0,%a2                         /* copy of bss start */
+
+       movel   8(%a0),%d0                      /* get size of ROMFS */
+       addql   #8,%d0                          /* allow for rounding */
+       andl    #0xfffffffc, %d0                /* whole words */
+
+       addl    %d0,%a0                         /* copy from end */
+       addl    %d0,%a1                         /* copy from end */
+       movel   %a1,_ramstart                   /* set start of ram */
+
+_copy_romfs:
+       movel   -(%a0),%d0                      /* copy dword */
+       movel   %d0,-(%a1)
+       cmpl    %a0,%a2                         /* check if at end */
+       bne     _copy_romfs
+
+#else /* CONFIG_ROMFS_FS */
+       lea     __bss_stop,%a1
+       movel   %a1,_ramstart
+#endif /* CONFIG_ROMFS_FS */
+
+
+       /*
+        *      Zero out the bss region.
+        */
+       lea     __bss_start,%a0                 /* get start of bss */
+       lea     __bss_stop,%a1                  /* get end of bss */
+       clrl    %d0                             /* set value */
+_clear_bss:
+       movel   %d0,(%a0)+                      /* clear each word */
+       cmpl    %a0,%a1                         /* check if at end */
+       bne     _clear_bss
+
+       /*
+        *      Load the current task pointer and stack.
+        */
+       lea     init_thread_union,%a0
+       lea     THREAD_SIZE(%a0),%sp
+
+#ifdef CONFIG_MMU
+.global m68k_cputype
+.global m68k_mmutype
+.global m68k_fputype
+.global m68k_machtype
+       movel   #CPU_COLDFIRE,%d0
+       movel   %d0,m68k_cputype                /* Mark us as a ColdFire */
+       movel   #MMU_COLDFIRE,%d0
+       movel   %d0,m68k_mmutype
+       movel   #FPU_COLDFIRE,%d0
+       movel   %d0,m68k_fputype
+       movel   #MACH_M54XX,%d0
+       movel   %d0,m68k_machtype               /* Mark us as a 54xx machine */
+       lea     init_task,%a2                   /* Set "current" init task */
+#endif
+
+       /*
+        *      Assember start up done, start code proper.
+        */
+       jsr     start_kernel                    /* start Linux kernel */
+
+_exit:
+       jmp     _exit                           /* should never get here */
+
+/*****************************************************************************/
diff --git a/arch/m68k/coldfire/intc-2.c b/arch/m68k/coldfire/intc-2.c
new file mode 100644 (file)
index 0000000..9950933
--- /dev/null
@@ -0,0 +1,212 @@
+/*
+ * intc-2.c
+ *
+ * General interrupt controller code for the many ColdFire cores that use
+ * interrupt controllers with 63 interrupt sources, organized as 56 fully-
+ * programmable + 7 fixed-level interrupt sources. This includes the 523x
+ * family, the 5270, 5271, 5274, 5275, and the 528x family which have two such
+ * controllers, and the 547x and 548x families which have only one of them.
+ *
+ * The external 7 fixed interrupts are part the the Edge Port unit of these
+ * ColdFire parts. They can be configured as level or edge triggered.
+ *
+ * (C) Copyright 2009-2011, Greg Ungerer <gerg@snapgear.com>
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file COPYING in the main directory of this archive
+ * for more details.
+ */
+
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/io.h>
+#include <asm/coldfire.h>
+#include <asm/mcfsim.h>
+#include <asm/traps.h>
+
+/*
+ * Bit definitions for the ICR family of registers.
+ */
+#define MCFSIM_ICR_LEVEL(l)    ((l)<<3)        /* Level l intr */
+#define MCFSIM_ICR_PRI(p)      (p)             /* Priority p intr */
+
+/*
+ *     The EDGE Port interrupts are the fixed 7 external interrupts.
+ *     They need some special treatment, for example they need to be acked.
+ */
+#define        EINT0   64      /* Is not actually used, but spot reserved for it */
+#define        EINT1   65      /* EDGE Port interrupt 1 */
+#define        EINT7   71      /* EDGE Port interrupt 7 */
+
+#ifdef MCFICM_INTC1
+#define NR_VECS        128
+#else
+#define NR_VECS        64
+#endif
+
+static void intc_irq_mask(struct irq_data *d)
+{
+       unsigned int irq = d->irq - MCFINT_VECBASE;
+       unsigned long imraddr;
+       u32 val, imrbit;
+
+#ifdef MCFICM_INTC1
+       imraddr = (irq & 0x40) ? MCFICM_INTC1 : MCFICM_INTC0;
+#else
+       imraddr = MCFICM_INTC0;
+#endif
+       imraddr += (irq & 0x20) ? MCFINTC_IMRH : MCFINTC_IMRL;
+       imrbit = 0x1 << (irq & 0x1f);
+
+       val = __raw_readl(imraddr);
+       __raw_writel(val | imrbit, imraddr);
+}
+
+static void intc_irq_unmask(struct irq_data *d)
+{
+       unsigned int irq = d->irq - MCFINT_VECBASE;
+       unsigned long imraddr;
+       u32 val, imrbit;
+
+#ifdef MCFICM_INTC1
+       imraddr = (irq & 0x40) ? MCFICM_INTC1 : MCFICM_INTC0;
+#else
+       imraddr = MCFICM_INTC0;
+#endif
+       imraddr += ((irq & 0x20) ? MCFINTC_IMRH : MCFINTC_IMRL);
+       imrbit = 0x1 << (irq & 0x1f);
+
+       /* Don't set the "maskall" bit! */
+       if ((irq & 0x20) == 0)
+               imrbit |= 0x1;
+
+       val = __raw_readl(imraddr);
+       __raw_writel(val & ~imrbit, imraddr);
+}
+
+/*
+ *     Only the external (or EDGE Port) interrupts need to be acknowledged
+ *     here, as part of the IRQ handler. They only really need to be ack'ed
+ *     if they are in edge triggered mode, but there is no harm in doing it
+ *     for all types.
+ */
+static void intc_irq_ack(struct irq_data *d)
+{
+       unsigned int irq = d->irq;
+
+       __raw_writeb(0x1 << (irq - EINT0), MCFEPORT_EPFR);
+}
+
+/*
+ *     Each vector needs a unique priority and level associated with it.
+ *     We don't really care so much what they are, we don't rely on the
+ *     traditional priority interrupt scheme of the m68k/ColdFire. This
+ *     only needs to be set once for an interrupt, and we will never change
+ *     these values once we have set them.
+ */
+static u8 intc_intpri = MCFSIM_ICR_LEVEL(6) | MCFSIM_ICR_PRI(6);
+
+static unsigned int intc_irq_startup(struct irq_data *d)
+{
+       unsigned int irq = d->irq - MCFINT_VECBASE;
+       unsigned long icraddr;
+
+#ifdef MCFICM_INTC1
+       icraddr = (irq & 0x40) ? MCFICM_INTC1 : MCFICM_INTC0;
+#else
+       icraddr = MCFICM_INTC0;
+#endif
+       icraddr += MCFINTC_ICR0 + (irq & 0x3f);
+       if (__raw_readb(icraddr) == 0)
+               __raw_writeb(intc_intpri--, icraddr);
+
+       irq = d->irq;
+       if ((irq >= EINT1) && (irq <= EINT7)) {
+               u8 v;
+
+               irq -= EINT0;
+
+               /* Set EPORT line as input */
+               v = __raw_readb(MCFEPORT_EPDDR);
+               __raw_writeb(v & ~(0x1 << irq), MCFEPORT_EPDDR);
+
+               /* Set EPORT line as interrupt source */
+               v = __raw_readb(MCFEPORT_EPIER);
+               __raw_writeb(v | (0x1 << irq), MCFEPORT_EPIER);
+       }
+
+       intc_irq_unmask(d);
+       return 0;
+}
+
+static int intc_irq_set_type(struct irq_data *d, unsigned int type)
+{
+       unsigned int irq = d->irq;
+       u16 pa, tb;
+
+       switch (type) {
+       case IRQ_TYPE_EDGE_RISING:
+               tb = 0x1;
+               break;
+       case IRQ_TYPE_EDGE_FALLING:
+               tb = 0x2;
+               break;
+       case IRQ_TYPE_EDGE_BOTH:
+               tb = 0x3;
+               break;
+       default:
+               /* Level triggered */
+               tb = 0;
+               break;
+       }
+
+       if (tb)
+               irq_set_handler(irq, handle_edge_irq);
+
+       irq -= EINT0;
+       pa = __raw_readw(MCFEPORT_EPPAR);
+       pa = (pa & ~(0x3 << (irq * 2))) | (tb << (irq * 2));
+       __raw_writew(pa, MCFEPORT_EPPAR);
+       
+       return 0;
+}
+
+static struct irq_chip intc_irq_chip = {
+       .name           = "CF-INTC",
+       .irq_startup    = intc_irq_startup,
+       .irq_mask       = intc_irq_mask,
+       .irq_unmask     = intc_irq_unmask,
+};
+
+static struct irq_chip intc_irq_chip_edge_port = {
+       .name           = "CF-INTC-EP",
+       .irq_startup    = intc_irq_startup,
+       .irq_mask       = intc_irq_mask,
+       .irq_unmask     = intc_irq_unmask,
+       .irq_ack        = intc_irq_ack,
+       .irq_set_type   = intc_irq_set_type,
+};
+
+void __init init_IRQ(void)
+{
+       int irq;
+
+       /* Mask all interrupt sources */
+       __raw_writel(0x1, MCFICM_INTC0 + MCFINTC_IMRL);
+#ifdef MCFICM_INTC1
+       __raw_writel(0x1, MCFICM_INTC1 + MCFINTC_IMRL);
+#endif
+
+       for (irq = MCFINT_VECBASE; (irq < MCFINT_VECBASE + NR_VECS); irq++) {
+               if ((irq >= EINT1) && (irq <=EINT7))
+                       irq_set_chip(irq, &intc_irq_chip_edge_port);
+               else
+                       irq_set_chip(irq, &intc_irq_chip);
+               irq_set_irq_type(irq, IRQ_TYPE_LEVEL_HIGH);
+               irq_set_handler(irq, handle_level_irq);
+       }
+}
+
diff --git a/arch/m68k/coldfire/intc-5249.c b/arch/m68k/coldfire/intc-5249.c
new file mode 100644 (file)
index 0000000..b0d1641
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * intc2.c  -- support for the 2nd INTC controller of the 5249
+ *
+ * (C) Copyright 2009, Greg Ungerer <gerg@snapgear.com>
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file COPYING in the main directory of this archive
+ * for more details.
+ */
+
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/io.h>
+#include <asm/coldfire.h>
+#include <asm/mcfsim.h>
+
+static void intc2_irq_gpio_mask(struct irq_data *d)
+{
+       u32 imr;
+       imr = readl(MCFSIM2_GPIOINTENABLE);
+       imr &= ~(0x1 << (d->irq - MCF_IRQ_GPIO0));
+       writel(imr, MCFSIM2_GPIOINTENABLE);
+}
+
+static void intc2_irq_gpio_unmask(struct irq_data *d)
+{
+       u32 imr;
+       imr = readl(MCFSIM2_GPIOINTENABLE);
+       imr |= (0x1 << (d->irq - MCF_IRQ_GPIO0));
+       writel(imr, MCFSIM2_GPIOINTENABLE);
+}
+
+static void intc2_irq_gpio_ack(struct irq_data *d)
+{
+       writel(0x1 << (d->irq - MCF_IRQ_GPIO0), MCFSIM2_GPIOINTCLEAR);
+}
+
+static struct irq_chip intc2_irq_gpio_chip = {
+       .name           = "CF-INTC2",
+       .irq_mask       = intc2_irq_gpio_mask,
+       .irq_unmask     = intc2_irq_gpio_unmask,
+       .irq_ack        = intc2_irq_gpio_ack,
+};
+
+static int __init mcf_intc2_init(void)
+{
+       int irq;
+
+       /* GPIO interrupt sources */
+       for (irq = MCF_IRQ_GPIO0; (irq <= MCF_IRQ_GPIO7); irq++) {
+               irq_set_chip(irq, &intc2_irq_gpio_chip);
+               irq_set_handler(irq, handle_edge_irq);
+       }
+
+       return 0;
+}
+
+arch_initcall(mcf_intc2_init);
diff --git a/arch/m68k/coldfire/intc-525x.c b/arch/m68k/coldfire/intc-525x.c
new file mode 100644 (file)
index 0000000..b23204d
--- /dev/null
@@ -0,0 +1,91 @@
+/*
+ * intc2.c  -- support for the 2nd INTC controller of the 525x
+ *
+ * (C) Copyright 2012, Steven King <sfking@fdwdc.com>
+ * (C) Copyright 2009, Greg Ungerer <gerg@snapgear.com>
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file COPYING in the main directory of this archive
+ * for more details.
+ */
+
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/io.h>
+#include <asm/coldfire.h>
+#include <asm/mcfsim.h>
+
+static void intc2_irq_gpio_mask(struct irq_data *d)
+{
+       u32 imr = readl(MCFSIM2_GPIOINTENABLE);
+       u32 type = irqd_get_trigger_type(d);
+       int irq = d->irq - MCF_IRQ_GPIO0;
+
+       if (type & IRQ_TYPE_EDGE_RISING)
+               imr &= ~(0x001 << irq);
+       if (type & IRQ_TYPE_EDGE_FALLING)
+               imr &= ~(0x100 << irq);
+       writel(imr, MCFSIM2_GPIOINTENABLE);
+}
+
+static void intc2_irq_gpio_unmask(struct irq_data *d)
+{
+       u32 imr = readl(MCFSIM2_GPIOINTENABLE);
+       u32 type = irqd_get_trigger_type(d);
+       int irq = d->irq - MCF_IRQ_GPIO0;
+
+       if (type & IRQ_TYPE_EDGE_RISING)
+               imr |= (0x001 << irq);
+       if (type & IRQ_TYPE_EDGE_FALLING)
+               imr |= (0x100 << irq);
+       writel(imr, MCFSIM2_GPIOINTENABLE);
+}
+
+static void intc2_irq_gpio_ack(struct irq_data *d)
+{
+       u32 imr = 0;
+       u32 type = irqd_get_trigger_type(d);
+       int irq = d->irq - MCF_IRQ_GPIO0;
+
+       if (type & IRQ_TYPE_EDGE_RISING)
+               imr |= (0x001 << irq);
+       if (type & IRQ_TYPE_EDGE_FALLING)
+               imr |= (0x100 << irq);
+       writel(imr, MCFSIM2_GPIOINTCLEAR);
+}
+
+static int intc2_irq_gpio_set_type(struct irq_data *d, unsigned int f)
+{
+       if (f & ~IRQ_TYPE_EDGE_BOTH)
+               return -EINVAL;
+       return 0;
+}
+
+static struct irq_chip intc2_irq_gpio_chip = {
+       .name           = "CF-INTC2",
+       .irq_mask       = intc2_irq_gpio_mask,
+       .irq_unmask     = intc2_irq_gpio_unmask,
+       .irq_ack        = intc2_irq_gpio_ack,
+       .irq_set_type   = intc2_irq_gpio_set_type,
+};
+
+static int __init mcf_intc2_init(void)
+{
+       int irq;
+
+       /* set the interrupt base for the second interrupt controller */
+       writel(MCFINTC2_VECBASE, MCFINTC2_INTBASE);
+
+       /* GPIO interrupt sources */
+       for (irq = MCF_IRQ_GPIO0; (irq <= MCF_IRQ_GPIO6); irq++) {
+               irq_set_chip(irq, &intc2_irq_gpio_chip);
+               irq_set_handler(irq, handle_edge_irq);
+       }
+
+       return 0;
+}
+
+arch_initcall(mcf_intc2_init);
diff --git a/arch/m68k/coldfire/intc-5272.c b/arch/m68k/coldfire/intc-5272.c
new file mode 100644 (file)
index 0000000..d1e2fba
--- /dev/null
@@ -0,0 +1,185 @@
+/*
+ * intc.c  --  interrupt controller or ColdFire 5272 SoC
+ *
+ * (C) Copyright 2009, Greg Ungerer <gerg@snapgear.com>
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file COPYING in the main directory of this archive
+ * for more details.
+ */
+
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/interrupt.h>
+#include <linux/kernel_stat.h>
+#include <linux/irq.h>
+#include <linux/io.h>
+#include <asm/coldfire.h>
+#include <asm/mcfsim.h>
+#include <asm/traps.h>
+
+/*
+ * The 5272 ColdFire interrupt controller is nothing like any other
+ * ColdFire interrupt controller - it truly is completely different.
+ * Given its age it is unlikely to be used on any other ColdFire CPU.
+ */
+
+/*
+ * The masking and priproty setting of interrupts on the 5272 is done
+ * via a set of 4 "Interrupt Controller Registers" (ICR). There is a
+ * loose mapping of vector number to register and internal bits, but
+ * a table is the easiest and quickest way to map them.
+ *
+ * Note that the external interrupts are edge triggered (unlike the
+ * internal interrupt sources which are level triggered). Which means
+ * they also need acknowledging via acknowledge bits.
+ */
+struct irqmap {
+       unsigned int    icr;
+       unsigned char   index;
+       unsigned char   ack;
+};
+
+static struct irqmap intc_irqmap[MCFINT_VECMAX - MCFINT_VECBASE] = {
+       /*MCF_IRQ_SPURIOUS*/    { .icr = 0,           .index = 0,  .ack = 0, },
+       /*MCF_IRQ_EINT1*/       { .icr = MCFSIM_ICR1, .index = 28, .ack = 1, },
+       /*MCF_IRQ_EINT2*/       { .icr = MCFSIM_ICR1, .index = 24, .ack = 1, },
+       /*MCF_IRQ_EINT3*/       { .icr = MCFSIM_ICR1, .index = 20, .ack = 1, },
+       /*MCF_IRQ_EINT4*/       { .icr = MCFSIM_ICR1, .index = 16, .ack = 1, },
+       /*MCF_IRQ_TIMER1*/      { .icr = MCFSIM_ICR1, .index = 12, .ack = 0, },
+       /*MCF_IRQ_TIMER2*/      { .icr = MCFSIM_ICR1, .index = 8,  .ack = 0, },
+       /*MCF_IRQ_TIMER3*/      { .icr = MCFSIM_ICR1, .index = 4,  .ack = 0, },
+       /*MCF_IRQ_TIMER4*/      { .icr = MCFSIM_ICR1, .index = 0,  .ack = 0, },
+       /*MCF_IRQ_UART1*/       { .icr = MCFSIM_ICR2, .index = 28, .ack = 0, },
+       /*MCF_IRQ_UART2*/       { .icr = MCFSIM_ICR2, .index = 24, .ack = 0, },
+       /*MCF_IRQ_PLIP*/        { .icr = MCFSIM_ICR2, .index = 20, .ack = 0, },
+       /*MCF_IRQ_PLIA*/        { .icr = MCFSIM_ICR2, .index = 16, .ack = 0, },
+       /*MCF_IRQ_USB0*/        { .icr = MCFSIM_ICR2, .index = 12, .ack = 0, },
+       /*MCF_IRQ_USB1*/        { .icr = MCFSIM_ICR2, .index = 8,  .ack = 0, },
+       /*MCF_IRQ_USB2*/        { .icr = MCFSIM_ICR2, .index = 4,  .ack = 0, },
+       /*MCF_IRQ_USB3*/        { .icr = MCFSIM_ICR2, .index = 0,  .ack = 0, },
+       /*MCF_IRQ_USB4*/        { .icr = MCFSIM_ICR3, .index = 28, .ack = 0, },
+       /*MCF_IRQ_USB5*/        { .icr = MCFSIM_ICR3, .index = 24, .ack = 0, },
+       /*MCF_IRQ_USB6*/        { .icr = MCFSIM_ICR3, .index = 20, .ack = 0, },
+       /*MCF_IRQ_USB7*/        { .icr = MCFSIM_ICR3, .index = 16, .ack = 0, },
+       /*MCF_IRQ_DMA*/         { .icr = MCFSIM_ICR3, .index = 12, .ack = 0, },
+       /*MCF_IRQ_ERX*/         { .icr = MCFSIM_ICR3, .index = 8,  .ack = 0, },
+       /*MCF_IRQ_ETX*/         { .icr = MCFSIM_ICR3, .index = 4,  .ack = 0, },
+       /*MCF_IRQ_ENTC*/        { .icr = MCFSIM_ICR3, .index = 0,  .ack = 0, },
+       /*MCF_IRQ_QSPI*/        { .icr = MCFSIM_ICR4, .index = 28, .ack = 0, },
+       /*MCF_IRQ_EINT5*/       { .icr = MCFSIM_ICR4, .index = 24, .ack = 1, },
+       /*MCF_IRQ_EINT6*/       { .icr = MCFSIM_ICR4, .index = 20, .ack = 1, },
+       /*MCF_IRQ_SWTO*/        { .icr = MCFSIM_ICR4, .index = 16, .ack = 0, },
+};
+
+/*
+ * The act of masking the interrupt also has a side effect of 'ack'ing
+ * an interrupt on this irq (for the external irqs). So this mask function
+ * is also an ack_mask function.
+ */
+static void intc_irq_mask(struct irq_data *d)
+{
+       unsigned int irq = d->irq;
+
+       if ((irq >= MCFINT_VECBASE) && (irq <= MCFINT_VECMAX)) {
+               u32 v;
+               irq -= MCFINT_VECBASE;
+               v = 0x8 << intc_irqmap[irq].index;
+               writel(v, intc_irqmap[irq].icr);
+       }
+}
+
+static void intc_irq_unmask(struct irq_data *d)
+{
+       unsigned int irq = d->irq;
+
+       if ((irq >= MCFINT_VECBASE) && (irq <= MCFINT_VECMAX)) {
+               u32 v;
+               irq -= MCFINT_VECBASE;
+               v = 0xd << intc_irqmap[irq].index;
+               writel(v, intc_irqmap[irq].icr);
+       }
+}
+
+static void intc_irq_ack(struct irq_data *d)
+{
+       unsigned int irq = d->irq;
+
+       /* Only external interrupts are acked */
+       if ((irq >= MCFINT_VECBASE) && (irq <= MCFINT_VECMAX)) {
+               irq -= MCFINT_VECBASE;
+               if (intc_irqmap[irq].ack) {
+                       u32 v;
+                       v = readl(intc_irqmap[irq].icr);
+                       v &= (0x7 << intc_irqmap[irq].index);
+                       v |= (0x8 << intc_irqmap[irq].index);
+                       writel(v, intc_irqmap[irq].icr);
+               }
+       }
+}
+
+static int intc_irq_set_type(struct irq_data *d, unsigned int type)
+{
+       unsigned int irq = d->irq;
+
+       if ((irq >= MCFINT_VECBASE) && (irq <= MCFINT_VECMAX)) {
+               irq -= MCFINT_VECBASE;
+               if (intc_irqmap[irq].ack) {
+                       u32 v;
+                       v = readl(MCFSIM_PITR);
+                       if (type == IRQ_TYPE_EDGE_FALLING)
+                               v &= ~(0x1 << (32 - irq));
+                       else
+                               v |= (0x1 << (32 - irq));
+                       writel(v, MCFSIM_PITR);
+               }
+       }
+       return 0;
+}
+
+/*
+ * Simple flow handler to deal with the external edge triggered interrupts.
+ * We need to be careful with the masking/acking due to the side effects
+ * of masking an interrupt.
+ */
+static void intc_external_irq(unsigned int irq, struct irq_desc *desc)
+{
+       irq_desc_get_chip(desc)->irq_ack(&desc->irq_data);
+       handle_simple_irq(irq, desc);
+}
+
+static struct irq_chip intc_irq_chip = {
+       .name           = "CF-INTC",
+       .irq_mask       = intc_irq_mask,
+       .irq_unmask     = intc_irq_unmask,
+       .irq_mask_ack   = intc_irq_mask,
+       .irq_ack        = intc_irq_ack,
+       .irq_set_type   = intc_irq_set_type,
+};
+
+void __init init_IRQ(void)
+{
+       int irq, edge;
+
+       /* Mask all interrupt sources */
+       writel(0x88888888, MCFSIM_ICR1);
+       writel(0x88888888, MCFSIM_ICR2);
+       writel(0x88888888, MCFSIM_ICR3);
+       writel(0x88888888, MCFSIM_ICR4);
+
+       for (irq = 0; (irq < NR_IRQS); irq++) {
+               irq_set_chip(irq, &intc_irq_chip);
+               edge = 0;
+               if ((irq >= MCFINT_VECBASE) && (irq <= MCFINT_VECMAX))
+                       edge = intc_irqmap[irq - MCFINT_VECBASE].ack;
+               if (edge) {
+                       irq_set_irq_type(irq, IRQ_TYPE_EDGE_RISING);
+                       irq_set_handler(irq, intc_external_irq);
+               } else {
+                       irq_set_irq_type(irq, IRQ_TYPE_LEVEL_HIGH);
+                       irq_set_handler(irq, handle_level_irq);
+               }
+       }
+}
+
diff --git a/arch/m68k/coldfire/intc-simr.c b/arch/m68k/coldfire/intc-simr.c
new file mode 100644 (file)
index 0000000..7cf2c15
--- /dev/null
@@ -0,0 +1,199 @@
+/*
+ * intc-simr.c
+ *
+ * Interrupt controller code for the ColdFire 5208, 5207 & 532x parts.
+ *
+ * (C) Copyright 2009-2011, Greg Ungerer <gerg@snapgear.com>
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file COPYING in the main directory of this archive
+ * for more details.
+ */
+
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/io.h>
+#include <asm/coldfire.h>
+#include <asm/mcfsim.h>
+#include <asm/traps.h>
+
+/*
+ *     The EDGE Port interrupts are the fixed 7 external interrupts.
+ *     They need some special treatment, for example they need to be acked.
+ */
+#ifdef CONFIG_M520x
+/*
+ *     The 520x parts only support a limited range of these external
+ *     interrupts, only 1, 4 and 7 (as interrupts 65, 66 and 67).
+ */
+#define        EINT0   64      /* Is not actually used, but spot reserved for it */
+#define        EINT1   65      /* EDGE Port interrupt 1 */
+#define        EINT4   66      /* EDGE Port interrupt 4 */
+#define        EINT7   67      /* EDGE Port interrupt 7 */
+
+static unsigned int irqebitmap[] = { 0, 1, 4, 7 };
+static unsigned int inline irq2ebit(unsigned int irq)
+{
+       return irqebitmap[irq - EINT0];
+}
+
+#else
+
+/*
+ *     Most of the ColdFire parts with the EDGE Port module just have
+ *     a strait direct mapping of the 7 external interrupts. Although
+ *     there is a bit reserved for 0, it is not used.
+ */
+#define        EINT0   64      /* Is not actually used, but spot reserved for it */
+#define        EINT1   65      /* EDGE Port interrupt 1 */
+#define        EINT7   71      /* EDGE Port interrupt 7 */
+
+static unsigned int inline irq2ebit(unsigned int irq)
+{
+       return irq - EINT0;
+}
+
+#endif
+
+/*
+ *     There maybe one, two or three interrupt control units, each has 64
+ *     interrupts. If there is no second or third unit then MCFINTC1_* or
+ *     MCFINTC2_* defines will be 0 (and code for them optimized away).
+ */
+
+static void intc_irq_mask(struct irq_data *d)
+{
+       unsigned int irq = d->irq - MCFINT_VECBASE;
+
+       if (MCFINTC2_SIMR && (irq > 128))
+               __raw_writeb(irq - 128, MCFINTC2_SIMR);
+       else if (MCFINTC1_SIMR && (irq > 64))
+               __raw_writeb(irq - 64, MCFINTC1_SIMR);
+       else
+               __raw_writeb(irq, MCFINTC0_SIMR);
+}
+
+static void intc_irq_unmask(struct irq_data *d)
+{
+       unsigned int irq = d->irq - MCFINT_VECBASE;
+
+       if (MCFINTC2_CIMR && (irq > 128))
+               __raw_writeb(irq - 128, MCFINTC2_CIMR);
+       else if (MCFINTC1_CIMR && (irq > 64))
+               __raw_writeb(irq - 64, MCFINTC1_CIMR);
+       else
+               __raw_writeb(irq, MCFINTC0_CIMR);
+}
+
+static void intc_irq_ack(struct irq_data *d)
+{
+       unsigned int ebit = irq2ebit(d->irq);
+
+       __raw_writeb(0x1 << ebit, MCFEPORT_EPFR);
+}
+
+static unsigned int intc_irq_startup(struct irq_data *d)
+{
+       unsigned int irq = d->irq;
+
+       if ((irq >= EINT1) && (irq <= EINT7)) {
+               unsigned int ebit = irq2ebit(irq);
+               u8 v;
+
+#if defined(MCFEPORT_EPDDR)
+               /* Set EPORT line as input */
+               v = __raw_readb(MCFEPORT_EPDDR);
+               __raw_writeb(v & ~(0x1 << ebit), MCFEPORT_EPDDR);
+#endif
+
+               /* Set EPORT line as interrupt source */
+               v = __raw_readb(MCFEPORT_EPIER);
+               __raw_writeb(v | (0x1 << ebit), MCFEPORT_EPIER);
+       }
+
+       irq -= MCFINT_VECBASE;
+       if (MCFINTC2_ICR0 && (irq > 128))
+               __raw_writeb(5, MCFINTC2_ICR0 + irq - 128);
+       else if (MCFINTC1_ICR0 && (irq > 64))
+               __raw_writeb(5, MCFINTC1_ICR0 + irq - 64);
+       else
+               __raw_writeb(5, MCFINTC0_ICR0 + irq);
+
+       intc_irq_unmask(d);
+       return 0;
+}
+
+static int intc_irq_set_type(struct irq_data *d, unsigned int type)
+{
+       unsigned int ebit, irq = d->irq;
+       u16 pa, tb;
+
+       switch (type) {
+       case IRQ_TYPE_EDGE_RISING:
+               tb = 0x1;
+               break;
+       case IRQ_TYPE_EDGE_FALLING:
+               tb = 0x2;
+               break;
+       case IRQ_TYPE_EDGE_BOTH:
+               tb = 0x3;
+               break;
+       default:
+               /* Level triggered */
+               tb = 0;
+               break;
+       }
+
+       if (tb)
+               irq_set_handler(irq, handle_edge_irq);
+
+       ebit = irq2ebit(irq) * 2;
+       pa = __raw_readw(MCFEPORT_EPPAR);
+       pa = (pa & ~(0x3 << ebit)) | (tb << ebit);
+       __raw_writew(pa, MCFEPORT_EPPAR);
+       
+       return 0;
+}
+
+static struct irq_chip intc_irq_chip = {
+       .name           = "CF-INTC",
+       .irq_startup    = intc_irq_startup,
+       .irq_mask       = intc_irq_mask,
+       .irq_unmask     = intc_irq_unmask,
+};
+
+static struct irq_chip intc_irq_chip_edge_port = {
+       .name           = "CF-INTC-EP",
+       .irq_startup    = intc_irq_startup,
+       .irq_mask       = intc_irq_mask,
+       .irq_unmask     = intc_irq_unmask,
+       .irq_ack        = intc_irq_ack,
+       .irq_set_type   = intc_irq_set_type,
+};
+
+void __init init_IRQ(void)
+{
+       int irq, eirq;
+
+       /* Mask all interrupt sources */
+       __raw_writeb(0xff, MCFINTC0_SIMR);
+       if (MCFINTC1_SIMR)
+               __raw_writeb(0xff, MCFINTC1_SIMR);
+       if (MCFINTC2_SIMR)
+               __raw_writeb(0xff, MCFINTC2_SIMR);
+
+       eirq = MCFINT_VECBASE + 64 + (MCFINTC1_ICR0 ? 64 : 0) +
+                                               (MCFINTC2_ICR0 ? 64 : 0);
+       for (irq = MCFINT_VECBASE; (irq < eirq); irq++) {
+               if ((irq >= EINT1) && (irq <= EINT7))
+                       irq_set_chip(irq, &intc_irq_chip_edge_port);
+               else
+                       irq_set_chip(irq, &intc_irq_chip);
+               irq_set_irq_type(irq, IRQ_TYPE_LEVEL_HIGH);
+               irq_set_handler(irq, handle_level_irq);
+       }
+}
+
diff --git a/arch/m68k/coldfire/intc.c b/arch/m68k/coldfire/intc.c
new file mode 100644 (file)
index 0000000..cce2574
--- /dev/null
@@ -0,0 +1,150 @@
+/*
+ * intc.c  -- support for the old ColdFire interrupt controller
+ *
+ * (C) Copyright 2009, Greg Ungerer <gerg@snapgear.com>
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file COPYING in the main directory of this archive
+ * for more details.
+ */
+
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/io.h>
+#include <asm/traps.h>
+#include <asm/coldfire.h>
+#include <asm/mcfsim.h>
+
+/*
+ * The mapping of irq number to a mask register bit is not one-to-one.
+ * The irq numbers are either based on "level" of interrupt or fixed
+ * for an autovector-able interrupt. So we keep a local data structure
+ * that maps from irq to mask register. Not all interrupts will have
+ * an IMR bit.
+ */
+unsigned char mcf_irq2imr[NR_IRQS];
+
+/*
+ * Define the miniumun and maximum external interrupt numbers.
+ * This is also used as the "level" interrupt numbers.
+ */
+#define        EIRQ1   25
+#define        EIRQ7   31
+
+/*
+ * In the early version 2 core ColdFire parts the IMR register was 16 bits
+ * in size. Version 3 (and later version 2) core parts have a 32 bit
+ * sized IMR register. Provide some size independent methods to access the
+ * IMR register.
+ */
+#ifdef MCFSIM_IMR_IS_16BITS
+
+void mcf_setimr(int index)
+{
+       u16 imr;
+       imr = __raw_readw(MCFSIM_IMR);
+       __raw_writew(imr | (0x1 << index), MCFSIM_IMR);
+}
+
+void mcf_clrimr(int index)
+{
+       u16 imr;
+       imr = __raw_readw(MCFSIM_IMR);
+       __raw_writew(imr & ~(0x1 << index), MCFSIM_IMR);
+}
+
+void mcf_maskimr(unsigned int mask)
+{
+       u16 imr;
+       imr = __raw_readw(MCFSIM_IMR);
+       imr |= mask;
+       __raw_writew(imr, MCFSIM_IMR);
+}
+
+#else
+
+void mcf_setimr(int index)
+{
+       u32 imr;
+       imr = __raw_readl(MCFSIM_IMR);
+       __raw_writel(imr | (0x1 << index), MCFSIM_IMR);
+}
+
+void mcf_clrimr(int index)
+{
+       u32 imr;
+       imr = __raw_readl(MCFSIM_IMR);
+       __raw_writel(imr & ~(0x1 << index), MCFSIM_IMR);
+}
+
+void mcf_maskimr(unsigned int mask)
+{
+       u32 imr;
+       imr = __raw_readl(MCFSIM_IMR);
+       imr |= mask;
+       __raw_writel(imr, MCFSIM_IMR);
+}
+
+#endif
+
+/*
+ * Interrupts can be "vectored" on the ColdFire cores that support this old
+ * interrupt controller. That is, the device raising the interrupt can also
+ * supply the vector number to interrupt through. The AVR register of the
+ * interrupt controller enables or disables this for each external interrupt,
+ * so provide generic support for this. Setting this up is out-of-band for
+ * the interrupt system API's, and needs to be done by the driver that
+ * supports this device. Very few devices actually use this.
+ */
+void mcf_autovector(int irq)
+{
+#ifdef MCFSIM_AVR
+       if ((irq >= EIRQ1) && (irq <= EIRQ7)) {
+               u8 avec;
+               avec = __raw_readb(MCFSIM_AVR);
+               avec |= (0x1 << (irq - EIRQ1 + 1));
+               __raw_writeb(avec, MCFSIM_AVR);
+       }
+#endif
+}
+
+static void intc_irq_mask(struct irq_data *d)
+{
+       if (mcf_irq2imr[d->irq])
+               mcf_setimr(mcf_irq2imr[d->irq]);
+}
+
+static void intc_irq_unmask(struct irq_data *d)
+{
+       if (mcf_irq2imr[d->irq])
+               mcf_clrimr(mcf_irq2imr[d->irq]);
+}
+
+static int intc_irq_set_type(struct irq_data *d, unsigned int type)
+{
+       return 0;
+}
+
+static struct irq_chip intc_irq_chip = {
+       .name           = "CF-INTC",
+       .irq_mask       = intc_irq_mask,
+       .irq_unmask     = intc_irq_unmask,
+       .irq_set_type   = intc_irq_set_type,
+};
+
+void __init init_IRQ(void)
+{
+       int irq;
+
+       mcf_maskimr(0xffffffff);
+
+       for (irq = 0; (irq < NR_IRQS); irq++) {
+               irq_set_chip(irq, &intc_irq_chip);
+               irq_set_irq_type(irq, IRQ_TYPE_LEVEL_HIGH);
+               irq_set_handler(irq, handle_level_irq);
+       }
+}
+
diff --git a/arch/m68k/coldfire/m5206.c b/arch/m68k/coldfire/m5206.c
new file mode 100644 (file)
index 0000000..8945f5e
--- /dev/null
@@ -0,0 +1,58 @@
+/***************************************************************************/
+
+/*
+ *     m5206.c  -- platform support for ColdFire 5206 based boards
+ *
+ *     Copyright (C) 1999-2002, Greg Ungerer (gerg@snapgear.com)
+ *     Copyright (C) 2000-2001, Lineo Inc. (www.lineo.com) 
+ */
+
+/***************************************************************************/
+
+#include <linux/kernel.h>
+#include <linux/param.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <asm/machdep.h>
+#include <asm/coldfire.h>
+#include <asm/mcfsim.h>
+#include <asm/mcfclk.h>
+
+/***************************************************************************/
+
+DEFINE_CLK(pll, "pll.0", MCF_CLK);
+DEFINE_CLK(sys, "sys.0", MCF_BUSCLK);
+DEFINE_CLK(mcftmr0, "mcftmr.0", MCF_BUSCLK);
+DEFINE_CLK(mcftmr1, "mcftmr.1", MCF_BUSCLK);
+DEFINE_CLK(mcfuart0, "mcfuart.0", MCF_BUSCLK);
+DEFINE_CLK(mcfuart1, "mcfuart.1", MCF_BUSCLK);
+
+struct clk *mcf_clks[] = {
+       &clk_pll,
+       &clk_sys,
+       &clk_mcftmr0,
+       &clk_mcftmr1,
+       &clk_mcfuart0,
+       &clk_mcfuart1,
+       NULL
+};
+
+/***************************************************************************/
+
+void __init config_BSP(char *commandp, int size)
+{
+#if defined(CONFIG_NETtel)
+       /* Copy command line from FLASH to local buffer... */
+       memcpy(commandp, (char *) 0xf0004000, size);
+       commandp[size-1] = 0;
+#endif /* CONFIG_NETtel */
+
+       mach_sched_init = hw_timer_init;
+
+       /* Only support the external interrupts on their primary level */
+       mcf_mapirq2imr(25, MCFINTC_EINT1);
+       mcf_mapirq2imr(28, MCFINTC_EINT4);
+       mcf_mapirq2imr(31, MCFINTC_EINT7);
+}
+
+/***************************************************************************/
diff --git a/arch/m68k/coldfire/m520x.c b/arch/m68k/coldfire/m520x.c
new file mode 100644 (file)
index 0000000..173834f
--- /dev/null
@@ -0,0 +1,180 @@
+/***************************************************************************/
+
+/*
+ *  m520x.c  -- platform support for ColdFire 520x based boards
+ *
+ *  Copyright (C) 2005,      Freescale (www.freescale.com)
+ *  Copyright (C) 2005,      Intec Automation (mike@steroidmicros.com)
+ *  Copyright (C) 1999-2007, Greg Ungerer (gerg@snapgear.com)
+ *  Copyright (C) 2001-2003, SnapGear Inc. (www.snapgear.com)
+ */
+
+/***************************************************************************/
+
+#include <linux/kernel.h>
+#include <linux/param.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <asm/machdep.h>
+#include <asm/coldfire.h>
+#include <asm/mcfsim.h>
+#include <asm/mcfuart.h>
+#include <asm/mcfclk.h>
+
+/***************************************************************************/
+
+DEFINE_CLK(0, "flexbus", 2, MCF_CLK);
+DEFINE_CLK(0, "fec.0", 12, MCF_CLK);
+DEFINE_CLK(0, "edma", 17, MCF_CLK);
+DEFINE_CLK(0, "intc.0", 18, MCF_CLK);
+DEFINE_CLK(0, "iack.0", 21, MCF_CLK);
+DEFINE_CLK(0, "mcfi2c.0", 22, MCF_CLK);
+DEFINE_CLK(0, "mcfqspi.0", 23, MCF_CLK);
+DEFINE_CLK(0, "mcfuart.0", 24, MCF_BUSCLK);
+DEFINE_CLK(0, "mcfuart.1", 25, MCF_BUSCLK);
+DEFINE_CLK(0, "mcfuart.2", 26, MCF_BUSCLK);
+DEFINE_CLK(0, "mcftmr.0", 28, MCF_CLK);
+DEFINE_CLK(0, "mcftmr.1", 29, MCF_CLK);
+DEFINE_CLK(0, "mcftmr.2", 30, MCF_CLK);
+DEFINE_CLK(0, "mcftmr.3", 31, MCF_CLK);
+
+DEFINE_CLK(0, "mcfpit.0", 32, MCF_CLK);
+DEFINE_CLK(0, "mcfpit.1", 33, MCF_CLK);
+DEFINE_CLK(0, "mcfeport.0", 34, MCF_CLK);
+DEFINE_CLK(0, "mcfwdt.0", 35, MCF_CLK);
+DEFINE_CLK(0, "pll.0", 36, MCF_CLK);
+DEFINE_CLK(0, "sys.0", 40, MCF_BUSCLK);
+DEFINE_CLK(0, "gpio.0", 41, MCF_BUSCLK);
+DEFINE_CLK(0, "sdram.0", 42, MCF_CLK);
+
+struct clk *mcf_clks[] = {
+       &__clk_0_2, /* flexbus */
+       &__clk_0_12, /* fec.0 */
+       &__clk_0_17, /* edma */
+       &__clk_0_18, /* intc.0 */
+       &__clk_0_21, /* iack.0 */
+       &__clk_0_22, /* mcfi2c.0 */
+       &__clk_0_23, /* mcfqspi.0 */
+       &__clk_0_24, /* mcfuart.0 */
+       &__clk_0_25, /* mcfuart.1 */
+       &__clk_0_26, /* mcfuart.2 */
+       &__clk_0_28, /* mcftmr.0 */
+       &__clk_0_29, /* mcftmr.1 */
+       &__clk_0_30, /* mcftmr.2 */
+       &__clk_0_31, /* mcftmr.3 */
+
+       &__clk_0_32, /* mcfpit.0 */
+       &__clk_0_33, /* mcfpit.1 */
+       &__clk_0_34, /* mcfeport.0 */
+       &__clk_0_35, /* mcfwdt.0 */
+       &__clk_0_36, /* pll.0 */
+       &__clk_0_40, /* sys.0 */
+       &__clk_0_41, /* gpio.0 */
+       &__clk_0_42, /* sdram.0 */
+NULL,
+};
+
+static struct clk * const enable_clks[] __initconst = {
+       &__clk_0_2, /* flexbus */
+       &__clk_0_18, /* intc.0 */
+       &__clk_0_21, /* iack.0 */
+       &__clk_0_24, /* mcfuart.0 */
+       &__clk_0_25, /* mcfuart.1 */
+       &__clk_0_26, /* mcfuart.2 */
+
+       &__clk_0_32, /* mcfpit.0 */
+       &__clk_0_33, /* mcfpit.1 */
+       &__clk_0_34, /* mcfeport.0 */
+       &__clk_0_36, /* pll.0 */
+       &__clk_0_40, /* sys.0 */
+       &__clk_0_41, /* gpio.0 */
+       &__clk_0_42, /* sdram.0 */
+};
+
+static struct clk * const disable_clks[] __initconst = {
+       &__clk_0_12, /* fec.0 */
+       &__clk_0_17, /* edma */
+       &__clk_0_22, /* mcfi2c.0 */
+       &__clk_0_23, /* mcfqspi.0 */
+       &__clk_0_28, /* mcftmr.0 */
+       &__clk_0_29, /* mcftmr.1 */
+       &__clk_0_30, /* mcftmr.2 */
+       &__clk_0_31, /* mcftmr.3 */
+       &__clk_0_35, /* mcfwdt.0 */
+};
+
+
+static void __init m520x_clk_init(void)
+{
+       unsigned i;
+
+       /* make sure these clocks are enabled */
+       for (i = 0; i < ARRAY_SIZE(enable_clks); ++i)
+               __clk_init_enabled(enable_clks[i]);
+       /* make sure these clocks are disabled */
+       for (i = 0; i < ARRAY_SIZE(disable_clks); ++i)
+               __clk_init_disabled(disable_clks[i]);
+}
+
+/***************************************************************************/
+
+static void __init m520x_qspi_init(void)
+{
+#if IS_ENABLED(CONFIG_SPI_COLDFIRE_QSPI)
+       u16 par;
+       /* setup Port QS for QSPI with gpio CS control */
+       writeb(0x3f, MCF_GPIO_PAR_QSPI);
+       /* make U1CTS and U2RTS gpio for cs_control */
+       par = readw(MCF_GPIO_PAR_UART);
+       par &= 0x00ff;
+       writew(par, MCF_GPIO_PAR_UART);
+#endif /* IS_ENABLED(CONFIG_SPI_COLDFIRE_QSPI) */
+}
+
+/***************************************************************************/
+
+static void __init m520x_uarts_init(void)
+{
+       u16 par;
+       u8 par2;
+
+       /* UART0 and UART1 GPIO pin setup */
+       par = readw(MCF_GPIO_PAR_UART);
+       par |= MCF_GPIO_PAR_UART_PAR_UTXD0 | MCF_GPIO_PAR_UART_PAR_URXD0;
+       par |= MCF_GPIO_PAR_UART_PAR_UTXD1 | MCF_GPIO_PAR_UART_PAR_URXD1;
+       writew(par, MCF_GPIO_PAR_UART);
+
+       /* UART1 GPIO pin setup */
+       par2 = readb(MCF_GPIO_PAR_FECI2C);
+       par2 &= ~0x0F;
+       par2 |= MCF_GPIO_PAR_FECI2C_PAR_SCL_UTXD2 |
+               MCF_GPIO_PAR_FECI2C_PAR_SDA_URXD2;
+       writeb(par2, MCF_GPIO_PAR_FECI2C);
+}
+
+/***************************************************************************/
+
+static void __init m520x_fec_init(void)
+{
+       u8 v;
+
+       /* Set multi-function pins to ethernet mode */
+       v = readb(MCF_GPIO_PAR_FEC);
+       writeb(v | 0xf0, MCF_GPIO_PAR_FEC);
+
+       v = readb(MCF_GPIO_PAR_FECI2C);
+       writeb(v | 0x0f, MCF_GPIO_PAR_FECI2C);
+}
+
+/***************************************************************************/
+
+void __init config_BSP(char *commandp, int size)
+{
+       mach_sched_init = hw_timer_init;
+       m520x_clk_init();
+       m520x_uarts_init();
+       m520x_fec_init();
+       m520x_qspi_init();
+}
+
+/***************************************************************************/
diff --git a/arch/m68k/coldfire/m523x.c b/arch/m68k/coldfire/m523x.c
new file mode 100644 (file)
index 0000000..a191a46
--- /dev/null
@@ -0,0 +1,86 @@
+/***************************************************************************/
+
+/*
+ *     m523x.c  -- platform support for ColdFire 523x based boards
+ *
+ *     Sub-architcture dependent initialization code for the Freescale
+ *     523x CPUs.
+ *
+ *     Copyright (C) 1999-2005, Greg Ungerer (gerg@snapgear.com)
+ *     Copyright (C) 2001-2003, SnapGear Inc. (www.snapgear.com)
+ */
+
+/***************************************************************************/
+
+#include <linux/kernel.h>
+#include <linux/param.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <asm/machdep.h>
+#include <asm/coldfire.h>
+#include <asm/mcfsim.h>
+#include <asm/mcfclk.h>
+
+/***************************************************************************/
+
+DEFINE_CLK(pll, "pll.0", MCF_CLK);
+DEFINE_CLK(sys, "sys.0", MCF_BUSCLK);
+DEFINE_CLK(mcfpit0, "mcfpit.0", MCF_CLK);
+DEFINE_CLK(mcfpit1, "mcfpit.1", MCF_CLK);
+DEFINE_CLK(mcfpit2, "mcfpit.2", MCF_CLK);
+DEFINE_CLK(mcfpit3, "mcfpit.3", MCF_CLK);
+DEFINE_CLK(mcfuart0, "mcfuart.0", MCF_BUSCLK);
+DEFINE_CLK(mcfuart1, "mcfuart.1", MCF_BUSCLK);
+DEFINE_CLK(mcfuart2, "mcfuart.2", MCF_BUSCLK);
+DEFINE_CLK(mcfqspi0, "mcfqspi.0", MCF_BUSCLK);
+DEFINE_CLK(fec0, "fec.0", MCF_BUSCLK);
+
+struct clk *mcf_clks[] = {
+       &clk_pll,
+       &clk_sys,
+       &clk_mcfpit0,
+       &clk_mcfpit1,
+       &clk_mcfpit2,
+       &clk_mcfpit3,
+       &clk_mcfuart0,
+       &clk_mcfuart1,
+       &clk_mcfuart2,
+       &clk_mcfqspi0,
+       &clk_fec0,
+       NULL
+};
+
+/***************************************************************************/
+
+static void __init m523x_qspi_init(void)
+{
+#if IS_ENABLED(CONFIG_SPI_COLDFIRE_QSPI)
+       u16 par;
+
+       /* setup QSPS pins for QSPI with gpio CS control */
+       writeb(0x1f, MCFGPIO_PAR_QSPI);
+       /* and CS2 & CS3 as gpio */
+       par = readw(MCFGPIO_PAR_TIMER);
+       par &= 0x3f3f;
+       writew(par, MCFGPIO_PAR_TIMER);
+#endif /* IS_ENABLED(CONFIG_SPI_COLDFIRE_QSPI) */
+}
+
+/***************************************************************************/
+
+static void __init m523x_fec_init(void)
+{
+       /* Set multi-function pins to ethernet use */
+       writeb(readb(MCFGPIO_PAR_FECI2C) | 0xf0, MCFGPIO_PAR_FECI2C);
+}
+
+/***************************************************************************/
+
+void __init config_BSP(char *commandp, int size)
+{
+       mach_sched_init = hw_timer_init;
+       m523x_fec_init();
+       m523x_qspi_init();
+}
+
+/***************************************************************************/
diff --git a/arch/m68k/coldfire/m5249.c b/arch/m68k/coldfire/m5249.c
new file mode 100644 (file)
index 0000000..e48f55a
--- /dev/null
@@ -0,0 +1,126 @@
+/***************************************************************************/
+
+/*
+ *     m5249.c  -- platform support for ColdFire 5249 based boards
+ *
+ *     Copyright (C) 2002, Greg Ungerer (gerg@snapgear.com)
+ */
+
+/***************************************************************************/
+
+#include <linux/kernel.h>
+#include <linux/param.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+#include <asm/machdep.h>
+#include <asm/coldfire.h>
+#include <asm/mcfsim.h>
+#include <asm/mcfclk.h>
+
+/***************************************************************************/
+
+DEFINE_CLK(pll, "pll.0", MCF_CLK);
+DEFINE_CLK(sys, "sys.0", MCF_BUSCLK);
+DEFINE_CLK(mcftmr0, "mcftmr.0", MCF_BUSCLK);
+DEFINE_CLK(mcftmr1, "mcftmr.1", MCF_BUSCLK);
+DEFINE_CLK(mcfuart0, "mcfuart.0", MCF_BUSCLK);
+DEFINE_CLK(mcfuart1, "mcfuart.1", MCF_BUSCLK);
+DEFINE_CLK(mcfqspi0, "mcfqspi.0", MCF_BUSCLK);
+
+struct clk *mcf_clks[] = {
+       &clk_pll,
+       &clk_sys,
+       &clk_mcftmr0,
+       &clk_mcftmr1,
+       &clk_mcfuart0,
+       &clk_mcfuart1,
+       &clk_mcfqspi0,
+       NULL
+};
+
+/***************************************************************************/
+
+#ifdef CONFIG_M5249C3
+
+static struct resource m5249_smc91x_resources[] = {
+       {
+               .start          = 0xe0000300,
+               .end            = 0xe0000300 + 0x100,
+               .flags          = IORESOURCE_MEM,
+       },
+       {
+               .start          = MCF_IRQ_GPIO6,
+               .end            = MCF_IRQ_GPIO6,
+               .flags          = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device m5249_smc91x = {
+       .name                   = "smc91x",
+       .id                     = 0,
+       .num_resources          = ARRAY_SIZE(m5249_smc91x_resources),
+       .resource               = m5249_smc91x_resources,
+};
+
+#endif /* CONFIG_M5249C3 */
+
+static struct platform_device *m5249_devices[] __initdata = {
+#ifdef CONFIG_M5249C3
+       &m5249_smc91x,
+#endif
+};
+
+/***************************************************************************/
+
+static void __init m5249_qspi_init(void)
+{
+#if IS_ENABLED(CONFIG_SPI_COLDFIRE_QSPI)
+       /* QSPI irq setup */
+       writeb(MCFSIM_ICR_AUTOVEC | MCFSIM_ICR_LEVEL4 | MCFSIM_ICR_PRI0,
+              MCFSIM_QSPIICR);
+       mcf_mapirq2imr(MCF_IRQ_QSPI, MCFINTC_QSPI);
+#endif /* IS_ENABLED(CONFIG_SPI_COLDFIRE_QSPI) */
+}
+
+/***************************************************************************/
+
+#ifdef CONFIG_M5249C3
+
+static void __init m5249_smc91x_init(void)
+{
+       u32  gpio;
+
+       /* Set the GPIO line as interrupt source for smc91x device */
+       gpio = readl(MCFSIM2_GPIOINTENABLE);
+       writel(gpio | 0x40, MCFSIM2_GPIOINTENABLE);
+
+       gpio = readl(MCFINTC2_INTPRI5);
+       writel(gpio | 0x04000000, MCFINTC2_INTPRI5);
+}
+
+#endif /* CONFIG_M5249C3 */
+
+/***************************************************************************/
+
+void __init config_BSP(char *commandp, int size)
+{
+       mach_sched_init = hw_timer_init;
+
+#ifdef CONFIG_M5249C3
+       m5249_smc91x_init();
+#endif
+       m5249_qspi_init();
+}
+
+/***************************************************************************/
+
+static int __init init_BSP(void)
+{
+       platform_add_devices(m5249_devices, ARRAY_SIZE(m5249_devices));
+       return 0;
+}
+
+arch_initcall(init_BSP);
+
+/***************************************************************************/
diff --git a/arch/m68k/coldfire/m525x.c b/arch/m68k/coldfire/m525x.c
new file mode 100644 (file)
index 0000000..3d8583e
--- /dev/null
@@ -0,0 +1,88 @@
+/***************************************************************************/
+
+/*
+ *     525x.c  -- platform support for ColdFire 525x based boards
+ *
+ *     Copyright (C) 2012, Steven King <sfking@fdwdc.com>
+ */
+
+/***************************************************************************/
+
+#include <linux/kernel.h>
+#include <linux/param.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+#include <asm/machdep.h>
+#include <asm/coldfire.h>
+#include <asm/mcfsim.h>
+#include <asm/mcfclk.h>
+
+/***************************************************************************/
+
+DEFINE_CLK(pll, "pll.0", MCF_CLK);
+DEFINE_CLK(sys, "sys.0", MCF_BUSCLK);
+DEFINE_CLK(mcftmr0, "mcftmr.0", MCF_BUSCLK);
+DEFINE_CLK(mcftmr1, "mcftmr.1", MCF_BUSCLK);
+DEFINE_CLK(mcfuart0, "mcfuart.0", MCF_BUSCLK);
+DEFINE_CLK(mcfuart1, "mcfuart.1", MCF_BUSCLK);
+DEFINE_CLK(mcfqspi0, "mcfqspi.0", MCF_BUSCLK);
+
+struct clk *mcf_clks[] = {
+       &clk_pll,
+       &clk_sys,
+       &clk_mcftmr0,
+       &clk_mcftmr1,
+       &clk_mcfuart0,
+       &clk_mcfuart1,
+       &clk_mcfqspi0,
+       NULL
+};
+
+/***************************************************************************/
+
+static void __init m525x_qspi_init(void)
+{
+#if IS_ENABLED(CONFIG_SPI_COLDFIRE_QSPI)
+       /* set the GPIO function for the qspi cs gpios */
+       /* FIXME: replace with pinmux/pinctl support */
+       u32 f = readl(MCFSIM2_GPIOFUNC);
+       f |= (1 << MCFQSPI_CS2) | (1 << MCFQSPI_CS1) | (1 << MCFQSPI_CS0);
+       writel(f, MCFSIM2_GPIOFUNC);
+
+       /* QSPI irq setup */
+       writeb(MCFSIM_ICR_AUTOVEC | MCFSIM_ICR_LEVEL4 | MCFSIM_ICR_PRI0,
+              MCFSIM_QSPIICR);
+       mcf_mapirq2imr(MCF_IRQ_QSPI, MCFINTC_QSPI);
+#endif /* IS_ENABLED(CONFIG_SPI_COLDFIRE_QSPI) */
+}
+
+static void __init m525x_i2c_init(void)
+{
+#if IS_ENABLED(CONFIG_I2C_COLDFIRE)
+       u32 r;
+
+       /* first I2C controller uses regular irq setup */
+       writeb(MCFSIM_ICR_AUTOVEC | MCFSIM_ICR_LEVEL5 | MCFSIM_ICR_PRI0,
+               MCFSIM_I2CICR);
+       mcf_mapirq2imr(MCF_IRQ_I2C0, MCFINTC_I2C);
+
+       /* second I2C controller is completely different */
+       r = readl(MCFINTC2_INTPRI_REG(MCF_IRQ_I2C1));
+       r &= ~MCFINTC2_INTPRI_BITS(0xf, MCF_IRQ_I2C1);
+       r |= MCFINTC2_INTPRI_BITS(0x5, MCF_IRQ_I2C1);
+       writel(r, MCFINTC2_INTPRI_REG(MCF_IRQ_I2C1));
+#endif /* IS_ENABLED(CONFIG_I2C_COLDFIRE) */
+}
+
+/***************************************************************************/
+
+void __init config_BSP(char *commandp, int size)
+{
+       mach_sched_init = hw_timer_init;
+
+       m525x_qspi_init();
+       m525x_i2c_init();
+}
+
+/***************************************************************************/
diff --git a/arch/m68k/coldfire/m5272.c b/arch/m68k/coldfire/m5272.c
new file mode 100644 (file)
index 0000000..b15219e
--- /dev/null
@@ -0,0 +1,135 @@
+/***************************************************************************/
+
+/*
+ *     m5272.c  -- platform support for ColdFire 5272 based boards
+ *
+ *     Copyright (C) 1999-2002, Greg Ungerer (gerg@snapgear.com)
+ *     Copyright (C) 2001-2002, SnapGear Inc. (www.snapgear.com)
+ */
+
+/***************************************************************************/
+
+#include <linux/kernel.h>
+#include <linux/param.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/phy.h>
+#include <linux/phy_fixed.h>
+#include <asm/machdep.h>
+#include <asm/coldfire.h>
+#include <asm/mcfsim.h>
+#include <asm/mcfuart.h>
+#include <asm/mcfclk.h>
+
+/***************************************************************************/
+
+/*
+ *     Some platforms need software versions of the GPIO data registers.
+ */
+unsigned short ppdata;
+unsigned char ledbank = 0xff;
+
+/***************************************************************************/
+
+DEFINE_CLK(pll, "pll.0", MCF_CLK);
+DEFINE_CLK(sys, "sys.0", MCF_BUSCLK);
+DEFINE_CLK(mcftmr0, "mcftmr.0", MCF_BUSCLK);
+DEFINE_CLK(mcftmr1, "mcftmr.1", MCF_BUSCLK);
+DEFINE_CLK(mcftmr2, "mcftmr.2", MCF_BUSCLK);
+DEFINE_CLK(mcftmr3, "mcftmr.3", MCF_BUSCLK);
+DEFINE_CLK(mcfuart0, "mcfuart.0", MCF_BUSCLK);
+DEFINE_CLK(mcfuart1, "mcfuart.1", MCF_BUSCLK);
+DEFINE_CLK(mcfqspi0, "mcfqspi.0", MCF_BUSCLK);
+DEFINE_CLK(fec0, "fec.0", MCF_BUSCLK);
+
+struct clk *mcf_clks[] = {
+       &clk_pll,
+       &clk_sys,
+       &clk_mcftmr0,
+       &clk_mcftmr1,
+       &clk_mcftmr2,
+       &clk_mcftmr3,
+       &clk_mcfuart0,
+       &clk_mcfuart1,
+       &clk_mcfqspi0,
+       &clk_fec0,
+       NULL
+};
+
+/***************************************************************************/
+
+static void __init m5272_uarts_init(void)
+{
+       u32 v;
+
+       /* Enable the output lines for the serial ports */
+       v = readl(MCFSIM_PBCNT);
+       v = (v & ~0x000000ff) | 0x00000055;
+       writel(v, MCFSIM_PBCNT);
+
+       v = readl(MCFSIM_PDCNT);
+       v = (v & ~0x000003fc) | 0x000002a8;
+       writel(v, MCFSIM_PDCNT);
+}
+
+/***************************************************************************/
+
+static void m5272_cpu_reset(void)
+{
+       local_irq_disable();
+       /* Set watchdog to reset, and enabled */
+       __raw_writew(0, MCFSIM_WIRR);
+       __raw_writew(1, MCFSIM_WRRR);
+       __raw_writew(0, MCFSIM_WCR);
+       for (;;)
+               /* wait for watchdog to timeout */;
+}
+
+/***************************************************************************/
+
+void __init config_BSP(char *commandp, int size)
+{
+#if defined (CONFIG_MOD5272)
+       /* Set base of device vectors to be 64 */
+       writeb(0x40, MCFSIM_PIVR);
+#endif
+
+#if defined(CONFIG_NETtel) || defined(CONFIG_SCALES)
+       /* Copy command line from FLASH to local buffer... */
+       memcpy(commandp, (char *) 0xf0004000, size);
+       commandp[size-1] = 0;
+#elif defined(CONFIG_CANCam)
+       /* Copy command line from FLASH to local buffer... */
+       memcpy(commandp, (char *) 0xf0010000, size);
+       commandp[size-1] = 0;
+#endif
+
+       mach_reset = m5272_cpu_reset;
+       mach_sched_init = hw_timer_init;
+}
+
+/***************************************************************************/
+
+/*
+ * Some 5272 based boards have the FEC ethernet diectly connected to
+ * an ethernet switch. In this case we need to use the fixed phy type,
+ * and we need to declare it early in boot.
+ */
+static struct fixed_phy_status nettel_fixed_phy_status __initdata = {
+       .link   = 1,
+       .speed  = 100,
+       .duplex = 0,
+};
+
+/***************************************************************************/
+
+static int __init init_BSP(void)
+{
+       m5272_uarts_init();
+       fixed_phy_add(PHY_POLL, 0, &nettel_fixed_phy_status);
+       return 0;
+}
+
+arch_initcall(init_BSP);
+
+/***************************************************************************/
diff --git a/arch/m68k/coldfire/m527x.c b/arch/m68k/coldfire/m527x.c
new file mode 100644 (file)
index 0000000..2ba4707
--- /dev/null
@@ -0,0 +1,126 @@
+/***************************************************************************/
+
+/*
+ *     m527x.c  -- platform support for ColdFire 527x based boards
+ *
+ *     Sub-architcture dependent initialization code for the Freescale
+ *     5270/5271 and 5274/5275 CPUs.
+ *
+ *     Copyright (C) 1999-2004, Greg Ungerer (gerg@snapgear.com)
+ *     Copyright (C) 2001-2004, SnapGear Inc. (www.snapgear.com)
+ */
+
+/***************************************************************************/
+
+#include <linux/kernel.h>
+#include <linux/param.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <asm/machdep.h>
+#include <asm/coldfire.h>
+#include <asm/mcfsim.h>
+#include <asm/mcfuart.h>
+#include <asm/mcfclk.h>
+
+/***************************************************************************/
+
+DEFINE_CLK(pll, "pll.0", MCF_CLK);
+DEFINE_CLK(sys, "sys.0", MCF_BUSCLK);
+DEFINE_CLK(mcfpit0, "mcfpit.0", MCF_CLK);
+DEFINE_CLK(mcfpit1, "mcfpit.1", MCF_CLK);
+DEFINE_CLK(mcfpit2, "mcfpit.2", MCF_CLK);
+DEFINE_CLK(mcfpit3, "mcfpit.3", MCF_CLK);
+DEFINE_CLK(mcfuart0, "mcfuart.0", MCF_BUSCLK);
+DEFINE_CLK(mcfuart1, "mcfuart.1", MCF_BUSCLK);
+DEFINE_CLK(mcfuart2, "mcfuart.2", MCF_BUSCLK);
+DEFINE_CLK(mcfqspi0, "mcfqspi.0", MCF_BUSCLK);
+DEFINE_CLK(fec0, "fec.0", MCF_BUSCLK);
+DEFINE_CLK(fec1, "fec.1", MCF_BUSCLK);
+
+struct clk *mcf_clks[] = {
+       &clk_pll,
+       &clk_sys,
+       &clk_mcfpit0,
+       &clk_mcfpit1,
+       &clk_mcfpit2,
+       &clk_mcfpit3,
+       &clk_mcfuart0,
+       &clk_mcfuart1,
+       &clk_mcfuart2,
+       &clk_mcfqspi0,
+       &clk_fec0,
+       &clk_fec1,
+       NULL
+};
+
+/***************************************************************************/
+
+static void __init m527x_qspi_init(void)
+{
+#if IS_ENABLED(CONFIG_SPI_COLDFIRE_QSPI)
+#if defined(CONFIG_M5271)
+       u16 par;
+
+       /* setup QSPS pins for QSPI with gpio CS control */
+       writeb(0x1f, MCFGPIO_PAR_QSPI);
+       /* and CS2 & CS3 as gpio */
+       par = readw(MCFGPIO_PAR_TIMER);
+       par &= 0x3f3f;
+       writew(par, MCFGPIO_PAR_TIMER);
+#elif defined(CONFIG_M5275)
+       /* setup QSPS pins for QSPI with gpio CS control */
+       writew(0x003e, MCFGPIO_PAR_QSPI);
+#endif
+#endif /* IS_ENABLED(CONFIG_SPI_COLDFIRE_QSPI) */
+}
+
+/***************************************************************************/
+
+static void __init m527x_uarts_init(void)
+{
+       u16 sepmask;
+
+       /*
+        * External Pin Mask Setting & Enable External Pin for Interface
+        */
+       sepmask = readw(MCFGPIO_PAR_UART);
+       sepmask |= UART0_ENABLE_MASK | UART1_ENABLE_MASK | UART2_ENABLE_MASK;
+       writew(sepmask, MCFGPIO_PAR_UART);
+}
+
+/***************************************************************************/
+
+static void __init m527x_fec_init(void)
+{
+       u16 par;
+       u8 v;
+
+       /* Set multi-function pins to ethernet mode for fec0 */
+#if defined(CONFIG_M5271)
+       v = readb(MCFGPIO_PAR_FECI2C);
+       writeb(v | 0xf0, MCFGPIO_PAR_FECI2C);
+#else
+       par = readw(MCFGPIO_PAR_FECI2C);
+       writew(par | 0xf00, MCFGPIO_PAR_FECI2C);
+       v = readb(MCFGPIO_PAR_FEC0HL);
+       writeb(v | 0xc0, MCFGPIO_PAR_FEC0HL);
+
+       /* Set multi-function pins to ethernet mode for fec1 */
+       par = readw(MCFGPIO_PAR_FECI2C);
+       writew(par | 0xa0, MCFGPIO_PAR_FECI2C);
+       v = readb(MCFGPIO_PAR_FEC1HL);
+       writeb(v | 0xc0, MCFGPIO_PAR_FEC1HL);
+#endif
+}
+
+/***************************************************************************/
+
+void __init config_BSP(char *commandp, int size)
+{
+       mach_sched_init = hw_timer_init;
+       m527x_uarts_init();
+       m527x_fec_init();
+       m527x_qspi_init();
+}
+
+/***************************************************************************/
diff --git a/arch/m68k/coldfire/m528x.c b/arch/m68k/coldfire/m528x.c
new file mode 100644 (file)
index 0000000..45e947a
--- /dev/null
@@ -0,0 +1,132 @@
+/***************************************************************************/
+
+/*
+ *     m528x.c  -- platform support for ColdFire 528x based boards
+ *
+ *     Sub-architcture dependent initialization code for the Freescale
+ *     5280, 5281 and 5282 CPUs.
+ *
+ *     Copyright (C) 1999-2003, Greg Ungerer (gerg@snapgear.com)
+ *     Copyright (C) 2001-2003, SnapGear Inc. (www.snapgear.com)
+ */
+
+/***************************************************************************/
+
+#include <linux/kernel.h>
+#include <linux/param.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <asm/machdep.h>
+#include <asm/coldfire.h>
+#include <asm/mcfsim.h>
+#include <asm/mcfuart.h>
+#include <asm/mcfclk.h>
+
+/***************************************************************************/
+
+DEFINE_CLK(pll, "pll.0", MCF_CLK);
+DEFINE_CLK(sys, "sys.0", MCF_BUSCLK);
+DEFINE_CLK(mcfpit0, "mcfpit.0", MCF_CLK);
+DEFINE_CLK(mcfpit1, "mcfpit.1", MCF_CLK);
+DEFINE_CLK(mcfpit2, "mcfpit.2", MCF_CLK);
+DEFINE_CLK(mcfpit3, "mcfpit.3", MCF_CLK);
+DEFINE_CLK(mcfuart0, "mcfuart.0", MCF_BUSCLK);
+DEFINE_CLK(mcfuart1, "mcfuart.1", MCF_BUSCLK);
+DEFINE_CLK(mcfuart2, "mcfuart.2", MCF_BUSCLK);
+DEFINE_CLK(mcfqspi0, "mcfqspi.0", MCF_BUSCLK);
+DEFINE_CLK(fec0, "fec.0", MCF_BUSCLK);
+
+struct clk *mcf_clks[] = {
+       &clk_pll,
+       &clk_sys,
+       &clk_mcfpit0,
+       &clk_mcfpit1,
+       &clk_mcfpit2,
+       &clk_mcfpit3,
+       &clk_mcfuart0,
+       &clk_mcfuart1,
+       &clk_mcfuart2,
+       &clk_mcfqspi0,
+       &clk_fec0,
+       NULL
+};
+
+/***************************************************************************/
+
+static void __init m528x_qspi_init(void)
+{
+#if IS_ENABLED(CONFIG_SPI_COLDFIRE_QSPI)
+       /* setup Port QS for QSPI with gpio CS control */
+       __raw_writeb(0x07, MCFGPIO_PQSPAR);
+#endif /* IS_ENABLED(CONFIG_SPI_COLDFIRE_QSPI) */
+}
+
+/***************************************************************************/
+
+static void __init m528x_uarts_init(void)
+{
+       u8 port;
+
+       /* make sure PUAPAR is set for UART0 and UART1 */
+       port = readb(MCFGPIO_PUAPAR);
+       port |= 0x03 | (0x03 << 2);
+       writeb(port, MCFGPIO_PUAPAR);
+}
+
+/***************************************************************************/
+
+static void __init m528x_fec_init(void)
+{
+       u16 v16;
+
+       /* Set multi-function pins to ethernet mode for fec0 */
+       v16 = readw(MCFGPIO_PASPAR);
+       writew(v16 | 0xf00, MCFGPIO_PASPAR);
+       writeb(0xc0, MCFGPIO_PEHLPAR);
+}
+
+/***************************************************************************/
+
+#ifdef CONFIG_WILDFIRE
+void wildfire_halt(void)
+{
+       writeb(0, 0x30000007);
+       writeb(0x2, 0x30000007);
+}
+#endif
+
+#ifdef CONFIG_WILDFIREMOD
+void wildfiremod_halt(void)
+{
+       printk(KERN_INFO "WildFireMod hibernating...\n");
+
+       /* Set portE.5 to Digital IO */
+       MCF5282_GPIO_PEPAR &= ~(1 << (5 * 2));
+
+       /* Make portE.5 an output */
+       MCF5282_GPIO_DDRE |= (1 << 5);
+
+       /* Now toggle portE.5 from low to high */
+       MCF5282_GPIO_PORTE &= ~(1 << 5);
+       MCF5282_GPIO_PORTE |= (1 << 5);
+
+       printk(KERN_EMERG "Failed to hibernate. Halting!\n");
+}
+#endif
+
+void __init config_BSP(char *commandp, int size)
+{
+#ifdef CONFIG_WILDFIRE
+       mach_halt = wildfire_halt;
+#endif
+#ifdef CONFIG_WILDFIREMOD
+       mach_halt = wildfiremod_halt;
+#endif
+       mach_sched_init = hw_timer_init;
+       m528x_uarts_init();
+       m528x_fec_init();
+       m528x_qspi_init();
+}
+
+/***************************************************************************/
diff --git a/arch/m68k/coldfire/m5307.c b/arch/m68k/coldfire/m5307.c
new file mode 100644 (file)
index 0000000..2da1d14
--- /dev/null
@@ -0,0 +1,78 @@
+/***************************************************************************/
+
+/*
+ *     m5307.c  -- platform support for ColdFire 5307 based boards
+ *
+ *     Copyright (C) 1999-2002, Greg Ungerer (gerg@snapgear.com)
+ *     Copyright (C) 2000, Lineo (www.lineo.com)
+ */
+
+/***************************************************************************/
+
+#include <linux/kernel.h>
+#include <linux/param.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <asm/machdep.h>
+#include <asm/coldfire.h>
+#include <asm/mcfsim.h>
+#include <asm/mcfwdebug.h>
+#include <asm/mcfclk.h>
+
+/***************************************************************************/
+
+/*
+ *     Some platforms need software versions of the GPIO data registers.
+ */
+unsigned short ppdata;
+unsigned char ledbank = 0xff;
+
+/***************************************************************************/
+
+DEFINE_CLK(pll, "pll.0", MCF_CLK);
+DEFINE_CLK(sys, "sys.0", MCF_BUSCLK);
+DEFINE_CLK(mcftmr0, "mcftmr.0", MCF_BUSCLK);
+DEFINE_CLK(mcftmr1, "mcftmr.1", MCF_BUSCLK);
+DEFINE_CLK(mcfuart0, "mcfuart.0", MCF_BUSCLK);
+DEFINE_CLK(mcfuart1, "mcfuart.1", MCF_BUSCLK);
+
+struct clk *mcf_clks[] = {
+       &clk_pll,
+       &clk_sys,
+       &clk_mcftmr0,
+       &clk_mcftmr1,
+       &clk_mcfuart0,
+       &clk_mcfuart1,
+       NULL
+};
+
+/***************************************************************************/
+
+void __init config_BSP(char *commandp, int size)
+{
+#if defined(CONFIG_NETtel) || \
+    defined(CONFIG_SECUREEDGEMP3) || defined(CONFIG_CLEOPATRA)
+       /* Copy command line from FLASH to local buffer... */
+       memcpy(commandp, (char *) 0xf0004000, size);
+       commandp[size-1] = 0;
+#endif
+
+       mach_sched_init = hw_timer_init;
+
+       /* Only support the external interrupts on their primary level */
+       mcf_mapirq2imr(25, MCFINTC_EINT1);
+       mcf_mapirq2imr(27, MCFINTC_EINT3);
+       mcf_mapirq2imr(29, MCFINTC_EINT5);
+       mcf_mapirq2imr(31, MCFINTC_EINT7);
+
+#ifdef CONFIG_BDM_DISABLE
+       /*
+        * Disable the BDM clocking.  This also turns off most of the rest of
+        * the BDM device.  This is good for EMC reasons. This option is not
+        * incompatible with the memory protection option.
+        */
+       wdebug(MCFDEBUG_CSR, MCFDEBUG_CSR_PSTCLK);
+#endif
+}
+
+/***************************************************************************/
diff --git a/arch/m68k/coldfire/m53xx.c b/arch/m68k/coldfire/m53xx.c
new file mode 100644 (file)
index 0000000..80879a7
--- /dev/null
@@ -0,0 +1,588 @@
+/***************************************************************************/
+
+/*
+ *     m53xx.c -- platform support for ColdFire 53xx based boards
+ *
+ *     Copyright (C) 1999-2002, Greg Ungerer (gerg@snapgear.com)
+ *     Copyright (C) 2000, Lineo (www.lineo.com)
+ *     Yaroslav Vinogradov yaroslav.vinogradov@freescale.com
+ *     Copyright Freescale Semiconductor, Inc 2006
+ *     Copyright (c) 2006, emlix, Sebastian Hess <shess@hessware.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+/***************************************************************************/
+
+#include <linux/kernel.h>
+#include <linux/param.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <asm/machdep.h>
+#include <asm/coldfire.h>
+#include <asm/mcfsim.h>
+#include <asm/mcfuart.h>
+#include <asm/mcfdma.h>
+#include <asm/mcfwdebug.h>
+#include <asm/mcfclk.h>
+
+/***************************************************************************/
+
+DEFINE_CLK(0, "flexbus", 2, MCF_CLK);
+DEFINE_CLK(0, "mcfcan.0", 8, MCF_CLK);
+DEFINE_CLK(0, "fec.0", 12, MCF_CLK);
+DEFINE_CLK(0, "edma", 17, MCF_CLK);
+DEFINE_CLK(0, "intc.0", 18, MCF_CLK);
+DEFINE_CLK(0, "intc.1", 19, MCF_CLK);
+DEFINE_CLK(0, "iack.0", 21, MCF_CLK);
+DEFINE_CLK(0, "mcfi2c.0", 22, MCF_CLK);
+DEFINE_CLK(0, "mcfqspi.0", 23, MCF_CLK);
+DEFINE_CLK(0, "mcfuart.0", 24, MCF_BUSCLK);
+DEFINE_CLK(0, "mcfuart.1", 25, MCF_BUSCLK);
+DEFINE_CLK(0, "mcfuart.2", 26, MCF_BUSCLK);
+DEFINE_CLK(0, "mcftmr.0", 28, MCF_CLK);
+DEFINE_CLK(0, "mcftmr.1", 29, MCF_CLK);
+DEFINE_CLK(0, "mcftmr.2", 30, MCF_CLK);
+DEFINE_CLK(0, "mcftmr.3", 31, MCF_CLK);
+
+DEFINE_CLK(0, "mcfpit.0", 32, MCF_CLK);
+DEFINE_CLK(0, "mcfpit.1", 33, MCF_CLK);
+DEFINE_CLK(0, "mcfpit.2", 34, MCF_CLK);
+DEFINE_CLK(0, "mcfpit.3", 35, MCF_CLK);
+DEFINE_CLK(0, "mcfpwm.0", 36, MCF_CLK);
+DEFINE_CLK(0, "mcfeport.0", 37, MCF_CLK);
+DEFINE_CLK(0, "mcfwdt.0", 38, MCF_CLK);
+DEFINE_CLK(0, "sys.0", 40, MCF_BUSCLK);
+DEFINE_CLK(0, "gpio.0", 41, MCF_BUSCLK);
+DEFINE_CLK(0, "mcfrtc.0", 42, MCF_CLK);
+DEFINE_CLK(0, "mcflcd.0", 43, MCF_CLK);
+DEFINE_CLK(0, "mcfusb-otg.0", 44, MCF_CLK);
+DEFINE_CLK(0, "mcfusb-host.0", 45, MCF_CLK);
+DEFINE_CLK(0, "sdram.0", 46, MCF_CLK);
+DEFINE_CLK(0, "ssi.0", 47, MCF_CLK);
+DEFINE_CLK(0, "pll.0", 48, MCF_CLK);
+
+DEFINE_CLK(1, "mdha.0", 32, MCF_CLK);
+DEFINE_CLK(1, "skha.0", 33, MCF_CLK);
+DEFINE_CLK(1, "rng.0", 34, MCF_CLK);
+
+struct clk *mcf_clks[] = {
+       &__clk_0_2,     /* flexbus */
+       &__clk_0_8,     /* mcfcan.0 */
+       &__clk_0_12,    /* fec.0 */
+       &__clk_0_17,    /* edma */
+       &__clk_0_18,    /* intc.0 */
+       &__clk_0_19,    /* intc.1 */
+       &__clk_0_21,    /* iack.0 */
+       &__clk_0_22,    /* mcfi2c.0 */
+       &__clk_0_23,    /* mcfqspi.0 */
+       &__clk_0_24,    /* mcfuart.0 */
+       &__clk_0_25,    /* mcfuart.1 */
+       &__clk_0_26,    /* mcfuart.2 */
+       &__clk_0_28,    /* mcftmr.0 */
+       &__clk_0_29,    /* mcftmr.1 */
+       &__clk_0_30,    /* mcftmr.2 */
+       &__clk_0_31,    /* mcftmr.3 */
+
+       &__clk_0_32,    /* mcfpit.0 */
+       &__clk_0_33,    /* mcfpit.1 */
+       &__clk_0_34,    /* mcfpit.2 */
+       &__clk_0_35,    /* mcfpit.3 */
+       &__clk_0_36,    /* mcfpwm.0 */
+       &__clk_0_37,    /* mcfeport.0 */
+       &__clk_0_38,    /* mcfwdt.0 */
+       &__clk_0_40,    /* sys.0 */
+       &__clk_0_41,    /* gpio.0 */
+       &__clk_0_42,    /* mcfrtc.0 */
+       &__clk_0_43,    /* mcflcd.0 */
+       &__clk_0_44,    /* mcfusb-otg.0 */
+       &__clk_0_45,    /* mcfusb-host.0 */
+       &__clk_0_46,    /* sdram.0 */
+       &__clk_0_47,    /* ssi.0 */
+       &__clk_0_48,    /* pll.0 */
+
+       &__clk_1_32,    /* mdha.0 */
+       &__clk_1_33,    /* skha.0 */
+       &__clk_1_34,    /* rng.0 */
+       NULL,
+};
+
+static struct clk * const enable_clks[] __initconst = {
+       &__clk_0_2,     /* flexbus */
+       &__clk_0_18,    /* intc.0 */
+       &__clk_0_19,    /* intc.1 */
+       &__clk_0_21,    /* iack.0 */
+       &__clk_0_24,    /* mcfuart.0 */
+       &__clk_0_25,    /* mcfuart.1 */
+       &__clk_0_26,    /* mcfuart.2 */
+       &__clk_0_28,    /* mcftmr.0 */
+       &__clk_0_29,    /* mcftmr.1 */
+       &__clk_0_32,    /* mcfpit.0 */
+       &__clk_0_33,    /* mcfpit.1 */
+       &__clk_0_37,    /* mcfeport.0 */
+       &__clk_0_40,    /* sys.0 */
+       &__clk_0_41,    /* gpio.0 */
+       &__clk_0_46,    /* sdram.0 */
+       &__clk_0_48,    /* pll.0 */
+};
+
+static struct clk * const disable_clks[] __initconst = {
+       &__clk_0_8,     /* mcfcan.0 */
+       &__clk_0_12,    /* fec.0 */
+       &__clk_0_17,    /* edma */
+       &__clk_0_22,    /* mcfi2c.0 */
+       &__clk_0_23,    /* mcfqspi.0 */
+       &__clk_0_30,    /* mcftmr.2 */
+       &__clk_0_31,    /* mcftmr.3 */
+       &__clk_0_34,    /* mcfpit.2 */
+       &__clk_0_35,    /* mcfpit.3 */
+       &__clk_0_36,    /* mcfpwm.0 */
+       &__clk_0_38,    /* mcfwdt.0 */
+       &__clk_0_42,    /* mcfrtc.0 */
+       &__clk_0_43,    /* mcflcd.0 */
+       &__clk_0_44,    /* mcfusb-otg.0 */
+       &__clk_0_45,    /* mcfusb-host.0 */
+       &__clk_0_47,    /* ssi.0 */
+       &__clk_1_32,    /* mdha.0 */
+       &__clk_1_33,    /* skha.0 */
+       &__clk_1_34,    /* rng.0 */
+};
+
+
+static void __init m53xx_clk_init(void)
+{
+       unsigned i;
+
+       /* make sure these clocks are enabled */
+       for (i = 0; i < ARRAY_SIZE(enable_clks); ++i)
+               __clk_init_enabled(enable_clks[i]);
+       /* make sure these clocks are disabled */
+       for (i = 0; i < ARRAY_SIZE(disable_clks); ++i)
+               __clk_init_disabled(disable_clks[i]);
+}
+
+/***************************************************************************/
+
+static void __init m53xx_qspi_init(void)
+{
+#if IS_ENABLED(CONFIG_SPI_COLDFIRE_QSPI)
+       /* setup QSPS pins for QSPI with gpio CS control */
+       writew(0x01f0, MCFGPIO_PAR_QSPI);
+#endif /* IS_ENABLED(CONFIG_SPI_COLDFIRE_QSPI) */
+}
+
+/***************************************************************************/
+
+static void __init m53xx_uarts_init(void)
+{
+       /* UART GPIO initialization */
+       writew(readw(MCFGPIO_PAR_UART) | 0x0FFF, MCFGPIO_PAR_UART);
+}
+
+/***************************************************************************/
+
+static void __init m53xx_fec_init(void)
+{
+       u8 v;
+
+       /* Set multi-function pins to ethernet mode for fec0 */
+       v = readb(MCFGPIO_PAR_FECI2C);
+       v |= MCF_GPIO_PAR_FECI2C_PAR_MDC_EMDC |
+               MCF_GPIO_PAR_FECI2C_PAR_MDIO_EMDIO;
+       writeb(v, MCFGPIO_PAR_FECI2C);
+
+       v = readb(MCFGPIO_PAR_FEC);
+       v = MCF_GPIO_PAR_FEC_PAR_FEC_7W_FEC | MCF_GPIO_PAR_FEC_PAR_FEC_MII_FEC;
+       writeb(v, MCFGPIO_PAR_FEC);
+}
+
+/***************************************************************************/
+
+void __init config_BSP(char *commandp, int size)
+{
+#if !defined(CONFIG_BOOTPARAM)
+       /* Copy command line from FLASH to local buffer... */
+       memcpy(commandp, (char *) 0x4000, 4);
+       if(strncmp(commandp, "kcl ", 4) == 0){
+               memcpy(commandp, (char *) 0x4004, size);
+               commandp[size-1] = 0;
+       } else {
+               memset(commandp, 0, size);
+       }
+#endif
+       mach_sched_init = hw_timer_init;
+       m53xx_clk_init();
+       m53xx_uarts_init();
+       m53xx_fec_init();
+       m53xx_qspi_init();
+
+#ifdef CONFIG_BDM_DISABLE
+       /*
+        * Disable the BDM clocking.  This also turns off most of the rest of
+        * the BDM device.  This is good for EMC reasons. This option is not
+        * incompatible with the memory protection option.
+        */
+       wdebug(MCFDEBUG_CSR, MCFDEBUG_CSR_PSTCLK);
+#endif
+}
+
+/***************************************************************************/
+/* Board initialization */
+/***************************************************************************/
+/* 
+ * PLL min/max specifications
+ */
+#define MAX_FVCO       500000  /* KHz */
+#define MAX_FSYS       80000   /* KHz */
+#define MIN_FSYS       58333   /* KHz */
+#define FREF           16000   /* KHz */
+
+
+#define MAX_MFD                135     /* Multiplier */
+#define MIN_MFD                88      /* Multiplier */
+#define BUSDIV         6       /* Divider */
+
+/*
+ * Low Power Divider specifications
+ */
+#define MIN_LPD                (1 << 0)    /* Divider (not encoded) */
+#define MAX_LPD                (1 << 15)   /* Divider (not encoded) */
+#define DEFAULT_LPD    (1 << 1)        /* Divider (not encoded) */
+
+#define SYS_CLK_KHZ    80000
+#define SYSTEM_PERIOD  12.5
+/*
+ *  SDRAM Timing Parameters
+ */  
+#define SDRAM_BL       8       /* # of beats in a burst */
+#define SDRAM_TWR      2       /* in clocks */
+#define SDRAM_CASL     2.5     /* CASL in clocks */
+#define SDRAM_TRCD     2       /* in clocks */
+#define SDRAM_TRP      2       /* in clocks */
+#define SDRAM_TRFC     7       /* in clocks */
+#define SDRAM_TREFI    7800    /* in ns */
+
+#define EXT_SRAM_ADDRESS       (0xC0000000)
+#define FLASH_ADDRESS          (0x00000000)
+#define SDRAM_ADDRESS          (0x40000000)
+
+#define NAND_FLASH_ADDRESS     (0xD0000000)
+
+int sys_clk_khz = 0;
+int sys_clk_mhz = 0;
+
+void wtm_init(void);
+void scm_init(void);
+void gpio_init(void);
+void fbcs_init(void);
+void sdramc_init(void);
+int  clock_pll (int fsys, int flags);
+int  clock_limp (int);
+int  clock_exit_limp (void);
+int  get_sys_clock (void);
+
+asmlinkage void __init sysinit(void)
+{
+       sys_clk_khz = clock_pll(0, 0);
+       sys_clk_mhz = sys_clk_khz/1000;
+       
+       wtm_init();
+       scm_init();
+       gpio_init();
+       fbcs_init();
+       sdramc_init();
+}
+
+void wtm_init(void)
+{
+       /* Disable watchdog timer */
+       writew(0, MCF_WTM_WCR);
+}
+
+#define MCF_SCM_BCR_GBW                (0x00000100)
+#define MCF_SCM_BCR_GBR                (0x00000200)
+
+void scm_init(void)
+{
+       /* All masters are trusted */
+       writel(0x77777777, MCF_SCM_MPR);
+    
+       /* Allow supervisor/user, read/write, and trusted/untrusted
+          access to all slaves */
+       writel(0, MCF_SCM_PACRA);
+       writel(0, MCF_SCM_PACRB);
+       writel(0, MCF_SCM_PACRC);
+       writel(0, MCF_SCM_PACRD);
+       writel(0, MCF_SCM_PACRE);
+       writel(0, MCF_SCM_PACRF);
+
+       /* Enable bursts */
+       writel(MCF_SCM_BCR_GBR | MCF_SCM_BCR_GBW, MCF_SCM_BCR);
+}
+
+
+void fbcs_init(void)
+{
+       writeb(0x3E, MCFGPIO_PAR_CS);
+
+       /* Latch chip select */
+       writel(0x10080000, MCF_FBCS1_CSAR);
+
+       writel(0x002A3780, MCF_FBCS1_CSCR);
+       writel(MCF_FBCS_CSMR_BAM_2M | MCF_FBCS_CSMR_V, MCF_FBCS1_CSMR);
+
+       /* Initialize latch to drive signals to inactive states */
+       writew(0xffff, 0x10080000);
+
+       /* External SRAM */
+       writel(EXT_SRAM_ADDRESS, MCF_FBCS1_CSAR);
+       writel(MCF_FBCS_CSCR_PS_16 |
+               MCF_FBCS_CSCR_AA |
+               MCF_FBCS_CSCR_SBM |
+               MCF_FBCS_CSCR_WS(1),
+               MCF_FBCS1_CSCR);
+       writel(MCF_FBCS_CSMR_BAM_512K | MCF_FBCS_CSMR_V, MCF_FBCS1_CSMR);
+
+       /* Boot Flash connected to FBCS0 */
+       writel(FLASH_ADDRESS, MCF_FBCS0_CSAR);
+       writel(MCF_FBCS_CSCR_PS_16 |
+               MCF_FBCS_CSCR_BEM |
+               MCF_FBCS_CSCR_AA |
+               MCF_FBCS_CSCR_SBM |
+               MCF_FBCS_CSCR_WS(7),
+               MCF_FBCS0_CSCR);
+       writel(MCF_FBCS_CSMR_BAM_32M | MCF_FBCS_CSMR_V, MCF_FBCS0_CSMR);
+}
+
+void sdramc_init(void)
+{
+       /*
+        * Check to see if the SDRAM has already been initialized
+        * by a run control tool
+        */
+       if (!(readl(MCF_SDRAMC_SDCR) & MCF_SDRAMC_SDCR_REF)) {
+               /* SDRAM chip select initialization */
+               
+               /* Initialize SDRAM chip select */
+               writel(MCF_SDRAMC_SDCS_BA(SDRAM_ADDRESS) |
+                       MCF_SDRAMC_SDCS_CSSZ(MCF_SDRAMC_SDCS_CSSZ_32MBYTE),
+                       MCF_SDRAMC_SDCS0);
+
+       /*
+        * Basic configuration and initialization
+        */
+       writel(MCF_SDRAMC_SDCFG1_SRD2RW((int)((SDRAM_CASL + 2) + 0.5)) |
+               MCF_SDRAMC_SDCFG1_SWT2RD(SDRAM_TWR + 1) |
+               MCF_SDRAMC_SDCFG1_RDLAT((int)((SDRAM_CASL * 2) + 2)) |
+               MCF_SDRAMC_SDCFG1_ACT2RW((int)(SDRAM_TRCD + 0.5)) |
+               MCF_SDRAMC_SDCFG1_PRE2ACT((int)(SDRAM_TRP + 0.5)) |
+               MCF_SDRAMC_SDCFG1_REF2ACT((int)(SDRAM_TRFC + 0.5)) |
+               MCF_SDRAMC_SDCFG1_WTLAT(3),
+               MCF_SDRAMC_SDCFG1);
+       writel(MCF_SDRAMC_SDCFG2_BRD2PRE(SDRAM_BL / 2 + 1) |
+               MCF_SDRAMC_SDCFG2_BWT2RW(SDRAM_BL / 2 + SDRAM_TWR) |
+               MCF_SDRAMC_SDCFG2_BRD2WT((int)((SDRAM_CASL + SDRAM_BL / 2 - 1.0) + 0.5)) |
+               MCF_SDRAMC_SDCFG2_BL(SDRAM_BL - 1),
+               MCF_SDRAMC_SDCFG2);
+
+            
+       /*
+        * Precharge and enable write to SDMR
+        */
+       writel(MCF_SDRAMC_SDCR_MODE_EN |
+               MCF_SDRAMC_SDCR_CKE |
+               MCF_SDRAMC_SDCR_DDR |
+               MCF_SDRAMC_SDCR_MUX(1) |
+               MCF_SDRAMC_SDCR_RCNT((int)(((SDRAM_TREFI / (SYSTEM_PERIOD * 64)) - 1) + 0.5)) |
+               MCF_SDRAMC_SDCR_PS_16 |
+               MCF_SDRAMC_SDCR_IPALL,
+               MCF_SDRAMC_SDCR);
+
+       /*
+        * Write extended mode register
+        */
+       writel(MCF_SDRAMC_SDMR_BNKAD_LEMR |
+               MCF_SDRAMC_SDMR_AD(0x0) |
+               MCF_SDRAMC_SDMR_CMD,
+               MCF_SDRAMC_SDMR);
+
+       /*
+        * Write mode register and reset DLL
+        */
+       writel(MCF_SDRAMC_SDMR_BNKAD_LMR |
+               MCF_SDRAMC_SDMR_AD(0x163) |
+               MCF_SDRAMC_SDMR_CMD,
+               MCF_SDRAMC_SDMR);
+
+       /*
+        * Execute a PALL command
+        */
+       writel(readl(MCF_SDRAMC_SDCR) | MCF_SDRAMC_SDCR_IPALL, MCF_SDRAMC_SDCR);
+
+       /*
+        * Perform two REF cycles
+        */
+       writel(readl(MCF_SDRAMC_SDCR) | MCF_SDRAMC_SDCR_IREF, MCF_SDRAMC_SDCR);
+       writel(readl(MCF_SDRAMC_SDCR) | MCF_SDRAMC_SDCR_IREF, MCF_SDRAMC_SDCR);
+
+       /*
+        * Write mode register and clear reset DLL
+        */
+       writel(MCF_SDRAMC_SDMR_BNKAD_LMR |
+               MCF_SDRAMC_SDMR_AD(0x063) |
+               MCF_SDRAMC_SDMR_CMD,
+               MCF_SDRAMC_SDMR);
+                               
+       /*
+        * Enable auto refresh and lock SDMR
+        */
+       writel(readl(MCF_SDRAMC_SDCR) & ~MCF_SDRAMC_SDCR_MODE_EN,
+               MCF_SDRAMC_SDCR);
+       writel(MCF_SDRAMC_SDCR_REF | MCF_SDRAMC_SDCR_DQS_OE(0xC),
+               MCF_SDRAMC_SDCR);
+       }
+}
+
+void gpio_init(void)
+{
+       /* Enable UART0 pins */
+       writew(MCF_GPIO_PAR_UART_PAR_URXD0 | MCF_GPIO_PAR_UART_PAR_UTXD0,
+               MCFGPIO_PAR_UART);
+
+       /*
+        * Initialize TIN3 as a GPIO output to enable the write
+        * half of the latch.
+        */
+       writeb(0x00, MCFGPIO_PAR_TIMER);
+       writeb(0x08, MCFGPIO_PDDR_TIMER);
+       writeb(0x00, MCFGPIO_PCLRR_TIMER);
+}
+
+int clock_pll(int fsys, int flags)
+{
+       int fref, temp, fout, mfd;
+       u32 i;
+
+       fref = FREF;
+        
+       if (fsys == 0) {
+               /* Return current PLL output */
+               mfd = readb(MCF_PLL_PFDR);
+
+               return (fref * mfd / (BUSDIV * 4));
+       }
+
+       /* Check bounds of requested system clock */
+       if (fsys > MAX_FSYS)
+               fsys = MAX_FSYS;
+       if (fsys < MIN_FSYS)
+               fsys = MIN_FSYS;
+
+       /* Multiplying by 100 when calculating the temp value,
+          and then dividing by 100 to calculate the mfd allows
+          for exact values without needing to include floating
+          point libraries. */
+       temp = 100 * fsys / fref;
+       mfd = 4 * BUSDIV * temp / 100;
+                       
+       /* Determine the output frequency for selected values */
+       fout = (fref * mfd / (BUSDIV * 4));
+
+       /*
+        * Check to see if the SDRAM has already been initialized.
+        * If it has then the SDRAM needs to be put into self refresh
+        * mode before reprogramming the PLL.
+        */
+       if (readl(MCF_SDRAMC_SDCR) & MCF_SDRAMC_SDCR_REF)
+               /* Put SDRAM into self refresh mode */
+               writel(readl(MCF_SDRAMC_SDCR) & ~MCF_SDRAMC_SDCR_CKE,
+                       MCF_SDRAMC_SDCR);
+
+       /*
+        * Initialize the PLL to generate the new system clock frequency.
+        * The device must be put into LIMP mode to reprogram the PLL.
+        */
+
+       /* Enter LIMP mode */
+       clock_limp(DEFAULT_LPD);
+                                       
+       /* Reprogram PLL for desired fsys */
+       writeb(MCF_PLL_PODR_CPUDIV(BUSDIV/3) | MCF_PLL_PODR_BUSDIV(BUSDIV),
+               MCF_PLL_PODR);
+                                               
+       writeb(mfd, MCF_PLL_PFDR);
+               
+       /* Exit LIMP mode */
+       clock_exit_limp();
+       
+       /*
+        * Return the SDRAM to normal operation if it is in use.
+        */
+       if (readl(MCF_SDRAMC_SDCR) & MCF_SDRAMC_SDCR_REF)
+               /* Exit self refresh mode */
+               writel(readl(MCF_SDRAMC_SDCR) | MCF_SDRAMC_SDCR_CKE,
+                       MCF_SDRAMC_SDCR);
+
+       /* Errata - workaround for SDRAM opeartion after exiting LIMP mode */
+       writel(MCF_SDRAMC_REFRESH, MCF_SDRAMC_LIMP_FIX);
+
+       /* wait for DQS logic to relock */
+       for (i = 0; i < 0x200; i++)
+               ;
+
+       return fout;
+}
+
+int clock_limp(int div)
+{
+       u32 temp;
+
+       /* Check bounds of divider */
+       if (div < MIN_LPD)
+               div = MIN_LPD;
+       if (div > MAX_LPD)
+               div = MAX_LPD;
+    
+       /* Save of the current value of the SSIDIV so we don't
+          overwrite the value*/
+       temp = readw(MCF_CCM_CDR) & MCF_CCM_CDR_SSIDIV(0xF);
+      
+       /* Apply the divider to the system clock */
+       writew(MCF_CCM_CDR_LPDIV(div) | MCF_CCM_CDR_SSIDIV(temp), MCF_CCM_CDR);
+    
+       writew(readw(MCF_CCM_MISCCR) | MCF_CCM_MISCCR_LIMP, MCF_CCM_MISCCR);
+    
+       return (FREF/(3*(1 << div)));
+}
+
+int clock_exit_limp(void)
+{
+       int fout;
+       
+       /* Exit LIMP mode */
+       writew(readw(MCF_CCM_MISCCR) & ~MCF_CCM_MISCCR_LIMP, MCF_CCM_MISCCR);
+
+       /* Wait for PLL to lock */
+       while (!(readw(MCF_CCM_MISCCR) & MCF_CCM_MISCCR_PLL_LOCK))
+               ;
+       
+       fout = get_sys_clock();
+
+       return fout;
+}
+
+int get_sys_clock(void)
+{
+       int divider;
+       
+       /* Test to see if device is in LIMP mode */
+       if (readw(MCF_CCM_MISCCR) & MCF_CCM_MISCCR_LIMP) {
+               divider = readw(MCF_CCM_CDR) & MCF_CCM_CDR_LPDIV(0xF);
+               return (FREF/(2 << divider));
+       }
+       else
+               return (FREF * readb(MCF_PLL_PFDR)) / (BUSDIV * 4);
+}
diff --git a/arch/m68k/coldfire/m5407.c b/arch/m68k/coldfire/m5407.c
new file mode 100644 (file)
index 0000000..738eba6
--- /dev/null
@@ -0,0 +1,53 @@
+/***************************************************************************/
+
+/*
+ *     m5407.c  -- platform support for ColdFire 5407 based boards
+ *
+ *     Copyright (C) 1999-2002, Greg Ungerer (gerg@snapgear.com)
+ *     Copyright (C) 2000, Lineo (www.lineo.com)
+ */
+
+/***************************************************************************/
+
+#include <linux/kernel.h>
+#include <linux/param.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <asm/machdep.h>
+#include <asm/coldfire.h>
+#include <asm/mcfsim.h>
+#include <asm/mcfclk.h>
+
+/***************************************************************************/
+
+DEFINE_CLK(pll, "pll.0", MCF_CLK);
+DEFINE_CLK(sys, "sys.0", MCF_BUSCLK);
+DEFINE_CLK(mcftmr0, "mcftmr.0", MCF_BUSCLK);
+DEFINE_CLK(mcftmr1, "mcftmr.1", MCF_BUSCLK);
+DEFINE_CLK(mcfuart0, "mcfuart.0", MCF_BUSCLK);
+DEFINE_CLK(mcfuart1, "mcfuart.1", MCF_BUSCLK);
+
+struct clk *mcf_clks[] = {
+       &clk_pll,
+       &clk_sys,
+       &clk_mcftmr0,
+       &clk_mcftmr1,
+       &clk_mcfuart0,
+       &clk_mcfuart1,
+       NULL
+};
+
+/***************************************************************************/
+
+void __init config_BSP(char *commandp, int size)
+{
+       mach_sched_init = hw_timer_init;
+
+       /* Only support the external interrupts on their primary level */
+       mcf_mapirq2imr(25, MCFINTC_EINT1);
+       mcf_mapirq2imr(27, MCFINTC_EINT3);
+       mcf_mapirq2imr(29, MCFINTC_EINT5);
+       mcf_mapirq2imr(31, MCFINTC_EINT7);
+}
+
+/***************************************************************************/
diff --git a/arch/m68k/coldfire/m5441x.c b/arch/m68k/coldfire/m5441x.c
new file mode 100644 (file)
index 0000000..98a13cc
--- /dev/null
@@ -0,0 +1,261 @@
+/*
+ *     m5441x.c -- support for Coldfire m5441x processors
+ *
+ *     (C) Copyright Steven King <sfking@fdwdc.com>
+ */
+
+#include <linux/kernel.h>
+#include <linux/param.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/clk.h>
+#include <asm/machdep.h>
+#include <asm/coldfire.h>
+#include <asm/mcfsim.h>
+#include <asm/mcfuart.h>
+#include <asm/mcfdma.h>
+#include <asm/mcfclk.h>
+
+DEFINE_CLK(0, "flexbus", 2, MCF_CLK);
+DEFINE_CLK(0, "mcfcan.0", 8, MCF_CLK);
+DEFINE_CLK(0, "mcfcan.1", 9, MCF_CLK);
+DEFINE_CLK(0, "mcfi2c.1", 14, MCF_CLK);
+DEFINE_CLK(0, "mcfdspi.1", 15, MCF_CLK);
+DEFINE_CLK(0, "edma", 17, MCF_CLK);
+DEFINE_CLK(0, "intc.0", 18, MCF_CLK);
+DEFINE_CLK(0, "intc.1", 19, MCF_CLK);
+DEFINE_CLK(0, "intc.2", 20, MCF_CLK);
+DEFINE_CLK(0, "mcfi2c.0", 22, MCF_CLK);
+DEFINE_CLK(0, "mcfdspi.0", 23, MCF_CLK);
+DEFINE_CLK(0, "mcfuart.0", 24, MCF_BUSCLK);
+DEFINE_CLK(0, "mcfuart.1", 25, MCF_BUSCLK);
+DEFINE_CLK(0, "mcfuart.2", 26, MCF_BUSCLK);
+DEFINE_CLK(0, "mcfuart.3", 27, MCF_BUSCLK);
+DEFINE_CLK(0, "mcftmr.0", 28, MCF_CLK);
+DEFINE_CLK(0, "mcftmr.1", 29, MCF_CLK);
+DEFINE_CLK(0, "mcftmr.2", 30, MCF_CLK);
+DEFINE_CLK(0, "mcftmr.3", 31, MCF_CLK);
+DEFINE_CLK(0, "mcfpit.0", 32, MCF_CLK);
+DEFINE_CLK(0, "mcfpit.1", 33, MCF_CLK);
+DEFINE_CLK(0, "mcfpit.2", 34, MCF_CLK);
+DEFINE_CLK(0, "mcfpit.3", 35, MCF_CLK);
+DEFINE_CLK(0, "mcfeport.0", 37, MCF_CLK);
+DEFINE_CLK(0, "mcfadc.0", 38, MCF_CLK);
+DEFINE_CLK(0, "mcfdac.0", 39, MCF_CLK);
+DEFINE_CLK(0, "mcfrtc.0", 42, MCF_CLK);
+DEFINE_CLK(0, "mcfsim.0", 43, MCF_CLK);
+DEFINE_CLK(0, "mcfusb-otg.0", 44, MCF_CLK);
+DEFINE_CLK(0, "mcfusb-host.0", 45, MCF_CLK);
+DEFINE_CLK(0, "mcfddr-sram.0", 46, MCF_CLK);
+DEFINE_CLK(0, "mcfssi.0", 47, MCF_CLK);
+DEFINE_CLK(0, "pll.0", 48, MCF_CLK);
+DEFINE_CLK(0, "mcfrng.0", 49, MCF_CLK);
+DEFINE_CLK(0, "mcfssi.1", 50, MCF_CLK);
+DEFINE_CLK(0, "mcfsdhc.0", 51, MCF_CLK);
+DEFINE_CLK(0, "enet-fec.0", 53, MCF_CLK);
+DEFINE_CLK(0, "enet-fec.1", 54, MCF_CLK);
+DEFINE_CLK(0, "switch.0", 55, MCF_CLK);
+DEFINE_CLK(0, "switch.1", 56, MCF_CLK);
+DEFINE_CLK(0, "nand.0", 63, MCF_CLK);
+
+DEFINE_CLK(1, "mcfow.0", 2, MCF_CLK);
+DEFINE_CLK(1, "mcfi2c.2", 4, MCF_CLK);
+DEFINE_CLK(1, "mcfi2c.3", 5, MCF_CLK);
+DEFINE_CLK(1, "mcfi2c.4", 6, MCF_CLK);
+DEFINE_CLK(1, "mcfi2c.5", 7, MCF_CLK);
+DEFINE_CLK(1, "mcfuart.4", 24, MCF_BUSCLK);
+DEFINE_CLK(1, "mcfuart.5", 25, MCF_BUSCLK);
+DEFINE_CLK(1, "mcfuart.6", 26, MCF_BUSCLK);
+DEFINE_CLK(1, "mcfuart.7", 27, MCF_BUSCLK);
+DEFINE_CLK(1, "mcfuart.8", 28, MCF_BUSCLK);
+DEFINE_CLK(1, "mcfuart.9", 29, MCF_BUSCLK);
+DEFINE_CLK(1, "mcfpwm.0", 34, MCF_BUSCLK);
+DEFINE_CLK(1, "sys.0", 36, MCF_BUSCLK);
+DEFINE_CLK(1, "gpio.0", 37, MCF_BUSCLK);
+
+struct clk *mcf_clks[] = {
+       &__clk_0_2,
+       &__clk_0_8,
+       &__clk_0_9,
+       &__clk_0_14,
+       &__clk_0_15,
+       &__clk_0_17,
+       &__clk_0_18,
+       &__clk_0_19,
+       &__clk_0_20,
+       &__clk_0_22,
+       &__clk_0_23,
+       &__clk_0_24,
+       &__clk_0_25,
+       &__clk_0_26,
+       &__clk_0_27,
+       &__clk_0_28,
+       &__clk_0_29,
+       &__clk_0_30,
+       &__clk_0_31,
+       &__clk_0_32,
+       &__clk_0_33,
+       &__clk_0_34,
+       &__clk_0_35,
+       &__clk_0_37,
+       &__clk_0_38,
+       &__clk_0_39,
+       &__clk_0_42,
+       &__clk_0_43,
+       &__clk_0_44,
+       &__clk_0_45,
+       &__clk_0_46,
+       &__clk_0_47,
+       &__clk_0_48,
+       &__clk_0_49,
+       &__clk_0_50,
+       &__clk_0_51,
+       &__clk_0_53,
+       &__clk_0_54,
+       &__clk_0_55,
+       &__clk_0_56,
+       &__clk_0_63,
+
+       &__clk_1_2,
+       &__clk_1_4,
+       &__clk_1_5,
+       &__clk_1_6,
+       &__clk_1_7,
+       &__clk_1_24,
+       &__clk_1_25,
+       &__clk_1_26,
+       &__clk_1_27,
+       &__clk_1_28,
+       &__clk_1_29,
+       &__clk_1_34,
+       &__clk_1_36,
+       &__clk_1_37,
+       NULL,
+};
+
+
+static struct clk * const enable_clks[] __initconst = {
+       /* make sure these clocks are enabled */
+       &__clk_0_18, /* intc0 */
+       &__clk_0_19, /* intc0 */
+       &__clk_0_20, /* intc0 */
+       &__clk_0_24, /* uart0 */
+       &__clk_0_25, /* uart1 */
+       &__clk_0_26, /* uart2 */
+       &__clk_0_27, /* uart3 */
+
+       &__clk_0_33, /* pit.1 */
+       &__clk_0_37, /* eport */
+       &__clk_0_48, /* pll */
+
+       &__clk_1_36, /* CCM/reset module/Power management */
+       &__clk_1_37, /* gpio */
+};
+static struct clk * const disable_clks[] __initconst = {
+       &__clk_0_8, /* can.0 */
+       &__clk_0_9, /* can.1 */
+       &__clk_0_14, /* i2c.1 */
+       &__clk_0_15, /* dspi.1 */
+       &__clk_0_17, /* eDMA */
+       &__clk_0_22, /* i2c.0 */
+       &__clk_0_23, /* dspi.0 */
+       &__clk_0_28, /* tmr.1 */
+       &__clk_0_29, /* tmr.2 */
+       &__clk_0_30, /* tmr.2 */
+       &__clk_0_31, /* tmr.3 */
+       &__clk_0_32, /* pit.0 */
+       &__clk_0_34, /* pit.2 */
+       &__clk_0_35, /* pit.3 */
+       &__clk_0_38, /* adc */
+       &__clk_0_39, /* dac */
+       &__clk_0_44, /* usb otg */
+       &__clk_0_45, /* usb host */
+       &__clk_0_47, /* ssi.0 */
+       &__clk_0_49, /* rng */
+       &__clk_0_50, /* ssi.1 */
+       &__clk_0_51, /* eSDHC */
+       &__clk_0_53, /* enet-fec */
+       &__clk_0_54, /* enet-fec */
+       &__clk_0_55, /* switch.0 */
+       &__clk_0_56, /* switch.1 */
+
+       &__clk_1_2, /* 1-wire */
+       &__clk_1_4, /* i2c.2 */
+       &__clk_1_5, /* i2c.3 */
+       &__clk_1_6, /* i2c.4 */
+       &__clk_1_7, /* i2c.5 */
+       &__clk_1_24, /* uart 4 */
+       &__clk_1_25, /* uart 5 */
+       &__clk_1_26, /* uart 6 */
+       &__clk_1_27, /* uart 7 */
+       &__clk_1_28, /* uart 8 */
+       &__clk_1_29, /* uart 9 */
+};
+
+static void __init m5441x_clk_init(void)
+{
+       unsigned i;
+
+       for (i = 0; i < ARRAY_SIZE(enable_clks); ++i)
+               __clk_init_enabled(enable_clks[i]);
+       /* make sure these clocks are disabled */
+       for (i = 0; i < ARRAY_SIZE(disable_clks); ++i)
+               __clk_init_disabled(disable_clks[i]);
+}
+
+static void __init m5441x_uarts_init(void)
+{
+       __raw_writeb(0x0f, MCFGPIO_PAR_UART0);
+       __raw_writeb(0x00, MCFGPIO_PAR_UART1);
+       __raw_writeb(0x00, MCFGPIO_PAR_UART2);
+}
+
+static void __init m5441x_fec_init(void)
+{
+       __raw_writeb(0x03, MCFGPIO_PAR_FEC);
+}
+
+void __init config_BSP(char *commandp, int size)
+{
+       m5441x_clk_init();
+       mach_sched_init = hw_timer_init;
+       m5441x_uarts_init();
+       m5441x_fec_init();
+}
+
+
+#if IS_ENABLED(CONFIG_RTC_DRV_M5441x)
+static struct resource m5441x_rtc_resources[] = {
+       {
+               .start          = MCFRTC_BASE,
+               .end            = MCFRTC_BASE + MCFRTC_SIZE - 1,
+               .flags          = IORESOURCE_MEM,
+       },
+       {
+               .start          = MCF_IRQ_RTC,
+               .end            = MCF_IRQ_RTC,
+               .flags          = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device m5441x_rtc = {
+       .name                   = "mcfrtc",
+       .id                     = 0,
+       .resource               = m5441x_rtc_resources,
+       .num_resources          = ARRAY_SIZE(m5441x_rtc_resources),
+};
+#endif
+
+static struct platform_device *m5441x_devices[] __initdata = {
+#if IS_ENABLED(CONFIG_RTC_DRV_M5441x)
+       &m5441x_rtc,
+#endif
+};
+
+static int __init init_BSP(void)
+{
+       platform_add_devices(m5441x_devices, ARRAY_SIZE(m5441x_devices));
+       return 0;
+}
+
+arch_initcall(init_BSP);
diff --git a/arch/m68k/coldfire/m54xx.c b/arch/m68k/coldfire/m54xx.c
new file mode 100644 (file)
index 0000000..075aaab
--- /dev/null
@@ -0,0 +1,128 @@
+/***************************************************************************/
+
+/*
+ *     m54xx.c  -- platform support for ColdFire 54xx based boards
+ *
+ *     Copyright (C) 2010, Philippe De Muyter <phdm@macqel.be>
+ */
+
+/***************************************************************************/
+
+#include <linux/kernel.h>
+#include <linux/param.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/mm.h>
+#include <linux/clk.h>
+#include <linux/bootmem.h>
+#include <asm/pgalloc.h>
+#include <asm/machdep.h>
+#include <asm/coldfire.h>
+#include <asm/m54xxsim.h>
+#include <asm/mcfuart.h>
+#include <asm/mcfclk.h>
+#include <asm/m54xxgpt.h>
+#ifdef CONFIG_MMU
+#include <asm/mmu_context.h>
+#endif
+
+/***************************************************************************/
+
+DEFINE_CLK(pll, "pll.0", MCF_CLK);
+DEFINE_CLK(sys, "sys.0", MCF_BUSCLK);
+DEFINE_CLK(mcfslt0, "mcfslt.0", MCF_BUSCLK);
+DEFINE_CLK(mcfslt1, "mcfslt.1", MCF_BUSCLK);
+DEFINE_CLK(mcfuart0, "mcfuart.0", MCF_BUSCLK);
+DEFINE_CLK(mcfuart1, "mcfuart.1", MCF_BUSCLK);
+DEFINE_CLK(mcfuart2, "mcfuart.2", MCF_BUSCLK);
+DEFINE_CLK(mcfuart3, "mcfuart.3", MCF_BUSCLK);
+
+struct clk *mcf_clks[] = {
+       &clk_pll,
+       &clk_sys,
+       &clk_mcfslt0,
+       &clk_mcfslt1,
+       &clk_mcfuart0,
+       &clk_mcfuart1,
+       &clk_mcfuart2,
+       &clk_mcfuart3,
+       NULL
+};
+
+/***************************************************************************/
+
+static void __init m54xx_uarts_init(void)
+{
+       /* enable io pins */
+       __raw_writeb(MCF_PAR_PSC_TXD | MCF_PAR_PSC_RXD, MCFGPIO_PAR_PSC0);
+       __raw_writeb(MCF_PAR_PSC_TXD | MCF_PAR_PSC_RXD | MCF_PAR_PSC_RTS_RTS,
+               MCFGPIO_PAR_PSC1);
+       __raw_writeb(MCF_PAR_PSC_TXD | MCF_PAR_PSC_RXD | MCF_PAR_PSC_RTS_RTS |
+               MCF_PAR_PSC_CTS_CTS, MCFGPIO_PAR_PSC2);
+       __raw_writeb(MCF_PAR_PSC_TXD | MCF_PAR_PSC_RXD, MCFGPIO_PAR_PSC3);
+}
+
+/***************************************************************************/
+
+static void mcf54xx_reset(void)
+{
+       /* disable interrupts and enable the watchdog */
+       asm("movew #0x2700, %sr\n");
+       __raw_writel(0, MCF_GPT_GMS0);
+       __raw_writel(MCF_GPT_GCIR_CNT(1), MCF_GPT_GCIR0);
+       __raw_writel(MCF_GPT_GMS_WDEN | MCF_GPT_GMS_CE | MCF_GPT_GMS_TMS(4),
+               MCF_GPT_GMS0);
+}
+
+/***************************************************************************/
+
+#ifdef CONFIG_MMU
+
+unsigned long num_pages;
+
+static void __init mcf54xx_bootmem_alloc(void)
+{
+       unsigned long start_pfn;
+       unsigned long memstart;
+
+       /* _rambase and _ramend will be naturally page aligned */
+       m68k_memory[0].addr = _rambase;
+       m68k_memory[0].size = _ramend - _rambase;
+
+       /* compute total pages in system */
+       num_pages = (_ramend - _rambase) >> PAGE_SHIFT;
+
+       /* page numbers */
+       memstart = PAGE_ALIGN(_ramstart);
+       min_low_pfn = _rambase >> PAGE_SHIFT;
+       start_pfn = memstart >> PAGE_SHIFT;
+       max_low_pfn = _ramend >> PAGE_SHIFT;
+       high_memory = (void *)_ramend;
+
+       m68k_virt_to_node_shift = fls(_ramend - _rambase - 1) - 6;
+       module_fixup(NULL, __start_fixup, __stop_fixup);
+
+       /* setup bootmem data */
+       m68k_setup_node(0);
+       memstart += init_bootmem_node(NODE_DATA(0), start_pfn,
+               min_low_pfn, max_low_pfn);
+       free_bootmem_node(NODE_DATA(0), memstart, _ramend - memstart);
+}
+
+#endif /* CONFIG_MMU */
+
+/***************************************************************************/
+
+void __init config_BSP(char *commandp, int size)
+{
+#ifdef CONFIG_MMU
+       mcf54xx_bootmem_alloc();
+       mmu_context_init();
+#endif
+       mach_reset = mcf54xx_reset;
+       mach_sched_init = hw_timer_init;
+       m54xx_uarts_init();
+}
+
+/***************************************************************************/
diff --git a/arch/m68k/coldfire/mcf8390.c b/arch/m68k/coldfire/mcf8390.c
new file mode 100644 (file)
index 0000000..23a6874
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * mcf8390.c  -- platform support for 8390 ethernet on many boards
+ *
+ * (C) Copyright 2012, Greg Ungerer <gerg@uclinux.org>
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file COPYING in the main directory of this archive
+ * for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/resource.h>
+#include <linux/platform_device.h>
+#include <asm/mcf8390.h>
+
+static struct resource mcf8390_resources[] = {
+       {
+               .start  = NE2000_ADDR,
+               .end    = NE2000_ADDR + NE2000_ADDRSIZE - 1,
+               .flags  = IORESOURCE_MEM,
+       },
+       {
+               .start  = NE2000_IRQ_VECTOR,
+               .end    = NE2000_IRQ_VECTOR,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static int __init mcf8390_platform_init(void)
+{
+       platform_device_register_simple("mcf8390", -1, mcf8390_resources,
+               ARRAY_SIZE(mcf8390_resources));
+       return 0;
+}
+
+arch_initcall(mcf8390_platform_init);
diff --git a/arch/m68k/coldfire/nettel.c b/arch/m68k/coldfire/nettel.c
new file mode 100644 (file)
index 0000000..ddc48ec
--- /dev/null
@@ -0,0 +1,153 @@
+/***************************************************************************/
+
+/*
+ *     nettel.c -- startup code support for the NETtel boards
+ *
+ *     Copyright (C) 2009, Greg Ungerer (gerg@snapgear.com)
+ */
+
+/***************************************************************************/
+
+#include <linux/kernel.h>
+#include <linux/param.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+#include <asm/coldfire.h>
+#include <asm/mcfsim.h>
+#include <asm/nettel.h>
+
+/***************************************************************************/
+
+/*
+ * Define the IO and interrupt resources of the 2 SMC9196 interfaces.
+ */
+#define        NETTEL_SMC0_ADDR        0x30600300
+#define        NETTEL_SMC0_IRQ         29
+
+#define        NETTEL_SMC1_ADDR        0x30600000
+#define        NETTEL_SMC1_IRQ         27
+
+/*
+ * We need some access into the SMC9196 registers. Define those registers
+ * we will need here (including the smc91x.h doesn't seem to give us these
+ * in a simple form).
+ */
+#define        SMC91xx_BANKSELECT      14
+#define        SMC91xx_BASEADDR        2
+#define        SMC91xx_BASEMAC         4
+
+/***************************************************************************/
+
+static struct resource nettel_smc91x_0_resources[] = {
+       {
+               .start          = NETTEL_SMC0_ADDR,
+               .end            = NETTEL_SMC0_ADDR + 0x20,
+               .flags          = IORESOURCE_MEM,
+       },
+       {
+               .start          = NETTEL_SMC0_IRQ,
+               .end            = NETTEL_SMC0_IRQ,
+               .flags          = IORESOURCE_IRQ,
+       },
+};
+
+static struct resource nettel_smc91x_1_resources[] = {
+       {
+               .start          = NETTEL_SMC1_ADDR,
+               .end            = NETTEL_SMC1_ADDR + 0x20,
+               .flags          = IORESOURCE_MEM,
+       },
+       {
+               .start          = NETTEL_SMC1_IRQ,
+               .end            = NETTEL_SMC1_IRQ,
+               .flags          = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device nettel_smc91x[] = {
+       {
+               .name                   = "smc91x",
+               .id                     = 0,
+               .num_resources          = ARRAY_SIZE(nettel_smc91x_0_resources),
+               .resource               = nettel_smc91x_0_resources,
+       },
+       {
+               .name                   = "smc91x",
+               .id                     = 1,
+               .num_resources          = ARRAY_SIZE(nettel_smc91x_1_resources),
+               .resource               = nettel_smc91x_1_resources,
+       },
+};
+
+static struct platform_device *nettel_devices[] __initdata = {
+       &nettel_smc91x[0],
+       &nettel_smc91x[1],
+};
+
+/***************************************************************************/
+
+static u8 nettel_macdefault[] __initdata = {
+       0x00, 0xd0, 0xcf, 0x00, 0x00, 0x01,
+};
+
+/*
+ * Set flash contained MAC address into SMC9196 core. Make sure the flash
+ * MAC address is sane, and not an empty flash. If no good use the Moreton
+ * Bay default MAC address instead.
+ */
+
+static void __init nettel_smc91x_setmac(unsigned int ioaddr, unsigned int flashaddr)
+{
+       u16 *macp;
+
+       macp = (u16 *) flashaddr;
+       if ((macp[0] == 0xffff) && (macp[1] == 0xffff) && (macp[2] == 0xffff))
+               macp = (u16 *) &nettel_macdefault[0];
+
+       writew(1, NETTEL_SMC0_ADDR + SMC91xx_BANKSELECT);
+       writew(macp[0], ioaddr + SMC91xx_BASEMAC);
+       writew(macp[1], ioaddr + SMC91xx_BASEMAC + 2);
+       writew(macp[2], ioaddr + SMC91xx_BASEMAC + 4);
+}
+
+/***************************************************************************/
+
+/*
+ * Re-map the address space of at least one of the SMC ethernet
+ * parts. Both parts power up decoding the same address, so we
+ * need to move one of them first, before doing anything else.
+ */
+
+static void __init nettel_smc91x_init(void)
+{
+       writew(0x00ec, MCFSIM_PADDR);
+       mcf_setppdata(0, 0x0080);
+       writew(1, NETTEL_SMC0_ADDR + SMC91xx_BANKSELECT);
+       writew(0x0067, NETTEL_SMC0_ADDR + SMC91xx_BASEADDR);
+       mcf_setppdata(0x0080, 0);
+
+       /* Set correct chip select timing for SMC9196 accesses */
+       writew(0x1180, MCFSIM_CSCR3);
+
+       /* Set the SMC interrupts to be auto-vectored */
+       mcf_autovector(NETTEL_SMC0_IRQ);
+       mcf_autovector(NETTEL_SMC1_IRQ);
+
+       /* Set MAC addresses from flash for both interfaces */
+       nettel_smc91x_setmac(NETTEL_SMC0_ADDR, 0xf0006000);
+       nettel_smc91x_setmac(NETTEL_SMC1_ADDR, 0xf0006006);
+}
+
+/***************************************************************************/
+
+static int __init init_nettel(void)
+{
+       nettel_smc91x_init();
+       platform_add_devices(nettel_devices, ARRAY_SIZE(nettel_devices));
+       return 0;
+}
+
+arch_initcall(init_nettel);
+
+/***************************************************************************/
diff --git a/arch/m68k/coldfire/pci.c b/arch/m68k/coldfire/pci.c
new file mode 100644 (file)
index 0000000..df96792
--- /dev/null
@@ -0,0 +1,325 @@
+/*
+ * pci.c -- PCI bus support for ColdFire processors
+ *
+ * (C) Copyright 2012, Greg Ungerer <gerg@uclinux.com>
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file COPYING in the main directory of this archive
+ * for more details.
+ */
+
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/io.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <asm/coldfire.h>
+#include <asm/mcfsim.h>
+#include <asm/m54xxpci.h>
+
+/*
+ * Memory and IO mappings. We use a 1:1 mapping for local host memory to
+ * PCI bus memory (no reason not to really). IO space doesn't matter, we
+ * always use access functions for that. The device configuration space is
+ * mapped over the IO map space when we enable it in the PCICAR register.
+ */
+#define        PCI_MEM_PA      0xf0000000              /* Host physical address */
+#define        PCI_MEM_BA      0xf0000000              /* Bus physical address */
+#define        PCI_MEM_SIZE    0x08000000              /* 128 MB */
+#define        PCI_MEM_MASK    (PCI_MEM_SIZE - 1)
+
+#define        PCI_IO_PA       0xf8000000              /* Host physical address */
+#define        PCI_IO_BA       0x00000000              /* Bus physical address */
+#define        PCI_IO_SIZE     0x00010000              /* 64k */
+#define        PCI_IO_MASK     (PCI_IO_SIZE - 1)
+
+static struct pci_bus *rootbus;
+static unsigned long iospace;
+
+/*
+ * We need to be carefull probing on bus 0 (directly connected to host
+ * bridge). We should only acccess the well defined possible devices in
+ * use, ignore aliases and the like.
+ */
+static unsigned char mcf_host_slot2sid[32] = {
+       0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0,
+       0, 1, 2, 0, 3, 4, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0,
+};
+
+static unsigned char mcf_host_irq[] = {
+       0, 69, 69, 71, 71,
+};
+
+
+static inline void syncio(void)
+{
+       /* The ColdFire "nop" instruction waits for all bus IO to complete */
+       __asm__ __volatile__ ("nop");
+}
+
+/*
+ * Configuration space access functions. Configuration space access is
+ * through the IO mapping window, enabling it via the PCICAR register.
+ */
+static unsigned long mcf_mk_pcicar(int bus, unsigned int devfn, int where)
+{
+       return (bus << PCICAR_BUSN) | (devfn << PCICAR_DEVFNN) | (where & 0xfc);
+}
+
+static int mcf_pci_readconfig(struct pci_bus *bus, unsigned int devfn,
+       int where, int size, u32 *value)
+{
+       unsigned long addr;
+
+       *value = 0xffffffff;
+
+       if (bus->number == 0) {
+               if (mcf_host_slot2sid[PCI_SLOT(devfn)] == 0)
+                       return PCIBIOS_SUCCESSFUL;
+       }
+
+       syncio();
+       addr = mcf_mk_pcicar(bus->number, devfn, where);
+       __raw_writel(PCICAR_E | addr, PCICAR);
+       addr = iospace + (where & 0x3);
+
+       switch (size) {
+       case 1:
+               *value = __raw_readb(addr);
+               break;
+       case 2:
+               *value = le16_to_cpu(__raw_readw(addr));
+               break;
+       default:
+               *value = le32_to_cpu(__raw_readl(addr));
+               break;
+       }
+
+       syncio();
+       __raw_writel(0, PCICAR);
+       return PCIBIOS_SUCCESSFUL;
+}
+
+static int mcf_pci_writeconfig(struct pci_bus *bus, unsigned int devfn,
+       int where, int size, u32 value)
+{
+       unsigned long addr;
+
+       if (bus->number == 0) {
+               if (mcf_host_slot2sid[PCI_SLOT(devfn)] == 0)
+                       return PCIBIOS_SUCCESSFUL;
+       }
+
+       syncio();
+       addr = mcf_mk_pcicar(bus->number, devfn, where);
+       __raw_writel(PCICAR_E | addr, PCICAR);
+       addr = iospace + (where & 0x3);
+
+       switch (size) {
+       case 1:
+                __raw_writeb(value, addr);
+               break;
+       case 2:
+               __raw_writew(cpu_to_le16(value), addr);
+               break;
+       default:
+               __raw_writel(cpu_to_le32(value), addr);
+               break;
+       }
+
+       syncio();
+       __raw_writel(0, PCICAR);
+       return PCIBIOS_SUCCESSFUL;
+}
+
+static struct pci_ops mcf_pci_ops = {
+       .read   = mcf_pci_readconfig,
+       .write  = mcf_pci_writeconfig,
+};
+
+/*
+ *     IO address space access functions. Pretty strait forward, these are
+ *     directly mapped in to the IO mapping window. And that is mapped into
+ *     virtual address space.
+ */
+u8 mcf_pci_inb(u32 addr)
+{
+       return __raw_readb(iospace + (addr & PCI_IO_MASK));
+}
+EXPORT_SYMBOL(mcf_pci_inb);
+
+u16 mcf_pci_inw(u32 addr)
+{
+       return le16_to_cpu(__raw_readw(iospace + (addr & PCI_IO_MASK)));
+}
+EXPORT_SYMBOL(mcf_pci_inw);
+
+u32 mcf_pci_inl(u32 addr)
+{
+       return le32_to_cpu(__raw_readl(iospace + (addr & PCI_IO_MASK)));
+}
+EXPORT_SYMBOL(mcf_pci_inl);
+
+void mcf_pci_insb(u32 addr, u8 *buf, u32 len)
+{
+       for (; len; len--)
+               *buf++ = mcf_pci_inb(addr);
+}
+EXPORT_SYMBOL(mcf_pci_insb);
+
+void mcf_pci_insw(u32 addr, u16 *buf, u32 len)
+{
+       for (; len; len--)
+               *buf++ = mcf_pci_inw(addr);
+}
+EXPORT_SYMBOL(mcf_pci_insw);
+
+void mcf_pci_insl(u32 addr, u32 *buf, u32 len)
+{
+       for (; len; len--)
+               *buf++ = mcf_pci_inl(addr);
+}
+EXPORT_SYMBOL(mcf_pci_insl);
+
+void mcf_pci_outb(u8 v, u32 addr)
+{
+       __raw_writeb(v, iospace + (addr & PCI_IO_MASK));
+}
+EXPORT_SYMBOL(mcf_pci_outb);
+
+void mcf_pci_outw(u16 v, u32 addr)
+{
+       __raw_writew(cpu_to_le16(v), iospace + (addr & PCI_IO_MASK));
+}
+EXPORT_SYMBOL(mcf_pci_outw);
+
+void mcf_pci_outl(u32 v, u32 addr)
+{
+       __raw_writel(cpu_to_le32(v), iospace + (addr & PCI_IO_MASK));
+}
+EXPORT_SYMBOL(mcf_pci_outl);
+
+void mcf_pci_outsb(u32 addr, const u8 *buf, u32 len)
+{
+       for (; len; len--)
+               mcf_pci_outb(*buf++, addr);
+}
+EXPORT_SYMBOL(mcf_pci_outsb);
+
+void mcf_pci_outsw(u32 addr, const u16 *buf, u32 len)
+{
+       for (; len; len--)
+               mcf_pci_outw(*buf++, addr);
+}
+EXPORT_SYMBOL(mcf_pci_outsw);
+
+void mcf_pci_outsl(u32 addr, const u32 *buf, u32 len)
+{
+       for (; len; len--)
+               mcf_pci_outl(*buf++, addr);
+}
+EXPORT_SYMBOL(mcf_pci_outsl);
+
+/*
+ * Initialize the PCI bus registers, and scan the bus.
+ */
+static struct resource mcf_pci_mem = {
+       .name   = "PCI Memory space",
+       .start  = PCI_MEM_PA,
+       .end    = PCI_MEM_PA + PCI_MEM_SIZE - 1,
+       .flags  = IORESOURCE_MEM,
+};
+
+static struct resource mcf_pci_io = {
+       .name   = "PCI IO space",
+       .start  = 0x400,
+       .end    = 0x10000 - 1,
+       .flags  = IORESOURCE_IO,
+};
+
+/*
+ * Interrupt mapping and setting.
+ */
+static int mcf_pci_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
+{
+       int sid;
+
+       sid = mcf_host_slot2sid[slot];
+       if (sid)
+               return mcf_host_irq[sid];
+       return 0;
+}
+
+static int __init mcf_pci_init(void)
+{
+       pr_info("ColdFire: PCI bus initialization...\n");
+
+       /* Reset the external PCI bus */
+       __raw_writel(PCIGSCR_RESET, PCIGSCR);
+       __raw_writel(0, PCITCR);
+
+       request_resource(&iomem_resource, &mcf_pci_mem);
+       request_resource(&iomem_resource, &mcf_pci_io);
+
+       /* Configure PCI arbiter */
+       __raw_writel(PACR_INTMPRI | PACR_INTMINTE | PACR_EXTMPRI(0x1f) |
+               PACR_EXTMINTE(0x1f), PACR);
+
+       /* Set required multi-function pins for PCI bus use */
+       __raw_writew(0x3ff, MCFGPIO_PAR_PCIBG);
+       __raw_writew(0x3ff, MCFGPIO_PAR_PCIBR);
+
+       /* Set up config space for local host bus controller */
+       __raw_writel(PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER |
+               PCI_COMMAND_INVALIDATE, PCISCR);
+       __raw_writel(PCICR1_LT(32) | PCICR1_CL(8), PCICR1);
+       __raw_writel(0, PCICR2);
+
+       /*
+        * Set up the initiator windows for memory and IO mapping.
+        * These give the CPU bus access onto the PCI bus. One for each of
+        * PCI memory and IO address spaces.
+        */
+       __raw_writel(WXBTAR(PCI_MEM_PA, PCI_MEM_BA, PCI_MEM_SIZE),
+               PCIIW0BTAR);
+       __raw_writel(WXBTAR(PCI_IO_PA, PCI_IO_BA, PCI_IO_SIZE),
+               PCIIW1BTAR);
+       __raw_writel(PCIIWCR_W0_MEM /*| PCIIWCR_W0_MRDL*/ | PCIIWCR_W0_E |
+               PCIIWCR_W1_IO | PCIIWCR_W1_E, PCIIWCR);
+
+       /*
+        * Set up the target windows for access from the PCI bus back to the
+        * CPU bus. All we need is access to system RAM (for mastering).
+        */
+       __raw_writel(CONFIG_RAMBASE, PCIBAR1);
+       __raw_writel(CONFIG_RAMBASE | PCITBATR1_E, PCITBATR1);
+
+       /* Keep a virtual mapping to IO/config space active */
+       iospace = (unsigned long) ioremap(PCI_IO_PA, PCI_IO_SIZE);
+       if (iospace == 0)
+               return -ENODEV;
+       pr_info("Coldfire: PCI IO/config window mapped to 0x%x\n",
+               (u32) iospace);
+
+       /* Turn of PCI reset, and wait for devices to settle */
+       __raw_writel(0, PCIGSCR);
+       set_current_state(TASK_UNINTERRUPTIBLE);
+       schedule_timeout(msecs_to_jiffies(200));
+
+       rootbus = pci_scan_bus(0, &mcf_pci_ops, NULL);
+       rootbus->resource[0] = &mcf_pci_io;
+       rootbus->resource[1] = &mcf_pci_mem;
+
+       pci_fixup_irqs(pci_common_swizzle, mcf_pci_map_irq);
+       pci_bus_size_bridges(rootbus);
+       pci_bus_assign_resources(rootbus);
+       return 0;
+}
+
+subsys_initcall(mcf_pci_init);
diff --git a/arch/m68k/coldfire/pit.c b/arch/m68k/coldfire/pit.c
new file mode 100644 (file)
index 0000000..493b311
--- /dev/null
@@ -0,0 +1,167 @@
+/***************************************************************************/
+
+/*
+ *     pit.c -- Freescale ColdFire PIT timer. Currently this type of
+ *              hardware timer only exists in the Freescale ColdFire
+ *              5270/5271, 5282 and 5208 CPUs. No doubt newer ColdFire
+ *              family members will probably use it too.
+ *
+ *     Copyright (C) 1999-2008, Greg Ungerer (gerg@snapgear.com)
+ *     Copyright (C) 2001-2004, SnapGear Inc. (www.snapgear.com)
+ */
+
+/***************************************************************************/
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/param.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/clockchips.h>
+#include <asm/machdep.h>
+#include <asm/io.h>
+#include <asm/coldfire.h>
+#include <asm/mcfpit.h>
+#include <asm/mcfsim.h>
+
+/***************************************************************************/
+
+/*
+ *     By default use timer1 as the system clock timer.
+ */
+#define        FREQ    ((MCF_CLK / 2) / 64)
+#define        TA(a)   (MCFPIT_BASE1 + (a))
+#define PIT_CYCLES_PER_JIFFY (FREQ / HZ)
+
+static u32 pit_cnt;
+
+/*
+ * Initialize the PIT timer.
+ *
+ * This is also called after resume to bring the PIT into operation again.
+ */
+
+static void init_cf_pit_timer(enum clock_event_mode mode,
+                             struct clock_event_device *evt)
+{
+       switch (mode) {
+       case CLOCK_EVT_MODE_PERIODIC:
+
+               __raw_writew(MCFPIT_PCSR_DISABLE, TA(MCFPIT_PCSR));
+               __raw_writew(PIT_CYCLES_PER_JIFFY, TA(MCFPIT_PMR));
+               __raw_writew(MCFPIT_PCSR_EN | MCFPIT_PCSR_PIE | \
+                               MCFPIT_PCSR_OVW | MCFPIT_PCSR_RLD | \
+                               MCFPIT_PCSR_CLK64, TA(MCFPIT_PCSR));
+               break;
+
+       case CLOCK_EVT_MODE_SHUTDOWN:
+       case CLOCK_EVT_MODE_UNUSED:
+
+               __raw_writew(MCFPIT_PCSR_DISABLE, TA(MCFPIT_PCSR));
+               break;
+
+       case CLOCK_EVT_MODE_ONESHOT:
+
+               __raw_writew(MCFPIT_PCSR_DISABLE, TA(MCFPIT_PCSR));
+               __raw_writew(MCFPIT_PCSR_EN | MCFPIT_PCSR_PIE | \
+                               MCFPIT_PCSR_OVW | MCFPIT_PCSR_CLK64, \
+                               TA(MCFPIT_PCSR));
+               break;
+
+       case CLOCK_EVT_MODE_RESUME:
+               /* Nothing to do here */
+               break;
+       }
+}
+
+/*
+ * Program the next event in oneshot mode
+ *
+ * Delta is given in PIT ticks
+ */
+static int cf_pit_next_event(unsigned long delta,
+               struct clock_event_device *evt)
+{
+       __raw_writew(delta, TA(MCFPIT_PMR));
+       return 0;
+}
+
+struct clock_event_device cf_pit_clockevent = {
+       .name           = "pit",
+       .features       = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
+       .set_mode       = init_cf_pit_timer,
+       .set_next_event = cf_pit_next_event,
+       .shift          = 32,
+       .irq            = MCF_IRQ_PIT1,
+};
+
+
+
+/***************************************************************************/
+
+static irqreturn_t pit_tick(int irq, void *dummy)
+{
+       struct clock_event_device *evt = &cf_pit_clockevent;
+       u16 pcsr;
+
+       /* Reset the ColdFire timer */
+       pcsr = __raw_readw(TA(MCFPIT_PCSR));
+       __raw_writew(pcsr | MCFPIT_PCSR_PIF, TA(MCFPIT_PCSR));
+
+       pit_cnt += PIT_CYCLES_PER_JIFFY;
+       evt->event_handler(evt);
+       return IRQ_HANDLED;
+}
+
+/***************************************************************************/
+
+static struct irqaction pit_irq = {
+       .name    = "timer",
+       .flags   = IRQF_TIMER,
+       .handler = pit_tick,
+};
+
+/***************************************************************************/
+
+static cycle_t pit_read_clk(struct clocksource *cs)
+{
+       unsigned long flags;
+       u32 cycles;
+       u16 pcntr;
+
+       local_irq_save(flags);
+       pcntr = __raw_readw(TA(MCFPIT_PCNTR));
+       cycles = pit_cnt;
+       local_irq_restore(flags);
+
+       return cycles + PIT_CYCLES_PER_JIFFY - pcntr;
+}
+
+/***************************************************************************/
+
+static struct clocksource pit_clk = {
+       .name   = "pit",
+       .rating = 100,
+       .read   = pit_read_clk,
+       .mask   = CLOCKSOURCE_MASK(32),
+};
+
+/***************************************************************************/
+
+void hw_timer_init(irq_handler_t handler)
+{
+       cf_pit_clockevent.cpumask = cpumask_of(smp_processor_id());
+       cf_pit_clockevent.mult = div_sc(FREQ, NSEC_PER_SEC, 32);
+       cf_pit_clockevent.max_delta_ns =
+               clockevent_delta2ns(0xFFFF, &cf_pit_clockevent);
+       cf_pit_clockevent.min_delta_ns =
+               clockevent_delta2ns(0x3f, &cf_pit_clockevent);
+       clockevents_register_device(&cf_pit_clockevent);
+
+       setup_irq(MCF_IRQ_PIT1, &pit_irq);
+
+       clocksource_register_hz(&pit_clk, FREQ);
+}
+
+/***************************************************************************/
diff --git a/arch/m68k/coldfire/reset.c b/arch/m68k/coldfire/reset.c
new file mode 100644 (file)
index 0000000..f30952f
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * reset.c  -- common ColdFire SoC reset support
+ *
+ * (C) Copyright 2012, Greg Ungerer <gerg@uclinux.org>
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file COPYING in the main directory of this archive
+ * for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <asm/machdep.h>
+#include <asm/coldfire.h>
+#include <asm/mcfsim.h>
+
+/*
+ *     There are 2 common methods amongst the ColdFure parts for reseting
+ *     the CPU. But there are couple of exceptions, the 5272 and the 547x
+ *     have something completely special to them, and we let their specific
+ *     subarch code handle them.
+ */
+
+#ifdef MCFSIM_SYPCR
+static void mcf_cpu_reset(void)
+{
+       local_irq_disable();
+       /* Set watchdog to soft reset, and enabled */
+       __raw_writeb(0xc0, MCFSIM_SYPCR);
+       for (;;)
+               /* wait for watchdog to timeout */;
+}
+#endif
+
+#ifdef MCF_RCR
+static void mcf_cpu_reset(void)
+{
+       local_irq_disable();
+       __raw_writeb(MCF_RCR_SWRESET, MCF_RCR);
+}
+#endif
+
+static int __init mcf_setup_reset(void)
+{
+       mach_reset = mcf_cpu_reset;
+       return 0;
+}
+
+arch_initcall(mcf_setup_reset);
diff --git a/arch/m68k/coldfire/sltimers.c b/arch/m68k/coldfire/sltimers.c
new file mode 100644 (file)
index 0000000..831a08c
--- /dev/null
@@ -0,0 +1,149 @@
+/***************************************************************************/
+
+/*
+ *     sltimers.c -- generic ColdFire slice timer support.
+ *
+ *     Copyright (C) 2009-2010, Philippe De Muyter <phdm@macqel.be>
+ *     based on
+ *     timers.c -- generic ColdFire hardware timer support.
+ *     Copyright (C) 1999-2008, Greg Ungerer <gerg@snapgear.com>
+ */
+
+/***************************************************************************/
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/profile.h>
+#include <linux/clocksource.h>
+#include <asm/io.h>
+#include <asm/traps.h>
+#include <asm/machdep.h>
+#include <asm/coldfire.h>
+#include <asm/mcfslt.h>
+#include <asm/mcfsim.h>
+
+/***************************************************************************/
+
+#ifdef CONFIG_HIGHPROFILE
+
+/*
+ *     By default use Slice Timer 1 as the profiler clock timer.
+ */
+#define        PA(a)   (MCFSLT_TIMER1 + (a))
+
+/*
+ *     Choose a reasonably fast profile timer. Make it an odd value to
+ *     try and get good coverage of kernel operations.
+ */
+#define        PROFILEHZ       1013
+
+irqreturn_t mcfslt_profile_tick(int irq, void *dummy)
+{
+       /* Reset Slice Timer 1 */
+       __raw_writel(MCFSLT_SSR_BE | MCFSLT_SSR_TE, PA(MCFSLT_SSR));
+       if (current->pid)
+               profile_tick(CPU_PROFILING);
+       return IRQ_HANDLED;
+}
+
+static struct irqaction mcfslt_profile_irq = {
+       .name    = "profile timer",
+       .flags   = IRQF_TIMER,
+       .handler = mcfslt_profile_tick,
+};
+
+void mcfslt_profile_init(void)
+{
+       printk(KERN_INFO "PROFILE: lodging TIMER 1 @ %dHz as profile timer\n",
+              PROFILEHZ);
+
+       setup_irq(MCF_IRQ_PROFILER, &mcfslt_profile_irq);
+
+       /* Set up TIMER 2 as high speed profile clock */
+       __raw_writel(MCF_BUSCLK / PROFILEHZ - 1, PA(MCFSLT_STCNT));
+       __raw_writel(MCFSLT_SCR_RUN | MCFSLT_SCR_IEN | MCFSLT_SCR_TEN,
+                                                               PA(MCFSLT_SCR));
+
+}
+
+#endif /* CONFIG_HIGHPROFILE */
+
+/***************************************************************************/
+
+/*
+ *     By default use Slice Timer 0 as the system clock timer.
+ */
+#define        TA(a)   (MCFSLT_TIMER0 + (a))
+
+static u32 mcfslt_cycles_per_jiffy;
+static u32 mcfslt_cnt;
+
+static irq_handler_t timer_interrupt;
+
+static irqreturn_t mcfslt_tick(int irq, void *dummy)
+{
+       /* Reset Slice Timer 0 */
+       __raw_writel(MCFSLT_SSR_BE | MCFSLT_SSR_TE, TA(MCFSLT_SSR));
+       mcfslt_cnt += mcfslt_cycles_per_jiffy;
+       return timer_interrupt(irq, dummy);
+}
+
+static struct irqaction mcfslt_timer_irq = {
+       .name    = "timer",
+       .flags   = IRQF_TIMER,
+       .handler = mcfslt_tick,
+};
+
+static cycle_t mcfslt_read_clk(struct clocksource *cs)
+{
+       unsigned long flags;
+       u32 cycles, scnt;
+
+       local_irq_save(flags);
+       scnt = __raw_readl(TA(MCFSLT_SCNT));
+       cycles = mcfslt_cnt;
+       if (__raw_readl(TA(MCFSLT_SSR)) & MCFSLT_SSR_TE) {
+               cycles += mcfslt_cycles_per_jiffy;
+               scnt = __raw_readl(TA(MCFSLT_SCNT));
+       }
+       local_irq_restore(flags);
+
+       /* subtract because slice timers count down */
+       return cycles + ((mcfslt_cycles_per_jiffy - 1) - scnt);
+}
+
+static struct clocksource mcfslt_clk = {
+       .name   = "slt",
+       .rating = 250,
+       .read   = mcfslt_read_clk,
+       .mask   = CLOCKSOURCE_MASK(32),
+       .flags  = CLOCK_SOURCE_IS_CONTINUOUS,
+};
+
+void hw_timer_init(irq_handler_t handler)
+{
+       mcfslt_cycles_per_jiffy = MCF_BUSCLK / HZ;
+       /*
+        *      The coldfire slice timer (SLT) runs from STCNT to 0 included,
+        *      then STCNT again and so on.  It counts thus actually
+        *      STCNT + 1 steps for 1 tick, not STCNT.  So if you want
+        *      n cycles, initialize STCNT with n - 1.
+        */
+       __raw_writel(mcfslt_cycles_per_jiffy - 1, TA(MCFSLT_STCNT));
+       __raw_writel(MCFSLT_SCR_RUN | MCFSLT_SCR_IEN | MCFSLT_SCR_TEN,
+                                                               TA(MCFSLT_SCR));
+       /* initialize mcfslt_cnt knowing that slice timers count down */
+       mcfslt_cnt = mcfslt_cycles_per_jiffy;
+
+       timer_interrupt = handler;
+       setup_irq(MCF_IRQ_TIMER, &mcfslt_timer_irq);
+
+       clocksource_register_hz(&mcfslt_clk, MCF_BUSCLK);
+
+#ifdef CONFIG_HIGHPROFILE
+       mcfslt_profile_init();
+#endif
+}
diff --git a/arch/m68k/coldfire/timers.c b/arch/m68k/coldfire/timers.c
new file mode 100644 (file)
index 0000000..cd496a2
--- /dev/null
@@ -0,0 +1,195 @@
+/***************************************************************************/
+
+/*
+ *     timers.c -- generic ColdFire hardware timer support.
+ *
+ *     Copyright (C) 1999-2008, Greg Ungerer <gerg@snapgear.com>
+ */
+
+/***************************************************************************/
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/profile.h>
+#include <linux/clocksource.h>
+#include <asm/io.h>
+#include <asm/traps.h>
+#include <asm/machdep.h>
+#include <asm/coldfire.h>
+#include <asm/mcftimer.h>
+#include <asm/mcfsim.h>
+
+/***************************************************************************/
+
+/*
+ *     By default use timer1 as the system clock timer.
+ */
+#define        FREQ    (MCF_BUSCLK / 16)
+#define        TA(a)   (MCFTIMER_BASE1 + (a))
+
+/*
+ *     These provide the underlying interrupt vector support.
+ *     Unfortunately it is a little different on each ColdFire.
+ */
+void coldfire_profile_init(void);
+
+#if defined(CONFIG_M53xx) || defined(CONFIG_M5441x)
+#define        __raw_readtrr   __raw_readl
+#define        __raw_writetrr  __raw_writel
+#else
+#define        __raw_readtrr   __raw_readw
+#define        __raw_writetrr  __raw_writew
+#endif
+
+static u32 mcftmr_cycles_per_jiffy;
+static u32 mcftmr_cnt;
+
+static irq_handler_t timer_interrupt;
+
+/***************************************************************************/
+
+static void init_timer_irq(void)
+{
+#ifdef MCFSIM_ICR_AUTOVEC
+       /* Timer1 is always used as system timer */
+       writeb(MCFSIM_ICR_AUTOVEC | MCFSIM_ICR_LEVEL6 | MCFSIM_ICR_PRI3,
+               MCFSIM_TIMER1ICR);
+       mcf_mapirq2imr(MCF_IRQ_TIMER, MCFINTC_TIMER1);
+
+#ifdef CONFIG_HIGHPROFILE
+       /* Timer2 is to be used as a high speed profile timer  */
+       writeb(MCFSIM_ICR_AUTOVEC | MCFSIM_ICR_LEVEL7 | MCFSIM_ICR_PRI3,
+               MCFSIM_TIMER2ICR);
+       mcf_mapirq2imr(MCF_IRQ_PROFILER, MCFINTC_TIMER2);
+#endif
+#endif /* MCFSIM_ICR_AUTOVEC */
+}
+
+/***************************************************************************/
+
+static irqreturn_t mcftmr_tick(int irq, void *dummy)
+{
+       /* Reset the ColdFire timer */
+       __raw_writeb(MCFTIMER_TER_CAP | MCFTIMER_TER_REF, TA(MCFTIMER_TER));
+
+       mcftmr_cnt += mcftmr_cycles_per_jiffy;
+       return timer_interrupt(irq, dummy);
+}
+
+/***************************************************************************/
+
+static struct irqaction mcftmr_timer_irq = {
+       .name    = "timer",
+       .flags   = IRQF_TIMER,
+       .handler = mcftmr_tick,
+};
+
+/***************************************************************************/
+
+static cycle_t mcftmr_read_clk(struct clocksource *cs)
+{
+       unsigned long flags;
+       u32 cycles;
+       u16 tcn;
+
+       local_irq_save(flags);
+       tcn = __raw_readw(TA(MCFTIMER_TCN));
+       cycles = mcftmr_cnt;
+       local_irq_restore(flags);
+
+       return cycles + tcn;
+}
+
+/***************************************************************************/
+
+static struct clocksource mcftmr_clk = {
+       .name   = "tmr",
+       .rating = 250,
+       .read   = mcftmr_read_clk,
+       .mask   = CLOCKSOURCE_MASK(32),
+       .flags  = CLOCK_SOURCE_IS_CONTINUOUS,
+};
+
+/***************************************************************************/
+
+void hw_timer_init(irq_handler_t handler)
+{
+       __raw_writew(MCFTIMER_TMR_DISABLE, TA(MCFTIMER_TMR));
+       mcftmr_cycles_per_jiffy = FREQ / HZ;
+       /*
+        *      The coldfire timer runs from 0 to TRR included, then 0
+        *      again and so on.  It counts thus actually TRR + 1 steps
+        *      for 1 tick, not TRR.  So if you want n cycles,
+        *      initialize TRR with n - 1.
+        */
+       __raw_writetrr(mcftmr_cycles_per_jiffy - 1, TA(MCFTIMER_TRR));
+       __raw_writew(MCFTIMER_TMR_ENORI | MCFTIMER_TMR_CLK16 |
+               MCFTIMER_TMR_RESTART | MCFTIMER_TMR_ENABLE, TA(MCFTIMER_TMR));
+
+       clocksource_register_hz(&mcftmr_clk, FREQ);
+
+       timer_interrupt = handler;
+       init_timer_irq();
+       setup_irq(MCF_IRQ_TIMER, &mcftmr_timer_irq);
+
+#ifdef CONFIG_HIGHPROFILE
+       coldfire_profile_init();
+#endif
+}
+
+/***************************************************************************/
+#ifdef CONFIG_HIGHPROFILE
+/***************************************************************************/
+
+/*
+ *     By default use timer2 as the profiler clock timer.
+ */
+#define        PA(a)   (MCFTIMER_BASE2 + (a))
+
+/*
+ *     Choose a reasonably fast profile timer. Make it an odd value to
+ *     try and get good coverage of kernel operations.
+ */
+#define        PROFILEHZ       1013
+
+/*
+ *     Use the other timer to provide high accuracy profiling info.
+ */
+irqreturn_t coldfire_profile_tick(int irq, void *dummy)
+{
+       /* Reset ColdFire timer2 */
+       __raw_writeb(MCFTIMER_TER_CAP | MCFTIMER_TER_REF, PA(MCFTIMER_TER));
+       if (current->pid)
+               profile_tick(CPU_PROFILING);
+       return IRQ_HANDLED;
+}
+
+/***************************************************************************/
+
+static struct irqaction coldfire_profile_irq = {
+       .name    = "profile timer",
+       .flags   = IRQF_TIMER,
+       .handler = coldfire_profile_tick,
+};
+
+void coldfire_profile_init(void)
+{
+       printk(KERN_INFO "PROFILE: lodging TIMER2 @ %dHz as profile timer\n",
+              PROFILEHZ);
+
+       /* Set up TIMER 2 as high speed profile clock */
+       __raw_writew(MCFTIMER_TMR_DISABLE, PA(MCFTIMER_TMR));
+
+       __raw_writetrr(((MCF_BUSCLK / 16) / PROFILEHZ), PA(MCFTIMER_TRR));
+       __raw_writew(MCFTIMER_TMR_ENORI | MCFTIMER_TMR_CLK16 |
+               MCFTIMER_TMR_RESTART | MCFTIMER_TMR_ENABLE, PA(MCFTIMER_TMR));
+
+       setup_irq(MCF_IRQ_PROFILER, &coldfire_profile_irq);
+}
+
+/***************************************************************************/
+#endif /* CONFIG_HIGHPROFILE */
+/***************************************************************************/
diff --git a/arch/m68k/coldfire/vectors.c b/arch/m68k/coldfire/vectors.c
new file mode 100644 (file)
index 0000000..08923fe
--- /dev/null
@@ -0,0 +1,70 @@
+/***************************************************************************/
+
+/*
+ *     vectors.c  -- high level trap setup for ColdFire
+ *
+ *     Copyright (C) 1999-2007, Greg Ungerer <gerg@snapgear.com>
+ */
+
+/***************************************************************************/
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/irq.h>
+#include <asm/traps.h>
+#include <asm/machdep.h>
+#include <asm/coldfire.h>
+#include <asm/mcfsim.h>
+#include <asm/mcfwdebug.h>
+
+/***************************************************************************/
+
+#ifdef TRAP_DBG_INTERRUPT
+
+asmlinkage void dbginterrupt_c(struct frame *fp)
+{
+       extern void dump(struct pt_regs *fp);
+       printk(KERN_DEBUG "%s(%d): BUS ERROR TRAP\n", __FILE__, __LINE__);
+       dump((struct pt_regs *) fp);
+       asm("halt");
+}
+
+#endif
+
+/***************************************************************************/
+
+/* Assembler routines */
+asmlinkage void buserr(void);
+asmlinkage void trap(void);
+asmlinkage void system_call(void);
+asmlinkage void inthandler(void);
+
+void __init trap_init(void)
+{
+       int i;
+
+       /*
+        *      There is a common trap handler and common interrupt
+        *      handler that handle almost every vector. We treat
+        *      the system call and bus error special, they get their
+        *      own first level handlers.
+        */
+       for (i = 3; (i <= 23); i++)
+               _ramvec[i] = trap;
+       for (i = 33; (i <= 63); i++)
+               _ramvec[i] = trap;
+       for (i = 24; (i <= 31); i++)
+               _ramvec[i] = inthandler;
+       for (i = 64; (i < 255); i++)
+               _ramvec[i] = inthandler;
+       _ramvec[255] = 0;
+
+       _ramvec[2] = buserr;
+       _ramvec[32] = system_call;
+
+#ifdef TRAP_DBG_INTERRUPT
+       _ramvec[12] = dbginterrupt;
+#endif
+}
+
+/***************************************************************************/
index 55695212a2ae98ec9f4e6c6e5c7289a6cd36651b..e85f047fb072e8aa3aff7bc56b9afc3b33ff842d 100644 (file)
@@ -17,7 +17,7 @@
 
 #define ATOMIC_INIT(i) { (i) }
 
-#define atomic_read(v)         (*(volatile int *)&(v)->counter)
+#define atomic_read(v)         ACCESS_ONCE((v)->counter)
 #define atomic_set(v, i)       (((v)->counter) = i)
 
 /*
 #define        ASM_DI  "di"
 #endif
 
-static inline void atomic_add(int i, atomic_t *v)
-{
-       __asm__ __volatile__("addl %1,%0" : "+m" (*v) : ASM_DI (i));
+#define ATOMIC_OP(op, c_op, asm_op)                                    \
+static inline void atomic_##op(int i, atomic_t *v)                     \
+{                                                                      \
+       __asm__ __volatile__(#asm_op "l %1,%0" : "+m" (*v) : ASM_DI (i));\
+}                                                                      \
+
+#ifdef CONFIG_RMW_INSNS
+
+#define ATOMIC_OP_RETURN(op, c_op, asm_op)                             \
+static inline int atomic_##op##_return(int i, atomic_t *v)             \
+{                                                                      \
+       int t, tmp;                                                     \
+                                                                       \
+       __asm__ __volatile__(                                           \
+                       "1:     movel %2,%1\n"                          \
+                       "       " #asm_op "l %3,%1\n"                   \
+                       "       casl %2,%1,%0\n"                        \
+                       "       jne 1b"                                 \
+                       : "+m" (*v), "=&d" (t), "=&d" (tmp)             \
+                       : "g" (i), "2" (atomic_read(v)));               \
+       return t;                                                       \
 }
 
-static inline void atomic_sub(int i, atomic_t *v)
-{
-       __asm__ __volatile__("subl %1,%0" : "+m" (*v) : ASM_DI (i));
+#else
+
+#define ATOMIC_OP_RETURN(op, c_op, asm_op)                             \
+static inline int atomic_##op##_return(int i, atomic_t * v)            \
+{                                                                      \
+       unsigned long flags;                                            \
+       int t;                                                          \
+                                                                       \
+       local_irq_save(flags);                                          \
+       t = (v->counter c_op i);                                        \
+       local_irq_restore(flags);                                       \
+                                                                       \
+       return t;                                                       \
 }
 
+#endif /* CONFIG_RMW_INSNS */
+
+#define ATOMIC_OPS(op, c_op, asm_op)                                   \
+       ATOMIC_OP(op, c_op, asm_op)                                     \
+       ATOMIC_OP_RETURN(op, c_op, asm_op)
+
+ATOMIC_OPS(add, +=, add)
+ATOMIC_OPS(sub, -=, sub)
+
+#undef ATOMIC_OPS
+#undef ATOMIC_OP_RETURN
+#undef ATOMIC_OP
+
 static inline void atomic_inc(atomic_t *v)
 {
        __asm__ __volatile__("addql #1,%0" : "+m" (*v));
@@ -76,67 +117,11 @@ static inline int atomic_inc_and_test(atomic_t *v)
 
 #ifdef CONFIG_RMW_INSNS
 
-static inline int atomic_add_return(int i, atomic_t *v)
-{
-       int t, tmp;
-
-       __asm__ __volatile__(
-                       "1:     movel %2,%1\n"
-                       "       addl %3,%1\n"
-                       "       casl %2,%1,%0\n"
-                       "       jne 1b"
-                       : "+m" (*v), "=&d" (t), "=&d" (tmp)
-                       : "g" (i), "2" (atomic_read(v)));
-       return t;
-}
-
-static inline int atomic_sub_return(int i, atomic_t *v)
-{
-       int t, tmp;
-
-       __asm__ __volatile__(
-                       "1:     movel %2,%1\n"
-                       "       subl %3,%1\n"
-                       "       casl %2,%1,%0\n"
-                       "       jne 1b"
-                       : "+m" (*v), "=&d" (t), "=&d" (tmp)
-                       : "g" (i), "2" (atomic_read(v)));
-       return t;
-}
-
 #define atomic_cmpxchg(v, o, n) ((int)cmpxchg(&((v)->counter), (o), (n)))
 #define atomic_xchg(v, new) (xchg(&((v)->counter), new))
 
 #else /* !CONFIG_RMW_INSNS */
 
-static inline int atomic_add_return(int i, atomic_t * v)
-{
-       unsigned long flags;
-       int t;
-
-       local_irq_save(flags);
-       t = atomic_read(v);
-       t += i;
-       atomic_set(v, t);
-       local_irq_restore(flags);
-
-       return t;
-}
-
-static inline int atomic_sub_return(int i, atomic_t * v)
-{
-       unsigned long flags;
-       int t;
-
-       local_irq_save(flags);
-       t = atomic_read(v);
-       t -= i;
-       atomic_set(v, t);
-       local_irq_restore(flags);
-
-       return t;
-}
-
 static inline int atomic_cmpxchg(atomic_t *v, int old, int new)
 {
        unsigned long flags;
index 52f7e8499172e101b5ba3d925c9d9d9694c325c1..be4b5a813ad401972624886802f5f69aa047e7dc 100644 (file)
@@ -179,6 +179,15 @@ static inline void *ioremap_fullcache(unsigned long physaddr, unsigned long size
  */
 #define xlate_dev_kmem_ptr(p)  p
 
+static inline void __iomem *ioport_map(unsigned long port, unsigned int nr)
+{
+       return (void __iomem *) port;
+}
+
+static inline void ioport_unmap(void __iomem *p)
+{
+}
+
 #endif /* __KERNEL__ */
 
 #endif /* _M68KNOMMU_IO_H */
index 6fbf54f72f2e0a5cc27b7b29207e68e2d702826c..4687f5aa374170c5780fb1f817e08770654f303d 100644 (file)
@@ -72,7 +72,7 @@
 #define        PCIRFWPR        (CONFIG_MBAR + 0x84d4)  /* RX FIFO write pointer */
 
 #define        PACR            (CONFIG_MBAR + 0xc00)   /* PCI arbiter control */
-#define        PASR            (COFNIG_MBAR + 0xc04)   /* PCI arbiter status */
+#define        PASR            (CONFIG_MBAR + 0xc04)   /* PCI arbiter status */
 
 /*
  *     Definitions for the Global status and control register.
diff --git a/arch/m68k/platform/68000/Makefile b/arch/m68k/platform/68000/Makefile
deleted file mode 100644 (file)
index 1eab70c..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-##################################################
-#
-# Makefile for 68000 core based cpus
-#
-# 2012.10.21, Luis Alves <ljalvs@gmail.com>
-#             Merged all 68000 based cpu's config
-#             files into a single directory.
-#
-
-# 68328, 68EZ328, 68VZ328
-
-obj-y                  += entry.o ints.o timers.o
-obj-$(CONFIG_M68328)   += m68328.o
-obj-$(CONFIG_M68EZ328) += m68EZ328.o
-obj-$(CONFIG_M68VZ328) += m68VZ328.o
-obj-$(CONFIG_ROM)      += romvec.o
-
-extra-y                := head.o
diff --git a/arch/m68k/platform/68000/bootlogo-vz.h b/arch/m68k/platform/68000/bootlogo-vz.h
deleted file mode 100644 (file)
index b38e2b2..0000000
+++ /dev/null
@@ -1,3204 +0,0 @@
-#define splash_width 640
-#define splash_height 480
-unsigned char __attribute__ ((aligned(16))) bootlogo_bits[] = {
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x80, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0xff,
-  0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0xf8, 0xff, 0xff, 0xff, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff,
-  0xff, 0xff, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0xc0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x03, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0xff, 0xff, 0xff,
-  0xff, 0xff, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0xf8, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xff, 0xff,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
-  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x0f, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xff, 0xff, 0xff, 0xff,
-  0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0xe0, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-  0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8,
-  0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8,
-  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x07, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xff, 0x7f, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0xff, 0xff, 0xff, 0xff,
-  0xff, 0xff, 0xff, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0xe0, 0xff, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-  0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0,
-  0x03, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xff,
-  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x00, 0xfe, 0xff, 0x1f,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xff, 0xff, 0xff, 0xff, 0xff,
-  0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x7c, 0x00, 0xe0, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0xe0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-  0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c,
-  0x00, 0x00, 0xf8, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xff,
-  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0xe0, 0x7f,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xff,
-  0xff, 0xff, 0xff, 0xff, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0xfc, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-  0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xff,
-  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff,
-  0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-  0xff, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xff, 0xff,
-  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0xc0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-  0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xff, 0xff,
-  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-  0xff, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xff, 0xff,
-  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x07, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x01, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0xe0, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0xfc, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-  0xff, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0,
-  0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0xff, 0xff,
-  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0f, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x7f, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0xfc, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-  0xff, 0xff, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe,
-  0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff,
-  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0x3f, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x3e, 0xf8, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x80, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-  0xff, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e,
-  0x00, 0xfe, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xff, 0xff, 0xff,
-  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x00, 0xfe, 0xff, 0x1f,
-  0x00, 0x00, 0x00, 0x00, 0x80, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00,
-  0xc0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-  0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0xfc, 0x7f, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xff, 0xff, 0xff,
-  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x7f,
-  0x00, 0x00, 0x00, 0x00, 0xc0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x00,
-  0xe0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-  0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xff, 0x7f, 0xe0,
-  0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0xe0, 0xff, 0xff, 0xff, 0xff, 0x01,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0xe0, 0xff, 0x7f, 0xe0, 0xff, 0xff, 0xff, 0xff,
-  0xff, 0x7f, 0xe0, 0xff, 0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0xe0, 0xff, 0x7f, 0xe0, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0xe0, 0xff,
-  0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0xe0, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xff, 0x7f, 0xe0,
-  0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0xe0, 0xff, 0xff, 0xff, 0xff, 0x03,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xff, 0x1f,
-  0x00, 0x00, 0x00, 0x00, 0xf0, 0xff, 0x7f, 0xe0, 0xff, 0xff, 0xff, 0xff,
-  0xff, 0x7f, 0xe0, 0xff, 0xff, 0xff, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00,
-  0xf0, 0xff, 0x7f, 0xe0, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0xe0, 0xff,
-  0xff, 0xff, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0xf0, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xff, 0x7f, 0xe0,
-  0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0xe0, 0xff, 0x07, 0xfe, 0xff, 0x03,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0xff, 0xff,
-  0x03, 0x00, 0x00, 0x00, 0xf0, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0xe0, 0xff, 0x01, 0xf8, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x80, 0xff, 0xff, 0xff, 0xff, 0x0f, 0x00, 0x00, 0x00,
-  0xf8, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xff,
-  0x00, 0xf0, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
-  0xff, 0xff, 0xff, 0xff, 0x1f, 0x00, 0x00, 0x00, 0xf8, 0xff, 0x7f, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x7f, 0x00, 0xe0, 0xff, 0x07,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xff, 0xff, 0xff, 0x03,
-  0x3f, 0x00, 0x00, 0x00, 0xf8, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0xe0, 0x3f, 0x00, 0xc0, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0xf8, 0xff, 0xff, 0xff, 0x0f, 0xfc, 0x00, 0x00, 0x00,
-  0xf8, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x1f,
-  0x00, 0x80, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8,
-  0xff, 0xff, 0xff, 0x3f, 0xf0, 0x01, 0x00, 0x00, 0xf8, 0xff, 0x7f, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x1f, 0x00, 0x80, 0xff, 0x07,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x3f, 0x00, 0xc0, 0xff,
-  0xc1, 0x03, 0x00, 0x00, 0xf8, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0xe0, 0x0f, 0x00, 0x00, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0xfe, 0x0f, 0x00, 0x00, 0xfc, 0x07, 0x07, 0x00, 0x00,
-  0xf8, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x0f,
-  0x00, 0x00, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe,
-  0x07, 0x00, 0x00, 0xe0, 0x07, 0x0e, 0x00, 0x00, 0xf8, 0xff, 0x7f, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x0f, 0x00, 0x00, 0xff, 0x07,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x01, 0x00, 0x00, 0x00,
-  0x3f, 0x1c, 0x00, 0x00, 0xf8, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0xe0, 0x0f, 0x00, 0x00, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x38, 0x00, 0x00,
-  0xf8, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x0f,
-  0x00, 0x00, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e,
-  0x00, 0x00, 0x00, 0x00, 0x78, 0x70, 0x00, 0x00, 0xf8, 0xff, 0x7f, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x0f, 0x00, 0x00, 0xff, 0x07,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00,
-  0xf0, 0xe0, 0x00, 0x00, 0xf8, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0xe0, 0x0f, 0x00, 0x00, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xc3, 0x01, 0x00,
-  0xf8, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x1f,
-  0x00, 0x80, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f,
-  0x00, 0x00, 0x00, 0x00, 0x80, 0xc7, 0x03, 0x00, 0xf8, 0xff, 0x7f, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x1f, 0x00, 0x80, 0xff, 0x07,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x87, 0x03, 0x00, 0xf8, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0xe0, 0x3f, 0x00, 0xc0, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x07, 0x00,
-  0xf8, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x7f,
-  0x00, 0xe0, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x1f,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x0e, 0x00, 0xf0, 0xff, 0x7f, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xff, 0x00, 0xf0, 0xff, 0x03,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x1f, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x30, 0x0c, 0x00, 0xf0, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0xe0, 0xff, 0x01, 0xf8, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x1c, 0x00,
-  0xf0, 0xff, 0x7f, 0xe0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-  0x07, 0xfe, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x38, 0x00, 0xf0, 0xff, 0x7f, 0xe0,
-  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x80, 0x38, 0x00, 0xf0, 0xff, 0x7f, 0xe0, 0xff, 0xff, 0xff, 0xff,
-  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x71, 0x00,
-  0xe0, 0xff, 0x7f, 0xe0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-  0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x72, 0x00, 0xe0, 0xff, 0x7f, 0xe0,
-  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0xe2, 0x00, 0xe0, 0xff, 0x7f, 0xe0, 0xff, 0xff, 0xff, 0xff,
-  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x00,
-  0xe0, 0xff, 0x7f, 0xe0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-  0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x01, 0xc0, 0xff, 0xff, 0xff,
-  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0xe0, 0x01, 0xc0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x01,
-  0xc0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-  0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x03, 0x80, 0xff, 0xff, 0xff,
-  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0xc0, 0x03, 0x80, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x03,
-  0x80, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-  0xff, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x07, 0x00, 0xff, 0xff, 0xff,
-  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x01, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0xc0, 0x07, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0xe0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x07,
-  0x00, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-  0xff, 0xff, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
-  0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x07, 0x00, 0xfe, 0xff, 0xff,
-  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x03, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0xc0, 0x07, 0x00, 0xfc, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x07,
-  0x00, 0xfc, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-  0xff, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x07, 0x00, 0xf8, 0xff, 0xff,
-  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x07, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0xc0, 0x07, 0x00, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x07,
-  0x00, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-  0xff, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x07, 0x00, 0xf0, 0xff, 0xff,
-  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x07, 0x00, 0xe0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07,
-  0x00, 0xc0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-  0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xff, 0xff,
-  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-  0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x10, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-  0xff, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc,
-  0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xff,
-  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0f, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x9f, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff,
-  0xff, 0xff, 0xff, 0xff, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0xfe, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0xfc, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-  0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe,
-  0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xff,
-  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0x0f, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff,
-  0xff, 0xff, 0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x1c, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0xe0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-  0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c,
-  0xf8, 0xff, 0x1f, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xff,
-  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x80, 0xff, 0xff, 0x00,
-  0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xff, 0xff, 0xff, 0xff, 0xff,
-  0xff, 0xff, 0xff, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x38, 0x00, 0xfe, 0xff, 0x0f, 0x20, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-  0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70,
-  0x00, 0xf8, 0xff, 0xff, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc,
-  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0f, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x00, 0xc0, 0xff, 0xff,
-  0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xff, 0xff, 0xff, 0xff,
-  0xff, 0xff, 0xff, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x80, 0x03, 0x00, 0xfc, 0xff, 0x7f, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-  0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x03, 0x00, 0xe0, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
-  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe,
-  0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xff, 0xff, 0xff, 0xff,
-  0xff, 0xff, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x7f, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0xfc, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xff, 0xff, 0xff,
-  0xff, 0xff, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0xc0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x07, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xff, 0xff,
-  0xff, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0xfe, 0x3f, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe,
-  0xff, 0x03, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0xfc, 0xff, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0x1f, 0xc0, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xff,
-  0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0xfe, 0xff, 0xff, 0xc1, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c,
-  0xfe, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0xf0, 0xff, 0xff, 0x01,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x38, 0x00, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70,
-  0x00, 0xf8, 0xff, 0x01, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x00, 0xc0, 0xff, 0x01,
-  0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0xc0, 0x01, 0x00, 0xfc, 0x01, 0xff, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x80, 0x41, 0x08, 0x04, 0xb3, 0x07, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x01, 0x00, 0xe0, 0x03, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
-  0x41, 0x08, 0x04, 0xb3, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02,
-  0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x18, 0x8e, 0x31, 0x7b, 0x30,
-  0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x08, 0x00, 0x00, 0x18, 0x8e, 0x31, 0x7b, 0x30, 0x30, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0xf8,
-  0x41, 0xc6, 0x84, 0x0c, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x80, 0x0f, 0x00, 0x00, 0xf8, 0x41, 0xc6, 0x84, 0x0c,
-  0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0,
-  0x0f, 0x00, 0x00, 0x18, 0x0c, 0x08, 0x00, 0x40, 0xc0, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x0f, 0x00, 0x00, 0xe4,
-  0xb1, 0xc1, 0x98, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x03, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0xff, 0x09, 0x00, 0x00, 0xe4, 0xb1, 0xc1, 0x98, 0x00,
-  0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0xfc, 0x3f, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f,
-  0x08, 0x00, 0x00, 0x1c, 0x02, 0x08, 0x04, 0x4c, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc,
-  0xff, 0x01, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x10, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x1c,
-  0x02, 0x08, 0x04, 0x4c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0xff, 0x1f, 0xc0, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x10, 0x80,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x64, 0x4c, 0x00, 0x00, 0x00,
-  0x36, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0xf0, 0xff, 0xff, 0xc1, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0xf0, 0xff, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
-  0x09, 0x00, 0x00, 0x64, 0x4c, 0x00, 0x00, 0x00, 0x36, 0x01, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
-  0xff, 0x03, 0xf0, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x9c,
-  0x01, 0x08, 0x83, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xff, 0xff, 0x01,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x03, 0xf0, 0xff,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x80, 0x0f, 0x00, 0x00, 0x64, 0x8c, 0x01, 0x18, 0x40,
-  0x30, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0xe0, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0xff, 0xff, 0x03, 0xf0, 0xff, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0,
-  0x0f, 0x00, 0x00, 0x64, 0x8c, 0x01, 0x18, 0x40, 0x30, 0x01, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
-  0xff, 0x03, 0x10, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x0f, 0x00, 0x00, 0x9b,
-  0x01, 0xc0, 0x00, 0x00, 0xc6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbc, 0xff, 0x01,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x02, 0x00, 0x40,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0xff, 0x09, 0x00, 0x00, 0x9b, 0x01, 0xc0, 0x00, 0x00,
-  0xc6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0xc0, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0xf8, 0x01, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x01, 0x02, 0x02, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f,
-  0x00, 0x00, 0x00, 0x07, 0x32, 0x06, 0x18, 0x43, 0x00, 0x06, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0,
-  0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0xf0, 0xc1, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
-  0x02, 0x02, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x07,
-  0x32, 0x06, 0x18, 0x43, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xff, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x03, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x02, 0x10, 0xe0,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x70, 0x08, 0x00, 0x00, 0x7b, 0x00, 0x30, 0x03, 0x0c,
-  0x08, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0xf0, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0xe0, 0x07, 0x03, 0xf0, 0xff, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
-  0x09, 0x00, 0xc0, 0x84, 0x8d, 0x01, 0x80, 0x00, 0xc0, 0x06, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8,
-  0xfd, 0x03, 0xf0, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0xc0, 0x84,
-  0x8d, 0x01, 0x80, 0x00, 0xc0, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xfd, 0x03, 0xf0, 0x7f,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0xc0, 0x1b, 0x00, 0x30, 0x00, 0x40,
-  0x08, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0xff, 0xfc, 0x01, 0xf0, 0x3f, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x08, 0x00, 0xc0, 0x1b, 0x00, 0x30, 0x00, 0x40, 0x08, 0x18, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc,
-  0x07, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f,
-  0xf8, 0x01, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0xc0, 0x64,
-  0x42, 0x06, 0x1b, 0x03, 0x00, 0x61, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x80, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x7f, 0x00, 0xc0, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xf0, 0x00, 0x10, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0xc0, 0x64, 0x42, 0x06, 0x1b, 0x03,
-  0x00, 0x61, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0xf0, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0xfe, 0xff, 0x03, 0xe0, 0x01, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
-  0x0f, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x80, 0x30, 0x08, 0x86, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0,
-  0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe,
-  0xff, 0x3f, 0xc0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x0f, 0x00, 0x00, 0x1b,
-  0x00, 0x00, 0x80, 0x30, 0x08, 0x86, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xff, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0xff, 0xff, 0xc3, 0x03,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0xfc, 0x0f, 0x00, 0xe0, 0x84, 0x31, 0x30, 0x04, 0x80,
-  0xc1, 0x18, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0xf0, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x1c, 0xff, 0xff, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
-  0x09, 0x00, 0xc0, 0x63, 0x02, 0x06, 0x00, 0x00, 0x00, 0x60, 0x6c, 0xfc,
-  0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18,
-  0xe0, 0xff, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x08, 0x00, 0xc0, 0x63,
-  0x02, 0x06, 0x00, 0x00, 0x00, 0x60, 0x6c, 0xfc, 0xff, 0x03, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0xff, 0xff, 0x03,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0xe0, 0x1c, 0x40, 0x00, 0x1b, 0x4c,
-  0x06, 0x81, 0x80, 0xfd, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x70, 0x00, 0xf0, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70,
-  0x00, 0x00, 0xe0, 0x1c, 0x40, 0x00, 0x1b, 0x4c, 0x06, 0x81, 0x80, 0xfd,
-  0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0,
-  0x00, 0x80, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x09, 0x00, 0x20, 0x63,
-  0x0c, 0x08, 0x80, 0x00, 0x30, 0x06, 0x0c, 0xfc, 0xff, 0x7f, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x30, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x20, 0x63, 0x0c, 0x08, 0x80, 0x00,
-  0x30, 0x06, 0x0c, 0xfc, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x3f, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
-  0x0f, 0x00, 0xd8, 0x84, 0x01, 0xc0, 0x00, 0x00, 0x06, 0x00, 0x80, 0xf1,
-  0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
-  0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0xe0, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x0f, 0x00, 0xf8, 0x1b,
-  0x40, 0x08, 0x84, 0x0c, 0xc0, 0x18, 0x13, 0xcc, 0xff, 0xff, 0x0f, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xff, 0x0f, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x00, 0xe0, 0x7f,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0xfc, 0x0f, 0x00, 0xf8, 0x1b, 0x40, 0x08, 0x84, 0x0c,
-  0xc0, 0x18, 0x13, 0xcc, 0xff, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0xe0, 0xff, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0xfc, 0x03, 0x00, 0xf0, 0xe4, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
-  0x09, 0x00, 0x38, 0x80, 0x01, 0x00, 0x18, 0x30, 0x06, 0x01, 0x00, 0xc0,
-  0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30,
-  0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe,
-  0x07, 0x00, 0x30, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x38, 0x80,
-  0x01, 0x00, 0x18, 0x30, 0x06, 0x01, 0x00, 0xc0, 0xff, 0xff, 0xff, 0x01,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x30, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x07, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x07, 0x00, 0x10, 0x84,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0xd8, 0x1f, 0x30, 0x36, 0x80, 0x00,
-  0x00, 0x00, 0x03, 0xf2, 0xff, 0xff, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x10, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0xfc, 0x3f, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x4f, 0x0e, 0x00, 0x10, 0x84, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70,
-  0x08, 0x00, 0xd8, 0x1f, 0x30, 0x36, 0x80, 0x00, 0x00, 0x00, 0x03, 0xf2,
-  0xff, 0xff, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10,
-  0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe,
-  0xff, 0x03, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x43,
-  0x08, 0x00, 0x10, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x09, 0x00, 0x3e, 0x00,
-  0x82, 0x01, 0x03, 0x40, 0x30, 0x98, 0x10, 0xf0, 0xe7, 0xff, 0xff, 0xff,
-  0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x20, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0x1f, 0xc0, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x08, 0x00, 0x10, 0xe4,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0xe6, 0x1b, 0x00, 0x00, 0x18, 0x0c,
-  0x00, 0x00, 0x00, 0xfc, 0xff, 0xfb, 0xff, 0xff, 0x1f, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x10, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0xfe, 0xff, 0xff, 0xc1, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x41, 0x08, 0x00, 0x30, 0x7c, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x08, 0x00, 0xe6, 0x1b, 0x00, 0x00, 0x18, 0x0c, 0x00, 0x00, 0x00, 0xfc,
-  0xff, 0xfb, 0xff, 0xff, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10,
-  0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9e,
-  0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41,
-  0x08, 0x00, 0x20, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x1e, 0x64,
-  0x30, 0xc6, 0x80, 0x80, 0x09, 0x06, 0x63, 0xfe, 0xf9, 0xff, 0xff, 0xff,
-  0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x30, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0xf8, 0xff, 0xff, 0x01,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x0e, 0x00, 0xc0, 0x3c,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x1e, 0x64, 0x30, 0xc6, 0x80, 0x80,
-  0x09, 0x06, 0x63, 0xfe, 0xf9, 0xff, 0xff, 0xff, 0xff, 0x03, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x20, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x1c, 0x80, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0xc3, 0x07, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x0e, 0x00, 0x39, 0x03, 0x00, 0x00, 0x04, 0x0c, 0xc0, 0x60, 0x80, 0x3f,
-  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
-  0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c,
-  0x00, 0xfc, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc2,
-  0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x0f, 0x00, 0x39, 0x03,
-  0x00, 0x00, 0x04, 0x0c, 0xc0, 0x60, 0x80, 0x3f, 0xff, 0xff, 0xff, 0xff,
-  0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x3e, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0x80, 0xff, 0x01,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xcc, 0x03, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0xe0, 0x0f, 0x00, 0xe7, 0x04, 0x42, 0xc6, 0x00, 0x00,
-  0x00, 0x00, 0xec, 0xcf, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0x0f, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x80, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0xe0, 0x00, 0x00, 0xfc, 0x01, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc,
-  0x0f, 0xc0, 0x1f, 0x80, 0x01, 0x00, 0x98, 0x4c, 0x06, 0x06, 0xf0, 0x01,
-  0x00, 0xe0, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0,
-  0x01, 0x00, 0xc0, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x09, 0xc0, 0x1f, 0x80,
-  0x01, 0x00, 0x98, 0x4c, 0x06, 0x06, 0xf0, 0x01, 0x00, 0xe0, 0xff, 0xff,
-  0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x20, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x07, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x3f, 0x08, 0xc0, 0xe6, 0x04, 0x0c, 0x08, 0x00, 0x00,
-  0xc0, 0x60, 0x7c, 0x00, 0x00, 0x00, 0xc0, 0xff, 0xff, 0xff, 0xff, 0x01,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0xf0, 0x1f, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c,
-  0x00, 0xc0, 0xe6, 0x04, 0x0c, 0x08, 0x00, 0x00, 0xc0, 0x60, 0x7c, 0x00,
-  0x00, 0x00, 0xc0, 0xff, 0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0,
-  0xff, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0xc0, 0x19, 0x60,
-  0x40, 0x00, 0x63, 0x30, 0x08, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x00, 0xf8,
-  0xff, 0xf3, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xff, 0x3f, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0xc0, 0x09, 0xc0, 0x19, 0x60, 0x40, 0x00, 0x63, 0x30,
-  0x08, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xff, 0xf3, 0xff, 0x07,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0xf0, 0xff, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x78, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x0f, 0xc0, 0x27, 0x03, 0x00, 0x30, 0x00, 0x03, 0x00, 0xe6, 0x1f, 0x00,
-  0x00, 0x00, 0x00, 0xc0, 0xff, 0xff, 0xff, 0x1f, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10,
-  0xe0, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc,
-  0xcf, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0xe0, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x0f, 0xc0, 0x27, 0x03,
-  0x00, 0x30, 0x00, 0x03, 0x00, 0xe6, 0x1f, 0x00, 0x00, 0x00, 0x00, 0xc0,
-  0xff, 0xff, 0xff, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0x0f, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xff,
-  0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0xf0, 0x0f, 0xc0, 0xde, 0x04, 0x0c, 0x06, 0x03, 0x80,
-  0xc1, 0xf8, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0xff, 0xff, 0x7f,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0xfe, 0xff, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x0f, 0x03, 0x00, 0xf8, 0xff, 0x07, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc,
-  0x0f, 0xc0, 0x19, 0x00, 0x32, 0x00, 0x60, 0x30, 0x08, 0xff, 0x03, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0xe0, 0xff, 0xff, 0xff, 0x03, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe,
-  0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x9f,
-  0x07, 0x00, 0xf8, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x09, 0xc0, 0x19, 0x00,
-  0x32, 0x00, 0x60, 0x30, 0x08, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0xe0, 0xff, 0xff, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x80, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0xff, 0x07, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x9f, 0x07, 0x00, 0x18, 0x40,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x3f, 0x00, 0xc0, 0x27, 0x63, 0x80, 0x31, 0x04, 0x03,
-  0xf0, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff,
-  0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0xf8, 0x5f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x1c, 0xfe, 0xff, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x80, 0x1f, 0x07, 0x00, 0x18, 0x40, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c,
-  0x00, 0xc0, 0x27, 0x63, 0x80, 0x31, 0x04, 0x03, 0xf0, 0xff, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x1f, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8,
-  0x7f, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c,
-  0xe0, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x31,
-  0x04, 0x00, 0x10, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x08, 0x00, 0xd9, 0x04,
-  0x00, 0x08, 0x00, 0x80, 0xf9, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0xf0, 0xff, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x7f, 0x1e, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0xfe, 0xff, 0x01,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x20, 0x04, 0x00, 0x60, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0xc0, 0x09, 0x00, 0xd9, 0x04, 0x00, 0x08, 0x00, 0x80,
-  0xf9, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xff, 0xff,
-  0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0xf8, 0x7f, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x78, 0x00, 0xf0, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x80, 0x20, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x0f, 0xc0, 0x27, 0x00, 0x30, 0xc0, 0x60, 0xb0, 0xff, 0x7f, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xff, 0xff, 0xff, 0x01, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08,
-  0x60, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
-  0x00, 0x00, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41,
-  0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0xc0, 0xde, 0x9b,
-  0x8d, 0x01, 0x04, 0xc3, 0xff, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x80, 0xf1, 0xff, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbc, 0x03, 0x00, 0xf0, 0x01,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x07, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x08, 0xc0, 0xde, 0x9b, 0x8d, 0x01, 0x04, 0xc3,
-  0xff, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xf1, 0xff,
-  0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x3e, 0x03, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0xc0, 0x39, 0x04, 0x00, 0xc8, 0x00, 0xfc, 0xff, 0x07, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0xf8, 0xff, 0x3f, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xff,
-  0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0xc0, 0x39, 0x04,
-  0x00, 0xc8, 0x00, 0xfc, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0xc6, 0xf8, 0xff, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x40, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xff, 0x01, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x1f, 0x00, 0xc0, 0xc7, 0x60, 0x42, 0x00, 0x60, 0xff,
-  0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
-  0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0xf8, 0x5f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f,
-  0x00, 0xc0, 0xc7, 0x60, 0x42, 0x00, 0x60, 0xff, 0xff, 0x01, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xff, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8,
-  0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0xc0, 0xff, 0x07,
-  0xb0, 0x09, 0xe4, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x30, 0x00, 0xfc, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x7f, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x0e, 0x00, 0xc0, 0xde, 0x78, 0x02, 0x00, 0xfb, 0xff,
-  0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x80, 0xff, 0x1f, 0xf8, 0xff, 0xff, 0x1f, 0xf0, 0xff, 0xff, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0xf8, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0xc0, 0xde, 0x78, 0x02, 0x00, 0xfb, 0xff, 0xff, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xff, 0x1f, 0xf8,
-  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x08,
-  0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70,
-  0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0xc0, 0x3f, 0x07,
-  0xb0, 0xc9, 0xf8, 0xff, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-  0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x00, 0xc0, 0x01,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x08, 0xc0, 0x3f, 0x07, 0xb0, 0xc9, 0xf8, 0xff,
-  0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0f,
-  0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x80, 0x03, 0x00, 0xc0, 0x01, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc,
-  0x0f, 0x00, 0xe7, 0xfb, 0x43, 0x30, 0xf8, 0xff, 0x0f, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0xff, 0xff,
-  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00,
-  0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x07, 0x00, 0xc0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x0f, 0x00, 0xe7, 0xfb,
-  0x43, 0x30, 0xf8, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-  0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x08, 0x70, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0xe0, 0x01,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0xff, 0x0f, 0x00, 0xfe, 0x1c, 0xb2, 0x0f, 0xe0, 0xff,
-  0x07, 0x00, 0xe0, 0xff, 0xff, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0xc0, 0xff, 0xff, 0xcf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-  0x00, 0x00, 0x00, 0xf8, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x78, 0x00, 0xfc, 0x03, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
-  0x0f, 0x00, 0xf8, 0xe7, 0xfd, 0x01, 0xe0, 0xff, 0x07, 0x00, 0xe0, 0xff,
-  0xff, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc1, 0xe0,
-  0xb1, 0x3f, 0x00, 0xe0, 0xff, 0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0xf8,
-  0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0xf0, 0xc0, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0xf8, 0xe7,
-  0xfd, 0x01, 0xe0, 0xff, 0x07, 0x00, 0xe0, 0xff, 0xff, 0xff, 0x0f, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc1, 0xe0, 0xb1, 0x3f, 0x00, 0x00,
-  0xf8, 0xff, 0xff, 0xff, 0x07, 0x00, 0x00, 0xf8, 0x7f, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xff, 0xff, 0x03,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x01, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0xf8, 0xff, 0x7f, 0x00, 0x80, 0xff,
-  0x01, 0x00, 0xe0, 0x03, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x98, 0x4f, 0x0e, 0x18, 0x00, 0xf8, 0xff, 0xff, 0xff,
-  0x07, 0x00, 0x00, 0xf8, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0xf8, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03,
-  0x00, 0x00, 0xf8, 0xff, 0x7f, 0x00, 0x80, 0xff, 0x01, 0x00, 0xe0, 0x03,
-  0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x98,
-  0x4f, 0x0e, 0xf8, 0x1f, 0xf6, 0xff, 0xff, 0xff, 0x1f, 0x00, 0x00, 0x08,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
-  0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
-  0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0xf8, 0xff,
-  0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xb1, 0x01, 0xff, 0x1f,
-  0xf6, 0xff, 0xff, 0xff, 0x1f, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xff, 0xff, 0x1f, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x03, 0x07, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x04, 0x08, 0x00, 0xf8, 0xff, 0x7f, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0xf8, 0xb1, 0x01, 0xff, 0x7f, 0xc0, 0xff, 0xff, 0xff,
-  0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0xfc, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x80, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
-  0x0f, 0x00, 0xe0, 0xff, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
-  0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f,
-  0x00, 0xce, 0xff, 0x7f, 0xc0, 0xff, 0xff, 0xff, 0x3f, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe,
-  0xff, 0xe3, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00,
-  0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x0f, 0x00, 0xe0, 0xff,
-  0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x00, 0xce, 0xff, 0x7f,
-  0x00, 0xff, 0xff, 0xff, 0x3f, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x1f, 0x00, 0x07, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x04, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0xff, 0x0f, 0x00, 0xc0, 0xff, 0x3f, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x20, 0x1b, 0xb2, 0x31, 0xff, 0x7f, 0x00, 0xff, 0xff, 0xff,
-  0x3f, 0x00, 0x00, 0xe0, 0x5f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0xfe, 0x03, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x80, 0x01, 0x06, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
-  0x0f, 0x00, 0xc0, 0xff, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
-  0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xc0, 0x1c,
-  0x00, 0xc0, 0xff, 0x73, 0xc0, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xf0,
-  0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e,
-  0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03,
-  0x03, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0xc0, 0xff,
-  0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x07, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xc0, 0x1c, 0x00, 0xc0, 0x7f, 0x1c,
-  0x30, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xf8, 0x7f, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x78, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xff, 0xff, 0x01, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0xc0, 0xff, 0x0f, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x38, 0x87, 0x31, 0x06, 0x7c, 0x1c, 0x30, 0xff, 0xff, 0xff,
-  0xff, 0x00, 0x00, 0xf8, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x80, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0xc0, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0xff, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x87,
-  0x31, 0x06, 0xfc, 0x0f, 0xc8, 0xff, 0xff, 0xff, 0xff, 0x03, 0x00, 0x38,
-  0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30,
-  0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xff,
-  0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x00, 0xc0, 0xff,
-  0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x0f, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0xe6, 0x04, 0x00, 0x30, 0xe3, 0x0f,
-  0xc8, 0xff, 0xff, 0xff, 0xff, 0x03, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0xe0, 0x01,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xff, 0xff, 0x01, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0xfc, 0x03, 0x00, 0xc0, 0xff, 0x0f, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x30, 0xe6, 0x04, 0x00, 0x30, 0x03, 0x00, 0xf0, 0xff, 0xff, 0xff,
-  0xff, 0x03, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0xc0, 0x01, 0x00, 0xe0, 0x03, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe,
-  0x07, 0x00, 0xc0, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
-  0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x1b,
-  0x4c, 0x00, 0x04, 0x00, 0xf0, 0xff, 0xff, 0xff, 0xff, 0x03, 0x00, 0x10,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x01, 0x00, 0xf0, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x07, 0x00, 0xc0, 0xff,
-  0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x07, 0x04, 0x00, 0x06, 0x18, 0x80,
-  0xff, 0xff, 0xff, 0xff, 0xff, 0x03, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x03,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x0f, 0x0e, 0x00, 0xc0, 0xff, 0x0f, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x02, 0x07, 0x04, 0x00, 0x06, 0x78, 0xf3, 0xff, 0xff, 0xff, 0xff,
-  0xff, 0x07, 0x00, 0xf8, 0x5f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x01, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03,
-  0x08, 0x00, 0xc0, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x3e, 0x04,
-  0x02, 0x30, 0x60, 0xf3, 0xff, 0xff, 0xff, 0xff, 0xff, 0x07, 0x00, 0xf8,
-  0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0xc0, 0xff,
-  0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x3e, 0x04, 0x02, 0x30, 0xe0, 0xff,
-  0xff, 0xff, 0xff, 0xff, 0xff, 0x07, 0x00, 0xf8, 0x7f, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0xff, 0x0f, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0xc6, 0x04, 0x40, 0x00, 0xfb, 0xff, 0xff, 0xff, 0xff, 0xff,
-  0xff, 0x07, 0x00, 0xf8, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
-  0x08, 0x00, 0x00, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0x04,
-  0x40, 0x00, 0xfb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x07, 0x00, 0x08,
-  0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x0e, 0x00, 0x00, 0xff,
-  0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xff, 0x03, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x39, 0x67, 0x00, 0x06, 0xe0, 0xff,
-  0xff, 0xff, 0xff, 0xff, 0xff, 0x07, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x03, 0x0f, 0x00, 0x00, 0xff, 0x0f, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x06, 0x04, 0x30, 0x00, 0xfb, 0xff, 0xff, 0xff, 0xff, 0xff,
-  0xff, 0x3f, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x18, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02,
-  0x0f, 0x00, 0x00, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0xff, 0xff, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x04,
-  0x30, 0x00, 0xfb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x00, 0x08,
-  0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x00,
-  0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x06, 0x00, 0x00, 0xff,
-  0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x1f, 0x00, 0x7e, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x3e, 0x9b, 0x01, 0x30, 0xe0, 0xff,
-  0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x00, 0x08, 0x60, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x06, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x0f, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0xc0, 0x1f, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x30, 0x3e, 0x9b, 0x01, 0x30, 0xe0, 0xff, 0xff, 0xff, 0xff, 0xff,
-  0xff, 0x3f, 0x00, 0x18, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x1c, 0x80, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
-  0x00, 0x02, 0x00, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0,
-  0x01, 0x00, 0xf0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0x1c,
-  0x0c, 0x06, 0xfb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x00, 0x38,
-  0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0xe0,
-  0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0xff,
-  0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x01, 0x00, 0xf0, 0x01,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0x1c, 0x0c, 0x06, 0xfb, 0xff,
-  0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x00, 0x68, 0x7c, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0xf8, 0x07, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0xff, 0xff, 0x03, 0x00, 0xff, 0x3f, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0xf0, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x38, 0x18, 0x00, 0x00, 0xfb, 0xff, 0xff, 0xff, 0xff, 0xff,
-  0xff, 0x3f, 0x00, 0xc0, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x18, 0xfe, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
-  0xff, 0x03, 0x00, 0xff, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc,
-  0x00, 0x00, 0xc0, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xc6, 0x9b,
-  0x81, 0x01, 0x60, 0x00, 0xfe, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x00, 0x80,
-  0x5f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x7f,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x03, 0x00, 0xff,
-  0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0xc0, 0x07,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xc6, 0x9b, 0x81, 0x01, 0x00, 0x00,
-  0xf6, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x00, 0xc0, 0x0f, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x1f, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0xff, 0xff, 0x03, 0x00, 0xff, 0x3f, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x80, 0x07, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x38, 0x78, 0x0c, 0x30, 0x04, 0x00, 0xf6, 0xff, 0xff, 0xff,
-  0xff, 0x3f, 0x00, 0xe8, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
-  0x00, 0x00, 0x00, 0xff, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c,
-  0x00, 0x00, 0x80, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x78,
-  0x0c, 0x30, 0x04, 0x00, 0xc8, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x00, 0xf8,
-  0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38,
-  0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xff,
-  0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x80, 0x07,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x64, 0x40, 0x00, 0x1c, 0x00,
-  0xc8, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x00, 0xf8, 0x58, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x04, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x3f, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x80, 0x07, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0xc0, 0x64, 0x40, 0x00, 0xfc, 0x03, 0xc0, 0xff, 0xff, 0xff,
-  0xff, 0x3f, 0x00, 0x78, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x80, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
-  0x08, 0x00, 0x00, 0xff, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c,
-  0x00, 0x00, 0x80, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0xe0,
-  0x01, 0x36, 0xfc, 0x03, 0xc0, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x00, 0x38,
-  0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0xff,
-  0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x80, 0x07,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0xe0, 0x01, 0x36, 0xfc, 0x1f,
-  0x30, 0xff, 0xff, 0xff, 0xff, 0x07, 0x00, 0x18, 0x40, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0xff, 0x8f, 0x01, 0x00, 0xff, 0x3f, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x80, 0x07, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0xc6, 0x87, 0x0f, 0x00, 0xff, 0x1f, 0x30, 0xff, 0xff, 0xff,
-  0xff, 0x07, 0x00, 0x08, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0xfe, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
-  0xcf, 0x03, 0x00, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc,
-  0x00, 0x00, 0xc0, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18,
-  0x40, 0xc0, 0xff, 0x7f, 0xc0, 0xfe, 0xff, 0xff, 0xff, 0x07, 0x00, 0x08,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0xff, 0x0f, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xcf, 0x03, 0x00, 0xff,
-  0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0xc0, 0x07,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x40, 0xc0, 0xff, 0x7f,
-  0x00, 0xff, 0xff, 0xff, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0xfc, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0xff, 0x8f, 0x01, 0x00, 0xff, 0x7f, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0xf0, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x03, 0x0e, 0xc6, 0xff, 0x7f, 0x00, 0xff, 0xff, 0xff,
-  0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0xfe, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
-  0x00, 0x00, 0x00, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0,
-  0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03,
-  0x0e, 0xc6, 0xff, 0x7f, 0x00, 0xfe, 0xff, 0xff, 0xff, 0x07, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x0c, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xff,
-  0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x01, 0x00, 0xf0, 0x01,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x9c, 0x01, 0x30, 0xff, 0x7f,
-  0x00, 0xfe, 0xff, 0xff, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x02, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x7f, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0xf0, 0x01, 0x00, 0xf0, 0x01, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x20, 0x9c, 0x01, 0x30, 0xff, 0x63, 0x30, 0xff, 0xff, 0xff,
-  0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x02, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
-  0x08, 0x00, 0x00, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
-  0x07, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60,
-  0x4c, 0x00, 0xff, 0x63, 0x30, 0xff, 0xff, 0xff, 0xff, 0x07, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x10, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0xff,
-  0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x3e, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb2, 0x31, 0xfc, 0x1f,
-  0x00, 0xff, 0xff, 0xfd, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x02, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0xff, 0x0f, 0x00, 0x00, 0xff, 0xff, 0x01, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0xb2, 0x31, 0xfc, 0x0f, 0x00, 0xff, 0xff, 0x03,
-  0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x0e, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
-  0x0f, 0x00, 0x00, 0xff, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x98,
-  0x41, 0x00, 0xe0, 0x0f, 0x00, 0xff, 0xff, 0x03, 0xff, 0x03, 0x00, 0x38,
-  0x80, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x0f, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x0f, 0x00, 0x00, 0xff,
-  0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x98, 0x41, 0x00, 0x00, 0x80,
-  0xc9, 0xf9, 0xff, 0x3d, 0xff, 0x03, 0x00, 0x78, 0xc0, 0x0f, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0xfc, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0xff, 0x0f, 0x00, 0x00, 0xff, 0xff, 0x07, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x60, 0x32, 0x08, 0x00, 0x80, 0xc9, 0xf9, 0xff, 0x3d,
-  0xff, 0x03, 0x00, 0xf8, 0xc0, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0xf8, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
-  0x02, 0x00, 0x00, 0xff, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60,
-  0x32, 0x08, 0x00, 0x00, 0xf0, 0xff, 0xff, 0xcf, 0xff, 0x00, 0x00, 0xf8,
-  0x81, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x01, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0xff,
-  0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0xe0, 0x01, 0xf8, 0x00, 0x00,
-  0xf0, 0xff, 0xff, 0xcf, 0xff, 0x00, 0x00, 0x38, 0x03, 0x10, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x60, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0xff, 0xff, 0x3f, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0xf8, 0xff, 0xff, 0x03, 0x80, 0xff, 0xff, 0xff, 0xff,
-  0x3f, 0x00, 0x00, 0x38, 0x06, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0,
-  0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x0c, 0x00, 0x00, 0xff, 0xff, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8,
-  0xff, 0xff, 0x03, 0xfc, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x00, 0x00, 0x38,
-  0x1e, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x18, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x0e, 0x00, 0x00, 0xff,
-  0xff, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xff, 0xff, 0x03, 0xfc,
-  0xff, 0xff, 0xff, 0xff, 0x3f, 0x00, 0x00, 0x38, 0xfc, 0x1f, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x70, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0xff, 0x0f, 0x00, 0x00, 0xff, 0xff, 0x3f, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-  0x1f, 0x00, 0x00, 0x38, 0xf8, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30,
-  0x80, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
-  0x0f, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
-  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0x00, 0x00, 0x78,
-  0xf0, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0xe0, 0x1f, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x07, 0x00, 0x00, 0xff,
-  0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xff,
-  0xff, 0xff, 0xff, 0xff, 0x07, 0x00, 0x00, 0xf8, 0xc1, 0x07, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x60, 0xf8, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0xff, 0x03, 0x00, 0xc0, 0xff, 0xff, 0xff, 0x03, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00,
-  0x00, 0x00, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-  0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
-  0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
-  0x00, 0x00, 0xc0, 0xff, 0xff, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0xff, 0xff,
-  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x07, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0xc0, 0xff,
-  0xff, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-  0xff, 0xff, 0xff, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xff, 0xff, 0xff, 0x1f, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-  0x01, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0xe0, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x08, 0x00, 0xc0, 0xff, 0xff, 0xff, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0x67,
-  0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0xf8,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x13, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0xc0, 0xff,
-  0xff, 0xff, 0x1f, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0xf0, 0xff, 0xff, 0x67, 0xfe, 0xff, 0xff, 0xff,
-  0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0xfc, 0x0f, 0x00, 0xc0, 0xff, 0xff, 0xff, 0x1f, 0x03,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0xf0, 0xff, 0xff, 0x98, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0f,
-  0x00, 0x00, 0x00, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe,
-  0x0f, 0x00, 0xf8, 0xff, 0xff, 0xff, 0x7f, 0x00, 0x08, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xff, 0xff, 0xff, 0x98,
-  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x70,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x0f, 0x00, 0xf8, 0xff,
-  0xff, 0xff, 0x7f, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x80, 0xff, 0xff, 0x3f, 0xe7, 0xff, 0xff, 0xff, 0xff,
-  0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0xff, 0x0f, 0x00, 0xff, 0xfc, 0xff, 0xff, 0xff, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe,
-  0xff, 0xff, 0x3f, 0xe7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07,
-  0x00, 0xc0, 0xff, 0x67, 0x8c, 0xf9, 0xfb, 0x73, 0x00, 0x67, 0x10, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xff, 0xff, 0xff, 0xff, 0xf8,
-  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x80,
-  0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0xc0, 0xff, 0x67,
-  0x8c, 0xf9, 0xfb, 0x73, 0x00, 0x67, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0xc0, 0xff, 0xff, 0xff, 0x1f, 0xe7, 0xff, 0xff, 0xff, 0xff,
-  0xff, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xff, 0x07, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x03, 0x00, 0xc0, 0x27, 0xfc, 0x73, 0xc6, 0x1c, 0x8c,
-  0x37, 0x80, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xff,
-  0xff, 0xff, 0x1f, 0xe7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0f, 0x00,
-  0x00, 0x00, 0x00, 0xf0, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02,
-  0x00, 0xc0, 0x27, 0xfc, 0x73, 0xc6, 0x1c, 0x8c, 0x37, 0x80, 0x0c, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xfc,
-  0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0,
-  0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x08, 0xc0, 0xfe, 0x03,
-  0x8c, 0x09, 0xe3, 0x73, 0xc8, 0x06, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x80, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xff,
-  0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x18, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0xff, 0x0f, 0xc0, 0xfe, 0x03, 0x8c, 0x09, 0xe3, 0x73,
-  0xc8, 0x06, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xff, 0xff,
-  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x07, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x08, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
-  0x0f, 0xc0, 0x27, 0xe7, 0x31, 0x36, 0x04, 0x8c, 0x01, 0x60, 0x03, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-  0xff, 0xff, 0xff, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08,
-  0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x0f, 0xc0, 0xde, 0x18,
-  0x42, 0xc0, 0x98, 0x30, 0x08, 0x01, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x07, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x18, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0xff, 0x0f, 0xc0, 0xde, 0x18, 0x42, 0xc0, 0x98, 0x30,
-  0x08, 0x01, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff,
-  0xff, 0xff, 0xff, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0xf0, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x02, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
-  0x00, 0xc0, 0x27, 0x63, 0x00, 0x08, 0x63, 0x03, 0x06, 0x60, 0x10, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0xe0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-  0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0,
-  0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0x07, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0xc0, 0x27, 0x63,
-  0x00, 0x08, 0x63, 0x03, 0x06, 0x60, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0xe0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xff, 0x07, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x08, 0xc0, 0xd9, 0x04, 0xb2, 0x01, 0x00, 0xb0,
-  0x31, 0x19, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xf9, 0xff,
-  0xff, 0xff, 0xff, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x80, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0xfe, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
-  0x08, 0xc0, 0xd9, 0x04, 0xb2, 0x01, 0x00, 0xb0, 0x31, 0x19, 0x03, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xf9, 0xff, 0xff, 0xff, 0xff, 0x07,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0x07, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x0c, 0xc0, 0x1e, 0x63,
-  0x00, 0x30, 0x04, 0x03, 0xc8, 0x60, 0x00, 0x0e, 0x00, 0x00, 0xfc, 0xff,
-  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x02, 0x04, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x03, 0x0e, 0xc0, 0xe1, 0x18, 0x80, 0x01, 0x60, 0xb0,
-  0x01, 0xe7, 0xf3, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-  0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x02, 0x04, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07,
-  0x0f, 0xc0, 0xe1, 0x18, 0x80, 0x01, 0x60, 0xb0, 0x01, 0xe7, 0xf3, 0xff,
-  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x07, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x04, 0x04, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8d, 0x0f, 0xc0, 0x1e, 0x03,
-  0x02, 0x08, 0x04, 0x00, 0xc8, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0xd8, 0x0f, 0xc0, 0x1e, 0x03, 0x02, 0x08, 0x04, 0x00,
-  0xc8, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-  0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0xc0, 0x0f, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0,
-  0x0b, 0x00, 0x21, 0x64, 0x40, 0xc0, 0x00, 0xb3, 0xf1, 0xfe, 0xff, 0xff,
-  0xff, 0xff, 0xff, 0xff, 0xfb, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xfb, 0x07, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x01, 0x00, 0x21, 0x64,
-  0x40, 0xc0, 0x00, 0xb3, 0xf1, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-  0xfb, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0xfc, 0xfb, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0xfd, 0x00, 0xc0, 0xdf, 0x00, 0x00, 0x06, 0x60, 0x00,
-  0x0e, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-  0xff, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0xfe, 0xf9, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbf,
-  0x01, 0xc0, 0xdf, 0x00, 0x00, 0x06, 0x60, 0x00, 0x0e, 0xff, 0xff, 0xff,
-  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0f, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0,
-  0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0xf0, 0x03, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x0b, 0xc0, 0xc0, 0x84,
-  0x31, 0xc0, 0x00, 0x4c, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-  0xff, 0xff, 0xff, 0xff, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x83, 0x07, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x1e, 0xe0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x0f, 0x0e, 0xc0, 0x3f, 0x18, 0x00, 0x06, 0x84, 0x80,
-  0x09, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-  0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0xf0, 0xc3, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07,
-  0x0c, 0xc0, 0x3f, 0x18, 0x00, 0x06, 0x84, 0x80, 0x09, 0xff, 0xff, 0x3f,
-  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc8,
-  0xc1, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x08, 0xc0, 0xc1, 0x03,
-  0x4c, 0x00, 0x00, 0x30, 0xf6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-  0xff, 0xff, 0xff, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x90, 0x13, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x01, 0x08, 0xc0, 0xc1, 0x03, 0x4c, 0x00, 0x00, 0x30,
-  0xf6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-  0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x08, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
-  0x00, 0xc0, 0x3f, 0x98, 0x01, 0x08, 0x1b, 0x43, 0xc8, 0xff, 0xff, 0xff,
-  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0f, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08,
-  0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x3f, 0x98,
-  0x01, 0x08, 0x1b, 0x43, 0xc8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-  0xff, 0xff, 0xff, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x38, 0x18, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x0e, 0x00, 0xc0, 0xc6, 0x03, 0x40, 0x00, 0x00, 0x80,
-  0x31, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf7, 0xff, 0xff, 0xff, 0xff,
-  0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0xf8, 0xef, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f,
-  0x00, 0x00, 0x3f, 0x18, 0x0c, 0x30, 0x60, 0x0c, 0xce, 0xff, 0xff, 0xff,
-  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0,
-  0xef, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x3f, 0x18,
-  0x0c, 0x30, 0x60, 0x0c, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-  0xff, 0xff, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xc7, 0x0f, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0xde, 0x63, 0x40, 0x06, 0x03, 0x30,
-  0x30, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0xc0, 0x83, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x02, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e,
-  0x00, 0x00, 0xde, 0x63, 0x40, 0x06, 0x03, 0x30, 0x30, 0xff, 0xff, 0xff,
-  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x04, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x04,
-  0x02, 0x00, 0x00, 0x83, 0xc9, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-  0xff, 0xff, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0xf0, 0x00, 0x00, 0x38, 0x04, 0x02, 0x00, 0x00, 0x83,
-  0xc9, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0xc0, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0xfe, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc,
-  0x03, 0x00, 0xe0, 0x1b, 0x0c, 0x08, 0x18, 0x40, 0x30, 0xfe, 0xff, 0xff,
-  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0,
-  0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0x07, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x07, 0x00, 0xc0, 0x84,
-  0x81, 0x01, 0x03, 0x0c, 0xc6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-  0xff, 0xff, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xff, 0x0f, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0xfe, 0x07, 0x00, 0xc0, 0x84, 0x81, 0x01, 0x03, 0x0c,
-  0xc6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0f, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0xf8, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x02, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07,
-  0x0e, 0x00, 0x00, 0x1b, 0x0c, 0x30, 0x80, 0x00, 0x30, 0xf8, 0xff, 0xff,
-  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18,
-  0x10, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x04, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x1b,
-  0x0c, 0x30, 0x80, 0x00, 0x30, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-  0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x20, 0x10, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x67, 0xc0, 0x01, 0x04, 0x40,
-  0x00, 0xe1, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x08, 0x20, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
-  0x08, 0x00, 0x00, 0x67, 0xc0, 0x01, 0x04, 0x40, 0x00, 0xe1, 0xff, 0xff,
-  0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18,
-  0x30, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x9c,
-  0x01, 0x08, 0x60, 0x0c, 0x06, 0x86, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xff,
-  0xff, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xbf, 0x1f, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x07, 0x0e, 0x00, 0x00, 0x18, 0x0c, 0xc0, 0x00, 0x00,
-  0xc0, 0x00, 0xfc, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0xf0, 0x9f, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe,
-  0x07, 0x00, 0x00, 0x18, 0x0c, 0xc0, 0x00, 0x00, 0xc0, 0x00, 0xfc, 0xff,
-  0xff, 0xff, 0xff, 0xff, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0,
-  0x1f, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x07, 0x00, 0x00, 0xe0,
-  0x01, 0x06, 0x00, 0x30, 0x06, 0x86, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff,
-  0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x07, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0xfc, 0x03, 0x00, 0x00, 0xe0, 0x01, 0x06, 0x00, 0x30,
-  0x06, 0x86, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0,
-  0x00, 0x00, 0x00, 0x60, 0x30, 0x00, 0x63, 0x03, 0x30, 0x00, 0xe0, 0xff,
-  0xff, 0xff, 0xff, 0x8f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60,
-  0x30, 0x00, 0x63, 0x03, 0x30, 0x00, 0xe0, 0xff, 0xff, 0xff, 0xff, 0x0f,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x80, 0x83, 0x09, 0x18, 0x00,
-  0x00, 0x06, 0x83, 0xff, 0xff, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
-  0x08, 0x00, 0x00, 0x80, 0x83, 0x09, 0x18, 0x00, 0x00, 0x06, 0x83, 0xff,
-  0xff, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x0f, 0x00, 0x00, 0x00,
-  0x00, 0xc0, 0x00, 0x8c, 0xc9, 0x60, 0x00, 0xfe, 0xff, 0xff, 0x01, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x8e, 0x01, 0x84, 0x40,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
-  0x0f, 0x00, 0x00, 0x00, 0x8e, 0x01, 0x84, 0x40, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x0f, 0x00, 0x00, 0x00,
-  0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
-  0x04, 0x00, 0x00, 0x00, 0x00, 0xc8, 0x60, 0x83, 0x01, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00,
-  0x00, 0xc8, 0x60, 0x83, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x30, 0x06, 0x00, 0x0c,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x0f, 0x00, 0x00, 0x00, 0x80, 0xc1, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x1f, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,
-  0x80, 0xc1, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0xe0, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x08, 0x60, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0xf8, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0xc6,
-  0x03, 0x00, 0x00, 0x00, 0x40, 0x08, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xff, 0x01, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xef, 0x07, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0xfc, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0xd8, 0xef, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x1c, 0x80, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0xf3,
-  0x0f, 0x00, 0x00, 0x00, 0x80, 0x09, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x06, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0x33, 0x0c, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x88, 0x13, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x02, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0x13,
-  0x08, 0x00, 0x00, 0x00, 0x00, 0x18, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x04, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0x33, 0x0c, 0x00, 0x00, 0x00,
-  0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x88, 0xf3, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x02, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0xe3,
-  0x0f, 0x00, 0x00, 0x00, 0x00, 0x86, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x06, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd8, 0xe1, 0x1f, 0x00, 0x00, 0x00,
-  0x00, 0x86, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0xf0, 0xc1, 0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x04, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x00,
-  0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0xc0, 0x07, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x60, 0xf0, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x01, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0xf8, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0xfc, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x0f, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x0e, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x02, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x10, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x02, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x02, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x1c, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0xfc, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0xfc, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x07, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0xe0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x10, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x02, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0xfe, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x1f, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0xfe, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0xfe, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x04, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x02, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0xfe, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x1f, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0xfe, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0xfe, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0xf8, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0xfc, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0x01, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x06, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x10, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x04, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x02, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x02, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x1f, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0xfe, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0xfe, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x1f, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x02, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x02, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0xe0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0xf8, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x0f, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0xfc, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x0e, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x10, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x02, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x02, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x10, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x0e, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0xfc, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x0f, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0xf8, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0xe0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x02, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0x07, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0xfe, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0x07, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  };
diff --git a/arch/m68k/platform/68000/bootlogo.h b/arch/m68k/platform/68000/bootlogo.h
deleted file mode 100644 (file)
index b896c93..0000000
+++ /dev/null
@@ -1,270 +0,0 @@
-#define bootlogo_width 160
-#define bootlogo_height 160
-unsigned char __attribute__ ((aligned(16))) bootlogo_bits[] = {
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x01, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x40, 0x55, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x55,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xac, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x10, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x01, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x82, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x20, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x80, 0x08, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x08, 0x00, 0x00,
-  0x00, 0xff, 0x80, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x20, 0x04, 0x00, 0x00, 0x00, 0xf8, 0x80, 0x0f,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x50, 0x04, 0x00, 0x00, 0x00, 0x78, 0x80, 0x0f, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x03, 0x00, 0x00,
-  0x00, 0x78, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x90, 0x00, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x40,
-  0xa8, 0x02, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x70, 0x28, 0x01, 0x00, 0x00,
-  0x00, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x20, 0x00, 0x00, 0xaa, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x70,
-  0x54, 0x01, 0x00, 0x00, 0x00, 0x3e, 0x80, 0x01, 0x3a, 0x78, 0x80, 0x0e,
-  0x50, 0xc0, 0x03, 0x0e, 0x00, 0x20, 0x00, 0x00, 0xaa, 0x00, 0x00, 0x00,
-  0x00, 0x3e, 0xf0, 0x83, 0x1f, 0xfc, 0xe0, 0x0f, 0x78, 0xf8, 0x87, 0x1f,
-  0x00, 0x18, 0x00, 0x30, 0xaa, 0x00, 0x00, 0x00, 0x00, 0x1e, 0xf8, 0xc3,
-  0x1f, 0xfc, 0xe0, 0x0f, 0x78, 0xf8, 0x87, 0x0f, 0x00, 0x20, 0x00, 0x10,
-  0x55, 0x00, 0x00, 0x00, 0x00, 0x1e, 0xc0, 0x03, 0x9f, 0xf3, 0x80, 0x0f,
-  0x78, 0x80, 0xc7, 0x0e, 0x00, 0x18, 0x00, 0x20, 0xaa, 0x00, 0x00, 0x00,
-  0x00, 0x1e, 0xe0, 0x03, 0x9f, 0xf1, 0x80, 0x07, 0x78, 0x80, 0x67, 0x00,
-  0x00, 0x24, 0x00, 0x18, 0x55, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xe0, 0x01,
-  0x5e, 0xf0, 0x80, 0x07, 0x3c, 0x00, 0x2f, 0x00, 0x00, 0x14, 0x00, 0x20,
-  0xaa, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xe0, 0x01, 0x7f, 0xf0, 0x80, 0x07,
-  0x3c, 0x00, 0x3f, 0x00, 0x00, 0x08, 0x00, 0x18, 0x55, 0x00, 0x00, 0x00,
-  0x00, 0x0f, 0xe0, 0x00, 0x3f, 0xf0, 0xc0, 0x03, 0x1e, 0x00, 0x1f, 0x00,
-  0x00, 0x14, 0x00, 0x28, 0xaa, 0x00, 0x00, 0x00, 0x80, 0x0f, 0xf0, 0x00,
-  0x1f, 0xf0, 0xc0, 0x03, 0x1f, 0x00, 0x1f, 0x00, 0x00, 0x04, 0x00, 0x0c,
-  0x54, 0x00, 0x00, 0x00, 0x80, 0x07, 0x78, 0x00, 0x1f, 0x78, 0xc0, 0x03,
-  0x1f, 0x00, 0x1e, 0x00, 0x00, 0x0a, 0x00, 0x12, 0xa8, 0x00, 0x00, 0x00,
-  0x80, 0x07, 0x78, 0x00, 0x1f, 0x78, 0xe0, 0x03, 0x1f, 0x00, 0x1f, 0x00,
-  0x00, 0x04, 0x00, 0x0a, 0x54, 0x00, 0x00, 0x00, 0x80, 0x07, 0x78, 0x80,
-  0x0f, 0x78, 0xe0, 0x03, 0x1f, 0x00, 0x1e, 0x00, 0x00, 0x0a, 0x00, 0x08,
-  0x50, 0x01, 0x00, 0x00, 0x84, 0x03, 0x78, 0x80, 0x07, 0x3c, 0xe0, 0xc1,
-  0x0f, 0x00, 0x1f, 0x00, 0x00, 0x04, 0x00, 0x06, 0xa8, 0x00, 0x00, 0x00,
-  0xc0, 0x03, 0x78, 0xc0, 0x07, 0x3c, 0xe0, 0xc1, 0x0f, 0x00, 0x1f, 0x00,
-  0x00, 0x0a, 0x00, 0x08, 0x50, 0x01, 0x00, 0x00, 0xc2, 0x01, 0x38, 0xc0,
-  0x07, 0x3c, 0xe0, 0x60, 0x0f, 0x80, 0x1e, 0x00, 0x00, 0x05, 0x00, 0x07,
-  0xa0, 0x00, 0x00, 0x80, 0xe0, 0x01, 0x3c, 0xc0, 0x07, 0x3c, 0xf0, 0xa0,
-  0x07, 0xc0, 0x1c, 0x00, 0x00, 0x0a, 0x80, 0x08, 0xa0, 0x02, 0x00, 0xa0,
-  0xe0, 0x21, 0x1c, 0xc0, 0x03, 0x1c, 0x71, 0x90, 0x47, 0x40, 0x3c, 0x04,
-  0x00, 0x05, 0x80, 0x06, 0xa0, 0x02, 0x00, 0x20, 0xe0, 0x31, 0x1e, 0xc3,
-  0x03, 0x1e, 0x79, 0x98, 0x47, 0x60, 0x38, 0x04, 0x00, 0x15, 0x40, 0x0a,
-  0xa0, 0x0a, 0x00, 0x1a, 0xe0, 0x19, 0x9e, 0xe1, 0x01, 0x9e, 0x78, 0xcc,
-  0xa7, 0x32, 0x78, 0x02, 0x80, 0x2a, 0x40, 0x05, 0x80, 0x2a, 0x00, 0x05,
-  0xe0, 0x0d, 0x9e, 0xe0, 0x01, 0xde, 0x78, 0xc6, 0x97, 0x1b, 0x78, 0x03,
-  0x80, 0x52, 0x30, 0x0a, 0x00, 0x95, 0xd2, 0x0a, 0xe0, 0x0f, 0xfe, 0xe0,
-  0x00, 0x7e, 0xf8, 0x87, 0x9f, 0x0f, 0xf8, 0x01, 0x00, 0xa1, 0x0e, 0x15,
-  0x80, 0x55, 0x55, 0x01, 0xe0, 0x01, 0x3c, 0xf0, 0x00, 0x3c, 0xf0, 0x80,
-  0x8f, 0x0f, 0x70, 0x00, 0x00, 0x81, 0x02, 0x14, 0x00, 0x54, 0x55, 0x00,
-  0xc0, 0x01, 0x3c, 0x00, 0x00, 0x0c, 0x60, 0x00, 0x07, 0x03, 0x70, 0x00,
-  0x80, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x40, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x40, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x40, 0x01, 0x00, 0x11, 0x09, 0x00, 0x04, 0x00, 0x01, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00,
-  0x00, 0x20, 0x01, 0x00, 0x04, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x49, 0x32, 0x49, 0x49, 0x91,
-  0x24, 0x86, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x20, 0x49, 0x0a, 0x09, 0xc9, 0x92, 0x14, 0x81, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x49,
-  0x18, 0x01, 0x49, 0x92, 0x0c, 0x43, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x49, 0x30, 0x01, 0x49, 0x92,
-  0x14, 0x26, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x08, 0x69, 0x22, 0x09, 0x49, 0xd2, 0x24, 0x24, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x51,
-  0x1a, 0x09, 0x49, 0xa2, 0x44, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x01, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
-  0x08, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x87, 0x08, 0x00, 0x00, 0x00,
-  0xf2, 0xf0, 0xf0, 0xf0, 0xf0, 0x00, 0xf0, 0x00, 0x08, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x40, 0x88, 0x00, 0x00, 0x00, 0x00, 0x09, 0x09, 0x09, 0x09,
-  0x09, 0x01, 0x10, 0x01, 0x08, 0x00, 0x00, 0x00, 0x00, 0x40, 0x24, 0x80,
-  0x88, 0x86, 0x48, 0x04, 0x09, 0x08, 0x01, 0x01, 0x09, 0x01, 0x10, 0x71,
-  0x88, 0x66, 0x00, 0x00, 0x00, 0x40, 0x24, 0x80, 0x88, 0x89, 0x48, 0x84,
-  0x08, 0x08, 0x01, 0x01, 0x09, 0x01, 0x10, 0x89, 0x88, 0x99, 0x00, 0x00,
-  0x00, 0x40, 0x24, 0x80, 0x88, 0x88, 0x88, 0x82, 0xf8, 0xf0, 0xe0, 0x80,
-  0xf0, 0xf8, 0x13, 0x81, 0x88, 0x88, 0x00, 0x00, 0x00, 0x40, 0x24, 0x80,
-  0x88, 0x88, 0x08, 0x81, 0x08, 0x09, 0x01, 0x41, 0x08, 0x01, 0xf0, 0xf0,
-  0x88, 0x88, 0x00, 0x00, 0x00, 0x40, 0x24, 0x80, 0x88, 0x88, 0x88, 0x42,
-  0x08, 0x09, 0x01, 0x21, 0x08, 0x01, 0x10, 0x88, 0x88, 0x88, 0x00, 0x00,
-  0x00, 0x40, 0x46, 0x88, 0x88, 0x88, 0x4c, 0x44, 0x08, 0x09, 0x09, 0x11,
-  0x08, 0x01, 0x10, 0x88, 0x88, 0x88, 0x00, 0x00, 0x00, 0x80, 0x85, 0x87,
-  0x88, 0x08, 0x4b, 0x24, 0xf0, 0xf0, 0xf0, 0xf8, 0xf1, 0x00, 0x10, 0x70,
-  0x89, 0x88, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x7f, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0xf8, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc,
-  0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0x0f, 0x00, 0x00,
-  0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0xff, 0x3f, 0x0f, 0x00, 0x00, 0x08, 0x02, 0x04, 0x00,
-  0x00, 0x00, 0x08, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
-  0xff, 0x1f, 0x00, 0x00, 0x48, 0x62, 0xc4, 0x31, 0x4a, 0x18, 0x3c, 0x03,
-  0x21, 0x45, 0x92, 0x00, 0x00, 0x00, 0x80, 0xff, 0xff, 0x1f, 0x00, 0x00,
-  0x48, 0x92, 0x24, 0x48, 0xb6, 0x24, 0x88, 0x04, 0x21, 0x4b, 0x92, 0x00,
-  0x00, 0x00, 0x80, 0xff, 0xff, 0x3f, 0x00, 0x00, 0xa8, 0xf2, 0x24, 0x48,
-  0x92, 0x3c, 0x88, 0x04, 0x21, 0x49, 0x62, 0x00, 0x00, 0x00, 0x80, 0xff,
-  0xff, 0x3f, 0x00, 0x00, 0x10, 0x11, 0x24, 0x48, 0x92, 0x04, 0x88, 0x04,
-  0x21, 0x49, 0x62, 0x00, 0x00, 0x00, 0x80, 0xff, 0xff, 0x3f, 0x00, 0x00,
-  0x10, 0x11, 0x24, 0x48, 0x92, 0x04, 0x88, 0x04, 0x21, 0x49, 0x93, 0x00,
-  0x00, 0x00, 0x80, 0xff, 0xcf, 0x7e, 0x00, 0x00, 0x10, 0xe1, 0xc4, 0x31,
-  0x92, 0x38, 0x30, 0x03, 0x2f, 0x89, 0x92, 0x00, 0x00, 0x00, 0x80, 0xe3,
-  0x07, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xc1, 0x03, 0x7e, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x80, 0xc9, 0x23, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x95,
-  0x33, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xdd, 0xfb, 0x7e, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x80, 0x1d, 0xf8, 0x7e, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00,
-  0x02, 0x00, 0x40, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x9b,
-  0x70, 0x7e, 0x00, 0x00, 0x08, 0x00, 0xe0, 0x00, 0x02, 0x00, 0x47, 0x80,
-  0x08, 0x00, 0x00, 0x08, 0x00, 0x00, 0x80, 0x03, 0x00, 0x7e, 0x00, 0x00,
-  0x3c, 0xa3, 0x20, 0x31, 0x52, 0x02, 0x49, 0xcc, 0x3f, 0xa3, 0x94, 0x08,
-  0x00, 0x00, 0x00, 0x27, 0x02, 0x7e, 0x00, 0x00, 0x88, 0xe4, 0x20, 0x41,
-  0xb2, 0x05, 0x49, 0x90, 0x88, 0xe4, 0x6c, 0x09, 0x00, 0x00, 0x00, 0x01,
-  0x00, 0x7e, 0x00, 0x00, 0x88, 0x24, 0xe0, 0x70, 0x92, 0x04, 0x47, 0x9c,
-  0x88, 0x24, 0x24, 0x09, 0x00, 0x00, 0x00, 0x13, 0x48, 0x7e, 0x00, 0x00,
-  0x88, 0x24, 0x20, 0x48, 0x92, 0x04, 0x41, 0x92, 0x88, 0x24, 0x24, 0x01,
-  0x00, 0x00, 0x00, 0x43, 0x00, 0xfe, 0x00, 0x00, 0x88, 0x24, 0x20, 0x48,
-  0x92, 0x04, 0x41, 0x92, 0x88, 0x24, 0x24, 0x09, 0x00, 0x00, 0x00, 0x07,
-  0x94, 0xce, 0x00, 0x00, 0x08, 0x23, 0x20, 0xb0, 0x92, 0x04, 0x41, 0x2c,
-  0x0b, 0x23, 0x24, 0x09, 0x00, 0x00, 0x00, 0x49, 0x02, 0xce, 0x01, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x11, 0x08, 0xdc, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41,
-  0x01, 0xfc, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0xf8, 0x07, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0xc0, 0x01, 0x00, 0xf8, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x01,
-  0x00, 0xf0, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x00, 0x00, 0xf0, 0x1f, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x70, 0x00, 0x00, 0xe0, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x00,
-  0x00, 0xe0, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0xe0, 0x7f, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x3c, 0x00, 0x00, 0xe0, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x00,
-  0x00, 0xc0, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0xc0, 0xff, 0x01,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x1f, 0x00, 0x00, 0x80, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00,
-  0x00, 0x80, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x0f, 0x00, 0x00, 0x00, 0xff, 0x07,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x80, 0x07, 0x00, 0x00, 0x00, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x07, 0x00,
-  0x00, 0x00, 0xfe, 0x07, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x07, 0x00, 0x00, 0x00, 0xfe, 0x0f,
-  0x00, 0x00, 0x80, 0x08, 0x00, 0x00, 0x05, 0x00, 0x00, 0x80, 0x08, 0x00,
-  0x00, 0xc0, 0x03, 0x00, 0x78, 0x00, 0xfe, 0x0f, 0x00, 0x00, 0x40, 0x10,
-  0x12, 0x10, 0x05, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0xe0, 0x03, 0x00,
-  0x84, 0x00, 0xfe, 0x0f, 0x00, 0x00, 0x20, 0x26, 0x0a, 0x10, 0x9d, 0x39,
-  0xa6, 0xb2, 0x0a, 0x00, 0x00, 0xe0, 0x01, 0x00, 0x02, 0x00, 0xfe, 0x0f,
-  0x00, 0x00, 0x20, 0x21, 0x06, 0x28, 0x25, 0x4a, 0xa9, 0x8a, 0x09, 0x00,
-  0x00, 0xe0, 0x01, 0x22, 0x02, 0x00, 0xfc, 0x1f, 0x00, 0x00, 0x20, 0x21,
-  0x0e, 0x38, 0xa5, 0x4b, 0xa9, 0xb2, 0x09, 0x00, 0x00, 0xf0, 0x01, 0x22,
-  0x02, 0x00, 0xfc, 0x1f, 0x00, 0x00, 0x20, 0x21, 0x12, 0x44, 0xa5, 0x4a,
-  0x49, 0xa1, 0x0a, 0x00, 0x00, 0xf8, 0x01, 0x22, 0x02, 0x00, 0xfc, 0x1f,
-  0x00, 0x00, 0x20, 0x26, 0x52, 0x44, 0x9d, 0x4d, 0x46, 0x99, 0x0a, 0x00,
-  0x00, 0xfc, 0x01, 0x22, 0x02, 0x00, 0xfc, 0x1f, 0x00, 0x00, 0x40, 0x10,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x01, 0xb2,
-  0x84, 0x00, 0xfc, 0x1f, 0x00, 0x00, 0x80, 0x08, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x01, 0x6e, 0x78, 0x00, 0xfc, 0x1f,
-  0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0xfc, 0x01, 0x02, 0x00, 0x00, 0xfc, 0x1f, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0x01, 0x02,
-  0x00, 0x00, 0xfe, 0x1f, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x06, 0x00, 0x00, 0xfc, 0x0f,
-  0x00, 0x00, 0x80, 0x08, 0x00, 0x00, 0x20, 0x01, 0x02, 0x00, 0x00, 0x00,
-  0x00, 0x24, 0x06, 0x00, 0x00, 0x00, 0xfc, 0x07, 0x00, 0x00, 0x40, 0x10,
-  0x1e, 0x20, 0x90, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00,
-  0x00, 0x80, 0xfc, 0x03, 0x00, 0x00, 0x20, 0x26, 0x22, 0x20, 0xf9, 0x89,
-  0x32, 0xe7, 0x08, 0x00, 0x00, 0x92, 0x38, 0x00, 0x00, 0x00, 0xfc, 0x01,
-  0x00, 0x00, 0x20, 0x21, 0x22, 0xa0, 0x92, 0x88, 0x4a, 0x29, 0x15, 0x00,
-  0x00, 0x00, 0x78, 0x00, 0x00, 0x40, 0xfa, 0x04, 0x00, 0x00, 0x20, 0x21,
-  0x22, 0xa0, 0x93, 0x88, 0x4a, 0x29, 0x1d, 0x00, 0x00, 0x11, 0xf2, 0x00,
-  0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x20, 0x21, 0x22, 0xa8, 0x90, 0x88,
-  0x4a, 0x29, 0x05, 0x00, 0x48, 0x40, 0xf0, 0x01, 0x00, 0x80, 0x14, 0x04,
-  0x00, 0x00, 0x20, 0x26, 0x9e, 0x10, 0x93, 0x78, 0x32, 0x29, 0x19, 0x00,
-  0x00, 0x09, 0xe0, 0x03, 0x00, 0x00, 0x80, 0x10, 0x00, 0x00, 0x40, 0x10,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0xc5, 0x03,
-  0x00, 0x40, 0x22, 0x00, 0x00, 0x00, 0x80, 0x08, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x40, 0x04, 0xc0, 0x07, 0x00, 0x20, 0x08, 0x04,
-  0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x08, 0x50, 0x90, 0x03, 0x00, 0xb0, 0x00, 0x41, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00,
-  0x00, 0x38, 0x22, 0x08, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x48, 0x04, 0x44, 0x00, 0x00, 0x3c, 0x08, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x20, 0x00, 0x00, 0x00, 0xbf, 0x40, 0x42, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x40, 0x02, 0x00, 0x00, 0x00, 0x00, 0x24, 0x80, 0x48, 0x02,
-  0xc0, 0x1f, 0x00, 0x08, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4e, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x05, 0xf0, 0x3f, 0x09, 0x00,
-  0x00, 0x10, 0x24, 0x48, 0x10, 0x12, 0x41, 0x52, 0x24, 0x09, 0x46, 0x71,
-  0x90, 0x20, 0x02, 0xfc, 0xff, 0x1f, 0x80, 0x22, 0x00, 0x90, 0x24, 0x49,
-  0x12, 0x92, 0x40, 0xb2, 0x24, 0x09, 0xc9, 0x49, 0x04, 0x80, 0x90, 0xfc,
-  0xff, 0xbf, 0x24, 0x00, 0x00, 0x90, 0x24, 0x49, 0x12, 0x92, 0x40, 0x92,
-  0x24, 0x06, 0x49, 0x48, 0x50, 0x0a, 0x02, 0xfe, 0xff, 0x3f, 0x00, 0x05,
-  0x00, 0x50, 0xa5, 0x4a, 0x15, 0x92, 0x40, 0x92, 0x24, 0x06, 0x49, 0x48,
-  0x80, 0x40, 0x48, 0xfe, 0xff, 0x3f, 0x49, 0x00, 0x00, 0x20, 0x42, 0x84,
-  0x88, 0x1a, 0x41, 0x92, 0x34, 0x49, 0x49, 0x68, 0x00, 0x38, 0x10, 0x07,
-  0x00, 0x60, 0x80, 0x00, 0x00, 0x20, 0x42, 0x84, 0x88, 0x14, 0x4e, 0x92,
-  0x28, 0x49, 0x46, 0x50, 0x00, 0x80, 0x83, 0x01, 0x00, 0xa0, 0x6a, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40,
-  0x00, 0x00, 0xfc, 0x00, 0x00, 0xc0, 0x3b, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, };
diff --git a/arch/m68k/platform/68000/entry.S b/arch/m68k/platform/68000/entry.S
deleted file mode 100644 (file)
index 23ac054..0000000
+++ /dev/null
@@ -1,244 +0,0 @@
-/*
- *  linux/arch/m68knommu/platform/68328/entry.S
- *
- *  Copyright (C) 1991, 1992  Linus Torvalds
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file README.legal in the main directory of this archive
- * for more details.
- *
- * Linux/m68k support by Hamish Macdonald
- */
-
-#include <linux/linkage.h>
-#include <asm/thread_info.h>
-#include <asm/unistd.h>
-#include <asm/errno.h>
-#include <asm/setup.h>
-#include <asm/segment.h>
-#include <asm/traps.h>
-#include <asm/asm-offsets.h>
-#include <asm/entry.h>
-
-.text
-
-.globl system_call
-.globl resume
-.globl ret_from_exception
-.globl ret_from_signal
-.globl sys_call_table
-.globl bad_interrupt
-.globl inthandler1
-.globl inthandler2
-.globl inthandler3
-.globl inthandler4
-.globl inthandler5
-.globl inthandler6
-.globl inthandler7
-
-badsys:
-       movel   #-ENOSYS,%sp@(PT_OFF_D0)
-       jra     ret_from_exception
-
-do_trace:
-       movel   #-ENOSYS,%sp@(PT_OFF_D0) /* needed for strace*/
-       subql   #4,%sp
-       SAVE_SWITCH_STACK
-       jbsr    syscall_trace_enter
-       RESTORE_SWITCH_STACK
-       addql   #4,%sp
-       movel   %sp@(PT_OFF_ORIG_D0),%d1
-       movel   #-ENOSYS,%d0
-       cmpl    #NR_syscalls,%d1
-       jcc     1f
-       lsl     #2,%d1
-       lea     sys_call_table, %a0
-       jbsr    %a0@(%d1)
-
-1:     movel   %d0,%sp@(PT_OFF_D0)     /* save the return value */
-       subql   #4,%sp                  /* dummy return address */
-       SAVE_SWITCH_STACK
-       jbsr    syscall_trace_leave
-
-ret_from_signal:
-       RESTORE_SWITCH_STACK
-       addql   #4,%sp
-       jra     ret_from_exception
-
-ENTRY(system_call)
-       SAVE_ALL_SYS
-
-       /* save top of frame*/
-       pea     %sp@
-       jbsr    set_esp0
-       addql   #4,%sp
-
-       movel   %sp@(PT_OFF_ORIG_D0),%d0
-
-       movel   %sp,%d1                 /* get thread_info pointer */
-       andl    #-THREAD_SIZE,%d1
-       movel   %d1,%a2
-       btst    #(TIF_SYSCALL_TRACE%8),%a2@(TINFO_FLAGS+(31-TIF_SYSCALL_TRACE)/8)
-       jne     do_trace
-       cmpl    #NR_syscalls,%d0
-       jcc     badsys
-       lsl     #2,%d0
-       lea     sys_call_table,%a0
-       movel   %a0@(%d0), %a0
-       jbsr    %a0@
-       movel   %d0,%sp@(PT_OFF_D0)     /* save the return value*/
-
-ret_from_exception:
-       btst    #5,%sp@(PT_OFF_SR)      /* check if returning to kernel*/
-       jeq     Luser_return            /* if so, skip resched, signals*/
-
-Lkernel_return:
-       RESTORE_ALL
-
-Luser_return:
-       /* only allow interrupts when we are really the last one on the*/
-       /* kernel stack, otherwise stack overflow can occur during*/
-       /* heavy interrupt load*/
-       andw    #ALLOWINT,%sr
-
-       movel   %sp,%d1                 /* get thread_info pointer */
-       andl    #-THREAD_SIZE,%d1
-       movel   %d1,%a2
-1:
-       move    %a2@(TINFO_FLAGS),%d1   /* thread_info->flags */
-       jne     Lwork_to_do
-       RESTORE_ALL
-
-Lwork_to_do:
-       movel   %a2@(TINFO_FLAGS),%d1   /* thread_info->flags */
-       btst    #TIF_NEED_RESCHED,%d1
-       jne     reschedule
-
-Lsignal_return:
-       subql   #4,%sp                  /* dummy return address*/
-       SAVE_SWITCH_STACK
-       pea     %sp@(SWITCH_STACK_SIZE)
-       bsrw    do_notify_resume
-       addql   #4,%sp
-       RESTORE_SWITCH_STACK
-       addql   #4,%sp
-       jra     1b
-
-/*
- * This is the main interrupt handler, responsible for calling process_int()
- */
-inthandler1:
-       SAVE_ALL_INT
-       movew   %sp@(PT_OFF_FORMATVEC), %d0
-       and     #0x3ff, %d0
-
-       movel   %sp,%sp@-
-       movel   #65,%sp@-               /*  put vector # on stack*/
-       jbsr    process_int             /*  process the IRQ*/
-3:             addql   #8,%sp                  /*  pop parameters off stack*/
-       bra     ret_from_exception
-
-inthandler2:
-       SAVE_ALL_INT
-       movew   %sp@(PT_OFF_FORMATVEC), %d0
-       and     #0x3ff, %d0
-
-       movel   %sp,%sp@-
-       movel   #66,%sp@-               /*  put vector # on stack*/
-       jbsr    process_int             /*  process the IRQ*/
-3:             addql   #8,%sp                  /*  pop parameters off stack*/
-       bra     ret_from_exception
-
-inthandler3:
-       SAVE_ALL_INT
-       movew   %sp@(PT_OFF_FORMATVEC), %d0
-       and     #0x3ff, %d0
-
-       movel   %sp,%sp@-
-       movel   #67,%sp@-               /*  put vector # on stack*/
-       jbsr    process_int             /*  process the IRQ*/
-3:             addql   #8,%sp                  /*  pop parameters off stack*/
-       bra     ret_from_exception
-
-inthandler4:
-       SAVE_ALL_INT
-       movew   %sp@(PT_OFF_FORMATVEC), %d0
-       and     #0x3ff, %d0
-
-       movel   %sp,%sp@-
-       movel   #68,%sp@-               /*  put vector # on stack*/
-       jbsr    process_int             /*  process the IRQ*/
-3:             addql   #8,%sp                  /*  pop parameters off stack*/
-       bra     ret_from_exception
-
-inthandler5:
-       SAVE_ALL_INT
-       movew   %sp@(PT_OFF_FORMATVEC), %d0
-       and     #0x3ff, %d0
-
-       movel   %sp,%sp@-
-       movel   #69,%sp@-               /*  put vector # on stack*/
-       jbsr    process_int             /*  process the IRQ*/
-3:             addql   #8,%sp                  /*  pop parameters off stack*/
-       bra     ret_from_exception
-
-inthandler6:
-       SAVE_ALL_INT
-       movew   %sp@(PT_OFF_FORMATVEC), %d0
-       and     #0x3ff, %d0
-
-       movel   %sp,%sp@-
-       movel   #70,%sp@-               /*  put vector # on stack*/
-       jbsr    process_int             /*  process the IRQ*/
-3:             addql   #8,%sp                  /*  pop parameters off stack*/
-       bra     ret_from_exception
-
-inthandler7:
-       SAVE_ALL_INT
-       movew   %sp@(PT_OFF_FORMATVEC), %d0
-       and     #0x3ff, %d0
-
-       movel   %sp,%sp@-
-       movel   #71,%sp@-               /*  put vector # on stack*/
-       jbsr    process_int             /*  process the IRQ*/
-3:             addql   #8,%sp                  /*  pop parameters off stack*/
-       bra     ret_from_exception
-
-inthandler:
-       SAVE_ALL_INT
-       movew   %sp@(PT_OFF_FORMATVEC), %d0
-       and     #0x3ff, %d0
-
-       movel   %sp,%sp@-
-       movel   %d0,%sp@-               /*  put vector # on stack*/
-       jbsr    process_int             /*  process the IRQ*/
-3:             addql   #8,%sp                  /*  pop parameters off stack*/
-       bra     ret_from_exception
-
-/*
- * Handler for uninitialized and spurious interrupts.
- */
-ENTRY(bad_interrupt)
-       addql   #1,irq_err_count
-       rte
-
-/*
- * Beware - when entering resume, prev (the current task) is
- * in a0, next (the new task) is in a1, so don't change these
- * registers until their contents are no longer needed.
- */
-ENTRY(resume)
-       movel   %a0,%d1                         /* save prev thread in d1 */
-       movew   %sr,%a0@(TASK_THREAD+THREAD_SR) /* save sr */
-       SAVE_SWITCH_STACK
-       movel   %sp,%a0@(TASK_THREAD+THREAD_KSP) /* save kernel stack */
-       movel   %usp,%a3                        /* save usp */
-       movel   %a3,%a0@(TASK_THREAD+THREAD_USP)
-
-       movel   %a1@(TASK_THREAD+THREAD_USP),%a3 /* restore user stack */
-       movel   %a3,%usp
-       movel   %a1@(TASK_THREAD+THREAD_KSP),%sp /* restore new thread stack */
-       RESTORE_SWITCH_STACK
-       movew   %a1@(TASK_THREAD+THREAD_SR),%sr /* restore thread status reg */
-       rts
-
diff --git a/arch/m68k/platform/68000/head.S b/arch/m68k/platform/68000/head.S
deleted file mode 100644 (file)
index 536ef96..0000000
+++ /dev/null
@@ -1,240 +0,0 @@
-/*
- * head.S - Common startup code for 68000 core based CPU's
- *
- * 2012.10.21, Luis Alves <ljalvs@gmail.com>, Single head.S file for all
- *             68000 core based CPU's. Based on the sources from:
- *             Coldfire by Greg Ungerer <gerg@snapgear.com>
- *             68328 by D. Jeff Dionne <jeff@ryeham.ee.ryerson.ca>,
- *                      Kenneth Albanowski <kjahds@kjahds.com>,
- *                      The Silver Hammer Group, Ltd.
- *
- */
-
-#include <linux/linkage.h>
-#include <linux/init.h>
-#include <asm/asm-offsets.h>
-#include <asm/thread_info.h>
-
-
-/*****************************************************************************
- * UCSIMM and UCDIMM use CONFIG_MEMORY_RESERVE to reserve some RAM
- *****************************************************************************/
-#ifdef CONFIG_MEMORY_RESERVE
-#define RAMEND (CONFIG_RAMBASE+CONFIG_RAMSIZE)-(CONFIG_MEMORY_RESERVE*0x100000)
-#else
-#define RAMEND (CONFIG_RAMBASE+CONFIG_RAMSIZE)
-#endif
-/*****************************************************************************/
-
-.global _start
-.global _rambase
-.global _ramvec
-.global _ramstart
-.global _ramend
-
-#if defined(CONFIG_PILOT) || defined(CONFIG_INIT_LCD)
-.global bootlogo_bits
-#endif
-
-/* Defining DEBUG_HEAD_CODE, serial port in 68x328 is inited */
-/* #define DEBUG_HEAD_CODE */
-#undef DEBUG_HEAD_CODE
-
-.data
-
-/*****************************************************************************
- * RAM setup pointers. Used by the kernel to determine RAM location and size.
- *****************************************************************************/
-
-_rambase:
-       .long   0
-_ramvec:
-       .long   0
-_ramstart:
-       .long   0
-_ramend:
-       .long   0
-
-__HEAD
-
-/*****************************************************************************
- * Entry point, where all begins!
- *****************************************************************************/
-
-_start:
-
-/* Pilot need this specific signature at the start of ROM */
-#ifdef CONFIG_PILOT
-       .byte   0x4e, 0xfa, 0x00, 0x0a          /* bra opcode (jmp 10 bytes) */
-       .byte   'b', 'o', 'o', 't'
-       .word   10000
-       nop
-       moveq   #0, %d0
-       movew   %d0, 0xfffff618                 /* Watchdog off */
-       movel   #0x00011f07, 0xfffff114         /* CS A1 Mask */
-#endif /* CONFIG_PILOT */
-
-       movew   #0x2700, %sr                    /* disable all interrupts */
-
-/*****************************************************************************
- * Setup PLL and wait for it to settle (in 68x328 cpu's).
- * Also, if enabled, init serial port.
- *****************************************************************************/
-#if defined(CONFIG_M68328) || \
-    defined(CONFIG_M68EZ328) || \
-    defined(CONFIG_M68VZ328)
-
-/* Serial port setup. Should only be needed if debugging this startup code. */
-#ifdef DEBUG_HEAD_CODE
-       movew   #0x0800, 0xfffff906             /* Ignore CTS */
-       movew   #0x010b, 0xfffff902             /* BAUD to 9600 */
-       movew   #0xe100, 0xfffff900             /* enable */
-#endif /* DEBUG_HEAD */
-
-#ifdef CONFIG_PILOT
-       movew   #0x2410, 0xfffff200             /* PLLCR */
-#else
-       movew   #0x2400, 0xfffff200             /* PLLCR */
-#endif
-       movew   #0x0123, 0xfffff202             /* PLLFSR */
-       moveq   #0, %d0
-       movew   #16384, %d0                     /* PLL settle wait loop */
-_pll_settle:
-       subw    #1, %d0
-       bne     _pll_settle
-#endif /* CONFIG_M68x328 */
-
-
-/*****************************************************************************
- * If running kernel from ROM some specific initialization has to be done.
- * (Assuming that everything is already init'ed when running from RAM)
- *****************************************************************************/
-#ifdef CONFIG_ROMKERNEL
-
-/*****************************************************************************
- * Init chip registers (uCsimm specific)
- *****************************************************************************/
-#ifdef CONFIG_UCSIMM
-       moveb   #0x00, 0xfffffb0b       /* Watchdog off */
-       moveb   #0x10, 0xfffff000       /* SCR */
-       moveb   #0x00, 0xfffff40b       /* enable chip select */
-       moveb   #0x00, 0xfffff423       /* enable /DWE */
-       moveb   #0x08, 0xfffffd0d       /* disable hardmap */
-       moveb   #0x07, 0xfffffd0e       /* level 7 interrupt clear */
-       movew   #0x8600, 0xfffff100     /* FLASH at 0x10c00000 */
-       movew   #0x018b, 0xfffff110     /* 2Meg, enable, 0ws */
-       movew   #0x8f00, 0xfffffc00     /* DRAM configuration */
-       movew   #0x9667, 0xfffffc02     /* DRAM control */
-       movew   #0x0000, 0xfffff106     /* DRAM at 0x00000000 */
-       movew   #0x068f, 0xfffff116     /* 8Meg, enable, 0ws */
-       moveb   #0x40, 0xfffff300       /* IVR */
-       movel   #0x007FFFFF, %d0        /* IMR */
-       movel   %d0, 0xfffff304
-       moveb   0xfffff42b, %d0
-       andb    #0xe0, %d0
-       moveb   %d0, 0xfffff42b
-#endif
-
-/*****************************************************************************
- * Init LCD controller.
- * (Assuming that LCD controller is already init'ed when running from RAM)
- *****************************************************************************/
-#ifdef CONFIG_INIT_LCD
-#ifdef CONFIG_PILOT
-       moveb   #0, 0xfffffA27                  /* LCKCON */
-       movel   #_start, 0xfffffA00             /* LSSA */
-       moveb   #0xa, 0xfffffA05                /* LVPW */
-       movew   #0x9f, 0xFFFFFa08               /* LXMAX */
-       movew   #0x9f, 0xFFFFFa0a               /* LYMAX */
-       moveb   #9, 0xfffffa29                  /* LBAR */
-       moveb   #0, 0xfffffa25                  /* LPXCD */
-       moveb   #0x04, 0xFFFFFa20               /* LPICF */
-       moveb   #0x58, 0xfffffA27               /* LCKCON */
-       moveb   #0x85, 0xfffff429               /* PFDATA */
-       moveb   #0xd8, 0xfffffA27               /* LCKCON */
-       moveb   #0xc5, 0xfffff429               /* PFDATA */
-       moveb   #0xd5, 0xfffff429               /* PFDATA */
-       movel   #bootlogo_bits, 0xFFFFFA00      /* LSSA */
-       moveb   #10, 0xFFFFFA05                 /* LVPW */
-       movew   #160, 0xFFFFFA08                /* LXMAX */
-       movew   #160, 0xFFFFFA0A                /* LYMAX */
-#else /* CONFIG_PILOT */
-       movel   #bootlogo_bits, 0xfffffA00      /* LSSA */
-       moveb   #0x28, 0xfffffA05               /* LVPW */
-       movew   #0x280, 0xFFFFFa08              /* LXMAX */
-       movew   #0x1df, 0xFFFFFa0a              /* LYMAX */
-       moveb   #0, 0xfffffa29                  /* LBAR */
-       moveb   #0, 0xfffffa25                  /* LPXCD */
-       moveb   #0x08, 0xFFFFFa20               /* LPICF */
-       moveb   #0x01, 0xFFFFFA21               /* -ve pol */
-       moveb   #0x81, 0xfffffA27               /* LCKCON */
-       movew   #0xff00, 0xfffff412             /* LCD pins */
-#endif /* CONFIG_PILOT */
-#endif /* CONFIG_INIT_LCD */
-
-/*****************************************************************************
- * Kernel is running from FLASH/ROM (XIP)
- * Copy init text & data to RAM
- *****************************************************************************/
-       moveal  #_etext, %a0
-       moveal  #_sdata, %a1
-       moveal  #__bss_start, %a2
-_copy_initmem:
-       movel   %a0@+, %a1@+
-       cmpal   %a1, %a2
-       bhi     _copy_initmem
-#endif /* CONFIG_ROMKERNEL */
-
-/*****************************************************************************
- * Setup basic memory information for kernel
- *****************************************************************************/
-       movel   #CONFIG_VECTORBASE,_ramvec      /* set vector base location */
-       movel   #CONFIG_RAMBASE,_rambase        /* set the base of RAM */
-       movel   #RAMEND, _ramend                /* set end ram addr */
-       lea     __bss_stop,%a1
-       movel   %a1,_ramstart
-
-/*****************************************************************************
- * If the kernel is in RAM, move romfs to right above bss and
- * adjust _ramstart to where romfs ends.
- *
- * (Do this only if CONFIG_MTD_UCLINUX is true)
- *****************************************************************************/
-
-#if defined(CONFIG_ROMFS_FS) && defined(CONFIG_RAMKERNEL) && \
-    defined(CONFIG_MTD_UCLINUX)
-       lea     __bss_start, %a0                /* get start of bss */
-       lea     __bss_stop, %a1                 /* set up destination  */
-       movel   %a0, %a2                        /* copy of bss start */
-
-       movel   8(%a0), %d0                     /* get size of ROMFS */
-       addql   #8, %d0                         /* allow for rounding */
-       andl    #0xfffffffc, %d0                /* whole words */
-
-       addl    %d0, %a0                        /* copy from end */
-       addl    %d0, %a1                        /* copy from end */
-       movel   %a1, _ramstart                  /* set start of ram */
-_copy_romfs:
-       movel   -(%a0), -(%a1)                  /* copy dword */
-       cmpl    %a0, %a2                        /* check if at end */
-       bne     _copy_romfs
-#endif /* CONFIG_ROMFS_FS && CONFIG_RAMKERNEL && CONFIG_MTD_UCLINUX */
-
-/*****************************************************************************
- * Clear bss region
- *****************************************************************************/
-       lea     __bss_start, %a0                /* get start of bss */
-       lea     __bss_stop, %a1                 /* get end of bss */
-_clear_bss:
-       movel   #0, (%a0)+                      /* clear each word */
-       cmpl    %a0, %a1                        /* check if at end */
-       bne     _clear_bss
-
-/*****************************************************************************
- * Load the current task pointer and stack.
- *****************************************************************************/
-       lea     init_thread_union,%a0
-       lea     THREAD_SIZE(%a0),%sp
-       jsr     start_kernel                    /* start Linux kernel */
-_exit:
-       jmp     _exit                           /* should never get here */
diff --git a/arch/m68k/platform/68000/ints.c b/arch/m68k/platform/68000/ints.c
deleted file mode 100644 (file)
index cda49b1..0000000
+++ /dev/null
@@ -1,186 +0,0 @@
-/*
- * ints.c - Generic interrupt controller support
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file COPYING in the main directory of this archive
- * for more details.
- *
- * Copyright 1996 Roman Zippel
- * Copyright 1999 D. Jeff Dionne <jeff@rt-control.com>
- */
-
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/irq.h>
-#include <asm/traps.h>
-#include <asm/io.h>
-#include <asm/machdep.h>
-
-#if defined(CONFIG_M68328)
-#include <asm/MC68328.h>
-#elif defined(CONFIG_M68EZ328)
-#include <asm/MC68EZ328.h>
-#elif defined(CONFIG_M68VZ328)
-#include <asm/MC68VZ328.h>
-#endif
-
-/* assembler routines */
-asmlinkage void system_call(void);
-asmlinkage void buserr(void);
-asmlinkage void trap(void);
-asmlinkage void trap3(void);
-asmlinkage void trap4(void);
-asmlinkage void trap5(void);
-asmlinkage void trap6(void);
-asmlinkage void trap7(void);
-asmlinkage void trap8(void);
-asmlinkage void trap9(void);
-asmlinkage void trap10(void);
-asmlinkage void trap11(void);
-asmlinkage void trap12(void);
-asmlinkage void trap13(void);
-asmlinkage void trap14(void);
-asmlinkage void trap15(void);
-asmlinkage void trap33(void);
-asmlinkage void trap34(void);
-asmlinkage void trap35(void);
-asmlinkage void trap36(void);
-asmlinkage void trap37(void);
-asmlinkage void trap38(void);
-asmlinkage void trap39(void);
-asmlinkage void trap40(void);
-asmlinkage void trap41(void);
-asmlinkage void trap42(void);
-asmlinkage void trap43(void);
-asmlinkage void trap44(void);
-asmlinkage void trap45(void);
-asmlinkage void trap46(void);
-asmlinkage void trap47(void);
-asmlinkage irqreturn_t bad_interrupt(int, void *);
-asmlinkage irqreturn_t inthandler(void);
-asmlinkage irqreturn_t inthandler1(void);
-asmlinkage irqreturn_t inthandler2(void);
-asmlinkage irqreturn_t inthandler3(void);
-asmlinkage irqreturn_t inthandler4(void);
-asmlinkage irqreturn_t inthandler5(void);
-asmlinkage irqreturn_t inthandler6(void);
-asmlinkage irqreturn_t inthandler7(void);
-
-/* The 68k family did not have a good way to determine the source
- * of interrupts until later in the family.  The EC000 core does
- * not provide the vector number on the stack, we vector everything
- * into one vector and look in the blasted mask register...
- * This code is designed to be fast, almost constant time, not clean!
- */
-void process_int(int vec, struct pt_regs *fp)
-{
-       int irq;
-       int mask;
-
-       unsigned long pend = ISR;
-
-       while (pend) {
-               if (pend & 0x0000ffff) {
-                       if (pend & 0x000000ff) {
-                               if (pend & 0x0000000f) {
-                                       mask = 0x00000001;
-                                       irq = 0;
-                               } else {
-                                       mask = 0x00000010;
-                                       irq = 4;
-                               }
-                       } else {
-                               if (pend & 0x00000f00) {
-                                       mask = 0x00000100;
-                                       irq = 8;
-                               } else {
-                                       mask = 0x00001000;
-                                       irq = 12;
-                               }
-                       }
-               } else {
-                       if (pend & 0x00ff0000) {
-                               if (pend & 0x000f0000) {
-                                       mask = 0x00010000;
-                                       irq = 16;
-                               } else {
-                                       mask = 0x00100000;
-                                       irq = 20;
-                               }
-                       } else {
-                               if (pend & 0x0f000000) {
-                                       mask = 0x01000000;
-                                       irq = 24;
-                               } else {
-                                       mask = 0x10000000;
-                                       irq = 28;
-                               }
-                       }
-               }
-
-               while (! (mask & pend)) {
-                       mask <<=1;
-                       irq++;
-               }
-
-               do_IRQ(irq, fp);
-               pend &= ~mask;
-       }
-}
-
-static void intc_irq_unmask(struct irq_data *d)
-{
-       IMR &= ~(1 << d->irq);
-}
-
-static void intc_irq_mask(struct irq_data *d)
-{
-       IMR |= (1 << d->irq);
-}
-
-static struct irq_chip intc_irq_chip = {
-       .name           = "M68K-INTC",
-       .irq_mask       = intc_irq_mask,
-       .irq_unmask     = intc_irq_unmask,
-};
-
-/*
- * This function should be called during kernel startup to initialize
- * the machine vector table.
- */
-void __init trap_init(void)
-{
-       int i;
-
-       /* set up the vectors */
-       for (i = 72; i < 256; ++i)
-               _ramvec[i] = (e_vector) bad_interrupt;
-
-       _ramvec[32] = system_call;
-
-       _ramvec[65] = (e_vector) inthandler1;
-       _ramvec[66] = (e_vector) inthandler2;
-       _ramvec[67] = (e_vector) inthandler3;
-       _ramvec[68] = (e_vector) inthandler4;
-       _ramvec[69] = (e_vector) inthandler5;
-       _ramvec[70] = (e_vector) inthandler6;
-       _ramvec[71] = (e_vector) inthandler7;
-}
-
-void __init init_IRQ(void)
-{
-       int i;
-
-       IVR = 0x40; /* Set DragonBall IVR (interrupt base) to 64 */
-
-       /* turn off all interrupts */
-       IMR = ~0;
-
-       for (i = 0; (i < NR_IRQS); i++) {
-               irq_set_chip(i, &intc_irq_chip);
-               irq_set_handler(i, handle_level_irq);
-       }
-}
-
diff --git a/arch/m68k/platform/68000/m68328.c b/arch/m68k/platform/68000/m68328.c
deleted file mode 100644 (file)
index e53caf4..0000000
+++ /dev/null
@@ -1,56 +0,0 @@
-/***************************************************************************/
-
-/*
- *  m68328.c - 68328 specific config
- *
- *  Copyright (C) 1993 Hamish Macdonald
- *  Copyright (C) 1999 D. Jeff Dionne
- *
- * 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.
- *
- * VZ Support/Fixes             Evan Stawnyczy <e@lineo.ca>
- */
-
-/***************************************************************************/
-
-#include <linux/init.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/rtc.h>
-#include <asm/machdep.h>
-#include <asm/MC68328.h>
-#if defined(CONFIG_PILOT) || defined(CONFIG_INIT_LCD)
-#include "bootlogo.h"
-#endif
-
-/***************************************************************************/
-
-int m68328_hwclk(int set, struct rtc_time *t);
-
-/***************************************************************************/
-
-void m68328_reset (void)
-{
-  local_irq_disable();
-  asm volatile ("moveal #0x10c00000, %a0;\n\t"
-               "moveb #0, 0xFFFFF300;\n\t"
-               "moveal 0(%a0), %sp;\n\t"
-               "moveal 4(%a0), %a0;\n\t"
-               "jmp (%a0);");
-}
-
-/***************************************************************************/
-
-void __init config_BSP(char *command, int len)
-{
-  printk(KERN_INFO "\n68328 support D. Jeff Dionne <jeff@uclinux.org>\n");
-  printk(KERN_INFO "68328 support Kenneth Albanowski <kjahds@kjshds.com>\n");
-  printk(KERN_INFO "68328/Pilot support Bernhard Kuhn <kuhn@lpr.e-technik.tu-muenchen.de>\n");
-
-  mach_hwclk = m68328_hwclk;
-  mach_reset = m68328_reset;
-}
-
-/***************************************************************************/
diff --git a/arch/m68k/platform/68000/m68EZ328.c b/arch/m68k/platform/68000/m68EZ328.c
deleted file mode 100644 (file)
index 2195290..0000000
+++ /dev/null
@@ -1,78 +0,0 @@
-/***************************************************************************/
-
-/*
- *  m68EZ328.c - 68EZ328 specific config
- *
- *  Copyright (C) 1993 Hamish Macdonald
- *  Copyright (C) 1999 D. Jeff Dionne
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file COPYING in the main directory of this archive
- * for more details.
- */
-
-/***************************************************************************/
-
-#include <linux/init.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/rtc.h>
-#include <asm/pgtable.h>
-#include <asm/machdep.h>
-#include <asm/MC68EZ328.h>
-#ifdef CONFIG_UCSIMM
-#include <asm/bootstd.h>
-#endif
-
-/***************************************************************************/
-
-int m68328_hwclk(int set, struct rtc_time *t);
-
-/***************************************************************************/
-
-void m68ez328_reset(void)
-{
-  local_irq_disable();
-  asm volatile (
-    "moveal #0x10c00000, %a0;\n"
-    "moveb #0, 0xFFFFF300;\n"
-    "moveal 0(%a0), %sp;\n"
-    "moveal 4(%a0), %a0;\n"
-    "jmp (%a0);\n"
-    );
-}
-
-/***************************************************************************/
-
-unsigned char *cs8900a_hwaddr;
-static int errno;
-
-#ifdef CONFIG_UCSIMM
-_bsc0(char *, getserialnum)
-_bsc1(unsigned char *, gethwaddr, int, a)
-_bsc1(char *, getbenv, char *, a)
-#endif
-
-void __init config_BSP(char *command, int len)
-{
-  unsigned char *p;
-
-  printk(KERN_INFO "\n68EZ328 DragonBallEZ support (C) 1999 Rt-Control, Inc\n");
-
-#ifdef CONFIG_UCSIMM
-  printk(KERN_INFO "uCsimm serial string [%s]\n",getserialnum());
-  p = cs8900a_hwaddr = gethwaddr(0);
-  printk(KERN_INFO "uCsimm hwaddr %.2x:%.2x:%.2x:%.2x:%.2x:%.2x\n",
-         p[0], p[1], p[2], p[3], p[4], p[5]);
-
-  p = getbenv("APPEND");
-  if (p) strcpy(p,command);
-  else command[0] = 0;
-#endif
-
-  mach_sched_init = hw_timer_init;
-  mach_hwclk = m68328_hwclk;
-  mach_reset = m68ez328_reset;
-}
-
-/***************************************************************************/
diff --git a/arch/m68k/platform/68000/m68VZ328.c b/arch/m68k/platform/68000/m68VZ328.c
deleted file mode 100644 (file)
index 0e5e5a1..0000000
+++ /dev/null
@@ -1,190 +0,0 @@
-/***************************************************************************/
-
-/*
- *  m68VZ328.c - 68VZ328 specific config
- *
- *  Copyright (C) 1993 Hamish Macdonald
- *  Copyright (C) 1999 D. Jeff Dionne
- *  Copyright (C) 2001 Georges Menie, Ken Desmet
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file COPYING in the main directory of this archive
- * for more details.
- */
-
-/***************************************************************************/
-
-#include <linux/init.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/kd.h>
-#include <linux/netdevice.h>
-#include <linux/interrupt.h>
-#include <linux/irq.h>
-#include <linux/rtc.h>
-
-#include <asm/pgtable.h>
-#include <asm/machdep.h>
-#include <asm/MC68VZ328.h>
-#include <asm/bootstd.h>
-
-#ifdef CONFIG_INIT_LCD
-#include "bootlogo-vz.h"
-#endif
-
-/***************************************************************************/
-
-int m68328_hwclk(int set, struct rtc_time *t);
-
-/***************************************************************************/
-/*                        Init Drangon Engine hardware                     */
-/***************************************************************************/
-#if defined(CONFIG_DRAGEN2)
-
-static void m68vz328_reset(void)
-{
-       local_irq_disable();
-
-#ifdef CONFIG_INIT_LCD
-       PBDATA |= 0x20;                         /* disable CCFL light */
-       PKDATA |= 0x4;                          /* disable LCD controller */
-       LCKCON = 0;
-#endif
-
-       __asm__ __volatile__(
-               "reset\n\t"
-               "moveal #0x04000000, %a0\n\t"
-               "moveal 0(%a0), %sp\n\t"
-               "moveal 4(%a0), %a0\n\t"
-               "jmp (%a0)"
-       );
-}
-
-static void __init init_hardware(char *command, int size)
-{
-#ifdef CONFIG_DIRECT_IO_ACCESS
-       SCR = 0x10;                                     /* allow user access to internal registers */
-#endif
-
-       /* CSGB Init */
-       CSGBB = 0x4000;
-       CSB = 0x1a1;
-
-       /* CS8900 init */
-       /* PK3: hardware sleep function pin, active low */
-       PKSEL |= PK(3);                         /* select pin as I/O */
-       PKDIR |= PK(3);                         /* select pin as output */
-       PKDATA |= PK(3);                        /* set pin high */
-
-       /* PF5: hardware reset function pin, active high */
-       PFSEL |= PF(5);                         /* select pin as I/O */
-       PFDIR |= PF(5);                         /* select pin as output */
-       PFDATA &= ~PF(5);                       /* set pin low */
-
-       /* cs8900 hardware reset */
-       PFDATA |= PF(5);
-       { int i; for (i = 0; i < 32000; ++i); }
-       PFDATA &= ~PF(5);
-
-       /* INT1 enable (cs8900 IRQ) */
-       PDPOL &= ~PD(1);                        /* active high signal */
-       PDIQEG &= ~PD(1);
-       PDIRQEN |= PD(1);                       /* IRQ enabled */
-
-#ifdef CONFIG_INIT_LCD
-       /* initialize LCD controller */
-       LSSA = (long) screen_bits;
-       LVPW = 0x14;
-       LXMAX = 0x140;
-       LYMAX = 0xef;
-       LRRA = 0;
-       LPXCD = 3;
-       LPICF = 0x08;
-       LPOLCF = 0;
-       LCKCON = 0x80;
-       PCPDEN = 0xff;
-       PCSEL = 0;
-
-       /* Enable LCD controller */
-       PKDIR |= 0x4;
-       PKSEL |= 0x4;
-       PKDATA &= ~0x4;
-
-       /* Enable CCFL backlighting circuit */
-       PBDIR |= 0x20;
-       PBSEL |= 0x20;
-       PBDATA &= ~0x20;
-
-       /* contrast control register */
-       PFDIR |= 0x1;
-       PFSEL &= ~0x1;
-       PWMR = 0x037F;
-#endif
-}
-
-/***************************************************************************/
-/*                      Init RT-Control uCdimm hardware                    */
-/***************************************************************************/
-#elif defined(CONFIG_UCDIMM)
-
-static void m68vz328_reset(void)
-{
-       local_irq_disable();
-       asm volatile (
-               "moveal #0x10c00000, %a0;\n\t"
-               "moveb #0, 0xFFFFF300;\n\t"
-               "moveal 0(%a0), %sp;\n\t"
-               "moveal 4(%a0), %a0;\n\t"
-               "jmp (%a0);\n"
-       );
-}
-
-unsigned char *cs8900a_hwaddr;
-static int errno;
-
-_bsc0(char *, getserialnum)
-_bsc1(unsigned char *, gethwaddr, int, a)
-_bsc1(char *, getbenv, char *, a)
-
-static void __init init_hardware(char *command, int size)
-{
-       char *p;
-
-       printk(KERN_INFO "uCdimm serial string [%s]\n", getserialnum());
-       p = cs8900a_hwaddr = gethwaddr(0);
-       printk(KERN_INFO "uCdimm hwaddr %.2x:%.2x:%.2x:%.2x:%.2x:%.2x\n",
-               p[0], p[1], p[2], p[3], p[4], p[5]);
-       p = getbenv("APPEND");
-       if (p)
-               strcpy(p, command);
-       else
-               command[0] = 0;
-}
-
-/***************************************************************************/
-#else
-
-static void m68vz328_reset(void)
-{
-}
-
-static void __init init_hardware(char *command, int size)
-{
-}
-
-/***************************************************************************/
-#endif
-/***************************************************************************/
-
-void __init config_BSP(char *command, int size)
-{
-       printk(KERN_INFO "68VZ328 DragonBallVZ support (c) 2001 Lineo, Inc.\n");
-
-       init_hardware(command, size);
-
-       mach_sched_init = hw_timer_init;
-       mach_hwclk = m68328_hwclk;
-       mach_reset = m68vz328_reset;
-}
-
-/***************************************************************************/
diff --git a/arch/m68k/platform/68000/romvec.S b/arch/m68k/platform/68000/romvec.S
deleted file mode 100644 (file)
index 15c70cd..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * romvec.S - Vector table for 68000 cpus
- *
- * 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 1996 Roman Zippel
- * Copyright 1999 D. Jeff Dionne <jeff@rt-control.com>
- * Copyright 2006 Greg Ungerer <gerg@snapgear.com>
- */
-
-.global _start
-.global _buserr
-.global trap
-.global system_call
-
-.section .romvec
-
-e_vectors:
-.long CONFIG_RAMBASE+CONFIG_RAMSIZE-4, _start, buserr, trap
-.long trap, trap, trap, trap
-.long trap, trap, trap, trap
-.long trap, trap, trap, trap
-.long trap, trap, trap, trap
-.long trap, trap, trap, trap
-.long trap, trap, trap, trap
-.long trap, trap, trap, trap
-/* TRAP #0-15 */
-.long system_call, trap, trap, trap
-.long trap, trap, trap, trap
-.long trap, trap, trap, trap
-.long trap, trap, trap, trap
-.long 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
-
diff --git a/arch/m68k/platform/68000/timers.c b/arch/m68k/platform/68000/timers.c
deleted file mode 100644 (file)
index 99a9869..0000000
+++ /dev/null
@@ -1,137 +0,0 @@
-/***************************************************************************/
-
-/*
- *  timers.c - Generic hardware timer support.
- *
- *  Copyright (C) 1993 Hamish Macdonald
- *  Copyright (C) 1999 D. Jeff Dionne
- *  Copyright (C) 2001 Georges Menie, Ken Desmet
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file COPYING in the main directory of this archive
- * for more details.
- */
-
-/***************************************************************************/
-
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/mm.h>
-#include <linux/interrupt.h>
-#include <linux/irq.h>
-#include <linux/clocksource.h>
-#include <linux/rtc.h>
-#include <asm/setup.h>
-#include <asm/pgtable.h>
-#include <asm/machdep.h>
-#include <asm/MC68VZ328.h>
-
-/***************************************************************************/
-
-#if defined(CONFIG_DRAGEN2)
-/* with a 33.16 MHz clock, this will give usec resolution to the time functions */
-#define CLOCK_SOURCE   TCTL_CLKSOURCE_SYSCLK
-#define CLOCK_PRE      7
-#define TICKS_PER_JIFFY        41450
-
-#elif defined(CONFIG_XCOPILOT_BUGS)
-/*
- * The only thing I know is that CLK32 is not available on Xcopilot
- * I have little idea about what frequency SYSCLK has on Xcopilot.
- * The values for prescaler and compare registers were simply
- * taken from the original source
- */
-#define CLOCK_SOURCE   TCTL_CLKSOURCE_SYSCLK
-#define CLOCK_PRE      2
-#define TICKS_PER_JIFFY        0xd7e4
-
-#else
-/* default to using the 32Khz clock */
-#define CLOCK_SOURCE   TCTL_CLKSOURCE_32KHZ
-#define CLOCK_PRE      31
-#define TICKS_PER_JIFFY        10
-#endif
-
-static u32 m68328_tick_cnt;
-static irq_handler_t timer_interrupt;
-
-/***************************************************************************/
-
-static irqreturn_t hw_tick(int irq, void *dummy)
-{
-       /* Reset Timer1 */
-       TSTAT &= 0;
-
-       m68328_tick_cnt += TICKS_PER_JIFFY;
-       return timer_interrupt(irq, dummy);
-}
-
-/***************************************************************************/
-
-static struct irqaction m68328_timer_irq = {
-       .name    = "timer",
-       .flags   = IRQF_TIMER,
-       .handler = hw_tick,
-};
-
-/***************************************************************************/
-
-static cycle_t m68328_read_clk(struct clocksource *cs)
-{
-       unsigned long flags;
-       u32 cycles;
-
-       local_irq_save(flags);
-       cycles = m68328_tick_cnt + TCN;
-       local_irq_restore(flags);
-
-       return cycles;
-}
-
-/***************************************************************************/
-
-static struct clocksource m68328_clk = {
-       .name   = "timer",
-       .rating = 250,
-       .read   = m68328_read_clk,
-       .mask   = CLOCKSOURCE_MASK(32),
-       .flags  = CLOCK_SOURCE_IS_CONTINUOUS,
-};
-
-/***************************************************************************/
-
-void hw_timer_init(irq_handler_t handler)
-{
-       /* disable timer 1 */
-       TCTL = 0;
-
-       /* set ISR */
-       setup_irq(TMR_IRQ_NUM, &m68328_timer_irq);
-
-       /* Restart mode, Enable int, Set clock source */
-       TCTL = TCTL_OM | TCTL_IRQEN | CLOCK_SOURCE;
-       TPRER = CLOCK_PRE;
-       TCMP = TICKS_PER_JIFFY;
-
-       /* Enable timer 1 */
-       TCTL |= TCTL_TEN;
-       clocksource_register_hz(&m68328_clk, TICKS_PER_JIFFY*HZ);
-       timer_interrupt = handler;
-}
-
-/***************************************************************************/
-
-int m68328_hwclk(int set, struct rtc_time *t)
-{
-       if (!set) {
-               long now = RTCTIME;
-               t->tm_year = t->tm_mon = t->tm_mday = 1;
-               t->tm_hour = (now >> 24) % 24;
-               t->tm_min = (now >> 16) % 60;
-               t->tm_sec = now % 60;
-       }
-
-       return 0;
-}
-
-/***************************************************************************/
diff --git a/arch/m68k/platform/68360/Makefile b/arch/m68k/platform/68360/Makefile
deleted file mode 100644 (file)
index f6f4343..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-#
-# Makefile for arch/m68knommu/platform/68360.
-#
-model-y                          := ram
-model-$(CONFIG_ROMKERNEL) := rom
-
-obj-y := config.o commproc.o entry.o ints.o
-
-extra-y := head.o
-
-$(obj)/head.o: $(obj)/head-$(model-y).o
-       ln -sf head-$(model-y).o $(obj)/head.o
diff --git a/arch/m68k/platform/68360/commproc.c b/arch/m68k/platform/68360/commproc.c
deleted file mode 100644 (file)
index 315727b..0000000
+++ /dev/null
@@ -1,309 +0,0 @@
-/*
- * General Purpose functions for the global management of the
- * Communication Processor Module.
- *
- * Copyright (c) 2000 Michael Leslie <mleslie@lineo.com>
- * Copyright (c) 1997 Dan Malek (dmalek@jlc.net)
- *
- * In addition to the individual control of the communication
- * channels, there are a few functions that globally affect the
- * communication processor.
- *
- * Buffer descriptors must be allocated from the dual ported memory
- * space.  The allocator for that is here.  When the communication
- * process is reset, we reclaim the memory available.  There is
- * currently no deallocator for this memory.
- * The amount of space available is platform dependent.  On the
- * MBX, the EPPC software loads additional microcode into the
- * communication processor, and uses some of the DP ram for this
- * purpose.  Current, the first 512 bytes and the last 256 bytes of
- * memory are used.  Right now I am conservative and only use the
- * memory that can never be used for microcode.  If there are
- * applications that require more DP ram, we can expand the boundaries
- * but then we have to be careful of any downloaded microcode.
- *
- */
-
-/*
- * Michael Leslie <mleslie@lineo.com>
- * adapted Dan Malek's ppc8xx drivers to M68360
- *
- */
-
-#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/sched.h>
-#include <linux/kernel.h>
-#include <linux/param.h>
-#include <linux/string.h>
-#include <linux/mm.h>
-#include <linux/interrupt.h>
-#include <asm/irq.h>
-#include <asm/m68360.h>
-#include <asm/commproc.h>
-
-/* #include <asm/page.h> */
-/* #include <asm/pgtable.h> */
-extern void *_quicc_base;
-extern unsigned int system_clock;
-
-
-static uint dp_alloc_base;     /* Starting offset in DP ram */
-static uint dp_alloc_top;      /* Max offset + 1 */
-
-#if 0
-static void    *host_buffer;   /* One page of host buffer */
-static void    *host_end;          /* end + 1 */
-#endif
-
-/* struct  cpm360_t *cpmp; */         /* Pointer to comm processor space */
-
-QUICC  *pquicc;
-/* QUICC  *quicc_dpram; */ /* mleslie - temporary; use extern pquicc elsewhere instead */
-
-
-/* CPM interrupt vector functions. */
-struct cpm_action {
-       void    (*handler)(void *);
-       void    *dev_id;
-};
-static struct  cpm_action cpm_vecs[CPMVEC_NR];
-static void    cpm_interrupt(int irq, void * dev, struct pt_regs * regs);
-static void    cpm_error_interrupt(void *);
-
-/* prototypes: */
-void cpm_install_handler(int vec, void (*handler)(), void *dev_id);
-void m360_cpm_reset(void);
-
-
-
-
-void __init m360_cpm_reset()
-{
-/*     pte_t              *pte; */
-
-       pquicc = (struct quicc *)(_quicc_base); /* initialized in crt0_rXm.S */
-
-       /* Perform a CPM reset. */
-       pquicc->cp_cr = (SOFTWARE_RESET | CMD_FLAG);
-
-       /* Wait for CPM to become ready (should be 2 clocks). */
-       while (pquicc->cp_cr & CMD_FLAG);
-
-       /* On the recommendation of the 68360 manual, p. 7-60
-        * - Set sdma interrupt service mask to 7
-        * - Set sdma arbitration ID to 4
-        */
-       pquicc->sdma_sdcr = 0x0740;
-
-
-       /* Claim the DP memory for our use.
-        */
-       dp_alloc_base = CPM_DATAONLY_BASE;
-       dp_alloc_top = dp_alloc_base + CPM_DATAONLY_SIZE;
-
-
-       /* Set the host page for allocation.
-        */
-       /*      host_buffer = host_page_addr; */
-       /*      host_end = host_page_addr + PAGE_SIZE; */
-
-       /*      pte = find_pte(&init_mm, host_page_addr); */
-       /*      pte_val(*pte) |= _PAGE_NO_CACHE; */
-       /*      flush_tlb_page(current->mm->mmap, host_buffer); */
-
-       /* Tell everyone where the comm processor resides.
-       */
-/*     cpmp = (cpm360_t *)commproc; */
-}
-
-
-/* This is called during init_IRQ.  We used to do it above, but this
- * was too early since init_IRQ was not yet called.
- */
-void
-cpm_interrupt_init(void)
-{
-       /* Initialize the CPM interrupt controller.
-        * NOTE THAT pquicc had better have been initialized!
-        * reference: MC68360UM p. 7-377
-        */
-       pquicc->intr_cicr =
-               (CICR_SCD_SCC4 | CICR_SCC_SCC3 | CICR_SCB_SCC2 | CICR_SCA_SCC1) |
-               (CPM_INTERRUPT << 13) |
-               CICR_HP_MASK |
-               (CPM_VECTOR_BASE << 5) |
-               CICR_SPS;
-
-       /* mask all CPM interrupts from reaching the cpu32 core: */
-       pquicc->intr_cimr = 0;
-
-
-       /* mles - If I understand correctly, the 360 just pops over to the CPM
-        * specific vector, obviating the necessity to vector through the IRQ
-        * whose priority the CPM is set to. This needs a closer look, though.
-        */
-
-       /* Set our interrupt handler with the core CPU. */
-/*     if (request_irq(CPM_INTERRUPT, cpm_interrupt, 0, "cpm", NULL) != 0) */
-/*             panic("Could not allocate CPM IRQ!"); */
-
-       /* Install our own error handler.
-        */
-       /* I think we want to hold off on this one for the moment - mles */
-       /* cpm_install_handler(CPMVEC_ERROR, cpm_error_interrupt, NULL); */
-
-       /* master CPM interrupt enable */
-       /* pquicc->intr_cicr |= CICR_IEN; */ /* no such animal for 360 */
-}
-
-
-
-/* CPM interrupt controller interrupt.
-*/
-static void
-cpm_interrupt(int irq, void * dev, struct pt_regs * regs)
-{
-       /* uint vec; */
-
-       /* mles: Note that this stuff is currently being performed by
-        * M68360_do_irq(int vec, struct pt_regs *fp), in ../ints.c  */
-
-       /* figure out the vector */
-       /* call that vector's handler */
-       /* clear the irq's bit in the service register */
-
-#if 0 /* old 860 stuff: */
-       /* Get the vector by setting the ACK bit and then reading
-        * the register.
-        */
-       ((volatile immap_t *)IMAP_ADDR)->im_cpic.cpic_civr = 1;
-       vec = ((volatile immap_t *)IMAP_ADDR)->im_cpic.cpic_civr;
-       vec >>= 11;
-
-
-       if (cpm_vecs[vec].handler != 0)
-               (*cpm_vecs[vec].handler)(cpm_vecs[vec].dev_id);
-       else
-               ((immap_t *)IMAP_ADDR)->im_cpic.cpic_cimr &= ~(1 << vec);
-
-       /* After servicing the interrupt, we have to remove the status
-        * indicator.
-        */
-       ((immap_t *)IMAP_ADDR)->im_cpic.cpic_cisr |= (1 << vec);
-#endif
-
-}
-
-/* The CPM can generate the error interrupt when there is a race condition
- * between generating and masking interrupts.  All we have to do is ACK it
- * and return.  This is a no-op function so we don't need any special
- * tests in the interrupt handler.
- */
-static void
-cpm_error_interrupt(void *dev)
-{
-}
-
-/* Install a CPM interrupt handler.
-*/
-void
-cpm_install_handler(int vec, void (*handler)(), void *dev_id)
-{
-
-       request_irq(vec, handler, 0, "timer", dev_id);
-
-/*     if (cpm_vecs[vec].handler != 0) */
-/*             printk(KERN_INFO "CPM interrupt %x replacing %x\n", */
-/*                     (uint)handler, (uint)cpm_vecs[vec].handler); */
-/*     cpm_vecs[vec].handler = handler; */
-/*     cpm_vecs[vec].dev_id = dev_id; */
-
-       /*              ((immap_t *)IMAP_ADDR)->im_cpic.cpic_cimr |= (1 << vec); */
-/*     pquicc->intr_cimr |= (1 << vec); */
-
-}
-
-/* Free a CPM interrupt handler.
-*/
-void
-cpm_free_handler(int vec)
-{
-       cpm_vecs[vec].handler = NULL;
-       cpm_vecs[vec].dev_id = NULL;
-       /* ((immap_t *)IMAP_ADDR)->im_cpic.cpic_cimr &= ~(1 << vec); */
-       pquicc->intr_cimr &= ~(1 << vec);
-}
-
-
-
-
-/* Allocate some memory from the dual ported ram.  We may want to
- * enforce alignment restrictions, but right now everyone is a good
- * citizen.
- */
-uint
-m360_cpm_dpalloc(uint size)
-{
-        uint    retloc;
-
-        if ((dp_alloc_base + size) >= dp_alloc_top)
-                return(CPM_DP_NOSPACE);
-
-        retloc = dp_alloc_base;
-        dp_alloc_base += size;
-
-        return(retloc);
-}
-
-
-#if 0 /* mleslie - for now these are simply kmalloc'd */
-/* We also own one page of host buffer space for the allocation of
- * UART "fifos" and the like.
- */
-uint
-m360_cpm_hostalloc(uint size)
-{
-       uint    retloc;
-
-       if ((host_buffer + size) >= host_end)
-               return(0);
-
-       retloc = host_buffer;
-       host_buffer += size;
-
-       return(retloc);
-}
-#endif
-
-
-/* Set a baud rate generator.  This needs lots of work.  There are
- * four BRGs, any of which can be wired to any channel.
- * The internal baud rate clock is the system clock divided by 16.
- * This assumes the baudrate is 16x oversampled by the uart.
- */
-/* #define BRG_INT_CLK (((bd_t *)__res)->bi_intfreq * 1000000) */
-#define BRG_INT_CLK            system_clock
-#define BRG_UART_CLK   (BRG_INT_CLK/16)
-
-void
-m360_cpm_setbrg(uint brg, uint rate)
-{
-       volatile uint   *bp;
-
-       /* This is good enough to get SMCs running.....
-        */
-       /* bp = (uint *)&cpmp->cp_brgc1; */
-       bp = (volatile uint *)(&pquicc->brgc[0].l);
-       bp += brg;
-       *bp = ((BRG_UART_CLK / rate - 1) << 1) | CPM_BRG_EN;
-}
-
-
-/*
- * Local variables:
- *  c-indent-level: 4
- *  c-basic-offset: 4
- *  tab-width: 4
- * End:
- */
diff --git a/arch/m68k/platform/68360/config.c b/arch/m68k/platform/68360/config.c
deleted file mode 100644 (file)
index d493ac4..0000000
+++ /dev/null
@@ -1,183 +0,0 @@
-/*
- *  linux/arch/m68knommu/platform/68360/config.c
- *
- *  Copyright (c) 2000 Michael Leslie <mleslie@lineo.com>
- *  Copyright (C) 1993 Hamish Macdonald
- *  Copyright (C) 1999 D. Jeff Dionne <jeff@uclinux.org>
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file COPYING in the main directory of this archive
- * for more details.
- */
-
-#include <stdarg.h>
-#include <linux/init.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/mm.h>
-#include <linux/interrupt.h>
-#include <linux/irq.h>
-
-#include <asm/setup.h>
-#include <asm/pgtable.h>
-#include <asm/machdep.h>
-#include <asm/m68360.h>
-
-#ifdef CONFIG_UCQUICC
-#include <asm/bootstd.h>
-#endif
-
-extern void m360_cpm_reset(void);
-
-// Mask to select if the PLL prescaler is enabled.
-#define MCU_PREEN   ((unsigned short)(0x0001 << 13))
-
-#if defined(CONFIG_UCQUICC)
-#define OSCILLATOR  (unsigned long int)33000000
-#endif
-
-static irq_handler_t timer_interrupt;
-unsigned long int system_clock;
-
-extern QUICC *pquicc;
-
-/* TODO  DON"T Hard Code this */
-/* calculate properly using the right PLL and prescaller */
-// unsigned int system_clock = 33000000l;
-extern unsigned long int system_clock; //In kernel setup.c
-
-
-static irqreturn_t hw_tick(int irq, void *dummy)
-{
-  /* Reset Timer1 */
-  /* TSTAT &= 0; */
-
-  pquicc->timer_ter1 = 0x0002; /* clear timer event */
-
-  return timer_interrupt(irq, dummy);
-}
-
-static struct irqaction m68360_timer_irq = {
-       .name    = "timer",
-       .flags   = IRQF_TIMER,
-       .handler = hw_tick,
-};
-
-void hw_timer_init(irq_handler_t handler)
-{
-  unsigned char prescaler;
-  unsigned short tgcr_save;
-
-#if 0
-  /* Restart mode, Enable int, 32KHz, Enable timer */
-  TCTL = TCTL_OM | TCTL_IRQEN | TCTL_CLKSOURCE_32KHZ | TCTL_TEN;
-  /* Set prescaler (Divide 32KHz by 32)*/
-  TPRER = 31;
-  /* Set compare register  32Khz / 32 / 10 = 100 */
-  TCMP = 10;                                                              
-
-  request_irq(IRQ_MACHSPEC | 1, timer_routine, 0, "timer", NULL);
-#endif
-
-  /* General purpose quicc timers: MC68360UM p7-20 */
-
-  /* Set up timer 1 (in [1..4]) to do 100Hz */
-  tgcr_save = pquicc->timer_tgcr & 0xfff0;
-  pquicc->timer_tgcr  = tgcr_save; /* stop and reset timer 1 */
-  /* pquicc->timer_tgcr |= 0x4444; */ /* halt timers when FREEZE (ie bdm freeze) */
-
-  prescaler = 8;
-  pquicc->timer_tmr1 = 0x001a | /* or=1, frr=1, iclk=01b */
-                           (unsigned short)((prescaler - 1) << 8);
-    
-  pquicc->timer_tcn1 = 0x0000; /* initial count */
-  /* calculate interval for 100Hz based on the _system_clock: */
-  pquicc->timer_trr1 = (system_clock/ prescaler) / HZ; /* reference count */
-
-  pquicc->timer_ter1 = 0x0003; /* clear timer events */
-
-  timer_interrupt = handler;
-
-  /* enable timer 1 interrupt in CIMR */
-  setup_irq(CPMVEC_TIMER1, &m68360_timer_irq);
-
-  /* Start timer 1: */
-  tgcr_save = (pquicc->timer_tgcr & 0xfff0) | 0x0001;
-  pquicc->timer_tgcr  = tgcr_save;
-}
-
-int BSP_set_clock_mmss(unsigned long nowtime)
-{
-#if 0
-  short real_seconds = nowtime % 60, real_minutes = (nowtime / 60) % 60;
-
-  tod->second1 = real_seconds / 10;
-  tod->second2 = real_seconds % 10;
-  tod->minute1 = real_minutes / 10;
-  tod->minute2 = real_minutes % 10;
-#endif
-  return 0;
-}
-
-void BSP_reset (void)
-{
-  local_irq_disable();
-  asm volatile (
-    "moveal #_start, %a0;\n"
-    "moveb #0, 0xFFFFF300;\n"
-    "moveal 0(%a0), %sp;\n"
-    "moveal 4(%a0), %a0;\n"
-    "jmp (%a0);\n"
-    );
-}
-
-unsigned char *scc1_hwaddr;
-static int errno;
-
-#if defined (CONFIG_UCQUICC)
-_bsc0(char *, getserialnum)
-_bsc1(unsigned char *, gethwaddr, int, a)
-_bsc1(char *, getbenv, char *, a)
-#endif
-
-
-void __init config_BSP(char *command, int len)
-{
-  unsigned char *p;
-
-  m360_cpm_reset();
-
-  /* Calculate the real system clock value. */
-  {
-     unsigned int local_pllcr = (unsigned int)(pquicc->sim_pllcr);
-     if( local_pllcr & MCU_PREEN ) // If the prescaler is dividing by 128
-     {
-         int mf = (int)(pquicc->sim_pllcr & 0x0fff);
-         system_clock = (OSCILLATOR / 128) * (mf + 1);
-     }
-     else
-     {
-         int mf = (int)(pquicc->sim_pllcr & 0x0fff);
-         system_clock = (OSCILLATOR) * (mf + 1);
-     }
-  }
-
-  printk(KERN_INFO "\n68360 QUICC support (C) 2000 Lineo Inc.\n");
-
-#if defined(CONFIG_UCQUICC) && 0
-  printk(KERN_INFO "uCquicc serial string [%s]\n",getserialnum());
-  p = scc1_hwaddr = gethwaddr(0);
-  printk(KERN_INFO "uCquicc hwaddr %.2x:%.2x:%.2x:%.2x:%.2x:%.2x\n",
-         p[0], p[1], p[2], p[3], p[4], p[5]);
-
-  p = getbenv("APPEND");
-  if (p)
-    strcpy(p,command);
-  else
-    command[0] = 0;
-#else
-  scc1_hwaddr = "\00\01\02\03\04\05";
-#endif
-  mach_reset = BSP_reset;
-}
diff --git a/arch/m68k/platform/68360/entry.S b/arch/m68k/platform/68360/entry.S
deleted file mode 100644 (file)
index 447c33e..0000000
+++ /dev/null
@@ -1,164 +0,0 @@
-/*
- *  linux/arch/m68knommu/platform/68360/entry.S
- *
- *  Copyright (C) 1991, 1992  Linus Torvalds
- *  Copyright (C) 2001 SED Systems, a Division of Calian Ltd.
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file README.legal in the main directory of this archive
- * for more details.
- *
- * Linux/m68k support by Hamish Macdonald
- * M68360 Port by SED Systems, and Lineo.
- */
-
-#include <linux/linkage.h>
-#include <asm/thread_info.h>
-#include <asm/unistd.h>
-#include <asm/errno.h>
-#include <asm/setup.h>
-#include <asm/segment.h>
-#include <asm/traps.h>
-#include <asm/asm-offsets.h>
-#include <asm/entry.h>
-
-.text
-
-.globl system_call
-.globl resume
-.globl ret_from_exception
-.globl ret_from_signal
-.globl sys_call_table
-.globl bad_interrupt
-.globl inthandler
-
-badsys:
-       movel   #-ENOSYS,%sp@(PT_OFF_D0)
-       jra     ret_from_exception
-
-do_trace:
-       movel   #-ENOSYS,%sp@(PT_OFF_D0) /* needed for strace*/
-       subql   #4,%sp
-       SAVE_SWITCH_STACK
-       jbsr    syscall_trace_enter
-       RESTORE_SWITCH_STACK
-       addql   #4,%sp
-       movel   %sp@(PT_OFF_ORIG_D0),%d1
-       movel   #-ENOSYS,%d0
-       cmpl    #NR_syscalls,%d1
-       jcc     1f
-       lsl     #2,%d1
-       lea     sys_call_table, %a0
-       jbsr    %a0@(%d1)
-
-1:     movel   %d0,%sp@(PT_OFF_D0)     /* save the return value */
-       subql   #4,%sp                  /* dummy return address */
-       SAVE_SWITCH_STACK
-       jbsr    syscall_trace_leave
-
-ret_from_signal:
-       RESTORE_SWITCH_STACK
-       addql   #4,%sp
-       jra     ret_from_exception
-
-ENTRY(system_call)
-       SAVE_ALL_SYS
-
-       /* save top of frame*/
-       pea     %sp@
-       jbsr    set_esp0
-       addql   #4,%sp
-
-       movel   %sp@(PT_OFF_ORIG_D0),%d0
-
-       movel   %sp,%d1                 /* get thread_info pointer */
-       andl    #-THREAD_SIZE,%d1
-       movel   %d1,%a2
-       btst    #(TIF_SYSCALL_TRACE%8),%a2@(TINFO_FLAGS+(31-TIF_SYSCALL_TRACE)/8)
-       jne     do_trace
-       cmpl    #NR_syscalls,%d0
-       jcc     badsys
-       lsl     #2,%d0
-       lea     sys_call_table,%a0
-       movel   %a0@(%d0), %a0
-       jbsr    %a0@
-       movel   %d0,%sp@(PT_OFF_D0)     /* save the return value*/
-
-ret_from_exception:
-       btst    #5,%sp@(PT_OFF_SR)      /* check if returning to kernel*/
-       jeq     Luser_return            /* if so, skip resched, signals*/
-
-Lkernel_return:
-       RESTORE_ALL
-
-Luser_return:
-       /* only allow interrupts when we are really the last one on the*/
-       /* kernel stack, otherwise stack overflow can occur during*/
-       /* heavy interrupt load*/
-       andw    #ALLOWINT,%sr
-
-       movel   %sp,%d1                 /* get thread_info pointer */
-       andl    #-THREAD_SIZE,%d1
-       movel   %d1,%a2
-1:
-       move    %a2@(TINFO_FLAGS),%d1   /* thread_info->flags */
-       jne     Lwork_to_do
-       RESTORE_ALL
-
-Lwork_to_do:
-       movel   %a2@(TINFO_FLAGS),%d1   /* thread_info->flags */
-       btst    #TIF_NEED_RESCHED,%d1
-       jne     reschedule
-
-Lsignal_return:
-       subql   #4,%sp                  /* dummy return address*/
-       SAVE_SWITCH_STACK
-       pea     %sp@(SWITCH_STACK_SIZE)
-       bsrw    do_notify_resume
-       addql   #4,%sp
-       RESTORE_SWITCH_STACK
-       addql   #4,%sp
-       jra     1b
-
-/*
- * This is the main interrupt handler, responsible for calling do_IRQ()
- */
-inthandler:
-       SAVE_ALL_INT
-       movew   %sp@(PT_OFF_FORMATVEC), %d0
-       and.l   #0x3ff, %d0
-       lsr.l   #0x02,  %d0
-
-       movel   %sp,%sp@-
-       movel   %d0,%sp@-               /*  put vector # on stack*/
-       jbsr    do_IRQ                  /*  process the IRQ */
-       addql   #8,%sp                  /*  pop parameters off stack*/
-       jra     ret_from_exception
-
-/*
- * Handler for uninitialized and spurious interrupts.
- */
-bad_interrupt:
-       addql   #1,irq_err_count
-       rte
-
-/*
- * Beware - when entering resume, prev (the current task) is
- * in a0, next (the new task) is in a1, so don't change these
- * registers until their contents are no longer needed.
- */
-ENTRY(resume)
-       movel   %a0,%d1                         /* save prev thread in d1 */
-       movew   %sr,%a0@(TASK_THREAD+THREAD_SR) /* save sr */
-       SAVE_SWITCH_STACK
-       movel   %sp,%a0@(TASK_THREAD+THREAD_KSP) /* save kernel stack */
-       movel   %usp,%a3                        /* save usp */
-       movel   %a3,%a0@(TASK_THREAD+THREAD_USP)
-
-       movel   %a1@(TASK_THREAD+THREAD_USP),%a3 /* restore user stack */
-       movel   %a3,%usp
-       movel   %a1@(TASK_THREAD+THREAD_KSP),%sp /* restore new thread stack */
-       RESTORE_SWITCH_STACK
-       movew   %a1@(TASK_THREAD+THREAD_SR),%sr /* restore thread status reg */
-       rts
-
diff --git a/arch/m68k/platform/68360/head-ram.S b/arch/m68k/platform/68360/head-ram.S
deleted file mode 100644 (file)
index acd2131..0000000
+++ /dev/null
@@ -1,403 +0,0 @@
-/* arch/m68knommu/platform/68360/head-ram.S
- *
- * Startup code for Motorola 68360
- *
- * Copyright 2001 (C) SED Systems, a Division of Calian Ltd.
- * Based on: arch/m68knommu/platform/68328/pilot/crt0_rom.S
- * Based on: arch/m68knommu/platform/68360/uCquicc/crt0_rom.S, 2.0.38.1.pre7
- *           uClinux Kernel
- * Copyright (C) Michael Leslie <mleslie@lineo.com>
- * Based on: arch/m68knommu/platform/68EZ328/ucsimm/crt0_rom.S
- * Copyright (C) 1998  D. Jeff Dionne <jeff@uclinux.org>,
- *
- */
-#define ASSEMBLY
-
-.global _stext
-.global _start
-
-.global _rambase
-.global _ramvec
-.global _ramstart
-.global _ramend
-
-.global _quicc_base
-.global _periph_base
-
-#define        RAMEND                      (CONFIG_RAMBASE + CONFIG_RAMSIZE)
-#define        ROMEND                      (CONFIG_ROMBASE + CONFIG_ROMSIZE)
-
-#define REGB                        0x1000
-#define PEPAR                       (_dprbase + REGB + 0x0016)
-#define GMR                         (_dprbase + REGB + 0x0040)
-#define OR0                         (_dprbase + REGB + 0x0054)
-#define BR0                         (_dprbase + REGB + 0x0050)
-#define OR1                         (_dprbase + REGB + 0x0064)
-#define BR1                         (_dprbase + REGB + 0x0060)
-#define OR4                         (_dprbase + REGB + 0x0094)
-#define BR4                         (_dprbase + REGB + 0x0090)
-#define OR6                         (_dprbase + REGB + 0x00b4)
-#define BR6                         (_dprbase + REGB + 0x00b0)
-#define OR7                         (_dprbase + REGB + 0x00c4)
-#define BR7                         (_dprbase + REGB + 0x00c0)
-
-#define MCR                         (_dprbase + REGB + 0x0000)
-#define AVR                         (_dprbase + REGB + 0x0008)
-
-#define SYPCR                       (_dprbase + REGB + 0x0022)
-
-#define PLLCR                       (_dprbase + REGB + 0x0010)
-#define CLKOCR                      (_dprbase + REGB + 0x000C)
-#define CDVCR                       (_dprbase + REGB + 0x0014)
-
-#define BKAR                        (_dprbase + REGB + 0x0030)
-#define BKCR                        (_dprbase + REGB + 0x0034)
-#define SWIV                        (_dprbase + REGB + 0x0023)
-#define PICR                        (_dprbase + REGB + 0x0026)
-#define PITR                        (_dprbase + REGB + 0x002A)
-
-/* Define for all memory configuration */
-#define MCU_SIM_GMR                 0x00000000
-#define SIM_OR_MASK                 0x0fffffff
-
-/* Defines for chip select zero - the flash */
-#define SIM_OR0_MASK                0x20000002
-#define SIM_BR0_MASK                0x00000001
-
-
-/* Defines for chip select one - the RAM */
-#define SIM_OR1_MASK                0x10000000
-#define SIM_BR1_MASK                0x00000001
-
-#define MCU_SIM_MBAR_ADRS           0x0003ff00
-#define MCU_SIM_MBAR_BA_MASK        0xfffff000
-#define MCU_SIM_MBAR_AS_MASK        0x00000001
-
-#define MCU_SIM_PEPAR               0x00B4
-    
-#define MCU_DISABLE_INTRPTS         0x2700
-#define MCU_SIM_AVR                 0x00
-    
-#define MCU_SIM_MCR                 0x00005cff
-
-#define MCU_SIM_CLKOCR              0x00
-#define MCU_SIM_PLLCR               0x8000
-#define MCU_SIM_CDVCR               0x0000
-
-#define MCU_SIM_SYPCR               0x0000
-#define MCU_SIM_SWIV                0x00
-#define MCU_SIM_PICR                0x0000
-#define MCU_SIM_PITR                0x0000
-
-
-#include <asm/m68360_regs.h>
-
-       
-/*
- * By the time this RAM specific code begins to execute, DPRAM
- * and DRAM should already be mapped and accessible.
- */
-
-       .text
-_start:
-_stext:
-       nop
-       ori.w   #MCU_DISABLE_INTRPTS, %sr       /* disable interrupts: */
-       /* We should not need to setup the boot stack the reset should do it. */
-       movea.l #RAMEND, %sp                    /*set up stack at the end of DRAM:*/
-
-set_mbar_register:
-       moveq.l #0x07, %d1                      /* Setup MBAR */
-       movec   %d1, %dfc
-
-       lea.l   MCU_SIM_MBAR_ADRS, %a0
-       move.l  #_dprbase, %d0
-       andi.l  #MCU_SIM_MBAR_BA_MASK, %d0
-       ori.l   #MCU_SIM_MBAR_AS_MASK, %d0
-       moves.l %d0, %a0@
-
-       moveq.l #0x05, %d1
-       movec.l %d1, %dfc
-
-       /* Now we can begin to access registers in DPRAM */
-
-set_sim_mcr:
-       /* Set Module Configuration Register */
-       move.l  #MCU_SIM_MCR, MCR
-
-       /* to do:       Determine cause of reset */
-
-       /*
-        *       configure system clock MC68360 p. 6-40
-        *       (value +1)*osc/128 = system clock
-        */
-set_sim_clock:
-       move.w  #MCU_SIM_PLLCR, PLLCR
-       move.b  #MCU_SIM_CLKOCR, CLKOCR
-       move.w  #MCU_SIM_CDVCR, CDVCR
-
-       /* Wait for the PLL to settle */
-       move.w  #16384, %d0
-pll_settle_wait:
-       subi.w  #1, %d0
-       bne     pll_settle_wait
-
-       /* Setup the system protection register, and watchdog timer register */
-       move.b  #MCU_SIM_SWIV, SWIV
-       move.w  #MCU_SIM_PICR, PICR
-       move.w  #MCU_SIM_PITR, PITR
-       move.w  #MCU_SIM_SYPCR, SYPCR
-
-       /* Clear DPRAM - system + parameter */
-       movea.l #_dprbase, %a0
-       movea.l #_dprbase+0x2000, %a1
-
-       /* Copy 0 to %a0 until %a0 == %a1 */
-clear_dpram:
-       movel   #0, %a0@+
-       cmpal   %a0, %a1
-       bhi     clear_dpram
-
-configure_memory_controller:    
-       /* Set up Global Memory Register (GMR) */
-       move.l  #MCU_SIM_GMR, %d0
-       move.l  %d0, GMR
-
-configure_chip_select_0:
-       move.l  #RAMEND, %d0
-       subi.l  #__ramstart, %d0
-       subq.l  #0x01, %d0
-       eori.l  #SIM_OR_MASK, %d0
-       ori.l   #SIM_OR0_MASK, %d0
-       move.l  %d0, OR0
-
-       move.l  #__ramstart, %d0
-       ori.l   #SIM_BR0_MASK, %d0
-       move.l  %d0, BR0
-
-configure_chip_select_1:
-       move.l  #ROMEND, %d0
-       subi.l  #__rom_start, %d0
-       subq.l  #0x01, %d0
-       eori.l  #SIM_OR_MASK, %d0
-       ori.l   #SIM_OR1_MASK, %d0
-       move.l  %d0, OR1
-
-       move.l  #__rom_start, %d0
-       ori.l   #SIM_BR1_MASK, %d0
-       move.l  %d0, BR1
-
-       move.w  #MCU_SIM_PEPAR, PEPAR 
-
-       /* point to vector table: */
-       move.l  #_romvec, %a0
-       move.l  #_ramvec, %a1
-copy_vectors:
-       move.l  %a0@, %d0
-       move.l  %d0, %a1@
-       move.l  %a0@, %a1@
-       addq.l  #0x04, %a0
-       addq.l  #0x04, %a1
-       cmp.l   #_start, %a0
-       blt     copy_vectors
-
-       move.l  #_ramvec, %a1
-       movec   %a1, %vbr
-
-
-       /* Copy data segment from ROM to RAM */
-       moveal  #_stext, %a0
-       moveal  #_sdata, %a1
-       moveal  #_edata, %a2
-
-       /* Copy %a0 to %a1 until %a1 == %a2 */
-LD1:
-       move.l  %a0@, %d0
-       addq.l  #0x04, %a0
-       move.l  %d0, %a1@
-       addq.l  #0x04, %a1
-       cmp.l   #_edata, %a1
-       blt     LD1
-
-       moveal  #__bss_start, %a0
-       moveal  #__bss_stop, %a1
-
-       /* Copy 0 to %a0 until %a0 == %a1 */
-L1:
-       movel   #0, %a0@+
-       cmpal   %a0, %a1
-       bhi     L1
-
-load_quicc:
-       move.l  #_dprbase, _quicc_base
-
-store_ram_size:
-       /* Set ram size information */
-       move.l  #_sdata, _rambase
-       move.l  #__bss_stop, _ramstart
-       move.l  #RAMEND, %d0
-       sub.l   #0x1000, %d0                    /* Reserve 4K for stack space.*/
-       move.l  %d0, _ramend                    /* Different from RAMEND.*/
-
-       pea     0
-       pea     env
-       pea     %sp@(4)
-       pea     0
-
-       lea     init_thread_union, %a2
-       lea     0x2000(%a2), %sp
-
-lp:
-       jsr     start_kernel
-
-_exit:
-       jmp     _exit
-
-
-       .data
-       .align 4
-env:
-       .long   0
-_quicc_base:
-       .long   0
-_periph_base:
-       .long   0
-_ramvec:
-       .long   0
-_rambase:
-       .long   0
-_ramstart:
-       .long   0
-_ramend:
-       .long   0
-_dprbase:
-       .long   0xffffe000
-
-       .text
-
-    /*
-     * These are the exception vectors at boot up, they are copied into RAM
-     * and then overwritten as needed.
-     */
-.section ".data..initvect","awx"
-    .long   RAMEND     /* Reset: Initial Stack Pointer                 - 0.  */
-    .long   _start      /* Reset: Initial Program Counter               - 1.  */
-    .long   buserr      /* Bus Error                                    - 2.  */
-    .long   trap        /* Address Error                                - 3.  */
-    .long   trap        /* Illegal Instruction                          - 4.  */
-    .long   trap        /* Divide by zero                               - 5.  */
-    .long   trap        /* CHK, CHK2 Instructions                       - 6.  */
-    .long   trap        /* TRAPcc, TRAPV Instructions                   - 7.  */
-    .long   trap        /* Privilege Violation                          - 8.  */
-    .long   trap        /* Trace                                        - 9.  */
-    .long   trap        /* Line 1010 Emulator                           - 10. */
-    .long   trap        /* Line 1111 Emualtor                           - 11. */
-    .long   trap        /* Harware Breakpoint                           - 12. */
-    .long   trap        /* (Reserved for Coprocessor Protocol Violation)- 13. */
-    .long   trap        /* Format Error                                 - 14. */
-    .long   trap        /* Uninitialized Interrupt                      - 15. */
-    .long   trap        /* (Unassigned, Reserver)                       - 16. */
-    .long   trap        /* (Unassigned, Reserver)                       - 17. */
-    .long   trap        /* (Unassigned, Reserver)                       - 18. */
-    .long   trap        /* (Unassigned, Reserver)                       - 19. */
-    .long   trap        /* (Unassigned, Reserver)                       - 20. */
-    .long   trap        /* (Unassigned, Reserver)                       - 21. */
-    .long   trap        /* (Unassigned, Reserver)                       - 22. */
-    .long   trap        /* (Unassigned, Reserver)                       - 23. */
-    .long   trap        /* Spurious Interrupt                           - 24. */
-    .long   trap        /* Level 1 Interrupt Autovector                 - 25. */
-    .long   trap        /* Level 2 Interrupt Autovector                 - 26. */
-    .long   trap        /* Level 3 Interrupt Autovector                 - 27. */
-    .long   trap        /* Level 4 Interrupt Autovector                 - 28. */
-    .long   trap        /* Level 5 Interrupt Autovector                 - 29. */
-    .long   trap        /* Level 6 Interrupt Autovector                 - 30. */
-    .long   trap        /* Level 7 Interrupt Autovector                 - 31. */
-    .long   system_call /* Trap Instruction Vectors 0                   - 32. */
-    .long   trap        /* Trap Instruction Vectors 1                   - 33. */
-    .long   trap        /* Trap Instruction Vectors 2                   - 34. */
-    .long   trap        /* Trap Instruction Vectors 3                   - 35. */
-    .long   trap        /* Trap Instruction Vectors 4                   - 36. */
-    .long   trap        /* Trap Instruction Vectors 5                   - 37. */
-    .long   trap        /* Trap Instruction Vectors 6                   - 38. */
-    .long   trap        /* Trap Instruction Vectors 7                   - 39. */
-    .long   trap        /* Trap Instruction Vectors 8                   - 40. */
-    .long   trap        /* Trap Instruction Vectors 9                   - 41. */
-    .long   trap        /* Trap Instruction Vectors 10                  - 42. */
-    .long   trap        /* Trap Instruction Vectors 11                  - 43. */
-    .long   trap        /* Trap Instruction Vectors 12                  - 44. */
-    .long   trap        /* Trap Instruction Vectors 13                  - 45. */
-    .long   trap        /* Trap Instruction Vectors 14                  - 46. */
-    .long   trap        /* Trap Instruction Vectors 15                  - 47. */
-    .long   0           /* (Reserved for Coprocessor)                   - 48. */
-    .long   0           /* (Reserved for Coprocessor)                   - 49. */
-    .long   0           /* (Reserved for Coprocessor)                   - 50. */
-    .long   0           /* (Reserved for Coprocessor)                   - 51. */
-    .long   0           /* (Reserved for Coprocessor)                   - 52. */
-    .long   0           /* (Reserved for Coprocessor)                   - 53. */
-    .long   0           /* (Reserved for Coprocessor)                   - 54. */
-    .long   0           /* (Reserved for Coprocessor)                   - 55. */
-    .long   0           /* (Reserved for Coprocessor)                   - 56. */
-    .long   0           /* (Reserved for Coprocessor)                   - 57. */
-    .long   0           /* (Reserved for Coprocessor)                   - 58. */
-    .long   0           /* (Unassigned, Reserved)                       - 59. */
-    .long   0           /* (Unassigned, Reserved)                       - 60. */
-    .long   0           /* (Unassigned, Reserved)                       - 61. */
-    .long   0           /* (Unassigned, Reserved)                       - 62. */
-    .long   0           /* (Unassigned, Reserved)                       - 63. */
-    /*                  The assignment of these vectors to the CPM is         */
-    /*                  dependent on the configuration of the CPM vba         */
-    /*                          fields.                                       */
-    .long   0           /* (User-Defined Vectors 1) CPM Error           - 64. */
-    .long   0           /* (User-Defined Vectors 2) CPM Parallel IO PC11- 65. */
-    .long   0           /* (User-Defined Vectors 3) CPM Parallel IO PC10- 66. */
-    .long   0           /* (User-Defined Vectors 4) CPM SMC2 / PIP      - 67. */
-    .long   0           /* (User-Defined Vectors 5) CPM SMC1            - 68. */
-    .long   0           /* (User-Defined Vectors 6) CPM SPI             - 69. */
-    .long   0           /* (User-Defined Vectors 7) CPM Parallel IO PC9 - 70. */
-    .long   0           /* (User-Defined Vectors 8) CPM Timer 4         - 71. */
-    .long   0           /* (User-Defined Vectors 9) CPM Reserved        - 72. */
-    .long   0           /* (User-Defined Vectors 10) CPM Parallel IO PC8- 73. */
-    .long   0           /* (User-Defined Vectors 11) CPM Parallel IO PC7- 74. */
-    .long   0           /* (User-Defined Vectors 12) CPM Parallel IO PC6- 75. */
-    .long   0           /* (User-Defined Vectors 13) CPM Timer 3        - 76. */
-    .long   0           /* (User-Defined Vectors 14) CPM Reserved       - 77. */
-    .long   0           /* (User-Defined Vectors 15) CPM Parallel IO PC5- 78. */
-    .long   0           /* (User-Defined Vectors 16) CPM Parallel IO PC4- 79. */
-    .long   0           /* (User-Defined Vectors 17) CPM Reserved       - 80. */
-    .long   0           /* (User-Defined Vectors 18) CPM RISC Timer Tbl - 81. */
-    .long   0           /* (User-Defined Vectors 19) CPM Timer 2        - 82. */
-    .long   0           /* (User-Defined Vectors 21) CPM Reserved       - 83. */
-    .long   0           /* (User-Defined Vectors 22) CPM IDMA2          - 84. */
-    .long   0           /* (User-Defined Vectors 23) CPM IDMA1          - 85. */
-    .long   0           /* (User-Defined Vectors 24) CPM SDMA Bus Err   - 86. */
-    .long   0           /* (User-Defined Vectors 25) CPM Parallel IO PC3- 87. */
-    .long   0           /* (User-Defined Vectors 26) CPM Parallel IO PC2- 88. */
-    .long   0           /* (User-Defined Vectors 27) CPM Timer 1        - 89. */
-    .long   0           /* (User-Defined Vectors 28) CPM Parallel IO PC1- 90. */
-    .long   0           /* (User-Defined Vectors 29) CPM SCC 4          - 91. */
-    .long   0           /* (User-Defined Vectors 30) CPM SCC 3          - 92. */
-    .long   0           /* (User-Defined Vectors 31) CPM SCC 2          - 93. */
-    .long   0           /* (User-Defined Vectors 32) CPM SCC 1          - 94. */
-    .long   0           /* (User-Defined Vectors 33) CPM Parallel IO PC0- 95. */
-    /*                  I don't think anything uses the vectors after here.   */
-    .long   0           /* (User-Defined Vectors 34)                    - 96. */
-    .long   0,0,0,0,0               /* (User-Defined Vectors 35  -  39). */
-    .long   0,0,0,0,0,0,0,0,0,0     /* (User-Defined Vectors 40  -  49). */
-    .long   0,0,0,0,0,0,0,0,0,0     /* (User-Defined Vectors 50  -  59). */
-    .long   0,0,0,0,0,0,0,0,0,0     /* (User-Defined Vectors 60  -  69). */
-    .long   0,0,0,0,0,0,0,0,0,0     /* (User-Defined Vectors 70  -  79). */
-    .long   0,0,0,0,0,0,0,0,0,0     /* (User-Defined Vectors 80  -  89). */
-    .long   0,0,0,0,0,0,0,0,0,0     /* (User-Defined Vectors 90  -  99). */
-    .long   0,0,0,0,0,0,0,0,0,0     /* (User-Defined Vectors 100 - 109). */
-    .long   0,0,0,0,0,0,0,0,0,0     /* (User-Defined Vectors 110 - 119). */
-    .long   0,0,0,0,0,0,0,0,0,0     /* (User-Defined Vectors 120 - 129). */
-    .long   0,0,0,0,0,0,0,0,0,0     /* (User-Defined Vectors 130 - 139). */
-    .long   0,0,0,0,0,0,0,0,0,0     /* (User-Defined Vectors 140 - 149). */
-    .long   0,0,0,0,0,0,0,0,0,0     /* (User-Defined Vectors 150 - 159). */
-    .long   0,0,0,0,0,0,0,0,0,0     /* (User-Defined Vectors 160 - 169). */
-    .long   0,0,0,0,0,0,0,0,0,0     /* (User-Defined Vectors 170 - 179). */
-    .long   0,0,0,0,0,0,0,0,0,0     /* (User-Defined Vectors 180 - 189). */
-    .long   0,0,0                   /* (User-Defined Vectors 190 - 192). */
-.text
-ignore: rte
diff --git a/arch/m68k/platform/68360/head-rom.S b/arch/m68k/platform/68360/head-rom.S
deleted file mode 100644 (file)
index dfc756d..0000000
+++ /dev/null
@@ -1,414 +0,0 @@
-/* arch/m68knommu/platform/68360/head-rom.S
- *
- * Startup code for Motorola 68360
- *
- * Copyright (C) SED Systems, a Division of Calian Ltd.
- * Based on: arch/m68knommu/platform/68328/pilot/crt0_rom.S
- * Based on: arch/m68knommu/platform/68360/uCquicc/crt0_rom.S, 2.0.38.1.pre7
- *           uClinux Kernel
- * Copyright (C) Michael Leslie <mleslie@lineo.com>
- * Based on: arch/m68knommu/platform/68EZ328/ucsimm/crt0_rom.S
- * Copyright (C) 1998  D. Jeff Dionne <jeff@uclinux.org>,
- *
- */
-
-.global _stext
-.global __bss_start
-.global _start
-
-.global _rambase
-.global _ramvec
-.global _ramstart
-.global _ramend
-
-.global _quicc_base
-.global _periph_base
-
-#define        RAMEND                      (CONFIG_RAMBASE + CONFIG_RAMSIZE)
-
-#define REGB                        0x1000
-#define PEPAR                       (_dprbase + REGB + 0x0016)
-#define GMR                         (_dprbase + REGB + 0x0040)
-#define OR0                         (_dprbase + REGB + 0x0054)
-#define BR0                         (_dprbase + REGB + 0x0050)
-
-#define OR1                         (_dprbase + REGB + 0x0064)
-#define BR1                         (_dprbase + REGB + 0x0060)
-
-#define OR2                         (_dprbase + REGB + 0x0074)
-#define BR2                         (_dprbase + REGB + 0x0070)
-
-#define OR3                         (_dprbase + REGB + 0x0084)
-#define BR3                         (_dprbase + REGB + 0x0080)
-
-#define OR4                         (_dprbase + REGB + 0x0094)
-#define BR4                         (_dprbase + REGB + 0x0090)
-
-#define OR5                         (_dprbase + REGB + 0x00A4)
-#define BR5                         (_dprbase + REGB + 0x00A0)
-
-#define OR6                         (_dprbase + REGB + 0x00b4)
-#define BR6                         (_dprbase + REGB + 0x00b0)
-
-#define OR7                         (_dprbase + REGB + 0x00c4)
-#define BR7                         (_dprbase + REGB + 0x00c0)
-
-#define MCR                         (_dprbase + REGB + 0x0000)
-#define AVR                         (_dprbase + REGB + 0x0008)
-
-#define SYPCR                       (_dprbase + REGB + 0x0022)
-
-#define PLLCR                       (_dprbase + REGB + 0x0010)
-#define CLKOCR                      (_dprbase + REGB + 0x000C)
-#define CDVCR                       (_dprbase + REGB + 0x0014)
-
-#define BKAR                        (_dprbase + REGB + 0x0030)
-#define BKCR                        (_dprbase + REGB + 0x0034)
-#define SWIV                        (_dprbase + REGB + 0x0023)
-#define PICR                        (_dprbase + REGB + 0x0026)
-#define PITR                        (_dprbase + REGB + 0x002A)
-
-/* Define for all memory configuration */
-#define MCU_SIM_GMR                 0x00000000
-#define SIM_OR_MASK                 0x0fffffff
-
-/* Defines for chip select zero - the flash */
-#define SIM_OR0_MASK                0x20000000
-#define SIM_BR0_MASK                0x00000001
-
-/* Defines for chip select one - the RAM */
-#define SIM_OR1_MASK                0x10000000
-#define SIM_BR1_MASK                0x00000001
-
-#define MCU_SIM_MBAR_ADRS           0x0003ff00
-#define MCU_SIM_MBAR_BA_MASK        0xfffff000
-#define MCU_SIM_MBAR_AS_MASK        0x00000001
-
-#define MCU_SIM_PEPAR               0x00B4
-    
-#define MCU_DISABLE_INTRPTS         0x2700
-#define MCU_SIM_AVR                 0x00
-    
-#define MCU_SIM_MCR                 0x00005cff
-
-#define MCU_SIM_CLKOCR              0x00
-#define MCU_SIM_PLLCR               0x8000
-#define MCU_SIM_CDVCR               0x0000
-
-#define MCU_SIM_SYPCR               0x0000
-#define MCU_SIM_SWIV                0x00
-#define MCU_SIM_PICR                0x0000
-#define MCU_SIM_PITR                0x0000
-
-
-#include <asm/m68360_regs.h>
-
-       
-/*
- * By the time this RAM specific code begins to execute, DPRAM
- * and DRAM should already be mapped and accessible.
- */
-
-       .text
-_start:
-_stext:
-       nop
-       ori.w   #MCU_DISABLE_INTRPTS, %sr       /* disable interrupts: */
-       /* We should not need to setup the boot stack the reset should do it. */
-       movea.l #RAMEND, %sp            /* set up stack at the end of DRAM:*/
-
-
-set_mbar_register:
-       moveq.l #0x07, %d1                      /* Setup MBAR */
-       movec   %d1, %dfc
-
-       lea.l   MCU_SIM_MBAR_ADRS, %a0
-       move.l  #_dprbase, %d0
-       andi.l  #MCU_SIM_MBAR_BA_MASK, %d0
-       ori.l   #MCU_SIM_MBAR_AS_MASK, %d0
-       moves.l %d0, %a0@
-
-       moveq.l #0x05, %d1
-       movec.l %d1, %dfc
-
-       /* Now we can begin to access registers in DPRAM */
-
-set_sim_mcr:
-       /* Set Module Configuration Register */
-       move.l  #MCU_SIM_MCR, MCR
-
-       /* to do:       Determine cause of reset */
-
-       /*
-        *      configure system clock MC68360 p. 6-40
-        *      (value +1)*osc/128 = system clock
-        *                    or
-        *      (value + 1)*osc = system clock
-        *      You do not need to divide the oscillator by 128 unless you want to.
-        */
-set_sim_clock:
-       move.w  #MCU_SIM_PLLCR, PLLCR
-       move.b  #MCU_SIM_CLKOCR, CLKOCR
-       move.w  #MCU_SIM_CDVCR, CDVCR
-
-       /* Wait for the PLL to settle */
-       move.w  #16384, %d0
-pll_settle_wait:
-       subi.w  #1, %d0
-       bne     pll_settle_wait
-
-       /* Setup the system protection register, and watchdog timer register */
-       move.b  #MCU_SIM_SWIV, SWIV
-       move.w  #MCU_SIM_PICR, PICR
-       move.w  #MCU_SIM_PITR, PITR
-       move.w  #MCU_SIM_SYPCR, SYPCR
-
-       /* Clear DPRAM - system + parameter */
-       movea.l #_dprbase, %a0
-       movea.l #_dprbase+0x2000, %a1
-
-       /* Copy 0 to %a0 until %a0 == %a1 */
-clear_dpram:
-       movel   #0, %a0@+
-       cmpal   %a0, %a1
-       bhi     clear_dpram
-
-configure_memory_controller:    
-       /* Set up Global Memory Register (GMR) */
-       move.l  #MCU_SIM_GMR, %d0
-       move.l  %d0, GMR
-
-configure_chip_select_0:
-       move.l  #0x00400000, %d0
-       subq.l  #0x01, %d0
-       eori.l  #SIM_OR_MASK, %d0
-       ori.l   #SIM_OR0_MASK, %d0
-       move.l  %d0, OR0
-
-       move.l  #__rom_start, %d0
-       ori.l   #SIM_BR0_MASK, %d0
-       move.l  %d0, BR0
-
-       move.l  #0x0, BR1
-       move.l  #0x0, BR2
-       move.l  #0x0, BR3
-       move.l  #0x0, BR4
-       move.l  #0x0, BR5
-       move.l  #0x0, BR6
-       move.l  #0x0, BR7
-
-       move.w  #MCU_SIM_PEPAR, PEPAR 
-
-       /* point to vector table: */
-       move.l  #_romvec, %a0
-       move.l  #_ramvec, %a1
-copy_vectors:
-       move.l  %a0@, %d0
-       move.l  %d0, %a1@
-       move.l  %a0@, %a1@
-       addq.l  #0x04, %a0
-       addq.l  #0x04, %a1
-       cmp.l   #_start, %a0
-       blt     copy_vectors
-
-       move.l  #_ramvec, %a1
-       movec   %a1, %vbr
-
-
-       /* Copy data segment from ROM to RAM */
-       moveal  #_etext, %a0
-       moveal  #_sdata, %a1
-       moveal  #_edata, %a2
-
-       /* Copy %a0 to %a1 until %a1 == %a2 */
-LD1:
-       move.l  %a0@, %d0
-       addq.l  #0x04, %a0
-       move.l  %d0, %a1@
-       addq.l  #0x04, %a1
-       cmp.l   #_edata, %a1
-       blt     LD1
-
-       moveal  #__bss_start, %a0
-       moveal  #__bss_stop, %a1
-
-       /* Copy 0 to %a0 until %a0 == %a1 */
-L1:
-       movel   #0, %a0@+
-       cmpal   %a0, %a1
-       bhi     L1
-
-load_quicc:
-       move.l  #_dprbase, _quicc_base
-
-store_ram_size:
-       /* Set ram size information */
-       move.l  #_sdata, _rambase
-       move.l  #__bss_stop, _ramstart
-       move.l  #RAMEND, %d0
-       sub.l   #0x1000, %d0                    /* Reserve 4K for stack space.*/
-       move.l  %d0, _ramend                    /* Different from RAMEND.*/
-
-       pea     0
-       pea     env
-       pea     %sp@(4)
-       pea     0
-
-       lea     init_thread_union, %a2
-       lea     0x2000(%a2), %sp
-
-lp:
-       jsr     start_kernel
-
-_exit:
-       jmp     _exit
-
-
-       .data
-       .align 4
-env:
-       .long   0
-_quicc_base:
-       .long   0
-_periph_base:
-       .long   0
-_ramvec:
-       .long   0
-_rambase:
-       .long   0
-_ramstart:
-       .long   0
-_ramend:
-       .long   0
-_dprbase:
-       .long   0xffffe000
-
-
-       .text
-
-    /*
-     * These are the exception vectors at boot up, they are copied into RAM
-     * and then overwritten as needed.
-     */
-.section ".data..initvect","awx"
-    .long   RAMEND     /* Reset: Initial Stack Pointer                 - 0.  */
-    .long   _start      /* Reset: Initial Program Counter               - 1.  */
-    .long   buserr      /* Bus Error                                    - 2.  */
-    .long   trap        /* Address Error                                - 3.  */
-    .long   trap        /* Illegal Instruction                          - 4.  */
-    .long   trap        /* Divide by zero                               - 5.  */
-    .long   trap        /* CHK, CHK2 Instructions                       - 6.  */
-    .long   trap        /* TRAPcc, TRAPV Instructions                   - 7.  */
-    .long   trap        /* Privilege Violation                          - 8.  */
-    .long   trap        /* Trace                                        - 9.  */
-    .long   trap        /* Line 1010 Emulator                           - 10. */
-    .long   trap        /* Line 1111 Emualtor                           - 11. */
-    .long   trap        /* Harware Breakpoint                           - 12. */
-    .long   trap        /* (Reserved for Coprocessor Protocol Violation)- 13. */
-    .long   trap        /* Format Error                                 - 14. */
-    .long   trap        /* Uninitialized Interrupt                      - 15. */
-    .long   trap        /* (Unassigned, Reserver)                       - 16. */
-    .long   trap        /* (Unassigned, Reserver)                       - 17. */
-    .long   trap        /* (Unassigned, Reserver)                       - 18. */
-    .long   trap        /* (Unassigned, Reserver)                       - 19. */
-    .long   trap        /* (Unassigned, Reserver)                       - 20. */
-    .long   trap        /* (Unassigned, Reserver)                       - 21. */
-    .long   trap        /* (Unassigned, Reserver)                       - 22. */
-    .long   trap        /* (Unassigned, Reserver)                       - 23. */
-    .long   trap        /* Spurious Interrupt                           - 24. */
-    .long   trap        /* Level 1 Interrupt Autovector                 - 25. */
-    .long   trap        /* Level 2 Interrupt Autovector                 - 26. */
-    .long   trap        /* Level 3 Interrupt Autovector                 - 27. */
-    .long   trap        /* Level 4 Interrupt Autovector                 - 28. */
-    .long   trap        /* Level 5 Interrupt Autovector                 - 29. */
-    .long   trap        /* Level 6 Interrupt Autovector                 - 30. */
-    .long   trap        /* Level 7 Interrupt Autovector                 - 31. */
-    .long   system_call /* Trap Instruction Vectors 0                   - 32. */
-    .long   trap        /* Trap Instruction Vectors 1                   - 33. */
-    .long   trap        /* Trap Instruction Vectors 2                   - 34. */
-    .long   trap        /* Trap Instruction Vectors 3                   - 35. */
-    .long   trap        /* Trap Instruction Vectors 4                   - 36. */
-    .long   trap        /* Trap Instruction Vectors 5                   - 37. */
-    .long   trap        /* Trap Instruction Vectors 6                   - 38. */
-    .long   trap        /* Trap Instruction Vectors 7                   - 39. */
-    .long   trap        /* Trap Instruction Vectors 8                   - 40. */
-    .long   trap        /* Trap Instruction Vectors 9                   - 41. */
-    .long   trap        /* Trap Instruction Vectors 10                  - 42. */
-    .long   trap        /* Trap Instruction Vectors 11                  - 43. */
-    .long   trap        /* Trap Instruction Vectors 12                  - 44. */
-    .long   trap        /* Trap Instruction Vectors 13                  - 45. */
-    .long   trap        /* Trap Instruction Vectors 14                  - 46. */
-    .long   trap        /* Trap Instruction Vectors 15                  - 47. */
-    .long   0           /* (Reserved for Coprocessor)                   - 48. */
-    .long   0           /* (Reserved for Coprocessor)                   - 49. */
-    .long   0           /* (Reserved for Coprocessor)                   - 50. */
-    .long   0           /* (Reserved for Coprocessor)                   - 51. */
-    .long   0           /* (Reserved for Coprocessor)                   - 52. */
-    .long   0           /* (Reserved for Coprocessor)                   - 53. */
-    .long   0           /* (Reserved for Coprocessor)                   - 54. */
-    .long   0           /* (Reserved for Coprocessor)                   - 55. */
-    .long   0           /* (Reserved for Coprocessor)                   - 56. */
-    .long   0           /* (Reserved for Coprocessor)                   - 57. */
-    .long   0           /* (Reserved for Coprocessor)                   - 58. */
-    .long   0           /* (Unassigned, Reserved)                       - 59. */
-    .long   0           /* (Unassigned, Reserved)                       - 60. */
-    .long   0           /* (Unassigned, Reserved)                       - 61. */
-    .long   0           /* (Unassigned, Reserved)                       - 62. */
-    .long   0           /* (Unassigned, Reserved)                       - 63. */
-    /*                  The assignment of these vectors to the CPM is         */
-    /*                  dependent on the configuration of the CPM vba         */
-    /*                          fields.                                       */
-    .long   0           /* (User-Defined Vectors 1) CPM Error           - 64. */
-    .long   0           /* (User-Defined Vectors 2) CPM Parallel IO PC11- 65. */
-    .long   0           /* (User-Defined Vectors 3) CPM Parallel IO PC10- 66. */
-    .long   0           /* (User-Defined Vectors 4) CPM SMC2 / PIP      - 67. */
-    .long   0           /* (User-Defined Vectors 5) CPM SMC1            - 68. */
-    .long   0           /* (User-Defined Vectors 6) CPM SPI             - 69. */
-    .long   0           /* (User-Defined Vectors 7) CPM Parallel IO PC9 - 70. */
-    .long   0           /* (User-Defined Vectors 8) CPM Timer 4         - 71. */
-    .long   0           /* (User-Defined Vectors 9) CPM Reserved        - 72. */
-    .long   0           /* (User-Defined Vectors 10) CPM Parallel IO PC8- 73. */
-    .long   0           /* (User-Defined Vectors 11) CPM Parallel IO PC7- 74. */
-    .long   0           /* (User-Defined Vectors 12) CPM Parallel IO PC6- 75. */
-    .long   0           /* (User-Defined Vectors 13) CPM Timer 3        - 76. */
-    .long   0           /* (User-Defined Vectors 14) CPM Reserved       - 77. */
-    .long   0           /* (User-Defined Vectors 15) CPM Parallel IO PC5- 78. */
-    .long   0           /* (User-Defined Vectors 16) CPM Parallel IO PC4- 79. */
-    .long   0           /* (User-Defined Vectors 17) CPM Reserved       - 80. */
-    .long   0           /* (User-Defined Vectors 18) CPM RISC Timer Tbl - 81. */
-    .long   0           /* (User-Defined Vectors 19) CPM Timer 2        - 82. */
-    .long   0           /* (User-Defined Vectors 21) CPM Reserved       - 83. */
-    .long   0           /* (User-Defined Vectors 22) CPM IDMA2          - 84. */
-    .long   0           /* (User-Defined Vectors 23) CPM IDMA1          - 85. */
-    .long   0           /* (User-Defined Vectors 24) CPM SDMA Bus Err   - 86. */
-    .long   0           /* (User-Defined Vectors 25) CPM Parallel IO PC3- 87. */
-    .long   0           /* (User-Defined Vectors 26) CPM Parallel IO PC2- 88. */
-    .long   0           /* (User-Defined Vectors 27) CPM Timer 1        - 89. */
-    .long   0           /* (User-Defined Vectors 28) CPM Parallel IO PC1- 90. */
-    .long   0           /* (User-Defined Vectors 29) CPM SCC 4          - 91. */
-    .long   0           /* (User-Defined Vectors 30) CPM SCC 3          - 92. */
-    .long   0           /* (User-Defined Vectors 31) CPM SCC 2          - 93. */
-    .long   0           /* (User-Defined Vectors 32) CPM SCC 1          - 94. */
-    .long   0           /* (User-Defined Vectors 33) CPM Parallel IO PC0- 95. */
-    /*                  I don't think anything uses the vectors after here.   */
-    .long   0           /* (User-Defined Vectors 34)                    - 96. */
-    .long   0,0,0,0,0               /* (User-Defined Vectors 35  -  39). */
-    .long   0,0,0,0,0,0,0,0,0,0     /* (User-Defined Vectors 40  -  49). */
-    .long   0,0,0,0,0,0,0,0,0,0     /* (User-Defined Vectors 50  -  59). */
-    .long   0,0,0,0,0,0,0,0,0,0     /* (User-Defined Vectors 60  -  69). */
-    .long   0,0,0,0,0,0,0,0,0,0     /* (User-Defined Vectors 70  -  79). */
-    .long   0,0,0,0,0,0,0,0,0,0     /* (User-Defined Vectors 80  -  89). */
-    .long   0,0,0,0,0,0,0,0,0,0     /* (User-Defined Vectors 90  -  99). */
-    .long   0,0,0,0,0,0,0,0,0,0     /* (User-Defined Vectors 100 - 109). */
-    .long   0,0,0,0,0,0,0,0,0,0     /* (User-Defined Vectors 110 - 119). */
-    .long   0,0,0,0,0,0,0,0,0,0     /* (User-Defined Vectors 120 - 129). */
-    .long   0,0,0,0,0,0,0,0,0,0     /* (User-Defined Vectors 130 - 139). */
-    .long   0,0,0,0,0,0,0,0,0,0     /* (User-Defined Vectors 140 - 149). */
-    .long   0,0,0,0,0,0,0,0,0,0     /* (User-Defined Vectors 150 - 159). */
-    .long   0,0,0,0,0,0,0,0,0,0     /* (User-Defined Vectors 160 - 169). */
-    .long   0,0,0,0,0,0,0,0,0,0     /* (User-Defined Vectors 170 - 179). */
-    .long   0,0,0,0,0,0,0,0,0,0     /* (User-Defined Vectors 180 - 189). */
-    .long   0,0,0                   /* (User-Defined Vectors 190 - 192). */
-.text
-ignore: rte
diff --git a/arch/m68k/platform/68360/ints.c b/arch/m68k/platform/68360/ints.c
deleted file mode 100644 (file)
index 8cd4269..0000000
+++ /dev/null
@@ -1,138 +0,0 @@
-/*
- * linux/arch/$(ARCH)/platform/$(PLATFORM)/ints.c
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file COPYING in the main directory of this archive
- * for more details.
- *
- * Copyright (c) 2000  Michael Leslie <mleslie@lineo.com>
- * Copyright (c) 1996 Roman Zippel
- * Copyright (c) 1999 D. Jeff Dionne <jeff@uclinux.org>
- */
-
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/irq.h>
-#include <asm/traps.h>
-#include <asm/machdep.h>
-#include <asm/m68360.h>
-
-/* from quicc/commproc.c: */
-extern QUICC *pquicc;
-extern void cpm_interrupt_init(void);
-
-#define INTERNAL_IRQS (96)
-
-/* assembler routines */
-asmlinkage void system_call(void);
-asmlinkage void buserr(void);
-asmlinkage void trap(void);
-asmlinkage void bad_interrupt(void);
-asmlinkage void inthandler(void);
-
-static void intc_irq_unmask(struct irq_data *d)
-{
-       pquicc->intr_cimr |= (1 << d->irq);
-}
-
-static void intc_irq_mask(struct irq_data *d)
-{
-       pquicc->intr_cimr &= ~(1 << d->irq);
-}
-
-static void intc_irq_ack(struct irq_data *d)
-{
-       pquicc->intr_cisr = (1 << d->irq);
-}
-
-static struct irq_chip intc_irq_chip = {
-       .name           = "M68K-INTC",
-       .irq_mask       = intc_irq_mask,
-       .irq_unmask     = intc_irq_unmask,
-       .irq_ack        = intc_irq_ack,
-};
-
-/*
- * This function should be called during kernel startup to initialize
- * the vector table.
- */
-void __init trap_init(void)
-{
-       int vba = (CPM_VECTOR_BASE<<4);
-
-       /* set up the vectors */
-       _ramvec[2] = buserr;
-       _ramvec[3] = trap;
-       _ramvec[4] = trap;
-       _ramvec[5] = trap;
-       _ramvec[6] = trap;
-       _ramvec[7] = trap;
-       _ramvec[8] = trap;
-       _ramvec[9] = trap;
-       _ramvec[10] = trap;
-       _ramvec[11] = trap;
-       _ramvec[12] = trap;
-       _ramvec[13] = trap;
-       _ramvec[14] = trap;
-       _ramvec[15] = trap;
-
-       _ramvec[32] = system_call;
-       _ramvec[33] = trap;
-
-       cpm_interrupt_init();
-
-       /* set up CICR for vector base address and irq level */
-       /* irl = 4, hp = 1f - see MC68360UM p 7-377 */
-       pquicc->intr_cicr = 0x00e49f00 | vba;
-
-       /* CPM interrupt vectors: (p 7-376) */
-       _ramvec[vba+CPMVEC_ERROR]       = bad_interrupt; /* Error */
-       _ramvec[vba+CPMVEC_PIO_PC11]    = inthandler;   /* pio - pc11 */
-       _ramvec[vba+CPMVEC_PIO_PC10]    = inthandler;   /* pio - pc10 */
-       _ramvec[vba+CPMVEC_SMC2]        = inthandler;   /* smc2/pip */
-       _ramvec[vba+CPMVEC_SMC1]        = inthandler;   /* smc1 */
-       _ramvec[vba+CPMVEC_SPI]         = inthandler;   /* spi */
-       _ramvec[vba+CPMVEC_PIO_PC9]     = inthandler;   /* pio - pc9 */
-       _ramvec[vba+CPMVEC_TIMER4]      = inthandler;   /* timer 4 */
-       _ramvec[vba+CPMVEC_RESERVED1]   = inthandler;   /* reserved */
-       _ramvec[vba+CPMVEC_PIO_PC8]     = inthandler;   /* pio - pc8 */
-       _ramvec[vba+CPMVEC_PIO_PC7]     = inthandler;  /* pio - pc7 */
-       _ramvec[vba+CPMVEC_PIO_PC6]     = inthandler;  /* pio - pc6 */
-       _ramvec[vba+CPMVEC_TIMER3]      = inthandler;  /* timer 3 */
-       _ramvec[vba+CPMVEC_PIO_PC5]     = inthandler;  /* pio - pc5 */
-       _ramvec[vba+CPMVEC_PIO_PC4]     = inthandler;  /* pio - pc4 */
-       _ramvec[vba+CPMVEC_RESERVED2]   = inthandler;  /* reserved */
-       _ramvec[vba+CPMVEC_RISCTIMER]   = inthandler;  /* timer table */
-       _ramvec[vba+CPMVEC_TIMER2]      = inthandler;  /* timer 2 */
-       _ramvec[vba+CPMVEC_RESERVED3]   = inthandler;  /* reserved */
-       _ramvec[vba+CPMVEC_IDMA2]       = inthandler;  /* idma 2 */
-       _ramvec[vba+CPMVEC_IDMA1]       = inthandler;  /* idma 1 */
-       _ramvec[vba+CPMVEC_SDMA_CB_ERR] = inthandler;  /* sdma channel bus error */
-       _ramvec[vba+CPMVEC_PIO_PC3]     = inthandler;  /* pio - pc3 */
-       _ramvec[vba+CPMVEC_PIO_PC2]     = inthandler;  /* pio - pc2 */
-       /* _ramvec[vba+CPMVEC_TIMER1]      = cpm_isr_timer1; */  /* timer 1 */
-       _ramvec[vba+CPMVEC_TIMER1]      = inthandler;  /* timer 1 */
-       _ramvec[vba+CPMVEC_PIO_PC1]     = inthandler;  /* pio - pc1 */
-       _ramvec[vba+CPMVEC_SCC4]        = inthandler;  /* scc 4 */
-       _ramvec[vba+CPMVEC_SCC3]        = inthandler;  /* scc 3 */
-       _ramvec[vba+CPMVEC_SCC2]        = inthandler;  /* scc 2 */
-       _ramvec[vba+CPMVEC_SCC1]        = inthandler;  /* scc 1 */
-       _ramvec[vba+CPMVEC_PIO_PC0]     = inthandler;  /* pio - pc0 */
-
-
-       /* turn off all CPM interrupts */
-       pquicc->intr_cimr = 0x00000000;
-}
-
-void init_IRQ(void)
-{
-       int i;
-
-       for (i = 0; (i < NR_IRQS); i++) {
-               irq_set_chip(i, &intc_irq_chip);
-               irq_set_handler(i, handle_level_irq);
-       }
-}
-
diff --git a/arch/m68k/platform/Makefile b/arch/m68k/platform/Makefile
deleted file mode 100644 (file)
index fc932bf..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-#
-# Makefile for the arch/m68knommu/platform.
-#
diff --git a/arch/m68k/platform/coldfire/Makefile b/arch/m68k/platform/coldfire/Makefile
deleted file mode 100644 (file)
index 68f0fac..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-#
-# Makefile for the m68knommu kernel.
-#
-
-#
-# If you want to play with the HW breakpoints then you will
-# need to add define this,  which will give you a stack backtrace
-# on the console port whenever a DBG interrupt occurs. You have to
-# set up you HW breakpoints to trigger a DBG interrupt:
-#
-# ccflags-y := -DTRAP_DBG_INTERRUPT
-# asflags-y := -DTRAP_DBG_INTERRUPT
-#
-
-asflags-$(CONFIG_FULLDEBUG) := -DDEBUGGER_COMPATIBLE_CACHE=1
-
-obj-$(CONFIG_COLDFIRE) += cache.o clk.o device.o dma.o entry.o vectors.o
-obj-$(CONFIG_M5206)    += m5206.o timers.o intc.o reset.o
-obj-$(CONFIG_M5206e)   += m5206.o timers.o intc.o reset.o
-obj-$(CONFIG_M520x)    += m520x.o pit.o intc-simr.o reset.o
-obj-$(CONFIG_M523x)    += m523x.o pit.o dma_timer.o intc-2.o reset.o
-obj-$(CONFIG_M5249)    += m5249.o timers.o intc.o intc-5249.o reset.o
-obj-$(CONFIG_M525x)    += m525x.o timers.o intc.o intc-525x.o reset.o
-obj-$(CONFIG_M527x)    += m527x.o pit.o intc-2.o reset.o
-obj-$(CONFIG_M5272)    += m5272.o intc-5272.o timers.o
-obj-$(CONFIG_M528x)    += m528x.o pit.o intc-2.o reset.o
-obj-$(CONFIG_M5307)    += m5307.o timers.o intc.o reset.o
-obj-$(CONFIG_M53xx)    += m53xx.o timers.o intc-simr.o reset.o
-obj-$(CONFIG_M5407)    += m5407.o timers.o intc.o reset.o
-obj-$(CONFIG_M54xx)    += m54xx.o sltimers.o intc-2.o
-obj-$(CONFIG_M5441x)   += m5441x.o pit.o intc-simr.o reset.o
-
-obj-$(CONFIG_NETtel)   += nettel.o
-obj-$(CONFIG_CLEOPATRA)        += nettel.o
-obj-$(CONFIG_FIREBEE)  += firebee.o
-obj-$(CONFIG_MCF8390)  += mcf8390.o
-
-obj-$(CONFIG_PCI)      += pci.o
-
-obj-y                  += gpio.o
-extra-y := head.o
diff --git a/arch/m68k/platform/coldfire/cache.c b/arch/m68k/platform/coldfire/cache.c
deleted file mode 100644 (file)
index 71beeaf..0000000
+++ /dev/null
@@ -1,48 +0,0 @@
-/***************************************************************************/
-
-/*
- *     cache.c -- general ColdFire Cache maintenance code
- *
- *     Copyright (C) 2010, Greg Ungerer (gerg@snapgear.com)
- */
-
-/***************************************************************************/
-
-#include <linux/kernel.h>
-#include <asm/coldfire.h>
-#include <asm/mcfsim.h>
-
-/***************************************************************************/
-#ifdef CACHE_PUSH
-/***************************************************************************/
-
-/*
- *     Use cpushl to push all dirty cache lines back to memory.
- *     Older versions of GAS don't seem to know how to generate the
- *     ColdFire cpushl instruction... Oh well, bit stuff it for now.
- */
-
-void mcf_cache_push(void)
-{
-       __asm__ __volatile__ (
-               "clrl   %%d0\n\t"
-               "1:\n\t"
-               "movel  %%d0,%%a0\n\t"
-               "2:\n\t"
-               ".word  0xf468\n\t"
-               "addl   %0,%%a0\n\t"
-               "cmpl   %1,%%a0\n\t"
-               "blt    2b\n\t"
-               "addql  #1,%%d0\n\t"
-               "cmpil  %2,%%d0\n\t"
-               "bne    1b\n\t"
-               : /* No output */
-               : "i" (CACHE_LINE_SIZE),
-                 "i" (DCACHE_SIZE / CACHE_WAYS),
-                 "i" (CACHE_WAYS)
-               : "d0", "a0" );
-}
-
-/***************************************************************************/
-#endif /* CACHE_PUSH */
-/***************************************************************************/
diff --git a/arch/m68k/platform/coldfire/clk.c b/arch/m68k/platform/coldfire/clk.c
deleted file mode 100644 (file)
index fddfdcc..0000000
+++ /dev/null
@@ -1,124 +0,0 @@
-/***************************************************************************/
-
-/*
- *     clk.c -- general ColdFire CPU kernel clk handling
- *
- *     Copyright (C) 2009, Greg Ungerer (gerg@snapgear.com)
- */
-
-/***************************************************************************/
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/mutex.h>
-#include <linux/clk.h>
-#include <linux/io.h>
-#include <linux/err.h>
-#include <asm/coldfire.h>
-#include <asm/mcfsim.h>
-#include <asm/mcfclk.h>
-
-static DEFINE_SPINLOCK(clk_lock);
-
-#ifdef MCFPM_PPMCR0
-/*
- *     For more advanced ColdFire parts that have clocks that can be enabled
- *     we supply enable/disable functions. These must properly define their
- *     clocks in their platform specific code.
- */
-void __clk_init_enabled(struct clk *clk)
-{
-       clk->enabled = 1;
-       clk->clk_ops->enable(clk);
-}
-
-void __clk_init_disabled(struct clk *clk)
-{
-       clk->enabled = 0;
-       clk->clk_ops->disable(clk);
-}
-
-static void __clk_enable0(struct clk *clk)
-{
-       __raw_writeb(clk->slot, MCFPM_PPMCR0);
-}
-
-static void __clk_disable0(struct clk *clk)
-{
-       __raw_writeb(clk->slot, MCFPM_PPMSR0);
-}
-
-struct clk_ops clk_ops0 = {
-       .enable         = __clk_enable0,
-       .disable        = __clk_disable0,
-};
-
-#ifdef MCFPM_PPMCR1
-static void __clk_enable1(struct clk *clk)
-{
-       __raw_writeb(clk->slot, MCFPM_PPMCR1);
-}
-
-static void __clk_disable1(struct clk *clk)
-{
-       __raw_writeb(clk->slot, MCFPM_PPMSR1);
-}
-
-struct clk_ops clk_ops1 = {
-       .enable         = __clk_enable1,
-       .disable        = __clk_disable1,
-};
-#endif /* MCFPM_PPMCR1 */
-#endif /* MCFPM_PPMCR0 */
-
-struct clk *clk_get(struct device *dev, const char *id)
-{
-       const char *clk_name = dev ? dev_name(dev) : id ? id : NULL;
-       struct clk *clk;
-       unsigned i;
-
-       for (i = 0; (clk = mcf_clks[i]) != NULL; ++i)
-               if (!strcmp(clk->name, clk_name))
-                       return clk;
-       pr_warn("clk_get: didn't find clock %s\n", clk_name);
-       return ERR_PTR(-ENOENT);
-}
-EXPORT_SYMBOL(clk_get);
-
-int clk_enable(struct clk *clk)
-{
-       unsigned long flags;
-       spin_lock_irqsave(&clk_lock, flags);
-       if ((clk->enabled++ == 0) && clk->clk_ops)
-               clk->clk_ops->enable(clk);
-       spin_unlock_irqrestore(&clk_lock, flags);
-
-       return 0;
-}
-EXPORT_SYMBOL(clk_enable);
-
-void clk_disable(struct clk *clk)
-{
-       unsigned long flags;
-       spin_lock_irqsave(&clk_lock, flags);
-       if ((--clk->enabled == 0) && clk->clk_ops)
-               clk->clk_ops->disable(clk);
-       spin_unlock_irqrestore(&clk_lock, flags);
-}
-EXPORT_SYMBOL(clk_disable);
-
-void clk_put(struct clk *clk)
-{
-       if (clk->enabled != 0)
-               pr_warn("clk_put %s still enabled\n", clk->name);
-}
-EXPORT_SYMBOL(clk_put);
-
-unsigned long clk_get_rate(struct clk *clk)
-{
-       return clk->rate;
-}
-EXPORT_SYMBOL(clk_get_rate);
-
-/***************************************************************************/
diff --git a/arch/m68k/platform/coldfire/device.c b/arch/m68k/platform/coldfire/device.c
deleted file mode 100644 (file)
index 71ea4c0..0000000
+++ /dev/null
@@ -1,369 +0,0 @@
-/*
- * device.c  -- common ColdFire SoC device support
- *
- * (C) Copyright 2011, Greg Ungerer <gerg@uclinux.org>
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file COPYING in the main directory of this archive
- * for more details.
- */
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/io.h>
-#include <linux/spi/spi.h>
-#include <linux/gpio.h>
-#include <linux/fec.h>
-#include <asm/traps.h>
-#include <asm/coldfire.h>
-#include <asm/mcfsim.h>
-#include <asm/mcfuart.h>
-#include <asm/mcfqspi.h>
-
-/*
- *     All current ColdFire parts contain from 2, 3, 4 or 10 UARTS.
- */
-static struct mcf_platform_uart mcf_uart_platform_data[] = {
-       {
-               .mapbase        = MCFUART_BASE0,
-               .irq            = MCF_IRQ_UART0,
-       },
-       {
-               .mapbase        = MCFUART_BASE1,
-               .irq            = MCF_IRQ_UART1,
-       },
-#ifdef MCFUART_BASE2
-       {
-               .mapbase        = MCFUART_BASE2,
-               .irq            = MCF_IRQ_UART2,
-       },
-#endif
-#ifdef MCFUART_BASE3
-       {
-               .mapbase        = MCFUART_BASE3,
-               .irq            = MCF_IRQ_UART3,
-       },
-#endif
-#ifdef MCFUART_BASE4
-       {
-               .mapbase        = MCFUART_BASE4,
-               .irq            = MCF_IRQ_UART4,
-       },
-#endif
-#ifdef MCFUART_BASE5
-       {
-               .mapbase        = MCFUART_BASE5,
-               .irq            = MCF_IRQ_UART5,
-       },
-#endif
-#ifdef MCFUART_BASE6
-       {
-               .mapbase        = MCFUART_BASE6,
-               .irq            = MCF_IRQ_UART6,
-       },
-#endif
-#ifdef MCFUART_BASE7
-       {
-               .mapbase        = MCFUART_BASE7,
-               .irq            = MCF_IRQ_UART7,
-       },
-#endif
-#ifdef MCFUART_BASE8
-       {
-               .mapbase        = MCFUART_BASE8,
-               .irq            = MCF_IRQ_UART8,
-       },
-#endif
-#ifdef MCFUART_BASE9
-       {
-               .mapbase        = MCFUART_BASE9,
-               .irq            = MCF_IRQ_UART9,
-       },
-#endif
-       { },
-};
-
-static struct platform_device mcf_uart = {
-       .name                   = "mcfuart",
-       .id                     = 0,
-       .dev.platform_data      = mcf_uart_platform_data,
-};
-
-#ifdef CONFIG_FEC
-
-#ifdef CONFIG_M5441x
-#define FEC_NAME       "enet-fec"
-static struct fec_platform_data fec_pdata = {
-       .phy            = PHY_INTERFACE_MODE_RMII,
-};
-#define FEC_PDATA      (&fec_pdata)
-#else
-#define FEC_NAME       "fec"
-#define FEC_PDATA      NULL
-#endif
-
-/*
- *     Some ColdFire cores contain the Fast Ethernet Controller (FEC)
- *     block. It is Freescale's own hardware block. Some ColdFires
- *     have 2 of these.
- */
-static struct resource mcf_fec0_resources[] = {
-       {
-               .start          = MCFFEC_BASE0,
-               .end            = MCFFEC_BASE0 + MCFFEC_SIZE0 - 1,
-               .flags          = IORESOURCE_MEM,
-       },
-       {
-               .start          = MCF_IRQ_FECRX0,
-               .end            = MCF_IRQ_FECRX0,
-               .flags          = IORESOURCE_IRQ,
-       },
-       {
-               .start          = MCF_IRQ_FECTX0,
-               .end            = MCF_IRQ_FECTX0,
-               .flags          = IORESOURCE_IRQ,
-       },
-       {
-               .start          = MCF_IRQ_FECENTC0,
-               .end            = MCF_IRQ_FECENTC0,
-               .flags          = IORESOURCE_IRQ,
-       },
-};
-
-static struct platform_device mcf_fec0 = {
-       .name                   = FEC_NAME,
-       .id                     = 0,
-       .num_resources          = ARRAY_SIZE(mcf_fec0_resources),
-       .resource               = mcf_fec0_resources,
-       .dev.platform_data      = FEC_PDATA,
-};
-
-#ifdef MCFFEC_BASE1
-static struct resource mcf_fec1_resources[] = {
-       {
-               .start          = MCFFEC_BASE1,
-               .end            = MCFFEC_BASE1 + MCFFEC_SIZE1 - 1,
-               .flags          = IORESOURCE_MEM,
-       },
-       {
-               .start          = MCF_IRQ_FECRX1,
-               .end            = MCF_IRQ_FECRX1,
-               .flags          = IORESOURCE_IRQ,
-       },
-       {
-               .start          = MCF_IRQ_FECTX1,
-               .end            = MCF_IRQ_FECTX1,
-               .flags          = IORESOURCE_IRQ,
-       },
-       {
-               .start          = MCF_IRQ_FECENTC1,
-               .end            = MCF_IRQ_FECENTC1,
-               .flags          = IORESOURCE_IRQ,
-       },
-};
-
-static struct platform_device mcf_fec1 = {
-       .name                   = FEC_NAME,
-       .id                     = 1,
-       .num_resources          = ARRAY_SIZE(mcf_fec1_resources),
-       .resource               = mcf_fec1_resources,
-       .dev.platform_data      = FEC_PDATA,
-};
-#endif /* MCFFEC_BASE1 */
-#endif /* CONFIG_FEC */
-
-#if IS_ENABLED(CONFIG_SPI_COLDFIRE_QSPI)
-/*
- *     The ColdFire QSPI module is an SPI protocol hardware block used
- *     on a number of different ColdFire CPUs.
- */
-static struct resource mcf_qspi_resources[] = {
-       {
-               .start          = MCFQSPI_BASE,
-               .end            = MCFQSPI_BASE + MCFQSPI_SIZE - 1,
-               .flags          = IORESOURCE_MEM,
-       },
-       {
-               .start          = MCF_IRQ_QSPI,
-               .end            = MCF_IRQ_QSPI,
-               .flags          = IORESOURCE_IRQ,
-       },
-};
-
-static int mcf_cs_setup(struct mcfqspi_cs_control *cs_control)
-{
-       int status;
-
-       status = gpio_request(MCFQSPI_CS0, "MCFQSPI_CS0");
-       if (status) {
-               pr_debug("gpio_request for MCFQSPI_CS0 failed\n");
-               goto fail0;
-       }
-       status = gpio_direction_output(MCFQSPI_CS0, 1);
-       if (status) {
-               pr_debug("gpio_direction_output for MCFQSPI_CS0 failed\n");
-               goto fail1;
-       }
-
-       status = gpio_request(MCFQSPI_CS1, "MCFQSPI_CS1");
-       if (status) {
-               pr_debug("gpio_request for MCFQSPI_CS1 failed\n");
-               goto fail1;
-       }
-       status = gpio_direction_output(MCFQSPI_CS1, 1);
-       if (status) {
-               pr_debug("gpio_direction_output for MCFQSPI_CS1 failed\n");
-               goto fail2;
-       }
-
-       status = gpio_request(MCFQSPI_CS2, "MCFQSPI_CS2");
-       if (status) {
-               pr_debug("gpio_request for MCFQSPI_CS2 failed\n");
-               goto fail2;
-       }
-       status = gpio_direction_output(MCFQSPI_CS2, 1);
-       if (status) {
-               pr_debug("gpio_direction_output for MCFQSPI_CS2 failed\n");
-               goto fail3;
-       }
-
-#ifdef MCFQSPI_CS3
-       status = gpio_request(MCFQSPI_CS3, "MCFQSPI_CS3");
-       if (status) {
-               pr_debug("gpio_request for MCFQSPI_CS3 failed\n");
-               goto fail3;
-       }
-       status = gpio_direction_output(MCFQSPI_CS3, 1);
-       if (status) {
-               pr_debug("gpio_direction_output for MCFQSPI_CS3 failed\n");
-               gpio_free(MCFQSPI_CS3);
-               goto fail3;
-       }
-#endif
-
-       return 0;
-
-fail3:
-       gpio_free(MCFQSPI_CS2);
-fail2:
-       gpio_free(MCFQSPI_CS1);
-fail1:
-       gpio_free(MCFQSPI_CS0);
-fail0:
-       return status;
-}
-
-static void mcf_cs_teardown(struct mcfqspi_cs_control *cs_control)
-{
-#ifdef MCFQSPI_CS3
-       gpio_free(MCFQSPI_CS3);
-#endif
-       gpio_free(MCFQSPI_CS2);
-       gpio_free(MCFQSPI_CS1);
-       gpio_free(MCFQSPI_CS0);
-}
-
-static void mcf_cs_select(struct mcfqspi_cs_control *cs_control,
-                         u8 chip_select, bool cs_high)
-{
-       switch (chip_select) {
-       case 0:
-               gpio_set_value(MCFQSPI_CS0, cs_high);
-               break;
-       case 1:
-               gpio_set_value(MCFQSPI_CS1, cs_high);
-               break;
-       case 2:
-               gpio_set_value(MCFQSPI_CS2, cs_high);
-               break;
-#ifdef MCFQSPI_CS3
-       case 3:
-               gpio_set_value(MCFQSPI_CS3, cs_high);
-               break;
-#endif
-       }
-}
-
-static void mcf_cs_deselect(struct mcfqspi_cs_control *cs_control,
-                           u8 chip_select, bool cs_high)
-{
-       switch (chip_select) {
-       case 0:
-               gpio_set_value(MCFQSPI_CS0, !cs_high);
-               break;
-       case 1:
-               gpio_set_value(MCFQSPI_CS1, !cs_high);
-               break;
-       case 2:
-               gpio_set_value(MCFQSPI_CS2, !cs_high);
-               break;
-#ifdef MCFQSPI_CS3
-       case 3:
-               gpio_set_value(MCFQSPI_CS3, !cs_high);
-               break;
-#endif
-       }
-}
-
-static struct mcfqspi_cs_control mcf_cs_control = {
-       .setup                  = mcf_cs_setup,
-       .teardown               = mcf_cs_teardown,
-       .select                 = mcf_cs_select,
-       .deselect               = mcf_cs_deselect,
-};
-
-static struct mcfqspi_platform_data mcf_qspi_data = {
-       .bus_num                = 0,
-       .num_chipselect         = 4,
-       .cs_control             = &mcf_cs_control,
-};
-
-static struct platform_device mcf_qspi = {
-       .name                   = "mcfqspi",
-       .id                     = 0,
-       .num_resources          = ARRAY_SIZE(mcf_qspi_resources),
-       .resource               = mcf_qspi_resources,
-       .dev.platform_data      = &mcf_qspi_data,
-};
-#endif /* IS_ENABLED(CONFIG_SPI_COLDFIRE_QSPI) */
-
-static struct platform_device *mcf_devices[] __initdata = {
-       &mcf_uart,
-#ifdef CONFIG_FEC
-       &mcf_fec0,
-#ifdef MCFFEC_BASE1
-       &mcf_fec1,
-#endif
-#endif
-#if IS_ENABLED(CONFIG_SPI_COLDFIRE_QSPI)
-       &mcf_qspi,
-#endif
-};
-
-/*
- *     Some ColdFire UARTs let you set the IRQ line to use.
- */
-static void __init mcf_uart_set_irq(void)
-{
-#ifdef MCFUART_UIVR
-       /* UART0 interrupt setup */
-       writeb(MCFSIM_ICR_LEVEL6 | MCFSIM_ICR_PRI1, MCFSIM_UART1ICR);
-       writeb(MCF_IRQ_UART0, MCFUART_BASE0 + MCFUART_UIVR);
-       mcf_mapirq2imr(MCF_IRQ_UART0, MCFINTC_UART0);
-
-       /* UART1 interrupt setup */
-       writeb(MCFSIM_ICR_LEVEL6 | MCFSIM_ICR_PRI2, MCFSIM_UART2ICR);
-       writeb(MCF_IRQ_UART1, MCFUART_BASE1 + MCFUART_UIVR);
-       mcf_mapirq2imr(MCF_IRQ_UART1, MCFINTC_UART1);
-#endif
-}
-
-static int __init mcf_init_devices(void)
-{
-       mcf_uart_set_irq();
-       platform_add_devices(mcf_devices, ARRAY_SIZE(mcf_devices));
-       return 0;
-}
-
-arch_initcall(mcf_init_devices);
-
diff --git a/arch/m68k/platform/coldfire/dma.c b/arch/m68k/platform/coldfire/dma.c
deleted file mode 100644 (file)
index df5ce20..0000000
+++ /dev/null
@@ -1,42 +0,0 @@
-/***************************************************************************/
-
-/*
- *     dma.c -- Freescale ColdFire DMA support
- *
- *     Copyright (C) 2007, Greg Ungerer (gerg@snapgear.com)
- */
-
-/***************************************************************************/
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <asm/dma.h>
-#include <asm/coldfire.h>
-#include <asm/mcfsim.h>
-#include <asm/mcfdma.h>
-
-/***************************************************************************/
-
-/*
- *      DMA channel base address table.
- */
-unsigned int dma_base_addr[MAX_M68K_DMA_CHANNELS] = {
-#ifdef MCFDMA_BASE0
-       MCFDMA_BASE0,
-#endif
-#ifdef MCFDMA_BASE1
-       MCFDMA_BASE1,
-#endif
-#ifdef MCFDMA_BASE2
-       MCFDMA_BASE2,
-#endif
-#ifdef MCFDMA_BASE3
-       MCFDMA_BASE3,
-#endif
-};
-EXPORT_SYMBOL(dma_base_addr);
-
-unsigned int dma_device_address[MAX_M68K_DMA_CHANNELS];
-EXPORT_SYMBOL(dma_device_address);
-
-/***************************************************************************/
diff --git a/arch/m68k/platform/coldfire/dma_timer.c b/arch/m68k/platform/coldfire/dma_timer.c
deleted file mode 100644 (file)
index 235ad57..0000000
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * dma_timer.c -- Freescale ColdFire DMA Timer.
- *
- * Copyright (C) 2007, Benedikt Spranger <b.spranger@linutronix.de>
- * Copyright (C) 2008. Sebastian Siewior, Linutronix
- *
- */
-
-#include <linux/clocksource.h>
-#include <linux/io.h>
-
-#include <asm/machdep.h>
-#include <asm/coldfire.h>
-#include <asm/mcfpit.h>
-#include <asm/mcfsim.h>
-
-#define DMA_TIMER_0    (0x00)
-#define DMA_TIMER_1    (0x40)
-#define DMA_TIMER_2    (0x80)
-#define DMA_TIMER_3    (0xc0)
-
-#define DTMR0  (MCF_IPSBAR + DMA_TIMER_0 + 0x400)
-#define DTXMR0 (MCF_IPSBAR + DMA_TIMER_0 + 0x402)
-#define DTER0  (MCF_IPSBAR + DMA_TIMER_0 + 0x403)
-#define DTRR0  (MCF_IPSBAR + DMA_TIMER_0 + 0x404)
-#define DTCR0  (MCF_IPSBAR + DMA_TIMER_0 + 0x408)
-#define DTCN0  (MCF_IPSBAR + DMA_TIMER_0 + 0x40c)
-
-#define DMA_FREQ    ((MCF_CLK / 2) / 16)
-
-/* DTMR */
-#define DMA_DTMR_RESTART       (1 << 3)
-#define DMA_DTMR_CLK_DIV_1     (1 << 1)
-#define DMA_DTMR_CLK_DIV_16    (2 << 1)
-#define DMA_DTMR_ENABLE                (1 << 0)
-
-static cycle_t cf_dt_get_cycles(struct clocksource *cs)
-{
-       return __raw_readl(DTCN0);
-}
-
-static struct clocksource clocksource_cf_dt = {
-       .name           = "coldfire_dma_timer",
-       .rating         = 200,
-       .read           = cf_dt_get_cycles,
-       .mask           = CLOCKSOURCE_MASK(32),
-       .flags          = CLOCK_SOURCE_IS_CONTINUOUS,
-};
-
-static int __init  init_cf_dt_clocksource(void)
-{
-       /*
-        * We setup DMA timer 0 in free run mode. This incrementing counter is
-        * used as a highly precious clock source. With MCF_CLOCK = 150 MHz we
-        * get a ~213 ns resolution and the 32bit register will overflow almost
-        * every 15 minutes.
-        */
-       __raw_writeb(0x00, DTXMR0);
-       __raw_writeb(0x00, DTER0);
-       __raw_writel(0x00000000, DTRR0);
-       __raw_writew(DMA_DTMR_CLK_DIV_16 | DMA_DTMR_ENABLE, DTMR0);
-       return clocksource_register_hz(&clocksource_cf_dt, DMA_FREQ);
-}
-
-arch_initcall(init_cf_dt_clocksource);
-
-#define CYC2NS_SCALE_FACTOR 10 /* 2^10, carefully chosen */
-#define CYC2NS_SCALE   ((1000000 << CYC2NS_SCALE_FACTOR) / (DMA_FREQ / 1000))
-
-static unsigned long long cycles2ns(unsigned long cycl)
-{
-       return (unsigned long long) ((unsigned long long)cycl *
-                       CYC2NS_SCALE) >> CYC2NS_SCALE_FACTOR;
-}
-
-unsigned long long sched_clock(void)
-{
-       unsigned long cycl = __raw_readl(DTCN0);
-
-       return cycles2ns(cycl);
-}
diff --git a/arch/m68k/platform/coldfire/entry.S b/arch/m68k/platform/coldfire/entry.S
deleted file mode 100644 (file)
index 881ab8e..0000000
+++ /dev/null
@@ -1,203 +0,0 @@
-/*
- *  linux/arch/m68knommu/platform/5307/entry.S
- *
- *  Copyright (C) 1999-2007, Greg Ungerer (gerg@snapgear.com)
- *  Copyright (C) 1998  D. Jeff Dionne <jeff@lineo.ca>,
- *                      Kenneth Albanowski <kjahds@kjahds.com>,
- *  Copyright (C) 2000  Lineo Inc. (www.lineo.com)
- *  Copyright (C) 2004-2006  Macq Electronique SA. (www.macqel.com)
- *
- * Based on:
- *
- *  linux/arch/m68k/kernel/entry.S
- *
- *  Copyright (C) 1991, 1992  Linus Torvalds
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file README.legal in the main directory of this archive
- * for more details.
- *
- * Linux/m68k support by Hamish Macdonald
- *
- * 68060 fixes by Jesper Skov
- * ColdFire support by Greg Ungerer (gerg@snapgear.com)
- * 5307 fixes by David W. Miller
- * linux 2.4 support David McCullough <davidm@snapgear.com>
- * Bug, speed and maintainability fixes by Philippe De Muyter <phdm@macqel.be>
- */
-
-#include <linux/linkage.h>
-#include <asm/unistd.h>
-#include <asm/thread_info.h>
-#include <asm/errno.h>
-#include <asm/setup.h>
-#include <asm/segment.h>
-#include <asm/asm-offsets.h>
-#include <asm/entry.h>
-
-#ifdef CONFIG_COLDFIRE_SW_A7
-/*
- *     Define software copies of the supervisor and user stack pointers.
- */
-.bss
-sw_ksp:
-.long  0
-sw_usp:
-.long  0
-#endif /* CONFIG_COLDFIRE_SW_A7 */
-
-.text
-
-.globl system_call
-.globl resume
-.globl ret_from_exception
-.globl ret_from_signal
-.globl sys_call_table
-.globl inthandler
-
-enosys:
-       mov.l   #sys_ni_syscall,%d3
-       bra     1f
-
-ENTRY(system_call)
-       SAVE_ALL_SYS
-       move    #0x2000,%sr             /* enable intrs again */
-       GET_CURRENT(%d2)
-
-       cmpl    #NR_syscalls,%d0
-       jcc     enosys
-       lea     sys_call_table,%a0
-       lsll    #2,%d0                  /* movel %a0@(%d0:l:4),%d3 */
-       movel   %a0@(%d0),%d3
-       jeq     enosys
-
-1:
-       movel   %sp,%d2                 /* get thread_info pointer */
-       andl    #-THREAD_SIZE,%d2       /* at start of kernel stack */
-       movel   %d2,%a0
-       movel   %a0@,%a1                /* save top of frame */
-       movel   %sp,%a1@(TASK_THREAD+THREAD_ESP0)
-       btst    #(TIF_SYSCALL_TRACE%8),%a0@(TINFO_FLAGS+(31-TIF_SYSCALL_TRACE)/8)
-       bnes    1f
-
-       movel   %d3,%a0
-       jbsr    %a0@
-       movel   %d0,%sp@(PT_OFF_D0)     /* save the return value */
-       jra     ret_from_exception
-1:
-       movel   #-ENOSYS,%d2            /* strace needs -ENOSYS in PT_OFF_D0 */
-       movel   %d2,PT_OFF_D0(%sp)      /* on syscall entry */
-       subql   #4,%sp
-       SAVE_SWITCH_STACK
-       jbsr    syscall_trace_enter
-       RESTORE_SWITCH_STACK
-       addql   #4,%sp
-       movel   %d3,%a0
-       jbsr    %a0@
-       movel   %d0,%sp@(PT_OFF_D0)             /* save the return value */
-       subql   #4,%sp                  /* dummy return address */
-       SAVE_SWITCH_STACK
-       jbsr    syscall_trace_leave
-
-ret_from_signal:
-       RESTORE_SWITCH_STACK
-       addql   #4,%sp
-
-ret_from_exception:
-       move    #0x2700,%sr             /* disable intrs */
-       btst    #5,%sp@(PT_OFF_SR)      /* check if returning to kernel */
-       jeq     Luser_return            /* if so, skip resched, signals */
-
-#ifdef CONFIG_PREEMPT
-       movel   %sp,%d1                 /* get thread_info pointer */
-       andl    #-THREAD_SIZE,%d1       /* at base of kernel stack */
-       movel   %d1,%a0
-       movel   %a0@(TINFO_FLAGS),%d1   /* get thread_info->flags */
-       andl    #(1<<TIF_NEED_RESCHED),%d1
-       jeq     Lkernel_return
-
-       movel   %a0@(TINFO_PREEMPT),%d1
-       cmpl    #0,%d1
-       jne     Lkernel_return
-
-       pea     Lkernel_return
-       jmp     preempt_schedule_irq    /* preempt the kernel */
-#endif
-
-Lkernel_return:
-       moveml  %sp@,%d1-%d5/%a0-%a2
-       lea     %sp@(32),%sp            /* space for 8 regs */
-       movel   %sp@+,%d0
-       addql   #4,%sp                  /* orig d0 */
-       addl    %sp@+,%sp               /* stk adj */
-       rte
-
-Luser_return:
-       movel   %sp,%d1                 /* get thread_info pointer */
-       andl    #-THREAD_SIZE,%d1       /* at base of kernel stack */
-       movel   %d1,%a0
-       moveb   %a0@(TINFO_FLAGS+3),%d1 /* thread_info->flags (low 8 bits) */
-       jne     Lwork_to_do             /* still work to do */
-
-Lreturn:
-       RESTORE_USER
-
-Lwork_to_do:
-       movel   %a0@(TINFO_FLAGS),%d1   /* get thread_info->flags */
-       move    #0x2000,%sr             /* enable intrs again */
-       btst    #TIF_NEED_RESCHED,%d1
-       jne     reschedule
-
-Lsignal_return:
-       subql   #4,%sp                  /* dummy return address */
-       SAVE_SWITCH_STACK
-       pea     %sp@(SWITCH_STACK_SIZE)
-       jsr     do_notify_resume
-       addql   #4,%sp
-       RESTORE_SWITCH_STACK
-       addql   #4,%sp
-       jmp     Luser_return
-
-/*
- * This is the generic interrupt handler (for all hardware interrupt
- * sources). Calls up to high level code to do all the work.
- */
-ENTRY(inthandler)
-       SAVE_ALL_INT
-       GET_CURRENT(%d2)
-
-       movew   %sp@(PT_OFF_FORMATVEC),%d0 /* put exception # in d0 */
-       andl    #0x03fc,%d0             /* mask out vector only */
-
-       movel   %sp,%sp@-               /* push regs arg */
-       lsrl    #2,%d0                  /* calculate real vector # */
-       movel   %d0,%sp@-               /* push vector number */
-       jbsr    do_IRQ                  /* call high level irq handler */
-       lea     %sp@(8),%sp             /* pop args off stack */
-
-       bra     ret_from_exception
-
-/*
- * Beware - when entering resume, prev (the current task) is
- * in a0, next (the new task) is in a1, so don't change these
- * registers until their contents are no longer needed.
- */
-ENTRY(resume)
-       movew   %sr,%d1                          /* save current status */
-       movew   %d1,%a0@(TASK_THREAD+THREAD_SR)
-       movel   %a0,%d1                          /* get prev thread in d1 */
-       SAVE_SWITCH_STACK
-       movel   %sp,%a0@(TASK_THREAD+THREAD_KSP) /* save kernel stack pointer */
-       RDUSP                                    /* movel %usp,%a3 */
-       movel   %a3,%a0@(TASK_THREAD+THREAD_USP) /* save thread user stack */
-#ifdef CONFIG_MMU
-       movel   %a1,%a2                          /* set new current */
-#endif
-       movel   %a1@(TASK_THREAD+THREAD_USP),%a3 /* restore thread user stack */
-       WRUSP                                    /* movel %a3,%usp */
-       movel   %a1@(TASK_THREAD+THREAD_KSP),%sp /* restore new kernel stack */
-       movew   %a1@(TASK_THREAD+THREAD_SR),%d7  /* restore new status */
-       movew   %d7,%sr
-       RESTORE_SWITCH_STACK
-       rts
-
diff --git a/arch/m68k/platform/coldfire/firebee.c b/arch/m68k/platform/coldfire/firebee.c
deleted file mode 100644 (file)
index 46d5053..0000000
+++ /dev/null
@@ -1,86 +0,0 @@
-/***************************************************************************/
-
-/*
- *     firebee.c -- extra startup code support for the FireBee boards
- *
- *     Copyright (C) 2011, Greg Ungerer (gerg@snapgear.com)
- */
-
-/***************************************************************************/
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/io.h>
-#include <linux/platform_device.h>
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/partitions.h>
-#include <linux/mtd/physmap.h>
-#include <asm/coldfire.h>
-#include <asm/mcfsim.h>
-
-/***************************************************************************/
-
-/*
- *     8MB of NOR flash fitted to the FireBee board.
- */
-#define        FLASH_PHYS_ADDR         0xe0000000      /* Physical address of flash */
-#define        FLASH_PHYS_SIZE         0x00800000      /* Size of flash */
-
-#define        PART_BOOT_START         0x00000000      /* Start at bottom of flash */
-#define        PART_BOOT_SIZE          0x00040000      /* 256k in size */
-#define        PART_IMAGE_START        0x00040000      /* Start after boot loader */
-#define        PART_IMAGE_SIZE         0x006c0000      /* Most of flash */
-#define        PART_FPGA_START         0x00700000      /* Start at offset 7MB */
-#define        PART_FPGA_SIZE          0x00100000      /* 1MB in size */
-
-static struct mtd_partition firebee_flash_parts[] = {
-       {
-               .name   = "dBUG",
-               .offset = PART_BOOT_START,
-               .size   = PART_BOOT_SIZE,
-       },
-       {
-               .name   = "FPGA",
-               .offset = PART_FPGA_START,
-               .size   = PART_FPGA_SIZE,
-       },
-       {
-               .name   = "image",
-               .offset = PART_IMAGE_START,
-               .size   = PART_IMAGE_SIZE,
-       },
-};
-
-static struct physmap_flash_data firebee_flash_data = {
-       .width          = 2,
-       .nr_parts       = ARRAY_SIZE(firebee_flash_parts),
-       .parts          = firebee_flash_parts,
-};
-
-static struct resource firebee_flash_resource = {
-       .start          = FLASH_PHYS_ADDR,
-       .end            = FLASH_PHYS_ADDR + FLASH_PHYS_SIZE,
-       .flags          = IORESOURCE_MEM,
-};
-
-static struct platform_device firebee_flash = {
-       .name           = "physmap-flash",
-       .id             = 0,
-       .dev            = {
-               .platform_data = &firebee_flash_data,
-       },
-       .num_resources  = 1,
-       .resource       = &firebee_flash_resource,
-};
-
-/***************************************************************************/
-
-static int __init init_firebee(void)
-{
-       platform_device_register(&firebee_flash);
-       return 0;
-}
-
-arch_initcall(init_firebee);
-
-/***************************************************************************/
diff --git a/arch/m68k/platform/coldfire/gpio.c b/arch/m68k/platform/coldfire/gpio.c
deleted file mode 100644 (file)
index e7e4286..0000000
+++ /dev/null
@@ -1,186 +0,0 @@
-/*
- * Coldfire generic GPIO support.
- *
- * (C) Copyright 2009, Steven King <sfking@fdwdc.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/device.h>
-
-#include <linux/io.h>
-#include <asm/coldfire.h>
-#include <asm/mcfsim.h>
-#include <asm/mcfgpio.h>
-
-int __mcfgpio_get_value(unsigned gpio)
-{
-       return mcfgpio_read(__mcfgpio_ppdr(gpio)) & mcfgpio_bit(gpio);
-}
-EXPORT_SYMBOL(__mcfgpio_get_value);
-
-void __mcfgpio_set_value(unsigned gpio, int value)
-{
-       if (gpio < MCFGPIO_SCR_START) {
-               unsigned long flags;
-               MCFGPIO_PORTTYPE data;
-
-               local_irq_save(flags);
-               data = mcfgpio_read(__mcfgpio_podr(gpio));
-               if (value)
-                       data |= mcfgpio_bit(gpio);
-               else
-                       data &= ~mcfgpio_bit(gpio);
-               mcfgpio_write(data, __mcfgpio_podr(gpio));
-               local_irq_restore(flags);
-       } else {
-               if (value)
-                       mcfgpio_write(mcfgpio_bit(gpio),
-                                       MCFGPIO_SETR_PORT(gpio));
-               else
-                       mcfgpio_write(~mcfgpio_bit(gpio),
-                                       MCFGPIO_CLRR_PORT(gpio));
-       }
-}
-EXPORT_SYMBOL(__mcfgpio_set_value);
-
-int __mcfgpio_direction_input(unsigned gpio)
-{
-       unsigned long flags;
-       MCFGPIO_PORTTYPE dir;
-
-       local_irq_save(flags);
-       dir = mcfgpio_read(__mcfgpio_pddr(gpio));
-       dir &= ~mcfgpio_bit(gpio);
-       mcfgpio_write(dir, __mcfgpio_pddr(gpio));
-       local_irq_restore(flags);
-
-       return 0;
-}
-EXPORT_SYMBOL(__mcfgpio_direction_input);
-
-int __mcfgpio_direction_output(unsigned gpio, int value)
-{
-       unsigned long flags;
-       MCFGPIO_PORTTYPE data;
-
-       local_irq_save(flags);
-       data = mcfgpio_read(__mcfgpio_pddr(gpio));
-       data |= mcfgpio_bit(gpio);
-       mcfgpio_write(data, __mcfgpio_pddr(gpio));
-
-       /* now set the data to output */
-       if (gpio < MCFGPIO_SCR_START) {
-               data = mcfgpio_read(__mcfgpio_podr(gpio));
-               if (value)
-                       data |= mcfgpio_bit(gpio);
-               else
-                       data &= ~mcfgpio_bit(gpio);
-               mcfgpio_write(data, __mcfgpio_podr(gpio));
-       } else {
-                if (value)
-                       mcfgpio_write(mcfgpio_bit(gpio),
-                                       MCFGPIO_SETR_PORT(gpio));
-                else
-                        mcfgpio_write(~mcfgpio_bit(gpio),
-                                        MCFGPIO_CLRR_PORT(gpio));
-       }
-       local_irq_restore(flags);
-       return 0;
-}
-EXPORT_SYMBOL(__mcfgpio_direction_output);
-
-int __mcfgpio_request(unsigned gpio)
-{
-       return 0;
-}
-EXPORT_SYMBOL(__mcfgpio_request);
-
-void __mcfgpio_free(unsigned gpio)
-{
-       __mcfgpio_direction_input(gpio);
-}
-EXPORT_SYMBOL(__mcfgpio_free);
-
-#ifdef CONFIG_GPIOLIB
-
-static int mcfgpio_direction_input(struct gpio_chip *chip, unsigned offset)
-{
-       return __mcfgpio_direction_input(offset);
-}
-
-static int mcfgpio_get_value(struct gpio_chip *chip, unsigned offset)
-{
-       return __mcfgpio_get_value(offset);
-}
-
-static int mcfgpio_direction_output(struct gpio_chip *chip, unsigned offset,
-                                   int value)
-{
-       return __mcfgpio_direction_output(offset, value);
-}
-
-static void mcfgpio_set_value(struct gpio_chip *chip, unsigned offset,
-                             int value)
-{
-       __mcfgpio_set_value(offset, value);
-}
-
-static int mcfgpio_request(struct gpio_chip *chip, unsigned offset)
-{
-       return __mcfgpio_request(offset);
-}
-
-static void mcfgpio_free(struct gpio_chip *chip, unsigned offset)
-{
-       __mcfgpio_free(offset);
-}
-
-static int mcfgpio_to_irq(struct gpio_chip *chip, unsigned offset)
-{
-#if defined(MCFGPIO_IRQ_MIN)
-       if ((offset >= MCFGPIO_IRQ_MIN) && (offset < MCFGPIO_IRQ_MAX))
-#else
-       if (offset < MCFGPIO_IRQ_MAX)
-#endif
-               return MCFGPIO_IRQ_VECBASE + offset;
-       else
-               return -EINVAL;
-}
-
-static struct bus_type mcfgpio_subsys = {
-       .name           = "gpio",
-       .dev_name       = "gpio",
-};
-
-static struct gpio_chip mcfgpio_chip = {
-       .label                  = "mcfgpio",
-       .request                = mcfgpio_request,
-       .free                   = mcfgpio_free,
-       .direction_input        = mcfgpio_direction_input,
-       .direction_output       = mcfgpio_direction_output,
-       .get                    = mcfgpio_get_value,
-       .set                    = mcfgpio_set_value,
-       .to_irq                 = mcfgpio_to_irq,
-       .base                   = 0,
-       .ngpio                  = MCFGPIO_PIN_MAX,
-};
-
-static int __init mcfgpio_sysinit(void)
-{
-       gpiochip_add(&mcfgpio_chip);
-       return subsys_system_register(&mcfgpio_subsys, NULL);
-}
-
-core_initcall(mcfgpio_sysinit);
-#endif
diff --git a/arch/m68k/platform/coldfire/head.S b/arch/m68k/platform/coldfire/head.S
deleted file mode 100644 (file)
index fa31be2..0000000
+++ /dev/null
@@ -1,298 +0,0 @@
-/*****************************************************************************/
-
-/*
- *     head.S -- common startup code for ColdFire CPUs.
- *
- *     (C) Copyright 1999-2011, Greg Ungerer <gerg@snapgear.com>.
- */
-
-/*****************************************************************************/
-
-#include <linux/linkage.h>
-#include <linux/init.h>
-#include <asm/asm-offsets.h>
-#include <asm/coldfire.h>
-#include <asm/mcfsim.h>
-#include <asm/mcfmmu.h>
-#include <asm/thread_info.h>
-
-/*****************************************************************************/
-
-/*
- *     If we don't have a fixed memory size, then lets build in code
- *     to auto detect the DRAM size. Obviously this is the preferred
- *     method, and should work for most boards. It won't work for those
- *     that do not have their RAM starting at address 0, and it only
- *     works on SDRAM (not boards fitted with SRAM).
- */
-#if CONFIG_RAMSIZE != 0
-.macro GET_MEM_SIZE
-       movel   #CONFIG_RAMSIZE,%d0     /* hard coded memory size */
-.endm
-
-#elif defined(CONFIG_M5206) || defined(CONFIG_M5206e) || \
-      defined(CONFIG_M5249) || defined(CONFIG_M525x) || \
-      defined(CONFIG_M527x) || defined(CONFIG_M528x) || \
-      defined(CONFIG_M5307) || defined(CONFIG_M5407)
-/*
- *     Not all these devices have exactly the same DRAM controller,
- *     but the DCMR register is virtually identical - give or take
- *     a couple of bits. The only exception is the 5272 devices, their
- *     DRAM controller is quite different.
- */
-.macro GET_MEM_SIZE
-       movel   MCFSIM_DMR0,%d0         /* get mask for 1st bank */
-       btst    #0,%d0                  /* check if region enabled */
-       beq     1f
-       andl    #0xfffc0000,%d0
-       beq     1f
-       addl    #0x00040000,%d0         /* convert mask to size */
-1:
-       movel   MCFSIM_DMR1,%d1         /* get mask for 2nd bank */
-       btst    #0,%d1                  /* check if region enabled */
-       beq     2f
-       andl    #0xfffc0000,%d1
-       beq     2f
-       addl    #0x00040000,%d1
-       addl    %d1,%d0                 /* total mem size in d0 */
-2:
-.endm
-
-#elif defined(CONFIG_M5272)
-.macro GET_MEM_SIZE
-       movel   MCFSIM_CSOR7,%d0        /* get SDRAM address mask */
-       andil   #0xfffff000,%d0         /* mask out chip select options */
-       negl    %d0                     /* negate bits */
-.endm
-
-#elif defined(CONFIG_M520x)
-.macro GET_MEM_SIZE
-       clrl    %d0
-       movel   MCFSIM_SDCS0, %d2       /* Get SDRAM chip select 0 config */
-       andl    #0x1f, %d2              /* Get only the chip select size */
-       beq     3f                      /* Check if it is enabled */
-       addql   #1, %d2                 /* Form exponent */
-       moveql  #1, %d0
-       lsll    %d2, %d0                /* 2 ^ exponent */
-3:
-       movel   MCFSIM_SDCS1, %d2       /* Get SDRAM chip select 1 config */
-       andl    #0x1f, %d2              /* Get only the chip select size */
-       beq     4f                      /* Check if it is enabled */
-       addql   #1, %d2                 /* Form exponent */
-       moveql  #1, %d1
-       lsll    %d2, %d1                /* 2 ^ exponent */
-       addl    %d1, %d0                /* Total size of SDRAM in d0 */
-4:
-.endm
-
-#else
-#error "ERROR: I don't know how to probe your boards memory size?"
-#endif
-
-/*****************************************************************************/
-
-/*
- *     Boards and platforms can do specific early hardware setup if
- *     they need to. Most don't need this, define away if not required.
- */
-#ifndef PLATFORM_SETUP
-#define        PLATFORM_SETUP
-#endif
-
-/*****************************************************************************/
-
-.global        _start
-.global _rambase
-.global _ramvec
-.global        _ramstart
-.global        _ramend
-#if defined(CONFIG_UBOOT)
-.global        _init_sp
-#endif
-
-/*****************************************************************************/
-
-.data
-
-/*
- *     During startup we store away the RAM setup. These are not in the
- *     bss, since their values are determined and written before the bss
- *     has been cleared.
- */
-_rambase:
-.long  0
-_ramvec:
-.long  0
-_ramstart:
-.long  0
-_ramend:
-.long  0
-#if defined(CONFIG_UBOOT)
-_init_sp:
-.long  0
-#endif
-
-/*****************************************************************************/
-
-__HEAD
-
-#ifdef CONFIG_MMU
-_start0:
-       jmp     _start
-.global kernel_pg_dir
-.equ   kernel_pg_dir,_start0
-.equ   .,_start0+0x1000
-#endif
-
-/*
- *     This is the codes first entry point. This is where it all
- *     begins...
- */
-
-_start:
-       nop                                     /* filler */
-       movew   #0x2700, %sr                    /* no interrupts */
-       movel   #CACHE_INIT,%d0                 /* disable cache */
-       movec   %d0,%CACR
-       nop
-#if defined(CONFIG_UBOOT)
-       movel   %sp,_init_sp                    /* save initial stack pointer */
-#endif
-#ifdef CONFIG_MBAR
-       movel   #CONFIG_MBAR+1,%d0              /* configured MBAR address */
-       movec   %d0,%MBAR                       /* set it */
-#endif
-
-       /*
-        *      Do any platform or board specific setup now. Most boards
-        *      don't need anything. Those exceptions are define this in
-        *      their board specific includes.
-        */
-       PLATFORM_SETUP
-
-       /*
-        *      Create basic memory configuration. Set VBR accordingly,
-        *      and size memory.
-        */
-       movel   #CONFIG_VECTORBASE,%a7
-       movec   %a7,%VBR                        /* set vectors addr */
-       movel   %a7,_ramvec
-
-       movel   #CONFIG_RAMBASE,%a7             /* mark the base of RAM */
-       movel   %a7,_rambase
-
-       GET_MEM_SIZE                            /* macro code determines size */
-       addl    %a7,%d0
-       movel   %d0,_ramend                     /* set end ram addr */
-
-       /*
-        *      Now that we know what the memory is, lets enable cache
-        *      and get things moving. This is Coldfire CPU specific. Not
-        *      all version cores have identical cache register setup. But
-        *      it is very similar. Define the exact settings in the headers
-        *      then the code here is the same for all.
-        */
-       movel   #ACR0_MODE,%d0                  /* set RAM region for caching */
-       movec   %d0,%ACR0
-       movel   #ACR1_MODE,%d0                  /* anything else to cache? */
-       movec   %d0,%ACR1
-#ifdef ACR2_MODE
-       movel   #ACR2_MODE,%d0
-       movec   %d0,%ACR2
-       movel   #ACR3_MODE,%d0
-       movec   %d0,%ACR3
-#endif
-       movel   #CACHE_MODE,%d0                 /* enable cache */
-       movec   %d0,%CACR
-       nop
-
-#ifdef CONFIG_MMU
-       /*
-        *      Identity mapping for the kernel region.
-        */
-       movel   #(MMUBASE+1),%d0                /* enable MMUBAR registers */
-       movec   %d0,%MMUBAR
-       movel   #MMUOR_CA,%d0                   /* clear TLB entries */
-       movel   %d0,MMUOR
-       movel   #0,%d0                          /* set ASID to 0 */
-       movec   %d0,%asid
-
-       movel   #MMUCR_EN,%d0                   /* Enable the identity map */
-       movel   %d0,MMUCR
-       nop                                     /* sync i-pipeline */
-
-       movel   #_vstart,%a0                    /* jump to "virtual" space */
-       jmp     %a0@
-_vstart:
-#endif /* CONFIG_MMU */
-
-#ifdef CONFIG_ROMFS_FS
-       /*
-        *      Move ROM filesystem above bss :-)
-        */
-       lea     __bss_start,%a0                 /* get start of bss */
-       lea     __bss_stop,%a1                  /* set up destination  */
-       movel   %a0,%a2                         /* copy of bss start */
-
-       movel   8(%a0),%d0                      /* get size of ROMFS */
-       addql   #8,%d0                          /* allow for rounding */
-       andl    #0xfffffffc, %d0                /* whole words */
-
-       addl    %d0,%a0                         /* copy from end */
-       addl    %d0,%a1                         /* copy from end */
-       movel   %a1,_ramstart                   /* set start of ram */
-
-_copy_romfs:
-       movel   -(%a0),%d0                      /* copy dword */
-       movel   %d0,-(%a1)
-       cmpl    %a0,%a2                         /* check if at end */
-       bne     _copy_romfs
-
-#else /* CONFIG_ROMFS_FS */
-       lea     __bss_stop,%a1
-       movel   %a1,_ramstart
-#endif /* CONFIG_ROMFS_FS */
-
-
-       /*
-        *      Zero out the bss region.
-        */
-       lea     __bss_start,%a0                 /* get start of bss */
-       lea     __bss_stop,%a1                  /* get end of bss */
-       clrl    %d0                             /* set value */
-_clear_bss:
-       movel   %d0,(%a0)+                      /* clear each word */
-       cmpl    %a0,%a1                         /* check if at end */
-       bne     _clear_bss
-
-       /*
-        *      Load the current task pointer and stack.
-        */
-       lea     init_thread_union,%a0
-       lea     THREAD_SIZE(%a0),%sp
-
-#ifdef CONFIG_MMU
-.global m68k_cputype
-.global m68k_mmutype
-.global m68k_fputype
-.global m68k_machtype
-       movel   #CPU_COLDFIRE,%d0
-       movel   %d0,m68k_cputype                /* Mark us as a ColdFire */
-       movel   #MMU_COLDFIRE,%d0
-       movel   %d0,m68k_mmutype
-       movel   #FPU_COLDFIRE,%d0
-       movel   %d0,m68k_fputype
-       movel   #MACH_M54XX,%d0
-       movel   %d0,m68k_machtype               /* Mark us as a 54xx machine */
-       lea     init_task,%a2                   /* Set "current" init task */
-#endif
-
-       /*
-        *      Assember start up done, start code proper.
-        */
-       jsr     start_kernel                    /* start Linux kernel */
-
-_exit:
-       jmp     _exit                           /* should never get here */
-
-/*****************************************************************************/
diff --git a/arch/m68k/platform/coldfire/intc-2.c b/arch/m68k/platform/coldfire/intc-2.c
deleted file mode 100644 (file)
index 9950933..0000000
+++ /dev/null
@@ -1,212 +0,0 @@
-/*
- * intc-2.c
- *
- * General interrupt controller code for the many ColdFire cores that use
- * interrupt controllers with 63 interrupt sources, organized as 56 fully-
- * programmable + 7 fixed-level interrupt sources. This includes the 523x
- * family, the 5270, 5271, 5274, 5275, and the 528x family which have two such
- * controllers, and the 547x and 548x families which have only one of them.
- *
- * The external 7 fixed interrupts are part the the Edge Port unit of these
- * ColdFire parts. They can be configured as level or edge triggered.
- *
- * (C) Copyright 2009-2011, Greg Ungerer <gerg@snapgear.com>
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file COPYING in the main directory of this archive
- * for more details.
- */
-
-#include <linux/types.h>
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/interrupt.h>
-#include <linux/irq.h>
-#include <linux/io.h>
-#include <asm/coldfire.h>
-#include <asm/mcfsim.h>
-#include <asm/traps.h>
-
-/*
- * Bit definitions for the ICR family of registers.
- */
-#define MCFSIM_ICR_LEVEL(l)    ((l)<<3)        /* Level l intr */
-#define MCFSIM_ICR_PRI(p)      (p)             /* Priority p intr */
-
-/*
- *     The EDGE Port interrupts are the fixed 7 external interrupts.
- *     They need some special treatment, for example they need to be acked.
- */
-#define        EINT0   64      /* Is not actually used, but spot reserved for it */
-#define        EINT1   65      /* EDGE Port interrupt 1 */
-#define        EINT7   71      /* EDGE Port interrupt 7 */
-
-#ifdef MCFICM_INTC1
-#define NR_VECS        128
-#else
-#define NR_VECS        64
-#endif
-
-static void intc_irq_mask(struct irq_data *d)
-{
-       unsigned int irq = d->irq - MCFINT_VECBASE;
-       unsigned long imraddr;
-       u32 val, imrbit;
-
-#ifdef MCFICM_INTC1
-       imraddr = (irq & 0x40) ? MCFICM_INTC1 : MCFICM_INTC0;
-#else
-       imraddr = MCFICM_INTC0;
-#endif
-       imraddr += (irq & 0x20) ? MCFINTC_IMRH : MCFINTC_IMRL;
-       imrbit = 0x1 << (irq & 0x1f);
-
-       val = __raw_readl(imraddr);
-       __raw_writel(val | imrbit, imraddr);
-}
-
-static void intc_irq_unmask(struct irq_data *d)
-{
-       unsigned int irq = d->irq - MCFINT_VECBASE;
-       unsigned long imraddr;
-       u32 val, imrbit;
-
-#ifdef MCFICM_INTC1
-       imraddr = (irq & 0x40) ? MCFICM_INTC1 : MCFICM_INTC0;
-#else
-       imraddr = MCFICM_INTC0;
-#endif
-       imraddr += ((irq & 0x20) ? MCFINTC_IMRH : MCFINTC_IMRL);
-       imrbit = 0x1 << (irq & 0x1f);
-
-       /* Don't set the "maskall" bit! */
-       if ((irq & 0x20) == 0)
-               imrbit |= 0x1;
-
-       val = __raw_readl(imraddr);
-       __raw_writel(val & ~imrbit, imraddr);
-}
-
-/*
- *     Only the external (or EDGE Port) interrupts need to be acknowledged
- *     here, as part of the IRQ handler. They only really need to be ack'ed
- *     if they are in edge triggered mode, but there is no harm in doing it
- *     for all types.
- */
-static void intc_irq_ack(struct irq_data *d)
-{
-       unsigned int irq = d->irq;
-
-       __raw_writeb(0x1 << (irq - EINT0), MCFEPORT_EPFR);
-}
-
-/*
- *     Each vector needs a unique priority and level associated with it.
- *     We don't really care so much what they are, we don't rely on the
- *     traditional priority interrupt scheme of the m68k/ColdFire. This
- *     only needs to be set once for an interrupt, and we will never change
- *     these values once we have set them.
- */
-static u8 intc_intpri = MCFSIM_ICR_LEVEL(6) | MCFSIM_ICR_PRI(6);
-
-static unsigned int intc_irq_startup(struct irq_data *d)
-{
-       unsigned int irq = d->irq - MCFINT_VECBASE;
-       unsigned long icraddr;
-
-#ifdef MCFICM_INTC1
-       icraddr = (irq & 0x40) ? MCFICM_INTC1 : MCFICM_INTC0;
-#else
-       icraddr = MCFICM_INTC0;
-#endif
-       icraddr += MCFINTC_ICR0 + (irq & 0x3f);
-       if (__raw_readb(icraddr) == 0)
-               __raw_writeb(intc_intpri--, icraddr);
-
-       irq = d->irq;
-       if ((irq >= EINT1) && (irq <= EINT7)) {
-               u8 v;
-
-               irq -= EINT0;
-
-               /* Set EPORT line as input */
-               v = __raw_readb(MCFEPORT_EPDDR);
-               __raw_writeb(v & ~(0x1 << irq), MCFEPORT_EPDDR);
-
-               /* Set EPORT line as interrupt source */
-               v = __raw_readb(MCFEPORT_EPIER);
-               __raw_writeb(v | (0x1 << irq), MCFEPORT_EPIER);
-       }
-
-       intc_irq_unmask(d);
-       return 0;
-}
-
-static int intc_irq_set_type(struct irq_data *d, unsigned int type)
-{
-       unsigned int irq = d->irq;
-       u16 pa, tb;
-
-       switch (type) {
-       case IRQ_TYPE_EDGE_RISING:
-               tb = 0x1;
-               break;
-       case IRQ_TYPE_EDGE_FALLING:
-               tb = 0x2;
-               break;
-       case IRQ_TYPE_EDGE_BOTH:
-               tb = 0x3;
-               break;
-       default:
-               /* Level triggered */
-               tb = 0;
-               break;
-       }
-
-       if (tb)
-               irq_set_handler(irq, handle_edge_irq);
-
-       irq -= EINT0;
-       pa = __raw_readw(MCFEPORT_EPPAR);
-       pa = (pa & ~(0x3 << (irq * 2))) | (tb << (irq * 2));
-       __raw_writew(pa, MCFEPORT_EPPAR);
-       
-       return 0;
-}
-
-static struct irq_chip intc_irq_chip = {
-       .name           = "CF-INTC",
-       .irq_startup    = intc_irq_startup,
-       .irq_mask       = intc_irq_mask,
-       .irq_unmask     = intc_irq_unmask,
-};
-
-static struct irq_chip intc_irq_chip_edge_port = {
-       .name           = "CF-INTC-EP",
-       .irq_startup    = intc_irq_startup,
-       .irq_mask       = intc_irq_mask,
-       .irq_unmask     = intc_irq_unmask,
-       .irq_ack        = intc_irq_ack,
-       .irq_set_type   = intc_irq_set_type,
-};
-
-void __init init_IRQ(void)
-{
-       int irq;
-
-       /* Mask all interrupt sources */
-       __raw_writel(0x1, MCFICM_INTC0 + MCFINTC_IMRL);
-#ifdef MCFICM_INTC1
-       __raw_writel(0x1, MCFICM_INTC1 + MCFINTC_IMRL);
-#endif
-
-       for (irq = MCFINT_VECBASE; (irq < MCFINT_VECBASE + NR_VECS); irq++) {
-               if ((irq >= EINT1) && (irq <=EINT7))
-                       irq_set_chip(irq, &intc_irq_chip_edge_port);
-               else
-                       irq_set_chip(irq, &intc_irq_chip);
-               irq_set_irq_type(irq, IRQ_TYPE_LEVEL_HIGH);
-               irq_set_handler(irq, handle_level_irq);
-       }
-}
-
diff --git a/arch/m68k/platform/coldfire/intc-5249.c b/arch/m68k/platform/coldfire/intc-5249.c
deleted file mode 100644 (file)
index b0d1641..0000000
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * intc2.c  -- support for the 2nd INTC controller of the 5249
- *
- * (C) Copyright 2009, Greg Ungerer <gerg@snapgear.com>
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file COPYING in the main directory of this archive
- * for more details.
- */
-
-#include <linux/types.h>
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/interrupt.h>
-#include <linux/irq.h>
-#include <linux/io.h>
-#include <asm/coldfire.h>
-#include <asm/mcfsim.h>
-
-static void intc2_irq_gpio_mask(struct irq_data *d)
-{
-       u32 imr;
-       imr = readl(MCFSIM2_GPIOINTENABLE);
-       imr &= ~(0x1 << (d->irq - MCF_IRQ_GPIO0));
-       writel(imr, MCFSIM2_GPIOINTENABLE);
-}
-
-static void intc2_irq_gpio_unmask(struct irq_data *d)
-{
-       u32 imr;
-       imr = readl(MCFSIM2_GPIOINTENABLE);
-       imr |= (0x1 << (d->irq - MCF_IRQ_GPIO0));
-       writel(imr, MCFSIM2_GPIOINTENABLE);
-}
-
-static void intc2_irq_gpio_ack(struct irq_data *d)
-{
-       writel(0x1 << (d->irq - MCF_IRQ_GPIO0), MCFSIM2_GPIOINTCLEAR);
-}
-
-static struct irq_chip intc2_irq_gpio_chip = {
-       .name           = "CF-INTC2",
-       .irq_mask       = intc2_irq_gpio_mask,
-       .irq_unmask     = intc2_irq_gpio_unmask,
-       .irq_ack        = intc2_irq_gpio_ack,
-};
-
-static int __init mcf_intc2_init(void)
-{
-       int irq;
-
-       /* GPIO interrupt sources */
-       for (irq = MCF_IRQ_GPIO0; (irq <= MCF_IRQ_GPIO7); irq++) {
-               irq_set_chip(irq, &intc2_irq_gpio_chip);
-               irq_set_handler(irq, handle_edge_irq);
-       }
-
-       return 0;
-}
-
-arch_initcall(mcf_intc2_init);
diff --git a/arch/m68k/platform/coldfire/intc-525x.c b/arch/m68k/platform/coldfire/intc-525x.c
deleted file mode 100644 (file)
index b23204d..0000000
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * intc2.c  -- support for the 2nd INTC controller of the 525x
- *
- * (C) Copyright 2012, Steven King <sfking@fdwdc.com>
- * (C) Copyright 2009, Greg Ungerer <gerg@snapgear.com>
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file COPYING in the main directory of this archive
- * for more details.
- */
-
-#include <linux/types.h>
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/interrupt.h>
-#include <linux/irq.h>
-#include <linux/io.h>
-#include <asm/coldfire.h>
-#include <asm/mcfsim.h>
-
-static void intc2_irq_gpio_mask(struct irq_data *d)
-{
-       u32 imr = readl(MCFSIM2_GPIOINTENABLE);
-       u32 type = irqd_get_trigger_type(d);
-       int irq = d->irq - MCF_IRQ_GPIO0;
-
-       if (type & IRQ_TYPE_EDGE_RISING)
-               imr &= ~(0x001 << irq);
-       if (type & IRQ_TYPE_EDGE_FALLING)
-               imr &= ~(0x100 << irq);
-       writel(imr, MCFSIM2_GPIOINTENABLE);
-}
-
-static void intc2_irq_gpio_unmask(struct irq_data *d)
-{
-       u32 imr = readl(MCFSIM2_GPIOINTENABLE);
-       u32 type = irqd_get_trigger_type(d);
-       int irq = d->irq - MCF_IRQ_GPIO0;
-
-       if (type & IRQ_TYPE_EDGE_RISING)
-               imr |= (0x001 << irq);
-       if (type & IRQ_TYPE_EDGE_FALLING)
-               imr |= (0x100 << irq);
-       writel(imr, MCFSIM2_GPIOINTENABLE);
-}
-
-static void intc2_irq_gpio_ack(struct irq_data *d)
-{
-       u32 imr = 0;
-       u32 type = irqd_get_trigger_type(d);
-       int irq = d->irq - MCF_IRQ_GPIO0;
-
-       if (type & IRQ_TYPE_EDGE_RISING)
-               imr |= (0x001 << irq);
-       if (type & IRQ_TYPE_EDGE_FALLING)
-               imr |= (0x100 << irq);
-       writel(imr, MCFSIM2_GPIOINTCLEAR);
-}
-
-static int intc2_irq_gpio_set_type(struct irq_data *d, unsigned int f)
-{
-       if (f & ~IRQ_TYPE_EDGE_BOTH)
-               return -EINVAL;
-       return 0;
-}
-
-static struct irq_chip intc2_irq_gpio_chip = {
-       .name           = "CF-INTC2",
-       .irq_mask       = intc2_irq_gpio_mask,
-       .irq_unmask     = intc2_irq_gpio_unmask,
-       .irq_ack        = intc2_irq_gpio_ack,
-       .irq_set_type   = intc2_irq_gpio_set_type,
-};
-
-static int __init mcf_intc2_init(void)
-{
-       int irq;
-
-       /* set the interrupt base for the second interrupt controller */
-       writel(MCFINTC2_VECBASE, MCFINTC2_INTBASE);
-
-       /* GPIO interrupt sources */
-       for (irq = MCF_IRQ_GPIO0; (irq <= MCF_IRQ_GPIO6); irq++) {
-               irq_set_chip(irq, &intc2_irq_gpio_chip);
-               irq_set_handler(irq, handle_edge_irq);
-       }
-
-       return 0;
-}
-
-arch_initcall(mcf_intc2_init);
diff --git a/arch/m68k/platform/coldfire/intc-5272.c b/arch/m68k/platform/coldfire/intc-5272.c
deleted file mode 100644 (file)
index d7b6956..0000000
+++ /dev/null
@@ -1,185 +0,0 @@
-/*
- * intc.c  --  interrupt controller or ColdFire 5272 SoC
- *
- * (C) Copyright 2009, Greg Ungerer <gerg@snapgear.com>
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file COPYING in the main directory of this archive
- * for more details.
- */
-
-#include <linux/types.h>
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/interrupt.h>
-#include <linux/kernel_stat.h>
-#include <linux/irq.h>
-#include <linux/io.h>
-#include <asm/coldfire.h>
-#include <asm/mcfsim.h>
-#include <asm/traps.h>
-
-/*
- * The 5272 ColdFire interrupt controller is nothing like any other
- * ColdFire interrupt controller - it truly is completely different.
- * Given its age it is unlikely to be used on any other ColdFire CPU.
- */
-
-/*
- * The masking and priproty setting of interrupts on the 5272 is done
- * via a set of 4 "Interrupt Controller Registers" (ICR). There is a
- * loose mapping of vector number to register and internal bits, but
- * a table is the easiest and quickest way to map them.
- *
- * Note that the external interrupts are edge triggered (unlike the
- * internal interrupt sources which are level triggered). Which means
- * they also need acknowledging via acknowledge bits.
- */
-struct irqmap {
-       unsigned char   icr;
-       unsigned char   index;
-       unsigned char   ack;
-};
-
-static struct irqmap intc_irqmap[MCFINT_VECMAX - MCFINT_VECBASE] = {
-       /*MCF_IRQ_SPURIOUS*/    { .icr = 0,           .index = 0,  .ack = 0, },
-       /*MCF_IRQ_EINT1*/       { .icr = MCFSIM_ICR1, .index = 28, .ack = 1, },
-       /*MCF_IRQ_EINT2*/       { .icr = MCFSIM_ICR1, .index = 24, .ack = 1, },
-       /*MCF_IRQ_EINT3*/       { .icr = MCFSIM_ICR1, .index = 20, .ack = 1, },
-       /*MCF_IRQ_EINT4*/       { .icr = MCFSIM_ICR1, .index = 16, .ack = 1, },
-       /*MCF_IRQ_TIMER1*/      { .icr = MCFSIM_ICR1, .index = 12, .ack = 0, },
-       /*MCF_IRQ_TIMER2*/      { .icr = MCFSIM_ICR1, .index = 8,  .ack = 0, },
-       /*MCF_IRQ_TIMER3*/      { .icr = MCFSIM_ICR1, .index = 4,  .ack = 0, },
-       /*MCF_IRQ_TIMER4*/      { .icr = MCFSIM_ICR1, .index = 0,  .ack = 0, },
-       /*MCF_IRQ_UART1*/       { .icr = MCFSIM_ICR2, .index = 28, .ack = 0, },
-       /*MCF_IRQ_UART2*/       { .icr = MCFSIM_ICR2, .index = 24, .ack = 0, },
-       /*MCF_IRQ_PLIP*/        { .icr = MCFSIM_ICR2, .index = 20, .ack = 0, },
-       /*MCF_IRQ_PLIA*/        { .icr = MCFSIM_ICR2, .index = 16, .ack = 0, },
-       /*MCF_IRQ_USB0*/        { .icr = MCFSIM_ICR2, .index = 12, .ack = 0, },
-       /*MCF_IRQ_USB1*/        { .icr = MCFSIM_ICR2, .index = 8,  .ack = 0, },
-       /*MCF_IRQ_USB2*/        { .icr = MCFSIM_ICR2, .index = 4,  .ack = 0, },
-       /*MCF_IRQ_USB3*/        { .icr = MCFSIM_ICR2, .index = 0,  .ack = 0, },
-       /*MCF_IRQ_USB4*/        { .icr = MCFSIM_ICR3, .index = 28, .ack = 0, },
-       /*MCF_IRQ_USB5*/        { .icr = MCFSIM_ICR3, .index = 24, .ack = 0, },
-       /*MCF_IRQ_USB6*/        { .icr = MCFSIM_ICR3, .index = 20, .ack = 0, },
-       /*MCF_IRQ_USB7*/        { .icr = MCFSIM_ICR3, .index = 16, .ack = 0, },
-       /*MCF_IRQ_DMA*/         { .icr = MCFSIM_ICR3, .index = 12, .ack = 0, },
-       /*MCF_IRQ_ERX*/         { .icr = MCFSIM_ICR3, .index = 8,  .ack = 0, },
-       /*MCF_IRQ_ETX*/         { .icr = MCFSIM_ICR3, .index = 4,  .ack = 0, },
-       /*MCF_IRQ_ENTC*/        { .icr = MCFSIM_ICR3, .index = 0,  .ack = 0, },
-       /*MCF_IRQ_QSPI*/        { .icr = MCFSIM_ICR4, .index = 28, .ack = 0, },
-       /*MCF_IRQ_EINT5*/       { .icr = MCFSIM_ICR4, .index = 24, .ack = 1, },
-       /*MCF_IRQ_EINT6*/       { .icr = MCFSIM_ICR4, .index = 20, .ack = 1, },
-       /*MCF_IRQ_SWTO*/        { .icr = MCFSIM_ICR4, .index = 16, .ack = 0, },
-};
-
-/*
- * The act of masking the interrupt also has a side effect of 'ack'ing
- * an interrupt on this irq (for the external irqs). So this mask function
- * is also an ack_mask function.
- */
-static void intc_irq_mask(struct irq_data *d)
-{
-       unsigned int irq = d->irq;
-
-       if ((irq >= MCFINT_VECBASE) && (irq <= MCFINT_VECMAX)) {
-               u32 v;
-               irq -= MCFINT_VECBASE;
-               v = 0x8 << intc_irqmap[irq].index;
-               writel(v, intc_irqmap[irq].icr);
-       }
-}
-
-static void intc_irq_unmask(struct irq_data *d)
-{
-       unsigned int irq = d->irq;
-
-       if ((irq >= MCFINT_VECBASE) && (irq <= MCFINT_VECMAX)) {
-               u32 v;
-               irq -= MCFINT_VECBASE;
-               v = 0xd << intc_irqmap[irq].index;
-               writel(v, intc_irqmap[irq].icr);
-       }
-}
-
-static void intc_irq_ack(struct irq_data *d)
-{
-       unsigned int irq = d->irq;
-
-       /* Only external interrupts are acked */
-       if ((irq >= MCFINT_VECBASE) && (irq <= MCFINT_VECMAX)) {
-               irq -= MCFINT_VECBASE;
-               if (intc_irqmap[irq].ack) {
-                       u32 v;
-                       v = readl(intc_irqmap[irq].icr);
-                       v &= (0x7 << intc_irqmap[irq].index);
-                       v |= (0x8 << intc_irqmap[irq].index);
-                       writel(v, intc_irqmap[irq].icr);
-               }
-       }
-}
-
-static int intc_irq_set_type(struct irq_data *d, unsigned int type)
-{
-       unsigned int irq = d->irq;
-
-       if ((irq >= MCFINT_VECBASE) && (irq <= MCFINT_VECMAX)) {
-               irq -= MCFINT_VECBASE;
-               if (intc_irqmap[irq].ack) {
-                       u32 v;
-                       v = readl(MCFSIM_PITR);
-                       if (type == IRQ_TYPE_EDGE_FALLING)
-                               v &= ~(0x1 << (32 - irq));
-                       else
-                               v |= (0x1 << (32 - irq));
-                       writel(v, MCFSIM_PITR);
-               }
-       }
-       return 0;
-}
-
-/*
- * Simple flow handler to deal with the external edge triggered interrupts.
- * We need to be careful with the masking/acking due to the side effects
- * of masking an interrupt.
- */
-static void intc_external_irq(unsigned int irq, struct irq_desc *desc)
-{
-       irq_desc_get_chip(desc)->irq_ack(&desc->irq_data);
-       handle_simple_irq(irq, desc);
-}
-
-static struct irq_chip intc_irq_chip = {
-       .name           = "CF-INTC",
-       .irq_mask       = intc_irq_mask,
-       .irq_unmask     = intc_irq_unmask,
-       .irq_mask_ack   = intc_irq_mask,
-       .irq_ack        = intc_irq_ack,
-       .irq_set_type   = intc_irq_set_type,
-};
-
-void __init init_IRQ(void)
-{
-       int irq, edge;
-
-       /* Mask all interrupt sources */
-       writel(0x88888888, MCFSIM_ICR1);
-       writel(0x88888888, MCFSIM_ICR2);
-       writel(0x88888888, MCFSIM_ICR3);
-       writel(0x88888888, MCFSIM_ICR4);
-
-       for (irq = 0; (irq < NR_IRQS); irq++) {
-               irq_set_chip(irq, &intc_irq_chip);
-               edge = 0;
-               if ((irq >= MCFINT_VECBASE) && (irq <= MCFINT_VECMAX))
-                       edge = intc_irqmap[irq - MCFINT_VECBASE].ack;
-               if (edge) {
-                       irq_set_irq_type(irq, IRQ_TYPE_EDGE_RISING);
-                       irq_set_handler(irq, intc_external_irq);
-               } else {
-                       irq_set_irq_type(irq, IRQ_TYPE_LEVEL_HIGH);
-                       irq_set_handler(irq, handle_level_irq);
-               }
-       }
-}
-
diff --git a/arch/m68k/platform/coldfire/intc-simr.c b/arch/m68k/platform/coldfire/intc-simr.c
deleted file mode 100644 (file)
index 7cf2c15..0000000
+++ /dev/null
@@ -1,199 +0,0 @@
-/*
- * intc-simr.c
- *
- * Interrupt controller code for the ColdFire 5208, 5207 & 532x parts.
- *
- * (C) Copyright 2009-2011, Greg Ungerer <gerg@snapgear.com>
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file COPYING in the main directory of this archive
- * for more details.
- */
-
-#include <linux/types.h>
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/interrupt.h>
-#include <linux/irq.h>
-#include <linux/io.h>
-#include <asm/coldfire.h>
-#include <asm/mcfsim.h>
-#include <asm/traps.h>
-
-/*
- *     The EDGE Port interrupts are the fixed 7 external interrupts.
- *     They need some special treatment, for example they need to be acked.
- */
-#ifdef CONFIG_M520x
-/*
- *     The 520x parts only support a limited range of these external
- *     interrupts, only 1, 4 and 7 (as interrupts 65, 66 and 67).
- */
-#define        EINT0   64      /* Is not actually used, but spot reserved for it */
-#define        EINT1   65      /* EDGE Port interrupt 1 */
-#define        EINT4   66      /* EDGE Port interrupt 4 */
-#define        EINT7   67      /* EDGE Port interrupt 7 */
-
-static unsigned int irqebitmap[] = { 0, 1, 4, 7 };
-static unsigned int inline irq2ebit(unsigned int irq)
-{
-       return irqebitmap[irq - EINT0];
-}
-
-#else
-
-/*
- *     Most of the ColdFire parts with the EDGE Port module just have
- *     a strait direct mapping of the 7 external interrupts. Although
- *     there is a bit reserved for 0, it is not used.
- */
-#define        EINT0   64      /* Is not actually used, but spot reserved for it */
-#define        EINT1   65      /* EDGE Port interrupt 1 */
-#define        EINT7   71      /* EDGE Port interrupt 7 */
-
-static unsigned int inline irq2ebit(unsigned int irq)
-{
-       return irq - EINT0;
-}
-
-#endif
-
-/*
- *     There maybe one, two or three interrupt control units, each has 64
- *     interrupts. If there is no second or third unit then MCFINTC1_* or
- *     MCFINTC2_* defines will be 0 (and code for them optimized away).
- */
-
-static void intc_irq_mask(struct irq_data *d)
-{
-       unsigned int irq = d->irq - MCFINT_VECBASE;
-
-       if (MCFINTC2_SIMR && (irq > 128))
-               __raw_writeb(irq - 128, MCFINTC2_SIMR);
-       else if (MCFINTC1_SIMR && (irq > 64))
-               __raw_writeb(irq - 64, MCFINTC1_SIMR);
-       else
-               __raw_writeb(irq, MCFINTC0_SIMR);
-}
-
-static void intc_irq_unmask(struct irq_data *d)
-{
-       unsigned int irq = d->irq - MCFINT_VECBASE;
-
-       if (MCFINTC2_CIMR && (irq > 128))
-               __raw_writeb(irq - 128, MCFINTC2_CIMR);
-       else if (MCFINTC1_CIMR && (irq > 64))
-               __raw_writeb(irq - 64, MCFINTC1_CIMR);
-       else
-               __raw_writeb(irq, MCFINTC0_CIMR);
-}
-
-static void intc_irq_ack(struct irq_data *d)
-{
-       unsigned int ebit = irq2ebit(d->irq);
-
-       __raw_writeb(0x1 << ebit, MCFEPORT_EPFR);
-}
-
-static unsigned int intc_irq_startup(struct irq_data *d)
-{
-       unsigned int irq = d->irq;
-
-       if ((irq >= EINT1) && (irq <= EINT7)) {
-               unsigned int ebit = irq2ebit(irq);
-               u8 v;
-
-#if defined(MCFEPORT_EPDDR)
-               /* Set EPORT line as input */
-               v = __raw_readb(MCFEPORT_EPDDR);
-               __raw_writeb(v & ~(0x1 << ebit), MCFEPORT_EPDDR);
-#endif
-
-               /* Set EPORT line as interrupt source */
-               v = __raw_readb(MCFEPORT_EPIER);
-               __raw_writeb(v | (0x1 << ebit), MCFEPORT_EPIER);
-       }
-
-       irq -= MCFINT_VECBASE;
-       if (MCFINTC2_ICR0 && (irq > 128))
-               __raw_writeb(5, MCFINTC2_ICR0 + irq - 128);
-       else if (MCFINTC1_ICR0 && (irq > 64))
-               __raw_writeb(5, MCFINTC1_ICR0 + irq - 64);
-       else
-               __raw_writeb(5, MCFINTC0_ICR0 + irq);
-
-       intc_irq_unmask(d);
-       return 0;
-}
-
-static int intc_irq_set_type(struct irq_data *d, unsigned int type)
-{
-       unsigned int ebit, irq = d->irq;
-       u16 pa, tb;
-
-       switch (type) {
-       case IRQ_TYPE_EDGE_RISING:
-               tb = 0x1;
-               break;
-       case IRQ_TYPE_EDGE_FALLING:
-               tb = 0x2;
-               break;
-       case IRQ_TYPE_EDGE_BOTH:
-               tb = 0x3;
-               break;
-       default:
-               /* Level triggered */
-               tb = 0;
-               break;
-       }
-
-       if (tb)
-               irq_set_handler(irq, handle_edge_irq);
-
-       ebit = irq2ebit(irq) * 2;
-       pa = __raw_readw(MCFEPORT_EPPAR);
-       pa = (pa & ~(0x3 << ebit)) | (tb << ebit);
-       __raw_writew(pa, MCFEPORT_EPPAR);
-       
-       return 0;
-}
-
-static struct irq_chip intc_irq_chip = {
-       .name           = "CF-INTC",
-       .irq_startup    = intc_irq_startup,
-       .irq_mask       = intc_irq_mask,
-       .irq_unmask     = intc_irq_unmask,
-};
-
-static struct irq_chip intc_irq_chip_edge_port = {
-       .name           = "CF-INTC-EP",
-       .irq_startup    = intc_irq_startup,
-       .irq_mask       = intc_irq_mask,
-       .irq_unmask     = intc_irq_unmask,
-       .irq_ack        = intc_irq_ack,
-       .irq_set_type   = intc_irq_set_type,
-};
-
-void __init init_IRQ(void)
-{
-       int irq, eirq;
-
-       /* Mask all interrupt sources */
-       __raw_writeb(0xff, MCFINTC0_SIMR);
-       if (MCFINTC1_SIMR)
-               __raw_writeb(0xff, MCFINTC1_SIMR);
-       if (MCFINTC2_SIMR)
-               __raw_writeb(0xff, MCFINTC2_SIMR);
-
-       eirq = MCFINT_VECBASE + 64 + (MCFINTC1_ICR0 ? 64 : 0) +
-                                               (MCFINTC2_ICR0 ? 64 : 0);
-       for (irq = MCFINT_VECBASE; (irq < eirq); irq++) {
-               if ((irq >= EINT1) && (irq <= EINT7))
-                       irq_set_chip(irq, &intc_irq_chip_edge_port);
-               else
-                       irq_set_chip(irq, &intc_irq_chip);
-               irq_set_irq_type(irq, IRQ_TYPE_LEVEL_HIGH);
-               irq_set_handler(irq, handle_level_irq);
-       }
-}
-
diff --git a/arch/m68k/platform/coldfire/intc.c b/arch/m68k/platform/coldfire/intc.c
deleted file mode 100644 (file)
index cce2574..0000000
+++ /dev/null
@@ -1,150 +0,0 @@
-/*
- * intc.c  -- support for the old ColdFire interrupt controller
- *
- * (C) Copyright 2009, Greg Ungerer <gerg@snapgear.com>
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file COPYING in the main directory of this archive
- * for more details.
- */
-
-#include <linux/types.h>
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/interrupt.h>
-#include <linux/irq.h>
-#include <linux/io.h>
-#include <asm/traps.h>
-#include <asm/coldfire.h>
-#include <asm/mcfsim.h>
-
-/*
- * The mapping of irq number to a mask register bit is not one-to-one.
- * The irq numbers are either based on "level" of interrupt or fixed
- * for an autovector-able interrupt. So we keep a local data structure
- * that maps from irq to mask register. Not all interrupts will have
- * an IMR bit.
- */
-unsigned char mcf_irq2imr[NR_IRQS];
-
-/*
- * Define the miniumun and maximum external interrupt numbers.
- * This is also used as the "level" interrupt numbers.
- */
-#define        EIRQ1   25
-#define        EIRQ7   31
-
-/*
- * In the early version 2 core ColdFire parts the IMR register was 16 bits
- * in size. Version 3 (and later version 2) core parts have a 32 bit
- * sized IMR register. Provide some size independent methods to access the
- * IMR register.
- */
-#ifdef MCFSIM_IMR_IS_16BITS
-
-void mcf_setimr(int index)
-{
-       u16 imr;
-       imr = __raw_readw(MCFSIM_IMR);
-       __raw_writew(imr | (0x1 << index), MCFSIM_IMR);
-}
-
-void mcf_clrimr(int index)
-{
-       u16 imr;
-       imr = __raw_readw(MCFSIM_IMR);
-       __raw_writew(imr & ~(0x1 << index), MCFSIM_IMR);
-}
-
-void mcf_maskimr(unsigned int mask)
-{
-       u16 imr;
-       imr = __raw_readw(MCFSIM_IMR);
-       imr |= mask;
-       __raw_writew(imr, MCFSIM_IMR);
-}
-
-#else
-
-void mcf_setimr(int index)
-{
-       u32 imr;
-       imr = __raw_readl(MCFSIM_IMR);
-       __raw_writel(imr | (0x1 << index), MCFSIM_IMR);
-}
-
-void mcf_clrimr(int index)
-{
-       u32 imr;
-       imr = __raw_readl(MCFSIM_IMR);
-       __raw_writel(imr & ~(0x1 << index), MCFSIM_IMR);
-}
-
-void mcf_maskimr(unsigned int mask)
-{
-       u32 imr;
-       imr = __raw_readl(MCFSIM_IMR);
-       imr |= mask;
-       __raw_writel(imr, MCFSIM_IMR);
-}
-
-#endif
-
-/*
- * Interrupts can be "vectored" on the ColdFire cores that support this old
- * interrupt controller. That is, the device raising the interrupt can also
- * supply the vector number to interrupt through. The AVR register of the
- * interrupt controller enables or disables this for each external interrupt,
- * so provide generic support for this. Setting this up is out-of-band for
- * the interrupt system API's, and needs to be done by the driver that
- * supports this device. Very few devices actually use this.
- */
-void mcf_autovector(int irq)
-{
-#ifdef MCFSIM_AVR
-       if ((irq >= EIRQ1) && (irq <= EIRQ7)) {
-               u8 avec;
-               avec = __raw_readb(MCFSIM_AVR);
-               avec |= (0x1 << (irq - EIRQ1 + 1));
-               __raw_writeb(avec, MCFSIM_AVR);
-       }
-#endif
-}
-
-static void intc_irq_mask(struct irq_data *d)
-{
-       if (mcf_irq2imr[d->irq])
-               mcf_setimr(mcf_irq2imr[d->irq]);
-}
-
-static void intc_irq_unmask(struct irq_data *d)
-{
-       if (mcf_irq2imr[d->irq])
-               mcf_clrimr(mcf_irq2imr[d->irq]);
-}
-
-static int intc_irq_set_type(struct irq_data *d, unsigned int type)
-{
-       return 0;
-}
-
-static struct irq_chip intc_irq_chip = {
-       .name           = "CF-INTC",
-       .irq_mask       = intc_irq_mask,
-       .irq_unmask     = intc_irq_unmask,
-       .irq_set_type   = intc_irq_set_type,
-};
-
-void __init init_IRQ(void)
-{
-       int irq;
-
-       mcf_maskimr(0xffffffff);
-
-       for (irq = 0; (irq < NR_IRQS); irq++) {
-               irq_set_chip(irq, &intc_irq_chip);
-               irq_set_irq_type(irq, IRQ_TYPE_LEVEL_HIGH);
-               irq_set_handler(irq, handle_level_irq);
-       }
-}
-
diff --git a/arch/m68k/platform/coldfire/m5206.c b/arch/m68k/platform/coldfire/m5206.c
deleted file mode 100644 (file)
index 0e55f44..0000000
+++ /dev/null
@@ -1,58 +0,0 @@
-/***************************************************************************/
-
-/*
- *     linux/arch/m68knommu/platform/5206/config.c
- *
- *     Copyright (C) 1999-2002, Greg Ungerer (gerg@snapgear.com)
- *     Copyright (C) 2000-2001, Lineo Inc. (www.lineo.com) 
- */
-
-/***************************************************************************/
-
-#include <linux/kernel.h>
-#include <linux/param.h>
-#include <linux/init.h>
-#include <linux/io.h>
-#include <asm/machdep.h>
-#include <asm/coldfire.h>
-#include <asm/mcfsim.h>
-#include <asm/mcfclk.h>
-
-/***************************************************************************/
-
-DEFINE_CLK(pll, "pll.0", MCF_CLK);
-DEFINE_CLK(sys, "sys.0", MCF_BUSCLK);
-DEFINE_CLK(mcftmr0, "mcftmr.0", MCF_BUSCLK);
-DEFINE_CLK(mcftmr1, "mcftmr.1", MCF_BUSCLK);
-DEFINE_CLK(mcfuart0, "mcfuart.0", MCF_BUSCLK);
-DEFINE_CLK(mcfuart1, "mcfuart.1", MCF_BUSCLK);
-
-struct clk *mcf_clks[] = {
-       &clk_pll,
-       &clk_sys,
-       &clk_mcftmr0,
-       &clk_mcftmr1,
-       &clk_mcfuart0,
-       &clk_mcfuart1,
-       NULL
-};
-
-/***************************************************************************/
-
-void __init config_BSP(char *commandp, int size)
-{
-#if defined(CONFIG_NETtel)
-       /* Copy command line from FLASH to local buffer... */
-       memcpy(commandp, (char *) 0xf0004000, size);
-       commandp[size-1] = 0;
-#endif /* CONFIG_NETtel */
-
-       mach_sched_init = hw_timer_init;
-
-       /* Only support the external interrupts on their primary level */
-       mcf_mapirq2imr(25, MCFINTC_EINT1);
-       mcf_mapirq2imr(28, MCFINTC_EINT4);
-       mcf_mapirq2imr(31, MCFINTC_EINT7);
-}
-
-/***************************************************************************/
diff --git a/arch/m68k/platform/coldfire/m520x.c b/arch/m68k/platform/coldfire/m520x.c
deleted file mode 100644 (file)
index 4040a3c..0000000
+++ /dev/null
@@ -1,180 +0,0 @@
-/***************************************************************************/
-
-/*
- *  linux/arch/m68knommu/platform/520x/config.c
- *
- *  Copyright (C) 2005,      Freescale (www.freescale.com)
- *  Copyright (C) 2005,      Intec Automation (mike@steroidmicros.com)
- *  Copyright (C) 1999-2007, Greg Ungerer (gerg@snapgear.com)
- *  Copyright (C) 2001-2003, SnapGear Inc. (www.snapgear.com)
- */
-
-/***************************************************************************/
-
-#include <linux/kernel.h>
-#include <linux/param.h>
-#include <linux/init.h>
-#include <linux/io.h>
-#include <asm/machdep.h>
-#include <asm/coldfire.h>
-#include <asm/mcfsim.h>
-#include <asm/mcfuart.h>
-#include <asm/mcfclk.h>
-
-/***************************************************************************/
-
-DEFINE_CLK(0, "flexbus", 2, MCF_CLK);
-DEFINE_CLK(0, "fec.0", 12, MCF_CLK);
-DEFINE_CLK(0, "edma", 17, MCF_CLK);
-DEFINE_CLK(0, "intc.0", 18, MCF_CLK);
-DEFINE_CLK(0, "iack.0", 21, MCF_CLK);
-DEFINE_CLK(0, "mcfi2c.0", 22, MCF_CLK);
-DEFINE_CLK(0, "mcfqspi.0", 23, MCF_CLK);
-DEFINE_CLK(0, "mcfuart.0", 24, MCF_BUSCLK);
-DEFINE_CLK(0, "mcfuart.1", 25, MCF_BUSCLK);
-DEFINE_CLK(0, "mcfuart.2", 26, MCF_BUSCLK);
-DEFINE_CLK(0, "mcftmr.0", 28, MCF_CLK);
-DEFINE_CLK(0, "mcftmr.1", 29, MCF_CLK);
-DEFINE_CLK(0, "mcftmr.2", 30, MCF_CLK);
-DEFINE_CLK(0, "mcftmr.3", 31, MCF_CLK);
-
-DEFINE_CLK(0, "mcfpit.0", 32, MCF_CLK);
-DEFINE_CLK(0, "mcfpit.1", 33, MCF_CLK);
-DEFINE_CLK(0, "mcfeport.0", 34, MCF_CLK);
-DEFINE_CLK(0, "mcfwdt.0", 35, MCF_CLK);
-DEFINE_CLK(0, "pll.0", 36, MCF_CLK);
-DEFINE_CLK(0, "sys.0", 40, MCF_BUSCLK);
-DEFINE_CLK(0, "gpio.0", 41, MCF_BUSCLK);
-DEFINE_CLK(0, "sdram.0", 42, MCF_CLK);
-
-struct clk *mcf_clks[] = {
-       &__clk_0_2, /* flexbus */
-       &__clk_0_12, /* fec.0 */
-       &__clk_0_17, /* edma */
-       &__clk_0_18, /* intc.0 */
-       &__clk_0_21, /* iack.0 */
-       &__clk_0_22, /* mcfi2c.0 */
-       &__clk_0_23, /* mcfqspi.0 */
-       &__clk_0_24, /* mcfuart.0 */
-       &__clk_0_25, /* mcfuart.1 */
-       &__clk_0_26, /* mcfuart.2 */
-       &__clk_0_28, /* mcftmr.0 */
-       &__clk_0_29, /* mcftmr.1 */
-       &__clk_0_30, /* mcftmr.2 */
-       &__clk_0_31, /* mcftmr.3 */
-
-       &__clk_0_32, /* mcfpit.0 */
-       &__clk_0_33, /* mcfpit.1 */
-       &__clk_0_34, /* mcfeport.0 */
-       &__clk_0_35, /* mcfwdt.0 */
-       &__clk_0_36, /* pll.0 */
-       &__clk_0_40, /* sys.0 */
-       &__clk_0_41, /* gpio.0 */
-       &__clk_0_42, /* sdram.0 */
-NULL,
-};
-
-static struct clk * const enable_clks[] __initconst = {
-       &__clk_0_2, /* flexbus */
-       &__clk_0_18, /* intc.0 */
-       &__clk_0_21, /* iack.0 */
-       &__clk_0_24, /* mcfuart.0 */
-       &__clk_0_25, /* mcfuart.1 */
-       &__clk_0_26, /* mcfuart.2 */
-
-       &__clk_0_32, /* mcfpit.0 */
-       &__clk_0_33, /* mcfpit.1 */
-       &__clk_0_34, /* mcfeport.0 */
-       &__clk_0_36, /* pll.0 */
-       &__clk_0_40, /* sys.0 */
-       &__clk_0_41, /* gpio.0 */
-       &__clk_0_42, /* sdram.0 */
-};
-
-static struct clk * const disable_clks[] __initconst = {
-       &__clk_0_12, /* fec.0 */
-       &__clk_0_17, /* edma */
-       &__clk_0_22, /* mcfi2c.0 */
-       &__clk_0_23, /* mcfqspi.0 */
-       &__clk_0_28, /* mcftmr.0 */
-       &__clk_0_29, /* mcftmr.1 */
-       &__clk_0_30, /* mcftmr.2 */
-       &__clk_0_31, /* mcftmr.3 */
-       &__clk_0_35, /* mcfwdt.0 */
-};
-
-
-static void __init m520x_clk_init(void)
-{
-       unsigned i;
-
-       /* make sure these clocks are enabled */
-       for (i = 0; i < ARRAY_SIZE(enable_clks); ++i)
-               __clk_init_enabled(enable_clks[i]);
-       /* make sure these clocks are disabled */
-       for (i = 0; i < ARRAY_SIZE(disable_clks); ++i)
-               __clk_init_disabled(disable_clks[i]);
-}
-
-/***************************************************************************/
-
-static void __init m520x_qspi_init(void)
-{
-#if IS_ENABLED(CONFIG_SPI_COLDFIRE_QSPI)
-       u16 par;
-       /* setup Port QS for QSPI with gpio CS control */
-       writeb(0x3f, MCF_GPIO_PAR_QSPI);
-       /* make U1CTS and U2RTS gpio for cs_control */
-       par = readw(MCF_GPIO_PAR_UART);
-       par &= 0x00ff;
-       writew(par, MCF_GPIO_PAR_UART);
-#endif /* IS_ENABLED(CONFIG_SPI_COLDFIRE_QSPI) */
-}
-
-/***************************************************************************/
-
-static void __init m520x_uarts_init(void)
-{
-       u16 par;
-       u8 par2;
-
-       /* UART0 and UART1 GPIO pin setup */
-       par = readw(MCF_GPIO_PAR_UART);
-       par |= MCF_GPIO_PAR_UART_PAR_UTXD0 | MCF_GPIO_PAR_UART_PAR_URXD0;
-       par |= MCF_GPIO_PAR_UART_PAR_UTXD1 | MCF_GPIO_PAR_UART_PAR_URXD1;
-       writew(par, MCF_GPIO_PAR_UART);
-
-       /* UART1 GPIO pin setup */
-       par2 = readb(MCF_GPIO_PAR_FECI2C);
-       par2 &= ~0x0F;
-       par2 |= MCF_GPIO_PAR_FECI2C_PAR_SCL_UTXD2 |
-               MCF_GPIO_PAR_FECI2C_PAR_SDA_URXD2;
-       writeb(par2, MCF_GPIO_PAR_FECI2C);
-}
-
-/***************************************************************************/
-
-static void __init m520x_fec_init(void)
-{
-       u8 v;
-
-       /* Set multi-function pins to ethernet mode */
-       v = readb(MCF_GPIO_PAR_FEC);
-       writeb(v | 0xf0, MCF_GPIO_PAR_FEC);
-
-       v = readb(MCF_GPIO_PAR_FECI2C);
-       writeb(v | 0x0f, MCF_GPIO_PAR_FECI2C);
-}
-
-/***************************************************************************/
-
-void __init config_BSP(char *commandp, int size)
-{
-       mach_sched_init = hw_timer_init;
-       m520x_clk_init();
-       m520x_uarts_init();
-       m520x_fec_init();
-       m520x_qspi_init();
-}
-
-/***************************************************************************/
diff --git a/arch/m68k/platform/coldfire/m523x.c b/arch/m68k/platform/coldfire/m523x.c
deleted file mode 100644 (file)
index 6b7135e..0000000
+++ /dev/null
@@ -1,86 +0,0 @@
-/***************************************************************************/
-
-/*
- *     linux/arch/m68knommu/platform/523x/config.c
- *
- *     Sub-architcture dependent initialization code for the Freescale
- *     523x CPUs.
- *
- *     Copyright (C) 1999-2005, Greg Ungerer (gerg@snapgear.com)
- *     Copyright (C) 2001-2003, SnapGear Inc. (www.snapgear.com)
- */
-
-/***************************************************************************/
-
-#include <linux/kernel.h>
-#include <linux/param.h>
-#include <linux/init.h>
-#include <linux/io.h>
-#include <asm/machdep.h>
-#include <asm/coldfire.h>
-#include <asm/mcfsim.h>
-#include <asm/mcfclk.h>
-
-/***************************************************************************/
-
-DEFINE_CLK(pll, "pll.0", MCF_CLK);
-DEFINE_CLK(sys, "sys.0", MCF_BUSCLK);
-DEFINE_CLK(mcfpit0, "mcfpit.0", MCF_CLK);
-DEFINE_CLK(mcfpit1, "mcfpit.1", MCF_CLK);
-DEFINE_CLK(mcfpit2, "mcfpit.2", MCF_CLK);
-DEFINE_CLK(mcfpit3, "mcfpit.3", MCF_CLK);
-DEFINE_CLK(mcfuart0, "mcfuart.0", MCF_BUSCLK);
-DEFINE_CLK(mcfuart1, "mcfuart.1", MCF_BUSCLK);
-DEFINE_CLK(mcfuart2, "mcfuart.2", MCF_BUSCLK);
-DEFINE_CLK(mcfqspi0, "mcfqspi.0", MCF_BUSCLK);
-DEFINE_CLK(fec0, "fec.0", MCF_BUSCLK);
-
-struct clk *mcf_clks[] = {
-       &clk_pll,
-       &clk_sys,
-       &clk_mcfpit0,
-       &clk_mcfpit1,
-       &clk_mcfpit2,
-       &clk_mcfpit3,
-       &clk_mcfuart0,
-       &clk_mcfuart1,
-       &clk_mcfuart2,
-       &clk_mcfqspi0,
-       &clk_fec0,
-       NULL
-};
-
-/***************************************************************************/
-
-static void __init m523x_qspi_init(void)
-{
-#if IS_ENABLED(CONFIG_SPI_COLDFIRE_QSPI)
-       u16 par;
-
-       /* setup QSPS pins for QSPI with gpio CS control */
-       writeb(0x1f, MCFGPIO_PAR_QSPI);
-       /* and CS2 & CS3 as gpio */
-       par = readw(MCFGPIO_PAR_TIMER);
-       par &= 0x3f3f;
-       writew(par, MCFGPIO_PAR_TIMER);
-#endif /* IS_ENABLED(CONFIG_SPI_COLDFIRE_QSPI) */
-}
-
-/***************************************************************************/
-
-static void __init m523x_fec_init(void)
-{
-       /* Set multi-function pins to ethernet use */
-       writeb(readb(MCFGPIO_PAR_FECI2C) | 0xf0, MCFGPIO_PAR_FECI2C);
-}
-
-/***************************************************************************/
-
-void __init config_BSP(char *commandp, int size)
-{
-       mach_sched_init = hw_timer_init;
-       m523x_fec_init();
-       m523x_qspi_init();
-}
-
-/***************************************************************************/
diff --git a/arch/m68k/platform/coldfire/m5249.c b/arch/m68k/platform/coldfire/m5249.c
deleted file mode 100644 (file)
index f6253a3..0000000
+++ /dev/null
@@ -1,126 +0,0 @@
-/***************************************************************************/
-
-/*
- *     linux/arch/m68knommu/platform/5249/config.c
- *
- *     Copyright (C) 2002, Greg Ungerer (gerg@snapgear.com)
- */
-
-/***************************************************************************/
-
-#include <linux/kernel.h>
-#include <linux/param.h>
-#include <linux/init.h>
-#include <linux/io.h>
-#include <linux/platform_device.h>
-#include <asm/machdep.h>
-#include <asm/coldfire.h>
-#include <asm/mcfsim.h>
-#include <asm/mcfclk.h>
-
-/***************************************************************************/
-
-DEFINE_CLK(pll, "pll.0", MCF_CLK);
-DEFINE_CLK(sys, "sys.0", MCF_BUSCLK);
-DEFINE_CLK(mcftmr0, "mcftmr.0", MCF_BUSCLK);
-DEFINE_CLK(mcftmr1, "mcftmr.1", MCF_BUSCLK);
-DEFINE_CLK(mcfuart0, "mcfuart.0", MCF_BUSCLK);
-DEFINE_CLK(mcfuart1, "mcfuart.1", MCF_BUSCLK);
-DEFINE_CLK(mcfqspi0, "mcfqspi.0", MCF_BUSCLK);
-
-struct clk *mcf_clks[] = {
-       &clk_pll,
-       &clk_sys,
-       &clk_mcftmr0,
-       &clk_mcftmr1,
-       &clk_mcfuart0,
-       &clk_mcfuart1,
-       &clk_mcfqspi0,
-       NULL
-};
-
-/***************************************************************************/
-
-#ifdef CONFIG_M5249C3
-
-static struct resource m5249_smc91x_resources[] = {
-       {
-               .start          = 0xe0000300,
-               .end            = 0xe0000300 + 0x100,
-               .flags          = IORESOURCE_MEM,
-       },
-       {
-               .start          = MCF_IRQ_GPIO6,
-               .end            = MCF_IRQ_GPIO6,
-               .flags          = IORESOURCE_IRQ,
-       },
-};
-
-static struct platform_device m5249_smc91x = {
-       .name                   = "smc91x",
-       .id                     = 0,
-       .num_resources          = ARRAY_SIZE(m5249_smc91x_resources),
-       .resource               = m5249_smc91x_resources,
-};
-
-#endif /* CONFIG_M5249C3 */
-
-static struct platform_device *m5249_devices[] __initdata = {
-#ifdef CONFIG_M5249C3
-       &m5249_smc91x,
-#endif
-};
-
-/***************************************************************************/
-
-static void __init m5249_qspi_init(void)
-{
-#if IS_ENABLED(CONFIG_SPI_COLDFIRE_QSPI)
-       /* QSPI irq setup */
-       writeb(MCFSIM_ICR_AUTOVEC | MCFSIM_ICR_LEVEL4 | MCFSIM_ICR_PRI0,
-              MCFSIM_QSPIICR);
-       mcf_mapirq2imr(MCF_IRQ_QSPI, MCFINTC_QSPI);
-#endif /* IS_ENABLED(CONFIG_SPI_COLDFIRE_QSPI) */
-}
-
-/***************************************************************************/
-
-#ifdef CONFIG_M5249C3
-
-static void __init m5249_smc91x_init(void)
-{
-       u32  gpio;
-
-       /* Set the GPIO line as interrupt source for smc91x device */
-       gpio = readl(MCFSIM2_GPIOINTENABLE);
-       writel(gpio | 0x40, MCFSIM2_GPIOINTENABLE);
-
-       gpio = readl(MCFINTC2_INTPRI5);
-       writel(gpio | 0x04000000, MCFINTC2_INTPRI5);
-}
-
-#endif /* CONFIG_M5249C3 */
-
-/***************************************************************************/
-
-void __init config_BSP(char *commandp, int size)
-{
-       mach_sched_init = hw_timer_init;
-
-#ifdef CONFIG_M5249C3
-       m5249_smc91x_init();
-#endif
-       m5249_qspi_init();
-}
-
-/***************************************************************************/
-
-static int __init init_BSP(void)
-{
-       platform_add_devices(m5249_devices, ARRAY_SIZE(m5249_devices));
-       return 0;
-}
-
-arch_initcall(init_BSP);
-
-/***************************************************************************/
diff --git a/arch/m68k/platform/coldfire/m525x.c b/arch/m68k/platform/coldfire/m525x.c
deleted file mode 100644 (file)
index 1adba39..0000000
+++ /dev/null
@@ -1,88 +0,0 @@
-/***************************************************************************/
-
-/*
- *     525x.c
- *
- *     Copyright (C) 2012, Steven King <sfking@fdwdc.com>
- */
-
-/***************************************************************************/
-
-#include <linux/kernel.h>
-#include <linux/param.h>
-#include <linux/init.h>
-#include <linux/io.h>
-#include <linux/platform_device.h>
-#include <asm/machdep.h>
-#include <asm/coldfire.h>
-#include <asm/mcfsim.h>
-#include <asm/mcfclk.h>
-
-/***************************************************************************/
-
-DEFINE_CLK(pll, "pll.0", MCF_CLK);
-DEFINE_CLK(sys, "sys.0", MCF_BUSCLK);
-DEFINE_CLK(mcftmr0, "mcftmr.0", MCF_BUSCLK);
-DEFINE_CLK(mcftmr1, "mcftmr.1", MCF_BUSCLK);
-DEFINE_CLK(mcfuart0, "mcfuart.0", MCF_BUSCLK);
-DEFINE_CLK(mcfuart1, "mcfuart.1", MCF_BUSCLK);
-DEFINE_CLK(mcfqspi0, "mcfqspi.0", MCF_BUSCLK);
-
-struct clk *mcf_clks[] = {
-       &clk_pll,
-       &clk_sys,
-       &clk_mcftmr0,
-       &clk_mcftmr1,
-       &clk_mcfuart0,
-       &clk_mcfuart1,
-       &clk_mcfqspi0,
-       NULL
-};
-
-/***************************************************************************/
-
-static void __init m525x_qspi_init(void)
-{
-#if IS_ENABLED(CONFIG_SPI_COLDFIRE_QSPI)
-       /* set the GPIO function for the qspi cs gpios */
-       /* FIXME: replace with pinmux/pinctl support */
-       u32 f = readl(MCFSIM2_GPIOFUNC);
-       f |= (1 << MCFQSPI_CS2) | (1 << MCFQSPI_CS1) | (1 << MCFQSPI_CS0);
-       writel(f, MCFSIM2_GPIOFUNC);
-
-       /* QSPI irq setup */
-       writeb(MCFSIM_ICR_AUTOVEC | MCFSIM_ICR_LEVEL4 | MCFSIM_ICR_PRI0,
-              MCFSIM_QSPIICR);
-       mcf_mapirq2imr(MCF_IRQ_QSPI, MCFINTC_QSPI);
-#endif /* IS_ENABLED(CONFIG_SPI_COLDFIRE_QSPI) */
-}
-
-static void __init m525x_i2c_init(void)
-{
-#if IS_ENABLED(CONFIG_I2C_COLDFIRE)
-       u32 r;
-
-       /* first I2C controller uses regular irq setup */
-       writeb(MCFSIM_ICR_AUTOVEC | MCFSIM_ICR_LEVEL5 | MCFSIM_ICR_PRI0,
-               MCFSIM_I2CICR);
-       mcf_mapirq2imr(MCF_IRQ_I2C0, MCFINTC_I2C);
-
-       /* second I2C controller is completely different */
-       r = readl(MCFINTC2_INTPRI_REG(MCF_IRQ_I2C1));
-       r &= ~MCFINTC2_INTPRI_BITS(0xf, MCF_IRQ_I2C1);
-       r |= MCFINTC2_INTPRI_BITS(0x5, MCF_IRQ_I2C1);
-       writel(r, MCFINTC2_INTPRI_REG(MCF_IRQ_I2C1));
-#endif /* IS_ENABLED(CONFIG_I2C_COLDFIRE) */
-}
-
-/***************************************************************************/
-
-void __init config_BSP(char *commandp, int size)
-{
-       mach_sched_init = hw_timer_init;
-
-       m525x_qspi_init();
-       m525x_i2c_init();
-}
-
-/***************************************************************************/
diff --git a/arch/m68k/platform/coldfire/m5272.c b/arch/m68k/platform/coldfire/m5272.c
deleted file mode 100644 (file)
index 8a4d3cc..0000000
+++ /dev/null
@@ -1,135 +0,0 @@
-/***************************************************************************/
-
-/*
- *     linux/arch/m68knommu/platform/5272/config.c
- *
- *     Copyright (C) 1999-2002, Greg Ungerer (gerg@snapgear.com)
- *     Copyright (C) 2001-2002, SnapGear Inc. (www.snapgear.com)
- */
-
-/***************************************************************************/
-
-#include <linux/kernel.h>
-#include <linux/param.h>
-#include <linux/init.h>
-#include <linux/io.h>
-#include <linux/phy.h>
-#include <linux/phy_fixed.h>
-#include <asm/machdep.h>
-#include <asm/coldfire.h>
-#include <asm/mcfsim.h>
-#include <asm/mcfuart.h>
-#include <asm/mcfclk.h>
-
-/***************************************************************************/
-
-/*
- *     Some platforms need software versions of the GPIO data registers.
- */
-unsigned short ppdata;
-unsigned char ledbank = 0xff;
-
-/***************************************************************************/
-
-DEFINE_CLK(pll, "pll.0", MCF_CLK);
-DEFINE_CLK(sys, "sys.0", MCF_BUSCLK);
-DEFINE_CLK(mcftmr0, "mcftmr.0", MCF_BUSCLK);
-DEFINE_CLK(mcftmr1, "mcftmr.1", MCF_BUSCLK);
-DEFINE_CLK(mcftmr2, "mcftmr.2", MCF_BUSCLK);
-DEFINE_CLK(mcftmr3, "mcftmr.3", MCF_BUSCLK);
-DEFINE_CLK(mcfuart0, "mcfuart.0", MCF_BUSCLK);
-DEFINE_CLK(mcfuart1, "mcfuart.1", MCF_BUSCLK);
-DEFINE_CLK(mcfqspi0, "mcfqspi.0", MCF_BUSCLK);
-DEFINE_CLK(fec0, "fec.0", MCF_BUSCLK);
-
-struct clk *mcf_clks[] = {
-       &clk_pll,
-       &clk_sys,
-       &clk_mcftmr0,
-       &clk_mcftmr1,
-       &clk_mcftmr2,
-       &clk_mcftmr3,
-       &clk_mcfuart0,
-       &clk_mcfuart1,
-       &clk_mcfqspi0,
-       &clk_fec0,
-       NULL
-};
-
-/***************************************************************************/
-
-static void __init m5272_uarts_init(void)
-{
-       u32 v;
-
-       /* Enable the output lines for the serial ports */
-       v = readl(MCFSIM_PBCNT);
-       v = (v & ~0x000000ff) | 0x00000055;
-       writel(v, MCFSIM_PBCNT);
-
-       v = readl(MCFSIM_PDCNT);
-       v = (v & ~0x000003fc) | 0x000002a8;
-       writel(v, MCFSIM_PDCNT);
-}
-
-/***************************************************************************/
-
-static void m5272_cpu_reset(void)
-{
-       local_irq_disable();
-       /* Set watchdog to reset, and enabled */
-       __raw_writew(0, MCFSIM_WIRR);
-       __raw_writew(1, MCFSIM_WRRR);
-       __raw_writew(0, MCFSIM_WCR);
-       for (;;)
-               /* wait for watchdog to timeout */;
-}
-
-/***************************************************************************/
-
-void __init config_BSP(char *commandp, int size)
-{
-#if defined (CONFIG_MOD5272)
-       /* Set base of device vectors to be 64 */
-       writeb(0x40, MCFSIM_PIVR);
-#endif
-
-#if defined(CONFIG_NETtel) || defined(CONFIG_SCALES)
-       /* Copy command line from FLASH to local buffer... */
-       memcpy(commandp, (char *) 0xf0004000, size);
-       commandp[size-1] = 0;
-#elif defined(CONFIG_CANCam)
-       /* Copy command line from FLASH to local buffer... */
-       memcpy(commandp, (char *) 0xf0010000, size);
-       commandp[size-1] = 0;
-#endif
-
-       mach_reset = m5272_cpu_reset;
-       mach_sched_init = hw_timer_init;
-}
-
-/***************************************************************************/
-
-/*
- * Some 5272 based boards have the FEC ethernet diectly connected to
- * an ethernet switch. In this case we need to use the fixed phy type,
- * and we need to declare it early in boot.
- */
-static struct fixed_phy_status nettel_fixed_phy_status __initdata = {
-       .link   = 1,
-       .speed  = 100,
-       .duplex = 0,
-};
-
-/***************************************************************************/
-
-static int __init init_BSP(void)
-{
-       m5272_uarts_init();
-       fixed_phy_add(PHY_POLL, 0, &nettel_fixed_phy_status);
-       return 0;
-}
-
-arch_initcall(init_BSP);
-
-/***************************************************************************/
diff --git a/arch/m68k/platform/coldfire/m527x.c b/arch/m68k/platform/coldfire/m527x.c
deleted file mode 100644 (file)
index 62d81ef..0000000
+++ /dev/null
@@ -1,126 +0,0 @@
-/***************************************************************************/
-
-/*
- *     linux/arch/m68knommu/platform/527x/config.c
- *
- *     Sub-architcture dependent initialization code for the Freescale
- *     5270/5271 CPUs.
- *
- *     Copyright (C) 1999-2004, Greg Ungerer (gerg@snapgear.com)
- *     Copyright (C) 2001-2004, SnapGear Inc. (www.snapgear.com)
- */
-
-/***************************************************************************/
-
-#include <linux/kernel.h>
-#include <linux/param.h>
-#include <linux/init.h>
-#include <linux/io.h>
-#include <asm/machdep.h>
-#include <asm/coldfire.h>
-#include <asm/mcfsim.h>
-#include <asm/mcfuart.h>
-#include <asm/mcfclk.h>
-
-/***************************************************************************/
-
-DEFINE_CLK(pll, "pll.0", MCF_CLK);
-DEFINE_CLK(sys, "sys.0", MCF_BUSCLK);
-DEFINE_CLK(mcfpit0, "mcfpit.0", MCF_CLK);
-DEFINE_CLK(mcfpit1, "mcfpit.1", MCF_CLK);
-DEFINE_CLK(mcfpit2, "mcfpit.2", MCF_CLK);
-DEFINE_CLK(mcfpit3, "mcfpit.3", MCF_CLK);
-DEFINE_CLK(mcfuart0, "mcfuart.0", MCF_BUSCLK);
-DEFINE_CLK(mcfuart1, "mcfuart.1", MCF_BUSCLK);
-DEFINE_CLK(mcfuart2, "mcfuart.2", MCF_BUSCLK);
-DEFINE_CLK(mcfqspi0, "mcfqspi.0", MCF_BUSCLK);
-DEFINE_CLK(fec0, "fec.0", MCF_BUSCLK);
-DEFINE_CLK(fec1, "fec.1", MCF_BUSCLK);
-
-struct clk *mcf_clks[] = {
-       &clk_pll,
-       &clk_sys,
-       &clk_mcfpit0,
-       &clk_mcfpit1,
-       &clk_mcfpit2,
-       &clk_mcfpit3,
-       &clk_mcfuart0,
-       &clk_mcfuart1,
-       &clk_mcfuart2,
-       &clk_mcfqspi0,
-       &clk_fec0,
-       &clk_fec1,
-       NULL
-};
-
-/***************************************************************************/
-
-static void __init m527x_qspi_init(void)
-{
-#if IS_ENABLED(CONFIG_SPI_COLDFIRE_QSPI)
-#if defined(CONFIG_M5271)
-       u16 par;
-
-       /* setup QSPS pins for QSPI with gpio CS control */
-       writeb(0x1f, MCFGPIO_PAR_QSPI);
-       /* and CS2 & CS3 as gpio */
-       par = readw(MCFGPIO_PAR_TIMER);
-       par &= 0x3f3f;
-       writew(par, MCFGPIO_PAR_TIMER);
-#elif defined(CONFIG_M5275)
-       /* setup QSPS pins for QSPI with gpio CS control */
-       writew(0x003e, MCFGPIO_PAR_QSPI);
-#endif
-#endif /* IS_ENABLED(CONFIG_SPI_COLDFIRE_QSPI) */
-}
-
-/***************************************************************************/
-
-static void __init m527x_uarts_init(void)
-{
-       u16 sepmask;
-
-       /*
-        * External Pin Mask Setting & Enable External Pin for Interface
-        */
-       sepmask = readw(MCFGPIO_PAR_UART);
-       sepmask |= UART0_ENABLE_MASK | UART1_ENABLE_MASK | UART2_ENABLE_MASK;
-       writew(sepmask, MCFGPIO_PAR_UART);
-}
-
-/***************************************************************************/
-
-static void __init m527x_fec_init(void)
-{
-       u16 par;
-       u8 v;
-
-       /* Set multi-function pins to ethernet mode for fec0 */
-#if defined(CONFIG_M5271)
-       v = readb(MCFGPIO_PAR_FECI2C);
-       writeb(v | 0xf0, MCFGPIO_PAR_FECI2C);
-#else
-       par = readw(MCFGPIO_PAR_FECI2C);
-       writew(par | 0xf00, MCFGPIO_PAR_FECI2C);
-       v = readb(MCFGPIO_PAR_FEC0HL);
-       writeb(v | 0xc0, MCFGPIO_PAR_FEC0HL);
-
-       /* Set multi-function pins to ethernet mode for fec1 */
-       par = readw(MCFGPIO_PAR_FECI2C);
-       writew(par | 0xa0, MCFGPIO_PAR_FECI2C);
-       v = readb(MCFGPIO_PAR_FEC1HL);
-       writeb(v | 0xc0, MCFGPIO_PAR_FEC1HL);
-#endif
-}
-
-/***************************************************************************/
-
-void __init config_BSP(char *commandp, int size)
-{
-       mach_sched_init = hw_timer_init;
-       m527x_uarts_init();
-       m527x_fec_init();
-       m527x_qspi_init();
-}
-
-/***************************************************************************/
diff --git a/arch/m68k/platform/coldfire/m528x.c b/arch/m68k/platform/coldfire/m528x.c
deleted file mode 100644 (file)
index 21cd161..0000000
+++ /dev/null
@@ -1,132 +0,0 @@
-/***************************************************************************/
-
-/*
- *     linux/arch/m68knommu/platform/528x/config.c
- *
- *     Sub-architcture dependent initialization code for the Freescale
- *     5280, 5281 and 5282 CPUs.
- *
- *     Copyright (C) 1999-2003, Greg Ungerer (gerg@snapgear.com)
- *     Copyright (C) 2001-2003, SnapGear Inc. (www.snapgear.com)
- */
-
-/***************************************************************************/
-
-#include <linux/kernel.h>
-#include <linux/param.h>
-#include <linux/init.h>
-#include <linux/platform_device.h>
-#include <linux/io.h>
-#include <asm/machdep.h>
-#include <asm/coldfire.h>
-#include <asm/mcfsim.h>
-#include <asm/mcfuart.h>
-#include <asm/mcfclk.h>
-
-/***************************************************************************/
-
-DEFINE_CLK(pll, "pll.0", MCF_CLK);
-DEFINE_CLK(sys, "sys.0", MCF_BUSCLK);
-DEFINE_CLK(mcfpit0, "mcfpit.0", MCF_CLK);
-DEFINE_CLK(mcfpit1, "mcfpit.1", MCF_CLK);
-DEFINE_CLK(mcfpit2, "mcfpit.2", MCF_CLK);
-DEFINE_CLK(mcfpit3, "mcfpit.3", MCF_CLK);
-DEFINE_CLK(mcfuart0, "mcfuart.0", MCF_BUSCLK);
-DEFINE_CLK(mcfuart1, "mcfuart.1", MCF_BUSCLK);
-DEFINE_CLK(mcfuart2, "mcfuart.2", MCF_BUSCLK);
-DEFINE_CLK(mcfqspi0, "mcfqspi.0", MCF_BUSCLK);
-DEFINE_CLK(fec0, "fec.0", MCF_BUSCLK);
-
-struct clk *mcf_clks[] = {
-       &clk_pll,
-       &clk_sys,
-       &clk_mcfpit0,
-       &clk_mcfpit1,
-       &clk_mcfpit2,
-       &clk_mcfpit3,
-       &clk_mcfuart0,
-       &clk_mcfuart1,
-       &clk_mcfuart2,
-       &clk_mcfqspi0,
-       &clk_fec0,
-       NULL
-};
-
-/***************************************************************************/
-
-static void __init m528x_qspi_init(void)
-{
-#if IS_ENABLED(CONFIG_SPI_COLDFIRE_QSPI)
-       /* setup Port QS for QSPI with gpio CS control */
-       __raw_writeb(0x07, MCFGPIO_PQSPAR);
-#endif /* IS_ENABLED(CONFIG_SPI_COLDFIRE_QSPI) */
-}
-
-/***************************************************************************/
-
-static void __init m528x_uarts_init(void)
-{
-       u8 port;
-
-       /* make sure PUAPAR is set for UART0 and UART1 */
-       port = readb(MCFGPIO_PUAPAR);
-       port |= 0x03 | (0x03 << 2);
-       writeb(port, MCFGPIO_PUAPAR);
-}
-
-/***************************************************************************/
-
-static void __init m528x_fec_init(void)
-{
-       u16 v16;
-
-       /* Set multi-function pins to ethernet mode for fec0 */
-       v16 = readw(MCFGPIO_PASPAR);
-       writew(v16 | 0xf00, MCFGPIO_PASPAR);
-       writeb(0xc0, MCFGPIO_PEHLPAR);
-}
-
-/***************************************************************************/
-
-#ifdef CONFIG_WILDFIRE
-void wildfire_halt(void)
-{
-       writeb(0, 0x30000007);
-       writeb(0x2, 0x30000007);
-}
-#endif
-
-#ifdef CONFIG_WILDFIREMOD
-void wildfiremod_halt(void)
-{
-       printk(KERN_INFO "WildFireMod hibernating...\n");
-
-       /* Set portE.5 to Digital IO */
-       MCF5282_GPIO_PEPAR &= ~(1 << (5 * 2));
-
-       /* Make portE.5 an output */
-       MCF5282_GPIO_DDRE |= (1 << 5);
-
-       /* Now toggle portE.5 from low to high */
-       MCF5282_GPIO_PORTE &= ~(1 << 5);
-       MCF5282_GPIO_PORTE |= (1 << 5);
-
-       printk(KERN_EMERG "Failed to hibernate. Halting!\n");
-}
-#endif
-
-void __init config_BSP(char *commandp, int size)
-{
-#ifdef CONFIG_WILDFIRE
-       mach_halt = wildfire_halt;
-#endif
-#ifdef CONFIG_WILDFIREMOD
-       mach_halt = wildfiremod_halt;
-#endif
-       mach_sched_init = hw_timer_init;
-       m528x_uarts_init();
-       m528x_fec_init();
-       m528x_qspi_init();
-}
-
-/***************************************************************************/
diff --git a/arch/m68k/platform/coldfire/m5307.c b/arch/m68k/platform/coldfire/m5307.c
deleted file mode 100644 (file)
index 8874353..0000000
+++ /dev/null
@@ -1,78 +0,0 @@
-/***************************************************************************/
-
-/*
- *     linux/arch/m68knommu/platform/5307/config.c
- *
- *     Copyright (C) 1999-2002, Greg Ungerer (gerg@snapgear.com)
- *     Copyright (C) 2000, Lineo (www.lineo.com)
- */
-
-/***************************************************************************/
-
-#include <linux/kernel.h>
-#include <linux/param.h>
-#include <linux/init.h>
-#include <linux/io.h>
-#include <asm/machdep.h>
-#include <asm/coldfire.h>
-#include <asm/mcfsim.h>
-#include <asm/mcfwdebug.h>
-#include <asm/mcfclk.h>
-
-/***************************************************************************/
-
-/*
- *     Some platforms need software versions of the GPIO data registers.
- */
-unsigned short ppdata;
-unsigned char ledbank = 0xff;
-
-/***************************************************************************/
-
-DEFINE_CLK(pll, "pll.0", MCF_CLK);
-DEFINE_CLK(sys, "sys.0", MCF_BUSCLK);
-DEFINE_CLK(mcftmr0, "mcftmr.0", MCF_BUSCLK);
-DEFINE_CLK(mcftmr1, "mcftmr.1", MCF_BUSCLK);
-DEFINE_CLK(mcfuart0, "mcfuart.0", MCF_BUSCLK);
-DEFINE_CLK(mcfuart1, "mcfuart.1", MCF_BUSCLK);
-
-struct clk *mcf_clks[] = {
-       &clk_pll,
-       &clk_sys,
-       &clk_mcftmr0,
-       &clk_mcftmr1,
-       &clk_mcfuart0,
-       &clk_mcfuart1,
-       NULL
-};
-
-/***************************************************************************/
-
-void __init config_BSP(char *commandp, int size)
-{
-#if defined(CONFIG_NETtel) || \
-    defined(CONFIG_SECUREEDGEMP3) || defined(CONFIG_CLEOPATRA)
-       /* Copy command line from FLASH to local buffer... */
-       memcpy(commandp, (char *) 0xf0004000, size);
-       commandp[size-1] = 0;
-#endif
-
-       mach_sched_init = hw_timer_init;
-
-       /* Only support the external interrupts on their primary level */
-       mcf_mapirq2imr(25, MCFINTC_EINT1);
-       mcf_mapirq2imr(27, MCFINTC_EINT3);
-       mcf_mapirq2imr(29, MCFINTC_EINT5);
-       mcf_mapirq2imr(31, MCFINTC_EINT7);
-
-#ifdef CONFIG_BDM_DISABLE
-       /*
-        * Disable the BDM clocking.  This also turns off most of the rest of
-        * the BDM device.  This is good for EMC reasons. This option is not
-        * incompatible with the memory protection option.
-        */
-       wdebug(MCFDEBUG_CSR, MCFDEBUG_CSR_PSTCLK);
-#endif
-}
-
-/***************************************************************************/
diff --git a/arch/m68k/platform/coldfire/m53xx.c b/arch/m68k/platform/coldfire/m53xx.c
deleted file mode 100644 (file)
index 80879a7..0000000
+++ /dev/null
@@ -1,588 +0,0 @@
-/***************************************************************************/
-
-/*
- *     m53xx.c -- platform support for ColdFire 53xx based boards
- *
- *     Copyright (C) 1999-2002, Greg Ungerer (gerg@snapgear.com)
- *     Copyright (C) 2000, Lineo (www.lineo.com)
- *     Yaroslav Vinogradov yaroslav.vinogradov@freescale.com
- *     Copyright Freescale Semiconductor, Inc 2006
- *     Copyright (c) 2006, emlix, Sebastian Hess <shess@hessware.de>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- */
-
-/***************************************************************************/
-
-#include <linux/kernel.h>
-#include <linux/param.h>
-#include <linux/init.h>
-#include <linux/io.h>
-#include <asm/machdep.h>
-#include <asm/coldfire.h>
-#include <asm/mcfsim.h>
-#include <asm/mcfuart.h>
-#include <asm/mcfdma.h>
-#include <asm/mcfwdebug.h>
-#include <asm/mcfclk.h>
-
-/***************************************************************************/
-
-DEFINE_CLK(0, "flexbus", 2, MCF_CLK);
-DEFINE_CLK(0, "mcfcan.0", 8, MCF_CLK);
-DEFINE_CLK(0, "fec.0", 12, MCF_CLK);
-DEFINE_CLK(0, "edma", 17, MCF_CLK);
-DEFINE_CLK(0, "intc.0", 18, MCF_CLK);
-DEFINE_CLK(0, "intc.1", 19, MCF_CLK);
-DEFINE_CLK(0, "iack.0", 21, MCF_CLK);
-DEFINE_CLK(0, "mcfi2c.0", 22, MCF_CLK);
-DEFINE_CLK(0, "mcfqspi.0", 23, MCF_CLK);
-DEFINE_CLK(0, "mcfuart.0", 24, MCF_BUSCLK);
-DEFINE_CLK(0, "mcfuart.1", 25, MCF_BUSCLK);
-DEFINE_CLK(0, "mcfuart.2", 26, MCF_BUSCLK);
-DEFINE_CLK(0, "mcftmr.0", 28, MCF_CLK);
-DEFINE_CLK(0, "mcftmr.1", 29, MCF_CLK);
-DEFINE_CLK(0, "mcftmr.2", 30, MCF_CLK);
-DEFINE_CLK(0, "mcftmr.3", 31, MCF_CLK);
-
-DEFINE_CLK(0, "mcfpit.0", 32, MCF_CLK);
-DEFINE_CLK(0, "mcfpit.1", 33, MCF_CLK);
-DEFINE_CLK(0, "mcfpit.2", 34, MCF_CLK);
-DEFINE_CLK(0, "mcfpit.3", 35, MCF_CLK);
-DEFINE_CLK(0, "mcfpwm.0", 36, MCF_CLK);
-DEFINE_CLK(0, "mcfeport.0", 37, MCF_CLK);
-DEFINE_CLK(0, "mcfwdt.0", 38, MCF_CLK);
-DEFINE_CLK(0, "sys.0", 40, MCF_BUSCLK);
-DEFINE_CLK(0, "gpio.0", 41, MCF_BUSCLK);
-DEFINE_CLK(0, "mcfrtc.0", 42, MCF_CLK);
-DEFINE_CLK(0, "mcflcd.0", 43, MCF_CLK);
-DEFINE_CLK(0, "mcfusb-otg.0", 44, MCF_CLK);
-DEFINE_CLK(0, "mcfusb-host.0", 45, MCF_CLK);
-DEFINE_CLK(0, "sdram.0", 46, MCF_CLK);
-DEFINE_CLK(0, "ssi.0", 47, MCF_CLK);
-DEFINE_CLK(0, "pll.0", 48, MCF_CLK);
-
-DEFINE_CLK(1, "mdha.0", 32, MCF_CLK);
-DEFINE_CLK(1, "skha.0", 33, MCF_CLK);
-DEFINE_CLK(1, "rng.0", 34, MCF_CLK);
-
-struct clk *mcf_clks[] = {
-       &__clk_0_2,     /* flexbus */
-       &__clk_0_8,     /* mcfcan.0 */
-       &__clk_0_12,    /* fec.0 */
-       &__clk_0_17,    /* edma */
-       &__clk_0_18,    /* intc.0 */
-       &__clk_0_19,    /* intc.1 */
-       &__clk_0_21,    /* iack.0 */
-       &__clk_0_22,    /* mcfi2c.0 */
-       &__clk_0_23,    /* mcfqspi.0 */
-       &__clk_0_24,    /* mcfuart.0 */
-       &__clk_0_25,    /* mcfuart.1 */
-       &__clk_0_26,    /* mcfuart.2 */
-       &__clk_0_28,    /* mcftmr.0 */
-       &__clk_0_29,    /* mcftmr.1 */
-       &__clk_0_30,    /* mcftmr.2 */
-       &__clk_0_31,    /* mcftmr.3 */
-
-       &__clk_0_32,    /* mcfpit.0 */
-       &__clk_0_33,    /* mcfpit.1 */
-       &__clk_0_34,    /* mcfpit.2 */
-       &__clk_0_35,    /* mcfpit.3 */
-       &__clk_0_36,    /* mcfpwm.0 */
-       &__clk_0_37,    /* mcfeport.0 */
-       &__clk_0_38,    /* mcfwdt.0 */
-       &__clk_0_40,    /* sys.0 */
-       &__clk_0_41,    /* gpio.0 */
-       &__clk_0_42,    /* mcfrtc.0 */
-       &__clk_0_43,    /* mcflcd.0 */
-       &__clk_0_44,    /* mcfusb-otg.0 */
-       &__clk_0_45,    /* mcfusb-host.0 */
-       &__clk_0_46,    /* sdram.0 */
-       &__clk_0_47,    /* ssi.0 */
-       &__clk_0_48,    /* pll.0 */
-
-       &__clk_1_32,    /* mdha.0 */
-       &__clk_1_33,    /* skha.0 */
-       &__clk_1_34,    /* rng.0 */
-       NULL,
-};
-
-static struct clk * const enable_clks[] __initconst = {
-       &__clk_0_2,     /* flexbus */
-       &__clk_0_18,    /* intc.0 */
-       &__clk_0_19,    /* intc.1 */
-       &__clk_0_21,    /* iack.0 */
-       &__clk_0_24,    /* mcfuart.0 */
-       &__clk_0_25,    /* mcfuart.1 */
-       &__clk_0_26,    /* mcfuart.2 */
-       &__clk_0_28,    /* mcftmr.0 */
-       &__clk_0_29,    /* mcftmr.1 */
-       &__clk_0_32,    /* mcfpit.0 */
-       &__clk_0_33,    /* mcfpit.1 */
-       &__clk_0_37,    /* mcfeport.0 */
-       &__clk_0_40,    /* sys.0 */
-       &__clk_0_41,    /* gpio.0 */
-       &__clk_0_46,    /* sdram.0 */
-       &__clk_0_48,    /* pll.0 */
-};
-
-static struct clk * const disable_clks[] __initconst = {
-       &__clk_0_8,     /* mcfcan.0 */
-       &__clk_0_12,    /* fec.0 */
-       &__clk_0_17,    /* edma */
-       &__clk_0_22,    /* mcfi2c.0 */
-       &__clk_0_23,    /* mcfqspi.0 */
-       &__clk_0_30,    /* mcftmr.2 */
-       &__clk_0_31,    /* mcftmr.3 */
-       &__clk_0_34,    /* mcfpit.2 */
-       &__clk_0_35,    /* mcfpit.3 */
-       &__clk_0_36,    /* mcfpwm.0 */
-       &__clk_0_38,    /* mcfwdt.0 */
-       &__clk_0_42,    /* mcfrtc.0 */
-       &__clk_0_43,    /* mcflcd.0 */
-       &__clk_0_44,    /* mcfusb-otg.0 */
-       &__clk_0_45,    /* mcfusb-host.0 */
-       &__clk_0_47,    /* ssi.0 */
-       &__clk_1_32,    /* mdha.0 */
-       &__clk_1_33,    /* skha.0 */
-       &__clk_1_34,    /* rng.0 */
-};
-
-
-static void __init m53xx_clk_init(void)
-{
-       unsigned i;
-
-       /* make sure these clocks are enabled */
-       for (i = 0; i < ARRAY_SIZE(enable_clks); ++i)
-               __clk_init_enabled(enable_clks[i]);
-       /* make sure these clocks are disabled */
-       for (i = 0; i < ARRAY_SIZE(disable_clks); ++i)
-               __clk_init_disabled(disable_clks[i]);
-}
-
-/***************************************************************************/
-
-static void __init m53xx_qspi_init(void)
-{
-#if IS_ENABLED(CONFIG_SPI_COLDFIRE_QSPI)
-       /* setup QSPS pins for QSPI with gpio CS control */
-       writew(0x01f0, MCFGPIO_PAR_QSPI);
-#endif /* IS_ENABLED(CONFIG_SPI_COLDFIRE_QSPI) */
-}
-
-/***************************************************************************/
-
-static void __init m53xx_uarts_init(void)
-{
-       /* UART GPIO initialization */
-       writew(readw(MCFGPIO_PAR_UART) | 0x0FFF, MCFGPIO_PAR_UART);
-}
-
-/***************************************************************************/
-
-static void __init m53xx_fec_init(void)
-{
-       u8 v;
-
-       /* Set multi-function pins to ethernet mode for fec0 */
-       v = readb(MCFGPIO_PAR_FECI2C);
-       v |= MCF_GPIO_PAR_FECI2C_PAR_MDC_EMDC |
-               MCF_GPIO_PAR_FECI2C_PAR_MDIO_EMDIO;
-       writeb(v, MCFGPIO_PAR_FECI2C);
-
-       v = readb(MCFGPIO_PAR_FEC);
-       v = MCF_GPIO_PAR_FEC_PAR_FEC_7W_FEC | MCF_GPIO_PAR_FEC_PAR_FEC_MII_FEC;
-       writeb(v, MCFGPIO_PAR_FEC);
-}
-
-/***************************************************************************/
-
-void __init config_BSP(char *commandp, int size)
-{
-#if !defined(CONFIG_BOOTPARAM)
-       /* Copy command line from FLASH to local buffer... */
-       memcpy(commandp, (char *) 0x4000, 4);
-       if(strncmp(commandp, "kcl ", 4) == 0){
-               memcpy(commandp, (char *) 0x4004, size);
-               commandp[size-1] = 0;
-       } else {
-               memset(commandp, 0, size);
-       }
-#endif
-       mach_sched_init = hw_timer_init;
-       m53xx_clk_init();
-       m53xx_uarts_init();
-       m53xx_fec_init();
-       m53xx_qspi_init();
-
-#ifdef CONFIG_BDM_DISABLE
-       /*
-        * Disable the BDM clocking.  This also turns off most of the rest of
-        * the BDM device.  This is good for EMC reasons. This option is not
-        * incompatible with the memory protection option.
-        */
-       wdebug(MCFDEBUG_CSR, MCFDEBUG_CSR_PSTCLK);
-#endif
-}
-
-/***************************************************************************/
-/* Board initialization */
-/***************************************************************************/
-/* 
- * PLL min/max specifications
- */
-#define MAX_FVCO       500000  /* KHz */
-#define MAX_FSYS       80000   /* KHz */
-#define MIN_FSYS       58333   /* KHz */
-#define FREF           16000   /* KHz */
-
-
-#define MAX_MFD                135     /* Multiplier */
-#define MIN_MFD                88      /* Multiplier */
-#define BUSDIV         6       /* Divider */
-
-/*
- * Low Power Divider specifications
- */
-#define MIN_LPD                (1 << 0)    /* Divider (not encoded) */
-#define MAX_LPD                (1 << 15)   /* Divider (not encoded) */
-#define DEFAULT_LPD    (1 << 1)        /* Divider (not encoded) */
-
-#define SYS_CLK_KHZ    80000
-#define SYSTEM_PERIOD  12.5
-/*
- *  SDRAM Timing Parameters
- */  
-#define SDRAM_BL       8       /* # of beats in a burst */
-#define SDRAM_TWR      2       /* in clocks */
-#define SDRAM_CASL     2.5     /* CASL in clocks */
-#define SDRAM_TRCD     2       /* in clocks */
-#define SDRAM_TRP      2       /* in clocks */
-#define SDRAM_TRFC     7       /* in clocks */
-#define SDRAM_TREFI    7800    /* in ns */
-
-#define EXT_SRAM_ADDRESS       (0xC0000000)
-#define FLASH_ADDRESS          (0x00000000)
-#define SDRAM_ADDRESS          (0x40000000)
-
-#define NAND_FLASH_ADDRESS     (0xD0000000)
-
-int sys_clk_khz = 0;
-int sys_clk_mhz = 0;
-
-void wtm_init(void);
-void scm_init(void);
-void gpio_init(void);
-void fbcs_init(void);
-void sdramc_init(void);
-int  clock_pll (int fsys, int flags);
-int  clock_limp (int);
-int  clock_exit_limp (void);
-int  get_sys_clock (void);
-
-asmlinkage void __init sysinit(void)
-{
-       sys_clk_khz = clock_pll(0, 0);
-       sys_clk_mhz = sys_clk_khz/1000;
-       
-       wtm_init();
-       scm_init();
-       gpio_init();
-       fbcs_init();
-       sdramc_init();
-}
-
-void wtm_init(void)
-{
-       /* Disable watchdog timer */
-       writew(0, MCF_WTM_WCR);
-}
-
-#define MCF_SCM_BCR_GBW                (0x00000100)
-#define MCF_SCM_BCR_GBR                (0x00000200)
-
-void scm_init(void)
-{
-       /* All masters are trusted */
-       writel(0x77777777, MCF_SCM_MPR);
-    
-       /* Allow supervisor/user, read/write, and trusted/untrusted
-          access to all slaves */
-       writel(0, MCF_SCM_PACRA);
-       writel(0, MCF_SCM_PACRB);
-       writel(0, MCF_SCM_PACRC);
-       writel(0, MCF_SCM_PACRD);
-       writel(0, MCF_SCM_PACRE);
-       writel(0, MCF_SCM_PACRF);
-
-       /* Enable bursts */
-       writel(MCF_SCM_BCR_GBR | MCF_SCM_BCR_GBW, MCF_SCM_BCR);
-}
-
-
-void fbcs_init(void)
-{
-       writeb(0x3E, MCFGPIO_PAR_CS);
-
-       /* Latch chip select */
-       writel(0x10080000, MCF_FBCS1_CSAR);
-
-       writel(0x002A3780, MCF_FBCS1_CSCR);
-       writel(MCF_FBCS_CSMR_BAM_2M | MCF_FBCS_CSMR_V, MCF_FBCS1_CSMR);
-
-       /* Initialize latch to drive signals to inactive states */
-       writew(0xffff, 0x10080000);
-
-       /* External SRAM */
-       writel(EXT_SRAM_ADDRESS, MCF_FBCS1_CSAR);
-       writel(MCF_FBCS_CSCR_PS_16 |
-               MCF_FBCS_CSCR_AA |
-               MCF_FBCS_CSCR_SBM |
-               MCF_FBCS_CSCR_WS(1),
-               MCF_FBCS1_CSCR);
-       writel(MCF_FBCS_CSMR_BAM_512K | MCF_FBCS_CSMR_V, MCF_FBCS1_CSMR);
-
-       /* Boot Flash connected to FBCS0 */
-       writel(FLASH_ADDRESS, MCF_FBCS0_CSAR);
-       writel(MCF_FBCS_CSCR_PS_16 |
-               MCF_FBCS_CSCR_BEM |
-               MCF_FBCS_CSCR_AA |
-               MCF_FBCS_CSCR_SBM |
-               MCF_FBCS_CSCR_WS(7),
-               MCF_FBCS0_CSCR);
-       writel(MCF_FBCS_CSMR_BAM_32M | MCF_FBCS_CSMR_V, MCF_FBCS0_CSMR);
-}
-
-void sdramc_init(void)
-{
-       /*
-        * Check to see if the SDRAM has already been initialized
-        * by a run control tool
-        */
-       if (!(readl(MCF_SDRAMC_SDCR) & MCF_SDRAMC_SDCR_REF)) {
-               /* SDRAM chip select initialization */
-               
-               /* Initialize SDRAM chip select */
-               writel(MCF_SDRAMC_SDCS_BA(SDRAM_ADDRESS) |
-                       MCF_SDRAMC_SDCS_CSSZ(MCF_SDRAMC_SDCS_CSSZ_32MBYTE),
-                       MCF_SDRAMC_SDCS0);
-
-       /*
-        * Basic configuration and initialization
-        */
-       writel(MCF_SDRAMC_SDCFG1_SRD2RW((int)((SDRAM_CASL + 2) + 0.5)) |
-               MCF_SDRAMC_SDCFG1_SWT2RD(SDRAM_TWR + 1) |
-               MCF_SDRAMC_SDCFG1_RDLAT((int)((SDRAM_CASL * 2) + 2)) |
-               MCF_SDRAMC_SDCFG1_ACT2RW((int)(SDRAM_TRCD + 0.5)) |
-               MCF_SDRAMC_SDCFG1_PRE2ACT((int)(SDRAM_TRP + 0.5)) |
-               MCF_SDRAMC_SDCFG1_REF2ACT((int)(SDRAM_TRFC + 0.5)) |
-               MCF_SDRAMC_SDCFG1_WTLAT(3),
-               MCF_SDRAMC_SDCFG1);
-       writel(MCF_SDRAMC_SDCFG2_BRD2PRE(SDRAM_BL / 2 + 1) |
-               MCF_SDRAMC_SDCFG2_BWT2RW(SDRAM_BL / 2 + SDRAM_TWR) |
-               MCF_SDRAMC_SDCFG2_BRD2WT((int)((SDRAM_CASL + SDRAM_BL / 2 - 1.0) + 0.5)) |
-               MCF_SDRAMC_SDCFG2_BL(SDRAM_BL - 1),
-               MCF_SDRAMC_SDCFG2);
-
-            
-       /*
-        * Precharge and enable write to SDMR
-        */
-       writel(MCF_SDRAMC_SDCR_MODE_EN |
-               MCF_SDRAMC_SDCR_CKE |
-               MCF_SDRAMC_SDCR_DDR |
-               MCF_SDRAMC_SDCR_MUX(1) |
-               MCF_SDRAMC_SDCR_RCNT((int)(((SDRAM_TREFI / (SYSTEM_PERIOD * 64)) - 1) + 0.5)) |
-               MCF_SDRAMC_SDCR_PS_16 |
-               MCF_SDRAMC_SDCR_IPALL,
-               MCF_SDRAMC_SDCR);
-
-       /*
-        * Write extended mode register
-        */
-       writel(MCF_SDRAMC_SDMR_BNKAD_LEMR |
-               MCF_SDRAMC_SDMR_AD(0x0) |
-               MCF_SDRAMC_SDMR_CMD,
-               MCF_SDRAMC_SDMR);
-
-       /*
-        * Write mode register and reset DLL
-        */
-       writel(MCF_SDRAMC_SDMR_BNKAD_LMR |
-               MCF_SDRAMC_SDMR_AD(0x163) |
-               MCF_SDRAMC_SDMR_CMD,
-               MCF_SDRAMC_SDMR);
-
-       /*
-        * Execute a PALL command
-        */
-       writel(readl(MCF_SDRAMC_SDCR) | MCF_SDRAMC_SDCR_IPALL, MCF_SDRAMC_SDCR);
-
-       /*
-        * Perform two REF cycles
-        */
-       writel(readl(MCF_SDRAMC_SDCR) | MCF_SDRAMC_SDCR_IREF, MCF_SDRAMC_SDCR);
-       writel(readl(MCF_SDRAMC_SDCR) | MCF_SDRAMC_SDCR_IREF, MCF_SDRAMC_SDCR);
-
-       /*
-        * Write mode register and clear reset DLL
-        */
-       writel(MCF_SDRAMC_SDMR_BNKAD_LMR |
-               MCF_SDRAMC_SDMR_AD(0x063) |
-               MCF_SDRAMC_SDMR_CMD,
-               MCF_SDRAMC_SDMR);
-                               
-       /*
-        * Enable auto refresh and lock SDMR
-        */
-       writel(readl(MCF_SDRAMC_SDCR) & ~MCF_SDRAMC_SDCR_MODE_EN,
-               MCF_SDRAMC_SDCR);
-       writel(MCF_SDRAMC_SDCR_REF | MCF_SDRAMC_SDCR_DQS_OE(0xC),
-               MCF_SDRAMC_SDCR);
-       }
-}
-
-void gpio_init(void)
-{
-       /* Enable UART0 pins */
-       writew(MCF_GPIO_PAR_UART_PAR_URXD0 | MCF_GPIO_PAR_UART_PAR_UTXD0,
-               MCFGPIO_PAR_UART);
-
-       /*
-        * Initialize TIN3 as a GPIO output to enable the write
-        * half of the latch.
-        */
-       writeb(0x00, MCFGPIO_PAR_TIMER);
-       writeb(0x08, MCFGPIO_PDDR_TIMER);
-       writeb(0x00, MCFGPIO_PCLRR_TIMER);
-}
-
-int clock_pll(int fsys, int flags)
-{
-       int fref, temp, fout, mfd;
-       u32 i;
-
-       fref = FREF;
-        
-       if (fsys == 0) {
-               /* Return current PLL output */
-               mfd = readb(MCF_PLL_PFDR);
-
-               return (fref * mfd / (BUSDIV * 4));
-       }
-
-       /* Check bounds of requested system clock */
-       if (fsys > MAX_FSYS)
-               fsys = MAX_FSYS;
-       if (fsys < MIN_FSYS)
-               fsys = MIN_FSYS;
-
-       /* Multiplying by 100 when calculating the temp value,
-          and then dividing by 100 to calculate the mfd allows
-          for exact values without needing to include floating
-          point libraries. */
-       temp = 100 * fsys / fref;
-       mfd = 4 * BUSDIV * temp / 100;
-                       
-       /* Determine the output frequency for selected values */
-       fout = (fref * mfd / (BUSDIV * 4));
-
-       /*
-        * Check to see if the SDRAM has already been initialized.
-        * If it has then the SDRAM needs to be put into self refresh
-        * mode before reprogramming the PLL.
-        */
-       if (readl(MCF_SDRAMC_SDCR) & MCF_SDRAMC_SDCR_REF)
-               /* Put SDRAM into self refresh mode */
-               writel(readl(MCF_SDRAMC_SDCR) & ~MCF_SDRAMC_SDCR_CKE,
-                       MCF_SDRAMC_SDCR);
-
-       /*
-        * Initialize the PLL to generate the new system clock frequency.
-        * The device must be put into LIMP mode to reprogram the PLL.
-        */
-
-       /* Enter LIMP mode */
-       clock_limp(DEFAULT_LPD);
-                                       
-       /* Reprogram PLL for desired fsys */
-       writeb(MCF_PLL_PODR_CPUDIV(BUSDIV/3) | MCF_PLL_PODR_BUSDIV(BUSDIV),
-               MCF_PLL_PODR);
-                                               
-       writeb(mfd, MCF_PLL_PFDR);
-               
-       /* Exit LIMP mode */
-       clock_exit_limp();
-       
-       /*
-        * Return the SDRAM to normal operation if it is in use.
-        */
-       if (readl(MCF_SDRAMC_SDCR) & MCF_SDRAMC_SDCR_REF)
-               /* Exit self refresh mode */
-               writel(readl(MCF_SDRAMC_SDCR) | MCF_SDRAMC_SDCR_CKE,
-                       MCF_SDRAMC_SDCR);
-
-       /* Errata - workaround for SDRAM opeartion after exiting LIMP mode */
-       writel(MCF_SDRAMC_REFRESH, MCF_SDRAMC_LIMP_FIX);
-
-       /* wait for DQS logic to relock */
-       for (i = 0; i < 0x200; i++)
-               ;
-
-       return fout;
-}
-
-int clock_limp(int div)
-{
-       u32 temp;
-
-       /* Check bounds of divider */
-       if (div < MIN_LPD)
-               div = MIN_LPD;
-       if (div > MAX_LPD)
-               div = MAX_LPD;
-    
-       /* Save of the current value of the SSIDIV so we don't
-          overwrite the value*/
-       temp = readw(MCF_CCM_CDR) & MCF_CCM_CDR_SSIDIV(0xF);
-      
-       /* Apply the divider to the system clock */
-       writew(MCF_CCM_CDR_LPDIV(div) | MCF_CCM_CDR_SSIDIV(temp), MCF_CCM_CDR);
-    
-       writew(readw(MCF_CCM_MISCCR) | MCF_CCM_MISCCR_LIMP, MCF_CCM_MISCCR);
-    
-       return (FREF/(3*(1 << div)));
-}
-
-int clock_exit_limp(void)
-{
-       int fout;
-       
-       /* Exit LIMP mode */
-       writew(readw(MCF_CCM_MISCCR) & ~MCF_CCM_MISCCR_LIMP, MCF_CCM_MISCCR);
-
-       /* Wait for PLL to lock */
-       while (!(readw(MCF_CCM_MISCCR) & MCF_CCM_MISCCR_PLL_LOCK))
-               ;
-       
-       fout = get_sys_clock();
-
-       return fout;
-}
-
-int get_sys_clock(void)
-{
-       int divider;
-       
-       /* Test to see if device is in LIMP mode */
-       if (readw(MCF_CCM_MISCCR) & MCF_CCM_MISCCR_LIMP) {
-               divider = readw(MCF_CCM_CDR) & MCF_CCM_CDR_LPDIV(0xF);
-               return (FREF/(2 << divider));
-       }
-       else
-               return (FREF * readb(MCF_PLL_PFDR)) / (BUSDIV * 4);
-}
diff --git a/arch/m68k/platform/coldfire/m5407.c b/arch/m68k/platform/coldfire/m5407.c
deleted file mode 100644 (file)
index 2fb3cdb..0000000
+++ /dev/null
@@ -1,53 +0,0 @@
-/***************************************************************************/
-
-/*
- *     linux/arch/m68knommu/platform/5407/config.c
- *
- *     Copyright (C) 1999-2002, Greg Ungerer (gerg@snapgear.com)
- *     Copyright (C) 2000, Lineo (www.lineo.com)
- */
-
-/***************************************************************************/
-
-#include <linux/kernel.h>
-#include <linux/param.h>
-#include <linux/init.h>
-#include <linux/io.h>
-#include <asm/machdep.h>
-#include <asm/coldfire.h>
-#include <asm/mcfsim.h>
-#include <asm/mcfclk.h>
-
-/***************************************************************************/
-
-DEFINE_CLK(pll, "pll.0", MCF_CLK);
-DEFINE_CLK(sys, "sys.0", MCF_BUSCLK);
-DEFINE_CLK(mcftmr0, "mcftmr.0", MCF_BUSCLK);
-DEFINE_CLK(mcftmr1, "mcftmr.1", MCF_BUSCLK);
-DEFINE_CLK(mcfuart0, "mcfuart.0", MCF_BUSCLK);
-DEFINE_CLK(mcfuart1, "mcfuart.1", MCF_BUSCLK);
-
-struct clk *mcf_clks[] = {
-       &clk_pll,
-       &clk_sys,
-       &clk_mcftmr0,
-       &clk_mcftmr1,
-       &clk_mcfuart0,
-       &clk_mcfuart1,
-       NULL
-};
-
-/***************************************************************************/
-
-void __init config_BSP(char *commandp, int size)
-{
-       mach_sched_init = hw_timer_init;
-
-       /* Only support the external interrupts on their primary level */
-       mcf_mapirq2imr(25, MCFINTC_EINT1);
-       mcf_mapirq2imr(27, MCFINTC_EINT3);
-       mcf_mapirq2imr(29, MCFINTC_EINT5);
-       mcf_mapirq2imr(31, MCFINTC_EINT7);
-}
-
-/***************************************************************************/
diff --git a/arch/m68k/platform/coldfire/m5441x.c b/arch/m68k/platform/coldfire/m5441x.c
deleted file mode 100644 (file)
index 98a13cc..0000000
+++ /dev/null
@@ -1,261 +0,0 @@
-/*
- *     m5441x.c -- support for Coldfire m5441x processors
- *
- *     (C) Copyright Steven King <sfking@fdwdc.com>
- */
-
-#include <linux/kernel.h>
-#include <linux/param.h>
-#include <linux/init.h>
-#include <linux/io.h>
-#include <linux/clk.h>
-#include <asm/machdep.h>
-#include <asm/coldfire.h>
-#include <asm/mcfsim.h>
-#include <asm/mcfuart.h>
-#include <asm/mcfdma.h>
-#include <asm/mcfclk.h>
-
-DEFINE_CLK(0, "flexbus", 2, MCF_CLK);
-DEFINE_CLK(0, "mcfcan.0", 8, MCF_CLK);
-DEFINE_CLK(0, "mcfcan.1", 9, MCF_CLK);
-DEFINE_CLK(0, "mcfi2c.1", 14, MCF_CLK);
-DEFINE_CLK(0, "mcfdspi.1", 15, MCF_CLK);
-DEFINE_CLK(0, "edma", 17, MCF_CLK);
-DEFINE_CLK(0, "intc.0", 18, MCF_CLK);
-DEFINE_CLK(0, "intc.1", 19, MCF_CLK);
-DEFINE_CLK(0, "intc.2", 20, MCF_CLK);
-DEFINE_CLK(0, "mcfi2c.0", 22, MCF_CLK);
-DEFINE_CLK(0, "mcfdspi.0", 23, MCF_CLK);
-DEFINE_CLK(0, "mcfuart.0", 24, MCF_BUSCLK);
-DEFINE_CLK(0, "mcfuart.1", 25, MCF_BUSCLK);
-DEFINE_CLK(0, "mcfuart.2", 26, MCF_BUSCLK);
-DEFINE_CLK(0, "mcfuart.3", 27, MCF_BUSCLK);
-DEFINE_CLK(0, "mcftmr.0", 28, MCF_CLK);
-DEFINE_CLK(0, "mcftmr.1", 29, MCF_CLK);
-DEFINE_CLK(0, "mcftmr.2", 30, MCF_CLK);
-DEFINE_CLK(0, "mcftmr.3", 31, MCF_CLK);
-DEFINE_CLK(0, "mcfpit.0", 32, MCF_CLK);
-DEFINE_CLK(0, "mcfpit.1", 33, MCF_CLK);
-DEFINE_CLK(0, "mcfpit.2", 34, MCF_CLK);
-DEFINE_CLK(0, "mcfpit.3", 35, MCF_CLK);
-DEFINE_CLK(0, "mcfeport.0", 37, MCF_CLK);
-DEFINE_CLK(0, "mcfadc.0", 38, MCF_CLK);
-DEFINE_CLK(0, "mcfdac.0", 39, MCF_CLK);
-DEFINE_CLK(0, "mcfrtc.0", 42, MCF_CLK);
-DEFINE_CLK(0, "mcfsim.0", 43, MCF_CLK);
-DEFINE_CLK(0, "mcfusb-otg.0", 44, MCF_CLK);
-DEFINE_CLK(0, "mcfusb-host.0", 45, MCF_CLK);
-DEFINE_CLK(0, "mcfddr-sram.0", 46, MCF_CLK);
-DEFINE_CLK(0, "mcfssi.0", 47, MCF_CLK);
-DEFINE_CLK(0, "pll.0", 48, MCF_CLK);
-DEFINE_CLK(0, "mcfrng.0", 49, MCF_CLK);
-DEFINE_CLK(0, "mcfssi.1", 50, MCF_CLK);
-DEFINE_CLK(0, "mcfsdhc.0", 51, MCF_CLK);
-DEFINE_CLK(0, "enet-fec.0", 53, MCF_CLK);
-DEFINE_CLK(0, "enet-fec.1", 54, MCF_CLK);
-DEFINE_CLK(0, "switch.0", 55, MCF_CLK);
-DEFINE_CLK(0, "switch.1", 56, MCF_CLK);
-DEFINE_CLK(0, "nand.0", 63, MCF_CLK);
-
-DEFINE_CLK(1, "mcfow.0", 2, MCF_CLK);
-DEFINE_CLK(1, "mcfi2c.2", 4, MCF_CLK);
-DEFINE_CLK(1, "mcfi2c.3", 5, MCF_CLK);
-DEFINE_CLK(1, "mcfi2c.4", 6, MCF_CLK);
-DEFINE_CLK(1, "mcfi2c.5", 7, MCF_CLK);
-DEFINE_CLK(1, "mcfuart.4", 24, MCF_BUSCLK);
-DEFINE_CLK(1, "mcfuart.5", 25, MCF_BUSCLK);
-DEFINE_CLK(1, "mcfuart.6", 26, MCF_BUSCLK);
-DEFINE_CLK(1, "mcfuart.7", 27, MCF_BUSCLK);
-DEFINE_CLK(1, "mcfuart.8", 28, MCF_BUSCLK);
-DEFINE_CLK(1, "mcfuart.9", 29, MCF_BUSCLK);
-DEFINE_CLK(1, "mcfpwm.0", 34, MCF_BUSCLK);
-DEFINE_CLK(1, "sys.0", 36, MCF_BUSCLK);
-DEFINE_CLK(1, "gpio.0", 37, MCF_BUSCLK);
-
-struct clk *mcf_clks[] = {
-       &__clk_0_2,
-       &__clk_0_8,
-       &__clk_0_9,
-       &__clk_0_14,
-       &__clk_0_15,
-       &__clk_0_17,
-       &__clk_0_18,
-       &__clk_0_19,
-       &__clk_0_20,
-       &__clk_0_22,
-       &__clk_0_23,
-       &__clk_0_24,
-       &__clk_0_25,
-       &__clk_0_26,
-       &__clk_0_27,
-       &__clk_0_28,
-       &__clk_0_29,
-       &__clk_0_30,
-       &__clk_0_31,
-       &__clk_0_32,
-       &__clk_0_33,
-       &__clk_0_34,
-       &__clk_0_35,
-       &__clk_0_37,
-       &__clk_0_38,
-       &__clk_0_39,
-       &__clk_0_42,
-       &__clk_0_43,
-       &__clk_0_44,
-       &__clk_0_45,
-       &__clk_0_46,
-       &__clk_0_47,
-       &__clk_0_48,
-       &__clk_0_49,
-       &__clk_0_50,
-       &__clk_0_51,
-       &__clk_0_53,
-       &__clk_0_54,
-       &__clk_0_55,
-       &__clk_0_56,
-       &__clk_0_63,
-
-       &__clk_1_2,
-       &__clk_1_4,
-       &__clk_1_5,
-       &__clk_1_6,
-       &__clk_1_7,
-       &__clk_1_24,
-       &__clk_1_25,
-       &__clk_1_26,
-       &__clk_1_27,
-       &__clk_1_28,
-       &__clk_1_29,
-       &__clk_1_34,
-       &__clk_1_36,
-       &__clk_1_37,
-       NULL,
-};
-
-
-static struct clk * const enable_clks[] __initconst = {
-       /* make sure these clocks are enabled */
-       &__clk_0_18, /* intc0 */
-       &__clk_0_19, /* intc0 */
-       &__clk_0_20, /* intc0 */
-       &__clk_0_24, /* uart0 */
-       &__clk_0_25, /* uart1 */
-       &__clk_0_26, /* uart2 */
-       &__clk_0_27, /* uart3 */
-
-       &__clk_0_33, /* pit.1 */
-       &__clk_0_37, /* eport */
-       &__clk_0_48, /* pll */
-
-       &__clk_1_36, /* CCM/reset module/Power management */
-       &__clk_1_37, /* gpio */
-};
-static struct clk * const disable_clks[] __initconst = {
-       &__clk_0_8, /* can.0 */
-       &__clk_0_9, /* can.1 */
-       &__clk_0_14, /* i2c.1 */
-       &__clk_0_15, /* dspi.1 */
-       &__clk_0_17, /* eDMA */
-       &__clk_0_22, /* i2c.0 */
-       &__clk_0_23, /* dspi.0 */
-       &__clk_0_28, /* tmr.1 */
-       &__clk_0_29, /* tmr.2 */
-       &__clk_0_30, /* tmr.2 */
-       &__clk_0_31, /* tmr.3 */
-       &__clk_0_32, /* pit.0 */
-       &__clk_0_34, /* pit.2 */
-       &__clk_0_35, /* pit.3 */
-       &__clk_0_38, /* adc */
-       &__clk_0_39, /* dac */
-       &__clk_0_44, /* usb otg */
-       &__clk_0_45, /* usb host */
-       &__clk_0_47, /* ssi.0 */
-       &__clk_0_49, /* rng */
-       &__clk_0_50, /* ssi.1 */
-       &__clk_0_51, /* eSDHC */
-       &__clk_0_53, /* enet-fec */
-       &__clk_0_54, /* enet-fec */
-       &__clk_0_55, /* switch.0 */
-       &__clk_0_56, /* switch.1 */
-
-       &__clk_1_2, /* 1-wire */
-       &__clk_1_4, /* i2c.2 */
-       &__clk_1_5, /* i2c.3 */
-       &__clk_1_6, /* i2c.4 */
-       &__clk_1_7, /* i2c.5 */
-       &__clk_1_24, /* uart 4 */
-       &__clk_1_25, /* uart 5 */
-       &__clk_1_26, /* uart 6 */
-       &__clk_1_27, /* uart 7 */
-       &__clk_1_28, /* uart 8 */
-       &__clk_1_29, /* uart 9 */
-};
-
-static void __init m5441x_clk_init(void)
-{
-       unsigned i;
-
-       for (i = 0; i < ARRAY_SIZE(enable_clks); ++i)
-               __clk_init_enabled(enable_clks[i]);
-       /* make sure these clocks are disabled */
-       for (i = 0; i < ARRAY_SIZE(disable_clks); ++i)
-               __clk_init_disabled(disable_clks[i]);
-}
-
-static void __init m5441x_uarts_init(void)
-{
-       __raw_writeb(0x0f, MCFGPIO_PAR_UART0);
-       __raw_writeb(0x00, MCFGPIO_PAR_UART1);
-       __raw_writeb(0x00, MCFGPIO_PAR_UART2);
-}
-
-static void __init m5441x_fec_init(void)
-{
-       __raw_writeb(0x03, MCFGPIO_PAR_FEC);
-}
-
-void __init config_BSP(char *commandp, int size)
-{
-       m5441x_clk_init();
-       mach_sched_init = hw_timer_init;
-       m5441x_uarts_init();
-       m5441x_fec_init();
-}
-
-
-#if IS_ENABLED(CONFIG_RTC_DRV_M5441x)
-static struct resource m5441x_rtc_resources[] = {
-       {
-               .start          = MCFRTC_BASE,
-               .end            = MCFRTC_BASE + MCFRTC_SIZE - 1,
-               .flags          = IORESOURCE_MEM,
-       },
-       {
-               .start          = MCF_IRQ_RTC,
-               .end            = MCF_IRQ_RTC,
-               .flags          = IORESOURCE_IRQ,
-       },
-};
-
-static struct platform_device m5441x_rtc = {
-       .name                   = "mcfrtc",
-       .id                     = 0,
-       .resource               = m5441x_rtc_resources,
-       .num_resources          = ARRAY_SIZE(m5441x_rtc_resources),
-};
-#endif
-
-static struct platform_device *m5441x_devices[] __initdata = {
-#if IS_ENABLED(CONFIG_RTC_DRV_M5441x)
-       &m5441x_rtc,
-#endif
-};
-
-static int __init init_BSP(void)
-{
-       platform_add_devices(m5441x_devices, ARRAY_SIZE(m5441x_devices));
-       return 0;
-}
-
-arch_initcall(init_BSP);
diff --git a/arch/m68k/platform/coldfire/m54xx.c b/arch/m68k/platform/coldfire/m54xx.c
deleted file mode 100644 (file)
index 952da53..0000000
+++ /dev/null
@@ -1,129 +0,0 @@
-/***************************************************************************/
-
-/*
- *     linux/arch/m68knommu/platform/54xx/config.c
- *
- *     Copyright (C) 2010, Philippe De Muyter <phdm@macqel.be>
- */
-
-/***************************************************************************/
-
-#include <linux/kernel.h>
-#include <linux/param.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/io.h>
-#include <linux/mm.h>
-#include <linux/clk.h>
-#include <linux/bootmem.h>
-#include <asm/pgalloc.h>
-#include <asm/machdep.h>
-#include <asm/coldfire.h>
-#include <asm/m54xxsim.h>
-#include <asm/mcfuart.h>
-#include <asm/mcfclk.h>
-#include <asm/m54xxgpt.h>
-#include <asm/mcfclk.h>
-#ifdef CONFIG_MMU
-#include <asm/mmu_context.h>
-#endif
-
-/***************************************************************************/
-
-DEFINE_CLK(pll, "pll.0", MCF_CLK);
-DEFINE_CLK(sys, "sys.0", MCF_BUSCLK);
-DEFINE_CLK(mcfslt0, "mcfslt.0", MCF_BUSCLK);
-DEFINE_CLK(mcfslt1, "mcfslt.1", MCF_BUSCLK);
-DEFINE_CLK(mcfuart0, "mcfuart.0", MCF_BUSCLK);
-DEFINE_CLK(mcfuart1, "mcfuart.1", MCF_BUSCLK);
-DEFINE_CLK(mcfuart2, "mcfuart.2", MCF_BUSCLK);
-DEFINE_CLK(mcfuart3, "mcfuart.3", MCF_BUSCLK);
-
-struct clk *mcf_clks[] = {
-       &clk_pll,
-       &clk_sys,
-       &clk_mcfslt0,
-       &clk_mcfslt1,
-       &clk_mcfuart0,
-       &clk_mcfuart1,
-       &clk_mcfuart2,
-       &clk_mcfuart3,
-       NULL
-};
-
-/***************************************************************************/
-
-static void __init m54xx_uarts_init(void)
-{
-       /* enable io pins */
-       __raw_writeb(MCF_PAR_PSC_TXD | MCF_PAR_PSC_RXD, MCFGPIO_PAR_PSC0);
-       __raw_writeb(MCF_PAR_PSC_TXD | MCF_PAR_PSC_RXD | MCF_PAR_PSC_RTS_RTS,
-               MCFGPIO_PAR_PSC1);
-       __raw_writeb(MCF_PAR_PSC_TXD | MCF_PAR_PSC_RXD | MCF_PAR_PSC_RTS_RTS |
-               MCF_PAR_PSC_CTS_CTS, MCFGPIO_PAR_PSC2);
-       __raw_writeb(MCF_PAR_PSC_TXD | MCF_PAR_PSC_RXD, MCFGPIO_PAR_PSC3);
-}
-
-/***************************************************************************/
-
-static void mcf54xx_reset(void)
-{
-       /* disable interrupts and enable the watchdog */
-       asm("movew #0x2700, %sr\n");
-       __raw_writel(0, MCF_GPT_GMS0);
-       __raw_writel(MCF_GPT_GCIR_CNT(1), MCF_GPT_GCIR0);
-       __raw_writel(MCF_GPT_GMS_WDEN | MCF_GPT_GMS_CE | MCF_GPT_GMS_TMS(4),
-               MCF_GPT_GMS0);
-}
-
-/***************************************************************************/
-
-#ifdef CONFIG_MMU
-
-unsigned long num_pages;
-
-static void __init mcf54xx_bootmem_alloc(void)
-{
-       unsigned long start_pfn;
-       unsigned long memstart;
-
-       /* _rambase and _ramend will be naturally page aligned */
-       m68k_memory[0].addr = _rambase;
-       m68k_memory[0].size = _ramend - _rambase;
-
-       /* compute total pages in system */
-       num_pages = (_ramend - _rambase) >> PAGE_SHIFT;
-
-       /* page numbers */
-       memstart = PAGE_ALIGN(_ramstart);
-       min_low_pfn = _rambase >> PAGE_SHIFT;
-       start_pfn = memstart >> PAGE_SHIFT;
-       max_low_pfn = _ramend >> PAGE_SHIFT;
-       high_memory = (void *)_ramend;
-
-       m68k_virt_to_node_shift = fls(_ramend - _rambase - 1) - 6;
-       module_fixup(NULL, __start_fixup, __stop_fixup);
-
-       /* setup bootmem data */
-       m68k_setup_node(0);
-       memstart += init_bootmem_node(NODE_DATA(0), start_pfn,
-               min_low_pfn, max_low_pfn);
-       free_bootmem_node(NODE_DATA(0), memstart, _ramend - memstart);
-}
-
-#endif /* CONFIG_MMU */
-
-/***************************************************************************/
-
-void __init config_BSP(char *commandp, int size)
-{
-#ifdef CONFIG_MMU
-       mcf54xx_bootmem_alloc();
-       mmu_context_init();
-#endif
-       mach_reset = mcf54xx_reset;
-       mach_sched_init = hw_timer_init;
-       m54xx_uarts_init();
-}
-
-/***************************************************************************/
diff --git a/arch/m68k/platform/coldfire/mcf8390.c b/arch/m68k/platform/coldfire/mcf8390.c
deleted file mode 100644 (file)
index 23a6874..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * mcf8390.c  -- platform support for 8390 ethernet on many boards
- *
- * (C) Copyright 2012, Greg Ungerer <gerg@uclinux.org>
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file COPYING in the main directory of this archive
- * for more details.
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/resource.h>
-#include <linux/platform_device.h>
-#include <asm/mcf8390.h>
-
-static struct resource mcf8390_resources[] = {
-       {
-               .start  = NE2000_ADDR,
-               .end    = NE2000_ADDR + NE2000_ADDRSIZE - 1,
-               .flags  = IORESOURCE_MEM,
-       },
-       {
-               .start  = NE2000_IRQ_VECTOR,
-               .end    = NE2000_IRQ_VECTOR,
-               .flags  = IORESOURCE_IRQ,
-       },
-};
-
-static int __init mcf8390_platform_init(void)
-{
-       platform_device_register_simple("mcf8390", -1, mcf8390_resources,
-               ARRAY_SIZE(mcf8390_resources));
-       return 0;
-}
-
-arch_initcall(mcf8390_platform_init);
diff --git a/arch/m68k/platform/coldfire/nettel.c b/arch/m68k/platform/coldfire/nettel.c
deleted file mode 100644 (file)
index ddc48ec..0000000
+++ /dev/null
@@ -1,153 +0,0 @@
-/***************************************************************************/
-
-/*
- *     nettel.c -- startup code support for the NETtel boards
- *
- *     Copyright (C) 2009, Greg Ungerer (gerg@snapgear.com)
- */
-
-/***************************************************************************/
-
-#include <linux/kernel.h>
-#include <linux/param.h>
-#include <linux/init.h>
-#include <linux/io.h>
-#include <linux/platform_device.h>
-#include <asm/coldfire.h>
-#include <asm/mcfsim.h>
-#include <asm/nettel.h>
-
-/***************************************************************************/
-
-/*
- * Define the IO and interrupt resources of the 2 SMC9196 interfaces.
- */
-#define        NETTEL_SMC0_ADDR        0x30600300
-#define        NETTEL_SMC0_IRQ         29
-
-#define        NETTEL_SMC1_ADDR        0x30600000
-#define        NETTEL_SMC1_IRQ         27
-
-/*
- * We need some access into the SMC9196 registers. Define those registers
- * we will need here (including the smc91x.h doesn't seem to give us these
- * in a simple form).
- */
-#define        SMC91xx_BANKSELECT      14
-#define        SMC91xx_BASEADDR        2
-#define        SMC91xx_BASEMAC         4
-
-/***************************************************************************/
-
-static struct resource nettel_smc91x_0_resources[] = {
-       {
-               .start          = NETTEL_SMC0_ADDR,
-               .end            = NETTEL_SMC0_ADDR + 0x20,
-               .flags          = IORESOURCE_MEM,
-       },
-       {
-               .start          = NETTEL_SMC0_IRQ,
-               .end            = NETTEL_SMC0_IRQ,
-               .flags          = IORESOURCE_IRQ,
-       },
-};
-
-static struct resource nettel_smc91x_1_resources[] = {
-       {
-               .start          = NETTEL_SMC1_ADDR,
-               .end            = NETTEL_SMC1_ADDR + 0x20,
-               .flags          = IORESOURCE_MEM,
-       },
-       {
-               .start          = NETTEL_SMC1_IRQ,
-               .end            = NETTEL_SMC1_IRQ,
-               .flags          = IORESOURCE_IRQ,
-       },
-};
-
-static struct platform_device nettel_smc91x[] = {
-       {
-               .name                   = "smc91x",
-               .id                     = 0,
-               .num_resources          = ARRAY_SIZE(nettel_smc91x_0_resources),
-               .resource               = nettel_smc91x_0_resources,
-       },
-       {
-               .name                   = "smc91x",
-               .id                     = 1,
-               .num_resources          = ARRAY_SIZE(nettel_smc91x_1_resources),
-               .resource               = nettel_smc91x_1_resources,
-       },
-};
-
-static struct platform_device *nettel_devices[] __initdata = {
-       &nettel_smc91x[0],
-       &nettel_smc91x[1],
-};
-
-/***************************************************************************/
-
-static u8 nettel_macdefault[] __initdata = {
-       0x00, 0xd0, 0xcf, 0x00, 0x00, 0x01,
-};
-
-/*
- * Set flash contained MAC address into SMC9196 core. Make sure the flash
- * MAC address is sane, and not an empty flash. If no good use the Moreton
- * Bay default MAC address instead.
- */
-
-static void __init nettel_smc91x_setmac(unsigned int ioaddr, unsigned int flashaddr)
-{
-       u16 *macp;
-
-       macp = (u16 *) flashaddr;
-       if ((macp[0] == 0xffff) && (macp[1] == 0xffff) && (macp[2] == 0xffff))
-               macp = (u16 *) &nettel_macdefault[0];
-
-       writew(1, NETTEL_SMC0_ADDR + SMC91xx_BANKSELECT);
-       writew(macp[0], ioaddr + SMC91xx_BASEMAC);
-       writew(macp[1], ioaddr + SMC91xx_BASEMAC + 2);
-       writew(macp[2], ioaddr + SMC91xx_BASEMAC + 4);
-}
-
-/***************************************************************************/
-
-/*
- * Re-map the address space of at least one of the SMC ethernet
- * parts. Both parts power up decoding the same address, so we
- * need to move one of them first, before doing anything else.
- */
-
-static void __init nettel_smc91x_init(void)
-{
-       writew(0x00ec, MCFSIM_PADDR);
-       mcf_setppdata(0, 0x0080);
-       writew(1, NETTEL_SMC0_ADDR + SMC91xx_BANKSELECT);
-       writew(0x0067, NETTEL_SMC0_ADDR + SMC91xx_BASEADDR);
-       mcf_setppdata(0x0080, 0);
-
-       /* Set correct chip select timing for SMC9196 accesses */
-       writew(0x1180, MCFSIM_CSCR3);
-
-       /* Set the SMC interrupts to be auto-vectored */
-       mcf_autovector(NETTEL_SMC0_IRQ);
-       mcf_autovector(NETTEL_SMC1_IRQ);
-
-       /* Set MAC addresses from flash for both interfaces */
-       nettel_smc91x_setmac(NETTEL_SMC0_ADDR, 0xf0006000);
-       nettel_smc91x_setmac(NETTEL_SMC1_ADDR, 0xf0006006);
-}
-
-/***************************************************************************/
-
-static int __init init_nettel(void)
-{
-       nettel_smc91x_init();
-       platform_add_devices(nettel_devices, ARRAY_SIZE(nettel_devices));
-       return 0;
-}
-
-arch_initcall(init_nettel);
-
-/***************************************************************************/
diff --git a/arch/m68k/platform/coldfire/pci.c b/arch/m68k/platform/coldfire/pci.c
deleted file mode 100644 (file)
index df96792..0000000
+++ /dev/null
@@ -1,325 +0,0 @@
-/*
- * pci.c -- PCI bus support for ColdFire processors
- *
- * (C) Copyright 2012, Greg Ungerer <gerg@uclinux.com>
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file COPYING in the main directory of this archive
- * for more details.
- */
-
-#include <linux/types.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/interrupt.h>
-#include <linux/irq.h>
-#include <linux/io.h>
-#include <linux/pci.h>
-#include <linux/delay.h>
-#include <asm/coldfire.h>
-#include <asm/mcfsim.h>
-#include <asm/m54xxpci.h>
-
-/*
- * Memory and IO mappings. We use a 1:1 mapping for local host memory to
- * PCI bus memory (no reason not to really). IO space doesn't matter, we
- * always use access functions for that. The device configuration space is
- * mapped over the IO map space when we enable it in the PCICAR register.
- */
-#define        PCI_MEM_PA      0xf0000000              /* Host physical address */
-#define        PCI_MEM_BA      0xf0000000              /* Bus physical address */
-#define        PCI_MEM_SIZE    0x08000000              /* 128 MB */
-#define        PCI_MEM_MASK    (PCI_MEM_SIZE - 1)
-
-#define        PCI_IO_PA       0xf8000000              /* Host physical address */
-#define        PCI_IO_BA       0x00000000              /* Bus physical address */
-#define        PCI_IO_SIZE     0x00010000              /* 64k */
-#define        PCI_IO_MASK     (PCI_IO_SIZE - 1)
-
-static struct pci_bus *rootbus;
-static unsigned long iospace;
-
-/*
- * We need to be carefull probing on bus 0 (directly connected to host
- * bridge). We should only acccess the well defined possible devices in
- * use, ignore aliases and the like.
- */
-static unsigned char mcf_host_slot2sid[32] = {
-       0, 0, 0, 0, 0, 0, 0, 0,
-       0, 0, 0, 0, 0, 0, 0, 0,
-       0, 1, 2, 0, 3, 4, 0, 0,
-       0, 0, 0, 0, 0, 0, 0, 0,
-};
-
-static unsigned char mcf_host_irq[] = {
-       0, 69, 69, 71, 71,
-};
-
-
-static inline void syncio(void)
-{
-       /* The ColdFire "nop" instruction waits for all bus IO to complete */
-       __asm__ __volatile__ ("nop");
-}
-
-/*
- * Configuration space access functions. Configuration space access is
- * through the IO mapping window, enabling it via the PCICAR register.
- */
-static unsigned long mcf_mk_pcicar(int bus, unsigned int devfn, int where)
-{
-       return (bus << PCICAR_BUSN) | (devfn << PCICAR_DEVFNN) | (where & 0xfc);
-}
-
-static int mcf_pci_readconfig(struct pci_bus *bus, unsigned int devfn,
-       int where, int size, u32 *value)
-{
-       unsigned long addr;
-
-       *value = 0xffffffff;
-
-       if (bus->number == 0) {
-               if (mcf_host_slot2sid[PCI_SLOT(devfn)] == 0)
-                       return PCIBIOS_SUCCESSFUL;
-       }
-
-       syncio();
-       addr = mcf_mk_pcicar(bus->number, devfn, where);
-       __raw_writel(PCICAR_E | addr, PCICAR);
-       addr = iospace + (where & 0x3);
-
-       switch (size) {
-       case 1:
-               *value = __raw_readb(addr);
-               break;
-       case 2:
-               *value = le16_to_cpu(__raw_readw(addr));
-               break;
-       default:
-               *value = le32_to_cpu(__raw_readl(addr));
-               break;
-       }
-
-       syncio();
-       __raw_writel(0, PCICAR);
-       return PCIBIOS_SUCCESSFUL;
-}
-
-static int mcf_pci_writeconfig(struct pci_bus *bus, unsigned int devfn,
-       int where, int size, u32 value)
-{
-       unsigned long addr;
-
-       if (bus->number == 0) {
-               if (mcf_host_slot2sid[PCI_SLOT(devfn)] == 0)
-                       return PCIBIOS_SUCCESSFUL;
-       }
-
-       syncio();
-       addr = mcf_mk_pcicar(bus->number, devfn, where);
-       __raw_writel(PCICAR_E | addr, PCICAR);
-       addr = iospace + (where & 0x3);
-
-       switch (size) {
-       case 1:
-                __raw_writeb(value, addr);
-               break;
-       case 2:
-               __raw_writew(cpu_to_le16(value), addr);
-               break;
-       default:
-               __raw_writel(cpu_to_le32(value), addr);
-               break;
-       }
-
-       syncio();
-       __raw_writel(0, PCICAR);
-       return PCIBIOS_SUCCESSFUL;
-}
-
-static struct pci_ops mcf_pci_ops = {
-       .read   = mcf_pci_readconfig,
-       .write  = mcf_pci_writeconfig,
-};
-
-/*
- *     IO address space access functions. Pretty strait forward, these are
- *     directly mapped in to the IO mapping window. And that is mapped into
- *     virtual address space.
- */
-u8 mcf_pci_inb(u32 addr)
-{
-       return __raw_readb(iospace + (addr & PCI_IO_MASK));
-}
-EXPORT_SYMBOL(mcf_pci_inb);
-
-u16 mcf_pci_inw(u32 addr)
-{
-       return le16_to_cpu(__raw_readw(iospace + (addr & PCI_IO_MASK)));
-}
-EXPORT_SYMBOL(mcf_pci_inw);
-
-u32 mcf_pci_inl(u32 addr)
-{
-       return le32_to_cpu(__raw_readl(iospace + (addr & PCI_IO_MASK)));
-}
-EXPORT_SYMBOL(mcf_pci_inl);
-
-void mcf_pci_insb(u32 addr, u8 *buf, u32 len)
-{
-       for (; len; len--)
-               *buf++ = mcf_pci_inb(addr);
-}
-EXPORT_SYMBOL(mcf_pci_insb);
-
-void mcf_pci_insw(u32 addr, u16 *buf, u32 len)
-{
-       for (; len; len--)
-               *buf++ = mcf_pci_inw(addr);
-}
-EXPORT_SYMBOL(mcf_pci_insw);
-
-void mcf_pci_insl(u32 addr, u32 *buf, u32 len)
-{
-       for (; len; len--)
-               *buf++ = mcf_pci_inl(addr);
-}
-EXPORT_SYMBOL(mcf_pci_insl);
-
-void mcf_pci_outb(u8 v, u32 addr)
-{
-       __raw_writeb(v, iospace + (addr & PCI_IO_MASK));
-}
-EXPORT_SYMBOL(mcf_pci_outb);
-
-void mcf_pci_outw(u16 v, u32 addr)
-{
-       __raw_writew(cpu_to_le16(v), iospace + (addr & PCI_IO_MASK));
-}
-EXPORT_SYMBOL(mcf_pci_outw);
-
-void mcf_pci_outl(u32 v, u32 addr)
-{
-       __raw_writel(cpu_to_le32(v), iospace + (addr & PCI_IO_MASK));
-}
-EXPORT_SYMBOL(mcf_pci_outl);
-
-void mcf_pci_outsb(u32 addr, const u8 *buf, u32 len)
-{
-       for (; len; len--)
-               mcf_pci_outb(*buf++, addr);
-}
-EXPORT_SYMBOL(mcf_pci_outsb);
-
-void mcf_pci_outsw(u32 addr, const u16 *buf, u32 len)
-{
-       for (; len; len--)
-               mcf_pci_outw(*buf++, addr);
-}
-EXPORT_SYMBOL(mcf_pci_outsw);
-
-void mcf_pci_outsl(u32 addr, const u32 *buf, u32 len)
-{
-       for (; len; len--)
-               mcf_pci_outl(*buf++, addr);
-}
-EXPORT_SYMBOL(mcf_pci_outsl);
-
-/*
- * Initialize the PCI bus registers, and scan the bus.
- */
-static struct resource mcf_pci_mem = {
-       .name   = "PCI Memory space",
-       .start  = PCI_MEM_PA,
-       .end    = PCI_MEM_PA + PCI_MEM_SIZE - 1,
-       .flags  = IORESOURCE_MEM,
-};
-
-static struct resource mcf_pci_io = {
-       .name   = "PCI IO space",
-       .start  = 0x400,
-       .end    = 0x10000 - 1,
-       .flags  = IORESOURCE_IO,
-};
-
-/*
- * Interrupt mapping and setting.
- */
-static int mcf_pci_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
-{
-       int sid;
-
-       sid = mcf_host_slot2sid[slot];
-       if (sid)
-               return mcf_host_irq[sid];
-       return 0;
-}
-
-static int __init mcf_pci_init(void)
-{
-       pr_info("ColdFire: PCI bus initialization...\n");
-
-       /* Reset the external PCI bus */
-       __raw_writel(PCIGSCR_RESET, PCIGSCR);
-       __raw_writel(0, PCITCR);
-
-       request_resource(&iomem_resource, &mcf_pci_mem);
-       request_resource(&iomem_resource, &mcf_pci_io);
-
-       /* Configure PCI arbiter */
-       __raw_writel(PACR_INTMPRI | PACR_INTMINTE | PACR_EXTMPRI(0x1f) |
-               PACR_EXTMINTE(0x1f), PACR);
-
-       /* Set required multi-function pins for PCI bus use */
-       __raw_writew(0x3ff, MCFGPIO_PAR_PCIBG);
-       __raw_writew(0x3ff, MCFGPIO_PAR_PCIBR);
-
-       /* Set up config space for local host bus controller */
-       __raw_writel(PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER |
-               PCI_COMMAND_INVALIDATE, PCISCR);
-       __raw_writel(PCICR1_LT(32) | PCICR1_CL(8), PCICR1);
-       __raw_writel(0, PCICR2);
-
-       /*
-        * Set up the initiator windows for memory and IO mapping.
-        * These give the CPU bus access onto the PCI bus. One for each of
-        * PCI memory and IO address spaces.
-        */
-       __raw_writel(WXBTAR(PCI_MEM_PA, PCI_MEM_BA, PCI_MEM_SIZE),
-               PCIIW0BTAR);
-       __raw_writel(WXBTAR(PCI_IO_PA, PCI_IO_BA, PCI_IO_SIZE),
-               PCIIW1BTAR);
-       __raw_writel(PCIIWCR_W0_MEM /*| PCIIWCR_W0_MRDL*/ | PCIIWCR_W0_E |
-               PCIIWCR_W1_IO | PCIIWCR_W1_E, PCIIWCR);
-
-       /*
-        * Set up the target windows for access from the PCI bus back to the
-        * CPU bus. All we need is access to system RAM (for mastering).
-        */
-       __raw_writel(CONFIG_RAMBASE, PCIBAR1);
-       __raw_writel(CONFIG_RAMBASE | PCITBATR1_E, PCITBATR1);
-
-       /* Keep a virtual mapping to IO/config space active */
-       iospace = (unsigned long) ioremap(PCI_IO_PA, PCI_IO_SIZE);
-       if (iospace == 0)
-               return -ENODEV;
-       pr_info("Coldfire: PCI IO/config window mapped to 0x%x\n",
-               (u32) iospace);
-
-       /* Turn of PCI reset, and wait for devices to settle */
-       __raw_writel(0, PCIGSCR);
-       set_current_state(TASK_UNINTERRUPTIBLE);
-       schedule_timeout(msecs_to_jiffies(200));
-
-       rootbus = pci_scan_bus(0, &mcf_pci_ops, NULL);
-       rootbus->resource[0] = &mcf_pci_io;
-       rootbus->resource[1] = &mcf_pci_mem;
-
-       pci_fixup_irqs(pci_common_swizzle, mcf_pci_map_irq);
-       pci_bus_size_bridges(rootbus);
-       pci_bus_assign_resources(rootbus);
-       return 0;
-}
-
-subsys_initcall(mcf_pci_init);
diff --git a/arch/m68k/platform/coldfire/pit.c b/arch/m68k/platform/coldfire/pit.c
deleted file mode 100644 (file)
index 493b311..0000000
+++ /dev/null
@@ -1,167 +0,0 @@
-/***************************************************************************/
-
-/*
- *     pit.c -- Freescale ColdFire PIT timer. Currently this type of
- *              hardware timer only exists in the Freescale ColdFire
- *              5270/5271, 5282 and 5208 CPUs. No doubt newer ColdFire
- *              family members will probably use it too.
- *
- *     Copyright (C) 1999-2008, Greg Ungerer (gerg@snapgear.com)
- *     Copyright (C) 2001-2004, SnapGear Inc. (www.snapgear.com)
- */
-
-/***************************************************************************/
-
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/param.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/irq.h>
-#include <linux/clockchips.h>
-#include <asm/machdep.h>
-#include <asm/io.h>
-#include <asm/coldfire.h>
-#include <asm/mcfpit.h>
-#include <asm/mcfsim.h>
-
-/***************************************************************************/
-
-/*
- *     By default use timer1 as the system clock timer.
- */
-#define        FREQ    ((MCF_CLK / 2) / 64)
-#define        TA(a)   (MCFPIT_BASE1 + (a))
-#define PIT_CYCLES_PER_JIFFY (FREQ / HZ)
-
-static u32 pit_cnt;
-
-/*
- * Initialize the PIT timer.
- *
- * This is also called after resume to bring the PIT into operation again.
- */
-
-static void init_cf_pit_timer(enum clock_event_mode mode,
-                             struct clock_event_device *evt)
-{
-       switch (mode) {
-       case CLOCK_EVT_MODE_PERIODIC:
-
-               __raw_writew(MCFPIT_PCSR_DISABLE, TA(MCFPIT_PCSR));
-               __raw_writew(PIT_CYCLES_PER_JIFFY, TA(MCFPIT_PMR));
-               __raw_writew(MCFPIT_PCSR_EN | MCFPIT_PCSR_PIE | \
-                               MCFPIT_PCSR_OVW | MCFPIT_PCSR_RLD | \
-                               MCFPIT_PCSR_CLK64, TA(MCFPIT_PCSR));
-               break;
-
-       case CLOCK_EVT_MODE_SHUTDOWN:
-       case CLOCK_EVT_MODE_UNUSED:
-
-               __raw_writew(MCFPIT_PCSR_DISABLE, TA(MCFPIT_PCSR));
-               break;
-
-       case CLOCK_EVT_MODE_ONESHOT:
-
-               __raw_writew(MCFPIT_PCSR_DISABLE, TA(MCFPIT_PCSR));
-               __raw_writew(MCFPIT_PCSR_EN | MCFPIT_PCSR_PIE | \
-                               MCFPIT_PCSR_OVW | MCFPIT_PCSR_CLK64, \
-                               TA(MCFPIT_PCSR));
-               break;
-
-       case CLOCK_EVT_MODE_RESUME:
-               /* Nothing to do here */
-               break;
-       }
-}
-
-/*
- * Program the next event in oneshot mode
- *
- * Delta is given in PIT ticks
- */
-static int cf_pit_next_event(unsigned long delta,
-               struct clock_event_device *evt)
-{
-       __raw_writew(delta, TA(MCFPIT_PMR));
-       return 0;
-}
-
-struct clock_event_device cf_pit_clockevent = {
-       .name           = "pit",
-       .features       = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
-       .set_mode       = init_cf_pit_timer,
-       .set_next_event = cf_pit_next_event,
-       .shift          = 32,
-       .irq            = MCF_IRQ_PIT1,
-};
-
-
-
-/***************************************************************************/
-
-static irqreturn_t pit_tick(int irq, void *dummy)
-{
-       struct clock_event_device *evt = &cf_pit_clockevent;
-       u16 pcsr;
-
-       /* Reset the ColdFire timer */
-       pcsr = __raw_readw(TA(MCFPIT_PCSR));
-       __raw_writew(pcsr | MCFPIT_PCSR_PIF, TA(MCFPIT_PCSR));
-
-       pit_cnt += PIT_CYCLES_PER_JIFFY;
-       evt->event_handler(evt);
-       return IRQ_HANDLED;
-}
-
-/***************************************************************************/
-
-static struct irqaction pit_irq = {
-       .name    = "timer",
-       .flags   = IRQF_TIMER,
-       .handler = pit_tick,
-};
-
-/***************************************************************************/
-
-static cycle_t pit_read_clk(struct clocksource *cs)
-{
-       unsigned long flags;
-       u32 cycles;
-       u16 pcntr;
-
-       local_irq_save(flags);
-       pcntr = __raw_readw(TA(MCFPIT_PCNTR));
-       cycles = pit_cnt;
-       local_irq_restore(flags);
-
-       return cycles + PIT_CYCLES_PER_JIFFY - pcntr;
-}
-
-/***************************************************************************/
-
-static struct clocksource pit_clk = {
-       .name   = "pit",
-       .rating = 100,
-       .read   = pit_read_clk,
-       .mask   = CLOCKSOURCE_MASK(32),
-};
-
-/***************************************************************************/
-
-void hw_timer_init(irq_handler_t handler)
-{
-       cf_pit_clockevent.cpumask = cpumask_of(smp_processor_id());
-       cf_pit_clockevent.mult = div_sc(FREQ, NSEC_PER_SEC, 32);
-       cf_pit_clockevent.max_delta_ns =
-               clockevent_delta2ns(0xFFFF, &cf_pit_clockevent);
-       cf_pit_clockevent.min_delta_ns =
-               clockevent_delta2ns(0x3f, &cf_pit_clockevent);
-       clockevents_register_device(&cf_pit_clockevent);
-
-       setup_irq(MCF_IRQ_PIT1, &pit_irq);
-
-       clocksource_register_hz(&pit_clk, FREQ);
-}
-
-/***************************************************************************/
diff --git a/arch/m68k/platform/coldfire/reset.c b/arch/m68k/platform/coldfire/reset.c
deleted file mode 100644 (file)
index f30952f..0000000
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * reset.c  -- common ColdFire SoC reset support
- *
- * (C) Copyright 2012, Greg Ungerer <gerg@uclinux.org>
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file COPYING in the main directory of this archive
- * for more details.
- */
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/io.h>
-#include <asm/machdep.h>
-#include <asm/coldfire.h>
-#include <asm/mcfsim.h>
-
-/*
- *     There are 2 common methods amongst the ColdFure parts for reseting
- *     the CPU. But there are couple of exceptions, the 5272 and the 547x
- *     have something completely special to them, and we let their specific
- *     subarch code handle them.
- */
-
-#ifdef MCFSIM_SYPCR
-static void mcf_cpu_reset(void)
-{
-       local_irq_disable();
-       /* Set watchdog to soft reset, and enabled */
-       __raw_writeb(0xc0, MCFSIM_SYPCR);
-       for (;;)
-               /* wait for watchdog to timeout */;
-}
-#endif
-
-#ifdef MCF_RCR
-static void mcf_cpu_reset(void)
-{
-       local_irq_disable();
-       __raw_writeb(MCF_RCR_SWRESET, MCF_RCR);
-}
-#endif
-
-static int __init mcf_setup_reset(void)
-{
-       mach_reset = mcf_cpu_reset;
-       return 0;
-}
-
-arch_initcall(mcf_setup_reset);
diff --git a/arch/m68k/platform/coldfire/sltimers.c b/arch/m68k/platform/coldfire/sltimers.c
deleted file mode 100644 (file)
index 831a08c..0000000
+++ /dev/null
@@ -1,149 +0,0 @@
-/***************************************************************************/
-
-/*
- *     sltimers.c -- generic ColdFire slice timer support.
- *
- *     Copyright (C) 2009-2010, Philippe De Muyter <phdm@macqel.be>
- *     based on
- *     timers.c -- generic ColdFire hardware timer support.
- *     Copyright (C) 1999-2008, Greg Ungerer <gerg@snapgear.com>
- */
-
-/***************************************************************************/
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/sched.h>
-#include <linux/interrupt.h>
-#include <linux/irq.h>
-#include <linux/profile.h>
-#include <linux/clocksource.h>
-#include <asm/io.h>
-#include <asm/traps.h>
-#include <asm/machdep.h>
-#include <asm/coldfire.h>
-#include <asm/mcfslt.h>
-#include <asm/mcfsim.h>
-
-/***************************************************************************/
-
-#ifdef CONFIG_HIGHPROFILE
-
-/*
- *     By default use Slice Timer 1 as the profiler clock timer.
- */
-#define        PA(a)   (MCFSLT_TIMER1 + (a))
-
-/*
- *     Choose a reasonably fast profile timer. Make it an odd value to
- *     try and get good coverage of kernel operations.
- */
-#define        PROFILEHZ       1013
-
-irqreturn_t mcfslt_profile_tick(int irq, void *dummy)
-{
-       /* Reset Slice Timer 1 */
-       __raw_writel(MCFSLT_SSR_BE | MCFSLT_SSR_TE, PA(MCFSLT_SSR));
-       if (current->pid)
-               profile_tick(CPU_PROFILING);
-       return IRQ_HANDLED;
-}
-
-static struct irqaction mcfslt_profile_irq = {
-       .name    = "profile timer",
-       .flags   = IRQF_TIMER,
-       .handler = mcfslt_profile_tick,
-};
-
-void mcfslt_profile_init(void)
-{
-       printk(KERN_INFO "PROFILE: lodging TIMER 1 @ %dHz as profile timer\n",
-              PROFILEHZ);
-
-       setup_irq(MCF_IRQ_PROFILER, &mcfslt_profile_irq);
-
-       /* Set up TIMER 2 as high speed profile clock */
-       __raw_writel(MCF_BUSCLK / PROFILEHZ - 1, PA(MCFSLT_STCNT));
-       __raw_writel(MCFSLT_SCR_RUN | MCFSLT_SCR_IEN | MCFSLT_SCR_TEN,
-                                                               PA(MCFSLT_SCR));
-
-}
-
-#endif /* CONFIG_HIGHPROFILE */
-
-/***************************************************************************/
-
-/*
- *     By default use Slice Timer 0 as the system clock timer.
- */
-#define        TA(a)   (MCFSLT_TIMER0 + (a))
-
-static u32 mcfslt_cycles_per_jiffy;
-static u32 mcfslt_cnt;
-
-static irq_handler_t timer_interrupt;
-
-static irqreturn_t mcfslt_tick(int irq, void *dummy)
-{
-       /* Reset Slice Timer 0 */
-       __raw_writel(MCFSLT_SSR_BE | MCFSLT_SSR_TE, TA(MCFSLT_SSR));
-       mcfslt_cnt += mcfslt_cycles_per_jiffy;
-       return timer_interrupt(irq, dummy);
-}
-
-static struct irqaction mcfslt_timer_irq = {
-       .name    = "timer",
-       .flags   = IRQF_TIMER,
-       .handler = mcfslt_tick,
-};
-
-static cycle_t mcfslt_read_clk(struct clocksource *cs)
-{
-       unsigned long flags;
-       u32 cycles, scnt;
-
-       local_irq_save(flags);
-       scnt = __raw_readl(TA(MCFSLT_SCNT));
-       cycles = mcfslt_cnt;
-       if (__raw_readl(TA(MCFSLT_SSR)) & MCFSLT_SSR_TE) {
-               cycles += mcfslt_cycles_per_jiffy;
-               scnt = __raw_readl(TA(MCFSLT_SCNT));
-       }
-       local_irq_restore(flags);
-
-       /* subtract because slice timers count down */
-       return cycles + ((mcfslt_cycles_per_jiffy - 1) - scnt);
-}
-
-static struct clocksource mcfslt_clk = {
-       .name   = "slt",
-       .rating = 250,
-       .read   = mcfslt_read_clk,
-       .mask   = CLOCKSOURCE_MASK(32),
-       .flags  = CLOCK_SOURCE_IS_CONTINUOUS,
-};
-
-void hw_timer_init(irq_handler_t handler)
-{
-       mcfslt_cycles_per_jiffy = MCF_BUSCLK / HZ;
-       /*
-        *      The coldfire slice timer (SLT) runs from STCNT to 0 included,
-        *      then STCNT again and so on.  It counts thus actually
-        *      STCNT + 1 steps for 1 tick, not STCNT.  So if you want
-        *      n cycles, initialize STCNT with n - 1.
-        */
-       __raw_writel(mcfslt_cycles_per_jiffy - 1, TA(MCFSLT_STCNT));
-       __raw_writel(MCFSLT_SCR_RUN | MCFSLT_SCR_IEN | MCFSLT_SCR_TEN,
-                                                               TA(MCFSLT_SCR));
-       /* initialize mcfslt_cnt knowing that slice timers count down */
-       mcfslt_cnt = mcfslt_cycles_per_jiffy;
-
-       timer_interrupt = handler;
-       setup_irq(MCF_IRQ_TIMER, &mcfslt_timer_irq);
-
-       clocksource_register_hz(&mcfslt_clk, MCF_BUSCLK);
-
-#ifdef CONFIG_HIGHPROFILE
-       mcfslt_profile_init();
-#endif
-}
diff --git a/arch/m68k/platform/coldfire/timers.c b/arch/m68k/platform/coldfire/timers.c
deleted file mode 100644 (file)
index cd496a2..0000000
+++ /dev/null
@@ -1,195 +0,0 @@
-/***************************************************************************/
-
-/*
- *     timers.c -- generic ColdFire hardware timer support.
- *
- *     Copyright (C) 1999-2008, Greg Ungerer <gerg@snapgear.com>
- */
-
-/***************************************************************************/
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/sched.h>
-#include <linux/interrupt.h>
-#include <linux/irq.h>
-#include <linux/profile.h>
-#include <linux/clocksource.h>
-#include <asm/io.h>
-#include <asm/traps.h>
-#include <asm/machdep.h>
-#include <asm/coldfire.h>
-#include <asm/mcftimer.h>
-#include <asm/mcfsim.h>
-
-/***************************************************************************/
-
-/*
- *     By default use timer1 as the system clock timer.
- */
-#define        FREQ    (MCF_BUSCLK / 16)
-#define        TA(a)   (MCFTIMER_BASE1 + (a))
-
-/*
- *     These provide the underlying interrupt vector support.
- *     Unfortunately it is a little different on each ColdFire.
- */
-void coldfire_profile_init(void);
-
-#if defined(CONFIG_M53xx) || defined(CONFIG_M5441x)
-#define        __raw_readtrr   __raw_readl
-#define        __raw_writetrr  __raw_writel
-#else
-#define        __raw_readtrr   __raw_readw
-#define        __raw_writetrr  __raw_writew
-#endif
-
-static u32 mcftmr_cycles_per_jiffy;
-static u32 mcftmr_cnt;
-
-static irq_handler_t timer_interrupt;
-
-/***************************************************************************/
-
-static void init_timer_irq(void)
-{
-#ifdef MCFSIM_ICR_AUTOVEC
-       /* Timer1 is always used as system timer */
-       writeb(MCFSIM_ICR_AUTOVEC | MCFSIM_ICR_LEVEL6 | MCFSIM_ICR_PRI3,
-               MCFSIM_TIMER1ICR);
-       mcf_mapirq2imr(MCF_IRQ_TIMER, MCFINTC_TIMER1);
-
-#ifdef CONFIG_HIGHPROFILE
-       /* Timer2 is to be used as a high speed profile timer  */
-       writeb(MCFSIM_ICR_AUTOVEC | MCFSIM_ICR_LEVEL7 | MCFSIM_ICR_PRI3,
-               MCFSIM_TIMER2ICR);
-       mcf_mapirq2imr(MCF_IRQ_PROFILER, MCFINTC_TIMER2);
-#endif
-#endif /* MCFSIM_ICR_AUTOVEC */
-}
-
-/***************************************************************************/
-
-static irqreturn_t mcftmr_tick(int irq, void *dummy)
-{
-       /* Reset the ColdFire timer */
-       __raw_writeb(MCFTIMER_TER_CAP | MCFTIMER_TER_REF, TA(MCFTIMER_TER));
-
-       mcftmr_cnt += mcftmr_cycles_per_jiffy;
-       return timer_interrupt(irq, dummy);
-}
-
-/***************************************************************************/
-
-static struct irqaction mcftmr_timer_irq = {
-       .name    = "timer",
-       .flags   = IRQF_TIMER,
-       .handler = mcftmr_tick,
-};
-
-/***************************************************************************/
-
-static cycle_t mcftmr_read_clk(struct clocksource *cs)
-{
-       unsigned long flags;
-       u32 cycles;
-       u16 tcn;
-
-       local_irq_save(flags);
-       tcn = __raw_readw(TA(MCFTIMER_TCN));
-       cycles = mcftmr_cnt;
-       local_irq_restore(flags);
-
-       return cycles + tcn;
-}
-
-/***************************************************************************/
-
-static struct clocksource mcftmr_clk = {
-       .name   = "tmr",
-       .rating = 250,
-       .read   = mcftmr_read_clk,
-       .mask   = CLOCKSOURCE_MASK(32),
-       .flags  = CLOCK_SOURCE_IS_CONTINUOUS,
-};
-
-/***************************************************************************/
-
-void hw_timer_init(irq_handler_t handler)
-{
-       __raw_writew(MCFTIMER_TMR_DISABLE, TA(MCFTIMER_TMR));
-       mcftmr_cycles_per_jiffy = FREQ / HZ;
-       /*
-        *      The coldfire timer runs from 0 to TRR included, then 0
-        *      again and so on.  It counts thus actually TRR + 1 steps
-        *      for 1 tick, not TRR.  So if you want n cycles,
-        *      initialize TRR with n - 1.
-        */
-       __raw_writetrr(mcftmr_cycles_per_jiffy - 1, TA(MCFTIMER_TRR));
-       __raw_writew(MCFTIMER_TMR_ENORI | MCFTIMER_TMR_CLK16 |
-               MCFTIMER_TMR_RESTART | MCFTIMER_TMR_ENABLE, TA(MCFTIMER_TMR));
-
-       clocksource_register_hz(&mcftmr_clk, FREQ);
-
-       timer_interrupt = handler;
-       init_timer_irq();
-       setup_irq(MCF_IRQ_TIMER, &mcftmr_timer_irq);
-
-#ifdef CONFIG_HIGHPROFILE
-       coldfire_profile_init();
-#endif
-}
-
-/***************************************************************************/
-#ifdef CONFIG_HIGHPROFILE
-/***************************************************************************/
-
-/*
- *     By default use timer2 as the profiler clock timer.
- */
-#define        PA(a)   (MCFTIMER_BASE2 + (a))
-
-/*
- *     Choose a reasonably fast profile timer. Make it an odd value to
- *     try and get good coverage of kernel operations.
- */
-#define        PROFILEHZ       1013
-
-/*
- *     Use the other timer to provide high accuracy profiling info.
- */
-irqreturn_t coldfire_profile_tick(int irq, void *dummy)
-{
-       /* Reset ColdFire timer2 */
-       __raw_writeb(MCFTIMER_TER_CAP | MCFTIMER_TER_REF, PA(MCFTIMER_TER));
-       if (current->pid)
-               profile_tick(CPU_PROFILING);
-       return IRQ_HANDLED;
-}
-
-/***************************************************************************/
-
-static struct irqaction coldfire_profile_irq = {
-       .name    = "profile timer",
-       .flags   = IRQF_TIMER,
-       .handler = coldfire_profile_tick,
-};
-
-void coldfire_profile_init(void)
-{
-       printk(KERN_INFO "PROFILE: lodging TIMER2 @ %dHz as profile timer\n",
-              PROFILEHZ);
-
-       /* Set up TIMER 2 as high speed profile clock */
-       __raw_writew(MCFTIMER_TMR_DISABLE, PA(MCFTIMER_TMR));
-
-       __raw_writetrr(((MCF_BUSCLK / 16) / PROFILEHZ), PA(MCFTIMER_TRR));
-       __raw_writew(MCFTIMER_TMR_ENORI | MCFTIMER_TMR_CLK16 |
-               MCFTIMER_TMR_RESTART | MCFTIMER_TMR_ENABLE, PA(MCFTIMER_TMR));
-
-       setup_irq(MCF_IRQ_PROFILER, &coldfire_profile_irq);
-}
-
-/***************************************************************************/
-#endif /* CONFIG_HIGHPROFILE */
-/***************************************************************************/
diff --git a/arch/m68k/platform/coldfire/vectors.c b/arch/m68k/platform/coldfire/vectors.c
deleted file mode 100644 (file)
index a4dbdec..0000000
+++ /dev/null
@@ -1,70 +0,0 @@
-/***************************************************************************/
-
-/*
- *     linux/arch/m68knommu/platform/coldfire/vectors.c
- *
- *     Copyright (C) 1999-2007, Greg Ungerer <gerg@snapgear.com>
- */
-
-/***************************************************************************/
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/irq.h>
-#include <asm/traps.h>
-#include <asm/machdep.h>
-#include <asm/coldfire.h>
-#include <asm/mcfsim.h>
-#include <asm/mcfwdebug.h>
-
-/***************************************************************************/
-
-#ifdef TRAP_DBG_INTERRUPT
-
-asmlinkage void dbginterrupt_c(struct frame *fp)
-{
-       extern void dump(struct pt_regs *fp);
-       printk(KERN_DEBUG "%s(%d): BUS ERROR TRAP\n", __FILE__, __LINE__);
-       dump((struct pt_regs *) fp);
-       asm("halt");
-}
-
-#endif
-
-/***************************************************************************/
-
-/* Assembler routines */
-asmlinkage void buserr(void);
-asmlinkage void trap(void);
-asmlinkage void system_call(void);
-asmlinkage void inthandler(void);
-
-void __init trap_init(void)
-{
-       int i;
-
-       /*
-        *      There is a common trap handler and common interrupt
-        *      handler that handle almost every vector. We treat
-        *      the system call and bus error special, they get their
-        *      own first level handlers.
-        */
-       for (i = 3; (i <= 23); i++)
-               _ramvec[i] = trap;
-       for (i = 33; (i <= 63); i++)
-               _ramvec[i] = trap;
-       for (i = 24; (i <= 31); i++)
-               _ramvec[i] = inthandler;
-       for (i = 64; (i < 255); i++)
-               _ramvec[i] = inthandler;
-       _ramvec[255] = 0;
-
-       _ramvec[2] = buserr;
-       _ramvec[32] = system_call;
-
-#ifdef TRAP_DBG_INTERRUPT
-       _ramvec[12] = dbginterrupt;
-#endif
-}
-
-/***************************************************************************/
index d2e60a18986c37a3c35263d3a8beff18a2316643..948d8688643c5823ae8cfc71cae920fa5b9ede02 100644 (file)
@@ -27,85 +27,56 @@ static inline int atomic_read(const atomic_t *v)
        return temp;
 }
 
-static inline void atomic_add(int i, atomic_t *v)
-{
-       int temp;
-
-       asm volatile (
-               "1:     LNKGETD %0, [%1]\n"
-               "       ADD     %0, %0, %2\n"
-               "       LNKSETD [%1], %0\n"
-               "       DEFR    %0, TXSTAT\n"
-               "       ANDT    %0, %0, #HI(0x3f000000)\n"
-               "       CMPT    %0, #HI(0x02000000)\n"
-               "       BNZ     1b\n"
-               : "=&d" (temp)
-               : "da" (&v->counter), "bd" (i)
-               : "cc");
+#define ATOMIC_OP(op)                                                  \
+static inline void atomic_##op(int i, atomic_t *v)                     \
+{                                                                      \
+       int temp;                                                       \
+                                                                       \
+       asm volatile (                                                  \
+               "1:     LNKGETD %0, [%1]\n"                             \
+               "       " #op " %0, %0, %2\n"                           \
+               "       LNKSETD [%1], %0\n"                             \
+               "       DEFR    %0, TXSTAT\n"                           \
+               "       ANDT    %0, %0, #HI(0x3f000000)\n"              \
+               "       CMPT    %0, #HI(0x02000000)\n"                  \
+               "       BNZ     1b\n"                                   \
+               : "=&d" (temp)                                          \
+               : "da" (&v->counter), "bd" (i)                          \
+               : "cc");                                                \
+}                                                                      \
+
+#define ATOMIC_OP_RETURN(op)                                           \
+static inline int atomic_##op##_return(int i, atomic_t *v)             \
+{                                                                      \
+       int result, temp;                                               \
+                                                                       \
+       smp_mb();                                                       \
+                                                                       \
+       asm volatile (                                                  \
+               "1:     LNKGETD %1, [%2]\n"                             \
+               "       " #op " %1, %1, %3\n"                           \
+               "       LNKSETD [%2], %1\n"                             \
+               "       DEFR    %0, TXSTAT\n"                           \
+               "       ANDT    %0, %0, #HI(0x3f000000)\n"              \
+               "       CMPT    %0, #HI(0x02000000)\n"                  \
+               "       BNZ 1b\n"                                       \
+               : "=&d" (temp), "=&da" (result)                         \
+               : "da" (&v->counter), "bd" (i)                          \
+               : "cc");                                                \
+                                                                       \
+       smp_mb();                                                       \
+                                                                       \
+       return result;                                                  \
 }
 
-static inline void atomic_sub(int i, atomic_t *v)
-{
-       int temp;
+#define ATOMIC_OPS(op) ATOMIC_OP(op) ATOMIC_OP_RETURN(op)
 
-       asm volatile (
-               "1:     LNKGETD %0, [%1]\n"
-               "       SUB     %0, %0, %2\n"
-               "       LNKSETD [%1], %0\n"
-               "       DEFR    %0, TXSTAT\n"
-               "       ANDT    %0, %0, #HI(0x3f000000)\n"
-               "       CMPT    %0, #HI(0x02000000)\n"
-               "       BNZ 1b\n"
-               : "=&d" (temp)
-               : "da" (&v->counter), "bd" (i)
-               : "cc");
-}
+ATOMIC_OPS(add)
+ATOMIC_OPS(sub)
 
-static inline int atomic_add_return(int i, atomic_t *v)
-{
-       int result, temp;
-
-       smp_mb();
-
-       asm volatile (
-               "1:     LNKGETD %1, [%2]\n"
-               "       ADD     %1, %1, %3\n"
-               "       LNKSETD [%2], %1\n"
-               "       DEFR    %0, TXSTAT\n"
-               "       ANDT    %0, %0, #HI(0x3f000000)\n"
-               "       CMPT    %0, #HI(0x02000000)\n"
-               "       BNZ 1b\n"
-               : "=&d" (temp), "=&da" (result)
-               : "da" (&v->counter), "bd" (i)
-               : "cc");
-
-       smp_mb();
-
-       return result;
-}
-
-static inline int atomic_sub_return(int i, atomic_t *v)
-{
-       int result, temp;
-
-       smp_mb();
-
-       asm volatile (
-               "1:     LNKGETD %1, [%2]\n"
-               "       SUB     %1, %1, %3\n"
-               "       LNKSETD [%2], %1\n"
-               "       DEFR    %0, TXSTAT\n"
-               "       ANDT    %0, %0, #HI(0x3f000000)\n"
-               "       CMPT    %0, #HI(0x02000000)\n"
-               "       BNZ     1b\n"
-               : "=&d" (temp), "=&da" (result)
-               : "da" (&v->counter), "bd" (i)
-               : "cc");
-
-       smp_mb();
-
-       return result;
-}
+#undef ATOMIC_OPS
+#undef ATOMIC_OP_RETURN
+#undef ATOMIC_OP
 
 static inline void atomic_clear_mask(unsigned int mask, atomic_t *v)
 {
index e578955e674b8a4517b6f3e13fe38b062eff80b6..f5d5898c10201cb32a94044ec53a4e2d5ef3b01a 100644 (file)
@@ -37,55 +37,41 @@ static inline int atomic_set(atomic_t *v, int i)
        return i;
 }
 
-static inline void atomic_add(int i, atomic_t *v)
-{
-       unsigned long flags;
-
-       __global_lock1(flags);
-       fence();
-       v->counter += i;
-       __global_unlock1(flags);
+#define ATOMIC_OP(op, c_op)                                            \
+static inline void atomic_##op(int i, atomic_t *v)                     \
+{                                                                      \
+       unsigned long flags;                                            \
+                                                                       \
+       __global_lock1(flags);                                          \
+       fence();                                                        \
+       v->counter c_op i;                                              \
+       __global_unlock1(flags);                                        \
+}                                                                      \
+
+#define ATOMIC_OP_RETURN(op, c_op)                                     \
+static inline int atomic_##op##_return(int i, atomic_t *v)             \
+{                                                                      \
+       unsigned long result;                                           \
+       unsigned long flags;                                            \
+                                                                       \
+       __global_lock1(flags);                                          \
+       result = v->counter;                                            \
+       result c_op i;                                                  \
+       fence();                                                        \
+       v->counter = result;                                            \
+       __global_unlock1(flags);                                        \
+                                                                       \
+       return result;                                                  \
 }
 
-static inline void atomic_sub(int i, atomic_t *v)
-{
-       unsigned long flags;
+#define ATOMIC_OPS(op, c_op) ATOMIC_OP(op, c_op) ATOMIC_OP_RETURN(op, c_op)
 
-       __global_lock1(flags);
-       fence();
-       v->counter -= i;
-       __global_unlock1(flags);
-}
-
-static inline int atomic_add_return(int i, atomic_t *v)
-{
-       unsigned long result;
-       unsigned long flags;
+ATOMIC_OPS(add, +=)
+ATOMIC_OPS(sub, -=)
 
-       __global_lock1(flags);
-       result = v->counter;
-       result += i;
-       fence();
-       v->counter = result;
-       __global_unlock1(flags);
-
-       return result;
-}
-
-static inline int atomic_sub_return(int i, atomic_t *v)
-{
-       unsigned long result;
-       unsigned long flags;
-
-       __global_lock1(flags);
-       result = v->counter;
-       result -= i;
-       fence();
-       v->counter = result;
-       __global_unlock1(flags);
-
-       return result;
-}
+#undef ATOMIC_OPS
+#undef ATOMIC_OP_RETURN
+#undef ATOMIC_OP
 
 static inline void atomic_clear_mask(unsigned int mask, atomic_t *v)
 {
index 37b2befe651a5e3b1c2ea2e37486065f24911867..6dd6bfc607e9a6bee5a2beead58741526d23369e 100644 (file)
@@ -29,7 +29,7 @@
  *
  * Atomically reads the value of @v.
  */
-#define atomic_read(v)         (*(volatile int *)&(v)->counter)
+#define atomic_read(v)         ACCESS_ONCE((v)->counter)
 
 /*
  * atomic_set - set atomic variable
  */
 #define atomic_set(v, i)               ((v)->counter = (i))
 
-/*
- * atomic_add - add integer to atomic variable
- * @i: integer value to add
- * @v: pointer of type atomic_t
- *
- * Atomically adds @i to @v.
- */
-static __inline__ void atomic_add(int i, atomic_t * v)
-{
-       if (kernel_uses_llsc && R10000_LLSC_WAR) {
-               int temp;
-
-               __asm__ __volatile__(
-               "       .set    arch=r4000                              \n"
-               "1:     ll      %0, %1          # atomic_add            \n"
-               "       addu    %0, %2                                  \n"
-               "       sc      %0, %1                                  \n"
-               "       beqzl   %0, 1b                                  \n"
-               "       .set    mips0                                   \n"
-               : "=&r" (temp), "+m" (v->counter)
-               : "Ir" (i));
-       } else if (kernel_uses_llsc) {
-               int temp;
-
-               do {
-                       __asm__ __volatile__(
-                       "       .set    arch=r4000                      \n"
-                       "       ll      %0, %1          # atomic_add    \n"
-                       "       addu    %0, %2                          \n"
-                       "       sc      %0, %1                          \n"
-                       "       .set    mips0                           \n"
-                       : "=&r" (temp), "+m" (v->counter)
-                       : "Ir" (i));
-               } while (unlikely(!temp));
-       } else {
-               unsigned long flags;
-
-               raw_local_irq_save(flags);
-               v->counter += i;
-               raw_local_irq_restore(flags);
-       }
-}
-
-/*
- * atomic_sub - subtract the atomic variable
- * @i: integer value to subtract
- * @v: pointer of type atomic_t
- *
- * Atomically subtracts @i from @v.
- */
-static __inline__ void atomic_sub(int i, atomic_t * v)
-{
-       if (kernel_uses_llsc && R10000_LLSC_WAR) {
-               int temp;
-
-               __asm__ __volatile__(
-               "       .set    arch=r4000                              \n"
-               "1:     ll      %0, %1          # atomic_sub            \n"
-               "       subu    %0, %2                                  \n"
-               "       sc      %0, %1                                  \n"
-               "       beqzl   %0, 1b                                  \n"
-               "       .set    mips0                                   \n"
-               : "=&r" (temp), "+m" (v->counter)
-               : "Ir" (i));
-       } else if (kernel_uses_llsc) {
-               int temp;
-
-               do {
-                       __asm__ __volatile__(
-                       "       .set    arch=r4000                      \n"
-                       "       ll      %0, %1          # atomic_sub    \n"
-                       "       subu    %0, %2                          \n"
-                       "       sc      %0, %1                          \n"
-                       "       .set    mips0                           \n"
-                       : "=&r" (temp), "+m" (v->counter)
-                       : "Ir" (i));
-               } while (unlikely(!temp));
-       } else {
-               unsigned long flags;
-
-               raw_local_irq_save(flags);
-               v->counter -= i;
-               raw_local_irq_restore(flags);
-       }
-}
-
-/*
- * Same as above, but return the result value
- */
-static __inline__ int atomic_add_return(int i, atomic_t * v)
-{
-       int result;
-
-       smp_mb__before_llsc();
-
-       if (kernel_uses_llsc && R10000_LLSC_WAR) {
-               int temp;
-
-               __asm__ __volatile__(
-               "       .set    arch=r4000                              \n"
-               "1:     ll      %1, %2          # atomic_add_return     \n"
-               "       addu    %0, %1, %3                              \n"
-               "       sc      %0, %2                                  \n"
-               "       beqzl   %0, 1b                                  \n"
-               "       addu    %0, %1, %3                              \n"
-               "       .set    mips0                                   \n"
-               : "=&r" (result), "=&r" (temp), "+m" (v->counter)
-               : "Ir" (i));
-       } else if (kernel_uses_llsc) {
-               int temp;
-
-               do {
-                       __asm__ __volatile__(
-                       "       .set    arch=r4000                      \n"
-                       "       ll      %1, %2  # atomic_add_return     \n"
-                       "       addu    %0, %1, %3                      \n"
-                       "       sc      %0, %2                          \n"
-                       "       .set    mips0                           \n"
-                       : "=&r" (result), "=&r" (temp), "+m" (v->counter)
-                       : "Ir" (i));
-               } while (unlikely(!result));
-
-               result = temp + i;
-       } else {
-               unsigned long flags;
-
-               raw_local_irq_save(flags);
-               result = v->counter;
-               result += i;
-               v->counter = result;
-               raw_local_irq_restore(flags);
-       }
-
-       smp_llsc_mb();
-
-       return result;
+#define ATOMIC_OP(op, c_op, asm_op)                                            \
+static __inline__ void atomic_##op(int i, atomic_t * v)                                \
+{                                                                              \
+       if (kernel_uses_llsc && R10000_LLSC_WAR) {                              \
+               int temp;                                                       \
+                                                                               \
+               __asm__ __volatile__(                                           \
+               "       .set    arch=r4000                              \n"     \
+               "1:     ll      %0, %1          # atomic_" #op "        \n"     \
+               "       " #asm_op " %0, %2                              \n"     \
+               "       sc      %0, %1                                  \n"     \
+               "       beqzl   %0, 1b                                  \n"     \
+               "       .set    mips0                                   \n"     \
+               : "=&r" (temp), "+m" (v->counter)                               \
+               : "Ir" (i));                                                    \
+       } else if (kernel_uses_llsc) {                                          \
+               int temp;                                                       \
+                                                                               \
+               do {                                                            \
+                       __asm__ __volatile__(                                   \
+                       "       .set    arch=r4000                      \n"     \
+                       "       ll      %0, %1          # atomic_" #op "\n"     \
+                       "       " #asm_op " %0, %2                      \n"     \
+                       "       sc      %0, %1                          \n"     \
+                       "       .set    mips0                           \n"     \
+                       : "=&r" (temp), "+m" (v->counter)                       \
+                       : "Ir" (i));                                            \
+               } while (unlikely(!temp));                                      \
+       } else {                                                                \
+               unsigned long flags;                                            \
+                                                                               \
+               raw_local_irq_save(flags);                                      \
+               v->counter c_op i;                                              \
+               raw_local_irq_restore(flags);                                   \
+       }                                                                       \
+}                                                                              \
+
+#define ATOMIC_OP_RETURN(op, c_op, asm_op)                                     \
+static __inline__ int atomic_##op##_return(int i, atomic_t * v)                        \
+{                                                                              \
+       int result;                                                             \
+                                                                               \
+       smp_mb__before_llsc();                                                  \
+                                                                               \
+       if (kernel_uses_llsc && R10000_LLSC_WAR) {                              \
+               int temp;                                                       \
+                                                                               \
+               __asm__ __volatile__(                                           \
+               "       .set    arch=r4000                              \n"     \
+               "1:     ll      %1, %2          # atomic_" #op "_return \n"     \
+               "       " #asm_op " %0, %1, %3                          \n"     \
+               "       sc      %0, %2                                  \n"     \
+               "       beqzl   %0, 1b                                  \n"     \
+               "       " #asm_op " %0, %1, %3                          \n"     \
+               "       .set    mips0                                   \n"     \
+               : "=&r" (result), "=&r" (temp), "+m" (v->counter)               \
+               : "Ir" (i));                                                    \
+       } else if (kernel_uses_llsc) {                                          \
+               int temp;                                                       \
+                                                                               \
+               do {                                                            \
+                       __asm__ __volatile__(                                   \
+                       "       .set    arch=r4000                      \n"     \
+                       "       ll      %1, %2  # atomic_" #op "_return \n"     \
+                       "       " #asm_op " %0, %1, %3                  \n"     \
+                       "       sc      %0, %2                          \n"     \
+                       "       .set    mips0                           \n"     \
+                       : "=&r" (result), "=&r" (temp), "+m" (v->counter)       \
+                       : "Ir" (i));                                            \
+               } while (unlikely(!result));                                    \
+                                                                               \
+               result = temp; result c_op i;                                   \
+       } else {                                                                \
+               unsigned long flags;                                            \
+                                                                               \
+               raw_local_irq_save(flags);                                      \
+               result = v->counter;                                            \
+               result c_op i;                                                  \
+               v->counter = result;                                            \
+               raw_local_irq_restore(flags);                                   \
+       }                                                                       \
+                                                                               \
+       smp_llsc_mb();                                                          \
+                                                                               \
+       return result;                                                          \
 }
 
-static __inline__ int atomic_sub_return(int i, atomic_t * v)
-{
-       int result;
+#define ATOMIC_OPS(op, c_op, asm_op)                                           \
+       ATOMIC_OP(op, c_op, asm_op)                                             \
+       ATOMIC_OP_RETURN(op, c_op, asm_op)
 
-       smp_mb__before_llsc();
+ATOMIC_OPS(add, +=, addu)
+ATOMIC_OPS(sub, -=, subu)
 
-       if (kernel_uses_llsc && R10000_LLSC_WAR) {
-               int temp;
-
-               __asm__ __volatile__(
-               "       .set    arch=r4000                              \n"
-               "1:     ll      %1, %2          # atomic_sub_return     \n"
-               "       subu    %0, %1, %3                              \n"
-               "       sc      %0, %2                                  \n"
-               "       beqzl   %0, 1b                                  \n"
-               "       subu    %0, %1, %3                              \n"
-               "       .set    mips0                                   \n"
-               : "=&r" (result), "=&r" (temp), "=m" (v->counter)
-               : "Ir" (i), "m" (v->counter)
-               : "memory");
-
-               result = temp - i;
-       } else if (kernel_uses_llsc) {
-               int temp;
-
-               do {
-                       __asm__ __volatile__(
-                       "       .set    arch=r4000                      \n"
-                       "       ll      %1, %2  # atomic_sub_return     \n"
-                       "       subu    %0, %1, %3                      \n"
-                       "       sc      %0, %2                          \n"
-                       "       .set    mips0                           \n"
-                       : "=&r" (result), "=&r" (temp), "+m" (v->counter)
-                       : "Ir" (i));
-               } while (unlikely(!result));
-
-               result = temp - i;
-       } else {
-               unsigned long flags;
-
-               raw_local_irq_save(flags);
-               result = v->counter;
-               result -= i;
-               v->counter = result;
-               raw_local_irq_restore(flags);
-       }
-
-       smp_llsc_mb();
-
-       return result;
-}
+#undef ATOMIC_OPS
+#undef ATOMIC_OP_RETURN
+#undef ATOMIC_OP
 
 /*
  * atomic_sub_if_positive - conditionally subtract integer from atomic variable
@@ -398,7 +306,7 @@ static __inline__ int __atomic_add_unless(atomic_t *v, int a, int u)
  * @v: pointer of type atomic64_t
  *
  */
-#define atomic64_read(v)       (*(volatile long *)&(v)->counter)
+#define atomic64_read(v)       ACCESS_ONCE((v)->counter)
 
 /*
  * atomic64_set - set atomic variable
@@ -407,195 +315,104 @@ static __inline__ int __atomic_add_unless(atomic_t *v, int a, int u)
  */
 #define atomic64_set(v, i)     ((v)->counter = (i))
 
-/*
- * atomic64_add - add integer to atomic variable
- * @i: integer value to add
- * @v: pointer of type atomic64_t
- *
- * Atomically adds @i to @v.
- */
-static __inline__ void atomic64_add(long i, atomic64_t * v)
-{
-       if (kernel_uses_llsc && R10000_LLSC_WAR) {
-               long temp;
-
-               __asm__ __volatile__(
-               "       .set    arch=r4000                              \n"
-               "1:     lld     %0, %1          # atomic64_add          \n"
-               "       daddu   %0, %2                                  \n"
-               "       scd     %0, %1                                  \n"
-               "       beqzl   %0, 1b                                  \n"
-               "       .set    mips0                                   \n"
-               : "=&r" (temp), "+m" (v->counter)
-               : "Ir" (i));
-       } else if (kernel_uses_llsc) {
-               long temp;
-
-               do {
-                       __asm__ __volatile__(
-                       "       .set    arch=r4000                      \n"
-                       "       lld     %0, %1          # atomic64_add  \n"
-                       "       daddu   %0, %2                          \n"
-                       "       scd     %0, %1                          \n"
-                       "       .set    mips0                           \n"
-                       : "=&r" (temp), "+m" (v->counter)
-                       : "Ir" (i));
-               } while (unlikely(!temp));
-       } else {
-               unsigned long flags;
-
-               raw_local_irq_save(flags);
-               v->counter += i;
-               raw_local_irq_restore(flags);
-       }
+#define ATOMIC64_OP(op, c_op, asm_op)                                          \
+static __inline__ void atomic64_##op(long i, atomic64_t * v)                   \
+{                                                                              \
+       if (kernel_uses_llsc && R10000_LLSC_WAR) {                              \
+               long temp;                                                      \
+                                                                               \
+               __asm__ __volatile__(                                           \
+               "       .set    arch=r4000                              \n"     \
+               "1:     lld     %0, %1          # atomic64_" #op "      \n"     \
+               "       " #asm_op " %0, %2                              \n"     \
+               "       scd     %0, %1                                  \n"     \
+               "       beqzl   %0, 1b                                  \n"     \
+               "       .set    mips0                                   \n"     \
+               : "=&r" (temp), "+m" (v->counter)                               \
+               : "Ir" (i));                                                    \
+       } else if (kernel_uses_llsc) {                                          \
+               long temp;                                                      \
+                                                                               \
+               do {                                                            \
+                       __asm__ __volatile__(                                   \
+                       "       .set    arch=r4000                      \n"     \
+                       "       lld     %0, %1          # atomic64_" #op "\n"   \
+                       "       " #asm_op " %0, %2                      \n"     \
+                       "       scd     %0, %1                          \n"     \
+                       "       .set    mips0                           \n"     \
+                       : "=&r" (temp), "+m" (v->counter)                       \
+                       : "Ir" (i));                                            \
+               } while (unlikely(!temp));                                      \
+       } else {                                                                \
+               unsigned long flags;                                            \
+                                                                               \
+               raw_local_irq_save(flags);                                      \
+               v->counter c_op i;                                              \
+               raw_local_irq_restore(flags);                                   \
+       }                                                                       \
+}                                                                              \
+
+#define ATOMIC64_OP_RETURN(op, c_op, asm_op)                                   \
+static __inline__ long atomic64_##op##_return(long i, atomic64_t * v)          \
+{                                                                              \
+       long result;                                                            \
+                                                                               \
+       smp_mb__before_llsc();                                                  \
+                                                                               \
+       if (kernel_uses_llsc && R10000_LLSC_WAR) {                              \
+               long temp;                                                      \
+                                                                               \
+               __asm__ __volatile__(                                           \
+               "       .set    arch=r4000                              \n"     \
+               "1:     lld     %1, %2          # atomic64_" #op "_return\n"    \
+               "       " #asm_op " %0, %1, %3                          \n"     \
+               "       scd     %0, %2                                  \n"     \
+               "       beqzl   %0, 1b                                  \n"     \
+               "       " #asm_op " %0, %1, %3                          \n"     \
+               "       .set    mips0                                   \n"     \
+               : "=&r" (result), "=&r" (temp), "+m" (v->counter)               \
+               : "Ir" (i));                                                    \
+       } else if (kernel_uses_llsc) {                                          \
+               long temp;                                                      \
+                                                                               \
+               do {                                                            \
+                       __asm__ __volatile__(                                   \
+                       "       .set    arch=r4000                      \n"     \
+                       "       lld     %1, %2  # atomic64_" #op "_return\n"    \
+                       "       " #asm_op " %0, %1, %3                  \n"     \
+                       "       scd     %0, %2                          \n"     \
+                       "       .set    mips0                           \n"     \
+                       : "=&r" (result), "=&r" (temp), "=m" (v->counter)       \
+                       : "Ir" (i), "m" (v->counter)                            \
+                       : "memory");                                            \
+               } while (unlikely(!result));                                    \
+                                                                               \
+               result = temp; result c_op i;                                   \
+       } else {                                                                \
+               unsigned long flags;                                            \
+                                                                               \
+               raw_local_irq_save(flags);                                      \
+               result = v->counter;                                            \
+               result c_op i;                                                  \
+               v->counter = result;                                            \
+               raw_local_irq_restore(flags);                                   \
+       }                                                                       \
+                                                                               \
+       smp_llsc_mb();                                                          \
+                                                                               \
+       return result;                                                          \
 }
 
-/*
- * atomic64_sub - subtract the atomic variable
- * @i: integer value to subtract
- * @v: pointer of type atomic64_t
- *
- * Atomically subtracts @i from @v.
- */
-static __inline__ void atomic64_sub(long i, atomic64_t * v)
-{
-       if (kernel_uses_llsc && R10000_LLSC_WAR) {
-               long temp;
-
-               __asm__ __volatile__(
-               "       .set    arch=r4000                              \n"
-               "1:     lld     %0, %1          # atomic64_sub          \n"
-               "       dsubu   %0, %2                                  \n"
-               "       scd     %0, %1                                  \n"
-               "       beqzl   %0, 1b                                  \n"
-               "       .set    mips0                                   \n"
-               : "=&r" (temp), "+m" (v->counter)
-               : "Ir" (i));
-       } else if (kernel_uses_llsc) {
-               long temp;
-
-               do {
-                       __asm__ __volatile__(
-                       "       .set    arch=r4000                      \n"
-                       "       lld     %0, %1          # atomic64_sub  \n"
-                       "       dsubu   %0, %2                          \n"
-                       "       scd     %0, %1                          \n"
-                       "       .set    mips0                           \n"
-                       : "=&r" (temp), "+m" (v->counter)
-                       : "Ir" (i));
-               } while (unlikely(!temp));
-       } else {
-               unsigned long flags;
-
-               raw_local_irq_save(flags);
-               v->counter -= i;
-               raw_local_irq_restore(flags);
-       }
-}
-
-/*
- * Same as above, but return the result value
- */
-static __inline__ long atomic64_add_return(long i, atomic64_t * v)
-{
-       long result;
+#define ATOMIC64_OPS(op, c_op, asm_op)                                         \
+       ATOMIC64_OP(op, c_op, asm_op)                                           \
+       ATOMIC64_OP_RETURN(op, c_op, asm_op)
 
-       smp_mb__before_llsc();
+ATOMIC64_OPS(add, +=, daddu)
+ATOMIC64_OPS(sub, -=, dsubu)
 
-       if (kernel_uses_llsc && R10000_LLSC_WAR) {
-               long temp;
-
-               __asm__ __volatile__(
-               "       .set    arch=r4000                              \n"
-               "1:     lld     %1, %2          # atomic64_add_return   \n"
-               "       daddu   %0, %1, %3                              \n"
-               "       scd     %0, %2                                  \n"
-               "       beqzl   %0, 1b                                  \n"
-               "       daddu   %0, %1, %3                              \n"
-               "       .set    mips0                                   \n"
-               : "=&r" (result), "=&r" (temp), "+m" (v->counter)
-               : "Ir" (i));
-       } else if (kernel_uses_llsc) {
-               long temp;
-
-               do {
-                       __asm__ __volatile__(
-                       "       .set    arch=r4000                      \n"
-                       "       lld     %1, %2  # atomic64_add_return   \n"
-                       "       daddu   %0, %1, %3                      \n"
-                       "       scd     %0, %2                          \n"
-                       "       .set    mips0                           \n"
-                       : "=&r" (result), "=&r" (temp), "=m" (v->counter)
-                       : "Ir" (i), "m" (v->counter)
-                       : "memory");
-               } while (unlikely(!result));
-
-               result = temp + i;
-       } else {
-               unsigned long flags;
-
-               raw_local_irq_save(flags);
-               result = v->counter;
-               result += i;
-               v->counter = result;
-               raw_local_irq_restore(flags);
-       }
-
-       smp_llsc_mb();
-
-       return result;
-}
-
-static __inline__ long atomic64_sub_return(long i, atomic64_t * v)
-{
-       long result;
-
-       smp_mb__before_llsc();
-
-       if (kernel_uses_llsc && R10000_LLSC_WAR) {
-               long temp;
-
-               __asm__ __volatile__(
-               "       .set    arch=r4000                              \n"
-               "1:     lld     %1, %2          # atomic64_sub_return   \n"
-               "       dsubu   %0, %1, %3                              \n"
-               "       scd     %0, %2                                  \n"
-               "       beqzl   %0, 1b                                  \n"
-               "       dsubu   %0, %1, %3                              \n"
-               "       .set    mips0                                   \n"
-               : "=&r" (result), "=&r" (temp), "=m" (v->counter)
-               : "Ir" (i), "m" (v->counter)
-               : "memory");
-       } else if (kernel_uses_llsc) {
-               long temp;
-
-               do {
-                       __asm__ __volatile__(
-                       "       .set    arch=r4000                      \n"
-                       "       lld     %1, %2  # atomic64_sub_return   \n"
-                       "       dsubu   %0, %1, %3                      \n"
-                       "       scd     %0, %2                          \n"
-                       "       .set    mips0                           \n"
-                       : "=&r" (result), "=&r" (temp), "=m" (v->counter)
-                       : "Ir" (i), "m" (v->counter)
-                       : "memory");
-               } while (unlikely(!result));
-
-               result = temp - i;
-       } else {
-               unsigned long flags;
-
-               raw_local_irq_save(flags);
-               result = v->counter;
-               result -= i;
-               v->counter = result;
-               raw_local_irq_restore(flags);
-       }
-
-       smp_llsc_mb();
-
-       return result;
-}
+#undef ATOMIC64_OPS
+#undef ATOMIC64_OP_RETURN
+#undef ATOMIC64_OP
 
 /*
  * atomic64_sub_if_positive - conditionally subtract integer from atomic variable
index 05f08438a7c468fde74c885d9291548a3b71eb68..f1df4cb4a286dc8f76f1186ca9b2b1c439ce1764 100644 (file)
@@ -397,12 +397,6 @@ unsigned long get_wchan(struct task_struct *p);
 #define ARCH_HAS_PREFETCHW
 #define prefetchw(x) __builtin_prefetch((x), 1, 1)
 
-/*
- * See Documentation/scheduler/sched-arch.txt; prevents deadlock on SMP
- * systems.
- */
-#define __ARCH_WANT_UNLOCKED_CTXSW
-
 #endif
 
 #endif /* _ASM_PROCESSOR_H */
index 645b3c4fcfba9ae747f378a54fcbaf797103492b..f7aac5b57b4b8e29470d0d2dd5ee37db4523398e 100644 (file)
@@ -770,7 +770,7 @@ asmlinkage long syscall_trace_enter(struct pt_regs *regs, long syscall)
        long ret = 0;
        user_exit();
 
-       if (secure_computing(syscall) == -1)
+       if (secure_computing() == -1)
                return -1;
 
        if (test_thread_flag(TIF_SYSCALL_TRACE) &&
index cadeb1e2cdfcfa1f473ac44f1e63a3a81b0c2fa9..5be655e83e709dbaf762efac0e3befea8dfd0d9f 100644 (file)
@@ -33,7 +33,6 @@
  * @v: pointer of type atomic_t
  *
  * Atomically reads the value of @v.  Note that the guaranteed
- * useful range of an atomic_t is only 24 bits.
  */
 #define atomic_read(v) (ACCESS_ONCE((v)->counter))
 
  * @i: required value
  *
  * Atomically sets the value of @v to @i.  Note that the guaranteed
- * useful range of an atomic_t is only 24 bits.
  */
 #define atomic_set(v, i) (((v)->counter) = (i))
 
-/**
- * atomic_add_return - add integer to atomic variable
- * @i: integer value to add
- * @v: pointer of type atomic_t
- *
- * Atomically adds @i to @v and returns the result
- * Note that the guaranteed useful range of an atomic_t is only 24 bits.
- */
-static inline int atomic_add_return(int i, atomic_t *v)
-{
-       int retval;
-#ifdef CONFIG_SMP
-       int status;
-
-       asm volatile(
-               "1:     mov     %4,(_AAR,%3)    \n"
-               "       mov     (_ADR,%3),%1    \n"
-               "       add     %5,%1           \n"
-               "       mov     %1,(_ADR,%3)    \n"
-               "       mov     (_ADR,%3),%0    \n"     /* flush */
-               "       mov     (_ASR,%3),%0    \n"
-               "       or      %0,%0           \n"
-               "       bne     1b              \n"
-               : "=&r"(status), "=&r"(retval), "=m"(v->counter)
-               : "a"(ATOMIC_OPS_BASE_ADDR), "r"(&v->counter), "r"(i)
-               : "memory", "cc");
-
-#else
-       unsigned long flags;
+#define ATOMIC_OP(op)                                                  \
+static inline void atomic_##op(int i, atomic_t *v)                     \
+{                                                                      \
+       int retval, status;                                             \
+                                                                       \
+       asm volatile(                                                   \
+               "1:     mov     %4,(_AAR,%3)    \n"                     \
+               "       mov     (_ADR,%3),%1    \n"                     \
+               "       " #op " %5,%1           \n"                     \
+               "       mov     %1,(_ADR,%3)    \n"                     \
+               "       mov     (_ADR,%3),%0    \n"     /* flush */     \
+               "       mov     (_ASR,%3),%0    \n"                     \
+               "       or      %0,%0           \n"                     \
+               "       bne     1b              \n"                     \
+               : "=&r"(status), "=&r"(retval), "=m"(v->counter)        \
+               : "a"(ATOMIC_OPS_BASE_ADDR), "r"(&v->counter), "r"(i)   \
+               : "memory", "cc");                                      \
+}
 
-       flags = arch_local_cli_save();
-       retval = v->counter;
-       retval += i;
-       v->counter = retval;
-       arch_local_irq_restore(flags);
-#endif
-       return retval;
+#define ATOMIC_OP_RETURN(op)                                           \
+static inline int atomic_##op##_return(int i, atomic_t *v)             \
+{                                                                      \
+       int retval, status;                                             \
+                                                                       \
+       asm volatile(                                                   \
+               "1:     mov     %4,(_AAR,%3)    \n"                     \
+               "       mov     (_ADR,%3),%1    \n"                     \
+               "       " #op " %5,%1           \n"                     \
+               "       mov     %1,(_ADR,%3)    \n"                     \
+               "       mov     (_ADR,%3),%0    \n"     /* flush */     \
+               "       mov     (_ASR,%3),%0    \n"                     \
+               "       or      %0,%0           \n"                     \
+               "       bne     1b              \n"                     \
+               : "=&r"(status), "=&r"(retval), "=m"(v->counter)        \
+               : "a"(ATOMIC_OPS_BASE_ADDR), "r"(&v->counter), "r"(i)   \
+               : "memory", "cc");                                      \
+       return retval;                                                  \
 }
 
-/**
- * atomic_sub_return - subtract integer from atomic variable
- * @i: integer value to subtract
- * @v: pointer of type atomic_t
- *
- * Atomically subtracts @i from @v and returns the result
- * Note that the guaranteed useful range of an atomic_t is only 24 bits.
- */
-static inline int atomic_sub_return(int i, atomic_t *v)
-{
-       int retval;
-#ifdef CONFIG_SMP
-       int status;
+#define ATOMIC_OPS(op) ATOMIC_OP(op) ATOMIC_OP_RETURN(op)
 
-       asm volatile(
-               "1:     mov     %4,(_AAR,%3)    \n"
-               "       mov     (_ADR,%3),%1    \n"
-               "       sub     %5,%1           \n"
-               "       mov     %1,(_ADR,%3)    \n"
-               "       mov     (_ADR,%3),%0    \n"     /* flush */
-               "       mov     (_ASR,%3),%0    \n"
-               "       or      %0,%0           \n"
-               "       bne     1b              \n"
-               : "=&r"(status), "=&r"(retval), "=m"(v->counter)
-               : "a"(ATOMIC_OPS_BASE_ADDR), "r"(&v->counter), "r"(i)
-               : "memory", "cc");
+ATOMIC_OPS(add)
+ATOMIC_OPS(sub)
 
-#else
-       unsigned long flags;
-       flags = arch_local_cli_save();
-       retval = v->counter;
-       retval -= i;
-       v->counter = retval;
-       arch_local_irq_restore(flags);
-#endif
-       return retval;
-}
+#undef ATOMIC_OPS
+#undef ATOMIC_OP_RETURN
+#undef ATOMIC_OP
 
 static inline int atomic_add_negative(int i, atomic_t *v)
 {
        return atomic_add_return(i, v) < 0;
 }
 
-static inline void atomic_add(int i, atomic_t *v)
-{
-       atomic_add_return(i, v);
-}
-
-static inline void atomic_sub(int i, atomic_t *v)
-{
-       atomic_sub_return(i, v);
-}
-
 static inline void atomic_inc(atomic_t *v)
 {
        atomic_add_return(1, v);
index 0be2db2c7d44bade175a0e3814444f21204d62c1..226f8ca993f69372016e634e345cf1d3a139cdb5 100644 (file)
@@ -55,24 +55,7 @@ extern arch_spinlock_t __atomic_hash[ATOMIC_HASH_SIZE] __lock_aligned;
  * are atomic, so a reader never sees inconsistent values.
  */
 
-/* It's possible to reduce all atomic operations to either
- * __atomic_add_return, atomic_set and atomic_read (the latter
- * is there only for consistency).
- */
-
-static __inline__ int __atomic_add_return(int i, atomic_t *v)
-{
-       int ret;
-       unsigned long flags;
-       _atomic_spin_lock_irqsave(v, flags);
-
-       ret = (v->counter += i);
-
-       _atomic_spin_unlock_irqrestore(v, flags);
-       return ret;
-}
-
-static __inline__ void atomic_set(atomic_t *v, int i) 
+static __inline__ void atomic_set(atomic_t *v, int i)
 {
        unsigned long flags;
        _atomic_spin_lock_irqsave(v, flags);
@@ -84,7 +67,7 @@ static __inline__ void atomic_set(atomic_t *v, int i)
 
 static __inline__ int atomic_read(const atomic_t *v)
 {
-       return (*(volatile int *)&(v)->counter);
+       return ACCESS_ONCE((v)->counter);
 }
 
 /* exported interface */
@@ -115,16 +98,43 @@ static __inline__ int __atomic_add_unless(atomic_t *v, int a, int u)
        return c;
 }
 
+#define ATOMIC_OP(op, c_op)                                            \
+static __inline__ void atomic_##op(int i, atomic_t *v)                 \
+{                                                                      \
+       unsigned long flags;                                            \
+                                                                       \
+       _atomic_spin_lock_irqsave(v, flags);                            \
+       v->counter c_op i;                                              \
+       _atomic_spin_unlock_irqrestore(v, flags);                       \
+}                                                                      \
+
+#define ATOMIC_OP_RETURN(op, c_op)                                     \
+static __inline__ int atomic_##op##_return(int i, atomic_t *v)         \
+{                                                                      \
+       unsigned long flags;                                            \
+       int ret;                                                        \
+                                                                       \
+       _atomic_spin_lock_irqsave(v, flags);                            \
+       ret = (v->counter c_op i);                                      \
+       _atomic_spin_unlock_irqrestore(v, flags);                       \
+                                                                       \
+       return ret;                                                     \
+}
+
+#define ATOMIC_OPS(op, c_op) ATOMIC_OP(op, c_op) ATOMIC_OP_RETURN(op, c_op)
+
+ATOMIC_OPS(add, +=)
+ATOMIC_OPS(sub, -=)
+
+#undef ATOMIC_OPS
+#undef ATOMIC_OP_RETURN
+#undef ATOMIC_OP
 
-#define atomic_add(i,v)        ((void)(__atomic_add_return(        (i),(v))))
-#define atomic_sub(i,v)        ((void)(__atomic_add_return(-((int) (i)),(v))))
-#define atomic_inc(v)  ((void)(__atomic_add_return(   1,(v))))
-#define atomic_dec(v)  ((void)(__atomic_add_return(  -1,(v))))
+#define atomic_inc(v)  (atomic_add(   1,(v)))
+#define atomic_dec(v)  (atomic_add(  -1,(v)))
 
-#define atomic_add_return(i,v) (__atomic_add_return( (i),(v)))
-#define atomic_sub_return(i,v) (__atomic_add_return(-(i),(v)))
-#define atomic_inc_return(v)   (__atomic_add_return(   1,(v)))
-#define atomic_dec_return(v)   (__atomic_add_return(  -1,(v)))
+#define atomic_inc_return(v)   (atomic_add_return(   1,(v)))
+#define atomic_dec_return(v)   (atomic_add_return(  -1,(v)))
 
 #define atomic_add_negative(a, v)      (atomic_add_return((a), (v)) < 0)
 
@@ -148,18 +158,37 @@ static __inline__ int __atomic_add_unless(atomic_t *v, int a, int u)
 
 #define ATOMIC64_INIT(i) { (i) }
 
-static __inline__ s64
-__atomic64_add_return(s64 i, atomic64_t *v)
-{
-       s64 ret;
-       unsigned long flags;
-       _atomic_spin_lock_irqsave(v, flags);
+#define ATOMIC64_OP(op, c_op)                                          \
+static __inline__ void atomic64_##op(s64 i, atomic64_t *v)             \
+{                                                                      \
+       unsigned long flags;                                            \
+                                                                       \
+       _atomic_spin_lock_irqsave(v, flags);                            \
+       v->counter c_op i;                                              \
+       _atomic_spin_unlock_irqrestore(v, flags);                       \
+}                                                                      \
+
+#define ATOMIC64_OP_RETURN(op, c_op)                                   \
+static __inline__ s64 atomic64_##op##_return(s64 i, atomic64_t *v)     \
+{                                                                      \
+       unsigned long flags;                                            \
+       s64 ret;                                                        \
+                                                                       \
+       _atomic_spin_lock_irqsave(v, flags);                            \
+       ret = (v->counter c_op i);                                      \
+       _atomic_spin_unlock_irqrestore(v, flags);                       \
+                                                                       \
+       return ret;                                                     \
+}
 
-       ret = (v->counter += i);
+#define ATOMIC64_OPS(op, c_op) ATOMIC64_OP(op, c_op) ATOMIC64_OP_RETURN(op, c_op)
 
-       _atomic_spin_unlock_irqrestore(v, flags);
-       return ret;
-}
+ATOMIC64_OPS(add, +=)
+ATOMIC64_OPS(sub, -=)
+
+#undef ATOMIC64_OPS
+#undef ATOMIC64_OP_RETURN
+#undef ATOMIC64_OP
 
 static __inline__ void
 atomic64_set(atomic64_t *v, s64 i)
@@ -175,18 +204,14 @@ atomic64_set(atomic64_t *v, s64 i)
 static __inline__ s64
 atomic64_read(const atomic64_t *v)
 {
-       return (*(volatile long *)&(v)->counter);
+       return ACCESS_ONCE((v)->counter);
 }
 
-#define atomic64_add(i,v)      ((void)(__atomic64_add_return( ((s64)(i)),(v))))
-#define atomic64_sub(i,v)      ((void)(__atomic64_add_return(-((s64)(i)),(v))))
-#define atomic64_inc(v)                ((void)(__atomic64_add_return(   1,(v))))
-#define atomic64_dec(v)                ((void)(__atomic64_add_return(  -1,(v))))
+#define atomic64_inc(v)                (atomic64_add(   1,(v)))
+#define atomic64_dec(v)                (atomic64_add(  -1,(v)))
 
-#define atomic64_add_return(i,v)       (__atomic64_add_return( ((s64)(i)),(v)))
-#define atomic64_sub_return(i,v)       (__atomic64_add_return(-((s64)(i)),(v)))
-#define atomic64_inc_return(v)         (__atomic64_add_return(   1,(v)))
-#define atomic64_dec_return(v)         (__atomic64_add_return(  -1,(v)))
+#define atomic64_inc_return(v)         (atomic64_add_return(   1,(v)))
+#define atomic64_dec_return(v)         (atomic64_add_return(  -1,(v)))
 
 #define atomic64_add_negative(a, v)    (atomic64_add_return((a), (v)) < 0)
 
index f5645d6a89f2c9c79e8e22cd9a7201df6dc389df..10df7079f4cdf08dec0e26d871e4270d157a50ed 100644 (file)
@@ -8,12 +8,12 @@
 #define SIGTRAP                 5
 #define SIGABRT                 6
 #define SIGIOT          6
-#define SIGEMT          7
+#define SIGSTKFLT       7
 #define SIGFPE          8
 #define SIGKILL                 9
 #define SIGBUS         10
 #define SIGSEGV                11
-#define SIGSYS         12 /* Linux doesn't use this */
+#define SIGXCPU                12
 #define SIGPIPE                13
 #define SIGALRM                14
 #define SIGTERM                15
 #define SIGTTIN                27
 #define SIGTTOU                28
 #define SIGURG         29
-#define SIGLOST                30 /* Linux doesn't use this either */
-#define        SIGUNUSED       31
-#define SIGRESERVE     SIGUNUSED
-
-#define SIGXCPU                33
-#define SIGXFSZ                34
-#define SIGSTKFLT      36
+#define SIGXFSZ                30
+#define SIGUNUSED      31
+#define SIGSYS         31 /* Linux doesn't use this */
 
 /* These should not be considered constants from userland.  */
-#define SIGRTMIN       37
+#define SIGRTMIN       32
 #define SIGRTMAX       _NSIG /* it's 44 under HP/UX */
 
 /*
index 4bc7b62fb4b68761341619d7bd8300dbb8786d76..88eace4e28c3dfbdbbe35261f0f03656f8616a1e 100644 (file)
@@ -147,6 +147,7 @@ config PPC
        select ARCH_USE_CMPXCHG_LOCKREF if PPC64
        select HAVE_ARCH_AUDITSYSCALL
        select ARCH_SUPPORTS_ATOMIC_RMW
+       select DCACHE_WORD_ACCESS if PPC64 && CPU_LITTLE_ENDIAN
 
 config GENERIC_CSUM
        def_bool CPU_LITTLE_ENDIAN
@@ -182,7 +183,7 @@ config SCHED_OMIT_FRAME_POINTER
 
 config ARCH_MAY_HAVE_PC_FDC
        bool
-       default !PPC_PSERIES || PCI
+       default PCI
 
 config PPC_OF
        def_bool y
@@ -287,6 +288,10 @@ config PPC_EMULATE_SSTEP
        bool
        default y if KPROBES || UPROBES || XMON || HAVE_HW_BREAKPOINT
 
+config ZONE_DMA32
+       bool
+       default y if PPC64
+
 source "init/Kconfig"
 
 source "kernel/Kconfig.freezer"
@@ -603,6 +608,10 @@ config PPC_SUBPAGE_PROT
          to set access permissions (read/write, readonly, or no access)
          on the 4k subpages of each 64k page.
 
+config PPC_COPRO_BASE
+       bool
+       default n
+
 config SCHED_SMT
        bool "SMT (Hyperthreading) scheduler support"
        depends on PPC64 && SMP
index 5687e299d0a5b3b58970804a04af057d3b6f64f4..132d9c681d6ae275ca6129a20fee4b9e55487840 100644 (file)
@@ -135,6 +135,7 @@ CFLAGS-$(CONFIG_POWER4_CPU) += $(call cc-option,-mcpu=power4)
 CFLAGS-$(CONFIG_POWER5_CPU) += $(call cc-option,-mcpu=power5)
 CFLAGS-$(CONFIG_POWER6_CPU) += $(call cc-option,-mcpu=power6)
 CFLAGS-$(CONFIG_POWER7_CPU) += $(call cc-option,-mcpu=power7)
+CFLAGS-$(CONFIG_POWER8_CPU) += $(call cc-option,-mcpu=power8)
 
 # Altivec option not allowed with e500mc64 in GCC.
 ifeq ($(CONFIG_ALTIVEC),y)
index ccc25eddbcb8b2ff8404d66cecbaec1e450f5a51..8a5bc1cfc6aa0fa16a52c2ef1be0ae3b18999966 100644 (file)
@@ -389,7 +389,12 @@ $(obj)/zImage:             $(addprefix $(obj)/, $(image-y))
 $(obj)/zImage.initrd:  $(addprefix $(obj)/, $(initrd-y))
        @rm -f $@; ln $< $@
 
+# Only install the vmlinux
 install: $(CONFIGURE) $(addprefix $(obj)/, $(image-y))
+       sh -x $(srctree)/$(src)/install.sh "$(KERNELRELEASE)" vmlinux System.map "$(INSTALL_PATH)"
+
+# Install the vmlinux and other built boot targets.
+zInstall: $(CONFIGURE) $(addprefix $(obj)/, $(image-y))
        sh -x $(srctree)/$(src)/install.sh "$(KERNELRELEASE)" vmlinux System.map "$(INSTALL_PATH)" $^
 
 # anything not in $(targets)
index 97479f0ce630317f97000a073702e5467335031d..aecee9690a88a0ec09320f5b43c9740bdfb2c4cf 100644 (file)
 /include/ "qoriq-gpio-3.dtsi"
 /include/ "qoriq-usb2-mph-0.dtsi"
        usb0: usb@210000 {
-               compatible = "fsl-usb2-mph-v2.4", "fsl-usb2-mph";
+               compatible = "fsl-usb2-mph-v2.5", "fsl-usb2-mph";
                fsl,iommu-parent = <&pamu1>;
                fsl,liodn-reg = <&guts 0x520>; /* USB1LIODNR */
                phy_type = "utmi";
        };
 /include/ "qoriq-usb2-dr-0.dtsi"
        usb1: usb@211000 {
-               compatible = "fsl-usb2-dr-v2.4", "fsl-usb2-dr";
+               compatible = "fsl-usb2-dr-v2.5", "fsl-usb2-dr";
                fsl,iommu-parent = <&pamu1>;
                fsl,liodn-reg = <&guts 0x524>; /* USB1LIODNR */
                dr_mode = "host";
index a3d582e0361ae706920a4eba4d8e50bcce177b58..7e2fc7cdce4833039a80f8fa650c7292a7b030e1 100644 (file)
 /include/ "qoriq-gpio-3.dtsi"
 /include/ "qoriq-usb2-mph-0.dtsi"
                usb0: usb@210000 {
-                       compatible = "fsl-usb2-mph-v2.4", "fsl-usb2-mph";
+                       compatible = "fsl-usb2-mph-v2.5", "fsl-usb2-mph";
                        phy_type = "utmi";
                        port0;
                };
 /include/ "qoriq-usb2-dr-0.dtsi"
                usb1: usb@211000 {
-                       compatible = "fsl-usb2-dr-v2.4", "fsl-usb2-dr";
+                       compatible = "fsl-usb2-dr-v2.5", "fsl-usb2-dr";
                        dr_mode = "host";
                        phy_type = "utmi";
                };
diff --git a/arch/powerpc/boot/dts/t1040rdb.dts b/arch/powerpc/boot/dts/t1040rdb.dts
new file mode 100644 (file)
index 0000000..79a0bed
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * T1040RDB Device Tree Source
+ *
+ * Copyright 2014 Freescale Semiconductor Inc.
+ *
+ * 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 Freescale Semiconductor nor the
+ *      names of its contributors may be used to endorse or promote products
+ *      derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor "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 Freescale Semiconductor 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/ "fsl/t104xsi-pre.dtsi"
+/include/ "t104xrdb.dtsi"
+
+/ {
+       model = "fsl,T1040RDB";
+       compatible = "fsl,T1040RDB";
+       ifc: localbus@ffe124000 {
+               cpld@3,0 {
+                       compatible = "fsl,t1040rdb-cpld";
+               };
+       };
+};
+
+/include/ "fsl/t1040si-post.dtsi"
diff --git a/arch/powerpc/boot/dts/t1042rdb.dts b/arch/powerpc/boot/dts/t1042rdb.dts
new file mode 100644 (file)
index 0000000..738c237
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * T1042RDB Device Tree Source
+ *
+ * Copyright 2014 Freescale Semiconductor Inc.
+ *
+ * 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 Freescale Semiconductor nor the
+ *      names of its contributors may be used to endorse or promote products
+ *      derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor "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 Freescale Semiconductor 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/ "fsl/t104xsi-pre.dtsi"
+/include/ "t104xrdb.dtsi"
+
+/ {
+       model = "fsl,T1042RDB";
+       compatible = "fsl,T1042RDB";
+       ifc: localbus@ffe124000 {
+               cpld@3,0 {
+                       compatible = "fsl,t1042rdb-cpld";
+               };
+       };
+};
+
+/include/ "fsl/t1042si-post.dtsi"
diff --git a/arch/powerpc/boot/dts/t1042rdb_pi.dts b/arch/powerpc/boot/dts/t1042rdb_pi.dts
new file mode 100644 (file)
index 0000000..634f751
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * T1042RDB_PI Device Tree Source
+ *
+ * Copyright 2014 Freescale Semiconductor Inc.
+ *
+ * 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 Freescale Semiconductor nor the
+ *      names of its contributors may be used to endorse or promote products
+ *      derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor "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 Freescale Semiconductor 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/ "fsl/t104xsi-pre.dtsi"
+/include/ "t104xrdb.dtsi"
+
+/ {
+       model = "fsl,T1042RDB_PI";
+       compatible = "fsl,T1042RDB_PI";
+       ifc: localbus@ffe124000 {
+               cpld@3,0 {
+                       compatible = "fsl,t1042rdb_pi-cpld";
+               };
+       };
+       soc: soc@ffe000000 {
+               i2c@118000 {
+                       rtc@68 {
+                               compatible = "dallas,ds1337";
+                               reg = <0x68>;
+                               interrupts = <0x2 0x1 0 0>;
+                       };
+               };
+       };
+};
+
+/include/ "fsl/t1042si-post.dtsi"
diff --git a/arch/powerpc/boot/dts/t104xrdb.dtsi b/arch/powerpc/boot/dts/t104xrdb.dtsi
new file mode 100644 (file)
index 0000000..1cf0f3c
--- /dev/null
@@ -0,0 +1,156 @@
+/*
+ * T1040RDB/T1042RDB Device Tree Source
+ *
+ * Copyright 2014 Freescale Semiconductor Inc.
+ *
+ * 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 Freescale Semiconductor nor the
+ *      names of its contributors may be used to endorse or promote products
+ *      derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor "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 Freescale Semiconductor 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.
+ */
+
+/ {
+
+       ifc: localbus@ffe124000 {
+               reg = <0xf 0xfe124000 0 0x2000>;
+               ranges = <0 0 0xf 0xe8000000 0x08000000
+                         2 0 0xf 0xff800000 0x00010000
+                         3 0 0xf 0xffdf0000 0x00008000>;
+
+               nor@0,0 {
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       compatible = "cfi-flash";
+                       reg = <0x0 0x0 0x8000000>;
+                       bank-width = <2>;
+                       device-width = <1>;
+               };
+
+               nand@2,0 {
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       compatible = "fsl,ifc-nand";
+                       reg = <0x2 0x0 0x10000>;
+               };
+
+               cpld@3,0 {
+                       reg = <3 0 0x300>;
+               };
+       };
+
+       memory {
+               device_type = "memory";
+       };
+
+       dcsr: dcsr@f00000000 {
+               ranges = <0x00000000 0xf 0x00000000 0x01072000>;
+       };
+
+       soc: soc@ffe000000 {
+               ranges = <0x00000000 0xf 0xfe000000 0x1000000>;
+               reg = <0xf 0xfe000000 0 0x00001000>;
+
+               spi@110000 {
+                       flash@0 {
+                               #address-cells = <1>;
+                               #size-cells = <1>;
+                               compatible = "micron,n25q512a";
+                               reg = <0>;
+                               spi-max-frequency = <10000000>; /* input clock */
+                       };
+               };
+
+               i2c@118100 {
+                       pca9546@77 {
+                               compatible = "nxp,pca9546";
+                               reg = <0x77>;
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                       };
+               };
+
+       };
+
+       pci0: pcie@ffe240000 {
+               reg = <0xf 0xfe240000 0 0x10000>;
+               ranges = <0x02000000 0 0xe0000000 0xc 0x00000000 0x0 0x10000000
+                         0x01000000 0 0x00000000 0xf 0xf8000000 0x0 0x00010000>;
+               pcie@0 {
+                       ranges = <0x02000000 0 0xe0000000
+                                 0x02000000 0 0xe0000000
+                                 0 0x10000000
+
+                                 0x01000000 0 0x00000000
+                                 0x01000000 0 0x00000000
+                                 0 0x00010000>;
+               };
+       };
+
+       pci1: pcie@ffe250000 {
+               reg = <0xf 0xfe250000 0 0x10000>;
+               ranges = <0x02000000 0x0 0xe0000000 0xc 0x10000000 0x0 0x10000000
+                         0x01000000 0x0 0x00000000 0xf 0xf8010000 0x0 0x00010000>;
+               pcie@0 {
+                       ranges = <0x02000000 0 0xe0000000
+                                 0x02000000 0 0xe0000000
+                                 0 0x10000000
+
+                                 0x01000000 0 0x00000000
+                                 0x01000000 0 0x00000000
+                                 0 0x00010000>;
+               };
+       };
+
+       pci2: pcie@ffe260000 {
+               reg = <0xf 0xfe260000 0 0x10000>;
+               ranges = <0x02000000 0 0xe0000000 0xc 0x20000000 0 0x10000000
+                         0x01000000 0 0x00000000 0xf 0xf8020000 0 0x00010000>;
+               pcie@0 {
+                       ranges = <0x02000000 0 0xe0000000
+                                 0x02000000 0 0xe0000000
+                                 0 0x10000000
+
+                                 0x01000000 0 0x00000000
+                                 0x01000000 0 0x00000000
+                                 0 0x00010000>;
+               };
+       };
+
+       pci3: pcie@ffe270000 {
+               reg = <0xf 0xfe270000 0 0x10000>;
+               ranges = <0x02000000 0 0xe0000000 0xc 0x30000000 0 0x10000000
+                         0x01000000 0 0x00000000 0xf 0xf8030000 0 0x00010000>;
+               pcie@0 {
+                       ranges = <0x02000000 0 0xe0000000
+                                 0x02000000 0 0xe0000000
+                                 0 0x10000000
+
+                                 0x01000000 0 0x00000000
+                                 0x01000000 0 0x00000000
+                                 0 0x00010000>;
+               };
+       };
+};
index 45fd06cdc3e86639d3ddc829c4d44c8db0069bd0..7a7b3c879f96f83723c132a22c4367297215599a 100644 (file)
@@ -18,6 +18,7 @@ CONFIG_OPROFILE=m
 CONFIG_MODULES=y
 CONFIG_MODULE_UNLOAD=y
 # CONFIG_BLK_DEV_BSG is not set
+# CONFIG_PPC_POWERNV is not set
 # CONFIG_PPC_PSERIES is not set
 # CONFIG_PPC_PMAC is not set
 CONFIG_PPC_PS3=y
index 77d7bf3ca2acb014def979d68d21c7f94401ed10..acccbfde8a5094293c681aecf45fb3f32eea9e7b 100644 (file)
@@ -15,6 +15,7 @@ CONFIG_MODULES=y
 CONFIG_MODULE_UNLOAD=y
 CONFIG_MODVERSIONS=y
 CONFIG_MODULE_SRCVERSION_ALL=y
+# CONFIG_PPC_POWERNV is not set
 # CONFIG_PPC_PSERIES is not set
 # CONFIG_PPC_PMAC is not set
 CONFIG_PPC_CELLEB=y
index 6a3c58adf2530a45f312cc3df25d90934880b6ae..688e9e4d29a1a699af841aadb4ba1865cf442061 100644 (file)
@@ -165,6 +165,8 @@ CONFIG_NFS_FS=y
 CONFIG_NFS_V4=y
 CONFIG_ROOT_NFS=y
 CONFIG_NFSD=m
+CONFIG_NLS_CODEPAGE_437=y
+CONFIG_NLS_CODEPAGE_850=y
 CONFIG_NLS_ISO8859_1=y
 CONFIG_NLS_UTF8=m
 CONFIG_MAGIC_SYSRQ=y
index 269d6e47c67d2a998272f27545ec238766c68dc8..6db97e4414b2eabaa92b82af533f7facd646e675 100644 (file)
@@ -50,7 +50,6 @@ CONFIG_NET_IPIP=y
 CONFIG_IP_MROUTE=y
 CONFIG_IP_PIMSM_V1=y
 CONFIG_IP_PIMSM_V2=y
-CONFIG_ARPD=y
 CONFIG_INET_ESP=y
 # CONFIG_INET_XFRM_MODE_BEET is not set
 # CONFIG_INET_LRO is not set
@@ -60,33 +59,17 @@ CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 CONFIG_DEVTMPFS=y
 CONFIG_DEVTMPFS_MOUNT=y
 CONFIG_MTD=y
-CONFIG_MTD_OF_PARTS=y
 CONFIG_MTD_CMDLINE_PARTS=y
-CONFIG_MTD_CHAR=y
-CONFIG_MTD_BLKDEVS=y
 CONFIG_MTD_BLOCK=y
 CONFIG_FTL=y
 CONFIG_MTD_CFI=y
-CONFIG_MTD_GEN_PROBE=y
-CONFIG_MTD_MAP_BANK_WIDTH_1=y
-CONFIG_MTD_MAP_BANK_WIDTH_2=y
-CONFIG_MTD_MAP_BANK_WIDTH_4=y
-CONFIG_MTD_CFI_I1=y
-CONFIG_MTD_CFI_I2=y
 CONFIG_MTD_CFI_INTELEXT=y
 CONFIG_MTD_CFI_AMDSTD=y
 CONFIG_MTD_PHYSMAP_OF=y
-CONFIG_MTD_M25P80=y
-CONFIG_MTD_CFI_UTIL=y
-CONFIG_MTD_NAND_ECC=y
 CONFIG_MTD_NAND=y
-CONFIG_MTD_NAND_IDS=y
 CONFIG_MTD_NAND_FSL_ELBC=y
 CONFIG_MTD_NAND_FSL_IFC=y
 CONFIG_MTD_UBI=y
-CONFIG_MTD_UBI_WL_THRESHOLD=4096
-CONFIG_MTD_UBI_BEB_RESERVE=1
-CONFIG_PROC_DEVICETREE=y
 CONFIG_BLK_DEV_LOOP=y
 CONFIG_BLK_DEV_RAM=y
 CONFIG_BLK_DEV_RAM_SIZE=131072
@@ -102,6 +85,7 @@ CONFIG_INPUT_FF_MEMLESS=m
 # CONFIG_INPUT_KEYBOARD is not set
 # CONFIG_INPUT_MOUSE is not set
 CONFIG_SERIO_LIBPS2=y
+CONFIG_PPC_EPAPR_HV_BYTECHAN=y
 CONFIG_SERIAL_8250=y
 CONFIG_SERIAL_8250_CONSOLE=y
 CONFIG_SERIAL_8250_MANY_PORTS=y
@@ -115,7 +99,6 @@ CONFIG_SPI_GPIO=y
 CONFIG_SPI_FSL_SPI=y
 CONFIG_SPI_FSL_ESPI=y
 # CONFIG_HWMON is not set
-CONFIG_VIDEO_OUTPUT_CONTROL=y
 CONFIG_USB_HID=m
 CONFIG_USB=y
 CONFIG_USB_MON=y
@@ -124,14 +107,17 @@ CONFIG_USB_EHCI_FSL=y
 CONFIG_USB_STORAGE=y
 CONFIG_MMC=y
 CONFIG_MMC_SDHCI=y
+CONFIG_EDAC=y
+CONFIG_EDAC_MM_EDAC=y
 CONFIG_RTC_CLASS=y
 CONFIG_RTC_DRV_DS1307=y
 CONFIG_RTC_DRV_DS1374=y
 CONFIG_RTC_DRV_DS3232=y
-CONFIG_EDAC=y
-CONFIG_EDAC_MM_EDAC=y
 CONFIG_DMADEVICES=y
 CONFIG_FSL_DMA=y
+CONFIG_VIRT_DRIVERS=y
+CONFIG_FSL_HV_MANAGER=y
+CONFIG_FSL_CORENET_CF=y
 CONFIG_EXT2_FS=y
 CONFIG_EXT3_FS=y
 CONFIG_ISO9660_FS=m
@@ -144,35 +130,24 @@ CONFIG_NTFS_FS=y
 CONFIG_PROC_KCORE=y
 CONFIG_TMPFS=y
 CONFIG_HUGETLBFS=y
-CONFIG_MISC_FILESYSTEMS=y
 CONFIG_JFFS2_FS=y
 CONFIG_JFFS2_FS_DEBUG=1
-CONFIG_JFFS2_FS_WRITEBUFFER=y
-CONFIG_JFFS2_ZLIB=y
-CONFIG_JFFS2_RTIME=y
 CONFIG_UBIFS_FS=y
-CONFIG_UBIFS_FS_XATTR=y
-CONFIG_UBIFS_FS_LZO=y
-CONFIG_UBIFS_FS_ZLIB=y
 CONFIG_NFS_FS=y
 CONFIG_NFS_V4=y
 CONFIG_ROOT_NFS=y
 CONFIG_NFSD=m
+CONFIG_NLS_CODEPAGE_437=y
+CONFIG_NLS_CODEPAGE_850=y
 CONFIG_NLS_ISO8859_1=y
 CONFIG_NLS_UTF8=m
 CONFIG_CRC_T10DIF=y
-CONFIG_CRC16=y
-CONFIG_ZLIB_DEFLATE=y
-CONFIG_LZO_COMPRESS=y
-CONFIG_LZO_DECOMPRESS=y
-CONFIG_CRYPTO_DEFLATE=y
-CONFIG_CRYPTO_LZO=y
+CONFIG_DEBUG_INFO=y
 CONFIG_FRAME_WARN=1024
-CONFIG_MAGIC_SYSRQ=y
 CONFIG_DEBUG_FS=y
+CONFIG_MAGIC_SYSRQ=y
 CONFIG_DEBUG_SHIRQ=y
 CONFIG_DETECT_HUNG_TASK=y
-CONFIG_DEBUG_INFO=y
 CONFIG_CRYPTO_NULL=y
 CONFIG_CRYPTO_PCBC=m
 CONFIG_CRYPTO_MD4=y
@@ -180,4 +155,3 @@ CONFIG_CRYPTO_SHA256=y
 CONFIG_CRYPTO_SHA512=y
 # CONFIG_CRYPTO_ANSI_CPRNG is not set
 CONFIG_CRYPTO_DEV_FSL_CAAM=y
-CONFIG_FSL_CORENET_CF=y
index 7594c5ac64818f6b01537bb0c0be3519c73bd455..6fab06f7f4117bb65ee7ee6594706edd281c6d65 100644 (file)
@@ -16,6 +16,7 @@ CONFIG_MODULES=y
 CONFIG_MODULE_UNLOAD=y
 CONFIG_MODVERSIONS=y
 CONFIG_MODULE_SRCVERSION_ALL=y
+# CONFIG_PPC_POWERNV is not set
 # CONFIG_PPC_PSERIES is not set
 CONFIG_CPU_FREQ=y
 CONFIG_CPU_FREQ_GOV_POWERSAVE=y
index c8b6a9ddb21bf813c448dfc4f847a3f611c23dd1..fbd9e4163311c060ee67bdbe35caba1083fc1601 100644 (file)
@@ -16,6 +16,7 @@ CONFIG_MODULE_UNLOAD=y
 CONFIG_MODVERSIONS=y
 CONFIG_MODULE_SRCVERSION_ALL=y
 # CONFIG_BLK_DEV_BSG is not set
+# CONFIG_PPC_POWERNV is not set
 # CONFIG_PPC_PSERIES is not set
 # CONFIG_PPC_PMAC is not set
 CONFIG_PPC_MAPLE=y
index fa1bfd37f1ec446551eafac579d9a3141738856e..d2c415489f724b4c3acdc6b8ea7d0f8b83ff5341 100644 (file)
@@ -213,7 +213,6 @@ CONFIG_RTC_DRV_DS1307=y
 CONFIG_RTC_DRV_DS1374=y
 CONFIG_RTC_DRV_DS3232=y
 CONFIG_RTC_DRV_CMOS=y
-CONFIG_RTC_DRV_DS1307=y
 CONFIG_DMADEVICES=y
 CONFIG_FSL_DMA=y
 # CONFIG_NET_DMA is not set
@@ -227,6 +226,9 @@ CONFIG_UDF_FS=m
 CONFIG_MSDOS_FS=m
 CONFIG_VFAT_FS=y
 CONFIG_NTFS_FS=y
+CONFIG_NLS_CODEPAGE_437=y
+CONFIG_NLS_CODEPAGE_850=y
+CONFIG_NLS_ISO8859_1=y
 CONFIG_PROC_KCORE=y
 CONFIG_TMPFS=y
 CONFIG_HUGETLBFS=y
index 0b452ebd8b3d7d8b0569a9196470ee205993278d..87460083dbc7a508fcd567db4b1ba7fa5728a40d 100644 (file)
@@ -214,7 +214,6 @@ CONFIG_RTC_DRV_DS1307=y
 CONFIG_RTC_DRV_DS1374=y
 CONFIG_RTC_DRV_DS3232=y
 CONFIG_RTC_DRV_CMOS=y
-CONFIG_RTC_DRV_DS1307=y
 CONFIG_DMADEVICES=y
 CONFIG_FSL_DMA=y
 # CONFIG_NET_DMA is not set
@@ -228,6 +227,9 @@ CONFIG_UDF_FS=m
 CONFIG_MSDOS_FS=m
 CONFIG_VFAT_FS=y
 CONFIG_NTFS_FS=y
+CONFIG_NLS_CODEPAGE_437=y
+CONFIG_NLS_CODEPAGE_850=y
+CONFIG_NLS_ISO8859_1=y
 CONFIG_PROC_KCORE=y
 CONFIG_TMPFS=y
 CONFIG_HUGETLBFS=y
index 35595ea74ff4208c48a16a0e5252eb6716150178..fc58aa8a89e498b859f8d53e6ae19adade127678 100644 (file)
@@ -145,6 +145,9 @@ CONFIG_UDF_FS=m
 CONFIG_MSDOS_FS=m
 CONFIG_VFAT_FS=y
 CONFIG_NTFS_FS=y
+CONFIG_NLS_CODEPAGE_437=y
+CONFIG_NLS_CODEPAGE_850=y
+CONFIG_NLS_ISO8859_1=y
 CONFIG_PROC_KCORE=y
 CONFIG_TMPFS=y
 CONFIG_ADFS_FS=m
index e5e7838af0088f04b8faf5f40d8204962bd0bb6f..3e72c8c06a0dc7d3c9cb9470066dc33f93cc894f 100644 (file)
@@ -14,6 +14,7 @@ CONFIG_MODULE_UNLOAD=y
 # CONFIG_BLK_DEV_BSG is not set
 CONFIG_PARTITION_ADVANCED=y
 CONFIG_MAC_PARTITION=y
+# CONFIG_PPC_POWERNV is not set
 # CONFIG_PPC_PSERIES is not set
 # CONFIG_PPC_PMAC is not set
 CONFIG_PPC_PASEMI=y
index 36518870e6b29f75811b0b7ec4cddcb7859c04b5..20bc5e2d368d05601fd267ac81c2b375c9f95e6d 100644 (file)
@@ -50,6 +50,7 @@ CONFIG_HZ_100=y
 CONFIG_BINFMT_MISC=m
 CONFIG_PPC_TRANSACTIONAL_MEM=y
 CONFIG_KEXEC=y
+CONFIG_CRASH_DUMP=y
 CONFIG_IRQ_ALL_CPUS=y
 CONFIG_MEMORY_HOTREMOVE=y
 CONFIG_SCHED_SMT=y
index 28992d01292633f2d473eeae47e202497fa691a6..512d2782b043ddc506c865028b1e7dc54a871b75 100644 (file)
@@ -26,76 +26,53 @@ static __inline__ void atomic_set(atomic_t *v, int i)
        __asm__ __volatile__("stw%U0%X0 %1,%0" : "=m"(v->counter) : "r"(i));
 }
 
-static __inline__ void atomic_add(int a, atomic_t *v)
-{
-       int t;
-
-       __asm__ __volatile__(
-"1:    lwarx   %0,0,%3         # atomic_add\n\
-       add     %0,%2,%0\n"
-       PPC405_ERR77(0,%3)
-"      stwcx.  %0,0,%3 \n\
-       bne-    1b"
-       : "=&r" (t), "+m" (v->counter)
-       : "r" (a), "r" (&v->counter)
-       : "cc");
+#define ATOMIC_OP(op, asm_op)                                          \
+static __inline__ void atomic_##op(int a, atomic_t *v)                 \
+{                                                                      \
+       int t;                                                          \
+                                                                       \
+       __asm__ __volatile__(                                           \
+"1:    lwarx   %0,0,%3         # atomic_" #op "\n"                     \
+       #asm_op " %0,%2,%0\n"                                           \
+       PPC405_ERR77(0,%3)                                              \
+"      stwcx.  %0,0,%3 \n"                                             \
+"      bne-    1b\n"                                                   \
+       : "=&r" (t), "+m" (v->counter)                                  \
+       : "r" (a), "r" (&v->counter)                                    \
+       : "cc");                                                        \
+}                                                                      \
+
+#define ATOMIC_OP_RETURN(op, asm_op)                                   \
+static __inline__ int atomic_##op##_return(int a, atomic_t *v)         \
+{                                                                      \
+       int t;                                                          \
+                                                                       \
+       __asm__ __volatile__(                                           \
+       PPC_ATOMIC_ENTRY_BARRIER                                        \
+"1:    lwarx   %0,0,%2         # atomic_" #op "_return\n"              \
+       #asm_op " %0,%1,%0\n"                                           \
+       PPC405_ERR77(0,%2)                                              \
+"      stwcx.  %0,0,%2 \n"                                             \
+"      bne-    1b\n"                                                   \
+       PPC_ATOMIC_EXIT_BARRIER                                         \
+       : "=&r" (t)                                                     \
+       : "r" (a), "r" (&v->counter)                                    \
+       : "cc", "memory");                                              \
+                                                                       \
+       return t;                                                       \
 }
 
-static __inline__ int atomic_add_return(int a, atomic_t *v)
-{
-       int t;
+#define ATOMIC_OPS(op, asm_op) ATOMIC_OP(op, asm_op) ATOMIC_OP_RETURN(op, asm_op)
 
-       __asm__ __volatile__(
-       PPC_ATOMIC_ENTRY_BARRIER
-"1:    lwarx   %0,0,%2         # atomic_add_return\n\
-       add     %0,%1,%0\n"
-       PPC405_ERR77(0,%2)
-"      stwcx.  %0,0,%2 \n\
-       bne-    1b"
-       PPC_ATOMIC_EXIT_BARRIER
-       : "=&r" (t)
-       : "r" (a), "r" (&v->counter)
-       : "cc", "memory");
+ATOMIC_OPS(add, add)
+ATOMIC_OPS(sub, subf)
 
-       return t;
-}
+#undef ATOMIC_OPS
+#undef ATOMIC_OP_RETURN
+#undef ATOMIC_OP
 
 #define atomic_add_negative(a, v)      (atomic_add_return((a), (v)) < 0)
 
-static __inline__ void atomic_sub(int a, atomic_t *v)
-{
-       int t;
-
-       __asm__ __volatile__(
-"1:    lwarx   %0,0,%3         # atomic_sub\n\
-       subf    %0,%2,%0\n"
-       PPC405_ERR77(0,%3)
-"      stwcx.  %0,0,%3 \n\
-       bne-    1b"
-       : "=&r" (t), "+m" (v->counter)
-       : "r" (a), "r" (&v->counter)
-       : "cc");
-}
-
-static __inline__ int atomic_sub_return(int a, atomic_t *v)
-{
-       int t;
-
-       __asm__ __volatile__(
-       PPC_ATOMIC_ENTRY_BARRIER
-"1:    lwarx   %0,0,%2         # atomic_sub_return\n\
-       subf    %0,%1,%0\n"
-       PPC405_ERR77(0,%2)
-"      stwcx.  %0,0,%2 \n\
-       bne-    1b"
-       PPC_ATOMIC_EXIT_BARRIER
-       : "=&r" (t)
-       : "r" (a), "r" (&v->counter)
-       : "cc", "memory");
-
-       return t;
-}
-
 static __inline__ void atomic_inc(atomic_t *v)
 {
        int t;
@@ -289,71 +266,50 @@ static __inline__ void atomic64_set(atomic64_t *v, long i)
        __asm__ __volatile__("std%U0%X0 %1,%0" : "=m"(v->counter) : "r"(i));
 }
 
-static __inline__ void atomic64_add(long a, atomic64_t *v)
-{
-       long t;
-
-       __asm__ __volatile__(
-"1:    ldarx   %0,0,%3         # atomic64_add\n\
-       add     %0,%2,%0\n\
-       stdcx.  %0,0,%3 \n\
-       bne-    1b"
-       : "=&r" (t), "+m" (v->counter)
-       : "r" (a), "r" (&v->counter)
-       : "cc");
+#define ATOMIC64_OP(op, asm_op)                                                \
+static __inline__ void atomic64_##op(long a, atomic64_t *v)            \
+{                                                                      \
+       long t;                                                         \
+                                                                       \
+       __asm__ __volatile__(                                           \
+"1:    ldarx   %0,0,%3         # atomic64_" #op "\n"                   \
+       #asm_op " %0,%2,%0\n"                                           \
+"      stdcx.  %0,0,%3 \n"                                             \
+"      bne-    1b\n"                                                   \
+       : "=&r" (t), "+m" (v->counter)                                  \
+       : "r" (a), "r" (&v->counter)                                    \
+       : "cc");                                                        \
 }
 
-static __inline__ long atomic64_add_return(long a, atomic64_t *v)
-{
-       long t;
-
-       __asm__ __volatile__(
-       PPC_ATOMIC_ENTRY_BARRIER
-"1:    ldarx   %0,0,%2         # atomic64_add_return\n\
-       add     %0,%1,%0\n\
-       stdcx.  %0,0,%2 \n\
-       bne-    1b"
-       PPC_ATOMIC_EXIT_BARRIER
-       : "=&r" (t)
-       : "r" (a), "r" (&v->counter)
-       : "cc", "memory");
-
-       return t;
+#define ATOMIC64_OP_RETURN(op, asm_op)                                 \
+static __inline__ long atomic64_##op##_return(long a, atomic64_t *v)   \
+{                                                                      \
+       long t;                                                         \
+                                                                       \
+       __asm__ __volatile__(                                           \
+       PPC_ATOMIC_ENTRY_BARRIER                                        \
+"1:    ldarx   %0,0,%2         # atomic64_" #op "_return\n"            \
+       #asm_op " %0,%1,%0\n"                                           \
+"      stdcx.  %0,0,%2 \n"                                             \
+"      bne-    1b\n"                                                   \
+       PPC_ATOMIC_EXIT_BARRIER                                         \
+       : "=&r" (t)                                                     \
+       : "r" (a), "r" (&v->counter)                                    \
+       : "cc", "memory");                                              \
+                                                                       \
+       return t;                                                       \
 }
 
-#define atomic64_add_negative(a, v)    (atomic64_add_return((a), (v)) < 0)
-
-static __inline__ void atomic64_sub(long a, atomic64_t *v)
-{
-       long t;
-
-       __asm__ __volatile__(
-"1:    ldarx   %0,0,%3         # atomic64_sub\n\
-       subf    %0,%2,%0\n\
-       stdcx.  %0,0,%3 \n\
-       bne-    1b"
-       : "=&r" (t), "+m" (v->counter)
-       : "r" (a), "r" (&v->counter)
-       : "cc");
-}
+#define ATOMIC64_OPS(op, asm_op) ATOMIC64_OP(op, asm_op) ATOMIC64_OP_RETURN(op, asm_op)
 
-static __inline__ long atomic64_sub_return(long a, atomic64_t *v)
-{
-       long t;
+ATOMIC64_OPS(add, add)
+ATOMIC64_OPS(sub, subf)
 
-       __asm__ __volatile__(
-       PPC_ATOMIC_ENTRY_BARRIER
-"1:    ldarx   %0,0,%2         # atomic64_sub_return\n\
-       subf    %0,%1,%0\n\
-       stdcx.  %0,0,%2 \n\
-       bne-    1b"
-       PPC_ATOMIC_EXIT_BARRIER
-       : "=&r" (t)
-       : "r" (a), "r" (&v->counter)
-       : "cc", "memory");
+#undef ATOMIC64_OPS
+#undef ATOMIC64_OP_RETURN
+#undef ATOMIC64_OP
 
-       return t;
-}
+#define atomic64_add_negative(a, v)    (atomic64_add_return((a), (v)) < 0)
 
 static __inline__ void atomic64_inc(atomic64_t *v)
 {
index 3eb53d741070d69fe3505b694d04b8a40303a71e..3a39283333c3cdbba5139f1c97f83d7f36815ed9 100644 (file)
@@ -133,7 +133,6 @@ extern int do_page_fault(struct pt_regs *, unsigned long, unsigned long);
 extern void bad_page_fault(struct pt_regs *, unsigned long, int);
 extern void _exception(int, struct pt_regs *, int, unsigned long);
 extern void die(const char *, struct pt_regs *, long);
-extern void print_backtrace(unsigned long *);
 
 #endif /* !__ASSEMBLY__ */
 
diff --git a/arch/powerpc/include/asm/copro.h b/arch/powerpc/include/asm/copro.h
new file mode 100644 (file)
index 0000000..ce216df
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2014 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.
+ */
+
+#ifndef _ASM_POWERPC_COPRO_H
+#define _ASM_POWERPC_COPRO_H
+
+struct copro_slb
+{
+       u64 esid, vsid;
+};
+
+int copro_handle_mm_fault(struct mm_struct *mm, unsigned long ea,
+                         unsigned long dsisr, unsigned *flt);
+
+int copro_calculate_slb(struct mm_struct *mm, u64 ea, struct copro_slb *slb);
+
+
+#ifdef CONFIG_PPC_COPRO_BASE
+void copro_flush_all_slbs(struct mm_struct *mm);
+#else
+static inline void copro_flush_all_slbs(struct mm_struct *mm) {}
+#endif
+#endif /* _ASM_POWERPC_COPRO_H */
index 607559ab271ff98b45de1f11964416bebaf32841..6c840ceab8201cc191f4699d15561c62b2e0c9c2 100644 (file)
@@ -32,6 +32,8 @@ static inline void setup_cputime_one_jiffy(void) { }
 typedef u64 __nocast cputime_t;
 typedef u64 __nocast cputime64_t;
 
+#define cmpxchg_cputime(ptr, old, new) cmpxchg(ptr, old, new)
+
 #ifdef __KERNEL__
 
 /*
index 150866b2a3fe07337f38905511a73cd726e07689..894d538f356783336f6addf6468ab941cafd0d02 100644 (file)
@@ -135,6 +135,7 @@ static inline int dma_supported(struct device *dev, u64 mask)
 
 extern int dma_set_mask(struct device *dev, u64 dma_mask);
 extern int __dma_set_mask(struct device *dev, u64 dma_mask);
+extern u64 __dma_get_required_mask(struct device *dev);
 
 #define dma_alloc_coherent(d,s,h,f)    dma_alloc_attrs(d,s,h,f,NULL)
 
index 9983c3d26bcaa1f4e5572f434deaeb05868c4758..3b260efbfbf9833a5d23263b64f50c833564b74a 100644 (file)
@@ -146,6 +146,11 @@ static inline struct pci_dev *eeh_dev_to_pci_dev(struct eeh_dev *edev)
        return edev ? edev->pdev : NULL;
 }
 
+static inline struct eeh_pe *eeh_dev_to_pe(struct eeh_dev* edev)
+{
+       return edev ? edev->pe : NULL;
+}
+
 /* Return values from eeh_ops::next_error */
 enum {
        EEH_NEXT_ERR_NONE = 0,
@@ -167,6 +172,7 @@ enum {
 #define EEH_OPT_ENABLE         1       /* EEH enable   */
 #define EEH_OPT_THAW_MMIO      2       /* MMIO enable  */
 #define EEH_OPT_THAW_DMA       3       /* DMA enable   */
+#define EEH_OPT_FREEZE_PE      4       /* Freeze PE    */
 #define EEH_STATE_UNAVAILABLE  (1 << 0)        /* State unavailable    */
 #define EEH_STATE_NOT_SUPPORT  (1 << 1)        /* EEH not supported    */
 #define EEH_STATE_RESET_ACTIVE (1 << 2)        /* Active reset         */
@@ -198,6 +204,8 @@ struct eeh_ops {
        int (*wait_state)(struct eeh_pe *pe, int max_wait);
        int (*get_log)(struct eeh_pe *pe, int severity, char *drv_log, unsigned long len);
        int (*configure_bridge)(struct eeh_pe *pe);
+       int (*err_inject)(struct eeh_pe *pe, int type, int func,
+                         unsigned long addr, unsigned long mask);
        int (*read_config)(struct device_node *dn, int where, int size, u32 *val);
        int (*write_config)(struct device_node *dn, int where, int size, u32 val);
        int (*next_error)(struct eeh_pe **pe);
@@ -269,8 +277,7 @@ void eeh_dev_phb_init_dynamic(struct pci_controller *phb);
 int eeh_init(void);
 int __init eeh_ops_register(struct eeh_ops *ops);
 int __exit eeh_ops_unregister(const char *name);
-unsigned long eeh_check_failure(const volatile void __iomem *token,
-                               unsigned long val);
+int eeh_check_failure(const volatile void __iomem *token);
 int eeh_dev_check_failure(struct eeh_dev *edev);
 void eeh_addr_cache_build(void);
 void eeh_add_device_early(struct device_node *);
@@ -279,6 +286,8 @@ void eeh_add_device_late(struct pci_dev *);
 void eeh_add_device_tree_late(struct pci_bus *);
 void eeh_add_sysfs_files(struct pci_bus *);
 void eeh_remove_device(struct pci_dev *);
+int eeh_unfreeze_pe(struct eeh_pe *pe, bool sw_state);
+int eeh_pe_reset_and_recover(struct eeh_pe *pe);
 int eeh_dev_open(struct pci_dev *pdev);
 void eeh_dev_release(struct pci_dev *pdev);
 struct eeh_pe *eeh_iommu_group_to_pe(struct iommu_group *group);
@@ -321,9 +330,9 @@ static inline void *eeh_dev_init(struct device_node *dn, void *data)
 
 static inline void eeh_dev_phb_init_dynamic(struct pci_controller *phb) { }
 
-static inline unsigned long eeh_check_failure(const volatile void __iomem *token, unsigned long val)
+static inline int eeh_check_failure(const volatile void __iomem *token)
 {
-       return val;
+       return 0;
 }
 
 #define eeh_dev_check_failure(x) (0)
@@ -354,7 +363,7 @@ static inline u8 eeh_readb(const volatile void __iomem *addr)
 {
        u8 val = in_8(addr);
        if (EEH_POSSIBLE_ERROR(val, u8))
-               return eeh_check_failure(addr, val);
+               eeh_check_failure(addr);
        return val;
 }
 
@@ -362,7 +371,7 @@ static inline u16 eeh_readw(const volatile void __iomem *addr)
 {
        u16 val = in_le16(addr);
        if (EEH_POSSIBLE_ERROR(val, u16))
-               return eeh_check_failure(addr, val);
+               eeh_check_failure(addr);
        return val;
 }
 
@@ -370,7 +379,7 @@ static inline u32 eeh_readl(const volatile void __iomem *addr)
 {
        u32 val = in_le32(addr);
        if (EEH_POSSIBLE_ERROR(val, u32))
-               return eeh_check_failure(addr, val);
+               eeh_check_failure(addr);
        return val;
 }
 
@@ -378,7 +387,7 @@ static inline u64 eeh_readq(const volatile void __iomem *addr)
 {
        u64 val = in_le64(addr);
        if (EEH_POSSIBLE_ERROR(val, u64))
-               return eeh_check_failure(addr, val);
+               eeh_check_failure(addr);
        return val;
 }
 
@@ -386,7 +395,7 @@ static inline u16 eeh_readw_be(const volatile void __iomem *addr)
 {
        u16 val = in_be16(addr);
        if (EEH_POSSIBLE_ERROR(val, u16))
-               return eeh_check_failure(addr, val);
+               eeh_check_failure(addr);
        return val;
 }
 
@@ -394,7 +403,7 @@ static inline u32 eeh_readl_be(const volatile void __iomem *addr)
 {
        u32 val = in_be32(addr);
        if (EEH_POSSIBLE_ERROR(val, u32))
-               return eeh_check_failure(addr, val);
+               eeh_check_failure(addr);
        return val;
 }
 
@@ -402,7 +411,7 @@ static inline u64 eeh_readq_be(const volatile void __iomem *addr)
 {
        u64 val = in_be64(addr);
        if (EEH_POSSIBLE_ERROR(val, u64))
-               return eeh_check_failure(addr, val);
+               eeh_check_failure(addr);
        return val;
 }
 
@@ -416,7 +425,7 @@ static inline void eeh_memcpy_fromio(void *dest, const
         * were copied. Check all four bytes.
         */
        if (n >= 4 && EEH_POSSIBLE_ERROR(*((u32 *)(dest + n - 4)), u32))
-               eeh_check_failure(src, *((u32 *)(dest + n - 4)));
+               eeh_check_failure(src);
 }
 
 /* in-string eeh macros */
@@ -425,7 +434,7 @@ static inline void eeh_readsb(const volatile void __iomem *addr, void * buf,
 {
        _insb(addr, buf, ns);
        if (EEH_POSSIBLE_ERROR((*(((u8*)buf)+ns-1)), u8))
-               eeh_check_failure(addr, *(u8*)buf);
+               eeh_check_failure(addr);
 }
 
 static inline void eeh_readsw(const volatile void __iomem *addr, void * buf,
@@ -433,7 +442,7 @@ static inline void eeh_readsw(const volatile void __iomem *addr, void * buf,
 {
        _insw(addr, buf, ns);
        if (EEH_POSSIBLE_ERROR((*(((u16*)buf)+ns-1)), u16))
-               eeh_check_failure(addr, *(u16*)buf);
+               eeh_check_failure(addr);
 }
 
 static inline void eeh_readsl(const volatile void __iomem *addr, void * buf,
@@ -441,7 +450,7 @@ static inline void eeh_readsl(const volatile void __iomem *addr, void * buf,
 {
        _insl(addr, buf, nl);
        if (EEH_POSSIBLE_ERROR((*(((u32*)buf)+nl-1)), u32))
-               eeh_check_failure(addr, *(u32*)buf);
+               eeh_check_failure(addr);
 }
 
 #endif /* CONFIG_PPC64 */
index 5b0c98bd46abb346c2a6966265ff767651f3de4f..1cb39c96d1558fcded9b86d7aa5e3a5512f929cc 100644 (file)
@@ -95,7 +95,6 @@ extern volatile struct Hydra __iomem *Hydra;
 #define HYDRA_INT_SPARE                19
 
 extern int hydra_init(void);
-extern void macio_adb_init(void);
 
 #endif /* __KERNEL__ */
 
index 41f13cec8a8fcd01bbd2e02f3cfc50083b3addba..e8e3a0a04eb079b179d3a67c47641a0ad95b07da 100644 (file)
@@ -31,11 +31,6 @@ extern atomic_t ppc_n_lost_interrupts;
 
 extern irq_hw_number_t virq_to_hw(unsigned int virq);
 
-/**
- * irq_early_init - Init irq remapping subsystem
- */
-extern void irq_early_init(void);
-
 static __inline__ int irq_canonicalize(int irq)
 {
        return irq;
index 16d7e33d35e970c742585f9c19fb0fc62b61f0ba..19c36cba37c4acac5e63e7c4d8a093b4dbe65781 100644 (file)
@@ -81,7 +81,6 @@ extern void default_machine_crash_shutdown(struct pt_regs *regs);
 extern int crash_shutdown_register(crash_shutdown_t handler);
 extern int crash_shutdown_unregister(crash_shutdown_t handler);
 
-extern void machine_kexec_simple(struct kimage *image);
 extern void crash_kexec_secondary(struct pt_regs *regs);
 extern int overlaps_crashkernel(unsigned long start, unsigned long size);
 extern void reserve_crashkernel(void);
index 3af721633618316024854d1cc281489a9062ceb1..307347f8ddbdc808f49ca4cbc4825a5fbe8c5c99 100644 (file)
@@ -328,8 +328,6 @@ extern struct machdep_calls *machine_id;
 
 extern void probe_machine(void);
 
-extern char cmd_line[COMMAND_LINE_SIZE];
-
 #ifdef CONFIG_PPC_PMAC
 /*
  * Power macintoshes have either a CUDA, PMU or SMU controlling
index d76514487d6f8f19c5409941dafa970b21426118..aeebc94b2bced66d4d5762077629362ece591103 100644 (file)
@@ -190,6 +190,13 @@ static inline unsigned int mmu_psize_to_shift(unsigned int mmu_psize)
 
 #ifndef __ASSEMBLY__
 
+static inline int slb_vsid_shift(int ssize)
+{
+       if (ssize == MMU_SEGSIZE_256M)
+               return SLB_VSID_SHIFT;
+       return SLB_VSID_SHIFT_1T;
+}
+
 static inline int segment_shift(int ssize)
 {
        if (ssize == MMU_SEGSIZE_256M)
@@ -317,6 +324,7 @@ extern int __hash_page_64K(unsigned long ea, unsigned long access,
                           unsigned int local, int ssize);
 struct mm_struct;
 unsigned int hash_page_do_lazy_icache(unsigned int pp, pte_t pte, int trap);
+extern int hash_page_mm(struct mm_struct *mm, unsigned long ea, unsigned long access, unsigned long trap);
 extern int hash_page(unsigned long ea, unsigned long access, unsigned long trap);
 int __hash_page_huge(unsigned long ea, unsigned long access, unsigned long vsid,
                     pte_t *ptep, unsigned long trap, int local, int ssize,
@@ -342,6 +350,8 @@ extern void hash_failure_debug(unsigned long ea, unsigned long access,
 extern int htab_bolt_mapping(unsigned long vstart, unsigned long vend,
                             unsigned long pstart, unsigned long prot,
                             int psize, int ssize);
+int htab_remove_mapping(unsigned long vstart, unsigned long vend,
+                       int psize, int ssize);
 extern void add_gpage(u64 addr, u64 page_size, unsigned long number_of_pages);
 extern void demote_segment_4k(struct mm_struct *mm, unsigned long addr);
 
index 86055e598269ebc9c4ba2c52ea3b6f59a27599e2..9124b0ede1fc7f531a97d369169706024741ce17 100644 (file)
@@ -135,6 +135,7 @@ struct opal_sg_list {
 #define OPAL_FLASH_MANAGE                      77
 #define OPAL_FLASH_UPDATE                      78
 #define OPAL_RESYNC_TIMEBASE                   79
+#define OPAL_CHECK_TOKEN                       80
 #define OPAL_DUMP_INIT                         81
 #define OPAL_DUMP_INFO                         82
 #define OPAL_DUMP_READ                         83
@@ -146,7 +147,9 @@ struct opal_sg_list {
 #define OPAL_GET_PARAM                         89
 #define OPAL_SET_PARAM                         90
 #define OPAL_DUMP_RESEND                       91
+#define OPAL_PCI_SET_PHB_CXL_MODE              93
 #define OPAL_DUMP_INFO2                                94
+#define OPAL_PCI_ERR_INJECT                    96
 #define OPAL_PCI_EEH_FREEZE_SET                        97
 #define OPAL_HANDLE_HMI                                98
 #define OPAL_REGISTER_DUMP_REGION              101
@@ -199,6 +202,35 @@ enum OpalPciErrorSeverity {
        OPAL_EEH_SEV_INF        = 5
 };
 
+enum OpalErrinjectType {
+       OPAL_ERR_INJECT_TYPE_IOA_BUS_ERR        = 0,
+       OPAL_ERR_INJECT_TYPE_IOA_BUS_ERR64      = 1,
+};
+
+enum OpalErrinjectFunc {
+       /* IOA bus specific errors */
+       OPAL_ERR_INJECT_FUNC_IOA_LD_MEM_ADDR    = 0,
+       OPAL_ERR_INJECT_FUNC_IOA_LD_MEM_DATA    = 1,
+       OPAL_ERR_INJECT_FUNC_IOA_LD_IO_ADDR     = 2,
+       OPAL_ERR_INJECT_FUNC_IOA_LD_IO_DATA     = 3,
+       OPAL_ERR_INJECT_FUNC_IOA_LD_CFG_ADDR    = 4,
+       OPAL_ERR_INJECT_FUNC_IOA_LD_CFG_DATA    = 5,
+       OPAL_ERR_INJECT_FUNC_IOA_ST_MEM_ADDR    = 6,
+       OPAL_ERR_INJECT_FUNC_IOA_ST_MEM_DATA    = 7,
+       OPAL_ERR_INJECT_FUNC_IOA_ST_IO_ADDR     = 8,
+       OPAL_ERR_INJECT_FUNC_IOA_ST_IO_DATA     = 9,
+       OPAL_ERR_INJECT_FUNC_IOA_ST_CFG_ADDR    = 10,
+       OPAL_ERR_INJECT_FUNC_IOA_ST_CFG_DATA    = 11,
+       OPAL_ERR_INJECT_FUNC_IOA_DMA_RD_ADDR    = 12,
+       OPAL_ERR_INJECT_FUNC_IOA_DMA_RD_DATA    = 13,
+       OPAL_ERR_INJECT_FUNC_IOA_DMA_RD_MASTER  = 14,
+       OPAL_ERR_INJECT_FUNC_IOA_DMA_RD_TARGET  = 15,
+       OPAL_ERR_INJECT_FUNC_IOA_DMA_WR_ADDR    = 16,
+       OPAL_ERR_INJECT_FUNC_IOA_DMA_WR_DATA    = 17,
+       OPAL_ERR_INJECT_FUNC_IOA_DMA_WR_MASTER  = 18,
+       OPAL_ERR_INJECT_FUNC_IOA_DMA_WR_TARGET  = 19,
+};
+
 enum OpalShpcAction {
        OPAL_SHPC_GET_LINK_STATE = 0,
        OPAL_SHPC_GET_SLOT_STATE = 1
@@ -356,9 +388,12 @@ enum OpalM64EnableAction {
 };
 
 enum OpalPciResetScope {
-       OPAL_PHB_COMPLETE = 1, OPAL_PCI_LINK = 2, OPAL_PHB_ERROR = 3,
-       OPAL_PCI_HOT_RESET = 4, OPAL_PCI_FUNDAMENTAL_RESET = 5,
-       OPAL_PCI_IODA_TABLE_RESET = 6,
+       OPAL_RESET_PHB_COMPLETE         = 1,
+       OPAL_RESET_PCI_LINK             = 2,
+       OPAL_RESET_PHB_ERROR            = 3,
+       OPAL_RESET_PCI_HOT              = 4,
+       OPAL_RESET_PCI_FUNDAMENTAL      = 5,
+       OPAL_RESET_PCI_IODA_TABLE       = 6
 };
 
 enum OpalPciReinitScope {
@@ -819,6 +854,8 @@ int64_t opal_pci_eeh_freeze_clear(uint64_t phb_id, uint64_t pe_number,
                                  uint64_t eeh_action_token);
 int64_t opal_pci_eeh_freeze_set(uint64_t phb_id, uint64_t pe_number,
                                uint64_t eeh_action_token);
+int64_t opal_pci_err_inject(uint64_t phb_id, uint32_t pe_no, uint32_t type,
+                           uint32_t func, uint64_t addr, uint64_t mask);
 int64_t opal_pci_shpc(uint64_t phb_id, uint64_t shpc_action, uint8_t *state);
 
 
@@ -887,6 +924,7 @@ int64_t opal_pci_next_error(uint64_t phb_id, __be64 *first_frozen_pe,
                            __be16 *pci_error_type, __be16 *severity);
 int64_t opal_pci_poll(uint64_t phb_id);
 int64_t opal_return_cpu(void);
+int64_t opal_check_token(uint64_t token);
 int64_t opal_reinit_cpus(uint64_t flags);
 
 int64_t opal_xscom_read(uint32_t gcid, uint64_t pcb_addr, __be64 *val);
@@ -924,6 +962,7 @@ int64_t opal_sensor_read(uint32_t sensor_hndl, int token, __be32 *sensor_data);
 int64_t opal_handle_hmi(void);
 int64_t opal_register_dump_region(uint32_t id, uint64_t start, uint64_t end);
 int64_t opal_unregister_dump_region(uint32_t id);
+int64_t opal_pci_set_phb_cxl_mode(uint64_t phb_id, uint64_t mode, uint64_t pe_number);
 
 /* Internal functions */
 extern int early_init_dt_scan_opal(unsigned long node, const char *uname,
index 88693cef4f3d60545f17881000451f71319477e6..d908a46d05c0b1be8bbb5b35a90425465fd5d3aa 100644 (file)
 
 typedef unsigned long pte_basic_t;
 
-static __inline__ void clear_page(void *addr)
+static inline void clear_page(void *addr)
 {
-       unsigned long lines, line_size;
-
-       line_size = ppc64_caches.dline_size;
-       lines = ppc64_caches.dlines_per_page;
-
-       __asm__ __volatile__(
+       unsigned long iterations;
+       unsigned long onex, twox, fourx, eightx;
+
+       iterations = ppc64_caches.dlines_per_page / 8;
+
+       /*
+        * Some verisions of gcc use multiply instructions to
+        * calculate the offsets so lets give it a hand to
+        * do better.
+        */
+       onex = ppc64_caches.dline_size;
+       twox = onex << 1;
+       fourx = onex << 2;
+       eightx = onex << 3;
+
+       asm volatile(
        "mtctr  %1      # clear_page\n\
-1:      dcbz   0,%0\n\
-       add     %0,%0,%3\n\
+       .balign 16\n\
+1:     dcbz    0,%0\n\
+       dcbz    %3,%0\n\
+       dcbz    %4,%0\n\
+       dcbz    %5,%0\n\
+       dcbz    %6,%0\n\
+       dcbz    %7,%0\n\
+       dcbz    %8,%0\n\
+       dcbz    %9,%0\n\
+       add     %0,%0,%10\n\
        bdnz+   1b"
-        : "=r" (addr)
-        : "r" (lines), "0" (addr), "r" (line_size)
+       : "=&r" (addr)
+       : "r" (iterations), "0" (addr), "b" (onex), "b" (twox),
+               "b" (twox+onex), "b" (fourx), "b" (fourx+onex),
+               "b" (twox+fourx), "b" (eightx-onex), "r" (eightx)
        : "ctr", "memory");
 }
 
@@ -104,7 +124,6 @@ extern unsigned long slice_get_unmapped_area(unsigned long addr,
 extern unsigned int get_slice_psize(struct mm_struct *mm,
                                    unsigned long addr);
 
-extern void slice_init_context(struct mm_struct *mm, unsigned int psize);
 extern void slice_set_user_psize(struct mm_struct *mm, unsigned int psize);
 extern void slice_set_range_psize(struct mm_struct *mm, unsigned long start,
                                  unsigned long len, unsigned int psize);
index 47edde8c3556221b7371b225f32e1065b4b2fdb8..945e47adf7db633ae13fc5003e948f19e38fbb08 100644 (file)
@@ -8,8 +8,6 @@
 #include <linux/threads.h>
 #include <asm/io.h>                    /* For sub-arch specific PPC_PIN_SIZE */
 
-extern unsigned long va_to_phys(unsigned long address);
-extern pte_t *va_to_pte(unsigned long address);
 extern unsigned long ioremap_bot;
 
 #ifdef CONFIG_44x
@@ -50,10 +48,10 @@ extern int icache_44x_need_flush;
 #define FIRST_USER_ADDRESS     0
 
 #define pte_ERROR(e) \
-       printk("%s:%d: bad pte %llx.\n", __FILE__, __LINE__, \
+       pr_err("%s:%d: bad pte %llx.\n", __FILE__, __LINE__, \
                (unsigned long long)pte_val(e))
 #define pgd_ERROR(e) \
-       printk("%s:%d: bad pgd %08lx.\n", __FILE__, __LINE__, pgd_val(e))
+       pr_err("%s:%d: bad pgd %08lx.\n", __FILE__, __LINE__, pgd_val(e))
 
 /*
  * This is the bottom of the PKMAP area with HIGHMEM or an arbitrary
index 12798c9d4b4ba5401c77c41bc605e722a11b6266..7b935683f2684687813f470765091bcec064b219 100644 (file)
@@ -64,7 +64,7 @@
     (((addr) >> PUD_SHIFT) & (PTRS_PER_PUD - 1)))
 
 #define pud_ERROR(e) \
-       printk("%s:%d: bad pud %08lx.\n", __FILE__, __LINE__, pud_val(e))
+       pr_err("%s:%d: bad pud %08lx.\n", __FILE__, __LINE__, pud_val(e))
 
 /*
  * On all 4K setups, remap_4k_pfn() equates to remap_pfn_range() */
index 7b3d54fae46f92a80dcaddf301a2ea2687beafba..ae153c40ab7c7e9a552731e3b5673c1cd0efdd75 100644 (file)
@@ -328,11 +328,11 @@ static inline void __ptep_set_access_flags(pte_t *ptep, pte_t entry)
 #define pte_same(A,B)  (((pte_val(A) ^ pte_val(B)) & ~_PAGE_HPTEFLAGS) == 0)
 
 #define pte_ERROR(e) \
-       printk("%s:%d: bad pte %08lx.\n", __FILE__, __LINE__, pte_val(e))
+       pr_err("%s:%d: bad pte %08lx.\n", __FILE__, __LINE__, pte_val(e))
 #define pmd_ERROR(e) \
-       printk("%s:%d: bad pmd %08lx.\n", __FILE__, __LINE__, pmd_val(e))
+       pr_err("%s:%d: bad pmd %08lx.\n", __FILE__, __LINE__, pmd_val(e))
 #define pgd_ERROR(e) \
-       printk("%s:%d: bad pgd %08lx.\n", __FILE__, __LINE__, pgd_val(e))
+       pr_err("%s:%d: bad pgd %08lx.\n", __FILE__, __LINE__, pgd_val(e))
 
 /* Encode and de-code a swap entry */
 #define __swp_type(entry)      (((entry).val >> 1) & 0x3f)
index f60d4ea8b50c8f3bd32f3886a7fb24b9c99f14df..316f9a5da173f1653fe03a4a8cbc43749f85516a 100644 (file)
@@ -4,6 +4,7 @@
 
 #ifndef __ASSEMBLY__
 #include <linux/mmdebug.h>
+#include <linux/mmzone.h>
 #include <asm/processor.h>             /* For TASK_SIZE */
 #include <asm/mmu.h>
 #include <asm/page.h>
@@ -248,6 +249,8 @@ extern unsigned long empty_zero_page[];
 
 extern pgd_t swapper_pg_dir[];
 
+void limit_zone_pfn(enum zone_type zone, unsigned long max_pfn);
+int dma_pfn_limit_to_zone(u64 pfn_limit);
 extern void paging_init(void);
 
 /*
index 12c32c5f533d924428714301f7482493df00e3c8..67859edbf8fd39aba27c8f8b7503533d6d9a3271 100644 (file)
@@ -273,7 +273,7 @@ static inline long plpar_set_mode(unsigned long mflags, unsigned long resource,
 static inline long enable_reloc_on_exceptions(void)
 {
        /* mflags = 3: Exceptions at 0xC000000000004000 */
-       return plpar_set_mode(3, 3, 0, 0);
+       return plpar_set_mode(3, H_SET_MODE_RESOURCE_ADDR_TRANS_MODE, 0, 0);
 }
 
 /*
@@ -284,7 +284,7 @@ static inline long enable_reloc_on_exceptions(void)
  * returns H_SUCCESS.
  */
 static inline long disable_reloc_on_exceptions(void) {
-       return plpar_set_mode(0, 3, 0, 0);
+       return plpar_set_mode(0, H_SET_MODE_RESOURCE_ADDR_TRANS_MODE, 0, 0);
 }
 
 /*
@@ -297,7 +297,7 @@ static inline long disable_reloc_on_exceptions(void) {
 static inline long enable_big_endian_exceptions(void)
 {
        /* mflags = 0: big endian exceptions */
-       return plpar_set_mode(0, 4, 0, 0);
+       return plpar_set_mode(0, H_SET_MODE_RESOURCE_LE, 0, 0);
 }
 
 /*
@@ -310,17 +310,17 @@ static inline long enable_big_endian_exceptions(void)
 static inline long enable_little_endian_exceptions(void)
 {
        /* mflags = 1: little endian exceptions */
-       return plpar_set_mode(1, 4, 0, 0);
+       return plpar_set_mode(1, H_SET_MODE_RESOURCE_LE, 0, 0);
 }
 
 static inline long plapr_set_ciabr(unsigned long ciabr)
 {
-       return plpar_set_mode(0, 1, ciabr, 0);
+       return plpar_set_mode(0, H_SET_MODE_RESOURCE_SET_CIABR, ciabr, 0);
 }
 
 static inline long plapr_set_watchpoint0(unsigned long dawr0, unsigned long dawrx0)
 {
-       return plpar_set_mode(0, 2, dawr0, dawrx0);
+       return plpar_set_mode(0, H_SET_MODE_RESOURCE_SET_DAWR, dawr0, dawrx0);
 }
 
 #endif /* _ASM_POWERPC_PLPAR_WRAPPERS_H */
diff --git a/arch/powerpc/include/asm/pnv-pci.h b/arch/powerpc/include/asm/pnv-pci.h
new file mode 100644 (file)
index 0000000..f09a22f
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2014 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.
+ */
+
+#ifndef _ASM_PNV_PCI_H
+#define _ASM_PNV_PCI_H
+
+#include <linux/pci.h>
+#include <misc/cxl.h>
+
+int pnv_phb_to_cxl(struct pci_dev *dev);
+int pnv_cxl_ioda_msi_setup(struct pci_dev *dev, unsigned int hwirq,
+                          unsigned int virq);
+int pnv_cxl_alloc_hwirqs(struct pci_dev *dev, int num);
+void pnv_cxl_release_hwirqs(struct pci_dev *dev, int hwirq, int num);
+int pnv_cxl_get_irq_count(struct pci_dev *dev);
+struct device_node *pnv_pci_to_phb_node(struct pci_dev *dev);
+
+#ifdef CONFIG_CXL_BASE
+int pnv_cxl_alloc_hwirq_ranges(struct cxl_irq_ranges *irqs,
+                              struct pci_dev *dev, int num);
+void pnv_cxl_release_hwirq_ranges(struct cxl_irq_ranges *irqs,
+                                 struct pci_dev *dev);
+#endif
+
+#endif
index 74b79f07f0412bbebd160cc4b14ab8d08d583278..7f436ba1b56f5d2246fed43825c41a2581fb7662 100644 (file)
@@ -76,8 +76,6 @@ void of_parse_dma_window(struct device_node *dn, const __be32 *dma_window,
                         unsigned long *busno, unsigned long *phys,
                         unsigned long *size);
 
-extern void kdump_move_device_tree(void);
-
 extern void of_instantiate_rtc(void);
 
 extern int of_get_ibm_chip_id(struct device_node *np);
index 0c0505956a296bd83a185042a04e4e096880a04c..fe3f9488f321e5ec20448ac92c6e6a3e16d4fc77 100644 (file)
  * 32-bit 8xx:
  *     - SPRG0 scratch for exception vectors
  *     - SPRG1 scratch for exception vectors
- *     - SPRG2 apparently unused but initialized
+ *     - SPRG2 scratch for exception vectors
  *
  */
 #ifdef CONFIG_PPC64
 #ifdef CONFIG_8xx
 #define SPRN_SPRG_SCRATCH0     SPRN_SPRG0
 #define SPRN_SPRG_SCRATCH1     SPRN_SPRG1
+#define SPRN_SPRG_SCRATCH2     SPRN_SPRG2
 #endif
 
 
index b1d2deceeedbc1f24030a302e2f190ff8929084b..ec800f28fec5249e2478f718260d05ca87176c12 100644 (file)
@@ -13,7 +13,6 @@
 #ifndef ASM_PPC_RIO_H
 #define ASM_PPC_RIO_H
 
-extern void platform_rio_init(void);
 #ifdef CONFIG_FSL_RIO
 extern int fsl_rio_mcheck_exception(struct pt_regs *);
 #else
index 37b7ca39ec9f1b5ec2d3e574a8806de34ccff555..a6e6e2bf9d15a5be729d1190c511c1b8eb503393 100644 (file)
@@ -27,6 +27,8 @@
 #include <linux/workqueue.h>
 #include <linux/device.h>
 #include <linux/mutex.h>
+#include <asm/reg.h>
+#include <asm/copro.h>
 
 #define LS_SIZE (256 * 1024)
 #define LS_ADDR_MASK (LS_SIZE - 1)
@@ -277,9 +279,6 @@ void spu_remove_dev_attr(struct device_attribute *attr);
 int spu_add_dev_attr_group(struct attribute_group *attrs);
 void spu_remove_dev_attr_group(struct attribute_group *attrs);
 
-int spu_handle_mm_fault(struct mm_struct *mm, unsigned long ea,
-               unsigned long dsisr, unsigned *flt);
-
 /*
  * Notifier blocks:
  *
index f593b0f9b6278ee5625173931bb19eb72fb3d894..d3a42cc45a8286023b47f98403229e02f8e1f238 100644 (file)
@@ -25,3 +25,65 @@ struct pt_regs;
 
 /* Emulate instructions that cause a transfer of control. */
 extern int emulate_step(struct pt_regs *regs, unsigned int instr);
+
+enum instruction_type {
+       COMPUTE,                /* arith/logical/CR op, etc. */
+       LOAD,
+       LOAD_MULTI,
+       LOAD_FP,
+       LOAD_VMX,
+       LOAD_VSX,
+       STORE,
+       STORE_MULTI,
+       STORE_FP,
+       STORE_VMX,
+       STORE_VSX,
+       LARX,
+       STCX,
+       BRANCH,
+       MFSPR,
+       MTSPR,
+       CACHEOP,
+       BARRIER,
+       SYSCALL,
+       MFMSR,
+       MTMSR,
+       RFI,
+       INTERRUPT,
+       UNKNOWN
+};
+
+#define INSTR_TYPE_MASK        0x1f
+
+/* Load/store flags, ORed in with type */
+#define SIGNEXT                0x20
+#define UPDATE         0x40    /* matches bit in opcode 31 instructions */
+#define BYTEREV                0x80
+
+/* Cacheop values, ORed in with type */
+#define CACHEOP_MASK   0x700
+#define DCBST          0
+#define DCBF           0x100
+#define DCBTST         0x200
+#define DCBT           0x300
+#define ICBI           0x400
+
+/* Size field in type word */
+#define SIZE(n)                ((n) << 8)
+#define GETSIZE(w)     ((w) >> 8)
+
+#define MKOP(t, f, s)  ((t) | (f) | SIZE(s))
+
+struct instruction_op {
+       int type;
+       int reg;
+       unsigned long val;
+       /* For LOAD/STORE/LARX/STCX */
+       unsigned long ea;
+       int update_reg;
+       /* For MFSPR */
+       int spr;
+};
+
+extern int analyse_instr(struct instruction_op *op, struct pt_regs *regs,
+                        unsigned int instr);
index f8b60793b7a908f508904619ad2a8a023f6e82a1..d531d9e173ef8c2e86bfa0a5f352264f75062a5c 100644 (file)
 extern u32 tsi108_pci_cfg_base;
 /* Exported functions */
 
-extern int tsi108_bridge_init(struct pci_controller *hose, uint phys_csr_base);
-extern unsigned long tsi108_get_mem_size(void);
-extern unsigned long tsi108_get_cpu_clk(void);
-extern unsigned long tsi108_get_sdc_clk(void);
 extern int tsi108_direct_write_config(struct pci_bus *bus, unsigned int devfn,
                                      int offset, int len, u32 val);
 extern int tsi108_direct_read_config(struct pci_bus *bus, unsigned int devfn,
index b51fba10e733d453ac29e0c535ff419d480f206d..78f2675f2aacb3e4f08258270e604af40103a62c 100644 (file)
@@ -52,7 +52,6 @@ extern void __init udbg_init_44x_as1(void);
 extern void __init udbg_init_40x_realmode(void);
 extern void __init udbg_init_cpm(void);
 extern void __init udbg_init_usbgecko(void);
-extern void __init udbg_init_wsp(void);
 extern void __init udbg_init_memcons(void);
 extern void __init udbg_init_ehv_bc(void);
 extern void __init udbg_init_ps3gelic(void);
index 9a5c928bb3c64ea8cb021da323c46b1d59dc6446..5b3a903adae6d761effa550a802ed5d6a2aeb656 100644 (file)
@@ -42,32 +42,65 @@ static inline bool has_zero(unsigned long val, unsigned long *data, const struct
 
 #else
 
+#ifdef CONFIG_64BIT
+
+/* unused */
 struct word_at_a_time {
-       const unsigned long one_bits, high_bits;
 };
 
-#define WORD_AT_A_TIME_CONSTANTS { REPEAT_BYTE(0x01), REPEAT_BYTE(0x80) }
+#define WORD_AT_A_TIME_CONSTANTS { }
 
-#ifdef CONFIG_64BIT
+/* This will give us 0xff for a NULL char and 0x00 elsewhere */
+static inline unsigned long has_zero(unsigned long a, unsigned long *bits, const struct word_at_a_time *c)
+{
+       unsigned long ret;
+       unsigned long zero = 0;
 
-/* Alan Modra's little-endian strlen tail for 64-bit */
-#define create_zero_mask(mask) (mask)
+       asm("cmpb %0,%1,%2" : "=r" (ret) : "r" (a), "r" (zero));
+       *bits = ret;
 
-static inline unsigned long find_zero(unsigned long mask)
+       return ret;
+}
+
+static inline unsigned long prep_zero_mask(unsigned long a, unsigned long bits, const struct word_at_a_time *c)
+{
+       return bits;
+}
+
+/* Alan Modra's little-endian strlen tail for 64-bit */
+static inline unsigned long create_zero_mask(unsigned long bits)
 {
        unsigned long leading_zero_bits;
        long trailing_zero_bit_mask;
 
-       asm ("addi %1,%2,-1\n\t"
-            "andc %1,%1,%2\n\t"
-            "popcntd %0,%1"
-            : "=r" (leading_zero_bits), "=&r" (trailing_zero_bit_mask)
-            : "r" (mask));
-       return leading_zero_bits >> 3;
+       asm("addi       %1,%2,-1\n\t"
+           "andc       %1,%1,%2\n\t"
+           "popcntd    %0,%1"
+               : "=r" (leading_zero_bits), "=&r" (trailing_zero_bit_mask)
+               : "r" (bits));
+
+       return leading_zero_bits;
+}
+
+static inline unsigned long find_zero(unsigned long mask)
+{
+       return mask >> 3;
+}
+
+/* This assumes that we never ask for an all 1s bitmask */
+static inline unsigned long zero_bytemask(unsigned long mask)
+{
+       return (1UL << mask) - 1;
 }
 
 #else  /* 32-bit case */
 
+struct word_at_a_time {
+       const unsigned long one_bits, high_bits;
+};
+
+#define WORD_AT_A_TIME_CONSTANTS { REPEAT_BYTE(0x01), REPEAT_BYTE(0x80) }
+
 /*
  * This is largely generic for little-endian machines, but the
  * optimal byte mask counting is probably going to be something
@@ -96,8 +129,6 @@ static inline unsigned long find_zero(unsigned long mask)
        return count_masked_bytes(mask);
 }
 
-#endif
-
 /* Return nonzero if it has a zero */
 static inline unsigned long has_zero(unsigned long a, unsigned long *bits, const struct word_at_a_time *c)
 {
@@ -114,6 +145,59 @@ static inline unsigned long prep_zero_mask(unsigned long a, unsigned long bits,
 /* The mask we created is directly usable as a bytemask */
 #define zero_bytemask(mask) (mask)
 
+#endif /* CONFIG_64BIT */
+
+#endif /* __BIG_ENDIAN__ */
+
+/*
+ * We use load_unaligned_zero() in a selftest, which builds a userspace
+ * program. Some linker scripts seem to discard the .fixup section, so allow
+ * the test code to use a different section name.
+ */
+#ifndef FIXUP_SECTION
+#define FIXUP_SECTION ".fixup"
+#endif
+
+static inline unsigned long load_unaligned_zeropad(const void *addr)
+{
+       unsigned long ret, offset, tmp;
+
+       asm(
+       "1:     " PPC_LL "%[ret], 0(%[addr])\n"
+       "2:\n"
+       ".section " FIXUP_SECTION ",\"ax\"\n"
+       "3:     "
+#ifdef __powerpc64__
+       "clrrdi         %[tmp], %[addr], 3\n\t"
+       "clrlsldi       %[offset], %[addr], 61, 3\n\t"
+       "ld             %[ret], 0(%[tmp])\n\t"
+#ifdef __BIG_ENDIAN__
+       "sld            %[ret], %[ret], %[offset]\n\t"
+#else
+       "srd            %[ret], %[ret], %[offset]\n\t"
 #endif
+#else
+       "clrrwi         %[tmp], %[addr], 2\n\t"
+       "clrlslwi       %[offset], %[addr], 30, 3\n\t"
+       "lwz            %[ret], 0(%[tmp])\n\t"
+#ifdef __BIG_ENDIAN__
+       "slw            %[ret], %[ret], %[offset]\n\t"
+#else
+       "srw            %[ret], %[ret], %[offset]\n\t"
+#endif
+#endif
+       "b      2b\n"
+       ".previous\n"
+       ".section __ex_table,\"a\"\n\t"
+               PPC_LONG_ALIGN "\n\t"
+               PPC_LONG "1b,3b\n"
+       ".previous"
+       : [tmp] "=&b" (tmp), [offset] "=&r" (offset), [ret] "=&r" (ret)
+       : [addr] "b" (addr), "m" (*(unsigned long *)addr));
+
+       return ret;
+}
+
+#undef FIXUP_SECTION
 
 #endif /* _ASM_WORD_AT_A_TIME_H */
index 282d43a0c85566927755dc71d6a2ce9b5bd40d4a..0d050ea37a0489a90eae1d844be6400e4eb9965d 100644 (file)
@@ -29,6 +29,7 @@
 /* Native ICP */
 #ifdef CONFIG_PPC_ICP_NATIVE
 extern int icp_native_init(void);
+extern void icp_native_flush_interrupt(void);
 #else
 static inline int icp_native_init(void) { return -ENODEV; }
 #endif
index 670c312d914e64508ddcf8599d639663504603f6..502cf69b6c89e30c75545ac34cc4092b4af80416 100644 (file)
@@ -93,6 +93,9 @@ obj-$(CONFIG_PPC32)           += entry_32.o setup_32.o
 obj-$(CONFIG_PPC64)            += dma-iommu.o iommu.o
 obj-$(CONFIG_KGDB)             += kgdb.o
 obj-$(CONFIG_MODULES)          += ppc_ksyms.o
+ifeq ($(CONFIG_PPC32),y)
+obj-$(CONFIG_MODULES)          += ppc_ksyms_32.o
+endif
 obj-$(CONFIG_BOOTX_TEXT)       += btext.o
 obj-$(CONFIG_SMP)              += smp.o
 obj-$(CONFIG_KPROBES)          += kprobes.o
index 7a13f378ca2c7b1c715b9719e01329f99bf2ef2e..c78e6dac4d7de2842c1d679691373eb53762057a 100644 (file)
@@ -13,6 +13,7 @@
 
 #include <linux/crash_dump.h>
 #include <linux/bootmem.h>
+#include <linux/io.h>
 #include <linux/memblock.h>
 #include <asm/code-patching.h>
 #include <asm/kdump.h>
index bd1a2aba599f59aaee4d31d9d971f5afb9d5bca4..735979764cd4ce6b9100051b88e947b02bc4f9b2 100644 (file)
@@ -106,10 +106,14 @@ int __init swiotlb_setup_bus_notifier(void)
        return 0;
 }
 
-void swiotlb_detect_4g(void)
+void __init swiotlb_detect_4g(void)
 {
-       if ((memblock_end_of_DRAM() - 1) > 0xffffffff)
+       if ((memblock_end_of_DRAM() - 1) > 0xffffffff) {
                ppc_swiotlb_enable = 1;
+#ifdef CONFIG_ZONE_DMA32
+               limit_zone_pfn(ZONE_DMA32, (1ULL << 32) >> PAGE_SHIFT);
+#endif
+       }
 }
 
 static int __init swiotlb_late_init(void)
index ee78f6e49d64bddc78d58382b73008841896b38a..adac9dc54aeed2c748ae62a7a3cd1ad9fad8eb2f 100644 (file)
@@ -15,6 +15,7 @@
 #include <asm/vio.h>
 #include <asm/bug.h>
 #include <asm/machdep.h>
+#include <asm/swiotlb.h>
 
 /*
  * Generic direct DMA implementation
  * default the offset is PCI_DRAM_OFFSET.
  */
 
+static u64 __maybe_unused get_pfn_limit(struct device *dev)
+{
+       u64 pfn = (dev->coherent_dma_mask >> PAGE_SHIFT) + 1;
+       struct dev_archdata __maybe_unused *sd = &dev->archdata;
+
+#ifdef CONFIG_SWIOTLB
+       if (sd->max_direct_dma_addr && sd->dma_ops == &swiotlb_dma_ops)
+               pfn = min_t(u64, pfn, sd->max_direct_dma_addr >> PAGE_SHIFT);
+#endif
+
+       return pfn;
+}
 
 void *dma_direct_alloc_coherent(struct device *dev, size_t size,
                                dma_addr_t *dma_handle, gfp_t flag,
@@ -40,6 +53,26 @@ void *dma_direct_alloc_coherent(struct device *dev, size_t size,
 #else
        struct page *page;
        int node = dev_to_node(dev);
+       u64 pfn = get_pfn_limit(dev);
+       int zone;
+
+       zone = dma_pfn_limit_to_zone(pfn);
+       if (zone < 0) {
+               dev_err(dev, "%s: No suitable zone for pfn %#llx\n",
+                       __func__, pfn);
+               return NULL;
+       }
+
+       switch (zone) {
+       case ZONE_DMA:
+               flag |= GFP_DMA;
+               break;
+#ifdef CONFIG_ZONE_DMA32
+       case ZONE_DMA32:
+               flag |= GFP_DMA32;
+               break;
+#endif
+       };
 
        /* ignore region specifiers */
        flag  &= ~(__GFP_HIGHMEM);
@@ -202,6 +235,7 @@ int __dma_set_mask(struct device *dev, u64 dma_mask)
        *dev->dma_mask = dma_mask;
        return 0;
 }
+
 int dma_set_mask(struct device *dev, u64 dma_mask)
 {
        if (ppc_md.dma_set_mask)
@@ -210,13 +244,10 @@ int dma_set_mask(struct device *dev, u64 dma_mask)
 }
 EXPORT_SYMBOL(dma_set_mask);
 
-u64 dma_get_required_mask(struct device *dev)
+u64 __dma_get_required_mask(struct device *dev)
 {
        struct dma_map_ops *dma_ops = get_dma_ops(dev);
 
-       if (ppc_md.dma_get_required_mask)
-               return ppc_md.dma_get_required_mask(dev);
-
        if (unlikely(dma_ops == NULL))
                return 0;
 
@@ -225,6 +256,14 @@ u64 dma_get_required_mask(struct device *dev)
 
        return DMA_BIT_MASK(8 * sizeof(dma_addr_t));
 }
+
+u64 dma_get_required_mask(struct device *dev)
+{
+       if (ppc_md.dma_get_required_mask)
+               return ppc_md.dma_get_required_mask(dev);
+
+       return __dma_get_required_mask(dev);
+}
 EXPORT_SYMBOL_GPL(dma_get_required_mask);
 
 static int __init dma_init(void)
index 59a64f8dc85f4cbd771e68b72ebaf8019429eeb3..d543e4179c18cc7737569c8a0e5ef5e8ebf48e14 100644 (file)
@@ -117,7 +117,7 @@ static DEFINE_MUTEX(eeh_dev_mutex);
  * not dynamically alloced, so that it ends up in RMO where RTAS
  * can access it.
  */
-#define EEH_PCI_REGS_LOG_LEN 4096
+#define EEH_PCI_REGS_LOG_LEN 8192
 static unsigned char pci_regs_buf[EEH_PCI_REGS_LOG_LEN];
 
 /*
@@ -148,16 +148,12 @@ static int __init eeh_setup(char *str)
 }
 __setup("eeh=", eeh_setup);
 
-/**
- * eeh_gather_pci_data - Copy assorted PCI config space registers to buff
- * @edev: device to report data for
- * @buf: point to buffer in which to log
- * @len: amount of room in buffer
- *
- * This routine captures assorted PCI configuration space data,
- * and puts them into a buffer for RTAS error logging.
+/*
+ * This routine captures assorted PCI configuration space data
+ * for the indicated PCI device, and puts them into a buffer
+ * for RTAS error logging.
  */
-static size_t eeh_gather_pci_data(struct eeh_dev *edev, char *buf, size_t len)
+static size_t eeh_dump_dev_log(struct eeh_dev *edev, char *buf, size_t len)
 {
        struct device_node *dn = eeh_dev_to_of_node(edev);
        u32 cfg;
@@ -255,6 +251,19 @@ static size_t eeh_gather_pci_data(struct eeh_dev *edev, char *buf, size_t len)
        return n;
 }
 
+static void *eeh_dump_pe_log(void *data, void *flag)
+{
+       struct eeh_pe *pe = data;
+       struct eeh_dev *edev, *tmp;
+       size_t *plen = flag;
+
+       eeh_pe_for_each_dev(pe, edev, tmp)
+               *plen += eeh_dump_dev_log(edev, pci_regs_buf + *plen,
+                                         EEH_PCI_REGS_LOG_LEN - *plen);
+
+       return NULL;
+}
+
 /**
  * eeh_slot_error_detail - Generate combined log including driver log and error log
  * @pe: EEH PE
@@ -268,7 +277,6 @@ static size_t eeh_gather_pci_data(struct eeh_dev *edev, char *buf, size_t len)
 void eeh_slot_error_detail(struct eeh_pe *pe, int severity)
 {
        size_t loglen = 0;
-       struct eeh_dev *edev, *tmp;
 
        /*
         * When the PHB is fenced or dead, it's pointless to collect
@@ -286,10 +294,7 @@ void eeh_slot_error_detail(struct eeh_pe *pe, int severity)
                eeh_pe_restore_bars(pe);
 
                pci_regs_buf[0] = 0;
-               eeh_pe_for_each_dev(pe, edev, tmp) {
-                       loglen += eeh_gather_pci_data(edev, pci_regs_buf + loglen,
-                                                     EEH_PCI_REGS_LOG_LEN - loglen);
-               }
+               eeh_pe_traverse(pe, eeh_dump_pe_log, &loglen);
        }
 
        eeh_ops->get_log(pe, severity, pci_regs_buf, loglen);
@@ -410,7 +415,7 @@ int eeh_dev_check_failure(struct eeh_dev *edev)
        }
        dn = eeh_dev_to_of_node(edev);
        dev = eeh_dev_to_pci_dev(edev);
-       pe = edev->pe;
+       pe = eeh_dev_to_pe(edev);
 
        /* Access to IO BARs might get this far and still not want checking. */
        if (!pe) {
@@ -542,17 +547,16 @@ EXPORT_SYMBOL_GPL(eeh_dev_check_failure);
 
 /**
  * eeh_check_failure - Check if all 1's data is due to EEH slot freeze
- * @token: I/O token, should be address in the form 0xA....
- * @val: value, should be all 1's (XXX why do we need this arg??)
+ * @token: I/O address
  *
- * Check for an EEH failure at the given token address.  Call this
+ * Check for an EEH failure at the given I/O address. Call this
  * routine if the result of a read was all 0xff's and you want to
- * find out if this is due to an EEH slot freeze event.  This routine
+ * find out if this is due to an EEH slot freeze event. This routine
  * will query firmware for the EEH status.
  *
  * Note this routine is safe to call in an interrupt context.
  */
-unsigned long eeh_check_failure(const volatile void __iomem *token, unsigned long val)
+int eeh_check_failure(const volatile void __iomem *token)
 {
        unsigned long addr;
        struct eeh_dev *edev;
@@ -562,13 +566,11 @@ unsigned long eeh_check_failure(const volatile void __iomem *token, unsigned lon
        edev = eeh_addr_cache_get_dev(addr);
        if (!edev) {
                eeh_stats.no_device++;
-               return val;
+               return 0;
        }
 
-       eeh_dev_check_failure(edev);
-       return val;
+       return eeh_dev_check_failure(edev);
 }
-
 EXPORT_SYMBOL(eeh_check_failure);
 
 
@@ -582,25 +584,51 @@ EXPORT_SYMBOL(eeh_check_failure);
  */
 int eeh_pci_enable(struct eeh_pe *pe, int function)
 {
-       int rc, flags = (EEH_STATE_MMIO_ACTIVE | EEH_STATE_DMA_ACTIVE);
+       int active_flag, rc;
 
        /*
         * pHyp doesn't allow to enable IO or DMA on unfrozen PE.
         * Also, it's pointless to enable them on unfrozen PE. So
-        * we have the check here.
+        * we have to check before enabling IO or DMA.
         */
-       if (function == EEH_OPT_THAW_MMIO ||
-           function == EEH_OPT_THAW_DMA) {
+       switch (function) {
+       case EEH_OPT_THAW_MMIO:
+               active_flag = EEH_STATE_MMIO_ACTIVE;
+               break;
+       case EEH_OPT_THAW_DMA:
+               active_flag = EEH_STATE_DMA_ACTIVE;
+               break;
+       case EEH_OPT_DISABLE:
+       case EEH_OPT_ENABLE:
+       case EEH_OPT_FREEZE_PE:
+               active_flag = 0;
+               break;
+       default:
+               pr_warn("%s: Invalid function %d\n",
+                       __func__, function);
+               return -EINVAL;
+       }
+
+       /*
+        * Check if IO or DMA has been enabled before
+        * enabling them.
+        */
+       if (active_flag) {
                rc = eeh_ops->get_state(pe, NULL);
                if (rc < 0)
                        return rc;
 
-               /* Needn't to enable or already enabled */
-               if ((rc == EEH_STATE_NOT_SUPPORT) ||
-                   ((rc & flags) == flags))
+               /* Needn't enable it at all */
+               if (rc == EEH_STATE_NOT_SUPPORT)
+                       return 0;
+
+               /* It's already enabled */
+               if (rc & active_flag)
                        return 0;
        }
 
+
+       /* Issue the request */
        rc = eeh_ops->set_option(pe, function);
        if (rc)
                pr_warn("%s: Unexpected state change %d on "
@@ -608,17 +636,17 @@ int eeh_pci_enable(struct eeh_pe *pe, int function)
                        __func__, function, pe->phb->global_number,
                        pe->addr, rc);
 
-       rc = eeh_ops->wait_state(pe, PCI_BUS_RESET_WAIT_MSEC);
-       if (rc <= 0)
-               return rc;
+       /* Check if the request is finished successfully */
+       if (active_flag) {
+               rc = eeh_ops->wait_state(pe, PCI_BUS_RESET_WAIT_MSEC);
+               if (rc <= 0)
+                       return rc;
 
-       if ((function == EEH_OPT_THAW_MMIO) &&
-           (rc & EEH_STATE_MMIO_ENABLED))
-               return 0;
+               if (rc & active_flag)
+                       return 0;
 
-       if ((function == EEH_OPT_THAW_DMA) &&
-           (rc & EEH_STATE_DMA_ENABLED))
-               return 0;
+               return -EIO;
+       }
 
        return rc;
 }
@@ -634,7 +662,7 @@ int eeh_pci_enable(struct eeh_pe *pe, int function)
 int pcibios_set_pcie_reset_state(struct pci_dev *dev, enum pcie_reset_state state)
 {
        struct eeh_dev *edev = pci_dev_to_eeh_dev(dev);
-       struct eeh_pe *pe = edev->pe;
+       struct eeh_pe *pe = eeh_dev_to_pe(edev);
 
        if (!pe) {
                pr_err("%s: No PE found on PCI device %s\n",
@@ -645,14 +673,18 @@ int pcibios_set_pcie_reset_state(struct pci_dev *dev, enum pcie_reset_state stat
        switch (state) {
        case pcie_deassert_reset:
                eeh_ops->reset(pe, EEH_RESET_DEACTIVATE);
+               eeh_pe_state_clear(pe, EEH_PE_RESET);
                break;
        case pcie_hot_reset:
+               eeh_pe_state_mark(pe, EEH_PE_RESET);
                eeh_ops->reset(pe, EEH_RESET_HOT);
                break;
        case pcie_warm_reset:
+               eeh_pe_state_mark(pe, EEH_PE_RESET);
                eeh_ops->reset(pe, EEH_RESET_FUNDAMENTAL);
                break;
        default:
+               eeh_pe_state_clear(pe, EEH_PE_RESET);
                return -EINVAL;
        };
 
@@ -1141,6 +1173,85 @@ void eeh_remove_device(struct pci_dev *dev)
        edev->mode &= ~EEH_DEV_SYSFS;
 }
 
+int eeh_unfreeze_pe(struct eeh_pe *pe, bool sw_state)
+{
+       int ret;
+
+       ret = eeh_pci_enable(pe, EEH_OPT_THAW_MMIO);
+       if (ret) {
+               pr_warn("%s: Failure %d enabling IO on PHB#%x-PE#%x\n",
+                       __func__, ret, pe->phb->global_number, pe->addr);
+               return ret;
+       }
+
+       ret = eeh_pci_enable(pe, EEH_OPT_THAW_DMA);
+       if (ret) {
+               pr_warn("%s: Failure %d enabling DMA on PHB#%x-PE#%x\n",
+                       __func__, ret, pe->phb->global_number, pe->addr);
+               return ret;
+       }
+
+       /* Clear software isolated state */
+       if (sw_state && (pe->state & EEH_PE_ISOLATED))
+               eeh_pe_state_clear(pe, EEH_PE_ISOLATED);
+
+       return ret;
+}
+
+
+static struct pci_device_id eeh_reset_ids[] = {
+       { PCI_DEVICE(0x19a2, 0x0710) }, /* Emulex, BE     */
+       { PCI_DEVICE(0x10df, 0xe220) }, /* Emulex, Lancer */
+       { 0 }
+};
+
+static int eeh_pe_change_owner(struct eeh_pe *pe)
+{
+       struct eeh_dev *edev, *tmp;
+       struct pci_dev *pdev;
+       struct pci_device_id *id;
+       int flags, ret;
+
+       /* Check PE state */
+       flags = (EEH_STATE_MMIO_ACTIVE | EEH_STATE_DMA_ACTIVE);
+       ret = eeh_ops->get_state(pe, NULL);
+       if (ret < 0 || ret == EEH_STATE_NOT_SUPPORT)
+               return 0;
+
+       /* Unfrozen PE, nothing to do */
+       if ((ret & flags) == flags)
+               return 0;
+
+       /* Frozen PE, check if it needs PE level reset */
+       eeh_pe_for_each_dev(pe, edev, tmp) {
+               pdev = eeh_dev_to_pci_dev(edev);
+               if (!pdev)
+                       continue;
+
+               for (id = &eeh_reset_ids[0]; id->vendor != 0; id++) {
+                       if (id->vendor != PCI_ANY_ID &&
+                           id->vendor != pdev->vendor)
+                               continue;
+                       if (id->device != PCI_ANY_ID &&
+                           id->device != pdev->device)
+                               continue;
+                       if (id->subvendor != PCI_ANY_ID &&
+                           id->subvendor != pdev->subsystem_vendor)
+                               continue;
+                       if (id->subdevice != PCI_ANY_ID &&
+                           id->subdevice != pdev->subsystem_device)
+                               continue;
+
+                       goto reset;
+               }
+       }
+
+       return eeh_unfreeze_pe(pe, true);
+
+reset:
+       return eeh_pe_reset_and_recover(pe);
+}
+
 /**
  * eeh_dev_open - Increase count of pass through devices for PE
  * @pdev: PCI device
@@ -1153,6 +1264,7 @@ void eeh_remove_device(struct pci_dev *dev)
 int eeh_dev_open(struct pci_dev *pdev)
 {
        struct eeh_dev *edev;
+       int ret = -ENODEV;
 
        mutex_lock(&eeh_dev_mutex);
 
@@ -1165,6 +1277,16 @@ int eeh_dev_open(struct pci_dev *pdev)
        if (!edev || !edev->pe)
                goto out;
 
+       /*
+        * The PE might have been put into frozen state, but we
+        * didn't detect that yet. The passed through PCI devices
+        * in frozen PE won't work properly. Clear the frozen state
+        * in advance.
+        */
+       ret = eeh_pe_change_owner(edev->pe);
+       if (ret)
+               goto out;
+
        /* Increase PE's pass through count */
        atomic_inc(&edev->pe->pass_dev_cnt);
        mutex_unlock(&eeh_dev_mutex);
@@ -1172,7 +1294,7 @@ int eeh_dev_open(struct pci_dev *pdev)
        return 0;
 out:
        mutex_unlock(&eeh_dev_mutex);
-       return -ENODEV;
+       return ret;
 }
 EXPORT_SYMBOL_GPL(eeh_dev_open);
 
@@ -1202,6 +1324,7 @@ void eeh_dev_release(struct pci_dev *pdev)
        /* Decrease PE's pass through count */
        atomic_dec(&edev->pe->pass_dev_cnt);
        WARN_ON(atomic_read(&edev->pe->pass_dev_cnt) < 0);
+       eeh_pe_change_owner(edev->pe);
 out:
        mutex_unlock(&eeh_dev_mutex);
 }
@@ -1281,8 +1404,10 @@ int eeh_pe_set_option(struct eeh_pe *pe, int option)
         */
        switch (option) {
        case EEH_OPT_ENABLE:
-               if (eeh_enabled())
+               if (eeh_enabled()) {
+                       ret = eeh_pe_change_owner(pe);
                        break;
+               }
                ret = -EIO;
                break;
        case EEH_OPT_DISABLE:
@@ -1294,7 +1419,7 @@ int eeh_pe_set_option(struct eeh_pe *pe, int option)
                        break;
                }
 
-               ret = eeh_ops->set_option(pe, option);
+               ret = eeh_pci_enable(pe, option);
                break;
        default:
                pr_debug("%s: Option %d out of range (%d, %d)\n",
@@ -1345,6 +1470,36 @@ int eeh_pe_get_state(struct eeh_pe *pe)
 }
 EXPORT_SYMBOL_GPL(eeh_pe_get_state);
 
+static int eeh_pe_reenable_devices(struct eeh_pe *pe)
+{
+       struct eeh_dev *edev, *tmp;
+       struct pci_dev *pdev;
+       int ret = 0;
+
+       /* Restore config space */
+       eeh_pe_restore_bars(pe);
+
+       /*
+        * Reenable PCI devices as the devices passed
+        * through are always enabled before the reset.
+        */
+       eeh_pe_for_each_dev(pe, edev, tmp) {
+               pdev = eeh_dev_to_pci_dev(edev);
+               if (!pdev)
+                       continue;
+
+               ret = pci_reenable_device(pdev);
+               if (ret) {
+                       pr_warn("%s: Failure %d reenabling %s\n",
+                               __func__, ret, pci_name(pdev));
+                       return ret;
+               }
+       }
+
+       /* The PE is still in frozen state */
+       return eeh_unfreeze_pe(pe, true);
+}
+
 /**
  * eeh_pe_reset - Issue PE reset according to specified type
  * @pe: EEH PE
@@ -1368,23 +1523,22 @@ int eeh_pe_reset(struct eeh_pe *pe, int option)
        switch (option) {
        case EEH_RESET_DEACTIVATE:
                ret = eeh_ops->reset(pe, option);
+               eeh_pe_state_clear(pe, EEH_PE_RESET);
                if (ret)
                        break;
 
-               /*
-                * The PE is still in frozen state and we need to clear
-                * that. It's good to clear frozen state after deassert
-                * to avoid messy IO access during reset, which might
-                * cause recursive frozen PE.
-                */
-               ret = eeh_ops->set_option(pe, EEH_OPT_THAW_MMIO);
-               if (!ret)
-                       ret = eeh_ops->set_option(pe, EEH_OPT_THAW_DMA);
-               if (!ret)
-                       eeh_pe_state_clear(pe, EEH_PE_ISOLATED);
+               ret = eeh_pe_reenable_devices(pe);
                break;
        case EEH_RESET_HOT:
        case EEH_RESET_FUNDAMENTAL:
+               /*
+                * Proactively freeze the PE to drop all MMIO access
+                * during reset, which should be banned as it's always
+                * cause recursive EEH error.
+                */
+               eeh_ops->set_option(pe, EEH_OPT_FREEZE_PE);
+
+               eeh_pe_state_mark(pe, EEH_PE_RESET);
                ret = eeh_ops->reset(pe, option);
                break;
        default:
@@ -1413,9 +1567,6 @@ int eeh_pe_configure(struct eeh_pe *pe)
        if (!pe)
                return -ENODEV;
 
-       /* Restore config space for the affected devices */
-       eeh_pe_restore_bars(pe);
-
        return ret;
 }
 EXPORT_SYMBOL_GPL(eeh_pe_configure);
index 6a0dcee8e931f6584ac5066b8997e114dbc2cba9..3fd514f8e4b2a8e300b87171378185260dc901b3 100644 (file)
@@ -180,6 +180,22 @@ static bool eeh_dev_removed(struct eeh_dev *edev)
        return false;
 }
 
+static void *eeh_dev_save_state(void *data, void *userdata)
+{
+       struct eeh_dev *edev = data;
+       struct pci_dev *pdev;
+
+       if (!edev)
+               return NULL;
+
+       pdev = eeh_dev_to_pci_dev(edev);
+       if (!pdev)
+               return NULL;
+
+       pci_save_state(pdev);
+       return NULL;
+}
+
 /**
  * eeh_report_error - Report pci error to each device driver
  * @data: eeh device
@@ -303,6 +319,22 @@ static void *eeh_report_reset(void *data, void *userdata)
        return NULL;
 }
 
+static void *eeh_dev_restore_state(void *data, void *userdata)
+{
+       struct eeh_dev *edev = data;
+       struct pci_dev *pdev;
+
+       if (!edev)
+               return NULL;
+
+       pdev = eeh_dev_to_pci_dev(edev);
+       if (!pdev)
+               return NULL;
+
+       pci_restore_state(pdev);
+       return NULL;
+}
+
 /**
  * eeh_report_resume - Tell device to resume normal operations
  * @data: eeh device
@@ -450,38 +482,82 @@ static void *eeh_pe_detach_dev(void *data, void *userdata)
 static void *__eeh_clear_pe_frozen_state(void *data, void *flag)
 {
        struct eeh_pe *pe = (struct eeh_pe *)data;
-       int i, rc;
+       bool *clear_sw_state = flag;
+       int i, rc = 1;
 
-       for (i = 0; i < 3; i++) {
-               rc = eeh_pci_enable(pe, EEH_OPT_THAW_MMIO);
-               if (rc)
-                       continue;
-               rc = eeh_pci_enable(pe, EEH_OPT_THAW_DMA);
-               if (!rc)
-                       break;
-       }
+       for (i = 0; rc && i < 3; i++)
+               rc = eeh_unfreeze_pe(pe, clear_sw_state);
 
-       /* The PE has been isolated, clear it */
+       /* Stop immediately on any errors */
        if (rc) {
-               pr_warn("%s: Can't clear frozen PHB#%x-PE#%x (%d)\n",
-                       __func__, pe->phb->global_number, pe->addr, rc);
+               pr_warn("%s: Failure %d unfreezing PHB#%x-PE#%x\n",
+                       __func__, rc, pe->phb->global_number, pe->addr);
                return (void *)pe;
        }
 
        return NULL;
 }
 
-static int eeh_clear_pe_frozen_state(struct eeh_pe *pe)
+static int eeh_clear_pe_frozen_state(struct eeh_pe *pe,
+                                    bool clear_sw_state)
 {
        void *rc;
 
-       rc = eeh_pe_traverse(pe, __eeh_clear_pe_frozen_state, NULL);
+       rc = eeh_pe_traverse(pe, __eeh_clear_pe_frozen_state, &clear_sw_state);
        if (!rc)
                eeh_pe_state_clear(pe, EEH_PE_ISOLATED);
 
        return rc ? -EIO : 0;
 }
 
+int eeh_pe_reset_and_recover(struct eeh_pe *pe)
+{
+       int result, ret;
+
+       /* Bail if the PE is being recovered */
+       if (pe->state & EEH_PE_RECOVERING)
+               return 0;
+
+       /* Put the PE into recovery mode */
+       eeh_pe_state_mark(pe, EEH_PE_RECOVERING);
+
+       /* Save states */
+       eeh_pe_dev_traverse(pe, eeh_dev_save_state, NULL);
+
+       /* Report error */
+       eeh_pe_dev_traverse(pe, eeh_report_error, &result);
+
+       /* Issue reset */
+       eeh_pe_state_mark(pe, EEH_PE_RESET);
+       ret = eeh_reset_pe(pe);
+       if (ret) {
+               eeh_pe_state_clear(pe, EEH_PE_RECOVERING | EEH_PE_RESET);
+               return ret;
+       }
+       eeh_pe_state_clear(pe, EEH_PE_RESET);
+
+       /* Unfreeze the PE */
+       ret = eeh_clear_pe_frozen_state(pe, true);
+       if (ret) {
+               eeh_pe_state_clear(pe, EEH_PE_RECOVERING);
+               return ret;
+       }
+
+       /* Notify completion of reset */
+       eeh_pe_dev_traverse(pe, eeh_report_reset, &result);
+
+       /* Restore device state */
+       eeh_pe_dev_traverse(pe, eeh_dev_restore_state, NULL);
+
+       /* Resume */
+       eeh_pe_dev_traverse(pe, eeh_report_resume, NULL);
+
+       /* Clear recovery mode */
+       eeh_pe_state_clear(pe, EEH_PE_RECOVERING);
+
+       return 0;
+}
+
 /**
  * eeh_reset_device - Perform actual reset of a pci slot
  * @pe: EEH PE
@@ -540,7 +616,7 @@ static int eeh_reset_device(struct eeh_pe *pe, struct pci_bus *bus)
        eeh_pe_state_clear(pe, EEH_PE_RESET);
 
        /* Clear frozen state */
-       rc = eeh_clear_pe_frozen_state(pe);
+       rc = eeh_clear_pe_frozen_state(pe, false);
        if (rc)
                return rc;
 
index 00e3844525a6d479b4e69c70222588369589594c..53dd0915e6907165aaed9740575d4c8f7b7a5c5a 100644 (file)
@@ -428,7 +428,7 @@ int eeh_rmv_from_parent_pe(struct eeh_dev *edev)
        }
 
        /* Remove the EEH device */
-       pe = edev->pe;
+       pe = eeh_dev_to_pe(edev);
        edev->pe = NULL;
        list_del(&edev->list);
 
@@ -584,6 +584,8 @@ static void *__eeh_pe_state_clear(void *data, void *flag)
 {
        struct eeh_pe *pe = (struct eeh_pe *)data;
        int state = *((int *)flag);
+       struct eeh_dev *edev, *tmp;
+       struct pci_dev *pdev;
 
        /* Keep the state of permanently removed PE intact */
        if ((pe->freeze_count > EEH_MAX_ALLOWED_FREEZES) &&
@@ -592,9 +594,22 @@ static void *__eeh_pe_state_clear(void *data, void *flag)
 
        pe->state &= ~state;
 
-       /* Clear check count since last isolation */
-       if (state & EEH_PE_ISOLATED)
-               pe->check_count = 0;
+       /*
+        * Special treatment on clearing isolated state. Clear
+        * check count since last isolation and put all affected
+        * devices to normal state.
+        */
+       if (!(state & EEH_PE_ISOLATED))
+               return NULL;
+
+       pe->check_count = 0;
+       eeh_pe_for_each_dev(pe, edev, tmp) {
+               pdev = eeh_dev_to_pci_dev(edev);
+               if (!pdev)
+                       continue;
+
+               pdev->error_state = pci_channel_io_normal;
+       }
 
        return NULL;
 }
index e2595ba4b720123ad89908b26bf9f9eeff35255c..f19b1e5cb06096e2bd9b68b8cd620669c8943cac 100644 (file)
@@ -54,6 +54,43 @@ EEH_SHOW_ATTR(eeh_mode,            mode,            "0x%x");
 EEH_SHOW_ATTR(eeh_config_addr,     config_addr,     "0x%x");
 EEH_SHOW_ATTR(eeh_pe_config_addr,  pe_config_addr,  "0x%x");
 
+static ssize_t eeh_pe_state_show(struct device *dev,
+                                struct device_attribute *attr, char *buf)
+{
+       struct pci_dev *pdev = to_pci_dev(dev);
+       struct eeh_dev *edev = pci_dev_to_eeh_dev(pdev);
+       int state;
+
+       if (!edev || !edev->pe)
+               return -ENODEV;
+
+       state = eeh_ops->get_state(edev->pe, NULL);
+       return sprintf(buf, "%0x08x %0x08x\n",
+                      state, edev->pe->state);
+}
+
+static ssize_t eeh_pe_state_store(struct device *dev,
+                                 struct device_attribute *attr,
+                                 const char *buf, size_t count)
+{
+       struct pci_dev *pdev = to_pci_dev(dev);
+       struct eeh_dev *edev = pci_dev_to_eeh_dev(pdev);
+
+       if (!edev || !edev->pe)
+               return -ENODEV;
+
+       /* Nothing to do if it's not frozen */
+       if (!(edev->pe->state & EEH_PE_ISOLATED))
+               return count;
+
+       if (eeh_unfreeze_pe(edev->pe, true))
+               return -EIO;
+
+       return count;
+}
+
+static DEVICE_ATTR_RW(eeh_pe_state);
+
 void eeh_sysfs_add_device(struct pci_dev *pdev)
 {
        struct eeh_dev *edev = pci_dev_to_eeh_dev(pdev);
@@ -68,9 +105,10 @@ void eeh_sysfs_add_device(struct pci_dev *pdev)
        rc += device_create_file(&pdev->dev, &dev_attr_eeh_mode);
        rc += device_create_file(&pdev->dev, &dev_attr_eeh_config_addr);
        rc += device_create_file(&pdev->dev, &dev_attr_eeh_pe_config_addr);
+       rc += device_create_file(&pdev->dev, &dev_attr_eeh_pe_state);
 
        if (rc)
-               printk(KERN_WARNING "EEH: Unable to create sysfs entries\n");
+               pr_warn("EEH: Unable to create sysfs entries\n");
        else if (edev)
                edev->mode |= EEH_DEV_SYSFS;
 }
@@ -92,6 +130,7 @@ void eeh_sysfs_remove_device(struct pci_dev *pdev)
        device_remove_file(&pdev->dev, &dev_attr_eeh_mode);
        device_remove_file(&pdev->dev, &dev_attr_eeh_config_addr);
        device_remove_file(&pdev->dev, &dev_attr_eeh_pe_config_addr);
+       device_remove_file(&pdev->dev, &dev_attr_eeh_pe_state);
 
        if (edev)
                edev->mode &= ~EEH_DEV_SYSFS;
index 7ee876d2adb57c6cc1e78d1d3204ab240238c02d..fafff8dbd5d990175874d9ca09e40a44085be525 100644 (file)
@@ -104,12 +104,15 @@ turn_on_mmu:
  * task's thread_struct.
  */
 #define EXCEPTION_PROLOG       \
-       mtspr   SPRN_SPRG_SCRATCH0,r10; \
-       mtspr   SPRN_SPRG_SCRATCH1,r11; \
-       mfcr    r10;            \
+       EXCEPTION_PROLOG_0;     \
        EXCEPTION_PROLOG_1;     \
        EXCEPTION_PROLOG_2
 
+#define EXCEPTION_PROLOG_0     \
+       mtspr   SPRN_SPRG_SCRATCH0,r10; \
+       mtspr   SPRN_SPRG_SCRATCH1,r11; \
+       mfcr    r10
+
 #define EXCEPTION_PROLOG_1     \
        mfspr   r11,SPRN_SRR1;          /* check whether user or kernel */ \
        andi.   r11,r11,MSR_PR; \
@@ -144,6 +147,14 @@ turn_on_mmu:
        SAVE_4GPRS(3, r11);     \
        SAVE_2GPRS(7, r11)
 
+/*
+ * Exception exit code.
+ */
+#define EXCEPTION_EPILOG_0     \
+       mtcr    r10;            \
+       mfspr   r10,SPRN_SPRG_SCRATCH0; \
+       mfspr   r11,SPRN_SPRG_SCRATCH1
+
 /*
  * Note: code which follows this uses cr0.eq (set if from kernel),
  * r11, r12 (SRR0), and r9 (SRR1).
@@ -293,16 +304,8 @@ InstructionTLBMiss:
 #ifdef CONFIG_8xx_CPU6
        stw     r3, 8(r0)
 #endif
-       DO_8xx_CPU6(0x3f80, r3)
-       mtspr   SPRN_M_TW, r10  /* Save a couple of working registers */
-       mfcr    r10
-#ifdef CONFIG_8xx_CPU6
-       stw     r10, 0(r0)
-       stw     r11, 4(r0)
-#else
-       mtspr   SPRN_DAR, r10
-       mtspr   SPRN_SPRG2, r11
-#endif
+       EXCEPTION_PROLOG_0
+       mtspr   SPRN_SPRG_SCRATCH2, r10
        mfspr   r10, SPRN_SRR0  /* Get effective address of fault */
 #ifdef CONFIG_8xx_CPU15
        addi    r11, r10, 0x1000
@@ -359,18 +362,11 @@ InstructionTLBMiss:
        mtspr   SPRN_MI_RPN, r10        /* Update TLB entry */
 
        /* Restore registers */
-#ifndef CONFIG_8xx_CPU6
-       mfspr   r10, SPRN_DAR
-       mtcr    r10
-       mtspr   SPRN_DAR, r11   /* Tag DAR */
-       mfspr   r11, SPRN_SPRG2
-#else
-       lwz     r11, 0(r0)
-       mtcr    r11
-       lwz     r11, 4(r0)
+#ifdef CONFIG_8xx_CPU6
        lwz     r3, 8(r0)
 #endif
-       mfspr   r10, SPRN_M_TW
+       mfspr   r10, SPRN_SPRG_SCRATCH2
+       EXCEPTION_EPILOG_0
        rfi
 2:
        mfspr   r11, SPRN_SRR1
@@ -381,19 +377,11 @@ InstructionTLBMiss:
        mtspr   SPRN_SRR1, r11
 
        /* Restore registers */
-#ifndef CONFIG_8xx_CPU6
-       mfspr   r10, SPRN_DAR
-       mtcr    r10
-       li      r11, 0x00f0
-       mtspr   SPRN_DAR, r11   /* Tag DAR */
-       mfspr   r11, SPRN_SPRG2
-#else
-       lwz     r11, 0(r0)
-       mtcr    r11
-       lwz     r11, 4(r0)
+#ifdef CONFIG_8xx_CPU6
        lwz     r3, 8(r0)
 #endif
-       mfspr   r10, SPRN_M_TW
+       mfspr   r10, SPRN_SPRG_SCRATCH2
+       EXCEPTION_EPILOG_0
        b       InstructionAccess
 
        . = 0x1200
@@ -401,16 +389,8 @@ DataStoreTLBMiss:
 #ifdef CONFIG_8xx_CPU6
        stw     r3, 8(r0)
 #endif
-       DO_8xx_CPU6(0x3f80, r3)
-       mtspr   SPRN_M_TW, r10  /* Save a couple of working registers */
-       mfcr    r10
-#ifdef CONFIG_8xx_CPU6
-       stw     r10, 0(r0)
-       stw     r11, 4(r0)
-#else
-       mtspr   SPRN_DAR, r10
-       mtspr   SPRN_SPRG2, r11
-#endif
+       EXCEPTION_PROLOG_0
+       mtspr   SPRN_SPRG_SCRATCH2, r10
        mfspr   r10, SPRN_M_TWB /* Get level 1 table entry address */
 
        /* If we are faulting a kernel address, we have to use the
@@ -483,19 +463,12 @@ DataStoreTLBMiss:
        mtspr   SPRN_MD_RPN, r10        /* Update TLB entry */
 
        /* Restore registers */
-#ifndef CONFIG_8xx_CPU6
-       mfspr   r10, SPRN_DAR
-       mtcr    r10
-       mtspr   SPRN_DAR, r11   /* Tag DAR */
-       mfspr   r11, SPRN_SPRG2
-#else
-       mtspr   SPRN_DAR, r11   /* Tag DAR */
-       lwz     r11, 0(r0)
-       mtcr    r11
-       lwz     r11, 4(r0)
+#ifdef CONFIG_8xx_CPU6
        lwz     r3, 8(r0)
 #endif
-       mfspr   r10, SPRN_M_TW
+       mtspr   SPRN_DAR, r11   /* Tag DAR */
+       mfspr   r10, SPRN_SPRG_SCRATCH2
+       EXCEPTION_EPILOG_0
        rfi
 
 /* This is an instruction TLB error on the MPC8xx.  This could be due
@@ -507,35 +480,18 @@ InstructionTLBError:
        b       InstructionAccess
 
 /* This is the data TLB error on the MPC8xx.  This could be due to
- * many reasons, including a dirty update to a pte.  We can catch that
- * one here, but anything else is an error.  First, we track down the
- * Linux pte.  If it is valid, write access is allowed, but the
- * page dirty bit is not set, we will set it and reload the TLB.  For
- * any other case, we bail out to a higher level function that can
- * handle it.
+ * many reasons, including a dirty update to a pte.  We bail out to
+ * a higher level function that can handle it.
  */
        . = 0x1400
 DataTLBError:
-#ifdef CONFIG_8xx_CPU6
-       stw     r3, 8(r0)
-#endif
-       DO_8xx_CPU6(0x3f80, r3)
-       mtspr   SPRN_M_TW, r10  /* Save a couple of working registers */
-       mfcr    r10
-       stw     r10, 0(r0)
-       stw     r11, 4(r0)
+       EXCEPTION_PROLOG_0
 
-       mfspr   r10, SPRN_DAR
-       cmpwi   cr0, r10, 0x00f0
+       mfspr   r11, SPRN_DAR
+       cmpwi   cr0, r11, 0x00f0
        beq-    FixupDAR        /* must be a buggy dcbX, icbi insn. */
-DARFixed:/* Return from dcbx instruction bug workaround, r10 holds value of DAR */
-       mfspr   r10, SPRN_M_TW  /* Restore registers */
-       lwz     r11, 0(r0)
-       mtcr    r11
-       lwz     r11, 4(r0)
-#ifdef CONFIG_8xx_CPU6
-       lwz     r3, 8(r0)
-#endif
+DARFixed:/* Return from dcbx instruction bug workaround */
+       EXCEPTION_EPILOG_0
        b       DataAccess
 
        EXCEPTION(0x1500, Trap_15, unknown_exception, EXC_XFER_EE)
@@ -559,11 +515,15 @@ DARFixed:/* Return from dcbx instruction bug workaround, r10 holds value of DAR
 
 /* This is the procedure to calculate the data EA for buggy dcbx,dcbi instructions
  * by decoding the registers used by the dcbx instruction and adding them.
- * DAR is set to the calculated address and r10 also holds the EA on exit.
+ * DAR is set to the calculated address.
  */
  /* define if you don't want to use self modifying code */
 #define NO_SELF_MODIFYING_CODE
 FixupDAR:/* Entry point for dcbx workaround. */
+#ifdef CONFIG_8xx_CPU6
+       stw     r3, 8(r0)
+#endif
+       mtspr   SPRN_SPRG_SCRATCH2, r10
        /* fetch instruction from memory. */
        mfspr   r10, SPRN_SRR0
        andis.  r11, r10, 0x8000        /* Address >= 0x80000000 */
@@ -579,16 +539,17 @@ FixupDAR:/* Entry point for dcbx workaround. */
        mtspr   SPRN_MD_TWC, r11        /* Load pte table base address */
        mfspr   r11, SPRN_MD_TWC        /* ....and get the pte address */
        lwz     r11, 0(r11)     /* Get the pte */
+#ifdef CONFIG_8xx_CPU6
+       lwz     r3, 8(r0)       /* restore r3 from memory */
+#endif
        /* concat physical page address(r11) and page offset(r10) */
        rlwimi  r11, r10, 0, 20, 31
        lwz     r11,0(r11)
 /* Check if it really is a dcbx instruction. */
 /* dcbt and dcbtst does not generate DTLB Misses/Errors,
  * no need to include them here */
-       srwi    r10, r11, 26    /* check if major OP code is 31 */
-       cmpwi   cr0, r10, 31
-       bne-    141f
-       rlwinm  r10, r11, 0, 21, 30
+       xoris   r10, r11, 0x7c00        /* check if major OP code is 31 */
+       rlwinm  r10, r10, 0, 21, 5
        cmpwi   cr0, r10, 2028  /* Is dcbz? */
        beq+    142f
        cmpwi   cr0, r10, 940   /* Is dcbi? */
@@ -599,16 +560,13 @@ FixupDAR:/* Entry point for dcbx workaround. */
        beq+    142f
        cmpwi   cr0, r10, 1964  /* Is icbi? */
        beq+    142f
-141:   mfspr   r10, SPRN_DAR   /* r10 must hold DAR at exit */
+141:   mfspr   r10,SPRN_SPRG_SCRATCH2
        b       DARFixed        /* Nope, go back to normal TLB processing */
 
 144:   mfspr   r10, SPRN_DSISR
        rlwinm  r10, r10,0,7,5  /* Clear store bit for buggy dcbst insn */
        mtspr   SPRN_DSISR, r10
 142:   /* continue, it was a dcbx, dcbi instruction. */
-#ifdef CONFIG_8xx_CPU6
-       lwz     r3, 8(r0)       /* restore r3 from memory */
-#endif
 #ifndef NO_SELF_MODIFYING_CODE
        andis.  r10,r11,0x1f    /* test if reg RA is r0 */
        li      r10,modified_instr@l
@@ -619,14 +577,15 @@ FixupDAR:/* Entry point for dcbx workaround. */
        stw     r11,0(r10)      /* store add/and instruction */
        dcbf    0,r10           /* flush new instr. to memory. */
        icbi    0,r10           /* invalidate instr. cache line */
-       lwz     r11, 4(r0)      /* restore r11 from memory */
-       mfspr   r10, SPRN_M_TW  /* restore r10 from M_TW */
+       mfspr   r11, SPRN_SPRG_SCRATCH1 /* restore r11 */
+       mfspr   r10, SPRN_SPRG_SCRATCH0 /* restore r10 */
        isync                   /* Wait until new instr is loaded from memory */
 modified_instr:
        .space  4               /* this is where the add instr. is stored */
        bne+    143f
        subf    r10,r0,r10      /* r10=r10-r0, only if reg RA is r0 */
 143:   mtdar   r10             /* store faulting EA in DAR */
+       mfspr   r10,SPRN_SPRG_SCRATCH2
        b       DARFixed        /* Go back to normal TLB handling */
 #else
        mfctr   r10
@@ -680,13 +639,16 @@ modified_instr:
        mfdar   r11
        mtctr   r11                     /* restore ctr reg from DAR */
        mtdar   r10                     /* save fault EA to DAR */
+       mfspr   r10,SPRN_SPRG_SCRATCH2
        b       DARFixed                /* Go back to normal TLB handling */
 
        /* special handling for r10,r11 since these are modified already */
-153:   lwz     r11, 4(r0)      /* load r11 from memory */
-       b       155f
-154:   mfspr   r11, SPRN_M_TW  /* load r10 from M_TW */
-155:   add     r10, r10, r11   /* add it */
+153:   mfspr   r11, SPRN_SPRG_SCRATCH1 /* load r11 from SPRN_SPRG_SCRATCH1 */
+       add     r10, r10, r11   /* add it */
+       mfctr   r11             /* restore r11 */
+       b       151b
+154:   mfspr   r11, SPRN_SPRG_SCRATCH0 /* load r10 from SPRN_SPRG_SCRATCH0 */
+       add     r10, r10, r11   /* add it */
        mfctr   r11             /* restore r11 */
        b       151b
 #endif
index 0bb5918faaaf2c008f9e3ae25a7ae3d1c7ad4f21..1f7d84e2e8b219e42d5e40c00a90ff5544c02a3a 100644 (file)
@@ -293,7 +293,7 @@ out:
 /*
  * Handle single-step exceptions following a DABR hit.
  */
-int __kprobes single_step_dabr_instruction(struct die_args *args)
+static int __kprobes single_step_dabr_instruction(struct die_args *args)
 {
        struct pt_regs *regs = args->regs;
        struct perf_event *bp = NULL;
index 1114d13ac19f6ec5e0294a2d197e2db3ec8e6814..ac86c53e25428baaad22800ae1cedb2775680732 100644 (file)
@@ -55,7 +55,7 @@ static struct device ibmebus_bus_device = { /* fake "parent" device */
 struct bus_type ibmebus_bus_type;
 
 /* These devices will automatically be added to the bus during init */
-static struct of_device_id __initdata ibmebus_matches[] = {
+static const struct of_device_id ibmebus_matches[] __initconst = {
        { .compatible = "IBM,lhca" },
        { .compatible = "IBM,lhea" },
        {},
index be05841396cff00d6095e8a9edecd6e4fed7ffc3..c0754bbf81181c93c36cd8e1b12776b5ab729463 100644 (file)
@@ -73,7 +73,7 @@ _GLOBAL(power7_powersave_common)
 
        /* Check if something happened while soft-disabled */
        lbz     r0,PACAIRQHAPPENED(r13)
-       cmpwi   cr0,r0,0
+       andi.   r0,r0,~PACA_IRQ_HARD_DIS@l
        beq     1f
        cmpwi   cr0,r4,0
        beq     1f
index 4c5891de162e2de7bff803f6139853c6ef066221..8eb857f216c1ba1404a4e3b153a2077b7f7880c4 100644 (file)
@@ -444,13 +444,13 @@ void migrate_irqs(void)
 
                cpumask_and(mask, data->affinity, map);
                if (cpumask_any(mask) >= nr_cpu_ids) {
-                       printk("Breaking affinity for irq %i\n", irq);
+                       pr_warn("Breaking affinity for irq %i\n", irq);
                        cpumask_copy(mask, map);
                }
                if (chip->irq_set_affinity)
                        chip->irq_set_affinity(data, mask, true);
                else if (desc->action && !(warned++))
-                       printk("Cannot set affinity for irq %i\n", irq);
+                       pr_err("Cannot set affinity for irq %i\n", irq);
        }
 
        free_cpumask_var(mask);
@@ -470,7 +470,7 @@ static inline void check_stack_overflow(void)
 
        /* check for stack overflow: is there less than 2KB free? */
        if (unlikely(sp < (sizeof(struct thread_info) + 2048))) {
-               printk("do_IRQ: stack overflow: %ld\n",
+               pr_err("do_IRQ: stack overflow: %ld\n",
                        sp - sizeof(struct thread_info));
                dump_stack();
        }
index 936258881c98ccaee684998a3d05b2485c7fce0c..7b750c4ed5c73a5a1e7a4dfa8aa2e6055ae933d3 100644 (file)
@@ -35,7 +35,7 @@ static struct legacy_serial_info {
        phys_addr_t                     taddr;
 } legacy_serial_infos[MAX_LEGACY_SERIAL_PORTS];
 
-static struct of_device_id legacy_serial_parents[] __initdata = {
+static const struct of_device_id legacy_serial_parents[] __initconst = {
        {.type = "soc",},
        {.type = "tsi-bridge",},
        {.type = "opb", },
index 6cff040bf4565ae618e801a7159e2e5871b2c1e1..c94d2e018d843dc9d9054561252bef19f7672516 100644 (file)
@@ -15,6 +15,9 @@
     along with this program; if not, write to the Free Software
     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/module.h>
 #include <linux/moduleloader.h>
 #include <linux/elf.h>
 #include <linux/sort.h>
 #include <asm/setup.h>
 
-#if 0
-#define DEBUGP printk
-#else
-#define DEBUGP(fmt , ...)
-#endif
-
 /* Count how many different relocations (different symbol, different
    addend) */
 static unsigned int count_relocs(const Elf32_Rela *rela, unsigned int num)
@@ -121,8 +118,8 @@ static unsigned long get_plt_size(const Elf32_Ehdr *hdr,
                        continue;
 
                if (sechdrs[i].sh_type == SHT_RELA) {
-                       DEBUGP("Found relocations in section %u\n", i);
-                       DEBUGP("Ptr: %p.  Number: %u\n",
+                       pr_debug("Found relocations in section %u\n", i);
+                       pr_debug("Ptr: %p.  Number: %u\n",
                               (void *)hdr + sechdrs[i].sh_offset,
                               sechdrs[i].sh_size / sizeof(Elf32_Rela));
 
@@ -161,7 +158,7 @@ int module_frob_arch_sections(Elf32_Ehdr *hdr,
                        me->arch.core_plt_section = i;
        }
        if (!me->arch.core_plt_section || !me->arch.init_plt_section) {
-               printk("Module doesn't contain .plt or .init.plt sections.\n");
+               pr_err("Module doesn't contain .plt or .init.plt sections.\n");
                return -ENOEXEC;
        }
 
@@ -189,7 +186,7 @@ static uint32_t do_plt_call(void *location,
 {
        struct ppc_plt_entry *entry;
 
-       DEBUGP("Doing plt for call to 0x%x at 0x%x\n", val, (unsigned int)location);
+       pr_debug("Doing plt for call to 0x%x at 0x%x\n", val, (unsigned int)location);
        /* Init, or core PLT? */
        if (location >= mod->module_core
            && location < mod->module_core + mod->core_size)
@@ -208,7 +205,7 @@ static uint32_t do_plt_call(void *location,
        entry->jump[2] = 0x7d8903a6;                    /* mtctr r12 */
        entry->jump[3] = 0x4e800420;                    /* bctr */
 
-       DEBUGP("Initialized plt for 0x%x at %p\n", val, entry);
+       pr_debug("Initialized plt for 0x%x at %p\n", val, entry);
        return (uint32_t)entry;
 }
 
@@ -224,7 +221,7 @@ int apply_relocate_add(Elf32_Shdr *sechdrs,
        uint32_t *location;
        uint32_t value;
 
-       DEBUGP("Applying ADD relocate section %u to %u\n", relsec,
+       pr_debug("Applying ADD relocate section %u to %u\n", relsec,
               sechdrs[relsec].sh_info);
        for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rela); i++) {
                /* This is where to make the change */
@@ -268,17 +265,17 @@ int apply_relocate_add(Elf32_Shdr *sechdrs,
                                                    sechdrs, module);
 
                        /* Only replace bits 2 through 26 */
-                       DEBUGP("REL24 value = %08X. location = %08X\n",
+                       pr_debug("REL24 value = %08X. location = %08X\n",
                               value, (uint32_t)location);
-                       DEBUGP("Location before: %08X.\n",
+                       pr_debug("Location before: %08X.\n",
                               *(uint32_t *)location);
                        *(uint32_t *)location
                                = (*(uint32_t *)location & ~0x03fffffc)
                                | ((value - (uint32_t)location)
                                   & 0x03fffffc);
-                       DEBUGP("Location after: %08X.\n",
+                       pr_debug("Location after: %08X.\n",
                               *(uint32_t *)location);
-                       DEBUGP("ie. jump to %08X+%08X = %08X\n",
+                       pr_debug("ie. jump to %08X+%08X = %08X\n",
                               *(uint32_t *)location & 0x03fffffc,
                               (uint32_t)location,
                               (*(uint32_t *)location & 0x03fffffc)
@@ -291,7 +288,7 @@ int apply_relocate_add(Elf32_Shdr *sechdrs,
                        break;
 
                default:
-                       printk("%s: unknown ADD relocation: %u\n",
+                       pr_err("%s: unknown ADD relocation: %u\n",
                               module->name,
                               ELF32_R_TYPE(rela[i].r_info));
                        return -ENOEXEC;
index d807ee626af9c32a1a258c673c508e6bb9519081..68384514506b7725346d4b1cefd61048459efa24 100644 (file)
@@ -15,6 +15,9 @@
     along with this program; if not, write to the Free Software
     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/module.h>
 #include <linux/elf.h>
 #include <linux/moduleloader.h>
    Using a magic allocator which places modules within 32MB solves
    this, and makes other things simpler.  Anton?
    --RR.  */
-#if 0
-#define DEBUGP printk
-#else
-#define DEBUGP(fmt , ...)
-#endif
 
 #if defined(_CALL_ELF) && _CALL_ELF == 2
 #define R2_STACK_OFFSET 24
@@ -279,8 +277,8 @@ static unsigned long get_stubs_size(const Elf64_Ehdr *hdr,
        /* Every relocated section... */
        for (i = 1; i < hdr->e_shnum; i++) {
                if (sechdrs[i].sh_type == SHT_RELA) {
-                       DEBUGP("Found relocations in section %u\n", i);
-                       DEBUGP("Ptr: %p.  Number: %lu\n",
+                       pr_debug("Found relocations in section %u\n", i);
+                       pr_debug("Ptr: %p.  Number: %Lu\n",
                               (void *)sechdrs[i].sh_addr,
                               sechdrs[i].sh_size / sizeof(Elf64_Rela));
 
@@ -304,7 +302,7 @@ static unsigned long get_stubs_size(const Elf64_Ehdr *hdr,
        relocs++;
 #endif
 
-       DEBUGP("Looks like a total of %lu stubs, max\n", relocs);
+       pr_debug("Looks like a total of %lu stubs, max\n", relocs);
        return relocs * sizeof(struct ppc64_stub_entry);
 }
 
@@ -390,7 +388,7 @@ int module_frob_arch_sections(Elf64_Ehdr *hdr,
        }
 
        if (!me->arch.stubs_section) {
-               printk("%s: doesn't contain .stubs.\n", me->name);
+               pr_err("%s: doesn't contain .stubs.\n", me->name);
                return -ENOEXEC;
        }
 
@@ -434,11 +432,11 @@ static inline int create_stub(Elf64_Shdr *sechdrs,
        /* Stub uses address relative to r2. */
        reladdr = (unsigned long)entry - my_r2(sechdrs, me);
        if (reladdr > 0x7FFFFFFF || reladdr < -(0x80000000L)) {
-               printk("%s: Address %p of stub out of range of %p.\n",
+               pr_err("%s: Address %p of stub out of range of %p.\n",
                       me->name, (void *)reladdr, (void *)my_r2);
                return 0;
        }
-       DEBUGP("Stub %p get data from reladdr %li\n", entry, reladdr);
+       pr_debug("Stub %p get data from reladdr %li\n", entry, reladdr);
 
        entry->jump[0] |= PPC_HA(reladdr);
        entry->jump[1] |= PPC_LO(reladdr);
@@ -477,7 +475,7 @@ static unsigned long stub_for_addr(Elf64_Shdr *sechdrs,
 static int restore_r2(u32 *instruction, struct module *me)
 {
        if (*instruction != PPC_INST_NOP) {
-               printk("%s: Expect noop after relocate, got %08x\n",
+               pr_err("%s: Expect noop after relocate, got %08x\n",
                       me->name, *instruction);
                return 0;
        }
@@ -498,7 +496,7 @@ int apply_relocate_add(Elf64_Shdr *sechdrs,
        unsigned long *location;
        unsigned long value;
 
-       DEBUGP("Applying ADD relocate section %u to %u\n", relsec,
+       pr_debug("Applying ADD relocate section %u to %u\n", relsec,
               sechdrs[relsec].sh_info);
 
        /* First time we're called, we can fix up .TOC. */
@@ -519,7 +517,7 @@ int apply_relocate_add(Elf64_Shdr *sechdrs,
                sym = (Elf64_Sym *)sechdrs[symindex].sh_addr
                        + ELF64_R_SYM(rela[i].r_info);
 
-               DEBUGP("RELOC at %p: %li-type as %s (%lu) + %li\n",
+               pr_debug("RELOC at %p: %li-type as %s (0x%lx) + %li\n",
                       location, (long)ELF64_R_TYPE(rela[i].r_info),
                       strtab + sym->st_name, (unsigned long)sym->st_value,
                       (long)rela[i].r_addend);
@@ -546,7 +544,7 @@ int apply_relocate_add(Elf64_Shdr *sechdrs,
                        /* Subtract TOC pointer */
                        value -= my_r2(sechdrs, me);
                        if (value + 0x8000 > 0xffff) {
-                               printk("%s: bad TOC16 relocation (%lu)\n",
+                               pr_err("%s: bad TOC16 relocation (0x%lx)\n",
                                       me->name, value);
                                return -ENOEXEC;
                        }
@@ -567,7 +565,7 @@ int apply_relocate_add(Elf64_Shdr *sechdrs,
                        /* Subtract TOC pointer */
                        value -= my_r2(sechdrs, me);
                        if ((value & 3) != 0 || value + 0x8000 > 0xffff) {
-                               printk("%s: bad TOC16_DS relocation (%lu)\n",
+                               pr_err("%s: bad TOC16_DS relocation (0x%lx)\n",
                                       me->name, value);
                                return -ENOEXEC;
                        }
@@ -580,7 +578,7 @@ int apply_relocate_add(Elf64_Shdr *sechdrs,
                        /* Subtract TOC pointer */
                        value -= my_r2(sechdrs, me);
                        if ((value & 3) != 0) {
-                               printk("%s: bad TOC16_LO_DS relocation (%lu)\n",
+                               pr_err("%s: bad TOC16_LO_DS relocation (0x%lx)\n",
                                       me->name, value);
                                return -ENOEXEC;
                        }
@@ -613,7 +611,7 @@ int apply_relocate_add(Elf64_Shdr *sechdrs,
                        /* Convert value to relative */
                        value -= (unsigned long)location;
                        if (value + 0x2000000 > 0x3ffffff || (value & 3) != 0){
-                               printk("%s: REL24 %li out of range!\n",
+                               pr_err("%s: REL24 %li out of range!\n",
                                       me->name, (long int)value);
                                return -ENOEXEC;
                        }
@@ -655,7 +653,7 @@ int apply_relocate_add(Elf64_Shdr *sechdrs,
                        break;
 
                default:
-                       printk("%s: Unknown ADD relocation: %lu\n",
+                       pr_err("%s: Unknown ADD relocation: %lu\n",
                               me->name,
                               (unsigned long)ELF64_R_TYPE(rela[i].r_info));
                        return -ENOEXEC;
index 28b898e681850ab22996a2043d46c867e96232be..34f7c9b7cd96b78a7ddf338a61f2d20a5fd16611 100644 (file)
@@ -567,7 +567,7 @@ static int __init nvram_init(void)
        return rc;
 }
 
-void __exit nvram_cleanup(void)
+static void __exit nvram_cleanup(void)
 {
         misc_deregister( &nvram_dev );
 }
index a7b743076720d3a2fc04dad98be34b0d55b40978..f87bc1b4bdda60c6bf68a966eb8496e9498da8b7 100644 (file)
@@ -97,7 +97,7 @@ static int of_pci_phb_probe(struct platform_device *dev)
        return 0;
 }
 
-static struct of_device_id of_pci_phb_ids[] = {
+static const struct of_device_id of_pci_phb_ids[] = {
        { .type = "pci", },
        { .type = "pcix", },
        { .type = "pcie", },
index b2814e23e1edceacba1d2c659a2c8b73be907b3b..bd70a51d5747594906f24911d46f8a7b2abfb489 100644 (file)
@@ -1140,7 +1140,7 @@ static int reparent_resources(struct resource *parent,
  *         as well.
  */
 
-void pcibios_allocate_bus_resources(struct pci_bus *bus)
+static void pcibios_allocate_bus_resources(struct pci_bus *bus)
 {
        struct pci_bus *b;
        int i;
@@ -1561,7 +1561,6 @@ EARLY_PCI_OP(write, byte, u8)
 EARLY_PCI_OP(write, word, u16)
 EARLY_PCI_OP(write, dword, u32)
 
-extern int pci_bus_find_capability (struct pci_bus *bus, unsigned int devfn, int cap);
 int early_find_capability(struct pci_controller *hose, int bus, int devfn,
                          int cap)
 {
index 44562aa97f1611f5bcf1a26b56a425efa0c7a33e..e6245e9c7d8d7d54022a408e66e64d74d795757a 100644 (file)
@@ -38,7 +38,7 @@ static u32 get_int_prop(struct device_node *np, const char *name, u32 def)
  * @addr0: value of 1st cell of a device tree PCI address.
  * @bridge: Set this flag if the address is from a bridge 'ranges' property
  */
-unsigned int pci_parse_of_flags(u32 addr0, int bridge)
+static unsigned int pci_parse_of_flags(u32 addr0, int bridge)
 {
        unsigned int flags = 0;
 
index 48d17d6fca5b6e43ab1c77759f04a87f90c5aa2c..c4dfff6c2719ca5bfc6a17c9faf204fa836cad7f 100644 (file)
-#include <linux/export.h>
-#include <linux/threads.h>
-#include <linux/smp.h>
-#include <linux/sched.h>
-#include <linux/elfcore.h>
-#include <linux/string.h>
-#include <linux/interrupt.h>
-#include <linux/screen_info.h>
-#include <linux/vt_kern.h>
-#include <linux/nvram.h>
-#include <linux/irq.h>
-#include <linux/pci.h>
-#include <linux/delay.h>
-#include <linux/bitops.h>
+#include <linux/ftrace.h>
+#include <linux/mm.h>
 
-#include <asm/page.h>
 #include <asm/processor.h>
-#include <asm/cacheflush.h>
-#include <asm/uaccess.h>
-#include <asm/io.h>
-#include <linux/atomic.h>
-#include <asm/checksum.h>
-#include <asm/pgtable.h>
-#include <asm/tlbflush.h>
-#include <linux/adb.h>
-#include <linux/cuda.h>
-#include <linux/pmu.h>
-#include <asm/prom.h>
-#include <asm/pci-bridge.h>
-#include <asm/irq.h>
-#include <asm/pmac_feature.h>
-#include <asm/dma.h>
-#include <asm/machdep.h>
-#include <asm/hw_irq.h>
-#include <asm/nvram.h>
-#include <asm/mmu_context.h>
-#include <asm/backlight.h>
-#include <asm/time.h>
-#include <asm/cputable.h>
-#include <asm/btext.h>
-#include <asm/div64.h>
-#include <asm/signal.h>
-#include <asm/dcr.h>
-#include <asm/ftrace.h>
 #include <asm/switch_to.h>
+#include <asm/cacheflush.h>
 #include <asm/epapr_hcalls.h>
 
-#ifdef CONFIG_PPC32
-extern void transfer_to_handler(void);
-extern void do_IRQ(struct pt_regs *regs);
-extern void machine_check_exception(struct pt_regs *regs);
-extern void alignment_exception(struct pt_regs *regs);
-extern void program_check_exception(struct pt_regs *regs);
-extern void single_step_exception(struct pt_regs *regs);
-extern int sys_sigreturn(struct pt_regs *regs);
+EXPORT_SYMBOL(flush_dcache_range);
+EXPORT_SYMBOL(flush_icache_range);
 
-EXPORT_SYMBOL(clear_pages);
-EXPORT_SYMBOL(ISA_DMA_THRESHOLD);
-EXPORT_SYMBOL(DMA_MODE_READ);
-EXPORT_SYMBOL(DMA_MODE_WRITE);
+EXPORT_SYMBOL(empty_zero_page);
 
-EXPORT_SYMBOL(transfer_to_handler);
-EXPORT_SYMBOL(do_IRQ);
-EXPORT_SYMBOL(machine_check_exception);
-EXPORT_SYMBOL(alignment_exception);
-EXPORT_SYMBOL(program_check_exception);
-EXPORT_SYMBOL(single_step_exception);
-EXPORT_SYMBOL(sys_sigreturn);
-#endif
+long long __bswapdi2(long long);
+EXPORT_SYMBOL(__bswapdi2);
 
 #ifdef CONFIG_FUNCTION_TRACER
 EXPORT_SYMBOL(_mcount);
 #endif
 
-EXPORT_SYMBOL(strcpy);
-EXPORT_SYMBOL(strncpy);
-EXPORT_SYMBOL(strcat);
-EXPORT_SYMBOL(strlen);
-EXPORT_SYMBOL(strcmp);
-EXPORT_SYMBOL(strncmp);
-
-#ifndef CONFIG_GENERIC_CSUM
-EXPORT_SYMBOL(csum_partial);
-EXPORT_SYMBOL(csum_partial_copy_generic);
-EXPORT_SYMBOL(ip_fast_csum);
-EXPORT_SYMBOL(csum_tcpudp_magic);
-#endif
-
-EXPORT_SYMBOL(__copy_tofrom_user);
-EXPORT_SYMBOL(__clear_user);
-EXPORT_SYMBOL(copy_page);
-
-#if defined(CONFIG_PCI) && defined(CONFIG_PPC32)
-EXPORT_SYMBOL(isa_io_base);
-EXPORT_SYMBOL(isa_mem_base);
-EXPORT_SYMBOL(pci_dram_offset);
-#endif /* CONFIG_PCI */
-
-EXPORT_SYMBOL(start_thread);
-
 #ifdef CONFIG_PPC_FPU
 EXPORT_SYMBOL(giveup_fpu);
 EXPORT_SYMBOL(load_fp_state);
 EXPORT_SYMBOL(store_fp_state);
 #endif
+
 #ifdef CONFIG_ALTIVEC
 EXPORT_SYMBOL(giveup_altivec);
 EXPORT_SYMBOL(load_vr_state);
 EXPORT_SYMBOL(store_vr_state);
-#endif /* CONFIG_ALTIVEC */
-#ifdef CONFIG_VSX
-EXPORT_SYMBOL(giveup_vsx);
-EXPORT_SYMBOL_GPL(__giveup_vsx);
-#endif /* CONFIG_VSX */
-#ifdef CONFIG_SPE
-EXPORT_SYMBOL(giveup_spe);
-#endif /* CONFIG_SPE */
-
-#ifndef CONFIG_PPC64
-EXPORT_SYMBOL(flush_instruction_cache);
 #endif
-EXPORT_SYMBOL(flush_dcache_range);
-EXPORT_SYMBOL(flush_icache_range);
 
-#ifdef CONFIG_SMP
-#ifdef CONFIG_PPC32
-EXPORT_SYMBOL(smp_hw_index);
-#endif
-#endif
-
-#ifdef CONFIG_ADB
-EXPORT_SYMBOL(adb_request);
-EXPORT_SYMBOL(adb_register);
-EXPORT_SYMBOL(adb_unregister);
-EXPORT_SYMBOL(adb_poll);
-EXPORT_SYMBOL(adb_try_handler_change);
-#endif /* CONFIG_ADB */
-#ifdef CONFIG_ADB_CUDA
-EXPORT_SYMBOL(cuda_request);
-EXPORT_SYMBOL(cuda_poll);
-#endif /* CONFIG_ADB_CUDA */
-EXPORT_SYMBOL(to_tm);
-
-#ifdef CONFIG_PPC32
-long long __ashrdi3(long long, int);
-long long __ashldi3(long long, int);
-long long __lshrdi3(long long, int);
-EXPORT_SYMBOL(__ashrdi3);
-EXPORT_SYMBOL(__ashldi3);
-EXPORT_SYMBOL(__lshrdi3);
-int __ucmpdi2(unsigned long long, unsigned long long);
-EXPORT_SYMBOL(__ucmpdi2);
-int __cmpdi2(long long, long long);
-EXPORT_SYMBOL(__cmpdi2);
-#endif
-long long __bswapdi2(long long);
-EXPORT_SYMBOL(__bswapdi2);
-EXPORT_SYMBOL(memcpy);
-EXPORT_SYMBOL(memset);
-EXPORT_SYMBOL(memmove);
-EXPORT_SYMBOL(memcmp);
-EXPORT_SYMBOL(memchr);
-
-#if defined(CONFIG_FB_VGA16_MODULE)
-EXPORT_SYMBOL(screen_info);
-#endif
-
-#ifdef CONFIG_PPC32
-EXPORT_SYMBOL(timer_interrupt);
-EXPORT_SYMBOL(tb_ticks_per_jiffy);
-EXPORT_SYMBOL(cacheable_memcpy);
-EXPORT_SYMBOL(cacheable_memzero);
-#endif
-
-#ifdef CONFIG_PPC32
-EXPORT_SYMBOL(switch_mmu_context);
-#endif
-
-#ifdef CONFIG_PPC_STD_MMU_32
-extern long mol_trampoline;
-EXPORT_SYMBOL(mol_trampoline); /* For MOL */
-EXPORT_SYMBOL(flush_hash_pages); /* For MOL */
-#ifdef CONFIG_SMP
-extern int mmu_hash_lock;
-EXPORT_SYMBOL(mmu_hash_lock); /* For MOL */
-#endif /* CONFIG_SMP */
-extern long *intercept_table;
-EXPORT_SYMBOL(intercept_table);
-#endif /* CONFIG_PPC_STD_MMU_32 */
-#ifdef CONFIG_PPC_DCR_NATIVE
-EXPORT_SYMBOL(__mtdcr);
-EXPORT_SYMBOL(__mfdcr);
-#endif
-EXPORT_SYMBOL(empty_zero_page);
-
-#ifdef CONFIG_PPC64
-EXPORT_SYMBOL(__arch_hweight8);
-EXPORT_SYMBOL(__arch_hweight16);
-EXPORT_SYMBOL(__arch_hweight32);
-EXPORT_SYMBOL(__arch_hweight64);
+#ifdef CONFIG_VSX
+EXPORT_SYMBOL_GPL(__giveup_vsx);
 #endif
 
-#ifdef CONFIG_PPC_BOOK3S_64
-EXPORT_SYMBOL_GPL(mmu_psize_defs);
+#ifdef CONFIG_SPE
+EXPORT_SYMBOL(giveup_spe);
 #endif
 
 #ifdef CONFIG_EPAPR_PARAVIRT
diff --git a/arch/powerpc/kernel/ppc_ksyms_32.c b/arch/powerpc/kernel/ppc_ksyms_32.c
new file mode 100644 (file)
index 0000000..30ddd8a
--- /dev/null
@@ -0,0 +1,61 @@
+#include <linux/export.h>
+#include <linux/smp.h>
+
+#include <asm/page.h>
+#include <asm/dma.h>
+#include <asm/io.h>
+#include <asm/hw_irq.h>
+#include <asm/time.h>
+#include <asm/mmu_context.h>
+#include <asm/pgtable.h>
+#include <asm/dcr.h>
+
+EXPORT_SYMBOL(clear_pages);
+EXPORT_SYMBOL(ISA_DMA_THRESHOLD);
+EXPORT_SYMBOL(DMA_MODE_READ);
+EXPORT_SYMBOL(DMA_MODE_WRITE);
+
+#if defined(CONFIG_PCI)
+EXPORT_SYMBOL(isa_io_base);
+EXPORT_SYMBOL(isa_mem_base);
+EXPORT_SYMBOL(pci_dram_offset);
+#endif
+
+#ifdef CONFIG_SMP
+EXPORT_SYMBOL(smp_hw_index);
+#endif
+
+long long __ashrdi3(long long, int);
+long long __ashldi3(long long, int);
+long long __lshrdi3(long long, int);
+int __ucmpdi2(unsigned long long, unsigned long long);
+int __cmpdi2(long long, long long);
+EXPORT_SYMBOL(__ashrdi3);
+EXPORT_SYMBOL(__ashldi3);
+EXPORT_SYMBOL(__lshrdi3);
+EXPORT_SYMBOL(__ucmpdi2);
+EXPORT_SYMBOL(__cmpdi2);
+
+EXPORT_SYMBOL(timer_interrupt);
+EXPORT_SYMBOL(tb_ticks_per_jiffy);
+
+EXPORT_SYMBOL(switch_mmu_context);
+
+#ifdef CONFIG_PPC_STD_MMU_32
+extern long mol_trampoline;
+EXPORT_SYMBOL(mol_trampoline); /* For MOL */
+EXPORT_SYMBOL(flush_hash_pages); /* For MOL */
+#ifdef CONFIG_SMP
+extern int mmu_hash_lock;
+EXPORT_SYMBOL(mmu_hash_lock); /* For MOL */
+#endif /* CONFIG_SMP */
+extern long *intercept_table;
+EXPORT_SYMBOL(intercept_table);
+#endif /* CONFIG_PPC_STD_MMU_32 */
+
+#ifdef CONFIG_PPC_DCR_NATIVE
+EXPORT_SYMBOL(__mtdcr);
+EXPORT_SYMBOL(__mfdcr);
+#endif
+
+EXPORT_SYMBOL(flush_instruction_cache);
index bf44ae962ab82206bb148c674dd2dbb7f093d1fd..aa1df89c8b2a8165411d588af394ea85f833265b 100644 (file)
@@ -228,6 +228,7 @@ void giveup_vsx(struct task_struct *tsk)
        giveup_altivec_maybe_transactional(tsk);
        __giveup_vsx(tsk);
 }
+EXPORT_SYMBOL(giveup_vsx);
 
 void flush_vsx_to_thread(struct task_struct *tsk)
 {
@@ -1316,6 +1317,7 @@ void start_thread(struct pt_regs *regs, unsigned long start, unsigned long sp)
        current->thread.tm_tfiar = 0;
 #endif /* CONFIG_PPC_TRANSACTIONAL_MEM */
 }
+EXPORT_SYMBOL(start_thread);
 
 #define PR_FP_ALL_EXCEPT (PR_FP_EXC_DIV | PR_FP_EXC_OVF | PR_FP_EXC_UND \
                | PR_FP_EXC_RES | PR_FP_EXC_INV)
index 4e139f8a69effa0a403a2e6d75b0fe7d7e268e3d..099f27e6d1b07e148c0b2c25d8f377d1d4f23654 100644 (file)
@@ -386,8 +386,9 @@ static int __init early_init_dt_scan_cpus(unsigned long node,
        return 0;
 }
 
-int __init early_init_dt_scan_chosen_ppc(unsigned long node, const char *uname,
-                                        int depth, void *data)
+static int __init early_init_dt_scan_chosen_ppc(unsigned long node,
+                                               const char *uname,
+                                               int depth, void *data)
 {
        const unsigned long *lprop; /* All these set by kernel, so no need to convert endian */
 
@@ -641,6 +642,10 @@ void __init early_init_devtree(void *params)
 
        DBG(" -> early_init_devtree(%p)\n", params);
 
+       /* Too early to BUG_ON(), do it by hand */
+       if (!early_init_dt_verify(params))
+               panic("BUG: Failed verifying flat device tree, bad version?");
+
        /* Setup flat device-tree pointer */
        initial_boot_params = params;
 
@@ -663,14 +668,12 @@ void __init early_init_devtree(void *params)
         * device-tree, including the platform type, initrd location and
         * size, TCE reserve, and more ...
         */
-       of_scan_flat_dt(early_init_dt_scan_chosen_ppc, cmd_line);
+       of_scan_flat_dt(early_init_dt_scan_chosen_ppc, boot_command_line);
 
        /* Scan memory nodes and rebuild MEMBLOCKs */
        of_scan_flat_dt(early_init_dt_scan_root, NULL);
        of_scan_flat_dt(early_init_dt_scan_memory_ppc, NULL);
 
-       /* Save command line for /proc/cmdline and then parse parameters */
-       strlcpy(boot_command_line, cmd_line, COMMAND_LINE_SIZE);
        parse_early_param();
 
        /* make sure we've parsed cmdline for mem= before this */
index fe8e54b9ef7db5bddd01b3917741cadbc0746fa3..12640f7e726b29ce5ac9d256c589ce758a2521e8 100644 (file)
@@ -50,24 +50,14 @@ do
        done
 
        # ignore register save/restore funcitons
-       if [ "${UNDEF:0:9}" = "_restgpr_" ]; then
+       case $UNDEF in
+       _restgpr_*|_restgpr0_*|_rest32gpr_*)
                OK=1
-       fi
-       if [ "${UNDEF:0:10}" = "_restgpr0_" ]; then
-               OK=1
-       fi
-       if [ "${UNDEF:0:11}" = "_rest32gpr_" ]; then
-               OK=1
-       fi
-       if [ "${UNDEF:0:9}" = "_savegpr_" ]; then
+               ;;
+       _savegpr_*|_savegpr0_*|_save32gpr_*)
                OK=1
-       fi
-       if [ "${UNDEF:0:10}" = "_savegpr0_" ]; then
-               OK=1
-       fi
-       if [ "${UNDEF:0:11}" = "_save32gpr_" ]; then
-               OK=1
-       fi
+               ;;
+       esac
 
        if [ $OK -eq 0 ]; then
                ERROR=1
index 2e3d2bf536c5662c00f02e07cf36cd1e4b111825..cdb404ea34688b581a788694ed1f8da43aed1f91 100644 (file)
@@ -932,7 +932,7 @@ void ptrace_triggered(struct perf_event *bp,
 }
 #endif /* CONFIG_HAVE_HW_BREAKPOINT */
 
-int ptrace_set_debugreg(struct task_struct *task, unsigned long addr,
+static int ptrace_set_debugreg(struct task_struct *task, unsigned long addr,
                               unsigned long data)
 {
 #ifdef CONFIG_HAVE_HW_BREAKPOINT
index e736387fee6af3ee5b92ed6407b4f2e7fb38024b..5a2c049c1c61461a50546a05082338158bdd7d08 100644 (file)
@@ -286,7 +286,7 @@ static void prrn_work_fn(struct work_struct *work)
 
 static DECLARE_WORK(prrn_work, prrn_work_fn);
 
-void prrn_schedule_update(u32 scope)
+static void prrn_schedule_update(u32 scope)
 {
        flush_work(&prrn_work);
        prrn_update_scope = scope;
index 1b0e26013a62d3c9b2853b429b9f5fedad7fc1ed..1362cd62b3fa5c32fdcc27d3ba3e5ee0e21fd974 100644 (file)
@@ -81,8 +81,6 @@ EXPORT_SYMBOL_GPL(boot_cpuid);
 
 unsigned long klimit = (unsigned long) _end;
 
-char cmd_line[COMMAND_LINE_SIZE];
-
 /*
  * This still seems to be needed... -- paulus
  */ 
@@ -94,6 +92,9 @@ struct screen_info screen_info = {
        .orig_video_isVGA = 1,
        .orig_video_points = 16
 };
+#if defined(CONFIG_FB_VGA16_MODULE)
+EXPORT_SYMBOL(screen_info);
+#endif
 
 /* Variables required to store legacy IO irq routing */
 int of_i8042_kbd_irq;
@@ -382,7 +383,7 @@ void __init check_for_initrd(void)
                initrd_start = initrd_end = 0;
 
        if (initrd_start)
-               printk("Found initrd at 0x%lx:0x%lx\n", initrd_start, initrd_end);
+               pr_info("Found initrd at 0x%lx:0x%lx\n", initrd_start, initrd_end);
 
        DBG(" <- check_for_initrd()\n");
 #endif /* CONFIG_BLK_DEV_INITRD */
index ea4fda60e57b93f18163b487a4bd2a56d43715ba..07831ed0d9efd12c86dce4b6346661b7e9fa216f 100644 (file)
@@ -268,7 +268,7 @@ static void __init exc_lvl_early_init(void)
 /* Warning, IO base is not yet inited */
 void __init setup_arch(char **cmdline_p)
 {
-       *cmdline_p = cmd_line;
+       *cmdline_p = boot_command_line;
 
        /* so udelay does something sensible, assume <= 1000 bogomips */
        loops_per_jiffy = 500000000 / HZ;
index 75d62d63fe684ad77b33efac9ac2a13d59222ac7..cd07d79ad21cac659d9966fb09e2ac41fa13a374 100644 (file)
@@ -525,21 +525,31 @@ void __init setup_system(void)
        printk("Starting Linux PPC64 %s\n", init_utsname()->version);
 
        printk("-----------------------------------------------------\n");
-       printk("ppc64_pft_size                = 0x%llx\n", ppc64_pft_size);
-       printk("physicalMemorySize            = 0x%llx\n", memblock_phys_mem_size());
+       printk("ppc64_pft_size    = 0x%llx\n", ppc64_pft_size);
+       printk("phys_mem_size     = 0x%llx\n", memblock_phys_mem_size());
+
        if (ppc64_caches.dline_size != 0x80)
-               printk("ppc64_caches.dcache_line_size = 0x%x\n",
-                      ppc64_caches.dline_size);
+               printk("dcache_line_size  = 0x%x\n", ppc64_caches.dline_size);
        if (ppc64_caches.iline_size != 0x80)
-               printk("ppc64_caches.icache_line_size = 0x%x\n",
-                      ppc64_caches.iline_size);
+               printk("icache_line_size  = 0x%x\n", ppc64_caches.iline_size);
+
+       printk("cpu_features      = 0x%016lx\n", cur_cpu_spec->cpu_features);
+       printk("  possible        = 0x%016lx\n", CPU_FTRS_POSSIBLE);
+       printk("  always          = 0x%016lx\n", CPU_FTRS_ALWAYS);
+       printk("cpu_user_features = 0x%08x 0x%08x\n", cur_cpu_spec->cpu_user_features,
+               cur_cpu_spec->cpu_user_features2);
+       printk("mmu_features      = 0x%08x\n", cur_cpu_spec->mmu_features);
+       printk("firmware_features = 0x%016lx\n", powerpc_firmware_features);
+
 #ifdef CONFIG_PPC_STD_MMU_64
        if (htab_address)
-               printk("htab_address                  = 0x%p\n", htab_address);
-       printk("htab_hash_mask                = 0x%lx\n", htab_hash_mask);
-#endif /* CONFIG_PPC_STD_MMU_64 */
+               printk("htab_address      = 0x%p\n", htab_address);
+
+       printk("htab_hash_mask    = 0x%lx\n", htab_hash_mask);
+#endif
+
        if (PHYSICAL_START > 0)
-               printk("physical_start                = 0x%llx\n",
+               printk("physical_start    = 0x%llx\n",
                       (unsigned long long)PHYSICAL_START);
        printk("-----------------------------------------------------\n");
 
@@ -657,7 +667,7 @@ void __init setup_arch(char **cmdline_p)
 {
        ppc64_boot_msg(0x12, "Setup Arch");
 
-       *cmdline_p = cmd_line;
+       *cmdline_p = boot_command_line;
 
        /*
         * Set cache line size based on type of cpu as a default.
index a0738af4aba6b80b3d356935d3bcf5c3b61a4f48..71e186d5f331a3320259e4d0ad432d29944a684e 100644 (file)
@@ -52,6 +52,7 @@
 #endif
 #include <asm/vdso.h>
 #include <asm/debug.h>
+#include <asm/kexec.h>
 
 #ifdef DEBUG
 #include <asm/udbg.h>
@@ -379,8 +380,11 @@ void __init smp_prepare_cpus(unsigned int max_cpus)
                /*
                 * numa_node_id() works after this.
                 */
-               set_cpu_numa_node(cpu, numa_cpu_lookup_table[cpu]);
-               set_cpu_numa_mem(cpu, local_memory_node(numa_cpu_lookup_table[cpu]));
+               if (cpu_present(cpu)) {
+                       set_cpu_numa_node(cpu, numa_cpu_lookup_table[cpu]);
+                       set_cpu_numa_mem(cpu,
+                               local_memory_node(numa_cpu_lookup_table[cpu]));
+               }
        }
 
        cpumask_set_cpu(boot_cpuid, cpu_sibling_mask(boot_cpuid));
@@ -728,6 +732,9 @@ void start_secondary(void *unused)
        }
        traverse_core_siblings(cpu, true);
 
+       set_numa_node(numa_cpu_lookup_table[cpu]);
+       set_numa_mem(local_memory_node(numa_cpu_lookup_table[cpu]));
+
        smp_wmb();
        notify_cpu_starting(cpu);
        set_cpu_online(cpu, true);
index 368ab374d33c6b315c4a553a613d10f7d453970b..7505599c2593cc63fd89709fad21e9e5af92c906 100644 (file)
@@ -479,7 +479,7 @@ void arch_irq_work_raise(void)
 
 #endif /* CONFIG_IRQ_WORK */
 
-void __timer_interrupt(void)
+static void __timer_interrupt(void)
 {
        struct pt_regs *regs = get_irq_regs();
        u64 *next_tb = &__get_cpu_var(decrementers_next_tb);
@@ -643,7 +643,7 @@ static int __init get_freq(char *name, int cells, unsigned long *val)
        return found;
 }
 
-void start_cpu_decrementer(void)
+static void start_cpu_decrementer(void)
 {
 #if defined(CONFIG_BOOKE) || defined(CONFIG_40x)
        /* Clear any pending timer interrupts */
@@ -1024,6 +1024,7 @@ void to_tm(int tim, struct rtc_time * tm)
         */
        GregorianDay(tm);
 }
+EXPORT_SYMBOL(to_tm);
 
 /*
  * Divide a 128-bit dividend by a 32-bit divisor, leaving a 128 bit
index 59fa2de9546d7fb0ba8ca05729ad78e75e0a9e88..9f342f134ae486d2ea7be1b656202d9957713c8a 100644 (file)
@@ -10,7 +10,7 @@ CFLAGS_REMOVE_code-patching.o = -pg
 CFLAGS_REMOVE_feature-fixups.o = -pg
 
 obj-y                  := string.o alloc.o \
-                          crtsavres.o
+                          crtsavres.o ppc_ksyms.o
 obj-$(CONFIG_PPC32)    += div64.o copy_32.o
 obj-$(CONFIG_HAS_IOMEM)        += devres.o
 
index 7a8a7487cee8dde9d06aa86fff3bd32bdd54433e..7ce3870d7ddd1054898421647c54819ead09e20e 100644 (file)
@@ -164,7 +164,7 @@ static long calc_offset(struct fixup_entry *entry, unsigned int *p)
        return (unsigned long)p - (unsigned long)entry;
 }
 
-void test_basic_patching(void)
+static void test_basic_patching(void)
 {
        extern unsigned int ftr_fixup_test1;
        extern unsigned int end_ftr_fixup_test1;
diff --git a/arch/powerpc/lib/ppc_ksyms.c b/arch/powerpc/lib/ppc_ksyms.c
new file mode 100644 (file)
index 0000000..f993959
--- /dev/null
@@ -0,0 +1,39 @@
+#include <linux/string.h>
+#include <linux/uaccess.h>
+#include <linux/bitops.h>
+#include <net/checksum.h>
+
+EXPORT_SYMBOL(memcpy);
+EXPORT_SYMBOL(memset);
+EXPORT_SYMBOL(memmove);
+EXPORT_SYMBOL(memcmp);
+EXPORT_SYMBOL(memchr);
+#ifdef CONFIG_PPC32
+EXPORT_SYMBOL(cacheable_memcpy);
+EXPORT_SYMBOL(cacheable_memzero);
+#endif
+
+EXPORT_SYMBOL(strcpy);
+EXPORT_SYMBOL(strncpy);
+EXPORT_SYMBOL(strcat);
+EXPORT_SYMBOL(strlen);
+EXPORT_SYMBOL(strcmp);
+EXPORT_SYMBOL(strncmp);
+
+#ifndef CONFIG_GENERIC_CSUM
+EXPORT_SYMBOL(csum_partial);
+EXPORT_SYMBOL(csum_partial_copy_generic);
+EXPORT_SYMBOL(ip_fast_csum);
+EXPORT_SYMBOL(csum_tcpudp_magic);
+#endif
+
+EXPORT_SYMBOL(__copy_tofrom_user);
+EXPORT_SYMBOL(__clear_user);
+EXPORT_SYMBOL(copy_page);
+
+#ifdef CONFIG_PPC64
+EXPORT_SYMBOL(__arch_hweight8);
+EXPORT_SYMBOL(__arch_hweight16);
+EXPORT_SYMBOL(__arch_hweight32);
+EXPORT_SYMBOL(__arch_hweight64);
+#endif
index 5c09f365c84276161b75fd524fe270b2d43a1db2..54651fc2d4124dc7fd9b80fa5fbc3d551e7b8f06 100644 (file)
@@ -98,13 +98,8 @@ static unsigned long __kprobes dform_ea(unsigned int instr, struct pt_regs *regs
 
        ra = (instr >> 16) & 0x1f;
        ea = (signed short) instr;              /* sign-extend */
-       if (ra) {
+       if (ra)
                ea += regs->gpr[ra];
-               if (instr & 0x04000000) {               /* update forms */
-                       if ((instr>>26) != 47)          /* stmw is not an update form */
-                               regs->gpr[ra] = ea;
-               }
-       }
 
        return truncate_if_32bit(regs->msr, ea);
 }
@@ -120,11 +115,8 @@ static unsigned long __kprobes dsform_ea(unsigned int instr, struct pt_regs *reg
 
        ra = (instr >> 16) & 0x1f;
        ea = (signed short) (instr & ~3);       /* sign-extend */
-       if (ra) {
+       if (ra)
                ea += regs->gpr[ra];
-               if ((instr & 3) == 1)           /* update forms */
-                       regs->gpr[ra] = ea;
-       }
 
        return truncate_if_32bit(regs->msr, ea);
 }
@@ -133,8 +125,8 @@ static unsigned long __kprobes dsform_ea(unsigned int instr, struct pt_regs *reg
 /*
  * Calculate effective address for an X-form instruction
  */
-static unsigned long __kprobes xform_ea(unsigned int instr, struct pt_regs *regs,
-                                    int do_update)
+static unsigned long __kprobes xform_ea(unsigned int instr,
+                                       struct pt_regs *regs)
 {
        int ra, rb;
        unsigned long ea;
@@ -142,11 +134,8 @@ static unsigned long __kprobes xform_ea(unsigned int instr, struct pt_regs *regs
        ra = (instr >> 16) & 0x1f;
        rb = (instr >> 11) & 0x1f;
        ea = regs->gpr[rb];
-       if (ra) {
+       if (ra)
                ea += regs->gpr[ra];
-               if (do_update)          /* update forms */
-                       regs->gpr[ra] = ea;
-       }
 
        return truncate_if_32bit(regs->msr, ea);
 }
@@ -611,6 +600,23 @@ static void __kprobes do_cmp_unsigned(struct pt_regs *regs, unsigned long v1,
        regs->ccr = (regs->ccr & ~(0xf << shift)) | (crval << shift);
 }
 
+static int __kprobes trap_compare(long v1, long v2)
+{
+       int ret = 0;
+
+       if (v1 < v2)
+               ret |= 0x10;
+       else if (v1 > v2)
+               ret |= 0x08;
+       else
+               ret |= 0x04;
+       if ((unsigned long)v1 < (unsigned long)v2)
+               ret |= 0x02;
+       else if ((unsigned long)v1 > (unsigned long)v2)
+               ret |= 0x01;
+       return ret;
+}
+
 /*
  * Elements of 32-bit rotate and mask instructions.
  */
@@ -627,26 +633,27 @@ static void __kprobes do_cmp_unsigned(struct pt_regs *regs, unsigned long v1,
 #define ROTATE(x, n)   ((n) ? (((x) << (n)) | ((x) >> (8 * sizeof(long) - (n)))) : (x))
 
 /*
- * Emulate instructions that cause a transfer of control,
- * loads and stores, and a few other instructions.
- * Returns 1 if the step was emulated, 0 if not,
- * or -1 if the instruction is one that should not be stepped,
- * such as an rfid, or a mtmsrd that would clear MSR_RI.
+ * Decode an instruction, and execute it if that can be done just by
+ * modifying *regs (i.e. integer arithmetic and logical instructions,
+ * branches, and barrier instructions).
+ * Returns 1 if the instruction has been executed, or 0 if not.
+ * Sets *op to indicate what the instruction does.
  */
-int __kprobes emulate_step(struct pt_regs *regs, unsigned int instr)
+int __kprobes analyse_instr(struct instruction_op *op, struct pt_regs *regs,
+                           unsigned int instr)
 {
        unsigned int opcode, ra, rb, rd, spr, u;
        unsigned long int imm;
        unsigned long int val, val2;
-       unsigned long int ea;
-       unsigned int cr, mb, me, sh;
-       int err;
-       unsigned long old_ra, val3;
+       unsigned int mb, me, sh;
        long ival;
 
+       op->type = COMPUTE;
+
        opcode = instr >> 26;
        switch (opcode) {
        case 16:        /* bc */
+               op->type = BRANCH;
                imm = (signed short)(instr & 0xfffc);
                if ((instr & 2) == 0)
                        imm += regs->nip;
@@ -659,26 +666,14 @@ int __kprobes emulate_step(struct pt_regs *regs, unsigned int instr)
                return 1;
 #ifdef CONFIG_PPC64
        case 17:        /* sc */
-               /*
-                * N.B. this uses knowledge about how the syscall
-                * entry code works.  If that is changed, this will
-                * need to be changed also.
-                */
-               if (regs->gpr[0] == 0x1ebe &&
-                   cpu_has_feature(CPU_FTR_REAL_LE)) {
-                       regs->msr ^= MSR_LE;
-                       goto instr_done;
-               }
-               regs->gpr[9] = regs->gpr[13];
-               regs->gpr[10] = MSR_KERNEL;
-               regs->gpr[11] = regs->nip + 4;
-               regs->gpr[12] = regs->msr & MSR_MASK;
-               regs->gpr[13] = (unsigned long) get_paca();
-               regs->nip = (unsigned long) &system_call_common;
-               regs->msr = MSR_KERNEL;
-               return 1;
+               if ((instr & 0xfe2) == 2)
+                       op->type = SYSCALL;
+               else
+                       op->type = UNKNOWN;
+               return 0;
 #endif
        case 18:        /* b */
+               op->type = BRANCH;
                imm = instr & 0x03fffffc;
                if (imm & 0x02000000)
                        imm -= 0x04000000;
@@ -691,8 +686,16 @@ int __kprobes emulate_step(struct pt_regs *regs, unsigned int instr)
                return 1;
        case 19:
                switch ((instr >> 1) & 0x3ff) {
+               case 0:         /* mcrf */
+                       rd = (instr >> 21) & 0x1c;
+                       ra = (instr >> 16) & 0x1c;
+                       val = (regs->ccr >> ra) & 0xf;
+                       regs->ccr = (regs->ccr & ~(0xfUL << rd)) | (val << rd);
+                       goto instr_done;
+
                case 16:        /* bclr */
                case 528:       /* bcctr */
+                       op->type = BRANCH;
                        imm = (instr & 0x400)? regs->ctr: regs->link;
                        regs->nip = truncate_if_32bit(regs->msr, regs->nip + 4);
                        imm = truncate_if_32bit(regs->msr, imm);
@@ -703,9 +706,13 @@ int __kprobes emulate_step(struct pt_regs *regs, unsigned int instr)
                        return 1;
 
                case 18:        /* rfid, scary */
-                       return -1;
+                       if (regs->msr & MSR_PR)
+                               goto priv;
+                       op->type = RFI;
+                       return 0;
 
                case 150:       /* isync */
+                       op->type = BARRIER;
                        isync();
                        goto instr_done;
 
@@ -731,6 +738,7 @@ int __kprobes emulate_step(struct pt_regs *regs, unsigned int instr)
        case 31:
                switch ((instr >> 1) & 0x3ff) {
                case 598:       /* sync */
+                       op->type = BARRIER;
 #ifdef __powerpc64__
                        switch ((instr >> 21) & 3) {
                        case 1:         /* lwsync */
@@ -745,6 +753,7 @@ int __kprobes emulate_step(struct pt_regs *regs, unsigned int instr)
                        goto instr_done;
 
                case 854:       /* eieio */
+                       op->type = BARRIER;
                        eieio();
                        goto instr_done;
                }
@@ -760,6 +769,17 @@ int __kprobes emulate_step(struct pt_regs *regs, unsigned int instr)
        rb = (instr >> 11) & 0x1f;
 
        switch (opcode) {
+#ifdef __powerpc64__
+       case 2:         /* tdi */
+               if (rd & trap_compare(regs->gpr[ra], (short) instr))
+                       goto trap;
+               goto instr_done;
+#endif
+       case 3:         /* twi */
+               if (rd & trap_compare((int)regs->gpr[ra], (short) instr))
+                       goto trap;
+               goto instr_done;
+
        case 7:         /* mulli */
                regs->gpr[rd] = regs->gpr[ra] * (short) instr;
                goto instr_done;
@@ -908,35 +928,44 @@ int __kprobes emulate_step(struct pt_regs *regs, unsigned int instr)
 
        case 31:
                switch ((instr >> 1) & 0x3ff) {
+               case 4:         /* tw */
+                       if (rd == 0x1f ||
+                           (rd & trap_compare((int)regs->gpr[ra],
+                                              (int)regs->gpr[rb])))
+                               goto trap;
+                       goto instr_done;
+#ifdef __powerpc64__
+               case 68:        /* td */
+                       if (rd & trap_compare(regs->gpr[ra], regs->gpr[rb]))
+                               goto trap;
+                       goto instr_done;
+#endif
                case 83:        /* mfmsr */
                        if (regs->msr & MSR_PR)
-                               break;
-                       regs->gpr[rd] = regs->msr & MSR_MASK;
-                       goto instr_done;
+                               goto priv;
+                       op->type = MFMSR;
+                       op->reg = rd;
+                       return 0;
                case 146:       /* mtmsr */
                        if (regs->msr & MSR_PR)
-                               break;
-                       imm = regs->gpr[rd];
-                       if ((imm & MSR_RI) == 0)
-                               /* can't step mtmsr that would clear MSR_RI */
-                               return -1;
-                       regs->msr = imm;
-                       goto instr_done;
+                               goto priv;
+                       op->type = MTMSR;
+                       op->reg = rd;
+                       op->val = 0xffffffff & ~(MSR_ME | MSR_LE);
+                       return 0;
 #ifdef CONFIG_PPC64
                case 178:       /* mtmsrd */
-                       /* only MSR_EE and MSR_RI get changed if bit 15 set */
-                       /* mtmsrd doesn't change MSR_HV and MSR_ME */
                        if (regs->msr & MSR_PR)
-                               break;
-                       imm = (instr & 0x10000)? 0x8002: 0xefffffffffffefffUL;
-                       imm = (regs->msr & MSR_MASK & ~imm)
-                               | (regs->gpr[rd] & imm);
-                       if ((imm & MSR_RI) == 0)
-                               /* can't step mtmsrd that would clear MSR_RI */
-                               return -1;
-                       regs->msr = imm;
-                       goto instr_done;
+                               goto priv;
+                       op->type = MTMSR;
+                       op->reg = rd;
+                       /* only MSR_EE and MSR_RI get changed if bit 15 set */
+                       /* mtmsrd doesn't change MSR_HV, MSR_ME or MSR_LE */
+                       imm = (instr & 0x10000)? 0x8002: 0xefffffffffffeffeUL;
+                       op->val = imm;
+                       return 0;
 #endif
+
                case 19:        /* mfcr */
                        regs->gpr[rd] = regs->ccr;
                        regs->gpr[rd] &= 0xffffffffUL;
@@ -954,33 +983,43 @@ int __kprobes emulate_step(struct pt_regs *regs, unsigned int instr)
                        goto instr_done;
 
                case 339:       /* mfspr */
-                       spr = (instr >> 11) & 0x3ff;
+                       spr = ((instr >> 16) & 0x1f) | ((instr >> 6) & 0x3e0);
                        switch (spr) {
-                       case 0x20:      /* mfxer */
+                       case SPRN_XER:  /* mfxer */
                                regs->gpr[rd] = regs->xer;
                                regs->gpr[rd] &= 0xffffffffUL;
                                goto instr_done;
-                       case 0x100:     /* mflr */
+                       case SPRN_LR:   /* mflr */
                                regs->gpr[rd] = regs->link;
                                goto instr_done;
-                       case 0x120:     /* mfctr */
+                       case SPRN_CTR:  /* mfctr */
                                regs->gpr[rd] = regs->ctr;
                                goto instr_done;
+                       default:
+                               op->type = MFSPR;
+                               op->reg = rd;
+                               op->spr = spr;
+                               return 0;
                        }
                        break;
 
                case 467:       /* mtspr */
-                       spr = (instr >> 11) & 0x3ff;
+                       spr = ((instr >> 16) & 0x1f) | ((instr >> 6) & 0x3e0);
                        switch (spr) {
-                       case 0x20:      /* mtxer */
+                       case SPRN_XER:  /* mtxer */
                                regs->xer = (regs->gpr[rd] & 0xffffffffUL);
                                goto instr_done;
-                       case 0x100:     /* mtlr */
+                       case SPRN_LR:   /* mtlr */
                                regs->link = regs->gpr[rd];
                                goto instr_done;
-                       case 0x120:     /* mtctr */
+                       case SPRN_CTR:  /* mtctr */
                                regs->ctr = regs->gpr[rd];
                                goto instr_done;
+                       default:
+                               op->type = MTSPR;
+                               op->val = regs->gpr[rd];
+                               op->spr = spr;
+                               return 0;
                        }
                        break;
 
@@ -1257,294 +1296,242 @@ int __kprobes emulate_step(struct pt_regs *regs, unsigned int instr)
  * Cache instructions
  */
                case 54:        /* dcbst */
-                       ea = xform_ea(instr, regs, 0);
-                       if (!address_ok(regs, ea, 8))
-                               return 0;
-                       err = 0;
-                       __cacheop_user_asmx(ea, err, "dcbst");
-                       if (err)
-                               return 0;
-                       goto instr_done;
+                       op->type = MKOP(CACHEOP, DCBST, 0);
+                       op->ea = xform_ea(instr, regs);
+                       return 0;
 
                case 86:        /* dcbf */
-                       ea = xform_ea(instr, regs, 0);
-                       if (!address_ok(regs, ea, 8))
-                               return 0;
-                       err = 0;
-                       __cacheop_user_asmx(ea, err, "dcbf");
-                       if (err)
-                               return 0;
-                       goto instr_done;
+                       op->type = MKOP(CACHEOP, DCBF, 0);
+                       op->ea = xform_ea(instr, regs);
+                       return 0;
 
                case 246:       /* dcbtst */
-                       if (rd == 0) {
-                               ea = xform_ea(instr, regs, 0);
-                               prefetchw((void *) ea);
-                       }
-                       goto instr_done;
+                       op->type = MKOP(CACHEOP, DCBTST, 0);
+                       op->ea = xform_ea(instr, regs);
+                       op->reg = rd;
+                       return 0;
 
                case 278:       /* dcbt */
-                       if (rd == 0) {
-                               ea = xform_ea(instr, regs, 0);
-                               prefetch((void *) ea);
-                       }
-                       goto instr_done;
+                       op->type = MKOP(CACHEOP, DCBTST, 0);
+                       op->ea = xform_ea(instr, regs);
+                       op->reg = rd;
+                       return 0;
 
+               case 982:       /* icbi */
+                       op->type = MKOP(CACHEOP, ICBI, 0);
+                       op->ea = xform_ea(instr, regs);
+                       return 0;
                }
                break;
        }
 
        /*
-        * Following cases are for loads and stores, so bail out
-        * if we're in little-endian mode.
+        * Loads and stores.
         */
-       if (regs->msr & MSR_LE)
-               return 0;
-
-       /*
-        * Save register RA in case it's an update form load or store
-        * and the access faults.
-        */
-       old_ra = regs->gpr[ra];
+       op->type = UNKNOWN;
+       op->update_reg = ra;
+       op->reg = rd;
+       op->val = regs->gpr[rd];
+       u = (instr >> 20) & UPDATE;
 
        switch (opcode) {
        case 31:
-               u = instr & 0x40;
+               u = instr & UPDATE;
+               op->ea = xform_ea(instr, regs);
                switch ((instr >> 1) & 0x3ff) {
                case 20:        /* lwarx */
-                       ea = xform_ea(instr, regs, 0);
-                       if (ea & 3)
-                               break;          /* can't handle misaligned */
-                       err = -EFAULT;
-                       if (!address_ok(regs, ea, 4))
-                               goto ldst_done;
-                       err = 0;
-                       __get_user_asmx(val, ea, err, "lwarx");
-                       if (!err)
-                               regs->gpr[rd] = val;
-                       goto ldst_done;
+                       op->type = MKOP(LARX, 0, 4);
+                       break;
 
                case 150:       /* stwcx. */
-                       ea = xform_ea(instr, regs, 0);
-                       if (ea & 3)
-                               break;          /* can't handle misaligned */
-                       err = -EFAULT;
-                       if (!address_ok(regs, ea, 4))
-                               goto ldst_done;
-                       err = 0;
-                       __put_user_asmx(regs->gpr[rd], ea, err, "stwcx.", cr);
-                       if (!err)
-                               regs->ccr = (regs->ccr & 0x0fffffff) |
-                                       (cr & 0xe0000000) |
-                                       ((regs->xer >> 3) & 0x10000000);
-                       goto ldst_done;
+                       op->type = MKOP(STCX, 0, 4);
+                       break;
 
 #ifdef __powerpc64__
                case 84:        /* ldarx */
-                       ea = xform_ea(instr, regs, 0);
-                       if (ea & 7)
-                               break;          /* can't handle misaligned */
-                       err = -EFAULT;
-                       if (!address_ok(regs, ea, 8))
-                               goto ldst_done;
-                       err = 0;
-                       __get_user_asmx(val, ea, err, "ldarx");
-                       if (!err)
-                               regs->gpr[rd] = val;
-                       goto ldst_done;
+                       op->type = MKOP(LARX, 0, 8);
+                       break;
 
                case 214:       /* stdcx. */
-                       ea = xform_ea(instr, regs, 0);
-                       if (ea & 7)
-                               break;          /* can't handle misaligned */
-                       err = -EFAULT;
-                       if (!address_ok(regs, ea, 8))
-                               goto ldst_done;
-                       err = 0;
-                       __put_user_asmx(regs->gpr[rd], ea, err, "stdcx.", cr);
-                       if (!err)
-                               regs->ccr = (regs->ccr & 0x0fffffff) |
-                                       (cr & 0xe0000000) |
-                                       ((regs->xer >> 3) & 0x10000000);
-                       goto ldst_done;
+                       op->type = MKOP(STCX, 0, 8);
+                       break;
 
                case 21:        /* ldx */
                case 53:        /* ldux */
-                       err = read_mem(&regs->gpr[rd], xform_ea(instr, regs, u),
-                                      8, regs);
-                       goto ldst_done;
+                       op->type = MKOP(LOAD, u, 8);
+                       break;
 #endif
 
                case 23:        /* lwzx */
                case 55:        /* lwzux */
-                       err = read_mem(&regs->gpr[rd], xform_ea(instr, regs, u),
-                                      4, regs);
-                       goto ldst_done;
+                       op->type = MKOP(LOAD, u, 4);
+                       break;
 
                case 87:        /* lbzx */
                case 119:       /* lbzux */
-                       err = read_mem(&regs->gpr[rd], xform_ea(instr, regs, u),
-                                      1, regs);
-                       goto ldst_done;
+                       op->type = MKOP(LOAD, u, 1);
+                       break;
 
 #ifdef CONFIG_ALTIVEC
                case 103:       /* lvx */
                case 359:       /* lvxl */
                        if (!(regs->msr & MSR_VEC))
-                               break;
-                       ea = xform_ea(instr, regs, 0);
-                       err = do_vec_load(rd, do_lvx, ea, regs);
-                       goto ldst_done;
+                               goto vecunavail;
+                       op->type = MKOP(LOAD_VMX, 0, 16);
+                       break;
 
                case 231:       /* stvx */
                case 487:       /* stvxl */
                        if (!(regs->msr & MSR_VEC))
-                               break;
-                       ea = xform_ea(instr, regs, 0);
-                       err = do_vec_store(rd, do_stvx, ea, regs);
-                       goto ldst_done;
+                               goto vecunavail;
+                       op->type = MKOP(STORE_VMX, 0, 16);
+                       break;
 #endif /* CONFIG_ALTIVEC */
 
 #ifdef __powerpc64__
                case 149:       /* stdx */
                case 181:       /* stdux */
-                       val = regs->gpr[rd];
-                       err = write_mem(val, xform_ea(instr, regs, u), 8, regs);
-                       goto ldst_done;
+                       op->type = MKOP(STORE, u, 8);
+                       break;
 #endif
 
                case 151:       /* stwx */
                case 183:       /* stwux */
-                       val = regs->gpr[rd];
-                       err = write_mem(val, xform_ea(instr, regs, u), 4, regs);
-                       goto ldst_done;
+                       op->type = MKOP(STORE, u, 4);
+                       break;
 
                case 215:       /* stbx */
                case 247:       /* stbux */
-                       val = regs->gpr[rd];
-                       err = write_mem(val, xform_ea(instr, regs, u), 1, regs);
-                       goto ldst_done;
+                       op->type = MKOP(STORE, u, 1);
+                       break;
 
                case 279:       /* lhzx */
                case 311:       /* lhzux */
-                       err = read_mem(&regs->gpr[rd], xform_ea(instr, regs, u),
-                                      2, regs);
-                       goto ldst_done;
+                       op->type = MKOP(LOAD, u, 2);
+                       break;
 
 #ifdef __powerpc64__
                case 341:       /* lwax */
                case 373:       /* lwaux */
-                       err = read_mem(&regs->gpr[rd], xform_ea(instr, regs, u),
-                                      4, regs);
-                       if (!err)
-                               regs->gpr[rd] = (signed int) regs->gpr[rd];
-                       goto ldst_done;
+                       op->type = MKOP(LOAD, SIGNEXT | u, 4);
+                       break;
 #endif
 
                case 343:       /* lhax */
                case 375:       /* lhaux */
-                       err = read_mem(&regs->gpr[rd], xform_ea(instr, regs, u),
-                                      2, regs);
-                       if (!err)
-                               regs->gpr[rd] = (signed short) regs->gpr[rd];
-                       goto ldst_done;
+                       op->type = MKOP(LOAD, SIGNEXT | u, 2);
+                       break;
 
                case 407:       /* sthx */
                case 439:       /* sthux */
-                       val = regs->gpr[rd];
-                       err = write_mem(val, xform_ea(instr, regs, u), 2, regs);
-                       goto ldst_done;
+                       op->type = MKOP(STORE, u, 2);
+                       break;
 
 #ifdef __powerpc64__
                case 532:       /* ldbrx */
-                       err = read_mem(&val, xform_ea(instr, regs, 0), 8, regs);
-                       if (!err)
-                               regs->gpr[rd] = byterev_8(val);
-                       goto ldst_done;
+                       op->type = MKOP(LOAD, BYTEREV, 8);
+                       break;
 
 #endif
+               case 533:       /* lswx */
+                       op->type = MKOP(LOAD_MULTI, 0, regs->xer & 0x7f);
+                       break;
 
                case 534:       /* lwbrx */
-                       err = read_mem(&val, xform_ea(instr, regs, 0), 4, regs);
-                       if (!err)
-                               regs->gpr[rd] = byterev_4(val);
-                       goto ldst_done;
+                       op->type = MKOP(LOAD, BYTEREV, 4);
+                       break;
+
+               case 597:       /* lswi */
+                       if (rb == 0)
+                               rb = 32;        /* # bytes to load */
+                       op->type = MKOP(LOAD_MULTI, 0, rb);
+                       op->ea = 0;
+                       if (ra)
+                               op->ea = truncate_if_32bit(regs->msr,
+                                                          regs->gpr[ra]);
+                       break;
 
 #ifdef CONFIG_PPC_FPU
                case 535:       /* lfsx */
                case 567:       /* lfsux */
                        if (!(regs->msr & MSR_FP))
-                               break;
-                       ea = xform_ea(instr, regs, u);
-                       err = do_fp_load(rd, do_lfs, ea, 4, regs);
-                       goto ldst_done;
+                               goto fpunavail;
+                       op->type = MKOP(LOAD_FP, u, 4);
+                       break;
 
                case 599:       /* lfdx */
                case 631:       /* lfdux */
                        if (!(regs->msr & MSR_FP))
-                               break;
-                       ea = xform_ea(instr, regs, u);
-                       err = do_fp_load(rd, do_lfd, ea, 8, regs);
-                       goto ldst_done;
+                               goto fpunavail;
+                       op->type = MKOP(LOAD_FP, u, 8);
+                       break;
 
                case 663:       /* stfsx */
                case 695:       /* stfsux */
                        if (!(regs->msr & MSR_FP))
-                               break;
-                       ea = xform_ea(instr, regs, u);
-                       err = do_fp_store(rd, do_stfs, ea, 4, regs);
-                       goto ldst_done;
+                               goto fpunavail;
+                       op->type = MKOP(STORE_FP, u, 4);
+                       break;
 
                case 727:       /* stfdx */
                case 759:       /* stfdux */
                        if (!(regs->msr & MSR_FP))
-                               break;
-                       ea = xform_ea(instr, regs, u);
-                       err = do_fp_store(rd, do_stfd, ea, 8, regs);
-                       goto ldst_done;
+                               goto fpunavail;
+                       op->type = MKOP(STORE_FP, u, 8);
+                       break;
 #endif
 
 #ifdef __powerpc64__
                case 660:       /* stdbrx */
-                       val = byterev_8(regs->gpr[rd]);
-                       err = write_mem(val, xform_ea(instr, regs, 0), 8, regs);
-                       goto ldst_done;
+                       op->type = MKOP(STORE, BYTEREV, 8);
+                       op->val = byterev_8(regs->gpr[rd]);
+                       break;
 
 #endif
+               case 661:       /* stswx */
+                       op->type = MKOP(STORE_MULTI, 0, regs->xer & 0x7f);
+                       break;
+
                case 662:       /* stwbrx */
-                       val = byterev_4(regs->gpr[rd]);
-                       err = write_mem(val, xform_ea(instr, regs, 0), 4, regs);
-                       goto ldst_done;
+                       op->type = MKOP(STORE, BYTEREV, 4);
+                       op->val = byterev_4(regs->gpr[rd]);
+                       break;
+
+               case 725:
+                       if (rb == 0)
+                               rb = 32;        /* # bytes to store */
+                       op->type = MKOP(STORE_MULTI, 0, rb);
+                       op->ea = 0;
+                       if (ra)
+                               op->ea = truncate_if_32bit(regs->msr,
+                                                          regs->gpr[ra]);
+                       break;
 
                case 790:       /* lhbrx */
-                       err = read_mem(&val, xform_ea(instr, regs, 0), 2, regs);
-                       if (!err)
-                               regs->gpr[rd] = byterev_2(val);
-                       goto ldst_done;
+                       op->type = MKOP(LOAD, BYTEREV, 2);
+                       break;
 
                case 918:       /* sthbrx */
-                       val = byterev_2(regs->gpr[rd]);
-                       err = write_mem(val, xform_ea(instr, regs, 0), 2, regs);
-                       goto ldst_done;
+                       op->type = MKOP(STORE, BYTEREV, 2);
+                       op->val = byterev_2(regs->gpr[rd]);
+                       break;
 
 #ifdef CONFIG_VSX
                case 844:       /* lxvd2x */
                case 876:       /* lxvd2ux */
                        if (!(regs->msr & MSR_VSX))
-                               break;
-                       rd |= (instr & 1) << 5;
-                       ea = xform_ea(instr, regs, u);
-                       err = do_vsx_load(rd, do_lxvd2x, ea, regs);
-                       goto ldst_done;
+                               goto vsxunavail;
+                       op->reg = rd | ((instr & 1) << 5);
+                       op->type = MKOP(LOAD_VSX, u, 16);
+                       break;
 
                case 972:       /* stxvd2x */
                case 1004:      /* stxvd2ux */
                        if (!(regs->msr & MSR_VSX))
-                               break;
-                       rd |= (instr & 1) << 5;
-                       ea = xform_ea(instr, regs, u);
-                       err = do_vsx_store(rd, do_stxvd2x, ea, regs);
-                       goto ldst_done;
+                               goto vsxunavail;
+                       op->reg = rd | ((instr & 1) << 5);
+                       op->type = MKOP(STORE_VSX, u, 16);
+                       break;
 
 #endif /* CONFIG_VSX */
                }
@@ -1552,178 +1539,123 @@ int __kprobes emulate_step(struct pt_regs *regs, unsigned int instr)
 
        case 32:        /* lwz */
        case 33:        /* lwzu */
-               err = read_mem(&regs->gpr[rd], dform_ea(instr, regs), 4, regs);
-               goto ldst_done;
+               op->type = MKOP(LOAD, u, 4);
+               op->ea = dform_ea(instr, regs);
+               break;
 
        case 34:        /* lbz */
        case 35:        /* lbzu */
-               err = read_mem(&regs->gpr[rd], dform_ea(instr, regs), 1, regs);
-               goto ldst_done;
+               op->type = MKOP(LOAD, u, 1);
+               op->ea = dform_ea(instr, regs);
+               break;
 
        case 36:        /* stw */
-               val = regs->gpr[rd];
-               err = write_mem(val, dform_ea(instr, regs), 4, regs);
-               goto ldst_done;
-
        case 37:        /* stwu */
-               val = regs->gpr[rd];
-               val3 = dform_ea(instr, regs);
-               /*
-                * For PPC32 we always use stwu to change stack point with r1. So
-                * this emulated store may corrupt the exception frame, now we
-                * have to provide the exception frame trampoline, which is pushed
-                * below the kprobed function stack. So we only update gpr[1] but
-                * don't emulate the real store operation. We will do real store
-                * operation safely in exception return code by checking this flag.
-                */
-               if ((ra == 1) && !(regs->msr & MSR_PR) \
-                       && (val3 >= (regs->gpr[1] - STACK_INT_FRAME_SIZE))) {
-#ifdef CONFIG_PPC32
-                       /*
-                        * Check if we will touch kernel sack overflow
-                        */
-                       if (val3 - STACK_INT_FRAME_SIZE <= current->thread.ksp_limit) {
-                               printk(KERN_CRIT "Can't kprobe this since Kernel stack overflow.\n");
-                               err = -EINVAL;
-                               break;
-                       }
-#endif /* CONFIG_PPC32 */
-                       /*
-                        * Check if we already set since that means we'll
-                        * lose the previous value.
-                        */
-                       WARN_ON(test_thread_flag(TIF_EMULATE_STACK_STORE));
-                       set_thread_flag(TIF_EMULATE_STACK_STORE);
-                       err = 0;
-               } else
-                       err = write_mem(val, val3, 4, regs);
-               goto ldst_done;
+               op->type = MKOP(STORE, u, 4);
+               op->ea = dform_ea(instr, regs);
+               break;
 
        case 38:        /* stb */
        case 39:        /* stbu */
-               val = regs->gpr[rd];
-               err = write_mem(val, dform_ea(instr, regs), 1, regs);
-               goto ldst_done;
+               op->type = MKOP(STORE, u, 1);
+               op->ea = dform_ea(instr, regs);
+               break;
 
        case 40:        /* lhz */
        case 41:        /* lhzu */
-               err = read_mem(&regs->gpr[rd], dform_ea(instr, regs), 2, regs);
-               goto ldst_done;
+               op->type = MKOP(LOAD, u, 2);
+               op->ea = dform_ea(instr, regs);
+               break;
 
        case 42:        /* lha */
        case 43:        /* lhau */
-               err = read_mem(&regs->gpr[rd], dform_ea(instr, regs), 2, regs);
-               if (!err)
-                       regs->gpr[rd] = (signed short) regs->gpr[rd];
-               goto ldst_done;
+               op->type = MKOP(LOAD, SIGNEXT | u, 2);
+               op->ea = dform_ea(instr, regs);
+               break;
 
        case 44:        /* sth */
        case 45:        /* sthu */
-               val = regs->gpr[rd];
-               err = write_mem(val, dform_ea(instr, regs), 2, regs);
-               goto ldst_done;
+               op->type = MKOP(STORE, u, 2);
+               op->ea = dform_ea(instr, regs);
+               break;
 
        case 46:        /* lmw */
-               ra = (instr >> 16) & 0x1f;
                if (ra >= rd)
                        break;          /* invalid form, ra in range to load */
-               ea = dform_ea(instr, regs);
-               do {
-                       err = read_mem(&regs->gpr[rd], ea, 4, regs);
-                       if (err)
-                               return 0;
-                       ea += 4;
-               } while (++rd < 32);
-               goto instr_done;
+               op->type = MKOP(LOAD_MULTI, 0, 4 * (32 - rd));
+               op->ea = dform_ea(instr, regs);
+               break;
 
        case 47:        /* stmw */
-               ea = dform_ea(instr, regs);
-               do {
-                       err = write_mem(regs->gpr[rd], ea, 4, regs);
-                       if (err)
-                               return 0;
-                       ea += 4;
-               } while (++rd < 32);
-               goto instr_done;
+               op->type = MKOP(STORE_MULTI, 0, 4 * (32 - rd));
+               op->ea = dform_ea(instr, regs);
+               break;
 
 #ifdef CONFIG_PPC_FPU
        case 48:        /* lfs */
        case 49:        /* lfsu */
                if (!(regs->msr & MSR_FP))
-                       break;
-               ea = dform_ea(instr, regs);
-               err = do_fp_load(rd, do_lfs, ea, 4, regs);
-               goto ldst_done;
+                       goto fpunavail;
+               op->type = MKOP(LOAD_FP, u, 4);
+               op->ea = dform_ea(instr, regs);
+               break;
 
        case 50:        /* lfd */
        case 51:        /* lfdu */
                if (!(regs->msr & MSR_FP))
-                       break;
-               ea = dform_ea(instr, regs);
-               err = do_fp_load(rd, do_lfd, ea, 8, regs);
-               goto ldst_done;
+                       goto fpunavail;
+               op->type = MKOP(LOAD_FP, u, 8);
+               op->ea = dform_ea(instr, regs);
+               break;
 
        case 52:        /* stfs */
        case 53:        /* stfsu */
                if (!(regs->msr & MSR_FP))
-                       break;
-               ea = dform_ea(instr, regs);
-               err = do_fp_store(rd, do_stfs, ea, 4, regs);
-               goto ldst_done;
+                       goto fpunavail;
+               op->type = MKOP(STORE_FP, u, 4);
+               op->ea = dform_ea(instr, regs);
+               break;
 
        case 54:        /* stfd */
        case 55:        /* stfdu */
                if (!(regs->msr & MSR_FP))
-                       break;
-               ea = dform_ea(instr, regs);
-               err = do_fp_store(rd, do_stfd, ea, 8, regs);
-               goto ldst_done;
+                       goto fpunavail;
+               op->type = MKOP(STORE_FP, u, 8);
+               op->ea = dform_ea(instr, regs);
+               break;
 #endif
 
 #ifdef __powerpc64__
        case 58:        /* ld[u], lwa */
+               op->ea = dsform_ea(instr, regs);
                switch (instr & 3) {
                case 0:         /* ld */
-                       err = read_mem(&regs->gpr[rd], dsform_ea(instr, regs),
-                                      8, regs);
-                       goto ldst_done;
+                       op->type = MKOP(LOAD, 0, 8);
+                       break;
                case 1:         /* ldu */
-                       err = read_mem(&regs->gpr[rd], dsform_ea(instr, regs),
-                                      8, regs);
-                       goto ldst_done;
+                       op->type = MKOP(LOAD, UPDATE, 8);
+                       break;
                case 2:         /* lwa */
-                       err = read_mem(&regs->gpr[rd], dsform_ea(instr, regs),
-                                      4, regs);
-                       if (!err)
-                               regs->gpr[rd] = (signed int) regs->gpr[rd];
-                       goto ldst_done;
+                       op->type = MKOP(LOAD, SIGNEXT, 4);
+                       break;
                }
                break;
 
        case 62:        /* std[u] */
-               val = regs->gpr[rd];
+               op->ea = dsform_ea(instr, regs);
                switch (instr & 3) {
                case 0:         /* std */
-                       err = write_mem(val, dsform_ea(instr, regs), 8, regs);
-                       goto ldst_done;
+                       op->type = MKOP(STORE, 0, 8);
+                       break;
                case 1:         /* stdu */
-                       err = write_mem(val, dsform_ea(instr, regs), 8, regs);
-                       goto ldst_done;
+                       op->type = MKOP(STORE, UPDATE, 8);
+                       break;
                }
                break;
 #endif /* __powerpc64__ */
 
        }
-       err = -EINVAL;
-
- ldst_done:
-       if (err) {
-               regs->gpr[ra] = old_ra;
-               return 0;       /* invoke DSI if -EFAULT? */
-       }
- instr_done:
-       regs->nip = truncate_if_32bit(regs->msr, regs->nip + 4);
-       return 1;
+       return 0;
 
  logical_done:
        if (instr & 1)
@@ -1733,5 +1665,349 @@ int __kprobes emulate_step(struct pt_regs *regs, unsigned int instr)
  arith_done:
        if (instr & 1)
                set_cr0(regs, rd);
-       goto instr_done;
+
+ instr_done:
+       regs->nip = truncate_if_32bit(regs->msr, regs->nip + 4);
+       return 1;
+
+ priv:
+       op->type = INTERRUPT | 0x700;
+       op->val = SRR1_PROGPRIV;
+       return 0;
+
+ trap:
+       op->type = INTERRUPT | 0x700;
+       op->val = SRR1_PROGTRAP;
+       return 0;
+
+#ifdef CONFIG_PPC_FPU
+ fpunavail:
+       op->type = INTERRUPT | 0x800;
+       return 0;
+#endif
+
+#ifdef CONFIG_ALTIVEC
+ vecunavail:
+       op->type = INTERRUPT | 0xf20;
+       return 0;
+#endif
+
+#ifdef CONFIG_VSX
+ vsxunavail:
+       op->type = INTERRUPT | 0xf40;
+       return 0;
+#endif
+}
+EXPORT_SYMBOL_GPL(analyse_instr);
+
+/*
+ * For PPC32 we always use stwu with r1 to change the stack pointer.
+ * So this emulated store may corrupt the exception frame, now we
+ * have to provide the exception frame trampoline, which is pushed
+ * below the kprobed function stack. So we only update gpr[1] but
+ * don't emulate the real store operation. We will do real store
+ * operation safely in exception return code by checking this flag.
+ */
+static __kprobes int handle_stack_update(unsigned long ea, struct pt_regs *regs)
+{
+#ifdef CONFIG_PPC32
+       /*
+        * Check if we will touch kernel stack overflow
+        */
+       if (ea - STACK_INT_FRAME_SIZE <= current->thread.ksp_limit) {
+               printk(KERN_CRIT "Can't kprobe this since kernel stack would overflow.\n");
+               return -EINVAL;
+       }
+#endif /* CONFIG_PPC32 */
+       /*
+        * Check if we already set since that means we'll
+        * lose the previous value.
+        */
+       WARN_ON(test_thread_flag(TIF_EMULATE_STACK_STORE));
+       set_thread_flag(TIF_EMULATE_STACK_STORE);
+       return 0;
+}
+
+static __kprobes void do_signext(unsigned long *valp, int size)
+{
+       switch (size) {
+       case 2:
+               *valp = (signed short) *valp;
+               break;
+       case 4:
+               *valp = (signed int) *valp;
+               break;
+       }
+}
+
+static __kprobes void do_byterev(unsigned long *valp, int size)
+{
+       switch (size) {
+       case 2:
+               *valp = byterev_2(*valp);
+               break;
+       case 4:
+               *valp = byterev_4(*valp);
+               break;
+#ifdef __powerpc64__
+       case 8:
+               *valp = byterev_8(*valp);
+               break;
+#endif
+       }
+}
+
+/*
+ * Emulate instructions that cause a transfer of control,
+ * loads and stores, and a few other instructions.
+ * Returns 1 if the step was emulated, 0 if not,
+ * or -1 if the instruction is one that should not be stepped,
+ * such as an rfid, or a mtmsrd that would clear MSR_RI.
+ */
+int __kprobes emulate_step(struct pt_regs *regs, unsigned int instr)
+{
+       struct instruction_op op;
+       int r, err, size;
+       unsigned long val;
+       unsigned int cr;
+       int i, rd, nb;
+
+       r = analyse_instr(&op, regs, instr);
+       if (r != 0)
+               return r;
+
+       err = 0;
+       size = GETSIZE(op.type);
+       switch (op.type & INSTR_TYPE_MASK) {
+       case CACHEOP:
+               if (!address_ok(regs, op.ea, 8))
+                       return 0;
+               switch (op.type & CACHEOP_MASK) {
+               case DCBST:
+                       __cacheop_user_asmx(op.ea, err, "dcbst");
+                       break;
+               case DCBF:
+                       __cacheop_user_asmx(op.ea, err, "dcbf");
+                       break;
+               case DCBTST:
+                       if (op.reg == 0)
+                               prefetchw((void *) op.ea);
+                       break;
+               case DCBT:
+                       if (op.reg == 0)
+                               prefetch((void *) op.ea);
+                       break;
+               case ICBI:
+                       __cacheop_user_asmx(op.ea, err, "icbi");
+                       break;
+               }
+               if (err)
+                       return 0;
+               goto instr_done;
+
+       case LARX:
+               if (regs->msr & MSR_LE)
+                       return 0;
+               if (op.ea & (size - 1))
+                       break;          /* can't handle misaligned */
+               err = -EFAULT;
+               if (!address_ok(regs, op.ea, size))
+                       goto ldst_done;
+               err = 0;
+               switch (size) {
+               case 4:
+                       __get_user_asmx(val, op.ea, err, "lwarx");
+                       break;
+               case 8:
+                       __get_user_asmx(val, op.ea, err, "ldarx");
+                       break;
+               default:
+                       return 0;
+               }
+               if (!err)
+                       regs->gpr[op.reg] = val;
+               goto ldst_done;
+
+       case STCX:
+               if (regs->msr & MSR_LE)
+                       return 0;
+               if (op.ea & (size - 1))
+                       break;          /* can't handle misaligned */
+               err = -EFAULT;
+               if (!address_ok(regs, op.ea, size))
+                       goto ldst_done;
+               err = 0;
+               switch (size) {
+               case 4:
+                       __put_user_asmx(op.val, op.ea, err, "stwcx.", cr);
+                       break;
+               case 8:
+                       __put_user_asmx(op.val, op.ea, err, "stdcx.", cr);
+                       break;
+               default:
+                       return 0;
+               }
+               if (!err)
+                       regs->ccr = (regs->ccr & 0x0fffffff) |
+                               (cr & 0xe0000000) |
+                               ((regs->xer >> 3) & 0x10000000);
+               goto ldst_done;
+
+       case LOAD:
+               if (regs->msr & MSR_LE)
+                       return 0;
+               err = read_mem(&regs->gpr[op.reg], op.ea, size, regs);
+               if (!err) {
+                       if (op.type & SIGNEXT)
+                               do_signext(&regs->gpr[op.reg], size);
+                       if (op.type & BYTEREV)
+                               do_byterev(&regs->gpr[op.reg], size);
+               }
+               goto ldst_done;
+
+       case LOAD_FP:
+               if (regs->msr & MSR_LE)
+                       return 0;
+               if (size == 4)
+                       err = do_fp_load(op.reg, do_lfs, op.ea, size, regs);
+               else
+                       err = do_fp_load(op.reg, do_lfd, op.ea, size, regs);
+               goto ldst_done;
+
+#ifdef CONFIG_ALTIVEC
+       case LOAD_VMX:
+               if (regs->msr & MSR_LE)
+                       return 0;
+               err = do_vec_load(op.reg, do_lvx, op.ea & ~0xfUL, regs);
+               goto ldst_done;
+#endif
+#ifdef CONFIG_VSX
+       case LOAD_VSX:
+               if (regs->msr & MSR_LE)
+                       return 0;
+               err = do_vsx_load(op.reg, do_lxvd2x, op.ea, regs);
+               goto ldst_done;
+#endif
+       case LOAD_MULTI:
+               if (regs->msr & MSR_LE)
+                       return 0;
+               rd = op.reg;
+               for (i = 0; i < size; i += 4) {
+                       nb = size - i;
+                       if (nb > 4)
+                               nb = 4;
+                       err = read_mem(&regs->gpr[rd], op.ea, nb, regs);
+                       if (err)
+                               return 0;
+                       if (nb < 4)     /* left-justify last bytes */
+                               regs->gpr[rd] <<= 32 - 8 * nb;
+                       op.ea += 4;
+                       ++rd;
+               }
+               goto instr_done;
+
+       case STORE:
+               if (regs->msr & MSR_LE)
+                       return 0;
+               if ((op.type & UPDATE) && size == sizeof(long) &&
+                   op.reg == 1 && op.update_reg == 1 &&
+                   !(regs->msr & MSR_PR) &&
+                   op.ea >= regs->gpr[1] - STACK_INT_FRAME_SIZE) {
+                       err = handle_stack_update(op.ea, regs);
+                       goto ldst_done;
+               }
+               err = write_mem(op.val, op.ea, size, regs);
+               goto ldst_done;
+
+       case STORE_FP:
+               if (regs->msr & MSR_LE)
+                       return 0;
+               if (size == 4)
+                       err = do_fp_store(op.reg, do_stfs, op.ea, size, regs);
+               else
+                       err = do_fp_store(op.reg, do_stfd, op.ea, size, regs);
+               goto ldst_done;
+
+#ifdef CONFIG_ALTIVEC
+       case STORE_VMX:
+               if (regs->msr & MSR_LE)
+                       return 0;
+               err = do_vec_store(op.reg, do_stvx, op.ea & ~0xfUL, regs);
+               goto ldst_done;
+#endif
+#ifdef CONFIG_VSX
+       case STORE_VSX:
+               if (regs->msr & MSR_LE)
+                       return 0;
+               err = do_vsx_store(op.reg, do_stxvd2x, op.ea, regs);
+               goto ldst_done;
+#endif
+       case STORE_MULTI:
+               if (regs->msr & MSR_LE)
+                       return 0;
+               rd = op.reg;
+               for (i = 0; i < size; i += 4) {
+                       val = regs->gpr[rd];
+                       nb = size - i;
+                       if (nb > 4)
+                               nb = 4;
+                       else
+                               val >>= 32 - 8 * nb;
+                       err = write_mem(val, op.ea, nb, regs);
+                       if (err)
+                               return 0;
+                       op.ea += 4;
+                       ++rd;
+               }
+               goto instr_done;
+
+       case MFMSR:
+               regs->gpr[op.reg] = regs->msr & MSR_MASK;
+               goto instr_done;
+
+       case MTMSR:
+               val = regs->gpr[op.reg];
+               if ((val & MSR_RI) == 0)
+                       /* can't step mtmsr[d] that would clear MSR_RI */
+                       return -1;
+               /* here op.val is the mask of bits to change */
+               regs->msr = (regs->msr & ~op.val) | (val & op.val);
+               goto instr_done;
+
+#ifdef CONFIG_PPC64
+       case SYSCALL:   /* sc */
+               /*
+                * N.B. this uses knowledge about how the syscall
+                * entry code works.  If that is changed, this will
+                * need to be changed also.
+                */
+               if (regs->gpr[0] == 0x1ebe &&
+                   cpu_has_feature(CPU_FTR_REAL_LE)) {
+                       regs->msr ^= MSR_LE;
+                       goto instr_done;
+               }
+               regs->gpr[9] = regs->gpr[13];
+               regs->gpr[10] = MSR_KERNEL;
+               regs->gpr[11] = regs->nip + 4;
+               regs->gpr[12] = regs->msr & MSR_MASK;
+               regs->gpr[13] = (unsigned long) get_paca();
+               regs->nip = (unsigned long) &system_call_common;
+               regs->msr = MSR_KERNEL;
+               return 1;
+
+       case RFI:
+               return -1;
+#endif
+       }
+       return 0;
+
+ ldst_done:
+       if (err)
+               return 0;
+       if (op.type & UPDATE)
+               regs->gpr[op.update_reg] = op.ea;
+
+ instr_done:
+       regs->nip = truncate_if_32bit(regs->msr, regs->nip + 4);
+       return 1;
 }
index d0130fff20e532791fec298cd07ad16e59b010b1..325e861616a175b65e72db96514d2f84e087d3d3 100644 (file)
@@ -34,3 +34,4 @@ obj-$(CONFIG_TRANSPARENT_HUGEPAGE) += hugepage-hash64.o
 obj-$(CONFIG_PPC_SUBPAGE_PROT) += subpage-prot.o
 obj-$(CONFIG_NOT_COHERENT_CACHE) += dma-noncoherent.o
 obj-$(CONFIG_HIGHMEM)          += highmem.o
+obj-$(CONFIG_PPC_COPRO_BASE)   += copro_fault.o
diff --git a/arch/powerpc/mm/copro_fault.c b/arch/powerpc/mm/copro_fault.c
new file mode 100644 (file)
index 0000000..0f9939e
--- /dev/null
@@ -0,0 +1,149 @@
+/*
+ * CoProcessor (SPU/AFU) mm fault handler
+ *
+ * (C) Copyright IBM Deutschland Entwicklung GmbH 2007
+ *
+ * Author: Arnd Bergmann <arndb@de.ibm.com>
+ * Author: Jeremy Kerr <jk@ozlabs.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/export.h>
+#include <asm/reg.h>
+#include <asm/copro.h>
+#include <asm/spu.h>
+#include <misc/cxl.h>
+
+/*
+ * This ought to be kept in sync with the powerpc specific do_page_fault
+ * function. Currently, there are a few corner cases that we haven't had
+ * to handle fortunately.
+ */
+int copro_handle_mm_fault(struct mm_struct *mm, unsigned long ea,
+               unsigned long dsisr, unsigned *flt)
+{
+       struct vm_area_struct *vma;
+       unsigned long is_write;
+       int ret;
+
+       if (mm == NULL)
+               return -EFAULT;
+
+       if (mm->pgd == NULL)
+               return -EFAULT;
+
+       down_read(&mm->mmap_sem);
+       ret = -EFAULT;
+       vma = find_vma(mm, ea);
+       if (!vma)
+               goto out_unlock;
+
+       if (ea < vma->vm_start) {
+               if (!(vma->vm_flags & VM_GROWSDOWN))
+                       goto out_unlock;
+               if (expand_stack(vma, ea))
+                       goto out_unlock;
+       }
+
+       is_write = dsisr & DSISR_ISSTORE;
+       if (is_write) {
+               if (!(vma->vm_flags & VM_WRITE))
+                       goto out_unlock;
+       } else {
+               if (dsisr & DSISR_PROTFAULT)
+                       goto out_unlock;
+               if (!(vma->vm_flags & (VM_READ | VM_EXEC)))
+                       goto out_unlock;
+       }
+
+       ret = 0;
+       *flt = handle_mm_fault(mm, vma, ea, is_write ? FAULT_FLAG_WRITE : 0);
+       if (unlikely(*flt & VM_FAULT_ERROR)) {
+               if (*flt & VM_FAULT_OOM) {
+                       ret = -ENOMEM;
+                       goto out_unlock;
+               } else if (*flt & VM_FAULT_SIGBUS) {
+                       ret = -EFAULT;
+                       goto out_unlock;
+               }
+               BUG();
+       }
+
+       if (*flt & VM_FAULT_MAJOR)
+               current->maj_flt++;
+       else
+               current->min_flt++;
+
+out_unlock:
+       up_read(&mm->mmap_sem);
+       return ret;
+}
+EXPORT_SYMBOL_GPL(copro_handle_mm_fault);
+
+int copro_calculate_slb(struct mm_struct *mm, u64 ea, struct copro_slb *slb)
+{
+       u64 vsid;
+       int psize, ssize;
+
+       slb->esid = (ea & ESID_MASK) | SLB_ESID_V;
+
+       switch (REGION_ID(ea)) {
+       case USER_REGION_ID:
+               pr_devel("%s: 0x%llx -- USER_REGION_ID\n", __func__, ea);
+               psize = get_slice_psize(mm, ea);
+               ssize = user_segment_size(ea);
+               vsid = get_vsid(mm->context.id, ea, ssize);
+               break;
+       case VMALLOC_REGION_ID:
+               pr_devel("%s: 0x%llx -- VMALLOC_REGION_ID\n", __func__, ea);
+               if (ea < VMALLOC_END)
+                       psize = mmu_vmalloc_psize;
+               else
+                       psize = mmu_io_psize;
+               ssize = mmu_kernel_ssize;
+               vsid = get_kernel_vsid(ea, mmu_kernel_ssize);
+               break;
+       case KERNEL_REGION_ID:
+               pr_devel("%s: 0x%llx -- KERNEL_REGION_ID\n", __func__, ea);
+               psize = mmu_linear_psize;
+               ssize = mmu_kernel_ssize;
+               vsid = get_kernel_vsid(ea, mmu_kernel_ssize);
+               break;
+       default:
+               pr_debug("%s: invalid region access at %016llx\n", __func__, ea);
+               return 1;
+       }
+
+       vsid = (vsid << slb_vsid_shift(ssize)) | SLB_VSID_USER;
+
+       vsid |= mmu_psize_defs[psize].sllp |
+               ((ssize == MMU_SEGSIZE_1T) ? SLB_VSID_B_1T : 0);
+
+       slb->vsid = vsid;
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(copro_calculate_slb);
+
+void copro_flush_all_slbs(struct mm_struct *mm)
+{
+#ifdef CONFIG_SPU_BASE
+       spu_flush_all_slbs(mm);
+#endif
+       cxl_slbia(mm);
+}
+EXPORT_SYMBOL_GPL(copro_flush_all_slbs);
index 51ab9e7e6c391b9497a08730a7b5e4c625c96304..08d659a9fcdbf16026e7dfc2af9306416028c671 100644 (file)
@@ -30,9 +30,9 @@
 #include <linux/kprobes.h>
 #include <linux/kdebug.h>
 #include <linux/perf_event.h>
-#include <linux/magic.h>
 #include <linux/ratelimit.h>
 #include <linux/context_tracking.h>
+#include <linux/hugetlb.h>
 
 #include <asm/firmware.h>
 #include <asm/page.h>
@@ -114,22 +114,37 @@ static int store_updates_sp(struct pt_regs *regs)
 #define MM_FAULT_CONTINUE      -1
 #define MM_FAULT_ERR(sig)      (sig)
 
-static int do_sigbus(struct pt_regs *regs, unsigned long address)
+static int do_sigbus(struct pt_regs *regs, unsigned long address,
+                    unsigned int fault)
 {
        siginfo_t info;
+       unsigned int lsb = 0;
 
        up_read(&current->mm->mmap_sem);
 
-       if (user_mode(regs)) {
-               current->thread.trap_nr = BUS_ADRERR;
-               info.si_signo = SIGBUS;
-               info.si_errno = 0;
-               info.si_code = BUS_ADRERR;
-               info.si_addr = (void __user *)address;
-               force_sig_info(SIGBUS, &info, current);
-               return MM_FAULT_RETURN;
+       if (!user_mode(regs))
+               return MM_FAULT_ERR(SIGBUS);
+
+       current->thread.trap_nr = BUS_ADRERR;
+       info.si_signo = SIGBUS;
+       info.si_errno = 0;
+       info.si_code = BUS_ADRERR;
+       info.si_addr = (void __user *)address;
+#ifdef CONFIG_MEMORY_FAILURE
+       if (fault & (VM_FAULT_HWPOISON|VM_FAULT_HWPOISON_LARGE)) {
+               pr_err("MCE: Killing %s:%d due to hardware memory corruption fault at %lx\n",
+                       current->comm, current->pid, address);
+               info.si_code = BUS_MCEERR_AR;
        }
-       return MM_FAULT_ERR(SIGBUS);
+
+       if (fault & VM_FAULT_HWPOISON_LARGE)
+               lsb = hstate_index_to_shift(VM_FAULT_GET_HINDEX(fault));
+       if (fault & VM_FAULT_HWPOISON)
+               lsb = PAGE_SHIFT;
+#endif
+       info.si_addr_lsb = lsb;
+       force_sig_info(SIGBUS, &info, current);
+       return MM_FAULT_RETURN;
 }
 
 static int mm_fault_error(struct pt_regs *regs, unsigned long addr, int fault)
@@ -170,11 +185,8 @@ static int mm_fault_error(struct pt_regs *regs, unsigned long addr, int fault)
                return MM_FAULT_RETURN;
        }
 
-       /* Bus error. x86 handles HWPOISON here, we'll add this if/when
-        * we support the feature in HW
-        */
-       if (fault & VM_FAULT_SIGBUS)
-               return do_sigbus(regs, addr);
+       if (fault & (VM_FAULT_SIGBUS|VM_FAULT_HWPOISON|VM_FAULT_HWPOISON_LARGE))
+               return do_sigbus(regs, addr, fault);
 
        /* We don't understand the fault code, this is fatal */
        BUG();
@@ -508,7 +520,6 @@ bail:
 void bad_page_fault(struct pt_regs *regs, unsigned long address, int sig)
 {
        const struct exception_table_entry *entry;
-       unsigned long *stackend;
 
        /* Are we prepared to handle this fault?  */
        if ((entry = search_exception_tables(regs->nip)) != NULL) {
@@ -537,8 +548,7 @@ void bad_page_fault(struct pt_regs *regs, unsigned long address, int sig)
        printk(KERN_ALERT "Faulting instruction address: 0x%08lx\n",
                regs->nip);
 
-       stackend = end_of_stack(current);
-       if (current != &init_task && *stackend != STACK_END_MAGIC)
+       if (task_stack_end_corrupted(current))
                printk(KERN_ALERT "Thread overran stack, or stack corrupted\n");
 
        die("Kernel access of bad area", regs, sig);
index afc0a8295f84c7097217855fae59f62b1ed6149e..ae4962a06476eed53eb4f6bfa84fc283f59197c4 100644 (file)
@@ -29,6 +29,8 @@
 #include <asm/kexec.h>
 #include <asm/ppc-opcode.h>
 
+#include <misc/cxl.h>
+
 #ifdef DEBUG_LOW
 #define DBG_LOW(fmt...) udbg_printf(fmt)
 #else
@@ -149,9 +151,11 @@ static inline void __tlbiel(unsigned long vpn, int psize, int apsize, int ssize)
 static inline void tlbie(unsigned long vpn, int psize, int apsize,
                         int ssize, int local)
 {
-       unsigned int use_local = local && mmu_has_feature(MMU_FTR_TLBIEL);
+       unsigned int use_local;
        int lock_tlbie = !mmu_has_feature(MMU_FTR_LOCKLESS_TLBIE);
 
+       use_local = local && mmu_has_feature(MMU_FTR_TLBIEL) && !cxl_ctx_in_use();
+
        if (use_local)
                use_local = mmu_psize_defs[psize].tlbiel;
        if (lock_tlbie && !use_local)
index daee7f4e5a14ca0048a7dfee9f2f07921529fced..d5339a3b99458d191123e56c94a6ef3df0b48fc3 100644 (file)
@@ -51,7 +51,7 @@
 #include <asm/cacheflush.h>
 #include <asm/cputable.h>
 #include <asm/sections.h>
-#include <asm/spu.h>
+#include <asm/copro.h>
 #include <asm/udbg.h>
 #include <asm/code-patching.h>
 #include <asm/fadump.h>
@@ -92,12 +92,14 @@ extern unsigned long dart_tablebase;
 
 static unsigned long _SDR1;
 struct mmu_psize_def mmu_psize_defs[MMU_PAGE_COUNT];
+EXPORT_SYMBOL_GPL(mmu_psize_defs);
 
 struct hash_pte *htab_address;
 unsigned long htab_size_bytes;
 unsigned long htab_hash_mask;
 EXPORT_SYMBOL_GPL(htab_hash_mask);
 int mmu_linear_psize = MMU_PAGE_4K;
+EXPORT_SYMBOL_GPL(mmu_linear_psize);
 int mmu_virtual_psize = MMU_PAGE_4K;
 int mmu_vmalloc_psize = MMU_PAGE_4K;
 #ifdef CONFIG_SPARSEMEM_VMEMMAP
@@ -105,6 +107,7 @@ int mmu_vmemmap_psize = MMU_PAGE_4K;
 #endif
 int mmu_io_psize = MMU_PAGE_4K;
 int mmu_kernel_ssize = MMU_SEGSIZE_256M;
+EXPORT_SYMBOL_GPL(mmu_kernel_ssize);
 int mmu_highuser_ssize = MMU_SEGSIZE_256M;
 u16 mmu_slb_size = 64;
 EXPORT_SYMBOL_GPL(mmu_slb_size);
@@ -333,70 +336,69 @@ static int __init htab_dt_scan_page_sizes(unsigned long node,
                return 0;
 
        prop = of_get_flat_dt_prop(node, "ibm,segment-page-sizes", &size);
-       if (prop != NULL) {
-               pr_info("Page sizes from device-tree:\n");
-               size /= 4;
-               cur_cpu_spec->mmu_features &= ~(MMU_FTR_16M_PAGE);
-               while(size > 0) {
-                       unsigned int base_shift = be32_to_cpu(prop[0]);
-                       unsigned int slbenc = be32_to_cpu(prop[1]);
-                       unsigned int lpnum = be32_to_cpu(prop[2]);
-                       struct mmu_psize_def *def;
-                       int idx, base_idx;
-
-                       size -= 3; prop += 3;
-                       base_idx = get_idx_from_shift(base_shift);
-                       if (base_idx < 0) {
-                               /*
-                                * skip the pte encoding also
-                                */
-                               prop += lpnum * 2; size -= lpnum * 2;
+       if (!prop)
+               return 0;
+
+       pr_info("Page sizes from device-tree:\n");
+       size /= 4;
+       cur_cpu_spec->mmu_features &= ~(MMU_FTR_16M_PAGE);
+       while(size > 0) {
+               unsigned int base_shift = be32_to_cpu(prop[0]);
+               unsigned int slbenc = be32_to_cpu(prop[1]);
+               unsigned int lpnum = be32_to_cpu(prop[2]);
+               struct mmu_psize_def *def;
+               int idx, base_idx;
+
+               size -= 3; prop += 3;
+               base_idx = get_idx_from_shift(base_shift);
+               if (base_idx < 0) {
+                       /* skip the pte encoding also */
+                       prop += lpnum * 2; size -= lpnum * 2;
+                       continue;
+               }
+               def = &mmu_psize_defs[base_idx];
+               if (base_idx == MMU_PAGE_16M)
+                       cur_cpu_spec->mmu_features |= MMU_FTR_16M_PAGE;
+
+               def->shift = base_shift;
+               if (base_shift <= 23)
+                       def->avpnm = 0;
+               else
+                       def->avpnm = (1 << (base_shift - 23)) - 1;
+               def->sllp = slbenc;
+               /*
+                * We don't know for sure what's up with tlbiel, so
+                * for now we only set it for 4K and 64K pages
+                */
+               if (base_idx == MMU_PAGE_4K || base_idx == MMU_PAGE_64K)
+                       def->tlbiel = 1;
+               else
+                       def->tlbiel = 0;
+
+               while (size > 0 && lpnum) {
+                       unsigned int shift = be32_to_cpu(prop[0]);
+                       int penc  = be32_to_cpu(prop[1]);
+
+                       prop += 2; size -= 2;
+                       lpnum--;
+
+                       idx = get_idx_from_shift(shift);
+                       if (idx < 0)
                                continue;
-                       }
-                       def = &mmu_psize_defs[base_idx];
-                       if (base_idx == MMU_PAGE_16M)
-                               cur_cpu_spec->mmu_features |= MMU_FTR_16M_PAGE;
-
-                       def->shift = base_shift;
-                       if (base_shift <= 23)
-                               def->avpnm = 0;
-                       else
-                               def->avpnm = (1 << (base_shift - 23)) - 1;
-                       def->sllp = slbenc;
-                       /*
-                        * We don't know for sure what's up with tlbiel, so
-                        * for now we only set it for 4K and 64K pages
-                        */
-                       if (base_idx == MMU_PAGE_4K || base_idx == MMU_PAGE_64K)
-                               def->tlbiel = 1;
-                       else
-                               def->tlbiel = 0;
-
-                       while (size > 0 && lpnum) {
-                               unsigned int shift = be32_to_cpu(prop[0]);
-                               int penc  = be32_to_cpu(prop[1]);
-
-                               prop += 2; size -= 2;
-                               lpnum--;
-
-                               idx = get_idx_from_shift(shift);
-                               if (idx < 0)
-                                       continue;
-
-                               if (penc == -1)
-                                       pr_err("Invalid penc for base_shift=%d "
-                                              "shift=%d\n", base_shift, shift);
-
-                               def->penc[idx] = penc;
-                               pr_info("base_shift=%d: shift=%d, sllp=0x%04lx,"
-                                       " avpnm=0x%08lx, tlbiel=%d, penc=%d\n",
-                                       base_shift, shift, def->sllp,
-                                       def->avpnm, def->tlbiel, def->penc[idx]);
-                       }
+
+                       if (penc == -1)
+                               pr_err("Invalid penc for base_shift=%d "
+                                      "shift=%d\n", base_shift, shift);
+
+                       def->penc[idx] = penc;
+                       pr_info("base_shift=%d: shift=%d, sllp=0x%04lx,"
+                               " avpnm=0x%08lx, tlbiel=%d, penc=%d\n",
+                               base_shift, shift, def->sllp,
+                               def->avpnm, def->tlbiel, def->penc[idx]);
                }
-               return 1;
        }
-       return 0;
+
+       return 1;
 }
 
 #ifdef CONFIG_HUGETLB_PAGE
@@ -867,7 +869,7 @@ unsigned int hash_page_do_lazy_icache(unsigned int pp, pte_t pte, int trap)
 }
 
 #ifdef CONFIG_PPC_MM_SLICES
-unsigned int get_paca_psize(unsigned long addr)
+static unsigned int get_paca_psize(unsigned long addr)
 {
        u64 lpsizes;
        unsigned char *hpsizes;
@@ -901,10 +903,8 @@ void demote_segment_4k(struct mm_struct *mm, unsigned long addr)
        if (get_slice_psize(mm, addr) == MMU_PAGE_4K)
                return;
        slice_set_range_psize(mm, addr, 1, MMU_PAGE_4K);
-#ifdef CONFIG_SPU_BASE
-       spu_flush_all_slbs(mm);
-#endif
-       if (get_paca_psize(addr) != MMU_PAGE_4K) {
+       copro_flush_all_slbs(mm);
+       if ((get_paca_psize(addr) != MMU_PAGE_4K) && (current->mm == mm)) {
                get_paca()->context = mm->context;
                slb_flush_and_rebolt();
        }
@@ -989,12 +989,11 @@ static void check_paca_psize(unsigned long ea, struct mm_struct *mm,
  * -1 - critical hash insertion error
  * -2 - access not permitted by subpage protection mechanism
  */
-int hash_page(unsigned long ea, unsigned long access, unsigned long trap)
+int hash_page_mm(struct mm_struct *mm, unsigned long ea, unsigned long access, unsigned long trap)
 {
        enum ctx_state prev_state = exception_enter();
        pgd_t *pgdir;
        unsigned long vsid;
-       struct mm_struct *mm;
        pte_t *ptep;
        unsigned hugeshift;
        const struct cpumask *tmp;
@@ -1008,7 +1007,6 @@ int hash_page(unsigned long ea, unsigned long access, unsigned long trap)
        switch (REGION_ID(ea)) {
        case USER_REGION_ID:
                user_region = 1;
-               mm = current->mm;
                if (! mm) {
                        DBG_LOW(" user region with no mm !\n");
                        rc = 1;
@@ -1019,7 +1017,6 @@ int hash_page(unsigned long ea, unsigned long access, unsigned long trap)
                vsid = get_vsid(mm->context.id, ea, ssize);
                break;
        case VMALLOC_REGION_ID:
-               mm = &init_mm;
                vsid = get_kernel_vsid(ea, mmu_kernel_ssize);
                if (ea < VMALLOC_END)
                        psize = mmu_vmalloc_psize;
@@ -1104,7 +1101,8 @@ int hash_page(unsigned long ea, unsigned long access, unsigned long trap)
                        WARN_ON(1);
                }
 #endif
-               check_paca_psize(ea, mm, psize, user_region);
+               if (current->mm == mm)
+                       check_paca_psize(ea, mm, psize, user_region);
 
                goto bail;
        }
@@ -1141,13 +1139,12 @@ int hash_page(unsigned long ea, unsigned long access, unsigned long trap)
                               "to 4kB pages because of "
                               "non-cacheable mapping\n");
                        psize = mmu_vmalloc_psize = MMU_PAGE_4K;
-#ifdef CONFIG_SPU_BASE
-                       spu_flush_all_slbs(mm);
-#endif
+                       copro_flush_all_slbs(mm);
                }
        }
 
-       check_paca_psize(ea, mm, psize, user_region);
+       if (current->mm == mm)
+               check_paca_psize(ea, mm, psize, user_region);
 #endif /* CONFIG_PPC_64K_PAGES */
 
 #ifdef CONFIG_PPC_HAS_HASH_64K
@@ -1182,6 +1179,17 @@ bail:
        exception_exit(prev_state);
        return rc;
 }
+EXPORT_SYMBOL_GPL(hash_page_mm);
+
+int hash_page(unsigned long ea, unsigned long access, unsigned long trap)
+{
+       struct mm_struct *mm = current->mm;
+
+       if (REGION_ID(ea) == VMALLOC_REGION_ID)
+               mm = &init_mm;
+
+       return hash_page_mm(mm, ea, access, trap);
+}
 EXPORT_SYMBOL_GPL(hash_page);
 
 void hash_preload(struct mm_struct *mm, unsigned long ea,
index cff59f1bec238bd41fbcd246d6a732ccc357e1ce..cad68ff8eca5322990cfa56ee46003ae530e1d39 100644 (file)
@@ -106,11 +106,11 @@ unsigned long __max_low_memory = MAX_LOW_MEM;
 void MMU_setup(void)
 {
        /* Check for nobats option (used in mapin_ram). */
-       if (strstr(cmd_line, "nobats")) {
+       if (strstr(boot_command_line, "nobats")) {
                __map_without_bats = 1;
        }
 
-       if (strstr(cmd_line, "noltlbs")) {
+       if (strstr(boot_command_line, "noltlbs")) {
                __map_without_ltlbs = 1;
        }
 #ifdef CONFIG_DEBUG_PAGEALLOC
index 253b4b971c8afa261d110d653e15495a8c55dc6c..3481556a1880407db79fe32527289040eb9b6d77 100644 (file)
@@ -233,9 +233,6 @@ static void __meminit vmemmap_create_mapping(unsigned long start,
 }
 
 #ifdef CONFIG_MEMORY_HOTPLUG
-extern int htab_remove_mapping(unsigned long vstart, unsigned long vend,
-                       int psize, int ssize);
-
 static void vmemmap_remove_mapping(unsigned long start,
                                   unsigned long page_size)
 {
index e0f7a189c48ea440dc2e05ac659eb46895490590..8ebaac75c940ad7c5e9752a71c7dd7894e2bdedf 100644 (file)
@@ -260,6 +260,60 @@ static int __init mark_nonram_nosave(void)
        }
        return 0;
 }
+#else /* CONFIG_NEED_MULTIPLE_NODES */
+static int __init mark_nonram_nosave(void)
+{
+       return 0;
+}
+#endif
+
+static bool zone_limits_final;
+
+static unsigned long max_zone_pfns[MAX_NR_ZONES] = {
+       [0 ... MAX_NR_ZONES - 1] = ~0UL
+};
+
+/*
+ * Restrict the specified zone and all more restrictive zones
+ * to be below the specified pfn.  May not be called after
+ * paging_init().
+ */
+void __init limit_zone_pfn(enum zone_type zone, unsigned long pfn_limit)
+{
+       int i;
+
+       if (WARN_ON(zone_limits_final))
+               return;
+
+       for (i = zone; i >= 0; i--) {
+               if (max_zone_pfns[i] > pfn_limit)
+                       max_zone_pfns[i] = pfn_limit;
+       }
+}
+
+/*
+ * Find the least restrictive zone that is entirely below the
+ * specified pfn limit.  Returns < 0 if no suitable zone is found.
+ *
+ * pfn_limit must be u64 because it can exceed 32 bits even on 32-bit
+ * systems -- the DMA limit can be higher than any possible real pfn.
+ */
+int dma_pfn_limit_to_zone(u64 pfn_limit)
+{
+       enum zone_type top_zone = ZONE_NORMAL;
+       int i;
+
+#ifdef CONFIG_HIGHMEM
+       top_zone = ZONE_HIGHMEM;
+#endif
+
+       for (i = top_zone; i >= 0; i--) {
+               if (max_zone_pfns[i] <= pfn_limit)
+                       return i;
+       }
+
+       return -EPERM;
+}
 
 /*
  * paging_init() sets up the page tables - in fact we've already done this.
@@ -268,7 +322,7 @@ void __init paging_init(void)
 {
        unsigned long long total_ram = memblock_phys_mem_size();
        phys_addr_t top_of_ram = memblock_end_of_DRAM();
-       unsigned long max_zone_pfns[MAX_NR_ZONES];
+       enum zone_type top_zone;
 
 #ifdef CONFIG_PPC32
        unsigned long v = __fix_to_virt(__end_of_fixed_addresses - 1);
@@ -290,18 +344,20 @@ void __init paging_init(void)
               (unsigned long long)top_of_ram, total_ram);
        printk(KERN_DEBUG "Memory hole size: %ldMB\n",
               (long int)((top_of_ram - total_ram) >> 20));
-       memset(max_zone_pfns, 0, sizeof(max_zone_pfns));
+
 #ifdef CONFIG_HIGHMEM
-       max_zone_pfns[ZONE_DMA] = lowmem_end_addr >> PAGE_SHIFT;
-       max_zone_pfns[ZONE_HIGHMEM] = top_of_ram >> PAGE_SHIFT;
+       top_zone = ZONE_HIGHMEM;
+       limit_zone_pfn(ZONE_NORMAL, lowmem_end_addr >> PAGE_SHIFT);
 #else
-       max_zone_pfns[ZONE_DMA] = top_of_ram >> PAGE_SHIFT;
+       top_zone = ZONE_NORMAL;
 #endif
+
+       limit_zone_pfn(top_zone, top_of_ram >> PAGE_SHIFT);
+       zone_limits_final = true;
        free_area_init_nodes(max_zone_pfns);
 
        mark_nonram_nosave();
 }
-#endif /* ! CONFIG_NEED_MULTIPLE_NODES */
 
 static void __init register_page_bootmem_info(void)
 {
index d7737a542fd7d5f5af82bde3ec417262575175af..649666d5d1c20520ed554a3375c11393660871e1 100644 (file)
@@ -538,7 +538,7 @@ static int of_drconf_to_nid_single(struct of_drconf_cell *drmem,
  */
 static int numa_setup_cpu(unsigned long lcpu)
 {
-       int nid;
+       int nid = -1;
        struct device_node *cpu;
 
        /*
@@ -555,19 +555,21 @@ static int numa_setup_cpu(unsigned long lcpu)
 
        if (!cpu) {
                WARN_ON(1);
-               nid = 0;
-               goto out;
+               if (cpu_present(lcpu))
+                       goto out_present;
+               else
+                       goto out;
        }
 
        nid = of_node_to_nid_single(cpu);
 
+out_present:
        if (nid < 0 || !node_online(nid))
                nid = first_online_node;
-out:
-       map_cpu_to_node(lcpu, nid);
 
+       map_cpu_to_node(lcpu, nid);
        of_node_put(cpu);
-
+out:
        return nid;
 }
 
@@ -1127,20 +1129,11 @@ void __init do_init_bootmem(void)
         * even before we online them, so that we can use cpu_to_{node,mem}
         * early in boot, cf. smp_prepare_cpus().
         */
-       for_each_possible_cpu(cpu) {
-               cpu_numa_callback(&ppc64_numa_nb, CPU_UP_PREPARE,
-                                 (void *)(unsigned long)cpu);
+       for_each_present_cpu(cpu) {
+               numa_setup_cpu((unsigned long)cpu);
        }
 }
 
-void __init paging_init(void)
-{
-       unsigned long max_zone_pfns[MAX_NR_ZONES];
-       memset(max_zone_pfns, 0, sizeof(max_zone_pfns));
-       max_zone_pfns[ZONE_DMA] = memblock_end_of_DRAM() >> PAGE_SHIFT;
-       free_area_init_nodes(max_zone_pfns);
-}
-
 static int __init early_numa(char *p)
 {
        if (!p)
index c695943a513cc638621c830f537ea903ccfa3b86..c90e602677c94f38e084957a78ab386cba89b037 100644 (file)
@@ -48,7 +48,7 @@ static inline int pte_looks_normal(pte_t pte)
            (_PAGE_PRESENT | _PAGE_USER);
 }
 
-struct page * maybe_pte_to_page(pte_t pte)
+static struct page *maybe_pte_to_page(pte_t pte)
 {
        unsigned long pfn = pte_pfn(pte);
        struct page *page;
index 0399a6702958dd933f8581cf8b75cfe16a184bb3..6e450ca6652684eede4bb00f17ebb3e9a74e91d5 100644 (file)
@@ -46,9 +46,6 @@ static inline unsigned long mk_esid_data(unsigned long ea, int ssize,
        return (ea & slb_esid_mask(ssize)) | SLB_ESID_V | slot;
 }
 
-#define slb_vsid_shift(ssize)  \
-       ((ssize) == MMU_SEGSIZE_256M? SLB_VSID_SHIFT: SLB_VSID_SHIFT_1T)
-
 static inline unsigned long mk_vsid_data(unsigned long ea, int ssize,
                                         unsigned long flags)
 {
index b0c75cc15efc673a0ff8f22e0c0e6ef8dc18a038..8d7bda94d1969b2325073315875a05545922b0fc 100644 (file)
 #include <linux/err.h>
 #include <linux/spinlock.h>
 #include <linux/export.h>
+#include <linux/hugetlb.h>
 #include <asm/mman.h>
 #include <asm/mmu.h>
-#include <asm/spu.h>
+#include <asm/copro.h>
+#include <asm/hugetlb.h>
 
 /* some sanity checks */
 #if (PGTABLE_RANGE >> 43) > SLICE_MASK_SIZE
@@ -232,9 +234,7 @@ static void slice_convert(struct mm_struct *mm, struct slice_mask mask, int psiz
 
        spin_unlock_irqrestore(&slice_convert_lock, flags);
 
-#ifdef CONFIG_SPU_BASE
-       spu_flush_all_slbs(mm);
-#endif
+       copro_flush_all_slbs(mm);
 }
 
 /*
@@ -671,9 +671,7 @@ void slice_set_psize(struct mm_struct *mm, unsigned long address,
 
        spin_unlock_irqrestore(&slice_convert_lock, flags);
 
-#ifdef CONFIG_SPU_BASE
-       spu_flush_all_slbs(mm);
-#endif
+       copro_flush_all_slbs(mm);
 }
 
 void slice_set_range_psize(struct mm_struct *mm, unsigned long start,
index f75301f2c85fd2960acd21ee427527614934585e..6adf55fa5d88c2cb55b13dc99cfbdaecba7dcff3 100644 (file)
@@ -12,6 +12,7 @@
 #include <asm/processor.h>
 #include <asm/uaccess.h>
 #include <asm/compat.h>
+#include <asm/oprofile_impl.h>
 
 #define STACK_SP(STACK)                *(STACK)
 
index b7cd00b0171ed9776603969e2af25d5abe3f66a9..a6995d4e93d43d29a34d3c4f833097530f13ebf8 100644 (file)
@@ -59,9 +59,9 @@ struct cpu_hw_events {
        struct  perf_branch_entry       bhrb_entries[BHRB_MAX_ENTRIES];
 };
 
-DEFINE_PER_CPU(struct cpu_hw_events, cpu_hw_events);
+static DEFINE_PER_CPU(struct cpu_hw_events, cpu_hw_events);
 
-struct power_pmu *ppmu;
+static struct power_pmu *ppmu;
 
 /*
  * Normally, to ignore kernel events we set the FCS (freeze counters
@@ -124,7 +124,7 @@ static unsigned long ebb_switch_in(bool ebb, struct cpu_hw_events *cpuhw)
 
 static inline void power_pmu_bhrb_enable(struct perf_event *event) {}
 static inline void power_pmu_bhrb_disable(struct perf_event *event) {}
-void power_pmu_flush_branch_stack(void) {}
+static void power_pmu_flush_branch_stack(void) {}
 static inline void power_pmu_bhrb_read(struct cpu_hw_events *cpuhw) {}
 static void pmao_restore_workaround(bool ebb) { }
 #endif /* CONFIG_PPC32 */
@@ -375,7 +375,7 @@ static void power_pmu_bhrb_disable(struct perf_event *event)
 /* Called from ctxsw to prevent one process's branch entries to
  * mingle with the other process's entries during context switch.
  */
-void power_pmu_flush_branch_stack(void)
+static void power_pmu_flush_branch_stack(void)
 {
        if (ppmu->bhrb_nr)
                power_pmu_bhrb_reset();
@@ -408,7 +408,7 @@ static __u64 power_pmu_bhrb_to(u64 addr)
 }
 
 /* Processing BHRB entries */
-void power_pmu_bhrb_read(struct cpu_hw_events *cpuhw)
+static void power_pmu_bhrb_read(struct cpu_hw_events *cpuhw)
 {
        u64 val;
        u64 addr;
@@ -1573,7 +1573,7 @@ static void power_pmu_stop(struct perf_event *event, int ef_flags)
  * Set the flag to make pmu::enable() not perform the
  * schedulability test, it will be performed at commit time
  */
-void power_pmu_start_txn(struct pmu *pmu)
+static void power_pmu_start_txn(struct pmu *pmu)
 {
        struct cpu_hw_events *cpuhw = &__get_cpu_var(cpu_hw_events);
 
@@ -1587,7 +1587,7 @@ void power_pmu_start_txn(struct pmu *pmu)
  * Clear the flag and pmu::enable() will perform the
  * schedulability test.
  */
-void power_pmu_cancel_txn(struct pmu *pmu)
+static void power_pmu_cancel_txn(struct pmu *pmu)
 {
        struct cpu_hw_events *cpuhw = &__get_cpu_var(cpu_hw_events);
 
@@ -1600,7 +1600,7 @@ void power_pmu_cancel_txn(struct pmu *pmu)
  * Perform the group schedulability test as a whole
  * Return 0 if success
  */
-int power_pmu_commit_txn(struct pmu *pmu)
+static int power_pmu_commit_txn(struct pmu *pmu)
 {
        struct cpu_hw_events *cpuhw;
        long i, n;
@@ -1888,7 +1888,7 @@ ssize_t power_events_sysfs_show(struct device *dev,
        return sprintf(page, "event=0x%02llx\n", pmu_attr->id);
 }
 
-struct pmu power_pmu = {
+static struct pmu power_pmu = {
        .pmu_enable     = power_pmu_enable,
        .pmu_disable    = power_pmu_disable,
        .event_init     = power_pmu_event_init,
index 70d4f748b54bead98a8889ea3de6d344dbb3ca31..6c8710dd90c9b12d7e746113b43fdc9231c8b8b3 100644 (file)
@@ -75,86 +75,6 @@ static struct attribute_group format_group = {
 
 static struct kmem_cache *hv_page_cache;
 
-/*
- * read_offset_data - copy data from one buffer to another while treating the
- *                    source buffer as a small view on the total avaliable
- *                    source data.
- *
- * @dest: buffer to copy into
- * @dest_len: length of @dest in bytes
- * @requested_offset: the offset within the source data we want. Must be > 0
- * @src: buffer to copy data from
- * @src_len: length of @src in bytes
- * @source_offset: the offset in the sorce data that (src,src_len) refers to.
- *                 Must be > 0
- *
- * returns the number of bytes copied.
- *
- * The following ascii art shows the various buffer possitioning we need to
- * handle, assigns some arbitrary varibles to points on the buffer, and then
- * shows how we fiddle with those values to get things we care about (copy
- * start in src and copy len)
- *
- * s = @src buffer
- * d = @dest buffer
- * '.' areas in d are written to.
- *
- *                       u
- *   x         w        v  z
- * d           |.........|
- * s |----------------------|
- *
- *                      u
- *   x         w       z     v
- * d           |........------|
- * s |------------------|
- *
- *   x         w        u,z,v
- * d           |........|
- * s |------------------|
- *
- *   x,w                u,v,z
- * d |..................|
- * s |------------------|
- *
- *   x        u
- *   w        v                z
- * d |........|
- * s |------------------|
- *
- *   x      z   w      v
- * d            |------|
- * s |------|
- *
- * x = source_offset
- * w = requested_offset
- * z = source_offset + src_len
- * v = requested_offset + dest_len
- *
- * w_offset_in_s = w - x = requested_offset - source_offset
- * z_offset_in_s = z - x = src_len
- * v_offset_in_s = v - x = request_offset + dest_len - src_len
- */
-static ssize_t read_offset_data(void *dest, size_t dest_len,
-                               loff_t requested_offset, void *src,
-                               size_t src_len, loff_t source_offset)
-{
-       size_t w_offset_in_s = requested_offset - source_offset;
-       size_t z_offset_in_s = src_len;
-       size_t v_offset_in_s = requested_offset + dest_len - src_len;
-       size_t u_offset_in_s = min(z_offset_in_s, v_offset_in_s);
-       size_t copy_len = u_offset_in_s - w_offset_in_s;
-
-       if (requested_offset < 0 || source_offset < 0)
-               return -EINVAL;
-
-       if (z_offset_in_s <= w_offset_in_s)
-               return 0;
-
-       memcpy(dest, src + w_offset_in_s, copy_len);
-       return copy_len;
-}
-
 static unsigned long h_get_24x7_catalog_page_(unsigned long phys_4096,
                                              unsigned long version,
                                              unsigned long index)
@@ -183,8 +103,10 @@ static ssize_t catalog_read(struct file *filp, struct kobject *kobj,
 {
        unsigned long hret;
        ssize_t ret = 0;
-       size_t catalog_len = 0, catalog_page_len = 0, page_count = 0;
+       size_t catalog_len = 0, catalog_page_len = 0;
        loff_t page_offset = 0;
+       loff_t offset_in_page;
+       size_t copy_len;
        uint64_t catalog_version_num = 0;
        void *page = kmem_cache_alloc(hv_page_cache, GFP_USER);
        struct hv_24x7_catalog_page_0 *page_0 = page;
@@ -202,7 +124,7 @@ static ssize_t catalog_read(struct file *filp, struct kobject *kobj,
        catalog_len = catalog_page_len * 4096;
 
        page_offset = offset / 4096;
-       page_count  = count  / 4096;
+       offset_in_page = offset % 4096;
 
        if (page_offset >= catalog_page_len)
                goto e_free;
@@ -216,8 +138,13 @@ static ssize_t catalog_read(struct file *filp, struct kobject *kobj,
                }
        }
 
-       ret = read_offset_data(buf, count, offset,
-                               page, 4096, page_offset * 4096);
+       copy_len = 4096 - offset_in_page;
+       if (copy_len > count)
+               copy_len = count;
+
+       memcpy(buf, page+offset_in_page, copy_len);
+       ret = copy_len;
+
 e_free:
        if (hret)
                pr_err("h_get_24x7_catalog_page(ver=%lld, page=%lld) failed:"
@@ -225,9 +152,9 @@ e_free:
                       catalog_version_num, page_offset, hret);
        kmem_cache_free(hv_page_cache, page);
 
-       pr_devel("catalog_read: offset=%lld(%lld) count=%zu(%zu) catalog_len=%zu(%zu) => %zd\n",
-                       offset, page_offset, count, page_count, catalog_len,
-                       catalog_page_len, ret);
+       pr_devel("catalog_read: offset=%lld(%lld) count=%zu "
+                       "catalog_len=%zu(%zu) => %zd\n", offset, page_offset,
+                       count, catalog_len, catalog_page_len, ret);
 
        return ret;
 }
@@ -294,7 +221,7 @@ static unsigned long single_24x7_request(u8 domain, u32 offset, u16 ix,
                                         u16 lpar, u64 *res,
                                         bool success_expected)
 {
-       unsigned long ret;
+       unsigned long ret = -ENOMEM;
 
        /*
         * request_buffer and result_buffer are not required to be 4k aligned,
@@ -304,7 +231,27 @@ static unsigned long single_24x7_request(u8 domain, u32 offset, u16 ix,
        struct reqb {
                struct hv_24x7_request_buffer buf;
                struct hv_24x7_request req;
-       } __packed __aligned(4096) request_buffer = {
+       } __packed *request_buffer;
+
+       struct {
+               struct hv_24x7_data_result_buffer buf;
+               struct hv_24x7_result res;
+               struct hv_24x7_result_element elem;
+               __be64 result;
+       } __packed *result_buffer;
+
+       BUILD_BUG_ON(sizeof(*request_buffer) > 4096);
+       BUILD_BUG_ON(sizeof(*result_buffer) > 4096);
+
+       request_buffer = kmem_cache_zalloc(hv_page_cache, GFP_USER);
+       if (!request_buffer)
+               goto out;
+
+       result_buffer = kmem_cache_zalloc(hv_page_cache, GFP_USER);
+       if (!result_buffer)
+               goto out_free_request_buffer;
+
+       *request_buffer = (struct reqb) {
                .buf = {
                        .interface_version = HV_24X7_IF_VERSION_CURRENT,
                        .num_requests = 1,
@@ -320,28 +267,27 @@ static unsigned long single_24x7_request(u8 domain, u32 offset, u16 ix,
                }
        };
 
-       struct resb {
-               struct hv_24x7_data_result_buffer buf;
-               struct hv_24x7_result res;
-               struct hv_24x7_result_element elem;
-               __be64 result;
-       } __packed __aligned(4096) result_buffer = {};
-
        ret = plpar_hcall_norets(H_GET_24X7_DATA,
-                       virt_to_phys(&request_buffer), sizeof(request_buffer),
-                       virt_to_phys(&result_buffer),  sizeof(result_buffer));
+                       virt_to_phys(request_buffer), sizeof(*request_buffer),
+                       virt_to_phys(result_buffer),  sizeof(*result_buffer));
 
        if (ret) {
                if (success_expected)
-                       pr_err_ratelimited("hcall failed: %d %#x %#x %d => 0x%lx (%ld) detail=0x%x failing ix=%x\n",
-                                       domain, offset, ix, lpar,
-                                       ret, ret,
-                                       result_buffer.buf.detailed_rc,
-                                       result_buffer.buf.failing_request_ix);
-               return ret;
+                       pr_err_ratelimited("hcall failed: %d %#x %#x %d => "
+                               "0x%lx (%ld) detail=0x%x failing ix=%x\n",
+                               domain, offset, ix, lpar, ret, ret,
+                               result_buffer->buf.detailed_rc,
+                               result_buffer->buf.failing_request_ix);
+               goto out_free_result_buffer;
        }
 
-       *res = be64_to_cpu(result_buffer.result);
+       *res = be64_to_cpu(result_buffer->result);
+
+out_free_result_buffer:
+       kfree(result_buffer);
+out_free_request_buffer:
+       kfree(request_buffer);
+out:
        return ret;
 }
 
index b0389bbe4f94328206eb00bf4d384e6c9c9fbc93..ddc12a1926ef0a189dc7e7d591c87cf5b80cbf2b 100644 (file)
@@ -49,7 +49,7 @@ static void __iomem *bcsr_regs;
 /* there's more, can't be bothered typing them tho */
 
 
-static __initdata struct of_device_id ep405_of_bus[] = {
+static const struct of_device_id ep405_of_bus[] __initconst = {
        { .compatible = "ibm,plb3", },
        { .compatible = "ibm,opb", },
        { .compatible = "ibm,ebc", },
index 8f3920e5a046c4df771ecd30371154a84e813d82..b0c46375dd9567d9b85d19688ab1f0bb5b102fd3 100644 (file)
@@ -24,7 +24,7 @@
 #include <linux/init.h>
 #include <linux/of_platform.h>
 
-static __initdata struct of_device_id ppc40x_of_bus[] = {
+static const struct of_device_id ppc40x_of_bus[] __initconst = {
        { .compatible = "ibm,plb3", },
        { .compatible = "ibm,plb4", },
        { .compatible = "ibm,opb", },
index d0fc6866b00ca04884a2a39bb1d0922763e5a6a0..9aa7ae2f4164ba45c51f0522aac1bb5ccccc032d 100644 (file)
@@ -17,7 +17,7 @@
 #include <asm/xilinx_pci.h>
 #include <asm/ppc4xx.h>
 
-static struct of_device_id xilinx_of_bus_ids[] __initdata = {
+static const struct of_device_id xilinx_of_bus_ids[] __initconst = {
        { .compatible = "xlnx,plb-v46-1.00.a", },
        { .compatible = "xlnx,plb-v34-1.01.a", },
        { .compatible = "xlnx,plb-v34-1.02.a", },
index 8b691df72f745232b85a349b702c4a72d6869288..f7ac2d0fcb4461023371b08d3ab67e2770b33a47 100644 (file)
@@ -28,7 +28,7 @@
 #include <asm/pci-bridge.h>
 #include <asm/ppc4xx.h>
 
-static __initdata struct of_device_id walnut_of_bus[] = {
+static const struct of_device_id walnut_of_bus[] __initconst = {
        { .compatible = "ibm,plb3", },
        { .compatible = "ibm,opb", },
        { .compatible = "ibm,ebc", },
index 4d88f6a19058cc253dcd885eec86e077f7441295..82f2da28cd2775c4051a60d3f4014e25148f892c 100644 (file)
@@ -215,9 +215,9 @@ config AKEBONO
        select NET_VENDOR_IBM
        select IBM_EMAC_EMAC4
        select IBM_EMAC_RGMII_WOL
-       select USB
-       select USB_OHCI_HCD_PLATFORM
-       select USB_EHCI_HCD_PLATFORM
+       select USB if USB_SUPPORT
+       select USB_OHCI_HCD_PLATFORM if USB_OHCI_HCD
+       select USB_EHCI_HCD_PLATFORM if USB_EHCI_HCD
        select MMC_SDHCI
        select MMC_SDHCI_PLTFM
        select MMC_SDHCI_OF_476GTR
index e300dd4c89bff9964ecfaf72734fbf9c08a03352..22ca5430c9cb5614256bc2cd939d628fb4ad8bd2 100644 (file)
@@ -33,7 +33,7 @@
 
 #define BCSR_USB_EN    0x11
 
-static __initdata struct of_device_id ppc460ex_of_bus[] = {
+static const struct of_device_id ppc460ex_of_bus[] __initconst = {
        { .compatible = "ibm,plb4", },
        { .compatible = "ibm,opb", },
        { .compatible = "ibm,ebc", },
index 6a4232bbdf88a35e9d4c1baa76eb37a620c7a8be..ae893226392dbf4f5494a95a55070ac758e7c685 100644 (file)
@@ -28,7 +28,7 @@
 #include <asm/pci-bridge.h>
 #include <asm/ppc4xx.h>
 
-static __initdata struct of_device_id ebony_of_bus[] = {
+static const struct of_device_id ebony_of_bus[] __initconst = {
        { .compatible = "ibm,plb4", },
        { .compatible = "ibm,opb", },
        { .compatible = "ibm,ebc", },
index 4241bc825800d72450bc994bacf2a4203fd9aa63..c7c6758b3cfe56ff8a8c919adb6921d4b382c69d 100644 (file)
@@ -32,7 +32,7 @@
 #include <asm/mpic.h>
 #include <asm/mmu.h>
 
-static __initdata struct of_device_id iss4xx_of_bus[] = {
+static const struct of_device_id iss4xx_of_bus[] __initconst = {
        { .compatible = "ibm,plb4", },
        { .compatible = "ibm,plb6", },
        { .compatible = "ibm,opb", },
index 3ffb915446e39bdf74f716395a6a05f8e559c632..573c3d2689c616981186c3c083b28d73c950e1e2 100644 (file)
@@ -24,7 +24,7 @@
 #include <linux/init.h>
 #include <linux/of_platform.h>
 
-static __initdata struct of_device_id ppc44x_of_bus[] = {
+static const struct of_device_id ppc44x_of_bus[] __initconst = {
        { .compatible = "ibm,plb4", },
        { .compatible = "ibm,opb", },
        { .compatible = "ibm,ebc", },
index 33986c1a05da2eaa6e1722dac53de62a2586f304..58db9d0839698fa65429e40703f196d416f7d02a 100644 (file)
@@ -38,7 +38,7 @@
 #include <linux/pci.h>
 #include <linux/i2c.h>
 
-static struct of_device_id ppc47x_of_bus[] __initdata = {
+static const struct of_device_id ppc47x_of_bus[] __initconst = {
        { .compatible = "ibm,plb4", },
        { .compatible = "ibm,plb6", },
        { .compatible = "ibm,opb", },
index 9e09b835758bc85479531469cfb2dff02b2e4e0d..3ee4a03c14969cccbdea835ed96287cb50d65377 100644 (file)
@@ -29,7 +29,7 @@
 #include <asm/ppc4xx.h>
 #include <linux/i2c.h>
 
-static __initdata struct of_device_id sam440ep_of_bus[] = {
+static const struct of_device_id sam440ep_of_bus[] __initconst = {
        { .compatible = "ibm,plb4", },
        { .compatible = "ibm,opb", },
        { .compatible = "ibm,ebc", },
index cf96ccaa760cd98ca9efc3cedf12f653e7e8f43d..ad272c17c640f561a1ed790c3fd40bc7f6359d9b 100644 (file)
@@ -21,7 +21,7 @@
 #include <asm/ppc4xx.h>
 #include "44x.h"
 
-static struct of_device_id xilinx_of_bus_ids[] __initdata = {
+static const struct of_device_id xilinx_of_bus_ids[] __initconst = {
        { .compatible = "simple-bus", },
        { .compatible = "xlnx,plb-v46-1.00.a", },
        { .compatible = "xlnx,plb-v46-1.02.a", },
index 3a104284b338f700d1ec56478dcb679859db514f..501333cf42cf194743528e0017477a095bbf3bfb 100644 (file)
@@ -28,7 +28,7 @@
 #include <asm/dma.h>
 
 
-static __initdata struct of_device_id warp_of_bus[] = {
+static const struct of_device_id warp_of_bus[] __initconst = {
        { .compatible = "ibm,plb4", },
        { .compatible = "ibm,opb", },
        { .compatible = "ibm,ebc", },
index adb95f03d4d4b20002992977120bd8a27073dc88..e996e007bc44cef80ab30541f4b045bd5e87158c 100644 (file)
@@ -337,7 +337,7 @@ void __init mpc512x_init_IRQ(void)
 /*
  * Nodes to do bus probe on, soc and localbus
  */
-static struct of_device_id __initdata of_bus_ids[] = {
+static const struct of_device_id of_bus_ids[] __initconst = {
        { .compatible = "fsl,mpc5121-immr", },
        { .compatible = "fsl,mpc5121-localbus", },
        { .compatible = "fsl,mpc5121-mbx", },
index 1843bc9320118b84d47cc2e44a5a083b891de6c0..7492de3cf6d058bb38e56bca84dd4f34be6b51e3 100644 (file)
  */
 
 /* mpc5200 device tree match tables */
-static struct of_device_id mpc5200_cdm_ids[] __initdata = {
+static const struct of_device_id mpc5200_cdm_ids[] __initconst = {
        { .compatible = "fsl,mpc5200-cdm", },
        { .compatible = "mpc5200-cdm", },
        {}
 };
 
-static struct of_device_id mpc5200_gpio_ids[] __initdata = {
+static const struct of_device_id mpc5200_gpio_ids[] __initconst = {
        { .compatible = "fsl,mpc5200-gpio", },
        { .compatible = "mpc5200-gpio", },
        {}
index 070d315dd6cd18359a4b62bb0927ca3681f84998..32cae33c4266b990d2dc88d89cc6d6df8ae9a9df 100644 (file)
@@ -30,7 +30,7 @@
 #include <asm/machdep.h>
 #include <asm/mpc52xx.h>
 
-static struct of_device_id mpc5200_gpio_ids[] __initdata = {
+static const struct of_device_id mpc5200_gpio_ids[] __initconst = {
        { .compatible = "fsl,mpc5200-gpio", },
        { .compatible = "mpc5200-gpio", },
        {}
index d7e94f49532a156f78f3fc2da2d98b73e60c0554..26993826a797683e0fea881fc7f6f1c11fa0c703 100644 (file)
 #include <asm/mpc52xx.h>
 
 /* MPC5200 device tree match tables */
-static struct of_device_id mpc52xx_xlb_ids[] __initdata = {
+static const struct of_device_id mpc52xx_xlb_ids[] __initconst = {
        { .compatible = "fsl,mpc5200-xlb", },
        { .compatible = "mpc5200-xlb", },
        {}
 };
-static struct of_device_id mpc52xx_bus_ids[] __initdata = {
+static const struct of_device_id mpc52xx_bus_ids[] __initconst = {
        { .compatible = "fsl,mpc5200-immr", },
        { .compatible = "fsl,mpc5200b-immr", },
        { .compatible = "simple-bus", },
@@ -108,21 +108,21 @@ void __init mpc52xx_declare_of_platform_devices(void)
 /*
  * match tables used by mpc52xx_map_common_devices()
  */
-static struct of_device_id mpc52xx_gpt_ids[] __initdata = {
+static const struct of_device_id mpc52xx_gpt_ids[] __initconst = {
        { .compatible = "fsl,mpc5200-gpt", },
        { .compatible = "mpc5200-gpt", }, /* old */
        {}
 };
-static struct of_device_id mpc52xx_cdm_ids[] __initdata = {
+static const struct of_device_id mpc52xx_cdm_ids[] __initconst = {
        { .compatible = "fsl,mpc5200-cdm", },
        { .compatible = "mpc5200-cdm", }, /* old */
        {}
 };
-static const struct of_device_id mpc52xx_gpio_simple[] = {
+static const struct of_device_id mpc52xx_gpio_simple[] __initconst = {
        { .compatible = "fsl,mpc5200-gpio", },
        {}
 };
-static const struct of_device_id mpc52xx_gpio_wkup[] = {
+static const struct of_device_id mpc52xx_gpio_wkup[] __initconst = {
        { .compatible = "fsl,mpc5200-gpio-wkup", },
        {}
 };
index 37f7a89c10f2581c0366606d471623cc26bf4997..f8f0081759fb7941ab70de2994c07ffb70e8ec5d 100644 (file)
@@ -564,7 +564,7 @@ static int mpc52xx_lpbfifo_remove(struct platform_device *op)
        return 0;
 }
 
-static struct of_device_id mpc52xx_lpbfifo_match[] = {
+static const struct of_device_id mpc52xx_lpbfifo_match[] = {
        { .compatible = "fsl,mpc5200-lpbfifo", },
        {},
 };
index 2898b737deb79e5015c7658568a696254d6f23b5..2944bc84b9d6fc790bc2b3ece7878cdf1ff208ba 100644 (file)
 
 
 /* MPC5200 device tree match tables */
-static struct of_device_id mpc52xx_pic_ids[] __initdata = {
+static const struct of_device_id mpc52xx_pic_ids[] __initconst = {
        { .compatible = "fsl,mpc5200-pic", },
        { .compatible = "mpc5200-pic", },
        {}
 };
-static struct of_device_id mpc52xx_sdma_ids[] __initdata = {
+static const struct of_device_id mpc52xx_sdma_ids[] __initconst = {
        { .compatible = "fsl,mpc5200-bestcomm", },
        { .compatible = "mpc5200-bestcomm", },
        {}
index 79799b29ffe21912dfa437885d2affaf8e916912..3d0c3a01143de70d8bac28a1e884fed0c64cfe24 100644 (file)
@@ -298,7 +298,7 @@ static void __init ep8248e_setup_arch(void)
                ppc_md.progress("ep8248e_setup_arch(), finish", 0);
 }
 
-static  __initdata struct of_device_id of_bus_ids[] = {
+static const struct of_device_id of_bus_ids[] __initconst = {
        { .compatible = "simple-bus", },
        { .compatible = "fsl,ep8248e-bcsr", },
        {},
index 058cc1895c886588a2a7886fd3f4510d5f6b5af1..387b446f416111982ab16390e16ffea65eeb5642 100644 (file)
@@ -180,7 +180,7 @@ static void __init km82xx_setup_arch(void)
                ppc_md.progress("km82xx_setup_arch(), finish", 0);
 }
 
-static  __initdata struct of_device_id of_bus_ids[] = {
+static const struct of_device_id of_bus_ids[] __initconst = {
        { .compatible = "simple-bus", },
        {},
 };
index 6a14cf50f4a27ec21409018f435c48361979321d..d24deacf07d0796120b60517cf7ea849a2bb5630 100644 (file)
@@ -181,7 +181,7 @@ static void __init mpc8272_ads_setup_arch(void)
                ppc_md.progress("mpc8272_ads_setup_arch(), finish", 0);
 }
 
-static struct of_device_id __initdata of_bus_ids[] = {
+static const struct of_device_id of_bus_ids[] __initconst = {
        { .name = "soc", },
        { .name = "cpm", },
        { .name = "localbus", },
index e5f82ec8df17b54d8b8bac693074c741207a649e..3a5164ad10ad73a77a1a77df7c50b7e3420a6732 100644 (file)
@@ -168,7 +168,7 @@ static int __init pq2fads_probe(void)
        return of_flat_dt_is_compatible(root, "fsl,pq2fads");
 }
 
-static struct of_device_id __initdata of_bus_ids[] = {
+static const struct of_device_id of_bus_ids[] __initconst = {
        { .name = "soc", },
        { .name = "cpm", },
        { .name = "localbus", },
index 73997027b08544892c1f4f4bb87e93f41c2ae707..463fa91ee5b663034c9859139e8ab6a11d9a921c 100644 (file)
@@ -214,7 +214,7 @@ static const struct i2c_device_id mcu_ids[] = {
 };
 MODULE_DEVICE_TABLE(i2c, mcu_ids);
 
-static struct of_device_id mcu_of_match_table[] = {
+static const struct of_device_id mcu_of_match_table[] = {
        { .compatible = "fsl,mcu-mpc8349emitx", },
        { },
 };
index 125336f750c6969273d70d09e0eeefc39cb5a0c5..ef9d01a049c16755ddf2616f4a9babfec0867de5 100644 (file)
@@ -114,7 +114,7 @@ void __init mpc83xx_ipic_and_qe_init_IRQ(void)
 }
 #endif /* CONFIG_QUICC_ENGINE */
 
-static struct of_device_id __initdata of_bus_ids[] = {
+static const struct of_device_id of_bus_ids[] __initconst = {
        { .type = "soc", },
        { .compatible = "soc", },
        { .compatible = "simple-bus" },
index a494fa57bdf9b1ef78060531e78729251a472aca..80aea8c4b5a3b2c96d5a2f03490568085d07075b 100644 (file)
@@ -38,7 +38,7 @@
 
 #include "mpc83xx.h"
 
-static struct of_device_id __initdata mpc834x_itx_ids[] = {
+static const struct of_device_id mpc834x_itx_ids[] __initconst = {
        { .compatible = "fsl,pq2pro-localbus", },
        {},
 };
index 4b4c081df94db168e480e10bff1d427debb1c6bb..eeb80e25214df75acbdb83696fad8e5503aac161 100644 (file)
@@ -321,7 +321,7 @@ static const struct platform_suspend_ops mpc83xx_suspend_ops = {
        .end = mpc83xx_suspend_end,
 };
 
-static struct of_device_id pmc_match[];
+static const struct of_device_id pmc_match[];
 static int pmc_probe(struct platform_device *ofdev)
 {
        const struct of_device_id *match;
@@ -420,7 +420,7 @@ static struct pmc_type pmc_types[] = {
        }
 };
 
-static struct of_device_id pmc_match[] = {
+static const struct of_device_id pmc_match[] = {
        {
                .compatible = "fsl,mpc8313-pmc",
                .data = &pmc_types[0],
index 0c1e6903597e18fdee65acc64af163df49848d7f..f22635a71d0117f1a62e441b5a666026376c30b1 100644 (file)
@@ -276,7 +276,7 @@ config CORENET_GENERIC
          For 64bit kernel, the following boards are supported:
            T208x QDS/RDB, T4240 QDS/RDB and B4 QDS
          The following boards are supported for both 32bit and 64bit kernel:
-           P5020 DS, P5040 DS and T104xQDS
+           P5020 DS, P5040 DS and T104xQDS/RDB
 
 endif # FSL_SOC_BOOKE
 
index b564b5e23f7c315d9fb88e2d0c7f5374f9aa24e8..4a9ad871a168e6452e365d512ae20a95578ce216 100644 (file)
@@ -14,7 +14,7 @@
 
 #include "mpc85xx.h"
 
-static struct of_device_id __initdata mpc85xx_common_ids[] = {
+static const struct of_device_id mpc85xx_common_ids[] __initconst = {
        { .type = "soc", },
        { .compatible = "soc", },
        { .compatible = "simple-bus", },
index d22dd85e50bf316891fbb806adf62e171ec24d70..e56b89a792eda51bffd3cfe0e8c9791da7c306b4 100644 (file)
@@ -20,6 +20,7 @@
 #include <asm/time.h>
 #include <asm/machdep.h>
 #include <asm/pci-bridge.h>
+#include <asm/pgtable.h>
 #include <asm/ppc-pci.h>
 #include <mm/mmu_decl.h>
 #include <asm/prom.h>
@@ -67,6 +68,16 @@ void __init corenet_gen_setup_arch(void)
 
        swiotlb_detect_4g();
 
+#if defined(CONFIG_FSL_PCI) && defined(CONFIG_ZONE_DMA32)
+       /*
+        * Inbound windows don't cover the full lower 4 GiB
+        * due to conflicts with PCICSRBAR and outbound windows,
+        * so limit the DMA32 zone to 2 GiB, to allow consistent
+        * allocations to succeed.
+        */
+       limit_zone_pfn(ZONE_DMA32, 1UL << (31 - PAGE_SHIFT));
+#endif
+
        pr_info("%s board\n", ppc_md.name);
 
        mpc85xx_qe_init();
@@ -129,6 +140,9 @@ static const char * const boards[] __initconst = {
        "fsl,B4220QDS",
        "fsl,T1040QDS",
        "fsl,T1042QDS",
+       "fsl,T1040RDB",
+       "fsl,T1042RDB",
+       "fsl,T1042RDB_PI",
        "keymile,kmcoge4",
        NULL
 };
index 3daff7c635693a0e716e246a6be037d360aca662..12019f17f297c7e216e53f3fa06aec53601bf2d3 100644 (file)
@@ -59,7 +59,7 @@ static void ppa8548_show_cpuinfo(struct seq_file *m)
        seq_printf(m, "PLL setting\t: 0x%x\n", ((phid1 >> 24) & 0x3f));
 }
 
-static struct of_device_id __initdata of_bus_ids[] = {
+static const struct of_device_id of_bus_ids[] __initconst = {
        { .name = "soc", },
        { .type = "soc", },
        { .compatible = "simple-bus", },
index 7f26732935496381f92446600f30262dccb4215a..8ad2fe6f200a5b0b5956a61969ca86f6d47fb645 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/kernel.h>
 #include <linux/of_fdt.h>
 #include <asm/machdep.h>
+#include <asm/pgtable.h>
 #include <asm/time.h>
 #include <asm/udbg.h>
 #include <asm/mpic.h>
@@ -44,6 +45,15 @@ static void __init qemu_e500_setup_arch(void)
 
        fsl_pci_assign_primary();
        swiotlb_detect_4g();
+#if defined(CONFIG_FSL_PCI) && defined(CONFIG_ZONE_DMA32)
+       /*
+        * Inbound windows don't cover the full lower 4 GiB
+        * due to conflicts with PCICSRBAR and outbound windows,
+        * so limit the DMA32 zone to 2 GiB, to allow consistent
+        * allocations to succeed.
+        */
+       limit_zone_pfn(ZONE_DMA32, 1UL << (31 - PAGE_SHIFT));
+#endif
        mpc85xx_smp_init();
 }
 
index bb75add670844e3f2e990d0a21e1c48a0ac42c20..8162b0412117a18171cccea8dd7cb61d7b7ef4ac 100644 (file)
@@ -24,7 +24,7 @@
 
 static struct device_node *halt_node;
 
-static struct of_device_id child_match[] = {
+static const struct of_device_id child_match[] = {
        {
                .compatible = "sgy,gpio-halt",
        },
@@ -147,7 +147,7 @@ static int gpio_halt_remove(struct platform_device *pdev)
        return 0;
 }
 
-static struct of_device_id gpio_halt_match[] = {
+static const struct of_device_id gpio_halt_match[] = {
        /* We match on the gpio bus itself and scan the children since they
         * wont be matched against us. We know the bus wont match until it
         * has been registered too. */
index c23f3443880ac96d138c1483120802559a5ee75b..bf17933b20f32c315caf1393d0e666c88cf8876a 100644 (file)
@@ -213,7 +213,7 @@ static long __init mpc86xx_time_init(void)
        return 0;
 }
 
-static __initdata struct of_device_id of_bus_ids[] = {
+static const struct of_device_id of_bus_ids[] __initconst = {
        { .compatible = "simple-bus", },
        { .compatible = "gianfar", },
        { .compatible = "fsl,mpc8641-pcie", },
index 8a6ac20686ea2b0218c89059521788b7377a0ad9..8facf5873866ad94e583cdae37ad42b6573a4d3a 100644 (file)
@@ -200,7 +200,7 @@ static long __init mpc86xx_time_init(void)
        return 0;
 }
 
-static __initdata struct of_device_id of_bus_ids[] = {
+static const struct of_device_id of_bus_ids[] __initconst = {
        { .compatible = "simple-bus", },
        { .compatible = "gianfar", },
        { .compatible = "fsl,mpc8641-pcie", },
index 06c72636f2992d5ac3a632cc28ab05ccb8b6048f..8c9058df5642d13eb30e8e6c66e14523c2dd3d4e 100644 (file)
@@ -190,7 +190,7 @@ static long __init mpc86xx_time_init(void)
        return 0;
 }
 
-static __initdata struct of_device_id of_bus_ids[] = {
+static const struct of_device_id of_bus_ids[] __initconst = {
        { .compatible = "simple-bus", },
        { .compatible = "gianfar", },
        { .compatible = "fsl,mpc8641-pcie", },
index d479d68fbb2bc5017b00b161975533be0c7181cf..55413a547ea8eb0779f28f00835c78fc8b68d75c 100644 (file)
@@ -85,7 +85,7 @@ static void __init mpc8610_suspend_init(void)
 static inline void mpc8610_suspend_init(void) { }
 #endif /* CONFIG_SUSPEND */
 
-static struct of_device_id __initdata mpc8610_ids[] = {
+static const struct of_device_id mpc8610_ids[] __initconst = {
        { .compatible = "fsl,mpc8610-immr", },
        { .compatible = "fsl,mpc8610-guts", },
        { .compatible = "simple-bus", },
index e8bf3fae56060dfa2645701db57839e8092f8e28..07ccb1b0cc7de168cc46eec53c8723a8c43491d1 100644 (file)
@@ -127,7 +127,7 @@ mpc86xx_time_init(void)
        return 0;
 }
 
-static __initdata struct of_device_id of_bus_ids[] = {
+static const struct of_device_id of_bus_ids[] __initconst = {
        { .compatible = "simple-bus", },
        { .compatible = "fsl,srio", },
        { .compatible = "gianfar", },
index b47a8fd0f3d30ad4d2d3e1bfa45a43761bc9e8f1..6810b71d54a795803a6a8cdc6d021af84ebf4b21 100644 (file)
@@ -92,7 +92,7 @@ mpc86xx_time_init(void)
        return 0;
 }
 
-static __initdata struct of_device_id of_bus_ids[] = {
+static const struct of_device_id of_bus_ids[] __initconst = {
        { .compatible = "simple-bus", },
        { .compatible = "gianfar", },
        { .compatible = "fsl,mpc8641-pcie", },
index 82363e98f50e4bc05240df0c147e65a3168b2c65..61cae4c1edb8532f47acd9fa549eda858aebdcc3 100644 (file)
@@ -92,7 +92,7 @@ static int __init adder875_probe(void)
        return of_flat_dt_is_compatible(root, "analogue-and-micro,adder875");
 }
 
-static __initdata struct of_device_id of_bus_ids[] = {
+static const struct of_device_id of_bus_ids[] __initconst = {
        { .compatible = "simple-bus", },
        {},
 };
index e62166681d0811113680965696944c8c23514db3..2bedeb7d5f8f143b97183cb8cb725911b449ca4a 100644 (file)
@@ -147,7 +147,7 @@ static int __init ep88xc_probe(void)
        return of_flat_dt_is_compatible(root, "fsl,ep88xc");
 }
 
-static struct of_device_id __initdata of_bus_ids[] = {
+static const struct of_device_id of_bus_ids[] __initconst = {
        { .name = "soc", },
        { .name = "cpm", },
        { .name = "localbus", },
index 63084640c5c5af872aba11a94979324cec02ccd6..78180c5e73ffc293f9122d147a3981194ff6574e 100644 (file)
@@ -122,7 +122,7 @@ static int __init mpc86xads_probe(void)
        return of_flat_dt_is_compatible(root, "fsl,mpc866ads");
 }
 
-static struct of_device_id __initdata of_bus_ids[] = {
+static const struct of_device_id of_bus_ids[] __initconst = {
        { .name = "soc", },
        { .name = "cpm", },
        { .name = "localbus", },
index 5921dcb498fd2bdf5957563a143f68b9463fe791..4d62bf9dc7894fba257488dbe1ec482be32e2cf5 100644 (file)
@@ -197,7 +197,7 @@ static int __init mpc885ads_probe(void)
        return of_flat_dt_is_compatible(root, "fsl,mpc885ads");
 }
 
-static struct of_device_id __initdata of_bus_ids[] = {
+static const struct of_device_id of_bus_ids[] __initconst = {
        { .name = "soc", },
        { .name = "cpm", },
        { .name = "localbus", },
index dda607807def7d8a782c212ae74dc270858abc5d..bee47a2b23e66b9f487adc565aa3d879c4ae5296 100644 (file)
@@ -124,7 +124,7 @@ static int __init tqm8xx_probe(void)
        return of_flat_dt_is_compatible(node, "tqc,tqm8xx");
 }
 
-static struct of_device_id __initdata of_bus_ids[] = {
+static const struct of_device_id of_bus_ids[] __initconst = {
        { .name = "soc", },
        { .name = "cpm", },
        { .name = "localbus", },
index 7d9ee3d8c61810fdd0fc5cbd17ca8721623f346d..76483e3acd60e432a83d568b49924224eec83bbf 100644 (file)
@@ -116,6 +116,12 @@ config POWER6_CPU
 config POWER7_CPU
        bool "POWER7"
        depends on PPC_BOOK3S_64
+       select ARCH_HAS_FAST_MULTIPLIER
+
+config POWER8_CPU
+       bool "POWER8"
+       depends on PPC_BOOK3S_64
+       select ARCH_HAS_FAST_MULTIPLIER
 
 config E5500_CPU
        bool "Freescale e5500"
index 9978f594cac013a5f94095846a4e98816784f2a7..870b6dbd4d18affa403b7dc0a8037da0c29a58e4 100644 (file)
@@ -86,6 +86,7 @@ config SPU_FS_64K_LS
 config SPU_BASE
        bool
        default n
+       select PPC_COPRO_BASE
 
 config CBE_RAS
        bool "RAS features for bare metal Cell BE"
index fe053e7c73ee95ae21dc618232c19190930c309a..2d16884f67b9dbca7d56752d9cc5a1711eaf1d24 100644 (file)
@@ -20,7 +20,7 @@ spu-manage-$(CONFIG_PPC_CELL_COMMON)  += spu_manage.o
 
 obj-$(CONFIG_SPU_BASE)                 += spu_callbacks.o spu_base.o \
                                           spu_notify.o \
-                                          spu_syscalls.o spu_fault.o \
+                                          spu_syscalls.o \
                                           $(spu-priv1-y) \
                                           $(spu-manage-y) \
                                           spufs/
index 173568140a32ec0df09c0269107c1caa7ec035c6..2b98a36ef8fb740ac7b087ff1cb856400af841d3 100644 (file)
@@ -454,7 +454,7 @@ static struct celleb_phb_spec celleb_fake_pci_spec __initdata = {
        .setup = celleb_setup_fake_pci,
 };
 
-static struct of_device_id celleb_phb_match[] __initdata = {
+static const struct of_device_id celleb_phb_match[] __initconst = {
        {
                .name = "pci-pseudo",
                .data = &celleb_fake_pci_spec,
index 1d5a4d8ddad9dd221f110ba3768db00134055bad..34e8ce2976aac3ff3d2ee7ac5500cda0698367d9 100644 (file)
@@ -102,7 +102,7 @@ static void __init celleb_setup_arch_common(void)
 #endif
 }
 
-static struct of_device_id celleb_bus_ids[] __initdata = {
+static const struct of_device_id celleb_bus_ids[] __initconst = {
        { .type = "scc", },
        { .type = "ioif", },    /* old style */
        {},
index 2930d1e81a05c0f960e08e344ee4ff6601a3bbf4..ffcbd242e6693de80a632be5100f1c8d7b1fd072 100644 (file)
@@ -76,10 +76,6 @@ static LIST_HEAD(spu_full_list);
 static DEFINE_SPINLOCK(spu_full_list_lock);
 static DEFINE_MUTEX(spu_full_list_mutex);
 
-struct spu_slb {
-       u64 esid, vsid;
-};
-
 void spu_invalidate_slbs(struct spu *spu)
 {
        struct spu_priv2 __iomem *priv2 = spu->priv2;
@@ -149,7 +145,7 @@ static void spu_restart_dma(struct spu *spu)
        }
 }
 
-static inline void spu_load_slb(struct spu *spu, int slbe, struct spu_slb *slb)
+static inline void spu_load_slb(struct spu *spu, int slbe, struct copro_slb *slb)
 {
        struct spu_priv2 __iomem *priv2 = spu->priv2;
 
@@ -167,45 +163,12 @@ static inline void spu_load_slb(struct spu *spu, int slbe, struct spu_slb *slb)
 
 static int __spu_trap_data_seg(struct spu *spu, unsigned long ea)
 {
-       struct mm_struct *mm = spu->mm;
-       struct spu_slb slb;
-       int psize;
-
-       pr_debug("%s\n", __func__);
-
-       slb.esid = (ea & ESID_MASK) | SLB_ESID_V;
+       struct copro_slb slb;
+       int ret;
 
-       switch(REGION_ID(ea)) {
-       case USER_REGION_ID:
-#ifdef CONFIG_PPC_MM_SLICES
-               psize = get_slice_psize(mm, ea);
-#else
-               psize = mm->context.user_psize;
-#endif
-               slb.vsid = (get_vsid(mm->context.id, ea, MMU_SEGSIZE_256M)
-                               << SLB_VSID_SHIFT) | SLB_VSID_USER;
-               break;
-       case VMALLOC_REGION_ID:
-               if (ea < VMALLOC_END)
-                       psize = mmu_vmalloc_psize;
-               else
-                       psize = mmu_io_psize;
-               slb.vsid = (get_kernel_vsid(ea, MMU_SEGSIZE_256M)
-                               << SLB_VSID_SHIFT) | SLB_VSID_KERNEL;
-               break;
-       case KERNEL_REGION_ID:
-               psize = mmu_linear_psize;
-               slb.vsid = (get_kernel_vsid(ea, MMU_SEGSIZE_256M)
-                               << SLB_VSID_SHIFT) | SLB_VSID_KERNEL;
-               break;
-       default:
-               /* Future: support kernel segments so that drivers
-                * can use SPUs.
-                */
-               pr_debug("invalid region access at %016lx\n", ea);
-               return 1;
-       }
-       slb.vsid |= mmu_psize_defs[psize].sllp;
+       ret = copro_calculate_slb(spu->mm, ea, &slb);
+       if (ret)
+               return ret;
 
        spu_load_slb(spu, spu->slb_replace, &slb);
 
@@ -253,7 +216,7 @@ static int __spu_trap_data_map(struct spu *spu, unsigned long ea, u64 dsisr)
        return 0;
 }
 
-static void __spu_kernel_slb(void *addr, struct spu_slb *slb)
+static void __spu_kernel_slb(void *addr, struct copro_slb *slb)
 {
        unsigned long ea = (unsigned long)addr;
        u64 llp;
@@ -272,7 +235,7 @@ static void __spu_kernel_slb(void *addr, struct spu_slb *slb)
  * Given an array of @nr_slbs SLB entries, @slbs, return non-zero if the
  * address @new_addr is present.
  */
-static inline int __slb_present(struct spu_slb *slbs, int nr_slbs,
+static inline int __slb_present(struct copro_slb *slbs, int nr_slbs,
                void *new_addr)
 {
        unsigned long ea = (unsigned long)new_addr;
@@ -297,7 +260,7 @@ static inline int __slb_present(struct spu_slb *slbs, int nr_slbs,
 void spu_setup_kernel_slbs(struct spu *spu, struct spu_lscsa *lscsa,
                void *code, int code_size)
 {
-       struct spu_slb slbs[4];
+       struct copro_slb slbs[4];
        int i, nr_slbs = 0;
        /* start and end addresses of both mappings */
        void *addrs[] = {
diff --git a/arch/powerpc/platforms/cell/spu_fault.c b/arch/powerpc/platforms/cell/spu_fault.c
deleted file mode 100644 (file)
index 641e727..0000000
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * SPU mm fault handler
- *
- * (C) Copyright IBM Deutschland Entwicklung GmbH 2007
- *
- * Author: Arnd Bergmann <arndb@de.ibm.com>
- * Author: Jeremy Kerr <jk@ozlabs.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-#include <linux/sched.h>
-#include <linux/mm.h>
-#include <linux/export.h>
-
-#include <asm/spu.h>
-#include <asm/spu_csa.h>
-
-/*
- * This ought to be kept in sync with the powerpc specific do_page_fault
- * function. Currently, there are a few corner cases that we haven't had
- * to handle fortunately.
- */
-int spu_handle_mm_fault(struct mm_struct *mm, unsigned long ea,
-               unsigned long dsisr, unsigned *flt)
-{
-       struct vm_area_struct *vma;
-       unsigned long is_write;
-       int ret;
-
-       if (mm == NULL)
-               return -EFAULT;
-
-       if (mm->pgd == NULL)
-               return -EFAULT;
-
-       down_read(&mm->mmap_sem);
-       ret = -EFAULT;
-       vma = find_vma(mm, ea);
-       if (!vma)
-               goto out_unlock;
-
-       if (ea < vma->vm_start) {
-               if (!(vma->vm_flags & VM_GROWSDOWN))
-                       goto out_unlock;
-               if (expand_stack(vma, ea))
-                       goto out_unlock;
-       }
-
-       is_write = dsisr & MFC_DSISR_ACCESS_PUT;
-       if (is_write) {
-               if (!(vma->vm_flags & VM_WRITE))
-                       goto out_unlock;
-       } else {
-               if (dsisr & MFC_DSISR_ACCESS_DENIED)
-                       goto out_unlock;
-               if (!(vma->vm_flags & (VM_READ | VM_EXEC)))
-                       goto out_unlock;
-       }
-
-       ret = 0;
-       *flt = handle_mm_fault(mm, vma, ea, is_write ? FAULT_FLAG_WRITE : 0);
-       if (unlikely(*flt & VM_FAULT_ERROR)) {
-               if (*flt & VM_FAULT_OOM) {
-                       ret = -ENOMEM;
-                       goto out_unlock;
-               } else if (*flt & VM_FAULT_SIGBUS) {
-                       ret = -EFAULT;
-                       goto out_unlock;
-               }
-               BUG();
-       }
-
-       if (*flt & VM_FAULT_MAJOR)
-               current->maj_flt++;
-       else
-               current->min_flt++;
-
-out_unlock:
-       up_read(&mm->mmap_sem);
-       return ret;
-}
-EXPORT_SYMBOL_GPL(spu_handle_mm_fault);
index 8cb6260cc80fa66231a4e7d5205ebb94e3a9b9a2..e45894a081185bc92142ad4b75a2eec9138e5fe0 100644 (file)
@@ -138,7 +138,7 @@ int spufs_handle_class1(struct spu_context *ctx)
        if (ctx->state == SPU_STATE_RUNNABLE)
                ctx->spu->stats.hash_flt++;
 
-       /* we must not hold the lock when entering spu_handle_mm_fault */
+       /* we must not hold the lock when entering copro_handle_mm_fault */
        spu_release(ctx);
 
        access = (_PAGE_PRESENT | _PAGE_USER);
@@ -149,7 +149,7 @@ int spufs_handle_class1(struct spu_context *ctx)
 
        /* hashing failed, so try the actual fault handler */
        if (ret)
-               ret = spu_handle_mm_fault(current->mm, ea, dsisr, &flt);
+               ret = copro_handle_mm_fault(current->mm, ea, dsisr, &flt);
 
        /*
         * This is nasty: we need the state_mutex for all the bookkeeping even
index 7044fd36197b90a42af0a3196aabc5c9bd2e971b..5b77b1919fd21b5007f5dadc10e1f8a2129553aa 100644 (file)
@@ -258,7 +258,7 @@ static void chrp_init_early(void)
        struct device_node *node;
        const char *property;
 
-       if (strstr(cmd_line, "console="))
+       if (strstr(boot_command_line, "console="))
                return;
        /* find the boot console from /chosen/stdout */
        if (!of_chosen)
index a138e14bad2e7292565bf807be59e784e1e77f89..bd4ba5d7d568f3064675e51ea46c389ede739e5a 100644 (file)
@@ -90,7 +90,7 @@ define_machine(gamecube) {
 };
 
 
-static struct of_device_id gamecube_of_bus[] = {
+static const struct of_device_id gamecube_of_bus[] = {
        { .compatible = "nintendo,flipper", },
        { },
 };
index 455e7c08742290a6bfb175dc3f3d730829c5545b..168e1d80b2e5dd58ace20584c265b9c539c3d7b1 100644 (file)
@@ -21,7 +21,7 @@
 
 #include "mpc10x.h"
 
-static __initdata struct of_device_id of_bus_ids[] = {
+static const struct of_device_id of_bus_ids[] __initconst = {
        { .type = "soc", },
        { .compatible = "simple-bus", },
        {},
index 25e3bfb64efbe7d0b9a5e8b0e5ad26d2affd1394..1613303177e64e6b3b60830c90b6be50a56e01a7 100644 (file)
@@ -149,7 +149,7 @@ static int __init mvme5100_add_bridge(struct device_node *dev)
        return 0;
 }
 
-static struct of_device_id mvme5100_of_bus_ids[] __initdata = {
+static const struct of_device_id mvme5100_of_bus_ids[] __initconst = {
        { .compatible = "hawk-bridge", },
        {},
 };
index c458b60d14c4f78064485f209a026438e73f1e9a..d572833ebd00cc3e27b1a7671292335f2f2507b5 100644 (file)
@@ -24,7 +24,7 @@
 #include "mpc10x.h"
 
 
-static __initdata struct of_device_id storcenter_of_bus[] = {
+static const struct of_device_id storcenter_of_bus[] __initconst = {
        { .name = "soc", },
        {},
 };
index 6d8dadf19f0b84e95cd58fbed9bfbdd1101f3126..388e29bab8f61a3fa673efd13ab517383ef6e302 100644 (file)
@@ -235,7 +235,7 @@ define_machine(wii) {
        .machine_shutdown       = wii_shutdown,
 };
 
-static struct of_device_id wii_of_bus[] = {
+static const struct of_device_id wii_of_bus[] = {
        { .compatible = "nintendo,hollywood", },
        { },
 };
index 15adee544638b6c11fcea4f0a8c7d813403496c5..ada33358950dcd582d106c068724c2ddb892cc95 100644 (file)
@@ -290,7 +290,7 @@ static int gpio_mdio_remove(struct platform_device *dev)
        return 0;
 }
 
-static struct of_device_id gpio_mdio_match[] =
+static const struct of_device_id gpio_mdio_match[] =
 {
        {
                .compatible      = "gpio-mdio",
index 8c54de6d8ec426e11e7a84ee7193159176f0b482..d71b2c7e84031ba4c94e41664b365eb14c1e24b5 100644 (file)
@@ -393,7 +393,7 @@ static inline void pasemi_pcmcia_init(void)
 #endif
 
 
-static struct of_device_id pasemi_bus_ids[] = {
+static const struct of_device_id pasemi_bus_ids[] = {
        /* Unfortunately needed for legacy firmwares */
        { .type = "localbus", },
        { .type = "sdc", },
index 141f8899a633f04182d65179c410b53a78a74109..b127a29ac526dd0e27e5f5a7b487c0d58c2ae9c1 100644 (file)
@@ -336,7 +336,7 @@ static void __init pmac_setup_arch(void)
 #endif
 
 #ifdef CONFIG_ADB
-       if (strstr(cmd_line, "adb_sync")) {
+       if (strstr(boot_command_line, "adb_sync")) {
                extern int __adb_probe_sync;
                __adb_probe_sync = 1;
        }
@@ -460,7 +460,7 @@ pmac_halt(void)
 static void __init pmac_init_early(void)
 {
        /* Enable early btext debug if requested */
-       if (strstr(cmd_line, "btextdbg")) {
+       if (strstr(boot_command_line, "btextdbg")) {
                udbg_adb_init_early();
                register_early_udbg_console();
        }
@@ -469,8 +469,8 @@ static void __init pmac_init_early(void)
        pmac_feature_init();
 
        /* Initialize debug stuff */
-       udbg_scc_init(!!strstr(cmd_line, "sccdbg"));
-       udbg_adb_init(!!strstr(cmd_line, "btextdbg"));
+       udbg_scc_init(!!strstr(boot_command_line, "sccdbg"));
+       udbg_adb_init(!!strstr(boot_command_line, "btextdbg"));
 
 #ifdef CONFIG_PPC64
        iommu_init_early_dart();
index c945bed4dc9e7439c929350effb3b583d3f3a740..426814a2ede34db7f83c6405a123aa4317a3008c 100644 (file)
@@ -66,6 +66,54 @@ static struct notifier_block ioda_eeh_nb = {
 };
 
 #ifdef CONFIG_DEBUG_FS
+static ssize_t ioda_eeh_ei_write(struct file *filp,
+                                const char __user *user_buf,
+                                size_t count, loff_t *ppos)
+{
+       struct pci_controller *hose = filp->private_data;
+       struct pnv_phb *phb = hose->private_data;
+       struct eeh_dev *edev;
+       struct eeh_pe *pe;
+       int pe_no, type, func;
+       unsigned long addr, mask;
+       char buf[50];
+       int ret;
+
+       if (!phb->eeh_ops || !phb->eeh_ops->err_inject)
+               return -ENXIO;
+
+       ret = simple_write_to_buffer(buf, sizeof(buf), ppos, user_buf, count);
+       if (!ret)
+               return -EFAULT;
+
+       /* Retrieve parameters */
+       ret = sscanf(buf, "%x:%x:%x:%lx:%lx",
+                    &pe_no, &type, &func, &addr, &mask);
+       if (ret != 5)
+               return -EINVAL;
+
+       /* Retrieve PE */
+       edev = kzalloc(sizeof(*edev), GFP_KERNEL);
+       if (!edev)
+               return -ENOMEM;
+       edev->phb = hose;
+       edev->pe_config_addr = pe_no;
+       pe = eeh_pe_get(edev);
+       kfree(edev);
+       if (!pe)
+               return -ENODEV;
+
+       /* Do error injection */
+       ret = phb->eeh_ops->err_inject(pe, type, func, addr, mask);
+       return ret < 0 ? ret : count;
+}
+
+static const struct file_operations ioda_eeh_ei_fops = {
+       .open   = simple_open,
+       .llseek = no_llseek,
+       .write  = ioda_eeh_ei_write,
+};
+
 static int ioda_eeh_dbgfs_set(void *data, int offset, u64 val)
 {
        struct pci_controller *hose = data;
@@ -152,6 +200,10 @@ static int ioda_eeh_post_init(struct pci_controller *hose)
        if (!phb->has_dbgfs && phb->dbgfs) {
                phb->has_dbgfs = 1;
 
+               debugfs_create_file("err_injct", 0200,
+                                   phb->dbgfs, hose,
+                                   &ioda_eeh_ei_fops);
+
                debugfs_create_file("err_injct_outbound", 0600,
                                    phb->dbgfs, hose,
                                    &ioda_eeh_outb_dbgfs_ops);
@@ -189,6 +241,7 @@ static int ioda_eeh_set_option(struct eeh_pe *pe, int option)
 {
        struct pci_controller *hose = pe->phb;
        struct pnv_phb *phb = hose->private_data;
+       bool freeze_pe = false;
        int enable, ret = 0;
        s64 rc;
 
@@ -212,6 +265,10 @@ static int ioda_eeh_set_option(struct eeh_pe *pe, int option)
        case EEH_OPT_THAW_DMA:
                enable = OPAL_EEH_ACTION_CLEAR_FREEZE_DMA;
                break;
+       case EEH_OPT_FREEZE_PE:
+               freeze_pe = true;
+               enable = OPAL_EEH_ACTION_SET_FREEZE_ALL;
+               break;
        default:
                pr_warn("%s: Invalid option %d\n",
                        __func__, option);
@@ -219,17 +276,35 @@ static int ioda_eeh_set_option(struct eeh_pe *pe, int option)
        }
 
        /* If PHB supports compound PE, to handle it */
-       if (phb->unfreeze_pe) {
-               ret = phb->unfreeze_pe(phb, pe->addr, enable);
+       if (freeze_pe) {
+               if (phb->freeze_pe) {
+                       phb->freeze_pe(phb, pe->addr);
+               } else {
+                       rc = opal_pci_eeh_freeze_set(phb->opal_id,
+                                                    pe->addr,
+                                                    enable);
+                       if (rc != OPAL_SUCCESS) {
+                               pr_warn("%s: Failure %lld freezing "
+                                       "PHB#%x-PE#%x\n",
+                                       __func__, rc,
+                                       phb->hose->global_number, pe->addr);
+                               ret = -EIO;
+                       }
+               }
        } else {
-               rc = opal_pci_eeh_freeze_clear(phb->opal_id,
-                                              pe->addr,
-                                              enable);
-               if (rc != OPAL_SUCCESS) {
-                       pr_warn("%s: Failure %lld enable %d for PHB#%x-PE#%x\n",
-                               __func__, rc, option, phb->hose->global_number,
-                               pe->addr);
-                       ret = -EIO;
+               if (phb->unfreeze_pe) {
+                       ret = phb->unfreeze_pe(phb, pe->addr, enable);
+               } else {
+                       rc = opal_pci_eeh_freeze_clear(phb->opal_id,
+                                                      pe->addr,
+                                                      enable);
+                       if (rc != OPAL_SUCCESS) {
+                               pr_warn("%s: Failure %lld enable %d "
+                                       "for PHB#%x-PE#%x\n",
+                                       __func__, rc, option,
+                                       phb->hose->global_number, pe->addr);
+                               ret = -EIO;
+                       }
                }
        }
 
@@ -439,11 +514,11 @@ int ioda_eeh_phb_reset(struct pci_controller *hose, int option)
        if (option == EEH_RESET_FUNDAMENTAL ||
            option == EEH_RESET_HOT)
                rc = opal_pci_reset(phb->opal_id,
-                               OPAL_PHB_COMPLETE,
+                               OPAL_RESET_PHB_COMPLETE,
                                OPAL_ASSERT_RESET);
        else if (option == EEH_RESET_DEACTIVATE)
                rc = opal_pci_reset(phb->opal_id,
-                               OPAL_PHB_COMPLETE,
+                               OPAL_RESET_PHB_COMPLETE,
                                OPAL_DEASSERT_RESET);
        if (rc < 0)
                goto out;
@@ -483,15 +558,15 @@ static int ioda_eeh_root_reset(struct pci_controller *hose, int option)
         */
        if (option == EEH_RESET_FUNDAMENTAL)
                rc = opal_pci_reset(phb->opal_id,
-                               OPAL_PCI_FUNDAMENTAL_RESET,
+                               OPAL_RESET_PCI_FUNDAMENTAL,
                                OPAL_ASSERT_RESET);
        else if (option == EEH_RESET_HOT)
                rc = opal_pci_reset(phb->opal_id,
-                               OPAL_PCI_HOT_RESET,
+                               OPAL_RESET_PCI_HOT,
                                OPAL_ASSERT_RESET);
        else if (option == EEH_RESET_DEACTIVATE)
                rc = opal_pci_reset(phb->opal_id,
-                               OPAL_PCI_HOT_RESET,
+                               OPAL_RESET_PCI_HOT,
                                OPAL_DEASSERT_RESET);
        if (rc < 0)
                goto out;
@@ -607,6 +682,31 @@ static int ioda_eeh_reset(struct eeh_pe *pe, int option)
        if (pe->type & EEH_PE_PHB) {
                ret = ioda_eeh_phb_reset(hose, option);
        } else {
+               struct pnv_phb *phb;
+               s64 rc;
+
+               /*
+                * The frozen PE might be caused by PAPR error injection
+                * registers, which are expected to be cleared after hitting
+                * frozen PE as stated in the hardware spec. Unfortunately,
+                * that's not true on P7IOC. So we have to clear it manually
+                * to avoid recursive EEH errors during recovery.
+                */
+               phb = hose->private_data;
+               if (phb->model == PNV_PHB_MODEL_P7IOC &&
+                   (option == EEH_RESET_HOT ||
+                   option == EEH_RESET_FUNDAMENTAL)) {
+                       rc = opal_pci_reset(phb->opal_id,
+                                           OPAL_RESET_PHB_ERROR,
+                                           OPAL_ASSERT_RESET);
+                       if (rc != OPAL_SUCCESS) {
+                               pr_warn("%s: Failure %lld clearing "
+                                       "error injection registers\n",
+                                       __func__, rc);
+                               return -EIO;
+                       }
+               }
+
                bus = eeh_pe_bus_get(pe);
                if (pci_is_root_bus(bus) ||
                    pci_is_root_bus(bus->parent))
@@ -628,8 +728,8 @@ static int ioda_eeh_reset(struct eeh_pe *pe, int option)
  * Retrieve error log, which contains log from device driver
  * and firmware.
  */
-int ioda_eeh_get_log(struct eeh_pe *pe, int severity,
-                    char *drv_log, unsigned long len)
+static int ioda_eeh_get_log(struct eeh_pe *pe, int severity,
+                           char *drv_log, unsigned long len)
 {
        pnv_pci_dump_phb_diag_data(pe->phb, pe->data);
 
@@ -650,6 +750,49 @@ static int ioda_eeh_configure_bridge(struct eeh_pe *pe)
        return 0;
 }
 
+static int ioda_eeh_err_inject(struct eeh_pe *pe, int type, int func,
+                              unsigned long addr, unsigned long mask)
+{
+       struct pci_controller *hose = pe->phb;
+       struct pnv_phb *phb = hose->private_data;
+       s64 ret;
+
+       /* Sanity check on error type */
+       if (type != OPAL_ERR_INJECT_TYPE_IOA_BUS_ERR &&
+           type != OPAL_ERR_INJECT_TYPE_IOA_BUS_ERR64) {
+               pr_warn("%s: Invalid error type %d\n",
+                       __func__, type);
+               return -ERANGE;
+       }
+
+       if (func < OPAL_ERR_INJECT_FUNC_IOA_LD_MEM_ADDR ||
+           func > OPAL_ERR_INJECT_FUNC_IOA_DMA_WR_TARGET) {
+               pr_warn("%s: Invalid error function %d\n",
+                       __func__, func);
+               return -ERANGE;
+       }
+
+       /* Firmware supports error injection ? */
+       if (!opal_check_token(OPAL_PCI_ERR_INJECT)) {
+               pr_warn("%s: Firmware doesn't support error injection\n",
+                       __func__);
+               return -ENXIO;
+       }
+
+       /* Do error injection */
+       ret = opal_pci_err_inject(phb->opal_id, pe->addr,
+                                 type, func, addr, mask);
+       if (ret != OPAL_SUCCESS) {
+               pr_warn("%s: Failure %lld injecting error "
+                       "%d-%d to PHB#%x-PE#%x\n",
+                       __func__, ret, type, func,
+                       hose->global_number, pe->addr);
+               return -EIO;
+       }
+
+       return 0;
+}
+
 static void ioda_eeh_hub_diag_common(struct OpalIoP7IOCErrorData *data)
 {
        /* GEM */
@@ -743,14 +886,12 @@ static int ioda_eeh_get_pe(struct pci_controller *hose,
         * the master PE because slave PE is invisible
         * to EEH core.
         */
-       if (phb->get_pe_state) {
-               pnv_pe = &phb->ioda.pe_array[pe_no];
-               if (pnv_pe->flags & PNV_IODA_PE_SLAVE) {
-                       pnv_pe = pnv_pe->master;
-                       WARN_ON(!pnv_pe ||
-                               !(pnv_pe->flags & PNV_IODA_PE_MASTER));
-                       pe_no = pnv_pe->pe_number;
-               }
+       pnv_pe = &phb->ioda.pe_array[pe_no];
+       if (pnv_pe->flags & PNV_IODA_PE_SLAVE) {
+               pnv_pe = pnv_pe->master;
+               WARN_ON(!pnv_pe ||
+                       !(pnv_pe->flags & PNV_IODA_PE_MASTER));
+               pe_no = pnv_pe->pe_number;
        }
 
        /* Find the PE according to PE# */
@@ -761,15 +902,37 @@ static int ioda_eeh_get_pe(struct pci_controller *hose,
        if (!dev_pe)
                return -EEXIST;
 
-       /*
-        * At this point, we're sure the compound PE should
-        * be put into frozen state.
-        */
+       /* Freeze the (compound) PE */
        *pe = dev_pe;
-       if (phb->freeze_pe &&
-           !(dev_pe->state & EEH_PE_ISOLATED))
+       if (!(dev_pe->state & EEH_PE_ISOLATED))
                phb->freeze_pe(phb, pe_no);
 
+       /*
+        * At this point, we're sure the (compound) PE should
+        * have been frozen. However, we still need poke until
+        * hitting the frozen PE on top level.
+        */
+       dev_pe = dev_pe->parent;
+       while (dev_pe && !(dev_pe->type & EEH_PE_PHB)) {
+               int ret;
+               int active_flags = (EEH_STATE_MMIO_ACTIVE |
+                                   EEH_STATE_DMA_ACTIVE);
+
+               ret = eeh_ops->get_state(dev_pe, NULL);
+               if (ret <= 0 || (ret & active_flags) == active_flags) {
+                       dev_pe = dev_pe->parent;
+                       continue;
+               }
+
+               /* Frozen parent PE */
+               *pe = dev_pe;
+               if (!(dev_pe->state & EEH_PE_ISOLATED))
+                       phb->freeze_pe(phb, dev_pe->addr);
+
+               /* Next one */
+               dev_pe = dev_pe->parent;
+       }
+
        return 0;
 }
 
@@ -971,5 +1134,6 @@ struct pnv_eeh_ops ioda_eeh_ops = {
        .reset                  = ioda_eeh_reset,
        .get_log                = ioda_eeh_get_log,
        .configure_bridge       = ioda_eeh_configure_bridge,
+       .err_inject             = ioda_eeh_err_inject,
        .next_error             = ioda_eeh_next_error
 };
index fd7a16f855edffd1315b055800b7e4de6ab28fc3..3e89cbf5588547660ed9f3543735c6b644ae77e9 100644 (file)
@@ -358,6 +358,31 @@ static int powernv_eeh_configure_bridge(struct eeh_pe *pe)
        return ret;
 }
 
+/**
+ * powernv_pe_err_inject - Inject specified error to the indicated PE
+ * @pe: the indicated PE
+ * @type: error type
+ * @func: specific error type
+ * @addr: address
+ * @mask: address mask
+ *
+ * The routine is called to inject specified error, which is
+ * determined by @type and @func, to the indicated PE for
+ * testing purpose.
+ */
+static int powernv_eeh_err_inject(struct eeh_pe *pe, int type, int func,
+                                 unsigned long addr, unsigned long mask)
+{
+       struct pci_controller *hose = pe->phb;
+       struct pnv_phb *phb = hose->private_data;
+       int ret = -EEXIST;
+
+       if (phb->eeh_ops && phb->eeh_ops->err_inject)
+               ret = phb->eeh_ops->err_inject(pe, type, func, addr, mask);
+
+       return ret;
+}
+
 /**
  * powernv_eeh_next_error - Retrieve next EEH error to handle
  * @pe: Affected PE
@@ -414,6 +439,7 @@ static struct eeh_ops powernv_eeh_ops = {
        .wait_state             = powernv_eeh_wait_state,
        .get_log                = powernv_eeh_get_log,
        .configure_bridge       = powernv_eeh_configure_bridge,
+       .err_inject             = powernv_eeh_err_inject,
        .read_config            = pnv_pci_cfg_read,
        .write_config           = pnv_pci_cfg_write,
        .next_error             = powernv_eeh_next_error,
index 85bb8fff7947f9d752d4f3adddbc0b99e76b78be..23260f7dfa7aeca7446dcfcc6e59f5ced346e6b1 100644 (file)
@@ -112,7 +112,7 @@ static ssize_t init_dump_show(struct dump_obj *dump_obj,
                              struct dump_attribute *attr,
                              char *buf)
 {
-       return sprintf(buf, "1 - initiate dump\n");
+       return sprintf(buf, "1 - initiate Service Processor(FSP) dump\n");
 }
 
 static int64_t dump_fips_init(uint8_t type)
@@ -121,7 +121,7 @@ static int64_t dump_fips_init(uint8_t type)
 
        rc = opal_dump_init(type);
        if (rc)
-               pr_warn("%s: Failed to initiate FipS dump (%d)\n",
+               pr_warn("%s: Failed to initiate FSP dump (%d)\n",
                        __func__, rc);
        return rc;
 }
@@ -131,8 +131,12 @@ static ssize_t init_dump_store(struct dump_obj *dump_obj,
                               const char *buf,
                               size_t count)
 {
-       dump_fips_init(DUMP_TYPE_FSP);
-       pr_info("%s: Initiated FSP dump\n", __func__);
+       int rc;
+
+       rc = dump_fips_init(DUMP_TYPE_FSP);
+       if (rc == OPAL_SUCCESS)
+               pr_info("%s: Initiated FSP dump\n", __func__);
+
        return count;
 }
 
@@ -297,7 +301,7 @@ static ssize_t dump_attr_read(struct file *filep, struct kobject *kobj,
                         * and rely on userspace to ask us to try
                         * again.
                         */
-                       pr_info("%s: Platform dump partially read.ID = 0x%x\n",
+                       pr_info("%s: Platform dump partially read. ID = 0x%x\n",
                                __func__, dump->id);
                        return -EIO;
                }
@@ -423,6 +427,10 @@ void __init opal_platform_dump_init(void)
 {
        int rc;
 
+       /* ELOG not supported by firmware */
+       if (!opal_check_token(OPAL_DUMP_READ))
+               return;
+
        dump_kset = kset_create_and_add("dump", NULL, opal_kobj);
        if (!dump_kset) {
                pr_warn("%s: Failed to create dump kset\n", __func__);
index bbdb3ffaab98f165a63b000961a26c3db41cc921..518fe95dbf24ec6bde07bf1f7c3923db0680b361 100644 (file)
@@ -295,6 +295,10 @@ int __init opal_elog_init(void)
 {
        int rc = 0;
 
+       /* ELOG not supported by firmware */
+       if (!opal_check_token(OPAL_ELOG_READ))
+               return -1;
+
        elog_kset = kset_create_and_add("elog", NULL, opal_kobj);
        if (!elog_kset) {
                pr_warn("%s: failed to create elog kset\n", __func__);
index ad4b31df779a389ceb83b1c62d77a850e9c1b749..dd2c285ad1708d755b5a1950558566149e837839 100644 (file)
@@ -191,6 +191,7 @@ static ssize_t lpc_debug_read(struct file *filp, char __user *ubuf,
 {
        struct lpc_debugfs_entry *lpc = filp->private_data;
        u32 data, pos, len, todo;
+       __be32 bedata;
        int rc;
 
        if (!access_ok(VERIFY_WRITE, ubuf, count))
@@ -213,9 +214,10 @@ static ssize_t lpc_debug_read(struct file *filp, char __user *ubuf,
                                len = 2;
                }
                rc = opal_lpc_read(opal_lpc_chip_id, lpc->lpc_type, pos,
-                                  &data, len);
+                                  &bedata, len);
                if (rc)
                        return -ENXIO;
+               data = be32_to_cpu(bedata);
                switch(len) {
                case 4:
                        rc = __put_user((u32)data, (u32 __user *)ubuf);
index acd9f7e96678256e2620b24494fded8e90b08ebb..f9896fd5d04afa1acc62f6ca6e82e25edce65d85 100644 (file)
@@ -78,7 +78,7 @@ void __init opal_nvram_init(void)
        }
        nvram_size = be32_to_cpup(nbytes_p);
 
-       printk(KERN_INFO "OPAL nvram setup, %u bytes\n", nvram_size);
+       pr_info("OPAL nvram setup, %u bytes\n", nvram_size);
        of_node_put(np);
 
        ppc_md.nvram_read = opal_nvram_read;
index b1885db8fdf34bfe068f1712d486f6884dc50d0e..499707ddaa9c79bc94dc900c725d828224209a0d 100644 (file)
@@ -42,6 +42,9 @@ unsigned long __init opal_get_boot_time(void)
        __be64 __h_m_s_ms;
        long rc = OPAL_BUSY;
 
+       if (!opal_check_token(OPAL_RTC_READ))
+               goto out;
+
        while (rc == OPAL_BUSY || rc == OPAL_BUSY_EVENT) {
                rc = opal_rtc_read(&__y_m_d, &__h_m_s_ms);
                if (rc == OPAL_BUSY_EVENT)
@@ -49,16 +52,18 @@ unsigned long __init opal_get_boot_time(void)
                else
                        mdelay(10);
        }
-       if (rc != OPAL_SUCCESS) {
-               ppc_md.get_rtc_time = NULL;
-               ppc_md.set_rtc_time = NULL;
-               return 0;
-       }
+       if (rc != OPAL_SUCCESS)
+               goto out;
+
        y_m_d = be32_to_cpu(__y_m_d);
        h_m_s_ms = be64_to_cpu(__h_m_s_ms);
        opal_to_tm(y_m_d, h_m_s_ms, &tm);
        return mktime(tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
                      tm.tm_hour, tm.tm_min, tm.tm_sec);
+out:
+       ppc_md.get_rtc_time = NULL;
+       ppc_md.set_rtc_time = NULL;
+       return 0;
 }
 
 void opal_get_rtc_time(struct rtc_time *tm)
index d8a000a9988b035db116aa446792a3968426e13d..ae14c40b4b1c8b0d119a905be191f1153b32fb6a 100644 (file)
@@ -2,7 +2,7 @@
 #include <linux/jump_label.h>
 #include <asm/trace.h>
 
-#ifdef CONFIG_JUMP_LABEL
+#ifdef HAVE_JUMP_LABEL
 struct static_key opal_tracepoint_key = STATIC_KEY_INIT;
 
 void opal_tracepoint_regfunc(void)
index 2e6ce1b8dc8ffcdd0d21cd86034c9e86e745880b..e9e2450c1fddd3bb6988084fb38039a8b3c3300b 100644 (file)
@@ -184,6 +184,7 @@ OPAL_CALL(opal_register_exception_handler,  OPAL_REGISTER_OPAL_EXCEPTION_HANDLER)
 OPAL_CALL(opal_pci_eeh_freeze_status,          OPAL_PCI_EEH_FREEZE_STATUS);
 OPAL_CALL(opal_pci_eeh_freeze_clear,           OPAL_PCI_EEH_FREEZE_CLEAR);
 OPAL_CALL(opal_pci_eeh_freeze_set,             OPAL_PCI_EEH_FREEZE_SET);
+OPAL_CALL(opal_pci_err_inject,                 OPAL_PCI_ERR_INJECT);
 OPAL_CALL(opal_pci_shpc,                       OPAL_PCI_SHPC);
 OPAL_CALL(opal_pci_phb_mmio_enable,            OPAL_PCI_PHB_MMIO_ENABLE);
 OPAL_CALL(opal_pci_set_phb_mem_window,         OPAL_PCI_SET_PHB_MEM_WINDOW);
@@ -232,6 +233,7 @@ OPAL_CALL(opal_validate_flash,                      OPAL_FLASH_VALIDATE);
 OPAL_CALL(opal_manage_flash,                   OPAL_FLASH_MANAGE);
 OPAL_CALL(opal_update_flash,                   OPAL_FLASH_UPDATE);
 OPAL_CALL(opal_resync_timebase,                        OPAL_RESYNC_TIMEBASE);
+OPAL_CALL(opal_check_token,                    OPAL_CHECK_TOKEN);
 OPAL_CALL(opal_dump_init,                      OPAL_DUMP_INIT);
 OPAL_CALL(opal_dump_info,                      OPAL_DUMP_INFO);
 OPAL_CALL(opal_dump_info2,                     OPAL_DUMP_INFO2);
@@ -247,3 +249,4 @@ OPAL_CALL(opal_set_param,                   OPAL_SET_PARAM);
 OPAL_CALL(opal_handle_hmi,                     OPAL_HANDLE_HMI);
 OPAL_CALL(opal_register_dump_region,           OPAL_REGISTER_DUMP_REGION);
 OPAL_CALL(opal_unregister_dump_region,         OPAL_UNREGISTER_DUMP_REGION);
+OPAL_CALL(opal_pci_set_phb_cxl_mode,           OPAL_PCI_SET_PHB_CXL_MODE);
index 4b005ae5dc4b6cfb4c9a73c94b3debd3b3edc08d..b642b0562f5aca3e8ecde20d3f86738e621f9092 100644 (file)
@@ -105,12 +105,12 @@ int __init early_init_dt_scan_opal(unsigned long node,
        if (of_flat_dt_is_compatible(node, "ibm,opal-v3")) {
                powerpc_firmware_features |= FW_FEATURE_OPALv2;
                powerpc_firmware_features |= FW_FEATURE_OPALv3;
-               printk("OPAL V3 detected !\n");
+               pr_info("OPAL V3 detected !\n");
        } else if (of_flat_dt_is_compatible(node, "ibm,opal-v2")) {
                powerpc_firmware_features |= FW_FEATURE_OPALv2;
-               printk("OPAL V2 detected !\n");
+               pr_info("OPAL V2 detected !\n");
        } else {
-               printk("OPAL V1 detected !\n");
+               pr_info("OPAL V1 detected !\n");
        }
 
        /* Reinit all cores with the right endian */
index df241b11d4f7d346f4a85c0632668677a9f3e07a..468a0f23c7f2b5f756c1b553315793c03492c0d6 100644 (file)
 #include <asm/xics.h>
 #include <asm/debug.h>
 #include <asm/firmware.h>
+#include <asm/pnv-pci.h>
+
+#include <misc/cxl.h>
 
 #include "powernv.h"
 #include "pci.h"
 
-#define define_pe_printk_level(func, kern_level)               \
-static int func(const struct pnv_ioda_pe *pe, const char *fmt, ...)    \
-{                                                              \
-       struct va_format vaf;                                   \
-       va_list args;                                           \
-       char pfix[32];                                          \
-       int r;                                                  \
-                                                               \
-       va_start(args, fmt);                                    \
-                                                               \
-       vaf.fmt = fmt;                                          \
-       vaf.va = &args;                                         \
-                                                               \
-       if (pe->pdev)                                           \
-               strlcpy(pfix, dev_name(&pe->pdev->dev),         \
-                       sizeof(pfix));                          \
-       else                                                    \
-               sprintf(pfix, "%04x:%02x     ",                 \
-                       pci_domain_nr(pe->pbus),                \
-                       pe->pbus->number);                      \
-       r = printk(kern_level "pci %s: [PE# %.3d] %pV",         \
-                  pfix, pe->pe_number, &vaf);                  \
-                                                               \
-       va_end(args);                                           \
-                                                               \
-       return r;                                               \
-}                                                              \
-
-define_pe_printk_level(pe_err, KERN_ERR);
-define_pe_printk_level(pe_warn, KERN_WARNING);
-define_pe_printk_level(pe_info, KERN_INFO);
+static void pe_level_printk(const struct pnv_ioda_pe *pe, const char *level,
+                           const char *fmt, ...)
+{
+       struct va_format vaf;
+       va_list args;
+       char pfix[32];
+
+       va_start(args, fmt);
+
+       vaf.fmt = fmt;
+       vaf.va = &args;
+
+       if (pe->pdev)
+               strlcpy(pfix, dev_name(&pe->pdev->dev), sizeof(pfix));
+       else
+               sprintf(pfix, "%04x:%02x     ",
+                       pci_domain_nr(pe->pbus), pe->pbus->number);
+
+       printk("%spci %s: [PE# %.3d] %pV",
+              level, pfix, pe->pe_number, &vaf);
+
+       va_end(args);
+}
+
+#define pe_err(pe, fmt, ...)                                   \
+       pe_level_printk(pe, KERN_ERR, fmt, ##__VA_ARGS__)
+#define pe_warn(pe, fmt, ...)                                  \
+       pe_level_printk(pe, KERN_WARNING, fmt, ##__VA_ARGS__)
+#define pe_info(pe, fmt, ...)                                  \
+       pe_level_printk(pe, KERN_INFO, fmt, ##__VA_ARGS__)
 
 /*
  * stdcix is only supposed to be used in hypervisor real mode as per
@@ -385,7 +387,7 @@ static void pnv_ioda_freeze_pe(struct pnv_phb *phb, int pe_no)
        }
 }
 
-int pnv_ioda_unfreeze_pe(struct pnv_phb *phb, int pe_no, int opt)
+static int pnv_ioda_unfreeze_pe(struct pnv_phb *phb, int pe_no, int opt)
 {
        struct pnv_ioda_pe *pe, *slave;
        s64 rc;
@@ -890,6 +892,28 @@ static int pnv_pci_ioda_dma_set_mask(struct pnv_phb *phb,
        return 0;
 }
 
+static u64 pnv_pci_ioda_dma_get_required_mask(struct pnv_phb *phb,
+                                             struct pci_dev *pdev)
+{
+       struct pci_dn *pdn = pci_get_pdn(pdev);
+       struct pnv_ioda_pe *pe;
+       u64 end, mask;
+
+       if (WARN_ON(!pdn || pdn->pe_number == IODA_INVALID_PE))
+               return 0;
+
+       pe = &phb->ioda.pe_array[pdn->pe_number];
+       if (!pe->tce_bypass_enabled)
+               return __dma_get_required_mask(&pdev->dev);
+
+
+       end = pe->tce_bypass_base + memblock_end_of_DRAM();
+       mask = 1ULL << (fls64(end) - 1);
+       mask += mask - 1;
+
+       return mask;
+}
+
 static void pnv_ioda_setup_bus_dma(struct pnv_ioda_pe *pe,
                                   struct pci_bus *bus,
                                   bool add_to_iommu_group)
@@ -1306,14 +1330,186 @@ static void pnv_ioda2_msi_eoi(struct irq_data *d)
        icp_native_eoi(d);
 }
 
+
+static void set_msi_irq_chip(struct pnv_phb *phb, unsigned int virq)
+{
+       struct irq_data *idata;
+       struct irq_chip *ichip;
+
+       if (phb->type != PNV_PHB_IODA2)
+               return;
+
+       if (!phb->ioda.irq_chip_init) {
+               /*
+                * First time we setup an MSI IRQ, we need to setup the
+                * corresponding IRQ chip to route correctly.
+                */
+               idata = irq_get_irq_data(virq);
+               ichip = irq_data_get_irq_chip(idata);
+               phb->ioda.irq_chip_init = 1;
+               phb->ioda.irq_chip = *ichip;
+               phb->ioda.irq_chip.irq_eoi = pnv_ioda2_msi_eoi;
+       }
+       irq_set_chip(virq, &phb->ioda.irq_chip);
+}
+
+#ifdef CONFIG_CXL_BASE
+
+struct device_node *pnv_pci_to_phb_node(struct pci_dev *dev)
+{
+       struct pci_controller *hose = pci_bus_to_host(dev->bus);
+
+       return hose->dn;
+}
+EXPORT_SYMBOL(pnv_pci_to_phb_node);
+
+int pnv_phb_to_cxl(struct pci_dev *dev)
+{
+       struct pci_controller *hose = pci_bus_to_host(dev->bus);
+       struct pnv_phb *phb = hose->private_data;
+       struct pnv_ioda_pe *pe;
+       int rc;
+
+       pe = pnv_ioda_get_pe(dev);
+       if (!pe)
+               return -ENODEV;
+
+       pe_info(pe, "Switching PHB to CXL\n");
+
+       rc = opal_pci_set_phb_cxl_mode(phb->opal_id, 1, pe->pe_number);
+       if (rc)
+               dev_err(&dev->dev, "opal_pci_set_phb_cxl_mode failed: %i\n", rc);
+
+       return rc;
+}
+EXPORT_SYMBOL(pnv_phb_to_cxl);
+
+/* Find PHB for cxl dev and allocate MSI hwirqs?
+ * Returns the absolute hardware IRQ number
+ */
+int pnv_cxl_alloc_hwirqs(struct pci_dev *dev, int num)
+{
+       struct pci_controller *hose = pci_bus_to_host(dev->bus);
+       struct pnv_phb *phb = hose->private_data;
+       int hwirq = msi_bitmap_alloc_hwirqs(&phb->msi_bmp, num);
+
+       if (hwirq < 0) {
+               dev_warn(&dev->dev, "Failed to find a free MSI\n");
+               return -ENOSPC;
+       }
+
+       return phb->msi_base + hwirq;
+}
+EXPORT_SYMBOL(pnv_cxl_alloc_hwirqs);
+
+void pnv_cxl_release_hwirqs(struct pci_dev *dev, int hwirq, int num)
+{
+       struct pci_controller *hose = pci_bus_to_host(dev->bus);
+       struct pnv_phb *phb = hose->private_data;
+
+       msi_bitmap_free_hwirqs(&phb->msi_bmp, hwirq - phb->msi_base, num);
+}
+EXPORT_SYMBOL(pnv_cxl_release_hwirqs);
+
+void pnv_cxl_release_hwirq_ranges(struct cxl_irq_ranges *irqs,
+                                 struct pci_dev *dev)
+{
+       struct pci_controller *hose = pci_bus_to_host(dev->bus);
+       struct pnv_phb *phb = hose->private_data;
+       int i, hwirq;
+
+       for (i = 1; i < CXL_IRQ_RANGES; i++) {
+               if (!irqs->range[i])
+                       continue;
+               pr_devel("cxl release irq range 0x%x: offset: 0x%lx  limit: %ld\n",
+                        i, irqs->offset[i],
+                        irqs->range[i]);
+               hwirq = irqs->offset[i] - phb->msi_base;
+               msi_bitmap_free_hwirqs(&phb->msi_bmp, hwirq,
+                                      irqs->range[i]);
+       }
+}
+EXPORT_SYMBOL(pnv_cxl_release_hwirq_ranges);
+
+int pnv_cxl_alloc_hwirq_ranges(struct cxl_irq_ranges *irqs,
+                              struct pci_dev *dev, int num)
+{
+       struct pci_controller *hose = pci_bus_to_host(dev->bus);
+       struct pnv_phb *phb = hose->private_data;
+       int i, hwirq, try;
+
+       memset(irqs, 0, sizeof(struct cxl_irq_ranges));
+
+       /* 0 is reserved for the multiplexed PSL DSI interrupt */
+       for (i = 1; i < CXL_IRQ_RANGES && num; i++) {
+               try = num;
+               while (try) {
+                       hwirq = msi_bitmap_alloc_hwirqs(&phb->msi_bmp, try);
+                       if (hwirq >= 0)
+                               break;
+                       try /= 2;
+               }
+               if (!try)
+                       goto fail;
+
+               irqs->offset[i] = phb->msi_base + hwirq;
+               irqs->range[i] = try;
+               pr_devel("cxl alloc irq range 0x%x: offset: 0x%lx  limit: %li\n",
+                        i, irqs->offset[i], irqs->range[i]);
+               num -= try;
+       }
+       if (num)
+               goto fail;
+
+       return 0;
+fail:
+       pnv_cxl_release_hwirq_ranges(irqs, dev);
+       return -ENOSPC;
+}
+EXPORT_SYMBOL(pnv_cxl_alloc_hwirq_ranges);
+
+int pnv_cxl_get_irq_count(struct pci_dev *dev)
+{
+       struct pci_controller *hose = pci_bus_to_host(dev->bus);
+       struct pnv_phb *phb = hose->private_data;
+
+       return phb->msi_bmp.irq_count;
+}
+EXPORT_SYMBOL(pnv_cxl_get_irq_count);
+
+int pnv_cxl_ioda_msi_setup(struct pci_dev *dev, unsigned int hwirq,
+                          unsigned int virq)
+{
+       struct pci_controller *hose = pci_bus_to_host(dev->bus);
+       struct pnv_phb *phb = hose->private_data;
+       unsigned int xive_num = hwirq - phb->msi_base;
+       struct pnv_ioda_pe *pe;
+       int rc;
+
+       if (!(pe = pnv_ioda_get_pe(dev)))
+               return -ENODEV;
+
+       /* Assign XIVE to PE */
+       rc = opal_pci_set_xive_pe(phb->opal_id, pe->pe_number, xive_num);
+       if (rc) {
+               pe_warn(pe, "%s: OPAL error %d setting msi_base 0x%x "
+                       "hwirq 0x%x XIVE 0x%x PE\n",
+                       pci_name(dev), rc, phb->msi_base, hwirq, xive_num);
+               return -EIO;
+       }
+       set_msi_irq_chip(phb, virq);
+
+       return 0;
+}
+EXPORT_SYMBOL(pnv_cxl_ioda_msi_setup);
+#endif
+
 static int pnv_pci_ioda_msi_setup(struct pnv_phb *phb, struct pci_dev *dev,
                                  unsigned int hwirq, unsigned int virq,
                                  unsigned int is_64, struct msi_msg *msg)
 {
        struct pnv_ioda_pe *pe = pnv_ioda_get_pe(dev);
        struct pci_dn *pdn = pci_get_pdn(dev);
-       struct irq_data *idata;
-       struct irq_chip *ichip;
        unsigned int xive_num = hwirq - phb->msi_base;
        __be32 data;
        int rc;
@@ -1365,22 +1561,7 @@ static int pnv_pci_ioda_msi_setup(struct pnv_phb *phb, struct pci_dev *dev,
        }
        msg->data = be32_to_cpu(data);
 
-       /*
-        * Change the IRQ chip for the MSI interrupts on PHB3.
-        * The corresponding IRQ chip should be populated for
-        * the first time.
-        */
-       if (phb->type == PNV_PHB_IODA2) {
-               if (!phb->ioda.irq_chip_init) {
-                       idata = irq_get_irq_data(virq);
-                       ichip = irq_data_get_irq_chip(idata);
-                       phb->ioda.irq_chip_init = 1;
-                       phb->ioda.irq_chip = *ichip;
-                       phb->ioda.irq_chip.irq_eoi = pnv_ioda2_msi_eoi;
-               }
-
-               irq_set_chip(virq, &phb->ioda.irq_chip);
-       }
+       set_msi_irq_chip(phb, virq);
 
        pr_devel("%s: %s-bit MSI on hwirq %x (xive #%d),"
                 " address=%x_%08x data=%x PE# %d\n",
@@ -1627,12 +1808,12 @@ static u32 pnv_ioda_bdfn_to_pe(struct pnv_phb *phb, struct pci_bus *bus,
 
 static void pnv_pci_ioda_shutdown(struct pnv_phb *phb)
 {
-       opal_pci_reset(phb->opal_id, OPAL_PCI_IODA_TABLE_RESET,
+       opal_pci_reset(phb->opal_id, OPAL_RESET_PCI_IODA_TABLE,
                       OPAL_ASSERT_RESET);
 }
 
-void __init pnv_pci_init_ioda_phb(struct device_node *np,
-                                 u64 hub_id, int ioda_type)
+static void __init pnv_pci_init_ioda_phb(struct device_node *np,
+                                        u64 hub_id, int ioda_type)
 {
        struct pci_controller *hose;
        struct pnv_phb *phb;
@@ -1782,6 +1963,7 @@ void __init pnv_pci_init_ioda_phb(struct device_node *np,
        /* Setup TCEs */
        phb->dma_dev_setup = pnv_pci_ioda_dma_dev_setup;
        phb->dma_set_mask = pnv_pci_ioda_dma_set_mask;
+       phb->dma_get_required_mask = pnv_pci_ioda_dma_get_required_mask;
 
        /* Setup shutdown function for kexec */
        phb->shutdown = pnv_pci_ioda_shutdown;
@@ -1803,7 +1985,7 @@ void __init pnv_pci_init_ioda_phb(struct device_node *np,
        pci_add_flags(PCI_REASSIGN_ALL_RSRC);
 
        /* Reset IODA tables to a clean state */
-       rc = opal_pci_reset(phb_id, OPAL_PCI_IODA_TABLE_RESET, OPAL_ASSERT_RESET);
+       rc = opal_pci_reset(phb_id, OPAL_RESET_PCI_IODA_TABLE, OPAL_ASSERT_RESET);
        if (rc)
                pr_warning("  OPAL Error %ld performing IODA table reset !\n", rc);
 
index b45c49249a5dd960e03fdb0a927c1455735df50c..b3ca77ddf36dfbd07de81feb5015b27bd675c009 100644 (file)
@@ -753,6 +753,17 @@ int pnv_pci_dma_set_mask(struct pci_dev *pdev, u64 dma_mask)
        return __dma_set_mask(&pdev->dev, dma_mask);
 }
 
+u64 pnv_pci_dma_get_required_mask(struct pci_dev *pdev)
+{
+       struct pci_controller *hose = pci_bus_to_host(pdev->bus);
+       struct pnv_phb *phb = hose->private_data;
+
+       if (phb && phb->dma_get_required_mask)
+               return phb->dma_get_required_mask(phb, pdev);
+
+       return __dma_get_required_mask(&pdev->dev);
+}
+
 void pnv_pci_shutdown(void)
 {
        struct pci_controller *hose;
index 48494d4b60581d43baac6a59a198166786ec4101..34d29eb2a4def4dc83044ad6cfaf5c42210a9e86 100644 (file)
@@ -85,6 +85,8 @@ struct pnv_eeh_ops {
        int (*get_log)(struct eeh_pe *pe, int severity,
                       char *drv_log, unsigned long len);
        int (*configure_bridge)(struct eeh_pe *pe);
+       int (*err_inject)(struct eeh_pe *pe, int type, int func,
+                         unsigned long addr, unsigned long mask);
        int (*next_error)(struct eeh_pe **pe);
 };
 #endif /* CONFIG_EEH */
@@ -122,6 +124,8 @@ struct pnv_phb {
        void (*dma_dev_setup)(struct pnv_phb *phb, struct pci_dev *pdev);
        int (*dma_set_mask)(struct pnv_phb *phb, struct pci_dev *pdev,
                            u64 dma_mask);
+       u64 (*dma_get_required_mask)(struct pnv_phb *phb,
+                                    struct pci_dev *pdev);
        void (*fixup_phb)(struct pci_controller *hose);
        u32 (*bdfn_to_pe)(struct pnv_phb *phb, struct pci_bus *bus, u32 devfn);
        void (*shutdown)(struct pnv_phb *phb);
index 75501bfede7f9b2fdc51a3987fd03d09383477ee..6c8e2d188cd096330b7b1926da13c50de1e73f2e 100644 (file)
@@ -13,6 +13,7 @@ struct pci_dev;
 extern void pnv_pci_init(void);
 extern void pnv_pci_shutdown(void);
 extern int pnv_pci_dma_set_mask(struct pci_dev *pdev, u64 dma_mask);
+extern u64 pnv_pci_dma_get_required_mask(struct pci_dev *pdev);
 #else
 static inline void pnv_pci_init(void) { }
 static inline void pnv_pci_shutdown(void) { }
@@ -21,6 +22,11 @@ static inline int pnv_pci_dma_set_mask(struct pci_dev *pdev, u64 dma_mask)
 {
        return -ENODEV;
 }
+
+static inline u64 pnv_pci_dma_get_required_mask(struct pci_dev *pdev)
+{
+       return 0;
+}
 #endif
 
 extern void pnv_lpc_init(void);
index 5a0e2dc6de5f127abef1748090fb15e17dfb58fe..3f9546d8a51f907dda294d33c1d507bc01d6aa1b 100644 (file)
@@ -173,6 +173,14 @@ static int pnv_dma_set_mask(struct device *dev, u64 dma_mask)
        return __dma_set_mask(dev, dma_mask);
 }
 
+static u64 pnv_dma_get_required_mask(struct device *dev)
+{
+       if (dev_is_pci(dev))
+               return pnv_pci_dma_get_required_mask(to_pci_dev(dev));
+
+       return __dma_get_required_mask(dev);
+}
+
 static void pnv_shutdown(void)
 {
        /* Let the PCI code clear up IODA tables */
@@ -307,7 +315,7 @@ static int __init pnv_probe(void)
  * Returns the cpu frequency for 'cpu' in Hz. This is used by
  * /proc/cpuinfo
  */
-unsigned long pnv_get_proc_freq(unsigned int cpu)
+static unsigned long pnv_get_proc_freq(unsigned int cpu)
 {
        unsigned long ret_freq;
 
@@ -335,6 +343,7 @@ define_machine(powernv) {
        .power_save             = power7_idle,
        .calibrate_decr         = generic_calibrate_decr,
        .dma_set_mask           = pnv_dma_set_mask,
+       .dma_get_required_mask  = pnv_dma_get_required_mask,
 #ifdef CONFIG_KEXEC
        .kexec_cpu_down         = pnv_kexec_cpu_down,
 #endif
index 5fcfcf44e3a9b949e6536ebcf53038645286fde6..4753958cd509bdfeec1be8bf088eb69e32077569 100644 (file)
@@ -54,7 +54,7 @@ static void pnv_smp_setup_cpu(int cpu)
 #endif
 }
 
-int pnv_smp_kick_cpu(int nr)
+static int pnv_smp_kick_cpu(int nr)
 {
        unsigned int pcpu = get_hard_smp_processor_id(nr);
        unsigned long start_here =
@@ -168,9 +168,9 @@ static void pnv_smp_cpu_kill_self(void)
                power7_nap(1);
                ppc64_runlatch_on();
 
-               /* Reenable IRQs briefly to clear the IPI that woke us */
-               local_irq_enable();
-               local_irq_disable();
+               /* Clear the IPI that woke us up */
+               icp_native_flush_interrupt();
+               local_paca->irq_happened &= PACA_IRQ_HARD_DIS;
                mb();
 
                if (cpu_core_split_required())
index 894ecb3eb5963506be9e0efead851a48cf577b1e..c87f96b79d1a02ed5f5371a2d02fc509deb3f3a1 100644 (file)
@@ -24,6 +24,7 @@
 #include <asm/smp.h>
 
 #include "subcore.h"
+#include "powernv.h"
 
 
 /*
index 2d8bf15879fdd3e14da6c8c46f6bbeaf7ab3f138..fc44ad0475f845e6787e387511b2848698cb333e 100644 (file)
@@ -555,7 +555,6 @@ static int cmm_mem_going_offline(void *arg)
                                pa_last = pa_last->next;
                                free_page((unsigned long)cmm_page_list);
                                cmm_page_list = pa_last;
-                               continue;
                        }
                }
                pa_curr = pa_curr->next;
index a2450b8a50a5eaaf3bbab9fc402bbf8997c00ed4..fdf01b660d5930cd31c4f246c7d4f4659aad6690 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/slab.h>
 #include <linux/of.h>
 #include "offline_states.h"
+#include "pseries.h"
 
 #include <asm/prom.h>
 #include <asm/machdep.h>
@@ -363,7 +364,8 @@ static int dlpar_online_cpu(struct device_node *dn)
        int rc = 0;
        unsigned int cpu;
        int len, nthreads, i;
-       const u32 *intserv;
+       const __be32 *intserv;
+       u32 thread;
 
        intserv = of_get_property(dn, "ibm,ppc-interrupt-server#s", &len);
        if (!intserv)
@@ -373,8 +375,9 @@ static int dlpar_online_cpu(struct device_node *dn)
 
        cpu_maps_update_begin();
        for (i = 0; i < nthreads; i++) {
+               thread = be32_to_cpu(intserv[i]);
                for_each_present_cpu(cpu) {
-                       if (get_hard_smp_processor_id(cpu) != intserv[i])
+                       if (get_hard_smp_processor_id(cpu) != thread)
                                continue;
                        BUG_ON(get_cpu_current_state(cpu)
                                        != CPU_STATE_OFFLINE);
@@ -388,7 +391,7 @@ static int dlpar_online_cpu(struct device_node *dn)
                }
                if (cpu == num_possible_cpus())
                        printk(KERN_WARNING "Could not find cpu to online "
-                              "with physical id 0x%x\n", intserv[i]);
+                              "with physical id 0x%x\n", thread);
        }
        cpu_maps_update_done();
 
@@ -442,7 +445,8 @@ static int dlpar_offline_cpu(struct device_node *dn)
        int rc = 0;
        unsigned int cpu;
        int len, nthreads, i;
-       const u32 *intserv;
+       const __be32 *intserv;
+       u32 thread;
 
        intserv = of_get_property(dn, "ibm,ppc-interrupt-server#s", &len);
        if (!intserv)
@@ -452,8 +456,9 @@ static int dlpar_offline_cpu(struct device_node *dn)
 
        cpu_maps_update_begin();
        for (i = 0; i < nthreads; i++) {
+               thread = be32_to_cpu(intserv[i]);
                for_each_present_cpu(cpu) {
-                       if (get_hard_smp_processor_id(cpu) != intserv[i])
+                       if (get_hard_smp_processor_id(cpu) != thread)
                                continue;
 
                        if (get_cpu_current_state(cpu) == CPU_STATE_OFFLINE)
@@ -475,14 +480,14 @@ static int dlpar_offline_cpu(struct device_node *dn)
                         * Upgrade it's state to CPU_STATE_OFFLINE.
                         */
                        set_preferred_offline_state(cpu, CPU_STATE_OFFLINE);
-                       BUG_ON(plpar_hcall_norets(H_PROD, intserv[i])
+                       BUG_ON(plpar_hcall_norets(H_PROD, thread)
                                                                != H_SUCCESS);
                        __cpu_die(cpu);
                        break;
                }
                if (cpu == num_possible_cpus())
                        printk(KERN_WARNING "Could not find cpu to offline "
-                              "with physical id 0x%x\n", intserv[i]);
+                              "with physical id 0x%x\n", thread);
        }
        cpu_maps_update_done();
 
@@ -494,15 +499,15 @@ out:
 static ssize_t dlpar_cpu_release(const char *buf, size_t count)
 {
        struct device_node *dn;
-       const u32 *drc_index;
+       u32 drc_index;
        int rc;
 
        dn = of_find_node_by_path(buf);
        if (!dn)
                return -EINVAL;
 
-       drc_index = of_get_property(dn, "ibm,my-drc-index", NULL);
-       if (!drc_index) {
+       rc = of_property_read_u32(dn, "ibm,my-drc-index", &drc_index);
+       if (rc) {
                of_node_put(dn);
                return -EINVAL;
        }
@@ -513,7 +518,7 @@ static ssize_t dlpar_cpu_release(const char *buf, size_t count)
                return -EINVAL;
        }
 
-       rc = dlpar_release_drc(*drc_index);
+       rc = dlpar_release_drc(drc_index);
        if (rc) {
                of_node_put(dn);
                return rc;
@@ -521,7 +526,7 @@ static ssize_t dlpar_cpu_release(const char *buf, size_t count)
 
        rc = dlpar_detach_node(dn);
        if (rc) {
-               dlpar_acquire_drc(*drc_index);
+               dlpar_acquire_drc(drc_index);
                return rc;
        }
 
index b08053819d99f1f9d2a7da36828faa268837e66e..a6c7e19f5eb365e2091a270929cf9a7025548e08 100644 (file)
@@ -88,29 +88,14 @@ static int pseries_eeh_init(void)
         * and its variant since the old firmware probably support address
         * of domain/bus/slot/function for EEH RTAS operations.
         */
-       if (ibm_set_eeh_option == RTAS_UNKNOWN_SERVICE) {
-               pr_warn("%s: RTAS service <ibm,set-eeh-option> invalid\n",
-                       __func__);
-               return -EINVAL;
-       } else if (ibm_set_slot_reset == RTAS_UNKNOWN_SERVICE) {
-               pr_warn("%s: RTAS service <ibm,set-slot-reset> invalid\n",
-                       __func__);
-               return -EINVAL;
-       } else if (ibm_read_slot_reset_state2 == RTAS_UNKNOWN_SERVICE &&
-                  ibm_read_slot_reset_state == RTAS_UNKNOWN_SERVICE) {
-               pr_warn("%s: RTAS service <ibm,read-slot-reset-state2> and "
-                       "<ibm,read-slot-reset-state> invalid\n",
-                       __func__);
-               return -EINVAL;
-       } else if (ibm_slot_error_detail == RTAS_UNKNOWN_SERVICE) {
-               pr_warn("%s: RTAS service <ibm,slot-error-detail> invalid\n",
-                       __func__);
-               return -EINVAL;
-       } else if (ibm_configure_pe == RTAS_UNKNOWN_SERVICE &&
-                  ibm_configure_bridge == RTAS_UNKNOWN_SERVICE) {
-               pr_warn("%s: RTAS service <ibm,configure-pe> and "
-                       "<ibm,configure-bridge> invalid\n",
-                       __func__);
+       if (ibm_set_eeh_option == RTAS_UNKNOWN_SERVICE          ||
+           ibm_set_slot_reset == RTAS_UNKNOWN_SERVICE          ||
+           (ibm_read_slot_reset_state2 == RTAS_UNKNOWN_SERVICE &&
+            ibm_read_slot_reset_state == RTAS_UNKNOWN_SERVICE) ||
+           ibm_slot_error_detail == RTAS_UNKNOWN_SERVICE       ||
+           (ibm_configure_pe == RTAS_UNKNOWN_SERVICE           &&
+            ibm_configure_bridge == RTAS_UNKNOWN_SERVICE)) {
+               pr_info("EEH functionality not supported\n");
                return -EINVAL;
        }
 
@@ -118,11 +103,11 @@ static int pseries_eeh_init(void)
        spin_lock_init(&slot_errbuf_lock);
        eeh_error_buf_size = rtas_token("rtas-error-log-max");
        if (eeh_error_buf_size == RTAS_UNKNOWN_SERVICE) {
-               pr_warn("%s: unknown EEH error log size\n",
+               pr_info("%s: unknown EEH error log size\n",
                        __func__);
                eeh_error_buf_size = 1024;
        } else if (eeh_error_buf_size > RTAS_ERROR_LOG_MAX) {
-               pr_warn("%s: EEH error log size %d exceeds the maximal %d\n",
+               pr_info("%s: EEH error log size %d exceeds the maximal %d\n",
                        __func__, eeh_error_buf_size, RTAS_ERROR_LOG_MAX);
                eeh_error_buf_size = RTAS_ERROR_LOG_MAX;
        }
@@ -349,7 +334,9 @@ static int pseries_eeh_set_option(struct eeh_pe *pe, int option)
                if (pe->addr)
                        config_addr = pe->addr;
                break;
-
+       case EEH_OPT_FREEZE_PE:
+               /* Not support */
+               return 0;
        default:
                pr_err("%s: Invalid option %d\n",
                        __func__, option);
@@ -729,6 +716,7 @@ static struct eeh_ops pseries_eeh_ops = {
        .wait_state             = pseries_eeh_wait_state,
        .get_log                = pseries_eeh_get_log,
        .configure_bridge       = pseries_eeh_configure_bridge,
+       .err_inject             = NULL,
        .read_config            = pseries_eeh_read_config,
        .write_config           = pseries_eeh_write_config,
        .next_error             = NULL,
index 20d62975856fb7fa5795a566629bbb69aa7a3139..b174fa751d260bcebd20b0af83cf5e13ba28158a 100644 (file)
@@ -90,7 +90,7 @@ static void rtas_stop_self(void)
 {
        static struct rtas_args args = {
                .nargs = 0,
-               .nret = 1,
+               .nret = cpu_to_be32(1),
                .rets = &args.args[0],
        };
 
@@ -312,7 +312,8 @@ static void pseries_remove_processor(struct device_node *np)
 {
        unsigned int cpu;
        int len, nthreads, i;
-       const u32 *intserv;
+       const __be32 *intserv;
+       u32 thread;
 
        intserv = of_get_property(np, "ibm,ppc-interrupt-server#s", &len);
        if (!intserv)
@@ -322,8 +323,9 @@ static void pseries_remove_processor(struct device_node *np)
 
        cpu_maps_update_begin();
        for (i = 0; i < nthreads; i++) {
+               thread = be32_to_cpu(intserv[i]);
                for_each_present_cpu(cpu) {
-                       if (get_hard_smp_processor_id(cpu) != intserv[i])
+                       if (get_hard_smp_processor_id(cpu) != thread)
                                continue;
                        BUG_ON(cpu_online(cpu));
                        set_cpu_present(cpu, false);
@@ -332,7 +334,7 @@ static void pseries_remove_processor(struct device_node *np)
                }
                if (cpu >= nr_cpu_ids)
                        printk(KERN_WARNING "Could not find cpu to remove "
-                              "with physical id 0x%x\n", intserv[i]);
+                              "with physical id 0x%x\n", thread);
        }
        cpu_maps_update_done();
 }
index 34064f50945ef22a1246c8201556c7dc75a7cc8e..3c4c0dcd90d3e03051b4b09a3c28caabfe6edd1c 100644 (file)
@@ -20,6 +20,7 @@
 #include <asm/machdep.h>
 #include <asm/prom.h>
 #include <asm/sparsemem.h>
+#include "pseries.h"
 
 unsigned long pseries_memory_block_size(void)
 {
index 4642d6a4d35641d5219a2378ce917409cea4c850..de1ec54a2a57924ac2f3c29a6d43153e773e8aee 100644 (file)
@@ -329,16 +329,16 @@ struct direct_window {
 
 /* Dynamic DMA Window support */
 struct ddw_query_response {
-       __be32 windows_available;
-       __be32 largest_available_block;
-       __be32 page_size;
-       __be32 migration_capable;
+       u32 windows_available;
+       u32 largest_available_block;
+       u32 page_size;
+       u32 migration_capable;
 };
 
 struct ddw_create_response {
-       __be32 liobn;
-       __be32 addr_hi;
-       __be32 addr_lo;
+       u32 liobn;
+       u32 addr_hi;
+       u32 addr_lo;
 };
 
 static LIST_HEAD(direct_window_list);
@@ -725,16 +725,18 @@ static void remove_ddw(struct device_node *np, bool remove_prop)
 {
        struct dynamic_dma_window_prop *dwp;
        struct property *win64;
-       const u32 *ddw_avail;
+       u32 ddw_avail[3];
        u64 liobn;
-       int len, ret = 0;
+       int ret = 0;
+
+       ret = of_property_read_u32_array(np, "ibm,ddw-applicable",
+                                        &ddw_avail[0], 3);
 
-       ddw_avail = of_get_property(np, "ibm,ddw-applicable", &len);
        win64 = of_find_property(np, DIRECT64_PROPNAME, NULL);
        if (!win64)
                return;
 
-       if (!ddw_avail || len < 3 * sizeof(u32) || win64->length < sizeof(*dwp))
+       if (ret || win64->length < sizeof(*dwp))
                goto delprop;
 
        dwp = win64->value;
@@ -872,8 +874,9 @@ static int create_ddw(struct pci_dev *dev, const u32 *ddw_avail,
 
        do {
                /* extra outputs are LIOBN and dma-addr (hi, lo) */
-               ret = rtas_call(ddw_avail[1], 5, 4, (u32 *)create, cfg_addr,
-                               BUID_HI(buid), BUID_LO(buid), page_shift, window_shift);
+               ret = rtas_call(ddw_avail[1], 5, 4, (u32 *)create,
+                               cfg_addr, BUID_HI(buid), BUID_LO(buid),
+                               page_shift, window_shift);
        } while (rtas_busy_delay(ret));
        dev_info(&dev->dev,
                "ibm,create-pe-dma-window(%x) %x %x %x %x %x returned %d "
@@ -910,7 +913,7 @@ static u64 enable_ddw(struct pci_dev *dev, struct device_node *pdn)
        int page_shift;
        u64 dma_addr, max_addr;
        struct device_node *dn;
-       const u32 *uninitialized_var(ddw_avail);
+       u32 ddw_avail[3];
        struct direct_window *window;
        struct property *win64;
        struct dynamic_dma_window_prop *ddwprop;
@@ -942,8 +945,9 @@ static u64 enable_ddw(struct pci_dev *dev, struct device_node *pdn)
         * for the given node in that order.
         * the property is actually in the parent, not the PE
         */
-       ddw_avail = of_get_property(pdn, "ibm,ddw-applicable", &len);
-       if (!ddw_avail || len < 3 * sizeof(u32))
+       ret = of_property_read_u32_array(pdn, "ibm,ddw-applicable",
+                                        &ddw_avail[0], 3);
+       if (ret)
                goto out_failed;
 
        /*
@@ -966,11 +970,11 @@ static u64 enable_ddw(struct pci_dev *dev, struct device_node *pdn)
                dev_dbg(&dev->dev, "no free dynamic windows");
                goto out_failed;
        }
-       if (be32_to_cpu(query.page_size) & 4) {
+       if (query.page_size & 4) {
                page_shift = 24; /* 16MB */
-       } else if (be32_to_cpu(query.page_size) & 2) {
+       } else if (query.page_size & 2) {
                page_shift = 16; /* 64kB */
-       } else if (be32_to_cpu(query.page_size) & 1) {
+       } else if (query.page_size & 1) {
                page_shift = 12; /* 4kB */
        } else {
                dev_dbg(&dev->dev, "no supported direct page size in mask %x",
@@ -980,7 +984,7 @@ static u64 enable_ddw(struct pci_dev *dev, struct device_node *pdn)
        /* verify the window * number of ptes will map the partition */
        /* check largest block * page size > max memory hotplug addr */
        max_addr = memory_hotplug_max();
-       if (be32_to_cpu(query.largest_available_block) < (max_addr >> page_shift)) {
+       if (query.largest_available_block < (max_addr >> page_shift)) {
                dev_dbg(&dev->dev, "can't map partiton max 0x%llx with %u "
                          "%llu-sized pages\n", max_addr,  query.largest_available_block,
                          1ULL << page_shift);
@@ -1006,8 +1010,9 @@ static u64 enable_ddw(struct pci_dev *dev, struct device_node *pdn)
        if (ret != 0)
                goto out_free_prop;
 
-       ddwprop->liobn = create.liobn;
-       ddwprop->dma_base = cpu_to_be64(of_read_number(&create.addr_hi, 2));
+       ddwprop->liobn = cpu_to_be32(create.liobn);
+       ddwprop->dma_base = cpu_to_be64(((u64)create.addr_hi << 32) |
+                       create.addr_lo);
        ddwprop->tce_shift = cpu_to_be32(page_shift);
        ddwprop->window_shift = cpu_to_be32(len);
 
@@ -1039,7 +1044,7 @@ static u64 enable_ddw(struct pci_dev *dev, struct device_node *pdn)
        list_add(&window->list, &direct_window_list);
        spin_unlock(&direct_window_list_lock);
 
-       dma_addr = of_read_number(&create.addr_hi, 2);
+       dma_addr = be64_to_cpu(ddwprop->dma_base);
        goto out_unlock;
 
 out_free_window:
index 34e64237fff9a9ca4cf6d62751e99feff41a3f1e..8c509d5397c6e9a6f54c19ec569612e0005f96e2 100644 (file)
@@ -59,8 +59,6 @@ EXPORT_SYMBOL(plpar_hcall);
 EXPORT_SYMBOL(plpar_hcall9);
 EXPORT_SYMBOL(plpar_hcall_norets);
 
-extern void pSeries_find_serial_port(void);
-
 void vpa_init(int cpu)
 {
        int hwcpu = get_hard_smp_processor_id(cpu);
@@ -642,7 +640,7 @@ EXPORT_SYMBOL(arch_free_page);
 #endif
 
 #ifdef CONFIG_TRACEPOINTS
-#ifdef CONFIG_JUMP_LABEL
+#ifdef HAVE_JUMP_LABEL
 struct static_key hcall_tracepoint_key = STATIC_KEY_INIT;
 
 void hcall_tracepoint_regfunc(void)
index 0cc240b7f694ef3b35c2930d5356a4e4cb39d863..11a3b617ef5dbd4b7d6cbed7d045d9bc3c4c7d95 100644 (file)
@@ -276,8 +276,10 @@ static ssize_t pSeries_nvram_get_size(void)
  * sequence #: The unique sequence # for each event. (until it wraps)
  * error log: The error log from event_scan
  */
-int nvram_write_os_partition(struct nvram_os_partition *part, char * buff,
-               int length, unsigned int err_type, unsigned int error_log_cnt)
+static int nvram_write_os_partition(struct nvram_os_partition *part,
+                                   char *buff, int length,
+                                   unsigned int err_type,
+                                   unsigned int error_log_cnt)
 {
        int rc;
        loff_t tmp_index;
@@ -330,9 +332,9 @@ int nvram_write_error_log(char * buff, int length,
  *
  * Reads nvram partition for at most 'length'
  */
-int nvram_read_partition(struct nvram_os_partition *part, char *buff,
-                       int length, unsigned int *err_type,
-                       unsigned int *error_log_cnt)
+static int nvram_read_partition(struct nvram_os_partition *part, char *buff,
+                               int length, unsigned int *err_type,
+                               unsigned int *error_log_cnt)
 {
        int rc;
        loff_t tmp_index;
index c413ec158ff5a6587e7c611659f817dc33d9c7e4..67e48594040cb6fcceec3989b89ebb420f742037 100644 (file)
@@ -29,6 +29,7 @@
 #include <asm/pci-bridge.h>
 #include <asm/prom.h>
 #include <asm/ppc-pci.h>
+#include "pseries.h"
 
 #if 0
 void pcibios_name_device(struct pci_dev *dev)
index dff05b9eb94682267fed3a79c9ad72998ec7d053..5a4d0fc03b03f5666f9fe80e3e67d364cb46db9a 100644 (file)
@@ -126,7 +126,7 @@ struct epow_errorlog {
 #define EPOW_MAIN_ENCLOSURE            5
 #define EPOW_POWER_OFF                 7
 
-void rtas_parse_epow_errlog(struct rtas_error_log *log)
+static void rtas_parse_epow_errlog(struct rtas_error_log *log)
 {
        struct pseries_errorlog *pseries_log;
        struct epow_errorlog *epow_log;
index e724d3186e739999cc6daf726d073fe035d26739..125c589eeef52b9b8b2ee10bc8748f66c866ac12 100644 (file)
@@ -561,7 +561,7 @@ void pSeries_coalesce_init(void)
  * fw_cmo_feature_init - FW_FEATURE_CMO is not stored in ibm,hypertas-functions,
  * handle that here. (Stolen from parse_system_parameter_string)
  */
-void pSeries_cmo_feature_init(void)
+static void pSeries_cmo_feature_init(void)
 {
        char *ptr, *key, *value, *end;
        int call_status;
index 47b6b9f81d4305537b7d0e6290e178efb4253f4c..ad56edc39919fb223e21da9a9b75e8a9ba032b4e 100644 (file)
@@ -314,7 +314,7 @@ axon_ram_remove(struct platform_device *device)
        return 0;
 }
 
-static struct of_device_id axon_ram_device_id[] = {
+static const struct of_device_id axon_ram_device_id[] = {
        {
                .type   = "dma-memory"
        },
index e9056e4385756cf93a8e1d4ef7b54a9a1affa982..2d8a101b6b9edba7bebe70a8b03ebb4e2f0ba7ab 100644 (file)
@@ -230,5 +230,6 @@ EXPORT_SYMBOL_GPL(dcr_unmap_mmio);
 
 #ifdef CONFIG_PPC_DCR_NATIVE
 DEFINE_SPINLOCK(dcr_ind_lock);
+EXPORT_SYMBOL_GPL(dcr_ind_lock);
 #endif /* defined(CONFIG_PPC_DCR_NATIVE) */
 
index afc2dbf37011e67805d8ed1db68c801dca4073f0..90545ad1626ea2e68d1a1dc22baabc5731c0d2c3 100644 (file)
@@ -171,7 +171,7 @@ static int mpc85xx_l2ctlr_of_remove(struct platform_device *dev)
        return 0;
 }
 
-static struct of_device_id mpc85xx_l2ctlr_of_match[] = {
+static const struct of_device_id mpc85xx_l2ctlr_of_match[] = {
        {
                .compatible = "fsl,p2020-l2-cache-controller",
        },
index b32e79dbef4f1d14ca704a1e7bd6c6ff8cc13d6e..de40b48b460e83a8aaec5168c8a4a1f025d8dd38 100644 (file)
@@ -18,6 +18,8 @@
 #include <linux/pci.h>
 #include <linux/slab.h>
 #include <linux/of_platform.h>
+#include <linux/interrupt.h>
+#include <linux/seq_file.h>
 #include <sysdev/fsl_soc.h>
 #include <asm/prom.h>
 #include <asm/hw_irq.h>
@@ -50,6 +52,7 @@ struct fsl_msi_feature {
 struct fsl_msi_cascade_data {
        struct fsl_msi *msi_data;
        int index;
+       int virq;
 };
 
 static inline u32 fsl_msi_read(u32 __iomem *base, unsigned int reg)
@@ -65,11 +68,24 @@ static void fsl_msi_end_irq(struct irq_data *d)
 {
 }
 
+static void fsl_msi_print_chip(struct irq_data *irqd, struct seq_file *p)
+{
+       struct fsl_msi *msi_data = irqd->domain->host_data;
+       irq_hw_number_t hwirq = irqd_to_hwirq(irqd);
+       int cascade_virq, srs;
+
+       srs = (hwirq >> msi_data->srs_shift) & MSI_SRS_MASK;
+       cascade_virq = msi_data->cascade_array[srs]->virq;
+
+       seq_printf(p, " fsl-msi-%d", cascade_virq);
+}
+
+
 static struct irq_chip fsl_msi_chip = {
        .irq_mask       = mask_msi_irq,
        .irq_unmask     = unmask_msi_irq,
        .irq_ack        = fsl_msi_end_irq,
-       .name           = "FSL-MSI",
+       .irq_print_chip = fsl_msi_print_chip,
 };
 
 static int fsl_msi_host_map(struct irq_domain *h, unsigned int virq,
@@ -175,7 +191,8 @@ static int fsl_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type)
        np = of_parse_phandle(hose->dn, "fsl,msi", 0);
        if (np) {
                if (of_device_is_compatible(np, "fsl,mpic-msi") ||
-                   of_device_is_compatible(np, "fsl,vmpic-msi"))
+                   of_device_is_compatible(np, "fsl,vmpic-msi") ||
+                   of_device_is_compatible(np, "fsl,vmpic-msi-v4.3"))
                        phandle = np->phandle;
                else {
                        dev_err(&pdev->dev,
@@ -234,40 +251,24 @@ out_free:
        return rc;
 }
 
-static void fsl_msi_cascade(unsigned int irq, struct irq_desc *desc)
+static irqreturn_t fsl_msi_cascade(int irq, void *data)
 {
-       struct irq_chip *chip = irq_desc_get_chip(desc);
-       struct irq_data *idata = irq_desc_get_irq_data(desc);
        unsigned int cascade_irq;
        struct fsl_msi *msi_data;
        int msir_index = -1;
        u32 msir_value = 0;
        u32 intr_index;
        u32 have_shift = 0;
-       struct fsl_msi_cascade_data *cascade_data;
+       struct fsl_msi_cascade_data *cascade_data = data;
+       irqreturn_t ret = IRQ_NONE;
 
-       cascade_data = irq_get_handler_data(irq);
        msi_data = cascade_data->msi_data;
 
-       raw_spin_lock(&desc->lock);
-       if ((msi_data->feature &  FSL_PIC_IP_MASK) == FSL_PIC_IP_IPIC) {
-               if (chip->irq_mask_ack)
-                       chip->irq_mask_ack(idata);
-               else {
-                       chip->irq_mask(idata);
-                       chip->irq_ack(idata);
-               }
-       }
-
-       if (unlikely(irqd_irq_inprogress(idata)))
-               goto unlock;
-
        msir_index = cascade_data->index;
 
        if (msir_index >= NR_MSI_REG_MAX)
                cascade_irq = NO_IRQ;
 
-       irqd_set_chained_irq_inprogress(idata);
        switch (msi_data->feature & FSL_PIC_IP_MASK) {
        case FSL_PIC_IP_MPIC:
                msir_value = fsl_msi_read(msi_data->msi_regs,
@@ -296,40 +297,32 @@ static void fsl_msi_cascade(unsigned int irq, struct irq_desc *desc)
                cascade_irq = irq_linear_revmap(msi_data->irqhost,
                                msi_hwirq(msi_data, msir_index,
                                          intr_index + have_shift));
-               if (cascade_irq != NO_IRQ)
+               if (cascade_irq != NO_IRQ) {
                        generic_handle_irq(cascade_irq);
+                       ret = IRQ_HANDLED;
+               }
                have_shift += intr_index + 1;
                msir_value = msir_value >> (intr_index + 1);
        }
-       irqd_clr_chained_irq_inprogress(idata);
 
-       switch (msi_data->feature & FSL_PIC_IP_MASK) {
-       case FSL_PIC_IP_MPIC:
-       case FSL_PIC_IP_VMPIC:
-               chip->irq_eoi(idata);
-               break;
-       case FSL_PIC_IP_IPIC:
-               if (!irqd_irq_disabled(idata) && chip->irq_unmask)
-                       chip->irq_unmask(idata);
-               break;
-       }
-unlock:
-       raw_spin_unlock(&desc->lock);
+       return ret;
 }
 
 static int fsl_of_msi_remove(struct platform_device *ofdev)
 {
        struct fsl_msi *msi = platform_get_drvdata(ofdev);
        int virq, i;
-       struct fsl_msi_cascade_data *cascade_data;
 
        if (msi->list.prev != NULL)
                list_del(&msi->list);
        for (i = 0; i < NR_MSI_REG_MAX; i++) {
-               virq = msi->msi_virqs[i];
-               if (virq != NO_IRQ) {
-                       cascade_data = irq_get_handler_data(virq);
-                       kfree(cascade_data);
+               if (msi->cascade_array[i]) {
+                       virq = msi->cascade_array[i]->virq;
+
+                       BUG_ON(virq == NO_IRQ);
+
+                       free_irq(virq, msi->cascade_array[i]);
+                       kfree(msi->cascade_array[i]);
                        irq_dispose_mapping(virq);
                }
        }
@@ -348,7 +341,7 @@ static int fsl_msi_setup_hwirq(struct fsl_msi *msi, struct platform_device *dev,
                               int offset, int irq_index)
 {
        struct fsl_msi_cascade_data *cascade_data = NULL;
-       int virt_msir, i;
+       int virt_msir, i, ret;
 
        virt_msir = irq_of_parse_and_map(dev->dev.of_node, irq_index);
        if (virt_msir == NO_IRQ) {
@@ -363,11 +356,18 @@ static int fsl_msi_setup_hwirq(struct fsl_msi *msi, struct platform_device *dev,
                return -ENOMEM;
        }
        irq_set_lockdep_class(virt_msir, &fsl_msi_irq_class);
-       msi->msi_virqs[irq_index] = virt_msir;
        cascade_data->index = offset;
        cascade_data->msi_data = msi;
-       irq_set_handler_data(virt_msir, cascade_data);
-       irq_set_chained_handler(virt_msir, fsl_msi_cascade);
+       cascade_data->virq = virt_msir;
+       msi->cascade_array[irq_index] = cascade_data;
+
+       ret = request_irq(virt_msir, fsl_msi_cascade, 0,
+                         "fsl-msi-cascade", cascade_data);
+       if (ret) {
+               dev_err(&dev->dev, "failed to request_irq(%d), ret = %d\n",
+                       virt_msir, ret);
+               return ret;
+       }
 
        /* Release the hwirqs corresponding to this MSI register */
        for (i = 0; i < IRQS_PER_MSI_REG; i++)
@@ -461,7 +461,8 @@ static int fsl_of_msi_probe(struct platform_device *dev)
 
        p = of_get_property(dev->dev.of_node, "msi-available-ranges", &len);
 
-       if (of_device_is_compatible(dev->dev.of_node, "fsl,mpic-msi-v4.3")) {
+       if (of_device_is_compatible(dev->dev.of_node, "fsl,mpic-msi-v4.3") ||
+           of_device_is_compatible(dev->dev.of_node, "fsl,vmpic-msi-v4.3")) {
                msi->srs_shift = MSIIR1_SRS_SHIFT;
                msi->ibs_shift = MSIIR1_IBS_SHIFT;
                if (p)
@@ -566,6 +567,10 @@ static const struct of_device_id fsl_of_msi_ids[] = {
                .compatible = "fsl,vmpic-msi",
                .data = &vmpic_msi_feature,
        },
+       {
+               .compatible = "fsl,vmpic-msi-v4.3",
+               .data = &vmpic_msi_feature,
+       },
 #endif
        {}
 };
index df9aa9fe0933b1f1f08ca8dcb270218b955e5b5b..420cfcbdac01c5c30a72fa64613a43373e17c8c5 100644 (file)
@@ -27,6 +27,8 @@
 #define FSL_PIC_IP_IPIC   0x00000002
 #define FSL_PIC_IP_VMPIC  0x00000003
 
+struct fsl_msi_cascade_data;
+
 struct fsl_msi {
        struct irq_domain *irqhost;
 
@@ -37,7 +39,7 @@ struct fsl_msi {
        u32 srs_shift; /* Shift of the shared interrupt register select */
        void __iomem *msi_regs;
        u32 feature;
-       int msi_virqs[NR_MSI_REG_MAX];
+       struct fsl_msi_cascade_data *cascade_array[NR_MSI_REG_MAX];
 
        struct msi_bitmap bitmap;
 
index c5077673bd9433633be839cc58c02bfc6137d29c..65d2ed4549e667ec981f272d88ff12fc234e9fd9 100644 (file)
@@ -522,7 +522,8 @@ int fsl_add_bridge(struct platform_device *pdev, int is_primary)
        } else {
                /* For PCI read PROG to identify controller mode */
                early_read_config_byte(hose, 0, 0, PCI_CLASS_PROG, &progif);
-               if ((progif & 1) == 1)
+               if ((progif & 1) &&
+                   !of_property_read_bool(dev, "fsl,pci-agent-force-enum"))
                        goto no_bridge;
        }
 
index be33c9768ea11b376669083eeb4eec605ae13e16..89cec0ed6a58acc9104ef2727d7313f5e9031451 100644 (file)
@@ -960,7 +960,7 @@ void mpic_set_vector(unsigned int virq, unsigned int vector)
        mpic_irq_write(src, MPIC_INFO(IRQ_VECTOR_PRI), vecpri);
 }
 
-void mpic_set_destination(unsigned int virq, unsigned int cpuid)
+static void mpic_set_destination(unsigned int virq, unsigned int cpuid)
 {
        struct mpic *mpic = mpic_from_irq(virq);
        unsigned int src = virq_to_hw(virq);
index 2ff630267e9efaef1eac6cf15634751e6de51b9e..0c75214b6f9220d433f8ea88776041694f744add 100644 (file)
@@ -20,32 +20,37 @@ int msi_bitmap_alloc_hwirqs(struct msi_bitmap *bmp, int num)
        int offset, order = get_count_order(num);
 
        spin_lock_irqsave(&bmp->lock, flags);
-       /*
-        * This is fast, but stricter than we need. We might want to add
-        * a fallback routine which does a linear search with no alignment.
-        */
-       offset = bitmap_find_free_region(bmp->bitmap, bmp->irq_count, order);
+
+       offset = bitmap_find_next_zero_area(bmp->bitmap, bmp->irq_count, 0,
+                                           num, (1 << order) - 1);
+       if (offset > bmp->irq_count)
+               goto err;
+
+       bitmap_set(bmp->bitmap, offset, num);
        spin_unlock_irqrestore(&bmp->lock, flags);
 
-       pr_debug("msi_bitmap: allocated 0x%x (2^%d) at offset 0x%x\n",
-                num, order, offset);
+       pr_debug("msi_bitmap: allocated 0x%x at offset 0x%x\n", num, offset);
 
        return offset;
+err:
+       spin_unlock_irqrestore(&bmp->lock, flags);
+       return -ENOMEM;
 }
+EXPORT_SYMBOL(msi_bitmap_alloc_hwirqs);
 
 void msi_bitmap_free_hwirqs(struct msi_bitmap *bmp, unsigned int offset,
                            unsigned int num)
 {
        unsigned long flags;
-       int order = get_count_order(num);
 
-       pr_debug("msi_bitmap: freeing 0x%x (2^%d) at offset 0x%x\n",
-                num, order, offset);
+       pr_debug("msi_bitmap: freeing 0x%x at offset 0x%x\n",
+                num, offset);
 
        spin_lock_irqsave(&bmp->lock, flags);
-       bitmap_release_region(bmp->bitmap, offset, order);
+       bitmap_clear(bmp->bitmap, offset, num);
        spin_unlock_irqrestore(&bmp->lock, flags);
 }
+EXPORT_SYMBOL(msi_bitmap_free_hwirqs);
 
 void msi_bitmap_reserve_hwirq(struct msi_bitmap *bmp, unsigned int hwirq)
 {
@@ -143,7 +148,7 @@ void msi_bitmap_free(struct msi_bitmap *bmp)
 #define check(x)       \
        if (!(x)) printk("msi_bitmap: test failed at line %d\n", __LINE__);
 
-void __init test_basics(void)
+static void __init test_basics(void)
 {
        struct msi_bitmap bmp;
        int i, size = 512;
@@ -180,6 +185,15 @@ void __init test_basics(void)
        msi_bitmap_free_hwirqs(&bmp, size / 2, 1);
        check(msi_bitmap_alloc_hwirqs(&bmp, 1) == size / 2);
 
+       /* Check we get a naturally aligned offset */
+       check(msi_bitmap_alloc_hwirqs(&bmp, 2) % 2 == 0);
+       check(msi_bitmap_alloc_hwirqs(&bmp, 4) % 4 == 0);
+       check(msi_bitmap_alloc_hwirqs(&bmp, 8) % 8 == 0);
+       check(msi_bitmap_alloc_hwirqs(&bmp, 9) % 16 == 0);
+       check(msi_bitmap_alloc_hwirqs(&bmp, 3) % 4 == 0);
+       check(msi_bitmap_alloc_hwirqs(&bmp, 7) % 8 == 0);
+       check(msi_bitmap_alloc_hwirqs(&bmp, 121) % 128 == 0);
+
        msi_bitmap_free(&bmp);
 
        /* Clients may check bitmap == NULL for "not-allocated" */
@@ -188,7 +202,7 @@ void __init test_basics(void)
        kfree(bmp.bitmap);
 }
 
-void __init test_of_node(void)
+static void __init test_of_node(void)
 {
        u32 prop_data[] = { 10, 10, 25, 3, 40, 1, 100, 100, 200, 20 };
        const char *expected_str = "0-9,20-24,28-39,41-99,220-255";
@@ -236,7 +250,7 @@ void __init test_of_node(void)
        kfree(bmp.bitmap);
 }
 
-int __init msi_bitmap_selftest(void)
+static int __init msi_bitmap_selftest(void)
 {
        printk(KERN_DEBUG "Running MSI bitmap self-tests ...\n");
 
index c2dba7db71ad533bf15b20739646f1369013033f..026bbc3b2c47d75f967d777bc797f446a615438c 100644 (file)
@@ -23,7 +23,7 @@
 
 /* These functions provide the necessary setup for the mv64x60 drivers. */
 
-static struct of_device_id __initdata of_mv64x60_devices[] = {
+static const struct of_device_id of_mv64x60_devices[] __initconst = {
        { .compatible = "marvell,mv64306-devctrl", },
        {}
 };
index 5aaf86c03893446474b538760d6d3fa169ec4e2b..13e67d93a7c111f785df07050c5e991104bb0407 100644 (file)
@@ -101,7 +101,7 @@ out:
 }
 
 
-static struct of_device_id pmi_match[] = {
+static const struct of_device_id pmi_match[] = {
        { .type = "ibm,pmi", .name = "ibm,pmi" },
        { .type = "ibm,pmi" },
        {},
index de8d9483bbe89136042d0685680c6bddc815849a..2fc4cf1b75575f9916e26fcf330cfce4959f39a5 100644 (file)
@@ -155,6 +155,31 @@ static void icp_native_cause_ipi(int cpu, unsigned long data)
                icp_native_set_qirr(cpu, IPI_PRIORITY);
 }
 
+/*
+ * Called when an interrupt is received on an off-line CPU to
+ * clear the interrupt, so that the CPU can go back to nap mode.
+ */
+void icp_native_flush_interrupt(void)
+{
+       unsigned int xirr = icp_native_get_xirr();
+       unsigned int vec = xirr & 0x00ffffff;
+
+       if (vec == XICS_IRQ_SPURIOUS)
+               return;
+       if (vec == XICS_IPI) {
+               /* Clear pending IPI */
+               int cpu = smp_processor_id();
+               kvmppc_set_host_ipi(cpu, 0);
+               icp_native_set_qirr(cpu, 0xff);
+       } else {
+               pr_err("XICS: hw interrupt 0x%x to offline cpu, disabling\n",
+                      vec);
+               xics_mask_unknown_vec(vec);
+       }
+       /* EOI the interrupt */
+       icp_native_set_xirr(xirr);
+}
+
 void xics_wake_cpu(int cpu)
 {
        icp_native_set_qirr(cpu, IPI_PRIORITY);
index 83f943a8e0db90ed0cf7a700c70f201861db8062..56f0524e47a6f84f723d26a3bf90a2c688b4d051 100644 (file)
@@ -265,7 +265,7 @@ static void __init xilinx_i8259_setup_cascade(void)
 static inline void xilinx_i8259_setup_cascade(void) { return; }
 #endif /* defined(CONFIG_PPC_I8259) */
 
-static struct of_device_id xilinx_intc_match[] __initconst = {
+static const struct of_device_id xilinx_intc_match[] __initconst = {
        { .compatible = "xlnx,opb-intc-1.00.c", },
        { .compatible = "xlnx,xps-intc-1.00.a", },
        {}
index 1453b0eed2202acf7facca6628db2f09b00ed9bf..fea5667699ed99f33795573254e994bebcb729de 100644 (file)
@@ -27,7 +27,7 @@
 
 #define PCI_HOST_ENABLE_CMD PCI_COMMAND_SERR | PCI_COMMAND_PARITY | PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY
 
-static struct of_device_id xilinx_pci_match[] = {
+static const struct of_device_id xilinx_pci_match[] = {
        { .compatible = "xlnx,plbv46-pci-1.03.a", },
        {}
 };
index 05c78bb5f57024bf220e778af99888a1df6e6bbc..f2cf1f90295b6b38e855b398a3e0a2180e82fe4e 100644 (file)
@@ -58,6 +58,9 @@ config NO_IOPORT_MAP
 config PCI_QUIRKS
        def_bool n
 
+config ARCH_SUPPORTS_UPROBES
+       def_bool 64BIT
+
 config S390
        def_bool y
        select ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE
@@ -97,6 +100,7 @@ config S390
        select ARCH_WANT_IPC_PARSE_VERSION
        select BUILDTIME_EXTABLE_SORT
        select CLONE_BACKWARDS2
+       select DYNAMIC_FTRACE if FUNCTION_TRACER
        select GENERIC_CLOCKEVENTS
        select GENERIC_CPU_DEVICES if !SMP
        select GENERIC_FIND_FIRST_BIT
@@ -113,10 +117,11 @@ config S390
        select HAVE_CMPXCHG_LOCAL
        select HAVE_C_RECORDMCOUNT
        select HAVE_DEBUG_KMEMLEAK
-       select HAVE_DYNAMIC_FTRACE
+       select HAVE_DYNAMIC_FTRACE if 64BIT
+       select HAVE_DYNAMIC_FTRACE_WITH_REGS if 64BIT
        select HAVE_FTRACE_MCOUNT_RECORD
-       select HAVE_FUNCTION_GRAPH_TRACER
-       select HAVE_FUNCTION_TRACER
+       select HAVE_FUNCTION_GRAPH_TRACER if 64BIT
+       select HAVE_FUNCTION_TRACER if 64BIT
        select HAVE_FUTEX_CMPXCHG if FUTEX
        select HAVE_KERNEL_BZIP2
        select HAVE_KERNEL_GZIP
@@ -496,8 +501,8 @@ config QDIO
 
 menuconfig PCI
        bool "PCI support"
-       default n
        depends on 64BIT
+       select HAVE_DMA_ATTRS
        select PCI_MSI
        help
          Enable PCI support.
@@ -544,9 +549,6 @@ config HAS_DMA
 config NEED_SG_DMA_LENGTH
        def_bool PCI
 
-config HAVE_DMA_ATTRS
-       def_bool PCI
-
 config NEED_DMA_MAP_STATE
        def_bool PCI
 
index 874e6d6e9c5fe41e035f4fafb08f0cba44f92760..878e67973151b54c93c5eb078d53a4beef330f10 100644 (file)
@@ -35,13 +35,16 @@ endif
 
 export LD_BFD
 
-cflags-$(CONFIG_MARCH_G5)     += -march=g5
-cflags-$(CONFIG_MARCH_Z900)   += -march=z900
-cflags-$(CONFIG_MARCH_Z990)   += -march=z990
-cflags-$(CONFIG_MARCH_Z9_109) += -march=z9-109
-cflags-$(CONFIG_MARCH_Z10)    += -march=z10
-cflags-$(CONFIG_MARCH_Z196)   += -march=z196
-cflags-$(CONFIG_MARCH_ZEC12)  += -march=zEC12
+mflags-$(CONFIG_MARCH_G5)     := -march=g5
+mflags-$(CONFIG_MARCH_Z900)   := -march=z900
+mflags-$(CONFIG_MARCH_Z990)   := -march=z990
+mflags-$(CONFIG_MARCH_Z9_109) := -march=z9-109
+mflags-$(CONFIG_MARCH_Z10)    := -march=z10
+mflags-$(CONFIG_MARCH_Z196)   := -march=z196
+mflags-$(CONFIG_MARCH_ZEC12)  := -march=zEC12
+
+aflags-y += $(mflags-y)
+cflags-y += $(mflags-y)
 
 cflags-$(CONFIG_MARCH_G5_TUNE)         += -mtune=g5
 cflags-$(CONFIG_MARCH_Z900_TUNE)       += -mtune=z900
index 19ff956b752baf751380e1ecf553b8983cdad56d..b5dce6544d76e3357e4e8629333817008a0ee183 100644 (file)
 
 #ifdef CONFIG_HAVE_MARCH_Z196_FEATURES
 /* Fast-BCR without checkpoint synchronization */
-#define mb() do {  asm volatile("bcr 14,0" : : : "memory"); } while (0)
+#define __ASM_BARRIER "bcr 14,0\n"
 #else
-#define mb() do {  asm volatile("bcr 15,0" : : : "memory"); } while (0)
+#define __ASM_BARRIER "bcr 15,0\n"
 #endif
 
+#define mb() do {  asm volatile(__ASM_BARRIER : : : "memory"); } while (0)
+
 #define rmb()                          mb()
 #define wmb()                          mb()
 #define read_barrier_depends()         do { } while(0)
index f65bd36345194db88b71bca1f3740cca8744fa33..f8c196984853e963c6e22dc6553b5f4cccdc2d23 100644 (file)
@@ -8,8 +8,6 @@
 #define _S390_CPUTIME_H
 
 #include <linux/types.h>
-#include <linux/percpu.h>
-#include <linux/spinlock.h>
 #include <asm/div64.h>
 
 
@@ -18,6 +16,8 @@
 typedef unsigned long long __nocast cputime_t;
 typedef unsigned long long __nocast cputime64_t;
 
+#define cmpxchg_cputime(ptr, old, new) cmpxchg64(ptr, old, new)
+
 static inline unsigned long __div(unsigned long long n, unsigned long base)
 {
 #ifndef CONFIG_64BIT
@@ -165,28 +165,8 @@ static inline clock_t cputime64_to_clock_t(cputime64_t cputime)
        return clock;
 }
 
-struct s390_idle_data {
-       int nohz_delay;
-       unsigned int sequence;
-       unsigned long long idle_count;
-       unsigned long long idle_time;
-       unsigned long long clock_idle_enter;
-       unsigned long long clock_idle_exit;
-       unsigned long long timer_idle_enter;
-       unsigned long long timer_idle_exit;
-};
-
-DECLARE_PER_CPU(struct s390_idle_data, s390_idle);
-
-cputime64_t s390_get_idle_time(int cpu);
-
-#define arch_idle_time(cpu) s390_get_idle_time(cpu)
-
-static inline int s390_nohz_delay(int cpu)
-{
-       return __get_cpu_var(s390_idle).nohz_delay != 0;
-}
+cputime64_t arch_cpu_idle_time(int cpu);
 
-#define arch_needs_cpu(cpu) s390_nohz_delay(cpu)
+#define arch_idle_time(cpu) arch_cpu_idle_time(cpu)
 
 #endif /* _S390_CPUTIME_H */
index 04a83f5773cd5638959c8d7187a4c0043ffca190..60323c21938bb5d97407e9f0cb35c6fcdd335597 100644 (file)
 #define OPERAND_FPR    0x2     /* Operand printed as %fx */
 #define OPERAND_AR     0x4     /* Operand printed as %ax */
 #define OPERAND_CR     0x8     /* Operand printed as %cx */
-#define OPERAND_DISP   0x10    /* Operand printed as displacement */
-#define OPERAND_BASE   0x20    /* Operand printed as base register */
-#define OPERAND_INDEX  0x40    /* Operand printed as index register */
-#define OPERAND_PCREL  0x80    /* Operand printed as pc-relative symbol */
-#define OPERAND_SIGNED 0x100   /* Operand printed as signed value */
-#define OPERAND_LENGTH 0x200   /* Operand printed as length (+1) */
+#define OPERAND_VR     0x10    /* Operand printed as %vx */
+#define OPERAND_DISP   0x20    /* Operand printed as displacement */
+#define OPERAND_BASE   0x40    /* Operand printed as base register */
+#define OPERAND_INDEX  0x80    /* Operand printed as index register */
+#define OPERAND_PCREL  0x100   /* Operand printed as pc-relative symbol */
+#define OPERAND_SIGNED 0x200   /* Operand printed as signed value */
+#define OPERAND_LENGTH 0x400   /* Operand printed as length (+1) */
 
 
 struct s390_operand {
index 3fbc67d9e19739edbf5be625a68c5f7e34153771..709955ddaa4deeb822715e24e3e24a149868ff10 100644 (file)
@@ -56,24 +56,35 @@ static inline int dma_mapping_error(struct device *dev, dma_addr_t dma_addr)
        return dma_addr == DMA_ERROR_CODE;
 }
 
-static inline void *dma_alloc_coherent(struct device *dev, size_t size,
-                                      dma_addr_t *dma_handle, gfp_t flag)
+#define dma_alloc_coherent(d, s, h, f) dma_alloc_attrs(d, s, h, f, NULL)
+
+static inline void *dma_alloc_attrs(struct device *dev, size_t size,
+                                   dma_addr_t *dma_handle, gfp_t flags,
+                                   struct dma_attrs *attrs)
 {
        struct dma_map_ops *ops = get_dma_ops(dev);
-       void *ret;
+       void *cpu_addr;
+
+       BUG_ON(!ops);
 
-       ret = ops->alloc(dev, size, dma_handle, flag, NULL);
-       debug_dma_alloc_coherent(dev, size, *dma_handle, ret);
-       return ret;
+       cpu_addr = ops->alloc(dev, size, dma_handle, flags, attrs);
+       debug_dma_alloc_coherent(dev, size, *dma_handle, cpu_addr);
+
+       return cpu_addr;
 }
 
-static inline void dma_free_coherent(struct device *dev, size_t size,
-                                    void *cpu_addr, dma_addr_t dma_handle)
+#define dma_free_coherent(d, s, c, h) dma_free_attrs(d, s, c, h, NULL)
+
+static inline void dma_free_attrs(struct device *dev, size_t size,
+                                 void *cpu_addr, dma_addr_t dma_handle,
+                                 struct dma_attrs *attrs)
 {
-       struct dma_map_ops *dma_ops = get_dma_ops(dev);
+       struct dma_map_ops *ops = get_dma_ops(dev);
+
+       BUG_ON(!ops);
 
        debug_dma_free_coherent(dev, size, cpu_addr, dma_handle);
-       dma_ops->free(dev, size, cpu_addr, dma_handle, NULL);
+       ops->free(dev, size, cpu_addr, dma_handle, attrs);
 }
 
 #endif /* _ASM_S390_DMA_MAPPING_H */
index 78f4f8711d58a78f0a3e277b13719bd1514f38ea..f6e43d39e3d82e7c86e771078b752a88f998c481 100644 (file)
 #define HWCAP_S390_ETF3EH      256
 #define HWCAP_S390_HIGH_GPRS   512
 #define HWCAP_S390_TE          1024
+#define HWCAP_S390_VXRS                2048
 
 /*
  * These are used to set parameters in the core dumps.
@@ -225,6 +226,6 @@ int arch_setup_additional_pages(struct linux_binprm *, int);
 extern unsigned long arch_randomize_brk(struct mm_struct *mm);
 #define arch_randomize_brk arch_randomize_brk
 
-void *fill_cpu_elf_notes(void *ptr, struct save_area *sa);
+void *fill_cpu_elf_notes(void *ptr, struct save_area *sa, __vector128 *vxrs);
 
 #endif
index bf246dae1367333c109f7f28a60789c2f97deb84..3aef8afec336c822e2f3f44b76209e510ab510e0 100644 (file)
@@ -4,6 +4,7 @@
 #ifndef __ASSEMBLY__
 
 extern void _mcount(void);
+extern char ftrace_graph_caller_end;
 
 struct dyn_arch_ftrace { };
 
@@ -17,10 +18,8 @@ static inline unsigned long ftrace_call_adjust(unsigned long addr)
 
 #endif /* __ASSEMBLY__ */
 
-#ifdef CONFIG_64BIT
-#define MCOUNT_INSN_SIZE  12
-#else
-#define MCOUNT_INSN_SIZE  22
-#endif
+#define MCOUNT_INSN_SIZE  18
+
+#define ARCH_SUPPORTS_FTRACE_OPS 1
 
 #endif /* _ASM_S390_FTRACE_H */
diff --git a/arch/s390/include/asm/idle.h b/arch/s390/include/asm/idle.h
new file mode 100644 (file)
index 0000000..6af037f
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ *  Copyright IBM Corp. 2014
+ *
+ *  Author: Martin Schwidefsky <schwidefsky@de.ibm.com>
+ */
+
+#ifndef _S390_IDLE_H
+#define _S390_IDLE_H
+
+#include <linux/types.h>
+#include <linux/device.h>
+
+struct s390_idle_data {
+       unsigned int sequence;
+       unsigned long long idle_count;
+       unsigned long long idle_time;
+       unsigned long long clock_idle_enter;
+       unsigned long long clock_idle_exit;
+       unsigned long long timer_idle_enter;
+       unsigned long long timer_idle_exit;
+};
+
+extern struct device_attribute dev_attr_idle_count;
+extern struct device_attribute dev_attr_idle_time_us;
+
+#endif /* _S390_IDLE_H */
index c81661e756a0396bb8e90dee214492b154081d91..ece606c2ee8674111b81bf9c5a6342e8ae5db421 100644 (file)
@@ -89,12 +89,12 @@ extern u32 ipl_flags;
 extern u32 dump_prefix_page;
 
 struct dump_save_areas {
-       struct save_area **areas;
+       struct save_area_ext **areas;
        int count;
 };
 
 extern struct dump_save_areas dump_save_areas;
-struct save_area *dump_save_area_create(int cpu);
+struct save_area_ext *dump_save_area_create(int cpu);
 
 extern void do_reipl(void);
 extern void do_halt(void);
index c4dd400a27917b7fa38a4e6daf66d91b5e88e688..e787cc1bff8fa30874358e069ecbeb1a8b136b10 100644 (file)
@@ -51,6 +51,7 @@ enum interruption_class {
        IRQEXT_CMS,
        IRQEXT_CMC,
        IRQEXT_CMR,
+       IRQEXT_FTP,
        IRQIO_CIO,
        IRQIO_QAI,
        IRQIO_DAS,
index 4176dfe0fba1c75ed253966ecab56eeea54c174b..98629173ce3b38bf07b07324df8515b1c5e285ad 100644 (file)
@@ -84,6 +84,10 @@ int kprobe_fault_handler(struct pt_regs *regs, int trapnr);
 int kprobe_exceptions_notify(struct notifier_block *self,
        unsigned long val, void *data);
 
+int probe_is_prohibited_opcode(u16 *insn);
+int probe_get_fixup_type(u16 *insn);
+int probe_is_insn_relative_long(u16 *insn);
+
 #define flush_insn_slot(p)     do { } while (0)
 
 #endif /* _ASM_S390_KPROBES_H */
index 4349197ab9df9019ea5a23938f4b473e8d95442f..6cc51fe844108d712285ddfeb7b970a2f33d8329 100644 (file)
@@ -11,6 +11,7 @@
 #include <linux/types.h>
 #include <asm/ptrace.h>
 #include <asm/cpu.h>
+#include <asm/types.h>
 
 #ifdef CONFIG_32BIT
 
@@ -31,6 +32,11 @@ struct save_area {
        u32     ctrl_regs[16];
 } __packed;
 
+struct save_area_ext {
+       struct save_area        sa;
+       __vector128             vx_regs[32];
+};
+
 struct _lowcore {
        psw_t   restart_psw;                    /* 0x0000 */
        psw_t   restart_old_psw;                /* 0x0008 */
@@ -183,6 +189,11 @@ struct save_area {
        u64     ctrl_regs[16];
 } __packed;
 
+struct save_area_ext {
+       struct save_area        sa;
+       __vector128             vx_regs[32];
+};
+
 struct _lowcore {
        __u8    pad_0x0000[0x0014-0x0000];      /* 0x0000 */
        __u32   ipl_parmblock_ptr;              /* 0x0014 */
@@ -310,7 +321,10 @@ struct _lowcore {
 
        /* Extended facility list */
        __u64   stfle_fac_list[32];             /* 0x0f00 */
-       __u8    pad_0x1000[0x11b8-0x1000];      /* 0x1000 */
+       __u8    pad_0x1000[0x11b0-0x1000];      /* 0x1000 */
+
+       /* Pointer to vector register save area */
+       __u64   vector_save_area_addr;          /* 0x11b0 */
 
        /* 64 bit extparam used for pfault/diag 250: defined by architecture */
        __u64   ext_params2;                    /* 0x11B8 */
@@ -334,9 +348,10 @@ struct _lowcore {
 
        /* Transaction abort diagnostic block */
        __u8    pgm_tdb[256];                   /* 0x1800 */
+       __u8    pad_0x1900[0x1c00-0x1900];      /* 0x1900 */
 
-       /* align to the top of the prefix area */
-       __u8    pad_0x1900[0x2000-0x1900];      /* 0x1900 */
+       /* Software defined save area for vector registers */
+       __u8    vector_save_area[1024];         /* 0x1c00 */
 } __packed;
 
 #endif /* CONFIG_32BIT */
index 35f8ec185616f07a1485b1bd7085133d3f299d07..3027a5a72b748ab776d1693df011da55a2049ea1 100644 (file)
@@ -38,7 +38,7 @@ struct mci {
        __u32 pm :  1; /* 22 psw program mask and cc validity */
        __u32 ia :  1; /* 23 psw instruction address validity */
        __u32 fa :  1; /* 24 failing storage address validity */
-       __u32    :  1; /* 25 */
+       __u32 vr :  1; /* 25 vector register validity */
        __u32 ec :  1; /* 26 external damage code validity */
        __u32 fp :  1; /* 27 floating point register validity */
        __u32 gr :  1; /* 28 general register validity */
index b7054356cc9843ba4e80d17bc38614614f3361e3..57c882761deaa2e543342e5bb68cdb5524851eef 100644 (file)
@@ -217,7 +217,6 @@ extern unsigned long MODULES_END;
  */
 
 /* Hardware bits in the page table entry */
-#define _PAGE_CO       0x100           /* HW Change-bit override */
 #define _PAGE_PROTECT  0x200           /* HW read-only bit  */
 #define _PAGE_INVALID  0x400           /* HW invalid bit    */
 #define _PAGE_LARGE    0x800           /* Bit to mark a large pte */
@@ -234,8 +233,8 @@ extern unsigned long MODULES_END;
 #define __HAVE_ARCH_PTE_SPECIAL
 
 /* Set of bits not changed in pte_modify */
-#define _PAGE_CHG_MASK         (PAGE_MASK | _PAGE_SPECIAL | _PAGE_CO | \
-                                _PAGE_DIRTY | _PAGE_YOUNG)
+#define _PAGE_CHG_MASK         (PAGE_MASK | _PAGE_SPECIAL | _PAGE_DIRTY | \
+                                _PAGE_YOUNG)
 
 /*
  * handle_pte_fault uses pte_present, pte_none and pte_file to find out the
@@ -354,7 +353,6 @@ extern unsigned long MODULES_END;
 
 #define _REGION3_ENTRY_LARGE   0x400   /* RTTE-format control, large page  */
 #define _REGION3_ENTRY_RO      0x200   /* page protection bit              */
-#define _REGION3_ENTRY_CO      0x100   /* change-recording override        */
 
 /* Bits in the segment table entry */
 #define _SEGMENT_ENTRY_BITS    0xfffffffffffffe33UL
@@ -371,7 +369,6 @@ extern unsigned long MODULES_END;
 #define _SEGMENT_ENTRY_YOUNG   0x1000  /* SW segment young bit */
 #define _SEGMENT_ENTRY_SPLIT   0x0800  /* THP splitting bit */
 #define _SEGMENT_ENTRY_LARGE   0x0400  /* STE-format control, large page */
-#define _SEGMENT_ENTRY_CO      0x0100  /* change-recording override   */
 #define _SEGMENT_ENTRY_READ    0x0002  /* SW segment read bit */
 #define _SEGMENT_ENTRY_WRITE   0x0001  /* SW segment write bit */
 
@@ -873,8 +870,6 @@ static inline void set_pte_at(struct mm_struct *mm, unsigned long addr,
                pgste = pgste_set_pte(ptep, pgste, entry);
                pgste_set_unlock(ptep, pgste);
        } else {
-               if (!(pte_val(entry) & _PAGE_INVALID) && MACHINE_HAS_EDAT1)
-                       pte_val(entry) |= _PAGE_CO;
                *ptep = entry;
        }
 }
@@ -1044,6 +1039,22 @@ static inline void __ptep_ipte_local(unsigned long address, pte_t *ptep)
                : "=m" (*ptep) : "m" (*ptep), "a" (pto), "a" (address));
 }
 
+static inline void __ptep_ipte_range(unsigned long address, int nr, pte_t *ptep)
+{
+       unsigned long pto = (unsigned long) ptep;
+
+#ifndef CONFIG_64BIT
+       /* pto in ESA mode must point to the start of the segment table */
+       pto &= 0x7ffffc00;
+#endif
+       /* Invalidate a range of ptes + global TLB flush of the ptes */
+       do {
+               asm volatile(
+                       "       .insn rrf,0xb2210000,%2,%0,%1,0"
+                       : "+a" (address), "+a" (nr) : "a" (pto) : "memory");
+       } while (nr != 255);
+}
+
 static inline void ptep_flush_direct(struct mm_struct *mm,
                                     unsigned long address, pte_t *ptep)
 {
index e568fc8a725062f707b7875c7c4010a21bd0fcfa..d559bdb03d18325f5c5fda2e97eb0136aeb1baf3 100644 (file)
 
 #define CIF_MCCK_PENDING       0       /* machine check handling is pending */
 #define CIF_ASCE               1       /* user asce needs fixup / uaccess */
+#define CIF_NOHZ_DELAY         2       /* delay HZ disable for a tick */
 
 #define _CIF_MCCK_PENDING      (1<<CIF_MCCK_PENDING)
 #define _CIF_ASCE              (1<<CIF_ASCE)
+#define _CIF_NOHZ_DELAY                (1<<CIF_NOHZ_DELAY)
 
 
 #ifndef __ASSEMBLY__
@@ -43,6 +45,8 @@ static inline int test_cpu_flag(int flag)
        return !!(S390_lowcore.cpu_flags & (1U << flag));
 }
 
+#define arch_needs_cpu() test_cpu_flag(CIF_NOHZ_DELAY)
+
 /*
  * Default implementation of macro that returns current
  * instruction pointer ("program counter").
@@ -113,6 +117,7 @@ struct thread_struct {
        int ri_signum;
 #ifdef CONFIG_64BIT
        unsigned char trap_tdb[256];    /* Transaction abort diagnose block */
+       __vector128 *vxrs;              /* Vector register save area */
 #endif
 };
 
@@ -285,7 +290,12 @@ static inline unsigned long __rewind_psw(psw_t psw, unsigned long ilc)
        return (psw.addr - ilc) & mask;
 #endif
 }
+
+/*
+ * Function to stop a processor until the next interrupt occurs
+ */
+void enabled_wait(void);
+
 /*
  * Function to drop a processor into disabled wait state
  */
index 55d69dd7473c82db6f61855856fbd60e8c029272..be317feff7ac47fcdb0d6cd8903156c429c23255 100644 (file)
@@ -161,6 +161,12 @@ static inline long regs_return_value(struct pt_regs *regs)
        return regs->gprs[2];
 }
 
+static inline void instruction_pointer_set(struct pt_regs *regs,
+                                          unsigned long val)
+{
+       regs->psw.addr = val | PSW_ADDR_AMODE;
+}
+
 int regs_query_register_offset(const char *name);
 const char *regs_query_register_name(unsigned int offset);
 unsigned long regs_get_register(struct pt_regs *regs, unsigned int offset);
index 089a49814c505b506ed1689230a470ebfc575d03..7736fdd725953c862f3df931723ed355d8b23f8b 100644 (file)
@@ -55,8 +55,8 @@ extern void detect_memory_memblock(void);
 #define MACHINE_FLAG_LPP       (1UL << 13)
 #define MACHINE_FLAG_TOPOLOGY  (1UL << 14)
 #define MACHINE_FLAG_TE                (1UL << 15)
-#define MACHINE_FLAG_RRBM      (1UL << 16)
 #define MACHINE_FLAG_TLB_LC    (1UL << 17)
+#define MACHINE_FLAG_VX                (1UL << 18)
 
 #define MACHINE_IS_VM          (S390_lowcore.machine_flags & MACHINE_FLAG_VM)
 #define MACHINE_IS_KVM         (S390_lowcore.machine_flags & MACHINE_FLAG_KVM)
@@ -78,8 +78,8 @@ extern void detect_memory_memblock(void);
 #define MACHINE_HAS_LPP                (0)
 #define MACHINE_HAS_TOPOLOGY   (0)
 #define MACHINE_HAS_TE         (0)
-#define MACHINE_HAS_RRBM       (0)
 #define MACHINE_HAS_TLB_LC     (0)
+#define MACHINE_HAS_VX         (0)
 #else /* CONFIG_64BIT */
 #define MACHINE_HAS_IEEE       (1)
 #define MACHINE_HAS_CSP                (1)
@@ -91,8 +91,8 @@ extern void detect_memory_memblock(void);
 #define MACHINE_HAS_LPP                (S390_lowcore.machine_flags & MACHINE_FLAG_LPP)
 #define MACHINE_HAS_TOPOLOGY   (S390_lowcore.machine_flags & MACHINE_FLAG_TOPOLOGY)
 #define MACHINE_HAS_TE         (S390_lowcore.machine_flags & MACHINE_FLAG_TE)
-#define MACHINE_HAS_RRBM       (S390_lowcore.machine_flags & MACHINE_FLAG_RRBM)
 #define MACHINE_HAS_TLB_LC     (S390_lowcore.machine_flags & MACHINE_FLAG_TLB_LC)
+#define MACHINE_HAS_VX         (S390_lowcore.machine_flags & MACHINE_FLAG_VX)
 #endif /* CONFIG_64BIT */
 
 /*
index bf9c823d4020ec2549aecba28996a08d9d69fdc4..49576115dbb76da7659bdcceffca7f1452e37fdf 100644 (file)
@@ -15,6 +15,7 @@
 #define SIGP_SET_ARCHITECTURE       18
 #define SIGP_COND_EMERGENCY_SIGNAL   19
 #define SIGP_SENSE_RUNNING          21
+#define SIGP_STORE_ADDITIONAL_STATUS 23
 
 /* SIGP condition codes */
 #define SIGP_CC_ORDER_CODE_ACCEPTED 0
 
 #ifndef __ASSEMBLY__
 
-static inline int __pcpu_sigp(u16 addr, u8 order, u32 parm, u32 *status)
+static inline int __pcpu_sigp(u16 addr, u8 order, unsigned long parm,
+                             u32 *status)
 {
-       register unsigned int reg1 asm ("1") = parm;
+       register unsigned long reg1 asm ("1") = parm;
        int cc;
 
        asm volatile(
index 4f1307962a95a307d6dff37acf897abba8f7595d..762d4f88af5ae3453402e99fd216bd612e2d4377 100644 (file)
@@ -29,7 +29,6 @@ extern int smp_find_processor_id(u16 address);
 extern int smp_store_status(int cpu);
 extern int smp_vcpu_scheduled(int cpu);
 extern void smp_yield_cpu(int cpu);
-extern void smp_yield(void);
 extern void smp_cpu_set_polarization(int cpu, int val);
 extern int smp_cpu_get_polarization(int cpu);
 extern void smp_fill_possible_mask(void);
@@ -50,7 +49,6 @@ static inline int smp_find_processor_id(u16 address) { return 0; }
 static inline int smp_store_status(int cpu) { return 0; }
 static inline int smp_vcpu_scheduled(int cpu) { return 1; }
 static inline void smp_yield_cpu(int cpu) { }
-static inline void smp_yield(void) { }
 static inline void smp_fill_possible_mask(void) { }
 
 #endif /* CONFIG_SMP */
index 96879f7ad6daaebd896745a1edf08cd134e8546c..d6bdf906caa533231660113144c74861ef031e6c 100644 (file)
@@ -37,11 +37,17 @@ _raw_compare_and_swap(unsigned int *lock, unsigned int old, unsigned int new)
  * (the type definitions are in asm/spinlock_types.h)
  */
 
+void arch_lock_relax(unsigned int cpu);
+
 void arch_spin_lock_wait(arch_spinlock_t *);
 int arch_spin_trylock_retry(arch_spinlock_t *);
-void arch_spin_relax(arch_spinlock_t *);
 void arch_spin_lock_wait_flags(arch_spinlock_t *, unsigned long flags);
 
+static inline void arch_spin_relax(arch_spinlock_t *lock)
+{
+       arch_lock_relax(lock->lock);
+}
+
 static inline u32 arch_spin_lockval(int cpu)
 {
        return ~cpu;
@@ -64,11 +70,6 @@ static inline int arch_spin_trylock_once(arch_spinlock_t *lp)
                      _raw_compare_and_swap(&lp->lock, 0, SPINLOCK_LOCKVAL));
 }
 
-static inline int arch_spin_tryrelease_once(arch_spinlock_t *lp)
-{
-       return _raw_compare_and_swap(&lp->lock, SPINLOCK_LOCKVAL, 0);
-}
-
 static inline void arch_spin_lock(arch_spinlock_t *lp)
 {
        if (!arch_spin_trylock_once(lp))
@@ -91,7 +92,13 @@ static inline int arch_spin_trylock(arch_spinlock_t *lp)
 
 static inline void arch_spin_unlock(arch_spinlock_t *lp)
 {
-       arch_spin_tryrelease_once(lp);
+       typecheck(unsigned int, lp->lock);
+       asm volatile(
+               __ASM_BARRIER
+               "st     %1,%0\n"
+               : "+Q" (lp->lock)
+               : "d" (0)
+               : "cc", "memory");
 }
 
 static inline void arch_spin_unlock_wait(arch_spinlock_t *lock)
@@ -123,13 +130,12 @@ static inline void arch_spin_unlock_wait(arch_spinlock_t *lock)
  */
 #define arch_write_can_lock(x) ((x)->lock == 0)
 
-extern void _raw_read_lock_wait(arch_rwlock_t *lp);
-extern void _raw_read_lock_wait_flags(arch_rwlock_t *lp, unsigned long flags);
 extern int _raw_read_trylock_retry(arch_rwlock_t *lp);
-extern void _raw_write_lock_wait(arch_rwlock_t *lp);
-extern void _raw_write_lock_wait_flags(arch_rwlock_t *lp, unsigned long flags);
 extern int _raw_write_trylock_retry(arch_rwlock_t *lp);
 
+#define arch_read_lock_flags(lock, flags) arch_read_lock(lock)
+#define arch_write_lock_flags(lock, flags) arch_write_lock(lock)
+
 static inline int arch_read_trylock_once(arch_rwlock_t *rw)
 {
        unsigned int old = ACCESS_ONCE(rw->lock);
@@ -144,16 +150,82 @@ static inline int arch_write_trylock_once(arch_rwlock_t *rw)
                      _raw_compare_and_swap(&rw->lock, 0, 0x80000000));
 }
 
+#ifdef CONFIG_HAVE_MARCH_Z196_FEATURES
+
+#define __RAW_OP_OR    "lao"
+#define __RAW_OP_AND   "lan"
+#define __RAW_OP_ADD   "laa"
+
+#define __RAW_LOCK(ptr, op_val, op_string)             \
+({                                                     \
+       unsigned int old_val;                           \
+                                                       \
+       typecheck(unsigned int *, ptr);                 \
+       asm volatile(                                   \
+               op_string "     %0,%2,%1\n"             \
+               "bcr    14,0\n"                         \
+               : "=d" (old_val), "+Q" (*ptr)           \
+               : "d" (op_val)                          \
+               : "cc", "memory");                      \
+       old_val;                                        \
+})
+
+#define __RAW_UNLOCK(ptr, op_val, op_string)           \
+({                                                     \
+       unsigned int old_val;                           \
+                                                       \
+       typecheck(unsigned int *, ptr);                 \
+       asm volatile(                                   \
+               "bcr    14,0\n"                         \
+               op_string "     %0,%2,%1\n"             \
+               : "=d" (old_val), "+Q" (*ptr)           \
+               : "d" (op_val)                          \
+               : "cc", "memory");                      \
+       old_val;                                        \
+})
+
+extern void _raw_read_lock_wait(arch_rwlock_t *lp);
+extern void _raw_write_lock_wait(arch_rwlock_t *lp, unsigned int prev);
+
 static inline void arch_read_lock(arch_rwlock_t *rw)
 {
-       if (!arch_read_trylock_once(rw))
+       unsigned int old;
+
+       old = __RAW_LOCK(&rw->lock, 1, __RAW_OP_ADD);
+       if ((int) old < 0)
                _raw_read_lock_wait(rw);
 }
 
-static inline void arch_read_lock_flags(arch_rwlock_t *rw, unsigned long flags)
+static inline void arch_read_unlock(arch_rwlock_t *rw)
+{
+       __RAW_UNLOCK(&rw->lock, -1, __RAW_OP_ADD);
+}
+
+static inline void arch_write_lock(arch_rwlock_t *rw)
+{
+       unsigned int old;
+
+       old = __RAW_LOCK(&rw->lock, 0x80000000, __RAW_OP_OR);
+       if (old != 0)
+               _raw_write_lock_wait(rw, old);
+       rw->owner = SPINLOCK_LOCKVAL;
+}
+
+static inline void arch_write_unlock(arch_rwlock_t *rw)
+{
+       rw->owner = 0;
+       __RAW_UNLOCK(&rw->lock, 0x7fffffff, __RAW_OP_AND);
+}
+
+#else /* CONFIG_HAVE_MARCH_Z196_FEATURES */
+
+extern void _raw_read_lock_wait(arch_rwlock_t *lp);
+extern void _raw_write_lock_wait(arch_rwlock_t *lp);
+
+static inline void arch_read_lock(arch_rwlock_t *rw)
 {
        if (!arch_read_trylock_once(rw))
-               _raw_read_lock_wait_flags(rw, flags);
+               _raw_read_lock_wait(rw);
 }
 
 static inline void arch_read_unlock(arch_rwlock_t *rw)
@@ -169,19 +241,24 @@ static inline void arch_write_lock(arch_rwlock_t *rw)
 {
        if (!arch_write_trylock_once(rw))
                _raw_write_lock_wait(rw);
-}
-
-static inline void arch_write_lock_flags(arch_rwlock_t *rw, unsigned long flags)
-{
-       if (!arch_write_trylock_once(rw))
-               _raw_write_lock_wait_flags(rw, flags);
+       rw->owner = SPINLOCK_LOCKVAL;
 }
 
 static inline void arch_write_unlock(arch_rwlock_t *rw)
 {
-       _raw_compare_and_swap(&rw->lock, 0x80000000, 0);
+       typecheck(unsigned int, rw->lock);
+
+       rw->owner = 0;
+       asm volatile(
+               __ASM_BARRIER
+               "st     %1,%0\n"
+               : "+Q" (rw->lock)
+               : "d" (0)
+               : "cc", "memory");
 }
 
+#endif /* CONFIG_HAVE_MARCH_Z196_FEATURES */
+
 static inline int arch_read_trylock(arch_rwlock_t *rw)
 {
        if (!arch_read_trylock_once(rw))
@@ -191,12 +268,20 @@ static inline int arch_read_trylock(arch_rwlock_t *rw)
 
 static inline int arch_write_trylock(arch_rwlock_t *rw)
 {
-       if (!arch_write_trylock_once(rw))
-               return _raw_write_trylock_retry(rw);
+       if (!arch_write_trylock_once(rw) && !_raw_write_trylock_retry(rw))
+               return 0;
+       rw->owner = SPINLOCK_LOCKVAL;
        return 1;
 }
 
-#define arch_read_relax(lock)  cpu_relax()
-#define arch_write_relax(lock) cpu_relax()
+static inline void arch_read_relax(arch_rwlock_t *rw)
+{
+       arch_lock_relax(rw->owner);
+}
+
+static inline void arch_write_relax(arch_rwlock_t *rw)
+{
+       arch_lock_relax(rw->owner);
+}
 
 #endif /* __ASM_SPINLOCK_H */
index b2cd6ff7c2c5bcdad941bb91297fa64fb8908616..d84b6939237c1cc2c4f671edabbe9d062acd7d27 100644 (file)
@@ -13,6 +13,7 @@ typedef struct {
 
 typedef struct {
        unsigned int lock;
+       unsigned int owner;
 } arch_rwlock_t;
 
 #define __ARCH_RW_LOCK_UNLOCKED                { 0 }
index 18ea9e3f8142954926b8fea3afe79ce90193a4b3..2542a7e4c8b4577fa8c1081a0d372ba70e618d38 100644 (file)
@@ -103,6 +103,61 @@ static inline void restore_fp_regs(freg_t *fprs)
        asm volatile("ld 15,%0" : : "Q" (fprs[15]));
 }
 
+static inline void save_vx_regs(__vector128 *vxrs)
+{
+       typedef struct { __vector128 _[__NUM_VXRS]; } addrtype;
+
+       asm volatile(
+               "       la      1,%0\n"
+               "       .word   0xe70f,0x1000,0x003e\n" /* vstm 0,15,0(1) */
+               "       .word   0xe70f,0x1100,0x0c3e\n" /* vstm 16,31,256(1) */
+               : "=Q" (*(addrtype *) vxrs) : : "1");
+}
+
+static inline void save_vx_regs_safe(__vector128 *vxrs)
+{
+       unsigned long cr0, flags;
+
+       flags = arch_local_irq_save();
+       __ctl_store(cr0, 0, 0);
+       __ctl_set_bit(0, 17);
+       __ctl_set_bit(0, 18);
+       save_vx_regs(vxrs);
+       __ctl_load(cr0, 0, 0);
+       arch_local_irq_restore(flags);
+}
+
+static inline void restore_vx_regs(__vector128 *vxrs)
+{
+       typedef struct { __vector128 _[__NUM_VXRS]; } addrtype;
+
+       asm volatile(
+               "       la      1,%0\n"
+               "       .word   0xe70f,0x1000,0x0036\n" /* vlm 0,15,0(1) */
+               "       .word   0xe70f,0x1100,0x0c36\n" /* vlm 16,31,256(1) */
+               : : "Q" (*(addrtype *) vxrs) : "1");
+}
+
+static inline void save_fp_vx_regs(struct task_struct *task)
+{
+#ifdef CONFIG_64BIT
+       if (task->thread.vxrs)
+               save_vx_regs(task->thread.vxrs);
+       else
+#endif
+       save_fp_regs(task->thread.fp_regs.fprs);
+}
+
+static inline void restore_fp_vx_regs(struct task_struct *task)
+{
+#ifdef CONFIG_64BIT
+       if (task->thread.vxrs)
+               restore_vx_regs(task->thread.vxrs);
+       else
+#endif
+       restore_fp_regs(task->thread.fp_regs.fprs);
+}
+
 static inline void save_access_regs(unsigned int *acrs)
 {
        typedef struct { int _[NUM_ACRS]; } acrstype;
@@ -120,16 +175,16 @@ static inline void restore_access_regs(unsigned int *acrs)
 #define switch_to(prev,next,last) do {                                 \
        if (prev->mm) {                                                 \
                save_fp_ctl(&prev->thread.fp_regs.fpc);                 \
-               save_fp_regs(prev->thread.fp_regs.fprs);                \
+               save_fp_vx_regs(prev);                                  \
                save_access_regs(&prev->thread.acrs[0]);                \
                save_ri_cb(prev->thread.ri_cb);                         \
        }                                                               \
        if (next->mm) {                                                 \
+               update_cr_regs(next);                                   \
                restore_fp_ctl(&next->thread.fp_regs.fpc);              \
-               restore_fp_regs(next->thread.fp_regs.fprs);             \
+               restore_fp_vx_regs(next);                               \
                restore_access_regs(&next->thread.acrs[0]);             \
                restore_ri_cb(next->thread.ri_cb, prev->thread.ri_cb);  \
-               update_cr_regs(next);                                   \
        }                                                               \
        prev = __switch_to(prev,next);                                  \
 } while (0)
index b833e9c0bfbf2feb6e4f9dc2559e22385115e9b2..4d62fd5b56e5d13a264a1f3b691f90d282c355ac 100644 (file)
@@ -84,11 +84,13 @@ static inline struct thread_info *current_thread_info(void)
 #define TIF_SYSCALL_AUDIT      4       /* syscall auditing active */
 #define TIF_SECCOMP            5       /* secure computing */
 #define TIF_SYSCALL_TRACEPOINT 6       /* syscall tracepoint instrumentation */
+#define TIF_UPROBE             7       /* breakpointed or single-stepping */
 #define TIF_31BIT              16      /* 32bit process */
 #define TIF_MEMDIE             17      /* is terminating due to OOM killer */
 #define TIF_RESTORE_SIGMASK    18      /* restore signal mask in do_signal() */
 #define TIF_SINGLE_STEP                19      /* This task is single stepped */
 #define TIF_BLOCK_STEP         20      /* This task is block stepped */
+#define TIF_UPROBE_SINGLESTEP  21      /* This task is uprobe single stepped */
 
 #define _TIF_NOTIFY_RESUME     (1<<TIF_NOTIFY_RESUME)
 #define _TIF_SIGPENDING                (1<<TIF_SIGPENDING)
@@ -97,6 +99,7 @@ static inline struct thread_info *current_thread_info(void)
 #define _TIF_SYSCALL_AUDIT     (1<<TIF_SYSCALL_AUDIT)
 #define _TIF_SECCOMP           (1<<TIF_SECCOMP)
 #define _TIF_SYSCALL_TRACEPOINT        (1<<TIF_SYSCALL_TRACEPOINT)
+#define _TIF_UPROBE            (1<<TIF_UPROBE)
 #define _TIF_31BIT             (1<<TIF_31BIT)
 #define _TIF_SINGLE_STEP       (1<<TIF_SINGLE_STEP)
 
diff --git a/arch/s390/include/asm/uprobes.h b/arch/s390/include/asm/uprobes.h
new file mode 100644 (file)
index 0000000..1411dff
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ *    User-space Probes (UProbes) for s390
+ *
+ *    Copyright IBM Corp. 2014
+ *    Author(s): Jan Willeke,
+ */
+
+#ifndef _ASM_UPROBES_H
+#define _ASM_UPROBES_H
+
+#include <linux/notifier.h>
+
+typedef u16 uprobe_opcode_t;
+
+#define UPROBE_XOL_SLOT_BYTES  256 /* cache aligned */
+
+#define UPROBE_SWBP_INSN       0x0002
+#define UPROBE_SWBP_INSN_SIZE  2
+
+struct arch_uprobe {
+       union{
+               uprobe_opcode_t insn[3];
+               uprobe_opcode_t ixol[3];
+       };
+       unsigned int saved_per : 1;
+       unsigned int saved_int_code;
+};
+
+struct arch_uprobe_task {
+};
+
+int arch_uprobe_analyze_insn(struct arch_uprobe *aup, struct mm_struct *mm,
+                            unsigned long addr);
+int arch_uprobe_pre_xol(struct arch_uprobe *aup, struct pt_regs *regs);
+int arch_uprobe_post_xol(struct arch_uprobe *aup, struct pt_regs *regs);
+bool arch_uprobe_xol_was_trapped(struct task_struct *tsk);
+int arch_uprobe_exception_notify(struct notifier_block *self, unsigned long val,
+                                void *data);
+void arch_uprobe_abort_xol(struct arch_uprobe *ap, struct pt_regs *regs);
+unsigned long arch_uretprobe_hijack_return_addr(unsigned long trampoline,
+                                               struct pt_regs *regs);
+#endif /* _ASM_UPROBES_H */
index bc9746a7d47c53edf219c4b4b1f500bc0728a284..a62526d09201667f5d485192d9c6d081b7559060 100644 (file)
@@ -22,13 +22,17 @@ struct vdso_data {
        __u64 xtime_tod_stamp;          /* TOD clock for xtime          0x08 */
        __u64 xtime_clock_sec;          /* Kernel time                  0x10 */
        __u64 xtime_clock_nsec;         /*                              0x18 */
-       __u64 wtom_clock_sec;           /* Wall to monotonic clock      0x20 */
-       __u64 wtom_clock_nsec;          /*                              0x28 */
-       __u32 tz_minuteswest;           /* Minutes west of Greenwich    0x30 */
-       __u32 tz_dsttime;               /* Type of dst correction       0x34 */
-       __u32 ectg_available;           /* ECTG instruction present     0x38 */
-       __u32 tk_mult;                  /* Mult. used for xtime_nsec    0x3c */
-       __u32 tk_shift;                 /* Shift used for xtime_nsec    0x40 */
+       __u64 xtime_coarse_sec;         /* Coarse kernel time           0x20 */
+       __u64 xtime_coarse_nsec;        /*                              0x28 */
+       __u64 wtom_clock_sec;           /* Wall to monotonic clock      0x30 */
+       __u64 wtom_clock_nsec;          /*                              0x38 */
+       __u64 wtom_coarse_sec;          /* Coarse wall to monotonic     0x40 */
+       __u64 wtom_coarse_nsec;         /*                              0x48 */
+       __u32 tz_minuteswest;           /* Minutes west of Greenwich    0x50 */
+       __u32 tz_dsttime;               /* Type of dst correction       0x54 */
+       __u32 ectg_available;           /* ECTG instruction present     0x58 */
+       __u32 tk_mult;                  /* Mult. used for xtime_nsec    0x5c */
+       __u32 tk_shift;                 /* Shift used for xtime_nsec    0x60 */
 };
 
 struct vdso_per_cpu_data {
index bfe25d513ad26462f22fce6e66dd3f688e25c352..10a179af62d8c3f512a253752494b61c1801310f 100644 (file)
@@ -28,6 +28,4 @@ extern int del_virt_timer(struct vtimer_list *timer);
 extern void init_cpu_vtimer(void);
 extern void vtime_init(void);
 
-extern void vtime_stop_cpu(void);
-
 #endif /* _ASM_S390_TIMER_H */
index b30de9c01bbedad00c5e15ff52ffa8d19b06c824..5f0b8d7ddb0bce1ad36dd45f70ab757e5a33e99f 100644 (file)
@@ -7,10 +7,14 @@
 #define _ASM_S390_SIGCONTEXT_H
 
 #include <linux/compiler.h>
+#include <linux/types.h>
 
-#define __NUM_GPRS 16
-#define __NUM_FPRS 16
-#define __NUM_ACRS 16
+#define __NUM_GPRS             16
+#define __NUM_FPRS             16
+#define __NUM_ACRS             16
+#define __NUM_VXRS             32
+#define __NUM_VXRS_LOW         16
+#define __NUM_VXRS_HIGH                16
 
 #ifndef __s390x__
 
@@ -59,6 +63,16 @@ typedef struct
        _s390_fp_regs     fpregs;
 } _sigregs;
 
+typedef struct
+{
+#ifndef __s390x__
+       unsigned long gprs_high[__NUM_GPRS];
+#endif
+       unsigned long long vxrs_low[__NUM_VXRS_LOW];
+       __vector128 vxrs_high[__NUM_VXRS_HIGH];
+       unsigned char __reserved[128];
+} _sigregs_ext;
+
 struct sigcontext
 {
        unsigned long   oldmask[_SIGCONTEXT_NSIG_WORDS];
index 038f2b9178a4a2f159d9e289327a074e3ad0704c..3c3951e3415be0efd38b348bda8bea922b17d10a 100644 (file)
 typedef unsigned long addr_t; 
 typedef __signed__ long saddr_t;
 
+typedef struct {
+       __u32 u[4];
+} __vector128;
+
 #endif /* __ASSEMBLY__ */
 
 #endif /* _UAPI_S390_TYPES_H */
index 3e077b2a470579af0cb0827c5ba3050fa373450c..64a69aa5dde041cc733265b90aca197044d1fedb 100644 (file)
@@ -7,10 +7,15 @@
 #ifndef _ASM_S390_UCONTEXT_H
 #define _ASM_S390_UCONTEXT_H
 
-#define UC_EXTENDED    0x00000001
-
-#ifndef __s390x__
+#define UC_GPRS_HIGH   1       /* uc_mcontext_ext has valid high gprs */
+#define UC_VXRS                2       /* uc_mcontext_ext has valid vector regs */
 
+/*
+ * The struct ucontext_extended describes how the registers are stored
+ * on a rt signal frame. Please note that the structure is not fixed,
+ * if new CPU registers are added to the user state the size of the
+ * struct ucontext_extended will increase.
+ */
 struct ucontext_extended {
        unsigned long     uc_flags;
        struct ucontext  *uc_link;
@@ -19,11 +24,9 @@ struct ucontext_extended {
        sigset_t          uc_sigmask;
        /* Allow for uc_sigmask growth.  Glibc uses a 1024-bit sigset_t.  */
        unsigned char     __unused[128 - sizeof(sigset_t)];
-       unsigned long     uc_gprs_high[16];
+       _sigregs_ext      uc_mcontext_ext;
 };
 
-#endif
-
 struct ucontext {
        unsigned long     uc_flags;
        struct ucontext  *uc_link;
index a95c4ca99617e43360fb3b867ac3aefb92b374d6..204c43a4c245dd1835915adbbae39da494c2d947 100644 (file)
@@ -28,7 +28,7 @@ CFLAGS_ptrace.o               += -DUTS_MACHINE='"$(UTS_MACHINE)"'
 
 CFLAGS_sysinfo.o += -Iinclude/math-emu -Iarch/s390/math-emu -w
 
-obj-y  := traps.o time.o process.o base.o early.o setup.o vtime.o
+obj-y  := traps.o time.o process.o base.o early.o setup.o idle.o vtime.o
 obj-y  += processor.o sys_s390.o ptrace.o signal.o cpcmd.o ebcdic.o nmi.o
 obj-y  += debug.o irq.o ipl.o dis.o diag.o sclp.o vdso.o
 obj-y  += sysinfo.o jump_label.o lgr.o os_info.o machine_kexec.o pgm_check.o
@@ -52,11 +52,9 @@ obj-$(CONFIG_COMPAT)         += compat_wrapper.o $(compat-obj-y)
 
 obj-$(CONFIG_STACKTRACE)       += stacktrace.o
 obj-$(CONFIG_KPROBES)          += kprobes.o
-obj-$(CONFIG_FUNCTION_TRACER)  += $(if $(CONFIG_64BIT),mcount64.o,mcount.o)
-obj-$(CONFIG_DYNAMIC_FTRACE)   += ftrace.o
-obj-$(CONFIG_FUNCTION_GRAPH_TRACER) += ftrace.o
-obj-$(CONFIG_FTRACE_SYSCALLS)  += ftrace.o
+obj-$(CONFIG_FUNCTION_TRACER)  += mcount.o ftrace.o
 obj-$(CONFIG_CRASH_DUMP)       += crash_dump.o
+obj-$(CONFIG_UPROBES)          += uprobes.o
 
 ifdef CONFIG_64BIT
 obj-$(CONFIG_PERF_EVENTS)      += perf_event.o perf_cpum_cf.o perf_cpum_sf.o \
index afe1715a4eb765cb06d1ab3277bce0b4ce8fc3c2..ef279a1368012e67fbbbbb3092783b461e1b98c0 100644 (file)
@@ -9,7 +9,7 @@
 #include <linux/kbuild.h>
 #include <linux/kvm_host.h>
 #include <linux/sched.h>
-#include <asm/cputime.h>
+#include <asm/idle.h>
 #include <asm/vdso.h>
 #include <asm/pgtable.h>
 
@@ -62,8 +62,12 @@ int main(void)
        DEFINE(__VDSO_XTIME_STAMP, offsetof(struct vdso_data, xtime_tod_stamp));
        DEFINE(__VDSO_XTIME_SEC, offsetof(struct vdso_data, xtime_clock_sec));
        DEFINE(__VDSO_XTIME_NSEC, offsetof(struct vdso_data, xtime_clock_nsec));
+       DEFINE(__VDSO_XTIME_CRS_SEC, offsetof(struct vdso_data, xtime_coarse_sec));
+       DEFINE(__VDSO_XTIME_CRS_NSEC, offsetof(struct vdso_data, xtime_coarse_nsec));
        DEFINE(__VDSO_WTOM_SEC, offsetof(struct vdso_data, wtom_clock_sec));
        DEFINE(__VDSO_WTOM_NSEC, offsetof(struct vdso_data, wtom_clock_nsec));
+       DEFINE(__VDSO_WTOM_CRS_SEC, offsetof(struct vdso_data, wtom_coarse_sec));
+       DEFINE(__VDSO_WTOM_CRS_NSEC, offsetof(struct vdso_data, wtom_coarse_nsec));
        DEFINE(__VDSO_TIMEZONE, offsetof(struct vdso_data, tz_minuteswest));
        DEFINE(__VDSO_ECTG_OK, offsetof(struct vdso_data, ectg_available));
        DEFINE(__VDSO_TK_MULT, offsetof(struct vdso_data, tk_mult));
@@ -73,8 +77,11 @@ int main(void)
        /* constants used by the vdso */
        DEFINE(__CLOCK_REALTIME, CLOCK_REALTIME);
        DEFINE(__CLOCK_MONOTONIC, CLOCK_MONOTONIC);
+       DEFINE(__CLOCK_REALTIME_COARSE, CLOCK_REALTIME_COARSE);
+       DEFINE(__CLOCK_MONOTONIC_COARSE, CLOCK_MONOTONIC_COARSE);
        DEFINE(__CLOCK_THREAD_CPUTIME_ID, CLOCK_THREAD_CPUTIME_ID);
        DEFINE(__CLOCK_REALTIME_RES, MONOTONIC_RES_NSEC);
+       DEFINE(__CLOCK_COARSE_RES, LOW_RES_NSEC);
        BLANK();
        /* idle data offsets */
        DEFINE(__CLOCK_IDLE_ENTER, offsetof(struct s390_idle_data, clock_idle_enter));
index 70d4b7c4beaa92d1b85ec7b38373830b38aab3ee..a0a886c0497759e0338acd45157f267d57a724fb 100644 (file)
@@ -50,6 +50,14 @@ typedef struct
        _s390_fp_regs32     fpregs;
 } _sigregs32;
 
+typedef struct
+{
+       __u32 gprs_high[__NUM_GPRS];
+       __u64 vxrs_low[__NUM_VXRS_LOW];
+       __vector128 vxrs_high[__NUM_VXRS_HIGH];
+       __u8 __reserved[128];
+} _sigregs_ext32;
+
 #define _SIGCONTEXT_NSIG32     64
 #define _SIGCONTEXT_NSIG_BPW32 32
 #define __SIGNAL_FRAMESIZE32   96
@@ -72,6 +80,7 @@ struct ucontext32 {
        compat_sigset_t         uc_sigmask;
        /* Allow for uc_sigmask growth.  Glibc uses a 1024-bit sigset_t.  */
        unsigned char           __unused[128 - sizeof(compat_sigset_t)];
+       _sigregs_ext32          uc_mcontext_ext;
 };
 
 struct stat64_emu31;
index 598b0b42668bfc81eb6e2c5293a337e838717bbc..009f5eb111254028125104ccbf25566d2d72c5fa 100644 (file)
@@ -36,17 +36,16 @@ typedef struct
        struct sigcontext32 sc;
        _sigregs32 sregs;
        int signo;
-       __u32 gprs_high[NUM_GPRS];
-       __u8 retcode[S390_SYSCALL_SIZE];
+       _sigregs_ext32 sregs_ext;
+       __u16 svc_insn;         /* Offset of svc_insn is NOT fixed! */
 } sigframe32;
 
 typedef struct 
 {
        __u8 callee_used_stack[__SIGNAL_FRAMESIZE32];
-       __u8 retcode[S390_SYSCALL_SIZE];
+       __u16 svc_insn;
        compat_siginfo_t info;
        struct ucontext32 uc;
-       __u32 gprs_high[NUM_GPRS];
 } rt_sigframe32;
 
 int copy_siginfo_to_user32(compat_siginfo_t __user *to, const siginfo_t *from)
@@ -151,6 +150,38 @@ int copy_siginfo_from_user32(siginfo_t *to, compat_siginfo_t __user *from)
        return err ? -EFAULT : 0;
 }
 
+/* Store registers needed to create the signal frame */
+static void store_sigregs(void)
+{
+       int i;
+
+       save_access_regs(current->thread.acrs);
+       save_fp_ctl(&current->thread.fp_regs.fpc);
+       if (current->thread.vxrs) {
+               save_vx_regs(current->thread.vxrs);
+               for (i = 0; i < __NUM_FPRS; i++)
+                       current->thread.fp_regs.fprs[i] =
+                               *(freg_t *)(current->thread.vxrs + i);
+       } else
+               save_fp_regs(current->thread.fp_regs.fprs);
+}
+
+/* Load registers after signal return */
+static void load_sigregs(void)
+{
+       int i;
+
+       restore_access_regs(current->thread.acrs);
+       /* restore_fp_ctl is done in restore_sigregs */
+       if (current->thread.vxrs) {
+               for (i = 0; i < __NUM_FPRS; i++)
+                       *(freg_t *)(current->thread.vxrs + i) =
+                               current->thread.fp_regs.fprs[i];
+               restore_vx_regs(current->thread.vxrs);
+       } else
+               restore_fp_regs(current->thread.fp_regs.fprs);
+}
+
 static int save_sigregs32(struct pt_regs *regs, _sigregs32 __user *sregs)
 {
        _sigregs32 user_sregs;
@@ -163,11 +194,8 @@ static int save_sigregs32(struct pt_regs *regs, _sigregs32 __user *sregs)
                (__u32)(regs->psw.mask & PSW_MASK_BA);
        for (i = 0; i < NUM_GPRS; i++)
                user_sregs.regs.gprs[i] = (__u32) regs->gprs[i];
-       save_access_regs(current->thread.acrs);
        memcpy(&user_sregs.regs.acrs, current->thread.acrs,
               sizeof(user_sregs.regs.acrs));
-       save_fp_ctl(&current->thread.fp_regs.fpc);
-       save_fp_regs(current->thread.fp_regs.fprs);
        memcpy(&user_sregs.fpregs, &current->thread.fp_regs,
               sizeof(user_sregs.fpregs));
        if (__copy_to_user(sregs, &user_sregs, sizeof(_sigregs32)))
@@ -207,37 +235,67 @@ static int restore_sigregs32(struct pt_regs *regs,_sigregs32 __user *sregs)
                regs->gprs[i] = (__u64) user_sregs.regs.gprs[i];
        memcpy(&current->thread.acrs, &user_sregs.regs.acrs,
               sizeof(current->thread.acrs));
-       restore_access_regs(current->thread.acrs);
 
        memcpy(&current->thread.fp_regs, &user_sregs.fpregs,
               sizeof(current->thread.fp_regs));
 
-       restore_fp_regs(current->thread.fp_regs.fprs);
        clear_pt_regs_flag(regs, PIF_SYSCALL); /* No longer in a system call */
        return 0;
 }
 
-static int save_sigregs_gprs_high(struct pt_regs *regs, __u32 __user *uregs)
+static int save_sigregs_ext32(struct pt_regs *regs,
+                             _sigregs_ext32 __user *sregs_ext)
 {
        __u32 gprs_high[NUM_GPRS];
+       __u64 vxrs[__NUM_VXRS_LOW];
        int i;
 
+       /* Save high gprs to signal stack */
        for (i = 0; i < NUM_GPRS; i++)
                gprs_high[i] = regs->gprs[i] >> 32;
-       if (__copy_to_user(uregs, &gprs_high, sizeof(gprs_high)))
+       if (__copy_to_user(&sregs_ext->gprs_high, &gprs_high,
+                          sizeof(sregs_ext->gprs_high)))
                return -EFAULT;
+
+       /* Save vector registers to signal stack */
+       if (current->thread.vxrs) {
+               for (i = 0; i < __NUM_VXRS_LOW; i++)
+                       vxrs[i] = *((__u64 *)(current->thread.vxrs + i) + 1);
+               if (__copy_to_user(&sregs_ext->vxrs_low, vxrs,
+                                  sizeof(sregs_ext->vxrs_low)) ||
+                   __copy_to_user(&sregs_ext->vxrs_high,
+                                  current->thread.vxrs + __NUM_VXRS_LOW,
+                                  sizeof(sregs_ext->vxrs_high)))
+                       return -EFAULT;
+       }
        return 0;
 }
 
-static int restore_sigregs_gprs_high(struct pt_regs *regs, __u32 __user *uregs)
+static int restore_sigregs_ext32(struct pt_regs *regs,
+                                _sigregs_ext32 __user *sregs_ext)
 {
        __u32 gprs_high[NUM_GPRS];
+       __u64 vxrs[__NUM_VXRS_LOW];
        int i;
 
-       if (__copy_from_user(&gprs_high, uregs, sizeof(gprs_high)))
+       /* Restore high gprs from signal stack */
+       if (__copy_from_user(&gprs_high, &sregs_ext->gprs_high,
+                            sizeof(&sregs_ext->gprs_high)))
                return -EFAULT;
        for (i = 0; i < NUM_GPRS; i++)
                *(__u32 *)&regs->gprs[i] = gprs_high[i];
+
+       /* Restore vector registers from signal stack */
+       if (current->thread.vxrs) {
+               if (__copy_from_user(vxrs, &sregs_ext->vxrs_low,
+                                    sizeof(sregs_ext->vxrs_low)) ||
+                   __copy_from_user(current->thread.vxrs + __NUM_VXRS_LOW,
+                                    &sregs_ext->vxrs_high,
+                                    sizeof(sregs_ext->vxrs_high)))
+                       return -EFAULT;
+               for (i = 0; i < __NUM_VXRS_LOW; i++)
+                       *((__u64 *)(current->thread.vxrs + i) + 1) = vxrs[i];
+       }
        return 0;
 }
 
@@ -252,8 +310,9 @@ COMPAT_SYSCALL_DEFINE0(sigreturn)
        set_current_blocked(&set);
        if (restore_sigregs32(regs, &frame->sregs))
                goto badframe;
-       if (restore_sigregs_gprs_high(regs, frame->gprs_high))
+       if (restore_sigregs_ext32(regs, &frame->sregs_ext))
                goto badframe;
+       load_sigregs();
        return regs->gprs[2];
 badframe:
        force_sig(SIGSEGV, current);
@@ -269,12 +328,13 @@ COMPAT_SYSCALL_DEFINE0(rt_sigreturn)
        if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set)))
                goto badframe;
        set_current_blocked(&set);
+       if (compat_restore_altstack(&frame->uc.uc_stack))
+               goto badframe;
        if (restore_sigregs32(regs, &frame->uc.uc_mcontext))
                goto badframe;
-       if (restore_sigregs_gprs_high(regs, frame->gprs_high))
+       if (restore_sigregs_ext32(regs, &frame->uc.uc_mcontext_ext))
                goto badframe;
-       if (compat_restore_altstack(&frame->uc.uc_stack))
-               goto badframe; 
+       load_sigregs();
        return regs->gprs[2];
 badframe:
        force_sig(SIGSEGV, current);
@@ -324,37 +384,64 @@ static int setup_frame32(struct ksignal *ksig, sigset_t *set,
                         struct pt_regs *regs)
 {
        int sig = ksig->sig;
-       sigframe32 __user *frame = get_sigframe(&ksig->ka, regs, sizeof(sigframe32));
-
+       sigframe32 __user *frame;
+       struct sigcontext32 sc;
+       unsigned long restorer;
+       size_t frame_size;
+
+       /*
+        * gprs_high are always present for 31-bit compat tasks.
+        * The space for vector registers is only allocated if
+        * the machine supports it
+        */
+       frame_size = sizeof(*frame) - sizeof(frame->sregs_ext.__reserved);
+       if (!MACHINE_HAS_VX)
+               frame_size -= sizeof(frame->sregs_ext.vxrs_low) +
+                             sizeof(frame->sregs_ext.vxrs_high);
+       frame = get_sigframe(&ksig->ka, regs, frame_size);
        if (frame == (void __user *) -1UL)
                return -EFAULT;
 
-       if (__copy_to_user(&frame->sc.oldmask, &set->sig, _SIGMASK_COPY_SIZE32))
+       /* Set up backchain. */
+       if (__put_user(regs->gprs[15], (unsigned int __user *) frame))
+               return -EFAULT;
+
+       /* Create struct sigcontext32 on the signal stack */
+       memcpy(&sc.oldmask, &set->sig, _SIGMASK_COPY_SIZE32);
+       sc.sregs = (__u32)(unsigned long __force) &frame->sregs;
+       if (__copy_to_user(&frame->sc, &sc, sizeof(frame->sc)))
                return -EFAULT;
 
+       /* Store registers needed to create the signal frame */
+       store_sigregs();
+
+       /* Create _sigregs32 on the signal stack */
        if (save_sigregs32(regs, &frame->sregs))
                return -EFAULT;
-       if (save_sigregs_gprs_high(regs, frame->gprs_high))
+
+       /* Place signal number on stack to allow backtrace from handler.  */
+       if (__put_user(regs->gprs[2], (int __force __user *) &frame->signo))
                return -EFAULT;
-       if (__put_user((unsigned long) &frame->sregs, &frame->sc.sregs))
+
+       /* Create _sigregs_ext32 on the signal stack */
+       if (save_sigregs_ext32(regs, &frame->sregs_ext))
                return -EFAULT;
 
        /* Set up to return from userspace.  If provided, use a stub
           already in userspace.  */
        if (ksig->ka.sa.sa_flags & SA_RESTORER) {
-               regs->gprs[14] = (__u64 __force) ksig->ka.sa.sa_restorer | PSW32_ADDR_AMODE;
+               restorer = (unsigned long __force)
+                       ksig->ka.sa.sa_restorer | PSW32_ADDR_AMODE;
        } else {
-               regs->gprs[14] = (__u64 __force) frame->retcode | PSW32_ADDR_AMODE;
-               if (__put_user(S390_SYSCALL_OPCODE | __NR_sigreturn,
-                              (u16 __force __user *)(frame->retcode)))
+               /* Signal frames without vectors registers are short ! */
+               __u16 __user *svc = (void *) frame + frame_size - 2;
+               if (__put_user(S390_SYSCALL_OPCODE | __NR_sigreturn, svc))
                        return -EFAULT;
+               restorer = (unsigned long __force) svc | PSW32_ADDR_AMODE;
         }
 
-       /* Set up backchain. */
-       if (__put_user(regs->gprs[15], (unsigned int __user *) frame))
-               return -EFAULT;
-
        /* Set up registers for signal handler */
+       regs->gprs[14] = restorer;
        regs->gprs[15] = (__force __u64) frame;
        /* Force 31 bit amode and default user address space control. */
        regs->psw.mask = PSW_MASK_BA |
@@ -375,50 +462,69 @@ static int setup_frame32(struct ksignal *ksig, sigset_t *set,
                regs->gprs[6] = task_thread_info(current)->last_break;
        }
 
-       /* Place signal number on stack to allow backtrace from handler.  */
-       if (__put_user(regs->gprs[2], (int __force __user *) &frame->signo))
-               return -EFAULT;
        return 0;
 }
 
 static int setup_rt_frame32(struct ksignal *ksig, sigset_t *set,
                            struct pt_regs *regs)
 {
-       int err = 0;
-       rt_sigframe32 __user *frame = get_sigframe(&ksig->ka, regs, sizeof(rt_sigframe32));
-
+       rt_sigframe32 __user *frame;
+       unsigned long restorer;
+       size_t frame_size;
+       u32 uc_flags;
+
+       frame_size = sizeof(*frame) -
+                    sizeof(frame->uc.uc_mcontext_ext.__reserved);
+       /*
+        * gprs_high are always present for 31-bit compat tasks.
+        * The space for vector registers is only allocated if
+        * the machine supports it
+        */
+       uc_flags = UC_GPRS_HIGH;
+       if (MACHINE_HAS_VX) {
+               if (current->thread.vxrs)
+                       uc_flags |= UC_VXRS;
+       } else
+               frame_size -= sizeof(frame->uc.uc_mcontext_ext.vxrs_low) +
+                             sizeof(frame->uc.uc_mcontext_ext.vxrs_high);
+       frame = get_sigframe(&ksig->ka, regs, frame_size);
        if (frame == (void __user *) -1UL)
                return -EFAULT;
 
-       if (copy_siginfo_to_user32(&frame->info, &ksig->info))
-               return -EFAULT;
-
-       /* Create the ucontext.  */
-       err |= __put_user(UC_EXTENDED, &frame->uc.uc_flags);
-       err |= __put_user(0, &frame->uc.uc_link);
-       err |= __compat_save_altstack(&frame->uc.uc_stack, regs->gprs[15]);
-       err |= save_sigregs32(regs, &frame->uc.uc_mcontext);
-       err |= save_sigregs_gprs_high(regs, frame->gprs_high);
-       err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
-       if (err)
+       /* Set up backchain. */
+       if (__put_user(regs->gprs[15], (unsigned int __force __user *) frame))
                return -EFAULT;
 
        /* Set up to return from userspace.  If provided, use a stub
           already in userspace.  */
        if (ksig->ka.sa.sa_flags & SA_RESTORER) {
-               regs->gprs[14] = (__u64 __force) ksig->ka.sa.sa_restorer | PSW32_ADDR_AMODE;
+               restorer = (unsigned long __force)
+                       ksig->ka.sa.sa_restorer | PSW32_ADDR_AMODE;
        } else {
-               regs->gprs[14] = (__u64 __force) frame->retcode | PSW32_ADDR_AMODE;
-               if (__put_user(S390_SYSCALL_OPCODE | __NR_rt_sigreturn,
-                              (u16 __force __user *)(frame->retcode)))
+               __u16 __user *svc = &frame->svc_insn;
+               if (__put_user(S390_SYSCALL_OPCODE | __NR_rt_sigreturn, svc))
                        return -EFAULT;
+               restorer = (unsigned long __force) svc | PSW32_ADDR_AMODE;
        }
 
-       /* Set up backchain. */
-       if (__put_user(regs->gprs[15], (unsigned int __force __user *) frame))
+       /* Create siginfo on the signal stack */
+       if (copy_siginfo_to_user32(&frame->info, &ksig->info))
+               return -EFAULT;
+
+       /* Store registers needed to create the signal frame */
+       store_sigregs();
+
+       /* Create ucontext on the signal stack. */
+       if (__put_user(uc_flags, &frame->uc.uc_flags) ||
+           __put_user(0, &frame->uc.uc_link) ||
+           __compat_save_altstack(&frame->uc.uc_stack, regs->gprs[15]) ||
+           save_sigregs32(regs, &frame->uc.uc_mcontext) ||
+           __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)) ||
+           save_sigregs_ext32(regs, &frame->uc.uc_mcontext_ext))
                return -EFAULT;
 
        /* Set up registers for signal handler */
+       regs->gprs[14] = restorer;
        regs->gprs[15] = (__force __u64) frame;
        /* Force 31 bit amode and default user address space control. */
        regs->psw.mask = PSW_MASK_BA |
index a3b9150e6802973b3b82a6db379c7959dfb48e9d..9f73c805902291c1619335cb38c4fe0f8492b29a 100644 (file)
@@ -46,9 +46,9 @@ struct dump_save_areas dump_save_areas;
 /*
  * Allocate and add a save area for a CPU
  */
-struct save_area *dump_save_area_create(int cpu)
+struct save_area_ext *dump_save_area_create(int cpu)
 {
-       struct save_area **save_areas, *save_area;
+       struct save_area_ext **save_areas, *save_area;
 
        save_area = kmalloc(sizeof(*save_area), GFP_KERNEL);
        if (!save_area)
@@ -385,10 +385,46 @@ static void *nt_s390_prefix(void *ptr, struct save_area *sa)
                         sizeof(sa->pref_reg), KEXEC_CORE_NOTE_NAME);
 }
 
+/*
+ * Initialize vxrs high note (full 128 bit VX registers 16-31)
+ */
+static void *nt_s390_vx_high(void *ptr, __vector128 *vx_regs)
+{
+       return nt_init(ptr, NT_S390_VXRS_HIGH, &vx_regs[16],
+                      16 * sizeof(__vector128), KEXEC_CORE_NOTE_NAME);
+}
+
+/*
+ * Initialize vxrs low note (lower halves of VX registers 0-15)
+ */
+static void *nt_s390_vx_low(void *ptr, __vector128 *vx_regs)
+{
+       Elf64_Nhdr *note;
+       u64 len;
+       int i;
+
+       note = (Elf64_Nhdr *)ptr;
+       note->n_namesz = strlen(KEXEC_CORE_NOTE_NAME) + 1;
+       note->n_descsz = 16 * 8;
+       note->n_type = NT_S390_VXRS_LOW;
+       len = sizeof(Elf64_Nhdr);
+
+       memcpy(ptr + len, KEXEC_CORE_NOTE_NAME, note->n_namesz);
+       len = roundup(len + note->n_namesz, 4);
+
+       ptr += len;
+       /* Copy lower halves of SIMD registers 0-15 */
+       for (i = 0; i < 16; i++) {
+               memcpy(ptr, &vx_regs[i], 8);
+               ptr += 8;
+       }
+       return ptr;
+}
+
 /*
  * Fill ELF notes for one CPU with save area registers
  */
-void *fill_cpu_elf_notes(void *ptr, struct save_area *sa)
+void *fill_cpu_elf_notes(void *ptr, struct save_area *sa, __vector128 *vx_regs)
 {
        ptr = nt_prstatus(ptr, sa);
        ptr = nt_fpregset(ptr, sa);
@@ -397,6 +433,10 @@ void *fill_cpu_elf_notes(void *ptr, struct save_area *sa)
        ptr = nt_s390_tod_preg(ptr, sa);
        ptr = nt_s390_ctrs(ptr, sa);
        ptr = nt_s390_prefix(ptr, sa);
+       if (MACHINE_HAS_VX && vx_regs) {
+               ptr = nt_s390_vx_low(ptr, vx_regs);
+               ptr = nt_s390_vx_high(ptr, vx_regs);
+       }
        return ptr;
 }
 
@@ -484,7 +524,7 @@ static int get_cpu_cnt(void)
        int i, cpus = 0;
 
        for (i = 0; i < dump_save_areas.count; i++) {
-               if (dump_save_areas.areas[i]->pref_reg == 0)
+               if (dump_save_areas.areas[i]->sa.pref_reg == 0)
                        continue;
                cpus++;
        }
@@ -530,17 +570,17 @@ static void loads_init(Elf64_Phdr *phdr, u64 loads_offset)
  */
 static void *notes_init(Elf64_Phdr *phdr, void *ptr, u64 notes_offset)
 {
-       struct save_area *sa;
+       struct save_area_ext *sa_ext;
        void *ptr_start = ptr;
        int i;
 
        ptr = nt_prpsinfo(ptr);
 
        for (i = 0; i < dump_save_areas.count; i++) {
-               sa = dump_save_areas.areas[i];
-               if (sa->pref_reg == 0)
+               sa_ext = dump_save_areas.areas[i];
+               if (sa_ext->sa.pref_reg == 0)
                        continue;
-               ptr = fill_cpu_elf_notes(ptr, sa);
+               ptr = fill_cpu_elf_notes(ptr, &sa_ext->sa, sa_ext->vx_regs);
        }
        ptr = nt_vmcoreinfo(ptr);
        memset(phdr, 0, sizeof(*phdr));
@@ -581,7 +621,7 @@ int elfcorehdr_alloc(unsigned long long *addr, unsigned long long *size)
 
        mem_chunk_cnt = get_mem_chunk_cnt();
 
-       alloc_size = 0x1000 + get_cpu_cnt() * 0x300 +
+       alloc_size = 0x1000 + get_cpu_cnt() * 0x4a0 +
                mem_chunk_cnt * sizeof(Elf64_Phdr);
        hdr = kzalloc_panic(alloc_size);
        /* Init elf header */
index 993efe6a887c2c31d4bcd90b02bccbb3c0234ae9..f3762937dd82ee8afcc2c0fddae6397e2be863fa 100644 (file)
@@ -60,6 +60,11 @@ enum {
        A_28,   /* Access reg. starting at position 28 */
        C_8,    /* Control reg. starting at position 8 */
        C_12,   /* Control reg. starting at position 12 */
+       V_8,    /* Vector reg. starting at position 8, extension bit at 36 */
+       V_12,   /* Vector reg. starting at position 12, extension bit at 37 */
+       V_16,   /* Vector reg. starting at position 16, extension bit at 38 */
+       V_32,   /* Vector reg. starting at position 32, extension bit at 39 */
+       W_12,   /* Vector reg. at bit 12, extension at bit 37, used as index */
        B_16,   /* Base register starting at position 16 */
        B_32,   /* Base register starting at position 32 */
        X_12,   /* Index register starting at position 12 */
@@ -82,6 +87,8 @@ enum {
        U8_24,  /* 8 bit unsigned value starting at 24 */
        U8_32,  /* 8 bit unsigned value starting at 32 */
        I8_8,   /* 8 bit signed value starting at 8 */
+       I8_16,  /* 8 bit signed value starting at 16 */
+       I8_24,  /* 8 bit signed value starting at 24 */
        I8_32,  /* 8 bit signed value starting at 32 */
        J12_12, /* PC relative offset at 12 */
        I16_16, /* 16 bit signed value starting at 16 */
@@ -96,6 +103,9 @@ enum {
        U32_16, /* 32 bit unsigned value starting at 16 */
        M_16,   /* 4 bit optional mask starting at 16 */
        M_20,   /* 4 bit optional mask starting at 20 */
+       M_24,   /* 4 bit optional mask starting at 24 */
+       M_28,   /* 4 bit optional mask starting at 28 */
+       M_32,   /* 4 bit optional mask starting at 32 */
        RO_28,  /* optional GPR starting at position 28 */
 };
 
@@ -130,7 +140,7 @@ enum {
        INSTR_RSY_RDRM,
        INSTR_RS_AARD, INSTR_RS_CCRD, INSTR_RS_R0RD, INSTR_RS_RRRD,
        INSTR_RS_RURD,
-       INSTR_RXE_FRRD, INSTR_RXE_RRRD,
+       INSTR_RXE_FRRD, INSTR_RXE_RRRD, INSTR_RXE_RRRDM,
        INSTR_RXF_FRRDF,
        INSTR_RXY_FRRD, INSTR_RXY_RRRD, INSTR_RXY_URRD,
        INSTR_RX_FRRD, INSTR_RX_RRRD, INSTR_RX_URRD,
@@ -143,6 +153,17 @@ enum {
        INSTR_SS_L0RDRD, INSTR_SS_LIRDRD, INSTR_SS_LLRDRD, INSTR_SS_RRRDRD,
        INSTR_SS_RRRDRD2, INSTR_SS_RRRDRD3,
        INSTR_S_00, INSTR_S_RD,
+       INSTR_VRI_V0IM, INSTR_VRI_V0I0, INSTR_VRI_V0IIM, INSTR_VRI_VVIM,
+       INSTR_VRI_VVV0IM, INSTR_VRI_VVV0I0, INSTR_VRI_VVIMM,
+       INSTR_VRR_VV00MMM, INSTR_VRR_VV000MM, INSTR_VRR_VV0000M,
+       INSTR_VRR_VV00000, INSTR_VRR_VVV0M0M, INSTR_VRR_VV00M0M,
+       INSTR_VRR_VVV000M, INSTR_VRR_VVV000V, INSTR_VRR_VVV0000,
+       INSTR_VRR_VVV0MMM, INSTR_VRR_VVV00MM, INSTR_VRR_VVVMM0V,
+       INSTR_VRR_VVVM0MV, INSTR_VRR_VVVM00V, INSTR_VRR_VRR0000,
+       INSTR_VRS_VVRDM, INSTR_VRS_VVRD0, INSTR_VRS_VRRDM, INSTR_VRS_VRRD0,
+       INSTR_VRS_RVRDM,
+       INSTR_VRV_VVRDM, INSTR_VRV_VWRDM,
+       INSTR_VRX_VRRDM, INSTR_VRX_VRRD0,
 };
 
 static const struct s390_operand operands[] =
@@ -168,6 +189,11 @@ static const struct s390_operand operands[] =
        [A_28]   = {  4, 28, OPERAND_AR },
        [C_8]    = {  4,  8, OPERAND_CR },
        [C_12]   = {  4, 12, OPERAND_CR },
+       [V_8]    = {  4,  8, OPERAND_VR },
+       [V_12]   = {  4, 12, OPERAND_VR },
+       [V_16]   = {  4, 16, OPERAND_VR },
+       [V_32]   = {  4, 32, OPERAND_VR },
+       [W_12]   = {  4, 12, OPERAND_INDEX | OPERAND_VR },
        [B_16]   = {  4, 16, OPERAND_BASE | OPERAND_GPR },
        [B_32]   = {  4, 32, OPERAND_BASE | OPERAND_GPR },
        [X_12]   = {  4, 12, OPERAND_INDEX | OPERAND_GPR },
@@ -190,6 +216,11 @@ static const struct s390_operand operands[] =
        [U8_24]  = {  8, 24, 0 },
        [U8_32]  = {  8, 32, 0 },
        [J12_12] = { 12, 12, OPERAND_PCREL },
+       [I8_8]   = {  8,  8, OPERAND_SIGNED },
+       [I8_16]  = {  8, 16, OPERAND_SIGNED },
+       [I8_24]  = {  8, 24, OPERAND_SIGNED },
+       [I8_32]  = {  8, 32, OPERAND_SIGNED },
+       [I16_32] = { 16, 32, OPERAND_SIGNED },
        [I16_16] = { 16, 16, OPERAND_SIGNED },
        [U16_16] = { 16, 16, 0 },
        [U16_32] = { 16, 32, 0 },
@@ -202,6 +233,9 @@ static const struct s390_operand operands[] =
        [U32_16] = { 32, 16, 0 },
        [M_16]   = {  4, 16, 0 },
        [M_20]   = {  4, 20, 0 },
+       [M_24]   = {  4, 24, 0 },
+       [M_28]   = {  4, 28, 0 },
+       [M_32]   = {  4, 32, 0 },
        [RO_28]  = {  4, 28, OPERAND_GPR }
 };
 
@@ -283,6 +317,7 @@ static const unsigned char formats[][7] = {
        [INSTR_RS_RURD]   = { 0xff, R_8,U4_12,D_20,B_16,0,0 },
        [INSTR_RXE_FRRD]  = { 0xff, F_8,D_20,X_12,B_16,0,0 },
        [INSTR_RXE_RRRD]  = { 0xff, R_8,D_20,X_12,B_16,0,0 },
+       [INSTR_RXE_RRRDM] = { 0xff, R_8,D_20,X_12,B_16,M_32,0 },
        [INSTR_RXF_FRRDF] = { 0xff, F_32,F_8,D_20,X_12,B_16,0 },
        [INSTR_RXY_FRRD]  = { 0xff, F_8,D20_20,X_12,B_16,0,0 },
        [INSTR_RXY_RRRD]  = { 0xff, R_8,D20_20,X_12,B_16,0,0 },
@@ -307,6 +342,37 @@ static const unsigned char formats[][7] = {
        [INSTR_SS_RRRDRD] = { 0xff, D_20,R_8,B_16,D_36,B_32,R_12 },
        [INSTR_S_00]      = { 0xff, 0,0,0,0,0,0 },
        [INSTR_S_RD]      = { 0xff, D_20,B_16,0,0,0,0 },
+       [INSTR_VRI_V0IM]  = { 0xff, V_8,I16_16,M_32,0,0,0 },
+       [INSTR_VRI_V0I0]  = { 0xff, V_8,I16_16,0,0,0,0 },
+       [INSTR_VRI_V0IIM] = { 0xff, V_8,I8_16,I8_24,M_32,0,0 },
+       [INSTR_VRI_VVIM]  = { 0xff, V_8,I16_16,V_12,M_32,0,0 },
+       [INSTR_VRI_VVV0IM]= { 0xff, V_8,V_12,V_16,I8_24,M_32,0 },
+       [INSTR_VRI_VVV0I0]= { 0xff, V_8,V_12,V_16,I8_24,0,0 },
+       [INSTR_VRI_VVIMM] = { 0xff, V_8,V_12,I16_16,M_32,M_28,0 },
+       [INSTR_VRR_VV00MMM]={ 0xff, V_8,V_12,M_32,M_28,M_24,0 },
+       [INSTR_VRR_VV000MM]={ 0xff, V_8,V_12,M_32,M_28,0,0 },
+       [INSTR_VRR_VV0000M]={ 0xff, V_8,V_12,M_32,0,0,0 },
+       [INSTR_VRR_VV00000]={ 0xff, V_8,V_12,0,0,0,0 },
+       [INSTR_VRR_VVV0M0M]={ 0xff, V_8,V_12,V_16,M_32,M_24,0 },
+       [INSTR_VRR_VV00M0M]={ 0xff, V_8,V_12,M_32,M_24,0,0 },
+       [INSTR_VRR_VVV000M]={ 0xff, V_8,V_12,V_16,M_32,0,0 },
+       [INSTR_VRR_VVV000V]={ 0xff, V_8,V_12,V_16,V_32,0,0 },
+       [INSTR_VRR_VVV0000]={ 0xff, V_8,V_12,V_16,0,0,0 },
+       [INSTR_VRR_VVV0MMM]={ 0xff, V_8,V_12,V_16,M_32,M_28,M_24 },
+       [INSTR_VRR_VVV00MM]={ 0xff, V_8,V_12,V_16,M_32,M_28,0 },
+       [INSTR_VRR_VVVMM0V]={ 0xff, V_8,V_12,V_16,V_32,M_20,M_24 },
+       [INSTR_VRR_VVVM0MV]={ 0xff, V_8,V_12,V_16,V_32,M_28,M_20 },
+       [INSTR_VRR_VVVM00V]={ 0xff, V_8,V_12,V_16,V_32,M_20,0 },
+       [INSTR_VRR_VRR0000]={ 0xff, V_8,R_12,R_16,0,0,0 },
+       [INSTR_VRS_VVRDM] = { 0xff, V_8,V_12,D_20,B_16,M_32,0 },
+       [INSTR_VRS_VVRD0] = { 0xff, V_8,V_12,D_20,B_16,0,0 },
+       [INSTR_VRS_VRRDM] = { 0xff, V_8,R_12,D_20,B_16,M_32,0 },
+       [INSTR_VRS_VRRD0] = { 0xff, V_8,R_12,D_20,B_16,0,0 },
+       [INSTR_VRS_RVRDM] = { 0xff, R_8,V_12,D_20,B_16,M_32,0 },
+       [INSTR_VRV_VVRDM] = { 0xff, V_8,V_12,D_20,B_16,M_32,0 },
+       [INSTR_VRV_VWRDM] = { 0xff, V_8,D_20,W_12,B_16,M_32,0 },
+       [INSTR_VRX_VRRDM] = { 0xff, V_8,D_20,X_12,B_16,M_32,0 },
+       [INSTR_VRX_VRRD0] = { 0xff, V_8,D_20,X_12,B_16,0,0 },
 };
 
 enum {
@@ -381,6 +447,11 @@ enum {
        LONG_INSN_MPCIFC,
        LONG_INSN_STPCIFC,
        LONG_INSN_PCISTB,
+       LONG_INSN_VPOPCT,
+       LONG_INSN_VERLLV,
+       LONG_INSN_VESRAV,
+       LONG_INSN_VESRLV,
+       LONG_INSN_VSBCBI
 };
 
 static char *long_insn_name[] = {
@@ -455,6 +526,11 @@ static char *long_insn_name[] = {
        [LONG_INSN_MPCIFC] = "mpcifc",
        [LONG_INSN_STPCIFC] = "stpcifc",
        [LONG_INSN_PCISTB] = "pcistb",
+       [LONG_INSN_VPOPCT] = "vpopct",
+       [LONG_INSN_VERLLV] = "verllv",
+       [LONG_INSN_VESRAV] = "vesrav",
+       [LONG_INSN_VESRLV] = "vesrlv",
+       [LONG_INSN_VSBCBI] = "vsbcbi",
 };
 
 static struct s390_insn opcode[] = {
@@ -1369,6 +1445,150 @@ static struct s390_insn opcode_e5[] = {
        { "", 0, INSTR_INVALID }
 };
 
+static struct s390_insn opcode_e7[] = {
+#ifdef CONFIG_64BIT
+       { "lcbb", 0x27, INSTR_RXE_RRRDM },
+       { "vgef", 0x13, INSTR_VRV_VVRDM },
+       { "vgeg", 0x12, INSTR_VRV_VVRDM },
+       { "vgbm", 0x44, INSTR_VRI_V0I0 },
+       { "vgm", 0x46, INSTR_VRI_V0IIM },
+       { "vl", 0x06, INSTR_VRX_VRRD0 },
+       { "vlr", 0x56, INSTR_VRR_VV00000 },
+       { "vlrp", 0x05, INSTR_VRX_VRRDM },
+       { "vleb", 0x00, INSTR_VRX_VRRDM },
+       { "vleh", 0x01, INSTR_VRX_VRRDM },
+       { "vlef", 0x03, INSTR_VRX_VRRDM },
+       { "vleg", 0x02, INSTR_VRX_VRRDM },
+       { "vleib", 0x40, INSTR_VRI_V0IM },
+       { "vleih", 0x41, INSTR_VRI_V0IM },
+       { "vleif", 0x43, INSTR_VRI_V0IM },
+       { "vleig", 0x42, INSTR_VRI_V0IM },
+       { "vlgv", 0x21, INSTR_VRS_RVRDM },
+       { "vllez", 0x04, INSTR_VRX_VRRDM },
+       { "vlm", 0x36, INSTR_VRS_VVRD0 },
+       { "vlbb", 0x07, INSTR_VRX_VRRDM },
+       { "vlvg", 0x22, INSTR_VRS_VRRDM },
+       { "vlvgp", 0x62, INSTR_VRR_VRR0000 },
+       { "vll", 0x37, INSTR_VRS_VRRD0 },
+       { "vmrh", 0x61, INSTR_VRR_VVV000M },
+       { "vmrl", 0x60, INSTR_VRR_VVV000M },
+       { "vpk", 0x94, INSTR_VRR_VVV000M },
+       { "vpks", 0x97, INSTR_VRR_VVV0M0M },
+       { "vpkls", 0x95, INSTR_VRR_VVV0M0M },
+       { "vperm", 0x8c, INSTR_VRR_VVV000V },
+       { "vpdi", 0x84, INSTR_VRR_VVV000M },
+       { "vrep", 0x4d, INSTR_VRI_VVIM },
+       { "vrepi", 0x45, INSTR_VRI_V0IM },
+       { "vscef", 0x1b, INSTR_VRV_VWRDM },
+       { "vsceg", 0x1a, INSTR_VRV_VWRDM },
+       { "vsel", 0x8d, INSTR_VRR_VVV000V },
+       { "vseg", 0x5f, INSTR_VRR_VV0000M },
+       { "vst", 0x0e, INSTR_VRX_VRRD0 },
+       { "vsteb", 0x08, INSTR_VRX_VRRDM },
+       { "vsteh", 0x09, INSTR_VRX_VRRDM },
+       { "vstef", 0x0b, INSTR_VRX_VRRDM },
+       { "vsteg", 0x0a, INSTR_VRX_VRRDM },
+       { "vstm", 0x3e, INSTR_VRS_VVRD0 },
+       { "vstl", 0x3f, INSTR_VRS_VRRD0 },
+       { "vuph", 0xd7, INSTR_VRR_VV0000M },
+       { "vuplh", 0xd5, INSTR_VRR_VV0000M },
+       { "vupl", 0xd6, INSTR_VRR_VV0000M },
+       { "vupll", 0xd4, INSTR_VRR_VV0000M },
+       { "va", 0xf3, INSTR_VRR_VVV000M },
+       { "vacc", 0xf1, INSTR_VRR_VVV000M },
+       { "vac", 0xbb, INSTR_VRR_VVVM00V },
+       { "vaccc", 0xb9, INSTR_VRR_VVVM00V },
+       { "vn", 0x68, INSTR_VRR_VVV0000 },
+       { "vnc", 0x69, INSTR_VRR_VVV0000 },
+       { "vavg", 0xf2, INSTR_VRR_VVV000M },
+       { "vavgl", 0xf0, INSTR_VRR_VVV000M },
+       { "vcksm", 0x66, INSTR_VRR_VVV0000 },
+       { "vec", 0xdb, INSTR_VRR_VV0000M },
+       { "vecl", 0xd9, INSTR_VRR_VV0000M },
+       { "vceq", 0xf8, INSTR_VRR_VVV0M0M },
+       { "vch", 0xfb, INSTR_VRR_VVV0M0M },
+       { "vchl", 0xf9, INSTR_VRR_VVV0M0M },
+       { "vclz", 0x53, INSTR_VRR_VV0000M },
+       { "vctz", 0x52, INSTR_VRR_VV0000M },
+       { "vx", 0x6d, INSTR_VRR_VVV0000 },
+       { "vgfm", 0xb4, INSTR_VRR_VVV000M },
+       { "vgfma", 0xbc, INSTR_VRR_VVVM00V },
+       { "vlc", 0xde, INSTR_VRR_VV0000M },
+       { "vlp", 0xdf, INSTR_VRR_VV0000M },
+       { "vmx", 0xff, INSTR_VRR_VVV000M },
+       { "vmxl", 0xfd, INSTR_VRR_VVV000M },
+       { "vmn", 0xfe, INSTR_VRR_VVV000M },
+       { "vmnl", 0xfc, INSTR_VRR_VVV000M },
+       { "vmal", 0xaa, INSTR_VRR_VVVM00V },
+       { "vmae", 0xae, INSTR_VRR_VVVM00V },
+       { "vmale", 0xac, INSTR_VRR_VVVM00V },
+       { "vmah", 0xab, INSTR_VRR_VVVM00V },
+       { "vmalh", 0xa9, INSTR_VRR_VVVM00V },
+       { "vmao", 0xaf, INSTR_VRR_VVVM00V },
+       { "vmalo", 0xad, INSTR_VRR_VVVM00V },
+       { "vmh", 0xa3, INSTR_VRR_VVV000M },
+       { "vmlh", 0xa1, INSTR_VRR_VVV000M },
+       { "vml", 0xa2, INSTR_VRR_VVV000M },
+       { "vme", 0xa6, INSTR_VRR_VVV000M },
+       { "vmle", 0xa4, INSTR_VRR_VVV000M },
+       { "vmo", 0xa7, INSTR_VRR_VVV000M },
+       { "vmlo", 0xa5, INSTR_VRR_VVV000M },
+       { "vno", 0x6b, INSTR_VRR_VVV0000 },
+       { "vo", 0x6a, INSTR_VRR_VVV0000 },
+       { { 0, LONG_INSN_VPOPCT }, 0x50, INSTR_VRR_VV0000M },
+       { { 0, LONG_INSN_VERLLV }, 0x73, INSTR_VRR_VVV000M },
+       { "verll", 0x33, INSTR_VRS_VVRDM },
+       { "verim", 0x72, INSTR_VRI_VVV0IM },
+       { "veslv", 0x70, INSTR_VRR_VVV000M },
+       { "vesl", 0x30, INSTR_VRS_VVRDM },
+       { { 0, LONG_INSN_VESRAV }, 0x7a, INSTR_VRR_VVV000M },
+       { "vesra", 0x3a, INSTR_VRS_VVRDM },
+       { { 0, LONG_INSN_VESRLV }, 0x78, INSTR_VRR_VVV000M },
+       { "vesrl", 0x38, INSTR_VRS_VVRDM },
+       { "vsl", 0x74, INSTR_VRR_VVV0000 },
+       { "vslb", 0x75, INSTR_VRR_VVV0000 },
+       { "vsldb", 0x77, INSTR_VRI_VVV0I0 },
+       { "vsra", 0x7e, INSTR_VRR_VVV0000 },
+       { "vsrab", 0x7f, INSTR_VRR_VVV0000 },
+       { "vsrl", 0x7c, INSTR_VRR_VVV0000 },
+       { "vsrlb", 0x7d, INSTR_VRR_VVV0000 },
+       { "vs", 0xf7, INSTR_VRR_VVV000M },
+       { "vscb", 0xf5, INSTR_VRR_VVV000M },
+       { "vsb", 0xbf, INSTR_VRR_VVVM00V },
+       { { 0, LONG_INSN_VSBCBI }, 0xbd, INSTR_VRR_VVVM00V },
+       { "vsumg", 0x65, INSTR_VRR_VVV000M },
+       { "vsumq", 0x67, INSTR_VRR_VVV000M },
+       { "vsum", 0x64, INSTR_VRR_VVV000M },
+       { "vtm", 0xd8, INSTR_VRR_VV00000 },
+       { "vfae", 0x82, INSTR_VRR_VVV0M0M },
+       { "vfee", 0x80, INSTR_VRR_VVV0M0M },
+       { "vfene", 0x81, INSTR_VRR_VVV0M0M },
+       { "vistr", 0x5c, INSTR_VRR_VV00M0M },
+       { "vstrc", 0x8a, INSTR_VRR_VVVMM0V },
+       { "vfa", 0xe3, INSTR_VRR_VVV00MM },
+       { "wfc", 0xcb, INSTR_VRR_VV000MM },
+       { "wfk", 0xca, INSTR_VRR_VV000MM },
+       { "vfce", 0xe8, INSTR_VRR_VVV0MMM },
+       { "vfch", 0xeb, INSTR_VRR_VVV0MMM },
+       { "vfche", 0xea, INSTR_VRR_VVV0MMM },
+       { "vcdg", 0xc3, INSTR_VRR_VV00MMM },
+       { "vcdlg", 0xc1, INSTR_VRR_VV00MMM },
+       { "vcgd", 0xc2, INSTR_VRR_VV00MMM },
+       { "vclgd", 0xc0, INSTR_VRR_VV00MMM },
+       { "vfd", 0xe5, INSTR_VRR_VVV00MM },
+       { "vfi", 0xc7, INSTR_VRR_VV00MMM },
+       { "vlde", 0xc4, INSTR_VRR_VV000MM },
+       { "vled", 0xc5, INSTR_VRR_VV00MMM },
+       { "vfm", 0xe7, INSTR_VRR_VVV00MM },
+       { "vfma", 0x8f, INSTR_VRR_VVVM0MV },
+       { "vfms", 0x8e, INSTR_VRR_VVVM0MV },
+       { "vfpso", 0xcc, INSTR_VRR_VV00MMM },
+       { "vfsq", 0xce, INSTR_VRR_VV000MM },
+       { "vfs", 0xe2, INSTR_VRR_VVV00MM },
+       { "vftci", 0x4a, INSTR_VRI_VVIMM },
+#endif
+};
+
 static struct s390_insn opcode_eb[] = {
 #ifdef CONFIG_64BIT
        { "lmg", 0x04, INSTR_RSY_RRRD },
@@ -1552,16 +1772,17 @@ static struct s390_insn opcode_ed[] = {
 static unsigned int extract_operand(unsigned char *code,
                                    const struct s390_operand *operand)
 {
+       unsigned char *cp;
        unsigned int val;
        int bits;
 
        /* Extract fragments of the operand byte for byte.  */
-       code += operand->shift / 8;
+       cp = code + operand->shift / 8;
        bits = (operand->shift & 7) + operand->bits;
        val = 0;
        do {
                val <<= 8;
-               val |= (unsigned int) *code++;
+               val |= (unsigned int) *cp++;
                bits -= 8;
        } while (bits > 0);
        val >>= -bits;
@@ -1571,6 +1792,18 @@ static unsigned int extract_operand(unsigned char *code,
        if (operand->bits == 20 && operand->shift == 20)
                val = (val & 0xff) << 12 | (val & 0xfff00) >> 8;
 
+       /* Check for register extensions bits for vector registers. */
+       if (operand->flags & OPERAND_VR) {
+               if (operand->shift == 8)
+                       val |= (code[4] & 8) << 1;
+               else if (operand->shift == 12)
+                       val |= (code[4] & 4) << 2;
+               else if (operand->shift == 16)
+                       val |= (code[4] & 2) << 3;
+               else if (operand->shift == 32)
+                       val |= (code[4] & 1) << 4;
+       }
+
        /* Sign extend value if the operand is signed or pc relative.  */
        if ((operand->flags & (OPERAND_SIGNED | OPERAND_PCREL)) &&
            (val & (1U << (operand->bits - 1))))
@@ -1639,6 +1872,10 @@ struct s390_insn *find_insn(unsigned char *code)
        case 0xe5:
                table = opcode_e5;
                break;
+       case 0xe7:
+               table = opcode_e7;
+               opfrag = code[5];
+               break;
        case 0xeb:
                table = opcode_eb;
                opfrag = code[5];
@@ -1734,6 +1971,8 @@ static int print_insn(char *buffer, unsigned char *code, unsigned long addr)
                                ptr += sprintf(ptr, "%%a%i", value);
                        else if (operand->flags & OPERAND_CR)
                                ptr += sprintf(ptr, "%%c%i", value);
+                       else if (operand->flags & OPERAND_VR)
+                               ptr += sprintf(ptr, "%%v%i", value);
                        else if (operand->flags & OPERAND_PCREL)
                                ptr += sprintf(ptr, "%lx", (signed int) value
                                                                      + addr);
index 0dff972a169c16dd533c8256de9771e96f459e01..cef2879edff321e151972f059973cd7e9babca68 100644 (file)
@@ -390,10 +390,10 @@ static __init void detect_machine_facilities(void)
                S390_lowcore.machine_flags |= MACHINE_FLAG_LPP;
        if (test_facility(50) && test_facility(73))
                S390_lowcore.machine_flags |= MACHINE_FLAG_TE;
-       if (test_facility(66))
-               S390_lowcore.machine_flags |= MACHINE_FLAG_RRBM;
        if (test_facility(51))
                S390_lowcore.machine_flags |= MACHINE_FLAG_TLB_LC;
+       if (test_facility(129))
+               S390_lowcore.machine_flags |= MACHINE_FLAG_VX;
 #endif
 }
 
index 1aad48398d06124541ef7936aacdb8d08f26c038..0554b9771c9f29eb727d40f0552258403e3201e3 100644 (file)
@@ -4,7 +4,7 @@
 #include <linux/types.h>
 #include <linux/signal.h>
 #include <asm/ptrace.h>
-#include <asm/cputime.h>
+#include <asm/idle.h>
 
 extern void *restart_stack;
 extern unsigned long suspend_zero_pages;
@@ -21,6 +21,8 @@ void psw_idle(struct s390_idle_data *, unsigned long);
 asmlinkage long do_syscall_trace_enter(struct pt_regs *regs);
 asmlinkage void do_syscall_trace_exit(struct pt_regs *regs);
 
+int alloc_vector_registers(struct task_struct *tsk);
+
 void do_protection_exception(struct pt_regs *regs);
 void do_dat_exception(struct pt_regs *regs);
 
@@ -43,8 +45,10 @@ void special_op_exception(struct pt_regs *regs);
 void specification_exception(struct pt_regs *regs);
 void transaction_exception(struct pt_regs *regs);
 void translation_exception(struct pt_regs *regs);
+void vector_exception(struct pt_regs *regs);
 
 void do_per_trap(struct pt_regs *regs);
+void do_report_trap(struct pt_regs *regs, int si_signo, int si_code, char *str);
 void syscall_trace(struct pt_regs *regs, int entryexit);
 void kernel_stack_overflow(struct pt_regs * regs);
 void do_signal(struct pt_regs *regs);
index f2e674c702e1f904de800b94c33bedfd5fd30b91..7b2e03afd0177cda23a6d8424f0fe8934f705648 100644 (file)
@@ -42,7 +42,8 @@ STACK_SHIFT = PAGE_SHIFT + THREAD_ORDER
 STACK_SIZE  = 1 << STACK_SHIFT
 STACK_INIT = STACK_SIZE - STACK_FRAME_OVERHEAD - __PT_SIZE
 
-_TIF_WORK      = (_TIF_SIGPENDING | _TIF_NOTIFY_RESUME | _TIF_NEED_RESCHED)
+_TIF_WORK      = (_TIF_SIGPENDING | _TIF_NOTIFY_RESUME | _TIF_NEED_RESCHED | \
+                  _TIF_UPROBE)
 _TIF_TRACE     = (_TIF_SYSCALL_TRACE | _TIF_SYSCALL_AUDIT | _TIF_SECCOMP | \
                   _TIF_SYSCALL_TRACEPOINT)
 _CIF_WORK      = (_CIF_MCCK_PENDING | _CIF_ASCE)
@@ -265,6 +266,10 @@ sysc_work:
        jo      sysc_mcck_pending
        tm      __TI_flags+7(%r12),_TIF_NEED_RESCHED
        jo      sysc_reschedule
+#ifdef CONFIG_UPROBES
+       tm      __TI_flags+7(%r12),_TIF_UPROBE
+       jo      sysc_uprobe_notify
+#endif
        tm      __PT_FLAGS+7(%r11),_PIF_PER_TRAP
        jo      sysc_singlestep
        tm      __TI_flags+7(%r12),_TIF_SIGPENDING
@@ -322,6 +327,16 @@ sysc_notify_resume:
        larl    %r14,sysc_return
        jg      do_notify_resume
 
+#
+# _TIF_UPROBE is set, call uprobe_notify_resume
+#
+#ifdef CONFIG_UPROBES
+sysc_uprobe_notify:
+       lgr     %r2,%r11                # pass pointer to pt_regs
+       larl    %r14,sysc_return
+       jg      uprobe_notify_resume
+#endif
+
 #
 # _PIF_PER_TRAP is set, call do_per_trap
 #
index 54d6493c4a561b050ad5e47bb21b6a041b6d496f..51d14fe5eb9a318349876eb376b359695770a0a2 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Dynamic function tracer architecture backend.
  *
- * Copyright IBM Corp. 2009
+ * Copyright IBM Corp. 2009,2014
  *
  *   Author(s): Heiko Carstens <heiko.carstens@de.ibm.com>,
  *             Martin Schwidefsky <schwidefsky@de.ibm.com>
 #include <asm/asm-offsets.h>
 #include "entry.h"
 
-#ifdef CONFIG_DYNAMIC_FTRACE
-
+void mcount_replace_code(void);
 void ftrace_disable_code(void);
 void ftrace_enable_insn(void);
 
-#ifdef CONFIG_64BIT
 /*
- * The 64-bit mcount code looks like this:
+ * The mcount code looks like this:
  *     stg     %r14,8(%r15)            # offset 0
- * >   larl    %r1,<&counter>          # offset 6
- * >   brasl   %r14,_mcount            # offset 12
+ *     larl    %r1,<&counter>          # offset 6
+ *     brasl   %r14,_mcount            # offset 12
  *     lg      %r14,8(%r15)            # offset 18
- * Total length is 24 bytes. The middle two instructions of the mcount
- * block get overwritten by ftrace_make_nop / ftrace_make_call.
- * The 64-bit enabled ftrace code block looks like this:
- *     stg     %r14,8(%r15)            # offset 0
+ * Total length is 24 bytes. The complete mcount block initially gets replaced
+ * by ftrace_make_nop. Subsequent calls to ftrace_make_call / ftrace_make_nop
+ * only patch the jg/lg instruction within the block.
+ * Note: we do not patch the first instruction to an unconditional branch,
+ * since that would break kprobes/jprobes. It is easier to leave the larl
+ * instruction in and only modify the second instruction.
+ * The enabled ftrace code block looks like this:
+ *     larl    %r0,.+24                # offset 0
  * >   lg      %r1,__LC_FTRACE_FUNC    # offset 6
- * >   lgr     %r0,%r0                 # offset 12
- * >   basr    %r14,%r1                # offset 16
- *     lg      %r14,8(%15)             # offset 18
- * The return points of the mcount/ftrace function have the same offset 18.
- * The 64-bit disable ftrace code block looks like this:
- *     stg     %r14,8(%r15)            # offset 0
+ *     br      %r1                     # offset 12
+ *     brcl    0,0                     # offset 14
+ *     brc     0,0                     # offset 20
+ * The ftrace function gets called with a non-standard C function call ABI
+ * where r0 contains the return address. It is also expected that the called
+ * function only clobbers r0 and r1, but restores r2-r15.
+ * The return point of the ftrace function has offset 24, so execution
+ * continues behind the mcount block.
+ *     larl    %r0,.+24                # offset 0
  * >   jg      .+18                    # offset 6
- * >   lgr     %r0,%r0                 # offset 12
- * >   basr    %r14,%r1                # offset 16
- *     lg      %r14,8(%15)             # offset 18
+ *     br      %r1                     # offset 12
+ *     brcl    0,0                     # offset 14
+ *     brc     0,0                     # offset 20
  * The jg instruction branches to offset 24 to skip as many instructions
  * as possible.
  */
 asm(
        "       .align  4\n"
+       "mcount_replace_code:\n"
+       "       larl    %r0,0f\n"
        "ftrace_disable_code:\n"
        "       jg      0f\n"
-       "       lgr     %r0,%r0\n"
-       "       basr    %r14,%r1\n"
+       "       br      %r1\n"
+       "       brcl    0,0\n"
+       "       brc     0,0\n"
        "0:\n"
        "       .align  4\n"
        "ftrace_enable_insn:\n"
        "       lg      %r1,"__stringify(__LC_FTRACE_FUNC)"\n");
 
+#define MCOUNT_BLOCK_SIZE      24
+#define MCOUNT_INSN_OFFSET     6
 #define FTRACE_INSN_SIZE       6
 
-#else /* CONFIG_64BIT */
-/*
- * The 31-bit mcount code looks like this:
- *     st      %r14,4(%r15)            # offset 0
- * >   bras    %r1,0f                  # offset 4
- * >   .long   _mcount                 # offset 8
- * >   .long   <&counter>              # offset 12
- * > 0:        l       %r14,0(%r1)             # offset 16
- * >   l       %r1,4(%r1)              # offset 20
- *     basr    %r14,%r14               # offset 24
- *     l       %r14,4(%r15)            # offset 26
- * Total length is 30 bytes. The twenty bytes starting from offset 4
- * to offset 24 get overwritten by ftrace_make_nop / ftrace_make_call.
- * The 31-bit enabled ftrace code block looks like this:
- *     st      %r14,4(%r15)            # offset 0
- * >   l       %r14,__LC_FTRACE_FUNC   # offset 4
- * >   j       0f                      # offset 8
- * >   .fill   12,1,0x07               # offset 12
- *   0:        basr    %r14,%r14               # offset 24
- *     l       %r14,4(%r14)            # offset 26
- * The return points of the mcount/ftrace function have the same offset 26.
- * The 31-bit disabled ftrace code block looks like this:
- *     st      %r14,4(%r15)            # offset 0
- * >   j       .+26                    # offset 4
- * >   j       0f                      # offset 8
- * >   .fill   12,1,0x07               # offset 12
- *   0:        basr    %r14,%r14               # offset 24
- *     l       %r14,4(%r14)            # offset 26
- * The j instruction branches to offset 30 to skip as many instructions
- * as possible.
- */
-asm(
-       "       .align  4\n"
-       "ftrace_disable_code:\n"
-       "       j       1f\n"
-       "       j       0f\n"
-       "       .fill   12,1,0x07\n"
-       "0:     basr    %r14,%r14\n"
-       "1:\n"
-       "       .align  4\n"
-       "ftrace_enable_insn:\n"
-       "       l       %r14,"__stringify(__LC_FTRACE_FUNC)"\n");
-
-#define FTRACE_INSN_SIZE       4
-
-#endif /* CONFIG_64BIT */
-
+int ftrace_modify_call(struct dyn_ftrace *rec, unsigned long old_addr,
+                      unsigned long addr)
+{
+       return 0;
+}
 
 int ftrace_make_nop(struct module *mod, struct dyn_ftrace *rec,
                    unsigned long addr)
 {
+       /* Initial replacement of the whole mcount block */
+       if (addr == MCOUNT_ADDR) {
+               if (probe_kernel_write((void *) rec->ip - MCOUNT_INSN_OFFSET,
+                                      mcount_replace_code,
+                                      MCOUNT_BLOCK_SIZE))
+                       return -EPERM;
+               return 0;
+       }
        if (probe_kernel_write((void *) rec->ip, ftrace_disable_code,
                               MCOUNT_INSN_SIZE))
                return -EPERM;
@@ -135,8 +111,6 @@ int __init ftrace_dyn_arch_init(void)
        return 0;
 }
 
-#endif /* CONFIG_DYNAMIC_FTRACE */
-
 #ifdef CONFIG_FUNCTION_GRAPH_TRACER
 /*
  * Hook the return address and push it in the stack of return addresses
@@ -162,31 +136,26 @@ out:
        return parent;
 }
 
-#ifdef CONFIG_DYNAMIC_FTRACE
 /*
  * Patch the kernel code at ftrace_graph_caller location. The instruction
- * there is branch relative and save to prepare_ftrace_return. To disable
- * the call to prepare_ftrace_return we patch the bras offset to point
- * directly after the instructions. To enable the call we calculate
- * the original offset to prepare_ftrace_return and put it back.
+ * there is branch relative on condition. To enable the ftrace graph code
+ * block, we simply patch the mask field of the instruction to zero and
+ * turn the instruction into a nop.
+ * To disable the ftrace graph code the mask field will be patched to
+ * all ones, which turns the instruction into an unconditional branch.
  */
 int ftrace_enable_ftrace_graph_caller(void)
 {
-       unsigned short offset;
+       u8 op = 0x04; /* set mask field to zero */
 
-       offset = ((void *) prepare_ftrace_return -
-                 (void *) ftrace_graph_caller) / 2;
-       return probe_kernel_write((void *) ftrace_graph_caller + 2,
-                                 &offset, sizeof(offset));
+       return probe_kernel_write(__va(ftrace_graph_caller)+1, &op, sizeof(op));
 }
 
 int ftrace_disable_ftrace_graph_caller(void)
 {
-       static unsigned short offset = 0x0002;
+       u8 op = 0xf4; /* set mask field to all ones */
 
-       return probe_kernel_write((void *) ftrace_graph_caller + 2,
-                                 &offset, sizeof(offset));
+       return probe_kernel_write(__va(ftrace_graph_caller)+1, &op, sizeof(op));
 }
 
-#endif /* CONFIG_DYNAMIC_FTRACE */
 #endif /* CONFIG_FUNCTION_GRAPH_TRACER */
index e88d35d749501e43b296e8794351f691368dcf5e..d62eee11f0b54240339d898fbf95d4299c011545 100644 (file)
@@ -398,7 +398,7 @@ ENTRY(startup_kdump)
        xc      __LC_STFL_FAC_LIST(8),__LC_STFL_FAC_LIST
 #ifndef CONFIG_MARCH_G5
        # check capabilities against MARCH_{G5,Z900,Z990,Z9_109,Z10}
-       .insn   s,0xb2b10000,__LC_STFL_FAC_LIST # store facility list
+       .insn   s,0xb2b10000,0          # store facilities @ __LC_STFL_FAC_LIST
        tm      __LC_STFL_FAC_LIST,0x01 # stfle available ?
        jz      0f
        la      %r0,1
diff --git a/arch/s390/kernel/idle.c b/arch/s390/kernel/idle.c
new file mode 100644 (file)
index 0000000..c846aee
--- /dev/null
@@ -0,0 +1,124 @@
+/*
+ * Idle functions for s390.
+ *
+ * Copyright IBM Corp. 2014
+ *
+ * Author(s): Martin Schwidefsky <schwidefsky@de.ibm.com>
+ */
+
+#include <linux/kernel.h>
+#include <linux/kernel_stat.h>
+#include <linux/kprobes.h>
+#include <linux/notifier.h>
+#include <linux/init.h>
+#include <linux/cpu.h>
+#include <asm/cputime.h>
+#include <asm/nmi.h>
+#include <asm/smp.h>
+#include "entry.h"
+
+static DEFINE_PER_CPU(struct s390_idle_data, s390_idle);
+
+void __kprobes enabled_wait(void)
+{
+       struct s390_idle_data *idle = &__get_cpu_var(s390_idle);
+       unsigned long long idle_time;
+       unsigned long psw_mask;
+
+       trace_hardirqs_on();
+
+       /* Wait for external, I/O or machine check interrupt. */
+       psw_mask = PSW_KERNEL_BITS | PSW_MASK_WAIT | PSW_MASK_DAT |
+               PSW_MASK_IO | PSW_MASK_EXT | PSW_MASK_MCHECK;
+       clear_cpu_flag(CIF_NOHZ_DELAY);
+
+       /* Call the assembler magic in entry.S */
+       psw_idle(idle, psw_mask);
+
+       /* Account time spent with enabled wait psw loaded as idle time. */
+       idle->sequence++;
+       smp_wmb();
+       idle_time = idle->clock_idle_exit - idle->clock_idle_enter;
+       idle->clock_idle_enter = idle->clock_idle_exit = 0ULL;
+       idle->idle_time += idle_time;
+       idle->idle_count++;
+       account_idle_time(idle_time);
+       smp_wmb();
+       idle->sequence++;
+}
+
+static ssize_t show_idle_count(struct device *dev,
+                               struct device_attribute *attr, char *buf)
+{
+       struct s390_idle_data *idle = &per_cpu(s390_idle, dev->id);
+       unsigned long long idle_count;
+       unsigned int sequence;
+
+       do {
+               sequence = ACCESS_ONCE(idle->sequence);
+               idle_count = ACCESS_ONCE(idle->idle_count);
+               if (ACCESS_ONCE(idle->clock_idle_enter))
+                       idle_count++;
+       } while ((sequence & 1) || (ACCESS_ONCE(idle->sequence) != sequence));
+       return sprintf(buf, "%llu\n", idle_count);
+}
+DEVICE_ATTR(idle_count, 0444, show_idle_count, NULL);
+
+static ssize_t show_idle_time(struct device *dev,
+                               struct device_attribute *attr, char *buf)
+{
+       struct s390_idle_data *idle = &per_cpu(s390_idle, dev->id);
+       unsigned long long now, idle_time, idle_enter, idle_exit;
+       unsigned int sequence;
+
+       do {
+               now = get_tod_clock();
+               sequence = ACCESS_ONCE(idle->sequence);
+               idle_time = ACCESS_ONCE(idle->idle_time);
+               idle_enter = ACCESS_ONCE(idle->clock_idle_enter);
+               idle_exit = ACCESS_ONCE(idle->clock_idle_exit);
+       } while ((sequence & 1) || (ACCESS_ONCE(idle->sequence) != sequence));
+       idle_time += idle_enter ? ((idle_exit ? : now) - idle_enter) : 0;
+       return sprintf(buf, "%llu\n", idle_time >> 12);
+}
+DEVICE_ATTR(idle_time_us, 0444, show_idle_time, NULL);
+
+cputime64_t arch_cpu_idle_time(int cpu)
+{
+       struct s390_idle_data *idle = &per_cpu(s390_idle, cpu);
+       unsigned long long now, idle_enter, idle_exit;
+       unsigned int sequence;
+
+       do {
+               now = get_tod_clock();
+               sequence = ACCESS_ONCE(idle->sequence);
+               idle_enter = ACCESS_ONCE(idle->clock_idle_enter);
+               idle_exit = ACCESS_ONCE(idle->clock_idle_exit);
+       } while ((sequence & 1) || (ACCESS_ONCE(idle->sequence) != sequence));
+       return idle_enter ? ((idle_exit ?: now) - idle_enter) : 0;
+}
+
+void arch_cpu_idle_enter(void)
+{
+       local_mcck_disable();
+}
+
+void arch_cpu_idle(void)
+{
+       if (!test_cpu_flag(CIF_MCCK_PENDING))
+               /* Halt the cpu and keep track of cpu time accounting. */
+               enabled_wait();
+       local_irq_enable();
+}
+
+void arch_cpu_idle_exit(void)
+{
+       local_mcck_enable();
+       if (test_cpu_flag(CIF_MCCK_PENDING))
+               s390_handle_mcck();
+}
+
+void arch_cpu_idle_dead(void)
+{
+       cpu_die();
+}
index 8eb82443cfbdc812ebb56d67112e6c4b50ef2a2b..1b8a38ab7861c685af7d9b1b7f593a9733135909 100644 (file)
@@ -70,6 +70,7 @@ static const struct irq_class irqclass_sub_desc[NR_ARCH_IRQS] = {
        {.irq = IRQEXT_CMS, .name = "CMS", .desc = "[EXT] CPU-Measurement: Sampling"},
        {.irq = IRQEXT_CMC, .name = "CMC", .desc = "[EXT] CPU-Measurement: Counter"},
        {.irq = IRQEXT_CMR, .name = "CMR", .desc = "[EXT] CPU-Measurement: RI"},
+       {.irq = IRQEXT_FTP, .name = "FTP", .desc = "[EXT] HMC FTP Service"},
        {.irq = IRQIO_CIO,  .name = "CIO", .desc = "[I/O] Common I/O Layer Interrupt"},
        {.irq = IRQIO_QAI,  .name = "QAI", .desc = "[I/O] QDIO Adapter Interrupt"},
        {.irq = IRQIO_DAS,  .name = "DAS", .desc = "[I/O] DASD"},
@@ -258,7 +259,7 @@ static irqreturn_t do_ext_interrupt(int irq, void *dummy)
 
        ext_code = *(struct ext_code *) &regs->int_code;
        if (ext_code.code != EXT_IRQ_CLK_COMP)
-               __get_cpu_var(s390_idle).nohz_delay = 1;
+               set_cpu_flag(CIF_NOHZ_DELAY);
 
        index = ext_hash(ext_code.code);
        rcu_read_lock();
index bc71a7b95af546b94d6ac6ba74c6484bbb261069..27ae5433fe4d40dde353983e5a7fed711b3d7db4 100644 (file)
@@ -58,161 +58,13 @@ struct kprobe_insn_cache kprobe_dmainsn_slots = {
        .insn_size = MAX_INSN_SIZE,
 };
 
-static int __kprobes is_prohibited_opcode(kprobe_opcode_t *insn)
-{
-       if (!is_known_insn((unsigned char *)insn))
-               return -EINVAL;
-       switch (insn[0] >> 8) {
-       case 0x0c:      /* bassm */
-       case 0x0b:      /* bsm   */
-       case 0x83:      /* diag  */
-       case 0x44:      /* ex    */
-       case 0xac:      /* stnsm */
-       case 0xad:      /* stosm */
-               return -EINVAL;
-       case 0xc6:
-               switch (insn[0] & 0x0f) {
-               case 0x00: /* exrl   */
-                       return -EINVAL;
-               }
-       }
-       switch (insn[0]) {
-       case 0x0101:    /* pr    */
-       case 0xb25a:    /* bsa   */
-       case 0xb240:    /* bakr  */
-       case 0xb258:    /* bsg   */
-       case 0xb218:    /* pc    */
-       case 0xb228:    /* pt    */
-       case 0xb98d:    /* epsw  */
-               return -EINVAL;
-       }
-       return 0;
-}
-
-static int __kprobes get_fixup_type(kprobe_opcode_t *insn)
-{
-       /* default fixup method */
-       int fixup = FIXUP_PSW_NORMAL;
-
-       switch (insn[0] >> 8) {
-       case 0x05:      /* balr */
-       case 0x0d:      /* basr */
-               fixup = FIXUP_RETURN_REGISTER;
-               /* if r2 = 0, no branch will be taken */
-               if ((insn[0] & 0x0f) == 0)
-                       fixup |= FIXUP_BRANCH_NOT_TAKEN;
-               break;
-       case 0x06:      /* bctr */
-       case 0x07:      /* bcr  */
-               fixup = FIXUP_BRANCH_NOT_TAKEN;
-               break;
-       case 0x45:      /* bal  */
-       case 0x4d:      /* bas  */
-               fixup = FIXUP_RETURN_REGISTER;
-               break;
-       case 0x47:      /* bc   */
-       case 0x46:      /* bct  */
-       case 0x86:      /* bxh  */
-       case 0x87:      /* bxle */
-               fixup = FIXUP_BRANCH_NOT_TAKEN;
-               break;
-       case 0x82:      /* lpsw */
-               fixup = FIXUP_NOT_REQUIRED;
-               break;
-       case 0xb2:      /* lpswe */
-               if ((insn[0] & 0xff) == 0xb2)
-                       fixup = FIXUP_NOT_REQUIRED;
-               break;
-       case 0xa7:      /* bras */
-               if ((insn[0] & 0x0f) == 0x05)
-                       fixup |= FIXUP_RETURN_REGISTER;
-               break;
-       case 0xc0:
-               if ((insn[0] & 0x0f) == 0x05)   /* brasl */
-                       fixup |= FIXUP_RETURN_REGISTER;
-               break;
-       case 0xeb:
-               switch (insn[2] & 0xff) {
-               case 0x44: /* bxhg  */
-               case 0x45: /* bxleg */
-                       fixup = FIXUP_BRANCH_NOT_TAKEN;
-                       break;
-               }
-               break;
-       case 0xe3:      /* bctg */
-               if ((insn[2] & 0xff) == 0x46)
-                       fixup = FIXUP_BRANCH_NOT_TAKEN;
-               break;
-       case 0xec:
-               switch (insn[2] & 0xff) {
-               case 0xe5: /* clgrb */
-               case 0xe6: /* cgrb  */
-               case 0xf6: /* crb   */
-               case 0xf7: /* clrb  */
-               case 0xfc: /* cgib  */
-               case 0xfd: /* cglib */
-               case 0xfe: /* cib   */
-               case 0xff: /* clib  */
-                       fixup = FIXUP_BRANCH_NOT_TAKEN;
-                       break;
-               }
-               break;
-       }
-       return fixup;
-}
-
-static int __kprobes is_insn_relative_long(kprobe_opcode_t *insn)
-{
-       /* Check if we have a RIL-b or RIL-c format instruction which
-        * we need to modify in order to avoid instruction emulation. */
-       switch (insn[0] >> 8) {
-       case 0xc0:
-               if ((insn[0] & 0x0f) == 0x00) /* larl */
-                       return true;
-               break;
-       case 0xc4:
-               switch (insn[0] & 0x0f) {
-               case 0x02: /* llhrl  */
-               case 0x04: /* lghrl  */
-               case 0x05: /* lhrl   */
-               case 0x06: /* llghrl */
-               case 0x07: /* sthrl  */
-               case 0x08: /* lgrl   */
-               case 0x0b: /* stgrl  */
-               case 0x0c: /* lgfrl  */
-               case 0x0d: /* lrl    */
-               case 0x0e: /* llgfrl */
-               case 0x0f: /* strl   */
-                       return true;
-               }
-               break;
-       case 0xc6:
-               switch (insn[0] & 0x0f) {
-               case 0x02: /* pfdrl  */
-               case 0x04: /* cghrl  */
-               case 0x05: /* chrl   */
-               case 0x06: /* clghrl */
-               case 0x07: /* clhrl  */
-               case 0x08: /* cgrl   */
-               case 0x0a: /* clgrl  */
-               case 0x0c: /* cgfrl  */
-               case 0x0d: /* crl    */
-               case 0x0e: /* clgfrl */
-               case 0x0f: /* clrl   */
-                       return true;
-               }
-               break;
-       }
-       return false;
-}
-
 static void __kprobes copy_instruction(struct kprobe *p)
 {
        s64 disp, new_disp;
        u64 addr, new_addr;
 
        memcpy(p->ainsn.insn, p->addr, insn_length(p->opcode >> 8));
-       if (!is_insn_relative_long(p->ainsn.insn))
+       if (!probe_is_insn_relative_long(p->ainsn.insn))
                return;
        /*
         * For pc-relative instructions in RIL-b or RIL-c format patch the
@@ -276,7 +128,7 @@ int __kprobes arch_prepare_kprobe(struct kprobe *p)
        if ((unsigned long) p->addr & 0x01)
                return -EINVAL;
        /* Make sure the probe isn't going on a difficult instruction */
-       if (is_prohibited_opcode(p->addr))
+       if (probe_is_prohibited_opcode(p->addr))
                return -EINVAL;
        if (s390_get_insn_slot(p))
                return -ENOMEM;
@@ -605,7 +457,7 @@ static void __kprobes resume_execution(struct kprobe *p, struct pt_regs *regs)
 {
        struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
        unsigned long ip = regs->psw.addr & PSW_ADDR_INSN;
-       int fixup = get_fixup_type(p->ainsn.insn);
+       int fixup = probe_get_fixup_type(p->ainsn.insn);
 
        if (fixup & FIXUP_PSW_NORMAL)
                ip += (unsigned long) p->addr - (unsigned long) p->ainsn.insn;
@@ -789,11 +641,6 @@ void __kprobes jprobe_return(void)
        asm volatile(".word 0x0002");
 }
 
-static void __used __kprobes jprobe_return_end(void)
-{
-       asm volatile("bcr 0,0");
-}
-
 int __kprobes longjmp_break_handler(struct kprobe *p, struct pt_regs *regs)
 {
        struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
index 719e27b2cf2264b4000d65635ad26b6e06284043..4685337fa7c6bf9464630f5ec648ca65e53cea0c 100644 (file)
@@ -25,6 +25,7 @@
 #include <asm/elf.h>
 #include <asm/asm-offsets.h>
 #include <asm/os_info.h>
+#include <asm/switch_to.h>
 
 typedef void (*relocate_kernel_t)(kimage_entry_t *, unsigned long);
 
@@ -43,7 +44,7 @@ static void add_elf_notes(int cpu)
 
        memcpy((void *) (4608UL + sa->pref_reg), sa, sizeof(*sa));
        ptr = (u64 *) per_cpu_ptr(crash_notes, cpu);
-       ptr = fill_cpu_elf_notes(ptr, sa);
+       ptr = fill_cpu_elf_notes(ptr, sa, NULL);
        memset(ptr, 0, sizeof(struct elf_note));
 }
 
@@ -53,8 +54,11 @@ static void add_elf_notes(int cpu)
 static void setup_regs(void)
 {
        unsigned long sa = S390_lowcore.prefixreg_save_area + SAVE_AREA_BASE;
+       struct _lowcore *lc;
        int cpu, this_cpu;
 
+       /* Get lowcore pointer from store status of this CPU (absolute zero) */
+       lc = (struct _lowcore *)(unsigned long)S390_lowcore.prefixreg_save_area;
        this_cpu = smp_find_processor_id(stap());
        add_elf_notes(this_cpu);
        for_each_online_cpu(cpu) {
@@ -64,6 +68,8 @@ static void setup_regs(void)
                        continue;
                add_elf_notes(cpu);
        }
+       if (MACHINE_HAS_VX)
+               save_vx_regs_safe((void *) lc->vector_save_area_addr);
        /* Copy dump CPU store status info to absolute zero */
        memcpy((void *) SAVE_AREA_BASE, (void *) sa, sizeof(struct save_area));
 }
index 433c6dbfa442439b1b7cd5ce8c8b5a9e5566b44d..4300ea3748263d582d3baee7f1cdf8a7e2499dd6 100644 (file)
@@ -8,62 +8,72 @@
 #include <linux/linkage.h>
 #include <asm/asm-offsets.h>
 #include <asm/ftrace.h>
+#include <asm/ptrace.h>
 
        .section .kprobes.text, "ax"
 
 ENTRY(ftrace_stub)
        br      %r14
 
+#define STACK_FRAME_SIZE  (STACK_FRAME_OVERHEAD + __PT_SIZE)
+#define STACK_PTREGS     (STACK_FRAME_OVERHEAD)
+#define STACK_PTREGS_GPRS (STACK_PTREGS + __PT_GPRS)
+#define STACK_PTREGS_PSW  (STACK_PTREGS + __PT_PSW)
+
 ENTRY(_mcount)
-#ifdef CONFIG_DYNAMIC_FTRACE
        br      %r14
 
 ENTRY(ftrace_caller)
+       .globl  ftrace_regs_caller
+       .set    ftrace_regs_caller,ftrace_caller
+       lgr     %r1,%r15
+       aghi    %r15,-STACK_FRAME_SIZE
+       stg     %r1,__SF_BACKCHAIN(%r15)
+       stg     %r1,(STACK_PTREGS_GPRS+15*8)(%r15)
+       stg     %r0,(STACK_PTREGS_PSW+8)(%r15)
+       stmg    %r2,%r14,(STACK_PTREGS_GPRS+2*8)(%r15)
+#ifdef CONFIG_HAVE_MARCH_Z196_FEATURES
+       aghik   %r2,%r0,-MCOUNT_INSN_SIZE
+       lgrl    %r4,function_trace_op
+       lgrl    %r1,ftrace_trace_function
+#else
+       lgr     %r2,%r0
+       aghi    %r2,-MCOUNT_INSN_SIZE
+       larl    %r4,function_trace_op
+       lg      %r4,0(%r4)
+       larl    %r1,ftrace_trace_function
+       lg      %r1,0(%r1)
 #endif
-       stm     %r2,%r5,16(%r15)
-       bras    %r1,1f
-0:     .long   ftrace_trace_function
-1:     st      %r14,56(%r15)
-       lr      %r0,%r15
-       ahi     %r15,-96
-       l       %r3,100(%r15)
-       la      %r2,0(%r14)
-       st      %r0,__SF_BACKCHAIN(%r15)
-       la      %r3,0(%r3)
-       ahi     %r2,-MCOUNT_INSN_SIZE
-       l       %r14,0b-0b(%r1)
-       l       %r14,0(%r14)
-       basr    %r14,%r14
+       lgr     %r3,%r14
+       la      %r5,STACK_PTREGS(%r15)
+       basr    %r14,%r1
 #ifdef CONFIG_FUNCTION_GRAPH_TRACER
-       l       %r2,100(%r15)
-       l       %r3,152(%r15)
+# The j instruction gets runtime patched to a nop instruction.
+# See ftrace_enable_ftrace_graph_caller.
 ENTRY(ftrace_graph_caller)
-# The bras instruction gets runtime patched to call prepare_ftrace_return.
-# See ftrace_enable_ftrace_graph_caller. The patched instruction is:
-#      bras    %r14,prepare_ftrace_return
-       bras    %r14,0f
-0:     st      %r2,100(%r15)
+       j       ftrace_graph_caller_end
+       lg      %r2,(STACK_PTREGS_GPRS+14*8)(%r15)
+       lg      %r3,(STACK_PTREGS_PSW+8)(%r15)
+       brasl   %r14,prepare_ftrace_return
+       stg     %r2,(STACK_PTREGS_GPRS+14*8)(%r15)
+ftrace_graph_caller_end:
+       .globl  ftrace_graph_caller_end
 #endif
-       ahi     %r15,96
-       l       %r14,56(%r15)
-       lm      %r2,%r5,16(%r15)
-       br      %r14
+       lg      %r1,(STACK_PTREGS_PSW+8)(%r15)
+       lmg     %r2,%r15,(STACK_PTREGS_GPRS+2*8)(%r15)
+       br      %r1
 
 #ifdef CONFIG_FUNCTION_GRAPH_TRACER
 
 ENTRY(return_to_handler)
-       stm     %r2,%r5,16(%r15)
-       st      %r14,56(%r15)
-       lr      %r0,%r15
-       ahi     %r15,-96
-       st      %r0,__SF_BACKCHAIN(%r15)
-       bras    %r1,0f
-       .long   ftrace_return_to_handler
-0:     l       %r2,0b-0b(%r1)
-       basr    %r14,%r2
-       lr      %r14,%r2
-       ahi     %r15,96
-       lm      %r2,%r5,16(%r15)
+       stmg    %r2,%r5,32(%r15)
+       lgr     %r1,%r15
+       aghi    %r15,-STACK_FRAME_OVERHEAD
+       stg     %r1,__SF_BACKCHAIN(%r15)
+       brasl   %r14,ftrace_return_to_handler
+       aghi    %r15,STACK_FRAME_OVERHEAD
+       lgr     %r14,%r2
+       lmg     %r2,%r5,32(%r15)
        br      %r14
 
 #endif
diff --git a/arch/s390/kernel/mcount64.S b/arch/s390/kernel/mcount64.S
deleted file mode 100644 (file)
index c67a8bf..0000000
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Copyright IBM Corp. 2008, 2009
- *
- *   Author(s): Heiko Carstens <heiko.carstens@de.ibm.com>,
- *
- */
-
-#include <linux/linkage.h>
-#include <asm/asm-offsets.h>
-#include <asm/ftrace.h>
-
-       .section .kprobes.text, "ax"
-
-ENTRY(ftrace_stub)
-       br      %r14
-
-ENTRY(_mcount)
-#ifdef CONFIG_DYNAMIC_FTRACE
-       br      %r14
-
-ENTRY(ftrace_caller)
-#endif
-       stmg    %r2,%r5,32(%r15)
-       stg     %r14,112(%r15)
-       lgr     %r1,%r15
-       aghi    %r15,-160
-       stg     %r1,__SF_BACKCHAIN(%r15)
-       lgr     %r2,%r14
-       lg      %r3,168(%r15)
-       aghi    %r2,-MCOUNT_INSN_SIZE
-       larl    %r14,ftrace_trace_function
-       lg      %r14,0(%r14)
-       basr    %r14,%r14
-#ifdef CONFIG_FUNCTION_GRAPH_TRACER
-       lg      %r2,168(%r15)
-       lg      %r3,272(%r15)
-ENTRY(ftrace_graph_caller)
-# The bras instruction gets runtime patched to call prepare_ftrace_return.
-# See ftrace_enable_ftrace_graph_caller. The patched instruction is:
-#      bras    %r14,prepare_ftrace_return
-       bras    %r14,0f
-0:     stg     %r2,168(%r15)
-#endif
-       aghi    %r15,160
-       lmg     %r2,%r5,32(%r15)
-       lg      %r14,112(%r15)
-       br      %r14
-
-#ifdef CONFIG_FUNCTION_GRAPH_TRACER
-
-ENTRY(return_to_handler)
-       stmg    %r2,%r5,32(%r15)
-       lgr     %r1,%r15
-       aghi    %r15,-160
-       stg     %r1,__SF_BACKCHAIN(%r15)
-       brasl   %r14,ftrace_return_to_handler
-       aghi    %r15,160
-       lgr     %r14,%r2
-       lmg     %r2,%r5,32(%r15)
-       br      %r14
-
-#endif
index 210e1285f75a44e4fb931e527bdf786eeba6c5ee..db96b418160a0260e305e54d73190097e3dce4f0 100644 (file)
@@ -20,6 +20,7 @@
 #include <asm/cputime.h>
 #include <asm/nmi.h>
 #include <asm/crw.h>
+#include <asm/switch_to.h>
 
 struct mcck_struct {
        int kill_task;
@@ -163,6 +164,21 @@ static int notrace s390_revalidate_registers(struct mci *mci)
                        "       ld      15,120(%0)\n"
                        : : "a" (fpt_save_area));
        }
+
+#ifdef CONFIG_64BIT
+       /* Revalidate vector registers */
+       if (MACHINE_HAS_VX && current->thread.vxrs) {
+               if (!mci->vr) {
+                       /*
+                        * Vector registers can't be restored and therefore
+                        * the process needs to be terminated.
+                        */
+                       kill_task = 1;
+               }
+               restore_vx_regs((__vector128 *)
+                               S390_lowcore.vector_save_area_addr);
+       }
+#endif
        /* Revalidate access registers */
        asm volatile(
                "       lam     0,15,0(%0)"
index 813ec7260878662d097ba90ef04d90b6f183367d..f6f8886399f64e1ebcf7a6a2662451286ecc1ec1 100644 (file)
@@ -49,7 +49,7 @@ PGM_CHECK_DEFAULT                     /* 17 */
 PGM_CHECK_64BIT(transaction_exception) /* 18 */
 PGM_CHECK_DEFAULT                      /* 19 */
 PGM_CHECK_DEFAULT                      /* 1a */
-PGM_CHECK_DEFAULT                      /* 1b */
+PGM_CHECK_64BIT(vector_exception)      /* 1b */
 PGM_CHECK(space_switch_exception)      /* 1c */
 PGM_CHECK(hfp_sqrt_exception)          /* 1d */
 PGM_CHECK_DEFAULT                      /* 1e */
index 93b9ca42e5c0ace2ac209789befa3242850b0043..ed84cc224899ff76ca30e5755d7cf7f2a734d981 100644 (file)
@@ -61,30 +61,6 @@ unsigned long thread_saved_pc(struct task_struct *tsk)
        return sf->gprs[8];
 }
 
-void arch_cpu_idle(void)
-{
-       local_mcck_disable();
-       if (test_cpu_flag(CIF_MCCK_PENDING)) {
-               local_mcck_enable();
-               local_irq_enable();
-               return;
-       }
-       /* Halt the cpu and keep track of cpu time accounting. */
-       vtime_stop_cpu();
-       local_irq_enable();
-}
-
-void arch_cpu_idle_exit(void)
-{
-       if (test_cpu_flag(CIF_MCCK_PENDING))
-               s390_handle_mcck();
-}
-
-void arch_cpu_idle_dead(void)
-{
-       cpu_die();
-}
-
 extern void __kprobes kernel_thread_starter(void);
 
 /*
index 24612029f4502064b64c53ba52426c52a9337adc..edefead3b43a55dee5e197fae4a68011a1c3c41c 100644 (file)
@@ -23,7 +23,6 @@ static DEFINE_PER_CPU(struct cpuid, cpu_id);
  */
 void cpu_init(void)
 {
-       struct s390_idle_data *idle = &__get_cpu_var(s390_idle);
        struct cpuid *id = &__get_cpu_var(cpu_id);
 
        get_cpu_id(id);
@@ -31,7 +30,6 @@ void cpu_init(void)
        current->active_mm = &init_mm;
        BUG_ON(current->mm);
        enter_lazy_tlb(&init_mm, current);
-       memset(idle, 0, sizeof(*idle));
 }
 
 /*
@@ -41,7 +39,7 @@ static int show_cpuinfo(struct seq_file *m, void *v)
 {
        static const char *hwcap_str[] = {
                "esan3", "zarch", "stfle", "msa", "ldisp", "eimm", "dfp",
-               "edat", "etf3eh", "highgprs", "te"
+               "edat", "etf3eh", "highgprs", "te", "vx"
        };
        unsigned long n = (unsigned long) v - 1;
        int i;
index 5dc7ad9e2fbf2d1b035194b30db18a82957c1358..f537e937a9882f74f61a4830651bbd1abd4ddc66 100644 (file)
 #define CREATE_TRACE_POINTS
 #include <trace/events/syscalls.h>
 
-enum s390_regset {
-       REGSET_GENERAL,
-       REGSET_FP,
-       REGSET_LAST_BREAK,
-       REGSET_TDB,
-       REGSET_SYSTEM_CALL,
-       REGSET_GENERAL_EXTENDED,
-};
-
 void update_cr_regs(struct task_struct *task)
 {
        struct pt_regs *regs = task_pt_regs(task);
@@ -55,27 +46,39 @@ void update_cr_regs(struct task_struct *task)
 
 #ifdef CONFIG_64BIT
        /* Take care of the enable/disable of transactional execution. */
-       if (MACHINE_HAS_TE) {
+       if (MACHINE_HAS_TE || MACHINE_HAS_VX) {
                unsigned long cr, cr_new;
 
                __ctl_store(cr, 0, 0);
-               /* Set or clear transaction execution TXC bit 8. */
-               cr_new = cr | (1UL << 55);
-               if (task->thread.per_flags & PER_FLAG_NO_TE)
-                       cr_new &= ~(1UL << 55);
+               cr_new = cr;
+               if (MACHINE_HAS_TE) {
+                       /* Set or clear transaction execution TXC bit 8. */
+                       cr_new |= (1UL << 55);
+                       if (task->thread.per_flags & PER_FLAG_NO_TE)
+                               cr_new &= ~(1UL << 55);
+               }
+               if (MACHINE_HAS_VX) {
+                       /* Enable/disable of vector extension */
+                       cr_new &= ~(1UL << 17);
+                       if (task->thread.vxrs)
+                               cr_new |= (1UL << 17);
+               }
                if (cr_new != cr)
                        __ctl_load(cr_new, 0, 0);
-               /* Set or clear transaction execution TDC bits 62 and 63. */
-               __ctl_store(cr, 2, 2);
-               cr_new = cr & ~3UL;
-               if (task->thread.per_flags & PER_FLAG_TE_ABORT_RAND) {
-                       if (task->thread.per_flags & PER_FLAG_TE_ABORT_RAND_TEND)
-                               cr_new |= 1UL;
-                       else
-                               cr_new |= 2UL;
+               if (MACHINE_HAS_TE) {
+                       /* Set/clear transaction execution TDC bits 62/63. */
+                       __ctl_store(cr, 2, 2);
+                       cr_new = cr & ~3UL;
+                       if (task->thread.per_flags & PER_FLAG_TE_ABORT_RAND) {
+                               if (task->thread.per_flags &
+                                   PER_FLAG_TE_ABORT_RAND_TEND)
+                                       cr_new |= 1UL;
+                               else
+                                       cr_new |= 2UL;
+                       }
+                       if (cr_new != cr)
+                               __ctl_load(cr_new, 2, 2);
                }
-               if (cr_new != cr)
-                       __ctl_load(cr_new, 2, 2);
        }
 #endif
        /* Copy user specified PER registers */
@@ -84,7 +87,8 @@ void update_cr_regs(struct task_struct *task)
        new.end = thread->per_user.end;
 
        /* merge TIF_SINGLE_STEP into user specified PER registers. */
-       if (test_tsk_thread_flag(task, TIF_SINGLE_STEP)) {
+       if (test_tsk_thread_flag(task, TIF_SINGLE_STEP) ||
+           test_tsk_thread_flag(task, TIF_UPROBE_SINGLESTEP)) {
                if (test_tsk_thread_flag(task, TIF_BLOCK_STEP))
                        new.control |= PER_EVENT_BRANCH;
                else
@@ -93,6 +97,8 @@ void update_cr_regs(struct task_struct *task)
                new.control |= PER_CONTROL_SUSPENSION;
                new.control |= PER_EVENT_TRANSACTION_END;
 #endif
+               if (test_tsk_thread_flag(task, TIF_UPROBE_SINGLESTEP))
+                       new.control |= PER_EVENT_IFETCH;
                new.start = 0;
                new.end = PSW_ADDR_INSN;
        }
@@ -803,7 +809,7 @@ asmlinkage long do_syscall_trace_enter(struct pt_regs *regs)
        long ret = 0;
 
        /* Do the secure computing check first. */
-       if (secure_computing(regs->gprs[2])) {
+       if (secure_computing()) {
                /* seccomp failures shouldn't expose any additional code. */
                ret = -1;
                goto out;
@@ -923,7 +929,15 @@ static int s390_fpregs_get(struct task_struct *target,
                save_fp_ctl(&target->thread.fp_regs.fpc);
                save_fp_regs(target->thread.fp_regs.fprs);
        }
+#ifdef CONFIG_64BIT
+       else if (target->thread.vxrs) {
+               int i;
 
+               for (i = 0; i < __NUM_VXRS_LOW; i++)
+                       target->thread.fp_regs.fprs[i] =
+                               *(freg_t *)(target->thread.vxrs + i);
+       }
+#endif
        return user_regset_copyout(&pos, &count, &kbuf, &ubuf,
                                   &target->thread.fp_regs, 0, -1);
 }
@@ -957,9 +971,20 @@ static int s390_fpregs_set(struct task_struct *target,
                                        target->thread.fp_regs.fprs,
                                        offsetof(s390_fp_regs, fprs), -1);
 
-       if (rc == 0 && target == current) {
-               restore_fp_ctl(&target->thread.fp_regs.fpc);
-               restore_fp_regs(target->thread.fp_regs.fprs);
+       if (rc == 0) {
+               if (target == current) {
+                       restore_fp_ctl(&target->thread.fp_regs.fpc);
+                       restore_fp_regs(target->thread.fp_regs.fprs);
+               }
+#ifdef CONFIG_64BIT
+               else if (target->thread.vxrs) {
+                       int i;
+
+                       for (i = 0; i < __NUM_VXRS_LOW; i++)
+                               *(freg_t *)(target->thread.vxrs + i) =
+                                       target->thread.fp_regs.fprs[i];
+               }
+#endif
        }
 
        return rc;
@@ -1015,6 +1040,95 @@ static int s390_tdb_set(struct task_struct *target,
        return 0;
 }
 
+static int s390_vxrs_active(struct task_struct *target,
+                             const struct user_regset *regset)
+{
+       return !!target->thread.vxrs;
+}
+
+static int s390_vxrs_low_get(struct task_struct *target,
+                            const struct user_regset *regset,
+                            unsigned int pos, unsigned int count,
+                            void *kbuf, void __user *ubuf)
+{
+       __u64 vxrs[__NUM_VXRS_LOW];
+       int i;
+
+       if (target->thread.vxrs) {
+               if (target == current)
+                       save_vx_regs(target->thread.vxrs);
+               for (i = 0; i < __NUM_VXRS_LOW; i++)
+                       vxrs[i] = *((__u64 *)(target->thread.vxrs + i) + 1);
+       } else
+               memset(vxrs, 0, sizeof(vxrs));
+       return user_regset_copyout(&pos, &count, &kbuf, &ubuf, vxrs, 0, -1);
+}
+
+static int s390_vxrs_low_set(struct task_struct *target,
+                            const struct user_regset *regset,
+                            unsigned int pos, unsigned int count,
+                            const void *kbuf, const void __user *ubuf)
+{
+       __u64 vxrs[__NUM_VXRS_LOW];
+       int i, rc;
+
+       if (!target->thread.vxrs) {
+               rc = alloc_vector_registers(target);
+               if (rc)
+                       return rc;
+       } else if (target == current)
+               save_vx_regs(target->thread.vxrs);
+
+       rc = user_regset_copyin(&pos, &count, &kbuf, &ubuf, vxrs, 0, -1);
+       if (rc == 0) {
+               for (i = 0; i < __NUM_VXRS_LOW; i++)
+                       *((__u64 *)(target->thread.vxrs + i) + 1) = vxrs[i];
+               if (target == current)
+                       restore_vx_regs(target->thread.vxrs);
+       }
+
+       return rc;
+}
+
+static int s390_vxrs_high_get(struct task_struct *target,
+                             const struct user_regset *regset,
+                             unsigned int pos, unsigned int count,
+                             void *kbuf, void __user *ubuf)
+{
+       __vector128 vxrs[__NUM_VXRS_HIGH];
+
+       if (target->thread.vxrs) {
+               if (target == current)
+                       save_vx_regs(target->thread.vxrs);
+               memcpy(vxrs, target->thread.vxrs + __NUM_VXRS_LOW,
+                      sizeof(vxrs));
+       } else
+               memset(vxrs, 0, sizeof(vxrs));
+       return user_regset_copyout(&pos, &count, &kbuf, &ubuf, vxrs, 0, -1);
+}
+
+static int s390_vxrs_high_set(struct task_struct *target,
+                             const struct user_regset *regset,
+                             unsigned int pos, unsigned int count,
+                             const void *kbuf, const void __user *ubuf)
+{
+       int rc;
+
+       if (!target->thread.vxrs) {
+               rc = alloc_vector_registers(target);
+               if (rc)
+                       return rc;
+       } else if (target == current)
+               save_vx_regs(target->thread.vxrs);
+
+       rc = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
+                               target->thread.vxrs + __NUM_VXRS_LOW, 0, -1);
+       if (rc == 0 && target == current)
+               restore_vx_regs(target->thread.vxrs);
+
+       return rc;
+}
+
 #endif
 
 static int s390_system_call_get(struct task_struct *target,
@@ -1038,7 +1152,7 @@ static int s390_system_call_set(struct task_struct *target,
 }
 
 static const struct user_regset s390_regsets[] = {
-       [REGSET_GENERAL] = {
+       {
                .core_note_type = NT_PRSTATUS,
                .n = sizeof(s390_regs) / sizeof(long),
                .size = sizeof(long),
@@ -1046,7 +1160,7 @@ static const struct user_regset s390_regsets[] = {
                .get = s390_regs_get,
                .set = s390_regs_set,
        },
-       [REGSET_FP] = {
+       {
                .core_note_type = NT_PRFPREG,
                .n = sizeof(s390_fp_regs) / sizeof(long),
                .size = sizeof(long),
@@ -1054,8 +1168,16 @@ static const struct user_regset s390_regsets[] = {
                .get = s390_fpregs_get,
                .set = s390_fpregs_set,
        },
+       {
+               .core_note_type = NT_S390_SYSTEM_CALL,
+               .n = 1,
+               .size = sizeof(unsigned int),
+               .align = sizeof(unsigned int),
+               .get = s390_system_call_get,
+               .set = s390_system_call_set,
+       },
 #ifdef CONFIG_64BIT
-       [REGSET_LAST_BREAK] = {
+       {
                .core_note_type = NT_S390_LAST_BREAK,
                .n = 1,
                .size = sizeof(long),
@@ -1063,7 +1185,7 @@ static const struct user_regset s390_regsets[] = {
                .get = s390_last_break_get,
                .set = s390_last_break_set,
        },
-       [REGSET_TDB] = {
+       {
                .core_note_type = NT_S390_TDB,
                .n = 1,
                .size = 256,
@@ -1071,15 +1193,25 @@ static const struct user_regset s390_regsets[] = {
                .get = s390_tdb_get,
                .set = s390_tdb_set,
        },
-#endif
-       [REGSET_SYSTEM_CALL] = {
-               .core_note_type = NT_S390_SYSTEM_CALL,
-               .n = 1,
-               .size = sizeof(unsigned int),
-               .align = sizeof(unsigned int),
-               .get = s390_system_call_get,
-               .set = s390_system_call_set,
+       {
+               .core_note_type = NT_S390_VXRS_LOW,
+               .n = __NUM_VXRS_LOW,
+               .size = sizeof(__u64),
+               .align = sizeof(__u64),
+               .active = s390_vxrs_active,
+               .get = s390_vxrs_low_get,
+               .set = s390_vxrs_low_set,
        },
+       {
+               .core_note_type = NT_S390_VXRS_HIGH,
+               .n = __NUM_VXRS_HIGH,
+               .size = sizeof(__vector128),
+               .align = sizeof(__vector128),
+               .active = s390_vxrs_active,
+               .get = s390_vxrs_high_get,
+               .set = s390_vxrs_high_set,
+       },
+#endif
 };
 
 static const struct user_regset_view user_s390_view = {
@@ -1244,7 +1376,7 @@ static int s390_compat_last_break_set(struct task_struct *target,
 }
 
 static const struct user_regset s390_compat_regsets[] = {
-       [REGSET_GENERAL] = {
+       {
                .core_note_type = NT_PRSTATUS,
                .n = sizeof(s390_compat_regs) / sizeof(compat_long_t),
                .size = sizeof(compat_long_t),
@@ -1252,7 +1384,7 @@ static const struct user_regset s390_compat_regsets[] = {
                .get = s390_compat_regs_get,
                .set = s390_compat_regs_set,
        },
-       [REGSET_FP] = {
+       {
                .core_note_type = NT_PRFPREG,
                .n = sizeof(s390_fp_regs) / sizeof(compat_long_t),
                .size = sizeof(compat_long_t),
@@ -1260,7 +1392,15 @@ static const struct user_regset s390_compat_regsets[] = {
                .get = s390_fpregs_get,
                .set = s390_fpregs_set,
        },
-       [REGSET_LAST_BREAK] = {
+       {
+               .core_note_type = NT_S390_SYSTEM_CALL,
+               .n = 1,
+               .size = sizeof(compat_uint_t),
+               .align = sizeof(compat_uint_t),
+               .get = s390_system_call_get,
+               .set = s390_system_call_set,
+       },
+       {
                .core_note_type = NT_S390_LAST_BREAK,
                .n = 1,
                .size = sizeof(long),
@@ -1268,7 +1408,7 @@ static const struct user_regset s390_compat_regsets[] = {
                .get = s390_compat_last_break_get,
                .set = s390_compat_last_break_set,
        },
-       [REGSET_TDB] = {
+       {
                .core_note_type = NT_S390_TDB,
                .n = 1,
                .size = 256,
@@ -1276,15 +1416,25 @@ static const struct user_regset s390_compat_regsets[] = {
                .get = s390_tdb_get,
                .set = s390_tdb_set,
        },
-       [REGSET_SYSTEM_CALL] = {
-               .core_note_type = NT_S390_SYSTEM_CALL,
-               .n = 1,
-               .size = sizeof(compat_uint_t),
-               .align = sizeof(compat_uint_t),
-               .get = s390_system_call_get,
-               .set = s390_system_call_set,
+       {
+               .core_note_type = NT_S390_VXRS_LOW,
+               .n = __NUM_VXRS_LOW,
+               .size = sizeof(__u64),
+               .align = sizeof(__u64),
+               .active = s390_vxrs_active,
+               .get = s390_vxrs_low_get,
+               .set = s390_vxrs_low_set,
+       },
+       {
+               .core_note_type = NT_S390_VXRS_HIGH,
+               .n = __NUM_VXRS_HIGH,
+               .size = sizeof(__vector128),
+               .align = sizeof(__vector128),
+               .active = s390_vxrs_active,
+               .get = s390_vxrs_high_get,
+               .set = s390_vxrs_high_set,
        },
-       [REGSET_GENERAL_EXTENDED] = {
+       {
                .core_note_type = NT_S390_HIGH_GPRS,
                .n = sizeof(s390_compat_regs_high) / sizeof(compat_long_t),
                .size = sizeof(compat_long_t),
index 82bc113e8c1dd3718cf663a88d7bc9a2c9c97fb4..e80d9ff9a56d41b15055e3270234c4683f7f7d91 100644 (file)
@@ -343,6 +343,9 @@ static void __init setup_lowcore(void)
                __ctl_set_bit(14, 29);
        }
 #else
+       if (MACHINE_HAS_VX)
+               lc->vector_save_area_addr =
+                       (unsigned long) &lc->vector_save_area;
        lc->vdso_per_cpu_data = (unsigned long) &lc->paste[0];
 #endif
        lc->sync_enter_timer = S390_lowcore.sync_enter_timer;
@@ -452,8 +455,8 @@ static void __init setup_memory_end(void)
 #ifdef CONFIG_64BIT
        vmalloc_size = VMALLOC_END ?: (128UL << 30) - MODULES_LEN;
        tmp = (memory_end ?: max_physmem_end) / PAGE_SIZE;
-       tmp = tmp * (sizeof(struct page) + PAGE_SIZE) + vmalloc_size;
-       if (tmp <= (1UL << 42))
+       tmp = tmp * (sizeof(struct page) + PAGE_SIZE);
+       if (tmp + vmalloc_size + MODULES_LEN <= (1UL << 42))
                vmax = 1UL << 42;       /* 3-level kernel page table */
        else
                vmax = 1UL << 53;       /* 4-level kernel page table */
@@ -765,6 +768,12 @@ static void __init setup_hwcaps(void)
         */
        if (test_facility(50) && test_facility(73))
                elf_hwcap |= HWCAP_S390_TE;
+
+       /*
+        * Vector extension HWCAP_S390_VXRS is bit 11.
+        */
+       if (test_facility(129))
+               elf_hwcap |= HWCAP_S390_VXRS;
 #endif
 
        get_cpu_id(&cpu_id);
index 469c4c6d91822f32c2512551d6c8c29026ff8462..0c1a0ff0a558bda9a389091f86628fb8b0f825bc 100644 (file)
 #include <asm/switch_to.h>
 #include "entry.h"
 
-typedef struct 
+/*
+ * Layout of an old-style signal-frame:
+ *     -----------------------------------------
+ *     | save area (_SIGNAL_FRAMESIZE)         |
+ *     -----------------------------------------
+ *     | struct sigcontext                     |
+ *     |       oldmask                         |
+ *     |       _sigregs *                      |
+ *     -----------------------------------------
+ *     | _sigregs with                         |
+ *     |       _s390_regs_common               |
+ *     |       _s390_fp_regs                   |
+ *     -----------------------------------------
+ *     | int signo                             |
+ *     -----------------------------------------
+ *     | _sigregs_ext with                     |
+ *     |       gprs_high 64 byte (opt)         |
+ *     |       vxrs_low 128 byte (opt)         |
+ *     |       vxrs_high 256 byte (opt)        |
+ *     |       reserved 128 byte (opt)         |
+ *     -----------------------------------------
+ *     | __u16 svc_insn                        |
+ *     -----------------------------------------
+ * The svc_insn entry with the sigreturn system call opcode does not
+ * have a fixed position and moves if gprs_high or vxrs exist.
+ * Future extensions will be added to _sigregs_ext.
+ */
+struct sigframe
 {
        __u8 callee_used_stack[__SIGNAL_FRAMESIZE];
        struct sigcontext sc;
        _sigregs sregs;
        int signo;
-       __u8 retcode[S390_SYSCALL_SIZE];
-} sigframe;
+       _sigregs_ext sregs_ext;
+       __u16 svc_insn;         /* Offset of svc_insn is NOT fixed! */
+};
 
-typedef struct 
+/*
+ * Layout of an rt signal-frame:
+ *     -----------------------------------------
+ *     | save area (_SIGNAL_FRAMESIZE)         |
+ *     -----------------------------------------
+ *     | svc __NR_rt_sigreturn 2 byte          |
+ *     -----------------------------------------
+ *     | struct siginfo                        |
+ *     -----------------------------------------
+ *     | struct ucontext_extended with         |
+ *     |       unsigned long uc_flags          |
+ *     |       struct ucontext *uc_link        |
+ *     |       stack_t uc_stack                |
+ *     |       _sigregs uc_mcontext with       |
+ *     |               _s390_regs_common       |
+ *     |               _s390_fp_regs           |
+ *     |       sigset_t uc_sigmask             |
+ *     |       _sigregs_ext uc_mcontext_ext    |
+ *     |               gprs_high 64 byte (opt) |
+ *     |               vxrs_low 128 byte (opt) |
+ *     |               vxrs_high 256 byte (opt)|
+ *     |               reserved 128 byte (opt) |
+ *     -----------------------------------------
+ * Future extensions will be added to _sigregs_ext.
+ */
+struct rt_sigframe
 {
        __u8 callee_used_stack[__SIGNAL_FRAMESIZE];
-       __u8 retcode[S390_SYSCALL_SIZE];
+       __u16 svc_insn;
        struct siginfo info;
-       struct ucontext uc;
-} rt_sigframe;
+       struct ucontext_extended uc;
+};
+
+/* Store registers needed to create the signal frame */
+static void store_sigregs(void)
+{
+       save_access_regs(current->thread.acrs);
+       save_fp_ctl(&current->thread.fp_regs.fpc);
+#ifdef CONFIG_64BIT
+       if (current->thread.vxrs) {
+               int i;
+
+               save_vx_regs(current->thread.vxrs);
+               for (i = 0; i < __NUM_FPRS; i++)
+                       current->thread.fp_regs.fprs[i] =
+                               *(freg_t *)(current->thread.vxrs + i);
+       } else
+#endif
+               save_fp_regs(current->thread.fp_regs.fprs);
+}
+
+/* Load registers after signal return */
+static void load_sigregs(void)
+{
+       restore_access_regs(current->thread.acrs);
+       /* restore_fp_ctl is done in restore_sigregs */
+#ifdef CONFIG_64BIT
+       if (current->thread.vxrs) {
+               int i;
+
+               for (i = 0; i < __NUM_FPRS; i++)
+                       *(freg_t *)(current->thread.vxrs + i) =
+                               current->thread.fp_regs.fprs[i];
+               restore_vx_regs(current->thread.vxrs);
+       } else
+#endif
+               restore_fp_regs(current->thread.fp_regs.fprs);
+}
 
 /* Returns non-zero on fault. */
 static int save_sigregs(struct pt_regs *regs, _sigregs __user *sregs)
 {
        _sigregs user_sregs;
 
-       save_access_regs(current->thread.acrs);
-
        /* Copy a 'clean' PSW mask to the user to avoid leaking
           information about whether PER is currently on.  */
        user_sregs.regs.psw.mask = PSW_USER_BITS |
@@ -63,12 +150,6 @@ static int save_sigregs(struct pt_regs *regs, _sigregs __user *sregs)
        memcpy(&user_sregs.regs.gprs, &regs->gprs, sizeof(sregs->regs.gprs));
        memcpy(&user_sregs.regs.acrs, current->thread.acrs,
               sizeof(user_sregs.regs.acrs));
-       /* 
-        * We have to store the fp registers to current->thread.fp_regs
-        * to merge them with the emulated registers.
-        */
-       save_fp_ctl(&current->thread.fp_regs.fpc);
-       save_fp_regs(current->thread.fp_regs.fprs);
        memcpy(&user_sregs.fpregs, &current->thread.fp_regs,
               sizeof(user_sregs.fpregs));
        if (__copy_to_user(sregs, &user_sregs, sizeof(_sigregs)))
@@ -107,20 +188,64 @@ static int restore_sigregs(struct pt_regs *regs, _sigregs __user *sregs)
        memcpy(&regs->gprs, &user_sregs.regs.gprs, sizeof(sregs->regs.gprs));
        memcpy(&current->thread.acrs, &user_sregs.regs.acrs,
               sizeof(current->thread.acrs));
-       restore_access_regs(current->thread.acrs);
 
        memcpy(&current->thread.fp_regs, &user_sregs.fpregs,
               sizeof(current->thread.fp_regs));
 
-       restore_fp_regs(current->thread.fp_regs.fprs);
        clear_pt_regs_flag(regs, PIF_SYSCALL); /* No longer in a system call */
        return 0;
 }
 
+/* Returns non-zero on fault. */
+static int save_sigregs_ext(struct pt_regs *regs,
+                           _sigregs_ext __user *sregs_ext)
+{
+#ifdef CONFIG_64BIT
+       __u64 vxrs[__NUM_VXRS_LOW];
+       int i;
+
+       /* Save vector registers to signal stack */
+       if (current->thread.vxrs) {
+               for (i = 0; i < __NUM_VXRS_LOW; i++)
+                       vxrs[i] = *((__u64 *)(current->thread.vxrs + i) + 1);
+               if (__copy_to_user(&sregs_ext->vxrs_low, vxrs,
+                                  sizeof(sregs_ext->vxrs_low)) ||
+                   __copy_to_user(&sregs_ext->vxrs_high,
+                                  current->thread.vxrs + __NUM_VXRS_LOW,
+                                  sizeof(sregs_ext->vxrs_high)))
+                       return -EFAULT;
+       }
+#endif
+       return 0;
+}
+
+static int restore_sigregs_ext(struct pt_regs *regs,
+                              _sigregs_ext __user *sregs_ext)
+{
+#ifdef CONFIG_64BIT
+       __u64 vxrs[__NUM_VXRS_LOW];
+       int i;
+
+       /* Restore vector registers from signal stack */
+       if (current->thread.vxrs) {
+               if (__copy_from_user(vxrs, &sregs_ext->vxrs_low,
+                                    sizeof(sregs_ext->vxrs_low)) ||
+                   __copy_from_user(current->thread.vxrs + __NUM_VXRS_LOW,
+                                    &sregs_ext->vxrs_high,
+                                    sizeof(sregs_ext->vxrs_high)))
+                       return -EFAULT;
+               for (i = 0; i < __NUM_VXRS_LOW; i++)
+                       *((__u64 *)(current->thread.vxrs + i) + 1) = vxrs[i];
+       }
+#endif
+       return 0;
+}
+
 SYSCALL_DEFINE0(sigreturn)
 {
        struct pt_regs *regs = task_pt_regs(current);
-       sigframe __user *frame = (sigframe __user *)regs->gprs[15];
+       struct sigframe __user *frame =
+               (struct sigframe __user *) regs->gprs[15];
        sigset_t set;
 
        if (__copy_from_user(&set.sig, &frame->sc.oldmask, _SIGMASK_COPY_SIZE))
@@ -128,6 +253,9 @@ SYSCALL_DEFINE0(sigreturn)
        set_current_blocked(&set);
        if (restore_sigregs(regs, &frame->sregs))
                goto badframe;
+       if (restore_sigregs_ext(regs, &frame->sregs_ext))
+               goto badframe;
+       load_sigregs();
        return regs->gprs[2];
 badframe:
        force_sig(SIGSEGV, current);
@@ -137,27 +265,26 @@ badframe:
 SYSCALL_DEFINE0(rt_sigreturn)
 {
        struct pt_regs *regs = task_pt_regs(current);
-       rt_sigframe __user *frame = (rt_sigframe __user *)regs->gprs[15];
+       struct rt_sigframe __user *frame =
+               (struct rt_sigframe __user *)regs->gprs[15];
        sigset_t set;
 
        if (__copy_from_user(&set.sig, &frame->uc.uc_sigmask, sizeof(set)))
                goto badframe;
        set_current_blocked(&set);
+       if (restore_altstack(&frame->uc.uc_stack))
+               goto badframe;
        if (restore_sigregs(regs, &frame->uc.uc_mcontext))
                goto badframe;
-       if (restore_altstack(&frame->uc.uc_stack))
+       if (restore_sigregs_ext(regs, &frame->uc.uc_mcontext_ext))
                goto badframe;
+       load_sigregs();
        return regs->gprs[2];
 badframe:
        force_sig(SIGSEGV, current);
        return 0;
 }
 
-/*
- * Set up a signal frame.
- */
-
-
 /*
  * Determine which stack to use..
  */
@@ -195,39 +322,63 @@ static inline int map_signal(int sig)
 static int setup_frame(int sig, struct k_sigaction *ka,
                       sigset_t *set, struct pt_regs * regs)
 {
-       sigframe __user *frame;
-
-       frame = get_sigframe(ka, regs, sizeof(sigframe));
+       struct sigframe __user *frame;
+       struct sigcontext sc;
+       unsigned long restorer;
+       size_t frame_size;
 
+       /*
+        * gprs_high are only present for a 31-bit task running on
+        * a 64-bit kernel (see compat_signal.c) but the space for
+        * gprs_high need to be allocated if vector registers are
+        * included in the signal frame on a 31-bit system.
+        */
+       frame_size = sizeof(*frame) - sizeof(frame->sregs_ext);
+       if (MACHINE_HAS_VX)
+               frame_size += sizeof(frame->sregs_ext);
+       frame = get_sigframe(ka, regs, frame_size);
        if (frame == (void __user *) -1UL)
                return -EFAULT;
 
-       if (__copy_to_user(&frame->sc.oldmask, &set->sig, _SIGMASK_COPY_SIZE))
+       /* Set up backchain. */
+       if (__put_user(regs->gprs[15], (addr_t __user *) frame))
                return -EFAULT;
 
+       /* Create struct sigcontext on the signal stack */
+       memcpy(&sc.oldmask, &set->sig, _SIGMASK_COPY_SIZE);
+       sc.sregs = (_sigregs __user __force *) &frame->sregs;
+       if (__copy_to_user(&frame->sc, &sc, sizeof(frame->sc)))
+               return -EFAULT;
+
+       /* Store registers needed to create the signal frame */
+       store_sigregs();
+
+       /* Create _sigregs on the signal stack */
        if (save_sigregs(regs, &frame->sregs))
                return -EFAULT;
-       if (__put_user(&frame->sregs, &frame->sc.sregs))
+
+       /* Place signal number on stack to allow backtrace from handler.  */
+       if (__put_user(regs->gprs[2], (int __user *) &frame->signo))
+               return -EFAULT;
+
+       /* Create _sigregs_ext on the signal stack */
+       if (save_sigregs_ext(regs, &frame->sregs_ext))
                return -EFAULT;
 
        /* Set up to return from userspace.  If provided, use a stub
           already in userspace.  */
        if (ka->sa.sa_flags & SA_RESTORER) {
-                regs->gprs[14] = (unsigned long)
-                       ka->sa.sa_restorer | PSW_ADDR_AMODE;
+               restorer = (unsigned long) ka->sa.sa_restorer | PSW_ADDR_AMODE;
        } else {
-                regs->gprs[14] = (unsigned long)
-                       frame->retcode | PSW_ADDR_AMODE;
-               if (__put_user(S390_SYSCALL_OPCODE | __NR_sigreturn,
-                              (u16 __user *)(frame->retcode)))
+               /* Signal frame without vector registers are short ! */
+               __u16 __user *svc = (void *) frame + frame_size - 2;
+               if (__put_user(S390_SYSCALL_OPCODE | __NR_sigreturn, svc))
                        return -EFAULT;
+               restorer = (unsigned long) svc | PSW_ADDR_AMODE;
        }
 
-       /* Set up backchain. */
-       if (__put_user(regs->gprs[15], (addr_t __user *) frame))
-               return -EFAULT;
-
        /* Set up registers for signal handler */
+       regs->gprs[14] = restorer;
        regs->gprs[15] = (unsigned long) frame;
        /* Force default amode and default user address space control. */
        regs->psw.mask = PSW_MASK_EA | PSW_MASK_BA |
@@ -247,54 +398,69 @@ static int setup_frame(int sig, struct k_sigaction *ka,
                regs->gprs[5] = regs->int_parm_long;
                regs->gprs[6] = task_thread_info(current)->last_break;
        }
-
-       /* Place signal number on stack to allow backtrace from handler.  */
-       if (__put_user(regs->gprs[2], (int __user *) &frame->signo))
-               return -EFAULT;
        return 0;
 }
 
 static int setup_rt_frame(struct ksignal *ksig, sigset_t *set,
                          struct pt_regs *regs)
 {
-       int err = 0;
-       rt_sigframe __user *frame;
-
-       frame = get_sigframe(&ksig->ka, regs, sizeof(rt_sigframe));
+       struct rt_sigframe __user *frame;
+       unsigned long uc_flags, restorer;
+       size_t frame_size;
 
+       frame_size = sizeof(struct rt_sigframe) - sizeof(_sigregs_ext);
+       /*
+        * gprs_high are only present for a 31-bit task running on
+        * a 64-bit kernel (see compat_signal.c) but the space for
+        * gprs_high need to be allocated if vector registers are
+        * included in the signal frame on a 31-bit system.
+        */
+       uc_flags = 0;
+#ifdef CONFIG_64BIT
+       if (MACHINE_HAS_VX) {
+               frame_size += sizeof(_sigregs_ext);
+               if (current->thread.vxrs)
+                       uc_flags |= UC_VXRS;
+       }
+#endif
+       frame = get_sigframe(&ksig->ka, regs, frame_size);
        if (frame == (void __user *) -1UL)
                return -EFAULT;
 
-       if (copy_siginfo_to_user(&frame->info, &ksig->info))
-               return -EFAULT;
-
-       /* Create the ucontext.  */
-       err |= __put_user(0, &frame->uc.uc_flags);
-       err |= __put_user(NULL, &frame->uc.uc_link);
-       err |= __save_altstack(&frame->uc.uc_stack, regs->gprs[15]);
-       err |= save_sigregs(regs, &frame->uc.uc_mcontext);
-       err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
-       if (err)
+       /* Set up backchain. */
+       if (__put_user(regs->gprs[15], (addr_t __user *) frame))
                return -EFAULT;
 
        /* Set up to return from userspace.  If provided, use a stub
           already in userspace.  */
        if (ksig->ka.sa.sa_flags & SA_RESTORER) {
-                regs->gprs[14] = (unsigned long)
+               restorer = (unsigned long)
                        ksig->ka.sa.sa_restorer | PSW_ADDR_AMODE;
        } else {
-                regs->gprs[14] = (unsigned long)
-                       frame->retcode | PSW_ADDR_AMODE;
-               if (__put_user(S390_SYSCALL_OPCODE | __NR_rt_sigreturn,
-                              (u16 __user *)(frame->retcode)))
+               __u16 __user *svc = &frame->svc_insn;
+               if (__put_user(S390_SYSCALL_OPCODE | __NR_rt_sigreturn, svc))
                        return -EFAULT;
+               restorer = (unsigned long) svc | PSW_ADDR_AMODE;
        }
 
-       /* Set up backchain. */
-       if (__put_user(regs->gprs[15], (addr_t __user *) frame))
+       /* Create siginfo on the signal stack */
+       if (copy_siginfo_to_user(&frame->info, &ksig->info))
+               return -EFAULT;
+
+       /* Store registers needed to create the signal frame */
+       store_sigregs();
+
+       /* Create ucontext on the signal stack. */
+       if (__put_user(uc_flags, &frame->uc.uc_flags) ||
+           __put_user(NULL, &frame->uc.uc_link) ||
+           __save_altstack(&frame->uc.uc_stack, regs->gprs[15]) ||
+           save_sigregs(regs, &frame->uc.uc_mcontext) ||
+           __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)) ||
+           save_sigregs_ext(regs, &frame->uc.uc_mcontext_ext))
                return -EFAULT;
 
        /* Set up registers for signal handler */
+       regs->gprs[14] = restorer;
        regs->gprs[15] = (unsigned long) frame;
        /* Force default amode and default user address space control. */
        regs->psw.mask = PSW_MASK_EA | PSW_MASK_BA |
index 243c7e51260055c3de2a57e2852ed82de075f18f..6fd9e60101f1733cc3c84f010657561d4c895985 100644 (file)
@@ -45,6 +45,7 @@
 #include <asm/debug.h>
 #include <asm/os_info.h>
 #include <asm/sigp.h>
+#include <asm/idle.h>
 #include "entry.h"
 
 enum {
@@ -82,7 +83,8 @@ DEFINE_MUTEX(smp_cpu_state_mutex);
 /*
  * Signal processor helper functions.
  */
-static inline int __pcpu_sigp_relax(u16 addr, u8 order, u32 parm, u32 *status)
+static inline int __pcpu_sigp_relax(u16 addr, u8 order, unsigned long parm,
+                                   u32 *status)
 {
        int cc;
 
@@ -178,6 +180,9 @@ static int pcpu_alloc_lowcore(struct pcpu *pcpu, int cpu)
                        goto out;
        }
 #else
+       if (MACHINE_HAS_VX)
+               lc->vector_save_area_addr =
+                       (unsigned long) &lc->vector_save_area;
        if (vdso_alloc_per_cpu(lc))
                goto out;
 #endif
@@ -333,12 +338,6 @@ int smp_vcpu_scheduled(int cpu)
        return pcpu_running(pcpu_devices + cpu);
 }
 
-void smp_yield(void)
-{
-       if (MACHINE_HAS_DIAG44)
-               asm volatile("diag 0,0,0x44");
-}
-
 void smp_yield_cpu(int cpu)
 {
        if (MACHINE_HAS_DIAG9C)
@@ -517,35 +516,53 @@ EXPORT_SYMBOL(smp_ctl_clear_bit);
 static void __init smp_get_save_area(int cpu, u16 address)
 {
        void *lc = pcpu_devices[0].lowcore;
-       struct save_area *save_area;
+       struct save_area_ext *sa_ext;
+       unsigned long vx_sa;
 
        if (is_kdump_kernel())
                return;
        if (!OLDMEM_BASE && (address == boot_cpu_address ||
                             ipl_info.type != IPL_TYPE_FCP_DUMP))
                return;
-       save_area = dump_save_area_create(cpu);
-       if (!save_area)
+       sa_ext = dump_save_area_create(cpu);
+       if (!sa_ext)
                panic("could not allocate memory for save area\n");
        if (address == boot_cpu_address) {
                /* Copy the registers of the boot cpu. */
-               copy_oldmem_page(1, (void *) save_area, sizeof(*save_area),
+               copy_oldmem_page(1, (void *) &sa_ext->sa, sizeof(sa_ext->sa),
                                 SAVE_AREA_BASE - PAGE_SIZE, 0);
+               if (MACHINE_HAS_VX)
+                       save_vx_regs_safe(sa_ext->vx_regs);
                return;
        }
        /* Get the registers of a non-boot cpu. */
        __pcpu_sigp_relax(address, SIGP_STOP_AND_STORE_STATUS, 0, NULL);
-       memcpy_real(save_area, lc + SAVE_AREA_BASE, sizeof(*save_area));
+       memcpy_real(&sa_ext->sa, lc + SAVE_AREA_BASE, sizeof(sa_ext->sa));
+       if (!MACHINE_HAS_VX)
+               return;
+       /* Get the VX registers */
+       vx_sa = __get_free_page(GFP_KERNEL);
+       if (!vx_sa)
+               panic("could not allocate memory for VX save area\n");
+       __pcpu_sigp_relax(address, SIGP_STORE_ADDITIONAL_STATUS, vx_sa, NULL);
+       memcpy(sa_ext->vx_regs, (void *) vx_sa, sizeof(sa_ext->vx_regs));
+       free_page(vx_sa);
 }
 
 int smp_store_status(int cpu)
 {
+       unsigned long vx_sa;
        struct pcpu *pcpu;
 
        pcpu = pcpu_devices + cpu;
        if (__pcpu_sigp_relax(pcpu->address, SIGP_STOP_AND_STORE_STATUS,
                              0, NULL) != SIGP_CC_ORDER_CODE_ACCEPTED)
                return -EIO;
+       if (!MACHINE_HAS_VX)
+               return 0;
+       vx_sa = __pa(pcpu->lowcore->vector_save_area_addr);
+       __pcpu_sigp_relax(pcpu->address, SIGP_STORE_ADDITIONAL_STATUS,
+                         vx_sa, NULL);
        return 0;
 }
 
@@ -667,7 +684,7 @@ static void smp_start_secondary(void *cpuvoid)
        cpu_init();
        preempt_disable();
        init_cpu_timer();
-       init_cpu_vtimer();
+       vtime_init();
        pfault_init();
        notify_cpu_starting(smp_processor_id());
        set_cpu_online(smp_processor_id(), true);
@@ -726,6 +743,7 @@ int __cpu_disable(void)
        cregs[6]  &= ~0xff000000UL;     /* disable all I/O interrupts */
        cregs[14] &= ~0x1f000000UL;     /* disable most machine checks */
        __ctl_load(cregs, 0, 15);
+       clear_cpu_flag(CIF_NOHZ_DELAY);
        return 0;
 }
 
@@ -898,42 +916,6 @@ static struct attribute_group cpu_common_attr_group = {
        .attrs = cpu_common_attrs,
 };
 
-static ssize_t show_idle_count(struct device *dev,
-                               struct device_attribute *attr, char *buf)
-{
-       struct s390_idle_data *idle = &per_cpu(s390_idle, dev->id);
-       unsigned long long idle_count;
-       unsigned int sequence;
-
-       do {
-               sequence = ACCESS_ONCE(idle->sequence);
-               idle_count = ACCESS_ONCE(idle->idle_count);
-               if (ACCESS_ONCE(idle->clock_idle_enter))
-                       idle_count++;
-       } while ((sequence & 1) || (ACCESS_ONCE(idle->sequence) != sequence));
-       return sprintf(buf, "%llu\n", idle_count);
-}
-static DEVICE_ATTR(idle_count, 0444, show_idle_count, NULL);
-
-static ssize_t show_idle_time(struct device *dev,
-                               struct device_attribute *attr, char *buf)
-{
-       struct s390_idle_data *idle = &per_cpu(s390_idle, dev->id);
-       unsigned long long now, idle_time, idle_enter, idle_exit;
-       unsigned int sequence;
-
-       do {
-               now = get_tod_clock();
-               sequence = ACCESS_ONCE(idle->sequence);
-               idle_time = ACCESS_ONCE(idle->idle_time);
-               idle_enter = ACCESS_ONCE(idle->clock_idle_enter);
-               idle_exit = ACCESS_ONCE(idle->clock_idle_exit);
-       } while ((sequence & 1) || (ACCESS_ONCE(idle->sequence) != sequence));
-       idle_time += idle_enter ? ((idle_exit ? : now) - idle_enter) : 0;
-       return sprintf(buf, "%llu\n", idle_time >> 12);
-}
-static DEVICE_ATTR(idle_time_us, 0444, show_idle_time, NULL);
-
 static struct attribute *cpu_online_attrs[] = {
        &dev_attr_idle_count.attr,
        &dev_attr_idle_time_us.attr,
index 4cef607f371122fc2fcc7959bd6f12cff3d3d896..69e980de0f6282310e7978ee398a2a5a0d7184c6 100644 (file)
@@ -232,6 +232,19 @@ void update_vsyscall(struct timekeeper *tk)
                vdso_data->wtom_clock_nsec -= nsecps;
                vdso_data->wtom_clock_sec++;
        }
+
+       vdso_data->xtime_coarse_sec = tk->xtime_sec;
+       vdso_data->xtime_coarse_nsec =
+               (long)(tk->tkr.xtime_nsec >> tk->tkr.shift);
+       vdso_data->wtom_coarse_sec =
+               vdso_data->xtime_coarse_sec + tk->wall_to_monotonic.tv_sec;
+       vdso_data->wtom_coarse_nsec =
+               vdso_data->xtime_coarse_nsec + tk->wall_to_monotonic.tv_nsec;
+       while (vdso_data->wtom_coarse_nsec >= NSEC_PER_SEC) {
+               vdso_data->wtom_coarse_nsec -= NSEC_PER_SEC;
+               vdso_data->wtom_coarse_sec++;
+       }
+
        vdso_data->tk_mult = tk->tkr.mult;
        vdso_data->tk_shift = tk->tkr.shift;
        smp_wmb();
index 355a16c557026a21f50fbb39b51a5f1320b0773a..b93bed76ea94026d45c782eebe75c08dfb1a323d 100644 (file)
@@ -464,15 +464,17 @@ static struct sched_domain_topology_level s390_topology[] = {
 
 static int __init topology_init(void)
 {
-       if (!MACHINE_HAS_TOPOLOGY) {
+       if (MACHINE_HAS_TOPOLOGY)
+               set_topology_timer();
+       else
                topology_update_polarization_simple();
-               goto out;
-       }
-       set_topology_timer();
-out:
-
-       set_sched_topology(s390_topology);
-
        return device_create_file(cpu_subsys.dev_root, &dev_attr_dispatching);
 }
 device_initcall(topology_init);
+
+static int __init early_topology_init(void)
+{
+       set_sched_topology(s390_topology);
+       return 0;
+}
+early_initcall(early_topology_init);
index c5762324d9ee435367314d8fa2f03e32e2365f0e..9ff5ecba26aba803f3d8ad24196f61409bc99e2a 100644 (file)
@@ -18,6 +18,8 @@
 #include <linux/ptrace.h>
 #include <linux/sched.h>
 #include <linux/mm.h>
+#include <linux/slab.h>
+#include <asm/switch_to.h>
 #include "entry.h"
 
 int show_unhandled_signals = 1;
@@ -58,15 +60,10 @@ int is_valid_bugaddr(unsigned long addr)
        return 1;
 }
 
-static void __kprobes do_trap(struct pt_regs *regs,
-                             int si_signo, int si_code, char *str)
+void do_report_trap(struct pt_regs *regs, int si_signo, int si_code, char *str)
 {
        siginfo_t info;
 
-       if (notify_die(DIE_TRAP, str, regs, 0,
-                      regs->int_code, si_signo) == NOTIFY_STOP)
-               return;
-
        if (user_mode(regs)) {
                info.si_signo = si_signo;
                info.si_errno = 0;
@@ -90,6 +87,15 @@ static void __kprobes do_trap(struct pt_regs *regs,
         }
 }
 
+static void __kprobes do_trap(struct pt_regs *regs, int si_signo, int si_code,
+                             char *str)
+{
+       if (notify_die(DIE_TRAP, str, regs, 0,
+                      regs->int_code, si_signo) == NOTIFY_STOP)
+               return;
+       do_report_trap(regs, si_signo, si_code, str);
+}
+
 void __kprobes do_per_trap(struct pt_regs *regs)
 {
        siginfo_t info;
@@ -178,6 +184,7 @@ void __kprobes illegal_op(struct pt_regs *regs)
        siginfo_t info;
         __u8 opcode[6];
        __u16 __user *location;
+       int is_uprobe_insn = 0;
        int signal = 0;
 
        location = get_trap_ip(regs);
@@ -194,6 +201,10 @@ void __kprobes illegal_op(struct pt_regs *regs)
                                force_sig_info(SIGTRAP, &info, current);
                        } else
                                signal = SIGILL;
+#ifdef CONFIG_UPROBES
+               } else if (*((__u16 *) opcode) == UPROBE_SWBP_INSN) {
+                       is_uprobe_insn = 1;
+#endif
 #ifdef CONFIG_MATHEMU
                } else if (opcode[0] == 0xb3) {
                        if (get_user(*((__u16 *) (opcode+2)), location+1))
@@ -219,11 +230,13 @@ void __kprobes illegal_op(struct pt_regs *regs)
 #endif
                } else
                        signal = SIGILL;
-       } else {
-               /*
-                * If we get an illegal op in kernel mode, send it through the
-                * kprobes notifier. If kprobes doesn't pick it up, SIGILL
-                */
+       }
+       /*
+        * We got either an illegal op in kernel mode, or user space trapped
+        * on a uprobes illegal instruction. See if kprobes or uprobes picks
+        * it up. If not, SIGILL.
+        */
+       if (is_uprobe_insn || !user_mode(regs)) {
                if (notify_die(DIE_BPT, "bpt", regs, 0,
                               3, SIGTRAP) != NOTIFY_STOP)
                        signal = SIGILL;
@@ -292,6 +305,74 @@ DO_ERROR_INFO(specification_exception, SIGILL, ILL_ILLOPN,
              "specification exception");
 #endif
 
+#ifdef CONFIG_64BIT
+int alloc_vector_registers(struct task_struct *tsk)
+{
+       __vector128 *vxrs;
+       int i;
+
+       /* Allocate vector register save area. */
+       vxrs = kzalloc(sizeof(__vector128) * __NUM_VXRS,
+                      GFP_KERNEL|__GFP_REPEAT);
+       if (!vxrs)
+               return -ENOMEM;
+       preempt_disable();
+       if (tsk == current)
+               save_fp_regs(tsk->thread.fp_regs.fprs);
+       /* Copy the 16 floating point registers */
+       for (i = 0; i < 16; i++)
+               *(freg_t *) &vxrs[i] = tsk->thread.fp_regs.fprs[i];
+       tsk->thread.vxrs = vxrs;
+       if (tsk == current) {
+               __ctl_set_bit(0, 17);
+               restore_vx_regs(vxrs);
+       }
+       preempt_enable();
+       return 0;
+}
+
+void vector_exception(struct pt_regs *regs)
+{
+       int si_code, vic;
+
+       if (!MACHINE_HAS_VX) {
+               do_trap(regs, SIGILL, ILL_ILLOPN, "illegal operation");
+               return;
+       }
+
+       /* get vector interrupt code from fpc */
+       asm volatile("stfpc %0" : "=m" (current->thread.fp_regs.fpc));
+       vic = (current->thread.fp_regs.fpc & 0xf00) >> 8;
+       switch (vic) {
+       case 1: /* invalid vector operation */
+               si_code = FPE_FLTINV;
+               break;
+       case 2: /* division by zero */
+               si_code = FPE_FLTDIV;
+               break;
+       case 3: /* overflow */
+               si_code = FPE_FLTOVF;
+               break;
+       case 4: /* underflow */
+               si_code = FPE_FLTUND;
+               break;
+       case 5: /* inexact */
+               si_code = FPE_FLTRES;
+               break;
+       default: /* unknown cause */
+               si_code = 0;
+       }
+       do_trap(regs, SIGFPE, si_code, "vector exception");
+}
+
+static int __init disable_vector_extension(char *str)
+{
+       S390_lowcore.machine_flags &= ~MACHINE_FLAG_VX;
+       return 1;
+}
+__setup("novx", disable_vector_extension);
+#endif
+
 void data_exception(struct pt_regs *regs)
 {
        __u16 __user *location;
@@ -357,6 +438,18 @@ void data_exception(struct pt_regs *regs)
                 }
         }
 #endif 
+#ifdef CONFIG_64BIT
+       /* Check for vector register enablement */
+       if (MACHINE_HAS_VX && !current->thread.vxrs &&
+           (current->thread.fp_regs.fpc & FPC_DXC_MASK) == 0xfe00) {
+               alloc_vector_registers(current);
+               /* Vector data exception is suppressing, rewind psw. */
+               regs->psw.addr = __rewind_psw(regs->psw, regs->int_code >> 16);
+               clear_pt_regs_flag(regs, PIF_PER_TRAP);
+               return;
+       }
+#endif
+
        if (current->thread.fp_regs.fpc & FPC_DXC_MASK)
                signal = SIGFPE;
        else
diff --git a/arch/s390/kernel/uprobes.c b/arch/s390/kernel/uprobes.c
new file mode 100644 (file)
index 0000000..956f4f7
--- /dev/null
@@ -0,0 +1,332 @@
+/*
+ *  User-space Probes (UProbes) for s390
+ *
+ *    Copyright IBM Corp. 2014
+ *    Author(s): Jan Willeke,
+ */
+
+#include <linux/kprobes.h>
+#include <linux/uaccess.h>
+#include <linux/uprobes.h>
+#include <linux/compat.h>
+#include <linux/kdebug.h>
+#include <asm/switch_to.h>
+#include <asm/facility.h>
+#include <asm/dis.h>
+#include "entry.h"
+
+#define        UPROBE_TRAP_NR  UINT_MAX
+
+int arch_uprobe_analyze_insn(struct arch_uprobe *auprobe, struct mm_struct *mm,
+                            unsigned long addr)
+{
+       return probe_is_prohibited_opcode(auprobe->insn);
+}
+
+int arch_uprobe_pre_xol(struct arch_uprobe *auprobe, struct pt_regs *regs)
+{
+       if (psw_bits(regs->psw).eaba == PSW_AMODE_24BIT)
+               return -EINVAL;
+       if (!is_compat_task() && psw_bits(regs->psw).eaba == PSW_AMODE_31BIT)
+               return -EINVAL;
+       clear_pt_regs_flag(regs, PIF_PER_TRAP);
+       auprobe->saved_per = psw_bits(regs->psw).r;
+       auprobe->saved_int_code = regs->int_code;
+       regs->int_code = UPROBE_TRAP_NR;
+       regs->psw.addr = current->utask->xol_vaddr;
+       set_tsk_thread_flag(current, TIF_UPROBE_SINGLESTEP);
+       update_cr_regs(current);
+       return 0;
+}
+
+bool arch_uprobe_xol_was_trapped(struct task_struct *tsk)
+{
+       struct pt_regs *regs = task_pt_regs(tsk);
+
+       if (regs->int_code != UPROBE_TRAP_NR)
+               return true;
+       return false;
+}
+
+int arch_uprobe_post_xol(struct arch_uprobe *auprobe, struct pt_regs *regs)
+{
+       int fixup = probe_get_fixup_type(auprobe->insn);
+       struct uprobe_task *utask = current->utask;
+
+       clear_tsk_thread_flag(current, TIF_UPROBE_SINGLESTEP);
+       update_cr_regs(current);
+       psw_bits(regs->psw).r = auprobe->saved_per;
+       regs->int_code = auprobe->saved_int_code;
+
+       if (fixup & FIXUP_PSW_NORMAL)
+               regs->psw.addr += utask->vaddr - utask->xol_vaddr;
+       if (fixup & FIXUP_RETURN_REGISTER) {
+               int reg = (auprobe->insn[0] & 0xf0) >> 4;
+
+               regs->gprs[reg] += utask->vaddr - utask->xol_vaddr;
+       }
+       if (fixup & FIXUP_BRANCH_NOT_TAKEN) {
+               int ilen = insn_length(auprobe->insn[0] >> 8);
+
+               if (regs->psw.addr - utask->xol_vaddr == ilen)
+                       regs->psw.addr = utask->vaddr + ilen;
+       }
+       /* If per tracing was active generate trap */
+       if (regs->psw.mask & PSW_MASK_PER)
+               do_per_trap(regs);
+       return 0;
+}
+
+int arch_uprobe_exception_notify(struct notifier_block *self, unsigned long val,
+                                void *data)
+{
+       struct die_args *args = data;
+       struct pt_regs *regs = args->regs;
+
+       if (!user_mode(regs))
+               return NOTIFY_DONE;
+       if (regs->int_code & 0x200) /* Trap during transaction */
+               return NOTIFY_DONE;
+       switch (val) {
+       case DIE_BPT:
+               if (uprobe_pre_sstep_notifier(regs))
+                       return NOTIFY_STOP;
+               break;
+       case DIE_SSTEP:
+               if (uprobe_post_sstep_notifier(regs))
+                       return NOTIFY_STOP;
+       default:
+               break;
+       }
+       return NOTIFY_DONE;
+}
+
+void arch_uprobe_abort_xol(struct arch_uprobe *auprobe, struct pt_regs *regs)
+{
+       clear_thread_flag(TIF_UPROBE_SINGLESTEP);
+       regs->int_code = auprobe->saved_int_code;
+       regs->psw.addr = current->utask->vaddr;
+}
+
+unsigned long arch_uretprobe_hijack_return_addr(unsigned long trampoline,
+                                               struct pt_regs *regs)
+{
+       unsigned long orig;
+
+       orig = regs->gprs[14];
+       regs->gprs[14] = trampoline;
+       return orig;
+}
+
+/* Instruction Emulation */
+
+static void adjust_psw_addr(psw_t *psw, unsigned long len)
+{
+       psw->addr = __rewind_psw(*psw, -len);
+}
+
+#define EMU_ILLEGAL_OP         1
+#define EMU_SPECIFICATION      2
+#define EMU_ADDRESSING         3
+
+#define emu_load_ril(ptr, output)                      \
+({                                                     \
+       unsigned int mask = sizeof(*(ptr)) - 1;         \
+       __typeof__(*(ptr)) input;                       \
+       int __rc = 0;                                   \
+                                                       \
+       if (!test_facility(34))                         \
+               __rc = EMU_ILLEGAL_OP;                  \
+       else if ((u64 __force)ptr & mask)               \
+               __rc = EMU_SPECIFICATION;               \
+       else if (get_user(input, ptr))                  \
+               __rc = EMU_ADDRESSING;                  \
+       else                                            \
+               *(output) = input;                      \
+       __rc;                                           \
+})
+
+#define emu_store_ril(ptr, input)                      \
+({                                                     \
+       unsigned int mask = sizeof(*(ptr)) - 1;         \
+       int __rc = 0;                                   \
+                                                       \
+       if (!test_facility(34))                         \
+               __rc = EMU_ILLEGAL_OP;                  \
+       else if ((u64 __force)ptr & mask)               \
+               __rc = EMU_SPECIFICATION;               \
+       else if (put_user(*(input), ptr))               \
+               __rc = EMU_ADDRESSING;                  \
+       __rc;                                           \
+})
+
+#define emu_cmp_ril(regs, ptr, cmp)                    \
+({                                                     \
+       unsigned int mask = sizeof(*(ptr)) - 1;         \
+       __typeof__(*(ptr)) input;                       \
+       int __rc = 0;                                   \
+                                                       \
+       if (!test_facility(34))                         \
+               __rc = EMU_ILLEGAL_OP;                  \
+       else if ((u64 __force)ptr & mask)               \
+               __rc = EMU_SPECIFICATION;               \
+       else if (get_user(input, ptr))                  \
+               __rc = EMU_ADDRESSING;                  \
+       else if (input > *(cmp))                        \
+               psw_bits((regs)->psw).cc = 1;           \
+       else if (input < *(cmp))                        \
+               psw_bits((regs)->psw).cc = 2;           \
+       else                                            \
+               psw_bits((regs)->psw).cc = 0;           \
+       __rc;                                           \
+})
+
+struct insn_ril {
+       u8 opc0;
+       u8 reg  : 4;
+       u8 opc1 : 4;
+       s32 disp;
+} __packed;
+
+union split_register {
+       u64 u64;
+       u32 u32[2];
+       u16 u16[4];
+       s64 s64;
+       s32 s32[2];
+       s16 s16[4];
+};
+
+/*
+ * pc relative instructions are emulated, since parameters may not be
+ * accessible from the xol area due to range limitations.
+ */
+static void handle_insn_ril(struct arch_uprobe *auprobe, struct pt_regs *regs)
+{
+       union split_register *rx;
+       struct insn_ril *insn;
+       unsigned int ilen;
+       void *uptr;
+       int rc = 0;
+
+       insn = (struct insn_ril *) &auprobe->insn;
+       rx = (union split_register *) &regs->gprs[insn->reg];
+       uptr = (void *)(regs->psw.addr + (insn->disp * 2));
+       ilen = insn_length(insn->opc0);
+
+       switch (insn->opc0) {
+       case 0xc0:
+               switch (insn->opc1) {
+               case 0x00: /* larl */
+                       rx->u64 = (unsigned long)uptr;
+                       break;
+               }
+               break;
+       case 0xc4:
+               switch (insn->opc1) {
+               case 0x02: /* llhrl */
+                       rc = emu_load_ril((u16 __user *)uptr, &rx->u32[1]);
+                       break;
+               case 0x04: /* lghrl */
+                       rc = emu_load_ril((s16 __user *)uptr, &rx->u64);
+                       break;
+               case 0x05: /* lhrl */
+                       rc = emu_load_ril((s16 __user *)uptr, &rx->u32[1]);
+                       break;
+               case 0x06: /* llghrl */
+                       rc = emu_load_ril((u16 __user *)uptr, &rx->u64);
+                       break;
+               case 0x08: /* lgrl */
+                       rc = emu_load_ril((u64 __user *)uptr, &rx->u64);
+                       break;
+               case 0x0c: /* lgfrl */
+                       rc = emu_load_ril((s32 __user *)uptr, &rx->u64);
+                       break;
+               case 0x0d: /* lrl */
+                       rc = emu_load_ril((u32 __user *)uptr, &rx->u32[1]);
+                       break;
+               case 0x0e: /* llgfrl */
+                       rc = emu_load_ril((u32 __user *)uptr, &rx->u64);
+                       break;
+               case 0x07: /* sthrl */
+                       rc = emu_store_ril((u16 __user *)uptr, &rx->u16[3]);
+                       break;
+               case 0x0b: /* stgrl */
+                       rc = emu_store_ril((u64 __user *)uptr, &rx->u64);
+                       break;
+               case 0x0f: /* strl */
+                       rc = emu_store_ril((u32 __user *)uptr, &rx->u32[1]);
+                       break;
+               }
+               break;
+       case 0xc6:
+               switch (insn->opc1) {
+               case 0x02: /* pfdrl */
+                       if (!test_facility(34))
+                               rc = EMU_ILLEGAL_OP;
+                       break;
+               case 0x04: /* cghrl */
+                       rc = emu_cmp_ril(regs, (s16 __user *)uptr, &rx->s64);
+                       break;
+               case 0x05: /* chrl */
+                       rc = emu_cmp_ril(regs, (s16 __user *)uptr, &rx->s32[1]);
+                       break;
+               case 0x06: /* clghrl */
+                       rc = emu_cmp_ril(regs, (u16 __user *)uptr, &rx->u64);
+                       break;
+               case 0x07: /* clhrl */
+                       rc = emu_cmp_ril(regs, (u16 __user *)uptr, &rx->u32[1]);
+                       break;
+               case 0x08: /* cgrl */
+                       rc = emu_cmp_ril(regs, (s64 __user *)uptr, &rx->s64);
+                       break;
+               case 0x0a: /* clgrl */
+                       rc = emu_cmp_ril(regs, (u64 __user *)uptr, &rx->u64);
+                       break;
+               case 0x0c: /* cgfrl */
+                       rc = emu_cmp_ril(regs, (s32 __user *)uptr, &rx->s64);
+                       break;
+               case 0x0d: /* crl */
+                       rc = emu_cmp_ril(regs, (s32 __user *)uptr, &rx->s32[1]);
+                       break;
+               case 0x0e: /* clgfrl */
+                       rc = emu_cmp_ril(regs, (u32 __user *)uptr, &rx->u64);
+                       break;
+               case 0x0f: /* clrl */
+                       rc = emu_cmp_ril(regs, (u32 __user *)uptr, &rx->u32[1]);
+                       break;
+               }
+               break;
+       }
+       adjust_psw_addr(&regs->psw, ilen);
+       switch (rc) {
+       case EMU_ILLEGAL_OP:
+               regs->int_code = ilen << 16 | 0x0001;
+               do_report_trap(regs, SIGILL, ILL_ILLOPC, NULL);
+               break;
+       case EMU_SPECIFICATION:
+               regs->int_code = ilen << 16 | 0x0006;
+               do_report_trap(regs, SIGILL, ILL_ILLOPC , NULL);
+               break;
+       case EMU_ADDRESSING:
+               regs->int_code = ilen << 16 | 0x0005;
+               do_report_trap(regs, SIGSEGV, SEGV_MAPERR, NULL);
+               break;
+       }
+}
+
+bool arch_uprobe_skip_sstep(struct arch_uprobe *auprobe, struct pt_regs *regs)
+{
+       if ((psw_bits(regs->psw).eaba == PSW_AMODE_24BIT) ||
+           ((psw_bits(regs->psw).eaba == PSW_AMODE_31BIT) &&
+            !is_compat_task())) {
+               regs->psw.addr = __rewind_psw(regs->psw, UPROBE_SWBP_INSN_SIZE);
+               do_report_trap(regs, SIGILL, ILL_ILLADR, NULL);
+               return true;
+       }
+       if (probe_is_insn_relative_long(auprobe->insn)) {
+               handle_insn_ril(auprobe, regs);
+               return true;
+       }
+       return false;
+}
index 36aaa25d05daa4e1d785103d85a2bb5a078fc2cc..eca3f001f081309c88372de459a6dfcccd754e7d 100644 (file)
        .type  __kernel_clock_getres,@function
 __kernel_clock_getres:
        .cfi_startproc
+       basr    %r1,0
+       la      %r1,4f-.(%r1)
        chi     %r2,__CLOCK_REALTIME
        je      0f
        chi     %r2,__CLOCK_MONOTONIC
+       je      0f
+       la      %r1,5f-4f(%r1)
+       chi     %r2,__CLOCK_REALTIME_COARSE
+       je      0f
+       chi     %r2,__CLOCK_MONOTONIC_COARSE
        jne     3f
 0:     ltr     %r3,%r3
        jz      2f                              /* res == NULL */
-       basr    %r1,0
-1:     l       %r0,4f-1b(%r1)
+1:     l       %r0,0(%r1)
        xc      0(4,%r3),0(%r3)                 /* set tp->tv_sec to zero */
        st      %r0,4(%r3)                      /* store tp->tv_usec */
 2:     lhi     %r2,0
@@ -35,5 +41,6 @@ __kernel_clock_getres:
        svc     0
        br      %r14
 4:     .long   __CLOCK_REALTIME_RES
+5:     .long   __CLOCK_COARSE_RES
        .cfi_endproc
        .size   __kernel_clock_getres,.-__kernel_clock_getres
index 7cf18f8d4cb4fc9d281169ed8dee675f4c68b6be..48c2206a39561ea9373bb3fb8ec48297b3509867 100644 (file)
@@ -21,8 +21,12 @@ __kernel_clock_gettime:
        .cfi_startproc
        basr    %r5,0
 0:     al      %r5,21f-0b(%r5)                 /* get &_vdso_data */
+       chi     %r2,__CLOCK_REALTIME_COARSE
+       je      10f
        chi     %r2,__CLOCK_REALTIME
        je      11f
+       chi     %r2,__CLOCK_MONOTONIC_COARSE
+       je      9f
        chi     %r2,__CLOCK_MONOTONIC
        jne     19f
 
@@ -30,8 +34,8 @@ __kernel_clock_gettime:
 1:     l       %r4,__VDSO_UPD_COUNT+4(%r5)     /* load update counter */
        tml     %r4,0x0001                      /* pending update ? loop */
        jnz     1b
-       stck    24(%r15)                        /* Store TOD clock */
-       lm      %r0,%r1,24(%r15)
+       stcke   24(%r15)                        /* Store TOD clock */
+       lm      %r0,%r1,25(%r15)
        s       %r0,__VDSO_XTIME_STAMP(%r5)     /* TOD - cycle_last */
        sl      %r1,__VDSO_XTIME_STAMP+4(%r5)
        brc     3,2f
@@ -68,12 +72,32 @@ __kernel_clock_gettime:
        lhi     %r2,0
        br      %r14
 
+       /* CLOCK_MONOTONIC_COARSE */
+9:     l       %r4,__VDSO_UPD_COUNT+4(%r5)     /* load update counter */
+       tml     %r4,0x0001                      /* pending update ? loop */
+       jnz     9b
+       l       %r2,__VDSO_WTOM_CRS_SEC+4(%r5)
+       l       %r1,__VDSO_WTOM_CRS_NSEC+4(%r5)
+       cl      %r4,__VDSO_UPD_COUNT+4(%r5)     /* check update counter */
+       jne     9b
+       j       8b
+
+       /* CLOCK_REALTIME_COARSE */
+10:    l       %r4,__VDSO_UPD_COUNT+4(%r5)     /* load update counter */
+       tml     %r4,0x0001                      /* pending update ? loop */
+       jnz     10b
+       l       %r2,__VDSO_XTIME_CRS_SEC+4(%r5)
+       l       %r1,__VDSO_XTIME_CRS_NSEC+4(%r5)
+       cl      %r4,__VDSO_UPD_COUNT+4(%r5)     /* check update counter */
+       jne     10b
+       j       17f
+
        /* CLOCK_REALTIME */
 11:    l       %r4,__VDSO_UPD_COUNT+4(%r5)     /* load update counter */
        tml     %r4,0x0001                      /* pending update ? loop */
        jnz     11b
-       stck    24(%r15)                        /* Store TOD clock */
-       lm      %r0,%r1,24(%r15)
+       stcke   24(%r15)                        /* Store TOD clock */
+       lm      %r0,%r1,25(%r15)
        s       %r0,__VDSO_XTIME_STAMP(%r5)     /* TOD - cycle_last */
        sl      %r1,__VDSO_XTIME_STAMP+4(%r5)
        brc     3,12f
index fd621a950f7c70e917ea6ca44bb4a5fd5b9869ab..60def5f562db532e4c014687e38dcefdf1344383 100644 (file)
@@ -29,8 +29,8 @@ __kernel_gettimeofday:
        l       %r4,__VDSO_UPD_COUNT+4(%r5)     /* load update counter */
        tml     %r4,0x0001                      /* pending update ? loop */
        jnz     1b
-       stck    24(%r15)                        /* Store TOD clock */
-       lm      %r0,%r1,24(%r15)
+       stcke   24(%r15)                        /* Store TOD clock */
+       lm      %r0,%r1,25(%r15)
        s       %r0,__VDSO_XTIME_STAMP(%r5)     /* TOD - cycle_last */
        sl      %r1,__VDSO_XTIME_STAMP+4(%r5)
        brc     3,3f
index 34deba7c7ed1d8b18036b0b07f9b7cd9d41e9259..c8513deb8c663f51fa4f4bc2b2299ea24f1aaefd 100644 (file)
        .type  __kernel_clock_getres,@function
 __kernel_clock_getres:
        .cfi_startproc
+       larl    %r1,4f
+       cghi    %r2,__CLOCK_REALTIME_COARSE
+       je      0f
+       cghi    %r2,__CLOCK_MONOTONIC_COARSE
+       je      0f
+       larl    %r1,3f
        cghi    %r2,__CLOCK_REALTIME
        je      0f
        cghi    %r2,__CLOCK_MONOTONIC
@@ -32,7 +38,6 @@ __kernel_clock_getres:
        jz      2f
 0:     ltgr    %r3,%r3
        jz      1f                              /* res == NULL */
-       larl    %r1,3f
        lg      %r0,0(%r1)
        xc      0(8,%r3),0(%r3)                 /* set tp->tv_sec to zero */
        stg     %r0,8(%r3)                      /* store tp->tv_usec */
@@ -42,5 +47,6 @@ __kernel_clock_getres:
        svc     0
        br      %r14
 3:     .quad   __CLOCK_REALTIME_RES
+4:     .quad   __CLOCK_COARSE_RES
        .cfi_endproc
        .size   __kernel_clock_getres,.-__kernel_clock_getres
index 3f34e09db5f4d4d0e5f7a12b9e3acb89a72a6773..9d9761f8e11035761c3b1143c6486a9fc52193c6 100644 (file)
 __kernel_clock_gettime:
        .cfi_startproc
        larl    %r5,_vdso_data
+       cghi    %r2,__CLOCK_REALTIME_COARSE
+       je      4f
        cghi    %r2,__CLOCK_REALTIME
        je      5f
        cghi    %r2,__CLOCK_THREAD_CPUTIME_ID
        je      9f
        cghi    %r2,-2          /* Per-thread CPUCLOCK with PID=0, VIRT=1 */
        je      9f
+       cghi    %r2,__CLOCK_MONOTONIC_COARSE
+       je      3f
        cghi    %r2,__CLOCK_MONOTONIC
        jne     12f
 
@@ -33,10 +37,10 @@ __kernel_clock_gettime:
 0:     lg      %r4,__VDSO_UPD_COUNT(%r5)       /* load update counter */
        tmll    %r4,0x0001                      /* pending update ? loop */
        jnz     0b
-       stck    48(%r15)                        /* Store TOD clock */
+       stcke   48(%r15)                        /* Store TOD clock */
        lgf     %r2,__VDSO_TK_SHIFT(%r5)        /* Timekeeper shift */
        lg      %r0,__VDSO_WTOM_SEC(%r5)
-       lg      %r1,48(%r15)
+       lg      %r1,49(%r15)
        sg      %r1,__VDSO_XTIME_STAMP(%r5)     /* TOD - cycle_last */
        msgf    %r1,__VDSO_TK_MULT(%r5)         /*  * tk->mult */
        alg     %r1,__VDSO_WTOM_NSEC(%r5)
@@ -54,13 +58,33 @@ __kernel_clock_gettime:
        lghi    %r2,0
        br      %r14
 
+       /* CLOCK_MONOTONIC_COARSE */
+3:     lg      %r4,__VDSO_UPD_COUNT(%r5)       /* load update counter */
+       tmll    %r4,0x0001                      /* pending update ? loop */
+       jnz     3b
+       lg      %r0,__VDSO_WTOM_CRS_SEC(%r5)
+       lg      %r1,__VDSO_WTOM_CRS_NSEC(%r5)
+       clg     %r4,__VDSO_UPD_COUNT(%r5)       /* check update counter */
+       jne     3b
+       j       2b
+
+       /* CLOCK_REALTIME_COARSE */
+4:     lg      %r4,__VDSO_UPD_COUNT(%r5)       /* load update counter */
+       tmll    %r4,0x0001                      /* pending update ? loop */
+       jnz     4b
+       lg      %r0,__VDSO_XTIME_CRS_SEC(%r5)
+       lg      %r1,__VDSO_XTIME_CRS_NSEC(%r5)
+       clg     %r4,__VDSO_UPD_COUNT(%r5)       /* check update counter */
+       jne     4b
+       j       7f
+
        /* CLOCK_REALTIME */
 5:     lg      %r4,__VDSO_UPD_COUNT(%r5)       /* load update counter */
        tmll    %r4,0x0001                      /* pending update ? loop */
        jnz     5b
-       stck    48(%r15)                        /* Store TOD clock */
+       stcke   48(%r15)                        /* Store TOD clock */
        lgf     %r2,__VDSO_TK_SHIFT(%r5)        /* Timekeeper shift */
-       lg      %r1,48(%r15)
+       lg      %r1,49(%r15)
        sg      %r1,__VDSO_XTIME_STAMP(%r5)     /* TOD - cycle_last */
        msgf    %r1,__VDSO_TK_MULT(%r5)         /*  * tk->mult */
        alg     %r1,__VDSO_XTIME_NSEC(%r5)      /*  + tk->xtime_nsec */
index d0860d1d0cccfafe86320a07380ea14ddff1a284..7a344995a97fd21246de5554f09674449db8f2fd 100644 (file)
@@ -28,8 +28,8 @@ __kernel_gettimeofday:
        lg      %r4,__VDSO_UPD_COUNT(%r5)       /* load update counter */
        tmll    %r4,0x0001                      /* pending update ? loop */
        jnz     0b
-       stck    48(%r15)                        /* Store TOD clock */
-       lg      %r1,48(%r15)
+       stcke   48(%r15)                        /* Store TOD clock */
+       lg      %r1,49(%r15)
        sg      %r1,__VDSO_XTIME_STAMP(%r5)     /* TOD - cycle_last */
        msgf    %r1,__VDSO_TK_MULT(%r5)         /*  * tk->mult */
        alg     %r1,__VDSO_XTIME_NSEC(%r5)      /*  + tk->xtime_nsec */
index 8c34363d6f1e88571074b01593b1efaa80c007d0..416f2a323ba5e3a3d59a806a921751749ccb7a46 100644 (file)
@@ -6,27 +6,18 @@
  */
 
 #include <linux/kernel_stat.h>
-#include <linux/notifier.h>
-#include <linux/kprobes.h>
 #include <linux/export.h>
 #include <linux/kernel.h>
 #include <linux/timex.h>
 #include <linux/types.h>
 #include <linux/time.h>
-#include <linux/cpu.h>
-#include <linux/smp.h>
 
-#include <asm/irq_regs.h>
 #include <asm/cputime.h>
 #include <asm/vtimer.h>
 #include <asm/vtime.h>
-#include <asm/irq.h>
-#include "entry.h"
 
 static void virt_timer_expire(void);
 
-DEFINE_PER_CPU(struct s390_idle_data, s390_idle);
-
 static LIST_HEAD(virt_timer_list);
 static DEFINE_SPINLOCK(virt_timer_lock);
 static atomic64_t virt_timer_current;
@@ -152,49 +143,6 @@ void vtime_account_system(struct task_struct *tsk)
 __attribute__((alias("vtime_account_irq_enter")));
 EXPORT_SYMBOL_GPL(vtime_account_system);
 
-void __kprobes vtime_stop_cpu(void)
-{
-       struct s390_idle_data *idle = &__get_cpu_var(s390_idle);
-       unsigned long long idle_time;
-       unsigned long psw_mask;
-
-       trace_hardirqs_on();
-
-       /* Wait for external, I/O or machine check interrupt. */
-       psw_mask = PSW_KERNEL_BITS | PSW_MASK_WAIT | PSW_MASK_DAT |
-               PSW_MASK_IO | PSW_MASK_EXT | PSW_MASK_MCHECK;
-       idle->nohz_delay = 0;
-
-       /* Call the assembler magic in entry.S */
-       psw_idle(idle, psw_mask);
-
-       /* Account time spent with enabled wait psw loaded as idle time. */
-       idle->sequence++;
-       smp_wmb();
-       idle_time = idle->clock_idle_exit - idle->clock_idle_enter;
-       idle->clock_idle_enter = idle->clock_idle_exit = 0ULL;
-       idle->idle_time += idle_time;
-       idle->idle_count++;
-       account_idle_time(idle_time);
-       smp_wmb();
-       idle->sequence++;
-}
-
-cputime64_t s390_get_idle_time(int cpu)
-{
-       struct s390_idle_data *idle = &per_cpu(s390_idle, cpu);
-       unsigned long long now, idle_enter, idle_exit;
-       unsigned int sequence;
-
-       do {
-               now = get_tod_clock();
-               sequence = ACCESS_ONCE(idle->sequence);
-               idle_enter = ACCESS_ONCE(idle->clock_idle_enter);
-               idle_exit = ACCESS_ONCE(idle->clock_idle_exit);
-       } while ((sequence & 1) || (ACCESS_ONCE(idle->sequence) != sequence));
-       return idle_enter ? ((idle_exit ?: now) - idle_enter) : 0;
-}
-
 /*
  * Sorted add to a list. List is linear searched until first bigger
  * element is found.
@@ -372,31 +320,8 @@ EXPORT_SYMBOL(del_virt_timer);
 /*
  * Start the virtual CPU timer on the current CPU.
  */
-void init_cpu_vtimer(void)
+void vtime_init(void)
 {
        /* set initial cpu timer */
        set_vtimer(VTIMER_MAX_SLICE);
 }
-
-static int s390_nohz_notify(struct notifier_block *self, unsigned long action,
-                           void *hcpu)
-{
-       struct s390_idle_data *idle;
-       long cpu = (long) hcpu;
-
-       idle = &per_cpu(s390_idle, cpu);
-       switch (action & ~CPU_TASKS_FROZEN) {
-       case CPU_DYING:
-               idle->nohz_delay = 0;
-       default:
-               break;
-       }
-       return NOTIFY_OK;
-}
-
-void __init vtime_init(void)
-{
-       /* Enable cpu timer interrupts on the boot cpu. */
-       init_cpu_vtimer();
-       cpu_notifier(s390_nohz_notify, 0);
-}
index c6d752e8bf28e2dbee2839915b46d10107eb047b..a01df233856f40bafef9424115f59026546be824 100644 (file)
@@ -6,3 +6,5 @@ lib-y += delay.o string.o uaccess.o find.o
 obj-$(CONFIG_32BIT) += div64.o qrnnd.o ucmpdi2.o mem32.o
 obj-$(CONFIG_64BIT) += mem64.o
 lib-$(CONFIG_SMP) += spinlock.o
+lib-$(CONFIG_KPROBES) += probes.o
+lib-$(CONFIG_UPROBES) += probes.o
index a9f3d0042d58ba849b8c624f23915d88d03d6f70..16dc42d83f9316c8524436457b2a92df59b2fbf0 100644 (file)
@@ -43,7 +43,7 @@ static void __udelay_disabled(unsigned long long usecs)
        lockdep_off();
        do {
                set_clock_comparator(end);
-               vtime_stop_cpu();
+               enabled_wait();
        } while (get_tod_clock_fast() < end);
        lockdep_on();
        __ctl_load(cr0, 0, 0);
@@ -62,7 +62,7 @@ static void __udelay_enabled(unsigned long long usecs)
                        clock_saved = local_tick_disable();
                        set_clock_comparator(end);
                }
-               vtime_stop_cpu();
+               enabled_wait();
                if (clock_saved)
                        local_tick_enable(clock_saved);
        } while (get_tod_clock_fast() < end);
diff --git a/arch/s390/lib/probes.c b/arch/s390/lib/probes.c
new file mode 100644 (file)
index 0000000..c5d64a0
--- /dev/null
@@ -0,0 +1,159 @@
+/*
+ *    Common helper functions for kprobes and uprobes
+ *
+ *    Copyright IBM Corp. 2014
+ */
+
+#include <linux/kprobes.h>
+#include <asm/dis.h>
+
+int probe_is_prohibited_opcode(u16 *insn)
+{
+       if (!is_known_insn((unsigned char *)insn))
+               return -EINVAL;
+       switch (insn[0] >> 8) {
+       case 0x0c:      /* bassm */
+       case 0x0b:      /* bsm   */
+       case 0x83:      /* diag  */
+       case 0x44:      /* ex    */
+       case 0xac:      /* stnsm */
+       case 0xad:      /* stosm */
+               return -EINVAL;
+       case 0xc6:
+               switch (insn[0] & 0x0f) {
+               case 0x00: /* exrl   */
+                       return -EINVAL;
+               }
+       }
+       switch (insn[0]) {
+       case 0x0101:    /* pr    */
+       case 0xb25a:    /* bsa   */
+       case 0xb240:    /* bakr  */
+       case 0xb258:    /* bsg   */
+       case 0xb218:    /* pc    */
+       case 0xb228:    /* pt    */
+       case 0xb98d:    /* epsw  */
+       case 0xe560:    /* tbegin */
+       case 0xe561:    /* tbeginc */
+       case 0xb2f8:    /* tend  */
+               return -EINVAL;
+       }
+       return 0;
+}
+
+int probe_get_fixup_type(u16 *insn)
+{
+       /* default fixup method */
+       int fixup = FIXUP_PSW_NORMAL;
+
+       switch (insn[0] >> 8) {
+       case 0x05:      /* balr */
+       case 0x0d:      /* basr */
+               fixup = FIXUP_RETURN_REGISTER;
+               /* if r2 = 0, no branch will be taken */
+               if ((insn[0] & 0x0f) == 0)
+                       fixup |= FIXUP_BRANCH_NOT_TAKEN;
+               break;
+       case 0x06:      /* bctr */
+       case 0x07:      /* bcr  */
+               fixup = FIXUP_BRANCH_NOT_TAKEN;
+               break;
+       case 0x45:      /* bal  */
+       case 0x4d:      /* bas  */
+               fixup = FIXUP_RETURN_REGISTER;
+               break;
+       case 0x47:      /* bc   */
+       case 0x46:      /* bct  */
+       case 0x86:      /* bxh  */
+       case 0x87:      /* bxle */
+               fixup = FIXUP_BRANCH_NOT_TAKEN;
+               break;
+       case 0x82:      /* lpsw */
+               fixup = FIXUP_NOT_REQUIRED;
+               break;
+       case 0xb2:      /* lpswe */
+               if ((insn[0] & 0xff) == 0xb2)
+                       fixup = FIXUP_NOT_REQUIRED;
+               break;
+       case 0xa7:      /* bras */
+               if ((insn[0] & 0x0f) == 0x05)
+                       fixup |= FIXUP_RETURN_REGISTER;
+               break;
+       case 0xc0:
+               if ((insn[0] & 0x0f) == 0x05)   /* brasl */
+                       fixup |= FIXUP_RETURN_REGISTER;
+               break;
+       case 0xeb:
+               switch (insn[2] & 0xff) {
+               case 0x44: /* bxhg  */
+               case 0x45: /* bxleg */
+                       fixup = FIXUP_BRANCH_NOT_TAKEN;
+                       break;
+               }
+               break;
+       case 0xe3:      /* bctg */
+               if ((insn[2] & 0xff) == 0x46)
+                       fixup = FIXUP_BRANCH_NOT_TAKEN;
+               break;
+       case 0xec:
+               switch (insn[2] & 0xff) {
+               case 0xe5: /* clgrb */
+               case 0xe6: /* cgrb  */
+               case 0xf6: /* crb   */
+               case 0xf7: /* clrb  */
+               case 0xfc: /* cgib  */
+               case 0xfd: /* cglib */
+               case 0xfe: /* cib   */
+               case 0xff: /* clib  */
+                       fixup = FIXUP_BRANCH_NOT_TAKEN;
+                       break;
+               }
+               break;
+       }
+       return fixup;
+}
+
+int probe_is_insn_relative_long(u16 *insn)
+{
+       /* Check if we have a RIL-b or RIL-c format instruction which
+        * we need to modify in order to avoid instruction emulation. */
+       switch (insn[0] >> 8) {
+       case 0xc0:
+               if ((insn[0] & 0x0f) == 0x00) /* larl */
+                       return true;
+               break;
+       case 0xc4:
+               switch (insn[0] & 0x0f) {
+               case 0x02: /* llhrl  */
+               case 0x04: /* lghrl  */
+               case 0x05: /* lhrl   */
+               case 0x06: /* llghrl */
+               case 0x07: /* sthrl  */
+               case 0x08: /* lgrl   */
+               case 0x0b: /* stgrl  */
+               case 0x0c: /* lgfrl  */
+               case 0x0d: /* lrl    */
+               case 0x0e: /* llgfrl */
+               case 0x0f: /* strl   */
+                       return true;
+               }
+               break;
+       case 0xc6:
+               switch (insn[0] & 0x0f) {
+               case 0x02: /* pfdrl  */
+               case 0x04: /* cghrl  */
+               case 0x05: /* chrl   */
+               case 0x06: /* clghrl */
+               case 0x07: /* clhrl  */
+               case 0x08: /* cgrl   */
+               case 0x0a: /* clgrl  */
+               case 0x0c: /* cgfrl  */
+               case 0x0d: /* crl    */
+               case 0x0e: /* clgfrl */
+               case 0x0f: /* clrl   */
+                       return true;
+               }
+               break;
+       }
+       return false;
+}
index 5b0e445bc3f39930317bafc745c76c674874bf0e..034a35a3e9c11a0a5a9b7f2d73ba16cf9adbd314 100644 (file)
@@ -98,17 +98,6 @@ void arch_spin_lock_wait_flags(arch_spinlock_t *lp, unsigned long flags)
 }
 EXPORT_SYMBOL(arch_spin_lock_wait_flags);
 
-void arch_spin_relax(arch_spinlock_t *lp)
-{
-       unsigned int cpu = lp->lock;
-       if (cpu != 0) {
-               if (MACHINE_IS_VM || MACHINE_IS_KVM ||
-                   !smp_vcpu_scheduled(~cpu))
-                       smp_yield_cpu(~cpu);
-       }
-}
-EXPORT_SYMBOL(arch_spin_relax);
-
 int arch_spin_trylock_retry(arch_spinlock_t *lp)
 {
        int count;
@@ -122,15 +111,21 @@ EXPORT_SYMBOL(arch_spin_trylock_retry);
 
 void _raw_read_lock_wait(arch_rwlock_t *rw)
 {
-       unsigned int old;
+       unsigned int owner, old;
        int count = spin_retry;
 
+#ifdef CONFIG_HAVE_MARCH_Z196_FEATURES
+       __RAW_LOCK(&rw->lock, -1, __RAW_OP_ADD);
+#endif
+       owner = 0;
        while (1) {
                if (count-- <= 0) {
-                       smp_yield();
+                       if (owner && !smp_vcpu_scheduled(~owner))
+                               smp_yield_cpu(~owner);
                        count = spin_retry;
                }
                old = ACCESS_ONCE(rw->lock);
+               owner = ACCESS_ONCE(rw->owner);
                if ((int) old < 0)
                        continue;
                if (_raw_compare_and_swap(&rw->lock, old, old + 1))
@@ -139,28 +134,6 @@ void _raw_read_lock_wait(arch_rwlock_t *rw)
 }
 EXPORT_SYMBOL(_raw_read_lock_wait);
 
-void _raw_read_lock_wait_flags(arch_rwlock_t *rw, unsigned long flags)
-{
-       unsigned int old;
-       int count = spin_retry;
-
-       local_irq_restore(flags);
-       while (1) {
-               if (count-- <= 0) {
-                       smp_yield();
-                       count = spin_retry;
-               }
-               old = ACCESS_ONCE(rw->lock);
-               if ((int) old < 0)
-                       continue;
-               local_irq_disable();
-               if (_raw_compare_and_swap(&rw->lock, old, old + 1))
-                       return;
-               local_irq_restore(flags);
-       }
-}
-EXPORT_SYMBOL(_raw_read_lock_wait_flags);
-
 int _raw_read_trylock_retry(arch_rwlock_t *rw)
 {
        unsigned int old;
@@ -177,46 +150,62 @@ int _raw_read_trylock_retry(arch_rwlock_t *rw)
 }
 EXPORT_SYMBOL(_raw_read_trylock_retry);
 
-void _raw_write_lock_wait(arch_rwlock_t *rw)
+#ifdef CONFIG_HAVE_MARCH_Z196_FEATURES
+
+void _raw_write_lock_wait(arch_rwlock_t *rw, unsigned int prev)
 {
-       unsigned int old;
+       unsigned int owner, old;
        int count = spin_retry;
 
+       owner = 0;
        while (1) {
                if (count-- <= 0) {
-                       smp_yield();
+                       if (owner && !smp_vcpu_scheduled(~owner))
+                               smp_yield_cpu(~owner);
                        count = spin_retry;
                }
                old = ACCESS_ONCE(rw->lock);
-               if (old)
-                       continue;
-               if (_raw_compare_and_swap(&rw->lock, 0, 0x80000000))
-                       return;
+               owner = ACCESS_ONCE(rw->owner);
+               smp_rmb();
+               if ((int) old >= 0) {
+                       prev = __RAW_LOCK(&rw->lock, 0x80000000, __RAW_OP_OR);
+                       old = prev;
+               }
+               if ((old & 0x7fffffff) == 0 && (int) prev >= 0)
+                       break;
        }
 }
 EXPORT_SYMBOL(_raw_write_lock_wait);
 
-void _raw_write_lock_wait_flags(arch_rwlock_t *rw, unsigned long flags)
+#else /* CONFIG_HAVE_MARCH_Z196_FEATURES */
+
+void _raw_write_lock_wait(arch_rwlock_t *rw)
 {
-       unsigned int old;
+       unsigned int owner, old, prev;
        int count = spin_retry;
 
-       local_irq_restore(flags);
+       prev = 0x80000000;
+       owner = 0;
        while (1) {
                if (count-- <= 0) {
-                       smp_yield();
+                       if (owner && !smp_vcpu_scheduled(~owner))
+                               smp_yield_cpu(~owner);
                        count = spin_retry;
                }
                old = ACCESS_ONCE(rw->lock);
-               if (old)
-                       continue;
-               local_irq_disable();
-               if (_raw_compare_and_swap(&rw->lock, 0, 0x80000000))
-                       return;
-               local_irq_restore(flags);
+               owner = ACCESS_ONCE(rw->owner);
+               if ((int) old >= 0 &&
+                   _raw_compare_and_swap(&rw->lock, old, old | 0x80000000))
+                       prev = old;
+               else
+                       smp_rmb();
+               if ((old & 0x7fffffff) == 0 && (int) prev >= 0)
+                       break;
        }
 }
-EXPORT_SYMBOL(_raw_write_lock_wait_flags);
+EXPORT_SYMBOL(_raw_write_lock_wait);
+
+#endif /* CONFIG_HAVE_MARCH_Z196_FEATURES */
 
 int _raw_write_trylock_retry(arch_rwlock_t *rw)
 {
@@ -233,3 +222,13 @@ int _raw_write_trylock_retry(arch_rwlock_t *rw)
        return 0;
 }
 EXPORT_SYMBOL(_raw_write_trylock_retry);
+
+void arch_lock_relax(unsigned int cpu)
+{
+       if (!cpu)
+               return;
+       if (MACHINE_IS_LPAR && smp_vcpu_scheduled(~cpu))
+               return;
+       smp_yield_cpu(~cpu);
+}
+EXPORT_SYMBOL(arch_lock_relax);
index 46d517c3c76366c7459b7f539888a29064a43d78..d46cadeda204d5a51308ec7a7a4b1d2e100de0ee 100644 (file)
@@ -54,7 +54,6 @@ static void print_prot(struct seq_file *m, unsigned int pr, int level)
                return;
        }
        seq_printf(m, "%s", pr & _PAGE_PROTECT ? "RO " : "RW ");
-       seq_printf(m, "%s", pr & _PAGE_CO ? "CO " : "   ");
        seq_putc(m, '\n');
 }
 
@@ -129,7 +128,7 @@ static void walk_pte_level(struct seq_file *m, struct pg_state *st,
 }
 
 #ifdef CONFIG_64BIT
-#define _PMD_PROT_MASK (_SEGMENT_ENTRY_PROTECT | _SEGMENT_ENTRY_CO)
+#define _PMD_PROT_MASK _SEGMENT_ENTRY_PROTECT
 #else
 #define _PMD_PROT_MASK 0
 #endif
@@ -157,7 +156,7 @@ static void walk_pmd_level(struct seq_file *m, struct pg_state *st,
 }
 
 #ifdef CONFIG_64BIT
-#define _PUD_PROT_MASK (_REGION3_ENTRY_RO | _REGION3_ENTRY_CO)
+#define _PUD_PROT_MASK _REGION3_ENTRY_RO
 #else
 #define _PUD_PROT_MASK 0
 #endif
index 389bc17934b7887625598963284b12e8900ce4fe..3c80d2e38f03c45c014eb3a46551cb0e14a920de 100644 (file)
@@ -88,7 +88,7 @@ void set_huge_pte_at(struct mm_struct *mm, unsigned long addr,
                pmd_val(pmd) &= ~_SEGMENT_ENTRY_ORIGIN;
                pmd_val(pmd) |= pte_page(pte)[1].index;
        } else
-               pmd_val(pmd) |= _SEGMENT_ENTRY_LARGE | _SEGMENT_ENTRY_CO;
+               pmd_val(pmd) |= _SEGMENT_ENTRY_LARGE;
        *(pmd_t *) ptep = pmd;
 }
 
index 8400f494623f4591a5de3e5ea6442a08fe767ed4..3fef3b299665797bbd486baec5239d5f88705428 100644 (file)
@@ -6,6 +6,7 @@
 #include <linux/module.h>
 #include <linux/mm.h>
 #include <asm/cacheflush.h>
+#include <asm/facility.h>
 #include <asm/pgtable.h>
 #include <asm/page.h>
 
@@ -103,27 +104,50 @@ int set_memory_x(unsigned long addr, int numpages)
 }
 
 #ifdef CONFIG_DEBUG_PAGEALLOC
+
+static void ipte_range(pte_t *pte, unsigned long address, int nr)
+{
+       int i;
+
+       if (test_facility(13) && IS_ENABLED(CONFIG_64BIT)) {
+               __ptep_ipte_range(address, nr - 1, pte);
+               return;
+       }
+       for (i = 0; i < nr; i++) {
+               __ptep_ipte(address, pte);
+               address += PAGE_SIZE;
+               pte++;
+       }
+}
+
 void kernel_map_pages(struct page *page, int numpages, int enable)
 {
        unsigned long address;
+       int nr, i, j;
        pgd_t *pgd;
        pud_t *pud;
        pmd_t *pmd;
        pte_t *pte;
-       int i;
 
-       for (i = 0; i < numpages; i++) {
+       for (i = 0; i < numpages;) {
                address = page_to_phys(page + i);
                pgd = pgd_offset_k(address);
                pud = pud_offset(pgd, address);
                pmd = pmd_offset(pud, address);
                pte = pte_offset_kernel(pmd, address);
-               if (!enable) {
-                       __ptep_ipte(address, pte);
-                       pte_val(*pte) = _PAGE_INVALID;
-                       continue;
+               nr = (unsigned long)pte >> ilog2(sizeof(long));
+               nr = PTRS_PER_PTE - (nr & (PTRS_PER_PTE - 1));
+               nr = min(numpages - i, nr);
+               if (enable) {
+                       for (j = 0; j < nr; j++) {
+                               pte_val(*pte) = __pa(address);
+                               address += PAGE_SIZE;
+                               pte++;
+                       }
+               } else {
+                       ipte_range(pte, address, nr);
                }
-               pte_val(*pte) = __pa(address);
+               i += nr;
        }
 }
 
index fdbd7888cb076f87a9b6f9d94dcae434ccac77e5..b1593c2f751a89aa71675f1375d412d6736a6673 100644 (file)
@@ -236,8 +236,7 @@ int __meminit vmemmap_populate(unsigned long start, unsigned long end, int node)
                                if (!new_page)
                                        goto out;
                                pmd_val(*pm_dir) = __pa(new_page) |
-                                       _SEGMENT_ENTRY | _SEGMENT_ENTRY_LARGE |
-                                       _SEGMENT_ENTRY_CO;
+                                       _SEGMENT_ENTRY | _SEGMENT_ENTRY_LARGE;
                                address = (address + PMD_SIZE) & PMD_MASK;
                                continue;
                        }
@@ -253,9 +252,9 @@ int __meminit vmemmap_populate(unsigned long start, unsigned long end, int node)
 
                pt_dir = pte_offset_kernel(pm_dir, address);
                if (pte_none(*pt_dir)) {
-                       unsigned long new_page;
+                       void *new_page;
 
-                       new_page =__pa(vmem_alloc_pages(0));
+                       new_page = vmemmap_alloc_block(PAGE_SIZE, node);
                        if (!new_page)
                                goto out;
                        pte_val(*pt_dir) =
@@ -263,7 +262,6 @@ int __meminit vmemmap_populate(unsigned long start, unsigned long end, int node)
                }
                address += PAGE_SIZE;
        }
-       memset((void *)start, 0, end - start);
        ret = 0;
 out:
        return ret;
index a273c88578fc99d81cc4a2879d628372349b8fbd..97a5fda83450e74bde284fead9cd2f3a8b31200e 100644 (file)
@@ -1,85 +1,56 @@
 #ifndef __ASM_SH_ATOMIC_GRB_H
 #define __ASM_SH_ATOMIC_GRB_H
 
-static inline void atomic_add(int i, atomic_t *v)
-{
-       int tmp;
-
-       __asm__ __volatile__ (
-               "   .align 2              \n\t"
-               "   mova    1f,   r0      \n\t" /* r0 = end point */
-               "   mov    r15,   r1      \n\t" /* r1 = saved sp */
-               "   mov    #-6,   r15     \n\t" /* LOGIN: r15 = size */
-               "   mov.l  @%1,   %0      \n\t" /* load  old value */
-               "   add     %2,   %0      \n\t" /* add */
-               "   mov.l   %0,   @%1     \n\t" /* store new value */
-               "1: mov     r1,   r15     \n\t" /* LOGOUT */
-               : "=&r" (tmp),
-                 "+r"  (v)
-               : "r"   (i)
-               : "memory" , "r0", "r1");
-}
-
-static inline void atomic_sub(int i, atomic_t *v)
-{
-       int tmp;
-
-       __asm__ __volatile__ (
-               "   .align 2              \n\t"
-               "   mova    1f,   r0      \n\t" /* r0 = end point */
-               "   mov     r15,  r1      \n\t" /* r1 = saved sp */
-               "   mov    #-6,   r15     \n\t" /* LOGIN: r15 = size */
-               "   mov.l  @%1,   %0      \n\t" /* load  old value */
-               "   sub     %2,   %0      \n\t" /* sub */
-               "   mov.l   %0,   @%1     \n\t" /* store new value */
-               "1: mov     r1,   r15     \n\t" /* LOGOUT */
-               : "=&r" (tmp),
-                 "+r"  (v)
-               : "r"   (i)
-               : "memory" , "r0", "r1");
-}
-
-static inline int atomic_add_return(int i, atomic_t *v)
-{
-       int tmp;
+#define ATOMIC_OP(op)                                                  \
+static inline void atomic_##op(int i, atomic_t *v)                     \
+{                                                                      \
+       int tmp;                                                        \
+                                                                       \
+       __asm__ __volatile__ (                                          \
+               "   .align 2              \n\t"                         \
+               "   mova    1f,   r0      \n\t" /* r0 = end point */    \
+               "   mov    r15,   r1      \n\t" /* r1 = saved sp */     \
+               "   mov    #-6,   r15     \n\t" /* LOGIN: r15 = size */ \
+               "   mov.l  @%1,   %0      \n\t" /* load  old value */   \
+               " " #op "   %2,   %0      \n\t" /* $op */               \
+               "   mov.l   %0,   @%1     \n\t" /* store new value */   \
+               "1: mov     r1,   r15     \n\t" /* LOGOUT */            \
+               : "=&r" (tmp),                                          \
+                 "+r"  (v)                                             \
+               : "r"   (i)                                             \
+               : "memory" , "r0", "r1");                               \
+}                                                                      \
 
-       __asm__ __volatile__ (
-               "   .align 2              \n\t"
-               "   mova    1f,   r0      \n\t" /* r0 = end point */
-               "   mov    r15,   r1      \n\t" /* r1 = saved sp */
-               "   mov    #-6,   r15     \n\t" /* LOGIN: r15 = size */
-               "   mov.l  @%1,   %0      \n\t" /* load  old value */
-               "   add     %2,   %0      \n\t" /* add */
-               "   mov.l   %0,   @%1     \n\t" /* store new value */
-               "1: mov     r1,   r15     \n\t" /* LOGOUT */
-               : "=&r" (tmp),
-                 "+r"  (v)
-               : "r"   (i)
-               : "memory" , "r0", "r1");
-
-       return tmp;
+#define ATOMIC_OP_RETURN(op)                                           \
+static inline int atomic_##op##_return(int i, atomic_t *v)             \
+{                                                                      \
+       int tmp;                                                        \
+                                                                       \
+       __asm__ __volatile__ (                                          \
+               "   .align 2              \n\t"                         \
+               "   mova    1f,   r0      \n\t" /* r0 = end point */    \
+               "   mov    r15,   r1      \n\t" /* r1 = saved sp */     \
+               "   mov    #-6,   r15     \n\t" /* LOGIN: r15 = size */ \
+               "   mov.l  @%1,   %0      \n\t" /* load  old value */   \
+               " " #op "   %2,   %0      \n\t" /* $op */               \
+               "   mov.l   %0,   @%1     \n\t" /* store new value */   \
+               "1: mov     r1,   r15     \n\t" /* LOGOUT */            \
+               : "=&r" (tmp),                                          \
+                 "+r"  (v)                                             \
+               : "r"   (i)                                             \
+               : "memory" , "r0", "r1");                               \
+                                                                       \
+       return tmp;                                                     \
 }
 
-static inline int atomic_sub_return(int i, atomic_t *v)
-{
-       int tmp;
+#define ATOMIC_OPS(op) ATOMIC_OP(op) ATOMIC_OP_RETURN(op)
 
-       __asm__ __volatile__ (
-               "   .align 2              \n\t"
-               "   mova    1f,   r0      \n\t" /* r0 = end point */
-               "   mov    r15,   r1      \n\t" /* r1 = saved sp */
-               "   mov    #-6,   r15     \n\t" /* LOGIN: r15 = size */
-               "   mov.l  @%1,   %0      \n\t" /* load  old value */
-               "   sub     %2,   %0      \n\t" /* sub */
-               "   mov.l   %0,   @%1     \n\t" /* store new value */
-               "1: mov     r1,   r15     \n\t" /* LOGOUT */
-               : "=&r" (tmp),
-                 "+r"  (v)
-               : "r"   (i)
-               : "memory", "r0", "r1");
+ATOMIC_OPS(add)
+ATOMIC_OPS(sub)
 
-       return tmp;
-}
+#undef ATOMIC_OPS
+#undef ATOMIC_OP_RETURN
+#undef ATOMIC_OP
 
 static inline void atomic_clear_mask(unsigned int mask, atomic_t *v)
 {
index 9f7c56609e535b27365cd24777491de4d9a70c67..61d107523f0649245c138701e4e1f56b2f000d98 100644 (file)
@@ -8,49 +8,39 @@
  * forward to code at the end of this object's .text section, then
  * branch back to restart the operation.
  */
-static inline void atomic_add(int i, atomic_t *v)
-{
-       unsigned long flags;
-
-       raw_local_irq_save(flags);
-       v->counter += i;
-       raw_local_irq_restore(flags);
-}
 
-static inline void atomic_sub(int i, atomic_t *v)
-{
-       unsigned long flags;
-
-       raw_local_irq_save(flags);
-       v->counter -= i;
-       raw_local_irq_restore(flags);
+#define ATOMIC_OP(op, c_op)                                            \
+static inline void atomic_##op(int i, atomic_t *v)                     \
+{                                                                      \
+       unsigned long flags;                                            \
+                                                                       \
+       raw_local_irq_save(flags);                                      \
+       v->counter c_op i;                                              \
+       raw_local_irq_restore(flags);                                   \
 }
 
-static inline int atomic_add_return(int i, atomic_t *v)
-{
-       unsigned long temp, flags;
-
-       raw_local_irq_save(flags);
-       temp = v->counter;
-       temp += i;
-       v->counter = temp;
-       raw_local_irq_restore(flags);
-
-       return temp;
+#define ATOMIC_OP_RETURN(op, c_op)                                     \
+static inline int atomic_##op##_return(int i, atomic_t *v)             \
+{                                                                      \
+       unsigned long temp, flags;                                      \
+                                                                       \
+       raw_local_irq_save(flags);                                      \
+       temp = v->counter;                                              \
+       temp c_op i;                                                    \
+       v->counter = temp;                                              \
+       raw_local_irq_restore(flags);                                   \
+                                                                       \
+       return temp;                                                    \
 }
 
-static inline int atomic_sub_return(int i, atomic_t *v)
-{
-       unsigned long temp, flags;
+#define ATOMIC_OPS(op, c_op) ATOMIC_OP(op, c_op) ATOMIC_OP_RETURN(op, c_op)
 
-       raw_local_irq_save(flags);
-       temp = v->counter;
-       temp -= i;
-       v->counter = temp;
-       raw_local_irq_restore(flags);
+ATOMIC_OPS(add, +=)
+ATOMIC_OPS(sub, -=)
 
-       return temp;
-}
+#undef ATOMIC_OPS
+#undef ATOMIC_OP_RETURN
+#undef ATOMIC_OP
 
 static inline void atomic_clear_mask(unsigned int mask, atomic_t *v)
 {
index 4b00b78e3f4f3a6a5be4a70a924123c84f32c895..8575dccb9ef78165bcac39d8c6e8903466557a64 100644 (file)
@@ -1,39 +1,6 @@
 #ifndef __ASM_SH_ATOMIC_LLSC_H
 #define __ASM_SH_ATOMIC_LLSC_H
 
-/*
- * To get proper branch prediction for the main line, we must branch
- * forward to code at the end of this object's .text section, then
- * branch back to restart the operation.
- */
-static inline void atomic_add(int i, atomic_t *v)
-{
-       unsigned long tmp;
-
-       __asm__ __volatile__ (
-"1:    movli.l @%2, %0         ! atomic_add    \n"
-"      add     %1, %0                          \n"
-"      movco.l %0, @%2                         \n"
-"      bf      1b                              \n"
-       : "=&z" (tmp)
-       : "r" (i), "r" (&v->counter)
-       : "t");
-}
-
-static inline void atomic_sub(int i, atomic_t *v)
-{
-       unsigned long tmp;
-
-       __asm__ __volatile__ (
-"1:    movli.l @%2, %0         ! atomic_sub    \n"
-"      sub     %1, %0                          \n"
-"      movco.l %0, @%2                         \n"
-"      bf      1b                              \n"
-       : "=&z" (tmp)
-       : "r" (i), "r" (&v->counter)
-       : "t");
-}
-
 /*
  * SH-4A note:
  *
@@ -42,39 +9,53 @@ static inline void atomic_sub(int i, atomic_t *v)
  * encoding, so the retval is automatically set without having to
  * do any special work.
  */
-static inline int atomic_add_return(int i, atomic_t *v)
-{
-       unsigned long temp;
+/*
+ * To get proper branch prediction for the main line, we must branch
+ * forward to code at the end of this object's .text section, then
+ * branch back to restart the operation.
+ */
 
-       __asm__ __volatile__ (
-"1:    movli.l @%2, %0         ! atomic_add_return     \n"
-"      add     %1, %0                                  \n"
-"      movco.l %0, @%2                                 \n"
-"      bf      1b                                      \n"
-"      synco                                           \n"
-       : "=&z" (temp)
-       : "r" (i), "r" (&v->counter)
-       : "t");
+#define ATOMIC_OP(op)                                                  \
+static inline void atomic_##op(int i, atomic_t *v)                     \
+{                                                                      \
+       unsigned long tmp;                                              \
+                                                                       \
+       __asm__ __volatile__ (                                          \
+"1:    movli.l @%2, %0         ! atomic_" #op "\n"                     \
+"      " #op " %1, %0                          \n"                     \
+"      movco.l %0, @%2                         \n"                     \
+"      bf      1b                              \n"                     \
+       : "=&z" (tmp)                                                   \
+       : "r" (i), "r" (&v->counter)                                    \
+       : "t");                                                         \
+}
 
-       return temp;
+#define ATOMIC_OP_RETURN(op)                                           \
+static inline int atomic_##op##_return(int i, atomic_t *v)             \
+{                                                                      \
+       unsigned long temp;                                             \
+                                                                       \
+       __asm__ __volatile__ (                                          \
+"1:    movli.l @%2, %0         ! atomic_" #op "_return \n"             \
+"      " #op " %1, %0                                  \n"             \
+"      movco.l %0, @%2                                 \n"             \
+"      bf      1b                                      \n"             \
+"      synco                                           \n"             \
+       : "=&z" (temp)                                                  \
+       : "r" (i), "r" (&v->counter)                                    \
+       : "t");                                                         \
+                                                                       \
+       return temp;                                                    \
 }
 
-static inline int atomic_sub_return(int i, atomic_t *v)
-{
-       unsigned long temp;
+#define ATOMIC_OPS(op) ATOMIC_OP(op) ATOMIC_OP_RETURN(op)
 
-       __asm__ __volatile__ (
-"1:    movli.l @%2, %0         ! atomic_sub_return     \n"
-"      sub     %1, %0                                  \n"
-"      movco.l %0, @%2                                 \n"
-"      bf      1b                                      \n"
-"      synco                                           \n"
-       : "=&z" (temp)
-       : "r" (i), "r" (&v->counter)
-       : "t");
+ATOMIC_OPS(add)
+ATOMIC_OPS(sub)
 
-       return temp;
-}
+#undef ATOMIC_OPS
+#undef ATOMIC_OP_RETURN
+#undef ATOMIC_OP
 
 static inline void atomic_clear_mask(unsigned int mask, atomic_t *v)
 {
index f57b8a6743b30a24f3008623d8d72bf5deecd3f9..05b9f74ce2d544d3f9d7bede26cdc57c04a54e2c 100644 (file)
@@ -14,7 +14,7 @@
 
 #define ATOMIC_INIT(i) { (i) }
 
-#define atomic_read(v)         (*(volatile int *)&(v)->counter)
+#define atomic_read(v)         ACCESS_ONCE((v)->counter)
 #define atomic_set(v,i)                ((v)->counter = (i))
 
 #if defined(CONFIG_GUSA_RB)
index a537816613f99d952bab734ca0e97134cda468ac..96ac69c5eba016a7b5c1ef93fd35baccf8e2f52b 100644 (file)
@@ -67,6 +67,7 @@ config SPARC64
        select HAVE_SYSCALL_TRACEPOINTS
        select HAVE_CONTEXT_TRACKING
        select HAVE_DEBUG_KMEMLEAK
+       select SPARSE_IRQ
        select RTC_DRV_CMOS
        select RTC_DRV_BQ4802
        select RTC_DRV_SUN4V
index 7aed2be45b445b8a3d613f3343714bc3069b108e..765c1776ec9fd6e900e8c23f39e55af0bf2b316b 100644 (file)
 
 #define ATOMIC_INIT(i)  { (i) }
 
-int __atomic_add_return(int, atomic_t *);
+int atomic_add_return(int, atomic_t *);
 int atomic_cmpxchg(atomic_t *, int, int);
 #define atomic_xchg(v, new) (xchg(&((v)->counter), new))
 int __atomic_add_unless(atomic_t *, int, int);
 void atomic_set(atomic_t *, int);
 
-#define atomic_read(v)          (*(volatile int *)&(v)->counter)
+#define atomic_read(v)          ACCESS_ONCE((v)->counter)
 
-#define atomic_add(i, v)       ((void)__atomic_add_return( (int)(i), (v)))
-#define atomic_sub(i, v)       ((void)__atomic_add_return(-(int)(i), (v)))
-#define atomic_inc(v)          ((void)__atomic_add_return(        1, (v)))
-#define atomic_dec(v)          ((void)__atomic_add_return(       -1, (v)))
+#define atomic_add(i, v)       ((void)atomic_add_return( (int)(i), (v)))
+#define atomic_sub(i, v)       ((void)atomic_add_return(-(int)(i), (v)))
+#define atomic_inc(v)          ((void)atomic_add_return(        1, (v)))
+#define atomic_dec(v)          ((void)atomic_add_return(       -1, (v)))
 
-#define atomic_add_return(i, v)        (__atomic_add_return( (int)(i), (v)))
-#define atomic_sub_return(i, v)        (__atomic_add_return(-(int)(i), (v)))
-#define atomic_inc_return(v)   (__atomic_add_return(        1, (v)))
-#define atomic_dec_return(v)   (__atomic_add_return(       -1, (v)))
+#define atomic_sub_return(i, v)        (atomic_add_return(-(int)(i), (v)))
+#define atomic_inc_return(v)   (atomic_add_return(        1, (v)))
+#define atomic_dec_return(v)   (atomic_add_return(       -1, (v)))
 
 #define atomic_add_negative(a, v)      (atomic_add_return((a), (v)) < 0)
 
index bb894c8bec562c337e3166c3509ba11334c864c2..4082749913ce06109a3bd923e0bef4677d0376c9 100644 (file)
 #define ATOMIC_INIT(i)         { (i) }
 #define ATOMIC64_INIT(i)       { (i) }
 
-#define atomic_read(v)         (*(volatile int *)&(v)->counter)
-#define atomic64_read(v)       (*(volatile long *)&(v)->counter)
+#define atomic_read(v)         ACCESS_ONCE((v)->counter)
+#define atomic64_read(v)       ACCESS_ONCE((v)->counter)
 
 #define atomic_set(v, i)       (((v)->counter) = i)
 #define atomic64_set(v, i)     (((v)->counter) = i)
 
-void atomic_add(int, atomic_t *);
-void atomic64_add(long, atomic64_t *);
-void atomic_sub(int, atomic_t *);
-void atomic64_sub(long, atomic64_t *);
+#define ATOMIC_OP(op)                                                  \
+void atomic_##op(int, atomic_t *);                                     \
+void atomic64_##op(long, atomic64_t *);
 
-int atomic_add_ret(int, atomic_t *);
-long atomic64_add_ret(long, atomic64_t *);
-int atomic_sub_ret(int, atomic_t *);
-long atomic64_sub_ret(long, atomic64_t *);
+#define ATOMIC_OP_RETURN(op)                                           \
+int atomic_##op##_return(int, atomic_t *);                             \
+long atomic64_##op##_return(long, atomic64_t *);
 
-#define atomic_dec_return(v) atomic_sub_ret(1, v)
-#define atomic64_dec_return(v) atomic64_sub_ret(1, v)
+#define ATOMIC_OPS(op) ATOMIC_OP(op) ATOMIC_OP_RETURN(op)
 
-#define atomic_inc_return(v) atomic_add_ret(1, v)
-#define atomic64_inc_return(v) atomic64_add_ret(1, v)
+ATOMIC_OPS(add)
+ATOMIC_OPS(sub)
 
-#define atomic_sub_return(i, v) atomic_sub_ret(i, v)
-#define atomic64_sub_return(i, v) atomic64_sub_ret(i, v)
+#undef ATOMIC_OPS
+#undef ATOMIC_OP_RETURN
+#undef ATOMIC_OP
 
-#define atomic_add_return(i, v) atomic_add_ret(i, v)
-#define atomic64_add_return(i, v) atomic64_add_ret(i, v)
+#define atomic_dec_return(v)   atomic_sub_return(1, v)
+#define atomic64_dec_return(v) atomic64_sub_return(1, v)
+
+#define atomic_inc_return(v)   atomic_add_return(1, v)
+#define atomic64_inc_return(v) atomic64_add_return(1, v)
 
 /*
  * atomic_inc_and_test - increment and test
@@ -53,11 +54,11 @@ long atomic64_sub_ret(long, atomic64_t *);
 #define atomic_inc_and_test(v) (atomic_inc_return(v) == 0)
 #define atomic64_inc_and_test(v) (atomic64_inc_return(v) == 0)
 
-#define atomic_sub_and_test(i, v) (atomic_sub_ret(i, v) == 0)
-#define atomic64_sub_and_test(i, v) (atomic64_sub_ret(i, v) == 0)
+#define atomic_sub_and_test(i, v) (atomic_sub_return(i, v) == 0)
+#define atomic64_sub_and_test(i, v) (atomic64_sub_return(i, v) == 0)
 
-#define atomic_dec_and_test(v) (atomic_sub_ret(1, v) == 0)
-#define atomic64_dec_and_test(v) (atomic64_sub_ret(1, v) == 0)
+#define atomic_dec_and_test(v) (atomic_sub_return(1, v) == 0)
+#define atomic64_dec_and_test(v) (atomic64_sub_return(1, v) == 0)
 
 #define atomic_inc(v) atomic_add(1, v)
 #define atomic64_inc(v) atomic64_add(1, v)
@@ -65,8 +66,8 @@ long atomic64_sub_ret(long, atomic64_t *);
 #define atomic_dec(v) atomic_sub(1, v)
 #define atomic64_dec(v) atomic64_sub(1, v)
 
-#define atomic_add_negative(i, v) (atomic_add_ret(i, v) < 0)
-#define atomic64_add_negative(i, v) (atomic64_add_ret(i, v) < 0)
+#define atomic_add_negative(i, v) (atomic_add_return(i, v) < 0)
+#define atomic64_add_negative(i, v) (atomic64_add_return(i, v) < 0)
 
 #define atomic_cmpxchg(v, o, n) (cmpxchg(&((v)->counter), (o), (n)))
 #define atomic_xchg(v, new) (xchg(&((v)->counter), new))
index 1ee02710b2dc61b47c8a9494995bcf1e21287cce..5b1b52a04ad6283fb67308d9bf84b08494870140 100644 (file)
@@ -20,10 +20,12 @@ extern struct bus_type pci_bus_type;
 
 static inline struct dma_map_ops *get_dma_ops(struct device *dev)
 {
-#if defined(CONFIG_SPARC32) && defined(CONFIG_PCI)
+#ifdef CONFIG_SPARC_LEON
        if (sparc_cpu_model == sparc_leon)
                return leon_dma_ops;
-       else if (dev->bus == &pci_bus_type)
+#endif
+#if defined(CONFIG_SPARC32) && defined(CONFIG_PCI)
+       if (dev->bus == &pci_bus_type)
                return &pci32_dma_ops;
 #endif
        return dma_ops;
index 94b39caea3ebabf262c2322cb9a3d8756400aa56..4f6725ff4c336878fd3600f840f81897fdc65099 100644 (file)
@@ -2947,6 +2947,16 @@ unsigned long sun4v_vt_set_perfreg(unsigned long reg_num,
                                   unsigned long reg_val);
 #endif
 
+#define        HV_FAST_T5_GET_PERFREG          0x1a8
+#define        HV_FAST_T5_SET_PERFREG          0x1a9
+
+#ifndef        __ASSEMBLY__
+unsigned long sun4v_t5_get_perfreg(unsigned long reg_num,
+                                  unsigned long *reg_val);
+unsigned long sun4v_t5_set_perfreg(unsigned long reg_num,
+                                  unsigned long reg_val);
+#endif
+
 /* Function numbers for HV_CORE_TRAP.  */
 #define HV_CORE_SET_VER                        0x00
 #define HV_CORE_PUTCHAR                        0x01
@@ -2978,6 +2988,7 @@ unsigned long sun4v_vt_set_perfreg(unsigned long reg_num,
 #define HV_GRP_VF_CPU                  0x0205
 #define HV_GRP_KT_CPU                  0x0209
 #define HV_GRP_VT_CPU                  0x020c
+#define HV_GRP_T5_CPU                  0x0211
 #define HV_GRP_DIAG                    0x0300
 
 #ifndef __ASSEMBLY__
index 91d2193813069eb8d7e4572dc48269a8d9d50812..3f70f900e834203f0974169ebe95380442486d1f 100644 (file)
@@ -37,7 +37,7 @@
  *
  * ino_bucket->irq allocation is made during {sun4v_,}build_irq().
  */
-#define NR_IRQS    255
+#define NR_IRQS                (2048)
 
 void irq_install_pre_handler(int irq,
                             void (*func)(unsigned int, void *, void *),
@@ -57,11 +57,8 @@ unsigned int sun4u_build_msi(u32 portid, unsigned int *irq_p,
                             unsigned long iclr_base);
 void sun4u_destroy_msi(unsigned int irq);
 
-unsigned char irq_alloc(unsigned int dev_handle,
-                       unsigned int dev_ino);
-#ifdef CONFIG_PCI_MSI
+unsigned int irq_alloc(unsigned int dev_handle, unsigned int dev_ino);
 void irq_free(unsigned int irq);
-#endif
 
 void __init init_IRQ(void);
 void fixup_irqs(void);
index c8c67f621f4f445f9842c4a392843475c909a7c3..58ab64de25d2ce7133c8af67882d37a478f51d78 100644 (file)
@@ -53,13 +53,14 @@ struct ldc_channel;
 /* Allocate state for a channel.  */
 struct ldc_channel *ldc_alloc(unsigned long id,
                              const struct ldc_channel_config *cfgp,
-                             void *event_arg);
+                             void *event_arg,
+                             const char *name);
 
 /* Shut down and free state for a channel.  */
 void ldc_free(struct ldc_channel *lp);
 
 /* Register TX and RX queues of the link with the hypervisor.  */
-int ldc_bind(struct ldc_channel *lp, const char *name);
+int ldc_bind(struct ldc_channel *lp);
 
 /* For non-RAW protocols we need to complete a handshake before
  * communication can proceed.  ldc_connect() does that, if the
index bf109984a03238be02980c92bdc70c55f523fb8f..8c2a8c937540ffebb206576d06334bb8ba1a2438 100644 (file)
@@ -57,18 +57,21 @@ void copy_user_page(void *to, void *from, unsigned long vaddr, struct page *topa
 typedef struct { unsigned long pte; } pte_t;
 typedef struct { unsigned long iopte; } iopte_t;
 typedef struct { unsigned long pmd; } pmd_t;
+typedef struct { unsigned long pud; } pud_t;
 typedef struct { unsigned long pgd; } pgd_t;
 typedef struct { unsigned long pgprot; } pgprot_t;
 
 #define pte_val(x)     ((x).pte)
 #define iopte_val(x)   ((x).iopte)
 #define pmd_val(x)      ((x).pmd)
+#define pud_val(x)      ((x).pud)
 #define pgd_val(x)     ((x).pgd)
 #define pgprot_val(x)  ((x).pgprot)
 
 #define __pte(x)       ((pte_t) { (x) } )
 #define __iopte(x)     ((iopte_t) { (x) } )
 #define __pmd(x)        ((pmd_t) { (x) } )
+#define __pud(x)        ((pud_t) { (x) } )
 #define __pgd(x)       ((pgd_t) { (x) } )
 #define __pgprot(x)    ((pgprot_t) { (x) } )
 
@@ -77,18 +80,21 @@ typedef struct { unsigned long pgprot; } pgprot_t;
 typedef unsigned long pte_t;
 typedef unsigned long iopte_t;
 typedef unsigned long pmd_t;
+typedef unsigned long pud_t;
 typedef unsigned long pgd_t;
 typedef unsigned long pgprot_t;
 
 #define pte_val(x)     (x)
 #define iopte_val(x)   (x)
 #define pmd_val(x)      (x)
+#define pud_val(x)      (x)
 #define pgd_val(x)     (x)
 #define pgprot_val(x)  (x)
 
 #define __pte(x)       (x)
 #define __iopte(x)     (x)
 #define __pmd(x)        (x)
+#define __pud(x)        (x)
 #define __pgd(x)       (x)
 #define __pgprot(x)    (x)
 
@@ -96,21 +102,14 @@ typedef unsigned long pgprot_t;
 
 typedef pte_t *pgtable_t;
 
-/* These two values define the virtual address space range in which we
- * must forbid 64-bit user processes from making mappings.  It used to
- * represent precisely the virtual address space hole present in most
- * early sparc64 chips including UltraSPARC-I.  But now it also is
- * further constrained by the limits of our page tables, which is
- * 43-bits of virtual address.
- */
-#define SPARC64_VA_HOLE_TOP    _AC(0xfffffc0000000000,UL)
-#define SPARC64_VA_HOLE_BOTTOM _AC(0x0000040000000000,UL)
+extern unsigned long sparc64_va_hole_top;
+extern unsigned long sparc64_va_hole_bottom;
 
 /* The next two defines specify the actual exclusion region we
  * enforce, wherein we use a 4GB red zone on each side of the VA hole.
  */
-#define VA_EXCLUDE_START (SPARC64_VA_HOLE_BOTTOM - (1UL << 32UL))
-#define VA_EXCLUDE_END   (SPARC64_VA_HOLE_TOP + (1UL << 32UL))
+#define VA_EXCLUDE_START (sparc64_va_hole_bottom - (1UL << 32UL))
+#define VA_EXCLUDE_END   (sparc64_va_hole_top + (1UL << 32UL))
 
 #define TASK_UNMAPPED_BASE     (test_thread_flag(TIF_32BIT) ? \
                                 _AC(0x0000000070000000,UL) : \
@@ -118,20 +117,16 @@ typedef pte_t *pgtable_t;
 
 #include <asm-generic/memory_model.h>
 
-#define PAGE_OFFSET_BY_BITS(X) (-(_AC(1,UL) << (X)))
 extern unsigned long PAGE_OFFSET;
 
 #endif /* !(__ASSEMBLY__) */
 
-/* The maximum number of physical memory address bits we support, this
- * is used to size various tables used to manage kernel TLB misses and
- * also the sparsemem code.
+/* The maximum number of physical memory address bits we support.  The
+ * largest value we can support is whatever "KPGD_SHIFT + KPTE_BITS"
+ * evaluates to.
  */
-#define MAX_PHYS_ADDRESS_BITS  47
+#define MAX_PHYS_ADDRESS_BITS  53
 
-/* These two shift counts are used when indexing sparc64_valid_addr_bitmap
- * and kpte_linear_bitmap.
- */
 #define ILOG2_4MB              22
 #define ILOG2_256MB            28
 
index 39a7ac49b00c71353ef9e9f0a1a555187ab0457b..5e3187185b4a8b9c3f22d4a67ea538a12fdcd9e7 100644 (file)
 
 extern struct kmem_cache *pgtable_cache;
 
+static inline void __pgd_populate(pgd_t *pgd, pud_t *pud)
+{
+       pgd_set(pgd, pud);
+}
+
+#define pgd_populate(MM, PGD, PUD)     __pgd_populate(PGD, PUD)
+
 static inline pgd_t *pgd_alloc(struct mm_struct *mm)
 {
        return kmem_cache_alloc(pgtable_cache, GFP_KERNEL);
@@ -25,7 +32,23 @@ static inline void pgd_free(struct mm_struct *mm, pgd_t *pgd)
        kmem_cache_free(pgtable_cache, pgd);
 }
 
-#define pud_populate(MM, PUD, PMD)     pud_set(PUD, PMD)
+static inline void __pud_populate(pud_t *pud, pmd_t *pmd)
+{
+       pud_set(pud, pmd);
+}
+
+#define pud_populate(MM, PUD, PMD)     __pud_populate(PUD, PMD)
+
+static inline pud_t *pud_alloc_one(struct mm_struct *mm, unsigned long addr)
+{
+       return kmem_cache_alloc(pgtable_cache,
+                               GFP_KERNEL|__GFP_REPEAT);
+}
+
+static inline void pud_free(struct mm_struct *mm, pud_t *pud)
+{
+       kmem_cache_free(pgtable_cache, pud);
+}
 
 static inline pmd_t *pmd_alloc_one(struct mm_struct *mm, unsigned long addr)
 {
@@ -91,4 +114,7 @@ static inline void __pte_free_tlb(struct mmu_gather *tlb, pte_t *pte,
 #define __pmd_free_tlb(tlb, pmd, addr)               \
        pgtable_free_tlb(tlb, pmd, false)
 
+#define __pud_free_tlb(tlb, pud, addr)               \
+       pgtable_free_tlb(tlb, pud, false)
+
 #endif /* _SPARC64_PGALLOC_H */
index 3770bf5c6e1b434feedd15150a23aaac0b15e51e..bfeb626085ac3964fb1f9c31a17092a98728a3b6 100644 (file)
@@ -20,8 +20,6 @@
 #include <asm/page.h>
 #include <asm/processor.h>
 
-#include <asm-generic/pgtable-nopud.h>
-
 /* The kernel image occupies 0x4000000 to 0x6000000 (4MB --> 96MB).
  * The page copy blockops can use 0x6000000 to 0x8000000.
  * The 8K TSB is mapped in the 0x8000000 to 0x8400000 range.
 #define LOW_OBP_ADDRESS                _AC(0x00000000f0000000,UL)
 #define HI_OBP_ADDRESS         _AC(0x0000000100000000,UL)
 #define VMALLOC_START          _AC(0x0000000100000000,UL)
-#define VMALLOC_END            _AC(0x0000010000000000,UL)
-#define VMEMMAP_BASE           _AC(0x0000010000000000,UL)
-
-#define vmemmap                        ((struct page *)VMEMMAP_BASE)
+#define VMEMMAP_BASE           VMALLOC_END
 
 /* PMD_SHIFT determines the size of the area a second-level page
  * table can map
 #define PMD_MASK       (~(PMD_SIZE-1))
 #define PMD_BITS       (PAGE_SHIFT - 3)
 
-/* PGDIR_SHIFT determines what a third-level page table entry can map */
-#define PGDIR_SHIFT    (PAGE_SHIFT + (PAGE_SHIFT-3) + PMD_BITS)
+/* PUD_SHIFT determines the size of the area a third-level page
+ * table can map
+ */
+#define PUD_SHIFT      (PMD_SHIFT + PMD_BITS)
+#define PUD_SIZE       (_AC(1,UL) << PUD_SHIFT)
+#define PUD_MASK       (~(PUD_SIZE-1))
+#define PUD_BITS       (PAGE_SHIFT - 3)
+
+/* PGDIR_SHIFT determines what a fourth-level page table entry can map */
+#define PGDIR_SHIFT    (PUD_SHIFT + PUD_BITS)
 #define PGDIR_SIZE     (_AC(1,UL) << PGDIR_SHIFT)
 #define PGDIR_MASK     (~(PGDIR_SIZE-1))
 #define PGDIR_BITS     (PAGE_SHIFT - 3)
 
-#if (PGDIR_SHIFT + PGDIR_BITS) != 43
+#if (MAX_PHYS_ADDRESS_BITS > PGDIR_SHIFT + PGDIR_BITS)
+#error MAX_PHYS_ADDRESS_BITS exceeds what kernel page tables can support
+#endif
+
+#if (PGDIR_SHIFT + PGDIR_BITS) != 53
 #error Page table parameters do not cover virtual address space properly.
 #endif
 
 
 #ifndef __ASSEMBLY__
 
-#include <linux/sched.h>
-
-extern unsigned long sparc64_valid_addr_bitmap[];
+extern unsigned long VMALLOC_END;
 
-/* Needs to be defined here and not in linux/mm.h, as it is arch dependent */
-static inline bool __kern_addr_valid(unsigned long paddr)
-{
-       if ((paddr >> MAX_PHYS_ADDRESS_BITS) != 0UL)
-               return false;
-       return test_bit(paddr >> ILOG2_4MB, sparc64_valid_addr_bitmap);
-}
+#define vmemmap                        ((struct page *)VMEMMAP_BASE)
 
-static inline bool kern_addr_valid(unsigned long addr)
-{
-       unsigned long paddr = __pa(addr);
+#include <linux/sched.h>
 
-       return __kern_addr_valid(paddr);
-}
+bool kern_addr_valid(unsigned long addr);
 
 /* Entries per page directory level. */
 #define PTRS_PER_PTE   (1UL << (PAGE_SHIFT-3))
 #define PTRS_PER_PMD   (1UL << PMD_BITS)
+#define PTRS_PER_PUD   (1UL << PUD_BITS)
 #define PTRS_PER_PGD   (1UL << PGDIR_BITS)
 
 /* Kernel has a separate 44bit address space. */
@@ -101,6 +98,9 @@ static inline bool kern_addr_valid(unsigned long addr)
 #define pmd_ERROR(e)                                                   \
        pr_err("%s:%d: bad pmd %p(%016lx) seen at (%pS)\n",             \
               __FILE__, __LINE__, &(e), pmd_val(e), __builtin_return_address(0))
+#define pud_ERROR(e)                                                   \
+       pr_err("%s:%d: bad pud %p(%016lx) seen at (%pS)\n",             \
+              __FILE__, __LINE__, &(e), pud_val(e), __builtin_return_address(0))
 #define pgd_ERROR(e)                                                   \
        pr_err("%s:%d: bad pgd %p(%016lx) seen at (%pS)\n",             \
               __FILE__, __LINE__, &(e), pgd_val(e), __builtin_return_address(0))
@@ -112,6 +112,7 @@ static inline bool kern_addr_valid(unsigned long addr)
 #define _PAGE_R                  _AC(0x8000000000000000,UL) /* Keep ref bit uptodate*/
 #define _PAGE_SPECIAL     _AC(0x0200000000000000,UL) /* Special page         */
 #define _PAGE_PMD_HUGE    _AC(0x0100000000000000,UL) /* Huge page            */
+#define _PAGE_PUD_HUGE    _PAGE_PMD_HUGE
 
 /* Advertise support for _PAGE_SPECIAL */
 #define __HAVE_ARCH_PTE_SPECIAL
@@ -658,26 +659,26 @@ static inline unsigned long pmd_large(pmd_t pmd)
        return pte_val(pte) & _PAGE_PMD_HUGE;
 }
 
-#ifdef CONFIG_TRANSPARENT_HUGEPAGE
-static inline unsigned long pmd_young(pmd_t pmd)
+static inline unsigned long pmd_pfn(pmd_t pmd)
 {
        pte_t pte = __pte(pmd_val(pmd));
 
-       return pte_young(pte);
+       return pte_pfn(pte);
 }
 
-static inline unsigned long pmd_write(pmd_t pmd)
+#ifdef CONFIG_TRANSPARENT_HUGEPAGE
+static inline unsigned long pmd_young(pmd_t pmd)
 {
        pte_t pte = __pte(pmd_val(pmd));
 
-       return pte_write(pte);
+       return pte_young(pte);
 }
 
-static inline unsigned long pmd_pfn(pmd_t pmd)
+static inline unsigned long pmd_write(pmd_t pmd)
 {
        pte_t pte = __pte(pmd_val(pmd));
 
-       return pte_pfn(pte);
+       return pte_write(pte);
 }
 
 static inline unsigned long pmd_trans_huge(pmd_t pmd)
@@ -771,13 +772,15 @@ static inline int pmd_present(pmd_t pmd)
  * the top bits outside of the range of any physical address size we
  * support are clear as well.  We also validate the physical itself.
  */
-#define pmd_bad(pmd)                   ((pmd_val(pmd) & ~PAGE_MASK) || \
-                                        !__kern_addr_valid(pmd_val(pmd)))
+#define pmd_bad(pmd)                   (pmd_val(pmd) & ~PAGE_MASK)
 
 #define pud_none(pud)                  (!pud_val(pud))
 
-#define pud_bad(pud)                   ((pud_val(pud) & ~PAGE_MASK) || \
-                                        !__kern_addr_valid(pud_val(pud)))
+#define pud_bad(pud)                   (pud_val(pud) & ~PAGE_MASK)
+
+#define pgd_none(pgd)                  (!pgd_val(pgd))
+
+#define pgd_bad(pgd)                   (pgd_val(pgd) & ~PAGE_MASK)
 
 #ifdef CONFIG_TRANSPARENT_HUGEPAGE
 void set_pmd_at(struct mm_struct *mm, unsigned long addr,
@@ -815,10 +818,31 @@ static inline unsigned long __pmd_page(pmd_t pmd)
 #define pmd_clear(pmdp)                        (pmd_val(*(pmdp)) = 0UL)
 #define pud_present(pud)               (pud_val(pud) != 0U)
 #define pud_clear(pudp)                        (pud_val(*(pudp)) = 0UL)
+#define pgd_page_vaddr(pgd)            \
+       ((unsigned long) __va(pgd_val(pgd)))
+#define pgd_present(pgd)               (pgd_val(pgd) != 0U)
+#define pgd_clear(pgdp)                        (pgd_val(*(pgd)) = 0UL)
+
+static inline unsigned long pud_large(pud_t pud)
+{
+       pte_t pte = __pte(pud_val(pud));
+
+       return pte_val(pte) & _PAGE_PMD_HUGE;
+}
+
+static inline unsigned long pud_pfn(pud_t pud)
+{
+       pte_t pte = __pte(pud_val(pud));
+
+       return pte_pfn(pte);
+}
 
 /* Same in both SUN4V and SUN4U.  */
 #define pte_none(pte)                  (!pte_val(pte))
 
+#define pgd_set(pgdp, pudp)    \
+       (pgd_val(*(pgdp)) = (__pa((unsigned long) (pudp))))
+
 /* to find an entry in a page-table-directory. */
 #define pgd_index(address)     (((address) >> PGDIR_SHIFT) & (PTRS_PER_PGD - 1))
 #define pgd_offset(mm, address)        ((mm)->pgd + pgd_index(address))
@@ -826,6 +850,11 @@ static inline unsigned long __pmd_page(pmd_t pmd)
 /* to find an entry in a kernel page-table-directory */
 #define pgd_offset_k(address) pgd_offset(&init_mm, address)
 
+/* Find an entry in the third-level page table.. */
+#define pud_index(address)     (((address) >> PUD_SHIFT) & (PTRS_PER_PUD - 1))
+#define pud_offset(pgdp, address)      \
+       ((pud_t *) pgd_page_vaddr(*(pgdp)) + pud_index(address))
+
 /* Find an entry in the second-level page table.. */
 #define pmd_offset(pudp, address)      \
        ((pmd_t *) pud_page_vaddr(*(pudp)) + \
@@ -898,7 +927,6 @@ static inline void __set_pte_at(struct mm_struct *mm, unsigned long addr,
 #endif
 
 extern pgd_t swapper_pg_dir[PTRS_PER_PGD];
-extern pmd_t swapper_low_pmd_dir[PTRS_PER_PMD];
 
 void paging_init(void);
 unsigned long find_ecache_flush_span(unsigned long size);
index 3fc58691dbd0d45311bacec9ddf61fb7e7d9e0c4..56f933816144d47bf96506d09d3249445bc0fe32 100644 (file)
@@ -45,6 +45,8 @@
 #define SUN4V_CHIP_NIAGARA3    0x03
 #define SUN4V_CHIP_NIAGARA4    0x04
 #define SUN4V_CHIP_NIAGARA5    0x05
+#define SUN4V_CHIP_SPARC_M6    0x06
+#define SUN4V_CHIP_SPARC_M7    0x07
 #define SUN4V_CHIP_SPARC64X    0x8a
 #define SUN4V_CHIP_UNKNOWN     0xff
 
index a5f01ac6d0f1a2619cdac6b639248cb5a7153dac..f85dc8512ab3f6fdea1f1430aa8141bdccec2d44 100644 (file)
@@ -102,6 +102,7 @@ struct thread_info {
 #define FAULT_CODE_ITLB                0x04    /* Miss happened in I-TLB          */
 #define FAULT_CODE_WINFIXUP    0x08    /* Miss happened during spill/fill */
 #define FAULT_CODE_BLKCOMMIT   0x10    /* Use blk-commit ASI in copy_page */
+#define        FAULT_CODE_BAD_RA       0x20    /* Bad RA for sun4v                */
 
 #if PAGE_SHIFT == 13
 #define THREAD_SIZE (2*PAGE_SIZE)
index 90916f955cac80153c59dc74a768c3fdef3fae56..ecb49cfa3be9fa274053fb15bc2d5f3c38c76e08 100644 (file)
@@ -133,9 +133,24 @@ extern struct tsb_phys_patch_entry __tsb_phys_patch, __tsb_phys_patch_end;
        sub     TSB, 0x8, TSB;   \
        TSB_STORE(TSB, TAG);
 
-       /* Do a kernel page table walk.  Leaves physical PTE pointer in
-        * REG1.  Jumps to FAIL_LABEL on early page table walk termination.
-        * VADDR will not be clobbered, but REG2 will.
+       /* Do a kernel page table walk.  Leaves valid PTE value in
+        * REG1.  Jumps to FAIL_LABEL on early page table walk
+        * termination.  VADDR will not be clobbered, but REG2 will.
+        *
+        * There are two masks we must apply to propagate bits from
+        * the virtual address into the PTE physical address field
+        * when dealing with huge pages.  This is because the page
+        * table boundaries do not match the huge page size(s) the
+        * hardware supports.
+        *
+        * In these cases we propagate the bits that are below the
+        * page table level where we saw the huge page mapping, but
+        * are still within the relevant physical bits for the huge
+        * page size in question.  So for PMD mappings (which fall on
+        * bit 23, for 8MB per PMD) we must propagate bit 22 for a
+        * 4MB huge page.  For huge PUDs (which fall on bit 33, for
+        * 8GB per PUD), we have to accomodate 256MB and 2GB huge
+        * pages.  So for those we propagate bits 32 to 28.
         */
 #define KERN_PGTABLE_WALK(VADDR, REG1, REG2, FAIL_LABEL)       \
        sethi           %hi(swapper_pg_dir), REG1; \
@@ -145,15 +160,40 @@ extern struct tsb_phys_patch_entry __tsb_phys_patch, __tsb_phys_patch_end;
        andn            REG2, 0x7, REG2; \
        ldx             [REG1 + REG2], REG1; \
        brz,pn          REG1, FAIL_LABEL; \
-        sllx           VADDR, 64 - (PMD_SHIFT + PMD_BITS), REG2; \
+        sllx           VADDR, 64 - (PUD_SHIFT + PUD_BITS), REG2; \
        srlx            REG2, 64 - PAGE_SHIFT, REG2; \
        andn            REG2, 0x7, REG2; \
        ldxa            [REG1 + REG2] ASI_PHYS_USE_EC, REG1; \
        brz,pn          REG1, FAIL_LABEL; \
-        sllx           VADDR, 64 - PMD_SHIFT, REG2; \
+       sethi           %uhi(_PAGE_PUD_HUGE), REG2; \
+       brz,pn          REG1, FAIL_LABEL; \
+        sllx           REG2, 32, REG2; \
+       andcc           REG1, REG2, %g0; \
+       sethi           %hi(0xf8000000), REG2; \
+       bne,pt          %xcc, 697f; \
+        sllx           REG2, 1, REG2; \
+       sllx            VADDR, 64 - (PMD_SHIFT + PMD_BITS), REG2; \
        srlx            REG2, 64 - PAGE_SHIFT, REG2; \
        andn            REG2, 0x7, REG2; \
-       add             REG1, REG2, REG1;
+       ldxa            [REG1 + REG2] ASI_PHYS_USE_EC, REG1; \
+       sethi           %uhi(_PAGE_PMD_HUGE), REG2; \
+       brz,pn          REG1, FAIL_LABEL; \
+        sllx           REG2, 32, REG2; \
+       andcc           REG1, REG2, %g0; \
+       be,pn           %xcc, 698f; \
+        sethi          %hi(0x400000), REG2; \
+697:   brgez,pn        REG1, FAIL_LABEL; \
+        andn           REG1, REG2, REG1; \
+       and             VADDR, REG2, REG2; \
+       ba,pt           %xcc, 699f; \
+        or             REG1, REG2, REG1; \
+698:   sllx            VADDR, 64 - PMD_SHIFT, REG2; \
+       srlx            REG2, 64 - PAGE_SHIFT, REG2; \
+       andn            REG2, 0x7, REG2; \
+       ldxa            [REG1 + REG2] ASI_PHYS_USE_EC, REG1; \
+       brgez,pn        REG1, FAIL_LABEL; \
+        nop; \
+699:
 
        /* PMD has been loaded into REG1, interpret the value, seeing
         * if it is a HUGE PMD or a normal one.  If it is not valid
@@ -197,6 +237,11 @@ extern struct tsb_phys_patch_entry __tsb_phys_patch, __tsb_phys_patch_end;
        srlx            REG2, 64 - PAGE_SHIFT, REG2; \
        andn            REG2, 0x7, REG2; \
        ldxa            [PHYS_PGD + REG2] ASI_PHYS_USE_EC, REG1; \
+       brz,pn          REG1, FAIL_LABEL; \
+        sllx           VADDR, 64 - (PUD_SHIFT + PUD_BITS), REG2; \
+       srlx            REG2, 64 - PAGE_SHIFT, REG2; \
+       andn            REG2, 0x7, REG2; \
+       ldxa            [REG1 + REG2] ASI_PHYS_USE_EC, REG1; \
        brz,pn          REG1, FAIL_LABEL; \
         sllx           VADDR, 64 - (PMD_SHIFT + PMD_BITS), REG2; \
        srlx            REG2, 64 - PAGE_SHIFT, REG2; \
@@ -246,8 +291,6 @@ extern struct tsb_phys_patch_entry __tsb_phys_patch, __tsb_phys_patch_end;
        (KERNEL_TSB_SIZE_BYTES / 16)
 #define KERNEL_TSB4M_NENTRIES  4096
 
-#define KTSB_PHYS_SHIFT                15
-
        /* Do a kernel TSB lookup at tl>0 on VADDR+TAG, branch to OK_LABEL
         * on TSB hit.  REG1, REG2, REG3, and REG4 are used as temporaries
         * and the found TTE will be left in REG1.  REG3 and REG4 must
@@ -256,17 +299,15 @@ extern struct tsb_phys_patch_entry __tsb_phys_patch, __tsb_phys_patch_end;
         * VADDR and TAG will be preserved and not clobbered by this macro.
         */
 #define KERN_TSB_LOOKUP_TL1(VADDR, TAG, REG1, REG2, REG3, REG4, OK_LABEL) \
-661:   sethi           %hi(swapper_tsb), REG1;                 \
-       or              REG1, %lo(swapper_tsb), REG1; \
+661:   sethi           %uhi(swapper_tsb), REG1; \
+       sethi           %hi(swapper_tsb), REG2; \
+       or              REG1, %ulo(swapper_tsb), REG1; \
+       or              REG2, %lo(swapper_tsb), REG2; \
        .section        .swapper_tsb_phys_patch, "ax"; \
        .word           661b; \
        .previous; \
-661:   nop; \
-       .section        .tsb_ldquad_phys_patch, "ax"; \
-       .word           661b; \
-       sllx            REG1, KTSB_PHYS_SHIFT, REG1; \
-       sllx            REG1, KTSB_PHYS_SHIFT, REG1; \
-       .previous; \
+       sllx            REG1, 32, REG1; \
+       or              REG1, REG2, REG1; \
        srlx            VADDR, PAGE_SHIFT, REG2; \
        and             REG2, (KERNEL_TSB_NENTRIES - 1), REG2; \
        sllx            REG2, 4, REG2; \
@@ -281,17 +322,15 @@ extern struct tsb_phys_patch_entry __tsb_phys_patch, __tsb_phys_patch_end;
         * we can make use of that for the index computation.
         */
 #define KERN_TSB4M_LOOKUP_TL1(TAG, REG1, REG2, REG3, REG4, OK_LABEL) \
-661:   sethi           %hi(swapper_4m_tsb), REG1;           \
-       or              REG1, %lo(swapper_4m_tsb), REG1; \
+661:   sethi           %uhi(swapper_4m_tsb), REG1; \
+       sethi           %hi(swapper_4m_tsb), REG2; \
+       or              REG1, %ulo(swapper_4m_tsb), REG1; \
+       or              REG2, %lo(swapper_4m_tsb), REG2; \
        .section        .swapper_4m_tsb_phys_patch, "ax"; \
        .word           661b; \
        .previous; \
-661:   nop; \
-       .section        .tsb_ldquad_phys_patch, "ax"; \
-       .word           661b; \
-       sllx            REG1, KTSB_PHYS_SHIFT, REG1; \
-       sllx            REG1, KTSB_PHYS_SHIFT, REG1; \
-       .previous; \
+       sllx            REG1, 32, REG1; \
+       or              REG1, REG2, REG1; \
        and             TAG, (KERNEL_TSB4M_NENTRIES - 1), REG2; \
        sllx            REG2, 4, REG2; \
        add             REG1, REG2, REG2; \
index 6b135a8ab07bfdca9d8c2aa066d104a92bbb68e6..d758c8d8f47d90b9cefc18fc5ba973692b122a41 100644 (file)
@@ -121,12 +121,18 @@ struct vio_disk_attr_info {
        u8                      vdisk_type;
 #define VD_DISK_TYPE_SLICE     0x01 /* Slice in block device   */
 #define VD_DISK_TYPE_DISK      0x02 /* Entire block device     */
-       u16                     resv1;
+       u8                      vdisk_mtype;            /* v1.1 */
+#define VD_MEDIA_TYPE_FIXED    0x01 /* Fixed device */
+#define VD_MEDIA_TYPE_CD       0x02 /* CD Device    */
+#define VD_MEDIA_TYPE_DVD      0x03 /* DVD Device   */
+       u8                      resv1;
        u32                     vdisk_block_size;
        u64                     operations;
-       u64                     vdisk_size;
+       u64                     vdisk_size;             /* v1.1 */
        u64                     max_xfer_size;
-       u64                     resv2[2];
+       u32                     phys_block_size;        /* v1.2 */
+       u32                     resv2;
+       u64                     resv3[1];
 };
 
 struct vio_disk_desc {
@@ -272,7 +278,7 @@ static inline u32 vio_dring_avail(struct vio_dring_state *dr,
                                  unsigned int ring_size)
 {
        return (dr->pending -
-               ((dr->prod - dr->cons) & (ring_size - 1)));
+               ((dr->prod - dr->cons) & (ring_size - 1)) - 1);
 }
 
 #define VIO_MAX_TYPE_LEN       32
@@ -292,6 +298,7 @@ struct vio_dev {
 
        unsigned int            tx_irq;
        unsigned int            rx_irq;
+       u64                     rx_ino;
 
        struct device           dev;
 };
@@ -447,5 +454,6 @@ int vio_driver_init(struct vio_driver_state *vio, struct vio_dev *vdev,
                    char *name);
 
 void vio_port_up(struct vio_driver_state *vio);
+int vio_set_intr(unsigned long dev_ino, int state);
 
 #endif /* _SPARC64_VIO_H */
index 82a3a71c451e437248534d939834ae933dc2bdf4..dfad8b1aea9fb042a40290c766a3bb7ede4e0480 100644 (file)
@@ -494,6 +494,18 @@ static void __init sun4v_cpu_probe(void)
                sparc_pmu_type = "niagara5";
                break;
 
+       case SUN4V_CHIP_SPARC_M6:
+               sparc_cpu_type = "SPARC-M6";
+               sparc_fpu_type = "SPARC-M6 integrated FPU";
+               sparc_pmu_type = "sparc-m6";
+               break;
+
+       case SUN4V_CHIP_SPARC_M7:
+               sparc_cpu_type = "SPARC-M7";
+               sparc_fpu_type = "SPARC-M7 integrated FPU";
+               sparc_pmu_type = "sparc-m7";
+               break;
+
        case SUN4V_CHIP_SPARC64X:
                sparc_cpu_type = "SPARC64-X";
                sparc_fpu_type = "SPARC64-X integrated FPU";
index de1c844dfabc02569cfe71c91b3e52a9ea705ef4..e69ec0e3f15527705b3ce28fc89ff5c0341f03fb 100644 (file)
@@ -326,6 +326,8 @@ static int iterate_cpu(struct cpuinfo_tree *t, unsigned int root_index)
        case SUN4V_CHIP_NIAGARA3:
        case SUN4V_CHIP_NIAGARA4:
        case SUN4V_CHIP_NIAGARA5:
+       case SUN4V_CHIP_SPARC_M6:
+       case SUN4V_CHIP_SPARC_M7:
        case SUN4V_CHIP_SPARC64X:
                rover_inc_table = niagara_iterate_method;
                break;
index dff60abbea012f30a8b55221cc8d7a3a60a762ea..f87a55d7709469c63d8234fa9d3455513025dc55 100644 (file)
@@ -1200,14 +1200,14 @@ static int ds_probe(struct vio_dev *vdev, const struct vio_device_id *id)
        ds_cfg.tx_irq = vdev->tx_irq;
        ds_cfg.rx_irq = vdev->rx_irq;
 
-       lp = ldc_alloc(vdev->channel_id, &ds_cfg, dp);
+       lp = ldc_alloc(vdev->channel_id, &ds_cfg, dp, "DS");
        if (IS_ERR(lp)) {
                err = PTR_ERR(lp);
                goto out_free_ds_states;
        }
        dp->lp = lp;
 
-       err = ldc_bind(lp, "DS");
+       err = ldc_bind(lp);
        if (err)
                goto out_free_ldc;
 
index 452f04fe8da698bb8b4620abd40ac6d4fbcd8393..4fdeb8040d4dd4ae0326909f6b77231dcbc3a89d 100644 (file)
@@ -427,6 +427,12 @@ sun4v_chip_type:
        cmp     %g2, '5'
        be,pt   %xcc, 5f
         mov    SUN4V_CHIP_NIAGARA5, %g4
+       cmp     %g2, '6'
+       be,pt   %xcc, 5f
+        mov    SUN4V_CHIP_SPARC_M6, %g4
+       cmp     %g2, '7'
+       be,pt   %xcc, 5f
+        mov    SUN4V_CHIP_SPARC_M7, %g4
        ba,pt   %xcc, 49f
         nop
 
@@ -583,6 +589,12 @@ niagara_tlb_fixup:
        be,pt   %xcc, niagara4_patch
         nop
        cmp     %g1, SUN4V_CHIP_NIAGARA5
+       be,pt   %xcc, niagara4_patch
+        nop
+       cmp     %g1, SUN4V_CHIP_SPARC_M6
+       be,pt   %xcc, niagara4_patch
+        nop
+       cmp     %g1, SUN4V_CHIP_SPARC_M7
        be,pt   %xcc, niagara4_patch
         nop
 
index c0a2de0fd62424914754e19885f3ec1abff1c44e..5c55145bfbf02d616ec606feb94539e26cbe1831 100644 (file)
@@ -46,6 +46,7 @@ static struct api_info api_table[] = {
        { .group = HV_GRP_VF_CPU,                               },
        { .group = HV_GRP_KT_CPU,                               },
        { .group = HV_GRP_VT_CPU,                               },
+       { .group = HV_GRP_T5_CPU,                               },
        { .group = HV_GRP_DIAG,         .flags = FLAG_PRE_API   },
 };
 
index f3ab509b76a8daf32123ec47bbbf0ebb5b360bde..caedf8320416e1fe8bfc4cb76369ce1efd8ce729 100644 (file)
@@ -821,3 +821,19 @@ ENTRY(sun4v_vt_set_perfreg)
        retl
         nop
 ENDPROC(sun4v_vt_set_perfreg)
+
+ENTRY(sun4v_t5_get_perfreg)
+       mov     %o1, %o4
+       mov     HV_FAST_T5_GET_PERFREG, %o5
+       ta      HV_FAST_TRAP
+       stx     %o1, [%o4]
+       retl
+        nop
+ENDPROC(sun4v_t5_get_perfreg)
+
+ENTRY(sun4v_t5_set_perfreg)
+       mov     HV_FAST_T5_SET_PERFREG, %o5
+       ta      HV_FAST_TRAP
+       retl
+        nop
+ENDPROC(sun4v_t5_set_perfreg)
index 7f08ec8a7c682338dec59ff51c15740ee59cdc45..28fed53b13a0d3f1c69be7aec07734b39a2fac92 100644 (file)
@@ -278,7 +278,8 @@ static void *sbus_alloc_coherent(struct device *dev, size_t len,
        }
 
        order = get_order(len_total);
-       if ((va = __get_free_pages(GFP_KERNEL|__GFP_COMP, order)) == 0)
+       va = __get_free_pages(gfp, order);
+       if (va == 0)
                goto err_nopages;
 
        if ((res = kzalloc(sizeof(struct resource), GFP_KERNEL)) == NULL)
@@ -443,7 +444,7 @@ static void *pci32_alloc_coherent(struct device *dev, size_t len,
        }
 
        order = get_order(len_total);
-       va = (void *) __get_free_pages(GFP_KERNEL, order);
+       va = (void *) __get_free_pages(gfp, order);
        if (va == NULL) {
                printk("pci_alloc_consistent: no %ld pages\n", len_total>>PAGE_SHIFT);
                goto err_nopages;
index 666193f4e8bb414fcf64e45a15f89ebf0ab2f628..4033c23bdfa6cc76a9ef4b34ad671da39b6b5077 100644 (file)
@@ -47,8 +47,6 @@
 #include "cpumap.h"
 #include "kstack.h"
 
-#define NUM_IVECS      (IMAP_INR + 1)
-
 struct ino_bucket *ivector_table;
 unsigned long ivector_table_pa;
 
@@ -107,55 +105,196 @@ static void bucket_set_irq(unsigned long bucket_pa, unsigned int irq)
 
 #define irq_work_pa(__cpu)     &(trap_block[(__cpu)].irq_worklist_pa)
 
-static struct {
-       unsigned int dev_handle;
-       unsigned int dev_ino;
-       unsigned int in_use;
-} irq_table[NR_IRQS];
-static DEFINE_SPINLOCK(irq_alloc_lock);
+static unsigned long hvirq_major __initdata;
+static int __init early_hvirq_major(char *p)
+{
+       int rc = kstrtoul(p, 10, &hvirq_major);
+
+       return rc;
+}
+early_param("hvirq", early_hvirq_major);
+
+static int hv_irq_version;
+
+/* Major version 2.0 of HV_GRP_INTR added support for the VIRQ cookie
+ * based interfaces, but:
+ *
+ * 1) Several OSs, Solaris and Linux included, use them even when only
+ *    negotiating version 1.0 (or failing to negotiate at all).  So the
+ *    hypervisor has a workaround that provides the VIRQ interfaces even
+ *    when only verion 1.0 of the API is in use.
+ *
+ * 2) Second, and more importantly, with major version 2.0 these VIRQ
+ *    interfaces only were actually hooked up for LDC interrupts, even
+ *    though the Hypervisor specification clearly stated:
+ *
+ *     The new interrupt API functions will be available to a guest
+ *     when it negotiates version 2.0 in the interrupt API group 0x2. When
+ *     a guest negotiates version 2.0, all interrupt sources will only
+ *     support using the cookie interface, and any attempt to use the
+ *     version 1.0 interrupt APIs numbered 0xa0 to 0xa6 will result in the
+ *     ENOTSUPPORTED error being returned.
+ *
+ *   with an emphasis on "all interrupt sources".
+ *
+ * To correct this, major version 3.0 was created which does actually
+ * support VIRQs for all interrupt sources (not just LDC devices).  So
+ * if we want to move completely over the cookie based VIRQs we must
+ * negotiate major version 3.0 or later of HV_GRP_INTR.
+ */
+static bool sun4v_cookie_only_virqs(void)
+{
+       if (hv_irq_version >= 3)
+               return true;
+       return false;
+}
 
-unsigned char irq_alloc(unsigned int dev_handle, unsigned int dev_ino)
+static void __init irq_init_hv(void)
 {
-       unsigned long flags;
-       unsigned char ent;
+       unsigned long hv_error, major, minor = 0;
+
+       if (tlb_type != hypervisor)
+               return;
 
-       BUILD_BUG_ON(NR_IRQS >= 256);
+       if (hvirq_major)
+               major = hvirq_major;
+       else
+               major = 3;
 
-       spin_lock_irqsave(&irq_alloc_lock, flags);
+       hv_error = sun4v_hvapi_register(HV_GRP_INTR, major, &minor);
+       if (!hv_error)
+               hv_irq_version = major;
+       else
+               hv_irq_version = 1;
 
-       for (ent = 1; ent < NR_IRQS; ent++) {
-               if (!irq_table[ent].in_use)
+       pr_info("SUN4V: Using IRQ API major %d, cookie only virqs %s\n",
+               hv_irq_version,
+               sun4v_cookie_only_virqs() ? "enabled" : "disabled");
+}
+
+/* This function is for the timer interrupt.*/
+int __init arch_probe_nr_irqs(void)
+{
+       return 1;
+}
+
+#define DEFAULT_NUM_IVECS      (0xfffU)
+static unsigned int nr_ivec = DEFAULT_NUM_IVECS;
+#define NUM_IVECS (nr_ivec)
+
+static unsigned int __init size_nr_ivec(void)
+{
+       if (tlb_type == hypervisor) {
+               switch (sun4v_chip_type) {
+               /* Athena's devhandle|devino is large.*/
+               case SUN4V_CHIP_SPARC64X:
+                       nr_ivec = 0xffff;
                        break;
+               }
        }
-       if (ent >= NR_IRQS) {
-               printk(KERN_ERR "IRQ: Out of virtual IRQs.\n");
-               ent = 0;
-       } else {
-               irq_table[ent].dev_handle = dev_handle;
-               irq_table[ent].dev_ino = dev_ino;
-               irq_table[ent].in_use = 1;
-       }
+       return nr_ivec;
+}
+
+struct irq_handler_data {
+       union {
+               struct {
+                       unsigned int dev_handle;
+                       unsigned int dev_ino;
+               };
+               unsigned long sysino;
+       };
+       struct ino_bucket bucket;
+       unsigned long   iclr;
+       unsigned long   imap;
+};
+
+static inline unsigned int irq_data_to_handle(struct irq_data *data)
+{
+       struct irq_handler_data *ihd = data->handler_data;
+
+       return ihd->dev_handle;
+}
+
+static inline unsigned int irq_data_to_ino(struct irq_data *data)
+{
+       struct irq_handler_data *ihd = data->handler_data;
 
-       spin_unlock_irqrestore(&irq_alloc_lock, flags);
+       return ihd->dev_ino;
+}
+
+static inline unsigned long irq_data_to_sysino(struct irq_data *data)
+{
+       struct irq_handler_data *ihd = data->handler_data;
 
-       return ent;
+       return ihd->sysino;
 }
 
-#ifdef CONFIG_PCI_MSI
 void irq_free(unsigned int irq)
 {
-       unsigned long flags;
+       void *data = irq_get_handler_data(irq);
 
-       if (irq >= NR_IRQS)
-               return;
+       kfree(data);
+       irq_set_handler_data(irq, NULL);
+       irq_free_descs(irq, 1);
+}
 
-       spin_lock_irqsave(&irq_alloc_lock, flags);
+unsigned int irq_alloc(unsigned int dev_handle, unsigned int dev_ino)
+{
+       int irq;
 
-       irq_table[irq].in_use = 0;
+       irq = __irq_alloc_descs(-1, 1, 1, numa_node_id(), NULL);
+       if (irq <= 0)
+               goto out;
 
-       spin_unlock_irqrestore(&irq_alloc_lock, flags);
+       return irq;
+out:
+       return 0;
+}
+
+static unsigned int cookie_exists(u32 devhandle, unsigned int devino)
+{
+       unsigned long hv_err, cookie;
+       struct ino_bucket *bucket;
+       unsigned int irq = 0U;
+
+       hv_err = sun4v_vintr_get_cookie(devhandle, devino, &cookie);
+       if (hv_err) {
+               pr_err("HV get cookie failed hv_err = %ld\n", hv_err);
+               goto out;
+       }
+
+       if (cookie & ((1UL << 63UL))) {
+               cookie = ~cookie;
+               bucket = (struct ino_bucket *) __va(cookie);
+               irq = bucket->__irq;
+       }
+out:
+       return irq;
+}
+
+static unsigned int sysino_exists(u32 devhandle, unsigned int devino)
+{
+       unsigned long sysino = sun4v_devino_to_sysino(devhandle, devino);
+       struct ino_bucket *bucket;
+       unsigned int irq;
+
+       bucket = &ivector_table[sysino];
+       irq = bucket_get_irq(__pa(bucket));
+
+       return irq;
+}
+
+void ack_bad_irq(unsigned int irq)
+{
+       pr_crit("BAD IRQ ack %d\n", irq);
+}
+
+void irq_install_pre_handler(int irq,
+                            void (*func)(unsigned int, void *, void *),
+                            void *arg1, void *arg2)
+{
+       pr_warn("IRQ pre handler NOT supported.\n");
 }
-#endif
 
 /*
  * /proc/interrupts printing:
@@ -206,15 +345,6 @@ static unsigned int sun4u_compute_tid(unsigned long imap, unsigned long cpuid)
        return tid;
 }
 
-struct irq_handler_data {
-       unsigned long   iclr;
-       unsigned long   imap;
-
-       void            (*pre_handler)(unsigned int, void *, void *);
-       void            *arg1;
-       void            *arg2;
-};
-
 #ifdef CONFIG_SMP
 static int irq_choose_cpu(unsigned int irq, const struct cpumask *affinity)
 {
@@ -316,8 +446,8 @@ static void sun4u_irq_eoi(struct irq_data *data)
 
 static void sun4v_irq_enable(struct irq_data *data)
 {
-       unsigned int ino = irq_table[data->irq].dev_ino;
        unsigned long cpuid = irq_choose_cpu(data->irq, data->affinity);
+       unsigned int ino = irq_data_to_sysino(data);
        int err;
 
        err = sun4v_intr_settarget(ino, cpuid);
@@ -337,8 +467,8 @@ static void sun4v_irq_enable(struct irq_data *data)
 static int sun4v_set_affinity(struct irq_data *data,
                               const struct cpumask *mask, bool force)
 {
-       unsigned int ino = irq_table[data->irq].dev_ino;
        unsigned long cpuid = irq_choose_cpu(data->irq, mask);
+       unsigned int ino = irq_data_to_sysino(data);
        int err;
 
        err = sun4v_intr_settarget(ino, cpuid);
@@ -351,7 +481,7 @@ static int sun4v_set_affinity(struct irq_data *data,
 
 static void sun4v_irq_disable(struct irq_data *data)
 {
-       unsigned int ino = irq_table[data->irq].dev_ino;
+       unsigned int ino = irq_data_to_sysino(data);
        int err;
 
        err = sun4v_intr_setenabled(ino, HV_INTR_DISABLED);
@@ -362,7 +492,7 @@ static void sun4v_irq_disable(struct irq_data *data)
 
 static void sun4v_irq_eoi(struct irq_data *data)
 {
-       unsigned int ino = irq_table[data->irq].dev_ino;
+       unsigned int ino = irq_data_to_sysino(data);
        int err;
 
        err = sun4v_intr_setstate(ino, HV_INTR_STATE_IDLE);
@@ -373,14 +503,13 @@ static void sun4v_irq_eoi(struct irq_data *data)
 
 static void sun4v_virq_enable(struct irq_data *data)
 {
-       unsigned long cpuid, dev_handle, dev_ino;
+       unsigned long dev_handle = irq_data_to_handle(data);
+       unsigned long dev_ino = irq_data_to_ino(data);
+       unsigned long cpuid;
        int err;
 
        cpuid = irq_choose_cpu(data->irq, data->affinity);
 
-       dev_handle = irq_table[data->irq].dev_handle;
-       dev_ino = irq_table[data->irq].dev_ino;
-
        err = sun4v_vintr_set_target(dev_handle, dev_ino, cpuid);
        if (err != HV_EOK)
                printk(KERN_ERR "sun4v_vintr_set_target(%lx,%lx,%lu): "
@@ -403,14 +532,13 @@ static void sun4v_virq_enable(struct irq_data *data)
 static int sun4v_virt_set_affinity(struct irq_data *data,
                                    const struct cpumask *mask, bool force)
 {
-       unsigned long cpuid, dev_handle, dev_ino;
+       unsigned long dev_handle = irq_data_to_handle(data);
+       unsigned long dev_ino = irq_data_to_ino(data);
+       unsigned long cpuid;
        int err;
 
        cpuid = irq_choose_cpu(data->irq, mask);
 
-       dev_handle = irq_table[data->irq].dev_handle;
-       dev_ino = irq_table[data->irq].dev_ino;
-
        err = sun4v_vintr_set_target(dev_handle, dev_ino, cpuid);
        if (err != HV_EOK)
                printk(KERN_ERR "sun4v_vintr_set_target(%lx,%lx,%lu): "
@@ -422,11 +550,10 @@ static int sun4v_virt_set_affinity(struct irq_data *data,
 
 static void sun4v_virq_disable(struct irq_data *data)
 {
-       unsigned long dev_handle, dev_ino;
+       unsigned long dev_handle = irq_data_to_handle(data);
+       unsigned long dev_ino = irq_data_to_ino(data);
        int err;
 
-       dev_handle = irq_table[data->irq].dev_handle;
-       dev_ino = irq_table[data->irq].dev_ino;
 
        err = sun4v_vintr_set_valid(dev_handle, dev_ino,
                                    HV_INTR_DISABLED);
@@ -438,12 +565,10 @@ static void sun4v_virq_disable(struct irq_data *data)
 
 static void sun4v_virq_eoi(struct irq_data *data)
 {
-       unsigned long dev_handle, dev_ino;
+       unsigned long dev_handle = irq_data_to_handle(data);
+       unsigned long dev_ino = irq_data_to_ino(data);
        int err;
 
-       dev_handle = irq_table[data->irq].dev_handle;
-       dev_ino = irq_table[data->irq].dev_ino;
-
        err = sun4v_vintr_set_state(dev_handle, dev_ino,
                                    HV_INTR_STATE_IDLE);
        if (err != HV_EOK)
@@ -479,31 +604,10 @@ static struct irq_chip sun4v_virq = {
        .flags                  = IRQCHIP_EOI_IF_HANDLED,
 };
 
-static void pre_flow_handler(struct irq_data *d)
-{
-       struct irq_handler_data *handler_data = irq_data_get_irq_handler_data(d);
-       unsigned int ino = irq_table[d->irq].dev_ino;
-
-       handler_data->pre_handler(ino, handler_data->arg1, handler_data->arg2);
-}
-
-void irq_install_pre_handler(int irq,
-                            void (*func)(unsigned int, void *, void *),
-                            void *arg1, void *arg2)
-{
-       struct irq_handler_data *handler_data = irq_get_handler_data(irq);
-
-       handler_data->pre_handler = func;
-       handler_data->arg1 = arg1;
-       handler_data->arg2 = arg2;
-
-       __irq_set_preflow_handler(irq, pre_flow_handler);
-}
-
 unsigned int build_irq(int inofixup, unsigned long iclr, unsigned long imap)
 {
-       struct ino_bucket *bucket;
        struct irq_handler_data *handler_data;
+       struct ino_bucket *bucket;
        unsigned int irq;
        int ino;
 
@@ -537,119 +641,166 @@ out:
        return irq;
 }
 
-static unsigned int sun4v_build_common(unsigned long sysino,
-                                      struct irq_chip *chip)
+static unsigned int sun4v_build_common(u32 devhandle, unsigned int devino,
+               void (*handler_data_init)(struct irq_handler_data *data,
+               u32 devhandle, unsigned int devino),
+               struct irq_chip *chip)
 {
-       struct ino_bucket *bucket;
-       struct irq_handler_data *handler_data;
+       struct irq_handler_data *data;
        unsigned int irq;
 
-       BUG_ON(tlb_type != hypervisor);
+       irq = irq_alloc(devhandle, devino);
+       if (!irq)
+               goto out;
 
-       bucket = &ivector_table[sysino];
-       irq = bucket_get_irq(__pa(bucket));
-       if (!irq) {
-               irq = irq_alloc(0, sysino);
-               bucket_set_irq(__pa(bucket), irq);
-               irq_set_chip_and_handler_name(irq, chip, handle_fasteoi_irq,
-                                             "IVEC");
+       data = kzalloc(sizeof(struct irq_handler_data), GFP_ATOMIC);
+       if (unlikely(!data)) {
+               pr_err("IRQ handler data allocation failed.\n");
+               irq_free(irq);
+               irq = 0;
+               goto out;
        }
 
-       handler_data = irq_get_handler_data(irq);
-       if (unlikely(handler_data))
-               goto out;
+       irq_set_handler_data(irq, data);
+       handler_data_init(data, devhandle, devino);
+       irq_set_chip_and_handler_name(irq, chip, handle_fasteoi_irq, "IVEC");
+       data->imap = ~0UL;
+       data->iclr = ~0UL;
+out:
+       return irq;
+}
 
-       handler_data = kzalloc(sizeof(struct irq_handler_data), GFP_ATOMIC);
-       if (unlikely(!handler_data)) {
-               prom_printf("IRQ: kzalloc(irq_handler_data) failed.\n");
-               prom_halt();
-       }
-       irq_set_handler_data(irq, handler_data);
+static unsigned long cookie_assign(unsigned int irq, u32 devhandle,
+               unsigned int devino)
+{
+       struct irq_handler_data *ihd = irq_get_handler_data(irq);
+       unsigned long hv_error, cookie;
 
-       /* Catch accidental accesses to these things.  IMAP/ICLR handling
-        * is done by hypervisor calls on sun4v platforms, not by direct
-        * register accesses.
+       /* handler_irq needs to find the irq. cookie is seen signed in
+        * sun4v_dev_mondo and treated as a non ivector_table delivery.
         */
-       handler_data->imap = ~0UL;
-       handler_data->iclr = ~0UL;
+       ihd->bucket.__irq = irq;
+       cookie = ~__pa(&ihd->bucket);
 
-out:
-       return irq;
+       hv_error = sun4v_vintr_set_cookie(devhandle, devino, cookie);
+       if (hv_error)
+               pr_err("HV vintr set cookie failed = %ld\n", hv_error);
+
+       return hv_error;
 }
 
-unsigned int sun4v_build_irq(u32 devhandle, unsigned int devino)
+static void cookie_handler_data(struct irq_handler_data *data,
+                               u32 devhandle, unsigned int devino)
 {
-       unsigned long sysino = sun4v_devino_to_sysino(devhandle, devino);
+       data->dev_handle = devhandle;
+       data->dev_ino = devino;
+}
 
-       return sun4v_build_common(sysino, &sun4v_irq);
+static unsigned int cookie_build_irq(u32 devhandle, unsigned int devino,
+                                    struct irq_chip *chip)
+{
+       unsigned long hv_error;
+       unsigned int irq;
+
+       irq = sun4v_build_common(devhandle, devino, cookie_handler_data, chip);
+
+       hv_error = cookie_assign(irq, devhandle, devino);
+       if (hv_error) {
+               irq_free(irq);
+               irq = 0;
+       }
+
+       return irq;
 }
 
-unsigned int sun4v_build_virq(u32 devhandle, unsigned int devino)
+static unsigned int sun4v_build_cookie(u32 devhandle, unsigned int devino)
 {
-       struct irq_handler_data *handler_data;
-       unsigned long hv_err, cookie;
-       struct ino_bucket *bucket;
        unsigned int irq;
 
-       bucket = kzalloc(sizeof(struct ino_bucket), GFP_ATOMIC);
-       if (unlikely(!bucket))
-               return 0;
+       irq = cookie_exists(devhandle, devino);
+       if (irq)
+               goto out;
 
-       /* The only reference we store to the IRQ bucket is
-        * by physical address which kmemleak can't see, tell
-        * it that this object explicitly is not a leak and
-        * should be scanned.
-        */
-       kmemleak_not_leak(bucket);
+       irq = cookie_build_irq(devhandle, devino, &sun4v_virq);
 
-       __flush_dcache_range((unsigned long) bucket,
-                            ((unsigned long) bucket +
-                             sizeof(struct ino_bucket)));
+out:
+       return irq;
+}
 
-       irq = irq_alloc(devhandle, devino);
+static void sysino_set_bucket(unsigned int irq)
+{
+       struct irq_handler_data *ihd = irq_get_handler_data(irq);
+       struct ino_bucket *bucket;
+       unsigned long sysino;
+
+       sysino = sun4v_devino_to_sysino(ihd->dev_handle, ihd->dev_ino);
+       BUG_ON(sysino >= nr_ivec);
+       bucket = &ivector_table[sysino];
        bucket_set_irq(__pa(bucket), irq);
+}
 
-       irq_set_chip_and_handler_name(irq, &sun4v_virq, handle_fasteoi_irq,
-                                     "IVEC");
+static void sysino_handler_data(struct irq_handler_data *data,
+                               u32 devhandle, unsigned int devino)
+{
+       unsigned long sysino;
 
-       handler_data = kzalloc(sizeof(struct irq_handler_data), GFP_ATOMIC);
-       if (unlikely(!handler_data))
-               return 0;
+       sysino = sun4v_devino_to_sysino(devhandle, devino);
+       data->sysino = sysino;
+}
 
-       /* In order to make the LDC channel startup sequence easier,
-        * especially wrt. locking, we do not let request_irq() enable
-        * the interrupt.
-        */
-       irq_set_status_flags(irq, IRQ_NOAUTOEN);
-       irq_set_handler_data(irq, handler_data);
+static unsigned int sysino_build_irq(u32 devhandle, unsigned int devino,
+                                    struct irq_chip *chip)
+{
+       unsigned int irq;
 
-       /* Catch accidental accesses to these things.  IMAP/ICLR handling
-        * is done by hypervisor calls on sun4v platforms, not by direct
-        * register accesses.
-        */
-       handler_data->imap = ~0UL;
-       handler_data->iclr = ~0UL;
+       irq = sun4v_build_common(devhandle, devino, sysino_handler_data, chip);
+       if (!irq)
+               goto out;
 
-       cookie = ~__pa(bucket);
-       hv_err = sun4v_vintr_set_cookie(devhandle, devino, cookie);
-       if (hv_err) {
-               prom_printf("IRQ: Fatal, cannot set cookie for [%x:%x] "
-                           "err=%lu\n", devhandle, devino, hv_err);
-               prom_halt();
-       }
+       sysino_set_bucket(irq);
+out:
+       return irq;
+}
 
+static int sun4v_build_sysino(u32 devhandle, unsigned int devino)
+{
+       int irq;
+
+       irq = sysino_exists(devhandle, devino);
+       if (irq)
+               goto out;
+
+       irq = sysino_build_irq(devhandle, devino, &sun4v_irq);
+out:
        return irq;
 }
 
-void ack_bad_irq(unsigned int irq)
+unsigned int sun4v_build_irq(u32 devhandle, unsigned int devino)
 {
-       unsigned int ino = irq_table[irq].dev_ino;
+       unsigned int irq;
 
-       if (!ino)
-               ino = 0xdeadbeef;
+       if (sun4v_cookie_only_virqs())
+               irq = sun4v_build_cookie(devhandle, devino);
+       else
+               irq = sun4v_build_sysino(devhandle, devino);
 
-       printk(KERN_CRIT "Unexpected IRQ from ino[%x] irq[%u]\n",
-              ino, irq);
+       return irq;
+}
+
+unsigned int sun4v_build_virq(u32 devhandle, unsigned int devino)
+{
+       int irq;
+
+       irq = cookie_build_irq(devhandle, devino, &sun4v_virq);
+       if (!irq)
+               goto out;
+
+       /* This is borrowed from the original function.
+        */
+       irq_set_status_flags(irq, IRQ_NOAUTOEN);
+
+out:
+       return irq;
 }
 
 void *hardirq_stack[NR_CPUS];
@@ -720,9 +871,12 @@ void fixup_irqs(void)
 
        for (irq = 0; irq < NR_IRQS; irq++) {
                struct irq_desc *desc = irq_to_desc(irq);
-               struct irq_data *data = irq_desc_get_irq_data(desc);
+               struct irq_data *data;
                unsigned long flags;
 
+               if (!desc)
+                       continue;
+               data = irq_desc_get_irq_data(desc);
                raw_spin_lock_irqsave(&desc->lock, flags);
                if (desc->action && !irqd_is_per_cpu(data)) {
                        if (data->chip->irq_set_affinity)
@@ -922,16 +1076,22 @@ static struct irqaction timer_irq_action = {
        .name = "timer",
 };
 
-/* Only invoked on boot processor. */
-void __init init_IRQ(void)
+static void __init irq_ivector_init(void)
 {
-       unsigned long size;
+       unsigned long size, order;
+       unsigned int ivecs;
 
-       map_prom_timers();
-       kill_prom_timer();
+       /* If we are doing cookie only VIRQs then we do not need the ivector
+        * table to process interrupts.
+        */
+       if (sun4v_cookie_only_virqs())
+               return;
 
-       size = sizeof(struct ino_bucket) * NUM_IVECS;
-       ivector_table = kzalloc(size, GFP_KERNEL);
+       ivecs = size_nr_ivec();
+       size = sizeof(struct ino_bucket) * ivecs;
+       order = get_order(size);
+       ivector_table = (struct ino_bucket *)
+               __get_free_pages(GFP_KERNEL | __GFP_ZERO, order);
        if (!ivector_table) {
                prom_printf("Fatal error, cannot allocate ivector_table\n");
                prom_halt();
@@ -940,6 +1100,15 @@ void __init init_IRQ(void)
                             ((unsigned long) ivector_table) + size);
 
        ivector_table_pa = __pa(ivector_table);
+}
+
+/* Only invoked on boot processor.*/
+void __init init_IRQ(void)
+{
+       irq_init_hv();
+       irq_ivector_init();
+       map_prom_timers();
+       kill_prom_timer();
 
        if (tlb_type == hypervisor)
                sun4v_init_mondo_queues();
index 605d49204580585356a7fda6dede8657641fb7e1..ef0d8e9e1210e6dffbc184a8ce426c708a968062 100644 (file)
@@ -47,14 +47,6 @@ kvmap_itlb_vmalloc_addr:
        KERN_PGTABLE_WALK(%g4, %g5, %g2, kvmap_itlb_longpath)
 
        TSB_LOCK_TAG(%g1, %g2, %g7)
-
-       /* Load and check PTE.  */
-       ldxa            [%g5] ASI_PHYS_USE_EC, %g5
-       mov             1, %g7
-       sllx            %g7, TSB_TAG_INVALID_BIT, %g7
-       brgez,a,pn      %g5, kvmap_itlb_longpath
-        TSB_STORE(%g1, %g7)
-
        TSB_WRITE(%g1, %g5, %g6)
 
        /* fallthrough to TLB load */
@@ -118,6 +110,12 @@ kvmap_dtlb_obp:
        ba,pt           %xcc, kvmap_dtlb_load
         nop
 
+kvmap_linear_early:
+       sethi           %hi(kern_linear_pte_xor), %g7
+       ldx             [%g7 + %lo(kern_linear_pte_xor)], %g2
+       ba,pt           %xcc, kvmap_dtlb_tsb4m_load
+        xor            %g2, %g4, %g5
+
        .align          32
 kvmap_dtlb_tsb4m_load:
        TSB_LOCK_TAG(%g1, %g2, %g7)
@@ -146,105 +144,17 @@ kvmap_dtlb_4v:
        /* Correct TAG_TARGET is already in %g6, check 4mb TSB.  */
        KERN_TSB4M_LOOKUP_TL1(%g6, %g5, %g1, %g2, %g3, kvmap_dtlb_load)
 #endif
-       /* TSB entry address left in %g1, lookup linear PTE.
-        * Must preserve %g1 and %g6 (TAG).
-        */
-kvmap_dtlb_tsb4m_miss:
-       /* Clear the PAGE_OFFSET top virtual bits, shift
-        * down to get PFN, and make sure PFN is in range.
-        */
-661:   sllx            %g4, 0, %g5
-       .section        .page_offset_shift_patch, "ax"
-       .word           661b
-       .previous
-
-       /* Check to see if we know about valid memory at the 4MB
-        * chunk this physical address will reside within.
+       /* Linear mapping TSB lookup failed.  Fallthrough to kernel
+        * page table based lookup.
         */
-661:   srlx            %g5, MAX_PHYS_ADDRESS_BITS, %g2
-       .section        .page_offset_shift_patch, "ax"
-       .word           661b
-       .previous
-
-       brnz,pn         %g2, kvmap_dtlb_longpath
-        nop
-
-       /* This unconditional branch and delay-slot nop gets patched
-        * by the sethi sequence once the bitmap is properly setup.
-        */
-       .globl          valid_addr_bitmap_insn
-valid_addr_bitmap_insn:
-       ba,pt           %xcc, 2f
-        nop
-       .subsection     2
-       .globl          valid_addr_bitmap_patch
-valid_addr_bitmap_patch:
-       sethi           %hi(sparc64_valid_addr_bitmap), %g7
-       or              %g7, %lo(sparc64_valid_addr_bitmap), %g7
-       .previous
-
-661:   srlx            %g5, ILOG2_4MB, %g2
-       .section        .page_offset_shift_patch, "ax"
-       .word           661b
-       .previous
-
-       srlx            %g2, 6, %g5
-       and             %g2, 63, %g2
-       sllx            %g5, 3, %g5
-       ldx             [%g7 + %g5], %g5
-       mov             1, %g7
-       sllx            %g7, %g2, %g7
-       andcc           %g5, %g7, %g0
-       be,pn           %xcc, kvmap_dtlb_longpath
-
-2:      sethi          %hi(kpte_linear_bitmap), %g2
-
-       /* Get the 256MB physical address index. */
-661:   sllx            %g4, 0, %g5
-       .section        .page_offset_shift_patch, "ax"
-       .word           661b
-       .previous
-
-       or              %g2, %lo(kpte_linear_bitmap), %g2
-
-661:   srlx            %g5, ILOG2_256MB, %g5
-       .section        .page_offset_shift_patch, "ax"
-       .word           661b
-       .previous
-
-       and             %g5, (32 - 1), %g7
-
-       /* Divide by 32 to get the offset into the bitmask.  */
-       srlx            %g5, 5, %g5
-       add             %g7, %g7, %g7
-       sllx            %g5, 3, %g5
-
-       /* kern_linear_pte_xor[(mask >> shift) & 3)] */
-       ldx             [%g2 + %g5], %g2
-       srlx            %g2, %g7, %g7
-       sethi           %hi(kern_linear_pte_xor), %g5
-       and             %g7, 3, %g7
-       or              %g5, %lo(kern_linear_pte_xor), %g5
-       sllx            %g7, 3, %g7
-       ldx             [%g5 + %g7], %g2
-
        .globl          kvmap_linear_patch
 kvmap_linear_patch:
-       ba,pt           %xcc, kvmap_dtlb_tsb4m_load
-        xor            %g2, %g4, %g5
+       ba,a,pt         %xcc, kvmap_linear_early
 
 kvmap_dtlb_vmalloc_addr:
        KERN_PGTABLE_WALK(%g4, %g5, %g2, kvmap_dtlb_longpath)
 
        TSB_LOCK_TAG(%g1, %g2, %g7)
-
-       /* Load and check PTE.  */
-       ldxa            [%g5] ASI_PHYS_USE_EC, %g5
-       mov             1, %g7
-       sllx            %g7, TSB_TAG_INVALID_BIT, %g7
-       brgez,a,pn      %g5, kvmap_dtlb_longpath
-        TSB_STORE(%g1, %g7)
-
        TSB_WRITE(%g1, %g5, %g6)
 
        /* fallthrough to TLB load */
@@ -276,13 +186,8 @@ kvmap_dtlb_load:
 
 #ifdef CONFIG_SPARSEMEM_VMEMMAP
 kvmap_vmemmap:
-       sub             %g4, %g5, %g5
-       srlx            %g5, ILOG2_4MB, %g5
-       sethi           %hi(vmemmap_table), %g1
-       sllx            %g5, 3, %g5
-       or              %g1, %lo(vmemmap_table), %g1
-       ba,pt           %xcc, kvmap_dtlb_load
-        ldx            [%g1 + %g5], %g5
+       KERN_PGTABLE_WALK(%g4, %g5, %g2, kvmap_dtlb_longpath)
+       ba,a,pt         %xcc, kvmap_dtlb_load
 #endif
 
 kvmap_dtlb_nonlinear:
@@ -294,8 +199,8 @@ kvmap_dtlb_nonlinear:
 
 #ifdef CONFIG_SPARSEMEM_VMEMMAP
        /* Do not use the TSB for vmemmap.  */
-       mov             (VMEMMAP_BASE >> 40), %g5
-       sllx            %g5, 40, %g5
+       sethi           %hi(VMEMMAP_BASE), %g5
+       ldx             [%g5 + %lo(VMEMMAP_BASE)], %g5
        cmp             %g4,%g5
        bgeu,pn         %xcc, kvmap_vmemmap
         nop
@@ -307,8 +212,8 @@ kvmap_dtlb_tsbmiss:
        sethi           %hi(MODULES_VADDR), %g5
        cmp             %g4, %g5
        blu,pn          %xcc, kvmap_dtlb_longpath
-        mov            (VMALLOC_END >> 40), %g5
-       sllx            %g5, 40, %g5
+        sethi          %hi(VMALLOC_END), %g5
+       ldx             [%g5 + %lo(VMALLOC_END)], %g5
        cmp             %g4, %g5
        bgeu,pn         %xcc, kvmap_dtlb_longpath
         nop
index 0af28b9846954593612cf512cf85afb167eacbfc..4310332872d4cf90727b1e91b900dcbe601d296f 100644 (file)
@@ -1078,7 +1078,8 @@ static void ldc_iommu_release(struct ldc_channel *lp)
 
 struct ldc_channel *ldc_alloc(unsigned long id,
                              const struct ldc_channel_config *cfgp,
-                             void *event_arg)
+                             void *event_arg,
+                             const char *name)
 {
        struct ldc_channel *lp;
        const struct ldc_mode_ops *mops;
@@ -1093,6 +1094,8 @@ struct ldc_channel *ldc_alloc(unsigned long id,
        err = -EINVAL;
        if (!cfgp)
                goto out_err;
+       if (!name)
+               goto out_err;
 
        switch (cfgp->mode) {
        case LDC_MODE_RAW:
@@ -1185,6 +1188,21 @@ struct ldc_channel *ldc_alloc(unsigned long id,
 
        INIT_HLIST_HEAD(&lp->mh_list);
 
+       snprintf(lp->rx_irq_name, LDC_IRQ_NAME_MAX, "%s RX", name);
+       snprintf(lp->tx_irq_name, LDC_IRQ_NAME_MAX, "%s TX", name);
+
+       err = request_irq(lp->cfg.rx_irq, ldc_rx, 0,
+                         lp->rx_irq_name, lp);
+       if (err)
+               goto out_free_txq;
+
+       err = request_irq(lp->cfg.tx_irq, ldc_tx, 0,
+                         lp->tx_irq_name, lp);
+       if (err) {
+               free_irq(lp->cfg.rx_irq, lp);
+               goto out_free_txq;
+       }
+
        return lp;
 
 out_free_txq:
@@ -1237,31 +1255,14 @@ EXPORT_SYMBOL(ldc_free);
  * state.  This does not initiate a handshake, ldc_connect() does
  * that.
  */
-int ldc_bind(struct ldc_channel *lp, const char *name)
+int ldc_bind(struct ldc_channel *lp)
 {
        unsigned long hv_err, flags;
        int err = -EINVAL;
 
-       if (!name ||
-           (lp->state != LDC_STATE_INIT))
+       if (lp->state != LDC_STATE_INIT)
                return -EINVAL;
 
-       snprintf(lp->rx_irq_name, LDC_IRQ_NAME_MAX, "%s RX", name);
-       snprintf(lp->tx_irq_name, LDC_IRQ_NAME_MAX, "%s TX", name);
-
-       err = request_irq(lp->cfg.rx_irq, ldc_rx, 0,
-                         lp->rx_irq_name, lp);
-       if (err)
-               return err;
-
-       err = request_irq(lp->cfg.tx_irq, ldc_tx, 0,
-                         lp->tx_irq_name, lp);
-       if (err) {
-               free_irq(lp->cfg.rx_irq, lp);
-               return err;
-       }
-
-
        spin_lock_irqsave(&lp->lock, flags);
 
        enable_irq(lp->cfg.rx_irq);
index 683c4af999de5214d31dcfd1ff9438c32d0a5d59..9bbb8f2bbfcce1d0925be62ce3af8e525cfc5082 100644 (file)
@@ -37,6 +37,7 @@ unsigned long amba_system_id;
 static DEFINE_SPINLOCK(leon_irq_lock);
 
 static unsigned long leon3_gptimer_idx; /* Timer Index (0..6) within Timer Core */
+static unsigned long leon3_gptimer_ackmask; /* For clearing pending bit */
 unsigned long leon3_gptimer_irq; /* interrupt controller irq number */
 unsigned int sparc_leon_eirq;
 #define LEON_IMASK(cpu) (&leon3_irqctrl_regs->mask[cpu])
@@ -260,11 +261,19 @@ void leon_update_virq_handling(unsigned int virq,
 
 static u32 leon_cycles_offset(void)
 {
-       u32 rld, val, off;
+       u32 rld, val, ctrl, off;
+
        rld = LEON3_BYPASS_LOAD_PA(&leon3_gptimer_regs->e[leon3_gptimer_idx].rld);
        val = LEON3_BYPASS_LOAD_PA(&leon3_gptimer_regs->e[leon3_gptimer_idx].val);
-       off = rld - val;
-       return rld - val;
+       ctrl = LEON3_BYPASS_LOAD_PA(&leon3_gptimer_regs->e[leon3_gptimer_idx].ctrl);
+       if (LEON3_GPTIMER_CTRL_ISPENDING(ctrl)) {
+               val = LEON3_BYPASS_LOAD_PA(&leon3_gptimer_regs->e[leon3_gptimer_idx].val);
+               off = 2 * rld - val;
+       } else {
+               off = rld - val;
+       }
+
+       return off;
 }
 
 #ifdef CONFIG_SMP
@@ -302,6 +311,7 @@ void __init leon_init_timers(void)
        int ampopts;
        int err;
        u32 config;
+       u32 ctrl;
 
        sparc_config.get_cycles_offset = leon_cycles_offset;
        sparc_config.cs_period = 1000000 / HZ;
@@ -374,6 +384,16 @@ void __init leon_init_timers(void)
        if (!(leon3_gptimer_regs && leon3_irqctrl_regs && leon3_gptimer_irq))
                goto bad;
 
+       ctrl = LEON3_BYPASS_LOAD_PA(&leon3_gptimer_regs->e[leon3_gptimer_idx].ctrl);
+       LEON3_BYPASS_STORE_PA(&leon3_gptimer_regs->e[leon3_gptimer_idx].ctrl,
+                             ctrl | LEON3_GPTIMER_CTRL_PENDING);
+       ctrl = LEON3_BYPASS_LOAD_PA(&leon3_gptimer_regs->e[leon3_gptimer_idx].ctrl);
+
+       if ((ctrl & LEON3_GPTIMER_CTRL_PENDING) != 0)
+               leon3_gptimer_ackmask = ~LEON3_GPTIMER_CTRL_PENDING;
+       else
+               leon3_gptimer_ackmask = ~0;
+
        LEON3_BYPASS_STORE_PA(&leon3_gptimer_regs->e[leon3_gptimer_idx].val, 0);
        LEON3_BYPASS_STORE_PA(&leon3_gptimer_regs->e[leon3_gptimer_idx].rld,
                                (((1000000 / HZ) - 1)));
@@ -452,6 +472,11 @@ bad:
 
 static void leon_clear_clock_irq(void)
 {
+       u32 ctrl;
+
+       ctrl = LEON3_BYPASS_LOAD_PA(&leon3_gptimer_regs->e[leon3_gptimer_idx].ctrl);
+       LEON3_BYPASS_STORE_PA(&leon3_gptimer_regs->e[leon3_gptimer_idx].ctrl,
+                             ctrl & leon3_gptimer_ackmask);
 }
 
 static void leon_load_profile_irq(int cpu, unsigned int limit)
index 269af58497aa8b0844ea6e26d083e1c60eb60bca..7e967c8018c8cf19ba1886b39b087d9eb0638b0c 100644 (file)
@@ -191,12 +191,41 @@ static const struct pcr_ops n4_pcr_ops = {
        .pcr_nmi_disable        = PCR_N4_PICNPT,
 };
 
+static u64 n5_pcr_read(unsigned long reg_num)
+{
+       unsigned long val;
+
+       (void) sun4v_t5_get_perfreg(reg_num, &val);
+
+       return val;
+}
+
+static void n5_pcr_write(unsigned long reg_num, u64 val)
+{
+       (void) sun4v_t5_set_perfreg(reg_num, val);
+}
+
+static const struct pcr_ops n5_pcr_ops = {
+       .read_pcr               = n5_pcr_read,
+       .write_pcr              = n5_pcr_write,
+       .read_pic               = n4_pic_read,
+       .write_pic              = n4_pic_write,
+       .nmi_picl_value         = n4_picl_value,
+       .pcr_nmi_enable         = (PCR_N4_PICNPT | PCR_N4_STRACE |
+                                  PCR_N4_UTRACE | PCR_N4_TOE |
+                                  (26 << PCR_N4_SL_SHIFT)),
+       .pcr_nmi_disable        = PCR_N4_PICNPT,
+};
+
+
 static unsigned long perf_hsvc_group;
 static unsigned long perf_hsvc_major;
 static unsigned long perf_hsvc_minor;
 
 static int __init register_perf_hsvc(void)
 {
+       unsigned long hverror;
+
        if (tlb_type == hypervisor) {
                switch (sun4v_chip_type) {
                case SUN4V_CHIP_NIAGARA1:
@@ -215,6 +244,10 @@ static int __init register_perf_hsvc(void)
                        perf_hsvc_group = HV_GRP_VT_CPU;
                        break;
 
+               case SUN4V_CHIP_NIAGARA5:
+                       perf_hsvc_group = HV_GRP_T5_CPU;
+                       break;
+
                default:
                        return -ENODEV;
                }
@@ -222,10 +255,12 @@ static int __init register_perf_hsvc(void)
 
                perf_hsvc_major = 1;
                perf_hsvc_minor = 0;
-               if (sun4v_hvapi_register(perf_hsvc_group,
-                                        perf_hsvc_major,
-                                        &perf_hsvc_minor)) {
-                       printk("perfmon: Could not register hvapi.\n");
+               hverror = sun4v_hvapi_register(perf_hsvc_group,
+                                              perf_hsvc_major,
+                                              &perf_hsvc_minor);
+               if (hverror) {
+                       pr_err("perfmon: Could not register hvapi(0x%lx).\n",
+                              hverror);
                        return -ENODEV;
                }
        }
@@ -254,6 +289,10 @@ static int __init setup_sun4v_pcr_ops(void)
                pcr_ops = &n4_pcr_ops;
                break;
 
+       case SUN4V_CHIP_NIAGARA5:
+               pcr_ops = &n5_pcr_ops;
+               break;
+
        default:
                ret = -ENODEV;
                break;
index d35c490a91cb2952e6fa047591a5760087c966fe..c9759ad3f34af8230104309eec4168bae2980708 100644 (file)
@@ -1662,7 +1662,8 @@ static bool __init supported_pmu(void)
                sparc_pmu = &niagara2_pmu;
                return true;
        }
-       if (!strcmp(sparc_pmu_type, "niagara4")) {
+       if (!strcmp(sparc_pmu_type, "niagara4") ||
+           !strcmp(sparc_pmu_type, "niagara5")) {
                sparc_pmu = &niagara4_pmu;
                return true;
        }
index 3fdb455e3318fab7626763ba6fb9b907e02203d8..e629b83775879496a50b3db46684bb1c71fab0c4 100644 (file)
@@ -141,21 +141,9 @@ static void __init boot_flags_init(char *commands)
                                process_switch(*commands++);
                        continue;
                }
-               if (!strncmp(commands, "mem=", 4)) {
-                       /*
-                        * "mem=XXX[kKmM]" overrides the PROM-reported
-                        * memory size.
-                        */
-                       cmdline_memory_size = simple_strtoul(commands + 4,
-                                                            &commands, 0);
-                       if (*commands == 'K' || *commands == 'k') {
-                               cmdline_memory_size <<= 10;
-                               commands++;
-                       } else if (*commands=='M' || *commands=='m') {
-                               cmdline_memory_size <<= 20;
-                               commands++;
-                       }
-               }
+               if (!strncmp(commands, "mem=", 4))
+                       cmdline_memory_size = memparse(commands + 4, &commands);
+
                while (*commands && *commands != ' ')
                        commands++;
        }
@@ -500,12 +488,16 @@ static void __init init_sparc64_elf_hwcap(void)
                    sun4v_chip_type == SUN4V_CHIP_NIAGARA3 ||
                    sun4v_chip_type == SUN4V_CHIP_NIAGARA4 ||
                    sun4v_chip_type == SUN4V_CHIP_NIAGARA5 ||
+                   sun4v_chip_type == SUN4V_CHIP_SPARC_M6 ||
+                   sun4v_chip_type == SUN4V_CHIP_SPARC_M7 ||
                    sun4v_chip_type == SUN4V_CHIP_SPARC64X)
                        cap |= HWCAP_SPARC_BLKINIT;
                if (sun4v_chip_type == SUN4V_CHIP_NIAGARA2 ||
                    sun4v_chip_type == SUN4V_CHIP_NIAGARA3 ||
                    sun4v_chip_type == SUN4V_CHIP_NIAGARA4 ||
                    sun4v_chip_type == SUN4V_CHIP_NIAGARA5 ||
+                   sun4v_chip_type == SUN4V_CHIP_SPARC_M6 ||
+                   sun4v_chip_type == SUN4V_CHIP_SPARC_M7 ||
                    sun4v_chip_type == SUN4V_CHIP_SPARC64X)
                        cap |= HWCAP_SPARC_N2;
        }
@@ -533,6 +525,8 @@ static void __init init_sparc64_elf_hwcap(void)
                            sun4v_chip_type == SUN4V_CHIP_NIAGARA3 ||
                            sun4v_chip_type == SUN4V_CHIP_NIAGARA4 ||
                            sun4v_chip_type == SUN4V_CHIP_NIAGARA5 ||
+                           sun4v_chip_type == SUN4V_CHIP_SPARC_M6 ||
+                           sun4v_chip_type == SUN4V_CHIP_SPARC_M7 ||
                            sun4v_chip_type == SUN4V_CHIP_SPARC64X)
                                cap |= (AV_SPARC_VIS | AV_SPARC_VIS2 |
                                        AV_SPARC_ASI_BLK_INIT |
@@ -540,6 +534,8 @@ static void __init init_sparc64_elf_hwcap(void)
                        if (sun4v_chip_type == SUN4V_CHIP_NIAGARA3 ||
                            sun4v_chip_type == SUN4V_CHIP_NIAGARA4 ||
                            sun4v_chip_type == SUN4V_CHIP_NIAGARA5 ||
+                           sun4v_chip_type == SUN4V_CHIP_SPARC_M6 ||
+                           sun4v_chip_type == SUN4V_CHIP_SPARC_M7 ||
                            sun4v_chip_type == SUN4V_CHIP_SPARC64X)
                                cap |= (AV_SPARC_VIS3 | AV_SPARC_HPC |
                                        AV_SPARC_FMAF);
index f7ba87543e5ff092e723a14cf6df8403e343ac4c..302c476413d5c5eaeb29fd5cedd529f86de2d30f 100644 (file)
@@ -1138,7 +1138,7 @@ static unsigned long penguins_are_doing_time;
 
 void smp_capture(void)
 {
-       int result = atomic_add_ret(1, &smp_capture_depth);
+       int result = atomic_add_return(1, &smp_capture_depth);
 
        if (result == 1) {
                int ncpus = num_online_cpus();
@@ -1467,6 +1467,13 @@ static void __init pcpu_populate_pte(unsigned long addr)
        pud_t *pud;
        pmd_t *pmd;
 
+       if (pgd_none(*pgd)) {
+               pud_t *new;
+
+               new = __alloc_bootmem(PAGE_SIZE, PAGE_SIZE, PAGE_SIZE);
+               pgd_populate(&init_mm, pgd, new);
+       }
+
        pud = pud_offset(pgd, addr);
        if (pud_none(*pud)) {
                pmd_t *new;
index e0c09bf85610117e1632a86cfd87ef828d286709..6179e19bc9b98ea4542b59bb4953c1f9f2718330 100644 (file)
@@ -195,6 +195,11 @@ sun4v_tsb_miss_common:
         ldx    [%g2 + TRAP_PER_CPU_PGD_PADDR], %g7
 
 sun4v_itlb_error:
+       rdpr    %tl, %g1
+       cmp     %g1, 1
+       ble,pt  %icc, sun4v_bad_ra
+        or     %g0, FAULT_CODE_BAD_RA | FAULT_CODE_ITLB, %g1
+
        sethi   %hi(sun4v_err_itlb_vaddr), %g1
        stx     %g4, [%g1 + %lo(sun4v_err_itlb_vaddr)]
        sethi   %hi(sun4v_err_itlb_ctx), %g1
@@ -206,15 +211,10 @@ sun4v_itlb_error:
        sethi   %hi(sun4v_err_itlb_error), %g1
        stx     %o0, [%g1 + %lo(sun4v_err_itlb_error)]
 
+       sethi   %hi(1f), %g7
        rdpr    %tl, %g4
-       cmp     %g4, 1
-       ble,pt  %icc, 1f
-        sethi  %hi(2f), %g7
        ba,pt   %xcc, etraptl1
-        or     %g7, %lo(2f), %g7
-
-1:     ba,pt   %xcc, etrap
-2:      or     %g7, %lo(2b), %g7
+1:      or     %g7, %lo(1f), %g7
        mov     %l4, %o1
        call    sun4v_itlb_error_report
         add    %sp, PTREGS_OFF, %o0
@@ -222,6 +222,11 @@ sun4v_itlb_error:
        /* NOTREACHED */
 
 sun4v_dtlb_error:
+       rdpr    %tl, %g1
+       cmp     %g1, 1
+       ble,pt  %icc, sun4v_bad_ra
+        or     %g0, FAULT_CODE_BAD_RA | FAULT_CODE_DTLB, %g1
+
        sethi   %hi(sun4v_err_dtlb_vaddr), %g1
        stx     %g4, [%g1 + %lo(sun4v_err_dtlb_vaddr)]
        sethi   %hi(sun4v_err_dtlb_ctx), %g1
@@ -233,21 +238,23 @@ sun4v_dtlb_error:
        sethi   %hi(sun4v_err_dtlb_error), %g1
        stx     %o0, [%g1 + %lo(sun4v_err_dtlb_error)]
 
+       sethi   %hi(1f), %g7
        rdpr    %tl, %g4
-       cmp     %g4, 1
-       ble,pt  %icc, 1f
-        sethi  %hi(2f), %g7
        ba,pt   %xcc, etraptl1
-        or     %g7, %lo(2f), %g7
-
-1:     ba,pt   %xcc, etrap
-2:      or     %g7, %lo(2b), %g7
+1:      or     %g7, %lo(1f), %g7
        mov     %l4, %o1
        call    sun4v_dtlb_error_report
         add    %sp, PTREGS_OFF, %o0
 
        /* NOTREACHED */
 
+sun4v_bad_ra:
+       or      %g0, %g4, %g5
+       ba,pt   %xcc, sparc64_realfault_common
+        or     %g1, %g0, %g4
+
+       /* NOTREACHED */
+
        /* Instruction Access Exception, tl0. */
 sun4v_iacc:
        ldxa    [%g0] ASI_SCRATCHPAD, %g2
index fb6640ec8557a97281bf06dc0134d0feb0471d2c..981a769b955802573c00d184ed76581f68d88777 100644 (file)
@@ -2104,6 +2104,11 @@ void sun4v_nonresum_overflow(struct pt_regs *regs)
        atomic_inc(&sun4v_nonresum_oflow_cnt);
 }
 
+static void sun4v_tlb_error(struct pt_regs *regs)
+{
+       die_if_kernel("TLB/TSB error", regs);
+}
+
 unsigned long sun4v_err_itlb_vaddr;
 unsigned long sun4v_err_itlb_ctx;
 unsigned long sun4v_err_itlb_pte;
@@ -2111,8 +2116,7 @@ unsigned long sun4v_err_itlb_error;
 
 void sun4v_itlb_error_report(struct pt_regs *regs, int tl)
 {
-       if (tl > 1)
-               dump_tl1_traplog((struct tl1_traplog *)(regs + 1));
+       dump_tl1_traplog((struct tl1_traplog *)(regs + 1));
 
        printk(KERN_EMERG "SUN4V-ITLB: Error at TPC[%lx], tl %d\n",
               regs->tpc, tl);
@@ -2125,7 +2129,7 @@ void sun4v_itlb_error_report(struct pt_regs *regs, int tl)
               sun4v_err_itlb_vaddr, sun4v_err_itlb_ctx,
               sun4v_err_itlb_pte, sun4v_err_itlb_error);
 
-       prom_halt();
+       sun4v_tlb_error(regs);
 }
 
 unsigned long sun4v_err_dtlb_vaddr;
@@ -2135,8 +2139,7 @@ unsigned long sun4v_err_dtlb_error;
 
 void sun4v_dtlb_error_report(struct pt_regs *regs, int tl)
 {
-       if (tl > 1)
-               dump_tl1_traplog((struct tl1_traplog *)(regs + 1));
+       dump_tl1_traplog((struct tl1_traplog *)(regs + 1));
 
        printk(KERN_EMERG "SUN4V-DTLB: Error at TPC[%lx], tl %d\n",
               regs->tpc, tl);
@@ -2149,7 +2152,7 @@ void sun4v_dtlb_error_report(struct pt_regs *regs, int tl)
               sun4v_err_dtlb_vaddr, sun4v_err_dtlb_ctx,
               sun4v_err_dtlb_pte, sun4v_err_dtlb_error);
 
-       prom_halt();
+       sun4v_tlb_error(regs);
 }
 
 void hypervisor_tlbop_error(unsigned long err, unsigned long op)
index 8647fcc5ca6c5d5fad0f2b56f8865b8dcee876be..cb5789c9f9613ed692733d50dcf0e2c39784b1f7 100644 (file)
@@ -180,8 +180,10 @@ static void vio_fill_channel_info(struct mdesc_handle *hp, u64 mp,
                        vdev->tx_irq = sun4v_build_virq(cdev_cfg_handle, *irq);
 
                irq = mdesc_get_property(hp, target, "rx-ino", NULL);
-               if (irq)
+               if (irq) {
                        vdev->rx_irq = sun4v_build_virq(cdev_cfg_handle, *irq);
+                       vdev->rx_ino = *irq;
+               }
 
                chan_id = mdesc_get_property(hp, target, "id", NULL);
                if (chan_id)
@@ -189,6 +191,15 @@ static void vio_fill_channel_info(struct mdesc_handle *hp, u64 mp,
        }
 }
 
+int vio_set_intr(unsigned long dev_ino, int state)
+{
+       int err;
+
+       err = sun4v_vintr_set_valid(cdev_cfg_handle, dev_ino, state);
+       return err;
+}
+EXPORT_SYMBOL(vio_set_intr);
+
 static struct vio_dev *vio_create_one(struct mdesc_handle *hp, u64 mp,
                                      struct device *parent)
 {
index 7ef081a185b124cfd24757e9c7f206191efccfaa..526fcb5d8ce95d54c7afa7f5ea7c9c3a652dce3a 100644 (file)
@@ -724,7 +724,7 @@ int vio_ldc_alloc(struct vio_driver_state *vio,
        cfg.tx_irq = vio->vdev->tx_irq;
        cfg.rx_irq = vio->vdev->rx_irq;
 
-       lp = ldc_alloc(vio->vdev->channel_id, &cfg, event_arg);
+       lp = ldc_alloc(vio->vdev->channel_id, &cfg, event_arg, vio->name);
        if (IS_ERR(lp))
                return PTR_ERR(lp);
 
@@ -756,7 +756,7 @@ void vio_port_up(struct vio_driver_state *vio)
 
        err = 0;
        if (state == LDC_STATE_INIT) {
-               err = ldc_bind(vio->lp, vio->name);
+               err = ldc_bind(vio->lp);
                if (err)
                        printk(KERN_WARNING "%s: Port %lu bind failed, "
                               "err=%d\n",
index 932ff90fd7602b3f44aeac291f3e56936a197af2..09243057cb0b48f7fd1679129db63eb4094a8be6 100644 (file)
@@ -35,8 +35,9 @@ jiffies = jiffies_64;
 
 SECTIONS
 {
-       /* swapper_low_pmd_dir is sparc64 only */
-       swapper_low_pmd_dir = 0x0000000000402000;
+#ifdef CONFIG_SPARC64
+       swapper_pg_dir = 0x0000000000402000;
+#endif
        . = INITIAL_ADDRESS;
        .text TEXTSTART :
        {
@@ -122,11 +123,6 @@ SECTIONS
                *(.swapper_4m_tsb_phys_patch)
                __swapper_4m_tsb_phys_patch_end = .;
        }
-       .page_offset_shift_patch : {
-               __page_offset_shift_patch = .;
-               *(.page_offset_shift_patch)
-               __page_offset_shift_patch_end = .;
-       }
        .popc_3insn_patch : {
                __popc_3insn_patch = .;
                *(.popc_3insn_patch)
index 1d32b54089aad3e3d6094f9d3d013b4f3664602b..a7c418ac26afbb46500ff812d939a8aefff27945 100644 (file)
@@ -27,18 +27,23 @@ static DEFINE_SPINLOCK(dummy);
 
 #endif /* SMP */
 
-int __atomic_add_return(int i, atomic_t *v)
-{
-       int ret;
-       unsigned long flags;
-       spin_lock_irqsave(ATOMIC_HASH(v), flags);
-
-       ret = (v->counter += i);
-
-       spin_unlock_irqrestore(ATOMIC_HASH(v), flags);
-       return ret;
-}
-EXPORT_SYMBOL(__atomic_add_return);
+#define ATOMIC_OP(op, cop)                                             \
+int atomic_##op##_return(int i, atomic_t *v)                           \
+{                                                                      \
+       int ret;                                                        \
+       unsigned long flags;                                            \
+       spin_lock_irqsave(ATOMIC_HASH(v), flags);                       \
+                                                                       \
+       ret = (v->counter cop i);                                       \
+                                                                       \
+       spin_unlock_irqrestore(ATOMIC_HASH(v), flags);                  \
+       return ret;                                                     \
+}                                                                      \
+EXPORT_SYMBOL(atomic_##op##_return);
+
+ATOMIC_OP(add, +=)
+
+#undef ATOMIC_OP
 
 int atomic_cmpxchg(atomic_t *v, int old, int new)
 {
index 85c233d0a34003d551587c7c378bd813f64712fe..05dac43907d119ebb2f45037336e853f24068c2c 100644 (file)
         * memory barriers, and a second which returns
         * a value and does the barriers.
         */
-ENTRY(atomic_add) /* %o0 = increment, %o1 = atomic_ptr */
-       BACKOFF_SETUP(%o2)
-1:     lduw    [%o1], %g1
-       add     %g1, %o0, %g7
-       cas     [%o1], %g1, %g7
-       cmp     %g1, %g7
-       bne,pn  %icc, BACKOFF_LABEL(2f, 1b)
-        nop
-       retl
-        nop
-2:     BACKOFF_SPIN(%o2, %o3, 1b)
-ENDPROC(atomic_add)
 
-ENTRY(atomic_sub) /* %o0 = decrement, %o1 = atomic_ptr */
-       BACKOFF_SETUP(%o2)
-1:     lduw    [%o1], %g1
-       sub     %g1, %o0, %g7
-       cas     [%o1], %g1, %g7
-       cmp     %g1, %g7
-       bne,pn  %icc, BACKOFF_LABEL(2f, 1b)
-        nop
-       retl
-        nop
-2:     BACKOFF_SPIN(%o2, %o3, 1b)
-ENDPROC(atomic_sub)
+#define ATOMIC_OP(op)                                                  \
+ENTRY(atomic_##op) /* %o0 = increment, %o1 = atomic_ptr */             \
+       BACKOFF_SETUP(%o2);                                             \
+1:     lduw    [%o1], %g1;                                             \
+       op      %g1, %o0, %g7;                                          \
+       cas     [%o1], %g1, %g7;                                        \
+       cmp     %g1, %g7;                                               \
+       bne,pn  %icc, BACKOFF_LABEL(2f, 1b);                            \
+        nop;                                                           \
+       retl;                                                           \
+        nop;                                                           \
+2:     BACKOFF_SPIN(%o2, %o3, 1b);                                     \
+ENDPROC(atomic_##op);                                                  \
 
-ENTRY(atomic_add_ret) /* %o0 = increment, %o1 = atomic_ptr */
-       BACKOFF_SETUP(%o2)
-1:     lduw    [%o1], %g1
-       add     %g1, %o0, %g7
-       cas     [%o1], %g1, %g7
-       cmp     %g1, %g7
-       bne,pn  %icc, BACKOFF_LABEL(2f, 1b)
-        add    %g1, %o0, %g1
-       retl
-        sra    %g1, 0, %o0
-2:     BACKOFF_SPIN(%o2, %o3, 1b)
-ENDPROC(atomic_add_ret)
+#define ATOMIC_OP_RETURN(op)                                           \
+ENTRY(atomic_##op##_return) /* %o0 = increment, %o1 = atomic_ptr */    \
+       BACKOFF_SETUP(%o2);                                             \
+1:     lduw    [%o1], %g1;                                             \
+       op      %g1, %o0, %g7;                                          \
+       cas     [%o1], %g1, %g7;                                        \
+       cmp     %g1, %g7;                                               \
+       bne,pn  %icc, BACKOFF_LABEL(2f, 1b);                            \
+        op     %g1, %o0, %g1;                                          \
+       retl;                                                           \
+        sra    %g1, 0, %o0;                                            \
+2:     BACKOFF_SPIN(%o2, %o3, 1b);                                     \
+ENDPROC(atomic_##op##_return);
 
-ENTRY(atomic_sub_ret) /* %o0 = decrement, %o1 = atomic_ptr */
-       BACKOFF_SETUP(%o2)
-1:     lduw    [%o1], %g1
-       sub     %g1, %o0, %g7
-       cas     [%o1], %g1, %g7
-       cmp     %g1, %g7
-       bne,pn  %icc, BACKOFF_LABEL(2f, 1b)
-        sub    %g1, %o0, %g1
-       retl
-        sra    %g1, 0, %o0
-2:     BACKOFF_SPIN(%o2, %o3, 1b)
-ENDPROC(atomic_sub_ret)
+#define ATOMIC_OPS(op) ATOMIC_OP(op) ATOMIC_OP_RETURN(op)
 
-ENTRY(atomic64_add) /* %o0 = increment, %o1 = atomic_ptr */
-       BACKOFF_SETUP(%o2)
-1:     ldx     [%o1], %g1
-       add     %g1, %o0, %g7
-       casx    [%o1], %g1, %g7
-       cmp     %g1, %g7
-       bne,pn  %xcc, BACKOFF_LABEL(2f, 1b)
-        nop
-       retl
-        nop
-2:     BACKOFF_SPIN(%o2, %o3, 1b)
-ENDPROC(atomic64_add)
+ATOMIC_OPS(add)
+ATOMIC_OPS(sub)
 
-ENTRY(atomic64_sub) /* %o0 = decrement, %o1 = atomic_ptr */
-       BACKOFF_SETUP(%o2)
-1:     ldx     [%o1], %g1
-       sub     %g1, %o0, %g7
-       casx    [%o1], %g1, %g7
-       cmp     %g1, %g7
-       bne,pn  %xcc, BACKOFF_LABEL(2f, 1b)
-        nop
-       retl
-        nop
-2:     BACKOFF_SPIN(%o2, %o3, 1b)
-ENDPROC(atomic64_sub)
+#undef ATOMIC_OPS
+#undef ATOMIC_OP_RETURN
+#undef ATOMIC_OP
 
-ENTRY(atomic64_add_ret) /* %o0 = increment, %o1 = atomic_ptr */
-       BACKOFF_SETUP(%o2)
-1:     ldx     [%o1], %g1
-       add     %g1, %o0, %g7
-       casx    [%o1], %g1, %g7
-       cmp     %g1, %g7
-       bne,pn  %xcc, BACKOFF_LABEL(2f, 1b)
-        nop
-       retl
-        add    %g1, %o0, %o0
-2:     BACKOFF_SPIN(%o2, %o3, 1b)
-ENDPROC(atomic64_add_ret)
+#define ATOMIC64_OP(op)                                                        \
+ENTRY(atomic64_##op) /* %o0 = increment, %o1 = atomic_ptr */           \
+       BACKOFF_SETUP(%o2);                                             \
+1:     ldx     [%o1], %g1;                                             \
+       op      %g1, %o0, %g7;                                          \
+       casx    [%o1], %g1, %g7;                                        \
+       cmp     %g1, %g7;                                               \
+       bne,pn  %xcc, BACKOFF_LABEL(2f, 1b);                            \
+        nop;                                                           \
+       retl;                                                           \
+        nop;                                                           \
+2:     BACKOFF_SPIN(%o2, %o3, 1b);                                     \
+ENDPROC(atomic64_##op);                                                        \
 
-ENTRY(atomic64_sub_ret) /* %o0 = decrement, %o1 = atomic_ptr */
-       BACKOFF_SETUP(%o2)
-1:     ldx     [%o1], %g1
-       sub     %g1, %o0, %g7
-       casx    [%o1], %g1, %g7
-       cmp     %g1, %g7
-       bne,pn  %xcc, BACKOFF_LABEL(2f, 1b)
-        nop
-       retl
-        sub    %g1, %o0, %o0
-2:     BACKOFF_SPIN(%o2, %o3, 1b)
-ENDPROC(atomic64_sub_ret)
+#define ATOMIC64_OP_RETURN(op)                                         \
+ENTRY(atomic64_##op##_return) /* %o0 = increment, %o1 = atomic_ptr */  \
+       BACKOFF_SETUP(%o2);                                             \
+1:     ldx     [%o1], %g1;                                             \
+       op      %g1, %o0, %g7;                                          \
+       casx    [%o1], %g1, %g7;                                        \
+       cmp     %g1, %g7;                                               \
+       bne,pn  %xcc, BACKOFF_LABEL(2f, 1b);                            \
+        nop;                                                           \
+       retl;                                                           \
+        op     %g1, %o0, %o0;                                          \
+2:     BACKOFF_SPIN(%o2, %o3, 1b);                                     \
+ENDPROC(atomic64_##op##_return);
+
+#define ATOMIC64_OPS(op) ATOMIC64_OP(op) ATOMIC64_OP_RETURN(op)
+
+ATOMIC64_OPS(add)
+ATOMIC64_OPS(sub)
+
+#undef ATOMIC64_OPS
+#undef ATOMIC64_OP_RETURN
+#undef ATOMIC64_OP
 
 ENTRY(atomic64_dec_if_positive) /* %o0 = atomic_ptr */
        BACKOFF_SETUP(%o2)
index 323335b9cd2b5cc9d08f3fc100f088773c87a4aa..1d649a95660c8cad57fbe90feadb7c43b9e8263f 100644 (file)
@@ -99,14 +99,23 @@ EXPORT_SYMBOL(___copy_in_user);
 EXPORT_SYMBOL(__clear_user);
 
 /* Atomic counter implementation. */
-EXPORT_SYMBOL(atomic_add);
-EXPORT_SYMBOL(atomic_add_ret);
-EXPORT_SYMBOL(atomic_sub);
-EXPORT_SYMBOL(atomic_sub_ret);
-EXPORT_SYMBOL(atomic64_add);
-EXPORT_SYMBOL(atomic64_add_ret);
-EXPORT_SYMBOL(atomic64_sub);
-EXPORT_SYMBOL(atomic64_sub_ret);
+#define ATOMIC_OP(op)                                                  \
+EXPORT_SYMBOL(atomic_##op);                                            \
+EXPORT_SYMBOL(atomic64_##op);
+
+#define ATOMIC_OP_RETURN(op)                                           \
+EXPORT_SYMBOL(atomic_##op##_return);                                   \
+EXPORT_SYMBOL(atomic64_##op##_return);
+
+#define ATOMIC_OPS(op) ATOMIC_OP(op) ATOMIC_OP_RETURN(op)
+
+ATOMIC_OPS(add)
+ATOMIC_OPS(sub)
+
+#undef ATOMIC_OPS
+#undef ATOMIC_OP_RETURN
+#undef ATOMIC_OP
+
 EXPORT_SYMBOL(atomic64_dec_if_positive);
 
 /* Atomic bit operations. */
index 99c017be8719609bbc6e99ada83610e2d38763a1..f75e6906df146aae9a99cc83c6750903f9853783 100644 (file)
@@ -3,8 +3,9 @@
  * Copyright (C) 1996,1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
  * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
  *
- * Returns 0, if ok, and number of bytes not yet set if exception
- * occurs and we were called as clear_user.
+ * Calls to memset returns initial %o0. Calls to bzero returns 0, if ok, and
+ * number of bytes not yet set if exception occurs and we were called as
+ * clear_user.
  */
 
 #include <asm/ptrace.h>
@@ -65,6 +66,8 @@ __bzero_begin:
        .globl  __memset_start, __memset_end
 __memset_start:
 memset:
+       mov     %o0, %g1
+       mov     1, %g4
        and     %o1, 0xff, %g3
        sll     %g3, 8, %g2
        or      %g3, %g2, %g3
@@ -89,6 +92,7 @@ memset:
         sub    %o0, %o2, %o0
 
 __bzero:
+       clr     %g4
        mov     %g0, %g3
 1:
        cmp     %o1, 7
@@ -151,8 +155,8 @@ __bzero:
        bne,a   8f
         EX(stb %g3, [%o0], and %o1, 1)
 8:
-       retl
-        clr    %o0
+       b       0f
+        nop
 7:
        be      13b
         orcc   %o1, 0, %g0
@@ -164,6 +168,12 @@ __bzero:
        bne     8b
         EX(stb %g3, [%o0 - 1], add %o1, 1)
 0:
+       andcc   %g4, 1, %g0
+       be      5f
+        nop
+       retl
+        mov    %g1, %o0
+5:
        retl
         clr    %o0
 __memset_end:
index 587cd056512850f4b47f59fed47355fe07b41375..18fcd71670959291f8ef4933e37d5bc394e98f51 100644 (file)
@@ -346,6 +346,9 @@ retry:
                down_read(&mm->mmap_sem);
        }
 
+       if (fault_code & FAULT_CODE_BAD_RA)
+               goto do_sigbus;
+
        vma = find_vma(mm, address);
        if (!vma)
                goto bad_area;
index 98ac8e80adae07a841ade82c0ec3d5896f3aa3dd..2d91c62f7f5f156524b7bef4ff7737701c08db85 100644 (file)
@@ -75,7 +75,6 @@ unsigned long kern_linear_pte_xor[4] __read_mostly;
  * 'cpu' properties, but we need to have this table setup before the
  * MDESC is initialized.
  */
-unsigned long kpte_linear_bitmap[KPTE_BITMAP_BYTES / sizeof(unsigned long)];
 
 #ifndef CONFIG_DEBUG_PAGEALLOC
 /* A special kernel TSB for 4MB, 256MB, 2GB and 16GB linear mappings.
@@ -84,10 +83,11 @@ unsigned long kpte_linear_bitmap[KPTE_BITMAP_BYTES / sizeof(unsigned long)];
  */
 extern struct tsb swapper_4m_tsb[KERNEL_TSB4M_NENTRIES];
 #endif
+extern struct tsb swapper_tsb[KERNEL_TSB_NENTRIES];
 
 static unsigned long cpu_pgsz_mask;
 
-#define MAX_BANKS      32
+#define MAX_BANKS      1024
 
 static struct linux_prom64_registers pavail[MAX_BANKS];
 static int pavail_ents;
@@ -165,10 +165,6 @@ static void __init read_obp_memory(const char *property,
             cmp_p64, NULL);
 }
 
-unsigned long sparc64_valid_addr_bitmap[VALID_ADDR_BITMAP_BYTES /
-                                       sizeof(unsigned long)];
-EXPORT_SYMBOL(sparc64_valid_addr_bitmap);
-
 /* Kernel physical address base and size in bytes.  */
 unsigned long kern_base __read_mostly;
 unsigned long kern_size __read_mostly;
@@ -840,7 +836,10 @@ static int find_node(unsigned long addr)
                if ((addr & p->mask) == p->val)
                        return i;
        }
-       return -1;
+       /* The following condition has been observed on LDOM guests.*/
+       WARN_ONCE(1, "find_node: A physical address doesn't match a NUMA node"
+               " rule. Some physical memory will be owned by node 0.");
+       return 0;
 }
 
 static u64 memblock_nid_range(u64 start, u64 end, int *nid)
@@ -1366,9 +1365,144 @@ static unsigned long __init bootmem_init(unsigned long phys_base)
 static struct linux_prom64_registers pall[MAX_BANKS] __initdata;
 static int pall_ents __initdata;
 
-#ifdef CONFIG_DEBUG_PAGEALLOC
+static unsigned long max_phys_bits = 40;
+
+bool kern_addr_valid(unsigned long addr)
+{
+       pgd_t *pgd;
+       pud_t *pud;
+       pmd_t *pmd;
+       pte_t *pte;
+
+       if ((long)addr < 0L) {
+               unsigned long pa = __pa(addr);
+
+               if ((addr >> max_phys_bits) != 0UL)
+                       return false;
+
+               return pfn_valid(pa >> PAGE_SHIFT);
+       }
+
+       if (addr >= (unsigned long) KERNBASE &&
+           addr < (unsigned long)&_end)
+               return true;
+
+       pgd = pgd_offset_k(addr);
+       if (pgd_none(*pgd))
+               return 0;
+
+       pud = pud_offset(pgd, addr);
+       if (pud_none(*pud))
+               return 0;
+
+       if (pud_large(*pud))
+               return pfn_valid(pud_pfn(*pud));
+
+       pmd = pmd_offset(pud, addr);
+       if (pmd_none(*pmd))
+               return 0;
+
+       if (pmd_large(*pmd))
+               return pfn_valid(pmd_pfn(*pmd));
+
+       pte = pte_offset_kernel(pmd, addr);
+       if (pte_none(*pte))
+               return 0;
+
+       return pfn_valid(pte_pfn(*pte));
+}
+EXPORT_SYMBOL(kern_addr_valid);
+
+static unsigned long __ref kernel_map_hugepud(unsigned long vstart,
+                                             unsigned long vend,
+                                             pud_t *pud)
+{
+       const unsigned long mask16gb = (1UL << 34) - 1UL;
+       u64 pte_val = vstart;
+
+       /* Each PUD is 8GB */
+       if ((vstart & mask16gb) ||
+           (vend - vstart <= mask16gb)) {
+               pte_val ^= kern_linear_pte_xor[2];
+               pud_val(*pud) = pte_val | _PAGE_PUD_HUGE;
+
+               return vstart + PUD_SIZE;
+       }
+
+       pte_val ^= kern_linear_pte_xor[3];
+       pte_val |= _PAGE_PUD_HUGE;
+
+       vend = vstart + mask16gb + 1UL;
+       while (vstart < vend) {
+               pud_val(*pud) = pte_val;
+
+               pte_val += PUD_SIZE;
+               vstart += PUD_SIZE;
+               pud++;
+       }
+       return vstart;
+}
+
+static bool kernel_can_map_hugepud(unsigned long vstart, unsigned long vend,
+                                  bool guard)
+{
+       if (guard && !(vstart & ~PUD_MASK) && (vend - vstart) >= PUD_SIZE)
+               return true;
+
+       return false;
+}
+
+static unsigned long __ref kernel_map_hugepmd(unsigned long vstart,
+                                             unsigned long vend,
+                                             pmd_t *pmd)
+{
+       const unsigned long mask256mb = (1UL << 28) - 1UL;
+       const unsigned long mask2gb = (1UL << 31) - 1UL;
+       u64 pte_val = vstart;
+
+       /* Each PMD is 8MB */
+       if ((vstart & mask256mb) ||
+           (vend - vstart <= mask256mb)) {
+               pte_val ^= kern_linear_pte_xor[0];
+               pmd_val(*pmd) = pte_val | _PAGE_PMD_HUGE;
+
+               return vstart + PMD_SIZE;
+       }
+
+       if ((vstart & mask2gb) ||
+           (vend - vstart <= mask2gb)) {
+               pte_val ^= kern_linear_pte_xor[1];
+               pte_val |= _PAGE_PMD_HUGE;
+               vend = vstart + mask256mb + 1UL;
+       } else {
+               pte_val ^= kern_linear_pte_xor[2];
+               pte_val |= _PAGE_PMD_HUGE;
+               vend = vstart + mask2gb + 1UL;
+       }
+
+       while (vstart < vend) {
+               pmd_val(*pmd) = pte_val;
+
+               pte_val += PMD_SIZE;
+               vstart += PMD_SIZE;
+               pmd++;
+       }
+
+       return vstart;
+}
+
+static bool kernel_can_map_hugepmd(unsigned long vstart, unsigned long vend,
+                                  bool guard)
+{
+       if (guard && !(vstart & ~PMD_MASK) && (vend - vstart) >= PMD_SIZE)
+               return true;
+
+       return false;
+}
+
 static unsigned long __ref kernel_map_range(unsigned long pstart,
-                                           unsigned long pend, pgprot_t prot)
+                                           unsigned long pend, pgprot_t prot,
+                                           bool use_huge)
 {
        unsigned long vstart = PAGE_OFFSET + pstart;
        unsigned long vend = PAGE_OFFSET + pend;
@@ -1387,19 +1521,34 @@ static unsigned long __ref kernel_map_range(unsigned long pstart,
                pmd_t *pmd;
                pte_t *pte;
 
+               if (pgd_none(*pgd)) {
+                       pud_t *new;
+
+                       new = __alloc_bootmem(PAGE_SIZE, PAGE_SIZE, PAGE_SIZE);
+                       alloc_bytes += PAGE_SIZE;
+                       pgd_populate(&init_mm, pgd, new);
+               }
                pud = pud_offset(pgd, vstart);
                if (pud_none(*pud)) {
                        pmd_t *new;
 
+                       if (kernel_can_map_hugepud(vstart, vend, use_huge)) {
+                               vstart = kernel_map_hugepud(vstart, vend, pud);
+                               continue;
+                       }
                        new = __alloc_bootmem(PAGE_SIZE, PAGE_SIZE, PAGE_SIZE);
                        alloc_bytes += PAGE_SIZE;
                        pud_populate(&init_mm, pud, new);
                }
 
                pmd = pmd_offset(pud, vstart);
-               if (!pmd_present(*pmd)) {
+               if (pmd_none(*pmd)) {
                        pte_t *new;
 
+                       if (kernel_can_map_hugepmd(vstart, vend, use_huge)) {
+                               vstart = kernel_map_hugepmd(vstart, vend, pmd);
+                               continue;
+                       }
                        new = __alloc_bootmem(PAGE_SIZE, PAGE_SIZE, PAGE_SIZE);
                        alloc_bytes += PAGE_SIZE;
                        pmd_populate_kernel(&init_mm, pmd, new);
@@ -1422,100 +1571,34 @@ static unsigned long __ref kernel_map_range(unsigned long pstart,
        return alloc_bytes;
 }
 
-extern unsigned int kvmap_linear_patch[1];
-#endif /* CONFIG_DEBUG_PAGEALLOC */
-
-static void __init kpte_set_val(unsigned long index, unsigned long val)
-{
-       unsigned long *ptr = kpte_linear_bitmap;
-
-       val <<= ((index % (BITS_PER_LONG / 2)) * 2);
-       ptr += (index / (BITS_PER_LONG / 2));
-
-       *ptr |= val;
-}
-
-static const unsigned long kpte_shift_min = 28; /* 256MB */
-static const unsigned long kpte_shift_max = 34; /* 16GB */
-static const unsigned long kpte_shift_incr = 3;
-
-static unsigned long kpte_mark_using_shift(unsigned long start, unsigned long end,
-                                          unsigned long shift)
+static void __init flush_all_kernel_tsbs(void)
 {
-       unsigned long size = (1UL << shift);
-       unsigned long mask = (size - 1UL);
-       unsigned long remains = end - start;
-       unsigned long val;
-
-       if (remains < size || (start & mask))
-               return start;
-
-       /* VAL maps:
-        *
-        *      shift 28 --> kern_linear_pte_xor index 1
-        *      shift 31 --> kern_linear_pte_xor index 2
-        *      shift 34 --> kern_linear_pte_xor index 3
-        */
-       val = ((shift - kpte_shift_min) / kpte_shift_incr) + 1;
-
-       remains &= ~mask;
-       if (shift != kpte_shift_max)
-               remains = size;
-
-       while (remains) {
-               unsigned long index = start >> kpte_shift_min;
+       int i;
 
-               kpte_set_val(index, val);
+       for (i = 0; i < KERNEL_TSB_NENTRIES; i++) {
+               struct tsb *ent = &swapper_tsb[i];
 
-               start += 1UL << kpte_shift_min;
-               remains -= 1UL << kpte_shift_min;
+               ent->tag = (1UL << TSB_TAG_INVALID_BIT);
        }
+#ifndef CONFIG_DEBUG_PAGEALLOC
+       for (i = 0; i < KERNEL_TSB4M_NENTRIES; i++) {
+               struct tsb *ent = &swapper_4m_tsb[i];
 
-       return start;
-}
-
-static void __init mark_kpte_bitmap(unsigned long start, unsigned long end)
-{
-       unsigned long smallest_size, smallest_mask;
-       unsigned long s;
-
-       smallest_size = (1UL << kpte_shift_min);
-       smallest_mask = (smallest_size - 1UL);
-
-       while (start < end) {
-               unsigned long orig_start = start;
-
-               for (s = kpte_shift_max; s >= kpte_shift_min; s -= kpte_shift_incr) {
-                       start = kpte_mark_using_shift(start, end, s);
-
-                       if (start != orig_start)
-                               break;
-               }
-
-               if (start == orig_start)
-                       start = (start + smallest_size) & ~smallest_mask;
+               ent->tag = (1UL << TSB_TAG_INVALID_BIT);
        }
+#endif
 }
 
-static void __init init_kpte_bitmap(void)
-{
-       unsigned long i;
-
-       for (i = 0; i < pall_ents; i++) {
-               unsigned long phys_start, phys_end;
-
-               phys_start = pall[i].phys_addr;
-               phys_end = phys_start + pall[i].reg_size;
-
-               mark_kpte_bitmap(phys_start, phys_end);
-       }
-}
+extern unsigned int kvmap_linear_patch[1];
 
 static void __init kernel_physical_mapping_init(void)
 {
-#ifdef CONFIG_DEBUG_PAGEALLOC
        unsigned long i, mem_alloced = 0UL;
+       bool use_huge = true;
 
+#ifdef CONFIG_DEBUG_PAGEALLOC
+       use_huge = false;
+#endif
        for (i = 0; i < pall_ents; i++) {
                unsigned long phys_start, phys_end;
 
@@ -1523,7 +1606,7 @@ static void __init kernel_physical_mapping_init(void)
                phys_end = phys_start + pall[i].reg_size;
 
                mem_alloced += kernel_map_range(phys_start, phys_end,
-                                               PAGE_KERNEL);
+                                               PAGE_KERNEL, use_huge);
        }
 
        printk("Allocated %ld bytes for kernel page tables.\n",
@@ -1532,8 +1615,9 @@ static void __init kernel_physical_mapping_init(void)
        kvmap_linear_patch[0] = 0x01000000; /* nop */
        flushi(&kvmap_linear_patch[0]);
 
+       flush_all_kernel_tsbs();
+
        __flush_tlb_all();
-#endif
 }
 
 #ifdef CONFIG_DEBUG_PAGEALLOC
@@ -1543,7 +1627,7 @@ void kernel_map_pages(struct page *page, int numpages, int enable)
        unsigned long phys_end = phys_start + (numpages * PAGE_SIZE);
 
        kernel_map_range(phys_start, phys_end,
-                        (enable ? PAGE_KERNEL : __pgprot(0)));
+                        (enable ? PAGE_KERNEL : __pgprot(0)), false);
 
        flush_tsb_kernel_range(PAGE_OFFSET + phys_start,
                               PAGE_OFFSET + phys_end);
@@ -1571,76 +1655,56 @@ unsigned long __init find_ecache_flush_span(unsigned long size)
 unsigned long PAGE_OFFSET;
 EXPORT_SYMBOL(PAGE_OFFSET);
 
-static void __init page_offset_shift_patch_one(unsigned int *insn, unsigned long phys_bits)
-{
-       unsigned long final_shift;
-       unsigned int val = *insn;
-       unsigned int cnt;
-
-       /* We are patching in ilog2(max_supported_phys_address), and
-        * we are doing so in a manner similar to a relocation addend.
-        * That is, we are adding the shift value to whatever value
-        * is in the shift instruction count field already.
-        */
-       cnt = (val & 0x3f);
-       val &= ~0x3f;
-
-       /* If we are trying to shift >= 64 bits, clear the destination
-        * register.  This can happen when phys_bits ends up being equal
-        * to MAX_PHYS_ADDRESS_BITS.
-        */
-       final_shift = (cnt + (64 - phys_bits));
-       if (final_shift >= 64) {
-               unsigned int rd = (val >> 25) & 0x1f;
-
-               val = 0x80100000 | (rd << 25);
-       } else {
-               val |= final_shift;
-       }
-       *insn = val;
-
-       __asm__ __volatile__("flush     %0"
-                            : /* no outputs */
-                            : "r" (insn));
-}
-
-static void __init page_offset_shift_patch(unsigned long phys_bits)
-{
-       extern unsigned int __page_offset_shift_patch;
-       extern unsigned int __page_offset_shift_patch_end;
-       unsigned int *p;
-
-       p = &__page_offset_shift_patch;
-       while (p < &__page_offset_shift_patch_end) {
-               unsigned int *insn = (unsigned int *)(unsigned long)*p;
+unsigned long VMALLOC_END   = 0x0000010000000000UL;
+EXPORT_SYMBOL(VMALLOC_END);
 
-               page_offset_shift_patch_one(insn, phys_bits);
-
-               p++;
-       }
-}
+unsigned long sparc64_va_hole_top =    0xfffff80000000000UL;
+unsigned long sparc64_va_hole_bottom = 0x0000080000000000UL;
 
 static void __init setup_page_offset(void)
 {
-       unsigned long max_phys_bits = 40;
-
        if (tlb_type == cheetah || tlb_type == cheetah_plus) {
+               /* Cheetah/Panther support a full 64-bit virtual
+                * address, so we can use all that our page tables
+                * support.
+                */
+               sparc64_va_hole_top =    0xfff0000000000000UL;
+               sparc64_va_hole_bottom = 0x0010000000000000UL;
+
                max_phys_bits = 42;
        } else if (tlb_type == hypervisor) {
                switch (sun4v_chip_type) {
                case SUN4V_CHIP_NIAGARA1:
                case SUN4V_CHIP_NIAGARA2:
+                       /* T1 and T2 support 48-bit virtual addresses.  */
+                       sparc64_va_hole_top =    0xffff800000000000UL;
+                       sparc64_va_hole_bottom = 0x0000800000000000UL;
+
                        max_phys_bits = 39;
                        break;
                case SUN4V_CHIP_NIAGARA3:
+                       /* T3 supports 48-bit virtual addresses.  */
+                       sparc64_va_hole_top =    0xffff800000000000UL;
+                       sparc64_va_hole_bottom = 0x0000800000000000UL;
+
                        max_phys_bits = 43;
                        break;
                case SUN4V_CHIP_NIAGARA4:
                case SUN4V_CHIP_NIAGARA5:
                case SUN4V_CHIP_SPARC64X:
-               default:
+               case SUN4V_CHIP_SPARC_M6:
+                       /* T4 and later support 52-bit virtual addresses.  */
+                       sparc64_va_hole_top =    0xfff8000000000000UL;
+                       sparc64_va_hole_bottom = 0x0008000000000000UL;
                        max_phys_bits = 47;
                        break;
+               case SUN4V_CHIP_SPARC_M7:
+               default:
+                       /* M7 and later support 52-bit virtual addresses.  */
+                       sparc64_va_hole_top =    0xfff8000000000000UL;
+                       sparc64_va_hole_bottom = 0x0008000000000000UL;
+                       max_phys_bits = 49;
+                       break;
                }
        }
 
@@ -1650,12 +1714,16 @@ static void __init setup_page_offset(void)
                prom_halt();
        }
 
-       PAGE_OFFSET = PAGE_OFFSET_BY_BITS(max_phys_bits);
+       PAGE_OFFSET = sparc64_va_hole_top;
+       VMALLOC_END = ((sparc64_va_hole_bottom >> 1) +
+                      (sparc64_va_hole_bottom >> 2));
 
-       pr_info("PAGE_OFFSET is 0x%016lx (max_phys_bits == %lu)\n",
+       pr_info("MM: PAGE_OFFSET is 0x%016lx (max_phys_bits == %lu)\n",
                PAGE_OFFSET, max_phys_bits);
-
-       page_offset_shift_patch(max_phys_bits);
+       pr_info("MM: VMALLOC [0x%016lx --> 0x%016lx]\n",
+               VMALLOC_START, VMALLOC_END);
+       pr_info("MM: VMEMMAP [0x%016lx --> 0x%016lx]\n",
+               VMEMMAP_BASE, VMEMMAP_BASE << 1);
 }
 
 static void __init tsb_phys_patch(void)
@@ -1700,21 +1768,42 @@ static void __init tsb_phys_patch(void)
 #define NUM_KTSB_DESCR 1
 #endif
 static struct hv_tsb_descr ktsb_descr[NUM_KTSB_DESCR];
-extern struct tsb swapper_tsb[KERNEL_TSB_NENTRIES];
+
+/* The swapper TSBs are loaded with a base sequence of:
+ *
+ *     sethi   %uhi(SYMBOL), REG1
+ *     sethi   %hi(SYMBOL), REG2
+ *     or      REG1, %ulo(SYMBOL), REG1
+ *     or      REG2, %lo(SYMBOL), REG2
+ *     sllx    REG1, 32, REG1
+ *     or      REG1, REG2, REG1
+ *
+ * When we use physical addressing for the TSB accesses, we patch the
+ * first four instructions in the above sequence.
+ */
 
 static void patch_one_ktsb_phys(unsigned int *start, unsigned int *end, unsigned long pa)
 {
-       pa >>= KTSB_PHYS_SHIFT;
+       unsigned long high_bits, low_bits;
+
+       high_bits = (pa >> 32) & 0xffffffff;
+       low_bits = (pa >> 0) & 0xffffffff;
 
        while (start < end) {
                unsigned int *ia = (unsigned int *)(unsigned long)*start;
 
-               ia[0] = (ia[0] & ~0x3fffff) | (pa >> 10);
+               ia[0] = (ia[0] & ~0x3fffff) | (high_bits >> 10);
                __asm__ __volatile__("flush     %0" : : "r" (ia));
 
-               ia[1] = (ia[1] & ~0x3ff) | (pa & 0x3ff);
+               ia[1] = (ia[1] & ~0x3fffff) | (low_bits >> 10);
                __asm__ __volatile__("flush     %0" : : "r" (ia + 1));
 
+               ia[2] = (ia[2] & ~0x1fff) | (high_bits & 0x3ff);
+               __asm__ __volatile__("flush     %0" : : "r" (ia + 2));
+
+               ia[3] = (ia[3] & ~0x1fff) | (low_bits & 0x3ff);
+               __asm__ __volatile__("flush     %0" : : "r" (ia + 3));
+
                start++;
        }
 }
@@ -1853,11 +1942,56 @@ static void __init sun4v_linear_pte_xor_finalize(void)
 /* paging_init() sets up the page tables */
 
 static unsigned long last_valid_pfn;
-pgd_t swapper_pg_dir[PTRS_PER_PGD];
 
 static void sun4u_pgprot_init(void);
 static void sun4v_pgprot_init(void);
 
+static phys_addr_t __init available_memory(void)
+{
+       phys_addr_t available = 0ULL;
+       phys_addr_t pa_start, pa_end;
+       u64 i;
+
+       for_each_free_mem_range(i, NUMA_NO_NODE, &pa_start, &pa_end, NULL)
+               available = available + (pa_end  - pa_start);
+
+       return available;
+}
+
+/* We need to exclude reserved regions. This exclusion will include
+ * vmlinux and initrd. To be more precise the initrd size could be used to
+ * compute a new lower limit because it is freed later during initialization.
+ */
+static void __init reduce_memory(phys_addr_t limit_ram)
+{
+       phys_addr_t avail_ram = available_memory();
+       phys_addr_t pa_start, pa_end;
+       u64 i;
+
+       if (limit_ram >= avail_ram)
+               return;
+
+       for_each_free_mem_range(i, NUMA_NO_NODE, &pa_start, &pa_end, NULL) {
+               phys_addr_t region_size = pa_end - pa_start;
+               phys_addr_t clip_start = pa_start;
+
+               avail_ram = avail_ram - region_size;
+               /* Are we consuming too much? */
+               if (avail_ram < limit_ram) {
+                       phys_addr_t give_back = limit_ram - avail_ram;
+
+                       region_size = region_size - give_back;
+                       clip_start = clip_start + give_back;
+               }
+
+               memblock_remove(clip_start, region_size);
+
+               if (avail_ram <= limit_ram)
+                       break;
+               i = 0UL;
+       }
+}
+
 void __init paging_init(void)
 {
        unsigned long end_pfn, shift, phys_base;
@@ -1937,7 +2071,8 @@ void __init paging_init(void)
 
        find_ramdisk(phys_base);
 
-       memblock_enforce_memory_limit(cmdline_memory_size);
+       if (cmdline_memory_size)
+               reduce_memory(cmdline_memory_size);
 
        memblock_allow_resize();
        memblock_dump_all();
@@ -1956,16 +2091,10 @@ void __init paging_init(void)
         */
        init_mm.pgd += ((shift) / (sizeof(pgd_t)));
        
-       memset(swapper_low_pmd_dir, 0, sizeof(swapper_low_pmd_dir));
+       memset(swapper_pg_dir, 0, sizeof(swapper_pg_dir));
 
-       /* Now can init the kernel/bad page tables. */
-       pud_set(pud_offset(&swapper_pg_dir[0], 0),
-               swapper_low_pmd_dir + (shift / sizeof(pgd_t)));
-       
        inherit_prom_mappings();
        
-       init_kpte_bitmap();
-
        /* Ok, we can use our TLB miss and window trap handlers safely.  */
        setup_tba();
 
@@ -2072,70 +2201,6 @@ int page_in_phys_avail(unsigned long paddr)
        return 0;
 }
 
-static struct linux_prom64_registers pavail_rescan[MAX_BANKS] __initdata;
-static int pavail_rescan_ents __initdata;
-
-/* Certain OBP calls, such as fetching "available" properties, can
- * claim physical memory.  So, along with initializing the valid
- * address bitmap, what we do here is refetch the physical available
- * memory list again, and make sure it provides at least as much
- * memory as 'pavail' does.
- */
-static void __init setup_valid_addr_bitmap_from_pavail(unsigned long *bitmap)
-{
-       int i;
-
-       read_obp_memory("available", &pavail_rescan[0], &pavail_rescan_ents);
-
-       for (i = 0; i < pavail_ents; i++) {
-               unsigned long old_start, old_end;
-
-               old_start = pavail[i].phys_addr;
-               old_end = old_start + pavail[i].reg_size;
-               while (old_start < old_end) {
-                       int n;
-
-                       for (n = 0; n < pavail_rescan_ents; n++) {
-                               unsigned long new_start, new_end;
-
-                               new_start = pavail_rescan[n].phys_addr;
-                               new_end = new_start +
-                                       pavail_rescan[n].reg_size;
-
-                               if (new_start <= old_start &&
-                                   new_end >= (old_start + PAGE_SIZE)) {
-                                       set_bit(old_start >> ILOG2_4MB, bitmap);
-                                       goto do_next_page;
-                               }
-                       }
-
-                       prom_printf("mem_init: Lost memory in pavail\n");
-                       prom_printf("mem_init: OLD start[%lx] size[%lx]\n",
-                                   pavail[i].phys_addr,
-                                   pavail[i].reg_size);
-                       prom_printf("mem_init: NEW start[%lx] size[%lx]\n",
-                                   pavail_rescan[i].phys_addr,
-                                   pavail_rescan[i].reg_size);
-                       prom_printf("mem_init: Cannot continue, aborting.\n");
-                       prom_halt();
-
-               do_next_page:
-                       old_start += PAGE_SIZE;
-               }
-       }
-}
-
-static void __init patch_tlb_miss_handler_bitmap(void)
-{
-       extern unsigned int valid_addr_bitmap_insn[];
-       extern unsigned int valid_addr_bitmap_patch[];
-
-       valid_addr_bitmap_insn[1] = valid_addr_bitmap_patch[1];
-       mb();
-       valid_addr_bitmap_insn[0] = valid_addr_bitmap_patch[0];
-       flushi(&valid_addr_bitmap_insn[0]);
-}
-
 static void __init register_page_bootmem_info(void)
 {
 #ifdef CONFIG_NEED_MULTIPLE_NODES
@@ -2148,18 +2213,6 @@ static void __init register_page_bootmem_info(void)
 }
 void __init mem_init(void)
 {
-       unsigned long addr, last;
-
-       addr = PAGE_OFFSET + kern_base;
-       last = PAGE_ALIGN(kern_size) + addr;
-       while (addr < last) {
-               set_bit(__pa(addr) >> ILOG2_4MB, sparc64_valid_addr_bitmap);
-               addr += PAGE_SIZE;
-       }
-
-       setup_valid_addr_bitmap_from_pavail(sparc64_valid_addr_bitmap);
-       patch_tlb_miss_handler_bitmap();
-
        high_memory = __va(last_valid_pfn << PAGE_SHIFT);
 
        register_page_bootmem_info();
@@ -2249,18 +2302,9 @@ unsigned long _PAGE_CACHE __read_mostly;
 EXPORT_SYMBOL(_PAGE_CACHE);
 
 #ifdef CONFIG_SPARSEMEM_VMEMMAP
-unsigned long vmemmap_table[VMEMMAP_SIZE];
-
-static long __meminitdata addr_start, addr_end;
-static int __meminitdata node_start;
-
 int __meminit vmemmap_populate(unsigned long vstart, unsigned long vend,
                               int node)
 {
-       unsigned long phys_start = (vstart - VMEMMAP_BASE);
-       unsigned long phys_end = (vend - VMEMMAP_BASE);
-       unsigned long addr = phys_start & VMEMMAP_CHUNK_MASK;
-       unsigned long end = VMEMMAP_ALIGN(phys_end);
        unsigned long pte_base;
 
        pte_base = (_PAGE_VALID | _PAGE_SZ4MB_4U |
@@ -2271,47 +2315,52 @@ int __meminit vmemmap_populate(unsigned long vstart, unsigned long vend,
                            _PAGE_CP_4V | _PAGE_CV_4V |
                            _PAGE_P_4V | _PAGE_W_4V);
 
-       for (; addr < end; addr += VMEMMAP_CHUNK) {
-               unsigned long *vmem_pp =
-                       vmemmap_table + (addr >> VMEMMAP_CHUNK_SHIFT);
-               void *block;
+       pte_base |= _PAGE_PMD_HUGE;
 
-               if (!(*vmem_pp & _PAGE_VALID)) {
-                       block = vmemmap_alloc_block(1UL << ILOG2_4MB, node);
-                       if (!block)
+       vstart = vstart & PMD_MASK;
+       vend = ALIGN(vend, PMD_SIZE);
+       for (; vstart < vend; vstart += PMD_SIZE) {
+               pgd_t *pgd = pgd_offset_k(vstart);
+               unsigned long pte;
+               pud_t *pud;
+               pmd_t *pmd;
+
+               if (pgd_none(*pgd)) {
+                       pud_t *new = vmemmap_alloc_block(PAGE_SIZE, node);
+
+                       if (!new)
                                return -ENOMEM;
+                       pgd_populate(&init_mm, pgd, new);
+               }
 
-                       *vmem_pp = pte_base | __pa(block);
+               pud = pud_offset(pgd, vstart);
+               if (pud_none(*pud)) {
+                       pmd_t *new = vmemmap_alloc_block(PAGE_SIZE, node);
 
-                       /* check to see if we have contiguous blocks */
-                       if (addr_end != addr || node_start != node) {
-                               if (addr_start)
-                                       printk(KERN_DEBUG " [%lx-%lx] on node %d\n",
-                                              addr_start, addr_end-1, node_start);
-                               addr_start = addr;
-                               node_start = node;
-                       }
-                       addr_end = addr + VMEMMAP_CHUNK;
+                       if (!new)
+                               return -ENOMEM;
+                       pud_populate(&init_mm, pud, new);
                }
-       }
-       return 0;
-}
 
-void __meminit vmemmap_populate_print_last(void)
-{
-       if (addr_start) {
-               printk(KERN_DEBUG " [%lx-%lx] on node %d\n",
-                      addr_start, addr_end-1, node_start);
-               addr_start = 0;
-               addr_end = 0;
-               node_start = 0;
+               pmd = pmd_offset(pud, vstart);
+
+               pte = pmd_val(*pmd);
+               if (!(pte & _PAGE_VALID)) {
+                       void *block = vmemmap_alloc_block(PMD_SIZE, node);
+
+                       if (!block)
+                               return -ENOMEM;
+
+                       pmd_val(*pmd) = pte_base | __pa(block);
+               }
        }
+
+       return 0;
 }
 
 void vmemmap_free(unsigned long start, unsigned long end)
 {
 }
-
 #endif /* CONFIG_SPARSEMEM_VMEMMAP */
 
 static void prot_init_common(unsigned long page_none,
@@ -2787,8 +2836,8 @@ void flush_tlb_kernel_range(unsigned long start, unsigned long end)
                        do_flush_tlb_kernel_range(start, LOW_OBP_ADDRESS);
                }
                if (end > HI_OBP_ADDRESS) {
-                       flush_tsb_kernel_range(end, HI_OBP_ADDRESS);
-                       do_flush_tlb_kernel_range(end, HI_OBP_ADDRESS);
+                       flush_tsb_kernel_range(HI_OBP_ADDRESS, end);
+                       do_flush_tlb_kernel_range(HI_OBP_ADDRESS, end);
                }
        } else {
                flush_tsb_kernel_range(start, end);
index 0668b364f44ddb93ccac1849677529b206d5500f..a4c09603b05c09d8f1478d68004398e4ef4dbc1d 100644 (file)
@@ -8,15 +8,8 @@
  */
 
 #define MAX_PHYS_ADDRESS       (1UL << MAX_PHYS_ADDRESS_BITS)
-#define KPTE_BITMAP_CHUNK_SZ           (256UL * 1024UL * 1024UL)
-#define KPTE_BITMAP_BYTES      \
-       ((MAX_PHYS_ADDRESS / KPTE_BITMAP_CHUNK_SZ) / 4)
-#define VALID_ADDR_BITMAP_CHUNK_SZ     (4UL * 1024UL * 1024UL)
-#define VALID_ADDR_BITMAP_BYTES        \
-       ((MAX_PHYS_ADDRESS / VALID_ADDR_BITMAP_CHUNK_SZ) / 8)
 
 extern unsigned long kern_linear_pte_xor[4];
-extern unsigned long kpte_linear_bitmap[KPTE_BITMAP_BYTES / sizeof(unsigned long)];
 extern unsigned int sparc64_highest_unlocked_tlb_ent;
 extern unsigned long sparc64_kern_pri_context;
 extern unsigned long sparc64_kern_pri_nuc_bits;
@@ -38,15 +31,4 @@ extern unsigned long kern_locked_tte_data;
 
 void prom_world(int enter);
 
-#ifdef CONFIG_SPARSEMEM_VMEMMAP
-#define VMEMMAP_CHUNK_SHIFT    22
-#define VMEMMAP_CHUNK          (1UL << VMEMMAP_CHUNK_SHIFT)
-#define VMEMMAP_CHUNK_MASK     ~(VMEMMAP_CHUNK - 1UL)
-#define VMEMMAP_ALIGN(x)       (((x)+VMEMMAP_CHUNK-1UL)&VMEMMAP_CHUNK_MASK)
-
-#define VMEMMAP_SIZE   ((((1UL << MAX_PHYSADDR_BITS) >> PAGE_SHIFT) * \
-                         sizeof(struct page)) >> VMEMMAP_CHUNK_SHIFT)
-extern unsigned long vmemmap_table[VMEMMAP_SIZE];
-#endif
-
 #endif /* _SPARC64_MM_INIT_H */
index 79942166df841eeef137d25f9c8330ff7b27e7ac..d7d9017dcb15b23b8c98b4de8e14f1cc62749e34 100644 (file)
@@ -54,8 +54,8 @@ ENTRY(swsusp_arch_resume)
         nop
 
        /* Write PAGE_OFFSET to %g7 */
-       sethi   %uhi(PAGE_OFFSET), %g7
-       sllx    %g7, 32, %g7
+       sethi   %hi(PAGE_OFFSET), %g7
+       ldx     [%g7 + %lo(PAGE_OFFSET)], %g7
 
        setuw   (PAGE_SIZE-8), %g3
 
index ab9ccc63b3880f5de18eb427869574b872a1ceb2..7149e77714a4a45b3ffb96e1388adca25577cca6 100644 (file)
  *          the .bss section or it will break things.
  */
 
-#define BARG_LEN  256
+/* We limit BARG_LEN to 1024 because this is the size of the
+ * 'barg_out' command line buffer in the SILO bootloader.
+ */
+#define BARG_LEN 1024
 struct {
        int bootstr_len;
        int bootstr_valid;
index e58b817263199f9d45d28aed5f735b38eb94904b..b2340f008ae06a27614f2fc1c78e3b45b36946b0 100644 (file)
@@ -9,6 +9,7 @@
 #include <linux/smp.h>
 #include <linux/string.h>
 #include <linux/spinlock.h>
+#include <linux/irqflags.h>
 
 #include <asm/openprom.h>
 #include <asm/oplib.h>
@@ -36,8 +37,8 @@ void p1275_cmd_direct(unsigned long *args)
 {
        unsigned long flags;
 
-       raw_local_save_flags(flags);
-       raw_local_irq_restore((unsigned long)PIL_NMI);
+       local_save_flags(flags);
+       local_irq_restore((unsigned long)PIL_NMI);
        raw_spin_lock(&prom_entry_lock);
 
        prom_world(1);
@@ -45,7 +46,7 @@ void p1275_cmd_direct(unsigned long *args)
        prom_world(0);
 
        raw_spin_unlock(&prom_entry_lock);
-       raw_local_irq_restore(flags);
+       local_irq_restore(flags);
 }
 
 void prom_cif_init(void *cif_handler, void *cif_stack)
index 6915d28cf118f6c406ff53b20802a36e6ddfcbe0..87bc86821bc9b81380f46ac38557ad537fd0a442 100644 (file)
@@ -39,7 +39,8 @@ config LOCKDEP_SUPPORT
 
 config STACKTRACE_SUPPORT
        bool
-       default n
+       default y
+       select STACKTRACE
 
 config GENERIC_CALIBRATE_DELAY
        bool
index 7d26d9c0b2fb85cd96ca25953f2bb84d4022be9d..f70dd540655de57bdcddf8c0e2ab1fc6e0e611ba 100644 (file)
@@ -659,10 +659,6 @@ static int __init eth_setup(char *str)
        }
 
        new = alloc_bootmem(sizeof(*new));
-       if (new == NULL) {
-               printk(KERN_ERR "eth_init : alloc_bootmem failed\n");
-               return 1;
-       }
 
        INIT_LIST_HEAD(&new->list);
        new->index = n;
index 9e3a722058279ab1a9b0978f03d61589622e2bb1..dd16c902ff701398c14e055bf71aa6e6a612dfff 100644 (file)
@@ -79,7 +79,6 @@ static ssize_t rng_dev_read (struct file *filp, char __user *buf, size_t size,
                        set_task_state(current, TASK_INTERRUPTIBLE);
 
                        schedule();
-                       set_task_state(current, TASK_RUNNING);
                        remove_wait_queue(&host_read_wait, &wait);
 
                        if (atomic_dec_and_test(&host_sleep_count)) {
index 3716e69525546c984f8e730a458c6e22a4cc35af..e8ab93c3e638e160e300f016588184b12cc26bd8 100644 (file)
@@ -1277,7 +1277,7 @@ static void do_ubd_request(struct request_queue *q)
 
        while(1){
                struct ubd *dev = q->queuedata;
-               if(dev->end_sg == 0){
+               if(dev->request == NULL){
                        struct request *req = blk_fetch_request(q);
                        if(req == NULL)
                                return;
@@ -1299,7 +1299,8 @@ static void do_ubd_request(struct request_queue *q)
                                return;
                        }
                        prepare_flush_request(req, io_req);
-                       submit_request(io_req, dev);
+                       if (submit_request(io_req, dev) == false)
+                               return;
                }
 
                while(dev->start_sg < dev->end_sg){
diff --git a/arch/um/include/asm/stacktrace.h b/arch/um/include/asm/stacktrace.h
new file mode 100644 (file)
index 0000000..9a86432
--- /dev/null
@@ -0,0 +1,42 @@
+#ifndef _ASM_UML_STACKTRACE_H
+#define _ASM_UML_STACKTRACE_H
+
+#include <linux/uaccess.h>
+#include <linux/ptrace.h>
+
+struct stack_frame {
+       struct stack_frame *next_frame;
+       unsigned long return_address;
+};
+
+struct stacktrace_ops {
+       void (*address)(void *data, unsigned long address, int reliable);
+};
+
+#ifdef CONFIG_FRAME_POINTER
+static inline unsigned long
+get_frame_pointer(struct task_struct *task, struct pt_regs *segv_regs)
+{
+       if (!task || task == current)
+               return segv_regs ? PT_REGS_BP(segv_regs) : current_bp();
+       return KSTK_EBP(task);
+}
+#else
+static inline unsigned long
+get_frame_pointer(struct task_struct *task, struct pt_regs *segv_regs)
+{
+       return 0;
+}
+#endif
+
+static inline unsigned long
+*get_stack_pointer(struct task_struct *task, struct pt_regs *segv_regs)
+{
+       if (!task || task == current)
+               return segv_regs ? (unsigned long *)PT_REGS_SP(segv_regs) : current_sp();
+       return (unsigned long *)KSTK_ESP(task);
+}
+
+void dump_trace(struct task_struct *tsk, const struct stacktrace_ops *ops, void *data);
+
+#endif /* _ASM_UML_STACKTRACE_H */
index 46384acd547b7590bd75e4f564cf203327e2e522..cb84414e3e6663eb280c555d88ec447c5c6cad27 100644 (file)
@@ -49,7 +49,7 @@ extern int iomem_size;
 extern int init_mem_user(void);
 extern void setup_memory(void *entry);
 extern unsigned long find_iomem(char *driver, unsigned long *len_out);
-extern int init_maps(unsigned long physmem, unsigned long iomem,
+extern void mem_total_pages(unsigned long physmem, unsigned long iomem,
                     unsigned long highmem);
 extern unsigned long get_vm(unsigned long len);
 extern void setup_physmem(unsigned long start, unsigned long usable,
index d8b78a03855c6a1ad4c7ada6c96938f5e62ee02a..2d840a070c8bb56fc2f54d1bba6a25843ad59a6a 100644 (file)
@@ -19,6 +19,7 @@ obj-$(CONFIG_BLK_DEV_INITRD) += initrd.o
 obj-$(CONFIG_GPROF)    += gprof_syms.o
 obj-$(CONFIG_GCOV)     += gmon_syms.o
 obj-$(CONFIG_EARLY_PRINTK) += early_printk.o
+obj-$(CONFIG_STACKTRACE) += stacktrace.o
 
 USER_OBJS := config.o
 
index 30fdd5d0067b26c91fb8c831da5a1d4008c79e22..549ecf3f5857441c95e4344b6aabc99ce4723f7f 100644 (file)
@@ -22,39 +22,19 @@ EXPORT_SYMBOL(high_physmem);
 
 extern unsigned long long physmem_size;
 
-int __init init_maps(unsigned long physmem, unsigned long iomem,
+void __init mem_total_pages(unsigned long physmem, unsigned long iomem,
                     unsigned long highmem)
 {
-       struct page *p, *map;
-       unsigned long phys_len, phys_pages, highmem_len, highmem_pages;
-       unsigned long iomem_len, iomem_pages, total_len, total_pages;
-       int i;
-
-       phys_pages = physmem >> PAGE_SHIFT;
-       phys_len = phys_pages * sizeof(struct page);
-
-       iomem_pages = iomem >> PAGE_SHIFT;
-       iomem_len = iomem_pages * sizeof(struct page);
+       unsigned long phys_pages, highmem_pages;
+       unsigned long iomem_pages, total_pages;
 
+       phys_pages    = physmem >> PAGE_SHIFT;
+       iomem_pages   = iomem   >> PAGE_SHIFT;
        highmem_pages = highmem >> PAGE_SHIFT;
-       highmem_len = highmem_pages * sizeof(struct page);
-
-       total_pages = phys_pages + iomem_pages + highmem_pages;
-       total_len = phys_len + iomem_len + highmem_len;
 
-       map = alloc_bootmem_low_pages(total_len);
-       if (map == NULL)
-               return -ENOMEM;
-
-       for (i = 0; i < total_pages; i++) {
-               p = &map[i];
-               memset(p, 0, sizeof(struct page));
-               SetPageReserved(p);
-               INIT_LIST_HEAD(&p->lru);
-       }
+       total_pages   = phys_pages + iomem_pages + highmem_pages;
 
        max_mapnr = total_pages;
-       return 0;
 }
 
 void map_memory(unsigned long virt, unsigned long phys, unsigned long len,
diff --git a/arch/um/kernel/stacktrace.c b/arch/um/kernel/stacktrace.c
new file mode 100644 (file)
index 0000000..ebe7bcf
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2001 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
+ * Copyright (C) 2013 Richard Weinberger <richard@nod.at>
+ * Copyright (C) 2014 Google Inc., Author: Daniel Walter <dwalter@google.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/kallsyms.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/stacktrace.h>
+#include <linux/module.h>
+#include <linux/uaccess.h>
+#include <asm/stacktrace.h>
+
+void dump_trace(struct task_struct *tsk,
+               const struct stacktrace_ops *ops,
+               void *data)
+{
+       int reliable = 0;
+       unsigned long *sp, bp, addr;
+       struct pt_regs *segv_regs = tsk->thread.segv_regs;
+       struct stack_frame *frame;
+
+       bp = get_frame_pointer(tsk, segv_regs);
+       sp = get_stack_pointer(tsk, segv_regs);
+
+       frame = (struct stack_frame *)bp;
+       while (((long) sp & (THREAD_SIZE-1)) != 0) {
+               addr = *sp;
+               if (__kernel_text_address(addr)) {
+                       reliable = 0;
+                       if ((unsigned long) sp == bp + sizeof(long)) {
+                               frame = frame ? frame->next_frame : NULL;
+                               bp = (unsigned long)frame;
+                               reliable = 1;
+                       }
+                       ops->address(data, addr, reliable);
+               }
+               sp++;
+       }
+}
+
+static void save_addr(void *data, unsigned long address, int reliable)
+{
+       struct stack_trace *trace = data;
+
+       if (!reliable)
+               return;
+       if (trace->nr_entries >= trace->max_entries)
+               return;
+
+       trace->entries[trace->nr_entries++] = address;
+}
+
+static const struct stacktrace_ops dump_ops = {
+       .address = save_addr
+};
+
+static void __save_stack_trace(struct task_struct *tsk, struct stack_trace *trace)
+{
+       dump_trace(tsk, &dump_ops, trace);
+       if (trace->nr_entries < trace->max_entries)
+               trace->entries[trace->nr_entries++] = ULONG_MAX;
+}
+
+void save_stack_trace(struct stack_trace *trace)
+{
+       __save_stack_trace(current, trace);
+}
+EXPORT_SYMBOL_GPL(save_stack_trace);
+
+void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace)
+{
+       __save_stack_trace(tsk, trace);
+}
+EXPORT_SYMBOL_GPL(save_stack_trace_tsk);
index 799d7e413bf57247f258b25ad6306a91b363e67c..894c8d303cda7c753b000bb3edba035974930b84 100644 (file)
 #include <linux/module.h>
 #include <linux/sched.h>
 #include <asm/sysrq.h>
+#include <asm/stacktrace.h>
 #include <os.h>
 
-struct stack_frame {
-       struct stack_frame *next_frame;
-       unsigned long return_address;
-};
-
-static void do_stack_trace(unsigned long *sp, unsigned long bp)
+static void _print_addr(void *data, unsigned long address, int reliable)
 {
-       int reliable;
-       unsigned long addr;
-       struct stack_frame *frame = (struct stack_frame *)bp;
-
-       printk(KERN_INFO "Call Trace:\n");
-       while (((long) sp & (THREAD_SIZE-1)) != 0) {
-               addr = *sp;
-               if (__kernel_text_address(addr)) {
-                       reliable = 0;
-                       if ((unsigned long) sp == bp + sizeof(long)) {
-                               frame = frame ? frame->next_frame : NULL;
-                               bp = (unsigned long)frame;
-                               reliable = 1;
-                       }
-
-                       printk(KERN_INFO " [<%08lx>]", addr);
-                       printk(KERN_CONT " %s", reliable ? "" : "? ");
-                       print_symbol(KERN_CONT "%s", addr);
-                       printk(KERN_CONT "\n");
-               }
-               sp++;
-       }
-       printk(KERN_INFO "\n");
+       pr_info(" [<%08lx>]", address);
+       pr_cont(" %s", reliable ? "" : "? ");
+       print_symbol("%s", address);
+       pr_cont("\n");
 }
 
-static unsigned long get_frame_pointer(struct task_struct *task,
-                                      struct pt_regs *segv_regs)
-{
-       if (!task || task == current)
-               return segv_regs ? PT_REGS_BP(segv_regs) : current_bp();
-       else
-               return KSTK_EBP(task);
-}
-
-static unsigned long *get_stack_pointer(struct task_struct *task,
-                                       struct pt_regs *segv_regs)
-{
-       if (!task || task == current)
-               return segv_regs ? (unsigned long *)PT_REGS_SP(segv_regs) : current_sp();
-       else
-               return (unsigned long *)KSTK_ESP(task);
-}
+static const struct stacktrace_ops stackops = {
+       .address = _print_addr
+};
 
 void show_stack(struct task_struct *task, unsigned long *stack)
 {
@@ -71,7 +34,7 @@ void show_stack(struct task_struct *task, unsigned long *stack)
        int i;
 
        if (!segv_regs && os_is_signal_stack()) {
-               printk(KERN_ERR "Received SIGSEGV in SIGSEGV handler,"
+               pr_err("Received SIGSEGV in SIGSEGV handler,"
                                " aborting stack trace!\n");
                return;
        }
@@ -83,16 +46,18 @@ void show_stack(struct task_struct *task, unsigned long *stack)
        if (!stack)
                sp = get_stack_pointer(task, segv_regs);
 
-       printk(KERN_INFO "Stack:\n");
+       pr_info("Stack:\n");
        stack = sp;
        for (i = 0; i < 3 * STACKSLOTS_PER_LINE; i++) {
                if (kstack_end(stack))
                        break;
                if (i && ((i % STACKSLOTS_PER_LINE) == 0))
-                       printk(KERN_CONT "\n");
-               printk(KERN_CONT " %08lx", *stack++);
+                       pr_cont("\n");
+               pr_cont(" %08lx", *stack++);
        }
-       printk(KERN_CONT "\n");
+       pr_cont("\n");
 
-       do_stack_trace(sp, bp);
+       pr_info("Call Trace:\n");
+       dump_trace(current, &stackops, NULL);
+       pr_info("\n");
 }
index 016adf0985d522ccfb5f22e6d287bb60dfdb4e61..9274eae6ae7b81fb976f059ea9d8afb6b420722a 100644 (file)
@@ -348,12 +348,7 @@ int __init linux_main(int argc, char **argv)
        start_vm = VMALLOC_START;
 
        setup_physmem(uml_physmem, uml_reserved, physmem_size, highmem);
-       if (init_maps(physmem_size, iomem_size, highmem)) {
-               printf("Failed to allocate mem_map for %Lu bytes of physical "
-                      "memory and %Lu bytes of highmem\n", physmem_size,
-                      highmem);
-               exit(1);
-       }
+       mem_total_pages(physmem_size, iomem_size, highmem);
 
        virtmem_size = physmem_size;
        stack = (unsigned long) argv;
index 7cab8c08e6d1d2eee802397c9bc17ea0f7b1bbc1..aff152c87cf4ba62ed26ed6b7eb567b576dd84fd 100644 (file)
@@ -1,4 +1,6 @@
 boot/compressed/vmlinux
 tools/test_get_len
 tools/insn_sanity
+purgatory/kexec-purgatory.c
+purgatory/purgatory.ro
 
index 3eb8a41509b3d8ab531da89df39b20389793b23a..f2327e88e07cc64236636a9f5973af898be947f1 100644 (file)
@@ -491,6 +491,36 @@ config X86_INTEL_LPSS
          things like clock tree (common clock framework) and pincontrol
          which are needed by the LPSS peripheral drivers.
 
+config IOSF_MBI
+       tristate "Intel SoC IOSF Sideband support for SoC platforms"
+       depends on PCI
+       ---help---
+         This option enables sideband register access support for Intel SoC
+         platforms. On these platforms the IOSF sideband is used in lieu of
+         MSR's for some register accesses, mostly but not limited to thermal
+         and power. Drivers may query the availability of this device to
+         determine if they need the sideband in order to work on these
+         platforms. The sideband is available on the following SoC products.
+         This list is not meant to be exclusive.
+          - BayTrail
+          - Braswell
+          - Quark
+
+         You should say Y if you are running a kernel on one of these SoC's.
+
+config IOSF_MBI_DEBUG
+       bool "Enable IOSF sideband access through debugfs"
+       depends on IOSF_MBI && DEBUG_FS
+       ---help---
+         Select this option to expose the IOSF sideband access registers (MCR,
+         MDR, MCRX) through debugfs to write and read register information from
+         different units on the SoC. This is most useful for obtaining device
+         state information for debug and analysis. As this is a general access
+         mechanism, users of this option would have specific knowledge of the
+         device they want to access.
+
+         If you don't require the option or are in doubt, say N.
+
 config X86_RDC321X
        bool "RDC R-321x SoC"
        depends on X86_32
@@ -2454,11 +2484,6 @@ config X86_DMA_REMAP
        bool
        depends on STA2X11
 
-config IOSF_MBI
-       tristate
-       default m
-       depends on PCI
-
 config PMC_ATOM
        def_bool y
         depends on PCI
index 5692d6ac0f1861b9d6cff21b3dde0765381d8f91..920e6160c5353cda685d3e9d0e22ceacbdceded1 100644 (file)
@@ -50,9 +50,6 @@ ifeq ($(CONFIG_X86_32),y)
 
         KBUILD_CFLAGS += -msoft-float -mregparm=3 -freg-struct-return
 
-        # Don't autogenerate MMX or SSE instructions
-        KBUILD_CFLAGS += -mno-mmx -mno-sse
-
         # Never want PIC in a 32-bit kernel, prevent breakage with GCC built
         # with nonstandard options
         KBUILD_CFLAGS += -fno-pic
@@ -80,8 +77,7 @@ else
         KBUILD_AFLAGS += -m64
         KBUILD_CFLAGS += -m64
 
-        # Don't autogenerate traditional x87, MMX or SSE instructions
-        KBUILD_CFLAGS += -mno-mmx -mno-sse
+        # Don't autogenerate traditional x87 instructions
         KBUILD_CFLAGS += $(call cc-option,-mno-80387)
         KBUILD_CFLAGS += $(call cc-option,-mno-fp-ret-in-387)
 
@@ -168,7 +164,7 @@ KBUILD_CFLAGS += -Wno-sign-compare
 #
 KBUILD_CFLAGS += -fno-asynchronous-unwind-tables
 # prevent gcc from generating any FP code by mistake
-KBUILD_CFLAGS += $(call cc-option,-mno-sse -mno-mmx -mno-sse2 -mno-3dnow,)
+KBUILD_CFLAGS += -mno-sse -mno-mmx -mno-sse2 -mno-3dnow
 KBUILD_CFLAGS += $(call cc-option,-mno-avx,)
 
 KBUILD_CFLAGS += $(mflags-y)
index 7c68808edeb7070be08d195fafd35b502fef027f..bb1376381985edb9f96e49c0a1b0269e56bd0f9e 100644 (file)
@@ -194,7 +194,7 @@ static bool mem_avoid_overlap(struct mem_vector *img)
        while (ptr) {
                struct mem_vector avoid;
 
-               avoid.start = (u64)ptr;
+               avoid.start = (unsigned long)ptr;
                avoid.size = sizeof(*ptr) + ptr->len;
 
                if (mem_overlaps(img, &avoid))
index 4579eff0ef4db19fcff2f6336f6f82ab9b5d6998..637097e66a62a675de99040bdcf4f8fc011e2af0 100644 (file)
@@ -16,6 +16,7 @@
 #include <stdio.h>
 
 #include "../include/asm/required-features.h"
+#include "../include/asm/disabled-features.h"
 #include "../include/asm/cpufeature.h"
 #include "../kernel/cpu/capflags.c"
 
index d21ff89207cd655cb58c954e70fb351dd774e15a..df91466f973de7d568fe93b3ba64fb625ffc8e05 100644 (file)
@@ -308,11 +308,8 @@ static int load_aout_binary(struct linux_binprm *bprm)
                (current->mm->start_brk = N_BSSADDR(ex));
 
        retval = setup_arg_pages(bprm, IA32_STACK_TOP, EXSTACK_DEFAULT);
-       if (retval < 0) {
-               /* Someone check-me: is this error path enough? */
-               send_sig(SIGKILL, current, 0);
+       if (retval < 0)
                return retval;
-       }
 
        install_exec_creds(bprm);
 
@@ -324,17 +321,13 @@ static int load_aout_binary(struct linux_binprm *bprm)
 
                error = vm_brk(text_addr & PAGE_MASK, map_size);
 
-               if (error != (text_addr & PAGE_MASK)) {
-                       send_sig(SIGKILL, current, 0);
+               if (error != (text_addr & PAGE_MASK))
                        return error;
-               }
 
                error = read_code(bprm->file, text_addr, 32,
                                  ex.a_text + ex.a_data);
-               if ((signed long)error < 0) {
-                       send_sig(SIGKILL, current, 0);
+               if ((signed long)error < 0)
                        return error;
-               }
        } else {
 #ifdef WARN_OLD
                static unsigned long error_time, error_time2;
@@ -368,20 +361,16 @@ static int load_aout_binary(struct linux_binprm *bprm)
                                MAP_EXECUTABLE | MAP_32BIT,
                                fd_offset);
 
-               if (error != N_TXTADDR(ex)) {
-                       send_sig(SIGKILL, current, 0);
+               if (error != N_TXTADDR(ex))
                        return error;
-               }
 
                error = vm_mmap(bprm->file, N_DATADDR(ex), ex.a_data,
                                PROT_READ | PROT_WRITE | PROT_EXEC,
                                MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE |
                                MAP_EXECUTABLE | MAP_32BIT,
                                fd_offset + ex.a_text);
-               if (error != N_DATADDR(ex)) {
-                       send_sig(SIGKILL, current, 0);
+               if (error != N_DATADDR(ex))
                        return error;
-               }
        }
 beyond_if:
        set_binfmt(&aout_format);
index 4299eb05023cf812ee0f897a1a6189660167dc4e..711de084ab57114dc8410ea3de0fdbe436e0cf93 100644 (file)
@@ -151,6 +151,16 @@ ENTRY(ia32_sysenter_target)
 1:     movl    (%rbp),%ebp
        _ASM_EXTABLE(1b,ia32_badarg)
        ASM_CLAC
+
+       /*
+        * Sysenter doesn't filter flags, so we need to clear NT
+        * ourselves.  To save a few cycles, we can check whether
+        * NT was set instead of doing an unconditional popfq.
+        */
+       testl $X86_EFLAGS_NT,EFLAGS(%rsp)       /* saved EFLAGS match cpu */
+       jnz sysenter_fix_flags
+sysenter_flags_fixed:
+
        orl     $TS_COMPAT,TI_status+THREAD_INFO(%rsp,RIP-ARGOFFSET)
        testl   $_TIF_WORK_SYSCALL_ENTRY,TI_flags+THREAD_INFO(%rsp,RIP-ARGOFFSET)
        CFI_REMEMBER_STATE
@@ -184,6 +194,8 @@ sysexit_from_sys_call:
        TRACE_IRQS_ON
        ENABLE_INTERRUPTS_SYSEXIT32
 
+       CFI_RESTORE_STATE
+
 #ifdef CONFIG_AUDITSYSCALL
        .macro auditsys_entry_common
        movl %esi,%r9d                  /* 6th arg: 4th syscall arg */
@@ -226,7 +238,6 @@ sysexit_from_sys_call:
        .endm
 
 sysenter_auditsys:
-       CFI_RESTORE_STATE
        auditsys_entry_common
        movl %ebp,%r9d                  /* reload 6th syscall arg */
        jmp sysenter_dispatch
@@ -235,6 +246,11 @@ sysexit_audit:
        auditsys_exit sysexit_from_sys_call
 #endif
 
+sysenter_fix_flags:
+       pushq_cfi $(X86_EFLAGS_IF|X86_EFLAGS_FIXED)
+       popfq_cfi
+       jmp sysenter_flags_fixed
+
 sysenter_tracesys:
 #ifdef CONFIG_AUDITSYSCALL
        testl   $(_TIF_WORK_SYSCALL_ENTRY & ~_TIF_SYSCALL_AUDIT),TI_flags+THREAD_INFO(%rsp,RIP-ARGOFFSET)
index 6dd1c7dd0473aecbaa1af28377878a36ac3dfa73..5e5cd123fdfbc2b0fe90cabc5d27948d3ded267a 100644 (file)
@@ -24,7 +24,7 @@
  */
 static inline int atomic_read(const atomic_t *v)
 {
-       return (*(volatile int *)&(v)->counter);
+       return ACCESS_ONCE((v)->counter);
 }
 
 /**
@@ -219,21 +219,6 @@ static inline short int atomic_inc_short(short int *v)
        return *v;
 }
 
-#ifdef CONFIG_X86_64
-/**
- * atomic_or_long - OR of two long integers
- * @v1: pointer to type unsigned long
- * @v2: pointer to type unsigned long
- *
- * Atomically ORs @v1 and @v2
- * Returns the result of the OR
- */
-static inline void atomic_or_long(unsigned long *v1, unsigned long v2)
-{
-       asm(LOCK_PREFIX "orq %1, %0" : "+m" (*v1) : "r" (v2));
-}
-#endif
-
 /* These are x86-specific, used by some header files */
 #define atomic_clear_mask(mask, addr)                          \
        asm volatile(LOCK_PREFIX "andl %0,%1"                   \
index 46e9052bbd28cdea457130607cd5a50ddc5c6204..f8d273e18516dedf885bbafb16224c189913e14f 100644 (file)
@@ -18,7 +18,7 @@
  */
 static inline long atomic64_read(const atomic64_t *v)
 {
-       return (*(volatile long *)&(v)->counter);
+       return ACCESS_ONCE((v)->counter);
 }
 
 /**
index cb4c73bfeb48169056001d1c8426492a3ad4af79..76659b67fd11f6da9f9de43aacc74b3edd20697e 100644 (file)
@@ -85,7 +85,7 @@ For 32-bit we have the following conventions - kernel is built with
 #define ARGOFFSET      R11
 #define SWFRAME                ORIG_RAX
 
-       .macro SAVE_ARGS addskip=0, save_rcx=1, save_r891011=1
+       .macro SAVE_ARGS addskip=0, save_rcx=1, save_r891011=1, rax_enosys=0
        subq  $9*8+\addskip, %rsp
        CFI_ADJUST_CFA_OFFSET   9*8+\addskip
        movq_cfi rdi, 8*8
@@ -96,7 +96,11 @@ For 32-bit we have the following conventions - kernel is built with
        movq_cfi rcx, 5*8
        .endif
 
+       .if \rax_enosys
+       movq $-ENOSYS, 4*8(%rsp)
+       .else
        movq_cfi rax, 4*8
+       .endif
 
        .if \save_r891011
        movq_cfi r8,  3*8
index 094292a63e74b0c5b4378a7d94b2890c811e2da0..0bb1335313b249ca2c3c12d7758275eb7d674c00 100644 (file)
@@ -8,6 +8,10 @@
 #include <asm/required-features.h>
 #endif
 
+#ifndef _ASM_X86_DISABLED_FEATURES_H
+#include <asm/disabled-features.h>
+#endif
+
 #define NCAPINTS       11      /* N 32-bit words worth of info */
 #define NBUGINTS       1       /* N 32-bit bug flags */
 
@@ -282,6 +286,18 @@ extern const char * const x86_bug_flags[NBUGINTS*32];
           (((bit)>>5)==8 && (1UL<<((bit)&31) & REQUIRED_MASK8)) ||     \
           (((bit)>>5)==9 && (1UL<<((bit)&31) & REQUIRED_MASK9)) )
 
+#define DISABLED_MASK_BIT_SET(bit)                                     \
+        ( (((bit)>>5)==0 && (1UL<<((bit)&31) & DISABLED_MASK0)) ||     \
+          (((bit)>>5)==1 && (1UL<<((bit)&31) & DISABLED_MASK1)) ||     \
+          (((bit)>>5)==2 && (1UL<<((bit)&31) & DISABLED_MASK2)) ||     \
+          (((bit)>>5)==3 && (1UL<<((bit)&31) & DISABLED_MASK3)) ||     \
+          (((bit)>>5)==4 && (1UL<<((bit)&31) & DISABLED_MASK4)) ||     \
+          (((bit)>>5)==5 && (1UL<<((bit)&31) & DISABLED_MASK5)) ||     \
+          (((bit)>>5)==6 && (1UL<<((bit)&31) & DISABLED_MASK6)) ||     \
+          (((bit)>>5)==7 && (1UL<<((bit)&31) & DISABLED_MASK7)) ||     \
+          (((bit)>>5)==8 && (1UL<<((bit)&31) & DISABLED_MASK8)) ||     \
+          (((bit)>>5)==9 && (1UL<<((bit)&31) & DISABLED_MASK9)) )
+
 #define cpu_has(c, bit)                                                        \
        (__builtin_constant_p(bit) && REQUIRED_MASK_BIT_SET(bit) ? 1 :  \
         test_cpu_cap(c, bit))
@@ -290,6 +306,18 @@ extern const char * const x86_bug_flags[NBUGINTS*32];
        (__builtin_constant_p(bit) && REQUIRED_MASK_BIT_SET(bit) ? 1 :  \
         x86_this_cpu_test_bit(bit, (unsigned long *)&cpu_info.x86_capability))
 
+/*
+ * This macro is for detection of features which need kernel
+ * infrastructure to be used.  It may *not* directly test the CPU
+ * itself.  Use the cpu_has() family if you want true runtime
+ * testing of CPU features, like in hypervisor code where you are
+ * supporting a possible guest feature where host support for it
+ * is not relevant.
+ */
+#define cpu_feature_enabled(bit)       \
+       (__builtin_constant_p(bit) && DISABLED_MASK_BIT_SET(bit) ? 0 :  \
+        cpu_has(&boot_cpu_data, bit))
+
 #define boot_cpu_has(bit)      cpu_has(&boot_cpu_data, bit)
 
 #define set_cpu_cap(c, bit)    set_bit(bit, (unsigned long *)((c)->x86_capability))
@@ -304,11 +332,9 @@ extern const char * const x86_bug_flags[NBUGINTS*32];
 } while (0)
 
 #define cpu_has_fpu            boot_cpu_has(X86_FEATURE_FPU)
-#define cpu_has_vme            boot_cpu_has(X86_FEATURE_VME)
 #define cpu_has_de             boot_cpu_has(X86_FEATURE_DE)
 #define cpu_has_pse            boot_cpu_has(X86_FEATURE_PSE)
 #define cpu_has_tsc            boot_cpu_has(X86_FEATURE_TSC)
-#define cpu_has_pae            boot_cpu_has(X86_FEATURE_PAE)
 #define cpu_has_pge            boot_cpu_has(X86_FEATURE_PGE)
 #define cpu_has_apic           boot_cpu_has(X86_FEATURE_APIC)
 #define cpu_has_sep            boot_cpu_has(X86_FEATURE_SEP)
@@ -324,9 +350,6 @@ extern const char * const x86_bug_flags[NBUGINTS*32];
 #define cpu_has_avx2           boot_cpu_has(X86_FEATURE_AVX2)
 #define cpu_has_ht             boot_cpu_has(X86_FEATURE_HT)
 #define cpu_has_nx             boot_cpu_has(X86_FEATURE_NX)
-#define cpu_has_k6_mtrr                boot_cpu_has(X86_FEATURE_K6_MTRR)
-#define cpu_has_cyrix_arr      boot_cpu_has(X86_FEATURE_CYRIX_ARR)
-#define cpu_has_centaur_mcr    boot_cpu_has(X86_FEATURE_CENTAUR_MCR)
 #define cpu_has_xstore         boot_cpu_has(X86_FEATURE_XSTORE)
 #define cpu_has_xstore_enabled boot_cpu_has(X86_FEATURE_XSTORE_EN)
 #define cpu_has_xcrypt         boot_cpu_has(X86_FEATURE_XCRYPT)
@@ -361,25 +384,6 @@ extern const char * const x86_bug_flags[NBUGINTS*32];
 #define cpu_has_eager_fpu      boot_cpu_has(X86_FEATURE_EAGER_FPU)
 #define cpu_has_topoext                boot_cpu_has(X86_FEATURE_TOPOEXT)
 
-#ifdef CONFIG_X86_64
-
-#undef  cpu_has_vme
-#define cpu_has_vme            0
-
-#undef  cpu_has_pae
-#define cpu_has_pae            ___BUG___
-
-#undef  cpu_has_k6_mtrr
-#define cpu_has_k6_mtrr                0
-
-#undef  cpu_has_cyrix_arr
-#define cpu_has_cyrix_arr      0
-
-#undef  cpu_has_centaur_mcr
-#define cpu_has_centaur_mcr    0
-
-#endif /* CONFIG_X86_64 */
-
 #if __GNUC__ >= 4
 extern void warn_pre_alternatives(void);
 extern bool __static_cpu_has_safe(u16 bit);
diff --git a/arch/x86/include/asm/disabled-features.h b/arch/x86/include/asm/disabled-features.h
new file mode 100644 (file)
index 0000000..97534a7
--- /dev/null
@@ -0,0 +1,39 @@
+#ifndef _ASM_X86_DISABLED_FEATURES_H
+#define _ASM_X86_DISABLED_FEATURES_H
+
+/* These features, although they might be available in a CPU
+ * will not be used because the compile options to support
+ * them are not present.
+ *
+ * This code allows them to be checked and disabled at
+ * compile time without an explicit #ifdef.  Use
+ * cpu_feature_enabled().
+ */
+
+#ifdef CONFIG_X86_64
+# define DISABLE_VME           (1<<(X86_FEATURE_VME & 31))
+# define DISABLE_K6_MTRR       (1<<(X86_FEATURE_K6_MTRR & 31))
+# define DISABLE_CYRIX_ARR     (1<<(X86_FEATURE_CYRIX_ARR & 31))
+# define DISABLE_CENTAUR_MCR   (1<<(X86_FEATURE_CENTAUR_MCR & 31))
+#else
+# define DISABLE_VME           0
+# define DISABLE_K6_MTRR       0
+# define DISABLE_CYRIX_ARR     0
+# define DISABLE_CENTAUR_MCR   0
+#endif /* CONFIG_X86_64 */
+
+/*
+ * Make sure to add features to the correct mask
+ */
+#define DISABLED_MASK0 (DISABLE_VME)
+#define DISABLED_MASK1 0
+#define DISABLED_MASK2 0
+#define DISABLED_MASK3 (DISABLE_CYRIX_ARR|DISABLE_CENTAUR_MCR|DISABLE_K6_MTRR)
+#define DISABLED_MASK4 0
+#define DISABLED_MASK5 0
+#define DISABLED_MASK6 0
+#define DISABLED_MASK7 0
+#define DISABLED_MASK8 0
+#define DISABLED_MASK9 0
+
+#endif /* _ASM_X86_DISABLED_FEATURES_H */
index 1a055c81d864d0027499f56d03cf210571e3bacf..ca3347a9dab5211399e9e93a5e53d71ca1943095 100644 (file)
@@ -160,8 +160,9 @@ do {                                                \
 #define elf_check_arch(x)                      \
        ((x)->e_machine == EM_X86_64)
 
-#define compat_elf_check_arch(x)               \
-       (elf_check_arch_ia32(x) || (x)->e_machine == EM_X86_64)
+#define compat_elf_check_arch(x)                                       \
+       (elf_check_arch_ia32(x) ||                                      \
+        (IS_ENABLED(CONFIG_X86_X32_ABI) && (x)->e_machine == EM_X86_64))
 
 #if __USER32_DS != __USER_DS
 # error "The following code assumes __USER32_DS == __USER_DS"
index 412ececa00b957014a535e0a36d15ae108a88ffa..e97622f577229e431cd2f49c7b3aa30bb9f31ce8 100644 (file)
@@ -344,7 +344,7 @@ static inline void __thread_fpu_end(struct task_struct *tsk)
 
 static inline void __thread_fpu_begin(struct task_struct *tsk)
 {
-       if (!static_cpu_has_safe(X86_FEATURE_EAGER_FPU))
+       if (!use_eager_fpu())
                clts();
        __thread_set_has_fpu(tsk);
 }
index 9067166409bfe32b07358b74596032194628ef14..bbe296e0bce1995ca8f9324b801ef09714e6399c 100644 (file)
@@ -43,7 +43,7 @@ struct extended_sigtable {
 #define DWSIZE                 (sizeof(u32))
 
 #define get_totalsize(mc) \
-       (((struct microcode_intel *)mc)->hdr.totalsize ? \
+       (((struct microcode_intel *)mc)->hdr.datasize ? \
         ((struct microcode_intel *)mc)->hdr.totalsize : \
         DEFAULT_UCODE_TOTALSIZE)
 
index 4064acae625d95ebc904dbaa3d3ad10add9c4443..01b493e5a99b3bf296ccb44aeca865e77982254f 100644 (file)
@@ -9,7 +9,6 @@
 #ifdef CONFIG_NUMA
 
 #define NR_NODE_MEMBLKS                (MAX_NUMNODES*2)
-#define ZONE_ALIGN (1UL << (MAX_ORDER+PAGE_SHIFT))
 
 /*
  * Too small node sizes may confuse the VM badly. Usually they
index 8249df45d2f2b52dcecd46411db73408bf1ab392..8dfc9fd094a3b3fea4912da838d2114766017295 100644 (file)
         ARCH_PERFMON_EVENTSEL_EDGE  |  \
         ARCH_PERFMON_EVENTSEL_INV   |  \
         ARCH_PERFMON_EVENTSEL_CMASK)
+#define X86_ALL_EVENT_FLAGS                    \
+       (ARCH_PERFMON_EVENTSEL_EDGE |           \
+        ARCH_PERFMON_EVENTSEL_INV |            \
+        ARCH_PERFMON_EVENTSEL_CMASK |          \
+        ARCH_PERFMON_EVENTSEL_ANY |            \
+        ARCH_PERFMON_EVENTSEL_PIN_CONTROL |    \
+        HSW_IN_TX |                            \
+        HSW_IN_TX_CHECKPOINTED)
 #define AMD64_RAW_EVENT_MASK           \
        (X86_RAW_EVENT_MASK          |  \
         AMD64_EVENTSEL_EVENT)
index 9ee322103c6da79835fbae00772e9d6a7d60135c..b6c0b404898a71330d8c1cd923bd268dd2a64adc 100644 (file)
@@ -32,9 +32,6 @@ static inline void pgtable_cache_init(void) { }
 static inline void check_pgt_cache(void) { }
 void paging_init(void);
 
-extern void set_pmd_pfn(unsigned long, unsigned long, pgprot_t);
-
-
 /*
  * Define this if things work differently on an i386 and an i486:
  * it will (on an i486) warn about kernel memory accesses that are
index 3874693c0e53adc3593a21374154e99941944703..4572b2f302379ea04da04d99ab5933b49b6ae063 100644 (file)
@@ -116,7 +116,8 @@ static inline void native_pgd_clear(pgd_t *pgd)
        native_set_pgd(pgd, native_make_pgd(0));
 }
 
-extern void sync_global_pgds(unsigned long start, unsigned long end);
+extern void sync_global_pgds(unsigned long start, unsigned long end,
+                            int removed);
 
 /*
  * Conversion functions: convert a page and protection to a page entry,
index 0f9724c9c510125e78ebdaae845fcd0805f52bb9..07789647bf333458840685a5d35e91d49ed2e299 100644 (file)
@@ -23,7 +23,6 @@
 #define _PAGE_BIT_SPECIAL      _PAGE_BIT_SOFTW1
 #define _PAGE_BIT_CPA_TEST     _PAGE_BIT_SOFTW1
 #define _PAGE_BIT_SPLITTING    _PAGE_BIT_SOFTW2 /* only valid on a PSE pmd */
-#define _PAGE_BIT_IOMAP                _PAGE_BIT_SOFTW2 /* flag used to indicate IO mapping */
 #define _PAGE_BIT_HIDDEN       _PAGE_BIT_SOFTW3 /* hidden by kmemcheck */
 #define _PAGE_BIT_SOFT_DIRTY   _PAGE_BIT_SOFTW3 /* software dirty tracking */
 #define _PAGE_BIT_NX           63       /* No execute: only valid after cpuid check */
@@ -52,7 +51,7 @@
 #define _PAGE_PSE      (_AT(pteval_t, 1) << _PAGE_BIT_PSE)
 #define _PAGE_GLOBAL   (_AT(pteval_t, 1) << _PAGE_BIT_GLOBAL)
 #define _PAGE_SOFTW1   (_AT(pteval_t, 1) << _PAGE_BIT_SOFTW1)
-#define _PAGE_IOMAP    (_AT(pteval_t, 1) << _PAGE_BIT_IOMAP)
+#define _PAGE_SOFTW2   (_AT(pteval_t, 1) << _PAGE_BIT_SOFTW2)
 #define _PAGE_PAT      (_AT(pteval_t, 1) << _PAGE_BIT_PAT)
 #define _PAGE_PAT_LARGE (_AT(pteval_t, 1) << _PAGE_BIT_PAT_LARGE)
 #define _PAGE_SPECIAL  (_AT(pteval_t, 1) << _PAGE_BIT_SPECIAL)
 #define __PAGE_KERNEL_LARGE_NOCACHE    (__PAGE_KERNEL | _PAGE_CACHE_UC | _PAGE_PSE)
 #define __PAGE_KERNEL_LARGE_EXEC       (__PAGE_KERNEL_EXEC | _PAGE_PSE)
 
-#define __PAGE_KERNEL_IO               (__PAGE_KERNEL | _PAGE_IOMAP)
-#define __PAGE_KERNEL_IO_NOCACHE       (__PAGE_KERNEL_NOCACHE | _PAGE_IOMAP)
-#define __PAGE_KERNEL_IO_UC_MINUS      (__PAGE_KERNEL_UC_MINUS | _PAGE_IOMAP)
-#define __PAGE_KERNEL_IO_WC            (__PAGE_KERNEL_WC | _PAGE_IOMAP)
+#define __PAGE_KERNEL_IO               (__PAGE_KERNEL)
+#define __PAGE_KERNEL_IO_NOCACHE       (__PAGE_KERNEL_NOCACHE)
+#define __PAGE_KERNEL_IO_UC_MINUS      (__PAGE_KERNEL_UC_MINUS)
+#define __PAGE_KERNEL_IO_WC            (__PAGE_KERNEL_WC)
 
 #define PAGE_KERNEL                    __pgprot(__PAGE_KERNEL)
 #define PAGE_KERNEL_RO                 __pgprot(__PAGE_KERNEL_RO)
index 6205f0c434dbabcb72f7135821c614420904c1da..86fc2bb82287a687bd8ca0e976e8d32761678480 100644 (file)
@@ -75,6 +75,11 @@ convert_ip_to_linear(struct task_struct *child, struct pt_regs *regs);
 extern void send_sigtrap(struct task_struct *tsk, struct pt_regs *regs,
                         int error_code, int si_code);
 
+
+extern unsigned long syscall_trace_enter_phase1(struct pt_regs *, u32 arch);
+extern long syscall_trace_enter_phase2(struct pt_regs *, u32 arch,
+                                      unsigned long phase1_result);
+
 extern long syscall_trace_enter(struct pt_regs *);
 extern void syscall_trace_leave(struct pt_regs *);
 
diff --git a/arch/x86/include/asm/rwlock.h b/arch/x86/include/asm/rwlock.h
deleted file mode 100644 (file)
index a5370a0..0000000
+++ /dev/null
@@ -1,49 +0,0 @@
-#ifndef _ASM_X86_RWLOCK_H
-#define _ASM_X86_RWLOCK_H
-
-#include <asm/asm.h>
-
-#if CONFIG_NR_CPUS <= 2048
-
-#ifndef __ASSEMBLY__
-typedef union {
-       s32 lock;
-       s32 write;
-} arch_rwlock_t;
-#endif
-
-#define RW_LOCK_BIAS           0x00100000
-#define READ_LOCK_SIZE(insn)   __ASM_FORM(insn##l)
-#define READ_LOCK_ATOMIC(n)    atomic_##n
-#define WRITE_LOCK_ADD(n)      __ASM_FORM_COMMA(addl n)
-#define WRITE_LOCK_SUB(n)      __ASM_FORM_COMMA(subl n)
-#define WRITE_LOCK_CMP         RW_LOCK_BIAS
-
-#else /* CONFIG_NR_CPUS > 2048 */
-
-#include <linux/const.h>
-
-#ifndef __ASSEMBLY__
-typedef union {
-       s64 lock;
-       struct {
-               u32 read;
-               s32 write;
-       };
-} arch_rwlock_t;
-#endif
-
-#define RW_LOCK_BIAS           (_AC(1,L) << 32)
-#define READ_LOCK_SIZE(insn)   __ASM_FORM(insn##q)
-#define READ_LOCK_ATOMIC(n)    atomic64_##n
-#define WRITE_LOCK_ADD(n)      __ASM_FORM(incl)
-#define WRITE_LOCK_SUB(n)      __ASM_FORM(decl)
-#define WRITE_LOCK_CMP         1
-
-#endif /* CONFIG_NR_CPUS */
-
-#define __ARCH_RW_LOCK_UNLOCKED                { RW_LOCK_BIAS }
-
-/* Actual code is in asm/spinlock.h or in arch/x86/lib/rwlock.S */
-
-#endif /* _ASM_X86_RWLOCK_H */
index 628c801535ea912c00a57654310a832acca2e67f..460b84f64556dded375c779a59d2c6a521c575c7 100644 (file)
@@ -6,24 +6,24 @@
  *
  * It'd be nice if someone built a serial card with a 24.576 MHz
  * clock, since the 16550A is capable of handling a top speed of 1.5
- * megabits/second; but this requires the faster clock.
+ * megabits/second; but this requires a faster clock.
  */
-#define BASE_BAUD ( 1843200 / 16 )
+#define BASE_BAUD (1843200/16)
 
 /* Standard COM flags (except for COM4, because of the 8514 problem) */
 #ifdef CONFIG_SERIAL_DETECT_IRQ
-#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST | ASYNC_AUTO_IRQ)
-#define STD_COM4_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_AUTO_IRQ)
+# define STD_COMX_FLAGS        (ASYNC_BOOT_AUTOCONF |  ASYNC_SKIP_TEST | ASYNC_AUTO_IRQ)
+# define STD_COM4_FLAGS        (ASYNC_BOOT_AUTOCONF |  0               | ASYNC_AUTO_IRQ)
 #else
-#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST)
-#define STD_COM4_FLAGS ASYNC_BOOT_AUTOCONF
+# define STD_COMX_FLAGS        (ASYNC_BOOT_AUTOCONF |  ASYNC_SKIP_TEST | 0             )
+# define STD_COM4_FLAGS        (ASYNC_BOOT_AUTOCONF |  0               | 0             )
 #endif
 
-#define SERIAL_PORT_DFNS                       \
-       /* UART CLK   PORT IRQ     FLAGS        */                      \
-       { 0, BASE_BAUD, 0x3F8, 4, STD_COM_FLAGS },      /* ttyS0 */     \
-       { 0, BASE_BAUD, 0x2F8, 3, STD_COM_FLAGS },      /* ttyS1 */     \
-       { 0, BASE_BAUD, 0x3E8, 4, STD_COM_FLAGS },      /* ttyS2 */     \
-       { 0, BASE_BAUD, 0x2E8, 3, STD_COM4_FLAGS },     /* ttyS3 */
+#define SERIAL_PORT_DFNS                                                               \
+       /* UART         CLK             PORT    IRQ     FLAGS                       */  \
+       { .uart = 0,    BASE_BAUD,      0x3F8,  4,      STD_COMX_FLAGS  }, /* ttyS0 */  \
+       { .uart = 0,    BASE_BAUD,      0x2F8,  3,      STD_COMX_FLAGS  }, /* ttyS1 */  \
+       { .uart = 0,    BASE_BAUD,      0x3E8,  4,      STD_COMX_FLAGS  }, /* ttyS2 */  \
+       { .uart = 0,    BASE_BAUD,      0x2E8,  3,      STD_COM4_FLAGS  }, /* ttyS3 */
 
 #endif /* _ASM_X86_SERIAL_H */
index 54f1c8068c02340a4600049f843fd9f3067b51c5..9295016485c9039e96cb982da754aee40162ce96 100644 (file)
@@ -187,7 +187,6 @@ static inline void arch_spin_unlock_wait(arch_spinlock_t *lock)
                cpu_relax();
 }
 
-#ifndef CONFIG_QUEUE_RWLOCK
 /*
  * Read-write spinlocks, allowing multiple readers
  * but only one writer.
@@ -198,91 +197,15 @@ static inline void arch_spin_unlock_wait(arch_spinlock_t *lock)
  * irq-safe write-lock, but readers can get non-irqsafe
  * read-locks.
  *
- * On x86, we implement read-write locks as a 32-bit counter
- * with the high bit (sign) being the "contended" bit.
+ * On x86, we implement read-write locks using the generic qrwlock with
+ * x86 specific optimization.
  */
 
-/**
- * read_can_lock - would read_trylock() succeed?
- * @lock: the rwlock in question.
- */
-static inline int arch_read_can_lock(arch_rwlock_t *lock)
-{
-       return lock->lock > 0;
-}
-
-/**
- * write_can_lock - would write_trylock() succeed?
- * @lock: the rwlock in question.
- */
-static inline int arch_write_can_lock(arch_rwlock_t *lock)
-{
-       return lock->write == WRITE_LOCK_CMP;
-}
-
-static inline void arch_read_lock(arch_rwlock_t *rw)
-{
-       asm volatile(LOCK_PREFIX READ_LOCK_SIZE(dec) " (%0)\n\t"
-                    "jns 1f\n"
-                    "call __read_lock_failed\n\t"
-                    "1:\n"
-                    ::LOCK_PTR_REG (rw) : "memory");
-}
-
-static inline void arch_write_lock(arch_rwlock_t *rw)
-{
-       asm volatile(LOCK_PREFIX WRITE_LOCK_SUB(%1) "(%0)\n\t"
-                    "jz 1f\n"
-                    "call __write_lock_failed\n\t"
-                    "1:\n"
-                    ::LOCK_PTR_REG (&rw->write), "i" (RW_LOCK_BIAS)
-                    : "memory");
-}
-
-static inline int arch_read_trylock(arch_rwlock_t *lock)
-{
-       READ_LOCK_ATOMIC(t) *count = (READ_LOCK_ATOMIC(t) *)lock;
-
-       if (READ_LOCK_ATOMIC(dec_return)(count) >= 0)
-               return 1;
-       READ_LOCK_ATOMIC(inc)(count);
-       return 0;
-}
-
-static inline int arch_write_trylock(arch_rwlock_t *lock)
-{
-       atomic_t *count = (atomic_t *)&lock->write;
-
-       if (atomic_sub_and_test(WRITE_LOCK_CMP, count))
-               return 1;
-       atomic_add(WRITE_LOCK_CMP, count);
-       return 0;
-}
-
-static inline void arch_read_unlock(arch_rwlock_t *rw)
-{
-       asm volatile(LOCK_PREFIX READ_LOCK_SIZE(inc) " %0"
-                    :"+m" (rw->lock) : : "memory");
-}
-
-static inline void arch_write_unlock(arch_rwlock_t *rw)
-{
-       asm volatile(LOCK_PREFIX WRITE_LOCK_ADD(%1) "%0"
-                    : "+m" (rw->write) : "i" (RW_LOCK_BIAS) : "memory");
-}
-#else
 #include <asm/qrwlock.h>
-#endif /* CONFIG_QUEUE_RWLOCK */
 
 #define arch_read_lock_flags(lock, flags) arch_read_lock(lock)
 #define arch_write_lock_flags(lock, flags) arch_write_lock(lock)
 
-#undef READ_LOCK_SIZE
-#undef READ_LOCK_ATOMIC
-#undef WRITE_LOCK_ADD
-#undef WRITE_LOCK_SUB
-#undef WRITE_LOCK_CMP
-
 #define arch_spin_relax(lock)  cpu_relax()
 #define arch_read_relax(lock)  cpu_relax()
 #define arch_write_relax(lock) cpu_relax()
index 73c4c007200f066173f3f5628cefd62ccefa7d1e..5f9d7572d82b190a2b2d2219bb205a1e543d5acd 100644 (file)
@@ -34,10 +34,6 @@ typedef struct arch_spinlock {
 
 #define __ARCH_SPIN_LOCK_UNLOCKED      { { 0 } }
 
-#ifdef CONFIG_QUEUE_RWLOCK
 #include <asm-generic/qrwlock_types.h>
-#else
-#include <asm/rwlock.h>
-#endif
 
 #endif /* _ASM_X86_SPINLOCK_TYPES_H */
index bbae0247070143c7ff8b5d97969ef0c13a684238..d993e33f523654cf5a985481d62e60810830f66b 100644 (file)
  * this size.
  */
 
-/*
- * Odd: 'make headers_check' complains about numa.h if I try
- * to collapse the next two #ifdef lines to a single line:
- *     #if defined(__KERNEL__) && defined(CONFIG_EFI)
- */
 #ifndef __KERNEL__
 #define E820_X_MAX E820MAX
 #endif
index ada2e2d6be3e01335734016a2aae5dc677ab69af..8f1e77440b2bd65049b20a7a446213558b644f15 100644 (file)
@@ -39,8 +39,6 @@ obj-y                 += tsc.o tsc_msr.o io_delay.o rtc.o
 obj-y                  += pci-iommu_table.o
 obj-y                  += resource.o
 
-obj-$(CONFIG_PREEMPT)  += preempt.o
-
 obj-y                          += process.o
 obj-y                          += i387.o xsave.o
 obj-y                          += ptrace.o
index ae915391ebecdbe9d01abb63e5ab787f3c484381..4128b5fcb559ff5a1041ffafe79c99413ab21d7c 100644 (file)
@@ -32,7 +32,7 @@
 
 static int numachip_system __read_mostly;
 
-static const struct apic apic_numachip __read_mostly;
+static const struct apic apic_numachip;
 
 static unsigned int get_apic_id(unsigned long x)
 {
index 004f017aa7b9e633923aa6d861bb964f7abbe658..8e9dcfd630e4b539e7936050b7bb1673660ae752 100644 (file)
@@ -204,7 +204,6 @@ EXPORT_SYMBOL(sn_rtc_cycles_per_second);
 
 static int uv_wakeup_secondary(int phys_apicid, unsigned long start_rip)
 {
-#ifdef CONFIG_SMP
        unsigned long val;
        int pnode;
 
@@ -223,7 +222,6 @@ static int uv_wakeup_secondary(int phys_apicid, unsigned long start_rip)
        uv_write_global_mmr64(pnode, UVH_IPI_INT, val);
 
        atomic_set(&init_deasserted, 1);
-#endif
        return 0;
 }
 
index 77dcab277710763cc0e6cc7ceb9a3fb8ef0b8c57..01d5453b5502c235759712b751da809123b565cc 100644 (file)
@@ -39,7 +39,9 @@ obj-$(CONFIG_CPU_SUP_AMD)             += perf_event_amd_iommu.o
 endif
 obj-$(CONFIG_CPU_SUP_INTEL)            += perf_event_p6.o perf_event_knc.o perf_event_p4.o
 obj-$(CONFIG_CPU_SUP_INTEL)            += perf_event_intel_lbr.o perf_event_intel_ds.o perf_event_intel.o
-obj-$(CONFIG_CPU_SUP_INTEL)            += perf_event_intel_uncore.o perf_event_intel_rapl.o
+obj-$(CONFIG_CPU_SUP_INTEL)            += perf_event_intel_uncore.o perf_event_intel_uncore_snb.o
+obj-$(CONFIG_CPU_SUP_INTEL)            += perf_event_intel_uncore_snbep.o perf_event_intel_uncore_nhmex.o
+obj-$(CONFIG_CPU_SUP_INTEL)            += perf_event_intel_rapl.o
 endif
 
 
index c649f236e288849f94f8b2bf4501117cd2f1a698..3eff36f719fb62dbb78ef64f37421b73a90c95ac 100644 (file)
@@ -964,6 +964,7 @@ static void vgetcpu_set_mode(void)
                vgetcpu_mode = VGETCPU_LSL;
 }
 
+#ifdef CONFIG_IA32_EMULATION
 /* May not be __init: called during resume */
 static void syscall32_cpu_init(void)
 {
@@ -975,7 +976,8 @@ static void syscall32_cpu_init(void)
 
        wrmsrl(MSR_CSTAR, ia32_cstar_target);
 }
-#endif
+#endif         /* CONFIG_IA32_EMULATION */
+#endif         /* CONFIG_X86_64 */
 
 #ifdef CONFIG_X86_32
 void enable_sep_cpu(void)
@@ -1184,7 +1186,7 @@ void syscall_init(void)
        /* Flags to clear on syscall */
        wrmsrl(MSR_SYSCALL_MASK,
               X86_EFLAGS_TF|X86_EFLAGS_DF|X86_EFLAGS_IF|
-              X86_EFLAGS_IOPL|X86_EFLAGS_AC);
+              X86_EFLAGS_IOPL|X86_EFLAGS_AC|X86_EFLAGS_NT);
 }
 
 /*
@@ -1266,6 +1268,19 @@ static void dbg_restore_debug_regs(void)
 #define dbg_restore_debug_regs()
 #endif /* ! CONFIG_KGDB */
 
+static void wait_for_master_cpu(int cpu)
+{
+#ifdef CONFIG_SMP
+       /*
+        * wait for ACK from master CPU before continuing
+        * with AP initialization
+        */
+       WARN_ON(cpumask_test_and_set_cpu(cpu, cpu_initialized_mask));
+       while (!cpumask_test_cpu(cpu, cpu_callout_mask))
+               cpu_relax();
+#endif
+}
+
 /*
  * cpu_init() initializes state that is per-CPU. Some data is already
  * initialized (naturally) in the bootstrap process, such as the GDT
@@ -1281,16 +1296,17 @@ void cpu_init(void)
        struct task_struct *me;
        struct tss_struct *t;
        unsigned long v;
-       int cpu;
+       int cpu = stack_smp_processor_id();
        int i;
 
+       wait_for_master_cpu(cpu);
+
        /*
         * Load microcode on this cpu if a valid microcode is available.
         * This is early microcode loading procedure.
         */
        load_ucode_ap();
 
-       cpu = stack_smp_processor_id();
        t = &per_cpu(init_tss, cpu);
        oist = &per_cpu(orig_ist, cpu);
 
@@ -1302,9 +1318,6 @@ void cpu_init(void)
 
        me = current;
 
-       if (cpumask_test_and_set_cpu(cpu, cpu_initialized_mask))
-               panic("CPU#%d already initialized!\n", cpu);
-
        pr_debug("Initializing CPU#%d\n", cpu);
 
        clear_in_cr4(X86_CR4_VME|X86_CR4_PVI|X86_CR4_TSD|X86_CR4_DE);
@@ -1381,17 +1394,13 @@ void cpu_init(void)
        struct tss_struct *t = &per_cpu(init_tss, cpu);
        struct thread_struct *thread = &curr->thread;
 
-       show_ucode_info_early();
+       wait_for_master_cpu(cpu);
 
-       if (cpumask_test_and_set_cpu(cpu, cpu_initialized_mask)) {
-               printk(KERN_WARNING "CPU#%d already initialized!\n", cpu);
-               for (;;)
-                       local_irq_enable();
-       }
+       show_ucode_info_early();
 
        printk(KERN_INFO "Initializing CPU#%d\n", cpu);
 
-       if (cpu_has_vme || cpu_has_tsc || cpu_has_de)
+       if (cpu_feature_enabled(X86_FEATURE_VME) || cpu_has_tsc || cpu_has_de)
                clear_in_cr4(X86_CR4_VME|X86_CR4_PVI|X86_CR4_TSD|X86_CR4_DE);
 
        load_current_idt();
index 74e804ddc5c7567ec8b875fbca0e6f69d5922763..1ef456273172c8875e5673d890916dd70033e8e4 100644 (file)
@@ -144,6 +144,21 @@ static void early_init_intel(struct cpuinfo_x86 *c)
                        setup_clear_cpu_cap(X86_FEATURE_ERMS);
                }
        }
+
+       /*
+        * Intel Quark Core DevMan_001.pdf section 6.4.11
+        * "The operating system also is required to invalidate (i.e., flush)
+        *  the TLB when any changes are made to any of the page table entries.
+        *  The operating system must reload CR3 to cause the TLB to be flushed"
+        *
+        * As a result cpu_has_pge() in arch/x86/include/asm/tlbflush.h should
+        * be false so that __flush_tlb_all() causes CR3 insted of CR4.PGE
+        * to be modified
+        */
+       if (c->x86 == 5 && c->x86_model == 9) {
+               pr_info("Disabling PGE capability bit\n");
+               setup_clear_cpu_cap(X86_FEATURE_PGE);
+       }
 }
 
 #ifdef CONFIG_X86_32
@@ -382,6 +397,13 @@ static void init_intel(struct cpuinfo_x86 *c)
        }
 
        l2 = init_intel_cacheinfo(c);
+
+       /* Detect legacy cache sizes if init_intel_cacheinfo did not */
+       if (l2 == 0) {
+               cpu_detect_cache_sizes(c);
+               l2 = c->x86_cache_size;
+       }
+
        if (c->cpuid_level > 9) {
                unsigned eax = cpuid_eax(10);
                /* Check for version and the number of counters */
@@ -485,6 +507,13 @@ static unsigned int intel_size_cache(struct cpuinfo_x86 *c, unsigned int size)
         */
        if ((c->x86 == 6) && (c->x86_model == 11) && (size == 0))
                size = 256;
+
+       /*
+        * Intel Quark SoC X1000 contains a 4-way set associative
+        * 16K cache with a 16 byte cache line and 256 lines per tag
+        */
+       if ((c->x86 == 5) && (c->x86_model == 9))
+               size = 16;
        return size;
 }
 #endif
@@ -686,7 +715,8 @@ static const struct cpu_dev intel_cpu_dev = {
                          [3] = "OverDrive PODP5V83",
                          [4] = "Pentium MMX",
                          [7] = "Mobile Pentium 75 - 200",
-                         [8] = "Mobile Pentium MMX"
+                         [8] = "Mobile Pentium MMX",
+                         [9] = "Quark SoC X1000",
                  }
                },
                { .family = 6, .model_names =
index 36a1bb6d1ee0d431752a170714aa6a43576ffada..1af51b1586d7f7ae0bfa65ec377634b2d8fa39c2 100644 (file)
@@ -498,8 +498,8 @@ void intel_init_thermal(struct cpuinfo_x86 *c)
 
 
        if ((l & MSR_IA32_MISC_ENABLE_TM1) && (h & APIC_DM_SMI)) {
-               printk(KERN_DEBUG
-                      "CPU%d: Thermal monitoring handled by SMI\n", cpu);
+               if (system_state == SYSTEM_BOOTING)
+                       printk(KERN_DEBUG "CPU%d: Thermal monitoring handled by SMI\n", cpu);
                return;
        }
 
index 617a9e28424560d28e7594e2c8213985aaef3de2..7aa1acc79789aa9c38de7509dcb018132a50d901 100644 (file)
@@ -27,7 +27,7 @@ static u32 ucode_new_rev;
 u8 amd_ucode_patch[PATCH_MAX_SIZE];
 static u16 this_equiv_id;
 
-struct cpio_data ucode_cpio;
+static struct cpio_data ucode_cpio;
 
 /*
  * Microcode patch container file is prepended to the initrd in cpio format.
index a276fa75d9b5d997bf3d202f0579279f11d5b82a..c6826d1e8082584268d1b5e8f3abeb176ee61187 100644 (file)
@@ -127,7 +127,7 @@ static int get_matching_mc(struct microcode_intel *mc_intel, int cpu)
        return get_matching_microcode(csig, cpf, mc_intel, crev);
 }
 
-int apply_microcode(int cpu)
+static int apply_microcode_intel(int cpu)
 {
        struct microcode_intel *mc_intel;
        struct ucode_cpu_info *uci;
@@ -314,7 +314,7 @@ static struct microcode_ops microcode_intel_ops = {
        .request_microcode_user           = request_microcode_user,
        .request_microcode_fw             = request_microcode_fw,
        .collect_cpu_info                 = collect_cpu_info,
-       .apply_microcode                  = apply_microcode,
+       .apply_microcode                  = apply_microcode_intel,
        .microcode_fini_cpu               = microcode_fini_cpu,
 };
 
index 18f739129e72080c4c41c863361473e0412b414c..b88343f7a3b321f04a1ca03db587b43051aeba89 100644 (file)
@@ -28,8 +28,8 @@
 #include <asm/tlbflush.h>
 #include <asm/setup.h>
 
-unsigned long mc_saved_in_initrd[MAX_UCODE_COUNT];
-struct mc_saved_data {
+static unsigned long mc_saved_in_initrd[MAX_UCODE_COUNT];
+static struct mc_saved_data {
        unsigned int mc_saved_count;
        struct microcode_intel **mc_saved;
 } mc_saved_data;
@@ -415,7 +415,7 @@ static void __ref show_saved_mc(void)
        struct ucode_cpu_info uci;
 
        if (mc_saved_data.mc_saved_count == 0) {
-               pr_debug("no micorcode data saved.\n");
+               pr_debug("no microcode data saved.\n");
                return;
        }
        pr_debug("Total microcode saved: %d\n", mc_saved_data.mc_saved_count);
@@ -506,7 +506,7 @@ int save_mc_for_early(u8 *mc)
 
        if (mc_saved && mc_saved_count)
                memcpy(mc_saved_tmp, mc_saved,
-                      mc_saved_count * sizeof(struct mirocode_intel *));
+                      mc_saved_count * sizeof(struct microcode_intel *));
        /*
         * Save the microcode patch mc in mc_save_tmp structure if it's a newer
         * version.
@@ -526,7 +526,7 @@ int save_mc_for_early(u8 *mc)
        show_saved_mc();
 
        /*
-        * Free old saved microcod data.
+        * Free old saved microcode data.
         */
        if (mc_saved) {
                for (i = 0; i < mc_saved_count_init; i++)
index f961de9964c7ba2634c48793b8fe3ccfc7b46d3a..ea5f363a194866303395358353a658750dcff3d4 100644 (file)
@@ -707,7 +707,7 @@ void __init mtrr_bp_init(void)
        } else {
                switch (boot_cpu_data.x86_vendor) {
                case X86_VENDOR_AMD:
-                       if (cpu_has_k6_mtrr) {
+                       if (cpu_feature_enabled(X86_FEATURE_K6_MTRR)) {
                                /* Pre-Athlon (K6) AMD CPU MTRRs */
                                mtrr_if = mtrr_ops[X86_VENDOR_AMD];
                                size_or_mask = SIZE_OR_MASK_BITS(32);
@@ -715,14 +715,14 @@ void __init mtrr_bp_init(void)
                        }
                        break;
                case X86_VENDOR_CENTAUR:
-                       if (cpu_has_centaur_mcr) {
+                       if (cpu_feature_enabled(X86_FEATURE_CENTAUR_MCR)) {
                                mtrr_if = mtrr_ops[X86_VENDOR_CENTAUR];
                                size_or_mask = SIZE_OR_MASK_BITS(32);
                                size_and_mask = 0;
                        }
                        break;
                case X86_VENDOR_CYRIX:
-                       if (cpu_has_cyrix_arr) {
+                       if (cpu_feature_enabled(X86_FEATURE_CYRIX_ARR)) {
                                mtrr_if = mtrr_ops[X86_VENDOR_CYRIX];
                                size_or_mask = SIZE_OR_MASK_BITS(32);
                                size_and_mask = 0;
index 2879ecdaac430c62710db3c90b326e6e25f60acf..16c73022306ebcde1c92a208cfa460dea0fc47f0 100644 (file)
@@ -243,7 +243,8 @@ static bool check_hw_exists(void)
 
 msr_fail:
        printk(KERN_CONT "Broken PMU hardware detected, using software events only.\n");
-       printk(KERN_ERR "Failed to access perfctr msr (MSR %x is %Lx)\n", reg, val_new);
+       printk(boot_cpu_has(X86_FEATURE_HYPERVISOR) ? KERN_INFO : KERN_ERR
+              "Failed to access perfctr msr (MSR %x is %Lx)\n", reg, val_new);
 
        return false;
 }
@@ -387,7 +388,7 @@ int x86_pmu_hw_config(struct perf_event *event)
                        precise++;
 
                        /* Support for IP fixup */
-                       if (x86_pmu.lbr_nr)
+                       if (x86_pmu.lbr_nr || x86_pmu.intel_cap.pebs_format >= 2)
                                precise++;
                }
 
@@ -443,6 +444,12 @@ int x86_pmu_hw_config(struct perf_event *event)
        if (event->attr.type == PERF_TYPE_RAW)
                event->hw.config |= event->attr.config & X86_RAW_EVENT_MASK;
 
+       if (event->attr.sample_period && x86_pmu.limit_period) {
+               if (x86_pmu.limit_period(event, event->attr.sample_period) >
+                               event->attr.sample_period)
+                       return -EINVAL;
+       }
+
        return x86_setup_perfctr(event);
 }
 
@@ -980,6 +987,9 @@ int x86_perf_event_set_period(struct perf_event *event)
        if (left > x86_pmu.max_period)
                left = x86_pmu.max_period;
 
+       if (x86_pmu.limit_period)
+               left = x86_pmu.limit_period(event, left);
+
        per_cpu(pmc_prev_left[idx], smp_processor_id()) = left;
 
        /*
index 8ade93111e0379fd79e0b421d29256b6c9b1b206..d98a34d435d7b5260154bcf4463bbcb24ad073fb 100644 (file)
@@ -67,8 +67,10 @@ struct event_constraint {
  */
 #define PERF_X86_EVENT_PEBS_LDLAT      0x1 /* ld+ldlat data address sampling */
 #define PERF_X86_EVENT_PEBS_ST         0x2 /* st data address sampling */
-#define PERF_X86_EVENT_PEBS_ST_HSW     0x4 /* haswell style st data sampling */
+#define PERF_X86_EVENT_PEBS_ST_HSW     0x4 /* haswell style datala, store */
 #define PERF_X86_EVENT_COMMITTED       0x8 /* event passed commit_txn */
+#define PERF_X86_EVENT_PEBS_LD_HSW     0x10 /* haswell style datala, load */
+#define PERF_X86_EVENT_PEBS_NA_HSW     0x20 /* haswell style datala, unknown */
 
 struct amd_nb {
        int nb_id;  /* NorthBridge id */
@@ -252,18 +254,52 @@ struct cpu_hw_events {
        EVENT_CONSTRAINT(c, n, INTEL_ARCH_EVENT_MASK)
 
 #define INTEL_PLD_CONSTRAINT(c, n)     \
-       __EVENT_CONSTRAINT(c, n, INTEL_ARCH_EVENT_MASK, \
+       __EVENT_CONSTRAINT(c, n, INTEL_ARCH_EVENT_MASK|X86_ALL_EVENT_FLAGS, \
                           HWEIGHT(n), 0, PERF_X86_EVENT_PEBS_LDLAT)
 
 #define INTEL_PST_CONSTRAINT(c, n)     \
-       __EVENT_CONSTRAINT(c, n, INTEL_ARCH_EVENT_MASK, \
+       __EVENT_CONSTRAINT(c, n, INTEL_ARCH_EVENT_MASK|X86_ALL_EVENT_FLAGS, \
                          HWEIGHT(n), 0, PERF_X86_EVENT_PEBS_ST)
 
-/* DataLA version of store sampling without extra enable bit. */
-#define INTEL_PST_HSW_CONSTRAINT(c, n) \
-       __EVENT_CONSTRAINT(c, n, INTEL_ARCH_EVENT_MASK, \
+/* Event constraint, but match on all event flags too. */
+#define INTEL_FLAGS_EVENT_CONSTRAINT(c, n) \
+       EVENT_CONSTRAINT(c, n, INTEL_ARCH_EVENT_MASK|X86_ALL_EVENT_FLAGS)
+
+/* Check only flags, but allow all event/umask */
+#define INTEL_ALL_EVENT_CONSTRAINT(code, n)    \
+       EVENT_CONSTRAINT(code, n, X86_ALL_EVENT_FLAGS)
+
+/* Check flags and event code, and set the HSW store flag */
+#define INTEL_FLAGS_EVENT_CONSTRAINT_DATALA_ST(code, n) \
+       __EVENT_CONSTRAINT(code, n,                     \
+                         ARCH_PERFMON_EVENTSEL_EVENT|X86_ALL_EVENT_FLAGS, \
+                         HWEIGHT(n), 0, PERF_X86_EVENT_PEBS_ST_HSW)
+
+/* Check flags and event code, and set the HSW load flag */
+#define INTEL_FLAGS_EVENT_CONSTRAINT_DATALA_LD(code, n) \
+       __EVENT_CONSTRAINT(code, n,                     \
+                         ARCH_PERFMON_EVENTSEL_EVENT|X86_ALL_EVENT_FLAGS, \
+                         HWEIGHT(n), 0, PERF_X86_EVENT_PEBS_LD_HSW)
+
+/* Check flags and event code/umask, and set the HSW store flag */
+#define INTEL_FLAGS_UEVENT_CONSTRAINT_DATALA_ST(code, n) \
+       __EVENT_CONSTRAINT(code, n,                     \
+                         INTEL_ARCH_EVENT_MASK|X86_ALL_EVENT_FLAGS, \
                          HWEIGHT(n), 0, PERF_X86_EVENT_PEBS_ST_HSW)
 
+/* Check flags and event code/umask, and set the HSW load flag */
+#define INTEL_FLAGS_UEVENT_CONSTRAINT_DATALA_LD(code, n) \
+       __EVENT_CONSTRAINT(code, n,                     \
+                         INTEL_ARCH_EVENT_MASK|X86_ALL_EVENT_FLAGS, \
+                         HWEIGHT(n), 0, PERF_X86_EVENT_PEBS_LD_HSW)
+
+/* Check flags and event code/umask, and set the HSW N/A flag */
+#define INTEL_FLAGS_UEVENT_CONSTRAINT_DATALA_NA(code, n) \
+       __EVENT_CONSTRAINT(code, n,                     \
+                         INTEL_ARCH_EVENT_MASK|INTEL_ARCH_EVENT_MASK, \
+                         HWEIGHT(n), 0, PERF_X86_EVENT_PEBS_NA_HSW)
+
+
 /*
  * We define the end marker as having a weight of -1
  * to enable blacklisting of events using a counter bitmask
@@ -409,6 +445,7 @@ struct x86_pmu {
        struct x86_pmu_quirk *quirks;
        int             perfctr_second_write;
        bool            late_ack;
+       unsigned        (*limit_period)(struct perf_event *event, unsigned l);
 
        /*
         * sysfs attrs
index 2502d0d9d246a1fe63c57070176b2bcc04cad3bb..3851def5057c3dd1b2a7b08acc6641dc918a395a 100644 (file)
@@ -220,6 +220,15 @@ static struct event_constraint intel_hsw_event_constraints[] = {
        EVENT_CONSTRAINT_END
 };
 
+static struct event_constraint intel_bdw_event_constraints[] = {
+       FIXED_EVENT_CONSTRAINT(0x00c0, 0),      /* INST_RETIRED.ANY */
+       FIXED_EVENT_CONSTRAINT(0x003c, 1),      /* CPU_CLK_UNHALTED.CORE */
+       FIXED_EVENT_CONSTRAINT(0x0300, 2),      /* CPU_CLK_UNHALTED.REF */
+       INTEL_UEVENT_CONSTRAINT(0x148, 0x4),    /* L1D_PEND_MISS.PENDING */
+       INTEL_EVENT_CONSTRAINT(0xa3, 0x4),      /* CYCLE_ACTIVITY.* */
+       EVENT_CONSTRAINT_END
+};
+
 static u64 intel_pmu_event_map(int hw_event)
 {
        return intel_perfmon_event_map[hw_event];
@@ -415,6 +424,126 @@ static __initconst const u64 snb_hw_cache_event_ids
 
 };
 
+static __initconst const u64 hsw_hw_cache_event_ids
+                               [PERF_COUNT_HW_CACHE_MAX]
+                               [PERF_COUNT_HW_CACHE_OP_MAX]
+                               [PERF_COUNT_HW_CACHE_RESULT_MAX] =
+{
+ [ C(L1D ) ] = {
+       [ C(OP_READ) ] = {
+               [ C(RESULT_ACCESS) ] = 0x81d0,  /* MEM_UOPS_RETIRED.ALL_LOADS */
+               [ C(RESULT_MISS)   ] = 0x151,   /* L1D.REPLACEMENT */
+       },
+       [ C(OP_WRITE) ] = {
+               [ C(RESULT_ACCESS) ] = 0x82d0,  /* MEM_UOPS_RETIRED.ALL_STORES */
+               [ C(RESULT_MISS)   ] = 0x0,
+       },
+       [ C(OP_PREFETCH) ] = {
+               [ C(RESULT_ACCESS) ] = 0x0,
+               [ C(RESULT_MISS)   ] = 0x0,
+       },
+ },
+ [ C(L1I ) ] = {
+       [ C(OP_READ) ] = {
+               [ C(RESULT_ACCESS) ] = 0x0,
+               [ C(RESULT_MISS)   ] = 0x280,   /* ICACHE.MISSES */
+       },
+       [ C(OP_WRITE) ] = {
+               [ C(RESULT_ACCESS) ] = -1,
+               [ C(RESULT_MISS)   ] = -1,
+       },
+       [ C(OP_PREFETCH) ] = {
+               [ C(RESULT_ACCESS) ] = 0x0,
+               [ C(RESULT_MISS)   ] = 0x0,
+       },
+ },
+ [ C(LL  ) ] = {
+       [ C(OP_READ) ] = {
+               /* OFFCORE_RESPONSE:ALL_DATA_RD|ALL_CODE_RD */
+               [ C(RESULT_ACCESS) ] = 0x1b7,
+               /* OFFCORE_RESPONSE:ALL_DATA_RD|ALL_CODE_RD|SUPPLIER_NONE|
+                   L3_MISS|ANY_SNOOP */
+               [ C(RESULT_MISS)   ] = 0x1b7,
+       },
+       [ C(OP_WRITE) ] = {
+               [ C(RESULT_ACCESS) ] = 0x1b7,   /* OFFCORE_RESPONSE:ALL_RFO */
+               /* OFFCORE_RESPONSE:ALL_RFO|SUPPLIER_NONE|L3_MISS|ANY_SNOOP */
+               [ C(RESULT_MISS)   ] = 0x1b7,
+       },
+       [ C(OP_PREFETCH) ] = {
+               [ C(RESULT_ACCESS) ] = 0x0,
+               [ C(RESULT_MISS)   ] = 0x0,
+       },
+ },
+ [ C(DTLB) ] = {
+       [ C(OP_READ) ] = {
+               [ C(RESULT_ACCESS) ] = 0x81d0,  /* MEM_UOPS_RETIRED.ALL_LOADS */
+               [ C(RESULT_MISS)   ] = 0x108,   /* DTLB_LOAD_MISSES.MISS_CAUSES_A_WALK */
+       },
+       [ C(OP_WRITE) ] = {
+               [ C(RESULT_ACCESS) ] = 0x82d0,  /* MEM_UOPS_RETIRED.ALL_STORES */
+               [ C(RESULT_MISS)   ] = 0x149,   /* DTLB_STORE_MISSES.MISS_CAUSES_A_WALK */
+       },
+       [ C(OP_PREFETCH) ] = {
+               [ C(RESULT_ACCESS) ] = 0x0,
+               [ C(RESULT_MISS)   ] = 0x0,
+       },
+ },
+ [ C(ITLB) ] = {
+       [ C(OP_READ) ] = {
+               [ C(RESULT_ACCESS) ] = 0x6085,  /* ITLB_MISSES.STLB_HIT */
+               [ C(RESULT_MISS)   ] = 0x185,   /* ITLB_MISSES.MISS_CAUSES_A_WALK */
+       },
+       [ C(OP_WRITE) ] = {
+               [ C(RESULT_ACCESS) ] = -1,
+               [ C(RESULT_MISS)   ] = -1,
+       },
+       [ C(OP_PREFETCH) ] = {
+               [ C(RESULT_ACCESS) ] = -1,
+               [ C(RESULT_MISS)   ] = -1,
+       },
+ },
+ [ C(BPU ) ] = {
+       [ C(OP_READ) ] = {
+               [ C(RESULT_ACCESS) ] = 0xc4,    /* BR_INST_RETIRED.ALL_BRANCHES */
+               [ C(RESULT_MISS)   ] = 0xc5,    /* BR_MISP_RETIRED.ALL_BRANCHES */
+       },
+       [ C(OP_WRITE) ] = {
+               [ C(RESULT_ACCESS) ] = -1,
+               [ C(RESULT_MISS)   ] = -1,
+       },
+       [ C(OP_PREFETCH) ] = {
+               [ C(RESULT_ACCESS) ] = -1,
+               [ C(RESULT_MISS)   ] = -1,
+       },
+ },
+};
+
+static __initconst const u64 hsw_hw_cache_extra_regs
+                               [PERF_COUNT_HW_CACHE_MAX]
+                               [PERF_COUNT_HW_CACHE_OP_MAX]
+                               [PERF_COUNT_HW_CACHE_RESULT_MAX] =
+{
+ [ C(LL  ) ] = {
+       [ C(OP_READ) ] = {
+               /* OFFCORE_RESPONSE:ALL_DATA_RD|ALL_CODE_RD */
+               [ C(RESULT_ACCESS) ] = 0x2d5,
+               /* OFFCORE_RESPONSE:ALL_DATA_RD|ALL_CODE_RD|SUPPLIER_NONE|
+                   L3_MISS|ANY_SNOOP */
+               [ C(RESULT_MISS)   ] = 0x3fbc0202d5ull,
+       },
+       [ C(OP_WRITE) ] = {
+               [ C(RESULT_ACCESS) ] = 0x122,   /* OFFCORE_RESPONSE:ALL_RFO */
+               /* OFFCORE_RESPONSE:ALL_RFO|SUPPLIER_NONE|L3_MISS|ANY_SNOOP */
+               [ C(RESULT_MISS)   ] = 0x3fbc020122ull,
+       },
+       [ C(OP_PREFETCH) ] = {
+               [ C(RESULT_ACCESS) ] = 0x0,
+               [ C(RESULT_MISS)   ] = 0x0,
+       },
+ },
+};
+
 static __initconst const u64 westmere_hw_cache_event_ids
                                [PERF_COUNT_HW_CACHE_MAX]
                                [PERF_COUNT_HW_CACHE_OP_MAX]
@@ -1905,6 +2034,24 @@ hsw_get_event_constraints(struct cpu_hw_events *cpuc, struct perf_event *event)
        return c;
 }
 
+/*
+ * Broadwell:
+ * The INST_RETIRED.ALL period always needs to have lowest
+ * 6bits cleared (BDM57). It shall not use a period smaller
+ * than 100 (BDM11). We combine the two to enforce
+ * a min-period of 128.
+ */
+static unsigned bdw_limit_period(struct perf_event *event, unsigned left)
+{
+       if ((event->hw.config & INTEL_ARCH_EVENT_MASK) ==
+                       X86_CONFIG(.event=0xc0, .umask=0x01)) {
+               if (left < 128)
+                       left = 128;
+               left &= ~0x3fu;
+       }
+       return left;
+}
+
 PMU_FORMAT_ATTR(event, "config:0-7"    );
 PMU_FORMAT_ATTR(umask, "config:8-15"   );
 PMU_FORMAT_ATTR(edge,  "config:18"     );
@@ -2367,15 +2514,15 @@ __init int intel_pmu_init(void)
         * Install the hw-cache-events table:
         */
        switch (boot_cpu_data.x86_model) {
-       case 14: /* 65 nm core solo/duo, "Yonah" */
+       case 14: /* 65nm Core "Yonah" */
                pr_cont("Core events, ");
                break;
 
-       case 15: /* original 65 nm celeron/pentium/core2/xeon, "Merom"/"Conroe" */
+       case 15: /* 65nm Core2 "Merom"          */
                x86_add_quirk(intel_clovertown_quirk);
-       case 22: /* single-core 65 nm celeron/core2solo "Merom-L"/"Conroe-L" */
-       case 23: /* current 45 nm celeron/core2/xeon "Penryn"/"Wolfdale" */
-       case 29: /* six-core 45 nm xeon "Dunnington" */
+       case 22: /* 65nm Core2 "Merom-L"        */
+       case 23: /* 45nm Core2 "Penryn"         */
+       case 29: /* 45nm Core2 "Dunnington (MP) */
                memcpy(hw_cache_event_ids, core2_hw_cache_event_ids,
                       sizeof(hw_cache_event_ids));
 
@@ -2386,9 +2533,9 @@ __init int intel_pmu_init(void)
                pr_cont("Core2 events, ");
                break;
 
-       case 26: /* 45 nm nehalem, "Bloomfield" */
-       case 30: /* 45 nm nehalem, "Lynnfield" */
-       case 46: /* 45 nm nehalem-ex, "Beckton" */
+       case 30: /* 45nm Nehalem    */
+       case 26: /* 45nm Nehalem-EP */
+       case 46: /* 45nm Nehalem-EX */
                memcpy(hw_cache_event_ids, nehalem_hw_cache_event_ids,
                       sizeof(hw_cache_event_ids));
                memcpy(hw_cache_extra_regs, nehalem_hw_cache_extra_regs,
@@ -2415,11 +2562,11 @@ __init int intel_pmu_init(void)
                pr_cont("Nehalem events, ");
                break;
 
-       case 28: /* Atom */
-       case 38: /* Lincroft */
-       case 39: /* Penwell */
-       case 53: /* Cloverview */
-       case 54: /* Cedarview */
+       case 28: /* 45nm Atom "Pineview"   */
+       case 38: /* 45nm Atom "Lincroft"   */
+       case 39: /* 32nm Atom "Penwell"    */
+       case 53: /* 32nm Atom "Cloverview" */
+       case 54: /* 32nm Atom "Cedarview"  */
                memcpy(hw_cache_event_ids, atom_hw_cache_event_ids,
                       sizeof(hw_cache_event_ids));
 
@@ -2430,8 +2577,8 @@ __init int intel_pmu_init(void)
                pr_cont("Atom events, ");
                break;
 
-       case 55: /* Atom 22nm "Silvermont" */
-       case 77: /* Avoton "Silvermont" */
+       case 55: /* 22nm Atom "Silvermont"                */
+       case 77: /* 22nm Atom "Silvermont Avoton/Rangely" */
                memcpy(hw_cache_event_ids, slm_hw_cache_event_ids,
                        sizeof(hw_cache_event_ids));
                memcpy(hw_cache_extra_regs, slm_hw_cache_extra_regs,
@@ -2446,9 +2593,9 @@ __init int intel_pmu_init(void)
                pr_cont("Silvermont events, ");
                break;
 
-       case 37: /* 32 nm nehalem, "Clarkdale" */
-       case 44: /* 32 nm nehalem, "Gulftown" */
-       case 47: /* 32 nm Xeon E7 */
+       case 37: /* 32nm Westmere    */
+       case 44: /* 32nm Westmere-EP */
+       case 47: /* 32nm Westmere-EX */
                memcpy(hw_cache_event_ids, westmere_hw_cache_event_ids,
                       sizeof(hw_cache_event_ids));
                memcpy(hw_cache_extra_regs, nehalem_hw_cache_extra_regs,
@@ -2474,8 +2621,8 @@ __init int intel_pmu_init(void)
                pr_cont("Westmere events, ");
                break;
 
-       case 42: /* SandyBridge */
-       case 45: /* SandyBridge, "Romely-EP" */
+       case 42: /* 32nm SandyBridge         */
+       case 45: /* 32nm SandyBridge-E/EN/EP */
                x86_add_quirk(intel_sandybridge_quirk);
                memcpy(hw_cache_event_ids, snb_hw_cache_event_ids,
                       sizeof(hw_cache_event_ids));
@@ -2506,8 +2653,9 @@ __init int intel_pmu_init(void)
 
                pr_cont("SandyBridge events, ");
                break;
-       case 58: /* IvyBridge */
-       case 62: /* IvyBridge EP */
+
+       case 58: /* 22nm IvyBridge       */
+       case 62: /* 22nm IvyBridge-EP/EX */
                memcpy(hw_cache_event_ids, snb_hw_cache_event_ids,
                       sizeof(hw_cache_event_ids));
                /* dTLB-load-misses on IVB is different than SNB */
@@ -2539,20 +2687,19 @@ __init int intel_pmu_init(void)
                break;
 
 
-       case 60: /* Haswell Client */
-       case 70:
-       case 71:
-       case 63:
-       case 69:
+       case 60: /* 22nm Haswell Core */
+       case 63: /* 22nm Haswell Server */
+       case 69: /* 22nm Haswell ULT */
+       case 70: /* 22nm Haswell + GT3e (Intel Iris Pro graphics) */
                x86_pmu.late_ack = true;
-               memcpy(hw_cache_event_ids, snb_hw_cache_event_ids, sizeof(hw_cache_event_ids));
-               memcpy(hw_cache_extra_regs, snb_hw_cache_extra_regs, sizeof(hw_cache_extra_regs));
+               memcpy(hw_cache_event_ids, hsw_hw_cache_event_ids, sizeof(hw_cache_event_ids));
+               memcpy(hw_cache_extra_regs, hsw_hw_cache_extra_regs, sizeof(hw_cache_extra_regs));
 
                intel_pmu_lbr_init_snb();
 
                x86_pmu.event_constraints = intel_hsw_event_constraints;
                x86_pmu.pebs_constraints = intel_hsw_pebs_event_constraints;
-               x86_pmu.extra_regs = intel_snb_extra_regs;
+               x86_pmu.extra_regs = intel_snbep_extra_regs;
                x86_pmu.pebs_aliases = intel_pebs_aliases_snb;
                /* all extra regs are per-cpu when HT is on */
                x86_pmu.er_flags |= ERF_HAS_RSP_1;
@@ -2565,6 +2712,28 @@ __init int intel_pmu_init(void)
                pr_cont("Haswell events, ");
                break;
 
+       case 61: /* 14nm Broadwell Core-M */
+               x86_pmu.late_ack = true;
+               memcpy(hw_cache_event_ids, hsw_hw_cache_event_ids, sizeof(hw_cache_event_ids));
+               memcpy(hw_cache_extra_regs, hsw_hw_cache_extra_regs, sizeof(hw_cache_extra_regs));
+
+               intel_pmu_lbr_init_snb();
+
+               x86_pmu.event_constraints = intel_bdw_event_constraints;
+               x86_pmu.pebs_constraints = intel_hsw_pebs_event_constraints;
+               x86_pmu.extra_regs = intel_snbep_extra_regs;
+               x86_pmu.pebs_aliases = intel_pebs_aliases_snb;
+               /* all extra regs are per-cpu when HT is on */
+               x86_pmu.er_flags |= ERF_HAS_RSP_1;
+               x86_pmu.er_flags |= ERF_NO_HT_SHARING;
+
+               x86_pmu.hw_config = hsw_hw_config;
+               x86_pmu.get_event_constraints = hsw_get_event_constraints;
+               x86_pmu.cpu_events = hsw_events_attrs;
+               x86_pmu.limit_period = bdw_limit_period;
+               pr_cont("Broadwell events, ");
+               break;
+
        default:
                switch (x86_pmu.version) {
                case 1:
index 696ade311ded7d01103323d159cff621b46d4a89..b1553d05a5cb6adee590a2733913e1c774192025 100644 (file)
@@ -108,14 +108,16 @@ static u64 precise_store_data(u64 status)
        return val;
 }
 
-static u64 precise_store_data_hsw(struct perf_event *event, u64 status)
+static u64 precise_datala_hsw(struct perf_event *event, u64 status)
 {
        union perf_mem_data_src dse;
-       u64 cfg = event->hw.config & INTEL_ARCH_EVENT_MASK;
 
-       dse.val = 0;
-       dse.mem_op = PERF_MEM_OP_STORE;
-       dse.mem_lvl = PERF_MEM_LVL_NA;
+       dse.val = PERF_MEM_NA;
+
+       if (event->hw.flags & PERF_X86_EVENT_PEBS_ST_HSW)
+               dse.mem_op = PERF_MEM_OP_STORE;
+       else if (event->hw.flags & PERF_X86_EVENT_PEBS_LD_HSW)
+               dse.mem_op = PERF_MEM_OP_LOAD;
 
        /*
         * L1 info only valid for following events:
@@ -125,15 +127,12 @@ static u64 precise_store_data_hsw(struct perf_event *event, u64 status)
         * MEM_UOPS_RETIRED.SPLIT_STORES
         * MEM_UOPS_RETIRED.ALL_STORES
         */
-       if (cfg != 0x12d0 && cfg != 0x22d0 && cfg != 0x42d0 && cfg != 0x82d0)
-               return dse.mem_lvl;
-
-       if (status & 1)
-               dse.mem_lvl = PERF_MEM_LVL_L1 | PERF_MEM_LVL_HIT;
-       else
-               dse.mem_lvl = PERF_MEM_LVL_L1 | PERF_MEM_LVL_MISS;
-
-       /* Nothing else supported. Sorry. */
+       if (event->hw.flags & PERF_X86_EVENT_PEBS_ST_HSW) {
+               if (status & 1)
+                       dse.mem_lvl = PERF_MEM_LVL_L1 | PERF_MEM_LVL_HIT;
+               else
+                       dse.mem_lvl = PERF_MEM_LVL_L1 | PERF_MEM_LVL_MISS;
+       }
        return dse.val;
 }
 
@@ -569,28 +568,10 @@ struct event_constraint intel_atom_pebs_event_constraints[] = {
 };
 
 struct event_constraint intel_slm_pebs_event_constraints[] = {
-       INTEL_UEVENT_CONSTRAINT(0x0103, 0x1), /* REHABQ.LD_BLOCK_ST_FORWARD_PS */
-       INTEL_UEVENT_CONSTRAINT(0x0803, 0x1), /* REHABQ.LD_SPLITS_PS */
-       INTEL_UEVENT_CONSTRAINT(0x0204, 0x1), /* MEM_UOPS_RETIRED.L2_HIT_LOADS_PS */
-       INTEL_UEVENT_CONSTRAINT(0x0404, 0x1), /* MEM_UOPS_RETIRED.L2_MISS_LOADS_PS */
-       INTEL_UEVENT_CONSTRAINT(0x0804, 0x1), /* MEM_UOPS_RETIRED.DTLB_MISS_LOADS_PS */
-       INTEL_UEVENT_CONSTRAINT(0x2004, 0x1), /* MEM_UOPS_RETIRED.HITM_PS */
-       INTEL_UEVENT_CONSTRAINT(0x00c0, 0x1), /* INST_RETIRED.ANY_PS */
-       INTEL_UEVENT_CONSTRAINT(0x00c4, 0x1), /* BR_INST_RETIRED.ALL_BRANCHES_PS */
-       INTEL_UEVENT_CONSTRAINT(0x7ec4, 0x1), /* BR_INST_RETIRED.JCC_PS */
-       INTEL_UEVENT_CONSTRAINT(0xbfc4, 0x1), /* BR_INST_RETIRED.FAR_BRANCH_PS */
-       INTEL_UEVENT_CONSTRAINT(0xebc4, 0x1), /* BR_INST_RETIRED.NON_RETURN_IND_PS */
-       INTEL_UEVENT_CONSTRAINT(0xf7c4, 0x1), /* BR_INST_RETIRED.RETURN_PS */
-       INTEL_UEVENT_CONSTRAINT(0xf9c4, 0x1), /* BR_INST_RETIRED.CALL_PS */
-       INTEL_UEVENT_CONSTRAINT(0xfbc4, 0x1), /* BR_INST_RETIRED.IND_CALL_PS */
-       INTEL_UEVENT_CONSTRAINT(0xfdc4, 0x1), /* BR_INST_RETIRED.REL_CALL_PS */
-       INTEL_UEVENT_CONSTRAINT(0xfec4, 0x1), /* BR_INST_RETIRED.TAKEN_JCC_PS */
-       INTEL_UEVENT_CONSTRAINT(0x00c5, 0x1), /* BR_INST_MISP_RETIRED.ALL_BRANCHES_PS */
-       INTEL_UEVENT_CONSTRAINT(0x7ec5, 0x1), /* BR_INST_MISP_RETIRED.JCC_PS */
-       INTEL_UEVENT_CONSTRAINT(0xebc5, 0x1), /* BR_INST_MISP_RETIRED.NON_RETURN_IND_PS */
-       INTEL_UEVENT_CONSTRAINT(0xf7c5, 0x1), /* BR_INST_MISP_RETIRED.RETURN_PS */
-       INTEL_UEVENT_CONSTRAINT(0xfbc5, 0x1), /* BR_INST_MISP_RETIRED.IND_CALL_PS */
-       INTEL_UEVENT_CONSTRAINT(0xfec5, 0x1), /* BR_INST_MISP_RETIRED.TAKEN_JCC_PS */
+       /* UOPS_RETIRED.ALL, inv=1, cmask=16 (cycles:p). */
+       INTEL_FLAGS_EVENT_CONSTRAINT(0x108001c2, 0xf),
+       /* Allow all events as PEBS with no flags */
+       INTEL_ALL_EVENT_CONSTRAINT(0, 0x1),
        EVENT_CONSTRAINT_END
 };
 
@@ -626,68 +607,44 @@ struct event_constraint intel_westmere_pebs_event_constraints[] = {
 
 struct event_constraint intel_snb_pebs_event_constraints[] = {
        INTEL_UEVENT_CONSTRAINT(0x01c0, 0x2), /* INST_RETIRED.PRECDIST */
-       INTEL_UEVENT_CONSTRAINT(0x01c2, 0xf), /* UOPS_RETIRED.ALL */
-       INTEL_UEVENT_CONSTRAINT(0x02c2, 0xf), /* UOPS_RETIRED.RETIRE_SLOTS */
-       INTEL_EVENT_CONSTRAINT(0xc4, 0xf),    /* BR_INST_RETIRED.* */
-       INTEL_EVENT_CONSTRAINT(0xc5, 0xf),    /* BR_MISP_RETIRED.* */
        INTEL_PLD_CONSTRAINT(0x01cd, 0x8),    /* MEM_TRANS_RETIRED.LAT_ABOVE_THR */
        INTEL_PST_CONSTRAINT(0x02cd, 0x8),    /* MEM_TRANS_RETIRED.PRECISE_STORES */
-       INTEL_EVENT_CONSTRAINT(0xd0, 0xf),    /* MEM_UOP_RETIRED.* */
-       INTEL_EVENT_CONSTRAINT(0xd1, 0xf),    /* MEM_LOAD_UOPS_RETIRED.* */
-       INTEL_EVENT_CONSTRAINT(0xd2, 0xf),    /* MEM_LOAD_UOPS_LLC_HIT_RETIRED.* */
-       INTEL_EVENT_CONSTRAINT(0xd3, 0xf),    /* MEM_LOAD_UOPS_LLC_MISS_RETIRED.* */
-       INTEL_UEVENT_CONSTRAINT(0x02d4, 0xf), /* MEM_LOAD_UOPS_MISC_RETIRED.LLC_MISS */
+       /* UOPS_RETIRED.ALL, inv=1, cmask=16 (cycles:p). */
+       INTEL_FLAGS_EVENT_CONSTRAINT(0x108001c2, 0xf),
+       /* Allow all events as PEBS with no flags */
+       INTEL_ALL_EVENT_CONSTRAINT(0, 0xf),
        EVENT_CONSTRAINT_END
 };
 
 struct event_constraint intel_ivb_pebs_event_constraints[] = {
         INTEL_UEVENT_CONSTRAINT(0x01c0, 0x2), /* INST_RETIRED.PRECDIST */
-        INTEL_UEVENT_CONSTRAINT(0x01c2, 0xf), /* UOPS_RETIRED.ALL */
-        INTEL_UEVENT_CONSTRAINT(0x02c2, 0xf), /* UOPS_RETIRED.RETIRE_SLOTS */
-        INTEL_EVENT_CONSTRAINT(0xc4, 0xf),    /* BR_INST_RETIRED.* */
-        INTEL_EVENT_CONSTRAINT(0xc5, 0xf),    /* BR_MISP_RETIRED.* */
         INTEL_PLD_CONSTRAINT(0x01cd, 0x8),    /* MEM_TRANS_RETIRED.LAT_ABOVE_THR */
        INTEL_PST_CONSTRAINT(0x02cd, 0x8),    /* MEM_TRANS_RETIRED.PRECISE_STORES */
-        INTEL_EVENT_CONSTRAINT(0xd0, 0xf),    /* MEM_UOP_RETIRED.* */
-        INTEL_EVENT_CONSTRAINT(0xd1, 0xf),    /* MEM_LOAD_UOPS_RETIRED.* */
-        INTEL_EVENT_CONSTRAINT(0xd2, 0xf),    /* MEM_LOAD_UOPS_LLC_HIT_RETIRED.* */
-        INTEL_EVENT_CONSTRAINT(0xd3, 0xf),    /* MEM_LOAD_UOPS_LLC_MISS_RETIRED.* */
+       /* UOPS_RETIRED.ALL, inv=1, cmask=16 (cycles:p). */
+       INTEL_FLAGS_EVENT_CONSTRAINT(0x108001c2, 0xf),
+       /* Allow all events as PEBS with no flags */
+       INTEL_ALL_EVENT_CONSTRAINT(0, 0xf),
         EVENT_CONSTRAINT_END
 };
 
 struct event_constraint intel_hsw_pebs_event_constraints[] = {
        INTEL_UEVENT_CONSTRAINT(0x01c0, 0x2), /* INST_RETIRED.PRECDIST */
-       INTEL_PST_HSW_CONSTRAINT(0x01c2, 0xf), /* UOPS_RETIRED.ALL */
-       INTEL_UEVENT_CONSTRAINT(0x02c2, 0xf), /* UOPS_RETIRED.RETIRE_SLOTS */
-       INTEL_EVENT_CONSTRAINT(0xc4, 0xf),    /* BR_INST_RETIRED.* */
-       INTEL_UEVENT_CONSTRAINT(0x01c5, 0xf), /* BR_MISP_RETIRED.CONDITIONAL */
-       INTEL_UEVENT_CONSTRAINT(0x04c5, 0xf), /* BR_MISP_RETIRED.ALL_BRANCHES */
-       INTEL_UEVENT_CONSTRAINT(0x20c5, 0xf), /* BR_MISP_RETIRED.NEAR_TAKEN */
-       INTEL_PLD_CONSTRAINT(0x01cd, 0x8),    /* MEM_TRANS_RETIRED.* */
-       /* MEM_UOPS_RETIRED.STLB_MISS_LOADS */
-       INTEL_UEVENT_CONSTRAINT(0x11d0, 0xf),
-       /* MEM_UOPS_RETIRED.STLB_MISS_STORES */
-       INTEL_UEVENT_CONSTRAINT(0x12d0, 0xf),
-       INTEL_UEVENT_CONSTRAINT(0x21d0, 0xf), /* MEM_UOPS_RETIRED.LOCK_LOADS */
-       INTEL_UEVENT_CONSTRAINT(0x41d0, 0xf), /* MEM_UOPS_RETIRED.SPLIT_LOADS */
-       /* MEM_UOPS_RETIRED.SPLIT_STORES */
-       INTEL_UEVENT_CONSTRAINT(0x42d0, 0xf),
-       INTEL_UEVENT_CONSTRAINT(0x81d0, 0xf), /* MEM_UOPS_RETIRED.ALL_LOADS */
-       INTEL_PST_HSW_CONSTRAINT(0x82d0, 0xf), /* MEM_UOPS_RETIRED.ALL_STORES */
-       INTEL_UEVENT_CONSTRAINT(0x01d1, 0xf), /* MEM_LOAD_UOPS_RETIRED.L1_HIT */
-       INTEL_UEVENT_CONSTRAINT(0x02d1, 0xf), /* MEM_LOAD_UOPS_RETIRED.L2_HIT */
-       INTEL_UEVENT_CONSTRAINT(0x04d1, 0xf), /* MEM_LOAD_UOPS_RETIRED.L3_HIT */
-       /* MEM_LOAD_UOPS_RETIRED.HIT_LFB */
-       INTEL_UEVENT_CONSTRAINT(0x40d1, 0xf),
-       /* MEM_LOAD_UOPS_LLC_HIT_RETIRED.XSNP_MISS */
-       INTEL_UEVENT_CONSTRAINT(0x01d2, 0xf),
-       /* MEM_LOAD_UOPS_LLC_HIT_RETIRED.XSNP_HIT */
-       INTEL_UEVENT_CONSTRAINT(0x02d2, 0xf),
-       /* MEM_LOAD_UOPS_LLC_MISS_RETIRED.LOCAL_DRAM */
-       INTEL_UEVENT_CONSTRAINT(0x01d3, 0xf),
-       INTEL_UEVENT_CONSTRAINT(0x04c8, 0xf), /* HLE_RETIRED.Abort */
-       INTEL_UEVENT_CONSTRAINT(0x04c9, 0xf), /* RTM_RETIRED.Abort */
-
+       INTEL_PLD_CONSTRAINT(0x01cd, 0xf),    /* MEM_TRANS_RETIRED.* */
+       /* UOPS_RETIRED.ALL, inv=1, cmask=16 (cycles:p). */
+       INTEL_FLAGS_EVENT_CONSTRAINT(0x108001c2, 0xf),
+       INTEL_FLAGS_UEVENT_CONSTRAINT_DATALA_NA(0x01c2, 0xf), /* UOPS_RETIRED.ALL */
+       INTEL_FLAGS_UEVENT_CONSTRAINT_DATALA_LD(0x11d0, 0xf), /* MEM_UOPS_RETIRED.STLB_MISS_LOADS */
+       INTEL_FLAGS_UEVENT_CONSTRAINT_DATALA_LD(0x21d0, 0xf), /* MEM_UOPS_RETIRED.LOCK_LOADS */
+       INTEL_FLAGS_UEVENT_CONSTRAINT_DATALA_LD(0x41d0, 0xf), /* MEM_UOPS_RETIRED.SPLIT_LOADS */
+       INTEL_FLAGS_UEVENT_CONSTRAINT_DATALA_LD(0x81d0, 0xf), /* MEM_UOPS_RETIRED.ALL_LOADS */
+       INTEL_FLAGS_UEVENT_CONSTRAINT_DATALA_ST(0x12d0, 0xf), /* MEM_UOPS_RETIRED.STLB_MISS_STORES */
+       INTEL_FLAGS_UEVENT_CONSTRAINT_DATALA_ST(0x42d0, 0xf), /* MEM_UOPS_RETIRED.SPLIT_STORES */
+       INTEL_FLAGS_UEVENT_CONSTRAINT_DATALA_ST(0x82d0, 0xf), /* MEM_UOPS_RETIRED.ALL_STORES */
+       INTEL_FLAGS_EVENT_CONSTRAINT_DATALA_LD(0xd1, 0xf),    /* MEM_LOAD_UOPS_RETIRED.* */
+       INTEL_FLAGS_EVENT_CONSTRAINT_DATALA_LD(0xd2, 0xf),    /* MEM_LOAD_UOPS_L3_HIT_RETIRED.* */
+       INTEL_FLAGS_EVENT_CONSTRAINT_DATALA_LD(0xd3, 0xf),    /* MEM_LOAD_UOPS_L3_MISS_RETIRED.* */
+       /* Allow all events as PEBS with no flags */
+       INTEL_ALL_EVENT_CONSTRAINT(0, 0xf),
        EVENT_CONSTRAINT_END
 };
 
@@ -864,6 +821,10 @@ static inline u64 intel_hsw_transaction(struct pebs_record_hsw *pebs)
 static void __intel_pmu_pebs_event(struct perf_event *event,
                                   struct pt_regs *iregs, void *__pebs)
 {
+#define PERF_X86_EVENT_PEBS_HSW_PREC \
+               (PERF_X86_EVENT_PEBS_ST_HSW | \
+                PERF_X86_EVENT_PEBS_LD_HSW | \
+                PERF_X86_EVENT_PEBS_NA_HSW)
        /*
         * We cast to the biggest pebs_record but are careful not to
         * unconditionally access the 'extra' entries.
@@ -873,42 +834,40 @@ static void __intel_pmu_pebs_event(struct perf_event *event,
        struct perf_sample_data data;
        struct pt_regs regs;
        u64 sample_type;
-       int fll, fst;
+       int fll, fst, dsrc;
+       int fl = event->hw.flags;
 
        if (!intel_pmu_save_and_restart(event))
                return;
 
-       fll = event->hw.flags & PERF_X86_EVENT_PEBS_LDLAT;
-       fst = event->hw.flags & (PERF_X86_EVENT_PEBS_ST |
-                                PERF_X86_EVENT_PEBS_ST_HSW);
+       sample_type = event->attr.sample_type;
+       dsrc = sample_type & PERF_SAMPLE_DATA_SRC;
+
+       fll = fl & PERF_X86_EVENT_PEBS_LDLAT;
+       fst = fl & (PERF_X86_EVENT_PEBS_ST | PERF_X86_EVENT_PEBS_HSW_PREC);
 
        perf_sample_data_init(&data, 0, event->hw.last_period);
 
        data.period = event->hw.last_period;
-       sample_type = event->attr.sample_type;
 
        /*
-        * if PEBS-LL or PreciseStore
+        * Use latency for weight (only avail with PEBS-LL)
         */
-       if (fll || fst) {
-               /*
-                * Use latency for weight (only avail with PEBS-LL)
-                */
-               if (fll && (sample_type & PERF_SAMPLE_WEIGHT))
-                       data.weight = pebs->lat;
-
-               /*
-                * data.data_src encodes the data source
-                */
-               if (sample_type & PERF_SAMPLE_DATA_SRC) {
-                       if (fll)
-                               data.data_src.val = load_latency_data(pebs->dse);
-                       else if (event->hw.flags & PERF_X86_EVENT_PEBS_ST_HSW)
-                               data.data_src.val =
-                                       precise_store_data_hsw(event, pebs->dse);
-                       else
-                               data.data_src.val = precise_store_data(pebs->dse);
-               }
+       if (fll && (sample_type & PERF_SAMPLE_WEIGHT))
+               data.weight = pebs->lat;
+
+       /*
+        * data.data_src encodes the data source
+        */
+       if (dsrc) {
+               u64 val = PERF_MEM_NA;
+               if (fll)
+                       val = load_latency_data(pebs->dse);
+               else if (fst && (fl & PERF_X86_EVENT_PEBS_HSW_PREC))
+                       val = precise_datala_hsw(event, pebs->dse);
+               else if (fst)
+                       val = precise_store_data(pebs->dse);
+               data.data_src.val = val;
        }
 
        /*
@@ -935,16 +894,16 @@ static void __intel_pmu_pebs_event(struct perf_event *event,
        else
                regs.flags &= ~PERF_EFLAGS_EXACT;
 
-       if ((event->attr.sample_type & PERF_SAMPLE_ADDR) &&
+       if ((sample_type & PERF_SAMPLE_ADDR) &&
            x86_pmu.intel_cap.pebs_format >= 1)
                data.addr = pebs->dla;
 
        if (x86_pmu.intel_cap.pebs_format >= 2) {
                /* Only set the TSX weight when no memory weight. */
-               if ((event->attr.sample_type & PERF_SAMPLE_WEIGHT) && !fll)
+               if ((sample_type & PERF_SAMPLE_WEIGHT) && !fll)
                        data.weight = intel_hsw_weight(pebs);
 
-               if (event->attr.sample_type & PERF_SAMPLE_TRANSACTION)
+               if (sample_type & PERF_SAMPLE_TRANSACTION)
                        data.txn = intel_hsw_transaction(pebs);
        }
 
@@ -1055,7 +1014,7 @@ static void intel_pmu_drain_pebs_nhm(struct pt_regs *iregs)
  * BTS, PEBS probe and setup
  */
 
-void intel_ds_init(void)
+void __init intel_ds_init(void)
 {
        /*
         * No support for 32bit formats
index 9dd2459a4c738d99bb4a75ebf51062bcbf6b21de..4af10617de3389040f28a24dac6875ce933e359a 100644 (file)
@@ -697,7 +697,7 @@ static const int snb_lbr_sel_map[PERF_SAMPLE_BRANCH_MAX] = {
 };
 
 /* core */
-void intel_pmu_lbr_init_core(void)
+void __init intel_pmu_lbr_init_core(void)
 {
        x86_pmu.lbr_nr     = 4;
        x86_pmu.lbr_tos    = MSR_LBR_TOS;
@@ -712,7 +712,7 @@ void intel_pmu_lbr_init_core(void)
 }
 
 /* nehalem/westmere */
-void intel_pmu_lbr_init_nhm(void)
+void __init intel_pmu_lbr_init_nhm(void)
 {
        x86_pmu.lbr_nr     = 16;
        x86_pmu.lbr_tos    = MSR_LBR_TOS;
@@ -733,7 +733,7 @@ void intel_pmu_lbr_init_nhm(void)
 }
 
 /* sandy bridge */
-void intel_pmu_lbr_init_snb(void)
+void __init intel_pmu_lbr_init_snb(void)
 {
        x86_pmu.lbr_nr   = 16;
        x86_pmu.lbr_tos  = MSR_LBR_TOS;
@@ -753,7 +753,7 @@ void intel_pmu_lbr_init_snb(void)
 }
 
 /* atom */
-void intel_pmu_lbr_init_atom(void)
+void __init intel_pmu_lbr_init_atom(void)
 {
        /*
         * only models starting at stepping 10 seems
index 0939f86f543d04ceb9a4bcb81f0a60775e078ee3..9762dbd9f3f7d7a4e11f040aa19b21e31fe62667 100644 (file)
 #include "perf_event_intel_uncore.h"
 
 static struct intel_uncore_type *empty_uncore[] = { NULL, };
-static struct intel_uncore_type **msr_uncores = empty_uncore;
-static struct intel_uncore_type **pci_uncores = empty_uncore;
-/* pci bus to socket mapping */
-static int pcibus_to_physid[256] = { [0 ... 255] = -1, };
-
-static struct pci_dev *extra_pci_dev[UNCORE_SOCKET_MAX][UNCORE_EXTRA_PCI_DEV_MAX];
-
-static DEFINE_RAW_SPINLOCK(uncore_box_lock);
-
-/* mask of cpus that collect uncore events */
-static cpumask_t uncore_cpu_mask;
-
-/* constraint for the fixed counter */
-static struct event_constraint constraint_fixed =
-       EVENT_CONSTRAINT(~0ULL, 1 << UNCORE_PMC_IDX_FIXED, ~0ULL);
-static struct event_constraint constraint_empty =
-       EVENT_CONSTRAINT(0, 0, 0);
-
-#define __BITS_VALUE(x, i, n)  ((typeof(x))(((x) >> ((i) * (n))) & \
-                               ((1ULL << (n)) - 1)))
-
-DEFINE_UNCORE_FORMAT_ATTR(event, event, "config:0-7");
-DEFINE_UNCORE_FORMAT_ATTR(event_ext, event, "config:0-7,21");
-DEFINE_UNCORE_FORMAT_ATTR(umask, umask, "config:8-15");
-DEFINE_UNCORE_FORMAT_ATTR(edge, edge, "config:18");
-DEFINE_UNCORE_FORMAT_ATTR(tid_en, tid_en, "config:19");
-DEFINE_UNCORE_FORMAT_ATTR(inv, inv, "config:23");
-DEFINE_UNCORE_FORMAT_ATTR(cmask5, cmask, "config:24-28");
-DEFINE_UNCORE_FORMAT_ATTR(cmask8, cmask, "config:24-31");
-DEFINE_UNCORE_FORMAT_ATTR(thresh8, thresh, "config:24-31");
-DEFINE_UNCORE_FORMAT_ATTR(thresh5, thresh, "config:24-28");
-DEFINE_UNCORE_FORMAT_ATTR(occ_sel, occ_sel, "config:14-15");
-DEFINE_UNCORE_FORMAT_ATTR(occ_invert, occ_invert, "config:30");
-DEFINE_UNCORE_FORMAT_ATTR(occ_edge, occ_edge, "config:14-51");
-DEFINE_UNCORE_FORMAT_ATTR(filter_tid, filter_tid, "config1:0-4");
-DEFINE_UNCORE_FORMAT_ATTR(filter_link, filter_link, "config1:5-8");
-DEFINE_UNCORE_FORMAT_ATTR(filter_nid, filter_nid, "config1:10-17");
-DEFINE_UNCORE_FORMAT_ATTR(filter_nid2, filter_nid, "config1:32-47");
-DEFINE_UNCORE_FORMAT_ATTR(filter_state, filter_state, "config1:18-22");
-DEFINE_UNCORE_FORMAT_ATTR(filter_state2, filter_state, "config1:17-22");
-DEFINE_UNCORE_FORMAT_ATTR(filter_opc, filter_opc, "config1:23-31");
-DEFINE_UNCORE_FORMAT_ATTR(filter_opc2, filter_opc, "config1:52-60");
-DEFINE_UNCORE_FORMAT_ATTR(filter_band0, filter_band0, "config1:0-7");
-DEFINE_UNCORE_FORMAT_ATTR(filter_band1, filter_band1, "config1:8-15");
-DEFINE_UNCORE_FORMAT_ATTR(filter_band2, filter_band2, "config1:16-23");
-DEFINE_UNCORE_FORMAT_ATTR(filter_band3, filter_band3, "config1:24-31");
-DEFINE_UNCORE_FORMAT_ATTR(match_rds, match_rds, "config1:48-51");
-DEFINE_UNCORE_FORMAT_ATTR(match_rnid30, match_rnid30, "config1:32-35");
-DEFINE_UNCORE_FORMAT_ATTR(match_rnid4, match_rnid4, "config1:31");
-DEFINE_UNCORE_FORMAT_ATTR(match_dnid, match_dnid, "config1:13-17");
-DEFINE_UNCORE_FORMAT_ATTR(match_mc, match_mc, "config1:9-12");
-DEFINE_UNCORE_FORMAT_ATTR(match_opc, match_opc, "config1:5-8");
-DEFINE_UNCORE_FORMAT_ATTR(match_vnw, match_vnw, "config1:3-4");
-DEFINE_UNCORE_FORMAT_ATTR(match0, match0, "config1:0-31");
-DEFINE_UNCORE_FORMAT_ATTR(match1, match1, "config1:32-63");
-DEFINE_UNCORE_FORMAT_ATTR(mask_rds, mask_rds, "config2:48-51");
-DEFINE_UNCORE_FORMAT_ATTR(mask_rnid30, mask_rnid30, "config2:32-35");
-DEFINE_UNCORE_FORMAT_ATTR(mask_rnid4, mask_rnid4, "config2:31");
-DEFINE_UNCORE_FORMAT_ATTR(mask_dnid, mask_dnid, "config2:13-17");
-DEFINE_UNCORE_FORMAT_ATTR(mask_mc, mask_mc, "config2:9-12");
-DEFINE_UNCORE_FORMAT_ATTR(mask_opc, mask_opc, "config2:5-8");
-DEFINE_UNCORE_FORMAT_ATTR(mask_vnw, mask_vnw, "config2:3-4");
-DEFINE_UNCORE_FORMAT_ATTR(mask0, mask0, "config2:0-31");
-DEFINE_UNCORE_FORMAT_ATTR(mask1, mask1, "config2:32-63");
-
-static void uncore_pmu_start_hrtimer(struct intel_uncore_box *box);
-static void uncore_pmu_cancel_hrtimer(struct intel_uncore_box *box);
-static void uncore_perf_event_update(struct intel_uncore_box *box, struct perf_event *event);
-static void uncore_pmu_event_read(struct perf_event *event);
-
-static struct intel_uncore_pmu *uncore_event_to_pmu(struct perf_event *event)
-{
-       return container_of(event->pmu, struct intel_uncore_pmu, pmu);
-}
-
-static struct intel_uncore_box *
-uncore_pmu_to_box(struct intel_uncore_pmu *pmu, int cpu)
-{
-       struct intel_uncore_box *box;
-
-       box = *per_cpu_ptr(pmu->box, cpu);
-       if (box)
-               return box;
-
-       raw_spin_lock(&uncore_box_lock);
-       list_for_each_entry(box, &pmu->box_list, list) {
-               if (box->phys_id == topology_physical_package_id(cpu)) {
-                       atomic_inc(&box->refcnt);
-                       *per_cpu_ptr(pmu->box, cpu) = box;
-                       break;
-               }
-       }
-       raw_spin_unlock(&uncore_box_lock);
-
-       return *per_cpu_ptr(pmu->box, cpu);
-}
-
-static struct intel_uncore_box *uncore_event_to_box(struct perf_event *event)
-{
-       /*
-        * perf core schedules event on the basis of cpu, uncore events are
-        * collected by one of the cpus inside a physical package.
-        */
-       return uncore_pmu_to_box(uncore_event_to_pmu(event), smp_processor_id());
-}
-
-static u64 uncore_msr_read_counter(struct intel_uncore_box *box, struct perf_event *event)
-{
-       u64 count;
-
-       rdmsrl(event->hw.event_base, count);
-
-       return count;
-}
-
-/*
- * generic get constraint function for shared match/mask registers.
- */
-static struct event_constraint *
-uncore_get_constraint(struct intel_uncore_box *box, struct perf_event *event)
-{
-       struct intel_uncore_extra_reg *er;
-       struct hw_perf_event_extra *reg1 = &event->hw.extra_reg;
-       struct hw_perf_event_extra *reg2 = &event->hw.branch_reg;
-       unsigned long flags;
-       bool ok = false;
-
-       /*
-        * reg->alloc can be set due to existing state, so for fake box we
-        * need to ignore this, otherwise we might fail to allocate proper
-        * fake state for this extra reg constraint.
-        */
-       if (reg1->idx == EXTRA_REG_NONE ||
-           (!uncore_box_is_fake(box) && reg1->alloc))
-               return NULL;
-
-       er = &box->shared_regs[reg1->idx];
-       raw_spin_lock_irqsave(&er->lock, flags);
-       if (!atomic_read(&er->ref) ||
-           (er->config1 == reg1->config && er->config2 == reg2->config)) {
-               atomic_inc(&er->ref);
-               er->config1 = reg1->config;
-               er->config2 = reg2->config;
-               ok = true;
-       }
-       raw_spin_unlock_irqrestore(&er->lock, flags);
-
-       if (ok) {
-               if (!uncore_box_is_fake(box))
-                       reg1->alloc = 1;
-               return NULL;
-       }
-
-       return &constraint_empty;
-}
-
-static void uncore_put_constraint(struct intel_uncore_box *box, struct perf_event *event)
-{
-       struct intel_uncore_extra_reg *er;
-       struct hw_perf_event_extra *reg1 = &event->hw.extra_reg;
-
-       /*
-        * Only put constraint if extra reg was actually allocated. Also
-        * takes care of event which do not use an extra shared reg.
-        *
-        * Also, if this is a fake box we shouldn't touch any event state
-        * (reg->alloc) and we don't care about leaving inconsistent box
-        * state either since it will be thrown out.
-        */
-       if (uncore_box_is_fake(box) || !reg1->alloc)
-               return;
-
-       er = &box->shared_regs[reg1->idx];
-       atomic_dec(&er->ref);
-       reg1->alloc = 0;
-}
-
-static u64 uncore_shared_reg_config(struct intel_uncore_box *box, int idx)
-{
-       struct intel_uncore_extra_reg *er;
-       unsigned long flags;
-       u64 config;
-
-       er = &box->shared_regs[idx];
-
-       raw_spin_lock_irqsave(&er->lock, flags);
-       config = er->config;
-       raw_spin_unlock_irqrestore(&er->lock, flags);
-
-       return config;
-}
-
-/* Sandy Bridge-EP uncore support */
-static struct intel_uncore_type snbep_uncore_cbox;
-static struct intel_uncore_type snbep_uncore_pcu;
-
-static void snbep_uncore_pci_disable_box(struct intel_uncore_box *box)
-{
-       struct pci_dev *pdev = box->pci_dev;
-       int box_ctl = uncore_pci_box_ctl(box);
-       u32 config = 0;
-
-       if (!pci_read_config_dword(pdev, box_ctl, &config)) {
-               config |= SNBEP_PMON_BOX_CTL_FRZ;
-               pci_write_config_dword(pdev, box_ctl, config);
-       }
-}
-
-static void snbep_uncore_pci_enable_box(struct intel_uncore_box *box)
-{
-       struct pci_dev *pdev = box->pci_dev;
-       int box_ctl = uncore_pci_box_ctl(box);
-       u32 config = 0;
-
-       if (!pci_read_config_dword(pdev, box_ctl, &config)) {
-               config &= ~SNBEP_PMON_BOX_CTL_FRZ;
-               pci_write_config_dword(pdev, box_ctl, config);
-       }
-}
-
-static void snbep_uncore_pci_enable_event(struct intel_uncore_box *box, struct perf_event *event)
-{
-       struct pci_dev *pdev = box->pci_dev;
-       struct hw_perf_event *hwc = &event->hw;
-
-       pci_write_config_dword(pdev, hwc->config_base, hwc->config | SNBEP_PMON_CTL_EN);
-}
-
-static void snbep_uncore_pci_disable_event(struct intel_uncore_box *box, struct perf_event *event)
-{
-       struct pci_dev *pdev = box->pci_dev;
-       struct hw_perf_event *hwc = &event->hw;
-
-       pci_write_config_dword(pdev, hwc->config_base, hwc->config);
-}
-
-static u64 snbep_uncore_pci_read_counter(struct intel_uncore_box *box, struct perf_event *event)
-{
-       struct pci_dev *pdev = box->pci_dev;
-       struct hw_perf_event *hwc = &event->hw;
-       u64 count = 0;
-
-       pci_read_config_dword(pdev, hwc->event_base, (u32 *)&count);
-       pci_read_config_dword(pdev, hwc->event_base + 4, (u32 *)&count + 1);
-
-       return count;
-}
-
-static void snbep_uncore_pci_init_box(struct intel_uncore_box *box)
-{
-       struct pci_dev *pdev = box->pci_dev;
-
-       pci_write_config_dword(pdev, SNBEP_PCI_PMON_BOX_CTL, SNBEP_PMON_BOX_CTL_INT);
-}
-
-static void snbep_uncore_msr_disable_box(struct intel_uncore_box *box)
-{
-       u64 config;
-       unsigned msr;
-
-       msr = uncore_msr_box_ctl(box);
-       if (msr) {
-               rdmsrl(msr, config);
-               config |= SNBEP_PMON_BOX_CTL_FRZ;
-               wrmsrl(msr, config);
-       }
-}
-
-static void snbep_uncore_msr_enable_box(struct intel_uncore_box *box)
-{
-       u64 config;
-       unsigned msr;
-
-       msr = uncore_msr_box_ctl(box);
-       if (msr) {
-               rdmsrl(msr, config);
-               config &= ~SNBEP_PMON_BOX_CTL_FRZ;
-               wrmsrl(msr, config);
-       }
-}
-
-static void snbep_uncore_msr_enable_event(struct intel_uncore_box *box, struct perf_event *event)
-{
-       struct hw_perf_event *hwc = &event->hw;
-       struct hw_perf_event_extra *reg1 = &hwc->extra_reg;
-
-       if (reg1->idx != EXTRA_REG_NONE)
-               wrmsrl(reg1->reg, uncore_shared_reg_config(box, 0));
-
-       wrmsrl(hwc->config_base, hwc->config | SNBEP_PMON_CTL_EN);
-}
-
-static void snbep_uncore_msr_disable_event(struct intel_uncore_box *box,
-                                       struct perf_event *event)
-{
-       struct hw_perf_event *hwc = &event->hw;
-
-       wrmsrl(hwc->config_base, hwc->config);
-}
-
-static void snbep_uncore_msr_init_box(struct intel_uncore_box *box)
-{
-       unsigned msr = uncore_msr_box_ctl(box);
-
-       if (msr)
-               wrmsrl(msr, SNBEP_PMON_BOX_CTL_INT);
-}
-
-static struct attribute *snbep_uncore_formats_attr[] = {
-       &format_attr_event.attr,
-       &format_attr_umask.attr,
-       &format_attr_edge.attr,
-       &format_attr_inv.attr,
-       &format_attr_thresh8.attr,
-       NULL,
-};
-
-static struct attribute *snbep_uncore_ubox_formats_attr[] = {
-       &format_attr_event.attr,
-       &format_attr_umask.attr,
-       &format_attr_edge.attr,
-       &format_attr_inv.attr,
-       &format_attr_thresh5.attr,
-       NULL,
-};
-
-static struct attribute *snbep_uncore_cbox_formats_attr[] = {
-       &format_attr_event.attr,
-       &format_attr_umask.attr,
-       &format_attr_edge.attr,
-       &format_attr_tid_en.attr,
-       &format_attr_inv.attr,
-       &format_attr_thresh8.attr,
-       &format_attr_filter_tid.attr,
-       &format_attr_filter_nid.attr,
-       &format_attr_filter_state.attr,
-       &format_attr_filter_opc.attr,
-       NULL,
-};
-
-static struct attribute *snbep_uncore_pcu_formats_attr[] = {
-       &format_attr_event_ext.attr,
-       &format_attr_occ_sel.attr,
-       &format_attr_edge.attr,
-       &format_attr_inv.attr,
-       &format_attr_thresh5.attr,
-       &format_attr_occ_invert.attr,
-       &format_attr_occ_edge.attr,
-       &format_attr_filter_band0.attr,
-       &format_attr_filter_band1.attr,
-       &format_attr_filter_band2.attr,
-       &format_attr_filter_band3.attr,
-       NULL,
-};
-
-static struct attribute *snbep_uncore_qpi_formats_attr[] = {
-       &format_attr_event_ext.attr,
-       &format_attr_umask.attr,
-       &format_attr_edge.attr,
-       &format_attr_inv.attr,
-       &format_attr_thresh8.attr,
-       &format_attr_match_rds.attr,
-       &format_attr_match_rnid30.attr,
-       &format_attr_match_rnid4.attr,
-       &format_attr_match_dnid.attr,
-       &format_attr_match_mc.attr,
-       &format_attr_match_opc.attr,
-       &format_attr_match_vnw.attr,
-       &format_attr_match0.attr,
-       &format_attr_match1.attr,
-       &format_attr_mask_rds.attr,
-       &format_attr_mask_rnid30.attr,
-       &format_attr_mask_rnid4.attr,
-       &format_attr_mask_dnid.attr,
-       &format_attr_mask_mc.attr,
-       &format_attr_mask_opc.attr,
-       &format_attr_mask_vnw.attr,
-       &format_attr_mask0.attr,
-       &format_attr_mask1.attr,
-       NULL,
-};
-
-static struct uncore_event_desc snbep_uncore_imc_events[] = {
-       INTEL_UNCORE_EVENT_DESC(clockticks,      "event=0xff,umask=0x00"),
-       INTEL_UNCORE_EVENT_DESC(cas_count_read,  "event=0x04,umask=0x03"),
-       INTEL_UNCORE_EVENT_DESC(cas_count_write, "event=0x04,umask=0x0c"),
-       { /* end: all zeroes */ },
-};
-
-static struct uncore_event_desc snbep_uncore_qpi_events[] = {
-       INTEL_UNCORE_EVENT_DESC(clockticks,       "event=0x14"),
-       INTEL_UNCORE_EVENT_DESC(txl_flits_active, "event=0x00,umask=0x06"),
-       INTEL_UNCORE_EVENT_DESC(drs_data,         "event=0x102,umask=0x08"),
-       INTEL_UNCORE_EVENT_DESC(ncb_data,         "event=0x103,umask=0x04"),
-       { /* end: all zeroes */ },
-};
-
-static struct attribute_group snbep_uncore_format_group = {
-       .name = "format",
-       .attrs = snbep_uncore_formats_attr,
-};
-
-static struct attribute_group snbep_uncore_ubox_format_group = {
-       .name = "format",
-       .attrs = snbep_uncore_ubox_formats_attr,
-};
-
-static struct attribute_group snbep_uncore_cbox_format_group = {
-       .name = "format",
-       .attrs = snbep_uncore_cbox_formats_attr,
-};
-
-static struct attribute_group snbep_uncore_pcu_format_group = {
-       .name = "format",
-       .attrs = snbep_uncore_pcu_formats_attr,
-};
-
-static struct attribute_group snbep_uncore_qpi_format_group = {
-       .name = "format",
-       .attrs = snbep_uncore_qpi_formats_attr,
-};
-
-#define SNBEP_UNCORE_MSR_OPS_COMMON_INIT()                     \
-       .init_box       = snbep_uncore_msr_init_box,            \
-       .disable_box    = snbep_uncore_msr_disable_box,         \
-       .enable_box     = snbep_uncore_msr_enable_box,          \
-       .disable_event  = snbep_uncore_msr_disable_event,       \
-       .enable_event   = snbep_uncore_msr_enable_event,        \
-       .read_counter   = uncore_msr_read_counter
-
-static struct intel_uncore_ops snbep_uncore_msr_ops = {
-       SNBEP_UNCORE_MSR_OPS_COMMON_INIT(),
-};
-
-#define SNBEP_UNCORE_PCI_OPS_COMMON_INIT()                     \
-       .init_box       = snbep_uncore_pci_init_box,            \
-       .disable_box    = snbep_uncore_pci_disable_box,         \
-       .enable_box     = snbep_uncore_pci_enable_box,          \
-       .disable_event  = snbep_uncore_pci_disable_event,       \
-       .read_counter   = snbep_uncore_pci_read_counter
-
-static struct intel_uncore_ops snbep_uncore_pci_ops = {
-       SNBEP_UNCORE_PCI_OPS_COMMON_INIT(),
-       .enable_event   = snbep_uncore_pci_enable_event,        \
-};
-
-static struct event_constraint snbep_uncore_cbox_constraints[] = {
-       UNCORE_EVENT_CONSTRAINT(0x01, 0x1),
-       UNCORE_EVENT_CONSTRAINT(0x02, 0x3),
-       UNCORE_EVENT_CONSTRAINT(0x04, 0x3),
-       UNCORE_EVENT_CONSTRAINT(0x05, 0x3),
-       UNCORE_EVENT_CONSTRAINT(0x07, 0x3),
-       UNCORE_EVENT_CONSTRAINT(0x09, 0x3),
-       UNCORE_EVENT_CONSTRAINT(0x11, 0x1),
-       UNCORE_EVENT_CONSTRAINT(0x12, 0x3),
-       UNCORE_EVENT_CONSTRAINT(0x13, 0x3),
-       UNCORE_EVENT_CONSTRAINT(0x1b, 0xc),
-       UNCORE_EVENT_CONSTRAINT(0x1c, 0xc),
-       UNCORE_EVENT_CONSTRAINT(0x1d, 0xc),
-       UNCORE_EVENT_CONSTRAINT(0x1e, 0xc),
-       EVENT_CONSTRAINT_OVERLAP(0x1f, 0xe, 0xff),
-       UNCORE_EVENT_CONSTRAINT(0x21, 0x3),
-       UNCORE_EVENT_CONSTRAINT(0x23, 0x3),
-       UNCORE_EVENT_CONSTRAINT(0x31, 0x3),
-       UNCORE_EVENT_CONSTRAINT(0x32, 0x3),
-       UNCORE_EVENT_CONSTRAINT(0x33, 0x3),
-       UNCORE_EVENT_CONSTRAINT(0x34, 0x3),
-       UNCORE_EVENT_CONSTRAINT(0x35, 0x3),
-       UNCORE_EVENT_CONSTRAINT(0x36, 0x1),
-       UNCORE_EVENT_CONSTRAINT(0x37, 0x3),
-       UNCORE_EVENT_CONSTRAINT(0x38, 0x3),
-       UNCORE_EVENT_CONSTRAINT(0x39, 0x3),
-       UNCORE_EVENT_CONSTRAINT(0x3b, 0x1),
-       EVENT_CONSTRAINT_END
-};
-
-static struct event_constraint snbep_uncore_r2pcie_constraints[] = {
-       UNCORE_EVENT_CONSTRAINT(0x10, 0x3),
-       UNCORE_EVENT_CONSTRAINT(0x11, 0x3),
-       UNCORE_EVENT_CONSTRAINT(0x12, 0x1),
-       UNCORE_EVENT_CONSTRAINT(0x23, 0x3),
-       UNCORE_EVENT_CONSTRAINT(0x24, 0x3),
-       UNCORE_EVENT_CONSTRAINT(0x25, 0x3),
-       UNCORE_EVENT_CONSTRAINT(0x26, 0x3),
-       UNCORE_EVENT_CONSTRAINT(0x32, 0x3),
-       UNCORE_EVENT_CONSTRAINT(0x33, 0x3),
-       UNCORE_EVENT_CONSTRAINT(0x34, 0x3),
-       EVENT_CONSTRAINT_END
-};
-
-static struct event_constraint snbep_uncore_r3qpi_constraints[] = {
-       UNCORE_EVENT_CONSTRAINT(0x10, 0x3),
-       UNCORE_EVENT_CONSTRAINT(0x11, 0x3),
-       UNCORE_EVENT_CONSTRAINT(0x12, 0x3),
-       UNCORE_EVENT_CONSTRAINT(0x13, 0x1),
-       UNCORE_EVENT_CONSTRAINT(0x20, 0x3),
-       UNCORE_EVENT_CONSTRAINT(0x21, 0x3),
-       UNCORE_EVENT_CONSTRAINT(0x22, 0x3),
-       UNCORE_EVENT_CONSTRAINT(0x23, 0x3),
-       UNCORE_EVENT_CONSTRAINT(0x24, 0x3),
-       UNCORE_EVENT_CONSTRAINT(0x25, 0x3),
-       UNCORE_EVENT_CONSTRAINT(0x26, 0x3),
-       UNCORE_EVENT_CONSTRAINT(0x28, 0x3),
-       UNCORE_EVENT_CONSTRAINT(0x29, 0x3),
-       UNCORE_EVENT_CONSTRAINT(0x2a, 0x3),
-       UNCORE_EVENT_CONSTRAINT(0x2b, 0x3),
-       UNCORE_EVENT_CONSTRAINT(0x2c, 0x3),
-       UNCORE_EVENT_CONSTRAINT(0x2d, 0x3),
-       UNCORE_EVENT_CONSTRAINT(0x2e, 0x3),
-       UNCORE_EVENT_CONSTRAINT(0x2f, 0x3),
-       UNCORE_EVENT_CONSTRAINT(0x30, 0x3),
-       UNCORE_EVENT_CONSTRAINT(0x31, 0x3),
-       UNCORE_EVENT_CONSTRAINT(0x32, 0x3),
-       UNCORE_EVENT_CONSTRAINT(0x33, 0x3),
-       UNCORE_EVENT_CONSTRAINT(0x34, 0x3),
-       UNCORE_EVENT_CONSTRAINT(0x36, 0x3),
-       UNCORE_EVENT_CONSTRAINT(0x37, 0x3),
-       UNCORE_EVENT_CONSTRAINT(0x38, 0x3),
-       UNCORE_EVENT_CONSTRAINT(0x39, 0x3),
-       EVENT_CONSTRAINT_END
-};
-
-static struct intel_uncore_type snbep_uncore_ubox = {
-       .name           = "ubox",
-       .num_counters   = 2,
-       .num_boxes      = 1,
-       .perf_ctr_bits  = 44,
-       .fixed_ctr_bits = 48,
-       .perf_ctr       = SNBEP_U_MSR_PMON_CTR0,
-       .event_ctl      = SNBEP_U_MSR_PMON_CTL0,
-       .event_mask     = SNBEP_U_MSR_PMON_RAW_EVENT_MASK,
-       .fixed_ctr      = SNBEP_U_MSR_PMON_UCLK_FIXED_CTR,
-       .fixed_ctl      = SNBEP_U_MSR_PMON_UCLK_FIXED_CTL,
-       .ops            = &snbep_uncore_msr_ops,
-       .format_group   = &snbep_uncore_ubox_format_group,
-};
-
-static struct extra_reg snbep_uncore_cbox_extra_regs[] = {
-       SNBEP_CBO_EVENT_EXTRA_REG(SNBEP_CBO_PMON_CTL_TID_EN,
-                                 SNBEP_CBO_PMON_CTL_TID_EN, 0x1),
-       SNBEP_CBO_EVENT_EXTRA_REG(0x0334, 0xffff, 0x4),
-       SNBEP_CBO_EVENT_EXTRA_REG(0x4334, 0xffff, 0x6),
-       SNBEP_CBO_EVENT_EXTRA_REG(0x0534, 0xffff, 0x4),
-       SNBEP_CBO_EVENT_EXTRA_REG(0x4534, 0xffff, 0x6),
-       SNBEP_CBO_EVENT_EXTRA_REG(0x0934, 0xffff, 0x4),
-       SNBEP_CBO_EVENT_EXTRA_REG(0x4934, 0xffff, 0x6),
-       SNBEP_CBO_EVENT_EXTRA_REG(0x4134, 0xffff, 0x6),
-       SNBEP_CBO_EVENT_EXTRA_REG(0x0135, 0xffff, 0x8),
-       SNBEP_CBO_EVENT_EXTRA_REG(0x0335, 0xffff, 0x8),
-       SNBEP_CBO_EVENT_EXTRA_REG(0x4135, 0xffff, 0xa),
-       SNBEP_CBO_EVENT_EXTRA_REG(0x4335, 0xffff, 0xa),
-       SNBEP_CBO_EVENT_EXTRA_REG(0x4435, 0xffff, 0x2),
-       SNBEP_CBO_EVENT_EXTRA_REG(0x4835, 0xffff, 0x2),
-       SNBEP_CBO_EVENT_EXTRA_REG(0x4a35, 0xffff, 0x2),
-       SNBEP_CBO_EVENT_EXTRA_REG(0x5035, 0xffff, 0x2),
-       SNBEP_CBO_EVENT_EXTRA_REG(0x0136, 0xffff, 0x8),
-       SNBEP_CBO_EVENT_EXTRA_REG(0x0336, 0xffff, 0x8),
-       SNBEP_CBO_EVENT_EXTRA_REG(0x4136, 0xffff, 0xa),
-       SNBEP_CBO_EVENT_EXTRA_REG(0x4336, 0xffff, 0xa),
-       SNBEP_CBO_EVENT_EXTRA_REG(0x4436, 0xffff, 0x2),
-       SNBEP_CBO_EVENT_EXTRA_REG(0x4836, 0xffff, 0x2),
-       SNBEP_CBO_EVENT_EXTRA_REG(0x4a36, 0xffff, 0x2),
-       SNBEP_CBO_EVENT_EXTRA_REG(0x4037, 0x40ff, 0x2),
-       EVENT_EXTRA_END
-};
-
-static void snbep_cbox_put_constraint(struct intel_uncore_box *box, struct perf_event *event)
-{
-       struct hw_perf_event_extra *reg1 = &event->hw.extra_reg;
-       struct intel_uncore_extra_reg *er = &box->shared_regs[0];
-       int i;
-
-       if (uncore_box_is_fake(box))
-               return;
-
-       for (i = 0; i < 5; i++) {
-               if (reg1->alloc & (0x1 << i))
-                       atomic_sub(1 << (i * 6), &er->ref);
-       }
-       reg1->alloc = 0;
-}
-
-static struct event_constraint *
-__snbep_cbox_get_constraint(struct intel_uncore_box *box, struct perf_event *event,
-                           u64 (*cbox_filter_mask)(int fields))
-{
-       struct hw_perf_event_extra *reg1 = &event->hw.extra_reg;
-       struct intel_uncore_extra_reg *er = &box->shared_regs[0];
-       int i, alloc = 0;
-       unsigned long flags;
-       u64 mask;
-
-       if (reg1->idx == EXTRA_REG_NONE)
-               return NULL;
-
-       raw_spin_lock_irqsave(&er->lock, flags);
-       for (i = 0; i < 5; i++) {
-               if (!(reg1->idx & (0x1 << i)))
-                       continue;
-               if (!uncore_box_is_fake(box) && (reg1->alloc & (0x1 << i)))
-                       continue;
-
-               mask = cbox_filter_mask(0x1 << i);
-               if (!__BITS_VALUE(atomic_read(&er->ref), i, 6) ||
-                   !((reg1->config ^ er->config) & mask)) {
-                       atomic_add(1 << (i * 6), &er->ref);
-                       er->config &= ~mask;
-                       er->config |= reg1->config & mask;
-                       alloc |= (0x1 << i);
-               } else {
-                       break;
-               }
-       }
-       raw_spin_unlock_irqrestore(&er->lock, flags);
-       if (i < 5)
-               goto fail;
-
-       if (!uncore_box_is_fake(box))
-               reg1->alloc |= alloc;
-
-       return NULL;
-fail:
-       for (; i >= 0; i--) {
-               if (alloc & (0x1 << i))
-                       atomic_sub(1 << (i * 6), &er->ref);
-       }
-       return &constraint_empty;
-}
-
-static u64 snbep_cbox_filter_mask(int fields)
-{
-       u64 mask = 0;
-
-       if (fields & 0x1)
-               mask |= SNBEP_CB0_MSR_PMON_BOX_FILTER_TID;
-       if (fields & 0x2)
-               mask |= SNBEP_CB0_MSR_PMON_BOX_FILTER_NID;
-       if (fields & 0x4)
-               mask |= SNBEP_CB0_MSR_PMON_BOX_FILTER_STATE;
-       if (fields & 0x8)
-               mask |= SNBEP_CB0_MSR_PMON_BOX_FILTER_OPC;
-
-       return mask;
-}
-
-static struct event_constraint *
-snbep_cbox_get_constraint(struct intel_uncore_box *box, struct perf_event *event)
-{
-       return __snbep_cbox_get_constraint(box, event, snbep_cbox_filter_mask);
-}
-
-static int snbep_cbox_hw_config(struct intel_uncore_box *box, struct perf_event *event)
-{
-       struct hw_perf_event_extra *reg1 = &event->hw.extra_reg;
-       struct extra_reg *er;
-       int idx = 0;
-
-       for (er = snbep_uncore_cbox_extra_regs; er->msr; er++) {
-               if (er->event != (event->hw.config & er->config_mask))
-                       continue;
-               idx |= er->idx;
-       }
-
-       if (idx) {
-               reg1->reg = SNBEP_C0_MSR_PMON_BOX_FILTER +
-                       SNBEP_CBO_MSR_OFFSET * box->pmu->pmu_idx;
-               reg1->config = event->attr.config1 & snbep_cbox_filter_mask(idx);
-               reg1->idx = idx;
-       }
-       return 0;
-}
-
-static struct intel_uncore_ops snbep_uncore_cbox_ops = {
-       SNBEP_UNCORE_MSR_OPS_COMMON_INIT(),
-       .hw_config              = snbep_cbox_hw_config,
-       .get_constraint         = snbep_cbox_get_constraint,
-       .put_constraint         = snbep_cbox_put_constraint,
-};
-
-static struct intel_uncore_type snbep_uncore_cbox = {
-       .name                   = "cbox",
-       .num_counters           = 4,
-       .num_boxes              = 8,
-       .perf_ctr_bits          = 44,
-       .event_ctl              = SNBEP_C0_MSR_PMON_CTL0,
-       .perf_ctr               = SNBEP_C0_MSR_PMON_CTR0,
-       .event_mask             = SNBEP_CBO_MSR_PMON_RAW_EVENT_MASK,
-       .box_ctl                = SNBEP_C0_MSR_PMON_BOX_CTL,
-       .msr_offset             = SNBEP_CBO_MSR_OFFSET,
-       .num_shared_regs        = 1,
-       .constraints            = snbep_uncore_cbox_constraints,
-       .ops                    = &snbep_uncore_cbox_ops,
-       .format_group           = &snbep_uncore_cbox_format_group,
-};
-
-static u64 snbep_pcu_alter_er(struct perf_event *event, int new_idx, bool modify)
-{
-       struct hw_perf_event *hwc = &event->hw;
-       struct hw_perf_event_extra *reg1 = &hwc->extra_reg;
-       u64 config = reg1->config;
-
-       if (new_idx > reg1->idx)
-               config <<= 8 * (new_idx - reg1->idx);
-       else
-               config >>= 8 * (reg1->idx - new_idx);
-
-       if (modify) {
-               hwc->config += new_idx - reg1->idx;
-               reg1->config = config;
-               reg1->idx = new_idx;
-       }
-       return config;
-}
-
-static struct event_constraint *
-snbep_pcu_get_constraint(struct intel_uncore_box *box, struct perf_event *event)
-{
-       struct hw_perf_event_extra *reg1 = &event->hw.extra_reg;
-       struct intel_uncore_extra_reg *er = &box->shared_regs[0];
-       unsigned long flags;
-       int idx = reg1->idx;
-       u64 mask, config1 = reg1->config;
-       bool ok = false;
-
-       if (reg1->idx == EXTRA_REG_NONE ||
-           (!uncore_box_is_fake(box) && reg1->alloc))
-               return NULL;
-again:
-       mask = 0xffULL << (idx * 8);
-       raw_spin_lock_irqsave(&er->lock, flags);
-       if (!__BITS_VALUE(atomic_read(&er->ref), idx, 8) ||
-           !((config1 ^ er->config) & mask)) {
-               atomic_add(1 << (idx * 8), &er->ref);
-               er->config &= ~mask;
-               er->config |= config1 & mask;
-               ok = true;
-       }
-       raw_spin_unlock_irqrestore(&er->lock, flags);
-
-       if (!ok) {
-               idx = (idx + 1) % 4;
-               if (idx != reg1->idx) {
-                       config1 = snbep_pcu_alter_er(event, idx, false);
-                       goto again;
-               }
-               return &constraint_empty;
-       }
-
-       if (!uncore_box_is_fake(box)) {
-               if (idx != reg1->idx)
-                       snbep_pcu_alter_er(event, idx, true);
-               reg1->alloc = 1;
-       }
-       return NULL;
-}
-
-static void snbep_pcu_put_constraint(struct intel_uncore_box *box, struct perf_event *event)
-{
-       struct hw_perf_event_extra *reg1 = &event->hw.extra_reg;
-       struct intel_uncore_extra_reg *er = &box->shared_regs[0];
-
-       if (uncore_box_is_fake(box) || !reg1->alloc)
-               return;
-
-       atomic_sub(1 << (reg1->idx * 8), &er->ref);
-       reg1->alloc = 0;
-}
-
-static int snbep_pcu_hw_config(struct intel_uncore_box *box, struct perf_event *event)
-{
-       struct hw_perf_event *hwc = &event->hw;
-       struct hw_perf_event_extra *reg1 = &hwc->extra_reg;
-       int ev_sel = hwc->config & SNBEP_PMON_CTL_EV_SEL_MASK;
-
-       if (ev_sel >= 0xb && ev_sel <= 0xe) {
-               reg1->reg = SNBEP_PCU_MSR_PMON_BOX_FILTER;
-               reg1->idx = ev_sel - 0xb;
-               reg1->config = event->attr.config1 & (0xff << reg1->idx);
-       }
-       return 0;
-}
-
-static struct intel_uncore_ops snbep_uncore_pcu_ops = {
-       SNBEP_UNCORE_MSR_OPS_COMMON_INIT(),
-       .hw_config              = snbep_pcu_hw_config,
-       .get_constraint         = snbep_pcu_get_constraint,
-       .put_constraint         = snbep_pcu_put_constraint,
-};
-
-static struct intel_uncore_type snbep_uncore_pcu = {
-       .name                   = "pcu",
-       .num_counters           = 4,
-       .num_boxes              = 1,
-       .perf_ctr_bits          = 48,
-       .perf_ctr               = SNBEP_PCU_MSR_PMON_CTR0,
-       .event_ctl              = SNBEP_PCU_MSR_PMON_CTL0,
-       .event_mask             = SNBEP_PCU_MSR_PMON_RAW_EVENT_MASK,
-       .box_ctl                = SNBEP_PCU_MSR_PMON_BOX_CTL,
-       .num_shared_regs        = 1,
-       .ops                    = &snbep_uncore_pcu_ops,
-       .format_group           = &snbep_uncore_pcu_format_group,
-};
-
-static struct intel_uncore_type *snbep_msr_uncores[] = {
-       &snbep_uncore_ubox,
-       &snbep_uncore_cbox,
-       &snbep_uncore_pcu,
-       NULL,
-};
-
-enum {
-       SNBEP_PCI_QPI_PORT0_FILTER,
-       SNBEP_PCI_QPI_PORT1_FILTER,
-};
-
-static int snbep_qpi_hw_config(struct intel_uncore_box *box, struct perf_event *event)
-{
-       struct hw_perf_event *hwc = &event->hw;
-       struct hw_perf_event_extra *reg1 = &hwc->extra_reg;
-       struct hw_perf_event_extra *reg2 = &hwc->branch_reg;
-
-       if ((hwc->config & SNBEP_PMON_CTL_EV_SEL_MASK) == 0x38) {
-               reg1->idx = 0;
-               reg1->reg = SNBEP_Q_Py_PCI_PMON_PKT_MATCH0;
-               reg1->config = event->attr.config1;
-               reg2->reg = SNBEP_Q_Py_PCI_PMON_PKT_MASK0;
-               reg2->config = event->attr.config2;
-       }
-       return 0;
-}
-
-static void snbep_qpi_enable_event(struct intel_uncore_box *box, struct perf_event *event)
-{
-       struct pci_dev *pdev = box->pci_dev;
-       struct hw_perf_event *hwc = &event->hw;
-       struct hw_perf_event_extra *reg1 = &hwc->extra_reg;
-       struct hw_perf_event_extra *reg2 = &hwc->branch_reg;
-
-       if (reg1->idx != EXTRA_REG_NONE) {
-               int idx = box->pmu->pmu_idx + SNBEP_PCI_QPI_PORT0_FILTER;
-               struct pci_dev *filter_pdev = extra_pci_dev[box->phys_id][idx];
-               WARN_ON_ONCE(!filter_pdev);
-               if (filter_pdev) {
-                       pci_write_config_dword(filter_pdev, reg1->reg,
-                                               (u32)reg1->config);
-                       pci_write_config_dword(filter_pdev, reg1->reg + 4,
-                                               (u32)(reg1->config >> 32));
-                       pci_write_config_dword(filter_pdev, reg2->reg,
-                                               (u32)reg2->config);
-                       pci_write_config_dword(filter_pdev, reg2->reg + 4,
-                                               (u32)(reg2->config >> 32));
-               }
-       }
-
-       pci_write_config_dword(pdev, hwc->config_base, hwc->config | SNBEP_PMON_CTL_EN);
-}
-
-static struct intel_uncore_ops snbep_uncore_qpi_ops = {
-       SNBEP_UNCORE_PCI_OPS_COMMON_INIT(),
-       .enable_event           = snbep_qpi_enable_event,
-       .hw_config              = snbep_qpi_hw_config,
-       .get_constraint         = uncore_get_constraint,
-       .put_constraint         = uncore_put_constraint,
-};
-
-#define SNBEP_UNCORE_PCI_COMMON_INIT()                         \
-       .perf_ctr       = SNBEP_PCI_PMON_CTR0,                  \
-       .event_ctl      = SNBEP_PCI_PMON_CTL0,                  \
-       .event_mask     = SNBEP_PMON_RAW_EVENT_MASK,            \
-       .box_ctl        = SNBEP_PCI_PMON_BOX_CTL,               \
-       .ops            = &snbep_uncore_pci_ops,                \
-       .format_group   = &snbep_uncore_format_group
-
-static struct intel_uncore_type snbep_uncore_ha = {
-       .name           = "ha",
-       .num_counters   = 4,
-       .num_boxes      = 1,
-       .perf_ctr_bits  = 48,
-       SNBEP_UNCORE_PCI_COMMON_INIT(),
-};
-
-static struct intel_uncore_type snbep_uncore_imc = {
-       .name           = "imc",
-       .num_counters   = 4,
-       .num_boxes      = 4,
-       .perf_ctr_bits  = 48,
-       .fixed_ctr_bits = 48,
-       .fixed_ctr      = SNBEP_MC_CHy_PCI_PMON_FIXED_CTR,
-       .fixed_ctl      = SNBEP_MC_CHy_PCI_PMON_FIXED_CTL,
-       .event_descs    = snbep_uncore_imc_events,
-       SNBEP_UNCORE_PCI_COMMON_INIT(),
-};
-
-static struct intel_uncore_type snbep_uncore_qpi = {
-       .name                   = "qpi",
-       .num_counters           = 4,
-       .num_boxes              = 2,
-       .perf_ctr_bits          = 48,
-       .perf_ctr               = SNBEP_PCI_PMON_CTR0,
-       .event_ctl              = SNBEP_PCI_PMON_CTL0,
-       .event_mask             = SNBEP_QPI_PCI_PMON_RAW_EVENT_MASK,
-       .box_ctl                = SNBEP_PCI_PMON_BOX_CTL,
-       .num_shared_regs        = 1,
-       .ops                    = &snbep_uncore_qpi_ops,
-       .event_descs            = snbep_uncore_qpi_events,
-       .format_group           = &snbep_uncore_qpi_format_group,
-};
-
-
-static struct intel_uncore_type snbep_uncore_r2pcie = {
-       .name           = "r2pcie",
-       .num_counters   = 4,
-       .num_boxes      = 1,
-       .perf_ctr_bits  = 44,
-       .constraints    = snbep_uncore_r2pcie_constraints,
-       SNBEP_UNCORE_PCI_COMMON_INIT(),
-};
-
-static struct intel_uncore_type snbep_uncore_r3qpi = {
-       .name           = "r3qpi",
-       .num_counters   = 3,
-       .num_boxes      = 2,
-       .perf_ctr_bits  = 44,
-       .constraints    = snbep_uncore_r3qpi_constraints,
-       SNBEP_UNCORE_PCI_COMMON_INIT(),
-};
-
-enum {
-       SNBEP_PCI_UNCORE_HA,
-       SNBEP_PCI_UNCORE_IMC,
-       SNBEP_PCI_UNCORE_QPI,
-       SNBEP_PCI_UNCORE_R2PCIE,
-       SNBEP_PCI_UNCORE_R3QPI,
-};
-
-static struct intel_uncore_type *snbep_pci_uncores[] = {
-       [SNBEP_PCI_UNCORE_HA]           = &snbep_uncore_ha,
-       [SNBEP_PCI_UNCORE_IMC]          = &snbep_uncore_imc,
-       [SNBEP_PCI_UNCORE_QPI]          = &snbep_uncore_qpi,
-       [SNBEP_PCI_UNCORE_R2PCIE]       = &snbep_uncore_r2pcie,
-       [SNBEP_PCI_UNCORE_R3QPI]        = &snbep_uncore_r3qpi,
-       NULL,
-};
-
-static const struct pci_device_id snbep_uncore_pci_ids[] = {
-       { /* Home Agent */
-               PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_UNC_HA),
-               .driver_data = UNCORE_PCI_DEV_DATA(SNBEP_PCI_UNCORE_HA, 0),
-       },
-       { /* MC Channel 0 */
-               PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_UNC_IMC0),
-               .driver_data = UNCORE_PCI_DEV_DATA(SNBEP_PCI_UNCORE_IMC, 0),
-       },
-       { /* MC Channel 1 */
-               PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_UNC_IMC1),
-               .driver_data = UNCORE_PCI_DEV_DATA(SNBEP_PCI_UNCORE_IMC, 1),
-       },
-       { /* MC Channel 2 */
-               PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_UNC_IMC2),
-               .driver_data = UNCORE_PCI_DEV_DATA(SNBEP_PCI_UNCORE_IMC, 2),
-       },
-       { /* MC Channel 3 */
-               PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_UNC_IMC3),
-               .driver_data = UNCORE_PCI_DEV_DATA(SNBEP_PCI_UNCORE_IMC, 3),
-       },
-       { /* QPI Port 0 */
-               PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_UNC_QPI0),
-               .driver_data = UNCORE_PCI_DEV_DATA(SNBEP_PCI_UNCORE_QPI, 0),
-       },
-       { /* QPI Port 1 */
-               PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_UNC_QPI1),
-               .driver_data = UNCORE_PCI_DEV_DATA(SNBEP_PCI_UNCORE_QPI, 1),
-       },
-       { /* R2PCIe */
-               PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_UNC_R2PCIE),
-               .driver_data = UNCORE_PCI_DEV_DATA(SNBEP_PCI_UNCORE_R2PCIE, 0),
-       },
-       { /* R3QPI Link 0 */
-               PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_UNC_R3QPI0),
-               .driver_data = UNCORE_PCI_DEV_DATA(SNBEP_PCI_UNCORE_R3QPI, 0),
-       },
-       { /* R3QPI Link 1 */
-               PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_UNC_R3QPI1),
-               .driver_data = UNCORE_PCI_DEV_DATA(SNBEP_PCI_UNCORE_R3QPI, 1),
-       },
-       { /* QPI Port 0 filter  */
-               PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x3c86),
-               .driver_data = UNCORE_PCI_DEV_DATA(UNCORE_EXTRA_PCI_DEV,
-                                                  SNBEP_PCI_QPI_PORT0_FILTER),
-       },
-       { /* QPI Port 0 filter  */
-               PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x3c96),
-               .driver_data = UNCORE_PCI_DEV_DATA(UNCORE_EXTRA_PCI_DEV,
-                                                  SNBEP_PCI_QPI_PORT1_FILTER),
-       },
-       { /* end: all zeroes */ }
-};
-
-static struct pci_driver snbep_uncore_pci_driver = {
-       .name           = "snbep_uncore",
-       .id_table       = snbep_uncore_pci_ids,
-};
-
-/*
- * build pci bus to socket mapping
- */
-static int snbep_pci2phy_map_init(int devid)
-{
-       struct pci_dev *ubox_dev = NULL;
-       int i, bus, nodeid;
-       int err = 0;
-       u32 config = 0;
-
-       while (1) {
-               /* find the UBOX device */
-               ubox_dev = pci_get_device(PCI_VENDOR_ID_INTEL, devid, ubox_dev);
-               if (!ubox_dev)
-                       break;
-               bus = ubox_dev->bus->number;
-               /* get the Node ID of the local register */
-               err = pci_read_config_dword(ubox_dev, 0x40, &config);
-               if (err)
-                       break;
-               nodeid = config;
-               /* get the Node ID mapping */
-               err = pci_read_config_dword(ubox_dev, 0x54, &config);
-               if (err)
-                       break;
-               /*
-                * every three bits in the Node ID mapping register maps
-                * to a particular node.
-                */
-               for (i = 0; i < 8; i++) {
-                       if (nodeid == ((config >> (3 * i)) & 0x7)) {
-                               pcibus_to_physid[bus] = i;
-                               break;
-                       }
-               }
-       }
-
-       if (!err) {
-               /*
-                * For PCI bus with no UBOX device, find the next bus
-                * that has UBOX device and use its mapping.
-                */
-               i = -1;
-               for (bus = 255; bus >= 0; bus--) {
-                       if (pcibus_to_physid[bus] >= 0)
-                               i = pcibus_to_physid[bus];
-                       else
-                               pcibus_to_physid[bus] = i;
-               }
-       }
-
-       if (ubox_dev)
-               pci_dev_put(ubox_dev);
-
-       return err ? pcibios_err_to_errno(err) : 0;
-}
-/* end of Sandy Bridge-EP uncore support */
-
-/* IvyTown uncore support */
-static void ivt_uncore_msr_init_box(struct intel_uncore_box *box)
-{
-       unsigned msr = uncore_msr_box_ctl(box);
-       if (msr)
-               wrmsrl(msr, IVT_PMON_BOX_CTL_INT);
-}
-
-static void ivt_uncore_pci_init_box(struct intel_uncore_box *box)
-{
-       struct pci_dev *pdev = box->pci_dev;
-
-       pci_write_config_dword(pdev, SNBEP_PCI_PMON_BOX_CTL, IVT_PMON_BOX_CTL_INT);
-}
-
-#define IVT_UNCORE_MSR_OPS_COMMON_INIT()                       \
-       .init_box       = ivt_uncore_msr_init_box,              \
-       .disable_box    = snbep_uncore_msr_disable_box,         \
-       .enable_box     = snbep_uncore_msr_enable_box,          \
-       .disable_event  = snbep_uncore_msr_disable_event,       \
-       .enable_event   = snbep_uncore_msr_enable_event,        \
-       .read_counter   = uncore_msr_read_counter
-
-static struct intel_uncore_ops ivt_uncore_msr_ops = {
-       IVT_UNCORE_MSR_OPS_COMMON_INIT(),
-};
-
-static struct intel_uncore_ops ivt_uncore_pci_ops = {
-       .init_box       = ivt_uncore_pci_init_box,
-       .disable_box    = snbep_uncore_pci_disable_box,
-       .enable_box     = snbep_uncore_pci_enable_box,
-       .disable_event  = snbep_uncore_pci_disable_event,
-       .enable_event   = snbep_uncore_pci_enable_event,
-       .read_counter   = snbep_uncore_pci_read_counter,
-};
-
-#define IVT_UNCORE_PCI_COMMON_INIT()                           \
-       .perf_ctr       = SNBEP_PCI_PMON_CTR0,                  \
-       .event_ctl      = SNBEP_PCI_PMON_CTL0,                  \
-       .event_mask     = IVT_PMON_RAW_EVENT_MASK,              \
-       .box_ctl        = SNBEP_PCI_PMON_BOX_CTL,               \
-       .ops            = &ivt_uncore_pci_ops,                  \
-       .format_group   = &ivt_uncore_format_group
-
-static struct attribute *ivt_uncore_formats_attr[] = {
-       &format_attr_event.attr,
-       &format_attr_umask.attr,
-       &format_attr_edge.attr,
-       &format_attr_inv.attr,
-       &format_attr_thresh8.attr,
-       NULL,
-};
-
-static struct attribute *ivt_uncore_ubox_formats_attr[] = {
-       &format_attr_event.attr,
-       &format_attr_umask.attr,
-       &format_attr_edge.attr,
-       &format_attr_inv.attr,
-       &format_attr_thresh5.attr,
-       NULL,
-};
-
-static struct attribute *ivt_uncore_cbox_formats_attr[] = {
-       &format_attr_event.attr,
-       &format_attr_umask.attr,
-       &format_attr_edge.attr,
-       &format_attr_tid_en.attr,
-       &format_attr_thresh8.attr,
-       &format_attr_filter_tid.attr,
-       &format_attr_filter_link.attr,
-       &format_attr_filter_state2.attr,
-       &format_attr_filter_nid2.attr,
-       &format_attr_filter_opc2.attr,
-       NULL,
-};
-
-static struct attribute *ivt_uncore_pcu_formats_attr[] = {
-       &format_attr_event_ext.attr,
-       &format_attr_occ_sel.attr,
-       &format_attr_edge.attr,
-       &format_attr_thresh5.attr,
-       &format_attr_occ_invert.attr,
-       &format_attr_occ_edge.attr,
-       &format_attr_filter_band0.attr,
-       &format_attr_filter_band1.attr,
-       &format_attr_filter_band2.attr,
-       &format_attr_filter_band3.attr,
-       NULL,
-};
-
-static struct attribute *ivt_uncore_qpi_formats_attr[] = {
-       &format_attr_event_ext.attr,
-       &format_attr_umask.attr,
-       &format_attr_edge.attr,
-       &format_attr_thresh8.attr,
-       &format_attr_match_rds.attr,
-       &format_attr_match_rnid30.attr,
-       &format_attr_match_rnid4.attr,
-       &format_attr_match_dnid.attr,
-       &format_attr_match_mc.attr,
-       &format_attr_match_opc.attr,
-       &format_attr_match_vnw.attr,
-       &format_attr_match0.attr,
-       &format_attr_match1.attr,
-       &format_attr_mask_rds.attr,
-       &format_attr_mask_rnid30.attr,
-       &format_attr_mask_rnid4.attr,
-       &format_attr_mask_dnid.attr,
-       &format_attr_mask_mc.attr,
-       &format_attr_mask_opc.attr,
-       &format_attr_mask_vnw.attr,
-       &format_attr_mask0.attr,
-       &format_attr_mask1.attr,
-       NULL,
-};
-
-static struct attribute_group ivt_uncore_format_group = {
-       .name = "format",
-       .attrs = ivt_uncore_formats_attr,
-};
-
-static struct attribute_group ivt_uncore_ubox_format_group = {
-       .name = "format",
-       .attrs = ivt_uncore_ubox_formats_attr,
-};
-
-static struct attribute_group ivt_uncore_cbox_format_group = {
-       .name = "format",
-       .attrs = ivt_uncore_cbox_formats_attr,
-};
-
-static struct attribute_group ivt_uncore_pcu_format_group = {
-       .name = "format",
-       .attrs = ivt_uncore_pcu_formats_attr,
-};
-
-static struct attribute_group ivt_uncore_qpi_format_group = {
-       .name = "format",
-       .attrs = ivt_uncore_qpi_formats_attr,
-};
-
-static struct intel_uncore_type ivt_uncore_ubox = {
-       .name           = "ubox",
-       .num_counters   = 2,
-       .num_boxes      = 1,
-       .perf_ctr_bits  = 44,
-       .fixed_ctr_bits = 48,
-       .perf_ctr       = SNBEP_U_MSR_PMON_CTR0,
-       .event_ctl      = SNBEP_U_MSR_PMON_CTL0,
-       .event_mask     = IVT_U_MSR_PMON_RAW_EVENT_MASK,
-       .fixed_ctr      = SNBEP_U_MSR_PMON_UCLK_FIXED_CTR,
-       .fixed_ctl      = SNBEP_U_MSR_PMON_UCLK_FIXED_CTL,
-       .ops            = &ivt_uncore_msr_ops,
-       .format_group   = &ivt_uncore_ubox_format_group,
-};
-
-static struct extra_reg ivt_uncore_cbox_extra_regs[] = {
-       SNBEP_CBO_EVENT_EXTRA_REG(SNBEP_CBO_PMON_CTL_TID_EN,
-                                 SNBEP_CBO_PMON_CTL_TID_EN, 0x1),
-       SNBEP_CBO_EVENT_EXTRA_REG(0x1031, 0x10ff, 0x2),
-
-       SNBEP_CBO_EVENT_EXTRA_REG(0x1134, 0xffff, 0x4),
-       SNBEP_CBO_EVENT_EXTRA_REG(0x4134, 0xffff, 0xc),
-       SNBEP_CBO_EVENT_EXTRA_REG(0x5134, 0xffff, 0xc),
-       SNBEP_CBO_EVENT_EXTRA_REG(0x0334, 0xffff, 0x4),
-       SNBEP_CBO_EVENT_EXTRA_REG(0x4334, 0xffff, 0xc),
-       SNBEP_CBO_EVENT_EXTRA_REG(0x0534, 0xffff, 0x4),
-       SNBEP_CBO_EVENT_EXTRA_REG(0x4534, 0xffff, 0xc),
-       SNBEP_CBO_EVENT_EXTRA_REG(0x0934, 0xffff, 0x4),
-       SNBEP_CBO_EVENT_EXTRA_REG(0x4934, 0xffff, 0xc),
-       SNBEP_CBO_EVENT_EXTRA_REG(0x0135, 0xffff, 0x10),
-       SNBEP_CBO_EVENT_EXTRA_REG(0x0335, 0xffff, 0x10),
-       SNBEP_CBO_EVENT_EXTRA_REG(0x2135, 0xffff, 0x10),
-       SNBEP_CBO_EVENT_EXTRA_REG(0x2335, 0xffff, 0x10),
-       SNBEP_CBO_EVENT_EXTRA_REG(0x4135, 0xffff, 0x18),
-       SNBEP_CBO_EVENT_EXTRA_REG(0x4335, 0xffff, 0x18),
-       SNBEP_CBO_EVENT_EXTRA_REG(0x4435, 0xffff, 0x8),
-       SNBEP_CBO_EVENT_EXTRA_REG(0x4835, 0xffff, 0x8),
-       SNBEP_CBO_EVENT_EXTRA_REG(0x4a35, 0xffff, 0x8),
-       SNBEP_CBO_EVENT_EXTRA_REG(0x5035, 0xffff, 0x8),
-       SNBEP_CBO_EVENT_EXTRA_REG(0x8135, 0xffff, 0x10),
-       SNBEP_CBO_EVENT_EXTRA_REG(0x8335, 0xffff, 0x10),
-       SNBEP_CBO_EVENT_EXTRA_REG(0x0136, 0xffff, 0x10),
-       SNBEP_CBO_EVENT_EXTRA_REG(0x0336, 0xffff, 0x10),
-       SNBEP_CBO_EVENT_EXTRA_REG(0x2136, 0xffff, 0x10),
-       SNBEP_CBO_EVENT_EXTRA_REG(0x2336, 0xffff, 0x10),
-       SNBEP_CBO_EVENT_EXTRA_REG(0x4136, 0xffff, 0x18),
-       SNBEP_CBO_EVENT_EXTRA_REG(0x4336, 0xffff, 0x18),
-       SNBEP_CBO_EVENT_EXTRA_REG(0x4436, 0xffff, 0x8),
-       SNBEP_CBO_EVENT_EXTRA_REG(0x4836, 0xffff, 0x8),
-       SNBEP_CBO_EVENT_EXTRA_REG(0x4a36, 0xffff, 0x8),
-       SNBEP_CBO_EVENT_EXTRA_REG(0x5036, 0xffff, 0x8),
-       SNBEP_CBO_EVENT_EXTRA_REG(0x8136, 0xffff, 0x10),
-       SNBEP_CBO_EVENT_EXTRA_REG(0x8336, 0xffff, 0x10),
-       SNBEP_CBO_EVENT_EXTRA_REG(0x4037, 0x40ff, 0x8),
-       EVENT_EXTRA_END
-};
-
-static u64 ivt_cbox_filter_mask(int fields)
-{
-       u64 mask = 0;
-
-       if (fields & 0x1)
-               mask |= IVT_CB0_MSR_PMON_BOX_FILTER_TID;
-       if (fields & 0x2)
-               mask |= IVT_CB0_MSR_PMON_BOX_FILTER_LINK;
-       if (fields & 0x4)
-               mask |= IVT_CB0_MSR_PMON_BOX_FILTER_STATE;
-       if (fields & 0x8)
-               mask |= IVT_CB0_MSR_PMON_BOX_FILTER_NID;
-       if (fields & 0x10)
-               mask |= IVT_CB0_MSR_PMON_BOX_FILTER_OPC;
-
-       return mask;
-}
-
-static struct event_constraint *
-ivt_cbox_get_constraint(struct intel_uncore_box *box, struct perf_event *event)
-{
-       return __snbep_cbox_get_constraint(box, event, ivt_cbox_filter_mask);
-}
-
-static int ivt_cbox_hw_config(struct intel_uncore_box *box, struct perf_event *event)
-{
-       struct hw_perf_event_extra *reg1 = &event->hw.extra_reg;
-       struct extra_reg *er;
-       int idx = 0;
-
-       for (er = ivt_uncore_cbox_extra_regs; er->msr; er++) {
-               if (er->event != (event->hw.config & er->config_mask))
-                       continue;
-               idx |= er->idx;
-       }
-
-       if (idx) {
-               reg1->reg = SNBEP_C0_MSR_PMON_BOX_FILTER +
-                       SNBEP_CBO_MSR_OFFSET * box->pmu->pmu_idx;
-               reg1->config = event->attr.config1 & ivt_cbox_filter_mask(idx);
-               reg1->idx = idx;
-       }
-       return 0;
-}
-
-static void ivt_cbox_enable_event(struct intel_uncore_box *box, struct perf_event *event)
-{
-       struct hw_perf_event *hwc = &event->hw;
-       struct hw_perf_event_extra *reg1 = &hwc->extra_reg;
-
-       if (reg1->idx != EXTRA_REG_NONE) {
-               u64 filter = uncore_shared_reg_config(box, 0);
-               wrmsrl(reg1->reg, filter & 0xffffffff);
-               wrmsrl(reg1->reg + 6, filter >> 32);
-       }
-
-       wrmsrl(hwc->config_base, hwc->config | SNBEP_PMON_CTL_EN);
-}
-
-static struct intel_uncore_ops ivt_uncore_cbox_ops = {
-       .init_box               = ivt_uncore_msr_init_box,
-       .disable_box            = snbep_uncore_msr_disable_box,
-       .enable_box             = snbep_uncore_msr_enable_box,
-       .disable_event          = snbep_uncore_msr_disable_event,
-       .enable_event           = ivt_cbox_enable_event,
-       .read_counter           = uncore_msr_read_counter,
-       .hw_config              = ivt_cbox_hw_config,
-       .get_constraint         = ivt_cbox_get_constraint,
-       .put_constraint         = snbep_cbox_put_constraint,
-};
-
-static struct intel_uncore_type ivt_uncore_cbox = {
-       .name                   = "cbox",
-       .num_counters           = 4,
-       .num_boxes              = 15,
-       .perf_ctr_bits          = 44,
-       .event_ctl              = SNBEP_C0_MSR_PMON_CTL0,
-       .perf_ctr               = SNBEP_C0_MSR_PMON_CTR0,
-       .event_mask             = IVT_CBO_MSR_PMON_RAW_EVENT_MASK,
-       .box_ctl                = SNBEP_C0_MSR_PMON_BOX_CTL,
-       .msr_offset             = SNBEP_CBO_MSR_OFFSET,
-       .num_shared_regs        = 1,
-       .constraints            = snbep_uncore_cbox_constraints,
-       .ops                    = &ivt_uncore_cbox_ops,
-       .format_group           = &ivt_uncore_cbox_format_group,
-};
-
-static struct intel_uncore_ops ivt_uncore_pcu_ops = {
-       IVT_UNCORE_MSR_OPS_COMMON_INIT(),
-       .hw_config              = snbep_pcu_hw_config,
-       .get_constraint         = snbep_pcu_get_constraint,
-       .put_constraint         = snbep_pcu_put_constraint,
-};
-
-static struct intel_uncore_type ivt_uncore_pcu = {
-       .name                   = "pcu",
-       .num_counters           = 4,
-       .num_boxes              = 1,
-       .perf_ctr_bits          = 48,
-       .perf_ctr               = SNBEP_PCU_MSR_PMON_CTR0,
-       .event_ctl              = SNBEP_PCU_MSR_PMON_CTL0,
-       .event_mask             = IVT_PCU_MSR_PMON_RAW_EVENT_MASK,
-       .box_ctl                = SNBEP_PCU_MSR_PMON_BOX_CTL,
-       .num_shared_regs        = 1,
-       .ops                    = &ivt_uncore_pcu_ops,
-       .format_group           = &ivt_uncore_pcu_format_group,
-};
-
-static struct intel_uncore_type *ivt_msr_uncores[] = {
-       &ivt_uncore_ubox,
-       &ivt_uncore_cbox,
-       &ivt_uncore_pcu,
-       NULL,
-};
-
-static struct intel_uncore_type ivt_uncore_ha = {
-       .name           = "ha",
-       .num_counters   = 4,
-       .num_boxes      = 2,
-       .perf_ctr_bits  = 48,
-       IVT_UNCORE_PCI_COMMON_INIT(),
-};
-
-static struct intel_uncore_type ivt_uncore_imc = {
-       .name           = "imc",
-       .num_counters   = 4,
-       .num_boxes      = 8,
-       .perf_ctr_bits  = 48,
-       .fixed_ctr_bits = 48,
-       .fixed_ctr      = SNBEP_MC_CHy_PCI_PMON_FIXED_CTR,
-       .fixed_ctl      = SNBEP_MC_CHy_PCI_PMON_FIXED_CTL,
-       IVT_UNCORE_PCI_COMMON_INIT(),
-};
-
-/* registers in IRP boxes are not properly aligned */
-static unsigned ivt_uncore_irp_ctls[] = {0xd8, 0xdc, 0xe0, 0xe4};
-static unsigned ivt_uncore_irp_ctrs[] = {0xa0, 0xb0, 0xb8, 0xc0};
-
-static void ivt_uncore_irp_enable_event(struct intel_uncore_box *box, struct perf_event *event)
-{
-       struct pci_dev *pdev = box->pci_dev;
-       struct hw_perf_event *hwc = &event->hw;
-
-       pci_write_config_dword(pdev, ivt_uncore_irp_ctls[hwc->idx],
-                              hwc->config | SNBEP_PMON_CTL_EN);
-}
-
-static void ivt_uncore_irp_disable_event(struct intel_uncore_box *box, struct perf_event *event)
-{
-       struct pci_dev *pdev = box->pci_dev;
-       struct hw_perf_event *hwc = &event->hw;
-
-       pci_write_config_dword(pdev, ivt_uncore_irp_ctls[hwc->idx], hwc->config);
-}
-
-static u64 ivt_uncore_irp_read_counter(struct intel_uncore_box *box, struct perf_event *event)
-{
-       struct pci_dev *pdev = box->pci_dev;
-       struct hw_perf_event *hwc = &event->hw;
-       u64 count = 0;
-
-       pci_read_config_dword(pdev, ivt_uncore_irp_ctrs[hwc->idx], (u32 *)&count);
-       pci_read_config_dword(pdev, ivt_uncore_irp_ctrs[hwc->idx] + 4, (u32 *)&count + 1);
-
-       return count;
-}
-
-static struct intel_uncore_ops ivt_uncore_irp_ops = {
-       .init_box       = ivt_uncore_pci_init_box,
-       .disable_box    = snbep_uncore_pci_disable_box,
-       .enable_box     = snbep_uncore_pci_enable_box,
-       .disable_event  = ivt_uncore_irp_disable_event,
-       .enable_event   = ivt_uncore_irp_enable_event,
-       .read_counter   = ivt_uncore_irp_read_counter,
-};
-
-static struct intel_uncore_type ivt_uncore_irp = {
-       .name                   = "irp",
-       .num_counters           = 4,
-       .num_boxes              = 1,
-       .perf_ctr_bits          = 48,
-       .event_mask             = IVT_PMON_RAW_EVENT_MASK,
-       .box_ctl                = SNBEP_PCI_PMON_BOX_CTL,
-       .ops                    = &ivt_uncore_irp_ops,
-       .format_group           = &ivt_uncore_format_group,
-};
-
-static struct intel_uncore_ops ivt_uncore_qpi_ops = {
-       .init_box       = ivt_uncore_pci_init_box,
-       .disable_box    = snbep_uncore_pci_disable_box,
-       .enable_box     = snbep_uncore_pci_enable_box,
-       .disable_event  = snbep_uncore_pci_disable_event,
-       .enable_event   = snbep_qpi_enable_event,
-       .read_counter   = snbep_uncore_pci_read_counter,
-       .hw_config      = snbep_qpi_hw_config,
-       .get_constraint = uncore_get_constraint,
-       .put_constraint = uncore_put_constraint,
-};
-
-static struct intel_uncore_type ivt_uncore_qpi = {
-       .name                   = "qpi",
-       .num_counters           = 4,
-       .num_boxes              = 3,
-       .perf_ctr_bits          = 48,
-       .perf_ctr               = SNBEP_PCI_PMON_CTR0,
-       .event_ctl              = SNBEP_PCI_PMON_CTL0,
-       .event_mask             = IVT_QPI_PCI_PMON_RAW_EVENT_MASK,
-       .box_ctl                = SNBEP_PCI_PMON_BOX_CTL,
-       .num_shared_regs        = 1,
-       .ops                    = &ivt_uncore_qpi_ops,
-       .format_group           = &ivt_uncore_qpi_format_group,
-};
-
-static struct intel_uncore_type ivt_uncore_r2pcie = {
-       .name           = "r2pcie",
-       .num_counters   = 4,
-       .num_boxes      = 1,
-       .perf_ctr_bits  = 44,
-       .constraints    = snbep_uncore_r2pcie_constraints,
-       IVT_UNCORE_PCI_COMMON_INIT(),
-};
-
-static struct intel_uncore_type ivt_uncore_r3qpi = {
-       .name           = "r3qpi",
-       .num_counters   = 3,
-       .num_boxes      = 2,
-       .perf_ctr_bits  = 44,
-       .constraints    = snbep_uncore_r3qpi_constraints,
-       IVT_UNCORE_PCI_COMMON_INIT(),
-};
-
-enum {
-       IVT_PCI_UNCORE_HA,
-       IVT_PCI_UNCORE_IMC,
-       IVT_PCI_UNCORE_IRP,
-       IVT_PCI_UNCORE_QPI,
-       IVT_PCI_UNCORE_R2PCIE,
-       IVT_PCI_UNCORE_R3QPI,
-};
-
-static struct intel_uncore_type *ivt_pci_uncores[] = {
-       [IVT_PCI_UNCORE_HA]     = &ivt_uncore_ha,
-       [IVT_PCI_UNCORE_IMC]    = &ivt_uncore_imc,
-       [IVT_PCI_UNCORE_IRP]    = &ivt_uncore_irp,
-       [IVT_PCI_UNCORE_QPI]    = &ivt_uncore_qpi,
-       [IVT_PCI_UNCORE_R2PCIE] = &ivt_uncore_r2pcie,
-       [IVT_PCI_UNCORE_R3QPI]  = &ivt_uncore_r3qpi,
-       NULL,
-};
-
-static const struct pci_device_id ivt_uncore_pci_ids[] = {
-       { /* Home Agent 0 */
-               PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xe30),
-               .driver_data = UNCORE_PCI_DEV_DATA(IVT_PCI_UNCORE_HA, 0),
-       },
-       { /* Home Agent 1 */
-               PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xe38),
-               .driver_data = UNCORE_PCI_DEV_DATA(IVT_PCI_UNCORE_HA, 1),
-       },
-       { /* MC0 Channel 0 */
-               PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xeb4),
-               .driver_data = UNCORE_PCI_DEV_DATA(IVT_PCI_UNCORE_IMC, 0),
-       },
-       { /* MC0 Channel 1 */
-               PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xeb5),
-               .driver_data = UNCORE_PCI_DEV_DATA(IVT_PCI_UNCORE_IMC, 1),
-       },
-       { /* MC0 Channel 3 */
-               PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xeb0),
-               .driver_data = UNCORE_PCI_DEV_DATA(IVT_PCI_UNCORE_IMC, 2),
-       },
-       { /* MC0 Channel 4 */
-               PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xeb1),
-               .driver_data = UNCORE_PCI_DEV_DATA(IVT_PCI_UNCORE_IMC, 3),
-       },
-       { /* MC1 Channel 0 */
-               PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xef4),
-               .driver_data = UNCORE_PCI_DEV_DATA(IVT_PCI_UNCORE_IMC, 4),
-       },
-       { /* MC1 Channel 1 */
-               PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xef5),
-               .driver_data = UNCORE_PCI_DEV_DATA(IVT_PCI_UNCORE_IMC, 5),
-       },
-       { /* MC1 Channel 3 */
-               PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xef0),
-               .driver_data = UNCORE_PCI_DEV_DATA(IVT_PCI_UNCORE_IMC, 6),
-       },
-       { /* MC1 Channel 4 */
-               PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xef1),
-               .driver_data = UNCORE_PCI_DEV_DATA(IVT_PCI_UNCORE_IMC, 7),
-       },
-       { /* IRP */
-               PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xe39),
-               .driver_data = UNCORE_PCI_DEV_DATA(IVT_PCI_UNCORE_IRP, 0),
-       },
-       { /* QPI0 Port 0 */
-               PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xe32),
-               .driver_data = UNCORE_PCI_DEV_DATA(IVT_PCI_UNCORE_QPI, 0),
-       },
-       { /* QPI0 Port 1 */
-               PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xe33),
-               .driver_data = UNCORE_PCI_DEV_DATA(IVT_PCI_UNCORE_QPI, 1),
-       },
-       { /* QPI1 Port 2 */
-               PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xe3a),
-               .driver_data = UNCORE_PCI_DEV_DATA(IVT_PCI_UNCORE_QPI, 2),
-       },
-       { /* R2PCIe */
-               PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xe34),
-               .driver_data = UNCORE_PCI_DEV_DATA(IVT_PCI_UNCORE_R2PCIE, 0),
-       },
-       { /* R3QPI0 Link 0 */
-               PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xe36),
-               .driver_data = UNCORE_PCI_DEV_DATA(IVT_PCI_UNCORE_R3QPI, 0),
-       },
-       { /* R3QPI0 Link 1 */
-               PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xe37),
-               .driver_data = UNCORE_PCI_DEV_DATA(IVT_PCI_UNCORE_R3QPI, 1),
-       },
-       { /* R3QPI1 Link 2 */
-               PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xe3e),
-               .driver_data = UNCORE_PCI_DEV_DATA(IVT_PCI_UNCORE_R3QPI, 2),
-       },
-       { /* QPI Port 0 filter  */
-               PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xe86),
-               .driver_data = UNCORE_PCI_DEV_DATA(UNCORE_EXTRA_PCI_DEV,
-                                                  SNBEP_PCI_QPI_PORT0_FILTER),
-       },
-       { /* QPI Port 0 filter  */
-               PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xe96),
-               .driver_data = UNCORE_PCI_DEV_DATA(UNCORE_EXTRA_PCI_DEV,
-                                                  SNBEP_PCI_QPI_PORT1_FILTER),
-       },
-       { /* end: all zeroes */ }
-};
-
-static struct pci_driver ivt_uncore_pci_driver = {
-       .name           = "ivt_uncore",
-       .id_table       = ivt_uncore_pci_ids,
-};
-/* end of IvyTown uncore support */
-
-/* Sandy Bridge uncore support */
-static void snb_uncore_msr_enable_event(struct intel_uncore_box *box, struct perf_event *event)
-{
-       struct hw_perf_event *hwc = &event->hw;
-
-       if (hwc->idx < UNCORE_PMC_IDX_FIXED)
-               wrmsrl(hwc->config_base, hwc->config | SNB_UNC_CTL_EN);
-       else
-               wrmsrl(hwc->config_base, SNB_UNC_CTL_EN);
-}
-
-static void snb_uncore_msr_disable_event(struct intel_uncore_box *box, struct perf_event *event)
-{
-       wrmsrl(event->hw.config_base, 0);
-}
-
-static void snb_uncore_msr_init_box(struct intel_uncore_box *box)
-{
-       if (box->pmu->pmu_idx == 0) {
-               wrmsrl(SNB_UNC_PERF_GLOBAL_CTL,
-                       SNB_UNC_GLOBAL_CTL_EN | SNB_UNC_GLOBAL_CTL_CORE_ALL);
-       }
-}
-
-static struct uncore_event_desc snb_uncore_events[] = {
-       INTEL_UNCORE_EVENT_DESC(clockticks, "event=0xff,umask=0x00"),
-       { /* end: all zeroes */ },
-};
-
-static struct attribute *snb_uncore_formats_attr[] = {
-       &format_attr_event.attr,
-       &format_attr_umask.attr,
-       &format_attr_edge.attr,
-       &format_attr_inv.attr,
-       &format_attr_cmask5.attr,
-       NULL,
-};
-
-static struct attribute_group snb_uncore_format_group = {
-       .name           = "format",
-       .attrs          = snb_uncore_formats_attr,
-};
-
-static struct intel_uncore_ops snb_uncore_msr_ops = {
-       .init_box       = snb_uncore_msr_init_box,
-       .disable_event  = snb_uncore_msr_disable_event,
-       .enable_event   = snb_uncore_msr_enable_event,
-       .read_counter   = uncore_msr_read_counter,
-};
-
-static struct event_constraint snb_uncore_cbox_constraints[] = {
-       UNCORE_EVENT_CONSTRAINT(0x80, 0x1),
-       UNCORE_EVENT_CONSTRAINT(0x83, 0x1),
-       EVENT_CONSTRAINT_END
-};
-
-static struct intel_uncore_type snb_uncore_cbox = {
-       .name           = "cbox",
-       .num_counters   = 2,
-       .num_boxes      = 4,
-       .perf_ctr_bits  = 44,
-       .fixed_ctr_bits = 48,
-       .perf_ctr       = SNB_UNC_CBO_0_PER_CTR0,
-       .event_ctl      = SNB_UNC_CBO_0_PERFEVTSEL0,
-       .fixed_ctr      = SNB_UNC_FIXED_CTR,
-       .fixed_ctl      = SNB_UNC_FIXED_CTR_CTRL,
-       .single_fixed   = 1,
-       .event_mask     = SNB_UNC_RAW_EVENT_MASK,
-       .msr_offset     = SNB_UNC_CBO_MSR_OFFSET,
-       .constraints    = snb_uncore_cbox_constraints,
-       .ops            = &snb_uncore_msr_ops,
-       .format_group   = &snb_uncore_format_group,
-       .event_descs    = snb_uncore_events,
-};
-
-static struct intel_uncore_type *snb_msr_uncores[] = {
-       &snb_uncore_cbox,
-       NULL,
-};
-
-enum {
-       SNB_PCI_UNCORE_IMC,
-};
-
-static struct uncore_event_desc snb_uncore_imc_events[] = {
-       INTEL_UNCORE_EVENT_DESC(data_reads,  "event=0x01"),
-       INTEL_UNCORE_EVENT_DESC(data_reads.scale, "6.103515625e-5"),
-       INTEL_UNCORE_EVENT_DESC(data_reads.unit, "MiB"),
-
-       INTEL_UNCORE_EVENT_DESC(data_writes, "event=0x02"),
-       INTEL_UNCORE_EVENT_DESC(data_writes.scale, "6.103515625e-5"),
-       INTEL_UNCORE_EVENT_DESC(data_writes.unit, "MiB"),
-
-       { /* end: all zeroes */ },
-};
-
-#define SNB_UNCORE_PCI_IMC_EVENT_MASK          0xff
-#define SNB_UNCORE_PCI_IMC_BAR_OFFSET          0x48
-
-/* page size multiple covering all config regs */
-#define SNB_UNCORE_PCI_IMC_MAP_SIZE            0x6000
-
-#define SNB_UNCORE_PCI_IMC_DATA_READS          0x1
-#define SNB_UNCORE_PCI_IMC_DATA_READS_BASE     0x5050
-#define SNB_UNCORE_PCI_IMC_DATA_WRITES         0x2
-#define SNB_UNCORE_PCI_IMC_DATA_WRITES_BASE    0x5054
-#define SNB_UNCORE_PCI_IMC_CTR_BASE            SNB_UNCORE_PCI_IMC_DATA_READS_BASE
-
-static struct attribute *snb_uncore_imc_formats_attr[] = {
-       &format_attr_event.attr,
-       NULL,
-};
-
-static struct attribute_group snb_uncore_imc_format_group = {
-       .name = "format",
-       .attrs = snb_uncore_imc_formats_attr,
-};
-
-static void snb_uncore_imc_init_box(struct intel_uncore_box *box)
-{
-       struct pci_dev *pdev = box->pci_dev;
-       int where = SNB_UNCORE_PCI_IMC_BAR_OFFSET;
-       resource_size_t addr;
-       u32 pci_dword;
-
-       pci_read_config_dword(pdev, where, &pci_dword);
-       addr = pci_dword;
-
-#ifdef CONFIG_PHYS_ADDR_T_64BIT
-       pci_read_config_dword(pdev, where + 4, &pci_dword);
-       addr |= ((resource_size_t)pci_dword << 32);
-#endif
-
-       addr &= ~(PAGE_SIZE - 1);
-
-       box->io_addr = ioremap(addr, SNB_UNCORE_PCI_IMC_MAP_SIZE);
-       box->hrtimer_duration = UNCORE_SNB_IMC_HRTIMER_INTERVAL;
-}
-
-static void snb_uncore_imc_enable_box(struct intel_uncore_box *box)
-{}
-
-static void snb_uncore_imc_disable_box(struct intel_uncore_box *box)
-{}
-
-static void snb_uncore_imc_enable_event(struct intel_uncore_box *box, struct perf_event *event)
-{}
-
-static void snb_uncore_imc_disable_event(struct intel_uncore_box *box, struct perf_event *event)
-{}
-
-static u64 snb_uncore_imc_read_counter(struct intel_uncore_box *box, struct perf_event *event)
-{
-       struct hw_perf_event *hwc = &event->hw;
-
-       return (u64)*(unsigned int *)(box->io_addr + hwc->event_base);
-}
-
-/*
- * custom event_init() function because we define our own fixed, free
- * running counters, so we do not want to conflict with generic uncore
- * logic. Also simplifies processing
- */
-static int snb_uncore_imc_event_init(struct perf_event *event)
-{
-       struct intel_uncore_pmu *pmu;
-       struct intel_uncore_box *box;
-       struct hw_perf_event *hwc = &event->hw;
-       u64 cfg = event->attr.config & SNB_UNCORE_PCI_IMC_EVENT_MASK;
-       int idx, base;
-
-       if (event->attr.type != event->pmu->type)
-               return -ENOENT;
-
-       pmu = uncore_event_to_pmu(event);
-       /* no device found for this pmu */
-       if (pmu->func_id < 0)
-               return -ENOENT;
-
-       /* Sampling not supported yet */
-       if (hwc->sample_period)
-               return -EINVAL;
-
-       /* unsupported modes and filters */
-       if (event->attr.exclude_user   ||
-           event->attr.exclude_kernel ||
-           event->attr.exclude_hv     ||
-           event->attr.exclude_idle   ||
-           event->attr.exclude_host   ||
-           event->attr.exclude_guest  ||
-           event->attr.sample_period) /* no sampling */
-               return -EINVAL;
-
-       /*
-        * Place all uncore events for a particular physical package
-        * onto a single cpu
-        */
-       if (event->cpu < 0)
-               return -EINVAL;
-
-       /* check only supported bits are set */
-       if (event->attr.config & ~SNB_UNCORE_PCI_IMC_EVENT_MASK)
-               return -EINVAL;
-
-       box = uncore_pmu_to_box(pmu, event->cpu);
-       if (!box || box->cpu < 0)
-               return -EINVAL;
-
-       event->cpu = box->cpu;
-
-       event->hw.idx = -1;
-       event->hw.last_tag = ~0ULL;
-       event->hw.extra_reg.idx = EXTRA_REG_NONE;
-       event->hw.branch_reg.idx = EXTRA_REG_NONE;
-       /*
-        * check event is known (whitelist, determines counter)
-        */
-       switch (cfg) {
-       case SNB_UNCORE_PCI_IMC_DATA_READS:
-               base = SNB_UNCORE_PCI_IMC_DATA_READS_BASE;
-               idx = UNCORE_PMC_IDX_FIXED;
-               break;
-       case SNB_UNCORE_PCI_IMC_DATA_WRITES:
-               base = SNB_UNCORE_PCI_IMC_DATA_WRITES_BASE;
-               idx = UNCORE_PMC_IDX_FIXED + 1;
-               break;
-       default:
-               return -EINVAL;
-       }
-
-       /* must be done before validate_group */
-       event->hw.event_base = base;
-       event->hw.config = cfg;
-       event->hw.idx = idx;
-
-       /* no group validation needed, we have free running counters */
-
-       return 0;
-}
-
-static int snb_uncore_imc_hw_config(struct intel_uncore_box *box, struct perf_event *event)
-{
-       return 0;
-}
-
-static void snb_uncore_imc_event_start(struct perf_event *event, int flags)
-{
-       struct intel_uncore_box *box = uncore_event_to_box(event);
-       u64 count;
-
-       if (WARN_ON_ONCE(!(event->hw.state & PERF_HES_STOPPED)))
-               return;
-
-       event->hw.state = 0;
-       box->n_active++;
-
-       list_add_tail(&event->active_entry, &box->active_list);
-
-       count = snb_uncore_imc_read_counter(box, event);
-       local64_set(&event->hw.prev_count, count);
-
-       if (box->n_active == 1)
-               uncore_pmu_start_hrtimer(box);
-}
-
-static void snb_uncore_imc_event_stop(struct perf_event *event, int flags)
-{
-       struct intel_uncore_box *box = uncore_event_to_box(event);
-       struct hw_perf_event *hwc = &event->hw;
-
-       if (!(hwc->state & PERF_HES_STOPPED)) {
-               box->n_active--;
-
-               WARN_ON_ONCE(hwc->state & PERF_HES_STOPPED);
-               hwc->state |= PERF_HES_STOPPED;
-
-               list_del(&event->active_entry);
-
-               if (box->n_active == 0)
-                       uncore_pmu_cancel_hrtimer(box);
-       }
-
-       if ((flags & PERF_EF_UPDATE) && !(hwc->state & PERF_HES_UPTODATE)) {
-               /*
-                * Drain the remaining delta count out of a event
-                * that we are disabling:
-                */
-               uncore_perf_event_update(box, event);
-               hwc->state |= PERF_HES_UPTODATE;
-       }
-}
-
-static int snb_uncore_imc_event_add(struct perf_event *event, int flags)
-{
-       struct intel_uncore_box *box = uncore_event_to_box(event);
-       struct hw_perf_event *hwc = &event->hw;
-
-       if (!box)
-               return -ENODEV;
-
-       hwc->state = PERF_HES_UPTODATE | PERF_HES_STOPPED;
-       if (!(flags & PERF_EF_START))
-               hwc->state |= PERF_HES_ARCH;
-
-       snb_uncore_imc_event_start(event, 0);
-
-       box->n_events++;
-
-       return 0;
-}
-
-static void snb_uncore_imc_event_del(struct perf_event *event, int flags)
-{
-       struct intel_uncore_box *box = uncore_event_to_box(event);
-       int i;
-
-       snb_uncore_imc_event_stop(event, PERF_EF_UPDATE);
-
-       for (i = 0; i < box->n_events; i++) {
-               if (event == box->event_list[i]) {
-                       --box->n_events;
-                       break;
-               }
-       }
-}
-
-static int snb_pci2phy_map_init(int devid)
-{
-       struct pci_dev *dev = NULL;
-       int bus;
-
-       dev = pci_get_device(PCI_VENDOR_ID_INTEL, devid, dev);
-       if (!dev)
-               return -ENOTTY;
-
-       bus = dev->bus->number;
-
-       pcibus_to_physid[bus] = 0;
-
-       pci_dev_put(dev);
-
-       return 0;
-}
-
-static struct pmu snb_uncore_imc_pmu = {
-       .task_ctx_nr    = perf_invalid_context,
-       .event_init     = snb_uncore_imc_event_init,
-       .add            = snb_uncore_imc_event_add,
-       .del            = snb_uncore_imc_event_del,
-       .start          = snb_uncore_imc_event_start,
-       .stop           = snb_uncore_imc_event_stop,
-       .read           = uncore_pmu_event_read,
-};
-
-static struct intel_uncore_ops snb_uncore_imc_ops = {
-       .init_box       = snb_uncore_imc_init_box,
-       .enable_box     = snb_uncore_imc_enable_box,
-       .disable_box    = snb_uncore_imc_disable_box,
-       .disable_event  = snb_uncore_imc_disable_event,
-       .enable_event   = snb_uncore_imc_enable_event,
-       .hw_config      = snb_uncore_imc_hw_config,
-       .read_counter   = snb_uncore_imc_read_counter,
-};
-
-static struct intel_uncore_type snb_uncore_imc = {
-       .name           = "imc",
-       .num_counters   = 2,
-       .num_boxes      = 1,
-       .fixed_ctr_bits = 32,
-       .fixed_ctr      = SNB_UNCORE_PCI_IMC_CTR_BASE,
-       .event_descs    = snb_uncore_imc_events,
-       .format_group   = &snb_uncore_imc_format_group,
-       .perf_ctr       = SNB_UNCORE_PCI_IMC_DATA_READS_BASE,
-       .event_mask     = SNB_UNCORE_PCI_IMC_EVENT_MASK,
-       .ops            = &snb_uncore_imc_ops,
-       .pmu            = &snb_uncore_imc_pmu,
-};
-
-static struct intel_uncore_type *snb_pci_uncores[] = {
-       [SNB_PCI_UNCORE_IMC]    = &snb_uncore_imc,
-       NULL,
-};
-
-static const struct pci_device_id snb_uncore_pci_ids[] = {
-       { /* IMC */
-               PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_SNB_IMC),
-               .driver_data = UNCORE_PCI_DEV_DATA(SNB_PCI_UNCORE_IMC, 0),
-       },
-       { /* end: all zeroes */ },
-};
-
-static const struct pci_device_id ivb_uncore_pci_ids[] = {
-       { /* IMC */
-               PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_IVB_IMC),
-               .driver_data = UNCORE_PCI_DEV_DATA(SNB_PCI_UNCORE_IMC, 0),
-       },
-       { /* end: all zeroes */ },
-};
-
-static const struct pci_device_id hsw_uncore_pci_ids[] = {
-       { /* IMC */
-               PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_HSW_IMC),
-               .driver_data = UNCORE_PCI_DEV_DATA(SNB_PCI_UNCORE_IMC, 0),
-       },
-       { /* end: all zeroes */ },
-};
-
-static struct pci_driver snb_uncore_pci_driver = {
-       .name           = "snb_uncore",
-       .id_table       = snb_uncore_pci_ids,
-};
-
-static struct pci_driver ivb_uncore_pci_driver = {
-       .name           = "ivb_uncore",
-       .id_table       = ivb_uncore_pci_ids,
-};
-
-static struct pci_driver hsw_uncore_pci_driver = {
-       .name           = "hsw_uncore",
-       .id_table       = hsw_uncore_pci_ids,
-};
-
-/* end of Sandy Bridge uncore support */
-
-/* Nehalem uncore support */
-static void nhm_uncore_msr_disable_box(struct intel_uncore_box *box)
-{
-       wrmsrl(NHM_UNC_PERF_GLOBAL_CTL, 0);
-}
-
-static void nhm_uncore_msr_enable_box(struct intel_uncore_box *box)
-{
-       wrmsrl(NHM_UNC_PERF_GLOBAL_CTL, NHM_UNC_GLOBAL_CTL_EN_PC_ALL | NHM_UNC_GLOBAL_CTL_EN_FC);
-}
-
-static void nhm_uncore_msr_enable_event(struct intel_uncore_box *box, struct perf_event *event)
-{
-       struct hw_perf_event *hwc = &event->hw;
-
-       if (hwc->idx < UNCORE_PMC_IDX_FIXED)
-               wrmsrl(hwc->config_base, hwc->config | SNB_UNC_CTL_EN);
-       else
-               wrmsrl(hwc->config_base, NHM_UNC_FIXED_CTR_CTL_EN);
-}
-
-static struct attribute *nhm_uncore_formats_attr[] = {
-       &format_attr_event.attr,
-       &format_attr_umask.attr,
-       &format_attr_edge.attr,
-       &format_attr_inv.attr,
-       &format_attr_cmask8.attr,
-       NULL,
-};
-
-static struct attribute_group nhm_uncore_format_group = {
-       .name = "format",
-       .attrs = nhm_uncore_formats_attr,
-};
-
-static struct uncore_event_desc nhm_uncore_events[] = {
-       INTEL_UNCORE_EVENT_DESC(clockticks,                "event=0xff,umask=0x00"),
-       INTEL_UNCORE_EVENT_DESC(qmc_writes_full_any,       "event=0x2f,umask=0x0f"),
-       INTEL_UNCORE_EVENT_DESC(qmc_normal_reads_any,      "event=0x2c,umask=0x0f"),
-       INTEL_UNCORE_EVENT_DESC(qhl_request_ioh_reads,     "event=0x20,umask=0x01"),
-       INTEL_UNCORE_EVENT_DESC(qhl_request_ioh_writes,    "event=0x20,umask=0x02"),
-       INTEL_UNCORE_EVENT_DESC(qhl_request_remote_reads,  "event=0x20,umask=0x04"),
-       INTEL_UNCORE_EVENT_DESC(qhl_request_remote_writes, "event=0x20,umask=0x08"),
-       INTEL_UNCORE_EVENT_DESC(qhl_request_local_reads,   "event=0x20,umask=0x10"),
-       INTEL_UNCORE_EVENT_DESC(qhl_request_local_writes,  "event=0x20,umask=0x20"),
-       { /* end: all zeroes */ },
-};
-
-static struct intel_uncore_ops nhm_uncore_msr_ops = {
-       .disable_box    = nhm_uncore_msr_disable_box,
-       .enable_box     = nhm_uncore_msr_enable_box,
-       .disable_event  = snb_uncore_msr_disable_event,
-       .enable_event   = nhm_uncore_msr_enable_event,
-       .read_counter   = uncore_msr_read_counter,
-};
-
-static struct intel_uncore_type nhm_uncore = {
-       .name           = "",
-       .num_counters   = 8,
-       .num_boxes      = 1,
-       .perf_ctr_bits  = 48,
-       .fixed_ctr_bits = 48,
-       .event_ctl      = NHM_UNC_PERFEVTSEL0,
-       .perf_ctr       = NHM_UNC_UNCORE_PMC0,
-       .fixed_ctr      = NHM_UNC_FIXED_CTR,
-       .fixed_ctl      = NHM_UNC_FIXED_CTR_CTRL,
-       .event_mask     = NHM_UNC_RAW_EVENT_MASK,
-       .event_descs    = nhm_uncore_events,
-       .ops            = &nhm_uncore_msr_ops,
-       .format_group   = &nhm_uncore_format_group,
-};
-
-static struct intel_uncore_type *nhm_msr_uncores[] = {
-       &nhm_uncore,
-       NULL,
-};
-/* end of Nehalem uncore support */
-
-/* Nehalem-EX uncore support */
-DEFINE_UNCORE_FORMAT_ATTR(event5, event, "config:1-5");
-DEFINE_UNCORE_FORMAT_ATTR(counter, counter, "config:6-7");
-DEFINE_UNCORE_FORMAT_ATTR(match, match, "config1:0-63");
-DEFINE_UNCORE_FORMAT_ATTR(mask, mask, "config2:0-63");
-
-static void nhmex_uncore_msr_init_box(struct intel_uncore_box *box)
-{
-       wrmsrl(NHMEX_U_MSR_PMON_GLOBAL_CTL, NHMEX_U_PMON_GLOBAL_EN_ALL);
-}
-
-static void nhmex_uncore_msr_disable_box(struct intel_uncore_box *box)
-{
-       unsigned msr = uncore_msr_box_ctl(box);
-       u64 config;
-
-       if (msr) {
-               rdmsrl(msr, config);
-               config &= ~((1ULL << uncore_num_counters(box)) - 1);
-               /* WBox has a fixed counter */
-               if (uncore_msr_fixed_ctl(box))
-                       config &= ~NHMEX_W_PMON_GLOBAL_FIXED_EN;
-               wrmsrl(msr, config);
-       }
-}
-
-static void nhmex_uncore_msr_enable_box(struct intel_uncore_box *box)
-{
-       unsigned msr = uncore_msr_box_ctl(box);
-       u64 config;
-
-       if (msr) {
-               rdmsrl(msr, config);
-               config |= (1ULL << uncore_num_counters(box)) - 1;
-               /* WBox has a fixed counter */
-               if (uncore_msr_fixed_ctl(box))
-                       config |= NHMEX_W_PMON_GLOBAL_FIXED_EN;
-               wrmsrl(msr, config);
-       }
-}
-
-static void nhmex_uncore_msr_disable_event(struct intel_uncore_box *box, struct perf_event *event)
-{
-       wrmsrl(event->hw.config_base, 0);
-}
-
-static void nhmex_uncore_msr_enable_event(struct intel_uncore_box *box, struct perf_event *event)
-{
-       struct hw_perf_event *hwc = &event->hw;
-
-       if (hwc->idx >= UNCORE_PMC_IDX_FIXED)
-               wrmsrl(hwc->config_base, NHMEX_PMON_CTL_EN_BIT0);
-       else if (box->pmu->type->event_mask & NHMEX_PMON_CTL_EN_BIT0)
-               wrmsrl(hwc->config_base, hwc->config | NHMEX_PMON_CTL_EN_BIT22);
-       else
-               wrmsrl(hwc->config_base, hwc->config | NHMEX_PMON_CTL_EN_BIT0);
-}
-
-#define NHMEX_UNCORE_OPS_COMMON_INIT()                         \
-       .init_box       = nhmex_uncore_msr_init_box,            \
-       .disable_box    = nhmex_uncore_msr_disable_box,         \
-       .enable_box     = nhmex_uncore_msr_enable_box,          \
-       .disable_event  = nhmex_uncore_msr_disable_event,       \
-       .read_counter   = uncore_msr_read_counter
-
-static struct intel_uncore_ops nhmex_uncore_ops = {
-       NHMEX_UNCORE_OPS_COMMON_INIT(),
-       .enable_event   = nhmex_uncore_msr_enable_event,
-};
-
-static struct attribute *nhmex_uncore_ubox_formats_attr[] = {
-       &format_attr_event.attr,
-       &format_attr_edge.attr,
-       NULL,
-};
-
-static struct attribute_group nhmex_uncore_ubox_format_group = {
-       .name           = "format",
-       .attrs          = nhmex_uncore_ubox_formats_attr,
-};
-
-static struct intel_uncore_type nhmex_uncore_ubox = {
-       .name           = "ubox",
-       .num_counters   = 1,
-       .num_boxes      = 1,
-       .perf_ctr_bits  = 48,
-       .event_ctl      = NHMEX_U_MSR_PMON_EV_SEL,
-       .perf_ctr       = NHMEX_U_MSR_PMON_CTR,
-       .event_mask     = NHMEX_U_PMON_RAW_EVENT_MASK,
-       .box_ctl        = NHMEX_U_MSR_PMON_GLOBAL_CTL,
-       .ops            = &nhmex_uncore_ops,
-       .format_group   = &nhmex_uncore_ubox_format_group
-};
-
-static struct attribute *nhmex_uncore_cbox_formats_attr[] = {
-       &format_attr_event.attr,
-       &format_attr_umask.attr,
-       &format_attr_edge.attr,
-       &format_attr_inv.attr,
-       &format_attr_thresh8.attr,
-       NULL,
-};
-
-static struct attribute_group nhmex_uncore_cbox_format_group = {
-       .name = "format",
-       .attrs = nhmex_uncore_cbox_formats_attr,
-};
-
-/* msr offset for each instance of cbox */
-static unsigned nhmex_cbox_msr_offsets[] = {
-       0x0, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0, 0x240, 0x2c0,
-};
-
-static struct intel_uncore_type nhmex_uncore_cbox = {
-       .name                   = "cbox",
-       .num_counters           = 6,
-       .num_boxes              = 10,
-       .perf_ctr_bits          = 48,
-       .event_ctl              = NHMEX_C0_MSR_PMON_EV_SEL0,
-       .perf_ctr               = NHMEX_C0_MSR_PMON_CTR0,
-       .event_mask             = NHMEX_PMON_RAW_EVENT_MASK,
-       .box_ctl                = NHMEX_C0_MSR_PMON_GLOBAL_CTL,
-       .msr_offsets            = nhmex_cbox_msr_offsets,
-       .pair_ctr_ctl           = 1,
-       .ops                    = &nhmex_uncore_ops,
-       .format_group           = &nhmex_uncore_cbox_format_group
-};
-
-static struct uncore_event_desc nhmex_uncore_wbox_events[] = {
-       INTEL_UNCORE_EVENT_DESC(clockticks, "event=0xff,umask=0"),
-       { /* end: all zeroes */ },
-};
-
-static struct intel_uncore_type nhmex_uncore_wbox = {
-       .name                   = "wbox",
-       .num_counters           = 4,
-       .num_boxes              = 1,
-       .perf_ctr_bits          = 48,
-       .event_ctl              = NHMEX_W_MSR_PMON_CNT0,
-       .perf_ctr               = NHMEX_W_MSR_PMON_EVT_SEL0,
-       .fixed_ctr              = NHMEX_W_MSR_PMON_FIXED_CTR,
-       .fixed_ctl              = NHMEX_W_MSR_PMON_FIXED_CTL,
-       .event_mask             = NHMEX_PMON_RAW_EVENT_MASK,
-       .box_ctl                = NHMEX_W_MSR_GLOBAL_CTL,
-       .pair_ctr_ctl           = 1,
-       .event_descs            = nhmex_uncore_wbox_events,
-       .ops                    = &nhmex_uncore_ops,
-       .format_group           = &nhmex_uncore_cbox_format_group
-};
-
-static int nhmex_bbox_hw_config(struct intel_uncore_box *box, struct perf_event *event)
-{
-       struct hw_perf_event *hwc = &event->hw;
-       struct hw_perf_event_extra *reg1 = &hwc->extra_reg;
-       struct hw_perf_event_extra *reg2 = &hwc->branch_reg;
-       int ctr, ev_sel;
-
-       ctr = (hwc->config & NHMEX_B_PMON_CTR_MASK) >>
-               NHMEX_B_PMON_CTR_SHIFT;
-       ev_sel = (hwc->config & NHMEX_B_PMON_CTL_EV_SEL_MASK) >>
-                 NHMEX_B_PMON_CTL_EV_SEL_SHIFT;
-
-       /* events that do not use the match/mask registers */
-       if ((ctr == 0 && ev_sel > 0x3) || (ctr == 1 && ev_sel > 0x6) ||
-           (ctr == 2 && ev_sel != 0x4) || ctr == 3)
-               return 0;
-
-       if (box->pmu->pmu_idx == 0)
-               reg1->reg = NHMEX_B0_MSR_MATCH;
-       else
-               reg1->reg = NHMEX_B1_MSR_MATCH;
-       reg1->idx = 0;
-       reg1->config = event->attr.config1;
-       reg2->config = event->attr.config2;
-       return 0;
-}
-
-static void nhmex_bbox_msr_enable_event(struct intel_uncore_box *box, struct perf_event *event)
-{
-       struct hw_perf_event *hwc = &event->hw;
-       struct hw_perf_event_extra *reg1 = &hwc->extra_reg;
-       struct hw_perf_event_extra *reg2 = &hwc->branch_reg;
-
-       if (reg1->idx != EXTRA_REG_NONE) {
-               wrmsrl(reg1->reg, reg1->config);
-               wrmsrl(reg1->reg + 1, reg2->config);
-       }
-       wrmsrl(hwc->config_base, NHMEX_PMON_CTL_EN_BIT0 |
-               (hwc->config & NHMEX_B_PMON_CTL_EV_SEL_MASK));
-}
-
-/*
- * The Bbox has 4 counters, but each counter monitors different events.
- * Use bits 6-7 in the event config to select counter.
- */
-static struct event_constraint nhmex_uncore_bbox_constraints[] = {
-       EVENT_CONSTRAINT(0 , 1, 0xc0),
-       EVENT_CONSTRAINT(0x40, 2, 0xc0),
-       EVENT_CONSTRAINT(0x80, 4, 0xc0),
-       EVENT_CONSTRAINT(0xc0, 8, 0xc0),
-       EVENT_CONSTRAINT_END,
-};
-
-static struct attribute *nhmex_uncore_bbox_formats_attr[] = {
-       &format_attr_event5.attr,
-       &format_attr_counter.attr,
-       &format_attr_match.attr,
-       &format_attr_mask.attr,
-       NULL,
-};
-
-static struct attribute_group nhmex_uncore_bbox_format_group = {
-       .name = "format",
-       .attrs = nhmex_uncore_bbox_formats_attr,
-};
-
-static struct intel_uncore_ops nhmex_uncore_bbox_ops = {
-       NHMEX_UNCORE_OPS_COMMON_INIT(),
-       .enable_event           = nhmex_bbox_msr_enable_event,
-       .hw_config              = nhmex_bbox_hw_config,
-       .get_constraint         = uncore_get_constraint,
-       .put_constraint         = uncore_put_constraint,
-};
-
-static struct intel_uncore_type nhmex_uncore_bbox = {
-       .name                   = "bbox",
-       .num_counters           = 4,
-       .num_boxes              = 2,
-       .perf_ctr_bits          = 48,
-       .event_ctl              = NHMEX_B0_MSR_PMON_CTL0,
-       .perf_ctr               = NHMEX_B0_MSR_PMON_CTR0,
-       .event_mask             = NHMEX_B_PMON_RAW_EVENT_MASK,
-       .box_ctl                = NHMEX_B0_MSR_PMON_GLOBAL_CTL,
-       .msr_offset             = NHMEX_B_MSR_OFFSET,
-       .pair_ctr_ctl           = 1,
-       .num_shared_regs        = 1,
-       .constraints            = nhmex_uncore_bbox_constraints,
-       .ops                    = &nhmex_uncore_bbox_ops,
-       .format_group           = &nhmex_uncore_bbox_format_group
-};
-
-static int nhmex_sbox_hw_config(struct intel_uncore_box *box, struct perf_event *event)
-{
-       struct hw_perf_event *hwc = &event->hw;
-       struct hw_perf_event_extra *reg1 = &hwc->extra_reg;
-       struct hw_perf_event_extra *reg2 = &hwc->branch_reg;
-
-       /* only TO_R_PROG_EV event uses the match/mask register */
-       if ((hwc->config & NHMEX_PMON_CTL_EV_SEL_MASK) !=
-           NHMEX_S_EVENT_TO_R_PROG_EV)
-               return 0;
-
-       if (box->pmu->pmu_idx == 0)
-               reg1->reg = NHMEX_S0_MSR_MM_CFG;
-       else
-               reg1->reg = NHMEX_S1_MSR_MM_CFG;
-       reg1->idx = 0;
-       reg1->config = event->attr.config1;
-       reg2->config = event->attr.config2;
-       return 0;
-}
-
-static void nhmex_sbox_msr_enable_event(struct intel_uncore_box *box, struct perf_event *event)
-{
-       struct hw_perf_event *hwc = &event->hw;
-       struct hw_perf_event_extra *reg1 = &hwc->extra_reg;
-       struct hw_perf_event_extra *reg2 = &hwc->branch_reg;
-
-       if (reg1->idx != EXTRA_REG_NONE) {
-               wrmsrl(reg1->reg, 0);
-               wrmsrl(reg1->reg + 1, reg1->config);
-               wrmsrl(reg1->reg + 2, reg2->config);
-               wrmsrl(reg1->reg, NHMEX_S_PMON_MM_CFG_EN);
-       }
-       wrmsrl(hwc->config_base, hwc->config | NHMEX_PMON_CTL_EN_BIT22);
-}
-
-static struct attribute *nhmex_uncore_sbox_formats_attr[] = {
-       &format_attr_event.attr,
-       &format_attr_umask.attr,
-       &format_attr_edge.attr,
-       &format_attr_inv.attr,
-       &format_attr_thresh8.attr,
-       &format_attr_match.attr,
-       &format_attr_mask.attr,
-       NULL,
-};
-
-static struct attribute_group nhmex_uncore_sbox_format_group = {
-       .name                   = "format",
-       .attrs                  = nhmex_uncore_sbox_formats_attr,
-};
-
-static struct intel_uncore_ops nhmex_uncore_sbox_ops = {
-       NHMEX_UNCORE_OPS_COMMON_INIT(),
-       .enable_event           = nhmex_sbox_msr_enable_event,
-       .hw_config              = nhmex_sbox_hw_config,
-       .get_constraint         = uncore_get_constraint,
-       .put_constraint         = uncore_put_constraint,
-};
-
-static struct intel_uncore_type nhmex_uncore_sbox = {
-       .name                   = "sbox",
-       .num_counters           = 4,
-       .num_boxes              = 2,
-       .perf_ctr_bits          = 48,
-       .event_ctl              = NHMEX_S0_MSR_PMON_CTL0,
-       .perf_ctr               = NHMEX_S0_MSR_PMON_CTR0,
-       .event_mask             = NHMEX_PMON_RAW_EVENT_MASK,
-       .box_ctl                = NHMEX_S0_MSR_PMON_GLOBAL_CTL,
-       .msr_offset             = NHMEX_S_MSR_OFFSET,
-       .pair_ctr_ctl           = 1,
-       .num_shared_regs        = 1,
-       .ops                    = &nhmex_uncore_sbox_ops,
-       .format_group           = &nhmex_uncore_sbox_format_group
-};
-
-enum {
-       EXTRA_REG_NHMEX_M_FILTER,
-       EXTRA_REG_NHMEX_M_DSP,
-       EXTRA_REG_NHMEX_M_ISS,
-       EXTRA_REG_NHMEX_M_MAP,
-       EXTRA_REG_NHMEX_M_MSC_THR,
-       EXTRA_REG_NHMEX_M_PGT,
-       EXTRA_REG_NHMEX_M_PLD,
-       EXTRA_REG_NHMEX_M_ZDP_CTL_FVC,
-};
-
-static struct extra_reg nhmex_uncore_mbox_extra_regs[] = {
-       MBOX_INC_SEL_EXTAR_REG(0x0, DSP),
-       MBOX_INC_SEL_EXTAR_REG(0x4, MSC_THR),
-       MBOX_INC_SEL_EXTAR_REG(0x5, MSC_THR),
-       MBOX_INC_SEL_EXTAR_REG(0x9, ISS),
-       /* event 0xa uses two extra registers */
-       MBOX_INC_SEL_EXTAR_REG(0xa, ISS),
-       MBOX_INC_SEL_EXTAR_REG(0xa, PLD),
-       MBOX_INC_SEL_EXTAR_REG(0xb, PLD),
-       /* events 0xd ~ 0x10 use the same extra register */
-       MBOX_INC_SEL_EXTAR_REG(0xd, ZDP_CTL_FVC),
-       MBOX_INC_SEL_EXTAR_REG(0xe, ZDP_CTL_FVC),
-       MBOX_INC_SEL_EXTAR_REG(0xf, ZDP_CTL_FVC),
-       MBOX_INC_SEL_EXTAR_REG(0x10, ZDP_CTL_FVC),
-       MBOX_INC_SEL_EXTAR_REG(0x16, PGT),
-       MBOX_SET_FLAG_SEL_EXTRA_REG(0x0, DSP),
-       MBOX_SET_FLAG_SEL_EXTRA_REG(0x1, ISS),
-       MBOX_SET_FLAG_SEL_EXTRA_REG(0x5, PGT),
-       MBOX_SET_FLAG_SEL_EXTRA_REG(0x6, MAP),
-       EVENT_EXTRA_END
-};
-
-/* Nehalem-EX or Westmere-EX ? */
-static bool uncore_nhmex;
-
-static bool nhmex_mbox_get_shared_reg(struct intel_uncore_box *box, int idx, u64 config)
-{
-       struct intel_uncore_extra_reg *er;
-       unsigned long flags;
-       bool ret = false;
-       u64 mask;
-
-       if (idx < EXTRA_REG_NHMEX_M_ZDP_CTL_FVC) {
-               er = &box->shared_regs[idx];
-               raw_spin_lock_irqsave(&er->lock, flags);
-               if (!atomic_read(&er->ref) || er->config == config) {
-                       atomic_inc(&er->ref);
-                       er->config = config;
-                       ret = true;
-               }
-               raw_spin_unlock_irqrestore(&er->lock, flags);
-
-               return ret;
-       }
-       /*
-        * The ZDP_CTL_FVC MSR has 4 fields which are used to control
-        * events 0xd ~ 0x10. Besides these 4 fields, there are additional
-        * fields which are shared.
-        */
-       idx -= EXTRA_REG_NHMEX_M_ZDP_CTL_FVC;
-       if (WARN_ON_ONCE(idx >= 4))
-               return false;
+struct intel_uncore_type **uncore_msr_uncores = empty_uncore;
+struct intel_uncore_type **uncore_pci_uncores = empty_uncore;
 
-       /* mask of the shared fields */
-       if (uncore_nhmex)
-               mask = NHMEX_M_PMON_ZDP_CTL_FVC_MASK;
-       else
-               mask = WSMEX_M_PMON_ZDP_CTL_FVC_MASK;
-       er = &box->shared_regs[EXTRA_REG_NHMEX_M_ZDP_CTL_FVC];
-
-       raw_spin_lock_irqsave(&er->lock, flags);
-       /* add mask of the non-shared field if it's in use */
-       if (__BITS_VALUE(atomic_read(&er->ref), idx, 8)) {
-               if (uncore_nhmex)
-                       mask |= NHMEX_M_PMON_ZDP_CTL_FVC_EVENT_MASK(idx);
-               else
-                       mask |= WSMEX_M_PMON_ZDP_CTL_FVC_EVENT_MASK(idx);
-       }
+static bool pcidrv_registered;
+struct pci_driver *uncore_pci_driver;
+/* pci bus to socket mapping */
+int uncore_pcibus_to_physid[256] = { [0 ... 255] = -1, };
+struct pci_dev *uncore_extra_pci_dev[UNCORE_SOCKET_MAX][UNCORE_EXTRA_PCI_DEV_MAX];
 
-       if (!atomic_read(&er->ref) || !((er->config ^ config) & mask)) {
-               atomic_add(1 << (idx * 8), &er->ref);
-               if (uncore_nhmex)
-                       mask = NHMEX_M_PMON_ZDP_CTL_FVC_MASK |
-                               NHMEX_M_PMON_ZDP_CTL_FVC_EVENT_MASK(idx);
-               else
-                       mask = WSMEX_M_PMON_ZDP_CTL_FVC_MASK |
-                               WSMEX_M_PMON_ZDP_CTL_FVC_EVENT_MASK(idx);
-               er->config &= ~mask;
-               er->config |= (config & mask);
-               ret = true;
-       }
-       raw_spin_unlock_irqrestore(&er->lock, flags);
+static DEFINE_RAW_SPINLOCK(uncore_box_lock);
+/* mask of cpus that collect uncore events */
+static cpumask_t uncore_cpu_mask;
 
-       return ret;
-}
+/* constraint for the fixed counter */
+static struct event_constraint uncore_constraint_fixed =
+       EVENT_CONSTRAINT(~0ULL, 1 << UNCORE_PMC_IDX_FIXED, ~0ULL);
+struct event_constraint uncore_constraint_empty =
+       EVENT_CONSTRAINT(0, 0, 0);
 
-static void nhmex_mbox_put_shared_reg(struct intel_uncore_box *box, int idx)
+ssize_t uncore_event_show(struct kobject *kobj,
+                         struct kobj_attribute *attr, char *buf)
 {
-       struct intel_uncore_extra_reg *er;
-
-       if (idx < EXTRA_REG_NHMEX_M_ZDP_CTL_FVC) {
-               er = &box->shared_regs[idx];
-               atomic_dec(&er->ref);
-               return;
-       }
-
-       idx -= EXTRA_REG_NHMEX_M_ZDP_CTL_FVC;
-       er = &box->shared_regs[EXTRA_REG_NHMEX_M_ZDP_CTL_FVC];
-       atomic_sub(1 << (idx * 8), &er->ref);
+       struct uncore_event_desc *event =
+               container_of(attr, struct uncore_event_desc, attr);
+       return sprintf(buf, "%s", event->config);
 }
 
-static u64 nhmex_mbox_alter_er(struct perf_event *event, int new_idx, bool modify)
+struct intel_uncore_pmu *uncore_event_to_pmu(struct perf_event *event)
 {
-       struct hw_perf_event *hwc = &event->hw;
-       struct hw_perf_event_extra *reg1 = &hwc->extra_reg;
-       u64 idx, orig_idx = __BITS_VALUE(reg1->idx, 0, 8);
-       u64 config = reg1->config;
-
-       /* get the non-shared control bits and shift them */
-       idx = orig_idx - EXTRA_REG_NHMEX_M_ZDP_CTL_FVC;
-       if (uncore_nhmex)
-               config &= NHMEX_M_PMON_ZDP_CTL_FVC_EVENT_MASK(idx);
-       else
-               config &= WSMEX_M_PMON_ZDP_CTL_FVC_EVENT_MASK(idx);
-       if (new_idx > orig_idx) {
-               idx = new_idx - orig_idx;
-               config <<= 3 * idx;
-       } else {
-               idx = orig_idx - new_idx;
-               config >>= 3 * idx;
-       }
-
-       /* add the shared control bits back */
-       if (uncore_nhmex)
-               config |= NHMEX_M_PMON_ZDP_CTL_FVC_MASK & reg1->config;
-       else
-               config |= WSMEX_M_PMON_ZDP_CTL_FVC_MASK & reg1->config;
-       config |= NHMEX_M_PMON_ZDP_CTL_FVC_MASK & reg1->config;
-       if (modify) {
-               /* adjust the main event selector */
-               if (new_idx > orig_idx)
-                       hwc->config += idx << NHMEX_M_PMON_CTL_INC_SEL_SHIFT;
-               else
-                       hwc->config -= idx << NHMEX_M_PMON_CTL_INC_SEL_SHIFT;
-               reg1->config = config;
-               reg1->idx = ~0xff | new_idx;
-       }
-       return config;
+       return container_of(event->pmu, struct intel_uncore_pmu, pmu);
 }
 
-static struct event_constraint *
-nhmex_mbox_get_constraint(struct intel_uncore_box *box, struct perf_event *event)
+struct intel_uncore_box *uncore_pmu_to_box(struct intel_uncore_pmu *pmu, int cpu)
 {
-       struct hw_perf_event_extra *reg1 = &event->hw.extra_reg;
-       struct hw_perf_event_extra *reg2 = &event->hw.branch_reg;
-       int i, idx[2], alloc = 0;
-       u64 config1 = reg1->config;
-
-       idx[0] = __BITS_VALUE(reg1->idx, 0, 8);
-       idx[1] = __BITS_VALUE(reg1->idx, 1, 8);
-again:
-       for (i = 0; i < 2; i++) {
-               if (!uncore_box_is_fake(box) && (reg1->alloc & (0x1 << i)))
-                       idx[i] = 0xff;
-
-               if (idx[i] == 0xff)
-                       continue;
-
-               if (!nhmex_mbox_get_shared_reg(box, idx[i],
-                               __BITS_VALUE(config1, i, 32)))
-                       goto fail;
-               alloc |= (0x1 << i);
-       }
+       struct intel_uncore_box *box;
 
-       /* for the match/mask registers */
-       if (reg2->idx != EXTRA_REG_NONE &&
-           (uncore_box_is_fake(box) || !reg2->alloc) &&
-           !nhmex_mbox_get_shared_reg(box, reg2->idx, reg2->config))
-               goto fail;
+       box = *per_cpu_ptr(pmu->box, cpu);
+       if (box)
+               return box;
 
-       /*
-        * If it's a fake box -- as per validate_{group,event}() we
-        * shouldn't touch event state and we can avoid doing so
-        * since both will only call get_event_constraints() once
-        * on each event, this avoids the need for reg->alloc.
-        */
-       if (!uncore_box_is_fake(box)) {
-               if (idx[0] != 0xff && idx[0] != __BITS_VALUE(reg1->idx, 0, 8))
-                       nhmex_mbox_alter_er(event, idx[0], true);
-               reg1->alloc |= alloc;
-               if (reg2->idx != EXTRA_REG_NONE)
-                       reg2->alloc = 1;
-       }
-       return NULL;
-fail:
-       if (idx[0] != 0xff && !(alloc & 0x1) &&
-           idx[0] >= EXTRA_REG_NHMEX_M_ZDP_CTL_FVC) {
-               /*
-                * events 0xd ~ 0x10 are functional identical, but are
-                * controlled by different fields in the ZDP_CTL_FVC
-                * register. If we failed to take one field, try the
-                * rest 3 choices.
-                */
-               BUG_ON(__BITS_VALUE(reg1->idx, 1, 8) != 0xff);
-               idx[0] -= EXTRA_REG_NHMEX_M_ZDP_CTL_FVC;
-               idx[0] = (idx[0] + 1) % 4;
-               idx[0] += EXTRA_REG_NHMEX_M_ZDP_CTL_FVC;
-               if (idx[0] != __BITS_VALUE(reg1->idx, 0, 8)) {
-                       config1 = nhmex_mbox_alter_er(event, idx[0], false);
-                       goto again;
+       raw_spin_lock(&uncore_box_lock);
+       /* Recheck in lock to handle races. */
+       if (*per_cpu_ptr(pmu->box, cpu))
+               goto out;
+       list_for_each_entry(box, &pmu->box_list, list) {
+               if (box->phys_id == topology_physical_package_id(cpu)) {
+                       atomic_inc(&box->refcnt);
+                       *per_cpu_ptr(pmu->box, cpu) = box;
+                       break;
                }
        }
+out:
+       raw_spin_unlock(&uncore_box_lock);
 
-       if (alloc & 0x1)
-               nhmex_mbox_put_shared_reg(box, idx[0]);
-       if (alloc & 0x2)
-               nhmex_mbox_put_shared_reg(box, idx[1]);
-       return &constraint_empty;
-}
-
-static void nhmex_mbox_put_constraint(struct intel_uncore_box *box, struct perf_event *event)
-{
-       struct hw_perf_event_extra *reg1 = &event->hw.extra_reg;
-       struct hw_perf_event_extra *reg2 = &event->hw.branch_reg;
-
-       if (uncore_box_is_fake(box))
-               return;
-
-       if (reg1->alloc & 0x1)
-               nhmex_mbox_put_shared_reg(box, __BITS_VALUE(reg1->idx, 0, 8));
-       if (reg1->alloc & 0x2)
-               nhmex_mbox_put_shared_reg(box, __BITS_VALUE(reg1->idx, 1, 8));
-       reg1->alloc = 0;
-
-       if (reg2->alloc) {
-               nhmex_mbox_put_shared_reg(box, reg2->idx);
-               reg2->alloc = 0;
-       }
-}
-
-static int nhmex_mbox_extra_reg_idx(struct extra_reg *er)
-{
-       if (er->idx < EXTRA_REG_NHMEX_M_ZDP_CTL_FVC)
-               return er->idx;
-       return er->idx + (er->event >> NHMEX_M_PMON_CTL_INC_SEL_SHIFT) - 0xd;
+       return *per_cpu_ptr(pmu->box, cpu);
 }
 
-static int nhmex_mbox_hw_config(struct intel_uncore_box *box, struct perf_event *event)
+struct intel_uncore_box *uncore_event_to_box(struct perf_event *event)
 {
-       struct intel_uncore_type *type = box->pmu->type;
-       struct hw_perf_event_extra *reg1 = &event->hw.extra_reg;
-       struct hw_perf_event_extra *reg2 = &event->hw.branch_reg;
-       struct extra_reg *er;
-       unsigned msr;
-       int reg_idx = 0;
-       /*
-        * The mbox events may require 2 extra MSRs at the most. But only
-        * the lower 32 bits in these MSRs are significant, so we can use
-        * config1 to pass two MSRs' config.
-        */
-       for (er = nhmex_uncore_mbox_extra_regs; er->msr; er++) {
-               if (er->event != (event->hw.config & er->config_mask))
-                       continue;
-               if (event->attr.config1 & ~er->valid_mask)
-                       return -EINVAL;
-
-               msr = er->msr + type->msr_offset * box->pmu->pmu_idx;
-               if (WARN_ON_ONCE(msr >= 0xffff || er->idx >= 0xff))
-                       return -EINVAL;
-
-               /* always use the 32~63 bits to pass the PLD config */
-               if (er->idx == EXTRA_REG_NHMEX_M_PLD)
-                       reg_idx = 1;
-               else if (WARN_ON_ONCE(reg_idx > 0))
-                       return -EINVAL;
-
-               reg1->idx &= ~(0xff << (reg_idx * 8));
-               reg1->reg &= ~(0xffff << (reg_idx * 16));
-               reg1->idx |= nhmex_mbox_extra_reg_idx(er) << (reg_idx * 8);
-               reg1->reg |= msr << (reg_idx * 16);
-               reg1->config = event->attr.config1;
-               reg_idx++;
-       }
        /*
-        * The mbox only provides ability to perform address matching
-        * for the PLD events.
+        * perf core schedules event on the basis of cpu, uncore events are
+        * collected by one of the cpus inside a physical package.
         */
-       if (reg_idx == 2) {
-               reg2->idx = EXTRA_REG_NHMEX_M_FILTER;
-               if (event->attr.config2 & NHMEX_M_PMON_MM_CFG_EN)
-                       reg2->config = event->attr.config2;
-               else
-                       reg2->config = ~0ULL;
-               if (box->pmu->pmu_idx == 0)
-                       reg2->reg = NHMEX_M0_MSR_PMU_MM_CFG;
-               else
-                       reg2->reg = NHMEX_M1_MSR_PMU_MM_CFG;
-       }
-       return 0;
-}
-
-static u64 nhmex_mbox_shared_reg_config(struct intel_uncore_box *box, int idx)
-{
-       struct intel_uncore_extra_reg *er;
-       unsigned long flags;
-       u64 config;
-
-       if (idx < EXTRA_REG_NHMEX_M_ZDP_CTL_FVC)
-               return box->shared_regs[idx].config;
-
-       er = &box->shared_regs[EXTRA_REG_NHMEX_M_ZDP_CTL_FVC];
-       raw_spin_lock_irqsave(&er->lock, flags);
-       config = er->config;
-       raw_spin_unlock_irqrestore(&er->lock, flags);
-       return config;
-}
-
-static void nhmex_mbox_msr_enable_event(struct intel_uncore_box *box, struct perf_event *event)
-{
-       struct hw_perf_event *hwc = &event->hw;
-       struct hw_perf_event_extra *reg1 = &hwc->extra_reg;
-       struct hw_perf_event_extra *reg2 = &hwc->branch_reg;
-       int idx;
-
-       idx = __BITS_VALUE(reg1->idx, 0, 8);
-       if (idx != 0xff)
-               wrmsrl(__BITS_VALUE(reg1->reg, 0, 16),
-                       nhmex_mbox_shared_reg_config(box, idx));
-       idx = __BITS_VALUE(reg1->idx, 1, 8);
-       if (idx != 0xff)
-               wrmsrl(__BITS_VALUE(reg1->reg, 1, 16),
-                       nhmex_mbox_shared_reg_config(box, idx));
-
-       if (reg2->idx != EXTRA_REG_NONE) {
-               wrmsrl(reg2->reg, 0);
-               if (reg2->config != ~0ULL) {
-                       wrmsrl(reg2->reg + 1,
-                               reg2->config & NHMEX_M_PMON_ADDR_MATCH_MASK);
-                       wrmsrl(reg2->reg + 2, NHMEX_M_PMON_ADDR_MASK_MASK &
-                               (reg2->config >> NHMEX_M_PMON_ADDR_MASK_SHIFT));
-                       wrmsrl(reg2->reg, NHMEX_M_PMON_MM_CFG_EN);
-               }
-       }
-
-       wrmsrl(hwc->config_base, hwc->config | NHMEX_PMON_CTL_EN_BIT0);
+       return uncore_pmu_to_box(uncore_event_to_pmu(event), smp_processor_id());
 }
 
-DEFINE_UNCORE_FORMAT_ATTR(count_mode,          count_mode,     "config:2-3");
-DEFINE_UNCORE_FORMAT_ATTR(storage_mode,                storage_mode,   "config:4-5");
-DEFINE_UNCORE_FORMAT_ATTR(wrap_mode,           wrap_mode,      "config:6");
-DEFINE_UNCORE_FORMAT_ATTR(flag_mode,           flag_mode,      "config:7");
-DEFINE_UNCORE_FORMAT_ATTR(inc_sel,             inc_sel,        "config:9-13");
-DEFINE_UNCORE_FORMAT_ATTR(set_flag_sel,                set_flag_sel,   "config:19-21");
-DEFINE_UNCORE_FORMAT_ATTR(filter_cfg_en,       filter_cfg_en,  "config2:63");
-DEFINE_UNCORE_FORMAT_ATTR(filter_match,                filter_match,   "config2:0-33");
-DEFINE_UNCORE_FORMAT_ATTR(filter_mask,         filter_mask,    "config2:34-61");
-DEFINE_UNCORE_FORMAT_ATTR(dsp,                 dsp,            "config1:0-31");
-DEFINE_UNCORE_FORMAT_ATTR(thr,                 thr,            "config1:0-31");
-DEFINE_UNCORE_FORMAT_ATTR(fvc,                 fvc,            "config1:0-31");
-DEFINE_UNCORE_FORMAT_ATTR(pgt,                 pgt,            "config1:0-31");
-DEFINE_UNCORE_FORMAT_ATTR(map,                 map,            "config1:0-31");
-DEFINE_UNCORE_FORMAT_ATTR(iss,                 iss,            "config1:0-31");
-DEFINE_UNCORE_FORMAT_ATTR(pld,                 pld,            "config1:32-63");
-
-static struct attribute *nhmex_uncore_mbox_formats_attr[] = {
-       &format_attr_count_mode.attr,
-       &format_attr_storage_mode.attr,
-       &format_attr_wrap_mode.attr,
-       &format_attr_flag_mode.attr,
-       &format_attr_inc_sel.attr,
-       &format_attr_set_flag_sel.attr,
-       &format_attr_filter_cfg_en.attr,
-       &format_attr_filter_match.attr,
-       &format_attr_filter_mask.attr,
-       &format_attr_dsp.attr,
-       &format_attr_thr.attr,
-       &format_attr_fvc.attr,
-       &format_attr_pgt.attr,
-       &format_attr_map.attr,
-       &format_attr_iss.attr,
-       &format_attr_pld.attr,
-       NULL,
-};
-
-static struct attribute_group nhmex_uncore_mbox_format_group = {
-       .name           = "format",
-       .attrs          = nhmex_uncore_mbox_formats_attr,
-};
-
-static struct uncore_event_desc nhmex_uncore_mbox_events[] = {
-       INTEL_UNCORE_EVENT_DESC(bbox_cmds_read, "inc_sel=0xd,fvc=0x2800"),
-       INTEL_UNCORE_EVENT_DESC(bbox_cmds_write, "inc_sel=0xd,fvc=0x2820"),
-       { /* end: all zeroes */ },
-};
-
-static struct uncore_event_desc wsmex_uncore_mbox_events[] = {
-       INTEL_UNCORE_EVENT_DESC(bbox_cmds_read, "inc_sel=0xd,fvc=0x5000"),
-       INTEL_UNCORE_EVENT_DESC(bbox_cmds_write, "inc_sel=0xd,fvc=0x5040"),
-       { /* end: all zeroes */ },
-};
-
-static struct intel_uncore_ops nhmex_uncore_mbox_ops = {
-       NHMEX_UNCORE_OPS_COMMON_INIT(),
-       .enable_event   = nhmex_mbox_msr_enable_event,
-       .hw_config      = nhmex_mbox_hw_config,
-       .get_constraint = nhmex_mbox_get_constraint,
-       .put_constraint = nhmex_mbox_put_constraint,
-};
-
-static struct intel_uncore_type nhmex_uncore_mbox = {
-       .name                   = "mbox",
-       .num_counters           = 6,
-       .num_boxes              = 2,
-       .perf_ctr_bits          = 48,
-       .event_ctl              = NHMEX_M0_MSR_PMU_CTL0,
-       .perf_ctr               = NHMEX_M0_MSR_PMU_CNT0,
-       .event_mask             = NHMEX_M_PMON_RAW_EVENT_MASK,
-       .box_ctl                = NHMEX_M0_MSR_GLOBAL_CTL,
-       .msr_offset             = NHMEX_M_MSR_OFFSET,
-       .pair_ctr_ctl           = 1,
-       .num_shared_regs        = 8,
-       .event_descs            = nhmex_uncore_mbox_events,
-       .ops                    = &nhmex_uncore_mbox_ops,
-       .format_group           = &nhmex_uncore_mbox_format_group,
-};
-
-static void nhmex_rbox_alter_er(struct intel_uncore_box *box, struct perf_event *event)
+u64 uncore_msr_read_counter(struct intel_uncore_box *box, struct perf_event *event)
 {
-       struct hw_perf_event *hwc = &event->hw;
-       struct hw_perf_event_extra *reg1 = &hwc->extra_reg;
+       u64 count;
 
-       /* adjust the main event selector and extra register index */
-       if (reg1->idx % 2) {
-               reg1->idx--;
-               hwc->config -= 1 << NHMEX_R_PMON_CTL_EV_SEL_SHIFT;
-       } else {
-               reg1->idx++;
-               hwc->config += 1 << NHMEX_R_PMON_CTL_EV_SEL_SHIFT;
-       }
+       rdmsrl(event->hw.event_base, count);
 
-       /* adjust extra register config */
-       switch (reg1->idx % 6) {
-       case 2:
-               /* shift the 8~15 bits to the 0~7 bits */
-               reg1->config >>= 8;
-               break;
-       case 3:
-               /* shift the 0~7 bits to the 8~15 bits */
-               reg1->config <<= 8;
-               break;
-       };
+       return count;
 }
 
 /*
- * Each rbox has 4 event set which monitor PQI port 0~3 or 4~7.
- * An event set consists of 6 events, the 3rd and 4th events in
- * an event set use the same extra register. So an event set uses
- * 5 extra registers.
+ * generic get constraint function for shared match/mask registers.
  */
-static struct event_constraint *
-nhmex_rbox_get_constraint(struct intel_uncore_box *box, struct perf_event *event)
+struct event_constraint *
+uncore_get_constraint(struct intel_uncore_box *box, struct perf_event *event)
 {
-       struct hw_perf_event *hwc = &event->hw;
-       struct hw_perf_event_extra *reg1 = &hwc->extra_reg;
-       struct hw_perf_event_extra *reg2 = &hwc->branch_reg;
        struct intel_uncore_extra_reg *er;
+       struct hw_perf_event_extra *reg1 = &event->hw.extra_reg;
+       struct hw_perf_event_extra *reg2 = &event->hw.branch_reg;
        unsigned long flags;
-       int idx, er_idx;
-       u64 config1;
        bool ok = false;
 
-       if (!uncore_box_is_fake(box) && reg1->alloc)
+       /*
+        * reg->alloc can be set due to existing state, so for fake box we
+        * need to ignore this, otherwise we might fail to allocate proper
+        * fake state for this extra reg constraint.
+        */
+       if (reg1->idx == EXTRA_REG_NONE ||
+           (!uncore_box_is_fake(box) && reg1->alloc))
                return NULL;
 
-       idx = reg1->idx % 6;
-       config1 = reg1->config;
-again:
-       er_idx = idx;
-       /* the 3rd and 4th events use the same extra register */
-       if (er_idx > 2)
-               er_idx--;
-       er_idx += (reg1->idx / 6) * 5;
-
-       er = &box->shared_regs[er_idx];
+       er = &box->shared_regs[reg1->idx];
        raw_spin_lock_irqsave(&er->lock, flags);
-       if (idx < 2) {
-               if (!atomic_read(&er->ref) || er->config == reg1->config) {
-                       atomic_inc(&er->ref);
-                       er->config = reg1->config;
-                       ok = true;
-               }
-       } else if (idx == 2 || idx == 3) {
-               /*
-                * these two events use different fields in a extra register,
-                * the 0~7 bits and the 8~15 bits respectively.
-                */
-               u64 mask = 0xff << ((idx - 2) * 8);
-               if (!__BITS_VALUE(atomic_read(&er->ref), idx - 2, 8) ||
-                               !((er->config ^ config1) & mask)) {
-                       atomic_add(1 << ((idx - 2) * 8), &er->ref);
-                       er->config &= ~mask;
-                       er->config |= config1 & mask;
-                       ok = true;
-               }
-       } else {
-               if (!atomic_read(&er->ref) ||
-                               (er->config == (hwc->config >> 32) &&
-                                er->config1 == reg1->config &&
-                                er->config2 == reg2->config)) {
-                       atomic_inc(&er->ref);
-                       er->config = (hwc->config >> 32);
-                       er->config1 = reg1->config;
-                       er->config2 = reg2->config;
-                       ok = true;
-               }
+       if (!atomic_read(&er->ref) ||
+           (er->config1 == reg1->config && er->config2 == reg2->config)) {
+               atomic_inc(&er->ref);
+               er->config1 = reg1->config;
+               er->config2 = reg2->config;
+               ok = true;
        }
        raw_spin_unlock_irqrestore(&er->lock, flags);
 
-       if (!ok) {
-               /*
-                * The Rbox events are always in pairs. The paired
-                * events are functional identical, but use different
-                * extra registers. If we failed to take an extra
-                * register, try the alternative.
-                */
-               idx ^= 1;
-               if (idx != reg1->idx % 6) {
-                       if (idx == 2)
-                               config1 >>= 8;
-                       else if (idx == 3)
-                               config1 <<= 8;
-                       goto again;
-               }
-       } else {
-               if (!uncore_box_is_fake(box)) {
-                       if (idx != reg1->idx % 6)
-                               nhmex_rbox_alter_er(box, event);
+       if (ok) {
+               if (!uncore_box_is_fake(box))
                        reg1->alloc = 1;
-               }
                return NULL;
        }
-       return &constraint_empty;
+
+       return &uncore_constraint_empty;
 }
 
-static void nhmex_rbox_put_constraint(struct intel_uncore_box *box, struct perf_event *event)
+void uncore_put_constraint(struct intel_uncore_box *box, struct perf_event *event)
 {
        struct intel_uncore_extra_reg *er;
        struct hw_perf_event_extra *reg1 = &event->hw.extra_reg;
-       int idx, er_idx;
 
+       /*
+        * Only put constraint if extra reg was actually allocated. Also
+        * takes care of event which do not use an extra shared reg.
+        *
+        * Also, if this is a fake box we shouldn't touch any event state
+        * (reg->alloc) and we don't care about leaving inconsistent box
+        * state either since it will be thrown out.
+        */
        if (uncore_box_is_fake(box) || !reg1->alloc)
                return;
 
-       idx = reg1->idx % 6;
-       er_idx = idx;
-       if (er_idx > 2)
-               er_idx--;
-       er_idx += (reg1->idx / 6) * 5;
-
-       er = &box->shared_regs[er_idx];
-       if (idx == 2 || idx == 3)
-               atomic_sub(1 << ((idx - 2) * 8), &er->ref);
-       else
-               atomic_dec(&er->ref);
-
+       er = &box->shared_regs[reg1->idx];
+       atomic_dec(&er->ref);
        reg1->alloc = 0;
 }
 
-static int nhmex_rbox_hw_config(struct intel_uncore_box *box, struct perf_event *event)
-{
-       struct hw_perf_event *hwc = &event->hw;
-       struct hw_perf_event_extra *reg1 = &event->hw.extra_reg;
-       struct hw_perf_event_extra *reg2 = &event->hw.branch_reg;
-       int idx;
-
-       idx = (event->hw.config & NHMEX_R_PMON_CTL_EV_SEL_MASK) >>
-               NHMEX_R_PMON_CTL_EV_SEL_SHIFT;
-       if (idx >= 0x18)
-               return -EINVAL;
-
-       reg1->idx = idx;
-       reg1->config = event->attr.config1;
-
-       switch (idx % 6) {
-       case 4:
-       case 5:
-               hwc->config |= event->attr.config & (~0ULL << 32);
-               reg2->config = event->attr.config2;
-               break;
-       };
-       return 0;
-}
-
-static void nhmex_rbox_msr_enable_event(struct intel_uncore_box *box, struct perf_event *event)
+u64 uncore_shared_reg_config(struct intel_uncore_box *box, int idx)
 {
-       struct hw_perf_event *hwc = &event->hw;
-       struct hw_perf_event_extra *reg1 = &hwc->extra_reg;
-       struct hw_perf_event_extra *reg2 = &hwc->branch_reg;
-       int idx, port;
+       struct intel_uncore_extra_reg *er;
+       unsigned long flags;
+       u64 config;
 
-       idx = reg1->idx;
-       port = idx / 6 + box->pmu->pmu_idx * 4;
+       er = &box->shared_regs[idx];
 
-       switch (idx % 6) {
-       case 0:
-               wrmsrl(NHMEX_R_MSR_PORTN_IPERF_CFG0(port), reg1->config);
-               break;
-       case 1:
-               wrmsrl(NHMEX_R_MSR_PORTN_IPERF_CFG1(port), reg1->config);
-               break;
-       case 2:
-       case 3:
-               wrmsrl(NHMEX_R_MSR_PORTN_QLX_CFG(port),
-                       uncore_shared_reg_config(box, 2 + (idx / 6) * 5));
-               break;
-       case 4:
-               wrmsrl(NHMEX_R_MSR_PORTN_XBR_SET1_MM_CFG(port),
-                       hwc->config >> 32);
-               wrmsrl(NHMEX_R_MSR_PORTN_XBR_SET1_MATCH(port), reg1->config);
-               wrmsrl(NHMEX_R_MSR_PORTN_XBR_SET1_MASK(port), reg2->config);
-               break;
-       case 5:
-               wrmsrl(NHMEX_R_MSR_PORTN_XBR_SET2_MM_CFG(port),
-                       hwc->config >> 32);
-               wrmsrl(NHMEX_R_MSR_PORTN_XBR_SET2_MATCH(port), reg1->config);
-               wrmsrl(NHMEX_R_MSR_PORTN_XBR_SET2_MASK(port), reg2->config);
-               break;
-       };
+       raw_spin_lock_irqsave(&er->lock, flags);
+       config = er->config;
+       raw_spin_unlock_irqrestore(&er->lock, flags);
 
-       wrmsrl(hwc->config_base, NHMEX_PMON_CTL_EN_BIT0 |
-               (hwc->config & NHMEX_R_PMON_CTL_EV_SEL_MASK));
+       return config;
 }
 
-DEFINE_UNCORE_FORMAT_ATTR(xbr_mm_cfg, xbr_mm_cfg, "config:32-63");
-DEFINE_UNCORE_FORMAT_ATTR(xbr_match, xbr_match, "config1:0-63");
-DEFINE_UNCORE_FORMAT_ATTR(xbr_mask, xbr_mask, "config2:0-63");
-DEFINE_UNCORE_FORMAT_ATTR(qlx_cfg, qlx_cfg, "config1:0-15");
-DEFINE_UNCORE_FORMAT_ATTR(iperf_cfg, iperf_cfg, "config1:0-31");
-
-static struct attribute *nhmex_uncore_rbox_formats_attr[] = {
-       &format_attr_event5.attr,
-       &format_attr_xbr_mm_cfg.attr,
-       &format_attr_xbr_match.attr,
-       &format_attr_xbr_mask.attr,
-       &format_attr_qlx_cfg.attr,
-       &format_attr_iperf_cfg.attr,
-       NULL,
-};
-
-static struct attribute_group nhmex_uncore_rbox_format_group = {
-       .name = "format",
-       .attrs = nhmex_uncore_rbox_formats_attr,
-};
-
-static struct uncore_event_desc nhmex_uncore_rbox_events[] = {
-       INTEL_UNCORE_EVENT_DESC(qpi0_flit_send,         "event=0x0,iperf_cfg=0x80000000"),
-       INTEL_UNCORE_EVENT_DESC(qpi1_filt_send,         "event=0x6,iperf_cfg=0x80000000"),
-       INTEL_UNCORE_EVENT_DESC(qpi0_idle_filt,         "event=0x0,iperf_cfg=0x40000000"),
-       INTEL_UNCORE_EVENT_DESC(qpi1_idle_filt,         "event=0x6,iperf_cfg=0x40000000"),
-       INTEL_UNCORE_EVENT_DESC(qpi0_date_response,     "event=0x0,iperf_cfg=0xc4"),
-       INTEL_UNCORE_EVENT_DESC(qpi1_date_response,     "event=0x6,iperf_cfg=0xc4"),
-       { /* end: all zeroes */ },
-};
-
-static struct intel_uncore_ops nhmex_uncore_rbox_ops = {
-       NHMEX_UNCORE_OPS_COMMON_INIT(),
-       .enable_event           = nhmex_rbox_msr_enable_event,
-       .hw_config              = nhmex_rbox_hw_config,
-       .get_constraint         = nhmex_rbox_get_constraint,
-       .put_constraint         = nhmex_rbox_put_constraint,
-};
-
-static struct intel_uncore_type nhmex_uncore_rbox = {
-       .name                   = "rbox",
-       .num_counters           = 8,
-       .num_boxes              = 2,
-       .perf_ctr_bits          = 48,
-       .event_ctl              = NHMEX_R_MSR_PMON_CTL0,
-       .perf_ctr               = NHMEX_R_MSR_PMON_CNT0,
-       .event_mask             = NHMEX_R_PMON_RAW_EVENT_MASK,
-       .box_ctl                = NHMEX_R_MSR_GLOBAL_CTL,
-       .msr_offset             = NHMEX_R_MSR_OFFSET,
-       .pair_ctr_ctl           = 1,
-       .num_shared_regs        = 20,
-       .event_descs            = nhmex_uncore_rbox_events,
-       .ops                    = &nhmex_uncore_rbox_ops,
-       .format_group           = &nhmex_uncore_rbox_format_group
-};
-
-static struct intel_uncore_type *nhmex_msr_uncores[] = {
-       &nhmex_uncore_ubox,
-       &nhmex_uncore_cbox,
-       &nhmex_uncore_bbox,
-       &nhmex_uncore_sbox,
-       &nhmex_uncore_mbox,
-       &nhmex_uncore_rbox,
-       &nhmex_uncore_wbox,
-       NULL,
-};
-/* end of Nehalem-EX uncore support */
-
 static void uncore_assign_hw_event(struct intel_uncore_box *box, struct perf_event *event, int idx)
 {
        struct hw_perf_event *hwc = &event->hw;
@@ -3140,7 +170,7 @@ static void uncore_assign_hw_event(struct intel_uncore_box *box, struct perf_eve
        hwc->event_base  = uncore_perf_ctr(box, hwc->idx);
 }
 
-static void uncore_perf_event_update(struct intel_uncore_box *box, struct perf_event *event)
+void uncore_perf_event_update(struct intel_uncore_box *box, struct perf_event *event)
 {
        u64 prev_count, new_count, delta;
        int shift;
@@ -3201,14 +231,14 @@ static enum hrtimer_restart uncore_pmu_hrtimer(struct hrtimer *hrtimer)
        return HRTIMER_RESTART;
 }
 
-static void uncore_pmu_start_hrtimer(struct intel_uncore_box *box)
+void uncore_pmu_start_hrtimer(struct intel_uncore_box *box)
 {
        __hrtimer_start_range_ns(&box->hrtimer,
                        ns_to_ktime(box->hrtimer_duration), 0,
                        HRTIMER_MODE_REL_PINNED, 0);
 }
 
-static void uncore_pmu_cancel_hrtimer(struct intel_uncore_box *box)
+void uncore_pmu_cancel_hrtimer(struct intel_uncore_box *box)
 {
        hrtimer_cancel(&box->hrtimer);
 }
@@ -3291,7 +321,7 @@ uncore_get_event_constraint(struct intel_uncore_box *box, struct perf_event *eve
        }
 
        if (event->attr.config == UNCORE_FIXED_EVENT)
-               return &constraint_fixed;
+               return &uncore_constraint_fixed;
 
        if (type->constraints) {
                for_each_event_constraint(c, type->constraints) {
@@ -3496,7 +526,7 @@ static void uncore_pmu_event_del(struct perf_event *event, int flags)
        event->hw.last_tag = ~0ULL;
 }
 
-static void uncore_pmu_event_read(struct perf_event *event)
+void uncore_pmu_event_read(struct perf_event *event)
 {
        struct intel_uncore_box *box = uncore_event_to_box(event);
        uncore_perf_event_update(box, event);
@@ -3635,7 +665,7 @@ static struct attribute_group uncore_pmu_attr_group = {
        .attrs = uncore_pmu_attrs,
 };
 
-static int __init uncore_pmu_register(struct intel_uncore_pmu *pmu)
+static int uncore_pmu_register(struct intel_uncore_pmu *pmu)
 {
        int ret;
 
@@ -3758,9 +788,6 @@ fail:
        return ret;
 }
 
-static struct pci_driver *uncore_pci_driver;
-static bool pcidrv_registered;
-
 /*
  * add a pci uncore device
  */
@@ -3770,18 +797,20 @@ static int uncore_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id
        struct intel_uncore_box *box;
        struct intel_uncore_type *type;
        int phys_id;
+       bool first_box = false;
 
-       phys_id = pcibus_to_physid[pdev->bus->number];
+       phys_id = uncore_pcibus_to_physid[pdev->bus->number];
        if (phys_id < 0)
                return -ENODEV;
 
        if (UNCORE_PCI_DEV_TYPE(id->driver_data) == UNCORE_EXTRA_PCI_DEV) {
-               extra_pci_dev[phys_id][UNCORE_PCI_DEV_IDX(id->driver_data)] = pdev;
+               int idx = UNCORE_PCI_DEV_IDX(id->driver_data);
+               uncore_extra_pci_dev[phys_id][idx] = pdev;
                pci_set_drvdata(pdev, NULL);
                return 0;
        }
 
-       type = pci_uncores[UNCORE_PCI_DEV_TYPE(id->driver_data)];
+       type = uncore_pci_uncores[UNCORE_PCI_DEV_TYPE(id->driver_data)];
        box = uncore_alloc_box(type, NUMA_NO_NODE);
        if (!box)
                return -ENOMEM;
@@ -3803,9 +832,13 @@ static int uncore_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id
        pci_set_drvdata(pdev, box);
 
        raw_spin_lock(&uncore_box_lock);
+       if (list_empty(&pmu->box_list))
+               first_box = true;
        list_add_tail(&box->list, &pmu->box_list);
        raw_spin_unlock(&uncore_box_lock);
 
+       if (first_box)
+               uncore_pmu_register(pmu);
        return 0;
 }
 
@@ -3813,13 +846,14 @@ static void uncore_pci_remove(struct pci_dev *pdev)
 {
        struct intel_uncore_box *box = pci_get_drvdata(pdev);
        struct intel_uncore_pmu *pmu;
-       int i, cpu, phys_id = pcibus_to_physid[pdev->bus->number];
+       int i, cpu, phys_id = uncore_pcibus_to_physid[pdev->bus->number];
+       bool last_box = false;
 
        box = pci_get_drvdata(pdev);
        if (!box) {
                for (i = 0; i < UNCORE_EXTRA_PCI_DEV_MAX; i++) {
-                       if (extra_pci_dev[phys_id][i] == pdev) {
-                               extra_pci_dev[phys_id][i] = NULL;
+                       if (uncore_extra_pci_dev[phys_id][i] == pdev) {
+                               uncore_extra_pci_dev[phys_id][i] = NULL;
                                break;
                        }
                }
@@ -3835,6 +869,8 @@ static void uncore_pci_remove(struct pci_dev *pdev)
 
        raw_spin_lock(&uncore_box_lock);
        list_del(&box->list);
+       if (list_empty(&pmu->box_list))
+               last_box = true;
        raw_spin_unlock(&uncore_box_lock);
 
        for_each_possible_cpu(cpu) {
@@ -3846,6 +882,9 @@ static void uncore_pci_remove(struct pci_dev *pdev)
 
        WARN_ON_ONCE(atomic_read(&box->refcnt) != 1);
        kfree(box);
+
+       if (last_box)
+               perf_pmu_unregister(&pmu->pmu);
 }
 
 static int __init uncore_pci_init(void)
@@ -3854,46 +893,32 @@ static int __init uncore_pci_init(void)
 
        switch (boot_cpu_data.x86_model) {
        case 45: /* Sandy Bridge-EP */
-               ret = snbep_pci2phy_map_init(0x3ce0);
-               if (ret)
-                       return ret;
-               pci_uncores = snbep_pci_uncores;
-               uncore_pci_driver = &snbep_uncore_pci_driver;
+               ret = snbep_uncore_pci_init();
                break;
-       case 62: /* IvyTown */
-               ret = snbep_pci2phy_map_init(0x0e1e);
-               if (ret)
-                       return ret;
-               pci_uncores = ivt_pci_uncores;
-               uncore_pci_driver = &ivt_uncore_pci_driver;
+       case 62: /* Ivy Bridge-EP */
+               ret = ivbep_uncore_pci_init();
+               break;
+       case 63: /* Haswell-EP */
+               ret = hswep_uncore_pci_init();
                break;
        case 42: /* Sandy Bridge */
-               ret = snb_pci2phy_map_init(PCI_DEVICE_ID_INTEL_SNB_IMC);
-               if (ret)
-                       return ret;
-               pci_uncores = snb_pci_uncores;
-               uncore_pci_driver = &snb_uncore_pci_driver;
+               ret = snb_uncore_pci_init();
                break;
        case 58: /* Ivy Bridge */
-               ret = snb_pci2phy_map_init(PCI_DEVICE_ID_INTEL_IVB_IMC);
-               if (ret)
-                       return ret;
-               pci_uncores = snb_pci_uncores;
-               uncore_pci_driver = &ivb_uncore_pci_driver;
+               ret = ivb_uncore_pci_init();
                break;
        case 60: /* Haswell */
        case 69: /* Haswell Celeron */
-               ret = snb_pci2phy_map_init(PCI_DEVICE_ID_INTEL_HSW_IMC);
-               if (ret)
-                       return ret;
-               pci_uncores = snb_pci_uncores;
-               uncore_pci_driver = &hsw_uncore_pci_driver;
+               ret = hsw_uncore_pci_init();
                break;
        default:
                return 0;
        }
 
-       ret = uncore_types_init(pci_uncores);
+       if (ret)
+               return ret;
+
+       ret = uncore_types_init(uncore_pci_uncores);
        if (ret)
                return ret;
 
@@ -3904,7 +929,7 @@ static int __init uncore_pci_init(void)
        if (ret == 0)
                pcidrv_registered = true;
        else
-               uncore_types_exit(pci_uncores);
+               uncore_types_exit(uncore_pci_uncores);
 
        return ret;
 }
@@ -3914,7 +939,7 @@ static void __init uncore_pci_exit(void)
        if (pcidrv_registered) {
                pcidrv_registered = false;
                pci_unregister_driver(uncore_pci_driver);
-               uncore_types_exit(pci_uncores);
+               uncore_types_exit(uncore_pci_uncores);
        }
 }
 
@@ -3940,8 +965,8 @@ static void uncore_cpu_dying(int cpu)
        struct intel_uncore_box *box;
        int i, j;
 
-       for (i = 0; msr_uncores[i]; i++) {
-               type = msr_uncores[i];
+       for (i = 0; uncore_msr_uncores[i]; i++) {
+               type = uncore_msr_uncores[i];
                for (j = 0; j < type->num_boxes; j++) {
                        pmu = &type->pmus[j];
                        box = *per_cpu_ptr(pmu->box, cpu);
@@ -3961,8 +986,8 @@ static int uncore_cpu_starting(int cpu)
 
        phys_id = topology_physical_package_id(cpu);
 
-       for (i = 0; msr_uncores[i]; i++) {
-               type = msr_uncores[i];
+       for (i = 0; uncore_msr_uncores[i]; i++) {
+               type = uncore_msr_uncores[i];
                for (j = 0; j < type->num_boxes; j++) {
                        pmu = &type->pmus[j];
                        box = *per_cpu_ptr(pmu->box, cpu);
@@ -4002,8 +1027,8 @@ static int uncore_cpu_prepare(int cpu, int phys_id)
        struct intel_uncore_box *box;
        int i, j;
 
-       for (i = 0; msr_uncores[i]; i++) {
-               type = msr_uncores[i];
+       for (i = 0; uncore_msr_uncores[i]; i++) {
+               type = uncore_msr_uncores[i];
                for (j = 0; j < type->num_boxes; j++) {
                        pmu = &type->pmus[j];
                        if (pmu->func_id < 0)
@@ -4083,8 +1108,8 @@ static void uncore_event_exit_cpu(int cpu)
        if (target >= 0)
                cpumask_set_cpu(target, &uncore_cpu_mask);
 
-       uncore_change_context(msr_uncores, cpu, target);
-       uncore_change_context(pci_uncores, cpu, target);
+       uncore_change_context(uncore_msr_uncores, cpu, target);
+       uncore_change_context(uncore_pci_uncores, cpu, target);
 }
 
 static void uncore_event_init_cpu(int cpu)
@@ -4099,8 +1124,8 @@ static void uncore_event_init_cpu(int cpu)
 
        cpumask_set_cpu(cpu, &uncore_cpu_mask);
 
-       uncore_change_context(msr_uncores, -1, cpu);
-       uncore_change_context(pci_uncores, -1, cpu);
+       uncore_change_context(uncore_msr_uncores, -1, cpu);
+       uncore_change_context(uncore_pci_uncores, -1, cpu);
 }
 
 static int uncore_cpu_notifier(struct notifier_block *self,
@@ -4160,47 +1185,37 @@ static void __init uncore_cpu_setup(void *dummy)
 
 static int __init uncore_cpu_init(void)
 {
-       int ret, max_cores;
+       int ret;
 
-       max_cores = boot_cpu_data.x86_max_cores;
        switch (boot_cpu_data.x86_model) {
        case 26: /* Nehalem */
        case 30:
        case 37: /* Westmere */
        case 44:
-               msr_uncores = nhm_msr_uncores;
+               nhm_uncore_cpu_init();
                break;
        case 42: /* Sandy Bridge */
        case 58: /* Ivy Bridge */
-               if (snb_uncore_cbox.num_boxes > max_cores)
-                       snb_uncore_cbox.num_boxes = max_cores;
-               msr_uncores = snb_msr_uncores;
+               snb_uncore_cpu_init();
                break;
        case 45: /* Sandy Bridge-EP */
-               if (snbep_uncore_cbox.num_boxes > max_cores)
-                       snbep_uncore_cbox.num_boxes = max_cores;
-               msr_uncores = snbep_msr_uncores;
+               snbep_uncore_cpu_init();
                break;
        case 46: /* Nehalem-EX */
-               uncore_nhmex = true;
        case 47: /* Westmere-EX aka. Xeon E7 */
-               if (!uncore_nhmex)
-                       nhmex_uncore_mbox.event_descs = wsmex_uncore_mbox_events;
-               if (nhmex_uncore_cbox.num_boxes > max_cores)
-                       nhmex_uncore_cbox.num_boxes = max_cores;
-               msr_uncores = nhmex_msr_uncores;
+               nhmex_uncore_cpu_init();
                break;
-       case 62: /* IvyTown */
-               if (ivt_uncore_cbox.num_boxes > max_cores)
-                       ivt_uncore_cbox.num_boxes = max_cores;
-               msr_uncores = ivt_msr_uncores;
+       case 62: /* Ivy Bridge-EP */
+               ivbep_uncore_cpu_init();
+               break;
+       case 63: /* Haswell-EP */
+               hswep_uncore_cpu_init();
                break;
-
        default:
                return 0;
        }
 
-       ret = uncore_types_init(msr_uncores);
+       ret = uncore_types_init(uncore_msr_uncores);
        if (ret)
                return ret;
 
@@ -4213,16 +1228,8 @@ static int __init uncore_pmus_register(void)
        struct intel_uncore_type *type;
        int i, j;
 
-       for (i = 0; msr_uncores[i]; i++) {
-               type = msr_uncores[i];
-               for (j = 0; j < type->num_boxes; j++) {
-                       pmu = &type->pmus[j];
-                       uncore_pmu_register(pmu);
-               }
-       }
-
-       for (i = 0; pci_uncores[i]; i++) {
-               type = pci_uncores[i];
+       for (i = 0; uncore_msr_uncores[i]; i++) {
+               type = uncore_msr_uncores[i];
                for (j = 0; j < type->num_boxes; j++) {
                        pmu = &type->pmus[j];
                        uncore_pmu_register(pmu);
index 90236f0c94a90679506973efe6e56c51bfb9bb2f..18eb78bbdd1003a5f7d1d8b302b608405214741f 100644 (file)
 
 #define UNCORE_EVENT_CONSTRAINT(c, n) EVENT_CONSTRAINT(c, n, 0xff)
 
-/* SNB event control */
-#define SNB_UNC_CTL_EV_SEL_MASK                        0x000000ff
-#define SNB_UNC_CTL_UMASK_MASK                 0x0000ff00
-#define SNB_UNC_CTL_EDGE_DET                   (1 << 18)
-#define SNB_UNC_CTL_EN                         (1 << 22)
-#define SNB_UNC_CTL_INVERT                     (1 << 23)
-#define SNB_UNC_CTL_CMASK_MASK                 0x1f000000
-#define NHM_UNC_CTL_CMASK_MASK                 0xff000000
-#define NHM_UNC_FIXED_CTR_CTL_EN               (1 << 0)
-
-#define SNB_UNC_RAW_EVENT_MASK                 (SNB_UNC_CTL_EV_SEL_MASK | \
-                                                SNB_UNC_CTL_UMASK_MASK | \
-                                                SNB_UNC_CTL_EDGE_DET | \
-                                                SNB_UNC_CTL_INVERT | \
-                                                SNB_UNC_CTL_CMASK_MASK)
-
-#define NHM_UNC_RAW_EVENT_MASK                 (SNB_UNC_CTL_EV_SEL_MASK | \
-                                                SNB_UNC_CTL_UMASK_MASK | \
-                                                SNB_UNC_CTL_EDGE_DET | \
-                                                SNB_UNC_CTL_INVERT | \
-                                                NHM_UNC_CTL_CMASK_MASK)
-
-/* SNB global control register */
-#define SNB_UNC_PERF_GLOBAL_CTL                 0x391
-#define SNB_UNC_FIXED_CTR_CTRL                  0x394
-#define SNB_UNC_FIXED_CTR                       0x395
-
-/* SNB uncore global control */
-#define SNB_UNC_GLOBAL_CTL_CORE_ALL             ((1 << 4) - 1)
-#define SNB_UNC_GLOBAL_CTL_EN                   (1 << 29)
-
-/* SNB Cbo register */
-#define SNB_UNC_CBO_0_PERFEVTSEL0               0x700
-#define SNB_UNC_CBO_0_PER_CTR0                  0x706
-#define SNB_UNC_CBO_MSR_OFFSET                  0x10
-
-/* NHM global control register */
-#define NHM_UNC_PERF_GLOBAL_CTL                 0x391
-#define NHM_UNC_FIXED_CTR                       0x394
-#define NHM_UNC_FIXED_CTR_CTRL                  0x395
-
-/* NHM uncore global control */
-#define NHM_UNC_GLOBAL_CTL_EN_PC_ALL            ((1ULL << 8) - 1)
-#define NHM_UNC_GLOBAL_CTL_EN_FC                (1ULL << 32)
-
-/* NHM uncore register */
-#define NHM_UNC_PERFEVTSEL0                     0x3c0
-#define NHM_UNC_UNCORE_PMC0                     0x3b0
-
-/* SNB-EP Box level control */
-#define SNBEP_PMON_BOX_CTL_RST_CTRL    (1 << 0)
-#define SNBEP_PMON_BOX_CTL_RST_CTRS    (1 << 1)
-#define SNBEP_PMON_BOX_CTL_FRZ         (1 << 8)
-#define SNBEP_PMON_BOX_CTL_FRZ_EN      (1 << 16)
-#define SNBEP_PMON_BOX_CTL_INT         (SNBEP_PMON_BOX_CTL_RST_CTRL | \
-                                        SNBEP_PMON_BOX_CTL_RST_CTRS | \
-                                        SNBEP_PMON_BOX_CTL_FRZ_EN)
-/* SNB-EP event control */
-#define SNBEP_PMON_CTL_EV_SEL_MASK     0x000000ff
-#define SNBEP_PMON_CTL_UMASK_MASK      0x0000ff00
-#define SNBEP_PMON_CTL_RST             (1 << 17)
-#define SNBEP_PMON_CTL_EDGE_DET                (1 << 18)
-#define SNBEP_PMON_CTL_EV_SEL_EXT      (1 << 21)
-#define SNBEP_PMON_CTL_EN              (1 << 22)
-#define SNBEP_PMON_CTL_INVERT          (1 << 23)
-#define SNBEP_PMON_CTL_TRESH_MASK      0xff000000
-#define SNBEP_PMON_RAW_EVENT_MASK      (SNBEP_PMON_CTL_EV_SEL_MASK | \
-                                        SNBEP_PMON_CTL_UMASK_MASK | \
-                                        SNBEP_PMON_CTL_EDGE_DET | \
-                                        SNBEP_PMON_CTL_INVERT | \
-                                        SNBEP_PMON_CTL_TRESH_MASK)
-
-/* SNB-EP Ubox event control */
-#define SNBEP_U_MSR_PMON_CTL_TRESH_MASK                0x1f000000
-#define SNBEP_U_MSR_PMON_RAW_EVENT_MASK                \
-                               (SNBEP_PMON_CTL_EV_SEL_MASK | \
-                                SNBEP_PMON_CTL_UMASK_MASK | \
-                                SNBEP_PMON_CTL_EDGE_DET | \
-                                SNBEP_PMON_CTL_INVERT | \
-                                SNBEP_U_MSR_PMON_CTL_TRESH_MASK)
-
-#define SNBEP_CBO_PMON_CTL_TID_EN              (1 << 19)
-#define SNBEP_CBO_MSR_PMON_RAW_EVENT_MASK      (SNBEP_PMON_RAW_EVENT_MASK | \
-                                                SNBEP_CBO_PMON_CTL_TID_EN)
-
-/* SNB-EP PCU event control */
-#define SNBEP_PCU_MSR_PMON_CTL_OCC_SEL_MASK    0x0000c000
-#define SNBEP_PCU_MSR_PMON_CTL_TRESH_MASK      0x1f000000
-#define SNBEP_PCU_MSR_PMON_CTL_OCC_INVERT      (1 << 30)
-#define SNBEP_PCU_MSR_PMON_CTL_OCC_EDGE_DET    (1 << 31)
-#define SNBEP_PCU_MSR_PMON_RAW_EVENT_MASK      \
-                               (SNBEP_PMON_CTL_EV_SEL_MASK | \
-                                SNBEP_PCU_MSR_PMON_CTL_OCC_SEL_MASK | \
-                                SNBEP_PMON_CTL_EDGE_DET | \
-                                SNBEP_PMON_CTL_EV_SEL_EXT | \
-                                SNBEP_PMON_CTL_INVERT | \
-                                SNBEP_PCU_MSR_PMON_CTL_TRESH_MASK | \
-                                SNBEP_PCU_MSR_PMON_CTL_OCC_INVERT | \
-                                SNBEP_PCU_MSR_PMON_CTL_OCC_EDGE_DET)
-
-#define SNBEP_QPI_PCI_PMON_RAW_EVENT_MASK      \
-                               (SNBEP_PMON_RAW_EVENT_MASK | \
-                                SNBEP_PMON_CTL_EV_SEL_EXT)
-
-/* SNB-EP pci control register */
-#define SNBEP_PCI_PMON_BOX_CTL                 0xf4
-#define SNBEP_PCI_PMON_CTL0                    0xd8
-/* SNB-EP pci counter register */
-#define SNBEP_PCI_PMON_CTR0                    0xa0
-
-/* SNB-EP home agent register */
-#define SNBEP_HA_PCI_PMON_BOX_ADDRMATCH0       0x40
-#define SNBEP_HA_PCI_PMON_BOX_ADDRMATCH1       0x44
-#define SNBEP_HA_PCI_PMON_BOX_OPCODEMATCH      0x48
-/* SNB-EP memory controller register */
-#define SNBEP_MC_CHy_PCI_PMON_FIXED_CTL                0xf0
-#define SNBEP_MC_CHy_PCI_PMON_FIXED_CTR                0xd0
-/* SNB-EP QPI register */
-#define SNBEP_Q_Py_PCI_PMON_PKT_MATCH0         0x228
-#define SNBEP_Q_Py_PCI_PMON_PKT_MATCH1         0x22c
-#define SNBEP_Q_Py_PCI_PMON_PKT_MASK0          0x238
-#define SNBEP_Q_Py_PCI_PMON_PKT_MASK1          0x23c
-
-/* SNB-EP Ubox register */
-#define SNBEP_U_MSR_PMON_CTR0                  0xc16
-#define SNBEP_U_MSR_PMON_CTL0                  0xc10
-
-#define SNBEP_U_MSR_PMON_UCLK_FIXED_CTL                0xc08
-#define SNBEP_U_MSR_PMON_UCLK_FIXED_CTR                0xc09
-
-/* SNB-EP Cbo register */
-#define SNBEP_C0_MSR_PMON_CTR0                 0xd16
-#define SNBEP_C0_MSR_PMON_CTL0                 0xd10
-#define SNBEP_C0_MSR_PMON_BOX_CTL              0xd04
-#define SNBEP_C0_MSR_PMON_BOX_FILTER           0xd14
-#define SNBEP_CBO_MSR_OFFSET                   0x20
-
-#define SNBEP_CB0_MSR_PMON_BOX_FILTER_TID      0x1f
-#define SNBEP_CB0_MSR_PMON_BOX_FILTER_NID      0x3fc00
-#define SNBEP_CB0_MSR_PMON_BOX_FILTER_STATE    0x7c0000
-#define SNBEP_CB0_MSR_PMON_BOX_FILTER_OPC      0xff800000
-
-#define SNBEP_CBO_EVENT_EXTRA_REG(e, m, i) {   \
-       .event = (e),                           \
-       .msr = SNBEP_C0_MSR_PMON_BOX_FILTER,    \
-       .config_mask = (m),                     \
-       .idx = (i)                              \
-}
-
-/* SNB-EP PCU register */
-#define SNBEP_PCU_MSR_PMON_CTR0                        0xc36
-#define SNBEP_PCU_MSR_PMON_CTL0                        0xc30
-#define SNBEP_PCU_MSR_PMON_BOX_CTL             0xc24
-#define SNBEP_PCU_MSR_PMON_BOX_FILTER          0xc34
-#define SNBEP_PCU_MSR_PMON_BOX_FILTER_MASK     0xffffffff
-#define SNBEP_PCU_MSR_CORE_C3_CTR              0x3fc
-#define SNBEP_PCU_MSR_CORE_C6_CTR              0x3fd
-
-/* IVT event control */
-#define IVT_PMON_BOX_CTL_INT           (SNBEP_PMON_BOX_CTL_RST_CTRL | \
-                                        SNBEP_PMON_BOX_CTL_RST_CTRS)
-#define IVT_PMON_RAW_EVENT_MASK                (SNBEP_PMON_CTL_EV_SEL_MASK | \
-                                        SNBEP_PMON_CTL_UMASK_MASK | \
-                                        SNBEP_PMON_CTL_EDGE_DET | \
-                                        SNBEP_PMON_CTL_TRESH_MASK)
-/* IVT Ubox */
-#define IVT_U_MSR_PMON_GLOBAL_CTL              0xc00
-#define IVT_U_PMON_GLOBAL_FRZ_ALL              (1 << 31)
-#define IVT_U_PMON_GLOBAL_UNFRZ_ALL            (1 << 29)
-
-#define IVT_U_MSR_PMON_RAW_EVENT_MASK  \
-                               (SNBEP_PMON_CTL_EV_SEL_MASK | \
-                                SNBEP_PMON_CTL_UMASK_MASK | \
-                                SNBEP_PMON_CTL_EDGE_DET | \
-                                SNBEP_U_MSR_PMON_CTL_TRESH_MASK)
-/* IVT Cbo */
-#define IVT_CBO_MSR_PMON_RAW_EVENT_MASK                (IVT_PMON_RAW_EVENT_MASK | \
-                                                SNBEP_CBO_PMON_CTL_TID_EN)
-
-#define IVT_CB0_MSR_PMON_BOX_FILTER_TID                (0x1fULL << 0)
-#define IVT_CB0_MSR_PMON_BOX_FILTER_LINK       (0xfULL << 5)
-#define IVT_CB0_MSR_PMON_BOX_FILTER_STATE      (0x3fULL << 17)
-#define IVT_CB0_MSR_PMON_BOX_FILTER_NID                (0xffffULL << 32)
-#define IVT_CB0_MSR_PMON_BOX_FILTER_OPC                (0x1ffULL << 52)
-#define IVT_CB0_MSR_PMON_BOX_FILTER_C6         (0x1ULL << 61)
-#define IVT_CB0_MSR_PMON_BOX_FILTER_NC         (0x1ULL << 62)
-#define IVT_CB0_MSR_PMON_BOX_FILTER_IOSC       (0x1ULL << 63)
-
-/* IVT home agent */
-#define IVT_HA_PCI_PMON_CTL_Q_OCC_RST          (1 << 16)
-#define IVT_HA_PCI_PMON_RAW_EVENT_MASK         \
-                               (IVT_PMON_RAW_EVENT_MASK | \
-                                IVT_HA_PCI_PMON_CTL_Q_OCC_RST)
-/* IVT PCU */
-#define IVT_PCU_MSR_PMON_RAW_EVENT_MASK        \
-                               (SNBEP_PMON_CTL_EV_SEL_MASK | \
-                                SNBEP_PMON_CTL_EV_SEL_EXT | \
-                                SNBEP_PCU_MSR_PMON_CTL_OCC_SEL_MASK | \
-                                SNBEP_PMON_CTL_EDGE_DET | \
-                                SNBEP_PCU_MSR_PMON_CTL_TRESH_MASK | \
-                                SNBEP_PCU_MSR_PMON_CTL_OCC_INVERT | \
-                                SNBEP_PCU_MSR_PMON_CTL_OCC_EDGE_DET)
-/* IVT QPI */
-#define IVT_QPI_PCI_PMON_RAW_EVENT_MASK        \
-                               (IVT_PMON_RAW_EVENT_MASK | \
-                                SNBEP_PMON_CTL_EV_SEL_EXT)
-
-/* NHM-EX event control */
-#define NHMEX_PMON_CTL_EV_SEL_MASK     0x000000ff
-#define NHMEX_PMON_CTL_UMASK_MASK      0x0000ff00
-#define NHMEX_PMON_CTL_EN_BIT0         (1 << 0)
-#define NHMEX_PMON_CTL_EDGE_DET                (1 << 18)
-#define NHMEX_PMON_CTL_PMI_EN          (1 << 20)
-#define NHMEX_PMON_CTL_EN_BIT22                (1 << 22)
-#define NHMEX_PMON_CTL_INVERT          (1 << 23)
-#define NHMEX_PMON_CTL_TRESH_MASK      0xff000000
-#define NHMEX_PMON_RAW_EVENT_MASK      (NHMEX_PMON_CTL_EV_SEL_MASK | \
-                                        NHMEX_PMON_CTL_UMASK_MASK | \
-                                        NHMEX_PMON_CTL_EDGE_DET | \
-                                        NHMEX_PMON_CTL_INVERT | \
-                                        NHMEX_PMON_CTL_TRESH_MASK)
-
-/* NHM-EX Ubox */
-#define NHMEX_U_MSR_PMON_GLOBAL_CTL            0xc00
-#define NHMEX_U_MSR_PMON_CTR                   0xc11
-#define NHMEX_U_MSR_PMON_EV_SEL                        0xc10
-
-#define NHMEX_U_PMON_GLOBAL_EN                 (1 << 0)
-#define NHMEX_U_PMON_GLOBAL_PMI_CORE_SEL       0x0000001e
-#define NHMEX_U_PMON_GLOBAL_EN_ALL             (1 << 28)
-#define NHMEX_U_PMON_GLOBAL_RST_ALL            (1 << 29)
-#define NHMEX_U_PMON_GLOBAL_FRZ_ALL            (1 << 31)
-
-#define NHMEX_U_PMON_RAW_EVENT_MASK            \
-               (NHMEX_PMON_CTL_EV_SEL_MASK |   \
-                NHMEX_PMON_CTL_EDGE_DET)
-
-/* NHM-EX Cbox */
-#define NHMEX_C0_MSR_PMON_GLOBAL_CTL           0xd00
-#define NHMEX_C0_MSR_PMON_CTR0                 0xd11
-#define NHMEX_C0_MSR_PMON_EV_SEL0              0xd10
-#define NHMEX_C_MSR_OFFSET                     0x20
-
-/* NHM-EX Bbox */
-#define NHMEX_B0_MSR_PMON_GLOBAL_CTL           0xc20
-#define NHMEX_B0_MSR_PMON_CTR0                 0xc31
-#define NHMEX_B0_MSR_PMON_CTL0                 0xc30
-#define NHMEX_B_MSR_OFFSET                     0x40
-#define NHMEX_B0_MSR_MATCH                     0xe45
-#define NHMEX_B0_MSR_MASK                      0xe46
-#define NHMEX_B1_MSR_MATCH                     0xe4d
-#define NHMEX_B1_MSR_MASK                      0xe4e
-
-#define NHMEX_B_PMON_CTL_EN                    (1 << 0)
-#define NHMEX_B_PMON_CTL_EV_SEL_SHIFT          1
-#define NHMEX_B_PMON_CTL_EV_SEL_MASK           \
-               (0x1f << NHMEX_B_PMON_CTL_EV_SEL_SHIFT)
-#define NHMEX_B_PMON_CTR_SHIFT         6
-#define NHMEX_B_PMON_CTR_MASK          \
-               (0x3 << NHMEX_B_PMON_CTR_SHIFT)
-#define NHMEX_B_PMON_RAW_EVENT_MASK            \
-               (NHMEX_B_PMON_CTL_EV_SEL_MASK | \
-                NHMEX_B_PMON_CTR_MASK)
-
-/* NHM-EX Sbox */
-#define NHMEX_S0_MSR_PMON_GLOBAL_CTL           0xc40
-#define NHMEX_S0_MSR_PMON_CTR0                 0xc51
-#define NHMEX_S0_MSR_PMON_CTL0                 0xc50
-#define NHMEX_S_MSR_OFFSET                     0x80
-#define NHMEX_S0_MSR_MM_CFG                    0xe48
-#define NHMEX_S0_MSR_MATCH                     0xe49
-#define NHMEX_S0_MSR_MASK                      0xe4a
-#define NHMEX_S1_MSR_MM_CFG                    0xe58
-#define NHMEX_S1_MSR_MATCH                     0xe59
-#define NHMEX_S1_MSR_MASK                      0xe5a
-
-#define NHMEX_S_PMON_MM_CFG_EN                 (0x1ULL << 63)
-#define NHMEX_S_EVENT_TO_R_PROG_EV             0
-
-/* NHM-EX Mbox */
-#define NHMEX_M0_MSR_GLOBAL_CTL                        0xca0
-#define NHMEX_M0_MSR_PMU_DSP                   0xca5
-#define NHMEX_M0_MSR_PMU_ISS                   0xca6
-#define NHMEX_M0_MSR_PMU_MAP                   0xca7
-#define NHMEX_M0_MSR_PMU_MSC_THR               0xca8
-#define NHMEX_M0_MSR_PMU_PGT                   0xca9
-#define NHMEX_M0_MSR_PMU_PLD                   0xcaa
-#define NHMEX_M0_MSR_PMU_ZDP_CTL_FVC           0xcab
-#define NHMEX_M0_MSR_PMU_CTL0                  0xcb0
-#define NHMEX_M0_MSR_PMU_CNT0                  0xcb1
-#define NHMEX_M_MSR_OFFSET                     0x40
-#define NHMEX_M0_MSR_PMU_MM_CFG                        0xe54
-#define NHMEX_M1_MSR_PMU_MM_CFG                        0xe5c
-
-#define NHMEX_M_PMON_MM_CFG_EN                 (1ULL << 63)
-#define NHMEX_M_PMON_ADDR_MATCH_MASK           0x3ffffffffULL
-#define NHMEX_M_PMON_ADDR_MASK_MASK            0x7ffffffULL
-#define NHMEX_M_PMON_ADDR_MASK_SHIFT           34
-
-#define NHMEX_M_PMON_CTL_EN                    (1 << 0)
-#define NHMEX_M_PMON_CTL_PMI_EN                        (1 << 1)
-#define NHMEX_M_PMON_CTL_COUNT_MODE_SHIFT      2
-#define NHMEX_M_PMON_CTL_COUNT_MODE_MASK       \
-       (0x3 << NHMEX_M_PMON_CTL_COUNT_MODE_SHIFT)
-#define NHMEX_M_PMON_CTL_STORAGE_MODE_SHIFT    4
-#define NHMEX_M_PMON_CTL_STORAGE_MODE_MASK     \
-       (0x3 << NHMEX_M_PMON_CTL_STORAGE_MODE_SHIFT)
-#define NHMEX_M_PMON_CTL_WRAP_MODE             (1 << 6)
-#define NHMEX_M_PMON_CTL_FLAG_MODE             (1 << 7)
-#define NHMEX_M_PMON_CTL_INC_SEL_SHIFT         9
-#define NHMEX_M_PMON_CTL_INC_SEL_MASK          \
-       (0x1f << NHMEX_M_PMON_CTL_INC_SEL_SHIFT)
-#define NHMEX_M_PMON_CTL_SET_FLAG_SEL_SHIFT    19
-#define NHMEX_M_PMON_CTL_SET_FLAG_SEL_MASK     \
-       (0x7 << NHMEX_M_PMON_CTL_SET_FLAG_SEL_SHIFT)
-#define NHMEX_M_PMON_RAW_EVENT_MASK                    \
-               (NHMEX_M_PMON_CTL_COUNT_MODE_MASK |     \
-                NHMEX_M_PMON_CTL_STORAGE_MODE_MASK |   \
-                NHMEX_M_PMON_CTL_WRAP_MODE |           \
-                NHMEX_M_PMON_CTL_FLAG_MODE |           \
-                NHMEX_M_PMON_CTL_INC_SEL_MASK |        \
-                NHMEX_M_PMON_CTL_SET_FLAG_SEL_MASK)
-
-#define NHMEX_M_PMON_ZDP_CTL_FVC_MASK          (((1 << 11) - 1) | (1 << 23))
-#define NHMEX_M_PMON_ZDP_CTL_FVC_EVENT_MASK(n) (0x7ULL << (11 + 3 * (n)))
-
-#define WSMEX_M_PMON_ZDP_CTL_FVC_MASK          (((1 << 12) - 1) | (1 << 24))
-#define WSMEX_M_PMON_ZDP_CTL_FVC_EVENT_MASK(n) (0x7ULL << (12 + 3 * (n)))
-
-/*
- * use the 9~13 bits to select event If the 7th bit is not set,
- * otherwise use the 19~21 bits to select event.
- */
-#define MBOX_INC_SEL(x) ((x) << NHMEX_M_PMON_CTL_INC_SEL_SHIFT)
-#define MBOX_SET_FLAG_SEL(x) (((x) << NHMEX_M_PMON_CTL_SET_FLAG_SEL_SHIFT) | \
-                               NHMEX_M_PMON_CTL_FLAG_MODE)
-#define MBOX_INC_SEL_MASK (NHMEX_M_PMON_CTL_INC_SEL_MASK | \
-                          NHMEX_M_PMON_CTL_FLAG_MODE)
-#define MBOX_SET_FLAG_SEL_MASK (NHMEX_M_PMON_CTL_SET_FLAG_SEL_MASK | \
-                               NHMEX_M_PMON_CTL_FLAG_MODE)
-#define MBOX_INC_SEL_EXTAR_REG(c, r) \
-               EVENT_EXTRA_REG(MBOX_INC_SEL(c), NHMEX_M0_MSR_PMU_##r, \
-                               MBOX_INC_SEL_MASK, (u64)-1, NHMEX_M_##r)
-#define MBOX_SET_FLAG_SEL_EXTRA_REG(c, r) \
-               EVENT_EXTRA_REG(MBOX_SET_FLAG_SEL(c), NHMEX_M0_MSR_PMU_##r, \
-                               MBOX_SET_FLAG_SEL_MASK, \
-                               (u64)-1, NHMEX_M_##r)
-
-/* NHM-EX Rbox */
-#define NHMEX_R_MSR_GLOBAL_CTL                 0xe00
-#define NHMEX_R_MSR_PMON_CTL0                  0xe10
-#define NHMEX_R_MSR_PMON_CNT0                  0xe11
-#define NHMEX_R_MSR_OFFSET                     0x20
-
-#define NHMEX_R_MSR_PORTN_QLX_CFG(n)           \
-               ((n) < 4 ? (0xe0c + (n)) : (0xe2c + (n) - 4))
-#define NHMEX_R_MSR_PORTN_IPERF_CFG0(n)                (0xe04 + (n))
-#define NHMEX_R_MSR_PORTN_IPERF_CFG1(n)                (0xe24 + (n))
-#define NHMEX_R_MSR_PORTN_XBR_OFFSET(n)                \
-               (((n) < 4 ? 0 : 0x10) + (n) * 4)
-#define NHMEX_R_MSR_PORTN_XBR_SET1_MM_CFG(n)   \
-               (0xe60 + NHMEX_R_MSR_PORTN_XBR_OFFSET(n))
-#define NHMEX_R_MSR_PORTN_XBR_SET1_MATCH(n)    \
-               (NHMEX_R_MSR_PORTN_XBR_SET1_MM_CFG(n) + 1)
-#define NHMEX_R_MSR_PORTN_XBR_SET1_MASK(n)     \
-               (NHMEX_R_MSR_PORTN_XBR_SET1_MM_CFG(n) + 2)
-#define NHMEX_R_MSR_PORTN_XBR_SET2_MM_CFG(n)   \
-               (0xe70 + NHMEX_R_MSR_PORTN_XBR_OFFSET(n))
-#define NHMEX_R_MSR_PORTN_XBR_SET2_MATCH(n)    \
-               (NHMEX_R_MSR_PORTN_XBR_SET2_MM_CFG(n) + 1)
-#define NHMEX_R_MSR_PORTN_XBR_SET2_MASK(n)     \
-               (NHMEX_R_MSR_PORTN_XBR_SET2_MM_CFG(n) + 2)
-
-#define NHMEX_R_PMON_CTL_EN                    (1 << 0)
-#define NHMEX_R_PMON_CTL_EV_SEL_SHIFT          1
-#define NHMEX_R_PMON_CTL_EV_SEL_MASK           \
-               (0x1f << NHMEX_R_PMON_CTL_EV_SEL_SHIFT)
-#define NHMEX_R_PMON_CTL_PMI_EN                        (1 << 6)
-#define NHMEX_R_PMON_RAW_EVENT_MASK            NHMEX_R_PMON_CTL_EV_SEL_MASK
-
-/* NHM-EX Wbox */
-#define NHMEX_W_MSR_GLOBAL_CTL                 0xc80
-#define NHMEX_W_MSR_PMON_CNT0                  0xc90
-#define NHMEX_W_MSR_PMON_EVT_SEL0              0xc91
-#define NHMEX_W_MSR_PMON_FIXED_CTR             0x394
-#define NHMEX_W_MSR_PMON_FIXED_CTL             0x395
-
-#define NHMEX_W_PMON_GLOBAL_FIXED_EN           (1ULL << 31)
-
 struct intel_uncore_ops;
 struct intel_uncore_pmu;
 struct intel_uncore_box;
@@ -505,6 +116,9 @@ struct uncore_event_desc {
        const char *config;
 };
 
+ssize_t uncore_event_show(struct kobject *kobj,
+                         struct kobj_attribute *attr, char *buf);
+
 #define INTEL_UNCORE_EVENT_DESC(_name, _config)                        \
 {                                                              \
        .attr   = __ATTR(_name, 0444, uncore_event_show, NULL), \
@@ -522,15 +136,6 @@ static ssize_t __uncore_##_var##_show(struct kobject *kobj,                \
 static struct kobj_attribute format_attr_##_var =                      \
        __ATTR(_name, 0444, __uncore_##_var##_show, NULL)
 
-
-static ssize_t uncore_event_show(struct kobject *kobj,
-                               struct kobj_attribute *attr, char *buf)
-{
-       struct uncore_event_desc *event =
-               container_of(attr, struct uncore_event_desc, attr);
-       return sprintf(buf, "%s", event->config);
-}
-
 static inline unsigned uncore_pci_box_ctl(struct intel_uncore_box *box)
 {
        return box->pmu->type->box_ctl;
@@ -694,3 +299,41 @@ static inline bool uncore_box_is_fake(struct intel_uncore_box *box)
 {
        return (box->phys_id < 0);
 }
+
+struct intel_uncore_pmu *uncore_event_to_pmu(struct perf_event *event);
+struct intel_uncore_box *uncore_pmu_to_box(struct intel_uncore_pmu *pmu, int cpu);
+struct intel_uncore_box *uncore_event_to_box(struct perf_event *event);
+u64 uncore_msr_read_counter(struct intel_uncore_box *box, struct perf_event *event);
+void uncore_pmu_start_hrtimer(struct intel_uncore_box *box);
+void uncore_pmu_cancel_hrtimer(struct intel_uncore_box *box);
+void uncore_pmu_event_read(struct perf_event *event);
+void uncore_perf_event_update(struct intel_uncore_box *box, struct perf_event *event);
+struct event_constraint *
+uncore_get_constraint(struct intel_uncore_box *box, struct perf_event *event);
+void uncore_put_constraint(struct intel_uncore_box *box, struct perf_event *event);
+u64 uncore_shared_reg_config(struct intel_uncore_box *box, int idx);
+
+extern struct intel_uncore_type **uncore_msr_uncores;
+extern struct intel_uncore_type **uncore_pci_uncores;
+extern struct pci_driver *uncore_pci_driver;
+extern int uncore_pcibus_to_physid[256];
+extern struct pci_dev *uncore_extra_pci_dev[UNCORE_SOCKET_MAX][UNCORE_EXTRA_PCI_DEV_MAX];
+extern struct event_constraint uncore_constraint_empty;
+
+/* perf_event_intel_uncore_snb.c */
+int snb_uncore_pci_init(void);
+int ivb_uncore_pci_init(void);
+int hsw_uncore_pci_init(void);
+void snb_uncore_cpu_init(void);
+void nhm_uncore_cpu_init(void);
+
+/* perf_event_intel_uncore_snbep.c */
+int snbep_uncore_pci_init(void);
+void snbep_uncore_cpu_init(void);
+int ivbep_uncore_pci_init(void);
+void ivbep_uncore_cpu_init(void);
+int hswep_uncore_pci_init(void);
+void hswep_uncore_cpu_init(void);
+
+/* perf_event_intel_uncore_nhmex.c */
+void nhmex_uncore_cpu_init(void);
diff --git a/arch/x86/kernel/cpu/perf_event_intel_uncore_nhmex.c b/arch/x86/kernel/cpu/perf_event_intel_uncore_nhmex.c
new file mode 100644 (file)
index 0000000..2749965
--- /dev/null
@@ -0,0 +1,1221 @@
+/* Nehalem-EX/Westmere-EX uncore support */
+#include "perf_event_intel_uncore.h"
+
+/* NHM-EX event control */
+#define NHMEX_PMON_CTL_EV_SEL_MASK     0x000000ff
+#define NHMEX_PMON_CTL_UMASK_MASK      0x0000ff00
+#define NHMEX_PMON_CTL_EN_BIT0         (1 << 0)
+#define NHMEX_PMON_CTL_EDGE_DET                (1 << 18)
+#define NHMEX_PMON_CTL_PMI_EN          (1 << 20)
+#define NHMEX_PMON_CTL_EN_BIT22                (1 << 22)
+#define NHMEX_PMON_CTL_INVERT          (1 << 23)
+#define NHMEX_PMON_CTL_TRESH_MASK      0xff000000
+#define NHMEX_PMON_RAW_EVENT_MASK      (NHMEX_PMON_CTL_EV_SEL_MASK | \
+                                        NHMEX_PMON_CTL_UMASK_MASK | \
+                                        NHMEX_PMON_CTL_EDGE_DET | \
+                                        NHMEX_PMON_CTL_INVERT | \
+                                        NHMEX_PMON_CTL_TRESH_MASK)
+
+/* NHM-EX Ubox */
+#define NHMEX_U_MSR_PMON_GLOBAL_CTL            0xc00
+#define NHMEX_U_MSR_PMON_CTR                   0xc11
+#define NHMEX_U_MSR_PMON_EV_SEL                        0xc10
+
+#define NHMEX_U_PMON_GLOBAL_EN                 (1 << 0)
+#define NHMEX_U_PMON_GLOBAL_PMI_CORE_SEL       0x0000001e
+#define NHMEX_U_PMON_GLOBAL_EN_ALL             (1 << 28)
+#define NHMEX_U_PMON_GLOBAL_RST_ALL            (1 << 29)
+#define NHMEX_U_PMON_GLOBAL_FRZ_ALL            (1 << 31)
+
+#define NHMEX_U_PMON_RAW_EVENT_MASK            \
+               (NHMEX_PMON_CTL_EV_SEL_MASK |   \
+                NHMEX_PMON_CTL_EDGE_DET)
+
+/* NHM-EX Cbox */
+#define NHMEX_C0_MSR_PMON_GLOBAL_CTL           0xd00
+#define NHMEX_C0_MSR_PMON_CTR0                 0xd11
+#define NHMEX_C0_MSR_PMON_EV_SEL0              0xd10
+#define NHMEX_C_MSR_OFFSET                     0x20
+
+/* NHM-EX Bbox */
+#define NHMEX_B0_MSR_PMON_GLOBAL_CTL           0xc20
+#define NHMEX_B0_MSR_PMON_CTR0                 0xc31
+#define NHMEX_B0_MSR_PMON_CTL0                 0xc30
+#define NHMEX_B_MSR_OFFSET                     0x40
+#define NHMEX_B0_MSR_MATCH                     0xe45
+#define NHMEX_B0_MSR_MASK                      0xe46
+#define NHMEX_B1_MSR_MATCH                     0xe4d
+#define NHMEX_B1_MSR_MASK                      0xe4e
+
+#define NHMEX_B_PMON_CTL_EN                    (1 << 0)
+#define NHMEX_B_PMON_CTL_EV_SEL_SHIFT          1
+#define NHMEX_B_PMON_CTL_EV_SEL_MASK           \
+               (0x1f << NHMEX_B_PMON_CTL_EV_SEL_SHIFT)
+#define NHMEX_B_PMON_CTR_SHIFT         6
+#define NHMEX_B_PMON_CTR_MASK          \
+               (0x3 << NHMEX_B_PMON_CTR_SHIFT)
+#define NHMEX_B_PMON_RAW_EVENT_MASK            \
+               (NHMEX_B_PMON_CTL_EV_SEL_MASK | \
+                NHMEX_B_PMON_CTR_MASK)
+
+/* NHM-EX Sbox */
+#define NHMEX_S0_MSR_PMON_GLOBAL_CTL           0xc40
+#define NHMEX_S0_MSR_PMON_CTR0                 0xc51
+#define NHMEX_S0_MSR_PMON_CTL0                 0xc50
+#define NHMEX_S_MSR_OFFSET                     0x80
+#define NHMEX_S0_MSR_MM_CFG                    0xe48
+#define NHMEX_S0_MSR_MATCH                     0xe49
+#define NHMEX_S0_MSR_MASK                      0xe4a
+#define NHMEX_S1_MSR_MM_CFG                    0xe58
+#define NHMEX_S1_MSR_MATCH                     0xe59
+#define NHMEX_S1_MSR_MASK                      0xe5a
+
+#define NHMEX_S_PMON_MM_CFG_EN                 (0x1ULL << 63)
+#define NHMEX_S_EVENT_TO_R_PROG_EV             0
+
+/* NHM-EX Mbox */
+#define NHMEX_M0_MSR_GLOBAL_CTL                        0xca0
+#define NHMEX_M0_MSR_PMU_DSP                   0xca5
+#define NHMEX_M0_MSR_PMU_ISS                   0xca6
+#define NHMEX_M0_MSR_PMU_MAP                   0xca7
+#define NHMEX_M0_MSR_PMU_MSC_THR               0xca8
+#define NHMEX_M0_MSR_PMU_PGT                   0xca9
+#define NHMEX_M0_MSR_PMU_PLD                   0xcaa
+#define NHMEX_M0_MSR_PMU_ZDP_CTL_FVC           0xcab
+#define NHMEX_M0_MSR_PMU_CTL0                  0xcb0
+#define NHMEX_M0_MSR_PMU_CNT0                  0xcb1
+#define NHMEX_M_MSR_OFFSET                     0x40
+#define NHMEX_M0_MSR_PMU_MM_CFG                        0xe54
+#define NHMEX_M1_MSR_PMU_MM_CFG                        0xe5c
+
+#define NHMEX_M_PMON_MM_CFG_EN                 (1ULL << 63)
+#define NHMEX_M_PMON_ADDR_MATCH_MASK           0x3ffffffffULL
+#define NHMEX_M_PMON_ADDR_MASK_MASK            0x7ffffffULL
+#define NHMEX_M_PMON_ADDR_MASK_SHIFT           34
+
+#define NHMEX_M_PMON_CTL_EN                    (1 << 0)
+#define NHMEX_M_PMON_CTL_PMI_EN                        (1 << 1)
+#define NHMEX_M_PMON_CTL_COUNT_MODE_SHIFT      2
+#define NHMEX_M_PMON_CTL_COUNT_MODE_MASK       \
+       (0x3 << NHMEX_M_PMON_CTL_COUNT_MODE_SHIFT)
+#define NHMEX_M_PMON_CTL_STORAGE_MODE_SHIFT    4
+#define NHMEX_M_PMON_CTL_STORAGE_MODE_MASK     \
+       (0x3 << NHMEX_M_PMON_CTL_STORAGE_MODE_SHIFT)
+#define NHMEX_M_PMON_CTL_WRAP_MODE             (1 << 6)
+#define NHMEX_M_PMON_CTL_FLAG_MODE             (1 << 7)
+#define NHMEX_M_PMON_CTL_INC_SEL_SHIFT         9
+#define NHMEX_M_PMON_CTL_INC_SEL_MASK          \
+       (0x1f << NHMEX_M_PMON_CTL_INC_SEL_SHIFT)
+#define NHMEX_M_PMON_CTL_SET_FLAG_SEL_SHIFT    19
+#define NHMEX_M_PMON_CTL_SET_FLAG_SEL_MASK     \
+       (0x7 << NHMEX_M_PMON_CTL_SET_FLAG_SEL_SHIFT)
+#define NHMEX_M_PMON_RAW_EVENT_MASK                    \
+               (NHMEX_M_PMON_CTL_COUNT_MODE_MASK |     \
+                NHMEX_M_PMON_CTL_STORAGE_MODE_MASK |   \
+                NHMEX_M_PMON_CTL_WRAP_MODE |           \
+                NHMEX_M_PMON_CTL_FLAG_MODE |           \
+                NHMEX_M_PMON_CTL_INC_SEL_MASK |        \
+                NHMEX_M_PMON_CTL_SET_FLAG_SEL_MASK)
+
+#define NHMEX_M_PMON_ZDP_CTL_FVC_MASK          (((1 << 11) - 1) | (1 << 23))
+#define NHMEX_M_PMON_ZDP_CTL_FVC_EVENT_MASK(n) (0x7ULL << (11 + 3 * (n)))
+
+#define WSMEX_M_PMON_ZDP_CTL_FVC_MASK          (((1 << 12) - 1) | (1 << 24))
+#define WSMEX_M_PMON_ZDP_CTL_FVC_EVENT_MASK(n) (0x7ULL << (12 + 3 * (n)))
+
+/*
+ * use the 9~13 bits to select event If the 7th bit is not set,
+ * otherwise use the 19~21 bits to select event.
+ */
+#define MBOX_INC_SEL(x) ((x) << NHMEX_M_PMON_CTL_INC_SEL_SHIFT)
+#define MBOX_SET_FLAG_SEL(x) (((x) << NHMEX_M_PMON_CTL_SET_FLAG_SEL_SHIFT) | \
+                               NHMEX_M_PMON_CTL_FLAG_MODE)
+#define MBOX_INC_SEL_MASK (NHMEX_M_PMON_CTL_INC_SEL_MASK | \
+                          NHMEX_M_PMON_CTL_FLAG_MODE)
+#define MBOX_SET_FLAG_SEL_MASK (NHMEX_M_PMON_CTL_SET_FLAG_SEL_MASK | \
+                               NHMEX_M_PMON_CTL_FLAG_MODE)
+#define MBOX_INC_SEL_EXTAR_REG(c, r) \
+               EVENT_EXTRA_REG(MBOX_INC_SEL(c), NHMEX_M0_MSR_PMU_##r, \
+                               MBOX_INC_SEL_MASK, (u64)-1, NHMEX_M_##r)
+#define MBOX_SET_FLAG_SEL_EXTRA_REG(c, r) \
+               EVENT_EXTRA_REG(MBOX_SET_FLAG_SEL(c), NHMEX_M0_MSR_PMU_##r, \
+                               MBOX_SET_FLAG_SEL_MASK, \
+                               (u64)-1, NHMEX_M_##r)
+
+/* NHM-EX Rbox */
+#define NHMEX_R_MSR_GLOBAL_CTL                 0xe00
+#define NHMEX_R_MSR_PMON_CTL0                  0xe10
+#define NHMEX_R_MSR_PMON_CNT0                  0xe11
+#define NHMEX_R_MSR_OFFSET                     0x20
+
+#define NHMEX_R_MSR_PORTN_QLX_CFG(n)           \
+               ((n) < 4 ? (0xe0c + (n)) : (0xe2c + (n) - 4))
+#define NHMEX_R_MSR_PORTN_IPERF_CFG0(n)                (0xe04 + (n))
+#define NHMEX_R_MSR_PORTN_IPERF_CFG1(n)                (0xe24 + (n))
+#define NHMEX_R_MSR_PORTN_XBR_OFFSET(n)                \
+               (((n) < 4 ? 0 : 0x10) + (n) * 4)
+#define NHMEX_R_MSR_PORTN_XBR_SET1_MM_CFG(n)   \
+               (0xe60 + NHMEX_R_MSR_PORTN_XBR_OFFSET(n))
+#define NHMEX_R_MSR_PORTN_XBR_SET1_MATCH(n)    \
+               (NHMEX_R_MSR_PORTN_XBR_SET1_MM_CFG(n) + 1)
+#define NHMEX_R_MSR_PORTN_XBR_SET1_MASK(n)     \
+               (NHMEX_R_MSR_PORTN_XBR_SET1_MM_CFG(n) + 2)
+#define NHMEX_R_MSR_PORTN_XBR_SET2_MM_CFG(n)   \
+               (0xe70 + NHMEX_R_MSR_PORTN_XBR_OFFSET(n))
+#define NHMEX_R_MSR_PORTN_XBR_SET2_MATCH(n)    \
+               (NHMEX_R_MSR_PORTN_XBR_SET2_MM_CFG(n) + 1)
+#define NHMEX_R_MSR_PORTN_XBR_SET2_MASK(n)     \
+               (NHMEX_R_MSR_PORTN_XBR_SET2_MM_CFG(n) + 2)
+
+#define NHMEX_R_PMON_CTL_EN                    (1 << 0)
+#define NHMEX_R_PMON_CTL_EV_SEL_SHIFT          1
+#define NHMEX_R_PMON_CTL_EV_SEL_MASK           \
+               (0x1f << NHMEX_R_PMON_CTL_EV_SEL_SHIFT)
+#define NHMEX_R_PMON_CTL_PMI_EN                        (1 << 6)
+#define NHMEX_R_PMON_RAW_EVENT_MASK            NHMEX_R_PMON_CTL_EV_SEL_MASK
+
+/* NHM-EX Wbox */
+#define NHMEX_W_MSR_GLOBAL_CTL                 0xc80
+#define NHMEX_W_MSR_PMON_CNT0                  0xc90
+#define NHMEX_W_MSR_PMON_EVT_SEL0              0xc91
+#define NHMEX_W_MSR_PMON_FIXED_CTR             0x394
+#define NHMEX_W_MSR_PMON_FIXED_CTL             0x395
+
+#define NHMEX_W_PMON_GLOBAL_FIXED_EN           (1ULL << 31)
+
+#define __BITS_VALUE(x, i, n)  ((typeof(x))(((x) >> ((i) * (n))) & \
+                               ((1ULL << (n)) - 1)))
+
+DEFINE_UNCORE_FORMAT_ATTR(event, event, "config:0-7");
+DEFINE_UNCORE_FORMAT_ATTR(event5, event, "config:1-5");
+DEFINE_UNCORE_FORMAT_ATTR(umask, umask, "config:8-15");
+DEFINE_UNCORE_FORMAT_ATTR(edge, edge, "config:18");
+DEFINE_UNCORE_FORMAT_ATTR(inv, inv, "config:23");
+DEFINE_UNCORE_FORMAT_ATTR(thresh8, thresh, "config:24-31");
+DEFINE_UNCORE_FORMAT_ATTR(counter, counter, "config:6-7");
+DEFINE_UNCORE_FORMAT_ATTR(match, match, "config1:0-63");
+DEFINE_UNCORE_FORMAT_ATTR(mask, mask, "config2:0-63");
+
+static void nhmex_uncore_msr_init_box(struct intel_uncore_box *box)
+{
+       wrmsrl(NHMEX_U_MSR_PMON_GLOBAL_CTL, NHMEX_U_PMON_GLOBAL_EN_ALL);
+}
+
+static void nhmex_uncore_msr_disable_box(struct intel_uncore_box *box)
+{
+       unsigned msr = uncore_msr_box_ctl(box);
+       u64 config;
+
+       if (msr) {
+               rdmsrl(msr, config);
+               config &= ~((1ULL << uncore_num_counters(box)) - 1);
+               /* WBox has a fixed counter */
+               if (uncore_msr_fixed_ctl(box))
+                       config &= ~NHMEX_W_PMON_GLOBAL_FIXED_EN;
+               wrmsrl(msr, config);
+       }
+}
+
+static void nhmex_uncore_msr_enable_box(struct intel_uncore_box *box)
+{
+       unsigned msr = uncore_msr_box_ctl(box);
+       u64 config;
+
+       if (msr) {
+               rdmsrl(msr, config);
+               config |= (1ULL << uncore_num_counters(box)) - 1;
+               /* WBox has a fixed counter */
+               if (uncore_msr_fixed_ctl(box))
+                       config |= NHMEX_W_PMON_GLOBAL_FIXED_EN;
+               wrmsrl(msr, config);
+       }
+}
+
+static void nhmex_uncore_msr_disable_event(struct intel_uncore_box *box, struct perf_event *event)
+{
+       wrmsrl(event->hw.config_base, 0);
+}
+
+static void nhmex_uncore_msr_enable_event(struct intel_uncore_box *box, struct perf_event *event)
+{
+       struct hw_perf_event *hwc = &event->hw;
+
+       if (hwc->idx >= UNCORE_PMC_IDX_FIXED)
+               wrmsrl(hwc->config_base, NHMEX_PMON_CTL_EN_BIT0);
+       else if (box->pmu->type->event_mask & NHMEX_PMON_CTL_EN_BIT0)
+               wrmsrl(hwc->config_base, hwc->config | NHMEX_PMON_CTL_EN_BIT22);
+       else
+               wrmsrl(hwc->config_base, hwc->config | NHMEX_PMON_CTL_EN_BIT0);
+}
+
+#define NHMEX_UNCORE_OPS_COMMON_INIT()                         \
+       .init_box       = nhmex_uncore_msr_init_box,            \
+       .disable_box    = nhmex_uncore_msr_disable_box,         \
+       .enable_box     = nhmex_uncore_msr_enable_box,          \
+       .disable_event  = nhmex_uncore_msr_disable_event,       \
+       .read_counter   = uncore_msr_read_counter
+
+static struct intel_uncore_ops nhmex_uncore_ops = {
+       NHMEX_UNCORE_OPS_COMMON_INIT(),
+       .enable_event   = nhmex_uncore_msr_enable_event,
+};
+
+static struct attribute *nhmex_uncore_ubox_formats_attr[] = {
+       &format_attr_event.attr,
+       &format_attr_edge.attr,
+       NULL,
+};
+
+static struct attribute_group nhmex_uncore_ubox_format_group = {
+       .name           = "format",
+       .attrs          = nhmex_uncore_ubox_formats_attr,
+};
+
+static struct intel_uncore_type nhmex_uncore_ubox = {
+       .name           = "ubox",
+       .num_counters   = 1,
+       .num_boxes      = 1,
+       .perf_ctr_bits  = 48,
+       .event_ctl      = NHMEX_U_MSR_PMON_EV_SEL,
+       .perf_ctr       = NHMEX_U_MSR_PMON_CTR,
+       .event_mask     = NHMEX_U_PMON_RAW_EVENT_MASK,
+       .box_ctl        = NHMEX_U_MSR_PMON_GLOBAL_CTL,
+       .ops            = &nhmex_uncore_ops,
+       .format_group   = &nhmex_uncore_ubox_format_group
+};
+
+static struct attribute *nhmex_uncore_cbox_formats_attr[] = {
+       &format_attr_event.attr,
+       &format_attr_umask.attr,
+       &format_attr_edge.attr,
+       &format_attr_inv.attr,
+       &format_attr_thresh8.attr,
+       NULL,
+};
+
+static struct attribute_group nhmex_uncore_cbox_format_group = {
+       .name = "format",
+       .attrs = nhmex_uncore_cbox_formats_attr,
+};
+
+/* msr offset for each instance of cbox */
+static unsigned nhmex_cbox_msr_offsets[] = {
+       0x0, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0, 0x240, 0x2c0,
+};
+
+static struct intel_uncore_type nhmex_uncore_cbox = {
+       .name                   = "cbox",
+       .num_counters           = 6,
+       .num_boxes              = 10,
+       .perf_ctr_bits          = 48,
+       .event_ctl              = NHMEX_C0_MSR_PMON_EV_SEL0,
+       .perf_ctr               = NHMEX_C0_MSR_PMON_CTR0,
+       .event_mask             = NHMEX_PMON_RAW_EVENT_MASK,
+       .box_ctl                = NHMEX_C0_MSR_PMON_GLOBAL_CTL,
+       .msr_offsets            = nhmex_cbox_msr_offsets,
+       .pair_ctr_ctl           = 1,
+       .ops                    = &nhmex_uncore_ops,
+       .format_group           = &nhmex_uncore_cbox_format_group
+};
+
+static struct uncore_event_desc nhmex_uncore_wbox_events[] = {
+       INTEL_UNCORE_EVENT_DESC(clockticks, "event=0xff,umask=0"),
+       { /* end: all zeroes */ },
+};
+
+static struct intel_uncore_type nhmex_uncore_wbox = {
+       .name                   = "wbox",
+       .num_counters           = 4,
+       .num_boxes              = 1,
+       .perf_ctr_bits          = 48,
+       .event_ctl              = NHMEX_W_MSR_PMON_CNT0,
+       .perf_ctr               = NHMEX_W_MSR_PMON_EVT_SEL0,
+       .fixed_ctr              = NHMEX_W_MSR_PMON_FIXED_CTR,
+       .fixed_ctl              = NHMEX_W_MSR_PMON_FIXED_CTL,
+       .event_mask             = NHMEX_PMON_RAW_EVENT_MASK,
+       .box_ctl                = NHMEX_W_MSR_GLOBAL_CTL,
+       .pair_ctr_ctl           = 1,
+       .event_descs            = nhmex_uncore_wbox_events,
+       .ops                    = &nhmex_uncore_ops,
+       .format_group           = &nhmex_uncore_cbox_format_group
+};
+
+static int nhmex_bbox_hw_config(struct intel_uncore_box *box, struct perf_event *event)
+{
+       struct hw_perf_event *hwc = &event->hw;
+       struct hw_perf_event_extra *reg1 = &hwc->extra_reg;
+       struct hw_perf_event_extra *reg2 = &hwc->branch_reg;
+       int ctr, ev_sel;
+
+       ctr = (hwc->config & NHMEX_B_PMON_CTR_MASK) >>
+               NHMEX_B_PMON_CTR_SHIFT;
+       ev_sel = (hwc->config & NHMEX_B_PMON_CTL_EV_SEL_MASK) >>
+                 NHMEX_B_PMON_CTL_EV_SEL_SHIFT;
+
+       /* events that do not use the match/mask registers */
+       if ((ctr == 0 && ev_sel > 0x3) || (ctr == 1 && ev_sel > 0x6) ||
+           (ctr == 2 && ev_sel != 0x4) || ctr == 3)
+               return 0;
+
+       if (box->pmu->pmu_idx == 0)
+               reg1->reg = NHMEX_B0_MSR_MATCH;
+       else
+               reg1->reg = NHMEX_B1_MSR_MATCH;
+       reg1->idx = 0;
+       reg1->config = event->attr.config1;
+       reg2->config = event->attr.config2;
+       return 0;
+}
+
+static void nhmex_bbox_msr_enable_event(struct intel_uncore_box *box, struct perf_event *event)
+{
+       struct hw_perf_event *hwc = &event->hw;
+       struct hw_perf_event_extra *reg1 = &hwc->extra_reg;
+       struct hw_perf_event_extra *reg2 = &hwc->branch_reg;
+
+       if (reg1->idx != EXTRA_REG_NONE) {
+               wrmsrl(reg1->reg, reg1->config);
+               wrmsrl(reg1->reg + 1, reg2->config);
+       }
+       wrmsrl(hwc->config_base, NHMEX_PMON_CTL_EN_BIT0 |
+               (hwc->config & NHMEX_B_PMON_CTL_EV_SEL_MASK));
+}
+
+/*
+ * The Bbox has 4 counters, but each counter monitors different events.
+ * Use bits 6-7 in the event config to select counter.
+ */
+static struct event_constraint nhmex_uncore_bbox_constraints[] = {
+       EVENT_CONSTRAINT(0 , 1, 0xc0),
+       EVENT_CONSTRAINT(0x40, 2, 0xc0),
+       EVENT_CONSTRAINT(0x80, 4, 0xc0),
+       EVENT_CONSTRAINT(0xc0, 8, 0xc0),
+       EVENT_CONSTRAINT_END,
+};
+
+static struct attribute *nhmex_uncore_bbox_formats_attr[] = {
+       &format_attr_event5.attr,
+       &format_attr_counter.attr,
+       &format_attr_match.attr,
+       &format_attr_mask.attr,
+       NULL,
+};
+
+static struct attribute_group nhmex_uncore_bbox_format_group = {
+       .name = "format",
+       .attrs = nhmex_uncore_bbox_formats_attr,
+};
+
+static struct intel_uncore_ops nhmex_uncore_bbox_ops = {
+       NHMEX_UNCORE_OPS_COMMON_INIT(),
+       .enable_event           = nhmex_bbox_msr_enable_event,
+       .hw_config              = nhmex_bbox_hw_config,
+       .get_constraint         = uncore_get_constraint,
+       .put_constraint         = uncore_put_constraint,
+};
+
+static struct intel_uncore_type nhmex_uncore_bbox = {
+       .name                   = "bbox",
+       .num_counters           = 4,
+       .num_boxes              = 2,
+       .perf_ctr_bits          = 48,
+       .event_ctl              = NHMEX_B0_MSR_PMON_CTL0,
+       .perf_ctr               = NHMEX_B0_MSR_PMON_CTR0,
+       .event_mask             = NHMEX_B_PMON_RAW_EVENT_MASK,
+       .box_ctl                = NHMEX_B0_MSR_PMON_GLOBAL_CTL,
+       .msr_offset             = NHMEX_B_MSR_OFFSET,
+       .pair_ctr_ctl           = 1,
+       .num_shared_regs        = 1,
+       .constraints            = nhmex_uncore_bbox_constraints,
+       .ops                    = &nhmex_uncore_bbox_ops,
+       .format_group           = &nhmex_uncore_bbox_format_group
+};
+
+static int nhmex_sbox_hw_config(struct intel_uncore_box *box, struct perf_event *event)
+{
+       struct hw_perf_event *hwc = &event->hw;
+       struct hw_perf_event_extra *reg1 = &hwc->extra_reg;
+       struct hw_perf_event_extra *reg2 = &hwc->branch_reg;
+
+       /* only TO_R_PROG_EV event uses the match/mask register */
+       if ((hwc->config & NHMEX_PMON_CTL_EV_SEL_MASK) !=
+           NHMEX_S_EVENT_TO_R_PROG_EV)
+               return 0;
+
+       if (box->pmu->pmu_idx == 0)
+               reg1->reg = NHMEX_S0_MSR_MM_CFG;
+       else
+               reg1->reg = NHMEX_S1_MSR_MM_CFG;
+       reg1->idx = 0;
+       reg1->config = event->attr.config1;
+       reg2->config = event->attr.config2;
+       return 0;
+}
+
+static void nhmex_sbox_msr_enable_event(struct intel_uncore_box *box, struct perf_event *event)
+{
+       struct hw_perf_event *hwc = &event->hw;
+       struct hw_perf_event_extra *reg1 = &hwc->extra_reg;
+       struct hw_perf_event_extra *reg2 = &hwc->branch_reg;
+
+       if (reg1->idx != EXTRA_REG_NONE) {
+               wrmsrl(reg1->reg, 0);
+               wrmsrl(reg1->reg + 1, reg1->config);
+               wrmsrl(reg1->reg + 2, reg2->config);
+               wrmsrl(reg1->reg, NHMEX_S_PMON_MM_CFG_EN);
+       }
+       wrmsrl(hwc->config_base, hwc->config | NHMEX_PMON_CTL_EN_BIT22);
+}
+
+static struct attribute *nhmex_uncore_sbox_formats_attr[] = {
+       &format_attr_event.attr,
+       &format_attr_umask.attr,
+       &format_attr_edge.attr,
+       &format_attr_inv.attr,
+       &format_attr_thresh8.attr,
+       &format_attr_match.attr,
+       &format_attr_mask.attr,
+       NULL,
+};
+
+static struct attribute_group nhmex_uncore_sbox_format_group = {
+       .name                   = "format",
+       .attrs                  = nhmex_uncore_sbox_formats_attr,
+};
+
+static struct intel_uncore_ops nhmex_uncore_sbox_ops = {
+       NHMEX_UNCORE_OPS_COMMON_INIT(),
+       .enable_event           = nhmex_sbox_msr_enable_event,
+       .hw_config              = nhmex_sbox_hw_config,
+       .get_constraint         = uncore_get_constraint,
+       .put_constraint         = uncore_put_constraint,
+};
+
+static struct intel_uncore_type nhmex_uncore_sbox = {
+       .name                   = "sbox",
+       .num_counters           = 4,
+       .num_boxes              = 2,
+       .perf_ctr_bits          = 48,
+       .event_ctl              = NHMEX_S0_MSR_PMON_CTL0,
+       .perf_ctr               = NHMEX_S0_MSR_PMON_CTR0,
+       .event_mask             = NHMEX_PMON_RAW_EVENT_MASK,
+       .box_ctl                = NHMEX_S0_MSR_PMON_GLOBAL_CTL,
+       .msr_offset             = NHMEX_S_MSR_OFFSET,
+       .pair_ctr_ctl           = 1,
+       .num_shared_regs        = 1,
+       .ops                    = &nhmex_uncore_sbox_ops,
+       .format_group           = &nhmex_uncore_sbox_format_group
+};
+
+enum {
+       EXTRA_REG_NHMEX_M_FILTER,
+       EXTRA_REG_NHMEX_M_DSP,
+       EXTRA_REG_NHMEX_M_ISS,
+       EXTRA_REG_NHMEX_M_MAP,
+       EXTRA_REG_NHMEX_M_MSC_THR,
+       EXTRA_REG_NHMEX_M_PGT,
+       EXTRA_REG_NHMEX_M_PLD,
+       EXTRA_REG_NHMEX_M_ZDP_CTL_FVC,
+};
+
+static struct extra_reg nhmex_uncore_mbox_extra_regs[] = {
+       MBOX_INC_SEL_EXTAR_REG(0x0, DSP),
+       MBOX_INC_SEL_EXTAR_REG(0x4, MSC_THR),
+       MBOX_INC_SEL_EXTAR_REG(0x5, MSC_THR),
+       MBOX_INC_SEL_EXTAR_REG(0x9, ISS),
+       /* event 0xa uses two extra registers */
+       MBOX_INC_SEL_EXTAR_REG(0xa, ISS),
+       MBOX_INC_SEL_EXTAR_REG(0xa, PLD),
+       MBOX_INC_SEL_EXTAR_REG(0xb, PLD),
+       /* events 0xd ~ 0x10 use the same extra register */
+       MBOX_INC_SEL_EXTAR_REG(0xd, ZDP_CTL_FVC),
+       MBOX_INC_SEL_EXTAR_REG(0xe, ZDP_CTL_FVC),
+       MBOX_INC_SEL_EXTAR_REG(0xf, ZDP_CTL_FVC),
+       MBOX_INC_SEL_EXTAR_REG(0x10, ZDP_CTL_FVC),
+       MBOX_INC_SEL_EXTAR_REG(0x16, PGT),
+       MBOX_SET_FLAG_SEL_EXTRA_REG(0x0, DSP),
+       MBOX_SET_FLAG_SEL_EXTRA_REG(0x1, ISS),
+       MBOX_SET_FLAG_SEL_EXTRA_REG(0x5, PGT),
+       MBOX_SET_FLAG_SEL_EXTRA_REG(0x6, MAP),
+       EVENT_EXTRA_END
+};
+
+/* Nehalem-EX or Westmere-EX ? */
+static bool uncore_nhmex;
+
+static bool nhmex_mbox_get_shared_reg(struct intel_uncore_box *box, int idx, u64 config)
+{
+       struct intel_uncore_extra_reg *er;
+       unsigned long flags;
+       bool ret = false;
+       u64 mask;
+
+       if (idx < EXTRA_REG_NHMEX_M_ZDP_CTL_FVC) {
+               er = &box->shared_regs[idx];
+               raw_spin_lock_irqsave(&er->lock, flags);
+               if (!atomic_read(&er->ref) || er->config == config) {
+                       atomic_inc(&er->ref);
+                       er->config = config;
+                       ret = true;
+               }
+               raw_spin_unlock_irqrestore(&er->lock, flags);
+
+               return ret;
+       }
+       /*
+        * The ZDP_CTL_FVC MSR has 4 fields which are used to control
+        * events 0xd ~ 0x10. Besides these 4 fields, there are additional
+        * fields which are shared.
+        */
+       idx -= EXTRA_REG_NHMEX_M_ZDP_CTL_FVC;
+       if (WARN_ON_ONCE(idx >= 4))
+               return false;
+
+       /* mask of the shared fields */
+       if (uncore_nhmex)
+               mask = NHMEX_M_PMON_ZDP_CTL_FVC_MASK;
+       else
+               mask = WSMEX_M_PMON_ZDP_CTL_FVC_MASK;
+       er = &box->shared_regs[EXTRA_REG_NHMEX_M_ZDP_CTL_FVC];
+
+       raw_spin_lock_irqsave(&er->lock, flags);
+       /* add mask of the non-shared field if it's in use */
+       if (__BITS_VALUE(atomic_read(&er->ref), idx, 8)) {
+               if (uncore_nhmex)
+                       mask |= NHMEX_M_PMON_ZDP_CTL_FVC_EVENT_MASK(idx);
+               else
+                       mask |= WSMEX_M_PMON_ZDP_CTL_FVC_EVENT_MASK(idx);
+       }
+
+       if (!atomic_read(&er->ref) || !((er->config ^ config) & mask)) {
+               atomic_add(1 << (idx * 8), &er->ref);
+               if (uncore_nhmex)
+                       mask = NHMEX_M_PMON_ZDP_CTL_FVC_MASK |
+                               NHMEX_M_PMON_ZDP_CTL_FVC_EVENT_MASK(idx);
+               else
+                       mask = WSMEX_M_PMON_ZDP_CTL_FVC_MASK |
+                               WSMEX_M_PMON_ZDP_CTL_FVC_EVENT_MASK(idx);
+               er->config &= ~mask;
+               er->config |= (config & mask);
+               ret = true;
+       }
+       raw_spin_unlock_irqrestore(&er->lock, flags);
+
+       return ret;
+}
+
+static void nhmex_mbox_put_shared_reg(struct intel_uncore_box *box, int idx)
+{
+       struct intel_uncore_extra_reg *er;
+
+       if (idx < EXTRA_REG_NHMEX_M_ZDP_CTL_FVC) {
+               er = &box->shared_regs[idx];
+               atomic_dec(&er->ref);
+               return;
+       }
+
+       idx -= EXTRA_REG_NHMEX_M_ZDP_CTL_FVC;
+       er = &box->shared_regs[EXTRA_REG_NHMEX_M_ZDP_CTL_FVC];
+       atomic_sub(1 << (idx * 8), &er->ref);
+}
+
+static u64 nhmex_mbox_alter_er(struct perf_event *event, int new_idx, bool modify)
+{
+       struct hw_perf_event *hwc = &event->hw;
+       struct hw_perf_event_extra *reg1 = &hwc->extra_reg;
+       u64 idx, orig_idx = __BITS_VALUE(reg1->idx, 0, 8);
+       u64 config = reg1->config;
+
+       /* get the non-shared control bits and shift them */
+       idx = orig_idx - EXTRA_REG_NHMEX_M_ZDP_CTL_FVC;
+       if (uncore_nhmex)
+               config &= NHMEX_M_PMON_ZDP_CTL_FVC_EVENT_MASK(idx);
+       else
+               config &= WSMEX_M_PMON_ZDP_CTL_FVC_EVENT_MASK(idx);
+       if (new_idx > orig_idx) {
+               idx = new_idx - orig_idx;
+               config <<= 3 * idx;
+       } else {
+               idx = orig_idx - new_idx;
+               config >>= 3 * idx;
+       }
+
+       /* add the shared control bits back */
+       if (uncore_nhmex)
+               config |= NHMEX_M_PMON_ZDP_CTL_FVC_MASK & reg1->config;
+       else
+               config |= WSMEX_M_PMON_ZDP_CTL_FVC_MASK & reg1->config;
+       config |= NHMEX_M_PMON_ZDP_CTL_FVC_MASK & reg1->config;
+       if (modify) {
+               /* adjust the main event selector */
+               if (new_idx > orig_idx)
+                       hwc->config += idx << NHMEX_M_PMON_CTL_INC_SEL_SHIFT;
+               else
+                       hwc->config -= idx << NHMEX_M_PMON_CTL_INC_SEL_SHIFT;
+               reg1->config = config;
+               reg1->idx = ~0xff | new_idx;
+       }
+       return config;
+}
+
+static struct event_constraint *
+nhmex_mbox_get_constraint(struct intel_uncore_box *box, struct perf_event *event)
+{
+       struct hw_perf_event_extra *reg1 = &event->hw.extra_reg;
+       struct hw_perf_event_extra *reg2 = &event->hw.branch_reg;
+       int i, idx[2], alloc = 0;
+       u64 config1 = reg1->config;
+
+       idx[0] = __BITS_VALUE(reg1->idx, 0, 8);
+       idx[1] = __BITS_VALUE(reg1->idx, 1, 8);
+again:
+       for (i = 0; i < 2; i++) {
+               if (!uncore_box_is_fake(box) && (reg1->alloc & (0x1 << i)))
+                       idx[i] = 0xff;
+
+               if (idx[i] == 0xff)
+                       continue;
+
+               if (!nhmex_mbox_get_shared_reg(box, idx[i],
+                               __BITS_VALUE(config1, i, 32)))
+                       goto fail;
+               alloc |= (0x1 << i);
+       }
+
+       /* for the match/mask registers */
+       if (reg2->idx != EXTRA_REG_NONE &&
+           (uncore_box_is_fake(box) || !reg2->alloc) &&
+           !nhmex_mbox_get_shared_reg(box, reg2->idx, reg2->config))
+               goto fail;
+
+       /*
+        * If it's a fake box -- as per validate_{group,event}() we
+        * shouldn't touch event state and we can avoid doing so
+        * since both will only call get_event_constraints() once
+        * on each event, this avoids the need for reg->alloc.
+        */
+       if (!uncore_box_is_fake(box)) {
+               if (idx[0] != 0xff && idx[0] != __BITS_VALUE(reg1->idx, 0, 8))
+                       nhmex_mbox_alter_er(event, idx[0], true);
+               reg1->alloc |= alloc;
+               if (reg2->idx != EXTRA_REG_NONE)
+                       reg2->alloc = 1;
+       }
+       return NULL;
+fail:
+       if (idx[0] != 0xff && !(alloc & 0x1) &&
+           idx[0] >= EXTRA_REG_NHMEX_M_ZDP_CTL_FVC) {
+               /*
+                * events 0xd ~ 0x10 are functional identical, but are
+                * controlled by different fields in the ZDP_CTL_FVC
+                * register. If we failed to take one field, try the
+                * rest 3 choices.
+                */
+               BUG_ON(__BITS_VALUE(reg1->idx, 1, 8) != 0xff);
+               idx[0] -= EXTRA_REG_NHMEX_M_ZDP_CTL_FVC;
+               idx[0] = (idx[0] + 1) % 4;
+               idx[0] += EXTRA_REG_NHMEX_M_ZDP_CTL_FVC;
+               if (idx[0] != __BITS_VALUE(reg1->idx, 0, 8)) {
+                       config1 = nhmex_mbox_alter_er(event, idx[0], false);
+                       goto again;
+               }
+       }
+
+       if (alloc & 0x1)
+               nhmex_mbox_put_shared_reg(box, idx[0]);
+       if (alloc & 0x2)
+               nhmex_mbox_put_shared_reg(box, idx[1]);
+       return &uncore_constraint_empty;
+}
+
+static void nhmex_mbox_put_constraint(struct intel_uncore_box *box, struct perf_event *event)
+{
+       struct hw_perf_event_extra *reg1 = &event->hw.extra_reg;
+       struct hw_perf_event_extra *reg2 = &event->hw.branch_reg;
+
+       if (uncore_box_is_fake(box))
+               return;
+
+       if (reg1->alloc & 0x1)
+               nhmex_mbox_put_shared_reg(box, __BITS_VALUE(reg1->idx, 0, 8));
+       if (reg1->alloc & 0x2)
+               nhmex_mbox_put_shared_reg(box, __BITS_VALUE(reg1->idx, 1, 8));
+       reg1->alloc = 0;
+
+       if (reg2->alloc) {
+               nhmex_mbox_put_shared_reg(box, reg2->idx);
+               reg2->alloc = 0;
+       }
+}
+
+static int nhmex_mbox_extra_reg_idx(struct extra_reg *er)
+{
+       if (er->idx < EXTRA_REG_NHMEX_M_ZDP_CTL_FVC)
+               return er->idx;
+       return er->idx + (er->event >> NHMEX_M_PMON_CTL_INC_SEL_SHIFT) - 0xd;
+}
+
+static int nhmex_mbox_hw_config(struct intel_uncore_box *box, struct perf_event *event)
+{
+       struct intel_uncore_type *type = box->pmu->type;
+       struct hw_perf_event_extra *reg1 = &event->hw.extra_reg;
+       struct hw_perf_event_extra *reg2 = &event->hw.branch_reg;
+       struct extra_reg *er;
+       unsigned msr;
+       int reg_idx = 0;
+       /*
+        * The mbox events may require 2 extra MSRs at the most. But only
+        * the lower 32 bits in these MSRs are significant, so we can use
+        * config1 to pass two MSRs' config.
+        */
+       for (er = nhmex_uncore_mbox_extra_regs; er->msr; er++) {
+               if (er->event != (event->hw.config & er->config_mask))
+                       continue;
+               if (event->attr.config1 & ~er->valid_mask)
+                       return -EINVAL;
+
+               msr = er->msr + type->msr_offset * box->pmu->pmu_idx;
+               if (WARN_ON_ONCE(msr >= 0xffff || er->idx >= 0xff))
+                       return -EINVAL;
+
+               /* always use the 32~63 bits to pass the PLD config */
+               if (er->idx == EXTRA_REG_NHMEX_M_PLD)
+                       reg_idx = 1;
+               else if (WARN_ON_ONCE(reg_idx > 0))
+                       return -EINVAL;
+
+               reg1->idx &= ~(0xff << (reg_idx * 8));
+               reg1->reg &= ~(0xffff << (reg_idx * 16));
+               reg1->idx |= nhmex_mbox_extra_reg_idx(er) << (reg_idx * 8);
+               reg1->reg |= msr << (reg_idx * 16);
+               reg1->config = event->attr.config1;
+               reg_idx++;
+       }
+       /*
+        * The mbox only provides ability to perform address matching
+        * for the PLD events.
+        */
+       if (reg_idx == 2) {
+               reg2->idx = EXTRA_REG_NHMEX_M_FILTER;
+               if (event->attr.config2 & NHMEX_M_PMON_MM_CFG_EN)
+                       reg2->config = event->attr.config2;
+               else
+                       reg2->config = ~0ULL;
+               if (box->pmu->pmu_idx == 0)
+                       reg2->reg = NHMEX_M0_MSR_PMU_MM_CFG;
+               else
+                       reg2->reg = NHMEX_M1_MSR_PMU_MM_CFG;
+       }
+       return 0;
+}
+
+static u64 nhmex_mbox_shared_reg_config(struct intel_uncore_box *box, int idx)
+{
+       struct intel_uncore_extra_reg *er;
+       unsigned long flags;
+       u64 config;
+
+       if (idx < EXTRA_REG_NHMEX_M_ZDP_CTL_FVC)
+               return box->shared_regs[idx].config;
+
+       er = &box->shared_regs[EXTRA_REG_NHMEX_M_ZDP_CTL_FVC];
+       raw_spin_lock_irqsave(&er->lock, flags);
+       config = er->config;
+       raw_spin_unlock_irqrestore(&er->lock, flags);
+       return config;
+}
+
+static void nhmex_mbox_msr_enable_event(struct intel_uncore_box *box, struct perf_event *event)
+{
+       struct hw_perf_event *hwc = &event->hw;
+       struct hw_perf_event_extra *reg1 = &hwc->extra_reg;
+       struct hw_perf_event_extra *reg2 = &hwc->branch_reg;
+       int idx;
+
+       idx = __BITS_VALUE(reg1->idx, 0, 8);
+       if (idx != 0xff)
+               wrmsrl(__BITS_VALUE(reg1->reg, 0, 16),
+                       nhmex_mbox_shared_reg_config(box, idx));
+       idx = __BITS_VALUE(reg1->idx, 1, 8);
+       if (idx != 0xff)
+               wrmsrl(__BITS_VALUE(reg1->reg, 1, 16),
+                       nhmex_mbox_shared_reg_config(box, idx));
+
+       if (reg2->idx != EXTRA_REG_NONE) {
+               wrmsrl(reg2->reg, 0);
+               if (reg2->config != ~0ULL) {
+                       wrmsrl(reg2->reg + 1,
+                               reg2->config & NHMEX_M_PMON_ADDR_MATCH_MASK);
+                       wrmsrl(reg2->reg + 2, NHMEX_M_PMON_ADDR_MASK_MASK &
+                               (reg2->config >> NHMEX_M_PMON_ADDR_MASK_SHIFT));
+                       wrmsrl(reg2->reg, NHMEX_M_PMON_MM_CFG_EN);
+               }
+       }
+
+       wrmsrl(hwc->config_base, hwc->config | NHMEX_PMON_CTL_EN_BIT0);
+}
+
+DEFINE_UNCORE_FORMAT_ATTR(count_mode,          count_mode,     "config:2-3");
+DEFINE_UNCORE_FORMAT_ATTR(storage_mode,                storage_mode,   "config:4-5");
+DEFINE_UNCORE_FORMAT_ATTR(wrap_mode,           wrap_mode,      "config:6");
+DEFINE_UNCORE_FORMAT_ATTR(flag_mode,           flag_mode,      "config:7");
+DEFINE_UNCORE_FORMAT_ATTR(inc_sel,             inc_sel,        "config:9-13");
+DEFINE_UNCORE_FORMAT_ATTR(set_flag_sel,                set_flag_sel,   "config:19-21");
+DEFINE_UNCORE_FORMAT_ATTR(filter_cfg_en,       filter_cfg_en,  "config2:63");
+DEFINE_UNCORE_FORMAT_ATTR(filter_match,                filter_match,   "config2:0-33");
+DEFINE_UNCORE_FORMAT_ATTR(filter_mask,         filter_mask,    "config2:34-61");
+DEFINE_UNCORE_FORMAT_ATTR(dsp,                 dsp,            "config1:0-31");
+DEFINE_UNCORE_FORMAT_ATTR(thr,                 thr,            "config1:0-31");
+DEFINE_UNCORE_FORMAT_ATTR(fvc,                 fvc,            "config1:0-31");
+DEFINE_UNCORE_FORMAT_ATTR(pgt,                 pgt,            "config1:0-31");
+DEFINE_UNCORE_FORMAT_ATTR(map,                 map,            "config1:0-31");
+DEFINE_UNCORE_FORMAT_ATTR(iss,                 iss,            "config1:0-31");
+DEFINE_UNCORE_FORMAT_ATTR(pld,                 pld,            "config1:32-63");
+
+static struct attribute *nhmex_uncore_mbox_formats_attr[] = {
+       &format_attr_count_mode.attr,
+       &format_attr_storage_mode.attr,
+       &format_attr_wrap_mode.attr,
+       &format_attr_flag_mode.attr,
+       &format_attr_inc_sel.attr,
+       &format_attr_set_flag_sel.attr,
+       &format_attr_filter_cfg_en.attr,
+       &format_attr_filter_match.attr,
+       &format_attr_filter_mask.attr,
+       &format_attr_dsp.attr,
+       &format_attr_thr.attr,
+       &format_attr_fvc.attr,
+       &format_attr_pgt.attr,
+       &format_attr_map.attr,
+       &format_attr_iss.attr,
+       &format_attr_pld.attr,
+       NULL,
+};
+
+static struct attribute_group nhmex_uncore_mbox_format_group = {
+       .name           = "format",
+       .attrs          = nhmex_uncore_mbox_formats_attr,
+};
+
+static struct uncore_event_desc nhmex_uncore_mbox_events[] = {
+       INTEL_UNCORE_EVENT_DESC(bbox_cmds_read, "inc_sel=0xd,fvc=0x2800"),
+       INTEL_UNCORE_EVENT_DESC(bbox_cmds_write, "inc_sel=0xd,fvc=0x2820"),
+       { /* end: all zeroes */ },
+};
+
+static struct uncore_event_desc wsmex_uncore_mbox_events[] = {
+       INTEL_UNCORE_EVENT_DESC(bbox_cmds_read, "inc_sel=0xd,fvc=0x5000"),
+       INTEL_UNCORE_EVENT_DESC(bbox_cmds_write, "inc_sel=0xd,fvc=0x5040"),
+       { /* end: all zeroes */ },
+};
+
+static struct intel_uncore_ops nhmex_uncore_mbox_ops = {
+       NHMEX_UNCORE_OPS_COMMON_INIT(),
+       .enable_event   = nhmex_mbox_msr_enable_event,
+       .hw_config      = nhmex_mbox_hw_config,
+       .get_constraint = nhmex_mbox_get_constraint,
+       .put_constraint = nhmex_mbox_put_constraint,
+};
+
+static struct intel_uncore_type nhmex_uncore_mbox = {
+       .name                   = "mbox",
+       .num_counters           = 6,
+       .num_boxes              = 2,
+       .perf_ctr_bits          = 48,
+       .event_ctl              = NHMEX_M0_MSR_PMU_CTL0,
+       .perf_ctr               = NHMEX_M0_MSR_PMU_CNT0,
+       .event_mask             = NHMEX_M_PMON_RAW_EVENT_MASK,
+       .box_ctl                = NHMEX_M0_MSR_GLOBAL_CTL,
+       .msr_offset             = NHMEX_M_MSR_OFFSET,
+       .pair_ctr_ctl           = 1,
+       .num_shared_regs        = 8,
+       .event_descs            = nhmex_uncore_mbox_events,
+       .ops                    = &nhmex_uncore_mbox_ops,
+       .format_group           = &nhmex_uncore_mbox_format_group,
+};
+
+static void nhmex_rbox_alter_er(struct intel_uncore_box *box, struct perf_event *event)
+{
+       struct hw_perf_event *hwc = &event->hw;
+       struct hw_perf_event_extra *reg1 = &hwc->extra_reg;
+
+       /* adjust the main event selector and extra register index */
+       if (reg1->idx % 2) {
+               reg1->idx--;
+               hwc->config -= 1 << NHMEX_R_PMON_CTL_EV_SEL_SHIFT;
+       } else {
+               reg1->idx++;
+               hwc->config += 1 << NHMEX_R_PMON_CTL_EV_SEL_SHIFT;
+       }
+
+       /* adjust extra register config */
+       switch (reg1->idx % 6) {
+       case 2:
+               /* shift the 8~15 bits to the 0~7 bits */
+               reg1->config >>= 8;
+               break;
+       case 3:
+               /* shift the 0~7 bits to the 8~15 bits */
+               reg1->config <<= 8;
+               break;
+       }
+}
+
+/*
+ * Each rbox has 4 event set which monitor PQI port 0~3 or 4~7.
+ * An event set consists of 6 events, the 3rd and 4th events in
+ * an event set use the same extra register. So an event set uses
+ * 5 extra registers.
+ */
+static struct event_constraint *
+nhmex_rbox_get_constraint(struct intel_uncore_box *box, struct perf_event *event)
+{
+       struct hw_perf_event *hwc = &event->hw;
+       struct hw_perf_event_extra *reg1 = &hwc->extra_reg;
+       struct hw_perf_event_extra *reg2 = &hwc->branch_reg;
+       struct intel_uncore_extra_reg *er;
+       unsigned long flags;
+       int idx, er_idx;
+       u64 config1;
+       bool ok = false;
+
+       if (!uncore_box_is_fake(box) && reg1->alloc)
+               return NULL;
+
+       idx = reg1->idx % 6;
+       config1 = reg1->config;
+again:
+       er_idx = idx;
+       /* the 3rd and 4th events use the same extra register */
+       if (er_idx > 2)
+               er_idx--;
+       er_idx += (reg1->idx / 6) * 5;
+
+       er = &box->shared_regs[er_idx];
+       raw_spin_lock_irqsave(&er->lock, flags);
+       if (idx < 2) {
+               if (!atomic_read(&er->ref) || er->config == reg1->config) {
+                       atomic_inc(&er->ref);
+                       er->config = reg1->config;
+                       ok = true;
+               }
+       } else if (idx == 2 || idx == 3) {
+               /*
+                * these two events use different fields in a extra register,
+                * the 0~7 bits and the 8~15 bits respectively.
+                */
+               u64 mask = 0xff << ((idx - 2) * 8);
+               if (!__BITS_VALUE(atomic_read(&er->ref), idx - 2, 8) ||
+                               !((er->config ^ config1) & mask)) {
+                       atomic_add(1 << ((idx - 2) * 8), &er->ref);
+                       er->config &= ~mask;
+                       er->config |= config1 & mask;
+                       ok = true;
+               }
+       } else {
+               if (!atomic_read(&er->ref) ||
+                               (er->config == (hwc->config >> 32) &&
+                                er->config1 == reg1->config &&
+                                er->config2 == reg2->config)) {
+                       atomic_inc(&er->ref);
+                       er->config = (hwc->config >> 32);
+                       er->config1 = reg1->config;
+                       er->config2 = reg2->config;
+                       ok = true;
+               }
+       }
+       raw_spin_unlock_irqrestore(&er->lock, flags);
+
+       if (!ok) {
+               /*
+                * The Rbox events are always in pairs. The paired
+                * events are functional identical, but use different
+                * extra registers. If we failed to take an extra
+                * register, try the alternative.
+                */
+               idx ^= 1;
+               if (idx != reg1->idx % 6) {
+                       if (idx == 2)
+                               config1 >>= 8;
+                       else if (idx == 3)
+                               config1 <<= 8;
+                       goto again;
+               }
+       } else {
+               if (!uncore_box_is_fake(box)) {
+                       if (idx != reg1->idx % 6)
+                               nhmex_rbox_alter_er(box, event);
+                       reg1->alloc = 1;
+               }
+               return NULL;
+       }
+       return &uncore_constraint_empty;
+}
+
+static void nhmex_rbox_put_constraint(struct intel_uncore_box *box, struct perf_event *event)
+{
+       struct intel_uncore_extra_reg *er;
+       struct hw_perf_event_extra *reg1 = &event->hw.extra_reg;
+       int idx, er_idx;
+
+       if (uncore_box_is_fake(box) || !reg1->alloc)
+               return;
+
+       idx = reg1->idx % 6;
+       er_idx = idx;
+       if (er_idx > 2)
+               er_idx--;
+       er_idx += (reg1->idx / 6) * 5;
+
+       er = &box->shared_regs[er_idx];
+       if (idx == 2 || idx == 3)
+               atomic_sub(1 << ((idx - 2) * 8), &er->ref);
+       else
+               atomic_dec(&er->ref);
+
+       reg1->alloc = 0;
+}
+
+static int nhmex_rbox_hw_config(struct intel_uncore_box *box, struct perf_event *event)
+{
+       struct hw_perf_event *hwc = &event->hw;
+       struct hw_perf_event_extra *reg1 = &event->hw.extra_reg;
+       struct hw_perf_event_extra *reg2 = &event->hw.branch_reg;
+       int idx;
+
+       idx = (event->hw.config & NHMEX_R_PMON_CTL_EV_SEL_MASK) >>
+               NHMEX_R_PMON_CTL_EV_SEL_SHIFT;
+       if (idx >= 0x18)
+               return -EINVAL;
+
+       reg1->idx = idx;
+       reg1->config = event->attr.config1;
+
+       switch (idx % 6) {
+       case 4:
+       case 5:
+               hwc->config |= event->attr.config & (~0ULL << 32);
+               reg2->config = event->attr.config2;
+               break;
+       }
+       return 0;
+}
+
+static void nhmex_rbox_msr_enable_event(struct intel_uncore_box *box, struct perf_event *event)
+{
+       struct hw_perf_event *hwc = &event->hw;
+       struct hw_perf_event_extra *reg1 = &hwc->extra_reg;
+       struct hw_perf_event_extra *reg2 = &hwc->branch_reg;
+       int idx, port;
+
+       idx = reg1->idx;
+       port = idx / 6 + box->pmu->pmu_idx * 4;
+
+       switch (idx % 6) {
+       case 0:
+               wrmsrl(NHMEX_R_MSR_PORTN_IPERF_CFG0(port), reg1->config);
+               break;
+       case 1:
+               wrmsrl(NHMEX_R_MSR_PORTN_IPERF_CFG1(port), reg1->config);
+               break;
+       case 2:
+       case 3:
+               wrmsrl(NHMEX_R_MSR_PORTN_QLX_CFG(port),
+                       uncore_shared_reg_config(box, 2 + (idx / 6) * 5));
+               break;
+       case 4:
+               wrmsrl(NHMEX_R_MSR_PORTN_XBR_SET1_MM_CFG(port),
+                       hwc->config >> 32);
+               wrmsrl(NHMEX_R_MSR_PORTN_XBR_SET1_MATCH(port), reg1->config);
+               wrmsrl(NHMEX_R_MSR_PORTN_XBR_SET1_MASK(port), reg2->config);
+               break;
+       case 5:
+               wrmsrl(NHMEX_R_MSR_PORTN_XBR_SET2_MM_CFG(port),
+                       hwc->config >> 32);
+               wrmsrl(NHMEX_R_MSR_PORTN_XBR_SET2_MATCH(port), reg1->config);
+               wrmsrl(NHMEX_R_MSR_PORTN_XBR_SET2_MASK(port), reg2->config);
+               break;
+       }
+
+       wrmsrl(hwc->config_base, NHMEX_PMON_CTL_EN_BIT0 |
+               (hwc->config & NHMEX_R_PMON_CTL_EV_SEL_MASK));
+}
+
+DEFINE_UNCORE_FORMAT_ATTR(xbr_mm_cfg, xbr_mm_cfg, "config:32-63");
+DEFINE_UNCORE_FORMAT_ATTR(xbr_match, xbr_match, "config1:0-63");
+DEFINE_UNCORE_FORMAT_ATTR(xbr_mask, xbr_mask, "config2:0-63");
+DEFINE_UNCORE_FORMAT_ATTR(qlx_cfg, qlx_cfg, "config1:0-15");
+DEFINE_UNCORE_FORMAT_ATTR(iperf_cfg, iperf_cfg, "config1:0-31");
+
+static struct attribute *nhmex_uncore_rbox_formats_attr[] = {
+       &format_attr_event5.attr,
+       &format_attr_xbr_mm_cfg.attr,
+       &format_attr_xbr_match.attr,
+       &format_attr_xbr_mask.attr,
+       &format_attr_qlx_cfg.attr,
+       &format_attr_iperf_cfg.attr,
+       NULL,
+};
+
+static struct attribute_group nhmex_uncore_rbox_format_group = {
+       .name = "format",
+       .attrs = nhmex_uncore_rbox_formats_attr,
+};
+
+static struct uncore_event_desc nhmex_uncore_rbox_events[] = {
+       INTEL_UNCORE_EVENT_DESC(qpi0_flit_send,         "event=0x0,iperf_cfg=0x80000000"),
+       INTEL_UNCORE_EVENT_DESC(qpi1_filt_send,         "event=0x6,iperf_cfg=0x80000000"),
+       INTEL_UNCORE_EVENT_DESC(qpi0_idle_filt,         "event=0x0,iperf_cfg=0x40000000"),
+       INTEL_UNCORE_EVENT_DESC(qpi1_idle_filt,         "event=0x6,iperf_cfg=0x40000000"),
+       INTEL_UNCORE_EVENT_DESC(qpi0_date_response,     "event=0x0,iperf_cfg=0xc4"),
+       INTEL_UNCORE_EVENT_DESC(qpi1_date_response,     "event=0x6,iperf_cfg=0xc4"),
+       { /* end: all zeroes */ },
+};
+
+static struct intel_uncore_ops nhmex_uncore_rbox_ops = {
+       NHMEX_UNCORE_OPS_COMMON_INIT(),
+       .enable_event           = nhmex_rbox_msr_enable_event,
+       .hw_config              = nhmex_rbox_hw_config,
+       .get_constraint         = nhmex_rbox_get_constraint,
+       .put_constraint         = nhmex_rbox_put_constraint,
+};
+
+static struct intel_uncore_type nhmex_uncore_rbox = {
+       .name                   = "rbox",
+       .num_counters           = 8,
+       .num_boxes              = 2,
+       .perf_ctr_bits          = 48,
+       .event_ctl              = NHMEX_R_MSR_PMON_CTL0,
+       .perf_ctr               = NHMEX_R_MSR_PMON_CNT0,
+       .event_mask             = NHMEX_R_PMON_RAW_EVENT_MASK,
+       .box_ctl                = NHMEX_R_MSR_GLOBAL_CTL,
+       .msr_offset             = NHMEX_R_MSR_OFFSET,
+       .pair_ctr_ctl           = 1,
+       .num_shared_regs        = 20,
+       .event_descs            = nhmex_uncore_rbox_events,
+       .ops                    = &nhmex_uncore_rbox_ops,
+       .format_group           = &nhmex_uncore_rbox_format_group
+};
+
+static struct intel_uncore_type *nhmex_msr_uncores[] = {
+       &nhmex_uncore_ubox,
+       &nhmex_uncore_cbox,
+       &nhmex_uncore_bbox,
+       &nhmex_uncore_sbox,
+       &nhmex_uncore_mbox,
+       &nhmex_uncore_rbox,
+       &nhmex_uncore_wbox,
+       NULL,
+};
+
+void nhmex_uncore_cpu_init(void)
+{
+       if (boot_cpu_data.x86_model == 46)
+               uncore_nhmex = true;
+       else
+               nhmex_uncore_mbox.event_descs = wsmex_uncore_mbox_events;
+       if (nhmex_uncore_cbox.num_boxes > boot_cpu_data.x86_max_cores)
+               nhmex_uncore_cbox.num_boxes = boot_cpu_data.x86_max_cores;
+       uncore_msr_uncores = nhmex_msr_uncores;
+}
+/* end of Nehalem-EX uncore support */
diff --git a/arch/x86/kernel/cpu/perf_event_intel_uncore_snb.c b/arch/x86/kernel/cpu/perf_event_intel_uncore_snb.c
new file mode 100644 (file)
index 0000000..3001015
--- /dev/null
@@ -0,0 +1,636 @@
+/* Nehalem/SandBridge/Haswell uncore support */
+#include "perf_event_intel_uncore.h"
+
+/* SNB event control */
+#define SNB_UNC_CTL_EV_SEL_MASK                        0x000000ff
+#define SNB_UNC_CTL_UMASK_MASK                 0x0000ff00
+#define SNB_UNC_CTL_EDGE_DET                   (1 << 18)
+#define SNB_UNC_CTL_EN                         (1 << 22)
+#define SNB_UNC_CTL_INVERT                     (1 << 23)
+#define SNB_UNC_CTL_CMASK_MASK                 0x1f000000
+#define NHM_UNC_CTL_CMASK_MASK                 0xff000000
+#define NHM_UNC_FIXED_CTR_CTL_EN               (1 << 0)
+
+#define SNB_UNC_RAW_EVENT_MASK                 (SNB_UNC_CTL_EV_SEL_MASK | \
+                                                SNB_UNC_CTL_UMASK_MASK | \
+                                                SNB_UNC_CTL_EDGE_DET | \
+                                                SNB_UNC_CTL_INVERT | \
+                                                SNB_UNC_CTL_CMASK_MASK)
+
+#define NHM_UNC_RAW_EVENT_MASK                 (SNB_UNC_CTL_EV_SEL_MASK | \
+                                                SNB_UNC_CTL_UMASK_MASK | \
+                                                SNB_UNC_CTL_EDGE_DET | \
+                                                SNB_UNC_CTL_INVERT | \
+                                                NHM_UNC_CTL_CMASK_MASK)
+
+/* SNB global control register */
+#define SNB_UNC_PERF_GLOBAL_CTL                 0x391
+#define SNB_UNC_FIXED_CTR_CTRL                  0x394
+#define SNB_UNC_FIXED_CTR                       0x395
+
+/* SNB uncore global control */
+#define SNB_UNC_GLOBAL_CTL_CORE_ALL             ((1 << 4) - 1)
+#define SNB_UNC_GLOBAL_CTL_EN                   (1 << 29)
+
+/* SNB Cbo register */
+#define SNB_UNC_CBO_0_PERFEVTSEL0               0x700
+#define SNB_UNC_CBO_0_PER_CTR0                  0x706
+#define SNB_UNC_CBO_MSR_OFFSET                  0x10
+
+/* NHM global control register */
+#define NHM_UNC_PERF_GLOBAL_CTL                 0x391
+#define NHM_UNC_FIXED_CTR                       0x394
+#define NHM_UNC_FIXED_CTR_CTRL                  0x395
+
+/* NHM uncore global control */
+#define NHM_UNC_GLOBAL_CTL_EN_PC_ALL            ((1ULL << 8) - 1)
+#define NHM_UNC_GLOBAL_CTL_EN_FC                (1ULL << 32)
+
+/* NHM uncore register */
+#define NHM_UNC_PERFEVTSEL0                     0x3c0
+#define NHM_UNC_UNCORE_PMC0                     0x3b0
+
+DEFINE_UNCORE_FORMAT_ATTR(event, event, "config:0-7");
+DEFINE_UNCORE_FORMAT_ATTR(umask, umask, "config:8-15");
+DEFINE_UNCORE_FORMAT_ATTR(edge, edge, "config:18");
+DEFINE_UNCORE_FORMAT_ATTR(inv, inv, "config:23");
+DEFINE_UNCORE_FORMAT_ATTR(cmask5, cmask, "config:24-28");
+DEFINE_UNCORE_FORMAT_ATTR(cmask8, cmask, "config:24-31");
+
+/* Sandy Bridge uncore support */
+static void snb_uncore_msr_enable_event(struct intel_uncore_box *box, struct perf_event *event)
+{
+       struct hw_perf_event *hwc = &event->hw;
+
+       if (hwc->idx < UNCORE_PMC_IDX_FIXED)
+               wrmsrl(hwc->config_base, hwc->config | SNB_UNC_CTL_EN);
+       else
+               wrmsrl(hwc->config_base, SNB_UNC_CTL_EN);
+}
+
+static void snb_uncore_msr_disable_event(struct intel_uncore_box *box, struct perf_event *event)
+{
+       wrmsrl(event->hw.config_base, 0);
+}
+
+static void snb_uncore_msr_init_box(struct intel_uncore_box *box)
+{
+       if (box->pmu->pmu_idx == 0) {
+               wrmsrl(SNB_UNC_PERF_GLOBAL_CTL,
+                       SNB_UNC_GLOBAL_CTL_EN | SNB_UNC_GLOBAL_CTL_CORE_ALL);
+       }
+}
+
+static struct uncore_event_desc snb_uncore_events[] = {
+       INTEL_UNCORE_EVENT_DESC(clockticks, "event=0xff,umask=0x00"),
+       { /* end: all zeroes */ },
+};
+
+static struct attribute *snb_uncore_formats_attr[] = {
+       &format_attr_event.attr,
+       &format_attr_umask.attr,
+       &format_attr_edge.attr,
+       &format_attr_inv.attr,
+       &format_attr_cmask5.attr,
+       NULL,
+};
+
+static struct attribute_group snb_uncore_format_group = {
+       .name           = "format",
+       .attrs          = snb_uncore_formats_attr,
+};
+
+static struct intel_uncore_ops snb_uncore_msr_ops = {
+       .init_box       = snb_uncore_msr_init_box,
+       .disable_event  = snb_uncore_msr_disable_event,
+       .enable_event   = snb_uncore_msr_enable_event,
+       .read_counter   = uncore_msr_read_counter,
+};
+
+static struct event_constraint snb_uncore_cbox_constraints[] = {
+       UNCORE_EVENT_CONSTRAINT(0x80, 0x1),
+       UNCORE_EVENT_CONSTRAINT(0x83, 0x1),
+       EVENT_CONSTRAINT_END
+};
+
+static struct intel_uncore_type snb_uncore_cbox = {
+       .name           = "cbox",
+       .num_counters   = 2,
+       .num_boxes      = 4,
+       .perf_ctr_bits  = 44,
+       .fixed_ctr_bits = 48,
+       .perf_ctr       = SNB_UNC_CBO_0_PER_CTR0,
+       .event_ctl      = SNB_UNC_CBO_0_PERFEVTSEL0,
+       .fixed_ctr      = SNB_UNC_FIXED_CTR,
+       .fixed_ctl      = SNB_UNC_FIXED_CTR_CTRL,
+       .single_fixed   = 1,
+       .event_mask     = SNB_UNC_RAW_EVENT_MASK,
+       .msr_offset     = SNB_UNC_CBO_MSR_OFFSET,
+       .constraints    = snb_uncore_cbox_constraints,
+       .ops            = &snb_uncore_msr_ops,
+       .format_group   = &snb_uncore_format_group,
+       .event_descs    = snb_uncore_events,
+};
+
+static struct intel_uncore_type *snb_msr_uncores[] = {
+       &snb_uncore_cbox,
+       NULL,
+};
+
+void snb_uncore_cpu_init(void)
+{
+       uncore_msr_uncores = snb_msr_uncores;
+       if (snb_uncore_cbox.num_boxes > boot_cpu_data.x86_max_cores)
+               snb_uncore_cbox.num_boxes = boot_cpu_data.x86_max_cores;
+}
+
+enum {
+       SNB_PCI_UNCORE_IMC,
+};
+
+static struct uncore_event_desc snb_uncore_imc_events[] = {
+       INTEL_UNCORE_EVENT_DESC(data_reads,  "event=0x01"),
+       INTEL_UNCORE_EVENT_DESC(data_reads.scale, "6.103515625e-5"),
+       INTEL_UNCORE_EVENT_DESC(data_reads.unit, "MiB"),
+
+       INTEL_UNCORE_EVENT_DESC(data_writes, "event=0x02"),
+       INTEL_UNCORE_EVENT_DESC(data_writes.scale, "6.103515625e-5"),
+       INTEL_UNCORE_EVENT_DESC(data_writes.unit, "MiB"),
+
+       { /* end: all zeroes */ },
+};
+
+#define SNB_UNCORE_PCI_IMC_EVENT_MASK          0xff
+#define SNB_UNCORE_PCI_IMC_BAR_OFFSET          0x48
+
+/* page size multiple covering all config regs */
+#define SNB_UNCORE_PCI_IMC_MAP_SIZE            0x6000
+
+#define SNB_UNCORE_PCI_IMC_DATA_READS          0x1
+#define SNB_UNCORE_PCI_IMC_DATA_READS_BASE     0x5050
+#define SNB_UNCORE_PCI_IMC_DATA_WRITES         0x2
+#define SNB_UNCORE_PCI_IMC_DATA_WRITES_BASE    0x5054
+#define SNB_UNCORE_PCI_IMC_CTR_BASE            SNB_UNCORE_PCI_IMC_DATA_READS_BASE
+
+static struct attribute *snb_uncore_imc_formats_attr[] = {
+       &format_attr_event.attr,
+       NULL,
+};
+
+static struct attribute_group snb_uncore_imc_format_group = {
+       .name = "format",
+       .attrs = snb_uncore_imc_formats_attr,
+};
+
+static void snb_uncore_imc_init_box(struct intel_uncore_box *box)
+{
+       struct pci_dev *pdev = box->pci_dev;
+       int where = SNB_UNCORE_PCI_IMC_BAR_OFFSET;
+       resource_size_t addr;
+       u32 pci_dword;
+
+       pci_read_config_dword(pdev, where, &pci_dword);
+       addr = pci_dword;
+
+#ifdef CONFIG_PHYS_ADDR_T_64BIT
+       pci_read_config_dword(pdev, where + 4, &pci_dword);
+       addr |= ((resource_size_t)pci_dword << 32);
+#endif
+
+       addr &= ~(PAGE_SIZE - 1);
+
+       box->io_addr = ioremap(addr, SNB_UNCORE_PCI_IMC_MAP_SIZE);
+       box->hrtimer_duration = UNCORE_SNB_IMC_HRTIMER_INTERVAL;
+}
+
+static void snb_uncore_imc_enable_box(struct intel_uncore_box *box)
+{}
+
+static void snb_uncore_imc_disable_box(struct intel_uncore_box *box)
+{}
+
+static void snb_uncore_imc_enable_event(struct intel_uncore_box *box, struct perf_event *event)
+{}
+
+static void snb_uncore_imc_disable_event(struct intel_uncore_box *box, struct perf_event *event)
+{}
+
+static u64 snb_uncore_imc_read_counter(struct intel_uncore_box *box, struct perf_event *event)
+{
+       struct hw_perf_event *hwc = &event->hw;
+
+       return (u64)*(unsigned int *)(box->io_addr + hwc->event_base);
+}
+
+/*
+ * custom event_init() function because we define our own fixed, free
+ * running counters, so we do not want to conflict with generic uncore
+ * logic. Also simplifies processing
+ */
+static int snb_uncore_imc_event_init(struct perf_event *event)
+{
+       struct intel_uncore_pmu *pmu;
+       struct intel_uncore_box *box;
+       struct hw_perf_event *hwc = &event->hw;
+       u64 cfg = event->attr.config & SNB_UNCORE_PCI_IMC_EVENT_MASK;
+       int idx, base;
+
+       if (event->attr.type != event->pmu->type)
+               return -ENOENT;
+
+       pmu = uncore_event_to_pmu(event);
+       /* no device found for this pmu */
+       if (pmu->func_id < 0)
+               return -ENOENT;
+
+       /* Sampling not supported yet */
+       if (hwc->sample_period)
+               return -EINVAL;
+
+       /* unsupported modes and filters */
+       if (event->attr.exclude_user   ||
+           event->attr.exclude_kernel ||
+           event->attr.exclude_hv     ||
+           event->attr.exclude_idle   ||
+           event->attr.exclude_host   ||
+           event->attr.exclude_guest  ||
+           event->attr.sample_period) /* no sampling */
+               return -EINVAL;
+
+       /*
+        * Place all uncore events for a particular physical package
+        * onto a single cpu
+        */
+       if (event->cpu < 0)
+               return -EINVAL;
+
+       /* check only supported bits are set */
+       if (event->attr.config & ~SNB_UNCORE_PCI_IMC_EVENT_MASK)
+               return -EINVAL;
+
+       box = uncore_pmu_to_box(pmu, event->cpu);
+       if (!box || box->cpu < 0)
+               return -EINVAL;
+
+       event->cpu = box->cpu;
+
+       event->hw.idx = -1;
+       event->hw.last_tag = ~0ULL;
+       event->hw.extra_reg.idx = EXTRA_REG_NONE;
+       event->hw.branch_reg.idx = EXTRA_REG_NONE;
+       /*
+        * check event is known (whitelist, determines counter)
+        */
+       switch (cfg) {
+       case SNB_UNCORE_PCI_IMC_DATA_READS:
+               base = SNB_UNCORE_PCI_IMC_DATA_READS_BASE;
+               idx = UNCORE_PMC_IDX_FIXED;
+               break;
+       case SNB_UNCORE_PCI_IMC_DATA_WRITES:
+               base = SNB_UNCORE_PCI_IMC_DATA_WRITES_BASE;
+               idx = UNCORE_PMC_IDX_FIXED + 1;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       /* must be done before validate_group */
+       event->hw.event_base = base;
+       event->hw.config = cfg;
+       event->hw.idx = idx;
+
+       /* no group validation needed, we have free running counters */
+
+       return 0;
+}
+
+static int snb_uncore_imc_hw_config(struct intel_uncore_box *box, struct perf_event *event)
+{
+       return 0;
+}
+
+static void snb_uncore_imc_event_start(struct perf_event *event, int flags)
+{
+       struct intel_uncore_box *box = uncore_event_to_box(event);
+       u64 count;
+
+       if (WARN_ON_ONCE(!(event->hw.state & PERF_HES_STOPPED)))
+               return;
+
+       event->hw.state = 0;
+       box->n_active++;
+
+       list_add_tail(&event->active_entry, &box->active_list);
+
+       count = snb_uncore_imc_read_counter(box, event);
+       local64_set(&event->hw.prev_count, count);
+
+       if (box->n_active == 1)
+               uncore_pmu_start_hrtimer(box);
+}
+
+static void snb_uncore_imc_event_stop(struct perf_event *event, int flags)
+{
+       struct intel_uncore_box *box = uncore_event_to_box(event);
+       struct hw_perf_event *hwc = &event->hw;
+
+       if (!(hwc->state & PERF_HES_STOPPED)) {
+               box->n_active--;
+
+               WARN_ON_ONCE(hwc->state & PERF_HES_STOPPED);
+               hwc->state |= PERF_HES_STOPPED;
+
+               list_del(&event->active_entry);
+
+               if (box->n_active == 0)
+                       uncore_pmu_cancel_hrtimer(box);
+       }
+
+       if ((flags & PERF_EF_UPDATE) && !(hwc->state & PERF_HES_UPTODATE)) {
+               /*
+                * Drain the remaining delta count out of a event
+                * that we are disabling:
+                */
+               uncore_perf_event_update(box, event);
+               hwc->state |= PERF_HES_UPTODATE;
+       }
+}
+
+static int snb_uncore_imc_event_add(struct perf_event *event, int flags)
+{
+       struct intel_uncore_box *box = uncore_event_to_box(event);
+       struct hw_perf_event *hwc = &event->hw;
+
+       if (!box)
+               return -ENODEV;
+
+       hwc->state = PERF_HES_UPTODATE | PERF_HES_STOPPED;
+       if (!(flags & PERF_EF_START))
+               hwc->state |= PERF_HES_ARCH;
+
+       snb_uncore_imc_event_start(event, 0);
+
+       box->n_events++;
+
+       return 0;
+}
+
+static void snb_uncore_imc_event_del(struct perf_event *event, int flags)
+{
+       struct intel_uncore_box *box = uncore_event_to_box(event);
+       int i;
+
+       snb_uncore_imc_event_stop(event, PERF_EF_UPDATE);
+
+       for (i = 0; i < box->n_events; i++) {
+               if (event == box->event_list[i]) {
+                       --box->n_events;
+                       break;
+               }
+       }
+}
+
+static int snb_pci2phy_map_init(int devid)
+{
+       struct pci_dev *dev = NULL;
+       int bus;
+
+       dev = pci_get_device(PCI_VENDOR_ID_INTEL, devid, dev);
+       if (!dev)
+               return -ENOTTY;
+
+       bus = dev->bus->number;
+
+       uncore_pcibus_to_physid[bus] = 0;
+
+       pci_dev_put(dev);
+
+       return 0;
+}
+
+static struct pmu snb_uncore_imc_pmu = {
+       .task_ctx_nr    = perf_invalid_context,
+       .event_init     = snb_uncore_imc_event_init,
+       .add            = snb_uncore_imc_event_add,
+       .del            = snb_uncore_imc_event_del,
+       .start          = snb_uncore_imc_event_start,
+       .stop           = snb_uncore_imc_event_stop,
+       .read           = uncore_pmu_event_read,
+};
+
+static struct intel_uncore_ops snb_uncore_imc_ops = {
+       .init_box       = snb_uncore_imc_init_box,
+       .enable_box     = snb_uncore_imc_enable_box,
+       .disable_box    = snb_uncore_imc_disable_box,
+       .disable_event  = snb_uncore_imc_disable_event,
+       .enable_event   = snb_uncore_imc_enable_event,
+       .hw_config      = snb_uncore_imc_hw_config,
+       .read_counter   = snb_uncore_imc_read_counter,
+};
+
+static struct intel_uncore_type snb_uncore_imc = {
+       .name           = "imc",
+       .num_counters   = 2,
+       .num_boxes      = 1,
+       .fixed_ctr_bits = 32,
+       .fixed_ctr      = SNB_UNCORE_PCI_IMC_CTR_BASE,
+       .event_descs    = snb_uncore_imc_events,
+       .format_group   = &snb_uncore_imc_format_group,
+       .perf_ctr       = SNB_UNCORE_PCI_IMC_DATA_READS_BASE,
+       .event_mask     = SNB_UNCORE_PCI_IMC_EVENT_MASK,
+       .ops            = &snb_uncore_imc_ops,
+       .pmu            = &snb_uncore_imc_pmu,
+};
+
+static struct intel_uncore_type *snb_pci_uncores[] = {
+       [SNB_PCI_UNCORE_IMC]    = &snb_uncore_imc,
+       NULL,
+};
+
+static const struct pci_device_id snb_uncore_pci_ids[] = {
+       { /* IMC */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_SNB_IMC),
+               .driver_data = UNCORE_PCI_DEV_DATA(SNB_PCI_UNCORE_IMC, 0),
+       },
+       { /* end: all zeroes */ },
+};
+
+static const struct pci_device_id ivb_uncore_pci_ids[] = {
+       { /* IMC */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_IVB_IMC),
+               .driver_data = UNCORE_PCI_DEV_DATA(SNB_PCI_UNCORE_IMC, 0),
+       },
+       { /* IMC */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_IVB_E3_IMC),
+               .driver_data = UNCORE_PCI_DEV_DATA(SNB_PCI_UNCORE_IMC, 0),
+       },
+       { /* end: all zeroes */ },
+};
+
+static const struct pci_device_id hsw_uncore_pci_ids[] = {
+       { /* IMC */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_HSW_IMC),
+               .driver_data = UNCORE_PCI_DEV_DATA(SNB_PCI_UNCORE_IMC, 0),
+       },
+       { /* end: all zeroes */ },
+};
+
+static struct pci_driver snb_uncore_pci_driver = {
+       .name           = "snb_uncore",
+       .id_table       = snb_uncore_pci_ids,
+};
+
+static struct pci_driver ivb_uncore_pci_driver = {
+       .name           = "ivb_uncore",
+       .id_table       = ivb_uncore_pci_ids,
+};
+
+static struct pci_driver hsw_uncore_pci_driver = {
+       .name           = "hsw_uncore",
+       .id_table       = hsw_uncore_pci_ids,
+};
+
+struct imc_uncore_pci_dev {
+       __u32 pci_id;
+       struct pci_driver *driver;
+};
+#define IMC_DEV(a, d) \
+       { .pci_id = PCI_DEVICE_ID_INTEL_##a, .driver = (d) }
+
+static const struct imc_uncore_pci_dev desktop_imc_pci_ids[] = {
+       IMC_DEV(SNB_IMC, &snb_uncore_pci_driver),
+       IMC_DEV(IVB_IMC, &ivb_uncore_pci_driver),    /* 3rd Gen Core processor */
+       IMC_DEV(IVB_E3_IMC, &ivb_uncore_pci_driver), /* Xeon E3-1200 v2/3rd Gen Core processor */
+       IMC_DEV(HSW_IMC, &hsw_uncore_pci_driver),    /* 4th Gen Core Processor */
+       {  /* end marker */ }
+};
+
+
+#define for_each_imc_pci_id(x, t) \
+       for (x = (t); (x)->pci_id; x++)
+
+static struct pci_driver *imc_uncore_find_dev(void)
+{
+       const struct imc_uncore_pci_dev *p;
+       int ret;
+
+       for_each_imc_pci_id(p, desktop_imc_pci_ids) {
+               ret = snb_pci2phy_map_init(p->pci_id);
+               if (ret == 0)
+                       return p->driver;
+       }
+       return NULL;
+}
+
+static int imc_uncore_pci_init(void)
+{
+       struct pci_driver *imc_drv = imc_uncore_find_dev();
+
+       if (!imc_drv)
+               return -ENODEV;
+
+       uncore_pci_uncores = snb_pci_uncores;
+       uncore_pci_driver = imc_drv;
+
+       return 0;
+}
+
+int snb_uncore_pci_init(void)
+{
+       return imc_uncore_pci_init();
+}
+
+int ivb_uncore_pci_init(void)
+{
+       return imc_uncore_pci_init();
+}
+int hsw_uncore_pci_init(void)
+{
+       return imc_uncore_pci_init();
+}
+
+/* end of Sandy Bridge uncore support */
+
+/* Nehalem uncore support */
+static void nhm_uncore_msr_disable_box(struct intel_uncore_box *box)
+{
+       wrmsrl(NHM_UNC_PERF_GLOBAL_CTL, 0);
+}
+
+static void nhm_uncore_msr_enable_box(struct intel_uncore_box *box)
+{
+       wrmsrl(NHM_UNC_PERF_GLOBAL_CTL, NHM_UNC_GLOBAL_CTL_EN_PC_ALL | NHM_UNC_GLOBAL_CTL_EN_FC);
+}
+
+static void nhm_uncore_msr_enable_event(struct intel_uncore_box *box, struct perf_event *event)
+{
+       struct hw_perf_event *hwc = &event->hw;
+
+       if (hwc->idx < UNCORE_PMC_IDX_FIXED)
+               wrmsrl(hwc->config_base, hwc->config | SNB_UNC_CTL_EN);
+       else
+               wrmsrl(hwc->config_base, NHM_UNC_FIXED_CTR_CTL_EN);
+}
+
+static struct attribute *nhm_uncore_formats_attr[] = {
+       &format_attr_event.attr,
+       &format_attr_umask.attr,
+       &format_attr_edge.attr,
+       &format_attr_inv.attr,
+       &format_attr_cmask8.attr,
+       NULL,
+};
+
+static struct attribute_group nhm_uncore_format_group = {
+       .name = "format",
+       .attrs = nhm_uncore_formats_attr,
+};
+
+static struct uncore_event_desc nhm_uncore_events[] = {
+       INTEL_UNCORE_EVENT_DESC(clockticks,                "event=0xff,umask=0x00"),
+       INTEL_UNCORE_EVENT_DESC(qmc_writes_full_any,       "event=0x2f,umask=0x0f"),
+       INTEL_UNCORE_EVENT_DESC(qmc_normal_reads_any,      "event=0x2c,umask=0x0f"),
+       INTEL_UNCORE_EVENT_DESC(qhl_request_ioh_reads,     "event=0x20,umask=0x01"),
+       INTEL_UNCORE_EVENT_DESC(qhl_request_ioh_writes,    "event=0x20,umask=0x02"),
+       INTEL_UNCORE_EVENT_DESC(qhl_request_remote_reads,  "event=0x20,umask=0x04"),
+       INTEL_UNCORE_EVENT_DESC(qhl_request_remote_writes, "event=0x20,umask=0x08"),
+       INTEL_UNCORE_EVENT_DESC(qhl_request_local_reads,   "event=0x20,umask=0x10"),
+       INTEL_UNCORE_EVENT_DESC(qhl_request_local_writes,  "event=0x20,umask=0x20"),
+       { /* end: all zeroes */ },
+};
+
+static struct intel_uncore_ops nhm_uncore_msr_ops = {
+       .disable_box    = nhm_uncore_msr_disable_box,
+       .enable_box     = nhm_uncore_msr_enable_box,
+       .disable_event  = snb_uncore_msr_disable_event,
+       .enable_event   = nhm_uncore_msr_enable_event,
+       .read_counter   = uncore_msr_read_counter,
+};
+
+static struct intel_uncore_type nhm_uncore = {
+       .name           = "",
+       .num_counters   = 8,
+       .num_boxes      = 1,
+       .perf_ctr_bits  = 48,
+       .fixed_ctr_bits = 48,
+       .event_ctl      = NHM_UNC_PERFEVTSEL0,
+       .perf_ctr       = NHM_UNC_UNCORE_PMC0,
+       .fixed_ctr      = NHM_UNC_FIXED_CTR,
+       .fixed_ctl      = NHM_UNC_FIXED_CTR_CTRL,
+       .event_mask     = NHM_UNC_RAW_EVENT_MASK,
+       .event_descs    = nhm_uncore_events,
+       .ops            = &nhm_uncore_msr_ops,
+       .format_group   = &nhm_uncore_format_group,
+};
+
+static struct intel_uncore_type *nhm_msr_uncores[] = {
+       &nhm_uncore,
+       NULL,
+};
+
+void nhm_uncore_cpu_init(void)
+{
+       uncore_msr_uncores = nhm_msr_uncores;
+}
+
+/* end of Nehalem uncore support */
diff --git a/arch/x86/kernel/cpu/perf_event_intel_uncore_snbep.c b/arch/x86/kernel/cpu/perf_event_intel_uncore_snbep.c
new file mode 100644 (file)
index 0000000..adf138e
--- /dev/null
@@ -0,0 +1,2258 @@
+/* SandyBridge-EP/IvyTown uncore support */
+#include "perf_event_intel_uncore.h"
+
+
+/* SNB-EP Box level control */
+#define SNBEP_PMON_BOX_CTL_RST_CTRL    (1 << 0)
+#define SNBEP_PMON_BOX_CTL_RST_CTRS    (1 << 1)
+#define SNBEP_PMON_BOX_CTL_FRZ         (1 << 8)
+#define SNBEP_PMON_BOX_CTL_FRZ_EN      (1 << 16)
+#define SNBEP_PMON_BOX_CTL_INT         (SNBEP_PMON_BOX_CTL_RST_CTRL | \
+                                        SNBEP_PMON_BOX_CTL_RST_CTRS | \
+                                        SNBEP_PMON_BOX_CTL_FRZ_EN)
+/* SNB-EP event control */
+#define SNBEP_PMON_CTL_EV_SEL_MASK     0x000000ff
+#define SNBEP_PMON_CTL_UMASK_MASK      0x0000ff00
+#define SNBEP_PMON_CTL_RST             (1 << 17)
+#define SNBEP_PMON_CTL_EDGE_DET                (1 << 18)
+#define SNBEP_PMON_CTL_EV_SEL_EXT      (1 << 21)
+#define SNBEP_PMON_CTL_EN              (1 << 22)
+#define SNBEP_PMON_CTL_INVERT          (1 << 23)
+#define SNBEP_PMON_CTL_TRESH_MASK      0xff000000
+#define SNBEP_PMON_RAW_EVENT_MASK      (SNBEP_PMON_CTL_EV_SEL_MASK | \
+                                        SNBEP_PMON_CTL_UMASK_MASK | \
+                                        SNBEP_PMON_CTL_EDGE_DET | \
+                                        SNBEP_PMON_CTL_INVERT | \
+                                        SNBEP_PMON_CTL_TRESH_MASK)
+
+/* SNB-EP Ubox event control */
+#define SNBEP_U_MSR_PMON_CTL_TRESH_MASK                0x1f000000
+#define SNBEP_U_MSR_PMON_RAW_EVENT_MASK                \
+                               (SNBEP_PMON_CTL_EV_SEL_MASK | \
+                                SNBEP_PMON_CTL_UMASK_MASK | \
+                                SNBEP_PMON_CTL_EDGE_DET | \
+                                SNBEP_PMON_CTL_INVERT | \
+                                SNBEP_U_MSR_PMON_CTL_TRESH_MASK)
+
+#define SNBEP_CBO_PMON_CTL_TID_EN              (1 << 19)
+#define SNBEP_CBO_MSR_PMON_RAW_EVENT_MASK      (SNBEP_PMON_RAW_EVENT_MASK | \
+                                                SNBEP_CBO_PMON_CTL_TID_EN)
+
+/* SNB-EP PCU event control */
+#define SNBEP_PCU_MSR_PMON_CTL_OCC_SEL_MASK    0x0000c000
+#define SNBEP_PCU_MSR_PMON_CTL_TRESH_MASK      0x1f000000
+#define SNBEP_PCU_MSR_PMON_CTL_OCC_INVERT      (1 << 30)
+#define SNBEP_PCU_MSR_PMON_CTL_OCC_EDGE_DET    (1 << 31)
+#define SNBEP_PCU_MSR_PMON_RAW_EVENT_MASK      \
+                               (SNBEP_PMON_CTL_EV_SEL_MASK | \
+                                SNBEP_PCU_MSR_PMON_CTL_OCC_SEL_MASK | \
+                                SNBEP_PMON_CTL_EDGE_DET | \
+                                SNBEP_PMON_CTL_EV_SEL_EXT | \
+                                SNBEP_PMON_CTL_INVERT | \
+                                SNBEP_PCU_MSR_PMON_CTL_TRESH_MASK | \
+                                SNBEP_PCU_MSR_PMON_CTL_OCC_INVERT | \
+                                SNBEP_PCU_MSR_PMON_CTL_OCC_EDGE_DET)
+
+#define SNBEP_QPI_PCI_PMON_RAW_EVENT_MASK      \
+                               (SNBEP_PMON_RAW_EVENT_MASK | \
+                                SNBEP_PMON_CTL_EV_SEL_EXT)
+
+/* SNB-EP pci control register */
+#define SNBEP_PCI_PMON_BOX_CTL                 0xf4
+#define SNBEP_PCI_PMON_CTL0                    0xd8
+/* SNB-EP pci counter register */
+#define SNBEP_PCI_PMON_CTR0                    0xa0
+
+/* SNB-EP home agent register */
+#define SNBEP_HA_PCI_PMON_BOX_ADDRMATCH0       0x40
+#define SNBEP_HA_PCI_PMON_BOX_ADDRMATCH1       0x44
+#define SNBEP_HA_PCI_PMON_BOX_OPCODEMATCH      0x48
+/* SNB-EP memory controller register */
+#define SNBEP_MC_CHy_PCI_PMON_FIXED_CTL                0xf0
+#define SNBEP_MC_CHy_PCI_PMON_FIXED_CTR                0xd0
+/* SNB-EP QPI register */
+#define SNBEP_Q_Py_PCI_PMON_PKT_MATCH0         0x228
+#define SNBEP_Q_Py_PCI_PMON_PKT_MATCH1         0x22c
+#define SNBEP_Q_Py_PCI_PMON_PKT_MASK0          0x238
+#define SNBEP_Q_Py_PCI_PMON_PKT_MASK1          0x23c
+
+/* SNB-EP Ubox register */
+#define SNBEP_U_MSR_PMON_CTR0                  0xc16
+#define SNBEP_U_MSR_PMON_CTL0                  0xc10
+
+#define SNBEP_U_MSR_PMON_UCLK_FIXED_CTL                0xc08
+#define SNBEP_U_MSR_PMON_UCLK_FIXED_CTR                0xc09
+
+/* SNB-EP Cbo register */
+#define SNBEP_C0_MSR_PMON_CTR0                 0xd16
+#define SNBEP_C0_MSR_PMON_CTL0                 0xd10
+#define SNBEP_C0_MSR_PMON_BOX_CTL              0xd04
+#define SNBEP_C0_MSR_PMON_BOX_FILTER           0xd14
+#define SNBEP_CBO_MSR_OFFSET                   0x20
+
+#define SNBEP_CB0_MSR_PMON_BOX_FILTER_TID      0x1f
+#define SNBEP_CB0_MSR_PMON_BOX_FILTER_NID      0x3fc00
+#define SNBEP_CB0_MSR_PMON_BOX_FILTER_STATE    0x7c0000
+#define SNBEP_CB0_MSR_PMON_BOX_FILTER_OPC      0xff800000
+
+#define SNBEP_CBO_EVENT_EXTRA_REG(e, m, i) {   \
+       .event = (e),                           \
+       .msr = SNBEP_C0_MSR_PMON_BOX_FILTER,    \
+       .config_mask = (m),                     \
+       .idx = (i)                              \
+}
+
+/* SNB-EP PCU register */
+#define SNBEP_PCU_MSR_PMON_CTR0                        0xc36
+#define SNBEP_PCU_MSR_PMON_CTL0                        0xc30
+#define SNBEP_PCU_MSR_PMON_BOX_CTL             0xc24
+#define SNBEP_PCU_MSR_PMON_BOX_FILTER          0xc34
+#define SNBEP_PCU_MSR_PMON_BOX_FILTER_MASK     0xffffffff
+#define SNBEP_PCU_MSR_CORE_C3_CTR              0x3fc
+#define SNBEP_PCU_MSR_CORE_C6_CTR              0x3fd
+
+/* IVBEP event control */
+#define IVBEP_PMON_BOX_CTL_INT         (SNBEP_PMON_BOX_CTL_RST_CTRL | \
+                                        SNBEP_PMON_BOX_CTL_RST_CTRS)
+#define IVBEP_PMON_RAW_EVENT_MASK              (SNBEP_PMON_CTL_EV_SEL_MASK | \
+                                        SNBEP_PMON_CTL_UMASK_MASK | \
+                                        SNBEP_PMON_CTL_EDGE_DET | \
+                                        SNBEP_PMON_CTL_TRESH_MASK)
+/* IVBEP Ubox */
+#define IVBEP_U_MSR_PMON_GLOBAL_CTL            0xc00
+#define IVBEP_U_PMON_GLOBAL_FRZ_ALL            (1 << 31)
+#define IVBEP_U_PMON_GLOBAL_UNFRZ_ALL          (1 << 29)
+
+#define IVBEP_U_MSR_PMON_RAW_EVENT_MASK        \
+                               (SNBEP_PMON_CTL_EV_SEL_MASK | \
+                                SNBEP_PMON_CTL_UMASK_MASK | \
+                                SNBEP_PMON_CTL_EDGE_DET | \
+                                SNBEP_U_MSR_PMON_CTL_TRESH_MASK)
+/* IVBEP Cbo */
+#define IVBEP_CBO_MSR_PMON_RAW_EVENT_MASK              (IVBEP_PMON_RAW_EVENT_MASK | \
+                                                SNBEP_CBO_PMON_CTL_TID_EN)
+
+#define IVBEP_CB0_MSR_PMON_BOX_FILTER_TID              (0x1fULL << 0)
+#define IVBEP_CB0_MSR_PMON_BOX_FILTER_LINK     (0xfULL << 5)
+#define IVBEP_CB0_MSR_PMON_BOX_FILTER_STATE    (0x3fULL << 17)
+#define IVBEP_CB0_MSR_PMON_BOX_FILTER_NID              (0xffffULL << 32)
+#define IVBEP_CB0_MSR_PMON_BOX_FILTER_OPC              (0x1ffULL << 52)
+#define IVBEP_CB0_MSR_PMON_BOX_FILTER_C6               (0x1ULL << 61)
+#define IVBEP_CB0_MSR_PMON_BOX_FILTER_NC               (0x1ULL << 62)
+#define IVBEP_CB0_MSR_PMON_BOX_FILTER_ISOC     (0x1ULL << 63)
+
+/* IVBEP home agent */
+#define IVBEP_HA_PCI_PMON_CTL_Q_OCC_RST                (1 << 16)
+#define IVBEP_HA_PCI_PMON_RAW_EVENT_MASK               \
+                               (IVBEP_PMON_RAW_EVENT_MASK | \
+                                IVBEP_HA_PCI_PMON_CTL_Q_OCC_RST)
+/* IVBEP PCU */
+#define IVBEP_PCU_MSR_PMON_RAW_EVENT_MASK      \
+                               (SNBEP_PMON_CTL_EV_SEL_MASK | \
+                                SNBEP_PMON_CTL_EV_SEL_EXT | \
+                                SNBEP_PCU_MSR_PMON_CTL_OCC_SEL_MASK | \
+                                SNBEP_PMON_CTL_EDGE_DET | \
+                                SNBEP_PCU_MSR_PMON_CTL_TRESH_MASK | \
+                                SNBEP_PCU_MSR_PMON_CTL_OCC_INVERT | \
+                                SNBEP_PCU_MSR_PMON_CTL_OCC_EDGE_DET)
+/* IVBEP QPI */
+#define IVBEP_QPI_PCI_PMON_RAW_EVENT_MASK      \
+                               (IVBEP_PMON_RAW_EVENT_MASK | \
+                                SNBEP_PMON_CTL_EV_SEL_EXT)
+
+#define __BITS_VALUE(x, i, n)  ((typeof(x))(((x) >> ((i) * (n))) & \
+                               ((1ULL << (n)) - 1)))
+
+/* Haswell-EP Ubox */
+#define HSWEP_U_MSR_PMON_CTR0                  0x705
+#define HSWEP_U_MSR_PMON_CTL0                  0x709
+#define HSWEP_U_MSR_PMON_FILTER                        0x707
+
+#define HSWEP_U_MSR_PMON_UCLK_FIXED_CTL                0x703
+#define HSWEP_U_MSR_PMON_UCLK_FIXED_CTR                0x704
+
+#define HSWEP_U_MSR_PMON_BOX_FILTER_TID                (0x1 << 0)
+#define HSWEP_U_MSR_PMON_BOX_FILTER_CID                (0x1fULL << 1)
+#define HSWEP_U_MSR_PMON_BOX_FILTER_MASK \
+                                       (HSWEP_U_MSR_PMON_BOX_FILTER_TID | \
+                                        HSWEP_U_MSR_PMON_BOX_FILTER_CID)
+
+/* Haswell-EP CBo */
+#define HSWEP_C0_MSR_PMON_CTR0                 0xe08
+#define HSWEP_C0_MSR_PMON_CTL0                 0xe01
+#define HSWEP_C0_MSR_PMON_BOX_CTL                      0xe00
+#define HSWEP_C0_MSR_PMON_BOX_FILTER0          0xe05
+#define HSWEP_CBO_MSR_OFFSET                   0x10
+
+
+#define HSWEP_CB0_MSR_PMON_BOX_FILTER_TID              (0x3fULL << 0)
+#define HSWEP_CB0_MSR_PMON_BOX_FILTER_LINK     (0xfULL << 6)
+#define HSWEP_CB0_MSR_PMON_BOX_FILTER_STATE    (0x7fULL << 17)
+#define HSWEP_CB0_MSR_PMON_BOX_FILTER_NID              (0xffffULL << 32)
+#define HSWEP_CB0_MSR_PMON_BOX_FILTER_OPC              (0x1ffULL << 52)
+#define HSWEP_CB0_MSR_PMON_BOX_FILTER_C6               (0x1ULL << 61)
+#define HSWEP_CB0_MSR_PMON_BOX_FILTER_NC               (0x1ULL << 62)
+#define HSWEP_CB0_MSR_PMON_BOX_FILTER_ISOC     (0x1ULL << 63)
+
+
+/* Haswell-EP Sbox */
+#define HSWEP_S0_MSR_PMON_CTR0                 0x726
+#define HSWEP_S0_MSR_PMON_CTL0                 0x721
+#define HSWEP_S0_MSR_PMON_BOX_CTL                      0x720
+#define HSWEP_SBOX_MSR_OFFSET                  0xa
+#define HSWEP_S_MSR_PMON_RAW_EVENT_MASK                (SNBEP_PMON_RAW_EVENT_MASK | \
+                                                SNBEP_CBO_PMON_CTL_TID_EN)
+
+/* Haswell-EP PCU */
+#define HSWEP_PCU_MSR_PMON_CTR0                        0x717
+#define HSWEP_PCU_MSR_PMON_CTL0                        0x711
+#define HSWEP_PCU_MSR_PMON_BOX_CTL             0x710
+#define HSWEP_PCU_MSR_PMON_BOX_FILTER          0x715
+
+
+DEFINE_UNCORE_FORMAT_ATTR(event, event, "config:0-7");
+DEFINE_UNCORE_FORMAT_ATTR(event_ext, event, "config:0-7,21");
+DEFINE_UNCORE_FORMAT_ATTR(umask, umask, "config:8-15");
+DEFINE_UNCORE_FORMAT_ATTR(edge, edge, "config:18");
+DEFINE_UNCORE_FORMAT_ATTR(tid_en, tid_en, "config:19");
+DEFINE_UNCORE_FORMAT_ATTR(inv, inv, "config:23");
+DEFINE_UNCORE_FORMAT_ATTR(thresh8, thresh, "config:24-31");
+DEFINE_UNCORE_FORMAT_ATTR(thresh5, thresh, "config:24-28");
+DEFINE_UNCORE_FORMAT_ATTR(occ_sel, occ_sel, "config:14-15");
+DEFINE_UNCORE_FORMAT_ATTR(occ_invert, occ_invert, "config:30");
+DEFINE_UNCORE_FORMAT_ATTR(occ_edge, occ_edge, "config:14-51");
+DEFINE_UNCORE_FORMAT_ATTR(filter_tid, filter_tid, "config1:0-4");
+DEFINE_UNCORE_FORMAT_ATTR(filter_tid2, filter_tid, "config1:0");
+DEFINE_UNCORE_FORMAT_ATTR(filter_tid3, filter_tid, "config1:0-5");
+DEFINE_UNCORE_FORMAT_ATTR(filter_cid, filter_cid, "config1:5");
+DEFINE_UNCORE_FORMAT_ATTR(filter_link, filter_link, "config1:5-8");
+DEFINE_UNCORE_FORMAT_ATTR(filter_link2, filter_link, "config1:6-8");
+DEFINE_UNCORE_FORMAT_ATTR(filter_nid, filter_nid, "config1:10-17");
+DEFINE_UNCORE_FORMAT_ATTR(filter_nid2, filter_nid, "config1:32-47");
+DEFINE_UNCORE_FORMAT_ATTR(filter_state, filter_state, "config1:18-22");
+DEFINE_UNCORE_FORMAT_ATTR(filter_state2, filter_state, "config1:17-22");
+DEFINE_UNCORE_FORMAT_ATTR(filter_state3, filter_state, "config1:17-23");
+DEFINE_UNCORE_FORMAT_ATTR(filter_opc, filter_opc, "config1:23-31");
+DEFINE_UNCORE_FORMAT_ATTR(filter_opc2, filter_opc, "config1:52-60");
+DEFINE_UNCORE_FORMAT_ATTR(filter_nc, filter_nc, "config1:62");
+DEFINE_UNCORE_FORMAT_ATTR(filter_c6, filter_c6, "config1:61");
+DEFINE_UNCORE_FORMAT_ATTR(filter_isoc, filter_isoc, "config1:63");
+DEFINE_UNCORE_FORMAT_ATTR(filter_band0, filter_band0, "config1:0-7");
+DEFINE_UNCORE_FORMAT_ATTR(filter_band1, filter_band1, "config1:8-15");
+DEFINE_UNCORE_FORMAT_ATTR(filter_band2, filter_band2, "config1:16-23");
+DEFINE_UNCORE_FORMAT_ATTR(filter_band3, filter_band3, "config1:24-31");
+DEFINE_UNCORE_FORMAT_ATTR(match_rds, match_rds, "config1:48-51");
+DEFINE_UNCORE_FORMAT_ATTR(match_rnid30, match_rnid30, "config1:32-35");
+DEFINE_UNCORE_FORMAT_ATTR(match_rnid4, match_rnid4, "config1:31");
+DEFINE_UNCORE_FORMAT_ATTR(match_dnid, match_dnid, "config1:13-17");
+DEFINE_UNCORE_FORMAT_ATTR(match_mc, match_mc, "config1:9-12");
+DEFINE_UNCORE_FORMAT_ATTR(match_opc, match_opc, "config1:5-8");
+DEFINE_UNCORE_FORMAT_ATTR(match_vnw, match_vnw, "config1:3-4");
+DEFINE_UNCORE_FORMAT_ATTR(match0, match0, "config1:0-31");
+DEFINE_UNCORE_FORMAT_ATTR(match1, match1, "config1:32-63");
+DEFINE_UNCORE_FORMAT_ATTR(mask_rds, mask_rds, "config2:48-51");
+DEFINE_UNCORE_FORMAT_ATTR(mask_rnid30, mask_rnid30, "config2:32-35");
+DEFINE_UNCORE_FORMAT_ATTR(mask_rnid4, mask_rnid4, "config2:31");
+DEFINE_UNCORE_FORMAT_ATTR(mask_dnid, mask_dnid, "config2:13-17");
+DEFINE_UNCORE_FORMAT_ATTR(mask_mc, mask_mc, "config2:9-12");
+DEFINE_UNCORE_FORMAT_ATTR(mask_opc, mask_opc, "config2:5-8");
+DEFINE_UNCORE_FORMAT_ATTR(mask_vnw, mask_vnw, "config2:3-4");
+DEFINE_UNCORE_FORMAT_ATTR(mask0, mask0, "config2:0-31");
+DEFINE_UNCORE_FORMAT_ATTR(mask1, mask1, "config2:32-63");
+
+static void snbep_uncore_pci_disable_box(struct intel_uncore_box *box)
+{
+       struct pci_dev *pdev = box->pci_dev;
+       int box_ctl = uncore_pci_box_ctl(box);
+       u32 config = 0;
+
+       if (!pci_read_config_dword(pdev, box_ctl, &config)) {
+               config |= SNBEP_PMON_BOX_CTL_FRZ;
+               pci_write_config_dword(pdev, box_ctl, config);
+       }
+}
+
+static void snbep_uncore_pci_enable_box(struct intel_uncore_box *box)
+{
+       struct pci_dev *pdev = box->pci_dev;
+       int box_ctl = uncore_pci_box_ctl(box);
+       u32 config = 0;
+
+       if (!pci_read_config_dword(pdev, box_ctl, &config)) {
+               config &= ~SNBEP_PMON_BOX_CTL_FRZ;
+               pci_write_config_dword(pdev, box_ctl, config);
+       }
+}
+
+static void snbep_uncore_pci_enable_event(struct intel_uncore_box *box, struct perf_event *event)
+{
+       struct pci_dev *pdev = box->pci_dev;
+       struct hw_perf_event *hwc = &event->hw;
+
+       pci_write_config_dword(pdev, hwc->config_base, hwc->config | SNBEP_PMON_CTL_EN);
+}
+
+static void snbep_uncore_pci_disable_event(struct intel_uncore_box *box, struct perf_event *event)
+{
+       struct pci_dev *pdev = box->pci_dev;
+       struct hw_perf_event *hwc = &event->hw;
+
+       pci_write_config_dword(pdev, hwc->config_base, hwc->config);
+}
+
+static u64 snbep_uncore_pci_read_counter(struct intel_uncore_box *box, struct perf_event *event)
+{
+       struct pci_dev *pdev = box->pci_dev;
+       struct hw_perf_event *hwc = &event->hw;
+       u64 count = 0;
+
+       pci_read_config_dword(pdev, hwc->event_base, (u32 *)&count);
+       pci_read_config_dword(pdev, hwc->event_base + 4, (u32 *)&count + 1);
+
+       return count;
+}
+
+static void snbep_uncore_pci_init_box(struct intel_uncore_box *box)
+{
+       struct pci_dev *pdev = box->pci_dev;
+
+       pci_write_config_dword(pdev, SNBEP_PCI_PMON_BOX_CTL, SNBEP_PMON_BOX_CTL_INT);
+}
+
+static void snbep_uncore_msr_disable_box(struct intel_uncore_box *box)
+{
+       u64 config;
+       unsigned msr;
+
+       msr = uncore_msr_box_ctl(box);
+       if (msr) {
+               rdmsrl(msr, config);
+               config |= SNBEP_PMON_BOX_CTL_FRZ;
+               wrmsrl(msr, config);
+       }
+}
+
+static void snbep_uncore_msr_enable_box(struct intel_uncore_box *box)
+{
+       u64 config;
+       unsigned msr;
+
+       msr = uncore_msr_box_ctl(box);
+       if (msr) {
+               rdmsrl(msr, config);
+               config &= ~SNBEP_PMON_BOX_CTL_FRZ;
+               wrmsrl(msr, config);
+       }
+}
+
+static void snbep_uncore_msr_enable_event(struct intel_uncore_box *box, struct perf_event *event)
+{
+       struct hw_perf_event *hwc = &event->hw;
+       struct hw_perf_event_extra *reg1 = &hwc->extra_reg;
+
+       if (reg1->idx != EXTRA_REG_NONE)
+               wrmsrl(reg1->reg, uncore_shared_reg_config(box, 0));
+
+       wrmsrl(hwc->config_base, hwc->config | SNBEP_PMON_CTL_EN);
+}
+
+static void snbep_uncore_msr_disable_event(struct intel_uncore_box *box,
+                                       struct perf_event *event)
+{
+       struct hw_perf_event *hwc = &event->hw;
+
+       wrmsrl(hwc->config_base, hwc->config);
+}
+
+static void snbep_uncore_msr_init_box(struct intel_uncore_box *box)
+{
+       unsigned msr = uncore_msr_box_ctl(box);
+
+       if (msr)
+               wrmsrl(msr, SNBEP_PMON_BOX_CTL_INT);
+}
+
+static struct attribute *snbep_uncore_formats_attr[] = {
+       &format_attr_event.attr,
+       &format_attr_umask.attr,
+       &format_attr_edge.attr,
+       &format_attr_inv.attr,
+       &format_attr_thresh8.attr,
+       NULL,
+};
+
+static struct attribute *snbep_uncore_ubox_formats_attr[] = {
+       &format_attr_event.attr,
+       &format_attr_umask.attr,
+       &format_attr_edge.attr,
+       &format_attr_inv.attr,
+       &format_attr_thresh5.attr,
+       NULL,
+};
+
+static struct attribute *snbep_uncore_cbox_formats_attr[] = {
+       &format_attr_event.attr,
+       &format_attr_umask.attr,
+       &format_attr_edge.attr,
+       &format_attr_tid_en.attr,
+       &format_attr_inv.attr,
+       &format_attr_thresh8.attr,
+       &format_attr_filter_tid.attr,
+       &format_attr_filter_nid.attr,
+       &format_attr_filter_state.attr,
+       &format_attr_filter_opc.attr,
+       NULL,
+};
+
+static struct attribute *snbep_uncore_pcu_formats_attr[] = {
+       &format_attr_event_ext.attr,
+       &format_attr_occ_sel.attr,
+       &format_attr_edge.attr,
+       &format_attr_inv.attr,
+       &format_attr_thresh5.attr,
+       &format_attr_occ_invert.attr,
+       &format_attr_occ_edge.attr,
+       &format_attr_filter_band0.attr,
+       &format_attr_filter_band1.attr,
+       &format_attr_filter_band2.attr,
+       &format_attr_filter_band3.attr,
+       NULL,
+};
+
+static struct attribute *snbep_uncore_qpi_formats_attr[] = {
+       &format_attr_event_ext.attr,
+       &format_attr_umask.attr,
+       &format_attr_edge.attr,
+       &format_attr_inv.attr,
+       &format_attr_thresh8.attr,
+       &format_attr_match_rds.attr,
+       &format_attr_match_rnid30.attr,
+       &format_attr_match_rnid4.attr,
+       &format_attr_match_dnid.attr,
+       &format_attr_match_mc.attr,
+       &format_attr_match_opc.attr,
+       &format_attr_match_vnw.attr,
+       &format_attr_match0.attr,
+       &format_attr_match1.attr,
+       &format_attr_mask_rds.attr,
+       &format_attr_mask_rnid30.attr,
+       &format_attr_mask_rnid4.attr,
+       &format_attr_mask_dnid.attr,
+       &format_attr_mask_mc.attr,
+       &format_attr_mask_opc.attr,
+       &format_attr_mask_vnw.attr,
+       &format_attr_mask0.attr,
+       &format_attr_mask1.attr,
+       NULL,
+};
+
+static struct uncore_event_desc snbep_uncore_imc_events[] = {
+       INTEL_UNCORE_EVENT_DESC(clockticks,      "event=0xff,umask=0x00"),
+       INTEL_UNCORE_EVENT_DESC(cas_count_read,  "event=0x04,umask=0x03"),
+       INTEL_UNCORE_EVENT_DESC(cas_count_write, "event=0x04,umask=0x0c"),
+       { /* end: all zeroes */ },
+};
+
+static struct uncore_event_desc snbep_uncore_qpi_events[] = {
+       INTEL_UNCORE_EVENT_DESC(clockticks,       "event=0x14"),
+       INTEL_UNCORE_EVENT_DESC(txl_flits_active, "event=0x00,umask=0x06"),
+       INTEL_UNCORE_EVENT_DESC(drs_data,         "event=0x102,umask=0x08"),
+       INTEL_UNCORE_EVENT_DESC(ncb_data,         "event=0x103,umask=0x04"),
+       { /* end: all zeroes */ },
+};
+
+static struct attribute_group snbep_uncore_format_group = {
+       .name = "format",
+       .attrs = snbep_uncore_formats_attr,
+};
+
+static struct attribute_group snbep_uncore_ubox_format_group = {
+       .name = "format",
+       .attrs = snbep_uncore_ubox_formats_attr,
+};
+
+static struct attribute_group snbep_uncore_cbox_format_group = {
+       .name = "format",
+       .attrs = snbep_uncore_cbox_formats_attr,
+};
+
+static struct attribute_group snbep_uncore_pcu_format_group = {
+       .name = "format",
+       .attrs = snbep_uncore_pcu_formats_attr,
+};
+
+static struct attribute_group snbep_uncore_qpi_format_group = {
+       .name = "format",
+       .attrs = snbep_uncore_qpi_formats_attr,
+};
+
+#define SNBEP_UNCORE_MSR_OPS_COMMON_INIT()                     \
+       .init_box       = snbep_uncore_msr_init_box,            \
+       .disable_box    = snbep_uncore_msr_disable_box,         \
+       .enable_box     = snbep_uncore_msr_enable_box,          \
+       .disable_event  = snbep_uncore_msr_disable_event,       \
+       .enable_event   = snbep_uncore_msr_enable_event,        \
+       .read_counter   = uncore_msr_read_counter
+
+static struct intel_uncore_ops snbep_uncore_msr_ops = {
+       SNBEP_UNCORE_MSR_OPS_COMMON_INIT(),
+};
+
+#define SNBEP_UNCORE_PCI_OPS_COMMON_INIT()                     \
+       .init_box       = snbep_uncore_pci_init_box,            \
+       .disable_box    = snbep_uncore_pci_disable_box,         \
+       .enable_box     = snbep_uncore_pci_enable_box,          \
+       .disable_event  = snbep_uncore_pci_disable_event,       \
+       .read_counter   = snbep_uncore_pci_read_counter
+
+static struct intel_uncore_ops snbep_uncore_pci_ops = {
+       SNBEP_UNCORE_PCI_OPS_COMMON_INIT(),
+       .enable_event   = snbep_uncore_pci_enable_event,        \
+};
+
+static struct event_constraint snbep_uncore_cbox_constraints[] = {
+       UNCORE_EVENT_CONSTRAINT(0x01, 0x1),
+       UNCORE_EVENT_CONSTRAINT(0x02, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x04, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x05, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x07, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x09, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x11, 0x1),
+       UNCORE_EVENT_CONSTRAINT(0x12, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x13, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x1b, 0xc),
+       UNCORE_EVENT_CONSTRAINT(0x1c, 0xc),
+       UNCORE_EVENT_CONSTRAINT(0x1d, 0xc),
+       UNCORE_EVENT_CONSTRAINT(0x1e, 0xc),
+       EVENT_CONSTRAINT_OVERLAP(0x1f, 0xe, 0xff),
+       UNCORE_EVENT_CONSTRAINT(0x21, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x23, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x31, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x32, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x33, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x34, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x35, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x36, 0x1),
+       UNCORE_EVENT_CONSTRAINT(0x37, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x38, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x39, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x3b, 0x1),
+       EVENT_CONSTRAINT_END
+};
+
+static struct event_constraint snbep_uncore_r2pcie_constraints[] = {
+       UNCORE_EVENT_CONSTRAINT(0x10, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x11, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x12, 0x1),
+       UNCORE_EVENT_CONSTRAINT(0x23, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x24, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x25, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x26, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x32, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x33, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x34, 0x3),
+       EVENT_CONSTRAINT_END
+};
+
+static struct event_constraint snbep_uncore_r3qpi_constraints[] = {
+       UNCORE_EVENT_CONSTRAINT(0x10, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x11, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x12, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x13, 0x1),
+       UNCORE_EVENT_CONSTRAINT(0x20, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x21, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x22, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x23, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x24, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x25, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x26, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x28, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x29, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x2a, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x2b, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x2c, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x2d, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x2e, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x2f, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x30, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x31, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x32, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x33, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x34, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x36, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x37, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x38, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x39, 0x3),
+       EVENT_CONSTRAINT_END
+};
+
+static struct intel_uncore_type snbep_uncore_ubox = {
+       .name           = "ubox",
+       .num_counters   = 2,
+       .num_boxes      = 1,
+       .perf_ctr_bits  = 44,
+       .fixed_ctr_bits = 48,
+       .perf_ctr       = SNBEP_U_MSR_PMON_CTR0,
+       .event_ctl      = SNBEP_U_MSR_PMON_CTL0,
+       .event_mask     = SNBEP_U_MSR_PMON_RAW_EVENT_MASK,
+       .fixed_ctr      = SNBEP_U_MSR_PMON_UCLK_FIXED_CTR,
+       .fixed_ctl      = SNBEP_U_MSR_PMON_UCLK_FIXED_CTL,
+       .ops            = &snbep_uncore_msr_ops,
+       .format_group   = &snbep_uncore_ubox_format_group,
+};
+
+static struct extra_reg snbep_uncore_cbox_extra_regs[] = {
+       SNBEP_CBO_EVENT_EXTRA_REG(SNBEP_CBO_PMON_CTL_TID_EN,
+                                 SNBEP_CBO_PMON_CTL_TID_EN, 0x1),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x0334, 0xffff, 0x4),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x4334, 0xffff, 0x6),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x0534, 0xffff, 0x4),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x4534, 0xffff, 0x6),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x0934, 0xffff, 0x4),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x4934, 0xffff, 0x6),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x4134, 0xffff, 0x6),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x0135, 0xffff, 0x8),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x0335, 0xffff, 0x8),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x4135, 0xffff, 0xa),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x4335, 0xffff, 0xa),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x4435, 0xffff, 0x2),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x4835, 0xffff, 0x2),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x4a35, 0xffff, 0x2),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x5035, 0xffff, 0x2),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x0136, 0xffff, 0x8),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x0336, 0xffff, 0x8),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x4136, 0xffff, 0xa),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x4336, 0xffff, 0xa),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x4436, 0xffff, 0x2),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x4836, 0xffff, 0x2),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x4a36, 0xffff, 0x2),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x4037, 0x40ff, 0x2),
+       EVENT_EXTRA_END
+};
+
+static void snbep_cbox_put_constraint(struct intel_uncore_box *box, struct perf_event *event)
+{
+       struct hw_perf_event_extra *reg1 = &event->hw.extra_reg;
+       struct intel_uncore_extra_reg *er = &box->shared_regs[0];
+       int i;
+
+       if (uncore_box_is_fake(box))
+               return;
+
+       for (i = 0; i < 5; i++) {
+               if (reg1->alloc & (0x1 << i))
+                       atomic_sub(1 << (i * 6), &er->ref);
+       }
+       reg1->alloc = 0;
+}
+
+static struct event_constraint *
+__snbep_cbox_get_constraint(struct intel_uncore_box *box, struct perf_event *event,
+                           u64 (*cbox_filter_mask)(int fields))
+{
+       struct hw_perf_event_extra *reg1 = &event->hw.extra_reg;
+       struct intel_uncore_extra_reg *er = &box->shared_regs[0];
+       int i, alloc = 0;
+       unsigned long flags;
+       u64 mask;
+
+       if (reg1->idx == EXTRA_REG_NONE)
+               return NULL;
+
+       raw_spin_lock_irqsave(&er->lock, flags);
+       for (i = 0; i < 5; i++) {
+               if (!(reg1->idx & (0x1 << i)))
+                       continue;
+               if (!uncore_box_is_fake(box) && (reg1->alloc & (0x1 << i)))
+                       continue;
+
+               mask = cbox_filter_mask(0x1 << i);
+               if (!__BITS_VALUE(atomic_read(&er->ref), i, 6) ||
+                   !((reg1->config ^ er->config) & mask)) {
+                       atomic_add(1 << (i * 6), &er->ref);
+                       er->config &= ~mask;
+                       er->config |= reg1->config & mask;
+                       alloc |= (0x1 << i);
+               } else {
+                       break;
+               }
+       }
+       raw_spin_unlock_irqrestore(&er->lock, flags);
+       if (i < 5)
+               goto fail;
+
+       if (!uncore_box_is_fake(box))
+               reg1->alloc |= alloc;
+
+       return NULL;
+fail:
+       for (; i >= 0; i--) {
+               if (alloc & (0x1 << i))
+                       atomic_sub(1 << (i * 6), &er->ref);
+       }
+       return &uncore_constraint_empty;
+}
+
+static u64 snbep_cbox_filter_mask(int fields)
+{
+       u64 mask = 0;
+
+       if (fields & 0x1)
+               mask |= SNBEP_CB0_MSR_PMON_BOX_FILTER_TID;
+       if (fields & 0x2)
+               mask |= SNBEP_CB0_MSR_PMON_BOX_FILTER_NID;
+       if (fields & 0x4)
+               mask |= SNBEP_CB0_MSR_PMON_BOX_FILTER_STATE;
+       if (fields & 0x8)
+               mask |= SNBEP_CB0_MSR_PMON_BOX_FILTER_OPC;
+
+       return mask;
+}
+
+static struct event_constraint *
+snbep_cbox_get_constraint(struct intel_uncore_box *box, struct perf_event *event)
+{
+       return __snbep_cbox_get_constraint(box, event, snbep_cbox_filter_mask);
+}
+
+static int snbep_cbox_hw_config(struct intel_uncore_box *box, struct perf_event *event)
+{
+       struct hw_perf_event_extra *reg1 = &event->hw.extra_reg;
+       struct extra_reg *er;
+       int idx = 0;
+
+       for (er = snbep_uncore_cbox_extra_regs; er->msr; er++) {
+               if (er->event != (event->hw.config & er->config_mask))
+                       continue;
+               idx |= er->idx;
+       }
+
+       if (idx) {
+               reg1->reg = SNBEP_C0_MSR_PMON_BOX_FILTER +
+                       SNBEP_CBO_MSR_OFFSET * box->pmu->pmu_idx;
+               reg1->config = event->attr.config1 & snbep_cbox_filter_mask(idx);
+               reg1->idx = idx;
+       }
+       return 0;
+}
+
+static struct intel_uncore_ops snbep_uncore_cbox_ops = {
+       SNBEP_UNCORE_MSR_OPS_COMMON_INIT(),
+       .hw_config              = snbep_cbox_hw_config,
+       .get_constraint         = snbep_cbox_get_constraint,
+       .put_constraint         = snbep_cbox_put_constraint,
+};
+
+static struct intel_uncore_type snbep_uncore_cbox = {
+       .name                   = "cbox",
+       .num_counters           = 4,
+       .num_boxes              = 8,
+       .perf_ctr_bits          = 44,
+       .event_ctl              = SNBEP_C0_MSR_PMON_CTL0,
+       .perf_ctr               = SNBEP_C0_MSR_PMON_CTR0,
+       .event_mask             = SNBEP_CBO_MSR_PMON_RAW_EVENT_MASK,
+       .box_ctl                = SNBEP_C0_MSR_PMON_BOX_CTL,
+       .msr_offset             = SNBEP_CBO_MSR_OFFSET,
+       .num_shared_regs        = 1,
+       .constraints            = snbep_uncore_cbox_constraints,
+       .ops                    = &snbep_uncore_cbox_ops,
+       .format_group           = &snbep_uncore_cbox_format_group,
+};
+
+static u64 snbep_pcu_alter_er(struct perf_event *event, int new_idx, bool modify)
+{
+       struct hw_perf_event *hwc = &event->hw;
+       struct hw_perf_event_extra *reg1 = &hwc->extra_reg;
+       u64 config = reg1->config;
+
+       if (new_idx > reg1->idx)
+               config <<= 8 * (new_idx - reg1->idx);
+       else
+               config >>= 8 * (reg1->idx - new_idx);
+
+       if (modify) {
+               hwc->config += new_idx - reg1->idx;
+               reg1->config = config;
+               reg1->idx = new_idx;
+       }
+       return config;
+}
+
+static struct event_constraint *
+snbep_pcu_get_constraint(struct intel_uncore_box *box, struct perf_event *event)
+{
+       struct hw_perf_event_extra *reg1 = &event->hw.extra_reg;
+       struct intel_uncore_extra_reg *er = &box->shared_regs[0];
+       unsigned long flags;
+       int idx = reg1->idx;
+       u64 mask, config1 = reg1->config;
+       bool ok = false;
+
+       if (reg1->idx == EXTRA_REG_NONE ||
+           (!uncore_box_is_fake(box) && reg1->alloc))
+               return NULL;
+again:
+       mask = 0xffULL << (idx * 8);
+       raw_spin_lock_irqsave(&er->lock, flags);
+       if (!__BITS_VALUE(atomic_read(&er->ref), idx, 8) ||
+           !((config1 ^ er->config) & mask)) {
+               atomic_add(1 << (idx * 8), &er->ref);
+               er->config &= ~mask;
+               er->config |= config1 & mask;
+               ok = true;
+       }
+       raw_spin_unlock_irqrestore(&er->lock, flags);
+
+       if (!ok) {
+               idx = (idx + 1) % 4;
+               if (idx != reg1->idx) {
+                       config1 = snbep_pcu_alter_er(event, idx, false);
+                       goto again;
+               }
+               return &uncore_constraint_empty;
+       }
+
+       if (!uncore_box_is_fake(box)) {
+               if (idx != reg1->idx)
+                       snbep_pcu_alter_er(event, idx, true);
+               reg1->alloc = 1;
+       }
+       return NULL;
+}
+
+static void snbep_pcu_put_constraint(struct intel_uncore_box *box, struct perf_event *event)
+{
+       struct hw_perf_event_extra *reg1 = &event->hw.extra_reg;
+       struct intel_uncore_extra_reg *er = &box->shared_regs[0];
+
+       if (uncore_box_is_fake(box) || !reg1->alloc)
+               return;
+
+       atomic_sub(1 << (reg1->idx * 8), &er->ref);
+       reg1->alloc = 0;
+}
+
+static int snbep_pcu_hw_config(struct intel_uncore_box *box, struct perf_event *event)
+{
+       struct hw_perf_event *hwc = &event->hw;
+       struct hw_perf_event_extra *reg1 = &hwc->extra_reg;
+       int ev_sel = hwc->config & SNBEP_PMON_CTL_EV_SEL_MASK;
+
+       if (ev_sel >= 0xb && ev_sel <= 0xe) {
+               reg1->reg = SNBEP_PCU_MSR_PMON_BOX_FILTER;
+               reg1->idx = ev_sel - 0xb;
+               reg1->config = event->attr.config1 & (0xff << (reg1->idx * 8));
+       }
+       return 0;
+}
+
+static struct intel_uncore_ops snbep_uncore_pcu_ops = {
+       SNBEP_UNCORE_MSR_OPS_COMMON_INIT(),
+       .hw_config              = snbep_pcu_hw_config,
+       .get_constraint         = snbep_pcu_get_constraint,
+       .put_constraint         = snbep_pcu_put_constraint,
+};
+
+static struct intel_uncore_type snbep_uncore_pcu = {
+       .name                   = "pcu",
+       .num_counters           = 4,
+       .num_boxes              = 1,
+       .perf_ctr_bits          = 48,
+       .perf_ctr               = SNBEP_PCU_MSR_PMON_CTR0,
+       .event_ctl              = SNBEP_PCU_MSR_PMON_CTL0,
+       .event_mask             = SNBEP_PCU_MSR_PMON_RAW_EVENT_MASK,
+       .box_ctl                = SNBEP_PCU_MSR_PMON_BOX_CTL,
+       .num_shared_regs        = 1,
+       .ops                    = &snbep_uncore_pcu_ops,
+       .format_group           = &snbep_uncore_pcu_format_group,
+};
+
+static struct intel_uncore_type *snbep_msr_uncores[] = {
+       &snbep_uncore_ubox,
+       &snbep_uncore_cbox,
+       &snbep_uncore_pcu,
+       NULL,
+};
+
+void snbep_uncore_cpu_init(void)
+{
+       if (snbep_uncore_cbox.num_boxes > boot_cpu_data.x86_max_cores)
+               snbep_uncore_cbox.num_boxes = boot_cpu_data.x86_max_cores;
+       uncore_msr_uncores = snbep_msr_uncores;
+}
+
+enum {
+       SNBEP_PCI_QPI_PORT0_FILTER,
+       SNBEP_PCI_QPI_PORT1_FILTER,
+};
+
+static int snbep_qpi_hw_config(struct intel_uncore_box *box, struct perf_event *event)
+{
+       struct hw_perf_event *hwc = &event->hw;
+       struct hw_perf_event_extra *reg1 = &hwc->extra_reg;
+       struct hw_perf_event_extra *reg2 = &hwc->branch_reg;
+
+       if ((hwc->config & SNBEP_PMON_CTL_EV_SEL_MASK) == 0x38) {
+               reg1->idx = 0;
+               reg1->reg = SNBEP_Q_Py_PCI_PMON_PKT_MATCH0;
+               reg1->config = event->attr.config1;
+               reg2->reg = SNBEP_Q_Py_PCI_PMON_PKT_MASK0;
+               reg2->config = event->attr.config2;
+       }
+       return 0;
+}
+
+static void snbep_qpi_enable_event(struct intel_uncore_box *box, struct perf_event *event)
+{
+       struct pci_dev *pdev = box->pci_dev;
+       struct hw_perf_event *hwc = &event->hw;
+       struct hw_perf_event_extra *reg1 = &hwc->extra_reg;
+       struct hw_perf_event_extra *reg2 = &hwc->branch_reg;
+
+       if (reg1->idx != EXTRA_REG_NONE) {
+               int idx = box->pmu->pmu_idx + SNBEP_PCI_QPI_PORT0_FILTER;
+               struct pci_dev *filter_pdev = uncore_extra_pci_dev[box->phys_id][idx];
+               if (filter_pdev) {
+                       pci_write_config_dword(filter_pdev, reg1->reg,
+                                               (u32)reg1->config);
+                       pci_write_config_dword(filter_pdev, reg1->reg + 4,
+                                               (u32)(reg1->config >> 32));
+                       pci_write_config_dword(filter_pdev, reg2->reg,
+                                               (u32)reg2->config);
+                       pci_write_config_dword(filter_pdev, reg2->reg + 4,
+                                               (u32)(reg2->config >> 32));
+               }
+       }
+
+       pci_write_config_dword(pdev, hwc->config_base, hwc->config | SNBEP_PMON_CTL_EN);
+}
+
+static struct intel_uncore_ops snbep_uncore_qpi_ops = {
+       SNBEP_UNCORE_PCI_OPS_COMMON_INIT(),
+       .enable_event           = snbep_qpi_enable_event,
+       .hw_config              = snbep_qpi_hw_config,
+       .get_constraint         = uncore_get_constraint,
+       .put_constraint         = uncore_put_constraint,
+};
+
+#define SNBEP_UNCORE_PCI_COMMON_INIT()                         \
+       .perf_ctr       = SNBEP_PCI_PMON_CTR0,                  \
+       .event_ctl      = SNBEP_PCI_PMON_CTL0,                  \
+       .event_mask     = SNBEP_PMON_RAW_EVENT_MASK,            \
+       .box_ctl        = SNBEP_PCI_PMON_BOX_CTL,               \
+       .ops            = &snbep_uncore_pci_ops,                \
+       .format_group   = &snbep_uncore_format_group
+
+static struct intel_uncore_type snbep_uncore_ha = {
+       .name           = "ha",
+       .num_counters   = 4,
+       .num_boxes      = 1,
+       .perf_ctr_bits  = 48,
+       SNBEP_UNCORE_PCI_COMMON_INIT(),
+};
+
+static struct intel_uncore_type snbep_uncore_imc = {
+       .name           = "imc",
+       .num_counters   = 4,
+       .num_boxes      = 4,
+       .perf_ctr_bits  = 48,
+       .fixed_ctr_bits = 48,
+       .fixed_ctr      = SNBEP_MC_CHy_PCI_PMON_FIXED_CTR,
+       .fixed_ctl      = SNBEP_MC_CHy_PCI_PMON_FIXED_CTL,
+       .event_descs    = snbep_uncore_imc_events,
+       SNBEP_UNCORE_PCI_COMMON_INIT(),
+};
+
+static struct intel_uncore_type snbep_uncore_qpi = {
+       .name                   = "qpi",
+       .num_counters           = 4,
+       .num_boxes              = 2,
+       .perf_ctr_bits          = 48,
+       .perf_ctr               = SNBEP_PCI_PMON_CTR0,
+       .event_ctl              = SNBEP_PCI_PMON_CTL0,
+       .event_mask             = SNBEP_QPI_PCI_PMON_RAW_EVENT_MASK,
+       .box_ctl                = SNBEP_PCI_PMON_BOX_CTL,
+       .num_shared_regs        = 1,
+       .ops                    = &snbep_uncore_qpi_ops,
+       .event_descs            = snbep_uncore_qpi_events,
+       .format_group           = &snbep_uncore_qpi_format_group,
+};
+
+
+static struct intel_uncore_type snbep_uncore_r2pcie = {
+       .name           = "r2pcie",
+       .num_counters   = 4,
+       .num_boxes      = 1,
+       .perf_ctr_bits  = 44,
+       .constraints    = snbep_uncore_r2pcie_constraints,
+       SNBEP_UNCORE_PCI_COMMON_INIT(),
+};
+
+static struct intel_uncore_type snbep_uncore_r3qpi = {
+       .name           = "r3qpi",
+       .num_counters   = 3,
+       .num_boxes      = 2,
+       .perf_ctr_bits  = 44,
+       .constraints    = snbep_uncore_r3qpi_constraints,
+       SNBEP_UNCORE_PCI_COMMON_INIT(),
+};
+
+enum {
+       SNBEP_PCI_UNCORE_HA,
+       SNBEP_PCI_UNCORE_IMC,
+       SNBEP_PCI_UNCORE_QPI,
+       SNBEP_PCI_UNCORE_R2PCIE,
+       SNBEP_PCI_UNCORE_R3QPI,
+};
+
+static struct intel_uncore_type *snbep_pci_uncores[] = {
+       [SNBEP_PCI_UNCORE_HA]           = &snbep_uncore_ha,
+       [SNBEP_PCI_UNCORE_IMC]          = &snbep_uncore_imc,
+       [SNBEP_PCI_UNCORE_QPI]          = &snbep_uncore_qpi,
+       [SNBEP_PCI_UNCORE_R2PCIE]       = &snbep_uncore_r2pcie,
+       [SNBEP_PCI_UNCORE_R3QPI]        = &snbep_uncore_r3qpi,
+       NULL,
+};
+
+static const struct pci_device_id snbep_uncore_pci_ids[] = {
+       { /* Home Agent */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_UNC_HA),
+               .driver_data = UNCORE_PCI_DEV_DATA(SNBEP_PCI_UNCORE_HA, 0),
+       },
+       { /* MC Channel 0 */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_UNC_IMC0),
+               .driver_data = UNCORE_PCI_DEV_DATA(SNBEP_PCI_UNCORE_IMC, 0),
+       },
+       { /* MC Channel 1 */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_UNC_IMC1),
+               .driver_data = UNCORE_PCI_DEV_DATA(SNBEP_PCI_UNCORE_IMC, 1),
+       },
+       { /* MC Channel 2 */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_UNC_IMC2),
+               .driver_data = UNCORE_PCI_DEV_DATA(SNBEP_PCI_UNCORE_IMC, 2),
+       },
+       { /* MC Channel 3 */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_UNC_IMC3),
+               .driver_data = UNCORE_PCI_DEV_DATA(SNBEP_PCI_UNCORE_IMC, 3),
+       },
+       { /* QPI Port 0 */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_UNC_QPI0),
+               .driver_data = UNCORE_PCI_DEV_DATA(SNBEP_PCI_UNCORE_QPI, 0),
+       },
+       { /* QPI Port 1 */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_UNC_QPI1),
+               .driver_data = UNCORE_PCI_DEV_DATA(SNBEP_PCI_UNCORE_QPI, 1),
+       },
+       { /* R2PCIe */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_UNC_R2PCIE),
+               .driver_data = UNCORE_PCI_DEV_DATA(SNBEP_PCI_UNCORE_R2PCIE, 0),
+       },
+       { /* R3QPI Link 0 */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_UNC_R3QPI0),
+               .driver_data = UNCORE_PCI_DEV_DATA(SNBEP_PCI_UNCORE_R3QPI, 0),
+       },
+       { /* R3QPI Link 1 */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_UNC_R3QPI1),
+               .driver_data = UNCORE_PCI_DEV_DATA(SNBEP_PCI_UNCORE_R3QPI, 1),
+       },
+       { /* QPI Port 0 filter  */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x3c86),
+               .driver_data = UNCORE_PCI_DEV_DATA(UNCORE_EXTRA_PCI_DEV,
+                                                  SNBEP_PCI_QPI_PORT0_FILTER),
+       },
+       { /* QPI Port 0 filter  */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x3c96),
+               .driver_data = UNCORE_PCI_DEV_DATA(UNCORE_EXTRA_PCI_DEV,
+                                                  SNBEP_PCI_QPI_PORT1_FILTER),
+       },
+       { /* end: all zeroes */ }
+};
+
+static struct pci_driver snbep_uncore_pci_driver = {
+       .name           = "snbep_uncore",
+       .id_table       = snbep_uncore_pci_ids,
+};
+
+/*
+ * build pci bus to socket mapping
+ */
+static int snbep_pci2phy_map_init(int devid)
+{
+       struct pci_dev *ubox_dev = NULL;
+       int i, bus, nodeid;
+       int err = 0;
+       u32 config = 0;
+
+       while (1) {
+               /* find the UBOX device */
+               ubox_dev = pci_get_device(PCI_VENDOR_ID_INTEL, devid, ubox_dev);
+               if (!ubox_dev)
+                       break;
+               bus = ubox_dev->bus->number;
+               /* get the Node ID of the local register */
+               err = pci_read_config_dword(ubox_dev, 0x40, &config);
+               if (err)
+                       break;
+               nodeid = config;
+               /* get the Node ID mapping */
+               err = pci_read_config_dword(ubox_dev, 0x54, &config);
+               if (err)
+                       break;
+               /*
+                * every three bits in the Node ID mapping register maps
+                * to a particular node.
+                */
+               for (i = 0; i < 8; i++) {
+                       if (nodeid == ((config >> (3 * i)) & 0x7)) {
+                               uncore_pcibus_to_physid[bus] = i;
+                               break;
+                       }
+               }
+       }
+
+       if (!err) {
+               /*
+                * For PCI bus with no UBOX device, find the next bus
+                * that has UBOX device and use its mapping.
+                */
+               i = -1;
+               for (bus = 255; bus >= 0; bus--) {
+                       if (uncore_pcibus_to_physid[bus] >= 0)
+                               i = uncore_pcibus_to_physid[bus];
+                       else
+                               uncore_pcibus_to_physid[bus] = i;
+               }
+       }
+
+       if (ubox_dev)
+               pci_dev_put(ubox_dev);
+
+       return err ? pcibios_err_to_errno(err) : 0;
+}
+
+int snbep_uncore_pci_init(void)
+{
+       int ret = snbep_pci2phy_map_init(0x3ce0);
+       if (ret)
+               return ret;
+       uncore_pci_uncores = snbep_pci_uncores;
+       uncore_pci_driver = &snbep_uncore_pci_driver;
+       return 0;
+}
+/* end of Sandy Bridge-EP uncore support */
+
+/* IvyTown uncore support */
+static void ivbep_uncore_msr_init_box(struct intel_uncore_box *box)
+{
+       unsigned msr = uncore_msr_box_ctl(box);
+       if (msr)
+               wrmsrl(msr, IVBEP_PMON_BOX_CTL_INT);
+}
+
+static void ivbep_uncore_pci_init_box(struct intel_uncore_box *box)
+{
+       struct pci_dev *pdev = box->pci_dev;
+
+       pci_write_config_dword(pdev, SNBEP_PCI_PMON_BOX_CTL, IVBEP_PMON_BOX_CTL_INT);
+}
+
+#define IVBEP_UNCORE_MSR_OPS_COMMON_INIT()                     \
+       .init_box       = ivbep_uncore_msr_init_box,            \
+       .disable_box    = snbep_uncore_msr_disable_box,         \
+       .enable_box     = snbep_uncore_msr_enable_box,          \
+       .disable_event  = snbep_uncore_msr_disable_event,       \
+       .enable_event   = snbep_uncore_msr_enable_event,        \
+       .read_counter   = uncore_msr_read_counter
+
+static struct intel_uncore_ops ivbep_uncore_msr_ops = {
+       IVBEP_UNCORE_MSR_OPS_COMMON_INIT(),
+};
+
+static struct intel_uncore_ops ivbep_uncore_pci_ops = {
+       .init_box       = ivbep_uncore_pci_init_box,
+       .disable_box    = snbep_uncore_pci_disable_box,
+       .enable_box     = snbep_uncore_pci_enable_box,
+       .disable_event  = snbep_uncore_pci_disable_event,
+       .enable_event   = snbep_uncore_pci_enable_event,
+       .read_counter   = snbep_uncore_pci_read_counter,
+};
+
+#define IVBEP_UNCORE_PCI_COMMON_INIT()                         \
+       .perf_ctr       = SNBEP_PCI_PMON_CTR0,                  \
+       .event_ctl      = SNBEP_PCI_PMON_CTL0,                  \
+       .event_mask     = IVBEP_PMON_RAW_EVENT_MASK,            \
+       .box_ctl        = SNBEP_PCI_PMON_BOX_CTL,               \
+       .ops            = &ivbep_uncore_pci_ops,                        \
+       .format_group   = &ivbep_uncore_format_group
+
+static struct attribute *ivbep_uncore_formats_attr[] = {
+       &format_attr_event.attr,
+       &format_attr_umask.attr,
+       &format_attr_edge.attr,
+       &format_attr_inv.attr,
+       &format_attr_thresh8.attr,
+       NULL,
+};
+
+static struct attribute *ivbep_uncore_ubox_formats_attr[] = {
+       &format_attr_event.attr,
+       &format_attr_umask.attr,
+       &format_attr_edge.attr,
+       &format_attr_inv.attr,
+       &format_attr_thresh5.attr,
+       NULL,
+};
+
+static struct attribute *ivbep_uncore_cbox_formats_attr[] = {
+       &format_attr_event.attr,
+       &format_attr_umask.attr,
+       &format_attr_edge.attr,
+       &format_attr_tid_en.attr,
+       &format_attr_thresh8.attr,
+       &format_attr_filter_tid.attr,
+       &format_attr_filter_link.attr,
+       &format_attr_filter_state2.attr,
+       &format_attr_filter_nid2.attr,
+       &format_attr_filter_opc2.attr,
+       &format_attr_filter_nc.attr,
+       &format_attr_filter_c6.attr,
+       &format_attr_filter_isoc.attr,
+       NULL,
+};
+
+static struct attribute *ivbep_uncore_pcu_formats_attr[] = {
+       &format_attr_event_ext.attr,
+       &format_attr_occ_sel.attr,
+       &format_attr_edge.attr,
+       &format_attr_thresh5.attr,
+       &format_attr_occ_invert.attr,
+       &format_attr_occ_edge.attr,
+       &format_attr_filter_band0.attr,
+       &format_attr_filter_band1.attr,
+       &format_attr_filter_band2.attr,
+       &format_attr_filter_band3.attr,
+       NULL,
+};
+
+static struct attribute *ivbep_uncore_qpi_formats_attr[] = {
+       &format_attr_event_ext.attr,
+       &format_attr_umask.attr,
+       &format_attr_edge.attr,
+       &format_attr_thresh8.attr,
+       &format_attr_match_rds.attr,
+       &format_attr_match_rnid30.attr,
+       &format_attr_match_rnid4.attr,
+       &format_attr_match_dnid.attr,
+       &format_attr_match_mc.attr,
+       &format_attr_match_opc.attr,
+       &format_attr_match_vnw.attr,
+       &format_attr_match0.attr,
+       &format_attr_match1.attr,
+       &format_attr_mask_rds.attr,
+       &format_attr_mask_rnid30.attr,
+       &format_attr_mask_rnid4.attr,
+       &format_attr_mask_dnid.attr,
+       &format_attr_mask_mc.attr,
+       &format_attr_mask_opc.attr,
+       &format_attr_mask_vnw.attr,
+       &format_attr_mask0.attr,
+       &format_attr_mask1.attr,
+       NULL,
+};
+
+static struct attribute_group ivbep_uncore_format_group = {
+       .name = "format",
+       .attrs = ivbep_uncore_formats_attr,
+};
+
+static struct attribute_group ivbep_uncore_ubox_format_group = {
+       .name = "format",
+       .attrs = ivbep_uncore_ubox_formats_attr,
+};
+
+static struct attribute_group ivbep_uncore_cbox_format_group = {
+       .name = "format",
+       .attrs = ivbep_uncore_cbox_formats_attr,
+};
+
+static struct attribute_group ivbep_uncore_pcu_format_group = {
+       .name = "format",
+       .attrs = ivbep_uncore_pcu_formats_attr,
+};
+
+static struct attribute_group ivbep_uncore_qpi_format_group = {
+       .name = "format",
+       .attrs = ivbep_uncore_qpi_formats_attr,
+};
+
+static struct intel_uncore_type ivbep_uncore_ubox = {
+       .name           = "ubox",
+       .num_counters   = 2,
+       .num_boxes      = 1,
+       .perf_ctr_bits  = 44,
+       .fixed_ctr_bits = 48,
+       .perf_ctr       = SNBEP_U_MSR_PMON_CTR0,
+       .event_ctl      = SNBEP_U_MSR_PMON_CTL0,
+       .event_mask     = IVBEP_U_MSR_PMON_RAW_EVENT_MASK,
+       .fixed_ctr      = SNBEP_U_MSR_PMON_UCLK_FIXED_CTR,
+       .fixed_ctl      = SNBEP_U_MSR_PMON_UCLK_FIXED_CTL,
+       .ops            = &ivbep_uncore_msr_ops,
+       .format_group   = &ivbep_uncore_ubox_format_group,
+};
+
+static struct extra_reg ivbep_uncore_cbox_extra_regs[] = {
+       SNBEP_CBO_EVENT_EXTRA_REG(SNBEP_CBO_PMON_CTL_TID_EN,
+                                 SNBEP_CBO_PMON_CTL_TID_EN, 0x1),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x1031, 0x10ff, 0x2),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x1134, 0xffff, 0x4),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x4134, 0xffff, 0xc),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x5134, 0xffff, 0xc),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x0334, 0xffff, 0x4),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x4334, 0xffff, 0xc),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x0534, 0xffff, 0x4),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x4534, 0xffff, 0xc),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x0934, 0xffff, 0x4),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x4934, 0xffff, 0xc),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x0135, 0xffff, 0x10),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x0335, 0xffff, 0x10),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x2135, 0xffff, 0x10),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x2335, 0xffff, 0x10),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x4135, 0xffff, 0x18),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x4335, 0xffff, 0x18),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x4435, 0xffff, 0x8),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x4835, 0xffff, 0x8),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x4a35, 0xffff, 0x8),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x5035, 0xffff, 0x8),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x8135, 0xffff, 0x10),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x8335, 0xffff, 0x10),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x0136, 0xffff, 0x10),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x0336, 0xffff, 0x10),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x2136, 0xffff, 0x10),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x2336, 0xffff, 0x10),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x4136, 0xffff, 0x18),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x4336, 0xffff, 0x18),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x4436, 0xffff, 0x8),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x4836, 0xffff, 0x8),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x4a36, 0xffff, 0x8),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x5036, 0xffff, 0x8),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x8136, 0xffff, 0x10),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x8336, 0xffff, 0x10),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x4037, 0x40ff, 0x8),
+       EVENT_EXTRA_END
+};
+
+static u64 ivbep_cbox_filter_mask(int fields)
+{
+       u64 mask = 0;
+
+       if (fields & 0x1)
+               mask |= IVBEP_CB0_MSR_PMON_BOX_FILTER_TID;
+       if (fields & 0x2)
+               mask |= IVBEP_CB0_MSR_PMON_BOX_FILTER_LINK;
+       if (fields & 0x4)
+               mask |= IVBEP_CB0_MSR_PMON_BOX_FILTER_STATE;
+       if (fields & 0x8)
+               mask |= IVBEP_CB0_MSR_PMON_BOX_FILTER_NID;
+       if (fields & 0x10) {
+               mask |= IVBEP_CB0_MSR_PMON_BOX_FILTER_OPC;
+               mask |= IVBEP_CB0_MSR_PMON_BOX_FILTER_NC;
+               mask |= IVBEP_CB0_MSR_PMON_BOX_FILTER_C6;
+               mask |= IVBEP_CB0_MSR_PMON_BOX_FILTER_ISOC;
+       }
+
+       return mask;
+}
+
+static struct event_constraint *
+ivbep_cbox_get_constraint(struct intel_uncore_box *box, struct perf_event *event)
+{
+       return __snbep_cbox_get_constraint(box, event, ivbep_cbox_filter_mask);
+}
+
+static int ivbep_cbox_hw_config(struct intel_uncore_box *box, struct perf_event *event)
+{
+       struct hw_perf_event_extra *reg1 = &event->hw.extra_reg;
+       struct extra_reg *er;
+       int idx = 0;
+
+       for (er = ivbep_uncore_cbox_extra_regs; er->msr; er++) {
+               if (er->event != (event->hw.config & er->config_mask))
+                       continue;
+               idx |= er->idx;
+       }
+
+       if (idx) {
+               reg1->reg = SNBEP_C0_MSR_PMON_BOX_FILTER +
+                       SNBEP_CBO_MSR_OFFSET * box->pmu->pmu_idx;
+               reg1->config = event->attr.config1 & ivbep_cbox_filter_mask(idx);
+               reg1->idx = idx;
+       }
+       return 0;
+}
+
+static void ivbep_cbox_enable_event(struct intel_uncore_box *box, struct perf_event *event)
+{
+       struct hw_perf_event *hwc = &event->hw;
+       struct hw_perf_event_extra *reg1 = &hwc->extra_reg;
+
+       if (reg1->idx != EXTRA_REG_NONE) {
+               u64 filter = uncore_shared_reg_config(box, 0);
+               wrmsrl(reg1->reg, filter & 0xffffffff);
+               wrmsrl(reg1->reg + 6, filter >> 32);
+       }
+
+       wrmsrl(hwc->config_base, hwc->config | SNBEP_PMON_CTL_EN);
+}
+
+static struct intel_uncore_ops ivbep_uncore_cbox_ops = {
+       .init_box               = ivbep_uncore_msr_init_box,
+       .disable_box            = snbep_uncore_msr_disable_box,
+       .enable_box             = snbep_uncore_msr_enable_box,
+       .disable_event          = snbep_uncore_msr_disable_event,
+       .enable_event           = ivbep_cbox_enable_event,
+       .read_counter           = uncore_msr_read_counter,
+       .hw_config              = ivbep_cbox_hw_config,
+       .get_constraint         = ivbep_cbox_get_constraint,
+       .put_constraint         = snbep_cbox_put_constraint,
+};
+
+static struct intel_uncore_type ivbep_uncore_cbox = {
+       .name                   = "cbox",
+       .num_counters           = 4,
+       .num_boxes              = 15,
+       .perf_ctr_bits          = 44,
+       .event_ctl              = SNBEP_C0_MSR_PMON_CTL0,
+       .perf_ctr               = SNBEP_C0_MSR_PMON_CTR0,
+       .event_mask             = IVBEP_CBO_MSR_PMON_RAW_EVENT_MASK,
+       .box_ctl                = SNBEP_C0_MSR_PMON_BOX_CTL,
+       .msr_offset             = SNBEP_CBO_MSR_OFFSET,
+       .num_shared_regs        = 1,
+       .constraints            = snbep_uncore_cbox_constraints,
+       .ops                    = &ivbep_uncore_cbox_ops,
+       .format_group           = &ivbep_uncore_cbox_format_group,
+};
+
+static struct intel_uncore_ops ivbep_uncore_pcu_ops = {
+       IVBEP_UNCORE_MSR_OPS_COMMON_INIT(),
+       .hw_config              = snbep_pcu_hw_config,
+       .get_constraint         = snbep_pcu_get_constraint,
+       .put_constraint         = snbep_pcu_put_constraint,
+};
+
+static struct intel_uncore_type ivbep_uncore_pcu = {
+       .name                   = "pcu",
+       .num_counters           = 4,
+       .num_boxes              = 1,
+       .perf_ctr_bits          = 48,
+       .perf_ctr               = SNBEP_PCU_MSR_PMON_CTR0,
+       .event_ctl              = SNBEP_PCU_MSR_PMON_CTL0,
+       .event_mask             = IVBEP_PCU_MSR_PMON_RAW_EVENT_MASK,
+       .box_ctl                = SNBEP_PCU_MSR_PMON_BOX_CTL,
+       .num_shared_regs        = 1,
+       .ops                    = &ivbep_uncore_pcu_ops,
+       .format_group           = &ivbep_uncore_pcu_format_group,
+};
+
+static struct intel_uncore_type *ivbep_msr_uncores[] = {
+       &ivbep_uncore_ubox,
+       &ivbep_uncore_cbox,
+       &ivbep_uncore_pcu,
+       NULL,
+};
+
+void ivbep_uncore_cpu_init(void)
+{
+       if (ivbep_uncore_cbox.num_boxes > boot_cpu_data.x86_max_cores)
+               ivbep_uncore_cbox.num_boxes = boot_cpu_data.x86_max_cores;
+       uncore_msr_uncores = ivbep_msr_uncores;
+}
+
+static struct intel_uncore_type ivbep_uncore_ha = {
+       .name           = "ha",
+       .num_counters   = 4,
+       .num_boxes      = 2,
+       .perf_ctr_bits  = 48,
+       IVBEP_UNCORE_PCI_COMMON_INIT(),
+};
+
+static struct intel_uncore_type ivbep_uncore_imc = {
+       .name           = "imc",
+       .num_counters   = 4,
+       .num_boxes      = 8,
+       .perf_ctr_bits  = 48,
+       .fixed_ctr_bits = 48,
+       .fixed_ctr      = SNBEP_MC_CHy_PCI_PMON_FIXED_CTR,
+       .fixed_ctl      = SNBEP_MC_CHy_PCI_PMON_FIXED_CTL,
+       .event_descs    = snbep_uncore_imc_events,
+       IVBEP_UNCORE_PCI_COMMON_INIT(),
+};
+
+/* registers in IRP boxes are not properly aligned */
+static unsigned ivbep_uncore_irp_ctls[] = {0xd8, 0xdc, 0xe0, 0xe4};
+static unsigned ivbep_uncore_irp_ctrs[] = {0xa0, 0xb0, 0xb8, 0xc0};
+
+static void ivbep_uncore_irp_enable_event(struct intel_uncore_box *box, struct perf_event *event)
+{
+       struct pci_dev *pdev = box->pci_dev;
+       struct hw_perf_event *hwc = &event->hw;
+
+       pci_write_config_dword(pdev, ivbep_uncore_irp_ctls[hwc->idx],
+                              hwc->config | SNBEP_PMON_CTL_EN);
+}
+
+static void ivbep_uncore_irp_disable_event(struct intel_uncore_box *box, struct perf_event *event)
+{
+       struct pci_dev *pdev = box->pci_dev;
+       struct hw_perf_event *hwc = &event->hw;
+
+       pci_write_config_dword(pdev, ivbep_uncore_irp_ctls[hwc->idx], hwc->config);
+}
+
+static u64 ivbep_uncore_irp_read_counter(struct intel_uncore_box *box, struct perf_event *event)
+{
+       struct pci_dev *pdev = box->pci_dev;
+       struct hw_perf_event *hwc = &event->hw;
+       u64 count = 0;
+
+       pci_read_config_dword(pdev, ivbep_uncore_irp_ctrs[hwc->idx], (u32 *)&count);
+       pci_read_config_dword(pdev, ivbep_uncore_irp_ctrs[hwc->idx] + 4, (u32 *)&count + 1);
+
+       return count;
+}
+
+static struct intel_uncore_ops ivbep_uncore_irp_ops = {
+       .init_box       = ivbep_uncore_pci_init_box,
+       .disable_box    = snbep_uncore_pci_disable_box,
+       .enable_box     = snbep_uncore_pci_enable_box,
+       .disable_event  = ivbep_uncore_irp_disable_event,
+       .enable_event   = ivbep_uncore_irp_enable_event,
+       .read_counter   = ivbep_uncore_irp_read_counter,
+};
+
+static struct intel_uncore_type ivbep_uncore_irp = {
+       .name                   = "irp",
+       .num_counters           = 4,
+       .num_boxes              = 1,
+       .perf_ctr_bits          = 48,
+       .event_mask             = IVBEP_PMON_RAW_EVENT_MASK,
+       .box_ctl                = SNBEP_PCI_PMON_BOX_CTL,
+       .ops                    = &ivbep_uncore_irp_ops,
+       .format_group           = &ivbep_uncore_format_group,
+};
+
+static struct intel_uncore_ops ivbep_uncore_qpi_ops = {
+       .init_box       = ivbep_uncore_pci_init_box,
+       .disable_box    = snbep_uncore_pci_disable_box,
+       .enable_box     = snbep_uncore_pci_enable_box,
+       .disable_event  = snbep_uncore_pci_disable_event,
+       .enable_event   = snbep_qpi_enable_event,
+       .read_counter   = snbep_uncore_pci_read_counter,
+       .hw_config      = snbep_qpi_hw_config,
+       .get_constraint = uncore_get_constraint,
+       .put_constraint = uncore_put_constraint,
+};
+
+static struct intel_uncore_type ivbep_uncore_qpi = {
+       .name                   = "qpi",
+       .num_counters           = 4,
+       .num_boxes              = 3,
+       .perf_ctr_bits          = 48,
+       .perf_ctr               = SNBEP_PCI_PMON_CTR0,
+       .event_ctl              = SNBEP_PCI_PMON_CTL0,
+       .event_mask             = IVBEP_QPI_PCI_PMON_RAW_EVENT_MASK,
+       .box_ctl                = SNBEP_PCI_PMON_BOX_CTL,
+       .num_shared_regs        = 1,
+       .ops                    = &ivbep_uncore_qpi_ops,
+       .format_group           = &ivbep_uncore_qpi_format_group,
+};
+
+static struct intel_uncore_type ivbep_uncore_r2pcie = {
+       .name           = "r2pcie",
+       .num_counters   = 4,
+       .num_boxes      = 1,
+       .perf_ctr_bits  = 44,
+       .constraints    = snbep_uncore_r2pcie_constraints,
+       IVBEP_UNCORE_PCI_COMMON_INIT(),
+};
+
+static struct intel_uncore_type ivbep_uncore_r3qpi = {
+       .name           = "r3qpi",
+       .num_counters   = 3,
+       .num_boxes      = 2,
+       .perf_ctr_bits  = 44,
+       .constraints    = snbep_uncore_r3qpi_constraints,
+       IVBEP_UNCORE_PCI_COMMON_INIT(),
+};
+
+enum {
+       IVBEP_PCI_UNCORE_HA,
+       IVBEP_PCI_UNCORE_IMC,
+       IVBEP_PCI_UNCORE_IRP,
+       IVBEP_PCI_UNCORE_QPI,
+       IVBEP_PCI_UNCORE_R2PCIE,
+       IVBEP_PCI_UNCORE_R3QPI,
+};
+
+static struct intel_uncore_type *ivbep_pci_uncores[] = {
+       [IVBEP_PCI_UNCORE_HA]   = &ivbep_uncore_ha,
+       [IVBEP_PCI_UNCORE_IMC]  = &ivbep_uncore_imc,
+       [IVBEP_PCI_UNCORE_IRP]  = &ivbep_uncore_irp,
+       [IVBEP_PCI_UNCORE_QPI]  = &ivbep_uncore_qpi,
+       [IVBEP_PCI_UNCORE_R2PCIE]       = &ivbep_uncore_r2pcie,
+       [IVBEP_PCI_UNCORE_R3QPI]        = &ivbep_uncore_r3qpi,
+       NULL,
+};
+
+static const struct pci_device_id ivbep_uncore_pci_ids[] = {
+       { /* Home Agent 0 */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xe30),
+               .driver_data = UNCORE_PCI_DEV_DATA(IVBEP_PCI_UNCORE_HA, 0),
+       },
+       { /* Home Agent 1 */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xe38),
+               .driver_data = UNCORE_PCI_DEV_DATA(IVBEP_PCI_UNCORE_HA, 1),
+       },
+       { /* MC0 Channel 0 */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xeb4),
+               .driver_data = UNCORE_PCI_DEV_DATA(IVBEP_PCI_UNCORE_IMC, 0),
+       },
+       { /* MC0 Channel 1 */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xeb5),
+               .driver_data = UNCORE_PCI_DEV_DATA(IVBEP_PCI_UNCORE_IMC, 1),
+       },
+       { /* MC0 Channel 3 */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xeb0),
+               .driver_data = UNCORE_PCI_DEV_DATA(IVBEP_PCI_UNCORE_IMC, 2),
+       },
+       { /* MC0 Channel 4 */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xeb1),
+               .driver_data = UNCORE_PCI_DEV_DATA(IVBEP_PCI_UNCORE_IMC, 3),
+       },
+       { /* MC1 Channel 0 */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xef4),
+               .driver_data = UNCORE_PCI_DEV_DATA(IVBEP_PCI_UNCORE_IMC, 4),
+       },
+       { /* MC1 Channel 1 */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xef5),
+               .driver_data = UNCORE_PCI_DEV_DATA(IVBEP_PCI_UNCORE_IMC, 5),
+       },
+       { /* MC1 Channel 3 */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xef0),
+               .driver_data = UNCORE_PCI_DEV_DATA(IVBEP_PCI_UNCORE_IMC, 6),
+       },
+       { /* MC1 Channel 4 */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xef1),
+               .driver_data = UNCORE_PCI_DEV_DATA(IVBEP_PCI_UNCORE_IMC, 7),
+       },
+       { /* IRP */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xe39),
+               .driver_data = UNCORE_PCI_DEV_DATA(IVBEP_PCI_UNCORE_IRP, 0),
+       },
+       { /* QPI0 Port 0 */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xe32),
+               .driver_data = UNCORE_PCI_DEV_DATA(IVBEP_PCI_UNCORE_QPI, 0),
+       },
+       { /* QPI0 Port 1 */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xe33),
+               .driver_data = UNCORE_PCI_DEV_DATA(IVBEP_PCI_UNCORE_QPI, 1),
+       },
+       { /* QPI1 Port 2 */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xe3a),
+               .driver_data = UNCORE_PCI_DEV_DATA(IVBEP_PCI_UNCORE_QPI, 2),
+       },
+       { /* R2PCIe */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xe34),
+               .driver_data = UNCORE_PCI_DEV_DATA(IVBEP_PCI_UNCORE_R2PCIE, 0),
+       },
+       { /* R3QPI0 Link 0 */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xe36),
+               .driver_data = UNCORE_PCI_DEV_DATA(IVBEP_PCI_UNCORE_R3QPI, 0),
+       },
+       { /* R3QPI0 Link 1 */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xe37),
+               .driver_data = UNCORE_PCI_DEV_DATA(IVBEP_PCI_UNCORE_R3QPI, 1),
+       },
+       { /* R3QPI1 Link 2 */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xe3e),
+               .driver_data = UNCORE_PCI_DEV_DATA(IVBEP_PCI_UNCORE_R3QPI, 2),
+       },
+       { /* QPI Port 0 filter  */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xe86),
+               .driver_data = UNCORE_PCI_DEV_DATA(UNCORE_EXTRA_PCI_DEV,
+                                                  SNBEP_PCI_QPI_PORT0_FILTER),
+       },
+       { /* QPI Port 0 filter  */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xe96),
+               .driver_data = UNCORE_PCI_DEV_DATA(UNCORE_EXTRA_PCI_DEV,
+                                                  SNBEP_PCI_QPI_PORT1_FILTER),
+       },
+       { /* end: all zeroes */ }
+};
+
+static struct pci_driver ivbep_uncore_pci_driver = {
+       .name           = "ivbep_uncore",
+       .id_table       = ivbep_uncore_pci_ids,
+};
+
+int ivbep_uncore_pci_init(void)
+{
+       int ret = snbep_pci2phy_map_init(0x0e1e);
+       if (ret)
+               return ret;
+       uncore_pci_uncores = ivbep_pci_uncores;
+       uncore_pci_driver = &ivbep_uncore_pci_driver;
+       return 0;
+}
+/* end of IvyTown uncore support */
+
+/* Haswell-EP uncore support */
+static struct attribute *hswep_uncore_ubox_formats_attr[] = {
+       &format_attr_event.attr,
+       &format_attr_umask.attr,
+       &format_attr_edge.attr,
+       &format_attr_inv.attr,
+       &format_attr_thresh5.attr,
+       &format_attr_filter_tid2.attr,
+       &format_attr_filter_cid.attr,
+       NULL,
+};
+
+static struct attribute_group hswep_uncore_ubox_format_group = {
+       .name = "format",
+       .attrs = hswep_uncore_ubox_formats_attr,
+};
+
+static int hswep_ubox_hw_config(struct intel_uncore_box *box, struct perf_event *event)
+{
+       struct hw_perf_event_extra *reg1 = &event->hw.extra_reg;
+       reg1->reg = HSWEP_U_MSR_PMON_FILTER;
+       reg1->config = event->attr.config1 & HSWEP_U_MSR_PMON_BOX_FILTER_MASK;
+       reg1->idx = 0;
+       return 0;
+}
+
+static struct intel_uncore_ops hswep_uncore_ubox_ops = {
+       SNBEP_UNCORE_MSR_OPS_COMMON_INIT(),
+       .hw_config              = hswep_ubox_hw_config,
+       .get_constraint         = uncore_get_constraint,
+       .put_constraint         = uncore_put_constraint,
+};
+
+static struct intel_uncore_type hswep_uncore_ubox = {
+       .name                   = "ubox",
+       .num_counters           = 2,
+       .num_boxes              = 1,
+       .perf_ctr_bits          = 44,
+       .fixed_ctr_bits         = 48,
+       .perf_ctr               = HSWEP_U_MSR_PMON_CTR0,
+       .event_ctl              = HSWEP_U_MSR_PMON_CTL0,
+       .event_mask             = SNBEP_U_MSR_PMON_RAW_EVENT_MASK,
+       .fixed_ctr              = HSWEP_U_MSR_PMON_UCLK_FIXED_CTR,
+       .fixed_ctl              = HSWEP_U_MSR_PMON_UCLK_FIXED_CTL,
+       .num_shared_regs        = 1,
+       .ops                    = &hswep_uncore_ubox_ops,
+       .format_group           = &hswep_uncore_ubox_format_group,
+};
+
+static struct attribute *hswep_uncore_cbox_formats_attr[] = {
+       &format_attr_event.attr,
+       &format_attr_umask.attr,
+       &format_attr_edge.attr,
+       &format_attr_tid_en.attr,
+       &format_attr_thresh8.attr,
+       &format_attr_filter_tid3.attr,
+       &format_attr_filter_link2.attr,
+       &format_attr_filter_state3.attr,
+       &format_attr_filter_nid2.attr,
+       &format_attr_filter_opc2.attr,
+       &format_attr_filter_nc.attr,
+       &format_attr_filter_c6.attr,
+       &format_attr_filter_isoc.attr,
+       NULL,
+};
+
+static struct attribute_group hswep_uncore_cbox_format_group = {
+       .name = "format",
+       .attrs = hswep_uncore_cbox_formats_attr,
+};
+
+static struct event_constraint hswep_uncore_cbox_constraints[] = {
+       UNCORE_EVENT_CONSTRAINT(0x01, 0x1),
+       UNCORE_EVENT_CONSTRAINT(0x09, 0x1),
+       UNCORE_EVENT_CONSTRAINT(0x11, 0x1),
+       UNCORE_EVENT_CONSTRAINT(0x36, 0x1),
+       UNCORE_EVENT_CONSTRAINT(0x38, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x3b, 0x1),
+       UNCORE_EVENT_CONSTRAINT(0x3e, 0x1),
+       EVENT_CONSTRAINT_END
+};
+
+static struct extra_reg hswep_uncore_cbox_extra_regs[] = {
+       SNBEP_CBO_EVENT_EXTRA_REG(SNBEP_CBO_PMON_CTL_TID_EN,
+                                 SNBEP_CBO_PMON_CTL_TID_EN, 0x1),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x0334, 0xffff, 0x4),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x0534, 0xffff, 0x4),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x0934, 0xffff, 0x4),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x1134, 0xffff, 0x4),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x2134, 0xffff, 0x4),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x4134, 0xffff, 0x4),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x4037, 0x40ff, 0x8),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x4028, 0x40ff, 0x8),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x4032, 0x40ff, 0x8),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x4029, 0x40ff, 0x8),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x4033, 0x40ff, 0x8),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x402A, 0x40ff, 0x8),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x0135, 0xffff, 0x12),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x0335, 0xffff, 0x10),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x4135, 0xffff, 0x18),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x4435, 0xffff, 0x8),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x4835, 0xffff, 0x8),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x5035, 0xffff, 0x8),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x4335, 0xffff, 0x18),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x4a35, 0xffff, 0x8),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x2335, 0xffff, 0x10),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x8335, 0xffff, 0x10),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x2135, 0xffff, 0x10),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x8135, 0xffff, 0x10),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x0136, 0xffff, 0x10),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x0336, 0xffff, 0x10),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x4136, 0xffff, 0x18),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x4436, 0xffff, 0x8),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x4836, 0xffff, 0x8),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x4336, 0xffff, 0x18),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x4a36, 0xffff, 0x8),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x2336, 0xffff, 0x10),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x8336, 0xffff, 0x10),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x2136, 0xffff, 0x10),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x8136, 0xffff, 0x10),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x5036, 0xffff, 0x8),
+       EVENT_EXTRA_END
+};
+
+static u64 hswep_cbox_filter_mask(int fields)
+{
+       u64 mask = 0;
+       if (fields & 0x1)
+               mask |= HSWEP_CB0_MSR_PMON_BOX_FILTER_TID;
+       if (fields & 0x2)
+               mask |= HSWEP_CB0_MSR_PMON_BOX_FILTER_LINK;
+       if (fields & 0x4)
+               mask |= HSWEP_CB0_MSR_PMON_BOX_FILTER_STATE;
+       if (fields & 0x8)
+               mask |= HSWEP_CB0_MSR_PMON_BOX_FILTER_NID;
+       if (fields & 0x10) {
+               mask |= HSWEP_CB0_MSR_PMON_BOX_FILTER_OPC;
+               mask |= HSWEP_CB0_MSR_PMON_BOX_FILTER_NC;
+               mask |= HSWEP_CB0_MSR_PMON_BOX_FILTER_C6;
+               mask |= HSWEP_CB0_MSR_PMON_BOX_FILTER_ISOC;
+       }
+       return mask;
+}
+
+static struct event_constraint *
+hswep_cbox_get_constraint(struct intel_uncore_box *box, struct perf_event *event)
+{
+       return __snbep_cbox_get_constraint(box, event, hswep_cbox_filter_mask);
+}
+
+static int hswep_cbox_hw_config(struct intel_uncore_box *box, struct perf_event *event)
+{
+       struct hw_perf_event_extra *reg1 = &event->hw.extra_reg;
+       struct extra_reg *er;
+       int idx = 0;
+
+       for (er = hswep_uncore_cbox_extra_regs; er->msr; er++) {
+               if (er->event != (event->hw.config & er->config_mask))
+                       continue;
+               idx |= er->idx;
+       }
+
+       if (idx) {
+               reg1->reg = HSWEP_C0_MSR_PMON_BOX_FILTER0 +
+                           HSWEP_CBO_MSR_OFFSET * box->pmu->pmu_idx;
+               reg1->config = event->attr.config1 & hswep_cbox_filter_mask(idx);
+               reg1->idx = idx;
+       }
+       return 0;
+}
+
+static void hswep_cbox_enable_event(struct intel_uncore_box *box,
+                                 struct perf_event *event)
+{
+       struct hw_perf_event *hwc = &event->hw;
+       struct hw_perf_event_extra *reg1 = &hwc->extra_reg;
+
+       if (reg1->idx != EXTRA_REG_NONE) {
+               u64 filter = uncore_shared_reg_config(box, 0);
+               wrmsrl(reg1->reg, filter & 0xffffffff);
+               wrmsrl(reg1->reg + 1, filter >> 32);
+       }
+
+       wrmsrl(hwc->config_base, hwc->config | SNBEP_PMON_CTL_EN);
+}
+
+static struct intel_uncore_ops hswep_uncore_cbox_ops = {
+       .init_box               = snbep_uncore_msr_init_box,
+       .disable_box            = snbep_uncore_msr_disable_box,
+       .enable_box             = snbep_uncore_msr_enable_box,
+       .disable_event          = snbep_uncore_msr_disable_event,
+       .enable_event           = hswep_cbox_enable_event,
+       .read_counter           = uncore_msr_read_counter,
+       .hw_config              = hswep_cbox_hw_config,
+       .get_constraint         = hswep_cbox_get_constraint,
+       .put_constraint         = snbep_cbox_put_constraint,
+};
+
+static struct intel_uncore_type hswep_uncore_cbox = {
+       .name                   = "cbox",
+       .num_counters           = 4,
+       .num_boxes              = 18,
+       .perf_ctr_bits          = 44,
+       .event_ctl              = HSWEP_C0_MSR_PMON_CTL0,
+       .perf_ctr               = HSWEP_C0_MSR_PMON_CTR0,
+       .event_mask             = SNBEP_CBO_MSR_PMON_RAW_EVENT_MASK,
+       .box_ctl                = HSWEP_C0_MSR_PMON_BOX_CTL,
+       .msr_offset             = HSWEP_CBO_MSR_OFFSET,
+       .num_shared_regs        = 1,
+       .constraints            = hswep_uncore_cbox_constraints,
+       .ops                    = &hswep_uncore_cbox_ops,
+       .format_group           = &hswep_uncore_cbox_format_group,
+};
+
+static struct attribute *hswep_uncore_sbox_formats_attr[] = {
+       &format_attr_event.attr,
+       &format_attr_umask.attr,
+       &format_attr_edge.attr,
+       &format_attr_tid_en.attr,
+       &format_attr_inv.attr,
+       &format_attr_thresh8.attr,
+       NULL,
+};
+
+static struct attribute_group hswep_uncore_sbox_format_group = {
+       .name = "format",
+       .attrs = hswep_uncore_sbox_formats_attr,
+};
+
+static struct intel_uncore_type hswep_uncore_sbox = {
+       .name                   = "sbox",
+       .num_counters           = 4,
+       .num_boxes              = 4,
+       .perf_ctr_bits          = 44,
+       .event_ctl              = HSWEP_S0_MSR_PMON_CTL0,
+       .perf_ctr               = HSWEP_S0_MSR_PMON_CTR0,
+       .event_mask             = HSWEP_S_MSR_PMON_RAW_EVENT_MASK,
+       .box_ctl                = HSWEP_S0_MSR_PMON_BOX_CTL,
+       .msr_offset             = HSWEP_SBOX_MSR_OFFSET,
+       .ops                    = &snbep_uncore_msr_ops,
+       .format_group           = &hswep_uncore_sbox_format_group,
+};
+
+static int hswep_pcu_hw_config(struct intel_uncore_box *box, struct perf_event *event)
+{
+       struct hw_perf_event *hwc = &event->hw;
+       struct hw_perf_event_extra *reg1 = &hwc->extra_reg;
+       int ev_sel = hwc->config & SNBEP_PMON_CTL_EV_SEL_MASK;
+
+       if (ev_sel >= 0xb && ev_sel <= 0xe) {
+               reg1->reg = HSWEP_PCU_MSR_PMON_BOX_FILTER;
+               reg1->idx = ev_sel - 0xb;
+               reg1->config = event->attr.config1 & (0xff << reg1->idx);
+       }
+       return 0;
+}
+
+static struct intel_uncore_ops hswep_uncore_pcu_ops = {
+       SNBEP_UNCORE_MSR_OPS_COMMON_INIT(),
+       .hw_config              = hswep_pcu_hw_config,
+       .get_constraint         = snbep_pcu_get_constraint,
+       .put_constraint         = snbep_pcu_put_constraint,
+};
+
+static struct intel_uncore_type hswep_uncore_pcu = {
+       .name                   = "pcu",
+       .num_counters           = 4,
+       .num_boxes              = 1,
+       .perf_ctr_bits          = 48,
+       .perf_ctr               = HSWEP_PCU_MSR_PMON_CTR0,
+       .event_ctl              = HSWEP_PCU_MSR_PMON_CTL0,
+       .event_mask             = SNBEP_PCU_MSR_PMON_RAW_EVENT_MASK,
+       .box_ctl                = HSWEP_PCU_MSR_PMON_BOX_CTL,
+       .num_shared_regs        = 1,
+       .ops                    = &hswep_uncore_pcu_ops,
+       .format_group           = &snbep_uncore_pcu_format_group,
+};
+
+static struct intel_uncore_type *hswep_msr_uncores[] = {
+       &hswep_uncore_ubox,
+       &hswep_uncore_cbox,
+       &hswep_uncore_sbox,
+       &hswep_uncore_pcu,
+       NULL,
+};
+
+void hswep_uncore_cpu_init(void)
+{
+       if (hswep_uncore_cbox.num_boxes > boot_cpu_data.x86_max_cores)
+               hswep_uncore_cbox.num_boxes = boot_cpu_data.x86_max_cores;
+       uncore_msr_uncores = hswep_msr_uncores;
+}
+
+static struct intel_uncore_type hswep_uncore_ha = {
+       .name           = "ha",
+       .num_counters   = 5,
+       .num_boxes      = 2,
+       .perf_ctr_bits  = 48,
+       SNBEP_UNCORE_PCI_COMMON_INIT(),
+};
+
+static struct uncore_event_desc hswep_uncore_imc_events[] = {
+       INTEL_UNCORE_EVENT_DESC(clockticks,      "event=0x00,umask=0x00"),
+       INTEL_UNCORE_EVENT_DESC(cas_count_read,  "event=0x04,umask=0x03"),
+       INTEL_UNCORE_EVENT_DESC(cas_count_write, "event=0x04,umask=0x0c"),
+       { /* end: all zeroes */ },
+};
+
+static struct intel_uncore_type hswep_uncore_imc = {
+       .name           = "imc",
+       .num_counters   = 5,
+       .num_boxes      = 8,
+       .perf_ctr_bits  = 48,
+       .fixed_ctr_bits = 48,
+       .fixed_ctr      = SNBEP_MC_CHy_PCI_PMON_FIXED_CTR,
+       .fixed_ctl      = SNBEP_MC_CHy_PCI_PMON_FIXED_CTL,
+       .event_descs    = hswep_uncore_imc_events,
+       SNBEP_UNCORE_PCI_COMMON_INIT(),
+};
+
+static struct intel_uncore_ops hswep_uncore_irp_ops = {
+       .init_box       = snbep_uncore_pci_init_box,
+       .disable_box    = snbep_uncore_pci_disable_box,
+       .enable_box     = snbep_uncore_pci_enable_box,
+       .disable_event  = ivbep_uncore_irp_disable_event,
+       .enable_event   = ivbep_uncore_irp_enable_event,
+       .read_counter   = ivbep_uncore_irp_read_counter,
+};
+
+static struct intel_uncore_type hswep_uncore_irp = {
+       .name                   = "irp",
+       .num_counters           = 4,
+       .num_boxes              = 1,
+       .perf_ctr_bits          = 48,
+       .event_mask             = SNBEP_PMON_RAW_EVENT_MASK,
+       .box_ctl                = SNBEP_PCI_PMON_BOX_CTL,
+       .ops                    = &hswep_uncore_irp_ops,
+       .format_group           = &snbep_uncore_format_group,
+};
+
+static struct intel_uncore_type hswep_uncore_qpi = {
+       .name                   = "qpi",
+       .num_counters           = 5,
+       .num_boxes              = 3,
+       .perf_ctr_bits          = 48,
+       .perf_ctr               = SNBEP_PCI_PMON_CTR0,
+       .event_ctl              = SNBEP_PCI_PMON_CTL0,
+       .event_mask             = SNBEP_QPI_PCI_PMON_RAW_EVENT_MASK,
+       .box_ctl                = SNBEP_PCI_PMON_BOX_CTL,
+       .num_shared_regs        = 1,
+       .ops                    = &snbep_uncore_qpi_ops,
+       .format_group           = &snbep_uncore_qpi_format_group,
+};
+
+static struct event_constraint hswep_uncore_r2pcie_constraints[] = {
+       UNCORE_EVENT_CONSTRAINT(0x10, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x11, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x13, 0x1),
+       UNCORE_EVENT_CONSTRAINT(0x23, 0x1),
+       UNCORE_EVENT_CONSTRAINT(0x24, 0x1),
+       UNCORE_EVENT_CONSTRAINT(0x25, 0x1),
+       UNCORE_EVENT_CONSTRAINT(0x26, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x27, 0x1),
+       UNCORE_EVENT_CONSTRAINT(0x28, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x29, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x2a, 0x1),
+       UNCORE_EVENT_CONSTRAINT(0x2b, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x2c, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x2d, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x32, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x33, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x34, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x35, 0x3),
+       EVENT_CONSTRAINT_END
+};
+
+static struct intel_uncore_type hswep_uncore_r2pcie = {
+       .name           = "r2pcie",
+       .num_counters   = 4,
+       .num_boxes      = 1,
+       .perf_ctr_bits  = 48,
+       .constraints    = hswep_uncore_r2pcie_constraints,
+       SNBEP_UNCORE_PCI_COMMON_INIT(),
+};
+
+static struct event_constraint hswep_uncore_r3qpi_constraints[] = {
+       UNCORE_EVENT_CONSTRAINT(0x01, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x07, 0x7),
+       UNCORE_EVENT_CONSTRAINT(0x08, 0x7),
+       UNCORE_EVENT_CONSTRAINT(0x09, 0x7),
+       UNCORE_EVENT_CONSTRAINT(0x0a, 0x7),
+       UNCORE_EVENT_CONSTRAINT(0x0e, 0x7),
+       UNCORE_EVENT_CONSTRAINT(0x10, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x11, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x12, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x13, 0x1),
+       UNCORE_EVENT_CONSTRAINT(0x14, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x15, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x1f, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x20, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x21, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x22, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x23, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x25, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x26, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x28, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x29, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x2c, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x2d, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x2e, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x2f, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x31, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x32, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x33, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x34, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x36, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x37, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x38, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x39, 0x3),
+       EVENT_CONSTRAINT_END
+};
+
+static struct intel_uncore_type hswep_uncore_r3qpi = {
+       .name           = "r3qpi",
+       .num_counters   = 4,
+       .num_boxes      = 3,
+       .perf_ctr_bits  = 44,
+       .constraints    = hswep_uncore_r3qpi_constraints,
+       SNBEP_UNCORE_PCI_COMMON_INIT(),
+};
+
+enum {
+       HSWEP_PCI_UNCORE_HA,
+       HSWEP_PCI_UNCORE_IMC,
+       HSWEP_PCI_UNCORE_IRP,
+       HSWEP_PCI_UNCORE_QPI,
+       HSWEP_PCI_UNCORE_R2PCIE,
+       HSWEP_PCI_UNCORE_R3QPI,
+};
+
+static struct intel_uncore_type *hswep_pci_uncores[] = {
+       [HSWEP_PCI_UNCORE_HA]   = &hswep_uncore_ha,
+       [HSWEP_PCI_UNCORE_IMC]  = &hswep_uncore_imc,
+       [HSWEP_PCI_UNCORE_IRP]  = &hswep_uncore_irp,
+       [HSWEP_PCI_UNCORE_QPI]  = &hswep_uncore_qpi,
+       [HSWEP_PCI_UNCORE_R2PCIE]       = &hswep_uncore_r2pcie,
+       [HSWEP_PCI_UNCORE_R3QPI]        = &hswep_uncore_r3qpi,
+       NULL,
+};
+
+static DEFINE_PCI_DEVICE_TABLE(hswep_uncore_pci_ids) = {
+       { /* Home Agent 0 */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x2f30),
+               .driver_data = UNCORE_PCI_DEV_DATA(HSWEP_PCI_UNCORE_HA, 0),
+       },
+       { /* Home Agent 1 */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x2f38),
+               .driver_data = UNCORE_PCI_DEV_DATA(HSWEP_PCI_UNCORE_HA, 1),
+       },
+       { /* MC0 Channel 0 */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x2fb0),
+               .driver_data = UNCORE_PCI_DEV_DATA(HSWEP_PCI_UNCORE_IMC, 0),
+       },
+       { /* MC0 Channel 1 */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x2fb1),
+               .driver_data = UNCORE_PCI_DEV_DATA(HSWEP_PCI_UNCORE_IMC, 1),
+       },
+       { /* MC0 Channel 2 */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x2fb4),
+               .driver_data = UNCORE_PCI_DEV_DATA(HSWEP_PCI_UNCORE_IMC, 2),
+       },
+       { /* MC0 Channel 3 */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x2fb5),
+               .driver_data = UNCORE_PCI_DEV_DATA(HSWEP_PCI_UNCORE_IMC, 3),
+       },
+       { /* MC1 Channel 0 */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x2fd0),
+               .driver_data = UNCORE_PCI_DEV_DATA(HSWEP_PCI_UNCORE_IMC, 4),
+       },
+       { /* MC1 Channel 1 */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x2fd1),
+               .driver_data = UNCORE_PCI_DEV_DATA(HSWEP_PCI_UNCORE_IMC, 5),
+       },
+       { /* MC1 Channel 2 */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x2fd4),
+               .driver_data = UNCORE_PCI_DEV_DATA(HSWEP_PCI_UNCORE_IMC, 6),
+       },
+       { /* MC1 Channel 3 */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x2fd5),
+               .driver_data = UNCORE_PCI_DEV_DATA(HSWEP_PCI_UNCORE_IMC, 7),
+       },
+       { /* IRP */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x2f39),
+               .driver_data = UNCORE_PCI_DEV_DATA(HSWEP_PCI_UNCORE_IRP, 0),
+       },
+       { /* QPI0 Port 0 */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x2f32),
+               .driver_data = UNCORE_PCI_DEV_DATA(HSWEP_PCI_UNCORE_QPI, 0),
+       },
+       { /* QPI0 Port 1 */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x2f33),
+               .driver_data = UNCORE_PCI_DEV_DATA(HSWEP_PCI_UNCORE_QPI, 1),
+       },
+       { /* QPI1 Port 2 */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x2f3a),
+               .driver_data = UNCORE_PCI_DEV_DATA(HSWEP_PCI_UNCORE_QPI, 2),
+       },
+       { /* R2PCIe */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x2f34),
+               .driver_data = UNCORE_PCI_DEV_DATA(HSWEP_PCI_UNCORE_R2PCIE, 0),
+       },
+       { /* R3QPI0 Link 0 */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x2f36),
+               .driver_data = UNCORE_PCI_DEV_DATA(HSWEP_PCI_UNCORE_R3QPI, 0),
+       },
+       { /* R3QPI0 Link 1 */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x2f37),
+               .driver_data = UNCORE_PCI_DEV_DATA(HSWEP_PCI_UNCORE_R3QPI, 1),
+       },
+       { /* R3QPI1 Link 2 */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x2f3e),
+               .driver_data = UNCORE_PCI_DEV_DATA(HSWEP_PCI_UNCORE_R3QPI, 2),
+       },
+       { /* QPI Port 0 filter  */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x2f86),
+               .driver_data = UNCORE_PCI_DEV_DATA(UNCORE_EXTRA_PCI_DEV,
+                                                  SNBEP_PCI_QPI_PORT0_FILTER),
+       },
+       { /* QPI Port 1 filter  */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x2f96),
+               .driver_data = UNCORE_PCI_DEV_DATA(UNCORE_EXTRA_PCI_DEV,
+                                                  SNBEP_PCI_QPI_PORT1_FILTER),
+       },
+       { /* end: all zeroes */ }
+};
+
+static struct pci_driver hswep_uncore_pci_driver = {
+       .name           = "hswep_uncore",
+       .id_table       = hswep_uncore_pci_ids,
+};
+
+int hswep_uncore_pci_init(void)
+{
+       int ret = snbep_pci2phy_map_init(0x2f1e);
+       if (ret)
+               return ret;
+       uncore_pci_uncores = hswep_pci_uncores;
+       uncore_pci_driver = &hswep_uncore_pci_driver;
+       return 0;
+}
+/* end of Haswell-EP uncore support */
index a618fcd2c07d3d54062a8558a7f9941b16859203..f5ab56d1428718f6327c91012d5373cc200438a2 100644 (file)
@@ -237,7 +237,7 @@ static void fill_up_crash_elf_data(struct crash_elf_data *ced,
        ced->max_nr_ranges++;
 
        /* If crashk_low_res is not 0, another range split possible */
-       if (crashk_low_res.end != 0)
+       if (crashk_low_res.end)
                ced->max_nr_ranges++;
 }
 
@@ -335,9 +335,11 @@ static int elf_header_exclude_ranges(struct crash_elf_data *ced,
        if (ret)
                return ret;
 
-       ret = exclude_mem_range(cmem, crashk_low_res.start, crashk_low_res.end);
-       if (ret)
-               return ret;
+       if (crashk_low_res.end) {
+               ret = exclude_mem_range(cmem, crashk_low_res.start, crashk_low_res.end);
+               if (ret)
+                       return ret;
+       }
 
        /* Exclude GART region */
        if (ced->gart_end) {
index 988c00a1f60dac037defb41d4419e82abaa7202c..49f88648161551a4d788cbe7952b0d256bc8eae4 100644 (file)
@@ -682,15 +682,14 @@ void __init parse_e820_ext(u64 phys_addr, u32 data_len)
  * hibernation (32 bit) or software suspend and suspend to RAM (64 bit).
  *
  * This function requires the e820 map to be sorted and without any
- * overlapping entries and assumes the first e820 area to be RAM.
+ * overlapping entries.
  */
 void __init e820_mark_nosave_regions(unsigned long limit_pfn)
 {
        int i;
-       unsigned long pfn;
+       unsigned long pfn = 0;
 
-       pfn = PFN_DOWN(e820.map[0].addr + e820.map[0].size);
-       for (i = 1; i < e820.nr_map; i++) {
+       for (i = 0; i < e820.nr_map; i++) {
                struct e820entry *ei = &e820.map[i];
 
                if (pfn < PFN_UP(ei->addr))
index 2fac1343a90b605fe41ebcde6ca965bd25021489..df088bb03fb3ffec9148c7cc44cb65ef1aa36118 100644 (file)
@@ -404,8 +404,8 @@ GLOBAL(system_call_after_swapgs)
         * and short:
         */
        ENABLE_INTERRUPTS(CLBR_NONE)
-       SAVE_ARGS 8,0
-       movq  %rax,ORIG_RAX-ARGOFFSET(%rsp)
+       SAVE_ARGS 8, 0, rax_enosys=1
+       movq_cfi rax,(ORIG_RAX-ARGOFFSET)
        movq  %rcx,RIP-ARGOFFSET(%rsp)
        CFI_REL_OFFSET rip,RIP-ARGOFFSET
        testl $_TIF_WORK_SYSCALL_ENTRY,TI_flags+THREAD_INFO(%rsp,RIP-ARGOFFSET)
@@ -417,7 +417,7 @@ system_call_fastpath:
        andl $__SYSCALL_MASK,%eax
        cmpl $__NR_syscall_max,%eax
 #endif
-       ja badsys
+       ja ret_from_sys_call  /* and return regs->ax */
        movq %r10,%rcx
        call *sys_call_table(,%rax,8)  # XXX:    rip relative
        movq %rax,RAX-ARGOFFSET(%rsp)
@@ -476,27 +476,7 @@ sysret_signal:
        FIXUP_TOP_OF_STACK %r11, -ARGOFFSET
        jmp int_check_syscall_exit_work
 
-badsys:
-       movq $-ENOSYS,RAX-ARGOFFSET(%rsp)
-       jmp ret_from_sys_call
-
 #ifdef CONFIG_AUDITSYSCALL
-       /*
-        * Fast path for syscall audit without full syscall trace.
-        * We just call __audit_syscall_entry() directly, and then
-        * jump back to the normal fast path.
-        */
-auditsys:
-       movq %r10,%r9                   /* 6th arg: 4th syscall arg */
-       movq %rdx,%r8                   /* 5th arg: 3rd syscall arg */
-       movq %rsi,%rcx                  /* 4th arg: 2nd syscall arg */
-       movq %rdi,%rdx                  /* 3rd arg: 1st syscall arg */
-       movq %rax,%rsi                  /* 2nd arg: syscall number */
-       movl $AUDIT_ARCH_X86_64,%edi    /* 1st arg: audit arch */
-       call __audit_syscall_entry
-       LOAD_ARGS 0             /* reload call-clobbered registers */
-       jmp system_call_fastpath
-
        /*
         * Return fast path for syscall audit.  Call __audit_syscall_exit()
         * directly and then jump back to the fast path with TIF_SYSCALL_AUDIT
@@ -514,18 +494,25 @@ sysret_audit:
 
        /* Do syscall tracing */
 tracesys:
-#ifdef CONFIG_AUDITSYSCALL
-       testl $(_TIF_WORK_SYSCALL_ENTRY & ~_TIF_SYSCALL_AUDIT),TI_flags+THREAD_INFO(%rsp,RIP-ARGOFFSET)
-       jz auditsys
-#endif
+       leaq -REST_SKIP(%rsp), %rdi
+       movq $AUDIT_ARCH_X86_64, %rsi
+       call syscall_trace_enter_phase1
+       test %rax, %rax
+       jnz tracesys_phase2             /* if needed, run the slow path */
+       LOAD_ARGS 0                     /* else restore clobbered regs */
+       jmp system_call_fastpath        /*      and return to the fast path */
+
+tracesys_phase2:
        SAVE_REST
-       movq $-ENOSYS,RAX(%rsp) /* ptrace can change this for a bad syscall */
        FIXUP_TOP_OF_STACK %rdi
-       movq %rsp,%rdi
-       call syscall_trace_enter
+       movq %rsp, %rdi
+       movq $AUDIT_ARCH_X86_64, %rsi
+       movq %rax,%rdx
+       call syscall_trace_enter_phase2
+
        /*
         * Reload arg registers from stack in case ptrace changed them.
-        * We don't reload %rax because syscall_trace_enter() returned
+        * We don't reload %rax because syscall_trace_entry_phase2() returned
         * the value it wants us to use in the table lookup.
         */
        LOAD_ARGS ARGOFFSET, 1
@@ -536,7 +523,7 @@ tracesys:
        andl $__SYSCALL_MASK,%eax
        cmpl $__NR_syscall_max,%eax
 #endif
-       ja   int_ret_from_sys_call      /* RAX(%rsp) set to -ENOSYS above */
+       ja   int_ret_from_sys_call      /* RAX(%rsp) is already set */
        movq %r10,%rcx  /* fixup for C */
        call *sys_call_table(,%rax,8)
        movq %rax,RAX-ARGOFFSET(%rsp)
index 9030e83db6eebf20235928995298ecb97e9befa2..82f8d02f0df215f658b947b28b027e01a6e46b91 100644 (file)
 #include <linux/init.h>
 #include <linux/spinlock.h>
 #include <linux/pci.h>
+#include <linux/debugfs.h>
+#include <linux/capability.h>
 
 #include <asm/iosf_mbi.h>
 
 #define PCI_DEVICE_ID_BAYTRAIL         0x0F00
+#define PCI_DEVICE_ID_BRASWELL         0x2280
 #define PCI_DEVICE_ID_QUARK_X1000      0x0958
 
 static DEFINE_SPINLOCK(iosf_mbi_lock);
@@ -187,6 +190,89 @@ bool iosf_mbi_available(void)
 }
 EXPORT_SYMBOL(iosf_mbi_available);
 
+#ifdef CONFIG_IOSF_MBI_DEBUG
+static u32     dbg_mdr;
+static u32     dbg_mcr;
+static u32     dbg_mcrx;
+
+static int mcr_get(void *data, u64 *val)
+{
+       *val = *(u32 *)data;
+       return 0;
+}
+
+static int mcr_set(void *data, u64 val)
+{
+       u8 command = ((u32)val & 0xFF000000) >> 24,
+          port    = ((u32)val & 0x00FF0000) >> 16,
+          offset  = ((u32)val & 0x0000FF00) >> 8;
+       int err;
+
+       *(u32 *)data = val;
+
+       if (!capable(CAP_SYS_RAWIO))
+               return -EACCES;
+
+       if (command & 1u)
+               err = iosf_mbi_write(port,
+                              command,
+                              dbg_mcrx | offset,
+                              dbg_mdr);
+       else
+               err = iosf_mbi_read(port,
+                             command,
+                             dbg_mcrx | offset,
+                             &dbg_mdr);
+
+       return err;
+}
+DEFINE_SIMPLE_ATTRIBUTE(iosf_mcr_fops, mcr_get, mcr_set , "%llx\n");
+
+static struct dentry *iosf_dbg;
+
+static void iosf_sideband_debug_init(void)
+{
+       struct dentry *d;
+
+       iosf_dbg = debugfs_create_dir("iosf_sb", NULL);
+       if (IS_ERR_OR_NULL(iosf_dbg))
+               return;
+
+       /* mdr */
+       d = debugfs_create_x32("mdr", 0660, iosf_dbg, &dbg_mdr);
+       if (IS_ERR_OR_NULL(d))
+               goto cleanup;
+
+       /* mcrx */
+       debugfs_create_x32("mcrx", 0660, iosf_dbg, &dbg_mcrx);
+       if (IS_ERR_OR_NULL(d))
+               goto cleanup;
+
+       /* mcr - initiates mailbox tranaction */
+       debugfs_create_file("mcr", 0660, iosf_dbg, &dbg_mcr, &iosf_mcr_fops);
+       if (IS_ERR_OR_NULL(d))
+               goto cleanup;
+
+       return;
+
+cleanup:
+       debugfs_remove_recursive(d);
+}
+
+static void iosf_debugfs_init(void)
+{
+       iosf_sideband_debug_init();
+}
+
+static void iosf_debugfs_remove(void)
+{
+       debugfs_remove_recursive(iosf_dbg);
+}
+#else
+static inline void iosf_debugfs_init(void) { }
+static inline void iosf_debugfs_remove(void) { }
+#endif /* CONFIG_IOSF_MBI_DEBUG */
+
 static int iosf_mbi_probe(struct pci_dev *pdev,
                          const struct pci_device_id *unused)
 {
@@ -204,6 +290,7 @@ static int iosf_mbi_probe(struct pci_dev *pdev,
 
 static const struct pci_device_id iosf_mbi_pci_ids[] = {
        { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_BAYTRAIL) },
+       { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_BRASWELL) },
        { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_QUARK_X1000) },
        { 0, },
 };
@@ -217,11 +304,15 @@ static struct pci_driver iosf_mbi_pci_driver = {
 
 static int __init iosf_mbi_init(void)
 {
+       iosf_debugfs_init();
+
        return pci_register_driver(&iosf_mbi_pci_driver);
 }
 
 static void __exit iosf_mbi_exit(void)
 {
+       iosf_debugfs_remove();
+
        pci_unregister_driver(&iosf_mbi_pci_driver);
        if (mbi_pdev) {
                pci_dev_put(mbi_pdev);
index 9642b9b33655a739880fd5105473c81ff1696c9e..ca05f86481aace3a37cd6bf3fbe0e7d7ce3bb33a 100644 (file)
@@ -26,6 +26,7 @@
 #include <asm/setup.h>
 #include <asm/crash.h>
 #include <asm/efi.h>
+#include <asm/kexec-bzimage64.h>
 
 #define MAX_ELFCOREHDR_STR_LEN 30      /* elfcorehdr=0x<64bit-value> */
 
@@ -267,7 +268,7 @@ setup_boot_parameters(struct kimage *image, struct boot_params *params,
        return ret;
 }
 
-int bzImage64_probe(const char *buf, unsigned long len)
+static int bzImage64_probe(const char *buf, unsigned long len)
 {
        int ret = -ENOEXEC;
        struct setup_header *header;
@@ -325,10 +326,10 @@ int bzImage64_probe(const char *buf, unsigned long len)
        return ret;
 }
 
-void *bzImage64_load(struct kimage *image, char *kernel,
-                    unsigned long kernel_len, char *initrd,
-                    unsigned long initrd_len, char *cmdline,
-                    unsigned long cmdline_len)
+static void *bzImage64_load(struct kimage *image, char *kernel,
+                           unsigned long kernel_len, char *initrd,
+                           unsigned long initrd_len, char *cmdline,
+                           unsigned long cmdline_len)
 {
 
        struct setup_header *header;
@@ -514,7 +515,7 @@ out_free_params:
 }
 
 /* This cleanup function is called after various segments have been loaded */
-int bzImage64_cleanup(void *loader_data)
+static int bzImage64_cleanup(void *loader_data)
 {
        struct bzimage64_data *ldata = loader_data;
 
@@ -528,7 +529,7 @@ int bzImage64_cleanup(void *loader_data)
 }
 
 #ifdef CONFIG_KEXEC_BZIMAGE_VERIFY_SIG
-int bzImage64_verify_sig(const char *kernel, unsigned long kernel_len)
+static int bzImage64_verify_sig(const char *kernel, unsigned long kernel_len)
 {
        bool trusted;
        int ret;
index 3dd8e2c4d74a9ed4a124baf36a83de78be1be02d..95c3cb16af3e59e74d8a890bc59c2e35cb0fc014 100644 (file)
@@ -35,6 +35,7 @@
 #include <linux/slab.h>
 #include <linux/kprobes.h>
 #include <linux/debugfs.h>
+#include <linux/nmi.h>
 #include <asm/timer.h>
 #include <asm/cpu.h>
 #include <asm/traps.h>
@@ -499,6 +500,13 @@ void __init kvm_guest_init(void)
 #else
        kvm_guest_cpu_init();
 #endif
+
+       /*
+        * Hard lockup detection is enabled by default. Disable it, as guests
+        * can get false positives too easily, for example if the host is
+        * overcommitted.
+        */
+       watchdog_enable_hardlockup_detector(false);
 }
 
 static noinline uint32_t __kvm_cpuid_base(void)
index 1667b1de8d5d62c1b10f4b702c7e9699902f8406..72e8e310258d610c8a05f89920ddf101deb92a05 100644 (file)
@@ -247,7 +247,8 @@ void machine_kexec(struct kimage *image)
        /* now call it */
        image->start = relocate_kernel_ptr((unsigned long)image->head,
                                           (unsigned long)page_list,
-                                          image->start, cpu_has_pae,
+                                          image->start,
+                                          boot_cpu_has(X86_FEATURE_PAE),
                                           image->preserve_context);
 
 #ifdef CONFIG_KEXEC_JUMP
index 0c424a67985dac7e02b6e7aff7ec3b4cdc1cb49c..0ee5025e0fa4cf5f177bd7f9e05efc66924bddc5 100644 (file)
@@ -235,6 +235,11 @@ err:
        pmc_dbgfs_unregister(pmc);
        return -ENODEV;
 }
+#else
+static int pmc_dbgfs_register(struct pmc_dev *pmc, struct pci_dev *pdev)
+{
+       return 0;
+}
 #endif /* CONFIG_DEBUG_FS */
 
 static int pmc_setup_dev(struct pci_dev *pdev)
@@ -262,14 +267,12 @@ static int pmc_setup_dev(struct pci_dev *pdev)
        /* PMC hardware registers setup */
        pmc_hw_reg_setup(pmc);
 
-#ifdef CONFIG_DEBUG_FS
        ret = pmc_dbgfs_register(pmc, pdev);
        if (ret) {
                iounmap(pmc->regmap);
-               return ret;
        }
-#endif /* CONFIG_DEBUG_FS */
-       return 0;
+
+       return ret;
 }
 
 /*
diff --git a/arch/x86/kernel/preempt.S b/arch/x86/kernel/preempt.S
deleted file mode 100644 (file)
index ca7f0d5..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-
-#include <linux/linkage.h>
-#include <asm/dwarf2.h>
-#include <asm/asm.h>
-#include <asm/calling.h>
-
-ENTRY(___preempt_schedule)
-       CFI_STARTPROC
-       SAVE_ALL
-       call preempt_schedule
-       RESTORE_ALL
-       ret
-       CFI_ENDPROC
-
-#ifdef CONFIG_CONTEXT_TRACKING
-
-ENTRY(___preempt_schedule_context)
-       CFI_STARTPROC
-       SAVE_ALL
-       call preempt_schedule_context
-       RESTORE_ALL
-       ret
-       CFI_ENDPROC
-
-#endif
index f804dc935d2adffb37f587d34de9c4cd10ce70a3..e127ddaa2d5ad3e139ff7a99fb5485b43fb19416 100644 (file)
@@ -64,14 +64,16 @@ EXPORT_SYMBOL_GPL(task_xstate_cachep);
  */
 int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src)
 {
-       int ret;
-
        *dst = *src;
-       if (fpu_allocated(&src->thread.fpu)) {
-               memset(&dst->thread.fpu, 0, sizeof(dst->thread.fpu));
-               ret = fpu_alloc(&dst->thread.fpu);
-               if (ret)
-                       return ret;
+
+       dst->thread.fpu_counter = 0;
+       dst->thread.fpu.has_fpu = 0;
+       dst->thread.fpu.last_cpu = ~0;
+       dst->thread.fpu.state = NULL;
+       if (tsk_used_math(src)) {
+               int err = fpu_alloc(&dst->thread.fpu);
+               if (err)
+                       return err;
                fpu_copy(dst, src);
        }
        return 0;
index 7bc86bbe748599b92c2b9b2b221f98b10224c5b2..8f3ebfe710d0715d9b876fa6f0d551933f30a225 100644 (file)
@@ -138,6 +138,7 @@ int copy_thread(unsigned long clone_flags, unsigned long sp,
 
        p->thread.sp = (unsigned long) childregs;
        p->thread.sp0 = (unsigned long) (childregs+1);
+       memset(p->thread.ptrace_bps, 0, sizeof(p->thread.ptrace_bps));
 
        if (unlikely(p->flags & PF_KTHREAD)) {
                /* kernel thread */
@@ -152,9 +153,7 @@ int copy_thread(unsigned long clone_flags, unsigned long sp,
                childregs->orig_ax = -1;
                childregs->cs = __KERNEL_CS | get_kernel_rpl();
                childregs->flags = X86_EFLAGS_IF | X86_EFLAGS_FIXED;
-               p->thread.fpu_counter = 0;
                p->thread.io_bitmap_ptr = NULL;
-               memset(p->thread.ptrace_bps, 0, sizeof(p->thread.ptrace_bps));
                return 0;
        }
        *childregs = *current_pt_regs();
@@ -165,13 +164,10 @@ int copy_thread(unsigned long clone_flags, unsigned long sp,
        p->thread.ip = (unsigned long) ret_from_fork;
        task_user_gs(p) = get_user_gs(current_pt_regs());
 
-       p->thread.fpu_counter = 0;
        p->thread.io_bitmap_ptr = NULL;
        tsk = current;
        err = -ENOMEM;
 
-       memset(p->thread.ptrace_bps, 0, sizeof(p->thread.ptrace_bps));
-
        if (unlikely(test_tsk_thread_flag(tsk, TIF_IO_BITMAP))) {
                p->thread.io_bitmap_ptr = kmemdup(tsk->thread.io_bitmap_ptr,
                                                IO_BITMAP_BYTES, GFP_KERNEL);
index ca5b02d405c3ba0c17e8c7e060222559a6a1d9b3..3ed4a68d4013fc6e6b5ea3350519ab92f8eeb33d 100644 (file)
@@ -163,7 +163,6 @@ int copy_thread(unsigned long clone_flags, unsigned long sp,
        p->thread.sp = (unsigned long) childregs;
        p->thread.usersp = me->thread.usersp;
        set_tsk_thread_flag(p, TIF_FORK);
-       p->thread.fpu_counter = 0;
        p->thread.io_bitmap_ptr = NULL;
 
        savesegment(gs, p->thread.gsindex);
@@ -193,8 +192,6 @@ int copy_thread(unsigned long clone_flags, unsigned long sp,
                childregs->sp = sp;
 
        err = -ENOMEM;
-       memset(p->thread.ptrace_bps, 0, sizeof(p->thread.ptrace_bps));
-
        if (unlikely(test_tsk_thread_flag(me, TIF_IO_BITMAP))) {
                p->thread.io_bitmap_ptr = kmemdup(me->thread.io_bitmap_ptr,
                                                  IO_BITMAP_BYTES, GFP_KERNEL);
index 678c0ada3b3ce5f94135c7076cf59800850ca474..29576c244699f0632e8d747ab8b8b8461bd4670c 100644 (file)
@@ -1441,24 +1441,126 @@ void send_sigtrap(struct task_struct *tsk, struct pt_regs *regs,
        force_sig_info(SIGTRAP, &info, tsk);
 }
 
-
-#ifdef CONFIG_X86_32
-# define IS_IA32       1
-#elif defined CONFIG_IA32_EMULATION
-# define IS_IA32       is_compat_task()
-#else
-# define IS_IA32       0
+static void do_audit_syscall_entry(struct pt_regs *regs, u32 arch)
+{
+#ifdef CONFIG_X86_64
+       if (arch == AUDIT_ARCH_X86_64) {
+               audit_syscall_entry(arch, regs->orig_ax, regs->di,
+                                   regs->si, regs->dx, regs->r10);
+       } else
 #endif
+       {
+               audit_syscall_entry(arch, regs->orig_ax, regs->bx,
+                                   regs->cx, regs->dx, regs->si);
+       }
+}
 
 /*
- * We must return the syscall number to actually look up in the table.
- * This can be -1L to skip running any syscall at all.
+ * We can return 0 to resume the syscall or anything else to go to phase
+ * 2.  If we resume the syscall, we need to put something appropriate in
+ * regs->orig_ax.
+ *
+ * NB: We don't have full pt_regs here, but regs->orig_ax and regs->ax
+ * are fully functional.
+ *
+ * For phase 2's benefit, our return value is:
+ * 0:                  resume the syscall
+ * 1:                  go to phase 2; no seccomp phase 2 needed
+ * anything else:      go to phase 2; pass return value to seccomp
  */
-long syscall_trace_enter(struct pt_regs *regs)
+unsigned long syscall_trace_enter_phase1(struct pt_regs *regs, u32 arch)
+{
+       unsigned long ret = 0;
+       u32 work;
+
+       BUG_ON(regs != task_pt_regs(current));
+
+       work = ACCESS_ONCE(current_thread_info()->flags) &
+               _TIF_WORK_SYSCALL_ENTRY;
+
+       /*
+        * If TIF_NOHZ is set, we are required to call user_exit() before
+        * doing anything that could touch RCU.
+        */
+       if (work & _TIF_NOHZ) {
+               user_exit();
+               work &= ~TIF_NOHZ;
+       }
+
+#ifdef CONFIG_SECCOMP
+       /*
+        * Do seccomp first -- it should minimize exposure of other
+        * code, and keeping seccomp fast is probably more valuable
+        * than the rest of this.
+        */
+       if (work & _TIF_SECCOMP) {
+               struct seccomp_data sd;
+
+               sd.arch = arch;
+               sd.nr = regs->orig_ax;
+               sd.instruction_pointer = regs->ip;
+#ifdef CONFIG_X86_64
+               if (arch == AUDIT_ARCH_X86_64) {
+                       sd.args[0] = regs->di;
+                       sd.args[1] = regs->si;
+                       sd.args[2] = regs->dx;
+                       sd.args[3] = regs->r10;
+                       sd.args[4] = regs->r8;
+                       sd.args[5] = regs->r9;
+               } else
+#endif
+               {
+                       sd.args[0] = regs->bx;
+                       sd.args[1] = regs->cx;
+                       sd.args[2] = regs->dx;
+                       sd.args[3] = regs->si;
+                       sd.args[4] = regs->di;
+                       sd.args[5] = regs->bp;
+               }
+
+               BUILD_BUG_ON(SECCOMP_PHASE1_OK != 0);
+               BUILD_BUG_ON(SECCOMP_PHASE1_SKIP != 1);
+
+               ret = seccomp_phase1(&sd);
+               if (ret == SECCOMP_PHASE1_SKIP) {
+                       regs->orig_ax = -1;
+                       ret = 0;
+               } else if (ret != SECCOMP_PHASE1_OK) {
+                       return ret;  /* Go directly to phase 2 */
+               }
+
+               work &= ~_TIF_SECCOMP;
+       }
+#endif
+
+       /* Do our best to finish without phase 2. */
+       if (work == 0)
+               return ret;  /* seccomp and/or nohz only (ret == 0 here) */
+
+#ifdef CONFIG_AUDITSYSCALL
+       if (work == _TIF_SYSCALL_AUDIT) {
+               /*
+                * If there is no more work to be done except auditing,
+                * then audit in phase 1.  Phase 2 always audits, so, if
+                * we audit here, then we can't go on to phase 2.
+                */
+               do_audit_syscall_entry(regs, arch);
+               return 0;
+       }
+#endif
+
+       return 1;  /* Something is enabled that we can't handle in phase 1 */
+}
+
+/* Returns the syscall nr to run (which should match regs->orig_ax). */
+long syscall_trace_enter_phase2(struct pt_regs *regs, u32 arch,
+                               unsigned long phase1_result)
 {
        long ret = 0;
+       u32 work = ACCESS_ONCE(current_thread_info()->flags) &
+               _TIF_WORK_SYSCALL_ENTRY;
 
-       user_exit();
+       BUG_ON(regs != task_pt_regs(current));
 
        /*
         * If we stepped into a sysenter/syscall insn, it trapped in
@@ -1467,17 +1569,21 @@ long syscall_trace_enter(struct pt_regs *regs)
         * do_debug() and we need to set it again to restore the user
         * state.  If we entered on the slow path, TF was already set.
         */
-       if (test_thread_flag(TIF_SINGLESTEP))
+       if (work & _TIF_SINGLESTEP)
                regs->flags |= X86_EFLAGS_TF;
 
-       /* do the secure computing check first */
-       if (secure_computing(regs->orig_ax)) {
+#ifdef CONFIG_SECCOMP
+       /*
+        * Call seccomp_phase2 before running the other hooks so that
+        * they can see any changes made by a seccomp tracer.
+        */
+       if (phase1_result > 1 && seccomp_phase2(phase1_result)) {
                /* seccomp failures shouldn't expose any additional code. */
-               ret = -1L;
-               goto out;
+               return -1;
        }
+#endif
 
-       if (unlikely(test_thread_flag(TIF_SYSCALL_EMU)))
+       if (unlikely(work & _TIF_SYSCALL_EMU))
                ret = -1L;
 
        if ((ret || test_thread_flag(TIF_SYSCALL_TRACE)) &&
@@ -1487,23 +1593,22 @@ long syscall_trace_enter(struct pt_regs *regs)
        if (unlikely(test_thread_flag(TIF_SYSCALL_TRACEPOINT)))
                trace_sys_enter(regs, regs->orig_ax);
 
-       if (IS_IA32)
-               audit_syscall_entry(AUDIT_ARCH_I386,
-                                   regs->orig_ax,
-                                   regs->bx, regs->cx,
-                                   regs->dx, regs->si);
-#ifdef CONFIG_X86_64
-       else
-               audit_syscall_entry(AUDIT_ARCH_X86_64,
-                                   regs->orig_ax,
-                                   regs->di, regs->si,
-                                   regs->dx, regs->r10);
-#endif
+       do_audit_syscall_entry(regs, arch);
 
-out:
        return ret ?: regs->orig_ax;
 }
 
+long syscall_trace_enter(struct pt_regs *regs)
+{
+       u32 arch = is_ia32_task() ? AUDIT_ARCH_I386 : AUDIT_ARCH_X86_64;
+       unsigned long phase1_result = syscall_trace_enter_phase1(regs, arch);
+
+       if (phase1_result == 0)
+               return regs->orig_ax;
+       else
+               return syscall_trace_enter_phase2(regs, arch, phase1_result);
+}
+
 void syscall_trace_leave(struct pt_regs *regs)
 {
        bool step;
index ff898bbf579d7f34ce7b8c98a5482f72e4d338bf..176a0f99d4daa6f2f94d2e505b1452d3a87d02db 100644 (file)
@@ -497,6 +497,24 @@ void force_hpet_resume(void)
        }
 }
 
+/*
+ * According to the datasheet e6xx systems have the HPET hardwired to
+ * 0xfed00000
+ */
+static void e6xx_force_enable_hpet(struct pci_dev *dev)
+{
+       if (hpet_address || force_hpet_address)
+               return;
+
+       force_hpet_address = 0xFED00000;
+       force_hpet_resume_type = NONE_FORCE_HPET_RESUME;
+       dev_printk(KERN_DEBUG, &dev->dev, "Force enabled HPET at "
+               "0x%lx\n", force_hpet_address);
+       return;
+}
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_E6XX_CU,
+                        e6xx_force_enable_hpet);
+
 /*
  * HPET MSI on some boards (ATI SB700/SB800) has side effect on
  * floppy DMA. Disable HPET MSI on such platforms.
index 41ead8d3bc0bb10110c4df9c595afbcee806df70..235cfd39e0d793c23299da10a9eb45f7b29006a4 100644 (file)
@@ -879,6 +879,15 @@ void __init setup_arch(char **cmdline_p)
                        KERNEL_PGD_PTRS);
 
        load_cr3(swapper_pg_dir);
+       /*
+        * Note: Quark X1000 CPUs advertise PGE incorrectly and require
+        * a cr3 based tlb flush, so the following __flush_tlb_all()
+        * will not flush anything because the cpu quirk which clears
+        * X86_FEATURE_PGE has not been invoked yet. Though due to the
+        * load_cr3() above the TLB has been flushed already. The
+        * quirk is invoked before subsequent calls to __flush_tlb_all()
+        * so proper operation is guaranteed.
+        */
        __flush_tlb_all();
 #else
        printk(KERN_INFO "Command line: %s\n", boot_command_line);
index 2851d63c1202fd414a0ddb0f5cd26944861acaf2..ed37a768d0fc03dae75cda0b3402dd73202b3c96 100644 (file)
@@ -675,6 +675,11 @@ handle_signal(struct ksignal *ksig, struct pt_regs *regs)
                 * handler too.
                 */
                regs->flags &= ~(X86_EFLAGS_DF|X86_EFLAGS_RF|X86_EFLAGS_TF);
+               /*
+                * Ensure the signal handler starts with the new fpu state.
+                */
+               if (used_math())
+                       drop_init_fpu(current);
        }
        signal_setup_done(failed, ksig, test_thread_flag(TIF_SINGLESTEP));
 }
index 42a2dca984b3d1816522684d97c8ac50d86193af..2d5200e56357d49f3466ce55e8ab2b3273306f68 100644 (file)
@@ -102,6 +102,8 @@ DEFINE_PER_CPU_READ_MOSTLY(cpumask_var_t, cpu_llc_shared_map);
 DEFINE_PER_CPU_SHARED_ALIGNED(struct cpuinfo_x86, cpu_info);
 EXPORT_PER_CPU_SYMBOL(cpu_info);
 
+static DEFINE_PER_CPU(struct completion, die_complete);
+
 atomic_t init_deasserted;
 
 /*
@@ -111,7 +113,6 @@ atomic_t init_deasserted;
 static void smp_callin(void)
 {
        int cpuid, phys_id;
-       unsigned long timeout;
 
        /*
         * If waken up by an INIT in an 82489DX configuration
@@ -130,37 +131,6 @@ static void smp_callin(void)
         * (This works even if the APIC is not enabled.)
         */
        phys_id = read_apic_id();
-       if (cpumask_test_cpu(cpuid, cpu_callin_mask)) {
-               panic("%s: phys CPU#%d, CPU#%d already present??\n", __func__,
-                                       phys_id, cpuid);
-       }
-       pr_debug("CPU#%d (phys ID: %d) waiting for CALLOUT\n", cpuid, phys_id);
-
-       /*
-        * STARTUP IPIs are fragile beasts as they might sometimes
-        * trigger some glue motherboard logic. Complete APIC bus
-        * silence for 1 second, this overestimates the time the
-        * boot CPU is spending to send the up to 2 STARTUP IPIs
-        * by a factor of two. This should be enough.
-        */
-
-       /*
-        * Waiting 2s total for startup (udelay is not yet working)
-        */
-       timeout = jiffies + 2*HZ;
-       while (time_before(jiffies, timeout)) {
-               /*
-                * Has the boot CPU finished it's STARTUP sequence?
-                */
-               if (cpumask_test_cpu(cpuid, cpu_callout_mask))
-                       break;
-               cpu_relax();
-       }
-
-       if (!time_before(jiffies, timeout)) {
-               panic("%s: CPU%d started up but did not get a callout!\n",
-                     __func__, cpuid);
-       }
 
        /*
         * the boot CPU has finished the init stage and is spinning
@@ -295,12 +265,20 @@ void smp_store_cpu_info(int id)
        identify_secondary_cpu(c);
 }
 
+static bool
+topology_same_node(struct cpuinfo_x86 *c, struct cpuinfo_x86 *o)
+{
+       int cpu1 = c->cpu_index, cpu2 = o->cpu_index;
+
+       return (cpu_to_node(cpu1) == cpu_to_node(cpu2));
+}
+
 static bool
 topology_sane(struct cpuinfo_x86 *c, struct cpuinfo_x86 *o, const char *name)
 {
        int cpu1 = c->cpu_index, cpu2 = o->cpu_index;
 
-       return !WARN_ONCE(cpu_to_node(cpu1) != cpu_to_node(cpu2),
+       return !WARN_ONCE(!topology_same_node(c, o),
                "sched: CPU #%d's %s-sibling CPU #%d is not on the same node! "
                "[node: %d != %d]. Ignoring dependency.\n",
                cpu1, name, cpu2, cpu_to_node(cpu1), cpu_to_node(cpu2));
@@ -341,17 +319,44 @@ static bool match_llc(struct cpuinfo_x86 *c, struct cpuinfo_x86 *o)
        return false;
 }
 
-static bool match_mc(struct cpuinfo_x86 *c, struct cpuinfo_x86 *o)
+/*
+ * Unlike the other levels, we do not enforce keeping a
+ * multicore group inside a NUMA node.  If this happens, we will
+ * discard the MC level of the topology later.
+ */
+static bool match_die(struct cpuinfo_x86 *c, struct cpuinfo_x86 *o)
 {
-       if (c->phys_proc_id == o->phys_proc_id) {
-               if (cpu_has(c, X86_FEATURE_AMD_DCM))
-                       return true;
-
-               return topology_sane(c, o, "mc");
-       }
+       if (c->phys_proc_id == o->phys_proc_id)
+               return true;
        return false;
 }
 
+static struct sched_domain_topology_level numa_inside_package_topology[] = {
+#ifdef CONFIG_SCHED_SMT
+       { cpu_smt_mask, cpu_smt_flags, SD_INIT_NAME(SMT) },
+#endif
+#ifdef CONFIG_SCHED_MC
+       { cpu_coregroup_mask, cpu_core_flags, SD_INIT_NAME(MC) },
+#endif
+       { NULL, },
+};
+/*
+ * set_sched_topology() sets the topology internal to a CPU.  The
+ * NUMA topologies are layered on top of it to build the full
+ * system topology.
+ *
+ * If NUMA nodes are observed to occur within a CPU package, this
+ * function should be called.  It forces the sched domain code to
+ * only use the SMT level for the CPU portion of the topology.
+ * This essentially falls back to relying on NUMA information
+ * from the SRAT table to describe the entire system topology
+ * (except for hyperthreads).
+ */
+static void primarily_use_numa_for_topology(void)
+{
+       set_sched_topology(numa_inside_package_topology);
+}
+
 void set_cpu_sibling_map(int cpu)
 {
        bool has_smt = smp_num_siblings > 1;
@@ -388,7 +393,7 @@ void set_cpu_sibling_map(int cpu)
        for_each_cpu(i, cpu_sibling_setup_mask) {
                o = &cpu_data(i);
 
-               if ((i == cpu) || (has_mp && match_mc(c, o))) {
+               if ((i == cpu) || (has_mp && match_die(c, o))) {
                        link_mask(core, cpu, i);
 
                        /*
@@ -410,6 +415,8 @@ void set_cpu_sibling_map(int cpu)
                        } else if (i != cpu && !c->booted_cores)
                                c->booted_cores = cpu_data(i).booted_cores;
                }
+               if (match_die(c, o) && !topology_same_node(c, o))
+                       primarily_use_numa_for_topology();
        }
 }
 
@@ -753,8 +760,8 @@ static int do_boot_cpu(int apicid, int cpu, struct task_struct *idle)
        unsigned long start_ip = real_mode_header->trampoline_start;
 
        unsigned long boot_error = 0;
-       int timeout;
        int cpu0_nmi_registered = 0;
+       unsigned long timeout;
 
        /* Just in case we booted with a single CPU. */
        alternatives_enable_smp();
@@ -801,6 +808,15 @@ static int do_boot_cpu(int apicid, int cpu, struct task_struct *idle)
                }
        }
 
+       /*
+        * AP might wait on cpu_callout_mask in cpu_init() with
+        * cpu_initialized_mask set if previous attempt to online
+        * it timed-out. Clear cpu_initialized_mask so that after
+        * INIT/SIPI it could start with a clean state.
+        */
+       cpumask_clear_cpu(cpu, cpu_initialized_mask);
+       smp_mb();
+
        /*
         * Wake up a CPU in difference cases:
         * - Use the method in the APIC driver if it's defined
@@ -815,53 +831,38 @@ static int do_boot_cpu(int apicid, int cpu, struct task_struct *idle)
 
        if (!boot_error) {
                /*
-                * allow APs to start initializing.
+                * Wait 10s total for a response from AP
                 */
-               pr_debug("Before Callout %d\n", cpu);
-               cpumask_set_cpu(cpu, cpu_callout_mask);
-               pr_debug("After Callout %d\n", cpu);
+               boot_error = -1;
+               timeout = jiffies + 10*HZ;
+               while (time_before(jiffies, timeout)) {
+                       if (cpumask_test_cpu(cpu, cpu_initialized_mask)) {
+                               /*
+                                * Tell AP to proceed with initialization
+                                */
+                               cpumask_set_cpu(cpu, cpu_callout_mask);
+                               boot_error = 0;
+                               break;
+                       }
+                       udelay(100);
+                       schedule();
+               }
+       }
 
+       if (!boot_error) {
                /*
-                * Wait 5s total for a response
+                * Wait till AP completes initial initialization
                 */
-               for (timeout = 0; timeout < 50000; timeout++) {
-                       if (cpumask_test_cpu(cpu, cpu_callin_mask))
-                               break;  /* It has booted */
-                       udelay(100);
+               while (!cpumask_test_cpu(cpu, cpu_callin_mask)) {
                        /*
                         * Allow other tasks to run while we wait for the
                         * AP to come online. This also gives a chance
                         * for the MTRR work(triggered by the AP coming online)
                         * to be completed in the stop machine context.
                         */
+                       udelay(100);
                        schedule();
                }
-
-               if (cpumask_test_cpu(cpu, cpu_callin_mask)) {
-                       print_cpu_msr(&cpu_data(cpu));
-                       pr_debug("CPU%d: has booted.\n", cpu);
-               } else {
-                       boot_error = 1;
-                       if (*trampoline_status == 0xA5A5A5A5)
-                               /* trampoline started but...? */
-                               pr_err("CPU%d: Stuck ??\n", cpu);
-                       else
-                               /* trampoline code not run */
-                               pr_err("CPU%d: Not responding\n", cpu);
-                       if (apic->inquire_remote_apic)
-                               apic->inquire_remote_apic(apicid);
-               }
-       }
-
-       if (boot_error) {
-               /* Try to put things back the way they were before ... */
-               numa_remove_cpu(cpu); /* was set by numa_add_cpu */
-
-               /* was set by do_boot_cpu() */
-               cpumask_clear_cpu(cpu, cpu_callout_mask);
-
-               /* was set by cpu_init() */
-               cpumask_clear_cpu(cpu, cpu_initialized_mask);
        }
 
        /* mark "stuck" area as not stuck */
@@ -1326,26 +1327,24 @@ int native_cpu_disable(void)
                return ret;
 
        clear_local_APIC();
-
+       init_completion(&per_cpu(die_complete, smp_processor_id()));
        cpu_disable_common();
+
        return 0;
 }
 
 void native_cpu_die(unsigned int cpu)
 {
        /* We don't do anything here: idle task is faking death itself. */
-       unsigned int i;
+       wait_for_completion_timeout(&per_cpu(die_complete, cpu), HZ);
 
-       for (i = 0; i < 10; i++) {
-               /* They ack this in play_dead by setting CPU_DEAD */
-               if (per_cpu(cpu_state, cpu) == CPU_DEAD) {
-                       if (system_state == SYSTEM_RUNNING)
-                               pr_info("CPU %u is now offline\n", cpu);
-                       return;
-               }
-               msleep(100);
+       /* They ack this in play_dead() by setting CPU_DEAD */
+       if (per_cpu(cpu_state, cpu) == CPU_DEAD) {
+               if (system_state == SYSTEM_RUNNING)
+                       pr_info("CPU %u is now offline\n", cpu);
+       } else {
+               pr_err("CPU %u didn't die...\n", cpu);
        }
-       pr_err("CPU %u didn't die...\n", cpu);
 }
 
 void play_dead_common(void)
@@ -1357,6 +1356,7 @@ void play_dead_common(void)
        mb();
        /* Ack it */
        __this_cpu_write(cpu_state, CPU_DEAD);
+       complete(&per_cpu(die_complete, smp_processor_id()));
 
        /*
         * With physical CPU hotplug, we should halt the cpu
index e1e1e80fc6a6fb1285d0efce67d651faa4550b61..957779f4eb40fbb920039d42ab34378055515311 100644 (file)
@@ -216,7 +216,7 @@ bool emulate_vsyscall(struct pt_regs *regs, unsigned long address)
         */
        regs->orig_ax = syscall_nr;
        regs->ax = -ENOSYS;
-       tmp = secure_computing(syscall_nr);
+       tmp = secure_computing();
        if ((!tmp && regs->orig_ax != syscall_nr) || regs->ip != address) {
                warn_bad_vsyscall(KERN_DEBUG, regs,
                                  "seccomp tried to change syscall nr or ip");
index 940b142cc11f8390ebdc15d1121cd67cc24c94aa..4c540c4719d80d14a9797648d2d65cfc768c2e10 100644 (file)
@@ -271,8 +271,6 @@ int save_xstate_sig(void __user *buf, void __user *buf_fx, int size)
        if (use_fxsr() && save_xstate_epilog(buf_fx, ia32_fxstate))
                return -1;
 
-       drop_init_fpu(tsk);     /* trigger finit */
-
        return 0;
 }
 
@@ -402,8 +400,11 @@ int __restore_xstate_sig(void __user *buf, void __user *buf_fx, int size)
                        set_used_math();
                }
 
-               if (use_eager_fpu())
+               if (use_eager_fpu()) {
+                       preempt_disable();
                        math_state_restore();
+                       preempt_enable();
+               }
 
                return err;
        } else {
index 4d4f96a27638c2bbeedf6a4206518508180d971e..db92793b7e23edaf7a252fe3d72daf4f893d5c31 100644 (file)
@@ -20,7 +20,6 @@ lib-y := delay.o misc.o cmdline.o
 lib-y += thunk_$(BITS).o
 lib-y += usercopy_$(BITS).o usercopy.o getuser.o putuser.o
 lib-y += memcpy_$(BITS).o
-lib-$(CONFIG_SMP) += rwlock.o
 lib-$(CONFIG_RWSEM_XCHGADD_ALGORITHM) += rwsem.o
 lib-$(CONFIG_INSTRUCTION_DECODER) += insn.o inat.o
 
@@ -39,7 +38,7 @@ endif
 else
         obj-y += iomap_copy_64.o
         lib-y += csum-partial_64.o csum-copy_64.o csum-wrappers_64.o
-        lib-y += thunk_64.o clear_page_64.o copy_page_64.o
+        lib-y += clear_page_64.o copy_page_64.o
         lib-y += memmove_64.o memset_64.o
         lib-y += copy_user_64.o copy_user_nocache_64.o
        lib-y += cmpxchg16b_emu.o
index 1e572c507d06c2ff4d8cb00deee4ac624d7e6f69..40a172541ee2cb2c2342a0a9934948769e87337f 100644 (file)
@@ -6,15 +6,8 @@
  *
  */
 #include <linux/linkage.h>
-#include <asm/alternative-asm.h>
-#include <asm/frame.h>
 #include <asm/dwarf2.h>
-
-#ifdef CONFIG_SMP
-#define SEG_PREFIX %gs:
-#else
-#define SEG_PREFIX
-#endif
+#include <asm/percpu.h>
 
 .text
 
@@ -39,24 +32,25 @@ CFI_STARTPROC
 # *atomic* on a single cpu (as provided by the this_cpu_xx class of
 # macros).
 #
-this_cpu_cmpxchg16b_emu:
-       pushf
+       pushfq_cfi
        cli
 
-       cmpq SEG_PREFIX(%rsi), %rax
-       jne not_same
-       cmpq SEG_PREFIX 8(%rsi), %rdx
-       jne not_same
+       cmpq PER_CPU_VAR((%rsi)), %rax
+       jne .Lnot_same
+       cmpq PER_CPU_VAR(8(%rsi)), %rdx
+       jne .Lnot_same
 
-       movq %rbx, SEG_PREFIX(%rsi)
-       movq %rcx, SEG_PREFIX 8(%rsi)
+       movq %rbx, PER_CPU_VAR((%rsi))
+       movq %rcx, PER_CPU_VAR(8(%rsi))
 
-       popf
+       CFI_REMEMBER_STATE
+       popfq_cfi
        mov $1, %al
        ret
 
- not_same:
-       popf
+       CFI_RESTORE_STATE
+.Lnot_same:
+       popfq_cfi
        xor %al,%al
        ret
 
index 828cb710dec29c38a1c0d588108accabf7562c0a..b4807fce517760ac4a72dceae939ae322b0bda6b 100644 (file)
@@ -7,11 +7,8 @@
  */
 
 #include <linux/linkage.h>
-#include <asm/alternative-asm.h>
-#include <asm/frame.h>
 #include <asm/dwarf2.h>
 
-
 .text
 
 /*
@@ -30,27 +27,28 @@ CFI_STARTPROC
 # set the whole ZF thing (caller will just compare
 # eax:edx with the expected value)
 #
-cmpxchg8b_emu:
-       pushfl
+       pushfl_cfi
        cli
 
        cmpl  (%esi), %eax
-       jne not_same
+       jne .Lnot_same
        cmpl 4(%esi), %edx
-       jne half_same
+       jne .Lhalf_same
 
        movl %ebx,  (%esi)
        movl %ecx, 4(%esi)
 
-       popfl
+       CFI_REMEMBER_STATE
+       popfl_cfi
        ret
 
- not_same:
+       CFI_RESTORE_STATE
+.Lnot_same:
        movl  (%esi), %eax
- half_same:
+.Lhalf_same:
        movl 4(%esi), %edx
 
-       popfl
+       popfl_cfi
        ret
 
 CFI_ENDPROC
diff --git a/arch/x86/lib/rwlock.S b/arch/x86/lib/rwlock.S
deleted file mode 100644 (file)
index 1cad221..0000000
+++ /dev/null
@@ -1,44 +0,0 @@
-/* Slow paths of read/write spinlocks. */
-
-#include <linux/linkage.h>
-#include <asm/alternative-asm.h>
-#include <asm/frame.h>
-#include <asm/rwlock.h>
-
-#ifdef CONFIG_X86_32
-# define __lock_ptr eax
-#else
-# define __lock_ptr rdi
-#endif
-
-ENTRY(__write_lock_failed)
-       CFI_STARTPROC
-       FRAME
-0:     LOCK_PREFIX
-       WRITE_LOCK_ADD($RW_LOCK_BIAS) (%__lock_ptr)
-1:     rep; nop
-       cmpl    $WRITE_LOCK_CMP, (%__lock_ptr)
-       jne     1b
-       LOCK_PREFIX
-       WRITE_LOCK_SUB($RW_LOCK_BIAS) (%__lock_ptr)
-       jnz     0b
-       ENDFRAME
-       ret
-       CFI_ENDPROC
-END(__write_lock_failed)
-
-ENTRY(__read_lock_failed)
-       CFI_STARTPROC
-       FRAME
-0:     LOCK_PREFIX
-       READ_LOCK_SIZE(inc) (%__lock_ptr)
-1:     rep; nop
-       READ_LOCK_SIZE(cmp) $1, (%__lock_ptr)
-       js      1b
-       LOCK_PREFIX
-       READ_LOCK_SIZE(dec) (%__lock_ptr)
-       js      0b
-       ENDFRAME
-       ret
-       CFI_ENDPROC
-END(__read_lock_failed)
index 28f85c916712232e951f30a0e9819b56357a87a9..e28cdaf5ac2c629cd8bca126a55a45745e403534 100644 (file)
@@ -6,25 +6,46 @@
  */
        #include <linux/linkage.h>
        #include <asm/asm.h>
+       #include <asm/dwarf2.h>
 
-#ifdef CONFIG_TRACE_IRQFLAGS
        /* put return address in eax (arg1) */
-       .macro thunk_ra name,func
+       .macro THUNK name, func, put_ret_addr_in_eax=0
        .globl \name
 \name:
-       pushl %eax
-       pushl %ecx
-       pushl %edx
+       CFI_STARTPROC
+       pushl_cfi %eax
+       CFI_REL_OFFSET eax, 0
+       pushl_cfi %ecx
+       CFI_REL_OFFSET ecx, 0
+       pushl_cfi %edx
+       CFI_REL_OFFSET edx, 0
+
+       .if \put_ret_addr_in_eax
        /* Place EIP in the arg1 */
        movl 3*4(%esp), %eax
+       .endif
+
        call \func
-       popl %edx
-       popl %ecx
-       popl %eax
+       popl_cfi %edx
+       CFI_RESTORE edx
+       popl_cfi %ecx
+       CFI_RESTORE ecx
+       popl_cfi %eax
+       CFI_RESTORE eax
        ret
+       CFI_ENDPROC
        _ASM_NOKPROBE(\name)
        .endm
 
-       thunk_ra trace_hardirqs_on_thunk,trace_hardirqs_on_caller
-       thunk_ra trace_hardirqs_off_thunk,trace_hardirqs_off_caller
+#ifdef CONFIG_TRACE_IRQFLAGS
+       THUNK trace_hardirqs_on_thunk,trace_hardirqs_on_caller,1
+       THUNK trace_hardirqs_off_thunk,trace_hardirqs_off_caller,1
+#endif
+
+#ifdef CONFIG_PREEMPT
+       THUNK ___preempt_schedule, preempt_schedule
+#ifdef CONFIG_CONTEXT_TRACKING
+       THUNK ___preempt_schedule_context, preempt_schedule_context
 #endif
+#endif
+
index 92d9feaff42b04fa0dd42f1c1f686cf3a43e7636..b30b5ebd614ada18d25b3fb7403f7a32e32a96d9 100644 (file)
        THUNK lockdep_sys_exit_thunk,lockdep_sys_exit
 #endif
 
+#ifdef CONFIG_PREEMPT
+       THUNK ___preempt_schedule, preempt_schedule
+#ifdef CONFIG_CONTEXT_TRACKING
+       THUNK ___preempt_schedule_context, preempt_schedule_context
+#endif
+#endif
+
        /* SAVE_ARGS below is used only for the .cfi directives it contains. */
        CFI_STARTPROC
        SAVE_ARGS
index a241946815131904498ae6ecd95d87c4e28bf2f9..d973e61e450dc4f4733e838c67500aa711168302 100644 (file)
@@ -3,7 +3,6 @@
  *  Copyright (C) 2001, 2002 Andi Kleen, SuSE Labs.
  *  Copyright (C) 2008-2009, Red Hat Inc., Ingo Molnar
  */
-#include <linux/magic.h>               /* STACK_END_MAGIC              */
 #include <linux/sched.h>               /* test_thread_flag(), ...      */
 #include <linux/kdebug.h>              /* oops_begin/end, ...          */
 #include <linux/module.h>              /* search_exception_table       */
@@ -350,7 +349,7 @@ out:
 
 void vmalloc_sync_all(void)
 {
-       sync_global_pgds(VMALLOC_START & PGDIR_MASK, VMALLOC_END);
+       sync_global_pgds(VMALLOC_START & PGDIR_MASK, VMALLOC_END, 0);
 }
 
 /*
@@ -649,7 +648,6 @@ no_context(struct pt_regs *regs, unsigned long error_code,
           unsigned long address, int signal, int si_code)
 {
        struct task_struct *tsk = current;
-       unsigned long *stackend;
        unsigned long flags;
        int sig;
 
@@ -709,8 +707,7 @@ no_context(struct pt_regs *regs, unsigned long error_code,
 
        show_fault_oops(regs, error_code, address);
 
-       stackend = end_of_stack(tsk);
-       if (tsk != &init_task && *stackend != STACK_END_MAGIC)
+       if (task_stack_end_corrupted(tsk))
                printk(KERN_EMERG "Thread overran stack, or stack corrupted\n");
 
        tsk->thread.cr2         = address;
@@ -933,8 +930,17 @@ static int spurious_fault_check(unsigned long error_code, pte_t *pte)
  * cross-processor TLB flush, even if no stale TLB entries exist
  * on other processors.
  *
+ * Spurious faults may only occur if the TLB contains an entry with
+ * fewer permission than the page table entry.  Non-present (P = 0)
+ * and reserved bit (R = 1) faults are never spurious.
+ *
  * There are no security implications to leaving a stale TLB when
  * increasing the permissions on a page.
+ *
+ * Returns non-zero if a spurious fault was handled, zero otherwise.
+ *
+ * See Intel Developer's Manual Vol 3 Section 4.10.4.3, bullet 3
+ * (Optional Invalidation).
  */
 static noinline int
 spurious_fault(unsigned long error_code, unsigned long address)
@@ -945,8 +951,17 @@ spurious_fault(unsigned long error_code, unsigned long address)
        pte_t *pte;
        int ret;
 
-       /* Reserved-bit violation or user access to kernel space? */
-       if (error_code & (PF_USER | PF_RSVD))
+       /*
+        * Only writes to RO or instruction fetches from NX may cause
+        * spurious faults.
+        *
+        * These could be from user or supervisor accesses but the TLB
+        * is only lazily flushed after a kernel mapping protection
+        * change, so user accesses are not expected to cause spurious
+        * faults.
+        */
+       if (error_code != (PF_WRITE | PF_PROT)
+           && error_code != (PF_INSTR | PF_PROT))
                return 0;
 
        pgd = init_mm.pgd + pgd_index(address);
index 7d05565ba7813047cfc4f4d96d339f9af0e5c3d3..c8140e12816a51f77702b273289222071ecb2350 100644 (file)
@@ -537,7 +537,7 @@ static void __init pagetable_init(void)
        permanent_kmaps_init(pgd_base);
 }
 
-pteval_t __supported_pte_mask __read_mostly = ~(_PAGE_NX | _PAGE_GLOBAL | _PAGE_IOMAP);
+pteval_t __supported_pte_mask __read_mostly = ~(_PAGE_NX | _PAGE_GLOBAL);
 EXPORT_SYMBOL_GPL(__supported_pte_mask);
 
 /* user-defined highmem size */
index 5621c47d7a1a0e7274c7fd49b6aa7602d952bd74..4cb8763868fc20add0018a26df9752f1cd03937d 100644 (file)
@@ -151,7 +151,7 @@ early_param("gbpages", parse_direct_gbpages_on);
  * around without checking the pgd every time.
  */
 
-pteval_t __supported_pte_mask __read_mostly = ~_PAGE_IOMAP;
+pteval_t __supported_pte_mask __read_mostly = ~0;
 EXPORT_SYMBOL_GPL(__supported_pte_mask);
 
 int force_personality32;
@@ -178,7 +178,7 @@ __setup("noexec32=", nonx32_setup);
  * When memory was added/removed make sure all the processes MM have
  * suitable PGD entries in the local PGD level page.
  */
-void sync_global_pgds(unsigned long start, unsigned long end)
+void sync_global_pgds(unsigned long start, unsigned long end, int removed)
 {
        unsigned long address;
 
@@ -186,7 +186,12 @@ void sync_global_pgds(unsigned long start, unsigned long end)
                const pgd_t *pgd_ref = pgd_offset_k(address);
                struct page *page;
 
-               if (pgd_none(*pgd_ref))
+               /*
+                * When it is called after memory hot remove, pgd_none()
+                * returns true. In this case (removed == 1), we must clear
+                * the PGD entries in the local PGD level page.
+                */
+               if (pgd_none(*pgd_ref) && !removed)
                        continue;
 
                spin_lock(&pgd_lock);
@@ -199,12 +204,18 @@ void sync_global_pgds(unsigned long start, unsigned long end)
                        pgt_lock = &pgd_page_get_mm(page)->page_table_lock;
                        spin_lock(pgt_lock);
 
-                       if (pgd_none(*pgd))
-                               set_pgd(pgd, *pgd_ref);
-                       else
+                       if (!pgd_none(*pgd_ref) && !pgd_none(*pgd))
                                BUG_ON(pgd_page_vaddr(*pgd)
                                       != pgd_page_vaddr(*pgd_ref));
 
+                       if (removed) {
+                               if (pgd_none(*pgd_ref) && !pgd_none(*pgd))
+                                       pgd_clear(pgd);
+                       } else {
+                               if (pgd_none(*pgd))
+                                       set_pgd(pgd, *pgd_ref);
+                       }
+
                        spin_unlock(pgt_lock);
                }
                spin_unlock(&pgd_lock);
@@ -633,7 +644,7 @@ kernel_physical_mapping_init(unsigned long start,
        }
 
        if (pgd_changed)
-               sync_global_pgds(addr, end - 1);
+               sync_global_pgds(addr, end - 1, 0);
 
        __flush_tlb_all();
 
@@ -976,25 +987,26 @@ static void __meminit
 remove_pagetable(unsigned long start, unsigned long end, bool direct)
 {
        unsigned long next;
+       unsigned long addr;
        pgd_t *pgd;
        pud_t *pud;
        bool pgd_changed = false;
 
-       for (; start < end; start = next) {
-               next = pgd_addr_end(start, end);
+       for (addr = start; addr < end; addr = next) {
+               next = pgd_addr_end(addr, end);
 
-               pgd = pgd_offset_k(start);
+               pgd = pgd_offset_k(addr);
                if (!pgd_present(*pgd))
                        continue;
 
                pud = (pud_t *)pgd_page_vaddr(*pgd);
-               remove_pud_table(pud, start, next, direct);
+               remove_pud_table(pud, addr, next, direct);
                if (free_pud_table(pud, pgd))
                        pgd_changed = true;
        }
 
        if (pgd_changed)
-               sync_global_pgds(start, end - 1);
+               sync_global_pgds(start, end - 1, 1);
 
        flush_tlb_all();
 }
@@ -1341,7 +1353,7 @@ int __meminit vmemmap_populate(unsigned long start, unsigned long end, int node)
        else
                err = vmemmap_populate_basepages(start, end, node);
        if (!err)
-               sync_global_pgds(start, end - 1);
+               sync_global_pgds(start, end - 1, 0);
        return err;
 }
 
index baff1da354e0ecfaf371b4e9f30ac6533d657a28..af78e50ca6cee7e4b7293075171986ab6f7166d5 100644 (file)
@@ -86,6 +86,7 @@ static void __iomem *__ioremap_caller(resource_size_t phys_addr,
        pgprot_t prot;
        int retval;
        void __iomem *ret_addr;
+       int ram_region;
 
        /* Don't allow wraparound or zero size */
        last_addr = phys_addr + size - 1;
@@ -108,12 +109,23 @@ static void __iomem *__ioremap_caller(resource_size_t phys_addr,
        /*
         * Don't allow anybody to remap normal RAM that we're using..
         */
-       pfn      = phys_addr >> PAGE_SHIFT;
-       last_pfn = last_addr >> PAGE_SHIFT;
-       if (walk_system_ram_range(pfn, last_pfn - pfn + 1, NULL,
-                                 __ioremap_check_ram) == 1)
+       /* First check if whole region can be identified as RAM or not */
+       ram_region = region_is_ram(phys_addr, size);
+       if (ram_region > 0) {
+               WARN_ONCE(1, "ioremap on RAM at 0x%lx - 0x%lx\n",
+                               (unsigned long int)phys_addr,
+                               (unsigned long int)last_addr);
                return NULL;
+       }
 
+       /* If could not be identified(-1), check page by page */
+       if (ram_region < 0) {
+               pfn      = phys_addr >> PAGE_SHIFT;
+               last_pfn = last_addr >> PAGE_SHIFT;
+               if (walk_system_ram_range(pfn, last_pfn - pfn + 1, NULL,
+                                         __ioremap_check_ram) == 1)
+                       return NULL;
+       }
        /*
         * Mappings have to be page-aligned
         */
index a32b706c401add2e47943cf1650ca63f26b8c1ae..1a883705a12a8a12410914be93b2ee65807cc423 100644 (file)
@@ -185,26 +185,14 @@ int __init numa_add_memblk(int nid, u64 start, u64 end)
        return numa_add_memblk_to(nid, start, end, &numa_meminfo);
 }
 
-/* Initialize NODE_DATA for a node on the local memory */
-static void __init setup_node_data(int nid, u64 start, u64 end)
+/* Allocate NODE_DATA for a node on the local memory */
+static void __init alloc_node_data(int nid)
 {
        const size_t nd_size = roundup(sizeof(pg_data_t), PAGE_SIZE);
        u64 nd_pa;
        void *nd;
        int tnid;
 
-       /*
-        * Don't confuse VM with a node that doesn't have the
-        * minimum amount of memory:
-        */
-       if (end && (end - start) < NODE_MIN_SIZE)
-               return;
-
-       start = roundup(start, ZONE_ALIGN);
-
-       printk(KERN_INFO "Initmem setup node %d [mem %#010Lx-%#010Lx]\n",
-              nid, start, end - 1);
-
        /*
         * Allocate node data.  Try node-local memory and then any node.
         * Never allocate in DMA zone.
@@ -222,7 +210,7 @@ static void __init setup_node_data(int nid, u64 start, u64 end)
        nd = __va(nd_pa);
 
        /* report and initialize */
-       printk(KERN_INFO "  NODE_DATA [mem %#010Lx-%#010Lx]\n",
+       printk(KERN_INFO "NODE_DATA(%d) allocated [mem %#010Lx-%#010Lx]\n", nid,
               nd_pa, nd_pa + nd_size - 1);
        tnid = early_pfn_to_nid(nd_pa >> PAGE_SHIFT);
        if (tnid != nid)
@@ -230,9 +218,6 @@ static void __init setup_node_data(int nid, u64 start, u64 end)
 
        node_data[nid] = nd;
        memset(NODE_DATA(nid), 0, sizeof(pg_data_t));
-       NODE_DATA(nid)->node_id = nid;
-       NODE_DATA(nid)->node_start_pfn = start >> PAGE_SHIFT;
-       NODE_DATA(nid)->node_spanned_pages = (end - start) >> PAGE_SHIFT;
 
        node_set_online(nid);
 }
@@ -478,6 +463,42 @@ static bool __init numa_meminfo_cover_memory(const struct numa_meminfo *mi)
        return true;
 }
 
+static void __init numa_clear_kernel_node_hotplug(void)
+{
+       int i, nid;
+       nodemask_t numa_kernel_nodes = NODE_MASK_NONE;
+       unsigned long start, end;
+       struct memblock_region *r;
+
+       /*
+        * At this time, all memory regions reserved by memblock are
+        * used by the kernel. Set the nid in memblock.reserved will
+        * mark out all the nodes the kernel resides in.
+        */
+       for (i = 0; i < numa_meminfo.nr_blks; i++) {
+               struct numa_memblk *mb = &numa_meminfo.blk[i];
+
+               memblock_set_node(mb->start, mb->end - mb->start,
+                                 &memblock.reserved, mb->nid);
+       }
+
+       /* Mark all kernel nodes. */
+       for_each_memblock(reserved, r)
+               node_set(r->nid, numa_kernel_nodes);
+
+       /* Clear MEMBLOCK_HOTPLUG flag for memory in kernel nodes. */
+       for (i = 0; i < numa_meminfo.nr_blks; i++) {
+               nid = numa_meminfo.blk[i].nid;
+               if (!node_isset(nid, numa_kernel_nodes))
+                       continue;
+
+               start = numa_meminfo.blk[i].start;
+               end = numa_meminfo.blk[i].end;
+
+               memblock_clear_hotplug(start, end - start);
+       }
+}
+
 static int __init numa_register_memblks(struct numa_meminfo *mi)
 {
        unsigned long uninitialized_var(pfn_align);
@@ -495,6 +516,15 @@ static int __init numa_register_memblks(struct numa_meminfo *mi)
                                  &memblock.memory, mb->nid);
        }
 
+       /*
+        * At very early time, the kernel have to use some memory such as
+        * loading the kernel image. We cannot prevent this anyway. So any
+        * node the kernel resides in should be un-hotpluggable.
+        *
+        * And when we come here, alloc node data won't fail.
+        */
+       numa_clear_kernel_node_hotplug();
+
        /*
         * If sections array is gonna be used for pfn -> nid mapping, check
         * whether its granularity is fine enough.
@@ -523,8 +553,17 @@ static int __init numa_register_memblks(struct numa_meminfo *mi)
                        end = max(mi->blk[i].end, end);
                }
 
-               if (start < end)
-                       setup_node_data(nid, start, end);
+               if (start >= end)
+                       continue;
+
+               /*
+                * Don't confuse VM with a node that doesn't have the
+                * minimum amount of memory:
+                */
+               if (end && (end - start) < NODE_MIN_SIZE)
+                       continue;
+
+               alloc_node_data(nid);
        }
 
        /* Dump memblock with node info and return. */
@@ -554,41 +593,6 @@ static void __init numa_init_array(void)
        }
 }
 
-static void __init numa_clear_kernel_node_hotplug(void)
-{
-       int i, nid;
-       nodemask_t numa_kernel_nodes = NODE_MASK_NONE;
-       unsigned long start, end;
-       struct memblock_region *r;
-
-       /*
-        * At this time, all memory regions reserved by memblock are
-        * used by the kernel. Set the nid in memblock.reserved will
-        * mark out all the nodes the kernel resides in.
-        */
-       for (i = 0; i < numa_meminfo.nr_blks; i++) {
-               struct numa_memblk *mb = &numa_meminfo.blk[i];
-               memblock_set_node(mb->start, mb->end - mb->start,
-                                 &memblock.reserved, mb->nid);
-       }
-
-       /* Mark all kernel nodes. */
-       for_each_memblock(reserved, r)
-               node_set(r->nid, numa_kernel_nodes);
-
-       /* Clear MEMBLOCK_HOTPLUG flag for memory in kernel nodes. */
-       for (i = 0; i < numa_meminfo.nr_blks; i++) {
-               nid = numa_meminfo.blk[i].nid;
-               if (!node_isset(nid, numa_kernel_nodes))
-                       continue;
-
-               start = numa_meminfo.blk[i].start;
-               end = numa_meminfo.blk[i].end;
-
-               memblock_clear_hotplug(start, end - start);
-       }
-}
-
 static int __init numa_init(int (*init_func)(void))
 {
        int i;
@@ -643,15 +647,6 @@ static int __init numa_init(int (*init_func)(void))
        }
        numa_init_array();
 
-       /*
-        * At very early time, the kernel have to use some memory such as
-        * loading the kernel image. We cannot prevent this anyway. So any
-        * node the kernel resides in should be un-hotpluggable.
-        *
-        * And when we come here, numa_init() won't fail.
-        */
-       numa_clear_kernel_node_hotplug();
-
        return 0;
 }
 
index 4dd8cf6525798cbaa817e47eb475545948fa2284..75cc0978d45d7d7acc43d65615b766c78df9ab1a 100644 (file)
@@ -59,41 +59,6 @@ void set_pte_vaddr(unsigned long vaddr, pte_t pteval)
        __flush_tlb_one(vaddr);
 }
 
-/*
- * Associate a large virtual page frame with a given physical page frame 
- * and protection flags for that frame. pfn is for the base of the page,
- * vaddr is what the page gets mapped to - both must be properly aligned. 
- * The pmd must already be instantiated. Assumes PAE mode.
- */ 
-void set_pmd_pfn(unsigned long vaddr, unsigned long pfn, pgprot_t flags)
-{
-       pgd_t *pgd;
-       pud_t *pud;
-       pmd_t *pmd;
-
-       if (vaddr & (PMD_SIZE-1)) {             /* vaddr is misaligned */
-               printk(KERN_WARNING "set_pmd_pfn: vaddr misaligned\n");
-               return; /* BUG(); */
-       }
-       if (pfn & (PTRS_PER_PTE-1)) {           /* pfn is misaligned */
-               printk(KERN_WARNING "set_pmd_pfn: pfn misaligned\n");
-               return; /* BUG(); */
-       }
-       pgd = swapper_pg_dir + pgd_index(vaddr);
-       if (pgd_none(*pgd)) {
-               printk(KERN_WARNING "set_pmd_pfn: pgd_none\n");
-               return; /* BUG(); */
-       }
-       pud = pud_offset(pgd, vaddr);
-       pmd = pmd_offset(pud, vaddr);
-       set_pmd(pmd, pfn_pmd(pfn, flags));
-       /*
-        * It's enough to flush this one mapping.
-        * (PGE mappings get flushed as well)
-        */
-       __flush_tlb_one(vaddr);
-}
-
 unsigned long __FIXADDR_TOP = 0xfffff000;
 EXPORT_SYMBOL(__FIXADDR_TOP);
 
index 2ae525e0d8ba641c1a58d9892d8c8d6e754ee74e..37c1435889cea24c66dd68e8e396a2fe5503d10a 100644 (file)
@@ -442,8 +442,6 @@ int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma,
                 */
                prot |= _PAGE_CACHE_UC_MINUS;
 
-       prot |= _PAGE_IOMAP;    /* creating a mapping for IO */
-
        vma->vm_page_prot = __pgprot(prot);
 
        if (io_remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff,
index 899dd24542568de85e815e4b9f206d66286bca8c..f52e033557c9e0b54c41248101e0d7d7ed7cb76f 100644 (file)
@@ -18,8 +18,9 @@ $(obj)/purgatory.ro: $(PURGATORY_OBJS) FORCE
 
 targets += kexec-purgatory.c
 
+CMD_BIN2C = $(objtree)/scripts/basic/bin2c
 quiet_cmd_bin2c = BIN2C   $@
-      cmd_bin2c = cat $(obj)/purgatory.ro | $(objtree)/scripts/basic/bin2c kexec_purgatory > $(obj)/kexec-purgatory.c
+      cmd_bin2c = $(CMD_BIN2C) kexec_purgatory < $< > $@
 
 $(obj)/kexec-purgatory.c: $(obj)/purgatory.ro FORCE
        $(call if_changed,bin2c)
index bbb1d2259ecf52acc24caf198a3d27f8fd594018..a5efb21d5228b63ad45cd4cf67dc1c521e4cd16a 100644 (file)
@@ -695,7 +695,7 @@ static void walk_relocs(int (*process)(struct section *sec, Elf_Rel *rel,
  *
  */
 static int per_cpu_shndx       = -1;
-Elf_Addr per_cpu_load_addr;
+static Elf_Addr per_cpu_load_addr;
 
 static void percpu_init(void)
 {
index 8d0c420465cce0cf897278e03f25904a51cd92ff..fa4b8b9841ff7071a993e61d2b55ca3bc8b35575 100644 (file)
@@ -214,242 +214,3 @@ csum_partial:
        ret
                                
 #endif
-
-/*
-unsigned int csum_partial_copy_generic (const char *src, char *dst,
-                                 int len, int sum, int *src_err_ptr, int *dst_err_ptr)
- */ 
-
-/*
- * Copy from ds while checksumming, otherwise like csum_partial
- *
- * The macros SRC and DST specify the type of access for the instruction.
- * thus we can call a custom exception handler for all access types.
- *
- * FIXME: could someone double-check whether I haven't mixed up some SRC and
- *       DST definitions? It's damn hard to trigger all cases.  I hope I got
- *       them all but there's no guarantee.
- */
-
-#define SRC(y...)                      \
-       9999: y;                        \
-       _ASM_EXTABLE(9999b, 6001f)
-
-#define DST(y...)                      \
-       9999: y;                        \
-       _ASM_EXTABLE(9999b, 6002f)
-
-.align 4
-
-#ifndef CONFIG_X86_USE_PPRO_CHECKSUM
-
-#define ARGBASE 16             
-#define FP             12
-
-csum_partial_copy_generic_i386:
-       subl  $4,%esp   
-       pushl %edi
-       pushl %esi
-       pushl %ebx
-       movl ARGBASE+16(%esp),%eax      # sum
-       movl ARGBASE+12(%esp),%ecx      # len
-       movl ARGBASE+4(%esp),%esi       # src
-       movl ARGBASE+8(%esp),%edi       # dst
-
-       testl $2, %edi                  # Check alignment. 
-       jz 2f                           # Jump if alignment is ok.
-       subl $2, %ecx                   # Alignment uses up two bytes.
-       jae 1f                          # Jump if we had at least two bytes.
-       addl $2, %ecx                   # ecx was < 2.  Deal with it.
-       jmp 4f
-SRC(1: movw (%esi), %bx        )
-       addl $2, %esi
-DST(   movw %bx, (%edi)        )
-       addl $2, %edi
-       addw %bx, %ax   
-       adcl $0, %eax
-2:
-       movl %ecx, FP(%esp)
-       shrl $5, %ecx
-       jz 2f
-       testl %esi, %esi
-SRC(1: movl (%esi), %ebx       )
-SRC(   movl 4(%esi), %edx      )
-       adcl %ebx, %eax
-DST(   movl %ebx, (%edi)       )
-       adcl %edx, %eax
-DST(   movl %edx, 4(%edi)      )
-
-SRC(   movl 8(%esi), %ebx      )
-SRC(   movl 12(%esi), %edx     )
-       adcl %ebx, %eax
-DST(   movl %ebx, 8(%edi)      )
-       adcl %edx, %eax
-DST(   movl %edx, 12(%edi)     )
-
-SRC(   movl 16(%esi), %ebx     )
-SRC(   movl 20(%esi), %edx     )
-       adcl %ebx, %eax
-DST(   movl %ebx, 16(%edi)     )
-       adcl %edx, %eax
-DST(   movl %edx, 20(%edi)     )
-
-SRC(   movl 24(%esi), %ebx     )
-SRC(   movl 28(%esi), %edx     )
-       adcl %ebx, %eax
-DST(   movl %ebx, 24(%edi)     )
-       adcl %edx, %eax
-DST(   movl %edx, 28(%edi)     )
-
-       lea 32(%esi), %esi
-       lea 32(%edi), %edi
-       dec %ecx
-       jne 1b
-       adcl $0, %eax
-2:     movl FP(%esp), %edx
-       movl %edx, %ecx
-       andl $0x1c, %edx
-       je 4f
-       shrl $2, %edx                   # This clears CF
-SRC(3: movl (%esi), %ebx       )
-       adcl %ebx, %eax
-DST(   movl %ebx, (%edi)       )
-       lea 4(%esi), %esi
-       lea 4(%edi), %edi
-       dec %edx
-       jne 3b
-       adcl $0, %eax
-4:     andl $3, %ecx
-       jz 7f
-       cmpl $2, %ecx
-       jb 5f
-SRC(   movw (%esi), %cx        )
-       leal 2(%esi), %esi
-DST(   movw %cx, (%edi)        )
-       leal 2(%edi), %edi
-       je 6f
-       shll $16,%ecx
-SRC(5: movb (%esi), %cl        )
-DST(   movb %cl, (%edi)        )
-6:     addl %ecx, %eax
-       adcl $0, %eax
-7:
-5000:
-
-# Exception handler:
-.section .fixup, "ax"                                                  
-
-6001:
-       movl ARGBASE+20(%esp), %ebx     # src_err_ptr
-       movl $-EFAULT, (%ebx)
-
-       # zero the complete destination - computing the rest
-       # is too much work 
-       movl ARGBASE+8(%esp), %edi      # dst
-       movl ARGBASE+12(%esp), %ecx     # len
-       xorl %eax,%eax
-       rep ; stosb
-
-       jmp 5000b
-
-6002:
-       movl ARGBASE+24(%esp), %ebx     # dst_err_ptr
-       movl $-EFAULT,(%ebx)
-       jmp 5000b
-
-.previous
-
-       popl %ebx
-       popl %esi
-       popl %edi
-       popl %ecx                       # equivalent to addl $4,%esp
-       ret     
-
-#else
-
-/* Version for PentiumII/PPro */
-
-#define ROUND1(x) \
-       SRC(movl x(%esi), %ebx  )       ;       \
-       addl %ebx, %eax                 ;       \
-       DST(movl %ebx, x(%edi)  )       ; 
-
-#define ROUND(x) \
-       SRC(movl x(%esi), %ebx  )       ;       \
-       adcl %ebx, %eax                 ;       \
-       DST(movl %ebx, x(%edi)  )       ;
-
-#define ARGBASE 12
-               
-csum_partial_copy_generic_i386:
-       pushl %ebx
-       pushl %edi
-       pushl %esi
-       movl ARGBASE+4(%esp),%esi       #src
-       movl ARGBASE+8(%esp),%edi       #dst    
-       movl ARGBASE+12(%esp),%ecx      #len
-       movl ARGBASE+16(%esp),%eax      #sum
-#      movl %ecx, %edx  
-       movl %ecx, %ebx  
-       movl %esi, %edx
-       shrl $6, %ecx     
-       andl $0x3c, %ebx  
-       negl %ebx
-       subl %ebx, %esi  
-       subl %ebx, %edi  
-       lea  -1(%esi),%edx
-       andl $-32,%edx
-       lea 3f(%ebx,%ebx), %ebx
-       testl %esi, %esi 
-       jmp *%ebx
-1:     addl $64,%esi
-       addl $64,%edi 
-       SRC(movb -32(%edx),%bl) ; SRC(movb (%edx),%bl)
-       ROUND1(-64) ROUND(-60) ROUND(-56) ROUND(-52)    
-       ROUND (-48) ROUND(-44) ROUND(-40) ROUND(-36)    
-       ROUND (-32) ROUND(-28) ROUND(-24) ROUND(-20)    
-       ROUND (-16) ROUND(-12) ROUND(-8)  ROUND(-4)     
-3:     adcl $0,%eax
-       addl $64, %edx
-       dec %ecx
-       jge 1b
-4:     movl ARGBASE+12(%esp),%edx      #len
-       andl $3, %edx
-       jz 7f
-       cmpl $2, %edx
-       jb 5f
-SRC(   movw (%esi), %dx         )
-       leal 2(%esi), %esi
-DST(   movw %dx, (%edi)         )
-       leal 2(%edi), %edi
-       je 6f
-       shll $16,%edx
-5:
-SRC(   movb (%esi), %dl         )
-DST(   movb %dl, (%edi)         )
-6:     addl %edx, %eax
-       adcl $0, %eax
-7:
-.section .fixup, "ax"
-6001:  movl    ARGBASE+20(%esp), %ebx  # src_err_ptr   
-       movl $-EFAULT, (%ebx)
-       # zero the complete destination (computing the rest is too much work)
-       movl ARGBASE+8(%esp),%edi       # dst
-       movl ARGBASE+12(%esp),%ecx      # len
-       xorl %eax,%eax
-       rep; stosb
-       jmp 7b
-6002:  movl ARGBASE+24(%esp), %ebx     # dst_err_ptr
-       movl $-EFAULT, (%ebx)
-       jmp  7b                 
-.previous                              
-
-       popl %esi
-       popl %edi
-       popl %ebx
-       ret
-                               
-#undef ROUND
-#undef ROUND1          
-               
-#endif
index fd57829b30d8874cb084496482b8f8b379129c14..0224987556ce80bd606063b56ef124b0857a3f44 100644 (file)
@@ -109,16 +109,18 @@ static void BITSFUNC(go)(void *raw_addr, size_t raw_len,
 
        /* Validate mapping addresses. */
        for (i = 0; i < sizeof(special_pages) / sizeof(special_pages[0]); i++) {
-               if (!syms[i])
+               INT_BITS symval = syms[special_pages[i]];
+
+               if (!symval)
                        continue;  /* The mapping isn't used; ignore it. */
 
-               if (syms[i] % 4096)
+               if (symval % 4096)
                        fail("%s must be a multiple of 4096\n",
                             required_syms[i].name);
-               if (syms[sym_vvar_start] > syms[i] + 4096)
-                       fail("%s underruns begin_vvar\n",
+               if (symval + 4096 < syms[sym_vvar_start])
+                       fail("%s underruns vvar_start\n",
                             required_syms[i].name);
-               if (syms[i] + 4096 > 0)
+               if (symval + 4096 > 0)
                        fail("%s is on the wrong side of the vdso text\n",
                             required_syms[i].name);
        }
index a02e09e18f57b160c8c5f036ac64d5e97a72a4c1..be14cc3e48d5fd8e0b5440396478a5c6a8932025 100644 (file)
  * with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
+#include <linux/bitops.h>
 #include <linux/efi.h>
 #include <linux/init.h>
 #include <linux/string.h>
 
 #include <xen/xen-ops.h>
 
+#include <asm/page.h>
 #include <asm/setup.h>
 
 void __init xen_efi_init(void)
index c0cb11fb500895f60b91e8ad1af679d878d40903..acb0effd80773f347ef8a7e6591d6a447c894423 100644 (file)
@@ -1463,6 +1463,7 @@ static void __ref xen_setup_gdt(int cpu)
        pv_cpu_ops.load_gdt = xen_load_gdt;
 }
 
+#ifdef CONFIG_XEN_PVH
 /*
  * A PV guest starts with default flags that are not set for PVH, set them
  * here asap.
@@ -1508,17 +1509,21 @@ static void __init xen_pvh_early_guest_init(void)
                return;
 
        xen_have_vector_callback = 1;
+
+       xen_pvh_early_cpu_init(0, false);
        xen_pvh_set_cr_flags(0);
 
 #ifdef CONFIG_X86_32
        BUG(); /* PVH: Implement proper support. */
 #endif
 }
+#endif    /* CONFIG_XEN_PVH */
 
 /* First C function to be called on Xen boot */
 asmlinkage __visible void __init xen_start_kernel(void)
 {
        struct physdev_set_iopl set_iopl;
+       unsigned long initrd_start = 0;
        int rc;
 
        if (!xen_start_info)
@@ -1527,7 +1532,9 @@ asmlinkage __visible void __init xen_start_kernel(void)
        xen_domain_type = XEN_PV_DOMAIN;
 
        xen_setup_features();
+#ifdef CONFIG_XEN_PVH
        xen_pvh_early_guest_init();
+#endif
        xen_setup_machphys_mapping();
 
        /* Install Xen paravirt ops */
@@ -1559,8 +1566,6 @@ asmlinkage __visible void __init xen_start_kernel(void)
 #endif
                __supported_pte_mask &= ~(_PAGE_PWT | _PAGE_PCD);
 
-       __supported_pte_mask |= _PAGE_IOMAP;
-
        /*
         * Prevent page tables from being allocated in highmem, even
         * if CONFIG_HIGHPTE is enabled.
@@ -1667,10 +1672,16 @@ asmlinkage __visible void __init xen_start_kernel(void)
        new_cpu_data.x86_capability[0] = cpuid_edx(1);
 #endif
 
+       if (xen_start_info->mod_start) {
+           if (xen_start_info->flags & SIF_MOD_START_PFN)
+               initrd_start = PFN_PHYS(xen_start_info->mod_start);
+           else
+               initrd_start = __pa(xen_start_info->mod_start);
+       }
+
        /* Poke various useful things into boot_params */
        boot_params.hdr.type_of_loader = (9 << 4) | 0;
-       boot_params.hdr.ramdisk_image = xen_start_info->mod_start
-               ? __pa(xen_start_info->mod_start) : 0;
+       boot_params.hdr.ramdisk_image = initrd_start;
        boot_params.hdr.ramdisk_size = xen_start_info->mod_len;
        boot_params.hdr.cmd_line_ptr = __pa(xen_start_info->cmd_line);
 
index 16fb0099b7f295ed40c206e25478037f0b2ff651..f62af7647ec9879055f433a540166cb4162a1f0d 100644 (file)
@@ -399,38 +399,14 @@ static pteval_t pte_pfn_to_mfn(pteval_t val)
                if (unlikely(mfn == INVALID_P2M_ENTRY)) {
                        mfn = 0;
                        flags = 0;
-               } else {
-                       /*
-                        * Paramount to do this test _after_ the
-                        * INVALID_P2M_ENTRY as INVALID_P2M_ENTRY &
-                        * IDENTITY_FRAME_BIT resolves to true.
-                        */
-                       mfn &= ~FOREIGN_FRAME_BIT;
-                       if (mfn & IDENTITY_FRAME_BIT) {
-                               mfn &= ~IDENTITY_FRAME_BIT;
-                               flags |= _PAGE_IOMAP;
-                       }
-               }
+               } else
+                       mfn &= ~(FOREIGN_FRAME_BIT | IDENTITY_FRAME_BIT);
                val = ((pteval_t)mfn << PAGE_SHIFT) | flags;
        }
 
        return val;
 }
 
-static pteval_t iomap_pte(pteval_t val)
-{
-       if (val & _PAGE_PRESENT) {
-               unsigned long pfn = (val & PTE_PFN_MASK) >> PAGE_SHIFT;
-               pteval_t flags = val & PTE_FLAGS_MASK;
-
-               /* We assume the pte frame number is a MFN, so
-                  just use it as-is. */
-               val = ((pteval_t)pfn << PAGE_SHIFT) | flags;
-       }
-
-       return val;
-}
-
 __visible pteval_t xen_pte_val(pte_t pte)
 {
        pteval_t pteval = pte.pte;
@@ -441,9 +417,6 @@ __visible pteval_t xen_pte_val(pte_t pte)
                pteval = (pteval & ~_PAGE_PAT) | _PAGE_PWT;
        }
 #endif
-       if (xen_initial_domain() && (pteval & _PAGE_IOMAP))
-               return pteval;
-
        return pte_mfn_to_pfn(pteval);
 }
 PV_CALLEE_SAVE_REGS_THUNK(xen_pte_val);
@@ -481,7 +454,6 @@ void xen_set_pat(u64 pat)
 
 __visible pte_t xen_make_pte(pteval_t pte)
 {
-       phys_addr_t addr = (pte & PTE_PFN_MASK);
 #if 0
        /* If Linux is trying to set a WC pte, then map to the Xen WC.
         * If _PAGE_PAT is set, then it probably means it is really
@@ -496,19 +468,7 @@ __visible pte_t xen_make_pte(pteval_t pte)
                        pte = (pte & ~(_PAGE_PCD | _PAGE_PWT)) | _PAGE_PAT;
        }
 #endif
-       /*
-        * Unprivileged domains are allowed to do IOMAPpings for
-        * PCI passthrough, but not map ISA space.  The ISA
-        * mappings are just dummy local mappings to keep other
-        * parts of the kernel happy.
-        */
-       if (unlikely(pte & _PAGE_IOMAP) &&
-           (xen_initial_domain() || addr >= ISA_END_ADDRESS)) {
-               pte = iomap_pte(pte);
-       } else {
-               pte &= ~_PAGE_IOMAP;
-               pte = pte_pfn_to_mfn(pte);
-       }
+       pte = pte_pfn_to_mfn(pte);
 
        return native_make_pte(pte);
 }
@@ -2091,7 +2051,7 @@ static void xen_set_fixmap(unsigned idx, phys_addr_t phys, pgprot_t prot)
 
        default:
                /* By default, set_fixmap is used for hardware mappings */
-               pte = mfn_pte(phys, __pgprot(pgprot_val(prot) | _PAGE_IOMAP));
+               pte = mfn_pte(phys, prot);
                break;
        }
 
index 3172692381aec4bb5dade9851fa7fa7715d58e46..9f5983b01ed91ebe7080a0e5928e3f549d0c1242 100644 (file)
 #include <xen/balloon.h>
 #include <xen/grant_table.h>
 
+#include "p2m.h"
 #include "multicalls.h"
 #include "xen-ops.h"
 
@@ -180,12 +181,6 @@ static void __init m2p_override_init(void);
 
 unsigned long xen_max_p2m_pfn __read_mostly;
 
-#define P2M_PER_PAGE           (PAGE_SIZE / sizeof(unsigned long))
-#define P2M_MID_PER_PAGE       (PAGE_SIZE / sizeof(unsigned long *))
-#define P2M_TOP_PER_PAGE       (PAGE_SIZE / sizeof(unsigned long **))
-
-#define MAX_P2M_PFN            (P2M_TOP_PER_PAGE * P2M_MID_PER_PAGE * P2M_PER_PAGE)
-
 /* Placeholders for holes in the address space */
 static RESERVE_BRK_ARRAY(unsigned long, p2m_missing, P2M_PER_PAGE);
 static RESERVE_BRK_ARRAY(unsigned long *, p2m_mid_missing, P2M_MID_PER_PAGE);
@@ -202,16 +197,12 @@ static RESERVE_BRK_ARRAY(unsigned long, p2m_mid_identity_mfn, P2M_MID_PER_PAGE);
 RESERVE_BRK(p2m_mid, PAGE_SIZE * (MAX_DOMAIN_PAGES / (P2M_PER_PAGE * P2M_MID_PER_PAGE)));
 RESERVE_BRK(p2m_mid_mfn, PAGE_SIZE * (MAX_DOMAIN_PAGES / (P2M_PER_PAGE * P2M_MID_PER_PAGE)));
 
-/* We might hit two boundary violations at the start and end, at max each
- * boundary violation will require three middle nodes. */
-RESERVE_BRK(p2m_mid_extra, PAGE_SIZE * 2 * 3);
-
-/* When we populate back during bootup, the amount of pages can vary. The
- * max we have is seen is 395979, but that does not mean it can't be more.
- * Some machines can have 3GB I/O holes even. With early_can_reuse_p2m_middle
- * it can re-use Xen provided mfn_list array, so we only need to allocate at
- * most three P2M top nodes. */
-RESERVE_BRK(p2m_populated, PAGE_SIZE * 3);
+/* For each I/O range remapped we may lose up to two leaf pages for the boundary
+ * violations and three mid pages to cover up to 3GB. With
+ * early_can_reuse_p2m_middle() most of the leaf pages will be reused by the
+ * remapped region.
+ */
+RESERVE_BRK(p2m_identity_remap, PAGE_SIZE * 2 * 3 * MAX_REMAP_RANGES);
 
 static inline unsigned p2m_top_index(unsigned long pfn)
 {
diff --git a/arch/x86/xen/p2m.h b/arch/x86/xen/p2m.h
new file mode 100644 (file)
index 0000000..ad8aee2
--- /dev/null
@@ -0,0 +1,15 @@
+#ifndef _XEN_P2M_H
+#define _XEN_P2M_H
+
+#define P2M_PER_PAGE        (PAGE_SIZE / sizeof(unsigned long))
+#define P2M_MID_PER_PAGE    (PAGE_SIZE / sizeof(unsigned long *))
+#define P2M_TOP_PER_PAGE    (PAGE_SIZE / sizeof(unsigned long **))
+
+#define MAX_P2M_PFN         (P2M_TOP_PER_PAGE * P2M_MID_PER_PAGE * P2M_PER_PAGE)
+
+#define MAX_REMAP_RANGES    10
+
+extern unsigned long __init set_phys_range_identity(unsigned long pfn_s,
+                                      unsigned long pfn_e);
+
+#endif  /* _XEN_P2M_H */
index 2e555163c2fe4f0b44f37289887539ab274adc1c..af7216128d93ac4949e574b52d45f91079f6898f 100644 (file)
@@ -29,6 +29,7 @@
 #include <xen/features.h>
 #include "xen-ops.h"
 #include "vdso.h"
+#include "p2m.h"
 
 /* These are code, but not functions.  Defined in entry.S */
 extern const char xen_hypervisor_callback[];
@@ -46,6 +47,9 @@ struct xen_memory_region xen_extra_mem[XEN_EXTRA_MEM_MAX_REGIONS] __initdata;
 /* Number of pages released from the initial allocation. */
 unsigned long xen_released_pages;
 
+/* Buffer used to remap identity mapped pages */
+unsigned long xen_remap_buf[P2M_PER_PAGE] __initdata;
+
 /* 
  * The maximum amount of extra memory compared to the base size.  The
  * main scaling factor is the size of struct page.  At extreme ratios
@@ -151,107 +155,325 @@ static unsigned long __init xen_do_chunk(unsigned long start,
        return len;
 }
 
-static unsigned long __init xen_release_chunk(unsigned long start,
-                                             unsigned long end)
-{
-       return xen_do_chunk(start, end, true);
-}
-
-static unsigned long __init xen_populate_chunk(
+/*
+ * Finds the next RAM pfn available in the E820 map after min_pfn.
+ * This function updates min_pfn with the pfn found and returns
+ * the size of that range or zero if not found.
+ */
+static unsigned long __init xen_find_pfn_range(
        const struct e820entry *list, size_t map_size,
-       unsigned long max_pfn, unsigned long *last_pfn,
-       unsigned long credits_left)
+       unsigned long *min_pfn)
 {
        const struct e820entry *entry;
        unsigned int i;
        unsigned long done = 0;
-       unsigned long dest_pfn;
 
        for (i = 0, entry = list; i < map_size; i++, entry++) {
                unsigned long s_pfn;
                unsigned long e_pfn;
-               unsigned long pfns;
-               long capacity;
-
-               if (credits_left <= 0)
-                       break;
 
                if (entry->type != E820_RAM)
                        continue;
 
                e_pfn = PFN_DOWN(entry->addr + entry->size);
 
-               /* We only care about E820 after the xen_start_info->nr_pages */
-               if (e_pfn <= max_pfn)
+               /* We only care about E820 after this */
+               if (e_pfn < *min_pfn)
                        continue;
 
                s_pfn = PFN_UP(entry->addr);
-               /* If the E820 falls within the nr_pages, we want to start
-                * at the nr_pages PFN.
-                * If that would mean going past the E820 entry, skip it
+
+               /* If min_pfn falls within the E820 entry, we want to start
+                * at the min_pfn PFN.
                 */
-               if (s_pfn <= max_pfn) {
-                       capacity = e_pfn - max_pfn;
-                       dest_pfn = max_pfn;
+               if (s_pfn <= *min_pfn) {
+                       done = e_pfn - *min_pfn;
                } else {
-                       capacity = e_pfn - s_pfn;
-                       dest_pfn = s_pfn;
+                       done = e_pfn - s_pfn;
+                       *min_pfn = s_pfn;
                }
+               break;
+       }
 
-               if (credits_left < capacity)
-                       capacity = credits_left;
+       return done;
+}
 
-               pfns = xen_do_chunk(dest_pfn, dest_pfn + capacity, false);
-               done += pfns;
-               *last_pfn = (dest_pfn + pfns);
-               if (pfns < capacity)
-                       break;
-               credits_left -= pfns;
+/*
+ * This releases a chunk of memory and then does the identity map. It's used as
+ * as a fallback if the remapping fails.
+ */
+static void __init xen_set_identity_and_release_chunk(unsigned long start_pfn,
+       unsigned long end_pfn, unsigned long nr_pages, unsigned long *identity,
+       unsigned long *released)
+{
+       WARN_ON(start_pfn > end_pfn);
+
+       /* Need to release pages first */
+       *released += xen_do_chunk(start_pfn, min(end_pfn, nr_pages), true);
+       *identity += set_phys_range_identity(start_pfn, end_pfn);
+}
+
+/*
+ * Helper function to update both the p2m and m2p tables.
+ */
+static unsigned long __init xen_update_mem_tables(unsigned long pfn,
+                                                 unsigned long mfn)
+{
+       struct mmu_update update = {
+               .ptr = ((unsigned long long)mfn << PAGE_SHIFT) | MMU_MACHPHYS_UPDATE,
+               .val = pfn
+       };
+
+       /* Update p2m */
+       if (!early_set_phys_to_machine(pfn, mfn)) {
+               WARN(1, "Failed to set p2m mapping for pfn=%ld mfn=%ld\n",
+                    pfn, mfn);
+               return false;
        }
-       return done;
+
+       /* Update m2p */
+       if (HYPERVISOR_mmu_update(&update, 1, NULL, DOMID_SELF) < 0) {
+               WARN(1, "Failed to set m2p mapping for mfn=%ld pfn=%ld\n",
+                    mfn, pfn);
+               return false;
+       }
+
+       return true;
 }
 
-static void __init xen_set_identity_and_release_chunk(
-       unsigned long start_pfn, unsigned long end_pfn, unsigned long nr_pages,
-       unsigned long *released, unsigned long *identity)
+/*
+ * This function updates the p2m and m2p tables with an identity map from
+ * start_pfn to start_pfn+size and remaps the underlying RAM of the original
+ * allocation at remap_pfn. It must do so carefully in P2M_PER_PAGE sized blocks
+ * to not exhaust the reserved brk space. Doing it in properly aligned blocks
+ * ensures we only allocate the minimum required leaf pages in the p2m table. It
+ * copies the existing mfns from the p2m table under the 1:1 map, overwrites
+ * them with the identity map and then updates the p2m and m2p tables with the
+ * remapped memory.
+ */
+static unsigned long __init xen_do_set_identity_and_remap_chunk(
+        unsigned long start_pfn, unsigned long size, unsigned long remap_pfn)
 {
-       unsigned long pfn;
+       unsigned long ident_pfn_iter, remap_pfn_iter;
+       unsigned long ident_start_pfn_align, remap_start_pfn_align;
+       unsigned long ident_end_pfn_align, remap_end_pfn_align;
+       unsigned long ident_boundary_pfn, remap_boundary_pfn;
+       unsigned long ident_cnt = 0;
+       unsigned long remap_cnt = 0;
+       unsigned long left = size;
+       unsigned long mod;
+       int i;
+
+       WARN_ON(size == 0);
+
+       BUG_ON(xen_feature(XENFEAT_auto_translated_physmap));
 
        /*
-        * If the PFNs are currently mapped, clear the mappings
-        * (except for the ISA region which must be 1:1 mapped) to
-        * release the refcounts (in Xen) on the original frames.
+        * Determine the proper alignment to remap memory in P2M_PER_PAGE sized
+        * blocks. We need to keep track of both the existing pfn mapping and
+        * the new pfn remapping.
         */
-       for (pfn = start_pfn; pfn <= max_pfn_mapped && pfn < end_pfn; pfn++) {
-               pte_t pte = __pte_ma(0);
+       mod = start_pfn % P2M_PER_PAGE;
+       ident_start_pfn_align =
+               mod ? (start_pfn - mod + P2M_PER_PAGE) : start_pfn;
+       mod = remap_pfn % P2M_PER_PAGE;
+       remap_start_pfn_align =
+               mod ? (remap_pfn - mod + P2M_PER_PAGE) : remap_pfn;
+       mod = (start_pfn + size) % P2M_PER_PAGE;
+       ident_end_pfn_align = start_pfn + size - mod;
+       mod = (remap_pfn + size) % P2M_PER_PAGE;
+       remap_end_pfn_align = remap_pfn + size - mod;
+
+       /* Iterate over each p2m leaf node in each range */
+       for (ident_pfn_iter = ident_start_pfn_align, remap_pfn_iter = remap_start_pfn_align;
+            ident_pfn_iter < ident_end_pfn_align && remap_pfn_iter < remap_end_pfn_align;
+            ident_pfn_iter += P2M_PER_PAGE, remap_pfn_iter += P2M_PER_PAGE) {
+               /* Check we aren't past the end */
+               BUG_ON(ident_pfn_iter + P2M_PER_PAGE > start_pfn + size);
+               BUG_ON(remap_pfn_iter + P2M_PER_PAGE > remap_pfn + size);
+
+               /* Save p2m mappings */
+               for (i = 0; i < P2M_PER_PAGE; i++)
+                       xen_remap_buf[i] = pfn_to_mfn(ident_pfn_iter + i);
+
+               /* Set identity map which will free a p2m leaf */
+               ident_cnt += set_phys_range_identity(ident_pfn_iter,
+                       ident_pfn_iter + P2M_PER_PAGE);
+
+#ifdef DEBUG
+               /* Helps verify a p2m leaf has been freed */
+               for (i = 0; i < P2M_PER_PAGE; i++) {
+                       unsigned int pfn = ident_pfn_iter + i;
+                       BUG_ON(pfn_to_mfn(pfn) != pfn);
+               }
+#endif
+               /* Now remap memory */
+               for (i = 0; i < P2M_PER_PAGE; i++) {
+                       unsigned long mfn = xen_remap_buf[i];
+
+                       /* This will use the p2m leaf freed above */
+                       if (!xen_update_mem_tables(remap_pfn_iter + i, mfn)) {
+                               WARN(1, "Failed to update mem mapping for pfn=%ld mfn=%ld\n",
+                                       remap_pfn_iter + i, mfn);
+                               return 0;
+                       }
+
+                       remap_cnt++;
+               }
 
-               if (pfn < PFN_UP(ISA_END_ADDRESS))
-                       pte = mfn_pte(pfn, PAGE_KERNEL_IO);
+               left -= P2M_PER_PAGE;
+       }
 
-               (void)HYPERVISOR_update_va_mapping(
-                       (unsigned long)__va(pfn << PAGE_SHIFT), pte, 0);
+       /* Max boundary space possible */
+       BUG_ON(left > (P2M_PER_PAGE - 1) * 2);
+
+       /* Now handle the boundary conditions */
+       ident_boundary_pfn = start_pfn;
+       remap_boundary_pfn = remap_pfn;
+       for (i = 0; i < left; i++) {
+               unsigned long mfn;
+
+               /* These two checks move from the start to end boundaries */
+               if (ident_boundary_pfn == ident_start_pfn_align)
+                       ident_boundary_pfn = ident_pfn_iter;
+               if (remap_boundary_pfn == remap_start_pfn_align)
+                       remap_boundary_pfn = remap_pfn_iter;
+
+               /* Check we aren't past the end */
+               BUG_ON(ident_boundary_pfn >= start_pfn + size);
+               BUG_ON(remap_boundary_pfn >= remap_pfn + size);
+
+               mfn = pfn_to_mfn(ident_boundary_pfn);
+
+               if (!xen_update_mem_tables(remap_boundary_pfn, mfn)) {
+                       WARN(1, "Failed to update mem mapping for pfn=%ld mfn=%ld\n",
+                               remap_pfn_iter + i, mfn);
+                       return 0;
+               }
+               remap_cnt++;
+
+               ident_boundary_pfn++;
+               remap_boundary_pfn++;
        }
 
-       if (start_pfn < nr_pages)
-               *released += xen_release_chunk(
-                       start_pfn, min(end_pfn, nr_pages));
+       /* Finish up the identity map */
+       if (ident_start_pfn_align >= ident_end_pfn_align) {
+               /*
+                 * In this case we have an identity range which does not span an
+                 * aligned block so everything needs to be identity mapped here.
+                 * If we didn't check this we might remap too many pages since
+                 * the align boundaries are not meaningful in this case.
+                */
+               ident_cnt += set_phys_range_identity(start_pfn,
+                       start_pfn + size);
+       } else {
+               /* Remapped above so check each end of the chunk */
+               if (start_pfn < ident_start_pfn_align)
+                       ident_cnt += set_phys_range_identity(start_pfn,
+                               ident_start_pfn_align);
+               if (start_pfn + size > ident_pfn_iter)
+                       ident_cnt += set_phys_range_identity(ident_pfn_iter,
+                               start_pfn + size);
+       }
 
-       *identity += set_phys_range_identity(start_pfn, end_pfn);
+       BUG_ON(ident_cnt != size);
+       BUG_ON(remap_cnt != size);
+
+       return size;
 }
 
-static unsigned long __init xen_set_identity_and_release(
-       const struct e820entry *list, size_t map_size, unsigned long nr_pages)
+/*
+ * This function takes a contiguous pfn range that needs to be identity mapped
+ * and:
+ *
+ *  1) Finds a new range of pfns to use to remap based on E820 and remap_pfn.
+ *  2) Calls the do_ function to actually do the mapping/remapping work.
+ *
+ * The goal is to not allocate additional memory but to remap the existing
+ * pages. In the case of an error the underlying memory is simply released back
+ * to Xen and not remapped.
+ */
+static unsigned long __init xen_set_identity_and_remap_chunk(
+        const struct e820entry *list, size_t map_size, unsigned long start_pfn,
+       unsigned long end_pfn, unsigned long nr_pages, unsigned long remap_pfn,
+       unsigned long *identity, unsigned long *remapped,
+       unsigned long *released)
+{
+       unsigned long pfn;
+       unsigned long i = 0;
+       unsigned long n = end_pfn - start_pfn;
+
+       while (i < n) {
+               unsigned long cur_pfn = start_pfn + i;
+               unsigned long left = n - i;
+               unsigned long size = left;
+               unsigned long remap_range_size;
+
+               /* Do not remap pages beyond the current allocation */
+               if (cur_pfn >= nr_pages) {
+                       /* Identity map remaining pages */
+                       *identity += set_phys_range_identity(cur_pfn,
+                               cur_pfn + size);
+                       break;
+               }
+               if (cur_pfn + size > nr_pages)
+                       size = nr_pages - cur_pfn;
+
+               remap_range_size = xen_find_pfn_range(list, map_size,
+                                                     &remap_pfn);
+               if (!remap_range_size) {
+                       pr_warning("Unable to find available pfn range, not remapping identity pages\n");
+                       xen_set_identity_and_release_chunk(cur_pfn,
+                               cur_pfn + left, nr_pages, identity, released);
+                       break;
+               }
+               /* Adjust size to fit in current e820 RAM region */
+               if (size > remap_range_size)
+                       size = remap_range_size;
+
+               if (!xen_do_set_identity_and_remap_chunk(cur_pfn, size, remap_pfn)) {
+                       WARN(1, "Failed to remap 1:1 memory cur_pfn=%ld size=%ld remap_pfn=%ld\n",
+                               cur_pfn, size, remap_pfn);
+                       xen_set_identity_and_release_chunk(cur_pfn,
+                               cur_pfn + left, nr_pages, identity, released);
+                       break;
+               }
+
+               /* Update variables to reflect new mappings. */
+               i += size;
+               remap_pfn += size;
+               *identity += size;
+               *remapped += size;
+       }
+
+       /*
+        * If the PFNs are currently mapped, the VA mapping also needs
+        * to be updated to be 1:1.
+        */
+       for (pfn = start_pfn; pfn <= max_pfn_mapped && pfn < end_pfn; pfn++)
+               (void)HYPERVISOR_update_va_mapping(
+                       (unsigned long)__va(pfn << PAGE_SHIFT),
+                       mfn_pte(pfn, PAGE_KERNEL_IO), 0);
+
+       return remap_pfn;
+}
+
+static unsigned long __init xen_set_identity_and_remap(
+       const struct e820entry *list, size_t map_size, unsigned long nr_pages,
+       unsigned long *released)
 {
        phys_addr_t start = 0;
-       unsigned long released = 0;
        unsigned long identity = 0;
+       unsigned long remapped = 0;
+       unsigned long last_pfn = nr_pages;
        const struct e820entry *entry;
+       unsigned long num_released = 0;
        int i;
 
        /*
         * Combine non-RAM regions and gaps until a RAM region (or the
         * end of the map) is reached, then set the 1:1 map and
-        * release the pages (if available) in those non-RAM regions.
+        * remap the memory in those non-RAM regions.
         *
         * The combined non-RAM regions are rounded to a whole number
         * of pages so any partial pages are accessible via the 1:1
@@ -269,22 +491,24 @@ static unsigned long __init xen_set_identity_and_release(
                                end_pfn = PFN_UP(entry->addr);
 
                        if (start_pfn < end_pfn)
-                               xen_set_identity_and_release_chunk(
-                                       start_pfn, end_pfn, nr_pages,
-                                       &released, &identity);
-
+                               last_pfn = xen_set_identity_and_remap_chunk(
+                                               list, map_size, start_pfn,
+                                               end_pfn, nr_pages, last_pfn,
+                                               &identity, &remapped,
+                                               &num_released);
                        start = end;
                }
        }
 
-       if (released)
-               printk(KERN_INFO "Released %lu pages of unused memory\n", released);
-       if (identity)
-               printk(KERN_INFO "Set %ld page(s) to 1-1 mapping\n", identity);
+       *released = num_released;
 
-       return released;
-}
+       pr_info("Set %ld page(s) to 1-1 mapping\n", identity);
+       pr_info("Remapped %ld page(s), last_pfn=%ld\n", remapped,
+               last_pfn);
+       pr_info("Released %ld page(s)\n", num_released);
 
+       return last_pfn;
+}
 static unsigned long __init xen_get_max_pages(void)
 {
        unsigned long max_pages = MAX_DOMAIN_PAGES;
@@ -347,7 +571,6 @@ char * __init xen_memory_setup(void)
        unsigned long max_pages;
        unsigned long last_pfn = 0;
        unsigned long extra_pages = 0;
-       unsigned long populated;
        int i;
        int op;
 
@@ -392,20 +615,11 @@ char * __init xen_memory_setup(void)
                extra_pages += max_pages - max_pfn;
 
        /*
-        * Set P2M for all non-RAM pages and E820 gaps to be identity
-        * type PFNs.  Any RAM pages that would be made inaccesible by
-        * this are first released.
+        * Set identity map on non-RAM pages and remap the underlying RAM.
         */
-       xen_released_pages = xen_set_identity_and_release(
-               map, memmap.nr_entries, max_pfn);
-
-       /*
-        * Populate back the non-RAM pages and E820 gaps that had been
-        * released. */
-       populated = xen_populate_chunk(map, memmap.nr_entries,
-                       max_pfn, &last_pfn, xen_released_pages);
+       last_pfn = xen_set_identity_and_remap(map, memmap.nr_entries, max_pfn,
+                                             &xen_released_pages);
 
-       xen_released_pages -= populated;
        extra_pages += xen_released_pages;
 
        if (last_pfn > max_pfn) {
index 7005974c3ff308a2504def1cb035d393ed82693f..8650cdb53209d0f298fa219ac617454cea0fa087 100644 (file)
@@ -37,6 +37,7 @@
 #include <xen/hvc-console.h>
 #include "xen-ops.h"
 #include "mmu.h"
+#include "smp.h"
 
 cpumask_var_t xen_cpu_initialized_map;
 
@@ -99,10 +100,14 @@ static void cpu_bringup(void)
        wmb();                  /* make sure everything is out */
 }
 
-/* Note: cpu parameter is only relevant for PVH */
-static void cpu_bringup_and_idle(int cpu)
+/*
+ * Note: cpu parameter is only relevant for PVH. The reason for passing it
+ * is we can't do smp_processor_id until the percpu segments are loaded, for
+ * which we need the cpu number! So we pass it in rdi as first parameter.
+ */
+asmlinkage __visible void cpu_bringup_and_idle(int cpu)
 {
-#ifdef CONFIG_X86_64
+#ifdef CONFIG_XEN_PVH
        if (xen_feature(XENFEAT_auto_translated_physmap) &&
            xen_feature(XENFEAT_supervisor_mode_kernel))
                xen_pvh_secondary_vcpu_init(cpu);
@@ -360,6 +365,8 @@ cpu_initialize_context(unsigned int cpu, struct task_struct *idle)
        struct desc_struct *gdt;
        unsigned long gdt_mfn;
 
+       /* used to tell cpu_init() that it can proceed with initialization */
+       cpumask_set_cpu(cpu, cpu_callout_mask);
        if (cpumask_test_and_set_cpu(cpu, xen_cpu_initialized_map))
                return 0;
 
@@ -374,11 +381,10 @@ cpu_initialize_context(unsigned int cpu, struct task_struct *idle)
        ctxt->user_regs.fs = __KERNEL_PERCPU;
        ctxt->user_regs.gs = __KERNEL_STACK_CANARY;
 #endif
-       ctxt->user_regs.eip = (unsigned long)cpu_bringup_and_idle;
-
        memset(&ctxt->fpu_ctxt, 0, sizeof(ctxt->fpu_ctxt));
 
        if (!xen_feature(XENFEAT_auto_translated_physmap)) {
+               ctxt->user_regs.eip = (unsigned long)cpu_bringup_and_idle;
                ctxt->flags = VGCF_IN_KERNEL;
                ctxt->user_regs.eflags = 0x1000; /* IOPL_RING1 */
                ctxt->user_regs.ds = __USER_DS;
@@ -413,15 +419,18 @@ cpu_initialize_context(unsigned int cpu, struct task_struct *idle)
                                        (unsigned long)xen_failsafe_callback;
                ctxt->user_regs.cs = __KERNEL_CS;
                per_cpu(xen_cr3, cpu) = __pa(swapper_pg_dir);
-#ifdef CONFIG_X86_32
        }
-#else
-       } else
-               /* N.B. The user_regs.eip (cpu_bringup_and_idle) is called with
-                * %rdi having the cpu number - which means are passing in
-                * as the first parameter the cpu. Subtle!
+#ifdef CONFIG_XEN_PVH
+       else {
+               /*
+                * The vcpu comes on kernel page tables which have the NX pte
+                * bit set. This means before DS/SS is touched, NX in
+                * EFER must be set. Hence the following assembly glue code.
                 */
+               ctxt->user_regs.eip = (unsigned long)xen_pvh_early_cpu_init;
                ctxt->user_regs.rdi = cpu;
+               ctxt->user_regs.rsi = true;  /* entry == true */
+       }
 #endif
        ctxt->user_regs.esp = idle->thread.sp0 - sizeof(struct pt_regs);
        ctxt->ctrlreg[3] = xen_pfn_to_cr3(virt_to_mfn(swapper_pg_dir));
index c7c2d89efd76ac3c7627168b0a3d2f3964627f66..963d62a35c824f69400675b51c2f4dc95e947826 100644 (file)
@@ -8,4 +8,12 @@ extern void xen_send_IPI_allbutself(int vector);
 extern void xen_send_IPI_all(int vector);
 extern void xen_send_IPI_self(int vector);
 
+#ifdef CONFIG_XEN_PVH
+extern void xen_pvh_early_cpu_init(int cpu, bool entry);
+#else
+static inline void xen_pvh_early_cpu_init(int cpu, bool entry)
+{
+}
+#endif
+
 #endif
index 485b69585540dc4fd67eada10d3a4c028aa81394..674b222544b78dde6c3b737a767500e5f19627b3 100644 (file)
@@ -47,6 +47,41 @@ ENTRY(startup_xen)
 
        __FINIT
 
+#ifdef CONFIG_XEN_PVH
+/*
+ * xen_pvh_early_cpu_init() - early PVH VCPU initialization
+ * @cpu:   this cpu number (%rdi)
+ * @entry: true if this is a secondary vcpu coming up on this entry
+ *         point, false if this is the boot CPU being initialized for
+ *         the first time (%rsi)
+ *
+ * Note: This is called as a function on the boot CPU, and is the entry point
+ *       on the secondary CPU.
+ */
+ENTRY(xen_pvh_early_cpu_init)
+       mov     %rsi, %r11
+
+       /* Gather features to see if NX implemented. */
+       mov     $0x80000001, %eax
+       cpuid
+       mov     %edx, %esi
+
+       mov     $MSR_EFER, %ecx
+       rdmsr
+       bts     $_EFER_SCE, %eax
+
+       bt      $20, %esi
+       jnc     1f              /* No NX, skip setting it */
+       bts     $_EFER_NX, %eax
+1:     wrmsr
+#ifdef CONFIG_SMP
+       cmp     $0, %r11b
+       jne     cpu_bringup_and_idle
+#endif
+       ret
+
+#endif /* CONFIG_XEN_PVH */
+
 .pushsection .text
        .balign PAGE_SIZE
 ENTRY(hypercall_page)
@@ -124,6 +159,7 @@ NEXT_HYPERCALL(arch_6)
        ELFNOTE(Xen, XEN_ELFNOTE_L1_MFN_VALID,
                .quad _PAGE_PRESENT; .quad _PAGE_PRESENT)
        ELFNOTE(Xen, XEN_ELFNOTE_SUSPEND_CANCEL, .long 1)
+       ELFNOTE(Xen, XEN_ELFNOTE_MOD_START_PFN,  .long 1)
        ELFNOTE(Xen, XEN_ELFNOTE_HV_START_LOW,   _ASM_PTR __HYPERVISOR_VIRT_START)
        ELFNOTE(Xen, XEN_ELFNOTE_PADDR_OFFSET,   _ASM_PTR 0)
 
index e5103b47a8cefaf98a6e97d5f6bbd987eecb8c91..00b7d46b35b848226cacd90034bc241181d3389c 100644 (file)
@@ -47,7 +47,7 @@
  *
  * Atomically reads the value of @v.
  */
-#define atomic_read(v)         (*(volatile int *)&(v)->counter)
+#define atomic_read(v)         ACCESS_ONCE((v)->counter)
 
 /**
  * atomic_set - set atomic variable
  */
 #define atomic_set(v,i)                ((v)->counter = (i))
 
-/**
- * atomic_add - add integer to atomic variable
- * @i: integer value to add
- * @v: pointer of type atomic_t
- *
- * Atomically adds @i to @v.
- */
-static inline void atomic_add(int i, atomic_t * v)
-{
 #if XCHAL_HAVE_S32C1I
-       unsigned long tmp;
-       int result;
-
-       __asm__ __volatile__(
-                       "1:     l32i    %1, %3, 0\n"
-                       "       wsr     %1, scompare1\n"
-                       "       add     %0, %1, %2\n"
-                       "       s32c1i  %0, %3, 0\n"
-                       "       bne     %0, %1, 1b\n"
-                       : "=&a" (result), "=&a" (tmp)
-                       : "a" (i), "a" (v)
-                       : "memory"
-                       );
-#else
-       unsigned int vval;
-
-       __asm__ __volatile__(
-                       "       rsil    a15, "__stringify(LOCKLEVEL)"\n"
-                       "       l32i    %0, %2, 0\n"
-                       "       add     %0, %0, %1\n"
-                       "       s32i    %0, %2, 0\n"
-                       "       wsr     a15, ps\n"
-                       "       rsync\n"
-                       : "=&a" (vval)
-                       : "a" (i), "a" (v)
-                       : "a15", "memory"
-                       );
-#endif
-}
-
-/**
- * atomic_sub - subtract the atomic variable
- * @i: integer value to subtract
- * @v: pointer of type atomic_t
- *
- * Atomically subtracts @i from @v.
- */
-static inline void atomic_sub(int i, atomic_t *v)
-{
-#if XCHAL_HAVE_S32C1I
-       unsigned long tmp;
-       int result;
-
-       __asm__ __volatile__(
-                       "1:     l32i    %1, %3, 0\n"
-                       "       wsr     %1, scompare1\n"
-                       "       sub     %0, %1, %2\n"
-                       "       s32c1i  %0, %3, 0\n"
-                       "       bne     %0, %1, 1b\n"
-                       : "=&a" (result), "=&a" (tmp)
-                       : "a" (i), "a" (v)
-                       : "memory"
-                       );
-#else
-       unsigned int vval;
-
-       __asm__ __volatile__(
-                       "       rsil    a15, "__stringify(LOCKLEVEL)"\n"
-                       "       l32i    %0, %2, 0\n"
-                       "       sub     %0, %0, %1\n"
-                       "       s32i    %0, %2, 0\n"
-                       "       wsr     a15, ps\n"
-                       "       rsync\n"
-                       : "=&a" (vval)
-                       : "a" (i), "a" (v)
-                       : "a15", "memory"
-                       );
-#endif
+#define ATOMIC_OP(op)                                                  \
+static inline void atomic_##op(int i, atomic_t * v)                    \
+{                                                                      \
+       unsigned long tmp;                                              \
+       int result;                                                     \
+                                                                       \
+       __asm__ __volatile__(                                           \
+                       "1:     l32i    %1, %3, 0\n"                    \
+                       "       wsr     %1, scompare1\n"                \
+                       "       " #op " %0, %1, %2\n"                   \
+                       "       s32c1i  %0, %3, 0\n"                    \
+                       "       bne     %0, %1, 1b\n"                   \
+                       : "=&a" (result), "=&a" (tmp)                   \
+                       : "a" (i), "a" (v)                              \
+                       : "memory"                                      \
+                       );                                              \
+}                                                                      \
+
+#define ATOMIC_OP_RETURN(op)                                           \
+static inline int atomic_##op##_return(int i, atomic_t * v)            \
+{                                                                      \
+       unsigned long tmp;                                              \
+       int result;                                                     \
+                                                                       \
+       __asm__ __volatile__(                                           \
+                       "1:     l32i    %1, %3, 0\n"                    \
+                       "       wsr     %1, scompare1\n"                \
+                       "       " #op " %0, %1, %2\n"                   \
+                       "       s32c1i  %0, %3, 0\n"                    \
+                       "       bne     %0, %1, 1b\n"                   \
+                       "       " #op " %0, %0, %2\n"                   \
+                       : "=&a" (result), "=&a" (tmp)                   \
+                       : "a" (i), "a" (v)                              \
+                       : "memory"                                      \
+                       );                                              \
+                                                                       \
+       return result;                                                  \
 }
 
-/*
- * We use atomic_{add|sub}_return to define other functions.
- */
-
-static inline int atomic_add_return(int i, atomic_t * v)
-{
-#if XCHAL_HAVE_S32C1I
-       unsigned long tmp;
-       int result;
-
-       __asm__ __volatile__(
-                       "1:     l32i    %1, %3, 0\n"
-                       "       wsr     %1, scompare1\n"
-                       "       add     %0, %1, %2\n"
-                       "       s32c1i  %0, %3, 0\n"
-                       "       bne     %0, %1, 1b\n"
-                       "       add     %0, %0, %2\n"
-                       : "=&a" (result), "=&a" (tmp)
-                       : "a" (i), "a" (v)
-                       : "memory"
-                       );
-
-       return result;
-#else
-       unsigned int vval;
-
-       __asm__ __volatile__(
-                       "       rsil    a15,"__stringify(LOCKLEVEL)"\n"
-                       "       l32i    %0, %2, 0\n"
-                       "       add     %0, %0, %1\n"
-                       "       s32i    %0, %2, 0\n"
-                       "       wsr     a15, ps\n"
-                       "       rsync\n"
-                       : "=&a" (vval)
-                       : "a" (i), "a" (v)
-                       : "a15", "memory"
-                       );
-
-       return vval;
-#endif
+#else /* XCHAL_HAVE_S32C1I */
+
+#define ATOMIC_OP(op)                                                  \
+static inline void atomic_##op(int i, atomic_t * v)                    \
+{                                                                      \
+       unsigned int vval;                                              \
+                                                                       \
+       __asm__ __volatile__(                                           \
+                       "       rsil    a15, "__stringify(LOCKLEVEL)"\n"\
+                       "       l32i    %0, %2, 0\n"                    \
+                       "       " #op " %0, %0, %1\n"                   \
+                       "       s32i    %0, %2, 0\n"                    \
+                       "       wsr     a15, ps\n"                      \
+                       "       rsync\n"                                \
+                       : "=&a" (vval)                                  \
+                       : "a" (i), "a" (v)                              \
+                       : "a15", "memory"                               \
+                       );                                              \
+}                                                                      \
+
+#define ATOMIC_OP_RETURN(op)                                           \
+static inline int atomic_##op##_return(int i, atomic_t * v)            \
+{                                                                      \
+       unsigned int vval;                                              \
+                                                                       \
+       __asm__ __volatile__(                                           \
+                       "       rsil    a15,"__stringify(LOCKLEVEL)"\n" \
+                       "       l32i    %0, %2, 0\n"                    \
+                       "       " #op " %0, %0, %1\n"                   \
+                       "       s32i    %0, %2, 0\n"                    \
+                       "       wsr     a15, ps\n"                      \
+                       "       rsync\n"                                \
+                       : "=&a" (vval)                                  \
+                       : "a" (i), "a" (v)                              \
+                       : "a15", "memory"                               \
+                       );                                              \
+                                                                       \
+       return vval;                                                    \
 }
 
-static inline int atomic_sub_return(int i, atomic_t * v)
-{
-#if XCHAL_HAVE_S32C1I
-       unsigned long tmp;
-       int result;
+#endif /* XCHAL_HAVE_S32C1I */
 
-       __asm__ __volatile__(
-                       "1:     l32i    %1, %3, 0\n"
-                       "       wsr     %1, scompare1\n"
-                       "       sub     %0, %1, %2\n"
-                       "       s32c1i  %0, %3, 0\n"
-                       "       bne     %0, %1, 1b\n"
-                       "       sub     %0, %0, %2\n"
-                       : "=&a" (result), "=&a" (tmp)
-                       : "a" (i), "a" (v)
-                       : "memory"
-                       );
+#define ATOMIC_OPS(op) ATOMIC_OP(op) ATOMIC_OP_RETURN(op)
 
-       return result;
-#else
-       unsigned int vval;
-
-       __asm__ __volatile__(
-                       "       rsil    a15,"__stringify(LOCKLEVEL)"\n"
-                       "       l32i    %0, %2, 0\n"
-                       "       sub     %0, %0, %1\n"
-                       "       s32i    %0, %2, 0\n"
-                       "       wsr     a15, ps\n"
-                       "       rsync\n"
-                       : "=&a" (vval)
-                       : "a" (i), "a" (v)
-                       : "a15", "memory"
-                       );
+ATOMIC_OPS(add)
+ATOMIC_OPS(sub)
 
-       return vval;
-#endif
-}
+#undef ATOMIC_OPS
+#undef ATOMIC_OP_RETURN
+#undef ATOMIC_OP
 
 /**
  * atomic_sub_and_test - subtract value from variable and test result
index a63c551c65570006ef2281ad2dc3ad6b70622482..f97330886d587527c7211acb5d41831f382530f0 100644 (file)
@@ -9,9 +9,10 @@
  * 2 of the Licence, or (at your option) any later version.
  */
 
-int asymmetric_keyid_match(const char *kid, const char *id);
+extern struct asymmetric_key_id *asymmetric_key_hex_to_key_id(const char *id);
 
-static inline const char *asymmetric_key_id(const struct key *key)
+static inline
+const struct asymmetric_key_ids *asymmetric_key_ids(const struct key *key)
 {
        return key->type_data.p[1];
 }
index eb8cd46961a5aa5a6a7470c6d17008d1745bbdf6..bcbbbd794e1da209d519baca7de8b0ddf1115716 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/seq_file.h>
 #include <linux/module.h>
 #include <linux/slab.h>
+#include <linux/ctype.h>
 #include "asymmetric_keys.h"
 
 MODULE_LICENSE("GPL");
@@ -22,85 +23,209 @@ MODULE_LICENSE("GPL");
 static LIST_HEAD(asymmetric_key_parsers);
 static DECLARE_RWSEM(asymmetric_key_parsers_sem);
 
-/*
- * Match asymmetric key id with partial match
- * @id:                key id to match in a form "id:<id>"
+/**
+ * asymmetric_key_generate_id: Construct an asymmetric key ID
+ * @val_1: First binary blob
+ * @len_1: Length of first binary blob
+ * @val_2: Second binary blob
+ * @len_2: Length of second binary blob
+ *
+ * Construct an asymmetric key ID from a pair of binary blobs.
  */
-int asymmetric_keyid_match(const char *kid, const char *id)
+struct asymmetric_key_id *asymmetric_key_generate_id(const void *val_1,
+                                                    size_t len_1,
+                                                    const void *val_2,
+                                                    size_t len_2)
 {
-       size_t idlen, kidlen;
+       struct asymmetric_key_id *kid;
+
+       kid = kmalloc(sizeof(struct asymmetric_key_id) + len_1 + len_2,
+                     GFP_KERNEL);
+       if (!kid)
+               return ERR_PTR(-ENOMEM);
+       kid->len = len_1 + len_2;
+       memcpy(kid->data, val_1, len_1);
+       memcpy(kid->data + len_1, val_2, len_2);
+       return kid;
+}
+EXPORT_SYMBOL_GPL(asymmetric_key_generate_id);
 
-       if (!kid || !id)
-               return 0;
+/**
+ * asymmetric_key_id_same - Return true if two asymmetric keys IDs are the same.
+ * @kid_1, @kid_2: The key IDs to compare
+ */
+bool asymmetric_key_id_same(const struct asymmetric_key_id *kid1,
+                           const struct asymmetric_key_id *kid2)
+{
+       if (!kid1 || !kid2)
+               return false;
+       if (kid1->len != kid2->len)
+               return false;
+       return memcmp(kid1->data, kid2->data, kid1->len) == 0;
+}
+EXPORT_SYMBOL_GPL(asymmetric_key_id_same);
 
-       /* make it possible to use id as in the request: "id:<id>" */
-       if (strncmp(id, "id:", 3) == 0)
-               id += 3;
+/**
+ * asymmetric_key_id_partial - Return true if two asymmetric keys IDs
+ * partially match
+ * @kid_1, @kid_2: The key IDs to compare
+ */
+bool asymmetric_key_id_partial(const struct asymmetric_key_id *kid1,
+                              const struct asymmetric_key_id *kid2)
+{
+       if (!kid1 || !kid2)
+               return false;
+       if (kid1->len < kid2->len)
+               return false;
+       return memcmp(kid1->data + (kid1->len - kid2->len),
+                     kid2->data, kid2->len) == 0;
+}
+EXPORT_SYMBOL_GPL(asymmetric_key_id_partial);
 
-       /* Anything after here requires a partial match on the ID string */
-       idlen = strlen(id);
-       kidlen = strlen(kid);
-       if (idlen > kidlen)
-               return 0;
+/**
+ * asymmetric_match_key_ids - Search asymmetric key IDs
+ * @kids: The list of key IDs to check
+ * @match_id: The key ID we're looking for
+ * @match: The match function to use
+ */
+static bool asymmetric_match_key_ids(
+       const struct asymmetric_key_ids *kids,
+       const struct asymmetric_key_id *match_id,
+       bool (*match)(const struct asymmetric_key_id *kid1,
+                     const struct asymmetric_key_id *kid2))
+{
+       int i;
+
+       if (!kids || !match_id)
+               return false;
+       for (i = 0; i < ARRAY_SIZE(kids->id); i++)
+               if (match(kids->id[i], match_id))
+                       return true;
+       return false;
+}
 
-       kid += kidlen - idlen;
-       if (strcasecmp(id, kid) != 0)
-               return 0;
+/**
+ * asymmetric_key_hex_to_key_id - Convert a hex string into a key ID.
+ * @id: The ID as a hex string.
+ */
+struct asymmetric_key_id *asymmetric_key_hex_to_key_id(const char *id)
+{
+       struct asymmetric_key_id *match_id;
+       size_t hexlen;
+       int ret;
 
-       return 1;
+       if (!*id)
+               return ERR_PTR(-EINVAL);
+       hexlen = strlen(id);
+       if (hexlen & 1)
+               return ERR_PTR(-EINVAL);
+
+       match_id = kmalloc(sizeof(struct asymmetric_key_id) + hexlen / 2,
+                          GFP_KERNEL);
+       if (!match_id)
+               return ERR_PTR(-ENOMEM);
+       match_id->len = hexlen / 2;
+       ret = hex2bin(match_id->data, id, hexlen / 2);
+       if (ret < 0) {
+               kfree(match_id);
+               return ERR_PTR(-EINVAL);
+       }
+       return match_id;
 }
-EXPORT_SYMBOL_GPL(asymmetric_keyid_match);
 
 /*
- * Match asymmetric keys on (part of) their name
- * We have some shorthand methods for matching keys.  We allow:
- *
- *     "<desc>"        - request a key by description
- *     "id:<id>"       - request a key matching the ID
- *     "<subtype>:<id>" - request a key of a subtype
+ * Match asymmetric keys by an exact match on an ID.
  */
-static int asymmetric_key_match(const struct key *key, const void *description)
+static bool asymmetric_key_cmp(const struct key *key,
+                              const struct key_match_data *match_data)
 {
-       const struct asymmetric_key_subtype *subtype = asymmetric_key_subtype(key);
-       const char *spec = description;
-       const char *id;
-       ptrdiff_t speclen;
+       const struct asymmetric_key_ids *kids = asymmetric_key_ids(key);
+       const struct asymmetric_key_id *match_id = match_data->preparsed;
 
-       if (!subtype || !spec || !*spec)
-               return 0;
+       return asymmetric_match_key_ids(kids, match_id,
+                                       asymmetric_key_id_same);
+}
 
-       /* See if the full key description matches as is */
-       if (key->description && strcmp(key->description, description) == 0)
-               return 1;
+/*
+ * Match asymmetric keys by a partial match on an IDs.
+ */
+static bool asymmetric_key_cmp_partial(const struct key *key,
+                                      const struct key_match_data *match_data)
+{
+       const struct asymmetric_key_ids *kids = asymmetric_key_ids(key);
+       const struct asymmetric_key_id *match_id = match_data->preparsed;
 
-       /* All tests from here on break the criterion description into a
-        * specifier, a colon and then an identifier.
-        */
-       id = strchr(spec, ':');
-       if (!id)
-               return 0;
+       return asymmetric_match_key_ids(kids, match_id,
+                                       asymmetric_key_id_partial);
+}
+
+/*
+ * Preparse the match criterion.  If we don't set lookup_type and cmp,
+ * the default will be an exact match on the key description.
+ *
+ * There are some specifiers for matching key IDs rather than by the key
+ * description:
+ *
+ *     "id:<id>" - find a key by partial match on any available ID
+ *     "ex:<id>" - find a key by exact match on any available ID
+ *
+ * These have to be searched by iteration rather than by direct lookup because
+ * the key is hashed according to its description.
+ */
+static int asymmetric_key_match_preparse(struct key_match_data *match_data)
+{
+       struct asymmetric_key_id *match_id;
+       const char *spec = match_data->raw_data;
+       const char *id;
+       bool (*cmp)(const struct key *, const struct key_match_data *) =
+               asymmetric_key_cmp;
 
-       speclen = id - spec;
-       id++;
+       if (!spec || !*spec)
+               return -EINVAL;
+       if (spec[0] == 'i' &&
+           spec[1] == 'd' &&
+           spec[2] == ':') {
+               id = spec + 3;
+               cmp = asymmetric_key_cmp_partial;
+       } else if (spec[0] == 'e' &&
+                  spec[1] == 'x' &&
+                  spec[2] == ':') {
+               id = spec + 3;
+       } else {
+               goto default_match;
+       }
 
-       if (speclen == 2 && memcmp(spec, "id", 2) == 0)
-               return asymmetric_keyid_match(asymmetric_key_id(key), id);
+       match_id = asymmetric_key_hex_to_key_id(id);
+       if (IS_ERR(match_id))
+               return PTR_ERR(match_id);
 
-       if (speclen == subtype->name_len &&
-           memcmp(spec, subtype->name, speclen) == 0)
-               return 1;
+       match_data->preparsed = match_id;
+       match_data->cmp = cmp;
+       match_data->lookup_type = KEYRING_SEARCH_LOOKUP_ITERATE;
+       return 0;
 
+default_match:
        return 0;
 }
 
+/*
+ * Free the preparsed the match criterion.
+ */
+static void asymmetric_key_match_free(struct key_match_data *match_data)
+{
+       kfree(match_data->preparsed);
+}
+
 /*
  * Describe the asymmetric key
  */
 static void asymmetric_key_describe(const struct key *key, struct seq_file *m)
 {
        const struct asymmetric_key_subtype *subtype = asymmetric_key_subtype(key);
-       const char *kid = asymmetric_key_id(key);
-       size_t n;
+       const struct asymmetric_key_ids *kids = asymmetric_key_ids(key);
+       const struct asymmetric_key_id *kid;
+       const unsigned char *p;
+       int n;
 
        seq_puts(m, key->description);
 
@@ -108,13 +233,16 @@ static void asymmetric_key_describe(const struct key *key, struct seq_file *m)
                seq_puts(m, ": ");
                subtype->describe(key, m);
 
-               if (kid) {
+               if (kids && kids->id[1]) {
+                       kid = kids->id[1];
                        seq_putc(m, ' ');
-                       n = strlen(kid);
-                       if (n <= 8)
-                               seq_puts(m, kid);
-                       else
-                               seq_puts(m, kid + n - 8);
+                       n = kid->len;
+                       p = kid->data;
+                       if (n > 4) {
+                               p += n - 4;
+                               n = 4;
+                       }
+                       seq_printf(m, "%*phN", n, p);
                }
 
                seq_puts(m, " [");
@@ -165,6 +293,8 @@ static int asymmetric_key_preparse(struct key_preparsed_payload *prep)
 static void asymmetric_key_free_preparse(struct key_preparsed_payload *prep)
 {
        struct asymmetric_key_subtype *subtype = prep->type_data[0];
+       struct asymmetric_key_ids *kids = prep->type_data[1];
+       int i;
 
        pr_devel("==>%s()\n", __func__);
 
@@ -172,7 +302,11 @@ static void asymmetric_key_free_preparse(struct key_preparsed_payload *prep)
                subtype->destroy(prep->payload[0]);
                module_put(subtype->owner);
        }
-       kfree(prep->type_data[1]);
+       if (kids) {
+               for (i = 0; i < ARRAY_SIZE(kids->id); i++)
+                       kfree(kids->id[i]);
+               kfree(kids);
+       }
        kfree(prep->description);
 }
 
@@ -182,13 +316,20 @@ static void asymmetric_key_free_preparse(struct key_preparsed_payload *prep)
 static void asymmetric_key_destroy(struct key *key)
 {
        struct asymmetric_key_subtype *subtype = asymmetric_key_subtype(key);
+       struct asymmetric_key_ids *kids = key->type_data.p[1];
+
        if (subtype) {
                subtype->destroy(key->payload.data);
                module_put(subtype->owner);
                key->type_data.p[0] = NULL;
        }
-       kfree(key->type_data.p[1]);
-       key->type_data.p[1] = NULL;
+
+       if (kids) {
+               kfree(kids->id[0]);
+               kfree(kids->id[1]);
+               kfree(kids);
+               key->type_data.p[1] = NULL;
+       }
 }
 
 struct key_type key_type_asymmetric = {
@@ -196,10 +337,10 @@ struct key_type key_type_asymmetric = {
        .preparse       = asymmetric_key_preparse,
        .free_preparse  = asymmetric_key_free_preparse,
        .instantiate    = generic_key_instantiate,
-       .match          = asymmetric_key_match,
+       .match_preparse = asymmetric_key_match_preparse,
+       .match_free     = asymmetric_key_match_free,
        .destroy        = asymmetric_key_destroy,
        .describe       = asymmetric_key_describe,
-       .def_lookup_type = KEYRING_SEARCH_LOOKUP_ITERATE,
 };
 EXPORT_SYMBOL_GPL(key_type_asymmetric);
 
index 3de5fb011de0b3b64e0dfde2b2c6d17c631dd3d1..751f8fd7335db2203f7257edc8ad680dc7ea2a14 100644 (file)
@@ -72,11 +72,9 @@ error:
  */
 static struct key_type key_type_pkcs7 = {
        .name                   = "pkcs7_test",
-       .def_lookup_type        = KEYRING_SEARCH_LOOKUP_DIRECT,
        .preparse               = pkcs7_preparse,
        .free_preparse          = user_free_preparse,
        .instantiate            = generic_key_instantiate,
-       .match                  = user_match,
        .revoke                 = user_revoke,
        .destroy                = user_destroy,
        .describe               = user_describe,
index 42e56aa7d277ef5236f8c3192f064c0a48d59a60..3bd5a1e4c493e23a78835cb82ff7623fa21fa6c2 100644 (file)
@@ -29,8 +29,25 @@ struct pkcs7_parse_context {
        enum OID        last_oid;               /* Last OID encountered */
        unsigned        x509_index;
        unsigned        sinfo_index;
+       const void      *raw_serial;
+       unsigned        raw_serial_size;
+       unsigned        raw_issuer_size;
+       const void      *raw_issuer;
 };
 
+/*
+ * Free a signed information block.
+ */
+static void pkcs7_free_signed_info(struct pkcs7_signed_info *sinfo)
+{
+       if (sinfo) {
+               mpi_free(sinfo->sig.mpi[0]);
+               kfree(sinfo->sig.digest);
+               kfree(sinfo->signing_cert_id);
+               kfree(sinfo);
+       }
+}
+
 /**
  * pkcs7_free_message - Free a PKCS#7 message
  * @pkcs7: The PKCS#7 message to free
@@ -54,9 +71,7 @@ void pkcs7_free_message(struct pkcs7_message *pkcs7)
                while (pkcs7->signed_infos) {
                        sinfo = pkcs7->signed_infos;
                        pkcs7->signed_infos = sinfo->next;
-                       mpi_free(sinfo->sig.mpi[0]);
-                       kfree(sinfo->sig.digest);
-                       kfree(sinfo);
+                       pkcs7_free_signed_info(sinfo);
                }
                kfree(pkcs7);
        }
@@ -71,51 +86,46 @@ EXPORT_SYMBOL_GPL(pkcs7_free_message);
 struct pkcs7_message *pkcs7_parse_message(const void *data, size_t datalen)
 {
        struct pkcs7_parse_context *ctx;
-       struct pkcs7_message *msg;
-       long ret;
+       struct pkcs7_message *msg = ERR_PTR(-ENOMEM);
+       int ret;
 
-       ret = -ENOMEM;
-       msg = kzalloc(sizeof(struct pkcs7_message), GFP_KERNEL);
-       if (!msg)
-               goto error_no_sig;
        ctx = kzalloc(sizeof(struct pkcs7_parse_context), GFP_KERNEL);
        if (!ctx)
-               goto error_no_ctx;
+               goto out_no_ctx;
+       ctx->msg = kzalloc(sizeof(struct pkcs7_message), GFP_KERNEL);
+       if (!ctx->msg)
+               goto out_no_msg;
        ctx->sinfo = kzalloc(sizeof(struct pkcs7_signed_info), GFP_KERNEL);
        if (!ctx->sinfo)
-               goto error_no_sinfo;
+               goto out_no_sinfo;
 
-       ctx->msg = msg;
        ctx->data = (unsigned long)data;
        ctx->ppcerts = &ctx->certs;
        ctx->ppsinfo = &ctx->msg->signed_infos;
 
        /* Attempt to decode the signature */
        ret = asn1_ber_decoder(&pkcs7_decoder, ctx, data, datalen);
-       if (ret < 0)
-               goto error_decode;
+       if (ret < 0) {
+               msg = ERR_PTR(ret);
+               goto out;
+       }
 
+       msg = ctx->msg;
+       ctx->msg = NULL;
+
+out:
        while (ctx->certs) {
                struct x509_certificate *cert = ctx->certs;
                ctx->certs = cert->next;
                x509_free_certificate(cert);
        }
-       mpi_free(ctx->sinfo->sig.mpi[0]);
-       kfree(ctx->sinfo->sig.digest);
-       kfree(ctx->sinfo);
+       pkcs7_free_signed_info(ctx->sinfo);
+out_no_sinfo:
+       pkcs7_free_message(ctx->msg);
+out_no_msg:
        kfree(ctx);
+out_no_ctx:
        return msg;
-
-error_decode:
-       mpi_free(ctx->sinfo->sig.mpi[0]);
-       kfree(ctx->sinfo->sig.digest);
-       kfree(ctx->sinfo);
-error_no_sinfo:
-       kfree(ctx);
-error_no_ctx:
-       pkcs7_free_message(msg);
-error_no_sig:
-       return ERR_PTR(ret);
 }
 EXPORT_SYMBOL_GPL(pkcs7_parse_message);
 
@@ -246,10 +256,10 @@ int pkcs7_extract_cert(void *context, size_t hdrlen,
        if (IS_ERR(x509))
                return PTR_ERR(x509);
 
-       pr_debug("Got cert for %s\n", x509->subject);
-       pr_debug("- fingerprint %s\n", x509->fingerprint);
-
        x509->index = ++ctx->x509_index;
+       pr_debug("Got cert %u for %s\n", x509->index, x509->subject);
+       pr_debug("- fingerprint %*phN\n", x509->id->len, x509->id->data);
+
        *ctx->ppcerts = x509;
        ctx->ppcerts = &x509->next;
        return 0;
@@ -338,8 +348,8 @@ int pkcs7_sig_note_serial(void *context, size_t hdrlen,
                          const void *value, size_t vlen)
 {
        struct pkcs7_parse_context *ctx = context;
-       ctx->sinfo->raw_serial = value;
-       ctx->sinfo->raw_serial_size = vlen;
+       ctx->raw_serial = value;
+       ctx->raw_serial_size = vlen;
        return 0;
 }
 
@@ -351,8 +361,8 @@ int pkcs7_sig_note_issuer(void *context, size_t hdrlen,
                          const void *value, size_t vlen)
 {
        struct pkcs7_parse_context *ctx = context;
-       ctx->sinfo->raw_issuer = value;
-       ctx->sinfo->raw_issuer_size = vlen;
+       ctx->raw_issuer = value;
+       ctx->raw_issuer_size = vlen;
        return 0;
 }
 
@@ -385,10 +395,21 @@ int pkcs7_note_signed_info(void *context, size_t hdrlen,
                           const void *value, size_t vlen)
 {
        struct pkcs7_parse_context *ctx = context;
-
-       ctx->sinfo->index = ++ctx->sinfo_index;
-       *ctx->ppsinfo = ctx->sinfo;
-       ctx->ppsinfo = &ctx->sinfo->next;
+       struct pkcs7_signed_info *sinfo = ctx->sinfo;
+       struct asymmetric_key_id *kid;
+
+       /* Generate cert issuer + serial number key ID */
+       kid = asymmetric_key_generate_id(ctx->raw_serial,
+                                        ctx->raw_serial_size,
+                                        ctx->raw_issuer,
+                                        ctx->raw_issuer_size);
+       if (IS_ERR(kid))
+               return PTR_ERR(kid);
+
+       sinfo->signing_cert_id = kid;
+       sinfo->index = ++ctx->sinfo_index;
+       *ctx->ppsinfo = sinfo;
+       ctx->ppsinfo = &sinfo->next;
        ctx->sinfo = kzalloc(sizeof(struct pkcs7_signed_info), GFP_KERNEL);
        if (!ctx->sinfo)
                return -ENOMEM;
index d25f4d15370fff5634ac87bdef71cca0f9a3e581..efc7dc9b8f9cfbc2ac9223e141239efb43bd60ae 100644 (file)
@@ -23,6 +23,7 @@ struct pkcs7_signed_info {
        struct x509_certificate *signer; /* Signing certificate (in msg->certs) */
        unsigned index;
        bool trusted;
+       bool unsupported_crypto;        /* T if not usable due to missing crypto */
 
        /* Message digest - the digest of the Content Data (or NULL) */
        const void      *msgdigest;
@@ -33,10 +34,7 @@ struct pkcs7_signed_info {
        const void      *authattrs;
 
        /* Issuing cert serial number and issuer's name */
-       const void      *raw_serial;
-       unsigned        raw_serial_size;
-       unsigned        raw_issuer_size;
-       const void      *raw_issuer;
+       struct asymmetric_key_id *signing_cert_id;
 
        /* Message signature.
         *
index e666eb011a85f276c2410926766a3bd93e87b945..1d29376072da4a502e720fe10fc8fb34f6c4749a 100644 (file)
@@ -23,9 +23,9 @@
 /**
  * Check the trust on one PKCS#7 SignedInfo block.
  */
-int pkcs7_validate_trust_one(struct pkcs7_message *pkcs7,
-                            struct pkcs7_signed_info *sinfo,
-                            struct key *trust_keyring)
+static int pkcs7_validate_trust_one(struct pkcs7_message *pkcs7,
+                                   struct pkcs7_signed_info *sinfo,
+                                   struct key *trust_keyring)
 {
        struct public_key_signature *sig = &sinfo->sig;
        struct x509_certificate *x509, *last = NULL, *p;
@@ -35,6 +35,11 @@ int pkcs7_validate_trust_one(struct pkcs7_message *pkcs7,
 
        kenter(",%u,", sinfo->index);
 
+       if (sinfo->unsupported_crypto) {
+               kleave(" = -ENOPKG [cached]");
+               return -ENOPKG;
+       }
+
        for (x509 = sinfo->signer; x509; x509 = x509->signer) {
                if (x509->seen) {
                        if (x509->verified) {
@@ -49,15 +54,18 @@ int pkcs7_validate_trust_one(struct pkcs7_message *pkcs7,
                /* Look to see if this certificate is present in the trusted
                 * keys.
                 */
-               key = x509_request_asymmetric_key(trust_keyring, x509->subject,
-                                                 x509->fingerprint);
-               if (!IS_ERR(key))
+               key = x509_request_asymmetric_key(trust_keyring, x509->id,
+                                                 false);
+               if (!IS_ERR(key)) {
                        /* One of the X.509 certificates in the PKCS#7 message
                         * is apparently the same as one we already trust.
                         * Verify that the trusted variant can also validate
                         * the signature on the descendant.
                         */
+                       pr_devel("sinfo %u: Cert %u as key %x\n",
+                                sinfo->index, x509->index, key_serial(key));
                        goto matched;
+               }
                if (key == ERR_PTR(-ENOMEM))
                        return -ENOMEM;
 
@@ -77,16 +85,36 @@ int pkcs7_validate_trust_one(struct pkcs7_message *pkcs7,
        /* No match - see if the root certificate has a signer amongst the
         * trusted keys.
         */
-       if (!last || !last->issuer || !last->authority) {
-               kleave(" = -ENOKEY [no backref]");
-               return -ENOKEY;
+       if (last && last->authority) {
+               key = x509_request_asymmetric_key(trust_keyring, last->authority,
+                                                 false);
+               if (!IS_ERR(key)) {
+                       x509 = last;
+                       pr_devel("sinfo %u: Root cert %u signer is key %x\n",
+                                sinfo->index, x509->index, key_serial(key));
+                       goto matched;
+               }
+               if (PTR_ERR(key) != -ENOKEY)
+                       return PTR_ERR(key);
+       }
+
+       /* As a last resort, see if we have a trusted public key that matches
+        * the signed info directly.
+        */
+       key = x509_request_asymmetric_key(trust_keyring,
+                                         sinfo->signing_cert_id,
+                                         false);
+       if (!IS_ERR(key)) {
+               pr_devel("sinfo %u: Direct signer is key %x\n",
+                        sinfo->index, key_serial(key));
+               x509 = NULL;
+               goto matched;
        }
+       if (PTR_ERR(key) != -ENOKEY)
+               return PTR_ERR(key);
 
-       key = x509_request_asymmetric_key(trust_keyring, last->issuer,
-                                         last->authority);
-       if (IS_ERR(key))
-               return PTR_ERR(key) == -ENOMEM ? -ENOMEM : -ENOKEY;
-       x509 = last;
+       kleave(" = -ENOKEY [no backref]");
+       return -ENOKEY;
 
 matched:
        ret = verify_signature(key, sig);
@@ -100,10 +128,12 @@ matched:
        }
 
 verified:
-       x509->verified = true;
-       for (p = sinfo->signer; p != x509; p = p->signer) {
-               p->verified = true;
-               p->trusted = trusted;
+       if (x509) {
+               x509->verified = true;
+               for (p = sinfo->signer; p != x509; p = p->signer) {
+                       p->verified = true;
+                       p->trusted = trusted;
+               }
        }
        sinfo->trusted = trusted;
        kleave(" = 0");
@@ -141,24 +171,28 @@ int pkcs7_validate_trust(struct pkcs7_message *pkcs7,
 {
        struct pkcs7_signed_info *sinfo;
        struct x509_certificate *p;
-       int cached_ret = 0, ret;
+       int cached_ret = -ENOKEY;
+       int ret;
 
        for (p = pkcs7->certs; p; p = p->next)
                p->seen = false;
 
        for (sinfo = pkcs7->signed_infos; sinfo; sinfo = sinfo->next) {
                ret = pkcs7_validate_trust_one(pkcs7, sinfo, trust_keyring);
-               if (ret < 0) {
-                       if (ret == -ENOPKG) {
+               switch (ret) {
+               case -ENOKEY:
+                       continue;
+               case -ENOPKG:
+                       if (cached_ret == -ENOKEY)
                                cached_ret = -ENOPKG;
-                       } else if (ret == -ENOKEY) {
-                               if (cached_ret == 0)
-                                       cached_ret = -ENOKEY;
-                       } else {
-                               return ret;
-                       }
+                       continue;
+               case 0:
+                       *_trusted |= sinfo->trusted;
+                       cached_ret = 0;
+                       continue;
+               default:
+                       return ret;
                }
-               *_trusted |= sinfo->trusted;
        }
 
        return cached_ret;
index c62cf8006e1f4e8d160e7cc6423b31d318ed58cc..cd455450b069e3c58d1a202484e3ccba2d5d7da1 100644 (file)
@@ -131,8 +131,7 @@ static int pkcs7_find_key(struct pkcs7_message *pkcs7,
        struct x509_certificate *x509;
        unsigned certix = 1;
 
-       kenter("%u,%u,%u",
-              sinfo->index, sinfo->raw_serial_size, sinfo->raw_issuer_size);
+       kenter("%u", sinfo->index);
 
        for (x509 = pkcs7->certs; x509; x509 = x509->next, certix++) {
                /* I'm _assuming_ that the generator of the PKCS#7 message will
@@ -140,21 +139,11 @@ static int pkcs7_find_key(struct pkcs7_message *pkcs7,
                 * PKCS#7 message - but I can't be 100% sure of that.  It's
                 * possible this will need element-by-element comparison.
                 */
-               if (x509->raw_serial_size != sinfo->raw_serial_size ||
-                   memcmp(x509->raw_serial, sinfo->raw_serial,
-                          sinfo->raw_serial_size) != 0)
+               if (!asymmetric_key_id_same(x509->id, sinfo->signing_cert_id))
                        continue;
                pr_devel("Sig %u: Found cert serial match X.509[%u]\n",
                         sinfo->index, certix);
 
-               if (x509->raw_issuer_size != sinfo->raw_issuer_size ||
-                   memcmp(x509->raw_issuer, sinfo->raw_issuer,
-                          sinfo->raw_issuer_size) != 0) {
-                       pr_warn("Sig %u: X.509 subject and PKCS#7 issuer don't match\n",
-                               sinfo->index);
-                       continue;
-               }
-
                if (x509->pub->pkey_algo != sinfo->sig.pkey_algo) {
                        pr_warn("Sig %u: X.509 algo and PKCS#7 sig algo don't match\n",
                                sinfo->index);
@@ -164,9 +153,14 @@ static int pkcs7_find_key(struct pkcs7_message *pkcs7,
                sinfo->signer = x509;
                return 0;
        }
-       pr_warn("Sig %u: Issuing X.509 cert not found (#%*ph)\n",
-               sinfo->index, sinfo->raw_serial_size, sinfo->raw_serial);
-       return -ENOKEY;
+
+       /* The relevant X.509 cert isn't found here, but it might be found in
+        * the trust keyring.
+        */
+       pr_debug("Sig %u: Issuing X.509 cert not found (#%*phN)\n",
+                sinfo->index,
+                sinfo->signing_cert_id->len, sinfo->signing_cert_id->data);
+       return 0;
 }
 
 /*
@@ -184,15 +178,18 @@ static int pkcs7_verify_sig_chain(struct pkcs7_message *pkcs7,
                p->seen = false;
 
        for (;;) {
-               pr_debug("verify %s: %s\n", x509->subject, x509->fingerprint);
+               pr_debug("verify %s: %*phN\n",
+                        x509->subject,
+                        x509->raw_serial_size, x509->raw_serial);
                x509->seen = true;
                ret = x509_get_sig_params(x509);
                if (ret < 0)
-                       return ret;
+                       goto maybe_missing_crypto_in_x509;
 
                pr_debug("- issuer %s\n", x509->issuer);
                if (x509->authority)
-                       pr_debug("- authkeyid %s\n", x509->authority);
+                       pr_debug("- authkeyid %*phN\n",
+                                x509->authority->len, x509->authority->data);
 
                if (!x509->authority ||
                    strcmp(x509->subject, x509->issuer) == 0) {
@@ -209,7 +206,7 @@ static int pkcs7_verify_sig_chain(struct pkcs7_message *pkcs7,
 
                        ret = x509_check_signature(x509->pub, x509);
                        if (ret < 0)
-                               return ret;
+                               goto maybe_missing_crypto_in_x509;
                        x509->signer = x509;
                        pr_debug("- self-signed\n");
                        return 0;
@@ -218,13 +215,14 @@ static int pkcs7_verify_sig_chain(struct pkcs7_message *pkcs7,
                /* Look through the X.509 certificates in the PKCS#7 message's
                 * list to see if the next one is there.
                 */
-               pr_debug("- want %s\n", x509->authority);
+               pr_debug("- want %*phN\n",
+                        x509->authority->len, x509->authority->data);
                for (p = pkcs7->certs; p; p = p->next) {
-                       pr_debug("- cmp [%u] %s\n", p->index, p->fingerprint);
-                       if (p->raw_subject_size == x509->raw_issuer_size &&
-                           strcmp(p->fingerprint, x509->authority) == 0 &&
-                           memcmp(p->raw_subject, x509->raw_issuer,
-                                  x509->raw_issuer_size) == 0)
+                       if (!p->skid)
+                               continue;
+                       pr_debug("- cmp [%u] %*phN\n",
+                                p->index, p->skid->len, p->skid->data);
+                       if (asymmetric_key_id_same(p->skid, x509->authority))
                                goto found_issuer;
                }
 
@@ -233,7 +231,7 @@ static int pkcs7_verify_sig_chain(struct pkcs7_message *pkcs7,
                return 0;
 
        found_issuer:
-               pr_debug("- issuer %s\n", p->subject);
+               pr_debug("- subject %s\n", p->subject);
                if (p->seen) {
                        pr_warn("Sig %u: X.509 chain contains loop\n",
                                sinfo->index);
@@ -250,6 +248,17 @@ static int pkcs7_verify_sig_chain(struct pkcs7_message *pkcs7,
                x509 = p;
                might_sleep();
        }
+
+maybe_missing_crypto_in_x509:
+       /* Just prune the certificate chain at this point if we lack some
+        * crypto module to go further.  Note, however, we don't want to set
+        * sinfo->missing_crypto as the signed info block may still be
+        * validatable against an X.509 cert lower in the chain that we have a
+        * trusted copy of.
+        */
+       if (ret == -ENOPKG)
+               return 0;
+       return ret;
 }
 
 /*
@@ -269,11 +278,14 @@ static int pkcs7_verify_one(struct pkcs7_message *pkcs7,
        if (ret < 0)
                return ret;
 
-       /* Find the key for the signature */
+       /* Find the key for the signature if there is one */
        ret = pkcs7_find_key(pkcs7, sinfo);
        if (ret < 0)
                return ret;
 
+       if (!sinfo->signer)
+               return 0;
+
        pr_devel("Using X.509[%u] for sig %u\n",
                 sinfo->signer->index, sinfo->index);
 
@@ -291,11 +303,33 @@ static int pkcs7_verify_one(struct pkcs7_message *pkcs7,
 /**
  * pkcs7_verify - Verify a PKCS#7 message
  * @pkcs7: The PKCS#7 message to be verified
+ *
+ * Verify a PKCS#7 message is internally consistent - that is, the data digest
+ * matches the digest in the AuthAttrs and any signature in the message or one
+ * of the X.509 certificates it carries that matches another X.509 cert in the
+ * message can be verified.
+ *
+ * This does not look to match the contents of the PKCS#7 message against any
+ * external public keys.
+ *
+ * Returns, in order of descending priority:
+ *
+ *  (*) -EKEYREJECTED if a signature failed to match for which we found an
+ *     appropriate X.509 certificate, or:
+ *
+ *  (*) -EBADMSG if some part of the message was invalid, or:
+ *
+ *  (*) -ENOPKG if none of the signature chains are verifiable because suitable
+ *     crypto modules couldn't be found, or:
+ *
+ *  (*) 0 if all the signature chains that don't incur -ENOPKG can be verified
+ *     (note that a signature chain may be of zero length), or:
  */
 int pkcs7_verify(struct pkcs7_message *pkcs7)
 {
        struct pkcs7_signed_info *sinfo;
        struct x509_certificate *x509;
+       int enopkg = -ENOPKG;
        int ret, n;
 
        kenter("");
@@ -304,18 +338,24 @@ int pkcs7_verify(struct pkcs7_message *pkcs7)
                ret = x509_get_sig_params(x509);
                if (ret < 0)
                        return ret;
-               pr_debug("X.509[%u] %s\n", n, x509->authority);
+               pr_debug("X.509[%u] %*phN\n",
+                        n, x509->authority->len, x509->authority->data);
        }
 
        for (sinfo = pkcs7->signed_infos; sinfo; sinfo = sinfo->next) {
                ret = pkcs7_verify_one(pkcs7, sinfo);
                if (ret < 0) {
+                       if (ret == -ENOPKG) {
+                               sinfo->unsupported_crypto = true;
+                               continue;
+                       }
                        kleave(" = %d", ret);
                        return ret;
                }
+               enopkg = 0;
        }
 
-       kleave(" = 0");
-       return 0;
+       kleave(" = %d", enopkg);
+       return enopkg;
 }
 EXPORT_SYMBOL_GPL(pkcs7_verify);
index 50b3f880b4ff0d761fa29bfc9d58344235e42c31..7525fd183574c826b2f85a5f4de3ba47e4c585ab 100644 (file)
@@ -11,6 +11,7 @@
  * 2 of the Licence, or (at your option) any later version.
  */
 
+#define pr_fmt(fmt) "SIG: "fmt
 #include <keys/asymmetric-subtype.h>
 #include <linux/module.h>
 #include <linux/err.h>
index ac72348c186aef8ad71618f5d9d014d5aa1d05a3..a668d90302d38c541fb5a78aa5442019cc739b21 100644 (file)
@@ -46,7 +46,8 @@ void x509_free_certificate(struct x509_certificate *cert)
                public_key_destroy(cert->pub);
                kfree(cert->issuer);
                kfree(cert->subject);
-               kfree(cert->fingerprint);
+               kfree(cert->id);
+               kfree(cert->skid);
                kfree(cert->authority);
                kfree(cert->sig.digest);
                mpi_free(cert->sig.rsa.s);
@@ -62,6 +63,7 @@ struct x509_certificate *x509_cert_parse(const void *data, size_t datalen)
 {
        struct x509_certificate *cert;
        struct x509_parse_context *ctx;
+       struct asymmetric_key_id *kid;
        long ret;
 
        ret = -ENOMEM;
@@ -89,6 +91,17 @@ struct x509_certificate *x509_cert_parse(const void *data, size_t datalen)
        if (ret < 0)
                goto error_decode;
 
+       /* Generate cert issuer + serial number key ID */
+       kid = asymmetric_key_generate_id(cert->raw_serial,
+                                        cert->raw_serial_size,
+                                        cert->raw_issuer,
+                                        cert->raw_issuer_size);
+       if (IS_ERR(kid)) {
+               ret = PTR_ERR(kid);
+               goto error_decode;
+       }
+       cert->id = kid;
+
        kfree(ctx);
        return cert;
 
@@ -407,36 +420,36 @@ int x509_process_extension(void *context, size_t hdrlen,
                           const void *value, size_t vlen)
 {
        struct x509_parse_context *ctx = context;
+       struct asymmetric_key_id *kid;
        const unsigned char *v = value;
-       char *f;
        int i;
 
        pr_debug("Extension: %u\n", ctx->last_oid);
 
        if (ctx->last_oid == OID_subjectKeyIdentifier) {
                /* Get hold of the key fingerprint */
-               if (vlen < 3)
+               if (ctx->cert->skid || vlen < 3)
                        return -EBADMSG;
                if (v[0] != ASN1_OTS || v[1] != vlen - 2)
                        return -EBADMSG;
                v += 2;
                vlen -= 2;
 
-               f = kmalloc(vlen * 2 + 1, GFP_KERNEL);
-               if (!f)
-                       return -ENOMEM;
-               for (i = 0; i < vlen; i++)
-                       sprintf(f + i * 2, "%02x", v[i]);
-               pr_debug("fingerprint %s\n", f);
-               ctx->cert->fingerprint = f;
+               ctx->cert->raw_skid_size = vlen;
+               ctx->cert->raw_skid = v;
+               kid = asymmetric_key_generate_id(ctx->cert->raw_subject,
+                                                ctx->cert->raw_subject_size,
+                                                v, vlen);
+               if (IS_ERR(kid))
+                       return PTR_ERR(kid);
+               ctx->cert->skid = kid;
+               pr_debug("subjkeyid %*phN\n", kid->len, kid->data);
                return 0;
        }
 
        if (ctx->last_oid == OID_authorityKeyIdentifier) {
-               size_t key_len;
-
                /* Get hold of the CA key fingerprint */
-               if (vlen < 5)
+               if (ctx->cert->authority || vlen < 5)
                        return -EBADMSG;
 
                /* Authority Key Identifier must be a Constructed SEQUENCE */
@@ -454,7 +467,7 @@ int x509_process_extension(void *context, size_t hdrlen,
                            v[3] > vlen - 4)
                                return -EBADMSG;
 
-                       key_len = v[3];
+                       vlen = v[3];
                        v += 4;
                } else {
                        /* Long Form length */
@@ -476,17 +489,17 @@ int x509_process_extension(void *context, size_t hdrlen,
                            v[sub + 1] > vlen - 4 - sub)
                                return -EBADMSG;
 
-                       key_len = v[sub + 1];
+                       vlen = v[sub + 1];
                        v += (sub + 2);
                }
 
-               f = kmalloc(key_len * 2 + 1, GFP_KERNEL);
-               if (!f)
-                       return -ENOMEM;
-               for (i = 0; i < key_len; i++)
-                       sprintf(f + i * 2, "%02x", v[i]);
-               pr_debug("authority   %s\n", f);
-               ctx->cert->authority = f;
+               kid = asymmetric_key_generate_id(ctx->cert->raw_issuer,
+                                                ctx->cert->raw_issuer_size,
+                                                v, vlen);
+               if (IS_ERR(kid))
+                       return PTR_ERR(kid);
+               pr_debug("authkeyid %*phN\n", kid->len, kid->data);
+               ctx->cert->authority = kid;
                return 0;
        }
 
index 1b76f207c1f3aeb3f8a5ade16979675aecd1c397..3dfe6b5d6f0b90433d9aefb2a627d70068f4d928 100644 (file)
@@ -19,8 +19,9 @@ struct x509_certificate {
        struct public_key_signature sig;        /* Signature parameters */
        char            *issuer;                /* Name of certificate issuer */
        char            *subject;               /* Name of certificate subject */
-       char            *fingerprint;           /* Key fingerprint as hex */
-       char            *authority;             /* Authority key fingerprint as hex */
+       struct asymmetric_key_id *id;           /* Serial number + issuer */
+       struct asymmetric_key_id *skid;         /* Subject + subjectKeyId (optional) */
+       struct asymmetric_key_id *authority;    /* Authority key identifier (optional) */
        struct tm       valid_from;
        struct tm       valid_to;
        const void      *tbs;                   /* Signed data */
@@ -33,10 +34,13 @@ struct x509_certificate {
        const void      *raw_issuer;            /* Raw issuer name in ASN.1 */
        const void      *raw_subject;           /* Raw subject name in ASN.1 */
        unsigned        raw_subject_size;
+       unsigned        raw_skid_size;
+       const void      *raw_skid;              /* Raw subjectKeyId in ASN.1 */
        unsigned        index;
        bool            seen;                   /* Infinite recursion prevention */
        bool            verified;
        bool            trusted;
+       bool            unsupported_crypto;     /* T if can't be verified due to missing crypto */
 };
 
 /*
index f3d62307e6eef7bf507dc78dddc4822739100cf9..a6c42031628e94172a112700f6cdb5cd01da9789 100644 (file)
@@ -25,7 +25,7 @@
 #include "x509_parser.h"
 
 static bool use_builtin_keys;
-static char *ca_keyid;
+static struct asymmetric_key_id *ca_keyid;
 
 #ifndef MODULE
 static int __init ca_keys_setup(char *str)
@@ -33,10 +33,16 @@ static int __init ca_keys_setup(char *str)
        if (!str)               /* default system keyring */
                return 1;
 
-       if (strncmp(str, "id:", 3) == 0)
-               ca_keyid = str; /* owner key 'id:xxxxxx' */
-       else if (strcmp(str, "builtin") == 0)
+       if (strncmp(str, "id:", 3) == 0) {
+               struct asymmetric_key_id *p;
+               p = asymmetric_key_hex_to_key_id(str + 3);
+               if (p == ERR_PTR(-EINVAL))
+                       pr_err("Unparsable hex string in ca_keys\n");
+               else if (!IS_ERR(p))
+                       ca_keyid = p;   /* owner key 'id:xxxxxx' */
+       } else if (strcmp(str, "builtin") == 0) {
                use_builtin_keys = true;
+       }
 
        return 1;
 }
@@ -46,31 +52,35 @@ __setup("ca_keys=", ca_keys_setup);
 /**
  * x509_request_asymmetric_key - Request a key by X.509 certificate params.
  * @keyring: The keys to search.
- * @subject: The name of the subject to whom the key belongs.
- * @key_id: The subject key ID as a hex string.
+ * @kid: The key ID.
+ * @partial: Use partial match if true, exact if false.
  *
  * Find a key in the given keyring by subject name and key ID.  These might,
  * for instance, be the issuer name and the authority key ID of an X.509
  * certificate that needs to be verified.
  */
 struct key *x509_request_asymmetric_key(struct key *keyring,
-                                       const char *subject,
-                                       const char *key_id)
+                                       const struct asymmetric_key_id *kid,
+                                       bool partial)
 {
        key_ref_t key;
-       size_t subject_len = strlen(subject), key_id_len = strlen(key_id);
-       char *id;
+       char *id, *p;
 
-       /* Construct an identifier "<subjname>:<keyid>". */
-       id = kmalloc(subject_len + 2 + key_id_len + 1, GFP_KERNEL);
+       /* Construct an identifier "id:<keyid>". */
+       p = id = kmalloc(2 + 1 + kid->len * 2 + 1, GFP_KERNEL);
        if (!id)
                return ERR_PTR(-ENOMEM);
 
-       memcpy(id, subject, subject_len);
-       id[subject_len + 0] = ':';
-       id[subject_len + 1] = ' ';
-       memcpy(id + subject_len + 2, key_id, key_id_len);
-       id[subject_len + 2 + key_id_len] = 0;
+       if (partial) {
+               *p++ = 'i';
+               *p++ = 'd';
+       } else {
+               *p++ = 'e';
+               *p++ = 'x';
+       }
+       *p++ = ':';
+       p = bin2hex(p, kid->data, kid->len);
+       *p = 0;
 
        pr_debug("Look up: \"%s\"\n", id);
 
@@ -112,6 +122,8 @@ int x509_get_sig_params(struct x509_certificate *cert)
 
        pr_devel("==>%s()\n", __func__);
 
+       if (cert->unsupported_crypto)
+               return -ENOPKG;
        if (cert->sig.rsa.s)
                return 0;
 
@@ -124,8 +136,13 @@ int x509_get_sig_params(struct x509_certificate *cert)
         * big the hash operational data will be.
         */
        tfm = crypto_alloc_shash(hash_algo_name[cert->sig.pkey_hash_algo], 0, 0);
-       if (IS_ERR(tfm))
-               return (PTR_ERR(tfm) == -ENOENT) ? -ENOPKG : PTR_ERR(tfm);
+       if (IS_ERR(tfm)) {
+               if (PTR_ERR(tfm) == -ENOENT) {
+                       cert->unsupported_crypto = true;
+                       return -ENOPKG;
+               }
+               return PTR_ERR(tfm);
+       }
 
        desc_size = crypto_shash_descsize(tfm) + sizeof(*desc);
        digest_size = crypto_shash_digestsize(tfm);
@@ -172,6 +189,8 @@ int x509_check_signature(const struct public_key *pub,
                return ret;
 
        ret = public_key_verify_signature(pub, &cert->sig);
+       if (ret == -ENOPKG)
+               cert->unsupported_crypto = true;
        pr_debug("Cert Verification: %d\n", ret);
        return ret;
 }
@@ -195,11 +214,11 @@ static int x509_validate_trust(struct x509_certificate *cert,
        if (!trust_keyring)
                return -EOPNOTSUPP;
 
-       if (ca_keyid && !asymmetric_keyid_match(cert->authority, ca_keyid))
+       if (ca_keyid && !asymmetric_key_id_partial(cert->authority, ca_keyid))
                return -EPERM;
 
-       key = x509_request_asymmetric_key(trust_keyring,
-                                         cert->issuer, cert->authority);
+       key = x509_request_asymmetric_key(trust_keyring, cert->authority,
+                                         false);
        if (!IS_ERR(key))  {
                if (!use_builtin_keys
                    || test_bit(KEY_FLAG_BUILTIN, &key->flags))
@@ -214,9 +233,11 @@ static int x509_validate_trust(struct x509_certificate *cert,
  */
 static int x509_key_preparse(struct key_preparsed_payload *prep)
 {
+       struct asymmetric_key_ids *kids;
        struct x509_certificate *cert;
+       const char *q;
        size_t srlen, sulen;
-       char *desc = NULL;
+       char *desc = NULL, *p;
        int ret;
 
        cert = x509_cert_parse(prep->data, prep->datalen);
@@ -249,19 +270,12 @@ static int x509_key_preparse(struct key_preparsed_payload *prep)
                 pkey_algo_name[cert->sig.pkey_algo],
                 hash_algo_name[cert->sig.pkey_hash_algo]);
 
-       if (!cert->fingerprint) {
-               pr_warn("Cert for '%s' must have a SubjKeyId extension\n",
-                       cert->subject);
-               ret = -EKEYREJECTED;
-               goto error_free_cert;
-       }
-
        cert->pub->algo = pkey_algo[cert->pub->pkey_algo];
        cert->pub->id_type = PKEY_ID_X509;
 
        /* Check the signature on the key if it appears to be self-signed */
        if (!cert->authority ||
-           strcmp(cert->fingerprint, cert->authority) == 0) {
+           asymmetric_key_id_same(cert->skid, cert->authority)) {
                ret = x509_check_signature(cert->pub, cert); /* self-signed */
                if (ret < 0)
                        goto error_free_cert;
@@ -273,31 +287,52 @@ static int x509_key_preparse(struct key_preparsed_payload *prep)
 
        /* Propose a description */
        sulen = strlen(cert->subject);
-       srlen = strlen(cert->fingerprint);
+       if (cert->raw_skid) {
+               srlen = cert->raw_skid_size;
+               q = cert->raw_skid;
+       } else {
+               srlen = cert->raw_serial_size;
+               q = cert->raw_serial;
+       }
+       if (srlen > 1 && *q == 0) {
+               srlen--;
+               q++;
+       }
+
        ret = -ENOMEM;
-       desc = kmalloc(sulen + 2 + srlen + 1, GFP_KERNEL);
+       desc = kmalloc(sulen + 2 + srlen * 2 + 1, GFP_KERNEL);
        if (!desc)
                goto error_free_cert;
-       memcpy(desc, cert->subject, sulen);
-       desc[sulen] = ':';
-       desc[sulen + 1] = ' ';
-       memcpy(desc + sulen + 2, cert->fingerprint, srlen);
-       desc[sulen + 2 + srlen] = 0;
+       p = memcpy(desc, cert->subject, sulen);
+       p += sulen;
+       *p++ = ':';
+       *p++ = ' ';
+       p = bin2hex(p, q, srlen);
+       *p = 0;
+
+       kids = kmalloc(sizeof(struct asymmetric_key_ids), GFP_KERNEL);
+       if (!kids)
+               goto error_free_desc;
+       kids->id[0] = cert->id;
+       kids->id[1] = cert->skid;
 
        /* We're pinning the module by being linked against it */
        __module_get(public_key_subtype.owner);
        prep->type_data[0] = &public_key_subtype;
-       prep->type_data[1] = cert->fingerprint;
+       prep->type_data[1] = kids;
        prep->payload[0] = cert->pub;
        prep->description = desc;
        prep->quotalen = 100;
 
        /* We've finished with the certificate */
        cert->pub = NULL;
-       cert->fingerprint = NULL;
+       cert->id = NULL;
+       cert->skid = NULL;
        desc = NULL;
        ret = 0;
 
+error_free_desc:
+       kfree(desc);
 error_free_cert:
        x509_free_certificate(cert);
        return ret;
index 7d6e84a51424b269d6bfffa401f6788ac44997ed..55b83983a9c00c8b5984c887a0435ffb6e03fe1d 100644 (file)
@@ -14,11 +14,14 @@ struct dma_coherent_mem {
        int             size;
        int             flags;
        unsigned long   *bitmap;
+       spinlock_t      spinlock;
 };
 
-int dma_declare_coherent_memory(struct device *dev, phys_addr_t phys_addr,
-                               dma_addr_t device_addr, size_t size, int flags)
+static int dma_init_coherent_memory(phys_addr_t phys_addr, dma_addr_t device_addr,
+                            size_t size, int flags,
+                            struct dma_coherent_mem **mem)
 {
+       struct dma_coherent_mem *dma_mem = NULL;
        void __iomem *mem_base = NULL;
        int pages = size >> PAGE_SHIFT;
        int bitmap_size = BITS_TO_LONGS(pages) * sizeof(long);
@@ -27,40 +30,77 @@ int dma_declare_coherent_memory(struct device *dev, phys_addr_t phys_addr,
                goto out;
        if (!size)
                goto out;
-       if (dev->dma_mem)
-               goto out;
-
-       /* FIXME: this routine just ignores DMA_MEMORY_INCLUDES_CHILDREN */
 
        mem_base = ioremap(phys_addr, size);
        if (!mem_base)
                goto out;
 
-       dev->dma_mem = kzalloc(sizeof(struct dma_coherent_mem), GFP_KERNEL);
-       if (!dev->dma_mem)
+       dma_mem = kzalloc(sizeof(struct dma_coherent_mem), GFP_KERNEL);
+       if (!dma_mem)
                goto out;
-       dev->dma_mem->bitmap = kzalloc(bitmap_size, GFP_KERNEL);
-       if (!dev->dma_mem->bitmap)
-               goto free1_out;
+       dma_mem->bitmap = kzalloc(bitmap_size, GFP_KERNEL);
+       if (!dma_mem->bitmap)
+               goto out;
+
+       dma_mem->virt_base = mem_base;
+       dma_mem->device_base = device_addr;
+       dma_mem->pfn_base = PFN_DOWN(phys_addr);
+       dma_mem->size = pages;
+       dma_mem->flags = flags;
+       spin_lock_init(&dma_mem->spinlock);
 
-       dev->dma_mem->virt_base = mem_base;
-       dev->dma_mem->device_base = device_addr;
-       dev->dma_mem->pfn_base = PFN_DOWN(phys_addr);
-       dev->dma_mem->size = pages;
-       dev->dma_mem->flags = flags;
+       *mem = dma_mem;
 
        if (flags & DMA_MEMORY_MAP)
                return DMA_MEMORY_MAP;
 
        return DMA_MEMORY_IO;
 
- free1_out:
-       kfree(dev->dma_mem);
- out:
+out:
+       kfree(dma_mem);
        if (mem_base)
                iounmap(mem_base);
        return 0;
 }
+
+static void dma_release_coherent_memory(struct dma_coherent_mem *mem)
+{
+       if (!mem)
+               return;
+       iounmap(mem->virt_base);
+       kfree(mem->bitmap);
+       kfree(mem);
+}
+
+static int dma_assign_coherent_memory(struct device *dev,
+                                     struct dma_coherent_mem *mem)
+{
+       if (dev->dma_mem)
+               return -EBUSY;
+
+       dev->dma_mem = mem;
+       /* FIXME: this routine just ignores DMA_MEMORY_INCLUDES_CHILDREN */
+
+       return 0;
+}
+
+int dma_declare_coherent_memory(struct device *dev, phys_addr_t phys_addr,
+                               dma_addr_t device_addr, size_t size, int flags)
+{
+       struct dma_coherent_mem *mem;
+       int ret;
+
+       ret = dma_init_coherent_memory(phys_addr, device_addr, size, flags,
+                                      &mem);
+       if (ret == 0)
+               return 0;
+
+       if (dma_assign_coherent_memory(dev, mem) == 0)
+               return ret;
+
+       dma_release_coherent_memory(mem);
+       return 0;
+}
 EXPORT_SYMBOL(dma_declare_coherent_memory);
 
 void dma_release_declared_memory(struct device *dev)
@@ -69,10 +109,8 @@ void dma_release_declared_memory(struct device *dev)
 
        if (!mem)
                return;
+       dma_release_coherent_memory(mem);
        dev->dma_mem = NULL;
-       iounmap(mem->virt_base);
-       kfree(mem->bitmap);
-       kfree(mem);
 }
 EXPORT_SYMBOL(dma_release_declared_memory);
 
@@ -80,6 +118,7 @@ void *dma_mark_declared_memory_occupied(struct device *dev,
                                        dma_addr_t device_addr, size_t size)
 {
        struct dma_coherent_mem *mem = dev->dma_mem;
+       unsigned long flags;
        int pos, err;
 
        size += device_addr & ~PAGE_MASK;
@@ -87,8 +126,11 @@ void *dma_mark_declared_memory_occupied(struct device *dev,
        if (!mem)
                return ERR_PTR(-EINVAL);
 
+       spin_lock_irqsave(&mem->spinlock, flags);
        pos = (device_addr - mem->device_base) >> PAGE_SHIFT;
        err = bitmap_allocate_region(mem->bitmap, pos, get_order(size));
+       spin_unlock_irqrestore(&mem->spinlock, flags);
+
        if (err != 0)
                return ERR_PTR(err);
        return mem->virt_base + (pos << PAGE_SHIFT);
@@ -115,6 +157,7 @@ int dma_alloc_from_coherent(struct device *dev, ssize_t size,
 {
        struct dma_coherent_mem *mem;
        int order = get_order(size);
+       unsigned long flags;
        int pageno;
 
        if (!dev)
@@ -124,6 +167,7 @@ int dma_alloc_from_coherent(struct device *dev, ssize_t size,
                return 0;
 
        *ret = NULL;
+       spin_lock_irqsave(&mem->spinlock, flags);
 
        if (unlikely(size > (mem->size << PAGE_SHIFT)))
                goto err;
@@ -138,10 +182,12 @@ int dma_alloc_from_coherent(struct device *dev, ssize_t size,
        *dma_handle = mem->device_base + (pageno << PAGE_SHIFT);
        *ret = mem->virt_base + (pageno << PAGE_SHIFT);
        memset(*ret, 0, size);
+       spin_unlock_irqrestore(&mem->spinlock, flags);
 
        return 1;
 
 err:
+       spin_unlock_irqrestore(&mem->spinlock, flags);
        /*
         * In the case where the allocation can not be satisfied from the
         * per-device area, try to fall back to generic memory if the
@@ -171,8 +217,11 @@ int dma_release_from_coherent(struct device *dev, int order, void *vaddr)
        if (mem && vaddr >= mem->virt_base && vaddr <
                   (mem->virt_base + (mem->size << PAGE_SHIFT))) {
                int page = (vaddr - mem->virt_base) >> PAGE_SHIFT;
+               unsigned long flags;
 
+               spin_lock_irqsave(&mem->spinlock, flags);
                bitmap_release_region(mem->bitmap, page, order);
+               spin_unlock_irqrestore(&mem->spinlock, flags);
                return 1;
        }
        return 0;
@@ -218,3 +267,61 @@ int dma_mmap_from_coherent(struct device *dev, struct vm_area_struct *vma,
        return 0;
 }
 EXPORT_SYMBOL(dma_mmap_from_coherent);
+
+/*
+ * Support for reserved memory regions defined in device tree
+ */
+#ifdef CONFIG_OF_RESERVED_MEM
+#include <linux/of.h>
+#include <linux/of_fdt.h>
+#include <linux/of_reserved_mem.h>
+
+static int rmem_dma_device_init(struct reserved_mem *rmem, struct device *dev)
+{
+       struct dma_coherent_mem *mem = rmem->priv;
+
+       if (!mem &&
+           dma_init_coherent_memory(rmem->base, rmem->base, rmem->size,
+                                    DMA_MEMORY_MAP | DMA_MEMORY_EXCLUSIVE,
+                                    &mem) != DMA_MEMORY_MAP) {
+               pr_err("Reserved memory: failed to init DMA memory pool at %pa, size %ld MiB\n",
+                       &rmem->base, (unsigned long)rmem->size / SZ_1M);
+               return -ENODEV;
+       }
+       rmem->priv = mem;
+       dma_assign_coherent_memory(dev, mem);
+       return 0;
+}
+
+static void rmem_dma_device_release(struct reserved_mem *rmem,
+                                   struct device *dev)
+{
+       dev->dma_mem = NULL;
+}
+
+static const struct reserved_mem_ops rmem_dma_ops = {
+       .device_init    = rmem_dma_device_init,
+       .device_release = rmem_dma_device_release,
+};
+
+static int __init rmem_dma_setup(struct reserved_mem *rmem)
+{
+       unsigned long node = rmem->fdt_node;
+
+       if (of_get_flat_dt_prop(node, "reusable", NULL))
+               return -EINVAL;
+
+#ifdef CONFIG_ARM
+       if (!of_get_flat_dt_prop(node, "no-map", NULL)) {
+               pr_err("Reserved memory: regions without no-map are not yet supported\n");
+               return -EINVAL;
+       }
+#endif
+
+       rmem->ops = &rmem_dma_ops;
+       pr_info("Reserved memory: created DMA memory pool at %pa, size %ld MiB\n",
+               &rmem->base, (unsigned long)rmem->size / SZ_1M);
+       return 0;
+}
+RESERVEDMEM_OF_DECLARE(dma, "shared-dma-pool", rmem_dma_setup);
+#endif
index 6606abdf880c816ce407c486fbabcc27d602cef9..473ff48924015f07daee1c81ebe3d6436727493e 100644 (file)
@@ -211,3 +211,69 @@ bool dma_release_from_contiguous(struct device *dev, struct page *pages,
 {
        return cma_release(dev_get_cma_area(dev), pages, count);
 }
+
+/*
+ * Support for reserved memory regions defined in device tree
+ */
+#ifdef CONFIG_OF_RESERVED_MEM
+#include <linux/of.h>
+#include <linux/of_fdt.h>
+#include <linux/of_reserved_mem.h>
+
+#undef pr_fmt
+#define pr_fmt(fmt) fmt
+
+static void rmem_cma_device_init(struct reserved_mem *rmem, struct device *dev)
+{
+       dev_set_cma_area(dev, rmem->priv);
+}
+
+static void rmem_cma_device_release(struct reserved_mem *rmem,
+                                   struct device *dev)
+{
+       dev_set_cma_area(dev, NULL);
+}
+
+static const struct reserved_mem_ops rmem_cma_ops = {
+       .device_init    = rmem_cma_device_init,
+       .device_release = rmem_cma_device_release,
+};
+
+static int __init rmem_cma_setup(struct reserved_mem *rmem)
+{
+       phys_addr_t align = PAGE_SIZE << max(MAX_ORDER - 1, pageblock_order);
+       phys_addr_t mask = align - 1;
+       unsigned long node = rmem->fdt_node;
+       struct cma *cma;
+       int err;
+
+       if (!of_get_flat_dt_prop(node, "reusable", NULL) ||
+           of_get_flat_dt_prop(node, "no-map", NULL))
+               return -EINVAL;
+
+       if ((rmem->base & mask) || (rmem->size & mask)) {
+               pr_err("Reserved memory: incorrect alignment of CMA region\n");
+               return -EINVAL;
+       }
+
+       err = cma_init_reserved_mem(rmem->base, rmem->size, 0, &cma);
+       if (err) {
+               pr_err("Reserved memory: unable to setup CMA region\n");
+               return err;
+       }
+       /* Architecture specific contiguous memory fixup. */
+       dma_contiguous_early_fixup(rmem->base, rmem->size);
+
+       if (of_get_flat_dt_prop(node, "linux,cma-default", NULL))
+               dma_contiguous_set_default(cma);
+
+       rmem->ops = &rmem_cma_ops;
+       rmem->priv = cma;
+
+       pr_info("Reserved memory: created CMA memory pool at %pa, size %ld MiB\n",
+               &rmem->base, (unsigned long)rmem->size / SZ_1M);
+
+       return 0;
+}
+RESERVEDMEM_OF_DECLARE(cma, "shared-dma-pool", rmem_cma_setup);
+#endif
index 820b4009d5f7cd7cf15c3b337fabee707f972b2a..3265ce94d2826e05c8ee2bb2e245eb34f55db41b 100644 (file)
@@ -62,12 +62,6 @@ static DEFINE_SPINLOCK(rsxx_ida_lock);
 
 /* --------------------Debugfs Setup ------------------- */
 
-struct rsxx_cram {
-       u32 f_pos;
-       u32 offset;
-       void *i_private;
-};
-
 static int rsxx_attr_pci_regs_show(struct seq_file *m, void *p)
 {
        struct rsxx_cardinfo *card = m->private;
@@ -184,93 +178,50 @@ static int rsxx_attr_pci_regs_open(struct inode *inode, struct file *file)
 static ssize_t rsxx_cram_read(struct file *fp, char __user *ubuf,
                              size_t cnt, loff_t *ppos)
 {
-       struct rsxx_cram *info = fp->private_data;
-       struct rsxx_cardinfo *card = info->i_private;
+       struct rsxx_cardinfo *card = file_inode(fp)->i_private;
        char *buf;
-       int st;
+       ssize_t st;
 
-       buf = kzalloc(sizeof(*buf) * cnt, GFP_KERNEL);
+       buf = kzalloc(cnt, GFP_KERNEL);
        if (!buf)
                return -ENOMEM;
 
-       info->f_pos = (u32)*ppos + info->offset;
-
-       st = rsxx_creg_read(card, CREG_ADD_CRAM + info->f_pos, cnt, buf, 1);
-       if (st)
-               return st;
-
-       st = copy_to_user(ubuf, buf, cnt);
+       st = rsxx_creg_read(card, CREG_ADD_CRAM + (u32)*ppos, cnt, buf, 1);
+       if (!st)
+               st = copy_to_user(ubuf, buf, cnt);
+       kfree(buf);
        if (st)
                return st;
-
-       info->offset += cnt;
-
-       kfree(buf);
-
+       *ppos += cnt;
        return cnt;
 }
 
 static ssize_t rsxx_cram_write(struct file *fp, const char __user *ubuf,
                               size_t cnt, loff_t *ppos)
 {
-       struct rsxx_cram *info = fp->private_data;
-       struct rsxx_cardinfo *card = info->i_private;
+       struct rsxx_cardinfo *card = file_inode(fp)->i_private;
        char *buf;
-       int st;
+       ssize_t st;
 
-       buf = kzalloc(sizeof(*buf) * cnt, GFP_KERNEL);
+       buf = kzalloc(cnt, GFP_KERNEL);
        if (!buf)
                return -ENOMEM;
 
        st = copy_from_user(buf, ubuf, cnt);
+       if (!st)
+               st = rsxx_creg_write(card, CREG_ADD_CRAM + (u32)*ppos, cnt,
+                                    buf, 1);
+       kfree(buf);
        if (st)
                return st;
-
-       info->f_pos = (u32)*ppos + info->offset;
-
-       st = rsxx_creg_write(card, CREG_ADD_CRAM + info->f_pos, cnt, buf, 1);
-       if (st)
-               return st;
-
-       info->offset += cnt;
-
-       kfree(buf);
-
+       *ppos += cnt;
        return cnt;
 }
 
-static int rsxx_cram_open(struct inode *inode, struct file *file)
-{
-       struct rsxx_cram *info = kzalloc(sizeof(*info), GFP_KERNEL);
-       if (!info)
-               return -ENOMEM;
-
-       info->i_private = inode->i_private;
-       info->f_pos = file->f_pos;
-       file->private_data = info;
-
-       return 0;
-}
-
-static int rsxx_cram_release(struct inode *inode, struct file *file)
-{
-       struct rsxx_cram *info = file->private_data;
-
-       if (!info)
-               return 0;
-
-       kfree(info);
-       file->private_data = NULL;
-
-       return 0;
-}
-
 static const struct file_operations debugfs_cram_fops = {
        .owner          = THIS_MODULE,
-       .open           = rsxx_cram_open,
        .read           = rsxx_cram_read,
        .write          = rsxx_cram_write,
-       .release        = rsxx_cram_release,
 };
 
 static const struct file_operations debugfs_stats_fops = {
index 5814deb6963d52a875708e78a4a3a38eb148145e..756b8ec00f16d73851bca0c8d5ec754752c58710 100644 (file)
@@ -9,6 +9,7 @@
 #include <linux/blkdev.h>
 #include <linux/hdreg.h>
 #include <linux/genhd.h>
+#include <linux/cdrom.h>
 #include <linux/slab.h>
 #include <linux/spinlock.h>
 #include <linux/completion.h>
@@ -22,8 +23,8 @@
 
 #define DRV_MODULE_NAME                "sunvdc"
 #define PFX DRV_MODULE_NAME    ": "
-#define DRV_MODULE_VERSION     "1.0"
-#define DRV_MODULE_RELDATE     "June 25, 2007"
+#define DRV_MODULE_VERSION     "1.1"
+#define DRV_MODULE_RELDATE     "February 13, 2013"
 
 static char version[] =
        DRV_MODULE_NAME ".c:v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n";
@@ -32,7 +33,7 @@ MODULE_DESCRIPTION("Sun LDOM virtual disk client driver");
 MODULE_LICENSE("GPL");
 MODULE_VERSION(DRV_MODULE_VERSION);
 
-#define VDC_TX_RING_SIZE       256
+#define VDC_TX_RING_SIZE       512
 
 #define WAITING_FOR_LINK_UP    0x01
 #define WAITING_FOR_TX_SPACE   0x02
@@ -65,10 +66,10 @@ struct vdc_port {
        u64                     operations;
        u32                     vdisk_size;
        u8                      vdisk_type;
+       u8                      vdisk_mtype;
 
        char                    disk_name[32];
 
-       struct vio_disk_geom    geom;
        struct vio_disk_vtoc    label;
 };
 
@@ -79,9 +80,16 @@ static inline struct vdc_port *to_vdc_port(struct vio_driver_state *vio)
 
 /* Ordered from largest major to lowest */
 static struct vio_version vdc_versions[] = {
+       { .major = 1, .minor = 1 },
        { .major = 1, .minor = 0 },
 };
 
+static inline int vdc_version_supported(struct vdc_port *port,
+                                       u16 major, u16 minor)
+{
+       return port->vio.ver.major == major && port->vio.ver.minor >= minor;
+}
+
 #define VDCBLK_NAME    "vdisk"
 static int vdc_major;
 #define PARTITION_SHIFT        3
@@ -94,18 +102,54 @@ static inline u32 vdc_tx_dring_avail(struct vio_dring_state *dr)
 static int vdc_getgeo(struct block_device *bdev, struct hd_geometry *geo)
 {
        struct gendisk *disk = bdev->bd_disk;
-       struct vdc_port *port = disk->private_data;
+       sector_t nsect = get_capacity(disk);
+       sector_t cylinders = nsect;
 
-       geo->heads = (u8) port->geom.num_hd;
-       geo->sectors = (u8) port->geom.num_sec;
-       geo->cylinders = port->geom.num_cyl;
+       geo->heads = 0xff;
+       geo->sectors = 0x3f;
+       sector_div(cylinders, geo->heads * geo->sectors);
+       geo->cylinders = cylinders;
+       if ((sector_t)(geo->cylinders + 1) * geo->heads * geo->sectors < nsect)
+               geo->cylinders = 0xffff;
 
        return 0;
 }
 
+/* Add ioctl/CDROM_GET_CAPABILITY to support cdrom_id in udev
+ * when vdisk_mtype is VD_MEDIA_TYPE_CD or VD_MEDIA_TYPE_DVD.
+ * Needed to be able to install inside an ldom from an iso image.
+ */
+static int vdc_ioctl(struct block_device *bdev, fmode_t mode,
+                    unsigned command, unsigned long argument)
+{
+       int i;
+       struct gendisk *disk;
+
+       switch (command) {
+       case CDROMMULTISESSION:
+               pr_debug(PFX "Multisession CDs not supported\n");
+               for (i = 0; i < sizeof(struct cdrom_multisession); i++)
+                       if (put_user(0, (char __user *)(argument + i)))
+                               return -EFAULT;
+               return 0;
+
+       case CDROM_GET_CAPABILITY:
+               disk = bdev->bd_disk;
+
+               if (bdev->bd_disk && (disk->flags & GENHD_FL_CD))
+                       return 0;
+               return -EINVAL;
+
+       default:
+               pr_debug(PFX "ioctl %08x not supported\n", command);
+               return -EINVAL;
+       }
+}
+
 static const struct block_device_operations vdc_fops = {
        .owner          = THIS_MODULE,
        .getgeo         = vdc_getgeo,
+       .ioctl          = vdc_ioctl,
 };
 
 static void vdc_finish(struct vio_driver_state *vio, int err, int waiting_for)
@@ -165,9 +209,9 @@ static int vdc_handle_attr(struct vio_driver_state *vio, void *arg)
        struct vio_disk_attr_info *pkt = arg;
 
        viodbg(HS, "GOT ATTR stype[0x%x] ops[%llx] disk_size[%llu] disk_type[%x] "
-              "xfer_mode[0x%x] blksz[%u] max_xfer[%llu]\n",
+              "mtype[0x%x] xfer_mode[0x%x] blksz[%u] max_xfer[%llu]\n",
               pkt->tag.stype, pkt->operations,
-              pkt->vdisk_size, pkt->vdisk_type,
+              pkt->vdisk_size, pkt->vdisk_type, pkt->vdisk_mtype,
               pkt->xfer_mode, pkt->vdisk_block_size,
               pkt->max_xfer_size);
 
@@ -192,8 +236,11 @@ static int vdc_handle_attr(struct vio_driver_state *vio, void *arg)
                }
 
                port->operations = pkt->operations;
-               port->vdisk_size = pkt->vdisk_size;
                port->vdisk_type = pkt->vdisk_type;
+               if (vdc_version_supported(port, 1, 1)) {
+                       port->vdisk_size = pkt->vdisk_size;
+                       port->vdisk_mtype = pkt->vdisk_mtype;
+               }
                if (pkt->max_xfer_size < port->max_xfer_size)
                        port->max_xfer_size = pkt->max_xfer_size;
                port->vdisk_block_size = pkt->vdisk_block_size;
@@ -236,7 +283,9 @@ static void vdc_end_one(struct vdc_port *port, struct vio_dring_state *dr,
 
        __blk_end_request(req, (desc->status ? -EIO : 0), desc->size);
 
-       if (blk_queue_stopped(port->disk->queue))
+       /* restart blk queue when ring is half emptied */
+       if (blk_queue_stopped(port->disk->queue) &&
+           vdc_tx_dring_avail(dr) * 100 / VDC_TX_RING_SIZE >= 50)
                blk_start_queue(port->disk->queue);
 }
 
@@ -388,12 +437,6 @@ static int __send_request(struct request *req)
        for (i = 0; i < nsg; i++)
                len += sg[i].length;
 
-       if (unlikely(vdc_tx_dring_avail(dr) < 1)) {
-               blk_stop_queue(port->disk->queue);
-               err = -ENOMEM;
-               goto out;
-       }
-
        desc = vio_dring_cur(dr);
 
        err = ldc_map_sg(port->vio.lp, sg, nsg,
@@ -433,21 +476,32 @@ static int __send_request(struct request *req)
                port->req_id++;
                dr->prod = (dr->prod + 1) & (VDC_TX_RING_SIZE - 1);
        }
-out:
 
        return err;
 }
 
-static void do_vdc_request(struct request_queue *q)
+static void do_vdc_request(struct request_queue *rq)
 {
-       while (1) {
-               struct request *req = blk_fetch_request(q);
+       struct request *req;
 
-               if (!req)
-                       break;
+       while ((req = blk_peek_request(rq)) != NULL) {
+               struct vdc_port *port;
+               struct vio_dring_state *dr;
+
+               port = req->rq_disk->private_data;
+               dr = &port->vio.drings[VIO_DRIVER_TX_RING];
+               if (unlikely(vdc_tx_dring_avail(dr) < 1))
+                       goto wait;
+
+               blk_start_request(req);
 
-               if (__send_request(req) < 0)
-                       __blk_end_request_all(req, -EIO);
+               if (__send_request(req) < 0) {
+                       blk_requeue_request(rq, req);
+wait:
+                       /* Avoid pointless unplugs. */
+                       blk_stop_queue(rq);
+                       break;
+               }
        }
 }
 
@@ -663,18 +717,27 @@ static int probe_disk(struct vdc_port *port)
                return err;
        }
 
-       err = generic_request(port, VD_OP_GET_DISKGEOM,
-                             &port->geom, sizeof(port->geom));
-       if (err < 0) {
-               printk(KERN_ERR PFX "VD_OP_GET_DISKGEOM returns "
-                      "error %d\n", err);
-               return err;
+       if (vdc_version_supported(port, 1, 1)) {
+               /* vdisk_size should be set during the handshake, if it wasn't
+                * then the underlying disk is reserved by another system
+                */
+               if (port->vdisk_size == -1)
+                       return -ENODEV;
+       } else {
+               struct vio_disk_geom geom;
+
+               err = generic_request(port, VD_OP_GET_DISKGEOM,
+                                     &geom, sizeof(geom));
+               if (err < 0) {
+                       printk(KERN_ERR PFX "VD_OP_GET_DISKGEOM returns "
+                              "error %d\n", err);
+                       return err;
+               }
+               port->vdisk_size = ((u64)geom.num_cyl *
+                                   (u64)geom.num_hd *
+                                   (u64)geom.num_sec);
        }
 
-       port->vdisk_size = ((u64)port->geom.num_cyl *
-                           (u64)port->geom.num_hd *
-                           (u64)port->geom.num_sec);
-
        q = blk_init_queue(do_vdc_request, &port->vio.lock);
        if (!q) {
                printk(KERN_ERR PFX "%s: Could not allocate queue.\n",
@@ -691,6 +754,10 @@ static int probe_disk(struct vdc_port *port)
 
        port->disk = g;
 
+       /* Each segment in a request is up to an aligned page in size. */
+       blk_queue_segment_boundary(q, PAGE_SIZE - 1);
+       blk_queue_max_segment_size(q, PAGE_SIZE);
+
        blk_queue_max_segments(q, port->ring_cookies);
        blk_queue_max_hw_sectors(q, port->max_xfer_size);
        g->major = vdc_major;
@@ -704,9 +771,32 @@ static int probe_disk(struct vdc_port *port)
 
        set_capacity(g, port->vdisk_size);
 
-       printk(KERN_INFO PFX "%s: %u sectors (%u MB)\n",
+       if (vdc_version_supported(port, 1, 1)) {
+               switch (port->vdisk_mtype) {
+               case VD_MEDIA_TYPE_CD:
+                       pr_info(PFX "Virtual CDROM %s\n", port->disk_name);
+                       g->flags |= GENHD_FL_CD;
+                       g->flags |= GENHD_FL_REMOVABLE;
+                       set_disk_ro(g, 1);
+                       break;
+
+               case VD_MEDIA_TYPE_DVD:
+                       pr_info(PFX "Virtual DVD %s\n", port->disk_name);
+                       g->flags |= GENHD_FL_CD;
+                       g->flags |= GENHD_FL_REMOVABLE;
+                       set_disk_ro(g, 1);
+                       break;
+
+               case VD_MEDIA_TYPE_FIXED:
+                       pr_info(PFX "Virtual Hard disk %s\n", port->disk_name);
+                       break;
+               }
+       }
+
+       pr_info(PFX "%s: %u sectors (%u MB) protocol %d.%d\n",
               g->disk_name,
-              port->vdisk_size, (port->vdisk_size >> (20 - 9)));
+              port->vdisk_size, (port->vdisk_size >> (20 - 9)),
+              port->vio.ver.major, port->vio.ver.minor);
 
        add_disk(g);
 
@@ -765,6 +855,7 @@ static int vdc_port_probe(struct vio_dev *vdev, const struct vio_device_id *id)
        else
                snprintf(port->disk_name, sizeof(port->disk_name),
                         VDCBLK_NAME "%c", 'a' + ((int)vdev->dev_no % 26));
+       port->vdisk_size = -1;
 
        err = vio_driver_init(&port->vio, vdev, VDEV_DISK,
                              vdc_versions, ARRAY_SIZE(vdc_versions),
index 3a8b810b4980582ddcb61bb1fc23f112adbe02d6..0b13b1c9a01e397fbb557e676beb77742c9737bc 100644 (file)
@@ -907,22 +907,17 @@ static int connect_ring(struct backend_info *be)
        return 0;
 }
 
-
-/* ** Driver Registration ** */
-
-
 static const struct xenbus_device_id xen_blkbk_ids[] = {
        { "vbd" },
        { "" }
 };
 
-
-static DEFINE_XENBUS_DRIVER(xen_blkbk, ,
+static struct xenbus_driver xen_blkbk_driver = {
+       .ids  = xen_blkbk_ids,
        .probe = xen_blkbk_probe,
        .remove = xen_blkbk_remove,
        .otherend_changed = frontend_changed
-);
-
+};
 
 int xen_blkif_xenbus_init(void)
 {
index 5deb235bd18fe07adb2efb09a7c77508aadfaeec..37af03e9d859d113f28c8ccb2be70be98a5ce831 100644 (file)
@@ -2055,13 +2055,14 @@ static const struct xenbus_device_id blkfront_ids[] = {
        { "" }
 };
 
-static DEFINE_XENBUS_DRIVER(blkfront, ,
+static struct xenbus_driver blkfront_driver = {
+       .ids  = blkfront_ids,
        .probe = blkfront_probe,
        .remove = blkfront_remove,
        .resume = blkfront_resume,
        .otherend_changed = blkback_changed,
        .is_ready = blkfront_is_ready,
-);
+};
 
 static int __init xlblk_init(void)
 {
index 5bb5872ffee60c060232eb5ddcab7957125b0161..6653473f2757d0579b790a6fffbc298eb2b43b0d 100644 (file)
@@ -160,13 +160,11 @@ static int vhci_create_device(struct vhci_data *data, __u8 opcode)
 }
 
 static inline ssize_t vhci_get_user(struct vhci_data *data,
-                                   const struct iovec *iov,
-                                   unsigned long count)
+                                   struct iov_iter *from)
 {
-       size_t len = iov_length(iov, count);
+       size_t len = iov_iter_count(from);
        struct sk_buff *skb;
        __u8 pkt_type, opcode;
-       unsigned long i;
        int ret;
 
        if (len < 2 || len > HCI_MAX_FRAME_SIZE)
@@ -176,12 +174,9 @@ static inline ssize_t vhci_get_user(struct vhci_data *data,
        if (!skb)
                return -ENOMEM;
 
-       for (i = 0; i < count; i++) {
-               if (copy_from_user(skb_put(skb, iov[i].iov_len),
-                                  iov[i].iov_base, iov[i].iov_len)) {
-                       kfree_skb(skb);
-                       return -EFAULT;
-               }
+       if (copy_from_iter(skb_put(skb, len), len, from) != len) {
+               kfree_skb(skb);
+               return -EFAULT;
        }
 
        pkt_type = *((__u8 *) skb->data);
@@ -294,13 +289,12 @@ static ssize_t vhci_read(struct file *file,
        return ret;
 }
 
-static ssize_t vhci_write(struct kiocb *iocb, const struct iovec *iov,
-                         unsigned long count, loff_t pos)
+static ssize_t vhci_write(struct kiocb *iocb, struct iov_iter *from)
 {
        struct file *file = iocb->ki_filp;
        struct vhci_data *data = file->private_data;
 
-       return vhci_get_user(data, iov, count);
+       return vhci_get_user(data, from);
 }
 
 static unsigned int vhci_poll(struct file *file, poll_table *wait)
@@ -365,7 +359,7 @@ static int vhci_release(struct inode *inode, struct file *file)
 static const struct file_operations vhci_fops = {
        .owner          = THIS_MODULE,
        .read           = vhci_read,
-       .aio_write      = vhci_write,
+       .write_iter     = vhci_write,
        .poll           = vhci_poll,
        .open           = vhci_open,
        .release        = vhci_release,
index 917403fe10da3eb62c0548bb29a2f0d898c8400a..524b707894ef14f43cf010bfd73c74928e811884 100644 (file)
@@ -622,53 +622,23 @@ static ssize_t splice_write_null(struct pipe_inode_info *pipe, struct file *out,
        return splice_from_pipe(pipe, out, ppos, len, flags, pipe_to_null);
 }
 
-static ssize_t read_zero(struct file *file, char __user *buf,
-                        size_t count, loff_t *ppos)
+static ssize_t read_iter_zero(struct kiocb *iocb, struct iov_iter *iter)
 {
-       size_t written;
-
-       if (!count)
-               return 0;
-
-       if (!access_ok(VERIFY_WRITE, buf, count))
-               return -EFAULT;
-
-       written = 0;
-       while (count) {
-               unsigned long unwritten;
-               size_t chunk = count;
+       size_t written = 0;
 
+       while (iov_iter_count(iter)) {
+               size_t chunk = iov_iter_count(iter), n;
                if (chunk > PAGE_SIZE)
                        chunk = PAGE_SIZE;      /* Just for latency reasons */
-               unwritten = __clear_user(buf, chunk);
-               written += chunk - unwritten;
-               if (unwritten)
-                       break;
+               n = iov_iter_zero(chunk, iter);
+               if (!n && iov_iter_count(iter))
+                       return written ? written : -EFAULT;
+               written += n;
                if (signal_pending(current))
                        return written ? written : -ERESTARTSYS;
-               buf += chunk;
-               count -= chunk;
                cond_resched();
        }
-       return written ? written : -EFAULT;
-}
-
-static ssize_t aio_read_zero(struct kiocb *iocb, const struct iovec *iov,
-                            unsigned long nr_segs, loff_t pos)
-{
-       size_t written = 0;
-       unsigned long i;
-       ssize_t ret;
-
-       for (i = 0; i < nr_segs; i++) {
-               ret = read_zero(iocb->ki_filp, iov[i].iov_base, iov[i].iov_len,
-                               &pos);
-               if (ret < 0)
-                       break;
-               written += ret;
-       }
-
-       return written ? written : -EFAULT;
+       return written;
 }
 
 static int mmap_zero(struct file *file, struct vm_area_struct *vma)
@@ -738,7 +708,6 @@ static int open_port(struct inode *inode, struct file *filp)
 #define zero_lseek     null_lseek
 #define full_lseek      null_lseek
 #define write_zero     write_null
-#define read_full       read_zero
 #define aio_write_zero aio_write_null
 #define open_mem       open_port
 #define open_kmem      open_mem
@@ -783,9 +752,9 @@ static const struct file_operations port_fops = {
 
 static const struct file_operations zero_fops = {
        .llseek         = zero_lseek,
-       .read           = read_zero,
+       .read           = new_sync_read,
        .write          = write_zero,
-       .aio_read       = aio_read_zero,
+       .read_iter      = read_iter_zero,
        .aio_write      = aio_write_zero,
        .mmap           = mmap_zero,
 };
@@ -802,7 +771,8 @@ static struct backing_dev_info zero_bdi = {
 
 static const struct file_operations full_fops = {
        .llseek         = full_lseek,
-       .read           = read_full,
+       .read           = new_sync_read,
+       .read_iter      = read_iter_zero,
        .write          = write_full,
 };
 
index 2064b4527040be68920c3ef9e557b090ca587f7a..441b44e5422691c7ed1a38a84ca8d0fa661849e1 100644 (file)
@@ -367,12 +367,13 @@ static const struct xenbus_device_id tpmfront_ids[] = {
 };
 MODULE_ALIAS("xen:vtpm");
 
-static DEFINE_XENBUS_DRIVER(tpmfront, ,
-               .probe = tpmfront_probe,
-               .remove = tpmfront_remove,
-               .resume = tpmfront_resume,
-               .otherend_changed = backend_changed,
-       );
+static struct xenbus_driver tpmfront_driver = {
+       .ids = tpmfront_ids,
+       .probe = tpmfront_probe,
+       .remove = tpmfront_remove,
+       .resume = tpmfront_resume,
+       .otherend_changed = backend_changed,
+};
 
 static int __init xen_tpmfront_init(void)
 {
index cfd3af7b2cbd16cec12c23cf0767cc787c66a812..84e0590e31dc754fd1562d8bd99d2c3273090f3f 100644 (file)
@@ -38,6 +38,15 @@ config COMMON_CLK_MAX77686
        ---help---
          This driver supports Maxim 77686 crystal oscillator clock. 
 
+config COMMON_CLK_RK808
+       tristate "Clock driver for RK808"
+       depends on MFD_RK808
+       ---help---
+         This driver supports RK808 crystal oscillator clock. These
+         multi-function devices have two fixed-rate oscillators,
+         clocked at 32KHz each. Clkout1 is always on, Clkout2 can off
+         by control register.
+
 config COMMON_CLK_SI5351
        tristate "Clock driver for SiLabs 5351A/B/C"
        depends on I2C
index f537a0b1f798159824aa1d90ffd4378d1bff908d..99f53d5f876618be908525c3cbc4b9c3803119a2 100644 (file)
@@ -28,6 +28,7 @@ obj-$(CONFIG_ARCH_NOMADIK)            += clk-nomadik.o
 obj-$(CONFIG_ARCH_NSPIRE)              += clk-nspire.o
 obj-$(CONFIG_COMMON_CLK_PALMAS)                += clk-palmas.o
 obj-$(CONFIG_CLK_PPC_CORENET)          += clk-ppc-corenet.o
+obj-$(CONFIG_COMMON_CLK_RK808)         += clk-rk808.o
 obj-$(CONFIG_COMMON_CLK_S2MPS11)       += clk-s2mps11.o
 obj-$(CONFIG_COMMON_CLK_SI5351)                += clk-si5351.o
 obj-$(CONFIG_COMMON_CLK_SI570)         += clk-si570.o
diff --git a/drivers/clk/clk-rk808.c b/drivers/clk/clk-rk808.c
new file mode 100644 (file)
index 0000000..83902b9
--- /dev/null
@@ -0,0 +1,170 @@
+/*
+ * Clkout driver for Rockchip RK808
+ *
+ * Copyright (c) 2014, Fuzhou Rockchip Electronics Co., Ltd
+ *
+ * Author:Chris Zhong <zyw@rock-chips.com>
+ *
+ * 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.
+ */
+
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+#include <linux/mfd/rk808.h>
+#include <linux/i2c.h>
+
+#define RK808_NR_OUTPUT 2
+
+struct rk808_clkout {
+       struct rk808 *rk808;
+       struct clk_onecell_data clk_data;
+       struct clk_hw           clkout1_hw;
+       struct clk_hw           clkout2_hw;
+};
+
+static unsigned long rk808_clkout_recalc_rate(struct clk_hw *hw,
+                                             unsigned long parent_rate)
+{
+       return 32768;
+}
+
+static int rk808_clkout2_enable(struct clk_hw *hw, bool enable)
+{
+       struct rk808_clkout *rk808_clkout = container_of(hw,
+                                                        struct rk808_clkout,
+                                                        clkout2_hw);
+       struct rk808 *rk808 = rk808_clkout->rk808;
+
+       return regmap_update_bits(rk808->regmap, RK808_CLK32OUT_REG,
+                                 CLK32KOUT2_EN, enable ? CLK32KOUT2_EN : 0);
+}
+
+static int rk808_clkout2_prepare(struct clk_hw *hw)
+{
+       return rk808_clkout2_enable(hw, true);
+}
+
+static void rk808_clkout2_unprepare(struct clk_hw *hw)
+{
+       rk808_clkout2_enable(hw, false);
+}
+
+static int rk808_clkout2_is_prepared(struct clk_hw *hw)
+{
+       struct rk808_clkout *rk808_clkout = container_of(hw,
+                                                        struct rk808_clkout,
+                                                        clkout2_hw);
+       struct rk808 *rk808 = rk808_clkout->rk808;
+       uint32_t val;
+
+       int ret = regmap_read(rk808->regmap, RK808_CLK32OUT_REG, &val);
+
+       if (ret < 0)
+               return ret;
+
+       return (val & CLK32KOUT2_EN) ? 1 : 0;
+}
+
+static const struct clk_ops rk808_clkout1_ops = {
+       .recalc_rate = rk808_clkout_recalc_rate,
+};
+
+static const struct clk_ops rk808_clkout2_ops = {
+       .prepare = rk808_clkout2_prepare,
+       .unprepare = rk808_clkout2_unprepare,
+       .is_prepared = rk808_clkout2_is_prepared,
+       .recalc_rate = rk808_clkout_recalc_rate,
+};
+
+static int rk808_clkout_probe(struct platform_device *pdev)
+{
+       struct rk808 *rk808 = dev_get_drvdata(pdev->dev.parent);
+       struct i2c_client *client = rk808->i2c;
+       struct device_node *node = client->dev.of_node;
+       struct clk_init_data init = {};
+       struct clk **clk_table;
+       struct rk808_clkout *rk808_clkout;
+
+       rk808_clkout = devm_kzalloc(&client->dev,
+                                   sizeof(*rk808_clkout), GFP_KERNEL);
+       if (!rk808_clkout)
+               return -ENOMEM;
+
+       rk808_clkout->rk808 = rk808;
+
+       clk_table = devm_kcalloc(&client->dev, RK808_NR_OUTPUT,
+                                sizeof(struct clk *), GFP_KERNEL);
+       if (!clk_table)
+               return -ENOMEM;
+
+       init.flags = CLK_IS_ROOT;
+       init.parent_names = NULL;
+       init.num_parents = 0;
+       init.name = "rk808-clkout1";
+       init.ops = &rk808_clkout1_ops;
+       rk808_clkout->clkout1_hw.init = &init;
+
+       /* optional override of the clockname */
+       of_property_read_string_index(node, "clock-output-names",
+                                     0, &init.name);
+
+       clk_table[0] = devm_clk_register(&client->dev,
+                                        &rk808_clkout->clkout1_hw);
+       if (IS_ERR(clk_table[0]))
+               return PTR_ERR(clk_table[0]);
+
+       init.name = "rk808-clkout2";
+       init.ops = &rk808_clkout2_ops;
+       rk808_clkout->clkout2_hw.init = &init;
+
+       /* optional override of the clockname */
+       of_property_read_string_index(node, "clock-output-names",
+                                     1, &init.name);
+
+       clk_table[1] = devm_clk_register(&client->dev,
+                                        &rk808_clkout->clkout2_hw);
+       if (IS_ERR(clk_table[1]))
+               return PTR_ERR(clk_table[1]);
+
+       rk808_clkout->clk_data.clks = clk_table;
+       rk808_clkout->clk_data.clk_num = RK808_NR_OUTPUT;
+
+       return of_clk_add_provider(node, of_clk_src_onecell_get,
+                                  &rk808_clkout->clk_data);
+}
+
+static int rk808_clkout_remove(struct platform_device *pdev)
+{
+       struct rk808 *rk808 = dev_get_drvdata(pdev->dev.parent);
+       struct i2c_client *client = rk808->i2c;
+       struct device_node *node = client->dev.of_node;
+
+       of_clk_del_provider(node);
+
+       return 0;
+}
+
+static struct platform_driver rk808_clkout_driver = {
+       .probe = rk808_clkout_probe,
+       .remove = rk808_clkout_remove,
+       .driver         = {
+               .name   = "rk808-clkout",
+       },
+};
+
+module_platform_driver(rk808_clkout_driver);
+
+MODULE_DESCRIPTION("Clkout driver for the rk808 series PMICs");
+MODULE_AUTHOR("Chris Zhong <zyw@rock-chips.com>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:rk808-clkout");
index 531d4f6c70501e12aa19a1e6c4118a4a4fa1c615..960bf22d42ae156bda33c375ccfcbbb42bed8712 100644 (file)
@@ -7,5 +7,3 @@ obj-$(CONFIG_ARCH_R8A7791)              += clk-rcar-gen2.o
 obj-$(CONFIG_ARCH_R8A7794)             += clk-rcar-gen2.o
 obj-$(CONFIG_ARCH_SHMOBILE_MULTI)      += clk-div6.o
 obj-$(CONFIG_ARCH_SHMOBILE_MULTI)      += clk-mstp.o
-# for emply built-in.o
-obj-n  := dummy
index 7615180d7ee3c497e915d72f18af11e9b3f09c5c..1f49d97a70ea164737570c3480a2dcac30265788 100644 (file)
@@ -611,7 +611,7 @@ static int __init pmac_cpufreq_setup(void)
        struct device_node      *cpunode;
        const u32               *value;
 
-       if (strstr(cmd_line, "nocpufreq"))
+       if (strstr(boot_command_line, "nocpufreq"))
                return 0;
 
        /* Get first CPU node */
index ee9df5e3f5eba2a5bb705e8be1898c2a370ccd21..125150dc6e81edf5a120adffce852080eeccf76f 100644 (file)
@@ -223,8 +223,14 @@ void cpuidle_uninstall_idle_handler(void)
 {
        if (enabled_devices) {
                initialized = 0;
-               kick_all_cpus_sync();
+               wake_up_all_idle_cpus();
        }
+
+       /*
+        * Make sure external observers (such as the scheduler)
+        * are done looking at pointed idle states.
+        */
+       synchronize_rcu();
 }
 
 /**
@@ -530,11 +536,6 @@ EXPORT_SYMBOL_GPL(cpuidle_register);
 
 #ifdef CONFIG_SMP
 
-static void smp_callback(void *v)
-{
-       /* we already woke the CPU up, nothing more to do */
-}
-
 /*
  * This function gets called when a part of the kernel has a new latency
  * requirement.  This means we need to get all processors out of their C-state,
@@ -544,7 +545,7 @@ static void smp_callback(void *v)
 static int cpuidle_latency_notify(struct notifier_block *b,
                unsigned long l, void *v)
 {
-       smp_call_function(smp_callback, NULL, 1);
+       wake_up_all_idle_cpus();
        return NOTIFY_OK;
 }
 
index f3014c448e1ef5fb24804945af9dbdca7950b4c5..5be225c2ba98d5ea11760217d9afdfa5240215d3 100644 (file)
@@ -799,7 +799,7 @@ static int dma_buf_describe(struct seq_file *s)
                seq_printf(s, "%08zu\t%08x\t%08x\t%08ld\t%s\n",
                                buf_obj->size,
                                buf_obj->file->f_flags, buf_obj->file->f_mode,
-                               (long)(buf_obj->file->f_count.counter),
+                               file_count(buf_obj->file),
                                buf_obj->exp_name);
 
                seq_puts(s, "\tAttached Devices:\n");
index 0034c48444280e7c40d21fd0f94d8faf4a9b7df2..e9bb1af67c8dfbae01408c16211e93c71207ee02 100644 (file)
@@ -52,36 +52,6 @@ static int probed;
 #define GET_BITFIELD(v, lo, hi)        \
        (((v) & GENMASK_ULL(hi, lo)) >> (lo))
 
-/*
- * sbridge Memory Controller Registers
- */
-
-/*
- * FIXME: For now, let's order by device function, as it makes
- * easier for driver's development process. This table should be
- * moved to pci_id.h when submitted upstream
- */
-#define PCI_DEVICE_ID_INTEL_SBRIDGE_SAD0       0x3cf4  /* 12.6 */
-#define PCI_DEVICE_ID_INTEL_SBRIDGE_SAD1       0x3cf6  /* 12.7 */
-#define PCI_DEVICE_ID_INTEL_SBRIDGE_BR         0x3cf5  /* 13.6 */
-#define PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_HA0    0x3ca0  /* 14.0 */
-#define PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_TA     0x3ca8  /* 15.0 */
-#define PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_RAS    0x3c71  /* 15.1 */
-#define PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_TAD0   0x3caa  /* 15.2 */
-#define PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_TAD1   0x3cab  /* 15.3 */
-#define PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_TAD2   0x3cac  /* 15.4 */
-#define PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_TAD3   0x3cad  /* 15.5 */
-#define PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_DDRIO  0x3cb8  /* 17.0 */
-
-       /*
-        * Currently, unused, but will be needed in the future
-        * implementations, as they hold the error counters
-        */
-#define PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_ERR0   0x3c72  /* 16.2 */
-#define PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_ERR1   0x3c73  /* 16.3 */
-#define PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_ERR2   0x3c76  /* 16.6 */
-#define PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_ERR3   0x3c77  /* 16.7 */
-
 /* Devices 12 Function 6, Offsets 0x80 to 0xcc */
 static const u32 sbridge_dram_rule[] = {
        0x80, 0x88, 0x90, 0x98, 0xa0,
@@ -283,8 +253,9 @@ static const u32 correrrthrsld[] = {
  * sbridge structs
  */
 
-#define NUM_CHANNELS   4
-#define MAX_DIMMS      3               /* Max DIMMS per channel */
+#define NUM_CHANNELS           4
+#define MAX_DIMMS              3       /* Max DIMMS per channel */
+#define CHANNEL_UNSPECIFIED    0xf     /* Intel IA32 SDM 15-14 */
 
 enum type {
        SANDY_BRIDGE,
@@ -529,7 +500,7 @@ static const struct pci_id_table pci_dev_descr_haswell_table[] = {
  *     pci_device_id   table for which devices we are looking for
  */
 static const struct pci_device_id sbridge_pci_tbl[] = {
-       {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_TA)},
+       {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_HA0)},
        {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_TA)},
        {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA0)},
        {0,}                    /* 0 terminated list. */
@@ -1991,6 +1962,9 @@ static void sbridge_mce_output_error(struct mem_ctl_info *mci,
 
        /* FIXME: need support for channel mask */
 
+       if (channel == CHANNEL_UNSPECIFIED)
+               channel = -1;
+
        /* Call the helper to output message */
        edac_mc_handle_error(tp_event, mci, core_err_cnt,
                             m->addr >> PAGE_SHIFT, m->addr & ~PAGE_MASK, 0,
index b066bb3ca01ace734e16abd61fccfb88cdd46c0c..e3b4b0f02b3d1de3e07a9d40cb11b22d1822701f 100644 (file)
@@ -8,6 +8,7 @@ menuconfig DRM
        tristate "Direct Rendering Manager (XFree86 4.1.0 and higher DRI support)"
        depends on (AGP || AGP=n) && !EMULATED_CMPXCHG && MMU && HAS_DMA
        select HDMI
+       select FB_CMDLINE
        select I2C
        select I2C_ALGOBIT
        select DMA_SHARED_BUFFER
@@ -24,12 +25,6 @@ config DRM_MIPI_DSI
        bool
        depends on DRM
 
-config DRM_USB
-       tristate
-       depends on DRM
-       depends on USB_SUPPORT && USB_ARCH_HAS_HCD
-       select USB
-
 config DRM_KMS_HELPER
        tristate
        depends on DRM
@@ -115,6 +110,7 @@ config DRM_RADEON
        select HWMON
        select BACKLIGHT_CLASS_DEVICE
        select INTERVAL_TREE
+       select MMU_NOTIFIER
        help
          Choose this option if you have an ATI Radeon graphics card.  There
          are both PCI and AGP versions.  You don't need to choose this to
index 4a55d59ccd22f21ed3c11f13bc92ab9761f22eae..9292a761ea6db9fa2844f762726b717e1bbce4b2 100644 (file)
@@ -4,7 +4,7 @@
 
 ccflags-y := -Iinclude/drm
 
-drm-y       := drm_auth.o drm_buffer.o drm_bufs.o drm_cache.o \
+drm-y       := drm_auth.o drm_bufs.o drm_cache.o \
                drm_context.o drm_dma.o \
                drm_fops.o drm_gem.o drm_ioctl.o drm_irq.o \
                drm_lock.o drm_memory.o drm_drv.o drm_vm.o \
@@ -22,8 +22,6 @@ drm-$(CONFIG_PCI) += ati_pcigart.o
 drm-$(CONFIG_DRM_PANEL) += drm_panel.o
 drm-$(CONFIG_OF) += drm_of.o
 
-drm-usb-y   := drm_usb.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_kms_helper-$(CONFIG_DRM_LOAD_EDID_FIRMWARE) += drm_edid_load.o
@@ -36,7 +34,6 @@ CFLAGS_drm_trace_points.o := -I$(src)
 
 obj-$(CONFIG_DRM)      += drm.o
 obj-$(CONFIG_DRM_MIPI_DSI) += drm_mipi_dsi.o
-obj-$(CONFIG_DRM_USB)   += drm_usb.o
 obj-$(CONFIG_DRM_TTM)  += ttm/
 obj-$(CONFIG_DRM_TDFX) += tdfx/
 obj-$(CONFIG_DRM_R128) += r128/
index e2d5792b140fb41069713661612e0853da0e5854..f672e6ad8afae05d42ebeb31b31bc9c3eb60c117 100644 (file)
@@ -308,6 +308,7 @@ static struct drm_driver armada_drm_driver = {
        .postclose              = NULL,
        .lastclose              = armada_drm_lastclose,
        .unload                 = armada_drm_unload,
+       .set_busid              = drm_platform_set_busid,
        .get_vblank_counter     = drm_vblank_count,
        .enable_vblank          = armada_drm_enable_vblank,
        .disable_vblank         = armada_drm_disable_vblank,
index 00b6cd461a03c9c1caf91b7af5264adf46c8a91e..b000ea3a829af66ca88cbaf1d314267d95623e33 100644 (file)
@@ -8,6 +8,8 @@
 #ifndef ARMADA_GEM_H
 #define ARMADA_GEM_H
 
+#include <drm/drm_gem.h>
+
 /* GEM */
 struct armada_gem_object {
        struct drm_gem_object   obj;
index 5da4b62285fa2c690b5876e4265971b5dfd1640d..76f07f38b941f5e8ea3ad9255e8870b293bfab84 100644 (file)
@@ -379,11 +379,39 @@ static bool ast_init_dvo(struct drm_device *dev)
        return true;
 }
 
+
+static void ast_init_analog(struct drm_device *dev)
+{
+       struct ast_private *ast = dev->dev_private;
+       u32 data;
+
+       /*
+        * Set DAC source to VGA mode in SCU2C via the P2A
+        * bridge. First configure the P2U to target the SCU
+        * in case it isn't at this stage.
+        */
+       ast_write32(ast, 0xf004, 0x1e6e0000);
+       ast_write32(ast, 0xf000, 0x1);
+
+       /* Then unlock the SCU with the magic password */
+       ast_write32(ast, 0x12000, 0x1688a8a8);
+       ast_write32(ast, 0x12000, 0x1688a8a8);
+       ast_write32(ast, 0x12000, 0x1688a8a8);
+
+       /* Finally, clear bits [17:16] of SCU2c */
+       data = ast_read32(ast, 0x1202c);
+       data &= 0xfffcffff;
+       ast_write32(ast, 0, data);
+
+       /* Disable DVO */
+       ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xa3, 0xcf, 0x00);
+}
+
 void ast_init_3rdtx(struct drm_device *dev)
 {
        struct ast_private *ast = dev->dev_private;
        u8 jreg;
-       u32 data;
+
        if (ast->chip == AST2300 || ast->chip == AST2400) {
                jreg = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xd1, 0xff);
                switch (jreg & 0x0e) {
@@ -399,12 +427,8 @@ void ast_init_3rdtx(struct drm_device *dev)
                default:
                        if (ast->tx_chip_type == AST_TX_SIL164)
                                ast_init_dvo(dev);
-                       else {
-                               ast_write32(ast, 0x12000, 0x1688a8a8);
-                               data = ast_read32(ast, 0x1202c);
-                               data &= 0xfffcffff;
-                               ast_write32(ast, 0, data);
-                       }
+                       else
+                               ast_init_analog(dev);
                }
        }
 }
index f19682a93c243e3775fa96b6b0750334b97dd95f..9a32d9dfdd269aaa1918e4340b660b5b9567ef4d 100644 (file)
@@ -199,6 +199,7 @@ static struct drm_driver driver = {
 
        .load = ast_driver_load,
        .unload = ast_driver_unload,
+       .set_busid = drm_pci_set_busid,
 
        .fops = &ast_fops,
        .name = DRIVER_NAME,
index 957d4fabf1e1c2c8e58348a9af7f6ba6fcdd63c6..86205a28e56b79ceeb247949343f7117a08c393c 100644 (file)
@@ -36,6 +36,8 @@
 #include <drm/ttm/ttm_memory.h>
 #include <drm/ttm/ttm_module.h>
 
+#include <drm/drm_gem.h>
+
 #include <linux/i2c.h>
 #include <linux/i2c-algo-bit.h>
 
@@ -125,8 +127,9 @@ struct ast_gem_object;
 
 #define AST_IO_AR_PORT_WRITE           (0x40)
 #define AST_IO_MISC_PORT_WRITE         (0x42)
+#define AST_IO_VGA_ENABLE_PORT         (0x43)
 #define AST_IO_SEQ_PORT                        (0x44)
-#define AST_DAC_INDEX_READ             (0x3c7)
+#define AST_IO_DAC_INDEX_READ          (0x47)
 #define AST_IO_DAC_INDEX_WRITE         (0x48)
 #define AST_IO_DAC_DATA                        (0x49)
 #define AST_IO_GR_PORT                 (0x4E)
@@ -134,6 +137,8 @@ struct ast_gem_object;
 #define AST_IO_INPUT_STATUS1_READ      (0x5A)
 #define AST_IO_MISC_PORT_READ          (0x4C)
 
+#define AST_IO_MM_OFFSET               (0x380)
+
 #define __ast_read(x) \
 static inline u##x ast_read##x(struct ast_private *ast, u32 reg) { \
 u##x val = 0;\
@@ -316,7 +321,7 @@ struct ast_bo {
        struct ttm_placement placement;
        struct ttm_bo_kmap_obj kmap;
        struct drm_gem_object gem;
-       u32 placements[3];
+       struct ttm_place placements[3];
        int pin_count;
 };
 #define gem_to_ast_bo(gobj) container_of((gobj), struct ast_bo, gem)
@@ -381,6 +386,9 @@ int ast_bo_push_sysram(struct ast_bo *bo);
 int ast_mmap(struct file *filp, struct vm_area_struct *vma);
 
 /* ast post */
+void ast_enable_vga(struct drm_device *dev);
+void ast_enable_mmio(struct drm_device *dev);
+bool ast_is_vga_enabled(struct drm_device *dev);
 void ast_post_gpu(struct drm_device *dev);
 u32 ast_mindwm(struct ast_private *ast, u32 r);
 void ast_moutdwm(struct ast_private *ast, u32 r, u32 v);
index cba45c77455279ff0aaaad8974e815b06e9b9f5c..5c60ae524c454952316f9d8f8864cf8e52ce8cc4 100644 (file)
@@ -186,7 +186,8 @@ static int astfb_create_object(struct ast_fbdev *afbdev,
 static int astfb_create(struct drm_fb_helper *helper,
                        struct drm_fb_helper_surface_size *sizes)
 {
-       struct ast_fbdev *afbdev = (struct ast_fbdev *)helper;
+       struct ast_fbdev *afbdev =
+               container_of(helper, struct ast_fbdev, helper);
        struct drm_device *dev = afbdev->helper.dev;
        struct drm_mode_fb_cmd2 mode_cmd;
        struct drm_framebuffer *fb;
index b792194e0d9ceb6320457c99f270a67680a2d6d8..035dacc93382f0923a9d52c645a70cc192a6756e 100644 (file)
@@ -63,7 +63,7 @@ uint8_t ast_get_index_reg_mask(struct ast_private *ast,
 }
 
 
-static int ast_detect_chip(struct drm_device *dev)
+static int ast_detect_chip(struct drm_device *dev, bool *need_post)
 {
        struct ast_private *ast = dev->dev_private;
        uint32_t data, jreg;
@@ -110,6 +110,21 @@ static int ast_detect_chip(struct drm_device *dev)
                }
        }
 
+       /*
+        * If VGA isn't enabled, we need to enable now or subsequent
+        * access to the scratch registers will fail. We also inform
+        * our caller that it needs to POST the chip
+        * (Assumption: VGA not enabled -> need to POST)
+        */
+       if (!ast_is_vga_enabled(dev)) {
+               ast_enable_vga(dev);
+               ast_enable_mmio(dev);
+               DRM_INFO("VGA not enabled on entry, requesting chip POST\n");
+               *need_post = true;
+       } else
+               *need_post = false;
+
+       /* Check if we support wide screen */
        switch (ast->chip) {
        case AST1180:
                ast->support_wide_screen = true;
@@ -125,6 +140,7 @@ static int ast_detect_chip(struct drm_device *dev)
                        ast->support_wide_screen = true;
                else {
                        ast->support_wide_screen = false;
+                       /* Read SCU7c (silicon revision register) */
                        ast_write32(ast, 0xf004, 0x1e6e0000);
                        ast_write32(ast, 0xf000, 0x1);
                        data = ast_read32(ast, 0x1207c);
@@ -137,11 +153,29 @@ static int ast_detect_chip(struct drm_device *dev)
                break;
        }
 
+       /* Check 3rd Tx option (digital output afaik) */
        ast->tx_chip_type = AST_TX_NONE;
-       jreg = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xa3, 0xff);
-       if (jreg & 0x80)
-               ast->tx_chip_type = AST_TX_SIL164;
+
+       /*
+        * VGACRA3 Enhanced Color Mode Register, check if DVO is already
+        * enabled, in that case, assume we have a SIL164 TMDS transmitter
+        *
+        * Don't make that assumption if we the chip wasn't enabled and
+        * is at power-on reset, otherwise we'll incorrectly "detect" a
+        * SIL164 when there is none.
+        */
+       if (!*need_post) {
+               jreg = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xa3, 0xff);
+               if (jreg & 0x80)
+                       ast->tx_chip_type = AST_TX_SIL164;
+       }
+
        if ((ast->chip == AST2300) || (ast->chip == AST2400)) {
+               /*
+                * On AST2300 and 2400, look the configuration set by the SoC in
+                * the SOC scratch register #1 bits 11:8 (interestingly marked
+                * as "reserved" in the spec)
+                */
                jreg = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xd1, 0xff);
                switch (jreg) {
                case 0x04:
@@ -162,6 +196,17 @@ static int ast_detect_chip(struct drm_device *dev)
                }
        }
 
+       /* Print stuff for diagnostic purposes */
+       switch(ast->tx_chip_type) {
+       case AST_TX_SIL164:
+               DRM_INFO("Using Sil164 TMDS transmitter\n");
+               break;
+       case AST_TX_DP501:
+               DRM_INFO("Using DP501 DisplayPort transmitter\n");
+               break;
+       default:
+               DRM_INFO("Analog VGA only\n");
+       }
        return 0;
 }
 
@@ -346,6 +391,7 @@ static u32 ast_get_vram_info(struct drm_device *dev)
 int ast_driver_load(struct drm_device *dev, unsigned long flags)
 {
        struct ast_private *ast;
+       bool need_post;
        int ret = 0;
 
        ast = kzalloc(sizeof(struct ast_private), GFP_KERNEL);
@@ -360,13 +406,27 @@ int ast_driver_load(struct drm_device *dev, unsigned long flags)
                ret = -EIO;
                goto out_free;
        }
-       ast->ioregs = pci_iomap(dev->pdev, 2, 0);
+
+       /*
+        * If we don't have IO space at all, use MMIO now and
+        * assume the chip has MMIO enabled by default (rev 0x20
+        * and higher).
+        */
+       if (!(pci_resource_flags(dev->pdev, 2) & IORESOURCE_IO)) {
+               DRM_INFO("platform has no IO space, trying MMIO\n");
+               ast->ioregs = ast->regs + AST_IO_MM_OFFSET;
+       }
+
+       /* "map" IO regs if the above hasn't done so already */
        if (!ast->ioregs) {
-               ret = -EIO;
-               goto out_free;
+               ast->ioregs = pci_iomap(dev->pdev, 2, 0);
+               if (!ast->ioregs) {
+                       ret = -EIO;
+                       goto out_free;
+               }
        }
 
-       ast_detect_chip(dev);
+       ast_detect_chip(dev, &need_post);
 
        if (ast->chip != AST1180) {
                ast_get_dram_info(dev);
@@ -374,6 +434,9 @@ int ast_driver_load(struct drm_device *dev, unsigned long flags)
                DRM_INFO("dram %d %d %d %08x\n", ast->mclk, ast->dram_type, ast->dram_bus_width, ast->vram_size);
        }
 
+       if (need_post)
+               ast_post_gpu(dev);
+
        ret = ast_mm_init(ast);
        if (ret)
                goto out_free;
index 5389350244f216fac07c5d98723ee2632c627e89..9dc0fd5c1ea4ef7741eaad8e85a65ea280096caf 100644 (file)
@@ -80,6 +80,8 @@ static bool ast_get_vbios_mode_info(struct drm_crtc *crtc, struct drm_display_mo
        struct ast_private *ast = crtc->dev->dev_private;
        u32 refresh_rate_index = 0, mode_id, color_index, refresh_rate;
        u32 hborder, vborder;
+       bool check_sync;
+       struct ast_vbios_enhtable *best = NULL;
 
        switch (crtc->primary->fb->bits_per_pixel) {
        case 8:
@@ -141,14 +143,34 @@ static bool ast_get_vbios_mode_info(struct drm_crtc *crtc, struct drm_display_mo
        }
 
        refresh_rate = drm_mode_vrefresh(mode);
-       while (vbios_mode->enh_table->refresh_rate < refresh_rate) {
-               vbios_mode->enh_table++;
-               if ((vbios_mode->enh_table->refresh_rate > refresh_rate) ||
-                   (vbios_mode->enh_table->refresh_rate == 0xff)) {
-                       vbios_mode->enh_table--;
-                       break;
+       check_sync = vbios_mode->enh_table->flags & WideScreenMode;
+       do {
+               struct ast_vbios_enhtable *loop = vbios_mode->enh_table;
+
+               while (loop->refresh_rate != 0xff) {
+                       if ((check_sync) &&
+                           (((mode->flags & DRM_MODE_FLAG_NVSYNC)  &&
+                             (loop->flags & PVSync))  ||
+                            ((mode->flags & DRM_MODE_FLAG_PVSYNC)  &&
+                             (loop->flags & NVSync))  ||
+                            ((mode->flags & DRM_MODE_FLAG_NHSYNC)  &&
+                             (loop->flags & PHSync))  ||
+                            ((mode->flags & DRM_MODE_FLAG_PHSYNC)  &&
+                             (loop->flags & NHSync)))) {
+                               loop++;
+                               continue;
+                       }
+                       if (loop->refresh_rate <= refresh_rate
+                           && (!best || loop->refresh_rate > best->refresh_rate))
+                               best = loop;
+                       loop++;
                }
-       }
+               if (best || !check_sync)
+                       break;
+               check_sync = 0;
+       } while (1);
+       if (best)
+               vbios_mode->enh_table = best;
 
        hborder = (vbios_mode->enh_table->flags & HBorder) ? 8 : 0;
        vborder = (vbios_mode->enh_table->flags & VBorder) ? 8 : 0;
@@ -419,8 +441,10 @@ static void ast_set_sync_reg(struct drm_device *dev, struct drm_display_mode *mo
        struct ast_private *ast = dev->dev_private;
        u8 jreg;
 
-       jreg = ast_io_read8(ast, AST_IO_MISC_PORT_READ);
-       jreg |= (vbios_mode->enh_table->flags & SyncNN);
+       jreg  = ast_io_read8(ast, AST_IO_MISC_PORT_READ);
+       jreg &= ~0xC0;
+       if (vbios_mode->enh_table->flags & NVSync) jreg |= 0x80;
+       if (vbios_mode->enh_table->flags & NHSync) jreg |= 0x40;
        ast_io_write8(ast, AST_IO_MISC_PORT_WRITE, jreg);
 }
 
@@ -1080,8 +1104,8 @@ static u32 copy_cursor_image(u8 *src, u8 *dst, int width, int height)
                        srcdata32[1].ul = *((u32 *)(srcxor + 4)) & 0xf0f0f0f0;
                        data32.b[0] = srcdata32[0].b[1] | (srcdata32[0].b[0] >> 4);
                        data32.b[1] = srcdata32[0].b[3] | (srcdata32[0].b[2] >> 4);
-                       data32.b[2] = srcdata32[0].b[1] | (srcdata32[1].b[0] >> 4);
-                       data32.b[3] = srcdata32[0].b[3] | (srcdata32[1].b[2] >> 4);
+                       data32.b[2] = srcdata32[1].b[1] | (srcdata32[1].b[0] >> 4);
+                       data32.b[3] = srcdata32[1].b[3] | (srcdata32[1].b[2] >> 4);
 
                        writel(data32.ul, dstxor);
                        csum += data32.ul;
index 38d437f3a267493fd097da14aa0a05d6cda68a99..810c51d92b99f81a441f37d02e319ed25b7768e5 100644 (file)
 
 static void ast_init_dram_2300(struct drm_device *dev);
 
-static void
-ast_enable_vga(struct drm_device *dev)
+void ast_enable_vga(struct drm_device *dev)
+{
+       struct ast_private *ast = dev->dev_private;
+
+       ast_io_write8(ast, AST_IO_VGA_ENABLE_PORT, 0x01);
+       ast_io_write8(ast, AST_IO_MISC_PORT_WRITE, 0x01);
+}
+
+void ast_enable_mmio(struct drm_device *dev)
 {
        struct ast_private *ast = dev->dev_private;
 
-       ast_io_write8(ast, 0x43, 0x01);
-       ast_io_write8(ast, 0x42, 0x01);
+       ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xa1, 0xff, 0x04);
 }
 
-#if 0 /* will use later */
-static bool
-ast_is_vga_enabled(struct drm_device *dev)
+
+bool ast_is_vga_enabled(struct drm_device *dev)
 {
        struct ast_private *ast = dev->dev_private;
        u8 ch;
@@ -52,7 +57,7 @@ ast_is_vga_enabled(struct drm_device *dev)
        if (ast->chip == AST1180) {
                /* TODO 1180 */
        } else {
-               ch = ast_io_read8(ast, 0x43);
+               ch = ast_io_read8(ast, AST_IO_VGA_ENABLE_PORT);
                if (ch) {
                        ast_open_key(ast);
                        ch = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xb6, 0xff);
@@ -61,7 +66,6 @@ ast_is_vga_enabled(struct drm_device *dev)
        }
        return 0;
 }
-#endif
 
 static const u8 extreginfo[] = { 0x0f, 0x04, 0x1c, 0xff };
 static const u8 extreginfo_ast2300a0[] = { 0x0f, 0x04, 0x1c, 0xff };
@@ -371,6 +375,7 @@ void ast_post_gpu(struct drm_device *dev)
        pci_write_config_dword(ast->dev->pdev, 0x04, reg);
 
        ast_enable_vga(dev);
+       ast_enable_mmio(dev);
        ast_open_key(ast);
        ast_set_def_ext_reg(dev);
 
index 05c01ea8529487c9d37f32cd31237291728c82c9..3608d5aa7451a458a07fcfe3199ce3984108992b 100644 (file)
 #define HalfDCLK                0x00000002
 #define DoubleScanMode          0x00000004
 #define LineCompareOff          0x00000008
-#define SyncPP                  0x00000000
-#define SyncPN                  0x00000040
-#define SyncNP                  0x00000080
-#define SyncNN                  0x000000C0
 #define HBorder                 0x00000020
 #define VBorder                 0x00000010
 #define WideScreenMode         0x00000100
 #define NewModeInfo            0x00000200
+#define NHSync                 0x00000400
+#define PHSync                 0x00000800
+#define NVSync                 0x00001000
+#define PVSync                 0x00002000
+#define SyncPP                 (PVSync | PHSync)
+#define SyncPN                 (PVSync | NHSync)
+#define SyncNP                 (NVSync | PHSync)
+#define SyncNN                 (NVSync | NHSync)
 
 /* DCLK Index */
 #define VCLK25_175                     0x00
@@ -72,6 +76,7 @@
 #define VCLK119                0x17
 #define VCLK85_5               0x18
 #define VCLK97_75              0x19
+#define VCLK118_25                     0x1A
 
 static struct ast_vbios_dclk_info dclk_table[] = {
        {0x2C, 0xE7, 0x03},                                     /* 00: VCLK25_175       */
@@ -100,6 +105,7 @@ static struct ast_vbios_dclk_info dclk_table[] = {
        {0x77, 0x58, 0x80},                                     /* 17: VCLK119      */
        {0x32, 0x67, 0x80},                                 /* 18: VCLK85_5     */
        {0x6a, 0x6d, 0x80},                                     /* 19: VCLK97_75        */
+       {0x3b, 0x2c, 0x81},                                     /* 1A: VCLK118_25       */
 };
 
 static struct ast_vbios_stdtable vbios_stdtable[] = {
@@ -246,8 +252,10 @@ static struct ast_vbios_enhtable res_1360x768[] = {
 static struct ast_vbios_enhtable res_1600x900[] = {
        {1760, 1600, 48, 32, 926,  900, 3, 5, VCLK97_75,        /* 60Hz CVT RB */
         (SyncNP | Charx8Dot | LineCompareOff | WideScreenMode | NewModeInfo), 60, 1, 0x3A },
-       {1760, 1600, 48, 32, 926,  900, 3, 5, VCLK97_75,        /* end */
-        (SyncNP | Charx8Dot | LineCompareOff | WideScreenMode | NewModeInfo), 0xFF, 1, 0x3A }
+       {2112, 1600, 88,168, 934,  900, 3, 5, VCLK118_25,       /* 60Hz CVT */
+        (SyncPN | Charx8Dot | LineCompareOff | WideScreenMode | NewModeInfo), 60, 2, 0x3A },
+       {2112, 1600, 88,168, 934,  900, 3, 5, VCLK118_25,       /* 60Hz CVT */
+        (SyncPN | Charx8Dot | LineCompareOff | WideScreenMode | NewModeInfo), 0xFF, 2, 0x3A },
 };
 
 static struct ast_vbios_enhtable res_1920x1080[] = {
@@ -261,11 +269,11 @@ static struct ast_vbios_enhtable res_1920x1080[] = {
 /* 16:10 */
 static struct ast_vbios_enhtable res_1280x800[] = {
        {1440, 1280, 48, 32,  823,  800, 3, 6, VCLK71,  /* 60Hz RB */
-        (SyncNP | Charx8Dot | LineCompareOff | WideScreenMode | NewModeInfo), 60, 1, 35 },
+        (SyncNP | Charx8Dot | LineCompareOff | WideScreenMode | NewModeInfo), 60, 1, 0x35 },
        {1680, 1280, 72,128,  831,  800, 3, 6, VCLK83_5,        /* 60Hz */
-        (SyncPN | Charx8Dot | LineCompareOff | WideScreenMode | NewModeInfo), 60, 1, 0x35 },
+        (SyncPN | Charx8Dot | LineCompareOff | WideScreenMode | NewModeInfo), 60, 2, 0x35 },
        {1680, 1280, 72,128,  831,  800, 3, 6, VCLK83_5,        /* 60Hz */
-        (SyncPN | Charx8Dot | LineCompareOff | WideScreenMode | NewModeInfo), 0xFF, 1, 0x35 },
+        (SyncPN | Charx8Dot | LineCompareOff | WideScreenMode | NewModeInfo), 0xFF, 2, 0x35 },
 
 };
 
@@ -273,24 +281,24 @@ static struct ast_vbios_enhtable res_1440x900[] = {
        {1600, 1440, 48, 32,  926,  900, 3, 6, VCLK88_75,       /* 60Hz RB */
         (SyncNP | Charx8Dot | LineCompareOff | WideScreenMode | NewModeInfo), 60, 1, 0x36 },
        {1904, 1440, 80,152,  934,  900, 3, 6, VCLK106_5,       /* 60Hz */
-        (SyncPN | Charx8Dot | LineCompareOff | WideScreenMode | NewModeInfo), 60, 1, 0x36 },
+        (SyncPN | Charx8Dot | LineCompareOff | WideScreenMode | NewModeInfo), 60, 2, 0x36 },
        {1904, 1440, 80,152,  934,  900, 3, 6, VCLK106_5,       /* 60Hz */
-        (SyncPN | Charx8Dot | LineCompareOff | WideScreenMode | NewModeInfo), 0xFF, 1, 0x36 },
+        (SyncPN | Charx8Dot | LineCompareOff | WideScreenMode | NewModeInfo), 0xFF, 2, 0x36 },
 };
 
 static struct ast_vbios_enhtable res_1680x1050[] = {
        {1840, 1680, 48, 32, 1080, 1050, 3, 6, VCLK119, /* 60Hz RB */
         (SyncNP | Charx8Dot | LineCompareOff | WideScreenMode | NewModeInfo), 60, 1, 0x37 },
        {2240, 1680,104,176, 1089, 1050, 3, 6, VCLK146_25,      /* 60Hz */
-        (SyncPN | Charx8Dot | LineCompareOff | WideScreenMode | NewModeInfo), 60, 1, 0x37 },
+        (SyncPN | Charx8Dot | LineCompareOff | WideScreenMode | NewModeInfo), 60, 2, 0x37 },
        {2240, 1680,104,176, 1089, 1050, 3, 6, VCLK146_25,      /* 60Hz */
-        (SyncPN | Charx8Dot | LineCompareOff | WideScreenMode | NewModeInfo), 0xFF, 1, 0x37 },
+        (SyncPN | Charx8Dot | LineCompareOff | WideScreenMode | NewModeInfo), 0xFF, 2, 0x37 },
 };
 
 static struct ast_vbios_enhtable res_1920x1200[] = {
-       {2080, 1920, 48, 32, 1235, 1200, 3, 6, VCLK154, /* 60Hz */
+       {2080, 1920, 48, 32, 1235, 1200, 3, 6, VCLK154, /* 60Hz RB*/
         (SyncNP | Charx8Dot | LineCompareOff | WideScreenMode | NewModeInfo), 60, 1, 0x34 },
-       {2080, 1920, 48, 32, 1235, 1200, 3, 6, VCLK154, /* 60Hz */
+       {2080, 1920, 48, 32, 1235, 1200, 3, 6, VCLK154, /* 60Hz RB */
         (SyncNP | Charx8Dot | LineCompareOff | WideScreenMode | NewModeInfo), 0xFF, 1, 0x34 },
 };
 
index b8246227bab009e042ebb46e3a4bb093301ffcec..08f82eae69398509a7daf55d55a4a94a4e57b6f4 100644 (file)
@@ -293,18 +293,22 @@ void ast_mm_fini(struct ast_private *ast)
 void ast_ttm_placement(struct ast_bo *bo, int domain)
 {
        u32 c = 0;
-       bo->placement.fpfn = 0;
-       bo->placement.lpfn = 0;
+       unsigned i;
+
        bo->placement.placement = bo->placements;
        bo->placement.busy_placement = bo->placements;
        if (domain & TTM_PL_FLAG_VRAM)
-               bo->placements[c++] = TTM_PL_FLAG_WC | TTM_PL_FLAG_UNCACHED | TTM_PL_FLAG_VRAM;
+               bo->placements[c++].flags = TTM_PL_FLAG_WC | TTM_PL_FLAG_UNCACHED | TTM_PL_FLAG_VRAM;
        if (domain & TTM_PL_FLAG_SYSTEM)
-               bo->placements[c++] = TTM_PL_MASK_CACHING | TTM_PL_FLAG_SYSTEM;
+               bo->placements[c++].flags = TTM_PL_FLAG_CACHED | TTM_PL_FLAG_SYSTEM;
        if (!c)
-               bo->placements[c++] = TTM_PL_MASK_CACHING | TTM_PL_FLAG_SYSTEM;
+               bo->placements[c++].flags = TTM_PL_FLAG_CACHED | TTM_PL_FLAG_SYSTEM;
        bo->placement.num_placement = c;
        bo->placement.num_busy_placement = c;
+       for (i = 0; i < c; ++i) {
+               bo->placements[i].fpfn = 0;
+               bo->placements[i].lpfn = 0;
+       }
 }
 
 int ast_bo_create(struct drm_device *dev, int size, int align,
@@ -335,7 +339,7 @@ int ast_bo_create(struct drm_device *dev, int size, int align,
        ret = ttm_bo_init(&ast->ttm.bdev, &astbo->bo, size,
                          ttm_bo_type_device, &astbo->placement,
                          align >> PAGE_SHIFT, false, NULL, acc_size,
-                         NULL, ast_bo_ttm_destroy);
+                         NULL, NULL, ast_bo_ttm_destroy);
        if (ret)
                return ret;
 
@@ -360,7 +364,7 @@ int ast_bo_pin(struct ast_bo *bo, u32 pl_flag, u64 *gpu_addr)
 
        ast_ttm_placement(bo, pl_flag);
        for (i = 0; i < bo->placement.num_placement; i++)
-               bo->placements[i] |= TTM_PL_FLAG_NO_EVICT;
+               bo->placements[i].flags |= TTM_PL_FLAG_NO_EVICT;
        ret = ttm_bo_validate(&bo->bo, &bo->placement, false, false);
        if (ret)
                return ret;
@@ -383,7 +387,7 @@ int ast_bo_unpin(struct ast_bo *bo)
                return 0;
 
        for (i = 0; i < bo->placement.num_placement ; i++)
-               bo->placements[i] &= ~TTM_PL_FLAG_NO_EVICT;
+               bo->placements[i].flags &= ~TTM_PL_FLAG_NO_EVICT;
        ret = ttm_bo_validate(&bo->bo, &bo->placement, false, false);
        if (ret)
                return ret;
@@ -407,7 +411,7 @@ int ast_bo_push_sysram(struct ast_bo *bo)
 
        ast_ttm_placement(bo, TTM_PL_FLAG_SYSTEM);
        for (i = 0; i < bo->placement.num_placement ; i++)
-               bo->placements[i] |= TTM_PL_FLAG_NO_EVICT;
+               bo->placements[i].flags |= TTM_PL_FLAG_NO_EVICT;
 
        ret = ttm_bo_validate(&bo->bo, &bo->placement, false, false);
        if (ret) {
@@ -423,7 +427,7 @@ int ast_mmap(struct file *filp, struct vm_area_struct *vma)
        struct ast_private *ast;
 
        if (unlikely(vma->vm_pgoff < DRM_FILE_PAGE_OFFSET))
-               return drm_mmap(filp, vma);
+               return -EINVAL;
 
        file_priv = filp->private_data;
        ast = file_priv->minor->dev->dev_private;
index c399dea27a3b0e2b74913a7369075070cf4d720e..6c4d4b6eba80a94e1cd4d42f746ae22c63aae80c 100644 (file)
@@ -34,6 +34,8 @@
 #include <linux/export.h>
 #include <drm/drmP.h>
 
+#include <drm/ati_pcigart.h>
+
 # define ATI_PCIGART_PAGE_SIZE         4096    /**< PCI GART page size */
 
 static int drm_ati_alloc_pcigart_table(struct drm_device *dev,
index 7eb52dd44b0109340c7add338c5e0babb175dd79..71f2687fc3ccc44fff4dd555cdfac7dd9f63d2b9 100644 (file)
@@ -7,6 +7,8 @@
 #include <drm/drm_crtc_helper.h>
 #include <drm/drm_fb_helper.h>
 
+#include <drm/drm_gem.h>
+
 #include <ttm/ttm_bo_driver.h>
 #include <ttm/ttm_page_alloc.h>
 
@@ -99,7 +101,7 @@ struct bochs_bo {
        struct ttm_placement placement;
        struct ttm_bo_kmap_obj kmap;
        struct drm_gem_object gem;
-       u32 placements[3];
+       struct ttm_place placements[3];
        int pin_count;
 };
 
index 9738e9b14708d7a59b549dc1717c6f8716fefeff..98837bde2d2528356c2764b27fe5ac3721c51817 100644 (file)
@@ -82,6 +82,7 @@ static struct drm_driver bochs_driver = {
        .driver_features        = DRIVER_GEM | DRIVER_MODESET,
        .load                   = bochs_load,
        .unload                 = bochs_unload,
+       .set_busid              = drm_pci_set_busid,
        .fops                   = &bochs_fops,
        .name                   = "bochs-drm",
        .desc                   = "bochs dispi vga interface (qemu stdvga)",
index 1728a1b0b81376ed43e7f39fb5f863cba7563166..66286ff518d4be28e8b71b2b8ebf0d0b2ada6496 100644 (file)
@@ -257,20 +257,26 @@ void bochs_mm_fini(struct bochs_device *bochs)
 
 static void bochs_ttm_placement(struct bochs_bo *bo, int domain)
 {
+       unsigned i;
        u32 c = 0;
-       bo->placement.fpfn = 0;
-       bo->placement.lpfn = 0;
        bo->placement.placement = bo->placements;
        bo->placement.busy_placement = bo->placements;
        if (domain & TTM_PL_FLAG_VRAM) {
-               bo->placements[c++] = TTM_PL_FLAG_WC | TTM_PL_FLAG_UNCACHED
+               bo->placements[c++].flags = TTM_PL_FLAG_WC
+                       | TTM_PL_FLAG_UNCACHED
                        | TTM_PL_FLAG_VRAM;
        }
        if (domain & TTM_PL_FLAG_SYSTEM) {
-               bo->placements[c++] = TTM_PL_MASK_CACHING | TTM_PL_FLAG_SYSTEM;
+               bo->placements[c++].flags = TTM_PL_MASK_CACHING
+                       | TTM_PL_FLAG_SYSTEM;
        }
        if (!c) {
-               bo->placements[c++] = TTM_PL_MASK_CACHING | TTM_PL_FLAG_SYSTEM;
+               bo->placements[c++].flags = TTM_PL_MASK_CACHING
+                       | TTM_PL_FLAG_SYSTEM;
+       }
+       for (i = 0; i < c; ++i) {
+               bo->placements[i].fpfn = 0;
+               bo->placements[i].lpfn = 0;
        }
        bo->placement.num_placement = c;
        bo->placement.num_busy_placement = c;
@@ -294,7 +300,7 @@ int bochs_bo_pin(struct bochs_bo *bo, u32 pl_flag, u64 *gpu_addr)
 
        bochs_ttm_placement(bo, pl_flag);
        for (i = 0; i < bo->placement.num_placement; i++)
-               bo->placements[i] |= TTM_PL_FLAG_NO_EVICT;
+               bo->placements[i].flags |= TTM_PL_FLAG_NO_EVICT;
        ret = ttm_bo_validate(&bo->bo, &bo->placement, false, false);
        if (ret)
                return ret;
@@ -319,7 +325,7 @@ int bochs_bo_unpin(struct bochs_bo *bo)
                return 0;
 
        for (i = 0; i < bo->placement.num_placement; i++)
-               bo->placements[i] &= ~TTM_PL_FLAG_NO_EVICT;
+               bo->placements[i].flags &= ~TTM_PL_FLAG_NO_EVICT;
        ret = ttm_bo_validate(&bo->bo, &bo->placement, false, false);
        if (ret)
                return ret;
@@ -333,7 +339,7 @@ int bochs_mmap(struct file *filp, struct vm_area_struct *vma)
        struct bochs_device *bochs;
 
        if (unlikely(vma->vm_pgoff < DRM_FILE_PAGE_OFFSET))
-               return drm_mmap(filp, vma);
+               return -EINVAL;
 
        file_priv = filp->private_data;
        bochs = file_priv->minor->dev->dev_private;
@@ -371,7 +377,7 @@ static int bochs_bo_create(struct drm_device *dev, int size, int align,
        ret = ttm_bo_init(&bochs->ttm.bdev, &bochsbo->bo, size,
                          ttm_bo_type_device, &bochsbo->placement,
                          align >> PAGE_SHIFT, false, NULL, acc_size,
-                         NULL, bochs_bo_ttm_destroy);
+                         NULL, NULL, bochs_bo_ttm_destroy);
        if (ret)
                return ret;
 
index 919c73b9444723eee3bfcfa71408c55e9cb9f631..e705335101a59ea0a703d9b699d8ea7af9eafcb5 100644 (file)
@@ -128,6 +128,7 @@ static struct drm_driver driver = {
        .driver_features = DRIVER_MODESET | DRIVER_GEM,
        .load = cirrus_driver_load,
        .unload = cirrus_driver_unload,
+       .set_busid = drm_pci_set_busid,
        .fops = &cirrus_driver_fops,
        .name = DRIVER_NAME,
        .desc = DRIVER_DESC,
index 401c890b6c6a817011923215706a9f2e259d4d71..d44e69daa23966c0e2f38332069a81cc24070d0a 100644 (file)
@@ -21,6 +21,8 @@
 #include <drm/ttm/ttm_memory.h>
 #include <drm/ttm/ttm_module.h>
 
+#include <drm/drm_gem.h>
+
 #define DRIVER_AUTHOR          "Matthew Garrett"
 
 #define DRIVER_NAME            "cirrus"
@@ -163,7 +165,7 @@ struct cirrus_bo {
        struct ttm_placement placement;
        struct ttm_bo_kmap_obj kmap;
        struct drm_gem_object gem;
-       u32 placements[3];
+       struct ttm_place placements[3];
        int pin_count;
 };
 #define gem_to_cirrus_bo(gobj) container_of((gobj), struct cirrus_bo, gem)
index 2a135f253e2930dd4d06da29b1a6a0da166969a6..d231b1c317afac94476e572b9560566311a38168 100644 (file)
@@ -160,7 +160,8 @@ static int cirrusfb_create_object(struct cirrus_fbdev *afbdev,
 static int cirrusfb_create(struct drm_fb_helper *helper,
                           struct drm_fb_helper_surface_size *sizes)
 {
-       struct cirrus_fbdev *gfbdev = (struct cirrus_fbdev *)helper;
+       struct cirrus_fbdev *gfbdev =
+               container_of(helper, struct cirrus_fbdev, helper);
        struct drm_device *dev = gfbdev->helper.dev;
        struct cirrus_device *cdev = gfbdev->helper.dev->dev_private;
        struct fb_info *info;
index 92e6b77860970097b30bb745859d7a020661eefa..dfffd528517a53b1783e8f5c22d1f622d1e7d537 100644 (file)
@@ -298,18 +298,21 @@ void cirrus_mm_fini(struct cirrus_device *cirrus)
 void cirrus_ttm_placement(struct cirrus_bo *bo, int domain)
 {
        u32 c = 0;
-       bo->placement.fpfn = 0;
-       bo->placement.lpfn = 0;
+       unsigned i;
        bo->placement.placement = bo->placements;
        bo->placement.busy_placement = bo->placements;
        if (domain & TTM_PL_FLAG_VRAM)
-               bo->placements[c++] = TTM_PL_FLAG_WC | TTM_PL_FLAG_UNCACHED | TTM_PL_FLAG_VRAM;
+               bo->placements[c++].flags = TTM_PL_FLAG_WC | TTM_PL_FLAG_UNCACHED | TTM_PL_FLAG_VRAM;
        if (domain & TTM_PL_FLAG_SYSTEM)
-               bo->placements[c++] = TTM_PL_MASK_CACHING | TTM_PL_FLAG_SYSTEM;
+               bo->placements[c++].flags = TTM_PL_MASK_CACHING | TTM_PL_FLAG_SYSTEM;
        if (!c)
-               bo->placements[c++] = TTM_PL_MASK_CACHING | TTM_PL_FLAG_SYSTEM;
+               bo->placements[c++].flags = TTM_PL_MASK_CACHING | TTM_PL_FLAG_SYSTEM;
        bo->placement.num_placement = c;
        bo->placement.num_busy_placement = c;
+       for (i = 0; i < c; ++i) {
+               bo->placements[i].fpfn = 0;
+               bo->placements[i].lpfn = 0;
+       }
 }
 
 int cirrus_bo_create(struct drm_device *dev, int size, int align,
@@ -340,7 +343,7 @@ int cirrus_bo_create(struct drm_device *dev, int size, int align,
        ret = ttm_bo_init(&cirrus->ttm.bdev, &cirrusbo->bo, size,
                          ttm_bo_type_device, &cirrusbo->placement,
                          align >> PAGE_SHIFT, false, NULL, acc_size,
-                         NULL, cirrus_bo_ttm_destroy);
+                         NULL, NULL, cirrus_bo_ttm_destroy);
        if (ret)
                return ret;
 
@@ -365,7 +368,7 @@ int cirrus_bo_pin(struct cirrus_bo *bo, u32 pl_flag, u64 *gpu_addr)
 
        cirrus_ttm_placement(bo, pl_flag);
        for (i = 0; i < bo->placement.num_placement; i++)
-               bo->placements[i] |= TTM_PL_FLAG_NO_EVICT;
+               bo->placements[i].flags |= TTM_PL_FLAG_NO_EVICT;
        ret = ttm_bo_validate(&bo->bo, &bo->placement, false, false);
        if (ret)
                return ret;
@@ -392,7 +395,7 @@ int cirrus_bo_push_sysram(struct cirrus_bo *bo)
 
        cirrus_ttm_placement(bo, TTM_PL_FLAG_SYSTEM);
        for (i = 0; i < bo->placement.num_placement ; i++)
-               bo->placements[i] |= TTM_PL_FLAG_NO_EVICT;
+               bo->placements[i].flags |= TTM_PL_FLAG_NO_EVICT;
 
        ret = ttm_bo_validate(&bo->bo, &bo->placement, false, false);
        if (ret) {
@@ -408,7 +411,7 @@ int cirrus_mmap(struct file *filp, struct vm_area_struct *vma)
        struct cirrus_device *cirrus;
 
        if (unlikely(vma->vm_pgoff < DRM_FILE_PAGE_OFFSET))
-               return drm_mmap(filp, vma);
+               return -EINVAL;
 
        file_priv = filp->private_data;
        cirrus = file_priv->minor->dev->dev_private;
index dde205cef384c08db92d114c16138c607ddc1da0..4b2b4aa5033ba1d6988f4f2c7dfc1ae605d82da5 100644 (file)
@@ -34,6 +34,7 @@
 #include <drm/drmP.h>
 #include <linux/module.h>
 #include <linux/slab.h>
+#include "drm_legacy.h"
 
 #if __OS_HAS_AGP
 
index 3cedae12b3c1f845084894cd4c8f2fe819cb1070..fc8e8aaa34fb37f44e338bb237867078d84c020f 100644 (file)
  */
 
 #include <drm/drmP.h>
+#include "drm_internal.h"
+
+struct drm_magic_entry {
+       struct list_head head;
+       struct drm_hash_item hash_item;
+       struct drm_file *priv;
+};
 
 /**
  * Find the file with the given magic number.
diff --git a/drivers/gpu/drm/drm_buffer.c b/drivers/gpu/drm/drm_buffer.c
deleted file mode 100644 (file)
index 86a4a4a..0000000
+++ /dev/null
@@ -1,181 +0,0 @@
-/**************************************************************************
- *
- * Copyright 2010 Pauli Nieminen.
- * All Rights Reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sub license, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice (including the
- * next paragraph) shall be included in all copies or substantial portions
- * of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS 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.
- *
- *
- **************************************************************************/
-/*
- * Multipart buffer for coping data which is larger than the page size.
- *
- * Authors:
- * Pauli Nieminen <suokkos-at-gmail-dot-com>
- */
-
-#include <linux/export.h>
-#include <drm/drm_buffer.h>
-
-/**
- * Allocate the drm buffer object.
- *
- *   buf: Pointer to a pointer where the object is stored.
- *   size: The number of bytes to allocate.
- */
-int drm_buffer_alloc(struct drm_buffer **buf, int size)
-{
-       int nr_pages = size / PAGE_SIZE + 1;
-       int idx;
-
-       /* Allocating pointer table to end of structure makes drm_buffer
-        * variable sized */
-       *buf = kzalloc(sizeof(struct drm_buffer) + nr_pages*sizeof(char *),
-                       GFP_KERNEL);
-
-       if (*buf == NULL) {
-               DRM_ERROR("Failed to allocate drm buffer object to hold"
-                               " %d bytes in %d pages.\n",
-                               size, nr_pages);
-               return -ENOMEM;
-       }
-
-       (*buf)->size = size;
-
-       for (idx = 0; idx < nr_pages; ++idx) {
-
-               (*buf)->data[idx] =
-                       kmalloc(min(PAGE_SIZE, size - idx * PAGE_SIZE),
-                               GFP_KERNEL);
-
-
-               if ((*buf)->data[idx] == NULL) {
-                       DRM_ERROR("Failed to allocate %dth page for drm"
-                                       " buffer with %d bytes and %d pages.\n",
-                                       idx + 1, size, nr_pages);
-                       goto error_out;
-               }
-
-       }
-
-       return 0;
-
-error_out:
-
-       for (; idx >= 0; --idx)
-               kfree((*buf)->data[idx]);
-
-       kfree(*buf);
-       return -ENOMEM;
-}
-EXPORT_SYMBOL(drm_buffer_alloc);
-
-/**
- * Copy the user data to the begin of the buffer and reset the processing
- * iterator.
- *
- *   user_data: A pointer the data that is copied to the buffer.
- *   size: The Number of bytes to copy.
- */
-int drm_buffer_copy_from_user(struct drm_buffer *buf,
-                             void __user *user_data, int size)
-{
-       int nr_pages = size / PAGE_SIZE + 1;
-       int idx;
-
-       if (size > buf->size) {
-               DRM_ERROR("Requesting to copy %d bytes to a drm buffer with"
-                               " %d bytes space\n",
-                               size, buf->size);
-               return -EFAULT;
-       }
-
-       for (idx = 0; idx < nr_pages; ++idx) {
-
-               if (copy_from_user(buf->data[idx],
-                       user_data + idx * PAGE_SIZE,
-                       min(PAGE_SIZE, size - idx * PAGE_SIZE))) {
-                       DRM_ERROR("Failed to copy user data (%p) to drm buffer"
-                                       " (%p) %dth page.\n",
-                                       user_data, buf, idx);
-                       return -EFAULT;
-
-               }
-       }
-       buf->iterator = 0;
-       return 0;
-}
-EXPORT_SYMBOL(drm_buffer_copy_from_user);
-
-/**
- * Free the drm buffer object
- */
-void drm_buffer_free(struct drm_buffer *buf)
-{
-
-       if (buf != NULL) {
-
-               int nr_pages = buf->size / PAGE_SIZE + 1;
-               int idx;
-               for (idx = 0; idx < nr_pages; ++idx)
-                       kfree(buf->data[idx]);
-
-               kfree(buf);
-       }
-}
-EXPORT_SYMBOL(drm_buffer_free);
-
-/**
- * Read an object from buffer that may be split to multiple parts. If object
- * is not split function just returns the pointer to object in buffer. But in
- * case of split object data is copied to given stack object that is suplied
- * by caller.
- *
- * The processing location of the buffer is also advanced to the next byte
- * after the object.
- *
- *   objsize: The size of the objet in bytes.
- *   stack_obj: A pointer to a memory location where object can be copied.
- */
-void *drm_buffer_read_object(struct drm_buffer *buf,
-               int objsize, void *stack_obj)
-{
-       int idx = drm_buffer_index(buf);
-       int page = drm_buffer_page(buf);
-       void *obj = NULL;
-
-       if (idx + objsize <= PAGE_SIZE) {
-               obj = &buf->data[page][idx];
-       } else {
-               /* The object is split which forces copy to temporary object.*/
-               int beginsz = PAGE_SIZE - idx;
-               memcpy(stack_obj, &buf->data[page][idx], beginsz);
-
-               memcpy(stack_obj + beginsz, &buf->data[page + 1][0],
-                               objsize - beginsz);
-
-               obj = stack_obj;
-       }
-
-       drm_buffer_advance(buf, objsize);
-       return obj;
-}
-EXPORT_SYMBOL(drm_buffer_read_object);
index 61acb8f6756d1f14caca006cd48e88ab8c6786c6..569064a00693eb2932186d72eddfda8b2aa74d5c 100644 (file)
@@ -1,18 +1,13 @@
-/**
- * \file drm_bufs.c
- * Generic buffer template
- *
- * \author Rickard E. (Rik) Faith <faith@valinux.com>
- * \author Gareth Hughes <gareth@valinux.com>
- */
-
 /*
- * Created: Thu Nov 23 03:10:50 2000 by gareth@valinux.com
+ * Legacy: Generic DRM Buffer Management
  *
  * Copyright 1999, 2000 Precision Insight, Inc., Cedar Park, Texas.
  * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
  * All Rights Reserved.
  *
+ * Author: Rickard E. (Rik) Faith <faith@valinux.com>
+ * Author: Gareth Hughes <gareth@valinux.com>
+ *
  * Permission is hereby granted, free of charge, to any person obtaining a
  * copy of this software and associated documentation files (the "Software"),
  * to deal in the Software without restriction, including without limitation
@@ -39,6 +34,7 @@
 #include <linux/export.h>
 #include <asm/shmparam.h>
 #include <drm/drmP.h>
+#include "drm_legacy.h"
 
 static struct drm_map_list *drm_find_matching_map(struct drm_device *dev,
                                                  struct drm_local_map *map)
@@ -365,9 +361,9 @@ static int drm_addmap_core(struct drm_device * dev, resource_size_t offset,
        return 0;
 }
 
-int drm_addmap(struct drm_device * dev, resource_size_t offset,
-              unsigned int size, enum drm_map_type type,
-              enum drm_map_flags flags, struct drm_local_map ** map_ptr)
+int drm_legacy_addmap(struct drm_device * dev, resource_size_t offset,
+                     unsigned int size, enum drm_map_type type,
+                     enum drm_map_flags flags, struct drm_local_map **map_ptr)
 {
        struct drm_map_list *list;
        int rc;
@@ -377,8 +373,7 @@ int drm_addmap(struct drm_device * dev, resource_size_t offset,
                *map_ptr = list->map;
        return rc;
 }
-
-EXPORT_SYMBOL(drm_addmap);
+EXPORT_SYMBOL(drm_legacy_addmap);
 
 /**
  * Ioctl to specify a range of memory that is available for mapping by a
@@ -391,8 +386,8 @@ EXPORT_SYMBOL(drm_addmap);
  * \return zero on success or a negative value on error.
  *
  */
-int drm_addmap_ioctl(struct drm_device *dev, void *data,
-                    struct drm_file *file_priv)
+int drm_legacy_addmap_ioctl(struct drm_device *dev, void *data,
+                           struct drm_file *file_priv)
 {
        struct drm_map *map = data;
        struct drm_map_list *maplist;
@@ -429,9 +424,9 @@ int drm_addmap_ioctl(struct drm_device *dev, void *data,
  * its being used, and free any associate resource (such as MTRR's) if it's not
  * being on use.
  *
- * \sa drm_addmap
+ * \sa drm_legacy_addmap
  */
-int drm_rmmap_locked(struct drm_device *dev, struct drm_local_map *map)
+int drm_legacy_rmmap_locked(struct drm_device *dev, struct drm_local_map *map)
 {
        struct drm_map_list *r_list = NULL, *list_t;
        drm_dma_handle_t dmah;
@@ -478,26 +473,26 @@ int drm_rmmap_locked(struct drm_device *dev, struct drm_local_map *map)
                dmah.vaddr = map->handle;
                dmah.busaddr = map->offset;
                dmah.size = map->size;
-               __drm_pci_free(dev, &dmah);
+               __drm_legacy_pci_free(dev, &dmah);
                break;
        }
        kfree(map);
 
        return 0;
 }
-EXPORT_SYMBOL(drm_rmmap_locked);
+EXPORT_SYMBOL(drm_legacy_rmmap_locked);
 
-int drm_rmmap(struct drm_device *dev, struct drm_local_map *map)
+int drm_legacy_rmmap(struct drm_device *dev, struct drm_local_map *map)
 {
        int ret;
 
        mutex_lock(&dev->struct_mutex);
-       ret = drm_rmmap_locked(dev, map);
+       ret = drm_legacy_rmmap_locked(dev, map);
        mutex_unlock(&dev->struct_mutex);
 
        return ret;
 }
-EXPORT_SYMBOL(drm_rmmap);
+EXPORT_SYMBOL(drm_legacy_rmmap);
 
 /* The rmmap ioctl appears to be unnecessary.  All mappings are torn down on
  * the last close of the device, and this is necessary for cleanup when things
@@ -514,8 +509,8 @@ EXPORT_SYMBOL(drm_rmmap);
  * \param arg pointer to a struct drm_map structure.
  * \return zero on success or a negative value on error.
  */
-int drm_rmmap_ioctl(struct drm_device *dev, void *data,
-                   struct drm_file *file_priv)
+int drm_legacy_rmmap_ioctl(struct drm_device *dev, void *data,
+                          struct drm_file *file_priv)
 {
        struct drm_map *request = data;
        struct drm_local_map *map = NULL;
@@ -546,7 +541,7 @@ int drm_rmmap_ioctl(struct drm_device *dev, void *data,
                return 0;
        }
 
-       ret = drm_rmmap_locked(dev, map);
+       ret = drm_legacy_rmmap_locked(dev, map);
 
        mutex_unlock(&dev->struct_mutex);
 
@@ -599,7 +594,8 @@ static void drm_cleanup_buf_error(struct drm_device * dev,
  * reallocates the buffer list of the same size order to accommodate the new
  * buffers.
  */
-int drm_addbufs_agp(struct drm_device * dev, struct drm_buf_desc * request)
+int drm_legacy_addbufs_agp(struct drm_device *dev,
+                          struct drm_buf_desc *request)
 {
        struct drm_device_dma *dma = dev->dma;
        struct drm_buf_entry *entry;
@@ -759,10 +755,11 @@ int drm_addbufs_agp(struct drm_device * dev, struct drm_buf_desc * request)
        atomic_dec(&dev->buf_alloc);
        return 0;
 }
-EXPORT_SYMBOL(drm_addbufs_agp);
+EXPORT_SYMBOL(drm_legacy_addbufs_agp);
 #endif                         /* __OS_HAS_AGP */
 
-int drm_addbufs_pci(struct drm_device * dev, struct drm_buf_desc * request)
+int drm_legacy_addbufs_pci(struct drm_device *dev,
+                          struct drm_buf_desc *request)
 {
        struct drm_device_dma *dma = dev->dma;
        int count;
@@ -964,9 +961,10 @@ int drm_addbufs_pci(struct drm_device * dev, struct drm_buf_desc * request)
        return 0;
 
 }
-EXPORT_SYMBOL(drm_addbufs_pci);
+EXPORT_SYMBOL(drm_legacy_addbufs_pci);
 
-static int drm_addbufs_sg(struct drm_device * dev, struct drm_buf_desc * request)
+static int drm_legacy_addbufs_sg(struct drm_device *dev,
+                                struct drm_buf_desc *request)
 {
        struct drm_device_dma *dma = dev->dma;
        struct drm_buf_entry *entry;
@@ -1135,8 +1133,8 @@ static int drm_addbufs_sg(struct drm_device * dev, struct drm_buf_desc * request
  * addbufs_sg() or addbufs_pci() for AGP, scatter-gather or consistent
  * PCI memory respectively.
  */
-int drm_addbufs(struct drm_device *dev, void *data,
-               struct drm_file *file_priv)
+int drm_legacy_addbufs(struct drm_device *dev, void *data,
+                      struct drm_file *file_priv)
 {
        struct drm_buf_desc *request = data;
        int ret;
@@ -1149,15 +1147,15 @@ int drm_addbufs(struct drm_device *dev, void *data,
 
 #if __OS_HAS_AGP
        if (request->flags & _DRM_AGP_BUFFER)
-               ret = drm_addbufs_agp(dev, request);
+               ret = drm_legacy_addbufs_agp(dev, request);
        else
 #endif
        if (request->flags & _DRM_SG_BUFFER)
-               ret = drm_addbufs_sg(dev, request);
+               ret = drm_legacy_addbufs_sg(dev, request);
        else if (request->flags & _DRM_FB_BUFFER)
                ret = -EINVAL;
        else
-               ret = drm_addbufs_pci(dev, request);
+               ret = drm_legacy_addbufs_pci(dev, request);
 
        return ret;
 }
@@ -1179,8 +1177,8 @@ int drm_addbufs(struct drm_device *dev, void *data,
  * lock, preventing of allocating more buffers after this call. Information
  * about each requested buffer is then copied into user space.
  */
-int drm_infobufs(struct drm_device *dev, void *data,
-                struct drm_file *file_priv)
+int drm_legacy_infobufs(struct drm_device *dev, void *data,
+                       struct drm_file *file_priv)
 {
        struct drm_device_dma *dma = dev->dma;
        struct drm_buf_info *request = data;
@@ -1260,8 +1258,8 @@ int drm_infobufs(struct drm_device *dev, void *data,
  *
  * \note This ioctl is deprecated and mostly never used.
  */
-int drm_markbufs(struct drm_device *dev, void *data,
-                struct drm_file *file_priv)
+int drm_legacy_markbufs(struct drm_device *dev, void *data,
+                       struct drm_file *file_priv)
 {
        struct drm_device_dma *dma = dev->dma;
        struct drm_buf_desc *request = data;
@@ -1307,8 +1305,8 @@ int drm_markbufs(struct drm_device *dev, void *data,
  * Calls free_buffer() for each used buffer.
  * This function is primarily used for debugging.
  */
-int drm_freebufs(struct drm_device *dev, void *data,
-                struct drm_file *file_priv)
+int drm_legacy_freebufs(struct drm_device *dev, void *data,
+                       struct drm_file *file_priv)
 {
        struct drm_device_dma *dma = dev->dma;
        struct drm_buf_free *request = data;
@@ -1340,7 +1338,7 @@ int drm_freebufs(struct drm_device *dev, void *data,
                                  task_pid_nr(current));
                        return -EINVAL;
                }
-               drm_free_buffer(dev, buf);
+               drm_legacy_free_buffer(dev, buf);
        }
 
        return 0;
@@ -1360,8 +1358,8 @@ int drm_freebufs(struct drm_device *dev, void *data,
  * offset equal to 0, which drm_mmap() interpretes as PCI buffers and calls
  * drm_mmap_dma().
  */
-int drm_mapbufs(struct drm_device *dev, void *data,
-               struct drm_file *file_priv)
+int drm_legacy_mapbufs(struct drm_device *dev, void *data,
+                      struct drm_file *file_priv)
 {
        struct drm_device_dma *dma = dev->dma;
        int retcode = 0;
@@ -1448,7 +1446,7 @@ int drm_mapbufs(struct drm_device *dev, void *data,
        return retcode;
 }
 
-int drm_dma_ioctl(struct drm_device *dev, void *data,
+int drm_legacy_dma_ioctl(struct drm_device *dev, void *data,
                  struct drm_file *file_priv)
 {
        if (drm_core_check_feature(dev, DRIVER_MODESET))
@@ -1460,7 +1458,7 @@ int drm_dma_ioctl(struct drm_device *dev, void *data,
                return -EINVAL;
 }
 
-struct drm_local_map *drm_getsarea(struct drm_device *dev)
+struct drm_local_map *drm_legacy_getsarea(struct drm_device *dev)
 {
        struct drm_map_list *entry;
 
@@ -1472,4 +1470,4 @@ struct drm_local_map *drm_getsarea(struct drm_device *dev)
        }
        return NULL;
 }
-EXPORT_SYMBOL(drm_getsarea);
+EXPORT_SYMBOL(drm_legacy_getsarea);
index 90e773019eac78f0a247f840eb5ada047a0b5573..e79c8d3700d838ff87f1095bcb92a773dbe36018 100644 (file)
 #include <drm/drm_modeset_lock.h>
 
 #include "drm_crtc_internal.h"
+#include "drm_internal.h"
 
 static struct drm_framebuffer *add_framebuffer_internal(struct drm_device *dev,
                                                        struct drm_mode_fb_cmd2 *r,
                                                        struct drm_file *file_priv);
 
-/**
- * drm_modeset_lock_all - take all modeset locks
- * @dev: drm device
- *
- * This function takes all modeset locks, suitable where a more fine-grained
- * scheme isn't (yet) implemented. Locks must be dropped with
- * drm_modeset_unlock_all.
- */
-void drm_modeset_lock_all(struct drm_device *dev)
-{
-       struct drm_mode_config *config = &dev->mode_config;
-       struct drm_modeset_acquire_ctx *ctx;
-       int ret;
-
-       ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
-       if (WARN_ON(!ctx))
-               return;
-
-       mutex_lock(&config->mutex);
-
-       drm_modeset_acquire_init(ctx, 0);
-
-retry:
-       ret = drm_modeset_lock(&config->connection_mutex, ctx);
-       if (ret)
-               goto fail;
-       ret = drm_modeset_lock_all_crtcs(dev, ctx);
-       if (ret)
-               goto fail;
-
-       WARN_ON(config->acquire_ctx);
-
-       /* now we hold the locks, so now that it is safe, stash the
-        * ctx for drm_modeset_unlock_all():
-        */
-       config->acquire_ctx = ctx;
-
-       drm_warn_on_modeset_not_all_locked(dev);
-
-       return;
-
-fail:
-       if (ret == -EDEADLK) {
-               drm_modeset_backoff(ctx);
-               goto retry;
-       }
-}
-EXPORT_SYMBOL(drm_modeset_lock_all);
-
-/**
- * drm_modeset_unlock_all - drop all modeset locks
- * @dev: device
- *
- * This function drop all modeset locks taken by drm_modeset_lock_all.
- */
-void drm_modeset_unlock_all(struct drm_device *dev)
-{
-       struct drm_mode_config *config = &dev->mode_config;
-       struct drm_modeset_acquire_ctx *ctx = config->acquire_ctx;
-
-       if (WARN_ON(!ctx))
-               return;
-
-       config->acquire_ctx = NULL;
-       drm_modeset_drop_locks(ctx);
-       drm_modeset_acquire_fini(ctx);
-
-       kfree(ctx);
-
-       mutex_unlock(&dev->mode_config.mutex);
-}
-EXPORT_SYMBOL(drm_modeset_unlock_all);
-
-/**
- * drm_warn_on_modeset_not_all_locked - check that all modeset locks are locked
- * @dev: device
- *
- * Useful as a debug assert.
- */
-void drm_warn_on_modeset_not_all_locked(struct drm_device *dev)
-{
-       struct drm_crtc *crtc;
-
-       /* Locking is currently fubar in the panic handler. */
-       if (oops_in_progress)
-               return;
-
-       list_for_each_entry(crtc, &dev->mode_config.crtc_list, head)
-               WARN_ON(!drm_modeset_is_locked(&crtc->mutex));
-
-       WARN_ON(!drm_modeset_is_locked(&dev->mode_config.connection_mutex));
-       WARN_ON(!mutex_is_locked(&dev->mode_config.mutex));
-}
-EXPORT_SYMBOL(drm_warn_on_modeset_not_all_locked);
-
 /* Avoid boilerplate.  I'm tired of typing. */
 #define DRM_ENUM_NAME_FN(fnname, list)                         \
        const char *fnname(int val)                             \
@@ -515,9 +421,6 @@ int drm_framebuffer_init(struct drm_device *dev, struct drm_framebuffer *fb,
        if (ret)
                goto out;
 
-       /* Grab the idr reference. */
-       drm_framebuffer_reference(fb);
-
        dev->mode_config.num_fb++;
        list_add(&fb->head, &dev->mode_config.fb_list);
 out:
@@ -527,10 +430,34 @@ out:
 }
 EXPORT_SYMBOL(drm_framebuffer_init);
 
+/* dev->mode_config.fb_lock must be held! */
+static void __drm_framebuffer_unregister(struct drm_device *dev,
+                                        struct drm_framebuffer *fb)
+{
+       mutex_lock(&dev->mode_config.idr_mutex);
+       idr_remove(&dev->mode_config.crtc_idr, fb->base.id);
+       mutex_unlock(&dev->mode_config.idr_mutex);
+
+       fb->base.id = 0;
+}
+
 static void drm_framebuffer_free(struct kref *kref)
 {
        struct drm_framebuffer *fb =
                        container_of(kref, struct drm_framebuffer, refcount);
+       struct drm_device *dev = fb->dev;
+
+       /*
+        * The lookup idr holds a weak reference, which has not necessarily been
+        * removed at this point. Check for that.
+        */
+       mutex_lock(&dev->mode_config.fb_lock);
+       if (fb->base.id) {
+               /* Mark fb as reaped and drop idr ref. */
+               __drm_framebuffer_unregister(dev, fb);
+       }
+       mutex_unlock(&dev->mode_config.fb_lock);
+
        fb->funcs->destroy(fb);
 }
 
@@ -567,8 +494,10 @@ struct drm_framebuffer *drm_framebuffer_lookup(struct drm_device *dev,
 
        mutex_lock(&dev->mode_config.fb_lock);
        fb = __drm_framebuffer_lookup(dev, id);
-       if (fb)
-               drm_framebuffer_reference(fb);
+       if (fb) {
+               if (!kref_get_unless_zero(&fb->refcount))
+                       fb = NULL;
+       }
        mutex_unlock(&dev->mode_config.fb_lock);
 
        return fb;
@@ -612,19 +541,6 @@ static void __drm_framebuffer_unreference(struct drm_framebuffer *fb)
        kref_put(&fb->refcount, drm_framebuffer_free_bug);
 }
 
-/* dev->mode_config.fb_lock must be held! */
-static void __drm_framebuffer_unregister(struct drm_device *dev,
-                                        struct drm_framebuffer *fb)
-{
-       mutex_lock(&dev->mode_config.idr_mutex);
-       idr_remove(&dev->mode_config.crtc_idr, fb->base.id);
-       mutex_unlock(&dev->mode_config.idr_mutex);
-
-       fb->base.id = 0;
-
-       __drm_framebuffer_unreference(fb);
-}
-
 /**
  * drm_framebuffer_unregister_private - unregister a private fb from the lookup idr
  * @fb: fb to unregister
@@ -764,11 +680,7 @@ int drm_crtc_init_with_planes(struct drm_device *dev, struct drm_crtc *crtc,
        crtc->funcs = funcs;
        crtc->invert_dimensions = false;
 
-       drm_modeset_lock_all(dev);
        drm_modeset_lock_init(&crtc->mutex);
-       /* dropped by _unlock_all(): */
-       drm_modeset_lock(&crtc->mutex, config->acquire_ctx);
-
        ret = drm_mode_object_get(dev, &crtc->base, DRM_MODE_OBJECT_CRTC);
        if (ret)
                goto out;
@@ -786,7 +698,6 @@ int drm_crtc_init_with_planes(struct drm_device *dev, struct drm_crtc *crtc,
                cursor->possible_crtcs = 1 << drm_crtc_index(crtc);
 
  out:
-       drm_modeset_unlock_all(dev);
 
        return ret;
 }
@@ -852,6 +763,59 @@ static void drm_mode_remove(struct drm_connector *connector,
        drm_mode_destroy(connector->dev, mode);
 }
 
+/**
+ * drm_connector_get_cmdline_mode - reads the user's cmdline mode
+ * @connector: connector to quwery
+ * @mode: returned mode
+ *
+ * The kernel supports per-connector configration of its consoles through
+ * use of the video= parameter. This function parses that option and
+ * extracts the user's specified mode (or enable/disable status) for a
+ * particular connector. This is typically only used during the early fbdev
+ * setup.
+ */
+static void drm_connector_get_cmdline_mode(struct drm_connector *connector)
+{
+       struct drm_cmdline_mode *mode = &connector->cmdline_mode;
+       char *option = NULL;
+
+       if (fb_get_options(connector->name, &option))
+               return;
+
+       if (!drm_mode_parse_command_line_for_connector(option,
+                                                      connector,
+                                                      mode))
+               return;
+
+       if (mode->force) {
+               const char *s;
+
+               switch (mode->force) {
+               case DRM_FORCE_OFF:
+                       s = "OFF";
+                       break;
+               case DRM_FORCE_ON_DIGITAL:
+                       s = "ON - dig";
+                       break;
+               default:
+               case DRM_FORCE_ON:
+                       s = "ON";
+                       break;
+               }
+
+               DRM_INFO("forcing %s connector %s\n", connector->name, s);
+               connector->force = mode->force;
+       }
+
+       DRM_DEBUG_KMS("cmdline mode for connector %s %dx%d@%dHz%s%s%s\n",
+                     connector->name,
+                     mode->xres, mode->yres,
+                     mode->refresh_specified ? mode->refresh : 60,
+                     mode->rb ? " reduced blanking" : "",
+                     mode->margins ? " with margins" : "",
+                     mode->interlace ?  " interlaced" : "");
+}
+
 /**
  * drm_connector_init - Init a preallocated connector
  * @dev: DRM device
@@ -904,6 +868,8 @@ int drm_connector_init(struct drm_device *dev,
        connector->edid_blob_ptr = NULL;
        connector->status = connector_status_unknown;
 
+       drm_connector_get_cmdline_mode(connector);
+
        list_add_tail(&connector->head, &dev->mode_config.connector_list);
        dev->mode_config.num_connector++;
 
@@ -956,6 +922,29 @@ void drm_connector_cleanup(struct drm_connector *connector)
 }
 EXPORT_SYMBOL(drm_connector_cleanup);
 
+/**
+ * drm_connector_index - find the index of a registered connector
+ * @connector: connector to find index for
+ *
+ * Given a registered connector, return the index of that connector within a DRM
+ * device's list of connectors.
+ */
+unsigned int drm_connector_index(struct drm_connector *connector)
+{
+       unsigned int index = 0;
+       struct drm_connector *tmp;
+
+       list_for_each_entry(tmp, &connector->dev->mode_config.connector_list, head) {
+               if (tmp == connector)
+                       return index;
+
+               index++;
+       }
+
+       BUG();
+}
+EXPORT_SYMBOL(drm_connector_index);
+
 /**
  * drm_connector_register - register a connector
  * @connector: the connector to register
@@ -1260,6 +1249,29 @@ void drm_plane_cleanup(struct drm_plane *plane)
 }
 EXPORT_SYMBOL(drm_plane_cleanup);
 
+/**
+ * drm_plane_index - find the index of a registered plane
+ * @plane: plane to find index for
+ *
+ * Given a registered plane, return the index of that CRTC within a DRM
+ * device's list of planes.
+ */
+unsigned int drm_plane_index(struct drm_plane *plane)
+{
+       unsigned int index = 0;
+       struct drm_plane *tmp;
+
+       list_for_each_entry(tmp, &plane->dev->mode_config.plane_list, head) {
+               if (tmp == plane)
+                       return index;
+
+               index++;
+       }
+
+       BUG();
+}
+EXPORT_SYMBOL(drm_plane_index);
+
 /**
  * drm_plane_force_disable - Forcibly disable a plane
  * @plane: plane to disable
@@ -1271,19 +1283,21 @@ EXPORT_SYMBOL(drm_plane_cleanup);
  */
 void drm_plane_force_disable(struct drm_plane *plane)
 {
-       struct drm_framebuffer *old_fb = plane->fb;
        int ret;
 
-       if (!old_fb)
+       if (!plane->fb)
                return;
 
+       plane->old_fb = plane->fb;
        ret = plane->funcs->disable_plane(plane);
        if (ret) {
                DRM_ERROR("failed to disable plane with busy fb\n");
+               plane->old_fb = NULL;
                return;
        }
        /* disconnect the plane from the fb and crtc: */
-       __drm_framebuffer_unreference(old_fb);
+       __drm_framebuffer_unreference(plane->old_fb);
+       plane->old_fb = NULL;
        plane->fb = NULL;
        plane->crtc = NULL;
 }
@@ -2249,33 +2263,29 @@ out:
  *
  * src_{x,y,w,h} are provided in 16.16 fixed point format
  */
-static int setplane_internal(struct drm_plane *plane,
-                            struct drm_crtc *crtc,
-                            struct drm_framebuffer *fb,
-                            int32_t crtc_x, int32_t crtc_y,
-                            uint32_t crtc_w, uint32_t crtc_h,
-                            /* src_{x,y,w,h} values are 16.16 fixed point */
-                            uint32_t src_x, uint32_t src_y,
-                            uint32_t src_w, uint32_t src_h)
+static int __setplane_internal(struct drm_plane *plane,
+                              struct drm_crtc *crtc,
+                              struct drm_framebuffer *fb,
+                              int32_t crtc_x, int32_t crtc_y,
+                              uint32_t crtc_w, uint32_t crtc_h,
+                              /* src_{x,y,w,h} values are 16.16 fixed point */
+                              uint32_t src_x, uint32_t src_y,
+                              uint32_t src_w, uint32_t src_h)
 {
-       struct drm_device *dev = plane->dev;
-       struct drm_framebuffer *old_fb = NULL;
        int ret = 0;
        unsigned int fb_width, fb_height;
        int i;
 
        /* No fb means shut it down */
        if (!fb) {
-               drm_modeset_lock_all(dev);
-               old_fb = plane->fb;
+               plane->old_fb = plane->fb;
                ret = plane->funcs->disable_plane(plane);
                if (!ret) {
                        plane->crtc = NULL;
                        plane->fb = NULL;
                } else {
-                       old_fb = NULL;
+                       plane->old_fb = NULL;
                }
-               drm_modeset_unlock_all(dev);
                goto out;
        }
 
@@ -2315,8 +2325,7 @@ static int setplane_internal(struct drm_plane *plane,
                goto out;
        }
 
-       drm_modeset_lock_all(dev);
-       old_fb = plane->fb;
+       plane->old_fb = plane->fb;
        ret = plane->funcs->update_plane(plane, crtc, fb,
                                         crtc_x, crtc_y, crtc_w, crtc_h,
                                         src_x, src_y, src_w, src_h);
@@ -2325,18 +2334,37 @@ static int setplane_internal(struct drm_plane *plane,
                plane->fb = fb;
                fb = NULL;
        } else {
-               old_fb = NULL;
+               plane->old_fb = NULL;
        }
-       drm_modeset_unlock_all(dev);
 
 out:
        if (fb)
                drm_framebuffer_unreference(fb);
-       if (old_fb)
-               drm_framebuffer_unreference(old_fb);
+       if (plane->old_fb)
+               drm_framebuffer_unreference(plane->old_fb);
+       plane->old_fb = NULL;
 
        return ret;
+}
+
+static int setplane_internal(struct drm_plane *plane,
+                            struct drm_crtc *crtc,
+                            struct drm_framebuffer *fb,
+                            int32_t crtc_x, int32_t crtc_y,
+                            uint32_t crtc_w, uint32_t crtc_h,
+                            /* src_{x,y,w,h} values are 16.16 fixed point */
+                            uint32_t src_x, uint32_t src_y,
+                            uint32_t src_w, uint32_t src_h)
+{
+       int ret;
+
+       drm_modeset_lock_all(plane->dev);
+       ret = __setplane_internal(plane, crtc, fb,
+                                 crtc_x, crtc_y, crtc_w, crtc_h,
+                                 src_x, src_y, src_w, src_h);
+       drm_modeset_unlock_all(plane->dev);
 
+       return ret;
 }
 
 /**
@@ -2440,7 +2468,7 @@ int drm_mode_set_config_internal(struct drm_mode_set *set)
         * crtcs. Atomic modeset will have saner semantics ...
         */
        list_for_each_entry(tmp, &crtc->dev->mode_config.crtc_list, head)
-               tmp->old_fb = tmp->primary->fb;
+               tmp->primary->old_fb = tmp->primary->fb;
 
        fb = set->fb;
 
@@ -2453,8 +2481,9 @@ int drm_mode_set_config_internal(struct drm_mode_set *set)
        list_for_each_entry(tmp, &crtc->dev->mode_config.crtc_list, head) {
                if (tmp->primary->fb)
                        drm_framebuffer_reference(tmp->primary->fb);
-               if (tmp->old_fb)
-                       drm_framebuffer_unreference(tmp->old_fb);
+               if (tmp->primary->old_fb)
+                       drm_framebuffer_unreference(tmp->primary->old_fb);
+               tmp->primary->old_fb = NULL;
        }
 
        return ret;
@@ -2701,6 +2730,7 @@ static int drm_mode_cursor_universal(struct drm_crtc *crtc,
        int ret = 0;
 
        BUG_ON(!crtc->cursor);
+       WARN_ON(crtc->cursor->crtc != crtc && crtc->cursor->crtc != NULL);
 
        /*
         * Obtain fb we'll be using (either new or existing) and take an extra
@@ -2720,11 +2750,9 @@ static int drm_mode_cursor_universal(struct drm_crtc *crtc,
                        fb = NULL;
                }
        } else {
-               mutex_lock(&dev->mode_config.mutex);
                fb = crtc->cursor->fb;
                if (fb)
                        drm_framebuffer_reference(fb);
-               mutex_unlock(&dev->mode_config.mutex);
        }
 
        if (req->flags & DRM_MODE_CURSOR_MOVE) {
@@ -2746,7 +2774,7 @@ static int drm_mode_cursor_universal(struct drm_crtc *crtc,
         * setplane_internal will take care of deref'ing either the old or new
         * framebuffer depending on success.
         */
-       ret = setplane_internal(crtc->cursor, crtc, fb,
+       ret = __setplane_internal(crtc->cursor, crtc, fb,
                                crtc_x, crtc_y, crtc_w, crtc_h,
                                0, 0, src_w, src_h);
 
@@ -2782,10 +2810,12 @@ static int drm_mode_cursor_common(struct drm_device *dev,
         * If this crtc has a universal cursor plane, call that plane's update
         * handler rather than using legacy cursor handlers.
         */
-       if (crtc->cursor)
-               return drm_mode_cursor_universal(crtc, req, file_priv);
+       drm_modeset_lock_crtc(crtc);
+       if (crtc->cursor) {
+               ret = drm_mode_cursor_universal(crtc, req, file_priv);
+               goto out;
+       }
 
-       drm_modeset_lock(&crtc->mutex, NULL);
        if (req->flags & DRM_MODE_CURSOR_BO) {
                if (!crtc->funcs->cursor_set && !crtc->funcs->cursor_set2) {
                        ret = -ENXIO;
@@ -2809,7 +2839,7 @@ static int drm_mode_cursor_common(struct drm_device *dev,
                }
        }
 out:
-       drm_modeset_unlock(&crtc->mutex);
+       drm_modeset_unlock_crtc(crtc);
 
        return ret;
 
@@ -3370,7 +3400,16 @@ void drm_fb_release(struct drm_file *priv)
        struct drm_device *dev = priv->minor->dev;
        struct drm_framebuffer *fb, *tfb;
 
-       mutex_lock(&priv->fbs_lock);
+       /*
+        * When the file gets released that means no one else can access the fb
+        * list any more, so no need to grab fpriv->fbs_lock. And we need to to
+        * avoid upsetting lockdep since the universal cursor code adds a
+        * framebuffer while holding mutex locks.
+        *
+        * Note that a real deadlock between fpriv->fbs_lock and the modeset
+        * locks is impossible here since no one else but this function can get
+        * at it any more.
+        */
        list_for_each_entry_safe(fb, tfb, &priv->fbs, filp_head) {
 
                mutex_lock(&dev->mode_config.fb_lock);
@@ -3383,7 +3422,6 @@ void drm_fb_release(struct drm_file *priv)
                /* This will also drop the fpriv->fbs reference. */
                drm_framebuffer_remove(fb);
        }
-       mutex_unlock(&priv->fbs_lock);
 }
 
 /**
@@ -3495,9 +3533,10 @@ EXPORT_SYMBOL(drm_property_create_enum);
  * @flags: flags specifying the property type
  * @name: name of the property
  * @props: enumeration lists with property bitflags
- * @num_values: number of pre-defined values
+ * @num_props: size of the @props array
+ * @supported_bits: bitmask of all supported enumeration values
  *
- * This creates a new generic drm property which can then be attached to a drm
+ * This creates a new bitmask drm property which can then be attached to a drm
  * object with drm_object_attach_property. The returned property object must be
  * freed with drm_property_destroy.
  *
@@ -4157,12 +4196,25 @@ static int drm_mode_crtc_set_obj_prop(struct drm_mode_object *obj,
        return ret;
 }
 
-static int drm_mode_plane_set_obj_prop(struct drm_mode_object *obj,
-                                     struct drm_property *property,
-                                     uint64_t value)
+/**
+ * drm_mode_plane_set_obj_prop - set the value of a property
+ * @plane: drm plane object to set property value for
+ * @property: property to set
+ * @value: value the property should be set to
+ *
+ * This functions sets a given property on a given plane object. This function
+ * calls the driver's ->set_property callback and changes the software state of
+ * the property if the callback succeeds.
+ *
+ * Returns:
+ * Zero on success, error code on failure.
+ */
+int drm_mode_plane_set_obj_prop(struct drm_plane *plane,
+                               struct drm_property *property,
+                               uint64_t value)
 {
        int ret = -EINVAL;
-       struct drm_plane *plane = obj_to_plane(obj);
+       struct drm_mode_object *obj = &plane->base;
 
        if (plane->funcs->set_property)
                ret = plane->funcs->set_property(plane, property, value);
@@ -4171,6 +4223,7 @@ static int drm_mode_plane_set_obj_prop(struct drm_mode_object *obj,
 
        return ret;
 }
+EXPORT_SYMBOL(drm_mode_plane_set_obj_prop);
 
 /**
  * drm_mode_getproperty_ioctl - get the current value of a object's property
@@ -4309,7 +4362,8 @@ int drm_mode_obj_set_property_ioctl(struct drm_device *dev, void *data,
                ret = drm_mode_crtc_set_obj_prop(arg_obj, property, arg->value);
                break;
        case DRM_MODE_OBJECT_PLANE:
-               ret = drm_mode_plane_set_obj_prop(arg_obj, property, arg->value);
+               ret = drm_mode_plane_set_obj_prop(obj_to_plane(arg_obj),
+                                                 property, arg->value);
                break;
        }
 
@@ -4529,7 +4583,7 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev,
 {
        struct drm_mode_crtc_page_flip *page_flip = data;
        struct drm_crtc *crtc;
-       struct drm_framebuffer *fb = NULL, *old_fb = NULL;
+       struct drm_framebuffer *fb = NULL;
        struct drm_pending_vblank_event *e = NULL;
        unsigned long flags;
        int ret = -EINVAL;
@@ -4545,7 +4599,7 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev,
        if (!crtc)
                return -ENOENT;
 
-       drm_modeset_lock(&crtc->mutex, NULL);
+       drm_modeset_lock_crtc(crtc);
        if (crtc->primary->fb == NULL) {
                /* The framebuffer is currently unbound, presumably
                 * due to a hotplug event, that userspace has not
@@ -4601,7 +4655,7 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev,
                        (void (*) (struct drm_pending_event *)) kfree;
        }
 
-       old_fb = crtc->primary->fb;
+       crtc->primary->old_fb = crtc->primary->fb;
        ret = crtc->funcs->page_flip(crtc, fb, e, page_flip->flags);
        if (ret) {
                if (page_flip->flags & DRM_MODE_PAGE_FLIP_EVENT) {
@@ -4611,7 +4665,7 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev,
                        kfree(e);
                }
                /* Keep the old fb, don't unref it. */
-               old_fb = NULL;
+               crtc->primary->old_fb = NULL;
        } else {
                /*
                 * Warn if the driver hasn't properly updated the crtc->fb
@@ -4627,9 +4681,10 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev,
 out:
        if (fb)
                drm_framebuffer_unreference(fb);
-       if (old_fb)
-               drm_framebuffer_unreference(old_fb);
-       drm_modeset_unlock(&crtc->mutex);
+       if (crtc->primary->old_fb)
+               drm_framebuffer_unreference(crtc->primary->old_fb);
+       crtc->primary->old_fb = NULL;
+       drm_modeset_unlock_crtc(crtc);
 
        return ret;
 }
@@ -4645,9 +4700,14 @@ out:
 void drm_mode_config_reset(struct drm_device *dev)
 {
        struct drm_crtc *crtc;
+       struct drm_plane *plane;
        struct drm_encoder *encoder;
        struct drm_connector *connector;
 
+       list_for_each_entry(plane, &dev->mode_config.plane_list, head)
+               if (plane->funcs->reset)
+                       plane->funcs->reset(plane);
+
        list_for_each_entry(crtc, &dev->mode_config.crtc_list, head)
                if (crtc->funcs->reset)
                        crtc->funcs->reset(crtc);
index 13bd42923dd4e2b4ca018e3ee2b1cb09a30b4677..3bcf8e6a85b355437e7aca009a3a205b9ba8f428 100644 (file)
@@ -36,6 +36,7 @@
 #include <linux/export.h>
 #include <drm/drmP.h>
 #include <drm/drm_edid.h>
+#include "drm_internal.h"
 
 #if defined(CONFIG_DEBUG_FS)
 
@@ -49,9 +50,7 @@ static const struct drm_info_list drm_debugfs_list[] = {
        {"clients", drm_clients_info, 0},
        {"bufs", drm_bufs_info, 0},
        {"gem_names", drm_gem_name_info, DRIVER_GEM},
-#if DRM_DEBUG_CODE
        {"vma", drm_vma_info, 0},
-#endif
 };
 #define DRM_DEBUGFS_ENTRIES ARRAY_SIZE(drm_debugfs_list)
 
index 8a140a953754de73d2a524bbaae8599bc5063984..ea481800ef565dfa3bd4852456f0f05efe60ac32 100644 (file)
@@ -35,6 +35,7 @@
 
 #include <linux/export.h>
 #include <drm/drmP.h>
+#include "drm_legacy.h"
 
 /**
  * Initialize the DMA data.
@@ -124,7 +125,7 @@ void drm_legacy_dma_takedown(struct drm_device *dev)
  *
  * Resets the fields of \p buf.
  */
-void drm_free_buffer(struct drm_device *dev, struct drm_buf * buf)
+void drm_legacy_free_buffer(struct drm_device *dev, struct drm_buf * buf)
 {
        if (!buf)
                return;
@@ -142,8 +143,8 @@ void drm_free_buffer(struct drm_device *dev, struct drm_buf * buf)
  *
  * Frees each buffer associated with \p file_priv not already on the hardware.
  */
-void drm_core_reclaim_buffers(struct drm_device *dev,
-                             struct drm_file *file_priv)
+void drm_legacy_reclaim_buffers(struct drm_device *dev,
+                               struct drm_file *file_priv)
 {
        struct drm_device_dma *dma = dev->dma;
        int i;
@@ -154,7 +155,7 @@ void drm_core_reclaim_buffers(struct drm_device *dev,
                if (dma->buflist[i]->file_priv == file_priv) {
                        switch (dma->buflist[i]->list) {
                        case DRM_LIST_NONE:
-                               drm_free_buffer(dev, dma->buflist[i]);
+                               drm_legacy_free_buffer(dev, dma->buflist[i]);
                                break;
                        case DRM_LIST_WAIT:
                                dma->buflist[i]->list = DRM_LIST_RECLAIM;
@@ -166,5 +167,3 @@ void drm_core_reclaim_buffers(struct drm_device *dev,
                }
        }
 }
-
-EXPORT_SYMBOL(drm_core_reclaim_buffers);
index ac3c2738db94ca2278686bfef33eb81e236d4bda..070f913d2dba40eede7075f6e4b4b652e18dbdfa 100644 (file)
@@ -682,7 +682,7 @@ static int build_allocate_payload(struct drm_dp_sideband_msg_tx *msg, int port_n
 static int drm_dp_mst_assign_payload_id(struct drm_dp_mst_topology_mgr *mgr,
                                        struct drm_dp_vcpi *vcpi)
 {
-       int ret;
+       int ret, vcpi_ret;
 
        mutex_lock(&mgr->payload_lock);
        ret = find_first_zero_bit(&mgr->payload_mask, mgr->max_payloads + 1);
@@ -692,8 +692,16 @@ static int drm_dp_mst_assign_payload_id(struct drm_dp_mst_topology_mgr *mgr,
                goto out_unlock;
        }
 
+       vcpi_ret = find_first_zero_bit(&mgr->vcpi_mask, mgr->max_payloads + 1);
+       if (vcpi_ret > mgr->max_payloads) {
+               ret = -EINVAL;
+               DRM_DEBUG_KMS("out of vcpi ids %d\n", ret);
+               goto out_unlock;
+       }
+
        set_bit(ret, &mgr->payload_mask);
-       vcpi->vcpi = ret;
+       set_bit(vcpi_ret, &mgr->vcpi_mask);
+       vcpi->vcpi = vcpi_ret + 1;
        mgr->proposed_vcpis[ret - 1] = vcpi;
 out_unlock:
        mutex_unlock(&mgr->payload_lock);
@@ -701,15 +709,23 @@ out_unlock:
 }
 
 static void drm_dp_mst_put_payload_id(struct drm_dp_mst_topology_mgr *mgr,
-                                     int id)
+                                     int vcpi)
 {
-       if (id == 0)
+       int i;
+       if (vcpi == 0)
                return;
 
        mutex_lock(&mgr->payload_lock);
-       DRM_DEBUG_KMS("putting payload %d\n", id);
-       clear_bit(id, &mgr->payload_mask);
-       mgr->proposed_vcpis[id - 1] = NULL;
+       DRM_DEBUG_KMS("putting payload %d\n", vcpi);
+       clear_bit(vcpi - 1, &mgr->vcpi_mask);
+
+       for (i = 0; i < mgr->max_payloads; i++) {
+               if (mgr->proposed_vcpis[i])
+                       if (mgr->proposed_vcpis[i]->vcpi == vcpi) {
+                               mgr->proposed_vcpis[i] = NULL;
+                               clear_bit(i + 1, &mgr->payload_mask);
+                       }
+       }
        mutex_unlock(&mgr->payload_lock);
 }
 
@@ -1563,7 +1579,7 @@ static int drm_dp_destroy_payload_step1(struct drm_dp_mst_topology_mgr *mgr,
        }
 
        drm_dp_dpcd_write_payload(mgr, id, payload);
-       payload->payload_state = 0;
+       payload->payload_state = DP_PAYLOAD_DELETE_LOCAL;
        return 0;
 }
 
@@ -1590,7 +1606,7 @@ static int drm_dp_destroy_payload_step2(struct drm_dp_mst_topology_mgr *mgr,
  */
 int drm_dp_update_payload_part1(struct drm_dp_mst_topology_mgr *mgr)
 {
-       int i;
+       int i, j;
        int cur_slots = 1;
        struct drm_dp_payload req_payload;
        struct drm_dp_mst_port *port;
@@ -1607,26 +1623,46 @@ int drm_dp_update_payload_part1(struct drm_dp_mst_topology_mgr *mgr)
                        port = NULL;
                        req_payload.num_slots = 0;
                }
+
+               if (mgr->payloads[i].start_slot != req_payload.start_slot) {
+                       mgr->payloads[i].start_slot = req_payload.start_slot;
+               }
                /* work out what is required to happen with this payload */
-               if (mgr->payloads[i].start_slot != req_payload.start_slot ||
-                   mgr->payloads[i].num_slots != req_payload.num_slots) {
+               if (mgr->payloads[i].num_slots != req_payload.num_slots) {
 
                        /* need to push an update for this payload */
                        if (req_payload.num_slots) {
-                               drm_dp_create_payload_step1(mgr, i + 1, &req_payload);
+                               drm_dp_create_payload_step1(mgr, mgr->proposed_vcpis[i]->vcpi, &req_payload);
                                mgr->payloads[i].num_slots = req_payload.num_slots;
                        } else if (mgr->payloads[i].num_slots) {
                                mgr->payloads[i].num_slots = 0;
-                               drm_dp_destroy_payload_step1(mgr, port, i + 1, &mgr->payloads[i]);
+                               drm_dp_destroy_payload_step1(mgr, port, port->vcpi.vcpi, &mgr->payloads[i]);
                                req_payload.payload_state = mgr->payloads[i].payload_state;
-                       } else
-                               req_payload.payload_state = 0;
-
-                       mgr->payloads[i].start_slot = req_payload.start_slot;
+                               mgr->payloads[i].start_slot = 0;
+                       }
                        mgr->payloads[i].payload_state = req_payload.payload_state;
                }
                cur_slots += req_payload.num_slots;
        }
+
+       for (i = 0; i < mgr->max_payloads; i++) {
+               if (mgr->payloads[i].payload_state == DP_PAYLOAD_DELETE_LOCAL) {
+                       DRM_DEBUG_KMS("removing payload %d\n", i);
+                       for (j = i; j < mgr->max_payloads - 1; j++) {
+                               memcpy(&mgr->payloads[j], &mgr->payloads[j + 1], sizeof(struct drm_dp_payload));
+                               mgr->proposed_vcpis[j] = mgr->proposed_vcpis[j + 1];
+                               if (mgr->proposed_vcpis[j] && mgr->proposed_vcpis[j]->num_slots) {
+                                       set_bit(j + 1, &mgr->payload_mask);
+                               } else {
+                                       clear_bit(j + 1, &mgr->payload_mask);
+                               }
+                       }
+                       memset(&mgr->payloads[mgr->max_payloads - 1], 0, sizeof(struct drm_dp_payload));
+                       mgr->proposed_vcpis[mgr->max_payloads - 1] = NULL;
+                       clear_bit(mgr->max_payloads, &mgr->payload_mask);
+
+               }
+       }
        mutex_unlock(&mgr->payload_lock);
 
        return 0;
@@ -1657,9 +1693,9 @@ int drm_dp_update_payload_part2(struct drm_dp_mst_topology_mgr *mgr)
 
                DRM_DEBUG_KMS("payload %d %d\n", i, mgr->payloads[i].payload_state);
                if (mgr->payloads[i].payload_state == DP_PAYLOAD_LOCAL) {
-                       ret = drm_dp_create_payload_step2(mgr, port, i + 1, &mgr->payloads[i]);
+                       ret = drm_dp_create_payload_step2(mgr, port, mgr->proposed_vcpis[i]->vcpi, &mgr->payloads[i]);
                } else if (mgr->payloads[i].payload_state == DP_PAYLOAD_DELETE_LOCAL) {
-                       ret = drm_dp_destroy_payload_step2(mgr, i + 1, &mgr->payloads[i]);
+                       ret = drm_dp_destroy_payload_step2(mgr, mgr->proposed_vcpis[i]->vcpi, &mgr->payloads[i]);
                }
                if (ret) {
                        mutex_unlock(&mgr->payload_lock);
@@ -1772,7 +1808,7 @@ static int drm_dp_get_vc_payload_bw(int dp_link_bw, int dp_link_count)
        case DP_LINK_BW_5_4:
                return 10 * dp_link_count;
        }
-       return 0;
+       BUG();
 }
 
 /**
@@ -1861,6 +1897,7 @@ int drm_dp_mst_topology_mgr_set_mst(struct drm_dp_mst_topology_mgr *mgr, bool ms
                memset(mgr->payloads, 0, mgr->max_payloads * sizeof(struct drm_dp_payload));
                mgr->payload_mask = 0;
                set_bit(0, &mgr->payload_mask);
+               mgr->vcpi_mask = 0;
        }
 
 out_unlock:
@@ -2071,6 +2108,7 @@ static int drm_dp_mst_handle_up_req(struct drm_dp_mst_topology_mgr *mgr)
  * drm_dp_mst_hpd_irq() - MST hotplug IRQ notify
  * @mgr: manager to notify irq for.
  * @esi: 4 bytes from SINK_COUNT_ESI
+ * @handled: whether the hpd interrupt was consumed or not
  *
  * This should be called from the driver when it detects a short IRQ,
  * along with the value of the DEVICE_SERVICE_IRQ_VECTOR_ESI0. The
@@ -2474,7 +2512,7 @@ void drm_dp_mst_dump_topology(struct seq_file *m,
        mutex_unlock(&mgr->lock);
 
        mutex_lock(&mgr->payload_lock);
-       seq_printf(m, "vcpi: %lx\n", mgr->payload_mask);
+       seq_printf(m, "vcpi: %lx %lx\n", mgr->payload_mask, mgr->vcpi_mask);
 
        for (i = 0; i < mgr->max_payloads; i++) {
                if (mgr->proposed_vcpis[i]) {
index 3242e208c0d0db205498df5e1ac371d30c488988..bc3da32d458590a849a785aeca890670741e5212 100644 (file)
 #include <drm/drmP.h>
 #include <drm/drm_core.h>
 #include "drm_legacy.h"
+#include "drm_internal.h"
 
 unsigned int drm_debug = 0;    /* 1 to enable debug output */
 EXPORT_SYMBOL(drm_debug);
 
-unsigned int drm_vblank_offdelay = 5000;    /* Default to 5000 msecs. */
-
-unsigned int drm_timestamp_precision = 20;  /* Default to 20 usecs. */
-
-/*
- * Default to use monotonic timestamps for wait-for-vblank and page-flip
- * complete events.
- */
-unsigned int drm_timestamp_monotonic = 1;
-
 MODULE_AUTHOR(CORE_AUTHOR);
 MODULE_DESCRIPTION(CORE_DESC);
 MODULE_LICENSE("GPL and additional rights");
 MODULE_PARM_DESC(debug, "Enable debug output");
-MODULE_PARM_DESC(vblankoffdelay, "Delay until vblank irq auto-disable [msecs]");
+MODULE_PARM_DESC(vblankoffdelay, "Delay until vblank irq auto-disable [msecs] (0: never disable, <0: disable immediately)");
 MODULE_PARM_DESC(timestamp_precision_usec, "Max. error on timestamps [usecs]");
 MODULE_PARM_DESC(timestamp_monotonic, "Use monotonic timestamps");
 
 module_param_named(debug, drm_debug, int, 0600);
-module_param_named(vblankoffdelay, drm_vblank_offdelay, int, 0600);
-module_param_named(timestamp_precision_usec, drm_timestamp_precision, int, 0600);
-module_param_named(timestamp_monotonic, drm_timestamp_monotonic, int, 0600);
 
 static DEFINE_SPINLOCK(drm_minor_lock);
 static struct idr drm_minors_idr;
@@ -68,22 +56,19 @@ static struct idr drm_minors_idr;
 struct class *drm_class;
 static struct dentry *drm_debugfs_root;
 
-int drm_err(const char *func, const char *format, ...)
+void drm_err(const char *func, const char *format, ...)
 {
        struct va_format vaf;
        va_list args;
-       int r;
 
        va_start(args, format);
 
        vaf.fmt = format;
        vaf.va = &args;
 
-       r = printk(KERN_ERR "[" DRM_NAME ":%s] *ERROR* %pV", func, &vaf);
+       printk(KERN_ERR "[" DRM_NAME ":%s] *ERROR* %pV", func, &vaf);
 
        va_end(args);
-
-       return r;
 }
 EXPORT_SYMBOL(drm_err);
 
@@ -102,6 +87,8 @@ void drm_ut_debug_printk(const char *function_name, const char *format, ...)
 }
 EXPORT_SYMBOL(drm_ut_debug_printk);
 
+#define DRM_MAGIC_HASH_ORDER  4  /**< Size of key hash table. Must be power of 2. */
+
 struct drm_master *drm_master_create(struct drm_minor *minor)
 {
        struct drm_master *master;
@@ -133,7 +120,6 @@ EXPORT_SYMBOL(drm_master_get);
 static void drm_master_destroy(struct kref *kref)
 {
        struct drm_master *master = container_of(kref, struct drm_master, refcount);
-       struct drm_magic_entry *pt, *next;
        struct drm_device *dev = master->minor->dev;
        struct drm_map_list *r_list, *list_temp;
 
@@ -143,7 +129,7 @@ static void drm_master_destroy(struct kref *kref)
 
        list_for_each_entry_safe(r_list, list_temp, &dev->maplist, head) {
                if (r_list->master == master) {
-                       drm_rmmap_locked(dev, r_list->map);
+                       drm_legacy_rmmap_locked(dev, r_list->map);
                        r_list = NULL;
                }
        }
@@ -154,12 +140,6 @@ static void drm_master_destroy(struct kref *kref)
                master->unique_len = 0;
        }
 
-       list_for_each_entry_safe(pt, next, &master->magicfree, head) {
-               list_del(&pt->head);
-               drm_ht_remove_item(&master->magiclist, &pt->hash_item);
-               kfree(pt);
-       }
-
        drm_ht_remove(&master->magiclist);
 
        mutex_unlock(&dev->struct_mutex);
@@ -615,7 +595,7 @@ struct drm_device *drm_dev_alloc(struct drm_driver *driver,
                goto err_ht;
        }
 
-       if (driver->driver_features & DRIVER_GEM) {
+       if (drm_core_check_feature(dev, DRIVER_GEM)) {
                ret = drm_gem_init(dev);
                if (ret) {
                        DRM_ERROR("Cannot initialize graphics execution manager (GEM)\n");
@@ -645,7 +625,7 @@ static void drm_dev_release(struct kref *ref)
 {
        struct drm_device *dev = container_of(ref, struct drm_device, ref);
 
-       if (dev->driver->driver_features & DRIVER_GEM)
+       if (drm_core_check_feature(dev, DRIVER_GEM))
                drm_gem_destroy(dev);
 
        drm_legacy_ctxbitmap_cleanup(dev);
@@ -779,7 +759,7 @@ void drm_dev_unregister(struct drm_device *dev)
        drm_vblank_cleanup(dev);
 
        list_for_each_entry_safe(r_list, list_temp, &dev->maplist, head)
-               drm_rmmap(dev, r_list->map);
+               drm_legacy_rmmap(dev, r_list->map);
 
        drm_minor_unregister(dev, DRM_MINOR_LEGACY);
        drm_minor_unregister(dev, DRM_MINOR_RENDER);
index 1dbf3bc4c6a3cdd580d00706052976aed01b94c9..3bf999134bcc503dd12e9c8dce3244a81e447a24 100644 (file)
@@ -632,27 +632,27 @@ static const struct drm_display_mode edid_cea_modes[] = {
                   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC |
                        DRM_MODE_FLAG_INTERLACE),
          .vrefresh = 60, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, },
-       /* 6 - 1440x480i@60Hz */
-       { DRM_MODE("1440x480i", DRM_MODE_TYPE_DRIVER, 27000, 1440, 1478,
-                  1602, 1716, 0, 480, 488, 494, 525, 0,
+       /* 6 - 720(1440)x480i@60Hz */
+       { DRM_MODE("720x480i", DRM_MODE_TYPE_DRIVER, 13500, 720, 739,
+                  801, 858, 0, 480, 488, 494, 525, 0,
                   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
                        DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK),
          .vrefresh = 60, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_4_3, },
-       /* 7 - 1440x480i@60Hz */
-       { DRM_MODE("1440x480i", DRM_MODE_TYPE_DRIVER, 27000, 1440, 1478,
-                  1602, 1716, 0, 480, 488, 494, 525, 0,
+       /* 7 - 720(1440)x480i@60Hz */
+       { DRM_MODE("720x480i", DRM_MODE_TYPE_DRIVER, 13500, 720, 739,
+                  801, 858, 0, 480, 488, 494, 525, 0,
                   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
                        DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK),
          .vrefresh = 60, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, },
-       /* 8 - 1440x240@60Hz */
-       { DRM_MODE("1440x240", DRM_MODE_TYPE_DRIVER, 27000, 1440, 1478,
-                  1602, 1716, 0, 240, 244, 247, 262, 0,
+       /* 8 - 720(1440)x240@60Hz */
+       { DRM_MODE("720x240", DRM_MODE_TYPE_DRIVER, 13500, 720, 739,
+                  801, 858, 0, 240, 244, 247, 262, 0,
                   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
                        DRM_MODE_FLAG_DBLCLK),
          .vrefresh = 60, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_4_3, },
-       /* 9 - 1440x240@60Hz */
-       { DRM_MODE("1440x240", DRM_MODE_TYPE_DRIVER, 27000, 1440, 1478,
-                  1602, 1716, 0, 240, 244, 247, 262, 0,
+       /* 9 - 720(1440)x240@60Hz */
+       { DRM_MODE("720x240", DRM_MODE_TYPE_DRIVER, 13500, 720, 739,
+                  801, 858, 0, 240, 244, 247, 262, 0,
                   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
                        DRM_MODE_FLAG_DBLCLK),
          .vrefresh = 60, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, },
@@ -714,27 +714,27 @@ static const struct drm_display_mode edid_cea_modes[] = {
                   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC |
                        DRM_MODE_FLAG_INTERLACE),
          .vrefresh = 50, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, },
-       /* 21 - 1440x576i@50Hz */
-       { DRM_MODE("1440x576i", DRM_MODE_TYPE_DRIVER, 27000, 1440, 1464,
-                  1590, 1728, 0, 576, 580, 586, 625, 0,
+       /* 21 - 720(1440)x576i@50Hz */
+       { DRM_MODE("720x576i", DRM_MODE_TYPE_DRIVER, 13500, 720, 732,
+                  795, 864, 0, 576, 580, 586, 625, 0,
                   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
                        DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK),
          .vrefresh = 50, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_4_3, },
-       /* 22 - 1440x576i@50Hz */
-       { DRM_MODE("1440x576i", DRM_MODE_TYPE_DRIVER, 27000, 1440, 1464,
-                  1590, 1728, 0, 576, 580, 586, 625, 0,
+       /* 22 - 720(1440)x576i@50Hz */
+       { DRM_MODE("720x576i", DRM_MODE_TYPE_DRIVER, 13500, 720, 732,
+                  795, 864, 0, 576, 580, 586, 625, 0,
                   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
                        DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK),
          .vrefresh = 50, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, },
-       /* 23 - 1440x288@50Hz */
-       { DRM_MODE("1440x288", DRM_MODE_TYPE_DRIVER, 27000, 1440, 1464,
-                  1590, 1728, 0, 288, 290, 293, 312, 0,
+       /* 23 - 720(1440)x288@50Hz */
+       { DRM_MODE("720x288", DRM_MODE_TYPE_DRIVER, 13500, 720, 732,
+                  795, 864, 0, 288, 290, 293, 312, 0,
                   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
                        DRM_MODE_FLAG_DBLCLK),
          .vrefresh = 50, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_4_3, },
-       /* 24 - 1440x288@50Hz */
-       { DRM_MODE("1440x288", DRM_MODE_TYPE_DRIVER, 27000, 1440, 1464,
-                  1590, 1728, 0, 288, 290, 293, 312, 0,
+       /* 24 - 720(1440)x288@50Hz */
+       { DRM_MODE("720x288", DRM_MODE_TYPE_DRIVER, 13500, 720, 732,
+                  795, 864, 0, 288, 290, 293, 312, 0,
                   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
                        DRM_MODE_FLAG_DBLCLK),
          .vrefresh = 50, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, },
@@ -837,17 +837,17 @@ static const struct drm_display_mode edid_cea_modes[] = {
                   796, 864, 0, 576, 581, 586, 625, 0,
                   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC),
          .vrefresh = 100, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, },
-       /* 44 - 1440x576i@100Hz */
-       { DRM_MODE("1440x576", DRM_MODE_TYPE_DRIVER, 54000, 1440, 1464,
-                  1590, 1728, 0, 576, 580, 586, 625, 0,
+       /* 44 - 720(1440)x576i@100Hz */
+       { DRM_MODE("720x576i", DRM_MODE_TYPE_DRIVER, 27000, 720, 732,
+                  795, 864, 0, 576, 580, 586, 625, 0,
                   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
-                       DRM_MODE_FLAG_DBLCLK),
+                       DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK),
          .vrefresh = 100, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_4_3, },
-       /* 45 - 1440x576i@100Hz */
-       { DRM_MODE("1440x576", DRM_MODE_TYPE_DRIVER, 54000, 1440, 1464,
-                  1590, 1728, 0, 576, 580, 586, 625, 0,
+       /* 45 - 720(1440)x576i@100Hz */
+       { DRM_MODE("720x576i", DRM_MODE_TYPE_DRIVER, 27000, 720, 732,
+                  795, 864, 0, 576, 580, 586, 625, 0,
                   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
-                       DRM_MODE_FLAG_DBLCLK),
+                       DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK),
          .vrefresh = 100, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, },
        /* 46 - 1920x1080i@120Hz */
        { DRM_MODE("1920x1080i", DRM_MODE_TYPE_DRIVER, 148500, 1920, 2008,
@@ -870,15 +870,15 @@ static const struct drm_display_mode edid_cea_modes[] = {
                   798, 858, 0, 480, 489, 495, 525, 0,
                   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC),
          .vrefresh = 120, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, },
-       /* 50 - 1440x480i@120Hz */
-       { DRM_MODE("1440x480i", DRM_MODE_TYPE_DRIVER, 54000, 1440, 1478,
-                  1602, 1716, 0, 480, 488, 494, 525, 0,
+       /* 50 - 720(1440)x480i@120Hz */
+       { DRM_MODE("720x480i", DRM_MODE_TYPE_DRIVER, 27000, 720, 739,
+                  801, 858, 0, 480, 488, 494, 525, 0,
                   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
                        DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK),
          .vrefresh = 120, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_4_3, },
-       /* 51 - 1440x480i@120Hz */
-       { DRM_MODE("1440x480i", DRM_MODE_TYPE_DRIVER, 54000, 1440, 1478,
-                  1602, 1716, 0, 480, 488, 494, 525, 0,
+       /* 51 - 720(1440)x480i@120Hz */
+       { DRM_MODE("720x480i", DRM_MODE_TYPE_DRIVER, 27000, 720, 739,
+                  801, 858, 0, 480, 488, 494, 525, 0,
                   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
                        DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK),
          .vrefresh = 120, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, },
@@ -892,15 +892,15 @@ static const struct drm_display_mode edid_cea_modes[] = {
                   796, 864, 0, 576, 581, 586, 625, 0,
                   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC),
          .vrefresh = 200, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, },
-       /* 54 - 1440x576i@200Hz */
-       { DRM_MODE("1440x576i", DRM_MODE_TYPE_DRIVER, 108000, 1440, 1464,
-                  1590, 1728, 0, 576, 580, 586, 625, 0,
+       /* 54 - 720(1440)x576i@200Hz */
+       { DRM_MODE("720x576i", DRM_MODE_TYPE_DRIVER, 54000, 720, 732,
+                  795, 864, 0, 576, 580, 586, 625, 0,
                   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
                        DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK),
          .vrefresh = 200, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_4_3, },
-       /* 55 - 1440x576i@200Hz */
-       { DRM_MODE("1440x576i", DRM_MODE_TYPE_DRIVER, 108000, 1440, 1464,
-                  1590, 1728, 0, 576, 580, 586, 625, 0,
+       /* 55 - 720(1440)x576i@200Hz */
+       { DRM_MODE("720x576i", DRM_MODE_TYPE_DRIVER, 54000, 720, 732,
+                  795, 864, 0, 576, 580, 586, 625, 0,
                   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
                        DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK),
          .vrefresh = 200, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, },
@@ -914,15 +914,15 @@ static const struct drm_display_mode edid_cea_modes[] = {
                   798, 858, 0, 480, 489, 495, 525, 0,
                   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC),
          .vrefresh = 240, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, },
-       /* 58 - 1440x480i@240 */
-       { DRM_MODE("1440x480i", DRM_MODE_TYPE_DRIVER, 108000, 1440, 1478,
-                  1602, 1716, 0, 480, 488, 494, 525, 0,
+       /* 58 - 720(1440)x480i@240 */
+       { DRM_MODE("720x480i", DRM_MODE_TYPE_DRIVER, 54000, 720, 739,
+                  801, 858, 0, 480, 488, 494, 525, 0,
                   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
                        DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK),
          .vrefresh = 240, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_4_3, },
-       /* 59 - 1440x480i@240 */
-       { DRM_MODE("1440x480i", DRM_MODE_TYPE_DRIVER, 108000, 1440, 1478,
-                  1602, 1716, 0, 480, 488, 494, 525, 0,
+       /* 59 - 720(1440)x480i@240 */
+       { DRM_MODE("720x480i", DRM_MODE_TYPE_DRIVER, 54000, 720, 739,
+                  801, 858, 0, 480, 488, 494, 525, 0,
                   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
                        DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK),
          .vrefresh = 240, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, },
@@ -2103,7 +2103,8 @@ static int
 add_inferred_modes(struct drm_connector *connector, struct edid *edid)
 {
        struct detailed_mode_closure closure = {
-               connector, edid, 0, 0, 0
+               .connector = connector,
+               .edid = edid,
        };
 
        if (version_greater(edid, 1, 0))
@@ -2169,7 +2170,8 @@ add_established_modes(struct drm_connector *connector, struct edid *edid)
                ((edid->established_timings.mfg_rsvd & 0x80) << 9);
        int i, modes = 0;
        struct detailed_mode_closure closure = {
-               connector, edid, 0, 0, 0
+               .connector = connector,
+               .edid = edid,
        };
 
        for (i = 0; i <= EDID_EST_TIMINGS; i++) {
@@ -2227,7 +2229,8 @@ add_standard_modes(struct drm_connector *connector, struct edid *edid)
 {
        int i, modes = 0;
        struct detailed_mode_closure closure = {
-               connector, edid, 0, 0, 0
+               .connector = connector,
+               .edid = edid,
        };
 
        for (i = 0; i < EDID_STD_TIMINGS; i++) {
@@ -2313,7 +2316,8 @@ static int
 add_cvt_modes(struct drm_connector *connector, struct edid *edid)
 {      
        struct detailed_mode_closure closure = {
-               connector, edid, 0, 0, 0
+               .connector = connector,
+               .edid = edid,
        };
 
        if (version_greater(edid, 1, 2))
@@ -2357,11 +2361,10 @@ add_detailed_modes(struct drm_connector *connector, struct edid *edid,
                   u32 quirks)
 {
        struct detailed_mode_closure closure = {
-               connector,
-               edid,
-               1,
-               quirks,
-               0
+               .connector = connector,
+               .edid = edid,
+               .preferred = 1,
+               .quirks = quirks,
        };
 
        if (closure.preferred && !version_greater(edid, 1, 3))
@@ -3433,10 +3436,10 @@ EXPORT_SYMBOL(drm_rgb_quant_range_selectable);
 /**
  * drm_assign_hdmi_deep_color_info - detect whether monitor supports
  * hdmi deep color modes and update drm_display_info if so.
- *
  * @edid: monitor EDID information
  * @info: Updated with maximum supported deep color bpc and color format
  *        if deep color supported.
+ * @connector: DRM connector, used only for debug output
  *
  * Parse the CEA extension according to CEA-861-B.
  * Return true if HDMI deep color supported, false if not or unknown.
index 3144db9dc0f1f0bf3b0ea7ca8d42665fb47a37f6..0c0c39bac23da21a368ef94681da10b173994660 100644 (file)
@@ -126,7 +126,7 @@ int drm_fb_helper_add_one_connector(struct drm_fb_helper *fb_helper, struct drm_
 
        WARN_ON(!mutex_is_locked(&fb_helper->dev->mode_config.mutex));
        if (fb_helper->connector_count + 1 > fb_helper->connector_info_alloc_count) {
-               temp = krealloc(fb_helper->connector_info, sizeof(struct drm_fb_helper_connector) * (fb_helper->connector_count + 1), GFP_KERNEL);
+               temp = krealloc(fb_helper->connector_info, sizeof(struct drm_fb_helper_connector *) * (fb_helper->connector_count + 1), GFP_KERNEL);
                if (!temp)
                        return -ENOMEM;
 
@@ -171,60 +171,6 @@ int drm_fb_helper_remove_one_connector(struct drm_fb_helper *fb_helper,
 }
 EXPORT_SYMBOL(drm_fb_helper_remove_one_connector);
 
-static int drm_fb_helper_parse_command_line(struct drm_fb_helper *fb_helper)
-{
-       struct drm_fb_helper_connector *fb_helper_conn;
-       int i;
-
-       for (i = 0; i < fb_helper->connector_count; i++) {
-               struct drm_cmdline_mode *mode;
-               struct drm_connector *connector;
-               char *option = NULL;
-
-               fb_helper_conn = fb_helper->connector_info[i];
-               connector = fb_helper_conn->connector;
-               mode = &fb_helper_conn->cmdline_mode;
-
-               /* do something on return - turn off connector maybe */
-               if (fb_get_options(connector->name, &option))
-                       continue;
-
-               if (drm_mode_parse_command_line_for_connector(option,
-                                                             connector,
-                                                             mode)) {
-                       if (mode->force) {
-                               const char *s;
-                               switch (mode->force) {
-                               case DRM_FORCE_OFF:
-                                       s = "OFF";
-                                       break;
-                               case DRM_FORCE_ON_DIGITAL:
-                                       s = "ON - dig";
-                                       break;
-                               default:
-                               case DRM_FORCE_ON:
-                                       s = "ON";
-                                       break;
-                               }
-
-                               DRM_INFO("forcing %s connector %s\n",
-                                        connector->name, s);
-                               connector->force = mode->force;
-                       }
-
-                       DRM_DEBUG_KMS("cmdline mode for connector %s %dx%d@%dHz%s%s%s\n",
-                                     connector->name,
-                                     mode->xres, mode->yres,
-                                     mode->refresh_specified ? mode->refresh : 60,
-                                     mode->rb ? " reduced blanking" : "",
-                                     mode->margins ? " with margins" : "",
-                                     mode->interlace ?  " interlaced" : "");
-               }
-
-       }
-       return 0;
-}
-
 static void drm_fb_helper_save_lut_atomic(struct drm_crtc *crtc, struct drm_fb_helper *helper)
 {
        uint16_t *r_base, *g_base, *b_base;
@@ -345,10 +291,17 @@ static bool restore_fbdev_mode(struct drm_fb_helper *fb_helper)
 
        drm_warn_on_modeset_not_all_locked(dev);
 
-       list_for_each_entry(plane, &dev->mode_config.plane_list, head)
+       list_for_each_entry(plane, &dev->mode_config.plane_list, head) {
                if (plane->type != DRM_PLANE_TYPE_PRIMARY)
                        drm_plane_force_disable(plane);
 
+               if (dev->mode_config.rotation_property) {
+                       drm_mode_plane_set_obj_prop(plane,
+                                                   dev->mode_config.rotation_property,
+                                                   BIT(DRM_ROTATE_0));
+               }
+       }
+
        for (i = 0; i < fb_helper->crtc_count; i++) {
                struct drm_mode_set *mode_set = &fb_helper->crtc_info[i].mode_set;
                struct drm_crtc *crtc = mode_set->crtc;
@@ -419,11 +372,11 @@ static bool drm_fb_helper_force_kernel_mode(void)
                if (dev->switch_power_state == DRM_SWITCH_POWER_OFF)
                        continue;
 
-               /* NOTE: we use lockless flag below to avoid grabbing other
-                * modeset locks.  So just trylock the underlying mutex
-                * directly:
+               /*
+                * NOTE: Use trylock mode to avoid deadlocks and sleeping in
+                * panic context.
                 */
-               if (!mutex_trylock(&dev->mode_config.mutex)) {
+               if (__drm_modeset_lock_all(dev, true) != 0) {
                        error = true;
                        continue;
                }
@@ -432,7 +385,7 @@ static bool drm_fb_helper_force_kernel_mode(void)
                if (ret)
                        error = true;
 
-               mutex_unlock(&dev->mode_config.mutex);
+               drm_modeset_unlock_all(dev);
        }
        return error;
 }
@@ -1013,7 +966,7 @@ static int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper,
                struct drm_fb_helper_connector *fb_helper_conn = fb_helper->connector_info[i];
                struct drm_cmdline_mode *cmdline_mode;
 
-               cmdline_mode = &fb_helper_conn->cmdline_mode;
+               cmdline_mode = &fb_helper_conn->connector->cmdline_mode;
 
                if (cmdline_mode->bpp_specified) {
                        switch (cmdline_mode->bpp) {
@@ -1260,9 +1213,7 @@ EXPORT_SYMBOL(drm_has_preferred_mode);
 
 static bool drm_has_cmdline_mode(struct drm_fb_helper_connector *fb_connector)
 {
-       struct drm_cmdline_mode *cmdline_mode;
-       cmdline_mode = &fb_connector->cmdline_mode;
-       return cmdline_mode->specified;
+       return fb_connector->connector->cmdline_mode.specified;
 }
 
 struct drm_display_mode *drm_pick_cmdline_mode(struct drm_fb_helper_connector *fb_helper_conn,
@@ -1272,7 +1223,7 @@ struct drm_display_mode *drm_pick_cmdline_mode(struct drm_fb_helper_connector *f
        struct drm_display_mode *mode = NULL;
        bool prefer_non_interlace;
 
-       cmdline_mode = &fb_helper_conn->cmdline_mode;
+       cmdline_mode = &fb_helper_conn->connector->cmdline_mode;
        if (cmdline_mode->specified == false)
                return mode;
 
@@ -1657,8 +1608,6 @@ bool drm_fb_helper_initial_config(struct drm_fb_helper *fb_helper, int bpp_sel)
        struct drm_device *dev = fb_helper->dev;
        int count = 0;
 
-       drm_fb_helper_parse_command_line(fb_helper);
-
        mutex_lock(&dev->mode_config.mutex);
        count = drm_fb_helper_probe_connector_modes(fb_helper,
                                                    dev->mode_config.max_width,
index 79d5221c6e41c9880b5620623c9653799c1044ed..ed7bc68f7e8700041894c7f35685af449c4deb2e 100644 (file)
 #include <linux/slab.h>
 #include <linux/module.h>
 #include "drm_legacy.h"
+#include "drm_internal.h"
 
 /* from BKL pushdown */
 DEFINE_MUTEX(drm_global_mutex);
-EXPORT_SYMBOL(drm_global_mutex);
 
 static int drm_open_helper(struct file *filp, struct drm_minor *minor);
 
@@ -171,7 +171,7 @@ static int drm_open_helper(struct file *filp, struct drm_minor *minor)
        init_waitqueue_head(&priv->event_wait);
        priv->event_space = 4096; /* set aside 4k for event buffer */
 
-       if (dev->driver->driver_features & DRIVER_GEM)
+       if (drm_core_check_feature(dev, DRIVER_GEM))
                drm_gem_open(dev, priv);
 
        if (drm_core_check_feature(dev, DRIVER_PRIME))
@@ -256,7 +256,7 @@ out_close:
 out_prime_destroy:
        if (drm_core_check_feature(dev, DRIVER_PRIME))
                drm_prime_destroy_file_private(&priv->prime);
-       if (dev->driver->driver_features & DRIVER_GEM)
+       if (drm_core_check_feature(dev, DRIVER_GEM))
                drm_gem_release(dev, priv);
        put_pid(priv->pid);
        kfree(priv);
@@ -268,11 +268,11 @@ static void drm_master_release(struct drm_device *dev, struct file *filp)
 {
        struct drm_file *file_priv = filp->private_data;
 
-       if (drm_i_have_hw_lock(dev, file_priv)) {
+       if (drm_legacy_i_have_hw_lock(dev, file_priv)) {
                DRM_DEBUG("File %p released, freeing lock for context %d\n",
                          filp, _DRM_LOCKING_CONTEXT(file_priv->master->lock.hw_lock->lock));
-               drm_lock_free(&file_priv->master->lock,
-                             _DRM_LOCKING_CONTEXT(file_priv->master->lock.hw_lock->lock));
+               drm_legacy_lock_free(&file_priv->master->lock,
+                                    _DRM_LOCKING_CONTEXT(file_priv->master->lock.hw_lock->lock));
        }
 }
 
@@ -330,8 +330,6 @@ static void drm_legacy_dev_reinit(struct drm_device *dev)
  */
 int drm_lastclose(struct drm_device * dev)
 {
-       struct drm_vma_entry *vma, *vma_temp;
-
        DRM_DEBUG("\n");
 
        if (dev->driver->lastclose)
@@ -346,13 +344,7 @@ int drm_lastclose(struct drm_device * dev)
        drm_agp_clear(dev);
 
        drm_legacy_sg_cleanup(dev);
-
-       /* Clear vma list (only built for debugging) */
-       list_for_each_entry_safe(vma, vma_temp, &dev->vmalist, head) {
-               list_del(&vma->head);
-               kfree(vma);
-       }
-
+       drm_legacy_vma_flush(dev);
        drm_legacy_dma_takedown(dev);
 
        mutex_unlock(&dev->struct_mutex);
@@ -412,14 +404,14 @@ int drm_release(struct inode *inode, struct file *filp)
                drm_master_release(dev, filp);
 
        if (drm_core_check_feature(dev, DRIVER_HAVE_DMA))
-               drm_core_reclaim_buffers(dev, file_priv);
+               drm_legacy_reclaim_buffers(dev, file_priv);
 
        drm_events_release(file_priv);
 
-       if (dev->driver->driver_features & DRIVER_MODESET)
+       if (drm_core_check_feature(dev, DRIVER_MODESET))
                drm_fb_release(file_priv);
 
-       if (dev->driver->driver_features & DRIVER_GEM)
+       if (drm_core_check_feature(dev, DRIVER_GEM))
                drm_gem_release(dev, file_priv);
 
        drm_legacy_ctxbitmap_flush(dev, file_priv);
@@ -464,6 +456,8 @@ int drm_release(struct inode *inode, struct file *filp)
        if (drm_core_check_feature(dev, DRIVER_PRIME))
                drm_prime_destroy_file_private(&file_priv->prime);
 
+       WARN_ON(!list_empty(&file_priv->event_list));
+
        put_pid(file_priv->pid);
        kfree(file_priv);
 
index 6adee4c2afc0870c6fb3bcbb07387f923d32eb1d..f6ca51259fa3a90dbc46fff70d8e15dc5e483ba8 100644 (file)
@@ -38,6 +38,8 @@
 #include <linux/dma-buf.h>
 #include <drm/drmP.h>
 #include <drm/drm_vma_manager.h>
+#include <drm/drm_gem.h>
+#include "drm_internal.h"
 
 /** @file drm_gem.c
  *
@@ -146,7 +148,7 @@ int drm_gem_object_init(struct drm_device *dev,
 EXPORT_SYMBOL(drm_gem_object_init);
 
 /**
- * drm_gem_object_init - initialize an allocated private GEM object
+ * drm_gem_private_object_init - initialize an allocated private GEM object
  * @dev: drm_device the object should be initialized for
  * @obj: drm_gem_object to initialize
  * @size: object size
@@ -579,7 +581,7 @@ drm_gem_close_ioctl(struct drm_device *dev, void *data,
        struct drm_gem_close *args = data;
        int ret;
 
-       if (!(dev->driver->driver_features & DRIVER_GEM))
+       if (!drm_core_check_feature(dev, DRIVER_GEM))
                return -ENODEV;
 
        ret = drm_gem_handle_delete(file_priv, args->handle);
@@ -606,7 +608,7 @@ drm_gem_flink_ioctl(struct drm_device *dev, void *data,
        struct drm_gem_object *obj;
        int ret;
 
-       if (!(dev->driver->driver_features & DRIVER_GEM))
+       if (!drm_core_check_feature(dev, DRIVER_GEM))
                return -ENODEV;
 
        obj = drm_gem_object_lookup(dev, file_priv, args->handle);
@@ -659,7 +661,7 @@ drm_gem_open_ioctl(struct drm_device *dev, void *data,
        int ret;
        u32 handle;
 
-       if (!(dev->driver->driver_features & DRIVER_GEM))
+       if (!drm_core_check_feature(dev, DRIVER_GEM))
                return -ENODEV;
 
        mutex_lock(&dev->object_name_lock);
@@ -887,7 +889,7 @@ int drm_gem_mmap(struct file *filp, struct vm_area_struct *vma)
                                           vma_pages(vma));
        if (!node) {
                mutex_unlock(&dev->struct_mutex);
-               return drm_mmap(filp, vma);
+               return -EINVAL;
        } else if (!drm_vma_node_is_allowed(node, filp)) {
                mutex_unlock(&dev->struct_mutex);
                return -EACCES;
index e467e67af6e7111c69b96cb792380b5727500650..0316310e2cc47400703418ea324e381cc65f8c8b 100644 (file)
@@ -316,7 +316,8 @@ out:
 EXPORT_SYMBOL_GPL(drm_gem_cma_prime_get_sg_table);
 
 struct drm_gem_object *
-drm_gem_cma_prime_import_sg_table(struct drm_device *dev, size_t size,
+drm_gem_cma_prime_import_sg_table(struct drm_device *dev,
+                                 struct dma_buf_attachment *attach,
                                  struct sg_table *sgt)
 {
        struct drm_gem_cma_object *cma_obj;
@@ -325,14 +326,14 @@ drm_gem_cma_prime_import_sg_table(struct drm_device *dev, size_t size,
                return ERR_PTR(-EINVAL);
 
        /* Create a CMA GEM buffer. */
-       cma_obj = __drm_gem_cma_create(dev, size);
+       cma_obj = __drm_gem_cma_create(dev, attach->dmabuf->size);
        if (IS_ERR(cma_obj))
                return ERR_CAST(cma_obj);
 
        cma_obj->paddr = sg_dma_address(sgt->sgl);
        cma_obj->sgt = sgt;
 
-       DRM_DEBUG_PRIME("dma_addr = %pad, size = %zu\n", &cma_obj->paddr, size);
+       DRM_DEBUG_PRIME("dma_addr = %pad, size = %zu\n", &cma_obj->paddr, attach->dmabuf->size);
 
        return &cma_obj->base;
 }
index ecaf0fa2eec8fe5d3c95ea324b6d6e0510003dec..51efebd434f302d61134c2eb384935ef4c1b2521 100644 (file)
@@ -35,6 +35,9 @@
 
 #include <linux/seq_file.h>
 #include <drm/drmP.h>
+#include <drm/drm_gem.h>
+
+#include "drm_legacy.h"
 
 /**
  * Called when "/proc/dri/.../name" is read.
@@ -183,15 +186,32 @@ int drm_clients_info(struct seq_file *m, void *data)
        struct drm_device *dev = node->minor->dev;
        struct drm_file *priv;
 
+       seq_printf(m,
+                  "%20s %5s %3s master a %5s %10s\n",
+                  "command",
+                  "pid",
+                  "dev",
+                  "uid",
+                  "magic");
+
+       /* dev->filelist is sorted youngest first, but we want to present
+        * oldest first (i.e. kernel, servers, clients), so walk backwardss.
+        */
        mutex_lock(&dev->struct_mutex);
-       seq_printf(m, "a dev    pid    uid      magic\n\n");
-       list_for_each_entry(priv, &dev->filelist, lhead) {
-               seq_printf(m, "%c %3d %5d %5d %10u\n",
-                          priv->authenticated ? 'y' : 'n',
-                          priv->minor->index,
+       list_for_each_entry_reverse(priv, &dev->filelist, lhead) {
+               struct task_struct *task;
+
+               rcu_read_lock(); /* locks pid_task()->comm */
+               task = pid_task(priv->pid, PIDTYPE_PID);
+               seq_printf(m, "%20s %5d %3d   %c    %c %5d %10u\n",
+                          task ? task->comm : "<unknown>",
                           pid_vnr(priv->pid),
+                          priv->minor->index,
+                          priv->is_master ? 'y' : 'n',
+                          priv->authenticated ? 'y' : 'n',
                           from_kuid_munged(seq_user_ns(m), priv->uid),
                           priv->magic);
+               rcu_read_unlock();
        }
        mutex_unlock(&dev->struct_mutex);
        return 0;
@@ -223,62 +243,3 @@ int drm_gem_name_info(struct seq_file *m, void *data)
 
        return 0;
 }
-
-#if DRM_DEBUG_CODE
-
-int drm_vma_info(struct seq_file *m, void *data)
-{
-       struct drm_info_node *node = (struct drm_info_node *) m->private;
-       struct drm_device *dev = node->minor->dev;
-       struct drm_vma_entry *pt;
-       struct vm_area_struct *vma;
-       unsigned long vma_count = 0;
-#if defined(__i386__)
-       unsigned int pgprot;
-#endif
-
-       mutex_lock(&dev->struct_mutex);
-       list_for_each_entry(pt, &dev->vmalist, head)
-               vma_count++;
-
-       seq_printf(m, "vma use count: %lu, high_memory = %pK, 0x%pK\n",
-                  vma_count, high_memory,
-                  (void *)(unsigned long)virt_to_phys(high_memory));
-
-       list_for_each_entry(pt, &dev->vmalist, head) {
-               vma = pt->vma;
-               if (!vma)
-                       continue;
-               seq_printf(m,
-                          "\n%5d 0x%pK-0x%pK %c%c%c%c%c%c 0x%08lx000",
-                          pt->pid,
-                          (void *)vma->vm_start, (void *)vma->vm_end,
-                          vma->vm_flags & VM_READ ? 'r' : '-',
-                          vma->vm_flags & VM_WRITE ? 'w' : '-',
-                          vma->vm_flags & VM_EXEC ? 'x' : '-',
-                          vma->vm_flags & VM_MAYSHARE ? 's' : 'p',
-                          vma->vm_flags & VM_LOCKED ? 'l' : '-',
-                          vma->vm_flags & VM_IO ? 'i' : '-',
-                          vma->vm_pgoff);
-
-#if defined(__i386__)
-               pgprot = pgprot_val(vma->vm_page_prot);
-               seq_printf(m, " %c%c%c%c%c%c%c%c%c",
-                          pgprot & _PAGE_PRESENT ? 'p' : '-',
-                          pgprot & _PAGE_RW ? 'w' : 'r',
-                          pgprot & _PAGE_USER ? 'u' : 's',
-                          pgprot & _PAGE_PWT ? 't' : 'b',
-                          pgprot & _PAGE_PCD ? 'u' : 'c',
-                          pgprot & _PAGE_ACCESSED ? 'a' : '-',
-                          pgprot & _PAGE_DIRTY ? 'd' : '-',
-                          pgprot & _PAGE_PSE ? 'm' : 'k',
-                          pgprot & _PAGE_GLOBAL ? 'g' : 'l');
-#endif
-               seq_printf(m, "\n");
-       }
-       mutex_unlock(&dev->struct_mutex);
-       return 0;
-}
-
-#endif
-
diff --git a/drivers/gpu/drm/drm_internal.h b/drivers/gpu/drm/drm_internal.h
new file mode 100644 (file)
index 0000000..7cc0a35
--- /dev/null
@@ -0,0 +1,132 @@
+/*
+ * Copyright Â© 2014 Intel Corporation
+ *   Daniel Vetter <daniel.vetter@ffwll.ch>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/* drm_irq.c */
+extern unsigned int drm_timestamp_monotonic;
+
+/* drm_fops.c */
+extern struct mutex drm_global_mutex;
+int drm_lastclose(struct drm_device *dev);
+
+/* drm_pci.c */
+int drm_pci_set_unique(struct drm_device *dev,
+                      struct drm_master *master,
+                      struct drm_unique *u);
+int drm_irq_by_busid(struct drm_device *dev, void *data,
+                    struct drm_file *file_priv);
+
+/* drm_vm.c */
+int drm_vma_info(struct seq_file *m, void *data);
+void drm_vm_open_locked(struct drm_device *dev, struct vm_area_struct *vma);
+void drm_vm_close_locked(struct drm_device *dev, struct vm_area_struct *vma);
+
+/* drm_prime.c */
+int drm_prime_handle_to_fd_ioctl(struct drm_device *dev, void *data,
+                                struct drm_file *file_priv);
+int drm_prime_fd_to_handle_ioctl(struct drm_device *dev, void *data,
+                                struct drm_file *file_priv);
+
+void drm_prime_init_file_private(struct drm_prime_file_private *prime_fpriv);
+void drm_prime_destroy_file_private(struct drm_prime_file_private *prime_fpriv);
+void drm_prime_remove_buf_handle_locked(struct drm_prime_file_private *prime_fpriv,
+                                       struct dma_buf *dma_buf);
+
+/* drm_info.c */
+int drm_name_info(struct seq_file *m, void *data);
+int drm_vm_info(struct seq_file *m, void *data);
+int drm_bufs_info(struct seq_file *m, void *data);
+int drm_vblank_info(struct seq_file *m, void *data);
+int drm_clients_info(struct seq_file *m, void* data);
+int drm_gem_name_info(struct seq_file *m, void *data);
+
+/* drm_irq.c */
+int drm_control(struct drm_device *dev, void *data,
+               struct drm_file *file_priv);
+int drm_modeset_ctl(struct drm_device *dev, void *data,
+                   struct drm_file *file_priv);
+
+/* drm_auth.c */
+int drm_getmagic(struct drm_device *dev, void *data,
+                struct drm_file *file_priv);
+int drm_authmagic(struct drm_device *dev, void *data,
+                 struct drm_file *file_priv);
+int drm_remove_magic(struct drm_master *master, drm_magic_t magic);
+
+/* drm_sysfs.c */
+extern struct class *drm_class;
+
+struct class *drm_sysfs_create(struct module *owner, char *name);
+void drm_sysfs_destroy(void);
+struct device *drm_sysfs_minor_alloc(struct drm_minor *minor);
+int drm_sysfs_connector_add(struct drm_connector *connector);
+void drm_sysfs_connector_remove(struct drm_connector *connector);
+
+/* drm_gem.c */
+int drm_gem_init(struct drm_device *dev);
+void drm_gem_destroy(struct drm_device *dev);
+int drm_gem_handle_create_tail(struct drm_file *file_priv,
+                              struct drm_gem_object *obj,
+                              u32 *handlep);
+int drm_gem_close_ioctl(struct drm_device *dev, void *data,
+                       struct drm_file *file_priv);
+int drm_gem_flink_ioctl(struct drm_device *dev, void *data,
+                       struct drm_file *file_priv);
+int drm_gem_open_ioctl(struct drm_device *dev, void *data,
+                      struct drm_file *file_priv);
+void drm_gem_open(struct drm_device *dev, struct drm_file *file_private);
+void drm_gem_release(struct drm_device *dev, struct drm_file *file_private);
+
+/* drm_drv.c */
+int drm_setmaster_ioctl(struct drm_device *dev, void *data,
+                       struct drm_file *file_priv);
+int drm_dropmaster_ioctl(struct drm_device *dev, void *data,
+                        struct drm_file *file_priv);
+struct drm_master *drm_master_create(struct drm_minor *minor);
+
+/* drm_debugfs.c */
+#if defined(CONFIG_DEBUG_FS)
+int drm_debugfs_init(struct drm_minor *minor, int minor_id,
+                    struct dentry *root);
+int drm_debugfs_cleanup(struct drm_minor *minor);
+int drm_debugfs_connector_add(struct drm_connector *connector);
+void drm_debugfs_connector_remove(struct drm_connector *connector);
+#else
+static inline int drm_debugfs_init(struct drm_minor *minor, int minor_id,
+                                  struct dentry *root)
+{
+       return 0;
+}
+
+static inline int drm_debugfs_cleanup(struct drm_minor *minor)
+{
+       return 0;
+}
+
+static inline int drm_debugfs_connector_add(struct drm_connector *connector)
+{
+       return 0;
+}
+static inline void drm_debugfs_connector_remove(struct drm_connector *connector)
+{
+}
+#endif
index 40be746b7e685ef2d205e700f15ca5c3c38a8afe..00587a1e3c83c0dc23c05a55a7d37ea10f891847 100644 (file)
@@ -31,6 +31,7 @@
 #include <drm/drmP.h>
 #include <drm/drm_core.h>
 #include "drm_legacy.h"
+#include "drm_internal.h"
 
 #include <linux/pci.h>
 #include <linux/export.h>
 static int drm_version(struct drm_device *dev, void *data,
                       struct drm_file *file_priv);
 
-#define DRM_IOCTL_DEF(ioctl, _func, _flags) \
-       [DRM_IOCTL_NR(ioctl)] = {.cmd = ioctl, .func = _func, .flags = _flags, .cmd_drv = 0, .name = #ioctl}
-
-/** Ioctl table */
-static const struct drm_ioctl_desc drm_ioctls[] = {
-       DRM_IOCTL_DEF(DRM_IOCTL_VERSION, drm_version, DRM_UNLOCKED|DRM_RENDER_ALLOW),
-       DRM_IOCTL_DEF(DRM_IOCTL_GET_UNIQUE, drm_getunique, 0),
-       DRM_IOCTL_DEF(DRM_IOCTL_GET_MAGIC, drm_getmagic, 0),
-       DRM_IOCTL_DEF(DRM_IOCTL_IRQ_BUSID, drm_irq_by_busid, DRM_MASTER|DRM_ROOT_ONLY),
-       DRM_IOCTL_DEF(DRM_IOCTL_GET_MAP, drm_getmap, DRM_UNLOCKED),
-       DRM_IOCTL_DEF(DRM_IOCTL_GET_CLIENT, drm_getclient, DRM_UNLOCKED),
-       DRM_IOCTL_DEF(DRM_IOCTL_GET_STATS, drm_getstats, DRM_UNLOCKED),
-       DRM_IOCTL_DEF(DRM_IOCTL_GET_CAP, drm_getcap, DRM_UNLOCKED|DRM_RENDER_ALLOW),
-       DRM_IOCTL_DEF(DRM_IOCTL_SET_CLIENT_CAP, drm_setclientcap, 0),
-       DRM_IOCTL_DEF(DRM_IOCTL_SET_VERSION, drm_setversion, DRM_MASTER),
-
-       DRM_IOCTL_DEF(DRM_IOCTL_SET_UNIQUE, drm_setunique, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
-       DRM_IOCTL_DEF(DRM_IOCTL_BLOCK, drm_noop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
-       DRM_IOCTL_DEF(DRM_IOCTL_UNBLOCK, drm_noop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
-       DRM_IOCTL_DEF(DRM_IOCTL_AUTH_MAGIC, drm_authmagic, DRM_AUTH|DRM_MASTER),
-
-       DRM_IOCTL_DEF(DRM_IOCTL_ADD_MAP, drm_addmap_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
-       DRM_IOCTL_DEF(DRM_IOCTL_RM_MAP, drm_rmmap_ioctl, DRM_AUTH),
-
-       DRM_IOCTL_DEF(DRM_IOCTL_SET_SAREA_CTX, drm_legacy_setsareactx, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
-       DRM_IOCTL_DEF(DRM_IOCTL_GET_SAREA_CTX, drm_legacy_getsareactx, DRM_AUTH),
-
-       DRM_IOCTL_DEF(DRM_IOCTL_SET_MASTER, drm_setmaster_ioctl, DRM_ROOT_ONLY),
-       DRM_IOCTL_DEF(DRM_IOCTL_DROP_MASTER, drm_dropmaster_ioctl, DRM_ROOT_ONLY),
-
-       DRM_IOCTL_DEF(DRM_IOCTL_ADD_CTX, drm_legacy_addctx, DRM_AUTH|DRM_ROOT_ONLY),
-       DRM_IOCTL_DEF(DRM_IOCTL_RM_CTX, drm_legacy_rmctx, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
-       DRM_IOCTL_DEF(DRM_IOCTL_MOD_CTX, drm_noop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
-       DRM_IOCTL_DEF(DRM_IOCTL_GET_CTX, drm_legacy_getctx, DRM_AUTH),
-       DRM_IOCTL_DEF(DRM_IOCTL_SWITCH_CTX, drm_legacy_switchctx, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
-       DRM_IOCTL_DEF(DRM_IOCTL_NEW_CTX, drm_legacy_newctx, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
-       DRM_IOCTL_DEF(DRM_IOCTL_RES_CTX, drm_legacy_resctx, DRM_AUTH),
-
-       DRM_IOCTL_DEF(DRM_IOCTL_ADD_DRAW, drm_noop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
-       DRM_IOCTL_DEF(DRM_IOCTL_RM_DRAW, drm_noop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
-
-       DRM_IOCTL_DEF(DRM_IOCTL_LOCK, drm_lock, DRM_AUTH),
-       DRM_IOCTL_DEF(DRM_IOCTL_UNLOCK, drm_unlock, DRM_AUTH),
-
-       DRM_IOCTL_DEF(DRM_IOCTL_FINISH, drm_noop, DRM_AUTH),
-
-       DRM_IOCTL_DEF(DRM_IOCTL_ADD_BUFS, drm_addbufs, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
-       DRM_IOCTL_DEF(DRM_IOCTL_MARK_BUFS, drm_markbufs, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
-       DRM_IOCTL_DEF(DRM_IOCTL_INFO_BUFS, drm_infobufs, DRM_AUTH),
-       DRM_IOCTL_DEF(DRM_IOCTL_MAP_BUFS, drm_mapbufs, DRM_AUTH),
-       DRM_IOCTL_DEF(DRM_IOCTL_FREE_BUFS, drm_freebufs, DRM_AUTH),
-       DRM_IOCTL_DEF(DRM_IOCTL_DMA, drm_dma_ioctl, DRM_AUTH),
-
-       DRM_IOCTL_DEF(DRM_IOCTL_CONTROL, drm_control, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
-
-#if __OS_HAS_AGP
-       DRM_IOCTL_DEF(DRM_IOCTL_AGP_ACQUIRE, drm_agp_acquire_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
-       DRM_IOCTL_DEF(DRM_IOCTL_AGP_RELEASE, drm_agp_release_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
-       DRM_IOCTL_DEF(DRM_IOCTL_AGP_ENABLE, drm_agp_enable_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
-       DRM_IOCTL_DEF(DRM_IOCTL_AGP_INFO, drm_agp_info_ioctl, DRM_AUTH),
-       DRM_IOCTL_DEF(DRM_IOCTL_AGP_ALLOC, drm_agp_alloc_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
-       DRM_IOCTL_DEF(DRM_IOCTL_AGP_FREE, drm_agp_free_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
-       DRM_IOCTL_DEF(DRM_IOCTL_AGP_BIND, drm_agp_bind_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
-       DRM_IOCTL_DEF(DRM_IOCTL_AGP_UNBIND, drm_agp_unbind_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
-#endif
-
-       DRM_IOCTL_DEF(DRM_IOCTL_SG_ALLOC, drm_sg_alloc, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
-       DRM_IOCTL_DEF(DRM_IOCTL_SG_FREE, drm_sg_free, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
-
-       DRM_IOCTL_DEF(DRM_IOCTL_WAIT_VBLANK, drm_wait_vblank, DRM_UNLOCKED),
-
-       DRM_IOCTL_DEF(DRM_IOCTL_MODESET_CTL, drm_modeset_ctl, 0),
-
-       DRM_IOCTL_DEF(DRM_IOCTL_UPDATE_DRAW, drm_noop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
-
-       DRM_IOCTL_DEF(DRM_IOCTL_GEM_CLOSE, drm_gem_close_ioctl, DRM_UNLOCKED|DRM_RENDER_ALLOW),
-       DRM_IOCTL_DEF(DRM_IOCTL_GEM_FLINK, drm_gem_flink_ioctl, DRM_AUTH|DRM_UNLOCKED),
-       DRM_IOCTL_DEF(DRM_IOCTL_GEM_OPEN, drm_gem_open_ioctl, DRM_AUTH|DRM_UNLOCKED),
-
-       DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETRESOURCES, drm_mode_getresources, DRM_CONTROL_ALLOW|DRM_UNLOCKED),
-
-       DRM_IOCTL_DEF(DRM_IOCTL_PRIME_HANDLE_TO_FD, drm_prime_handle_to_fd_ioctl, DRM_AUTH|DRM_UNLOCKED|DRM_RENDER_ALLOW),
-       DRM_IOCTL_DEF(DRM_IOCTL_PRIME_FD_TO_HANDLE, drm_prime_fd_to_handle_ioctl, DRM_AUTH|DRM_UNLOCKED|DRM_RENDER_ALLOW),
-
-       DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETPLANERESOURCES, drm_mode_getplane_res, DRM_CONTROL_ALLOW|DRM_UNLOCKED),
-       DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETCRTC, drm_mode_getcrtc, DRM_CONTROL_ALLOW|DRM_UNLOCKED),
-       DRM_IOCTL_DEF(DRM_IOCTL_MODE_SETCRTC, drm_mode_setcrtc, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
-       DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETPLANE, drm_mode_getplane, DRM_CONTROL_ALLOW|DRM_UNLOCKED),
-       DRM_IOCTL_DEF(DRM_IOCTL_MODE_SETPLANE, drm_mode_setplane, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
-       DRM_IOCTL_DEF(DRM_IOCTL_MODE_CURSOR, drm_mode_cursor_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
-       DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETGAMMA, drm_mode_gamma_get_ioctl, DRM_UNLOCKED),
-       DRM_IOCTL_DEF(DRM_IOCTL_MODE_SETGAMMA, drm_mode_gamma_set_ioctl, DRM_MASTER|DRM_UNLOCKED),
-       DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETENCODER, drm_mode_getencoder, DRM_CONTROL_ALLOW|DRM_UNLOCKED),
-       DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETCONNECTOR, drm_mode_getconnector, DRM_CONTROL_ALLOW|DRM_UNLOCKED),
-       DRM_IOCTL_DEF(DRM_IOCTL_MODE_ATTACHMODE, drm_noop, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
-       DRM_IOCTL_DEF(DRM_IOCTL_MODE_DETACHMODE, drm_noop, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
-       DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETPROPERTY, drm_mode_getproperty_ioctl, DRM_CONTROL_ALLOW|DRM_UNLOCKED),
-       DRM_IOCTL_DEF(DRM_IOCTL_MODE_SETPROPERTY, drm_mode_connector_property_set_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
-       DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETPROPBLOB, drm_mode_getblob_ioctl, DRM_CONTROL_ALLOW|DRM_UNLOCKED),
-       DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETFB, drm_mode_getfb, DRM_CONTROL_ALLOW|DRM_UNLOCKED),
-       DRM_IOCTL_DEF(DRM_IOCTL_MODE_ADDFB, drm_mode_addfb, DRM_CONTROL_ALLOW|DRM_UNLOCKED),
-       DRM_IOCTL_DEF(DRM_IOCTL_MODE_ADDFB2, drm_mode_addfb2, DRM_CONTROL_ALLOW|DRM_UNLOCKED),
-       DRM_IOCTL_DEF(DRM_IOCTL_MODE_RMFB, drm_mode_rmfb, DRM_CONTROL_ALLOW|DRM_UNLOCKED),
-       DRM_IOCTL_DEF(DRM_IOCTL_MODE_PAGE_FLIP, drm_mode_page_flip_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
-       DRM_IOCTL_DEF(DRM_IOCTL_MODE_DIRTYFB, drm_mode_dirtyfb_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
-       DRM_IOCTL_DEF(DRM_IOCTL_MODE_CREATE_DUMB, drm_mode_create_dumb_ioctl, DRM_CONTROL_ALLOW|DRM_UNLOCKED),
-       DRM_IOCTL_DEF(DRM_IOCTL_MODE_MAP_DUMB, drm_mode_mmap_dumb_ioctl, DRM_CONTROL_ALLOW|DRM_UNLOCKED),
-       DRM_IOCTL_DEF(DRM_IOCTL_MODE_DESTROY_DUMB, drm_mode_destroy_dumb_ioctl, DRM_CONTROL_ALLOW|DRM_UNLOCKED),
-       DRM_IOCTL_DEF(DRM_IOCTL_MODE_OBJ_GETPROPERTIES, drm_mode_obj_get_properties_ioctl, DRM_CONTROL_ALLOW|DRM_UNLOCKED),
-       DRM_IOCTL_DEF(DRM_IOCTL_MODE_OBJ_SETPROPERTY, drm_mode_obj_set_property_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
-       DRM_IOCTL_DEF(DRM_IOCTL_MODE_CURSOR2, drm_mode_cursor2_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
-};
-
-#define DRM_CORE_IOCTL_COUNT   ARRAY_SIZE( drm_ioctls )
-
 /**
  * Get the bus id.
  *
@@ -167,7 +53,7 @@ static const struct drm_ioctl_desc drm_ioctls[] = {
  *
  * Copies the bus id from drm_device::unique into user space.
  */
-int drm_getunique(struct drm_device *dev, void *data,
+static int drm_getunique(struct drm_device *dev, void *data,
                  struct drm_file *file_priv)
 {
        struct drm_unique *u = data;
@@ -189,7 +75,6 @@ drm_unset_busid(struct drm_device *dev,
        kfree(master->unique);
        master->unique = NULL;
        master->unique_len = 0;
-       master->unique_size = 0;
 }
 
 /**
@@ -207,7 +92,7 @@ drm_unset_busid(struct drm_device *dev,
  * version 1.1 or greater. Also note that KMS is all version 1.1 and later and
  * UMS was only ever supported on pci devices.
  */
-int drm_setunique(struct drm_device *dev, void *data,
+static int drm_setunique(struct drm_device *dev, void *data,
                  struct drm_file *file_priv)
 {
        struct drm_unique *u = data;
@@ -245,15 +130,15 @@ static int drm_set_busid(struct drm_device *dev, struct drm_file *file_priv)
        if (master->unique != NULL)
                drm_unset_busid(dev, master);
 
-       if (dev->driver->bus && dev->driver->bus->set_busid) {
-               ret = dev->driver->bus->set_busid(dev, master);
+       if (dev->driver->set_busid) {
+               ret = dev->driver->set_busid(dev, master);
                if (ret) {
                        drm_unset_busid(dev, master);
                        return ret;
                }
        } else {
                if (WARN(dev->unique == NULL,
-                        "No drm_bus.set_busid() implementation provided by "
+                        "No drm_driver.set_busid() implementation provided by "
                         "%ps. Use drm_dev_set_unique() to set the unique "
                         "name explicitly.", dev->driver))
                        return -EINVAL;
@@ -279,7 +164,7 @@ static int drm_set_busid(struct drm_device *dev, struct drm_file *file_priv)
  * Searches for the mapping with the specified offset and copies its information
  * into userspace
  */
-int drm_getmap(struct drm_device *dev, void *data,
+static int drm_getmap(struct drm_device *dev, void *data,
               struct drm_file *file_priv)
 {
        struct drm_map *map = data;
@@ -340,7 +225,7 @@ int drm_getmap(struct drm_device *dev, void *data,
  * Searches for the client with the specified index and copies its information
  * into userspace
  */
-int drm_getclient(struct drm_device *dev, void *data,
+static int drm_getclient(struct drm_device *dev, void *data,
                  struct drm_file *file_priv)
 {
        struct drm_client *client = data;
@@ -380,7 +265,7 @@ int drm_getclient(struct drm_device *dev, void *data,
  *
  * \return zero on success or a negative number on failure.
  */
-int drm_getstats(struct drm_device *dev, void *data,
+static int drm_getstats(struct drm_device *dev, void *data,
                 struct drm_file *file_priv)
 {
        struct drm_stats *stats = data;
@@ -394,7 +279,7 @@ int drm_getstats(struct drm_device *dev, void *data,
 /**
  * Get device/driver capabilities
  */
-int drm_getcap(struct drm_device *dev, void *data, struct drm_file *file_priv)
+static int drm_getcap(struct drm_device *dev, void *data, struct drm_file *file_priv)
 {
        struct drm_get_cap *req = data;
 
@@ -444,7 +329,7 @@ int drm_getcap(struct drm_device *dev, void *data, struct drm_file *file_priv)
 /**
  * Set device/driver capabilities
  */
-int
+static int
 drm_setclientcap(struct drm_device *dev, void *data, struct drm_file *file_priv)
 {
        struct drm_set_client_cap *req = data;
@@ -478,7 +363,7 @@ drm_setclientcap(struct drm_device *dev, void *data, struct drm_file *file_priv)
  *
  * Sets the requested interface version
  */
-int drm_setversion(struct drm_device *dev, void *data, struct drm_file *file_priv)
+static int drm_setversion(struct drm_device *dev, void *data, struct drm_file *file_priv)
 {
        struct drm_set_version *sv = data;
        int if_version, retcode = 0;
@@ -624,6 +509,121 @@ static int drm_ioctl_permit(u32 flags, struct drm_file *file_priv)
        return 0;
 }
 
+#define DRM_IOCTL_DEF(ioctl, _func, _flags) \
+       [DRM_IOCTL_NR(ioctl)] = {.cmd = ioctl, .func = _func, .flags = _flags, .cmd_drv = 0, .name = #ioctl}
+
+/** Ioctl table */
+static const struct drm_ioctl_desc drm_ioctls[] = {
+       DRM_IOCTL_DEF(DRM_IOCTL_VERSION, drm_version, DRM_UNLOCKED|DRM_RENDER_ALLOW),
+       DRM_IOCTL_DEF(DRM_IOCTL_GET_UNIQUE, drm_getunique, 0),
+       DRM_IOCTL_DEF(DRM_IOCTL_GET_MAGIC, drm_getmagic, 0),
+       DRM_IOCTL_DEF(DRM_IOCTL_IRQ_BUSID, drm_irq_by_busid, DRM_MASTER|DRM_ROOT_ONLY),
+       DRM_IOCTL_DEF(DRM_IOCTL_GET_MAP, drm_getmap, DRM_UNLOCKED),
+       DRM_IOCTL_DEF(DRM_IOCTL_GET_CLIENT, drm_getclient, DRM_UNLOCKED),
+       DRM_IOCTL_DEF(DRM_IOCTL_GET_STATS, drm_getstats, DRM_UNLOCKED),
+       DRM_IOCTL_DEF(DRM_IOCTL_GET_CAP, drm_getcap, DRM_UNLOCKED|DRM_RENDER_ALLOW),
+       DRM_IOCTL_DEF(DRM_IOCTL_SET_CLIENT_CAP, drm_setclientcap, 0),
+       DRM_IOCTL_DEF(DRM_IOCTL_SET_VERSION, drm_setversion, DRM_MASTER),
+
+       DRM_IOCTL_DEF(DRM_IOCTL_SET_UNIQUE, drm_setunique, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
+       DRM_IOCTL_DEF(DRM_IOCTL_BLOCK, drm_noop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
+       DRM_IOCTL_DEF(DRM_IOCTL_UNBLOCK, drm_noop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
+       DRM_IOCTL_DEF(DRM_IOCTL_AUTH_MAGIC, drm_authmagic, DRM_AUTH|DRM_MASTER),
+
+       DRM_IOCTL_DEF(DRM_IOCTL_ADD_MAP, drm_legacy_addmap_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
+       DRM_IOCTL_DEF(DRM_IOCTL_RM_MAP, drm_legacy_rmmap_ioctl, DRM_AUTH),
+
+       DRM_IOCTL_DEF(DRM_IOCTL_SET_SAREA_CTX, drm_legacy_setsareactx, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
+       DRM_IOCTL_DEF(DRM_IOCTL_GET_SAREA_CTX, drm_legacy_getsareactx, DRM_AUTH),
+
+       DRM_IOCTL_DEF(DRM_IOCTL_SET_MASTER, drm_setmaster_ioctl, DRM_ROOT_ONLY),
+       DRM_IOCTL_DEF(DRM_IOCTL_DROP_MASTER, drm_dropmaster_ioctl, DRM_ROOT_ONLY),
+
+       DRM_IOCTL_DEF(DRM_IOCTL_ADD_CTX, drm_legacy_addctx, DRM_AUTH|DRM_ROOT_ONLY),
+       DRM_IOCTL_DEF(DRM_IOCTL_RM_CTX, drm_legacy_rmctx, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
+       DRM_IOCTL_DEF(DRM_IOCTL_MOD_CTX, drm_noop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
+       DRM_IOCTL_DEF(DRM_IOCTL_GET_CTX, drm_legacy_getctx, DRM_AUTH),
+       DRM_IOCTL_DEF(DRM_IOCTL_SWITCH_CTX, drm_legacy_switchctx, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
+       DRM_IOCTL_DEF(DRM_IOCTL_NEW_CTX, drm_legacy_newctx, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
+       DRM_IOCTL_DEF(DRM_IOCTL_RES_CTX, drm_legacy_resctx, DRM_AUTH),
+
+       DRM_IOCTL_DEF(DRM_IOCTL_ADD_DRAW, drm_noop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
+       DRM_IOCTL_DEF(DRM_IOCTL_RM_DRAW, drm_noop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
+
+       DRM_IOCTL_DEF(DRM_IOCTL_LOCK, drm_legacy_lock, DRM_AUTH),
+       DRM_IOCTL_DEF(DRM_IOCTL_UNLOCK, drm_legacy_unlock, DRM_AUTH),
+
+       DRM_IOCTL_DEF(DRM_IOCTL_FINISH, drm_noop, DRM_AUTH),
+
+       DRM_IOCTL_DEF(DRM_IOCTL_ADD_BUFS, drm_legacy_addbufs, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
+       DRM_IOCTL_DEF(DRM_IOCTL_MARK_BUFS, drm_legacy_markbufs, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
+       DRM_IOCTL_DEF(DRM_IOCTL_INFO_BUFS, drm_legacy_infobufs, DRM_AUTH),
+       DRM_IOCTL_DEF(DRM_IOCTL_MAP_BUFS, drm_legacy_mapbufs, DRM_AUTH),
+       DRM_IOCTL_DEF(DRM_IOCTL_FREE_BUFS, drm_legacy_freebufs, DRM_AUTH),
+       DRM_IOCTL_DEF(DRM_IOCTL_DMA, drm_legacy_dma_ioctl, DRM_AUTH),
+
+       DRM_IOCTL_DEF(DRM_IOCTL_CONTROL, drm_control, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
+
+#if __OS_HAS_AGP
+       DRM_IOCTL_DEF(DRM_IOCTL_AGP_ACQUIRE, drm_agp_acquire_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
+       DRM_IOCTL_DEF(DRM_IOCTL_AGP_RELEASE, drm_agp_release_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
+       DRM_IOCTL_DEF(DRM_IOCTL_AGP_ENABLE, drm_agp_enable_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
+       DRM_IOCTL_DEF(DRM_IOCTL_AGP_INFO, drm_agp_info_ioctl, DRM_AUTH),
+       DRM_IOCTL_DEF(DRM_IOCTL_AGP_ALLOC, drm_agp_alloc_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
+       DRM_IOCTL_DEF(DRM_IOCTL_AGP_FREE, drm_agp_free_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
+       DRM_IOCTL_DEF(DRM_IOCTL_AGP_BIND, drm_agp_bind_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
+       DRM_IOCTL_DEF(DRM_IOCTL_AGP_UNBIND, drm_agp_unbind_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
+#endif
+
+       DRM_IOCTL_DEF(DRM_IOCTL_SG_ALLOC, drm_legacy_sg_alloc, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
+       DRM_IOCTL_DEF(DRM_IOCTL_SG_FREE, drm_legacy_sg_free, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
+
+       DRM_IOCTL_DEF(DRM_IOCTL_WAIT_VBLANK, drm_wait_vblank, DRM_UNLOCKED),
+
+       DRM_IOCTL_DEF(DRM_IOCTL_MODESET_CTL, drm_modeset_ctl, 0),
+
+       DRM_IOCTL_DEF(DRM_IOCTL_UPDATE_DRAW, drm_noop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
+
+       DRM_IOCTL_DEF(DRM_IOCTL_GEM_CLOSE, drm_gem_close_ioctl, DRM_UNLOCKED|DRM_RENDER_ALLOW),
+       DRM_IOCTL_DEF(DRM_IOCTL_GEM_FLINK, drm_gem_flink_ioctl, DRM_AUTH|DRM_UNLOCKED),
+       DRM_IOCTL_DEF(DRM_IOCTL_GEM_OPEN, drm_gem_open_ioctl, DRM_AUTH|DRM_UNLOCKED),
+
+       DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETRESOURCES, drm_mode_getresources, DRM_CONTROL_ALLOW|DRM_UNLOCKED),
+
+       DRM_IOCTL_DEF(DRM_IOCTL_PRIME_HANDLE_TO_FD, drm_prime_handle_to_fd_ioctl, DRM_AUTH|DRM_UNLOCKED|DRM_RENDER_ALLOW),
+       DRM_IOCTL_DEF(DRM_IOCTL_PRIME_FD_TO_HANDLE, drm_prime_fd_to_handle_ioctl, DRM_AUTH|DRM_UNLOCKED|DRM_RENDER_ALLOW),
+
+       DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETPLANERESOURCES, drm_mode_getplane_res, DRM_CONTROL_ALLOW|DRM_UNLOCKED),
+       DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETCRTC, drm_mode_getcrtc, DRM_CONTROL_ALLOW|DRM_UNLOCKED),
+       DRM_IOCTL_DEF(DRM_IOCTL_MODE_SETCRTC, drm_mode_setcrtc, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
+       DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETPLANE, drm_mode_getplane, DRM_CONTROL_ALLOW|DRM_UNLOCKED),
+       DRM_IOCTL_DEF(DRM_IOCTL_MODE_SETPLANE, drm_mode_setplane, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
+       DRM_IOCTL_DEF(DRM_IOCTL_MODE_CURSOR, drm_mode_cursor_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
+       DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETGAMMA, drm_mode_gamma_get_ioctl, DRM_UNLOCKED),
+       DRM_IOCTL_DEF(DRM_IOCTL_MODE_SETGAMMA, drm_mode_gamma_set_ioctl, DRM_MASTER|DRM_UNLOCKED),
+       DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETENCODER, drm_mode_getencoder, DRM_CONTROL_ALLOW|DRM_UNLOCKED),
+       DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETCONNECTOR, drm_mode_getconnector, DRM_CONTROL_ALLOW|DRM_UNLOCKED),
+       DRM_IOCTL_DEF(DRM_IOCTL_MODE_ATTACHMODE, drm_noop, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
+       DRM_IOCTL_DEF(DRM_IOCTL_MODE_DETACHMODE, drm_noop, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
+       DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETPROPERTY, drm_mode_getproperty_ioctl, DRM_CONTROL_ALLOW|DRM_UNLOCKED),
+       DRM_IOCTL_DEF(DRM_IOCTL_MODE_SETPROPERTY, drm_mode_connector_property_set_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
+       DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETPROPBLOB, drm_mode_getblob_ioctl, DRM_CONTROL_ALLOW|DRM_UNLOCKED),
+       DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETFB, drm_mode_getfb, DRM_CONTROL_ALLOW|DRM_UNLOCKED),
+       DRM_IOCTL_DEF(DRM_IOCTL_MODE_ADDFB, drm_mode_addfb, DRM_CONTROL_ALLOW|DRM_UNLOCKED),
+       DRM_IOCTL_DEF(DRM_IOCTL_MODE_ADDFB2, drm_mode_addfb2, DRM_CONTROL_ALLOW|DRM_UNLOCKED),
+       DRM_IOCTL_DEF(DRM_IOCTL_MODE_RMFB, drm_mode_rmfb, DRM_CONTROL_ALLOW|DRM_UNLOCKED),
+       DRM_IOCTL_DEF(DRM_IOCTL_MODE_PAGE_FLIP, drm_mode_page_flip_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
+       DRM_IOCTL_DEF(DRM_IOCTL_MODE_DIRTYFB, drm_mode_dirtyfb_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
+       DRM_IOCTL_DEF(DRM_IOCTL_MODE_CREATE_DUMB, drm_mode_create_dumb_ioctl, DRM_CONTROL_ALLOW|DRM_UNLOCKED),
+       DRM_IOCTL_DEF(DRM_IOCTL_MODE_MAP_DUMB, drm_mode_mmap_dumb_ioctl, DRM_CONTROL_ALLOW|DRM_UNLOCKED),
+       DRM_IOCTL_DEF(DRM_IOCTL_MODE_DESTROY_DUMB, drm_mode_destroy_dumb_ioctl, DRM_CONTROL_ALLOW|DRM_UNLOCKED),
+       DRM_IOCTL_DEF(DRM_IOCTL_MODE_OBJ_GETPROPERTIES, drm_mode_obj_get_properties_ioctl, DRM_CONTROL_ALLOW|DRM_UNLOCKED),
+       DRM_IOCTL_DEF(DRM_IOCTL_MODE_OBJ_SETPROPERTY, drm_mode_obj_set_property_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
+       DRM_IOCTL_DEF(DRM_IOCTL_MODE_CURSOR2, drm_mode_cursor2_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
+};
+
+#define DRM_CORE_IOCTL_COUNT   ARRAY_SIZE( drm_ioctls )
+
 /**
  * Called whenever a process performs an ioctl on /dev/drm.
  *
index 08ba1209228edf84d88883532b65c4708575e15a..5ef03c216a2740818468ef64ebb1a056f1644235 100644 (file)
@@ -34,6 +34,7 @@
 
 #include <drm/drmP.h>
 #include "drm_trace.h"
+#include "drm_internal.h"
 
 #include <linux/interrupt.h>   /* For task queue support */
 #include <linux/slab.h>
  */
 #define DRM_REDUNDANT_VBLIRQ_THRESH_NS 1000000
 
+static bool
+drm_get_last_vbltimestamp(struct drm_device *dev, int crtc,
+                         struct timeval *tvblank, unsigned flags);
+
+static unsigned int drm_timestamp_precision = 20;  /* Default to 20 usecs. */
+
 /*
- * Clear vblank timestamp buffer for a crtc.
+ * Default to use monotonic timestamps for wait-for-vblank and page-flip
+ * complete events.
+ */
+unsigned int drm_timestamp_monotonic = 1;
+
+static int drm_vblank_offdelay = 5000;    /* Default to 5000 msecs. */
+
+module_param_named(vblankoffdelay, drm_vblank_offdelay, int, 0600);
+module_param_named(timestamp_precision_usec, drm_timestamp_precision, int, 0600);
+module_param_named(timestamp_monotonic, drm_timestamp_monotonic, int, 0600);
+
+/**
+ * drm_update_vblank_count - update the master vblank counter
+ * @dev: DRM device
+ * @crtc: counter to update
+ *
+ * Call back into the driver to update the appropriate vblank counter
+ * (specified by @crtc).  Deal with wraparound, if it occurred, and
+ * update the last read value so we can deal with wraparound on the next
+ * call if necessary.
+ *
+ * Only necessary when going from off->on, to account for frames we
+ * didn't get an interrupt for.
+ *
+ * Note: caller must hold dev->vbl_lock since this reads & writes
+ * device vblank fields.
  */
-static void clear_vblank_timestamps(struct drm_device *dev, int crtc)
+static void drm_update_vblank_count(struct drm_device *dev, int crtc)
 {
-       memset(dev->vblank[crtc].time, 0, sizeof(dev->vblank[crtc].time));
+       struct drm_vblank_crtc *vblank = &dev->vblank[crtc];
+       u32 cur_vblank, diff, tslot;
+       bool rc;
+       struct timeval t_vblank;
+
+       /*
+        * Interrupts were disabled prior to this call, so deal with counter
+        * wrap if needed.
+        * NOTE!  It's possible we lost a full dev->max_vblank_count events
+        * here if the register is small or we had vblank interrupts off for
+        * a long time.
+        *
+        * We repeat the hardware vblank counter & timestamp query until
+        * we get consistent results. This to prevent races between gpu
+        * updating its hardware counter while we are retrieving the
+        * corresponding vblank timestamp.
+        */
+       do {
+               cur_vblank = dev->driver->get_vblank_counter(dev, crtc);
+               rc = drm_get_last_vbltimestamp(dev, crtc, &t_vblank, 0);
+       } while (cur_vblank != dev->driver->get_vblank_counter(dev, crtc));
+
+       /* Deal with counter wrap */
+       diff = cur_vblank - vblank->last;
+       if (cur_vblank < vblank->last) {
+               diff += dev->max_vblank_count;
+
+               DRM_DEBUG("last_vblank[%d]=0x%x, cur_vblank=0x%x => diff=0x%x\n",
+                         crtc, vblank->last, cur_vblank, diff);
+       }
+
+       DRM_DEBUG("updating vblank count on crtc %d, missed %d\n",
+                 crtc, diff);
+
+       if (diff == 0)
+               return;
+
+       /* Reinitialize corresponding vblank timestamp if high-precision query
+        * available. Skip this step if query unsupported or failed. Will
+        * reinitialize delayed at next vblank interrupt in that case.
+        */
+       if (rc) {
+               tslot = atomic_read(&vblank->count) + diff;
+               vblanktimestamp(dev, crtc, tslot) = t_vblank;
+       }
+
+       smp_mb__before_atomic();
+       atomic_add(diff, &vblank->count);
+       smp_mb__after_atomic();
 }
 
 /*
@@ -71,10 +151,11 @@ static void clear_vblank_timestamps(struct drm_device *dev, int crtc)
  */
 static void vblank_disable_and_save(struct drm_device *dev, int crtc)
 {
+       struct drm_vblank_crtc *vblank = &dev->vblank[crtc];
        unsigned long irqflags;
        u32 vblcount;
        s64 diff_ns;
-       int vblrc;
+       bool vblrc;
        struct timeval tvblank;
        int count = DRM_TIMESTAMP_MAXRETRIES;
 
@@ -84,8 +165,28 @@ static void vblank_disable_and_save(struct drm_device *dev, int crtc)
         */
        spin_lock_irqsave(&dev->vblank_time_lock, irqflags);
 
+       /*
+        * If the vblank interrupt was already disbled update the count
+        * and timestamp to maintain the appearance that the counter
+        * has been ticking all along until this time. This makes the
+        * count account for the entire time between drm_vblank_on() and
+        * drm_vblank_off().
+        *
+        * But only do this if precise vblank timestamps are available.
+        * Otherwise we might read a totally bogus timestamp since drivers
+        * lacking precise timestamp support rely upon sampling the system clock
+        * at vblank interrupt time. Which obviously won't work out well if the
+        * vblank interrupt is disabled.
+        */
+       if (!vblank->enabled &&
+           drm_get_last_vbltimestamp(dev, crtc, &tvblank, 0)) {
+               drm_update_vblank_count(dev, crtc);
+               spin_unlock_irqrestore(&dev->vblank_time_lock, irqflags);
+               return;
+       }
+
        dev->driver->disable_vblank(dev, crtc);
-       dev->vblank[crtc].enabled = false;
+       vblank->enabled = false;
 
        /* No further vblank irq's will be processed after
         * this point. Get current hardware vblank count and
@@ -100,9 +201,9 @@ static void vblank_disable_and_save(struct drm_device *dev, int crtc)
         * delayed gpu counter increment.
         */
        do {
-               dev->vblank[crtc].last = dev->driver->get_vblank_counter(dev, crtc);
+               vblank->last = dev->driver->get_vblank_counter(dev, crtc);
                vblrc = drm_get_last_vbltimestamp(dev, crtc, &tvblank, 0);
-       } while (dev->vblank[crtc].last != dev->driver->get_vblank_counter(dev, crtc) && (--count) && vblrc);
+       } while (vblank->last != dev->driver->get_vblank_counter(dev, crtc) && (--count) && vblrc);
 
        if (!count)
                vblrc = 0;
@@ -110,7 +211,7 @@ static void vblank_disable_and_save(struct drm_device *dev, int crtc)
        /* Compute time difference to stored timestamp of last vblank
         * as updated by last invocation of drm_handle_vblank() in vblank irq.
         */
-       vblcount = atomic_read(&dev->vblank[crtc].count);
+       vblcount = atomic_read(&vblank->count);
        diff_ns = timeval_to_ns(&tvblank) -
                  timeval_to_ns(&vblanktimestamp(dev, crtc, vblcount));
 
@@ -126,14 +227,18 @@ static void vblank_disable_and_save(struct drm_device *dev, int crtc)
         * available. In that case we can't account for this and just
         * hope for the best.
         */
-       if ((vblrc > 0) && (abs64(diff_ns) > 1000000)) {
-               atomic_inc(&dev->vblank[crtc].count);
+       if (vblrc && (abs64(diff_ns) > 1000000)) {
+               /* Store new timestamp in ringbuffer. */
+               vblanktimestamp(dev, crtc, vblcount + 1) = tvblank;
+
+               /* Increment cooked vblank count. This also atomically commits
+                * the timestamp computed above.
+                */
+               smp_mb__before_atomic();
+               atomic_inc(&vblank->count);
                smp_mb__after_atomic();
        }
 
-       /* Invalidate all timestamps while vblank irq's are off. */
-       clear_vblank_timestamps(dev, crtc);
-
        spin_unlock_irqrestore(&dev->vblank_time_lock, irqflags);
 }
 
@@ -164,14 +269,20 @@ static void vblank_disable_fn(unsigned long arg)
 void drm_vblank_cleanup(struct drm_device *dev)
 {
        int crtc;
+       unsigned long irqflags;
 
        /* Bail if the driver didn't call drm_vblank_init() */
        if (dev->num_crtcs == 0)
                return;
 
        for (crtc = 0; crtc < dev->num_crtcs; crtc++) {
-               del_timer_sync(&dev->vblank[crtc].disable_timer);
-               vblank_disable_fn((unsigned long)&dev->vblank[crtc]);
+               struct drm_vblank_crtc *vblank = &dev->vblank[crtc];
+
+               del_timer_sync(&vblank->disable_timer);
+
+               spin_lock_irqsave(&dev->vbl_lock, irqflags);
+               vblank_disable_and_save(dev, crtc);
+               spin_unlock_irqrestore(&dev->vbl_lock, irqflags);
        }
 
        kfree(dev->vblank);
@@ -204,11 +315,13 @@ int drm_vblank_init(struct drm_device *dev, int num_crtcs)
                goto err;
 
        for (i = 0; i < num_crtcs; i++) {
-               dev->vblank[i].dev = dev;
-               dev->vblank[i].crtc = i;
-               init_waitqueue_head(&dev->vblank[i].queue);
-               setup_timer(&dev->vblank[i].disable_timer, vblank_disable_fn,
-                           (unsigned long)&dev->vblank[i]);
+               struct drm_vblank_crtc *vblank = &dev->vblank[i];
+
+               vblank->dev = dev;
+               vblank->crtc = i;
+               init_waitqueue_head(&vblank->queue);
+               setup_timer(&vblank->disable_timer, vblank_disable_fn,
+                           (unsigned long)vblank);
        }
 
        DRM_INFO("Supports vblank timestamp caching Rev 2 (21.10.2013).\n");
@@ -224,7 +337,7 @@ int drm_vblank_init(struct drm_device *dev, int num_crtcs)
        return 0;
 
 err:
-       drm_vblank_cleanup(dev);
+       dev->num_crtcs = 0;
        return ret;
 }
 EXPORT_SYMBOL(drm_vblank_init);
@@ -360,9 +473,11 @@ int drm_irq_uninstall(struct drm_device *dev)
        if (dev->num_crtcs) {
                spin_lock_irqsave(&dev->vbl_lock, irqflags);
                for (i = 0; i < dev->num_crtcs; i++) {
-                       wake_up(&dev->vblank[i].queue);
-                       dev->vblank[i].enabled = false;
-                       dev->vblank[i].last =
+                       struct drm_vblank_crtc *vblank = &dev->vblank[i];
+
+                       wake_up(&vblank->queue);
+                       vblank->enabled = false;
+                       vblank->last =
                                dev->driver->get_vblank_counter(dev, i);
                }
                spin_unlock_irqrestore(&dev->vbl_lock, irqflags);
@@ -617,7 +732,7 @@ int drm_calc_vbltimestamp_from_scanoutpos(struct drm_device *dev, int crtc,
         * within vblank area, counting down the number of lines until
         * start of scanout.
         */
-       invbl = vbl_status & DRM_SCANOUTPOS_INVBL;
+       invbl = vbl_status & DRM_SCANOUTPOS_IN_VBLANK;
 
        /* Convert scanout position into elapsed time at raw_time query
         * since start of scanout at first display scanline. delta_ns
@@ -647,7 +762,7 @@ int drm_calc_vbltimestamp_from_scanoutpos(struct drm_device *dev, int crtc,
 
        vbl_status = DRM_VBLANKTIME_SCANOUTPOS_METHOD;
        if (invbl)
-               vbl_status |= DRM_VBLANKTIME_INVBL;
+               vbl_status |= DRM_VBLANKTIME_IN_VBLANK;
 
        return vbl_status;
 }
@@ -679,10 +794,11 @@ static struct timeval get_drm_timestamp(void)
  * call, i.e., it isn't very precisely locked to the true vblank.
  *
  * Returns:
- * Non-zero if timestamp is considered to be very precise, zero otherwise.
+ * True if timestamp is considered to be very precise, false otherwise.
  */
-u32 drm_get_last_vbltimestamp(struct drm_device *dev, int crtc,
-                             struct timeval *tvblank, unsigned flags)
+static bool
+drm_get_last_vbltimestamp(struct drm_device *dev, int crtc,
+                         struct timeval *tvblank, unsigned flags)
 {
        int ret;
 
@@ -694,7 +810,7 @@ u32 drm_get_last_vbltimestamp(struct drm_device *dev, int crtc,
                ret = dev->driver->get_vblank_timestamp(dev, crtc, &max_error,
                                                        tvblank, flags);
                if (ret > 0)
-                       return (u32) ret;
+                       return true;
        }
 
        /* GPU high precision timestamp query unsupported or failed.
@@ -702,9 +818,8 @@ u32 drm_get_last_vbltimestamp(struct drm_device *dev, int crtc,
         */
        *tvblank = get_drm_timestamp();
 
-       return 0;
+       return false;
 }
-EXPORT_SYMBOL(drm_get_last_vbltimestamp);
 
 /**
  * drm_vblank_count - retrieve "cooked" vblank counter value
@@ -720,7 +835,11 @@ EXPORT_SYMBOL(drm_get_last_vbltimestamp);
  */
 u32 drm_vblank_count(struct drm_device *dev, int crtc)
 {
-       return atomic_read(&dev->vblank[crtc].count);
+       struct drm_vblank_crtc *vblank = &dev->vblank[crtc];
+
+       if (WARN_ON(crtc >= dev->num_crtcs))
+               return 0;
+       return atomic_read(&vblank->count);
 }
 EXPORT_SYMBOL(drm_vblank_count);
 
@@ -740,18 +859,22 @@ EXPORT_SYMBOL(drm_vblank_count);
 u32 drm_vblank_count_and_time(struct drm_device *dev, int crtc,
                              struct timeval *vblanktime)
 {
+       struct drm_vblank_crtc *vblank = &dev->vblank[crtc];
        u32 cur_vblank;
 
+       if (WARN_ON(crtc >= dev->num_crtcs))
+               return 0;
+
        /* Read timestamp from slot of _vblank_time ringbuffer
         * that corresponds to current vblank count. Retry if
         * count has incremented during readout. This works like
         * a seqlock.
         */
        do {
-               cur_vblank = atomic_read(&dev->vblank[crtc].count);
+               cur_vblank = atomic_read(&vblank->count);
                *vblanktime = vblanktimestamp(dev, crtc, cur_vblank);
                smp_rmb();
-       } while (cur_vblank != atomic_read(&dev->vblank[crtc].count));
+       } while (cur_vblank != atomic_read(&vblank->count));
 
        return cur_vblank;
 }
@@ -799,70 +922,6 @@ void drm_send_vblank_event(struct drm_device *dev, int crtc,
 }
 EXPORT_SYMBOL(drm_send_vblank_event);
 
-/**
- * drm_update_vblank_count - update the master vblank counter
- * @dev: DRM device
- * @crtc: counter to update
- *
- * Call back into the driver to update the appropriate vblank counter
- * (specified by @crtc).  Deal with wraparound, if it occurred, and
- * update the last read value so we can deal with wraparound on the next
- * call if necessary.
- *
- * Only necessary when going from off->on, to account for frames we
- * didn't get an interrupt for.
- *
- * Note: caller must hold dev->vbl_lock since this reads & writes
- * device vblank fields.
- */
-static void drm_update_vblank_count(struct drm_device *dev, int crtc)
-{
-       u32 cur_vblank, diff, tslot, rc;
-       struct timeval t_vblank;
-
-       /*
-        * Interrupts were disabled prior to this call, so deal with counter
-        * wrap if needed.
-        * NOTE!  It's possible we lost a full dev->max_vblank_count events
-        * here if the register is small or we had vblank interrupts off for
-        * a long time.
-        *
-        * We repeat the hardware vblank counter & timestamp query until
-        * we get consistent results. This to prevent races between gpu
-        * updating its hardware counter while we are retrieving the
-        * corresponding vblank timestamp.
-        */
-       do {
-               cur_vblank = dev->driver->get_vblank_counter(dev, crtc);
-               rc = drm_get_last_vbltimestamp(dev, crtc, &t_vblank, 0);
-       } while (cur_vblank != dev->driver->get_vblank_counter(dev, crtc));
-
-       /* Deal with counter wrap */
-       diff = cur_vblank - dev->vblank[crtc].last;
-       if (cur_vblank < dev->vblank[crtc].last) {
-               diff += dev->max_vblank_count;
-
-               DRM_DEBUG("last_vblank[%d]=0x%x, cur_vblank=0x%x => diff=0x%x\n",
-                         crtc, dev->vblank[crtc].last, cur_vblank, diff);
-       }
-
-       DRM_DEBUG("enabling vblank interrupts on crtc %d, missed %d\n",
-                 crtc, diff);
-
-       /* Reinitialize corresponding vblank timestamp if high-precision query
-        * available. Skip this step if query unsupported or failed. Will
-        * reinitialize delayed at next vblank interrupt in that case.
-        */
-       if (rc) {
-               tslot = atomic_read(&dev->vblank[crtc].count) + diff;
-               vblanktimestamp(dev, crtc, tslot) = t_vblank;
-       }
-
-       smp_mb__before_atomic();
-       atomic_add(diff, &dev->vblank[crtc].count);
-       smp_mb__after_atomic();
-}
-
 /**
  * drm_vblank_enable - enable the vblank interrupt on a CRTC
  * @dev: DRM device
@@ -870,13 +929,14 @@ static void drm_update_vblank_count(struct drm_device *dev, int crtc)
  */
 static int drm_vblank_enable(struct drm_device *dev, int crtc)
 {
+       struct drm_vblank_crtc *vblank = &dev->vblank[crtc];
        int ret = 0;
 
        assert_spin_locked(&dev->vbl_lock);
 
        spin_lock(&dev->vblank_time_lock);
 
-       if (!dev->vblank[crtc].enabled) {
+       if (!vblank->enabled) {
                /*
                 * Enable vblank irqs under vblank_time_lock protection.
                 * All vblank count & timestamp updates are held off
@@ -887,9 +947,9 @@ static int drm_vblank_enable(struct drm_device *dev, int crtc)
                ret = dev->driver->enable_vblank(dev, crtc);
                DRM_DEBUG("enabling vblank on crtc %d, ret: %d\n", crtc, ret);
                if (ret)
-                       atomic_dec(&dev->vblank[crtc].refcount);
+                       atomic_dec(&vblank->refcount);
                else {
-                       dev->vblank[crtc].enabled = true;
+                       vblank->enabled = true;
                        drm_update_vblank_count(dev, crtc);
                }
        }
@@ -914,16 +974,20 @@ static int drm_vblank_enable(struct drm_device *dev, int crtc)
  */
 int drm_vblank_get(struct drm_device *dev, int crtc)
 {
+       struct drm_vblank_crtc *vblank = &dev->vblank[crtc];
        unsigned long irqflags;
        int ret = 0;
 
+       if (WARN_ON(crtc >= dev->num_crtcs))
+               return -EINVAL;
+
        spin_lock_irqsave(&dev->vbl_lock, irqflags);
        /* Going from 0->1 means we have to enable interrupts again */
-       if (atomic_add_return(1, &dev->vblank[crtc].refcount) == 1) {
+       if (atomic_add_return(1, &vblank->refcount) == 1) {
                ret = drm_vblank_enable(dev, crtc);
        } else {
-               if (!dev->vblank[crtc].enabled) {
-                       atomic_dec(&dev->vblank[crtc].refcount);
+               if (!vblank->enabled) {
+                       atomic_dec(&vblank->refcount);
                        ret = -EINVAL;
                }
        }
@@ -963,13 +1027,23 @@ EXPORT_SYMBOL(drm_crtc_vblank_get);
  */
 void drm_vblank_put(struct drm_device *dev, int crtc)
 {
-       BUG_ON(atomic_read(&dev->vblank[crtc].refcount) == 0);
+       struct drm_vblank_crtc *vblank = &dev->vblank[crtc];
+
+       BUG_ON(atomic_read(&vblank->refcount) == 0);
+
+       if (WARN_ON(crtc >= dev->num_crtcs))
+               return;
 
        /* Last user schedules interrupt disable */
-       if (atomic_dec_and_test(&dev->vblank[crtc].refcount) &&
-           (drm_vblank_offdelay > 0))
-               mod_timer(&dev->vblank[crtc].disable_timer,
-                         jiffies + ((drm_vblank_offdelay * HZ)/1000));
+       if (atomic_dec_and_test(&vblank->refcount)) {
+               if (drm_vblank_offdelay == 0)
+                       return;
+               else if (dev->vblank_disable_immediate || drm_vblank_offdelay < 0)
+                       vblank_disable_fn((unsigned long)vblank);
+               else
+                       mod_timer(&vblank->disable_timer,
+                                 jiffies + ((drm_vblank_offdelay * HZ)/1000));
+       }
 }
 EXPORT_SYMBOL(drm_vblank_put);
 
@@ -988,6 +1062,50 @@ void drm_crtc_vblank_put(struct drm_crtc *crtc)
 }
 EXPORT_SYMBOL(drm_crtc_vblank_put);
 
+/**
+ * drm_wait_one_vblank - wait for one vblank
+ * @dev: DRM device
+ * @crtc: crtc index
+ *
+ * This waits for one vblank to pass on @crtc, using the irq driver interfaces.
+ * It is a failure to call this when the vblank irq for @crtc is disabled, e.g.
+ * due to lack of driver support or because the crtc is off.
+ */
+void drm_wait_one_vblank(struct drm_device *dev, int crtc)
+{
+       int ret;
+       u32 last;
+
+       ret = drm_vblank_get(dev, crtc);
+       if (WARN(ret, "vblank not available on crtc %i, ret=%i\n", crtc, ret))
+               return;
+
+       last = drm_vblank_count(dev, crtc);
+
+       ret = wait_event_timeout(dev->vblank[crtc].queue,
+                                last != drm_vblank_count(dev, crtc),
+                                msecs_to_jiffies(100));
+
+       WARN(ret == 0, "vblank wait timed out on crtc %i\n", crtc);
+
+       drm_vblank_put(dev, crtc);
+}
+EXPORT_SYMBOL(drm_wait_one_vblank);
+
+/**
+ * drm_crtc_wait_one_vblank - wait for one vblank
+ * @crtc: DRM crtc
+ *
+ * This waits for one vblank to pass on @crtc, using the irq driver interfaces.
+ * It is a failure to call this when the vblank irq for @crtc is disabled, e.g.
+ * due to lack of driver support or because the crtc is off.
+ */
+void drm_crtc_wait_one_vblank(struct drm_crtc *crtc)
+{
+       drm_wait_one_vblank(crtc->dev, drm_crtc_index(crtc));
+}
+EXPORT_SYMBOL(drm_crtc_wait_one_vblank);
+
 /**
  * drm_vblank_off - disable vblank events on a CRTC
  * @dev: DRM device
@@ -1004,19 +1122,34 @@ EXPORT_SYMBOL(drm_crtc_vblank_put);
  */
 void drm_vblank_off(struct drm_device *dev, int crtc)
 {
+       struct drm_vblank_crtc *vblank = &dev->vblank[crtc];
        struct drm_pending_vblank_event *e, *t;
        struct timeval now;
        unsigned long irqflags;
        unsigned int seq;
 
-       spin_lock_irqsave(&dev->vbl_lock, irqflags);
+       if (WARN_ON(crtc >= dev->num_crtcs))
+               return;
+
+       spin_lock_irqsave(&dev->event_lock, irqflags);
+
+       spin_lock(&dev->vbl_lock);
        vblank_disable_and_save(dev, crtc);
-       wake_up(&dev->vblank[crtc].queue);
+       wake_up(&vblank->queue);
+
+       /*
+        * Prevent subsequent drm_vblank_get() from re-enabling
+        * the vblank interrupt by bumping the refcount.
+        */
+       if (!vblank->inmodeset) {
+               atomic_inc(&vblank->refcount);
+               vblank->inmodeset = 1;
+       }
+       spin_unlock(&dev->vbl_lock);
 
        /* Send any queued vblank events, lest the natives grow disquiet */
        seq = drm_vblank_count_and_time(dev, crtc, &now);
 
-       spin_lock(&dev->event_lock);
        list_for_each_entry_safe(e, t, &dev->vblank_event_list, base.link) {
                if (e->pipe != crtc)
                        continue;
@@ -1027,9 +1160,7 @@ void drm_vblank_off(struct drm_device *dev, int crtc)
                drm_vblank_put(dev, e->pipe);
                send_vblank_event(dev, e, seq, &now);
        }
-       spin_unlock(&dev->event_lock);
-
-       spin_unlock_irqrestore(&dev->vbl_lock, irqflags);
+       spin_unlock_irqrestore(&dev->event_lock, irqflags);
 }
 EXPORT_SYMBOL(drm_vblank_off);
 
@@ -1066,11 +1197,35 @@ EXPORT_SYMBOL(drm_crtc_vblank_off);
  */
 void drm_vblank_on(struct drm_device *dev, int crtc)
 {
+       struct drm_vblank_crtc *vblank = &dev->vblank[crtc];
        unsigned long irqflags;
 
+       if (WARN_ON(crtc >= dev->num_crtcs))
+               return;
+
        spin_lock_irqsave(&dev->vbl_lock, irqflags);
-       /* re-enable interrupts if there's are users left */
-       if (atomic_read(&dev->vblank[crtc].refcount) != 0)
+       /* Drop our private "prevent drm_vblank_get" refcount */
+       if (vblank->inmodeset) {
+               atomic_dec(&vblank->refcount);
+               vblank->inmodeset = 0;
+       }
+
+       /*
+        * sample the current counter to avoid random jumps
+        * when drm_vblank_enable() applies the diff
+        *
+        * -1 to make sure user will never see the same
+        * vblank counter value before and after a modeset
+        */
+       vblank->last =
+               (dev->driver->get_vblank_counter(dev, crtc) - 1) &
+               dev->max_vblank_count;
+       /*
+        * re-enable interrupts if there are users left, or the
+        * user wishes vblank interrupts to be enabled all the time.
+        */
+       if (atomic_read(&vblank->refcount) != 0 ||
+           (!dev->vblank_disable_immediate && drm_vblank_offdelay == 0))
                WARN_ON(drm_vblank_enable(dev, crtc));
        spin_unlock_irqrestore(&dev->vbl_lock, irqflags);
 }
@@ -1118,9 +1273,15 @@ EXPORT_SYMBOL(drm_crtc_vblank_on);
  */
 void drm_vblank_pre_modeset(struct drm_device *dev, int crtc)
 {
+       struct drm_vblank_crtc *vblank = &dev->vblank[crtc];
+
        /* vblank is not initialized (IRQ not installed ?), or has been freed */
        if (!dev->num_crtcs)
                return;
+
+       if (WARN_ON(crtc >= dev->num_crtcs))
+               return;
+
        /*
         * To avoid all the problems that might happen if interrupts
         * were enabled/disabled around or between these calls, we just
@@ -1128,10 +1289,10 @@ void drm_vblank_pre_modeset(struct drm_device *dev, int crtc)
         * to avoid corrupting the count if multiple, mismatch calls occur),
         * so that interrupts remain enabled in the interim.
         */
-       if (!dev->vblank[crtc].inmodeset) {
-               dev->vblank[crtc].inmodeset = 0x1;
+       if (!vblank->inmodeset) {
+               vblank->inmodeset = 0x1;
                if (drm_vblank_get(dev, crtc) == 0)
-                       dev->vblank[crtc].inmodeset |= 0x2;
+                       vblank->inmodeset |= 0x2;
        }
 }
 EXPORT_SYMBOL(drm_vblank_pre_modeset);
@@ -1146,21 +1307,22 @@ EXPORT_SYMBOL(drm_vblank_pre_modeset);
  */
 void drm_vblank_post_modeset(struct drm_device *dev, int crtc)
 {
+       struct drm_vblank_crtc *vblank = &dev->vblank[crtc];
        unsigned long irqflags;
 
        /* vblank is not initialized (IRQ not installed ?), or has been freed */
        if (!dev->num_crtcs)
                return;
 
-       if (dev->vblank[crtc].inmodeset) {
+       if (vblank->inmodeset) {
                spin_lock_irqsave(&dev->vbl_lock, irqflags);
                dev->vblank_disable_allowed = true;
                spin_unlock_irqrestore(&dev->vbl_lock, irqflags);
 
-               if (dev->vblank[crtc].inmodeset & 0x2)
+               if (vblank->inmodeset & 0x2)
                        drm_vblank_put(dev, crtc);
 
-               dev->vblank[crtc].inmodeset = 0;
+               vblank->inmodeset = 0;
        }
 }
 EXPORT_SYMBOL(drm_vblank_post_modeset);
@@ -1212,6 +1374,7 @@ static int drm_queue_vblank_event(struct drm_device *dev, int pipe,
                                  union drm_wait_vblank *vblwait,
                                  struct drm_file *file_priv)
 {
+       struct drm_vblank_crtc *vblank = &dev->vblank[pipe];
        struct drm_pending_vblank_event *e;
        struct timeval now;
        unsigned long flags;
@@ -1235,6 +1398,18 @@ static int drm_queue_vblank_event(struct drm_device *dev, int pipe,
 
        spin_lock_irqsave(&dev->event_lock, flags);
 
+       /*
+        * drm_vblank_off() might have been called after we called
+        * drm_vblank_get(). drm_vblank_off() holds event_lock
+        * around the vblank disable, so no need for further locking.
+        * The reference from drm_vblank_get() protects against
+        * vblank disable from another source.
+        */
+       if (!vblank->enabled) {
+               ret = -EINVAL;
+               goto err_unlock;
+       }
+
        if (file_priv->event_space < sizeof e->event) {
                ret = -EBUSY;
                goto err_unlock;
@@ -1295,6 +1470,7 @@ err_put:
 int drm_wait_vblank(struct drm_device *dev, void *data,
                    struct drm_file *file_priv)
 {
+       struct drm_vblank_crtc *vblank;
        union drm_wait_vblank *vblwait = data;
        int ret;
        unsigned int flags, seq, crtc, high_crtc;
@@ -1324,6 +1500,8 @@ int drm_wait_vblank(struct drm_device *dev, void *data,
        if (crtc >= dev->num_crtcs)
                return -EINVAL;
 
+       vblank = &dev->vblank[crtc];
+
        ret = drm_vblank_get(dev, crtc);
        if (ret) {
                DRM_DEBUG("failed to acquire vblank counter, %d\n", ret);
@@ -1356,11 +1534,11 @@ int drm_wait_vblank(struct drm_device *dev, void *data,
 
        DRM_DEBUG("waiting on vblank count %d, crtc %d\n",
                  vblwait->request.sequence, crtc);
-       dev->vblank[crtc].last_wait = vblwait->request.sequence;
-       DRM_WAIT_ON(ret, dev->vblank[crtc].queue, 3 * HZ,
+       vblank->last_wait = vblwait->request.sequence;
+       DRM_WAIT_ON(ret, vblank->queue, 3 * HZ,
                    (((drm_vblank_count(dev, crtc) -
                       vblwait->request.sequence) <= (1 << 23)) ||
-                    !dev->vblank[crtc].enabled ||
+                    !vblank->enabled ||
                     !dev->irq_enabled));
 
        if (ret != -EINTR) {
@@ -1385,12 +1563,11 @@ static void drm_handle_vblank_events(struct drm_device *dev, int crtc)
 {
        struct drm_pending_vblank_event *e, *t;
        struct timeval now;
-       unsigned long flags;
        unsigned int seq;
 
-       seq = drm_vblank_count_and_time(dev, crtc, &now);
+       assert_spin_locked(&dev->event_lock);
 
-       spin_lock_irqsave(&dev->event_lock, flags);
+       seq = drm_vblank_count_and_time(dev, crtc, &now);
 
        list_for_each_entry_safe(e, t, &dev->vblank_event_list, base.link) {
                if (e->pipe != crtc)
@@ -1406,8 +1583,6 @@ static void drm_handle_vblank_events(struct drm_device *dev, int crtc)
                send_vblank_event(dev, e, seq, &now);
        }
 
-       spin_unlock_irqrestore(&dev->event_lock, flags);
-
        trace_drm_vblank_event(crtc, seq);
 }
 
@@ -1421,6 +1596,7 @@ static void drm_handle_vblank_events(struct drm_device *dev, int crtc)
  */
 bool drm_handle_vblank(struct drm_device *dev, int crtc)
 {
+       struct drm_vblank_crtc *vblank = &dev->vblank[crtc];
        u32 vblcount;
        s64 diff_ns;
        struct timeval tvblank;
@@ -1429,15 +1605,21 @@ bool drm_handle_vblank(struct drm_device *dev, int crtc)
        if (!dev->num_crtcs)
                return false;
 
+       if (WARN_ON(crtc >= dev->num_crtcs))
+               return false;
+
+       spin_lock_irqsave(&dev->event_lock, irqflags);
+
        /* Need timestamp lock to prevent concurrent execution with
         * vblank enable/disable, as this would cause inconsistent
         * or corrupted timestamps and vblank counts.
         */
-       spin_lock_irqsave(&dev->vblank_time_lock, irqflags);
+       spin_lock(&dev->vblank_time_lock);
 
        /* Vblank irq handling disabled. Nothing to do. */
-       if (!dev->vblank[crtc].enabled) {
-               spin_unlock_irqrestore(&dev->vblank_time_lock, irqflags);
+       if (!vblank->enabled) {
+               spin_unlock(&dev->vblank_time_lock);
+               spin_unlock_irqrestore(&dev->event_lock, irqflags);
                return false;
        }
 
@@ -1446,7 +1628,7 @@ bool drm_handle_vblank(struct drm_device *dev, int crtc)
         */
 
        /* Get current timestamp and count. */
-       vblcount = atomic_read(&dev->vblank[crtc].count);
+       vblcount = atomic_read(&vblank->count);
        drm_get_last_vbltimestamp(dev, crtc, &tvblank, DRM_CALLED_FROM_VBLIRQ);
 
        /* Compute time difference to timestamp of last vblank */
@@ -1470,17 +1652,20 @@ bool drm_handle_vblank(struct drm_device *dev, int crtc)
                 * the timestamp computed above.
                 */
                smp_mb__before_atomic();
-               atomic_inc(&dev->vblank[crtc].count);
+               atomic_inc(&vblank->count);
                smp_mb__after_atomic();
        } else {
                DRM_DEBUG("crtc %d: Redundant vblirq ignored. diff_ns = %d\n",
                          crtc, (int) diff_ns);
        }
 
-       wake_up(&dev->vblank[crtc].queue);
+       spin_unlock(&dev->vblank_time_lock);
+
+       wake_up(&vblank->queue);
        drm_handle_vblank_events(dev, crtc);
 
-       spin_unlock_irqrestore(&dev->vblank_time_lock, irqflags);
+       spin_unlock_irqrestore(&dev->event_lock, irqflags);
+
        return true;
 }
 EXPORT_SYMBOL(drm_handle_vblank);
index d34f20a79b7cdbe1e080682d18a00889d551e284..c1dc61473db58b1a518c65eae09f25f00fa6fffc 100644 (file)
  * OTHER DEALINGS IN THE SOFTWARE.
  */
 
+/*
+ * This file contains legacy interfaces that modern drm drivers
+ * should no longer be using. They cannot be removed as legacy
+ * drivers use them, and removing them are API breaks.
+ */
+#include <linux/list.h>
+#include <drm/drm_legacy.h>
+
+struct agp_memory;
 struct drm_device;
 struct drm_file;
 
@@ -48,4 +57,57 @@ int drm_legacy_rmctx(struct drm_device *d, void *v, struct drm_file *f);
 int drm_legacy_setsareactx(struct drm_device *d, void *v, struct drm_file *f);
 int drm_legacy_getsareactx(struct drm_device *d, void *v, struct drm_file *f);
 
+/*
+ * Generic Buffer Management
+ */
+
+#define DRM_MAP_HASH_OFFSET 0x10000000
+
+int drm_legacy_addmap_ioctl(struct drm_device *d, void *v, struct drm_file *f);
+int drm_legacy_rmmap_ioctl(struct drm_device *d, void *v, struct drm_file *f);
+int drm_legacy_addbufs(struct drm_device *d, void *v, struct drm_file *f);
+int drm_legacy_infobufs(struct drm_device *d, void *v, struct drm_file *f);
+int drm_legacy_markbufs(struct drm_device *d, void *v, struct drm_file *f);
+int drm_legacy_freebufs(struct drm_device *d, void *v, struct drm_file *f);
+int drm_legacy_mapbufs(struct drm_device *d, void *v, struct drm_file *f);
+int drm_legacy_dma_ioctl(struct drm_device *d, void *v, struct drm_file *f);
+
+void drm_legacy_vma_flush(struct drm_device *d);
+
+/*
+ * AGP Support
+ */
+
+struct drm_agp_mem {
+       unsigned long handle;
+       struct agp_memory *memory;
+       unsigned long bound;
+       int pages;
+       struct list_head head;
+};
+
+/*
+ * Generic Userspace Locking-API
+ */
+
+int drm_legacy_i_have_hw_lock(struct drm_device *d, struct drm_file *f);
+int drm_legacy_lock(struct drm_device *d, void *v, struct drm_file *f);
+int drm_legacy_unlock(struct drm_device *d, void *v, struct drm_file *f);
+int drm_legacy_lock_free(struct drm_lock_data *lock, unsigned int ctx);
+
+/* DMA support */
+int drm_legacy_dma_setup(struct drm_device *dev);
+void drm_legacy_dma_takedown(struct drm_device *dev);
+void drm_legacy_free_buffer(struct drm_device *dev,
+                           struct drm_buf * buf);
+void drm_legacy_reclaim_buffers(struct drm_device *dev,
+                               struct drm_file *filp);
+
+/* Scatter Gather Support */
+void drm_legacy_sg_cleanup(struct drm_device *dev);
+int drm_legacy_sg_alloc(struct drm_device *dev, void *data,
+                       struct drm_file *file_priv);
+int drm_legacy_sg_free(struct drm_device *dev, void *data,
+                      struct drm_file *file_priv);
+
 #endif /* __DRM_LEGACY_H__ */
index e26b59e385ff151116f5af63bf47626c2839f8eb..f861361a635e05c3ab91e82fdde52b0f7f0e07e2 100644 (file)
@@ -36,6 +36,7 @@
 #include <linux/export.h>
 #include <drm/drmP.h>
 #include "drm_legacy.h"
+#include "drm_internal.h"
 
 static int drm_notifier(void *priv);
 
@@ -52,7 +53,8 @@ static int drm_lock_take(struct drm_lock_data *lock_data, unsigned int context);
  *
  * Add the current task to the lock wait queue, and attempt to take to lock.
  */
-int drm_lock(struct drm_device *dev, void *data, struct drm_file *file_priv)
+int drm_legacy_lock(struct drm_device *dev, void *data,
+                   struct drm_file *file_priv)
 {
        DECLARE_WAITQUEUE(entry, current);
        struct drm_lock *lock = data;
@@ -120,7 +122,7 @@ int drm_lock(struct drm_device *dev, void *data, struct drm_file *file_priv)
                sigaddset(&dev->sigmask, SIGTTOU);
                dev->sigdata.context = lock->context;
                dev->sigdata.lock = master->lock.hw_lock;
-               block_all_signals(drm_notifier, &dev->sigdata, &dev->sigmask);
+               block_all_signals(drm_notifier, dev, &dev->sigmask);
        }
 
        if (dev->driver->dma_quiescent && (lock->flags & _DRM_LOCK_QUIESCENT))
@@ -146,7 +148,7 @@ int drm_lock(struct drm_device *dev, void *data, struct drm_file *file_priv)
  *
  * Transfer and free the lock.
  */
-int drm_unlock(struct drm_device *dev, void *data, struct drm_file *file_priv)
+int drm_legacy_unlock(struct drm_device *dev, void *data, struct drm_file *file_priv)
 {
        struct drm_lock *lock = data;
        struct drm_master *master = file_priv->master;
@@ -157,7 +159,7 @@ int drm_unlock(struct drm_device *dev, void *data, struct drm_file *file_priv)
                return -EINVAL;
        }
 
-       if (drm_lock_free(&master->lock, lock->context)) {
+       if (drm_legacy_lock_free(&master->lock, lock->context)) {
                /* FIXME: Should really bail out here. */
        }
 
@@ -250,7 +252,7 @@ static int drm_lock_transfer(struct drm_lock_data *lock_data,
  * Marks the lock as not held, via the \p cmpxchg instruction. Wakes any task
  * waiting on the lock queue.
  */
-int drm_lock_free(struct drm_lock_data *lock_data, unsigned int context)
+int drm_legacy_lock_free(struct drm_lock_data *lock_data, unsigned int context)
 {
        unsigned int old, new, prev;
        volatile unsigned int *lock = &lock_data->hw_lock->lock;
@@ -286,26 +288,27 @@ int drm_lock_free(struct drm_lock_data *lock_data, unsigned int context)
  * If the lock is not held, then let the signal proceed as usual.  If the lock
  * is held, then set the contended flag and keep the signal blocked.
  *
- * \param priv pointer to a drm_sigdata structure.
+ * \param priv pointer to a drm_device structure.
  * \return one if the signal should be delivered normally, or zero if the
  * signal should be blocked.
  */
 static int drm_notifier(void *priv)
 {
-       struct drm_sigdata *s = (struct drm_sigdata *) priv;
+       struct drm_device *dev = priv;
+       struct drm_hw_lock *lock = dev->sigdata.lock;
        unsigned int old, new, prev;
 
        /* Allow signal delivery if lock isn't held */
-       if (!s->lock || !_DRM_LOCK_IS_HELD(s->lock->lock)
-           || _DRM_LOCKING_CONTEXT(s->lock->lock) != s->context)
+       if (!lock || !_DRM_LOCK_IS_HELD(lock->lock)
+           || _DRM_LOCKING_CONTEXT(lock->lock) != dev->sigdata.context)
                return 1;
 
        /* Otherwise, set flag to force call to
           drmUnlock */
        do {
-               old = s->lock->lock;
+               old = lock->lock;
                new = old | _DRM_LOCK_CONT;
-               prev = cmpxchg(&s->lock->lock, old, new);
+               prev = cmpxchg(&lock->lock, old, new);
        } while (prev != old);
        return 0;
 }
@@ -323,7 +326,7 @@ static int drm_notifier(void *priv)
  * having to worry about starvation.
  */
 
-void drm_idlelock_take(struct drm_lock_data *lock_data)
+void drm_legacy_idlelock_take(struct drm_lock_data *lock_data)
 {
        int ret;
 
@@ -340,9 +343,9 @@ void drm_idlelock_take(struct drm_lock_data *lock_data)
        }
        spin_unlock_bh(&lock_data->spinlock);
 }
-EXPORT_SYMBOL(drm_idlelock_take);
+EXPORT_SYMBOL(drm_legacy_idlelock_take);
 
-void drm_idlelock_release(struct drm_lock_data *lock_data)
+void drm_legacy_idlelock_release(struct drm_lock_data *lock_data)
 {
        unsigned int old, prev;
        volatile unsigned int *lock = &lock_data->hw_lock->lock;
@@ -360,9 +363,10 @@ void drm_idlelock_release(struct drm_lock_data *lock_data)
        }
        spin_unlock_bh(&lock_data->spinlock);
 }
-EXPORT_SYMBOL(drm_idlelock_release);
+EXPORT_SYMBOL(drm_legacy_idlelock_release);
 
-int drm_i_have_hw_lock(struct drm_device *dev, struct drm_file *file_priv)
+int drm_legacy_i_have_hw_lock(struct drm_device *dev,
+                             struct drm_file *file_priv)
 {
        struct drm_master *master = file_priv->master;
        return (file_priv->lock_count && master->lock.hw_lock &&
index 00c67c0f238127d1d36c8ba17e6caf184412c446..a521ef6ff8072ab7e65508b5da98b84dc058bfa0 100644 (file)
 #include <linux/highmem.h>
 #include <linux/export.h>
 #include <drm/drmP.h>
+#include "drm_legacy.h"
 
 #if __OS_HAS_AGP
+
+#ifdef HAVE_PAGE_AGP
+# include <asm/agp.h>
+#else
+# ifdef __powerpc__
+#  define PAGE_AGP     __pgprot(_PAGE_KERNEL | _PAGE_NO_CACHE)
+# else
+#  define PAGE_AGP     PAGE_KERNEL
+# endif
+#endif
+
 static void *agp_remap(unsigned long offset, unsigned long size,
                       struct drm_device * dev)
 {
@@ -108,25 +120,25 @@ static inline void *agp_remap(unsigned long offset, unsigned long size,
 
 #endif                         /* agp */
 
-void drm_core_ioremap(struct drm_local_map *map, struct drm_device *dev)
+void drm_legacy_ioremap(struct drm_local_map *map, struct drm_device *dev)
 {
        if (dev->agp && dev->agp->cant_use_aperture && map->type == _DRM_AGP)
                map->handle = agp_remap(map->offset, map->size, dev);
        else
                map->handle = ioremap(map->offset, map->size);
 }
-EXPORT_SYMBOL(drm_core_ioremap);
+EXPORT_SYMBOL(drm_legacy_ioremap);
 
-void drm_core_ioremap_wc(struct drm_local_map *map, struct drm_device *dev)
+void drm_legacy_ioremap_wc(struct drm_local_map *map, struct drm_device *dev)
 {
        if (dev->agp && dev->agp->cant_use_aperture && map->type == _DRM_AGP)
                map->handle = agp_remap(map->offset, map->size, dev);
        else
                map->handle = ioremap_wc(map->offset, map->size);
 }
-EXPORT_SYMBOL(drm_core_ioremap_wc);
+EXPORT_SYMBOL(drm_legacy_ioremap_wc);
 
-void drm_core_ioremapfree(struct drm_local_map *map, struct drm_device *dev)
+void drm_legacy_ioremapfree(struct drm_local_map *map, struct drm_device *dev)
 {
        if (!map->handle || !map->size)
                return;
@@ -136,4 +148,4 @@ void drm_core_ioremapfree(struct drm_local_map *map, struct drm_device *dev)
        else
                iounmap(map->handle);
 }
-EXPORT_SYMBOL(drm_core_ioremapfree);
+EXPORT_SYMBOL(drm_legacy_ioremapfree);
index 6aa6a9e95570690360d191953d1566ad55227809..eb6dfe52cab24e1aa36ef12ee951c7c2d7103d6f 100644 (file)
@@ -231,6 +231,9 @@ ssize_t mipi_dsi_dcs_write(struct mipi_dsi_device *dsi, const void *data,
                break;
        }
 
+       if (dsi->mode_flags & MIPI_DSI_MODE_LPM)
+               msg.flags = MIPI_DSI_MSG_USE_LPM;
+
        return ops->transfer(dsi->host, &msg);
 }
 EXPORT_SYMBOL(mipi_dsi_dcs_write);
@@ -260,6 +263,9 @@ ssize_t mipi_dsi_dcs_read(struct mipi_dsi_device *dsi, u8 cmd, void *data,
        if (!ops || !ops->transfer)
                return -ENOSYS;
 
+       if (dsi->mode_flags & MIPI_DSI_MODE_LPM)
+               msg.flags = MIPI_DSI_MSG_USE_LPM;
+
        return ops->transfer(dsi->host, &msg);
 }
 EXPORT_SYMBOL(mipi_dsi_dcs_read);
index bedf1894e17e5fa0f8f6a028a970c976725e1dba..d1b7d20065293338ccf88282369dda6a59c78c7f 100644 (file)
@@ -1259,6 +1259,7 @@ drm_mode_create_from_cmdline_mode(struct drm_device *dev,
        if (!mode)
                return NULL;
 
+       mode->type |= DRM_MODE_TYPE_USERDEF;
        drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V);
        return mode;
 }
index 0dc57d5ecd10d1e7e777c04817b0fd1a67df79e9..474e4d12a2d8a73109a35fe3eb3b9948635fedaa 100644 (file)
@@ -35,7 +35,7 @@
  * of extra utility/tracking out of our acquire-ctx.  This is provided
  * by drm_modeset_lock / drm_modeset_acquire_ctx.
  *
- * For basic principles of ww_mutex, see: Documentation/ww-mutex-design.txt
+ * For basic principles of ww_mutex, see: Documentation/locking/ww-mutex-design.txt
  *
  * The basic usage pattern is to:
  *
  */
 
 
+/**
+ * __drm_modeset_lock_all - internal helper to grab all modeset locks
+ * @dev: DRM device
+ * @trylock: trylock mode for atomic contexts
+ *
+ * This is a special version of drm_modeset_lock_all() which can also be used in
+ * atomic contexts. Then @trylock must be set to true.
+ *
+ * Returns:
+ * 0 on success or negative error code on failure.
+ */
+int __drm_modeset_lock_all(struct drm_device *dev,
+                          bool trylock)
+{
+       struct drm_mode_config *config = &dev->mode_config;
+       struct drm_modeset_acquire_ctx *ctx;
+       int ret;
+
+       ctx = kzalloc(sizeof(*ctx),
+                     trylock ? GFP_ATOMIC : GFP_KERNEL);
+       if (!ctx)
+               return -ENOMEM;
+
+       if (trylock) {
+               if (!mutex_trylock(&config->mutex))
+                       return -EBUSY;
+       } else {
+               mutex_lock(&config->mutex);
+       }
+
+       drm_modeset_acquire_init(ctx, 0);
+       ctx->trylock_only = trylock;
+
+retry:
+       ret = drm_modeset_lock(&config->connection_mutex, ctx);
+       if (ret)
+               goto fail;
+       ret = drm_modeset_lock_all_crtcs(dev, ctx);
+       if (ret)
+               goto fail;
+
+       WARN_ON(config->acquire_ctx);
+
+       /* now we hold the locks, so now that it is safe, stash the
+        * ctx for drm_modeset_unlock_all():
+        */
+       config->acquire_ctx = ctx;
+
+       drm_warn_on_modeset_not_all_locked(dev);
+
+       return 0;
+
+fail:
+       if (ret == -EDEADLK) {
+               drm_modeset_backoff(ctx);
+               goto retry;
+       }
+
+       return ret;
+}
+EXPORT_SYMBOL(__drm_modeset_lock_all);
+
+/**
+ * drm_modeset_lock_all - take all modeset locks
+ * @dev: drm device
+ *
+ * This function takes all modeset locks, suitable where a more fine-grained
+ * scheme isn't (yet) implemented. Locks must be dropped with
+ * drm_modeset_unlock_all.
+ */
+void drm_modeset_lock_all(struct drm_device *dev)
+{
+       WARN_ON(__drm_modeset_lock_all(dev, false) != 0);
+}
+EXPORT_SYMBOL(drm_modeset_lock_all);
+
+/**
+ * drm_modeset_unlock_all - drop all modeset locks
+ * @dev: device
+ *
+ * This function drop all modeset locks taken by drm_modeset_lock_all.
+ */
+void drm_modeset_unlock_all(struct drm_device *dev)
+{
+       struct drm_mode_config *config = &dev->mode_config;
+       struct drm_modeset_acquire_ctx *ctx = config->acquire_ctx;
+
+       if (WARN_ON(!ctx))
+               return;
+
+       config->acquire_ctx = NULL;
+       drm_modeset_drop_locks(ctx);
+       drm_modeset_acquire_fini(ctx);
+
+       kfree(ctx);
+
+       mutex_unlock(&dev->mode_config.mutex);
+}
+EXPORT_SYMBOL(drm_modeset_unlock_all);
+
+/**
+ * drm_modeset_lock_crtc - lock crtc with hidden acquire ctx
+ * @crtc: drm crtc
+ *
+ * This function locks the given crtc using a hidden acquire context. This is
+ * necessary so that drivers internally using the atomic interfaces can grab
+ * further locks with the lock acquire context.
+ */
+void drm_modeset_lock_crtc(struct drm_crtc *crtc)
+{
+       struct drm_modeset_acquire_ctx *ctx;
+       int ret;
+
+       ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
+       if (WARN_ON(!ctx))
+               return;
+
+       drm_modeset_acquire_init(ctx, 0);
+
+retry:
+       ret = drm_modeset_lock(&crtc->mutex, ctx);
+       if (ret)
+               goto fail;
+
+       WARN_ON(crtc->acquire_ctx);
+
+       /* now we hold the locks, so now that it is safe, stash the
+        * ctx for drm_modeset_unlock_crtc():
+        */
+       crtc->acquire_ctx = ctx;
+
+       return;
+
+fail:
+       if (ret == -EDEADLK) {
+               drm_modeset_backoff(ctx);
+               goto retry;
+       }
+}
+EXPORT_SYMBOL(drm_modeset_lock_crtc);
+
+/**
+ * drm_modeset_legacy_acquire_ctx - find acquire ctx for legacy ioctls
+ * @crtc: drm crtc
+ *
+ * Legacy ioctl operations like cursor updates or page flips only have per-crtc
+ * locking, and store the acquire ctx in the corresponding crtc. All other
+ * legacy operations take all locks and use a global acquire context. This
+ * function grabs the right one.
+ */
+struct drm_modeset_acquire_ctx *
+drm_modeset_legacy_acquire_ctx(struct drm_crtc *crtc)
+{
+       if (crtc->acquire_ctx)
+               return crtc->acquire_ctx;
+
+       WARN_ON(!crtc->dev->mode_config.acquire_ctx);
+
+       return crtc->dev->mode_config.acquire_ctx;
+}
+EXPORT_SYMBOL(drm_modeset_legacy_acquire_ctx);
+
+/**
+ * drm_modeset_unlock_crtc - drop crtc lock
+ * @crtc: drm crtc
+ *
+ * This drops the crtc lock acquire with drm_modeset_lock_crtc() and all other
+ * locks acquired through the hidden context.
+ */
+void drm_modeset_unlock_crtc(struct drm_crtc *crtc)
+{
+       struct drm_modeset_acquire_ctx *ctx = crtc->acquire_ctx;
+
+       if (WARN_ON(!ctx))
+               return;
+
+       crtc->acquire_ctx = NULL;
+       drm_modeset_drop_locks(ctx);
+       drm_modeset_acquire_fini(ctx);
+
+       kfree(ctx);
+}
+EXPORT_SYMBOL(drm_modeset_unlock_crtc);
+
+/**
+ * drm_warn_on_modeset_not_all_locked - check that all modeset locks are locked
+ * @dev: device
+ *
+ * Useful as a debug assert.
+ */
+void drm_warn_on_modeset_not_all_locked(struct drm_device *dev)
+{
+       struct drm_crtc *crtc;
+
+       /* Locking is currently fubar in the panic handler. */
+       if (oops_in_progress)
+               return;
+
+       list_for_each_entry(crtc, &dev->mode_config.crtc_list, head)
+               WARN_ON(!drm_modeset_is_locked(&crtc->mutex));
+
+       WARN_ON(!drm_modeset_is_locked(&dev->mode_config.connection_mutex));
+       WARN_ON(!mutex_is_locked(&dev->mode_config.mutex));
+}
+EXPORT_SYMBOL(drm_warn_on_modeset_not_all_locked);
+
 /**
  * drm_modeset_acquire_init - initialize acquire context
  * @ctx: the acquire context
@@ -108,7 +314,12 @@ static inline int modeset_lock(struct drm_modeset_lock *lock,
 
        WARN_ON(ctx->contended);
 
-       if (interruptible && slow) {
+       if (ctx->trylock_only) {
+               if (!ww_mutex_trylock(&lock->mutex))
+                       return -EBUSY;
+               else
+                       return 0;
+       } else if (interruptible && slow) {
                ret = ww_mutex_lock_slow_interruptible(&lock->mutex, &ctx->ww_ctx);
        } else if (interruptible) {
                ret = ww_mutex_lock_interruptible(&lock->mutex, &ctx->ww_ctx);
index 020cfd9348541107774a3bcb5fd2a9ab2d9cb539..fd29f03645b8e465b42add64384b339c13229dc2 100644 (file)
@@ -27,6 +27,7 @@
 #include <linux/dma-mapping.h>
 #include <linux/export.h>
 #include <drm/drmP.h>
+#include "drm_legacy.h"
 
 /**
  * drm_pci_alloc - Allocate a PCI consistent memory block, for DMA.
@@ -81,7 +82,7 @@ EXPORT_SYMBOL(drm_pci_alloc);
  *
  * This function is for internal use in the Linux-specific DRM core code.
  */
-void __drm_pci_free(struct drm_device * dev, drm_dma_handle_t * dmah)
+void __drm_legacy_pci_free(struct drm_device * dev, drm_dma_handle_t * dmah)
 {
        unsigned long addr;
        size_t sz;
@@ -105,7 +106,7 @@ void __drm_pci_free(struct drm_device * dev, drm_dma_handle_t * dmah)
  */
 void drm_pci_free(struct drm_device * dev, drm_dma_handle_t * dmah)
 {
-       __drm_pci_free(dev, dmah);
+       __drm_legacy_pci_free(dev, dmah);
        kfree(dmah);
 }
 
@@ -127,34 +128,20 @@ static int drm_get_pci_domain(struct drm_device *dev)
        return pci_domain_nr(dev->pdev->bus);
 }
 
-static int drm_pci_set_busid(struct drm_device *dev, struct drm_master *master)
+int drm_pci_set_busid(struct drm_device *dev, struct drm_master *master)
 {
-       int len, ret;
-       master->unique_len = 40;
-       master->unique_size = master->unique_len;
-       master->unique = kmalloc(master->unique_size, GFP_KERNEL);
-       if (master->unique == NULL)
+       master->unique = kasprintf(GFP_KERNEL, "pci:%04x:%02x:%02x.%d",
+                                       drm_get_pci_domain(dev),
+                                       dev->pdev->bus->number,
+                                       PCI_SLOT(dev->pdev->devfn),
+                                       PCI_FUNC(dev->pdev->devfn));
+       if (!master->unique)
                return -ENOMEM;
 
-
-       len = snprintf(master->unique, master->unique_len,
-                      "pci:%04x:%02x:%02x.%d",
-                      drm_get_pci_domain(dev),
-                      dev->pdev->bus->number,
-                      PCI_SLOT(dev->pdev->devfn),
-                      PCI_FUNC(dev->pdev->devfn));
-
-       if (len >= master->unique_len) {
-               DRM_ERROR("buffer overflow");
-               ret = -EINVAL;
-               goto err;
-       } else
-               master->unique_len = len;
-
+       master->unique_len = strlen(master->unique);
        return 0;
-err:
-       return ret;
 }
+EXPORT_SYMBOL(drm_pci_set_busid);
 
 int drm_pci_set_unique(struct drm_device *dev,
                       struct drm_master *master,
@@ -163,8 +150,7 @@ int drm_pci_set_unique(struct drm_device *dev,
        int domain, bus, slot, func, ret;
 
        master->unique_len = u->unique_len;
-       master->unique_size = u->unique_len + 1;
-       master->unique = kmalloc(master->unique_size, GFP_KERNEL);
+       master->unique = kmalloc(master->unique_len + 1, GFP_KERNEL);
        if (!master->unique) {
                ret = -ENOMEM;
                goto err;
@@ -269,10 +255,6 @@ void drm_pci_agp_destroy(struct drm_device *dev)
        }
 }
 
-static struct drm_bus drm_pci_bus = {
-       .set_busid = drm_pci_set_busid,
-};
-
 /**
  * drm_get_pci_dev - Register a PCI device with the DRM subsystem
  * @pdev: PCI device
@@ -353,8 +335,6 @@ int drm_pci_init(struct drm_driver *driver, struct pci_driver *pdriver)
 
        DRM_DEBUG("\n");
 
-       driver->bus = &drm_pci_bus;
-
        if (driver->driver_features & DRIVER_MODESET)
                return pci_register_driver(pdriver);
 
index d5b76f148c12aa2b214b9a4185d6e302eb3de71d..5314c9d5fef473daeb14677f08497780e87ef987 100644 (file)
@@ -68,42 +68,23 @@ err_free:
        return ret;
 }
 
-static int drm_platform_set_busid(struct drm_device *dev, struct drm_master *master)
+int drm_platform_set_busid(struct drm_device *dev, struct drm_master *master)
 {
-       int len, ret, id;
-
-       master->unique_len = 13 + strlen(dev->platformdev->name);
-       master->unique_size = master->unique_len;
-       master->unique = kmalloc(master->unique_len + 1, GFP_KERNEL);
-
-       if (master->unique == NULL)
-               return -ENOMEM;
+       int id;
 
        id = dev->platformdev->id;
-
-       /* if only a single instance of the platform device, id will be
-        * set to -1.. use 0 instead to avoid a funny looking bus-id:
-        */
-       if (id == -1)
+       if (id < 0)
                id = 0;
 
-       len = snprintf(master->unique, master->unique_len,
-                       "platform:%s:%02d", dev->platformdev->name, id);
-
-       if (len > master->unique_len) {
-               DRM_ERROR("Unique buffer overflowed\n");
-               ret = -EINVAL;
-               goto err;
-       }
+       master->unique = kasprintf(GFP_KERNEL, "platform:%s:%02d",
+                                               dev->platformdev->name, id);
+       if (!master->unique)
+               return -ENOMEM;
 
+       master->unique_len = strlen(master->unique);
        return 0;
-err:
-       return ret;
 }
-
-static struct drm_bus drm_platform_bus = {
-       .set_busid = drm_platform_set_busid,
-};
+EXPORT_SYMBOL(drm_platform_set_busid);
 
 /**
  * drm_platform_init - Register a platform device with the DRM subsystem
@@ -120,7 +101,6 @@ int drm_platform_init(struct drm_driver *driver, struct platform_device *platfor
 {
        DRM_DEBUG("\n");
 
-       driver->bus = &drm_platform_bus;
        return drm_get_platform_dev(platform_device, driver);
 }
 EXPORT_SYMBOL(drm_platform_init);
index 99d578bad17eabc26d972fab1c4e475f9ba46096..78ca30808422fc56c67acb4659f38f06a555b1db 100644 (file)
@@ -29,6 +29,9 @@
 #include <linux/export.h>
 #include <linux/dma-buf.h>
 #include <drm/drmP.h>
+#include <drm/drm_gem.h>
+
+#include "drm_internal.h"
 
 /*
  * DMA-BUF/GEM Object references and lifetime overview:
@@ -522,7 +525,7 @@ struct drm_gem_object *drm_gem_prime_import(struct drm_device *dev,
                goto fail_detach;
        }
 
-       obj = dev->driver->gem_prime_import_sg_table(dev, dma_buf->size, sgt);
+       obj = dev->driver->gem_prime_import_sg_table(dev, attach, sgt);
        if (IS_ERR(obj)) {
                ret = PTR_ERR(obj);
                goto fail_unmap;
index db7d250f7ac753dd244307d49217726e101df51e..6857e9ad6339c7a8ab94aea908be59323985df44 100644 (file)
@@ -82,6 +82,22 @@ static void drm_mode_validate_flag(struct drm_connector *connector,
        return;
 }
 
+static int drm_helper_probe_add_cmdline_mode(struct drm_connector *connector)
+{
+       struct drm_display_mode *mode;
+
+       if (!connector->cmdline_mode.specified)
+               return 0;
+
+       mode = drm_mode_create_from_cmdline_mode(connector->dev,
+                                                &connector->cmdline_mode);
+       if (mode == NULL)
+               return 0;
+
+       drm_mode_probed_add(connector, mode);
+       return 1;
+}
+
 static int drm_helper_probe_single_connector_modes_merge_bits(struct drm_connector *connector,
                                                              uint32_t maxX, uint32_t maxY, bool merge_type_bits)
 {
@@ -141,6 +157,7 @@ static int drm_helper_probe_single_connector_modes_merge_bits(struct drm_connect
 
        if (count == 0 && connector->status == connector_status_connected)
                count = drm_add_modes_noedid(connector, 1024, 768);
+       count += drm_helper_probe_add_cmdline_mode(connector);
        if (count == 0)
                goto prune;
 
index 1c78406f6e71395453734a705d772303862f041e..4f0f3b36d537c258dbf28fd0dde4dd962ed98ae4 100644 (file)
@@ -34,6 +34,7 @@
 #include <linux/vmalloc.h>
 #include <linux/slab.h>
 #include <drm/drmP.h>
+#include "drm_legacy.h"
 
 #define DEBUG_SCATTER 0
 
@@ -78,8 +79,8 @@ void drm_legacy_sg_cleanup(struct drm_device *dev)
 # define ScatterHandle(x) (unsigned int)(x)
 #endif
 
-int drm_sg_alloc(struct drm_device *dev, void *data,
-                struct drm_file *file_priv)
+int drm_legacy_sg_alloc(struct drm_device *dev, void *data,
+                       struct drm_file *file_priv)
 {
        struct drm_scatter_gather *request = data;
        struct drm_sg_mem *entry;
@@ -194,8 +195,8 @@ int drm_sg_alloc(struct drm_device *dev, void *data,
        return -ENOMEM;
 }
 
-int drm_sg_free(struct drm_device *dev, void *data,
-               struct drm_file *file_priv)
+int drm_legacy_sg_free(struct drm_device *dev, void *data,
+                      struct drm_file *file_priv)
 {
        struct drm_scatter_gather *request = data;
        struct drm_sg_mem *entry;
index ab1a5f6dde8afd40a58987d4faa2f5f2f54828cb..cc3d6d6d67e00a52d8924bfa5dba6a51dfda5f00 100644 (file)
@@ -21,6 +21,7 @@
 #include <drm/drm_sysfs.h>
 #include <drm/drm_core.h>
 #include <drm/drmP.h>
+#include "drm_internal.h"
 
 #define to_drm_minor(d) dev_get_drvdata(d)
 #define to_drm_connector(d) dev_get_drvdata(d)
diff --git a/drivers/gpu/drm/drm_usb.c b/drivers/gpu/drm/drm_usb.c
deleted file mode 100644 (file)
index f2fe94a..0000000
+++ /dev/null
@@ -1,88 +0,0 @@
-#include <drm/drmP.h>
-#include <drm/drm_usb.h>
-#include <linux/usb.h>
-#include <linux/module.h>
-
-int drm_get_usb_dev(struct usb_interface *interface,
-                   const struct usb_device_id *id,
-                   struct drm_driver *driver)
-{
-       struct drm_device *dev;
-       int ret;
-
-       DRM_DEBUG("\n");
-
-       dev = drm_dev_alloc(driver, &interface->dev);
-       if (!dev)
-               return -ENOMEM;
-
-       dev->usbdev = interface_to_usbdev(interface);
-       usb_set_intfdata(interface, dev);
-
-       ret = drm_dev_register(dev, 0);
-       if (ret)
-               goto err_free;
-
-       DRM_INFO("Initialized %s %d.%d.%d %s on minor %d\n",
-                driver->name, driver->major, driver->minor, driver->patchlevel,
-                driver->date, dev->primary->index);
-
-       return 0;
-
-err_free:
-       drm_dev_unref(dev);
-       return ret;
-
-}
-EXPORT_SYMBOL(drm_get_usb_dev);
-
-static int drm_usb_set_busid(struct drm_device *dev,
-                              struct drm_master *master)
-{
-       return 0;
-}
-
-static struct drm_bus drm_usb_bus = {
-       .set_busid = drm_usb_set_busid,
-};
-
-/**
- * drm_usb_init - Register matching USB devices with the DRM subsystem
- * @driver: DRM device driver
- * @udriver: USB device driver
- *
- * Registers one or more devices matched by a USB driver with the DRM
- * subsystem.
- *
- * Return: 0 on success or a negative error code on failure.
- */
-int drm_usb_init(struct drm_driver *driver, struct usb_driver *udriver)
-{
-       int res;
-       DRM_DEBUG("\n");
-
-       driver->bus = &drm_usb_bus;
-
-       res = usb_register(udriver);
-       return res;
-}
-EXPORT_SYMBOL(drm_usb_init);
-
-/**
- * drm_usb_exit - Unregister matching USB devices from the DRM subsystem
- * @driver: DRM device driver
- * @udriver: USB device driver
- *
- * Unregisters one or more devices matched by a USB driver from the DRM
- * subsystem.
- */
-void drm_usb_exit(struct drm_driver *driver,
-                 struct usb_driver *udriver)
-{
-       usb_deregister(udriver);
-}
-EXPORT_SYMBOL(drm_usb_exit);
-
-MODULE_AUTHOR("David Airlie");
-MODULE_DESCRIPTION("USB DRM support");
-MODULE_LICENSE("GPL and additional rights");
index 24e045c4f53140270ebbb28f9a6be21209b704a7..4a2c328959e59348ef7ee5f4bb0797835cd92ba5 100644 (file)
 
 #include <drm/drmP.h>
 #include <linux/export.h>
+#include <linux/seq_file.h>
 #if defined(__ia64__)
 #include <linux/efi.h>
 #include <linux/slab.h>
 #endif
+#include <asm/pgtable.h>
+#include "drm_legacy.h"
+
+struct drm_vma_entry {
+       struct list_head head;
+       struct vm_area_struct *vma;
+       pid_t pid;
+};
 
 static void drm_vm_open(struct vm_area_struct *vma);
 static void drm_vm_close(struct vm_area_struct *vma);
@@ -48,15 +57,11 @@ static pgprot_t drm_io_prot(struct drm_local_map *map,
 {
        pgprot_t tmp = vm_get_page_prot(vma->vm_flags);
 
-#if defined(__i386__) || defined(__x86_64__)
+#if defined(__i386__) || defined(__x86_64__) || defined(__powerpc__)
        if (map->type == _DRM_REGISTERS && !(map->flags & _DRM_WRITE_COMBINING))
                tmp = pgprot_noncached(tmp);
        else
                tmp = pgprot_writecombine(tmp);
-#elif defined(__powerpc__)
-       pgprot_val(tmp) |= _PAGE_NO_CACHE;
-       if (map->type == _DRM_REGISTERS)
-               pgprot_val(tmp) |= _PAGE_GUARDED;
 #elif defined(__ia64__)
        if (efi_range_is_wc(vma->vm_start, vma->vm_end -
                                    vma->vm_start))
@@ -263,7 +268,7 @@ static void drm_vm_shm_close(struct vm_area_struct *vma)
                                dmah.vaddr = map->handle;
                                dmah.busaddr = map->offset;
                                dmah.size = map->size;
-                               __drm_pci_free(dev, &dmah);
+                               __drm_legacy_pci_free(dev, &dmah);
                                break;
                        }
                        kfree(map);
@@ -412,7 +417,6 @@ void drm_vm_open_locked(struct drm_device *dev,
                list_add(&vma_entry->head, &dev->vmalist);
        }
 }
-EXPORT_SYMBOL_GPL(drm_vm_open_locked);
 
 static void drm_vm_open(struct vm_area_struct *vma)
 {
@@ -532,7 +536,7 @@ static resource_size_t drm_core_get_reg_ofs(struct drm_device *dev)
  * according to the mapping type and remaps the pages. Finally sets the file
  * pointer and calls vm_open().
  */
-int drm_mmap_locked(struct file *filp, struct vm_area_struct *vma)
+static int drm_mmap_locked(struct file *filp, struct vm_area_struct *vma)
 {
        struct drm_file *priv = filp->private_data;
        struct drm_device *dev = priv->minor->dev;
@@ -646,7 +650,7 @@ int drm_mmap_locked(struct file *filp, struct vm_area_struct *vma)
        return 0;
 }
 
-int drm_mmap(struct file *filp, struct vm_area_struct *vma)
+int drm_legacy_mmap(struct file *filp, struct vm_area_struct *vma)
 {
        struct drm_file *priv = filp->private_data;
        struct drm_device *dev = priv->minor->dev;
@@ -661,4 +665,69 @@ int drm_mmap(struct file *filp, struct vm_area_struct *vma)
 
        return ret;
 }
-EXPORT_SYMBOL(drm_mmap);
+EXPORT_SYMBOL(drm_legacy_mmap);
+
+void drm_legacy_vma_flush(struct drm_device *dev)
+{
+       struct drm_vma_entry *vma, *vma_temp;
+
+       /* Clear vma list (only needed for legacy drivers) */
+       list_for_each_entry_safe(vma, vma_temp, &dev->vmalist, head) {
+               list_del(&vma->head);
+               kfree(vma);
+       }
+}
+
+int drm_vma_info(struct seq_file *m, void *data)
+{
+       struct drm_info_node *node = (struct drm_info_node *) m->private;
+       struct drm_device *dev = node->minor->dev;
+       struct drm_vma_entry *pt;
+       struct vm_area_struct *vma;
+       unsigned long vma_count = 0;
+#if defined(__i386__)
+       unsigned int pgprot;
+#endif
+
+       mutex_lock(&dev->struct_mutex);
+       list_for_each_entry(pt, &dev->vmalist, head)
+               vma_count++;
+
+       seq_printf(m, "vma use count: %lu, high_memory = %pK, 0x%pK\n",
+                  vma_count, high_memory,
+                  (void *)(unsigned long)virt_to_phys(high_memory));
+
+       list_for_each_entry(pt, &dev->vmalist, head) {
+               vma = pt->vma;
+               if (!vma)
+                       continue;
+               seq_printf(m,
+                          "\n%5d 0x%pK-0x%pK %c%c%c%c%c%c 0x%08lx000",
+                          pt->pid,
+                          (void *)vma->vm_start, (void *)vma->vm_end,
+                          vma->vm_flags & VM_READ ? 'r' : '-',
+                          vma->vm_flags & VM_WRITE ? 'w' : '-',
+                          vma->vm_flags & VM_EXEC ? 'x' : '-',
+                          vma->vm_flags & VM_MAYSHARE ? 's' : 'p',
+                          vma->vm_flags & VM_LOCKED ? 'l' : '-',
+                          vma->vm_flags & VM_IO ? 'i' : '-',
+                          vma->vm_pgoff);
+
+#if defined(__i386__)
+               pgprot = pgprot_val(vma->vm_page_prot);
+               seq_printf(m, " %c%c%c%c%c%c%c%c%c",
+                          pgprot & _PAGE_PRESENT ? 'p' : '-',
+                          pgprot & _PAGE_RW ? 'w' : 'r',
+                          pgprot & _PAGE_USER ? 'u' : 's',
+                          pgprot & _PAGE_PWT ? 't' : 'b',
+                          pgprot & _PAGE_PCD ? 'u' : 'c',
+                          pgprot & _PAGE_ACCESSED ? 'a' : '-',
+                          pgprot & _PAGE_DIRTY ? 'd' : '-',
+                          pgprot & _PAGE_PSE ? 'm' : 'k',
+                          pgprot & _PAGE_GLOBAL ? 'g' : 'l');
+#endif
+               seq_printf(m, "\n");
+       }
+       mutex_unlock(&dev->struct_mutex);
+       return 0;
+}
index 4f3c7eb2d37d49a5aadc3d27ea401d3dcc430e20..cd50ece316016a403881ff7446f1ee9fdc512f9a 100644 (file)
@@ -329,8 +329,8 @@ static int exynos_dp_link_start(struct exynos_dp_device *dp)
                return retval;
 
        for (lane = 0; lane < lane_count; lane++)
-               buf[lane] = DP_TRAIN_PRE_EMPHASIS_0 |
-                           DP_TRAIN_VOLTAGE_SWING_400;
+               buf[lane] = DP_TRAIN_PRE_EMPH_LEVEL_0 |
+                           DP_TRAIN_VOLTAGE_SWING_LEVEL_0;
 
        retval = exynos_dp_write_bytes_to_dpcd(dp, DP_TRAINING_LANE0_SET,
                        lane_count, buf);
@@ -937,6 +937,8 @@ static enum drm_connector_status exynos_dp_detect(
 
 static void exynos_dp_connector_destroy(struct drm_connector *connector)
 {
+       drm_connector_unregister(connector);
+       drm_connector_cleanup(connector);
 }
 
 static struct drm_connector_funcs exynos_dp_connector_funcs = {
@@ -1358,8 +1360,8 @@ static void exynos_dp_unbind(struct device *dev, struct device *master,
 
        exynos_dp_dpms(display, DRM_MODE_DPMS_OFF);
 
+       exynos_dp_connector_destroy(&dp->connector);
        encoder->funcs->destroy(encoder);
-       drm_connector_cleanup(&dp->connector);
 }
 
 static const struct component_ops exynos_dp_ops = {
index b68e58f78cd12f15c639b443c62a3f94431dd093..8e38e9f8e542d17d9b793ceb1efed9cb3fcc0056 100644 (file)
@@ -32,7 +32,6 @@ enum exynos_crtc_mode {
  * Exynos specific crtc structure.
  *
  * @drm_crtc: crtc object.
- * @drm_plane: pointer of private plane object for this crtc
  * @manager: the manager associated with this crtc
  * @pipe: a crtc index created at load() with a new crtc object creation
  *     and the crtc object would be set to private->crtc array
@@ -46,7 +45,6 @@ enum exynos_crtc_mode {
  */
 struct exynos_drm_crtc {
        struct drm_crtc                 drm_crtc;
-       struct drm_plane                *plane;
        struct exynos_drm_manager       *manager;
        unsigned int                    pipe;
        unsigned int                    dpms;
@@ -94,12 +92,12 @@ static void exynos_drm_crtc_commit(struct drm_crtc *crtc)
 
        exynos_drm_crtc_dpms(crtc, DRM_MODE_DPMS_ON);
 
-       exynos_plane_commit(exynos_crtc->plane);
+       exynos_plane_commit(crtc->primary);
 
        if (manager->ops->commit)
                manager->ops->commit(manager);
 
-       exynos_plane_dpms(exynos_crtc->plane, DRM_MODE_DPMS_ON);
+       exynos_plane_dpms(crtc->primary, DRM_MODE_DPMS_ON);
 }
 
 static bool
@@ -123,10 +121,9 @@ exynos_drm_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *mode,
 {
        struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);
        struct exynos_drm_manager *manager = exynos_crtc->manager;
-       struct drm_plane *plane = exynos_crtc->plane;
+       struct drm_framebuffer *fb = crtc->primary->fb;
        unsigned int crtc_w;
        unsigned int crtc_h;
-       int ret;
 
        /*
         * copy the mode data adjusted by mode_fixup() into crtc->mode
@@ -134,29 +131,21 @@ exynos_drm_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *mode,
         */
        memcpy(&crtc->mode, adjusted_mode, sizeof(*adjusted_mode));
 
-       crtc_w = crtc->primary->fb->width - x;
-       crtc_h = crtc->primary->fb->height - y;
+       crtc_w = fb->width - x;
+       crtc_h = fb->height - y;
 
        if (manager->ops->mode_set)
                manager->ops->mode_set(manager, &crtc->mode);
 
-       ret = exynos_plane_mode_set(plane, crtc, crtc->primary->fb, 0, 0, crtc_w, crtc_h,
-                                   x, y, crtc_w, crtc_h);
-       if (ret)
-               return ret;
-
-       plane->crtc = crtc;
-       plane->fb = crtc->primary->fb;
-       drm_framebuffer_reference(plane->fb);
-
-       return 0;
+       return exynos_plane_mode_set(crtc->primary, crtc, fb, 0, 0,
+                                    crtc_w, crtc_h, x, y, crtc_w, crtc_h);
 }
 
 static int exynos_drm_crtc_mode_set_commit(struct drm_crtc *crtc, int x, int y,
                                          struct drm_framebuffer *old_fb)
 {
        struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);
-       struct drm_plane *plane = exynos_crtc->plane;
+       struct drm_framebuffer *fb = crtc->primary->fb;
        unsigned int crtc_w;
        unsigned int crtc_h;
        int ret;
@@ -167,11 +156,11 @@ static int exynos_drm_crtc_mode_set_commit(struct drm_crtc *crtc, int x, int y,
                return -EPERM;
        }
 
-       crtc_w = crtc->primary->fb->width - x;
-       crtc_h = crtc->primary->fb->height - y;
+       crtc_w = fb->width - x;
+       crtc_h = fb->height - y;
 
-       ret = exynos_plane_mode_set(plane, crtc, crtc->primary->fb, 0, 0, crtc_w, crtc_h,
-                                   x, y, crtc_w, crtc_h);
+       ret = exynos_plane_mode_set(crtc->primary, crtc, fb, 0, 0,
+                                   crtc_w, crtc_h, x, y, crtc_w, crtc_h);
        if (ret)
                return ret;
 
@@ -304,8 +293,7 @@ static int exynos_drm_crtc_set_property(struct drm_crtc *crtc,
                        exynos_drm_crtc_commit(crtc);
                        break;
                case CRTC_MODE_BLANK:
-                       exynos_plane_dpms(exynos_crtc->plane,
-                                         DRM_MODE_DPMS_OFF);
+                       exynos_plane_dpms(crtc->primary, DRM_MODE_DPMS_OFF);
                        break;
                default:
                        break;
@@ -351,8 +339,10 @@ static void exynos_drm_crtc_attach_mode_property(struct drm_crtc *crtc)
 int exynos_drm_crtc_create(struct exynos_drm_manager *manager)
 {
        struct exynos_drm_crtc *exynos_crtc;
+       struct drm_plane *plane;
        struct exynos_drm_private *private = manager->drm_dev->dev_private;
        struct drm_crtc *crtc;
+       int ret;
 
        exynos_crtc = kzalloc(sizeof(*exynos_crtc), GFP_KERNEL);
        if (!exynos_crtc)
@@ -364,11 +354,11 @@ int exynos_drm_crtc_create(struct exynos_drm_manager *manager)
        exynos_crtc->dpms = DRM_MODE_DPMS_OFF;
        exynos_crtc->manager = manager;
        exynos_crtc->pipe = manager->pipe;
-       exynos_crtc->plane = exynos_plane_init(manager->drm_dev,
-                               1 << manager->pipe, true);
-       if (!exynos_crtc->plane) {
-               kfree(exynos_crtc);
-               return -ENOMEM;
+       plane = exynos_plane_init(manager->drm_dev, 1 << manager->pipe,
+                                 DRM_PLANE_TYPE_PRIMARY);
+       if (IS_ERR(plane)) {
+               ret = PTR_ERR(plane);
+               goto err_plane;
        }
 
        manager->crtc = &exynos_crtc->drm_crtc;
@@ -376,12 +366,22 @@ int exynos_drm_crtc_create(struct exynos_drm_manager *manager)
 
        private->crtc[manager->pipe] = crtc;
 
-       drm_crtc_init(manager->drm_dev, crtc, &exynos_crtc_funcs);
+       ret = drm_crtc_init_with_planes(manager->drm_dev, crtc, plane, NULL,
+                                       &exynos_crtc_funcs);
+       if (ret < 0)
+               goto err_crtc;
+
        drm_crtc_helper_add(crtc, &exynos_crtc_helper_funcs);
 
        exynos_drm_crtc_attach_mode_property(crtc);
 
        return 0;
+
+err_crtc:
+       plane->funcs->destroy(plane);
+err_plane:
+       kfree(exynos_crtc);
+       return ret;
 }
 
 int exynos_drm_crtc_enable_vblank(struct drm_device *dev, int pipe)
index fa08f05e3e340be433fd399127bdd821d3b198df..96c87db388fb985614e7d4485b7df569dac40784 100644 (file)
@@ -342,8 +342,12 @@ int exynos_dpi_remove(struct device *dev)
        struct exynos_dpi *ctx = exynos_dpi_display.ctx;
 
        exynos_dpi_dpms(&exynos_dpi_display, DRM_MODE_DPMS_OFF);
+
+       exynos_dpi_connector_destroy(&ctx->connector);
        encoder->funcs->destroy(encoder);
-       drm_connector_cleanup(&ctx->connector);
+
+       if (ctx->panel)
+               drm_panel_detach(ctx->panel);
 
        exynos_drm_component_del(dev, EXYNOS_DEVICE_TYPE_CONNECTOR);
 
index 0d74e9b99c4ec672aa413bf6489cbb3a17898832..443a2069858a7e8589599078802281cc465de709 100644 (file)
@@ -15,7 +15,6 @@
 #include <drm/drmP.h>
 #include <drm/drm_crtc_helper.h>
 
-#include <linux/anon_inodes.h>
 #include <linux/component.h>
 
 #include <drm/exynos_drm.h>
@@ -86,8 +85,9 @@ static int exynos_drm_load(struct drm_device *dev, unsigned long flags)
                struct drm_plane *plane;
                unsigned long possible_crtcs = (1 << MAX_CRTC) - 1;
 
-               plane = exynos_plane_init(dev, possible_crtcs, false);
-               if (!plane)
+               plane = exynos_plane_init(dev, possible_crtcs,
+                                         DRM_PLANE_TYPE_OVERLAY);
+               if (IS_ERR(plane))
                        goto err_mode_config_cleanup;
        }
 
@@ -116,6 +116,23 @@ static int exynos_drm_load(struct drm_device *dev, unsigned long flags)
        /* force connectors detection */
        drm_helper_hpd_irq_event(dev);
 
+       /*
+        * enable drm irq mode.
+        * - with irq_enabled = true, we can use the vblank feature.
+        *
+        * P.S. note that we wouldn't use drm irq handler but
+        *      just specific driver own one instead because
+        *      drm framework supports only one irq handler.
+        */
+       dev->irq_enabled = true;
+
+       /*
+        * with vblank_disable_allowed = true, vblank interrupt will be disabled
+        * by drm timer once a current process gives up ownership of
+        * vblank event.(after drm_vblank_put function is called)
+        */
+       dev->vblank_disable_allowed = true;
+
        return 0;
 
 err_unbind_all:
@@ -136,23 +153,19 @@ static int exynos_drm_unload(struct drm_device *dev)
        exynos_drm_device_subdrv_remove(dev);
 
        exynos_drm_fbdev_fini(dev);
-       drm_vblank_cleanup(dev);
        drm_kms_helper_poll_fini(dev);
-       drm_mode_config_cleanup(dev);
 
+       component_unbind_all(dev->dev, dev);
+       drm_vblank_cleanup(dev);
+       drm_mode_config_cleanup(dev);
        drm_release_iommu_mapping(dev);
-       kfree(dev->dev_private);
 
-       component_unbind_all(dev->dev, dev);
+       kfree(dev->dev_private);
        dev->dev_private = NULL;
 
        return 0;
 }
 
-static const struct file_operations exynos_drm_gem_fops = {
-       .mmap = exynos_drm_gem_mmap_buffer,
-};
-
 static int exynos_drm_suspend(struct drm_device *dev, pm_message_t state)
 {
        struct drm_connector *connector;
@@ -191,7 +204,6 @@ static int exynos_drm_resume(struct drm_device *dev)
 static int exynos_drm_open(struct drm_device *dev, struct drm_file *file)
 {
        struct drm_exynos_file_private *file_priv;
-       struct file *anon_filp;
        int ret;
 
        file_priv = kzalloc(sizeof(*file_priv), GFP_KERNEL);
@@ -204,21 +216,8 @@ static int exynos_drm_open(struct drm_device *dev, struct drm_file *file)
        if (ret)
                goto err_file_priv_free;
 
-       anon_filp = anon_inode_getfile("exynos_gem", &exynos_drm_gem_fops,
-                                       NULL, 0);
-       if (IS_ERR(anon_filp)) {
-               ret = PTR_ERR(anon_filp);
-               goto err_subdrv_close;
-       }
-
-       anon_filp->f_mode = FMODE_READ | FMODE_WRITE;
-       file_priv->anon_filp = anon_filp;
-
        return ret;
 
-err_subdrv_close:
-       exynos_drm_subdrv_close(dev, file);
-
 err_file_priv_free:
        kfree(file_priv);
        file->driver_priv = NULL;
@@ -234,7 +233,6 @@ static void exynos_drm_preclose(struct drm_device *dev,
 static void exynos_drm_postclose(struct drm_device *dev, struct drm_file *file)
 {
        struct exynos_drm_private *private = dev->dev_private;
-       struct drm_exynos_file_private *file_priv;
        struct drm_pending_vblank_event *v, *vt;
        struct drm_pending_event *e, *et;
        unsigned long flags;
@@ -260,10 +258,6 @@ static void exynos_drm_postclose(struct drm_device *dev, struct drm_file *file)
        }
        spin_unlock_irqrestore(&dev->event_lock, flags);
 
-       file_priv = file->driver_priv;
-       if (file_priv->anon_filp)
-               fput(file_priv->anon_filp);
-
        kfree(file->driver_priv);
        file->driver_priv = NULL;
 }
@@ -282,11 +276,6 @@ static const struct vm_operations_struct exynos_drm_gem_vm_ops = {
 static const struct drm_ioctl_desc exynos_ioctls[] = {
        DRM_IOCTL_DEF_DRV(EXYNOS_GEM_CREATE, exynos_drm_gem_create_ioctl,
                        DRM_UNLOCKED | DRM_AUTH),
-       DRM_IOCTL_DEF_DRV(EXYNOS_GEM_MAP_OFFSET,
-                       exynos_drm_gem_map_offset_ioctl, DRM_UNLOCKED |
-                       DRM_AUTH),
-       DRM_IOCTL_DEF_DRV(EXYNOS_GEM_MMAP,
-                       exynos_drm_gem_mmap_ioctl, DRM_UNLOCKED | DRM_AUTH),
        DRM_IOCTL_DEF_DRV(EXYNOS_GEM_GET,
                        exynos_drm_gem_get_ioctl, DRM_UNLOCKED),
        DRM_IOCTL_DEF_DRV(EXYNOS_VIDI_CONNECTION,
@@ -330,6 +319,7 @@ static struct drm_driver exynos_drm_driver = {
        .preclose               = exynos_drm_preclose,
        .lastclose              = exynos_drm_lastclose,
        .postclose              = exynos_drm_postclose,
+       .set_busid              = drm_platform_set_busid,
        .get_vblank_counter     = drm_vblank_count,
        .enable_vblank          = exynos_drm_crtc_enable_vblank,
        .disable_vblank         = exynos_drm_crtc_disable_vblank,
@@ -485,21 +475,20 @@ void exynos_drm_component_del(struct device *dev,
        mutex_unlock(&drm_component_lock);
 }
 
-static int compare_of(struct device *dev, void *data)
+static int compare_dev(struct device *dev, void *data)
 {
        return dev == (struct device *)data;
 }
 
-static int exynos_drm_add_components(struct device *dev, struct master *m)
+static struct component_match *exynos_drm_match_add(struct device *dev)
 {
+       struct component_match *match = NULL;
        struct component_dev *cdev;
        unsigned int attach_cnt = 0;
 
        mutex_lock(&drm_component_lock);
 
        list_for_each_entry(cdev, &drm_component_list, list) {
-               int ret;
-
                /*
                 * Add components to master only in case that crtc and
                 * encoder/connector device objects exist.
@@ -514,16 +503,10 @@ static int exynos_drm_add_components(struct device *dev, struct master *m)
                /*
                 * fimd and dpi modules have same device object so add
                 * only crtc device object in this case.
-                *
-                * TODO. if dpi module follows driver-model driver then
-                * below codes can be removed.
                 */
                if (cdev->crtc_dev == cdev->conn_dev) {
-                       ret = component_master_add_child(m, compare_of,
-                                       cdev->crtc_dev);
-                       if (ret < 0)
-                               return ret;
-
+                       component_match_add(dev, &match, compare_dev,
+                                               cdev->crtc_dev);
                        goto out_lock;
                }
 
@@ -533,11 +516,8 @@ static int exynos_drm_add_components(struct device *dev, struct master *m)
                 * connector/encoder need pipe number of crtc when they
                 * are created.
                 */
-               ret = component_master_add_child(m, compare_of, cdev->crtc_dev);
-               ret |= component_master_add_child(m, compare_of,
-                                                       cdev->conn_dev);
-               if (ret < 0)
-                       return ret;
+               component_match_add(dev, &match, compare_dev, cdev->crtc_dev);
+               component_match_add(dev, &match, compare_dev, cdev->conn_dev);
 
 out_lock:
                mutex_lock(&drm_component_lock);
@@ -545,7 +525,7 @@ out_lock:
 
        mutex_unlock(&drm_component_lock);
 
-       return attach_cnt ? 0 : -ENODEV;
+       return attach_cnt ? match : ERR_PTR(-EPROBE_DEFER);
 }
 
 static int exynos_drm_bind(struct device *dev)
@@ -559,13 +539,13 @@ static void exynos_drm_unbind(struct device *dev)
 }
 
 static const struct component_master_ops exynos_drm_ops = {
-       .add_components = exynos_drm_add_components,
        .bind           = exynos_drm_bind,
        .unbind         = exynos_drm_unbind,
 };
 
 static int exynos_drm_platform_probe(struct platform_device *pdev)
 {
+       struct component_match *match;
        int ret;
 
        pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
@@ -632,13 +612,23 @@ static int exynos_drm_platform_probe(struct platform_device *pdev)
                goto err_unregister_ipp_drv;
 #endif
 
-       ret = component_master_add(&pdev->dev, &exynos_drm_ops);
+       match = exynos_drm_match_add(&pdev->dev);
+       if (IS_ERR(match)) {
+               ret = PTR_ERR(match);
+               goto err_unregister_resources;
+       }
+
+       ret = component_master_add_with_match(&pdev->dev, &exynos_drm_ops,
+                                               match);
        if (ret < 0)
-               DRM_DEBUG_KMS("re-tried by last sub driver probed later.\n");
+               goto err_unregister_resources;
 
-       return 0;
+       return ret;
+
+err_unregister_resources:
 
 #ifdef CONFIG_DRM_EXYNOS_IPP
+       exynos_platform_device_ipp_unregister();
 err_unregister_ipp_drv:
        platform_driver_unregister(&ipp_driver);
 err_unregister_gsc_drv:
index 69a6fa397d75b604174810f71a5aa0304789ac9b..d22e640f59a012c0b2e26d3d325c3a6154ec26c5 100644 (file)
@@ -240,7 +240,6 @@ struct exynos_drm_g2d_private {
 struct drm_exynos_file_private {
        struct exynos_drm_g2d_private   *g2d_priv;
        struct device                   *ipp_dev;
-       struct file                     *anon_filp;
 };
 
 /*
index 442aa2d0013217b500ebddad0ef63429f6dd1e00..24741d8758e88521439f82309b656c35afa83785 100644 (file)
 #define DSIM_SYNC_INFORM               (1 << 27)
 #define DSIM_EOT_DISABLE               (1 << 28)
 #define DSIM_MFLUSH_VS                 (1 << 29)
+/* This flag is valid only for exynos3250/3472/4415/5260/5430 */
+#define DSIM_CLKLANE_STOP              (1 << 30)
 
 /* DSIM_ESCMODE */
 #define DSIM_TX_TRIGGER_RST            (1 << 4)
@@ -262,6 +264,7 @@ struct exynos_dsi_driver_data {
        unsigned int plltmr_reg;
 
        unsigned int has_freqband:1;
+       unsigned int has_clklane_stop:1;
 };
 
 struct exynos_dsi {
@@ -301,9 +304,16 @@ struct exynos_dsi {
 #define host_to_dsi(host) container_of(host, struct exynos_dsi, dsi_host)
 #define connector_to_dsi(c) container_of(c, struct exynos_dsi, connector)
 
+static struct exynos_dsi_driver_data exynos3_dsi_driver_data = {
+       .plltmr_reg = 0x50,
+       .has_freqband = 1,
+       .has_clklane_stop = 1,
+};
+
 static struct exynos_dsi_driver_data exynos4_dsi_driver_data = {
        .plltmr_reg = 0x50,
        .has_freqband = 1,
+       .has_clklane_stop = 1,
 };
 
 static struct exynos_dsi_driver_data exynos5_dsi_driver_data = {
@@ -311,6 +321,8 @@ static struct exynos_dsi_driver_data exynos5_dsi_driver_data = {
 };
 
 static struct of_device_id exynos_dsi_of_match[] = {
+       { .compatible = "samsung,exynos3250-mipi-dsi",
+         .data = &exynos3_dsi_driver_data },
        { .compatible = "samsung,exynos4210-mipi-dsi",
          .data = &exynos4_dsi_driver_data },
        { .compatible = "samsung,exynos5410-mipi-dsi",
@@ -421,7 +433,7 @@ static unsigned long exynos_dsi_set_pll(struct exynos_dsi *dsi,
        if (!fout) {
                dev_err(dsi->dev,
                        "failed to find PLL PMS for requested frequency\n");
-               return -EFAULT;
+               return 0;
        }
        dev_dbg(dsi->dev, "PLL freq %lu, (p %d, m %d, s %d)\n", fout, p, m, s);
 
@@ -453,7 +465,7 @@ static unsigned long exynos_dsi_set_pll(struct exynos_dsi *dsi,
        do {
                if (timeout-- == 0) {
                        dev_err(dsi->dev, "PLL failed to stabilize\n");
-                       return -EFAULT;
+                       return 0;
                }
                reg = readl(dsi->reg_base + DSIM_STATUS_REG);
        } while ((reg & DSIM_PLL_STABLE) == 0);
@@ -569,6 +581,7 @@ static void exynos_dsi_disable_clock(struct exynos_dsi *dsi)
 
 static int exynos_dsi_init_link(struct exynos_dsi *dsi)
 {
+       struct exynos_dsi_driver_data *driver_data = dsi->driver_data;
        int timeout;
        u32 reg;
        u32 lanes_mask;
@@ -650,6 +663,20 @@ static int exynos_dsi_init_link(struct exynos_dsi *dsi)
        reg |= DSIM_LANE_EN(lanes_mask);
        writel(reg, dsi->reg_base + DSIM_CONFIG_REG);
 
+       /*
+        * Use non-continuous clock mode if the periparal wants and
+        * host controller supports
+        *
+        * In non-continous clock mode, host controller will turn off
+        * the HS clock between high-speed transmissions to reduce
+        * power consumption.
+        */
+       if (driver_data->has_clklane_stop &&
+                       dsi->mode_flags & MIPI_DSI_CLOCK_NON_CONTINUOUS) {
+               reg |= DSIM_CLKLANE_STOP;
+               writel(reg, dsi->reg_base + DSIM_CONFIG_REG);
+       }
+
        /* Check clock and data lane state are stop state */
        timeout = 100;
        do {
@@ -1414,6 +1441,9 @@ exynos_dsi_detect(struct drm_connector *connector, bool force)
 
 static void exynos_dsi_connector_destroy(struct drm_connector *connector)
 {
+       drm_connector_unregister(connector);
+       drm_connector_cleanup(connector);
+       connector->dev = NULL;
 }
 
 static struct drm_connector_funcs exynos_dsi_connector_funcs = {
@@ -1634,10 +1664,10 @@ static void exynos_dsi_unbind(struct device *dev, struct device *master,
 
        exynos_dsi_dpms(&exynos_dsi_display, DRM_MODE_DPMS_OFF);
 
-       mipi_dsi_host_unregister(&dsi->dsi_host);
-
+       exynos_dsi_connector_destroy(&dsi->connector);
        encoder->funcs->destroy(encoder);
-       drm_connector_cleanup(&dsi->connector);
+
+       mipi_dsi_host_unregister(&dsi->dsi_host);
 }
 
 static const struct component_ops exynos_dsi_component_ops = {
index 65a22cad7b36300811abf39b3a0d13020a479cc0..d346d1e6eda03775e63d6ad7f969a1e1a9f4431d 100644 (file)
@@ -165,6 +165,7 @@ exynos_drm_framebuffer_init(struct drm_device *dev,
 
        ret = drm_framebuffer_init(dev, &exynos_fb->fb, &exynos_drm_fb_funcs);
        if (ret) {
+               kfree(exynos_fb);
                DRM_ERROR("failed to initialize framebuffer\n");
                return ERR_PTR(ret);
        }
index 32e63f60e1d15a14deef0d11365201e2476e5d3c..e12ea90c62371e6212fba19623c1b2034545c2f4 100644 (file)
@@ -123,6 +123,7 @@ static int exynos_drm_fbdev_update(struct drm_fb_helper *helper,
 
        fbi->screen_base = buffer->kvaddr + offset;
        fbi->screen_size = size;
+       fbi->fix.smem_len = size;
 
        return 0;
 }
@@ -353,9 +354,6 @@ void exynos_drm_fbdev_fini(struct drm_device *dev)
 
        fbdev = to_exynos_fbdev(private->fb_helper);
 
-       if (fbdev->exynos_gem_obj)
-               exynos_drm_gem_destroy(fbdev->exynos_gem_obj);
-
        exynos_drm_fbdev_destroy(dev, private->fb_helper);
        kfree(fbdev);
        private->fb_helper = NULL;
index ec7cc9ea50df692db90293319a3f8fe2465d5107..68d38eb6774d5bb07ad2b12b0e78a6eb40dd32cd 100644 (file)
@@ -336,9 +336,6 @@ static bool fimc_check_ovf(struct fimc_context *ctx)
                fimc_set_bits(ctx, EXYNOS_CIWDOFST,
                        EXYNOS_CIWDOFST_CLROVFIY | EXYNOS_CIWDOFST_CLROVFICB |
                        EXYNOS_CIWDOFST_CLROVFICR);
-               fimc_clear_bits(ctx, EXYNOS_CIWDOFST,
-                       EXYNOS_CIWDOFST_CLROVFIY | EXYNOS_CIWDOFST_CLROVFICB |
-                       EXYNOS_CIWDOFST_CLROVFICR);
 
                dev_err(ippdrv->dev, "occurred overflow at %d, status 0x%x.\n",
                        ctx->id, status);
@@ -718,24 +715,24 @@ static int fimc_src_set_addr(struct device *dev,
        case IPP_BUF_ENQUEUE:
                config = &property->config[EXYNOS_DRM_OPS_SRC];
                fimc_write(ctx, buf_info->base[EXYNOS_DRM_PLANAR_Y],
-                       EXYNOS_CIIYSA(buf_id));
+                       EXYNOS_CIIYSA0);
 
                if (config->fmt == DRM_FORMAT_YVU420) {
                        fimc_write(ctx, buf_info->base[EXYNOS_DRM_PLANAR_CR],
-                               EXYNOS_CIICBSA(buf_id));
+                               EXYNOS_CIICBSA0);
                        fimc_write(ctx, buf_info->base[EXYNOS_DRM_PLANAR_CB],
-                               EXYNOS_CIICRSA(buf_id));
+                               EXYNOS_CIICRSA0);
                } else {
                        fimc_write(ctx, buf_info->base[EXYNOS_DRM_PLANAR_CB],
-                               EXYNOS_CIICBSA(buf_id));
+                               EXYNOS_CIICBSA0);
                        fimc_write(ctx, buf_info->base[EXYNOS_DRM_PLANAR_CR],
-                               EXYNOS_CIICRSA(buf_id));
+                               EXYNOS_CIICRSA0);
                }
                break;
        case IPP_BUF_DEQUEUE:
-               fimc_write(ctx, 0x0, EXYNOS_CIIYSA(buf_id));
-               fimc_write(ctx, 0x0, EXYNOS_CIICBSA(buf_id));
-               fimc_write(ctx, 0x0, EXYNOS_CIICRSA(buf_id));
+               fimc_write(ctx, 0x0, EXYNOS_CIIYSA0);
+               fimc_write(ctx, 0x0, EXYNOS_CIICBSA0);
+               fimc_write(ctx, 0x0, EXYNOS_CIICRSA0);
                break;
        default:
                /* bypass */
@@ -1122,67 +1119,34 @@ static int fimc_dst_set_size(struct device *dev, int swap,
        return 0;
 }
 
-static int fimc_dst_get_buf_count(struct fimc_context *ctx)
-{
-       u32 cfg, buf_num;
-
-       cfg = fimc_read(ctx, EXYNOS_CIFCNTSEQ);
-
-       buf_num = hweight32(cfg);
-
-       DRM_DEBUG_KMS("buf_num[%d]\n", buf_num);
-
-       return buf_num;
-}
-
-static int fimc_dst_set_buf_seq(struct fimc_context *ctx, u32 buf_id,
+static void fimc_dst_set_buf_seq(struct fimc_context *ctx, u32 buf_id,
                enum drm_exynos_ipp_buf_type buf_type)
 {
-       struct exynos_drm_ippdrv *ippdrv = &ctx->ippdrv;
-       bool enable;
-       u32 cfg;
-       u32 mask = 0x00000001 << buf_id;
-       int ret = 0;
        unsigned long flags;
+       u32 buf_num;
+       u32 cfg;
 
        DRM_DEBUG_KMS("buf_id[%d]buf_type[%d]\n", buf_id, buf_type);
 
        spin_lock_irqsave(&ctx->lock, flags);
 
-       /* mask register set */
        cfg = fimc_read(ctx, EXYNOS_CIFCNTSEQ);
 
-       switch (buf_type) {
-       case IPP_BUF_ENQUEUE:
-               enable = true;
-               break;
-       case IPP_BUF_DEQUEUE:
-               enable = false;
-               break;
-       default:
-               dev_err(ippdrv->dev, "invalid buf ctrl parameter.\n");
-               ret =  -EINVAL;
-               goto err_unlock;
-       }
+       if (buf_type == IPP_BUF_ENQUEUE)
+               cfg |= (1 << buf_id);
+       else
+               cfg &= ~(1 << buf_id);
 
-       /* sequence id */
-       cfg &= ~mask;
-       cfg |= (enable << buf_id);
        fimc_write(ctx, cfg, EXYNOS_CIFCNTSEQ);
 
-       /* interrupt enable */
-       if (buf_type == IPP_BUF_ENQUEUE &&
-           fimc_dst_get_buf_count(ctx) >= FIMC_BUF_START)
-               fimc_mask_irq(ctx, true);
+       buf_num = hweight32(cfg);
 
-       /* interrupt disable */
-       if (buf_type == IPP_BUF_DEQUEUE &&
-           fimc_dst_get_buf_count(ctx) <= FIMC_BUF_STOP)
+       if (buf_type == IPP_BUF_ENQUEUE && buf_num >= FIMC_BUF_START)
+               fimc_mask_irq(ctx, true);
+       else if (buf_type == IPP_BUF_DEQUEUE && buf_num <= FIMC_BUF_STOP)
                fimc_mask_irq(ctx, false);
 
-err_unlock:
        spin_unlock_irqrestore(&ctx->lock, flags);
-       return ret;
 }
 
 static int fimc_dst_set_addr(struct device *dev,
@@ -1240,7 +1204,9 @@ static int fimc_dst_set_addr(struct device *dev,
                break;
        }
 
-       return fimc_dst_set_buf_seq(ctx, buf_id, buf_type);
+       fimc_dst_set_buf_seq(ctx, buf_id, buf_type);
+
+       return 0;
 }
 
 static struct exynos_drm_ipp_ops fimc_dst_ops = {
@@ -1291,14 +1257,11 @@ static irqreturn_t fimc_irq_handler(int irq, void *dev_id)
 
        DRM_DEBUG_KMS("buf_id[%d]\n", buf_id);
 
-       if (fimc_dst_set_buf_seq(ctx, buf_id, IPP_BUF_DEQUEUE) < 0) {
-               DRM_ERROR("failed to dequeue.\n");
-               return IRQ_HANDLED;
-       }
+       fimc_dst_set_buf_seq(ctx, buf_id, IPP_BUF_DEQUEUE);
 
        event_work->ippdrv = ippdrv;
        event_work->buf_id[EXYNOS_DRM_OPS_DST] = buf_id;
-       queue_work(ippdrv->event_workq, (struct work_struct *)event_work);
+       queue_work(ippdrv->event_workq, &event_work->work);
 
        return IRQ_HANDLED;
 }
@@ -1590,11 +1553,8 @@ static int fimc_ippdrv_start(struct device *dev, enum drm_exynos_ipp_cmd cmd)
 
        fimc_clear_bits(ctx, EXYNOS_CIOCTRL, EXYNOS_CIOCTRL_WEAVE_MASK);
 
-       if (cmd == IPP_CMD_M2M) {
-               fimc_set_bits(ctx, EXYNOS_MSCTRL, EXYNOS_MSCTRL_ENVID);
-
+       if (cmd == IPP_CMD_M2M)
                fimc_set_bits(ctx, EXYNOS_MSCTRL, EXYNOS_MSCTRL_ENVID);
-       }
 
        return 0;
 }
index 5d09e33fef8716084a169bee2afb63e429187b48..085b066a99934116963b0aa3a1fe6d4a136387c2 100644 (file)
@@ -104,6 +104,14 @@ static struct fimd_driver_data s3c64xx_fimd_driver_data = {
        .has_limited_fmt = 1,
 };
 
+static struct fimd_driver_data exynos3_fimd_driver_data = {
+       .timing_base = 0x20000,
+       .lcdblk_offset = 0x210,
+       .lcdblk_bypass_shift = 1,
+       .has_shadowcon = 1,
+       .has_vidoutcon = 1,
+};
+
 static struct fimd_driver_data exynos4_fimd_driver_data = {
        .timing_base = 0x0,
        .lcdblk_offset = 0x210,
@@ -168,6 +176,8 @@ struct fimd_context {
 static const struct of_device_id fimd_driver_dt_match[] = {
        { .compatible = "samsung,s3c6400-fimd",
          .data = &s3c64xx_fimd_driver_data },
+       { .compatible = "samsung,exynos3250-fimd",
+         .data = &exynos3_fimd_driver_data },
        { .compatible = "samsung,exynos4210-fimd",
          .data = &exynos4_fimd_driver_data },
        { .compatible = "samsung,exynos5250-fimd",
@@ -204,7 +214,6 @@ static void fimd_wait_for_vblank(struct exynos_drm_manager *mgr)
                DRM_DEBUG_KMS("vblank wait timed out.\n");
 }
 
-
 static void fimd_clear_channel(struct exynos_drm_manager *mgr)
 {
        struct fimd_context *ctx = mgr->ctx;
@@ -214,17 +223,31 @@ static void fimd_clear_channel(struct exynos_drm_manager *mgr)
 
        /* Check if any channel is enabled. */
        for (win = 0; win < WINDOWS_NR; win++) {
-               u32 val = readl(ctx->regs + SHADOWCON);
-               if (val & SHADOWCON_CHx_ENABLE(win)) {
-                       val &= ~SHADOWCON_CHx_ENABLE(win);
-                       writel(val, ctx->regs + SHADOWCON);
+               u32 val = readl(ctx->regs + WINCON(win));
+
+               if (val & WINCONx_ENWIN) {
+                       /* wincon */
+                       val &= ~WINCONx_ENWIN;
+                       writel(val, ctx->regs + WINCON(win));
+
+                       /* unprotect windows */
+                       if (ctx->driver_data->has_shadowcon) {
+                               val = readl(ctx->regs + SHADOWCON);
+                               val &= ~SHADOWCON_CHx_ENABLE(win);
+                               writel(val, ctx->regs + SHADOWCON);
+                       }
                        ch_enabled = 1;
                }
        }
 
        /* Wait for vsync, as disable channel takes effect at next vsync */
-       if (ch_enabled)
+       if (ch_enabled) {
+               unsigned int state = ctx->suspended;
+
+               ctx->suspended = 0;
                fimd_wait_for_vblank(mgr);
+               ctx->suspended = state;
+       }
 }
 
 static int fimd_mgr_initialize(struct exynos_drm_manager *mgr,
@@ -237,23 +260,6 @@ static int fimd_mgr_initialize(struct exynos_drm_manager *mgr,
        mgr->drm_dev = ctx->drm_dev = drm_dev;
        mgr->pipe = ctx->pipe = priv->pipe++;
 
-       /*
-        * enable drm irq mode.
-        * - with irq_enabled = true, we can use the vblank feature.
-        *
-        * P.S. note that we wouldn't use drm irq handler but
-        *      just specific driver own one instead because
-        *      drm framework supports only one irq handler.
-        */
-       drm_dev->irq_enabled = true;
-
-       /*
-        * with vblank_disable_allowed = true, vblank interrupt will be disabled
-        * by drm timer once a current process gives up ownership of
-        * vblank event.(after drm_vblank_put function is called)
-        */
-       drm_dev->vblank_disable_allowed = true;
-
        /* attach this sub driver to iommu mapping if supported. */
        if (is_drm_iommu_supported(ctx->drm_dev)) {
                /*
@@ -1051,7 +1057,6 @@ static void fimd_unbind(struct device *dev, struct device *master,
 {
        struct exynos_drm_manager *mgr = dev_get_drvdata(dev);
        struct fimd_context *ctx = fimd_manager.ctx;
-       struct drm_crtc *crtc = mgr->crtc;
 
        fimd_dpms(mgr, DRM_MODE_DPMS_OFF);
 
@@ -1059,8 +1064,6 @@ static void fimd_unbind(struct device *dev, struct device *master,
                exynos_dpi_remove(dev);
 
        fimd_mgr_remove(mgr);
-
-       crtc->funcs->destroy(crtc);
 }
 
 static const struct component_ops fimd_component_ops = {
index 15db80138382f7d7fd58875663f0448f1312b284..0d5b9698d38402d912304b3915e95e37bd207978 100644 (file)
@@ -318,40 +318,16 @@ void exynos_drm_gem_put_dma_addr(struct drm_device *dev,
        drm_gem_object_unreference_unlocked(obj);
 }
 
-int exynos_drm_gem_map_offset_ioctl(struct drm_device *dev, void *data,
-                                   struct drm_file *file_priv)
-{
-       struct drm_exynos_gem_map_off *args = data;
-
-       DRM_DEBUG_KMS("handle = 0x%x, offset = 0x%lx\n",
-                       args->handle, (unsigned long)args->offset);
-
-       if (!(dev->driver->driver_features & DRIVER_GEM)) {
-               DRM_ERROR("does not support GEM.\n");
-               return -ENODEV;
-       }
-
-       return exynos_drm_gem_dumb_map_offset(file_priv, dev, args->handle,
-                       &args->offset);
-}
-
-int exynos_drm_gem_mmap_buffer(struct file *filp,
+int exynos_drm_gem_mmap_buffer(struct exynos_drm_gem_obj *exynos_gem_obj,
                                      struct vm_area_struct *vma)
 {
-       struct drm_gem_object *obj = filp->private_data;
-       struct exynos_drm_gem_obj *exynos_gem_obj = to_exynos_gem_obj(obj);
-       struct drm_device *drm_dev = obj->dev;
+       struct drm_device *drm_dev = exynos_gem_obj->base.dev;
        struct exynos_drm_gem_buf *buffer;
        unsigned long vm_size;
        int ret;
 
-       WARN_ON(!mutex_is_locked(&obj->dev->struct_mutex));
-
-       vma->vm_flags |= VM_IO | VM_DONTEXPAND | VM_DONTDUMP;
-       vma->vm_private_data = obj;
-       vma->vm_ops = drm_dev->driver->gem_vm_ops;
-
-       update_vm_cache_attr(exynos_gem_obj, vma);
+       vma->vm_flags &= ~VM_PFNMAP;
+       vma->vm_pgoff = 0;
 
        vm_size = vma->vm_end - vma->vm_start;
 
@@ -373,60 +349,6 @@ int exynos_drm_gem_mmap_buffer(struct file *filp,
                return ret;
        }
 
-       /*
-        * take a reference to this mapping of the object. And this reference
-        * is unreferenced by the corresponding vm_close call.
-        */
-       drm_gem_object_reference(obj);
-
-       drm_vm_open_locked(drm_dev, vma);
-
-       return 0;
-}
-
-int exynos_drm_gem_mmap_ioctl(struct drm_device *dev, void *data,
-                             struct drm_file *file_priv)
-{
-       struct drm_exynos_file_private *exynos_file_priv;
-       struct drm_exynos_gem_mmap *args = data;
-       struct drm_gem_object *obj;
-       struct file *anon_filp;
-       unsigned long addr;
-
-       if (!(dev->driver->driver_features & DRIVER_GEM)) {
-               DRM_ERROR("does not support GEM.\n");
-               return -ENODEV;
-       }
-
-       mutex_lock(&dev->struct_mutex);
-
-       obj = drm_gem_object_lookup(dev, file_priv, args->handle);
-       if (!obj) {
-               DRM_ERROR("failed to lookup gem object.\n");
-               mutex_unlock(&dev->struct_mutex);
-               return -EINVAL;
-       }
-
-       exynos_file_priv = file_priv->driver_priv;
-       anon_filp = exynos_file_priv->anon_filp;
-       anon_filp->private_data = obj;
-
-       addr = vm_mmap(anon_filp, 0, args->size, PROT_READ | PROT_WRITE,
-                       MAP_SHARED, 0);
-
-       drm_gem_object_unreference(obj);
-
-       if (IS_ERR_VALUE(addr)) {
-               mutex_unlock(&dev->struct_mutex);
-               return (int)addr;
-       }
-
-       mutex_unlock(&dev->struct_mutex);
-
-       args->mapped = addr;
-
-       DRM_DEBUG_KMS("mapped = 0x%lx\n", (unsigned long)args->mapped);
-
        return 0;
 }
 
@@ -710,16 +632,20 @@ int exynos_drm_gem_mmap(struct file *filp, struct vm_area_struct *vma)
        exynos_gem_obj = to_exynos_gem_obj(obj);
 
        ret = check_gem_flags(exynos_gem_obj->flags);
-       if (ret) {
-               drm_gem_vm_close(vma);
-               drm_gem_free_mmap_offset(obj);
-               return ret;
-       }
-
-       vma->vm_flags &= ~VM_PFNMAP;
-       vma->vm_flags |= VM_MIXEDMAP;
+       if (ret)
+               goto err_close_vm;
 
        update_vm_cache_attr(exynos_gem_obj, vma);
 
+       ret = exynos_drm_gem_mmap_buffer(exynos_gem_obj, vma);
+       if (ret)
+               goto err_close_vm;
+
+       return ret;
+
+err_close_vm:
+       drm_gem_vm_close(vma);
+       drm_gem_free_mmap_offset(obj);
+
        return ret;
 }
index 1592c0ba7de86b596f2000d5bb3f780fa17ca33e..ec58fe9c40df5814da0e10ebc95d6186bf6fbb2e 100644 (file)
@@ -12,6 +12,8 @@
 #ifndef _EXYNOS_DRM_GEM_H_
 #define _EXYNOS_DRM_GEM_H_
 
+#include <drm/drm_gem.h>
+
 #define to_exynos_gem_obj(x)   container_of(x,\
                        struct exynos_drm_gem_obj, base)
 
@@ -111,20 +113,6 @@ void exynos_drm_gem_put_dma_addr(struct drm_device *dev,
                                        unsigned int gem_handle,
                                        struct drm_file *filp);
 
-/* get buffer offset to map to user space. */
-int exynos_drm_gem_map_offset_ioctl(struct drm_device *dev, void *data,
-                                   struct drm_file *file_priv);
-
-/*
- * mmap the physically continuous memory that a gem object contains
- * to user space.
- */
-int exynos_drm_gem_mmap_ioctl(struct drm_device *dev, void *data,
-                             struct drm_file *file_priv);
-
-int exynos_drm_gem_mmap_buffer(struct file *filp,
-                                     struct vm_area_struct *vma);
-
 /* map user space allocated by malloc to pages. */
 int exynos_drm_gem_userptr_ioctl(struct drm_device *dev, void *data,
                                      struct drm_file *file_priv);
index 9e3ff1672965d3e17044d0e59fa524193404ff02..c6a013fc321cf13d9ce8b8f1a7403beb758e86e4 100644 (file)
@@ -1326,8 +1326,7 @@ static irqreturn_t gsc_irq_handler(int irq, void *dev_id)
                        buf_id[EXYNOS_DRM_OPS_SRC];
                event_work->buf_id[EXYNOS_DRM_OPS_DST] =
                        buf_id[EXYNOS_DRM_OPS_DST];
-               queue_work(ippdrv->event_workq,
-                       (struct work_struct *)event_work);
+               queue_work(ippdrv->event_workq, &event_work->work);
        }
 
        return IRQ_HANDLED;
index c411399070d671d1d79075230280dbf22949c267..00d74b18f7cbd841f88d252d57ca47eb5d768863 100644 (file)
@@ -75,7 +75,6 @@ struct drm_exynos_ipp_mem_node {
        u32     prop_id;
        u32     buf_id;
        struct drm_exynos_ipp_buf_info  buf_info;
-       struct drm_file         *filp;
 };
 
 /*
@@ -319,44 +318,6 @@ static void ipp_print_property(struct drm_exynos_ipp_property *property,
                sz->hsize, sz->vsize, config->flip, config->degree);
 }
 
-static int ipp_find_and_set_property(struct drm_exynos_ipp_property *property)
-{
-       struct exynos_drm_ippdrv *ippdrv;
-       struct drm_exynos_ipp_cmd_node *c_node;
-       u32 prop_id = property->prop_id;
-
-       DRM_DEBUG_KMS("prop_id[%d]\n", prop_id);
-
-       ippdrv = ipp_find_drv_by_handle(prop_id);
-       if (IS_ERR(ippdrv)) {
-               DRM_ERROR("failed to get ipp driver.\n");
-               return -EINVAL;
-       }
-
-       /*
-        * Find command node using command list in ippdrv.
-        * when we find this command no using prop_id.
-        * return property information set in this command node.
-        */
-       mutex_lock(&ippdrv->cmd_lock);
-       list_for_each_entry(c_node, &ippdrv->cmd_list, list) {
-               if ((c_node->property.prop_id == prop_id) &&
-                   (c_node->state == IPP_STATE_STOP)) {
-                       mutex_unlock(&ippdrv->cmd_lock);
-                       DRM_DEBUG_KMS("found cmd[%d]ippdrv[0x%x]\n",
-                               property->cmd, (int)ippdrv);
-
-                       c_node->property = *property;
-                       return 0;
-               }
-       }
-       mutex_unlock(&ippdrv->cmd_lock);
-
-       DRM_ERROR("failed to search property.\n");
-
-       return -EINVAL;
-}
-
 static struct drm_exynos_ipp_cmd_work *ipp_create_cmd_work(void)
 {
        struct drm_exynos_ipp_cmd_work *cmd_work;
@@ -392,6 +353,7 @@ int exynos_drm_ipp_set_property(struct drm_device *drm_dev, void *data,
        struct drm_exynos_ipp_property *property = data;
        struct exynos_drm_ippdrv *ippdrv;
        struct drm_exynos_ipp_cmd_node *c_node;
+       u32 prop_id;
        int ret, i;
 
        if (!ctx) {
@@ -404,6 +366,8 @@ int exynos_drm_ipp_set_property(struct drm_device *drm_dev, void *data,
                return -EINVAL;
        }
 
+       prop_id = property->prop_id;
+
        /*
         * This is log print for user application property.
         * user application set various property.
@@ -412,14 +376,24 @@ int exynos_drm_ipp_set_property(struct drm_device *drm_dev, void *data,
                ipp_print_property(property, i);
 
        /*
-        * set property ioctl generated new prop_id.
-        * but in this case already asigned prop_id using old set property.
-        * e.g PAUSE state. this case supports find current prop_id and use it
-        * instead of allocation.
+        * In case prop_id is not zero try to set existing property.
         */
-       if (property->prop_id) {
-               DRM_DEBUG_KMS("prop_id[%d]\n", property->prop_id);
-               return ipp_find_and_set_property(property);
+       if (prop_id) {
+               c_node = ipp_find_obj(&ctx->prop_idr, &ctx->prop_lock, prop_id);
+
+               if (!c_node || c_node->filp != file) {
+                       DRM_DEBUG_KMS("prop_id[%d] not found\n", prop_id);
+                       return -EINVAL;
+               }
+
+               if (c_node->state != IPP_STATE_STOP) {
+                       DRM_DEBUG_KMS("prop_id[%d] not stopped\n", prop_id);
+                       return -EINVAL;
+               }
+
+               c_node->property = *property;
+
+               return 0;
        }
 
        /* find ipp driver using ipp id */
@@ -445,9 +419,9 @@ int exynos_drm_ipp_set_property(struct drm_device *drm_dev, void *data,
                property->prop_id, property->cmd, (int)ippdrv);
 
        /* stored property information and ippdrv in private data */
-       c_node->dev = dev;
        c_node->property = *property;
        c_node->state = IPP_STATE_IDLE;
+       c_node->filp = file;
 
        c_node->start_work = ipp_create_cmd_work();
        if (IS_ERR(c_node->start_work)) {
@@ -499,105 +473,37 @@ err_clear:
        return ret;
 }
 
-static void ipp_clean_cmd_node(struct ipp_context *ctx,
-                               struct drm_exynos_ipp_cmd_node *c_node)
-{
-       /* delete list */
-       list_del(&c_node->list);
-
-       ipp_remove_id(&ctx->prop_idr, &ctx->prop_lock,
-                       c_node->property.prop_id);
-
-       /* destroy mutex */
-       mutex_destroy(&c_node->lock);
-       mutex_destroy(&c_node->mem_lock);
-       mutex_destroy(&c_node->event_lock);
-
-       /* free command node */
-       kfree(c_node->start_work);
-       kfree(c_node->stop_work);
-       kfree(c_node->event_work);
-       kfree(c_node);
-}
-
-static bool ipp_check_mem_list(struct drm_exynos_ipp_cmd_node *c_node)
-{
-       switch (c_node->property.cmd) {
-       case IPP_CMD_WB:
-               return !list_empty(&c_node->mem_list[EXYNOS_DRM_OPS_DST]);
-       case IPP_CMD_OUTPUT:
-               return !list_empty(&c_node->mem_list[EXYNOS_DRM_OPS_SRC]);
-       case IPP_CMD_M2M:
-       default:
-               return !list_empty(&c_node->mem_list[EXYNOS_DRM_OPS_SRC]) &&
-                      !list_empty(&c_node->mem_list[EXYNOS_DRM_OPS_DST]);
-       }
-}
-
-static struct drm_exynos_ipp_mem_node
-               *ipp_find_mem_node(struct drm_exynos_ipp_cmd_node *c_node,
-               struct drm_exynos_ipp_queue_buf *qbuf)
-{
-       struct drm_exynos_ipp_mem_node *m_node;
-       struct list_head *head;
-       int count = 0;
-
-       DRM_DEBUG_KMS("buf_id[%d]\n", qbuf->buf_id);
-
-       /* source/destination memory list */
-       head = &c_node->mem_list[qbuf->ops_id];
-
-       /* find memory node from memory list */
-       list_for_each_entry(m_node, head, list) {
-               DRM_DEBUG_KMS("count[%d]m_node[0x%x]\n", count++, (int)m_node);
-
-               /* compare buffer id */
-               if (m_node->buf_id == qbuf->buf_id)
-                       return m_node;
-       }
-
-       return NULL;
-}
-
-static int ipp_set_mem_node(struct exynos_drm_ippdrv *ippdrv,
+static int ipp_put_mem_node(struct drm_device *drm_dev,
                struct drm_exynos_ipp_cmd_node *c_node,
                struct drm_exynos_ipp_mem_node *m_node)
 {
-       struct exynos_drm_ipp_ops *ops = NULL;
-       int ret = 0;
+       int i;
 
        DRM_DEBUG_KMS("node[0x%x]\n", (int)m_node);
 
        if (!m_node) {
-               DRM_ERROR("invalid queue node.\n");
+               DRM_ERROR("invalid dequeue node.\n");
                return -EFAULT;
        }
 
        DRM_DEBUG_KMS("ops_id[%d]\n", m_node->ops_id);
 
-       /* get operations callback */
-       ops = ippdrv->ops[m_node->ops_id];
-       if (!ops) {
-               DRM_ERROR("not support ops.\n");
-               return -EFAULT;
+       /* put gem buffer */
+       for_each_ipp_planar(i) {
+               unsigned long handle = m_node->buf_info.handles[i];
+               if (handle)
+                       exynos_drm_gem_put_dma_addr(drm_dev, handle,
+                                                       c_node->filp);
        }
 
-       /* set address and enable irq */
-       if (ops->set_addr) {
-               ret = ops->set_addr(ippdrv->dev, &m_node->buf_info,
-                       m_node->buf_id, IPP_BUF_ENQUEUE);
-               if (ret) {
-                       DRM_ERROR("failed to set addr.\n");
-                       return ret;
-               }
-       }
+       list_del(&m_node->list);
+       kfree(m_node);
 
-       return ret;
+       return 0;
 }
 
 static struct drm_exynos_ipp_mem_node
                *ipp_get_mem_node(struct drm_device *drm_dev,
-               struct drm_file *file,
                struct drm_exynos_ipp_cmd_node *c_node,
                struct drm_exynos_ipp_queue_buf *qbuf)
 {
@@ -615,6 +521,7 @@ static struct drm_exynos_ipp_mem_node
        m_node->ops_id = qbuf->ops_id;
        m_node->prop_id = qbuf->prop_id;
        m_node->buf_id = qbuf->buf_id;
+       INIT_LIST_HEAD(&m_node->list);
 
        DRM_DEBUG_KMS("m_node[0x%x]ops_id[%d]\n", (int)m_node, qbuf->ops_id);
        DRM_DEBUG_KMS("prop_id[%d]buf_id[%d]\n", qbuf->prop_id, m_node->buf_id);
@@ -627,10 +534,11 @@ static struct drm_exynos_ipp_mem_node
                        dma_addr_t *addr;
 
                        addr = exynos_drm_gem_get_dma_addr(drm_dev,
-                                       qbuf->handle[i], file);
+                                       qbuf->handle[i], c_node->filp);
                        if (IS_ERR(addr)) {
                                DRM_ERROR("failed to get addr.\n");
-                               goto err_clear;
+                               ipp_put_mem_node(drm_dev, c_node, m_node);
+                               return ERR_PTR(-EFAULT);
                        }
 
                        buf_info->handles[i] = qbuf->handle[i];
@@ -640,46 +548,30 @@ static struct drm_exynos_ipp_mem_node
                }
        }
 
-       m_node->filp = file;
        mutex_lock(&c_node->mem_lock);
        list_add_tail(&m_node->list, &c_node->mem_list[qbuf->ops_id]);
        mutex_unlock(&c_node->mem_lock);
 
        return m_node;
-
-err_clear:
-       kfree(m_node);
-       return ERR_PTR(-EFAULT);
 }
 
-static int ipp_put_mem_node(struct drm_device *drm_dev,
-               struct drm_exynos_ipp_cmd_node *c_node,
-               struct drm_exynos_ipp_mem_node *m_node)
+static void ipp_clean_mem_nodes(struct drm_device *drm_dev,
+                              struct drm_exynos_ipp_cmd_node *c_node, int ops)
 {
-       int i;
-
-       DRM_DEBUG_KMS("node[0x%x]\n", (int)m_node);
+       struct drm_exynos_ipp_mem_node *m_node, *tm_node;
+       struct list_head *head = &c_node->mem_list[ops];
 
-       if (!m_node) {
-               DRM_ERROR("invalid dequeue node.\n");
-               return -EFAULT;
-       }
+       mutex_lock(&c_node->mem_lock);
 
-       DRM_DEBUG_KMS("ops_id[%d]\n", m_node->ops_id);
+       list_for_each_entry_safe(m_node, tm_node, head, list) {
+               int ret;
 
-       /* put gem buffer */
-       for_each_ipp_planar(i) {
-               unsigned long handle = m_node->buf_info.handles[i];
-               if (handle)
-                       exynos_drm_gem_put_dma_addr(drm_dev, handle,
-                                                       m_node->filp);
+               ret = ipp_put_mem_node(drm_dev, c_node, m_node);
+               if (ret)
+                       DRM_ERROR("failed to put m_node.\n");
        }
 
-       /* delete list in queue */
-       list_del(&m_node->list);
-       kfree(m_node);
-
-       return 0;
+       mutex_unlock(&c_node->mem_lock);
 }
 
 static void ipp_free_event(struct drm_pending_event *event)
@@ -688,7 +580,6 @@ static void ipp_free_event(struct drm_pending_event *event)
 }
 
 static int ipp_get_event(struct drm_device *drm_dev,
-               struct drm_file *file,
                struct drm_exynos_ipp_cmd_node *c_node,
                struct drm_exynos_ipp_queue_buf *qbuf)
 {
@@ -700,7 +591,7 @@ static int ipp_get_event(struct drm_device *drm_dev,
        e = kzalloc(sizeof(*e), GFP_KERNEL);
        if (!e) {
                spin_lock_irqsave(&drm_dev->event_lock, flags);
-               file->event_space += sizeof(e->event);
+               c_node->filp->event_space += sizeof(e->event);
                spin_unlock_irqrestore(&drm_dev->event_lock, flags);
                return -ENOMEM;
        }
@@ -712,7 +603,7 @@ static int ipp_get_event(struct drm_device *drm_dev,
        e->event.prop_id = qbuf->prop_id;
        e->event.buf_id[EXYNOS_DRM_OPS_DST] = qbuf->buf_id;
        e->base.event = &e->event.base;
-       e->base.file_priv = file;
+       e->base.file_priv = c_node->filp;
        e->base.destroy = ipp_free_event;
        mutex_lock(&c_node->event_lock);
        list_add_tail(&e->base.link, &c_node->event_list);
@@ -757,6 +648,115 @@ out_unlock:
        return;
 }
 
+static void ipp_clean_cmd_node(struct ipp_context *ctx,
+                               struct drm_exynos_ipp_cmd_node *c_node)
+{
+       int i;
+
+       /* cancel works */
+       cancel_work_sync(&c_node->start_work->work);
+       cancel_work_sync(&c_node->stop_work->work);
+       cancel_work_sync(&c_node->event_work->work);
+
+       /* put event */
+       ipp_put_event(c_node, NULL);
+
+       for_each_ipp_ops(i)
+               ipp_clean_mem_nodes(ctx->subdrv.drm_dev, c_node, i);
+
+       /* delete list */
+       list_del(&c_node->list);
+
+       ipp_remove_id(&ctx->prop_idr, &ctx->prop_lock,
+                       c_node->property.prop_id);
+
+       /* destroy mutex */
+       mutex_destroy(&c_node->lock);
+       mutex_destroy(&c_node->mem_lock);
+       mutex_destroy(&c_node->event_lock);
+
+       /* free command node */
+       kfree(c_node->start_work);
+       kfree(c_node->stop_work);
+       kfree(c_node->event_work);
+       kfree(c_node);
+}
+
+static bool ipp_check_mem_list(struct drm_exynos_ipp_cmd_node *c_node)
+{
+       switch (c_node->property.cmd) {
+       case IPP_CMD_WB:
+               return !list_empty(&c_node->mem_list[EXYNOS_DRM_OPS_DST]);
+       case IPP_CMD_OUTPUT:
+               return !list_empty(&c_node->mem_list[EXYNOS_DRM_OPS_SRC]);
+       case IPP_CMD_M2M:
+       default:
+               return !list_empty(&c_node->mem_list[EXYNOS_DRM_OPS_SRC]) &&
+                      !list_empty(&c_node->mem_list[EXYNOS_DRM_OPS_DST]);
+       }
+}
+
+static struct drm_exynos_ipp_mem_node
+               *ipp_find_mem_node(struct drm_exynos_ipp_cmd_node *c_node,
+               struct drm_exynos_ipp_queue_buf *qbuf)
+{
+       struct drm_exynos_ipp_mem_node *m_node;
+       struct list_head *head;
+       int count = 0;
+
+       DRM_DEBUG_KMS("buf_id[%d]\n", qbuf->buf_id);
+
+       /* source/destination memory list */
+       head = &c_node->mem_list[qbuf->ops_id];
+
+       /* find memory node from memory list */
+       list_for_each_entry(m_node, head, list) {
+               DRM_DEBUG_KMS("count[%d]m_node[0x%x]\n", count++, (int)m_node);
+
+               /* compare buffer id */
+               if (m_node->buf_id == qbuf->buf_id)
+                       return m_node;
+       }
+
+       return NULL;
+}
+
+static int ipp_set_mem_node(struct exynos_drm_ippdrv *ippdrv,
+               struct drm_exynos_ipp_cmd_node *c_node,
+               struct drm_exynos_ipp_mem_node *m_node)
+{
+       struct exynos_drm_ipp_ops *ops = NULL;
+       int ret = 0;
+
+       DRM_DEBUG_KMS("node[0x%x]\n", (int)m_node);
+
+       if (!m_node) {
+               DRM_ERROR("invalid queue node.\n");
+               return -EFAULT;
+       }
+
+       DRM_DEBUG_KMS("ops_id[%d]\n", m_node->ops_id);
+
+       /* get operations callback */
+       ops = ippdrv->ops[m_node->ops_id];
+       if (!ops) {
+               DRM_ERROR("not support ops.\n");
+               return -EFAULT;
+       }
+
+       /* set address and enable irq */
+       if (ops->set_addr) {
+               ret = ops->set_addr(ippdrv->dev, &m_node->buf_info,
+                       m_node->buf_id, IPP_BUF_ENQUEUE);
+               if (ret) {
+                       DRM_ERROR("failed to set addr.\n");
+                       return ret;
+               }
+       }
+
+       return ret;
+}
+
 static void ipp_handle_cmd_work(struct device *dev,
                struct exynos_drm_ippdrv *ippdrv,
                struct drm_exynos_ipp_cmd_work *cmd_work,
@@ -766,7 +766,7 @@ static void ipp_handle_cmd_work(struct device *dev,
 
        cmd_work->ippdrv = ippdrv;
        cmd_work->c_node = c_node;
-       queue_work(ctx->cmd_workq, (struct work_struct *)cmd_work);
+       queue_work(ctx->cmd_workq, &cmd_work->work);
 }
 
 static int ipp_queue_buf_with_run(struct device *dev,
@@ -872,7 +872,7 @@ int exynos_drm_ipp_queue_buf(struct drm_device *drm_dev, void *data,
        /* find command node */
        c_node = ipp_find_obj(&ctx->prop_idr, &ctx->prop_lock,
                qbuf->prop_id);
-       if (!c_node) {
+       if (!c_node || c_node->filp != file) {
                DRM_ERROR("failed to get command node.\n");
                return -ENODEV;
        }
@@ -881,7 +881,7 @@ int exynos_drm_ipp_queue_buf(struct drm_device *drm_dev, void *data,
        switch (qbuf->buf_type) {
        case IPP_BUF_ENQUEUE:
                /* get memory node */
-               m_node = ipp_get_mem_node(drm_dev, file, c_node, qbuf);
+               m_node = ipp_get_mem_node(drm_dev, c_node, qbuf);
                if (IS_ERR(m_node)) {
                        DRM_ERROR("failed to get m_node.\n");
                        return PTR_ERR(m_node);
@@ -894,7 +894,7 @@ int exynos_drm_ipp_queue_buf(struct drm_device *drm_dev, void *data,
                 */
                if (qbuf->ops_id == EXYNOS_DRM_OPS_DST) {
                        /* get event for destination buffer */
-                       ret = ipp_get_event(drm_dev, file, c_node, qbuf);
+                       ret = ipp_get_event(drm_dev, c_node, qbuf);
                        if (ret) {
                                DRM_ERROR("failed to get event.\n");
                                goto err_clean_node;
@@ -1007,7 +1007,7 @@ int exynos_drm_ipp_cmd_ctrl(struct drm_device *drm_dev, void *data,
 
        c_node = ipp_find_obj(&ctx->prop_idr, &ctx->prop_lock,
                cmd_ctrl->prop_id);
-       if (!c_node) {
+       if (!c_node || c_node->filp != file) {
                DRM_ERROR("invalid command node list.\n");
                return -ENODEV;
        }
@@ -1257,80 +1257,39 @@ static int ipp_stop_property(struct drm_device *drm_dev,
                struct exynos_drm_ippdrv *ippdrv,
                struct drm_exynos_ipp_cmd_node *c_node)
 {
-       struct drm_exynos_ipp_mem_node *m_node, *tm_node;
        struct drm_exynos_ipp_property *property = &c_node->property;
-       struct list_head *head;
-       int ret = 0, i;
+       int i;
 
        DRM_DEBUG_KMS("prop_id[%d]\n", property->prop_id);
 
-       /* put event */
-       ipp_put_event(c_node, NULL);
-
-       mutex_lock(&c_node->mem_lock);
+       /* stop operations */
+       if (ippdrv->stop)
+               ippdrv->stop(ippdrv->dev, property->cmd);
 
        /* check command */
        switch (property->cmd) {
        case IPP_CMD_M2M:
-               for_each_ipp_ops(i) {
-                       /* source/destination memory list */
-                       head = &c_node->mem_list[i];
-
-                       list_for_each_entry_safe(m_node, tm_node,
-                               head, list) {
-                               ret = ipp_put_mem_node(drm_dev, c_node,
-                                       m_node);
-                               if (ret) {
-                                       DRM_ERROR("failed to put m_node.\n");
-                                       goto err_clear;
-                               }
-                       }
-               }
+               for_each_ipp_ops(i)
+                       ipp_clean_mem_nodes(drm_dev, c_node, i);
                break;
        case IPP_CMD_WB:
-               /* destination memory list */
-               head = &c_node->mem_list[EXYNOS_DRM_OPS_DST];
-
-               list_for_each_entry_safe(m_node, tm_node, head, list) {
-                       ret = ipp_put_mem_node(drm_dev, c_node, m_node);
-                       if (ret) {
-                               DRM_ERROR("failed to put m_node.\n");
-                               goto err_clear;
-                       }
-               }
+               ipp_clean_mem_nodes(drm_dev, c_node, EXYNOS_DRM_OPS_DST);
                break;
        case IPP_CMD_OUTPUT:
-               /* source memory list */
-               head = &c_node->mem_list[EXYNOS_DRM_OPS_SRC];
-
-               list_for_each_entry_safe(m_node, tm_node, head, list) {
-                       ret = ipp_put_mem_node(drm_dev, c_node, m_node);
-                       if (ret) {
-                               DRM_ERROR("failed to put m_node.\n");
-                               goto err_clear;
-                       }
-               }
+               ipp_clean_mem_nodes(drm_dev, c_node, EXYNOS_DRM_OPS_SRC);
                break;
        default:
                DRM_ERROR("invalid operations.\n");
-               ret = -EINVAL;
-               goto err_clear;
+               return -EINVAL;
        }
 
-err_clear:
-       mutex_unlock(&c_node->mem_lock);
-
-       /* stop operations */
-       if (ippdrv->stop)
-               ippdrv->stop(ippdrv->dev, property->cmd);
-
-       return ret;
+       return 0;
 }
 
 void ipp_sched_cmd(struct work_struct *work)
 {
        struct drm_exynos_ipp_cmd_work *cmd_work =
-               (struct drm_exynos_ipp_cmd_work *)work;
+               container_of(work, struct drm_exynos_ipp_cmd_work, work);
        struct exynos_drm_ippdrv *ippdrv;
        struct drm_exynos_ipp_cmd_node *c_node;
        struct drm_exynos_ipp_property *property;
@@ -1543,7 +1502,7 @@ err_event_unlock:
 void ipp_sched_event(struct work_struct *work)
 {
        struct drm_exynos_ipp_event_work *event_work =
-               (struct drm_exynos_ipp_event_work *)work;
+               container_of(work, struct drm_exynos_ipp_event_work, work);
        struct exynos_drm_ippdrv *ippdrv;
        struct drm_exynos_ipp_cmd_node *c_node;
        int ret;
@@ -1646,11 +1605,11 @@ err:
 
 static void ipp_subdrv_remove(struct drm_device *drm_dev, struct device *dev)
 {
-       struct exynos_drm_ippdrv *ippdrv;
+       struct exynos_drm_ippdrv *ippdrv, *t;
        struct ipp_context *ctx = get_ipp_context(dev);
 
        /* get ipp driver entry */
-       list_for_each_entry(ippdrv, &exynos_drm_ippdrv_list, drv_list) {
+       list_for_each_entry_safe(ippdrv, t, &exynos_drm_ippdrv_list, drv_list) {
                if (is_drm_iommu_supported(drm_dev))
                        drm_iommu_detach_device(drm_dev, ippdrv->dev);
 
@@ -1677,14 +1636,11 @@ static int ipp_subdrv_open(struct drm_device *drm_dev, struct device *dev,
 static void ipp_subdrv_close(struct drm_device *drm_dev, struct device *dev,
                struct drm_file *file)
 {
-       struct drm_exynos_file_private *file_priv = file->driver_priv;
        struct exynos_drm_ippdrv *ippdrv = NULL;
        struct ipp_context *ctx = get_ipp_context(dev);
        struct drm_exynos_ipp_cmd_node *c_node, *tc_node;
        int count = 0;
 
-       DRM_DEBUG_KMS("for priv[0x%x]\n", (int)file_priv->ipp_dev);
-
        list_for_each_entry(ippdrv, &exynos_drm_ippdrv_list, drv_list) {
                mutex_lock(&ippdrv->cmd_lock);
                list_for_each_entry_safe(c_node, tc_node,
@@ -1692,7 +1648,7 @@ static void ipp_subdrv_close(struct drm_device *drm_dev, struct device *dev,
                        DRM_DEBUG_KMS("count[%d]ippdrv[0x%x]\n",
                                count++, (int)ippdrv);
 
-                       if (c_node->dev == file_priv->ipp_dev) {
+                       if (c_node->filp == file) {
                                /*
                                 * userland goto unnormal state. process killed.
                                 * and close the file.
@@ -1808,63 +1764,12 @@ static int ipp_remove(struct platform_device *pdev)
        return 0;
 }
 
-static int ipp_power_ctrl(struct ipp_context *ctx, bool enable)
-{
-       DRM_DEBUG_KMS("enable[%d]\n", enable);
-
-       return 0;
-}
-
-#ifdef CONFIG_PM_SLEEP
-static int ipp_suspend(struct device *dev)
-{
-       struct ipp_context *ctx = get_ipp_context(dev);
-
-       if (pm_runtime_suspended(dev))
-               return 0;
-
-       return ipp_power_ctrl(ctx, false);
-}
-
-static int ipp_resume(struct device *dev)
-{
-       struct ipp_context *ctx = get_ipp_context(dev);
-
-       if (!pm_runtime_suspended(dev))
-               return ipp_power_ctrl(ctx, true);
-
-       return 0;
-}
-#endif
-
-#ifdef CONFIG_PM_RUNTIME
-static int ipp_runtime_suspend(struct device *dev)
-{
-       struct ipp_context *ctx = get_ipp_context(dev);
-
-       return ipp_power_ctrl(ctx, false);
-}
-
-static int ipp_runtime_resume(struct device *dev)
-{
-       struct ipp_context *ctx = get_ipp_context(dev);
-
-       return ipp_power_ctrl(ctx, true);
-}
-#endif
-
-static const struct dev_pm_ops ipp_pm_ops = {
-       SET_SYSTEM_SLEEP_PM_OPS(ipp_suspend, ipp_resume)
-       SET_RUNTIME_PM_OPS(ipp_runtime_suspend, ipp_runtime_resume, NULL)
-};
-
 struct platform_driver ipp_driver = {
        .probe          = ipp_probe,
        .remove         = ipp_remove,
        .driver         = {
                .name   = "exynos-drm-ipp",
                .owner  = THIS_MODULE,
-               .pm     = &ipp_pm_ops,
        },
 };
 
index 6f48d62aeb30742636bea0b88d2edc8442d3e247..2a61547a39d0b56b86bfabe1a0bc5fcb4b930b21 100644 (file)
@@ -48,7 +48,6 @@ struct drm_exynos_ipp_cmd_work {
 /*
  * A structure of command node.
  *
- * @dev: IPP device.
  * @list: list head to command queue information.
  * @event_list: list head of event.
  * @mem_list: list head to source,destination memory queue information.
@@ -62,9 +61,9 @@ struct drm_exynos_ipp_cmd_work {
  * @stop_work: stop command work structure.
  * @event_work: event work structure.
  * @state: state of command node.
+ * @filp: associated file pointer.
  */
 struct drm_exynos_ipp_cmd_node {
-       struct device           *dev;
        struct list_head        list;
        struct list_head        event_list;
        struct list_head        mem_list[EXYNOS_DRM_OPS_MAX];
@@ -78,6 +77,7 @@ struct drm_exynos_ipp_cmd_node {
        struct drm_exynos_ipp_cmd_work *stop_work;
        struct drm_exynos_ipp_event_work *event_work;
        enum drm_exynos_ipp_state       state;
+       struct drm_file *filp;
 };
 
 /*
index 8371cbd7631d421365a194c9b3d936fd8b02a567..c7045a663763f28200b4ebbb59a32b8dd874463f 100644 (file)
@@ -139,6 +139,8 @@ int exynos_plane_mode_set(struct drm_plane *plane, struct drm_crtc *crtc,
                        overlay->crtc_x, overlay->crtc_y,
                        overlay->crtc_width, overlay->crtc_height);
 
+       plane->crtc = crtc;
+
        exynos_drm_crtc_plane_mode_set(crtc, overlay);
 
        return 0;
@@ -187,8 +189,6 @@ exynos_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
        if (ret < 0)
                return ret;
 
-       plane->crtc = crtc;
-
        exynos_plane_commit(plane);
        exynos_plane_dpms(plane, DRM_MODE_DPMS_ON);
 
@@ -254,25 +254,26 @@ static void exynos_plane_attach_zpos_property(struct drm_plane *plane)
 }
 
 struct drm_plane *exynos_plane_init(struct drm_device *dev,
-                                   unsigned long possible_crtcs, bool priv)
+                                   unsigned long possible_crtcs,
+                                   enum drm_plane_type type)
 {
        struct exynos_plane *exynos_plane;
        int err;
 
        exynos_plane = kzalloc(sizeof(struct exynos_plane), GFP_KERNEL);
        if (!exynos_plane)
-               return NULL;
+               return ERR_PTR(-ENOMEM);
 
-       err = drm_plane_init(dev, &exynos_plane->base, possible_crtcs,
-                             &exynos_plane_funcs, formats, ARRAY_SIZE(formats),
-                             priv);
+       err = drm_universal_plane_init(dev, &exynos_plane->base, possible_crtcs,
+                                      &exynos_plane_funcs, formats,
+                                      ARRAY_SIZE(formats), type);
        if (err) {
                DRM_ERROR("failed to initialize plane\n");
                kfree(exynos_plane);
-               return NULL;
+               return ERR_PTR(err);
        }
 
-       if (priv)
+       if (type == DRM_PLANE_TYPE_PRIMARY)
                exynos_plane->overlay.zpos = DEFAULT_ZPOS;
        else
                exynos_plane_attach_zpos_property(&exynos_plane->base);
index 84d464c90d3d34b095459e29304fb3aec1cf6a79..0d1986b115f89543fca89953aa04930addabc215 100644 (file)
@@ -17,4 +17,5 @@ int exynos_plane_mode_set(struct drm_plane *plane, struct drm_crtc *crtc,
 void exynos_plane_commit(struct drm_plane *plane);
 void exynos_plane_dpms(struct drm_plane *plane, int mode);
 struct drm_plane *exynos_plane_init(struct drm_device *dev,
-                                   unsigned long possible_crtcs, bool priv);
+                                   unsigned long possible_crtcs,
+                                   enum drm_plane_type type);
index 55af6b41c1dfa3f0da4be362245212838371ff1a..b6a37d4f5b1326f9eb8f2226feea954087f6879e 100644 (file)
@@ -156,8 +156,7 @@ static irqreturn_t rotator_irq_handler(int irq, void *arg)
                event_work->ippdrv = ippdrv;
                event_work->buf_id[EXYNOS_DRM_OPS_DST] =
                        rot->cur_buf_id[EXYNOS_DRM_OPS_DST];
-               queue_work(ippdrv->event_workq,
-                       (struct work_struct *)event_work);
+               queue_work(ippdrv->event_workq, &event_work->work);
        } else {
                DRM_ERROR("the SFR is set illegally\n");
        }
index 9528d81d8004d70bcd9f395a68f37ab12de5d9d5..d565207040a2590d416895b5dc9247ef68824492 100644 (file)
@@ -303,23 +303,6 @@ static int vidi_mgr_initialize(struct exynos_drm_manager *mgr,
        mgr->drm_dev = ctx->drm_dev = drm_dev;
        mgr->pipe = ctx->pipe = priv->pipe++;
 
-       /*
-        * enable drm irq mode.
-        * - with irq_enabled = 1, we can use the vblank feature.
-        *
-        * P.S. note that we wouldn't use drm irq handler but
-        *      just specific driver own one instead because
-        *      drm framework supports only one irq handler.
-        */
-       drm_dev->irq_enabled = 1;
-
-       /*
-        * with vblank_disable_allowed = 1, vblank interrupt will be disabled
-        * by drm timer once a current process gives up ownership of
-        * vblank event.(after drm_vblank_put function is called)
-        */
-       drm_dev->vblank_disable_allowed = 1;
-
        return 0;
 }
 
@@ -648,7 +631,6 @@ static int vidi_remove(struct platform_device *pdev)
        struct exynos_drm_manager *mgr = platform_get_drvdata(pdev);
        struct vidi_context *ctx = mgr->ctx;
        struct drm_encoder *encoder = ctx->encoder;
-       struct drm_crtc *crtc = mgr->crtc;
 
        if (ctx->raw_edid != (struct edid *)fake_edid_info) {
                kfree(ctx->raw_edid);
@@ -657,7 +639,6 @@ static int vidi_remove(struct platform_device *pdev)
                return -EINVAL;
        }
 
-       crtc->funcs->destroy(crtc);
        encoder->funcs->destroy(encoder);
        drm_connector_cleanup(&ctx->connector);
 
index 562966db2aa13eec90a5dbf588666675f8674892..7910fb37d9bbd6df2092f0c7147d6e0a8b944875 100644 (file)
@@ -1040,6 +1040,8 @@ static enum drm_connector_status hdmi_detect(struct drm_connector *connector,
 
 static void hdmi_connector_destroy(struct drm_connector *connector)
 {
+       drm_connector_unregister(connector);
+       drm_connector_cleanup(connector);
 }
 
 static struct drm_connector_funcs hdmi_connector_funcs = {
@@ -2314,8 +2316,8 @@ static void hdmi_unbind(struct device *dev, struct device *master, void *data)
        struct drm_encoder *encoder = display->encoder;
        struct hdmi_context *hdata = display->ctx;
 
+       hdmi_connector_destroy(&hdata->connector);
        encoder->funcs->destroy(encoder);
-       drm_connector_cleanup(&hdata->connector);
 }
 
 static const struct component_ops hdmi_component_ops = {
index e8b4ec84b312cc412351b08ab6e09f0626d5cc05..a41c84ee3a2d554a464219cf4000083b2e3fa4dd 100644 (file)
@@ -1302,15 +1302,12 @@ static int mixer_bind(struct device *dev, struct device *manager, void *data)
 static void mixer_unbind(struct device *dev, struct device *master, void *data)
 {
        struct exynos_drm_manager *mgr = dev_get_drvdata(dev);
-       struct drm_crtc *crtc = mgr->crtc;
 
        dev_info(dev, "remove successful\n");
 
        mixer_mgr_remove(mgr);
 
        pm_runtime_disable(dev);
-
-       crtc->funcs->destroy(crtc);
 }
 
 static const struct component_ops mixer_component_ops = {
index a4cc0e60a1be732c035c06754571dafa09e4d0c8..9f158eab517a46c0f40ae8a8b37066e3a1e031cd 100644 (file)
@@ -1089,7 +1089,7 @@ static char       *link_train_names[] = {
 };
 #endif
 
-#define CDV_DP_VOLTAGE_MAX         DP_TRAIN_VOLTAGE_SWING_1200
+#define CDV_DP_VOLTAGE_MAX         DP_TRAIN_VOLTAGE_SWING_LEVEL_3
 /*
 static uint8_t
 cdv_intel_dp_pre_emphasis_max(uint8_t voltage_swing)
@@ -1276,7 +1276,7 @@ cdv_intel_dp_set_vswing_premph(struct gma_encoder *encoder, uint8_t signal_level
                cdv_sb_write(dev, ddi_reg->VSwing2, dp_vswing_premph_table[index]);
 
        /* ;gfx_dpio_set_reg(0x814c, 0x40802040) */
-       if ((vswing + premph) == DP_TRAIN_VOLTAGE_SWING_1200)
+       if ((vswing + premph) == DP_TRAIN_VOLTAGE_SWING_LEVEL_3)
                cdv_sb_write(dev, ddi_reg->VSwing3, 0x70802040);
        else
                cdv_sb_write(dev, ddi_reg->VSwing3, 0x40802040);
index d0dd3bea8aa5a1a2d98b2505139f07dc1db57715..ddd90ddbc20097d7325379d7cf77d516854d60f6 100644 (file)
@@ -540,7 +540,8 @@ static void psbfb_gamma_get(struct drm_crtc *crtc, u16 *red,
 static int psbfb_probe(struct drm_fb_helper *helper,
                                struct drm_fb_helper_surface_size *sizes)
 {
-       struct psb_fbdev *psb_fbdev = (struct psb_fbdev *)helper;
+       struct psb_fbdev *psb_fbdev =
+               container_of(helper, struct psb_fbdev, psb_fb_helper);
        struct drm_device *dev = psb_fbdev->psb_fb_helper.dev;
        struct drm_psb_private *dev_priv = dev->dev_private;
        int bytespp;
index f5860a739bd8551fa60868b09ab61bb74b4c0edf..cdbb350c9d5d2b23c3272ac908163e8b6610677d 100644 (file)
@@ -21,6 +21,7 @@
 #define _PSB_GTT_H_
 
 #include <drm/drmP.h>
+#include <drm/drm_gem.h>
 
 /* This wants cleaning up with respect to the psb_dev and un-needed stuff */
 struct psb_gtt {
index d3497348c4d5d81a240369d1d0dc831b30c29dbe..63bde4e86c6a11643419a099b2e3b4216a0c038b 100644 (file)
@@ -116,30 +116,30 @@ parse_edp(struct drm_psb_private *dev_priv, struct bdb_header *bdb)
 
        switch (edp_link_params->preemphasis) {
        case 0:
-               dev_priv->edp.preemphasis = DP_TRAIN_PRE_EMPHASIS_0;
+               dev_priv->edp.preemphasis = DP_TRAIN_PRE_EMPH_LEVEL_0;
                break;
        case 1:
-               dev_priv->edp.preemphasis = DP_TRAIN_PRE_EMPHASIS_3_5;
+               dev_priv->edp.preemphasis = DP_TRAIN_PRE_EMPH_LEVEL_1;
                break;
        case 2:
-               dev_priv->edp.preemphasis = DP_TRAIN_PRE_EMPHASIS_6;
+               dev_priv->edp.preemphasis = DP_TRAIN_PRE_EMPH_LEVEL_2;
                break;
        case 3:
-               dev_priv->edp.preemphasis = DP_TRAIN_PRE_EMPHASIS_9_5;
+               dev_priv->edp.preemphasis = DP_TRAIN_PRE_EMPH_LEVEL_3;
                break;
        }
        switch (edp_link_params->vswing) {
        case 0:
-               dev_priv->edp.vswing = DP_TRAIN_VOLTAGE_SWING_400;
+               dev_priv->edp.vswing = DP_TRAIN_VOLTAGE_SWING_LEVEL_0;
                break;
        case 1:
-               dev_priv->edp.vswing = DP_TRAIN_VOLTAGE_SWING_600;
+               dev_priv->edp.vswing = DP_TRAIN_VOLTAGE_SWING_LEVEL_1;
                break;
        case 2:
-               dev_priv->edp.vswing = DP_TRAIN_VOLTAGE_SWING_800;
+               dev_priv->edp.vswing = DP_TRAIN_VOLTAGE_SWING_LEVEL_2;
                break;
        case 3:
-               dev_priv->edp.vswing = DP_TRAIN_VOLTAGE_SWING_1200;
+               dev_priv->edp.vswing = DP_TRAIN_VOLTAGE_SWING_LEVEL_3;
                break;
        }
        DRM_DEBUG_KMS("VBT reports EDP: VSwing  %d, Preemph %d\n",
index eec993f93b1aaea8cd7309918b2c51a08bf08725..6ec3a905fdd274bbcd1ec169efc802e8cf1663be 100644 (file)
@@ -476,6 +476,7 @@ static struct drm_driver driver = {
        .unload = psb_driver_unload,
        .lastclose = psb_driver_lastclose,
        .preclose = psb_driver_preclose,
+       .set_busid = drm_pci_set_busid,
 
        .num_ioctls = ARRAY_SIZE(psb_ioctls),
        .device_is_agp = psb_driver_device_is_agp,
index bae897de9468952f882df012da4f055d53edf892..d91856779bebca20a04f198da3ce486c907927e4 100644 (file)
@@ -213,7 +213,7 @@ static int i810_dma_cleanup(struct drm_device *dev)
                    (drm_i810_private_t *) dev->dev_private;
 
                if (dev_priv->ring.virtual_start)
-                       drm_core_ioremapfree(&dev_priv->ring.map, dev);
+                       drm_legacy_ioremapfree(&dev_priv->ring.map, dev);
                if (dev_priv->hw_status_page) {
                        pci_free_consistent(dev->pdev, PAGE_SIZE,
                                            dev_priv->hw_status_page,
@@ -227,7 +227,7 @@ static int i810_dma_cleanup(struct drm_device *dev)
                        drm_i810_buf_priv_t *buf_priv = buf->dev_private;
 
                        if (buf_priv->kernel_virtual && buf->total)
-                               drm_core_ioremapfree(&buf_priv->map, dev);
+                               drm_legacy_ioremapfree(&buf_priv->map, dev);
                }
        }
        return 0;
@@ -306,7 +306,7 @@ static int i810_freelist_init(struct drm_device *dev, drm_i810_private_t *dev_pr
                buf_priv->map.flags = 0;
                buf_priv->map.mtrr = 0;
 
-               drm_core_ioremap(&buf_priv->map, dev);
+               drm_legacy_ioremap(&buf_priv->map, dev);
                buf_priv->kernel_virtual = buf_priv->map.handle;
 
        }
@@ -334,7 +334,7 @@ static int i810_dma_initialize(struct drm_device *dev,
                DRM_ERROR("can not find sarea!\n");
                return -EINVAL;
        }
-       dev_priv->mmio_map = drm_core_findmap(dev, init->mmio_offset);
+       dev_priv->mmio_map = drm_legacy_findmap(dev, init->mmio_offset);
        if (!dev_priv->mmio_map) {
                dev->dev_private = (void *)dev_priv;
                i810_dma_cleanup(dev);
@@ -342,7 +342,7 @@ static int i810_dma_initialize(struct drm_device *dev,
                return -EINVAL;
        }
        dev->agp_buffer_token = init->buffers_offset;
-       dev->agp_buffer_map = drm_core_findmap(dev, init->buffers_offset);
+       dev->agp_buffer_map = drm_legacy_findmap(dev, init->buffers_offset);
        if (!dev->agp_buffer_map) {
                dev->dev_private = (void *)dev_priv;
                i810_dma_cleanup(dev);
@@ -363,7 +363,7 @@ static int i810_dma_initialize(struct drm_device *dev,
        dev_priv->ring.map.flags = 0;
        dev_priv->ring.map.mtrr = 0;
 
-       drm_core_ioremap(&dev_priv->ring.map, dev);
+       drm_legacy_ioremap(&dev_priv->ring.map, dev);
 
        if (dev_priv->ring.map.handle == NULL) {
                dev->dev_private = (void *)dev_priv;
@@ -1215,9 +1215,9 @@ void i810_driver_preclose(struct drm_device *dev, struct drm_file *file_priv)
        }
 
        if (file_priv->master && file_priv->master->lock.hw_lock) {
-               drm_idlelock_take(&file_priv->master->lock);
+               drm_legacy_idlelock_take(&file_priv->master->lock);
                i810_driver_reclaim_buffers(dev, file_priv);
-               drm_idlelock_release(&file_priv->master->lock);
+               drm_legacy_idlelock_release(&file_priv->master->lock);
        } else {
                /* master disappeared, clean up stuff anyway and hope nothing
                 * goes wrong */
index 441ccf8f5bdc3a7d2ebad9b4724eff2044d2c34b..44f4a131c8ddb4c0e68f16ecde7dbad324255edc 100644 (file)
@@ -47,7 +47,7 @@ static const struct file_operations i810_driver_fops = {
        .open = drm_open,
        .release = drm_release,
        .unlocked_ioctl = drm_ioctl,
-       .mmap = drm_mmap,
+       .mmap = drm_legacy_mmap,
        .poll = drm_poll,
 #ifdef CONFIG_COMPAT
        .compat_ioctl = drm_compat_ioctl,
@@ -63,6 +63,7 @@ static struct drm_driver driver = {
        .load = i810_driver_load,
        .lastclose = i810_driver_lastclose,
        .preclose = i810_driver_preclose,
+       .set_busid = drm_pci_set_busid,
        .device_is_agp = i810_driver_device_is_agp,
        .dma_quiescent = i810_driver_dma_quiescent,
        .ioctls = i810_ioctls,
index d4d16eddd65110c18c557175d870c432c25d1570..93ec5dc4e7d3034743bf03f32923f8c3db932abc 100644 (file)
@@ -32,6 +32,8 @@
 #ifndef _I810_DRV_H_
 #define _I810_DRV_H_
 
+#include <drm/drm_legacy.h>
+
 /* General customization:
  */
 
index 91bd167e1cb70322998d92050d01f43eae7d0888..c1dd485aeb6c255230c83e7fea876fb79fed3308 100644 (file)
@@ -31,6 +31,7 @@ i915-y += i915_cmd_parser.o \
          i915_gpu_error.o \
          i915_irq.o \
          i915_trace_points.o \
+         intel_lrc.o \
          intel_ringbuffer.o \
          intel_uncore.o
 
index 74f2af7c2d3ed41688494a41b78e28390cf7c2b5..441630434d34742b38d938e5ba6bee0fa6faa965 100644 (file)
 
 #define NS2501_REGC 0x0c
 
+enum {
+       MODE_640x480,
+       MODE_800x600,
+       MODE_1024x768,
+};
+
+struct ns2501_reg {
+        uint8_t offset;
+        uint8_t value;
+};
+
+/*
+ * Magic values based on what the BIOS on
+ * Fujitsu-Siemens Lifebook S6010 programs (1024x768 panel).
+ */
+static const struct ns2501_reg regs_1024x768[][86] = {
+       [MODE_640x480] = {
+               [0] = { .offset = 0x0a, .value = 0x81, },
+               [1] = { .offset = 0x18, .value = 0x07, },
+               [2] = { .offset = 0x19, .value = 0x00, },
+               [3] = { .offset = 0x1a, .value = 0x00, },
+               [4] = { .offset = 0x1b, .value = 0x11, },
+               [5] = { .offset = 0x1c, .value = 0x54, },
+               [6] = { .offset = 0x1d, .value = 0x03, },
+               [7] = { .offset = 0x1e, .value = 0x02, },
+               [8] = { .offset = 0xf3, .value = 0x90, },
+               [9] = { .offset = 0xf9, .value = 0x00, },
+               [10] = { .offset = 0xc1, .value = 0x90, },
+               [11] = { .offset = 0xc2, .value = 0x00, },
+               [12] = { .offset = 0xc3, .value = 0x0f, },
+               [13] = { .offset = 0xc4, .value = 0x03, },
+               [14] = { .offset = 0xc5, .value = 0x16, },
+               [15] = { .offset = 0xc6, .value = 0x00, },
+               [16] = { .offset = 0xc7, .value = 0x02, },
+               [17] = { .offset = 0xc8, .value = 0x02, },
+               [18] = { .offset = 0xf4, .value = 0x00, },
+               [19] = { .offset = 0x80, .value = 0xff, },
+               [20] = { .offset = 0x81, .value = 0x07, },
+               [21] = { .offset = 0x82, .value = 0x3d, },
+               [22] = { .offset = 0x83, .value = 0x05, },
+               [23] = { .offset = 0x94, .value = 0x00, },
+               [24] = { .offset = 0x95, .value = 0x00, },
+               [25] = { .offset = 0x96, .value = 0x05, },
+               [26] = { .offset = 0x97, .value = 0x00, },
+               [27] = { .offset = 0x9a, .value = 0x88, },
+               [28] = { .offset = 0x9b, .value = 0x00, },
+               [29] = { .offset = 0x98, .value = 0x00, },
+               [30] = { .offset = 0x99, .value = 0x00, },
+               [31] = { .offset = 0xf7, .value = 0x88, },
+               [32] = { .offset = 0xf8, .value = 0x0a, },
+               [33] = { .offset = 0x9c, .value = 0x24, },
+               [34] = { .offset = 0x9d, .value = 0x00, },
+               [35] = { .offset = 0x9e, .value = 0x25, },
+               [36] = { .offset = 0x9f, .value = 0x03, },
+               [37] = { .offset = 0xa0, .value = 0x28, },
+               [38] = { .offset = 0xa1, .value = 0x01, },
+               [39] = { .offset = 0xa2, .value = 0x28, },
+               [40] = { .offset = 0xa3, .value = 0x05, },
+               [41] = { .offset = 0xb6, .value = 0x09, },
+               [42] = { .offset = 0xb8, .value = 0x00, },
+               [43] = { .offset = 0xb9, .value = 0xa0, },
+               [44] = { .offset = 0xba, .value = 0x00, },
+               [45] = { .offset = 0xbb, .value = 0x20, },
+               [46] = { .offset = 0x10, .value = 0x00, },
+               [47] = { .offset = 0x11, .value = 0xa0, },
+               [48] = { .offset = 0x12, .value = 0x02, },
+               [49] = { .offset = 0x20, .value = 0x00, },
+               [50] = { .offset = 0x22, .value = 0x00, },
+               [51] = { .offset = 0x23, .value = 0x00, },
+               [52] = { .offset = 0x24, .value = 0x00, },
+               [53] = { .offset = 0x25, .value = 0x00, },
+               [54] = { .offset = 0x8c, .value = 0x10, },
+               [55] = { .offset = 0x8d, .value = 0x02, },
+               [56] = { .offset = 0x8e, .value = 0x10, },
+               [57] = { .offset = 0x8f, .value = 0x00, },
+               [58] = { .offset = 0x90, .value = 0xff, },
+               [59] = { .offset = 0x91, .value = 0x07, },
+               [60] = { .offset = 0x92, .value = 0xa0, },
+               [61] = { .offset = 0x93, .value = 0x02, },
+               [62] = { .offset = 0xa5, .value = 0x00, },
+               [63] = { .offset = 0xa6, .value = 0x00, },
+               [64] = { .offset = 0xa7, .value = 0x00, },
+               [65] = { .offset = 0xa8, .value = 0x00, },
+               [66] = { .offset = 0xa9, .value = 0x04, },
+               [67] = { .offset = 0xaa, .value = 0x70, },
+               [68] = { .offset = 0xab, .value = 0x4f, },
+               [69] = { .offset = 0xac, .value = 0x00, },
+               [70] = { .offset = 0xa4, .value = 0x84, },
+               [71] = { .offset = 0x7e, .value = 0x18, },
+               [72] = { .offset = 0x84, .value = 0x00, },
+               [73] = { .offset = 0x85, .value = 0x00, },
+               [74] = { .offset = 0x86, .value = 0x00, },
+               [75] = { .offset = 0x87, .value = 0x00, },
+               [76] = { .offset = 0x88, .value = 0x00, },
+               [77] = { .offset = 0x89, .value = 0x00, },
+               [78] = { .offset = 0x8a, .value = 0x00, },
+               [79] = { .offset = 0x8b, .value = 0x00, },
+               [80] = { .offset = 0x26, .value = 0x00, },
+               [81] = { .offset = 0x27, .value = 0x00, },
+               [82] = { .offset = 0xad, .value = 0x00, },
+               [83] = { .offset = 0x08, .value = 0x30, }, /* 0x31 */
+               [84] = { .offset = 0x41, .value = 0x00, },
+               [85] = { .offset = 0xc0, .value = 0x05, },
+       },
+       [MODE_800x600] = {
+               [0] = { .offset = 0x0a, .value = 0x81, },
+               [1] = { .offset = 0x18, .value = 0x07, },
+               [2] = { .offset = 0x19, .value = 0x00, },
+               [3] = { .offset = 0x1a, .value = 0x00, },
+               [4] = { .offset = 0x1b, .value = 0x19, },
+               [5] = { .offset = 0x1c, .value = 0x64, },
+               [6] = { .offset = 0x1d, .value = 0x02, },
+               [7] = { .offset = 0x1e, .value = 0x02, },
+               [8] = { .offset = 0xf3, .value = 0x90, },
+               [9] = { .offset = 0xf9, .value = 0x00, },
+               [10] = { .offset = 0xc1, .value = 0xd7, },
+               [11] = { .offset = 0xc2, .value = 0x00, },
+               [12] = { .offset = 0xc3, .value = 0xf8, },
+               [13] = { .offset = 0xc4, .value = 0x03, },
+               [14] = { .offset = 0xc5, .value = 0x1a, },
+               [15] = { .offset = 0xc6, .value = 0x00, },
+               [16] = { .offset = 0xc7, .value = 0x73, },
+               [17] = { .offset = 0xc8, .value = 0x02, },
+               [18] = { .offset = 0xf4, .value = 0x00, },
+               [19] = { .offset = 0x80, .value = 0x27, },
+               [20] = { .offset = 0x81, .value = 0x03, },
+               [21] = { .offset = 0x82, .value = 0x41, },
+               [22] = { .offset = 0x83, .value = 0x05, },
+               [23] = { .offset = 0x94, .value = 0x00, },
+               [24] = { .offset = 0x95, .value = 0x00, },
+               [25] = { .offset = 0x96, .value = 0x05, },
+               [26] = { .offset = 0x97, .value = 0x00, },
+               [27] = { .offset = 0x9a, .value = 0x88, },
+               [28] = { .offset = 0x9b, .value = 0x00, },
+               [29] = { .offset = 0x98, .value = 0x00, },
+               [30] = { .offset = 0x99, .value = 0x00, },
+               [31] = { .offset = 0xf7, .value = 0x88, },
+               [32] = { .offset = 0xf8, .value = 0x06, },
+               [33] = { .offset = 0x9c, .value = 0x23, },
+               [34] = { .offset = 0x9d, .value = 0x00, },
+               [35] = { .offset = 0x9e, .value = 0x25, },
+               [36] = { .offset = 0x9f, .value = 0x03, },
+               [37] = { .offset = 0xa0, .value = 0x28, },
+               [38] = { .offset = 0xa1, .value = 0x01, },
+               [39] = { .offset = 0xa2, .value = 0x28, },
+               [40] = { .offset = 0xa3, .value = 0x05, },
+               [41] = { .offset = 0xb6, .value = 0x09, },
+               [42] = { .offset = 0xb8, .value = 0x30, },
+               [43] = { .offset = 0xb9, .value = 0xc8, },
+               [44] = { .offset = 0xba, .value = 0x00, },
+               [45] = { .offset = 0xbb, .value = 0x20, },
+               [46] = { .offset = 0x10, .value = 0x20, },
+               [47] = { .offset = 0x11, .value = 0xc8, },
+               [48] = { .offset = 0x12, .value = 0x02, },
+               [49] = { .offset = 0x20, .value = 0x00, },
+               [50] = { .offset = 0x22, .value = 0x00, },
+               [51] = { .offset = 0x23, .value = 0x00, },
+               [52] = { .offset = 0x24, .value = 0x00, },
+               [53] = { .offset = 0x25, .value = 0x00, },
+               [54] = { .offset = 0x8c, .value = 0x10, },
+               [55] = { .offset = 0x8d, .value = 0x02, },
+               [56] = { .offset = 0x8e, .value = 0x04, },
+               [57] = { .offset = 0x8f, .value = 0x00, },
+               [58] = { .offset = 0x90, .value = 0xff, },
+               [59] = { .offset = 0x91, .value = 0x07, },
+               [60] = { .offset = 0x92, .value = 0xa0, },
+               [61] = { .offset = 0x93, .value = 0x02, },
+               [62] = { .offset = 0xa5, .value = 0x00, },
+               [63] = { .offset = 0xa6, .value = 0x00, },
+               [64] = { .offset = 0xa7, .value = 0x00, },
+               [65] = { .offset = 0xa8, .value = 0x00, },
+               [66] = { .offset = 0xa9, .value = 0x83, },
+               [67] = { .offset = 0xaa, .value = 0x40, },
+               [68] = { .offset = 0xab, .value = 0x32, },
+               [69] = { .offset = 0xac, .value = 0x00, },
+               [70] = { .offset = 0xa4, .value = 0x80, },
+               [71] = { .offset = 0x7e, .value = 0x18, },
+               [72] = { .offset = 0x84, .value = 0x00, },
+               [73] = { .offset = 0x85, .value = 0x00, },
+               [74] = { .offset = 0x86, .value = 0x00, },
+               [75] = { .offset = 0x87, .value = 0x00, },
+               [76] = { .offset = 0x88, .value = 0x00, },
+               [77] = { .offset = 0x89, .value = 0x00, },
+               [78] = { .offset = 0x8a, .value = 0x00, },
+               [79] = { .offset = 0x8b, .value = 0x00, },
+               [80] = { .offset = 0x26, .value = 0x00, },
+               [81] = { .offset = 0x27, .value = 0x00, },
+               [82] = { .offset = 0xad, .value = 0x00, },
+               [83] = { .offset = 0x08, .value = 0x30, }, /* 0x31 */
+               [84] = { .offset = 0x41, .value = 0x00, },
+               [85] = { .offset = 0xc0, .value = 0x07, },
+       },
+       [MODE_1024x768] = {
+               [0] = { .offset = 0x0a, .value = 0x81, },
+               [1] = { .offset = 0x18, .value = 0x07, },
+               [2] = { .offset = 0x19, .value = 0x00, },
+               [3] = { .offset = 0x1a, .value = 0x00, },
+               [4] = { .offset = 0x1b, .value = 0x11, },
+               [5] = { .offset = 0x1c, .value = 0x54, },
+               [6] = { .offset = 0x1d, .value = 0x03, },
+               [7] = { .offset = 0x1e, .value = 0x02, },
+               [8] = { .offset = 0xf3, .value = 0x90, },
+               [9] = { .offset = 0xf9, .value = 0x00, },
+               [10] = { .offset = 0xc1, .value = 0x90, },
+               [11] = { .offset = 0xc2, .value = 0x00, },
+               [12] = { .offset = 0xc3, .value = 0x0f, },
+               [13] = { .offset = 0xc4, .value = 0x03, },
+               [14] = { .offset = 0xc5, .value = 0x16, },
+               [15] = { .offset = 0xc6, .value = 0x00, },
+               [16] = { .offset = 0xc7, .value = 0x02, },
+               [17] = { .offset = 0xc8, .value = 0x02, },
+               [18] = { .offset = 0xf4, .value = 0x00, },
+               [19] = { .offset = 0x80, .value = 0xff, },
+               [20] = { .offset = 0x81, .value = 0x07, },
+               [21] = { .offset = 0x82, .value = 0x3d, },
+               [22] = { .offset = 0x83, .value = 0x05, },
+               [23] = { .offset = 0x94, .value = 0x00, },
+               [24] = { .offset = 0x95, .value = 0x00, },
+               [25] = { .offset = 0x96, .value = 0x05, },
+               [26] = { .offset = 0x97, .value = 0x00, },
+               [27] = { .offset = 0x9a, .value = 0x88, },
+               [28] = { .offset = 0x9b, .value = 0x00, },
+               [29] = { .offset = 0x98, .value = 0x00, },
+               [30] = { .offset = 0x99, .value = 0x00, },
+               [31] = { .offset = 0xf7, .value = 0x88, },
+               [32] = { .offset = 0xf8, .value = 0x0a, },
+               [33] = { .offset = 0x9c, .value = 0x24, },
+               [34] = { .offset = 0x9d, .value = 0x00, },
+               [35] = { .offset = 0x9e, .value = 0x25, },
+               [36] = { .offset = 0x9f, .value = 0x03, },
+               [37] = { .offset = 0xa0, .value = 0x28, },
+               [38] = { .offset = 0xa1, .value = 0x01, },
+               [39] = { .offset = 0xa2, .value = 0x28, },
+               [40] = { .offset = 0xa3, .value = 0x05, },
+               [41] = { .offset = 0xb6, .value = 0x09, },
+               [42] = { .offset = 0xb8, .value = 0x00, },
+               [43] = { .offset = 0xb9, .value = 0xa0, },
+               [44] = { .offset = 0xba, .value = 0x00, },
+               [45] = { .offset = 0xbb, .value = 0x20, },
+               [46] = { .offset = 0x10, .value = 0x00, },
+               [47] = { .offset = 0x11, .value = 0xa0, },
+               [48] = { .offset = 0x12, .value = 0x02, },
+               [49] = { .offset = 0x20, .value = 0x00, },
+               [50] = { .offset = 0x22, .value = 0x00, },
+               [51] = { .offset = 0x23, .value = 0x00, },
+               [52] = { .offset = 0x24, .value = 0x00, },
+               [53] = { .offset = 0x25, .value = 0x00, },
+               [54] = { .offset = 0x8c, .value = 0x10, },
+               [55] = { .offset = 0x8d, .value = 0x02, },
+               [56] = { .offset = 0x8e, .value = 0x10, },
+               [57] = { .offset = 0x8f, .value = 0x00, },
+               [58] = { .offset = 0x90, .value = 0xff, },
+               [59] = { .offset = 0x91, .value = 0x07, },
+               [60] = { .offset = 0x92, .value = 0xa0, },
+               [61] = { .offset = 0x93, .value = 0x02, },
+               [62] = { .offset = 0xa5, .value = 0x00, },
+               [63] = { .offset = 0xa6, .value = 0x00, },
+               [64] = { .offset = 0xa7, .value = 0x00, },
+               [65] = { .offset = 0xa8, .value = 0x00, },
+               [66] = { .offset = 0xa9, .value = 0x04, },
+               [67] = { .offset = 0xaa, .value = 0x70, },
+               [68] = { .offset = 0xab, .value = 0x4f, },
+               [69] = { .offset = 0xac, .value = 0x00, },
+               [70] = { .offset = 0xa4, .value = 0x84, },
+               [71] = { .offset = 0x7e, .value = 0x18, },
+               [72] = { .offset = 0x84, .value = 0x00, },
+               [73] = { .offset = 0x85, .value = 0x00, },
+               [74] = { .offset = 0x86, .value = 0x00, },
+               [75] = { .offset = 0x87, .value = 0x00, },
+               [76] = { .offset = 0x88, .value = 0x00, },
+               [77] = { .offset = 0x89, .value = 0x00, },
+               [78] = { .offset = 0x8a, .value = 0x00, },
+               [79] = { .offset = 0x8b, .value = 0x00, },
+               [80] = { .offset = 0x26, .value = 0x00, },
+               [81] = { .offset = 0x27, .value = 0x00, },
+               [82] = { .offset = 0xad, .value = 0x00, },
+               [83] = { .offset = 0x08, .value = 0x34, }, /* 0x35 */
+               [84] = { .offset = 0x41, .value = 0x00, },
+               [85] = { .offset = 0xc0, .value = 0x01, },
+       },
+};
+
+static const struct ns2501_reg regs_init[] = {
+       [0] = { .offset = 0x35, .value = 0xff, },
+       [1] = { .offset = 0x34, .value = 0x00, },
+       [2] = { .offset = 0x08, .value = 0x30, },
+};
+
 struct ns2501_priv {
-       //I2CDevRec d;
        bool quiet;
-       int reg_8_shadow;
-       int reg_8_set;
-       // Shadow registers for i915
-       int dvoc;
-       int pll_a;
-       int srcdim;
-       int fw_blc;
+       const struct ns2501_reg *regs;
 };
 
 #define NSPTR(d) ((NS2501Ptr)(d->DriverPrivate.ptr))
@@ -205,11 +486,9 @@ static bool ns2501_init(struct intel_dvo_device *dvo,
                goto out;
        }
        ns->quiet = false;
-       ns->reg_8_set = 0;
-       ns->reg_8_shadow =
-           NS2501_8_PD | NS2501_8_BPAS | NS2501_8_VEN | NS2501_8_HEN;
 
        DRM_DEBUG_KMS("init ns2501 dvo controller successfully!\n");
+
        return true;
 
 out:
@@ -242,9 +521,9 @@ static enum drm_mode_status ns2501_mode_valid(struct intel_dvo_device *dvo,
         * of the panel in here so we could always accept it
         * by disabling the scaler.
         */
-       if ((mode->hdisplay == 800 && mode->vdisplay == 600) ||
-           (mode->hdisplay == 640 && mode->vdisplay == 480) ||
-           (mode->hdisplay == 1024 && mode->vdisplay == 768)) {
+       if ((mode->hdisplay == 640 && mode->vdisplay == 480 && mode->clock == 25175) ||
+           (mode->hdisplay == 800 && mode->vdisplay == 600 && mode->clock == 40000) ||
+           (mode->hdisplay == 1024 && mode->vdisplay == 768 && mode->clock == 65000)) {
                return MODE_OK;
        } else {
                return MODE_ONE_SIZE;   /* Is this a reasonable error? */
@@ -255,180 +534,30 @@ static void ns2501_mode_set(struct intel_dvo_device *dvo,
                            struct drm_display_mode *mode,
                            struct drm_display_mode *adjusted_mode)
 {
-       bool ok;
-       int retries = 10;
        struct ns2501_priv *ns = (struct ns2501_priv *)(dvo->dev_priv);
+       int mode_idx, i;
 
        DRM_DEBUG_KMS
            ("set mode (hdisplay=%d,htotal=%d,vdisplay=%d,vtotal=%d).\n",
             mode->hdisplay, mode->htotal, mode->vdisplay, mode->vtotal);
 
-       /*
-        * Where do I find the native resolution for which scaling is not required???
-        *
-        * First trigger the DVO on as otherwise the chip does not appear on the i2c
-        * bus.
-        */
-       do {
-               ok = true;
-
-               if (mode->hdisplay == 800 && mode->vdisplay == 600) {
-                       /* mode 277 */
-                       ns->reg_8_shadow &= ~NS2501_8_BPAS;
-                       DRM_DEBUG_KMS("switching to 800x600\n");
-
-                       /*
-                        * No, I do not know where this data comes from.
-                        * It is just what the video bios left in the DVO, so
-                        * I'm just copying it here over.
-                        * This also means that I cannot support any other modes
-                        * except the ones supported by the bios.
-                        */
-                       ok &= ns2501_writeb(dvo, 0x11, 0xc8);   // 0xc7 also works.
-                       ok &= ns2501_writeb(dvo, 0x1b, 0x19);
-                       ok &= ns2501_writeb(dvo, 0x1c, 0x62);   // VBIOS left 0x64 here, but 0x62 works nicer
-                       ok &= ns2501_writeb(dvo, 0x1d, 0x02);
-
-                       ok &= ns2501_writeb(dvo, 0x34, 0x03);
-                       ok &= ns2501_writeb(dvo, 0x35, 0xff);
+       if (mode->hdisplay == 640 && mode->vdisplay == 480)
+               mode_idx = MODE_640x480;
+       else if (mode->hdisplay == 800 && mode->vdisplay == 600)
+               mode_idx = MODE_800x600;
+       else if (mode->hdisplay == 1024 && mode->vdisplay == 768)
+               mode_idx = MODE_1024x768;
+       else
+               return;
 
-                       ok &= ns2501_writeb(dvo, 0x80, 0x27);
-                       ok &= ns2501_writeb(dvo, 0x81, 0x03);
-                       ok &= ns2501_writeb(dvo, 0x82, 0x41);
-                       ok &= ns2501_writeb(dvo, 0x83, 0x05);
+       /* Hopefully doing it every time won't hurt... */
+       for (i = 0; i < ARRAY_SIZE(regs_init); i++)
+               ns2501_writeb(dvo, regs_init[i].offset, regs_init[i].value);
 
-                       ok &= ns2501_writeb(dvo, 0x8d, 0x02);
-                       ok &= ns2501_writeb(dvo, 0x8e, 0x04);
-                       ok &= ns2501_writeb(dvo, 0x8f, 0x00);
+       ns->regs = regs_1024x768[mode_idx];
 
-                       ok &= ns2501_writeb(dvo, 0x90, 0xfe);   /* vertical. VBIOS left 0xff here, but 0xfe works better */
-                       ok &= ns2501_writeb(dvo, 0x91, 0x07);
-                       ok &= ns2501_writeb(dvo, 0x94, 0x00);
-                       ok &= ns2501_writeb(dvo, 0x95, 0x00);
-
-                       ok &= ns2501_writeb(dvo, 0x96, 0x00);
-
-                       ok &= ns2501_writeb(dvo, 0x99, 0x00);
-                       ok &= ns2501_writeb(dvo, 0x9a, 0x88);
-
-                       ok &= ns2501_writeb(dvo, 0x9c, 0x23);   /* Looks like first and last line of the image. */
-                       ok &= ns2501_writeb(dvo, 0x9d, 0x00);
-                       ok &= ns2501_writeb(dvo, 0x9e, 0x25);
-                       ok &= ns2501_writeb(dvo, 0x9f, 0x03);
-
-                       ok &= ns2501_writeb(dvo, 0xa4, 0x80);
-
-                       ok &= ns2501_writeb(dvo, 0xb6, 0x00);
-
-                       ok &= ns2501_writeb(dvo, 0xb9, 0xc8);   /* horizontal? */
-                       ok &= ns2501_writeb(dvo, 0xba, 0x00);   /* horizontal? */
-
-                       ok &= ns2501_writeb(dvo, 0xc0, 0x05);   /* horizontal? */
-                       ok &= ns2501_writeb(dvo, 0xc1, 0xd7);
-
-                       ok &= ns2501_writeb(dvo, 0xc2, 0x00);
-                       ok &= ns2501_writeb(dvo, 0xc3, 0xf8);
-
-                       ok &= ns2501_writeb(dvo, 0xc4, 0x03);
-                       ok &= ns2501_writeb(dvo, 0xc5, 0x1a);
-
-                       ok &= ns2501_writeb(dvo, 0xc6, 0x00);
-                       ok &= ns2501_writeb(dvo, 0xc7, 0x73);
-                       ok &= ns2501_writeb(dvo, 0xc8, 0x02);
-
-               } else if (mode->hdisplay == 640 && mode->vdisplay == 480) {
-                       /* mode 274 */
-                       DRM_DEBUG_KMS("switching to 640x480\n");
-                       /*
-                        * No, I do not know where this data comes from.
-                        * It is just what the video bios left in the DVO, so
-                        * I'm just copying it here over.
-                        * This also means that I cannot support any other modes
-                        * except the ones supported by the bios.
-                        */
-                       ns->reg_8_shadow &= ~NS2501_8_BPAS;
-
-                       ok &= ns2501_writeb(dvo, 0x11, 0xa0);
-                       ok &= ns2501_writeb(dvo, 0x1b, 0x11);
-                       ok &= ns2501_writeb(dvo, 0x1c, 0x54);
-                       ok &= ns2501_writeb(dvo, 0x1d, 0x03);
-
-                       ok &= ns2501_writeb(dvo, 0x34, 0x03);
-                       ok &= ns2501_writeb(dvo, 0x35, 0xff);
-
-                       ok &= ns2501_writeb(dvo, 0x80, 0xff);
-                       ok &= ns2501_writeb(dvo, 0x81, 0x07);
-                       ok &= ns2501_writeb(dvo, 0x82, 0x3d);
-                       ok &= ns2501_writeb(dvo, 0x83, 0x05);
-
-                       ok &= ns2501_writeb(dvo, 0x8d, 0x02);
-                       ok &= ns2501_writeb(dvo, 0x8e, 0x10);
-                       ok &= ns2501_writeb(dvo, 0x8f, 0x00);
-
-                       ok &= ns2501_writeb(dvo, 0x90, 0xff);   /* vertical */
-                       ok &= ns2501_writeb(dvo, 0x91, 0x07);
-                       ok &= ns2501_writeb(dvo, 0x94, 0x00);
-                       ok &= ns2501_writeb(dvo, 0x95, 0x00);
-
-                       ok &= ns2501_writeb(dvo, 0x96, 0x05);
-
-                       ok &= ns2501_writeb(dvo, 0x99, 0x00);
-                       ok &= ns2501_writeb(dvo, 0x9a, 0x88);
-
-                       ok &= ns2501_writeb(dvo, 0x9c, 0x24);
-                       ok &= ns2501_writeb(dvo, 0x9d, 0x00);
-                       ok &= ns2501_writeb(dvo, 0x9e, 0x25);
-                       ok &= ns2501_writeb(dvo, 0x9f, 0x03);
-
-                       ok &= ns2501_writeb(dvo, 0xa4, 0x84);
-
-                       ok &= ns2501_writeb(dvo, 0xb6, 0x09);
-
-                       ok &= ns2501_writeb(dvo, 0xb9, 0xa0);   /* horizontal? */
-                       ok &= ns2501_writeb(dvo, 0xba, 0x00);   /* horizontal? */
-
-                       ok &= ns2501_writeb(dvo, 0xc0, 0x05);   /* horizontal? */
-                       ok &= ns2501_writeb(dvo, 0xc1, 0x90);
-
-                       ok &= ns2501_writeb(dvo, 0xc2, 0x00);
-                       ok &= ns2501_writeb(dvo, 0xc3, 0x0f);
-
-                       ok &= ns2501_writeb(dvo, 0xc4, 0x03);
-                       ok &= ns2501_writeb(dvo, 0xc5, 0x16);
-
-                       ok &= ns2501_writeb(dvo, 0xc6, 0x00);
-                       ok &= ns2501_writeb(dvo, 0xc7, 0x02);
-                       ok &= ns2501_writeb(dvo, 0xc8, 0x02);
-
-               } else if (mode->hdisplay == 1024 && mode->vdisplay == 768) {
-                       /* mode 280 */
-                       DRM_DEBUG_KMS("switching to 1024x768\n");
-                       /*
-                        * This might or might not work, actually. I'm silently
-                        * assuming here that the native panel resolution is
-                        * 1024x768. If not, then this leaves the scaler disabled
-                        * generating a picture that is likely not the expected.
-                        *
-                        * Problem is that I do not know where to take the panel
-                        * dimensions from.
-                        *
-                        * Enable the bypass, scaling not required.
-                        *
-                        * The scaler registers are irrelevant here....
-                        *
-                        */
-                       ns->reg_8_shadow |= NS2501_8_BPAS;
-                       ok &= ns2501_writeb(dvo, 0x37, 0x44);
-               } else {
-                       /*
-                        * Data not known. Bummer!
-                        * Hopefully, the code should not go here
-                        * as mode_OK delivered no other modes.
-                        */
-                       ns->reg_8_shadow |= NS2501_8_BPAS;
-               }
-               ok &= ns2501_writeb(dvo, NS2501_REG8, ns->reg_8_shadow);
-       } while (!ok && retries--);
+       for (i = 0; i < 84; i++)
+               ns2501_writeb(dvo, ns->regs[i].offset, ns->regs[i].value);
 }
 
 /* set the NS2501 power state */
@@ -439,60 +568,46 @@ static bool ns2501_get_hw_state(struct intel_dvo_device *dvo)
        if (!ns2501_readb(dvo, NS2501_REG8, &ch))
                return false;
 
-       if (ch & NS2501_8_PD)
-               return true;
-       else
-               return false;
+       return ch & NS2501_8_PD;
 }
 
 /* set the NS2501 power state */
 static void ns2501_dpms(struct intel_dvo_device *dvo, bool enable)
 {
-       bool ok;
-       int retries = 10;
        struct ns2501_priv *ns = (struct ns2501_priv *)(dvo->dev_priv);
-       unsigned char ch;
 
        DRM_DEBUG_KMS("Trying set the dpms of the DVO to %i\n", enable);
 
-       ch = ns->reg_8_shadow;
+       if (enable) {
+               if (WARN_ON(ns->regs[83].offset != 0x08 ||
+                           ns->regs[84].offset != 0x41 ||
+                           ns->regs[85].offset != 0xc0))
+                       return;
 
-       if (enable)
-               ch |= NS2501_8_PD;
-       else
-               ch &= ~NS2501_8_PD;
-
-       if (ns->reg_8_set == 0 || ns->reg_8_shadow != ch) {
-               ns->reg_8_set = 1;
-               ns->reg_8_shadow = ch;
-
-               do {
-                       ok = true;
-                       ok &= ns2501_writeb(dvo, NS2501_REG8, ch);
-                       ok &=
-                           ns2501_writeb(dvo, 0x34,
-                                         enable ? 0x03 : 0x00);
-                       ok &=
-                           ns2501_writeb(dvo, 0x35,
-                                         enable ? 0xff : 0x00);
-               } while (!ok && retries--);
-       }
-}
+               ns2501_writeb(dvo, 0xc0, ns->regs[85].value | 0x08);
 
-static void ns2501_dump_regs(struct intel_dvo_device *dvo)
-{
-       uint8_t val;
-
-       ns2501_readb(dvo, NS2501_FREQ_LO, &val);
-       DRM_DEBUG_KMS("NS2501_FREQ_LO: 0x%02x\n", val);
-       ns2501_readb(dvo, NS2501_FREQ_HI, &val);
-       DRM_DEBUG_KMS("NS2501_FREQ_HI: 0x%02x\n", val);
-       ns2501_readb(dvo, NS2501_REG8, &val);
-       DRM_DEBUG_KMS("NS2501_REG8: 0x%02x\n", val);
-       ns2501_readb(dvo, NS2501_REG9, &val);
-       DRM_DEBUG_KMS("NS2501_REG9: 0x%02x\n", val);
-       ns2501_readb(dvo, NS2501_REGC, &val);
-       DRM_DEBUG_KMS("NS2501_REGC: 0x%02x\n", val);
+               ns2501_writeb(dvo, 0x41, ns->regs[84].value);
+
+               ns2501_writeb(dvo, 0x34, 0x01);
+               msleep(15);
+
+               ns2501_writeb(dvo, 0x08, 0x35);
+               if (!(ns->regs[83].value & NS2501_8_BPAS))
+                       ns2501_writeb(dvo, 0x08, 0x31);
+               msleep(200);
+
+               ns2501_writeb(dvo, 0x34, 0x03);
+
+               ns2501_writeb(dvo, 0xc0, ns->regs[85].value);
+       } else {
+               ns2501_writeb(dvo, 0x34, 0x01);
+               msleep(200);
+
+               ns2501_writeb(dvo, 0x08, 0x34);
+               msleep(15);
+
+               ns2501_writeb(dvo, 0x34, 0x00);
+       }
 }
 
 static void ns2501_destroy(struct intel_dvo_device *dvo)
@@ -512,6 +627,5 @@ struct intel_dvo_dev_ops ns2501_ops = {
        .mode_set = ns2501_mode_set,
        .dpms = ns2501_dpms,
        .get_hw_state = ns2501_get_hw_state,
-       .dump_regs = ns2501_dump_regs,
        .destroy = ns2501_destroy,
 };
index 4b7ed52892173ea8fb595d7350f42eec20234591..593b657d3e59e21d3e73dac35086a64a850f8b69 100644 (file)
@@ -844,8 +844,6 @@ finish:
  */
 bool i915_needs_cmd_parser(struct intel_engine_cs *ring)
 {
-       struct drm_i915_private *dev_priv = ring->dev->dev_private;
-
        if (!ring->needs_cmd_parser)
                return false;
 
@@ -854,7 +852,7 @@ bool i915_needs_cmd_parser(struct intel_engine_cs *ring)
         * disabled. That will cause all of the parser's PPGTT checks to
         * fail. For now, disable parsing when PPGTT is off.
         */
-       if (!dev_priv->mm.aliasing_ppgtt)
+       if (USES_PPGTT(ring->dev))
                return false;
 
        return (i915.enable_cmd_parser == 1);
index 9e737b771c40ea2472f3e9f098cb91f363d75c23..063b44817e083649088f59f677fcc300679bd5ec 100644 (file)
@@ -136,7 +136,7 @@ describe_obj(struct seq_file *m, struct drm_i915_gem_object *obj)
                   obj->last_read_seqno,
                   obj->last_write_seqno,
                   obj->last_fenced_seqno,
-                  i915_cache_level_str(obj->cache_level),
+                  i915_cache_level_str(to_i915(obj->base.dev), obj->cache_level),
                   obj->dirty ? " dirty" : "",
                   obj->madv == I915_MADV_DONTNEED ? " purgeable" : "");
        if (obj->base.name)
@@ -333,7 +333,7 @@ static int per_file_stats(int id, void *ptr, void *data)
                        }
 
                        ppgtt = container_of(vma->vm, struct i915_hw_ppgtt, base);
-                       if (ppgtt->ctx && ppgtt->ctx->file_priv != stats->file_priv)
+                       if (ppgtt->file_priv != stats->file_priv)
                                continue;
 
                        if (obj->ring) /* XXX per-vma statistic */
@@ -515,6 +515,7 @@ static int i915_gem_pageflip_info(struct seq_file *m, void *data)
 {
        struct drm_info_node *node = m->private;
        struct drm_device *dev = node->minor->dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
        unsigned long flags;
        struct intel_crtc *crtc;
        int ret;
@@ -534,6 +535,8 @@ static int i915_gem_pageflip_info(struct seq_file *m, void *data)
                        seq_printf(m, "No flip due on pipe %c (plane %c)\n",
                                   pipe, plane);
                } else {
+                       u32 addr;
+
                        if (atomic_read(&work->pending) < INTEL_FLIP_COMPLETE) {
                                seq_printf(m, "Flip queued on pipe %c (plane %c)\n",
                                           pipe, plane);
@@ -541,23 +544,35 @@ static int i915_gem_pageflip_info(struct seq_file *m, void *data)
                                seq_printf(m, "Flip pending (waiting for vsync) on pipe %c (plane %c)\n",
                                           pipe, plane);
                        }
+                       if (work->flip_queued_ring) {
+                               seq_printf(m, "Flip queued on %s at seqno %u, next seqno %u [current breadcrumb %u], completed? %d\n",
+                                          work->flip_queued_ring->name,
+                                          work->flip_queued_seqno,
+                                          dev_priv->next_seqno,
+                                          work->flip_queued_ring->get_seqno(work->flip_queued_ring, true),
+                                          i915_seqno_passed(work->flip_queued_ring->get_seqno(work->flip_queued_ring, true),
+                                                            work->flip_queued_seqno));
+                       } else
+                               seq_printf(m, "Flip not associated with any ring\n");
+                       seq_printf(m, "Flip queued on frame %d, (was ready on frame %d), now %d\n",
+                                  work->flip_queued_vblank,
+                                  work->flip_ready_vblank,
+                                  drm_vblank_count(dev, crtc->pipe));
                        if (work->enable_stall_check)
                                seq_puts(m, "Stall check enabled, ");
                        else
                                seq_puts(m, "Stall check waiting for page flip ioctl, ");
                        seq_printf(m, "%d prepares\n", atomic_read(&work->pending));
 
-                       if (work->old_fb_obj) {
-                               struct drm_i915_gem_object *obj = work->old_fb_obj;
-                               if (obj)
-                                       seq_printf(m, "Old framebuffer gtt_offset 0x%08lx\n",
-                                                  i915_gem_obj_ggtt_offset(obj));
-                       }
+                       if (INTEL_INFO(dev)->gen >= 4)
+                               addr = I915_HI_DISPBASE(I915_READ(DSPSURF(crtc->plane)));
+                       else
+                               addr = I915_READ(DSPADDR(crtc->plane));
+                       seq_printf(m, "Current scanout address 0x%08x\n", addr);
+
                        if (work->pending_flip_obj) {
-                               struct drm_i915_gem_object *obj = work->pending_flip_obj;
-                               if (obj)
-                                       seq_printf(m, "New framebuffer gtt_offset 0x%08lx\n",
-                                                  i915_gem_obj_ggtt_offset(obj));
+                               seq_printf(m, "New framebuffer address 0x%08lx\n", (long)work->gtt_offset);
+                               seq_printf(m, "MMIO update completed? %d\n",  addr == work->gtt_offset);
                        }
                }
                spin_unlock_irqrestore(&dev->event_lock, flags);
@@ -650,7 +665,6 @@ static int i915_interrupt_info(struct seq_file *m, void *data)
        intel_runtime_pm_get(dev_priv);
 
        if (IS_CHERRYVIEW(dev)) {
-               int i;
                seq_printf(m, "Master Interrupt Control:\t%08x\n",
                           I915_READ(GEN8_MASTER_IRQ));
 
@@ -662,7 +676,7 @@ static int i915_interrupt_info(struct seq_file *m, void *data)
                           I915_READ(VLV_IIR_RW));
                seq_printf(m, "Display IMR:\t%08x\n",
                           I915_READ(VLV_IMR));
-               for_each_pipe(pipe)
+               for_each_pipe(dev_priv, pipe)
                        seq_printf(m, "Pipe %c stat:\t%08x\n",
                                   pipe_name(pipe),
                                   I915_READ(PIPESTAT(pipe)));
@@ -702,7 +716,13 @@ static int i915_interrupt_info(struct seq_file *m, void *data)
                                   i, I915_READ(GEN8_GT_IER(i)));
                }
 
-               for_each_pipe(pipe) {
+               for_each_pipe(dev_priv, pipe) {
+                       if (!intel_display_power_enabled(dev_priv,
+                                               POWER_DOMAIN_PIPE(pipe))) {
+                               seq_printf(m, "Pipe %c power disabled\n",
+                                          pipe_name(pipe));
+                               continue;
+                       }
                        seq_printf(m, "Pipe %c IMR:\t%08x\n",
                                   pipe_name(pipe),
                                   I915_READ(GEN8_DE_PIPE_IMR(pipe)));
@@ -743,7 +763,7 @@ static int i915_interrupt_info(struct seq_file *m, void *data)
                           I915_READ(VLV_IIR_RW));
                seq_printf(m, "Display IMR:\t%08x\n",
                           I915_READ(VLV_IMR));
-               for_each_pipe(pipe)
+               for_each_pipe(dev_priv, pipe)
                        seq_printf(m, "Pipe %c stat:\t%08x\n",
                                   pipe_name(pipe),
                                   I915_READ(PIPESTAT(pipe)));
@@ -779,7 +799,7 @@ static int i915_interrupt_info(struct seq_file *m, void *data)
                           I915_READ(IIR));
                seq_printf(m, "Interrupt mask:      %08x\n",
                           I915_READ(IMR));
-               for_each_pipe(pipe)
+               for_each_pipe(dev_priv, pipe)
                        seq_printf(m, "Pipe %c stat:         %08x\n",
                                   pipe_name(pipe),
                                   I915_READ(PIPESTAT(pipe)));
@@ -927,7 +947,7 @@ static ssize_t i915_error_state_read(struct file *file, char __user *userbuf,
        ssize_t ret_count = 0;
        int ret;
 
-       ret = i915_error_state_buf_init(&error_str, count, *pos);
+       ret = i915_error_state_buf_init(&error_str, to_i915(error_priv->dev), count, *pos);
        if (ret)
                return ret;
 
@@ -1024,6 +1044,7 @@ static int i915_frequency_info(struct seq_file *m, void *unused)
                u32 rpstat, cagf, reqf;
                u32 rpupei, rpcurup, rpprevup;
                u32 rpdownei, rpcurdown, rpprevdown;
+               u32 pm_ier, pm_imr, pm_isr, pm_iir, pm_mask;
                int max_freq;
 
                /* RPSTAT1 is in the GT power well */
@@ -1061,12 +1082,21 @@ static int i915_frequency_info(struct seq_file *m, void *unused)
                gen6_gt_force_wake_put(dev_priv, FORCEWAKE_ALL);
                mutex_unlock(&dev->struct_mutex);
 
+               if (IS_GEN6(dev) || IS_GEN7(dev)) {
+                       pm_ier = I915_READ(GEN6_PMIER);
+                       pm_imr = I915_READ(GEN6_PMIMR);
+                       pm_isr = I915_READ(GEN6_PMISR);
+                       pm_iir = I915_READ(GEN6_PMIIR);
+                       pm_mask = I915_READ(GEN6_PMINTRMSK);
+               } else {
+                       pm_ier = I915_READ(GEN8_GT_IER(2));
+                       pm_imr = I915_READ(GEN8_GT_IMR(2));
+                       pm_isr = I915_READ(GEN8_GT_ISR(2));
+                       pm_iir = I915_READ(GEN8_GT_IIR(2));
+                       pm_mask = I915_READ(GEN6_PMINTRMSK);
+               }
                seq_printf(m, "PM IER=0x%08x IMR=0x%08x ISR=0x%08x IIR=0x%08x, MASK=0x%08x\n",
-                          I915_READ(GEN6_PMIER),
-                          I915_READ(GEN6_PMIMR),
-                          I915_READ(GEN6_PMISR),
-                          I915_READ(GEN6_PMIIR),
-                          I915_READ(GEN6_PMINTRMSK));
+                          pm_ier, pm_imr, pm_isr, pm_iir, pm_mask);
                seq_printf(m, "GT_PERF_STATUS: 0x%08x\n", gt_perf_status);
                seq_printf(m, "Render p-state ratio: %d\n",
                           (gt_perf_status & 0xff00) >> 8);
@@ -1365,7 +1395,7 @@ static int i915_drpc_info(struct seq_file *m, void *unused)
 
        if (IS_VALLEYVIEW(dev))
                return vlv_drpc_info(m);
-       else if (IS_GEN6(dev) || IS_GEN7(dev))
+       else if (INTEL_INFO(dev)->gen >= 6)
                return gen6_drpc_info(m);
        else
                return ironlake_drpc_info(m);
@@ -1433,6 +1463,47 @@ static int i915_fbc_status(struct seq_file *m, void *unused)
        return 0;
 }
 
+static int i915_fbc_fc_get(void *data, u64 *val)
+{
+       struct drm_device *dev = data;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+
+       if (INTEL_INFO(dev)->gen < 7 || !HAS_FBC(dev))
+               return -ENODEV;
+
+       drm_modeset_lock_all(dev);
+       *val = dev_priv->fbc.false_color;
+       drm_modeset_unlock_all(dev);
+
+       return 0;
+}
+
+static int i915_fbc_fc_set(void *data, u64 val)
+{
+       struct drm_device *dev = data;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       u32 reg;
+
+       if (INTEL_INFO(dev)->gen < 7 || !HAS_FBC(dev))
+               return -ENODEV;
+
+       drm_modeset_lock_all(dev);
+
+       reg = I915_READ(ILK_DPFC_CONTROL);
+       dev_priv->fbc.false_color = val;
+
+       I915_WRITE(ILK_DPFC_CONTROL, val ?
+                  (reg | FBC_CTL_FALSE_COLOR) :
+                  (reg & ~FBC_CTL_FALSE_COLOR));
+
+       drm_modeset_unlock_all(dev);
+       return 0;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(i915_fbc_fc_fops,
+                       i915_fbc_fc_get, i915_fbc_fc_set,
+                       "%llu\n");
+
 static int i915_ips_status(struct seq_file *m, void *unused)
 {
        struct drm_info_node *node = m->private;
@@ -1630,6 +1701,14 @@ static int i915_gem_framebuffer_info(struct seq_file *m, void *data)
        return 0;
 }
 
+static void describe_ctx_ringbuf(struct seq_file *m,
+                                struct intel_ringbuffer *ringbuf)
+{
+       seq_printf(m, " (ringbuffer, space: %d, head: %u, tail: %u, last head: %d)",
+                  ringbuf->space, ringbuf->head, ringbuf->tail,
+                  ringbuf->last_retired_head);
+}
+
 static int i915_context_status(struct seq_file *m, void *unused)
 {
        struct drm_info_node *node = m->private;
@@ -1656,16 +1735,168 @@ static int i915_context_status(struct seq_file *m, void *unused)
        }
 
        list_for_each_entry(ctx, &dev_priv->context_list, link) {
-               if (ctx->legacy_hw_ctx.rcs_state == NULL)
+               if (!i915.enable_execlists &&
+                   ctx->legacy_hw_ctx.rcs_state == NULL)
                        continue;
 
                seq_puts(m, "HW context ");
                describe_ctx(m, ctx);
-               for_each_ring(ring, dev_priv, i)
+               for_each_ring(ring, dev_priv, i) {
+                       if (ring->default_context == ctx)
+                               seq_printf(m, "(default context %s) ",
+                                          ring->name);
+               }
+
+               if (i915.enable_execlists) {
+                       seq_putc(m, '\n');
+                       for_each_ring(ring, dev_priv, i) {
+                               struct drm_i915_gem_object *ctx_obj =
+                                       ctx->engine[i].state;
+                               struct intel_ringbuffer *ringbuf =
+                                       ctx->engine[i].ringbuf;
+
+                               seq_printf(m, "%s: ", ring->name);
+                               if (ctx_obj)
+                                       describe_obj(m, ctx_obj);
+                               if (ringbuf)
+                                       describe_ctx_ringbuf(m, ringbuf);
+                               seq_putc(m, '\n');
+                       }
+               } else {
+                       describe_obj(m, ctx->legacy_hw_ctx.rcs_state);
+               }
+
+               seq_putc(m, '\n');
+       }
+
+       mutex_unlock(&dev->struct_mutex);
+
+       return 0;
+}
+
+static int i915_dump_lrc(struct seq_file *m, void *unused)
+{
+       struct drm_info_node *node = (struct drm_info_node *) m->private;
+       struct drm_device *dev = node->minor->dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct intel_engine_cs *ring;
+       struct intel_context *ctx;
+       int ret, i;
+
+       if (!i915.enable_execlists) {
+               seq_printf(m, "Logical Ring Contexts are disabled\n");
+               return 0;
+       }
+
+       ret = mutex_lock_interruptible(&dev->struct_mutex);
+       if (ret)
+               return ret;
+
+       list_for_each_entry(ctx, &dev_priv->context_list, link) {
+               for_each_ring(ring, dev_priv, i) {
+                       struct drm_i915_gem_object *ctx_obj = ctx->engine[i].state;
+
                        if (ring->default_context == ctx)
-                               seq_printf(m, "(default context %s) ", ring->name);
+                               continue;
+
+                       if (ctx_obj) {
+                               struct page *page = i915_gem_object_get_page(ctx_obj, 1);
+                               uint32_t *reg_state = kmap_atomic(page);
+                               int j;
+
+                               seq_printf(m, "CONTEXT: %s %u\n", ring->name,
+                                               intel_execlists_ctx_id(ctx_obj));
+
+                               for (j = 0; j < 0x600 / sizeof(u32) / 4; j += 4) {
+                                       seq_printf(m, "\t[0x%08lx] 0x%08x 0x%08x 0x%08x 0x%08x\n",
+                                       i915_gem_obj_ggtt_offset(ctx_obj) + 4096 + (j * 4),
+                                       reg_state[j], reg_state[j + 1],
+                                       reg_state[j + 2], reg_state[j + 3]);
+                               }
+                               kunmap_atomic(reg_state);
+
+                               seq_putc(m, '\n');
+                       }
+               }
+       }
+
+       mutex_unlock(&dev->struct_mutex);
+
+       return 0;
+}
+
+static int i915_execlists(struct seq_file *m, void *data)
+{
+       struct drm_info_node *node = (struct drm_info_node *)m->private;
+       struct drm_device *dev = node->minor->dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct intel_engine_cs *ring;
+       u32 status_pointer;
+       u8 read_pointer;
+       u8 write_pointer;
+       u32 status;
+       u32 ctx_id;
+       struct list_head *cursor;
+       int ring_id, i;
+       int ret;
+
+       if (!i915.enable_execlists) {
+               seq_puts(m, "Logical Ring Contexts are disabled\n");
+               return 0;
+       }
+
+       ret = mutex_lock_interruptible(&dev->struct_mutex);
+       if (ret)
+               return ret;
+
+       for_each_ring(ring, dev_priv, ring_id) {
+               struct intel_ctx_submit_request *head_req = NULL;
+               int count = 0;
+               unsigned long flags;
+
+               seq_printf(m, "%s\n", ring->name);
+
+               status = I915_READ(RING_EXECLIST_STATUS(ring));
+               ctx_id = I915_READ(RING_EXECLIST_STATUS(ring) + 4);
+               seq_printf(m, "\tExeclist status: 0x%08X, context: %u\n",
+                          status, ctx_id);
+
+               status_pointer = I915_READ(RING_CONTEXT_STATUS_PTR(ring));
+               seq_printf(m, "\tStatus pointer: 0x%08X\n", status_pointer);
+
+               read_pointer = ring->next_context_status_buffer;
+               write_pointer = status_pointer & 0x07;
+               if (read_pointer > write_pointer)
+                       write_pointer += 6;
+               seq_printf(m, "\tRead pointer: 0x%08X, write pointer 0x%08X\n",
+                          read_pointer, write_pointer);
+
+               for (i = 0; i < 6; i++) {
+                       status = I915_READ(RING_CONTEXT_STATUS_BUF(ring) + 8*i);
+                       ctx_id = I915_READ(RING_CONTEXT_STATUS_BUF(ring) + 8*i + 4);
+
+                       seq_printf(m, "\tStatus buffer %d: 0x%08X, context: %u\n",
+                                  i, status, ctx_id);
+               }
+
+               spin_lock_irqsave(&ring->execlist_lock, flags);
+               list_for_each(cursor, &ring->execlist_queue)
+                       count++;
+               head_req = list_first_entry_or_null(&ring->execlist_queue,
+                               struct intel_ctx_submit_request, execlist_link);
+               spin_unlock_irqrestore(&ring->execlist_lock, flags);
+
+               seq_printf(m, "\t%d requests in queue\n", count);
+               if (head_req) {
+                       struct drm_i915_gem_object *ctx_obj;
+
+                       ctx_obj = head_req->ctx->engine[ring_id].state;
+                       seq_printf(m, "\tHead request id: %u\n",
+                                  intel_execlists_ctx_id(ctx_obj));
+                       seq_printf(m, "\tHead request tail: %u\n",
+                                  head_req->tail);
+               }
 
-               describe_obj(m, ctx->legacy_hw_ctx.rcs_state);
                seq_putc(m, '\n');
        }
 
@@ -1774,7 +2005,13 @@ static int per_file_ctx(int id, void *ptr, void *data)
 {
        struct intel_context *ctx = ptr;
        struct seq_file *m = data;
-       struct i915_hw_ppgtt *ppgtt = ctx_to_ppgtt(ctx);
+       struct i915_hw_ppgtt *ppgtt = ctx->ppgtt;
+
+       if (!ppgtt) {
+               seq_printf(m, "  no ppgtt for context %d\n",
+                          ctx->user_handle);
+               return 0;
+       }
 
        if (i915_gem_context_is_default(ctx))
                seq_puts(m, "  default context:\n");
@@ -1834,8 +2071,7 @@ static void gen6_ppgtt_info(struct seq_file *m, struct drm_device *dev)
                seq_printf(m, "pd gtt offset: 0x%08x\n", ppgtt->pd_offset);
 
                ppgtt->debug_dump(ppgtt, m);
-       } else
-               return;
+       }
 
        list_for_each_entry_reverse(file, &dev->filelist, lhead) {
                struct drm_i915_file_private *file_priv = file->driver_priv;
@@ -2406,6 +2642,40 @@ static int i915_shared_dplls_info(struct seq_file *m, void *unused)
        return 0;
 }
 
+static int i915_wa_registers(struct seq_file *m, void *unused)
+{
+       int i;
+       int ret;
+       struct drm_info_node *node = (struct drm_info_node *) m->private;
+       struct drm_device *dev = node->minor->dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+
+       ret = mutex_lock_interruptible(&dev->struct_mutex);
+       if (ret)
+               return ret;
+
+       intel_runtime_pm_get(dev_priv);
+
+       seq_printf(m, "Workarounds applied: %d\n", dev_priv->num_wa_regs);
+       for (i = 0; i < dev_priv->num_wa_regs; ++i) {
+               u32 addr, mask;
+
+               addr = dev_priv->intel_wa_regs[i].addr;
+               mask = dev_priv->intel_wa_regs[i].mask;
+               dev_priv->intel_wa_regs[i].value = I915_READ(addr) | mask;
+               if (dev_priv->intel_wa_regs[i].addr)
+                       seq_printf(m, "0x%X: 0x%08X, mask: 0x%08X\n",
+                                  dev_priv->intel_wa_regs[i].addr,
+                                  dev_priv->intel_wa_regs[i].value,
+                                  dev_priv->intel_wa_regs[i].mask);
+       }
+
+       intel_runtime_pm_put(dev_priv);
+       mutex_unlock(&dev->struct_mutex);
+
+       return 0;
+}
+
 struct pipe_crc_info {
        const char *name;
        struct drm_device *dev;
@@ -2667,8 +2937,7 @@ static int i9xx_pipe_crc_auto_source(struct drm_device *dev, enum pipe pipe,
        *source = INTEL_PIPE_CRC_SOURCE_PIPE;
 
        drm_modeset_lock_all(dev);
-       list_for_each_entry(encoder, &dev->mode_config.encoder_list,
-                           base.head) {
+       for_each_intel_encoder(dev, encoder) {
                if (!encoder->base.crtc)
                        continue;
 
@@ -3557,9 +3826,6 @@ i915_drop_caches_set(void *data, u64 val)
 {
        struct drm_device *dev = data;
        struct drm_i915_private *dev_priv = dev->dev_private;
-       struct drm_i915_gem_object *obj, *next;
-       struct i915_address_space *vm;
-       struct i915_vma *vma, *x;
        int ret;
 
        DRM_DEBUG("Dropping caches: 0x%08llx\n", val);
@@ -3579,29 +3845,11 @@ i915_drop_caches_set(void *data, u64 val)
        if (val & (DROP_RETIRE | DROP_ACTIVE))
                i915_gem_retire_requests(dev);
 
-       if (val & DROP_BOUND) {
-               list_for_each_entry(vm, &dev_priv->vm_list, global_link) {
-                       list_for_each_entry_safe(vma, x, &vm->inactive_list,
-                                                mm_list) {
-                               if (vma->pin_count)
-                                       continue;
+       if (val & DROP_BOUND)
+               i915_gem_shrink(dev_priv, LONG_MAX, I915_SHRINK_BOUND);
 
-                               ret = i915_vma_unbind(vma);
-                               if (ret)
-                                       goto unlock;
-                       }
-               }
-       }
-
-       if (val & DROP_UNBOUND) {
-               list_for_each_entry_safe(obj, next, &dev_priv->mm.unbound_list,
-                                        global_list)
-                       if (obj->pages_pin_count == 0) {
-                               ret = i915_gem_object_put_pages(obj);
-                               if (ret)
-                                       goto unlock;
-                       }
-       }
+       if (val & DROP_UNBOUND)
+               i915_gem_shrink(dev_priv, LONG_MAX, I915_SHRINK_UNBOUND);
 
 unlock:
        mutex_unlock(&dev->struct_mutex);
@@ -3923,6 +4171,8 @@ static const struct drm_info_list i915_debugfs_list[] = {
        {"i915_opregion", i915_opregion, 0},
        {"i915_gem_framebuffer", i915_gem_framebuffer_info, 0},
        {"i915_context_status", i915_context_status, 0},
+       {"i915_dump_lrc", i915_dump_lrc, 0},
+       {"i915_execlists", i915_execlists, 0},
        {"i915_gen6_forcewake_count", i915_gen6_forcewake_count_info, 0},
        {"i915_swizzle_info", i915_swizzle_info, 0},
        {"i915_ppgtt_info", i915_ppgtt_info, 0},
@@ -3936,6 +4186,7 @@ static const struct drm_info_list i915_debugfs_list[] = {
        {"i915_semaphore_status", i915_semaphore_status, 0},
        {"i915_shared_dplls_info", i915_shared_dplls_info, 0},
        {"i915_dp_mst_info", i915_dp_mst_info, 0},
+       {"i915_wa_registers", i915_wa_registers, 0},
 };
 #define I915_DEBUGFS_ENTRIES ARRAY_SIZE(i915_debugfs_list)
 
@@ -3957,6 +4208,7 @@ static const struct i915_debugfs_files {
        {"i915_pri_wm_latency", &i915_pri_wm_latency_fops},
        {"i915_spr_wm_latency", &i915_spr_wm_latency_fops},
        {"i915_cur_wm_latency", &i915_cur_wm_latency_fops},
+       {"i915_fbc_false_color", &i915_fbc_fc_fops},
 };
 
 void intel_display_crc_init(struct drm_device *dev)
@@ -3964,7 +4216,7 @@ void intel_display_crc_init(struct drm_device *dev)
        struct drm_i915_private *dev_priv = dev->dev_private;
        enum pipe pipe;
 
-       for_each_pipe(pipe) {
+       for_each_pipe(dev_priv, pipe) {
                struct intel_pipe_crc *pipe_crc = &dev_priv->pipe_crc[pipe];
 
                pipe_crc->opened = false;
index 9933c26017edae26a2bab5879e8be0543735c027..1403b01e821695cce6c42cb8b3704eb284aba17e 100644 (file)
 
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 
+#include <linux/async.h>
 #include <drm/drmP.h>
 #include <drm/drm_crtc_helper.h>
 #include <drm/drm_fb_helper.h>
+#include <drm/drm_legacy.h>
 #include "intel_drv.h"
 #include <drm/i915_drm.h>
 #include "i915_drv.h"
@@ -196,7 +198,7 @@ static int i915_initialize(struct drm_device *dev, drm_i915_init_t *init)
        struct drm_i915_master_private *master_priv = dev->primary->master->driver_priv;
        int ret;
 
-       master_priv->sarea = drm_getsarea(dev);
+       master_priv->sarea = drm_legacy_getsarea(dev);
        if (master_priv->sarea) {
                master_priv->sarea_priv = (drm_i915_sarea_t *)
                        ((u8 *)master_priv->sarea->handle + init->sarea_priv_offset);
@@ -999,7 +1001,7 @@ static int i915_getparam(struct drm_device *dev, void *data,
                value = HAS_WT(dev);
                break;
        case I915_PARAM_HAS_ALIASING_PPGTT:
-               value = dev_priv->mm.aliasing_ppgtt || USES_FULL_PPGTT(dev);
+               value = USES_PPGTT(dev);
                break;
        case I915_PARAM_HAS_WAIT_TIMEOUT:
                value = 1;
@@ -1355,8 +1357,6 @@ static int i915_load_modeset_init(struct drm_device *dev)
        if (ret)
                goto cleanup_irq;
 
-       INIT_WORK(&dev_priv->console_resume_work, intel_console_resume);
-
        intel_modeset_gem_init(dev);
 
        /* Always safe in the mode setting case. */
@@ -1382,7 +1382,7 @@ static int i915_load_modeset_init(struct drm_device *dev)
         * scanning against hotplug events. Hence do this first and ignore the
         * tiny window where we will loose hotplug notifactions.
         */
-       intel_fbdev_initial_config(dev);
+       async_schedule(intel_fbdev_initial_config, dev_priv);
 
        drm_kms_helper_poll_init(dev);
 
@@ -1393,7 +1393,6 @@ cleanup_gem:
        i915_gem_cleanup_ringbuffer(dev);
        i915_gem_context_fini(dev);
        mutex_unlock(&dev->struct_mutex);
-       WARN_ON(dev_priv->mm.aliasing_ppgtt);
 cleanup_irq:
        drm_irq_uninstall(dev);
 cleanup_gem_stolen:
@@ -1536,10 +1535,10 @@ static void intel_device_info_runtime_init(struct drm_device *dev)
        info = (struct intel_device_info *)&dev_priv->info;
 
        if (IS_VALLEYVIEW(dev))
-               for_each_pipe(pipe)
+               for_each_pipe(dev_priv, pipe)
                        info->num_sprites[pipe] = 2;
        else
-               for_each_pipe(pipe)
+               for_each_pipe(dev_priv, pipe)
                        info->num_sprites[pipe] = 1;
 
        if (i915.disable_display) {
@@ -1608,9 +1607,10 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
        dev->dev_private = dev_priv;
        dev_priv->dev = dev;
 
-       /* copy initial configuration to dev_priv->info */
+       /* Setup the write-once "constant" device info */
        device_info = (struct intel_device_info *)&dev_priv->info;
-       *device_info = *info;
+       memcpy(device_info, info, sizeof(dev_priv->info));
+       device_info->device_id = dev->pdev->device;
 
        spin_lock_init(&dev_priv->irq_lock);
        spin_lock_init(&dev_priv->gpu_error.lock);
@@ -1822,7 +1822,7 @@ out_mtrrfree:
        arch_phys_wc_del(dev_priv->gtt.mtrr);
        io_mapping_free(dev_priv->gtt.mappable);
 out_gtt:
-       dev_priv->gtt.base.cleanup(&dev_priv->gtt.base);
+       i915_global_gtt_cleanup(dev);
 out_regs:
        intel_uncore_fini(dev);
        pci_iounmap(dev->pdev, dev_priv->regs);
@@ -1869,7 +1869,6 @@ int i915_driver_unload(struct drm_device *dev)
        if (drm_core_check_feature(dev, DRIVER_MODESET)) {
                intel_fbdev_fini(dev);
                intel_modeset_cleanup(dev);
-               cancel_work_sync(&dev_priv->console_resume_work);
 
                /*
                 * free the memory space allocated for the child device
@@ -1902,7 +1901,6 @@ int i915_driver_unload(struct drm_device *dev)
                mutex_lock(&dev->struct_mutex);
                i915_gem_cleanup_ringbuffer(dev);
                i915_gem_context_fini(dev);
-               WARN_ON(dev_priv->mm.aliasing_ppgtt);
                mutex_unlock(&dev->struct_mutex);
                i915_gem_cleanup_stolen(dev);
 
@@ -1910,8 +1908,6 @@ int i915_driver_unload(struct drm_device *dev)
                        i915_free_hws(dev);
        }
 
-       WARN_ON(!list_empty(&dev_priv->vm_list));
-
        drm_vblank_cleanup(dev);
 
        intel_teardown_gmbus(dev);
@@ -1921,7 +1917,7 @@ int i915_driver_unload(struct drm_device *dev)
        destroy_workqueue(dev_priv->wq);
        pm_qos_remove_request(&dev_priv->pm_qos);
 
-       dev_priv->gtt.base.cleanup(&dev_priv->gtt.base);
+       i915_global_gtt_cleanup(dev);
 
        intel_uncore_fini(dev);
        if (dev_priv->regs != NULL)
@@ -1986,6 +1982,9 @@ void i915_driver_preclose(struct drm_device *dev, struct drm_file *file)
        i915_gem_context_close(dev, file);
        i915_gem_release(dev, file);
        mutex_unlock(&dev->struct_mutex);
+
+       if (drm_core_check_feature(dev, DRIVER_MODESET))
+               intel_modeset_preclose(dev, file);
 }
 
 void i915_driver_postclose(struct drm_device *dev, struct drm_file *file)
index e27cdbe9d524a79dbd4168febc15de0660e82d9f..055d5e7fbf12a14473c7b82f314630d1e5615b9c 100644 (file)
@@ -481,6 +481,10 @@ bool i915_semaphore_is_enabled(struct drm_device *dev)
        if (i915.semaphores >= 0)
                return i915.semaphores;
 
+       /* TODO: make semaphores and Execlists play nicely together */
+       if (i915.enable_execlists)
+               return false;
+
        /* Until we get further testing... */
        if (IS_GEN8(dev))
                return false;
@@ -524,6 +528,10 @@ static void intel_suspend_encoders(struct drm_i915_private *dev_priv)
        drm_modeset_unlock_all(dev);
 }
 
+static int intel_suspend_complete(struct drm_i915_private *dev_priv);
+static int intel_resume_prepare(struct drm_i915_private *dev_priv,
+                               bool rpm_resume);
+
 static int i915_drm_freeze(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
@@ -591,9 +599,7 @@ static int i915_drm_freeze(struct drm_device *dev)
        intel_uncore_forcewake_reset(dev, false);
        intel_opregion_fini(dev);
 
-       console_lock();
-       intel_fbdev_set_suspend(dev, FBINFO_STATE_SUSPENDED);
-       console_unlock();
+       intel_fbdev_set_suspend(dev, FBINFO_STATE_SUSPENDED, true);
 
        dev_priv->suspend_count++;
 
@@ -632,30 +638,20 @@ int i915_suspend(struct drm_device *dev, pm_message_t state)
        return 0;
 }
 
-void intel_console_resume(struct work_struct *work)
-{
-       struct drm_i915_private *dev_priv =
-               container_of(work, struct drm_i915_private,
-                            console_resume_work);
-       struct drm_device *dev = dev_priv->dev;
-
-       console_lock();
-       intel_fbdev_set_suspend(dev, FBINFO_STATE_RUNNING);
-       console_unlock();
-}
-
 static int i915_drm_thaw_early(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
+       int ret;
 
-       if (IS_HASWELL(dev) || IS_BROADWELL(dev))
-               hsw_disable_pc8(dev_priv);
+       ret = intel_resume_prepare(dev_priv, false);
+       if (ret)
+               DRM_ERROR("Resume prepare failed: %d,Continuing resume\n", ret);
 
        intel_uncore_early_sanitize(dev, true);
        intel_uncore_sanitize(dev);
        intel_power_domains_init_hw(dev_priv);
 
-       return 0;
+       return ret;
 }
 
 static int __i915_drm_thaw(struct drm_device *dev, bool restore_gtt_mappings)
@@ -714,17 +710,7 @@ static int __i915_drm_thaw(struct drm_device *dev, bool restore_gtt_mappings)
 
        intel_opregion_init(dev);
 
-       /*
-        * The console lock can be pretty contented on resume due
-        * to all the printk activity.  Try to keep it out of the hot
-        * path of resume if possible.
-        */
-       if (console_trylock()) {
-               intel_fbdev_set_suspend(dev, FBINFO_STATE_RUNNING);
-               console_unlock();
-       } else {
-               schedule_work(&dev_priv->console_resume_work);
-       }
+       intel_fbdev_set_suspend(dev, FBINFO_STATE_RUNNING, false);
 
        mutex_lock(&dev_priv->modeset_restore_lock);
        dev_priv->modeset_restore = MODESET_DONE;
@@ -858,7 +844,13 @@ int i915_reset(struct drm_device *dev)
                        !dev_priv->ums.mm_suspended) {
                dev_priv->ums.mm_suspended = 0;
 
+               /* Used to prevent gem_check_wedged returning -EAGAIN during gpu reset */
+               dev_priv->gpu_error.reload_in_reset = true;
+
                ret = i915_gem_init_hw(dev);
+
+               dev_priv->gpu_error.reload_in_reset = false;
+
                mutex_unlock(&dev->struct_mutex);
                if (ret) {
                        DRM_ERROR("Failed hw init on reset %d\n", ret);
@@ -879,8 +871,6 @@ int i915_reset(struct drm_device *dev)
                 */
                if (INTEL_INFO(dev)->gen > 5)
                        intel_reset_gt_powersave(dev);
-
-               intel_hpd_init(dev);
        } else {
                mutex_unlock(&dev->struct_mutex);
        }
@@ -941,6 +931,7 @@ static int i915_pm_suspend_late(struct device *dev)
        struct pci_dev *pdev = to_pci_dev(dev);
        struct drm_device *drm_dev = pci_get_drvdata(pdev);
        struct drm_i915_private *dev_priv = drm_dev->dev_private;
+       int ret;
 
        /*
         * We have a suspedn ordering issue with the snd-hda driver also
@@ -954,13 +945,16 @@ static int i915_pm_suspend_late(struct device *dev)
        if (drm_dev->switch_power_state == DRM_SWITCH_POWER_OFF)
                return 0;
 
-       if (IS_HASWELL(drm_dev) || IS_BROADWELL(drm_dev))
-               hsw_enable_pc8(dev_priv);
+       ret = intel_suspend_complete(dev_priv);
 
-       pci_disable_device(pdev);
-       pci_set_power_state(pdev, PCI_D3hot);
+       if (ret)
+               DRM_ERROR("Suspend complete failed: %d\n", ret);
+       else {
+               pci_disable_device(pdev);
+               pci_set_power_state(pdev, PCI_D3hot);
+       }
 
-       return 0;
+       return ret;
 }
 
 static int i915_pm_resume_early(struct device *dev)
@@ -1016,23 +1010,26 @@ static int i915_pm_poweroff(struct device *dev)
        return i915_drm_freeze(drm_dev);
 }
 
-static int hsw_runtime_suspend(struct drm_i915_private *dev_priv)
+static int hsw_suspend_complete(struct drm_i915_private *dev_priv)
 {
        hsw_enable_pc8(dev_priv);
 
        return 0;
 }
 
-static int snb_runtime_resume(struct drm_i915_private *dev_priv)
+static int snb_resume_prepare(struct drm_i915_private *dev_priv,
+                               bool rpm_resume)
 {
        struct drm_device *dev = dev_priv->dev;
 
-       intel_init_pch_refclk(dev);
+       if (rpm_resume)
+               intel_init_pch_refclk(dev);
 
        return 0;
 }
 
-static int hsw_runtime_resume(struct drm_i915_private *dev_priv)
+static int hsw_resume_prepare(struct drm_i915_private *dev_priv,
+                               bool rpm_resume)
 {
        hsw_disable_pc8(dev_priv);
 
@@ -1328,7 +1325,7 @@ static void vlv_check_no_gt_access(struct drm_i915_private *dev_priv)
        I915_WRITE(VLV_GTLC_PW_STATUS, VLV_GTLC_ALLOWWAKEERR);
 }
 
-static int vlv_runtime_suspend(struct drm_i915_private *dev_priv)
+static int vlv_suspend_complete(struct drm_i915_private *dev_priv)
 {
        u32 mask;
        int err;
@@ -1368,7 +1365,8 @@ err1:
        return err;
 }
 
-static int vlv_runtime_resume(struct drm_i915_private *dev_priv)
+static int vlv_resume_prepare(struct drm_i915_private *dev_priv,
+                               bool rpm_resume)
 {
        struct drm_device *dev = dev_priv->dev;
        int err;
@@ -1393,8 +1391,10 @@ static int vlv_runtime_resume(struct drm_i915_private *dev_priv)
 
        vlv_check_no_gt_access(dev_priv);
 
-       intel_init_clock_gating(dev);
-       i915_gem_restore_fences(dev);
+       if (rpm_resume) {
+               intel_init_clock_gating(dev);
+               i915_gem_restore_fences(dev);
+       }
 
        return ret;
 }
@@ -1409,7 +1409,9 @@ static int intel_runtime_suspend(struct device *device)
        if (WARN_ON_ONCE(!(dev_priv->rps.enabled && intel_enable_rc6(dev))))
                return -ENODEV;
 
-       WARN_ON(!HAS_RUNTIME_PM(dev));
+       if (WARN_ON_ONCE(!HAS_RUNTIME_PM(dev)))
+               return -ENODEV;
+
        assert_force_wake_inactive(dev_priv);
 
        DRM_DEBUG_KMS("Suspending device\n");
@@ -1446,17 +1448,7 @@ static int intel_runtime_suspend(struct device *device)
        cancel_work_sync(&dev_priv->rps.work);
        intel_runtime_pm_disable_interrupts(dev);
 
-       if (IS_GEN6(dev)) {
-               ret = 0;
-       } else if (IS_HASWELL(dev) || IS_BROADWELL(dev)) {
-               ret = hsw_runtime_suspend(dev_priv);
-       } else if (IS_VALLEYVIEW(dev)) {
-               ret = vlv_runtime_suspend(dev_priv);
-       } else {
-               ret = -ENODEV;
-               WARN_ON(1);
-       }
-
+       ret = intel_suspend_complete(dev_priv);
        if (ret) {
                DRM_ERROR("Runtime suspend failed, disabling it (%d)\n", ret);
                intel_runtime_pm_restore_interrupts(dev);
@@ -1468,13 +1460,29 @@ static int intel_runtime_suspend(struct device *device)
        dev_priv->pm.suspended = true;
 
        /*
-        * current versions of firmware which depend on this opregion
-        * notification have repurposed the D1 definition to mean
-        * "runtime suspended" vs. what you would normally expect (D3)
-        * to distinguish it from notifications that might be sent
-        * via the suspend path.
+        * FIXME: We really should find a document that references the arguments
+        * used below!
         */
-       intel_opregion_notify_adapter(dev, PCI_D1);
+       if (IS_HASWELL(dev)) {
+               /*
+                * current versions of firmware which depend on this opregion
+                * notification have repurposed the D1 definition to mean
+                * "runtime suspended" vs. what you would normally expect (D3)
+                * to distinguish it from notifications that might be sent via
+                * the suspend path.
+                */
+               intel_opregion_notify_adapter(dev, PCI_D1);
+       } else {
+               /*
+                * On Broadwell, if we use PCI_D1 the PCH DDI ports will stop
+                * being detected, and the call we do at intel_runtime_resume()
+                * won't be able to restore them. Since PCI_D3hot matches the
+                * actual specification and appears to be working, use it. Let's
+                * assume the other non-Haswell platforms will stay the same as
+                * Broadwell.
+                */
+               intel_opregion_notify_adapter(dev, PCI_D3hot);
+       }
 
        DRM_DEBUG_KMS("Device suspended\n");
        return 0;
@@ -1487,24 +1495,15 @@ static int intel_runtime_resume(struct device *device)
        struct drm_i915_private *dev_priv = dev->dev_private;
        int ret;
 
-       WARN_ON(!HAS_RUNTIME_PM(dev));
+       if (WARN_ON_ONCE(!HAS_RUNTIME_PM(dev)))
+               return -ENODEV;
 
        DRM_DEBUG_KMS("Resuming device\n");
 
        intel_opregion_notify_adapter(dev, PCI_D0);
        dev_priv->pm.suspended = false;
 
-       if (IS_GEN6(dev)) {
-               ret = snb_runtime_resume(dev_priv);
-       } else if (IS_HASWELL(dev) || IS_BROADWELL(dev)) {
-               ret = hsw_runtime_resume(dev_priv);
-       } else if (IS_VALLEYVIEW(dev)) {
-               ret = vlv_runtime_resume(dev_priv);
-       } else {
-               WARN_ON(1);
-               ret = -ENODEV;
-       }
-
+       ret = intel_resume_prepare(dev_priv, true);
        /*
         * No point of rolling back things in case of an error, as the best
         * we can do is to hope that things will still work (and disable RPM).
@@ -1523,6 +1522,48 @@ static int intel_runtime_resume(struct device *device)
        return ret;
 }
 
+/*
+ * This function implements common functionality of runtime and system
+ * suspend sequence.
+ */
+static int intel_suspend_complete(struct drm_i915_private *dev_priv)
+{
+       struct drm_device *dev = dev_priv->dev;
+       int ret;
+
+       if (IS_HASWELL(dev) || IS_BROADWELL(dev))
+               ret = hsw_suspend_complete(dev_priv);
+       else if (IS_VALLEYVIEW(dev))
+               ret = vlv_suspend_complete(dev_priv);
+       else
+               ret = 0;
+
+       return ret;
+}
+
+/*
+ * This function implements common functionality of runtime and system
+ * resume sequence. Variable rpm_resume used for implementing different
+ * code paths.
+ */
+static int intel_resume_prepare(struct drm_i915_private *dev_priv,
+                               bool rpm_resume)
+{
+       struct drm_device *dev = dev_priv->dev;
+       int ret;
+
+       if (IS_GEN6(dev))
+               ret = snb_resume_prepare(dev_priv, rpm_resume);
+       else if (IS_HASWELL(dev) || IS_BROADWELL(dev))
+               ret = hsw_resume_prepare(dev_priv, rpm_resume);
+       else if (IS_VALLEYVIEW(dev))
+               ret = vlv_resume_prepare(dev_priv, rpm_resume);
+       else
+               ret = 0;
+
+       return ret;
+}
+
 static const struct dev_pm_ops i915_pm_ops = {
        .suspend = i915_pm_suspend,
        .suspend_late = i915_pm_suspend_late,
@@ -1572,6 +1613,7 @@ static struct drm_driver driver = {
        .lastclose = i915_driver_lastclose,
        .preclose = i915_driver_preclose,
        .postclose = i915_driver_postclose,
+       .set_busid = drm_pci_set_busid,
 
        /* Used in place of i915_pm_ops for non-DRIVER_MODESET */
        .suspend = i915_suspend,
@@ -1663,6 +1705,8 @@ static void __exit i915_exit(void)
 module_init(i915_init);
 module_exit(i915_exit);
 
-MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_AUTHOR("Tungsten Graphics, Inc.");
+MODULE_AUTHOR("Intel Corporation");
+
 MODULE_DESCRIPTION(DRIVER_DESC);
 MODULE_LICENSE("GPL and additional rights");
index 3524306d8cfbf7b9d7e93b2bd076774eb69b36bc..16a6f6d187a193ca8cee8f9cae444a75aa7c4533 100644 (file)
 #include "i915_reg.h"
 #include "intel_bios.h"
 #include "intel_ringbuffer.h"
+#include "intel_lrc.h"
 #include "i915_gem_gtt.h"
+#include "i915_gem_render_state.h"
 #include <linux/io-mapping.h>
 #include <linux/i2c.h>
 #include <linux/i2c-algo-bit.h>
 #include <drm/intel-gtt.h>
+#include <drm/drm_legacy.h> /* for struct drm_dma_handle */
+#include <drm/drm_gem.h>
 #include <linux/backlight.h>
 #include <linux/hashtable.h>
 #include <linux/intel-iommu.h>
 /* General customization:
  */
 
-#define DRIVER_AUTHOR          "Tungsten Graphics, Inc."
-
 #define DRIVER_NAME            "i915"
 #define DRIVER_DESC            "Intel Graphics"
-#define DRIVER_DATE            "20140725"
+#define DRIVER_DATE            "20140905"
 
 enum pipe {
        INVALID_PIPE = -1,
@@ -162,7 +164,10 @@ enum hpd_pin {
         I915_GEM_DOMAIN_INSTRUCTION | \
         I915_GEM_DOMAIN_VERTEX)
 
-#define for_each_pipe(p) for ((p) = 0; (p) < INTEL_INFO(dev)->num_pipes; (p)++)
+#define for_each_pipe(__dev_priv, __p) \
+       for ((__p) = 0; (__p) < INTEL_INFO(__dev_priv)->num_pipes; (__p)++)
+#define for_each_plane(pipe, p) \
+       for ((p) = 0; (p) < INTEL_INFO(dev)->num_sprites[(pipe)] + 1; (p)++)
 #define for_each_sprite(p, s) for ((s) = 0; (s) < INTEL_INFO(dev)->num_sprites[(p)]; (s)++)
 
 #define for_each_crtc(dev, crtc) \
@@ -171,6 +176,11 @@ enum hpd_pin {
 #define for_each_intel_crtc(dev, intel_crtc) \
        list_for_each_entry(intel_crtc, &dev->mode_config.crtc_list, base.head)
 
+#define for_each_intel_encoder(dev, intel_encoder)             \
+       list_for_each_entry(intel_encoder,                      \
+                           &(dev)->mode_config.encoder_list,   \
+                           base.head)
+
 #define for_each_encoder_on_crtc(dev, __crtc, intel_encoder) \
        list_for_each_entry((intel_encoder), &(dev)->mode_config.encoder_list, base.head) \
                if ((intel_encoder)->base.crtc == (__crtc))
@@ -198,10 +208,13 @@ enum intel_dpll_id {
 #define I915_NUM_PLLS 2
 
 struct intel_dpll_hw_state {
+       /* i9xx, pch plls */
        uint32_t dpll;
        uint32_t dpll_md;
        uint32_t fp0;
        uint32_t fp1;
+
+       /* hsw, bdw */
        uint32_t wrpll;
 };
 
@@ -277,8 +290,10 @@ struct intel_opregion {
 struct intel_overlay;
 struct intel_overlay_error_state;
 
+struct drm_local_map;
+
 struct drm_i915_master_private {
-       drm_local_map_t *sarea;
+       struct drm_local_map *sarea;
        struct _drm_i915_sarea *sarea_priv;
 };
 #define I915_FENCE_REG_NONE -1
@@ -388,6 +403,7 @@ struct drm_i915_error_state {
                pid_t pid;
                char comm[TASK_COMM_LEN];
        } ring[I915_NUM_RINGS];
+
        struct drm_i915_error_buffer {
                u32 size;
                u32 name;
@@ -406,6 +422,7 @@ struct drm_i915_error_state {
        } **active_bo, **pinned_bo;
 
        u32 *active_bo_count, *pinned_bo_count;
+       u32 vm_count;
 };
 
 struct intel_connector;
@@ -551,6 +568,7 @@ struct intel_uncore {
 
 struct intel_device_info {
        u32 display_mmio_offset;
+       u16 device_id;
        u8 num_pipes:3;
        u8 num_sprites[I915_MAX_PIPES];
        u8 gen;
@@ -615,13 +633,21 @@ struct intel_context {
        uint8_t remap_slice;
        struct drm_i915_file_private *file_priv;
        struct i915_ctx_hang_stats hang_stats;
-       struct i915_address_space *vm;
+       struct i915_hw_ppgtt *ppgtt;
 
+       /* Legacy ring buffer submission */
        struct {
                struct drm_i915_gem_object *rcs_state;
                bool initialized;
        } legacy_hw_ctx;
 
+       /* Execlists */
+       bool rcs_initialized;
+       struct {
+               struct drm_i915_gem_object *state;
+               struct intel_ringbuffer *ringbuf;
+       } engine[I915_NUM_RINGS];
+
        struct list_head link;
 };
 
@@ -635,6 +661,8 @@ struct i915_fbc {
        struct drm_mm_node compressed_fb;
        struct drm_mm_node *compressed_llb;
 
+       bool false_color;
+
        struct intel_fbc_work {
                struct delayed_work work;
                struct drm_crtc *crtc;
@@ -688,6 +716,7 @@ enum intel_sbi_destination {
 #define QUIRK_LVDS_SSC_DISABLE (1<<1)
 #define QUIRK_INVERT_BRIGHTNESS (1<<2)
 #define QUIRK_BACKLIGHT_PRESENT (1<<3)
+#define QUIRK_PIPEB_FORCE (1<<4)
 
 struct intel_fbdev;
 struct intel_fbc_work;
@@ -1147,6 +1176,7 @@ struct i915_gem_mm {
 };
 
 struct drm_i915_error_state_buf {
+       struct drm_i915_private *i915;
        unsigned bytes;
        unsigned size;
        int err;
@@ -1219,6 +1249,9 @@ struct i915_gpu_error {
 
        /* For missed irq/seqno simulation. */
        unsigned int test_irq_rings;
+
+       /* Used to prevent gem_check_wedged returning -EAGAIN during gpu reset   */
+       bool reload_in_reset;
 };
 
 enum modeset_restore {
@@ -1228,6 +1261,12 @@ enum modeset_restore {
 };
 
 struct ddi_vbt_port_info {
+       /*
+        * This is an index in the HDMI/DVI DDI buffer translation table.
+        * The special value HDMI_LEVEL_SHIFT_UNKNOWN means the VBT didn't
+        * populate this field.
+        */
+#define HDMI_LEVEL_SHIFT_UNKNOWN       0xff
        uint8_t hdmi_level_shift;
 
        uint8_t supports_dvi:1;
@@ -1421,7 +1460,7 @@ struct drm_i915_private {
        struct drm_i915_gem_object *semaphore_obj;
        uint32_t last_seqno, next_seqno;
 
-       drm_dma_handle_t *status_page_dmah;
+       struct drm_dma_handle *status_page_dmah;
        struct resource mch_res;
 
        /* protects the irq masks */
@@ -1475,6 +1514,9 @@ struct drm_i915_private {
        /* LVDS info */
        bool no_aux_handshake;
 
+       /* protects panel power sequencer state */
+       struct mutex pps_mutex;
+
        struct drm_i915_fence_reg fence_regs[I915_MAX_NUM_FENCES]; /* assume 965 */
        int fence_reg_start; /* 4 if userland hasn't ioctl'd us yet */
        int num_fence_regs; /* 8 on pre-965, 16 otherwise */
@@ -1526,6 +1568,20 @@ struct drm_i915_private {
        struct intel_shared_dpll shared_dplls[I915_NUM_PLLS];
        int dpio_phy_iosf_port[I915_NUM_PHYS_VLV];
 
+       /*
+        * workarounds are currently applied at different places and
+        * changes are being done to consolidate them so exact count is
+        * not clear at this point, use a max value for now.
+        */
+#define I915_MAX_WA_REGS  16
+       struct {
+               u32 addr;
+               u32 value;
+               /* bitmask representing WA bits */
+               u32 mask;
+       } intel_wa_regs[I915_MAX_WA_REGS];
+       u32 num_wa_regs;
+
        /* Reclocking support */
        bool render_reclock_avail;
        bool lvds_downclock_avail;
@@ -1561,14 +1617,9 @@ struct drm_i915_private {
 #ifdef CONFIG_DRM_I915_FBDEV
        /* list of fbdev register on this device */
        struct intel_fbdev *fbdev;
+       struct work_struct fbdev_suspend_work;
 #endif
 
-       /*
-        * The console may be contended at resume, but we don't
-        * want it to block on it.
-        */
-       struct work_struct console_resume_work;
-
        struct drm_property *broadcast_rgb_property;
        struct drm_property *force_audio_property;
 
@@ -1614,12 +1665,28 @@ struct drm_i915_private {
         */
        struct workqueue_struct *dp_wq;
 
+       uint32_t bios_vgacntr;
+
        /* Old dri1 support infrastructure, beware the dragons ya fools entering
         * here! */
        struct i915_dri1_state dri1;
        /* Old ums support infrastructure, same warning applies. */
        struct i915_ums_state ums;
 
+       /* Abstract the submission mechanism (legacy ringbuffer or execlists) away */
+       struct {
+               int (*do_execbuf)(struct drm_device *dev, struct drm_file *file,
+                                 struct intel_engine_cs *ring,
+                                 struct intel_context *ctx,
+                                 struct drm_i915_gem_execbuffer2 *args,
+                                 struct list_head *vmas,
+                                 struct drm_i915_gem_object *batch_obj,
+                                 u64 exec_start, u32 flags);
+               int (*init_rings)(struct drm_device *dev);
+               void (*cleanup_ring)(struct intel_engine_cs *ring);
+               void (*stop_ring)(struct intel_engine_cs *ring);
+       } gt;
+
        /*
         * NOTE: This is the dri1/ums dungeon, don't add stuff here. Your patch
         * will be rejected. Instead look for a better place.
@@ -1761,13 +1828,6 @@ struct drm_i915_gem_object {
         * Only honoured if hardware has relevant pte bit
         */
        unsigned long gt_ro:1;
-
-       /*
-        * Is the GPU currently using a fence to access this buffer,
-        */
-       unsigned int pending_fenced_gpu_access:1;
-       unsigned int fenced_gpu_access:1;
-
        unsigned int cache_level:3;
 
        unsigned int has_aliasing_ppgtt_mapping:1;
@@ -1805,7 +1865,7 @@ struct drm_i915_gem_object {
        struct drm_file *pin_filp;
 
        /** for phy allocated objects */
-       drm_dma_handle_t *phys_handle;
+       struct drm_dma_handle *phys_handle;
 
        union {
                struct i915_gem_userptr {
@@ -1971,51 +2031,63 @@ struct drm_i915_cmd_table {
        int count;
 };
 
-#define INTEL_INFO(dev)        (&to_i915(dev)->info)
-
-#define IS_I830(dev)           ((dev)->pdev->device == 0x3577)
-#define IS_845G(dev)           ((dev)->pdev->device == 0x2562)
+/* Note that the (struct drm_i915_private *) cast is just to shut up gcc. */
+#define __I915__(p) ({ \
+       struct drm_i915_private *__p; \
+       if (__builtin_types_compatible_p(typeof(*p), struct drm_i915_private)) \
+               __p = (struct drm_i915_private *)p; \
+       else if (__builtin_types_compatible_p(typeof(*p), struct drm_device)) \
+               __p = to_i915((struct drm_device *)p); \
+       else \
+               BUILD_BUG(); \
+       __p; \
+})
+#define INTEL_INFO(p)  (&__I915__(p)->info)
+#define INTEL_DEVID(p) (INTEL_INFO(p)->device_id)
+
+#define IS_I830(dev)           (INTEL_DEVID(dev) == 0x3577)
+#define IS_845G(dev)           (INTEL_DEVID(dev) == 0x2562)
 #define IS_I85X(dev)           (INTEL_INFO(dev)->is_i85x)
-#define IS_I865G(dev)          ((dev)->pdev->device == 0x2572)
+#define IS_I865G(dev)          (INTEL_DEVID(dev) == 0x2572)
 #define IS_I915G(dev)          (INTEL_INFO(dev)->is_i915g)
-#define IS_I915GM(dev)         ((dev)->pdev->device == 0x2592)
-#define IS_I945G(dev)          ((dev)->pdev->device == 0x2772)
+#define IS_I915GM(dev)         (INTEL_DEVID(dev) == 0x2592)
+#define IS_I945G(dev)          (INTEL_DEVID(dev) == 0x2772)
 #define IS_I945GM(dev)         (INTEL_INFO(dev)->is_i945gm)
 #define IS_BROADWATER(dev)     (INTEL_INFO(dev)->is_broadwater)
 #define IS_CRESTLINE(dev)      (INTEL_INFO(dev)->is_crestline)
-#define IS_GM45(dev)           ((dev)->pdev->device == 0x2A42)
+#define IS_GM45(dev)           (INTEL_DEVID(dev) == 0x2A42)
 #define IS_G4X(dev)            (INTEL_INFO(dev)->is_g4x)
-#define IS_PINEVIEW_G(dev)     ((dev)->pdev->device == 0xa001)
-#define IS_PINEVIEW_M(dev)     ((dev)->pdev->device == 0xa011)
+#define IS_PINEVIEW_G(dev)     (INTEL_DEVID(dev) == 0xa001)
+#define IS_PINEVIEW_M(dev)     (INTEL_DEVID(dev) == 0xa011)
 #define IS_PINEVIEW(dev)       (INTEL_INFO(dev)->is_pineview)
 #define IS_G33(dev)            (INTEL_INFO(dev)->is_g33)
-#define IS_IRONLAKE_M(dev)     ((dev)->pdev->device == 0x0046)
+#define IS_IRONLAKE_M(dev)     (INTEL_DEVID(dev) == 0x0046)
 #define IS_IVYBRIDGE(dev)      (INTEL_INFO(dev)->is_ivybridge)
-#define IS_IVB_GT1(dev)                ((dev)->pdev->device == 0x0156 || \
-                                (dev)->pdev->device == 0x0152 || \
-                                (dev)->pdev->device == 0x015a)
-#define IS_SNB_GT1(dev)                ((dev)->pdev->device == 0x0102 || \
-                                (dev)->pdev->device == 0x0106 || \
-                                (dev)->pdev->device == 0x010A)
+#define IS_IVB_GT1(dev)                (INTEL_DEVID(dev) == 0x0156 || \
+                                INTEL_DEVID(dev) == 0x0152 || \
+                                INTEL_DEVID(dev) == 0x015a)
+#define IS_SNB_GT1(dev)                (INTEL_DEVID(dev) == 0x0102 || \
+                                INTEL_DEVID(dev) == 0x0106 || \
+                                INTEL_DEVID(dev) == 0x010A)
 #define IS_VALLEYVIEW(dev)     (INTEL_INFO(dev)->is_valleyview)
 #define IS_CHERRYVIEW(dev)     (INTEL_INFO(dev)->is_valleyview && IS_GEN8(dev))
 #define IS_HASWELL(dev)        (INTEL_INFO(dev)->is_haswell)
 #define IS_BROADWELL(dev)      (!INTEL_INFO(dev)->is_valleyview && IS_GEN8(dev))
 #define IS_MOBILE(dev)         (INTEL_INFO(dev)->is_mobile)
 #define IS_HSW_EARLY_SDV(dev)  (IS_HASWELL(dev) && \
-                                ((dev)->pdev->device & 0xFF00) == 0x0C00)
+                                (INTEL_DEVID(dev) & 0xFF00) == 0x0C00)
 #define IS_BDW_ULT(dev)                (IS_BROADWELL(dev) && \
-                                (((dev)->pdev->device & 0xf) == 0x2  || \
-                                ((dev)->pdev->device & 0xf) == 0x6 || \
-                                ((dev)->pdev->device & 0xf) == 0xe))
+                                ((INTEL_DEVID(dev) & 0xf) == 0x2  || \
+                                (INTEL_DEVID(dev) & 0xf) == 0x6 || \
+                                (INTEL_DEVID(dev) & 0xf) == 0xe))
 #define IS_HSW_ULT(dev)                (IS_HASWELL(dev) && \
-                                ((dev)->pdev->device & 0xFF00) == 0x0A00)
+                                (INTEL_DEVID(dev) & 0xFF00) == 0x0A00)
 #define IS_ULT(dev)            (IS_HSW_ULT(dev) || IS_BDW_ULT(dev))
 #define IS_HSW_GT3(dev)                (IS_HASWELL(dev) && \
-                                ((dev)->pdev->device & 0x00F0) == 0x0020)
+                                (INTEL_DEVID(dev) & 0x00F0) == 0x0020)
 /* ULX machines are also considered ULT. */
-#define IS_HSW_ULX(dev)                ((dev)->pdev->device == 0x0A0E || \
-                                (dev)->pdev->device == 0x0A1E)
+#define IS_HSW_ULX(dev)                (INTEL_DEVID(dev) == 0x0A0E || \
+                                INTEL_DEVID(dev) == 0x0A1E)
 #define IS_PRELIMINARY_HW(intel_info) ((intel_info)->is_preliminary)
 
 /*
@@ -2047,10 +2119,11 @@ struct drm_i915_cmd_table {
 #define I915_NEED_GFX_HWS(dev) (INTEL_INFO(dev)->need_gfx_hws)
 
 #define HAS_HW_CONTEXTS(dev)   (INTEL_INFO(dev)->gen >= 6)
+#define HAS_LOGICAL_RING_CONTEXTS(dev) (INTEL_INFO(dev)->gen >= 8)
 #define HAS_ALIASING_PPGTT(dev)        (INTEL_INFO(dev)->gen >= 6)
 #define HAS_PPGTT(dev)         (INTEL_INFO(dev)->gen >= 7 && !IS_GEN8(dev))
-#define USES_PPGTT(dev)                intel_enable_ppgtt(dev, false)
-#define USES_FULL_PPGTT(dev)   intel_enable_ppgtt(dev, true)
+#define USES_PPGTT(dev)                (i915.enable_ppgtt)
+#define USES_FULL_PPGTT(dev)   (i915.enable_ppgtt == 2)
 
 #define HAS_OVERLAY(dev)               (INTEL_INFO(dev)->has_overlay)
 #define OVERLAY_NEEDS_PHYSICAL(dev)    (INTEL_INFO(dev)->overlay_needs_physical)
@@ -2134,6 +2207,7 @@ struct i915_params {
        int enable_rc6;
        int enable_fbc;
        int enable_ppgtt;
+       int enable_execlists;
        int enable_psr;
        unsigned int preliminary_hw_support;
        int disable_power_well;
@@ -2180,8 +2254,6 @@ extern void i915_update_gfx_val(struct drm_i915_private *dev_priv);
 int vlv_force_gfx_clock(struct drm_i915_private *dev_priv, bool on);
 void intel_hpd_cancel_work(struct drm_i915_private *dev_priv);
 
-extern void intel_console_resume(struct work_struct *work);
-
 /* i915_irq.c */
 void i915_queue_hangcheck(struct drm_device *dev);
 __printf(3, 4)
@@ -2229,6 +2301,20 @@ int i915_gem_set_domain_ioctl(struct drm_device *dev, void *data,
                              struct drm_file *file_priv);
 int i915_gem_sw_finish_ioctl(struct drm_device *dev, void *data,
                             struct drm_file *file_priv);
+void i915_gem_execbuffer_move_to_active(struct list_head *vmas,
+                                       struct intel_engine_cs *ring);
+void i915_gem_execbuffer_retire_commands(struct drm_device *dev,
+                                        struct drm_file *file,
+                                        struct intel_engine_cs *ring,
+                                        struct drm_i915_gem_object *obj);
+int i915_gem_ringbuffer_submission(struct drm_device *dev,
+                                  struct drm_file *file,
+                                  struct intel_engine_cs *ring,
+                                  struct intel_context *ctx,
+                                  struct drm_i915_gem_execbuffer2 *args,
+                                  struct list_head *vmas,
+                                  struct drm_i915_gem_object *batch_obj,
+                                  u64 exec_start, u32 flags);
 int i915_gem_execbuffer(struct drm_device *dev, void *data,
                        struct drm_file *file_priv);
 int i915_gem_execbuffer2(struct drm_device *dev, void *data,
@@ -2263,6 +2349,12 @@ int i915_gem_get_aperture_ioctl(struct drm_device *dev, void *data,
 int i915_gem_wait_ioctl(struct drm_device *dev, void *data,
                        struct drm_file *file_priv);
 void i915_gem_load(struct drm_device *dev);
+unsigned long i915_gem_shrink(struct drm_i915_private *dev_priv,
+                             long target,
+                             unsigned flags);
+#define I915_SHRINK_PURGEABLE 0x1
+#define I915_SHRINK_UNBOUND 0x2
+#define I915_SHRINK_BOUND 0x4
 void *i915_gem_object_alloc(struct drm_device *dev);
 void i915_gem_object_free(struct drm_i915_gem_object *obj);
 void i915_gem_object_init(struct drm_i915_gem_object *obj,
@@ -2381,6 +2473,7 @@ void i915_gem_reset(struct drm_device *dev);
 bool i915_gem_clflush_object(struct drm_i915_gem_object *obj, bool force);
 int __must_check i915_gem_object_finish_gpu(struct drm_i915_gem_object *obj);
 int __must_check i915_gem_init(struct drm_device *dev);
+int i915_gem_init_rings(struct drm_device *dev);
 int __must_check i915_gem_init_hw(struct drm_device *dev);
 int i915_gem_l3_remap(struct intel_engine_cs *ring, int slice);
 void i915_gem_init_swizzling(struct drm_device *dev);
@@ -2451,7 +2544,7 @@ static inline bool i915_gem_obj_is_pinned(struct drm_i915_gem_object *obj) {
 }
 
 /* Some GGTT VM helpers */
-#define obj_to_ggtt(obj) \
+#define i915_obj_to_ggtt(obj) \
        (&((struct drm_i915_private *)(obj)->base.dev->dev_private)->gtt.base)
 static inline bool i915_is_ggtt(struct i915_address_space *vm)
 {
@@ -2460,21 +2553,30 @@ static inline bool i915_is_ggtt(struct i915_address_space *vm)
        return vm == ggtt;
 }
 
+static inline struct i915_hw_ppgtt *
+i915_vm_to_ppgtt(struct i915_address_space *vm)
+{
+       WARN_ON(i915_is_ggtt(vm));
+
+       return container_of(vm, struct i915_hw_ppgtt, base);
+}
+
+
 static inline bool i915_gem_obj_ggtt_bound(struct drm_i915_gem_object *obj)
 {
-       return i915_gem_obj_bound(obj, obj_to_ggtt(obj));
+       return i915_gem_obj_bound(obj, i915_obj_to_ggtt(obj));
 }
 
 static inline unsigned long
 i915_gem_obj_ggtt_offset(struct drm_i915_gem_object *obj)
 {
-       return i915_gem_obj_offset(obj, obj_to_ggtt(obj));
+       return i915_gem_obj_offset(obj, i915_obj_to_ggtt(obj));
 }
 
 static inline unsigned long
 i915_gem_obj_ggtt_size(struct drm_i915_gem_object *obj)
 {
-       return i915_gem_obj_size(obj, obj_to_ggtt(obj));
+       return i915_gem_obj_size(obj, i915_obj_to_ggtt(obj));
 }
 
 static inline int __must_check
@@ -2482,7 +2584,8 @@ i915_gem_obj_ggtt_pin(struct drm_i915_gem_object *obj,
                      uint32_t alignment,
                      unsigned flags)
 {
-       return i915_gem_object_pin(obj, obj_to_ggtt(obj), alignment, flags | PIN_GLOBAL);
+       return i915_gem_object_pin(obj, i915_obj_to_ggtt(obj),
+                                  alignment, flags | PIN_GLOBAL);
 }
 
 static inline int
@@ -2494,7 +2597,6 @@ i915_gem_object_ggtt_unbind(struct drm_i915_gem_object *obj)
 void i915_gem_object_ggtt_unpin(struct drm_i915_gem_object *obj);
 
 /* i915_gem_context.c */
-#define ctx_to_ppgtt(ctx) container_of((ctx)->vm, struct i915_hw_ppgtt, base)
 int __must_check i915_gem_context_init(struct drm_device *dev);
 void i915_gem_context_fini(struct drm_device *dev);
 void i915_gem_context_reset(struct drm_device *dev);
@@ -2506,6 +2608,8 @@ int i915_switch_context(struct intel_engine_cs *ring,
 struct intel_context *
 i915_gem_context_get(struct drm_i915_file_private *file_priv, u32 id);
 void i915_gem_context_free(struct kref *ctx_ref);
+struct drm_i915_gem_object *
+i915_gem_alloc_context_obj(struct drm_device *dev, size_t size);
 static inline void i915_gem_context_reference(struct intel_context *ctx)
 {
        kref_get(&ctx->ref);
@@ -2526,8 +2630,6 @@ int i915_gem_context_create_ioctl(struct drm_device *dev, void *data,
 int i915_gem_context_destroy_ioctl(struct drm_device *dev, void *data,
                                   struct drm_file *file);
 
-/* i915_gem_render_state.c */
-int i915_gem_render_state_init(struct intel_engine_cs *ring);
 /* i915_gem_evict.c */
 int __must_check i915_gem_evict_something(struct drm_device *dev,
                                          struct i915_address_space *vm,
@@ -2595,6 +2697,7 @@ void i915_error_printf(struct drm_i915_error_state_buf *e, const char *f, ...);
 int i915_error_state_to_str(struct drm_i915_error_state_buf *estr,
                            const struct i915_error_state_file_priv *error);
 int i915_error_state_buf_init(struct drm_i915_error_state_buf *eb,
+                             struct drm_i915_private *i915,
                              size_t count, loff_t pos);
 static inline void i915_error_state_buf_release(
        struct drm_i915_error_state_buf *eb)
@@ -2609,7 +2712,7 @@ void i915_error_state_put(struct i915_error_state_file_priv *error_priv);
 void i915_destroy_error_state(struct drm_device *dev);
 
 void i915_get_extra_instdone(struct drm_device *dev, uint32_t *instdone);
-const char *i915_cache_level_str(int type);
+const char *i915_cache_level_str(struct drm_i915_private *i915, int type);
 
 /* i915_cmd_parser.c */
 int i915_cmd_parser_get_version(void);
@@ -2701,6 +2804,7 @@ extern void intel_modeset_setup_hw_state(struct drm_device *dev,
 extern void i915_redisable_vga(struct drm_device *dev);
 extern void i915_redisable_vga_power_on(struct drm_device *dev);
 extern bool intel_fbc_enabled(struct drm_device *dev);
+extern void gen8_fbc_sw_flush(struct drm_device *dev, u32 value);
 extern void intel_disable_fbc(struct drm_device *dev);
 extern bool ironlake_set_drps(struct drm_device *dev, u8 val);
 extern void intel_init_pch_refclk(struct drm_device *dev);
index ad55b06a3cb1c69754fe60947a183e0af6604e46..28f91df2604db0bfb867a548e701a5e9a48b7fa3 100644 (file)
@@ -60,7 +60,6 @@ static unsigned long i915_gem_shrinker_scan(struct shrinker *shrinker,
 static int i915_gem_shrinker_oom(struct notifier_block *nb,
                                 unsigned long event,
                                 void *ptr);
-static unsigned long i915_gem_purge(struct drm_i915_private *dev_priv, long target);
 static unsigned long i915_gem_shrink_all(struct drm_i915_private *dev_priv);
 
 static bool cpu_cache_is_coherent(struct drm_device *dev,
@@ -1085,7 +1084,13 @@ i915_gem_check_wedge(struct i915_gpu_error *error,
                if (i915_terminally_wedged(error))
                        return -EIO;
 
-               return -EAGAIN;
+               /*
+                * Check if GPU Reset is in progress - we need intel_ring_begin
+                * to work properly to reinit the hw state while the gpu is
+                * still marked as reset-in-progress. Handle this with a flag.
+                */
+               if (!error->reload_in_reset)
+                       return -EAGAIN;
        }
 
        return 0;
@@ -1735,7 +1740,11 @@ static int i915_gem_object_create_mmap_offset(struct drm_i915_gem_object *obj)
         * offsets on purgeable objects by truncating it and marking it purged,
         * which prevents userspace from ever using that object again.
         */
-       i915_gem_purge(dev_priv, obj->base.size >> PAGE_SHIFT);
+       i915_gem_shrink(dev_priv,
+                       obj->base.size >> PAGE_SHIFT,
+                       I915_SHRINK_BOUND |
+                       I915_SHRINK_UNBOUND |
+                       I915_SHRINK_PURGEABLE);
        ret = drm_gem_create_mmap_offset(&obj->base);
        if (ret != -ENOSPC)
                goto out;
@@ -1932,12 +1941,11 @@ i915_gem_object_put_pages(struct drm_i915_gem_object *obj)
        return 0;
 }
 
-static unsigned long
-__i915_gem_shrink(struct drm_i915_private *dev_priv, long target,
-                 bool purgeable_only)
+unsigned long
+i915_gem_shrink(struct drm_i915_private *dev_priv,
+               long target, unsigned flags)
 {
-       struct list_head still_in_list;
-       struct drm_i915_gem_object *obj;
+       const bool purgeable_only = flags & I915_SHRINK_PURGEABLE;
        unsigned long count = 0;
 
        /*
@@ -1959,62 +1967,68 @@ __i915_gem_shrink(struct drm_i915_private *dev_priv, long target,
         * dev->struct_mutex and so we won't ever be able to observe an
         * object on the bound_list with a reference count equals 0.
         */
-       INIT_LIST_HEAD(&still_in_list);
-       while (count < target && !list_empty(&dev_priv->mm.unbound_list)) {
-               obj = list_first_entry(&dev_priv->mm.unbound_list,
-                                      typeof(*obj), global_list);
-               list_move_tail(&obj->global_list, &still_in_list);
+       if (flags & I915_SHRINK_UNBOUND) {
+               struct list_head still_in_list;
 
-               if (!i915_gem_object_is_purgeable(obj) && purgeable_only)
-                       continue;
+               INIT_LIST_HEAD(&still_in_list);
+               while (count < target && !list_empty(&dev_priv->mm.unbound_list)) {
+                       struct drm_i915_gem_object *obj;
 
-               drm_gem_object_reference(&obj->base);
+                       obj = list_first_entry(&dev_priv->mm.unbound_list,
+                                              typeof(*obj), global_list);
+                       list_move_tail(&obj->global_list, &still_in_list);
 
-               if (i915_gem_object_put_pages(obj) == 0)
-                       count += obj->base.size >> PAGE_SHIFT;
+                       if (!i915_gem_object_is_purgeable(obj) && purgeable_only)
+                               continue;
 
-               drm_gem_object_unreference(&obj->base);
+                       drm_gem_object_reference(&obj->base);
+
+                       if (i915_gem_object_put_pages(obj) == 0)
+                               count += obj->base.size >> PAGE_SHIFT;
+
+                       drm_gem_object_unreference(&obj->base);
+               }
+               list_splice(&still_in_list, &dev_priv->mm.unbound_list);
        }
-       list_splice(&still_in_list, &dev_priv->mm.unbound_list);
 
-       INIT_LIST_HEAD(&still_in_list);
-       while (count < target && !list_empty(&dev_priv->mm.bound_list)) {
-               struct i915_vma *vma, *v;
+       if (flags & I915_SHRINK_BOUND) {
+               struct list_head still_in_list;
 
-               obj = list_first_entry(&dev_priv->mm.bound_list,
-                                      typeof(*obj), global_list);
-               list_move_tail(&obj->global_list, &still_in_list);
+               INIT_LIST_HEAD(&still_in_list);
+               while (count < target && !list_empty(&dev_priv->mm.bound_list)) {
+                       struct drm_i915_gem_object *obj;
+                       struct i915_vma *vma, *v;
 
-               if (!i915_gem_object_is_purgeable(obj) && purgeable_only)
-                       continue;
+                       obj = list_first_entry(&dev_priv->mm.bound_list,
+                                              typeof(*obj), global_list);
+                       list_move_tail(&obj->global_list, &still_in_list);
 
-               drm_gem_object_reference(&obj->base);
+                       if (!i915_gem_object_is_purgeable(obj) && purgeable_only)
+                               continue;
 
-               list_for_each_entry_safe(vma, v, &obj->vma_list, vma_link)
-                       if (i915_vma_unbind(vma))
-                               break;
+                       drm_gem_object_reference(&obj->base);
 
-               if (i915_gem_object_put_pages(obj) == 0)
-                       count += obj->base.size >> PAGE_SHIFT;
+                       list_for_each_entry_safe(vma, v, &obj->vma_list, vma_link)
+                               if (i915_vma_unbind(vma))
+                                       break;
 
-               drm_gem_object_unreference(&obj->base);
+                       if (i915_gem_object_put_pages(obj) == 0)
+                               count += obj->base.size >> PAGE_SHIFT;
+
+                       drm_gem_object_unreference(&obj->base);
+               }
+               list_splice(&still_in_list, &dev_priv->mm.bound_list);
        }
-       list_splice(&still_in_list, &dev_priv->mm.bound_list);
 
        return count;
 }
 
-static unsigned long
-i915_gem_purge(struct drm_i915_private *dev_priv, long target)
-{
-       return __i915_gem_shrink(dev_priv, target, true);
-}
-
 static unsigned long
 i915_gem_shrink_all(struct drm_i915_private *dev_priv)
 {
        i915_gem_evict_everything(dev_priv->dev);
-       return __i915_gem_shrink(dev_priv, LONG_MAX, false);
+       return i915_gem_shrink(dev_priv, LONG_MAX,
+                              I915_SHRINK_BOUND | I915_SHRINK_UNBOUND);
 }
 
 static int
@@ -2061,7 +2075,11 @@ i915_gem_object_get_pages_gtt(struct drm_i915_gem_object *obj)
        for (i = 0; i < page_count; i++) {
                page = shmem_read_mapping_page_gfp(mapping, i, gfp);
                if (IS_ERR(page)) {
-                       i915_gem_purge(dev_priv, page_count);
+                       i915_gem_shrink(dev_priv,
+                                       page_count,
+                                       I915_SHRINK_BOUND |
+                                       I915_SHRINK_UNBOUND |
+                                       I915_SHRINK_PURGEABLE);
                        page = shmem_read_mapping_page_gfp(mapping, i, gfp);
                }
                if (IS_ERR(page)) {
@@ -2163,8 +2181,6 @@ static void
 i915_gem_object_move_to_active(struct drm_i915_gem_object *obj,
                               struct intel_engine_cs *ring)
 {
-       struct drm_device *dev = obj->base.dev;
-       struct drm_i915_private *dev_priv = dev->dev_private;
        u32 seqno = intel_ring_get_seqno(ring);
 
        BUG_ON(ring == NULL);
@@ -2183,19 +2199,6 @@ i915_gem_object_move_to_active(struct drm_i915_gem_object *obj,
        list_move_tail(&obj->ring_list, &ring->active_list);
 
        obj->last_read_seqno = seqno;
-
-       if (obj->fenced_gpu_access) {
-               obj->last_fenced_seqno = seqno;
-
-               /* Bump MRU to take account of the delayed flush */
-               if (obj->fence_reg != I915_FENCE_REG_NONE) {
-                       struct drm_i915_fence_reg *reg;
-
-                       reg = &dev_priv->fence_regs[obj->fence_reg];
-                       list_move_tail(&reg->lru_list,
-                                      &dev_priv->mm.fence_list);
-               }
-       }
 }
 
 void i915_vma_move_to_active(struct i915_vma *vma,
@@ -2231,7 +2234,6 @@ i915_gem_object_move_to_inactive(struct drm_i915_gem_object *obj)
        obj->base.write_domain = 0;
 
        obj->last_fenced_seqno = 0;
-       obj->fenced_gpu_access = false;
 
        obj->active = 0;
        drm_gem_object_unreference(&obj->base);
@@ -2329,10 +2331,21 @@ int __i915_add_request(struct intel_engine_cs *ring,
 {
        struct drm_i915_private *dev_priv = ring->dev->dev_private;
        struct drm_i915_gem_request *request;
+       struct intel_ringbuffer *ringbuf;
        u32 request_ring_position, request_start;
        int ret;
 
-       request_start = intel_ring_get_tail(ring->buffer);
+       request = ring->preallocated_lazy_request;
+       if (WARN_ON(request == NULL))
+               return -ENOMEM;
+
+       if (i915.enable_execlists) {
+               struct intel_context *ctx = request->ctx;
+               ringbuf = ctx->engine[ring->id].ringbuf;
+       } else
+               ringbuf = ring->buffer;
+
+       request_start = intel_ring_get_tail(ringbuf);
        /*
         * Emit any outstanding flushes - execbuf can fail to emit the flush
         * after having emitted the batchbuffer command. Hence we need to fix
@@ -2340,24 +2353,32 @@ int __i915_add_request(struct intel_engine_cs *ring,
         * is that the flush _must_ happen before the next request, no matter
         * what.
         */
-       ret = intel_ring_flush_all_caches(ring);
-       if (ret)
-               return ret;
-
-       request = ring->preallocated_lazy_request;
-       if (WARN_ON(request == NULL))
-               return -ENOMEM;
+       if (i915.enable_execlists) {
+               ret = logical_ring_flush_all_caches(ringbuf);
+               if (ret)
+                       return ret;
+       } else {
+               ret = intel_ring_flush_all_caches(ring);
+               if (ret)
+                       return ret;
+       }
 
        /* Record the position of the start of the request so that
         * should we detect the updated seqno part-way through the
         * GPU processing the request, we never over-estimate the
         * position of the head.
         */
-       request_ring_position = intel_ring_get_tail(ring->buffer);
+       request_ring_position = intel_ring_get_tail(ringbuf);
 
-       ret = ring->add_request(ring);
-       if (ret)
-               return ret;
+       if (i915.enable_execlists) {
+               ret = ring->emit_request(ringbuf);
+               if (ret)
+                       return ret;
+       } else {
+               ret = ring->add_request(ring);
+               if (ret)
+                       return ret;
+       }
 
        request->seqno = intel_ring_get_seqno(ring);
        request->ring = ring;
@@ -2372,12 +2393,14 @@ int __i915_add_request(struct intel_engine_cs *ring,
         */
        request->batch_obj = obj;
 
-       /* Hold a reference to the current context so that we can inspect
-        * it later in case a hangcheck error event fires.
-        */
-       request->ctx = ring->last_context;
-       if (request->ctx)
-               i915_gem_context_reference(request->ctx);
+       if (!i915.enable_execlists) {
+               /* Hold a reference to the current context so that we can inspect
+                * it later in case a hangcheck error event fires.
+                */
+               request->ctx = ring->last_context;
+               if (request->ctx)
+                       i915_gem_context_reference(request->ctx);
+       }
 
        request->emitted_jiffies = jiffies;
        list_add_tail(&request->list, &ring->request_list);
@@ -2548,6 +2571,18 @@ static void i915_gem_reset_ring_cleanup(struct drm_i915_private *dev_priv,
                i915_gem_free_request(request);
        }
 
+       while (!list_empty(&ring->execlist_queue)) {
+               struct intel_ctx_submit_request *submit_req;
+
+               submit_req = list_first_entry(&ring->execlist_queue,
+                               struct intel_ctx_submit_request,
+                               execlist_link);
+               list_del(&submit_req->execlist_link);
+               intel_runtime_pm_put(dev_priv);
+               i915_gem_context_unreference(submit_req->ctx);
+               kfree(submit_req);
+       }
+
        /* These may not have been flush before the reset, do so now */
        kfree(ring->preallocated_lazy_request);
        ring->preallocated_lazy_request = NULL;
@@ -2632,6 +2667,7 @@ i915_gem_retire_requests_ring(struct intel_engine_cs *ring)
 
        while (!list_empty(&ring->request_list)) {
                struct drm_i915_gem_request *request;
+               struct intel_ringbuffer *ringbuf;
 
                request = list_first_entry(&ring->request_list,
                                           struct drm_i915_gem_request,
@@ -2641,12 +2677,24 @@ i915_gem_retire_requests_ring(struct intel_engine_cs *ring)
                        break;
 
                trace_i915_gem_request_retire(ring, request->seqno);
+
+               /* This is one of the few common intersection points
+                * between legacy ringbuffer submission and execlists:
+                * we need to tell them apart in order to find the correct
+                * ringbuffer to which the request belongs to.
+                */
+               if (i915.enable_execlists) {
+                       struct intel_context *ctx = request->ctx;
+                       ringbuf = ctx->engine[ring->id].ringbuf;
+               } else
+                       ringbuf = ring->buffer;
+
                /* We know the GPU must have read the request to have
                 * sent us the seqno + interrupt, so use the position
                 * of tail of the request to update the last known position
                 * of the GPU head.
                 */
-               ring->buffer->last_retired_head = request->tail;
+               ringbuf->last_retired_head = request->tail;
 
                i915_gem_free_request(request);
        }
@@ -2908,6 +2956,9 @@ int i915_vma_unbind(struct i915_vma *vma)
         * cause memory corruption through use-after-free.
         */
 
+       /* Throw away the active reference before moving to the unbound list */
+       i915_gem_object_retire(obj);
+
        if (i915_is_ggtt(vma->vm)) {
                i915_gem_object_finish_gtt(obj);
 
@@ -2922,9 +2973,8 @@ int i915_vma_unbind(struct i915_vma *vma)
        vma->unbind_vma(vma);
 
        list_del_init(&vma->mm_list);
-       /* Avoid an unnecessary call to unbind on rebind. */
        if (i915_is_ggtt(vma->vm))
-               obj->map_and_fenceable = true;
+               obj->map_and_fenceable = false;
 
        drm_mm_remove_node(&vma->node);
        i915_gem_vma_destroy(vma);
@@ -2953,9 +3003,11 @@ int i915_gpu_idle(struct drm_device *dev)
 
        /* Flush everything onto the inactive list. */
        for_each_ring(ring, dev_priv, i) {
-               ret = i915_switch_context(ring, ring->default_context);
-               if (ret)
-                       return ret;
+               if (!i915.enable_execlists) {
+                       ret = i915_switch_context(ring, ring->default_context);
+                       if (ret)
+                               return ret;
+               }
 
                ret = intel_ring_idle(ring);
                if (ret)
@@ -3169,7 +3221,6 @@ i915_gem_object_wait_fence(struct drm_i915_gem_object *obj)
                obj->last_fenced_seqno = 0;
        }
 
-       obj->fenced_gpu_access = false;
        return 0;
 }
 
@@ -3276,6 +3327,9 @@ i915_gem_object_get_fence(struct drm_i915_gem_object *obj)
                        return 0;
                }
        } else if (enable) {
+               if (WARN_ON(!obj->map_and_fenceable))
+                       return -EINVAL;
+
                reg = i915_find_fence_reg(dev);
                if (IS_ERR(reg))
                        return PTR_ERR(reg);
@@ -3297,17 +3351,20 @@ i915_gem_object_get_fence(struct drm_i915_gem_object *obj)
        return 0;
 }
 
-static bool i915_gem_valid_gtt_space(struct drm_device *dev,
-                                    struct drm_mm_node *gtt_space,
+static bool i915_gem_valid_gtt_space(struct i915_vma *vma,
                                     unsigned long cache_level)
 {
+       struct drm_mm_node *gtt_space = &vma->node;
        struct drm_mm_node *other;
 
-       /* On non-LLC machines we have to be careful when putting differing
-        * types of snoopable memory together to avoid the prefetcher
-        * crossing memory domains and dying.
+       /*
+        * On some machines we have to be careful when putting differing types
+        * of snoopable memory together to avoid the prefetcher crossing memory
+        * domains and dying. During vm initialisation, we decide whether or not
+        * these constraints apply and set the drm_mm.color_adjust
+        * appropriately.
         */
-       if (HAS_LLC(dev))
+       if (vma->vm->mm.color_adjust == NULL)
                return true;
 
        if (!drm_mm_node_allocated(gtt_space))
@@ -3445,8 +3502,7 @@ search_free:
 
                goto err_free_vma;
        }
-       if (WARN_ON(!i915_gem_valid_gtt_space(dev, &vma->node,
-                                             obj->cache_level))) {
+       if (WARN_ON(!i915_gem_valid_gtt_space(vma, obj->cache_level))) {
                ret = -EINVAL;
                goto err_remove_node;
        }
@@ -3586,11 +3642,12 @@ int
 i915_gem_object_set_to_gtt_domain(struct drm_i915_gem_object *obj, bool write)
 {
        struct drm_i915_private *dev_priv = obj->base.dev->dev_private;
+       struct i915_vma *vma = i915_gem_obj_to_ggtt(obj);
        uint32_t old_write_domain, old_read_domains;
        int ret;
 
        /* Not valid to be called on unbound objects. */
-       if (!i915_gem_obj_bound_any(obj))
+       if (vma == NULL)
                return -EINVAL;
 
        if (obj->base.write_domain == I915_GEM_DOMAIN_GTT)
@@ -3632,13 +3689,9 @@ i915_gem_object_set_to_gtt_domain(struct drm_i915_gem_object *obj, bool write)
                                            old_write_domain);
 
        /* And bump the LRU for this access */
-       if (i915_gem_object_is_inactive(obj)) {
-               struct i915_vma *vma = i915_gem_obj_to_ggtt(obj);
-               if (vma)
-                       list_move_tail(&vma->mm_list,
-                                      &dev_priv->gtt.base.inactive_list);
-
-       }
+       if (i915_gem_object_is_inactive(obj))
+               list_move_tail(&vma->mm_list,
+                              &dev_priv->gtt.base.inactive_list);
 
        return 0;
 }
@@ -3659,7 +3712,7 @@ int i915_gem_object_set_cache_level(struct drm_i915_gem_object *obj,
        }
 
        list_for_each_entry_safe(vma, next, &obj->vma_list, vma_link) {
-               if (!i915_gem_valid_gtt_space(dev, &vma->node, cache_level)) {
+               if (!i915_gem_valid_gtt_space(vma, cache_level)) {
                        ret = i915_vma_unbind(vma);
                        if (ret)
                                return ret;
@@ -3802,9 +3855,6 @@ static bool is_pin_display(struct drm_i915_gem_object *obj)
 {
        struct i915_vma *vma;
 
-       if (list_empty(&obj->vma_list))
-               return false;
-
        vma = i915_gem_obj_to_ggtt(obj);
        if (!vma)
                return false;
@@ -4331,8 +4381,6 @@ void i915_gem_object_init(struct drm_i915_gem_object *obj,
 
        obj->fence_reg = I915_FENCE_REG_NONE;
        obj->madv = I915_MADV_WILLNEED;
-       /* Avoid an unnecessary call to unbind on the first bind. */
-       obj->map_and_fenceable = true;
 
        i915_gem_info_add_obj(obj->base.dev->dev_private, obj->base.size);
 }
@@ -4493,12 +4541,18 @@ struct i915_vma *i915_gem_obj_to_vma(struct drm_i915_gem_object *obj,
 
 void i915_gem_vma_destroy(struct i915_vma *vma)
 {
+       struct i915_address_space *vm = NULL;
        WARN_ON(vma->node.allocated);
 
        /* Keep the vma as a placeholder in the execbuffer reservation lists */
        if (!list_empty(&vma->exec_list))
                return;
 
+       vm = vma->vm;
+
+       if (!i915_is_ggtt(vm))
+               i915_ppgtt_put(i915_vm_to_ppgtt(vm));
+
        list_del(&vma->vma_link);
 
        kfree(vma);
@@ -4512,7 +4566,7 @@ i915_gem_stop_ringbuffers(struct drm_device *dev)
        int i;
 
        for_each_ring(ring, dev_priv, i)
-               intel_stop_ring_buffer(ring);
+               dev_priv->gt.stop_ring(ring);
 }
 
 int
@@ -4629,11 +4683,46 @@ intel_enable_blt(struct drm_device *dev)
        return true;
 }
 
-static int i915_gem_init_rings(struct drm_device *dev)
+static void init_unused_ring(struct drm_device *dev, u32 base)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+
+       I915_WRITE(RING_CTL(base), 0);
+       I915_WRITE(RING_HEAD(base), 0);
+       I915_WRITE(RING_TAIL(base), 0);
+       I915_WRITE(RING_START(base), 0);
+}
+
+static void init_unused_rings(struct drm_device *dev)
+{
+       if (IS_I830(dev)) {
+               init_unused_ring(dev, PRB1_BASE);
+               init_unused_ring(dev, SRB0_BASE);
+               init_unused_ring(dev, SRB1_BASE);
+               init_unused_ring(dev, SRB2_BASE);
+               init_unused_ring(dev, SRB3_BASE);
+       } else if (IS_GEN2(dev)) {
+               init_unused_ring(dev, SRB0_BASE);
+               init_unused_ring(dev, SRB1_BASE);
+       } else if (IS_GEN3(dev)) {
+               init_unused_ring(dev, PRB1_BASE);
+               init_unused_ring(dev, PRB2_BASE);
+       }
+}
+
+int i915_gem_init_rings(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
        int ret;
 
+       /*
+        * At least 830 can leave some of the unused rings
+        * "active" (ie. head != tail) after resume which
+        * will prevent c3 entry. Makes sure all unused rings
+        * are totally idle.
+        */
+       init_unused_rings(dev);
+
        ret = intel_init_render_ring_buffer(dev);
        if (ret)
                return ret;
@@ -4712,7 +4801,7 @@ i915_gem_init_hw(struct drm_device *dev)
 
        i915_gem_init_swizzling(dev);
 
-       ret = i915_gem_init_rings(dev);
+       ret = dev_priv->gt.init_rings(dev);
        if (ret)
                return ret;
 
@@ -4730,6 +4819,14 @@ i915_gem_init_hw(struct drm_device *dev)
        if (ret && ret != -EIO) {
                DRM_ERROR("Context enable failed %d\n", ret);
                i915_gem_cleanup_ringbuffer(dev);
+
+               return ret;
+       }
+
+       ret = i915_ppgtt_init_hw(dev);
+       if (ret && ret != -EIO) {
+               DRM_ERROR("PPGTT enable failed %d\n", ret);
+               i915_gem_cleanup_ringbuffer(dev);
        }
 
        return ret;
@@ -4740,6 +4837,9 @@ int i915_gem_init(struct drm_device *dev)
        struct drm_i915_private *dev_priv = dev->dev_private;
        int ret;
 
+       i915.enable_execlists = intel_sanitize_enable_execlists(dev,
+                       i915.enable_execlists);
+
        mutex_lock(&dev->struct_mutex);
 
        if (IS_VALLEYVIEW(dev)) {
@@ -4750,7 +4850,24 @@ int i915_gem_init(struct drm_device *dev)
                        DRM_DEBUG_DRIVER("allow wake ack timed out\n");
        }
 
-       i915_gem_init_userptr(dev);
+       if (!i915.enable_execlists) {
+               dev_priv->gt.do_execbuf = i915_gem_ringbuffer_submission;
+               dev_priv->gt.init_rings = i915_gem_init_rings;
+               dev_priv->gt.cleanup_ring = intel_cleanup_ring_buffer;
+               dev_priv->gt.stop_ring = intel_stop_ring_buffer;
+       } else {
+               dev_priv->gt.do_execbuf = intel_execlists_submission;
+               dev_priv->gt.init_rings = intel_logical_rings_init;
+               dev_priv->gt.cleanup_ring = intel_logical_ring_cleanup;
+               dev_priv->gt.stop_ring = intel_logical_ring_stop;
+       }
+
+       ret = i915_gem_init_userptr(dev);
+       if (ret) {
+               mutex_unlock(&dev->struct_mutex);
+               return ret;
+       }
+
        i915_gem_init_global_gtt(dev);
 
        ret = i915_gem_context_init(dev);
@@ -4785,7 +4902,7 @@ i915_gem_cleanup_ringbuffer(struct drm_device *dev)
        int i;
 
        for_each_ring(ring, dev_priv, i)
-               intel_cleanup_ring_buffer(ring);
+               dev_priv->gt.cleanup_ring(ring);
 }
 
 int
@@ -5097,9 +5214,7 @@ unsigned long i915_gem_obj_offset(struct drm_i915_gem_object *o,
        struct drm_i915_private *dev_priv = o->base.dev->dev_private;
        struct i915_vma *vma;
 
-       if (!dev_priv->mm.aliasing_ppgtt ||
-           vm == &dev_priv->mm.aliasing_ppgtt->base)
-               vm = &dev_priv->gtt.base;
+       WARN_ON(vm == &dev_priv->mm.aliasing_ppgtt->base);
 
        list_for_each_entry(vma, &o->vma_list, vma_link) {
                if (vma->vm == vm)
@@ -5140,9 +5255,7 @@ unsigned long i915_gem_obj_size(struct drm_i915_gem_object *o,
        struct drm_i915_private *dev_priv = o->base.dev->dev_private;
        struct i915_vma *vma;
 
-       if (!dev_priv->mm.aliasing_ppgtt ||
-           vm == &dev_priv->mm.aliasing_ppgtt->base)
-               vm = &dev_priv->gtt.base;
+       WARN_ON(vm == &dev_priv->mm.aliasing_ppgtt->base);
 
        BUG_ON(list_empty(&o->vma_list));
 
@@ -5165,11 +5278,16 @@ i915_gem_shrinker_scan(struct shrinker *shrinker, struct shrink_control *sc)
        if (!i915_gem_shrinker_lock(dev, &unlock))
                return SHRINK_STOP;
 
-       freed = i915_gem_purge(dev_priv, sc->nr_to_scan);
+       freed = i915_gem_shrink(dev_priv,
+                               sc->nr_to_scan,
+                               I915_SHRINK_BOUND |
+                               I915_SHRINK_UNBOUND |
+                               I915_SHRINK_PURGEABLE);
        if (freed < sc->nr_to_scan)
-               freed += __i915_gem_shrink(dev_priv,
-                                          sc->nr_to_scan - freed,
-                                          false);
+               freed += i915_gem_shrink(dev_priv,
+                                        sc->nr_to_scan - freed,
+                                        I915_SHRINK_BOUND |
+                                        I915_SHRINK_UNBOUND);
        if (unlock)
                mutex_unlock(&dev->struct_mutex);
 
@@ -5247,14 +5365,8 @@ struct i915_vma *i915_gem_obj_to_ggtt(struct drm_i915_gem_object *obj)
 {
        struct i915_vma *vma;
 
-       /* This WARN has probably outlived its usefulness (callers already
-        * WARN if they don't find the GGTT vma they expect). When removing,
-        * remember to remove the pre-check in is_pin_display() as well */
-       if (WARN_ON(list_empty(&obj->vma_list)))
-               return NULL;
-
        vma = list_first_entry(&obj->vma_list, typeof(*vma), vma_link);
-       if (vma->vm != obj_to_ggtt(obj))
+       if (vma->vm != i915_obj_to_ggtt(obj))
                return NULL;
 
        return vma;
index 3b99390e467aa3bfabcfb99438d66981ec2509c0..a5221d8f1580182fe80c7c9cfc34da7d3484fe11 100644 (file)
 #define GEN6_CONTEXT_ALIGN (64<<10)
 #define GEN7_CONTEXT_ALIGN 4096
 
-static void do_ppgtt_cleanup(struct i915_hw_ppgtt *ppgtt)
-{
-       struct drm_device *dev = ppgtt->base.dev;
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       struct i915_address_space *vm = &ppgtt->base;
-
-       if (ppgtt == dev_priv->mm.aliasing_ppgtt ||
-           (list_empty(&vm->active_list) && list_empty(&vm->inactive_list))) {
-               ppgtt->base.cleanup(&ppgtt->base);
-               return;
-       }
-
-       /*
-        * Make sure vmas are unbound before we take down the drm_mm
-        *
-        * FIXME: Proper refcounting should take care of this, this shouldn't be
-        * needed at all.
-        */
-       if (!list_empty(&vm->active_list)) {
-               struct i915_vma *vma;
-
-               list_for_each_entry(vma, &vm->active_list, mm_list)
-                       if (WARN_ON(list_empty(&vma->vma_link) ||
-                                   list_is_singular(&vma->vma_link)))
-                               break;
-
-               i915_gem_evict_vm(&ppgtt->base, true);
-       } else {
-               i915_gem_retire_requests(dev);
-               i915_gem_evict_vm(&ppgtt->base, false);
-       }
-
-       ppgtt->base.cleanup(&ppgtt->base);
-}
-
-static void ppgtt_release(struct kref *kref)
-{
-       struct i915_hw_ppgtt *ppgtt =
-               container_of(kref, struct i915_hw_ppgtt, ref);
-
-       do_ppgtt_cleanup(ppgtt);
-       kfree(ppgtt);
-}
-
 static size_t get_context_alignment(struct drm_device *dev)
 {
        if (IS_GEN6(dev))
@@ -179,24 +135,20 @@ static int get_context_size(struct drm_device *dev)
 void i915_gem_context_free(struct kref *ctx_ref)
 {
        struct intel_context *ctx = container_of(ctx_ref,
-                                                  typeof(*ctx), ref);
-       struct i915_hw_ppgtt *ppgtt = NULL;
+                                                typeof(*ctx), ref);
 
-       if (ctx->legacy_hw_ctx.rcs_state) {
-               /* We refcount even the aliasing PPGTT to keep the code symmetric */
-               if (USES_PPGTT(ctx->legacy_hw_ctx.rcs_state->base.dev))
-                       ppgtt = ctx_to_ppgtt(ctx);
-       }
+       if (i915.enable_execlists)
+               intel_lr_context_free(ctx);
+
+       i915_ppgtt_put(ctx->ppgtt);
 
-       if (ppgtt)
-               kref_put(&ppgtt->ref, ppgtt_release);
        if (ctx->legacy_hw_ctx.rcs_state)
                drm_gem_object_unreference(&ctx->legacy_hw_ctx.rcs_state->base);
        list_del(&ctx->link);
        kfree(ctx);
 }
 
-static struct drm_i915_gem_object *
+struct drm_i915_gem_object *
 i915_gem_alloc_context_obj(struct drm_device *dev, size_t size)
 {
        struct drm_i915_gem_object *obj;
@@ -226,29 +178,9 @@ i915_gem_alloc_context_obj(struct drm_device *dev, size_t size)
        return obj;
 }
 
-static struct i915_hw_ppgtt *
-create_vm_for_ctx(struct drm_device *dev, struct intel_context *ctx)
-{
-       struct i915_hw_ppgtt *ppgtt;
-       int ret;
-
-       ppgtt = kzalloc(sizeof(*ppgtt), GFP_KERNEL);
-       if (!ppgtt)
-               return ERR_PTR(-ENOMEM);
-
-       ret = i915_gem_init_ppgtt(dev, ppgtt);
-       if (ret) {
-               kfree(ppgtt);
-               return ERR_PTR(ret);
-       }
-
-       ppgtt->ctx = ctx;
-       return ppgtt;
-}
-
 static struct intel_context *
 __create_hw_context(struct drm_device *dev,
-                 struct drm_i915_file_private *file_priv)
+                   struct drm_i915_file_private *file_priv)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct intel_context *ctx;
@@ -301,11 +233,9 @@ err_out:
  */
 static struct intel_context *
 i915_gem_create_context(struct drm_device *dev,
-                       struct drm_i915_file_private *file_priv,
-                       bool create_vm)
+                       struct drm_i915_file_private *file_priv)
 {
        const bool is_global_default_ctx = file_priv == NULL;
-       struct drm_i915_private *dev_priv = dev->dev_private;
        struct intel_context *ctx;
        int ret = 0;
 
@@ -331,34 +261,18 @@ i915_gem_create_context(struct drm_device *dev,
                }
        }
 
-       if (create_vm) {
-               struct i915_hw_ppgtt *ppgtt = create_vm_for_ctx(dev, ctx);
+       if (USES_FULL_PPGTT(dev)) {
+               struct i915_hw_ppgtt *ppgtt = i915_ppgtt_create(dev, file_priv);
 
                if (IS_ERR_OR_NULL(ppgtt)) {
                        DRM_DEBUG_DRIVER("PPGTT setup failed (%ld)\n",
                                         PTR_ERR(ppgtt));
                        ret = PTR_ERR(ppgtt);
                        goto err_unpin;
-               } else
-                       ctx->vm = &ppgtt->base;
-
-               /* This case is reserved for the global default context and
-                * should only happen once. */
-               if (is_global_default_ctx) {
-                       if (WARN_ON(dev_priv->mm.aliasing_ppgtt)) {
-                               ret = -EEXIST;
-                               goto err_unpin;
-                       }
-
-                       dev_priv->mm.aliasing_ppgtt = ppgtt;
                }
-       } else if (USES_PPGTT(dev)) {
-               /* For platforms which only have aliasing PPGTT, we fake the
-                * address space and refcounting. */
-               ctx->vm = &dev_priv->mm.aliasing_ppgtt->base;
-               kref_get(&dev_priv->mm.aliasing_ppgtt->ref);
-       } else
-               ctx->vm = &dev_priv->gtt.base;
+
+               ctx->ppgtt = ppgtt;
+       }
 
        return ctx;
 
@@ -375,34 +289,23 @@ void i915_gem_context_reset(struct drm_device *dev)
        struct drm_i915_private *dev_priv = dev->dev_private;
        int i;
 
-       /* Prevent the hardware from restoring the last context (which hung) on
-        * the next switch */
+       /* In execlists mode we will unreference the context when the execlist
+        * queue is cleared and the requests destroyed.
+        */
+       if (i915.enable_execlists)
+               return;
+
        for (i = 0; i < I915_NUM_RINGS; i++) {
                struct intel_engine_cs *ring = &dev_priv->ring[i];
-               struct intel_context *dctx = ring->default_context;
                struct intel_context *lctx = ring->last_context;
 
-               /* Do a fake switch to the default context */
-               if (lctx == dctx)
-                       continue;
-
-               if (!lctx)
-                       continue;
+               if (lctx) {
+                       if (lctx->legacy_hw_ctx.rcs_state && i == RCS)
+                               i915_gem_object_ggtt_unpin(lctx->legacy_hw_ctx.rcs_state);
 
-               if (dctx->legacy_hw_ctx.rcs_state && i == RCS) {
-                       WARN_ON(i915_gem_obj_ggtt_pin(dctx->legacy_hw_ctx.rcs_state,
-                                                     get_context_alignment(dev), 0));
-                       /* Fake a finish/inactive */
-                       dctx->legacy_hw_ctx.rcs_state->base.write_domain = 0;
-                       dctx->legacy_hw_ctx.rcs_state->active = 0;
+                       i915_gem_context_unreference(lctx);
+                       ring->last_context = NULL;
                }
-
-               if (lctx->legacy_hw_ctx.rcs_state && i == RCS)
-                       i915_gem_object_ggtt_unpin(lctx->legacy_hw_ctx.rcs_state);
-
-               i915_gem_context_unreference(lctx);
-               i915_gem_context_reference(dctx);
-               ring->last_context = dctx;
        }
 }
 
@@ -417,7 +320,11 @@ int i915_gem_context_init(struct drm_device *dev)
        if (WARN_ON(dev_priv->ring[RCS].default_context))
                return 0;
 
-       if (HAS_HW_CONTEXTS(dev)) {
+       if (i915.enable_execlists) {
+               /* NB: intentionally left blank. We will allocate our own
+                * backing objects as we need them, thank you very much */
+               dev_priv->hw_context_size = 0;
+       } else if (HAS_HW_CONTEXTS(dev)) {
                dev_priv->hw_context_size = round_up(get_context_size(dev), 4096);
                if (dev_priv->hw_context_size > (1<<20)) {
                        DRM_DEBUG_DRIVER("Disabling HW Contexts; invalid size %d\n",
@@ -426,18 +333,23 @@ int i915_gem_context_init(struct drm_device *dev)
                }
        }
 
-       ctx = i915_gem_create_context(dev, NULL, USES_PPGTT(dev));
+       ctx = i915_gem_create_context(dev, NULL);
        if (IS_ERR(ctx)) {
                DRM_ERROR("Failed to create default global context (error %ld)\n",
                          PTR_ERR(ctx));
                return PTR_ERR(ctx);
        }
 
-       /* NB: RCS will hold a ref for all rings */
-       for (i = 0; i < I915_NUM_RINGS; i++)
-               dev_priv->ring[i].default_context = ctx;
+       for (i = 0; i < I915_NUM_RINGS; i++) {
+               struct intel_engine_cs *ring = &dev_priv->ring[i];
 
-       DRM_DEBUG_DRIVER("%s context support initialized\n", dev_priv->hw_context_size ? "HW" : "fake");
+               /* NB: RCS will hold a ref for all rings */
+               ring->default_context = ctx;
+       }
+
+       DRM_DEBUG_DRIVER("%s context support initialized\n",
+                       i915.enable_execlists ? "LR" :
+                       dev_priv->hw_context_size ? "HW" : "fake");
        return 0;
 }
 
@@ -489,19 +401,11 @@ int i915_gem_context_enable(struct drm_i915_private *dev_priv)
        struct intel_engine_cs *ring;
        int ret, i;
 
-       /* This is the only place the aliasing PPGTT gets enabled, which means
-        * it has to happen before we bail on reset */
-       if (dev_priv->mm.aliasing_ppgtt) {
-               struct i915_hw_ppgtt *ppgtt = dev_priv->mm.aliasing_ppgtt;
-               ppgtt->enable(ppgtt);
-       }
+       BUG_ON(!dev_priv->ring[RCS].default_context);
 
-       /* FIXME: We should make this work, even in reset */
-       if (i915_reset_in_progress(&dev_priv->gpu_error))
+       if (i915.enable_execlists)
                return 0;
 
-       BUG_ON(!dev_priv->ring[RCS].default_context);
-
        for_each_ring(ring, dev_priv, i) {
                ret = i915_switch_context(ring, ring->default_context);
                if (ret)
@@ -527,7 +431,7 @@ int i915_gem_context_open(struct drm_device *dev, struct drm_file *file)
        idr_init(&file_priv->context_idr);
 
        mutex_lock(&dev->struct_mutex);
-       ctx = i915_gem_create_context(dev, file_priv, USES_FULL_PPGTT(dev));
+       ctx = i915_gem_create_context(dev, file_priv);
        mutex_unlock(&dev->struct_mutex);
 
        if (IS_ERR(ctx)) {
@@ -563,6 +467,7 @@ mi_set_context(struct intel_engine_cs *ring,
               struct intel_context *new_context,
               u32 hw_flags)
 {
+       u32 flags = hw_flags | MI_MM_SPACE_GTT;
        int ret;
 
        /* w/a: If Flush TLB Invalidation Mode is enabled, driver must do a TLB
@@ -576,6 +481,10 @@ mi_set_context(struct intel_engine_cs *ring,
                        return ret;
        }
 
+       /* These flags are for resource streamer on HSW+ */
+       if (!IS_HASWELL(ring->dev) && INTEL_INFO(ring->dev)->gen < 8)
+               flags |= (MI_SAVE_EXT_STATE_EN | MI_RESTORE_EXT_STATE_EN);
+
        ret = intel_ring_begin(ring, 6);
        if (ret)
                return ret;
@@ -589,10 +498,7 @@ mi_set_context(struct intel_engine_cs *ring,
        intel_ring_emit(ring, MI_NOOP);
        intel_ring_emit(ring, MI_SET_CONTEXT);
        intel_ring_emit(ring, i915_gem_obj_ggtt_offset(new_context->legacy_hw_ctx.rcs_state) |
-                       MI_MM_SPACE_GTT |
-                       MI_SAVE_EXT_STATE_EN |
-                       MI_RESTORE_EXT_STATE_EN |
-                       hw_flags);
+                       flags);
        /*
         * w/a: MI_SET_CONTEXT must always be followed by MI_NOOP
         * WaMiSetContext_Hang:snb,ivb,vlv
@@ -614,7 +520,6 @@ static int do_switch(struct intel_engine_cs *ring,
 {
        struct drm_i915_private *dev_priv = ring->dev->dev_private;
        struct intel_context *from = ring->last_context;
-       struct i915_hw_ppgtt *ppgtt = ctx_to_ppgtt(to);
        u32 hw_flags = 0;
        bool uninitialized = false;
        int ret, i;
@@ -642,8 +547,8 @@ static int do_switch(struct intel_engine_cs *ring,
         */
        from = ring->last_context;
 
-       if (USES_FULL_PPGTT(ring->dev)) {
-               ret = ppgtt->switch_mm(ppgtt, ring, false);
+       if (to->ppgtt) {
+               ret = to->ppgtt->switch_mm(to->ppgtt, ring);
                if (ret)
                        goto unpin_out;
        }
@@ -723,6 +628,12 @@ done:
        ring->last_context = to;
 
        if (uninitialized) {
+               if (ring->init_context) {
+                       ret = ring->init_context(ring);
+                       if (ret)
+                               DRM_ERROR("ring init context: %d\n", ret);
+               }
+
                ret = i915_gem_render_state_init(ring);
                if (ret)
                        DRM_ERROR("init render state: %d\n", ret);
@@ -743,14 +654,19 @@ unpin_out:
  *
  * The context life cycle is simple. The context refcount is incremented and
  * decremented by 1 and create and destroy. If the context is in use by the GPU,
- * it will have a refoucnt > 1. This allows us to destroy the context abstract
+ * it will have a refcount > 1. This allows us to destroy the context abstract
  * object while letting the normal object tracking destroy the backing BO.
+ *
+ * This function should not be used in execlists mode.  Instead the context is
+ * switched by writing to the ELSP and requests keep a reference to their
+ * context.
  */
 int i915_switch_context(struct intel_engine_cs *ring,
                        struct intel_context *to)
 {
        struct drm_i915_private *dev_priv = ring->dev->dev_private;
 
+       WARN_ON(i915.enable_execlists);
        WARN_ON(!mutex_is_locked(&dev_priv->dev->struct_mutex));
 
        if (to->legacy_hw_ctx.rcs_state == NULL) { /* We have the fake context */
@@ -766,9 +682,9 @@ int i915_switch_context(struct intel_engine_cs *ring,
        return do_switch(ring, to);
 }
 
-static bool hw_context_enabled(struct drm_device *dev)
+static bool contexts_enabled(struct drm_device *dev)
 {
-       return to_i915(dev)->hw_context_size;
+       return i915.enable_execlists || to_i915(dev)->hw_context_size;
 }
 
 int i915_gem_context_create_ioctl(struct drm_device *dev, void *data,
@@ -779,14 +695,14 @@ int i915_gem_context_create_ioctl(struct drm_device *dev, void *data,
        struct intel_context *ctx;
        int ret;
 
-       if (!hw_context_enabled(dev))
+       if (!contexts_enabled(dev))
                return -ENODEV;
 
        ret = i915_mutex_lock_interruptible(dev);
        if (ret)
                return ret;
 
-       ctx = i915_gem_create_context(dev, file_priv, USES_FULL_PPGTT(dev));
+       ctx = i915_gem_create_context(dev, file_priv);
        mutex_unlock(&dev->struct_mutex);
        if (IS_ERR(ctx))
                return PTR_ERR(ctx);
index bbf4b12d842effa7972e7dcaaa23e1de08434b59..886ff2ee7a282e0762855e244e40cd8a7493b1fe 100644 (file)
@@ -243,7 +243,7 @@ int
 i915_gem_evict_everything(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
-       struct i915_address_space *vm;
+       struct i915_address_space *vm, *v;
        bool lists_empty = true;
        int ret;
 
@@ -270,7 +270,7 @@ i915_gem_evict_everything(struct drm_device *dev)
        i915_gem_retire_requests(dev);
 
        /* Having flushed everything, unbind() should never raise an error */
-       list_for_each_entry(vm, &dev_priv->vm_list, global_link)
+       list_for_each_entry_safe(vm, v, &dev_priv->vm_list, global_link)
                WARN_ON(i915_gem_evict_vm(vm, false));
 
        return 0;
index 60998fc4e5b22147687db554a4c80f27d08e1bea..1a0611bb576b3eb9b78ede149955f36b798360df 100644 (file)
@@ -35,6 +35,7 @@
 
 #define  __EXEC_OBJECT_HAS_PIN (1<<31)
 #define  __EXEC_OBJECT_HAS_FENCE (1<<30)
+#define  __EXEC_OBJECT_NEEDS_MAP (1<<29)
 #define  __EXEC_OBJECT_NEEDS_BIAS (1<<28)
 
 #define BATCH_OFFSET_BIAS (256*1024)
@@ -94,7 +95,6 @@ eb_lookup_vmas(struct eb_vmas *eb,
               struct i915_address_space *vm,
               struct drm_file *file)
 {
-       struct drm_i915_private *dev_priv = vm->dev->dev_private;
        struct drm_i915_gem_object *obj;
        struct list_head objects;
        int i, ret;
@@ -129,20 +129,6 @@ eb_lookup_vmas(struct eb_vmas *eb,
        i = 0;
        while (!list_empty(&objects)) {
                struct i915_vma *vma;
-               struct i915_address_space *bind_vm = vm;
-
-               if (exec[i].flags & EXEC_OBJECT_NEEDS_GTT &&
-                   USES_FULL_PPGTT(vm->dev)) {
-                       ret = -EINVAL;
-                       goto err;
-               }
-
-               /* If we have secure dispatch, or the userspace assures us that
-                * they know what they're doing, use the GGTT VM.
-                */
-               if (((args->flags & I915_EXEC_SECURE) &&
-                   (i == (args->buffer_count - 1))))
-                       bind_vm = &dev_priv->gtt.base;
 
                obj = list_first_entry(&objects,
                                       struct drm_i915_gem_object,
@@ -156,7 +142,7 @@ eb_lookup_vmas(struct eb_vmas *eb,
                 * from the (obj, vm) we don't run the risk of creating
                 * duplicated vmas for the same vm.
                 */
-               vma = i915_gem_obj_lookup_or_create_vma(obj, bind_vm);
+               vma = i915_gem_obj_lookup_or_create_vma(obj, vm);
                if (IS_ERR(vma)) {
                        DRM_DEBUG("Failed to lookup VMA\n");
                        ret = PTR_ERR(vma);
@@ -307,7 +293,7 @@ relocate_entry_gtt(struct drm_i915_gem_object *obj,
        struct drm_device *dev = obj->base.dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
        uint64_t delta = reloc->delta + target_offset;
-       uint32_t __iomem *reloc_entry;
+       uint64_t offset;
        void __iomem *reloc_page;
        int ret;
 
@@ -320,25 +306,24 @@ relocate_entry_gtt(struct drm_i915_gem_object *obj,
                return ret;
 
        /* Map the page containing the relocation we're going to perform.  */
-       reloc->offset += i915_gem_obj_ggtt_offset(obj);
+       offset = i915_gem_obj_ggtt_offset(obj);
+       offset += reloc->offset;
        reloc_page = io_mapping_map_atomic_wc(dev_priv->gtt.mappable,
-                       reloc->offset & PAGE_MASK);
-       reloc_entry = (uint32_t __iomem *)
-               (reloc_page + offset_in_page(reloc->offset));
-       iowrite32(lower_32_bits(delta), reloc_entry);
+                                             offset & PAGE_MASK);
+       iowrite32(lower_32_bits(delta), reloc_page + offset_in_page(offset));
 
        if (INTEL_INFO(dev)->gen >= 8) {
-               reloc_entry += 1;
+               offset += sizeof(uint32_t);
 
-               if (offset_in_page(reloc->offset + sizeof(uint32_t)) == 0) {
+               if (offset_in_page(offset) == 0) {
                        io_mapping_unmap_atomic(reloc_page);
-                       reloc_page = io_mapping_map_atomic_wc(
-                                       dev_priv->gtt.mappable,
-                                       reloc->offset + sizeof(uint32_t));
-                       reloc_entry = reloc_page;
+                       reloc_page =
+                               io_mapping_map_atomic_wc(dev_priv->gtt.mappable,
+                                                        offset);
                }
 
-               iowrite32(upper_32_bits(delta), reloc_entry);
+               iowrite32(upper_32_bits(delta),
+                         reloc_page + offset_in_page(offset));
        }
 
        io_mapping_unmap_atomic(reloc_page);
@@ -534,14 +519,6 @@ i915_gem_execbuffer_relocate(struct eb_vmas *eb)
        return ret;
 }
 
-static int
-need_reloc_mappable(struct i915_vma *vma)
-{
-       struct drm_i915_gem_exec_object2 *entry = vma->exec_entry;
-       return entry->relocation_count && !use_cpu_reloc(vma->obj) &&
-               i915_is_ggtt(vma->vm);
-}
-
 static int
 i915_gem_execbuffer_reserve_vma(struct i915_vma *vma,
                                struct intel_engine_cs *ring,
@@ -549,20 +526,12 @@ i915_gem_execbuffer_reserve_vma(struct i915_vma *vma,
 {
        struct drm_i915_gem_object *obj = vma->obj;
        struct drm_i915_gem_exec_object2 *entry = vma->exec_entry;
-       bool has_fenced_gpu_access = INTEL_INFO(ring->dev)->gen < 4;
-       bool need_fence;
        uint64_t flags;
        int ret;
 
        flags = 0;
-
-       need_fence =
-               has_fenced_gpu_access &&
-               entry->flags & EXEC_OBJECT_NEEDS_FENCE &&
-               obj->tiling_mode != I915_TILING_NONE;
-       if (need_fence || need_reloc_mappable(vma))
+       if (entry->flags & __EXEC_OBJECT_NEEDS_MAP)
                flags |= PIN_MAPPABLE;
-
        if (entry->flags & EXEC_OBJECT_NEEDS_GTT)
                flags |= PIN_GLOBAL;
        if (entry->flags & __EXEC_OBJECT_NEEDS_BIAS)
@@ -574,17 +543,13 @@ i915_gem_execbuffer_reserve_vma(struct i915_vma *vma,
 
        entry->flags |= __EXEC_OBJECT_HAS_PIN;
 
-       if (has_fenced_gpu_access) {
-               if (entry->flags & EXEC_OBJECT_NEEDS_FENCE) {
-                       ret = i915_gem_object_get_fence(obj);
-                       if (ret)
-                               return ret;
-
-                       if (i915_gem_object_pin_fence(obj))
-                               entry->flags |= __EXEC_OBJECT_HAS_FENCE;
+       if (entry->flags & EXEC_OBJECT_NEEDS_FENCE) {
+               ret = i915_gem_object_get_fence(obj);
+               if (ret)
+                       return ret;
 
-                       obj->pending_fenced_gpu_access = true;
-               }
+               if (i915_gem_object_pin_fence(obj))
+                       entry->flags |= __EXEC_OBJECT_HAS_FENCE;
        }
 
        if (entry->offset != vma->node.start) {
@@ -601,26 +566,40 @@ i915_gem_execbuffer_reserve_vma(struct i915_vma *vma,
 }
 
 static bool
-eb_vma_misplaced(struct i915_vma *vma, bool has_fenced_gpu_access)
+need_reloc_mappable(struct i915_vma *vma)
 {
        struct drm_i915_gem_exec_object2 *entry = vma->exec_entry;
-       struct drm_i915_gem_object *obj = vma->obj;
-       bool need_fence, need_mappable;
 
-       need_fence =
-               has_fenced_gpu_access &&
-               entry->flags & EXEC_OBJECT_NEEDS_FENCE &&
-               obj->tiling_mode != I915_TILING_NONE;
-       need_mappable = need_fence || need_reloc_mappable(vma);
+       if (entry->relocation_count == 0)
+               return false;
+
+       if (!i915_is_ggtt(vma->vm))
+               return false;
+
+       /* See also use_cpu_reloc() */
+       if (HAS_LLC(vma->obj->base.dev))
+               return false;
 
-       WARN_ON((need_mappable || need_fence) &&
+       if (vma->obj->base.write_domain == I915_GEM_DOMAIN_CPU)
+               return false;
+
+       return true;
+}
+
+static bool
+eb_vma_misplaced(struct i915_vma *vma)
+{
+       struct drm_i915_gem_exec_object2 *entry = vma->exec_entry;
+       struct drm_i915_gem_object *obj = vma->obj;
+
+       WARN_ON(entry->flags & __EXEC_OBJECT_NEEDS_MAP &&
               !i915_is_ggtt(vma->vm));
 
        if (entry->alignment &&
            vma->node.start & (entry->alignment - 1))
                return true;
 
-       if (need_mappable && !obj->map_and_fenceable)
+       if (entry->flags & __EXEC_OBJECT_NEEDS_MAP && !obj->map_and_fenceable)
                return true;
 
        if (entry->flags & __EXEC_OBJECT_NEEDS_BIAS &&
@@ -642,9 +621,6 @@ i915_gem_execbuffer_reserve(struct intel_engine_cs *ring,
        bool has_fenced_gpu_access = INTEL_INFO(ring->dev)->gen < 4;
        int retry;
 
-       if (list_empty(vmas))
-               return 0;
-
        i915_gem_retire_requests_ring(ring);
 
        vm = list_first_entry(vmas, struct i915_vma, exec_list)->vm;
@@ -658,20 +634,21 @@ i915_gem_execbuffer_reserve(struct intel_engine_cs *ring,
                obj = vma->obj;
                entry = vma->exec_entry;
 
+               if (!has_fenced_gpu_access)
+                       entry->flags &= ~EXEC_OBJECT_NEEDS_FENCE;
                need_fence =
-                       has_fenced_gpu_access &&
                        entry->flags & EXEC_OBJECT_NEEDS_FENCE &&
                        obj->tiling_mode != I915_TILING_NONE;
                need_mappable = need_fence || need_reloc_mappable(vma);
 
-               if (need_mappable)
+               if (need_mappable) {
+                       entry->flags |= __EXEC_OBJECT_NEEDS_MAP;
                        list_move(&vma->exec_list, &ordered_vmas);
-               else
+               else
                        list_move_tail(&vma->exec_list, &ordered_vmas);
 
                obj->base.pending_read_domains = I915_GEM_GPU_DOMAINS & ~I915_GEM_DOMAIN_COMMAND;
                obj->base.pending_write_domain = 0;
-               obj->pending_fenced_gpu_access = false;
        }
        list_splice(&ordered_vmas, vmas);
 
@@ -696,7 +673,7 @@ i915_gem_execbuffer_reserve(struct intel_engine_cs *ring,
                        if (!drm_mm_node_allocated(&vma->node))
                                continue;
 
-                       if (eb_vma_misplaced(vma, has_fenced_gpu_access))
+                       if (eb_vma_misplaced(vma))
                                ret = i915_vma_unbind(vma);
                        else
                                ret = i915_gem_execbuffer_reserve_vma(vma, ring, need_relocs);
@@ -744,9 +721,6 @@ i915_gem_execbuffer_relocate_slow(struct drm_device *dev,
        int i, total, ret;
        unsigned count = args->buffer_count;
 
-       if (WARN_ON(list_empty(&eb->vmas)))
-               return 0;
-
        vm = list_first_entry(&eb->vmas, struct i915_vma, exec_list)->vm;
 
        /* We may process another execbuffer during the unlock... */
@@ -890,18 +864,24 @@ i915_gem_check_execbuffer(struct drm_i915_gem_execbuffer2 *exec)
 }
 
 static int
-validate_exec_list(struct drm_i915_gem_exec_object2 *exec,
+validate_exec_list(struct drm_device *dev,
+                  struct drm_i915_gem_exec_object2 *exec,
                   int count)
 {
-       int i;
        unsigned relocs_total = 0;
        unsigned relocs_max = UINT_MAX / sizeof(struct drm_i915_gem_relocation_entry);
+       unsigned invalid_flags;
+       int i;
+
+       invalid_flags = __EXEC_OBJECT_UNKNOWN_FLAGS;
+       if (USES_FULL_PPGTT(dev))
+               invalid_flags |= EXEC_OBJECT_NEEDS_GTT;
 
        for (i = 0; i < count; i++) {
                char __user *ptr = to_user_ptr(exec[i].relocs_ptr);
                int length; /* limited by fault_in_pages_readable() */
 
-               if (exec[i].flags & __EXEC_OBJECT_UNKNOWN_FLAGS)
+               if (exec[i].flags & invalid_flags)
                        return -EINVAL;
 
                /* First check for malicious input causing overflow in
@@ -951,16 +931,26 @@ i915_gem_validate_context(struct drm_device *dev, struct drm_file *file,
                return ERR_PTR(-EIO);
        }
 
+       if (i915.enable_execlists && !ctx->engine[ring->id].state) {
+               int ret = intel_lr_context_deferred_create(ctx, ring);
+               if (ret) {
+                       DRM_DEBUG("Could not create LRC %u: %d\n", ctx_id, ret);
+                       return ERR_PTR(ret);
+               }
+       }
+
        return ctx;
 }
 
-static void
+void
 i915_gem_execbuffer_move_to_active(struct list_head *vmas,
                                   struct intel_engine_cs *ring)
 {
+       u32 seqno = intel_ring_get_seqno(ring);
        struct i915_vma *vma;
 
        list_for_each_entry(vma, vmas, exec_list) {
+               struct drm_i915_gem_exec_object2 *entry = vma->exec_entry;
                struct drm_i915_gem_object *obj = vma->obj;
                u32 old_read = obj->base.read_domains;
                u32 old_write = obj->base.write_domain;
@@ -969,24 +959,31 @@ i915_gem_execbuffer_move_to_active(struct list_head *vmas,
                if (obj->base.write_domain == 0)
                        obj->base.pending_read_domains |= obj->base.read_domains;
                obj->base.read_domains = obj->base.pending_read_domains;
-               obj->fenced_gpu_access = obj->pending_fenced_gpu_access;
 
                i915_vma_move_to_active(vma, ring);
                if (obj->base.write_domain) {
                        obj->dirty = 1;
-                       obj->last_write_seqno = intel_ring_get_seqno(ring);
+                       obj->last_write_seqno = seqno;
 
                        intel_fb_obj_invalidate(obj, ring);
 
                        /* update for the implicit flush after a batch */
                        obj->base.write_domain &= ~I915_GEM_GPU_DOMAINS;
                }
+               if (entry->flags & EXEC_OBJECT_NEEDS_FENCE) {
+                       obj->last_fenced_seqno = seqno;
+                       if (entry->flags & __EXEC_OBJECT_HAS_FENCE) {
+                               struct drm_i915_private *dev_priv = to_i915(ring->dev);
+                               list_move_tail(&dev_priv->fence_regs[obj->fence_reg].lru_list,
+                                              &dev_priv->mm.fence_list);
+                       }
+               }
 
                trace_i915_gem_object_change_domain(obj, old_read, old_write);
        }
 }
 
-static void
+void
 i915_gem_execbuffer_retire_commands(struct drm_device *dev,
                                    struct drm_file *file,
                                    struct intel_engine_cs *ring,
@@ -1026,14 +1023,14 @@ i915_reset_gen7_sol_offsets(struct drm_device *dev,
        return 0;
 }
 
-static int
-legacy_ringbuffer_submission(struct drm_device *dev, struct drm_file *file,
-                            struct intel_engine_cs *ring,
-                            struct intel_context *ctx,
-                            struct drm_i915_gem_execbuffer2 *args,
-                            struct list_head *vmas,
-                            struct drm_i915_gem_object *batch_obj,
-                            u64 exec_start, u32 flags)
+int
+i915_gem_ringbuffer_submission(struct drm_device *dev, struct drm_file *file,
+                              struct intel_engine_cs *ring,
+                              struct intel_context *ctx,
+                              struct drm_i915_gem_execbuffer2 *args,
+                              struct list_head *vmas,
+                              struct drm_i915_gem_object *batch_obj,
+                              u64 exec_start, u32 flags)
 {
        struct drm_clip_rect *cliprects = NULL;
        struct drm_i915_private *dev_priv = dev->dev_private;
@@ -1254,7 +1251,7 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data,
        if (!i915_gem_check_execbuffer(args))
                return -EINVAL;
 
-       ret = validate_exec_list(exec, args->buffer_count);
+       ret = validate_exec_list(dev, exec, args->buffer_count);
        if (ret)
                return ret;
 
@@ -1318,8 +1315,9 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data,
 
        i915_gem_context_reference(ctx);
 
-       vm = ctx->vm;
-       if (!USES_FULL_PPGTT(dev))
+       if (ctx->ppgtt)
+               vm = &ctx->ppgtt->base;
+       else
                vm = &dev_priv->gtt.base;
 
        eb = eb_create(args);
@@ -1386,25 +1384,36 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data,
        /* snb/ivb/vlv conflate the "batch in ppgtt" bit with the "non-secure
         * batch" bit. Hence we need to pin secure batches into the global gtt.
         * hsw should have this fixed, but bdw mucks it up again. */
-       if (flags & I915_DISPATCH_SECURE &&
-           !batch_obj->has_global_gtt_mapping) {
-               /* When we have multiple VMs, we'll need to make sure that we
-                * allocate space first */
-               struct i915_vma *vma = i915_gem_obj_to_ggtt(batch_obj);
-               BUG_ON(!vma);
-               vma->bind_vma(vma, batch_obj->cache_level, GLOBAL_BIND);
-       }
+       if (flags & I915_DISPATCH_SECURE) {
+               /*
+                * So on first glance it looks freaky that we pin the batch here
+                * outside of the reservation loop. But:
+                * - The batch is already pinned into the relevant ppgtt, so we
+                *   already have the backing storage fully allocated.
+                * - No other BO uses the global gtt (well contexts, but meh),
+                *   so we don't really have issues with mutliple objects not
+                *   fitting due to fragmentation.
+                * So this is actually safe.
+                */
+               ret = i915_gem_obj_ggtt_pin(batch_obj, 0, 0);
+               if (ret)
+                       goto err;
 
-       if (flags & I915_DISPATCH_SECURE)
                exec_start += i915_gem_obj_ggtt_offset(batch_obj);
-       else
+       else
                exec_start += i915_gem_obj_offset(batch_obj, vm);
 
-       ret = legacy_ringbuffer_submission(dev, file, ring, ctx,
-                       args, &eb->vmas, batch_obj, exec_start, flags);
-       if (ret)
-               goto err;
+       ret = dev_priv->gt.do_execbuf(dev, file, ring, ctx, args,
+                                     &eb->vmas, batch_obj, exec_start, flags);
 
+       /*
+        * FIXME: We crucially rely upon the active tracking for the (ppgtt)
+        * batch vma for correctness. For less ugly and less fragility this
+        * needs to be adjusted to also track the ggtt batch vma properly as
+        * active.
+        */
+       if (flags & I915_DISPATCH_SECURE)
+               i915_gem_object_ggtt_unpin(batch_obj);
 err:
        /* the request owns the ref now */
        i915_gem_context_unreference(ctx);
index e42925f76b4bb807393040e60c809fa8bc84e096..b672b843fd5e5831323094824116cffe912d8a55 100644 (file)
 static void bdw_setup_private_ppat(struct drm_i915_private *dev_priv);
 static void chv_setup_private_ppat(struct drm_i915_private *dev_priv);
 
-bool intel_enable_ppgtt(struct drm_device *dev, bool full)
-{
-       if (i915.enable_ppgtt == 0)
-               return false;
-
-       if (i915.enable_ppgtt == 1 && full)
-               return false;
-
-       return true;
-}
-
 static int sanitize_enable_ppgtt(struct drm_device *dev, int enable_ppgtt)
 {
        if (enable_ppgtt == 0 || !HAS_ALIASING_PPGTT(dev))
@@ -78,7 +67,6 @@ static void ppgtt_bind_vma(struct i915_vma *vma,
                           enum i915_cache_level cache_level,
                           u32 flags);
 static void ppgtt_unbind_vma(struct i915_vma *vma);
-static int gen8_ppgtt_enable(struct i915_hw_ppgtt *ppgtt);
 
 static inline gen8_gtt_pte_t gen8_pte_encode(dma_addr_t addr,
                                             enum i915_cache_level level,
@@ -216,19 +204,12 @@ static gen6_gtt_pte_t iris_pte_encode(dma_addr_t addr,
 
 /* Broadwell Page Directory Pointer Descriptors */
 static int gen8_write_pdp(struct intel_engine_cs *ring, unsigned entry,
-                          uint64_t val, bool synchronous)
+                          uint64_t val)
 {
-       struct drm_i915_private *dev_priv = ring->dev->dev_private;
        int ret;
 
        BUG_ON(entry >= 4);
 
-       if (synchronous) {
-               I915_WRITE(GEN8_RING_PDP_UDW(ring, entry), val >> 32);
-               I915_WRITE(GEN8_RING_PDP_LDW(ring, entry), (u32)val);
-               return 0;
-       }
-
        ret = intel_ring_begin(ring, 6);
        if (ret)
                return ret;
@@ -245,8 +226,7 @@ static int gen8_write_pdp(struct intel_engine_cs *ring, unsigned entry,
 }
 
 static int gen8_mm_switch(struct i915_hw_ppgtt *ppgtt,
-                         struct intel_engine_cs *ring,
-                         bool synchronous)
+                         struct intel_engine_cs *ring)
 {
        int i, ret;
 
@@ -255,7 +235,7 @@ static int gen8_mm_switch(struct i915_hw_ppgtt *ppgtt,
 
        for (i = used_pd - 1; i >= 0; i--) {
                dma_addr_t addr = ppgtt->pd_dma_addr[i];
-               ret = gen8_write_pdp(ring, i, addr, synchronous);
+               ret = gen8_write_pdp(ring, i, addr);
                if (ret)
                        return ret;
        }
@@ -403,9 +383,6 @@ static void gen8_ppgtt_cleanup(struct i915_address_space *vm)
        struct i915_hw_ppgtt *ppgtt =
                container_of(vm, struct i915_hw_ppgtt, base);
 
-       list_del(&vm->global_link);
-       drm_mm_takedown(&vm->mm);
-
        gen8_ppgtt_unmap_pages(ppgtt);
        gen8_ppgtt_free(ppgtt);
 }
@@ -615,7 +592,6 @@ static int gen8_ppgtt_init(struct i915_hw_ppgtt *ppgtt, uint64_t size)
                kunmap_atomic(pd_vaddr);
        }
 
-       ppgtt->enable = gen8_ppgtt_enable;
        ppgtt->switch_mm = gen8_mm_switch;
        ppgtt->base.clear_range = gen8_ppgtt_clear_range;
        ppgtt->base.insert_entries = gen8_ppgtt_insert_entries;
@@ -724,29 +700,10 @@ static uint32_t get_pd_offset(struct i915_hw_ppgtt *ppgtt)
 }
 
 static int hsw_mm_switch(struct i915_hw_ppgtt *ppgtt,
-                        struct intel_engine_cs *ring,
-                        bool synchronous)
+                        struct intel_engine_cs *ring)
 {
-       struct drm_device *dev = ppgtt->base.dev;
-       struct drm_i915_private *dev_priv = dev->dev_private;
        int ret;
 
-       /* If we're in reset, we can assume the GPU is sufficiently idle to
-        * manually frob these bits. Ideally we could use the ring functions,
-        * except our error handling makes it quite difficult (can't use
-        * intel_ring_begin, ring->flush, or intel_ring_advance)
-        *
-        * FIXME: We should try not to special case reset
-        */
-       if (synchronous ||
-           i915_reset_in_progress(&dev_priv->gpu_error)) {
-               WARN_ON(ppgtt != dev_priv->mm.aliasing_ppgtt);
-               I915_WRITE(RING_PP_DIR_DCLV(ring), PP_DIR_DCLV_2G);
-               I915_WRITE(RING_PP_DIR_BASE(ring), get_pd_offset(ppgtt));
-               POSTING_READ(RING_PP_DIR_BASE(ring));
-               return 0;
-       }
-
        /* NB: TLBs must be flushed and invalidated before a switch */
        ret = ring->flush(ring, I915_GEM_GPU_DOMAINS, I915_GEM_GPU_DOMAINS);
        if (ret)
@@ -768,29 +725,10 @@ static int hsw_mm_switch(struct i915_hw_ppgtt *ppgtt,
 }
 
 static int gen7_mm_switch(struct i915_hw_ppgtt *ppgtt,
-                         struct intel_engine_cs *ring,
-                         bool synchronous)
+                         struct intel_engine_cs *ring)
 {
-       struct drm_device *dev = ppgtt->base.dev;
-       struct drm_i915_private *dev_priv = dev->dev_private;
        int ret;
 
-       /* If we're in reset, we can assume the GPU is sufficiently idle to
-        * manually frob these bits. Ideally we could use the ring functions,
-        * except our error handling makes it quite difficult (can't use
-        * intel_ring_begin, ring->flush, or intel_ring_advance)
-        *
-        * FIXME: We should try not to special case reset
-        */
-       if (synchronous ||
-           i915_reset_in_progress(&dev_priv->gpu_error)) {
-               WARN_ON(ppgtt != dev_priv->mm.aliasing_ppgtt);
-               I915_WRITE(RING_PP_DIR_DCLV(ring), PP_DIR_DCLV_2G);
-               I915_WRITE(RING_PP_DIR_BASE(ring), get_pd_offset(ppgtt));
-               POSTING_READ(RING_PP_DIR_BASE(ring));
-               return 0;
-       }
-
        /* NB: TLBs must be flushed and invalidated before a switch */
        ret = ring->flush(ring, I915_GEM_GPU_DOMAINS, I915_GEM_GPU_DOMAINS);
        if (ret)
@@ -819,14 +757,11 @@ static int gen7_mm_switch(struct i915_hw_ppgtt *ppgtt,
 }
 
 static int gen6_mm_switch(struct i915_hw_ppgtt *ppgtt,
-                         struct intel_engine_cs *ring,
-                         bool synchronous)
+                         struct intel_engine_cs *ring)
 {
        struct drm_device *dev = ppgtt->base.dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
 
-       if (!synchronous)
-               return 0;
 
        I915_WRITE(RING_PP_DIR_DCLV(ring), PP_DIR_DCLV_2G);
        I915_WRITE(RING_PP_DIR_BASE(ring), get_pd_offset(ppgtt));
@@ -836,39 +771,20 @@ static int gen6_mm_switch(struct i915_hw_ppgtt *ppgtt,
        return 0;
 }
 
-static int gen8_ppgtt_enable(struct i915_hw_ppgtt *ppgtt)
+static void gen8_ppgtt_enable(struct drm_device *dev)
 {
-       struct drm_device *dev = ppgtt->base.dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct intel_engine_cs *ring;
-       int j, ret;
+       int j;
 
        for_each_ring(ring, dev_priv, j) {
                I915_WRITE(RING_MODE_GEN7(ring),
                           _MASKED_BIT_ENABLE(GFX_PPGTT_ENABLE));
-
-               /* We promise to do a switch later with FULL PPGTT. If this is
-                * aliasing, this is the one and only switch we'll do */
-               if (USES_FULL_PPGTT(dev))
-                       continue;
-
-               ret = ppgtt->switch_mm(ppgtt, ring, true);
-               if (ret)
-                       goto err_out;
        }
-
-       return 0;
-
-err_out:
-       for_each_ring(ring, dev_priv, j)
-               I915_WRITE(RING_MODE_GEN7(ring),
-                          _MASKED_BIT_DISABLE(GFX_PPGTT_ENABLE));
-       return ret;
 }
 
-static int gen7_ppgtt_enable(struct i915_hw_ppgtt *ppgtt)
+static void gen7_ppgtt_enable(struct drm_device *dev)
 {
-       struct drm_device *dev = ppgtt->base.dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct intel_engine_cs *ring;
        uint32_t ecochk, ecobits;
@@ -887,31 +803,16 @@ static int gen7_ppgtt_enable(struct i915_hw_ppgtt *ppgtt)
        I915_WRITE(GAM_ECOCHK, ecochk);
 
        for_each_ring(ring, dev_priv, i) {
-               int ret;
                /* GFX_MODE is per-ring on gen7+ */
                I915_WRITE(RING_MODE_GEN7(ring),
                           _MASKED_BIT_ENABLE(GFX_PPGTT_ENABLE));
-
-               /* We promise to do a switch later with FULL PPGTT. If this is
-                * aliasing, this is the one and only switch we'll do */
-               if (USES_FULL_PPGTT(dev))
-                       continue;
-
-               ret = ppgtt->switch_mm(ppgtt, ring, true);
-               if (ret)
-                       return ret;
        }
-
-       return 0;
 }
 
-static int gen6_ppgtt_enable(struct i915_hw_ppgtt *ppgtt)
+static void gen6_ppgtt_enable(struct drm_device *dev)
 {
-       struct drm_device *dev = ppgtt->base.dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
-       struct intel_engine_cs *ring;
        uint32_t ecochk, gab_ctl, ecobits;
-       int i;
 
        ecobits = I915_READ(GAC_ECO_BITS);
        I915_WRITE(GAC_ECO_BITS, ecobits | ECOBITS_SNB_BIT |
@@ -924,14 +825,6 @@ static int gen6_ppgtt_enable(struct i915_hw_ppgtt *ppgtt)
        I915_WRITE(GAM_ECOCHK, ecochk | ECOCHK_SNB_BIT | ECOCHK_PPGTT_CACHE64B);
 
        I915_WRITE(GFX_MODE, _MASKED_BIT_ENABLE(GFX_PPGTT_ENABLE));
-
-       for_each_ring(ring, dev_priv, i) {
-               int ret = ppgtt->switch_mm(ppgtt, ring, true);
-               if (ret)
-                       return ret;
-       }
-
-       return 0;
 }
 
 /* PPGTT support for Sandybdrige/Gen6 and later */
@@ -1029,8 +922,6 @@ static void gen6_ppgtt_cleanup(struct i915_address_space *vm)
        struct i915_hw_ppgtt *ppgtt =
                container_of(vm, struct i915_hw_ppgtt, base);
 
-       list_del(&vm->global_link);
-       drm_mm_takedown(&ppgtt->base.mm);
        drm_mm_remove_node(&ppgtt->node);
 
        gen6_ppgtt_unmap_pages(ppgtt);
@@ -1151,13 +1042,10 @@ static int gen6_ppgtt_init(struct i915_hw_ppgtt *ppgtt)
 
        ppgtt->base.pte_encode = dev_priv->gtt.base.pte_encode;
        if (IS_GEN6(dev)) {
-               ppgtt->enable = gen6_ppgtt_enable;
                ppgtt->switch_mm = gen6_mm_switch;
        } else if (IS_HASWELL(dev)) {
-               ppgtt->enable = gen7_ppgtt_enable;
                ppgtt->switch_mm = hsw_mm_switch;
        } else if (IS_GEN7(dev)) {
-               ppgtt->enable = gen7_ppgtt_enable;
                ppgtt->switch_mm = gen7_mm_switch;
        } else
                BUG();
@@ -1188,39 +1076,114 @@ static int gen6_ppgtt_init(struct i915_hw_ppgtt *ppgtt)
                         ppgtt->node.size >> 20,
                         ppgtt->node.start / PAGE_SIZE);
 
+       gen6_write_pdes(ppgtt);
+       DRM_DEBUG("Adding PPGTT at offset %x\n",
+                 ppgtt->pd_offset << 10);
+
        return 0;
 }
 
-int i915_gem_init_ppgtt(struct drm_device *dev, struct i915_hw_ppgtt *ppgtt)
+static int __hw_ppgtt_init(struct drm_device *dev, struct i915_hw_ppgtt *ppgtt)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
-       int ret = 0;
 
        ppgtt->base.dev = dev;
        ppgtt->base.scratch = dev_priv->gtt.base.scratch;
 
        if (INTEL_INFO(dev)->gen < 8)
-               ret = gen6_ppgtt_init(ppgtt);
+               return gen6_ppgtt_init(ppgtt);
        else if (IS_GEN8(dev))
-               ret = gen8_ppgtt_init(ppgtt, dev_priv->gtt.base.total);
+               return gen8_ppgtt_init(ppgtt, dev_priv->gtt.base.total);
        else
                BUG();
+}
+int i915_ppgtt_init(struct drm_device *dev, struct i915_hw_ppgtt *ppgtt)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       int ret = 0;
 
-       if (!ret) {
-               struct drm_i915_private *dev_priv = dev->dev_private;
+       ret = __hw_ppgtt_init(dev, ppgtt);
+       if (ret == 0) {
                kref_init(&ppgtt->ref);
                drm_mm_init(&ppgtt->base.mm, ppgtt->base.start,
                            ppgtt->base.total);
                i915_init_vm(dev_priv, &ppgtt->base);
-               if (INTEL_INFO(dev)->gen < 8) {
-                       gen6_write_pdes(ppgtt);
-                       DRM_DEBUG("Adding PPGTT at offset %x\n",
-                                 ppgtt->pd_offset << 10);
+       }
+
+       return ret;
+}
+
+int i915_ppgtt_init_hw(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct intel_engine_cs *ring;
+       struct i915_hw_ppgtt *ppgtt = dev_priv->mm.aliasing_ppgtt;
+       int i, ret = 0;
+
+       /* In the case of execlists, PPGTT is enabled by the context descriptor
+        * and the PDPs are contained within the context itself.  We don't
+        * need to do anything here. */
+       if (i915.enable_execlists)
+               return 0;
+
+       if (!USES_PPGTT(dev))
+               return 0;
+
+       if (IS_GEN6(dev))
+               gen6_ppgtt_enable(dev);
+       else if (IS_GEN7(dev))
+               gen7_ppgtt_enable(dev);
+       else if (INTEL_INFO(dev)->gen >= 8)
+               gen8_ppgtt_enable(dev);
+       else
+               WARN_ON(1);
+
+       if (ppgtt) {
+               for_each_ring(ring, dev_priv, i) {
+                       ret = ppgtt->switch_mm(ppgtt, ring);
+                       if (ret != 0)
+                               return ret;
                }
        }
 
        return ret;
 }
+struct i915_hw_ppgtt *
+i915_ppgtt_create(struct drm_device *dev, struct drm_i915_file_private *fpriv)
+{
+       struct i915_hw_ppgtt *ppgtt;
+       int ret;
+
+       ppgtt = kzalloc(sizeof(*ppgtt), GFP_KERNEL);
+       if (!ppgtt)
+               return ERR_PTR(-ENOMEM);
+
+       ret = i915_ppgtt_init(dev, ppgtt);
+       if (ret) {
+               kfree(ppgtt);
+               return ERR_PTR(ret);
+       }
+
+       ppgtt->file_priv = fpriv;
+
+       return ppgtt;
+}
+
+void  i915_ppgtt_release(struct kref *kref)
+{
+       struct i915_hw_ppgtt *ppgtt =
+               container_of(kref, struct i915_hw_ppgtt, ref);
+
+       /* vmas should already be unbound */
+       WARN_ON(!list_empty(&ppgtt->base.active_list));
+       WARN_ON(!list_empty(&ppgtt->base.inactive_list));
+
+       list_del(&ppgtt->base.global_link);
+       drm_mm_takedown(&ppgtt->base.mm);
+
+       ppgtt->base.cleanup(&ppgtt->base);
+       kfree(ppgtt);
+}
 
 static void
 ppgtt_bind_vma(struct i915_vma *vma,
@@ -1687,10 +1650,10 @@ static void i915_gtt_color_adjust(struct drm_mm_node *node,
        }
 }
 
-void i915_gem_setup_global_gtt(struct drm_device *dev,
-                              unsigned long start,
-                              unsigned long mappable_end,
-                              unsigned long end)
+int i915_gem_setup_global_gtt(struct drm_device *dev,
+                             unsigned long start,
+                             unsigned long mappable_end,
+                             unsigned long end)
 {
        /* Let GEM Manage all of the aperture.
         *
@@ -1706,6 +1669,7 @@ void i915_gem_setup_global_gtt(struct drm_device *dev,
        struct drm_mm_node *entry;
        struct drm_i915_gem_object *obj;
        unsigned long hole_start, hole_end;
+       int ret;
 
        BUG_ON(mappable_end > end);
 
@@ -1717,14 +1681,16 @@ void i915_gem_setup_global_gtt(struct drm_device *dev,
        /* Mark any preallocated objects as occupied */
        list_for_each_entry(obj, &dev_priv->mm.bound_list, global_list) {
                struct i915_vma *vma = i915_gem_obj_to_vma(obj, ggtt_vm);
-               int ret;
+
                DRM_DEBUG_KMS("reserving preallocated space: %lx + %zx\n",
                              i915_gem_obj_ggtt_offset(obj), obj->base.size);
 
                WARN_ON(i915_gem_obj_ggtt_bound(obj));
                ret = drm_mm_reserve_node(&ggtt_vm->mm, &vma->node);
-               if (ret)
-                       DRM_DEBUG_KMS("Reservation failed\n");
+               if (ret) {
+                       DRM_DEBUG_KMS("Reservation failed: %i\n", ret);
+                       return ret;
+               }
                obj->has_global_gtt_mapping = 1;
        }
 
@@ -1741,6 +1707,22 @@ void i915_gem_setup_global_gtt(struct drm_device *dev,
 
        /* And finally clear the reserved guard page */
        ggtt_vm->clear_range(ggtt_vm, end - PAGE_SIZE, PAGE_SIZE, true);
+
+       if (USES_PPGTT(dev) && !USES_FULL_PPGTT(dev)) {
+               struct i915_hw_ppgtt *ppgtt;
+
+               ppgtt = kzalloc(sizeof(*ppgtt), GFP_KERNEL);
+               if (!ppgtt)
+                       return -ENOMEM;
+
+               ret = __hw_ppgtt_init(dev, ppgtt);
+               if (ret != 0)
+                       return ret;
+
+               dev_priv->mm.aliasing_ppgtt = ppgtt;
+       }
+
+       return 0;
 }
 
 void i915_gem_init_global_gtt(struct drm_device *dev)
@@ -1754,6 +1736,25 @@ void i915_gem_init_global_gtt(struct drm_device *dev)
        i915_gem_setup_global_gtt(dev, 0, mappable_size, gtt_size);
 }
 
+void i915_global_gtt_cleanup(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct i915_address_space *vm = &dev_priv->gtt.base;
+
+       if (dev_priv->mm.aliasing_ppgtt) {
+               struct i915_hw_ppgtt *ppgtt = dev_priv->mm.aliasing_ppgtt;
+
+               ppgtt->base.cleanup(&ppgtt->base);
+       }
+
+       if (drm_mm_initialized(&vm->mm)) {
+               drm_mm_takedown(&vm->mm);
+               list_del(&vm->global_link);
+       }
+
+       vm->cleanup(vm);
+}
+
 static int setup_scratch_page(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
@@ -2022,10 +2023,6 @@ static void gen6_gmch_remove(struct i915_address_space *vm)
 
        struct i915_gtt *gtt = container_of(vm, struct i915_gtt, base);
 
-       if (drm_mm_initialized(&vm->mm)) {
-               drm_mm_takedown(&vm->mm);
-               list_del(&vm->global_link);
-       }
        iounmap(gtt->gsm);
        teardown_scratch_page(vm->dev);
 }
@@ -2058,10 +2055,6 @@ static int i915_gmch_probe(struct drm_device *dev,
 
 static void i915_gmch_remove(struct i915_address_space *vm)
 {
-       if (drm_mm_initialized(&vm->mm)) {
-               drm_mm_takedown(&vm->mm);
-               list_del(&vm->global_link);
-       }
        intel_gmch_remove();
 }
 
@@ -2160,8 +2153,10 @@ static struct i915_vma *__i915_gem_vma_create(struct drm_i915_gem_object *obj,
        /* Keep GGTT vmas first to make debug easier */
        if (i915_is_ggtt(vm))
                list_add(&vma->vma_link, &obj->vma_list);
-       else
+       else {
                list_add_tail(&vma->vma_link, &obj->vma_list);
+               i915_ppgtt_get(i915_vm_to_ppgtt(vm));
+       }
 
        return vma;
 }
index 8d6f7c18c40413bf46288bec1144d26b5fc652dc..d5c14af51e995d5c19a6d37b950dc2691a44ffb2 100644 (file)
@@ -34,6 +34,8 @@
 #ifndef __I915_GEM_GTT_H__
 #define __I915_GEM_GTT_H__
 
+struct drm_i915_file_private;
+
 typedef uint32_t gen6_gtt_pte_t;
 typedef uint64_t gen8_gtt_pte_t;
 typedef gen8_gtt_pte_t gen8_ppgtt_pde_t;
@@ -258,22 +260,36 @@ struct i915_hw_ppgtt {
                dma_addr_t *gen8_pt_dma_addr[4];
        };
 
-       struct intel_context *ctx;
+       struct drm_i915_file_private *file_priv;
 
        int (*enable)(struct i915_hw_ppgtt *ppgtt);
        int (*switch_mm)(struct i915_hw_ppgtt *ppgtt,
-                        struct intel_engine_cs *ring,
-                        bool synchronous);
+                        struct intel_engine_cs *ring);
        void (*debug_dump)(struct i915_hw_ppgtt *ppgtt, struct seq_file *m);
 };
 
 int i915_gem_gtt_init(struct drm_device *dev);
 void i915_gem_init_global_gtt(struct drm_device *dev);
-void i915_gem_setup_global_gtt(struct drm_device *dev, unsigned long start,
-                              unsigned long mappable_end, unsigned long end);
-
-bool intel_enable_ppgtt(struct drm_device *dev, bool full);
-int i915_gem_init_ppgtt(struct drm_device *dev, struct i915_hw_ppgtt *ppgtt);
+int i915_gem_setup_global_gtt(struct drm_device *dev, unsigned long start,
+                             unsigned long mappable_end, unsigned long end);
+void i915_global_gtt_cleanup(struct drm_device *dev);
+
+
+int i915_ppgtt_init(struct drm_device *dev, struct i915_hw_ppgtt *ppgtt);
+int i915_ppgtt_init_hw(struct drm_device *dev);
+void i915_ppgtt_release(struct kref *kref);
+struct i915_hw_ppgtt *i915_ppgtt_create(struct drm_device *dev,
+                                       struct drm_i915_file_private *fpriv);
+static inline void i915_ppgtt_get(struct i915_hw_ppgtt *ppgtt)
+{
+       if (ppgtt)
+               kref_get(&ppgtt->ref);
+}
+static inline void i915_ppgtt_put(struct i915_hw_ppgtt *ppgtt)
+{
+       if (ppgtt)
+               kref_put(&ppgtt->ref, i915_ppgtt_release);
+}
 
 void i915_check_and_clear_faults(struct drm_device *dev);
 void i915_gem_suspend_gtt_mappings(struct drm_device *dev);
index e60be3f552a6b1aed14770bef853a1eab2ddf5aa..a9a62d75aa577daa015543c7955c25cd5bf5b42a 100644 (file)
 #include "i915_drv.h"
 #include "intel_renderstate.h"
 
-struct render_state {
-       const struct intel_renderstate_rodata *rodata;
-       struct drm_i915_gem_object *obj;
-       u64 ggtt_offset;
-       int gen;
-};
-
 static const struct intel_renderstate_rodata *
 render_state_get_rodata(struct drm_device *dev, const int gen)
 {
@@ -127,30 +120,47 @@ static int render_state_setup(struct render_state *so)
        return 0;
 }
 
-static void render_state_fini(struct render_state *so)
+void i915_gem_render_state_fini(struct render_state *so)
 {
        i915_gem_object_ggtt_unpin(so->obj);
        drm_gem_object_unreference(&so->obj->base);
 }
 
-int i915_gem_render_state_init(struct intel_engine_cs *ring)
+int i915_gem_render_state_prepare(struct intel_engine_cs *ring,
+                                 struct render_state *so)
 {
-       struct render_state so;
        int ret;
 
        if (WARN_ON(ring->id != RCS))
                return -ENOENT;
 
-       ret = render_state_init(&so, ring->dev);
+       ret = render_state_init(so, ring->dev);
        if (ret)
                return ret;
 
-       if (so.rodata == NULL)
+       if (so->rodata == NULL)
                return 0;
 
-       ret = render_state_setup(&so);
+       ret = render_state_setup(so);
+       if (ret) {
+               i915_gem_render_state_fini(so);
+               return ret;
+       }
+
+       return 0;
+}
+
+int i915_gem_render_state_init(struct intel_engine_cs *ring)
+{
+       struct render_state so;
+       int ret;
+
+       ret = i915_gem_render_state_prepare(ring, &so);
        if (ret)
-               goto out;
+               return ret;
+
+       if (so.rodata == NULL)
+               return 0;
 
        ret = ring->dispatch_execbuffer(ring,
                                        so.ggtt_offset,
@@ -164,6 +174,6 @@ int i915_gem_render_state_init(struct intel_engine_cs *ring)
        ret = __i915_add_request(ring, NULL, so.obj, NULL);
        /* __i915_add_request moves object to inactive if it fails */
 out:
-       render_state_fini(&so);
+       i915_gem_render_state_fini(&so);
        return ret;
 }
diff --git a/drivers/gpu/drm/i915/i915_gem_render_state.h b/drivers/gpu/drm/i915/i915_gem_render_state.h
new file mode 100644 (file)
index 0000000..c44961e
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * Copyright Â© 2014 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef _I915_GEM_RENDER_STATE_H_
+#define _I915_GEM_RENDER_STATE_H_
+
+#include <linux/types.h>
+
+struct intel_renderstate_rodata {
+       const u32 *reloc;
+       const u32 *batch;
+       const u32 batch_items;
+};
+
+struct render_state {
+       const struct intel_renderstate_rodata *rodata;
+       struct drm_i915_gem_object *obj;
+       u64 ggtt_offset;
+       int gen;
+};
+
+int i915_gem_render_state_init(struct intel_engine_cs *ring);
+void i915_gem_render_state_fini(struct render_state *so);
+int i915_gem_render_state_prepare(struct intel_engine_cs *ring,
+                                 struct render_state *so);
+
+#endif /* _I915_GEM_RENDER_STATE_H_ */
index 21c025a209c079a88095fa8bd0de6c6d2926aa66..85fda6b803e4d33b8fbb405127f1a3d702478a8e 100644 (file)
@@ -289,6 +289,7 @@ void i915_gem_cleanup_stolen(struct drm_device *dev)
 int i915_gem_init_stolen(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
+       u32 tmp;
        int bios_reserved = 0;
 
 #ifdef CONFIG_INTEL_IOMMU
@@ -308,8 +309,16 @@ int i915_gem_init_stolen(struct drm_device *dev)
        DRM_DEBUG_KMS("found %zd bytes of stolen memory at %08lx\n",
                      dev_priv->gtt.stolen_size, dev_priv->mm.stolen_base);
 
-       if (IS_VALLEYVIEW(dev))
-               bios_reserved = 1024*1024; /* top 1M on VLV/BYT */
+       if (INTEL_INFO(dev)->gen >= 8) {
+               tmp = I915_READ(GEN7_BIOS_RESERVED);
+               tmp >>= GEN8_BIOS_RESERVED_SHIFT;
+               tmp &= GEN8_BIOS_RESERVED_MASK;
+               bios_reserved = (1024*1024) << tmp;
+       } else if (IS_GEN7(dev)) {
+               tmp = I915_READ(GEN7_BIOS_RESERVED);
+               bios_reserved = tmp & GEN7_BIOS_RESERVED_256K ?
+                       256*1024 : 1024*1024;
+       }
 
        if (WARN_ON(bios_reserved > dev_priv->gtt.stolen_size))
                return 0;
index cb150e8b433658feaa3ecf6f4d817bc5b495a953..2cefb597df6dc92d446557442073d5c998843a30 100644 (file)
@@ -91,7 +91,14 @@ i915_gem_detect_bit_6_swizzle(struct drm_device *dev)
        uint32_t swizzle_x = I915_BIT_6_SWIZZLE_UNKNOWN;
        uint32_t swizzle_y = I915_BIT_6_SWIZZLE_UNKNOWN;
 
-       if (IS_VALLEYVIEW(dev)) {
+       if (INTEL_INFO(dev)->gen >= 8 || IS_VALLEYVIEW(dev)) {
+               /*
+                * On BDW+, swizzling is not used. We leave the CPU memory
+                * controller in charge of optimizing memory accesses without
+                * the extra address manipulation GPU side.
+                *
+                * VLV and CHV don't have GPU swizzling.
+                */
                swizzle_x = I915_BIT_6_SWIZZLE_NONE;
                swizzle_y = I915_BIT_6_SWIZZLE_NONE;
        } else if (INTEL_INFO(dev)->gen >= 6) {
@@ -376,7 +383,7 @@ i915_gem_set_tiling(struct drm_device *dev, void *data,
 
                if (ret == 0) {
                        obj->fence_dirty =
-                               obj->fenced_gpu_access ||
+                               obj->last_fenced_seqno ||
                                obj->fence_reg != I915_FENCE_REG_NONE;
 
                        obj->tiling_mode = args->tiling_mode;
index d384139973790e09d2da3583861c7224b1596f44..d182058383a9ef7264339101265e511ac8fa0609 100644 (file)
@@ -293,15 +293,23 @@ i915_gem_userptr_release__mmu_notifier(struct drm_i915_gem_object *obj)
 static struct i915_mmu_notifier *
 i915_mmu_notifier_find(struct i915_mm_struct *mm)
 {
-       if (mm->mn == NULL) {
-               down_write(&mm->mm->mmap_sem);
-               mutex_lock(&to_i915(mm->dev)->mm_lock);
-               if (mm->mn == NULL)
-                       mm->mn = i915_mmu_notifier_create(mm->mm);
-               mutex_unlock(&to_i915(mm->dev)->mm_lock);
-               up_write(&mm->mm->mmap_sem);
+       struct i915_mmu_notifier *mn = mm->mn;
+
+       mn = mm->mn;
+       if (mn)
+               return mn;
+
+       down_write(&mm->mm->mmap_sem);
+       mutex_lock(&to_i915(mm->dev)->mm_lock);
+       if ((mn = mm->mn) == NULL) {
+               mn = i915_mmu_notifier_create(mm->mm);
+               if (!IS_ERR(mn))
+                       mm->mn = mn;
        }
-       return mm->mn;
+       mutex_unlock(&to_i915(mm->dev)->mm_lock);
+       up_write(&mm->mm->mmap_sem);
+
+       return mn;
 }
 
 static int
@@ -681,16 +689,15 @@ i915_gem_userptr_get_pages(struct drm_i915_gem_object *obj)
 static void
 i915_gem_userptr_put_pages(struct drm_i915_gem_object *obj)
 {
-       struct scatterlist *sg;
-       int i;
+       struct sg_page_iter sg_iter;
 
        BUG_ON(obj->userptr.work != NULL);
 
        if (obj->madv != I915_MADV_WILLNEED)
                obj->dirty = 0;
 
-       for_each_sg(obj->pages->sgl, sg, obj->pages->nents, i) {
-               struct page *page = sg_page(sg);
+       for_each_sg_page(obj->pages->sgl, &sg_iter, obj->pages->nents, 0) {
+               struct page *page = sg_page_iter_page(&sg_iter);
 
                if (obj->dirty)
                        set_page_dirty(page);
index eab41f9390f8c3bd1907c7625488c977a910ead3..2c87a797213f4e94305be2846bd9a7caa5765d51 100644 (file)
@@ -192,10 +192,10 @@ static void print_error_buffers(struct drm_i915_error_state_buf *m,
                                struct drm_i915_error_buffer *err,
                                int count)
 {
-       err_printf(m, "%s [%d]:\n", name, count);
+       err_printf(m, "  %s [%d]:\n", name, count);
 
        while (count--) {
-               err_printf(m, "  %08x %8u %02x %02x %x %x",
+               err_printf(m, "    %08x %8u %02x %02x %x %x",
                           err->gtt_offset,
                           err->size,
                           err->read_domains,
@@ -208,7 +208,7 @@ static void print_error_buffers(struct drm_i915_error_state_buf *m,
                err_puts(m, err->userptr ? " userptr" : "");
                err_puts(m, err->ring != -1 ? " " : "");
                err_puts(m, ring_str(err->ring));
-               err_puts(m, i915_cache_level_str(err->cache_level));
+               err_puts(m, i915_cache_level_str(m->i915, err->cache_level));
 
                if (err->name)
                        err_printf(m, " (name: %d)", err->name);
@@ -393,15 +393,17 @@ int i915_error_state_to_str(struct drm_i915_error_state_buf *m,
                i915_ring_error_state(m, dev, &error->ring[i]);
        }
 
-       if (error->active_bo)
+       for (i = 0; i < error->vm_count; i++) {
+               err_printf(m, "vm[%d]\n", i);
+
                print_error_buffers(m, "Active",
-                                   error->active_bo[0],
-                                   error->active_bo_count[0]);
+                                   error->active_bo[i],
+                                   error->active_bo_count[i]);
 
-       if (error->pinned_bo)
                print_error_buffers(m, "Pinned",
-                                   error->pinned_bo[0],
-                                   error->pinned_bo_count[0]);
+                                   error->pinned_bo[i],
+                                   error->pinned_bo_count[i]);
+       }
 
        for (i = 0; i < ARRAY_SIZE(error->ring); i++) {
                obj = error->ring[i].batchbuffer;
@@ -492,9 +494,11 @@ out:
 }
 
 int i915_error_state_buf_init(struct drm_i915_error_state_buf *ebuf,
+                             struct drm_i915_private *i915,
                              size_t count, loff_t pos)
 {
        memset(ebuf, 0, sizeof(*ebuf));
+       ebuf->i915 = i915;
 
        /* We need to have enough room to store any i915_error_state printf
         * so that we can move it to start position.
@@ -556,24 +560,54 @@ static void i915_error_state_free(struct kref *error_ref)
 }
 
 static struct drm_i915_error_object *
-i915_error_object_create_sized(struct drm_i915_private *dev_priv,
-                              struct drm_i915_gem_object *src,
-                              struct i915_address_space *vm,
-                              const int num_pages)
+i915_error_object_create(struct drm_i915_private *dev_priv,
+                        struct drm_i915_gem_object *src,
+                        struct i915_address_space *vm)
 {
        struct drm_i915_error_object *dst;
-       int i;
+       int num_pages;
+       bool use_ggtt;
+       int i = 0;
        u32 reloc_offset;
 
        if (src == NULL || src->pages == NULL)
                return NULL;
 
+       num_pages = src->base.size >> PAGE_SHIFT;
+
        dst = kmalloc(sizeof(*dst) + num_pages * sizeof(u32 *), GFP_ATOMIC);
        if (dst == NULL)
                return NULL;
 
-       reloc_offset = dst->gtt_offset = i915_gem_obj_offset(src, vm);
-       for (i = 0; i < num_pages; i++) {
+       if (i915_gem_obj_bound(src, vm))
+               dst->gtt_offset = i915_gem_obj_offset(src, vm);
+       else
+               dst->gtt_offset = -1;
+
+       reloc_offset = dst->gtt_offset;
+       use_ggtt = (src->cache_level == I915_CACHE_NONE &&
+                   i915_is_ggtt(vm) &&
+                   src->has_global_gtt_mapping &&
+                   reloc_offset + num_pages * PAGE_SIZE <= dev_priv->gtt.mappable_end);
+
+       /* Cannot access stolen address directly, try to use the aperture */
+       if (src->stolen) {
+               use_ggtt = true;
+
+               if (!src->has_global_gtt_mapping)
+                       goto unwind;
+
+               reloc_offset = i915_gem_obj_ggtt_offset(src);
+               if (reloc_offset + num_pages * PAGE_SIZE > dev_priv->gtt.mappable_end)
+                       goto unwind;
+       }
+
+       /* Cannot access snooped pages through the aperture */
+       if (use_ggtt && src->cache_level != I915_CACHE_NONE && !HAS_LLC(dev_priv->dev))
+               goto unwind;
+
+       dst->page_count = num_pages;
+       while (num_pages--) {
                unsigned long flags;
                void *d;
 
@@ -582,10 +616,7 @@ i915_error_object_create_sized(struct drm_i915_private *dev_priv,
                        goto unwind;
 
                local_irq_save(flags);
-               if (src->cache_level == I915_CACHE_NONE &&
-                   reloc_offset < dev_priv->gtt.mappable_end &&
-                   src->has_global_gtt_mapping &&
-                   i915_is_ggtt(vm)) {
+               if (use_ggtt) {
                        void __iomem *s;
 
                        /* Simply ignore tiling or any overlapping fence.
@@ -597,14 +628,6 @@ i915_error_object_create_sized(struct drm_i915_private *dev_priv,
                                                     reloc_offset);
                        memcpy_fromio(d, s, PAGE_SIZE);
                        io_mapping_unmap_atomic(s);
-               } else if (src->stolen) {
-                       unsigned long offset;
-
-                       offset = dev_priv->mm.stolen_base;
-                       offset += src->stolen->start;
-                       offset += i << PAGE_SHIFT;
-
-                       memcpy_fromio(d, (void __iomem *) offset, PAGE_SIZE);
                } else {
                        struct page *page;
                        void *s;
@@ -621,11 +644,9 @@ i915_error_object_create_sized(struct drm_i915_private *dev_priv,
                }
                local_irq_restore(flags);
 
-               dst->pages[i] = d;
-
+               dst->pages[i++] = d;
                reloc_offset += PAGE_SIZE;
        }
-       dst->page_count = num_pages;
 
        return dst;
 
@@ -635,22 +656,19 @@ unwind:
        kfree(dst);
        return NULL;
 }
-#define i915_error_object_create(dev_priv, src, vm) \
-       i915_error_object_create_sized((dev_priv), (src), (vm), \
-                                      (src)->base.size>>PAGE_SHIFT)
-
 #define i915_error_ggtt_object_create(dev_priv, src) \
-       i915_error_object_create_sized((dev_priv), (src), &(dev_priv)->gtt.base, \
-                                      (src)->base.size>>PAGE_SHIFT)
+       i915_error_object_create((dev_priv), (src), &(dev_priv)->gtt.base)
 
 static void capture_bo(struct drm_i915_error_buffer *err,
-                      struct drm_i915_gem_object *obj)
+                      struct i915_vma *vma)
 {
+       struct drm_i915_gem_object *obj = vma->obj;
+
        err->size = obj->base.size;
        err->name = obj->base.name;
        err->rseqno = obj->last_read_seqno;
        err->wseqno = obj->last_write_seqno;
-       err->gtt_offset = i915_gem_obj_ggtt_offset(obj);
+       err->gtt_offset = vma->node.start;
        err->read_domains = obj->base.read_domains;
        err->write_domain = obj->base.write_domain;
        err->fence_reg = obj->fence_reg;
@@ -674,7 +692,7 @@ static u32 capture_active_bo(struct drm_i915_error_buffer *err,
        int i = 0;
 
        list_for_each_entry(vma, head, mm_list) {
-               capture_bo(err++, vma->obj);
+               capture_bo(err++, vma);
                if (++i == count)
                        break;
        }
@@ -683,21 +701,27 @@ static u32 capture_active_bo(struct drm_i915_error_buffer *err,
 }
 
 static u32 capture_pinned_bo(struct drm_i915_error_buffer *err,
-                            int count, struct list_head *head)
+                            int count, struct list_head *head,
+                            struct i915_address_space *vm)
 {
        struct drm_i915_gem_object *obj;
-       int i = 0;
+       struct drm_i915_error_buffer * const first = err;
+       struct drm_i915_error_buffer * const last = err + count;
 
        list_for_each_entry(obj, head, global_list) {
-               if (!i915_gem_obj_is_pinned(obj))
-                       continue;
+               struct i915_vma *vma;
 
-               capture_bo(err++, obj);
-               if (++i == count)
+               if (err == last)
                        break;
+
+               list_for_each_entry(vma, &obj->vma_list, vma_link)
+                       if (vma->vm == vm && vma->pin_count > 0) {
+                               capture_bo(err++, vma);
+                               break;
+                       }
        }
 
-       return i;
+       return err - first;
 }
 
 /* Generate a semi-unique error code. The code is not meant to have meaning, The
@@ -890,9 +914,6 @@ static void i915_record_ring_state(struct drm_device *dev,
                ering->hws = I915_READ(mmio);
        }
 
-       ering->cpu_ring_head = ring->buffer->head;
-       ering->cpu_ring_tail = ring->buffer->tail;
-
        ering->hangcheck_score = ring->hangcheck.score;
        ering->hangcheck_action = ring->hangcheck.action;
 
@@ -955,6 +976,7 @@ static void i915_gem_record_rings(struct drm_device *dev,
 
        for (i = 0; i < I915_NUM_RINGS; i++) {
                struct intel_engine_cs *ring = &dev_priv->ring[i];
+               struct intel_ringbuffer *rbuf;
 
                error->ring[i].pid = -1;
 
@@ -967,6 +989,12 @@ static void i915_gem_record_rings(struct drm_device *dev,
 
                request = i915_gem_find_active_request(ring);
                if (request) {
+                       struct i915_address_space *vm;
+
+                       vm = request->ctx && request->ctx->ppgtt ?
+                               &request->ctx->ppgtt->base :
+                               &dev_priv->gtt.base;
+
                        /* We need to copy these to an anonymous buffer
                         * as the simplest method to avoid being overwritten
                         * by userspace.
@@ -974,12 +1002,9 @@ static void i915_gem_record_rings(struct drm_device *dev,
                        error->ring[i].batchbuffer =
                                i915_error_object_create(dev_priv,
                                                         request->batch_obj,
-                                                        request->ctx ?
-                                                        request->ctx->vm :
-                                                        &dev_priv->gtt.base);
+                                                        vm);
 
-                       if (HAS_BROKEN_CS_TLB(dev_priv->dev) &&
-                           ring->scratch.obj)
+                       if (HAS_BROKEN_CS_TLB(dev_priv->dev))
                                error->ring[i].wa_batchbuffer =
                                        i915_error_ggtt_object_create(dev_priv,
                                                             ring->scratch.obj);
@@ -998,12 +1023,27 @@ static void i915_gem_record_rings(struct drm_device *dev,
                        }
                }
 
+               if (i915.enable_execlists) {
+                       /* TODO: This is only a small fix to keep basic error
+                        * capture working, but we need to add more information
+                        * for it to be useful (e.g. dump the context being
+                        * executed).
+                        */
+                       if (request)
+                               rbuf = request->ctx->engine[ring->id].ringbuf;
+                       else
+                               rbuf = ring->default_context->engine[ring->id].ringbuf;
+               } else
+                       rbuf = ring->buffer;
+
+               error->ring[i].cpu_ring_head = rbuf->head;
+               error->ring[i].cpu_ring_tail = rbuf->tail;
+
                error->ring[i].ringbuffer =
-                       i915_error_ggtt_object_create(dev_priv, ring->buffer->obj);
+                       i915_error_ggtt_object_create(dev_priv, rbuf->obj);
 
-               if (ring->status_page.obj)
-                       error->ring[i].hws_page =
-                               i915_error_ggtt_object_create(dev_priv, ring->status_page.obj);
+               error->ring[i].hws_page =
+                       i915_error_ggtt_object_create(dev_priv, ring->status_page.obj);
 
                i915_gem_record_active_context(ring, error, &error->ring[i]);
 
@@ -1049,9 +1089,14 @@ static void i915_gem_capture_vm(struct drm_i915_private *dev_priv,
        list_for_each_entry(vma, &vm->active_list, mm_list)
                i++;
        error->active_bo_count[ndx] = i;
-       list_for_each_entry(obj, &dev_priv->mm.bound_list, global_list)
-               if (i915_gem_obj_is_pinned(obj))
-                       i++;
+
+       list_for_each_entry(obj, &dev_priv->mm.bound_list, global_list) {
+               list_for_each_entry(vma, &obj->vma_list, vma_link)
+                       if (vma->vm == vm && vma->pin_count > 0) {
+                               i++;
+                               break;
+                       }
+       }
        error->pinned_bo_count[ndx] = i - error->active_bo_count[ndx];
 
        if (i) {
@@ -1070,7 +1115,7 @@ static void i915_gem_capture_vm(struct drm_i915_private *dev_priv,
                error->pinned_bo_count[ndx] =
                        capture_pinned_bo(pinned_bo,
                                          error->pinned_bo_count[ndx],
-                                         &dev_priv->mm.bound_list);
+                                         &dev_priv->mm.bound_list, vm);
        error->active_bo[ndx] = active_bo;
        error->pinned_bo[ndx] = pinned_bo;
 }
@@ -1091,8 +1136,25 @@ static void i915_gem_capture_buffers(struct drm_i915_private *dev_priv,
        error->pinned_bo_count = kcalloc(cnt, sizeof(*error->pinned_bo_count),
                                         GFP_ATOMIC);
 
-       list_for_each_entry(vm, &dev_priv->vm_list, global_link)
-               i915_gem_capture_vm(dev_priv, error, vm, i++);
+       if (error->active_bo == NULL ||
+           error->pinned_bo == NULL ||
+           error->active_bo_count == NULL ||
+           error->pinned_bo_count == NULL) {
+               kfree(error->active_bo);
+               kfree(error->active_bo_count);
+               kfree(error->pinned_bo);
+               kfree(error->pinned_bo_count);
+
+               error->active_bo = NULL;
+               error->active_bo_count = NULL;
+               error->pinned_bo = NULL;
+               error->pinned_bo_count = NULL;
+       } else {
+               list_for_each_entry(vm, &dev_priv->vm_list, global_link)
+                       i915_gem_capture_vm(dev_priv, error, vm, i++);
+
+               error->vm_count = cnt;
+       }
 }
 
 /* Capture all registers which don't fit into another category. */
@@ -1295,11 +1357,11 @@ void i915_destroy_error_state(struct drm_device *dev)
                kref_put(&error->ref, i915_error_state_free);
 }
 
-const char *i915_cache_level_str(int type)
+const char *i915_cache_level_str(struct drm_i915_private *i915, int type)
 {
        switch (type) {
        case I915_CACHE_NONE: return " uncached";
-       case I915_CACHE_LLC: return " snooped or LLC";
+       case I915_CACHE_LLC: return HAS_LLC(i915) ? " LLC" : " snooped";
        case I915_CACHE_L3_LLC: return " L3+LLC";
        case I915_CACHE_WT: return " WT";
        default: return "";
index 0050ee9470f196748621b96ffd001cd3e4cd85d8..3201986bf25ebaf6a5b2a31089bd2e2b1871e09d 100644 (file)
@@ -151,7 +151,7 @@ ironlake_disable_display_irq(struct drm_i915_private *dev_priv, u32 mask)
 {
        assert_spin_locked(&dev_priv->irq_lock);
 
-       if (!intel_irqs_enabled(dev_priv))
+       if (WARN_ON(!intel_irqs_enabled(dev_priv)))
                return;
 
        if ((dev_priv->irq_mask & mask) != mask) {
@@ -238,7 +238,7 @@ static bool ivb_can_enable_err_int(struct drm_device *dev)
 
        assert_spin_locked(&dev_priv->irq_lock);
 
-       for_each_pipe(pipe) {
+       for_each_pipe(dev_priv, pipe) {
                crtc = to_intel_crtc(dev_priv->pipe_to_crtc_mapping[pipe]);
 
                if (crtc->cpu_fifo_underrun_disabled)
@@ -296,7 +296,7 @@ static bool cpt_can_enable_serr_int(struct drm_device *dev)
 
        assert_spin_locked(&dev_priv->irq_lock);
 
-       for_each_pipe(pipe) {
+       for_each_pipe(dev_priv, pipe) {
                crtc = to_intel_crtc(dev_priv->pipe_to_crtc_mapping[pipe]);
 
                if (crtc->pch_fifo_underrun_disabled)
@@ -497,7 +497,7 @@ static bool __intel_set_cpu_fifo_underrun_reporting(struct drm_device *dev,
        old = !intel_crtc->cpu_fifo_underrun_disabled;
        intel_crtc->cpu_fifo_underrun_disabled = !enable;
 
-       if (INTEL_INFO(dev)->gen < 5 || IS_VALLEYVIEW(dev))
+       if (HAS_GMCH_DISPLAY(dev))
                i9xx_set_fifo_underrun_reporting(dev, pipe, enable, old);
        else if (IS_GEN5(dev) || IS_GEN6(dev))
                ironlake_set_fifo_underrun_reporting(dev, pipe, enable);
@@ -1020,7 +1020,7 @@ static int i915_get_crtc_scanoutpos(struct drm_device *dev, int pipe,
 
        /* In vblank? */
        if (in_vbl)
-               ret |= DRM_SCANOUTPOS_INVBL;
+               ret |= DRM_SCANOUTPOS_IN_VBLANK;
 
        return ret;
 }
@@ -1322,10 +1322,10 @@ static u32 vlv_c0_residency(struct drm_i915_private *dev_priv,
  * @dev_priv: DRM device private
  *
  */
-static u32 vlv_calc_delay_from_C0_counters(struct drm_i915_private *dev_priv)
+static int vlv_calc_delay_from_C0_counters(struct drm_i915_private *dev_priv)
 {
        u32 residency_C0_up = 0, residency_C0_down = 0;
-       u8 new_delay, adj;
+       int new_delay, adj;
 
        dev_priv->rps.ei_interrupt_count++;
 
@@ -1627,6 +1627,7 @@ static irqreturn_t gen8_gt_irq_handler(struct drm_device *dev,
                                       struct drm_i915_private *dev_priv,
                                       u32 master_ctl)
 {
+       struct intel_engine_cs *ring;
        u32 rcs, bcs, vcs;
        uint32_t tmp = 0;
        irqreturn_t ret = IRQ_NONE;
@@ -1636,12 +1637,20 @@ static irqreturn_t gen8_gt_irq_handler(struct drm_device *dev,
                if (tmp) {
                        I915_WRITE(GEN8_GT_IIR(0), tmp);
                        ret = IRQ_HANDLED;
+
                        rcs = tmp >> GEN8_RCS_IRQ_SHIFT;
-                       bcs = tmp >> GEN8_BCS_IRQ_SHIFT;
+                       ring = &dev_priv->ring[RCS];
                        if (rcs & GT_RENDER_USER_INTERRUPT)
-                               notify_ring(dev, &dev_priv->ring[RCS]);
+                               notify_ring(dev, ring);
+                       if (rcs & GT_CONTEXT_SWITCH_INTERRUPT)
+                               intel_execlists_handle_ctx_events(ring);
+
+                       bcs = tmp >> GEN8_BCS_IRQ_SHIFT;
+                       ring = &dev_priv->ring[BCS];
                        if (bcs & GT_RENDER_USER_INTERRUPT)
-                               notify_ring(dev, &dev_priv->ring[BCS]);
+                               notify_ring(dev, ring);
+                       if (bcs & GT_CONTEXT_SWITCH_INTERRUPT)
+                               intel_execlists_handle_ctx_events(ring);
                } else
                        DRM_ERROR("The master control interrupt lied (GT0)!\n");
        }
@@ -1651,12 +1660,20 @@ static irqreturn_t gen8_gt_irq_handler(struct drm_device *dev,
                if (tmp) {
                        I915_WRITE(GEN8_GT_IIR(1), tmp);
                        ret = IRQ_HANDLED;
+
                        vcs = tmp >> GEN8_VCS1_IRQ_SHIFT;
+                       ring = &dev_priv->ring[VCS];
                        if (vcs & GT_RENDER_USER_INTERRUPT)
-                               notify_ring(dev, &dev_priv->ring[VCS]);
+                               notify_ring(dev, ring);
+                       if (vcs & GT_CONTEXT_SWITCH_INTERRUPT)
+                               intel_execlists_handle_ctx_events(ring);
+
                        vcs = tmp >> GEN8_VCS2_IRQ_SHIFT;
+                       ring = &dev_priv->ring[VCS2];
                        if (vcs & GT_RENDER_USER_INTERRUPT)
-                               notify_ring(dev, &dev_priv->ring[VCS2]);
+                               notify_ring(dev, ring);
+                       if (vcs & GT_CONTEXT_SWITCH_INTERRUPT)
+                               intel_execlists_handle_ctx_events(ring);
                } else
                        DRM_ERROR("The master control interrupt lied (GT1)!\n");
        }
@@ -1677,9 +1694,13 @@ static irqreturn_t gen8_gt_irq_handler(struct drm_device *dev,
                if (tmp) {
                        I915_WRITE(GEN8_GT_IIR(3), tmp);
                        ret = IRQ_HANDLED;
+
                        vcs = tmp >> GEN8_VECS_IRQ_SHIFT;
+                       ring = &dev_priv->ring[VECS];
                        if (vcs & GT_RENDER_USER_INTERRUPT)
-                               notify_ring(dev, &dev_priv->ring[VECS]);
+                               notify_ring(dev, ring);
+                       if (vcs & GT_CONTEXT_SWITCH_INTERRUPT)
+                               intel_execlists_handle_ctx_events(ring);
                } else
                        DRM_ERROR("The master control interrupt lied (GT3)!\n");
        }
@@ -1772,7 +1793,9 @@ static inline void intel_hpd_irq_handler(struct drm_device *dev,
                                long_hpd = (dig_hotplug_reg >> dig_shift) & PORTB_HOTPLUG_LONG_DETECT;
                        }
 
-                       DRM_DEBUG_DRIVER("digital hpd port %d %d\n", port, long_hpd);
+                       DRM_DEBUG_DRIVER("digital hpd port %c - %s\n",
+                                        port_name(port),
+                                        long_hpd ? "long" : "short");
                        /* for long HPD pulses we want to have the digital queue happen,
                           but we still want HPD storm detection to function. */
                        if (long_hpd) {
@@ -1984,14 +2007,9 @@ static void gen6_rps_irq_handler(struct drm_i915_private *dev_priv, u32 pm_iir)
 
 static bool intel_pipe_handle_vblank(struct drm_device *dev, enum pipe pipe)
 {
-       struct intel_crtc *crtc;
-
        if (!drm_handle_vblank(dev, pipe))
                return false;
 
-       crtc = to_intel_crtc(intel_get_crtc_for_pipe(dev, pipe));
-       wake_up(&crtc->vbl_wait);
-
        return true;
 }
 
@@ -2002,7 +2020,7 @@ static void valleyview_pipestat_irq_handler(struct drm_device *dev, u32 iir)
        int pipe;
 
        spin_lock(&dev_priv->irq_lock);
-       for_each_pipe(pipe) {
+       for_each_pipe(dev_priv, pipe) {
                int reg;
                u32 mask, iir_bit = 0;
 
@@ -2047,9 +2065,10 @@ static void valleyview_pipestat_irq_handler(struct drm_device *dev, u32 iir)
        }
        spin_unlock(&dev_priv->irq_lock);
 
-       for_each_pipe(pipe) {
-               if (pipe_stats[pipe] & PIPE_START_VBLANK_INTERRUPT_STATUS)
-                       intel_pipe_handle_vblank(dev, pipe);
+       for_each_pipe(dev_priv, pipe) {
+               if (pipe_stats[pipe] & PIPE_START_VBLANK_INTERRUPT_STATUS &&
+                   intel_pipe_handle_vblank(dev, pipe))
+                       intel_check_page_flip(dev, pipe);
 
                if (pipe_stats[pipe] & PLANE_FLIP_DONE_INT_STATUS_VLV) {
                        intel_prepare_page_flip(dev, pipe);
@@ -2216,7 +2235,7 @@ static void ibx_irq_handler(struct drm_device *dev, u32 pch_iir)
                DRM_ERROR("PCH poison interrupt\n");
 
        if (pch_iir & SDE_FDI_MASK)
-               for_each_pipe(pipe)
+               for_each_pipe(dev_priv, pipe)
                        DRM_DEBUG_DRIVER("  pipe %c FDI IIR: 0x%08x\n",
                                         pipe_name(pipe),
                                         I915_READ(FDI_RX_IIR(pipe)));
@@ -2247,7 +2266,7 @@ static void ivb_err_int_handler(struct drm_device *dev)
        if (err_int & ERR_INT_POISON)
                DRM_ERROR("Poison interrupt\n");
 
-       for_each_pipe(pipe) {
+       for_each_pipe(dev_priv, pipe) {
                if (err_int & ERR_INT_FIFO_UNDERRUN(pipe)) {
                        if (intel_set_cpu_fifo_underrun_reporting(dev, pipe,
                                                                  false))
@@ -2324,7 +2343,7 @@ static void cpt_irq_handler(struct drm_device *dev, u32 pch_iir)
                DRM_DEBUG_DRIVER("Audio CP change interrupt\n");
 
        if (pch_iir & SDE_FDI_MASK_CPT)
-               for_each_pipe(pipe)
+               for_each_pipe(dev_priv, pipe)
                        DRM_DEBUG_DRIVER("  pipe %c FDI IIR: 0x%08x\n",
                                         pipe_name(pipe),
                                         I915_READ(FDI_RX_IIR(pipe)));
@@ -2347,9 +2366,10 @@ static void ilk_display_irq_handler(struct drm_device *dev, u32 de_iir)
        if (de_iir & DE_POISON)
                DRM_ERROR("Poison interrupt\n");
 
-       for_each_pipe(pipe) {
-               if (de_iir & DE_PIPE_VBLANK(pipe))
-                       intel_pipe_handle_vblank(dev, pipe);
+       for_each_pipe(dev_priv, pipe) {
+               if (de_iir & DE_PIPE_VBLANK(pipe) &&
+                   intel_pipe_handle_vblank(dev, pipe))
+                       intel_check_page_flip(dev, pipe);
 
                if (de_iir & DE_PIPE_FIFO_UNDERRUN(pipe))
                        if (intel_set_cpu_fifo_underrun_reporting(dev, pipe, false))
@@ -2397,9 +2417,10 @@ static void ivb_display_irq_handler(struct drm_device *dev, u32 de_iir)
        if (de_iir & DE_GSE_IVB)
                intel_opregion_asle_intr(dev);
 
-       for_each_pipe(pipe) {
-               if (de_iir & (DE_PIPE_VBLANK_IVB(pipe)))
-                       intel_pipe_handle_vblank(dev, pipe);
+       for_each_pipe(dev_priv, pipe) {
+               if (de_iir & (DE_PIPE_VBLANK_IVB(pipe)) &&
+                   intel_pipe_handle_vblank(dev, pipe))
+                       intel_check_page_flip(dev, pipe);
 
                /* plane/pipes map 1:1 on ilk+ */
                if (de_iir & DE_PLANE_FLIP_DONE_IVB(pipe)) {
@@ -2544,7 +2565,7 @@ static irqreturn_t gen8_irq_handler(int irq, void *arg)
                        DRM_ERROR("The master control interrupt lied (DE PORT)!\n");
        }
 
-       for_each_pipe(pipe) {
+       for_each_pipe(dev_priv, pipe) {
                uint32_t pipe_iir;
 
                if (!(master_ctl & GEN8_DE_PIPE_IRQ(pipe)))
@@ -2554,8 +2575,9 @@ static irqreturn_t gen8_irq_handler(int irq, void *arg)
                if (pipe_iir) {
                        ret = IRQ_HANDLED;
                        I915_WRITE(GEN8_DE_PIPE_IIR(pipe), pipe_iir);
-                       if (pipe_iir & GEN8_PIPE_VBLANK)
-                               intel_pipe_handle_vblank(dev, pipe);
+                       if (pipe_iir & GEN8_PIPE_VBLANK &&
+                           intel_pipe_handle_vblank(dev, pipe))
+                               intel_check_page_flip(dev, pipe);
 
                        if (pipe_iir & GEN8_PIPE_PRIMARY_FLIP_DONE) {
                                intel_prepare_page_flip(dev, pipe);
@@ -2763,7 +2785,7 @@ static void i915_report_and_clear_eir(struct drm_device *dev)
 
        if (eir & I915_ERROR_MEMORY_REFRESH) {
                pr_err("memory refresh error:\n");
-               for_each_pipe(pipe)
+               for_each_pipe(dev_priv, pipe)
                        pr_err("pipe %c stat: 0x%08x\n",
                               pipe_name(pipe), I915_READ(PIPESTAT(pipe)));
                /* pipestat has already been acked */
@@ -2860,52 +2882,6 @@ void i915_handle_error(struct drm_device *dev, bool wedged,
        schedule_work(&dev_priv->gpu_error.work);
 }
 
-static void __always_unused i915_pageflip_stall_check(struct drm_device *dev, int pipe)
-{
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       struct drm_crtc *crtc = dev_priv->pipe_to_crtc_mapping[pipe];
-       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-       struct drm_i915_gem_object *obj;
-       struct intel_unpin_work *work;
-       unsigned long flags;
-       bool stall_detected;
-
-       /* Ignore early vblank irqs */
-       if (intel_crtc == NULL)
-               return;
-
-       spin_lock_irqsave(&dev->event_lock, flags);
-       work = intel_crtc->unpin_work;
-
-       if (work == NULL ||
-           atomic_read(&work->pending) >= INTEL_FLIP_COMPLETE ||
-           !work->enable_stall_check) {
-               /* Either the pending flip IRQ arrived, or we're too early. Don't check */
-               spin_unlock_irqrestore(&dev->event_lock, flags);
-               return;
-       }
-
-       /* Potential stall - if we see that the flip has happened, assume a missed interrupt */
-       obj = work->pending_flip_obj;
-       if (INTEL_INFO(dev)->gen >= 4) {
-               int dspsurf = DSPSURF(intel_crtc->plane);
-               stall_detected = I915_HI_DISPBASE(I915_READ(dspsurf)) ==
-                                       i915_gem_obj_ggtt_offset(obj);
-       } else {
-               int dspaddr = DSPADDR(intel_crtc->plane);
-               stall_detected = I915_READ(dspaddr) == (i915_gem_obj_ggtt_offset(obj) +
-                                                       crtc->y * crtc->primary->fb->pitches[0] +
-                                                       crtc->x * crtc->primary->fb->bits_per_pixel/8);
-       }
-
-       spin_unlock_irqrestore(&dev->event_lock, flags);
-
-       if (stall_detected) {
-               DRM_DEBUG_DRIVER("Pageflip stall detected\n");
-               intel_prepare_page_flip(dev, intel_crtc->plane);
-       }
-}
-
 /* Called from drm generic code, passed 'crtc' which
  * we use as a pipe index
  */
@@ -3441,7 +3417,7 @@ static void valleyview_irq_preinstall(struct drm_device *dev)
 
        I915_WRITE(PORT_HOTPLUG_EN, 0);
        I915_WRITE(PORT_HOTPLUG_STAT, I915_READ(PORT_HOTPLUG_STAT));
-       for_each_pipe(pipe)
+       for_each_pipe(dev_priv, pipe)
                I915_WRITE(PIPESTAT(pipe), 0xffff);
        I915_WRITE(VLV_IIR, 0xffffffff);
        I915_WRITE(VLV_IMR, 0xffffffff);
@@ -3467,7 +3443,7 @@ static void gen8_irq_reset(struct drm_device *dev)
 
        gen8_gt_irq_reset(dev_priv);
 
-       for_each_pipe(pipe)
+       for_each_pipe(dev_priv, pipe)
                if (intel_display_power_enabled(dev_priv,
                                                POWER_DOMAIN_PIPE(pipe)))
                        GEN8_IRQ_RESET_NDX(DE_PIPE, pipe);
@@ -3510,7 +3486,7 @@ static void cherryview_irq_preinstall(struct drm_device *dev)
        I915_WRITE(PORT_HOTPLUG_EN, 0);
        I915_WRITE(PORT_HOTPLUG_STAT, I915_READ(PORT_HOTPLUG_STAT));
 
-       for_each_pipe(pipe)
+       for_each_pipe(dev_priv, pipe)
                I915_WRITE(PIPESTAT(pipe), 0xffff);
 
        I915_WRITE(VLV_IMR, 0xffffffff);
@@ -3522,18 +3498,17 @@ static void cherryview_irq_preinstall(struct drm_device *dev)
 static void ibx_hpd_irq_setup(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
-       struct drm_mode_config *mode_config = &dev->mode_config;
        struct intel_encoder *intel_encoder;
        u32 hotplug_irqs, hotplug, enabled_irqs = 0;
 
        if (HAS_PCH_IBX(dev)) {
                hotplug_irqs = SDE_HOTPLUG_MASK;
-               list_for_each_entry(intel_encoder, &mode_config->encoder_list, base.head)
+               for_each_intel_encoder(dev, intel_encoder)
                        if (dev_priv->hpd_stats[intel_encoder->hpd_pin].hpd_mark == HPD_ENABLED)
                                enabled_irqs |= hpd_ibx[intel_encoder->hpd_pin];
        } else {
                hotplug_irqs = SDE_HOTPLUG_MASK_CPT;
-               list_for_each_entry(intel_encoder, &mode_config->encoder_list, base.head)
+               for_each_intel_encoder(dev, intel_encoder)
                        if (dev_priv->hpd_stats[intel_encoder->hpd_pin].hpd_mark == HPD_ENABLED)
                                enabled_irqs |= hpd_cpt[intel_encoder->hpd_pin];
        }
@@ -3782,28 +3757,31 @@ static int valleyview_irq_postinstall(struct drm_device *dev)
 
 static void gen8_gt_irq_postinstall(struct drm_i915_private *dev_priv)
 {
-       int i;
-
        /* These are interrupts we'll toggle with the ring mask register */
        uint32_t gt_interrupts[] = {
                GT_RENDER_USER_INTERRUPT << GEN8_RCS_IRQ_SHIFT |
+                       GT_CONTEXT_SWITCH_INTERRUPT << GEN8_RCS_IRQ_SHIFT |
                        GT_RENDER_L3_PARITY_ERROR_INTERRUPT |
-                       GT_RENDER_USER_INTERRUPT << GEN8_BCS_IRQ_SHIFT,
+                       GT_RENDER_USER_INTERRUPT << GEN8_BCS_IRQ_SHIFT |
+                       GT_CONTEXT_SWITCH_INTERRUPT << GEN8_BCS_IRQ_SHIFT,
                GT_RENDER_USER_INTERRUPT << GEN8_VCS1_IRQ_SHIFT |
-                       GT_RENDER_USER_INTERRUPT << GEN8_VCS2_IRQ_SHIFT,
+                       GT_CONTEXT_SWITCH_INTERRUPT << GEN8_VCS1_IRQ_SHIFT |
+                       GT_RENDER_USER_INTERRUPT << GEN8_VCS2_IRQ_SHIFT |
+                       GT_CONTEXT_SWITCH_INTERRUPT << GEN8_VCS2_IRQ_SHIFT,
                0,
-               GT_RENDER_USER_INTERRUPT << GEN8_VECS_IRQ_SHIFT
+               GT_RENDER_USER_INTERRUPT << GEN8_VECS_IRQ_SHIFT |
+                       GT_CONTEXT_SWITCH_INTERRUPT << GEN8_VECS_IRQ_SHIFT
                };
 
-       for (i = 0; i < ARRAY_SIZE(gt_interrupts); i++)
-               GEN8_IRQ_INIT_NDX(GT, i, ~gt_interrupts[i], gt_interrupts[i]);
-
        dev_priv->pm_irq_mask = 0xffffffff;
+       GEN8_IRQ_INIT_NDX(GT, 0, ~gt_interrupts[0], gt_interrupts[0]);
+       GEN8_IRQ_INIT_NDX(GT, 1, ~gt_interrupts[1], gt_interrupts[1]);
+       GEN8_IRQ_INIT_NDX(GT, 2, dev_priv->pm_irq_mask, dev_priv->pm_rps_events);
+       GEN8_IRQ_INIT_NDX(GT, 3, ~gt_interrupts[3], gt_interrupts[3]);
 }
 
 static void gen8_de_irq_postinstall(struct drm_i915_private *dev_priv)
 {
-       struct drm_device *dev = dev_priv->dev;
        uint32_t de_pipe_masked = GEN8_PIPE_PRIMARY_FLIP_DONE |
                GEN8_PIPE_CDCLK_CRC_DONE |
                GEN8_DE_PIPE_IRQ_FAULT_ERRORS;
@@ -3814,7 +3792,7 @@ static void gen8_de_irq_postinstall(struct drm_i915_private *dev_priv)
        dev_priv->de_irq_mask[PIPE_B] = ~de_pipe_masked;
        dev_priv->de_irq_mask[PIPE_C] = ~de_pipe_masked;
 
-       for_each_pipe(pipe)
+       for_each_pipe(dev_priv, pipe)
                if (intel_display_power_enabled(dev_priv,
                                POWER_DOMAIN_PIPE(pipe)))
                        GEN8_IRQ_INIT_NDX(DE_PIPE, pipe,
@@ -3859,12 +3837,12 @@ static int cherryview_irq_postinstall(struct drm_device *dev)
         */
        dev_priv->irq_mask = ~enable_mask;
 
-       for_each_pipe(pipe)
+       for_each_pipe(dev_priv, pipe)
                I915_WRITE(PIPESTAT(pipe), 0xffff);
 
        spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
        i915_enable_pipestat(dev_priv, PIPE_A, PIPE_GMBUS_INTERRUPT_STATUS);
-       for_each_pipe(pipe)
+       for_each_pipe(dev_priv, pipe)
                i915_enable_pipestat(dev_priv, pipe, pipestat_enable);
        spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
 
@@ -3901,7 +3879,7 @@ static void valleyview_irq_uninstall(struct drm_device *dev)
 
        I915_WRITE(VLV_MASTER_IER, 0);
 
-       for_each_pipe(pipe)
+       for_each_pipe(dev_priv, pipe)
                I915_WRITE(PIPESTAT(pipe), 0xffff);
 
        I915_WRITE(HWSTAM, 0xffffffff);
@@ -3963,7 +3941,7 @@ do {                                                      \
        I915_WRITE(PORT_HOTPLUG_EN, 0);
        I915_WRITE(PORT_HOTPLUG_STAT, I915_READ(PORT_HOTPLUG_STAT));
 
-       for_each_pipe(pipe)
+       for_each_pipe(dev_priv, pipe)
                I915_WRITE(PIPESTAT(pipe), 0xffff);
 
        I915_WRITE(VLV_IMR, 0xffffffff);
@@ -3987,7 +3965,7 @@ static void i8xx_irq_preinstall(struct drm_device * dev)
        struct drm_i915_private *dev_priv = dev->dev_private;
        int pipe;
 
-       for_each_pipe(pipe)
+       for_each_pipe(dev_priv, pipe)
                I915_WRITE(PIPESTAT(pipe), 0);
        I915_WRITE16(IMR, 0xffff);
        I915_WRITE16(IER, 0x0);
@@ -4041,7 +4019,7 @@ static bool i8xx_handle_vblank(struct drm_device *dev,
                return false;
 
        if ((iir & flip_pending) == 0)
-               return false;
+               goto check_page_flip;
 
        intel_prepare_page_flip(dev, plane);
 
@@ -4052,11 +4030,14 @@ static bool i8xx_handle_vblank(struct drm_device *dev,
         * an interrupt per se, we watch for the change at vblank.
         */
        if (I915_READ16(ISR) & flip_pending)
-               return false;
+               goto check_page_flip;
 
        intel_finish_page_flip(dev, pipe);
-
        return true;
+
+check_page_flip:
+       intel_check_page_flip(dev, pipe);
+       return false;
 }
 
 static irqreturn_t i8xx_irq_handler(int irq, void *arg)
@@ -4087,7 +4068,7 @@ static irqreturn_t i8xx_irq_handler(int irq, void *arg)
                                          "Command parser error, iir 0x%08x",
                                          iir);
 
-               for_each_pipe(pipe) {
+               for_each_pipe(dev_priv, pipe) {
                        int reg = PIPESTAT(pipe);
                        pipe_stats[pipe] = I915_READ(reg);
 
@@ -4107,7 +4088,7 @@ static irqreturn_t i8xx_irq_handler(int irq, void *arg)
                if (iir & I915_USER_INTERRUPT)
                        notify_ring(dev, &dev_priv->ring[RCS]);
 
-               for_each_pipe(pipe) {
+               for_each_pipe(dev_priv, pipe) {
                        int plane = pipe;
                        if (HAS_FBC(dev))
                                plane = !plane;
@@ -4135,7 +4116,7 @@ static void i8xx_irq_uninstall(struct drm_device * dev)
        struct drm_i915_private *dev_priv = dev->dev_private;
        int pipe;
 
-       for_each_pipe(pipe) {
+       for_each_pipe(dev_priv, pipe) {
                /* Clear enable bits; then clear status bits */
                I915_WRITE(PIPESTAT(pipe), 0);
                I915_WRITE(PIPESTAT(pipe), I915_READ(PIPESTAT(pipe)));
@@ -4156,7 +4137,7 @@ static void i915_irq_preinstall(struct drm_device * dev)
        }
 
        I915_WRITE16(HWSTAM, 0xeffe);
-       for_each_pipe(pipe)
+       for_each_pipe(dev_priv, pipe)
                I915_WRITE(PIPESTAT(pipe), 0);
        I915_WRITE(IMR, 0xffffffff);
        I915_WRITE(IER, 0x0);
@@ -4226,7 +4207,7 @@ static bool i915_handle_vblank(struct drm_device *dev,
                return false;
 
        if ((iir & flip_pending) == 0)
-               return false;
+               goto check_page_flip;
 
        intel_prepare_page_flip(dev, plane);
 
@@ -4237,11 +4218,14 @@ static bool i915_handle_vblank(struct drm_device *dev,
         * an interrupt per se, we watch for the change at vblank.
         */
        if (I915_READ(ISR) & flip_pending)
-               return false;
+               goto check_page_flip;
 
        intel_finish_page_flip(dev, pipe);
-
        return true;
+
+check_page_flip:
+       intel_check_page_flip(dev, pipe);
+       return false;
 }
 
 static irqreturn_t i915_irq_handler(int irq, void *arg)
@@ -4271,7 +4255,7 @@ static irqreturn_t i915_irq_handler(int irq, void *arg)
                                          "Command parser error, iir 0x%08x",
                                          iir);
 
-               for_each_pipe(pipe) {
+               for_each_pipe(dev_priv, pipe) {
                        int reg = PIPESTAT(pipe);
                        pipe_stats[pipe] = I915_READ(reg);
 
@@ -4297,7 +4281,7 @@ static irqreturn_t i915_irq_handler(int irq, void *arg)
                if (iir & I915_USER_INTERRUPT)
                        notify_ring(dev, &dev_priv->ring[RCS]);
 
-               for_each_pipe(pipe) {
+               for_each_pipe(dev_priv, pipe) {
                        int plane = pipe;
                        if (HAS_FBC(dev))
                                plane = !plane;
@@ -4355,7 +4339,7 @@ static void i915_irq_uninstall(struct drm_device * dev)
        }
 
        I915_WRITE16(HWSTAM, 0xffff);
-       for_each_pipe(pipe) {
+       for_each_pipe(dev_priv, pipe) {
                /* Clear enable bits; then clear status bits */
                I915_WRITE(PIPESTAT(pipe), 0);
                I915_WRITE(PIPESTAT(pipe), I915_READ(PIPESTAT(pipe)));
@@ -4375,7 +4359,7 @@ static void i965_irq_preinstall(struct drm_device * dev)
        I915_WRITE(PORT_HOTPLUG_STAT, I915_READ(PORT_HOTPLUG_STAT));
 
        I915_WRITE(HWSTAM, 0xeffe);
-       for_each_pipe(pipe)
+       for_each_pipe(dev_priv, pipe)
                I915_WRITE(PIPESTAT(pipe), 0);
        I915_WRITE(IMR, 0xffffffff);
        I915_WRITE(IER, 0x0);
@@ -4444,7 +4428,6 @@ static int i965_irq_postinstall(struct drm_device *dev)
 static void i915_hpd_irq_setup(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
-       struct drm_mode_config *mode_config = &dev->mode_config;
        struct intel_encoder *intel_encoder;
        u32 hotplug_en;
 
@@ -4455,7 +4438,7 @@ static void i915_hpd_irq_setup(struct drm_device *dev)
                hotplug_en &= ~HOTPLUG_INT_EN_MASK;
                /* Note HDMI and DP share hotplug bits */
                /* enable bits are the same for all generations */
-               list_for_each_entry(intel_encoder, &mode_config->encoder_list, base.head)
+               for_each_intel_encoder(dev, intel_encoder)
                        if (dev_priv->hpd_stats[intel_encoder->hpd_pin].hpd_mark == HPD_ENABLED)
                                hotplug_en |= hpd_mask_i915[intel_encoder->hpd_pin];
                /* Programming the CRT detection parameters tends
@@ -4501,7 +4484,7 @@ static irqreturn_t i965_irq_handler(int irq, void *arg)
                                          "Command parser error, iir 0x%08x",
                                          iir);
 
-               for_each_pipe(pipe) {
+               for_each_pipe(dev_priv, pipe) {
                        int reg = PIPESTAT(pipe);
                        pipe_stats[pipe] = I915_READ(reg);
 
@@ -4532,7 +4515,7 @@ static irqreturn_t i965_irq_handler(int irq, void *arg)
                if (iir & I915_BSD_USER_INTERRUPT)
                        notify_ring(dev, &dev_priv->ring[VCS]);
 
-               for_each_pipe(pipe) {
+               for_each_pipe(dev_priv, pipe) {
                        if (pipe_stats[pipe] & PIPE_START_VBLANK_INTERRUPT_STATUS &&
                            i915_handle_vblank(dev, pipe, pipe, iir))
                                flip_mask &= ~DISPLAY_PLANE_FLIP_PENDING(pipe);
@@ -4589,12 +4572,12 @@ static void i965_irq_uninstall(struct drm_device * dev)
        I915_WRITE(PORT_HOTPLUG_STAT, I915_READ(PORT_HOTPLUG_STAT));
 
        I915_WRITE(HWSTAM, 0xffffffff);
-       for_each_pipe(pipe)
+       for_each_pipe(dev_priv, pipe)
                I915_WRITE(PIPESTAT(pipe), 0);
        I915_WRITE(IMR, 0xffffffff);
        I915_WRITE(IER, 0x0);
 
-       for_each_pipe(pipe)
+       for_each_pipe(dev_priv, pipe)
                I915_WRITE(PIPESTAT(pipe),
                           I915_READ(PIPESTAT(pipe)) & 0x8000ffff);
        I915_WRITE(IIR, I915_READ(IIR));
@@ -4652,8 +4635,8 @@ void intel_irq_init(struct drm_device *dev)
        INIT_WORK(&dev_priv->l3_parity.error_work, ivybridge_parity_work);
 
        /* Let's track the enabled rps events */
-       if (IS_VALLEYVIEW(dev))
-               /* WaGsvRC0ResidenncyMethod:VLV */
+       if (IS_VALLEYVIEW(dev) && !IS_CHERRYVIEW(dev))
+               /* WaGsvRC0ResidencyMethod:vlv */
                dev_priv->pm_rps_events = GEN6_PM_RP_UP_EI_EXPIRED;
        else
                dev_priv->pm_rps_events = GEN6_PM_RPS_EVENTS;
@@ -4680,6 +4663,14 @@ void intel_irq_init(struct drm_device *dev)
                dev->max_vblank_count = 0xffffff; /* only 24 bits of frame count */
        }
 
+       /*
+        * Opt out of the vblank disable timer on everything except gen2.
+        * Gen2 doesn't have a hardware frame counter and so depends on
+        * vblank interrupts to produce sane vblank seuquence numbers.
+        */
+       if (!IS_GEN2(dev))
+               dev->vblank_disable_immediate = true;
+
        if (drm_core_check_feature(dev, DRIVER_MODESET)) {
                dev->driver->get_vblank_timestamp = i915_get_vblank_timestamp;
                dev->driver->get_scanout_position = i915_get_crtc_scanoutpos;
index 9842fd2e742a40d0b83c51f2e9f2dd012e1bc304..c91cb2033cc5ec02c248b95271fac95469e1acde 100644 (file)
@@ -35,6 +35,7 @@ struct i915_params i915 __read_mostly = {
        .vbt_sdvo_panel_type = -1,
        .enable_rc6 = -1,
        .enable_fbc = -1,
+       .enable_execlists = 0,
        .enable_hangcheck = true,
        .enable_ppgtt = -1,
        .enable_psr = 0,
@@ -118,6 +119,11 @@ MODULE_PARM_DESC(enable_ppgtt,
        "Override PPGTT usage. "
        "(-1=auto [default], 0=disabled, 1=aliasing, 2=full)");
 
+module_param_named(enable_execlists, i915.enable_execlists, int, 0400);
+MODULE_PARM_DESC(enable_execlists,
+       "Override execlists usage. "
+       "(-1=auto, 0=disabled [default], 1=enabled)");
+
 module_param_named(enable_psr, i915.enable_psr, int, 0600);
 MODULE_PARM_DESC(enable_psr, "Enable PSR (default: false)");
 
index f29b44c86a2f7354c29dd0ce3ca3a5cfc7ae723c..c01e5f31430ec420f469aacda6c520b39ccb158e 100644 (file)
 #define GAB_CTL                                0x24000
 #define   GAB_CTL_CONT_AFTER_PAGEFAULT (1<<8)
 
+#define GEN7_BIOS_RESERVED             0x1082C0
+#define GEN7_BIOS_RESERVED_1M          (0 << 5)
+#define GEN7_BIOS_RESERVED_256K                (1 << 5)
+#define GEN8_BIOS_RESERVED_SHIFT       7
+#define GEN7_BIOS_RESERVED_MASK        0x1
+#define GEN8_BIOS_RESERVED_MASK        0x3
+
+
 /* VGA stuff */
 
 #define VGA_ST01_MDA 0x3ba
 #define   MI_SEMAPHORE_POLL            (1<<15)
 #define   MI_SEMAPHORE_SAD_GTE_SDD     (1<<12)
 #define MI_STORE_DWORD_IMM     MI_INSTR(0x20, 1)
+#define MI_STORE_DWORD_IMM_GEN8        MI_INSTR(0x20, 2)
 #define   MI_MEM_VIRTUAL       (1 << 22) /* 965+ only */
 #define MI_STORE_DWORD_INDEX   MI_INSTR(0x21, 1)
 #define   MI_STORE_DWORD_INDEX_SHIFT 2
  *   address/value pairs. Don't overdue it, though, x <= 2^4 must hold!
  */
 #define MI_LOAD_REGISTER_IMM(x)        MI_INSTR(0x22, 2*(x)-1)
+#define   MI_LRI_FORCE_POSTED          (1<<12)
 #define MI_STORE_REGISTER_MEM(x) MI_INSTR(0x24, 2*(x)-1)
 #define MI_STORE_REGISTER_MEM_GEN8(x) MI_INSTR(0x24, 3*(x)-1)
 #define   MI_SRM_LRM_GLOBAL_GTT                (1<<22)
 #define BUNIT_REG_BISOC                                0x11
 
 #define PUNIT_REG_DSPFREQ                      0x36
+#define   DSPFREQSTAT_SHIFT_CHV                        24
+#define   DSPFREQSTAT_MASK_CHV                 (0x1f << DSPFREQSTAT_SHIFT_CHV)
+#define   DSPFREQGUAR_SHIFT_CHV                        8
+#define   DSPFREQGUAR_MASK_CHV                 (0x1f << DSPFREQGUAR_SHIFT_CHV)
 #define   DSPFREQSTAT_SHIFT                    30
 #define   DSPFREQSTAT_MASK                     (0x3 << DSPFREQSTAT_SHIFT)
 #define   DSPFREQGUAR_SHIFT                    14
 #define   DSPFREQGUAR_MASK                     (0x3 << DSPFREQGUAR_SHIFT)
+#define   _DP_SSC(val, pipe)                   ((val) << (2 * (pipe)))
+#define   DP_SSC_MASK(pipe)                    _DP_SSC(0x3, (pipe))
+#define   DP_SSC_PWR_ON(pipe)                  _DP_SSC(0x0, (pipe))
+#define   DP_SSC_CLK_GATE(pipe)                        _DP_SSC(0x1, (pipe))
+#define   DP_SSC_RESET(pipe)                   _DP_SSC(0x2, (pipe))
+#define   DP_SSC_PWR_GATE(pipe)                        _DP_SSC(0x3, (pipe))
+#define   _DP_SSS(val, pipe)                   ((val) << (2 * (pipe) + 16))
+#define   DP_SSS_MASK(pipe)                    _DP_SSS(0x3, (pipe))
+#define   DP_SSS_PWR_ON(pipe)                  _DP_SSS(0x0, (pipe))
+#define   DP_SSS_CLK_GATE(pipe)                        _DP_SSS(0x1, (pipe))
+#define   DP_SSS_RESET(pipe)                   _DP_SSS(0x2, (pipe))
+#define   DP_SSS_PWR_GATE(pipe)                        _DP_SSS(0x3, (pipe))
 
 /* See the PUNIT HAS v0.8 for the below bits */
 enum punit_power_well {
@@ -518,6 +544,11 @@ enum punit_power_well {
        PUNIT_POWER_WELL_DPIO_TX_C_LANES_23     = 9,
        PUNIT_POWER_WELL_DPIO_RX0               = 10,
        PUNIT_POWER_WELL_DPIO_RX1               = 11,
+       PUNIT_POWER_WELL_DPIO_CMN_D             = 12,
+       /* FIXME: guesswork below */
+       PUNIT_POWER_WELL_DPIO_TX_D_LANES_01     = 13,
+       PUNIT_POWER_WELL_DPIO_TX_D_LANES_23     = 14,
+       PUNIT_POWER_WELL_DPIO_RX2               = 15,
 
        PUNIT_POWER_WELL_NUM,
 };
@@ -838,8 +869,8 @@ enum punit_power_well {
 
 #define _VLV_TX_DW2_CH0                        0x8288
 #define _VLV_TX_DW2_CH1                        0x8488
-#define   DPIO_SWING_MARGIN_SHIFT      16
-#define   DPIO_SWING_MARGIN_MASK       (0xff << DPIO_SWING_MARGIN_SHIFT)
+#define   DPIO_SWING_MARGIN000_SHIFT   16
+#define   DPIO_SWING_MARGIN000_MASK    (0xff << DPIO_SWING_MARGIN000_SHIFT)
 #define   DPIO_UNIQ_TRANS_SCALE_SHIFT  8
 #define VLV_TX_DW2(ch) _PORT(ch, _VLV_TX_DW2_CH0, _VLV_TX_DW2_CH1)
 
@@ -847,12 +878,16 @@ enum punit_power_well {
 #define _VLV_TX_DW3_CH1                        0x848c
 /* The following bit for CHV phy */
 #define   DPIO_TX_UNIQ_TRANS_SCALE_EN  (1<<27)
+#define   DPIO_SWING_MARGIN101_SHIFT   16
+#define   DPIO_SWING_MARGIN101_MASK    (0xff << DPIO_SWING_MARGIN101_SHIFT)
 #define VLV_TX_DW3(ch) _PORT(ch, _VLV_TX_DW3_CH0, _VLV_TX_DW3_CH1)
 
 #define _VLV_TX_DW4_CH0                        0x8290
 #define _VLV_TX_DW4_CH1                        0x8490
 #define   DPIO_SWING_DEEMPH9P5_SHIFT   24
 #define   DPIO_SWING_DEEMPH9P5_MASK    (0xff << DPIO_SWING_DEEMPH9P5_SHIFT)
+#define   DPIO_SWING_DEEMPH6P0_SHIFT   16
+#define   DPIO_SWING_DEEMPH6P0_MASK    (0xff << DPIO_SWING_DEEMPH6P0_SHIFT)
 #define VLV_TX_DW4(ch) _PORT(ch, _VLV_TX_DW4_CH0, _VLV_TX_DW4_CH1)
 
 #define _VLV_TX3_DW4_CH0               0x690
@@ -1003,6 +1038,13 @@ enum punit_power_well {
 #define   PGTBL_ADDRESS_LO_MASK        0xfffff000 /* bits [31:12] */
 #define   PGTBL_ADDRESS_HI_MASK        0x000000f0 /* bits [35:32] (gen4) */
 #define PGTBL_ER       0x02024
+#define PRB0_BASE (0x2030-0x30)
+#define PRB1_BASE (0x2040-0x30) /* 830,gen3 */
+#define PRB2_BASE (0x2050-0x30) /* gen3 */
+#define SRB0_BASE (0x2100-0x30) /* gen2 */
+#define SRB1_BASE (0x2110-0x30) /* gen2 */
+#define SRB2_BASE (0x2120-0x30) /* 830 */
+#define SRB3_BASE (0x2130-0x30) /* 830 */
 #define RENDER_RING_BASE       0x02000
 #define BSD_RING_BASE          0x04000
 #define GEN6_BSD_RING_BASE     0x12000
@@ -1064,6 +1106,7 @@ enum punit_power_well {
 #define RING_ACTHD_UDW(base)   ((base)+0x5c)
 #define RING_NOPID(base)       ((base)+0x94)
 #define RING_IMR(base)         ((base)+0xa8)
+#define RING_HWSTAM(base)      ((base)+0x98)
 #define RING_TIMESTAMP(base)   ((base)+0x358)
 #define   TAIL_ADDR            0x001FFFF8
 #define   HEAD_WRAP_COUNT      0xFFE00000
@@ -1248,6 +1291,10 @@ enum punit_power_well {
 #define   INSTPM_TLB_INVALIDATE        (1<<9)
 #define   INSTPM_SYNC_FLUSH    (1<<5)
 #define ACTHD          0x020c8
+#define MEM_MODE       0x020cc
+#define   MEM_DISPLAY_B_TRICKLE_FEED_DISABLE (1<<3) /* 830 only */
+#define   MEM_DISPLAY_A_TRICKLE_FEED_DISABLE (1<<2) /* 830/845 only */
+#define   MEM_DISPLAY_TRICKLE_FEED_DISABLE (1<<2) /* 85x only */
 #define FW_BLC         0x020d8
 #define FW_BLC2                0x020dc
 #define FW_BLC_SELF    0x020e0 /* 915+ only */
@@ -1380,6 +1427,7 @@ enum punit_power_well {
 #define GT_BSD_CS_ERROR_INTERRUPT              (1 << 15)
 #define GT_BSD_USER_INTERRUPT                  (1 << 12)
 #define GT_RENDER_L3_PARITY_ERROR_INTERRUPT_S1 (1 << 11) /* hsw+; rsvd on snb, ivb, vlv */
+#define GT_CONTEXT_SWITCH_INTERRUPT            (1 <<  8)
 #define GT_RENDER_L3_PARITY_ERROR_INTERRUPT    (1 <<  5) /* !snb */
 #define GT_RENDER_PIPECTL_NOTIFY_INTERRUPT     (1 <<  4)
 #define GT_RENDER_CS_MASTER_ERROR_INTERRUPT    (1 <<  3)
@@ -1519,6 +1567,7 @@ enum punit_power_well {
 /* Framebuffer compression for Ironlake */
 #define ILK_DPFC_CB_BASE       0x43200
 #define ILK_DPFC_CONTROL       0x43208
+#define   FBC_CTL_FALSE_COLOR  (1<<10)
 /* The bit 28-8 is reserved */
 #define   DPFC_RESERVED                (0x1FFFFF00)
 #define ILK_DPFC_RECOMP_CTL    0x4320c
@@ -1675,12 +1724,9 @@ enum punit_power_well {
 #define DPIO_PHY_STATUS                        (VLV_DISPLAY_BASE + 0x6240)
 #define   DPLL_PORTD_READY_MASK                (0xf)
 #define DISPLAY_PHY_CONTROL (VLV_DISPLAY_BASE + 0x60100)
-#define   PHY_COM_LANE_RESET_DEASSERT(phy, val) \
-                               ((phy == DPIO_PHY0) ? (val | 1) : (val | 2))
-#define   PHY_COM_LANE_RESET_ASSERT(phy, val) \
-                               ((phy == DPIO_PHY0) ? (val & ~1) : (val & ~2))
+#define   PHY_COM_LANE_RESET_DEASSERT(phy) (1 << (phy))
 #define DISPLAY_PHY_STATUS (VLV_DISPLAY_BASE + 0x60104)
-#define   PHY_POWERGOOD(phy)   ((phy == DPIO_PHY0) ? (1<<31) : (1<<30))
+#define   PHY_POWERGOOD(phy)   (((phy) == DPIO_PHY0) ? (1<<31) : (1<<30))
 
 /*
  * The i830 generation, in LVDS mode, defines P1 as the bit number set within
@@ -2397,6 +2443,7 @@ enum punit_power_well {
 #define _PIPEASRC      0x6001c
 #define _BCLRPAT_A     0x60020
 #define _VSYNCSHIFT_A  0x60028
+#define _PIPE_MULT_A   0x6002c
 
 /* Pipe B timing regs */
 #define _HTOTAL_B      0x61000
@@ -2408,6 +2455,7 @@ enum punit_power_well {
 #define _PIPEBSRC      0x6101c
 #define _BCLRPAT_B     0x61020
 #define _VSYNCSHIFT_B  0x61028
+#define _PIPE_MULT_B   0x6102c
 
 #define TRANSCODER_A_OFFSET 0x60000
 #define TRANSCODER_B_OFFSET 0x61000
@@ -2428,6 +2476,7 @@ enum punit_power_well {
 #define BCLRPAT(trans) _TRANSCODER2(trans, _BCLRPAT_A)
 #define VSYNCSHIFT(trans) _TRANSCODER2(trans, _VSYNCSHIFT_A)
 #define PIPESRC(trans) _TRANSCODER2(trans, _PIPEASRC)
+#define PIPE_MULT(trans) _TRANSCODER2(trans, _PIPE_MULT_A)
 
 /* HSW+ eDP PSR registers */
 #define EDP_PSR_BASE(dev)                       (IS_HASWELL(dev) ? 0x64800 : 0x6f800)
@@ -3476,6 +3525,8 @@ enum punit_power_well {
 #define   DP_LINK_TRAIN_OFF            (3 << 28)
 #define   DP_LINK_TRAIN_MASK           (3 << 28)
 #define   DP_LINK_TRAIN_SHIFT          28
+#define   DP_LINK_TRAIN_PAT_3_CHV      (1 << 14)
+#define   DP_LINK_TRAIN_MASK_CHV       ((3 << 28)|(1<<14))
 
 /* CPT Link training mode */
 #define   DP_LINK_TRAIN_PAT_1_CPT      (0 << 8)
@@ -3732,7 +3783,6 @@ enum punit_power_well {
 #define   PIPE_VSYNC_INTERRUPT_STATUS          (1UL<<9)
 #define   PIPE_DISPLAY_LINE_COMPARE_STATUS     (1UL<<8)
 #define   PIPE_DPST_EVENT_STATUS               (1UL<<7)
-#define   PIPE_LEGACY_BLC_EVENT_STATUS         (1UL<<6)
 #define   PIPE_A_PSR_STATUS_VLV                        (1UL<<6)
 #define   PIPE_LEGACY_BLC_EVENT_STATUS         (1UL<<6)
 #define   PIPE_ODD_FIELD_INTERRUPT_STATUS      (1UL<<5)
@@ -3842,73 +3892,151 @@ enum punit_power_well {
 #define   DSPARB_BEND_SHIFT    9 /* on 855 */
 #define   DSPARB_AEND_SHIFT    0
 
+/* pnv/gen4/g4x/vlv/chv */
 #define DSPFW1                 (dev_priv->info.display_mmio_offset + 0x70034)
-#define   DSPFW_SR_SHIFT       23
-#define   DSPFW_SR_MASK                (0x1ff<<23)
-#define   DSPFW_CURSORB_SHIFT  16
-#define   DSPFW_CURSORB_MASK   (0x3f<<16)
-#define   DSPFW_PLANEB_SHIFT   8
-#define   DSPFW_PLANEB_MASK    (0x7f<<8)
-#define   DSPFW_PLANEA_MASK    (0x7f)
+#define   DSPFW_SR_SHIFT               23
+#define   DSPFW_SR_MASK                        (0x1ff<<23)
+#define   DSPFW_CURSORB_SHIFT          16
+#define   DSPFW_CURSORB_MASK           (0x3f<<16)
+#define   DSPFW_PLANEB_SHIFT           8
+#define   DSPFW_PLANEB_MASK            (0x7f<<8)
+#define   DSPFW_PLANEB_MASK_VLV                (0xff<<8) /* vlv/chv */
+#define   DSPFW_PLANEA_SHIFT           0
+#define   DSPFW_PLANEA_MASK            (0x7f<<0)
+#define   DSPFW_PLANEA_MASK_VLV                (0xff<<0) /* vlv/chv */
 #define DSPFW2                 (dev_priv->info.display_mmio_offset + 0x70038)
-#define   DSPFW_CURSORA_MASK   0x00003f00
-#define   DSPFW_CURSORA_SHIFT  8
-#define   DSPFW_PLANEC_MASK    (0x7f)
+#define   DSPFW_FBC_SR_EN              (1<<31)   /* g4x */
+#define   DSPFW_FBC_SR_SHIFT           28
+#define   DSPFW_FBC_SR_MASK            (0x7<<28) /* g4x */
+#define   DSPFW_FBC_HPLL_SR_SHIFT      24
+#define   DSPFW_FBC_HPLL_SR_MASK       (0xf<<24) /* g4x */
+#define   DSPFW_SPRITEB_SHIFT          (16)
+#define   DSPFW_SPRITEB_MASK           (0x7f<<16) /* g4x */
+#define   DSPFW_SPRITEB_MASK_VLV       (0xff<<16) /* vlv/chv */
+#define   DSPFW_CURSORA_SHIFT          8
+#define   DSPFW_CURSORA_MASK           (0x3f<<8)
+#define   DSPFW_PLANEC_SHIFT_OLD       0
+#define   DSPFW_PLANEC_MASK_OLD                (0x7f<<0) /* pre-gen4 sprite C */
+#define   DSPFW_SPRITEA_SHIFT          0
+#define   DSPFW_SPRITEA_MASK           (0x7f<<0) /* g4x */
+#define   DSPFW_SPRITEA_MASK_VLV       (0xff<<0) /* vlv/chv */
 #define DSPFW3                 (dev_priv->info.display_mmio_offset + 0x7003c)
-#define   DSPFW_HPLL_SR_EN     (1<<31)
-#define   DSPFW_CURSOR_SR_SHIFT        24
+#define   DSPFW_HPLL_SR_EN             (1<<31)
 #define   PINEVIEW_SELF_REFRESH_EN     (1<<30)
+#define   DSPFW_CURSOR_SR_SHIFT                24
 #define   DSPFW_CURSOR_SR_MASK         (0x3f<<24)
 #define   DSPFW_HPLL_CURSOR_SHIFT      16
 #define   DSPFW_HPLL_CURSOR_MASK       (0x3f<<16)
-#define   DSPFW_HPLL_SR_MASK           (0x1ff)
-#define DSPFW4                 (dev_priv->info.display_mmio_offset + 0x70070)
-#define DSPFW7                 (dev_priv->info.display_mmio_offset + 0x7007c)
+#define   DSPFW_HPLL_SR_SHIFT          0
+#define   DSPFW_HPLL_SR_MASK           (0x1ff<<0)
+
+/* vlv/chv */
+#define DSPFW4                 (VLV_DISPLAY_BASE + 0x70070)
+#define   DSPFW_SPRITEB_WM1_SHIFT      16
+#define   DSPFW_SPRITEB_WM1_MASK       (0xff<<16)
+#define   DSPFW_CURSORA_WM1_SHIFT      8
+#define   DSPFW_CURSORA_WM1_MASK       (0x3f<<8)
+#define   DSPFW_SPRITEA_WM1_SHIFT      0
+#define   DSPFW_SPRITEA_WM1_MASK       (0xff<<0)
+#define DSPFW5                 (VLV_DISPLAY_BASE + 0x70074)
+#define   DSPFW_PLANEB_WM1_SHIFT       24
+#define   DSPFW_PLANEB_WM1_MASK                (0xff<<24)
+#define   DSPFW_PLANEA_WM1_SHIFT       16
+#define   DSPFW_PLANEA_WM1_MASK                (0xff<<16)
+#define   DSPFW_CURSORB_WM1_SHIFT      8
+#define   DSPFW_CURSORB_WM1_MASK       (0x3f<<8)
+#define   DSPFW_CURSOR_SR_WM1_SHIFT    0
+#define   DSPFW_CURSOR_SR_WM1_MASK     (0x3f<<0)
+#define DSPFW6                 (VLV_DISPLAY_BASE + 0x70078)
+#define   DSPFW_SR_WM1_SHIFT           0
+#define   DSPFW_SR_WM1_MASK            (0x1ff<<0)
+#define DSPFW7                 (VLV_DISPLAY_BASE + 0x7007c)
+#define DSPFW7_CHV             (VLV_DISPLAY_BASE + 0x700b4) /* wtf #1? */
+#define   DSPFW_SPRITED_WM1_SHIFT      24
+#define   DSPFW_SPRITED_WM1_MASK       (0xff<<24)
+#define   DSPFW_SPRITED_SHIFT          16
+#define   DSPFW_SPRITED_MASK           (0xff<<16)
+#define   DSPFW_SPRITEC_WM1_SHIFT      8
+#define   DSPFW_SPRITEC_WM1_MASK       (0xff<<8)
+#define   DSPFW_SPRITEC_SHIFT          0
+#define   DSPFW_SPRITEC_MASK           (0xff<<0)
+#define DSPFW8_CHV             (VLV_DISPLAY_BASE + 0x700b8)
+#define   DSPFW_SPRITEF_WM1_SHIFT      24
+#define   DSPFW_SPRITEF_WM1_MASK       (0xff<<24)
+#define   DSPFW_SPRITEF_SHIFT          16
+#define   DSPFW_SPRITEF_MASK           (0xff<<16)
+#define   DSPFW_SPRITEE_WM1_SHIFT      8
+#define   DSPFW_SPRITEE_WM1_MASK       (0xff<<8)
+#define   DSPFW_SPRITEE_SHIFT          0
+#define   DSPFW_SPRITEE_MASK           (0xff<<0)
+#define DSPFW9_CHV             (VLV_DISPLAY_BASE + 0x7007c) /* wtf #2? */
+#define   DSPFW_PLANEC_WM1_SHIFT       24
+#define   DSPFW_PLANEC_WM1_MASK                (0xff<<24)
+#define   DSPFW_PLANEC_SHIFT           16
+#define   DSPFW_PLANEC_MASK            (0xff<<16)
+#define   DSPFW_CURSORC_WM1_SHIFT      8
+#define   DSPFW_CURSORC_WM1_MASK       (0x3f<<16)
+#define   DSPFW_CURSORC_SHIFT          0
+#define   DSPFW_CURSORC_MASK           (0x3f<<0)
+
+/* vlv/chv high order bits */
+#define DSPHOWM                        (VLV_DISPLAY_BASE + 0x70064)
+#define   DSPFW_SR_HI_SHIFT            24
+#define   DSPFW_SR_HI_MASK             (1<<24)
+#define   DSPFW_SPRITEF_HI_SHIFT       23
+#define   DSPFW_SPRITEF_HI_MASK                (1<<23)
+#define   DSPFW_SPRITEE_HI_SHIFT       22
+#define   DSPFW_SPRITEE_HI_MASK                (1<<22)
+#define   DSPFW_PLANEC_HI_SHIFT                21
+#define   DSPFW_PLANEC_HI_MASK         (1<<21)
+#define   DSPFW_SPRITED_HI_SHIFT       20
+#define   DSPFW_SPRITED_HI_MASK                (1<<20)
+#define   DSPFW_SPRITEC_HI_SHIFT       16
+#define   DSPFW_SPRITEC_HI_MASK                (1<<16)
+#define   DSPFW_PLANEB_HI_SHIFT                12
+#define   DSPFW_PLANEB_HI_MASK         (1<<12)
+#define   DSPFW_SPRITEB_HI_SHIFT       8
+#define   DSPFW_SPRITEB_HI_MASK                (1<<8)
+#define   DSPFW_SPRITEA_HI_SHIFT       4
+#define   DSPFW_SPRITEA_HI_MASK                (1<<4)
+#define   DSPFW_PLANEA_HI_SHIFT                0
+#define   DSPFW_PLANEA_HI_MASK         (1<<0)
+#define DSPHOWM1               (VLV_DISPLAY_BASE + 0x70068)
+#define   DSPFW_SR_WM1_HI_SHIFT                24
+#define   DSPFW_SR_WM1_HI_MASK         (1<<24)
+#define   DSPFW_SPRITEF_WM1_HI_SHIFT   23
+#define   DSPFW_SPRITEF_WM1_HI_MASK    (1<<23)
+#define   DSPFW_SPRITEE_WM1_HI_SHIFT   22
+#define   DSPFW_SPRITEE_WM1_HI_MASK    (1<<22)
+#define   DSPFW_PLANEC_WM1_HI_SHIFT    21
+#define   DSPFW_PLANEC_WM1_HI_MASK     (1<<21)
+#define   DSPFW_SPRITED_WM1_HI_SHIFT   20
+#define   DSPFW_SPRITED_WM1_HI_MASK    (1<<20)
+#define   DSPFW_SPRITEC_WM1_HI_SHIFT   16
+#define   DSPFW_SPRITEC_WM1_HI_MASK    (1<<16)
+#define   DSPFW_PLANEB_WM1_HI_SHIFT    12
+#define   DSPFW_PLANEB_WM1_HI_MASK     (1<<12)
+#define   DSPFW_SPRITEB_WM1_HI_SHIFT   8
+#define   DSPFW_SPRITEB_WM1_HI_MASK    (1<<8)
+#define   DSPFW_SPRITEA_WM1_HI_SHIFT   4
+#define   DSPFW_SPRITEA_WM1_HI_MASK    (1<<4)
+#define   DSPFW_PLANEA_WM1_HI_SHIFT    0
+#define   DSPFW_PLANEA_WM1_HI_MASK     (1<<0)
 
 /* drain latency register values*/
 #define DRAIN_LATENCY_PRECISION_32     32
 #define DRAIN_LATENCY_PRECISION_64     64
-#define VLV_DDL1                       (VLV_DISPLAY_BASE + 0x70050)
-#define DDL_CURSORA_PRECISION_64       (1<<31)
-#define DDL_CURSORA_PRECISION_32       (0<<31)
-#define DDL_CURSORA_SHIFT              24
-#define DDL_SPRITEB_PRECISION_64       (1<<23)
-#define DDL_SPRITEB_PRECISION_32       (0<<23)
-#define DDL_SPRITEB_SHIFT              16
-#define DDL_SPRITEA_PRECISION_64       (1<<15)
-#define DDL_SPRITEA_PRECISION_32       (0<<15)
-#define DDL_SPRITEA_SHIFT              8
-#define DDL_PLANEA_PRECISION_64                (1<<7)
-#define DDL_PLANEA_PRECISION_32                (0<<7)
-#define DDL_PLANEA_SHIFT               0
-
-#define VLV_DDL2                       (VLV_DISPLAY_BASE + 0x70054)
-#define DDL_CURSORB_PRECISION_64       (1<<31)
-#define DDL_CURSORB_PRECISION_32       (0<<31)
-#define DDL_CURSORB_SHIFT              24
-#define DDL_SPRITED_PRECISION_64       (1<<23)
-#define DDL_SPRITED_PRECISION_32       (0<<23)
-#define DDL_SPRITED_SHIFT              16
-#define DDL_SPRITEC_PRECISION_64       (1<<15)
-#define DDL_SPRITEC_PRECISION_32       (0<<15)
-#define DDL_SPRITEC_SHIFT              8
-#define DDL_PLANEB_PRECISION_64                (1<<7)
-#define DDL_PLANEB_PRECISION_32                (0<<7)
-#define DDL_PLANEB_SHIFT               0
-
-#define VLV_DDL3                       (VLV_DISPLAY_BASE + 0x70058)
-#define DDL_CURSORC_PRECISION_64       (1<<31)
-#define DDL_CURSORC_PRECISION_32       (0<<31)
-#define DDL_CURSORC_SHIFT              24
-#define DDL_SPRITEF_PRECISION_64       (1<<23)
-#define DDL_SPRITEF_PRECISION_32       (0<<23)
-#define DDL_SPRITEF_SHIFT              16
-#define DDL_SPRITEE_PRECISION_64       (1<<15)
-#define DDL_SPRITEE_PRECISION_32       (0<<15)
-#define DDL_SPRITEE_SHIFT              8
-#define DDL_PLANEC_PRECISION_64                (1<<7)
-#define DDL_PLANEC_PRECISION_32                (0<<7)
-#define DDL_PLANEC_SHIFT               0
+#define VLV_DDL(pipe)                  (VLV_DISPLAY_BASE + 0x70050 + 4 * (pipe))
+#define DDL_CURSOR_PRECISION_64                (1<<31)
+#define DDL_CURSOR_PRECISION_32                (0<<31)
+#define DDL_CURSOR_SHIFT               24
+#define DDL_SPRITE_PRECISION_64(sprite)        (1<<(15+8*(sprite)))
+#define DDL_SPRITE_PRECISION_32(sprite)        (0<<(15+8*(sprite)))
+#define DDL_SPRITE_SHIFT(sprite)       (8+8*(sprite))
+#define DDL_PLANE_PRECISION_64         (1<<7)
+#define DDL_PLANE_PRECISION_32         (0<<7)
+#define DDL_PLANE_SHIFT                        0
+#define DRAIN_LATENCY_MASK             0x7f
 
 /* FIFO watermark sizes etc */
 #define G4X_FIFO_LINE_SIZE     64
@@ -4026,7 +4154,8 @@ enum punit_power_well {
 /* Old style CUR*CNTR flags (desktop 8xx) */
 #define   CURSOR_ENABLE                0x80000000
 #define   CURSOR_GAMMA_ENABLE  0x40000000
-#define   CURSOR_STRIDE_MASK   0x30000000
+#define   CURSOR_STRIDE_SHIFT  28
+#define   CURSOR_STRIDE(x)     ((ffs(x)-9) << CURSOR_STRIDE_SHIFT) /* 256,512,1k,2k */
 #define   CURSOR_PIPE_CSC_ENABLE (1<<24)
 #define   CURSOR_FORMAT_SHIFT  24
 #define   CURSOR_FORMAT_MASK   (0x07 << CURSOR_FORMAT_SHIFT)
@@ -4111,6 +4240,7 @@ enum punit_power_well {
 #define   DISPPLANE_NO_LINE_DOUBLE             0
 #define   DISPPLANE_STEREO_POLARITY_FIRST      0
 #define   DISPPLANE_STEREO_POLARITY_SECOND     (1<<18)
+#define   DISPPLANE_ROTATE_180         (1<<15)
 #define   DISPPLANE_TRICKLE_FEED_DISABLE       (1<<14) /* Ironlake */
 #define   DISPPLANE_TILED                      (1<<10)
 #define _DSPAADDR                              0x70184
@@ -4195,6 +4325,7 @@ enum punit_power_well {
 #define   DVS_YUV_ORDER_UYVY   (1<<16)
 #define   DVS_YUV_ORDER_YVYU   (2<<16)
 #define   DVS_YUV_ORDER_VYUY   (3<<16)
+#define   DVS_ROTATE_180       (1<<15)
 #define   DVS_DEST_KEY         (1<<2)
 #define   DVS_TRICKLE_FEED_DISABLE (1<<14)
 #define   DVS_TILED            (1<<10)
@@ -4265,6 +4396,7 @@ enum punit_power_well {
 #define   SPRITE_YUV_ORDER_UYVY                (1<<16)
 #define   SPRITE_YUV_ORDER_YVYU                (2<<16)
 #define   SPRITE_YUV_ORDER_VYUY                (3<<16)
+#define   SPRITE_ROTATE_180            (1<<15)
 #define   SPRITE_TRICKLE_FEED_DISABLE  (1<<14)
 #define   SPRITE_INT_GAMMA_ENABLE      (1<<13)
 #define   SPRITE_TILED                 (1<<10)
@@ -4338,6 +4470,7 @@ enum punit_power_well {
 #define   SP_YUV_ORDER_UYVY            (1<<16)
 #define   SP_YUV_ORDER_YVYU            (2<<16)
 #define   SP_YUV_ORDER_VYUY            (3<<16)
+#define   SP_ROTATE_180                        (1<<15)
 #define   SP_TILED                     (1<<10)
 #define _SPALINOFF             (VLV_DISPLAY_BASE + 0x72184)
 #define _SPASTRIDE             (VLV_DISPLAY_BASE + 0x72188)
@@ -5246,8 +5379,7 @@ enum punit_power_well {
 #define PIPEA_PP_STATUS         (VLV_DISPLAY_BASE + 0x61200)
 #define PIPEA_PP_CONTROL        (VLV_DISPLAY_BASE + 0x61204)
 #define PIPEA_PP_ON_DELAYS      (VLV_DISPLAY_BASE + 0x61208)
-#define  PANEL_PORT_SELECT_DPB_VLV     (1 << 30)
-#define  PANEL_PORT_SELECT_DPC_VLV     (2 << 30)
+#define  PANEL_PORT_SELECT_VLV(port)   ((port) << 30)
 #define PIPEA_PP_OFF_DELAYS     (VLV_DISPLAY_BASE + 0x6120c)
 #define PIPEA_PP_DIVISOR        (VLV_DISPLAY_BASE + 0x61210)
 
@@ -5407,7 +5539,6 @@ enum punit_power_well {
 #define   VLV_GTLC_ALLOWWAKEERR                        (1 << 1)
 #define   VLV_GTLC_PW_MEDIA_STATUS_MASK                (1 << 5)
 #define   VLV_GTLC_PW_RENDER_STATUS_MASK       (1 << 7)
-#define VLV_GTLC_SURVIVABILITY_REG              0x130098
 #define  FORCEWAKE_MT                          0xa188 /* multi-threaded */
 #define   FORCEWAKE_KERNEL                     0x1
 #define   FORCEWAKE_USER                       0x2
@@ -5545,12 +5676,6 @@ enum punit_power_well {
                                                 GEN6_PM_RP_DOWN_THRESHOLD | \
                                                 GEN6_PM_RP_DOWN_TIMEOUT)
 
-#define CHV_CZ_CLOCK_FREQ_MODE_200                     200
-#define CHV_CZ_CLOCK_FREQ_MODE_267                     267
-#define CHV_CZ_CLOCK_FREQ_MODE_320                     320
-#define CHV_CZ_CLOCK_FREQ_MODE_333                     333
-#define CHV_CZ_CLOCK_FREQ_MODE_400                     400
-
 #define GEN7_GT_SCRATCH_BASE                   0x4F100
 #define GEN7_GT_SCRATCH_REG_NUM                        8
 
@@ -5866,15 +5991,7 @@ enum punit_power_well {
 #define DDI_BUF_CTL_B                          0x64100
 #define DDI_BUF_CTL(port) _PORT(port, DDI_BUF_CTL_A, DDI_BUF_CTL_B)
 #define  DDI_BUF_CTL_ENABLE                    (1<<31)
-#define  DDI_BUF_EMP_400MV_0DB_HSW             (0<<24)   /* Sel0 */
-#define  DDI_BUF_EMP_400MV_3_5DB_HSW           (1<<24)   /* Sel1 */
-#define  DDI_BUF_EMP_400MV_6DB_HSW             (2<<24)   /* Sel2 */
-#define  DDI_BUF_EMP_400MV_9_5DB_HSW           (3<<24)   /* Sel3 */
-#define  DDI_BUF_EMP_600MV_0DB_HSW             (4<<24)   /* Sel4 */
-#define  DDI_BUF_EMP_600MV_3_5DB_HSW           (5<<24)   /* Sel5 */
-#define  DDI_BUF_EMP_600MV_6DB_HSW             (6<<24)   /* Sel6 */
-#define  DDI_BUF_EMP_800MV_0DB_HSW             (7<<24)   /* Sel7 */
-#define  DDI_BUF_EMP_800MV_3_5DB_HSW           (8<<24)   /* Sel8 */
+#define  DDI_BUF_TRANS_SELECT(n)       ((n) << 24)
 #define  DDI_BUF_EMP_MASK                      (0xf<<24)
 #define  DDI_BUF_PORT_REVERSAL                 (1<<16)
 #define  DDI_BUF_IS_IDLE                       (1<<7)
index ae7fd8fc27f05cab33eea39739c96f816f156fe9..503847f18fdd5a1252403ca44d85de7daab6fa82 100644 (file)
@@ -540,7 +540,7 @@ static ssize_t error_state_read(struct file *filp, struct kobject *kobj,
 
        memset(&error_priv, 0, sizeof(error_priv));
 
-       ret = i915_error_state_buf_init(&error_str, count, off);
+       ret = i915_error_state_buf_init(&error_str, to_i915(dev), count, off);
        if (ret)
                return ret;
 
index afcc8dd40bdd437fa32c113d6aa966fb87bf3a1c..a4bd90f36a03396ea7e04854b2520a38e73918b2 100644 (file)
@@ -627,16 +627,16 @@ parse_edp(struct drm_i915_private *dev_priv, struct bdb_header *bdb)
 
        switch (edp_link_params->preemphasis) {
        case EDP_PREEMPHASIS_NONE:
-               dev_priv->vbt.edp_preemphasis = DP_TRAIN_PRE_EMPHASIS_0;
+               dev_priv->vbt.edp_preemphasis = DP_TRAIN_PRE_EMPH_LEVEL_0;
                break;
        case EDP_PREEMPHASIS_3_5dB:
-               dev_priv->vbt.edp_preemphasis = DP_TRAIN_PRE_EMPHASIS_3_5;
+               dev_priv->vbt.edp_preemphasis = DP_TRAIN_PRE_EMPH_LEVEL_1;
                break;
        case EDP_PREEMPHASIS_6dB:
-               dev_priv->vbt.edp_preemphasis = DP_TRAIN_PRE_EMPHASIS_6;
+               dev_priv->vbt.edp_preemphasis = DP_TRAIN_PRE_EMPH_LEVEL_2;
                break;
        case EDP_PREEMPHASIS_9_5dB:
-               dev_priv->vbt.edp_preemphasis = DP_TRAIN_PRE_EMPHASIS_9_5;
+               dev_priv->vbt.edp_preemphasis = DP_TRAIN_PRE_EMPH_LEVEL_3;
                break;
        default:
                DRM_DEBUG_KMS("VBT has unknown eDP pre-emphasis value %u\n",
@@ -646,16 +646,16 @@ parse_edp(struct drm_i915_private *dev_priv, struct bdb_header *bdb)
 
        switch (edp_link_params->vswing) {
        case EDP_VSWING_0_4V:
-               dev_priv->vbt.edp_vswing = DP_TRAIN_VOLTAGE_SWING_400;
+               dev_priv->vbt.edp_vswing = DP_TRAIN_VOLTAGE_SWING_LEVEL_0;
                break;
        case EDP_VSWING_0_6V:
-               dev_priv->vbt.edp_vswing = DP_TRAIN_VOLTAGE_SWING_600;
+               dev_priv->vbt.edp_vswing = DP_TRAIN_VOLTAGE_SWING_LEVEL_1;
                break;
        case EDP_VSWING_0_8V:
-               dev_priv->vbt.edp_vswing = DP_TRAIN_VOLTAGE_SWING_800;
+               dev_priv->vbt.edp_vswing = DP_TRAIN_VOLTAGE_SWING_LEVEL_2;
                break;
        case EDP_VSWING_1_2V:
-               dev_priv->vbt.edp_vswing = DP_TRAIN_VOLTAGE_SWING_1200;
+               dev_priv->vbt.edp_vswing = DP_TRAIN_VOLTAGE_SWING_LEVEL_3;
                break;
        default:
                DRM_DEBUG_KMS("VBT has unknown eDP voltage swing value %u\n",
@@ -976,12 +976,10 @@ static void parse_ddi_port(struct drm_i915_private *dev_priv, enum port port,
        if (bdb->version >= 158) {
                /* The VBT HDMI level shift values match the table we have. */
                hdmi_level_shift = child->raw[7] & 0xF;
-               if (hdmi_level_shift < 0xC) {
-                       DRM_DEBUG_KMS("VBT HDMI level shift for port %c: %d\n",
-                                     port_name(port),
-                                     hdmi_level_shift);
-                       info->hdmi_level_shift = hdmi_level_shift;
-               }
+               DRM_DEBUG_KMS("VBT HDMI level shift for port %c: %d\n",
+                             port_name(port),
+                             hdmi_level_shift);
+               info->hdmi_level_shift = hdmi_level_shift;
        }
 }
 
@@ -1114,8 +1112,7 @@ init_vbt_defaults(struct drm_i915_private *dev_priv)
                struct ddi_vbt_port_info *info =
                        &dev_priv->vbt.ddi_port_info[port];
 
-               /* Recommended BSpec default: 800mV 0dB. */
-               info->hdmi_level_shift = 6;
+               info->hdmi_level_shift = HDMI_LEVEL_SHIFT_UNKNOWN;
 
                info->supports_dvi = (port != PORT_A && port != PORT_E);
                info->supports_hdmi = info->supports_dvi;
index b98667796337d776b1d1d39c677a5dfffe6b32b6..905999bee2ac5ee7f7b550f1c3f4fa043f422a97 100644 (file)
@@ -802,7 +802,8 @@ struct mipi_config {
 
        u16 rsvd4;
 
-       u8 rsvd5[5];
+       u8 rsvd5;
+       u32 target_burst_mode_freq;
        u32 dsi_ddr_clk;
        u32 bridge_ref_clk;
 
index 5db0b5552e39a5005f1c9e1dde74fe7216bb5037..b63d4fa204a32b540529b9e49d72cb7108839190 100644 (file)
 #include "i915_drv.h"
 #include "intel_drv.h"
 
+struct ddi_buf_trans {
+       u32 trans1;     /* balance leg enable, de-emph level */
+       u32 trans2;     /* vref sel, vswing */
+};
+
 /* HDMI/DVI modes ignore everything but the last 2 items. So we share
  * them for both DP and FDI transports, allowing those ports to
  * automatically adapt to HDMI connections as well
  */
-static const u32 hsw_ddi_translations_dp[] = {
-       0x00FFFFFF, 0x0006000E,         /* DP parameters */
-       0x00D75FFF, 0x0005000A,
-       0x00C30FFF, 0x00040006,
-       0x80AAAFFF, 0x000B0000,
-       0x00FFFFFF, 0x0005000A,
-       0x00D75FFF, 0x000C0004,
-       0x80C30FFF, 0x000B0000,
-       0x00FFFFFF, 0x00040006,
-       0x80D75FFF, 0x000B0000,
+static const struct ddi_buf_trans hsw_ddi_translations_dp[] = {
+       { 0x00FFFFFF, 0x0006000E },
+       { 0x00D75FFF, 0x0005000A },
+       { 0x00C30FFF, 0x00040006 },
+       { 0x80AAAFFF, 0x000B0000 },
+       { 0x00FFFFFF, 0x0005000A },
+       { 0x00D75FFF, 0x000C0004 },
+       { 0x80C30FFF, 0x000B0000 },
+       { 0x00FFFFFF, 0x00040006 },
+       { 0x80D75FFF, 0x000B0000 },
 };
 
-static const u32 hsw_ddi_translations_fdi[] = {
-       0x00FFFFFF, 0x0007000E,         /* FDI parameters */
-       0x00D75FFF, 0x000F000A,
-       0x00C30FFF, 0x00060006,
-       0x00AAAFFF, 0x001E0000,
-       0x00FFFFFF, 0x000F000A,
-       0x00D75FFF, 0x00160004,
-       0x00C30FFF, 0x001E0000,
-       0x00FFFFFF, 0x00060006,
-       0x00D75FFF, 0x001E0000,
+static const struct ddi_buf_trans hsw_ddi_translations_fdi[] = {
+       { 0x00FFFFFF, 0x0007000E },
+       { 0x00D75FFF, 0x000F000A },
+       { 0x00C30FFF, 0x00060006 },
+       { 0x00AAAFFF, 0x001E0000 },
+       { 0x00FFFFFF, 0x000F000A },
+       { 0x00D75FFF, 0x00160004 },
+       { 0x00C30FFF, 0x001E0000 },
+       { 0x00FFFFFF, 0x00060006 },
+       { 0x00D75FFF, 0x001E0000 },
 };
 
-static const u32 hsw_ddi_translations_hdmi[] = {
-                               /* Idx  NT mV diff      T mV diff       db  */
-       0x00FFFFFF, 0x0006000E, /* 0:   400             400             0   */
-       0x00E79FFF, 0x000E000C, /* 1:   400             500             2   */
-       0x00D75FFF, 0x0005000A, /* 2:   400             600             3.5 */
-       0x00FFFFFF, 0x0005000A, /* 3:   600             600             0   */
-       0x00E79FFF, 0x001D0007, /* 4:   600             750             2   */
-       0x00D75FFF, 0x000C0004, /* 5:   600             900             3.5 */
-       0x00FFFFFF, 0x00040006, /* 6:   800             800             0   */
-       0x80E79FFF, 0x00030002, /* 7:   800             1000            2   */
-       0x00FFFFFF, 0x00140005, /* 8:   850             850             0   */
-       0x00FFFFFF, 0x000C0004, /* 9:   900             900             0   */
-       0x00FFFFFF, 0x001C0003, /* 10:  950             950             0   */
-       0x80FFFFFF, 0x00030002, /* 11:  1000            1000            0   */
+static const struct ddi_buf_trans hsw_ddi_translations_hdmi[] = {
+                                       /* Idx  NT mV d T mV d  db      */
+       { 0x00FFFFFF, 0x0006000E },     /* 0:   400     400     0       */
+       { 0x00E79FFF, 0x000E000C },     /* 1:   400     500     2       */
+       { 0x00D75FFF, 0x0005000A },     /* 2:   400     600     3.5     */
+       { 0x00FFFFFF, 0x0005000A },     /* 3:   600     600     0       */
+       { 0x00E79FFF, 0x001D0007 },     /* 4:   600     750     2       */
+       { 0x00D75FFF, 0x000C0004 },     /* 5:   600     900     3.5     */
+       { 0x00FFFFFF, 0x00040006 },     /* 6:   800     800     0       */
+       { 0x80E79FFF, 0x00030002 },     /* 7:   800     1000    2       */
+       { 0x00FFFFFF, 0x00140005 },     /* 8:   850     850     0       */
+       { 0x00FFFFFF, 0x000C0004 },     /* 9:   900     900     0       */
+       { 0x00FFFFFF, 0x001C0003 },     /* 10:  950     950     0       */
+       { 0x80FFFFFF, 0x00030002 },     /* 11:  1000    1000    0       */
 };
 
-static const u32 bdw_ddi_translations_edp[] = {
-       0x00FFFFFF, 0x00000012,         /* eDP parameters */
-       0x00EBAFFF, 0x00020011,
-       0x00C71FFF, 0x0006000F,
-       0x00AAAFFF, 0x000E000A,
-       0x00FFFFFF, 0x00020011,
-       0x00DB6FFF, 0x0005000F,
-       0x00BEEFFF, 0x000A000C,
-       0x00FFFFFF, 0x0005000F,
-       0x00DB6FFF, 0x000A000C,
-       0x00FFFFFF, 0x00140006          /* HDMI parameters 800mV 0dB*/
+static const struct ddi_buf_trans bdw_ddi_translations_edp[] = {
+       { 0x00FFFFFF, 0x00000012 },
+       { 0x00EBAFFF, 0x00020011 },
+       { 0x00C71FFF, 0x0006000F },
+       { 0x00AAAFFF, 0x000E000A },
+       { 0x00FFFFFF, 0x00020011 },
+       { 0x00DB6FFF, 0x0005000F },
+       { 0x00BEEFFF, 0x000A000C },
+       { 0x00FFFFFF, 0x0005000F },
+       { 0x00DB6FFF, 0x000A000C },
 };
 
-static const u32 bdw_ddi_translations_dp[] = {
-       0x00FFFFFF, 0x0007000E,         /* DP parameters */
-       0x00D75FFF, 0x000E000A,
-       0x00BEFFFF, 0x00140006,
-       0x80B2CFFF, 0x001B0002,
-       0x00FFFFFF, 0x000E000A,
-       0x00D75FFF, 0x00180004,
-       0x80CB2FFF, 0x001B0002,
-       0x00F7DFFF, 0x00180004,
-       0x80D75FFF, 0x001B0002,
-       0x00FFFFFF, 0x00140006          /* HDMI parameters 800mV 0dB*/
+static const struct ddi_buf_trans bdw_ddi_translations_dp[] = {
+       { 0x00FFFFFF, 0x0007000E },
+       { 0x00D75FFF, 0x000E000A },
+       { 0x00BEFFFF, 0x00140006 },
+       { 0x80B2CFFF, 0x001B0002 },
+       { 0x00FFFFFF, 0x000E000A },
+       { 0x00D75FFF, 0x00180004 },
+       { 0x80CB2FFF, 0x001B0002 },
+       { 0x00F7DFFF, 0x00180004 },
+       { 0x80D75FFF, 0x001B0002 },
 };
 
-static const u32 bdw_ddi_translations_fdi[] = {
-       0x00FFFFFF, 0x0001000E,         /* FDI parameters */
-       0x00D75FFF, 0x0004000A,
-       0x00C30FFF, 0x00070006,
-       0x00AAAFFF, 0x000C0000,
-       0x00FFFFFF, 0x0004000A,
-       0x00D75FFF, 0x00090004,
-       0x00C30FFF, 0x000C0000,
-       0x00FFFFFF, 0x00070006,
-       0x00D75FFF, 0x000C0000,
-       0x00FFFFFF, 0x00140006          /* HDMI parameters 800mV 0dB*/
+static const struct ddi_buf_trans bdw_ddi_translations_fdi[] = {
+       { 0x00FFFFFF, 0x0001000E },
+       { 0x00D75FFF, 0x0004000A },
+       { 0x00C30FFF, 0x00070006 },
+       { 0x00AAAFFF, 0x000C0000 },
+       { 0x00FFFFFF, 0x0004000A },
+       { 0x00D75FFF, 0x00090004 },
+       { 0x00C30FFF, 0x000C0000 },
+       { 0x00FFFFFF, 0x00070006 },
+       { 0x00D75FFF, 0x000C0000 },
+};
+
+static const struct ddi_buf_trans bdw_ddi_translations_hdmi[] = {
+                                       /* Idx  NT mV d T mV df db      */
+       { 0x00FFFFFF, 0x0007000E },     /* 0:   400     400     0       */
+       { 0x00D75FFF, 0x000E000A },     /* 1:   400     600     3.5     */
+       { 0x00BEFFFF, 0x00140006 },     /* 2:   400     800     6       */
+       { 0x00FFFFFF, 0x0009000D },     /* 3:   450     450     0       */
+       { 0x00FFFFFF, 0x000E000A },     /* 4:   600     600     0       */
+       { 0x00D7FFFF, 0x00140006 },     /* 5:   600     800     2.5     */
+       { 0x80CB2FFF, 0x001B0002 },     /* 6:   600     1000    4.5     */
+       { 0x00FFFFFF, 0x00140006 },     /* 7:   800     800     0       */
+       { 0x80E79FFF, 0x001B0002 },     /* 8:   800     1000    2       */
+       { 0x80FFFFFF, 0x001B0002 },     /* 9:   1000    1000    0       */
 };
 
 enum port intel_ddi_get_encoder_port(struct intel_encoder *intel_encoder)
@@ -145,26 +161,36 @@ static void intel_prepare_ddi_buffers(struct drm_device *dev, enum port port)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
        u32 reg;
-       int i;
+       int i, n_hdmi_entries, hdmi_800mV_0dB;
        int hdmi_level = dev_priv->vbt.ddi_port_info[port].hdmi_level_shift;
-       const u32 *ddi_translations_fdi;
-       const u32 *ddi_translations_dp;
-       const u32 *ddi_translations_edp;
-       const u32 *ddi_translations;
+       const struct ddi_buf_trans *ddi_translations_fdi;
+       const struct ddi_buf_trans *ddi_translations_dp;
+       const struct ddi_buf_trans *ddi_translations_edp;
+       const struct ddi_buf_trans *ddi_translations_hdmi;
+       const struct ddi_buf_trans *ddi_translations;
 
        if (IS_BROADWELL(dev)) {
                ddi_translations_fdi = bdw_ddi_translations_fdi;
                ddi_translations_dp = bdw_ddi_translations_dp;
                ddi_translations_edp = bdw_ddi_translations_edp;
+               ddi_translations_hdmi = bdw_ddi_translations_hdmi;
+               n_hdmi_entries = ARRAY_SIZE(bdw_ddi_translations_hdmi);
+               hdmi_800mV_0dB = 7;
        } else if (IS_HASWELL(dev)) {
                ddi_translations_fdi = hsw_ddi_translations_fdi;
                ddi_translations_dp = hsw_ddi_translations_dp;
                ddi_translations_edp = hsw_ddi_translations_dp;
+               ddi_translations_hdmi = hsw_ddi_translations_hdmi;
+               n_hdmi_entries = ARRAY_SIZE(hsw_ddi_translations_hdmi);
+               hdmi_800mV_0dB = 6;
        } else {
                WARN(1, "ddi translation table missing\n");
                ddi_translations_edp = bdw_ddi_translations_dp;
                ddi_translations_fdi = bdw_ddi_translations_fdi;
                ddi_translations_dp = bdw_ddi_translations_dp;
+               ddi_translations_hdmi = bdw_ddi_translations_hdmi;
+               n_hdmi_entries = ARRAY_SIZE(bdw_ddi_translations_hdmi);
+               hdmi_800mV_0dB = 7;
        }
 
        switch (port) {
@@ -190,14 +216,22 @@ static void intel_prepare_ddi_buffers(struct drm_device *dev, enum port port)
 
        for (i = 0, reg = DDI_BUF_TRANS(port);
             i < ARRAY_SIZE(hsw_ddi_translations_fdi); i++) {
-               I915_WRITE(reg, ddi_translations[i]);
+               I915_WRITE(reg, ddi_translations[i].trans1);
                reg += 4;
-       }
-       /* Entry 9 is for HDMI: */
-       for (i = 0; i < 2; i++) {
-               I915_WRITE(reg, hsw_ddi_translations_hdmi[hdmi_level * 2 + i]);
+               I915_WRITE(reg, ddi_translations[i].trans2);
                reg += 4;
        }
+
+       /* Choose a good default if VBT is badly populated */
+       if (hdmi_level == HDMI_LEVEL_SHIFT_UNKNOWN ||
+           hdmi_level >= n_hdmi_entries)
+               hdmi_level = hdmi_800mV_0dB;
+
+       /* Entry 9 is for HDMI: */
+       I915_WRITE(reg, ddi_translations_hdmi[hdmi_level].trans1);
+       reg += 4;
+       I915_WRITE(reg, ddi_translations_hdmi[hdmi_level].trans2);
+       reg += 4;
 }
 
 /* Program DDI buffers translations for DP. By default, program ports A-D in DP
@@ -214,18 +248,6 @@ void intel_prepare_ddi(struct drm_device *dev)
                intel_prepare_ddi_buffers(dev, port);
 }
 
-static const long hsw_ddi_buf_ctl_values[] = {
-       DDI_BUF_EMP_400MV_0DB_HSW,
-       DDI_BUF_EMP_400MV_3_5DB_HSW,
-       DDI_BUF_EMP_400MV_6DB_HSW,
-       DDI_BUF_EMP_400MV_9_5DB_HSW,
-       DDI_BUF_EMP_600MV_0DB_HSW,
-       DDI_BUF_EMP_600MV_3_5DB_HSW,
-       DDI_BUF_EMP_600MV_6DB_HSW,
-       DDI_BUF_EMP_800MV_0DB_HSW,
-       DDI_BUF_EMP_800MV_3_5DB_HSW
-};
-
 static void intel_wait_ddi_buf_idle(struct drm_i915_private *dev_priv,
                                    enum port port)
 {
@@ -285,7 +307,7 @@ void hsw_fdi_link_train(struct drm_crtc *crtc)
 
        /* Start the training iterating through available voltages and emphasis,
         * testing each value twice. */
-       for (i = 0; i < ARRAY_SIZE(hsw_ddi_buf_ctl_values) * 2; i++) {
+       for (i = 0; i < ARRAY_SIZE(hsw_ddi_translations_fdi) * 2; i++) {
                /* Configure DP_TP_CTL with auto-training */
                I915_WRITE(DP_TP_CTL(PORT_E),
                                        DP_TP_CTL_FDI_AUTOTRAIN |
@@ -300,7 +322,7 @@ void hsw_fdi_link_train(struct drm_crtc *crtc)
                I915_WRITE(DDI_BUF_CTL(PORT_E),
                           DDI_BUF_CTL_ENABLE |
                           ((intel_crtc->config.fdi_lanes - 1) << 1) |
-                          hsw_ddi_buf_ctl_values[i / 2]);
+                          DDI_BUF_TRANS_SELECT(i / 2));
                POSTING_READ(DDI_BUF_CTL(PORT_E));
 
                udelay(600);
@@ -375,7 +397,7 @@ void intel_ddi_init_dp_buf_reg(struct intel_encoder *encoder)
                enc_to_dig_port(&encoder->base);
 
        intel_dp->DP = intel_dig_port->saved_port_bits |
-               DDI_BUF_CTL_ENABLE | DDI_BUF_EMP_400MV_0DB_HSW;
+               DDI_BUF_CTL_ENABLE | DDI_BUF_TRANS_SELECT(0);
        intel_dp->DP |= DDI_PORT_WIDTH(intel_dp->lane_count);
 
 }
@@ -402,7 +424,7 @@ intel_ddi_get_crtc_encoder(struct drm_crtc *crtc)
 }
 
 #define LC_FREQ 2700
-#define LC_FREQ_2K (LC_FREQ * 2000)
+#define LC_FREQ_2K U64_C(LC_FREQ * 2000)
 
 #define P_MIN 2
 #define P_MAX 64
@@ -414,7 +436,11 @@ intel_ddi_get_crtc_encoder(struct drm_crtc *crtc)
 #define VCO_MIN 2400
 #define VCO_MAX 4800
 
-#define ABS_DIFF(a, b) ((a > b) ? (a - b) : (b - a))
+#define abs_diff(a, b) ({                      \
+       typeof(a) __a = (a);                    \
+       typeof(b) __b = (b);                    \
+       (void) (&__a == &__b);                  \
+       __a > __b ? (__a - __b) : (__b - __a); })
 
 struct wrpll_rnp {
        unsigned p, n2, r2;
@@ -524,9 +550,9 @@ static void wrpll_update_rnp(uint64_t freq2k, unsigned budget,
         */
        a = freq2k * budget * p * r2;
        b = freq2k * budget * best->p * best->r2;
-       diff = ABS_DIFF((freq2k * p * r2), (LC_FREQ_2K * n2));
-       diff_best = ABS_DIFF((freq2k * best->p * best->r2),
-                            (LC_FREQ_2K * best->n2));
+       diff = abs_diff(freq2k * p * r2, LC_FREQ_2K * n2);
+       diff_best = abs_diff(freq2k * best->p * best->r2,
+                            LC_FREQ_2K * best->n2);
        c = 1000000 * diff;
        d = 1000000 * diff_best;
 
@@ -587,8 +613,8 @@ static int intel_ddi_calc_wrpll_link(struct drm_i915_private *dev_priv,
        return (refclk * n * 100) / (p * r);
 }
 
-void intel_ddi_clock_get(struct intel_encoder *encoder,
-                        struct intel_crtc_config *pipe_config)
+static void hsw_ddi_clock_get(struct intel_encoder *encoder,
+                             struct intel_crtc_config *pipe_config)
 {
        struct drm_i915_private *dev_priv = encoder->base.dev->dev_private;
        int link_clock = 0;
@@ -643,9 +669,15 @@ void intel_ddi_clock_get(struct intel_encoder *encoder,
                pipe_config->adjusted_mode.crtc_clock = pipe_config->port_clock;
 }
 
+void intel_ddi_clock_get(struct intel_encoder *encoder,
+                        struct intel_crtc_config *pipe_config)
+{
+       hsw_ddi_clock_get(encoder, pipe_config);
+}
+
 static void
-intel_ddi_calculate_wrpll(int clock /* in Hz */,
-                         unsigned *r2_out, unsigned *n2_out, unsigned *p_out)
+hsw_ddi_calculate_wrpll(int clock /* in Hz */,
+                       unsigned *r2_out, unsigned *n2_out, unsigned *p_out)
 {
        uint64_t freq2k;
        unsigned p, n2, r2;
@@ -708,27 +740,17 @@ intel_ddi_calculate_wrpll(int clock /* in Hz */,
        *r2_out = best.r2;
 }
 
-/*
- * Tries to find a PLL for the CRTC. If it finds, it increases the refcount and
- * stores it in intel_crtc->ddi_pll_sel, so other mode sets won't be able to
- * steal the selected PLL. You need to call intel_ddi_pll_enable to actually
- * enable the PLL.
- */
-bool intel_ddi_pll_select(struct intel_crtc *intel_crtc)
+static bool
+hsw_ddi_pll_select(struct intel_crtc *intel_crtc,
+                  struct intel_encoder *intel_encoder,
+                  int clock)
 {
-       struct drm_crtc *crtc = &intel_crtc->base;
-       struct intel_encoder *intel_encoder = intel_ddi_get_crtc_encoder(crtc);
-       int type = intel_encoder->type;
-       int clock = intel_crtc->config.port_clock;
-
-       intel_put_shared_dpll(intel_crtc);
-
-       if (type == INTEL_OUTPUT_HDMI) {
+       if (intel_encoder->type == INTEL_OUTPUT_HDMI) {
                struct intel_shared_dpll *pll;
                uint32_t val;
                unsigned p, n2, r2;
 
-               intel_ddi_calculate_wrpll(clock * 1000, &r2, &n2, &p);
+               hsw_ddi_calculate_wrpll(clock * 1000, &r2, &n2, &p);
 
                val = WRPLL_PLL_ENABLE | WRPLL_PLL_LCPLL |
                      WRPLL_DIVIDER_REFERENCE(r2) | WRPLL_DIVIDER_FEEDBACK(n2) |
@@ -749,6 +771,25 @@ bool intel_ddi_pll_select(struct intel_crtc *intel_crtc)
        return true;
 }
 
+
+/*
+ * Tries to find a *shared* PLL for the CRTC and store it in
+ * intel_crtc->ddi_pll_sel.
+ *
+ * For private DPLLs, compute_config() should do the selection for us. This
+ * function should be folded into compute_config() eventually.
+ */
+bool intel_ddi_pll_select(struct intel_crtc *intel_crtc)
+{
+       struct drm_crtc *crtc = &intel_crtc->base;
+       struct intel_encoder *intel_encoder = intel_ddi_get_crtc_encoder(crtc);
+       int clock = intel_crtc->config.port_clock;
+
+       intel_put_shared_dpll(intel_crtc);
+
+       return hsw_ddi_pll_select(intel_crtc, intel_encoder, clock);
+}
+
 void intel_ddi_set_pipe_settings(struct drm_crtc *crtc)
 {
        struct drm_i915_private *dev_priv = crtc->dev->dev_private;
@@ -1183,31 +1224,52 @@ static void intel_disable_ddi(struct intel_encoder *intel_encoder)
        }
 }
 
-int intel_ddi_get_cdclk_freq(struct drm_i915_private *dev_priv)
+static int bdw_get_cdclk_freq(struct drm_i915_private *dev_priv)
+{
+       uint32_t lcpll = I915_READ(LCPLL_CTL);
+       uint32_t freq = lcpll & LCPLL_CLK_FREQ_MASK;
+
+       if (lcpll & LCPLL_CD_SOURCE_FCLK)
+               return 800000;
+       else if (I915_READ(FUSE_STRAP) & HSW_CDCLK_LIMIT)
+               return 450000;
+       else if (freq == LCPLL_CLK_FREQ_450)
+               return 450000;
+       else if (freq == LCPLL_CLK_FREQ_54O_BDW)
+               return 540000;
+       else if (freq == LCPLL_CLK_FREQ_337_5_BDW)
+               return 337500;
+       else
+               return 675000;
+}
+
+static int hsw_get_cdclk_freq(struct drm_i915_private *dev_priv)
 {
        struct drm_device *dev = dev_priv->dev;
        uint32_t lcpll = I915_READ(LCPLL_CTL);
        uint32_t freq = lcpll & LCPLL_CLK_FREQ_MASK;
 
-       if (lcpll & LCPLL_CD_SOURCE_FCLK) {
+       if (lcpll & LCPLL_CD_SOURCE_FCLK)
                return 800000;
-       } else if (I915_READ(FUSE_STRAP) & HSW_CDCLK_LIMIT) {
+       else if (I915_READ(FUSE_STRAP) & HSW_CDCLK_LIMIT)
                return 450000;
-       } else if (freq == LCPLL_CLK_FREQ_450) {
+       else if (freq == LCPLL_CLK_FREQ_450)
                return 450000;
-       } else if (IS_HASWELL(dev)) {
-               if (IS_ULT(dev))
-                       return 337500;
-               else
-                       return 540000;
-       } else {
-               if (freq == LCPLL_CLK_FREQ_54O_BDW)
-                       return 540000;
-               else if (freq == LCPLL_CLK_FREQ_337_5_BDW)
-                       return 337500;
-               else
-                       return 675000;
-       }
+       else if (IS_ULT(dev))
+               return 337500;
+       else
+               return 540000;
+}
+
+int intel_ddi_get_cdclk_freq(struct drm_i915_private *dev_priv)
+{
+       struct drm_device *dev = dev_priv->dev;
+
+       if (IS_BROADWELL(dev))
+               return bdw_get_cdclk_freq(dev_priv);
+
+       /* Haswell */
+       return hsw_get_cdclk_freq(dev_priv);
 }
 
 static void hsw_ddi_pll_enable(struct drm_i915_private *dev_priv,
@@ -1248,10 +1310,8 @@ static const char * const hsw_ddi_pll_names[] = {
        "WRPLL 2",
 };
 
-void intel_ddi_pll_init(struct drm_device *dev)
+static void hsw_shared_dplls_init(struct drm_i915_private *dev_priv)
 {
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       uint32_t val = I915_READ(LCPLL_CTL);
        int i;
 
        dev_priv->num_shared_dpll = 2;
@@ -1264,6 +1324,14 @@ void intel_ddi_pll_init(struct drm_device *dev)
                dev_priv->shared_dplls[i].get_hw_state =
                        hsw_ddi_pll_get_hw_state;
        }
+}
+
+void intel_ddi_pll_init(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       uint32_t val = I915_READ(LCPLL_CTL);
+
+       hsw_shared_dplls_init(dev_priv);
 
        /* The LCPLL register should be turned on by the BIOS. For now let's
         * just check its state and print errors in case something is wrong.
@@ -1444,7 +1512,7 @@ void intel_ddi_get_config(struct intel_encoder *encoder,
                dev_priv->vbt.edp_bpp = pipe_config->pipe_bpp;
        }
 
-       intel_ddi_clock_get(encoder, pipe_config);
+       hsw_ddi_clock_get(encoder, pipe_config);
 }
 
 static void intel_ddi_destroy(struct drm_encoder *encoder)
index d8324c69fa868de2364cf1b272426f5a634c5c31..507370513f3d2e8494f4d4ad89fe265b0128e295 100644 (file)
@@ -91,15 +91,16 @@ static int intel_framebuffer_init(struct drm_device *dev,
                                  struct intel_framebuffer *ifb,
                                  struct drm_mode_fb_cmd2 *mode_cmd,
                                  struct drm_i915_gem_object *obj);
-static void intel_dp_set_m_n(struct intel_crtc *crtc);
 static void i9xx_set_pipeconf(struct intel_crtc *intel_crtc);
 static void intel_set_pipe_timings(struct intel_crtc *intel_crtc);
 static void intel_cpu_transcoder_set_m_n(struct intel_crtc *crtc,
-                                        struct intel_link_m_n *m_n);
+                                        struct intel_link_m_n *m_n,
+                                        struct intel_link_m_n *m2_n2);
 static void ironlake_set_pipeconf(struct drm_crtc *crtc);
 static void haswell_set_pipeconf(struct drm_crtc *crtc);
 static void intel_set_pipe_csc(struct drm_crtc *crtc);
 static void vlv_prepare_pll(struct intel_crtc *crtc);
+static void chv_prepare_pll(struct intel_crtc *crtc);
 
 static struct intel_encoder *intel_find_encoder(struct intel_connector *connector, int pipe)
 {
@@ -899,7 +900,8 @@ static void g4x_wait_for_vblank(struct drm_device *dev, int pipe)
        frame = I915_READ(frame_reg);
 
        if (wait_for(I915_READ_NOTRACE(frame_reg) != frame, 50))
-               WARN(1, "vblank wait timed out\n");
+               WARN(1, "vblank wait on pipe %c timed out\n",
+                    pipe_name(pipe));
 }
 
 /**
@@ -940,7 +942,8 @@ void intel_wait_for_vblank(struct drm_device *dev, int pipe)
        if (wait_for(I915_READ(pipestat_reg) &
                     PIPE_VBLANK_INTERRUPT_STATUS,
                     50))
-               DRM_DEBUG_KMS("vblank wait timed out\n");
+               DRM_DEBUG_KMS("vblank wait on pipe %c timed out\n",
+                             pipe_name(pipe));
 }
 
 static bool pipe_dsl_stopped(struct drm_device *dev, enum pipe pipe)
@@ -964,8 +967,7 @@ static bool pipe_dsl_stopped(struct drm_device *dev, enum pipe pipe)
 
 /*
  * intel_wait_for_pipe_off - wait for pipe to turn off
- * @dev: drm device
- * @pipe: pipe to wait for
+ * @crtc: crtc whose pipe to wait for
  *
  * After disabling a pipe, we can't wait for vblank in the usual way,
  * spinning on the vblank interrupt status bit, since we won't actually
@@ -979,11 +981,12 @@ static bool pipe_dsl_stopped(struct drm_device *dev, enum pipe pipe)
  *   ends up stopping at the start of the next frame).
  *
  */
-void intel_wait_for_pipe_off(struct drm_device *dev, int pipe)
+static void intel_wait_for_pipe_off(struct intel_crtc *crtc)
 {
+       struct drm_device *dev = crtc->base.dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
-       enum transcoder cpu_transcoder = intel_pipe_to_cpu_transcoder(dev_priv,
-                                                                     pipe);
+       enum transcoder cpu_transcoder = crtc->config.cpu_transcoder;
+       enum pipe pipe = crtc->pipe;
 
        if (INTEL_INFO(dev)->gen >= 4) {
                int reg = PIPECONF(cpu_transcoder);
@@ -1192,27 +1195,40 @@ void assert_fdi_rx_pll(struct drm_i915_private *dev_priv,
 static void assert_panel_unlocked(struct drm_i915_private *dev_priv,
                                  enum pipe pipe)
 {
-       int pp_reg, lvds_reg;
+       struct drm_device *dev = dev_priv->dev;
+       int pp_reg;
        u32 val;
        enum pipe panel_pipe = PIPE_A;
        bool locked = true;
 
-       if (HAS_PCH_SPLIT(dev_priv->dev)) {
+       if (WARN_ON(HAS_DDI(dev)))
+               return;
+
+       if (HAS_PCH_SPLIT(dev)) {
+               u32 port_sel;
+
                pp_reg = PCH_PP_CONTROL;
-               lvds_reg = PCH_LVDS;
+               port_sel = I915_READ(PCH_PP_ON_DELAYS) & PANEL_PORT_SELECT_MASK;
+
+               if (port_sel == PANEL_PORT_SELECT_LVDS &&
+                   I915_READ(PCH_LVDS) & LVDS_PIPEB_SELECT)
+                       panel_pipe = PIPE_B;
+               /* XXX: else fix for eDP */
+       } else if (IS_VALLEYVIEW(dev)) {
+               /* presumably write lock depends on pipe, not port select */
+               pp_reg = VLV_PIPE_PP_CONTROL(pipe);
+               panel_pipe = pipe;
        } else {
                pp_reg = PP_CONTROL;
-               lvds_reg = LVDS;
+               if (I915_READ(LVDS) & LVDS_PIPEB_SELECT)
+                       panel_pipe = PIPE_B;
        }
 
        val = I915_READ(pp_reg);
        if (!(val & PANEL_POWER_ON) ||
-           ((val & PANEL_UNLOCK_REGS) == PANEL_UNLOCK_REGS))
+           ((val & PANEL_UNLOCK_MASK) == PANEL_UNLOCK_REGS))
                locked = false;
 
-       if (I915_READ(lvds_reg) & LVDS_PIPEB_SELECT)
-               panel_pipe = PIPE_B;
-
        WARN(panel_pipe == pipe && locked,
             "panel assertion failure, pipe %c regs locked\n",
             pipe_name(pipe));
@@ -1245,8 +1261,9 @@ void assert_pipe(struct drm_i915_private *dev_priv,
        enum transcoder cpu_transcoder = intel_pipe_to_cpu_transcoder(dev_priv,
                                                                      pipe);
 
-       /* if we need the pipe A quirk it must be always on */
-       if (pipe == PIPE_A && dev_priv->quirks & QUIRK_PIPEA_FORCE)
+       /* if we need the pipe quirk it must be always on */
+       if ((pipe == PIPE_A && dev_priv->quirks & QUIRK_PIPEA_FORCE) ||
+           (pipe == PIPE_B && dev_priv->quirks & QUIRK_PIPEB_FORCE))
                state = true;
 
        if (!intel_display_power_enabled(dev_priv,
@@ -1300,7 +1317,7 @@ static void assert_planes_disabled(struct drm_i915_private *dev_priv,
        }
 
        /* Need to check both planes against the pipe */
-       for_each_pipe(i) {
+       for_each_pipe(dev_priv, i) {
                reg = DSPCNTR(i);
                val = I915_READ(reg);
                cur_pipe = (val & DISPPLANE_SEL_PIPE_MASK) >>
@@ -1341,6 +1358,12 @@ static void assert_sprites_disabled(struct drm_i915_private *dev_priv,
        }
 }
 
+static void assert_vblank_disabled(struct drm_crtc *crtc)
+{
+       if (WARN_ON(drm_crtc_vblank_get(crtc) == 0))
+               drm_crtc_vblank_put(crtc);
+}
+
 static void ibx_assert_pch_refclk_enabled(struct drm_i915_private *dev_priv)
 {
        u32 val;
@@ -1513,34 +1536,6 @@ static void intel_init_dpio(struct drm_device *dev)
        }
 }
 
-static void intel_reset_dpio(struct drm_device *dev)
-{
-       struct drm_i915_private *dev_priv = dev->dev_private;
-
-       if (IS_CHERRYVIEW(dev)) {
-               enum dpio_phy phy;
-               u32 val;
-
-               for (phy = DPIO_PHY0; phy < I915_NUM_PHYS_VLV; phy++) {
-                       /* Poll for phypwrgood signal */
-                       if (wait_for(I915_READ(DISPLAY_PHY_STATUS) &
-                                               PHY_POWERGOOD(phy), 1))
-                               DRM_ERROR("Display PHY %d is not power up\n", phy);
-
-                       /*
-                        * Deassert common lane reset for PHY.
-                        *
-                        * This should only be done on init and resume from S3
-                        * with both PLLs disabled, or we risk losing DPIO and
-                        * PLL synchronization.
-                        */
-                       val = I915_READ(DISPLAY_PHY_CONTROL);
-                       I915_WRITE(DISPLAY_PHY_CONTROL,
-                               PHY_COM_LANE_RESET_DEASSERT(phy, val));
-               }
-       }
-}
-
 static void vlv_enable_pll(struct intel_crtc *crtc)
 {
        struct drm_device *dev = crtc->base.dev;
@@ -1554,7 +1549,7 @@ static void vlv_enable_pll(struct intel_crtc *crtc)
        BUG_ON(!IS_VALLEYVIEW(dev_priv->dev));
 
        /* PLL is protected by panel, make sure we can write it */
-       if (IS_MOBILE(dev_priv->dev) && !IS_I830(dev_priv->dev))
+       if (IS_MOBILE(dev_priv->dev))
                assert_panel_unlocked(dev_priv, crtc->pipe);
 
        I915_WRITE(reg, dpll);
@@ -1617,6 +1612,18 @@ static void chv_enable_pll(struct intel_crtc *crtc)
        mutex_unlock(&dev_priv->dpio_lock);
 }
 
+static int intel_num_dvo_pipes(struct drm_device *dev)
+{
+       struct intel_crtc *crtc;
+       int count = 0;
+
+       for_each_intel_crtc(dev, crtc)
+               count += crtc->active &&
+                       intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_DVO);
+
+       return count;
+}
+
 static void i9xx_enable_pll(struct intel_crtc *crtc)
 {
        struct drm_device *dev = crtc->base.dev;
@@ -1633,7 +1640,18 @@ static void i9xx_enable_pll(struct intel_crtc *crtc)
        if (IS_MOBILE(dev) && !IS_I830(dev))
                assert_panel_unlocked(dev_priv, crtc->pipe);
 
-       I915_WRITE(reg, dpll);
+       /* Enable DVO 2x clock on both PLLs if necessary */
+       if (IS_I830(dev) && intel_num_dvo_pipes(dev) > 0) {
+               /*
+                * It appears to be important that we don't enable this
+                * for the current pipe before otherwise configuring the
+                * PLL. No idea how this should be handled if multiple
+                * DVO outputs are enabled simultaneosly.
+                */
+               dpll |= DPLL_DVO_2X_MODE;
+               I915_WRITE(DPLL(!crtc->pipe),
+                          I915_READ(DPLL(!crtc->pipe)) | DPLL_DVO_2X_MODE);
+       }
 
        /* Wait for the clocks to stabilize. */
        POSTING_READ(reg);
@@ -1672,10 +1690,25 @@ static void i9xx_enable_pll(struct intel_crtc *crtc)
  *
  * Note!  This is for pre-ILK only.
  */
-static void i9xx_disable_pll(struct drm_i915_private *dev_priv, enum pipe pipe)
+static void i9xx_disable_pll(struct intel_crtc *crtc)
 {
-       /* Don't disable pipe A or pipe A PLLs if needed */
-       if (pipe == PIPE_A && (dev_priv->quirks & QUIRK_PIPEA_FORCE))
+       struct drm_device *dev = crtc->base.dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       enum pipe pipe = crtc->pipe;
+
+       /* Disable DVO 2x clock on both PLLs if necessary */
+       if (IS_I830(dev) &&
+           intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_DVO) &&
+           intel_num_dvo_pipes(dev) == 1) {
+               I915_WRITE(DPLL(PIPE_B),
+                          I915_READ(DPLL(PIPE_B)) & ~DPLL_DVO_2X_MODE);
+               I915_WRITE(DPLL(PIPE_A),
+                          I915_READ(DPLL(PIPE_A)) & ~DPLL_DVO_2X_MODE);
+       }
+
+       /* Don't disable pipe or pipe PLLs if needed */
+       if ((pipe == PIPE_A && dev_priv->quirks & QUIRK_PIPEA_FORCE) ||
+           (pipe == PIPE_B && dev_priv->quirks & QUIRK_PIPEB_FORCE))
                return;
 
        /* Make sure the pipe isn't still relying on us */
@@ -1712,7 +1745,7 @@ static void chv_disable_pll(struct drm_i915_private *dev_priv, enum pipe pipe)
        assert_pipe_disabled(dev_priv, pipe);
 
        /* Set PLL en = 0 */
-       val = DPLL_SSC_REF_CLOCK_CHV;
+       val = DPLL_SSC_REF_CLOCK_CHV | DPLL_REFA_CLK_ENABLE_VLV;
        if (pipe != PIPE_A)
                val |= DPLL_INTEGRATED_CRI_CLK_VLV;
        I915_WRITE(DPLL(pipe), val);
@@ -1806,7 +1839,7 @@ static void intel_enable_shared_dpll(struct intel_crtc *crtc)
        if (WARN_ON(pll->refcount == 0))
                return;
 
-       DRM_DEBUG_KMS("enable %s (active %d, on? %d)for crtc %d\n",
+       DRM_DEBUG_KMS("enable %s (active %d, on? %d) for crtc %d\n",
                      pll->name, pll->active, pll->on,
                      crtc->base.base.id);
 
@@ -1824,7 +1857,7 @@ static void intel_enable_shared_dpll(struct intel_crtc *crtc)
        pll->on = true;
 }
 
-void intel_disable_shared_dpll(struct intel_crtc *crtc)
+static void intel_disable_shared_dpll(struct intel_crtc *crtc)
 {
        struct drm_device *dev = crtc->base.dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
@@ -1868,7 +1901,7 @@ static void ironlake_enable_pch_transcoder(struct drm_i915_private *dev_priv,
        uint32_t reg, val, pipeconf_val;
 
        /* PCH only available on ILK+ */
-       BUG_ON(INTEL_INFO(dev)->gen < 5);
+       BUG_ON(!HAS_PCH_SPLIT(dev));
 
        /* Make sure PCH DPLL is enabled */
        assert_shared_dpll_enabled(dev_priv,
@@ -1921,7 +1954,7 @@ static void lpt_enable_pch_transcoder(struct drm_i915_private *dev_priv,
        u32 val, pipeconf_val;
 
        /* PCH only available on ILK+ */
-       BUG_ON(INTEL_INFO(dev_priv->dev)->gen < 5);
+       BUG_ON(!HAS_PCH_SPLIT(dev_priv->dev));
 
        /* FDI must be feeding us bits for PCH ports */
        assert_fdi_tx_enabled(dev_priv, (enum pipe) cpu_transcoder);
@@ -2043,8 +2076,8 @@ static void intel_enable_pipe(struct intel_crtc *crtc)
        reg = PIPECONF(cpu_transcoder);
        val = I915_READ(reg);
        if (val & PIPECONF_ENABLE) {
-               WARN_ON(!(pipe == PIPE_A &&
-                         dev_priv->quirks & QUIRK_PIPEA_FORCE));
+               WARN_ON(!((pipe == PIPE_A && dev_priv->quirks & QUIRK_PIPEA_FORCE) ||
+                         (pipe == PIPE_B && dev_priv->quirks & QUIRK_PIPEB_FORCE)));
                return;
        }
 
@@ -2054,21 +2087,19 @@ static void intel_enable_pipe(struct intel_crtc *crtc)
 
 /**
  * intel_disable_pipe - disable a pipe, asserting requirements
- * @dev_priv: i915 private structure
- * @pipe: pipe to disable
+ * @crtc: crtc whose pipes is to be disabled
  *
- * Disable @pipe, making sure that various hardware specific requirements
- * are met, if applicable, e.g. plane disabled, panel fitter off, etc.
- *
- * @pipe should be %PIPE_A or %PIPE_B.
+ * Disable the pipe of @crtc, making sure that various hardware
+ * specific requirements are met, if applicable, e.g. plane
+ * disabled, panel fitter off, etc.
  *
  * Will wait until the pipe has shut down before returning.
  */
-static void intel_disable_pipe(struct drm_i915_private *dev_priv,
-                              enum pipe pipe)
+static void intel_disable_pipe(struct intel_crtc *crtc)
 {
-       enum transcoder cpu_transcoder = intel_pipe_to_cpu_transcoder(dev_priv,
-                                                                     pipe);
+       struct drm_i915_private *dev_priv = crtc->base.dev->dev_private;
+       enum transcoder cpu_transcoder = crtc->config.cpu_transcoder;
+       enum pipe pipe = crtc->pipe;
        int reg;
        u32 val;
 
@@ -2080,17 +2111,26 @@ static void intel_disable_pipe(struct drm_i915_private *dev_priv,
        assert_cursor_disabled(dev_priv, pipe);
        assert_sprites_disabled(dev_priv, pipe);
 
-       /* Don't disable pipe A or pipe A PLLs if needed */
-       if (pipe == PIPE_A && (dev_priv->quirks & QUIRK_PIPEA_FORCE))
-               return;
-
        reg = PIPECONF(cpu_transcoder);
        val = I915_READ(reg);
        if ((val & PIPECONF_ENABLE) == 0)
                return;
 
-       I915_WRITE(reg, val & ~PIPECONF_ENABLE);
-       intel_wait_for_pipe_off(dev_priv->dev, pipe);
+       /*
+        * Double wide has implications for planes
+        * so best keep it disabled when not needed.
+        */
+       if (crtc->config.double_wide)
+               val &= ~PIPECONF_DOUBLE_WIDE;
+
+       /* Don't disable pipe or pipe PLLs if needed */
+       if (!(pipe == PIPE_A && dev_priv->quirks & QUIRK_PIPEA_FORCE) &&
+           !(pipe == PIPE_B && dev_priv->quirks & QUIRK_PIPEB_FORCE))
+               val &= ~PIPECONF_ENABLE;
+
+       I915_WRITE(reg, val);
+       if ((val & PIPECONF_ENABLE) == 0)
+               intel_wait_for_pipe_off(crtc);
 }
 
 /*
@@ -2109,35 +2149,28 @@ void intel_flush_primary_plane(struct drm_i915_private *dev_priv,
 
 /**
  * intel_enable_primary_hw_plane - enable the primary plane on a given pipe
- * @dev_priv: i915 private structure
- * @plane: plane to enable
- * @pipe: pipe being fed
+ * @plane:  plane to be enabled
+ * @crtc: crtc for the plane
  *
- * Enable @plane on @pipe, making sure that @pipe is running first.
+ * Enable @plane on @crtc, making sure that the pipe is running first.
  */
-static void intel_enable_primary_hw_plane(struct drm_i915_private *dev_priv,
-                                         enum plane plane, enum pipe pipe)
+static void intel_enable_primary_hw_plane(struct drm_plane *plane,
+                                         struct drm_crtc *crtc)
 {
-       struct drm_device *dev = dev_priv->dev;
-       struct intel_crtc *intel_crtc =
-               to_intel_crtc(dev_priv->pipe_to_crtc_mapping[pipe]);
-       int reg;
-       u32 val;
+       struct drm_device *dev = plane->dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
 
        /* If the pipe isn't enabled, we can't pump pixels and may hang */
-       assert_pipe_enabled(dev_priv, pipe);
+       assert_pipe_enabled(dev_priv, intel_crtc->pipe);
 
        if (intel_crtc->primary_enabled)
                return;
 
        intel_crtc->primary_enabled = true;
 
-       reg = DSPCNTR(plane);
-       val = I915_READ(reg);
-       WARN_ON(val & DISPLAY_PLANE_ENABLE);
-
-       I915_WRITE(reg, val | DISPLAY_PLANE_ENABLE);
-       intel_flush_primary_plane(dev_priv, plane);
+       dev_priv->display.update_primary_plane(crtc, plane->fb,
+                                              crtc->x, crtc->y);
 
        /*
         * BDW signals flip done immediately if the plane
@@ -2150,31 +2183,27 @@ static void intel_enable_primary_hw_plane(struct drm_i915_private *dev_priv,
 
 /**
  * intel_disable_primary_hw_plane - disable the primary hardware plane
- * @dev_priv: i915 private structure
- * @plane: plane to disable
- * @pipe: pipe consuming the data
+ * @plane: plane to be disabled
+ * @crtc: crtc for the plane
  *
- * Disable @plane; should be an independent operation.
+ * Disable @plane on @crtc, making sure that the pipe is running first.
  */
-static void intel_disable_primary_hw_plane(struct drm_i915_private *dev_priv,
-                                          enum plane plane, enum pipe pipe)
+static void intel_disable_primary_hw_plane(struct drm_plane *plane,
+                                          struct drm_crtc *crtc)
 {
-       struct intel_crtc *intel_crtc =
-               to_intel_crtc(dev_priv->pipe_to_crtc_mapping[pipe]);
-       int reg;
-       u32 val;
+       struct drm_device *dev = plane->dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+
+       assert_pipe_enabled(dev_priv, intel_crtc->pipe);
 
        if (!intel_crtc->primary_enabled)
                return;
 
        intel_crtc->primary_enabled = false;
 
-       reg = DSPCNTR(plane);
-       val = I915_READ(reg);
-       WARN_ON((val & DISPLAY_PLANE_ENABLE) == 0);
-
-       I915_WRITE(reg, val & ~DISPLAY_PLANE_ENABLE);
-       intel_flush_primary_plane(dev_priv, plane);
+       dev_priv->display.update_primary_plane(crtc, plane->fb,
+                                              crtc->x, crtc->y);
 }
 
 static bool need_vtd_wa(struct drm_device *dev)
@@ -2422,16 +2451,46 @@ static void i9xx_update_primary_plane(struct drm_crtc *crtc,
        struct drm_device *dev = crtc->dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-       struct drm_i915_gem_object *obj = intel_fb_obj(fb);
+       struct drm_i915_gem_object *obj;
        int plane = intel_crtc->plane;
        unsigned long linear_offset;
        u32 dspcntr;
-       u32 reg;
+       u32 reg = DSPCNTR(plane);
+       int pixel_size;
+
+       if (!intel_crtc->primary_enabled) {
+               I915_WRITE(reg, 0);
+               if (INTEL_INFO(dev)->gen >= 4)
+                       I915_WRITE(DSPSURF(plane), 0);
+               else
+                       I915_WRITE(DSPADDR(plane), 0);
+               POSTING_READ(reg);
+               return;
+       }
+
+       obj = intel_fb_obj(fb);
+       if (WARN_ON(obj == NULL))
+               return;
+
+       pixel_size = drm_format_plane_cpp(fb->pixel_format, 0);
+
+       dspcntr = DISPPLANE_GAMMA_ENABLE;
+
+       dspcntr |= DISPLAY_PLANE_ENABLE;
+
+       if (INTEL_INFO(dev)->gen < 4) {
+               if (intel_crtc->pipe == PIPE_B)
+                       dspcntr |= DISPPLANE_SEL_PIPE_B;
+
+               /* pipesrc and dspsize control the size that is scaled from,
+                * which should always be the user's requested size.
+                */
+               I915_WRITE(DSPSIZE(plane),
+                          ((intel_crtc->config.pipe_src_h - 1) << 16) |
+                          (intel_crtc->config.pipe_src_w - 1));
+               I915_WRITE(DSPPOS(plane), 0);
+       }
 
-       reg = DSPCNTR(plane);
-       dspcntr = I915_READ(reg);
-       /* Mask out pixel format bits in case we change it */
-       dspcntr &= ~DISPPLANE_PIXFORMAT_MASK;
        switch (fb->pixel_format) {
        case DRM_FORMAT_C8:
                dspcntr |= DISPPLANE_8BPP;
@@ -2463,30 +2522,40 @@ static void i9xx_update_primary_plane(struct drm_crtc *crtc,
                BUG();
        }
 
-       if (INTEL_INFO(dev)->gen >= 4) {
-               if (obj->tiling_mode != I915_TILING_NONE)
-                       dspcntr |= DISPPLANE_TILED;
-               else
-                       dspcntr &= ~DISPPLANE_TILED;
-       }
+       if (INTEL_INFO(dev)->gen >= 4 &&
+           obj->tiling_mode != I915_TILING_NONE)
+               dspcntr |= DISPPLANE_TILED;
 
        if (IS_G4X(dev))
                dspcntr |= DISPPLANE_TRICKLE_FEED_DISABLE;
 
-       I915_WRITE(reg, dspcntr);
-
-       linear_offset = y * fb->pitches[0] + x * (fb->bits_per_pixel / 8);
+       linear_offset = y * fb->pitches[0] + x * pixel_size;
 
        if (INTEL_INFO(dev)->gen >= 4) {
                intel_crtc->dspaddr_offset =
                        intel_gen4_compute_page_offset(&x, &y, obj->tiling_mode,
-                                                      fb->bits_per_pixel / 8,
+                                                      pixel_size,
                                                       fb->pitches[0]);
                linear_offset -= intel_crtc->dspaddr_offset;
        } else {
                intel_crtc->dspaddr_offset = linear_offset;
        }
 
+       if (to_intel_plane(crtc->primary)->rotation == BIT(DRM_ROTATE_180)) {
+               dspcntr |= DISPPLANE_ROTATE_180;
+
+               x += (intel_crtc->config.pipe_src_w - 1);
+               y += (intel_crtc->config.pipe_src_h - 1);
+
+               /* Finding the last pixel of the last line of the display
+               data and adding to linear_offset*/
+               linear_offset +=
+                       (intel_crtc->config.pipe_src_h - 1) * fb->pitches[0] +
+                       (intel_crtc->config.pipe_src_w - 1) * pixel_size;
+       }
+
+       I915_WRITE(reg, dspcntr);
+
        DRM_DEBUG_KMS("Writing base %08lX %08lX %d %d %d\n",
                      i915_gem_obj_ggtt_offset(obj), linear_offset, x, y,
                      fb->pitches[0]);
@@ -2508,16 +2577,33 @@ static void ironlake_update_primary_plane(struct drm_crtc *crtc,
        struct drm_device *dev = crtc->dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-       struct drm_i915_gem_object *obj = intel_fb_obj(fb);
+       struct drm_i915_gem_object *obj;
        int plane = intel_crtc->plane;
        unsigned long linear_offset;
        u32 dspcntr;
-       u32 reg;
+       u32 reg = DSPCNTR(plane);
+       int pixel_size;
+
+       if (!intel_crtc->primary_enabled) {
+               I915_WRITE(reg, 0);
+               I915_WRITE(DSPSURF(plane), 0);
+               POSTING_READ(reg);
+               return;
+       }
+
+       obj = intel_fb_obj(fb);
+       if (WARN_ON(obj == NULL))
+               return;
+
+       pixel_size = drm_format_plane_cpp(fb->pixel_format, 0);
+
+       dspcntr = DISPPLANE_GAMMA_ENABLE;
+
+       dspcntr |= DISPLAY_PLANE_ENABLE;
+
+       if (IS_HASWELL(dev) || IS_BROADWELL(dev))
+               dspcntr |= DISPPLANE_PIPE_CSC_ENABLE;
 
-       reg = DSPCNTR(plane);
-       dspcntr = I915_READ(reg);
-       /* Mask out pixel format bits in case we change it */
-       dspcntr &= ~DISPPLANE_PIXFORMAT_MASK;
        switch (fb->pixel_format) {
        case DRM_FORMAT_C8:
                dspcntr |= DISPPLANE_8BPP;
@@ -2547,22 +2633,32 @@ static void ironlake_update_primary_plane(struct drm_crtc *crtc,
 
        if (obj->tiling_mode != I915_TILING_NONE)
                dspcntr |= DISPPLANE_TILED;
-       else
-               dspcntr &= ~DISPPLANE_TILED;
 
-       if (IS_HASWELL(dev) || IS_BROADWELL(dev))
-               dspcntr &= ~DISPPLANE_TRICKLE_FEED_DISABLE;
-       else
+       if (!IS_HASWELL(dev) && !IS_BROADWELL(dev))
                dspcntr |= DISPPLANE_TRICKLE_FEED_DISABLE;
 
-       I915_WRITE(reg, dspcntr);
-
-       linear_offset = y * fb->pitches[0] + x * (fb->bits_per_pixel / 8);
+       linear_offset = y * fb->pitches[0] + x * pixel_size;
        intel_crtc->dspaddr_offset =
                intel_gen4_compute_page_offset(&x, &y, obj->tiling_mode,
-                                              fb->bits_per_pixel / 8,
+                                              pixel_size,
                                               fb->pitches[0]);
        linear_offset -= intel_crtc->dspaddr_offset;
+       if (to_intel_plane(crtc->primary)->rotation == BIT(DRM_ROTATE_180)) {
+               dspcntr |= DISPPLANE_ROTATE_180;
+
+               if (!IS_HASWELL(dev) && !IS_BROADWELL(dev)) {
+                       x += (intel_crtc->config.pipe_src_w - 1);
+                       y += (intel_crtc->config.pipe_src_h - 1);
+
+                       /* Finding the last pixel of the last line of the display
+                       data and adding to linear_offset*/
+                       linear_offset +=
+                               (intel_crtc->config.pipe_src_h - 1) * fb->pitches[0] +
+                               (intel_crtc->config.pipe_src_w - 1) * pixel_size;
+               }
+       }
+
+       I915_WRITE(reg, dspcntr);
 
        DRM_DEBUG_KMS("Writing base %08lX %08lX %d %d %d\n",
                      i915_gem_obj_ggtt_offset(obj), linear_offset, x, y,
@@ -3346,23 +3442,54 @@ bool intel_has_pending_fb_unpin(struct drm_device *dev)
        return false;
 }
 
+static void page_flip_completed(struct intel_crtc *intel_crtc)
+{
+       struct drm_i915_private *dev_priv = to_i915(intel_crtc->base.dev);
+       struct intel_unpin_work *work = intel_crtc->unpin_work;
+
+       /* ensure that the unpin work is consistent wrt ->pending. */
+       smp_rmb();
+       intel_crtc->unpin_work = NULL;
+
+       if (work->event)
+               drm_send_vblank_event(intel_crtc->base.dev,
+                                     intel_crtc->pipe,
+                                     work->event);
+
+       drm_crtc_vblank_put(&intel_crtc->base);
+
+       wake_up_all(&dev_priv->pending_flip_queue);
+       queue_work(dev_priv->wq, &work->work);
+
+       trace_i915_flip_complete(intel_crtc->plane,
+                                work->pending_flip_obj);
+}
+
 void intel_crtc_wait_for_pending_flips(struct drm_crtc *crtc)
 {
        struct drm_device *dev = crtc->dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
 
-       if (crtc->primary->fb == NULL)
-               return;
-
        WARN_ON(waitqueue_active(&dev_priv->pending_flip_queue));
+       if (WARN_ON(wait_event_timeout(dev_priv->pending_flip_queue,
+                                      !intel_crtc_has_pending_flip(crtc),
+                                      60*HZ) == 0)) {
+               struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+               unsigned long flags;
 
-       WARN_ON(wait_event_timeout(dev_priv->pending_flip_queue,
-                                  !intel_crtc_has_pending_flip(crtc),
-                                  60*HZ) == 0);
+               spin_lock_irqsave(&dev->event_lock, flags);
+               if (intel_crtc->unpin_work) {
+                       WARN_ONCE(1, "Removing stuck page flip\n");
+                       page_flip_completed(intel_crtc);
+               }
+               spin_unlock_irqrestore(&dev->event_lock, flags);
+       }
 
-       mutex_lock(&dev->struct_mutex);
-       intel_finish_fb(crtc->primary->fb);
-       mutex_unlock(&dev->struct_mutex);
+       if (crtc->primary->fb) {
+               mutex_lock(&dev->struct_mutex);
+               intel_finish_fb(crtc->primary->fb);
+               mutex_unlock(&dev->struct_mutex);
+       }
 }
 
 /* Program iCLKIP clock to the desired frequency */
@@ -3911,14 +4038,14 @@ static void intel_crtc_dpms_overlay(struct intel_crtc *intel_crtc, bool enable)
 static void intel_crtc_enable_planes(struct drm_crtc *crtc)
 {
        struct drm_device *dev = crtc->dev;
-       struct drm_i915_private *dev_priv = dev->dev_private;
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
        int pipe = intel_crtc->pipe;
-       int plane = intel_crtc->plane;
+
+       assert_vblank_disabled(crtc);
 
        drm_vblank_on(dev, pipe);
 
-       intel_enable_primary_hw_plane(dev_priv, plane, pipe);
+       intel_enable_primary_hw_plane(crtc->primary, crtc);
        intel_enable_planes(crtc);
        intel_crtc_update_cursor(crtc, true);
        intel_crtc_dpms_overlay(intel_crtc, true);
@@ -3955,7 +4082,7 @@ static void intel_crtc_disable_planes(struct drm_crtc *crtc)
        intel_crtc_dpms_overlay(intel_crtc, false);
        intel_crtc_update_cursor(crtc, false);
        intel_disable_planes(crtc);
-       intel_disable_primary_hw_plane(dev_priv, plane, pipe);
+       intel_disable_primary_hw_plane(crtc->primary, crtc);
 
        /*
         * FIXME: Once we grow proper nuclear flip support out of this we need
@@ -3965,6 +4092,8 @@ static void intel_crtc_disable_planes(struct drm_crtc *crtc)
        intel_frontbuffer_flip(dev, INTEL_FRONTBUFFER_ALL_MASK(pipe));
 
        drm_vblank_off(dev, pipe);
+
+       assert_vblank_disabled(crtc);
 }
 
 static void ironlake_crtc_enable(struct drm_crtc *crtc)
@@ -3974,7 +4103,6 @@ static void ironlake_crtc_enable(struct drm_crtc *crtc)
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
        struct intel_encoder *encoder;
        int pipe = intel_crtc->pipe;
-       enum plane plane = intel_crtc->plane;
 
        WARN_ON(!crtc->enabled);
 
@@ -3991,18 +4119,11 @@ static void ironlake_crtc_enable(struct drm_crtc *crtc)
 
        if (intel_crtc->config.has_pch_encoder) {
                intel_cpu_transcoder_set_m_n(intel_crtc,
-                                            &intel_crtc->config.fdi_m_n);
+                                    &intel_crtc->config.fdi_m_n, NULL);
        }
 
        ironlake_set_pipeconf(crtc);
 
-       /* Set up the display plane register */
-       I915_WRITE(DSPCNTR(plane), DISPPLANE_GAMMA_ENABLE);
-       POSTING_READ(DSPCNTR(plane));
-
-       dev_priv->display.update_primary_plane(crtc, crtc->primary->fb,
-                                              crtc->x, crtc->y);
-
        intel_crtc->active = true;
 
        intel_set_cpu_fifo_underrun_reporting(dev, pipe, true);
@@ -4087,7 +4208,6 @@ static void haswell_crtc_enable(struct drm_crtc *crtc)
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
        struct intel_encoder *encoder;
        int pipe = intel_crtc->pipe;
-       enum plane plane = intel_crtc->plane;
 
        WARN_ON(!crtc->enabled);
 
@@ -4102,22 +4222,20 @@ static void haswell_crtc_enable(struct drm_crtc *crtc)
 
        intel_set_pipe_timings(intel_crtc);
 
+       if (intel_crtc->config.cpu_transcoder != TRANSCODER_EDP) {
+               I915_WRITE(PIPE_MULT(intel_crtc->config.cpu_transcoder),
+                          intel_crtc->config.pixel_multiplier - 1);
+       }
+
        if (intel_crtc->config.has_pch_encoder) {
                intel_cpu_transcoder_set_m_n(intel_crtc,
-                                            &intel_crtc->config.fdi_m_n);
+                                    &intel_crtc->config.fdi_m_n, NULL);
        }
 
        haswell_set_pipeconf(crtc);
 
        intel_set_pipe_csc(crtc);
 
-       /* Set up the display plane register */
-       I915_WRITE(DSPCNTR(plane), DISPPLANE_GAMMA_ENABLE | DISPPLANE_PIPE_CSC_ENABLE);
-       POSTING_READ(DSPCNTR(plane));
-
-       dev_priv->display.update_primary_plane(crtc, crtc->primary->fb,
-                                              crtc->x, crtc->y);
-
        intel_crtc->active = true;
 
        intel_set_cpu_fifo_underrun_reporting(dev, pipe, true);
@@ -4198,7 +4316,8 @@ static void ironlake_crtc_disable(struct drm_crtc *crtc)
        if (intel_crtc->config.has_pch_encoder)
                intel_set_pch_fifo_underrun_reporting(dev, pipe, false);
 
-       intel_disable_pipe(dev_priv, pipe);
+       intel_disable_pipe(intel_crtc);
+
        ironlake_pfit_disable(intel_crtc);
 
        for_each_encoder_on_crtc(dev, crtc, encoder)
@@ -4246,7 +4365,6 @@ static void haswell_crtc_disable(struct drm_crtc *crtc)
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
        struct intel_encoder *encoder;
-       int pipe = intel_crtc->pipe;
        enum transcoder cpu_transcoder = intel_crtc->config.cpu_transcoder;
 
        if (!intel_crtc->active)
@@ -4261,7 +4379,7 @@ static void haswell_crtc_disable(struct drm_crtc *crtc)
 
        if (intel_crtc->config.has_pch_encoder)
                intel_set_pch_fifo_underrun_reporting(dev, TRANSCODER_A, false);
-       intel_disable_pipe(dev_priv, pipe);
+       intel_disable_pipe(intel_crtc);
 
        if (intel_crtc->config.dp_encoder_is_mst)
                intel_ddi_set_vc_payload_alloc(crtc, false);
@@ -4539,12 +4657,57 @@ static void valleyview_set_cdclk(struct drm_device *dev, int cdclk)
        vlv_update_cdclk(dev);
 }
 
+static void cherryview_set_cdclk(struct drm_device *dev, int cdclk)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       u32 val, cmd;
+
+       WARN_ON(dev_priv->display.get_display_clock_speed(dev) != dev_priv->vlv_cdclk_freq);
+
+       switch (cdclk) {
+       case 400000:
+               cmd = 3;
+               break;
+       case 333333:
+       case 320000:
+               cmd = 2;
+               break;
+       case 266667:
+               cmd = 1;
+               break;
+       case 200000:
+               cmd = 0;
+               break;
+       default:
+               WARN_ON(1);
+               return;
+       }
+
+       mutex_lock(&dev_priv->rps.hw_lock);
+       val = vlv_punit_read(dev_priv, PUNIT_REG_DSPFREQ);
+       val &= ~DSPFREQGUAR_MASK_CHV;
+       val |= (cmd << DSPFREQGUAR_SHIFT_CHV);
+       vlv_punit_write(dev_priv, PUNIT_REG_DSPFREQ, val);
+       if (wait_for((vlv_punit_read(dev_priv, PUNIT_REG_DSPFREQ) &
+                     DSPFREQSTAT_MASK_CHV) == (cmd << DSPFREQSTAT_SHIFT_CHV),
+                    50)) {
+               DRM_ERROR("timed out waiting for CDclk change\n");
+       }
+       mutex_unlock(&dev_priv->rps.hw_lock);
+
+       vlv_update_cdclk(dev);
+}
+
 static int valleyview_calc_cdclk(struct drm_i915_private *dev_priv,
                                 int max_pixclk)
 {
        int vco = valleyview_get_vco(dev_priv);
        int freq_320 = (vco <<  1) % 320000 != 0 ? 333333 : 320000;
 
+       /* FIXME: Punit isn't quite ready yet */
+       if (IS_CHERRYVIEW(dev_priv->dev))
+               return 400000;
+
        /*
         * Really only a few cases to deal with, as only 4 CDclks are supported:
         *   200MHz
@@ -4607,21 +4770,23 @@ static void valleyview_modeset_global_resources(struct drm_device *dev)
        int max_pixclk = intel_mode_max_pixclk(dev_priv);
        int req_cdclk = valleyview_calc_cdclk(dev_priv, max_pixclk);
 
-       if (req_cdclk != dev_priv->vlv_cdclk_freq)
-               valleyview_set_cdclk(dev, req_cdclk);
+       if (req_cdclk != dev_priv->vlv_cdclk_freq) {
+               if (IS_CHERRYVIEW(dev))
+                       cherryview_set_cdclk(dev, req_cdclk);
+               else
+                       valleyview_set_cdclk(dev, req_cdclk);
+       }
+
        modeset_update_crtc_power_domains(dev);
 }
 
 static void valleyview_crtc_enable(struct drm_crtc *crtc)
 {
        struct drm_device *dev = crtc->dev;
-       struct drm_i915_private *dev_priv = dev->dev_private;
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
        struct intel_encoder *encoder;
        int pipe = intel_crtc->pipe;
-       int plane = intel_crtc->plane;
        bool is_dsi;
-       u32 dspcntr;
 
        WARN_ON(!crtc->enabled);
 
@@ -4630,33 +4795,20 @@ static void valleyview_crtc_enable(struct drm_crtc *crtc)
 
        is_dsi = intel_pipe_has_type(crtc, INTEL_OUTPUT_DSI);
 
-       if (!is_dsi && !IS_CHERRYVIEW(dev))
-               vlv_prepare_pll(intel_crtc);
-
-       /* Set up the display plane register */
-       dspcntr = DISPPLANE_GAMMA_ENABLE;
+       if (!is_dsi) {
+               if (IS_CHERRYVIEW(dev))
+                       chv_prepare_pll(intel_crtc);
+               else
+                       vlv_prepare_pll(intel_crtc);
+       }
 
        if (intel_crtc->config.has_dp_encoder)
                intel_dp_set_m_n(intel_crtc);
 
        intel_set_pipe_timings(intel_crtc);
 
-       /* pipesrc and dspsize control the size that is scaled from,
-        * which should always be the user's requested size.
-        */
-       I915_WRITE(DSPSIZE(plane),
-                  ((intel_crtc->config.pipe_src_h - 1) << 16) |
-                  (intel_crtc->config.pipe_src_w - 1));
-       I915_WRITE(DSPPOS(plane), 0);
-
        i9xx_set_pipeconf(intel_crtc);
 
-       I915_WRITE(DSPCNTR(plane), dspcntr);
-       POSTING_READ(DSPCNTR(plane));
-
-       dev_priv->display.update_primary_plane(crtc, crtc->primary->fb,
-                                              crtc->x, crtc->y);
-
        intel_crtc->active = true;
 
        intel_set_cpu_fifo_underrun_reporting(dev, pipe, true);
@@ -4704,12 +4856,9 @@ static void i9xx_set_pll_dividers(struct intel_crtc *crtc)
 static void i9xx_crtc_enable(struct drm_crtc *crtc)
 {
        struct drm_device *dev = crtc->dev;
-       struct drm_i915_private *dev_priv = dev->dev_private;
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
        struct intel_encoder *encoder;
        int pipe = intel_crtc->pipe;
-       int plane = intel_crtc->plane;
-       u32 dspcntr;
 
        WARN_ON(!crtc->enabled);
 
@@ -4718,35 +4867,13 @@ static void i9xx_crtc_enable(struct drm_crtc *crtc)
 
        i9xx_set_pll_dividers(intel_crtc);
 
-       /* Set up the display plane register */
-       dspcntr = DISPPLANE_GAMMA_ENABLE;
-
-       if (pipe == 0)
-               dspcntr &= ~DISPPLANE_SEL_PIPE_MASK;
-       else
-               dspcntr |= DISPPLANE_SEL_PIPE_B;
-
        if (intel_crtc->config.has_dp_encoder)
                intel_dp_set_m_n(intel_crtc);
 
        intel_set_pipe_timings(intel_crtc);
 
-       /* pipesrc and dspsize control the size that is scaled from,
-        * which should always be the user's requested size.
-        */
-       I915_WRITE(DSPSIZE(plane),
-                  ((intel_crtc->config.pipe_src_h - 1) << 16) |
-                  (intel_crtc->config.pipe_src_w - 1));
-       I915_WRITE(DSPPOS(plane), 0);
-
        i9xx_set_pipeconf(intel_crtc);
 
-       I915_WRITE(DSPCNTR(plane), dspcntr);
-       POSTING_READ(DSPCNTR(plane));
-
-       dev_priv->display.update_primary_plane(crtc, crtc->primary->fb,
-                                              crtc->x, crtc->y);
-
        intel_crtc->active = true;
 
        if (!IS_GEN2(dev))
@@ -4842,7 +4969,7 @@ static void i9xx_crtc_disable(struct drm_crtc *crtc)
         */
        intel_wait_for_vblank(dev, pipe);
 
-       intel_disable_pipe(dev_priv, pipe);
+       intel_disable_pipe(intel_crtc);
 
        i9xx_pfit_disable(intel_crtc);
 
@@ -4856,7 +4983,7 @@ static void i9xx_crtc_disable(struct drm_crtc *crtc)
                else if (IS_VALLEYVIEW(dev))
                        vlv_disable_pll(dev_priv, pipe);
                else
-                       i9xx_disable_pll(dev_priv, pipe);
+                       i9xx_disable_pll(intel_crtc);
        }
 
        if (!IS_GEN2(dev))
@@ -5275,6 +5402,10 @@ static int valleyview_get_display_clock_speed(struct drm_device *dev)
        u32 val;
        int divider;
 
+       /* FIXME: Punit isn't quite ready yet */
+       if (IS_CHERRYVIEW(dev))
+               return 400000;
+
        mutex_lock(&dev_priv->dpio_lock);
        val = vlv_cck_read(dev_priv, CCK_DISPLAY_CLOCK_CONTROL);
        mutex_unlock(&dev_priv->dpio_lock);
@@ -5519,7 +5650,8 @@ static void intel_pch_transcoder_set_m_n(struct intel_crtc *crtc,
 }
 
 static void intel_cpu_transcoder_set_m_n(struct intel_crtc *crtc,
-                                        struct intel_link_m_n *m_n)
+                                        struct intel_link_m_n *m_n,
+                                        struct intel_link_m_n *m2_n2)
 {
        struct drm_device *dev = crtc->base.dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
@@ -5531,6 +5663,18 @@ static void intel_cpu_transcoder_set_m_n(struct intel_crtc *crtc,
                I915_WRITE(PIPE_DATA_N1(transcoder), m_n->gmch_n);
                I915_WRITE(PIPE_LINK_M1(transcoder), m_n->link_m);
                I915_WRITE(PIPE_LINK_N1(transcoder), m_n->link_n);
+               /* M2_N2 registers to be set only for gen < 8 (M2_N2 available
+                * for gen < 8) and if DRRS is supported (to make sure the
+                * registers are not unnecessarily accessed).
+                */
+               if (m2_n2 && INTEL_INFO(dev)->gen < 8 &&
+                       crtc->config.has_drrs) {
+                       I915_WRITE(PIPE_DATA_M2(transcoder),
+                                       TU_SIZE(m2_n2->tu) | m2_n2->gmch_m);
+                       I915_WRITE(PIPE_DATA_N2(transcoder), m2_n2->gmch_n);
+                       I915_WRITE(PIPE_LINK_M2(transcoder), m2_n2->link_m);
+                       I915_WRITE(PIPE_LINK_N2(transcoder), m2_n2->link_n);
+               }
        } else {
                I915_WRITE(PIPE_DATA_M_G4X(pipe), TU_SIZE(m_n->tu) | m_n->gmch_m);
                I915_WRITE(PIPE_DATA_N_G4X(pipe), m_n->gmch_n);
@@ -5539,12 +5683,13 @@ static void intel_cpu_transcoder_set_m_n(struct intel_crtc *crtc,
        }
 }
 
-static void intel_dp_set_m_n(struct intel_crtc *crtc)
+void intel_dp_set_m_n(struct intel_crtc *crtc)
 {
        if (crtc->config.has_pch_encoder)
                intel_pch_transcoder_set_m_n(crtc, &crtc->config.dp_m_n);
        else
-               intel_cpu_transcoder_set_m_n(crtc, &crtc->config.dp_m_n);
+               intel_cpu_transcoder_set_m_n(crtc, &crtc->config.dp_m_n,
+                                                  &crtc->config.dp_m2_n2);
 }
 
 static void vlv_update_pll(struct intel_crtc *crtc)
@@ -5661,6 +5806,18 @@ static void vlv_prepare_pll(struct intel_crtc *crtc)
 }
 
 static void chv_update_pll(struct intel_crtc *crtc)
+{
+       crtc->config.dpll_hw_state.dpll = DPLL_SSC_REF_CLOCK_CHV |
+               DPLL_REFA_CLK_ENABLE_VLV | DPLL_VGA_MODE_DIS |
+               DPLL_VCO_ENABLE;
+       if (crtc->pipe != PIPE_A)
+               crtc->config.dpll_hw_state.dpll |= DPLL_INTEGRATED_CRI_CLK_VLV;
+
+       crtc->config.dpll_hw_state.dpll_md =
+               (crtc->config.pixel_multiplier - 1) << DPLL_MD_UDI_MULTIPLIER_SHIFT;
+}
+
+static void chv_prepare_pll(struct intel_crtc *crtc)
 {
        struct drm_device *dev = crtc->base.dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
@@ -5671,15 +5828,6 @@ static void chv_update_pll(struct intel_crtc *crtc)
        u32 bestn, bestm1, bestm2, bestp1, bestp2, bestm2_frac;
        int refclk;
 
-       crtc->config.dpll_hw_state.dpll = DPLL_SSC_REF_CLOCK_CHV |
-               DPLL_REFA_CLK_ENABLE_VLV | DPLL_VGA_MODE_DIS |
-               DPLL_VCO_ENABLE;
-       if (pipe != PIPE_A)
-               crtc->config.dpll_hw_state.dpll |= DPLL_INTEGRATED_CRI_CLK_VLV;
-
-       crtc->config.dpll_hw_state.dpll_md =
-               (crtc->config.pixel_multiplier - 1) << DPLL_MD_UDI_MULTIPLIER_SHIFT;
-
        bestn = crtc->config.dpll.n;
        bestm2_frac = crtc->config.dpll.m2 & 0x3fffff;
        bestm1 = crtc->config.dpll.m1;
@@ -5839,7 +5987,7 @@ static void i8xx_update_pll(struct intel_crtc *crtc,
                        dpll |= PLL_P2_DIVIDE_BY_4;
        }
 
-       if (intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_DVO))
+       if (!IS_I830(dev) && intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_DVO))
                dpll |= DPLL_DVO_2X_MODE;
 
        if (intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_LVDS) &&
@@ -5990,9 +6138,9 @@ static void i9xx_set_pipeconf(struct intel_crtc *intel_crtc)
 
        pipeconf = 0;
 
-       if (dev_priv->quirks & QUIRK_PIPEA_FORCE &&
-           I915_READ(PIPECONF(intel_crtc->pipe)) & PIPECONF_ENABLE)
-               pipeconf |= PIPECONF_ENABLE;
+       if ((intel_crtc->pipe == PIPE_A && dev_priv->quirks & QUIRK_PIPEA_FORCE) ||
+           (intel_crtc->pipe == PIPE_B && dev_priv->quirks & QUIRK_PIPEB_FORCE))
+               pipeconf |= I915_READ(PIPECONF(intel_crtc->pipe)) & PIPECONF_ENABLE;
 
        if (intel_crtc->config.double_wide)
                pipeconf |= PIPECONF_DOUBLE_WIDE;
@@ -6235,7 +6383,7 @@ static void i9xx_get_plane_config(struct intel_crtc *crtc,
        crtc->base.primary->fb->height = ((val >> 0) & 0xfff) + 1;
 
        val = I915_READ(DSPSTRIDE(pipe));
-       crtc->base.primary->fb->pitches[0] = val & 0xffffff80;
+       crtc->base.primary->fb->pitches[0] = val & 0xffffffc0;
 
        aligned_height = intel_align_height(dev, crtc->base.primary->fb->height,
                                            plane_config->tiled);
@@ -6345,6 +6493,14 @@ static bool i9xx_get_pipe_config(struct intel_crtc *crtc,
        }
        pipe_config->dpll_hw_state.dpll = I915_READ(DPLL(crtc->pipe));
        if (!IS_VALLEYVIEW(dev)) {
+               /*
+                * DPLL_DVO_2X_MODE must be enabled for both DPLLs
+                * on 830. Filter it out here so that we don't
+                * report errors due to that.
+                */
+               if (IS_I830(dev))
+                       pipe_config->dpll_hw_state.dpll &= ~DPLL_DVO_2X_MODE;
+
                pipe_config->dpll_hw_state.fp0 = I915_READ(FP0(crtc->pipe));
                pipe_config->dpll_hw_state.fp1 = I915_READ(FP1(crtc->pipe));
        } else {
@@ -6367,7 +6523,6 @@ static bool i9xx_get_pipe_config(struct intel_crtc *crtc,
 static void ironlake_init_pch_refclk(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
-       struct drm_mode_config *mode_config = &dev->mode_config;
        struct intel_encoder *encoder;
        u32 val, final;
        bool has_lvds = false;
@@ -6377,8 +6532,7 @@ static void ironlake_init_pch_refclk(struct drm_device *dev)
        bool can_ssc = false;
 
        /* We need to take the global config into account */
-       list_for_each_entry(encoder, &mode_config->encoder_list,
-                           base.head) {
+       for_each_intel_encoder(dev, encoder) {
                switch (encoder->type) {
                case INTEL_OUTPUT_LVDS:
                        has_panel = true;
@@ -6685,11 +6839,10 @@ static void lpt_disable_clkout_dp(struct drm_device *dev)
 
 static void lpt_init_pch_refclk(struct drm_device *dev)
 {
-       struct drm_mode_config *mode_config = &dev->mode_config;
        struct intel_encoder *encoder;
        bool has_vga = false;
 
-       list_for_each_entry(encoder, &mode_config->encoder_list, base.head) {
+       for_each_intel_encoder(dev, encoder) {
                switch (encoder->type) {
                case INTEL_OUTPUT_ANALOG:
                        has_vga = true;
@@ -7145,7 +7298,8 @@ static void intel_pch_transcoder_get_m_n(struct intel_crtc *crtc,
 
 static void intel_cpu_transcoder_get_m_n(struct intel_crtc *crtc,
                                         enum transcoder transcoder,
-                                        struct intel_link_m_n *m_n)
+                                        struct intel_link_m_n *m_n,
+                                        struct intel_link_m_n *m2_n2)
 {
        struct drm_device *dev = crtc->base.dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
@@ -7159,6 +7313,20 @@ static void intel_cpu_transcoder_get_m_n(struct intel_crtc *crtc,
                m_n->gmch_n = I915_READ(PIPE_DATA_N1(transcoder));
                m_n->tu = ((I915_READ(PIPE_DATA_M1(transcoder))
                            & TU_SIZE_MASK) >> TU_SIZE_SHIFT) + 1;
+               /* Read M2_N2 registers only for gen < 8 (M2_N2 available for
+                * gen < 8) and if DRRS is supported (to make sure the
+                * registers are not unnecessarily read).
+                */
+               if (m2_n2 && INTEL_INFO(dev)->gen < 8 &&
+                       crtc->config.has_drrs) {
+                       m2_n2->link_m = I915_READ(PIPE_LINK_M2(transcoder));
+                       m2_n2->link_n = I915_READ(PIPE_LINK_N2(transcoder));
+                       m2_n2->gmch_m = I915_READ(PIPE_DATA_M2(transcoder))
+                                       & ~TU_SIZE_MASK;
+                       m2_n2->gmch_n = I915_READ(PIPE_DATA_N2(transcoder));
+                       m2_n2->tu = ((I915_READ(PIPE_DATA_M2(transcoder))
+                                       & TU_SIZE_MASK) >> TU_SIZE_SHIFT) + 1;
+               }
        } else {
                m_n->link_m = I915_READ(PIPE_LINK_M_G4X(pipe));
                m_n->link_n = I915_READ(PIPE_LINK_N_G4X(pipe));
@@ -7177,14 +7345,15 @@ void intel_dp_get_m_n(struct intel_crtc *crtc,
                intel_pch_transcoder_get_m_n(crtc, &pipe_config->dp_m_n);
        else
                intel_cpu_transcoder_get_m_n(crtc, pipe_config->cpu_transcoder,
-                                            &pipe_config->dp_m_n);
+                                            &pipe_config->dp_m_n,
+                                            &pipe_config->dp_m2_n2);
 }
 
 static void ironlake_get_fdi_m_n_config(struct intel_crtc *crtc,
                                        struct intel_crtc_config *pipe_config)
 {
        intel_cpu_transcoder_get_m_n(crtc, pipe_config->cpu_transcoder,
-                                    &pipe_config->fdi_m_n);
+                                    &pipe_config->fdi_m_n, NULL);
 }
 
 static void ironlake_get_pfit_config(struct intel_crtc *crtc,
@@ -7255,7 +7424,7 @@ static void ironlake_get_plane_config(struct intel_crtc *crtc,
        crtc->base.primary->fb->height = ((val >> 0) & 0xfff) + 1;
 
        val = I915_READ(DSPSTRIDE(pipe));
-       crtc->base.primary->fb->pitches[0] = val & 0xffffff80;
+       crtc->base.primary->fb->pitches[0] = val & 0xffffffc0;
 
        aligned_height = intel_align_height(dev, crtc->base.primary->fb->height,
                                            plane_config->tiled);
@@ -7615,6 +7784,22 @@ static int haswell_crtc_mode_set(struct drm_crtc *crtc,
        return 0;
 }
 
+static void haswell_get_ddi_pll(struct drm_i915_private *dev_priv,
+                               enum port port,
+                               struct intel_crtc_config *pipe_config)
+{
+       pipe_config->ddi_pll_sel = I915_READ(PORT_CLK_SEL(port));
+
+       switch (pipe_config->ddi_pll_sel) {
+       case PORT_CLK_SEL_WRPLL1:
+               pipe_config->shared_dpll = DPLL_ID_WRPLL1;
+               break;
+       case PORT_CLK_SEL_WRPLL2:
+               pipe_config->shared_dpll = DPLL_ID_WRPLL2;
+               break;
+       }
+}
+
 static void haswell_get_ddi_port_state(struct intel_crtc *crtc,
                                       struct intel_crtc_config *pipe_config)
 {
@@ -7628,16 +7813,7 @@ static void haswell_get_ddi_port_state(struct intel_crtc *crtc,
 
        port = (tmp & TRANS_DDI_PORT_MASK) >> TRANS_DDI_PORT_SHIFT;
 
-       pipe_config->ddi_pll_sel = I915_READ(PORT_CLK_SEL(port));
-
-       switch (pipe_config->ddi_pll_sel) {
-       case PORT_CLK_SEL_WRPLL1:
-               pipe_config->shared_dpll = DPLL_ID_WRPLL1;
-               break;
-       case PORT_CLK_SEL_WRPLL2:
-               pipe_config->shared_dpll = DPLL_ID_WRPLL2;
-               break;
-       }
+       haswell_get_ddi_pll(dev_priv, port, pipe_config);
 
        if (pipe_config->shared_dpll >= 0) {
                pll = &dev_priv->shared_dplls[pipe_config->shared_dpll];
@@ -7719,7 +7895,12 @@ static bool haswell_get_pipe_config(struct intel_crtc *crtc,
                pipe_config->ips_enabled = hsw_crtc_supports_ips(crtc) &&
                        (I915_READ(IPS_CTL) & IPS_ENABLE);
 
-       pipe_config->pixel_multiplier = 1;
+       if (pipe_config->cpu_transcoder != TRANSCODER_EDP) {
+               pipe_config->pixel_multiplier =
+                       I915_READ(PIPE_MULT(pipe_config->cpu_transcoder)) + 1;
+       } else {
+               pipe_config->pixel_multiplier = 1;
+       }
 
        return true;
 }
@@ -8037,74 +8218,62 @@ static void i845_update_cursor(struct drm_crtc *crtc, u32 base)
        struct drm_device *dev = crtc->dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-       uint32_t cntl;
+       uint32_t cntl = 0, size = 0;
 
-       if (base != intel_crtc->cursor_base) {
-               /* On these chipsets we can only modify the base whilst
-                * the cursor is disabled.
-                */
-               if (intel_crtc->cursor_cntl) {
-                       I915_WRITE(_CURACNTR, 0);
-                       POSTING_READ(_CURACNTR);
-                       intel_crtc->cursor_cntl = 0;
+       if (base) {
+               unsigned int width = intel_crtc->cursor_width;
+               unsigned int height = intel_crtc->cursor_height;
+               unsigned int stride = roundup_pow_of_two(width) * 4;
+
+               switch (stride) {
+               default:
+                       WARN_ONCE(1, "Invalid cursor width/stride, width=%u, stride=%u\n",
+                                 width, stride);
+                       stride = 256;
+                       /* fallthrough */
+               case 256:
+               case 512:
+               case 1024:
+               case 2048:
+                       break;
                }
 
-               I915_WRITE(_CURABASE, base);
-               POSTING_READ(_CURABASE);
+               cntl |= CURSOR_ENABLE |
+                       CURSOR_GAMMA_ENABLE |
+                       CURSOR_FORMAT_ARGB |
+                       CURSOR_STRIDE(stride);
+
+               size = (height << 12) | width;
        }
 
-       /* XXX width must be 64, stride 256 => 0x00 << 28 */
-       cntl = 0;
-       if (base)
-               cntl = (CURSOR_ENABLE |
-                       CURSOR_GAMMA_ENABLE |
-                       CURSOR_FORMAT_ARGB);
-       if (intel_crtc->cursor_cntl != cntl) {
-               I915_WRITE(_CURACNTR, cntl);
+       if (intel_crtc->cursor_cntl != 0 &&
+           (intel_crtc->cursor_base != base ||
+            intel_crtc->cursor_size != size ||
+            intel_crtc->cursor_cntl != cntl)) {
+               /* On these chipsets we can only modify the base/size/stride
+                * whilst the cursor is disabled.
+                */
+               I915_WRITE(_CURACNTR, 0);
                POSTING_READ(_CURACNTR);
-               intel_crtc->cursor_cntl = cntl;
+               intel_crtc->cursor_cntl = 0;
        }
-}
 
-static void i9xx_update_cursor(struct drm_crtc *crtc, u32 base)
-{
-       struct drm_device *dev = crtc->dev;
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-       int pipe = intel_crtc->pipe;
-       uint32_t cntl;
+       if (intel_crtc->cursor_base != base)
+               I915_WRITE(_CURABASE, base);
 
-       cntl = 0;
-       if (base) {
-               cntl = MCURSOR_GAMMA_ENABLE;
-               switch (intel_crtc->cursor_width) {
-                       case 64:
-                               cntl |= CURSOR_MODE_64_ARGB_AX;
-                               break;
-                       case 128:
-                               cntl |= CURSOR_MODE_128_ARGB_AX;
-                               break;
-                       case 256:
-                               cntl |= CURSOR_MODE_256_ARGB_AX;
-                               break;
-                       default:
-                               WARN_ON(1);
-                               return;
-               }
-               cntl |= pipe << 28; /* Connect to correct pipe */
+       if (intel_crtc->cursor_size != size) {
+               I915_WRITE(CURSIZE, size);
+               intel_crtc->cursor_size = size;
        }
+
        if (intel_crtc->cursor_cntl != cntl) {
-               I915_WRITE(CURCNTR(pipe), cntl);
-               POSTING_READ(CURCNTR(pipe));
+               I915_WRITE(_CURACNTR, cntl);
+               POSTING_READ(_CURACNTR);
                intel_crtc->cursor_cntl = cntl;
        }
-
-       /* and commit changes on next vblank */
-       I915_WRITE(CURBASE(pipe), base);
-       POSTING_READ(CURBASE(pipe));
 }
 
-static void ivb_update_cursor(struct drm_crtc *crtc, u32 base)
+static void i9xx_update_cursor(struct drm_crtc *crtc, u32 base)
 {
        struct drm_device *dev = crtc->dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
@@ -8129,6 +8298,7 @@ static void ivb_update_cursor(struct drm_crtc *crtc, u32 base)
                                WARN_ON(1);
                                return;
                }
+               cntl |= pipe << 28; /* Connect to correct pipe */
        }
        if (IS_HASWELL(dev) || IS_BROADWELL(dev))
                cntl |= CURSOR_PIPE_CSC_ENABLE;
@@ -8188,15 +8358,50 @@ static void intel_crtc_update_cursor(struct drm_crtc *crtc,
 
        I915_WRITE(CURPOS(pipe), pos);
 
-       if (IS_IVYBRIDGE(dev) || IS_HASWELL(dev) || IS_BROADWELL(dev))
-               ivb_update_cursor(crtc, base);
-       else if (IS_845G(dev) || IS_I865G(dev))
+       if (IS_845G(dev) || IS_I865G(dev))
                i845_update_cursor(crtc, base);
        else
                i9xx_update_cursor(crtc, base);
        intel_crtc->cursor_base = base;
 }
 
+static bool cursor_size_ok(struct drm_device *dev,
+                          uint32_t width, uint32_t height)
+{
+       if (width == 0 || height == 0)
+               return false;
+
+       /*
+        * 845g/865g are special in that they are only limited by
+        * the width of their cursors, the height is arbitrary up to
+        * the precision of the register. Everything else requires
+        * square cursors, limited to a few power-of-two sizes.
+        */
+       if (IS_845G(dev) || IS_I865G(dev)) {
+               if ((width & 63) != 0)
+                       return false;
+
+               if (width > (IS_845G(dev) ? 64 : 512))
+                       return false;
+
+               if (height > 1023)
+                       return false;
+       } else {
+               switch (width | height) {
+               case 256:
+               case 128:
+                       if (IS_GEN2(dev))
+                               return false;
+               case 64:
+                       break;
+               default:
+                       return false;
+               }
+       }
+
+       return true;
+}
+
 /*
  * intel_crtc_cursor_set_obj - Set cursor to specified GEM object
  *
@@ -8212,7 +8417,7 @@ static int intel_crtc_cursor_set_obj(struct drm_crtc *crtc,
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
        enum pipe pipe = intel_crtc->pipe;
-       unsigned old_width;
+       unsigned old_width, stride;
        uint32_t addr;
        int ret;
 
@@ -8220,20 +8425,18 @@ static int intel_crtc_cursor_set_obj(struct drm_crtc *crtc,
        if (!obj) {
                DRM_DEBUG_KMS("cursor off\n");
                addr = 0;
-               obj = NULL;
                mutex_lock(&dev->struct_mutex);
                goto finish;
        }
 
        /* Check for which cursor types we support */
-       if (!((width == 64 && height == 64) ||
-                       (width == 128 && height == 128 && !IS_GEN2(dev)) ||
-                       (width == 256 && height == 256 && !IS_GEN2(dev)))) {
+       if (!cursor_size_ok(dev, width, height)) {
                DRM_DEBUG("Cursor dimension not supported\n");
                return -EINVAL;
        }
 
-       if (obj->base.size < width * height * 4) {
+       stride = roundup_pow_of_two(width) * 4;
+       if (obj->base.size < stride * height) {
                DRM_DEBUG_KMS("buffer is too small\n");
                ret = -ENOMEM;
                goto fail;
@@ -8295,9 +8498,6 @@ static int intel_crtc_cursor_set_obj(struct drm_crtc *crtc,
                addr = obj->phys_handle->busaddr;
        }
 
-       if (IS_GEN2(dev))
-               I915_WRITE(CURSIZE, (height << 12) | width);
-
  finish:
        if (intel_crtc->cursor_bo) {
                if (!INTEL_INFO(dev)->cursor_needs_physical)
@@ -8944,12 +9144,13 @@ static void intel_mark_fb_busy(struct drm_device *dev,
                               unsigned frontbuffer_bits,
                               struct intel_engine_cs *ring)
 {
+       struct drm_i915_private *dev_priv = dev->dev_private;
        enum pipe pipe;
 
        if (!i915.powersave)
                return;
 
-       for_each_pipe(pipe) {
+       for_each_pipe(dev_priv, pipe) {
                if (!(frontbuffer_bits & INTEL_FRONTBUFFER_ALL_MASK(pipe)))
                        continue;
 
@@ -9019,6 +9220,14 @@ void intel_frontbuffer_flush(struct drm_device *dev,
        intel_mark_fb_busy(dev, frontbuffer_bits, NULL);
 
        intel_edp_psr_flush(dev, frontbuffer_bits);
+
+       /*
+        * FIXME: Unconditional fbc flushing here is a rather gross hack and
+        * needs to be reworked into a proper frontbuffer tracking scheme like
+        * psr employs.
+        */
+       if (IS_BROADWELL(dev))
+               gen8_fbc_sw_flush(dev, FBC_REND_CACHE_CLEAN);
 }
 
 /**
@@ -9151,7 +9360,6 @@ static void intel_unpin_work_fn(struct work_struct *__work)
 static void do_intel_finish_page_flip(struct drm_device *dev,
                                      struct drm_crtc *crtc)
 {
-       struct drm_i915_private *dev_priv = dev->dev_private;
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
        struct intel_unpin_work *work;
        unsigned long flags;
@@ -9171,23 +9379,9 @@ static void do_intel_finish_page_flip(struct drm_device *dev,
                return;
        }
 
-       /* and that the unpin work is consistent wrt ->pending. */
-       smp_rmb();
-
-       intel_crtc->unpin_work = NULL;
-
-       if (work->event)
-               drm_send_vblank_event(dev, intel_crtc->pipe, work->event);
-
-       drm_crtc_vblank_put(crtc);
+       page_flip_completed(intel_crtc);
 
        spin_unlock_irqrestore(&dev->event_lock, flags);
-
-       wake_up_all(&dev_priv->pending_flip_queue);
-
-       queue_work(dev_priv->wq, &work->work);
-
-       trace_i915_flip_complete(intel_crtc->plane, work->pending_flip_obj);
 }
 
 void intel_finish_page_flip(struct drm_device *dev, int pipe)
@@ -9532,6 +9726,8 @@ static bool use_mmio_flip(struct intel_engine_cs *ring,
                return false;
        else if (i915.use_mmio_flip > 0)
                return true;
+       else if (i915.enable_execlists)
+               return true;
        else
                return ring != obj->ring;
 }
@@ -9665,6 +9861,65 @@ static int intel_default_queue_flip(struct drm_device *dev,
        return -ENODEV;
 }
 
+static bool __intel_pageflip_stall_check(struct drm_device *dev,
+                                        struct drm_crtc *crtc)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+       struct intel_unpin_work *work = intel_crtc->unpin_work;
+       u32 addr;
+
+       if (atomic_read(&work->pending) >= INTEL_FLIP_COMPLETE)
+               return true;
+
+       if (!work->enable_stall_check)
+               return false;
+
+       if (work->flip_ready_vblank == 0) {
+               if (work->flip_queued_ring &&
+                   !i915_seqno_passed(work->flip_queued_ring->get_seqno(work->flip_queued_ring, true),
+                                      work->flip_queued_seqno))
+                       return false;
+
+               work->flip_ready_vblank = drm_vblank_count(dev, intel_crtc->pipe);
+       }
+
+       if (drm_vblank_count(dev, intel_crtc->pipe) - work->flip_ready_vblank < 3)
+               return false;
+
+       /* Potential stall - if we see that the flip has happened,
+        * assume a missed interrupt. */
+       if (INTEL_INFO(dev)->gen >= 4)
+               addr = I915_HI_DISPBASE(I915_READ(DSPSURF(intel_crtc->plane)));
+       else
+               addr = I915_READ(DSPADDR(intel_crtc->plane));
+
+       /* There is a potential issue here with a false positive after a flip
+        * to the same address. We could address this by checking for a
+        * non-incrementing frame counter.
+        */
+       return addr == work->gtt_offset;
+}
+
+void intel_check_page_flip(struct drm_device *dev, int pipe)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct drm_crtc *crtc = dev_priv->pipe_to_crtc_mapping[pipe];
+       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+       unsigned long flags;
+
+       if (crtc == NULL)
+               return;
+
+       spin_lock_irqsave(&dev->event_lock, flags);
+       if (intel_crtc->unpin_work && __intel_pageflip_stall_check(dev, crtc)) {
+               WARN_ONCE(1, "Kicking stuck page flip: queued at %d, now %d\n",
+                        intel_crtc->unpin_work->flip_queued_vblank, drm_vblank_count(dev, pipe));
+               page_flip_completed(intel_crtc);
+       }
+       spin_unlock_irqrestore(&dev->event_lock, flags);
+}
+
 static int intel_crtc_page_flip(struct drm_crtc *crtc,
                                struct drm_framebuffer *fb,
                                struct drm_pending_vblank_event *event,
@@ -9721,12 +9976,20 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
        /* We borrow the event spin lock for protecting unpin_work */
        spin_lock_irqsave(&dev->event_lock, flags);
        if (intel_crtc->unpin_work) {
-               spin_unlock_irqrestore(&dev->event_lock, flags);
-               kfree(work);
-               drm_crtc_vblank_put(crtc);
+               /* Before declaring the flip queue wedged, check if
+                * the hardware completed the operation behind our backs.
+                */
+               if (__intel_pageflip_stall_check(dev, crtc)) {
+                       DRM_DEBUG_DRIVER("flip queue: previous flip completed, continuing\n");
+                       page_flip_completed(intel_crtc);
+               } else {
+                       DRM_DEBUG_DRIVER("flip queue: crtc already busy\n");
+                       spin_unlock_irqrestore(&dev->event_lock, flags);
 
-               DRM_DEBUG_DRIVER("flip queue: crtc already busy\n");
-               return -EBUSY;
+                       drm_crtc_vblank_put(crtc);
+                       kfree(work);
+                       return -EBUSY;
+               }
        }
        intel_crtc->unpin_work = work;
        spin_unlock_irqrestore(&dev->event_lock, flags);
@@ -9746,8 +10009,6 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
 
        work->pending_flip_obj = obj;
 
-       work->enable_stall_check = true;
-
        atomic_inc(&intel_crtc->unpin_work_count);
        intel_crtc->reset_counter = atomic_read(&dev_priv->gpu_error.reset_counter);
 
@@ -9776,14 +10037,26 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
        work->gtt_offset =
                i915_gem_obj_ggtt_offset(obj) + intel_crtc->dspaddr_offset;
 
-       if (use_mmio_flip(ring, obj))
+       if (use_mmio_flip(ring, obj)) {
                ret = intel_queue_mmio_flip(dev, crtc, fb, obj, ring,
                                            page_flip_flags);
-       else
+               if (ret)
+                       goto cleanup_unpin;
+
+               work->flip_queued_seqno = obj->last_write_seqno;
+               work->flip_queued_ring = obj->ring;
+       } else {
                ret = dev_priv->display.queue_flip(dev, crtc, fb, obj, ring,
-                               page_flip_flags);
-       if (ret)
-               goto cleanup_unpin;
+                                                  page_flip_flags);
+               if (ret)
+                       goto cleanup_unpin;
+
+               work->flip_queued_seqno = intel_ring_get_seqno(ring);
+               work->flip_queued_ring = ring;
+       }
+
+       work->flip_queued_vblank = drm_vblank_count(dev, intel_crtc->pipe);
+       work->enable_stall_check = true;
 
        i915_gem_track_fb(work->old_fb_obj, obj,
                          INTEL_FRONTBUFFER_PRIMARY(pipe));
@@ -9818,8 +10091,11 @@ free_work:
 out_hang:
                intel_crtc_wait_for_pending_flips(crtc);
                ret = intel_pipe_set_base(crtc, crtc->x, crtc->y, fb);
-               if (ret == 0 && event)
+               if (ret == 0 && event) {
+                       spin_lock_irqsave(&dev->event_lock, flags);
                        drm_send_vblank_event(dev, pipe, event);
+                       spin_unlock_irqrestore(&dev->event_lock, flags);
+               }
        }
        return ret;
 }
@@ -9847,8 +10123,7 @@ static void intel_modeset_update_staged_output_state(struct drm_device *dev)
                        to_intel_encoder(connector->base.encoder);
        }
 
-       list_for_each_entry(encoder, &dev->mode_config.encoder_list,
-                           base.head) {
+       for_each_intel_encoder(dev, encoder) {
                encoder->new_crtc =
                        to_intel_crtc(encoder->base.crtc);
        }
@@ -9879,8 +10154,7 @@ static void intel_modeset_commit_output_state(struct drm_device *dev)
                connector->base.encoder = &connector->new_encoder->base;
        }
 
-       list_for_each_entry(encoder, &dev->mode_config.encoder_list,
-                           base.head) {
+       for_each_intel_encoder(dev, encoder) {
                encoder->base.crtc = &encoder->new_crtc->base;
        }
 
@@ -10007,6 +10281,15 @@ static void intel_dump_pipe_config(struct intel_crtc *crtc,
                      pipe_config->dp_m_n.gmch_m, pipe_config->dp_m_n.gmch_n,
                      pipe_config->dp_m_n.link_m, pipe_config->dp_m_n.link_n,
                      pipe_config->dp_m_n.tu);
+
+       DRM_DEBUG_KMS("dp: %i, gmch_m2: %u, gmch_n2: %u, link_m2: %u, link_n2: %u, tu2: %u\n",
+                     pipe_config->has_dp_encoder,
+                     pipe_config->dp_m2_n2.gmch_m,
+                     pipe_config->dp_m2_n2.gmch_n,
+                     pipe_config->dp_m2_n2.link_m,
+                     pipe_config->dp_m2_n2.link_n,
+                     pipe_config->dp_m2_n2.tu);
+
        DRM_DEBUG_KMS("requested mode:\n");
        drm_mode_debug_printmodeline(&pipe_config->requested_mode);
        DRM_DEBUG_KMS("adjusted mode:\n");
@@ -10041,8 +10324,7 @@ static bool check_single_encoder_cloning(struct intel_crtc *crtc,
        struct drm_device *dev = crtc->base.dev;
        struct intel_encoder *source_encoder;
 
-       list_for_each_entry(source_encoder,
-                           &dev->mode_config.encoder_list, base.head) {
+       for_each_intel_encoder(dev, source_encoder) {
                if (source_encoder->new_crtc != crtc)
                        continue;
 
@@ -10058,8 +10340,7 @@ static bool check_encoder_cloning(struct intel_crtc *crtc)
        struct drm_device *dev = crtc->base.dev;
        struct intel_encoder *encoder;
 
-       list_for_each_entry(encoder,
-                           &dev->mode_config.encoder_list, base.head) {
+       for_each_intel_encoder(dev, encoder) {
                if (encoder->new_crtc != crtc)
                        continue;
 
@@ -10143,8 +10424,7 @@ encoder_retry:
         * adjust it according to limitations or connector properties, and also
         * a chance to reject the mode entirely.
         */
-       list_for_each_entry(encoder, &dev->mode_config.encoder_list,
-                           base.head) {
+       for_each_intel_encoder(dev, encoder) {
 
                if (&encoder->new_crtc->base != crtc)
                        continue;
@@ -10222,8 +10502,7 @@ intel_modeset_affected_pipes(struct drm_crtc *crtc, unsigned *modeset_pipes,
                                1 << connector->new_encoder->new_crtc->pipe;
        }
 
-       list_for_each_entry(encoder, &dev->mode_config.encoder_list,
-                           base.head) {
+       for_each_intel_encoder(dev, encoder) {
                if (encoder->base.crtc == &encoder->new_crtc->base)
                        continue;
 
@@ -10297,8 +10576,7 @@ intel_modeset_update_state(struct drm_device *dev, unsigned prepare_pipes)
        struct intel_crtc *intel_crtc;
        struct drm_connector *connector;
 
-       list_for_each_entry(intel_encoder, &dev->mode_config.encoder_list,
-                           base.head) {
+       for_each_intel_encoder(dev, intel_encoder) {
                if (!intel_encoder->base.crtc)
                        continue;
 
@@ -10387,6 +10665,22 @@ intel_pipe_config_compare(struct drm_device *dev,
                return false; \
        }
 
+/* This is required for BDW+ where there is only one set of registers for
+ * switching between high and low RR.
+ * This macro can be used whenever a comparison has to be made between one
+ * hw state and multiple sw state variables.
+ */
+#define PIPE_CONF_CHECK_I_ALT(name, alt_name) \
+       if ((current_config->name != pipe_config->name) && \
+               (current_config->alt_name != pipe_config->name)) { \
+                       DRM_ERROR("mismatch in " #name " " \
+                                 "(expected %i or %i, found %i)\n", \
+                                 current_config->name, \
+                                 current_config->alt_name, \
+                                 pipe_config->name); \
+                       return false; \
+       }
+
 #define PIPE_CONF_CHECK_FLAGS(name, mask)      \
        if ((current_config->name ^ pipe_config->name) & (mask)) { \
                DRM_ERROR("mismatch in " #name "(" #mask ") "      \
@@ -10419,11 +10713,28 @@ intel_pipe_config_compare(struct drm_device *dev,
        PIPE_CONF_CHECK_I(fdi_m_n.tu);
 
        PIPE_CONF_CHECK_I(has_dp_encoder);
-       PIPE_CONF_CHECK_I(dp_m_n.gmch_m);
-       PIPE_CONF_CHECK_I(dp_m_n.gmch_n);
-       PIPE_CONF_CHECK_I(dp_m_n.link_m);
-       PIPE_CONF_CHECK_I(dp_m_n.link_n);
-       PIPE_CONF_CHECK_I(dp_m_n.tu);
+
+       if (INTEL_INFO(dev)->gen < 8) {
+               PIPE_CONF_CHECK_I(dp_m_n.gmch_m);
+               PIPE_CONF_CHECK_I(dp_m_n.gmch_n);
+               PIPE_CONF_CHECK_I(dp_m_n.link_m);
+               PIPE_CONF_CHECK_I(dp_m_n.link_n);
+               PIPE_CONF_CHECK_I(dp_m_n.tu);
+
+               if (current_config->has_drrs) {
+                       PIPE_CONF_CHECK_I(dp_m2_n2.gmch_m);
+                       PIPE_CONF_CHECK_I(dp_m2_n2.gmch_n);
+                       PIPE_CONF_CHECK_I(dp_m2_n2.link_m);
+                       PIPE_CONF_CHECK_I(dp_m2_n2.link_n);
+                       PIPE_CONF_CHECK_I(dp_m2_n2.tu);
+               }
+       } else {
+               PIPE_CONF_CHECK_I_ALT(dp_m_n.gmch_m, dp_m2_n2.gmch_m);
+               PIPE_CONF_CHECK_I_ALT(dp_m_n.gmch_n, dp_m2_n2.gmch_n);
+               PIPE_CONF_CHECK_I_ALT(dp_m_n.link_m, dp_m2_n2.link_m);
+               PIPE_CONF_CHECK_I_ALT(dp_m_n.link_n, dp_m2_n2.link_n);
+               PIPE_CONF_CHECK_I_ALT(dp_m_n.tu, dp_m2_n2.tu);
+       }
 
        PIPE_CONF_CHECK_I(adjusted_mode.crtc_hdisplay);
        PIPE_CONF_CHECK_I(adjusted_mode.crtc_htotal);
@@ -10509,6 +10820,7 @@ intel_pipe_config_compare(struct drm_device *dev,
 
 #undef PIPE_CONF_CHECK_X
 #undef PIPE_CONF_CHECK_I
+#undef PIPE_CONF_CHECK_I_ALT
 #undef PIPE_CONF_CHECK_FLAGS
 #undef PIPE_CONF_CHECK_CLOCK_FUZZY
 #undef PIPE_CONF_QUIRK
@@ -10538,8 +10850,7 @@ check_encoder_state(struct drm_device *dev)
        struct intel_encoder *encoder;
        struct intel_connector *connector;
 
-       list_for_each_entry(encoder, &dev->mode_config.encoder_list,
-                           base.head) {
+       for_each_intel_encoder(dev, encoder) {
                bool enabled = false;
                bool active = false;
                enum pipe pipe, tracked_pipe;
@@ -10618,8 +10929,7 @@ check_crtc_state(struct drm_device *dev)
                WARN(crtc->active && !crtc->base.enabled,
                     "active crtc, but not enabled in sw tracking\n");
 
-               list_for_each_entry(encoder, &dev->mode_config.encoder_list,
-                                   base.head) {
+               for_each_intel_encoder(dev, encoder) {
                        if (encoder->base.crtc != &crtc->base)
                                continue;
                        enabled = true;
@@ -10637,12 +10947,12 @@ check_crtc_state(struct drm_device *dev)
                active = dev_priv->display.get_pipe_config(crtc,
                                                           &pipe_config);
 
-               /* hw state is inconsistent with the pipe A quirk */
-               if (crtc->pipe == PIPE_A && dev_priv->quirks & QUIRK_PIPEA_FORCE)
+               /* hw state is inconsistent with the pipe quirk */
+               if ((crtc->pipe == PIPE_A && dev_priv->quirks & QUIRK_PIPEA_FORCE) ||
+                   (crtc->pipe == PIPE_B && dev_priv->quirks & QUIRK_PIPEB_FORCE))
                        active = crtc->active;
 
-               list_for_each_entry(encoder, &dev->mode_config.encoder_list,
-                                   base.head) {
+               for_each_intel_encoder(dev, encoder) {
                        enum pipe pipe;
                        if (encoder->base.crtc != &crtc->base)
                                continue;
@@ -11010,7 +11320,7 @@ static void intel_set_config_restore_state(struct drm_device *dev,
        }
 
        count = 0;
-       list_for_each_entry(encoder, &dev->mode_config.encoder_list, base.head) {
+       for_each_intel_encoder(dev, encoder) {
                encoder->new_crtc =
                        to_intel_crtc(config->save_encoder_crtcs[count++]);
        }
@@ -11169,8 +11479,7 @@ intel_modeset_stage_output_state(struct drm_device *dev,
        }
 
        /* Check for any encoders that needs to be disabled. */
-       list_for_each_entry(encoder, &dev->mode_config.encoder_list,
-                           base.head) {
+       for_each_intel_encoder(dev, encoder) {
                int num_connectors = 0;
                list_for_each_entry(connector,
                                    &dev->mode_config.connector_list,
@@ -11203,9 +11512,7 @@ intel_modeset_stage_output_state(struct drm_device *dev,
        for_each_intel_crtc(dev, crtc) {
                crtc->new_enabled = false;
 
-               list_for_each_entry(encoder,
-                                   &dev->mode_config.encoder_list,
-                                   base.head) {
+               for_each_intel_encoder(dev, encoder) {
                        if (encoder->new_crtc == crtc) {
                                crtc->new_enabled = true;
                                break;
@@ -11242,7 +11549,7 @@ static void disable_crtc_nofb(struct intel_crtc *crtc)
                        connector->new_encoder = NULL;
        }
 
-       list_for_each_entry(encoder, &dev->mode_config.encoder_list, base.head) {
+       for_each_intel_encoder(dev, encoder) {
                if (encoder->new_crtc == crtc)
                        encoder->new_crtc = NULL;
        }
@@ -11305,7 +11612,6 @@ static int intel_crtc_set_config(struct drm_mode_set *set)
                ret = intel_set_mode(set->crtc, set->mode,
                                     set->x, set->y, set->fb);
        } else if (config->fb_changed) {
-               struct drm_i915_private *dev_priv = dev->dev_private;
                struct intel_crtc *intel_crtc = to_intel_crtc(set->crtc);
 
                intel_crtc_wait_for_pending_flips(set->crtc);
@@ -11319,8 +11625,7 @@ static int intel_crtc_set_config(struct drm_mode_set *set)
                 */
                if (!intel_crtc->primary_enabled && ret == 0) {
                        WARN_ON(!intel_crtc->active);
-                       intel_enable_primary_hw_plane(dev_priv, intel_crtc->plane,
-                                                     intel_crtc->pipe);
+                       intel_enable_primary_hw_plane(set->crtc->primary, set->crtc);
                }
 
                /*
@@ -11473,8 +11778,6 @@ static int
 intel_primary_plane_disable(struct drm_plane *plane)
 {
        struct drm_device *dev = plane->dev;
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       struct intel_plane *intel_plane = to_intel_plane(plane);
        struct intel_crtc *intel_crtc;
 
        if (!plane->fb)
@@ -11497,8 +11800,8 @@ intel_primary_plane_disable(struct drm_plane *plane)
                goto disable_unpin;
 
        intel_crtc_wait_for_pending_flips(plane->crtc);
-       intel_disable_primary_hw_plane(dev_priv, intel_plane->plane,
-                                      intel_plane->pipe);
+       intel_disable_primary_hw_plane(plane, plane->crtc);
+
 disable_unpin:
        mutex_lock(&dev->struct_mutex);
        i915_gem_track_fb(intel_fb_obj(plane->fb), NULL,
@@ -11520,7 +11823,6 @@ intel_primary_plane_setplane(struct drm_plane *plane, struct drm_crtc *crtc,
        struct drm_device *dev = crtc->dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-       struct intel_plane *intel_plane = to_intel_plane(plane);
        struct drm_i915_gem_object *obj = intel_fb_obj(fb);
        struct drm_i915_gem_object *old_obj = intel_fb_obj(plane->fb);
        struct drm_rect dest = {
@@ -11542,6 +11844,21 @@ intel_primary_plane_setplane(struct drm_plane *plane, struct drm_crtc *crtc,
                .x2 = intel_crtc->active ? intel_crtc->config.pipe_src_w : 0,
                .y2 = intel_crtc->active ? intel_crtc->config.pipe_src_h : 0,
        };
+       const struct {
+               int crtc_x, crtc_y;
+               unsigned int crtc_w, crtc_h;
+               uint32_t src_x, src_y, src_w, src_h;
+       } orig = {
+               .crtc_x = crtc_x,
+               .crtc_y = crtc_y,
+               .crtc_w = crtc_w,
+               .crtc_h = crtc_h,
+               .src_x = src_x,
+               .src_y = src_y,
+               .src_w = src_w,
+               .src_h = src_h,
+       };
+       struct intel_plane *intel_plane = to_intel_plane(plane);
        bool visible;
        int ret;
 
@@ -11607,9 +11924,7 @@ intel_primary_plane_setplane(struct drm_plane *plane, struct drm_crtc *crtc,
                                  INTEL_FRONTBUFFER_PRIMARY(intel_crtc->pipe));
 
                if (intel_crtc->primary_enabled)
-                       intel_disable_primary_hw_plane(dev_priv,
-                                                      intel_plane->plane,
-                                                      intel_plane->pipe);
+                       intel_disable_primary_hw_plane(plane, crtc);
 
 
                if (plane->fb != fb)
@@ -11618,16 +11933,42 @@ intel_primary_plane_setplane(struct drm_plane *plane, struct drm_crtc *crtc,
 
                mutex_unlock(&dev->struct_mutex);
 
-               return 0;
-       }
+       } else {
+               if (intel_crtc && intel_crtc->active &&
+                   intel_crtc->primary_enabled) {
+                       /*
+                        * FBC does not work on some platforms for rotated
+                        * planes, so disable it when rotation is not 0 and
+                        * update it when rotation is set back to 0.
+                        *
+                        * FIXME: This is redundant with the fbc update done in
+                        * the primary plane enable function except that that
+                        * one is done too late. We eventually need to unify
+                        * this.
+                        */
+                       if (INTEL_INFO(dev)->gen <= 4 && !IS_G4X(dev) &&
+                           dev_priv->fbc.plane == intel_crtc->plane &&
+                           intel_plane->rotation != BIT(DRM_ROTATE_0)) {
+                               intel_disable_fbc(dev);
+                       }
+               }
+               ret = intel_pipe_set_base(crtc, src.x1, src.y1, fb);
+               if (ret)
+                       return ret;
 
-       ret = intel_pipe_set_base(crtc, src.x1, src.y1, fb);
-       if (ret)
-               return ret;
+               if (!intel_crtc->primary_enabled)
+                       intel_enable_primary_hw_plane(plane, crtc);
+       }
 
-       if (!intel_crtc->primary_enabled)
-               intel_enable_primary_hw_plane(dev_priv, intel_crtc->plane,
-                                             intel_crtc->pipe);
+       intel_plane->crtc_x = orig.crtc_x;
+       intel_plane->crtc_y = orig.crtc_y;
+       intel_plane->crtc_w = orig.crtc_w;
+       intel_plane->crtc_h = orig.crtc_h;
+       intel_plane->src_x = orig.src_x;
+       intel_plane->src_y = orig.src_y;
+       intel_plane->src_w = orig.src_w;
+       intel_plane->src_h = orig.src_h;
+       intel_plane->obj = obj;
 
        return 0;
 }
@@ -11644,6 +11985,7 @@ static const struct drm_plane_funcs intel_primary_plane_funcs = {
        .update_plane = intel_primary_plane_setplane,
        .disable_plane = intel_primary_plane_disable,
        .destroy = intel_plane_destroy,
+       .set_property = intel_plane_set_property
 };
 
 static struct drm_plane *intel_primary_plane_create(struct drm_device *dev,
@@ -11661,6 +12003,7 @@ static struct drm_plane *intel_primary_plane_create(struct drm_device *dev,
        primary->max_downscale = 1;
        primary->pipe = pipe;
        primary->plane = pipe;
+       primary->rotation = BIT(DRM_ROTATE_0);
        if (HAS_FBC(dev) && INTEL_INFO(dev)->gen < 4)
                primary->plane = !pipe;
 
@@ -11676,6 +12019,19 @@ static struct drm_plane *intel_primary_plane_create(struct drm_device *dev,
                                 &intel_primary_plane_funcs,
                                 intel_primary_formats, num_formats,
                                 DRM_PLANE_TYPE_PRIMARY);
+
+       if (INTEL_INFO(dev)->gen >= 4) {
+               if (!dev->mode_config.rotation_property)
+                       dev->mode_config.rotation_property =
+                               drm_mode_create_rotation_property(dev,
+                                                       BIT(DRM_ROTATE_0) |
+                                                       BIT(DRM_ROTATE_180));
+               if (dev->mode_config.rotation_property)
+                       drm_object_attach_property(&primary->base.base,
+                               dev->mode_config.rotation_property,
+                               primary->rotation);
+       }
+
        return &primary->base;
 }
 
@@ -11736,6 +12092,10 @@ intel_cursor_plane_update(struct drm_plane *plane, struct drm_crtc *crtc,
                return intel_crtc_cursor_set_obj(crtc, obj, crtc_w, crtc_h);
        } else {
                intel_crtc_update_cursor(crtc, visible);
+
+               intel_frontbuffer_flip(crtc->dev,
+                                      INTEL_FRONTBUFFER_CURSOR(intel_crtc->pipe));
+
                return 0;
        }
 }
@@ -11812,8 +12172,7 @@ static void intel_crtc_init(struct drm_device *dev, int pipe)
 
        intel_crtc->cursor_base = ~0;
        intel_crtc->cursor_cntl = ~0;
-
-       init_waitqueue_head(&intel_crtc->vbl_wait);
+       intel_crtc->cursor_size = ~0;
 
        BUG_ON(pipe >= ARRAY_SIZE(dev_priv->plane_to_crtc_mapping) ||
               dev_priv->plane_to_crtc_mapping[intel_crtc->plane] != NULL);
@@ -11876,8 +12235,7 @@ static int intel_encoder_clones(struct intel_encoder *encoder)
        int index_mask = 0;
        int entry = 0;
 
-       list_for_each_entry(source_encoder,
-                           &dev->mode_config.encoder_list, base.head) {
+       for_each_intel_encoder(dev, source_encoder) {
                if (encoders_cloneable(encoder, source_encoder))
                        index_mask |= (1 << entry);
 
@@ -12066,7 +12424,7 @@ static void intel_setup_outputs(struct drm_device *dev)
 
        intel_edp_psr_init(dev);
 
-       list_for_each_entry(encoder, &dev->mode_config.encoder_list, base.head) {
+       for_each_intel_encoder(dev, encoder) {
                encoder->base.possible_crtcs = encoder->crtc_mask;
                encoder->base.possible_clones =
                        intel_encoder_clones(encoder);
@@ -12332,29 +12690,27 @@ static void intel_init_display(struct drm_device *dev)
                dev_priv->display.get_display_clock_speed =
                        i830_get_display_clock_speed;
 
-       if (HAS_PCH_SPLIT(dev)) {
-               if (IS_GEN5(dev)) {
-                       dev_priv->display.fdi_link_train = ironlake_fdi_link_train;
-                       dev_priv->display.write_eld = ironlake_write_eld;
-               } else if (IS_GEN6(dev)) {
-                       dev_priv->display.fdi_link_train = gen6_fdi_link_train;
-                       dev_priv->display.write_eld = ironlake_write_eld;
-                       dev_priv->display.modeset_global_resources =
-                               snb_modeset_global_resources;
-               } else if (IS_IVYBRIDGE(dev)) {
-                       /* FIXME: detect B0+ stepping and use auto training */
-                       dev_priv->display.fdi_link_train = ivb_manual_fdi_link_train;
-                       dev_priv->display.write_eld = ironlake_write_eld;
-                       dev_priv->display.modeset_global_resources =
-                               ivb_modeset_global_resources;
-               } else if (IS_HASWELL(dev) || IS_GEN8(dev)) {
-                       dev_priv->display.fdi_link_train = hsw_fdi_link_train;
-                       dev_priv->display.write_eld = haswell_write_eld;
-                       dev_priv->display.modeset_global_resources =
-                               haswell_modeset_global_resources;
-               }
-       } else if (IS_G4X(dev)) {
+       if (IS_G4X(dev)) {
                dev_priv->display.write_eld = g4x_write_eld;
+       } else if (IS_GEN5(dev)) {
+               dev_priv->display.fdi_link_train = ironlake_fdi_link_train;
+               dev_priv->display.write_eld = ironlake_write_eld;
+       } else if (IS_GEN6(dev)) {
+               dev_priv->display.fdi_link_train = gen6_fdi_link_train;
+               dev_priv->display.write_eld = ironlake_write_eld;
+               dev_priv->display.modeset_global_resources =
+                       snb_modeset_global_resources;
+       } else if (IS_IVYBRIDGE(dev)) {
+               /* FIXME: detect B0+ stepping and use auto training */
+               dev_priv->display.fdi_link_train = ivb_manual_fdi_link_train;
+               dev_priv->display.write_eld = ironlake_write_eld;
+               dev_priv->display.modeset_global_resources =
+                       ivb_modeset_global_resources;
+       } else if (IS_HASWELL(dev) || IS_BROADWELL(dev)) {
+               dev_priv->display.fdi_link_train = hsw_fdi_link_train;
+               dev_priv->display.write_eld = haswell_write_eld;
+               dev_priv->display.modeset_global_resources =
+                       haswell_modeset_global_resources;
        } else if (IS_VALLEYVIEW(dev)) {
                dev_priv->display.modeset_global_resources =
                        valleyview_modeset_global_resources;
@@ -12388,6 +12744,8 @@ static void intel_init_display(struct drm_device *dev)
        }
 
        intel_panel_init_backlight_funcs(dev);
+
+       mutex_init(&dev_priv->pps_mutex);
 }
 
 /*
@@ -12403,6 +12761,14 @@ static void quirk_pipea_force(struct drm_device *dev)
        DRM_INFO("applying pipe a force quirk\n");
 }
 
+static void quirk_pipeb_force(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+
+       dev_priv->quirks |= QUIRK_PIPEB_FORCE;
+       DRM_INFO("applying pipe b force quirk\n");
+}
+
 /*
  * Some machines (Lenovo U160) do not work with SSC on LVDS for some reason
  */
@@ -12477,6 +12843,12 @@ static struct intel_quirk intel_quirks[] = {
        /* ThinkPad T60 needs pipe A force quirk (bug #16494) */
        { 0x2782, 0x17aa, 0x201a, quirk_pipea_force },
 
+       /* 830 needs to leave pipe A & dpll A up */
+       { 0x3577, PCI_ANY_ID, PCI_ANY_ID, quirk_pipea_force },
+
+       /* 830 needs to leave pipe B & dpll B up */
+       { 0x3577, PCI_ANY_ID, PCI_ANY_ID, quirk_pipeb_force },
+
        /* Lenovo U160 cannot use SSC on LVDS */
        { 0x0046, 0x17aa, 0x3920, quirk_ssc_force_disable },
 
@@ -12550,7 +12922,11 @@ static void i915_disable_vga(struct drm_device *dev)
        vga_put(dev->pdev, VGA_RSRC_LEGACY_IO);
        udelay(300);
 
-       I915_WRITE(vga_reg, VGA_DISP_DISABLE);
+       /*
+        * Fujitsu-Siemens Lifebook S6010 (830) has problems resuming
+        * from S3 without preserving (some of?) the other bits.
+        */
+       I915_WRITE(vga_reg, dev_priv->bios_vgacntr | VGA_DISP_DISABLE);
        POSTING_READ(vga_reg);
 }
 
@@ -12563,8 +12939,6 @@ void intel_modeset_init_hw(struct drm_device *dev)
 
        intel_init_clock_gating(dev);
 
-       intel_reset_dpio(dev);
-
        intel_enable_gt_powersave(dev);
 }
 
@@ -12610,7 +12984,10 @@ void intel_modeset_init(struct drm_device *dev)
                dev->mode_config.max_height = 8192;
        }
 
-       if (IS_GEN2(dev)) {
+       if (IS_845G(dev) || IS_I865G(dev)) {
+               dev->mode_config.cursor_width = IS_845G(dev) ? 64 : 512;
+               dev->mode_config.cursor_height = 1023;
+       } else if (IS_GEN2(dev)) {
                dev->mode_config.cursor_width = GEN2_CURSOR_WIDTH;
                dev->mode_config.cursor_height = GEN2_CURSOR_HEIGHT;
        } else {
@@ -12624,7 +13001,7 @@ void intel_modeset_init(struct drm_device *dev)
                      INTEL_INFO(dev)->num_pipes,
                      INTEL_INFO(dev)->num_pipes > 1 ? "s" : "");
 
-       for_each_pipe(pipe) {
+       for_each_pipe(dev_priv, pipe) {
                intel_crtc_init(dev, pipe);
                for_each_sprite(pipe, sprite) {
                        ret = intel_plane_init(dev, pipe, sprite);
@@ -12635,10 +13012,11 @@ void intel_modeset_init(struct drm_device *dev)
        }
 
        intel_init_dpio(dev);
-       intel_reset_dpio(dev);
 
        intel_shared_dpll_init(dev);
 
+       /* save the BIOS value before clobbering it */
+       dev_priv->bios_vgacntr = I915_READ(i915_vgacntrl_reg(dev));
        /* Just disable it once at startup */
        i915_disable_vga(dev);
        intel_setup_outputs(dev);
@@ -12730,9 +13108,10 @@ static void intel_sanitize_crtc(struct intel_crtc *crtc)
        I915_WRITE(reg, I915_READ(reg) & ~PIPECONF_FRAME_START_DELAY_MASK);
 
        /* restore vblank interrupts to correct state */
-       if (crtc->active)
+       if (crtc->active) {
+               update_scanline_offset(crtc);
                drm_vblank_on(dev, crtc->pipe);
-       else
+       else
                drm_vblank_off(dev, crtc->pipe);
 
        /* We need to sanitize the plane -> pipe mapping first because this will
@@ -12815,7 +13194,7 @@ static void intel_sanitize_crtc(struct intel_crtc *crtc)
                }
        }
 
-       if (crtc->active || IS_VALLEYVIEW(dev) || INTEL_INFO(dev)->gen < 5) {
+       if (crtc->active || HAS_GMCH_DISPLAY(dev)) {
                /*
                 * We start out with underrun reporting disabled to avoid races.
                 * For correct bookkeeping mark this on active crtcs.
@@ -12831,8 +13210,6 @@ static void intel_sanitize_crtc(struct intel_crtc *crtc)
                 */
                crtc->cpu_fifo_underrun_disabled = true;
                crtc->pch_fifo_underrun_disabled = true;
-
-               update_scanline_offset(crtc);
        }
 }
 
@@ -12964,8 +13341,7 @@ static void intel_modeset_readout_hw_state(struct drm_device *dev)
                        intel_display_power_get(dev_priv, POWER_DOMAIN_PLLS);
        }
 
-       list_for_each_entry(encoder, &dev->mode_config.encoder_list,
-                           base.head) {
+       for_each_intel_encoder(dev, encoder) {
                pipe = 0;
 
                if (encoder->get_hw_state(encoder, &pipe)) {
@@ -13029,12 +13405,11 @@ void intel_modeset_setup_hw_state(struct drm_device *dev,
        }
 
        /* HW state is read out, now we need to sanitize this mess. */
-       list_for_each_entry(encoder, &dev->mode_config.encoder_list,
-                           base.head) {
+       for_each_intel_encoder(dev, encoder) {
                intel_sanitize_encoder(encoder);
        }
 
-       for_each_pipe(pipe) {
+       for_each_pipe(dev_priv, pipe) {
                crtc = to_intel_crtc(dev_priv->pipe_to_crtc_mapping[pipe]);
                intel_sanitize_crtc(crtc);
                intel_dump_pipe_config(crtc, &crtc->config, "[setup_hw_state]");
@@ -13062,7 +13437,7 @@ void intel_modeset_setup_hw_state(struct drm_device *dev,
                 * We need to use raw interfaces for restoring state to avoid
                 * checking (bogus) intermediate states.
                 */
-               for_each_pipe(pipe) {
+               for_each_pipe(dev_priv, pipe) {
                        struct drm_crtc *crtc =
                                dev_priv->pipe_to_crtc_mapping[pipe];
 
@@ -13283,7 +13658,7 @@ intel_display_capture_error_state(struct drm_device *dev)
        if (IS_HASWELL(dev) || IS_BROADWELL(dev))
                error->power_well_driver = I915_READ(HSW_PWR_WELL_DRIVER);
 
-       for_each_pipe(i) {
+       for_each_pipe(dev_priv, i) {
                error->pipe[i].power_domain_on =
                        intel_display_power_enabled_unlocked(dev_priv,
                                                           POWER_DOMAIN_PIPE(i));
@@ -13347,6 +13722,7 @@ intel_display_print_error_state(struct drm_i915_error_state_buf *m,
                                struct drm_device *dev,
                                struct intel_display_error_state *error)
 {
+       struct drm_i915_private *dev_priv = dev->dev_private;
        int i;
 
        if (!error)
@@ -13356,7 +13732,7 @@ intel_display_print_error_state(struct drm_i915_error_state_buf *m,
        if (IS_HASWELL(dev) || IS_BROADWELL(dev))
                err_printf(m, "PWR_WELL_CTL2: %08x\n",
                           error->power_well_driver);
-       for_each_pipe(i) {
+       for_each_pipe(dev_priv, i) {
                err_printf(m, "Pipe [%d]:\n", i);
                err_printf(m, "  Power: %s\n",
                           error->pipe[i].power_domain_on ? "on" : "off");
@@ -13397,3 +13773,25 @@ intel_display_print_error_state(struct drm_i915_error_state_buf *m,
                err_printf(m, "  VSYNC: %08x\n", error->transcoder[i].vsync);
        }
 }
+
+void intel_modeset_preclose(struct drm_device *dev, struct drm_file *file)
+{
+       struct intel_crtc *crtc;
+
+       for_each_intel_crtc(dev, crtc) {
+               struct intel_unpin_work *work;
+               unsigned long irqflags;
+
+               spin_lock_irqsave(&dev->event_lock, irqflags);
+
+               work = crtc->unpin_work;
+
+               if (work && work->event &&
+                   work->event->base.file_priv == file) {
+                       kfree(work->event);
+                       work->event = NULL;
+               }
+
+               spin_unlock_irqrestore(&dev->event_lock, irqflags);
+       }
+}
index fdff1d420c14ab3536717607975c6cfa273fb474..f6a3fdd5589e33420e2f9b15ef4de42193eea356 100644 (file)
@@ -111,7 +111,7 @@ static struct intel_dp *intel_attached_dp(struct drm_connector *connector)
 }
 
 static void intel_dp_link_down(struct intel_dp *intel_dp);
-static bool _edp_panel_vdd_on(struct intel_dp *intel_dp);
+static bool edp_panel_vdd_on(struct intel_dp *intel_dp);
 static void edp_panel_vdd_off(struct intel_dp *intel_dp, bool sync);
 
 int
@@ -290,32 +290,201 @@ intel_dp_init_panel_power_sequencer_registers(struct drm_device *dev,
                                              struct intel_dp *intel_dp,
                                              struct edp_power_seq *out);
 
+static void pps_lock(struct intel_dp *intel_dp)
+{
+       struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
+       struct intel_encoder *encoder = &intel_dig_port->base;
+       struct drm_device *dev = encoder->base.dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       enum intel_display_power_domain power_domain;
+
+       /*
+        * See vlv_power_sequencer_reset() why we need
+        * a power domain reference here.
+        */
+       power_domain = intel_display_port_power_domain(encoder);
+       intel_display_power_get(dev_priv, power_domain);
+
+       mutex_lock(&dev_priv->pps_mutex);
+}
+
+static void pps_unlock(struct intel_dp *intel_dp)
+{
+       struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
+       struct intel_encoder *encoder = &intel_dig_port->base;
+       struct drm_device *dev = encoder->base.dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       enum intel_display_power_domain power_domain;
+
+       mutex_unlock(&dev_priv->pps_mutex);
+
+       power_domain = intel_display_port_power_domain(encoder);
+       intel_display_power_put(dev_priv, power_domain);
+}
+
 static enum pipe
 vlv_power_sequencer_pipe(struct intel_dp *intel_dp)
 {
        struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
-       struct drm_crtc *crtc = intel_dig_port->base.base.crtc;
        struct drm_device *dev = intel_dig_port->base.base.dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
-       enum port port = intel_dig_port->port;
-       enum pipe pipe;
+       struct intel_encoder *encoder;
+       unsigned int pipes = (1 << PIPE_A) | (1 << PIPE_B);
+       struct edp_power_seq power_seq;
+
+       lockdep_assert_held(&dev_priv->pps_mutex);
 
-       /* modeset should have pipe */
-       if (crtc)
-               return to_intel_crtc(crtc)->pipe;
+       if (intel_dp->pps_pipe != INVALID_PIPE)
+               return intel_dp->pps_pipe;
+
+       /*
+        * We don't have power sequencer currently.
+        * Pick one that's not used by other ports.
+        */
+       list_for_each_entry(encoder, &dev->mode_config.encoder_list,
+                           base.head) {
+               struct intel_dp *tmp;
+
+               if (encoder->type != INTEL_OUTPUT_EDP)
+                       continue;
+
+               tmp = enc_to_intel_dp(&encoder->base);
+
+               if (tmp->pps_pipe != INVALID_PIPE)
+                       pipes &= ~(1 << tmp->pps_pipe);
+       }
+
+       /*
+        * Didn't find one. This should not happen since there
+        * are two power sequencers and up to two eDP ports.
+        */
+       if (WARN_ON(pipes == 0))
+               return PIPE_A;
+
+       intel_dp->pps_pipe = ffs(pipes) - 1;
+
+       DRM_DEBUG_KMS("picked pipe %c power sequencer for port %c\n",
+                     pipe_name(intel_dp->pps_pipe),
+                     port_name(intel_dig_port->port));
+
+       /* init power sequencer on this pipe and port */
+       intel_dp_init_panel_power_sequencer(dev, intel_dp, &power_seq);
+       intel_dp_init_panel_power_sequencer_registers(dev, intel_dp,
+                                                     &power_seq);
+
+       return intel_dp->pps_pipe;
+}
+
+typedef bool (*vlv_pipe_check)(struct drm_i915_private *dev_priv,
+                              enum pipe pipe);
+
+static bool vlv_pipe_has_pp_on(struct drm_i915_private *dev_priv,
+                              enum pipe pipe)
+{
+       return I915_READ(VLV_PIPE_PP_STATUS(pipe)) & PP_ON;
+}
+
+static bool vlv_pipe_has_vdd_on(struct drm_i915_private *dev_priv,
+                               enum pipe pipe)
+{
+       return I915_READ(VLV_PIPE_PP_CONTROL(pipe)) & EDP_FORCE_VDD;
+}
+
+static bool vlv_pipe_any(struct drm_i915_private *dev_priv,
+                        enum pipe pipe)
+{
+       return true;
+}
+
+static enum pipe
+vlv_initial_pps_pipe(struct drm_i915_private *dev_priv,
+                    enum port port,
+                    vlv_pipe_check pipe_check)
+{
+       enum pipe pipe;
 
-       /* init time, try to find a pipe with this port selected */
        for (pipe = PIPE_A; pipe <= PIPE_B; pipe++) {
                u32 port_sel = I915_READ(VLV_PIPE_PP_ON_DELAYS(pipe)) &
                        PANEL_PORT_SELECT_MASK;
-               if (port_sel == PANEL_PORT_SELECT_DPB_VLV && port == PORT_B)
-                       return pipe;
-               if (port_sel == PANEL_PORT_SELECT_DPC_VLV && port == PORT_C)
-                       return pipe;
+
+               if (port_sel != PANEL_PORT_SELECT_VLV(port))
+                       continue;
+
+               if (!pipe_check(dev_priv, pipe))
+                       continue;
+
+               return pipe;
        }
 
-       /* shrug */
-       return PIPE_A;
+       return INVALID_PIPE;
+}
+
+static void
+vlv_initial_power_sequencer_setup(struct intel_dp *intel_dp)
+{
+       struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
+       struct drm_device *dev = intel_dig_port->base.base.dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct edp_power_seq power_seq;
+       enum port port = intel_dig_port->port;
+
+       lockdep_assert_held(&dev_priv->pps_mutex);
+
+       /* try to find a pipe with this port selected */
+       /* first pick one where the panel is on */
+       intel_dp->pps_pipe = vlv_initial_pps_pipe(dev_priv, port,
+                                                 vlv_pipe_has_pp_on);
+       /* didn't find one? pick one where vdd is on */
+       if (intel_dp->pps_pipe == INVALID_PIPE)
+               intel_dp->pps_pipe = vlv_initial_pps_pipe(dev_priv, port,
+                                                         vlv_pipe_has_vdd_on);
+       /* didn't find one? pick one with just the correct port */
+       if (intel_dp->pps_pipe == INVALID_PIPE)
+               intel_dp->pps_pipe = vlv_initial_pps_pipe(dev_priv, port,
+                                                         vlv_pipe_any);
+
+       /* didn't find one? just let vlv_power_sequencer_pipe() pick one when needed */
+       if (intel_dp->pps_pipe == INVALID_PIPE) {
+               DRM_DEBUG_KMS("no initial power sequencer for port %c\n",
+                             port_name(port));
+               return;
+       }
+
+       DRM_DEBUG_KMS("initial power sequencer for port %c: pipe %c\n",
+                     port_name(port), pipe_name(intel_dp->pps_pipe));
+
+       intel_dp_init_panel_power_sequencer(dev, intel_dp, &power_seq);
+       intel_dp_init_panel_power_sequencer_registers(dev, intel_dp,
+                                                     &power_seq);
+}
+
+void vlv_power_sequencer_reset(struct drm_i915_private *dev_priv)
+{
+       struct drm_device *dev = dev_priv->dev;
+       struct intel_encoder *encoder;
+
+       if (WARN_ON(!IS_VALLEYVIEW(dev)))
+               return;
+
+       /*
+        * We can't grab pps_mutex here due to deadlock with power_domain
+        * mutex when power_domain functions are called while holding pps_mutex.
+        * That also means that in order to use pps_pipe the code needs to
+        * hold both a power domain reference and pps_mutex, and the power domain
+        * reference get/put must be done while _not_ holding pps_mutex.
+        * pps_{lock,unlock}() do these steps in the correct order, so one
+        * should use them always.
+        */
+
+       list_for_each_entry(encoder, &dev->mode_config.encoder_list, base.head) {
+               struct intel_dp *intel_dp;
+
+               if (encoder->type != INTEL_OUTPUT_EDP)
+                       continue;
+
+               intel_dp = enc_to_intel_dp(&encoder->base);
+               intel_dp->pps_pipe = INVALID_PIPE;
+       }
 }
 
 static u32 _pp_ctrl_reg(struct intel_dp *intel_dp)
@@ -349,12 +518,15 @@ static int edp_notify_handler(struct notifier_block *this, unsigned long code,
        struct drm_i915_private *dev_priv = dev->dev_private;
        u32 pp_div;
        u32 pp_ctrl_reg, pp_div_reg;
-       enum pipe pipe = vlv_power_sequencer_pipe(intel_dp);
 
        if (!is_edp(intel_dp) || code != SYS_RESTART)
                return 0;
 
+       pps_lock(intel_dp);
+
        if (IS_VALLEYVIEW(dev)) {
+               enum pipe pipe = vlv_power_sequencer_pipe(intel_dp);
+
                pp_ctrl_reg = VLV_PIPE_PP_CONTROL(pipe);
                pp_div_reg  = VLV_PIPE_PP_DIVISOR(pipe);
                pp_div = I915_READ(pp_div_reg);
@@ -366,6 +538,8 @@ static int edp_notify_handler(struct notifier_block *this, unsigned long code,
                msleep(intel_dp->panel_power_cycle_delay);
        }
 
+       pps_unlock(intel_dp);
+
        return 0;
 }
 
@@ -374,6 +548,8 @@ static bool edp_have_panel_power(struct intel_dp *intel_dp)
        struct drm_device *dev = intel_dp_to_dev(intel_dp);
        struct drm_i915_private *dev_priv = dev->dev_private;
 
+       lockdep_assert_held(&dev_priv->pps_mutex);
+
        return (I915_READ(_pp_stat_reg(intel_dp)) & PP_ON) != 0;
 }
 
@@ -381,13 +557,10 @@ static bool edp_have_panel_vdd(struct intel_dp *intel_dp)
 {
        struct drm_device *dev = intel_dp_to_dev(intel_dp);
        struct drm_i915_private *dev_priv = dev->dev_private;
-       struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
-       struct intel_encoder *intel_encoder = &intel_dig_port->base;
-       enum intel_display_power_domain power_domain;
 
-       power_domain = intel_display_port_power_domain(intel_encoder);
-       return intel_display_power_enabled(dev_priv, power_domain) &&
-              (I915_READ(_pp_ctrl_reg(intel_dp)) & EDP_FORCE_VDD) != 0;
+       lockdep_assert_held(&dev_priv->pps_mutex);
+
+       return I915_READ(_pp_ctrl_reg(intel_dp)) & EDP_FORCE_VDD;
 }
 
 static void
@@ -535,7 +708,15 @@ intel_dp_aux_ch(struct intel_dp *intel_dp,
        bool has_aux_irq = HAS_AUX_IRQ(dev);
        bool vdd;
 
-       vdd = _edp_panel_vdd_on(intel_dp);
+       pps_lock(intel_dp);
+
+       /*
+        * We will be called with VDD already enabled for dpcd/edid/oui reads.
+        * In such cases we want to leave VDD enabled and it's up to upper layers
+        * to turn it off. But for eg. i2c-dev access we need to turn it on/off
+        * ourselves.
+        */
+       vdd = edp_panel_vdd_on(intel_dp);
 
        /* dp aux is extremely sensitive to irq latency, hence request the
         * lowest possible wakeup latency and so prevent the cpu from going into
@@ -644,6 +825,8 @@ out:
        if (vdd)
                edp_panel_vdd_off(intel_dp, false);
 
+       pps_unlock(intel_dp);
+
        return ret;
 }
 
@@ -828,20 +1011,6 @@ intel_dp_set_clock(struct intel_encoder *encoder,
        }
 }
 
-static void
-intel_dp_set_m2_n2(struct intel_crtc *crtc, struct intel_link_m_n *m_n)
-{
-       struct drm_device *dev = crtc->base.dev;
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       enum transcoder transcoder = crtc->config.cpu_transcoder;
-
-       I915_WRITE(PIPE_DATA_M2(transcoder),
-               TU_SIZE(m_n->tu) | m_n->gmch_m);
-       I915_WRITE(PIPE_DATA_N2(transcoder), m_n->gmch_n);
-       I915_WRITE(PIPE_LINK_M2(transcoder), m_n->link_m);
-       I915_WRITE(PIPE_LINK_N2(transcoder), m_n->link_n);
-}
-
 bool
 intel_dp_compute_config(struct intel_encoder *encoder,
                        struct intel_crtc_config *pipe_config)
@@ -867,6 +1036,7 @@ intel_dp_compute_config(struct intel_encoder *encoder,
                pipe_config->has_pch_encoder = true;
 
        pipe_config->has_dp_encoder = true;
+       pipe_config->has_drrs = false;
        pipe_config->has_audio = intel_dp->has_audio;
 
        if (is_edp(intel_dp) && intel_connector->panel.fixed_mode) {
@@ -898,23 +1068,15 @@ intel_dp_compute_config(struct intel_encoder *encoder,
                        bpp = dev_priv->vbt.edp_bpp;
                }
 
-               if (IS_BROADWELL(dev)) {
-                       /* Yes, it's an ugly hack. */
-                       min_lane_count = max_lane_count;
-                       DRM_DEBUG_KMS("forcing lane count to max (%u) on BDW\n",
-                                     min_lane_count);
-               } else if (dev_priv->vbt.edp_lanes) {
-                       min_lane_count = min(dev_priv->vbt.edp_lanes,
-                                            max_lane_count);
-                       DRM_DEBUG_KMS("using min %u lanes per VBT\n",
-                                     min_lane_count);
-               }
-
-               if (dev_priv->vbt.edp_rate) {
-                       min_clock = min(dev_priv->vbt.edp_rate >> 3, max_clock);
-                       DRM_DEBUG_KMS("using min %02x link bw per VBT\n",
-                                     bws[min_clock]);
-               }
+               /*
+                * Use the maximum clock and number of lanes the eDP panel
+                * advertizes being capable of. The panels are generally
+                * designed to support only a single clock and lane
+                * configuration, and typically these values correspond to the
+                * native resolution of the panel.
+                */
+               min_lane_count = max_lane_count;
+               min_clock = max_clock;
        }
 
        for (; bpp >= 6*3; bpp -= 2*3) {
@@ -970,13 +1132,14 @@ found:
 
        if (intel_connector->panel.downclock_mode != NULL &&
                intel_dp->drrs_state.type == SEAMLESS_DRRS_SUPPORT) {
+                       pipe_config->has_drrs = true;
                        intel_link_compute_m_n(bpp, lane_count,
                                intel_connector->panel.downclock_mode->clock,
                                pipe_config->port_clock,
                                &pipe_config->dp_m2_n2);
        }
 
-       if (HAS_DDI(dev))
+       if (IS_HASWELL(dev) || IS_BROADWELL(dev))
                hsw_dp_set_ddi_pll_sel(pipe_config, intel_dp->link_bw);
        else
                intel_dp_set_clock(encoder, pipe_config, intel_dp->link_bw);
@@ -1110,6 +1273,8 @@ static void wait_panel_status(struct intel_dp *intel_dp,
        struct drm_i915_private *dev_priv = dev->dev_private;
        u32 pp_stat_reg, pp_ctrl_reg;
 
+       lockdep_assert_held(&dev_priv->pps_mutex);
+
        pp_stat_reg = _pp_stat_reg(intel_dp);
        pp_ctrl_reg = _pp_ctrl_reg(intel_dp);
 
@@ -1173,13 +1338,20 @@ static  u32 ironlake_get_pp_control(struct intel_dp *intel_dp)
        struct drm_i915_private *dev_priv = dev->dev_private;
        u32 control;
 
+       lockdep_assert_held(&dev_priv->pps_mutex);
+
        control = I915_READ(_pp_ctrl_reg(intel_dp));
        control &= ~PANEL_UNLOCK_MASK;
        control |= PANEL_UNLOCK_REGS;
        return control;
 }
 
-static bool _edp_panel_vdd_on(struct intel_dp *intel_dp)
+/*
+ * Must be paired with edp_panel_vdd_off().
+ * Must hold pps_mutex around the whole on/off sequence.
+ * Can be nested with intel_edp_panel_vdd_{on,off}() calls.
+ */
+static bool edp_panel_vdd_on(struct intel_dp *intel_dp)
 {
        struct drm_device *dev = intel_dp_to_dev(intel_dp);
        struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
@@ -1190,6 +1362,8 @@ static bool _edp_panel_vdd_on(struct intel_dp *intel_dp)
        u32 pp_stat_reg, pp_ctrl_reg;
        bool need_to_disable = !intel_dp->want_panel_vdd;
 
+       lockdep_assert_held(&dev_priv->pps_mutex);
+
        if (!is_edp(intel_dp))
                return false;
 
@@ -1227,62 +1401,76 @@ static bool _edp_panel_vdd_on(struct intel_dp *intel_dp)
        return need_to_disable;
 }
 
+/*
+ * Must be paired with intel_edp_panel_vdd_off() or
+ * intel_edp_panel_off().
+ * Nested calls to these functions are not allowed since
+ * we drop the lock. Caller must use some higher level
+ * locking to prevent nested calls from other threads.
+ */
 void intel_edp_panel_vdd_on(struct intel_dp *intel_dp)
 {
-       if (is_edp(intel_dp)) {
-               bool vdd = _edp_panel_vdd_on(intel_dp);
+       bool vdd;
 
-               WARN(!vdd, "eDP VDD already requested on\n");
-       }
+       if (!is_edp(intel_dp))
+               return;
+
+       pps_lock(intel_dp);
+       vdd = edp_panel_vdd_on(intel_dp);
+       pps_unlock(intel_dp);
+
+       WARN(!vdd, "eDP VDD already requested on\n");
 }
 
 static void edp_panel_vdd_off_sync(struct intel_dp *intel_dp)
 {
        struct drm_device *dev = intel_dp_to_dev(intel_dp);
        struct drm_i915_private *dev_priv = dev->dev_private;
+       struct intel_digital_port *intel_dig_port =
+               dp_to_dig_port(intel_dp);
+       struct intel_encoder *intel_encoder = &intel_dig_port->base;
+       enum intel_display_power_domain power_domain;
        u32 pp;
        u32 pp_stat_reg, pp_ctrl_reg;
 
-       WARN_ON(!drm_modeset_is_locked(&dev->mode_config.connection_mutex));
+       lockdep_assert_held(&dev_priv->pps_mutex);
 
-       if (!intel_dp->want_panel_vdd && edp_have_panel_vdd(intel_dp)) {
-               struct intel_digital_port *intel_dig_port =
-                                               dp_to_dig_port(intel_dp);
-               struct intel_encoder *intel_encoder = &intel_dig_port->base;
-               enum intel_display_power_domain power_domain;
+       WARN_ON(intel_dp->want_panel_vdd);
 
-               DRM_DEBUG_KMS("Turning eDP VDD off\n");
+       if (!edp_have_panel_vdd(intel_dp))
+               return;
 
-               pp = ironlake_get_pp_control(intel_dp);
-               pp &= ~EDP_FORCE_VDD;
+       DRM_DEBUG_KMS("Turning eDP VDD off\n");
 
-               pp_ctrl_reg = _pp_ctrl_reg(intel_dp);
-               pp_stat_reg = _pp_stat_reg(intel_dp);
+       pp = ironlake_get_pp_control(intel_dp);
+       pp &= ~EDP_FORCE_VDD;
 
-               I915_WRITE(pp_ctrl_reg, pp);
-               POSTING_READ(pp_ctrl_reg);
+       pp_ctrl_reg = _pp_ctrl_reg(intel_dp);
+       pp_stat_reg = _pp_stat_reg(intel_dp);
 
-               /* Make sure sequencer is idle before allowing subsequent activity */
-               DRM_DEBUG_KMS("PP_STATUS: 0x%08x PP_CONTROL: 0x%08x\n",
-               I915_READ(pp_stat_reg), I915_READ(pp_ctrl_reg));
+       I915_WRITE(pp_ctrl_reg, pp);
+       POSTING_READ(pp_ctrl_reg);
 
-               if ((pp & POWER_TARGET_ON) == 0)
-                       intel_dp->last_power_cycle = jiffies;
+       /* Make sure sequencer is idle before allowing subsequent activity */
+       DRM_DEBUG_KMS("PP_STATUS: 0x%08x PP_CONTROL: 0x%08x\n",
+       I915_READ(pp_stat_reg), I915_READ(pp_ctrl_reg));
 
-               power_domain = intel_display_port_power_domain(intel_encoder);
-               intel_display_power_put(dev_priv, power_domain);
-       }
+       if ((pp & POWER_TARGET_ON) == 0)
+               intel_dp->last_power_cycle = jiffies;
+
+       power_domain = intel_display_port_power_domain(intel_encoder);
+       intel_display_power_put(dev_priv, power_domain);
 }
 
 static void edp_panel_vdd_work(struct work_struct *__work)
 {
        struct intel_dp *intel_dp = container_of(to_delayed_work(__work),
                                                 struct intel_dp, panel_vdd_work);
-       struct drm_device *dev = intel_dp_to_dev(intel_dp);
 
-       drm_modeset_lock(&dev->mode_config.connection_mutex, NULL);
-       edp_panel_vdd_off_sync(intel_dp);
-       drm_modeset_unlock(&dev->mode_config.connection_mutex);
+       pps_lock(intel_dp);
+       if (!intel_dp->want_panel_vdd)
+               edp_panel_vdd_off_sync(intel_dp);
+       pps_unlock(intel_dp);
 }
 
 static void edp_panel_vdd_schedule_off(struct intel_dp *intel_dp)
@@ -1298,8 +1486,18 @@ static void edp_panel_vdd_schedule_off(struct intel_dp *intel_dp)
        schedule_delayed_work(&intel_dp->panel_vdd_work, delay);
 }
 
+/*
+ * Must be paired with edp_panel_vdd_on().
+ * Must hold pps_mutex around the whole on/off sequence.
+ * Can be nested with intel_edp_panel_vdd_{on,off}() calls.
+ */
 static void edp_panel_vdd_off(struct intel_dp *intel_dp, bool sync)
 {
+       struct drm_i915_private *dev_priv =
+               intel_dp_to_dev(intel_dp)->dev_private;
+
+       lockdep_assert_held(&dev_priv->pps_mutex);
+
        if (!is_edp(intel_dp))
                return;
 
@@ -1313,6 +1511,22 @@ static void edp_panel_vdd_off(struct intel_dp *intel_dp, bool sync)
                edp_panel_vdd_schedule_off(intel_dp);
 }
 
+/*
+ * Must be paired with intel_edp_panel_vdd_on().
+ * Nested calls to these functions are not allowed since
+ * we drop the lock. Caller must use some higher level
+ * locking to prevent nested calls from other threads.
+ */
+static void intel_edp_panel_vdd_off(struct intel_dp *intel_dp, bool sync)
+{
+       if (!is_edp(intel_dp))
+               return;
+
+       pps_lock(intel_dp);
+       edp_panel_vdd_off(intel_dp, sync);
+       pps_unlock(intel_dp);
+}
+
 void intel_edp_panel_on(struct intel_dp *intel_dp)
 {
        struct drm_device *dev = intel_dp_to_dev(intel_dp);
@@ -1325,9 +1539,11 @@ void intel_edp_panel_on(struct intel_dp *intel_dp)
 
        DRM_DEBUG_KMS("Turn eDP power on\n");
 
+       pps_lock(intel_dp);
+
        if (edp_have_panel_power(intel_dp)) {
                DRM_DEBUG_KMS("eDP power already on\n");
-               return;
+               goto out;
        }
 
        wait_panel_power_cycle(intel_dp);
@@ -1356,6 +1572,9 @@ void intel_edp_panel_on(struct intel_dp *intel_dp)
                I915_WRITE(pp_ctrl_reg, pp);
                POSTING_READ(pp_ctrl_reg);
        }
+
+ out:
+       pps_unlock(intel_dp);
 }
 
 void intel_edp_panel_off(struct intel_dp *intel_dp)
@@ -1373,6 +1592,8 @@ void intel_edp_panel_off(struct intel_dp *intel_dp)
 
        DRM_DEBUG_KMS("Turn eDP power off\n");
 
+       pps_lock(intel_dp);
+
        WARN(!intel_dp->want_panel_vdd, "Need VDD to turn off panel\n");
 
        pp = ironlake_get_pp_control(intel_dp);
@@ -1394,9 +1615,12 @@ void intel_edp_panel_off(struct intel_dp *intel_dp)
        /* We got a reference when we enabled the VDD. */
        power_domain = intel_display_port_power_domain(intel_encoder);
        intel_display_power_put(dev_priv, power_domain);
+
+       pps_unlock(intel_dp);
 }
 
-void intel_edp_backlight_on(struct intel_dp *intel_dp)
+/* Enable backlight in the panel power control. */
+static void _intel_edp_backlight_on(struct intel_dp *intel_dp)
 {
        struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
        struct drm_device *dev = intel_dig_port->base.base.dev;
@@ -1404,13 +1628,6 @@ void intel_edp_backlight_on(struct intel_dp *intel_dp)
        u32 pp;
        u32 pp_ctrl_reg;
 
-       if (!is_edp(intel_dp))
-               return;
-
-       DRM_DEBUG_KMS("\n");
-
-       intel_panel_enable_backlight(intel_dp->attached_connector);
-
        /*
         * If we enable the backlight right away following a panel power
         * on, we may see slight flicker as the panel syncs with the eDP
@@ -1418,6 +1635,9 @@ void intel_edp_backlight_on(struct intel_dp *intel_dp)
         * allowing it to appear.
         */
        wait_backlight_on(intel_dp);
+
+       pps_lock(intel_dp);
+
        pp = ironlake_get_pp_control(intel_dp);
        pp |= EDP_BLC_ENABLE;
 
@@ -1425,9 +1645,24 @@ void intel_edp_backlight_on(struct intel_dp *intel_dp)
 
        I915_WRITE(pp_ctrl_reg, pp);
        POSTING_READ(pp_ctrl_reg);
+
+       pps_unlock(intel_dp);
 }
 
-void intel_edp_backlight_off(struct intel_dp *intel_dp)
+/* Enable backlight PWM and backlight PP control. */
+void intel_edp_backlight_on(struct intel_dp *intel_dp)
+{
+       if (!is_edp(intel_dp))
+               return;
+
+       DRM_DEBUG_KMS("\n");
+
+       intel_panel_enable_backlight(intel_dp->attached_connector);
+       _intel_edp_backlight_on(intel_dp);
+}
+
+/* Disable backlight in the panel power control. */
+static void _intel_edp_backlight_off(struct intel_dp *intel_dp)
 {
        struct drm_device *dev = intel_dp_to_dev(intel_dp);
        struct drm_i915_private *dev_priv = dev->dev_private;
@@ -1437,7 +1672,8 @@ void intel_edp_backlight_off(struct intel_dp *intel_dp)
        if (!is_edp(intel_dp))
                return;
 
-       DRM_DEBUG_KMS("\n");
+       pps_lock(intel_dp);
+
        pp = ironlake_get_pp_control(intel_dp);
        pp &= ~EDP_BLC_ENABLE;
 
@@ -1445,13 +1681,51 @@ void intel_edp_backlight_off(struct intel_dp *intel_dp)
 
        I915_WRITE(pp_ctrl_reg, pp);
        POSTING_READ(pp_ctrl_reg);
-       intel_dp->last_backlight_off = jiffies;
 
+       pps_unlock(intel_dp);
+
+       intel_dp->last_backlight_off = jiffies;
        edp_wait_backlight_off(intel_dp);
+}
 
+/* Disable backlight PP control and backlight PWM. */
+void intel_edp_backlight_off(struct intel_dp *intel_dp)
+{
+       if (!is_edp(intel_dp))
+               return;
+
+       DRM_DEBUG_KMS("\n");
+
+       _intel_edp_backlight_off(intel_dp);
        intel_panel_disable_backlight(intel_dp->attached_connector);
 }
 
+/*
+ * Hook for controlling the panel power control backlight through the bl_power
+ * sysfs attribute. Take care to handle multiple calls.
+ */
+static void intel_edp_backlight_power(struct intel_connector *connector,
+                                     bool enable)
+{
+       struct intel_dp *intel_dp = intel_attached_dp(&connector->base);
+       bool is_enabled;
+
+       pps_lock(intel_dp);
+       is_enabled = ironlake_get_pp_control(intel_dp) & EDP_BLC_ENABLE;
+       pps_unlock(intel_dp);
+
+       if (is_enabled == enable)
+               return;
+
+       DRM_DEBUG_KMS("panel power control backlight %s\n",
+                     enable ? "enable" : "disable");
+
+       if (enable)
+               _intel_edp_backlight_on(intel_dp);
+       else
+               _intel_edp_backlight_off(intel_dp);
+}
+
 static void ironlake_edp_pll_on(struct intel_dp *intel_dp)
 {
        struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
@@ -1515,8 +1789,6 @@ void intel_dp_sink_dpms(struct intel_dp *intel_dp, int mode)
        if (mode != DRM_MODE_DPMS_ON) {
                ret = drm_dp_dpcd_writeb(&intel_dp->aux, DP_SET_POWER,
                                         DP_SET_POWER_D3);
-               if (ret != 1)
-                       DRM_DEBUG_DRIVER("failed to write sink power state\n");
        } else {
                /*
                 * When turning on, we need to retry for 1ms to give the sink
@@ -1530,6 +1802,10 @@ void intel_dp_sink_dpms(struct intel_dp *intel_dp, int mode)
                        msleep(1);
                }
        }
+
+       if (ret != 1)
+               DRM_DEBUG_KMS("failed to %s sink power state\n",
+                             mode == DRM_MODE_DPMS_ON ? "enable" : "disable");
 }
 
 static bool intel_dp_get_hw_state(struct intel_encoder *encoder,
@@ -1576,7 +1852,7 @@ static bool intel_dp_get_hw_state(struct intel_encoder *encoder,
                        return true;
                }
 
-               for_each_pipe(i) {
+               for_each_pipe(dev_priv, i) {
                        trans_dp = I915_READ(TRANS_DP_CTL(i));
                        if ((trans_dp & TRANS_DP_PORT_SEL_MASK) == trans_sel) {
                                *pipe = i;
@@ -2036,7 +2312,6 @@ void intel_edp_psr_init(struct drm_device *dev)
 static void intel_disable_dp(struct intel_encoder *encoder)
 {
        struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
-       enum port port = dp_to_dig_port(intel_dp)->port;
        struct drm_device *dev = encoder->base.dev;
 
        /* Make sure the panel is off before trying to change the mode. But also
@@ -2046,21 +2321,19 @@ static void intel_disable_dp(struct intel_encoder *encoder)
        intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_OFF);
        intel_edp_panel_off(intel_dp);
 
-       /* cpu edp my only be disable _after_ the cpu pipe/plane is disabled. */
-       if (!(port == PORT_A || IS_VALLEYVIEW(dev)))
+       /* disable the port before the pipe on g4x */
+       if (INTEL_INFO(dev)->gen < 5)
                intel_dp_link_down(intel_dp);
 }
 
-static void g4x_post_disable_dp(struct intel_encoder *encoder)
+static void ilk_post_disable_dp(struct intel_encoder *encoder)
 {
        struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
        enum port port = dp_to_dig_port(intel_dp)->port;
 
-       if (port != PORT_A)
-               return;
-
        intel_dp_link_down(intel_dp);
-       ironlake_edp_pll_off(intel_dp);
+       if (port == PORT_A)
+               ironlake_edp_pll_off(intel_dp);
 }
 
 static void vlv_post_disable_dp(struct intel_encoder *encoder)
@@ -2103,7 +2376,105 @@ static void chv_post_disable_dp(struct intel_encoder *encoder)
        val &= ~(DPIO_PCS_TX_LANE2_RESET | DPIO_PCS_TX_LANE1_RESET);
        vlv_dpio_write(dev_priv, pipe, VLV_PCS23_DW0(ch), val);
 
-       mutex_unlock(&dev_priv->dpio_lock);
+       mutex_unlock(&dev_priv->dpio_lock);
+}
+
+static void
+_intel_dp_set_link_train(struct intel_dp *intel_dp,
+                        uint32_t *DP,
+                        uint8_t dp_train_pat)
+{
+       struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
+       struct drm_device *dev = intel_dig_port->base.base.dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       enum port port = intel_dig_port->port;
+
+       if (HAS_DDI(dev)) {
+               uint32_t temp = I915_READ(DP_TP_CTL(port));
+
+               if (dp_train_pat & DP_LINK_SCRAMBLING_DISABLE)
+                       temp |= DP_TP_CTL_SCRAMBLE_DISABLE;
+               else
+                       temp &= ~DP_TP_CTL_SCRAMBLE_DISABLE;
+
+               temp &= ~DP_TP_CTL_LINK_TRAIN_MASK;
+               switch (dp_train_pat & DP_TRAINING_PATTERN_MASK) {
+               case DP_TRAINING_PATTERN_DISABLE:
+                       temp |= DP_TP_CTL_LINK_TRAIN_NORMAL;
+
+                       break;
+               case DP_TRAINING_PATTERN_1:
+                       temp |= DP_TP_CTL_LINK_TRAIN_PAT1;
+                       break;
+               case DP_TRAINING_PATTERN_2:
+                       temp |= DP_TP_CTL_LINK_TRAIN_PAT2;
+                       break;
+               case DP_TRAINING_PATTERN_3:
+                       temp |= DP_TP_CTL_LINK_TRAIN_PAT3;
+                       break;
+               }
+               I915_WRITE(DP_TP_CTL(port), temp);
+
+       } else if (HAS_PCH_CPT(dev) && (IS_GEN7(dev) || port != PORT_A)) {
+               *DP &= ~DP_LINK_TRAIN_MASK_CPT;
+
+               switch (dp_train_pat & DP_TRAINING_PATTERN_MASK) {
+               case DP_TRAINING_PATTERN_DISABLE:
+                       *DP |= DP_LINK_TRAIN_OFF_CPT;
+                       break;
+               case DP_TRAINING_PATTERN_1:
+                       *DP |= DP_LINK_TRAIN_PAT_1_CPT;
+                       break;
+               case DP_TRAINING_PATTERN_2:
+                       *DP |= DP_LINK_TRAIN_PAT_2_CPT;
+                       break;
+               case DP_TRAINING_PATTERN_3:
+                       DRM_ERROR("DP training pattern 3 not supported\n");
+                       *DP |= DP_LINK_TRAIN_PAT_2_CPT;
+                       break;
+               }
+
+       } else {
+               if (IS_CHERRYVIEW(dev))
+                       *DP &= ~DP_LINK_TRAIN_MASK_CHV;
+               else
+                       *DP &= ~DP_LINK_TRAIN_MASK;
+
+               switch (dp_train_pat & DP_TRAINING_PATTERN_MASK) {
+               case DP_TRAINING_PATTERN_DISABLE:
+                       *DP |= DP_LINK_TRAIN_OFF;
+                       break;
+               case DP_TRAINING_PATTERN_1:
+                       *DP |= DP_LINK_TRAIN_PAT_1;
+                       break;
+               case DP_TRAINING_PATTERN_2:
+                       *DP |= DP_LINK_TRAIN_PAT_2;
+                       break;
+               case DP_TRAINING_PATTERN_3:
+                       if (IS_CHERRYVIEW(dev)) {
+                               *DP |= DP_LINK_TRAIN_PAT_3_CHV;
+                       } else {
+                               DRM_ERROR("DP training pattern 3 not supported\n");
+                               *DP |= DP_LINK_TRAIN_PAT_2;
+                       }
+                       break;
+               }
+       }
+}
+
+static void intel_dp_enable_port(struct intel_dp *intel_dp)
+{
+       struct drm_device *dev = intel_dp_to_dev(intel_dp);
+       struct drm_i915_private *dev_priv = dev->dev_private;
+
+       intel_dp->DP |= DP_PORT_EN;
+
+       /* enable with pattern 1 (as per spec) */
+       _intel_dp_set_link_train(intel_dp, &intel_dp->DP,
+                                DP_TRAINING_PATTERN_1);
+
+       I915_WRITE(intel_dp->output_reg, intel_dp->DP);
+       POSTING_READ(intel_dp->output_reg);
 }
 
 static void intel_enable_dp(struct intel_encoder *encoder)
@@ -2116,11 +2487,12 @@ static void intel_enable_dp(struct intel_encoder *encoder)
        if (WARN_ON(dp_reg & DP_PORT_EN))
                return;
 
+       intel_dp_enable_port(intel_dp);
        intel_edp_panel_vdd_on(intel_dp);
+       intel_edp_panel_on(intel_dp);
+       intel_edp_panel_vdd_off(intel_dp, true);
        intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_ON);
        intel_dp_start_link_train(intel_dp);
-       intel_edp_panel_on(intel_dp);
-       edp_panel_vdd_off(intel_dp, true);
        intel_dp_complete_link_train(intel_dp);
        intel_dp_stop_link_train(intel_dp);
 }
@@ -2154,6 +2526,78 @@ static void g4x_pre_enable_dp(struct intel_encoder *encoder)
        }
 }
 
+static void vlv_steal_power_sequencer(struct drm_device *dev,
+                                     enum pipe pipe)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct intel_encoder *encoder;
+
+       lockdep_assert_held(&dev_priv->pps_mutex);
+
+       list_for_each_entry(encoder, &dev->mode_config.encoder_list,
+                           base.head) {
+               struct intel_dp *intel_dp;
+               enum port port;
+
+               if (encoder->type != INTEL_OUTPUT_EDP)
+                       continue;
+
+               intel_dp = enc_to_intel_dp(&encoder->base);
+               port = dp_to_dig_port(intel_dp)->port;
+
+               if (intel_dp->pps_pipe != pipe)
+                       continue;
+
+               DRM_DEBUG_KMS("stealing pipe %c power sequencer from port %c\n",
+                             pipe_name(pipe), port_name(port));
+
+               /* make sure vdd is off before we steal it */
+               edp_panel_vdd_off_sync(intel_dp);
+
+               intel_dp->pps_pipe = INVALID_PIPE;
+       }
+}
+
+static void vlv_init_panel_power_sequencer(struct intel_dp *intel_dp)
+{
+       struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
+       struct intel_encoder *encoder = &intel_dig_port->base;
+       struct drm_device *dev = encoder->base.dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct intel_crtc *crtc = to_intel_crtc(encoder->base.crtc);
+       struct edp_power_seq power_seq;
+
+       lockdep_assert_held(&dev_priv->pps_mutex);
+
+       if (intel_dp->pps_pipe == crtc->pipe)
+               return;
+
+       /*
+        * If another power sequencer was being used on this
+        * port previously make sure to turn off vdd there while
+        * we still have control of it.
+        */
+       if (intel_dp->pps_pipe != INVALID_PIPE)
+               edp_panel_vdd_off_sync(intel_dp);
+
+       /*
+        * We may be stealing the power
+        * sequencer from another port.
+        */
+       vlv_steal_power_sequencer(dev, crtc->pipe);
+
+       /* now it's all ours */
+       intel_dp->pps_pipe = crtc->pipe;
+
+       DRM_DEBUG_KMS("initializing pipe %c power sequencer for port %c\n",
+                     pipe_name(intel_dp->pps_pipe), port_name(intel_dig_port->port));
+
+       /* init power sequencer on this pipe and port */
+       intel_dp_init_panel_power_sequencer(dev, intel_dp, &power_seq);
+       intel_dp_init_panel_power_sequencer_registers(dev, intel_dp,
+                                                     &power_seq);
+}
+
 static void vlv_pre_enable_dp(struct intel_encoder *encoder)
 {
        struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
@@ -2163,7 +2607,6 @@ static void vlv_pre_enable_dp(struct intel_encoder *encoder)
        struct intel_crtc *intel_crtc = to_intel_crtc(encoder->base.crtc);
        enum dpio_channel port = vlv_dport_to_channel(dport);
        int pipe = intel_crtc->pipe;
-       struct edp_power_seq power_seq;
        u32 val;
 
        mutex_lock(&dev_priv->dpio_lock);
@@ -2182,10 +2625,9 @@ static void vlv_pre_enable_dp(struct intel_encoder *encoder)
        mutex_unlock(&dev_priv->dpio_lock);
 
        if (is_edp(intel_dp)) {
-               /* init power sequencer on this pipe and port */
-               intel_dp_init_panel_power_sequencer(dev, intel_dp, &power_seq);
-               intel_dp_init_panel_power_sequencer_registers(dev, intel_dp,
-                                                             &power_seq);
+               pps_lock(intel_dp);
+               vlv_init_panel_power_sequencer(intel_dp);
+               pps_unlock(intel_dp);
        }
 
        intel_enable_dp(encoder);
@@ -2229,7 +2671,6 @@ static void chv_pre_enable_dp(struct intel_encoder *encoder)
        struct intel_digital_port *dport = dp_to_dig_port(intel_dp);
        struct drm_device *dev = encoder->base.dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
-       struct edp_power_seq power_seq;
        struct intel_crtc *intel_crtc =
                to_intel_crtc(encoder->base.crtc);
        enum dpio_channel ch = vlv_dport_to_channel(dport);
@@ -2275,10 +2716,9 @@ static void chv_pre_enable_dp(struct intel_encoder *encoder)
        mutex_unlock(&dev_priv->dpio_lock);
 
        if (is_edp(intel_dp)) {
-               /* init power sequencer on this pipe and port */
-               intel_dp_init_panel_power_sequencer(dev, intel_dp, &power_seq);
-               intel_dp_init_panel_power_sequencer_registers(dev, intel_dp,
-                                                             &power_seq);
+               pps_lock(intel_dp);
+               vlv_init_panel_power_sequencer(intel_dp);
+               pps_unlock(intel_dp);
        }
 
        intel_enable_dp(encoder);
@@ -2297,6 +2737,8 @@ static void chv_dp_pre_pll_enable(struct intel_encoder *encoder)
        enum pipe pipe = intel_crtc->pipe;
        u32 val;
 
+       intel_dp_prepare(encoder);
+
        mutex_lock(&dev_priv->dpio_lock);
 
        /* program left/right clock distribution */
@@ -2395,13 +2837,13 @@ intel_dp_voltage_max(struct intel_dp *intel_dp)
        enum port port = dp_to_dig_port(intel_dp)->port;
 
        if (IS_VALLEYVIEW(dev))
-               return DP_TRAIN_VOLTAGE_SWING_1200;
+               return DP_TRAIN_VOLTAGE_SWING_LEVEL_3;
        else if (IS_GEN7(dev) && port == PORT_A)
-               return DP_TRAIN_VOLTAGE_SWING_800;
+               return DP_TRAIN_VOLTAGE_SWING_LEVEL_2;
        else if (HAS_PCH_CPT(dev) && port != PORT_A)
-               return DP_TRAIN_VOLTAGE_SWING_1200;
+               return DP_TRAIN_VOLTAGE_SWING_LEVEL_3;
        else
-               return DP_TRAIN_VOLTAGE_SWING_800;
+               return DP_TRAIN_VOLTAGE_SWING_LEVEL_2;
 }
 
 static uint8_t
@@ -2412,49 +2854,49 @@ intel_dp_pre_emphasis_max(struct intel_dp *intel_dp, uint8_t voltage_swing)
 
        if (IS_HASWELL(dev) || IS_BROADWELL(dev)) {
                switch (voltage_swing & DP_TRAIN_VOLTAGE_SWING_MASK) {
-               case DP_TRAIN_VOLTAGE_SWING_400:
-                       return DP_TRAIN_PRE_EMPHASIS_9_5;
-               case DP_TRAIN_VOLTAGE_SWING_600:
-                       return DP_TRAIN_PRE_EMPHASIS_6;
-               case DP_TRAIN_VOLTAGE_SWING_800:
-                       return DP_TRAIN_PRE_EMPHASIS_3_5;
-               case DP_TRAIN_VOLTAGE_SWING_1200:
+               case DP_TRAIN_VOLTAGE_SWING_LEVEL_0:
+                       return DP_TRAIN_PRE_EMPH_LEVEL_3;
+               case DP_TRAIN_VOLTAGE_SWING_LEVEL_1:
+                       return DP_TRAIN_PRE_EMPH_LEVEL_2;
+               case DP_TRAIN_VOLTAGE_SWING_LEVEL_2:
+                       return DP_TRAIN_PRE_EMPH_LEVEL_1;
+               case DP_TRAIN_VOLTAGE_SWING_LEVEL_3:
                default:
-                       return DP_TRAIN_PRE_EMPHASIS_0;
+                       return DP_TRAIN_PRE_EMPH_LEVEL_0;
                }
        } else if (IS_VALLEYVIEW(dev)) {
                switch (voltage_swing & DP_TRAIN_VOLTAGE_SWING_MASK) {
-               case DP_TRAIN_VOLTAGE_SWING_400:
-                       return DP_TRAIN_PRE_EMPHASIS_9_5;
-               case DP_TRAIN_VOLTAGE_SWING_600:
-                       return DP_TRAIN_PRE_EMPHASIS_6;
-               case DP_TRAIN_VOLTAGE_SWING_800:
-                       return DP_TRAIN_PRE_EMPHASIS_3_5;
-               case DP_TRAIN_VOLTAGE_SWING_1200:
+               case DP_TRAIN_VOLTAGE_SWING_LEVEL_0:
+                       return DP_TRAIN_PRE_EMPH_LEVEL_3;
+               case DP_TRAIN_VOLTAGE_SWING_LEVEL_1:
+                       return DP_TRAIN_PRE_EMPH_LEVEL_2;
+               case DP_TRAIN_VOLTAGE_SWING_LEVEL_2:
+                       return DP_TRAIN_PRE_EMPH_LEVEL_1;
+               case DP_TRAIN_VOLTAGE_SWING_LEVEL_3:
                default:
-                       return DP_TRAIN_PRE_EMPHASIS_0;
+                       return DP_TRAIN_PRE_EMPH_LEVEL_0;
                }
        } else if (IS_GEN7(dev) && port == PORT_A) {
                switch (voltage_swing & DP_TRAIN_VOLTAGE_SWING_MASK) {
-               case DP_TRAIN_VOLTAGE_SWING_400:
-                       return DP_TRAIN_PRE_EMPHASIS_6;
-               case DP_TRAIN_VOLTAGE_SWING_600:
-               case DP_TRAIN_VOLTAGE_SWING_800:
-                       return DP_TRAIN_PRE_EMPHASIS_3_5;
+               case DP_TRAIN_VOLTAGE_SWING_LEVEL_0:
+                       return DP_TRAIN_PRE_EMPH_LEVEL_2;
+               case DP_TRAIN_VOLTAGE_SWING_LEVEL_1:
+               case DP_TRAIN_VOLTAGE_SWING_LEVEL_2:
+                       return DP_TRAIN_PRE_EMPH_LEVEL_1;
                default:
-                       return DP_TRAIN_PRE_EMPHASIS_0;
+                       return DP_TRAIN_PRE_EMPH_LEVEL_0;
                }
        } else {
                switch (voltage_swing & DP_TRAIN_VOLTAGE_SWING_MASK) {
-               case DP_TRAIN_VOLTAGE_SWING_400:
-                       return DP_TRAIN_PRE_EMPHASIS_6;
-               case DP_TRAIN_VOLTAGE_SWING_600:
-                       return DP_TRAIN_PRE_EMPHASIS_6;
-               case DP_TRAIN_VOLTAGE_SWING_800:
-                       return DP_TRAIN_PRE_EMPHASIS_3_5;
-               case DP_TRAIN_VOLTAGE_SWING_1200:
+               case DP_TRAIN_VOLTAGE_SWING_LEVEL_0:
+                       return DP_TRAIN_PRE_EMPH_LEVEL_2;
+               case DP_TRAIN_VOLTAGE_SWING_LEVEL_1:
+                       return DP_TRAIN_PRE_EMPH_LEVEL_2;
+               case DP_TRAIN_VOLTAGE_SWING_LEVEL_2:
+                       return DP_TRAIN_PRE_EMPH_LEVEL_1;
+               case DP_TRAIN_VOLTAGE_SWING_LEVEL_3:
                default:
-                       return DP_TRAIN_PRE_EMPHASIS_0;
+                       return DP_TRAIN_PRE_EMPH_LEVEL_0;
                }
        }
 }
@@ -2473,22 +2915,22 @@ static uint32_t intel_vlv_signal_levels(struct intel_dp *intel_dp)
        int pipe = intel_crtc->pipe;
 
        switch (train_set & DP_TRAIN_PRE_EMPHASIS_MASK) {
-       case DP_TRAIN_PRE_EMPHASIS_0:
+       case DP_TRAIN_PRE_EMPH_LEVEL_0:
                preemph_reg_value = 0x0004000;
                switch (train_set & DP_TRAIN_VOLTAGE_SWING_MASK) {
-               case DP_TRAIN_VOLTAGE_SWING_400:
+               case DP_TRAIN_VOLTAGE_SWING_LEVEL_0:
                        demph_reg_value = 0x2B405555;
                        uniqtranscale_reg_value = 0x552AB83A;
                        break;
-               case DP_TRAIN_VOLTAGE_SWING_600:
+               case DP_TRAIN_VOLTAGE_SWING_LEVEL_1:
                        demph_reg_value = 0x2B404040;
                        uniqtranscale_reg_value = 0x5548B83A;
                        break;
-               case DP_TRAIN_VOLTAGE_SWING_800:
+               case DP_TRAIN_VOLTAGE_SWING_LEVEL_2:
                        demph_reg_value = 0x2B245555;
                        uniqtranscale_reg_value = 0x5560B83A;
                        break;
-               case DP_TRAIN_VOLTAGE_SWING_1200:
+               case DP_TRAIN_VOLTAGE_SWING_LEVEL_3:
                        demph_reg_value = 0x2B405555;
                        uniqtranscale_reg_value = 0x5598DA3A;
                        break;
@@ -2496,18 +2938,18 @@ static uint32_t intel_vlv_signal_levels(struct intel_dp *intel_dp)
                        return 0;
                }
                break;
-       case DP_TRAIN_PRE_EMPHASIS_3_5:
+       case DP_TRAIN_PRE_EMPH_LEVEL_1:
                preemph_reg_value = 0x0002000;
                switch (train_set & DP_TRAIN_VOLTAGE_SWING_MASK) {
-               case DP_TRAIN_VOLTAGE_SWING_400:
+               case DP_TRAIN_VOLTAGE_SWING_LEVEL_0:
                        demph_reg_value = 0x2B404040;
                        uniqtranscale_reg_value = 0x5552B83A;
                        break;
-               case DP_TRAIN_VOLTAGE_SWING_600:
+               case DP_TRAIN_VOLTAGE_SWING_LEVEL_1:
                        demph_reg_value = 0x2B404848;
                        uniqtranscale_reg_value = 0x5580B83A;
                        break;
-               case DP_TRAIN_VOLTAGE_SWING_800:
+               case DP_TRAIN_VOLTAGE_SWING_LEVEL_2:
                        demph_reg_value = 0x2B404040;
                        uniqtranscale_reg_value = 0x55ADDA3A;
                        break;
@@ -2515,14 +2957,14 @@ static uint32_t intel_vlv_signal_levels(struct intel_dp *intel_dp)
                        return 0;
                }
                break;
-       case DP_TRAIN_PRE_EMPHASIS_6:
+       case DP_TRAIN_PRE_EMPH_LEVEL_2:
                preemph_reg_value = 0x0000000;
                switch (train_set & DP_TRAIN_VOLTAGE_SWING_MASK) {
-               case DP_TRAIN_VOLTAGE_SWING_400:
+               case DP_TRAIN_VOLTAGE_SWING_LEVEL_0:
                        demph_reg_value = 0x2B305555;
                        uniqtranscale_reg_value = 0x5570B83A;
                        break;
-               case DP_TRAIN_VOLTAGE_SWING_600:
+               case DP_TRAIN_VOLTAGE_SWING_LEVEL_1:
                        demph_reg_value = 0x2B2B4040;
                        uniqtranscale_reg_value = 0x55ADDA3A;
                        break;
@@ -2530,10 +2972,10 @@ static uint32_t intel_vlv_signal_levels(struct intel_dp *intel_dp)
                        return 0;
                }
                break;
-       case DP_TRAIN_PRE_EMPHASIS_9_5:
+       case DP_TRAIN_PRE_EMPH_LEVEL_3:
                preemph_reg_value = 0x0006000;
                switch (train_set & DP_TRAIN_VOLTAGE_SWING_MASK) {
-               case DP_TRAIN_VOLTAGE_SWING_400:
+               case DP_TRAIN_VOLTAGE_SWING_LEVEL_0:
                        demph_reg_value = 0x1B405555;
                        uniqtranscale_reg_value = 0x55ADDA3A;
                        break;
@@ -2572,21 +3014,21 @@ static uint32_t intel_chv_signal_levels(struct intel_dp *intel_dp)
        int i;
 
        switch (train_set & DP_TRAIN_PRE_EMPHASIS_MASK) {
-       case DP_TRAIN_PRE_EMPHASIS_0:
+       case DP_TRAIN_PRE_EMPH_LEVEL_0:
                switch (train_set & DP_TRAIN_VOLTAGE_SWING_MASK) {
-               case DP_TRAIN_VOLTAGE_SWING_400:
+               case DP_TRAIN_VOLTAGE_SWING_LEVEL_0:
                        deemph_reg_value = 128;
                        margin_reg_value = 52;
                        break;
-               case DP_TRAIN_VOLTAGE_SWING_600:
+               case DP_TRAIN_VOLTAGE_SWING_LEVEL_1:
                        deemph_reg_value = 128;
                        margin_reg_value = 77;
                        break;
-               case DP_TRAIN_VOLTAGE_SWING_800:
+               case DP_TRAIN_VOLTAGE_SWING_LEVEL_2:
                        deemph_reg_value = 128;
                        margin_reg_value = 102;
                        break;
-               case DP_TRAIN_VOLTAGE_SWING_1200:
+               case DP_TRAIN_VOLTAGE_SWING_LEVEL_3:
                        deemph_reg_value = 128;
                        margin_reg_value = 154;
                        /* FIXME extra to set for 1200 */
@@ -2595,17 +3037,17 @@ static uint32_t intel_chv_signal_levels(struct intel_dp *intel_dp)
                        return 0;
                }
                break;
-       case DP_TRAIN_PRE_EMPHASIS_3_5:
+       case DP_TRAIN_PRE_EMPH_LEVEL_1:
                switch (train_set & DP_TRAIN_VOLTAGE_SWING_MASK) {
-               case DP_TRAIN_VOLTAGE_SWING_400:
+               case DP_TRAIN_VOLTAGE_SWING_LEVEL_0:
                        deemph_reg_value = 85;
                        margin_reg_value = 78;
                        break;
-               case DP_TRAIN_VOLTAGE_SWING_600:
+               case DP_TRAIN_VOLTAGE_SWING_LEVEL_1:
                        deemph_reg_value = 85;
                        margin_reg_value = 116;
                        break;
-               case DP_TRAIN_VOLTAGE_SWING_800:
+               case DP_TRAIN_VOLTAGE_SWING_LEVEL_2:
                        deemph_reg_value = 85;
                        margin_reg_value = 154;
                        break;
@@ -2613,13 +3055,13 @@ static uint32_t intel_chv_signal_levels(struct intel_dp *intel_dp)
                        return 0;
                }
                break;
-       case DP_TRAIN_PRE_EMPHASIS_6:
+       case DP_TRAIN_PRE_EMPH_LEVEL_2:
                switch (train_set & DP_TRAIN_VOLTAGE_SWING_MASK) {
-               case DP_TRAIN_VOLTAGE_SWING_400:
+               case DP_TRAIN_VOLTAGE_SWING_LEVEL_0:
                        deemph_reg_value = 64;
                        margin_reg_value = 104;
                        break;
-               case DP_TRAIN_VOLTAGE_SWING_600:
+               case DP_TRAIN_VOLTAGE_SWING_LEVEL_1:
                        deemph_reg_value = 64;
                        margin_reg_value = 154;
                        break;
@@ -2627,9 +3069,9 @@ static uint32_t intel_chv_signal_levels(struct intel_dp *intel_dp)
                        return 0;
                }
                break;
-       case DP_TRAIN_PRE_EMPHASIS_9_5:
+       case DP_TRAIN_PRE_EMPH_LEVEL_3:
                switch (train_set & DP_TRAIN_VOLTAGE_SWING_MASK) {
-               case DP_TRAIN_VOLTAGE_SWING_400:
+               case DP_TRAIN_VOLTAGE_SWING_LEVEL_0:
                        deemph_reg_value = 43;
                        margin_reg_value = 154;
                        break;
@@ -2663,8 +3105,8 @@ static uint32_t intel_chv_signal_levels(struct intel_dp *intel_dp)
        /* Program swing margin */
        for (i = 0; i < 4; i++) {
                val = vlv_dpio_read(dev_priv, pipe, CHV_TX_DW2(ch, i));
-               val &= ~DPIO_SWING_MARGIN_MASK;
-               val |= margin_reg_value << DPIO_SWING_MARGIN_SHIFT;
+               val &= ~DPIO_SWING_MARGIN000_MASK;
+               val |= margin_reg_value << DPIO_SWING_MARGIN000_SHIFT;
                vlv_dpio_write(dev_priv, pipe, CHV_TX_DW2(ch, i), val);
        }
 
@@ -2676,9 +3118,9 @@ static uint32_t intel_chv_signal_levels(struct intel_dp *intel_dp)
        }
 
        if (((train_set & DP_TRAIN_PRE_EMPHASIS_MASK)
-                       == DP_TRAIN_PRE_EMPHASIS_0) &&
+                       == DP_TRAIN_PRE_EMPH_LEVEL_0) &&
                ((train_set & DP_TRAIN_VOLTAGE_SWING_MASK)
-                       == DP_TRAIN_VOLTAGE_SWING_1200)) {
+                       == DP_TRAIN_VOLTAGE_SWING_LEVEL_3)) {
 
                /*
                 * The document said it needs to set bit 27 for ch0 and bit 26
@@ -2757,32 +3199,32 @@ intel_gen4_signal_levels(uint8_t train_set)
        uint32_t        signal_levels = 0;
 
        switch (train_set & DP_TRAIN_VOLTAGE_SWING_MASK) {
-       case DP_TRAIN_VOLTAGE_SWING_400:
+       case DP_TRAIN_VOLTAGE_SWING_LEVEL_0:
        default:
                signal_levels |= DP_VOLTAGE_0_4;
                break;
-       case DP_TRAIN_VOLTAGE_SWING_600:
+       case DP_TRAIN_VOLTAGE_SWING_LEVEL_1:
                signal_levels |= DP_VOLTAGE_0_6;
                break;
-       case DP_TRAIN_VOLTAGE_SWING_800:
+       case DP_TRAIN_VOLTAGE_SWING_LEVEL_2:
                signal_levels |= DP_VOLTAGE_0_8;
                break;
-       case DP_TRAIN_VOLTAGE_SWING_1200:
+       case DP_TRAIN_VOLTAGE_SWING_LEVEL_3:
                signal_levels |= DP_VOLTAGE_1_2;
                break;
        }
        switch (train_set & DP_TRAIN_PRE_EMPHASIS_MASK) {
-       case DP_TRAIN_PRE_EMPHASIS_0:
+       case DP_TRAIN_PRE_EMPH_LEVEL_0:
        default:
                signal_levels |= DP_PRE_EMPHASIS_0;
                break;
-       case DP_TRAIN_PRE_EMPHASIS_3_5:
+       case DP_TRAIN_PRE_EMPH_LEVEL_1:
                signal_levels |= DP_PRE_EMPHASIS_3_5;
                break;
-       case DP_TRAIN_PRE_EMPHASIS_6:
+       case DP_TRAIN_PRE_EMPH_LEVEL_2:
                signal_levels |= DP_PRE_EMPHASIS_6;
                break;
-       case DP_TRAIN_PRE_EMPHASIS_9_5:
+       case DP_TRAIN_PRE_EMPH_LEVEL_3:
                signal_levels |= DP_PRE_EMPHASIS_9_5;
                break;
        }
@@ -2796,19 +3238,19 @@ intel_gen6_edp_signal_levels(uint8_t train_set)
        int signal_levels = train_set & (DP_TRAIN_VOLTAGE_SWING_MASK |
                                         DP_TRAIN_PRE_EMPHASIS_MASK);
        switch (signal_levels) {
-       case DP_TRAIN_VOLTAGE_SWING_400 | DP_TRAIN_PRE_EMPHASIS_0:
-       case DP_TRAIN_VOLTAGE_SWING_600 | DP_TRAIN_PRE_EMPHASIS_0:
+       case DP_TRAIN_VOLTAGE_SWING_LEVEL_0 | DP_TRAIN_PRE_EMPH_LEVEL_0:
+       case DP_TRAIN_VOLTAGE_SWING_LEVEL_1 | DP_TRAIN_PRE_EMPH_LEVEL_0:
                return EDP_LINK_TRAIN_400_600MV_0DB_SNB_B;
-       case DP_TRAIN_VOLTAGE_SWING_400 | DP_TRAIN_PRE_EMPHASIS_3_5:
+       case DP_TRAIN_VOLTAGE_SWING_LEVEL_0 | DP_TRAIN_PRE_EMPH_LEVEL_1:
                return EDP_LINK_TRAIN_400MV_3_5DB_SNB_B;
-       case DP_TRAIN_VOLTAGE_SWING_400 | DP_TRAIN_PRE_EMPHASIS_6:
-       case DP_TRAIN_VOLTAGE_SWING_600 | DP_TRAIN_PRE_EMPHASIS_6:
+       case DP_TRAIN_VOLTAGE_SWING_LEVEL_0 | DP_TRAIN_PRE_EMPH_LEVEL_2:
+       case DP_TRAIN_VOLTAGE_SWING_LEVEL_1 | DP_TRAIN_PRE_EMPH_LEVEL_2:
                return EDP_LINK_TRAIN_400_600MV_6DB_SNB_B;
-       case DP_TRAIN_VOLTAGE_SWING_600 | DP_TRAIN_PRE_EMPHASIS_3_5:
-       case DP_TRAIN_VOLTAGE_SWING_800 | DP_TRAIN_PRE_EMPHASIS_3_5:
+       case DP_TRAIN_VOLTAGE_SWING_LEVEL_1 | DP_TRAIN_PRE_EMPH_LEVEL_1:
+       case DP_TRAIN_VOLTAGE_SWING_LEVEL_2 | DP_TRAIN_PRE_EMPH_LEVEL_1:
                return EDP_LINK_TRAIN_600_800MV_3_5DB_SNB_B;
-       case DP_TRAIN_VOLTAGE_SWING_800 | DP_TRAIN_PRE_EMPHASIS_0:
-       case DP_TRAIN_VOLTAGE_SWING_1200 | DP_TRAIN_PRE_EMPHASIS_0:
+       case DP_TRAIN_VOLTAGE_SWING_LEVEL_2 | DP_TRAIN_PRE_EMPH_LEVEL_0:
+       case DP_TRAIN_VOLTAGE_SWING_LEVEL_3 | DP_TRAIN_PRE_EMPH_LEVEL_0:
                return EDP_LINK_TRAIN_800_1200MV_0DB_SNB_B;
        default:
                DRM_DEBUG_KMS("Unsupported voltage swing/pre-emphasis level:"
@@ -2824,21 +3266,21 @@ intel_gen7_edp_signal_levels(uint8_t train_set)
        int signal_levels = train_set & (DP_TRAIN_VOLTAGE_SWING_MASK |
                                         DP_TRAIN_PRE_EMPHASIS_MASK);
        switch (signal_levels) {
-       case DP_TRAIN_VOLTAGE_SWING_400 | DP_TRAIN_PRE_EMPHASIS_0:
+       case DP_TRAIN_VOLTAGE_SWING_LEVEL_0 | DP_TRAIN_PRE_EMPH_LEVEL_0:
                return EDP_LINK_TRAIN_400MV_0DB_IVB;
-       case DP_TRAIN_VOLTAGE_SWING_400 | DP_TRAIN_PRE_EMPHASIS_3_5:
+       case DP_TRAIN_VOLTAGE_SWING_LEVEL_0 | DP_TRAIN_PRE_EMPH_LEVEL_1:
                return EDP_LINK_TRAIN_400MV_3_5DB_IVB;
-       case DP_TRAIN_VOLTAGE_SWING_400 | DP_TRAIN_PRE_EMPHASIS_6:
+       case DP_TRAIN_VOLTAGE_SWING_LEVEL_0 | DP_TRAIN_PRE_EMPH_LEVEL_2:
                return EDP_LINK_TRAIN_400MV_6DB_IVB;
 
-       case DP_TRAIN_VOLTAGE_SWING_600 | DP_TRAIN_PRE_EMPHASIS_0:
+       case DP_TRAIN_VOLTAGE_SWING_LEVEL_1 | DP_TRAIN_PRE_EMPH_LEVEL_0:
                return EDP_LINK_TRAIN_600MV_0DB_IVB;
-       case DP_TRAIN_VOLTAGE_SWING_600 | DP_TRAIN_PRE_EMPHASIS_3_5:
+       case DP_TRAIN_VOLTAGE_SWING_LEVEL_1 | DP_TRAIN_PRE_EMPH_LEVEL_1:
                return EDP_LINK_TRAIN_600MV_3_5DB_IVB;
 
-       case DP_TRAIN_VOLTAGE_SWING_800 | DP_TRAIN_PRE_EMPHASIS_0:
+       case DP_TRAIN_VOLTAGE_SWING_LEVEL_2 | DP_TRAIN_PRE_EMPH_LEVEL_0:
                return EDP_LINK_TRAIN_800MV_0DB_IVB;
-       case DP_TRAIN_VOLTAGE_SWING_800 | DP_TRAIN_PRE_EMPHASIS_3_5:
+       case DP_TRAIN_VOLTAGE_SWING_LEVEL_2 | DP_TRAIN_PRE_EMPH_LEVEL_1:
                return EDP_LINK_TRAIN_800MV_3_5DB_IVB;
 
        default:
@@ -2855,30 +3297,30 @@ intel_hsw_signal_levels(uint8_t train_set)
        int signal_levels = train_set & (DP_TRAIN_VOLTAGE_SWING_MASK |
                                         DP_TRAIN_PRE_EMPHASIS_MASK);
        switch (signal_levels) {
-       case DP_TRAIN_VOLTAGE_SWING_400 | DP_TRAIN_PRE_EMPHASIS_0:
-               return DDI_BUF_EMP_400MV_0DB_HSW;
-       case DP_TRAIN_VOLTAGE_SWING_400 | DP_TRAIN_PRE_EMPHASIS_3_5:
-               return DDI_BUF_EMP_400MV_3_5DB_HSW;
-       case DP_TRAIN_VOLTAGE_SWING_400 | DP_TRAIN_PRE_EMPHASIS_6:
-               return DDI_BUF_EMP_400MV_6DB_HSW;
-       case DP_TRAIN_VOLTAGE_SWING_400 | DP_TRAIN_PRE_EMPHASIS_9_5:
-               return DDI_BUF_EMP_400MV_9_5DB_HSW;
-
-       case DP_TRAIN_VOLTAGE_SWING_600 | DP_TRAIN_PRE_EMPHASIS_0:
-               return DDI_BUF_EMP_600MV_0DB_HSW;
-       case DP_TRAIN_VOLTAGE_SWING_600 | DP_TRAIN_PRE_EMPHASIS_3_5:
-               return DDI_BUF_EMP_600MV_3_5DB_HSW;
-       case DP_TRAIN_VOLTAGE_SWING_600 | DP_TRAIN_PRE_EMPHASIS_6:
-               return DDI_BUF_EMP_600MV_6DB_HSW;
-
-       case DP_TRAIN_VOLTAGE_SWING_800 | DP_TRAIN_PRE_EMPHASIS_0:
-               return DDI_BUF_EMP_800MV_0DB_HSW;
-       case DP_TRAIN_VOLTAGE_SWING_800 | DP_TRAIN_PRE_EMPHASIS_3_5:
-               return DDI_BUF_EMP_800MV_3_5DB_HSW;
+       case DP_TRAIN_VOLTAGE_SWING_LEVEL_0 | DP_TRAIN_PRE_EMPH_LEVEL_0:
+               return DDI_BUF_TRANS_SELECT(0);
+       case DP_TRAIN_VOLTAGE_SWING_LEVEL_0 | DP_TRAIN_PRE_EMPH_LEVEL_1:
+               return DDI_BUF_TRANS_SELECT(1);
+       case DP_TRAIN_VOLTAGE_SWING_LEVEL_0 | DP_TRAIN_PRE_EMPH_LEVEL_2:
+               return DDI_BUF_TRANS_SELECT(2);
+       case DP_TRAIN_VOLTAGE_SWING_LEVEL_0 | DP_TRAIN_PRE_EMPH_LEVEL_3:
+               return DDI_BUF_TRANS_SELECT(3);
+
+       case DP_TRAIN_VOLTAGE_SWING_LEVEL_1 | DP_TRAIN_PRE_EMPH_LEVEL_0:
+               return DDI_BUF_TRANS_SELECT(4);
+       case DP_TRAIN_VOLTAGE_SWING_LEVEL_1 | DP_TRAIN_PRE_EMPH_LEVEL_1:
+               return DDI_BUF_TRANS_SELECT(5);
+       case DP_TRAIN_VOLTAGE_SWING_LEVEL_1 | DP_TRAIN_PRE_EMPH_LEVEL_2:
+               return DDI_BUF_TRANS_SELECT(6);
+
+       case DP_TRAIN_VOLTAGE_SWING_LEVEL_2 | DP_TRAIN_PRE_EMPH_LEVEL_0:
+               return DDI_BUF_TRANS_SELECT(7);
+       case DP_TRAIN_VOLTAGE_SWING_LEVEL_2 | DP_TRAIN_PRE_EMPH_LEVEL_1:
+               return DDI_BUF_TRANS_SELECT(8);
        default:
                DRM_DEBUG_KMS("Unsupported voltage swing/pre-emphasis level:"
                              "0x%x\n", signal_levels);
-               return DDI_BUF_EMP_400MV_0DB_HSW;
+               return DDI_BUF_TRANS_SELECT(0);
        }
 }
 
@@ -2925,74 +3367,10 @@ intel_dp_set_link_train(struct intel_dp *intel_dp,
        struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
        struct drm_device *dev = intel_dig_port->base.base.dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
-       enum port port = intel_dig_port->port;
        uint8_t buf[sizeof(intel_dp->train_set) + 1];
        int ret, len;
 
-       if (HAS_DDI(dev)) {
-               uint32_t temp = I915_READ(DP_TP_CTL(port));
-
-               if (dp_train_pat & DP_LINK_SCRAMBLING_DISABLE)
-                       temp |= DP_TP_CTL_SCRAMBLE_DISABLE;
-               else
-                       temp &= ~DP_TP_CTL_SCRAMBLE_DISABLE;
-
-               temp &= ~DP_TP_CTL_LINK_TRAIN_MASK;
-               switch (dp_train_pat & DP_TRAINING_PATTERN_MASK) {
-               case DP_TRAINING_PATTERN_DISABLE:
-                       temp |= DP_TP_CTL_LINK_TRAIN_NORMAL;
-
-                       break;
-               case DP_TRAINING_PATTERN_1:
-                       temp |= DP_TP_CTL_LINK_TRAIN_PAT1;
-                       break;
-               case DP_TRAINING_PATTERN_2:
-                       temp |= DP_TP_CTL_LINK_TRAIN_PAT2;
-                       break;
-               case DP_TRAINING_PATTERN_3:
-                       temp |= DP_TP_CTL_LINK_TRAIN_PAT3;
-                       break;
-               }
-               I915_WRITE(DP_TP_CTL(port), temp);
-
-       } else if (HAS_PCH_CPT(dev) && (IS_GEN7(dev) || port != PORT_A)) {
-               *DP &= ~DP_LINK_TRAIN_MASK_CPT;
-
-               switch (dp_train_pat & DP_TRAINING_PATTERN_MASK) {
-               case DP_TRAINING_PATTERN_DISABLE:
-                       *DP |= DP_LINK_TRAIN_OFF_CPT;
-                       break;
-               case DP_TRAINING_PATTERN_1:
-                       *DP |= DP_LINK_TRAIN_PAT_1_CPT;
-                       break;
-               case DP_TRAINING_PATTERN_2:
-                       *DP |= DP_LINK_TRAIN_PAT_2_CPT;
-                       break;
-               case DP_TRAINING_PATTERN_3:
-                       DRM_ERROR("DP training pattern 3 not supported\n");
-                       *DP |= DP_LINK_TRAIN_PAT_2_CPT;
-                       break;
-               }
-
-       } else {
-               *DP &= ~DP_LINK_TRAIN_MASK;
-
-               switch (dp_train_pat & DP_TRAINING_PATTERN_MASK) {
-               case DP_TRAINING_PATTERN_DISABLE:
-                       *DP |= DP_LINK_TRAIN_OFF;
-                       break;
-               case DP_TRAINING_PATTERN_1:
-                       *DP |= DP_LINK_TRAIN_PAT_1;
-                       break;
-               case DP_TRAINING_PATTERN_2:
-                       *DP |= DP_LINK_TRAIN_PAT_2;
-                       break;
-               case DP_TRAINING_PATTERN_3:
-                       DRM_ERROR("DP training pattern 3 not supported\n");
-                       *DP |= DP_LINK_TRAIN_PAT_2;
-                       break;
-               }
-       }
+       _intel_dp_set_link_train(intel_dp, DP, dp_train_pat);
 
        I915_WRITE(intel_dp->output_reg, *DP);
        POSTING_READ(intel_dp->output_reg);
@@ -3276,7 +3654,10 @@ intel_dp_link_down(struct intel_dp *intel_dp)
                DP &= ~DP_LINK_TRAIN_MASK_CPT;
                I915_WRITE(intel_dp->output_reg, DP | DP_LINK_TRAIN_PAT_IDLE_CPT);
        } else {
-               DP &= ~DP_LINK_TRAIN_MASK;
+               if (IS_CHERRYVIEW(dev))
+                       DP &= ~DP_LINK_TRAIN_MASK_CHV;
+               else
+                       DP &= ~DP_LINK_TRAIN_MASK;
                I915_WRITE(intel_dp->output_reg, DP | DP_LINK_TRAIN_PAT_IDLE);
        }
        POSTING_READ(intel_dp->output_reg);
@@ -3322,15 +3703,11 @@ intel_dp_get_dpcd(struct intel_dp *intel_dp)
        struct drm_device *dev = dig_port->base.base.dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
 
-       char dpcd_hex_dump[sizeof(intel_dp->dpcd) * 3];
-
        if (intel_dp_dpcd_read_wake(&intel_dp->aux, 0x000, intel_dp->dpcd,
                                    sizeof(intel_dp->dpcd)) < 0)
                return false; /* aux transfer failed */
 
-       hex_dump_to_buffer(intel_dp->dpcd, sizeof(intel_dp->dpcd),
-                          32, 1, dpcd_hex_dump, sizeof(dpcd_hex_dump), false);
-       DRM_DEBUG_KMS("DPCD: %s\n", dpcd_hex_dump);
+       DRM_DEBUG_KMS("DPCD: %*ph\n", (int) sizeof(intel_dp->dpcd), intel_dp->dpcd);
 
        if (intel_dp->dpcd[DP_DPCD_REV] == 0)
                return false; /* DPCD not present */
@@ -3351,7 +3728,7 @@ intel_dp_get_dpcd(struct intel_dp *intel_dp)
        if (intel_dp->dpcd[DP_DPCD_REV] >= 0x12 &&
            intel_dp->dpcd[DP_MAX_LANE_COUNT] & DP_TPS3_SUPPORTED) {
                intel_dp->use_tps3 = true;
-               DRM_DEBUG_KMS("Displayport TPS3 supported");
+               DRM_DEBUG_KMS("Displayport TPS3 supported\n");
        } else
                intel_dp->use_tps3 = false;
 
@@ -3388,7 +3765,7 @@ intel_dp_probe_oui(struct intel_dp *intel_dp)
                DRM_DEBUG_KMS("Branch OUI: %02hx%02hx%02hx\n",
                              buf[0], buf[1], buf[2]);
 
-       edp_panel_vdd_off(intel_dp, false);
+       intel_edp_panel_vdd_off(intel_dp, false);
 }
 
 static bool
@@ -3402,7 +3779,7 @@ intel_dp_probe_mst(struct intel_dp *intel_dp)
        if (intel_dp->dpcd[DP_DPCD_REV] < 0x12)
                return false;
 
-       _edp_panel_vdd_on(intel_dp);
+       intel_edp_panel_vdd_on(intel_dp);
        if (intel_dp_dpcd_read_wake(&intel_dp->aux, DP_MSTM_CAP, buf, 1)) {
                if (buf[0] & DP_MST_CAP) {
                        DRM_DEBUG_KMS("Sink is MST capable\n");
@@ -3412,7 +3789,7 @@ intel_dp_probe_mst(struct intel_dp *intel_dp)
                        intel_dp->is_mst = false;
                }
        }
-       edp_panel_vdd_off(intel_dp, false);
+       intel_edp_panel_vdd_off(intel_dp, false);
 
        drm_dp_mst_topology_mgr_set_mst(&intel_dp->mst_mgr, intel_dp->is_mst);
        return intel_dp->is_mst;
@@ -3427,21 +3804,21 @@ int intel_dp_sink_crc(struct intel_dp *intel_dp, u8 *crc)
        u8 buf[1];
 
        if (drm_dp_dpcd_readb(&intel_dp->aux, DP_TEST_SINK_MISC, buf) < 0)
-               return -EAGAIN;
+               return -EIO;
 
        if (!(buf[0] & DP_TEST_CRC_SUPPORTED))
                return -ENOTTY;
 
        if (drm_dp_dpcd_writeb(&intel_dp->aux, DP_TEST_SINK,
                               DP_TEST_SINK_START) < 0)
-               return -EAGAIN;
+               return -EIO;
 
        /* Wait 2 vblanks to be sure we will have the correct CRC value */
        intel_wait_for_vblank(dev, intel_crtc->pipe);
        intel_wait_for_vblank(dev, intel_crtc->pipe);
 
        if (drm_dp_dpcd_read(&intel_dp->aux, DP_TEST_CRC_R_CR, crc, 6) < 0)
-               return -EAGAIN;
+               return -EIO;
 
        drm_dp_dpcd_writeb(&intel_dp->aux, DP_TEST_SINK, 0);
        return 0;
@@ -3643,21 +4020,25 @@ intel_dp_detect_dpcd(struct intel_dp *intel_dp)
        return connector_status_disconnected;
 }
 
+static enum drm_connector_status
+edp_detect(struct intel_dp *intel_dp)
+{
+       struct drm_device *dev = intel_dp_to_dev(intel_dp);
+       enum drm_connector_status status;
+
+       status = intel_panel_detect(dev);
+       if (status == connector_status_unknown)
+               status = connector_status_connected;
+
+       return status;
+}
+
 static enum drm_connector_status
 ironlake_dp_detect(struct intel_dp *intel_dp)
 {
        struct drm_device *dev = intel_dp_to_dev(intel_dp);
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
-       enum drm_connector_status status;
-
-       /* Can't disconnect eDP, but you can close the lid... */
-       if (is_edp(intel_dp)) {
-               status = intel_panel_detect(dev);
-               if (status == connector_status_unknown)
-                       status = connector_status_connected;
-               return status;
-       }
 
        if (!ibx_digital_port_connected(dev_priv, intel_dig_port))
                return connector_status_disconnected;
@@ -3733,9 +4114,9 @@ g4x_dp_detect(struct intel_dp *intel_dp)
 }
 
 static struct edid *
-intel_dp_get_edid(struct drm_connector *connector, struct i2c_adapter *adapter)
+intel_dp_get_edid(struct intel_dp *intel_dp)
 {
-       struct intel_connector *intel_connector = to_intel_connector(connector);
+       struct intel_connector *intel_connector = intel_dp->attached_connector;
 
        /* use cached edid if we have one */
        if (intel_connector->edid) {
@@ -3744,27 +4125,55 @@ intel_dp_get_edid(struct drm_connector *connector, struct i2c_adapter *adapter)
                        return NULL;
 
                return drm_edid_duplicate(intel_connector->edid);
-       }
+       } else
+               return drm_get_edid(&intel_connector->base,
+                                   &intel_dp->aux.ddc);
+}
+
+static void
+intel_dp_set_edid(struct intel_dp *intel_dp)
+{
+       struct intel_connector *intel_connector = intel_dp->attached_connector;
+       struct edid *edid;
 
-       return drm_get_edid(connector, adapter);
+       edid = intel_dp_get_edid(intel_dp);
+       intel_connector->detect_edid = edid;
+
+       if (intel_dp->force_audio != HDMI_AUDIO_AUTO)
+               intel_dp->has_audio = intel_dp->force_audio == HDMI_AUDIO_ON;
+       else
+               intel_dp->has_audio = drm_detect_monitor_audio(edid);
 }
 
-static int
-intel_dp_get_edid_modes(struct drm_connector *connector, struct i2c_adapter *adapter)
+static void
+intel_dp_unset_edid(struct intel_dp *intel_dp)
 {
-       struct intel_connector *intel_connector = to_intel_connector(connector);
+       struct intel_connector *intel_connector = intel_dp->attached_connector;
 
-       /* use cached edid if we have one */
-       if (intel_connector->edid) {
-               /* invalid edid */
-               if (IS_ERR(intel_connector->edid))
-                       return 0;
+       kfree(intel_connector->detect_edid);
+       intel_connector->detect_edid = NULL;
 
-               return intel_connector_update_modes(connector,
-                                                   intel_connector->edid);
-       }
+       intel_dp->has_audio = false;
+}
+
+static enum intel_display_power_domain
+intel_dp_power_get(struct intel_dp *dp)
+{
+       struct intel_encoder *encoder = &dp_to_dig_port(dp)->base;
+       enum intel_display_power_domain power_domain;
+
+       power_domain = intel_display_port_power_domain(encoder);
+       intel_display_power_get(to_i915(encoder->base.dev), power_domain);
+
+       return power_domain;
+}
 
-       return intel_ddc_get_modes(connector, adapter);
+static void
+intel_dp_power_put(struct intel_dp *dp,
+                  enum intel_display_power_domain power_domain)
+{
+       struct intel_encoder *encoder = &dp_to_dig_port(dp)->base;
+       intel_display_power_put(to_i915(encoder->base.dev), power_domain);
 }
 
 static enum drm_connector_status
@@ -3774,33 +4183,30 @@ intel_dp_detect(struct drm_connector *connector, bool force)
        struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
        struct intel_encoder *intel_encoder = &intel_dig_port->base;
        struct drm_device *dev = connector->dev;
-       struct drm_i915_private *dev_priv = dev->dev_private;
        enum drm_connector_status status;
        enum intel_display_power_domain power_domain;
-       struct edid *edid = NULL;
        bool ret;
 
-       power_domain = intel_display_port_power_domain(intel_encoder);
-       intel_display_power_get(dev_priv, power_domain);
-
        DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n",
                      connector->base.id, connector->name);
+       intel_dp_unset_edid(intel_dp);
 
        if (intel_dp->is_mst) {
                /* MST devices are disconnected from a monitor POV */
                if (intel_encoder->type != INTEL_OUTPUT_EDP)
                        intel_encoder->type = INTEL_OUTPUT_DISPLAYPORT;
-               status = connector_status_disconnected;
-               goto out;
+               return connector_status_disconnected;
        }
 
-       intel_dp->has_audio = false;
+       power_domain = intel_dp_power_get(intel_dp);
 
-       if (HAS_PCH_SPLIT(dev))
+       /* Can't disconnect eDP, but you can close the lid... */
+       if (is_edp(intel_dp))
+               status = edp_detect(intel_dp);
+       else if (HAS_PCH_SPLIT(dev))
                status = ironlake_dp_detect(intel_dp);
        else
                status = g4x_dp_detect(intel_dp);
-
        if (status != connector_status_connected)
                goto out;
 
@@ -3816,82 +4222,78 @@ intel_dp_detect(struct drm_connector *connector, bool force)
                goto out;
        }
 
-       if (intel_dp->force_audio != HDMI_AUDIO_AUTO) {
-               intel_dp->has_audio = (intel_dp->force_audio == HDMI_AUDIO_ON);
-       } else {
-               edid = intel_dp_get_edid(connector, &intel_dp->aux.ddc);
-               if (edid) {
-                       intel_dp->has_audio = drm_detect_monitor_audio(edid);
-                       kfree(edid);
-               }
-       }
+       intel_dp_set_edid(intel_dp);
 
        if (intel_encoder->type != INTEL_OUTPUT_EDP)
                intel_encoder->type = INTEL_OUTPUT_DISPLAYPORT;
        status = connector_status_connected;
 
 out:
-       intel_display_power_put(dev_priv, power_domain);
+       intel_dp_power_put(intel_dp, power_domain);
        return status;
 }
 
-static int intel_dp_get_modes(struct drm_connector *connector)
+static void
+intel_dp_force(struct drm_connector *connector)
 {
        struct intel_dp *intel_dp = intel_attached_dp(connector);
-       struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
-       struct intel_encoder *intel_encoder = &intel_dig_port->base;
-       struct intel_connector *intel_connector = to_intel_connector(connector);
-       struct drm_device *dev = connector->dev;
-       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct intel_encoder *intel_encoder = &dp_to_dig_port(intel_dp)->base;
        enum intel_display_power_domain power_domain;
-       int ret;
 
-       /* We should parse the EDID data and find out if it has an audio sink
-        */
+       DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n",
+                     connector->base.id, connector->name);
+       intel_dp_unset_edid(intel_dp);
 
-       power_domain = intel_display_port_power_domain(intel_encoder);
-       intel_display_power_get(dev_priv, power_domain);
+       if (connector->status != connector_status_connected)
+               return;
 
-       ret = intel_dp_get_edid_modes(connector, &intel_dp->aux.ddc);
-       intel_display_power_put(dev_priv, power_domain);
-       if (ret)
-               return ret;
+       power_domain = intel_dp_power_get(intel_dp);
+
+       intel_dp_set_edid(intel_dp);
+
+       intel_dp_power_put(intel_dp, power_domain);
+
+       if (intel_encoder->type != INTEL_OUTPUT_EDP)
+               intel_encoder->type = INTEL_OUTPUT_DISPLAYPORT;
+}
+
+static int intel_dp_get_modes(struct drm_connector *connector)
+{
+       struct intel_connector *intel_connector = to_intel_connector(connector);
+       struct edid *edid;
+
+       edid = intel_connector->detect_edid;
+       if (edid) {
+               int ret = intel_connector_update_modes(connector, edid);
+               if (ret)
+                       return ret;
+       }
 
        /* if eDP has no EDID, fall back to fixed mode */
-       if (is_edp(intel_dp) && intel_connector->panel.fixed_mode) {
+       if (is_edp(intel_attached_dp(connector)) &&
+           intel_connector->panel.fixed_mode) {
                struct drm_display_mode *mode;
-               mode = drm_mode_duplicate(dev,
+
+               mode = drm_mode_duplicate(connector->dev,
                                          intel_connector->panel.fixed_mode);
                if (mode) {
                        drm_mode_probed_add(connector, mode);
                        return 1;
                }
        }
+
        return 0;
 }
 
 static bool
 intel_dp_detect_audio(struct drm_connector *connector)
 {
-       struct intel_dp *intel_dp = intel_attached_dp(connector);
-       struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
-       struct intel_encoder *intel_encoder = &intel_dig_port->base;
-       struct drm_device *dev = connector->dev;
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       enum intel_display_power_domain power_domain;
-       struct edid *edid;
        bool has_audio = false;
+       struct edid *edid;
 
-       power_domain = intel_display_port_power_domain(intel_encoder);
-       intel_display_power_get(dev_priv, power_domain);
-
-       edid = intel_dp_get_edid(connector, &intel_dp->aux.ddc);
-       if (edid) {
+       edid = to_intel_connector(connector)->detect_edid;
+       if (edid)
                has_audio = drm_detect_monitor_audio(edid);
-               kfree(edid);
-       }
-
-       intel_display_power_put(dev_priv, power_domain);
 
        return has_audio;
 }
@@ -3989,6 +4391,8 @@ intel_dp_connector_destroy(struct drm_connector *connector)
 {
        struct intel_connector *intel_connector = to_intel_connector(connector);
 
+       kfree(intel_connector->detect_edid);
+
        if (!IS_ERR_OR_NULL(intel_connector->edid))
                kfree(intel_connector->edid);
 
@@ -4005,16 +4409,20 @@ void intel_dp_encoder_destroy(struct drm_encoder *encoder)
 {
        struct intel_digital_port *intel_dig_port = enc_to_dig_port(encoder);
        struct intel_dp *intel_dp = &intel_dig_port->dp;
-       struct drm_device *dev = intel_dp_to_dev(intel_dp);
 
        drm_dp_aux_unregister(&intel_dp->aux);
        intel_dp_mst_encoder_cleanup(intel_dig_port);
        drm_encoder_cleanup(encoder);
        if (is_edp(intel_dp)) {
                cancel_delayed_work_sync(&intel_dp->panel_vdd_work);
-               drm_modeset_lock(&dev->mode_config.connection_mutex, NULL);
+               /*
+                * vdd might still be enabled do to the delayed vdd off.
+                * Make sure vdd is actually turned off here.
+                */
+               pps_lock(intel_dp);
                edp_panel_vdd_off_sync(intel_dp);
-               drm_modeset_unlock(&dev->mode_config.connection_mutex);
+               pps_unlock(intel_dp);
+
                if (intel_dp->edp_notifier.notifier_call) {
                        unregister_reboot_notifier(&intel_dp->edp_notifier);
                        intel_dp->edp_notifier.notifier_call = NULL;
@@ -4030,7 +4438,13 @@ static void intel_dp_encoder_suspend(struct intel_encoder *intel_encoder)
        if (!is_edp(intel_dp))
                return;
 
+       /*
+        * vdd might still be enabled do to the delayed vdd off.
+        * Make sure vdd is actually turned off here.
+        */
+       pps_lock(intel_dp);
        edp_panel_vdd_off_sync(intel_dp);
+       pps_unlock(intel_dp);
 }
 
 static void intel_dp_encoder_reset(struct drm_encoder *encoder)
@@ -4041,6 +4455,7 @@ static void intel_dp_encoder_reset(struct drm_encoder *encoder)
 static const struct drm_connector_funcs intel_dp_connector_funcs = {
        .dpms = intel_connector_dpms,
        .detect = intel_dp_detect,
+       .force = intel_dp_force,
        .fill_modes = drm_helper_probe_single_connector_modes,
        .set_property = intel_dp_set_property,
        .destroy = intel_dp_connector_destroy,
@@ -4076,7 +4491,8 @@ intel_dp_hpd_pulse(struct intel_digital_port *intel_dig_port, bool long_hpd)
        if (intel_dig_port->base.type != INTEL_OUTPUT_EDP)
                intel_dig_port->base.type = INTEL_OUTPUT_DISPLAYPORT;
 
-       DRM_DEBUG_KMS("got hpd irq on port %d - %s\n", intel_dig_port->port,
+       DRM_DEBUG_KMS("got hpd irq on port %c - %s\n",
+                     port_name(intel_dig_port->port),
                      long_hpd ? "long" : "short");
 
        power_domain = intel_display_port_power_domain(intel_encoder);
@@ -4216,6 +4632,8 @@ intel_dp_init_panel_power_sequencer(struct drm_device *dev,
        u32 pp_on, pp_off, pp_div, pp;
        int pp_ctrl_reg, pp_on_reg, pp_off_reg, pp_div_reg;
 
+       lockdep_assert_held(&dev_priv->pps_mutex);
+
        if (HAS_PCH_SPLIT(dev)) {
                pp_ctrl_reg = PCH_PP_CONTROL;
                pp_on_reg = PCH_PP_ON_DELAYS;
@@ -4315,6 +4733,9 @@ intel_dp_init_panel_power_sequencer_registers(struct drm_device *dev,
        u32 pp_on, pp_off, pp_div, port_sel = 0;
        int div = HAS_PCH_SPLIT(dev) ? intel_pch_rawclk(dev) : intel_hrawclk(dev);
        int pp_on_reg, pp_off_reg, pp_div_reg;
+       enum port port = dp_to_dig_port(intel_dp)->port;
+
+       lockdep_assert_held(&dev_priv->pps_mutex);
 
        if (HAS_PCH_SPLIT(dev)) {
                pp_on_reg = PCH_PP_ON_DELAYS;
@@ -4349,12 +4770,9 @@ intel_dp_init_panel_power_sequencer_registers(struct drm_device *dev,
        /* Haswell doesn't have any port selection bits for the panel
         * power sequencer any more. */
        if (IS_VALLEYVIEW(dev)) {
-               if (dp_to_dig_port(intel_dp)->port == PORT_B)
-                       port_sel = PANEL_PORT_SELECT_DPB_VLV;
-               else
-                       port_sel = PANEL_PORT_SELECT_DPC_VLV;
+               port_sel = PANEL_PORT_SELECT_VLV(port);
        } else if (HAS_PCH_IBX(dev) || HAS_PCH_CPT(dev)) {
-               if (dp_to_dig_port(intel_dp)->port == PORT_A)
+               if (port == PORT_A)
                        port_sel = PANEL_PORT_SELECT_DPA;
                else
                        port_sel = PANEL_PORT_SELECT_DPD;
@@ -4438,7 +4856,7 @@ void intel_dp_set_drrs_state(struct drm_device *dev, int refresh_rate)
                val = I915_READ(reg);
                if (index > DRRS_HIGH_RR) {
                        val |= PIPECONF_EDP_RR_MODE_SWITCH;
-                       intel_dp_set_m2_n2(intel_crtc, &config->dp_m2_n2);
+                       intel_dp_set_m_n(intel_crtc);
                } else {
                        val &= ~PIPECONF_EDP_RR_MODE_SWITCH;
                }
@@ -4478,7 +4896,7 @@ intel_dp_drrs_init(struct intel_digital_port *intel_dig_port,
        }
 
        if (dev_priv->vbt.drrs_type != SEAMLESS_DRRS_SUPPORT) {
-               DRM_INFO("VBT doesn't support DRRS\n");
+               DRM_DEBUG_KMS("VBT doesn't support DRRS\n");
                return NULL;
        }
 
@@ -4486,7 +4904,7 @@ intel_dp_drrs_init(struct intel_digital_port *intel_dig_port,
                                        (dev, fixed_mode, connector);
 
        if (!downclock_mode) {
-               DRM_INFO("DRRS not supported\n");
+               DRM_DEBUG_KMS("DRRS not supported\n");
                return NULL;
        }
 
@@ -4497,7 +4915,7 @@ intel_dp_drrs_init(struct intel_digital_port *intel_dig_port,
        intel_dp->drrs_state.type = dev_priv->vbt.drrs_type;
 
        intel_dp->drrs_state.refresh_rate_type = DRRS_HIGH_RR;
-       DRM_INFO("seamless DRRS supported for eDP panel.\n");
+       DRM_DEBUG_KMS("seamless DRRS supported for eDP panel.\n");
        return downclock_mode;
 }
 
@@ -4512,8 +4930,11 @@ void intel_edp_panel_vdd_sanitize(struct intel_encoder *intel_encoder)
                return;
 
        intel_dp = enc_to_intel_dp(&intel_encoder->base);
+
+       pps_lock(intel_dp);
+
        if (!edp_have_panel_vdd(intel_dp))
-               return;
+               goto out;
        /*
         * The VDD bit needs a power domain reference, so if the bit is
         * already enabled when we boot or resume, grab this reference and
@@ -4525,6 +4946,8 @@ void intel_edp_panel_vdd_sanitize(struct intel_encoder *intel_encoder)
        intel_display_power_get(dev_priv, power_domain);
 
        edp_panel_vdd_schedule_off(intel_dp);
+ out:
+       pps_unlock(intel_dp);
 }
 
 static bool intel_edp_init_connector(struct intel_dp *intel_dp,
@@ -4552,7 +4975,7 @@ static bool intel_edp_init_connector(struct intel_dp *intel_dp,
        /* Cache DPCD and EDID for edp. */
        intel_edp_panel_vdd_on(intel_dp);
        has_dpcd = intel_dp_get_dpcd(intel_dp);
-       edp_panel_vdd_off(intel_dp, false);
+       intel_edp_panel_vdd_off(intel_dp, false);
 
        if (has_dpcd) {
                if (intel_dp->dpcd[DP_DPCD_REV] >= 0x11)
@@ -4566,7 +4989,9 @@ static bool intel_edp_init_connector(struct intel_dp *intel_dp,
        }
 
        /* We now know it's not a ghost, init power sequence regs. */
+       pps_lock(intel_dp);
        intel_dp_init_panel_power_sequencer_registers(dev, intel_dp, power_seq);
+       pps_unlock(intel_dp);
 
        mutex_lock(&dev->mode_config.mutex);
        edid = drm_get_edid(connector, &intel_dp->aux.ddc);
@@ -4610,6 +5035,7 @@ static bool intel_edp_init_connector(struct intel_dp *intel_dp,
        }
 
        intel_panel_init(&intel_connector->panel, fixed_mode, downclock_mode);
+       intel_connector->panel.backlight_power = intel_edp_backlight_power;
        intel_panel_setup_backlight(connector);
 
        return true;
@@ -4628,6 +5054,8 @@ intel_dp_init_connector(struct intel_digital_port *intel_dig_port,
        struct edp_power_seq power_seq = { 0 };
        int type;
 
+       intel_dp->pps_pipe = INVALID_PIPE;
+
        /* intel_dp vfuncs */
        if (IS_VALLEYVIEW(dev))
                intel_dp->get_aux_clock_divider = vlv_get_aux_clock_divider;
@@ -4698,8 +5126,15 @@ intel_dp_init_connector(struct intel_digital_port *intel_dig_port,
        }
 
        if (is_edp(intel_dp)) {
-               intel_dp_init_panel_power_timestamps(intel_dp);
-               intel_dp_init_panel_power_sequencer(dev, intel_dp, &power_seq);
+               pps_lock(intel_dp);
+               if (IS_VALLEYVIEW(dev)) {
+                       vlv_initial_power_sequencer_setup(intel_dp);
+               } else {
+                       intel_dp_init_panel_power_timestamps(intel_dp);
+                       intel_dp_init_panel_power_sequencer(dev, intel_dp,
+                                                           &power_seq);
+               }
+               pps_unlock(intel_dp);
        }
 
        intel_dp_aux_init(intel_dp, intel_connector);
@@ -4707,7 +5142,8 @@ intel_dp_init_connector(struct intel_digital_port *intel_dig_port,
        /* init MST on ports that can support it */
        if (IS_HASWELL(dev) || IS_BROADWELL(dev)) {
                if (port == PORT_B || port == PORT_C || port == PORT_D) {
-                       intel_dp_mst_encoder_init(intel_dig_port, intel_connector->base.base.id);
+                       intel_dp_mst_encoder_init(intel_dig_port,
+                                                 intel_connector->base.base.id);
                }
        }
 
@@ -4715,9 +5151,13 @@ intel_dp_init_connector(struct intel_digital_port *intel_dig_port,
                drm_dp_aux_unregister(&intel_dp->aux);
                if (is_edp(intel_dp)) {
                        cancel_delayed_work_sync(&intel_dp->panel_vdd_work);
-                       drm_modeset_lock(&dev->mode_config.connection_mutex, NULL);
+                       /*
+                        * vdd might still be enabled do to the delayed vdd off.
+                        * Make sure vdd is actually turned off here.
+                        */
+                       pps_lock(intel_dp);
                        edp_panel_vdd_off_sync(intel_dp);
-                       drm_modeset_unlock(&dev->mode_config.connection_mutex);
+                       pps_unlock(intel_dp);
                }
                drm_connector_unregister(connector);
                drm_connector_cleanup(connector);
@@ -4781,7 +5221,8 @@ intel_dp_init(struct drm_device *dev, int output_reg, enum port port)
        } else {
                intel_encoder->pre_enable = g4x_pre_enable_dp;
                intel_encoder->enable = g4x_enable_dp;
-               intel_encoder->post_disable = g4x_post_disable_dp;
+               if (INTEL_INFO(dev)->gen >= 5)
+                       intel_encoder->post_disable = ilk_post_disable_dp;
        }
 
        intel_dig_port->port = port;
index b8c8bbd8e5f990b256ffe20f853395dbe6e784a2..07ce04683c3091a11afeacdee99e3b1b41c03461 100644 (file)
@@ -25,6 +25,7 @@
 #ifndef __INTEL_DRV_H__
 #define __INTEL_DRV_H__
 
+#include <linux/async.h>
 #include <linux/i2c.h>
 #include <linux/hdmi.h>
 #include <drm/i915_drm.h>
@@ -179,6 +180,8 @@ struct intel_panel {
                bool active_low_pwm;
                struct backlight_device *device;
        } backlight;
+
+       void (*backlight_power)(struct intel_connector *, bool enable);
 };
 
 struct intel_connector {
@@ -211,6 +214,7 @@ struct intel_connector {
 
        /* Cached EDID for eDP and LVDS. May hold ERR_PTR for invalid EDID. */
        struct edid *edid;
+       struct edid *detect_edid;
 
        /* since POLL and HPD connectors may use the same HPD line keep the native
           state of connector->polled in case hotplug storm detection changes it */
@@ -330,6 +334,7 @@ struct intel_crtc_config {
 
        /* m2_n2 for eDP downclock */
        struct intel_link_m_n dp_m2_n2;
+       bool has_drrs;
 
        /*
         * Frequence the dpll for the port should run at. Differs from the
@@ -410,6 +415,7 @@ struct intel_crtc {
        uint32_t cursor_addr;
        int16_t cursor_width, cursor_height;
        uint32_t cursor_cntl;
+       uint32_t cursor_size;
        uint32_t cursor_base;
 
        struct intel_plane_config plane_config;
@@ -430,8 +436,6 @@ struct intel_crtc {
                struct intel_pipe_wm active;
        } wm;
 
-       wait_queue_head_t vbl_wait;
-
        int scanline_offset;
        struct intel_mmio_flip mmio_flip;
 };
@@ -455,6 +459,7 @@ struct intel_plane {
        unsigned int crtc_w, crtc_h;
        uint32_t src_x, src_y;
        uint32_t src_w, src_h;
+       unsigned int rotation;
 
        /* Since we need to change the watermarks before/after
         * enabling/disabling the planes, we need to store the parameters here
@@ -565,6 +570,12 @@ struct intel_dp {
 
        struct notifier_block edp_notifier;
 
+       /*
+        * Pipe whose power sequencer is currently locked into
+        * this port. Only relevant on VLV/CHV.
+        */
+       enum pipe pps_pipe;
+
        bool use_tps3;
        bool can_mst; /* this port supports mst */
        bool is_mst;
@@ -663,6 +674,10 @@ struct intel_unpin_work {
 #define INTEL_FLIP_COMPLETE    2
        u32 flip_count;
        u32 gtt_offset;
+       struct intel_engine_cs *flip_queued_ring;
+       u32 flip_queued_seqno;
+       int flip_queued_vblank;
+       int flip_ready_vblank;
        bool enable_stall_check;
 };
 
@@ -827,7 +842,6 @@ int intel_get_pipe_from_crtc_id(struct drm_device *dev, void *data,
 enum transcoder intel_pipe_to_cpu_transcoder(struct drm_i915_private *dev_priv,
                                             enum pipe pipe);
 void intel_wait_for_vblank(struct drm_device *dev, int pipe);
-void intel_wait_for_pipe_off(struct drm_device *dev, int pipe);
 int ironlake_get_lanes_required(int target_clock, int link_bw, int bpp);
 void vlv_wait_port_ready(struct drm_i915_private *dev_priv,
                         struct intel_digital_port *dport);
@@ -848,6 +862,7 @@ __intel_framebuffer_create(struct drm_device *dev,
 void intel_prepare_page_flip(struct drm_device *dev, int plane);
 void intel_finish_page_flip(struct drm_device *dev, int pipe);
 void intel_finish_page_flip_plane(struct drm_device *dev, int plane);
+void intel_check_page_flip(struct drm_device *dev, int pipe);
 
 /* shared dpll functions */
 struct intel_shared_dpll *intel_crtc_to_shared_dpll(struct intel_crtc *crtc);
@@ -882,6 +897,7 @@ void hsw_enable_pc8(struct drm_i915_private *dev_priv);
 void hsw_disable_pc8(struct drm_i915_private *dev_priv);
 void intel_dp_get_m_n(struct intel_crtc *crtc,
                      struct intel_crtc_config *pipe_config);
+void intel_dp_set_m_n(struct intel_crtc *crtc);
 int intel_dotclock_calculate(int link_freq, const struct intel_link_m_n *m_n);
 void
 ironlake_check_encoder_dotclock(const struct intel_crtc_config *pipe_config,
@@ -896,7 +912,7 @@ void intel_mode_from_pipe_config(struct drm_display_mode *mode,
                                 struct intel_crtc_config *pipe_config);
 int intel_format_to_fourcc(int format);
 void intel_crtc_wait_for_pending_flips(struct drm_crtc *crtc);
-
+void intel_modeset_preclose(struct drm_device *dev, struct drm_file *file);
 
 /* intel_dp.c */
 void intel_dp_init(struct drm_device *dev, int output_reg, enum port port);
@@ -935,6 +951,7 @@ void intel_dp_mst_suspend(struct drm_device *dev);
 void intel_dp_mst_resume(struct drm_device *dev);
 int intel_dp_max_link_bw(struct intel_dp *intel_dp);
 void intel_dp_hot_plug(struct intel_encoder *intel_encoder);
+void vlv_power_sequencer_reset(struct drm_i915_private *dev_priv);
 /* intel_dp_mst.c */
 int intel_dp_mst_encoder_init(struct intel_digital_port *intel_dig_port, int conn_id);
 void intel_dp_mst_encoder_cleanup(struct intel_digital_port *intel_dig_port);
@@ -949,9 +966,9 @@ void intel_dvo_init(struct drm_device *dev);
 /* legacy fbdev emulation in intel_fbdev.c */
 #ifdef CONFIG_DRM_I915_FBDEV
 extern int intel_fbdev_init(struct drm_device *dev);
-extern void intel_fbdev_initial_config(struct drm_device *dev);
+extern void intel_fbdev_initial_config(void *data, async_cookie_t cookie);
 extern void intel_fbdev_fini(struct drm_device *dev);
-extern void intel_fbdev_set_suspend(struct drm_device *dev, int state);
+extern void intel_fbdev_set_suspend(struct drm_device *dev, int state, bool synchronous);
 extern void intel_fbdev_output_poll_changed(struct drm_device *dev);
 extern void intel_fbdev_restore_mode(struct drm_device *dev);
 #else
@@ -960,7 +977,7 @@ static inline int intel_fbdev_init(struct drm_device *dev)
        return 0;
 }
 
-static inline void intel_fbdev_initial_config(struct drm_device *dev)
+static inline void intel_fbdev_initial_config(void *data, async_cookie_t cookie)
 {
 }
 
@@ -968,7 +985,7 @@ static inline void intel_fbdev_fini(struct drm_device *dev)
 {
 }
 
-static inline void intel_fbdev_set_suspend(struct drm_device *dev, int state)
+static inline void intel_fbdev_set_suspend(struct drm_device *dev, int state, bool synchronous)
 {
 }
 
@@ -1091,7 +1108,10 @@ bool intel_sdvo_init(struct drm_device *dev, uint32_t sdvo_reg, bool is_sdvob);
 int intel_plane_init(struct drm_device *dev, enum pipe pipe, int plane);
 void intel_flush_primary_plane(struct drm_i915_private *dev_priv,
                               enum plane plane);
-void intel_plane_restore(struct drm_plane *plane);
+int intel_plane_set_property(struct drm_plane *plane,
+                            struct drm_property *prop,
+                            uint64_t val);
+int intel_plane_restore(struct drm_plane *plane);
 void intel_plane_disable(struct drm_plane *plane);
 int intel_sprite_set_colorkey(struct drm_device *dev, void *data,
                              struct drm_file *file_priv);
index 670c29a7b5dd8e2a10867be9d742ace0e6ad3e11..5bd9e09ad3c5ddac4202a6f21e6fb7198572ffb2 100644 (file)
@@ -184,7 +184,7 @@ static void intel_dsi_pre_enable(struct intel_encoder *encoder)
 
        /* update the hw state for DPLL */
        intel_crtc->config.dpll_hw_state.dpll = DPLL_INTEGRATED_CLOCK_VLV |
-                                               DPLL_REFA_CLK_ENABLE_VLV;
+               DPLL_REFA_CLK_ENABLE_VLV;
 
        tmp = I915_READ(DSPCLK_GATE_D);
        tmp |= DPOUNIT_CLOCK_GATE_DISABLE;
@@ -259,8 +259,8 @@ static void intel_dsi_disable(struct intel_encoder *encoder)
        temp = I915_READ(MIPI_CTRL(pipe));
        temp &= ~ESCAPE_CLOCK_DIVIDER_MASK;
        I915_WRITE(MIPI_CTRL(pipe), temp |
-                       intel_dsi->escape_clk_div <<
-                       ESCAPE_CLOCK_DIVIDER_SHIFT);
+                  intel_dsi->escape_clk_div <<
+                  ESCAPE_CLOCK_DIVIDER_SHIFT);
 
        I915_WRITE(MIPI_EOT_DISABLE(pipe), CLOCKSTOP);
 
@@ -297,7 +297,7 @@ static void intel_dsi_clear_device_ready(struct intel_encoder *encoder)
        usleep_range(2000, 2500);
 
        if (wait_for(((I915_READ(MIPI_PORT_CTRL(pipe)) & AFE_LATCHOUT)
-                                       == 0x00000), 30))
+                     == 0x00000), 30))
                DRM_ERROR("DSI LP not going Low\n");
 
        val = I915_READ(MIPI_PORT_CTRL(pipe));
@@ -423,9 +423,11 @@ static u16 txclkesc(u32 divider, unsigned int us)
 }
 
 /* return pixels in terms of txbyteclkhs */
-static u16 txbyteclkhs(u16 pixels, int bpp, int lane_count)
+static u16 txbyteclkhs(u16 pixels, int bpp, int lane_count,
+                      u16 burst_mode_ratio)
 {
-       return DIV_ROUND_UP(DIV_ROUND_UP(pixels * bpp, 8), lane_count);
+       return DIV_ROUND_UP(DIV_ROUND_UP(pixels * bpp * burst_mode_ratio,
+                                        8 * 100), lane_count);
 }
 
 static void set_dsi_timings(struct drm_encoder *encoder,
@@ -451,10 +453,12 @@ static void set_dsi_timings(struct drm_encoder *encoder,
        vbp = mode->vtotal - mode->vsync_end;
 
        /* horizontal values are in terms of high speed byte clock */
-       hactive = txbyteclkhs(hactive, bpp, lane_count);
-       hfp = txbyteclkhs(hfp, bpp, lane_count);
-       hsync = txbyteclkhs(hsync, bpp, lane_count);
-       hbp = txbyteclkhs(hbp, bpp, lane_count);
+       hactive = txbyteclkhs(hactive, bpp, lane_count,
+                             intel_dsi->burst_mode_ratio);
+       hfp = txbyteclkhs(hfp, bpp, lane_count, intel_dsi->burst_mode_ratio);
+       hsync = txbyteclkhs(hsync, bpp, lane_count,
+                           intel_dsi->burst_mode_ratio);
+       hbp = txbyteclkhs(hbp, bpp, lane_count, intel_dsi->burst_mode_ratio);
 
        I915_WRITE(MIPI_HACTIVE_AREA_COUNT(pipe), hactive);
        I915_WRITE(MIPI_HFP_COUNT(pipe), hfp);
@@ -541,12 +545,14 @@ static void intel_dsi_prepare(struct intel_encoder *intel_encoder)
            intel_dsi->video_mode_format == VIDEO_MODE_BURST) {
                I915_WRITE(MIPI_HS_TX_TIMEOUT(pipe),
                           txbyteclkhs(adjusted_mode->htotal, bpp,
-                                      intel_dsi->lane_count) + 1);
+                                      intel_dsi->lane_count,
+                                      intel_dsi->burst_mode_ratio) + 1);
        } else {
                I915_WRITE(MIPI_HS_TX_TIMEOUT(pipe),
                           txbyteclkhs(adjusted_mode->vtotal *
                                       adjusted_mode->htotal,
-                                      bpp, intel_dsi->lane_count) + 1);
+                                      bpp, intel_dsi->lane_count,
+                                      intel_dsi->burst_mode_ratio) + 1);
        }
        I915_WRITE(MIPI_LP_RX_TIMEOUT(pipe), intel_dsi->lp_rx_timeout);
        I915_WRITE(MIPI_TURN_AROUND_TIMEOUT(pipe), intel_dsi->turn_arnd_val);
@@ -576,7 +582,7 @@ static void intel_dsi_prepare(struct intel_encoder *intel_encoder)
         * XXX: write MIPI_STOP_STATE_STALL?
         */
        I915_WRITE(MIPI_HIGH_LOW_SWITCH_COUNT(pipe),
-                                               intel_dsi->hs_to_lp_count);
+                  intel_dsi->hs_to_lp_count);
 
        /* XXX: low power clock equivalence in terms of byte clock. the number
         * of byte clocks occupied in one low power clock. based on txbyteclkhs
@@ -601,10 +607,10 @@ static void intel_dsi_prepare(struct intel_encoder *intel_encoder)
                 * 64 like 1366 x 768. Enable RANDOM resolution support for such
                 * panels by default */
                I915_WRITE(MIPI_VIDEO_MODE_FORMAT(pipe),
-                               intel_dsi->video_frmt_cfg_bits |
-                               intel_dsi->video_mode_format |
-                               IP_TG_CONFIG |
-                               RANDOM_DPI_DISPLAY_RESOLUTION);
+                          intel_dsi->video_frmt_cfg_bits |
+                          intel_dsi->video_mode_format |
+                          IP_TG_CONFIG |
+                          RANDOM_DPI_DISPLAY_RESOLUTION);
 }
 
 static void intel_dsi_pre_pll_enable(struct intel_encoder *encoder)
index fd51867fd0d3157ef849f4f50367e92865932f77..657eb5c1b9d80db7993a28febb8847c2dcf8665f 100644 (file)
@@ -116,6 +116,8 @@ struct intel_dsi {
        u16 clk_hs_to_lp_count;
 
        u16 init_count;
+       u32 pclk;
+       u16 burst_mode_ratio;
 
        /* all delays in ms */
        u16 backlight_off_delay;
index 7f1430ac8543617e5cc1788c98be97836ef85771..f4767fd2ebeb0ea9d60c971de76a164c459a5ef8 100644 (file)
@@ -430,7 +430,7 @@ void wait_for_dsi_fifo_empty(struct intel_dsi *intel_dsi)
        u32 mask;
 
        mask = LP_CTRL_FIFO_EMPTY | HS_CTRL_FIFO_EMPTY |
-                                       LP_DATA_FIFO_EMPTY | HS_DATA_FIFO_EMPTY;
+               LP_DATA_FIFO_EMPTY | HS_DATA_FIFO_EMPTY;
 
        if (wait_for((I915_READ(MIPI_GEN_FIFO_STAT(pipe)) & mask) == mask, 100))
                DRM_ERROR("DPI FIFOs are not empty\n");
index 47c7584a4aa0336938bb1150cc141e0e1063bfee..f6bdd44069cec77c676b2ac7222642cb5ed76f32 100644 (file)
@@ -271,6 +271,8 @@ static bool generic_init(struct intel_dsi_device *dsi)
        u32 ths_prepare_ns, tclk_trail_ns;
        u32 tclk_prepare_clkzero, ths_prepare_hszero;
        u32 lp_to_hs_switch, hs_to_lp_switch;
+       u32 pclk, computed_ddr;
+       u16 burst_mode_ratio;
 
        DRM_DEBUG_KMS("\n");
 
@@ -284,8 +286,6 @@ static bool generic_init(struct intel_dsi_device *dsi)
        else if (intel_dsi->pixel_format == VID_MODE_FORMAT_RGB565)
                bits_per_pixel = 16;
 
-       bitrate = (mode->clock * bits_per_pixel) / intel_dsi->lane_count;
-
        intel_dsi->operation_mode = mipi_config->is_cmd_mode;
        intel_dsi->video_mode_format = mipi_config->video_transfer_mode;
        intel_dsi->escape_clk_div = mipi_config->byte_clk_sel;
@@ -297,6 +297,40 @@ static bool generic_init(struct intel_dsi_device *dsi)
        intel_dsi->video_frmt_cfg_bits =
                mipi_config->bta_enabled ? DISABLE_VIDEO_BTA : 0;
 
+       pclk = mode->clock;
+
+       /* Burst Mode Ratio
+        * Target ddr frequency from VBT / non burst ddr freq
+        * multiply by 100 to preserve remainder
+        */
+       if (intel_dsi->video_mode_format == VIDEO_MODE_BURST) {
+               if (mipi_config->target_burst_mode_freq) {
+                       computed_ddr =
+                               (pclk * bits_per_pixel) / intel_dsi->lane_count;
+
+                       if (mipi_config->target_burst_mode_freq <
+                                                               computed_ddr) {
+                               DRM_ERROR("Burst mode freq is less than computed\n");
+                               return false;
+                       }
+
+                       burst_mode_ratio = DIV_ROUND_UP(
+                               mipi_config->target_burst_mode_freq * 100,
+                               computed_ddr);
+
+                       pclk = DIV_ROUND_UP(pclk * burst_mode_ratio, 100);
+               } else {
+                       DRM_ERROR("Burst mode target is not set\n");
+                       return false;
+               }
+       } else
+               burst_mode_ratio = 100;
+
+       intel_dsi->burst_mode_ratio = burst_mode_ratio;
+       intel_dsi->pclk = pclk;
+
+       bitrate = (pclk * bits_per_pixel) / intel_dsi->lane_count;
+
        switch (intel_dsi->escape_clk_div) {
        case 0:
                tlpx_ns = 50;
index d8bb1ea2f0da5a4be3a7b097cfe9b79bad954795..fa7a6ca34cd654bb7c66665c4c80235b28ea2673 100644 (file)
@@ -134,8 +134,7 @@ static u32 dsi_rr_formula(const struct drm_display_mode *mode,
 #else
 
 /* Get DSI clock from pixel clock */
-static u32 dsi_clk_from_pclk(const struct drm_display_mode *mode,
-                         int pixel_format, int lane_count)
+static u32 dsi_clk_from_pclk(u32 pclk, int pixel_format, int lane_count)
 {
        u32 dsi_clk_khz;
        u32 bpp;
@@ -156,7 +155,7 @@ static u32 dsi_clk_from_pclk(const struct drm_display_mode *mode,
 
        /* DSI data rate = pixel clock * bits per pixel / lane count
           pixel clock is converted from KHz to Hz */
-       dsi_clk_khz = DIV_ROUND_CLOSEST(mode->clock * bpp, lane_count);
+       dsi_clk_khz = DIV_ROUND_CLOSEST(pclk * bpp, lane_count);
 
        return dsi_clk_khz;
 }
@@ -191,7 +190,7 @@ static int dsi_calc_mnp(u32 dsi_clk, struct dsi_mnp *dsi_mnp)
        for (m = 62; m <= 92; m++) {
                for (p = 2; p <= 6; p++) {
                        /* Find the optimal m and p divisors
-                       with minimal error +/- the required clock */
+                          with minimal error +/- the required clock */
                        calc_dsi_clk = (m * ref_clk) / p;
                        if (calc_dsi_clk == target_dsi_clk) {
                                calc_m = m;
@@ -228,15 +227,13 @@ static int dsi_calc_mnp(u32 dsi_clk, struct dsi_mnp *dsi_mnp)
 static void vlv_configure_dsi_pll(struct intel_encoder *encoder)
 {
        struct drm_i915_private *dev_priv = encoder->base.dev->dev_private;
-       struct intel_crtc *intel_crtc = to_intel_crtc(encoder->base.crtc);
-       const struct drm_display_mode *mode = &intel_crtc->config.adjusted_mode;
        struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
        int ret;
        struct dsi_mnp dsi_mnp;
        u32 dsi_clk;
 
-       dsi_clk = dsi_clk_from_pclk(mode, intel_dsi->pixel_format,
-                                               intel_dsi->lane_count);
+       dsi_clk = dsi_clk_from_pclk(intel_dsi->pclk, intel_dsi->pixel_format,
+                                   intel_dsi->lane_count);
 
        ret = dsi_calc_mnp(dsi_clk, &dsi_mnp);
        if (ret) {
@@ -318,8 +315,8 @@ static void assert_bpp_mismatch(int pixel_format, int pipe_bpp)
        }
 
        WARN(bpp != pipe_bpp,
-               "bpp match assertion failure (expected %d, current %d)\n",
-               bpp, pipe_bpp);
+            "bpp match assertion failure (expected %d, current %d)\n",
+            bpp, pipe_bpp);
 }
 
 u32 vlv_get_dsi_pclk(struct intel_encoder *encoder, int pipe_bpp)
index 56b47d2ffaf7ea0227fced60ee4ae8979e9803ec..e40e3df335179979c763123b866386af4ae75eb8 100644 (file)
@@ -85,7 +85,7 @@ static const struct intel_dvo_device intel_dvo_devices[] = {
        {
                .type = INTEL_DVO_CHIP_TMDS,
                .name = "ns2501",
-               .dvo_reg = DVOC,
+               .dvo_reg = DVOB,
                .slave_addr = NS2501_ADDR,
                .dev_ops = &ns2501_ops,
        }
@@ -185,12 +185,13 @@ static void intel_enable_dvo(struct intel_encoder *encoder)
        u32 dvo_reg = intel_dvo->dev.dvo_reg;
        u32 temp = I915_READ(dvo_reg);
 
-       I915_WRITE(dvo_reg, temp | DVO_ENABLE);
-       I915_READ(dvo_reg);
        intel_dvo->dev.dev_ops->mode_set(&intel_dvo->dev,
                                         &crtc->config.requested_mode,
                                         &crtc->config.adjusted_mode);
 
+       I915_WRITE(dvo_reg, temp | DVO_ENABLE);
+       I915_READ(dvo_reg);
+
        intel_dvo->dev.dev_ops->dpms(&intel_dvo->dev, true);
 }
 
@@ -226,10 +227,6 @@ static void intel_dvo_dpms(struct drm_connector *connector, int mode)
 
                intel_crtc_update_dpms(crtc);
 
-               intel_dvo->dev.dev_ops->mode_set(&intel_dvo->dev,
-                                                &config->requested_mode,
-                                                &config->adjusted_mode);
-
                intel_dvo->dev.dev_ops->dpms(&intel_dvo->dev, true);
        } else {
                intel_dvo->dev.dev_ops->dpms(&intel_dvo->dev, false);
index f475414671d8bdd5752a41fa8f4f6339470e365c..9b584f3fbb9912808709bf13ccb002b188eb1c0f 100644 (file)
  *     David Airlie
  */
 
+#include <linux/async.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
+#include <linux/console.h>
 #include <linux/errno.h>
 #include <linux/string.h>
 #include <linux/mm.h>
@@ -331,24 +333,6 @@ static bool intel_fb_initial_config(struct drm_fb_helper *fb_helper,
        int num_connectors_enabled = 0;
        int num_connectors_detected = 0;
 
-       /*
-        * If the user specified any force options, just bail here
-        * and use that config.
-        */
-       for (i = 0; i < fb_helper->connector_count; i++) {
-               struct drm_fb_helper_connector *fb_conn;
-               struct drm_connector *connector;
-
-               fb_conn = fb_helper->connector_info[i];
-               connector = fb_conn->connector;
-
-               if (!enabled[i])
-                       continue;
-
-               if (connector->force != DRM_FORCE_UNSPECIFIED)
-                       return false;
-       }
-
        save_enabled = kcalloc(dev->mode_config.num_connector, sizeof(bool),
                               GFP_KERNEL);
        if (!save_enabled)
@@ -374,8 +358,18 @@ static bool intel_fb_initial_config(struct drm_fb_helper *fb_helper,
                        continue;
                }
 
+               if (connector->force == DRM_FORCE_OFF) {
+                       DRM_DEBUG_KMS("connector %s is disabled by user, skipping\n",
+                                     connector->name);
+                       enabled[i] = false;
+                       continue;
+               }
+
                encoder = connector->encoder;
                if (!encoder || WARN_ON(!encoder->crtc)) {
+                       if (connector->force > DRM_FORCE_OFF)
+                               goto bail;
+
                        DRM_DEBUG_KMS("connector %s has no encoder or crtc, skipping\n",
                                      connector->name);
                        enabled[i] = false;
@@ -394,8 +388,7 @@ static bool intel_fb_initial_config(struct drm_fb_helper *fb_helper,
                for (j = 0; j < fb_helper->connector_count; j++) {
                        if (crtcs[j] == new_crtc) {
                                DRM_DEBUG_KMS("fallback: cloned configuration\n");
-                               fallback = true;
-                               goto out;
+                               goto bail;
                        }
                }
 
@@ -466,8 +459,8 @@ static bool intel_fb_initial_config(struct drm_fb_helper *fb_helper,
                fallback = true;
        }
 
-out:
        if (fallback) {
+bail:
                DRM_DEBUG_KMS("Not using firmware configuration\n");
                memcpy(enabled, save_enabled, dev->mode_config.num_connector);
                kfree(save_enabled);
@@ -636,6 +629,15 @@ out:
        return false;
 }
 
+static void intel_fbdev_suspend_worker(struct work_struct *work)
+{
+       intel_fbdev_set_suspend(container_of(work,
+                                            struct drm_i915_private,
+                                            fbdev_suspend_work)->dev,
+                               FBINFO_STATE_RUNNING,
+                               true);
+}
+
 int intel_fbdev_init(struct drm_device *dev)
 {
        struct intel_fbdev *ifbdev;
@@ -662,14 +664,16 @@ int intel_fbdev_init(struct drm_device *dev)
        }
 
        dev_priv->fbdev = ifbdev;
+       INIT_WORK(&dev_priv->fbdev_suspend_work, intel_fbdev_suspend_worker);
+
        drm_fb_helper_single_add_all_connectors(&ifbdev->helper);
 
        return 0;
 }
 
-void intel_fbdev_initial_config(struct drm_device *dev)
+void intel_fbdev_initial_config(void *data, async_cookie_t cookie)
 {
-       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct drm_i915_private *dev_priv = data;
        struct intel_fbdev *ifbdev = dev_priv->fbdev;
 
        /* Due to peculiar init order wrt to hpd handling this is separate. */
@@ -682,12 +686,15 @@ void intel_fbdev_fini(struct drm_device *dev)
        if (!dev_priv->fbdev)
                return;
 
+       flush_work(&dev_priv->fbdev_suspend_work);
+
+       async_synchronize_full();
        intel_fbdev_destroy(dev, dev_priv->fbdev);
        kfree(dev_priv->fbdev);
        dev_priv->fbdev = NULL;
 }
 
-void intel_fbdev_set_suspend(struct drm_device *dev, int state)
+void intel_fbdev_set_suspend(struct drm_device *dev, int state, bool synchronous)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct intel_fbdev *ifbdev = dev_priv->fbdev;
@@ -698,6 +705,33 @@ void intel_fbdev_set_suspend(struct drm_device *dev, int state)
 
        info = ifbdev->helper.fbdev;
 
+       if (synchronous) {
+               /* Flush any pending work to turn the console on, and then
+                * wait to turn it off. It must be synchronous as we are
+                * about to suspend or unload the driver.
+                *
+                * Note that from within the work-handler, we cannot flush
+                * ourselves, so only flush outstanding work upon suspend!
+                */
+               if (state != FBINFO_STATE_RUNNING)
+                       flush_work(&dev_priv->fbdev_suspend_work);
+               console_lock();
+       } else {
+               /*
+                * The console lock can be pretty contented on resume due
+                * to all the printk activity.  Try to keep it out of the hot
+                * path of resume if possible.
+                */
+               WARN_ON(state != FBINFO_STATE_RUNNING);
+               if (!console_trylock()) {
+                       /* Don't block our own workqueue as this can
+                        * be run in parallel with other i915.ko tasks.
+                        */
+                       schedule_work(&dev_priv->fbdev_suspend_work);
+                       return;
+               }
+       }
+
        /* On resume from hibernation: If the object is shmemfs backed, it has
         * been restored from swap. If the object is stolen however, it will be
         * full of whatever garbage was left in there.
@@ -706,6 +740,7 @@ void intel_fbdev_set_suspend(struct drm_device *dev, int state)
                memset_io(info->screen_base, 0, info->screen_size);
 
        fb_set_suspend(info, state);
+       console_unlock();
 }
 
 void intel_fbdev_output_poll_changed(struct drm_device *dev)
index 5a9de21637b7819818e1993f911432e0fdb634de..29ec1535992d413fa5faf70c8192c02d6334b02c 100644 (file)
@@ -869,10 +869,15 @@ static enum drm_mode_status
 intel_hdmi_mode_valid(struct drm_connector *connector,
                      struct drm_display_mode *mode)
 {
-       if (mode->clock > hdmi_portclock_limit(intel_attached_hdmi(connector),
-                                              true))
+       int clock = mode->clock;
+
+       if (mode->flags & DRM_MODE_FLAG_DBLCLK)
+               clock *= 2;
+
+       if (clock > hdmi_portclock_limit(intel_attached_hdmi(connector),
+                                        true))
                return MODE_CLOCK_HIGH;
-       if (mode->clock < 20000)
+       if (clock < 20000)
                return MODE_CLOCK_LOW;
 
        if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
@@ -890,7 +895,7 @@ static bool hdmi_12bpc_possible(struct intel_crtc *crtc)
        if (HAS_GMCH_DISPLAY(dev))
                return false;
 
-       list_for_each_entry(encoder, &dev->mode_config.encoder_list, base.head) {
+       for_each_intel_encoder(dev, encoder) {
                if (encoder->new_crtc != crtc)
                        continue;
 
@@ -926,6 +931,10 @@ bool intel_hdmi_compute_config(struct intel_encoder *encoder,
                        intel_hdmi->color_range = 0;
        }
 
+       if (adjusted_mode->flags & DRM_MODE_FLAG_DBLCLK) {
+               pipe_config->pixel_multiplier = 2;
+       }
+
        if (intel_hdmi->color_range)
                pipe_config->limited_color_range = true;
 
@@ -967,104 +976,117 @@ bool intel_hdmi_compute_config(struct intel_encoder *encoder,
        return true;
 }
 
-static enum drm_connector_status
-intel_hdmi_detect(struct drm_connector *connector, bool force)
+static void
+intel_hdmi_unset_edid(struct drm_connector *connector)
 {
-       struct drm_device *dev = connector->dev;
        struct intel_hdmi *intel_hdmi = intel_attached_hdmi(connector);
-       struct intel_digital_port *intel_dig_port =
-               hdmi_to_dig_port(intel_hdmi);
-       struct intel_encoder *intel_encoder = &intel_dig_port->base;
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       struct edid *edid;
-       enum intel_display_power_domain power_domain;
-       enum drm_connector_status status = connector_status_disconnected;
 
-       DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n",
-                     connector->base.id, connector->name);
+       intel_hdmi->has_hdmi_sink = false;
+       intel_hdmi->has_audio = false;
+       intel_hdmi->rgb_quant_range_selectable = false;
+
+       kfree(to_intel_connector(connector)->detect_edid);
+       to_intel_connector(connector)->detect_edid = NULL;
+}
+
+static bool
+intel_hdmi_set_edid(struct drm_connector *connector)
+{
+       struct drm_i915_private *dev_priv = to_i915(connector->dev);
+       struct intel_hdmi *intel_hdmi = intel_attached_hdmi(connector);
+       struct intel_encoder *intel_encoder =
+               &hdmi_to_dig_port(intel_hdmi)->base;
+       enum intel_display_power_domain power_domain;
+       struct edid *edid;
+       bool connected = false;
 
        power_domain = intel_display_port_power_domain(intel_encoder);
        intel_display_power_get(dev_priv, power_domain);
 
-       intel_hdmi->has_hdmi_sink = false;
-       intel_hdmi->has_audio = false;
-       intel_hdmi->rgb_quant_range_selectable = false;
        edid = drm_get_edid(connector,
                            intel_gmbus_get_adapter(dev_priv,
                                                    intel_hdmi->ddc_bus));
 
-       if (edid) {
-               if (edid->input & DRM_EDID_INPUT_DIGITAL) {
-                       status = connector_status_connected;
-                       if (intel_hdmi->force_audio != HDMI_AUDIO_OFF_DVI)
-                               intel_hdmi->has_hdmi_sink =
-                                               drm_detect_hdmi_monitor(edid);
-                       intel_hdmi->has_audio = drm_detect_monitor_audio(edid);
-                       intel_hdmi->rgb_quant_range_selectable =
-                               drm_rgb_quant_range_selectable(edid);
-               }
-               kfree(edid);
-       }
+       intel_display_power_put(dev_priv, power_domain);
+
+       to_intel_connector(connector)->detect_edid = edid;
+       if (edid && edid->input & DRM_EDID_INPUT_DIGITAL) {
+               intel_hdmi->rgb_quant_range_selectable =
+                       drm_rgb_quant_range_selectable(edid);
 
-       if (status == connector_status_connected) {
+               intel_hdmi->has_audio = drm_detect_monitor_audio(edid);
                if (intel_hdmi->force_audio != HDMI_AUDIO_AUTO)
                        intel_hdmi->has_audio =
-                               (intel_hdmi->force_audio == HDMI_AUDIO_ON);
-               intel_encoder->type = INTEL_OUTPUT_HDMI;
+                               intel_hdmi->force_audio == HDMI_AUDIO_ON;
+
+               if (intel_hdmi->force_audio != HDMI_AUDIO_OFF_DVI)
+                       intel_hdmi->has_hdmi_sink =
+                               drm_detect_hdmi_monitor(edid);
+
+               connected = true;
        }
 
-       intel_display_power_put(dev_priv, power_domain);
+       return connected;
+}
+
+static enum drm_connector_status
+intel_hdmi_detect(struct drm_connector *connector, bool force)
+{
+       enum drm_connector_status status;
+
+       DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n",
+                     connector->base.id, connector->name);
+
+       intel_hdmi_unset_edid(connector);
+
+       if (intel_hdmi_set_edid(connector)) {
+               struct intel_hdmi *intel_hdmi = intel_attached_hdmi(connector);
+
+               hdmi_to_dig_port(intel_hdmi)->base.type = INTEL_OUTPUT_HDMI;
+               status = connector_status_connected;
+       } else
+               status = connector_status_disconnected;
 
        return status;
 }
 
-static int intel_hdmi_get_modes(struct drm_connector *connector)
+static void
+intel_hdmi_force(struct drm_connector *connector)
 {
-       struct intel_encoder *intel_encoder = intel_attached_encoder(connector);
-       struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&intel_encoder->base);
-       struct drm_i915_private *dev_priv = connector->dev->dev_private;
-       enum intel_display_power_domain power_domain;
-       int ret;
+       struct intel_hdmi *intel_hdmi = intel_attached_hdmi(connector);
 
-       /* We should parse the EDID data and find out if it's an HDMI sink so
-        * we can send audio to it.
-        */
+       DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n",
+                     connector->base.id, connector->name);
 
-       power_domain = intel_display_port_power_domain(intel_encoder);
-       intel_display_power_get(dev_priv, power_domain);
+       intel_hdmi_unset_edid(connector);
 
-       ret = intel_ddc_get_modes(connector,
-                                  intel_gmbus_get_adapter(dev_priv,
-                                                          intel_hdmi->ddc_bus));
+       if (connector->status != connector_status_connected)
+               return;
 
-       intel_display_power_put(dev_priv, power_domain);
+       intel_hdmi_set_edid(connector);
+       hdmi_to_dig_port(intel_hdmi)->base.type = INTEL_OUTPUT_HDMI;
+}
 
-       return ret;
+static int intel_hdmi_get_modes(struct drm_connector *connector)
+{
+       struct edid *edid;
+
+       edid = to_intel_connector(connector)->detect_edid;
+       if (edid == NULL)
+               return 0;
+
+       return intel_connector_update_modes(connector, edid);
 }
 
 static bool
 intel_hdmi_detect_audio(struct drm_connector *connector)
 {
-       struct intel_encoder *intel_encoder = intel_attached_encoder(connector);
-       struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&intel_encoder->base);
-       struct drm_i915_private *dev_priv = connector->dev->dev_private;
-       enum intel_display_power_domain power_domain;
-       struct edid *edid;
        bool has_audio = false;
+       struct edid *edid;
 
-       power_domain = intel_display_port_power_domain(intel_encoder);
-       intel_display_power_get(dev_priv, power_domain);
-
-       edid = drm_get_edid(connector,
-                           intel_gmbus_get_adapter(dev_priv,
-                                                   intel_hdmi->ddc_bus));
-       if (edid) {
-               if (edid->input & DRM_EDID_INPUT_DIGITAL)
-                       has_audio = drm_detect_monitor_audio(edid);
-               kfree(edid);
-       }
-
-       intel_display_power_put(dev_priv, power_domain);
+       edid = to_intel_connector(connector)->detect_edid;
+       if (edid && edid->input & DRM_EDID_INPUT_DIGITAL)
+               has_audio = drm_detect_monitor_audio(edid);
 
        return has_audio;
 }
@@ -1265,6 +1287,8 @@ static void chv_hdmi_pre_pll_enable(struct intel_encoder *encoder)
        enum pipe pipe = intel_crtc->pipe;
        u32 val;
 
+       intel_hdmi_prepare(encoder);
+
        mutex_lock(&dev_priv->dpio_lock);
 
        /* program left/right clock distribution */
@@ -1434,8 +1458,8 @@ static void chv_hdmi_pre_enable(struct intel_encoder *encoder)
 
        for (i = 0; i < 4; i++) {
                val = vlv_dpio_read(dev_priv, pipe, CHV_TX_DW2(ch, i));
-               val &= ~DPIO_SWING_MARGIN_MASK;
-               val |= 102 << DPIO_SWING_MARGIN_SHIFT;
+               val &= ~DPIO_SWING_MARGIN000_MASK;
+               val |= 102 << DPIO_SWING_MARGIN000_SHIFT;
                vlv_dpio_write(dev_priv, pipe, CHV_TX_DW2(ch, i), val);
        }
 
@@ -1482,6 +1506,7 @@ static void chv_hdmi_pre_enable(struct intel_encoder *encoder)
 
 static void intel_hdmi_destroy(struct drm_connector *connector)
 {
+       kfree(to_intel_connector(connector)->detect_edid);
        drm_connector_cleanup(connector);
        kfree(connector);
 }
@@ -1489,6 +1514,7 @@ static void intel_hdmi_destroy(struct drm_connector *connector)
 static const struct drm_connector_funcs intel_hdmi_connector_funcs = {
        .dpms = intel_connector_dpms,
        .detect = intel_hdmi_detect,
+       .force = intel_hdmi_force,
        .fill_modes = drm_helper_probe_single_connector_modes,
        .set_property = intel_hdmi_set_property,
        .destroy = intel_hdmi_destroy,
diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c
new file mode 100644 (file)
index 0000000..bafd38b
--- /dev/null
@@ -0,0 +1,1766 @@
+/*
+ * Copyright Â© 2014 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ * Authors:
+ *    Ben Widawsky <ben@bwidawsk.net>
+ *    Michel Thierry <michel.thierry@intel.com>
+ *    Thomas Daniel <thomas.daniel@intel.com>
+ *    Oscar Mateo <oscar.mateo@intel.com>
+ *
+ */
+
+/**
+ * DOC: Logical Rings, Logical Ring Contexts and Execlists
+ *
+ * Motivation:
+ * GEN8 brings an expansion of the HW contexts: "Logical Ring Contexts".
+ * These expanded contexts enable a number of new abilities, especially
+ * "Execlists" (also implemented in this file).
+ *
+ * One of the main differences with the legacy HW contexts is that logical
+ * ring contexts incorporate many more things to the context's state, like
+ * PDPs or ringbuffer control registers:
+ *
+ * The reason why PDPs are included in the context is straightforward: as
+ * PPGTTs (per-process GTTs) are actually per-context, having the PDPs
+ * contained there mean you don't need to do a ppgtt->switch_mm yourself,
+ * instead, the GPU will do it for you on the context switch.
+ *
+ * But, what about the ringbuffer control registers (head, tail, etc..)?
+ * shouldn't we just need a set of those per engine command streamer? This is
+ * where the name "Logical Rings" starts to make sense: by virtualizing the
+ * rings, the engine cs shifts to a new "ring buffer" with every context
+ * switch. When you want to submit a workload to the GPU you: A) choose your
+ * context, B) find its appropriate virtualized ring, C) write commands to it
+ * and then, finally, D) tell the GPU to switch to that context.
+ *
+ * Instead of the legacy MI_SET_CONTEXT, the way you tell the GPU to switch
+ * to a contexts is via a context execution list, ergo "Execlists".
+ *
+ * LRC implementation:
+ * Regarding the creation of contexts, we have:
+ *
+ * - One global default context.
+ * - One local default context for each opened fd.
+ * - One local extra context for each context create ioctl call.
+ *
+ * Now that ringbuffers belong per-context (and not per-engine, like before)
+ * and that contexts are uniquely tied to a given engine (and not reusable,
+ * like before) we need:
+ *
+ * - One ringbuffer per-engine inside each context.
+ * - One backing object per-engine inside each context.
+ *
+ * The global default context starts its life with these new objects fully
+ * allocated and populated. The local default context for each opened fd is
+ * more complex, because we don't know at creation time which engine is going
+ * to use them. To handle this, we have implemented a deferred creation of LR
+ * contexts:
+ *
+ * The local context starts its life as a hollow or blank holder, that only
+ * gets populated for a given engine once we receive an execbuffer. If later
+ * on we receive another execbuffer ioctl for the same context but a different
+ * engine, we allocate/populate a new ringbuffer and context backing object and
+ * so on.
+ *
+ * Finally, regarding local contexts created using the ioctl call: as they are
+ * only allowed with the render ring, we can allocate & populate them right
+ * away (no need to defer anything, at least for now).
+ *
+ * Execlists implementation:
+ * Execlists are the new method by which, on gen8+ hardware, workloads are
+ * submitted for execution (as opposed to the legacy, ringbuffer-based, method).
+ * This method works as follows:
+ *
+ * When a request is committed, its commands (the BB start and any leading or
+ * trailing commands, like the seqno breadcrumbs) are placed in the ringbuffer
+ * for the appropriate context. The tail pointer in the hardware context is not
+ * updated at this time, but instead, kept by the driver in the ringbuffer
+ * structure. A structure representing this request is added to a request queue
+ * for the appropriate engine: this structure contains a copy of the context's
+ * tail after the request was written to the ring buffer and a pointer to the
+ * context itself.
+ *
+ * If the engine's request queue was empty before the request was added, the
+ * queue is processed immediately. Otherwise the queue will be processed during
+ * a context switch interrupt. In any case, elements on the queue will get sent
+ * (in pairs) to the GPU's ExecLists Submit Port (ELSP, for short) with a
+ * globally unique 20-bits submission ID.
+ *
+ * When execution of a request completes, the GPU updates the context status
+ * buffer with a context complete event and generates a context switch interrupt.
+ * During the interrupt handling, the driver examines the events in the buffer:
+ * for each context complete event, if the announced ID matches that on the head
+ * of the request queue, then that request is retired and removed from the queue.
+ *
+ * After processing, if any requests were retired and the queue is not empty
+ * then a new execution list can be submitted. The two requests at the front of
+ * the queue are next to be submitted but since a context may not occur twice in
+ * an execution list, if subsequent requests have the same ID as the first then
+ * the two requests must be combined. This is done simply by discarding requests
+ * at the head of the queue until either only one requests is left (in which case
+ * we use a NULL second context) or the first two requests have unique IDs.
+ *
+ * By always executing the first two requests in the queue the driver ensures
+ * that the GPU is kept as busy as possible. In the case where a single context
+ * completes but a second context is still executing, the request for this second
+ * context will be at the head of the queue when we remove the first one. This
+ * request will then be resubmitted along with a new request for a different context,
+ * which will cause the hardware to continue executing the second request and queue
+ * the new request (the GPU detects the condition of a context getting preempted
+ * with the same context and optimizes the context switch flow by not doing
+ * preemption, but just sampling the new tail pointer).
+ *
+ */
+
+#include <drm/drmP.h>
+#include <drm/i915_drm.h>
+#include "i915_drv.h"
+
+#define GEN8_LR_CONTEXT_RENDER_SIZE (20 * PAGE_SIZE)
+#define GEN8_LR_CONTEXT_OTHER_SIZE (2 * PAGE_SIZE)
+
+#define GEN8_LR_CONTEXT_ALIGN 4096
+
+#define RING_EXECLIST_QFULL            (1 << 0x2)
+#define RING_EXECLIST1_VALID           (1 << 0x3)
+#define RING_EXECLIST0_VALID           (1 << 0x4)
+#define RING_EXECLIST_ACTIVE_STATUS    (3 << 0xE)
+#define RING_EXECLIST1_ACTIVE          (1 << 0x11)
+#define RING_EXECLIST0_ACTIVE          (1 << 0x12)
+
+#define GEN8_CTX_STATUS_IDLE_ACTIVE    (1 << 0)
+#define GEN8_CTX_STATUS_PREEMPTED      (1 << 1)
+#define GEN8_CTX_STATUS_ELEMENT_SWITCH (1 << 2)
+#define GEN8_CTX_STATUS_ACTIVE_IDLE    (1 << 3)
+#define GEN8_CTX_STATUS_COMPLETE       (1 << 4)
+#define GEN8_CTX_STATUS_LITE_RESTORE   (1 << 15)
+
+#define CTX_LRI_HEADER_0               0x01
+#define CTX_CONTEXT_CONTROL            0x02
+#define CTX_RING_HEAD                  0x04
+#define CTX_RING_TAIL                  0x06
+#define CTX_RING_BUFFER_START          0x08
+#define CTX_RING_BUFFER_CONTROL                0x0a
+#define CTX_BB_HEAD_U                  0x0c
+#define CTX_BB_HEAD_L                  0x0e
+#define CTX_BB_STATE                   0x10
+#define CTX_SECOND_BB_HEAD_U           0x12
+#define CTX_SECOND_BB_HEAD_L           0x14
+#define CTX_SECOND_BB_STATE            0x16
+#define CTX_BB_PER_CTX_PTR             0x18
+#define CTX_RCS_INDIRECT_CTX           0x1a
+#define CTX_RCS_INDIRECT_CTX_OFFSET    0x1c
+#define CTX_LRI_HEADER_1               0x21
+#define CTX_CTX_TIMESTAMP              0x22
+#define CTX_PDP3_UDW                   0x24
+#define CTX_PDP3_LDW                   0x26
+#define CTX_PDP2_UDW                   0x28
+#define CTX_PDP2_LDW                   0x2a
+#define CTX_PDP1_UDW                   0x2c
+#define CTX_PDP1_LDW                   0x2e
+#define CTX_PDP0_UDW                   0x30
+#define CTX_PDP0_LDW                   0x32
+#define CTX_LRI_HEADER_2               0x41
+#define CTX_R_PWR_CLK_STATE            0x42
+#define CTX_GPGPU_CSR_BASE_ADDRESS     0x44
+
+#define GEN8_CTX_VALID (1<<0)
+#define GEN8_CTX_FORCE_PD_RESTORE (1<<1)
+#define GEN8_CTX_FORCE_RESTORE (1<<2)
+#define GEN8_CTX_L3LLC_COHERENT (1<<5)
+#define GEN8_CTX_PRIVILEGE (1<<8)
+enum {
+       ADVANCED_CONTEXT = 0,
+       LEGACY_CONTEXT,
+       ADVANCED_AD_CONTEXT,
+       LEGACY_64B_CONTEXT
+};
+#define GEN8_CTX_MODE_SHIFT 3
+enum {
+       FAULT_AND_HANG = 0,
+       FAULT_AND_HALT, /* Debug only */
+       FAULT_AND_STREAM,
+       FAULT_AND_CONTINUE /* Unsupported */
+};
+#define GEN8_CTX_ID_SHIFT 32
+
+/**
+ * intel_sanitize_enable_execlists() - sanitize i915.enable_execlists
+ * @dev: DRM device.
+ * @enable_execlists: value of i915.enable_execlists module parameter.
+ *
+ * Only certain platforms support Execlists (the prerequisites being
+ * support for Logical Ring Contexts and Aliasing PPGTT or better),
+ * and only when enabled via module parameter.
+ *
+ * Return: 1 if Execlists is supported and has to be enabled.
+ */
+int intel_sanitize_enable_execlists(struct drm_device *dev, int enable_execlists)
+{
+       WARN_ON(i915.enable_ppgtt == -1);
+
+       if (enable_execlists == 0)
+               return 0;
+
+       if (HAS_LOGICAL_RING_CONTEXTS(dev) && USES_PPGTT(dev) &&
+           i915.use_mmio_flip >= 0)
+               return 1;
+
+       return 0;
+}
+
+/**
+ * intel_execlists_ctx_id() - get the Execlists Context ID
+ * @ctx_obj: Logical Ring Context backing object.
+ *
+ * Do not confuse with ctx->id! Unfortunately we have a name overload
+ * here: the old context ID we pass to userspace as a handler so that
+ * they can refer to a context, and the new context ID we pass to the
+ * ELSP so that the GPU can inform us of the context status via
+ * interrupts.
+ *
+ * Return: 20-bits globally unique context ID.
+ */
+u32 intel_execlists_ctx_id(struct drm_i915_gem_object *ctx_obj)
+{
+       u32 lrca = i915_gem_obj_ggtt_offset(ctx_obj);
+
+       /* LRCA is required to be 4K aligned so the more significant 20 bits
+        * are globally unique */
+       return lrca >> 12;
+}
+
+static uint64_t execlists_ctx_descriptor(struct drm_i915_gem_object *ctx_obj)
+{
+       uint64_t desc;
+       uint64_t lrca = i915_gem_obj_ggtt_offset(ctx_obj);
+
+       WARN_ON(lrca & 0xFFFFFFFF00000FFFULL);
+
+       desc = GEN8_CTX_VALID;
+       desc |= LEGACY_CONTEXT << GEN8_CTX_MODE_SHIFT;
+       desc |= GEN8_CTX_L3LLC_COHERENT;
+       desc |= GEN8_CTX_PRIVILEGE;
+       desc |= lrca;
+       desc |= (u64)intel_execlists_ctx_id(ctx_obj) << GEN8_CTX_ID_SHIFT;
+
+       /* TODO: WaDisableLiteRestore when we start using semaphore
+        * signalling between Command Streamers */
+       /* desc |= GEN8_CTX_FORCE_RESTORE; */
+
+       return desc;
+}
+
+static void execlists_elsp_write(struct intel_engine_cs *ring,
+                                struct drm_i915_gem_object *ctx_obj0,
+                                struct drm_i915_gem_object *ctx_obj1)
+{
+       struct drm_i915_private *dev_priv = ring->dev->dev_private;
+       uint64_t temp = 0;
+       uint32_t desc[4];
+       unsigned long flags;
+
+       /* XXX: You must always write both descriptors in the order below. */
+       if (ctx_obj1)
+               temp = execlists_ctx_descriptor(ctx_obj1);
+       else
+               temp = 0;
+       desc[1] = (u32)(temp >> 32);
+       desc[0] = (u32)temp;
+
+       temp = execlists_ctx_descriptor(ctx_obj0);
+       desc[3] = (u32)(temp >> 32);
+       desc[2] = (u32)temp;
+
+       /* Set Force Wakeup bit to prevent GT from entering C6 while ELSP writes
+        * are in progress.
+        *
+        * The other problem is that we can't just call gen6_gt_force_wake_get()
+        * because that function calls intel_runtime_pm_get(), which might sleep.
+        * Instead, we do the runtime_pm_get/put when creating/destroying requests.
+        */
+       spin_lock_irqsave(&dev_priv->uncore.lock, flags);
+       if (IS_CHERRYVIEW(dev_priv->dev)) {
+               if (dev_priv->uncore.fw_rendercount++ == 0)
+                       dev_priv->uncore.funcs.force_wake_get(dev_priv,
+                                                             FORCEWAKE_RENDER);
+               if (dev_priv->uncore.fw_mediacount++ == 0)
+                       dev_priv->uncore.funcs.force_wake_get(dev_priv,
+                                                             FORCEWAKE_MEDIA);
+       } else {
+               if (dev_priv->uncore.forcewake_count++ == 0)
+                       dev_priv->uncore.funcs.force_wake_get(dev_priv,
+                                                             FORCEWAKE_ALL);
+       }
+       spin_unlock_irqrestore(&dev_priv->uncore.lock, flags);
+
+       I915_WRITE(RING_ELSP(ring), desc[1]);
+       I915_WRITE(RING_ELSP(ring), desc[0]);
+       I915_WRITE(RING_ELSP(ring), desc[3]);
+       /* The context is automatically loaded after the following */
+       I915_WRITE(RING_ELSP(ring), desc[2]);
+
+       /* ELSP is a wo register, so use another nearby reg for posting instead */
+       POSTING_READ(RING_EXECLIST_STATUS(ring));
+
+       /* Release Force Wakeup (see the big comment above). */
+       spin_lock_irqsave(&dev_priv->uncore.lock, flags);
+       if (IS_CHERRYVIEW(dev_priv->dev)) {
+               if (--dev_priv->uncore.fw_rendercount == 0)
+                       dev_priv->uncore.funcs.force_wake_put(dev_priv,
+                                                             FORCEWAKE_RENDER);
+               if (--dev_priv->uncore.fw_mediacount == 0)
+                       dev_priv->uncore.funcs.force_wake_put(dev_priv,
+                                                             FORCEWAKE_MEDIA);
+       } else {
+               if (--dev_priv->uncore.forcewake_count == 0)
+                       dev_priv->uncore.funcs.force_wake_put(dev_priv,
+                                                             FORCEWAKE_ALL);
+       }
+
+       spin_unlock_irqrestore(&dev_priv->uncore.lock, flags);
+}
+
+static int execlists_ctx_write_tail(struct drm_i915_gem_object *ctx_obj, u32 tail)
+{
+       struct page *page;
+       uint32_t *reg_state;
+
+       page = i915_gem_object_get_page(ctx_obj, 1);
+       reg_state = kmap_atomic(page);
+
+       reg_state[CTX_RING_TAIL+1] = tail;
+
+       kunmap_atomic(reg_state);
+
+       return 0;
+}
+
+static int execlists_submit_context(struct intel_engine_cs *ring,
+                                   struct intel_context *to0, u32 tail0,
+                                   struct intel_context *to1, u32 tail1)
+{
+       struct drm_i915_gem_object *ctx_obj0;
+       struct drm_i915_gem_object *ctx_obj1 = NULL;
+
+       ctx_obj0 = to0->engine[ring->id].state;
+       BUG_ON(!ctx_obj0);
+       WARN_ON(!i915_gem_obj_is_pinned(ctx_obj0));
+
+       execlists_ctx_write_tail(ctx_obj0, tail0);
+
+       if (to1) {
+               ctx_obj1 = to1->engine[ring->id].state;
+               BUG_ON(!ctx_obj1);
+               WARN_ON(!i915_gem_obj_is_pinned(ctx_obj1));
+
+               execlists_ctx_write_tail(ctx_obj1, tail1);
+       }
+
+       execlists_elsp_write(ring, ctx_obj0, ctx_obj1);
+
+       return 0;
+}
+
+static void execlists_context_unqueue(struct intel_engine_cs *ring)
+{
+       struct intel_ctx_submit_request *req0 = NULL, *req1 = NULL;
+       struct intel_ctx_submit_request *cursor = NULL, *tmp = NULL;
+       struct drm_i915_private *dev_priv = ring->dev->dev_private;
+
+       assert_spin_locked(&ring->execlist_lock);
+
+       if (list_empty(&ring->execlist_queue))
+               return;
+
+       /* Try to read in pairs */
+       list_for_each_entry_safe(cursor, tmp, &ring->execlist_queue,
+                                execlist_link) {
+               if (!req0) {
+                       req0 = cursor;
+               } else if (req0->ctx == cursor->ctx) {
+                       /* Same ctx: ignore first request, as second request
+                        * will update tail past first request's workload */
+                       cursor->elsp_submitted = req0->elsp_submitted;
+                       list_del(&req0->execlist_link);
+                       queue_work(dev_priv->wq, &req0->work);
+                       req0 = cursor;
+               } else {
+                       req1 = cursor;
+                       break;
+               }
+       }
+
+       WARN_ON(req1 && req1->elsp_submitted);
+
+       WARN_ON(execlists_submit_context(ring, req0->ctx, req0->tail,
+                                        req1 ? req1->ctx : NULL,
+                                        req1 ? req1->tail : 0));
+
+       req0->elsp_submitted++;
+       if (req1)
+               req1->elsp_submitted++;
+}
+
+static bool execlists_check_remove_request(struct intel_engine_cs *ring,
+                                          u32 request_id)
+{
+       struct drm_i915_private *dev_priv = ring->dev->dev_private;
+       struct intel_ctx_submit_request *head_req;
+
+       assert_spin_locked(&ring->execlist_lock);
+
+       head_req = list_first_entry_or_null(&ring->execlist_queue,
+                                           struct intel_ctx_submit_request,
+                                           execlist_link);
+
+       if (head_req != NULL) {
+               struct drm_i915_gem_object *ctx_obj =
+                               head_req->ctx->engine[ring->id].state;
+               if (intel_execlists_ctx_id(ctx_obj) == request_id) {
+                       WARN(head_req->elsp_submitted == 0,
+                            "Never submitted head request\n");
+
+                       if (--head_req->elsp_submitted <= 0) {
+                               list_del(&head_req->execlist_link);
+                               queue_work(dev_priv->wq, &head_req->work);
+                               return true;
+                       }
+               }
+       }
+
+       return false;
+}
+
+/**
+ * intel_execlists_handle_ctx_events() - handle Context Switch interrupts
+ * @ring: Engine Command Streamer to handle.
+ *
+ * Check the unread Context Status Buffers and manage the submission of new
+ * contexts to the ELSP accordingly.
+ */
+void intel_execlists_handle_ctx_events(struct intel_engine_cs *ring)
+{
+       struct drm_i915_private *dev_priv = ring->dev->dev_private;
+       u32 status_pointer;
+       u8 read_pointer;
+       u8 write_pointer;
+       u32 status;
+       u32 status_id;
+       u32 submit_contexts = 0;
+
+       status_pointer = I915_READ(RING_CONTEXT_STATUS_PTR(ring));
+
+       read_pointer = ring->next_context_status_buffer;
+       write_pointer = status_pointer & 0x07;
+       if (read_pointer > write_pointer)
+               write_pointer += 6;
+
+       spin_lock(&ring->execlist_lock);
+
+       while (read_pointer < write_pointer) {
+               read_pointer++;
+               status = I915_READ(RING_CONTEXT_STATUS_BUF(ring) +
+                               (read_pointer % 6) * 8);
+               status_id = I915_READ(RING_CONTEXT_STATUS_BUF(ring) +
+                               (read_pointer % 6) * 8 + 4);
+
+               if (status & GEN8_CTX_STATUS_PREEMPTED) {
+                       if (status & GEN8_CTX_STATUS_LITE_RESTORE) {
+                               if (execlists_check_remove_request(ring, status_id))
+                                       WARN(1, "Lite Restored request removed from queue\n");
+                       } else
+                               WARN(1, "Preemption without Lite Restore\n");
+               }
+
+                if ((status & GEN8_CTX_STATUS_ACTIVE_IDLE) ||
+                    (status & GEN8_CTX_STATUS_ELEMENT_SWITCH)) {
+                       if (execlists_check_remove_request(ring, status_id))
+                               submit_contexts++;
+               }
+       }
+
+       if (submit_contexts != 0)
+               execlists_context_unqueue(ring);
+
+       spin_unlock(&ring->execlist_lock);
+
+       WARN(submit_contexts > 2, "More than two context complete events?\n");
+       ring->next_context_status_buffer = write_pointer % 6;
+
+       I915_WRITE(RING_CONTEXT_STATUS_PTR(ring),
+                  ((u32)ring->next_context_status_buffer & 0x07) << 8);
+}
+
+static void execlists_free_request_task(struct work_struct *work)
+{
+       struct intel_ctx_submit_request *req =
+               container_of(work, struct intel_ctx_submit_request, work);
+       struct drm_device *dev = req->ring->dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+
+       intel_runtime_pm_put(dev_priv);
+
+       mutex_lock(&dev->struct_mutex);
+       i915_gem_context_unreference(req->ctx);
+       mutex_unlock(&dev->struct_mutex);
+
+       kfree(req);
+}
+
+static int execlists_context_queue(struct intel_engine_cs *ring,
+                                  struct intel_context *to,
+                                  u32 tail)
+{
+       struct intel_ctx_submit_request *req = NULL, *cursor;
+       struct drm_i915_private *dev_priv = ring->dev->dev_private;
+       unsigned long flags;
+       int num_elements = 0;
+
+       req = kzalloc(sizeof(*req), GFP_KERNEL);
+       if (req == NULL)
+               return -ENOMEM;
+       req->ctx = to;
+       i915_gem_context_reference(req->ctx);
+       req->ring = ring;
+       req->tail = tail;
+       INIT_WORK(&req->work, execlists_free_request_task);
+
+       intel_runtime_pm_get(dev_priv);
+
+       spin_lock_irqsave(&ring->execlist_lock, flags);
+
+       list_for_each_entry(cursor, &ring->execlist_queue, execlist_link)
+               if (++num_elements > 2)
+                       break;
+
+       if (num_elements > 2) {
+               struct intel_ctx_submit_request *tail_req;
+
+               tail_req = list_last_entry(&ring->execlist_queue,
+                                          struct intel_ctx_submit_request,
+                                          execlist_link);
+
+               if (to == tail_req->ctx) {
+                       WARN(tail_req->elsp_submitted != 0,
+                            "More than 2 already-submitted reqs queued\n");
+                       list_del(&tail_req->execlist_link);
+                       queue_work(dev_priv->wq, &tail_req->work);
+               }
+       }
+
+       list_add_tail(&req->execlist_link, &ring->execlist_queue);
+       if (num_elements == 0)
+               execlists_context_unqueue(ring);
+
+       spin_unlock_irqrestore(&ring->execlist_lock, flags);
+
+       return 0;
+}
+
+static int logical_ring_invalidate_all_caches(struct intel_ringbuffer *ringbuf)
+{
+       struct intel_engine_cs *ring = ringbuf->ring;
+       uint32_t flush_domains;
+       int ret;
+
+       flush_domains = 0;
+       if (ring->gpu_caches_dirty)
+               flush_domains = I915_GEM_GPU_DOMAINS;
+
+       ret = ring->emit_flush(ringbuf, I915_GEM_GPU_DOMAINS, flush_domains);
+       if (ret)
+               return ret;
+
+       ring->gpu_caches_dirty = false;
+       return 0;
+}
+
+static int execlists_move_to_gpu(struct intel_ringbuffer *ringbuf,
+                                struct list_head *vmas)
+{
+       struct intel_engine_cs *ring = ringbuf->ring;
+       struct i915_vma *vma;
+       uint32_t flush_domains = 0;
+       bool flush_chipset = false;
+       int ret;
+
+       list_for_each_entry(vma, vmas, exec_list) {
+               struct drm_i915_gem_object *obj = vma->obj;
+
+               ret = i915_gem_object_sync(obj, ring);
+               if (ret)
+                       return ret;
+
+               if (obj->base.write_domain & I915_GEM_DOMAIN_CPU)
+                       flush_chipset |= i915_gem_clflush_object(obj, false);
+
+               flush_domains |= obj->base.write_domain;
+       }
+
+       if (flush_domains & I915_GEM_DOMAIN_GTT)
+               wmb();
+
+       /* Unconditionally invalidate gpu caches and ensure that we do flush
+        * any residual writes from the previous batch.
+        */
+       return logical_ring_invalidate_all_caches(ringbuf);
+}
+
+/**
+ * execlists_submission() - submit a batchbuffer for execution, Execlists style
+ * @dev: DRM device.
+ * @file: DRM file.
+ * @ring: Engine Command Streamer to submit to.
+ * @ctx: Context to employ for this submission.
+ * @args: execbuffer call arguments.
+ * @vmas: list of vmas.
+ * @batch_obj: the batchbuffer to submit.
+ * @exec_start: batchbuffer start virtual address pointer.
+ * @flags: translated execbuffer call flags.
+ *
+ * This is the evil twin version of i915_gem_ringbuffer_submission. It abstracts
+ * away the submission details of the execbuffer ioctl call.
+ *
+ * Return: non-zero if the submission fails.
+ */
+int intel_execlists_submission(struct drm_device *dev, struct drm_file *file,
+                              struct intel_engine_cs *ring,
+                              struct intel_context *ctx,
+                              struct drm_i915_gem_execbuffer2 *args,
+                              struct list_head *vmas,
+                              struct drm_i915_gem_object *batch_obj,
+                              u64 exec_start, u32 flags)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct intel_ringbuffer *ringbuf = ctx->engine[ring->id].ringbuf;
+       int instp_mode;
+       u32 instp_mask;
+       int ret;
+
+       instp_mode = args->flags & I915_EXEC_CONSTANTS_MASK;
+       instp_mask = I915_EXEC_CONSTANTS_MASK;
+       switch (instp_mode) {
+       case I915_EXEC_CONSTANTS_REL_GENERAL:
+       case I915_EXEC_CONSTANTS_ABSOLUTE:
+       case I915_EXEC_CONSTANTS_REL_SURFACE:
+               if (instp_mode != 0 && ring != &dev_priv->ring[RCS]) {
+                       DRM_DEBUG("non-0 rel constants mode on non-RCS\n");
+                       return -EINVAL;
+               }
+
+               if (instp_mode != dev_priv->relative_constants_mode) {
+                       if (instp_mode == I915_EXEC_CONSTANTS_REL_SURFACE) {
+                               DRM_DEBUG("rel surface constants mode invalid on gen5+\n");
+                               return -EINVAL;
+                       }
+
+                       /* The HW changed the meaning on this bit on gen6 */
+                       instp_mask &= ~I915_EXEC_CONSTANTS_REL_SURFACE;
+               }
+               break;
+       default:
+               DRM_DEBUG("execbuf with unknown constants: %d\n", instp_mode);
+               return -EINVAL;
+       }
+
+       if (args->num_cliprects != 0) {
+               DRM_DEBUG("clip rectangles are only valid on pre-gen5\n");
+               return -EINVAL;
+       } else {
+               if (args->DR4 == 0xffffffff) {
+                       DRM_DEBUG("UXA submitting garbage DR4, fixing up\n");
+                       args->DR4 = 0;
+               }
+
+               if (args->DR1 || args->DR4 || args->cliprects_ptr) {
+                       DRM_DEBUG("0 cliprects but dirt in cliprects fields\n");
+                       return -EINVAL;
+               }
+       }
+
+       if (args->flags & I915_EXEC_GEN7_SOL_RESET) {
+               DRM_DEBUG("sol reset is gen7 only\n");
+               return -EINVAL;
+       }
+
+       ret = execlists_move_to_gpu(ringbuf, vmas);
+       if (ret)
+               return ret;
+
+       if (ring == &dev_priv->ring[RCS] &&
+           instp_mode != dev_priv->relative_constants_mode) {
+               ret = intel_logical_ring_begin(ringbuf, 4);
+               if (ret)
+                       return ret;
+
+               intel_logical_ring_emit(ringbuf, MI_NOOP);
+               intel_logical_ring_emit(ringbuf, MI_LOAD_REGISTER_IMM(1));
+               intel_logical_ring_emit(ringbuf, INSTPM);
+               intel_logical_ring_emit(ringbuf, instp_mask << 16 | instp_mode);
+               intel_logical_ring_advance(ringbuf);
+
+               dev_priv->relative_constants_mode = instp_mode;
+       }
+
+       ret = ring->emit_bb_start(ringbuf, exec_start, flags);
+       if (ret)
+               return ret;
+
+       i915_gem_execbuffer_move_to_active(vmas, ring);
+       i915_gem_execbuffer_retire_commands(dev, file, ring, batch_obj);
+
+       return 0;
+}
+
+void intel_logical_ring_stop(struct intel_engine_cs *ring)
+{
+       struct drm_i915_private *dev_priv = ring->dev->dev_private;
+       int ret;
+
+       if (!intel_ring_initialized(ring))
+               return;
+
+       ret = intel_ring_idle(ring);
+       if (ret && !i915_reset_in_progress(&to_i915(ring->dev)->gpu_error))
+               DRM_ERROR("failed to quiesce %s whilst cleaning up: %d\n",
+                         ring->name, ret);
+
+       /* TODO: Is this correct with Execlists enabled? */
+       I915_WRITE_MODE(ring, _MASKED_BIT_ENABLE(STOP_RING));
+       if (wait_for_atomic((I915_READ_MODE(ring) & MODE_IDLE) != 0, 1000)) {
+               DRM_ERROR("%s :timed out trying to stop ring\n", ring->name);
+               return;
+       }
+       I915_WRITE_MODE(ring, _MASKED_BIT_DISABLE(STOP_RING));
+}
+
+int logical_ring_flush_all_caches(struct intel_ringbuffer *ringbuf)
+{
+       struct intel_engine_cs *ring = ringbuf->ring;
+       int ret;
+
+       if (!ring->gpu_caches_dirty)
+               return 0;
+
+       ret = ring->emit_flush(ringbuf, 0, I915_GEM_GPU_DOMAINS);
+       if (ret)
+               return ret;
+
+       ring->gpu_caches_dirty = false;
+       return 0;
+}
+
+/**
+ * intel_logical_ring_advance_and_submit() - advance the tail and submit the workload
+ * @ringbuf: Logical Ringbuffer to advance.
+ *
+ * The tail is updated in our logical ringbuffer struct, not in the actual context. What
+ * really happens during submission is that the context and current tail will be placed
+ * on a queue waiting for the ELSP to be ready to accept a new context submission. At that
+ * point, the tail *inside* the context is updated and the ELSP written to.
+ */
+void intel_logical_ring_advance_and_submit(struct intel_ringbuffer *ringbuf)
+{
+       struct intel_engine_cs *ring = ringbuf->ring;
+       struct intel_context *ctx = ringbuf->FIXME_lrc_ctx;
+
+       intel_logical_ring_advance(ringbuf);
+
+       if (intel_ring_stopped(ring))
+               return;
+
+       execlists_context_queue(ring, ctx, ringbuf->tail);
+}
+
+static int logical_ring_alloc_seqno(struct intel_engine_cs *ring,
+                                   struct intel_context *ctx)
+{
+       if (ring->outstanding_lazy_seqno)
+               return 0;
+
+       if (ring->preallocated_lazy_request == NULL) {
+               struct drm_i915_gem_request *request;
+
+               request = kmalloc(sizeof(*request), GFP_KERNEL);
+               if (request == NULL)
+                       return -ENOMEM;
+
+               /* Hold a reference to the context this request belongs to
+                * (we will need it when the time comes to emit/retire the
+                * request).
+                */
+               request->ctx = ctx;
+               i915_gem_context_reference(request->ctx);
+
+               ring->preallocated_lazy_request = request;
+       }
+
+       return i915_gem_get_seqno(ring->dev, &ring->outstanding_lazy_seqno);
+}
+
+static int logical_ring_wait_request(struct intel_ringbuffer *ringbuf,
+                                    int bytes)
+{
+       struct intel_engine_cs *ring = ringbuf->ring;
+       struct drm_i915_gem_request *request;
+       u32 seqno = 0;
+       int ret;
+
+       if (ringbuf->last_retired_head != -1) {
+               ringbuf->head = ringbuf->last_retired_head;
+               ringbuf->last_retired_head = -1;
+
+               ringbuf->space = intel_ring_space(ringbuf);
+               if (ringbuf->space >= bytes)
+                       return 0;
+       }
+
+       list_for_each_entry(request, &ring->request_list, list) {
+               if (__intel_ring_space(request->tail, ringbuf->tail,
+                                      ringbuf->size) >= bytes) {
+                       seqno = request->seqno;
+                       break;
+               }
+       }
+
+       if (seqno == 0)
+               return -ENOSPC;
+
+       ret = i915_wait_seqno(ring, seqno);
+       if (ret)
+               return ret;
+
+       i915_gem_retire_requests_ring(ring);
+       ringbuf->head = ringbuf->last_retired_head;
+       ringbuf->last_retired_head = -1;
+
+       ringbuf->space = intel_ring_space(ringbuf);
+       return 0;
+}
+
+static int logical_ring_wait_for_space(struct intel_ringbuffer *ringbuf,
+                                      int bytes)
+{
+       struct intel_engine_cs *ring = ringbuf->ring;
+       struct drm_device *dev = ring->dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       unsigned long end;
+       int ret;
+
+       ret = logical_ring_wait_request(ringbuf, bytes);
+       if (ret != -ENOSPC)
+               return ret;
+
+       /* Force the context submission in case we have been skipping it */
+       intel_logical_ring_advance_and_submit(ringbuf);
+
+       /* With GEM the hangcheck timer should kick us out of the loop,
+        * leaving it early runs the risk of corrupting GEM state (due
+        * to running on almost untested codepaths). But on resume
+        * timers don't work yet, so prevent a complete hang in that
+        * case by choosing an insanely large timeout. */
+       end = jiffies + 60 * HZ;
+
+       do {
+               ringbuf->head = I915_READ_HEAD(ring);
+               ringbuf->space = intel_ring_space(ringbuf);
+               if (ringbuf->space >= bytes) {
+                       ret = 0;
+                       break;
+               }
+
+               msleep(1);
+
+               if (dev_priv->mm.interruptible && signal_pending(current)) {
+                       ret = -ERESTARTSYS;
+                       break;
+               }
+
+               ret = i915_gem_check_wedge(&dev_priv->gpu_error,
+                                          dev_priv->mm.interruptible);
+               if (ret)
+                       break;
+
+               if (time_after(jiffies, end)) {
+                       ret = -EBUSY;
+                       break;
+               }
+       } while (1);
+
+       return ret;
+}
+
+static int logical_ring_wrap_buffer(struct intel_ringbuffer *ringbuf)
+{
+       uint32_t __iomem *virt;
+       int rem = ringbuf->size - ringbuf->tail;
+
+       if (ringbuf->space < rem) {
+               int ret = logical_ring_wait_for_space(ringbuf, rem);
+
+               if (ret)
+                       return ret;
+       }
+
+       virt = ringbuf->virtual_start + ringbuf->tail;
+       rem /= 4;
+       while (rem--)
+               iowrite32(MI_NOOP, virt++);
+
+       ringbuf->tail = 0;
+       ringbuf->space = intel_ring_space(ringbuf);
+
+       return 0;
+}
+
+static int logical_ring_prepare(struct intel_ringbuffer *ringbuf, int bytes)
+{
+       int ret;
+
+       if (unlikely(ringbuf->tail + bytes > ringbuf->effective_size)) {
+               ret = logical_ring_wrap_buffer(ringbuf);
+               if (unlikely(ret))
+                       return ret;
+       }
+
+       if (unlikely(ringbuf->space < bytes)) {
+               ret = logical_ring_wait_for_space(ringbuf, bytes);
+               if (unlikely(ret))
+                       return ret;
+       }
+
+       return 0;
+}
+
+/**
+ * intel_logical_ring_begin() - prepare the logical ringbuffer to accept some commands
+ *
+ * @ringbuf: Logical ringbuffer.
+ * @num_dwords: number of DWORDs that we plan to write to the ringbuffer.
+ *
+ * The ringbuffer might not be ready to accept the commands right away (maybe it needs to
+ * be wrapped, or wait a bit for the tail to be updated). This function takes care of that
+ * and also preallocates a request (every workload submission is still mediated through
+ * requests, same as it did with legacy ringbuffer submission).
+ *
+ * Return: non-zero if the ringbuffer is not ready to be written to.
+ */
+int intel_logical_ring_begin(struct intel_ringbuffer *ringbuf, int num_dwords)
+{
+       struct intel_engine_cs *ring = ringbuf->ring;
+       struct drm_device *dev = ring->dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       int ret;
+
+       ret = i915_gem_check_wedge(&dev_priv->gpu_error,
+                                  dev_priv->mm.interruptible);
+       if (ret)
+               return ret;
+
+       ret = logical_ring_prepare(ringbuf, num_dwords * sizeof(uint32_t));
+       if (ret)
+               return ret;
+
+       /* Preallocate the olr before touching the ring */
+       ret = logical_ring_alloc_seqno(ring, ringbuf->FIXME_lrc_ctx);
+       if (ret)
+               return ret;
+
+       ringbuf->space -= num_dwords * sizeof(uint32_t);
+       return 0;
+}
+
+static int gen8_init_common_ring(struct intel_engine_cs *ring)
+{
+       struct drm_device *dev = ring->dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+
+       I915_WRITE_IMR(ring, ~(ring->irq_enable_mask | ring->irq_keep_mask));
+       I915_WRITE(RING_HWSTAM(ring->mmio_base), 0xffffffff);
+
+       I915_WRITE(RING_MODE_GEN7(ring),
+                  _MASKED_BIT_DISABLE(GFX_REPLAY_MODE) |
+                  _MASKED_BIT_ENABLE(GFX_RUN_LIST_ENABLE));
+       POSTING_READ(RING_MODE_GEN7(ring));
+       DRM_DEBUG_DRIVER("Execlists enabled for %s\n", ring->name);
+
+       memset(&ring->hangcheck, 0, sizeof(ring->hangcheck));
+
+       return 0;
+}
+
+static int gen8_init_render_ring(struct intel_engine_cs *ring)
+{
+       struct drm_device *dev = ring->dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       int ret;
+
+       ret = gen8_init_common_ring(ring);
+       if (ret)
+               return ret;
+
+       /* We need to disable the AsyncFlip performance optimisations in order
+        * to use MI_WAIT_FOR_EVENT within the CS. It should already be
+        * programmed to '1' on all products.
+        *
+        * WaDisableAsyncFlipPerfMode:snb,ivb,hsw,vlv,bdw,chv
+        */
+       I915_WRITE(MI_MODE, _MASKED_BIT_ENABLE(ASYNC_FLIP_PERF_DISABLE));
+
+       ret = intel_init_pipe_control(ring);
+       if (ret)
+               return ret;
+
+       I915_WRITE(INSTPM, _MASKED_BIT_ENABLE(INSTPM_FORCE_ORDERING));
+
+       return ret;
+}
+
+static int gen8_emit_bb_start(struct intel_ringbuffer *ringbuf,
+                             u64 offset, unsigned flags)
+{
+       bool ppgtt = !(flags & I915_DISPATCH_SECURE);
+       int ret;
+
+       ret = intel_logical_ring_begin(ringbuf, 4);
+       if (ret)
+               return ret;
+
+       /* FIXME(BDW): Address space and security selectors. */
+       intel_logical_ring_emit(ringbuf, MI_BATCH_BUFFER_START_GEN8 | (ppgtt<<8));
+       intel_logical_ring_emit(ringbuf, lower_32_bits(offset));
+       intel_logical_ring_emit(ringbuf, upper_32_bits(offset));
+       intel_logical_ring_emit(ringbuf, MI_NOOP);
+       intel_logical_ring_advance(ringbuf);
+
+       return 0;
+}
+
+static bool gen8_logical_ring_get_irq(struct intel_engine_cs *ring)
+{
+       struct drm_device *dev = ring->dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       unsigned long flags;
+
+       if (!dev->irq_enabled)
+               return false;
+
+       spin_lock_irqsave(&dev_priv->irq_lock, flags);
+       if (ring->irq_refcount++ == 0) {
+               I915_WRITE_IMR(ring, ~(ring->irq_enable_mask | ring->irq_keep_mask));
+               POSTING_READ(RING_IMR(ring->mmio_base));
+       }
+       spin_unlock_irqrestore(&dev_priv->irq_lock, flags);
+
+       return true;
+}
+
+static void gen8_logical_ring_put_irq(struct intel_engine_cs *ring)
+{
+       struct drm_device *dev = ring->dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       unsigned long flags;
+
+       spin_lock_irqsave(&dev_priv->irq_lock, flags);
+       if (--ring->irq_refcount == 0) {
+               I915_WRITE_IMR(ring, ~ring->irq_keep_mask);
+               POSTING_READ(RING_IMR(ring->mmio_base));
+       }
+       spin_unlock_irqrestore(&dev_priv->irq_lock, flags);
+}
+
+static int gen8_emit_flush(struct intel_ringbuffer *ringbuf,
+                          u32 invalidate_domains,
+                          u32 unused)
+{
+       struct intel_engine_cs *ring = ringbuf->ring;
+       struct drm_device *dev = ring->dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       uint32_t cmd;
+       int ret;
+
+       ret = intel_logical_ring_begin(ringbuf, 4);
+       if (ret)
+               return ret;
+
+       cmd = MI_FLUSH_DW + 1;
+
+       if (ring == &dev_priv->ring[VCS]) {
+               if (invalidate_domains & I915_GEM_GPU_DOMAINS)
+                       cmd |= MI_INVALIDATE_TLB | MI_INVALIDATE_BSD |
+                               MI_FLUSH_DW_STORE_INDEX |
+                               MI_FLUSH_DW_OP_STOREDW;
+       } else {
+               if (invalidate_domains & I915_GEM_DOMAIN_RENDER)
+                       cmd |= MI_INVALIDATE_TLB | MI_FLUSH_DW_STORE_INDEX |
+                               MI_FLUSH_DW_OP_STOREDW;
+       }
+
+       intel_logical_ring_emit(ringbuf, cmd);
+       intel_logical_ring_emit(ringbuf,
+                               I915_GEM_HWS_SCRATCH_ADDR |
+                               MI_FLUSH_DW_USE_GTT);
+       intel_logical_ring_emit(ringbuf, 0); /* upper addr */
+       intel_logical_ring_emit(ringbuf, 0); /* value */
+       intel_logical_ring_advance(ringbuf);
+
+       return 0;
+}
+
+static int gen8_emit_flush_render(struct intel_ringbuffer *ringbuf,
+                                 u32 invalidate_domains,
+                                 u32 flush_domains)
+{
+       struct intel_engine_cs *ring = ringbuf->ring;
+       u32 scratch_addr = ring->scratch.gtt_offset + 2 * CACHELINE_BYTES;
+       u32 flags = 0;
+       int ret;
+
+       flags |= PIPE_CONTROL_CS_STALL;
+
+       if (flush_domains) {
+               flags |= PIPE_CONTROL_RENDER_TARGET_CACHE_FLUSH;
+               flags |= PIPE_CONTROL_DEPTH_CACHE_FLUSH;
+       }
+
+       if (invalidate_domains) {
+               flags |= PIPE_CONTROL_TLB_INVALIDATE;
+               flags |= PIPE_CONTROL_INSTRUCTION_CACHE_INVALIDATE;
+               flags |= PIPE_CONTROL_TEXTURE_CACHE_INVALIDATE;
+               flags |= PIPE_CONTROL_VF_CACHE_INVALIDATE;
+               flags |= PIPE_CONTROL_CONST_CACHE_INVALIDATE;
+               flags |= PIPE_CONTROL_STATE_CACHE_INVALIDATE;
+               flags |= PIPE_CONTROL_QW_WRITE;
+               flags |= PIPE_CONTROL_GLOBAL_GTT_IVB;
+       }
+
+       ret = intel_logical_ring_begin(ringbuf, 6);
+       if (ret)
+               return ret;
+
+       intel_logical_ring_emit(ringbuf, GFX_OP_PIPE_CONTROL(6));
+       intel_logical_ring_emit(ringbuf, flags);
+       intel_logical_ring_emit(ringbuf, scratch_addr);
+       intel_logical_ring_emit(ringbuf, 0);
+       intel_logical_ring_emit(ringbuf, 0);
+       intel_logical_ring_emit(ringbuf, 0);
+       intel_logical_ring_advance(ringbuf);
+
+       return 0;
+}
+
+static u32 gen8_get_seqno(struct intel_engine_cs *ring, bool lazy_coherency)
+{
+       return intel_read_status_page(ring, I915_GEM_HWS_INDEX);
+}
+
+static void gen8_set_seqno(struct intel_engine_cs *ring, u32 seqno)
+{
+       intel_write_status_page(ring, I915_GEM_HWS_INDEX, seqno);
+}
+
+static int gen8_emit_request(struct intel_ringbuffer *ringbuf)
+{
+       struct intel_engine_cs *ring = ringbuf->ring;
+       u32 cmd;
+       int ret;
+
+       ret = intel_logical_ring_begin(ringbuf, 6);
+       if (ret)
+               return ret;
+
+       cmd = MI_STORE_DWORD_IMM_GEN8;
+       cmd |= MI_GLOBAL_GTT;
+
+       intel_logical_ring_emit(ringbuf, cmd);
+       intel_logical_ring_emit(ringbuf,
+                               (ring->status_page.gfx_addr +
+                               (I915_GEM_HWS_INDEX << MI_STORE_DWORD_INDEX_SHIFT)));
+       intel_logical_ring_emit(ringbuf, 0);
+       intel_logical_ring_emit(ringbuf, ring->outstanding_lazy_seqno);
+       intel_logical_ring_emit(ringbuf, MI_USER_INTERRUPT);
+       intel_logical_ring_emit(ringbuf, MI_NOOP);
+       intel_logical_ring_advance_and_submit(ringbuf);
+
+       return 0;
+}
+
+/**
+ * intel_logical_ring_cleanup() - deallocate the Engine Command Streamer
+ *
+ * @ring: Engine Command Streamer.
+ *
+ */
+void intel_logical_ring_cleanup(struct intel_engine_cs *ring)
+{
+       struct drm_i915_private *dev_priv = ring->dev->dev_private;
+
+       if (!intel_ring_initialized(ring))
+               return;
+
+       intel_logical_ring_stop(ring);
+       WARN_ON((I915_READ_MODE(ring) & MODE_IDLE) == 0);
+       ring->preallocated_lazy_request = NULL;
+       ring->outstanding_lazy_seqno = 0;
+
+       if (ring->cleanup)
+               ring->cleanup(ring);
+
+       i915_cmd_parser_fini_ring(ring);
+
+       if (ring->status_page.obj) {
+               kunmap(sg_page(ring->status_page.obj->pages->sgl));
+               ring->status_page.obj = NULL;
+       }
+}
+
+static int logical_ring_init(struct drm_device *dev, struct intel_engine_cs *ring)
+{
+       int ret;
+
+       /* Intentionally left blank. */
+       ring->buffer = NULL;
+
+       ring->dev = dev;
+       INIT_LIST_HEAD(&ring->active_list);
+       INIT_LIST_HEAD(&ring->request_list);
+       init_waitqueue_head(&ring->irq_queue);
+
+       INIT_LIST_HEAD(&ring->execlist_queue);
+       spin_lock_init(&ring->execlist_lock);
+       ring->next_context_status_buffer = 0;
+
+       ret = i915_cmd_parser_init_ring(ring);
+       if (ret)
+               return ret;
+
+       if (ring->init) {
+               ret = ring->init(ring);
+               if (ret)
+                       return ret;
+       }
+
+       ret = intel_lr_context_deferred_create(ring->default_context, ring);
+
+       return ret;
+}
+
+static int logical_render_ring_init(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct intel_engine_cs *ring = &dev_priv->ring[RCS];
+
+       ring->name = "render ring";
+       ring->id = RCS;
+       ring->mmio_base = RENDER_RING_BASE;
+       ring->irq_enable_mask =
+               GT_RENDER_USER_INTERRUPT << GEN8_RCS_IRQ_SHIFT;
+       ring->irq_keep_mask =
+               GT_CONTEXT_SWITCH_INTERRUPT << GEN8_RCS_IRQ_SHIFT;
+       if (HAS_L3_DPF(dev))
+               ring->irq_keep_mask |= GT_RENDER_L3_PARITY_ERROR_INTERRUPT;
+
+       ring->init = gen8_init_render_ring;
+       ring->cleanup = intel_fini_pipe_control;
+       ring->get_seqno = gen8_get_seqno;
+       ring->set_seqno = gen8_set_seqno;
+       ring->emit_request = gen8_emit_request;
+       ring->emit_flush = gen8_emit_flush_render;
+       ring->irq_get = gen8_logical_ring_get_irq;
+       ring->irq_put = gen8_logical_ring_put_irq;
+       ring->emit_bb_start = gen8_emit_bb_start;
+
+       return logical_ring_init(dev, ring);
+}
+
+static int logical_bsd_ring_init(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct intel_engine_cs *ring = &dev_priv->ring[VCS];
+
+       ring->name = "bsd ring";
+       ring->id = VCS;
+       ring->mmio_base = GEN6_BSD_RING_BASE;
+       ring->irq_enable_mask =
+               GT_RENDER_USER_INTERRUPT << GEN8_VCS1_IRQ_SHIFT;
+       ring->irq_keep_mask =
+               GT_CONTEXT_SWITCH_INTERRUPT << GEN8_VCS1_IRQ_SHIFT;
+
+       ring->init = gen8_init_common_ring;
+       ring->get_seqno = gen8_get_seqno;
+       ring->set_seqno = gen8_set_seqno;
+       ring->emit_request = gen8_emit_request;
+       ring->emit_flush = gen8_emit_flush;
+       ring->irq_get = gen8_logical_ring_get_irq;
+       ring->irq_put = gen8_logical_ring_put_irq;
+       ring->emit_bb_start = gen8_emit_bb_start;
+
+       return logical_ring_init(dev, ring);
+}
+
+static int logical_bsd2_ring_init(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct intel_engine_cs *ring = &dev_priv->ring[VCS2];
+
+       ring->name = "bds2 ring";
+       ring->id = VCS2;
+       ring->mmio_base = GEN8_BSD2_RING_BASE;
+       ring->irq_enable_mask =
+               GT_RENDER_USER_INTERRUPT << GEN8_VCS2_IRQ_SHIFT;
+       ring->irq_keep_mask =
+               GT_CONTEXT_SWITCH_INTERRUPT << GEN8_VCS2_IRQ_SHIFT;
+
+       ring->init = gen8_init_common_ring;
+       ring->get_seqno = gen8_get_seqno;
+       ring->set_seqno = gen8_set_seqno;
+       ring->emit_request = gen8_emit_request;
+       ring->emit_flush = gen8_emit_flush;
+       ring->irq_get = gen8_logical_ring_get_irq;
+       ring->irq_put = gen8_logical_ring_put_irq;
+       ring->emit_bb_start = gen8_emit_bb_start;
+
+       return logical_ring_init(dev, ring);
+}
+
+static int logical_blt_ring_init(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct intel_engine_cs *ring = &dev_priv->ring[BCS];
+
+       ring->name = "blitter ring";
+       ring->id = BCS;
+       ring->mmio_base = BLT_RING_BASE;
+       ring->irq_enable_mask =
+               GT_RENDER_USER_INTERRUPT << GEN8_BCS_IRQ_SHIFT;
+       ring->irq_keep_mask =
+               GT_CONTEXT_SWITCH_INTERRUPT << GEN8_BCS_IRQ_SHIFT;
+
+       ring->init = gen8_init_common_ring;
+       ring->get_seqno = gen8_get_seqno;
+       ring->set_seqno = gen8_set_seqno;
+       ring->emit_request = gen8_emit_request;
+       ring->emit_flush = gen8_emit_flush;
+       ring->irq_get = gen8_logical_ring_get_irq;
+       ring->irq_put = gen8_logical_ring_put_irq;
+       ring->emit_bb_start = gen8_emit_bb_start;
+
+       return logical_ring_init(dev, ring);
+}
+
+static int logical_vebox_ring_init(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct intel_engine_cs *ring = &dev_priv->ring[VECS];
+
+       ring->name = "video enhancement ring";
+       ring->id = VECS;
+       ring->mmio_base = VEBOX_RING_BASE;
+       ring->irq_enable_mask =
+               GT_RENDER_USER_INTERRUPT << GEN8_VECS_IRQ_SHIFT;
+       ring->irq_keep_mask =
+               GT_CONTEXT_SWITCH_INTERRUPT << GEN8_VECS_IRQ_SHIFT;
+
+       ring->init = gen8_init_common_ring;
+       ring->get_seqno = gen8_get_seqno;
+       ring->set_seqno = gen8_set_seqno;
+       ring->emit_request = gen8_emit_request;
+       ring->emit_flush = gen8_emit_flush;
+       ring->irq_get = gen8_logical_ring_get_irq;
+       ring->irq_put = gen8_logical_ring_put_irq;
+       ring->emit_bb_start = gen8_emit_bb_start;
+
+       return logical_ring_init(dev, ring);
+}
+
+/**
+ * intel_logical_rings_init() - allocate, populate and init the Engine Command Streamers
+ * @dev: DRM device.
+ *
+ * This function inits the engines for an Execlists submission style (the equivalent in the
+ * legacy ringbuffer submission world would be i915_gem_init_rings). It does it only for
+ * those engines that are present in the hardware.
+ *
+ * Return: non-zero if the initialization failed.
+ */
+int intel_logical_rings_init(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       int ret;
+
+       ret = logical_render_ring_init(dev);
+       if (ret)
+               return ret;
+
+       if (HAS_BSD(dev)) {
+               ret = logical_bsd_ring_init(dev);
+               if (ret)
+                       goto cleanup_render_ring;
+       }
+
+       if (HAS_BLT(dev)) {
+               ret = logical_blt_ring_init(dev);
+               if (ret)
+                       goto cleanup_bsd_ring;
+       }
+
+       if (HAS_VEBOX(dev)) {
+               ret = logical_vebox_ring_init(dev);
+               if (ret)
+                       goto cleanup_blt_ring;
+       }
+
+       if (HAS_BSD2(dev)) {
+               ret = logical_bsd2_ring_init(dev);
+               if (ret)
+                       goto cleanup_vebox_ring;
+       }
+
+       ret = i915_gem_set_seqno(dev, ((u32)~0 - 0x1000));
+       if (ret)
+               goto cleanup_bsd2_ring;
+
+       return 0;
+
+cleanup_bsd2_ring:
+       intel_logical_ring_cleanup(&dev_priv->ring[VCS2]);
+cleanup_vebox_ring:
+       intel_logical_ring_cleanup(&dev_priv->ring[VECS]);
+cleanup_blt_ring:
+       intel_logical_ring_cleanup(&dev_priv->ring[BCS]);
+cleanup_bsd_ring:
+       intel_logical_ring_cleanup(&dev_priv->ring[VCS]);
+cleanup_render_ring:
+       intel_logical_ring_cleanup(&dev_priv->ring[RCS]);
+
+       return ret;
+}
+
+int intel_lr_context_render_state_init(struct intel_engine_cs *ring,
+                                      struct intel_context *ctx)
+{
+       struct intel_ringbuffer *ringbuf = ctx->engine[ring->id].ringbuf;
+       struct render_state so;
+       struct drm_i915_file_private *file_priv = ctx->file_priv;
+       struct drm_file *file = file_priv ? file_priv->file : NULL;
+       int ret;
+
+       ret = i915_gem_render_state_prepare(ring, &so);
+       if (ret)
+               return ret;
+
+       if (so.rodata == NULL)
+               return 0;
+
+       ret = ring->emit_bb_start(ringbuf,
+                       so.ggtt_offset,
+                       I915_DISPATCH_SECURE);
+       if (ret)
+               goto out;
+
+       i915_vma_move_to_active(i915_gem_obj_to_ggtt(so.obj), ring);
+
+       ret = __i915_add_request(ring, file, so.obj, NULL);
+       /* intel_logical_ring_add_request moves object to inactive if it
+        * fails */
+out:
+       i915_gem_render_state_fini(&so);
+       return ret;
+}
+
+static int
+populate_lr_context(struct intel_context *ctx, struct drm_i915_gem_object *ctx_obj,
+                   struct intel_engine_cs *ring, struct intel_ringbuffer *ringbuf)
+{
+       struct drm_device *dev = ring->dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct drm_i915_gem_object *ring_obj = ringbuf->obj;
+       struct i915_hw_ppgtt *ppgtt = ctx->ppgtt;
+       struct page *page;
+       uint32_t *reg_state;
+       int ret;
+
+       if (!ppgtt)
+               ppgtt = dev_priv->mm.aliasing_ppgtt;
+
+       ret = i915_gem_object_set_to_cpu_domain(ctx_obj, true);
+       if (ret) {
+               DRM_DEBUG_DRIVER("Could not set to CPU domain\n");
+               return ret;
+       }
+
+       ret = i915_gem_object_get_pages(ctx_obj);
+       if (ret) {
+               DRM_DEBUG_DRIVER("Could not get object pages\n");
+               return ret;
+       }
+
+       i915_gem_object_pin_pages(ctx_obj);
+
+       /* The second page of the context object contains some fields which must
+        * be set up prior to the first execution. */
+       page = i915_gem_object_get_page(ctx_obj, 1);
+       reg_state = kmap_atomic(page);
+
+       /* A context is actually a big batch buffer with several MI_LOAD_REGISTER_IMM
+        * commands followed by (reg, value) pairs. The values we are setting here are
+        * only for the first context restore: on a subsequent save, the GPU will
+        * recreate this batchbuffer with new values (including all the missing
+        * MI_LOAD_REGISTER_IMM commands that we are not initializing here). */
+       if (ring->id == RCS)
+               reg_state[CTX_LRI_HEADER_0] = MI_LOAD_REGISTER_IMM(14);
+       else
+               reg_state[CTX_LRI_HEADER_0] = MI_LOAD_REGISTER_IMM(11);
+       reg_state[CTX_LRI_HEADER_0] |= MI_LRI_FORCE_POSTED;
+       reg_state[CTX_CONTEXT_CONTROL] = RING_CONTEXT_CONTROL(ring);
+       reg_state[CTX_CONTEXT_CONTROL+1] =
+                       _MASKED_BIT_ENABLE((1<<3) | MI_RESTORE_INHIBIT);
+       reg_state[CTX_RING_HEAD] = RING_HEAD(ring->mmio_base);
+       reg_state[CTX_RING_HEAD+1] = 0;
+       reg_state[CTX_RING_TAIL] = RING_TAIL(ring->mmio_base);
+       reg_state[CTX_RING_TAIL+1] = 0;
+       reg_state[CTX_RING_BUFFER_START] = RING_START(ring->mmio_base);
+       reg_state[CTX_RING_BUFFER_START+1] = i915_gem_obj_ggtt_offset(ring_obj);
+       reg_state[CTX_RING_BUFFER_CONTROL] = RING_CTL(ring->mmio_base);
+       reg_state[CTX_RING_BUFFER_CONTROL+1] =
+                       ((ringbuf->size - PAGE_SIZE) & RING_NR_PAGES) | RING_VALID;
+       reg_state[CTX_BB_HEAD_U] = ring->mmio_base + 0x168;
+       reg_state[CTX_BB_HEAD_U+1] = 0;
+       reg_state[CTX_BB_HEAD_L] = ring->mmio_base + 0x140;
+       reg_state[CTX_BB_HEAD_L+1] = 0;
+       reg_state[CTX_BB_STATE] = ring->mmio_base + 0x110;
+       reg_state[CTX_BB_STATE+1] = (1<<5);
+       reg_state[CTX_SECOND_BB_HEAD_U] = ring->mmio_base + 0x11c;
+       reg_state[CTX_SECOND_BB_HEAD_U+1] = 0;
+       reg_state[CTX_SECOND_BB_HEAD_L] = ring->mmio_base + 0x114;
+       reg_state[CTX_SECOND_BB_HEAD_L+1] = 0;
+       reg_state[CTX_SECOND_BB_STATE] = ring->mmio_base + 0x118;
+       reg_state[CTX_SECOND_BB_STATE+1] = 0;
+       if (ring->id == RCS) {
+               /* TODO: according to BSpec, the register state context
+                * for CHV does not have these. OTOH, these registers do
+                * exist in CHV. I'm waiting for a clarification */
+               reg_state[CTX_BB_PER_CTX_PTR] = ring->mmio_base + 0x1c0;
+               reg_state[CTX_BB_PER_CTX_PTR+1] = 0;
+               reg_state[CTX_RCS_INDIRECT_CTX] = ring->mmio_base + 0x1c4;
+               reg_state[CTX_RCS_INDIRECT_CTX+1] = 0;
+               reg_state[CTX_RCS_INDIRECT_CTX_OFFSET] = ring->mmio_base + 0x1c8;
+               reg_state[CTX_RCS_INDIRECT_CTX_OFFSET+1] = 0;
+       }
+       reg_state[CTX_LRI_HEADER_1] = MI_LOAD_REGISTER_IMM(9);
+       reg_state[CTX_LRI_HEADER_1] |= MI_LRI_FORCE_POSTED;
+       reg_state[CTX_CTX_TIMESTAMP] = ring->mmio_base + 0x3a8;
+       reg_state[CTX_CTX_TIMESTAMP+1] = 0;
+       reg_state[CTX_PDP3_UDW] = GEN8_RING_PDP_UDW(ring, 3);
+       reg_state[CTX_PDP3_LDW] = GEN8_RING_PDP_LDW(ring, 3);
+       reg_state[CTX_PDP2_UDW] = GEN8_RING_PDP_UDW(ring, 2);
+       reg_state[CTX_PDP2_LDW] = GEN8_RING_PDP_LDW(ring, 2);
+       reg_state[CTX_PDP1_UDW] = GEN8_RING_PDP_UDW(ring, 1);
+       reg_state[CTX_PDP1_LDW] = GEN8_RING_PDP_LDW(ring, 1);
+       reg_state[CTX_PDP0_UDW] = GEN8_RING_PDP_UDW(ring, 0);
+       reg_state[CTX_PDP0_LDW] = GEN8_RING_PDP_LDW(ring, 0);
+       reg_state[CTX_PDP3_UDW+1] = upper_32_bits(ppgtt->pd_dma_addr[3]);
+       reg_state[CTX_PDP3_LDW+1] = lower_32_bits(ppgtt->pd_dma_addr[3]);
+       reg_state[CTX_PDP2_UDW+1] = upper_32_bits(ppgtt->pd_dma_addr[2]);
+       reg_state[CTX_PDP2_LDW+1] = lower_32_bits(ppgtt->pd_dma_addr[2]);
+       reg_state[CTX_PDP1_UDW+1] = upper_32_bits(ppgtt->pd_dma_addr[1]);
+       reg_state[CTX_PDP1_LDW+1] = lower_32_bits(ppgtt->pd_dma_addr[1]);
+       reg_state[CTX_PDP0_UDW+1] = upper_32_bits(ppgtt->pd_dma_addr[0]);
+       reg_state[CTX_PDP0_LDW+1] = lower_32_bits(ppgtt->pd_dma_addr[0]);
+       if (ring->id == RCS) {
+               reg_state[CTX_LRI_HEADER_2] = MI_LOAD_REGISTER_IMM(1);
+               reg_state[CTX_R_PWR_CLK_STATE] = 0x20c8;
+               reg_state[CTX_R_PWR_CLK_STATE+1] = 0;
+       }
+
+       kunmap_atomic(reg_state);
+
+       ctx_obj->dirty = 1;
+       set_page_dirty(page);
+       i915_gem_object_unpin_pages(ctx_obj);
+
+       return 0;
+}
+
+/**
+ * intel_lr_context_free() - free the LRC specific bits of a context
+ * @ctx: the LR context to free.
+ *
+ * The real context freeing is done in i915_gem_context_free: this only
+ * takes care of the bits that are LRC related: the per-engine backing
+ * objects and the logical ringbuffer.
+ */
+void intel_lr_context_free(struct intel_context *ctx)
+{
+       int i;
+
+       for (i = 0; i < I915_NUM_RINGS; i++) {
+               struct drm_i915_gem_object *ctx_obj = ctx->engine[i].state;
+               struct intel_ringbuffer *ringbuf = ctx->engine[i].ringbuf;
+
+               if (ctx_obj) {
+                       intel_destroy_ringbuffer_obj(ringbuf);
+                       kfree(ringbuf);
+                       i915_gem_object_ggtt_unpin(ctx_obj);
+                       drm_gem_object_unreference(&ctx_obj->base);
+               }
+       }
+}
+
+static uint32_t get_lr_context_size(struct intel_engine_cs *ring)
+{
+       int ret = 0;
+
+       WARN_ON(INTEL_INFO(ring->dev)->gen != 8);
+
+       switch (ring->id) {
+       case RCS:
+               ret = GEN8_LR_CONTEXT_RENDER_SIZE;
+               break;
+       case VCS:
+       case BCS:
+       case VECS:
+       case VCS2:
+               ret = GEN8_LR_CONTEXT_OTHER_SIZE;
+               break;
+       }
+
+       return ret;
+}
+
+/**
+ * intel_lr_context_deferred_create() - create the LRC specific bits of a context
+ * @ctx: LR context to create.
+ * @ring: engine to be used with the context.
+ *
+ * This function can be called more than once, with different engines, if we plan
+ * to use the context with them. The context backing objects and the ringbuffers
+ * (specially the ringbuffer backing objects) suck a lot of memory up, and that's why
+ * the creation is a deferred call: it's better to make sure first that we need to use
+ * a given ring with the context.
+ *
+ * Return: non-zero on eror.
+ */
+int intel_lr_context_deferred_create(struct intel_context *ctx,
+                                    struct intel_engine_cs *ring)
+{
+       struct drm_device *dev = ring->dev;
+       struct drm_i915_gem_object *ctx_obj;
+       uint32_t context_size;
+       struct intel_ringbuffer *ringbuf;
+       int ret;
+
+       WARN_ON(ctx->legacy_hw_ctx.rcs_state != NULL);
+       if (ctx->engine[ring->id].state)
+               return 0;
+
+       context_size = round_up(get_lr_context_size(ring), 4096);
+
+       ctx_obj = i915_gem_alloc_context_obj(dev, context_size);
+       if (IS_ERR(ctx_obj)) {
+               ret = PTR_ERR(ctx_obj);
+               DRM_DEBUG_DRIVER("Alloc LRC backing obj failed: %d\n", ret);
+               return ret;
+       }
+
+       ret = i915_gem_obj_ggtt_pin(ctx_obj, GEN8_LR_CONTEXT_ALIGN, 0);
+       if (ret) {
+               DRM_DEBUG_DRIVER("Pin LRC backing obj failed: %d\n", ret);
+               drm_gem_object_unreference(&ctx_obj->base);
+               return ret;
+       }
+
+       ringbuf = kzalloc(sizeof(*ringbuf), GFP_KERNEL);
+       if (!ringbuf) {
+               DRM_DEBUG_DRIVER("Failed to allocate ringbuffer %s\n",
+                               ring->name);
+               i915_gem_object_ggtt_unpin(ctx_obj);
+               drm_gem_object_unreference(&ctx_obj->base);
+               ret = -ENOMEM;
+               return ret;
+       }
+
+       ringbuf->ring = ring;
+       ringbuf->FIXME_lrc_ctx = ctx;
+
+       ringbuf->size = 32 * PAGE_SIZE;
+       ringbuf->effective_size = ringbuf->size;
+       ringbuf->head = 0;
+       ringbuf->tail = 0;
+       ringbuf->space = ringbuf->size;
+       ringbuf->last_retired_head = -1;
+
+       /* TODO: For now we put this in the mappable region so that we can reuse
+        * the existing ringbuffer code which ioremaps it. When we start
+        * creating many contexts, this will no longer work and we must switch
+        * to a kmapish interface.
+        */
+       ret = intel_alloc_ringbuffer_obj(dev, ringbuf);
+       if (ret) {
+               DRM_DEBUG_DRIVER("Failed to allocate ringbuffer obj %s: %d\n",
+                               ring->name, ret);
+               goto error;
+       }
+
+       ret = populate_lr_context(ctx, ctx_obj, ring, ringbuf);
+       if (ret) {
+               DRM_DEBUG_DRIVER("Failed to populate LRC: %d\n", ret);
+               intel_destroy_ringbuffer_obj(ringbuf);
+               goto error;
+       }
+
+       ctx->engine[ring->id].ringbuf = ringbuf;
+       ctx->engine[ring->id].state = ctx_obj;
+
+       if (ctx == ring->default_context) {
+               /* The status page is offset 0 from the default context object
+                * in LRC mode. */
+               ring->status_page.gfx_addr = i915_gem_obj_ggtt_offset(ctx_obj);
+               ring->status_page.page_addr =
+                               kmap(sg_page(ctx_obj->pages->sgl));
+               if (ring->status_page.page_addr == NULL)
+                       return -ENOMEM;
+               ring->status_page.obj = ctx_obj;
+       }
+
+       if (ring->id == RCS && !ctx->rcs_initialized) {
+               ret = intel_lr_context_render_state_init(ring, ctx);
+               if (ret) {
+                       DRM_ERROR("Init render state failed: %d\n", ret);
+                       ctx->engine[ring->id].ringbuf = NULL;
+                       ctx->engine[ring->id].state = NULL;
+                       intel_destroy_ringbuffer_obj(ringbuf);
+                       goto error;
+               }
+               ctx->rcs_initialized = true;
+       }
+
+       return 0;
+
+error:
+       kfree(ringbuf);
+       i915_gem_object_ggtt_unpin(ctx_obj);
+       drm_gem_object_unreference(&ctx_obj->base);
+       return ret;
+}
diff --git a/drivers/gpu/drm/i915/intel_lrc.h b/drivers/gpu/drm/i915/intel_lrc.h
new file mode 100644 (file)
index 0000000..33c3b4b
--- /dev/null
@@ -0,0 +1,114 @@
+/*
+ * Copyright Â© 2014 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef _INTEL_LRC_H_
+#define _INTEL_LRC_H_
+
+/* Execlists regs */
+#define RING_ELSP(ring)                        ((ring)->mmio_base+0x230)
+#define RING_EXECLIST_STATUS(ring)     ((ring)->mmio_base+0x234)
+#define RING_CONTEXT_CONTROL(ring)     ((ring)->mmio_base+0x244)
+#define RING_CONTEXT_STATUS_BUF(ring)  ((ring)->mmio_base+0x370)
+#define RING_CONTEXT_STATUS_PTR(ring)  ((ring)->mmio_base+0x3a0)
+
+/* Logical Rings */
+void intel_logical_ring_stop(struct intel_engine_cs *ring);
+void intel_logical_ring_cleanup(struct intel_engine_cs *ring);
+int intel_logical_rings_init(struct drm_device *dev);
+
+int logical_ring_flush_all_caches(struct intel_ringbuffer *ringbuf);
+void intel_logical_ring_advance_and_submit(struct intel_ringbuffer *ringbuf);
+/**
+ * intel_logical_ring_advance() - advance the ringbuffer tail
+ * @ringbuf: Ringbuffer to advance.
+ *
+ * The tail is only updated in our logical ringbuffer struct.
+ */
+static inline void intel_logical_ring_advance(struct intel_ringbuffer *ringbuf)
+{
+       ringbuf->tail &= ringbuf->size - 1;
+}
+/**
+ * intel_logical_ring_emit() - write a DWORD to the ringbuffer.
+ * @ringbuf: Ringbuffer to write to.
+ * @data: DWORD to write.
+ */
+static inline void intel_logical_ring_emit(struct intel_ringbuffer *ringbuf,
+                                          u32 data)
+{
+       iowrite32(data, ringbuf->virtual_start + ringbuf->tail);
+       ringbuf->tail += 4;
+}
+int intel_logical_ring_begin(struct intel_ringbuffer *ringbuf, int num_dwords);
+
+/* Logical Ring Contexts */
+int intel_lr_context_render_state_init(struct intel_engine_cs *ring,
+                                      struct intel_context *ctx);
+void intel_lr_context_free(struct intel_context *ctx);
+int intel_lr_context_deferred_create(struct intel_context *ctx,
+                                    struct intel_engine_cs *ring);
+
+/* Execlists */
+int intel_sanitize_enable_execlists(struct drm_device *dev, int enable_execlists);
+int intel_execlists_submission(struct drm_device *dev, struct drm_file *file,
+                              struct intel_engine_cs *ring,
+                              struct intel_context *ctx,
+                              struct drm_i915_gem_execbuffer2 *args,
+                              struct list_head *vmas,
+                              struct drm_i915_gem_object *batch_obj,
+                              u64 exec_start, u32 flags);
+u32 intel_execlists_ctx_id(struct drm_i915_gem_object *ctx_obj);
+
+/**
+ * struct intel_ctx_submit_request - queued context submission request
+ * @ctx: Context to submit to the ELSP.
+ * @ring: Engine to submit it to.
+ * @tail: how far in the context's ringbuffer this request goes to.
+ * @execlist_link: link in the submission queue.
+ * @work: workqueue for processing this request in a bottom half.
+ * @elsp_submitted: no. of times this request has been sent to the ELSP.
+ *
+ * The ELSP only accepts two elements at a time, so we queue context/tail
+ * pairs on a given queue (ring->execlist_queue) until the hardware is
+ * available. The queue serves a double purpose: we also use it to keep track
+ * of the up to 2 contexts currently in the hardware (usually one in execution
+ * and the other queued up by the GPU): We only remove elements from the head
+ * of the queue when the hardware informs us that an element has been
+ * completed.
+ *
+ * All accesses to the queue are mediated by a spinlock (ring->execlist_lock).
+ */
+struct intel_ctx_submit_request {
+       struct intel_context *ctx;
+       struct intel_engine_cs *ring;
+       u32 tail;
+
+       struct list_head execlist_link;
+       struct work_struct work;
+
+       int elsp_submitted;
+};
+
+void intel_execlists_handle_ctx_events(struct intel_engine_cs *ring);
+
+#endif /* _INTEL_LRC_H_ */
index fdf40267249c1031a4a52a8f110b41fbf93ff61f..a6bd1422e38fd33fccc19f2fd78684291c0f54d3 100644 (file)
@@ -823,8 +823,7 @@ bool intel_is_dual_link_lvds(struct drm_device *dev)
        struct intel_encoder *encoder;
        struct intel_lvds_encoder *lvds_encoder;
 
-       list_for_each_entry(encoder, &dev->mode_config.encoder_list,
-                           base.head) {
+       for_each_intel_encoder(dev, encoder) {
                if (encoder->type == INTEL_OUTPUT_LVDS) {
                        lvds_encoder = to_lvds_encoder(&encoder->base);
 
index 8e374449c6b562356f47ac2ba169f974f8e7226f..18784470a760def6c6fd4af4938e53145acd4cab 100644 (file)
@@ -751,6 +751,8 @@ void intel_panel_disable_backlight(struct intel_connector *connector)
 
        spin_lock_irqsave(&dev_priv->backlight_lock, flags);
 
+       if (panel->backlight.device)
+               panel->backlight.device->props.power = FB_BLANK_POWERDOWN;
        panel->backlight.enabled = false;
        dev_priv->display.disable_backlight(connector);
 
@@ -957,6 +959,8 @@ void intel_panel_enable_backlight(struct intel_connector *connector)
 
        dev_priv->display.enable_backlight(connector);
        panel->backlight.enabled = true;
+       if (panel->backlight.device)
+               panel->backlight.device->props.power = FB_BLANK_UNBLANK;
 
        spin_unlock_irqrestore(&dev_priv->backlight_lock, flags);
 }
@@ -965,6 +969,7 @@ void intel_panel_enable_backlight(struct intel_connector *connector)
 static int intel_backlight_device_update_status(struct backlight_device *bd)
 {
        struct intel_connector *connector = bl_get_data(bd);
+       struct intel_panel *panel = &connector->panel;
        struct drm_device *dev = connector->base.dev;
 
        drm_modeset_lock(&dev->mode_config.connection_mutex, NULL);
@@ -972,6 +977,23 @@ static int intel_backlight_device_update_status(struct backlight_device *bd)
                      bd->props.brightness, bd->props.max_brightness);
        intel_panel_set_backlight(connector, bd->props.brightness,
                                  bd->props.max_brightness);
+
+       /*
+        * Allow flipping bl_power as a sub-state of enabled. Sadly the
+        * backlight class device does not make it easy to to differentiate
+        * between callbacks for brightness and bl_power, so our backlight_power
+        * callback needs to take this into account.
+        */
+       if (panel->backlight.enabled) {
+               if (panel->backlight_power) {
+                       bool enable = bd->props.power == FB_BLANK_UNBLANK &&
+                               bd->props.brightness != 0;
+                       panel->backlight_power(connector, enable);
+               }
+       } else {
+               bd->props.power = FB_BLANK_POWERDOWN;
+       }
+
        drm_modeset_unlock(&dev->mode_config.connection_mutex);
        return 0;
 }
@@ -1023,6 +1045,11 @@ static int intel_backlight_device_register(struct intel_connector *connector)
                                            panel->backlight.level,
                                            props.max_brightness);
 
+       if (panel->backlight.enabled)
+               props.power = FB_BLANK_UNBLANK;
+       else
+               props.power = FB_BLANK_POWERDOWN;
+
        /*
         * Note: using the same name independent of the connector prevents
         * registration of multiple backlight devices in the driver.
@@ -1203,7 +1230,7 @@ static int vlv_setup_backlight(struct intel_connector *connector)
        enum pipe pipe;
        u32 ctl, ctl2, val;
 
-       for_each_pipe(pipe) {
+       for_each_pipe(dev_priv, pipe) {
                u32 cur_val = I915_READ(VLV_BLC_PWM_CTL(pipe));
 
                /* Skip if the modulation freq is already set */
index 40c12295c0bde4648d319f3da48205ab131fc92a..c27b6140bfd10e3912006f994da2bb75090c6b82 100644 (file)
@@ -309,6 +309,9 @@ static void gen7_enable_fbc(struct drm_crtc *crtc)
 
        dpfc_ctl |= IVB_DPFC_CTL_FENCE_EN;
 
+       if (dev_priv->fbc.false_color)
+               dpfc_ctl |= FBC_CTL_FALSE_COLOR;
+
        I915_WRITE(ILK_DPFC_CONTROL, dpfc_ctl | DPFC_CTL_EN);
 
        if (IS_IVYBRIDGE(dev)) {
@@ -342,6 +345,16 @@ bool intel_fbc_enabled(struct drm_device *dev)
        return dev_priv->display.fbc_enabled(dev);
 }
 
+void gen8_fbc_sw_flush(struct drm_device *dev, u32 value)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+
+       if (!IS_GEN8(dev))
+               return;
+
+       I915_WRITE(MSG_FBC_REND_STATE, value);
+}
+
 static void intel_fbc_work_fn(struct work_struct *__work)
 {
        struct intel_fbc_work *work =
@@ -578,6 +591,12 @@ void intel_update_fbc(struct drm_device *dev)
                        DRM_DEBUG_KMS("framebuffer not tiled or fenced, disabling compression\n");
                goto out_disable;
        }
+       if (INTEL_INFO(dev)->gen <= 4 && !IS_G4X(dev) &&
+           to_intel_plane(crtc->primary)->rotation != BIT(DRM_ROTATE_0)) {
+               if (set_no_fbc_reason(dev_priv, FBC_UNSUPPORTED_MODE))
+                       DRM_DEBUG_KMS("Rotation unsupported, disabling\n");
+               goto out_disable;
+       }
 
        /* If the kernel debugger is active, always disable compression */
        if (in_dbg_master())
@@ -853,7 +872,7 @@ void intel_set_memory_cxsr(struct drm_i915_private *dev_priv, bool enable)
  * A value of 5us seems to be a good balance; safe for very low end
  * platforms but not overly aggressive on lower latency configs.
  */
-static const int latency_ns = 5000;
+static const int pessimal_latency_ns = 5000;
 
 static int i9xx_get_fifo_size(struct drm_device *dev, int plane)
 {
@@ -982,13 +1001,20 @@ static const struct intel_watermark_params i915_wm_info = {
        .guard_size = 2,
        .cacheline_size = I915_FIFO_LINE_SIZE,
 };
-static const struct intel_watermark_params i830_wm_info = {
+static const struct intel_watermark_params i830_a_wm_info = {
        .fifo_size = I855GM_FIFO_SIZE,
        .max_wm = I915_MAX_WM,
        .default_wm = 1,
        .guard_size = 2,
        .cacheline_size = I830_FIFO_LINE_SIZE,
 };
+static const struct intel_watermark_params i830_bc_wm_info = {
+       .fifo_size = I855GM_FIFO_SIZE,
+       .max_wm = I915_MAX_WM/2,
+       .default_wm = 1,
+       .guard_size = 2,
+       .cacheline_size = I830_FIFO_LINE_SIZE,
+};
 static const struct intel_watermark_params i845_wm_info = {
        .fifo_size = I830_FIFO_SIZE,
        .max_wm = I915_MAX_WM,
@@ -1044,6 +1070,17 @@ static unsigned long intel_calculate_wm(unsigned long clock_in_khz,
                wm_size = wm->max_wm;
        if (wm_size <= 0)
                wm_size = wm->default_wm;
+
+       /*
+        * Bspec seems to indicate that the value shouldn't be lower than
+        * 'burst size + 1'. Certainly 830 is quite unhappy with low values.
+        * Lets go for 8 which is the burst size since certain platforms
+        * already use a hardcoded 8 (which is what the spec says should be
+        * done).
+        */
+       if (wm_size <= 8)
+               wm_size = 8;
+
        return wm_size;
 }
 
@@ -1268,33 +1305,27 @@ static bool g4x_compute_srwm(struct drm_device *dev,
                              display, cursor);
 }
 
-static bool vlv_compute_drain_latency(struct drm_device *dev,
-                                    int plane,
-                                    int *plane_prec_mult,
-                                    int *plane_dl,
-                                    int *cursor_prec_mult,
-                                    int *cursor_dl)
+static bool vlv_compute_drain_latency(struct drm_crtc *crtc,
+                                     int pixel_size,
+                                     int *prec_mult,
+                                     int *drain_latency)
 {
-       struct drm_crtc *crtc;
-       int clock, pixel_size;
        int entries;
+       int clock = to_intel_crtc(crtc)->config.adjusted_mode.crtc_clock;
 
-       crtc = intel_get_crtc_for_plane(dev, plane);
-       if (!intel_crtc_active(crtc))
+       if (WARN(clock == 0, "Pixel clock is zero!\n"))
                return false;
 
-       clock = to_intel_crtc(crtc)->config.adjusted_mode.crtc_clock;
-       pixel_size = crtc->primary->fb->bits_per_pixel / 8;     /* BPP */
+       if (WARN(pixel_size == 0, "Pixel size is zero!\n"))
+               return false;
 
-       entries = (clock / 1000) * pixel_size;
-       *plane_prec_mult = (entries > 128) ?
-               DRAIN_LATENCY_PRECISION_64 : DRAIN_LATENCY_PRECISION_32;
-       *plane_dl = (64 * (*plane_prec_mult) * 4) / entries;
+       entries = DIV_ROUND_UP(clock, 1000) * pixel_size;
+       *prec_mult = (entries > 128) ? DRAIN_LATENCY_PRECISION_64 :
+                                      DRAIN_LATENCY_PRECISION_32;
+       *drain_latency = (64 * (*prec_mult) * 4) / entries;
 
-       entries = (clock / 1000) * 4;   /* BPP is always 4 for cursor */
-       *cursor_prec_mult = (entries > 128) ?
-               DRAIN_LATENCY_PRECISION_64 : DRAIN_LATENCY_PRECISION_32;
-       *cursor_dl = (64 * (*cursor_prec_mult) * 4) / entries;
+       if (*drain_latency > DRAIN_LATENCY_MASK)
+               *drain_latency = DRAIN_LATENCY_MASK;
 
        return true;
 }
@@ -1307,39 +1338,48 @@ static bool vlv_compute_drain_latency(struct drm_device *dev,
  * latency value.
  */
 
-static void vlv_update_drain_latency(struct drm_device *dev)
+static void vlv_update_drain_latency(struct drm_crtc *crtc)
 {
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       int planea_prec, planea_dl, planeb_prec, planeb_dl;
-       int cursora_prec, cursora_dl, cursorb_prec, cursorb_dl;
-       int plane_prec_mult, cursor_prec_mult; /* Precision multiplier is
-                                                       either 16 or 32 */
+       struct drm_i915_private *dev_priv = crtc->dev->dev_private;
+       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+       int pixel_size;
+       int drain_latency;
+       enum pipe pipe = intel_crtc->pipe;
+       int plane_prec, prec_mult, plane_dl;
+
+       plane_dl = I915_READ(VLV_DDL(pipe)) & ~(DDL_PLANE_PRECISION_64 |
+                  DRAIN_LATENCY_MASK | DDL_CURSOR_PRECISION_64 |
+                  (DRAIN_LATENCY_MASK << DDL_CURSOR_SHIFT));
 
-       /* For plane A, Cursor A */
-       if (vlv_compute_drain_latency(dev, 0, &plane_prec_mult, &planea_dl,
-                                     &cursor_prec_mult, &cursora_dl)) {
-               cursora_prec = (cursor_prec_mult == DRAIN_LATENCY_PRECISION_32) ?
-                       DDL_CURSORA_PRECISION_32 : DDL_CURSORA_PRECISION_64;
-               planea_prec = (plane_prec_mult == DRAIN_LATENCY_PRECISION_32) ?
-                       DDL_PLANEA_PRECISION_32 : DDL_PLANEA_PRECISION_64;
+       if (!intel_crtc_active(crtc)) {
+               I915_WRITE(VLV_DDL(pipe), plane_dl);
+               return;
+       }
 
-               I915_WRITE(VLV_DDL1, cursora_prec |
-                               (cursora_dl << DDL_CURSORA_SHIFT) |
-                               planea_prec | planea_dl);
+       /* Primary plane Drain Latency */
+       pixel_size = crtc->primary->fb->bits_per_pixel / 8;     /* BPP */
+       if (vlv_compute_drain_latency(crtc, pixel_size, &prec_mult, &drain_latency)) {
+               plane_prec = (prec_mult == DRAIN_LATENCY_PRECISION_64) ?
+                                          DDL_PLANE_PRECISION_64 :
+                                          DDL_PLANE_PRECISION_32;
+               plane_dl |= plane_prec | drain_latency;
        }
 
-       /* For plane B, Cursor B */
-       if (vlv_compute_drain_latency(dev, 1, &plane_prec_mult, &planeb_dl,
-                                     &cursor_prec_mult, &cursorb_dl)) {
-               cursorb_prec = (cursor_prec_mult == DRAIN_LATENCY_PRECISION_32) ?
-                       DDL_CURSORB_PRECISION_32 : DDL_CURSORB_PRECISION_64;
-               planeb_prec = (plane_prec_mult == DRAIN_LATENCY_PRECISION_32) ?
-                       DDL_PLANEB_PRECISION_32 : DDL_PLANEB_PRECISION_64;
+       /* Cursor Drain Latency
+        * BPP is always 4 for cursor
+        */
+       pixel_size = 4;
 
-               I915_WRITE(VLV_DDL2, cursorb_prec |
-                               (cursorb_dl << DDL_CURSORB_SHIFT) |
-                               planeb_prec | planeb_dl);
+       /* Program cursor DL only if it is enabled */
+       if (intel_crtc->cursor_base &&
+           vlv_compute_drain_latency(crtc, pixel_size, &prec_mult, &drain_latency)) {
+               plane_prec = (prec_mult == DRAIN_LATENCY_PRECISION_64) ?
+                                          DDL_CURSOR_PRECISION_64 :
+                                          DDL_CURSOR_PRECISION_32;
+               plane_dl |= plane_prec | (drain_latency << DDL_CURSOR_SHIFT);
        }
+
+       I915_WRITE(VLV_DDL(pipe), plane_dl);
 }
 
 #define single_plane_enabled(mask) is_power_of_2(mask)
@@ -1355,20 +1395,92 @@ static void valleyview_update_wm(struct drm_crtc *crtc)
        unsigned int enabled = 0;
        bool cxsr_enabled;
 
-       vlv_update_drain_latency(dev);
+       vlv_update_drain_latency(crtc);
+
+       if (g4x_compute_wm0(dev, PIPE_A,
+                           &valleyview_wm_info, pessimal_latency_ns,
+                           &valleyview_cursor_wm_info, pessimal_latency_ns,
+                           &planea_wm, &cursora_wm))
+               enabled |= 1 << PIPE_A;
+
+       if (g4x_compute_wm0(dev, PIPE_B,
+                           &valleyview_wm_info, pessimal_latency_ns,
+                           &valleyview_cursor_wm_info, pessimal_latency_ns,
+                           &planeb_wm, &cursorb_wm))
+               enabled |= 1 << PIPE_B;
+
+       if (single_plane_enabled(enabled) &&
+           g4x_compute_srwm(dev, ffs(enabled) - 1,
+                            sr_latency_ns,
+                            &valleyview_wm_info,
+                            &valleyview_cursor_wm_info,
+                            &plane_sr, &ignore_cursor_sr) &&
+           g4x_compute_srwm(dev, ffs(enabled) - 1,
+                            2*sr_latency_ns,
+                            &valleyview_wm_info,
+                            &valleyview_cursor_wm_info,
+                            &ignore_plane_sr, &cursor_sr)) {
+               cxsr_enabled = true;
+       } else {
+               cxsr_enabled = false;
+               intel_set_memory_cxsr(dev_priv, false);
+               plane_sr = cursor_sr = 0;
+       }
+
+       DRM_DEBUG_KMS("Setting FIFO watermarks - A: plane=%d, cursor=%d, "
+                     "B: plane=%d, cursor=%d, SR: plane=%d, cursor=%d\n",
+                     planea_wm, cursora_wm,
+                     planeb_wm, cursorb_wm,
+                     plane_sr, cursor_sr);
+
+       I915_WRITE(DSPFW1,
+                  (plane_sr << DSPFW_SR_SHIFT) |
+                  (cursorb_wm << DSPFW_CURSORB_SHIFT) |
+                  (planeb_wm << DSPFW_PLANEB_SHIFT) |
+                  (planea_wm << DSPFW_PLANEA_SHIFT));
+       I915_WRITE(DSPFW2,
+                  (I915_READ(DSPFW2) & ~DSPFW_CURSORA_MASK) |
+                  (cursora_wm << DSPFW_CURSORA_SHIFT));
+       I915_WRITE(DSPFW3,
+                  (I915_READ(DSPFW3) & ~DSPFW_CURSOR_SR_MASK) |
+                  (cursor_sr << DSPFW_CURSOR_SR_SHIFT));
+
+       if (cxsr_enabled)
+               intel_set_memory_cxsr(dev_priv, true);
+}
+
+static void cherryview_update_wm(struct drm_crtc *crtc)
+{
+       struct drm_device *dev = crtc->dev;
+       static const int sr_latency_ns = 12000;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       int planea_wm, planeb_wm, planec_wm;
+       int cursora_wm, cursorb_wm, cursorc_wm;
+       int plane_sr, cursor_sr;
+       int ignore_plane_sr, ignore_cursor_sr;
+       unsigned int enabled = 0;
+       bool cxsr_enabled;
+
+       vlv_update_drain_latency(crtc);
 
        if (g4x_compute_wm0(dev, PIPE_A,
-                           &valleyview_wm_info, latency_ns,
-                           &valleyview_cursor_wm_info, latency_ns,
+                           &valleyview_wm_info, pessimal_latency_ns,
+                           &valleyview_cursor_wm_info, pessimal_latency_ns,
                            &planea_wm, &cursora_wm))
                enabled |= 1 << PIPE_A;
 
        if (g4x_compute_wm0(dev, PIPE_B,
-                           &valleyview_wm_info, latency_ns,
-                           &valleyview_cursor_wm_info, latency_ns,
+                           &valleyview_wm_info, pessimal_latency_ns,
+                           &valleyview_cursor_wm_info, pessimal_latency_ns,
                            &planeb_wm, &cursorb_wm))
                enabled |= 1 << PIPE_B;
 
+       if (g4x_compute_wm0(dev, PIPE_C,
+                           &valleyview_wm_info, pessimal_latency_ns,
+                           &valleyview_cursor_wm_info, pessimal_latency_ns,
+                           &planec_wm, &cursorc_wm))
+               enabled |= 1 << PIPE_C;
+
        if (single_plane_enabled(enabled) &&
            g4x_compute_srwm(dev, ffs(enabled) - 1,
                             sr_latency_ns,
@@ -1387,27 +1499,66 @@ static void valleyview_update_wm(struct drm_crtc *crtc)
                plane_sr = cursor_sr = 0;
        }
 
-       DRM_DEBUG_KMS("Setting FIFO watermarks - A: plane=%d, cursor=%d, B: plane=%d, cursor=%d, SR: plane=%d, cursor=%d\n",
+       DRM_DEBUG_KMS("Setting FIFO watermarks - A: plane=%d, cursor=%d, "
+                     "B: plane=%d, cursor=%d, C: plane=%d, cursor=%d, "
+                     "SR: plane=%d, cursor=%d\n",
                      planea_wm, cursora_wm,
                      planeb_wm, cursorb_wm,
+                     planec_wm, cursorc_wm,
                      plane_sr, cursor_sr);
 
        I915_WRITE(DSPFW1,
                   (plane_sr << DSPFW_SR_SHIFT) |
                   (cursorb_wm << DSPFW_CURSORB_SHIFT) |
                   (planeb_wm << DSPFW_PLANEB_SHIFT) |
-                  planea_wm);
+                  (planea_wm << DSPFW_PLANEA_SHIFT));
        I915_WRITE(DSPFW2,
                   (I915_READ(DSPFW2) & ~DSPFW_CURSORA_MASK) |
                   (cursora_wm << DSPFW_CURSORA_SHIFT));
        I915_WRITE(DSPFW3,
                   (I915_READ(DSPFW3) & ~DSPFW_CURSOR_SR_MASK) |
                   (cursor_sr << DSPFW_CURSOR_SR_SHIFT));
+       I915_WRITE(DSPFW9_CHV,
+                  (I915_READ(DSPFW9_CHV) & ~(DSPFW_PLANEC_MASK |
+                                             DSPFW_CURSORC_MASK)) |
+                  (planec_wm << DSPFW_PLANEC_SHIFT) |
+                  (cursorc_wm << DSPFW_CURSORC_SHIFT));
 
        if (cxsr_enabled)
                intel_set_memory_cxsr(dev_priv, true);
 }
 
+static void valleyview_update_sprite_wm(struct drm_plane *plane,
+                                       struct drm_crtc *crtc,
+                                       uint32_t sprite_width,
+                                       uint32_t sprite_height,
+                                       int pixel_size,
+                                       bool enabled, bool scaled)
+{
+       struct drm_device *dev = crtc->dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       int pipe = to_intel_plane(plane)->pipe;
+       int sprite = to_intel_plane(plane)->plane;
+       int drain_latency;
+       int plane_prec;
+       int sprite_dl;
+       int prec_mult;
+
+       sprite_dl = I915_READ(VLV_DDL(pipe)) & ~(DDL_SPRITE_PRECISION_64(sprite) |
+                   (DRAIN_LATENCY_MASK << DDL_SPRITE_SHIFT(sprite)));
+
+       if (enabled && vlv_compute_drain_latency(crtc, pixel_size, &prec_mult,
+                                                &drain_latency)) {
+               plane_prec = (prec_mult == DRAIN_LATENCY_PRECISION_64) ?
+                                          DDL_SPRITE_PRECISION_64(sprite) :
+                                          DDL_SPRITE_PRECISION_32(sprite);
+               sprite_dl |= plane_prec |
+                            (drain_latency << DDL_SPRITE_SHIFT(sprite));
+       }
+
+       I915_WRITE(VLV_DDL(pipe), sprite_dl);
+}
+
 static void g4x_update_wm(struct drm_crtc *crtc)
 {
        struct drm_device *dev = crtc->dev;
@@ -1419,14 +1570,14 @@ static void g4x_update_wm(struct drm_crtc *crtc)
        bool cxsr_enabled;
 
        if (g4x_compute_wm0(dev, PIPE_A,
-                           &g4x_wm_info, latency_ns,
-                           &g4x_cursor_wm_info, latency_ns,
+                           &g4x_wm_info, pessimal_latency_ns,
+                           &g4x_cursor_wm_info, pessimal_latency_ns,
                            &planea_wm, &cursora_wm))
                enabled |= 1 << PIPE_A;
 
        if (g4x_compute_wm0(dev, PIPE_B,
-                           &g4x_wm_info, latency_ns,
-                           &g4x_cursor_wm_info, latency_ns,
+                           &g4x_wm_info, pessimal_latency_ns,
+                           &g4x_cursor_wm_info, pessimal_latency_ns,
                            &planeb_wm, &cursorb_wm))
                enabled |= 1 << PIPE_B;
 
@@ -1443,7 +1594,8 @@ static void g4x_update_wm(struct drm_crtc *crtc)
                plane_sr = cursor_sr = 0;
        }
 
-       DRM_DEBUG_KMS("Setting FIFO watermarks - A: plane=%d, cursor=%d, B: plane=%d, cursor=%d, SR: plane=%d, cursor=%d\n",
+       DRM_DEBUG_KMS("Setting FIFO watermarks - A: plane=%d, cursor=%d, "
+                     "B: plane=%d, cursor=%d, SR: plane=%d, cursor=%d\n",
                      planea_wm, cursora_wm,
                      planeb_wm, cursorb_wm,
                      plane_sr, cursor_sr);
@@ -1452,7 +1604,7 @@ static void g4x_update_wm(struct drm_crtc *crtc)
                   (plane_sr << DSPFW_SR_SHIFT) |
                   (cursorb_wm << DSPFW_CURSORB_SHIFT) |
                   (planeb_wm << DSPFW_PLANEB_SHIFT) |
-                  planea_wm);
+                  (planea_wm << DSPFW_PLANEA_SHIFT));
        I915_WRITE(DSPFW2,
                   (I915_READ(DSPFW2) & ~DSPFW_CURSORA_MASK) |
                   (cursora_wm << DSPFW_CURSORA_SHIFT));
@@ -1526,8 +1678,11 @@ static void i965_update_wm(struct drm_crtc *unused_crtc)
 
        /* 965 has limitations... */
        I915_WRITE(DSPFW1, (srwm << DSPFW_SR_SHIFT) |
-                  (8 << 16) | (8 << 8) | (8 << 0));
-       I915_WRITE(DSPFW2, (8 << 8) | (8 << 0));
+                  (8 << DSPFW_CURSORB_SHIFT) |
+                  (8 << DSPFW_PLANEB_SHIFT) |
+                  (8 << DSPFW_PLANEA_SHIFT));
+       I915_WRITE(DSPFW2, (8 << DSPFW_CURSORA_SHIFT) |
+                  (8 << DSPFW_PLANEC_SHIFT_OLD));
        /* update cursor SR watermark */
        I915_WRITE(DSPFW3, (cursor_sr << DSPFW_CURSOR_SR_SHIFT));
 
@@ -1552,7 +1707,7 @@ static void i9xx_update_wm(struct drm_crtc *unused_crtc)
        else if (!IS_GEN2(dev))
                wm_info = &i915_wm_info;
        else
-               wm_info = &i830_wm_info;
+               wm_info = &i830_a_wm_info;
 
        fifo_size = dev_priv->display.get_fifo_size(dev, 0);
        crtc = intel_get_crtc_for_plane(dev, 0);
@@ -1565,10 +1720,16 @@ static void i9xx_update_wm(struct drm_crtc *unused_crtc)
                adjusted_mode = &to_intel_crtc(crtc)->config.adjusted_mode;
                planea_wm = intel_calculate_wm(adjusted_mode->crtc_clock,
                                               wm_info, fifo_size, cpp,
-                                              latency_ns);
+                                              pessimal_latency_ns);
                enabled = crtc;
-       } else
+       } else {
                planea_wm = fifo_size - wm_info->guard_size;
+               if (planea_wm > (long)wm_info->max_wm)
+                       planea_wm = wm_info->max_wm;
+       }
+
+       if (IS_GEN2(dev))
+               wm_info = &i830_bc_wm_info;
 
        fifo_size = dev_priv->display.get_fifo_size(dev, 1);
        crtc = intel_get_crtc_for_plane(dev, 1);
@@ -1581,13 +1742,16 @@ static void i9xx_update_wm(struct drm_crtc *unused_crtc)
                adjusted_mode = &to_intel_crtc(crtc)->config.adjusted_mode;
                planeb_wm = intel_calculate_wm(adjusted_mode->crtc_clock,
                                               wm_info, fifo_size, cpp,
-                                              latency_ns);
+                                              pessimal_latency_ns);
                if (enabled == NULL)
                        enabled = crtc;
                else
                        enabled = NULL;
-       } else
+       } else {
                planeb_wm = fifo_size - wm_info->guard_size;
+               if (planeb_wm > (long)wm_info->max_wm)
+                       planeb_wm = wm_info->max_wm;
+       }
 
        DRM_DEBUG_KMS("FIFO watermarks - A: %d, B: %d\n", planea_wm, planeb_wm);
 
@@ -1674,7 +1838,7 @@ static void i845_update_wm(struct drm_crtc *unused_crtc)
        planea_wm = intel_calculate_wm(adjusted_mode->crtc_clock,
                                       &i845_wm_info,
                                       dev_priv->display.get_fifo_size(dev, 0),
-                                      4, latency_ns);
+                                      4, pessimal_latency_ns);
        fwater_lo = I915_READ(FW_BLC) & ~0xfff;
        fwater_lo |= (3<<8) | planea_wm;
 
@@ -2527,7 +2691,7 @@ static struct intel_pipe_wm *ilk_find_best_result(struct drm_device *dev,
 #define WM_DIRTY_FBC (1 << 24)
 #define WM_DIRTY_DDB (1 << 25)
 
-static unsigned int ilk_compute_wm_dirty(struct drm_device *dev,
+static unsigned int ilk_compute_wm_dirty(struct drm_i915_private *dev_priv,
                                         const struct ilk_wm_values *old,
                                         const struct ilk_wm_values *new)
 {
@@ -2535,7 +2699,7 @@ static unsigned int ilk_compute_wm_dirty(struct drm_device *dev,
        enum pipe pipe;
        int wm_lp;
 
-       for_each_pipe(pipe) {
+       for_each_pipe(dev_priv, pipe) {
                if (old->wm_linetime[pipe] != new->wm_linetime[pipe]) {
                        dirty |= WM_DIRTY_LINETIME(pipe);
                        /* Must disable LP1+ watermarks too */
@@ -2621,7 +2785,7 @@ static void ilk_write_wm_values(struct drm_i915_private *dev_priv,
        unsigned int dirty;
        uint32_t val;
 
-       dirty = ilk_compute_wm_dirty(dev, previous, results);
+       dirty = ilk_compute_wm_dirty(dev_priv, previous, results);
        if (!dirty)
                return;
 
@@ -3327,13 +3491,18 @@ void valleyview_set_rps(struct drm_device *dev, u8 val)
        WARN_ON(val > dev_priv->rps.max_freq_softlimit);
        WARN_ON(val < dev_priv->rps.min_freq_softlimit);
 
-       DRM_DEBUG_DRIVER("GPU freq request from %d MHz (%u) to %d MHz (%u)\n",
-                        vlv_gpu_freq(dev_priv, dev_priv->rps.cur_freq),
-                        dev_priv->rps.cur_freq,
-                        vlv_gpu_freq(dev_priv, val), val);
+       if (WARN_ONCE(IS_CHERRYVIEW(dev) && (val & 1),
+                     "Odd GPU freq value\n"))
+               val &= ~1;
+
+       if (val != dev_priv->rps.cur_freq) {
+               DRM_DEBUG_DRIVER("GPU freq request from %d MHz (%u) to %d MHz (%u)\n",
+                                vlv_gpu_freq(dev_priv, dev_priv->rps.cur_freq),
+                                dev_priv->rps.cur_freq,
+                                vlv_gpu_freq(dev_priv, val), val);
 
-       if (val != dev_priv->rps.cur_freq)
                vlv_punit_write(dev_priv, PUNIT_REG_GPU_FREQ_REQ, val);
+       }
 
        I915_WRITE(GEN6_PMINTRMSK, gen6_rps_pm_mask(dev_priv, val));
 
@@ -3406,8 +3575,14 @@ static void valleyview_disable_rps(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
 
+       /* we're doing forcewake before Disabling RC6,
+        * This what the BIOS expects when going into suspend */
+       gen6_gt_force_wake_get(dev_priv, FORCEWAKE_ALL);
+
        I915_WRITE(GEN6_RC_CONTROL, 0);
 
+       gen6_gt_force_wake_put(dev_priv, FORCEWAKE_ALL);
+
        gen6_disable_rps_interrupts(dev);
 }
 
@@ -3598,7 +3773,6 @@ static void gen6_enable_rps(struct drm_device *dev)
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct intel_engine_cs *ring;
        u32 rp_state_cap;
-       u32 gt_perf_status;
        u32 rc6vids, pcu_mbox = 0, rc6_mask = 0;
        u32 gtfifodbg;
        int rc6_mode;
@@ -3623,7 +3797,6 @@ static void gen6_enable_rps(struct drm_device *dev)
        gen6_gt_force_wake_get(dev_priv, FORCEWAKE_ALL);
 
        rp_state_cap = I915_READ(GEN6_RP_STATE_CAP);
-       gt_perf_status = I915_READ(GEN6_GT_PERF_STATUS);
 
        parse_rp_state_cap(dev_priv, rp_state_cap);
 
@@ -3965,11 +4138,27 @@ static void valleyview_cleanup_pctx(struct drm_device *dev)
 static void valleyview_init_gt_powersave(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
+       u32 val;
 
        valleyview_setup_pctx(dev);
 
        mutex_lock(&dev_priv->rps.hw_lock);
 
+       val = vlv_punit_read(dev_priv, PUNIT_REG_GPU_FREQ_STS);
+       switch ((val >> 6) & 3) {
+       case 0:
+       case 1:
+               dev_priv->mem_freq = 800;
+               break;
+       case 2:
+               dev_priv->mem_freq = 1066;
+               break;
+       case 3:
+               dev_priv->mem_freq = 1333;
+               break;
+       }
+       DRM_DEBUG_DRIVER("DDR speed: %d MHz", dev_priv->mem_freq);
+
        dev_priv->rps.max_freq = valleyview_rps_max_freq(dev_priv);
        dev_priv->rps.rp0_freq = dev_priv->rps.max_freq;
        DRM_DEBUG_DRIVER("max GPU freq: %d MHz (%u)\n",
@@ -4004,11 +4193,38 @@ static void valleyview_init_gt_powersave(struct drm_device *dev)
 static void cherryview_init_gt_powersave(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
+       u32 val;
 
        cherryview_setup_pctx(dev);
 
        mutex_lock(&dev_priv->rps.hw_lock);
 
+       val = vlv_punit_read(dev_priv, CCK_FUSE_REG);
+       switch ((val >> 2) & 0x7) {
+       case 0:
+       case 1:
+               dev_priv->rps.cz_freq = 200;
+               dev_priv->mem_freq = 1600;
+               break;
+       case 2:
+               dev_priv->rps.cz_freq = 267;
+               dev_priv->mem_freq = 1600;
+               break;
+       case 3:
+               dev_priv->rps.cz_freq = 333;
+               dev_priv->mem_freq = 2000;
+               break;
+       case 4:
+               dev_priv->rps.cz_freq = 320;
+               dev_priv->mem_freq = 1600;
+               break;
+       case 5:
+               dev_priv->rps.cz_freq = 400;
+               dev_priv->mem_freq = 1600;
+               break;
+       }
+       DRM_DEBUG_DRIVER("DDR speed: %d MHz", dev_priv->mem_freq);
+
        dev_priv->rps.max_freq = cherryview_rps_max_freq(dev_priv);
        dev_priv->rps.rp0_freq = dev_priv->rps.max_freq;
        DRM_DEBUG_DRIVER("max GPU freq: %d MHz (%u)\n",
@@ -4030,6 +4246,12 @@ static void cherryview_init_gt_powersave(struct drm_device *dev)
                         vlv_gpu_freq(dev_priv, dev_priv->rps.min_freq),
                         dev_priv->rps.min_freq);
 
+       WARN_ONCE((dev_priv->rps.max_freq |
+                  dev_priv->rps.efficient_freq |
+                  dev_priv->rps.rp1_freq |
+                  dev_priv->rps.min_freq) & 1,
+                 "Odd GPU freq values\n");
+
        /* Preserve min/max settings in case of re-init */
        if (dev_priv->rps.max_freq_softlimit == 0)
                dev_priv->rps.max_freq_softlimit = dev_priv->rps.max_freq;
@@ -5088,7 +5310,7 @@ static void g4x_disable_trickle_feed(struct drm_device *dev)
        struct drm_i915_private *dev_priv = dev->dev_private;
        int pipe;
 
-       for_each_pipe(pipe) {
+       for_each_pipe(dev_priv, pipe) {
                I915_WRITE(DSPCNTR(pipe),
                           I915_READ(DSPCNTR(pipe)) |
                           DISPPLANE_TRICKLE_FEED_DISABLE);
@@ -5203,7 +5425,7 @@ static void cpt_init_clock_gating(struct drm_device *dev)
        /* The below fixes the weird display corruption, a few pixels shifted
         * downward, on (only) LVDS of some HP laptops with IVY.
         */
-       for_each_pipe(pipe) {
+       for_each_pipe(dev_priv, pipe) {
                val = I915_READ(TRANS_CHICKEN2(pipe));
                val |= TRANS_CHICKEN2_TIMING_OVERRIDE;
                val &= ~TRANS_CHICKEN2_FDI_POLARITY_REVERSED;
@@ -5215,7 +5437,7 @@ static void cpt_init_clock_gating(struct drm_device *dev)
                I915_WRITE(TRANS_CHICKEN2(pipe), val);
        }
        /* WADP0ClockGatingDisable */
-       for_each_pipe(pipe) {
+       for_each_pipe(dev_priv, pipe) {
                I915_WRITE(TRANS_CHICKEN1(pipe),
                           TRANS_CHICKEN1_DP0UNIT_GC_DISABLE);
        }
@@ -5383,7 +5605,7 @@ static void lpt_suspend_hw(struct drm_device *dev)
        }
 }
 
-static void gen8_init_clock_gating(struct drm_device *dev)
+static void broadwell_init_clock_gating(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
        enum pipe pipe;
@@ -5395,37 +5617,12 @@ static void gen8_init_clock_gating(struct drm_device *dev)
        /* FIXME(BDW): Check all the w/a, some might only apply to
         * pre-production hw. */
 
-       /* WaDisablePartialInstShootdown:bdw */
-       I915_WRITE(GEN8_ROW_CHICKEN,
-                  _MASKED_BIT_ENABLE(PARTIAL_INSTRUCTION_SHOOTDOWN_DISABLE));
 
-       /* WaDisableThreadStallDopClockGating:bdw */
-       /* FIXME: Unclear whether we really need this on production bdw. */
-       I915_WRITE(GEN8_ROW_CHICKEN,
-                  _MASKED_BIT_ENABLE(STALL_DOP_GATING_DISABLE));
-
-       /*
-        * This GEN8_CENTROID_PIXEL_OPT_DIS W/A is only needed for
-        * pre-production hardware
-        */
-       I915_WRITE(HALF_SLICE_CHICKEN3,
-                  _MASKED_BIT_ENABLE(GEN8_CENTROID_PIXEL_OPT_DIS));
-       I915_WRITE(HALF_SLICE_CHICKEN3,
-                  _MASKED_BIT_ENABLE(GEN8_SAMPLER_POWER_BYPASS_DIS));
        I915_WRITE(GAMTARBMODE, _MASKED_BIT_ENABLE(ARB_MODE_BWGTLB_DISABLE));
 
        I915_WRITE(_3D_CHICKEN3,
                   _MASKED_BIT_ENABLE(_3D_CHICKEN_SDE_LIMIT_FIFO_POLY_DEPTH(2)));
 
-       I915_WRITE(COMMON_SLICE_CHICKEN2,
-                  _MASKED_BIT_ENABLE(GEN8_CSC2_SBE_VUE_CACHE_CONSERVATIVE));
-
-       I915_WRITE(GEN7_HALF_SLICE_CHICKEN1,
-                  _MASKED_BIT_ENABLE(GEN7_SINGLE_SUBSCAN_DISPATCH_ENABLE));
-
-       /* WaDisableDopClockGating:bdw May not be needed for production */
-       I915_WRITE(GEN7_ROW_CHICKEN2,
-                  _MASKED_BIT_ENABLE(DOP_CLOCK_GATING_DISABLE));
 
        /* WaSwitchSolVfFArbitrationPriority:bdw */
        I915_WRITE(GAM_ECOCHK, I915_READ(GAM_ECOCHK) | HSW_ECOCHK_ARB_PRIO_SOL);
@@ -5435,37 +5632,18 @@ static void gen8_init_clock_gating(struct drm_device *dev)
                   I915_READ(CHICKEN_PAR1_1) | DPA_MASK_VBLANK_SRD);
 
        /* WaPsrDPRSUnmaskVBlankInSRD:bdw */
-       for_each_pipe(pipe) {
+       for_each_pipe(dev_priv, pipe) {
                I915_WRITE(CHICKEN_PIPESL_1(pipe),
                           I915_READ(CHICKEN_PIPESL_1(pipe)) |
                           BDW_DPRS_MASK_VBLANK_SRD);
        }
 
-       /* Use Force Non-Coherent whenever executing a 3D context. This is a
-        * workaround for for a possible hang in the unlikely event a TLB
-        * invalidation occurs during a PSD flush.
-        */
-       I915_WRITE(HDC_CHICKEN0,
-                  I915_READ(HDC_CHICKEN0) |
-                  _MASKED_BIT_ENABLE(HDC_FORCE_NON_COHERENT));
-
        /* WaVSRefCountFullforceMissDisable:bdw */
        /* WaDSRefCountFullforceMissDisable:bdw */
        I915_WRITE(GEN7_FF_THREAD_MODE,
                   I915_READ(GEN7_FF_THREAD_MODE) &
                   ~(GEN8_FF_DS_REF_CNT_FFME | GEN7_FF_VS_REF_CNT_FFME));
 
-       /*
-        * BSpec recommends 8x4 when MSAA is used,
-        * however in practice 16x4 seems fastest.
-        *
-        * Note that PS/WM thread counts depend on the WIZ hashing
-        * disable bit, which we don't touch here, but it's good
-        * to keep in mind (see 3DSTATE_PS and 3DSTATE_WM).
-        */
-       I915_WRITE(GEN7_GT_MODE,
-                  GEN6_WIZ_HASHING_MASK | GEN6_WIZ_HASHING_16x4);
-
        I915_WRITE(GEN6_RC_SLEEP_PSMI_CONTROL,
                   _MASKED_BIT_ENABLE(GEN8_RC_SEMA_IDLE_MSG_DISABLE));
 
@@ -5473,9 +5651,7 @@ static void gen8_init_clock_gating(struct drm_device *dev)
        I915_WRITE(GEN8_UCGCTL6, I915_READ(GEN8_UCGCTL6) |
                   GEN8_SDEUNIT_CLOCK_GATE_DISABLE);
 
-       /* Wa4x4STCOptimizationDisable:bdw */
-       I915_WRITE(CACHE_MODE_1,
-                  _MASKED_BIT_ENABLE(GEN8_4x4_STC_OPTIMIZATION_DISABLE));
+       lpt_init_clock_gating(dev);
 }
 
 static void haswell_init_clock_gating(struct drm_device *dev)
@@ -5631,24 +5807,6 @@ static void ivybridge_init_clock_gating(struct drm_device *dev)
 static void valleyview_init_clock_gating(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
-       u32 val;
-
-       mutex_lock(&dev_priv->rps.hw_lock);
-       val = vlv_punit_read(dev_priv, PUNIT_REG_GPU_FREQ_STS);
-       mutex_unlock(&dev_priv->rps.hw_lock);
-       switch ((val >> 6) & 3) {
-       case 0:
-       case 1:
-               dev_priv->mem_freq = 800;
-               break;
-       case 2:
-               dev_priv->mem_freq = 1066;
-               break;
-       case 3:
-               dev_priv->mem_freq = 1333;
-               break;
-       }
-       DRM_DEBUG_DRIVER("DDR speed: %d MHz", dev_priv->mem_freq);
 
        I915_WRITE(DSPCLK_GATE_D, VRHUNIT_CLOCK_GATE_DISABLE);
 
@@ -5724,48 +5882,11 @@ static void valleyview_init_clock_gating(struct drm_device *dev)
 static void cherryview_init_clock_gating(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
-       u32 val;
-
-       mutex_lock(&dev_priv->rps.hw_lock);
-       val = vlv_punit_read(dev_priv, CCK_FUSE_REG);
-       mutex_unlock(&dev_priv->rps.hw_lock);
-       switch ((val >> 2) & 0x7) {
-       case 0:
-       case 1:
-                       dev_priv->rps.cz_freq = CHV_CZ_CLOCK_FREQ_MODE_200;
-                       dev_priv->mem_freq = 1600;
-                       break;
-       case 2:
-                       dev_priv->rps.cz_freq = CHV_CZ_CLOCK_FREQ_MODE_267;
-                       dev_priv->mem_freq = 1600;
-                       break;
-       case 3:
-                       dev_priv->rps.cz_freq = CHV_CZ_CLOCK_FREQ_MODE_333;
-                       dev_priv->mem_freq = 2000;
-                       break;
-       case 4:
-                       dev_priv->rps.cz_freq = CHV_CZ_CLOCK_FREQ_MODE_320;
-                       dev_priv->mem_freq = 1600;
-                       break;
-       case 5:
-                       dev_priv->rps.cz_freq = CHV_CZ_CLOCK_FREQ_MODE_400;
-                       dev_priv->mem_freq = 1600;
-                       break;
-       }
-       DRM_DEBUG_DRIVER("DDR speed: %d MHz", dev_priv->mem_freq);
 
        I915_WRITE(DSPCLK_GATE_D, VRHUNIT_CLOCK_GATE_DISABLE);
 
        I915_WRITE(MI_ARB_VLV, MI_ARB_DISPLAY_TRICKLE_FEED_DISABLE);
 
-       /* WaDisablePartialInstShootdown:chv */
-       I915_WRITE(GEN8_ROW_CHICKEN,
-                  _MASKED_BIT_ENABLE(PARTIAL_INSTRUCTION_SHOOTDOWN_DISABLE));
-
-       /* WaDisableThreadStallDopClockGating:chv */
-       I915_WRITE(GEN8_ROW_CHICKEN,
-                  _MASKED_BIT_ENABLE(STALL_DOP_GATING_DISABLE));
-
        /* WaVSRefCountFullforceMissDisable:chv */
        /* WaDSRefCountFullforceMissDisable:chv */
        I915_WRITE(GEN7_FF_THREAD_MODE,
@@ -5784,10 +5905,6 @@ static void cherryview_init_clock_gating(struct drm_device *dev)
        I915_WRITE(GEN8_UCGCTL6, I915_READ(GEN8_UCGCTL6) |
                   GEN8_SDEUNIT_CLOCK_GATE_DISABLE);
 
-       /* WaDisableSamplerPowerBypass:chv (pre-production hw) */
-       I915_WRITE(HALF_SLICE_CHICKEN3,
-                  _MASKED_BIT_ENABLE(GEN8_SAMPLER_POWER_BYPASS_DIS));
-
        /* WaDisableGunitClockGating:chv (pre-production hw) */
        I915_WRITE(VLV_GUNIT_CLOCK_GATE, I915_READ(VLV_GUNIT_CLOCK_GATE) |
                   GINT_DIS);
@@ -5797,8 +5914,6 @@ static void cherryview_init_clock_gating(struct drm_device *dev)
                   _MASKED_BIT_ENABLE(GEN8_FF_DOP_CLOCK_GATE_DISABLE));
 
        /* WaDisableDopClockGating:chv (pre-production hw) */
-       I915_WRITE(GEN7_ROW_CHICKEN2,
-                  _MASKED_BIT_ENABLE(DOP_CLOCK_GATING_DISABLE));
        I915_WRITE(GEN6_UCGCTL1, I915_READ(GEN6_UCGCTL1) |
                   GEN6_EU_TCUNIT_CLOCK_GATE_DISABLE);
 }
@@ -5883,6 +5998,9 @@ static void gen3_init_clock_gating(struct drm_device *dev)
 
        /* On GEN3 we really need to make sure the ARB C3 LP bit is set */
        I915_WRITE(MI_ARB_STATE, _MASKED_BIT_ENABLE(MI_ARB_C3_LP_WRITE_ENABLE));
+
+       I915_WRITE(MI_ARB_STATE,
+                  _MASKED_BIT_ENABLE(MI_ARB_DISPLAY_TRICKLE_FEED_DISABLE));
 }
 
 static void i85x_init_clock_gating(struct drm_device *dev)
@@ -5894,6 +6012,9 @@ static void i85x_init_clock_gating(struct drm_device *dev)
        /* interrupts should cause a wake up from C3 */
        I915_WRITE(MI_STATE, _MASKED_BIT_ENABLE(MI_AGPBUSY_INT_EN) |
                   _MASKED_BIT_DISABLE(MI_AGPBUSY_830_MODE));
+
+       I915_WRITE(MEM_MODE,
+                  _MASKED_BIT_ENABLE(MEM_DISPLAY_TRICKLE_FEED_DISABLE));
 }
 
 static void i830_init_clock_gating(struct drm_device *dev)
@@ -5901,6 +6022,10 @@ static void i830_init_clock_gating(struct drm_device *dev)
        struct drm_i915_private *dev_priv = dev->dev_private;
 
        I915_WRITE(DSPCLK_GATE_D, OVRUNIT_CLOCK_GATE_DISABLE);
+
+       I915_WRITE(MEM_MODE,
+                  _MASKED_BIT_ENABLE(MEM_DISPLAY_A_TRICKLE_FEED_DISABLE) |
+                  _MASKED_BIT_ENABLE(MEM_DISPLAY_B_TRICKLE_FEED_DISABLE));
 }
 
 void intel_init_clock_gating(struct drm_device *dev)
@@ -6203,6 +6328,8 @@ static void vlv_display_power_well_disable(struct drm_i915_private *dev_priv,
        spin_unlock_irq(&dev_priv->irq_lock);
 
        vlv_set_power_well(dev_priv, power_well, false);
+
+       vlv_power_sequencer_reset(dev_priv);
 }
 
 static void vlv_dpio_cmn_power_well_enable(struct drm_i915_private *dev_priv,
@@ -6238,12 +6365,11 @@ static void vlv_dpio_cmn_power_well_enable(struct drm_i915_private *dev_priv,
 static void vlv_dpio_cmn_power_well_disable(struct drm_i915_private *dev_priv,
                                            struct i915_power_well *power_well)
 {
-       struct drm_device *dev = dev_priv->dev;
        enum pipe pipe;
 
        WARN_ON_ONCE(power_well->data != PUNIT_POWER_WELL_DPIO_CMN_BC);
 
-       for_each_pipe(pipe)
+       for_each_pipe(dev_priv, pipe)
                assert_pll_disabled(dev_priv, pipe);
 
        /* Assert common reset */
@@ -6252,6 +6378,153 @@ static void vlv_dpio_cmn_power_well_disable(struct drm_i915_private *dev_priv,
        vlv_set_power_well(dev_priv, power_well, false);
 }
 
+static void chv_dpio_cmn_power_well_enable(struct drm_i915_private *dev_priv,
+                                          struct i915_power_well *power_well)
+{
+       enum dpio_phy phy;
+
+       WARN_ON_ONCE(power_well->data != PUNIT_POWER_WELL_DPIO_CMN_BC &&
+                    power_well->data != PUNIT_POWER_WELL_DPIO_CMN_D);
+
+       /*
+        * Enable the CRI clock source so we can get at the
+        * display and the reference clock for VGA
+        * hotplug / manual detection.
+        */
+       if (power_well->data == PUNIT_POWER_WELL_DPIO_CMN_BC) {
+               phy = DPIO_PHY0;
+               I915_WRITE(DPLL(PIPE_B), I915_READ(DPLL(PIPE_B)) |
+                          DPLL_REFA_CLK_ENABLE_VLV);
+               I915_WRITE(DPLL(PIPE_B), I915_READ(DPLL(PIPE_B)) |
+                          DPLL_REFA_CLK_ENABLE_VLV | DPLL_INTEGRATED_CRI_CLK_VLV);
+       } else {
+               phy = DPIO_PHY1;
+               I915_WRITE(DPLL(PIPE_C), I915_READ(DPLL(PIPE_C)) |
+                          DPLL_REFA_CLK_ENABLE_VLV | DPLL_INTEGRATED_CRI_CLK_VLV);
+       }
+       udelay(1); /* >10ns for cmnreset, >0ns for sidereset */
+       vlv_set_power_well(dev_priv, power_well, true);
+
+       /* Poll for phypwrgood signal */
+       if (wait_for(I915_READ(DISPLAY_PHY_STATUS) & PHY_POWERGOOD(phy), 1))
+               DRM_ERROR("Display PHY %d is not power up\n", phy);
+
+       I915_WRITE(DISPLAY_PHY_CONTROL, I915_READ(DISPLAY_PHY_CONTROL) |
+                  PHY_COM_LANE_RESET_DEASSERT(phy));
+}
+
+static void chv_dpio_cmn_power_well_disable(struct drm_i915_private *dev_priv,
+                                           struct i915_power_well *power_well)
+{
+       enum dpio_phy phy;
+
+       WARN_ON_ONCE(power_well->data != PUNIT_POWER_WELL_DPIO_CMN_BC &&
+                    power_well->data != PUNIT_POWER_WELL_DPIO_CMN_D);
+
+       if (power_well->data == PUNIT_POWER_WELL_DPIO_CMN_BC) {
+               phy = DPIO_PHY0;
+               assert_pll_disabled(dev_priv, PIPE_A);
+               assert_pll_disabled(dev_priv, PIPE_B);
+       } else {
+               phy = DPIO_PHY1;
+               assert_pll_disabled(dev_priv, PIPE_C);
+       }
+
+       I915_WRITE(DISPLAY_PHY_CONTROL, I915_READ(DISPLAY_PHY_CONTROL) &
+                  ~PHY_COM_LANE_RESET_DEASSERT(phy));
+
+       vlv_set_power_well(dev_priv, power_well, false);
+}
+
+static bool chv_pipe_power_well_enabled(struct drm_i915_private *dev_priv,
+                                       struct i915_power_well *power_well)
+{
+       enum pipe pipe = power_well->data;
+       bool enabled;
+       u32 state, ctrl;
+
+       mutex_lock(&dev_priv->rps.hw_lock);
+
+       state = vlv_punit_read(dev_priv, PUNIT_REG_DSPFREQ) & DP_SSS_MASK(pipe);
+       /*
+        * We only ever set the power-on and power-gate states, anything
+        * else is unexpected.
+        */
+       WARN_ON(state != DP_SSS_PWR_ON(pipe) && state != DP_SSS_PWR_GATE(pipe));
+       enabled = state == DP_SSS_PWR_ON(pipe);
+
+       /*
+        * A transient state at this point would mean some unexpected party
+        * is poking at the power controls too.
+        */
+       ctrl = vlv_punit_read(dev_priv, PUNIT_REG_DSPFREQ) & DP_SSC_MASK(pipe);
+       WARN_ON(ctrl << 16 != state);
+
+       mutex_unlock(&dev_priv->rps.hw_lock);
+
+       return enabled;
+}
+
+static void chv_set_pipe_power_well(struct drm_i915_private *dev_priv,
+                                   struct i915_power_well *power_well,
+                                   bool enable)
+{
+       enum pipe pipe = power_well->data;
+       u32 state;
+       u32 ctrl;
+
+       state = enable ? DP_SSS_PWR_ON(pipe) : DP_SSS_PWR_GATE(pipe);
+
+       mutex_lock(&dev_priv->rps.hw_lock);
+
+#define COND \
+       ((vlv_punit_read(dev_priv, PUNIT_REG_DSPFREQ) & DP_SSS_MASK(pipe)) == state)
+
+       if (COND)
+               goto out;
+
+       ctrl = vlv_punit_read(dev_priv, PUNIT_REG_DSPFREQ);
+       ctrl &= ~DP_SSC_MASK(pipe);
+       ctrl |= enable ? DP_SSC_PWR_ON(pipe) : DP_SSC_PWR_GATE(pipe);
+       vlv_punit_write(dev_priv, PUNIT_REG_DSPFREQ, ctrl);
+
+       if (wait_for(COND, 100))
+               DRM_ERROR("timout setting power well state %08x (%08x)\n",
+                         state,
+                         vlv_punit_read(dev_priv, PUNIT_REG_DSPFREQ));
+
+#undef COND
+
+out:
+       mutex_unlock(&dev_priv->rps.hw_lock);
+}
+
+static void chv_pipe_power_well_sync_hw(struct drm_i915_private *dev_priv,
+                                       struct i915_power_well *power_well)
+{
+       chv_set_pipe_power_well(dev_priv, power_well, power_well->count > 0);
+}
+
+static void chv_pipe_power_well_enable(struct drm_i915_private *dev_priv,
+                                      struct i915_power_well *power_well)
+{
+       WARN_ON_ONCE(power_well->data != PIPE_A &&
+                    power_well->data != PIPE_B &&
+                    power_well->data != PIPE_C);
+
+       chv_set_pipe_power_well(dev_priv, power_well, true);
+}
+
+static void chv_pipe_power_well_disable(struct drm_i915_private *dev_priv,
+                                       struct i915_power_well *power_well)
+{
+       WARN_ON_ONCE(power_well->data != PIPE_A &&
+                    power_well->data != PIPE_B &&
+                    power_well->data != PIPE_C);
+
+       chv_set_pipe_power_well(dev_priv, power_well, false);
+}
+
 static void check_power_well_state(struct drm_i915_private *dev_priv,
                                   struct i915_power_well *power_well)
 {
@@ -6443,6 +6716,39 @@ EXPORT_SYMBOL_GPL(i915_get_cdclk_freq);
        BIT(POWER_DOMAIN_PORT_DDI_C_4_LANES) |  \
        BIT(POWER_DOMAIN_INIT))
 
+#define CHV_PIPE_A_POWER_DOMAINS (     \
+       BIT(POWER_DOMAIN_PIPE_A) |      \
+       BIT(POWER_DOMAIN_INIT))
+
+#define CHV_PIPE_B_POWER_DOMAINS (     \
+       BIT(POWER_DOMAIN_PIPE_B) |      \
+       BIT(POWER_DOMAIN_INIT))
+
+#define CHV_PIPE_C_POWER_DOMAINS (     \
+       BIT(POWER_DOMAIN_PIPE_C) |      \
+       BIT(POWER_DOMAIN_INIT))
+
+#define CHV_DPIO_CMN_BC_POWER_DOMAINS (                \
+       BIT(POWER_DOMAIN_PORT_DDI_B_2_LANES) |  \
+       BIT(POWER_DOMAIN_PORT_DDI_B_4_LANES) |  \
+       BIT(POWER_DOMAIN_PORT_DDI_C_2_LANES) |  \
+       BIT(POWER_DOMAIN_PORT_DDI_C_4_LANES) |  \
+       BIT(POWER_DOMAIN_INIT))
+
+#define CHV_DPIO_CMN_D_POWER_DOMAINS (         \
+       BIT(POWER_DOMAIN_PORT_DDI_D_2_LANES) |  \
+       BIT(POWER_DOMAIN_PORT_DDI_D_4_LANES) |  \
+       BIT(POWER_DOMAIN_INIT))
+
+#define CHV_DPIO_TX_D_LANES_01_POWER_DOMAINS ( \
+       BIT(POWER_DOMAIN_PORT_DDI_D_2_LANES) |  \
+       BIT(POWER_DOMAIN_PORT_DDI_D_4_LANES) |  \
+       BIT(POWER_DOMAIN_INIT))
+
+#define CHV_DPIO_TX_D_LANES_23_POWER_DOMAINS ( \
+       BIT(POWER_DOMAIN_PORT_DDI_D_4_LANES) |  \
+       BIT(POWER_DOMAIN_INIT))
+
 static const struct i915_power_well_ops i9xx_always_on_power_well_ops = {
        .sync_hw = i9xx_always_on_power_well_noop,
        .enable = i9xx_always_on_power_well_noop,
@@ -6450,6 +6756,20 @@ static const struct i915_power_well_ops i9xx_always_on_power_well_ops = {
        .is_enabled = i9xx_always_on_power_well_enabled,
 };
 
+static const struct i915_power_well_ops chv_pipe_power_well_ops = {
+       .sync_hw = chv_pipe_power_well_sync_hw,
+       .enable = chv_pipe_power_well_enable,
+       .disable = chv_pipe_power_well_disable,
+       .is_enabled = chv_pipe_power_well_enabled,
+};
+
+static const struct i915_power_well_ops chv_dpio_cmn_power_well_ops = {
+       .sync_hw = vlv_power_well_sync_hw,
+       .enable = chv_dpio_cmn_power_well_enable,
+       .disable = chv_dpio_cmn_power_well_disable,
+       .is_enabled = vlv_power_well_enabled,
+};
+
 static struct i915_power_well i9xx_always_on_power_well[] = {
        {
                .name = "always-on",
@@ -6572,6 +6892,107 @@ static struct i915_power_well vlv_power_wells[] = {
        },
 };
 
+static struct i915_power_well chv_power_wells[] = {
+       {
+               .name = "always-on",
+               .always_on = 1,
+               .domains = VLV_ALWAYS_ON_POWER_DOMAINS,
+               .ops = &i9xx_always_on_power_well_ops,
+       },
+#if 0
+       {
+               .name = "display",
+               .domains = VLV_DISPLAY_POWER_DOMAINS,
+               .data = PUNIT_POWER_WELL_DISP2D,
+               .ops = &vlv_display_power_well_ops,
+       },
+       {
+               .name = "pipe-a",
+               .domains = CHV_PIPE_A_POWER_DOMAINS,
+               .data = PIPE_A,
+               .ops = &chv_pipe_power_well_ops,
+       },
+       {
+               .name = "pipe-b",
+               .domains = CHV_PIPE_B_POWER_DOMAINS,
+               .data = PIPE_B,
+               .ops = &chv_pipe_power_well_ops,
+       },
+       {
+               .name = "pipe-c",
+               .domains = CHV_PIPE_C_POWER_DOMAINS,
+               .data = PIPE_C,
+               .ops = &chv_pipe_power_well_ops,
+       },
+#endif
+       {
+               .name = "dpio-common-bc",
+               /*
+                * XXX: cmnreset for one PHY seems to disturb the other.
+                * As a workaround keep both powered on at the same
+                * time for now.
+                */
+               .domains = CHV_DPIO_CMN_BC_POWER_DOMAINS | CHV_DPIO_CMN_D_POWER_DOMAINS,
+               .data = PUNIT_POWER_WELL_DPIO_CMN_BC,
+               .ops = &chv_dpio_cmn_power_well_ops,
+       },
+       {
+               .name = "dpio-common-d",
+               /*
+                * XXX: cmnreset for one PHY seems to disturb the other.
+                * As a workaround keep both powered on at the same
+                * time for now.
+                */
+               .domains = CHV_DPIO_CMN_BC_POWER_DOMAINS | CHV_DPIO_CMN_D_POWER_DOMAINS,
+               .data = PUNIT_POWER_WELL_DPIO_CMN_D,
+               .ops = &chv_dpio_cmn_power_well_ops,
+       },
+#if 0
+       {
+               .name = "dpio-tx-b-01",
+               .domains = VLV_DPIO_TX_B_LANES_01_POWER_DOMAINS |
+                          VLV_DPIO_TX_B_LANES_23_POWER_DOMAINS,
+               .ops = &vlv_dpio_power_well_ops,
+               .data = PUNIT_POWER_WELL_DPIO_TX_B_LANES_01,
+       },
+       {
+               .name = "dpio-tx-b-23",
+               .domains = VLV_DPIO_TX_B_LANES_01_POWER_DOMAINS |
+                          VLV_DPIO_TX_B_LANES_23_POWER_DOMAINS,
+               .ops = &vlv_dpio_power_well_ops,
+               .data = PUNIT_POWER_WELL_DPIO_TX_B_LANES_23,
+       },
+       {
+               .name = "dpio-tx-c-01",
+               .domains = VLV_DPIO_TX_C_LANES_01_POWER_DOMAINS |
+                          VLV_DPIO_TX_C_LANES_23_POWER_DOMAINS,
+               .ops = &vlv_dpio_power_well_ops,
+               .data = PUNIT_POWER_WELL_DPIO_TX_C_LANES_01,
+       },
+       {
+               .name = "dpio-tx-c-23",
+               .domains = VLV_DPIO_TX_C_LANES_01_POWER_DOMAINS |
+                          VLV_DPIO_TX_C_LANES_23_POWER_DOMAINS,
+               .ops = &vlv_dpio_power_well_ops,
+               .data = PUNIT_POWER_WELL_DPIO_TX_C_LANES_23,
+       },
+       {
+               .name = "dpio-tx-d-01",
+               .domains = CHV_DPIO_TX_D_LANES_01_POWER_DOMAINS |
+                          CHV_DPIO_TX_D_LANES_23_POWER_DOMAINS,
+               .ops = &vlv_dpio_power_well_ops,
+               .data = PUNIT_POWER_WELL_DPIO_TX_D_LANES_01,
+       },
+       {
+               .name = "dpio-tx-d-23",
+               .domains = CHV_DPIO_TX_D_LANES_01_POWER_DOMAINS |
+                          CHV_DPIO_TX_D_LANES_23_POWER_DOMAINS,
+               .ops = &vlv_dpio_power_well_ops,
+               .data = PUNIT_POWER_WELL_DPIO_TX_D_LANES_23,
+       },
+#endif
+};
+
 static struct i915_power_well *lookup_power_well(struct drm_i915_private *dev_priv,
                                                 enum punit_power_well power_well_id)
 {
@@ -6608,6 +7029,8 @@ int intel_power_domains_init(struct drm_i915_private *dev_priv)
        } else if (IS_BROADWELL(dev_priv->dev)) {
                set_power_wells(power_domains, bdw_power_wells);
                hsw_pwr = power_domains;
+       } else if (IS_CHERRYVIEW(dev_priv->dev)) {
+               set_power_wells(power_domains, chv_power_wells);
        } else if (IS_VALLEYVIEW(dev_priv->dev)) {
                set_power_wells(power_domains, vlv_power_wells);
        } else {
@@ -6833,13 +7256,15 @@ void intel_init_pm(struct drm_device *dev)
                else if (IS_HASWELL(dev))
                        dev_priv->display.init_clock_gating = haswell_init_clock_gating;
                else if (INTEL_INFO(dev)->gen == 8)
-                       dev_priv->display.init_clock_gating = gen8_init_clock_gating;
+                       dev_priv->display.init_clock_gating = broadwell_init_clock_gating;
        } else if (IS_CHERRYVIEW(dev)) {
-               dev_priv->display.update_wm = valleyview_update_wm;
+               dev_priv->display.update_wm = cherryview_update_wm;
+               dev_priv->display.update_sprite_wm = valleyview_update_sprite_wm;
                dev_priv->display.init_clock_gating =
                        cherryview_init_clock_gating;
        } else if (IS_VALLEYVIEW(dev)) {
                dev_priv->display.update_wm = valleyview_update_wm;
+               dev_priv->display.update_sprite_wm = valleyview_update_sprite_wm;
                dev_priv->display.init_clock_gating =
                        valleyview_init_clock_gating;
        } else if (IS_PINEVIEW(dev)) {
@@ -7025,6 +7450,7 @@ static int chv_freq_opcode(struct drm_i915_private *dev_priv, int val)
                return -1;
        }
 
+       /* CHV needs even values */
        opcode = (DIV_ROUND_CLOSEST((val * 2 * mul), dev_priv->rps.cz_freq) * 2);
 
        return opcode;
index fd4f66231d30edec7d96236fac145e2b00b7b0c5..6c792d3a9c9caa55a6959868190223b396fd173e 100644 (file)
 #ifndef _INTEL_RENDERSTATE_H
 #define _INTEL_RENDERSTATE_H
 
-#include <linux/types.h>
-
-struct intel_renderstate_rodata {
-       const u32 *reloc;
-       const u32 *batch;
-       const u32 batch_items;
-};
+#include "i915_drv.h"
 
 extern const struct intel_renderstate_rodata gen6_null_state;
 extern const struct intel_renderstate_rodata gen7_null_state;
index 47a126a0493f811cad30474532477cfe5994734e..0a80e419b5894f1c36a1b6eb0f6078f76fe7c0f4 100644 (file)
 #include "i915_trace.h"
 #include "intel_drv.h"
 
-/* Early gen2 devices have a cacheline of just 32 bytes, using 64 is overkill,
- * but keeps the logic simple. Indeed, the whole purpose of this macro is just
- * to give some inclination as to some of the magic values used in the various
- * workarounds!
- */
-#define CACHELINE_BYTES 64
+bool
+intel_ring_initialized(struct intel_engine_cs *ring)
+{
+       struct drm_device *dev = ring->dev;
+
+       if (!dev)
+               return false;
+
+       if (i915.enable_execlists) {
+               struct intel_context *dctx = ring->default_context;
+               struct intel_ringbuffer *ringbuf = dctx->engine[ring->id].ringbuf;
+
+               return ringbuf->obj;
+       } else
+               return ring->buffer && ring->buffer->obj;
+}
 
-static inline int __ring_space(int head, int tail, int size)
+int __intel_ring_space(int head, int tail, int size)
 {
        int space = head - (tail + I915_RING_FREE_SPACE);
        if (space < 0)
@@ -48,12 +58,13 @@ static inline int __ring_space(int head, int tail, int size)
        return space;
 }
 
-static inline int ring_space(struct intel_ringbuffer *ringbuf)
+int intel_ring_space(struct intel_ringbuffer *ringbuf)
 {
-       return __ring_space(ringbuf->head & HEAD_ADDR, ringbuf->tail, ringbuf->size);
+       return __intel_ring_space(ringbuf->head & HEAD_ADDR,
+                                 ringbuf->tail, ringbuf->size);
 }
 
-static bool intel_ring_stopped(struct intel_engine_cs *ring)
+bool intel_ring_stopped(struct intel_engine_cs *ring)
 {
        struct drm_i915_private *dev_priv = ring->dev->dev_private;
        return dev_priv->gpu_error.stop_rings & intel_ring_flag(ring);
@@ -433,7 +444,14 @@ gen8_render_ring_flush(struct intel_engine_cs *ring,
                        return ret;
        }
 
-       return gen8_emit_pipe_control(ring, flags, scratch_addr);
+       ret = gen8_emit_pipe_control(ring, flags, scratch_addr);
+       if (ret)
+               return ret;
+
+       if (!invalidate_domains && flush_domains)
+               return gen7_ring_fbc_flush(ring, FBC_REND_NUKE);
+
+       return 0;
 }
 
 static void ring_write_tail(struct intel_engine_cs *ring,
@@ -476,9 +494,14 @@ static bool stop_ring(struct intel_engine_cs *ring)
 
        if (!IS_GEN2(ring->dev)) {
                I915_WRITE_MODE(ring, _MASKED_BIT_ENABLE(STOP_RING));
-               if (wait_for_atomic((I915_READ_MODE(ring) & MODE_IDLE) != 0, 1000)) {
-                       DRM_ERROR("%s :timed out trying to stop ring\n", ring->name);
-                       return false;
+               if (wait_for((I915_READ_MODE(ring) & MODE_IDLE) != 0, 1000)) {
+                       DRM_ERROR("%s : timed out trying to stop ring\n", ring->name);
+                       /* Sometimes we observe that the idle flag is not
+                        * set even though the ring is empty. So double
+                        * check before giving up.
+                        */
+                       if (I915_READ_HEAD(ring) != I915_READ_TAIL(ring))
+                               return false;
                }
        }
 
@@ -540,6 +563,14 @@ static int init_ring_common(struct intel_engine_cs *ring)
         * also enforces ordering), otherwise the hw might lose the new ring
         * register values. */
        I915_WRITE_START(ring, i915_gem_obj_ggtt_offset(obj));
+
+       /* WaClearRingBufHeadRegAtInit:ctg,elk */
+       if (I915_READ_HEAD(ring))
+               DRM_DEBUG("%s initialization failed [head=%08x], fudging\n",
+                         ring->name, I915_READ_HEAD(ring));
+       I915_WRITE_HEAD(ring, 0);
+       (void)I915_READ_HEAD(ring);
+
        I915_WRITE_CTL(ring,
                        ((ringbuf->size - PAGE_SIZE) & RING_NR_PAGES)
                        | RING_VALID);
@@ -563,7 +594,7 @@ static int init_ring_common(struct intel_engine_cs *ring)
        else {
                ringbuf->head = I915_READ_HEAD(ring);
                ringbuf->tail = I915_READ_TAIL(ring) & TAIL_ADDR;
-               ringbuf->space = ring_space(ringbuf);
+               ringbuf->space = intel_ring_space(ringbuf);
                ringbuf->last_retired_head = -1;
        }
 
@@ -575,8 +606,25 @@ out:
        return ret;
 }
 
-static int
-init_pipe_control(struct intel_engine_cs *ring)
+void
+intel_fini_pipe_control(struct intel_engine_cs *ring)
+{
+       struct drm_device *dev = ring->dev;
+
+       if (ring->scratch.obj == NULL)
+               return;
+
+       if (INTEL_INFO(dev)->gen >= 5) {
+               kunmap(sg_page(ring->scratch.obj->pages->sgl));
+               i915_gem_object_ggtt_unpin(ring->scratch.obj);
+       }
+
+       drm_gem_object_unreference(&ring->scratch.obj->base);
+       ring->scratch.obj = NULL;
+}
+
+int
+intel_init_pipe_control(struct intel_engine_cs *ring)
 {
        int ret;
 
@@ -617,6 +665,135 @@ err:
        return ret;
 }
 
+static inline void intel_ring_emit_wa(struct intel_engine_cs *ring,
+                                      u32 addr, u32 value)
+{
+       struct drm_device *dev = ring->dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+
+       if (WARN_ON(dev_priv->num_wa_regs >= I915_MAX_WA_REGS))
+               return;
+
+       intel_ring_emit(ring, MI_LOAD_REGISTER_IMM(1));
+       intel_ring_emit(ring, addr);
+       intel_ring_emit(ring, value);
+
+       dev_priv->intel_wa_regs[dev_priv->num_wa_regs].addr = addr;
+       dev_priv->intel_wa_regs[dev_priv->num_wa_regs].mask = value & 0xFFFF;
+       /* value is updated with the status of remaining bits of this
+        * register when it is read from debugfs file
+        */
+       dev_priv->intel_wa_regs[dev_priv->num_wa_regs].value = value;
+       dev_priv->num_wa_regs++;
+
+       return;
+}
+
+static int bdw_init_workarounds(struct intel_engine_cs *ring)
+{
+       int ret;
+       struct drm_device *dev = ring->dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+
+       /*
+        * workarounds applied in this fn are part of register state context,
+        * they need to be re-initialized followed by gpu reset, suspend/resume,
+        * module reload.
+        */
+       dev_priv->num_wa_regs = 0;
+       memset(dev_priv->intel_wa_regs, 0, sizeof(dev_priv->intel_wa_regs));
+
+       /*
+        * update the number of dwords required based on the
+        * actual number of workarounds applied
+        */
+       ret = intel_ring_begin(ring, 18);
+       if (ret)
+               return ret;
+
+       /* WaDisablePartialInstShootdown:bdw */
+       /* WaDisableThreadStallDopClockGating:bdw */
+       /* FIXME: Unclear whether we really need this on production bdw. */
+       intel_ring_emit_wa(ring, GEN8_ROW_CHICKEN,
+                          _MASKED_BIT_ENABLE(PARTIAL_INSTRUCTION_SHOOTDOWN_DISABLE
+                                            | STALL_DOP_GATING_DISABLE));
+
+       /* WaDisableDopClockGating:bdw May not be needed for production */
+       intel_ring_emit_wa(ring, GEN7_ROW_CHICKEN2,
+                          _MASKED_BIT_ENABLE(DOP_CLOCK_GATING_DISABLE));
+
+       intel_ring_emit_wa(ring, HALF_SLICE_CHICKEN3,
+                          _MASKED_BIT_ENABLE(GEN8_SAMPLER_POWER_BYPASS_DIS));
+
+       /* Use Force Non-Coherent whenever executing a 3D context. This is a
+        * workaround for for a possible hang in the unlikely event a TLB
+        * invalidation occurs during a PSD flush.
+        */
+       intel_ring_emit_wa(ring, HDC_CHICKEN0,
+                          _MASKED_BIT_ENABLE(HDC_FORCE_NON_COHERENT));
+
+       /* Wa4x4STCOptimizationDisable:bdw */
+       intel_ring_emit_wa(ring, CACHE_MODE_1,
+                          _MASKED_BIT_ENABLE(GEN8_4x4_STC_OPTIMIZATION_DISABLE));
+
+       /*
+        * BSpec recommends 8x4 when MSAA is used,
+        * however in practice 16x4 seems fastest.
+        *
+        * Note that PS/WM thread counts depend on the WIZ hashing
+        * disable bit, which we don't touch here, but it's good
+        * to keep in mind (see 3DSTATE_PS and 3DSTATE_WM).
+        */
+       intel_ring_emit_wa(ring, GEN7_GT_MODE,
+                          GEN6_WIZ_HASHING_MASK | GEN6_WIZ_HASHING_16x4);
+
+       intel_ring_advance(ring);
+
+       DRM_DEBUG_DRIVER("Number of Workarounds applied: %d\n",
+                        dev_priv->num_wa_regs);
+
+       return 0;
+}
+
+static int chv_init_workarounds(struct intel_engine_cs *ring)
+{
+       int ret;
+       struct drm_device *dev = ring->dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+
+       /*
+        * workarounds applied in this fn are part of register state context,
+        * they need to be re-initialized followed by gpu reset, suspend/resume,
+        * module reload.
+        */
+       dev_priv->num_wa_regs = 0;
+       memset(dev_priv->intel_wa_regs, 0, sizeof(dev_priv->intel_wa_regs));
+
+       ret = intel_ring_begin(ring, 12);
+       if (ret)
+               return ret;
+
+       /* WaDisablePartialInstShootdown:chv */
+       intel_ring_emit_wa(ring, GEN8_ROW_CHICKEN,
+                          _MASKED_BIT_ENABLE(PARTIAL_INSTRUCTION_SHOOTDOWN_DISABLE));
+
+       /* WaDisableThreadStallDopClockGating:chv */
+       intel_ring_emit_wa(ring, GEN8_ROW_CHICKEN,
+                          _MASKED_BIT_ENABLE(STALL_DOP_GATING_DISABLE));
+
+       /* WaDisableDopClockGating:chv (pre-production hw) */
+       intel_ring_emit_wa(ring, GEN7_ROW_CHICKEN2,
+                          _MASKED_BIT_ENABLE(DOP_CLOCK_GATING_DISABLE));
+
+       /* WaDisableSamplerPowerBypass:chv (pre-production hw) */
+       intel_ring_emit_wa(ring, HALF_SLICE_CHICKEN3,
+                          _MASKED_BIT_ENABLE(GEN8_SAMPLER_POWER_BYPASS_DIS));
+
+       intel_ring_advance(ring);
+
+       return 0;
+}
+
 static int init_render_ring(struct intel_engine_cs *ring)
 {
        struct drm_device *dev = ring->dev;
@@ -651,7 +828,7 @@ static int init_render_ring(struct intel_engine_cs *ring)
                           _MASKED_BIT_ENABLE(GFX_REPLAY_MODE));
 
        if (INTEL_INFO(dev)->gen >= 5) {
-               ret = init_pipe_control(ring);
+               ret = intel_init_pipe_control(ring);
                if (ret)
                        return ret;
        }
@@ -686,16 +863,7 @@ static void render_ring_cleanup(struct intel_engine_cs *ring)
                dev_priv->semaphore_obj = NULL;
        }
 
-       if (ring->scratch.obj == NULL)
-               return;
-
-       if (INTEL_INFO(dev)->gen >= 5) {
-               kunmap(sg_page(ring->scratch.obj->pages->sgl));
-               i915_gem_object_ggtt_unpin(ring->scratch.obj);
-       }
-
-       drm_gem_object_unreference(&ring->scratch.obj->base);
-       ring->scratch.obj = NULL;
+       intel_fini_pipe_control(ring);
 }
 
 static int gen8_rcs_signal(struct intel_engine_cs *signaller,
@@ -1526,7 +1694,7 @@ static int init_phys_status_page(struct intel_engine_cs *ring)
        return 0;
 }
 
-static void intel_destroy_ringbuffer_obj(struct intel_ringbuffer *ringbuf)
+void intel_destroy_ringbuffer_obj(struct intel_ringbuffer *ringbuf)
 {
        if (!ringbuf->obj)
                return;
@@ -1537,8 +1705,8 @@ static void intel_destroy_ringbuffer_obj(struct intel_ringbuffer *ringbuf)
        ringbuf->obj = NULL;
 }
 
-static int intel_alloc_ringbuffer_obj(struct drm_device *dev,
-                                     struct intel_ringbuffer *ringbuf)
+int intel_alloc_ringbuffer_obj(struct drm_device *dev,
+                              struct intel_ringbuffer *ringbuf)
 {
        struct drm_i915_private *dev_priv = to_i915(dev);
        struct drm_i915_gem_object *obj;
@@ -1600,7 +1768,9 @@ static int intel_init_ring_buffer(struct drm_device *dev,
        ring->dev = dev;
        INIT_LIST_HEAD(&ring->active_list);
        INIT_LIST_HEAD(&ring->request_list);
+       INIT_LIST_HEAD(&ring->execlist_queue);
        ringbuf->size = 32 * PAGE_SIZE;
+       ringbuf->ring = ring;
        memset(ring->semaphore.sync_seqno, 0, sizeof(ring->semaphore.sync_seqno));
 
        init_waitqueue_head(&ring->irq_queue);
@@ -1683,13 +1853,14 @@ static int intel_ring_wait_request(struct intel_engine_cs *ring, int n)
                ringbuf->head = ringbuf->last_retired_head;
                ringbuf->last_retired_head = -1;
 
-               ringbuf->space = ring_space(ringbuf);
+               ringbuf->space = intel_ring_space(ringbuf);
                if (ringbuf->space >= n)
                        return 0;
        }
 
        list_for_each_entry(request, &ring->request_list, list) {
-               if (__ring_space(request->tail, ringbuf->tail, ringbuf->size) >= n) {
+               if (__intel_ring_space(request->tail, ringbuf->tail,
+                                      ringbuf->size) >= n) {
                        seqno = request->seqno;
                        break;
                }
@@ -1706,7 +1877,7 @@ static int intel_ring_wait_request(struct intel_engine_cs *ring, int n)
        ringbuf->head = ringbuf->last_retired_head;
        ringbuf->last_retired_head = -1;
 
-       ringbuf->space = ring_space(ringbuf);
+       ringbuf->space = intel_ring_space(ringbuf);
        return 0;
 }
 
@@ -1735,7 +1906,7 @@ static int ring_wait_for_space(struct intel_engine_cs *ring, int n)
        trace_i915_ring_wait_begin(ring);
        do {
                ringbuf->head = I915_READ_HEAD(ring);
-               ringbuf->space = ring_space(ringbuf);
+               ringbuf->space = intel_ring_space(ringbuf);
                if (ringbuf->space >= n) {
                        ret = 0;
                        break;
@@ -1787,7 +1958,7 @@ static int intel_wrap_ring_buffer(struct intel_engine_cs *ring)
                iowrite32(MI_NOOP, virt++);
 
        ringbuf->tail = 0;
-       ringbuf->space = ring_space(ringbuf);
+       ringbuf->space = intel_ring_space(ringbuf);
 
        return 0;
 }
@@ -1992,9 +2163,7 @@ gen8_ring_dispatch_execbuffer(struct intel_engine_cs *ring,
                              u64 offset, u32 len,
                              unsigned flags)
 {
-       struct drm_i915_private *dev_priv = ring->dev->dev_private;
-       bool ppgtt = dev_priv->mm.aliasing_ppgtt != NULL &&
-               !(flags & I915_DISPATCH_SECURE);
+       bool ppgtt = USES_PPGTT(ring->dev) && !(flags & I915_DISPATCH_SECURE);
        int ret;
 
        ret = intel_ring_begin(ring, 4);
@@ -2023,8 +2192,9 @@ hsw_ring_dispatch_execbuffer(struct intel_engine_cs *ring,
                return ret;
 
        intel_ring_emit(ring,
-                       MI_BATCH_BUFFER_START | MI_BATCH_PPGTT_HSW |
-                       (flags & I915_DISPATCH_SECURE ? 0 : MI_BATCH_NON_SECURE_HSW));
+                       MI_BATCH_BUFFER_START |
+                       (flags & I915_DISPATCH_SECURE ?
+                        0 : MI_BATCH_PPGTT_HSW | MI_BATCH_NON_SECURE_HSW));
        /* bit0-7 is the length on GEN6+ */
        intel_ring_emit(ring, offset);
        intel_ring_advance(ring);
@@ -2123,6 +2293,10 @@ int intel_init_render_ring_buffer(struct drm_device *dev)
                                        dev_priv->semaphore_obj = obj;
                        }
                }
+               if (IS_CHERRYVIEW(dev))
+                       ring->init_context = chv_init_workarounds;
+               else
+                       ring->init_context = bdw_init_workarounds;
                ring->add_request = gen6_add_request;
                ring->flush = gen8_render_ring_flush;
                ring->irq_get = gen8_ring_get_irq;
index 70525d0c2c74650ef780a69c797c59316cedd371..96479c89f4bda9c2e6af0084e75b6785eee6ccfa 100644 (file)
@@ -5,6 +5,13 @@
 
 #define I915_CMD_HASH_ORDER 9
 
+/* Early gen2 devices have a cacheline of just 32 bytes, using 64 is overkill,
+ * but keeps the logic simple. Indeed, the whole purpose of this macro is just
+ * to give some inclination as to some of the magic values used in the various
+ * workarounds!
+ */
+#define CACHELINE_BYTES 64
+
 /*
  * Gen2 BSpec "1. Programming Environment" / 1.4.4.6 "Ring Buffer Use"
  * Gen3 BSpec "vol1c Memory Interface Functions" / 2.3.4.5 "Ring Buffer Use"
@@ -90,6 +97,15 @@ struct intel_ringbuffer {
        struct drm_i915_gem_object *obj;
        void __iomem *virtual_start;
 
+       struct intel_engine_cs *ring;
+
+       /*
+        * FIXME: This backpointer is an artifact of the history of how the
+        * execlist patches came into being. It will get removed once the basic
+        * code has landed.
+        */
+       struct intel_context *FIXME_lrc_ctx;
+
        u32 head;
        u32 tail;
        int space;
@@ -132,6 +148,8 @@ struct  intel_engine_cs {
 
        int             (*init)(struct intel_engine_cs *ring);
 
+       int             (*init_context)(struct intel_engine_cs *ring);
+
        void            (*write_tail)(struct intel_engine_cs *ring,
                                      u32 value);
        int __must_check (*flush)(struct intel_engine_cs *ring,
@@ -214,6 +232,18 @@ struct  intel_engine_cs {
                                  unsigned int num_dwords);
        } semaphore;
 
+       /* Execlists */
+       spinlock_t execlist_lock;
+       struct list_head execlist_queue;
+       u8 next_context_status_buffer;
+       u32             irq_keep_mask; /* bitmask for interrupts that should not be masked */
+       int             (*emit_request)(struct intel_ringbuffer *ringbuf);
+       int             (*emit_flush)(struct intel_ringbuffer *ringbuf,
+                                     u32 invalidate_domains,
+                                     u32 flush_domains);
+       int             (*emit_bb_start)(struct intel_ringbuffer *ringbuf,
+                                        u64 offset, unsigned flags);
+
        /**
         * List of objects currently involved in rendering from the
         * ringbuffer.
@@ -287,11 +317,7 @@ struct  intel_engine_cs {
        u32 (*get_cmd_length_mask)(u32 cmd_header);
 };
 
-static inline bool
-intel_ring_initialized(struct intel_engine_cs *ring)
-{
-       return ring->buffer && ring->buffer->obj;
-}
+bool intel_ring_initialized(struct intel_engine_cs *ring);
 
 static inline unsigned
 intel_ring_flag(struct intel_engine_cs *ring)
@@ -355,6 +381,10 @@ intel_write_status_page(struct intel_engine_cs *ring,
 #define I915_GEM_HWS_SCRATCH_INDEX     0x30
 #define I915_GEM_HWS_SCRATCH_ADDR (I915_GEM_HWS_SCRATCH_INDEX << MI_STORE_DWORD_INDEX_SHIFT)
 
+void intel_destroy_ringbuffer_obj(struct intel_ringbuffer *ringbuf);
+int intel_alloc_ringbuffer_obj(struct drm_device *dev,
+                              struct intel_ringbuffer *ringbuf);
+
 void intel_stop_ring_buffer(struct intel_engine_cs *ring);
 void intel_cleanup_ring_buffer(struct intel_engine_cs *ring);
 
@@ -372,6 +402,9 @@ static inline void intel_ring_advance(struct intel_engine_cs *ring)
        struct intel_ringbuffer *ringbuf = ring->buffer;
        ringbuf->tail &= ringbuf->size - 1;
 }
+int __intel_ring_space(int head, int tail, int size);
+int intel_ring_space(struct intel_ringbuffer *ringbuf);
+bool intel_ring_stopped(struct intel_engine_cs *ring);
 void __intel_ring_advance(struct intel_engine_cs *ring);
 
 int __must_check intel_ring_idle(struct intel_engine_cs *ring);
@@ -379,6 +412,9 @@ void intel_ring_init_seqno(struct intel_engine_cs *ring, u32 seqno);
 int intel_ring_flush_all_caches(struct intel_engine_cs *ring);
 int intel_ring_invalidate_all_caches(struct intel_engine_cs *ring);
 
+void intel_fini_pipe_control(struct intel_engine_cs *ring);
+int intel_init_pipe_control(struct intel_engine_cs *ring);
+
 int intel_init_render_ring_buffer(struct drm_device *dev);
 int intel_init_bsd_ring_buffer(struct drm_device *dev);
 int intel_init_bsd2_ring_buffer(struct drm_device *dev);
index 168c6652cda198731a2afa7d2675658f86ff6023..07a74ef589bd00636896510d245d6e149a49d653 100644 (file)
@@ -53,6 +53,7 @@ static bool intel_pipe_update_start(struct intel_crtc *crtc, uint32_t *start_vbl
        enum pipe pipe = crtc->pipe;
        long timeout = msecs_to_jiffies_timeout(1);
        int scanline, min, max, vblank_start;
+       wait_queue_head_t *wq = drm_crtc_vblank_waitqueue(&crtc->base);
        DEFINE_WAIT(wait);
 
        WARN_ON(!drm_modeset_is_locked(&crtc->base.mutex));
@@ -81,7 +82,7 @@ static bool intel_pipe_update_start(struct intel_crtc *crtc, uint32_t *start_vbl
                 * other CPUs can see the task state update by the time we
                 * read the scanline.
                 */
-               prepare_to_wait(&crtc->vbl_wait, &wait, TASK_UNINTERRUPTIBLE);
+               prepare_to_wait(wq, &wait, TASK_UNINTERRUPTIBLE);
 
                scanline = intel_get_crtc_scanline(crtc);
                if (scanline < min || scanline > max)
@@ -100,7 +101,7 @@ static bool intel_pipe_update_start(struct intel_crtc *crtc, uint32_t *start_vbl
                local_irq_disable();
        }
 
-       finish_wait(&crtc->vbl_wait, &wait);
+       finish_wait(wq, &wait);
 
        drm_vblank_put(dev, pipe);
 
@@ -163,6 +164,7 @@ vlv_update_plane(struct drm_plane *dplane, struct drm_crtc *crtc,
        sprctl &= ~SP_PIXFORMAT_MASK;
        sprctl &= ~SP_YUV_BYTE_ORDER_MASK;
        sprctl &= ~SP_TILED;
+       sprctl &= ~SP_ROTATE_180;
 
        switch (fb->pixel_format) {
        case DRM_FORMAT_YUYV:
@@ -235,6 +237,14 @@ vlv_update_plane(struct drm_plane *dplane, struct drm_crtc *crtc,
                                                        fb->pitches[0]);
        linear_offset -= sprsurf_offset;
 
+       if (intel_plane->rotation == BIT(DRM_ROTATE_180)) {
+               sprctl |= SP_ROTATE_180;
+
+               x += src_w;
+               y += src_h;
+               linear_offset += src_h * fb->pitches[0] + src_w * pixel_size;
+       }
+
        atomic_update = intel_pipe_update_start(intel_crtc, &start_vbl_count);
 
        intel_update_primary_plane(intel_crtc);
@@ -364,6 +374,7 @@ ivb_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
        sprctl &= ~SPRITE_RGB_ORDER_RGBX;
        sprctl &= ~SPRITE_YUV_BYTE_ORDER_MASK;
        sprctl &= ~SPRITE_TILED;
+       sprctl &= ~SPRITE_ROTATE_180;
 
        switch (fb->pixel_format) {
        case DRM_FORMAT_XBGR8888:
@@ -426,6 +437,18 @@ ivb_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
                                               pixel_size, fb->pitches[0]);
        linear_offset -= sprsurf_offset;
 
+       if (intel_plane->rotation == BIT(DRM_ROTATE_180)) {
+               sprctl |= SPRITE_ROTATE_180;
+
+               /* HSW and BDW does this automagically in hardware */
+               if (!IS_HASWELL(dev) && !IS_BROADWELL(dev)) {
+                       x += src_w;
+                       y += src_h;
+                       linear_offset += src_h * fb->pitches[0] +
+                               src_w * pixel_size;
+               }
+       }
+
        atomic_update = intel_pipe_update_start(intel_crtc, &start_vbl_count);
 
        intel_update_primary_plane(intel_crtc);
@@ -571,6 +594,7 @@ ilk_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
        dvscntr &= ~DVS_RGB_ORDER_XBGR;
        dvscntr &= ~DVS_YUV_BYTE_ORDER_MASK;
        dvscntr &= ~DVS_TILED;
+       dvscntr &= ~DVS_ROTATE_180;
 
        switch (fb->pixel_format) {
        case DRM_FORMAT_XBGR8888:
@@ -628,6 +652,14 @@ ilk_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
                                               pixel_size, fb->pitches[0]);
        linear_offset -= dvssurf_offset;
 
+       if (intel_plane->rotation == BIT(DRM_ROTATE_180)) {
+               dvscntr |= DVS_ROTATE_180;
+
+               x += src_w;
+               y += src_h;
+               linear_offset += src_h * fb->pitches[0] + src_w * pixel_size;
+       }
+
        atomic_update = intel_pipe_update_start(intel_crtc, &start_vbl_count);
 
        intel_update_primary_plane(intel_crtc);
@@ -895,6 +927,9 @@ intel_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
        max_scale = intel_plane->max_downscale << 16;
        min_scale = intel_plane->can_scale ? 1 : (1 << 16);
 
+       drm_rect_rotate(&src, fb->width << 16, fb->height << 16,
+                       intel_plane->rotation);
+
        hscale = drm_rect_calc_hscale_relaxed(&src, &dst, min_scale, max_scale);
        BUG_ON(hscale < 0);
 
@@ -933,6 +968,9 @@ intel_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
                                     drm_rect_width(&dst) * hscale - drm_rect_width(&src),
                                     drm_rect_height(&dst) * vscale - drm_rect_height(&src));
 
+               drm_rect_rotate_inv(&src, fb->width << 16, fb->height << 16,
+                                   intel_plane->rotation);
+
                /* sanity check to make sure the src viewport wasn't enlarged */
                WARN_ON(src.x1 < (int) src_x ||
                        src.y1 < (int) src_y ||
@@ -1180,18 +1218,45 @@ out_unlock:
        return ret;
 }
 
-void intel_plane_restore(struct drm_plane *plane)
+int intel_plane_set_property(struct drm_plane *plane,
+                            struct drm_property *prop,
+                            uint64_t val)
+{
+       struct drm_device *dev = plane->dev;
+       struct intel_plane *intel_plane = to_intel_plane(plane);
+       uint64_t old_val;
+       int ret = -ENOENT;
+
+       if (prop == dev->mode_config.rotation_property) {
+               /* exactly one rotation angle please */
+               if (hweight32(val & 0xf) != 1)
+                       return -EINVAL;
+
+               if (intel_plane->rotation == val)
+                       return 0;
+
+               old_val = intel_plane->rotation;
+               intel_plane->rotation = val;
+               ret = intel_plane_restore(plane);
+               if (ret)
+                       intel_plane->rotation = old_val;
+       }
+
+       return ret;
+}
+
+int intel_plane_restore(struct drm_plane *plane)
 {
        struct intel_plane *intel_plane = to_intel_plane(plane);
 
        if (!plane->crtc || !plane->fb)
-               return;
+               return 0;
 
-       intel_update_plane(plane, plane->crtc, plane->fb,
-                          intel_plane->crtc_x, intel_plane->crtc_y,
-                          intel_plane->crtc_w, intel_plane->crtc_h,
-                          intel_plane->src_x, intel_plane->src_y,
-                          intel_plane->src_w, intel_plane->src_h);
+       return plane->funcs->update_plane(plane, plane->crtc, plane->fb,
+                                 intel_plane->crtc_x, intel_plane->crtc_y,
+                                 intel_plane->crtc_w, intel_plane->crtc_h,
+                                 intel_plane->src_x, intel_plane->src_y,
+                                 intel_plane->src_w, intel_plane->src_h);
 }
 
 void intel_plane_disable(struct drm_plane *plane)
@@ -1206,6 +1271,7 @@ static const struct drm_plane_funcs intel_plane_funcs = {
        .update_plane = intel_update_plane,
        .disable_plane = intel_disable_plane,
        .destroy = intel_destroy_plane,
+       .set_property = intel_plane_set_property,
 };
 
 static uint32_t ilk_plane_formats[] = {
@@ -1310,13 +1376,28 @@ intel_plane_init(struct drm_device *dev, enum pipe pipe, int plane)
 
        intel_plane->pipe = pipe;
        intel_plane->plane = plane;
+       intel_plane->rotation = BIT(DRM_ROTATE_0);
        possible_crtcs = (1 << pipe);
-       ret = drm_plane_init(dev, &intel_plane->base, possible_crtcs,
-                            &intel_plane_funcs,
-                            plane_formats, num_plane_formats,
-                            false);
-       if (ret)
+       ret = drm_universal_plane_init(dev, &intel_plane->base, possible_crtcs,
+                                      &intel_plane_funcs,
+                                      plane_formats, num_plane_formats,
+                                      DRM_PLANE_TYPE_OVERLAY);
+       if (ret) {
                kfree(intel_plane);
+               goto out;
+       }
+
+       if (!dev->mode_config.rotation_property)
+               dev->mode_config.rotation_property =
+                       drm_mode_create_rotation_property(dev,
+                                                         BIT(DRM_ROTATE_0) |
+                                                         BIT(DRM_ROTATE_180));
+
+       if (dev->mode_config.rotation_property)
+               drm_object_attach_property(&intel_plane->base.base,
+                                          dev->mode_config.rotation_property,
+                                          intel_plane->rotation);
 
+ out:
        return ret;
 }
index e81bc3bdc533b5ae60a7fae77536d1dd83caf1da..918b761639651042edebf1ab7a3d886973774a15 100644 (file)
@@ -101,7 +101,7 @@ static void __gen7_gt_force_wake_mt_get(struct drm_i915_private *dev_priv,
 {
        u32 forcewake_ack;
 
-       if (IS_HASWELL(dev_priv->dev) || IS_GEN8(dev_priv->dev))
+       if (IS_HASWELL(dev_priv->dev) || IS_BROADWELL(dev_priv->dev))
                forcewake_ack = FORCEWAKE_ACK_HSW;
        else
                forcewake_ack = FORCEWAKE_MT_ACK;
@@ -334,7 +334,7 @@ void intel_uncore_forcewake_reset(struct drm_device *dev, bool restore)
        else if (IS_GEN6(dev) || IS_GEN7(dev))
                __gen6_gt_force_wake_reset(dev_priv);
 
-       if (IS_IVYBRIDGE(dev) || IS_HASWELL(dev) || IS_GEN8(dev))
+       if (IS_IVYBRIDGE(dev) || IS_HASWELL(dev) || IS_BROADWELL(dev))
                __gen7_gt_force_wake_mt_reset(dev_priv);
 
        if (restore) { /* If reset with a user forcewake, try to restore */
@@ -838,7 +838,7 @@ void intel_uncore_init(struct drm_device *dev)
        if (IS_VALLEYVIEW(dev)) {
                dev_priv->uncore.funcs.force_wake_get = __vlv_force_wake_get;
                dev_priv->uncore.funcs.force_wake_put = __vlv_force_wake_put;
-       } else if (IS_HASWELL(dev) || IS_GEN8(dev)) {
+       } else if (IS_HASWELL(dev) || IS_BROADWELL(dev)) {
                dev_priv->uncore.funcs.force_wake_get = __gen7_gt_force_wake_mt_get;
                dev_priv->uncore.funcs.force_wake_put = __gen7_gt_force_wake_mt_put;
        } else if (IS_IVYBRIDGE(dev)) {
index c3bf059ba720569540145f225222e0f2b444827c..8cfa9cb74c8679a329ff14293f0e1fd4b2927323 100644 (file)
@@ -502,31 +502,31 @@ static int mga_do_agp_dma_bootstrap(struct drm_device *dev,
                return err;
        }
 
-       /* Make drm_addbufs happy by not trying to create a mapping for less
-        * than a page.
+       /* Make drm_legacy_addbufs happy by not trying to create a mapping for
+        * less than a page.
         */
        if (warp_size < PAGE_SIZE)
                warp_size = PAGE_SIZE;
 
        offset = 0;
-       err = drm_addmap(dev, offset, warp_size,
-                        _DRM_AGP, _DRM_READ_ONLY, &dev_priv->warp);
+       err = drm_legacy_addmap(dev, offset, warp_size,
+                               _DRM_AGP, _DRM_READ_ONLY, &dev_priv->warp);
        if (err) {
                DRM_ERROR("Unable to map WARP microcode: %d\n", err);
                return err;
        }
 
        offset += warp_size;
-       err = drm_addmap(dev, offset, dma_bs->primary_size,
-                        _DRM_AGP, _DRM_READ_ONLY, &dev_priv->primary);
+       err = drm_legacy_addmap(dev, offset, dma_bs->primary_size,
+                               _DRM_AGP, _DRM_READ_ONLY, &dev_priv->primary);
        if (err) {
                DRM_ERROR("Unable to map primary DMA region: %d\n", err);
                return err;
        }
 
        offset += dma_bs->primary_size;
-       err = drm_addmap(dev, offset, secondary_size,
-                        _DRM_AGP, 0, &dev->agp_buffer_map);
+       err = drm_legacy_addmap(dev, offset, secondary_size,
+                               _DRM_AGP, 0, &dev->agp_buffer_map);
        if (err) {
                DRM_ERROR("Unable to map secondary DMA region: %d\n", err);
                return err;
@@ -538,7 +538,7 @@ static int mga_do_agp_dma_bootstrap(struct drm_device *dev,
        req.flags = _DRM_AGP_BUFFER;
        req.agp_start = offset;
 
-       err = drm_addbufs_agp(dev, &req);
+       err = drm_legacy_addbufs_agp(dev, &req);
        if (err) {
                DRM_ERROR("Unable to add secondary DMA buffers: %d\n", err);
                return err;
@@ -559,16 +559,16 @@ static int mga_do_agp_dma_bootstrap(struct drm_device *dev,
        }
 
        offset += secondary_size;
-       err = drm_addmap(dev, offset, agp_size - offset,
-                        _DRM_AGP, 0, &dev_priv->agp_textures);
+       err = drm_legacy_addmap(dev, offset, agp_size - offset,
+                               _DRM_AGP, 0, &dev_priv->agp_textures);
        if (err) {
                DRM_ERROR("Unable to map AGP texture region %d\n", err);
                return err;
        }
 
-       drm_core_ioremap(dev_priv->warp, dev);
-       drm_core_ioremap(dev_priv->primary, dev);
-       drm_core_ioremap(dev->agp_buffer_map, dev);
+       drm_legacy_ioremap(dev_priv->warp, dev);
+       drm_legacy_ioremap(dev_priv->primary, dev);
+       drm_legacy_ioremap(dev->agp_buffer_map, dev);
 
        if (!dev_priv->warp->handle ||
            !dev_priv->primary->handle || !dev->agp_buffer_map->handle) {
@@ -602,7 +602,7 @@ static int mga_do_agp_dma_bootstrap(struct drm_device *dev,
  *
  * \todo
  * Determine whether the maximum address passed to drm_pci_alloc is correct.
- * The same goes for drm_addbufs_pci.
+ * The same goes for drm_legacy_addbufs_pci.
  *
  * \sa mga_do_dma_bootstrap, mga_do_agp_dma_bootstrap
  */
@@ -622,15 +622,15 @@ static int mga_do_pci_dma_bootstrap(struct drm_device *dev,
                return -EFAULT;
        }
 
-       /* Make drm_addbufs happy by not trying to create a mapping for less
-        * than a page.
+       /* Make drm_legacy_addbufs happy by not trying to create a mapping for
+        * less than a page.
         */
        if (warp_size < PAGE_SIZE)
                warp_size = PAGE_SIZE;
 
        /* The proper alignment is 0x100 for this mapping */
-       err = drm_addmap(dev, 0, warp_size, _DRM_CONSISTENT,
-                        _DRM_READ_ONLY, &dev_priv->warp);
+       err = drm_legacy_addmap(dev, 0, warp_size, _DRM_CONSISTENT,
+                               _DRM_READ_ONLY, &dev_priv->warp);
        if (err != 0) {
                DRM_ERROR("Unable to create mapping for WARP microcode: %d\n",
                          err);
@@ -645,8 +645,8 @@ static int mga_do_pci_dma_bootstrap(struct drm_device *dev,
        for (primary_size = dma_bs->primary_size; primary_size != 0;
             primary_size >>= 1) {
                /* The proper alignment for this mapping is 0x04 */
-               err = drm_addmap(dev, 0, primary_size, _DRM_CONSISTENT,
-                                _DRM_READ_ONLY, &dev_priv->primary);
+               err = drm_legacy_addmap(dev, 0, primary_size, _DRM_CONSISTENT,
+                                       _DRM_READ_ONLY, &dev_priv->primary);
                if (!err)
                        break;
        }
@@ -669,7 +669,7 @@ static int mga_do_pci_dma_bootstrap(struct drm_device *dev,
                req.count = bin_count;
                req.size = dma_bs->secondary_bin_size;
 
-               err = drm_addbufs_pci(dev, &req);
+               err = drm_legacy_addbufs_pci(dev, &req);
                if (!err)
                        break;
        }
@@ -708,15 +708,16 @@ static int mga_do_dma_bootstrap(struct drm_device *dev,
        /* The first steps are the same for both PCI and AGP based DMA.  Map
         * the cards MMIO registers and map a status page.
         */
-       err = drm_addmap(dev, dev_priv->mmio_base, dev_priv->mmio_size,
-                        _DRM_REGISTERS, _DRM_READ_ONLY, &dev_priv->mmio);
+       err = drm_legacy_addmap(dev, dev_priv->mmio_base, dev_priv->mmio_size,
+                               _DRM_REGISTERS, _DRM_READ_ONLY,
+                               &dev_priv->mmio);
        if (err) {
                DRM_ERROR("Unable to map MMIO region: %d\n", err);
                return err;
        }
 
-       err = drm_addmap(dev, 0, SAREA_MAX, _DRM_SHM,
-                        _DRM_READ_ONLY | _DRM_LOCKED | _DRM_KERNEL,
+       err = drm_legacy_addmap(dev, 0, SAREA_MAX, _DRM_SHM,
+                               _DRM_READ_ONLY | _DRM_LOCKED | _DRM_KERNEL,
                         &dev_priv->status);
        if (err) {
                DRM_ERROR("Unable to map status region: %d\n", err);
@@ -809,7 +810,7 @@ static int mga_do_init_dma(struct drm_device *dev, drm_mga_init_t *init)
        dev_priv->texture_offset = init->texture_offset[0];
        dev_priv->texture_size = init->texture_size[0];
 
-       dev_priv->sarea = drm_getsarea(dev);
+       dev_priv->sarea = drm_legacy_getsarea(dev);
        if (!dev_priv->sarea) {
                DRM_ERROR("failed to find sarea!\n");
                return -EINVAL;
@@ -820,37 +821,37 @@ static int mga_do_init_dma(struct drm_device *dev, drm_mga_init_t *init)
                dev_priv->dma_access = MGA_PAGPXFER;
                dev_priv->wagp_enable = MGA_WAGP_ENABLE;
 
-               dev_priv->status = drm_core_findmap(dev, init->status_offset);
+               dev_priv->status = drm_legacy_findmap(dev, init->status_offset);
                if (!dev_priv->status) {
                        DRM_ERROR("failed to find status page!\n");
                        return -EINVAL;
                }
-               dev_priv->mmio = drm_core_findmap(dev, init->mmio_offset);
+               dev_priv->mmio = drm_legacy_findmap(dev, init->mmio_offset);
                if (!dev_priv->mmio) {
                        DRM_ERROR("failed to find mmio region!\n");
                        return -EINVAL;
                }
-               dev_priv->warp = drm_core_findmap(dev, init->warp_offset);
+               dev_priv->warp = drm_legacy_findmap(dev, init->warp_offset);
                if (!dev_priv->warp) {
                        DRM_ERROR("failed to find warp microcode region!\n");
                        return -EINVAL;
                }
-               dev_priv->primary = drm_core_findmap(dev, init->primary_offset);
+               dev_priv->primary = drm_legacy_findmap(dev, init->primary_offset);
                if (!dev_priv->primary) {
                        DRM_ERROR("failed to find primary dma region!\n");
                        return -EINVAL;
                }
                dev->agp_buffer_token = init->buffers_offset;
                dev->agp_buffer_map =
-                   drm_core_findmap(dev, init->buffers_offset);
+                   drm_legacy_findmap(dev, init->buffers_offset);
                if (!dev->agp_buffer_map) {
                        DRM_ERROR("failed to find dma buffer region!\n");
                        return -EINVAL;
                }
 
-               drm_core_ioremap(dev_priv->warp, dev);
-               drm_core_ioremap(dev_priv->primary, dev);
-               drm_core_ioremap(dev->agp_buffer_map, dev);
+               drm_legacy_ioremap(dev_priv->warp, dev);
+               drm_legacy_ioremap(dev_priv->primary, dev);
+               drm_legacy_ioremap(dev->agp_buffer_map, dev);
        }
 
        dev_priv->sarea_priv =
@@ -936,14 +937,14 @@ static int mga_do_cleanup_dma(struct drm_device *dev, int full_cleanup)
 
                if ((dev_priv->warp != NULL)
                    && (dev_priv->warp->type != _DRM_CONSISTENT))
-                       drm_core_ioremapfree(dev_priv->warp, dev);
+                       drm_legacy_ioremapfree(dev_priv->warp, dev);
 
                if ((dev_priv->primary != NULL)
                    && (dev_priv->primary->type != _DRM_CONSISTENT))
-                       drm_core_ioremapfree(dev_priv->primary, dev);
+                       drm_legacy_ioremapfree(dev_priv->primary, dev);
 
                if (dev->agp_buffer_map != NULL)
-                       drm_core_ioremapfree(dev->agp_buffer_map, dev);
+                       drm_legacy_ioremapfree(dev->agp_buffer_map, dev);
 
                if (dev_priv->used_new_dma_init) {
 #if __OS_HAS_AGP
index 6b1a87c8aac52f6f103385a7302713e719a3a1b3..5e2f131a6a72943f4f911c7428d507adae735bfa 100644 (file)
@@ -48,7 +48,7 @@ static const struct file_operations mga_driver_fops = {
        .open = drm_open,
        .release = drm_release,
        .unlocked_ioctl = drm_ioctl,
-       .mmap = drm_mmap,
+       .mmap = drm_legacy_mmap,
        .poll = drm_poll,
 #ifdef CONFIG_COMPAT
        .compat_ioctl = mga_compat_ioctl,
@@ -64,6 +64,7 @@ static struct drm_driver driver = {
        .load = mga_driver_load,
        .unload = mga_driver_unload,
        .lastclose = mga_driver_lastclose,
+       .set_busid = drm_pci_set_busid,
        .dma_quiescent = mga_driver_dma_quiescent,
        .device_is_agp = mga_driver_device_is_agp,
        .get_vblank_counter = mga_get_vblank_counter,
index fe453213600ab728e57385e40b272e4e8b8ebc49..b4a2014917e525109eaccdd5cd2237e6eb82915d 100644 (file)
@@ -31,6 +31,8 @@
 #ifndef __MGA_DRV_H__
 #define __MGA_DRV_H__
 
+#include <drm/drm_legacy.h>
+
 /* General customization:
  */
 
index 2d75d6df0789d5fd7d0515995ae1f80a35e982ca..97745991544ddd4a02000ed506a0a9cce5ccf8b1 100644 (file)
@@ -91,6 +91,7 @@ static struct drm_driver driver = {
        .driver_features = DRIVER_GEM | DRIVER_MODESET,
        .load = mgag200_driver_load,
        .unload = mgag200_driver_unload,
+       .set_busid = drm_pci_set_busid,
        .fops = &mgag200_driver_fops,
        .name = DRIVER_NAME,
        .desc = DRIVER_DESC,
index 80de23d9b9c9801daf630611205a2baa768a3341..e9eea1d4e7c3bff677d3b947d959685c7aa210cf 100644 (file)
@@ -22,6 +22,8 @@
 #include <drm/ttm/ttm_memory.h>
 #include <drm/ttm/ttm_module.h>
 
+#include <drm/drm_gem.h>
+
 #include <linux/i2c.h>
 #include <linux/i2c-algo-bit.h>
 
@@ -190,8 +192,6 @@ struct mga_device {
        resource_size_t                 rmmio_size;
        void __iomem                    *rmmio;
 
-       drm_local_map_t                 *framebuffer;
-
        struct mga_mc                   mc;
        struct mga_mode_info            mode_info;
 
@@ -224,7 +224,7 @@ struct mgag200_bo {
        struct ttm_placement placement;
        struct ttm_bo_kmap_obj kmap;
        struct drm_gem_object gem;
-       u32 placements[3];
+       struct ttm_place placements[3];
        int pin_count;
 };
 #define gem_to_mga_bo(gobj) container_of((gobj), struct mgag200_bo, gem)
index 5451dc58eff19ccb81d2eb4780c464e314ae6b11..4415af3666ab1116e0a07de45ffe1e272f5f4a9a 100644 (file)
@@ -158,7 +158,8 @@ static int mgag200fb_create_object(struct mga_fbdev *afbdev,
 static int mgag200fb_create(struct drm_fb_helper *helper,
                           struct drm_fb_helper_surface_size *sizes)
 {
-       struct mga_fbdev *mfbdev = (struct mga_fbdev *)helper;
+       struct mga_fbdev *mfbdev =
+               container_of(helper, struct mga_fbdev, helper);
        struct drm_device *dev = mfbdev->helper.dev;
        struct drm_mode_fb_cmd2 mode_cmd;
        struct mga_device *mdev = dev->dev_private;
index 45f04dea0ac2ad9f3f37847251e15b4fb0d09e80..83485ab81ce8714214c258b537fd1609e12bae2a 100644 (file)
@@ -1483,11 +1483,7 @@ static int mga_vga_mode_valid(struct drm_connector *connector,
 {
        struct drm_device *dev = connector->dev;
        struct mga_device *mdev = (struct mga_device*)dev->dev_private;
-       struct mga_fbdev *mfbdev = mdev->mfbdev;
-       struct drm_fb_helper *fb_helper = &mfbdev->helper;
-       struct drm_fb_helper_connector *fb_helper_conn = NULL;
        int bpp = 32;
-       int i = 0;
 
        if (IS_G200_SE(mdev)) {
                if (mdev->unique_rev_id == 0x01) {
@@ -1537,21 +1533,14 @@ static int mga_vga_mode_valid(struct drm_connector *connector,
        }
 
        /* Validate the mode input by the user */
-       for (i = 0; i < fb_helper->connector_count; i++) {
-               if (fb_helper->connector_info[i]->connector == connector) {
-                       /* Found the helper for this connector */
-                       fb_helper_conn = fb_helper->connector_info[i];
-                       if (fb_helper_conn->cmdline_mode.specified) {
-                               if (fb_helper_conn->cmdline_mode.bpp_specified) {
-                                       bpp = fb_helper_conn->cmdline_mode.bpp;
-                               }
-                       }
-               }
+       if (connector->cmdline_mode.specified) {
+               if (connector->cmdline_mode.bpp_specified)
+                       bpp = connector->cmdline_mode.bpp;
        }
 
        if ((mode->hdisplay * mode->vdisplay * (bpp/8)) > mdev->mc.vram_size) {
-               if (fb_helper_conn)
-                       fb_helper_conn->cmdline_mode.specified = false;
+               if (connector->cmdline_mode.specified)
+                       connector->cmdline_mode.specified = false;
                return MODE_BAD;
        }
 
index 5a00e90696de525129a98d9e4a438ab7b3779a49..d16964ea0ed4820039ca1b90030032e8ed735212 100644 (file)
@@ -293,18 +293,22 @@ void mgag200_mm_fini(struct mga_device *mdev)
 void mgag200_ttm_placement(struct mgag200_bo *bo, int domain)
 {
        u32 c = 0;
-       bo->placement.fpfn = 0;
-       bo->placement.lpfn = 0;
+       unsigned i;
+
        bo->placement.placement = bo->placements;
        bo->placement.busy_placement = bo->placements;
        if (domain & TTM_PL_FLAG_VRAM)
-               bo->placements[c++] = TTM_PL_FLAG_WC | TTM_PL_FLAG_UNCACHED | TTM_PL_FLAG_VRAM;
+               bo->placements[c++].flags = TTM_PL_FLAG_WC | TTM_PL_FLAG_UNCACHED | TTM_PL_FLAG_VRAM;
        if (domain & TTM_PL_FLAG_SYSTEM)
-               bo->placements[c++] = TTM_PL_MASK_CACHING | TTM_PL_FLAG_SYSTEM;
+               bo->placements[c++].flags = TTM_PL_MASK_CACHING | TTM_PL_FLAG_SYSTEM;
        if (!c)
-               bo->placements[c++] = TTM_PL_MASK_CACHING | TTM_PL_FLAG_SYSTEM;
+               bo->placements[c++].flags = TTM_PL_MASK_CACHING | TTM_PL_FLAG_SYSTEM;
        bo->placement.num_placement = c;
        bo->placement.num_busy_placement = c;
+       for (i = 0; i < c; ++i) {
+               bo->placements[i].fpfn = 0;
+               bo->placements[i].lpfn = 0;
+       }
 }
 
 int mgag200_bo_create(struct drm_device *dev, int size, int align,
@@ -335,7 +339,7 @@ int mgag200_bo_create(struct drm_device *dev, int size, int align,
        ret = ttm_bo_init(&mdev->ttm.bdev, &mgabo->bo, size,
                          ttm_bo_type_device, &mgabo->placement,
                          align >> PAGE_SHIFT, false, NULL, acc_size,
-                         NULL, mgag200_bo_ttm_destroy);
+                         NULL, NULL, mgag200_bo_ttm_destroy);
        if (ret)
                return ret;
 
@@ -361,7 +365,7 @@ int mgag200_bo_pin(struct mgag200_bo *bo, u32 pl_flag, u64 *gpu_addr)
 
        mgag200_ttm_placement(bo, pl_flag);
        for (i = 0; i < bo->placement.num_placement; i++)
-               bo->placements[i] |= TTM_PL_FLAG_NO_EVICT;
+               bo->placements[i].flags |= TTM_PL_FLAG_NO_EVICT;
        ret = ttm_bo_validate(&bo->bo, &bo->placement, false, false);
        if (ret)
                return ret;
@@ -384,7 +388,7 @@ int mgag200_bo_unpin(struct mgag200_bo *bo)
                return 0;
 
        for (i = 0; i < bo->placement.num_placement ; i++)
-               bo->placements[i] &= ~TTM_PL_FLAG_NO_EVICT;
+               bo->placements[i].flags &= ~TTM_PL_FLAG_NO_EVICT;
        ret = ttm_bo_validate(&bo->bo, &bo->placement, false, false);
        if (ret)
                return ret;
@@ -408,7 +412,7 @@ int mgag200_bo_push_sysram(struct mgag200_bo *bo)
 
        mgag200_ttm_placement(bo, TTM_PL_FLAG_SYSTEM);
        for (i = 0; i < bo->placement.num_placement ; i++)
-               bo->placements[i] |= TTM_PL_FLAG_NO_EVICT;
+               bo->placements[i].flags |= TTM_PL_FLAG_NO_EVICT;
 
        ret = ttm_bo_validate(&bo->bo, &bo->placement, false, false);
        if (ret) {
@@ -424,7 +428,7 @@ int mgag200_mmap(struct file *filp, struct vm_area_struct *vma)
        struct mga_device *mdev;
 
        if (unlikely(vma->vm_pgoff < DRM_FILE_PAGE_OFFSET))
-               return drm_mmap(filp, vma);
+               return -EINVAL;
 
        file_priv = filp->private_data;
        mdev = file_priv->minor->dev->dev_private;
index c99c50de3226d663bea299b722faeb2691581fbe..9d907c526c94d4df4d9a70a527678c2d58a743ff 100644 (file)
@@ -4,6 +4,7 @@ config DRM_MSM
        depends on DRM
        depends on ARCH_QCOM || (ARM && COMPILE_TEST)
        select DRM_KMS_HELPER
+       select DRM_PANEL
        select SHMEM
        select TMPFS
        default y
index 93ca49c8df44b06cfe832bfdf03eeccd5d559bb0..6283dcb96af51f8bd5e70c26a507412f216996f6 100644 (file)
@@ -4,6 +4,7 @@ ifeq (, $(findstring -W,$(EXTRA_CFLAGS)))
 endif
 
 msm-y := \
+       adreno/adreno_device.o \
        adreno/adreno_gpu.o \
        adreno/a3xx_gpu.o \
        hdmi/hdmi.o \
@@ -18,6 +19,8 @@ msm-y := \
        mdp/mdp_kms.o \
        mdp/mdp4/mdp4_crtc.o \
        mdp/mdp4/mdp4_dtv_encoder.o \
+       mdp/mdp4/mdp4_lcdc_encoder.o \
+       mdp/mdp4/mdp4_lvds_connector.o \
        mdp/mdp4/mdp4_irq.o \
        mdp/mdp4/mdp4_kms.o \
        mdp/mdp4/mdp4_plane.o \
@@ -39,5 +42,6 @@ msm-y := \
        msm_ringbuffer.o
 
 msm-$(CONFIG_DRM_MSM_FBDEV) += msm_fbdev.o
+msm-$(CONFIG_COMMON_CLK) += mdp/mdp4/mdp4_lvds_pll.o
 
 obj-$(CONFIG_DRM_MSM)  += msm.o
index a8a144b38eaabe12329f46f5ef9eea258c8f0c4b..a3104598c27f8117b5917ab2bdf7c018ad514383 100644 (file)
@@ -12,9 +12,9 @@ The rules-ng-ng source files this header was generated from are:
 - /home/robclark/src/freedreno/envytools/rnndb/freedreno_copyright.xml  (   1453 bytes, from 2013-03-31 16:51:27)
 - /home/robclark/src/freedreno/envytools/rnndb/adreno/a2xx.xml          (  32901 bytes, from 2014-06-02 15:21:30)
 - /home/robclark/src/freedreno/envytools/rnndb/adreno/adreno_common.xml (   9859 bytes, from 2014-06-02 15:21:30)
-- /home/robclark/src/freedreno/envytools/rnndb/adreno/adreno_pm4.xml    (  14477 bytes, from 2014-05-16 11:51:57)
-- /home/robclark/src/freedreno/envytools/rnndb/adreno/a3xx.xml          (  58020 bytes, from 2014-06-25 12:57:16)
-- /home/robclark/src/freedreno/envytools/rnndb/adreno/a4xx.xml          (  26602 bytes, from 2014-06-25 12:57:16)
+- /home/robclark/src/freedreno/envytools/rnndb/adreno/adreno_pm4.xml    (  14960 bytes, from 2014-07-27 17:22:13)
+- /home/robclark/src/freedreno/envytools/rnndb/adreno/a3xx.xml          (  58020 bytes, from 2014-08-01 12:22:48)
+- /home/robclark/src/freedreno/envytools/rnndb/adreno/a4xx.xml          (  41068 bytes, from 2014-08-01 12:22:48)
 
 Copyright (C) 2013-2014 by the following authors:
 - Rob Clark <robdclark@gmail.com> (robclark)
index 303e8a9e91a595bf5a09075d1865319c8206cada..82d015279b47bf493fc0b5773c2306387d17c7ce 100644 (file)
@@ -12,9 +12,9 @@ The rules-ng-ng source files this header was generated from are:
 - /home/robclark/src/freedreno/envytools/rnndb/freedreno_copyright.xml  (   1453 bytes, from 2013-03-31 16:51:27)
 - /home/robclark/src/freedreno/envytools/rnndb/adreno/a2xx.xml          (  32901 bytes, from 2014-06-02 15:21:30)
 - /home/robclark/src/freedreno/envytools/rnndb/adreno/adreno_common.xml (   9859 bytes, from 2014-06-02 15:21:30)
-- /home/robclark/src/freedreno/envytools/rnndb/adreno/adreno_pm4.xml    (  14477 bytes, from 2014-05-16 11:51:57)
-- /home/robclark/src/freedreno/envytools/rnndb/adreno/a3xx.xml          (  58020 bytes, from 2014-06-25 12:57:16)
-- /home/robclark/src/freedreno/envytools/rnndb/adreno/a4xx.xml          (  26602 bytes, from 2014-06-25 12:57:16)
+- /home/robclark/src/freedreno/envytools/rnndb/adreno/adreno_pm4.xml    (  14960 bytes, from 2014-07-27 17:22:13)
+- /home/robclark/src/freedreno/envytools/rnndb/adreno/a3xx.xml          (  58020 bytes, from 2014-08-01 12:22:48)
+- /home/robclark/src/freedreno/envytools/rnndb/adreno/a4xx.xml          (  41068 bytes, from 2014-08-01 12:22:48)
 
 Copyright (C) 2013-2014 by the following authors:
 - Rob Clark <robdclark@gmail.com> (robclark)
@@ -654,7 +654,7 @@ static inline uint32_t A3XX_GRAS_SU_POINT_SIZE(float val)
 #define A3XX_GRAS_SU_POLY_OFFSET_SCALE_VAL__SHIFT              0
 static inline uint32_t A3XX_GRAS_SU_POLY_OFFSET_SCALE_VAL(float val)
 {
-       return ((((uint32_t)(val * 40.0))) << A3XX_GRAS_SU_POLY_OFFSET_SCALE_VAL__SHIFT) & A3XX_GRAS_SU_POLY_OFFSET_SCALE_VAL__MASK;
+       return ((((uint32_t)(val * 28.0))) << A3XX_GRAS_SU_POLY_OFFSET_SCALE_VAL__SHIFT) & A3XX_GRAS_SU_POLY_OFFSET_SCALE_VAL__MASK;
 }
 
 #define REG_A3XX_GRAS_SU_POLY_OFFSET_OFFSET                    0x0000206d
@@ -662,7 +662,7 @@ static inline uint32_t A3XX_GRAS_SU_POLY_OFFSET_SCALE_VAL(float val)
 #define A3XX_GRAS_SU_POLY_OFFSET_OFFSET__SHIFT                 0
 static inline uint32_t A3XX_GRAS_SU_POLY_OFFSET_OFFSET(float val)
 {
-       return ((((uint32_t)(val * 44.0))) << A3XX_GRAS_SU_POLY_OFFSET_OFFSET__SHIFT) & A3XX_GRAS_SU_POLY_OFFSET_OFFSET__MASK;
+       return ((((uint32_t)(val * 28.0))) << A3XX_GRAS_SU_POLY_OFFSET_OFFSET__SHIFT) & A3XX_GRAS_SU_POLY_OFFSET_OFFSET__MASK;
 }
 
 #define REG_A3XX_GRAS_SU_MODE_CONTROL                          0x00002070
@@ -1696,7 +1696,7 @@ static inline uint32_t A3XX_SP_VS_CTRL_REG1_CONSTFOOTPRINT(uint32_t val)
 {
        return ((val) << A3XX_SP_VS_CTRL_REG1_CONSTFOOTPRINT__SHIFT) & A3XX_SP_VS_CTRL_REG1_CONSTFOOTPRINT__MASK;
 }
-#define A3XX_SP_VS_CTRL_REG1_INITIALOUTSTANDING__MASK          0x3f000000
+#define A3XX_SP_VS_CTRL_REG1_INITIALOUTSTANDING__MASK          0x7f000000
 #define A3XX_SP_VS_CTRL_REG1_INITIALOUTSTANDING__SHIFT         24
 static inline uint32_t A3XX_SP_VS_CTRL_REG1_INITIALOUTSTANDING(uint32_t val)
 {
index 2773600c94888c180c76100dd1848ad395bc596a..218c5b0603989b3474ef7815b91d6ec0371ab013 100644 (file)
         A3XX_INT0_CP_AHB_ERROR_HALT |     \
         A3XX_INT0_UCHE_OOB_ACCESS)
 
+extern bool hang_debug;
 
-static bool hang_debug = false;
-MODULE_PARM_DESC(hang_debug, "Dump registers when hang is detected (can be slow!)");
-module_param_named(hang_debug, hang_debug, bool, 0600);
 static void a3xx_dump(struct msm_gpu *gpu);
 
 static void a3xx_me_init(struct msm_gpu *gpu)
@@ -387,58 +385,26 @@ static const unsigned int a3xx_registers[] = {
        0x2750, 0x2756, 0x2760, 0x2760, 0x300c, 0x300e, 0x301c, 0x301d,
        0x302a, 0x302a, 0x302c, 0x302d, 0x3030, 0x3031, 0x3034, 0x3036,
        0x303c, 0x303c, 0x305e, 0x305f,
+       ~0   /* sentinel */
 };
 
 #ifdef CONFIG_DEBUG_FS
 static void a3xx_show(struct msm_gpu *gpu, struct seq_file *m)
 {
-       int i;
-
-       adreno_show(gpu, m);
-
        gpu->funcs->pm_resume(gpu);
-
        seq_printf(m, "status:   %08x\n",
                        gpu_read(gpu, REG_A3XX_RBBM_STATUS));
-
-       /* dump these out in a form that can be parsed by demsm: */
-       seq_printf(m, "IO:region %s 00000000 00020000\n", gpu->name);
-       for (i = 0; i < ARRAY_SIZE(a3xx_registers); i += 2) {
-               uint32_t start = a3xx_registers[i];
-               uint32_t end   = a3xx_registers[i+1];
-               uint32_t addr;
-
-               for (addr = start; addr <= end; addr++) {
-                       uint32_t val = gpu_read(gpu, addr);
-                       seq_printf(m, "IO:R %08x %08x\n", addr<<2, val);
-               }
-       }
-
        gpu->funcs->pm_suspend(gpu);
+       adreno_show(gpu, m);
 }
 #endif
 
 /* would be nice to not have to duplicate the _show() stuff with printk(): */
 static void a3xx_dump(struct msm_gpu *gpu)
 {
-       int i;
-
-       adreno_dump(gpu);
        printk("status:   %08x\n",
                        gpu_read(gpu, REG_A3XX_RBBM_STATUS));
-
-       /* dump these out in a form that can be parsed by demsm: */
-       printk("IO:region %s 00000000 00020000\n", gpu->name);
-       for (i = 0; i < ARRAY_SIZE(a3xx_registers); i += 2) {
-               uint32_t start = a3xx_registers[i];
-               uint32_t end   = a3xx_registers[i+1];
-               uint32_t addr;
-
-               for (addr = start; addr <= end; addr++) {
-                       uint32_t val = gpu_read(gpu, addr);
-                       printk("IO:R %08x %08x\n", addr<<2, val);
-               }
-       }
+       adreno_dump(gpu);
 }
 
 static const struct adreno_gpu_funcs funcs = {
@@ -474,7 +440,6 @@ struct msm_gpu *a3xx_gpu_init(struct drm_device *dev)
        struct msm_gpu *gpu;
        struct msm_drm_private *priv = dev->dev_private;
        struct platform_device *pdev = priv->gpu_pdev;
-       struct adreno_platform_config *config;
        int ret;
 
        if (!pdev) {
@@ -483,8 +448,6 @@ struct msm_gpu *a3xx_gpu_init(struct drm_device *dev)
                goto fail;
        }
 
-       config = pdev->dev.platform_data;
-
        a3xx_gpu = kzalloc(sizeof(*a3xx_gpu), GFP_KERNEL);
        if (!a3xx_gpu) {
                ret = -ENOMEM;
@@ -496,20 +459,12 @@ struct msm_gpu *a3xx_gpu_init(struct drm_device *dev)
 
        a3xx_gpu->pdev = pdev;
 
-       gpu->fast_rate = config->fast_rate;
-       gpu->slow_rate = config->slow_rate;
-       gpu->bus_freq  = config->bus_freq;
-#ifdef CONFIG_MSM_BUS_SCALING
-       gpu->bus_scale_table = config->bus_scale_table;
-#endif
-
-       DBG("fast_rate=%u, slow_rate=%u, bus_freq=%u",
-                       gpu->fast_rate, gpu->slow_rate, gpu->bus_freq);
-
        gpu->perfcntrs = perfcntrs;
        gpu->num_perfcntrs = ARRAY_SIZE(perfcntrs);
 
-       ret = adreno_gpu_init(dev, pdev, adreno_gpu, &funcs, config->rev);
+       adreno_gpu->registers = a3xx_registers;
+
+       ret = adreno_gpu_init(dev, pdev, adreno_gpu, &funcs);
        if (ret)
                goto fail;
 
@@ -549,158 +504,3 @@ fail:
 
        return ERR_PTR(ret);
 }
-
-/*
- * The a3xx device:
- */
-
-#if defined(CONFIG_MSM_BUS_SCALING) && !defined(CONFIG_OF)
-#  include <mach/kgsl.h>
-#endif
-
-static void set_gpu_pdev(struct drm_device *dev,
-               struct platform_device *pdev)
-{
-       struct msm_drm_private *priv = dev->dev_private;
-       priv->gpu_pdev = pdev;
-}
-
-static int a3xx_bind(struct device *dev, struct device *master, void *data)
-{
-       static struct adreno_platform_config config = {};
-#ifdef CONFIG_OF
-       struct device_node *child, *node = dev->of_node;
-       u32 val;
-       int ret;
-
-       ret = of_property_read_u32(node, "qcom,chipid", &val);
-       if (ret) {
-               dev_err(dev, "could not find chipid: %d\n", ret);
-               return ret;
-       }
-
-       config.rev = ADRENO_REV((val >> 24) & 0xff,
-                       (val >> 16) & 0xff, (val >> 8) & 0xff, val & 0xff);
-
-       /* find clock rates: */
-       config.fast_rate = 0;
-       config.slow_rate = ~0;
-       for_each_child_of_node(node, child) {
-               if (of_device_is_compatible(child, "qcom,gpu-pwrlevels")) {
-                       struct device_node *pwrlvl;
-                       for_each_child_of_node(child, pwrlvl) {
-                               ret = of_property_read_u32(pwrlvl, "qcom,gpu-freq", &val);
-                               if (ret) {
-                                       dev_err(dev, "could not find gpu-freq: %d\n", ret);
-                                       return ret;
-                               }
-                               config.fast_rate = max(config.fast_rate, val);
-                               config.slow_rate = min(config.slow_rate, val);
-                       }
-               }
-       }
-
-       if (!config.fast_rate) {
-               dev_err(dev, "could not find clk rates\n");
-               return -ENXIO;
-       }
-
-#else
-       struct kgsl_device_platform_data *pdata = dev->platform_data;
-       uint32_t version = socinfo_get_version();
-       if (cpu_is_apq8064ab()) {
-               config.fast_rate = 450000000;
-               config.slow_rate = 27000000;
-               config.bus_freq  = 4;
-               config.rev = ADRENO_REV(3, 2, 1, 0);
-       } else if (cpu_is_apq8064()) {
-               config.fast_rate = 400000000;
-               config.slow_rate = 27000000;
-               config.bus_freq  = 4;
-
-               if (SOCINFO_VERSION_MAJOR(version) == 2)
-                       config.rev = ADRENO_REV(3, 2, 0, 2);
-               else if ((SOCINFO_VERSION_MAJOR(version) == 1) &&
-                               (SOCINFO_VERSION_MINOR(version) == 1))
-                       config.rev = ADRENO_REV(3, 2, 0, 1);
-               else
-                       config.rev = ADRENO_REV(3, 2, 0, 0);
-
-       } else if (cpu_is_msm8960ab()) {
-               config.fast_rate = 400000000;
-               config.slow_rate = 320000000;
-               config.bus_freq  = 4;
-
-               if (SOCINFO_VERSION_MINOR(version) == 0)
-                       config.rev = ADRENO_REV(3, 2, 1, 0);
-               else
-                       config.rev = ADRENO_REV(3, 2, 1, 1);
-
-       } else if (cpu_is_msm8930()) {
-               config.fast_rate = 400000000;
-               config.slow_rate = 27000000;
-               config.bus_freq  = 3;
-
-               if ((SOCINFO_VERSION_MAJOR(version) == 1) &&
-                       (SOCINFO_VERSION_MINOR(version) == 2))
-                       config.rev = ADRENO_REV(3, 0, 5, 2);
-               else
-                       config.rev = ADRENO_REV(3, 0, 5, 0);
-
-       }
-#  ifdef CONFIG_MSM_BUS_SCALING
-       config.bus_scale_table = pdata->bus_scale_table;
-#  endif
-#endif
-       dev->platform_data = &config;
-       set_gpu_pdev(dev_get_drvdata(master), to_platform_device(dev));
-       return 0;
-}
-
-static void a3xx_unbind(struct device *dev, struct device *master,
-               void *data)
-{
-       set_gpu_pdev(dev_get_drvdata(master), NULL);
-}
-
-static const struct component_ops a3xx_ops = {
-               .bind   = a3xx_bind,
-               .unbind = a3xx_unbind,
-};
-
-static int a3xx_probe(struct platform_device *pdev)
-{
-       return component_add(&pdev->dev, &a3xx_ops);
-}
-
-static int a3xx_remove(struct platform_device *pdev)
-{
-       component_del(&pdev->dev, &a3xx_ops);
-       return 0;
-}
-
-static const struct of_device_id dt_match[] = {
-       { .compatible = "qcom,adreno-3xx" },
-       /* for backwards compat w/ downstream kgsl DT files: */
-       { .compatible = "qcom,kgsl-3d0" },
-       {}
-};
-
-static struct platform_driver a3xx_driver = {
-       .probe = a3xx_probe,
-       .remove = a3xx_remove,
-       .driver = {
-               .name = "kgsl-3d0",
-               .of_match_table = dt_match,
-       },
-};
-
-void __init a3xx_register(void)
-{
-       platform_driver_register(&a3xx_driver);
-}
-
-void __exit a3xx_unregister(void)
-{
-       platform_driver_unregister(&a3xx_driver);
-}
index 9de19ac2e86c7d7e310a4f5e55df37cdcb1d26a3..cc341bc62b51f8ff860f85e11663c6d6d2f2ff81 100644 (file)
@@ -12,9 +12,9 @@ The rules-ng-ng source files this header was generated from are:
 - /home/robclark/src/freedreno/envytools/rnndb/freedreno_copyright.xml  (   1453 bytes, from 2013-03-31 16:51:27)
 - /home/robclark/src/freedreno/envytools/rnndb/adreno/a2xx.xml          (  32901 bytes, from 2014-06-02 15:21:30)
 - /home/robclark/src/freedreno/envytools/rnndb/adreno/adreno_common.xml (   9859 bytes, from 2014-06-02 15:21:30)
-- /home/robclark/src/freedreno/envytools/rnndb/adreno/adreno_pm4.xml    (  14477 bytes, from 2014-05-16 11:51:57)
-- /home/robclark/src/freedreno/envytools/rnndb/adreno/a3xx.xml          (  58020 bytes, from 2014-06-25 12:57:16)
-- /home/robclark/src/freedreno/envytools/rnndb/adreno/a4xx.xml          (  26602 bytes, from 2014-06-25 12:57:16)
+- /home/robclark/src/freedreno/envytools/rnndb/adreno/adreno_pm4.xml    (  14960 bytes, from 2014-07-27 17:22:13)
+- /home/robclark/src/freedreno/envytools/rnndb/adreno/a3xx.xml          (  58020 bytes, from 2014-08-01 12:22:48)
+- /home/robclark/src/freedreno/envytools/rnndb/adreno/a4xx.xml          (  41068 bytes, from 2014-08-01 12:22:48)
 
 Copyright (C) 2013-2014 by the following authors:
 - Rob Clark <robdclark@gmail.com> (robclark)
diff --git a/drivers/gpu/drm/msm/adreno/adreno_device.c b/drivers/gpu/drm/msm/adreno/adreno_device.c
new file mode 100644 (file)
index 0000000..7ab85af
--- /dev/null
@@ -0,0 +1,285 @@
+/*
+ * Copyright (C) 2013-2014 Red Hat
+ * Author: Rob Clark <robdclark@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.
+ *
+ * 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 "adreno_gpu.h"
+
+#if defined(CONFIG_MSM_BUS_SCALING) && !defined(CONFIG_OF)
+#  include <mach/kgsl.h>
+#endif
+
+#define ANY_ID 0xff
+
+bool hang_debug = false;
+MODULE_PARM_DESC(hang_debug, "Dump registers when hang is detected (can be slow!)");
+module_param_named(hang_debug, hang_debug, bool, 0600);
+
+struct msm_gpu *a3xx_gpu_init(struct drm_device *dev);
+
+static const struct adreno_info gpulist[] = {
+       {
+               .rev   = ADRENO_REV(3, 0, 5, ANY_ID),
+               .revn  = 305,
+               .name  = "A305",
+               .pm4fw = "a300_pm4.fw",
+               .pfpfw = "a300_pfp.fw",
+               .gmem  = SZ_256K,
+               .init  = a3xx_gpu_init,
+       }, {
+               .rev   = ADRENO_REV(3, 2, ANY_ID, ANY_ID),
+               .revn  = 320,
+               .name  = "A320",
+               .pm4fw = "a300_pm4.fw",
+               .pfpfw = "a300_pfp.fw",
+               .gmem  = SZ_512K,
+               .init  = a3xx_gpu_init,
+       }, {
+               .rev   = ADRENO_REV(3, 3, 0, ANY_ID),
+               .revn  = 330,
+               .name  = "A330",
+               .pm4fw = "a330_pm4.fw",
+               .pfpfw = "a330_pfp.fw",
+               .gmem  = SZ_1M,
+               .init  = a3xx_gpu_init,
+       },
+};
+
+MODULE_FIRMWARE("a300_pm4.fw");
+MODULE_FIRMWARE("a300_pfp.fw");
+MODULE_FIRMWARE("a330_pm4.fw");
+MODULE_FIRMWARE("a330_pfp.fw");
+
+static inline bool _rev_match(uint8_t entry, uint8_t id)
+{
+       return (entry == ANY_ID) || (entry == id);
+}
+
+const struct adreno_info *adreno_info(struct adreno_rev rev)
+{
+       int i;
+
+       /* identify gpu: */
+       for (i = 0; i < ARRAY_SIZE(gpulist); i++) {
+               const struct adreno_info *info = &gpulist[i];
+               if (_rev_match(info->rev.core, rev.core) &&
+                               _rev_match(info->rev.major, rev.major) &&
+                               _rev_match(info->rev.minor, rev.minor) &&
+                               _rev_match(info->rev.patchid, rev.patchid))
+                       return info;
+       }
+
+       return NULL;
+}
+
+struct msm_gpu *adreno_load_gpu(struct drm_device *dev)
+{
+       struct msm_drm_private *priv = dev->dev_private;
+       struct platform_device *pdev = priv->gpu_pdev;
+       struct adreno_platform_config *config;
+       struct adreno_rev rev;
+       const struct adreno_info *info;
+       struct msm_gpu *gpu = NULL;
+
+       if (!pdev) {
+               dev_err(dev->dev, "no adreno device\n");
+               return NULL;
+       }
+
+       config = pdev->dev.platform_data;
+       rev = config->rev;
+       info = adreno_info(config->rev);
+
+       if (!info) {
+               dev_warn(dev->dev, "Unknown GPU revision: %u.%u.%u.%u\n",
+                               rev.core, rev.major, rev.minor, rev.patchid);
+               return NULL;
+       }
+
+       DBG("Found GPU: %u.%u.%u.%u",  rev.core, rev.major,
+                       rev.minor, rev.patchid);
+
+       gpu = info->init(dev);
+       if (IS_ERR(gpu)) {
+               dev_warn(dev->dev, "failed to load adreno gpu\n");
+               gpu = NULL;
+               /* not fatal */
+       }
+
+       if (gpu) {
+               int ret;
+               mutex_lock(&dev->struct_mutex);
+               gpu->funcs->pm_resume(gpu);
+               mutex_unlock(&dev->struct_mutex);
+               ret = gpu->funcs->hw_init(gpu);
+               if (ret) {
+                       dev_err(dev->dev, "gpu hw init failed: %d\n", ret);
+                       gpu->funcs->destroy(gpu);
+                       gpu = NULL;
+               } else {
+                       /* give inactive pm a chance to kick in: */
+                       msm_gpu_retire(gpu);
+               }
+       }
+
+       return gpu;
+}
+
+static void set_gpu_pdev(struct drm_device *dev,
+               struct platform_device *pdev)
+{
+       struct msm_drm_private *priv = dev->dev_private;
+       priv->gpu_pdev = pdev;
+}
+
+static int adreno_bind(struct device *dev, struct device *master, void *data)
+{
+       static struct adreno_platform_config config = {};
+#ifdef CONFIG_OF
+       struct device_node *child, *node = dev->of_node;
+       u32 val;
+       int ret;
+
+       ret = of_property_read_u32(node, "qcom,chipid", &val);
+       if (ret) {
+               dev_err(dev, "could not find chipid: %d\n", ret);
+               return ret;
+       }
+
+       config.rev = ADRENO_REV((val >> 24) & 0xff,
+                       (val >> 16) & 0xff, (val >> 8) & 0xff, val & 0xff);
+
+       /* find clock rates: */
+       config.fast_rate = 0;
+       config.slow_rate = ~0;
+       for_each_child_of_node(node, child) {
+               if (of_device_is_compatible(child, "qcom,gpu-pwrlevels")) {
+                       struct device_node *pwrlvl;
+                       for_each_child_of_node(child, pwrlvl) {
+                               ret = of_property_read_u32(pwrlvl, "qcom,gpu-freq", &val);
+                               if (ret) {
+                                       dev_err(dev, "could not find gpu-freq: %d\n", ret);
+                                       return ret;
+                               }
+                               config.fast_rate = max(config.fast_rate, val);
+                               config.slow_rate = min(config.slow_rate, val);
+                       }
+               }
+       }
+
+       if (!config.fast_rate) {
+               dev_err(dev, "could not find clk rates\n");
+               return -ENXIO;
+       }
+
+#else
+       struct kgsl_device_platform_data *pdata = dev->platform_data;
+       uint32_t version = socinfo_get_version();
+       if (cpu_is_apq8064ab()) {
+               config.fast_rate = 450000000;
+               config.slow_rate = 27000000;
+               config.bus_freq  = 4;
+               config.rev = ADRENO_REV(3, 2, 1, 0);
+       } else if (cpu_is_apq8064()) {
+               config.fast_rate = 400000000;
+               config.slow_rate = 27000000;
+               config.bus_freq  = 4;
+
+               if (SOCINFO_VERSION_MAJOR(version) == 2)
+                       config.rev = ADRENO_REV(3, 2, 0, 2);
+               else if ((SOCINFO_VERSION_MAJOR(version) == 1) &&
+                               (SOCINFO_VERSION_MINOR(version) == 1))
+                       config.rev = ADRENO_REV(3, 2, 0, 1);
+               else
+                       config.rev = ADRENO_REV(3, 2, 0, 0);
+
+       } else if (cpu_is_msm8960ab()) {
+               config.fast_rate = 400000000;
+               config.slow_rate = 320000000;
+               config.bus_freq  = 4;
+
+               if (SOCINFO_VERSION_MINOR(version) == 0)
+                       config.rev = ADRENO_REV(3, 2, 1, 0);
+               else
+                       config.rev = ADRENO_REV(3, 2, 1, 1);
+
+       } else if (cpu_is_msm8930()) {
+               config.fast_rate = 400000000;
+               config.slow_rate = 27000000;
+               config.bus_freq  = 3;
+
+               if ((SOCINFO_VERSION_MAJOR(version) == 1) &&
+                       (SOCINFO_VERSION_MINOR(version) == 2))
+                       config.rev = ADRENO_REV(3, 0, 5, 2);
+               else
+                       config.rev = ADRENO_REV(3, 0, 5, 0);
+
+       }
+#  ifdef CONFIG_MSM_BUS_SCALING
+       config.bus_scale_table = pdata->bus_scale_table;
+#  endif
+#endif
+       dev->platform_data = &config;
+       set_gpu_pdev(dev_get_drvdata(master), to_platform_device(dev));
+       return 0;
+}
+
+static void adreno_unbind(struct device *dev, struct device *master,
+               void *data)
+{
+       set_gpu_pdev(dev_get_drvdata(master), NULL);
+}
+
+static const struct component_ops a3xx_ops = {
+               .bind   = adreno_bind,
+               .unbind = adreno_unbind,
+};
+
+static int adreno_probe(struct platform_device *pdev)
+{
+       return component_add(&pdev->dev, &a3xx_ops);
+}
+
+static int adreno_remove(struct platform_device *pdev)
+{
+       component_del(&pdev->dev, &a3xx_ops);
+       return 0;
+}
+
+static const struct of_device_id dt_match[] = {
+       { .compatible = "qcom,adreno-3xx" },
+       /* for backwards compat w/ downstream kgsl DT files: */
+       { .compatible = "qcom,kgsl-3d0" },
+       {}
+};
+
+static struct platform_driver adreno_driver = {
+       .probe = adreno_probe,
+       .remove = adreno_remove,
+       .driver = {
+               .name = "adreno",
+               .of_match_table = dt_match,
+       },
+};
+
+void __init adreno_register(void)
+{
+       platform_driver_register(&adreno_driver);
+}
+
+void __exit adreno_unregister(void)
+{
+       platform_driver_unregister(&adreno_driver);
+}
index 655ce5b14ad04564a5fb73e72e26b338bb3fb4e3..6afa29167fee74fffaae26e8d7ded15d05ec87eb 100644 (file)
 #include "msm_gem.h"
 #include "msm_mmu.h"
 
-struct adreno_info {
-       struct adreno_rev rev;
-       uint32_t revn;
-       const char *name;
-       const char *pm4fw, *pfpfw;
-       uint32_t gmem;
-};
-
-#define ANY_ID 0xff
-
-static const struct adreno_info gpulist[] = {
-       {
-               .rev   = ADRENO_REV(3, 0, 5, ANY_ID),
-               .revn  = 305,
-               .name  = "A305",
-               .pm4fw = "a300_pm4.fw",
-               .pfpfw = "a300_pfp.fw",
-               .gmem  = SZ_256K,
-       }, {
-               .rev   = ADRENO_REV(3, 2, ANY_ID, ANY_ID),
-               .revn  = 320,
-               .name  = "A320",
-               .pm4fw = "a300_pm4.fw",
-               .pfpfw = "a300_pfp.fw",
-               .gmem  = SZ_512K,
-       }, {
-               .rev   = ADRENO_REV(3, 3, 0, ANY_ID),
-               .revn  = 330,
-               .name  = "A330",
-               .pm4fw = "a330_pm4.fw",
-               .pfpfw = "a330_pfp.fw",
-               .gmem  = SZ_1M,
-       },
-};
-
-MODULE_FIRMWARE("a300_pm4.fw");
-MODULE_FIRMWARE("a300_pfp.fw");
-MODULE_FIRMWARE("a330_pm4.fw");
-MODULE_FIRMWARE("a330_pfp.fw");
-
 #define RB_SIZE    SZ_32K
 #define RB_BLKSIZE 16
 
@@ -252,6 +212,7 @@ void adreno_idle(struct msm_gpu *gpu)
 void adreno_show(struct msm_gpu *gpu, struct seq_file *m)
 {
        struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu);
+       int i;
 
        seq_printf(m, "revision: %d (%d.%d.%d.%d)\n",
                        adreno_gpu->info->revn, adreno_gpu->rev.core,
@@ -263,6 +224,23 @@ void adreno_show(struct msm_gpu *gpu, struct seq_file *m)
        seq_printf(m, "rptr:     %d\n", adreno_gpu->memptrs->rptr);
        seq_printf(m, "wptr:     %d\n", adreno_gpu->memptrs->wptr);
        seq_printf(m, "rb wptr:  %d\n", get_wptr(gpu->rb));
+
+       gpu->funcs->pm_resume(gpu);
+
+       /* dump these out in a form that can be parsed by demsm: */
+       seq_printf(m, "IO:region %s 00000000 00020000\n", gpu->name);
+       for (i = 0; adreno_gpu->registers[i] != ~0; i += 2) {
+               uint32_t start = adreno_gpu->registers[i];
+               uint32_t end   = adreno_gpu->registers[i+1];
+               uint32_t addr;
+
+               for (addr = start; addr <= end; addr++) {
+                       uint32_t val = gpu_read(gpu, addr);
+                       seq_printf(m, "IO:R %08x %08x\n", addr<<2, val);
+               }
+       }
+
+       gpu->funcs->pm_suspend(gpu);
 }
 #endif
 
@@ -270,6 +248,7 @@ void adreno_show(struct msm_gpu *gpu, struct seq_file *m)
 void adreno_dump(struct msm_gpu *gpu)
 {
        struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu);
+       int i;
 
        printk("revision: %d (%d.%d.%d.%d)\n",
                        adreno_gpu->info->revn, adreno_gpu->rev.core,
@@ -282,6 +261,18 @@ void adreno_dump(struct msm_gpu *gpu)
        printk("wptr:     %d\n", adreno_gpu->memptrs->wptr);
        printk("rb wptr:  %d\n", get_wptr(gpu->rb));
 
+       /* dump these out in a form that can be parsed by demsm: */
+       printk("IO:region %s 00000000 00020000\n", gpu->name);
+       for (i = 0; adreno_gpu->registers[i] != ~0; i += 2) {
+               uint32_t start = adreno_gpu->registers[i];
+               uint32_t end   = adreno_gpu->registers[i+1];
+               uint32_t addr;
+
+               for (addr = start; addr <= end; addr++) {
+                       uint32_t val = gpu_read(gpu, addr);
+                       printk("IO:R %08x %08x\n", addr<<2, val);
+               }
+       }
 }
 
 static uint32_t ring_freewords(struct msm_gpu *gpu)
@@ -304,65 +295,51 @@ static const char *iommu_ports[] = {
                "gfx3d1_user", "gfx3d1_priv",
 };
 
-static inline bool _rev_match(uint8_t entry, uint8_t id)
-{
-       return (entry == ANY_ID) || (entry == id);
-}
-
 int adreno_gpu_init(struct drm_device *drm, struct platform_device *pdev,
-               struct adreno_gpu *gpu, const struct adreno_gpu_funcs *funcs,
-               struct adreno_rev rev)
+               struct adreno_gpu *adreno_gpu, const struct adreno_gpu_funcs *funcs)
 {
+       struct adreno_platform_config *config = pdev->dev.platform_data;
+       struct msm_gpu *gpu = &adreno_gpu->base;
        struct msm_mmu *mmu;
-       int i, ret;
-
-       /* identify gpu: */
-       for (i = 0; i < ARRAY_SIZE(gpulist); i++) {
-               const struct adreno_info *info = &gpulist[i];
-               if (_rev_match(info->rev.core, rev.core) &&
-                               _rev_match(info->rev.major, rev.major) &&
-                               _rev_match(info->rev.minor, rev.minor) &&
-                               _rev_match(info->rev.patchid, rev.patchid)) {
-                       gpu->info = info;
-                       gpu->revn = info->revn;
-                       break;
-               }
-       }
-
-       if (i == ARRAY_SIZE(gpulist)) {
-               dev_err(drm->dev, "Unknown GPU revision: %u.%u.%u.%u\n",
-                               rev.core, rev.major, rev.minor, rev.patchid);
-               return -ENXIO;
-       }
+       int ret;
 
-       DBG("Found GPU: %s (%u.%u.%u.%u)", gpu->info->name,
-                       rev.core, rev.major, rev.minor, rev.patchid);
+       adreno_gpu->funcs = funcs;
+       adreno_gpu->info = adreno_info(config->rev);
+       adreno_gpu->gmem = adreno_gpu->info->gmem;
+       adreno_gpu->revn = adreno_gpu->info->revn;
+       adreno_gpu->rev = config->rev;
+
+       gpu->fast_rate = config->fast_rate;
+       gpu->slow_rate = config->slow_rate;
+       gpu->bus_freq  = config->bus_freq;
+#ifdef CONFIG_MSM_BUS_SCALING
+       gpu->bus_scale_table = config->bus_scale_table;
+#endif
 
-       gpu->funcs = funcs;
-       gpu->gmem = gpu->info->gmem;
-       gpu->rev = rev;
+       DBG("fast_rate=%u, slow_rate=%u, bus_freq=%u",
+                       gpu->fast_rate, gpu->slow_rate, gpu->bus_freq);
 
-       ret = request_firmware(&gpu->pm4, gpu->info->pm4fw, drm->dev);
+       ret = request_firmware(&adreno_gpu->pm4, adreno_gpu->info->pm4fw, drm->dev);
        if (ret) {
                dev_err(drm->dev, "failed to load %s PM4 firmware: %d\n",
-                               gpu->info->pm4fw, ret);
+                               adreno_gpu->info->pm4fw, ret);
                return ret;
        }
 
-       ret = request_firmware(&gpu->pfp, gpu->info->pfpfw, drm->dev);
+       ret = request_firmware(&adreno_gpu->pfp, adreno_gpu->info->pfpfw, drm->dev);
        if (ret) {
                dev_err(drm->dev, "failed to load %s PFP firmware: %d\n",
-                               gpu->info->pfpfw, ret);
+                               adreno_gpu->info->pfpfw, ret);
                return ret;
        }
 
-       ret = msm_gpu_init(drm, pdev, &gpu->base, &funcs->base,
-                       gpu->info->name, "kgsl_3d0_reg_memory", "kgsl_3d0_irq",
+       ret = msm_gpu_init(drm, pdev, &adreno_gpu->base, &funcs->base,
+                       adreno_gpu->info->name, "kgsl_3d0_reg_memory", "kgsl_3d0_irq",
                        RB_SIZE);
        if (ret)
                return ret;
 
-       mmu = gpu->base.mmu;
+       mmu = gpu->mmu;
        if (mmu) {
                ret = mmu->funcs->attach(mmu, iommu_ports,
                                ARRAY_SIZE(iommu_ports));
@@ -371,24 +348,24 @@ int adreno_gpu_init(struct drm_device *drm, struct platform_device *pdev,
        }
 
        mutex_lock(&drm->struct_mutex);
-       gpu->memptrs_bo = msm_gem_new(drm, sizeof(*gpu->memptrs),
+       adreno_gpu->memptrs_bo = msm_gem_new(drm, sizeof(*adreno_gpu->memptrs),
                        MSM_BO_UNCACHED);
        mutex_unlock(&drm->struct_mutex);
-       if (IS_ERR(gpu->memptrs_bo)) {
-               ret = PTR_ERR(gpu->memptrs_bo);
-               gpu->memptrs_bo = NULL;
+       if (IS_ERR(adreno_gpu->memptrs_bo)) {
+               ret = PTR_ERR(adreno_gpu->memptrs_bo);
+               adreno_gpu->memptrs_bo = NULL;
                dev_err(drm->dev, "could not allocate memptrs: %d\n", ret);
                return ret;
        }
 
-       gpu->memptrs = msm_gem_vaddr(gpu->memptrs_bo);
-       if (!gpu->memptrs) {
+       adreno_gpu->memptrs = msm_gem_vaddr(adreno_gpu->memptrs_bo);
+       if (!adreno_gpu->memptrs) {
                dev_err(drm->dev, "could not vmap memptrs\n");
                return -ENOMEM;
        }
 
-       ret = msm_gem_get_iova(gpu->memptrs_bo, gpu->base.id,
-                       &gpu->memptrs_iova);
+       ret = msm_gem_get_iova(adreno_gpu->memptrs_bo, gpu->id,
+                       &adreno_gpu->memptrs_iova);
        if (ret) {
                dev_err(drm->dev, "could not map memptrs: %d\n", ret);
                return ret;
index 63c36ce330203669b597ff6a6e606a6066ee3832..52f0515797532cef0d4496918fe421306946d0a5 100644 (file)
@@ -39,7 +39,16 @@ struct adreno_gpu_funcs {
        struct msm_gpu_funcs base;
 };
 
-struct adreno_info;
+struct adreno_info {
+       struct adreno_rev rev;
+       uint32_t revn;
+       const char *name;
+       const char *pm4fw, *pfpfw;
+       uint32_t gmem;
+       struct msm_gpu *(*init)(struct drm_device *dev);
+};
+
+const struct adreno_info *adreno_info(struct adreno_rev rev);
 
 struct adreno_rbmemptrs {
        volatile uint32_t rptr;
@@ -55,6 +64,9 @@ struct adreno_gpu {
        uint32_t revn;  /* numeric revision name */
        const struct adreno_gpu_funcs *funcs;
 
+       /* interesting register offsets to dump: */
+       const unsigned int *registers;
+
        /* firmware: */
        const struct firmware *pm4, *pfp;
 
@@ -131,8 +143,7 @@ void adreno_dump(struct msm_gpu *gpu);
 void adreno_wait_ring(struct msm_gpu *gpu, uint32_t ndwords);
 
 int adreno_gpu_init(struct drm_device *drm, struct platform_device *pdev,
-               struct adreno_gpu *gpu, const struct adreno_gpu_funcs *funcs,
-               struct adreno_rev rev);
+               struct adreno_gpu *gpu, const struct adreno_gpu_funcs *funcs);
 void adreno_gpu_cleanup(struct adreno_gpu *gpu);
 
 
index 4eee0ec8f069108a32a94f239db78f2fda50cd9b..6ef43f66c30a37676b9231d8f9b202b5f50c49f3 100644 (file)
@@ -12,9 +12,9 @@ The rules-ng-ng source files this header was generated from are:
 - /home/robclark/src/freedreno/envytools/rnndb/freedreno_copyright.xml  (   1453 bytes, from 2013-03-31 16:51:27)
 - /home/robclark/src/freedreno/envytools/rnndb/adreno/a2xx.xml          (  32901 bytes, from 2014-06-02 15:21:30)
 - /home/robclark/src/freedreno/envytools/rnndb/adreno/adreno_common.xml (   9859 bytes, from 2014-06-02 15:21:30)
-- /home/robclark/src/freedreno/envytools/rnndb/adreno/adreno_pm4.xml    (  14477 bytes, from 2014-05-16 11:51:57)
-- /home/robclark/src/freedreno/envytools/rnndb/adreno/a3xx.xml          (  58020 bytes, from 2014-06-25 12:57:16)
-- /home/robclark/src/freedreno/envytools/rnndb/adreno/a4xx.xml          (  26602 bytes, from 2014-06-25 12:57:16)
+- /home/robclark/src/freedreno/envytools/rnndb/adreno/adreno_pm4.xml    (  14960 bytes, from 2014-07-27 17:22:13)
+- /home/robclark/src/freedreno/envytools/rnndb/adreno/a3xx.xml          (  58020 bytes, from 2014-08-01 12:22:48)
+- /home/robclark/src/freedreno/envytools/rnndb/adreno/a4xx.xml          (  41068 bytes, from 2014-08-01 12:22:48)
 
 Copyright (C) 2013-2014 by the following authors:
 - Rob Clark <robdclark@gmail.com> (robclark)
@@ -163,12 +163,16 @@ enum adreno_pm4_type3_packets {
        CP_INDIRECT_BUFFER_PFE = 63,
        CP_SET_BIN = 76,
        CP_TEST_TWO_MEMS = 113,
+       CP_REG_WR_NO_CTXT = 120,
+       CP_RECORD_PFP_TIMESTAMP = 17,
        CP_WAIT_FOR_ME = 19,
        CP_SET_DRAW_STATE = 67,
        CP_DRAW_INDX_OFFSET = 56,
        CP_DRAW_INDIRECT = 40,
        CP_DRAW_INDX_INDIRECT = 41,
        CP_DRAW_AUTO = 36,
+       CP_UNKNOWN_1A = 26,
+       CP_WIDE_REG_WRITE = 116,
        IN_IB_PREFETCH_END = 23,
        IN_SUBBLK_PREFETCH = 31,
        IN_INSTR_PREFETCH = 32,
index 0f1f5b9459a51de71dad5b75fbcede35762432f5..e965898dfda6cbc2b09876fe3a9f8b68582d8fc5 100644 (file)
@@ -10,14 +10,14 @@ git clone https://github.com/freedreno/envytools.git
 The rules-ng-ng source files this header was generated from are:
 - /home/robclark/src/freedreno/envytools/rnndb/msm.xml                 (    647 bytes, from 2013-11-30 14:45:35)
 - /home/robclark/src/freedreno/envytools/rnndb/freedreno_copyright.xml (   1453 bytes, from 2013-03-31 16:51:27)
-- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp4.xml            (  17996 bytes, from 2013-12-01 19:10:31)
-- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp_common.xml      (   1615 bytes, from 2013-11-30 15:00:52)
-- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp5.xml            (  22517 bytes, from 2014-06-25 12:55:02)
+- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp4.xml            (  20457 bytes, from 2014-08-01 12:22:48)
+- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp_common.xml      (   1615 bytes, from 2014-07-17 15:34:33)
+- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp5.xml            (  22517 bytes, from 2014-07-17 15:34:33)
 - /home/robclark/src/freedreno/envytools/rnndb/dsi/dsi.xml             (  11712 bytes, from 2013-08-17 17:13:43)
 - /home/robclark/src/freedreno/envytools/rnndb/dsi/sfpb.xml            (    344 bytes, from 2013-08-11 19:26:32)
-- /home/robclark/src/freedreno/envytools/rnndb/dsi/mmss_cc.xml         (   1544 bytes, from 2013-08-16 19:17:05)
+- /home/robclark/src/freedreno/envytools/rnndb/dsi/mmss_cc.xml         (   1686 bytes, from 2014-08-01 12:23:53)
 - /home/robclark/src/freedreno/envytools/rnndb/hdmi/qfprom.xml         (    600 bytes, from 2013-07-05 19:21:12)
-- /home/robclark/src/freedreno/envytools/rnndb/hdmi/hdmi.xml           (  23613 bytes, from 2014-06-25 12:53:44)
+- /home/robclark/src/freedreno/envytools/rnndb/hdmi/hdmi.xml           (  23613 bytes, from 2014-07-17 15:33:30)
 
 Copyright (C) 2013 by the following authors:
 - Rob Clark <robdclark@gmail.com> (robclark)
index d468f86f637cece324dc46299bbe19022cbb484f..f2bdda957205a092b4d4a0bd6f02cfcd0d32fdb6 100644 (file)
@@ -10,16 +10,16 @@ git clone https://github.com/freedreno/envytools.git
 The rules-ng-ng source files this header was generated from are:
 - /home/robclark/src/freedreno/envytools/rnndb/msm.xml                 (    647 bytes, from 2013-11-30 14:45:35)
 - /home/robclark/src/freedreno/envytools/rnndb/freedreno_copyright.xml (   1453 bytes, from 2013-03-31 16:51:27)
-- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp4.xml            (  17996 bytes, from 2013-12-01 19:10:31)
-- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp_common.xml      (   1615 bytes, from 2013-11-30 15:00:52)
-- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp5.xml            (  22517 bytes, from 2014-06-25 12:55:02)
+- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp4.xml            (  20457 bytes, from 2014-08-01 12:22:48)
+- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp_common.xml      (   1615 bytes, from 2014-07-17 15:34:33)
+- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp5.xml            (  22517 bytes, from 2014-07-17 15:34:33)
 - /home/robclark/src/freedreno/envytools/rnndb/dsi/dsi.xml             (  11712 bytes, from 2013-08-17 17:13:43)
 - /home/robclark/src/freedreno/envytools/rnndb/dsi/sfpb.xml            (    344 bytes, from 2013-08-11 19:26:32)
-- /home/robclark/src/freedreno/envytools/rnndb/dsi/mmss_cc.xml         (   1544 bytes, from 2013-08-16 19:17:05)
+- /home/robclark/src/freedreno/envytools/rnndb/dsi/mmss_cc.xml         (   1686 bytes, from 2014-08-01 12:23:53)
 - /home/robclark/src/freedreno/envytools/rnndb/hdmi/qfprom.xml         (    600 bytes, from 2013-07-05 19:21:12)
-- /home/robclark/src/freedreno/envytools/rnndb/hdmi/hdmi.xml           (  23613 bytes, from 2014-06-25 12:53:44)
+- /home/robclark/src/freedreno/envytools/rnndb/hdmi/hdmi.xml           (  23613 bytes, from 2014-07-17 15:33:30)
 
-Copyright (C) 2013 by the following authors:
+Copyright (C) 2013-2014 by the following authors:
 - Rob Clark <robdclark@gmail.com> (robclark)
 
 Permission is hereby granted, free of charge, to any person obtaining
@@ -112,5 +112,11 @@ static inline uint32_t MMSS_CC_CLK_NS_VAL(uint32_t val)
        return ((val) << MMSS_CC_CLK_NS_VAL__SHIFT) & MMSS_CC_CLK_NS_VAL__MASK;
 }
 
+#define REG_MMSS_CC_DSI2_PIXEL_CC                              0x00000094
+
+#define REG_MMSS_CC_DSI2_PIXEL_NS                              0x000000e4
+
+#define REG_MMSS_CC_DSI2_PIXEL_CC2                             0x00000264
+
 
 #endif /* MMSS_CC_XML */
index da8740054cdf264bef41396db1e8ca09964bf6bc..e5b071ffd8657761d78f8499f86eb5c4e825144b 100644 (file)
@@ -10,14 +10,14 @@ git clone https://github.com/freedreno/envytools.git
 The rules-ng-ng source files this header was generated from are:
 - /home/robclark/src/freedreno/envytools/rnndb/msm.xml                 (    647 bytes, from 2013-11-30 14:45:35)
 - /home/robclark/src/freedreno/envytools/rnndb/freedreno_copyright.xml (   1453 bytes, from 2013-03-31 16:51:27)
-- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp4.xml            (  17996 bytes, from 2013-12-01 19:10:31)
-- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp_common.xml      (   1615 bytes, from 2013-11-30 15:00:52)
-- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp5.xml            (  22517 bytes, from 2014-06-25 12:55:02)
+- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp4.xml            (  20457 bytes, from 2014-08-01 12:22:48)
+- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp_common.xml      (   1615 bytes, from 2014-07-17 15:34:33)
+- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp5.xml            (  22517 bytes, from 2014-07-17 15:34:33)
 - /home/robclark/src/freedreno/envytools/rnndb/dsi/dsi.xml             (  11712 bytes, from 2013-08-17 17:13:43)
 - /home/robclark/src/freedreno/envytools/rnndb/dsi/sfpb.xml            (    344 bytes, from 2013-08-11 19:26:32)
-- /home/robclark/src/freedreno/envytools/rnndb/dsi/mmss_cc.xml         (   1544 bytes, from 2013-08-16 19:17:05)
+- /home/robclark/src/freedreno/envytools/rnndb/dsi/mmss_cc.xml         (   1686 bytes, from 2014-08-01 12:23:53)
 - /home/robclark/src/freedreno/envytools/rnndb/hdmi/qfprom.xml         (    600 bytes, from 2013-07-05 19:21:12)
-- /home/robclark/src/freedreno/envytools/rnndb/hdmi/hdmi.xml           (  23613 bytes, from 2014-06-25 12:53:44)
+- /home/robclark/src/freedreno/envytools/rnndb/hdmi/hdmi.xml           (  23613 bytes, from 2014-07-17 15:33:30)
 
 Copyright (C) 2013 by the following authors:
 - Rob Clark <robdclark@gmail.com> (robclark)
index c6c9b02e0ada9f052249a556a9e2169aa967b91d..9d00dcba695950873c77baa761dea89e4b86aeac 100644 (file)
@@ -123,7 +123,7 @@ struct hdmi *hdmi_init(struct drm_device *dev, struct drm_encoder *encoder)
        for (i = 0; i < config->hpd_reg_cnt; i++) {
                struct regulator *reg;
 
-               reg = devm_regulator_get_exclusive(&pdev->dev,
+               reg = devm_regulator_get(&pdev->dev,
                                config->hpd_reg_names[i]);
                if (IS_ERR(reg)) {
                        ret = PTR_ERR(reg);
@@ -139,7 +139,7 @@ struct hdmi *hdmi_init(struct drm_device *dev, struct drm_encoder *encoder)
        for (i = 0; i < config->pwr_reg_cnt; i++) {
                struct regulator *reg;
 
-               reg = devm_regulator_get_exclusive(&pdev->dev,
+               reg = devm_regulator_get(&pdev->dev,
                                config->pwr_reg_names[i]);
                if (IS_ERR(reg)) {
                        ret = PTR_ERR(reg);
index e89fe053d375763b3252f3d6fba8e1fcad90d8f7..76fd0cfc6558fc622755ca90ff4c3fbc9a4f17ea 100644 (file)
@@ -10,14 +10,14 @@ git clone https://github.com/freedreno/envytools.git
 The rules-ng-ng source files this header was generated from are:
 - /home/robclark/src/freedreno/envytools/rnndb/msm.xml                 (    647 bytes, from 2013-11-30 14:45:35)
 - /home/robclark/src/freedreno/envytools/rnndb/freedreno_copyright.xml (   1453 bytes, from 2013-03-31 16:51:27)
-- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp4.xml            (  17996 bytes, from 2013-12-01 19:10:31)
-- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp_common.xml      (   1615 bytes, from 2013-11-30 15:00:52)
-- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp5.xml            (  22517 bytes, from 2014-06-25 12:55:02)
+- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp4.xml            (  20457 bytes, from 2014-08-01 12:22:48)
+- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp_common.xml      (   1615 bytes, from 2014-07-17 15:34:33)
+- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp5.xml            (  22517 bytes, from 2014-07-17 15:34:33)
 - /home/robclark/src/freedreno/envytools/rnndb/dsi/dsi.xml             (  11712 bytes, from 2013-08-17 17:13:43)
 - /home/robclark/src/freedreno/envytools/rnndb/dsi/sfpb.xml            (    344 bytes, from 2013-08-11 19:26:32)
-- /home/robclark/src/freedreno/envytools/rnndb/dsi/mmss_cc.xml         (   1544 bytes, from 2013-08-16 19:17:05)
+- /home/robclark/src/freedreno/envytools/rnndb/dsi/mmss_cc.xml         (   1686 bytes, from 2014-08-01 12:23:53)
 - /home/robclark/src/freedreno/envytools/rnndb/hdmi/qfprom.xml         (    600 bytes, from 2013-07-05 19:21:12)
-- /home/robclark/src/freedreno/envytools/rnndb/hdmi/hdmi.xml           (  23613 bytes, from 2014-06-25 12:53:44)
+- /home/robclark/src/freedreno/envytools/rnndb/hdmi/hdmi.xml           (  23613 bytes, from 2014-07-17 15:33:30)
 
 Copyright (C) 2013-2014 by the following authors:
 - Rob Clark <robdclark@gmail.com> (robclark)
index bd81db6a7829f999fd183a096e86dea8c88d1761..d53c29327df908c81e957467803ce0d6d6ad3ece 100644 (file)
@@ -10,14 +10,14 @@ git clone https://github.com/freedreno/envytools.git
 The rules-ng-ng source files this header was generated from are:
 - /home/robclark/src/freedreno/envytools/rnndb/msm.xml                 (    647 bytes, from 2013-11-30 14:45:35)
 - /home/robclark/src/freedreno/envytools/rnndb/freedreno_copyright.xml (   1453 bytes, from 2013-03-31 16:51:27)
-- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp4.xml            (  17996 bytes, from 2013-12-01 19:10:31)
-- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp_common.xml      (   1615 bytes, from 2013-11-30 15:00:52)
-- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp5.xml            (  22517 bytes, from 2014-06-25 12:55:02)
+- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp4.xml            (  20457 bytes, from 2014-08-01 12:22:48)
+- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp_common.xml      (   1615 bytes, from 2014-07-17 15:34:33)
+- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp5.xml            (  22517 bytes, from 2014-07-17 15:34:33)
 - /home/robclark/src/freedreno/envytools/rnndb/dsi/dsi.xml             (  11712 bytes, from 2013-08-17 17:13:43)
 - /home/robclark/src/freedreno/envytools/rnndb/dsi/sfpb.xml            (    344 bytes, from 2013-08-11 19:26:32)
-- /home/robclark/src/freedreno/envytools/rnndb/dsi/mmss_cc.xml         (   1544 bytes, from 2013-08-16 19:17:05)
+- /home/robclark/src/freedreno/envytools/rnndb/dsi/mmss_cc.xml         (   1686 bytes, from 2014-08-01 12:23:53)
 - /home/robclark/src/freedreno/envytools/rnndb/hdmi/qfprom.xml         (    600 bytes, from 2013-07-05 19:21:12)
-- /home/robclark/src/freedreno/envytools/rnndb/hdmi/hdmi.xml           (  23613 bytes, from 2014-06-25 12:53:44)
+- /home/robclark/src/freedreno/envytools/rnndb/hdmi/hdmi.xml           (  23613 bytes, from 2014-07-17 15:33:30)
 
 Copyright (C) 2013 by the following authors:
 - Rob Clark <robdclark@gmail.com> (robclark)
index 122208e8a2ee205d018f9d2c55ebd92de1af756b..03c0bd9cd5b9270dcec078aaa71ce7be2adff210 100644 (file)
@@ -10,16 +10,16 @@ git clone https://github.com/freedreno/envytools.git
 The rules-ng-ng source files this header was generated from are:
 - /home/robclark/src/freedreno/envytools/rnndb/msm.xml                 (    647 bytes, from 2013-11-30 14:45:35)
 - /home/robclark/src/freedreno/envytools/rnndb/freedreno_copyright.xml (   1453 bytes, from 2013-03-31 16:51:27)
-- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp4.xml            (  17996 bytes, from 2013-12-01 19:10:31)
-- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp_common.xml      (   1615 bytes, from 2013-11-30 15:00:52)
-- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp5.xml            (  22517 bytes, from 2014-06-25 12:55:02)
+- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp4.xml            (  20457 bytes, from 2014-08-01 12:22:48)
+- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp_common.xml      (   1615 bytes, from 2014-07-17 15:34:33)
+- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp5.xml            (  22517 bytes, from 2014-07-17 15:34:33)
 - /home/robclark/src/freedreno/envytools/rnndb/dsi/dsi.xml             (  11712 bytes, from 2013-08-17 17:13:43)
 - /home/robclark/src/freedreno/envytools/rnndb/dsi/sfpb.xml            (    344 bytes, from 2013-08-11 19:26:32)
-- /home/robclark/src/freedreno/envytools/rnndb/dsi/mmss_cc.xml         (   1544 bytes, from 2013-08-16 19:17:05)
+- /home/robclark/src/freedreno/envytools/rnndb/dsi/mmss_cc.xml         (   1686 bytes, from 2014-08-01 12:23:53)
 - /home/robclark/src/freedreno/envytools/rnndb/hdmi/qfprom.xml         (    600 bytes, from 2013-07-05 19:21:12)
-- /home/robclark/src/freedreno/envytools/rnndb/hdmi/hdmi.xml           (  23613 bytes, from 2014-06-25 12:53:44)
+- /home/robclark/src/freedreno/envytools/rnndb/hdmi/hdmi.xml           (  23613 bytes, from 2014-07-17 15:33:30)
 
-Copyright (C) 2013 by the following authors:
+Copyright (C) 2013-2014 by the following authors:
 - Rob Clark <robdclark@gmail.com> (robclark)
 
 Permission is hereby granted, free of charge, to any person obtaining
@@ -871,6 +871,101 @@ static inline uint32_t MDP4_LCDC_UNDERFLOW_CLR_COLOR(uint32_t val)
 #define MDP4_LCDC_CTRL_POLARITY_VSYNC_LOW                      0x00000002
 #define MDP4_LCDC_CTRL_POLARITY_DATA_EN_LOW                    0x00000004
 
+#define REG_MDP4_LCDC_LVDS_INTF_CTL                            0x000c2000
+#define MDP4_LCDC_LVDS_INTF_CTL_MODE_SEL                       0x00000004
+#define MDP4_LCDC_LVDS_INTF_CTL_RGB_OUT                                0x00000008
+#define MDP4_LCDC_LVDS_INTF_CTL_CH_SWAP                                0x00000010
+#define MDP4_LCDC_LVDS_INTF_CTL_CH1_RES_BIT                    0x00000020
+#define MDP4_LCDC_LVDS_INTF_CTL_CH2_RES_BIT                    0x00000040
+#define MDP4_LCDC_LVDS_INTF_CTL_ENABLE                         0x00000080
+#define MDP4_LCDC_LVDS_INTF_CTL_CH1_DATA_LANE0_EN              0x00000100
+#define MDP4_LCDC_LVDS_INTF_CTL_CH1_DATA_LANE1_EN              0x00000200
+#define MDP4_LCDC_LVDS_INTF_CTL_CH1_DATA_LANE2_EN              0x00000400
+#define MDP4_LCDC_LVDS_INTF_CTL_CH1_DATA_LANE3_EN              0x00000800
+#define MDP4_LCDC_LVDS_INTF_CTL_CH2_DATA_LANE0_EN              0x00001000
+#define MDP4_LCDC_LVDS_INTF_CTL_CH2_DATA_LANE1_EN              0x00002000
+#define MDP4_LCDC_LVDS_INTF_CTL_CH2_DATA_LANE2_EN              0x00004000
+#define MDP4_LCDC_LVDS_INTF_CTL_CH2_DATA_LANE3_EN              0x00008000
+#define MDP4_LCDC_LVDS_INTF_CTL_CH1_CLK_LANE_EN                        0x00010000
+#define MDP4_LCDC_LVDS_INTF_CTL_CH2_CLK_LANE_EN                        0x00020000
+
+static inline uint32_t REG_MDP4_LCDC_LVDS_MUX_CTL(uint32_t i0) { return 0x000c2014 + 0x8*i0; }
+
+static inline uint32_t REG_MDP4_LCDC_LVDS_MUX_CTL_3_TO_0(uint32_t i0) { return 0x000c2014 + 0x8*i0; }
+#define MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT0__MASK               0x000000ff
+#define MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT0__SHIFT              0
+static inline uint32_t MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT0(uint32_t val)
+{
+       return ((val) << MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT0__SHIFT) & MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT0__MASK;
+}
+#define MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT1__MASK               0x0000ff00
+#define MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT1__SHIFT              8
+static inline uint32_t MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT1(uint32_t val)
+{
+       return ((val) << MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT1__SHIFT) & MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT1__MASK;
+}
+#define MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT2__MASK               0x00ff0000
+#define MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT2__SHIFT              16
+static inline uint32_t MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT2(uint32_t val)
+{
+       return ((val) << MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT2__SHIFT) & MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT2__MASK;
+}
+#define MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT3__MASK               0xff000000
+#define MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT3__SHIFT              24
+static inline uint32_t MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT3(uint32_t val)
+{
+       return ((val) << MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT3__SHIFT) & MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT3__MASK;
+}
+
+static inline uint32_t REG_MDP4_LCDC_LVDS_MUX_CTL_6_TO_4(uint32_t i0) { return 0x000c2018 + 0x8*i0; }
+#define MDP4_LCDC_LVDS_MUX_CTL_6_TO_4_BIT4__MASK               0x000000ff
+#define MDP4_LCDC_LVDS_MUX_CTL_6_TO_4_BIT4__SHIFT              0
+static inline uint32_t MDP4_LCDC_LVDS_MUX_CTL_6_TO_4_BIT4(uint32_t val)
+{
+       return ((val) << MDP4_LCDC_LVDS_MUX_CTL_6_TO_4_BIT4__SHIFT) & MDP4_LCDC_LVDS_MUX_CTL_6_TO_4_BIT4__MASK;
+}
+#define MDP4_LCDC_LVDS_MUX_CTL_6_TO_4_BIT5__MASK               0x0000ff00
+#define MDP4_LCDC_LVDS_MUX_CTL_6_TO_4_BIT5__SHIFT              8
+static inline uint32_t MDP4_LCDC_LVDS_MUX_CTL_6_TO_4_BIT5(uint32_t val)
+{
+       return ((val) << MDP4_LCDC_LVDS_MUX_CTL_6_TO_4_BIT5__SHIFT) & MDP4_LCDC_LVDS_MUX_CTL_6_TO_4_BIT5__MASK;
+}
+#define MDP4_LCDC_LVDS_MUX_CTL_6_TO_4_BIT6__MASK               0x00ff0000
+#define MDP4_LCDC_LVDS_MUX_CTL_6_TO_4_BIT6__SHIFT              16
+static inline uint32_t MDP4_LCDC_LVDS_MUX_CTL_6_TO_4_BIT6(uint32_t val)
+{
+       return ((val) << MDP4_LCDC_LVDS_MUX_CTL_6_TO_4_BIT6__SHIFT) & MDP4_LCDC_LVDS_MUX_CTL_6_TO_4_BIT6__MASK;
+}
+
+#define REG_MDP4_LCDC_LVDS_PHY_RESET                           0x000c2034
+
+#define REG_MDP4_LVDS_PHY_PLL_CTRL_0                           0x000c3000
+
+#define REG_MDP4_LVDS_PHY_PLL_CTRL_1                           0x000c3004
+
+#define REG_MDP4_LVDS_PHY_PLL_CTRL_2                           0x000c3008
+
+#define REG_MDP4_LVDS_PHY_PLL_CTRL_3                           0x000c300c
+
+#define REG_MDP4_LVDS_PHY_PLL_CTRL_5                           0x000c3014
+
+#define REG_MDP4_LVDS_PHY_PLL_CTRL_6                           0x000c3018
+
+#define REG_MDP4_LVDS_PHY_PLL_CTRL_7                           0x000c301c
+
+#define REG_MDP4_LVDS_PHY_PLL_CTRL_8                           0x000c3020
+
+#define REG_MDP4_LVDS_PHY_PLL_CTRL_9                           0x000c3024
+
+#define REG_MDP4_LVDS_PHY_PLL_LOCKED                           0x000c3080
+
+#define REG_MDP4_LVDS_PHY_CFG2                                 0x000c3108
+
+#define REG_MDP4_LVDS_PHY_CFG0                                 0x000c3100
+#define MDP4_LVDS_PHY_CFG0_SERIALIZATION_ENBLE                 0x00000010
+#define MDP4_LVDS_PHY_CFG0_CHANNEL0                            0x00000040
+#define MDP4_LVDS_PHY_CFG0_CHANNEL1                            0x00000080
+
 #define REG_MDP4_DTV                                           0x000d0000
 
 #define REG_MDP4_DTV_ENABLE                                    0x000d0000
index c6c80ea28c35809dbe63bb22aec0a50da9f4d0c6..7d00f7fb5773571c2fd005df0e278c18de425b64 100644 (file)
@@ -273,14 +273,17 @@ static void blend_setup(struct drm_crtc *crtc)
        };
        bool alpha[4]= { false, false, false, false };
 
+       /* Don't rely on value read back from hw, but instead use our
+        * own shadowed value.  Possibly disable/reenable looses the
+        * previous value and goes back to power-on default?
+        */
+       mixer_cfg = mdp4_kms->mixer_cfg;
+
        mdp4_write(mdp4_kms, REG_MDP4_OVLP_TRANSP_LOW0(ovlp), 0);
        mdp4_write(mdp4_kms, REG_MDP4_OVLP_TRANSP_LOW1(ovlp), 0);
        mdp4_write(mdp4_kms, REG_MDP4_OVLP_TRANSP_HIGH0(ovlp), 0);
        mdp4_write(mdp4_kms, REG_MDP4_OVLP_TRANSP_HIGH1(ovlp), 0);
 
-       /* TODO single register for all CRTCs, so this won't work properly
-        * when multiple CRTCs are active..
-        */
        for (i = 0; i < ARRAY_SIZE(mdp4_crtc->planes); i++) {
                struct drm_plane *plane = mdp4_crtc->planes[i];
                if (plane) {
@@ -291,7 +294,8 @@ static void blend_setup(struct drm_crtc *crtc)
                                        to_mdp_format(msm_framebuffer_format(plane->fb));
                                alpha[idx-1] = format->alpha_enable;
                        }
-                       mixer_cfg |= mixercfg(mdp4_crtc->mixer, pipe_id, stages[idx]);
+                       mixer_cfg = mixercfg(mixer_cfg, mdp4_crtc->mixer,
+                                       pipe_id, stages[idx]);
                }
        }
 
@@ -320,6 +324,7 @@ static void blend_setup(struct drm_crtc *crtc)
                mdp4_write(mdp4_kms, REG_MDP4_OVLP_STAGE_TRANSP_HIGH1(ovlp, i), 0);
        }
 
+       mdp4_kms->mixer_cfg = mixer_cfg;
        mdp4_write(mdp4_kms, REG_MDP4_LAYERMIXER_IN_CFG, mixer_cfg);
 }
 
@@ -672,7 +677,7 @@ void mdp4_crtc_set_config(struct drm_crtc *crtc, uint32_t config)
 }
 
 /* set interface for routing crtc->encoder: */
-void mdp4_crtc_set_intf(struct drm_crtc *crtc, enum mdp4_intf intf)
+void mdp4_crtc_set_intf(struct drm_crtc *crtc, enum mdp4_intf intf, int mixer)
 {
        struct mdp4_crtc *mdp4_crtc = to_mdp4_crtc(crtc);
        struct mdp4_kms *mdp4_kms = get_kms(crtc);
@@ -698,15 +703,13 @@ void mdp4_crtc_set_intf(struct drm_crtc *crtc, enum mdp4_intf intf)
        if (intf == INTF_DSI_VIDEO) {
                intf_sel &= ~MDP4_DISP_INTF_SEL_DSI_CMD;
                intf_sel |= MDP4_DISP_INTF_SEL_DSI_VIDEO;
-               mdp4_crtc->mixer = 0;
        } else if (intf == INTF_DSI_CMD) {
                intf_sel &= ~MDP4_DISP_INTF_SEL_DSI_VIDEO;
                intf_sel |= MDP4_DISP_INTF_SEL_DSI_CMD;
-               mdp4_crtc->mixer = 0;
-       } else if (intf == INTF_LCDC_DTV){
-               mdp4_crtc->mixer = 1;
        }
 
+       mdp4_crtc->mixer = mixer;
+
        blend_setup(crtc);
 
        DBG("%s: intf_sel=%08x", mdp4_crtc->name, intf_sel);
index 067ed03b35fef964f530746a877efb77bf9fcbe5..c3878420180b82f4e0a0bf1c75d13e33432c51ee 100644 (file)
@@ -233,7 +233,7 @@ static void mdp4_dtv_encoder_commit(struct drm_encoder *encoder)
                        MDP4_DMA_CONFIG_G_BPC(BPC8) |
                        MDP4_DMA_CONFIG_B_BPC(BPC8) |
                        MDP4_DMA_CONFIG_PACK(0x21));
-       mdp4_crtc_set_intf(encoder->crtc, INTF_LCDC_DTV);
+       mdp4_crtc_set_intf(encoder->crtc, INTF_LCDC_DTV, 1);
        mdp4_dtv_encoder_dpms(encoder, DRM_MODE_DPMS_ON);
 }
 
index 733646c0d3f871cc090efedb741fb8ae73ec790f..79d804e61cc44e48710f7a4703f38008e7a37b6c 100644 (file)
@@ -106,6 +106,7 @@ static int mdp4_hw_init(struct msm_kms *kms)
 
        if (mdp4_kms->rev >= 2)
                mdp4_write(mdp4_kms, REG_MDP4_LAYERMIXER_IN_CFG_UPDATE_METHOD, 1);
+       mdp4_write(mdp4_kms, REG_MDP4_LAYERMIXER_IN_CFG, 0);
 
        /* disable CSC matrix / YUV by default: */
        mdp4_write(mdp4_kms, REG_MDP4_PIPE_OP_MODE(VG1), 0);
@@ -196,6 +197,28 @@ int mdp4_enable(struct mdp4_kms *mdp4_kms)
        return 0;
 }
 
+#ifdef CONFIG_OF
+static struct drm_panel *detect_panel(struct drm_device *dev, const char *name)
+{
+       struct device_node *n;
+       struct drm_panel *panel = NULL;
+
+       n = of_parse_phandle(dev->dev->of_node, name, 0);
+       if (n) {
+               panel = of_drm_find_panel(n);
+               if (!panel)
+                       panel = ERR_PTR(-EPROBE_DEFER);
+       }
+
+       return panel;
+}
+#else
+static struct drm_panel *detect_panel(struct drm_device *dev, const char *name)
+{
+       // ??? maybe use a module param to specify which panel is attached?
+}
+#endif
+
 static int modeset_init(struct mdp4_kms *mdp4_kms)
 {
        struct drm_device *dev = mdp4_kms->dev;
@@ -203,14 +226,11 @@ static int modeset_init(struct mdp4_kms *mdp4_kms)
        struct drm_plane *plane;
        struct drm_crtc *crtc;
        struct drm_encoder *encoder;
+       struct drm_connector *connector;
+       struct drm_panel *panel;
        struct hdmi *hdmi;
        int ret;
 
-       /*
-        *  NOTE: this is a bit simplistic until we add support
-        * for more than just RGB1->DMA_E->DTV->HDMI
-        */
-
        /* construct non-private planes: */
        plane = mdp4_plane_init(dev, VG1, false);
        if (IS_ERR(plane)) {
@@ -228,7 +248,57 @@ static int modeset_init(struct mdp4_kms *mdp4_kms)
        }
        priv->planes[priv->num_planes++] = plane;
 
-       /* the CRTCs get constructed with a private plane: */
+       /*
+        * Setup the LCDC/LVDS path: RGB2 -> DMA_P -> LCDC -> LVDS:
+        */
+
+       panel = detect_panel(dev, "qcom,lvds-panel");
+       if (IS_ERR(panel)) {
+               ret = PTR_ERR(panel);
+               dev_err(dev->dev, "failed to detect LVDS panel: %d\n", ret);
+               goto fail;
+       }
+
+       plane = mdp4_plane_init(dev, RGB2, true);
+       if (IS_ERR(plane)) {
+               dev_err(dev->dev, "failed to construct plane for RGB2\n");
+               ret = PTR_ERR(plane);
+               goto fail;
+       }
+
+       crtc  = mdp4_crtc_init(dev, plane, priv->num_crtcs, 0, DMA_P);
+       if (IS_ERR(crtc)) {
+               dev_err(dev->dev, "failed to construct crtc for DMA_P\n");
+               ret = PTR_ERR(crtc);
+               goto fail;
+       }
+
+       encoder = mdp4_lcdc_encoder_init(dev, panel);
+       if (IS_ERR(encoder)) {
+               dev_err(dev->dev, "failed to construct LCDC encoder\n");
+               ret = PTR_ERR(encoder);
+               goto fail;
+       }
+
+       /* LCDC can be hooked to DMA_P: */
+       encoder->possible_crtcs = 1 << priv->num_crtcs;
+
+       priv->crtcs[priv->num_crtcs++] = crtc;
+       priv->encoders[priv->num_encoders++] = encoder;
+
+       connector = mdp4_lvds_connector_init(dev, panel, encoder);
+       if (IS_ERR(connector)) {
+               ret = PTR_ERR(connector);
+               dev_err(dev->dev, "failed to initialize LVDS connector: %d\n", ret);
+               goto fail;
+       }
+
+       priv->connectors[priv->num_connectors++] = connector;
+
+       /*
+        * Setup DTV/HDMI path: RGB1 -> DMA_E -> DTV -> HDMI:
+        */
+
        plane = mdp4_plane_init(dev, RGB1, true);
        if (IS_ERR(plane)) {
                dev_err(dev->dev, "failed to construct plane for RGB1\n");
@@ -242,7 +312,6 @@ static int modeset_init(struct mdp4_kms *mdp4_kms)
                ret = PTR_ERR(crtc);
                goto fail;
        }
-       priv->crtcs[priv->num_crtcs++] = crtc;
 
        encoder = mdp4_dtv_encoder_init(dev);
        if (IS_ERR(encoder)) {
@@ -250,7 +319,11 @@ static int modeset_init(struct mdp4_kms *mdp4_kms)
                ret = PTR_ERR(encoder);
                goto fail;
        }
-       encoder->possible_crtcs = 0x1;     /* DTV can be hooked to DMA_E */
+
+       /* DTV can be hooked to DMA_E: */
+       encoder->possible_crtcs = 1 << priv->num_crtcs;
+
+       priv->crtcs[priv->num_crtcs++] = crtc;
        priv->encoders[priv->num_encoders++] = encoder;
 
        hdmi = hdmi_init(dev, encoder);
index 3225da804c613f4f9fce06960862bb6bb345b406..9ff6e7ccfe90d248fc70a2ccaabba6d92d7aab0a 100644 (file)
@@ -23,6 +23,8 @@
 #include "mdp/mdp_kms.h"
 #include "mdp4.xml.h"
 
+#include "drm_panel.h"
+
 struct mdp4_kms {
        struct mdp_kms base;
 
@@ -30,6 +32,13 @@ struct mdp4_kms {
 
        int rev;
 
+       /* Shadow value for MDP4_LAYERMIXER_IN_CFG.. since setup for all
+        * crtcs/encoders is in one shared register, we need to update it
+        * via read/modify/write.  But to avoid getting confused by power-
+        * on-default values after resume, use this shadow value instead:
+        */
+       uint32_t mixer_cfg;
+
        /* mapper-id used to request GEM buffer mapped for scanout: */
        int id;
 
@@ -74,7 +83,7 @@ static inline uint32_t pipe2flush(enum mdp4_pipe pipe)
        case VG1:      return MDP4_OVERLAY_FLUSH_VG1;
        case VG2:      return MDP4_OVERLAY_FLUSH_VG2;
        case RGB1:     return MDP4_OVERLAY_FLUSH_RGB1;
-       case RGB2:     return MDP4_OVERLAY_FLUSH_RGB1;
+       case RGB2:     return MDP4_OVERLAY_FLUSH_RGB2;
        default:       return 0;
        }
 }
@@ -108,38 +117,50 @@ static inline uint32_t dma2err(enum mdp4_dma dma)
        }
 }
 
-static inline uint32_t mixercfg(int mixer, enum mdp4_pipe pipe,
-               enum mdp_mixer_stage_id stage)
+static inline uint32_t mixercfg(uint32_t mixer_cfg, int mixer,
+               enum mdp4_pipe pipe, enum mdp_mixer_stage_id stage)
 {
-       uint32_t mixer_cfg = 0;
-
        switch (pipe) {
        case VG1:
-               mixer_cfg = MDP4_LAYERMIXER_IN_CFG_PIPE0(stage) |
+               mixer_cfg &= ~(MDP4_LAYERMIXER_IN_CFG_PIPE0__MASK |
+                               MDP4_LAYERMIXER_IN_CFG_PIPE0_MIXER1);
+               mixer_cfg |= MDP4_LAYERMIXER_IN_CFG_PIPE0(stage) |
                        COND(mixer == 1, MDP4_LAYERMIXER_IN_CFG_PIPE0_MIXER1);
                break;
        case VG2:
-               mixer_cfg = MDP4_LAYERMIXER_IN_CFG_PIPE1(stage) |
+               mixer_cfg &= ~(MDP4_LAYERMIXER_IN_CFG_PIPE1__MASK |
+                               MDP4_LAYERMIXER_IN_CFG_PIPE1_MIXER1);
+               mixer_cfg |= MDP4_LAYERMIXER_IN_CFG_PIPE1(stage) |
                        COND(mixer == 1, MDP4_LAYERMIXER_IN_CFG_PIPE1_MIXER1);
                break;
        case RGB1:
-               mixer_cfg = MDP4_LAYERMIXER_IN_CFG_PIPE2(stage) |
+               mixer_cfg &= ~(MDP4_LAYERMIXER_IN_CFG_PIPE2__MASK |
+                               MDP4_LAYERMIXER_IN_CFG_PIPE2_MIXER1);
+               mixer_cfg |= MDP4_LAYERMIXER_IN_CFG_PIPE2(stage) |
                        COND(mixer == 1, MDP4_LAYERMIXER_IN_CFG_PIPE2_MIXER1);
                break;
        case RGB2:
-               mixer_cfg = MDP4_LAYERMIXER_IN_CFG_PIPE3(stage) |
+               mixer_cfg &= ~(MDP4_LAYERMIXER_IN_CFG_PIPE3__MASK |
+                               MDP4_LAYERMIXER_IN_CFG_PIPE3_MIXER1);
+               mixer_cfg |= MDP4_LAYERMIXER_IN_CFG_PIPE3(stage) |
                        COND(mixer == 1, MDP4_LAYERMIXER_IN_CFG_PIPE3_MIXER1);
                break;
        case RGB3:
-               mixer_cfg = MDP4_LAYERMIXER_IN_CFG_PIPE4(stage) |
+               mixer_cfg &= ~(MDP4_LAYERMIXER_IN_CFG_PIPE4__MASK |
+                               MDP4_LAYERMIXER_IN_CFG_PIPE4_MIXER1);
+               mixer_cfg |= MDP4_LAYERMIXER_IN_CFG_PIPE4(stage) |
                        COND(mixer == 1, MDP4_LAYERMIXER_IN_CFG_PIPE4_MIXER1);
                break;
        case VG3:
-               mixer_cfg = MDP4_LAYERMIXER_IN_CFG_PIPE5(stage) |
+               mixer_cfg &= ~(MDP4_LAYERMIXER_IN_CFG_PIPE5__MASK |
+                               MDP4_LAYERMIXER_IN_CFG_PIPE5_MIXER1);
+               mixer_cfg |= MDP4_LAYERMIXER_IN_CFG_PIPE5(stage) |
                        COND(mixer == 1, MDP4_LAYERMIXER_IN_CFG_PIPE5_MIXER1);
                break;
        case VG4:
-               mixer_cfg = MDP4_LAYERMIXER_IN_CFG_PIPE6(stage) |
+               mixer_cfg &= ~(MDP4_LAYERMIXER_IN_CFG_PIPE6__MASK |
+                               MDP4_LAYERMIXER_IN_CFG_PIPE6_MIXER1);
+               mixer_cfg |= MDP4_LAYERMIXER_IN_CFG_PIPE6(stage) |
                        COND(mixer == 1, MDP4_LAYERMIXER_IN_CFG_PIPE6_MIXER1);
                break;
        default:
@@ -188,7 +209,7 @@ struct drm_plane *mdp4_plane_init(struct drm_device *dev,
 uint32_t mdp4_crtc_vblank(struct drm_crtc *crtc);
 void mdp4_crtc_cancel_pending_flip(struct drm_crtc *crtc, struct drm_file *file);
 void mdp4_crtc_set_config(struct drm_crtc *crtc, uint32_t config);
-void mdp4_crtc_set_intf(struct drm_crtc *crtc, enum mdp4_intf intf);
+void mdp4_crtc_set_intf(struct drm_crtc *crtc, enum mdp4_intf intf, int mixer);
 void mdp4_crtc_attach(struct drm_crtc *crtc, struct drm_plane *plane);
 void mdp4_crtc_detach(struct drm_crtc *crtc, struct drm_plane *plane);
 struct drm_crtc *mdp4_crtc_init(struct drm_device *dev,
@@ -198,6 +219,22 @@ struct drm_crtc *mdp4_crtc_init(struct drm_device *dev,
 long mdp4_dtv_round_pixclk(struct drm_encoder *encoder, unsigned long rate);
 struct drm_encoder *mdp4_dtv_encoder_init(struct drm_device *dev);
 
+long mdp4_lcdc_round_pixclk(struct drm_encoder *encoder, unsigned long rate);
+struct drm_encoder *mdp4_lcdc_encoder_init(struct drm_device *dev,
+               struct drm_panel *panel);
+
+struct drm_connector *mdp4_lvds_connector_init(struct drm_device *dev,
+               struct drm_panel *panel, struct drm_encoder *encoder);
+
+#ifdef CONFIG_COMMON_CLK
+struct clk *mpd4_lvds_pll_init(struct drm_device *dev);
+#else
+static inline struct clk *mpd4_lvds_pll_init(struct drm_device *dev)
+{
+       return ERR_PTR(-ENODEV);
+}
+#endif
+
 #ifdef CONFIG_MSM_BUS_SCALING
 static inline int match_dev_name(struct device *dev, void *data)
 {
diff --git a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_lcdc_encoder.c b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_lcdc_encoder.c
new file mode 100644 (file)
index 0000000..41f6436
--- /dev/null
@@ -0,0 +1,506 @@
+/*
+ * Copyright (C) 2014 Red Hat
+ * Author: Rob Clark <robdclark@gmail.com>
+ * Author: Vinay Simha <vinaysimha@inforcecomputing.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 "mdp4_kms.h"
+
+#include "drm_crtc.h"
+#include "drm_crtc_helper.h"
+
+struct mdp4_lcdc_encoder {
+       struct drm_encoder base;
+       struct drm_panel *panel;
+       struct clk *lcdc_clk;
+       unsigned long int pixclock;
+       struct regulator *regs[3];
+       bool enabled;
+       uint32_t bsc;
+};
+#define to_mdp4_lcdc_encoder(x) container_of(x, struct mdp4_lcdc_encoder, base)
+
+static struct mdp4_kms *get_kms(struct drm_encoder *encoder)
+{
+       struct msm_drm_private *priv = encoder->dev->dev_private;
+       return to_mdp4_kms(to_mdp_kms(priv->kms));
+}
+
+#ifdef CONFIG_MSM_BUS_SCALING
+#include <mach/board.h>
+static void bs_init(struct mdp4_lcdc_encoder *mdp4_lcdc_encoder)
+{
+       struct drm_device *dev = mdp4_lcdc_encoder->base.dev;
+       struct lcdc_platform_data *lcdc_pdata = mdp4_find_pdata("lvds.0");
+
+       if (!lcdc_pdata) {
+               dev_err(dev->dev, "could not find lvds pdata\n");
+               return;
+       }
+
+       if (lcdc_pdata->bus_scale_table) {
+               mdp4_lcdc_encoder->bsc = msm_bus_scale_register_client(
+                               lcdc_pdata->bus_scale_table);
+               DBG("lvds : bus scale client: %08x", mdp4_lcdc_encoder->bsc);
+       }
+}
+
+static void bs_fini(struct mdp4_lcdc_encoder *mdp4_lcdc_encoder)
+{
+       if (mdp4_lcdc_encoder->bsc) {
+               msm_bus_scale_unregister_client(mdp4_lcdc_encoder->bsc);
+               mdp4_lcdc_encoder->bsc = 0;
+       }
+}
+
+static void bs_set(struct mdp4_lcdc_encoder *mdp4_lcdc_encoder, int idx)
+{
+       if (mdp4_lcdc_encoder->bsc) {
+               DBG("set bus scaling: %d", idx);
+               msm_bus_scale_client_update_request(mdp4_lcdc_encoder->bsc, idx);
+       }
+}
+#else
+static void bs_init(struct mdp4_lcdc_encoder *mdp4_lcdc_encoder) {}
+static void bs_fini(struct mdp4_lcdc_encoder *mdp4_lcdc_encoder) {}
+static void bs_set(struct mdp4_lcdc_encoder *mdp4_lcdc_encoder, int idx) {}
+#endif
+
+static void mdp4_lcdc_encoder_destroy(struct drm_encoder *encoder)
+{
+       struct mdp4_lcdc_encoder *mdp4_lcdc_encoder =
+                       to_mdp4_lcdc_encoder(encoder);
+       bs_fini(mdp4_lcdc_encoder);
+       drm_encoder_cleanup(encoder);
+       kfree(mdp4_lcdc_encoder);
+}
+
+static const struct drm_encoder_funcs mdp4_lcdc_encoder_funcs = {
+       .destroy = mdp4_lcdc_encoder_destroy,
+};
+
+/* this should probably be a helper: */
+struct drm_connector *get_connector(struct drm_encoder *encoder)
+{
+       struct drm_device *dev = encoder->dev;
+       struct drm_connector *connector;
+
+       list_for_each_entry(connector, &dev->mode_config.connector_list, head)
+               if (connector->encoder == encoder)
+                       return connector;
+
+       return NULL;
+}
+
+static void setup_phy(struct drm_encoder *encoder)
+{
+       struct drm_device *dev = encoder->dev;
+       struct drm_connector *connector = get_connector(encoder);
+       struct mdp4_kms *mdp4_kms = get_kms(encoder);
+       uint32_t lvds_intf = 0, lvds_phy_cfg0 = 0;
+       int bpp, nchan, swap;
+
+       if (!connector)
+               return;
+
+       bpp = 3 * connector->display_info.bpc;
+
+       if (!bpp)
+               bpp = 18;
+
+       /* TODO, these should come from panel somehow: */
+       nchan = 1;
+       swap = 0;
+
+       switch (bpp) {
+       case 24:
+               mdp4_write(mdp4_kms, REG_MDP4_LCDC_LVDS_MUX_CTL_3_TO_0(0),
+                               MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT0(0x08) |
+                               MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT1(0x05) |
+                               MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT2(0x04) |
+                               MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT3(0x03));
+               mdp4_write(mdp4_kms, REG_MDP4_LCDC_LVDS_MUX_CTL_6_TO_4(0),
+                               MDP4_LCDC_LVDS_MUX_CTL_6_TO_4_BIT4(0x02) |
+                               MDP4_LCDC_LVDS_MUX_CTL_6_TO_4_BIT5(0x01) |
+                               MDP4_LCDC_LVDS_MUX_CTL_6_TO_4_BIT6(0x00));
+               mdp4_write(mdp4_kms, REG_MDP4_LCDC_LVDS_MUX_CTL_3_TO_0(1),
+                               MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT0(0x11) |
+                               MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT1(0x10) |
+                               MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT2(0x0d) |
+                               MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT3(0x0c));
+               mdp4_write(mdp4_kms, REG_MDP4_LCDC_LVDS_MUX_CTL_6_TO_4(1),
+                               MDP4_LCDC_LVDS_MUX_CTL_6_TO_4_BIT4(0x0b) |
+                               MDP4_LCDC_LVDS_MUX_CTL_6_TO_4_BIT5(0x0a) |
+                               MDP4_LCDC_LVDS_MUX_CTL_6_TO_4_BIT6(0x09));
+               mdp4_write(mdp4_kms, REG_MDP4_LCDC_LVDS_MUX_CTL_3_TO_0(2),
+                               MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT0(0x1a) |
+                               MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT1(0x19) |
+                               MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT2(0x18) |
+                               MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT3(0x15));
+               mdp4_write(mdp4_kms, REG_MDP4_LCDC_LVDS_MUX_CTL_6_TO_4(2),
+                               MDP4_LCDC_LVDS_MUX_CTL_6_TO_4_BIT4(0x14) |
+                               MDP4_LCDC_LVDS_MUX_CTL_6_TO_4_BIT5(0x13) |
+                               MDP4_LCDC_LVDS_MUX_CTL_6_TO_4_BIT6(0x12));
+               mdp4_write(mdp4_kms, REG_MDP4_LCDC_LVDS_MUX_CTL_3_TO_0(3),
+                               MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT0(0x1b) |
+                               MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT1(0x17) |
+                               MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT2(0x16) |
+                               MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT3(0x0f));
+               mdp4_write(mdp4_kms, REG_MDP4_LCDC_LVDS_MUX_CTL_6_TO_4(3),
+                               MDP4_LCDC_LVDS_MUX_CTL_6_TO_4_BIT4(0x0e) |
+                               MDP4_LCDC_LVDS_MUX_CTL_6_TO_4_BIT5(0x07) |
+                               MDP4_LCDC_LVDS_MUX_CTL_6_TO_4_BIT6(0x06));
+               if (nchan == 2) {
+                       lvds_intf |= MDP4_LCDC_LVDS_INTF_CTL_CH2_DATA_LANE3_EN |
+                                       MDP4_LCDC_LVDS_INTF_CTL_CH2_DATA_LANE2_EN |
+                                       MDP4_LCDC_LVDS_INTF_CTL_CH2_DATA_LANE1_EN |
+                                       MDP4_LCDC_LVDS_INTF_CTL_CH2_DATA_LANE0_EN |
+                                       MDP4_LCDC_LVDS_INTF_CTL_CH1_DATA_LANE3_EN |
+                                       MDP4_LCDC_LVDS_INTF_CTL_CH1_DATA_LANE2_EN |
+                                       MDP4_LCDC_LVDS_INTF_CTL_CH1_DATA_LANE1_EN |
+                                       MDP4_LCDC_LVDS_INTF_CTL_CH1_DATA_LANE0_EN;
+               } else {
+                       lvds_intf |= MDP4_LCDC_LVDS_INTF_CTL_CH1_DATA_LANE3_EN |
+                                       MDP4_LCDC_LVDS_INTF_CTL_CH1_DATA_LANE2_EN |
+                                       MDP4_LCDC_LVDS_INTF_CTL_CH1_DATA_LANE1_EN |
+                                       MDP4_LCDC_LVDS_INTF_CTL_CH1_DATA_LANE0_EN;
+               }
+               break;
+
+       case 18:
+               mdp4_write(mdp4_kms, REG_MDP4_LCDC_LVDS_MUX_CTL_3_TO_0(0),
+                               MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT0(0x0a) |
+                               MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT1(0x07) |
+                               MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT2(0x06) |
+                               MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT3(0x05));
+               mdp4_write(mdp4_kms, REG_MDP4_LCDC_LVDS_MUX_CTL_6_TO_4(0),
+                               MDP4_LCDC_LVDS_MUX_CTL_6_TO_4_BIT4(0x04) |
+                               MDP4_LCDC_LVDS_MUX_CTL_6_TO_4_BIT5(0x03) |
+                               MDP4_LCDC_LVDS_MUX_CTL_6_TO_4_BIT6(0x02));
+               mdp4_write(mdp4_kms, REG_MDP4_LCDC_LVDS_MUX_CTL_3_TO_0(1),
+                               MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT0(0x13) |
+                               MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT1(0x12) |
+                               MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT2(0x0f) |
+                               MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT3(0x0e));
+               mdp4_write(mdp4_kms, REG_MDP4_LCDC_LVDS_MUX_CTL_6_TO_4(1),
+                               MDP4_LCDC_LVDS_MUX_CTL_6_TO_4_BIT4(0x0d) |
+                               MDP4_LCDC_LVDS_MUX_CTL_6_TO_4_BIT5(0x0c) |
+                               MDP4_LCDC_LVDS_MUX_CTL_6_TO_4_BIT6(0x0b));
+               mdp4_write(mdp4_kms, REG_MDP4_LCDC_LVDS_MUX_CTL_3_TO_0(2),
+                               MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT0(0x1a) |
+                               MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT1(0x19) |
+                               MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT2(0x18) |
+                               MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT3(0x17));
+               mdp4_write(mdp4_kms, REG_MDP4_LCDC_LVDS_MUX_CTL_6_TO_4(2),
+                               MDP4_LCDC_LVDS_MUX_CTL_6_TO_4_BIT4(0x16) |
+                               MDP4_LCDC_LVDS_MUX_CTL_6_TO_4_BIT5(0x15) |
+                               MDP4_LCDC_LVDS_MUX_CTL_6_TO_4_BIT6(0x14));
+               if (nchan == 2) {
+                       lvds_intf |= MDP4_LCDC_LVDS_INTF_CTL_CH2_DATA_LANE2_EN |
+                                       MDP4_LCDC_LVDS_INTF_CTL_CH2_DATA_LANE1_EN |
+                                       MDP4_LCDC_LVDS_INTF_CTL_CH2_DATA_LANE0_EN |
+                                       MDP4_LCDC_LVDS_INTF_CTL_CH1_DATA_LANE2_EN |
+                                       MDP4_LCDC_LVDS_INTF_CTL_CH1_DATA_LANE1_EN |
+                                       MDP4_LCDC_LVDS_INTF_CTL_CH1_DATA_LANE0_EN;
+               } else {
+                       lvds_intf |= MDP4_LCDC_LVDS_INTF_CTL_CH1_DATA_LANE2_EN |
+                                       MDP4_LCDC_LVDS_INTF_CTL_CH1_DATA_LANE1_EN |
+                                       MDP4_LCDC_LVDS_INTF_CTL_CH1_DATA_LANE0_EN;
+               }
+               lvds_intf |= MDP4_LCDC_LVDS_INTF_CTL_RGB_OUT;
+               break;
+
+       default:
+               dev_err(dev->dev, "unknown bpp: %d\n", bpp);
+               return;
+       }
+
+       switch (nchan) {
+       case 1:
+               lvds_phy_cfg0 = MDP4_LVDS_PHY_CFG0_CHANNEL0;
+               lvds_intf |= MDP4_LCDC_LVDS_INTF_CTL_CH1_CLK_LANE_EN |
+                               MDP4_LCDC_LVDS_INTF_CTL_MODE_SEL;
+               break;
+       case 2:
+               lvds_phy_cfg0 = MDP4_LVDS_PHY_CFG0_CHANNEL0 |
+                               MDP4_LVDS_PHY_CFG0_CHANNEL1;
+               lvds_intf |= MDP4_LCDC_LVDS_INTF_CTL_CH2_CLK_LANE_EN |
+                               MDP4_LCDC_LVDS_INTF_CTL_CH1_CLK_LANE_EN;
+               break;
+       default:
+               dev_err(dev->dev, "unknown # of channels: %d\n", nchan);
+               return;
+       }
+
+       if (swap)
+               lvds_intf |= MDP4_LCDC_LVDS_INTF_CTL_CH_SWAP;
+
+       lvds_intf |= MDP4_LCDC_LVDS_INTF_CTL_ENABLE;
+
+       mdp4_write(mdp4_kms, REG_MDP4_LVDS_PHY_CFG0, lvds_phy_cfg0);
+       mdp4_write(mdp4_kms, REG_MDP4_LCDC_LVDS_INTF_CTL, lvds_intf);
+       mdp4_write(mdp4_kms, REG_MDP4_LVDS_PHY_CFG2, 0x30);
+
+       mb();
+       udelay(1);
+       lvds_phy_cfg0 |= MDP4_LVDS_PHY_CFG0_SERIALIZATION_ENBLE;
+       mdp4_write(mdp4_kms, REG_MDP4_LVDS_PHY_CFG0, lvds_phy_cfg0);
+}
+
+static void mdp4_lcdc_encoder_dpms(struct drm_encoder *encoder, int mode)
+{
+       struct drm_device *dev = encoder->dev;
+       struct mdp4_lcdc_encoder *mdp4_lcdc_encoder =
+                       to_mdp4_lcdc_encoder(encoder);
+       struct mdp4_kms *mdp4_kms = get_kms(encoder);
+       struct drm_panel *panel = mdp4_lcdc_encoder->panel;
+       bool enabled = (mode == DRM_MODE_DPMS_ON);
+       int i, ret;
+
+       DBG("mode=%d", mode);
+
+       if (enabled == mdp4_lcdc_encoder->enabled)
+               return;
+
+       if (enabled) {
+               unsigned long pc = mdp4_lcdc_encoder->pixclock;
+               int ret;
+
+               bs_set(mdp4_lcdc_encoder, 1);
+
+               for (i = 0; i < ARRAY_SIZE(mdp4_lcdc_encoder->regs); i++) {
+                       ret = regulator_enable(mdp4_lcdc_encoder->regs[i]);
+                       if (ret)
+                               dev_err(dev->dev, "failed to enable regulator: %d\n", ret);
+               }
+
+               DBG("setting lcdc_clk=%lu", pc);
+               ret = clk_set_rate(mdp4_lcdc_encoder->lcdc_clk, pc);
+               if (ret)
+                       dev_err(dev->dev, "failed to configure lcdc_clk: %d\n", ret);
+               ret = clk_prepare_enable(mdp4_lcdc_encoder->lcdc_clk);
+               if (ret)
+                       dev_err(dev->dev, "failed to enable lcdc_clk: %d\n", ret);
+
+               if (panel)
+                       drm_panel_enable(panel);
+
+               setup_phy(encoder);
+
+               mdp4_write(mdp4_kms, REG_MDP4_LCDC_ENABLE, 1);
+       } else {
+               mdp4_write(mdp4_kms, REG_MDP4_LCDC_ENABLE, 0);
+
+               if (panel)
+                       drm_panel_disable(panel);
+
+               /*
+                * Wait for a vsync so we know the ENABLE=0 latched before
+                * the (connector) source of the vsync's gets disabled,
+                * otherwise we end up in a funny state if we re-enable
+                * before the disable latches, which results that some of
+                * the settings changes for the new modeset (like new
+                * scanout buffer) don't latch properly..
+                */
+               mdp_irq_wait(&mdp4_kms->base, MDP4_IRQ_PRIMARY_VSYNC);
+
+               clk_disable_unprepare(mdp4_lcdc_encoder->lcdc_clk);
+
+               for (i = 0; i < ARRAY_SIZE(mdp4_lcdc_encoder->regs); i++) {
+                       ret = regulator_disable(mdp4_lcdc_encoder->regs[i]);
+                       if (ret)
+                               dev_err(dev->dev, "failed to disable regulator: %d\n", ret);
+               }
+
+               bs_set(mdp4_lcdc_encoder, 0);
+       }
+
+       mdp4_lcdc_encoder->enabled = enabled;
+}
+
+static bool mdp4_lcdc_encoder_mode_fixup(struct drm_encoder *encoder,
+               const struct drm_display_mode *mode,
+               struct drm_display_mode *adjusted_mode)
+{
+       return true;
+}
+
+static void mdp4_lcdc_encoder_mode_set(struct drm_encoder *encoder,
+               struct drm_display_mode *mode,
+               struct drm_display_mode *adjusted_mode)
+{
+       struct mdp4_lcdc_encoder *mdp4_lcdc_encoder =
+                       to_mdp4_lcdc_encoder(encoder);
+       struct mdp4_kms *mdp4_kms = get_kms(encoder);
+       uint32_t lcdc_hsync_skew, vsync_period, vsync_len, ctrl_pol;
+       uint32_t display_v_start, display_v_end;
+       uint32_t hsync_start_x, hsync_end_x;
+
+       mode = adjusted_mode;
+
+       DBG("set mode: %d:\"%s\" %d %d %d %d %d %d %d %d %d %d 0x%x 0x%x",
+                       mode->base.id, mode->name,
+                       mode->vrefresh, mode->clock,
+                       mode->hdisplay, mode->hsync_start,
+                       mode->hsync_end, mode->htotal,
+                       mode->vdisplay, mode->vsync_start,
+                       mode->vsync_end, mode->vtotal,
+                       mode->type, mode->flags);
+
+       mdp4_lcdc_encoder->pixclock = mode->clock * 1000;
+
+       DBG("pixclock=%lu", mdp4_lcdc_encoder->pixclock);
+
+       ctrl_pol = 0;
+       if (mode->flags & DRM_MODE_FLAG_NHSYNC)
+               ctrl_pol |= MDP4_LCDC_CTRL_POLARITY_HSYNC_LOW;
+       if (mode->flags & DRM_MODE_FLAG_NVSYNC)
+               ctrl_pol |= MDP4_LCDC_CTRL_POLARITY_VSYNC_LOW;
+       /* probably need to get DATA_EN polarity from panel.. */
+
+       lcdc_hsync_skew = 0;  /* get this from panel? */
+
+       hsync_start_x = (mode->htotal - mode->hsync_start);
+       hsync_end_x = mode->htotal - (mode->hsync_start - mode->hdisplay) - 1;
+
+       vsync_period = mode->vtotal * mode->htotal;
+       vsync_len = (mode->vsync_end - mode->vsync_start) * mode->htotal;
+       display_v_start = (mode->vtotal - mode->vsync_start) * mode->htotal + lcdc_hsync_skew;
+       display_v_end = vsync_period - ((mode->vsync_start - mode->vdisplay) * mode->htotal) + lcdc_hsync_skew - 1;
+
+       mdp4_write(mdp4_kms, REG_MDP4_LCDC_HSYNC_CTRL,
+                       MDP4_LCDC_HSYNC_CTRL_PULSEW(mode->hsync_end - mode->hsync_start) |
+                       MDP4_LCDC_HSYNC_CTRL_PERIOD(mode->htotal));
+       mdp4_write(mdp4_kms, REG_MDP4_LCDC_VSYNC_PERIOD, vsync_period);
+       mdp4_write(mdp4_kms, REG_MDP4_LCDC_VSYNC_LEN, vsync_len);
+       mdp4_write(mdp4_kms, REG_MDP4_LCDC_DISPLAY_HCTRL,
+                       MDP4_LCDC_DISPLAY_HCTRL_START(hsync_start_x) |
+                       MDP4_LCDC_DISPLAY_HCTRL_END(hsync_end_x));
+       mdp4_write(mdp4_kms, REG_MDP4_LCDC_DISPLAY_VSTART, display_v_start);
+       mdp4_write(mdp4_kms, REG_MDP4_LCDC_DISPLAY_VEND, display_v_end);
+       mdp4_write(mdp4_kms, REG_MDP4_LCDC_BORDER_CLR, 0);
+       mdp4_write(mdp4_kms, REG_MDP4_LCDC_UNDERFLOW_CLR,
+                       MDP4_LCDC_UNDERFLOW_CLR_ENABLE_RECOVERY |
+                       MDP4_LCDC_UNDERFLOW_CLR_COLOR(0xff));
+       mdp4_write(mdp4_kms, REG_MDP4_LCDC_HSYNC_SKEW, lcdc_hsync_skew);
+       mdp4_write(mdp4_kms, REG_MDP4_LCDC_CTRL_POLARITY, ctrl_pol);
+       mdp4_write(mdp4_kms, REG_MDP4_LCDC_ACTIVE_HCTL,
+                       MDP4_LCDC_ACTIVE_HCTL_START(0) |
+                       MDP4_LCDC_ACTIVE_HCTL_END(0));
+       mdp4_write(mdp4_kms, REG_MDP4_LCDC_ACTIVE_VSTART, 0);
+       mdp4_write(mdp4_kms, REG_MDP4_LCDC_ACTIVE_VEND, 0);
+}
+
+static void mdp4_lcdc_encoder_prepare(struct drm_encoder *encoder)
+{
+       mdp4_lcdc_encoder_dpms(encoder, DRM_MODE_DPMS_OFF);
+}
+
+static void mdp4_lcdc_encoder_commit(struct drm_encoder *encoder)
+{
+       /* TODO: hard-coded for 18bpp: */
+       mdp4_crtc_set_config(encoder->crtc,
+                       MDP4_DMA_CONFIG_R_BPC(BPC6) |
+                       MDP4_DMA_CONFIG_G_BPC(BPC6) |
+                       MDP4_DMA_CONFIG_B_BPC(BPC6) |
+                       MDP4_DMA_CONFIG_PACK_ALIGN_MSB |
+                       MDP4_DMA_CONFIG_PACK(0x21) |
+                       MDP4_DMA_CONFIG_DEFLKR_EN |
+                       MDP4_DMA_CONFIG_DITHER_EN);
+       mdp4_crtc_set_intf(encoder->crtc, INTF_LCDC_DTV, 0);
+       mdp4_lcdc_encoder_dpms(encoder, DRM_MODE_DPMS_ON);
+}
+
+static const struct drm_encoder_helper_funcs mdp4_lcdc_encoder_helper_funcs = {
+       .dpms = mdp4_lcdc_encoder_dpms,
+       .mode_fixup = mdp4_lcdc_encoder_mode_fixup,
+       .mode_set = mdp4_lcdc_encoder_mode_set,
+       .prepare = mdp4_lcdc_encoder_prepare,
+       .commit = mdp4_lcdc_encoder_commit,
+};
+
+long mdp4_lcdc_round_pixclk(struct drm_encoder *encoder, unsigned long rate)
+{
+       struct mdp4_lcdc_encoder *mdp4_lcdc_encoder =
+                       to_mdp4_lcdc_encoder(encoder);
+       return clk_round_rate(mdp4_lcdc_encoder->lcdc_clk, rate);
+}
+
+/* initialize encoder */
+struct drm_encoder *mdp4_lcdc_encoder_init(struct drm_device *dev,
+               struct drm_panel *panel)
+{
+       struct drm_encoder *encoder = NULL;
+       struct mdp4_lcdc_encoder *mdp4_lcdc_encoder;
+       struct regulator *reg;
+       int ret;
+
+       mdp4_lcdc_encoder = kzalloc(sizeof(*mdp4_lcdc_encoder), GFP_KERNEL);
+       if (!mdp4_lcdc_encoder) {
+               ret = -ENOMEM;
+               goto fail;
+       }
+
+       mdp4_lcdc_encoder->panel = panel;
+
+       encoder = &mdp4_lcdc_encoder->base;
+
+       drm_encoder_init(dev, encoder, &mdp4_lcdc_encoder_funcs,
+                        DRM_MODE_ENCODER_LVDS);
+       drm_encoder_helper_add(encoder, &mdp4_lcdc_encoder_helper_funcs);
+
+       /* TODO: do we need different pll in other cases? */
+       mdp4_lcdc_encoder->lcdc_clk = mpd4_lvds_pll_init(dev);
+       if (IS_ERR(mdp4_lcdc_encoder->lcdc_clk)) {
+               dev_err(dev->dev, "failed to get lvds_clk\n");
+               ret = PTR_ERR(mdp4_lcdc_encoder->lcdc_clk);
+               goto fail;
+       }
+
+       /* TODO: different regulators in other cases? */
+       reg = devm_regulator_get(dev->dev, "lvds-vccs-3p3v");
+       if (IS_ERR(reg)) {
+               ret = PTR_ERR(reg);
+               dev_err(dev->dev, "failed to get lvds-vccs-3p3v: %d\n", ret);
+               goto fail;
+       }
+       mdp4_lcdc_encoder->regs[0] = reg;
+
+       reg = devm_regulator_get(dev->dev, "lvds-pll-vdda");
+       if (IS_ERR(reg)) {
+               ret = PTR_ERR(reg);
+               dev_err(dev->dev, "failed to get lvds-pll-vdda: %d\n", ret);
+               goto fail;
+       }
+       mdp4_lcdc_encoder->regs[1] = reg;
+
+       reg = devm_regulator_get(dev->dev, "lvds-vdda");
+       if (IS_ERR(reg)) {
+               ret = PTR_ERR(reg);
+               dev_err(dev->dev, "failed to get lvds-vdda: %d\n", ret);
+               goto fail;
+       }
+       mdp4_lcdc_encoder->regs[2] = reg;
+
+       bs_init(mdp4_lcdc_encoder);
+
+       return encoder;
+
+fail:
+       if (encoder)
+               mdp4_lcdc_encoder_destroy(encoder);
+
+       return ERR_PTR(ret);
+}
diff --git a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_lvds_connector.c b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_lvds_connector.c
new file mode 100644 (file)
index 0000000..3100346
--- /dev/null
@@ -0,0 +1,151 @@
+/*
+ * Copyright (C) 2014 Red Hat
+ * Author: Rob Clark <robdclark@gmail.com>
+ * Author: Vinay Simha <vinaysimha@inforcecomputing.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/gpio.h>
+
+#include "mdp4_kms.h"
+
+struct mdp4_lvds_connector {
+       struct drm_connector base;
+       struct drm_encoder *encoder;
+       struct drm_panel *panel;
+};
+#define to_mdp4_lvds_connector(x) container_of(x, struct mdp4_lvds_connector, base)
+
+static enum drm_connector_status mdp4_lvds_connector_detect(
+               struct drm_connector *connector, bool force)
+{
+       struct mdp4_lvds_connector *mdp4_lvds_connector =
+                       to_mdp4_lvds_connector(connector);
+
+       return mdp4_lvds_connector->panel ?
+                       connector_status_connected :
+                       connector_status_disconnected;
+}
+
+static void mdp4_lvds_connector_destroy(struct drm_connector *connector)
+{
+       struct mdp4_lvds_connector *mdp4_lvds_connector =
+                       to_mdp4_lvds_connector(connector);
+       struct drm_panel *panel = mdp4_lvds_connector->panel;
+
+       if (panel)
+               drm_panel_detach(panel);
+
+       drm_connector_unregister(connector);
+       drm_connector_cleanup(connector);
+
+       kfree(mdp4_lvds_connector);
+}
+
+static int mdp4_lvds_connector_get_modes(struct drm_connector *connector)
+{
+       struct mdp4_lvds_connector *mdp4_lvds_connector =
+                       to_mdp4_lvds_connector(connector);
+       struct drm_panel *panel = mdp4_lvds_connector->panel;
+       int ret = 0;
+
+       if (panel)
+               ret = panel->funcs->get_modes(panel);
+
+       return ret;
+}
+
+static int mdp4_lvds_connector_mode_valid(struct drm_connector *connector,
+                                struct drm_display_mode *mode)
+{
+       struct mdp4_lvds_connector *mdp4_lvds_connector =
+                       to_mdp4_lvds_connector(connector);
+       struct drm_encoder *encoder = mdp4_lvds_connector->encoder;
+       long actual, requested;
+
+       requested = 1000 * mode->clock;
+       actual = mdp4_lcdc_round_pixclk(encoder, requested);
+
+       DBG("requested=%ld, actual=%ld", requested, actual);
+
+       if (actual != requested)
+               return MODE_CLOCK_RANGE;
+
+       return MODE_OK;
+}
+
+static struct drm_encoder *
+mdp4_lvds_connector_best_encoder(struct drm_connector *connector)
+{
+       struct mdp4_lvds_connector *mdp4_lvds_connector =
+                       to_mdp4_lvds_connector(connector);
+       return mdp4_lvds_connector->encoder;
+}
+
+static const struct drm_connector_funcs mdp4_lvds_connector_funcs = {
+       .dpms = drm_helper_connector_dpms,
+       .detect = mdp4_lvds_connector_detect,
+       .fill_modes = drm_helper_probe_single_connector_modes,
+       .destroy = mdp4_lvds_connector_destroy,
+};
+
+static const struct drm_connector_helper_funcs mdp4_lvds_connector_helper_funcs = {
+       .get_modes = mdp4_lvds_connector_get_modes,
+       .mode_valid = mdp4_lvds_connector_mode_valid,
+       .best_encoder = mdp4_lvds_connector_best_encoder,
+};
+
+/* initialize connector */
+struct drm_connector *mdp4_lvds_connector_init(struct drm_device *dev,
+               struct drm_panel *panel, struct drm_encoder *encoder)
+{
+       struct drm_connector *connector = NULL;
+       struct mdp4_lvds_connector *mdp4_lvds_connector;
+       int ret;
+
+       mdp4_lvds_connector = kzalloc(sizeof(*mdp4_lvds_connector), GFP_KERNEL);
+       if (!mdp4_lvds_connector) {
+               ret = -ENOMEM;
+               goto fail;
+       }
+
+       mdp4_lvds_connector->encoder = encoder;
+       mdp4_lvds_connector->panel = panel;
+
+       connector = &mdp4_lvds_connector->base;
+
+       drm_connector_init(dev, connector, &mdp4_lvds_connector_funcs,
+                       DRM_MODE_CONNECTOR_LVDS);
+       drm_connector_helper_add(connector, &mdp4_lvds_connector_helper_funcs);
+
+       connector->polled = 0;
+
+       connector->interlace_allowed = 0;
+       connector->doublescan_allowed = 0;
+
+       drm_connector_register(connector);
+
+       drm_mode_connector_attach_encoder(connector, encoder);
+
+       if (panel)
+               drm_panel_attach(panel, connector);
+
+       return connector;
+
+fail:
+       if (connector)
+               mdp4_lvds_connector_destroy(connector);
+
+       return ERR_PTR(ret);
+}
diff --git a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_lvds_pll.c b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_lvds_pll.c
new file mode 100644 (file)
index 0000000..ce42459
--- /dev/null
@@ -0,0 +1,172 @@
+/*
+ * Copyright (C) 2014 Red Hat
+ * Author: Rob Clark <robdclark@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.
+ *
+ * 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/clk.h>
+#include <linux/clk-provider.h>
+
+#include "mdp4_kms.h"
+
+struct mdp4_lvds_pll {
+       struct clk_hw pll_hw;
+       struct drm_device *dev;
+       unsigned long pixclk;
+};
+#define to_mdp4_lvds_pll(x) container_of(x, struct mdp4_lvds_pll, pll_hw)
+
+static struct mdp4_kms *get_kms(struct mdp4_lvds_pll *lvds_pll)
+{
+       struct msm_drm_private *priv = lvds_pll->dev->dev_private;
+       return to_mdp4_kms(to_mdp_kms(priv->kms));
+}
+
+struct pll_rate {
+       unsigned long rate;
+       struct {
+               uint32_t val;
+               uint32_t reg;
+       } conf[32];
+};
+
+/* NOTE: keep sorted highest freq to lowest: */
+static const struct pll_rate freqtbl[] = {
+       { 72000000, {
+               { 0x8f, REG_MDP4_LVDS_PHY_PLL_CTRL_1 },
+               { 0x30, REG_MDP4_LVDS_PHY_PLL_CTRL_2 },
+               { 0xc6, REG_MDP4_LVDS_PHY_PLL_CTRL_3 },
+               { 0x10, REG_MDP4_LVDS_PHY_PLL_CTRL_5 },
+               { 0x07, REG_MDP4_LVDS_PHY_PLL_CTRL_6 },
+               { 0x62, REG_MDP4_LVDS_PHY_PLL_CTRL_7 },
+               { 0x41, REG_MDP4_LVDS_PHY_PLL_CTRL_8 },
+               { 0x0d, REG_MDP4_LVDS_PHY_PLL_CTRL_9 },
+               { 0, 0 } }
+       },
+};
+
+static const struct pll_rate *find_rate(unsigned long rate)
+{
+       int i;
+       for (i = 1; i < ARRAY_SIZE(freqtbl); i++)
+               if (rate > freqtbl[i].rate)
+                       return &freqtbl[i-1];
+       return &freqtbl[i-1];
+}
+
+static int mpd4_lvds_pll_enable(struct clk_hw *hw)
+{
+       struct mdp4_lvds_pll *lvds_pll = to_mdp4_lvds_pll(hw);
+       struct mdp4_kms *mdp4_kms = get_kms(lvds_pll);
+       const struct pll_rate *pll_rate = find_rate(lvds_pll->pixclk);
+       int i;
+
+       DBG("pixclk=%lu (%lu)", lvds_pll->pixclk, pll_rate->rate);
+
+       if (WARN_ON(!pll_rate))
+               return -EINVAL;
+
+       mdp4_write(mdp4_kms, REG_MDP4_LCDC_LVDS_PHY_RESET, 0x33);
+
+       for (i = 0; pll_rate->conf[i].reg; i++)
+               mdp4_write(mdp4_kms, pll_rate->conf[i].reg, pll_rate->conf[i].val);
+
+       mdp4_write(mdp4_kms, REG_MDP4_LVDS_PHY_PLL_CTRL_0, 0x01);
+
+       /* Wait until LVDS PLL is locked and ready */
+       while (!mdp4_read(mdp4_kms, REG_MDP4_LVDS_PHY_PLL_LOCKED))
+               cpu_relax();
+
+       return 0;
+}
+
+static void mpd4_lvds_pll_disable(struct clk_hw *hw)
+{
+       struct mdp4_lvds_pll *lvds_pll = to_mdp4_lvds_pll(hw);
+       struct mdp4_kms *mdp4_kms = get_kms(lvds_pll);
+
+       DBG("");
+
+       mdp4_write(mdp4_kms, REG_MDP4_LVDS_PHY_CFG0, 0x0);
+       mdp4_write(mdp4_kms, REG_MDP4_LVDS_PHY_PLL_CTRL_0, 0x0);
+}
+
+static unsigned long mpd4_lvds_pll_recalc_rate(struct clk_hw *hw,
+                               unsigned long parent_rate)
+{
+       struct mdp4_lvds_pll *lvds_pll = to_mdp4_lvds_pll(hw);
+       return lvds_pll->pixclk;
+}
+
+static long mpd4_lvds_pll_round_rate(struct clk_hw *hw, unsigned long rate,
+               unsigned long *parent_rate)
+{
+       const struct pll_rate *pll_rate = find_rate(rate);
+       return pll_rate->rate;
+}
+
+static int mpd4_lvds_pll_set_rate(struct clk_hw *hw, unsigned long rate,
+               unsigned long parent_rate)
+{
+       struct mdp4_lvds_pll *lvds_pll = to_mdp4_lvds_pll(hw);
+       lvds_pll->pixclk = rate;
+       return 0;
+}
+
+
+static const struct clk_ops mpd4_lvds_pll_ops = {
+       .enable = mpd4_lvds_pll_enable,
+       .disable = mpd4_lvds_pll_disable,
+       .recalc_rate = mpd4_lvds_pll_recalc_rate,
+       .round_rate = mpd4_lvds_pll_round_rate,
+       .set_rate = mpd4_lvds_pll_set_rate,
+};
+
+static const char *mpd4_lvds_pll_parents[] = {
+       "pxo",
+};
+
+static struct clk_init_data pll_init = {
+       .name = "mpd4_lvds_pll",
+       .ops = &mpd4_lvds_pll_ops,
+       .parent_names = mpd4_lvds_pll_parents,
+       .num_parents = ARRAY_SIZE(mpd4_lvds_pll_parents),
+};
+
+struct clk *mpd4_lvds_pll_init(struct drm_device *dev)
+{
+       struct mdp4_lvds_pll *lvds_pll;
+       struct clk *clk;
+       int ret;
+
+       lvds_pll = devm_kzalloc(dev->dev, sizeof(*lvds_pll), GFP_KERNEL);
+       if (!lvds_pll) {
+               ret = -ENOMEM;
+               goto fail;
+       }
+
+       lvds_pll->dev = dev;
+
+       lvds_pll->pll_hw.init = &pll_init;
+       clk = devm_clk_register(dev->dev, &lvds_pll->pll_hw);
+       if (IS_ERR(clk)) {
+               ret = PTR_ERR(clk);
+               goto fail;
+       }
+
+       return clk;
+
+fail:
+       return ERR_PTR(ret);
+}
index fcf95680413d5da99c86fed5a44c9c6386ba3350..b67ef59851250f6c442cf1dedfa0a88db5230ce9 100644 (file)
@@ -280,7 +280,7 @@ static int msm_load(struct drm_device *dev, unsigned long flags)
        dev->mode_config.max_height = 2048;
        dev->mode_config.funcs = &mode_config_funcs;
 
-       ret = drm_vblank_init(dev, 1);
+       ret = drm_vblank_init(dev, priv->num_crtcs);
        if (ret < 0) {
                dev_err(dev->dev, "failed to initialize vblank\n");
                goto fail;
@@ -315,39 +315,12 @@ static void load_gpu(struct drm_device *dev)
 {
        static DEFINE_MUTEX(init_lock);
        struct msm_drm_private *priv = dev->dev_private;
-       struct msm_gpu *gpu;
 
        mutex_lock(&init_lock);
 
-       if (priv->gpu)
-               goto out;
-
-       gpu = a3xx_gpu_init(dev);
-       if (IS_ERR(gpu)) {
-               dev_warn(dev->dev, "failed to load a3xx gpu\n");
-               gpu = NULL;
-               /* not fatal */
-       }
-
-       if (gpu) {
-               int ret;
-               mutex_lock(&dev->struct_mutex);
-               gpu->funcs->pm_resume(gpu);
-               mutex_unlock(&dev->struct_mutex);
-               ret = gpu->funcs->hw_init(gpu);
-               if (ret) {
-                       dev_err(dev->dev, "gpu hw init failed: %d\n", ret);
-                       gpu->funcs->destroy(gpu);
-                       gpu = NULL;
-               } else {
-                       /* give inactive pm a chance to kick in: */
-                       msm_gpu_retire(gpu);
-               }
-       }
-
-       priv->gpu = gpu;
+       if (!priv->gpu)
+               priv->gpu = adreno_load_gpu(dev);
 
-out:
        mutex_unlock(&init_lock);
 }
 
@@ -836,6 +809,7 @@ static struct drm_driver msm_driver = {
        .open               = msm_open,
        .preclose           = msm_preclose,
        .lastclose          = msm_lastclose,
+       .set_busid          = drm_platform_set_busid,
        .irq_handler        = msm_irq,
        .irq_preinstall     = msm_irq_preinstall,
        .irq_postinstall    = msm_irq_postinstall,
@@ -1025,7 +999,7 @@ static int __init msm_drm_register(void)
 {
        DBG("init");
        hdmi_register();
-       a3xx_register();
+       adreno_register();
        return platform_driver_register(&msm_platform_driver);
 }
 
@@ -1034,7 +1008,7 @@ static void __exit msm_drm_unregister(void)
        DBG("fini");
        platform_driver_unregister(&msm_platform_driver);
        hdmi_unregister();
-       a3xx_unregister();
+       adreno_unregister();
 }
 
 module_init(msm_drm_register);
index 8a2c5fd0893e07f824b46e2d2d7528e96eca2ace..67f9d0a2332c28b9983d7fe29000f907ffcd87f5 100644 (file)
@@ -51,6 +51,7 @@ static inline struct device *msm_iommu_get_ctx(const char *ctx_name)
 #include <drm/drm_crtc_helper.h>
 #include <drm/drm_fb_helper.h>
 #include <drm/msm_drm.h>
+#include <drm/drm_gem.h>
 
 struct msm_kms;
 struct msm_gpu;
@@ -170,7 +171,7 @@ struct sg_table *msm_gem_prime_get_sg_table(struct drm_gem_object *obj);
 void *msm_gem_prime_vmap(struct drm_gem_object *obj);
 void msm_gem_prime_vunmap(struct drm_gem_object *obj, void *vaddr);
 struct drm_gem_object *msm_gem_prime_import_sg_table(struct drm_device *dev,
-               size_t size, struct sg_table *sg);
+               struct dma_buf_attachment *attach, struct sg_table *sg);
 int msm_gem_prime_pin(struct drm_gem_object *obj);
 void msm_gem_prime_unpin(struct drm_gem_object *obj);
 void *msm_gem_vaddr_locked(struct drm_gem_object *obj);
index d48f9fc5129bfbd1b8d8b60842c7272f72eadc5f..ad772fe36115f69c47aaca1f1caa2c2356a8bd01 100644 (file)
@@ -18,6 +18,7 @@
 #include "msm_drv.h"
 #include "msm_gem.h"
 
+#include <linux/dma-buf.h>
 
 struct sg_table *msm_gem_prime_get_sg_table(struct drm_gem_object *obj)
 {
@@ -37,9 +38,9 @@ void msm_gem_prime_vunmap(struct drm_gem_object *obj, void *vaddr)
 }
 
 struct drm_gem_object *msm_gem_prime_import_sg_table(struct drm_device *dev,
-               size_t size, struct sg_table *sg)
+               struct dma_buf_attachment *attach, struct sg_table *sg)
 {
-       return msm_gem_import(dev, size, sg);
+       return msm_gem_import(dev, attach->dmabuf->size, sg);
 }
 
 int msm_gem_prime_pin(struct drm_gem_object *obj)
index 9b579b792840fb8d1c84bc1176ee7c992ab5e731..fd1e4b4a6d402f56b754427bc2066bc7de8e77ce 100644 (file)
@@ -166,8 +166,8 @@ int msm_gpu_init(struct drm_device *drm, struct platform_device *pdev,
                const char *name, const char *ioname, const char *irqname, int ringsz);
 void msm_gpu_cleanup(struct msm_gpu *gpu);
 
-struct msm_gpu *a3xx_gpu_init(struct drm_device *dev);
-void __init a3xx_register(void);
-void __exit a3xx_unregister(void);
+struct msm_gpu *adreno_load_gpu(struct drm_device *dev);
+void __init adreno_register(void);
+void __exit adreno_unregister(void);
 
 #endif /* __MSM_GPU_H__ */
index f5d7f7ce4bc6b4b36d783cc1ec10d1680e5a5cd3..12c24c8abf7f54ab8c94af874b6220a931053d45 100644 (file)
@@ -38,6 +38,7 @@ nouveau-y += core/subdev/bios/dcb.o
 nouveau-y += core/subdev/bios/disp.o
 nouveau-y += core/subdev/bios/dp.o
 nouveau-y += core/subdev/bios/extdev.o
+nouveau-y += core/subdev/bios/fan.o
 nouveau-y += core/subdev/bios/gpio.o
 nouveau-y += core/subdev/bios/i2c.o
 nouveau-y += core/subdev/bios/init.o
@@ -51,6 +52,8 @@ nouveau-y += core/subdev/bios/therm.o
 nouveau-y += core/subdev/bios/vmap.o
 nouveau-y += core/subdev/bios/volt.o
 nouveau-y += core/subdev/bios/xpio.o
+nouveau-y += core/subdev/bios/M0205.o
+nouveau-y += core/subdev/bios/M0209.o
 nouveau-y += core/subdev/bios/P0260.o
 nouveau-y += core/subdev/bus/hwsq.o
 nouveau-y += core/subdev/bus/nv04.o
@@ -124,12 +127,17 @@ nouveau-y += core/subdev/fb/ramnvc0.o
 nouveau-y += core/subdev/fb/ramnve0.o
 nouveau-y += core/subdev/fb/ramgk20a.o
 nouveau-y += core/subdev/fb/ramgm107.o
+nouveau-y += core/subdev/fb/sddr2.o
 nouveau-y += core/subdev/fb/sddr3.o
 nouveau-y += core/subdev/fb/gddr5.o
+nouveau-y += core/subdev/fuse/base.o
+nouveau-y += core/subdev/fuse/g80.o
+nouveau-y += core/subdev/fuse/gf100.o
+nouveau-y += core/subdev/fuse/gm107.o
 nouveau-y += core/subdev/gpio/base.o
 nouveau-y += core/subdev/gpio/nv10.o
 nouveau-y += core/subdev/gpio/nv50.o
-nouveau-y += core/subdev/gpio/nv92.o
+nouveau-y += core/subdev/gpio/nv94.o
 nouveau-y += core/subdev/gpio/nvd0.o
 nouveau-y += core/subdev/gpio/nve0.o
 nouveau-y += core/subdev/i2c/base.o
@@ -190,6 +198,7 @@ nouveau-y += core/subdev/therm/nv50.o
 nouveau-y += core/subdev/therm/nv84.o
 nouveau-y += core/subdev/therm/nva3.o
 nouveau-y += core/subdev/therm/nvd0.o
+nouveau-y += core/subdev/therm/gm107.o
 nouveau-y += core/subdev/timer/base.o
 nouveau-y += core/subdev/timer/nv04.o
 nouveau-y += core/subdev/timer/gk20a.o
@@ -252,6 +261,7 @@ nouveau-y += core/engine/disp/hdanvd0.o
 nouveau-y += core/engine/disp/hdminv84.o
 nouveau-y += core/engine/disp/hdminva3.o
 nouveau-y += core/engine/disp/hdminvd0.o
+nouveau-y += core/engine/disp/hdminve0.o
 nouveau-y += core/engine/disp/piornv50.o
 nouveau-y += core/engine/disp/sornv50.o
 nouveau-y += core/engine/disp/sornv94.o
index 68bf06768123bb2d2fa92b0bf7777a28ad08f9c8..e962433294c317efb1e27f678d705092708c7e65 100644 (file)
@@ -91,9 +91,10 @@ nvkm_client_notify_del(struct nouveau_client *client, int index)
 }
 
 int
-nvkm_client_notify_new(struct nouveau_client *client,
+nvkm_client_notify_new(struct nouveau_object *object,
                       struct nvkm_event *event, void *data, u32 size)
 {
+       struct nouveau_client *client = nouveau_client(object);
        struct nvkm_client_notify *notify;
        union {
                struct nvif_notify_req_v0 v0;
@@ -127,8 +128,8 @@ nvkm_client_notify_new(struct nouveau_client *client,
        }
 
        if (ret == 0) {
-               ret = nvkm_notify_init(event, nvkm_client_notify, false,
-                                      data, size, reply, &notify->n);
+               ret = nvkm_notify_init(object, event, nvkm_client_notify,
+                                      false, data, size, reply, &notify->n);
                if (ret == 0) {
                        client->notify[index] = notify;
                        notify->client = client;
index 0540a48c5678e450f1fc6397948d17db59ccd560..ff2b434b3db480a47aa5b94515476714b2819693 100644 (file)
@@ -20,7 +20,7 @@
  * OTHER DEALINGS IN THE SOFTWARE.
  */
 
-#include <core/os.h>
+#include <core/object.h>
 #include <core/event.h>
 
 void
index 560b2214cf1cc6fefed5d21dd5e0ded550df7666..daee877025029d62b2023a5fe018d72cf6491d9a 100644 (file)
@@ -115,7 +115,7 @@ nouveau_gpuobj_create_(struct nouveau_object *parent,
        gpuobj->size = size;
 
        if (heap) {
-               ret = nouveau_mm_head(heap, 1, size, size,
+               ret = nouveau_mm_head(heap, 0, 1, size, size,
                                      max(align, (u32)1), &gpuobj->node);
                if (ret)
                        return ret;
index f7e19bfb489c6920ae6ea6d4231b1affc8fab86c..692aa92dd850edabb7c53d1002e02e2b5cd1265d 100644 (file)
@@ -349,7 +349,6 @@ nvkm_ioctl_unmap(struct nouveau_handle *handle, void *data, u32 size)
 static int
 nvkm_ioctl_ntfy_new(struct nouveau_handle *handle, void *data, u32 size)
 {
-       struct nouveau_client *client = nouveau_client(handle->object);
        struct nouveau_object *object = handle->object;
        struct nouveau_ofuncs *ofuncs = object->oclass->ofuncs;
        union {
@@ -365,7 +364,7 @@ nvkm_ioctl_ntfy_new(struct nouveau_handle *handle, void *data, u32 size)
                if (ret = -ENODEV, ofuncs->ntfy)
                        ret = ofuncs->ntfy(object, args->v0.event, &event);
                if (ret == 0) {
-                       ret = nvkm_client_notify_new(client, event, data, size);
+                       ret = nvkm_client_notify_new(object, event, data, size);
                        if (ret >= 0) {
                                args->v0.index = ret;
                                ret = 0;
index 7a4e0891c5f872e0dbda7dc5164b348aa59058c7..b4f5db66d5b545b58b351a5681f8509a5e7e71c1 100644 (file)
 #define node(root, dir) ((root)->nl_entry.dir == &mm->nodes) ? NULL : \
        list_entry((root)->nl_entry.dir, struct nouveau_mm_node, nl_entry)
 
+static void
+nouveau_mm_dump(struct nouveau_mm *mm, const char *header)
+{
+       struct nouveau_mm_node *node;
+
+       printk(KERN_ERR "nouveau: %s\n", header);
+       printk(KERN_ERR "nouveau: node list:\n");
+       list_for_each_entry(node, &mm->nodes, nl_entry) {
+               printk(KERN_ERR "nouveau: \t%08x %08x %d\n",
+                      node->offset, node->length, node->type);
+       }
+       printk(KERN_ERR "nouveau: free list:\n");
+       list_for_each_entry(node, &mm->free, fl_entry) {
+               printk(KERN_ERR "nouveau: \t%08x %08x %d\n",
+                      node->offset, node->length, node->type);
+       }
+}
+
 void
 nouveau_mm_free(struct nouveau_mm *mm, struct nouveau_mm_node **pthis)
 {
@@ -37,29 +55,29 @@ nouveau_mm_free(struct nouveau_mm *mm, struct nouveau_mm_node **pthis)
                struct nouveau_mm_node *prev = node(this, prev);
                struct nouveau_mm_node *next = node(this, next);
 
-               if (prev && prev->type == 0) {
+               if (prev && prev->type == NVKM_MM_TYPE_NONE) {
                        prev->length += this->length;
                        list_del(&this->nl_entry);
                        kfree(this); this = prev;
                }
 
-               if (next && next->type == 0) {
+               if (next && next->type == NVKM_MM_TYPE_NONE) {
                        next->offset  = this->offset;
                        next->length += this->length;
-                       if (this->type == 0)
+                       if (this->type == NVKM_MM_TYPE_NONE)
                                list_del(&this->fl_entry);
                        list_del(&this->nl_entry);
                        kfree(this); this = NULL;
                }
 
-               if (this && this->type != 0) {
+               if (this && this->type != NVKM_MM_TYPE_NONE) {
                        list_for_each_entry(prev, &mm->free, fl_entry) {
                                if (this->offset < prev->offset)
                                        break;
                        }
 
                        list_add_tail(&this->fl_entry, &prev->fl_entry);
-                       this->type = 0;
+                       this->type = NVKM_MM_TYPE_NONE;
                }
        }
 
@@ -80,27 +98,32 @@ region_head(struct nouveau_mm *mm, struct nouveau_mm_node *a, u32 size)
 
        b->offset = a->offset;
        b->length = size;
+       b->heap   = a->heap;
        b->type   = a->type;
        a->offset += size;
        a->length -= size;
        list_add_tail(&b->nl_entry, &a->nl_entry);
-       if (b->type == 0)
+       if (b->type == NVKM_MM_TYPE_NONE)
                list_add_tail(&b->fl_entry, &a->fl_entry);
        return b;
 }
 
 int
-nouveau_mm_head(struct nouveau_mm *mm, u8 type, u32 size_max, u32 size_min,
-               u32 align, struct nouveau_mm_node **pnode)
+nouveau_mm_head(struct nouveau_mm *mm, u8 heap, u8 type, u32 size_max,
+               u32 size_min, u32 align, struct nouveau_mm_node **pnode)
 {
        struct nouveau_mm_node *prev, *this, *next;
        u32 mask = align - 1;
        u32 splitoff;
        u32 s, e;
 
-       BUG_ON(!type);
+       BUG_ON(type == NVKM_MM_TYPE_NONE || type == NVKM_MM_TYPE_HOLE);
 
        list_for_each_entry(this, &mm->free, fl_entry) {
+               if (unlikely(heap != NVKM_MM_HEAP_ANY)) {
+                       if (this->heap != heap)
+                               continue;
+               }
                e = this->offset + this->length;
                s = this->offset;
 
@@ -149,27 +172,32 @@ region_tail(struct nouveau_mm *mm, struct nouveau_mm_node *a, u32 size)
        a->length -= size;
        b->offset  = a->offset + a->length;
        b->length  = size;
+       b->heap    = a->heap;
        b->type    = a->type;
 
        list_add(&b->nl_entry, &a->nl_entry);
-       if (b->type == 0)
+       if (b->type == NVKM_MM_TYPE_NONE)
                list_add(&b->fl_entry, &a->fl_entry);
        return b;
 }
 
 int
-nouveau_mm_tail(struct nouveau_mm *mm, u8 type, u32 size_max, u32 size_min,
-               u32 align, struct nouveau_mm_node **pnode)
+nouveau_mm_tail(struct nouveau_mm *mm, u8 heap, u8 type, u32 size_max,
+               u32 size_min, u32 align, struct nouveau_mm_node **pnode)
 {
        struct nouveau_mm_node *prev, *this, *next;
        u32 mask = align - 1;
 
-       BUG_ON(!type);
+       BUG_ON(type == NVKM_MM_TYPE_NONE || type == NVKM_MM_TYPE_HOLE);
 
        list_for_each_entry_reverse(this, &mm->free, fl_entry) {
                u32 e = this->offset + this->length;
                u32 s = this->offset;
                u32 c = 0, a;
+               if (unlikely(heap != NVKM_MM_HEAP_ANY)) {
+                       if (this->heap != heap)
+                               continue;
+               }
 
                prev = node(this, prev);
                if (prev && prev->type != type)
@@ -209,9 +237,23 @@ nouveau_mm_tail(struct nouveau_mm *mm, u8 type, u32 size_max, u32 size_min,
 int
 nouveau_mm_init(struct nouveau_mm *mm, u32 offset, u32 length, u32 block)
 {
-       struct nouveau_mm_node *node;
+       struct nouveau_mm_node *node, *prev;
+       u32 next;
 
-       if (block) {
+       if (nouveau_mm_initialised(mm)) {
+               prev = list_last_entry(&mm->nodes, typeof(*node), nl_entry);
+               next = prev->offset + prev->length;
+               if (next != offset) {
+                       BUG_ON(next > offset);
+                       if (!(node = kzalloc(sizeof(*node), GFP_KERNEL)))
+                               return -ENOMEM;
+                       node->type   = NVKM_MM_TYPE_HOLE;
+                       node->offset = next;
+                       node->length = offset - next;
+                       list_add_tail(&node->nl_entry, &mm->nodes);
+               }
+               BUG_ON(block != mm->block_size);
+       } else {
                INIT_LIST_HEAD(&mm->nodes);
                INIT_LIST_HEAD(&mm->free);
                mm->block_size = block;
@@ -230,25 +272,32 @@ nouveau_mm_init(struct nouveau_mm *mm, u32 offset, u32 length, u32 block)
 
        list_add_tail(&node->nl_entry, &mm->nodes);
        list_add_tail(&node->fl_entry, &mm->free);
-       mm->heap_nodes++;
+       node->heap = ++mm->heap_nodes;
        return 0;
 }
 
 int
 nouveau_mm_fini(struct nouveau_mm *mm)
 {
-       if (nouveau_mm_initialised(mm)) {
-               struct nouveau_mm_node *node, *heap =
-                       list_first_entry(&mm->nodes, typeof(*heap), nl_entry);
-               int nodes = 0;
+       struct nouveau_mm_node *node, *temp;
+       int nodes = 0;
 
-               list_for_each_entry(node, &mm->nodes, nl_entry) {
-                       if (WARN_ON(nodes++ == mm->heap_nodes))
+       if (!nouveau_mm_initialised(mm))
+               return 0;
+
+       list_for_each_entry(node, &mm->nodes, nl_entry) {
+               if (node->type != NVKM_MM_TYPE_HOLE) {
+                       if (++nodes > mm->heap_nodes) {
+                               nouveau_mm_dump(mm, "mm not clean!");
                                return -EBUSY;
+                       }
                }
-
-               kfree(heap);
        }
 
+       list_for_each_entry_safe(node, temp, &mm->nodes, nl_entry) {
+               list_del(&node->nl_entry);
+               kfree(node);
+       }
+       mm->heap_nodes = 0;
        return 0;
 }
index 76adb81bdea21d2fc2c6f22fd30686a8395bfd03..d1bcde55e9d734df7573366a21f87e8b40a5f18b 100644 (file)
@@ -134,14 +134,15 @@ nvkm_notify_fini(struct nvkm_notify *notify)
 }
 
 int
-nvkm_notify_init(struct nvkm_event *event, int (*func)(struct nvkm_notify *),
-                bool work, void *data, u32 size, u32 reply,
+nvkm_notify_init(struct nouveau_object *object, struct nvkm_event *event,
+                int (*func)(struct nvkm_notify *), bool work,
+                void *data, u32 size, u32 reply,
                 struct nvkm_notify *notify)
 {
        unsigned long flags;
        int ret = -ENODEV;
        if ((notify->event = event), event->refs) {
-               ret = event->func->ctor(data, size, notify);
+               ret = event->func->ctor(object, data, size, notify);
                if (ret == 0 && (ret = -EINVAL, notify->size == reply)) {
                        notify->flags = 0;
                        notify->block = 1;
index 8928f7981d4ada8eb4a7758878504e61b5a668ca..0ef5a5713182bc5e8d05a45ad8670672286d945b 100644 (file)
@@ -505,7 +505,8 @@ nouveau_device_sclass[] = {
 };
 
 static int
-nouveau_device_event_ctor(void *data, u32 size, struct nvkm_notify *notify)
+nouveau_device_event_ctor(struct nouveau_object *object, void *data, u32 size,
+                         struct nvkm_notify *notify)
 {
        if (!WARN_ON(size != 0)) {
                notify->size  = 0;
index 377ec0b8851e8a2d8606b1f461dfd302fc6b99c0..6295668e29a5897a45e08d2ce09efac9c5aac721 100644 (file)
@@ -26,6 +26,7 @@
 #include <subdev/bus.h>
 #include <subdev/gpio.h>
 #include <subdev/i2c.h>
+#include <subdev/fuse.h>
 #include <subdev/clock.h>
 #include <subdev/therm.h>
 #include <subdev/mxm.h>
@@ -62,10 +63,9 @@ gm100_identify(struct nouveau_device *device)
                device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
                device->oclass[NVDEV_SUBDEV_GPIO   ] =  nve0_gpio_oclass;
                device->oclass[NVDEV_SUBDEV_I2C    ] =  nvd0_i2c_oclass;
+               device->oclass[NVDEV_SUBDEV_FUSE   ] = &gm107_fuse_oclass;
                device->oclass[NVDEV_SUBDEV_CLOCK  ] = &nve0_clock_oclass;
-#if 0
-               device->oclass[NVDEV_SUBDEV_THERM  ] = &nvd0_therm_oclass;
-#endif
+               device->oclass[NVDEV_SUBDEV_THERM  ] = &gm107_therm_oclass;
                device->oclass[NVDEV_SUBDEV_MXM    ] = &nv50_mxm_oclass;
                device->oclass[NVDEV_SUBDEV_DEVINIT] =  gm107_devinit_oclass;
                device->oclass[NVDEV_SUBDEV_MC     ] =  gk20a_mc_oclass;
@@ -77,8 +77,9 @@ gm100_identify(struct nouveau_device *device)
                device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv50_instmem_oclass;
                device->oclass[NVDEV_SUBDEV_VM     ] = &nvc0_vmmgr_oclass;
                device->oclass[NVDEV_SUBDEV_BAR    ] = &nvc0_bar_oclass;
-#if 0
                device->oclass[NVDEV_SUBDEV_PWR    ] =  nv108_pwr_oclass;
+
+#if 0
                device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
 #endif
                device->oclass[NVDEV_ENGINE_DMAOBJ ] =  nvd0_dmaeng_oclass;
index 932f84fae4591c88c46164875afe76785a60476d..96f568d1321bc8d44abca71d98956a8dc3b01799 100644 (file)
@@ -26,6 +26,7 @@
 #include <subdev/bus.h>
 #include <subdev/gpio.h>
 #include <subdev/i2c.h>
+#include <subdev/fuse.h>
 #include <subdev/clock.h>
 #include <subdev/therm.h>
 #include <subdev/mxm.h>
@@ -62,6 +63,7 @@ nv50_identify(struct nouveau_device *device)
                device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
                device->oclass[NVDEV_SUBDEV_GPIO   ] =  nv50_gpio_oclass;
                device->oclass[NVDEV_SUBDEV_I2C    ] =  nv50_i2c_oclass;
+               device->oclass[NVDEV_SUBDEV_FUSE   ] =  &g80_fuse_oclass;
                device->oclass[NVDEV_SUBDEV_CLOCK  ] =  nv50_clock_oclass;
                device->oclass[NVDEV_SUBDEV_THERM  ] = &nv50_therm_oclass;
                device->oclass[NVDEV_SUBDEV_MXM    ] = &nv50_mxm_oclass;
@@ -87,6 +89,7 @@ nv50_identify(struct nouveau_device *device)
                device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
                device->oclass[NVDEV_SUBDEV_GPIO   ] =  nv50_gpio_oclass;
                device->oclass[NVDEV_SUBDEV_I2C    ] =  nv50_i2c_oclass;
+               device->oclass[NVDEV_SUBDEV_FUSE   ] =  &g80_fuse_oclass;
                device->oclass[NVDEV_SUBDEV_CLOCK  ] =  nv84_clock_oclass;
                device->oclass[NVDEV_SUBDEV_THERM  ] = &nv84_therm_oclass;
                device->oclass[NVDEV_SUBDEV_MXM    ] = &nv50_mxm_oclass;
@@ -115,6 +118,7 @@ nv50_identify(struct nouveau_device *device)
                device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
                device->oclass[NVDEV_SUBDEV_GPIO   ] =  nv50_gpio_oclass;
                device->oclass[NVDEV_SUBDEV_I2C    ] =  nv50_i2c_oclass;
+               device->oclass[NVDEV_SUBDEV_FUSE   ] =  &g80_fuse_oclass;
                device->oclass[NVDEV_SUBDEV_CLOCK  ] =  nv84_clock_oclass;
                device->oclass[NVDEV_SUBDEV_THERM  ] = &nv84_therm_oclass;
                device->oclass[NVDEV_SUBDEV_MXM    ] = &nv50_mxm_oclass;
@@ -141,8 +145,9 @@ nv50_identify(struct nouveau_device *device)
        case 0x92:
                device->cname = "G92";
                device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
-               device->oclass[NVDEV_SUBDEV_GPIO   ] =  nv92_gpio_oclass;
+               device->oclass[NVDEV_SUBDEV_GPIO   ] =  nv50_gpio_oclass;
                device->oclass[NVDEV_SUBDEV_I2C    ] =  nv50_i2c_oclass;
+               device->oclass[NVDEV_SUBDEV_FUSE   ] =  &g80_fuse_oclass;
                device->oclass[NVDEV_SUBDEV_CLOCK  ] =  nv84_clock_oclass;
                device->oclass[NVDEV_SUBDEV_THERM  ] = &nv84_therm_oclass;
                device->oclass[NVDEV_SUBDEV_MXM    ] = &nv50_mxm_oclass;
@@ -169,8 +174,9 @@ nv50_identify(struct nouveau_device *device)
        case 0x94:
                device->cname = "G94";
                device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
-               device->oclass[NVDEV_SUBDEV_GPIO   ] =  nv92_gpio_oclass;
+               device->oclass[NVDEV_SUBDEV_GPIO   ] =  nv94_gpio_oclass;
                device->oclass[NVDEV_SUBDEV_I2C    ] =  nv94_i2c_oclass;
+               device->oclass[NVDEV_SUBDEV_FUSE   ] =  &g80_fuse_oclass;
                device->oclass[NVDEV_SUBDEV_CLOCK  ] =  nv84_clock_oclass;
                device->oclass[NVDEV_SUBDEV_THERM  ] = &nv84_therm_oclass;
                device->oclass[NVDEV_SUBDEV_MXM    ] = &nv50_mxm_oclass;
@@ -197,8 +203,9 @@ nv50_identify(struct nouveau_device *device)
        case 0x96:
                device->cname = "G96";
                device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
-               device->oclass[NVDEV_SUBDEV_GPIO   ] =  nv92_gpio_oclass;
+               device->oclass[NVDEV_SUBDEV_GPIO   ] =  nv94_gpio_oclass;
                device->oclass[NVDEV_SUBDEV_I2C    ] =  nv94_i2c_oclass;
+               device->oclass[NVDEV_SUBDEV_FUSE   ] =  &g80_fuse_oclass;
                device->oclass[NVDEV_SUBDEV_CLOCK  ] =  nv84_clock_oclass;
                device->oclass[NVDEV_SUBDEV_THERM  ] = &nv84_therm_oclass;
                device->oclass[NVDEV_SUBDEV_MXM    ] = &nv50_mxm_oclass;
@@ -225,8 +232,9 @@ nv50_identify(struct nouveau_device *device)
        case 0x98:
                device->cname = "G98";
                device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
-               device->oclass[NVDEV_SUBDEV_GPIO   ] =  nv92_gpio_oclass;
+               device->oclass[NVDEV_SUBDEV_GPIO   ] =  nv94_gpio_oclass;
                device->oclass[NVDEV_SUBDEV_I2C    ] =  nv94_i2c_oclass;
+               device->oclass[NVDEV_SUBDEV_FUSE   ] =  &g80_fuse_oclass;
                device->oclass[NVDEV_SUBDEV_CLOCK  ] =  nv84_clock_oclass;
                device->oclass[NVDEV_SUBDEV_THERM  ] = &nv84_therm_oclass;
                device->oclass[NVDEV_SUBDEV_MXM    ] = &nv50_mxm_oclass;
@@ -253,8 +261,9 @@ nv50_identify(struct nouveau_device *device)
        case 0xa0:
                device->cname = "G200";
                device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
-               device->oclass[NVDEV_SUBDEV_GPIO   ] =  nv92_gpio_oclass;
+               device->oclass[NVDEV_SUBDEV_GPIO   ] =  nv94_gpio_oclass;
                device->oclass[NVDEV_SUBDEV_I2C    ] =  nv50_i2c_oclass;
+               device->oclass[NVDEV_SUBDEV_FUSE   ] =  &g80_fuse_oclass;
                device->oclass[NVDEV_SUBDEV_CLOCK  ] =  nv84_clock_oclass;
                device->oclass[NVDEV_SUBDEV_THERM  ] = &nv84_therm_oclass;
                device->oclass[NVDEV_SUBDEV_MXM    ] = &nv50_mxm_oclass;
@@ -281,8 +290,9 @@ nv50_identify(struct nouveau_device *device)
        case 0xaa:
                device->cname = "MCP77/MCP78";
                device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
-               device->oclass[NVDEV_SUBDEV_GPIO   ] =  nv92_gpio_oclass;
+               device->oclass[NVDEV_SUBDEV_GPIO   ] =  nv94_gpio_oclass;
                device->oclass[NVDEV_SUBDEV_I2C    ] =  nv94_i2c_oclass;
+               device->oclass[NVDEV_SUBDEV_FUSE   ] =  &g80_fuse_oclass;
                device->oclass[NVDEV_SUBDEV_CLOCK  ] =  nvaa_clock_oclass;
                device->oclass[NVDEV_SUBDEV_THERM  ] = &nv84_therm_oclass;
                device->oclass[NVDEV_SUBDEV_MXM    ] = &nv50_mxm_oclass;
@@ -309,8 +319,9 @@ nv50_identify(struct nouveau_device *device)
        case 0xac:
                device->cname = "MCP79/MCP7A";
                device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
-               device->oclass[NVDEV_SUBDEV_GPIO   ] =  nv92_gpio_oclass;
+               device->oclass[NVDEV_SUBDEV_GPIO   ] =  nv94_gpio_oclass;
                device->oclass[NVDEV_SUBDEV_I2C    ] =  nv94_i2c_oclass;
+               device->oclass[NVDEV_SUBDEV_FUSE   ] =  &g80_fuse_oclass;
                device->oclass[NVDEV_SUBDEV_CLOCK  ] =  nvaa_clock_oclass;
                device->oclass[NVDEV_SUBDEV_THERM  ] = &nv84_therm_oclass;
                device->oclass[NVDEV_SUBDEV_MXM    ] = &nv50_mxm_oclass;
@@ -337,8 +348,9 @@ nv50_identify(struct nouveau_device *device)
        case 0xa3:
                device->cname = "GT215";
                device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
-               device->oclass[NVDEV_SUBDEV_GPIO   ] =  nv92_gpio_oclass;
+               device->oclass[NVDEV_SUBDEV_GPIO   ] =  nv94_gpio_oclass;
                device->oclass[NVDEV_SUBDEV_I2C    ] =  nv94_i2c_oclass;
+               device->oclass[NVDEV_SUBDEV_FUSE   ] =  &g80_fuse_oclass;
                device->oclass[NVDEV_SUBDEV_CLOCK  ] = &nva3_clock_oclass;
                device->oclass[NVDEV_SUBDEV_THERM  ] = &nva3_therm_oclass;
                device->oclass[NVDEV_SUBDEV_MXM    ] = &nv50_mxm_oclass;
@@ -367,8 +379,9 @@ nv50_identify(struct nouveau_device *device)
        case 0xa5:
                device->cname = "GT216";
                device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
-               device->oclass[NVDEV_SUBDEV_GPIO   ] =  nv92_gpio_oclass;
+               device->oclass[NVDEV_SUBDEV_GPIO   ] =  nv94_gpio_oclass;
                device->oclass[NVDEV_SUBDEV_I2C    ] =  nv94_i2c_oclass;
+               device->oclass[NVDEV_SUBDEV_FUSE   ] =  &g80_fuse_oclass;
                device->oclass[NVDEV_SUBDEV_CLOCK  ] = &nva3_clock_oclass;
                device->oclass[NVDEV_SUBDEV_THERM  ] = &nva3_therm_oclass;
                device->oclass[NVDEV_SUBDEV_MXM    ] = &nv50_mxm_oclass;
@@ -396,8 +409,9 @@ nv50_identify(struct nouveau_device *device)
        case 0xa8:
                device->cname = "GT218";
                device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
-               device->oclass[NVDEV_SUBDEV_GPIO   ] =  nv92_gpio_oclass;
+               device->oclass[NVDEV_SUBDEV_GPIO   ] =  nv94_gpio_oclass;
                device->oclass[NVDEV_SUBDEV_I2C    ] =  nv94_i2c_oclass;
+               device->oclass[NVDEV_SUBDEV_FUSE   ] =  &g80_fuse_oclass;
                device->oclass[NVDEV_SUBDEV_CLOCK  ] = &nva3_clock_oclass;
                device->oclass[NVDEV_SUBDEV_THERM  ] = &nva3_therm_oclass;
                device->oclass[NVDEV_SUBDEV_MXM    ] = &nv50_mxm_oclass;
@@ -425,8 +439,9 @@ nv50_identify(struct nouveau_device *device)
        case 0xaf:
                device->cname = "MCP89";
                device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
-               device->oclass[NVDEV_SUBDEV_GPIO   ] =  nv92_gpio_oclass;
+               device->oclass[NVDEV_SUBDEV_GPIO   ] =  nv94_gpio_oclass;
                device->oclass[NVDEV_SUBDEV_I2C    ] =  nv94_i2c_oclass;
+               device->oclass[NVDEV_SUBDEV_FUSE   ] =  &g80_fuse_oclass;
                device->oclass[NVDEV_SUBDEV_CLOCK  ] = &nva3_clock_oclass;
                device->oclass[NVDEV_SUBDEV_THERM  ] = &nva3_therm_oclass;
                device->oclass[NVDEV_SUBDEV_MXM    ] = &nv50_mxm_oclass;
index b4a2917ce555705b24152714935c6edb0245e681..cd05677ad4b7a128a087f4b611f73b5ab4978006 100644 (file)
@@ -26,6 +26,7 @@
 #include <subdev/bus.h>
 #include <subdev/gpio.h>
 #include <subdev/i2c.h>
+#include <subdev/fuse.h>
 #include <subdev/clock.h>
 #include <subdev/therm.h>
 #include <subdev/mxm.h>
@@ -60,8 +61,9 @@ nvc0_identify(struct nouveau_device *device)
        case 0xc0:
                device->cname = "GF100";
                device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
-               device->oclass[NVDEV_SUBDEV_GPIO   ] =  nv92_gpio_oclass;
+               device->oclass[NVDEV_SUBDEV_GPIO   ] =  nv94_gpio_oclass;
                device->oclass[NVDEV_SUBDEV_I2C    ] =  nv94_i2c_oclass;
+               device->oclass[NVDEV_SUBDEV_FUSE   ] = &gf100_fuse_oclass;
                device->oclass[NVDEV_SUBDEV_CLOCK  ] = &nvc0_clock_oclass;
                device->oclass[NVDEV_SUBDEV_THERM  ] = &nva3_therm_oclass;
                device->oclass[NVDEV_SUBDEV_MXM    ] = &nv50_mxm_oclass;
@@ -92,8 +94,9 @@ nvc0_identify(struct nouveau_device *device)
        case 0xc4:
                device->cname = "GF104";
                device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
-               device->oclass[NVDEV_SUBDEV_GPIO   ] =  nv92_gpio_oclass;
+               device->oclass[NVDEV_SUBDEV_GPIO   ] =  nv94_gpio_oclass;
                device->oclass[NVDEV_SUBDEV_I2C    ] =  nv94_i2c_oclass;
+               device->oclass[NVDEV_SUBDEV_FUSE   ] = &gf100_fuse_oclass;
                device->oclass[NVDEV_SUBDEV_CLOCK  ] = &nvc0_clock_oclass;
                device->oclass[NVDEV_SUBDEV_THERM  ] = &nva3_therm_oclass;
                device->oclass[NVDEV_SUBDEV_MXM    ] = &nv50_mxm_oclass;
@@ -124,8 +127,9 @@ nvc0_identify(struct nouveau_device *device)
        case 0xc3:
                device->cname = "GF106";
                device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
-               device->oclass[NVDEV_SUBDEV_GPIO   ] =  nv92_gpio_oclass;
+               device->oclass[NVDEV_SUBDEV_GPIO   ] =  nv94_gpio_oclass;
                device->oclass[NVDEV_SUBDEV_I2C    ] =  nv94_i2c_oclass;
+               device->oclass[NVDEV_SUBDEV_FUSE   ] = &gf100_fuse_oclass;
                device->oclass[NVDEV_SUBDEV_CLOCK  ] = &nvc0_clock_oclass;
                device->oclass[NVDEV_SUBDEV_THERM  ] = &nva3_therm_oclass;
                device->oclass[NVDEV_SUBDEV_MXM    ] = &nv50_mxm_oclass;
@@ -155,8 +159,9 @@ nvc0_identify(struct nouveau_device *device)
        case 0xce:
                device->cname = "GF114";
                device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
-               device->oclass[NVDEV_SUBDEV_GPIO   ] =  nv92_gpio_oclass;
+               device->oclass[NVDEV_SUBDEV_GPIO   ] =  nv94_gpio_oclass;
                device->oclass[NVDEV_SUBDEV_I2C    ] =  nv94_i2c_oclass;
+               device->oclass[NVDEV_SUBDEV_FUSE   ] = &gf100_fuse_oclass;
                device->oclass[NVDEV_SUBDEV_CLOCK  ] = &nvc0_clock_oclass;
                device->oclass[NVDEV_SUBDEV_THERM  ] = &nva3_therm_oclass;
                device->oclass[NVDEV_SUBDEV_MXM    ] = &nv50_mxm_oclass;
@@ -187,8 +192,9 @@ nvc0_identify(struct nouveau_device *device)
        case 0xcf:
                device->cname = "GF116";
                device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
-               device->oclass[NVDEV_SUBDEV_GPIO   ] =  nv92_gpio_oclass;
+               device->oclass[NVDEV_SUBDEV_GPIO   ] =  nv94_gpio_oclass;
                device->oclass[NVDEV_SUBDEV_I2C    ] =  nv94_i2c_oclass;
+               device->oclass[NVDEV_SUBDEV_FUSE   ] = &gf100_fuse_oclass;
                device->oclass[NVDEV_SUBDEV_CLOCK  ] = &nvc0_clock_oclass;
                device->oclass[NVDEV_SUBDEV_THERM  ] = &nva3_therm_oclass;
                device->oclass[NVDEV_SUBDEV_MXM    ] = &nv50_mxm_oclass;
@@ -219,8 +225,9 @@ nvc0_identify(struct nouveau_device *device)
        case 0xc1:
                device->cname = "GF108";
                device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
-               device->oclass[NVDEV_SUBDEV_GPIO   ] =  nv92_gpio_oclass;
+               device->oclass[NVDEV_SUBDEV_GPIO   ] =  nv94_gpio_oclass;
                device->oclass[NVDEV_SUBDEV_I2C    ] =  nv94_i2c_oclass;
+               device->oclass[NVDEV_SUBDEV_FUSE   ] = &gf100_fuse_oclass;
                device->oclass[NVDEV_SUBDEV_CLOCK  ] = &nvc0_clock_oclass;
                device->oclass[NVDEV_SUBDEV_THERM  ] = &nva3_therm_oclass;
                device->oclass[NVDEV_SUBDEV_MXM    ] = &nv50_mxm_oclass;
@@ -250,8 +257,9 @@ nvc0_identify(struct nouveau_device *device)
        case 0xc8:
                device->cname = "GF110";
                device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
-               device->oclass[NVDEV_SUBDEV_GPIO   ] =  nv92_gpio_oclass;
+               device->oclass[NVDEV_SUBDEV_GPIO   ] =  nv94_gpio_oclass;
                device->oclass[NVDEV_SUBDEV_I2C    ] =  nv94_i2c_oclass;
+               device->oclass[NVDEV_SUBDEV_FUSE   ] = &gf100_fuse_oclass;
                device->oclass[NVDEV_SUBDEV_CLOCK  ] = &nvc0_clock_oclass;
                device->oclass[NVDEV_SUBDEV_THERM  ] = &nva3_therm_oclass;
                device->oclass[NVDEV_SUBDEV_MXM    ] = &nv50_mxm_oclass;
@@ -284,6 +292,7 @@ nvc0_identify(struct nouveau_device *device)
                device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
                device->oclass[NVDEV_SUBDEV_GPIO   ] =  nvd0_gpio_oclass;
                device->oclass[NVDEV_SUBDEV_I2C    ] =  nvd0_i2c_oclass;
+               device->oclass[NVDEV_SUBDEV_FUSE   ] = &gf100_fuse_oclass;
                device->oclass[NVDEV_SUBDEV_CLOCK  ] = &nvc0_clock_oclass;
                device->oclass[NVDEV_SUBDEV_THERM  ] = &nvd0_therm_oclass;
                device->oclass[NVDEV_SUBDEV_MXM    ] = &nv50_mxm_oclass;
@@ -315,6 +324,7 @@ nvc0_identify(struct nouveau_device *device)
                device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
                device->oclass[NVDEV_SUBDEV_GPIO   ] =  nvd0_gpio_oclass;
                device->oclass[NVDEV_SUBDEV_I2C    ] =  gf117_i2c_oclass;
+               device->oclass[NVDEV_SUBDEV_FUSE   ] = &gf100_fuse_oclass;
                device->oclass[NVDEV_SUBDEV_CLOCK  ] = &nvc0_clock_oclass;
                device->oclass[NVDEV_SUBDEV_THERM  ] = &nvd0_therm_oclass;
                device->oclass[NVDEV_SUBDEV_MXM    ] = &nv50_mxm_oclass;
index cdf9147f32a1e80df5c5e58fa840ce311fa54819..b1b2e484ecfabb1a51426a9737fa3d05a014c30c 100644 (file)
@@ -26,6 +26,7 @@
 #include <subdev/bus.h>
 #include <subdev/gpio.h>
 #include <subdev/i2c.h>
+#include <subdev/fuse.h>
 #include <subdev/clock.h>
 #include <subdev/therm.h>
 #include <subdev/mxm.h>
@@ -62,6 +63,7 @@ nve0_identify(struct nouveau_device *device)
                device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
                device->oclass[NVDEV_SUBDEV_GPIO   ] =  nve0_gpio_oclass;
                device->oclass[NVDEV_SUBDEV_I2C    ] =  nve0_i2c_oclass;
+               device->oclass[NVDEV_SUBDEV_FUSE   ] = &gf100_fuse_oclass;
                device->oclass[NVDEV_SUBDEV_CLOCK  ] = &nve0_clock_oclass;
                device->oclass[NVDEV_SUBDEV_THERM  ] = &nvd0_therm_oclass;
                device->oclass[NVDEV_SUBDEV_MXM    ] = &nv50_mxm_oclass;
@@ -95,6 +97,7 @@ nve0_identify(struct nouveau_device *device)
                device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
                device->oclass[NVDEV_SUBDEV_GPIO   ] =  nve0_gpio_oclass;
                device->oclass[NVDEV_SUBDEV_I2C    ] =  nve0_i2c_oclass;
+               device->oclass[NVDEV_SUBDEV_FUSE   ] = &gf100_fuse_oclass;
                device->oclass[NVDEV_SUBDEV_CLOCK  ] = &nve0_clock_oclass;
                device->oclass[NVDEV_SUBDEV_THERM  ] = &nvd0_therm_oclass;
                device->oclass[NVDEV_SUBDEV_MXM    ] = &nv50_mxm_oclass;
@@ -128,6 +131,7 @@ nve0_identify(struct nouveau_device *device)
                device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
                device->oclass[NVDEV_SUBDEV_GPIO   ] =  nve0_gpio_oclass;
                device->oclass[NVDEV_SUBDEV_I2C    ] =  nve0_i2c_oclass;
+               device->oclass[NVDEV_SUBDEV_FUSE   ] = &gf100_fuse_oclass;
                device->oclass[NVDEV_SUBDEV_CLOCK  ] = &nve0_clock_oclass;
                device->oclass[NVDEV_SUBDEV_THERM  ] = &nvd0_therm_oclass;
                device->oclass[NVDEV_SUBDEV_MXM    ] = &nv50_mxm_oclass;
@@ -161,6 +165,7 @@ nve0_identify(struct nouveau_device *device)
                device->oclass[NVDEV_SUBDEV_CLOCK  ] = &gk20a_clock_oclass;
                device->oclass[NVDEV_SUBDEV_MC     ] =  gk20a_mc_oclass;
                device->oclass[NVDEV_SUBDEV_BUS    ] =  nvc0_bus_oclass;
+               device->oclass[NVDEV_SUBDEV_FUSE   ] = &gf100_fuse_oclass;
                device->oclass[NVDEV_SUBDEV_TIMER  ] = &gk20a_timer_oclass;
                device->oclass[NVDEV_SUBDEV_FB     ] =  gk20a_fb_oclass;
                device->oclass[NVDEV_SUBDEV_LTC    ] =  gk104_ltc_oclass;
@@ -180,6 +185,7 @@ nve0_identify(struct nouveau_device *device)
                device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
                device->oclass[NVDEV_SUBDEV_GPIO   ] =  nve0_gpio_oclass;
                device->oclass[NVDEV_SUBDEV_I2C    ] =  nve0_i2c_oclass;
+               device->oclass[NVDEV_SUBDEV_FUSE   ] = &gf100_fuse_oclass;
                device->oclass[NVDEV_SUBDEV_CLOCK  ] = &nve0_clock_oclass;
                device->oclass[NVDEV_SUBDEV_THERM  ] = &nvd0_therm_oclass;
                device->oclass[NVDEV_SUBDEV_MXM    ] = &nv50_mxm_oclass;
@@ -213,6 +219,7 @@ nve0_identify(struct nouveau_device *device)
                device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
                device->oclass[NVDEV_SUBDEV_GPIO   ] =  nve0_gpio_oclass;
                device->oclass[NVDEV_SUBDEV_I2C    ] =  nvd0_i2c_oclass;
+               device->oclass[NVDEV_SUBDEV_FUSE   ] = &gf100_fuse_oclass;
                device->oclass[NVDEV_SUBDEV_CLOCK  ] = &nve0_clock_oclass;
                device->oclass[NVDEV_SUBDEV_THERM  ] = &nvd0_therm_oclass;
                device->oclass[NVDEV_SUBDEV_MXM    ] = &nv50_mxm_oclass;
@@ -246,6 +253,7 @@ nve0_identify(struct nouveau_device *device)
                device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
                device->oclass[NVDEV_SUBDEV_GPIO   ] =  nve0_gpio_oclass;
                device->oclass[NVDEV_SUBDEV_I2C    ] =  nve0_i2c_oclass;
+               device->oclass[NVDEV_SUBDEV_FUSE   ] = &gf100_fuse_oclass;
                device->oclass[NVDEV_SUBDEV_CLOCK  ] = &nve0_clock_oclass;
                device->oclass[NVDEV_SUBDEV_THERM  ] = &nvd0_therm_oclass;
                device->oclass[NVDEV_SUBDEV_MXM    ] = &nv50_mxm_oclass;
index 22d55f6cde5011f34c19bc938066d1306fcbd7e7..64b84667f3a5e9ebbf9f57ae2b1c6c4f76997d5f 100644 (file)
@@ -32,7 +32,8 @@
 #include "conn.h"
 
 int
-nouveau_disp_vblank_ctor(void *data, u32 size, struct nvkm_notify *notify)
+nouveau_disp_vblank_ctor(struct nouveau_object *object, void *data, u32 size,
+                        struct nvkm_notify *notify)
 {
        struct nouveau_disp *disp =
                container_of(notify->event, typeof(*disp), vblank);
@@ -61,7 +62,8 @@ nouveau_disp_vblank(struct nouveau_disp *disp, int head)
 }
 
 static int
-nouveau_disp_hpd_ctor(void *data, u32 size, struct nvkm_notify *notify)
+nouveau_disp_hpd_ctor(struct nouveau_object *object, void *data, u32 size,
+                     struct nvkm_notify *notify)
 {
        struct nouveau_disp *disp =
                container_of(notify->event, typeof(*disp), hpd);
index 3d1070228977eb86d3434a7282f7800452e0b6cb..1496b567dd4aab9e1978bda882b1bf3ab3802da0 100644 (file)
@@ -126,8 +126,8 @@ nvkm_connector_create_(struct nouveau_object *parent,
                        return 0;
                }
 
-               ret = nvkm_notify_init(&gpio->event, nvkm_connector_hpd, true,
-                                      &(struct nvkm_gpio_ntfy_req) {
+               ret = nvkm_notify_init(NULL, &gpio->event, nvkm_connector_hpd,
+                                      true, &(struct nvkm_gpio_ntfy_req) {
                                        .mask = NVKM_GPIO_TOGGLED,
                                        .line = func.line,
                                       },
index d54da8b5f87ec97f5587bde7447ab2fbbbe5f918..b3df3fe2dc094b6dbebdc861c94450ef48ddf3e2 100644 (file)
@@ -68,6 +68,10 @@ gm107_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
        if (ret)
                return ret;
 
+       ret = nvkm_event_init(&nvd0_disp_chan_uevent, 1, 17, &priv->uevent);
+       if (ret)
+               return ret;
+
        nv_engine(priv)->sclass = gm107_disp_base_oclass;
        nv_engine(priv)->cclass = &nv50_disp_cclass;
        nv_subdev(priv)->intr = nvd0_disp_intr;
@@ -80,7 +84,7 @@ gm107_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
        priv->dac.sense = nv50_dac_sense;
        priv->sor.power = nv50_sor_power;
        priv->sor.hda_eld = nvd0_hda_eld;
-       priv->sor.hdmi = nvd0_hdmi_ctrl;
+       priv->sor.hdmi = nve0_hdmi_ctrl;
        return 0;
 }
 
index 8b4e06abe5333230768ef047b58c3855a6cca305..fe9ef5894dd49e5fd93722cab01114f8c4b769ab 100644 (file)
@@ -26,6 +26,8 @@
 #include <nvif/unpack.h>
 #include <nvif/class.h>
 
+#include <subdev/timer.h>
+
 #include "nv50.h"
 
 int
@@ -46,16 +48,21 @@ nva3_hda_eld(NV50_DISP_MTHD_V1)
                return ret;
 
        if (size && args->v0.data[0]) {
+               if (outp->info.type == DCB_OUTPUT_DP) {
+                       nv_mask(priv, 0x61c1e0 + soff, 0x8000000d, 0x80000001);
+                       nv_wait(priv, 0x61c1e0 + soff, 0x80000000, 0x00000000);
+               }
                for (i = 0; i < size; i++)
                        nv_wr32(priv, 0x61c440 + soff, (i << 8) | args->v0.data[0]);
                for (; i < 0x60; i++)
                        nv_wr32(priv, 0x61c440 + soff, (i << 8));
                nv_mask(priv, 0x61c448 + soff, 0x80000003, 0x80000003);
-       } else
-       if (size) {
-               nv_mask(priv, 0x61c448 + soff, 0x80000003, 0x80000001);
        } else {
-               nv_mask(priv, 0x61c448 + soff, 0x80000003, 0x80000000);
+               if (outp->info.type == DCB_OUTPUT_DP) {
+                       nv_mask(priv, 0x61c1e0 + soff, 0x80000001, 0x80000000);
+                       nv_wait(priv, 0x61c1e0 + soff, 0x80000000, 0x00000000);
+               }
+               nv_mask(priv, 0x61c448 + soff, 0x80000003, 0x80000000 | !!size);
        }
 
        return 0;
index baf558fc12fb91dac6e2fd8d7a67a28084a7f926..1d4e8432d8579d54ba0934f8af591e4d572f3218 100644 (file)
 #include <nvif/unpack.h>
 #include <nvif/class.h>
 
-#include <subdev/bios.h>
-#include <subdev/bios/dcb.h>
-#include <subdev/bios/dp.h>
-#include <subdev/bios/init.h>
+#include <subdev/timer.h>
 
 #include "nv50.h"
 
@@ -40,6 +37,7 @@ nvd0_hda_eld(NV50_DISP_MTHD_V1)
                struct nv50_disp_sor_hda_eld_v0 v0;
        } *args = data;
        const u32 soff = outp->or * 0x030;
+       const u32 hoff = head * 0x800;
        int ret, i;
 
        nv_ioctl(object, "disp sor hda eld size %d\n", size);
@@ -51,16 +49,22 @@ nvd0_hda_eld(NV50_DISP_MTHD_V1)
                return ret;
 
        if (size && args->v0.data[0]) {
+               if (outp->info.type == DCB_OUTPUT_DP) {
+                       nv_mask(priv, 0x616618 + hoff, 0x8000000c, 0x80000001);
+                       nv_wait(priv, 0x616618 + hoff, 0x80000000, 0x00000000);
+               }
+               nv_mask(priv, 0x616548 + hoff, 0x00000070, 0x00000000);
                for (i = 0; i < size; i++)
                        nv_wr32(priv, 0x10ec00 + soff, (i << 8) | args->v0.data[i]);
                for (; i < 0x60; i++)
                        nv_wr32(priv, 0x10ec00 + soff, (i << 8));
                nv_mask(priv, 0x10ec10 + soff, 0x80000003, 0x80000003);
-       } else
-       if (size) {
-               nv_mask(priv, 0x10ec10 + soff, 0x80000003, 0x80000001);
        } else {
-               nv_mask(priv, 0x10ec10 + soff, 0x80000003, 0x80000000);
+               if (outp->info.type == DCB_OUTPUT_DP) {
+                       nv_mask(priv, 0x616618 + hoff, 0x80000001, 0x80000000);
+                       nv_wait(priv, 0x616618 + hoff, 0x80000000, 0x00000000);
+               }
+               nv_mask(priv, 0x10ec10 + soff, 0x80000003, 0x80000000 | !!size);
        }
 
        return 0;
index 3106d295b48d978028f62259a169935cdce0e012..bac4fc4570f0e3731f3a09ef1bc0869c015023c8 100644 (file)
@@ -75,8 +75,5 @@ nvd0_hdmi_ctrl(NV50_DISP_MTHD_V1)
 
        /* HDMI_CTRL */
        nv_mask(priv, 0x616798 + hoff, 0x401f007f, ctrl);
-
-       /* NFI, audio doesn't work without it though.. */
-       nv_mask(priv, 0x616548 + hoff, 0x00000070, 0x00000000);
        return 0;
 }
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/hdminve0.c b/drivers/gpu/drm/nouveau/core/engine/disp/hdminve0.c
new file mode 100644 (file)
index 0000000..528d14e
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+ * Copyright 2014 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+
+#include <core/client.h>
+#include <nvif/unpack.h>
+#include <nvif/class.h>
+
+#include "nv50.h"
+
+int
+nve0_hdmi_ctrl(NV50_DISP_MTHD_V1)
+{
+       const u32 hoff = (head * 0x800);
+       const u32 hdmi = (head * 0x400);
+       union {
+               struct nv50_disp_sor_hdmi_pwr_v0 v0;
+       } *args = data;
+       u32 ctrl;
+       int ret;
+
+       nv_ioctl(object, "disp sor hdmi ctrl size %d\n", size);
+       if (nvif_unpack(args->v0, 0, 0, false)) {
+               nv_ioctl(object, "disp sor hdmi ctrl vers %d state %d "
+                                "max_ac_packet %d rekey %d\n",
+                        args->v0.version, args->v0.state,
+                        args->v0.max_ac_packet, args->v0.rekey);
+               if (args->v0.max_ac_packet > 0x1f || args->v0.rekey > 0x7f)
+                       return -EINVAL;
+               ctrl  = 0x40000000 * !!args->v0.state;
+               ctrl |= args->v0.max_ac_packet << 16;
+               ctrl |= args->v0.rekey;
+       } else
+               return ret;
+
+       if (!(ctrl & 0x40000000)) {
+               nv_mask(priv, 0x616798 + hoff, 0x40000000, 0x00000000);
+               nv_mask(priv, 0x6900c0 + hdmi, 0x00000001, 0x00000000);
+               nv_mask(priv, 0x690000 + hdmi, 0x00000001, 0x00000000);
+               return 0;
+       }
+
+       /* AVI InfoFrame */
+       nv_mask(priv, 0x690000 + hdmi, 0x00000001, 0x00000000);
+       nv_wr32(priv, 0x690008 + hdmi, 0x000d0282);
+       nv_wr32(priv, 0x69000c + hdmi, 0x0000006f);
+       nv_wr32(priv, 0x690010 + hdmi, 0x00000000);
+       nv_wr32(priv, 0x690014 + hdmi, 0x00000000);
+       nv_wr32(priv, 0x690018 + hdmi, 0x00000000);
+       nv_mask(priv, 0x690000 + hdmi, 0x00000001, 0x00000001);
+
+       /* ??? InfoFrame? */
+       nv_mask(priv, 0x6900c0 + hdmi, 0x00000001, 0x00000000);
+       nv_wr32(priv, 0x6900cc + hdmi, 0x00000010);
+       nv_mask(priv, 0x6900c0 + hdmi, 0x00000001, 0x00000001);
+
+       /* ??? */
+       nv_wr32(priv, 0x690080 + hdmi, 0x82000000);
+
+       /* HDMI_CTRL */
+       nv_mask(priv, 0x616798 + hoff, 0x401f007f, ctrl);
+       return 0;
+}
index f8cbb512132fdcd224f6dda223689de4a4bb4350..2df3a937037de7c55d94f345bcdd8f2eeb88576e 100644 (file)
@@ -29,6 +29,7 @@
 #include <core/enum.h>
 #include <nvif/unpack.h>
 #include <nvif/class.h>
+#include <nvif/event.h>
 
 #include <subdev/bios.h>
 #include <subdev/bios/dcb.h>
@@ -82,6 +83,71 @@ nv50_disp_chan_destroy(struct nv50_disp_chan *chan)
        nouveau_namedb_destroy(&chan->base);
 }
 
+static void
+nv50_disp_chan_uevent_fini(struct nvkm_event *event, int type, int index)
+{
+       struct nv50_disp_priv *priv = container_of(event, typeof(*priv), uevent);
+       nv_mask(priv, 0x610028, 0x00000001 << index, 0x00000000 << index);
+}
+
+static void
+nv50_disp_chan_uevent_init(struct nvkm_event *event, int types, int index)
+{
+       struct nv50_disp_priv *priv = container_of(event, typeof(*priv), uevent);
+       nv_mask(priv, 0x610028, 0x00000001 << index, 0x00000001 << index);
+}
+
+void
+nv50_disp_chan_uevent_send(struct nv50_disp_priv *priv, int chid)
+{
+       struct nvif_notify_uevent_rep {
+       } rep;
+
+       nvkm_event_send(&priv->uevent, 1, chid, &rep, sizeof(rep));
+}
+
+int
+nv50_disp_chan_uevent_ctor(struct nouveau_object *object, void *data, u32 size,
+                          struct nvkm_notify *notify)
+{
+       struct nv50_disp_dmac *dmac = (void *)object;
+       union {
+               struct nvif_notify_uevent_req none;
+       } *args = data;
+       int ret;
+
+       if (nvif_unvers(args->none)) {
+               notify->size  = sizeof(struct nvif_notify_uevent_rep);
+               notify->types = 1;
+               notify->index = dmac->base.chid;
+               return 0;
+       }
+
+       return ret;
+}
+
+const struct nvkm_event_func
+nv50_disp_chan_uevent = {
+       .ctor = nv50_disp_chan_uevent_ctor,
+       .init = nv50_disp_chan_uevent_init,
+       .fini = nv50_disp_chan_uevent_fini,
+};
+
+int
+nv50_disp_chan_ntfy(struct nouveau_object *object, u32 type,
+                   struct nvkm_event **pevent)
+{
+       struct nv50_disp_priv *priv = (void *)object->engine;
+       switch (type) {
+       case NV50_DISP_CORE_CHANNEL_DMA_V0_NTFY_UEVENT:
+               *pevent = &priv->uevent;
+               return 0;
+       default:
+               break;
+       }
+       return -EINVAL;
+}
+
 int
 nv50_disp_chan_map(struct nouveau_object *object, u64 *addr, u32 *size)
 {
@@ -195,7 +261,7 @@ nv50_disp_dmac_init(struct nouveau_object *object)
                return ret;
 
        /* enable error reporting */
-       nv_mask(priv, 0x610028, 0x00010001 << chid, 0x00010001 << chid);
+       nv_mask(priv, 0x610028, 0x00010000 << chid, 0x00010000 << chid);
 
        /* initialise channel for dma command submission */
        nv_wr32(priv, 0x610204 + (chid * 0x0010), dmac->push);
@@ -232,7 +298,7 @@ nv50_disp_dmac_fini(struct nouveau_object *object, bool suspend)
                        return -EBUSY;
        }
 
-       /* disable error reporting */
+       /* disable error reporting and completion notifications */
        nv_mask(priv, 0x610028, 0x00010001 << chid, 0x00000000 << chid);
 
        return nv50_disp_chan_fini(&dmac->base, suspend);
@@ -454,7 +520,7 @@ nv50_disp_mast_init(struct nouveau_object *object)
                return ret;
 
        /* enable error reporting */
-       nv_mask(priv, 0x610028, 0x00010001, 0x00010001);
+       nv_mask(priv, 0x610028, 0x00010000, 0x00010000);
 
        /* attempt to unstick channel from some unknown state */
        if ((nv_rd32(priv, 0x610200) & 0x009f0000) == 0x00020000)
@@ -494,7 +560,7 @@ nv50_disp_mast_fini(struct nouveau_object *object, bool suspend)
                        return -EBUSY;
        }
 
-       /* disable error reporting */
+       /* disable error reporting and completion notifications */
        nv_mask(priv, 0x610028, 0x00010001, 0x00000000);
 
        return nv50_disp_chan_fini(&mast->base, suspend);
@@ -507,6 +573,7 @@ nv50_disp_mast_ofuncs = {
        .base.init = nv50_disp_mast_init,
        .base.fini = nv50_disp_mast_fini,
        .base.map  = nv50_disp_chan_map,
+       .base.ntfy = nv50_disp_chan_ntfy,
        .base.rd32 = nv50_disp_chan_rd32,
        .base.wr32 = nv50_disp_chan_wr32,
        .chid = 0,
@@ -607,6 +674,7 @@ nv50_disp_sync_ofuncs = {
        .base.dtor = nv50_disp_dmac_dtor,
        .base.init = nv50_disp_dmac_init,
        .base.fini = nv50_disp_dmac_fini,
+       .base.ntfy = nv50_disp_chan_ntfy,
        .base.map  = nv50_disp_chan_map,
        .base.rd32 = nv50_disp_chan_rd32,
        .base.wr32 = nv50_disp_chan_wr32,
@@ -696,6 +764,7 @@ nv50_disp_ovly_ofuncs = {
        .base.dtor = nv50_disp_dmac_dtor,
        .base.init = nv50_disp_dmac_init,
        .base.fini = nv50_disp_dmac_fini,
+       .base.ntfy = nv50_disp_chan_ntfy,
        .base.map  = nv50_disp_chan_map,
        .base.rd32 = nv50_disp_chan_rd32,
        .base.wr32 = nv50_disp_chan_wr32,
@@ -813,6 +882,7 @@ nv50_disp_oimm_ofuncs = {
        .base.dtor = nv50_disp_pioc_dtor,
        .base.init = nv50_disp_pioc_init,
        .base.fini = nv50_disp_pioc_fini,
+       .base.ntfy = nv50_disp_chan_ntfy,
        .base.map  = nv50_disp_chan_map,
        .base.rd32 = nv50_disp_chan_rd32,
        .base.wr32 = nv50_disp_chan_wr32,
@@ -860,6 +930,7 @@ nv50_disp_curs_ofuncs = {
        .base.dtor = nv50_disp_pioc_dtor,
        .base.init = nv50_disp_pioc_init,
        .base.fini = nv50_disp_pioc_fini,
+       .base.ntfy = nv50_disp_chan_ntfy,
        .base.map  = nv50_disp_chan_map,
        .base.rd32 = nv50_disp_chan_rd32,
        .base.wr32 = nv50_disp_chan_wr32,
@@ -1559,7 +1630,7 @@ nv50_disp_intr_unk20_1(struct nv50_disp_priv *priv, int head)
 }
 
 static void
-nv50_disp_intr_unk20_2_dp(struct nv50_disp_priv *priv,
+nv50_disp_intr_unk20_2_dp(struct nv50_disp_priv *priv, int head,
                          struct dcb_output *outp, u32 pclk)
 {
        const int link = !(outp->sorconf.link & 1);
@@ -1568,24 +1639,36 @@ nv50_disp_intr_unk20_2_dp(struct nv50_disp_priv *priv,
        const u32 loff = (link * 0x080) + soff;
        const u32 ctrl = nv_rd32(priv, 0x610794 + (or * 8));
        const u32 symbol = 100000;
-       u32 dpctrl = nv_rd32(priv, 0x61c10c + loff) & 0x0000f0000;
+       const s32 vactive = nv_rd32(priv, 0x610af8 + (head * 0x540)) & 0xffff;
+       const s32 vblanke = nv_rd32(priv, 0x610ae8 + (head * 0x540)) & 0xffff;
+       const s32 vblanks = nv_rd32(priv, 0x610af0 + (head * 0x540)) & 0xffff;
+       u32 dpctrl = nv_rd32(priv, 0x61c10c + loff);
        u32 clksor = nv_rd32(priv, 0x614300 + soff);
        int bestTU = 0, bestVTUi = 0, bestVTUf = 0, bestVTUa = 0;
        int TU, VTUi, VTUf, VTUa;
        u64 link_data_rate, link_ratio, unk;
        u32 best_diff = 64 * symbol;
        u32 link_nr, link_bw, bits;
-
-       /* calculate packed data rate for each lane */
-       if      (dpctrl > 0x00030000) link_nr = 4;
-       else if (dpctrl > 0x00010000) link_nr = 2;
-       else                          link_nr = 1;
-
-       if (clksor & 0x000c0000)
-               link_bw = 270000;
-       else
-               link_bw = 162000;
-
+       u64 value;
+
+       link_bw = (clksor & 0x000c0000) ? 270000 : 162000;
+       link_nr = hweight32(dpctrl & 0x000f0000);
+
+       /* symbols/hblank - algorithm taken from comments in tegra driver */
+       value = vblanke + vactive - vblanks - 7;
+       value = value * link_bw;
+       do_div(value, pclk);
+       value = value - (3 * !!(dpctrl & 0x00004000)) - (12 / link_nr);
+       nv_mask(priv, 0x61c1e8 + soff, 0x0000ffff, value);
+
+       /* symbols/vblank - algorithm taken from comments in tegra driver */
+       value = vblanks - vblanke - 25;
+       value = value * link_bw;
+       do_div(value, pclk);
+       value = value - ((36 / link_nr) + 3) - 1;
+       nv_mask(priv, 0x61c1ec + soff, 0x00ffffff, value);
+
+       /* watermark / activesym */
        if      ((ctrl & 0xf0000) == 0x60000) bits = 30;
        else if ((ctrl & 0xf0000) == 0x50000) bits = 24;
        else                                  bits = 18;
@@ -1731,7 +1814,7 @@ nv50_disp_intr_unk20_2(struct nv50_disp_priv *priv, int head)
        } else
        if (!outp->info.location) {
                if (outp->info.type == DCB_OUTPUT_DP)
-                       nv50_disp_intr_unk20_2_dp(priv, &outp->info, pclk);
+                       nv50_disp_intr_unk20_2_dp(priv, head, &outp->info, pclk);
                oreg = 0x614300 + (ffs(outp->info.or) - 1) * 0x800;
                oval = (conf & 0x0100) ? 0x00000101 : 0x00000000;
                hval = 0x00000000;
@@ -1847,6 +1930,12 @@ nv50_disp_intr(struct nouveau_subdev *subdev)
                intr0 &= ~(0x00010000 << chid);
        }
 
+       while (intr0 & 0x0000001f) {
+               u32 chid = __ffs(intr0 & 0x0000001f);
+               nv50_disp_chan_uevent_send(priv, chid);
+               intr0 &= ~(0x00000001 << chid);
+       }
+
        if (intr1 & 0x00000004) {
                nouveau_disp_vblank(&priv->base, 0);
                nv_wr32(priv, 0x610024, 0x00000004);
@@ -1881,6 +1970,10 @@ nv50_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
        if (ret)
                return ret;
 
+       ret = nvkm_event_init(&nv50_disp_chan_uevent, 1, 9, &priv->uevent);
+       if (ret)
+               return ret;
+
        nv_engine(priv)->sclass = nv50_disp_base_oclass;
        nv_engine(priv)->cclass = &nv50_disp_cclass;
        nv_subdev(priv)->intr = nv50_disp_intr;
index 8ab14461f70c645116b4bf82e36cd8afda36fad4..5279feefec062210706e087b315e802a84648913 100644 (file)
@@ -26,6 +26,8 @@ struct nv50_disp_priv {
        struct work_struct supervisor;
        u32 super;
 
+       struct nvkm_event uevent;
+
        struct {
                int nr;
        } head;
@@ -75,6 +77,7 @@ int nvd0_hda_eld(NV50_DISP_MTHD_V1);
 int nv84_hdmi_ctrl(NV50_DISP_MTHD_V1);
 int nva3_hdmi_ctrl(NV50_DISP_MTHD_V1);
 int nvd0_hdmi_ctrl(NV50_DISP_MTHD_V1);
+int nve0_hdmi_ctrl(NV50_DISP_MTHD_V1);
 
 int nv50_sor_power(NV50_DISP_MTHD_V1);
 
@@ -116,9 +119,16 @@ struct nv50_disp_chan {
        int chid;
 };
 
+int  nv50_disp_chan_ntfy(struct nouveau_object *, u32, struct nvkm_event **);
 int  nv50_disp_chan_map(struct nouveau_object *, u64 *, u32 *);
 u32  nv50_disp_chan_rd32(struct nouveau_object *, u64);
 void nv50_disp_chan_wr32(struct nouveau_object *, u64, u32);
+extern const struct nvkm_event_func nv50_disp_chan_uevent;
+int  nv50_disp_chan_uevent_ctor(struct nouveau_object *, void *, u32,
+                               struct nvkm_notify *);
+void nv50_disp_chan_uevent_send(struct nv50_disp_priv *, int);
+
+extern const struct nvkm_event_func nvd0_disp_chan_uevent;
 
 #define nv50_disp_chan_init(a)                                                 \
        nouveau_namedb_init(&(a)->base)
index 788ced1b6182f8c5cd925ed402cd6c85f772eb66..d36284715b2ab0f20ae26bce925fe05b3b1bea67 100644 (file)
@@ -236,6 +236,10 @@ nv84_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
        if (ret)
                return ret;
 
+       ret = nvkm_event_init(&nv50_disp_chan_uevent, 1, 9, &priv->uevent);
+       if (ret)
+               return ret;
+
        nv_engine(priv)->sclass = nv84_disp_base_oclass;
        nv_engine(priv)->cclass = &nv50_disp_cclass;
        nv_subdev(priv)->intr = nv50_disp_intr;
index fa79de906eaefd1dd39e90e9e2bc0d8994c6ebca..a117064002b1413a499a5a644ebd0c439abcdf75 100644 (file)
@@ -95,6 +95,10 @@ nv94_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
        if (ret)
                return ret;
 
+       ret = nvkm_event_init(&nv50_disp_chan_uevent, 1, 9, &priv->uevent);
+       if (ret)
+               return ret;
+
        nv_engine(priv)->sclass = nv94_disp_base_oclass;
        nv_engine(priv)->cclass = &nv50_disp_cclass;
        nv_subdev(priv)->intr = nv50_disp_intr;
index 7af15f5d48dc2c08a7ecc0c694ab1f7c04a0a524..c67e68aadd45987ae1f5dc6fb0a48a73102b1fcc 100644 (file)
@@ -112,6 +112,10 @@ nva0_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
        if (ret)
                return ret;
 
+       ret = nvkm_event_init(&nv50_disp_chan_uevent, 1, 9, &priv->uevent);
+       if (ret)
+               return ret;
+
        nv_engine(priv)->sclass = nva0_disp_base_oclass;
        nv_engine(priv)->cclass = &nv50_disp_cclass;
        nv_subdev(priv)->intr = nv50_disp_intr;
index 6bd39448f8dab91d621a09cc22b99a9c8b9ab591..22969f355aae66da0102bf722a87cbff81b529fc 100644 (file)
@@ -67,6 +67,10 @@ nva3_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
        if (ret)
                return ret;
 
+       ret = nvkm_event_init(&nv50_disp_chan_uevent, 1, 9, &priv->uevent);
+       if (ret)
+               return ret;
+
        nv_engine(priv)->sclass = nva3_disp_base_oclass;
        nv_engine(priv)->cclass = &nv50_disp_cclass;
        nv_subdev(priv)->intr = nv50_disp_intr;
index a4bb3c774ee1f6a853289003ab98a73cc2a78c5a..747e64bb9c06c935e1318a57ac7d8b879b473366 100644 (file)
 
 #include "nv50.h"
 
+/*******************************************************************************
+ * EVO channel base class
+ ******************************************************************************/
+
+static void
+nvd0_disp_chan_uevent_fini(struct nvkm_event *event, int type, int index)
+{
+       struct nv50_disp_priv *priv = container_of(event, typeof(*priv), uevent);
+       nv_mask(priv, 0x610090, 0x00000001 << index, 0x00000000 << index);
+}
+
+static void
+nvd0_disp_chan_uevent_init(struct nvkm_event *event, int types, int index)
+{
+       struct nv50_disp_priv *priv = container_of(event, typeof(*priv), uevent);
+       nv_mask(priv, 0x610090, 0x00000001 << index, 0x00000001 << index);
+}
+
+const struct nvkm_event_func
+nvd0_disp_chan_uevent = {
+       .ctor = nv50_disp_chan_uevent_ctor,
+       .init = nvd0_disp_chan_uevent_init,
+       .fini = nvd0_disp_chan_uevent_fini,
+};
+
 /*******************************************************************************
  * EVO DMA channel base class
  ******************************************************************************/
@@ -77,7 +102,6 @@ nvd0_disp_dmac_init(struct nouveau_object *object)
                return ret;
 
        /* enable error reporting */
-       nv_mask(priv, 0x610090, 0x00000001 << chid, 0x00000001 << chid);
        nv_mask(priv, 0x6100a0, 0x00000001 << chid, 0x00000001 << chid);
 
        /* initialise channel for dma command submission */
@@ -115,7 +139,7 @@ nvd0_disp_dmac_fini(struct nouveau_object *object, bool suspend)
                        return -EBUSY;
        }
 
-       /* disable error reporting */
+       /* disable error reporting and completion notification */
        nv_mask(priv, 0x610090, 0x00000001 << chid, 0x00000000);
        nv_mask(priv, 0x6100a0, 0x00000001 << chid, 0x00000000);
 
@@ -278,7 +302,6 @@ nvd0_disp_mast_init(struct nouveau_object *object)
                return ret;
 
        /* enable error reporting */
-       nv_mask(priv, 0x610090, 0x00000001, 0x00000001);
        nv_mask(priv, 0x6100a0, 0x00000001, 0x00000001);
 
        /* initialise channel for dma command submission */
@@ -313,7 +336,7 @@ nvd0_disp_mast_fini(struct nouveau_object *object, bool suspend)
                        return -EBUSY;
        }
 
-       /* disable error reporting */
+       /* disable error reporting and completion notification */
        nv_mask(priv, 0x610090, 0x00000001, 0x00000000);
        nv_mask(priv, 0x6100a0, 0x00000001, 0x00000000);
 
@@ -326,6 +349,7 @@ nvd0_disp_mast_ofuncs = {
        .base.dtor = nv50_disp_dmac_dtor,
        .base.init = nvd0_disp_mast_init,
        .base.fini = nvd0_disp_mast_fini,
+       .base.ntfy = nv50_disp_chan_ntfy,
        .base.map  = nv50_disp_chan_map,
        .base.rd32 = nv50_disp_chan_rd32,
        .base.wr32 = nv50_disp_chan_wr32,
@@ -419,6 +443,7 @@ nvd0_disp_sync_ofuncs = {
        .base.dtor = nv50_disp_dmac_dtor,
        .base.init = nvd0_disp_dmac_init,
        .base.fini = nvd0_disp_dmac_fini,
+       .base.ntfy = nv50_disp_chan_ntfy,
        .base.map  = nv50_disp_chan_map,
        .base.rd32 = nv50_disp_chan_rd32,
        .base.wr32 = nv50_disp_chan_wr32,
@@ -499,6 +524,7 @@ nvd0_disp_ovly_ofuncs = {
        .base.dtor = nv50_disp_dmac_dtor,
        .base.init = nvd0_disp_dmac_init,
        .base.fini = nvd0_disp_dmac_fini,
+       .base.ntfy = nv50_disp_chan_ntfy,
        .base.map  = nv50_disp_chan_map,
        .base.rd32 = nv50_disp_chan_rd32,
        .base.wr32 = nv50_disp_chan_wr32,
@@ -524,7 +550,6 @@ nvd0_disp_pioc_init(struct nouveau_object *object)
                return ret;
 
        /* enable error reporting */
-       nv_mask(priv, 0x610090, 0x00000001 << chid, 0x00000001 << chid);
        nv_mask(priv, 0x6100a0, 0x00000001 << chid, 0x00000001 << chid);
 
        /* activate channel */
@@ -553,7 +578,7 @@ nvd0_disp_pioc_fini(struct nouveau_object *object, bool suspend)
                        return -EBUSY;
        }
 
-       /* disable error reporting */
+       /* disable error reporting and completion notification */
        nv_mask(priv, 0x610090, 0x00000001 << chid, 0x00000000);
        nv_mask(priv, 0x6100a0, 0x00000001 << chid, 0x00000000);
 
@@ -570,6 +595,7 @@ nvd0_disp_oimm_ofuncs = {
        .base.dtor = nv50_disp_pioc_dtor,
        .base.init = nvd0_disp_pioc_init,
        .base.fini = nvd0_disp_pioc_fini,
+       .base.ntfy = nv50_disp_chan_ntfy,
        .base.map  = nv50_disp_chan_map,
        .base.rd32 = nv50_disp_chan_rd32,
        .base.wr32 = nv50_disp_chan_wr32,
@@ -586,6 +612,7 @@ nvd0_disp_curs_ofuncs = {
        .base.dtor = nv50_disp_pioc_dtor,
        .base.init = nvd0_disp_pioc_init,
        .base.fini = nvd0_disp_pioc_fini,
+       .base.ntfy = nv50_disp_chan_ntfy,
        .base.map  = nv50_disp_chan_map,
        .base.rd32 = nv50_disp_chan_rd32,
        .base.wr32 = nv50_disp_chan_wr32,
@@ -949,6 +976,9 @@ nvd0_disp_intr_unk2_2_tu(struct nv50_disp_priv *priv, int head,
        const int or = ffs(outp->or) - 1;
        const u32 ctrl = nv_rd32(priv, 0x660200 + (or   * 0x020));
        const u32 conf = nv_rd32(priv, 0x660404 + (head * 0x300));
+       const s32 vactive = nv_rd32(priv, 0x660414 + (head * 0x300)) & 0xffff;
+       const s32 vblanke = nv_rd32(priv, 0x66041c + (head * 0x300)) & 0xffff;
+       const s32 vblanks = nv_rd32(priv, 0x660420 + (head * 0x300)) & 0xffff;
        const u32 pclk = nv_rd32(priv, 0x660450 + (head * 0x300)) / 1000;
        const u32 link = ((ctrl & 0xf00) == 0x800) ? 0 : 1;
        const u32 hoff = (head * 0x800);
@@ -956,23 +986,35 @@ nvd0_disp_intr_unk2_2_tu(struct nv50_disp_priv *priv, int head,
        const u32 loff = (link * 0x080) + soff;
        const u32 symbol = 100000;
        const u32 TU = 64;
-       u32 dpctrl = nv_rd32(priv, 0x61c10c + loff) & 0x000f0000;
+       u32 dpctrl = nv_rd32(priv, 0x61c10c + loff);
        u32 clksor = nv_rd32(priv, 0x612300 + soff);
        u32 datarate, link_nr, link_bw, bits;
        u64 ratio, value;
 
+       link_nr  = hweight32(dpctrl & 0x000f0000);
+       link_bw  = (clksor & 0x007c0000) >> 18;
+       link_bw *= 27000;
+
+       /* symbols/hblank - algorithm taken from comments in tegra driver */
+       value = vblanke + vactive - vblanks - 7;
+       value = value * link_bw;
+       do_div(value, pclk);
+       value = value - (3 * !!(dpctrl & 0x00004000)) - (12 / link_nr);
+       nv_mask(priv, 0x616620 + hoff, 0x0000ffff, value);
+
+       /* symbols/vblank - algorithm taken from comments in tegra driver */
+       value = vblanks - vblanke - 25;
+       value = value * link_bw;
+       do_div(value, pclk);
+       value = value - ((36 / link_nr) + 3) - 1;
+       nv_mask(priv, 0x616624 + hoff, 0x00ffffff, value);
+
+       /* watermark */
        if      ((conf & 0x3c0) == 0x180) bits = 30;
        else if ((conf & 0x3c0) == 0x140) bits = 24;
        else                              bits = 18;
        datarate = (pclk * bits) / 8;
 
-       if      (dpctrl > 0x00030000) link_nr = 4;
-       else if (dpctrl > 0x00010000) link_nr = 2;
-       else                          link_nr = 1;
-
-       link_bw  = (clksor & 0x007c0000) >> 18;
-       link_bw *= 27000;
-
        ratio  = datarate;
        ratio *= symbol;
        do_div(ratio, link_nr * link_bw);
@@ -1153,7 +1195,11 @@ nvd0_disp_intr(struct nouveau_subdev *subdev)
 
        if (intr & 0x00000001) {
                u32 stat = nv_rd32(priv, 0x61008c);
-               nv_wr32(priv, 0x61008c, stat);
+               while (stat) {
+                       int chid = __ffs(stat); stat &= ~(1 << chid);
+                       nv50_disp_chan_uevent_send(priv, chid);
+                       nv_wr32(priv, 0x61008c, 1 << chid);
+               }
                intr &= ~0x00000001;
        }
 
@@ -1209,6 +1255,10 @@ nvd0_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
        if (ret)
                return ret;
 
+       ret = nvkm_event_init(&nvd0_disp_chan_uevent, 1, 17, &priv->uevent);
+       if (ret)
+               return ret;
+
        nv_engine(priv)->sclass = nvd0_disp_base_oclass;
        nv_engine(priv)->cclass = &nv50_disp_cclass;
        nv_subdev(priv)->intr = nvd0_disp_intr;
index 47fef1e398c4ca2e5c5077a689a9d957ff9a8e1b..db144b2cf06bd7a98df12c59a718a608ba5ef27b 100644 (file)
@@ -233,6 +233,10 @@ nve0_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
        if (ret)
                return ret;
 
+       ret = nvkm_event_init(&nvd0_disp_chan_uevent, 1, 17, &priv->uevent);
+       if (ret)
+               return ret;
+
        nv_engine(priv)->sclass = nve0_disp_base_oclass;
        nv_engine(priv)->cclass = &nv50_disp_cclass;
        nv_subdev(priv)->intr = nvd0_disp_intr;
@@ -245,7 +249,7 @@ nve0_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
        priv->dac.sense = nv50_dac_sense;
        priv->sor.power = nv50_sor_power;
        priv->sor.hda_eld = nvd0_hda_eld;
-       priv->sor.hdmi = nvd0_hdmi_ctrl;
+       priv->sor.hdmi = nve0_hdmi_ctrl;
        return 0;
 }
 
index 04bda4ac4ed3dab138db7f30ca7b9b9235b10126..402d7d67d806fa0cd81dd61c758c6e868dc4cf90 100644 (file)
@@ -68,6 +68,10 @@ nvf0_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
        if (ret)
                return ret;
 
+       ret = nvkm_event_init(&nvd0_disp_chan_uevent, 1, 17, &priv->uevent);
+       if (ret)
+               return ret;
+
        nv_engine(priv)->sclass = nvf0_disp_base_oclass;
        nv_engine(priv)->cclass = &nv50_disp_cclass;
        nv_subdev(priv)->intr = nvd0_disp_intr;
@@ -80,7 +84,7 @@ nvf0_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
        priv->dac.sense = nv50_dac_sense;
        priv->sor.power = nv50_sor_power;
        priv->sor.hda_eld = nvd0_hda_eld;
-       priv->sor.hdmi = nvd0_hdmi_ctrl;
+       priv->sor.hdmi = nve0_hdmi_ctrl;
        return 0;
 }
 
index 6f6e2a898270943f4de09e88ec2307bb701d8e44..667a9070e006fdb3715e1785d3fedc1a689de8f3 100644 (file)
@@ -254,7 +254,7 @@ nvkm_output_dp_create_(struct nouveau_object *parent,
        atomic_set(&outp->lt.done, 0);
 
        /* link maintenance */
-       ret = nvkm_notify_init(&i2c->event, nvkm_output_dp_irq, true,
+       ret = nvkm_notify_init(NULL, &i2c->event, nvkm_output_dp_irq, true,
                               &(struct nvkm_i2c_ntfy_req) {
                                .mask = NVKM_I2C_IRQ,
                                .port = outp->base.edid->index,
@@ -268,7 +268,7 @@ nvkm_output_dp_create_(struct nouveau_object *parent,
        }
 
        /* hotplug detect, replaces gpio-based mechanism with aux events */
-       ret = nvkm_notify_init(&i2c->event, nvkm_output_dp_hpd, true,
+       ret = nvkm_notify_init(NULL, &i2c->event, nvkm_output_dp_hpd, true,
                               &(struct nvkm_i2c_ntfy_req) {
                                .mask = NVKM_I2C_PLUG | NVKM_I2C_UNPLUG,
                                .port = outp->base.edid->index,
index dbd43ae9df81af3e3978f798793334349027f631..6a0511d54ce641829796bb20a529cf16f2da214f 100644 (file)
@@ -40,7 +40,8 @@ int  _nouveau_disp_fini(struct nouveau_object *, bool);
 extern struct nouveau_oclass *nvkm_output_oclass;
 extern struct nouveau_oclass *nvkm_connector_oclass;
 
-int  nouveau_disp_vblank_ctor(void *data, u32 size, struct nvkm_notify *);
+int  nouveau_disp_vblank_ctor(struct nouveau_object *, void *data, u32 size,
+                             struct nvkm_notify *);
 void nouveau_disp_vblank(struct nouveau_disp *, int head);
 int  nouveau_disp_ntfy(struct nouveau_object *, u32, struct nvkm_event **);
 
index 0f999fc45ab9e7842ece2dc7d0f06f64568343fe..ac8375cf4eef556cba4b8b1f2b90ac541a2c51e1 100644 (file)
@@ -34,7 +34,8 @@
 #include <engine/fifo.h>
 
 static int
-nouveau_fifo_event_ctor(void *data, u32 size, struct nvkm_notify *notify)
+nouveau_fifo_event_ctor(struct nouveau_object *object, void *data, u32 size,
+                       struct nvkm_notify *notify)
 {
        if (size == 0) {
                notify->size  = 0;
@@ -170,7 +171,8 @@ _nouveau_fifo_channel_wr32(struct nouveau_object *object, u64 addr, u32 data)
 }
 
 int
-nouveau_fifo_uevent_ctor(void *data, u32 size, struct nvkm_notify *notify)
+nouveau_fifo_uevent_ctor(struct nouveau_object *object, void *data, u32 size,
+                        struct nvkm_notify *notify)
 {
        union {
                struct nvif_notify_uevent_req none;
index 4d2994d8cc32209800977e3008c482897b92fb4f..a0fec205f9dbe2b8c737177ccd93b5b9a75875ee 100644 (file)
@@ -175,7 +175,8 @@ nv50_software_context_ctor(struct nouveau_object *parent,
                return ret;
 
        for (i = 0; pdisp && i < pdisp->vblank.index_nr; i++) {
-               ret = nvkm_notify_init(&pdisp->vblank, pclass->vblank, false,
+               ret = nvkm_notify_init(NULL, &pdisp->vblank, pclass->vblank,
+                                      false,
                                       &(struct nvif_notify_head_req_v0) {
                                        .head = i,
                                       },
index 1794a05205d8cc5f6e9064e7e790c605ba9327f0..b0ce9f6680b5ea2f67c160a2cd64180a28324ce4 100644 (file)
@@ -48,7 +48,7 @@ int  nouveau_client_init(struct nouveau_client *);
 int  nouveau_client_fini(struct nouveau_client *, bool suspend);
 const char *nouveau_client_name(void *obj);
 
-int nvkm_client_notify_new(struct nouveau_client *, struct nvkm_event *,
+int nvkm_client_notify_new(struct nouveau_object *, struct nvkm_event *,
                           void *data, u32 size);
 int nvkm_client_notify_del(struct nouveau_client *, int index);
 int nvkm_client_notify_get(struct nouveau_client *, int index);
index 8743766454a5fd94133123aaf7acf79b6764f092..1d9d893929bb3486b1c35229ac238ea89a883dbc 100644 (file)
@@ -24,6 +24,7 @@ enum nv_subdev_type {
         * been created, and are allowed to assume any subdevs in the
         * list above them exist and have been initialised.
         */
+       NVDEV_SUBDEV_FUSE,
        NVDEV_SUBDEV_MXM,
        NVDEV_SUBDEV_MC,
        NVDEV_SUBDEV_BUS,
index 51e55d03330a406e2329edad0c42bc04be49f2e5..92876528972fd5712d9589ae843c55dabc20520f 100644 (file)
@@ -4,7 +4,8 @@
 #include <core/notify.h>
 
 struct nvkm_event_func {
-       int  (*ctor)(void *data, u32 size, struct nvkm_notify *);
+       int  (*ctor)(struct nouveau_object *, void *data, u32 size,
+                    struct nvkm_notify *);
        void (*send)(void *data, u32 size, struct nvkm_notify *);
        void (*init)(struct nvkm_event *, int type, int index);
        void (*fini)(struct nvkm_event *, int type, int index);
index 2bf7d0e322611c18842b1a1c4f95c47d018c3f92..bfe6931544fe646ab4bb205bf661c9bd6adaf205 100644 (file)
@@ -6,6 +6,10 @@ struct nouveau_mm_node {
        struct list_head fl_entry;
        struct list_head rl_entry;
 
+#define NVKM_MM_HEAP_ANY 0x00
+       u8  heap;
+#define NVKM_MM_TYPE_NONE 0x00
+#define NVKM_MM_TYPE_HOLE 0xff
        u8  type;
        u32 offset;
        u32 length;
@@ -27,10 +31,10 @@ nouveau_mm_initialised(struct nouveau_mm *mm)
 
 int  nouveau_mm_init(struct nouveau_mm *, u32 offset, u32 length, u32 block);
 int  nouveau_mm_fini(struct nouveau_mm *);
-int  nouveau_mm_head(struct nouveau_mm *, u8 type, u32 size_max, u32 size_min,
-                    u32 align, struct nouveau_mm_node **);
-int  nouveau_mm_tail(struct nouveau_mm *, u8 type, u32 size_max, u32 size_min,
-                    u32 align, struct nouveau_mm_node **);
+int  nouveau_mm_head(struct nouveau_mm *, u8 heap, u8 type, u32 size_max,
+                    u32 size_min, u32 align, struct nouveau_mm_node **);
+int  nouveau_mm_tail(struct nouveau_mm *, u8 heap, u8 type, u32 size_max,
+                    u32 size_min, u32 align, struct nouveau_mm_node **);
 void nouveau_mm_free(struct nouveau_mm *, struct nouveau_mm_node **);
 
 #endif
index 1262d8f020f377920e260e7c3b25c4dd4334a0e2..a7c3c5f578cc19e6a31795aaeacf817f4107d1b6 100644 (file)
@@ -25,8 +25,9 @@ struct nvkm_notify {
        const void *data;
 };
 
-int  nvkm_notify_init(struct nvkm_event *, int (*func)(struct nvkm_notify *),
-                     bool work, void *data, u32 size, u32 reply,
+int  nvkm_notify_init(struct nouveau_object *, struct nvkm_event *,
+                     int (*func)(struct nvkm_notify *), bool work,
+                     void *data, u32 size, u32 reply,
                      struct nvkm_notify *);
 void nvkm_notify_fini(struct nvkm_notify *);
 void nvkm_notify_get(struct nvkm_notify *);
index e5e4d930b2c2cee0ee1dd1c063cd17301fd8f651..2007453f6fce075e3f7deceb47f654510d861e11 100644 (file)
@@ -116,7 +116,8 @@ extern struct nouveau_oclass *nve0_fifo_oclass;
 extern struct nouveau_oclass *gk20a_fifo_oclass;
 extern struct nouveau_oclass *nv108_fifo_oclass;
 
-int  nouveau_fifo_uevent_ctor(void *, u32, struct nvkm_notify *);
+int  nouveau_fifo_uevent_ctor(struct nouveau_object *, void *, u32,
+                             struct nvkm_notify *);
 void nouveau_fifo_uevent(struct nouveau_fifo *);
 
 void nv04_fifo_intr(struct nouveau_subdev *);
index be037fac534c11e613564db7a5c3ace2606fb259..257ddf6d36d46fa5c7e52bb8900d6d5300ab8c45 100644 (file)
@@ -12,7 +12,6 @@ struct nouveau_bar {
 
        int (*alloc)(struct nouveau_bar *, struct nouveau_object *,
                     struct nouveau_mem *, struct nouveau_object **);
-       void __iomem *iomem;
 
        int (*kmap)(struct nouveau_bar *, struct nouveau_mem *,
                    u32 flags, struct nouveau_vma *);
diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/bios/M0205.h b/drivers/gpu/drm/nouveau/core/include/subdev/bios/M0205.h
new file mode 100644 (file)
index 0000000..e171120
--- /dev/null
@@ -0,0 +1,32 @@
+#ifndef __NVBIOS_M0205_H__
+#define __NVBIOS_M0205_H__
+
+struct nvbios_M0205T {
+       u16 freq;
+};
+
+u32 nvbios_M0205Te(struct nouveau_bios *,
+                  u8 *ver, u8 *hdr, u8 *cnt, u8 *len, u8 *snr, u8 *ssz);
+u32 nvbios_M0205Tp(struct nouveau_bios *,
+                  u8 *ver, u8 *hdr, u8 *cnt, u8 *len, u8 *snr, u8 *ssz,
+                  struct nvbios_M0205T *);
+
+struct nvbios_M0205E {
+       u8 type;
+};
+
+u32 nvbios_M0205Ee(struct nouveau_bios *, int idx,
+                  u8 *ver, u8 *hdr, u8 *cnt, u8 *len);
+u32 nvbios_M0205Ep(struct nouveau_bios *, int idx,
+                  u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
+                  struct nvbios_M0205E *);
+
+struct nvbios_M0205S {
+       u8 data;
+};
+
+u32 nvbios_M0205Se(struct nouveau_bios *, int ent, int idx, u8 *ver, u8 *hdr);
+u32 nvbios_M0205Sp(struct nouveau_bios *, int ent, int idx, u8 *ver, u8 *hdr,
+                  struct nvbios_M0205S *);
+
+#endif
diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/bios/M0209.h b/drivers/gpu/drm/nouveau/core/include/subdev/bios/M0209.h
new file mode 100644 (file)
index 0000000..67dc50d
--- /dev/null
@@ -0,0 +1,30 @@
+#ifndef __NVBIOS_M0209_H__
+#define __NVBIOS_M0209_H__
+
+u32 nvbios_M0209Te(struct nouveau_bios *,
+                  u8 *ver, u8 *hdr, u8 *cnt, u8 *len, u8 *snr, u8 *ssz);
+
+struct nvbios_M0209E {
+       u8 v00_40;
+       u8 bits;
+       u8 modulo;
+       u8 v02_40;
+       u8 v02_07;
+       u8 v03;
+};
+
+u32 nvbios_M0209Ee(struct nouveau_bios *, int idx,
+                  u8 *ver, u8 *hdr, u8 *cnt, u8 *len);
+u32 nvbios_M0209Ep(struct nouveau_bios *, int idx,
+                  u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
+                  struct nvbios_M0209E *);
+
+struct nvbios_M0209S {
+       u32 data[0x200];
+};
+
+u32 nvbios_M0209Se(struct nouveau_bios *, int ent, int idx, u8 *ver, u8 *hdr);
+u32 nvbios_M0209Sp(struct nouveau_bios *, int ent, int idx, u8 *ver, u8 *hdr,
+                  struct nvbios_M0209S *);
+
+#endif
diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/bios/fan.h b/drivers/gpu/drm/nouveau/core/include/subdev/bios/fan.h
new file mode 100644 (file)
index 0000000..119d087
--- /dev/null
@@ -0,0 +1,8 @@
+#ifndef __NVBIOS_FAN_H__
+#define __NVBIOS_FAN_H__
+
+#include <subdev/bios/therm.h>
+
+u16 nvbios_fan_parse(struct nouveau_bios *bios, struct nvbios_therm_fan *fan);
+
+#endif
index c086ac6d677d5badd33542e1c7a87047325e883e..a685bbd045680529e33d6d54e78a0359ab61c0cb 100644 (file)
 struct nouveau_bios;
 
 struct nvbios_ramcfg {
-       unsigned rammap_11_08_01:1;
-       unsigned rammap_11_08_0c:2;
-       unsigned rammap_11_08_10:1;
-       unsigned rammap_11_11_0c:2;
+       unsigned rammap_ver;
+       unsigned rammap_hdr;
+       unsigned rammap_min;
+       unsigned rammap_max;
+       union {
+               struct {
+                       unsigned rammap_10_04_02:1;
+                       unsigned rammap_10_04_08:1;
+               };
+               struct {
+                       unsigned rammap_11_08_01:1;
+                       unsigned rammap_11_08_0c:2;
+                       unsigned rammap_11_08_10:1;
+                       unsigned rammap_11_09_01ff:9;
+                       unsigned rammap_11_0a_03fe:9;
+                       unsigned rammap_11_0a_0400:1;
+                       unsigned rammap_11_0a_0800:1;
+                       unsigned rammap_11_0b_01f0:5;
+                       unsigned rammap_11_0b_0200:1;
+                       unsigned rammap_11_0b_0400:1;
+                       unsigned rammap_11_0b_0800:1;
+                       unsigned rammap_11_0d:8;
+                       unsigned rammap_11_0e:8;
+                       unsigned rammap_11_0f:8;
+                       unsigned rammap_11_11_0c:2;
+               };
+       };
 
-       unsigned ramcfg_11_01_01:1;
-       unsigned ramcfg_11_01_02:1;
-       unsigned ramcfg_11_01_04:1;
-       unsigned ramcfg_11_01_08:1;
-       unsigned ramcfg_11_01_10:1;
-       unsigned ramcfg_11_01_20:1;
-       unsigned ramcfg_11_01_40:1;
-       unsigned ramcfg_11_01_80:1;
-       unsigned ramcfg_11_02_03:2;
-       unsigned ramcfg_11_02_04:1;
-       unsigned ramcfg_11_02_08:1;
-       unsigned ramcfg_11_02_10:1;
-       unsigned ramcfg_11_02_40:1;
-       unsigned ramcfg_11_02_80:1;
-       unsigned ramcfg_11_03_0f:4;
-       unsigned ramcfg_11_03_30:2;
-       unsigned ramcfg_11_03_c0:2;
-       unsigned ramcfg_11_03_f0:4;
-       unsigned ramcfg_11_04:8;
-       unsigned ramcfg_11_06:8;
-       unsigned ramcfg_11_07_02:1;
-       unsigned ramcfg_11_07_04:1;
-       unsigned ramcfg_11_07_08:1;
-       unsigned ramcfg_11_07_10:1;
-       unsigned ramcfg_11_07_40:1;
-       unsigned ramcfg_11_07_80:1;
-       unsigned ramcfg_11_08_01:1;
-       unsigned ramcfg_11_08_02:1;
-       unsigned ramcfg_11_08_04:1;
-       unsigned ramcfg_11_08_08:1;
-       unsigned ramcfg_11_08_10:1;
-       unsigned ramcfg_11_08_20:1;
-       unsigned ramcfg_11_09:8;
+       unsigned ramcfg_ver;
+       unsigned ramcfg_hdr;
+       unsigned ramcfg_timing;
+       union {
+               struct {
+                       unsigned ramcfg_10_02_01:1;
+                       unsigned ramcfg_10_02_02:1;
+                       unsigned ramcfg_10_02_04:1;
+                       unsigned ramcfg_10_02_08:1;
+                       unsigned ramcfg_10_02_10:1;
+                       unsigned ramcfg_10_02_20:1;
+                       unsigned ramcfg_10_02_40:1;
+                       unsigned ramcfg_10_03_0f:4;
+                       unsigned ramcfg_10_05:8;
+                       unsigned ramcfg_10_06:8;
+                       unsigned ramcfg_10_07:8;
+                       unsigned ramcfg_10_08:8;
+                       unsigned ramcfg_10_09_0f:4;
+                       unsigned ramcfg_10_09_f0:4;
+               };
+               struct {
+                       unsigned ramcfg_11_01_01:1;
+                       unsigned ramcfg_11_01_02:1;
+                       unsigned ramcfg_11_01_04:1;
+                       unsigned ramcfg_11_01_08:1;
+                       unsigned ramcfg_11_01_10:1;
+                       unsigned ramcfg_11_01_20:1;
+                       unsigned ramcfg_11_01_40:1;
+                       unsigned ramcfg_11_01_80:1;
+                       unsigned ramcfg_11_02_03:2;
+                       unsigned ramcfg_11_02_04:1;
+                       unsigned ramcfg_11_02_08:1;
+                       unsigned ramcfg_11_02_10:1;
+                       unsigned ramcfg_11_02_40:1;
+                       unsigned ramcfg_11_02_80:1;
+                       unsigned ramcfg_11_03_0f:4;
+                       unsigned ramcfg_11_03_30:2;
+                       unsigned ramcfg_11_03_c0:2;
+                       unsigned ramcfg_11_03_f0:4;
+                       unsigned ramcfg_11_04:8;
+                       unsigned ramcfg_11_06:8;
+                       unsigned ramcfg_11_07_02:1;
+                       unsigned ramcfg_11_07_04:1;
+                       unsigned ramcfg_11_07_08:1;
+                       unsigned ramcfg_11_07_10:1;
+                       unsigned ramcfg_11_07_40:1;
+                       unsigned ramcfg_11_07_80:1;
+                       unsigned ramcfg_11_08_01:1;
+                       unsigned ramcfg_11_08_02:1;
+                       unsigned ramcfg_11_08_04:1;
+                       unsigned ramcfg_11_08_08:1;
+                       unsigned ramcfg_11_08_10:1;
+                       unsigned ramcfg_11_08_20:1;
+                       unsigned ramcfg_11_09:8;
+               };
+       };
 
+       unsigned timing_ver;
+       unsigned timing_hdr;
        unsigned timing[11];
-       unsigned timing_20_2e_03:2;
-       unsigned timing_20_2e_30:2;
-       unsigned timing_20_2e_c0:2;
-       unsigned timing_20_2f_03:2;
-       unsigned timing_20_2c_003f:6;
-       unsigned timing_20_2c_1fc0:7;
-       unsigned timing_20_30_f8:5;
-       unsigned timing_20_30_07:3;
-       unsigned timing_20_31_0007:3;
-       unsigned timing_20_31_0078:4;
-       unsigned timing_20_31_0780:4;
-       unsigned timing_20_31_0800:1;
-       unsigned timing_20_31_7000:3;
-       unsigned timing_20_31_8000:1;
+       union {
+               struct {
+                       unsigned timing_10_WR:8;
+                       unsigned timing_10_CL:8;
+                       unsigned timing_10_ODT:3;
+                       unsigned timing_10_CWL:8;
+               };
+               struct {
+                       unsigned timing_20_2e_03:2;
+                       unsigned timing_20_2e_30:2;
+                       unsigned timing_20_2e_c0:2;
+                       unsigned timing_20_2f_03:2;
+                       unsigned timing_20_2c_003f:6;
+                       unsigned timing_20_2c_1fc0:7;
+                       unsigned timing_20_30_f8:5;
+                       unsigned timing_20_30_07:3;
+                       unsigned timing_20_31_0007:3;
+                       unsigned timing_20_31_0078:4;
+                       unsigned timing_20_31_0780:4;
+                       unsigned timing_20_31_0800:1;
+                       unsigned timing_20_31_7000:3;
+                       unsigned timing_20_31_8000:1;
+               };
+       };
 };
 
 u8 nvbios_ramcfg_count(struct nouveau_bios *);
index 5bdf8e4db40a137df8b00f4a0183424929ad828c..47e021d3e20dd34ee76912bb2b717d4640bbe32b 100644 (file)
@@ -8,9 +8,10 @@ u32 nvbios_rammapTe(struct nouveau_bios *, u8 *ver, u8 *hdr,
 
 u32 nvbios_rammapEe(struct nouveau_bios *, int idx,
                    u8 *ver, u8 *hdr, u8 *cnt, u8 *len);
+u32 nvbios_rammapEp(struct nouveau_bios *, int idx,
+                   u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
+                   struct nvbios_ramcfg *);
 u32 nvbios_rammapEm(struct nouveau_bios *, u16 mhz,
-                   u8 *ver, u8 *hdr, u8 *cnt, u8 *len);
-u32 nvbios_rammapEp(struct nouveau_bios *, u16 mhz,
                    u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
                    struct nvbios_ramcfg *);
 
index 8dc5051df55dfdddadc6a33c0e315369b6017a3d..295d093f3b3003c2505ac2e92dd350781beaa1a9 100644 (file)
@@ -23,6 +23,12 @@ struct nvbios_therm_sensor {
        struct nvbios_therm_threshold thrs_shutdown;
 };
 
+enum nvbios_therm_fan_type {
+       NVBIOS_THERM_FAN_UNK = 0,
+       NVBIOS_THERM_FAN_TOGGLE = 1,
+       NVBIOS_THERM_FAN_PWM = 2,
+};
+
 /* no vbios have more than 6 */
 #define NOUVEAU_TEMP_FAN_TRIP_MAX 10
 struct nouveau_therm_trip_point {
@@ -38,7 +44,9 @@ enum nvbios_therm_fan_mode {
 };
 
 struct nvbios_therm_fan {
-       u16 pwm_freq;
+       enum nvbios_therm_fan_type type;
+
+       u32 pwm_freq;
 
        u8 min_duty;
        u8 max_duty;
index a5ca00dd2f6166fa77a5fb3571fb37eb055d86fd..36ed035d4d421db3ad5b6dc10b563cf46e0280e6 100644 (file)
@@ -29,6 +29,7 @@ enum nv_clk_src {
        nv_clk_src_mdiv,
 
        nv_clk_src_core,
+       nv_clk_src_core_intm,
        nv_clk_src_shader,
 
        nv_clk_src_mem,
index 871e73914b24eb7b75ca6d2d952a16ed4cc72ecc..8d0032f152054f57dbe0b0e4f35e784b50171e56 100644 (file)
@@ -111,6 +111,7 @@ extern struct nouveau_oclass *gm107_fb_oclass;
 #include <subdev/bios/ramcfg.h>
 
 struct nouveau_ram_data {
+       struct list_head head;
        struct nvbios_ramcfg bios;
        u32 freq;
 };
@@ -136,6 +137,7 @@ struct nouveau_ram {
 
        int ranks;
        int parts;
+       int part_mask;
 
        int  (*get)(struct nouveau_fb *, u64 size, u32 align,
                    u32 size_nc, u32 type, struct nouveau_mem **);
@@ -144,11 +146,6 @@ struct nouveau_ram {
        int  (*calc)(struct nouveau_fb *, u32 freq);
        int  (*prog)(struct nouveau_fb *);
        void (*tidy)(struct nouveau_fb *);
-       struct {
-               u8  version;
-               u32 data;
-               u8  size;
-       } rammap, ramcfg, timing;
        u32 freq;
        u32 mr[16];
        u32 mr1_nuts;
diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/fb/regsnv04.h b/drivers/gpu/drm/nouveau/core/include/subdev/fb/regsnv04.h
new file mode 100644 (file)
index 0000000..0f7fc0c
--- /dev/null
@@ -0,0 +1,21 @@
+#ifndef __NOUVEAU_FB_REGS_04_H__
+#define __NOUVEAU_FB_REGS_04_H__
+
+#define NV04_PFB_BOOT_0                                                0x00100000
+#      define NV04_PFB_BOOT_0_RAM_AMOUNT                       0x00000003
+#      define NV04_PFB_BOOT_0_RAM_AMOUNT_32MB                  0x00000000
+#      define NV04_PFB_BOOT_0_RAM_AMOUNT_4MB                   0x00000001
+#      define NV04_PFB_BOOT_0_RAM_AMOUNT_8MB                   0x00000002
+#      define NV04_PFB_BOOT_0_RAM_AMOUNT_16MB                  0x00000003
+#      define NV04_PFB_BOOT_0_RAM_WIDTH_128                    0x00000004
+#      define NV04_PFB_BOOT_0_RAM_TYPE                         0x00000028
+#      define NV04_PFB_BOOT_0_RAM_TYPE_SGRAM_8MBIT             0x00000000
+#      define NV04_PFB_BOOT_0_RAM_TYPE_SGRAM_16MBIT            0x00000008
+#      define NV04_PFB_BOOT_0_RAM_TYPE_SGRAM_16MBIT_4BANK      0x00000010
+#      define NV04_PFB_BOOT_0_RAM_TYPE_SDRAM_16MBIT            0x00000018
+#      define NV04_PFB_BOOT_0_RAM_TYPE_SDRAM_64MBIT            0x00000020
+#      define NV04_PFB_BOOT_0_RAM_TYPE_SDRAM_64MBITX16         0x00000028
+#      define NV04_PFB_BOOT_0_UMA_ENABLE                       0x00000100
+#      define NV04_PFB_BOOT_0_UMA_SIZE                         0x0000f000
+
+#endif
diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/fuse.h b/drivers/gpu/drm/nouveau/core/include/subdev/fuse.h
new file mode 100644 (file)
index 0000000..2b1ddb2
--- /dev/null
@@ -0,0 +1,30 @@
+#ifndef __NOUVEAU_FUSE_H__
+#define __NOUVEAU_FUSE_H__
+
+#include <core/subdev.h>
+#include <core/device.h>
+
+struct nouveau_fuse {
+       struct nouveau_subdev base;
+};
+
+static inline struct nouveau_fuse *
+nouveau_fuse(void *obj)
+{
+       return (void *)nv_device(obj)->subdev[NVDEV_SUBDEV_FUSE];
+}
+
+#define nouveau_fuse_create(p, e, o, d)                                        \
+       nouveau_fuse_create_((p), (e), (o), sizeof(**d), (void **)d)
+
+int  nouveau_fuse_create_(struct nouveau_object *, struct nouveau_object *,
+                         struct nouveau_oclass *, int, void **);
+void _nouveau_fuse_dtor(struct nouveau_object *);
+int  _nouveau_fuse_init(struct nouveau_object *);
+#define _nouveau_fuse_fini _nouveau_subdev_fini
+
+extern struct nouveau_oclass g80_fuse_oclass;
+extern struct nouveau_oclass gf100_fuse_oclass;
+extern struct nouveau_oclass gm107_fuse_oclass;
+
+#endif
index b73733d21cc71c64d9871a0b8685cf21e3a2fc75..f855140dbcb70d3c081bbadaf941cfe25a5a14c2 100644 (file)
@@ -40,7 +40,7 @@ nouveau_gpio(void *obj)
 
 extern struct nouveau_oclass *nv10_gpio_oclass;
 extern struct nouveau_oclass *nv50_gpio_oclass;
-extern struct nouveau_oclass *nv92_gpio_oclass;
+extern struct nouveau_oclass *nv94_gpio_oclass;
 extern struct nouveau_oclass *nvd0_gpio_oclass;
 extern struct nouveau_oclass *nve0_gpio_oclass;
 
index f73feec151db453eb8160fba6263dd7999e808fe..bf3d1f6113331a72045c7f154eadb04c64ebc9f6 100644 (file)
@@ -47,5 +47,8 @@ void nouveau_memx_wr32(struct nouveau_memx *, u32 addr, u32 data);
 void nouveau_memx_wait(struct nouveau_memx *,
                       u32 addr, u32 mask, u32 data, u32 nsec);
 void nouveau_memx_nsec(struct nouveau_memx *, u32 nsec);
+void nouveau_memx_wait_vblank(struct nouveau_memx *);
+void nouveau_memx_block(struct nouveau_memx *);
+void nouveau_memx_unblock(struct nouveau_memx *);
 
 #endif
index d4a68179e5863c383640cd9c339ce941e34d9909..a437597dcafc5f58e0fe08953e85037d2b073f97 100644 (file)
@@ -78,5 +78,6 @@ extern struct nouveau_oclass nv50_therm_oclass;
 extern struct nouveau_oclass nv84_therm_oclass;
 extern struct nouveau_oclass nva3_therm_oclass;
 extern struct nouveau_oclass nvd0_therm_oclass;
+extern struct nouveau_oclass gm107_therm_oclass;
 
 #endif
index 8bcbdf39cfb2db0844a5c030494096488cfc40e2..b1adc69efd88154670b09852789f2ac3413501ab 100644 (file)
@@ -38,10 +38,12 @@ struct nouveau_barobj {
 static int
 nouveau_barobj_ctor(struct nouveau_object *parent,
                    struct nouveau_object *engine,
-                   struct nouveau_oclass *oclass, void *mem, u32 size,
+                   struct nouveau_oclass *oclass, void *data, u32 size,
                    struct nouveau_object **pobject)
 {
+       struct nouveau_device *device = nv_device(parent);
        struct nouveau_bar *bar = (void *)engine;
+       struct nouveau_mem *mem = data;
        struct nouveau_barobj *barobj;
        int ret;
 
@@ -54,7 +56,13 @@ nouveau_barobj_ctor(struct nouveau_object *parent,
        if (ret)
                return ret;
 
-       barobj->iomem = bar->iomem + (u32)barobj->vma.offset;
+       barobj->iomem = ioremap(nv_device_resource_start(device, 3) +
+                               (u32)barobj->vma.offset, mem->size << 12);
+       if (!barobj->iomem) {
+               nv_warn(bar, "PRAMIN ioremap failed\n");
+               return -ENOMEM;
+       }
+
        return 0;
 }
 
@@ -63,8 +71,11 @@ nouveau_barobj_dtor(struct nouveau_object *object)
 {
        struct nouveau_bar *bar = (void *)object->engine;
        struct nouveau_barobj *barobj = (void *)object;
-       if (barobj->vma.node)
+       if (barobj->vma.node) {
+               if (barobj->iomem)
+                       iounmap(barobj->iomem);
                bar->unmap(bar, &barobj->vma);
+       }
        nouveau_object_destroy(&barobj->base);
 }
 
@@ -99,12 +110,11 @@ nouveau_bar_alloc(struct nouveau_bar *bar, struct nouveau_object *parent,
                  struct nouveau_mem *mem, struct nouveau_object **pobject)
 {
        struct nouveau_object *engine = nv_object(bar);
-       int ret = -ENOMEM;
-       if (bar->iomem) {
-               ret = nouveau_object_ctor(parent, engine,
-                                         &nouveau_barobj_oclass,
-                                         mem, 0, pobject);
-       }
+       struct nouveau_object *gpuobj;
+       int ret = nouveau_object_ctor(parent, engine, &nouveau_barobj_oclass,
+                                     mem, 0, &gpuobj);
+       if (ret == 0)
+               *pobject = gpuobj;
        return ret;
 }
 
@@ -113,7 +123,6 @@ nouveau_bar_create_(struct nouveau_object *parent,
                    struct nouveau_object *engine,
                    struct nouveau_oclass *oclass, int length, void **pobject)
 {
-       struct nouveau_device *device = nv_device(parent);
        struct nouveau_bar *bar;
        int ret;
 
@@ -123,21 +132,12 @@ nouveau_bar_create_(struct nouveau_object *parent,
        if (ret)
                return ret;
 
-       if (nv_device_resource_len(device, 3) != 0) {
-               bar->iomem = ioremap(nv_device_resource_start(device, 3),
-                                    nv_device_resource_len(device, 3));
-               if (!bar->iomem)
-                       nv_warn(bar, "PRAMIN ioremap failed\n");
-       }
-
        return 0;
 }
 
 void
 nouveau_bar_destroy(struct nouveau_bar *bar)
 {
-       if (bar->iomem)
-               iounmap(bar->iomem);
        nouveau_subdev_destroy(&bar->base);
 }
 
diff --git a/drivers/gpu/drm/nouveau/core/subdev/bios/M0205.c b/drivers/gpu/drm/nouveau/core/subdev/bios/M0205.c
new file mode 100644 (file)
index 0000000..ac9617c
--- /dev/null
@@ -0,0 +1,136 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+
+#include <subdev/bios.h>
+#include <subdev/bios/bit.h>
+#include <subdev/bios/M0205.h>
+
+u32
+nvbios_M0205Te(struct nouveau_bios *bios,
+              u8 *ver, u8 *hdr, u8 *cnt, u8 *len, u8 *snr, u8 *ssz)
+{
+       struct bit_entry bit_M;
+       u32 data = 0x00000000;
+
+       if (!bit_entry(bios, 'M', &bit_M)) {
+               if (bit_M.version == 2 && bit_M.length > 0x08)
+                       data = nv_ro32(bios, bit_M.offset + 0x05);
+               if (data) {
+                       *ver = nv_ro08(bios, data + 0x00);
+                       switch (*ver) {
+                       case 0x10:
+                               *hdr = nv_ro08(bios, data + 0x01);
+                               *len = nv_ro08(bios, data + 0x02);
+                               *ssz = nv_ro08(bios, data + 0x03);
+                               *snr = nv_ro08(bios, data + 0x04);
+                               *cnt = nv_ro08(bios, data + 0x05);
+                               return data;
+                       default:
+                               break;
+                       }
+               }
+       }
+
+       return 0x00000000;
+}
+
+u32
+nvbios_M0205Tp(struct nouveau_bios *bios,
+              u8 *ver, u8 *hdr, u8 *cnt, u8 *len, u8 *snr, u8 *ssz,
+              struct nvbios_M0205T *info)
+{
+       u32 data = nvbios_M0205Te(bios, ver, hdr, cnt, len, snr, ssz);
+       memset(info, 0x00, sizeof(*info));
+       switch (!!data * *ver) {
+       case 0x10:
+               info->freq = nv_ro16(bios, data + 0x06);
+               break;
+       default:
+               break;
+       }
+       return data;
+}
+
+u32
+nvbios_M0205Ee(struct nouveau_bios *bios, int idx,
+              u8 *ver, u8 *hdr, u8 *cnt, u8 *len)
+{
+       u8  snr, ssz;
+       u32 data = nvbios_M0205Te(bios, ver, hdr, cnt, len, &snr, &ssz);
+       if (data && idx < *cnt) {
+               data = data + *hdr + idx * (*len + (snr * ssz));
+               *hdr = *len;
+               *cnt = snr;
+               *len = ssz;
+               return data;
+       }
+       return 0x00000000;
+}
+
+u32
+nvbios_M0205Ep(struct nouveau_bios *bios, int idx,
+              u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
+              struct nvbios_M0205E *info)
+{
+       u32 data = nvbios_M0205Ee(bios, idx, ver, hdr, cnt, len);
+       memset(info, 0x00, sizeof(*info));
+       switch (!!data * *ver) {
+       case 0x10:
+               info->type = nv_ro08(bios, data + 0x00) & 0x0f;
+               return data;
+       default:
+               break;
+       }
+       return 0x00000000;
+}
+
+u32
+nvbios_M0205Se(struct nouveau_bios *bios, int ent, int idx, u8 *ver, u8 *hdr)
+{
+
+       u8  cnt, len;
+       u32 data = nvbios_M0205Ee(bios, ent, ver, hdr, &cnt, &len);
+       if (data && idx < cnt) {
+               data = data + *hdr + idx * len;
+               *hdr = len;
+               return data;
+       }
+       return 0x00000000;
+}
+
+u32
+nvbios_M0205Sp(struct nouveau_bios *bios, int ent, int idx, u8 *ver, u8 *hdr,
+              struct nvbios_M0205S *info)
+{
+       u32 data = nvbios_M0205Se(bios, ent, idx, ver, hdr);
+       memset(info, 0x00, sizeof(*info));
+       switch (!!data * *ver) {
+       case 0x10:
+               info->data = nv_ro08(bios, data + 0x00);
+               return data;
+       default:
+               break;
+       }
+       return 0x00000000;
+}
diff --git a/drivers/gpu/drm/nouveau/core/subdev/bios/M0209.c b/drivers/gpu/drm/nouveau/core/subdev/bios/M0209.c
new file mode 100644 (file)
index 0000000..b142a51
--- /dev/null
@@ -0,0 +1,137 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+
+#include <subdev/bios.h>
+#include <subdev/bios/bit.h>
+#include <subdev/bios/M0209.h>
+
+u32
+nvbios_M0209Te(struct nouveau_bios *bios,
+              u8 *ver, u8 *hdr, u8 *cnt, u8 *len, u8 *snr, u8 *ssz)
+{
+       struct bit_entry bit_M;
+       u32 data = 0x00000000;
+
+       if (!bit_entry(bios, 'M', &bit_M)) {
+               if (bit_M.version == 2 && bit_M.length > 0x0c)
+                       data = nv_ro32(bios, bit_M.offset + 0x09);
+               if (data) {
+                       *ver = nv_ro08(bios, data + 0x00);
+                       switch (*ver) {
+                       case 0x10:
+                               *hdr = nv_ro08(bios, data + 0x01);
+                               *len = nv_ro08(bios, data + 0x02);
+                               *ssz = nv_ro08(bios, data + 0x03);
+                               *snr = 1;
+                               *cnt = nv_ro08(bios, data + 0x04);
+                               return data;
+                       default:
+                               break;
+                       }
+               }
+       }
+
+       return 0x00000000;
+}
+
+u32
+nvbios_M0209Ee(struct nouveau_bios *bios, int idx,
+              u8 *ver, u8 *hdr, u8 *cnt, u8 *len)
+{
+       u8  snr, ssz;
+       u32 data = nvbios_M0209Te(bios, ver, hdr, cnt, len, &snr, &ssz);
+       if (data && idx < *cnt) {
+               data = data + *hdr + idx * (*len + (snr * ssz));
+               *hdr = *len;
+               *cnt = snr;
+               *len = ssz;
+               return data;
+       }
+       return 0x00000000;
+}
+
+u32
+nvbios_M0209Ep(struct nouveau_bios *bios, int idx,
+              u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
+              struct nvbios_M0209E *info)
+{
+       u32 data = nvbios_M0209Ee(bios, idx, ver, hdr, cnt, len);
+       memset(info, 0x00, sizeof(*info));
+       switch (!!data * *ver) {
+       case 0x10:
+               info->v00_40 = (nv_ro08(bios, data + 0x00) & 0x40) >> 6;
+               info->bits   =  nv_ro08(bios, data + 0x00) & 0x3f;
+               info->modulo =  nv_ro08(bios, data + 0x01);
+               info->v02_40 = (nv_ro08(bios, data + 0x02) & 0x40) >> 6;
+               info->v02_07 =  nv_ro08(bios, data + 0x02) & 0x07;
+               info->v03    =  nv_ro08(bios, data + 0x03);
+               return data;
+       default:
+               break;
+       }
+       return 0x00000000;
+}
+
+u32
+nvbios_M0209Se(struct nouveau_bios *bios, int ent, int idx, u8 *ver, u8 *hdr)
+{
+
+       u8  cnt, len;
+       u32 data = nvbios_M0209Ee(bios, ent, ver, hdr, &cnt, &len);
+       if (data && idx < cnt) {
+               data = data + *hdr + idx * len;
+               *hdr = len;
+               return data;
+       }
+       return 0x00000000;
+}
+
+u32
+nvbios_M0209Sp(struct nouveau_bios *bios, int ent, int idx, u8 *ver, u8 *hdr,
+              struct nvbios_M0209S *info)
+{
+       struct nvbios_M0209E M0209E;
+       u8  cnt, len;
+       u32 data = nvbios_M0209Ep(bios, ent, ver, hdr, &cnt, &len, &M0209E);
+       if (data) {
+               u32 i, data = nvbios_M0209Se(bios, ent, idx, ver, hdr);
+               memset(info, 0x00, sizeof(*info));
+               switch (!!data * *ver) {
+               case 0x10:
+                       for (i = 0; i < ARRAY_SIZE(info->data); i++) {
+                               u32 bits = (i % M0209E.modulo) * M0209E.bits;
+                               u32 mask = (1ULL << M0209E.bits) - 1;
+                               u16  off = bits / 8;
+                               u8   mod = bits % 8;
+                               info->data[i] = nv_ro32(bios, data + off);
+                               info->data[i] = info->data[i] >> mod;
+                               info->data[i] = info->data[i] & mask;
+                       }
+                       return data;
+               default:
+                       break;
+               }
+       }
+       return 0x00000000;
+}
index 88606bfaf84742c3c87a26d0d8387c29fecc9d81..bd8d348385b38fe1a3231586bdea941be9657558 100644 (file)
@@ -124,6 +124,7 @@ dcb_outp_parse(struct nouveau_bios *bios, u8 idx, u8 *ver, u8 *len,
               struct dcb_output *outp)
 {
        u16 dcb = dcb_outp(bios, idx, ver, len);
+       memset(outp, 0x00, sizeof(*outp));
        if (dcb) {
                if (*ver >= 0x20) {
                        u32 conn = nv_ro32(bios, dcb + 0x00);
diff --git a/drivers/gpu/drm/nouveau/core/subdev/bios/fan.c b/drivers/gpu/drm/nouveau/core/subdev/bios/fan.c
new file mode 100644 (file)
index 0000000..e419892
--- /dev/null
@@ -0,0 +1,93 @@
+/*
+ * Copyright 2014 Martin Peres
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Martin Peres
+ */
+
+#include <subdev/bios.h>
+#include <subdev/bios/bit.h>
+#include <subdev/bios/fan.h>
+
+u16
+nvbios_fan_table(struct nouveau_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len)
+{
+       struct bit_entry bit_P;
+       u16 fan = 0x0000;
+
+       if (!bit_entry(bios, 'P', &bit_P)) {
+               if (bit_P.version == 2 && bit_P.length >= 0x5a)
+                       fan = nv_ro16(bios, bit_P.offset + 0x58);
+
+               if (fan) {
+                       *ver = nv_ro08(bios, fan + 0);
+                       switch (*ver) {
+                       case 0x10:
+                               *hdr = nv_ro08(bios, fan + 1);
+                               *len = nv_ro08(bios, fan + 2);
+                               *cnt = nv_ro08(bios, fan + 3);
+                               return fan;
+                       default:
+                               break;
+                       }
+               }
+       }
+
+       return 0x0000;
+}
+
+u16
+nvbios_fan_entry(struct nouveau_bios *bios, int idx, u8 *ver, u8 *hdr,
+                u8 *cnt, u8 *len)
+{
+       u16 data = nvbios_fan_table(bios, ver, hdr, cnt, len);
+       if (data && idx < *cnt)
+               return data + *hdr + (idx * (*len));
+       return 0x0000;
+}
+
+u16
+nvbios_fan_parse(struct nouveau_bios *bios, struct nvbios_therm_fan *fan)
+{
+       u8 ver, hdr, cnt, len;
+
+       u16 data = nvbios_fan_entry(bios, 0, &ver, &hdr, &cnt, &len);
+       if (data) {
+               u8 type = nv_ro08(bios, data + 0x00);
+               switch (type) {
+               case 0:
+                       fan->type = NVBIOS_THERM_FAN_TOGGLE;
+                       break;
+               case 1:
+               case 2:
+                       /* TODO: Understand the difference between the two! */
+                       fan->type = NVBIOS_THERM_FAN_PWM;
+                       break;
+               default:
+                       fan->type = NVBIOS_THERM_FAN_UNK;
+               }
+
+               fan->min_duty = nv_ro08(bios, data + 0x02);
+               fan->max_duty = nv_ro08(bios, data + 0x03);
+
+               fan->pwm_freq = nv_ro32(bios, data + 0x0b) & 0xffffff;
+       }
+       return data;
+}
index 1811b2cb047276ead557d6d1025568667a1fbc24..585e69331ccce91ac3bc694e7fc09942a06ba993 100644 (file)
@@ -75,31 +75,39 @@ nvbios_rammapEe(struct nouveau_bios *bios, int idx,
 }
 
 u32
-nvbios_rammapEm(struct nouveau_bios *bios, u16 khz,
-               u8 *ver, u8 *hdr, u8 *cnt, u8 *len)
-{
-       int idx = 0;
-       u32 data;
-       while ((data = nvbios_rammapEe(bios, idx++, ver, hdr, cnt, len))) {
-               if (khz >= nv_ro16(bios, data + 0x00) &&
-                   khz <= nv_ro16(bios, data + 0x02))
-                       break;
-       }
-       return data;
-}
-
-u32
-nvbios_rammapEp(struct nouveau_bios *bios, u16 khz,
+nvbios_rammapEp(struct nouveau_bios *bios, int idx,
                u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
                struct nvbios_ramcfg *p)
 {
-       u32 data = nvbios_rammapEm(bios, khz, ver, hdr, cnt, len);
+       u32 data = nvbios_rammapEe(bios, idx, ver, hdr, cnt, len), temp;
        memset(p, 0x00, sizeof(*p));
+       p->rammap_ver = *ver;
+       p->rammap_hdr = *hdr;
        switch (!!data * *ver) {
+       case 0x10:
+               p->rammap_min      =  nv_ro16(bios, data + 0x00);
+               p->rammap_max      =  nv_ro16(bios, data + 0x02);
+               p->rammap_10_04_02 = (nv_ro08(bios, data + 0x04) & 0x02) >> 1;
+               p->rammap_10_04_08 = (nv_ro08(bios, data + 0x04) & 0x08) >> 3;
+               break;
        case 0x11:
+               p->rammap_min      =  nv_ro16(bios, data + 0x00);
+               p->rammap_max      =  nv_ro16(bios, data + 0x02);
                p->rammap_11_08_01 = (nv_ro08(bios, data + 0x08) & 0x01) >> 0;
                p->rammap_11_08_0c = (nv_ro08(bios, data + 0x08) & 0x0c) >> 2;
                p->rammap_11_08_10 = (nv_ro08(bios, data + 0x08) & 0x10) >> 4;
+               temp = nv_ro32(bios, data + 0x09);
+               p->rammap_11_09_01ff = (temp & 0x000001ff) >> 0;
+               p->rammap_11_0a_03fe = (temp & 0x0003fe00) >> 9;
+               p->rammap_11_0a_0400 = (temp & 0x00040000) >> 18;
+               p->rammap_11_0a_0800 = (temp & 0x00080000) >> 19;
+               p->rammap_11_0b_01f0 = (temp & 0x01f00000) >> 20;
+               p->rammap_11_0b_0200 = (temp & 0x02000000) >> 25;
+               p->rammap_11_0b_0400 = (temp & 0x04000000) >> 26;
+               p->rammap_11_0b_0800 = (temp & 0x08000000) >> 27;
+               p->rammap_11_0d    =  nv_ro08(bios, data + 0x0d);
+               p->rammap_11_0e    =  nv_ro08(bios, data + 0x0e);
+               p->rammap_11_0f    =  nv_ro08(bios, data + 0x0f);
                p->rammap_11_11_0c = (nv_ro08(bios, data + 0x11) & 0x0c) >> 2;
                break;
        default:
@@ -109,6 +117,20 @@ nvbios_rammapEp(struct nouveau_bios *bios, u16 khz,
        return data;
 }
 
+u32
+nvbios_rammapEm(struct nouveau_bios *bios, u16 mhz,
+               u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
+               struct nvbios_ramcfg *info)
+{
+       int idx = 0;
+       u32 data;
+       while ((data = nvbios_rammapEp(bios, idx++, ver, hdr, cnt, len, info))) {
+               if (mhz >= info->rammap_min && mhz <= info->rammap_max)
+                       break;
+       }
+       return data;
+}
+
 u32
 nvbios_rammapSe(struct nouveau_bios *bios, u32 data,
                u8 ever, u8 ehdr, u8 ecnt, u8 elen, int idx,
@@ -129,8 +151,28 @@ nvbios_rammapSp(struct nouveau_bios *bios, u32 data,
                u8 *ver, u8 *hdr, struct nvbios_ramcfg *p)
 {
        data = nvbios_rammapSe(bios, data, ever, ehdr, ecnt, elen, idx, ver, hdr);
+       p->ramcfg_ver = *ver;
+       p->ramcfg_hdr = *hdr;
        switch (!!data * *ver) {
+       case 0x10:
+               p->ramcfg_timing   =  nv_ro08(bios, data + 0x01);
+               p->ramcfg_10_02_01 = (nv_ro08(bios, data + 0x02) & 0x01) >> 0;
+               p->ramcfg_10_02_02 = (nv_ro08(bios, data + 0x02) & 0x02) >> 1;
+               p->ramcfg_10_02_04 = (nv_ro08(bios, data + 0x02) & 0x04) >> 2;
+               p->ramcfg_10_02_08 = (nv_ro08(bios, data + 0x02) & 0x08) >> 3;
+               p->ramcfg_10_02_10 = (nv_ro08(bios, data + 0x02) & 0x10) >> 4;
+               p->ramcfg_10_02_20 = (nv_ro08(bios, data + 0x02) & 0x20) >> 5;
+               p->ramcfg_10_02_40 = (nv_ro08(bios, data + 0x02) & 0x40) >> 6;
+               p->ramcfg_10_03_0f = (nv_ro08(bios, data + 0x03) & 0x0f) >> 0;
+               p->ramcfg_10_05    = (nv_ro08(bios, data + 0x05) & 0xff) >> 0;
+               p->ramcfg_10_06    = (nv_ro08(bios, data + 0x06) & 0xff) >> 0;
+               p->ramcfg_10_07    = (nv_ro08(bios, data + 0x07) & 0xff) >> 0;
+               p->ramcfg_10_08    = (nv_ro08(bios, data + 0x08) & 0xff) >> 0;
+               p->ramcfg_10_09_0f = (nv_ro08(bios, data + 0x09) & 0x0f) >> 0;
+               p->ramcfg_10_09_f0 = (nv_ro08(bios, data + 0x09) & 0xf0) >> 4;
+               break;
        case 0x11:
+               p->ramcfg_timing   =  nv_ro08(bios, data + 0x00);
                p->ramcfg_11_01_01 = (nv_ro08(bios, data + 0x01) & 0x01) >> 0;
                p->ramcfg_11_01_02 = (nv_ro08(bios, data + 0x01) & 0x02) >> 1;
                p->ramcfg_11_01_04 = (nv_ro08(bios, data + 0x01) & 0x04) >> 2;
index 350d44ab2ba24b9e56a9dbf178a86497159cc326..46d955eb51eba6f956b238d0134fb2043fec7bd4 100644 (file)
@@ -89,7 +89,15 @@ nvbios_timingEp(struct nouveau_bios *bios, int idx,
                struct nvbios_ramcfg *p)
 {
        u16 data = nvbios_timingEe(bios, idx, ver, hdr, cnt, len), temp;
+       p->timing_ver = *ver;
+       p->timing_hdr = *hdr;
        switch (!!data * *ver) {
+       case 0x10:
+               p->timing_10_WR = nv_ro08(bios, data + 0x00);
+               p->timing_10_CL = nv_ro08(bios, data + 0x02);
+               p->timing_10_ODT = nv_ro08(bios, data + 0x0e) & 0x07;
+               p->timing_10_CWL = nv_ro08(bios, data + 0x13);
+               break;
        case 0x20:
                p->timing[0] = nv_ro32(bios, data + 0x00);
                p->timing[1] = nv_ro32(bios, data + 0x04);
index a276a711294a21e3bc6be1bbe102444df26e2ad6..e51b72d471293e304053c46eb4890c892f6a94a0 100644 (file)
@@ -573,7 +573,7 @@ nouveau_clock_create_(struct nouveau_object *parent,
 
        clk->allow_reclock = allow_reclock;
 
-       ret = nvkm_notify_init(&device->event, nouveau_clock_pwrsrc, true,
+       ret = nvkm_notify_init(NULL, &device->event, nouveau_clock_pwrsrc, true,
                               NULL, 0, 0, &clk->pwrsrc_ntfy);
        if (ret)
                return ret;
index 087012b189569ee8cf21e1d2f02327023093f25d..094551d8ad9b44619f9950c30c6553d1f0a5b730 100644 (file)
  * OTHER DEALINGS IN THE SOFTWARE.
  *
  * Authors: Ben Skeggs
+ *          Roy Spliet
  */
 
+#include <engine/fifo.h>
 #include <subdev/bios.h>
 #include <subdev/bios/pll.h>
 #include <subdev/timer.h>
@@ -42,9 +44,17 @@ static u32
 read_vco(struct nva3_clock_priv *priv, int clk)
 {
        u32 sctl = nv_rd32(priv, 0x4120 + (clk * 4));
-       if ((sctl & 0x00000030) != 0x00000030)
+
+       switch (sctl & 0x00000030) {
+       case 0x00000000:
+               return nv_device(priv)->crystal;
+       case 0x00000020:
                return read_pll(priv, 0x41, 0x00e820);
-       return read_pll(priv, 0x42, 0x00e8a0);
+       case 0x00000030:
+               return read_pll(priv, 0x42, 0x00e8a0);
+       default:
+               return 0;
+       }
 }
 
 static u32
@@ -66,14 +76,25 @@ read_clk(struct nva3_clock_priv *priv, int clk, bool ignore_en)
        if (!ignore_en && !(sctl & 0x00000100))
                return 0;
 
+       /* out_alt */
+       if (sctl & 0x00000400)
+               return 108000;
+
+       /* vco_out */
        switch (sctl & 0x00003000) {
        case 0x00000000:
-               return nv_device(priv)->crystal;
+               if (!(sctl & 0x00000200))
+                       return nv_device(priv)->crystal;
+               return 0;
        case 0x00002000:
                if (sctl & 0x00000040)
                        return 108000;
                return 100000;
        case 0x00003000:
+               /* vco_enable */
+               if (!(sctl & 0x00000001))
+                       return 0;
+
                sclk = read_vco(priv, clk);
                sdiv = ((sctl & 0x003f0000) >> 16) + 2;
                return (sclk * 2) / sdiv;
@@ -95,7 +116,9 @@ read_pll(struct nva3_clock_priv *priv, int clk, u32 pll)
                        N = (coef & 0x0000ff00) >> 8;
                        P = (coef & 0x003f0000) >> 16;
 
-                       /* no post-divider on these.. */
+                       /* no post-divider on these..
+                        * XXX: it looks more like two post-"dividers" that
+                        * cross each other out in the default RPLL config */
                        if ((pll & 0x00ff00) == 0x00e800)
                                P = 1;
 
@@ -114,13 +137,13 @@ static int
 nva3_clock_read(struct nouveau_clock *clk, enum nv_clk_src src)
 {
        struct nva3_clock_priv *priv = (void *)clk;
+       u32 hsrc;
 
        switch (src) {
        case nv_clk_src_crystal:
                return nv_device(priv)->crystal;
-       case nv_clk_src_href:
-               return 100000;
        case nv_clk_src_core:
+       case nv_clk_src_core_intm:
                return read_pll(priv, 0x00, 0x4200);
        case nv_clk_src_shader:
                return read_pll(priv, 0x01, 0x4220);
@@ -132,24 +155,33 @@ nva3_clock_read(struct nouveau_clock *clk, enum nv_clk_src src)
                return read_clk(priv, 0x21, false);
        case nv_clk_src_daemon:
                return read_clk(priv, 0x25, false);
+       case nv_clk_src_host:
+               hsrc = (nv_rd32(priv, 0xc040) & 0x30000000) >> 28;
+               switch (hsrc) {
+               case 0:
+                       return read_clk(priv, 0x1d, false);
+               case 2:
+               case 3:
+                       return 277000;
+               default:
+                       nv_error(clk, "unknown HOST clock source %d\n", hsrc);
+                       return -EINVAL;
+               }
        default:
                nv_error(clk, "invalid clock source %d\n", src);
                return -EINVAL;
        }
+
+       return 0;
 }
 
 int
-nva3_clock_info(struct nouveau_clock *clock, int clk, u32 pll, u32 khz,
+nva3_clk_info(struct nouveau_clock *clock, int clk, u32 khz,
                struct nva3_clock_info *info)
 {
-       struct nouveau_bios *bios = nouveau_bios(clock);
        struct nva3_clock_priv *priv = (void *)clock;
-       struct nvbios_pll limits;
-       u32 oclk, sclk, sdiv;
-       int P, N, M, diff;
-       int ret;
+       u32 oclk, sclk, sdiv, diff;
 
-       info->pll = 0;
        info->clk = 0;
 
        switch (khz) {
@@ -164,43 +196,69 @@ nva3_clock_info(struct nouveau_clock *clock, int clk, u32 pll, u32 khz,
                return khz;
        default:
                sclk = read_vco(priv, clk);
-               sdiv = min((sclk * 2) / (khz - 2999), (u32)65);
-               /* if the clock has a PLL attached, and we can get a within
-                * [-2, 3) MHz of a divider, we'll disable the PLL and use
-                * the divider instead.
-                *
-                * divider can go as low as 2, limited here because NVIDIA
+               sdiv = min((sclk * 2) / khz, (u32)65);
+               oclk = (sclk * 2) / sdiv;
+               diff = ((khz + 3000) - oclk);
+
+               /* When imprecise, play it safe and aim for a clock lower than
+                * desired rather than higher */
+               if (diff < 0) {
+                       sdiv++;
+                       oclk = (sclk * 2) / sdiv;
+               }
+
+               /* divider can go as low as 2, limited here because NVIDIA
                 * and the VBIOS on my NVA8 seem to prefer using the PLL
                 * for 810MHz - is there a good reason?
-                */
+                * XXX: PLLs with refclk 810MHz?  */
                if (sdiv > 4) {
-                       oclk = (sclk * 2) / sdiv;
-                       diff = khz - oclk;
-                       if (!pll || (diff >= -2000 && diff < 3000)) {
-                               info->clk = (((sdiv - 2) << 16) | 0x00003100);
-                               return oclk;
-                       }
+                       info->clk = (((sdiv - 2) << 16) | 0x00003100);
+                       return oclk;
                }
 
-               if (!pll)
-                       return -ERANGE;
                break;
        }
 
+       return -ERANGE;
+}
+
+int
+nva3_pll_info(struct nouveau_clock *clock, int clk, u32 pll, u32 khz,
+               struct nva3_clock_info *info)
+{
+       struct nouveau_bios *bios = nouveau_bios(clock);
+       struct nva3_clock_priv *priv = (void *)clock;
+       struct nvbios_pll limits;
+       int P, N, M, diff;
+       int ret;
+
+       info->pll = 0;
+
+       /* If we can get a within [-2, 3) MHz of a divider, we'll disable the
+        * PLL and use the divider instead. */
+       ret = nva3_clk_info(clock, clk, khz, info);
+       diff = khz - ret;
+       if (!pll || (diff >= -2000 && diff < 3000)) {
+               goto out;
+       }
+
+       /* Try with PLL */
        ret = nvbios_pll_parse(bios, pll, &limits);
        if (ret)
                return ret;
 
-       limits.refclk = read_clk(priv, clk - 0x10, true);
-       if (!limits.refclk)
+       ret = nva3_clk_info(clock, clk - 0x10, limits.refclk, info);
+       if (ret != limits.refclk)
                return -EINVAL;
 
        ret = nva3_pll_calc(nv_subdev(priv), &limits, khz, &N, NULL, &M, &P);
        if (ret >= 0) {
-               info->clk = nv_rd32(priv, 0x4120 + (clk * 4));
                info->pll = (P << 16) | (N << 8) | M;
        }
 
+out:
+       info->fb_delay = max(((khz + 7566) / 15133), (u32) 18);
+
        return ret ? ret : -ERANGE;
 }
 
@@ -208,13 +266,76 @@ static int
 calc_clk(struct nva3_clock_priv *priv, struct nouveau_cstate *cstate,
         int clk, u32 pll, int idx)
 {
-       int ret = nva3_clock_info(&priv->base, clk, pll, cstate->domain[idx],
+       int ret = nva3_pll_info(&priv->base, clk, pll, cstate->domain[idx],
                                  &priv->eng[idx]);
        if (ret >= 0)
                return 0;
        return ret;
 }
 
+static int
+calc_host(struct nva3_clock_priv *priv, struct nouveau_cstate *cstate)
+{
+       int ret = 0;
+       u32 kHz = cstate->domain[nv_clk_src_host];
+       struct nva3_clock_info *info = &priv->eng[nv_clk_src_host];
+
+       if (kHz == 277000) {
+               info->clk = 0;
+               info->host_out = NVA3_HOST_277;
+               return 0;
+       }
+
+       info->host_out = NVA3_HOST_CLK;
+
+       ret = nva3_clk_info(&priv->base, 0x1d, kHz, info);
+       if (ret >= 0)
+               return 0;
+       return ret;
+}
+
+int
+nva3_clock_pre(struct nouveau_clock *clk, unsigned long *flags)
+{
+       struct nouveau_fifo *pfifo = nouveau_fifo(clk);
+
+       /* halt and idle execution engines */
+       nv_mask(clk, 0x020060, 0x00070000, 0x00000000);
+       nv_mask(clk, 0x002504, 0x00000001, 0x00000001);
+       /* Wait until the interrupt handler is finished */
+       if (!nv_wait(clk, 0x000100, 0xffffffff, 0x00000000))
+               return -EBUSY;
+
+       if (pfifo)
+               pfifo->pause(pfifo, flags);
+
+       if (!nv_wait(clk, 0x002504, 0x00000010, 0x00000010))
+               return -EIO;
+       if (!nv_wait(clk, 0x00251c, 0x0000003f, 0x0000003f))
+               return -EIO;
+
+       return 0;
+}
+
+void
+nva3_clock_post(struct nouveau_clock *clk, unsigned long *flags)
+{
+       struct nouveau_fifo *pfifo = nouveau_fifo(clk);
+
+       if (pfifo && flags)
+               pfifo->start(pfifo, flags);
+
+       nv_mask(clk, 0x002504, 0x00000001, 0x00000000);
+       nv_mask(clk, 0x020060, 0x00070000, 0x00040000);
+}
+
+static void
+disable_clk_src(struct nva3_clock_priv *priv, u32 src)
+{
+       nv_mask(priv, src, 0x00000100, 0x00000000);
+       nv_mask(priv, src, 0x00000001, 0x00000000);
+}
+
 static void
 prog_pll(struct nva3_clock_priv *priv, int clk, u32 pll, int idx)
 {
@@ -223,24 +344,35 @@ prog_pll(struct nva3_clock_priv *priv, int clk, u32 pll, int idx)
        const u32 src1 = 0x004160 + (clk * 4);
        const u32 ctrl = pll + 0;
        const u32 coef = pll + 4;
+       u32 bypass;
 
        if (info->pll) {
-               nv_mask(priv, src0, 0x00000101, 0x00000101);
+               /* Always start from a non-PLL clock */
+               bypass = nv_rd32(priv, ctrl)  & 0x00000008;
+               if (!bypass) {
+                       nv_mask(priv, src1, 0x00000101, 0x00000101);
+                       nv_mask(priv, ctrl, 0x00000008, 0x00000008);
+                       udelay(20);
+               }
+
+               nv_mask(priv, src0, 0x003f3141, 0x00000101 | info->clk);
                nv_wr32(priv, coef, info->pll);
                nv_mask(priv, ctrl, 0x00000015, 0x00000015);
                nv_mask(priv, ctrl, 0x00000010, 0x00000000);
-               nv_wait(priv, ctrl, 0x00020000, 0x00020000);
+               if (!nv_wait(priv, ctrl, 0x00020000, 0x00020000)) {
+                       nv_mask(priv, ctrl, 0x00000010, 0x00000010);
+                       nv_mask(priv, src0, 0x00000101, 0x00000000);
+                       return;
+               }
                nv_mask(priv, ctrl, 0x00000010, 0x00000010);
                nv_mask(priv, ctrl, 0x00000008, 0x00000000);
-               nv_mask(priv, src1, 0x00000100, 0x00000000);
-               nv_mask(priv, src1, 0x00000001, 0x00000000);
+               disable_clk_src(priv, src1);
        } else {
                nv_mask(priv, src1, 0x003f3141, 0x00000101 | info->clk);
                nv_mask(priv, ctrl, 0x00000018, 0x00000018);
                udelay(20);
                nv_mask(priv, ctrl, 0x00000001, 0x00000000);
-               nv_mask(priv, src0, 0x00000100, 0x00000000);
-               nv_mask(priv, src0, 0x00000001, 0x00000000);
+               disable_clk_src(priv, src0);
        }
 }
 
@@ -251,18 +383,72 @@ prog_clk(struct nva3_clock_priv *priv, int clk, int idx)
        nv_mask(priv, 0x004120 + (clk * 4), 0x003f3141, 0x00000101 | info->clk);
 }
 
+static void
+prog_host(struct nva3_clock_priv *priv)
+{
+       struct nva3_clock_info *info = &priv->eng[nv_clk_src_host];
+       u32 hsrc = (nv_rd32(priv, 0xc040));
+
+       switch (info->host_out) {
+       case NVA3_HOST_277:
+               if ((hsrc & 0x30000000) == 0) {
+                       nv_wr32(priv, 0xc040, hsrc | 0x20000000);
+                       disable_clk_src(priv, 0x4194);
+               }
+               break;
+       case NVA3_HOST_CLK:
+               prog_clk(priv, 0x1d, nv_clk_src_host);
+               if ((hsrc & 0x30000000) >= 0x20000000) {
+                       nv_wr32(priv, 0xc040, hsrc & ~0x30000000);
+               }
+               break;
+       default:
+               break;
+       }
+
+       /* This seems to be a clock gating factor on idle, always set to 64 */
+       nv_wr32(priv, 0xc044, 0x3e);
+}
+
+static void
+prog_core(struct nva3_clock_priv *priv, int idx)
+{
+       struct nva3_clock_info *info = &priv->eng[idx];
+       u32 fb_delay = nv_rd32(priv, 0x10002c);
+
+       if (fb_delay < info->fb_delay)
+               nv_wr32(priv, 0x10002c, info->fb_delay);
+
+       prog_pll(priv, 0x00, 0x004200, idx);
+
+       if (fb_delay > info->fb_delay)
+               nv_wr32(priv, 0x10002c, info->fb_delay);
+}
+
 static int
 nva3_clock_calc(struct nouveau_clock *clk, struct nouveau_cstate *cstate)
 {
        struct nva3_clock_priv *priv = (void *)clk;
+       struct nva3_clock_info *core = &priv->eng[nv_clk_src_core];
        int ret;
 
        if ((ret = calc_clk(priv, cstate, 0x10, 0x4200, nv_clk_src_core)) ||
            (ret = calc_clk(priv, cstate, 0x11, 0x4220, nv_clk_src_shader)) ||
            (ret = calc_clk(priv, cstate, 0x20, 0x0000, nv_clk_src_disp)) ||
-           (ret = calc_clk(priv, cstate, 0x21, 0x0000, nv_clk_src_vdec)))
+           (ret = calc_clk(priv, cstate, 0x21, 0x0000, nv_clk_src_vdec)) ||
+           (ret = calc_host(priv, cstate)))
                return ret;
 
+       /* XXX: Should be reading the highest bit in the VBIOS clock to decide
+        * whether to use a PLL or not... but using a PLL defeats the purpose */
+       if (core->pll) {
+               ret = nva3_clk_info(clk, 0x10,
+                               cstate->domain[nv_clk_src_core_intm],
+                               &priv->eng[nv_clk_src_core_intm]);
+               if (ret < 0)
+                       return ret;
+       }
+
        return 0;
 }
 
@@ -270,11 +456,31 @@ static int
 nva3_clock_prog(struct nouveau_clock *clk)
 {
        struct nva3_clock_priv *priv = (void *)clk;
-       prog_pll(priv, 0x00, 0x004200, nv_clk_src_core);
+       struct nva3_clock_info *core = &priv->eng[nv_clk_src_core];
+       int ret = 0;
+       unsigned long flags;
+       unsigned long *f = &flags;
+
+       ret = nva3_clock_pre(clk, f);
+       if (ret)
+               goto out;
+
+       if (core->pll)
+               prog_core(priv, nv_clk_src_core_intm);
+
+       prog_core(priv,  nv_clk_src_core);
        prog_pll(priv, 0x01, 0x004220, nv_clk_src_shader);
        prog_clk(priv, 0x20, nv_clk_src_disp);
        prog_clk(priv, 0x21, nv_clk_src_vdec);
-       return 0;
+       prog_host(priv);
+
+out:
+       if (ret == -EBUSY)
+               f = NULL;
+
+       nva3_clock_post(clk, f);
+
+       return ret;
 }
 
 static void
@@ -284,13 +490,14 @@ nva3_clock_tidy(struct nouveau_clock *clk)
 
 static struct nouveau_clocks
 nva3_domain[] = {
-       { nv_clk_src_crystal, 0xff },
-       { nv_clk_src_href   , 0xff },
-       { nv_clk_src_core   , 0x00, 0, "core", 1000 },
-       { nv_clk_src_shader , 0x01, 0, "shader", 1000 },
-       { nv_clk_src_mem    , 0x02, 0, "memory", 1000 },
-       { nv_clk_src_vdec   , 0x03 },
-       { nv_clk_src_disp   , 0x04 },
+       { nv_clk_src_crystal  , 0xff },
+       { nv_clk_src_core     , 0x00, 0, "core", 1000 },
+       { nv_clk_src_shader   , 0x01, 0, "shader", 1000 },
+       { nv_clk_src_mem      , 0x02, 0, "memory", 1000 },
+       { nv_clk_src_vdec     , 0x03 },
+       { nv_clk_src_disp     , 0x04 },
+       { nv_clk_src_host     , 0x05 },
+       { nv_clk_src_core_intm, 0x06 },
        { nv_clk_src_max }
 };
 
index 6229a509b42e77a88777245fb5c3a2855e9baa2b..a45a1038b12fbe8f6ffec100734b1a7d40e95b57 100644 (file)
@@ -6,9 +6,15 @@
 struct nva3_clock_info {
        u32 clk;
        u32 pll;
+       enum {
+               NVA3_HOST_277,
+               NVA3_HOST_CLK,
+       } host_out;
+       u32 fb_delay;
 };
 
-int nva3_clock_info(struct nouveau_clock *, int, u32, u32,
+int nva3_pll_info(struct nouveau_clock *, int, u32, u32,
                    struct nva3_clock_info *);
-
+int nva3_clock_pre(struct nouveau_clock *clk, unsigned long *flags);
+void nva3_clock_post(struct nouveau_clock *clk, unsigned long *flags);
 #endif
index 74e19731b1b7db97fc942a70d6e7289a25083a93..54aeab8005a0042ec0ae4dccfd5908c7bef95843 100644 (file)
@@ -28,6 +28,7 @@
 #include <subdev/timer.h>
 #include <subdev/clock.h>
 
+#include "nva3.h"
 #include "pll.h"
 
 struct nvaa_clock_priv {
@@ -299,25 +300,14 @@ static int
 nvaa_clock_prog(struct nouveau_clock *clk)
 {
        struct nvaa_clock_priv *priv = (void *)clk;
-       struct nouveau_fifo *pfifo = nouveau_fifo(clk);
+       u32 pllmask = 0, mast;
        unsigned long flags;
-       u32 pllmask = 0, mast, ptherm_gate;
-       int ret = -EBUSY;
-
-       /* halt and idle execution engines */
-       ptherm_gate = nv_mask(clk, 0x020060, 0x00070000, 0x00000000);
-       nv_mask(clk, 0x002504, 0x00000001, 0x00000001);
-       /* Wait until the interrupt handler is finished */
-       if (!nv_wait(clk, 0x000100, 0xffffffff, 0x00000000))
-               goto resume;
-
-       if (pfifo)
-               pfifo->pause(pfifo, &flags);
+       unsigned long *f = &flags;
+       int ret = 0;
 
-       if (!nv_wait(clk, 0x002504, 0x00000010, 0x00000010))
-               goto resume;
-       if (!nv_wait(clk, 0x00251c, 0x0000003f, 0x0000003f))
-               goto resume;
+       ret = nva3_clock_pre(clk, f);
+       if (ret)
+               goto out;
 
        /* First switch to safe clocks: href */
        mast = nv_mask(clk, 0xc054, 0x03400e70, 0x03400640);
@@ -375,15 +365,8 @@ nvaa_clock_prog(struct nouveau_clock *clk)
        }
 
        nv_wr32(clk, 0xc054, mast);
-       ret = 0;
 
 resume:
-       if (pfifo)
-               pfifo->start(pfifo, &flags);
-
-       nv_mask(clk, 0x002504, 0x00000001, 0x00000000);
-       nv_wr32(clk, 0x020060, ptherm_gate);
-
        /* Disable some PLLs and dividers when unused */
        if (priv->csrc != nv_clk_src_core) {
                nv_wr32(clk, 0x4040, 0x00000000);
@@ -395,6 +378,12 @@ resume:
                nv_mask(clk, 0x4020, 0x80000000, 0x00000000);
        }
 
+out:
+       if (ret == -EBUSY)
+               f = NULL;
+
+       nva3_clock_post(clk, f);
+
        return ret;
 }
 
index 4fe49cf4c99a37eaf32d79eecf029501cac353f7..6103484fea724da49f8984529b12d5f7a6f8b371 100644 (file)
 
 #include <core/device.h>
 
-#define NV04_PFB_BOOT_0                                                0x00100000
-#      define NV04_PFB_BOOT_0_RAM_AMOUNT                       0x00000003
-#      define NV04_PFB_BOOT_0_RAM_AMOUNT_32MB                  0x00000000
-#      define NV04_PFB_BOOT_0_RAM_AMOUNT_4MB                   0x00000001
-#      define NV04_PFB_BOOT_0_RAM_AMOUNT_8MB                   0x00000002
-#      define NV04_PFB_BOOT_0_RAM_AMOUNT_16MB                  0x00000003
-#      define NV04_PFB_BOOT_0_RAM_WIDTH_128                    0x00000004
-#      define NV04_PFB_BOOT_0_RAM_TYPE                         0x00000028
-#      define NV04_PFB_BOOT_0_RAM_TYPE_SGRAM_8MBIT             0x00000000
-#      define NV04_PFB_BOOT_0_RAM_TYPE_SGRAM_16MBIT            0x00000008
-#      define NV04_PFB_BOOT_0_RAM_TYPE_SGRAM_16MBIT_4BANK      0x00000010
-#      define NV04_PFB_BOOT_0_RAM_TYPE_SDRAM_16MBIT            0x00000018
-#      define NV04_PFB_BOOT_0_RAM_TYPE_SDRAM_64MBIT            0x00000020
-#      define NV04_PFB_BOOT_0_RAM_TYPE_SDRAM_64MBITX16         0x00000028
-#      define NV04_PFB_BOOT_0_UMA_ENABLE                       0x00000100
-#      define NV04_PFB_BOOT_0_UMA_SIZE                         0x0000f000
+#include <subdev/fb/regsnv04.h>
+
 #define NV04_PFB_DEBUG_0                                       0x00100080
 #      define NV04_PFB_DEBUG_0_PAGE_MODE                       0x00000001
 #      define NV04_PFB_DEBUG_0_REFRESH_OFF                     0x00000010
index 66fe959b4f7431dd2cc1b9ce6520263560fb769f..7fbbe05d5c608d7037b07e9e9690f0035ba6dfa3 100644 (file)
@@ -40,7 +40,7 @@ nouveau_gddr5_calc(struct nouveau_ram *ram, bool nuts)
        int WL, CL, WR, at[2], dt, ds;
        int rq = ram->freq < 1000000; /* XXX */
 
-       switch (ram->ramcfg.version) {
+       switch (ram->next->bios.ramcfg_ver) {
        case 0x11:
                pd =  ram->next->bios.ramcfg_11_01_80;
                lf =  ram->next->bios.ramcfg_11_01_40;
@@ -54,7 +54,7 @@ nouveau_gddr5_calc(struct nouveau_ram *ram, bool nuts)
                return -ENOSYS;
        }
 
-       switch (ram->timing.version) {
+       switch (ram->next->bios.timing_ver) {
        case 0x20:
                WL = (ram->next->bios.timing[1] & 0x00000f80) >> 7;
                CL = (ram->next->bios.timing[1] & 0x0000001f);
index f003c1b1893f48c1a115e55e835a749d98b41207..2209ade63339ed93645f600bc5d0eb3e7626e2ba 100644 (file)
@@ -45,7 +45,7 @@ nv20_fb_tile_comp(struct nouveau_fb *pfb, int i, u32 size, u32 flags,
 {
        u32 tiles = DIV_ROUND_UP(size, 0x40);
        u32 tags  = round_up(tiles / pfb->ram->parts, 0x40);
-       if (!nouveau_mm_head(&pfb->tags, 1, tags, tags, 1, &tile->tag)) {
+       if (!nouveau_mm_head(&pfb->tags, 0, 1, tags, tags, 1, &tile->tag)) {
                if (!(flags & 2)) tile->zcomp = 0x00000000; /* Z16 */
                else              tile->zcomp = 0x04000000; /* Z24S8 */
                tile->zcomp |= tile->tag->offset;
index f34f4223210b8552bc143f096bd8117ca216e158..e2a66c355c50dff411098012dc808a085905dd1e 100644 (file)
@@ -32,7 +32,7 @@ nv25_fb_tile_comp(struct nouveau_fb *pfb, int i, u32 size, u32 flags,
 {
        u32 tiles = DIV_ROUND_UP(size, 0x40);
        u32 tags  = round_up(tiles / pfb->ram->parts, 0x40);
-       if (!nouveau_mm_head(&pfb->tags, 1, tags, tags, 1, &tile->tag)) {
+       if (!nouveau_mm_head(&pfb->tags, 0, 1, tags, tags, 1, &tile->tag)) {
                if (!(flags & 2)) tile->zcomp = 0x00100000; /* Z16 */
                else              tile->zcomp = 0x00200000; /* Z24S8 */
                tile->zcomp |= tile->tag->offset;
index 69093f7151f01d168117098983a6812e9b3ff965..cbec402ba5b92861f0f75dc48e781aaacd2212ec 100644 (file)
@@ -51,7 +51,7 @@ nv30_fb_tile_comp(struct nouveau_fb *pfb, int i, u32 size, u32 flags,
 {
        u32 tiles = DIV_ROUND_UP(size, 0x40);
        u32 tags  = round_up(tiles / pfb->ram->parts, 0x40);
-       if (!nouveau_mm_head(&pfb->tags, 1, tags, tags, 1, &tile->tag)) {
+       if (!nouveau_mm_head(&pfb->tags, 0, 1, tags, tags, 1, &tile->tag)) {
                if (flags & 2) tile->zcomp |= 0x01000000; /* Z16 */
                else           tile->zcomp |= 0x02000000; /* Z24S8 */
                tile->zcomp |= ((tile->tag->offset           ) >> 6);
index 161b06e8fc3f75f31567054c3f68117e0691e93e..b2cf8c69fb2ee67e9d50c973adf159fd6a16d431 100644 (file)
@@ -32,7 +32,7 @@ nv35_fb_tile_comp(struct nouveau_fb *pfb, int i, u32 size, u32 flags,
 {
        u32 tiles = DIV_ROUND_UP(size, 0x40);
        u32 tags  = round_up(tiles / pfb->ram->parts, 0x40);
-       if (!nouveau_mm_head(&pfb->tags, 1, tags, tags, 1, &tile->tag)) {
+       if (!nouveau_mm_head(&pfb->tags, 0, 1, tags, tags, 1, &tile->tag)) {
                if (flags & 2) tile->zcomp |= 0x04000000; /* Z16 */
                else           tile->zcomp |= 0x08000000; /* Z24S8 */
                tile->zcomp |= ((tile->tag->offset           ) >> 6);
index 2dd3d0aab6bb6434fdb780c1152f71453aa22324..b4cdae2a3b2f192bcbd4ee13fa45bef459435311 100644 (file)
@@ -32,7 +32,7 @@ nv36_fb_tile_comp(struct nouveau_fb *pfb, int i, u32 size, u32 flags,
 {
        u32 tiles = DIV_ROUND_UP(size, 0x40);
        u32 tags  = round_up(tiles / pfb->ram->parts, 0x40);
-       if (!nouveau_mm_head(&pfb->tags, 1, tags, tags, 1, &tile->tag)) {
+       if (!nouveau_mm_head(&pfb->tags, 0, 1, tags, tags, 1, &tile->tag)) {
                if (flags & 2) tile->zcomp |= 0x10000000; /* Z16 */
                else           tile->zcomp |= 0x20000000; /* Z24S8 */
                tile->zcomp |= ((tile->tag->offset           ) >> 6);
index 95a115ab0c860bc591f63033f6305c7f15fb0b59..52814258c21279f8fe88bd3b316dfac0fa4a95e3 100644 (file)
@@ -33,7 +33,7 @@ nv40_fb_tile_comp(struct nouveau_fb *pfb, int i, u32 size, u32 flags,
        u32 tiles = DIV_ROUND_UP(size, 0x80);
        u32 tags  = round_up(tiles / pfb->ram->parts, 0x100);
        if ( (flags & 2) &&
-           !nouveau_mm_head(&pfb->tags, 1, tags, tags, 1, &tile->tag)) {
+           !nouveau_mm_head(&pfb->tags, 0, 1, tags, tags, 1, &tile->tag)) {
                tile->zcomp  = 0x28000000; /* Z24S8_SPLIT_GRAD */
                tile->zcomp |= ((tile->tag->offset           ) >> 8);
                tile->zcomp |= ((tile->tag->offset + tags - 1) >> 8) << 13;
index 82273f832e42ef1fa5d7993e8db299c6e74be499..60322e906dd403c5b2d206c4590605f612d4ba0d 100644 (file)
@@ -35,6 +35,7 @@ extern struct nouveau_oclass nve0_ram_oclass;
 extern struct nouveau_oclass gk20a_ram_oclass;
 extern struct nouveau_oclass gm107_ram_oclass;
 
+int nouveau_sddr2_calc(struct nouveau_ram *ram);
 int nouveau_sddr3_calc(struct nouveau_ram *ram);
 int nouveau_gddr5_calc(struct nouveau_ram *ram, bool nuts);
 
index 2af9cfd2c60fd7667b54037fa9254224b065bd50..d1fbbe4b00a2a4ef1eeccef2f43b00cfa02c096d 100644 (file)
@@ -12,16 +12,32 @@ struct ramfuc {
 struct ramfuc_reg {
        int sequence;
        bool force;
-       u32 addr[2];
+       u32 addr;
+       u32 stride; /* in bytes */
+       u32 mask;
        u32 data;
 };
 
+static inline struct ramfuc_reg
+ramfuc_stride(u32 addr, u32 stride, u32 mask)
+{
+       return (struct ramfuc_reg) {
+               .sequence = 0,
+               .addr = addr,
+               .stride = stride,
+               .mask = mask,
+               .data = 0xdeadbeef,
+       };
+}
+
 static inline struct ramfuc_reg
 ramfuc_reg2(u32 addr1, u32 addr2)
 {
        return (struct ramfuc_reg) {
                .sequence = 0,
-               .addr = { addr1, addr2 },
+               .addr = addr1,
+               .stride = addr2 - addr1,
+               .mask = 0x3,
                .data = 0xdeadbeef,
        };
 }
@@ -29,7 +45,13 @@ ramfuc_reg2(u32 addr1, u32 addr2)
 static noinline struct ramfuc_reg
 ramfuc_reg(u32 addr)
 {
-       return ramfuc_reg2(addr, addr);
+       return (struct ramfuc_reg) {
+               .sequence = 0,
+               .addr = addr,
+               .stride = 0,
+               .mask = 0x1,
+               .data = 0xdeadbeef,
+       };
 }
 
 static inline int
@@ -62,18 +84,25 @@ static inline u32
 ramfuc_rd32(struct ramfuc *ram, struct ramfuc_reg *reg)
 {
        if (reg->sequence != ram->sequence)
-               reg->data = nv_rd32(ram->pfb, reg->addr[0]);
+               reg->data = nv_rd32(ram->pfb, reg->addr);
        return reg->data;
 }
 
 static inline void
 ramfuc_wr32(struct ramfuc *ram, struct ramfuc_reg *reg, u32 data)
 {
+       unsigned int mask, off = 0;
+
        reg->sequence = ram->sequence;
        reg->data = data;
-       if (reg->addr[0] != reg->addr[1])
-               nouveau_memx_wr32(ram->memx, reg->addr[1], reg->data);
-       nouveau_memx_wr32(ram->memx, reg->addr[0], reg->data);
+
+       for (mask = reg->mask; mask > 0; mask = (mask & ~1) >> 1) {
+               if (mask & 1) {
+                       nouveau_memx_wr32(ram->memx, reg->addr+off, reg->data);
+               }
+
+               off += reg->stride;
+       }
 }
 
 static inline void
@@ -105,14 +134,35 @@ ramfuc_nsec(struct ramfuc *ram, u32 nsec)
        nouveau_memx_nsec(ram->memx, nsec);
 }
 
-#define ram_init(s,p)       ramfuc_init(&(s)->base, (p))
-#define ram_exec(s,e)       ramfuc_exec(&(s)->base, (e))
-#define ram_have(s,r)       ((s)->r_##r.addr[0] != 0x000000)
-#define ram_rd32(s,r)       ramfuc_rd32(&(s)->base, &(s)->r_##r)
-#define ram_wr32(s,r,d)     ramfuc_wr32(&(s)->base, &(s)->r_##r, (d))
-#define ram_nuke(s,r)       ramfuc_nuke(&(s)->base, &(s)->r_##r)
-#define ram_mask(s,r,m,d)   ramfuc_mask(&(s)->base, &(s)->r_##r, (m), (d))
-#define ram_wait(s,r,m,d,n) ramfuc_wait(&(s)->base, (r), (m), (d), (n))
-#define ram_nsec(s,n)       ramfuc_nsec(&(s)->base, (n))
+static inline void
+ramfuc_wait_vblank(struct ramfuc *ram)
+{
+       nouveau_memx_wait_vblank(ram->memx);
+}
+
+static inline void
+ramfuc_block(struct ramfuc *ram)
+{
+       nouveau_memx_block(ram->memx);
+}
+
+static inline void
+ramfuc_unblock(struct ramfuc *ram)
+{
+       nouveau_memx_unblock(ram->memx);
+}
+
+#define ram_init(s,p)        ramfuc_init(&(s)->base, (p))
+#define ram_exec(s,e)        ramfuc_exec(&(s)->base, (e))
+#define ram_have(s,r)        ((s)->r_##r.addr != 0x000000)
+#define ram_rd32(s,r)        ramfuc_rd32(&(s)->base, &(s)->r_##r)
+#define ram_wr32(s,r,d)      ramfuc_wr32(&(s)->base, &(s)->r_##r, (d))
+#define ram_nuke(s,r)        ramfuc_nuke(&(s)->base, &(s)->r_##r)
+#define ram_mask(s,r,m,d)    ramfuc_mask(&(s)->base, &(s)->r_##r, (m), (d))
+#define ram_wait(s,r,m,d,n)  ramfuc_wait(&(s)->base, (r), (m), (d), (n))
+#define ram_nsec(s,n)        ramfuc_nsec(&(s)->base, (n))
+#define ram_wait_vblank(s)   ramfuc_wait_vblank(&(s)->base)
+#define ram_block(s)         ramfuc_block(&(s)->base)
+#define ram_unblock(s)       ramfuc_unblock(&(s)->base)
 
 #endif
index e781080d33276132722c4b382da880819f9459ec..1972268d14104d284aed6cf07a12b75147f01317 100644 (file)
  * Authors: Ben Skeggs
  */
 
-#define NV04_PFB_BOOT_0                                                0x00100000
-#      define NV04_PFB_BOOT_0_RAM_AMOUNT                       0x00000003
-#      define NV04_PFB_BOOT_0_RAM_AMOUNT_32MB                  0x00000000
-#      define NV04_PFB_BOOT_0_RAM_AMOUNT_4MB                   0x00000001
-#      define NV04_PFB_BOOT_0_RAM_AMOUNT_8MB                   0x00000002
-#      define NV04_PFB_BOOT_0_RAM_AMOUNT_16MB                  0x00000003
-#      define NV04_PFB_BOOT_0_RAM_WIDTH_128                    0x00000004
-#      define NV04_PFB_BOOT_0_RAM_TYPE                         0x00000028
-#      define NV04_PFB_BOOT_0_RAM_TYPE_SGRAM_8MBIT             0x00000000
-#      define NV04_PFB_BOOT_0_RAM_TYPE_SGRAM_16MBIT            0x00000008
-#      define NV04_PFB_BOOT_0_RAM_TYPE_SGRAM_16MBIT_4BANK      0x00000010
-#      define NV04_PFB_BOOT_0_RAM_TYPE_SDRAM_16MBIT            0x00000018
-#      define NV04_PFB_BOOT_0_RAM_TYPE_SDRAM_64MBIT            0x00000020
-#      define NV04_PFB_BOOT_0_RAM_TYPE_SDRAM_64MBITX16         0x00000028
-#      define NV04_PFB_BOOT_0_UMA_ENABLE                       0x00000100
-#      define NV04_PFB_BOOT_0_UMA_SIZE                         0x0000f000
+#include <subdev/fb/regsnv04.h>
 
 #include "priv.h"
 
index e5d12c24cc43e132df49142ba23256c7e99599f5..64a983c9662576bad70207aad209564b32cd6b4f 100644 (file)
@@ -280,7 +280,7 @@ nv50_ram_get(struct nouveau_fb *pfb, u64 size, u32 align, u32 ncmin,
                if (align == 16) {
                        int n = (max >> 4) * comp;
 
-                       ret = nouveau_mm_head(tags, 1, n, n, 1, &mem->tag);
+                       ret = nouveau_mm_head(tags, 0, 1, n, n, 1, &mem->tag);
                        if (ret)
                                mem->tag = NULL;
                }
@@ -296,9 +296,9 @@ nv50_ram_get(struct nouveau_fb *pfb, u64 size, u32 align, u32 ncmin,
        type = nv50_fb_memtype[type];
        do {
                if (back)
-                       ret = nouveau_mm_tail(heap, type, max, min, align, &r);
+                       ret = nouveau_mm_tail(heap, 0, type, max, min, align, &r);
                else
-                       ret = nouveau_mm_head(heap, type, max, min, align, &r);
+                       ret = nouveau_mm_head(heap, 0, type, max, min, align, &r);
                if (ret) {
                        mutex_unlock(&pfb->base.mutex);
                        pfb->ram->put(pfb, &mem);
@@ -319,27 +319,22 @@ nv50_ram_get(struct nouveau_fb *pfb, u64 size, u32 align, u32 ncmin,
 static u32
 nv50_fb_vram_rblock(struct nouveau_fb *pfb, struct nouveau_ram *ram)
 {
-       int i, parts, colbits, rowbitsa, rowbitsb, banks;
+       int colbits, rowbitsa, rowbitsb, banks;
        u64 rowsize, predicted;
-       u32 r0, r4, rt, ru, rblock_size;
+       u32 r0, r4, rt, rblock_size;
 
        r0 = nv_rd32(pfb, 0x100200);
        r4 = nv_rd32(pfb, 0x100204);
        rt = nv_rd32(pfb, 0x100250);
-       ru = nv_rd32(pfb, 0x001540);
-       nv_debug(pfb, "memcfg 0x%08x 0x%08x 0x%08x 0x%08x\n", r0, r4, rt, ru);
-
-       for (i = 0, parts = 0; i < 8; i++) {
-               if (ru & (0x00010000 << i))
-                       parts++;
-       }
+       nv_debug(pfb, "memcfg 0x%08x 0x%08x 0x%08x 0x%08x\n", r0, r4, rt,
+                       nv_rd32(pfb, 0x001540));
 
        colbits  =  (r4 & 0x0000f000) >> 12;
        rowbitsa = ((r4 & 0x000f0000) >> 16) + 8;
        rowbitsb = ((r4 & 0x00f00000) >> 20) + 8;
        banks    = 1 << (((r4 & 0x03000000) >> 24) + 2);
 
-       rowsize = parts * banks * (1 << colbits) * 8;
+       rowsize = ram->parts * banks * (1 << colbits) * 8;
        predicted = rowsize << rowbitsa;
        if (r0 & 0x00000004)
                predicted += rowsize << rowbitsb;
@@ -376,6 +371,9 @@ nv50_ram_create_(struct nouveau_object *parent, struct nouveau_object *engine,
        ram->size = nv_rd32(pfb, 0x10020c);
        ram->size = (ram->size & 0xffffff00) | ((ram->size & 0x000000ff) << 32);
 
+       ram->part_mask = (nv_rd32(pfb, 0x001540) & 0x00ff0000) >> 16;
+       ram->parts = hweight8(ram->part_mask);
+
        switch (nv_rd32(pfb, 0x100714) & 0x00000007) {
        case 0: ram->type = NV_MEM_TYPE_DDR1; break;
        case 1:
index 8076fb195dd514569466ae95d1ee12ef929ffab9..3601deca0bd5d01dd81920fc789aa5a96e148950 100644 (file)
@@ -79,20 +79,27 @@ nva3_ram_calc(struct nouveau_fb *pfb, u32 freq)
        struct nva3_ram *ram = (void *)pfb->ram;
        struct nva3_ramfuc *fuc = &ram->fuc;
        struct nva3_clock_info mclk;
-       u8  ver, cnt, len, strap;
+       struct nouveau_ram_data *next;
+       u8  ver, hdr, cnt, len, strap;
        u32 data;
-       struct {
-               u32 data;
-               u8  size;
-       } rammap, ramcfg, timing;
        u32 r004018, r100760, ctrl;
        u32 unk714, unk718, unk71c;
-       int ret;
+       int ret, i;
+
+       next = &ram->base.target;
+       next->freq = freq;
+       ram->base.next = next;
 
        /* lookup memory config data relevant to the target frequency */
-       rammap.data = nvbios_rammapEm(bios, freq / 1000, &ver, &rammap.size,
-                                    &cnt, &ramcfg.size);
-       if (!rammap.data || ver != 0x10 || rammap.size < 0x0e) {
+       i = 0;
+       while ((data = nvbios_rammapEp(bios, i++, &ver, &hdr, &cnt, &len,
+                                     &next->bios))) {
+               if (freq / 1000 >= next->bios.rammap_min &&
+                   freq / 1000 <= next->bios.rammap_max)
+                       break;
+       }
+
+       if (!data || ver != 0x10 || hdr < 0x0e) {
                nv_error(pfb, "invalid/missing rammap entry\n");
                return -EINVAL;
        }
@@ -104,26 +111,25 @@ nva3_ram_calc(struct nouveau_fb *pfb, u32 freq)
                return -EINVAL;
        }
 
-       ramcfg.data = rammap.data + rammap.size + (strap * ramcfg.size);
-       if (!ramcfg.data || ver != 0x10 || ramcfg.size < 0x0e) {
+       data = nvbios_rammapSp(bios, data, ver, hdr, cnt, len, strap,
+                              &ver, &hdr, &next->bios);
+       if (!data || ver != 0x10 || hdr < 0x0e) {
                nv_error(pfb, "invalid/missing ramcfg entry\n");
                return -EINVAL;
        }
 
        /* lookup memory timings, if bios says they're present */
-       strap = nv_ro08(bios, ramcfg.data + 0x01);
-       if (strap != 0xff) {
-               timing.data = nvbios_timingEe(bios, strap, &ver, &timing.size,
-                                            &cnt, &len);
-               if (!timing.data || ver != 0x10 || timing.size < 0x19) {
+       if (next->bios.ramcfg_timing != 0xff) {
+               data = nvbios_timingEp(bios, next->bios.ramcfg_timing,
+                                      &ver, &hdr, &cnt, &len,
+                                      &next->bios);
+               if (!data || ver != 0x10 || hdr < 0x19) {
                        nv_error(pfb, "invalid/missing timing entry\n");
                        return -EINVAL;
                }
-       } else {
-               timing.data = 0;
        }
 
-       ret = nva3_clock_info(nouveau_clock(pfb), 0x12, 0x4000, freq, &mclk);
+       ret = nva3_pll_info(nouveau_clock(pfb), 0x12, 0x4000, freq, &mclk);
        if (ret < 0) {
                nv_error(pfb, "failed mclk calculation\n");
                return ret;
@@ -163,17 +169,17 @@ nva3_ram_calc(struct nouveau_fb *pfb, u32 freq)
                ram_mask(fuc, 0x004168, 0x003f3141, ctrl);
        }
 
-       if ( (nv_ro08(bios, ramcfg.data + 0x02) & 0x10)) {
+       if (next->bios.ramcfg_10_02_10) {
                ram_mask(fuc, 0x111104, 0x00000600, 0x00000000);
        } else {
                ram_mask(fuc, 0x111100, 0x40000000, 0x40000000);
                ram_mask(fuc, 0x111104, 0x00000180, 0x00000000);
        }
 
-       if (!(nv_ro08(bios, rammap.data + 0x04) & 0x02))
+       if (!next->bios.rammap_10_04_02)
                ram_mask(fuc, 0x100200, 0x00000800, 0x00000000);
        ram_wr32(fuc, 0x611200, 0x00003300);
-       if (!(nv_ro08(bios, ramcfg.data + 0x02) & 0x10))
+       if (!next->bios.ramcfg_10_02_10)
                ram_wr32(fuc, 0x111100, 0x4c020000); /*XXX*/
 
        ram_wr32(fuc, 0x1002d4, 0x00000001);
@@ -202,17 +208,16 @@ nva3_ram_calc(struct nouveau_fb *pfb, u32 freq)
                ram_wr32(fuc, 0x004018, 0x0000d000 | r004018);
        }
 
-       if ( (nv_ro08(bios, rammap.data + 0x04) & 0x08)) {
-               u32 unk5a0 = (nv_ro16(bios, ramcfg.data + 0x05) << 8) |
-                             nv_ro08(bios, ramcfg.data + 0x05);
-               u32 unk5a4 = (nv_ro16(bios, ramcfg.data + 0x07));
-               u32 unk804 = (nv_ro08(bios, ramcfg.data + 0x09) & 0xf0) << 16 |
-                            (nv_ro08(bios, ramcfg.data + 0x03) & 0x0f) << 16 |
-                            (nv_ro08(bios, ramcfg.data + 0x09) & 0x0f) |
-                            0x80000000;
-               ram_wr32(fuc, 0x1005a0, unk5a0);
-               ram_wr32(fuc, 0x1005a4, unk5a4);
-               ram_wr32(fuc, 0x10f804, unk804);
+       if (next->bios.rammap_10_04_08) {
+               ram_wr32(fuc, 0x1005a0, next->bios.ramcfg_10_06 << 16 |
+                                       next->bios.ramcfg_10_05 << 8 |
+                                       next->bios.ramcfg_10_05);
+               ram_wr32(fuc, 0x1005a4, next->bios.ramcfg_10_08 << 8 |
+                                       next->bios.ramcfg_10_07);
+               ram_wr32(fuc, 0x10f804, next->bios.ramcfg_10_09_f0 << 20 |
+                                       next->bios.ramcfg_10_03_0f << 16 |
+                                       next->bios.ramcfg_10_09_0f |
+                                       0x80000000);
                ram_mask(fuc, 0x10053c, 0x00001000, 0x00000000);
        } else {
                ram_mask(fuc, 0x10053c, 0x00001000, 0x00001000);
@@ -250,27 +255,26 @@ nva3_ram_calc(struct nouveau_fb *pfb, u32 freq)
        ram_mask(fuc, 0x100220[0], 0x00000000, 0x00000000);
        ram_mask(fuc, 0x100220[8], 0x00000000, 0x00000000);
 
-       data = (nv_ro08(bios, ramcfg.data + 0x02) & 0x08) ? 0x00000000 : 0x00001000;
-       ram_mask(fuc, 0x100200, 0x00001000, data);
+       ram_mask(fuc, 0x100200, 0x00001000, !next->bios.ramcfg_10_02_08 << 12);
 
        unk714 = ram_rd32(fuc, 0x100714) & ~0xf0000010;
        unk718 = ram_rd32(fuc, 0x100718) & ~0x00000100;
        unk71c = ram_rd32(fuc, 0x10071c) & ~0x00000100;
-       if ( (nv_ro08(bios, ramcfg.data + 0x02) & 0x20))
+       if (next->bios.ramcfg_10_02_20)
                unk714 |= 0xf0000000;
-       if (!(nv_ro08(bios, ramcfg.data + 0x02) & 0x04))
+       if (!next->bios.ramcfg_10_02_04)
                unk714 |= 0x00000010;
        ram_wr32(fuc, 0x100714, unk714);
 
-       if (nv_ro08(bios, ramcfg.data + 0x02) & 0x01)
+       if (next->bios.ramcfg_10_02_01)
                unk71c |= 0x00000100;
        ram_wr32(fuc, 0x10071c, unk71c);
 
-       if (nv_ro08(bios, ramcfg.data + 0x02) & 0x02)
+       if (next->bios.ramcfg_10_02_02)
                unk718 |= 0x00000100;
        ram_wr32(fuc, 0x100718, unk718);
 
-       if (nv_ro08(bios, ramcfg.data + 0x02) & 0x10)
+       if (next->bios.ramcfg_10_02_10)
                ram_wr32(fuc, 0x111100, 0x48000000); /*XXX*/
 
        ram_mask(fuc, mr[0], 0x100, 0x100);
@@ -282,9 +286,9 @@ nva3_ram_calc(struct nouveau_fb *pfb, u32 freq)
        ram_nsec(fuc, 12000);
 
        ram_wr32(fuc, 0x611200, 0x00003330);
-       if ( (nv_ro08(bios, rammap.data + 0x04) & 0x02))
+       if (next->bios.rammap_10_04_02)
                ram_mask(fuc, 0x100200, 0x00000800, 0x00000800);
-       if ( (nv_ro08(bios, ramcfg.data + 0x02) & 0x10)) {
+       if (next->bios.ramcfg_10_02_10) {
                ram_mask(fuc, 0x111104, 0x00000180, 0x00000180);
                ram_mask(fuc, 0x111100, 0x40000000, 0x00000000);
        } else {
@@ -404,11 +408,11 @@ nva3_ram_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
        ram->fuc.r_0x100714 = ramfuc_reg(0x100714);
        ram->fuc.r_0x100718 = ramfuc_reg(0x100718);
        ram->fuc.r_0x10071c = ramfuc_reg(0x10071c);
-       ram->fuc.r_0x100760 = ramfuc_reg(0x100760);
-       ram->fuc.r_0x1007a0 = ramfuc_reg(0x1007a0);
-       ram->fuc.r_0x1007e0 = ramfuc_reg(0x1007e0);
+       ram->fuc.r_0x100760 = ramfuc_stride(0x100760, 4, ram->base.part_mask);
+       ram->fuc.r_0x1007a0 = ramfuc_stride(0x1007a0, 4, ram->base.part_mask);
+       ram->fuc.r_0x1007e0 = ramfuc_stride(0x1007e0, 4, ram->base.part_mask);
        ram->fuc.r_0x10f804 = ramfuc_reg(0x10f804);
-       ram->fuc.r_0x1110e0 = ramfuc_reg(0x1110e0);
+       ram->fuc.r_0x1110e0 = ramfuc_stride(0x1110e0, 4, ram->base.part_mask);
        ram->fuc.r_0x111100 = ramfuc_reg(0x111100);
        ram->fuc.r_0x111104 = ramfuc_reg(0x111104);
        ram->fuc.r_0x611200 = ramfuc_reg(0x611200);
index 2b284b19276330aabd6b584c55b21eb727232662..735cb9580abe88330efe78b8718378b619d4d66d 100644 (file)
@@ -133,6 +133,7 @@ nvc0_ram_calc(struct nouveau_fb *pfb, u32 freq)
        struct nouveau_bios *bios = nouveau_bios(pfb);
        struct nvc0_ram *ram = (void *)pfb->ram;
        struct nvc0_ramfuc *fuc = &ram->fuc;
+       struct nvbios_ramcfg cfg;
        u8  ver, cnt, len, strap;
        struct {
                u32 data;
@@ -145,7 +146,7 @@ nvc0_ram_calc(struct nouveau_fb *pfb, u32 freq)
 
        /* lookup memory config data relevant to the target frequency */
        rammap.data = nvbios_rammapEm(bios, freq / 1000, &ver, &rammap.size,
-                                    &cnt, &ramcfg.size);
+                                    &cnt, &ramcfg.size, &cfg);
        if (!rammap.data || ver != 0x10 || rammap.size < 0x0e) {
                nv_error(pfb, "invalid/missing rammap entry\n");
                return -EINVAL;
@@ -483,9 +484,9 @@ nvc0_ram_get(struct nouveau_fb *pfb, u64 size, u32 align, u32 ncmin,
 
        do {
                if (back)
-                       ret = nouveau_mm_tail(mm, 1, size, ncmin, align, &r);
+                       ret = nouveau_mm_tail(mm, 0, 1, size, ncmin, align, &r);
                else
-                       ret = nouveau_mm_head(mm, 1, size, ncmin, align, &r);
+                       ret = nouveau_mm_head(mm, 0, 1, size, ncmin, align, &r);
                if (ret) {
                        mutex_unlock(&pfb->base.mutex);
                        pfb->ram->put(pfb, &mem);
@@ -562,7 +563,7 @@ nvc0_ram_create_(struct nouveau_object *parent, struct nouveau_object *engine,
                offset = (0x0200000000ULL >> 12) + (bsize << 8);
                length = (ram->size >> 12) - ((bsize * parts) << 8) - rsvd_tail;
 
-               ret = nouveau_mm_init(&pfb->vram, offset, length, 0);
+               ret = nouveau_mm_init(&pfb->vram, offset, length, 1);
                if (ret)
                        nouveau_mm_fini(&pfb->vram);
        }
index c5b46e3023199299362f68181ef98ec9f4db7644..6bae474abb4476ed46510b74000c68b457e817f4 100644 (file)
@@ -29,6 +29,8 @@
 #include <subdev/bios/init.h>
 #include <subdev/bios/rammap.h>
 #include <subdev/bios/timing.h>
+#include <subdev/bios/M0205.h>
+#include <subdev/bios/M0209.h>
 
 #include <subdev/clock.h>
 #include <subdev/clock/pll.h>
 
 #include "ramfuc.h"
 
-/* binary driver only executes this path if the condition (a) is true
- * for any configuration (combination of rammap+ramcfg+timing) that
- * can be reached on a given card.  for now, we will execute the branch
- * unconditionally in the hope that a "false everywhere" in the bios
- * tables doesn't actually mean "don't touch this".
- */
-#define NOTE00(a) 1
-
 struct nve0_ramfuc {
        struct ramfuc base;
 
@@ -134,10 +128,12 @@ struct nve0_ram {
        struct nouveau_ram base;
        struct nve0_ramfuc fuc;
 
+       struct list_head cfg;
        u32 parts;
        u32 pmask;
        u32 pnuts;
 
+       struct nvbios_ramcfg diff;
        int from;
        int mode;
        int N1, fN1, M1, P1;
@@ -241,7 +237,7 @@ nve0_ram_nuts(struct nve0_ram *ram, struct ramfuc_reg *reg,
 {
        struct nve0_fb_priv *priv = (void *)nouveau_fb(ram);
        struct ramfuc *fuc = &ram->fuc.base;
-       u32 addr = 0x110000 + (reg->addr[0] & 0xfff);
+       u32 addr = 0x110000 + (reg->addr & 0xfff);
        u32 mask = _mask | _copy;
        u32 data = (_data & _mask) | (reg->data & _copy);
        u32 i;
@@ -268,6 +264,7 @@ nve0_ram_calc_gddr5(struct nouveau_fb *pfb, u32 freq)
        u32 mask, data;
 
        ram_mask(fuc, 0x10f808, 0x40000000, 0x40000000);
+       ram_block(fuc);
        ram_wr32(fuc, 0x62c000, 0x0f0f0000);
 
        /* MR1: turn termination on early, for some reason.. */
@@ -478,7 +475,7 @@ nve0_ram_calc_gddr5(struct nouveau_fb *pfb, u32 freq)
        ram_mask(fuc, 0x10f2e8, 0xffffffff, next->bios.timing[9]);
 
        data = mask = 0x00000000;
-       if (NOTE00(ramcfg_08_20)) {
+       if (ram->diff.ramcfg_11_08_20) {
                if (next->bios.ramcfg_11_08_20)
                        data |= 0x01000000;
                mask |= 0x01000000;
@@ -486,11 +483,11 @@ nve0_ram_calc_gddr5(struct nouveau_fb *pfb, u32 freq)
        ram_mask(fuc, 0x10f200, mask, data);
 
        data = mask = 0x00000000;
-       if (NOTE00(ramcfg_02_03 != 0)) {
+       if (ram->diff.ramcfg_11_02_03) {
                data |= next->bios.ramcfg_11_02_03 << 8;
                mask |= 0x00000300;
        }
-       if (NOTE00(ramcfg_01_10)) {
+       if (ram->diff.ramcfg_11_01_10) {
                if (next->bios.ramcfg_11_01_10)
                        data |= 0x70000000;
                mask |= 0x70000000;
@@ -498,11 +495,11 @@ nve0_ram_calc_gddr5(struct nouveau_fb *pfb, u32 freq)
        ram_mask(fuc, 0x10f604, mask, data);
 
        data = mask = 0x00000000;
-       if (NOTE00(timing_30_07 != 0)) {
+       if (ram->diff.timing_20_30_07) {
                data |= next->bios.timing_20_30_07 << 28;
                mask |= 0x70000000;
        }
-       if (NOTE00(ramcfg_01_01)) {
+       if (ram->diff.ramcfg_11_01_01) {
                if (next->bios.ramcfg_11_01_01)
                        data |= 0x00000100;
                mask |= 0x00000100;
@@ -510,11 +507,11 @@ nve0_ram_calc_gddr5(struct nouveau_fb *pfb, u32 freq)
        ram_mask(fuc, 0x10f614, mask, data);
 
        data = mask = 0x00000000;
-       if (NOTE00(timing_30_07 != 0)) {
+       if (ram->diff.timing_20_30_07) {
                data |= next->bios.timing_20_30_07 << 28;
                mask |= 0x70000000;
        }
-       if (NOTE00(ramcfg_01_02)) {
+       if (ram->diff.ramcfg_11_01_02) {
                if (next->bios.ramcfg_11_01_02)
                        data |= 0x00000100;
                mask |= 0x00000100;
@@ -548,11 +545,11 @@ nve0_ram_calc_gddr5(struct nouveau_fb *pfb, u32 freq)
        ram_wr32(fuc, 0x10f870, 0x11111111 * next->bios.ramcfg_11_03_0f);
 
        data = mask = 0x00000000;
-       if (NOTE00(ramcfg_02_03 != 0)) {
+       if (ram->diff.ramcfg_11_02_03) {
                data |= next->bios.ramcfg_11_02_03;
                mask |= 0x00000003;
        }
-       if (NOTE00(ramcfg_01_10)) {
+       if (ram->diff.ramcfg_11_01_10) {
                if (next->bios.ramcfg_11_01_10)
                        data |= 0x00000004;
                mask |= 0x00000004;
@@ -666,6 +663,7 @@ nve0_ram_calc_gddr5(struct nouveau_fb *pfb, u32 freq)
        if (next->bios.ramcfg_11_07_02)
                nve0_ram_train(fuc, 0x80020000, 0x01000000);
 
+       ram_unblock(fuc);
        ram_wr32(fuc, 0x62c000, 0x0f0f0f00);
 
        if (next->bios.rammap_11_08_01)
@@ -695,6 +693,7 @@ nve0_ram_calc_sddr3(struct nouveau_fb *pfb, u32 freq)
        u32 mask, data;
 
        ram_mask(fuc, 0x10f808, 0x40000000, 0x40000000);
+       ram_block(fuc);
        ram_wr32(fuc, 0x62c000, 0x0f0f0000);
 
        if (vc == 1 && ram_have(fuc, gpio2E)) {
@@ -917,6 +916,7 @@ nve0_ram_calc_sddr3(struct nouveau_fb *pfb, u32 freq)
        ram_mask(fuc, 0x10f200, 0x80000000, 0x00000000);
        ram_nsec(fuc, 1000);
 
+       ram_unblock(fuc);
        ram_wr32(fuc, 0x62c000, 0x0f0f0f00);
 
        if (next->bios.rammap_11_08_01)
@@ -932,58 +932,24 @@ nve0_ram_calc_sddr3(struct nouveau_fb *pfb, u32 freq)
  ******************************************************************************/
 
 static int
-nve0_ram_calc_data(struct nouveau_fb *pfb, u32 freq,
+nve0_ram_calc_data(struct nouveau_fb *pfb, u32 khz,
                   struct nouveau_ram_data *data)
 {
-       struct nouveau_bios *bios = nouveau_bios(pfb);
        struct nve0_ram *ram = (void *)pfb->ram;
-       u8 strap, cnt, len;
-
-       /* lookup memory config data relevant to the target frequency */
-       ram->base.rammap.data = nvbios_rammapEp(bios, freq / 1000,
-                                              &ram->base.rammap.version,
-                                              &ram->base.rammap.size,
-                                              &cnt, &len, &data->bios);
-       if (!ram->base.rammap.data || ram->base.rammap.version != 0x11 ||
-            ram->base.rammap.size < 0x09) {
-               nv_error(pfb, "invalid/missing rammap entry\n");
-               return -EINVAL;
-       }
-
-       /* locate specific data set for the attached memory */
-       strap = nvbios_ramcfg_index(nv_subdev(pfb));
-       ram->base.ramcfg.data = nvbios_rammapSp(bios, ram->base.rammap.data,
-                                               ram->base.rammap.version,
-                                               ram->base.rammap.size,
-                                               cnt, len, strap,
-                                               &ram->base.ramcfg.version,
-                                               &ram->base.ramcfg.size,
-                                               &data->bios);
-       if (!ram->base.ramcfg.data || ram->base.ramcfg.version != 0x11 ||
-            ram->base.ramcfg.size < 0x08) {
-               nv_error(pfb, "invalid/missing ramcfg entry\n");
-               return -EINVAL;
-       }
-
-       /* lookup memory timings, if bios says they're present */
-       strap = nv_ro08(bios, ram->base.ramcfg.data + 0x00);
-       if (strap != 0xff) {
-               ram->base.timing.data =
-                       nvbios_timingEp(bios, strap, &ram->base.timing.version,
-                                      &ram->base.timing.size, &cnt, &len,
-                                      &data->bios);
-               if (!ram->base.timing.data ||
-                    ram->base.timing.version != 0x20 ||
-                    ram->base.timing.size < 0x33) {
-                       nv_error(pfb, "invalid/missing timing entry\n");
-                       return -EINVAL;
+       struct nouveau_ram_data *cfg;
+       u32 mhz = khz / 1000;
+
+       list_for_each_entry(cfg, &ram->cfg, head) {
+               if (mhz >= cfg->bios.rammap_min &&
+                   mhz <= cfg->bios.rammap_max) {
+                       *data = *cfg;
+                       data->freq = khz;
+                       return 0;
                }
-       } else {
-               ram->base.timing.data = 0;
        }
 
-       data->freq = freq;
-       return 0;
+       nv_error(ram, "ramcfg data for %dMHz not found\n", mhz);
+       return -EINVAL;
 }
 
 static int
@@ -1106,13 +1072,99 @@ nve0_ram_calc(struct nouveau_fb *pfb, u32 freq)
        return nve0_ram_calc_xits(pfb, ram->base.next);
 }
 
+static void
+nve0_ram_prog_0(struct nouveau_fb *pfb, u32 freq)
+{
+       struct nve0_ram *ram = (void *)pfb->ram;
+       struct nouveau_ram_data *cfg;
+       u32 mhz = freq / 1000;
+       u32 mask, data;
+
+       list_for_each_entry(cfg, &ram->cfg, head) {
+               if (mhz >= cfg->bios.rammap_min &&
+                   mhz <= cfg->bios.rammap_max)
+                       break;
+       }
+
+       if (&cfg->head == &ram->cfg)
+               return;
+
+       if (mask = 0, data = 0, ram->diff.rammap_11_0a_03fe) {
+               data |= cfg->bios.rammap_11_0a_03fe << 12;
+               mask |= 0x001ff000;
+       }
+       if (ram->diff.rammap_11_09_01ff) {
+               data |= cfg->bios.rammap_11_09_01ff;
+               mask |= 0x000001ff;
+       }
+       nv_mask(pfb, 0x10f468, mask, data);
+
+       if (mask = 0, data = 0, ram->diff.rammap_11_0a_0400) {
+               data |= cfg->bios.rammap_11_0a_0400;
+               mask |= 0x00000001;
+       }
+       nv_mask(pfb, 0x10f420, mask, data);
+
+       if (mask = 0, data = 0, ram->diff.rammap_11_0a_0800) {
+               data |= cfg->bios.rammap_11_0a_0800;
+               mask |= 0x00000001;
+       }
+       nv_mask(pfb, 0x10f430, mask, data);
+
+       if (mask = 0, data = 0, ram->diff.rammap_11_0b_01f0) {
+               data |= cfg->bios.rammap_11_0b_01f0;
+               mask |= 0x0000001f;
+       }
+       nv_mask(pfb, 0x10f400, mask, data);
+
+       if (mask = 0, data = 0, ram->diff.rammap_11_0b_0200) {
+               data |= cfg->bios.rammap_11_0b_0200 << 9;
+               mask |= 0x00000200;
+       }
+       nv_mask(pfb, 0x10f410, mask, data);
+
+       if (mask = 0, data = 0, ram->diff.rammap_11_0d) {
+               data |= cfg->bios.rammap_11_0d << 16;
+               mask |= 0x00ff0000;
+       }
+       if (ram->diff.rammap_11_0f) {
+               data |= cfg->bios.rammap_11_0f << 8;
+               mask |= 0x0000ff00;
+       }
+       nv_mask(pfb, 0x10f440, mask, data);
+
+       if (mask = 0, data = 0, ram->diff.rammap_11_0e) {
+               data |= cfg->bios.rammap_11_0e << 8;
+               mask |= 0x0000ff00;
+       }
+       if (ram->diff.rammap_11_0b_0800) {
+               data |= cfg->bios.rammap_11_0b_0800 << 7;
+               mask |= 0x00000080;
+       }
+       if (ram->diff.rammap_11_0b_0400) {
+               data |= cfg->bios.rammap_11_0b_0400 << 5;
+               mask |= 0x00000020;
+       }
+       nv_mask(pfb, 0x10f444, mask, data);
+}
+
 static int
 nve0_ram_prog(struct nouveau_fb *pfb)
 {
        struct nouveau_device *device = nv_device(pfb);
        struct nve0_ram *ram = (void *)pfb->ram;
        struct nve0_ramfuc *fuc = &ram->fuc;
-       ram_exec(fuc, nouveau_boolopt(device->cfgopt, "NvMemExec", true));
+       struct nouveau_ram_data *next = ram->base.next;
+
+       if (!nouveau_boolopt(device->cfgopt, "NvMemExec", true)) {
+               ram_exec(fuc, false);
+               return (ram->base.next == &ram->base.xition);
+       }
+
+       nve0_ram_prog_0(pfb, 1000);
+       ram_exec(fuc, true);
+       nve0_ram_prog_0(pfb, next->freq);
+
        return (ram->base.next == &ram->base.xition);
 }
 
@@ -1125,24 +1177,147 @@ nve0_ram_tidy(struct nouveau_fb *pfb)
        ram_exec(fuc, false);
 }
 
+struct nve0_ram_train {
+       u16 mask;
+       struct nvbios_M0209S remap;
+       struct nvbios_M0209S type00;
+       struct nvbios_M0209S type01;
+       struct nvbios_M0209S type04;
+       struct nvbios_M0209S type06;
+       struct nvbios_M0209S type07;
+       struct nvbios_M0209S type08;
+       struct nvbios_M0209S type09;
+};
+
+static int
+nve0_ram_train_type(struct nouveau_fb *pfb, int i, u8 ramcfg,
+                   struct nve0_ram_train *train)
+{
+       struct nouveau_bios *bios = nouveau_bios(pfb);
+       struct nvbios_M0205E M0205E;
+       struct nvbios_M0205S M0205S;
+       struct nvbios_M0209E M0209E;
+       struct nvbios_M0209S *remap = &train->remap;
+       struct nvbios_M0209S *value;
+       u8  ver, hdr, cnt, len;
+       u32 data;
+
+       /* determine type of data for this index */
+       if (!(data = nvbios_M0205Ep(bios, i, &ver, &hdr, &cnt, &len, &M0205E)))
+               return -ENOENT;
+
+       switch (M0205E.type) {
+       case 0x00: value = &train->type00; break;
+       case 0x01: value = &train->type01; break;
+       case 0x04: value = &train->type04; break;
+       case 0x06: value = &train->type06; break;
+       case 0x07: value = &train->type07; break;
+       case 0x08: value = &train->type08; break;
+       case 0x09: value = &train->type09; break;
+       default:
+               return 0;
+       }
+
+       /* training data index determined by ramcfg strap */
+       if (!(data = nvbios_M0205Sp(bios, i, ramcfg, &ver, &hdr, &M0205S)))
+               return -EINVAL;
+       i = M0205S.data;
+
+       /* training data format information */
+       if (!(data = nvbios_M0209Ep(bios, i, &ver, &hdr, &cnt, &len, &M0209E)))
+               return -EINVAL;
+
+       /* ... and the raw data */
+       if (!(data = nvbios_M0209Sp(bios, i, 0, &ver, &hdr, value)))
+               return -EINVAL;
+
+       if (M0209E.v02_07 == 2) {
+               /* of course! why wouldn't we have a pointer to another entry
+                * in the same table, and use the first one as an array of
+                * remap indices...
+                */
+               if (!(data = nvbios_M0209Sp(bios, M0209E.v03, 0, &ver, &hdr,
+                                           remap)))
+                       return -EINVAL;
+
+               for (i = 0; i < ARRAY_SIZE(value->data); i++)
+                       value->data[i] = remap->data[value->data[i]];
+       } else
+       if (M0209E.v02_07 != 1)
+               return -EINVAL;
+
+       train->mask |= 1 << M0205E.type;
+       return 0;
+}
+
+static int
+nve0_ram_train_init_0(struct nouveau_fb *pfb, struct nve0_ram_train *train)
+{
+       int i, j;
+
+       if ((train->mask & 0x03d3) != 0x03d3) {
+               nv_warn(pfb, "missing link training data\n");
+               return -EINVAL;
+       }
+
+       for (i = 0; i < 0x30; i++) {
+               for (j = 0; j < 8; j += 4) {
+                       nv_wr32(pfb, 0x10f968 + j, 0x00000000 | (i << 8));
+                       nv_wr32(pfb, 0x10f920 + j, 0x00000000 |
+                                                  train->type08.data[i] << 4 |
+                                                  train->type06.data[i]);
+                       nv_wr32(pfb, 0x10f918 + j, train->type00.data[i]);
+                       nv_wr32(pfb, 0x10f920 + j, 0x00000100 |
+                                                  train->type09.data[i] << 4 |
+                                                  train->type07.data[i]);
+                       nv_wr32(pfb, 0x10f918 + j, train->type01.data[i]);
+               }
+       }
+
+       for (j = 0; j < 8; j += 4) {
+               for (i = 0; i < 0x100; i++) {
+                       nv_wr32(pfb, 0x10f968 + j, i);
+                       nv_wr32(pfb, 0x10f900 + j, train->type04.data[i]);
+               }
+       }
+
+       return 0;
+}
+
+static int
+nve0_ram_train_init(struct nouveau_fb *pfb)
+{
+       u8 ramcfg = nvbios_ramcfg_index(nv_subdev(pfb));
+       struct nve0_ram_train *train;
+       int ret = -ENOMEM, i;
+
+       if ((train = kzalloc(sizeof(*train), GFP_KERNEL))) {
+               for (i = 0; i < 0x100; i++) {
+                       ret = nve0_ram_train_type(pfb, i, ramcfg, train);
+                       if (ret && ret != -ENOENT)
+                               break;
+               }
+       }
+
+       switch (pfb->ram->type) {
+       case NV_MEM_TYPE_GDDR5:
+               ret = nve0_ram_train_init_0(pfb, train);
+               break;
+       default:
+               ret = 0;
+               break;
+       }
+
+       kfree(train);
+       return ret;
+}
+
 int
 nve0_ram_init(struct nouveau_object *object)
 {
        struct nouveau_fb *pfb = (void *)object->parent;
        struct nve0_ram *ram   = (void *)object;
        struct nouveau_bios *bios = nouveau_bios(pfb);
-       static const u8  train0[] = {
-               0x00, 0xff, 0xff, 0x00, 0xff, 0x00,
-               0x00, 0xff, 0xff, 0x00, 0xff, 0x00,
-       };
-       static const u32 train1[] = {
-               0x00000000, 0xffffffff,
-               0x55555555, 0xaaaaaaaa,
-               0x33333333, 0xcccccccc,
-               0xf0f0f0f0, 0x0f0f0f0f,
-               0x00ff00ff, 0xff00ff00,
-               0x0000ffff, 0xffff0000,
-       };
        u8  ver, hdr, cnt, len, snr, ssz;
        u32 data, save;
        int ret, i;
@@ -1168,51 +1343,107 @@ nve0_ram_init(struct nouveau_object *object)
 
        cnt  = nv_ro08(bios, data + 0x14); /* guess at count */
        data = nv_ro32(bios, data + 0x10); /* guess u32... */
-       save = nv_rd32(pfb, 0x10f65c);
-       for (i = 0; i < cnt; i++) {
-               nv_mask(pfb, 0x10f65c, 0x000000f0, i << 4);
-               nvbios_exec(&(struct nvbios_init) {
-                               .subdev = nv_subdev(pfb),
-                               .bios = bios,
-                               .offset = nv_ro32(bios, data), /* guess u32 */
-                               .execute = 1,
-                           });
-               data += 4;
-       }
-       nv_wr32(pfb, 0x10f65c, save);
+       save = nv_rd32(pfb, 0x10f65c) & 0x000000f0;
+       for (i = 0; i < cnt; i++, data += 4) {
+               if (i != save >> 4) {
+                       nv_mask(pfb, 0x10f65c, 0x000000f0, i << 4);
+                       nvbios_exec(&(struct nvbios_init) {
+                                       .subdev = nv_subdev(pfb),
+                                       .bios = bios,
+                                       .offset = nv_ro32(bios, data),
+                                       .execute = 1,
+                                   });
+               }
+       }
+       nv_mask(pfb, 0x10f65c, 0x000000f0, save);
        nv_mask(pfb, 0x10f584, 0x11000000, 0x00000000);
+       nv_wr32(pfb, 0x10ecc0, 0xffffffff);
+       nv_mask(pfb, 0x10f160, 0x00000010, 0x00000010);
 
-       switch (ram->base.type) {
-       case NV_MEM_TYPE_GDDR5:
-               for (i = 0; i < 0x30; i++) {
-                       nv_wr32(pfb, 0x10f968, 0x00000000 | (i << 8));
-                       nv_wr32(pfb, 0x10f920, 0x00000000 | train0[i % 12]);
-                       nv_wr32(pfb, 0x10f918,              train1[i % 12]);
-                       nv_wr32(pfb, 0x10f920, 0x00000100 | train0[i % 12]);
-                       nv_wr32(pfb, 0x10f918,              train1[i % 12]);
-
-                       nv_wr32(pfb, 0x10f96c, 0x00000000 | (i << 8));
-                       nv_wr32(pfb, 0x10f924, 0x00000000 | train0[i % 12]);
-                       nv_wr32(pfb, 0x10f91c,              train1[i % 12]);
-                       nv_wr32(pfb, 0x10f924, 0x00000100 | train0[i % 12]);
-                       nv_wr32(pfb, 0x10f91c,              train1[i % 12]);
-               }
+       return nve0_ram_train_init(pfb);
+}
 
-               for (i = 0; i < 0x100; i++) {
-                       nv_wr32(pfb, 0x10f968, i);
-                       nv_wr32(pfb, 0x10f900, train1[2 + (i & 1)]);
-               }
+static int
+nve0_ram_ctor_data(struct nve0_ram *ram, u8 ramcfg, int i)
+{
+       struct nouveau_fb *pfb = (void *)nv_object(ram)->parent;
+       struct nouveau_bios *bios = nouveau_bios(pfb);
+       struct nouveau_ram_data *cfg;
+       struct nvbios_ramcfg *d = &ram->diff;
+       struct nvbios_ramcfg *p, *n;
+       u8  ver, hdr, cnt, len;
+       u32 data;
+       int ret;
 
-               for (i = 0; i < 0x100; i++) {
-                       nv_wr32(pfb, 0x10f96c, i);
-                       nv_wr32(pfb, 0x10f900, train1[2 + (i & 1)]);
-               }
-               break;
-       default:
-               break;
+       if (!(cfg = kmalloc(sizeof(*cfg), GFP_KERNEL)))
+               return -ENOMEM;
+       p = &list_last_entry(&ram->cfg, typeof(*cfg), head)->bios;
+       n = &cfg->bios;
+
+       /* memory config data for a range of target frequencies */
+       data = nvbios_rammapEp(bios, i, &ver, &hdr, &cnt, &len, &cfg->bios);
+       if (ret = -ENOENT, !data)
+               goto done;
+       if (ret = -ENOSYS, ver != 0x11 || hdr < 0x12)
+               goto done;
+
+       /* ... and a portion specific to the attached memory */
+       data = nvbios_rammapSp(bios, data, ver, hdr, cnt, len, ramcfg,
+                              &ver, &hdr, &cfg->bios);
+       if (ret = -EINVAL, !data)
+               goto done;
+       if (ret = -ENOSYS, ver != 0x11 || hdr < 0x0a)
+               goto done;
+
+       /* lookup memory timings, if bios says they're present */
+       if (cfg->bios.ramcfg_timing != 0xff) {
+               data = nvbios_timingEp(bios, cfg->bios.ramcfg_timing,
+                                      &ver, &hdr, &cnt, &len,
+                                      &cfg->bios);
+               if (ret = -EINVAL, !data)
+                       goto done;
+               if (ret = -ENOSYS, ver != 0x20 || hdr < 0x33)
+                       goto done;
        }
 
-       return 0;
+       list_add_tail(&cfg->head, &ram->cfg);
+       if (ret = 0, i == 0)
+               goto done;
+
+       d->rammap_11_0a_03fe |= p->rammap_11_0a_03fe != n->rammap_11_0a_03fe;
+       d->rammap_11_09_01ff |= p->rammap_11_09_01ff != n->rammap_11_09_01ff;
+       d->rammap_11_0a_0400 |= p->rammap_11_0a_0400 != n->rammap_11_0a_0400;
+       d->rammap_11_0a_0800 |= p->rammap_11_0a_0800 != n->rammap_11_0a_0800;
+       d->rammap_11_0b_01f0 |= p->rammap_11_0b_01f0 != n->rammap_11_0b_01f0;
+       d->rammap_11_0b_0200 |= p->rammap_11_0b_0200 != n->rammap_11_0b_0200;
+       d->rammap_11_0d |= p->rammap_11_0d != n->rammap_11_0d;
+       d->rammap_11_0f |= p->rammap_11_0f != n->rammap_11_0f;
+       d->rammap_11_0e |= p->rammap_11_0e != n->rammap_11_0e;
+       d->rammap_11_0b_0800 |= p->rammap_11_0b_0800 != n->rammap_11_0b_0800;
+       d->rammap_11_0b_0400 |= p->rammap_11_0b_0400 != n->rammap_11_0b_0400;
+       d->ramcfg_11_01_01 |= p->ramcfg_11_01_01 != n->ramcfg_11_01_01;
+       d->ramcfg_11_01_02 |= p->ramcfg_11_01_02 != n->ramcfg_11_01_02;
+       d->ramcfg_11_01_10 |= p->ramcfg_11_01_10 != n->ramcfg_11_01_10;
+       d->ramcfg_11_02_03 |= p->ramcfg_11_02_03 != n->ramcfg_11_02_03;
+       d->ramcfg_11_08_20 |= p->ramcfg_11_08_20 != n->ramcfg_11_08_20;
+       d->timing_20_30_07 |= p->timing_20_30_07 != n->timing_20_30_07;
+done:
+       if (ret)
+               kfree(cfg);
+       return ret;
+}
+
+static void
+nve0_ram_dtor(struct nouveau_object *object)
+{
+       struct nve0_ram *ram = (void *)object;
+       struct nouveau_ram_data *cfg, *tmp;
+
+       list_for_each_entry_safe(cfg, tmp, &ram->cfg, head) {
+               kfree(cfg);
+       }
+
+       nouveau_ram_destroy(&ram->base);
 }
 
 static int
@@ -1226,6 +1457,7 @@ nve0_ram_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
        struct dcb_gpio_func func;
        struct nve0_ram *ram;
        int ret, i;
+       u8  ramcfg = nvbios_ramcfg_index(nv_subdev(pfb));
        u32 tmp;
 
        ret = nvc0_ram_create(parent, engine, oclass, 0x022554, &ram);
@@ -1233,6 +1465,8 @@ nve0_ram_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
        if (ret)
                return ret;
 
+       INIT_LIST_HEAD(&ram->cfg);
+
        switch (ram->base.type) {
        case NV_MEM_TYPE_DDR3:
        case NV_MEM_TYPE_GDDR5:
@@ -1264,7 +1498,26 @@ nve0_ram_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
                }
        }
 
-       // parse bios data for both pll's
+       /* parse bios data for all rammap table entries up-front, and
+        * build information on whether certain fields differ between
+        * any of the entries.
+        *
+        * the binary driver appears to completely ignore some fields
+        * when all entries contain the same value.  at first, it was
+        * hoped that these were mere optimisations and the bios init
+        * tables had configured as per the values here, but there is
+        * evidence now to suggest that this isn't the case and we do
+        * need to treat this condition as a "don't touch" indicator.
+        */
+       for (i = 0; !ret; i++) {
+               ret = nve0_ram_ctor_data(ram, ramcfg, i);
+               if (ret && ret != -ENOENT) {
+                       nv_error(pfb, "failed to parse ramcfg data\n");
+                       return ret;
+               }
+       }
+
+       /* parse bios data for both pll's */
        ret = nvbios_pll_parse(bios, 0x0c, &ram->fuc.refpll);
        if (ret) {
                nv_error(pfb, "mclk refpll data not found\n");
@@ -1277,6 +1530,7 @@ nve0_ram_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
                return ret;
        }
 
+       /* lookup memory voltage gpios */
        ret = gpio->find(gpio, 0, 0x18, DCB_GPIO_UNUSED, &func);
        if (ret == 0) {
                ram->fuc.r_gpioMV = ramfuc_reg(0x00d610 + (func.line * 0x04));
@@ -1385,7 +1639,7 @@ nve0_ram_oclass = {
        .handle = 0,
        .ofuncs = &(struct nouveau_ofuncs) {
                .ctor = nve0_ram_ctor,
-               .dtor = _nouveau_ram_dtor,
+               .dtor = nve0_ram_dtor,
                .init = nve0_ram_init,
                .fini = _nouveau_ram_fini,
        }
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/sddr2.c b/drivers/gpu/drm/nouveau/core/subdev/fb/sddr2.c
new file mode 100644 (file)
index 0000000..bb1eb8f
--- /dev/null
@@ -0,0 +1,94 @@
+/*
+ * Copyright 2014 Roy Spliet
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Roy Spliet <rspliet@eclipso.eu>
+ *          Ben Skeggs
+ */
+
+#include "priv.h"
+
+struct ramxlat {
+       int id;
+       u8 enc;
+};
+
+static inline int
+ramxlat(const struct ramxlat *xlat, int id)
+{
+       while (xlat->id >= 0) {
+               if (xlat->id == id)
+                       return xlat->enc;
+               xlat++;
+       }
+       return -EINVAL;
+}
+
+static const struct ramxlat
+ramddr2_cl[] = {
+       { 2, 2 }, { 3, 3 }, { 4, 4 }, { 5, 5 }, { 6, 6 },
+       /* The following are available in some, but not all DDR2 docs */
+       { 7, 7 },
+       { -1 }
+};
+
+static const struct ramxlat
+ramddr2_wr[] = {
+       { 2, 1 }, { 3, 2 }, { 4, 3 }, { 5, 4 }, { 6, 5 },
+       /* The following are available in some, but not all DDR2 docs */
+       { 7, 6 },
+       { -1 }
+};
+
+int
+nouveau_sddr2_calc(struct nouveau_ram *ram)
+{
+       int CL, WR, DLL = 0, ODT = 0;
+
+       switch (ram->next->bios.timing_ver) {
+       case 0x10:
+               CL  = ram->next->bios.timing_10_CL;
+               WR  = ram->next->bios.timing_10_WR;
+               DLL = !ram->next->bios.ramcfg_10_02_40;
+               ODT = ram->next->bios.timing_10_ODT & 3;
+               break;
+       case 0x20:
+               CL  = (ram->next->bios.timing[1] & 0x0000001f);
+               WR  = (ram->next->bios.timing[2] & 0x007f0000) >> 16;
+               break;
+       default:
+               return -ENOSYS;
+       }
+
+       CL  = ramxlat(ramddr2_cl, CL);
+       WR  = ramxlat(ramddr2_wr, WR);
+       if (CL < 0 || WR < 0)
+               return -EINVAL;
+
+       ram->mr[0] &= ~0xf70;
+       ram->mr[0] |= (WR & 0x07) << 9;
+       ram->mr[0] |= (CL & 0x07) << 4;
+
+       ram->mr[1] &= ~0x045;
+       ram->mr[1] |= (ODT & 0x1) << 2;
+       ram->mr[1] |= (ODT & 0x2) << 5;
+       ram->mr[1] |= !DLL;
+       return 0;
+}
index ebd4cd9c35d905eefc1adf51295fa0dfbafa5f1f..83949b11833af46ca1537904691ca7d13112133a 100644 (file)
@@ -20,9 +20,9 @@
  * OTHER DEALINGS IN THE SOFTWARE.
  *
  * Authors: Ben Skeggs <bskeggs@redhat.com>
+ *         Roy Spliet <rspliet@eclipso.eu>
  */
 
-#include <subdev/bios.h>
 #include "priv.h"
 
 struct ramxlat {
@@ -69,31 +69,52 @@ ramddr3_cwl[] = {
 int
 nouveau_sddr3_calc(struct nouveau_ram *ram)
 {
-       struct nouveau_bios *bios = nouveau_bios(ram);
-       int WL, CL, WR;
+       int CWL, CL, WR, DLL = 0, ODT = 0;
 
-       switch (!!ram->timing.data * ram->timing.version) {
+       switch (ram->next->bios.timing_ver) {
+       case 0x10:
+               if (ram->next->bios.timing_hdr < 0x17) {
+                       /* XXX: NV50: Get CWL from the timing register */
+                       return -ENOSYS;
+               }
+               CWL = ram->next->bios.timing_10_CWL;
+               CL  = ram->next->bios.timing_10_CL;
+               WR  = ram->next->bios.timing_10_WR;
+               DLL = !ram->next->bios.ramcfg_10_02_40;
+               ODT = ram->next->bios.timing_10_ODT;
+               break;
        case 0x20:
-               WL = (nv_ro16(bios, ram->timing.data + 0x04) & 0x0f80) >> 7;
-               CL =  nv_ro08(bios, ram->timing.data + 0x04) & 0x1f;
-               WR =  nv_ro08(bios, ram->timing.data + 0x0a) & 0x7f;
+               CWL = (ram->next->bios.timing[1] & 0x00000f80) >> 7;
+               CL  = (ram->next->bios.timing[1] & 0x0000001f) >> 0;
+               WR  = (ram->next->bios.timing[2] & 0x007f0000) >> 16;
+               /* XXX: Get these values from the VBIOS instead */
+               DLL = !(ram->mr[1] & 0x1);
+               ODT =   (ram->mr[1] & 0x004) >> 2 |
+                       (ram->mr[1] & 0x040) >> 5 |
+                       (ram->mr[1] & 0x200) >> 7;
                break;
        default:
                return -ENOSYS;
        }
 
-       WL = ramxlat(ramddr3_cwl, WL);
-       CL = ramxlat(ramddr3_cl, CL);
-       WR = ramxlat(ramddr3_wr, WR);
-       if (WL < 0 || CL < 0 || WR < 0)
+       CWL = ramxlat(ramddr3_cwl, CWL);
+       CL  = ramxlat(ramddr3_cl, CL);
+       WR  = ramxlat(ramddr3_wr, WR);
+       if (CL < 0 || CWL < 0 || WR < 0)
                return -EINVAL;
 
-       ram->mr[0] &= ~0xe74;
+       ram->mr[0] &= ~0xf74;
        ram->mr[0] |= (WR & 0x07) << 9;
        ram->mr[0] |= (CL & 0x0e) << 3;
        ram->mr[0] |= (CL & 0x01) << 2;
 
+       ram->mr[1] &= ~0x245;
+       ram->mr[1] |= (ODT & 0x1) << 2;
+       ram->mr[1] |= (ODT & 0x2) << 5;
+       ram->mr[1] |= (ODT & 0x4) << 7;
+       ram->mr[1] |= !DLL;
+
        ram->mr[2] &= ~0x038;
-       ram->mr[2] |= (WL & 0x07) << 3;
+       ram->mr[2] |= (CWL & 0x07) << 3;
        return 0;
 }
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fuse/base.c b/drivers/gpu/drm/nouveau/core/subdev/fuse/base.c
new file mode 100644 (file)
index 0000000..9e8e921
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2014 Martin Peres
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Martin Peres
+ */
+
+#include <subdev/fuse.h>
+
+int
+_nouveau_fuse_init(struct nouveau_object *object)
+{
+       struct nouveau_fuse *fuse = (void *)object;
+       return nouveau_subdev_init(&fuse->base);
+}
+
+void
+_nouveau_fuse_dtor(struct nouveau_object *object)
+{
+       struct nouveau_fuse *fuse = (void *)object;
+       nouveau_subdev_destroy(&fuse->base);
+}
+
+int
+nouveau_fuse_create_(struct nouveau_object *parent,
+                    struct nouveau_object *engine,
+                    struct nouveau_oclass *oclass, int length, void **pobject)
+{
+       struct nouveau_fuse *fuse;
+       int ret;
+
+       ret = nouveau_subdev_create_(parent, engine, oclass, 0, "FUSE",
+                                    "fuse", length, pobject);
+       fuse = *pobject;
+
+       return ret;
+}
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fuse/g80.c b/drivers/gpu/drm/nouveau/core/subdev/fuse/g80.c
new file mode 100644 (file)
index 0000000..a374ade
--- /dev/null
@@ -0,0 +1,81 @@
+/*
+ * Copyright 2014 Martin Peres
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Martin Peres
+ */
+
+#include "priv.h"
+
+struct g80_fuse_priv {
+       struct nouveau_fuse base;
+
+       spinlock_t fuse_enable_lock;
+};
+
+static u32
+g80_fuse_rd32(struct nouveau_object *object, u64 addr)
+{
+       struct g80_fuse_priv *priv = (void *)object;
+       unsigned long flags;
+       u32 fuse_enable, val;
+
+       spin_lock_irqsave(&priv->fuse_enable_lock, flags);
+
+       /* racy if another part of nouveau start writing to this reg */
+       fuse_enable = nv_mask(priv, 0x1084, 0x800, 0x800);
+       val = nv_rd32(priv, 0x21000 + addr);
+       nv_wr32(priv, 0x1084, fuse_enable);
+
+       spin_unlock_irqrestore(&priv->fuse_enable_lock, flags);
+
+       return val;
+}
+
+
+static int
+g80_fuse_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
+              struct nouveau_oclass *oclass, void *data, u32 size,
+              struct nouveau_object **pobject)
+{
+       struct g80_fuse_priv *priv;
+       int ret;
+
+       ret = nouveau_fuse_create(parent, engine, oclass, &priv);
+       *pobject = nv_object(priv);
+       if (ret)
+               return ret;
+
+       spin_lock_init(&priv->fuse_enable_lock);
+
+       return 0;
+}
+
+struct nouveau_oclass
+g80_fuse_oclass = {
+       .handle = NV_SUBDEV(FUSE, 0x50),
+       .ofuncs = &(struct nouveau_ofuncs) {
+               .ctor = g80_fuse_ctor,
+               .dtor = _nouveau_fuse_dtor,
+               .init = _nouveau_fuse_init,
+               .fini = _nouveau_fuse_fini,
+               .rd32 = g80_fuse_rd32,
+       },
+};
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fuse/gf100.c b/drivers/gpu/drm/nouveau/core/subdev/fuse/gf100.c
new file mode 100644 (file)
index 0000000..5ed03f5
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+ * Copyright 2014 Martin Peres
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Martin Peres
+ */
+
+#include "priv.h"
+
+struct gf100_fuse_priv {
+       struct nouveau_fuse base;
+
+       spinlock_t fuse_enable_lock;
+};
+
+static u32
+gf100_fuse_rd32(struct nouveau_object *object, u64 addr)
+{
+       struct gf100_fuse_priv *priv = (void *)object;
+       unsigned long flags;
+       u32 fuse_enable, unk, val;
+
+       spin_lock_irqsave(&priv->fuse_enable_lock, flags);
+
+       /* racy if another part of nouveau start writing to these regs */
+       fuse_enable = nv_mask(priv, 0x22400, 0x800, 0x800);
+       unk = nv_mask(priv, 0x21000, 0x1, 0x1);
+       val = nv_rd32(priv, 0x21100 + addr);
+       nv_wr32(priv, 0x21000, unk);
+       nv_wr32(priv, 0x22400, fuse_enable);
+
+       spin_unlock_irqrestore(&priv->fuse_enable_lock, flags);
+
+       return val;
+}
+
+
+static int
+gf100_fuse_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
+              struct nouveau_oclass *oclass, void *data, u32 size,
+              struct nouveau_object **pobject)
+{
+       struct gf100_fuse_priv *priv;
+       int ret;
+
+       ret = nouveau_fuse_create(parent, engine, oclass, &priv);
+       *pobject = nv_object(priv);
+       if (ret)
+               return ret;
+
+       spin_lock_init(&priv->fuse_enable_lock);
+
+       return 0;
+}
+
+struct nouveau_oclass
+gf100_fuse_oclass = {
+       .handle = NV_SUBDEV(FUSE, 0xC0),
+       .ofuncs = &(struct nouveau_ofuncs) {
+               .ctor = gf100_fuse_ctor,
+               .dtor = _nouveau_fuse_dtor,
+               .init = _nouveau_fuse_init,
+               .fini = _nouveau_fuse_fini,
+               .rd32 = gf100_fuse_rd32,
+       },
+};
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fuse/gm107.c b/drivers/gpu/drm/nouveau/core/subdev/fuse/gm107.c
new file mode 100644 (file)
index 0000000..4f1a636
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2014 Martin Peres
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Martin Peres
+ */
+
+#include "priv.h"
+
+struct gm107_fuse_priv {
+       struct nouveau_fuse base;
+};
+
+static u32
+gm107_fuse_rd32(struct nouveau_object *object, u64 addr)
+{
+       struct gf100_fuse_priv *priv = (void *)object;
+
+       return nv_rd32(priv, 0x21100 + addr);
+}
+
+
+static int
+gm107_fuse_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
+              struct nouveau_oclass *oclass, void *data, u32 size,
+              struct nouveau_object **pobject)
+{
+       struct gm107_fuse_priv *priv;
+       int ret;
+
+       ret = nouveau_fuse_create(parent, engine, oclass, &priv);
+       *pobject = nv_object(priv);
+       if (ret)
+               return ret;
+
+       return 0;
+}
+
+struct nouveau_oclass
+gm107_fuse_oclass = {
+       .handle = NV_SUBDEV(FUSE, 0x117),
+       .ofuncs = &(struct nouveau_ofuncs) {
+               .ctor = gm107_fuse_ctor,
+               .dtor = _nouveau_fuse_dtor,
+               .init = _nouveau_fuse_init,
+               .fini = _nouveau_fuse_fini,
+               .rd32 = gm107_fuse_rd32,
+       },
+};
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fuse/priv.h b/drivers/gpu/drm/nouveau/core/subdev/fuse/priv.h
new file mode 100644 (file)
index 0000000..d208541
--- /dev/null
@@ -0,0 +1,9 @@
+#ifndef __NVKM_FUSE_PRIV_H__
+#define __NVKM_FUSE_PRIV_H__
+
+#include <subdev/fuse.h>
+
+int _nouveau_fuse_init(struct nouveau_object *object);
+void _nouveau_fuse_dtor(struct nouveau_object *object);
+
+#endif
index b1e3ed7c8beb51a555b78be072a79faf39e369c7..7ad99b763f4c463334f7642a910e9f79fe8a9777 100644 (file)
@@ -122,7 +122,8 @@ nouveau_gpio_intr_init(struct nvkm_event *event, int type, int index)
 }
 
 static int
-nouveau_gpio_intr_ctor(void *data, u32 size, struct nvkm_notify *notify)
+nouveau_gpio_intr_ctor(struct nouveau_object *object, void *data, u32 size,
+                      struct nvkm_notify *notify)
 {
        struct nvkm_gpio_ntfy_req *req = data;
        if (!WARN_ON(size != sizeof(*req))) {
diff --git a/drivers/gpu/drm/nouveau/core/subdev/gpio/nv92.c b/drivers/gpu/drm/nouveau/core/subdev/gpio/nv92.c
deleted file mode 100644 (file)
index 252083d..0000000
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * Copyright 2012 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include "priv.h"
-
-void
-nv92_gpio_intr_stat(struct nouveau_gpio *gpio, u32 *hi, u32 *lo)
-{
-       u32 intr0 = nv_rd32(gpio, 0x00e054);
-       u32 intr1 = nv_rd32(gpio, 0x00e074);
-       u32 stat0 = nv_rd32(gpio, 0x00e050) & intr0;
-       u32 stat1 = nv_rd32(gpio, 0x00e070) & intr1;
-       *lo = (stat1 & 0xffff0000) | (stat0 >> 16);
-       *hi = (stat1 << 16) | (stat0 & 0x0000ffff);
-       nv_wr32(gpio, 0x00e054, intr0);
-       nv_wr32(gpio, 0x00e074, intr1);
-}
-
-void
-nv92_gpio_intr_mask(struct nouveau_gpio *gpio, u32 type, u32 mask, u32 data)
-{
-       u32 inte0 = nv_rd32(gpio, 0x00e050);
-       u32 inte1 = nv_rd32(gpio, 0x00e070);
-       if (type & NVKM_GPIO_LO)
-               inte0 = (inte0 & ~(mask << 16)) | (data << 16);
-       if (type & NVKM_GPIO_HI)
-               inte0 = (inte0 & ~(mask & 0xffff)) | (data & 0xffff);
-       mask >>= 16;
-       data >>= 16;
-       if (type & NVKM_GPIO_LO)
-               inte1 = (inte1 & ~(mask << 16)) | (data << 16);
-       if (type & NVKM_GPIO_HI)
-               inte1 = (inte1 & ~mask) | data;
-       nv_wr32(gpio, 0x00e050, inte0);
-       nv_wr32(gpio, 0x00e070, inte1);
-}
-
-struct nouveau_oclass *
-nv92_gpio_oclass = &(struct nouveau_gpio_impl) {
-       .base.handle = NV_SUBDEV(GPIO, 0x92),
-       .base.ofuncs = &(struct nouveau_ofuncs) {
-               .ctor = _nouveau_gpio_ctor,
-               .dtor = _nouveau_gpio_dtor,
-               .init = _nouveau_gpio_init,
-               .fini = _nouveau_gpio_fini,
-       },
-       .lines = 32,
-       .intr_stat = nv92_gpio_intr_stat,
-       .intr_mask = nv92_gpio_intr_mask,
-       .drive = nv50_gpio_drive,
-       .sense = nv50_gpio_sense,
-       .reset = nv50_gpio_reset,
-}.base;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/gpio/nv94.c b/drivers/gpu/drm/nouveau/core/subdev/gpio/nv94.c
new file mode 100644 (file)
index 0000000..cae404c
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+
+#include "priv.h"
+
+void
+nv94_gpio_intr_stat(struct nouveau_gpio *gpio, u32 *hi, u32 *lo)
+{
+       u32 intr0 = nv_rd32(gpio, 0x00e054);
+       u32 intr1 = nv_rd32(gpio, 0x00e074);
+       u32 stat0 = nv_rd32(gpio, 0x00e050) & intr0;
+       u32 stat1 = nv_rd32(gpio, 0x00e070) & intr1;
+       *lo = (stat1 & 0xffff0000) | (stat0 >> 16);
+       *hi = (stat1 << 16) | (stat0 & 0x0000ffff);
+       nv_wr32(gpio, 0x00e054, intr0);
+       nv_wr32(gpio, 0x00e074, intr1);
+}
+
+void
+nv94_gpio_intr_mask(struct nouveau_gpio *gpio, u32 type, u32 mask, u32 data)
+{
+       u32 inte0 = nv_rd32(gpio, 0x00e050);
+       u32 inte1 = nv_rd32(gpio, 0x00e070);
+       if (type & NVKM_GPIO_LO)
+               inte0 = (inte0 & ~(mask << 16)) | (data << 16);
+       if (type & NVKM_GPIO_HI)
+               inte0 = (inte0 & ~(mask & 0xffff)) | (data & 0xffff);
+       mask >>= 16;
+       data >>= 16;
+       if (type & NVKM_GPIO_LO)
+               inte1 = (inte1 & ~(mask << 16)) | (data << 16);
+       if (type & NVKM_GPIO_HI)
+               inte1 = (inte1 & ~mask) | data;
+       nv_wr32(gpio, 0x00e050, inte0);
+       nv_wr32(gpio, 0x00e070, inte1);
+}
+
+struct nouveau_oclass *
+nv94_gpio_oclass = &(struct nouveau_gpio_impl) {
+       .base.handle = NV_SUBDEV(GPIO, 0x94),
+       .base.ofuncs = &(struct nouveau_ofuncs) {
+               .ctor = _nouveau_gpio_ctor,
+               .dtor = _nouveau_gpio_dtor,
+               .init = _nouveau_gpio_init,
+               .fini = _nouveau_gpio_fini,
+       },
+       .lines = 32,
+       .intr_stat = nv94_gpio_intr_stat,
+       .intr_mask = nv94_gpio_intr_mask,
+       .drive = nv50_gpio_drive,
+       .sense = nv50_gpio_sense,
+       .reset = nv50_gpio_reset,
+}.base;
index a4682b0956ad3ef325451eb083393c4a741e8cee..480d6d2af770c98dde41c97bce82b5fd124cf2c2 100644 (file)
@@ -77,8 +77,8 @@ nvd0_gpio_oclass = &(struct nouveau_gpio_impl) {
                .fini = _nouveau_gpio_fini,
        },
        .lines = 32,
-       .intr_stat = nv92_gpio_intr_stat,
-       .intr_mask = nv92_gpio_intr_mask,
+       .intr_stat = nv94_gpio_intr_stat,
+       .intr_mask = nv94_gpio_intr_mask,
        .drive = nvd0_gpio_drive,
        .sense = nvd0_gpio_sense,
        .reset = nvd0_gpio_reset,
index e1724dfc86ae2edfe9801e59acd749203f304977..bff98b86e2b53b5cce1f7439cd7f0a48be667032 100644 (file)
@@ -56,8 +56,8 @@ void nv50_gpio_reset(struct nouveau_gpio *, u8);
 int  nv50_gpio_drive(struct nouveau_gpio *, int, int, int);
 int  nv50_gpio_sense(struct nouveau_gpio *, int);
 
-void nv92_gpio_intr_stat(struct nouveau_gpio *, u32 *, u32 *);
-void nv92_gpio_intr_mask(struct nouveau_gpio *, u32, u32, u32);
+void nv94_gpio_intr_stat(struct nouveau_gpio *, u32 *, u32 *);
+void nv94_gpio_intr_mask(struct nouveau_gpio *, u32, u32, u32);
 
 void nvd0_gpio_reset(struct nouveau_gpio *, u8);
 int  nvd0_gpio_drive(struct nouveau_gpio *, int, int, int);
index a652cafde3d6d01ddc4d5173927a3c6a5d6c78d2..2b1bf545e488df2b6b6ff99253e2cb38895de48f 100644 (file)
@@ -23,6 +23,7 @@
  */
 
 #include <core/option.h>
+#include <core/object.h>
 #include <core/event.h>
 
 #include <subdev/bios.h>
@@ -346,7 +347,8 @@ nouveau_i2c_intr_init(struct nvkm_event *event, int type, int index)
 }
 
 static int
-nouveau_i2c_intr_ctor(void *data, u32 size, struct nvkm_notify *notify)
+nouveau_i2c_intr_ctor(struct nouveau_object *object, void *data, u32 size,
+                     struct nvkm_notify *notify)
 {
        struct nvkm_i2c_ntfy_req *req = data;
        if (!WARN_ON(size != sizeof(*req))) {
index 7b64befee48fbb5b30b306c980ae53bd077c3368..e8b1401c59c0ef4c76fa9407eab862a8b8360dc3 100644 (file)
@@ -69,7 +69,7 @@ nv04_instobj_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
        if (ret)
                return ret;
 
-       ret = nouveau_mm_head(&priv->heap, 1, args->size, args->size,
+       ret = nouveau_mm_head(&priv->heap, 0, 1, args->size, args->size,
                              args->align, &node->mem);
        if (ret)
                return ret;
index 32ed442c59130548f0deeb88fb735048a7e45a9a..7fa331516f84f22bf27b9795e8e181b1b899335a 100644 (file)
@@ -31,7 +31,7 @@ nvkm_ltc_tags_alloc(struct nouveau_ltc *ltc, u32 n,
        struct nvkm_ltc_priv *priv = (void *)ltc;
        int ret;
 
-       ret = nouveau_mm_head(&priv->tags, 1, n, n, 1, pnode);
+       ret = nouveau_mm_head(&priv->tags, 0, 1, n, n, 1, pnode);
        if (ret)
                *pnode = NULL;
 
index d5d65285efe59188072f90fc020939d14c3f1dec..2db0977284f80dfb484f34969809491daf9cbbf7 100644 (file)
@@ -62,16 +62,38 @@ gf100_ltc_zbc_clear_depth(struct nvkm_ltc_priv *priv, int i, const u32 depth)
        nv_wr32(priv, 0x17ea58, depth);
 }
 
+static const struct nouveau_bitfield
+gf100_ltc_lts_intr_name[] = {
+       { 0x00000001, "IDLE_ERROR_IQ" },
+       { 0x00000002, "IDLE_ERROR_CBC" },
+       { 0x00000004, "IDLE_ERROR_TSTG" },
+       { 0x00000008, "IDLE_ERROR_DSTG" },
+       { 0x00000010, "EVICTED_CB" },
+       { 0x00000020, "ILLEGAL_COMPSTAT" },
+       { 0x00000040, "BLOCKLINEAR_CB" },
+       { 0x00000100, "ECC_SEC_ERROR" },
+       { 0x00000200, "ECC_DED_ERROR" },
+       { 0x00000400, "DEBUG" },
+       { 0x00000800, "ATOMIC_TO_Z" },
+       { 0x00001000, "ILLEGAL_ATOMIC" },
+       { 0x00002000, "BLKACTIVITY_ERR" },
+       {}
+};
+
 static void
-gf100_ltc_lts_isr(struct nvkm_ltc_priv *priv, int ltc, int lts)
+gf100_ltc_lts_intr(struct nvkm_ltc_priv *priv, int ltc, int lts)
 {
        u32 base = 0x141000 + (ltc * 0x2000) + (lts * 0x400);
-       u32 stat = nv_rd32(priv, base + 0x020);
+       u32 intr = nv_rd32(priv, base + 0x020);
+       u32 stat = intr & 0x0000ffff;
 
        if (stat) {
-               nv_info(priv, "LTC%d_LTS%d: 0x%08x\n", ltc, lts, stat);
-               nv_wr32(priv, base + 0x020, stat);
+               nv_info(priv, "LTC%d_LTS%d:", ltc, lts);
+               nouveau_bitfield_print(gf100_ltc_lts_intr_name, stat);
+               pr_cont("\n");
        }
+
+       nv_wr32(priv, base + 0x020, intr);
 }
 
 void
@@ -84,14 +106,9 @@ gf100_ltc_intr(struct nouveau_subdev *subdev)
        while (mask) {
                u32 lts, ltc = __ffs(mask);
                for (lts = 0; lts < priv->lts_nr; lts++)
-                       gf100_ltc_lts_isr(priv, ltc, lts);
+                       gf100_ltc_lts_intr(priv, ltc, lts);
                mask &= ~(1 << ltc);
        }
-
-       /* we do something horribly wrong and upset PMFB a lot, so mask off
-        * interrupts from it after the first one until it's fixed
-        */
-       nv_mask(priv, 0x000640, 0x02000000, 0x00000000);
 }
 
 static int
@@ -153,7 +170,7 @@ gf100_ltc_init_tag_ram(struct nouveau_fb *pfb, struct nvkm_ltc_priv *priv)
        tag_size += tag_align;
        tag_size  = (tag_size + 0xfff) >> 12; /* round up */
 
-       ret = nouveau_mm_tail(&pfb->vram, 1, tag_size, tag_size, 1,
+       ret = nouveau_mm_tail(&pfb->vram, 1, 1, tag_size, tag_size, 1,
                              &priv->tag_ram);
        if (ret) {
                priv->num_tags = 0;
index a4de64289762fc9cfe82ab40e424b4fba67fe0f0..89fc4238f50c4afea16fe2d5cb3501f5eb954216 100644 (file)
@@ -87,11 +87,6 @@ gm107_ltc_intr(struct nouveau_subdev *subdev)
                        gm107_ltc_lts_isr(priv, ltc, lts);
                mask &= ~(1 << ltc);
        }
-
-       /* we do something horribly wrong and upset PMFB a lot, so mask off
-        * interrupts from it after the first one until it's fixed
-        */
-       nv_mask(priv, 0x000640, 0x02000000, 0x00000000);
 }
 
 static int
index 594924f391261b9db9e25eba5940a908252e97e4..41f179d93da697e4ca6ea4fd41fef7077779dd25 100644 (file)
@@ -4,6 +4,8 @@
 #include <subdev/ltc.h>
 #include <subdev/fb.h>
 
+#include <core/enum.h>
+
 struct nvkm_ltc_priv {
        struct nouveau_ltc base;
        u32 ltc_nr;
index 69f1f34f6931d56f53cad1c16faf4d5caef7a935..0ab55f27ec450663ac47adb53e449f1e62215a67 100644 (file)
@@ -203,6 +203,8 @@ _nouveau_pwr_init(struct nouveau_object *object)
        nv_wait(ppwr, 0x10a04c, 0xffffffff, 0x00000000);
        nv_mask(ppwr, 0x000200, 0x00002000, 0x00000000);
        nv_mask(ppwr, 0x000200, 0x00002000, 0x00002000);
+       nv_rd32(ppwr, 0x000200);
+       nv_wait(ppwr, 0x10a10c, 0x00000006, 0x00000000);
 
        /* upload data segment */
        nv_wr32(ppwr, 0x10a1c0, 0x01000000);
diff --git a/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/arith.fuc b/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/arith.fuc
new file mode 100644 (file)
index 0000000..214a6d9
--- /dev/null
@@ -0,0 +1,94 @@
+/*
+ * Copyright 2014 Martin Peres <martin.peres@free.fr>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the folloing conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Martin Peres
+ */
+
+/******************************************************************************
+ * arith data segment
+ *****************************************************************************/
+#ifdef INCLUDE_PROC
+#endif
+
+#ifdef INCLUDE_DATA
+#endif
+
+/******************************************************************************
+ * arith code segment
+ *****************************************************************************/
+#ifdef INCLUDE_CODE
+
+// does a 32x32 -> 64 multiplication
+//
+// A * B = A_lo * B_lo
+//        + ( A_hi * B_lo ) << 16
+//        + ( A_lo * B_hi ) << 16
+//        + ( A_hi * B_hi ) << 32
+//
+// $r15 - current
+// $r14 - A
+// $r13 - B
+// $r12 - mul_lo (return)
+// $r11 - mul_hi (return)
+// $r0  - zero
+mulu32_32_64:
+       push $r1 // A_hi
+       push $r2 // B_hi
+       push $r3 // tmp0
+       push $r4 // tmp1
+
+       shr b32 $r1 $r14 16
+       shr b32 $r2 $r13 16
+
+       clear b32 $r12
+       clear b32 $r11
+
+       // A_lo * B_lo
+       mulu $r12 $r14 $r13
+
+       // ( A_hi * B_lo ) << 16
+       mulu $r3 $r1 $r13 // tmp0 = A_hi * B_lo
+       mov b32 $r4 $r3
+       and $r3 0xffff // tmp0 = tmp0_lo
+       shl b32 $r3 16
+       shr b32 $r4 16 // tmp1 = tmp0_hi
+       add b32 $r12 $r3
+       adc b32 $r11 $r4
+
+       // ( A_lo * B_hi ) << 16
+       mulu $r3 $r14 $r2 // tmp0 = A_lo * B_hi
+       mov b32 $r4 $r3
+       and $r3 0xffff // tmp0 = tmp0_lo
+       shl b32 $r3 16
+       shr b32 $r4 16 // tmp1 = tmp0_hi
+       add b32 $r12 $r3
+       adc b32 $r11 $r4
+
+       // ( A_hi * B_hi ) << 32
+       mulu $r3 $r1 $r2 // tmp0 = A_hi * B_hi
+       add b32 $r11 $r3
+
+       pop $r4
+       pop $r3
+       pop $r2
+       pop $r1
+       ret
+#endif
index 8f29badd785f16f9cd37cff7adf19d03f1aafc44..5cf5be63cbeff3ea4db031c606979d32fe413c89 100644 (file)
@@ -98,12 +98,16 @@ wr32:
 // $r14 - ns
 // $r0  - zero
 nsec:
+       push $r9
+       push $r8
        nv_iord($r8, NV_PPWR_TIMER_LOW)
        nsec_loop:
                nv_iord($r9, NV_PPWR_TIMER_LOW)
                sub b32 $r9 $r8
                cmp b32 $r9 $r14
                bra l #nsec_loop
+       pop $r8
+       pop $r9
        ret
 
 // busy-wait for a period of time
@@ -115,6 +119,8 @@ nsec:
 // $r11 - timeout (ns)
 // $r0  - zero
 wait:
+       push $r9
+       push $r8
        nv_iord($r8, NV_PPWR_TIMER_LOW)
        wait_loop:
                nv_rd32($r10, $r14)
@@ -126,6 +132,8 @@ wait:
                cmp b32 $r9 $r11
                bra l #wait_loop
        wait_done:
+       pop $r8
+       pop $r9
        ret
 
 // $r15 - current (kern)
@@ -242,12 +250,89 @@ intr:
        bclr $flags $p0
        iret
 
-// request the current process be sent a message after a timeout expires
+// calculate the number of ticks in the specified nanoseconds delay
+//
+// $r15 - current
+// $r14 - ns
+// $r14 - ticks (return)
+// $r0  - zero
+ticks_from_ns:
+       push $r12
+       push $r11
+
+       /* try not losing precision (multiply then divide) */
+       imm32($r13, HW_TICKS_PER_US)
+       call #mulu32_32_64
+
+       /* use an immeditate, it's ok because HW_TICKS_PER_US < 16 bits */
+       div $r12 $r12 1000
+
+       /* check if there wasn't any overflow */
+       cmpu b32 $r11 0
+       bra e #ticks_from_ns_quit
+
+       /* let's divide then multiply, too bad for the precision! */
+       div $r14 $r14 1000
+       imm32($r13, HW_TICKS_PER_US)
+       call #mulu32_32_64
+
+       /* this cannot overflow as long as HW_TICKS_PER_US < 1000 */
+
+ticks_from_ns_quit:
+       mov b32 $r14 $r12
+       pop $r11
+       pop $r12
+       ret
+
+// calculate the number of ticks in the specified microsecond delay
+//
+// $r15 - current
+// $r14 - us
+// $r14 - ticks (return)
+// $r0  - zero
+ticks_from_us:
+       push $r12
+       push $r11
+
+       /* simply multiply $us by HW_TICKS_PER_US */
+       imm32($r13, HW_TICKS_PER_US)
+       call #mulu32_32_64
+       mov b32 $r14 $r12
+
+       /* check if there wasn't any overflow */
+       cmpu b32 $r11 0
+       bra e #ticks_from_us_quit
+
+       /* Overflow! */
+       clear b32 $r14
+
+ticks_from_us_quit:
+       pop $r11
+       pop $r12
+       ret
+
+// calculate the number of ticks in the specified microsecond delay
 //
 // $r15 - current
 // $r14 - ticks
+// $r14 - us (return)
+// $r0  - zero
+ticks_to_us:
+       /* simply divide $ticks by HW_TICKS_PER_US */
+       imm32($r13, HW_TICKS_PER_US)
+       div $r14 $r14 $r13
+
+       ret
+
+// request the current process be sent a message after a timeout expires
+//
+// $r15 - current
+// $r14 - ticks (make sure it is < 2^31 to avoid any possible overflow)
 // $r0  - zero
 timer:
+       push $r9
+       push $r8
+
        // interrupts off to prevent racing with timer isr
        bclr $flags ie0
 
@@ -255,13 +340,22 @@ timer:
        ld b32 $r8 D[$r15 + #proc_time]
        cmp b32 $r8 0
        bra g #timer_done
-       st b32 D[$r15 + #proc_time] $r14
 
-       // halt watchdog timer temporarily and check for a pending
-       // interrupt.  if there's one already pending, we can just
-       // bail since the timer isr will queue the next soonest
-       // right after it's done
+       // halt watchdog timer temporarily
+       clear b32 $r8
        nv_iowr(NV_PPWR_WATCHDOG_ENABLE, $r8)
+
+       // find out how much time elapsed since the last update
+       // of the watchdog and add this time to the wanted ticks
+       nv_iord($r8, NV_PPWR_WATCHDOG_TIME)
+       ld b32 $r9 D[$r0 + #time_prev]
+       sub b32 $r9 $r8
+       add b32 $r14 $r9
+       st b32 D[$r15 + #proc_time] $r14
+
+       // check for a pending interrupt.  if there's one already
+       // pending, we can just bail since the timer isr will
+       // queue the next soonest right after it's done
        nv_iord($r8, NV_PPWR_INTR)
        and $r8 NV_PPWR_INTR_WATCHDOG
        bra nz #timer_enable
@@ -272,10 +366,10 @@ timer:
        cmp b32 $r14 $r0
        bra e #timer_reset
        cmp b32 $r14 $r8
-       bra l #timer_done
-       timer_reset:
-       nv_iowr(NV_PPWR_WATCHDOG_TIME, $r14)
-       st b32 D[$r0 + #time_prev] $r14
+       bra g #timer_enable
+               timer_reset:
+               nv_iowr(NV_PPWR_WATCHDOG_TIME, $r14)
+               st b32 D[$r0 + #time_prev] $r14
 
        // re-enable the watchdog timer
        timer_enable:
@@ -285,6 +379,9 @@ timer:
        // interrupts back on
        timer_done:
        bset $flags ie0
+
+       pop $r8
+       pop $r9
        ret
 
 // send message to another process
@@ -371,6 +468,9 @@ send:
 // $r14 - process
 // $r0  - zero
 recv:
+       push $r9
+       push $r8
+
        ld b32 $r8 D[$r14 + #proc_qget]
        ld b32 $r9 D[$r14 + #proc_qput]
        bclr $flags $p1
@@ -403,6 +503,8 @@ recv:
                bset $flags $p1
                pop $r15
        recv_done:
+       pop $r8
+       pop $r9
        ret
 
 init:
index 5668e045bac1aab2d9d4660b6ea1df84287abc76..96fc984dafdc95159d910b1670a9bef826be8705 100644 (file)
 */     st b32 D[$r0] reg /*
 */     clear b32 $r0
 #endif
+
+#define st(size, addr, reg) /*
+*/     movw $r0 addr /*
+*/     st size D[$r0] reg /*
+*/     clear b32 $r0
+
+#define ld(size, reg, addr) /*
+*/     movw $r0 addr /*
+*/     ld size reg D[$r0] /*
+*/     clear b32 $r0
+
+// does a 64+64 -> 64 unsigned addition (C = A + B)
+#define addu64(reg_a_c_hi, reg_a_c_lo, b_hi, b_lo) /*
+*/    add b32 reg_a_c_lo b_lo /*
+*/    adc b32 reg_a_c_hi b_hi
+
+// does a 64+64 -> 64 substraction (C = A - B)
+#define subu64(reg_a_c_hi, reg_a_c_lo, b_hi, b_lo) /*
+*/    sub b32 reg_a_c_lo b_lo /*
+*/    sbb b32 reg_a_c_hi b_hi
index d43741eccb11b66fd4106e233199c77516f0706b..e89789a53b80101721e1c5e6ea2589edfb642a94 100644 (file)
@@ -43,17 +43,23 @@ process(PROC_MEMX, #memx_init, #memx_recv)
 */     .b32 func
 
 memx_func_head:
-handler(ENTER , 0x0001, 0x0000, #memx_func_enter)
+handler(ENTER , 0x0000, 0x0000, #memx_func_enter)
 memx_func_next:
 handler(LEAVE , 0x0000, 0x0000, #memx_func_leave)
 handler(WR32  , 0x0000, 0x0002, #memx_func_wr32)
 handler(WAIT  , 0x0004, 0x0000, #memx_func_wait)
 handler(DELAY , 0x0001, 0x0000, #memx_func_delay)
+handler(VBLANK, 0x0001, 0x0000, #memx_func_wait_vblank)
 memx_func_tail:
 
 .equ #memx_func_size #memx_func_next - #memx_func_head
 .equ #memx_func_num (#memx_func_tail - #memx_func_head) / #memx_func_size
 
+memx_ts_start:
+.b32 0
+memx_ts_end:
+.b32 0
+
 memx_data_head:
 .skip 0x0800
 memx_data_tail:
@@ -67,19 +73,44 @@ memx_data_tail:
 //
 // $r15 - current (memx)
 // $r4  - packet length
-//     +00: bitmask of heads to wait for vblank on
 // $r3  - opcode desciption
 // $r0  - zero
 memx_func_enter:
+#if NVKM_PPWR_CHIPSET == GT215
+       movw $r8 0x1610
+       nv_rd32($r7, $r8)
+       imm32($r6, 0xfffffffc)
+       and $r7 $r6
+       movw $r6 0x2
+       or $r7 $r6
+       nv_wr32($r8, $r7)
+#else
+       movw $r6 0x001620
+       imm32($r7, ~0x00000aa2);
+       nv_rd32($r8, $r6)
+       and $r8 $r7
+       nv_wr32($r6, $r8)
+
+       imm32($r7, ~0x00000001)
+       nv_rd32($r8, $r6)
+       and $r8 $r7
+       nv_wr32($r6, $r8)
+
+       movw $r6 0x0026f0
+       nv_rd32($r8, $r6)
+       and $r8 $r7
+       nv_wr32($r6, $r8)
+#endif
+
        mov $r6 NV_PPWR_OUTPUT_SET_FB_PAUSE
        nv_iowr(NV_PPWR_OUTPUT_SET, $r6)
        memx_func_enter_wait:
                nv_iord($r6, NV_PPWR_OUTPUT)
                and $r6 NV_PPWR_OUTPUT_FB_PAUSE
                bra z #memx_func_enter_wait
-       //XXX: TODO
-       ld b32 $r6 D[$r1 + 0x00]
-       add b32 $r1 0x04
+
+       nv_iord($r6, NV_PPWR_TIMER_LOW)
+       st b32 D[$r0 + #memx_ts_start] $r6
        ret
 
 // description
@@ -89,14 +120,93 @@ memx_func_enter:
 // $r3  - opcode desciption
 // $r0  - zero
 memx_func_leave:
+       nv_iord($r6, NV_PPWR_TIMER_LOW)
+       st b32 D[$r0 + #memx_ts_end] $r6
+
        mov $r6 NV_PPWR_OUTPUT_CLR_FB_PAUSE
        nv_iowr(NV_PPWR_OUTPUT_CLR, $r6)
        memx_func_leave_wait:
                nv_iord($r6, NV_PPWR_OUTPUT)
                and $r6 NV_PPWR_OUTPUT_FB_PAUSE
                bra nz #memx_func_leave_wait
+
+#if NVKM_PPWR_CHIPSET == GT215
+       movw $r8 0x1610
+       nv_rd32($r7, $r8)
+       imm32($r6, 0xffffffcc)
+       and $r7 $r6
+       nv_wr32($r8, $r7)
+#else
+       movw $r6 0x0026f0
+       imm32($r7, 0x00000001)
+       nv_rd32($r8, $r6)
+       or $r8 $r7
+       nv_wr32($r6, $r8)
+
+       movw $r6 0x001620
+       nv_rd32($r8, $r6)
+       or $r8 $r7
+       nv_wr32($r6, $r8)
+
+       imm32($r7, 0x00000aa2);
+       nv_rd32($r8, $r6)
+       or $r8 $r7
+       nv_wr32($r6, $r8)
+#endif
+       ret
+
+#if NVKM_PPWR_CHIPSET < GF119
+// description
+//
+// $r15 - current (memx)
+// $r4  - packet length
+//     +00: head to wait for vblank on
+// $r3  - opcode desciption
+// $r0  - zero
+memx_func_wait_vblank:
+       ld b32 $r6 D[$r1 + 0x00]
+       cmp b32 $r6 0x0
+       bra z #memx_func_wait_vblank_head0
+       cmp b32 $r6 0x1
+       bra z #memx_func_wait_vblank_head1
+       bra #memx_func_wait_vblank_fini
+
+       memx_func_wait_vblank_head1:
+       movw $r7 0x20
+       bra #memx_func_wait_vblank_0
+
+       memx_func_wait_vblank_head0:
+       movw $r7 0x8
+
+       memx_func_wait_vblank_0:
+               nv_iord($r6, NV_PPWR_INPUT)
+               and $r6 $r7
+               bra nz #memx_func_wait_vblank_0
+
+       memx_func_wait_vblank_1:
+               nv_iord($r6, NV_PPWR_INPUT)
+               and $r6 $r7
+               bra z #memx_func_wait_vblank_1
+
+       memx_func_wait_vblank_fini:
+       add b32 $r1 0x4
+       ret
+
+#else
+
+// XXX: currently no-op
+//
+// $r15 - current (memx)
+// $r4  - packet length
+//     +00: head to wait for vblank on
+// $r3  - opcode desciption
+// $r0  - zero
+memx_func_wait_vblank:
+       add b32 $r1 0x4
        ret
 
+#endif
+
 // description
 //
 // $r15 - current (memx)
@@ -160,14 +270,17 @@ memx_exec:
        push $r13
        mov b32 $r1 $r12
        mov b32 $r2 $r11
+
        memx_exec_next:
-               // fetch the packet header, and locate opcode info
+               // fetch the packet header
                ld b32 $r3 D[$r1]
                add b32 $r1 4
-               shr b32 $r4 $r3 16
-               mulu $r3 #memx_func_size
+               extr $r4 $r3 16:31
+               extr $r3 $r3 0:15
 
                // execute the opcode handler
+               sub b32 $r3 1
+               mulu $r3 #memx_func_size
                ld b32 $r5 D[$r3 + #memx_func_head + #memx_func]
                call $r5
 
@@ -176,6 +289,10 @@ memx_exec:
                bra l #memx_exec_next
 
        // send completion reply
+       ld b32 $r11 D[$r0 + #memx_ts_start]
+       ld b32 $r12 D[$r0 + #memx_ts_end]
+       sub b32 $r12 $r11
+       nv_iord($r11, NV_PPWR_INPUT)
        pop $r13
        pop $r14
        call(send)
index 17a8a383d91a91929c2eebad9ef1f531861c6800..b439519ec866ac01a22a95e82ba124086560b9a5 100644 (file)
@@ -23,6 +23,7 @@
  */
 
 #define NVKM_PPWR_CHIPSET GK208
+#define HW_TICKS_PER_US 324
 
 #define NVKM_FALCON_PC24
 #define NVKM_FALCON_UNSHIFTED_IO
@@ -34,6 +35,7 @@
 .section #nv108_pwr_data
 #define INCLUDE_PROC
 #include "kernel.fuc"
+#include "arith.fuc"
 #include "host.fuc"
 #include "memx.fuc"
 #include "perf.fuc"
@@ -44,6 +46,7 @@
 
 #define INCLUDE_DATA
 #include "kernel.fuc"
+#include "arith.fuc"
 #include "host.fuc"
 #include "memx.fuc"
 #include "perf.fuc"
@@ -56,6 +59,7 @@
 .section #nv108_pwr_code
 #define INCLUDE_CODE
 #include "kernel.fuc"
+#include "arith.fuc"
 #include "host.fuc"
 #include "memx.fuc"
 #include "perf.fuc"
index 986495d533ddb30b9e842e8da6d443c91c0c6808..4d278a96b2bbb8459ff0517210967fe4d86dfc01 100644 (file)
@@ -24,8 +24,8 @@ uint32_t nv108_pwr_data[] = {
        0x00000000,
 /* 0x0058: proc_list_head */
        0x54534f48,
-       0x00000379,
-       0x0000032a,
+       0x00000453,
+       0x00000404,
        0x00000000,
        0x00000000,
        0x00000000,
@@ -46,8 +46,8 @@ uint32_t nv108_pwr_data[] = {
        0x00000000,
        0x00000000,
        0x584d454d,
-       0x00000464,
-       0x00000456,
+       0x0000061c,
+       0x0000060e,
        0x00000000,
        0x00000000,
        0x00000000,
@@ -68,8 +68,8 @@ uint32_t nv108_pwr_data[] = {
        0x00000000,
        0x00000000,
        0x46524550,
-       0x00000468,
-       0x00000466,
+       0x00000620,
+       0x0000061e,
        0x00000000,
        0x00000000,
        0x00000000,
@@ -90,8 +90,8 @@ uint32_t nv108_pwr_data[] = {
        0x00000000,
        0x00000000,
        0x5f433249,
-       0x0000086c,
-       0x00000713,
+       0x00000a24,
+       0x000008cb,
        0x00000000,
        0x00000000,
        0x00000000,
@@ -112,8 +112,8 @@ uint32_t nv108_pwr_data[] = {
        0x00000000,
        0x00000000,
        0x54534554,
-       0x0000088d,
-       0x0000086e,
+       0x00000a45,
+       0x00000a26,
        0x00000000,
        0x00000000,
        0x00000000,
@@ -134,8 +134,8 @@ uint32_t nv108_pwr_data[] = {
        0x00000000,
        0x00000000,
        0x454c4449,
-       0x00000898,
-       0x00000896,
+       0x00000a50,
+       0x00000a4e,
        0x00000000,
        0x00000000,
        0x00000000,
@@ -227,25 +227,31 @@ uint32_t nv108_pwr_data[] = {
        0x00000000,
        0x00000000,
 /* 0x0370: memx_func_head */
-       0x00010000,
-       0x00000000,
-       0x000003a9,
-/* 0x037c: memx_func_next */
        0x00000001,
        0x00000000,
-       0x000003c7,
+       0x00000483,
+/* 0x037c: memx_func_next */
        0x00000002,
+       0x00000000,
+       0x00000500,
+       0x00000003,
        0x00000002,
-       0x000003df,
-       0x00040003,
+       0x00000580,
+       0x00040004,
+       0x00000000,
+       0x0000059d,
+       0x00010005,
+       0x00000000,
+       0x000005b7,
+       0x00010006,
        0x00000000,
-       0x000003fc,
-       0x00010004,
+       0x0000057b,
+/* 0x03b8: memx_func_tail */
+/* 0x03b8: memx_ts_start */
        0x00000000,
-       0x00000416,
-/* 0x03ac: memx_func_tail */
-/* 0x03ac: memx_data_head */
+/* 0x03bc: memx_ts_end */
        0x00000000,
+/* 0x03c0: memx_data_head */
        0x00000000,
        0x00000000,
        0x00000000,
@@ -757,8 +763,9 @@ uint32_t nv108_pwr_data[] = {
        0x00000000,
        0x00000000,
        0x00000000,
-/* 0x0bac: memx_data_tail */
-/* 0x0bac: i2c_scl_map */
+       0x00000000,
+/* 0x0bc0: memx_data_tail */
+/* 0x0bc0: i2c_scl_map */
        0x00000400,
        0x00000800,
        0x00001000,
@@ -769,7 +776,7 @@ uint32_t nv108_pwr_data[] = {
        0x00020000,
        0x00040000,
        0x00080000,
-/* 0x0bd4: i2c_sda_map */
+/* 0x0be8: i2c_sda_map */
        0x00100000,
        0x00200000,
        0x00400000,
@@ -781,10 +788,69 @@ uint32_t nv108_pwr_data[] = {
        0x10000000,
        0x20000000,
        0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
 };
 
 uint32_t nv108_pwr_code[] = {
-       0x02910ef5,
+       0x031c0ef5,
 /* 0x0004: rd32 */
        0xf607a040,
        0x04bd000e,
@@ -812,15 +878,18 @@ uint32_t nv108_pwr_code[] = {
        0x7000d4f1,
        0xf8f61bf4,
 /* 0x005d: nsec */
-       0xcf2c0800,
-/* 0x0062: nsec_loop */
+       0xf990f900,
+       0xcf2c0880,
+/* 0x0066: nsec_loop */
        0x2c090088,
        0xbb0099cf,
        0x9ea60298,
-       0xf8f61ef4,
-/* 0x0071: wait */
-       0xcf2c0800,
-/* 0x0076: wait_loop */
+       0xfcf61ef4,
+       0xf890fc80,
+/* 0x0079: wait */
+       0xf990f900,
+       0xcf2c0880,
+/* 0x0082: wait_loop */
        0xeeb20088,
        0x0000047e,
        0xadfddab2,
@@ -828,28 +897,29 @@ uint32_t nv108_pwr_code[] = {
        0x2c09100b,
        0xbb0099cf,
        0x9ba60298,
-/* 0x0093: wait_done */
-       0xf8e61ef4,
-/* 0x0095: intr_watchdog */
+/* 0x009f: wait_done */
+       0xfce61ef4,
+       0xf890fc80,
+/* 0x00a5: intr_watchdog */
        0x03e99800,
        0xf40096b0,
        0x0a98280b,
        0x029abb9a,
        0x0d0e1cf4,
-       0x01de7e01,
+       0x02617e01,
        0xf494bd00,
-/* 0x00b2: intr_watchdog_next_time */
+/* 0x00c2: intr_watchdog_next_time */
        0x0a98140e,
        0x00a6b09b,
        0xa6080bf4,
        0x061cf49a,
-/* 0x00c0: intr_watchdog_next_time_set */
-/* 0x00c3: intr_watchdog_next_proc */
+/* 0x00d0: intr_watchdog_next_time_set */
+/* 0x00d3: intr_watchdog_next_proc */
        0xb59b09b5,
        0xe0b603e9,
        0x68e6b158,
        0xc81bf402,
-/* 0x00d2: intr */
+/* 0x00e2: intr */
        0x00f900f8,
        0x80f904bd,
        0xa0f990f9,
@@ -865,13 +935,13 @@ uint32_t nv108_pwr_code[] = {
        0xc40088cf,
        0x0bf40289,
        0x9b00b51f,
-       0x957e580e,
+       0xa57e580e,
        0x09980000,
        0x0096b09b,
        0x000d0bf4,
        0x0009f634,
        0x09b504bd,
-/* 0x0125: intr_skip_watchdog */
+/* 0x0135: intr_skip_watchdog */
        0x0089e49a,
        0x360bf408,
        0xcf068849,
@@ -881,20 +951,20 @@ uint32_t nv108_pwr_code[] = {
        0xc0f900cc,
        0xf14f484e,
        0x0d5453e3,
-       0x023f7e00,
+       0x02c27e00,
        0x40c0fc00,
        0x0cf604c0,
-/* 0x0157: intr_subintr_skip_fifo */
+/* 0x0167: intr_subintr_skip_fifo */
        0x4004bd00,
        0x09f60688,
-/* 0x015f: intr_skip_subintr */
+/* 0x016f: intr_skip_subintr */
        0xc404bd00,
        0x0bf42089,
        0xbfa4f107,
-/* 0x0169: intr_skip_pause */
+/* 0x0179: intr_skip_pause */
        0x4089c4ff,
        0xf1070bf4,
-/* 0x0173: intr_skip_user0 */
+/* 0x0183: intr_skip_user0 */
        0x00ffbfa4,
        0x0008f604,
        0x80fc04bd,
@@ -904,304 +974,417 @@ uint32_t nv108_pwr_code[] = {
        0xfca0fcb0,
        0xfc80fc90,
        0x0032f400,
-/* 0x0196: timer */
-       0x32f401f8,
-       0x03f89810,
-       0xf40086b0,
-       0xfeb53a1c,
-       0xf6380003,
+/* 0x01a6: ticks_from_ns */
+       0xc0f901f8,
+       0xd7f1b0f9,
+       0xd3f00144,
+       0x7721f500,
+       0xe8ccec03,
+       0x00b4b003,
+       0xec120bf4,
+       0xf103e8ee,
+       0xf00144d7,
+       0x21f500d3,
+/* 0x01ce: ticks_from_ns_quit */
+       0xceb20377,
+       0xc0fcb0fc,
+/* 0x01d6: ticks_from_us */
+       0xc0f900f8,
+       0xd7f1b0f9,
+       0xd3f00144,
+       0x7721f500,
+       0xb0ceb203,
+       0x0bf400b4,
+/* 0x01ef: ticks_from_us_quit */
+       0xfce4bd05,
+       0xf8c0fcb0,
+/* 0x01f5: ticks_to_us */
+       0x44d7f100,
+       0x00d3f001,
+       0xf8ecedff,
+/* 0x0201: timer */
+       0xf990f900,
+       0x1032f480,
+       0xb003f898,
+       0x1cf40086,
+       0x0084bd4a,
+       0x0008f638,
+       0x340804bd,
+       0x980088cf,
+       0x98bb9a09,
+       0x00e9bb02,
+       0x0803feb5,
+       0x0088cf08,
+       0xf40284f0,
+       0x34081c1b,
+       0xa60088cf,
+       0x080bf4e0,
+       0x1cf4e8a6,
+/* 0x0245: timer_reset */
+       0xf634000d,
+       0x04bd000e,
+/* 0x024f: timer_enable */
+       0x089a0eb5,
+       0xf6380001,
        0x04bd0008,
-       0x88cf0808,
-       0x0284f000,
-       0x081c1bf4,
-       0x0088cf34,
-       0x0bf4e0a6,
-       0xf4e8a608,
-/* 0x01c6: timer_reset */
-       0x3400161e,
-       0xbd000ef6,
-       0x9a0eb504,
-/* 0x01d0: timer_enable */
-       0x38000108,
-       0xbd0008f6,
-/* 0x01d9: timer_done */
-       0x1031f404,
-/* 0x01de: send_proc */
-       0x80f900f8,
-       0xe89890f9,
-       0x04e99805,
-       0xa60486f0,
-       0x2a0bf489,
-       0x940398c4,
-       0x80b60488,
-       0x008ebb18,
-       0xb500fa98,
-       0x8db5008a,
-       0x028cb501,
-       0xb6038bb5,
-       0x94f00190,
-       0x04e9b507,
-/* 0x0217: send_done */
-       0xfc0231f4,
-       0xf880fc90,
-/* 0x021d: find */
-       0x0880f900,
-       0x0131f458,
-/* 0x0224: find_loop */
-       0xa6008a98,
-       0x100bf4ae,
-       0xb15880b6,
-       0xf4026886,
-       0x32f4f11b,
-/* 0x0239: find_done */
-       0xfc8eb201,
-/* 0x023f: send */
-       0x7e00f880,
-       0xf400021d,
-       0x00f89b01,
-/* 0x0248: recv */
-       0x9805e898,
-       0x32f404e9,
-       0xf489a601,
-       0x89c43c0b,
-       0x0180b603,
-       0xb50784f0,
-       0xea9805e8,
-       0xfef0f902,
-       0xf0f9018f,
-       0x9994efb2,
-       0x00e9bb04,
-       0x9818e0b6,
-       0xec9803eb,
-       0x01ed9802,
-       0xf900ee98,
-       0xfef0fca5,
-       0x31f400f8,
-/* 0x028f: recv_done */
-       0xf8f0fc01,
-/* 0x0291: init */
-       0x01084100,
-       0xe70011cf,
-       0xb6010911,
-       0x14fe0814,
-       0x00e04100,
-       0x000013f0,
-       0x0001f61c,
-       0xff0104bd,
-       0x01f61400,
-       0x0104bd00,
-       0x0015f102,
-       0xf6100008,
-       0x04bd0001,
-       0xf000d241,
-       0x10fe0013,
-       0x1031f400,
-       0x38000101,
+/* 0x0258: timer_done */
+       0xfc1031f4,
+       0xf890fc80,
+/* 0x0261: send_proc */
+       0xf980f900,
+       0x05e89890,
+       0xf004e998,
+       0x89a60486,
+       0xc42a0bf4,
+       0x88940398,
+       0x1880b604,
+       0x98008ebb,
+       0x8ab500fa,
+       0x018db500,
+       0xb5028cb5,
+       0x90b6038b,
+       0x0794f001,
+       0xf404e9b5,
+/* 0x029a: send_done */
+       0x90fc0231,
+       0x00f880fc,
+/* 0x02a0: find */
+       0x580880f9,
+/* 0x02a7: find_loop */
+       0x980131f4,
+       0xaea6008a,
+       0xb6100bf4,
+       0x86b15880,
+       0x1bf40268,
+       0x0132f4f1,
+/* 0x02bc: find_done */
+       0x80fc8eb2,
+/* 0x02c2: send */
+       0xa07e00f8,
+       0x01f40002,
+/* 0x02cb: recv */
+       0xf900f89b,
+       0x9880f990,
+       0xe99805e8,
+       0x0132f404,
+       0x0bf489a6,
+       0x0389c43c,
+       0xf00180b6,
+       0xe8b50784,
+       0x02ea9805,
+       0x8ffef0f9,
+       0xb2f0f901,
+       0x049994ef,
+       0xb600e9bb,
+       0xeb9818e0,
+       0x02ec9803,
+       0x9801ed98,
+       0xa5f900ee,
+       0xf8fef0fc,
+       0x0131f400,
+/* 0x0316: recv_done */
+       0x80fcf0fc,
+       0x00f890fc,
+/* 0x031c: init */
+       0xcf010841,
+       0x11e70011,
+       0x14b60109,
+       0x0014fe08,
+       0xf000e041,
+       0x1c000013,
        0xbd0001f6,
-/* 0x02db: init_proc */
-       0x98580f04,
-       0x16b001f1,
-       0xfa0bf400,
-       0xf0b615f9,
-       0xf20ef458,
-/* 0x02ec: host_send */
-       0xcf04b041,
-       0xa0420011,
-       0x0022cf04,
-       0x0bf412a6,
-       0x071ec42e,
-       0xb704ee94,
-       0x980270e0,
-       0xec9803eb,
-       0x01ed9802,
-       0x7e00ee98,
-       0xb600023f,
-       0x1ec40110,
-       0x04b0400f,
-       0xbd000ef6,
-       0xc70ef404,
-/* 0x0328: host_send_done */
-/* 0x032a: host_recv */
-       0x494100f8,
-       0x5413f14e,
-       0xf4e1a652,
-/* 0x0336: host_recv_wait */
-       0xcc41b90b,
-       0x0011cf04,
-       0xcf04c842,
-       0x16f00022,
-       0xf412a608,
-       0x23c4ef0b,
-       0x0434b607,
-       0x02f030b7,
-       0xb5033bb5,
-       0x3db5023c,
-       0x003eb501,
-       0xf00120b6,
-       0xc8400f24,
-       0x0002f604,
-       0x400204bd,
-       0x02f60000,
-       0xf804bd00,
-/* 0x0379: host_init */
-       0x00804100,
-       0xf11014b6,
-       0x40027015,
-       0x01f604d0,
+       0x00ff0104,
+       0x0001f614,
+       0x020104bd,
+       0x080015f1,
+       0x01f61000,
        0x4104bd00,
+       0x13f000e2,
+       0x0010fe00,
+       0x011031f4,
+       0xf6380001,
+       0x04bd0001,
+/* 0x0366: init_proc */
+       0xf198580f,
+       0x0016b001,
+       0xf9fa0bf4,
+       0x58f0b615,
+/* 0x0377: mulu32_32_64 */
+       0xf9f20ef4,
+       0xf920f910,
+       0x9540f930,
+       0xd29510e1,
+       0xbdc4bd10,
+       0xc0edffb4,
+       0xb2301dff,
+       0xff34f134,
+       0x1034b6ff,
+       0xbb1045b6,
+       0xb4bb00c3,
+       0x30e2ff01,
+       0x34f134b2,
+       0x34b6ffff,
+       0x1045b610,
+       0xbb00c3bb,
+       0x12ff01b4,
+       0x00b3bb30,
+       0x30fc40fc,
+       0x10fc20fc,
+/* 0x03c6: host_send */
+       0xb04100f8,
+       0x0011cf04,
+       0xcf04a042,
+       0x12a60022,
+       0xc42e0bf4,
+       0xee94071e,
+       0x70e0b704,
+       0x03eb9802,
+       0x9802ec98,
+       0xee9801ed,
+       0x02c27e00,
+       0x0110b600,
+       0x400f1ec4,
+       0x0ef604b0,
+       0xf404bd00,
+/* 0x0402: host_send_done */
+       0x00f8c70e,
+/* 0x0404: host_recv */
+       0xf14e4941,
+       0xa6525413,
+       0xb90bf4e1,
+/* 0x0410: host_recv_wait */
+       0xcf04cc41,
+       0xc8420011,
+       0x0022cf04,
+       0xa60816f0,
+       0xef0bf412,
+       0xb60723c4,
+       0x30b70434,
+       0x3bb502f0,
+       0x023cb503,
+       0xb5013db5,
+       0x20b6003e,
+       0x0f24f001,
+       0xf604c840,
+       0x04bd0002,
+       0x00004002,
+       0xbd0002f6,
+/* 0x0453: host_init */
+       0x4100f804,
        0x14b60080,
-       0xf015f110,
-       0x04dc4002,
+       0x7015f110,
+       0x04d04002,
+       0xbd0001f6,
+       0x00804104,
+       0xf11014b6,
+       0x4002f015,
+       0x01f604dc,
+       0x0104bd00,
+       0x04c44001,
        0xbd0001f6,
-       0x40010104,
-       0x01f604c4,
-       0xf804bd00,
-/* 0x03a9: memx_func_enter */
-       0x40040600,
-       0x06f607e0,
-/* 0x03b3: memx_func_enter_wait */
-       0x4604bd00,
-       0x66cf07c0,
-       0x0464f000,
-       0x98f70bf4,
-       0x10b60016,
-/* 0x03c7: memx_func_leave */
-       0x0600f804,
-       0x07e44004,
-       0xbd0006f6,
-/* 0x03d1: memx_func_leave_wait */
-       0x07c04604,
-       0xf00066cf,
-       0x1bf40464,
-/* 0x03df: memx_func_wr32 */
-       0x9800f8f7,
-       0x15980016,
-       0x0810b601,
-       0x50f960f9,
+/* 0x0483: memx_func_enter */
+       0xf100f804,
+       0xf1162067,
+       0xf1f55d77,
+       0xb2ffff73,
+       0x00047e6e,
+       0xfdd8b200,
+       0x60f90487,
+       0xd0fc80f9,
+       0x2e7ee0fc,
+       0x77f10000,
+       0x73f1fffe,
+       0x6eb2ffff,
+       0x0000047e,
+       0x87fdd8b2,
+       0xf960f904,
+       0xfcd0fc80,
+       0x002e7ee0,
+       0xf067f100,
+       0x7e6eb226,
+       0xb2000004,
+       0x0487fdd8,
+       0x80f960f9,
        0xe0fcd0fc,
        0x00002e7e,
-       0xf40242b6,
-       0x00f8e81b,
-/* 0x03fc: memx_func_wait */
-       0x88cf2c08,
-       0x001e9800,
-       0x98011d98,
-       0x1b98021c,
-       0x1010b603,
-       0x0000717e,
-/* 0x0416: memx_func_delay */
-       0x1e9800f8,
-       0x0410b600,
-       0x00005d7e,
-/* 0x0422: memx_exec */
-       0xe0f900f8,
-       0xc1b2d0f9,
-/* 0x042a: memx_exec_next */
-       0x1398b2b2,
-       0x0410b600,
-       0xf0103495,
-       0x35980c30,
-       0xa655f9de,
-       0xed1ef412,
+       0xe0400406,
+       0x0006f607,
+/* 0x04ea: memx_func_enter_wait */
+       0xc04604bd,
+       0x0066cf07,
+       0xf40464f0,
+       0x2c06f70b,
+       0xb50066cf,
+       0x00f8ee06,
+/* 0x0500: memx_func_leave */
+       0x66cf2c06,
+       0xef06b500,
+       0xe4400406,
+       0x0006f607,
+/* 0x0512: memx_func_leave_wait */
+       0xc04604bd,
+       0x0066cf07,
+       0xf40464f0,
+       0x67f1f71b,
+       0x77f126f0,
+       0x73f00001,
+       0x7e6eb200,
+       0xb2000004,
+       0x0587fdd8,
+       0x80f960f9,
        0xe0fcd0fc,
-       0x00023f7e,
-/* 0x044a: memx_info */
-       0xac4c00f8,
+       0x00002e7e,
+       0x162067f1,
+       0x047e6eb2,
+       0xd8b20000,
+       0xf90587fd,
+       0xfc80f960,
+       0x7ee0fcd0,
+       0xf100002e,
+       0xf00aa277,
+       0x6eb20073,
+       0x0000047e,
+       0x87fdd8b2,
+       0xf960f905,
+       0xfcd0fc80,
+       0x002e7ee0,
+/* 0x057b: memx_func_wait_vblank */
+       0xb600f800,
+       0x00f80410,
+/* 0x0580: memx_func_wr32 */
+       0x98001698,
+       0x10b60115,
+       0xf960f908,
+       0xfcd0fc50,
+       0x002e7ee0,
+       0x0242b600,
+       0xf8e81bf4,
+/* 0x059d: memx_func_wait */
+       0xcf2c0800,
+       0x1e980088,
+       0x011d9800,
+       0x98021c98,
+       0x10b6031b,
+       0x00797e10,
+/* 0x05b7: memx_func_delay */
+       0x9800f800,
+       0x10b6001e,
+       0x005d7e04,
+/* 0x05c3: memx_exec */
+       0xf900f800,
+       0xb2d0f9e0,
+/* 0x05cb: memx_exec_next */
+       0x98b2b2c1,
+       0x10b60013,
+       0xf034e704,
+       0xe033e701,
+       0x0132b601,
+       0x980c30f0,
+       0x55f9de35,
+       0x1ef412a6,
+       0xee0b98e5,
+       0xbbef0c98,
+       0xc44b02cb,
+       0x00bbcf07,
+       0xe0fcd0fc,
+       0x0002c27e,
+/* 0x0602: memx_info */
+       0xc04c00f8,
        0x08004b03,
-       0x00023f7e,
-/* 0x0456: memx_recv */
+       0x0002c27e,
+/* 0x060e: memx_recv */
        0xd6b000f8,
-       0xc90bf401,
+       0xb20bf401,
        0xf400d6b0,
        0x00f8eb0b,
-/* 0x0464: memx_init */
-/* 0x0466: perf_recv */
+/* 0x061c: memx_init */
+/* 0x061e: perf_recv */
        0x00f800f8,
-/* 0x0468: perf_init */
-/* 0x046a: i2c_drive_scl */
+/* 0x0620: perf_init */
+/* 0x0622: i2c_drive_scl */
        0x36b000f8,
        0x0d0bf400,
        0xf607e040,
        0x04bd0001,
-/* 0x047a: i2c_drive_scl_lo */
+/* 0x0632: i2c_drive_scl_lo */
        0xe44000f8,
        0x0001f607,
        0x00f804bd,
-/* 0x0484: i2c_drive_sda */
+/* 0x063c: i2c_drive_sda */
        0xf40036b0,
        0xe0400d0b,
        0x0002f607,
        0x00f804bd,
-/* 0x0494: i2c_drive_sda_lo */
+/* 0x064c: i2c_drive_sda_lo */
        0xf607e440,
        0x04bd0002,
-/* 0x049e: i2c_sense_scl */
+/* 0x0656: i2c_sense_scl */
        0x32f400f8,
        0x07c44301,
        0xfd0033cf,
        0x0bf40431,
        0x0131f406,
-/* 0x04b0: i2c_sense_scl_done */
-/* 0x04b2: i2c_sense_sda */
+/* 0x0668: i2c_sense_scl_done */
+/* 0x066a: i2c_sense_sda */
        0x32f400f8,
        0x07c44301,
        0xfd0033cf,
        0x0bf40432,
        0x0131f406,
-/* 0x04c4: i2c_sense_sda_done */
-/* 0x04c6: i2c_raise_scl */
+/* 0x067c: i2c_sense_sda_done */
+/* 0x067e: i2c_raise_scl */
        0x40f900f8,
        0x03089844,
-       0x046a7e01,
-/* 0x04d1: i2c_raise_scl_wait */
+       0x06227e01,
+/* 0x0689: i2c_raise_scl_wait */
        0x03e84e00,
        0x00005d7e,
-       0x00049e7e,
+       0x0006567e,
        0xb60901f4,
        0x1bf40142,
-/* 0x04e5: i2c_raise_scl_done */
+/* 0x069d: i2c_raise_scl_done */
        0xf840fcef,
-/* 0x04e9: i2c_start */
-       0x049e7e00,
+/* 0x06a1: i2c_start */
+       0x06567e00,
        0x0d11f400,
-       0x0004b27e,
+       0x00066a7e,
        0xf40611f4,
-/* 0x04fa: i2c_start_rep */
+/* 0x06b2: i2c_start_rep */
        0x00032e0e,
-       0x00046a7e,
-       0x847e0103,
-       0x76bb0004,
+       0x0006227e,
+       0x3c7e0103,
+       0x76bb0006,
        0x0465b600,
        0x659450f9,
        0x0256bb04,
        0x75fd50bd,
        0x7e50fc04,
-       0xb60004c6,
+       0xb600067e,
        0x11f40464,
-/* 0x0525: i2c_start_send */
+/* 0x06dd: i2c_start_send */
        0x7e00031d,
-       0x4e000484,
+       0x4e00063c,
        0x5d7e1388,
        0x00030000,
-       0x00046a7e,
+       0x0006227e,
        0x7e13884e,
-/* 0x053f: i2c_start_out */
+/* 0x06f7: i2c_start_out */
        0xf800005d,
-/* 0x0541: i2c_stop */
+/* 0x06f9: i2c_stop */
        0x7e000300,
-       0x0300046a,
-       0x04847e00,
+       0x03000622,
+       0x063c7e00,
        0x03e84e00,
        0x00005d7e,
-       0x6a7e0103,
-       0x884e0004,
+       0x227e0103,
+       0x884e0006,
        0x005d7e13,
        0x7e010300,
-       0x4e000484,
+       0x4e00063c,
        0x5d7e1388,
        0x00f80000,
-/* 0x0570: i2c_bitw */
-       0x0004847e,
+/* 0x0728: i2c_bitw */
+       0x00063c7e,
        0x7e03e84e,
        0xbb00005d,
        0x65b60076,
@@ -1209,44 +1392,44 @@ uint32_t nv108_pwr_code[] = {
        0x56bb0465,
        0xfd50bd02,
        0x50fc0475,
-       0x0004c67e,
+       0x00067e7e,
        0xf40464b6,
        0x884e1711,
        0x005d7e13,
        0x7e000300,
-       0x4e00046a,
+       0x4e000622,
        0x5d7e1388,
-/* 0x05ae: i2c_bitw_out */
+/* 0x0766: i2c_bitw_out */
        0x00f80000,
-/* 0x05b0: i2c_bitr */
-       0x847e0103,
-       0xe84e0004,
+/* 0x0768: i2c_bitr */
+       0x3c7e0103,
+       0xe84e0006,
        0x005d7e03,
        0x0076bb00,
        0xf90465b6,
        0x04659450,
        0xbd0256bb,
        0x0475fd50,
-       0xc67e50fc,
-       0x64b60004,
+       0x7e7e50fc,
+       0x64b60006,
        0x1a11f404,
-       0x0004b27e,
-       0x6a7e0003,
-       0x884e0004,
+       0x00066a7e,
+       0x227e0003,
+       0x884e0006,
        0x005d7e13,
        0x013cf000,
-/* 0x05f3: i2c_bitr_done */
+/* 0x07ab: i2c_bitr_done */
        0xf80131f4,
-/* 0x05f5: i2c_get_byte */
+/* 0x07ad: i2c_get_byte */
        0x04000500,
-/* 0x05f9: i2c_get_byte_next */
+/* 0x07b1: i2c_get_byte_next */
        0x0154b608,
        0xb60076bb,
        0x50f90465,
        0xbb046594,
        0x50bd0256,
        0xfc0475fd,
-       0x05b07e50,
+       0x07687e50,
        0x0464b600,
        0xfd2a11f4,
        0x42b60553,
@@ -1257,11 +1440,11 @@ uint32_t nv108_pwr_code[] = {
        0x0256bb04,
        0x75fd50bd,
        0x7e50fc04,
-       0xb6000570,
-/* 0x0642: i2c_get_byte_done */
+       0xb6000728,
+/* 0x07fa: i2c_get_byte_done */
        0x00f80464,
-/* 0x0644: i2c_put_byte */
-/* 0x0646: i2c_put_byte_next */
+/* 0x07fc: i2c_put_byte */
+/* 0x07fe: i2c_put_byte_next */
        0x42b60804,
        0x3854ff01,
        0xb60076bb,
@@ -1269,7 +1452,7 @@ uint32_t nv108_pwr_code[] = {
        0xbb046594,
        0x50bd0256,
        0xfc0475fd,
-       0x05707e50,
+       0x07287e50,
        0x0464b600,
        0xb03411f4,
        0x1bf40046,
@@ -1278,21 +1461,21 @@ uint32_t nv108_pwr_code[] = {
        0x04659450,
        0xbd0256bb,
        0x0475fd50,
-       0xb07e50fc,
-       0x64b60005,
+       0x687e50fc,
+       0x64b60007,
        0x0f11f404,
        0xb00076bb,
        0x1bf40136,
        0x0132f406,
-/* 0x069c: i2c_put_byte_done */
-/* 0x069e: i2c_addr */
+/* 0x0854: i2c_put_byte_done */
+/* 0x0856: i2c_addr */
        0x76bb00f8,
        0x0465b600,
        0x659450f9,
        0x0256bb04,
        0x75fd50bd,
        0x7e50fc04,
-       0xb60004e9,
+       0xb60006a1,
        0x11f40464,
        0x2ec3e729,
        0x0134b601,
@@ -1302,32 +1485,32 @@ uint32_t nv108_pwr_code[] = {
        0x56bb0465,
        0xfd50bd02,
        0x50fc0475,
-       0x0006447e,
-/* 0x06e3: i2c_addr_done */
+       0x0007fc7e,
+/* 0x089b: i2c_addr_done */
        0xf80464b6,
-/* 0x06e5: i2c_acquire_addr */
+/* 0x089d: i2c_acquire_addr */
        0xf8cec700,
        0xb705e4b6,
        0xf8d014e0,
-/* 0x06f1: i2c_acquire */
-       0x06e57e00,
+/* 0x08a9: i2c_acquire */
+       0x089d7e00,
        0x00047e00,
        0x03d9f000,
        0x00002e7e,
-/* 0x0702: i2c_release */
-       0xe57e00f8,
-       0x047e0006,
+/* 0x08ba: i2c_release */
+       0x9d7e00f8,
+       0x047e0008,
        0xdaf00000,
        0x002e7e03,
-/* 0x0713: i2c_recv */
+/* 0x08cb: i2c_recv */
        0xf400f800,
        0xc1c70132,
        0x0214b6f8,
        0xf52816b0,
        0xb801371f,
-       0x000bd413,
+       0x000be813,
        0xb8003298,
-       0x000bac13,
+       0x000bc013,
        0xf4003198,
        0xd0f90231,
        0xd0f9e0f9,
@@ -1339,7 +1522,7 @@ uint32_t nv108_pwr_code[] = {
        0x56bb0465,
        0xfd50bd02,
        0x50fc0475,
-       0x0006f17e,
+       0x0008a97e,
        0xfc0464b6,
        0x00d6b0d0,
        0x00b01bf5,
@@ -1349,7 +1532,7 @@ uint32_t nv108_pwr_code[] = {
        0x0256bb04,
        0x75fd50bd,
        0x7e50fc04,
-       0xb600069e,
+       0xb6000856,
        0x11f50464,
        0xc5c700cc,
        0x0076bbe0,
@@ -1357,8 +1540,8 @@ uint32_t nv108_pwr_code[] = {
        0x04659450,
        0xbd0256bb,
        0x0475fd50,
-       0x447e50fc,
-       0x64b60006,
+       0xfc7e50fc,
+       0x64b60007,
        0xa911f504,
        0xbb010500,
        0x65b60076,
@@ -1366,7 +1549,7 @@ uint32_t nv108_pwr_code[] = {
        0x56bb0465,
        0xfd50bd02,
        0x50fc0475,
-       0x00069e7e,
+       0x0008567e,
        0xf50464b6,
        0xbb008711,
        0x65b60076,
@@ -1374,7 +1557,7 @@ uint32_t nv108_pwr_code[] = {
        0x56bb0465,
        0xfd50bd02,
        0x50fc0475,
-       0x0005f57e,
+       0x0007ad7e,
        0xf40464b6,
        0x5bcb6711,
        0x0076bbe0,
@@ -1382,37 +1565,37 @@ uint32_t nv108_pwr_code[] = {
        0x04659450,
        0xbd0256bb,
        0x0475fd50,
-       0x417e50fc,
-       0x64b60005,
+       0xf97e50fc,
+       0x64b60006,
        0xbd5bb204,
        0x410ef474,
-/* 0x0818: i2c_recv_not_rd08 */
+/* 0x09d0: i2c_recv_not_rd08 */
        0xf401d6b0,
        0x00053b1b,
-       0x00069e7e,
+       0x0008567e,
        0xc73211f4,
-       0x447ee0c5,
-       0x11f40006,
+       0xfc7ee0c5,
+       0x11f40007,
        0x7e000528,
-       0xf400069e,
+       0xf4000856,
        0xb5c71f11,
-       0x06447ee0,
+       0x07fc7ee0,
        0x1511f400,
-       0x0005417e,
+       0x0006f97e,
        0xc5c774bd,
        0x091bf408,
        0xf40232f4,
-/* 0x0856: i2c_recv_not_wr08 */
-/* 0x0856: i2c_recv_done */
+/* 0x0a0e: i2c_recv_not_wr08 */
+/* 0x0a0e: i2c_recv_done */
        0xcec7030e,
-       0x07027ef8,
+       0x08ba7ef8,
        0xfce0fc00,
        0x0912f4d0,
-       0x3f7e7cb2,
-/* 0x086a: i2c_recv_exit */
+       0xc27e7cb2,
+/* 0x0a22: i2c_recv_exit */
        0x00f80002,
-/* 0x086c: i2c_init */
-/* 0x086e: test_recv */
+/* 0x0a24: i2c_init */
+/* 0x0a26: test_recv */
        0x584100f8,
        0x0011cf04,
        0x400110b6,
@@ -1420,28 +1603,28 @@ uint32_t nv108_pwr_code[] = {
        0xf104bd00,
        0xf1d900e7,
        0x7e134fe3,
-       0xf8000196,
-/* 0x088d: test_init */
+       0xf8000201,
+/* 0x0a45: test_init */
        0x08004e00,
-       0x0001967e,
-/* 0x0896: idle_recv */
+       0x0002017e,
+/* 0x0a4e: idle_recv */
        0x00f800f8,
-/* 0x0898: idle */
+/* 0x0a50: idle */
        0x410031f4,
        0x11cf0454,
        0x0110b600,
        0xf6045440,
        0x04bd0001,
-/* 0x08ac: idle_loop */
+/* 0x0a64: idle_loop */
        0x32f45801,
-/* 0x08b1: idle_proc */
-/* 0x08b1: idle_proc_exec */
+/* 0x0a69: idle_proc */
+/* 0x0a69: idle_proc_exec */
        0xb210f902,
-       0x02487e1e,
+       0x02cb7e1e,
        0xf410fc00,
        0x31f40911,
        0xf00ef402,
-/* 0x08c4: idle_proc_next */
+/* 0x0a7c: idle_proc_next */
        0xa65810b6,
        0xe81bf41f,
        0xf4e002f4,
@@ -1457,4 +1640,22 @@ uint32_t nv108_pwr_code[] = {
        0x00000000,
        0x00000000,
        0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
 };
index 6744fcc0615160e657227285a70fc2c201bb7cb9..daa06c1c655e206dbff9ea20b7768d0b7d1e502e 100644 (file)
@@ -23,6 +23,7 @@
  */
 
 #define NVKM_PPWR_CHIPSET GT215
+#define HW_TICKS_PER_US 203 // should be 202.5
 
 //#define NVKM_FALCON_PC24
 //#define NVKM_FALCON_UNSHIFTED_IO
@@ -34,6 +35,7 @@
 .section #nva3_pwr_data
 #define INCLUDE_PROC
 #include "kernel.fuc"
+#include "arith.fuc"
 #include "host.fuc"
 #include "memx.fuc"
 #include "perf.fuc"
@@ -44,6 +46,7 @@
 
 #define INCLUDE_DATA
 #include "kernel.fuc"
+#include "arith.fuc"
 #include "host.fuc"
 #include "memx.fuc"
 #include "perf.fuc"
@@ -56,6 +59,7 @@
 .section #nva3_pwr_code
 #define INCLUDE_CODE
 #include "kernel.fuc"
+#include "arith.fuc"
 #include "host.fuc"
 #include "memx.fuc"
 #include "perf.fuc"
index e087ce3041beb51069821677b7b58c260acf5863..64e97baabc3c4d71850641df7a3652d94703bbb4 100644 (file)
@@ -24,8 +24,8 @@ uint32_t nva3_pwr_data[] = {
        0x00000000,
 /* 0x0058: proc_list_head */
        0x54534f48,
-       0x00000430,
-       0x000003cd,
+       0x00000512,
+       0x000004af,
        0x00000000,
        0x00000000,
        0x00000000,
@@ -46,8 +46,8 @@ uint32_t nva3_pwr_data[] = {
        0x00000000,
        0x00000000,
        0x584d454d,
-       0x00000542,
-       0x00000534,
+       0x000006e0,
+       0x000006d2,
        0x00000000,
        0x00000000,
        0x00000000,
@@ -68,8 +68,8 @@ uint32_t nva3_pwr_data[] = {
        0x00000000,
        0x00000000,
        0x46524550,
-       0x00000546,
-       0x00000544,
+       0x000006e4,
+       0x000006e2,
        0x00000000,
        0x00000000,
        0x00000000,
@@ -90,8 +90,8 @@ uint32_t nva3_pwr_data[] = {
        0x00000000,
        0x00000000,
        0x5f433249,
-       0x00000976,
-       0x00000819,
+       0x00000b14,
+       0x000009b7,
        0x00000000,
        0x00000000,
        0x00000000,
@@ -112,8 +112,8 @@ uint32_t nva3_pwr_data[] = {
        0x00000000,
        0x00000000,
        0x54534554,
-       0x0000099f,
-       0x00000978,
+       0x00000b3d,
+       0x00000b16,
        0x00000000,
        0x00000000,
        0x00000000,
@@ -134,8 +134,8 @@ uint32_t nva3_pwr_data[] = {
        0x00000000,
        0x00000000,
        0x454c4449,
-       0x000009ab,
-       0x000009a9,
+       0x00000b49,
+       0x00000b47,
        0x00000000,
        0x00000000,
        0x00000000,
@@ -227,25 +227,31 @@ uint32_t nva3_pwr_data[] = {
        0x00000000,
        0x00000000,
 /* 0x0370: memx_func_head */
-       0x00010000,
-       0x00000000,
-       0x0000046f,
-/* 0x037c: memx_func_next */
        0x00000001,
        0x00000000,
-       0x00000496,
+       0x00000551,
+/* 0x037c: memx_func_next */
        0x00000002,
+       0x00000000,
+       0x000005a8,
+       0x00000003,
        0x00000002,
-       0x000004b7,
-       0x00040003,
+       0x0000063a,
+       0x00040004,
+       0x00000000,
+       0x00000656,
+       0x00010005,
+       0x00000000,
+       0x00000673,
+       0x00010006,
        0x00000000,
-       0x000004d3,
-       0x00010004,
+       0x000005f8,
+/* 0x03b8: memx_func_tail */
+/* 0x03b8: memx_ts_start */
        0x00000000,
-       0x000004f0,
-/* 0x03ac: memx_func_tail */
-/* 0x03ac: memx_data_head */
+/* 0x03bc: memx_ts_end */
        0x00000000,
+/* 0x03c0: memx_data_head */
        0x00000000,
        0x00000000,
        0x00000000,
@@ -757,8 +763,9 @@ uint32_t nva3_pwr_data[] = {
        0x00000000,
        0x00000000,
        0x00000000,
-/* 0x0bac: memx_data_tail */
-/* 0x0bac: i2c_scl_map */
+       0x00000000,
+/* 0x0bc0: memx_data_tail */
+/* 0x0bc0: i2c_scl_map */
        0x00001000,
        0x00004000,
        0x00010000,
@@ -769,7 +776,7 @@ uint32_t nva3_pwr_data[] = {
        0x01000000,
        0x04000000,
        0x10000000,
-/* 0x0bd4: i2c_sda_map */
+/* 0x0be8: i2c_sda_map */
        0x00002000,
        0x00008000,
        0x00020000,
@@ -780,7 +787,7 @@ uint32_t nva3_pwr_data[] = {
        0x02000000,
        0x08000000,
        0x20000000,
-/* 0x0bfc: i2c_ctrl */
+/* 0x0c10: i2c_ctrl */
        0x0000e138,
        0x0000e150,
        0x0000e168,
@@ -841,15 +848,10 @@ uint32_t nva3_pwr_data[] = {
        0x00000000,
        0x00000000,
        0x00000000,
-       0x00000000,
-       0x00000000,
-       0x00000000,
-       0x00000000,
-       0x00000000,
 };
 
 uint32_t nva3_pwr_code[] = {
-       0x030d0ef5,
+       0x039e0ef5,
 /* 0x0004: rd32 */
        0x07a007f1,
        0xd00604b6,
@@ -885,19 +887,22 @@ uint32_t nva3_pwr_code[] = {
        0xd4f100dd,
        0x1bf47000,
 /* 0x007f: nsec */
-       0xf000f8f2,
+       0xf900f8f2,
+       0xf080f990,
        0x84b62c87,
        0x0088cf06,
-/* 0x0088: nsec_loop */
+/* 0x008c: nsec_loop */
        0xb62c97f0,
        0x99cf0694,
        0x0298bb00,
        0xf4069eb8,
-       0x00f8f11e,
-/* 0x009c: wait */
+       0x80fcf11e,
+       0x00f890fc,
+/* 0x00a4: wait */
+       0x80f990f9,
        0xb62c87f0,
        0x88cf0684,
-/* 0x00a5: wait_loop */
+/* 0x00b1: wait_loop */
        0x02eeb900,
        0xb90421f4,
        0xadfd02da,
@@ -907,28 +912,29 @@ uint32_t nva3_pwr_code[] = {
        0x0099cf06,
        0xb80298bb,
        0x1ef4069b,
-/* 0x00c9: wait_done */
-/* 0x00cb: intr_watchdog */
-       0x9800f8df,
+/* 0x00d5: wait_done */
+       0xfc80fcdf,
+/* 0x00db: intr_watchdog */
+       0x9800f890,
        0x96b003e9,
        0x2a0bf400,
        0xbb9a0a98,
        0x1cf4029a,
        0x01d7f00f,
-       0x025421f5,
+       0x02dd21f5,
        0x0ef494bd,
-/* 0x00e9: intr_watchdog_next_time */
+/* 0x00f9: intr_watchdog_next_time */
        0x9b0a9815,
        0xf400a6b0,
        0x9ab8090b,
        0x061cf406,
-/* 0x00f8: intr_watchdog_next_time_set */
-/* 0x00fb: intr_watchdog_next_proc */
+/* 0x0108: intr_watchdog_next_time_set */
+/* 0x010b: intr_watchdog_next_proc */
        0x809b0980,
        0xe0b603e9,
        0x68e6b158,
        0xc61bf402,
-/* 0x010a: intr */
+/* 0x011a: intr */
        0x00f900f8,
        0x80f904bd,
        0xa0f990f9,
@@ -948,13 +954,13 @@ uint32_t nva3_pwr_code[] = {
        0xf40289c4,
        0x0080230b,
        0x58e7f09b,
-       0x98cb21f4,
+       0x98db21f4,
        0x96b09b09,
        0x110bf400,
        0xb63407f0,
        0x09d00604,
        0x8004bd00,
-/* 0x016e: intr_skip_watchdog */
+/* 0x017e: intr_skip_watchdog */
        0x89e49a09,
        0x0bf40800,
        0x8897f148,
@@ -967,22 +973,22 @@ uint32_t nva3_pwr_code[] = {
        0x48e7f1c0,
        0x53e3f14f,
        0x00d7f054,
-       0x02b921f5,
+       0x034221f5,
        0x07f1c0fc,
        0x04b604c0,
        0x000cd006,
-/* 0x01ae: intr_subintr_skip_fifo */
+/* 0x01be: intr_subintr_skip_fifo */
        0x07f104bd,
        0x04b60688,
        0x0009d006,
-/* 0x01ba: intr_skip_subintr */
+/* 0x01ca: intr_skip_subintr */
        0x89c404bd,
        0x070bf420,
        0xffbfa4f1,
-/* 0x01c4: intr_skip_pause */
+/* 0x01d4: intr_skip_pause */
        0xf44089c4,
        0xa4f1070b,
-/* 0x01ce: intr_skip_user0 */
+/* 0x01de: intr_skip_user0 */
        0x07f0ffbf,
        0x0604b604,
        0xbd0008d0,
@@ -993,596 +999,732 @@ uint32_t nva3_pwr_code[] = {
        0x90fca0fc,
        0x00fc80fc,
        0xf80032f4,
-/* 0x01f5: timer */
-       0x1032f401,
-       0xb003f898,
-       0x1cf40086,
-       0x03fe8051,
+/* 0x0205: ticks_from_ns */
+       0xf9c0f901,
+       0xcbd7f1b0,
+       0x00d3f000,
+       0x041321f5,
+       0x03e8ccec,
+       0xf400b4b0,
+       0xeeec120b,
+       0xd7f103e8,
+       0xd3f000cb,
+       0x1321f500,
+/* 0x022d: ticks_from_ns_quit */
+       0x02ceb904,
+       0xc0fcb0fc,
+/* 0x0236: ticks_from_us */
+       0xc0f900f8,
+       0xd7f1b0f9,
+       0xd3f000cb,
+       0x1321f500,
+       0x02ceb904,
+       0xf400b4b0,
+       0xe4bd050b,
+/* 0x0250: ticks_from_us_quit */
+       0xc0fcb0fc,
+/* 0x0256: ticks_to_us */
+       0xd7f100f8,
+       0xd3f000cb,
+       0xecedff00,
+/* 0x0262: timer */
+       0x90f900f8,
+       0x32f480f9,
+       0x03f89810,
+       0xf40086b0,
+       0x84bd651c,
        0xb63807f0,
        0x08d00604,
        0xf004bd00,
-       0x84b60887,
+       0x84b63487,
        0x0088cf06,
-       0xf40284f0,
-       0x87f0261b,
-       0x0684b634,
-       0xb80088cf,
-       0x0bf406e0,
-       0x06e8b809,
-/* 0x0233: timer_reset */
-       0xf01f1ef4,
-       0x04b63407,
-       0x000ed006,
-       0x0e8004bd,
-/* 0x0241: timer_enable */
-       0x0187f09a,
+       0xbb9a0998,
+       0xe9bb0298,
+       0x03fe8000,
+       0xb60887f0,
+       0x88cf0684,
+       0x0284f000,
+       0xf0261bf4,
+       0x84b63487,
+       0x0088cf06,
+       0xf406e0b8,
+       0xe8b8090b,
+       0x111cf406,
+/* 0x02b8: timer_reset */
+       0xb63407f0,
+       0x0ed00604,
+       0x8004bd00,
+/* 0x02c6: timer_enable */
+       0x87f09a0e,
+       0x3807f001,
+       0xd00604b6,
+       0x04bd0008,
+/* 0x02d4: timer_done */
+       0xfc1031f4,
+       0xf890fc80,
+/* 0x02dd: send_proc */
+       0xf980f900,
+       0x05e89890,
+       0xf004e998,
+       0x89b80486,
+       0x2a0bf406,
+       0x940398c4,
+       0x80b60488,
+       0x008ebb18,
+       0x8000fa98,
+       0x8d80008a,
+       0x028c8001,
+       0xb6038b80,
+       0x94f00190,
+       0x04e98007,
+/* 0x0317: send_done */
+       0xfc0231f4,
+       0xf880fc90,
+/* 0x031d: find */
+       0xf080f900,
+       0x31f45887,
+/* 0x0325: find_loop */
+       0x008a9801,
+       0xf406aeb8,
+       0x80b6100b,
+       0x6886b158,
+       0xf01bf402,
+/* 0x033b: find_done */
+       0xb90132f4,
+       0x80fc028e,
+/* 0x0342: send */
+       0x21f500f8,
+       0x01f4031d,
+/* 0x034b: recv */
+       0xf900f897,
+       0x9880f990,
+       0xe99805e8,
+       0x0132f404,
+       0xf40689b8,
+       0x89c43d0b,
+       0x0180b603,
+       0x800784f0,
+       0xea9805e8,
+       0xfef0f902,
+       0xf0f9018f,
+       0x9402efb9,
+       0xe9bb0499,
+       0x18e0b600,
+       0x9803eb98,
+       0xed9802ec,
+       0x00ee9801,
+       0xf0fca5f9,
+       0xf400f8fe,
+       0xf0fc0131,
+/* 0x0398: recv_done */
+       0x90fc80fc,
+/* 0x039e: init */
+       0x17f100f8,
+       0x14b60108,
+       0x0011cf06,
+       0x010911e7,
+       0xfe0814b6,
+       0x17f10014,
+       0x13f000e0,
+       0x1c07f000,
+       0xd00604b6,
+       0x04bd0001,
+       0xf0ff17f0,
+       0x04b61407,
+       0x0001d006,
+       0x17f004bd,
+       0x0015f102,
+       0x1007f008,
+       0xd00604b6,
+       0x04bd0001,
+       0x011a17f1,
+       0xfe0013f0,
+       0x31f40010,
+       0x0117f010,
        0xb63807f0,
-       0x08d00604,
-/* 0x024f: timer_done */
-       0xf404bd00,
-       0x00f81031,
-/* 0x0254: send_proc */
-       0x90f980f9,
-       0x9805e898,
-       0x86f004e9,
-       0x0689b804,
-       0xc42a0bf4,
-       0x88940398,
-       0x1880b604,
-       0x98008ebb,
-       0x8a8000fa,
-       0x018d8000,
-       0x80028c80,
-       0x90b6038b,
-       0x0794f001,
-       0xf404e980,
-/* 0x028e: send_done */
-       0x90fc0231,
-       0x00f880fc,
-/* 0x0294: find */
-       0x87f080f9,
-       0x0131f458,
-/* 0x029c: find_loop */
-       0xb8008a98,
-       0x0bf406ae,
-       0x5880b610,
-       0x026886b1,
-       0xf4f01bf4,
-/* 0x02b2: find_done */
-       0x8eb90132,
-       0xf880fc02,
-/* 0x02b9: send */
-       0x9421f500,
-       0x9701f402,
-/* 0x02c2: recv */
-       0xe89800f8,
-       0x04e99805,
-       0xb80132f4,
-       0x0bf40689,
-       0x0389c43d,
-       0xf00180b6,
-       0xe8800784,
-       0x02ea9805,
-       0x8ffef0f9,
-       0xb9f0f901,
-       0x999402ef,
-       0x00e9bb04,
-       0x9818e0b6,
-       0xec9803eb,
-       0x01ed9802,
-       0xf900ee98,
-       0xfef0fca5,
-       0x31f400f8,
-/* 0x030b: recv_done */
-       0xf8f0fc01,
-/* 0x030d: init */
-       0x0817f100,
-       0x0614b601,
-       0xe70011cf,
-       0xb6010911,
-       0x14fe0814,
-       0xe017f100,
-       0x0013f000,
-       0xb61c07f0,
        0x01d00604,
        0xf004bd00,
-       0x07f0ff17,
-       0x0604b614,
-       0xbd0001d0,
-       0x0217f004,
-       0x080015f1,
-       0xb61007f0,
-       0x01d00604,
-       0xf104bd00,
-       0xf0010a17,
-       0x10fe0013,
-       0x1031f400,
-       0xf00117f0,
-       0x04b63807,
-       0x0001d006,
-       0xf7f004bd,
-/* 0x0371: init_proc */
-       0x01f19858,
-       0xf40016b0,
-       0x15f9fa0b,
-       0xf458f0b6,
-/* 0x0382: host_send */
-       0x17f1f20e,
-       0x14b604b0,
-       0x0011cf06,
-       0x04a027f1,
-       0xcf0624b6,
-       0x12b80022,
-       0x320bf406,
-       0x94071ec4,
-       0xe0b704ee,
-       0xeb980270,
-       0x02ec9803,
-       0x9801ed98,
-       0x21f500ee,
-       0x10b602b9,
-       0x0f1ec401,
-       0x04b007f1,
-       0xd00604b6,
-       0x04bd000e,
-/* 0x03cb: host_send_done */
-       0xf8ba0ef4,
-/* 0x03cd: host_recv */
-       0x4917f100,
-       0x5413f14e,
-       0x06e1b852,
-/* 0x03db: host_recv_wait */
-       0xf1aa0bf4,
-       0xb604cc17,
-       0x11cf0614,
-       0xc827f100,
-       0x0624b604,
-       0xf00022cf,
-       0x12b80816,
-       0xe60bf406,
-       0xb60723c4,
-       0x30b70434,
-       0x3b8002f0,
-       0x023c8003,
-       0x80013d80,
-       0x20b6003e,
-       0x0f24f001,
-       0x04c807f1,
+/* 0x0402: init_proc */
+       0xf19858f7,
+       0x0016b001,
+       0xf9fa0bf4,
+       0x58f0b615,
+/* 0x0413: mulu32_32_64 */
+       0xf9f20ef4,
+       0xf920f910,
+       0x9540f930,
+       0xd29510e1,
+       0xbdc4bd10,
+       0xc0edffb4,
+       0xb9301dff,
+       0x34f10234,
+       0x34b6ffff,
+       0x1045b610,
+       0xbb00c3bb,
+       0xe2ff01b4,
+       0x0234b930,
+       0xffff34f1,
+       0xb61034b6,
+       0xc3bb1045,
+       0x01b4bb00,
+       0xbb3012ff,
+       0x40fc00b3,
+       0x20fc30fc,
+       0x00f810fc,
+/* 0x0464: host_send */
+       0x04b017f1,
+       0xcf0614b6,
+       0x27f10011,
+       0x24b604a0,
+       0x0022cf06,
+       0xf40612b8,
+       0x1ec4320b,
+       0x04ee9407,
+       0x0270e0b7,
+       0x9803eb98,
+       0xed9802ec,
+       0x00ee9801,
+       0x034221f5,
+       0xc40110b6,
+       0x07f10f1e,
+       0x04b604b0,
+       0x000ed006,
+       0x0ef404bd,
+/* 0x04ad: host_send_done */
+/* 0x04af: host_recv */
+       0xf100f8ba,
+       0xf14e4917,
+       0xb8525413,
+       0x0bf406e1,
+/* 0x04bd: host_recv_wait */
+       0xcc17f1aa,
+       0x0614b604,
+       0xf10011cf,
+       0xb604c827,
+       0x22cf0624,
+       0x0816f000,
+       0xf40612b8,
+       0x23c4e60b,
+       0x0434b607,
+       0x02f030b7,
+       0x80033b80,
+       0x3d80023c,
+       0x003e8001,
+       0xf00120b6,
+       0x07f10f24,
+       0x04b604c8,
+       0x0002d006,
+       0x27f004bd,
+       0x0007f040,
        0xd00604b6,
        0x04bd0002,
-       0xf04027f0,
-       0x04b60007,
-       0x0002d006,
-       0x00f804bd,
-/* 0x0430: host_init */
-       0x008017f1,
-       0xf11014b6,
-       0xf1027015,
-       0xb604d007,
-       0x01d00604,
-       0xf104bd00,
-       0xb6008017,
-       0x15f11014,
-       0x07f102f0,
-       0x04b604dc,
-       0x0001d006,
-       0x17f004bd,
-       0xc407f101,
+/* 0x0512: host_init */
+       0x17f100f8,
+       0x14b60080,
+       0x7015f110,
+       0xd007f102,
        0x0604b604,
        0xbd0001d0,
-/* 0x046f: memx_func_enter */
-       0xf000f804,
+       0x8017f104,
+       0x1014b600,
+       0x02f015f1,
+       0x04dc07f1,
+       0xd00604b6,
+       0x04bd0001,
+       0xf10117f0,
+       0xb604c407,
+       0x01d00604,
+       0xf804bd00,
+/* 0x0551: memx_func_enter */
+       0x1087f100,
+       0x028eb916,
+       0xb90421f4,
+       0x67f102d7,
+       0x63f1fffc,
+       0x76fdffff,
+       0x0267f104,
+       0x0576fd00,
+       0x70f980f9,
+       0xe0fcd0fc,
+       0xf03f21f4,
        0x07f10467,
        0x04b607e0,
        0x0006d006,
-/* 0x047e: memx_func_enter_wait */
+/* 0x058a: memx_func_enter_wait */
        0x67f104bd,
        0x64b607c0,
        0x0066cf06,
        0xf40464f0,
-       0x1698f30b,
-       0x0410b600,
-/* 0x0496: memx_func_leave */
-       0x67f000f8,
-       0xe407f104,
-       0x0604b607,
-       0xbd0006d0,
-/* 0x04a5: memx_func_leave_wait */
-       0xc067f104,
+       0x67f0f30b,
+       0x0664b62c,
+       0x800066cf,
+       0x00f8ee06,
+/* 0x05a8: memx_func_leave */
+       0xb62c67f0,
+       0x66cf0664,
+       0xef068000,
+       0xf10467f0,
+       0xb607e407,
+       0x06d00604,
+/* 0x05c3: memx_func_leave_wait */
+       0xf104bd00,
+       0xb607c067,
+       0x66cf0664,
+       0x0464f000,
+       0xf1f31bf4,
+       0xb9161087,
+       0x21f4028e,
+       0x02d7b904,
+       0xffcc67f1,
+       0xffff63f1,
+       0xf90476fd,
+       0xfc70f980,
+       0xf4e0fcd0,
+       0x00f83f21,
+/* 0x05f8: memx_func_wait_vblank */
+       0xb0001698,
+       0x0bf40066,
+       0x0166b013,
+       0xf4060bf4,
+/* 0x060a: memx_func_wait_vblank_head1 */
+       0x77f12e0e,
+       0x0ef40020,
+/* 0x0611: memx_func_wait_vblank_head0 */
+       0x0877f107,
+/* 0x0615: memx_func_wait_vblank_0 */
+       0xc467f100,
        0x0664b607,
-       0xf00066cf,
-       0x1bf40464,
-/* 0x04b7: memx_func_wr32 */
-       0x9800f8f3,
-       0x15980016,
-       0x0810b601,
-       0x50f960f9,
-       0xe0fcd0fc,
-       0xb63f21f4,
-       0x1bf40242,
-/* 0x04d3: memx_func_wait */
-       0xf000f8e9,
-       0x84b62c87,
-       0x0088cf06,
-       0x98001e98,
-       0x1c98011d,
-       0x031b9802,
-       0xf41010b6,
-       0x00f89c21,
-/* 0x04f0: memx_func_delay */
-       0xb6001e98,
-       0x21f40410,
-/* 0x04fb: memx_exec */
-       0xf900f87f,
-       0xb9d0f9e0,
-       0xb2b902c1,
-/* 0x0505: memx_exec_next */
-       0x00139802,
-       0x950410b6,
-       0x30f01034,
-       0xde35980c,
-       0x12b855f9,
-       0xec1ef406,
-       0xe0fcd0fc,
-       0x02b921f5,
-/* 0x0526: memx_info */
-       0xc7f100f8,
-       0xb7f103ac,
-       0x21f50800,
-       0x00f802b9,
-/* 0x0534: memx_recv */
-       0xf401d6b0,
-       0xd6b0c40b,
-       0xe90bf400,
-/* 0x0542: memx_init */
-       0x00f800f8,
-/* 0x0544: perf_recv */
-/* 0x0546: perf_init */
+       0xfd0066cf,
+       0x1bf40467,
+/* 0x0625: memx_func_wait_vblank_1 */
+       0xc467f1f3,
+       0x0664b607,
+       0xfd0066cf,
+       0x0bf40467,
+/* 0x0635: memx_func_wait_vblank_fini */
+       0x0410b6f3,
+/* 0x063a: memx_func_wr32 */
+       0x169800f8,
+       0x01159800,
+       0xf90810b6,
+       0xfc50f960,
+       0xf4e0fcd0,
+       0x42b63f21,
+       0xe91bf402,
+/* 0x0656: memx_func_wait */
+       0x87f000f8,
+       0x0684b62c,
+       0x980088cf,
+       0x1d98001e,
+       0x021c9801,
+       0xb6031b98,
+       0x21f41010,
+/* 0x0673: memx_func_delay */
+       0x9800f8a4,
+       0x10b6001e,
+       0x7f21f404,
+/* 0x067e: memx_exec */
+       0xe0f900f8,
+       0xc1b9d0f9,
+       0x02b2b902,
+/* 0x0688: memx_exec_next */
+       0xb6001398,
+       0x34e70410,
+       0x33e701f0,
+       0x32b601e0,
+       0x0c30f001,
+       0xf9de3598,
+       0x0612b855,
+       0x98e41ef4,
+       0x0c98ee0b,
+       0x02cbbbef,
+       0x07c4b7f1,
+       0xcf06b4b6,
+       0xd0fc00bb,
+       0x21f5e0fc,
+       0x00f80342,
+/* 0x06c4: memx_info */
+       0x03c0c7f1,
+       0x0800b7f1,
+       0x034221f5,
+/* 0x06d2: memx_recv */
+       0xd6b000f8,
+       0xa90bf401,
+       0xf400d6b0,
+       0x00f8e90b,
+/* 0x06e0: memx_init */
+/* 0x06e2: perf_recv */
        0x00f800f8,
-/* 0x0548: i2c_drive_scl */
-       0xf40036b0,
-       0x07f1110b,
-       0x04b607e0,
-       0x0001d006,
-       0x00f804bd,
-/* 0x055c: i2c_drive_scl_lo */
-       0x07e407f1,
-       0xd00604b6,
-       0x04bd0001,
-/* 0x056a: i2c_drive_sda */
+/* 0x06e4: perf_init */
+/* 0x06e6: i2c_drive_scl */
        0x36b000f8,
        0x110bf400,
        0x07e007f1,
        0xd00604b6,
-       0x04bd0002,
-/* 0x057e: i2c_drive_sda_lo */
+       0x04bd0001,
+/* 0x06fa: i2c_drive_scl_lo */
        0x07f100f8,
        0x04b607e4,
+       0x0001d006,
+       0x00f804bd,
+/* 0x0708: i2c_drive_sda */
+       0xf40036b0,
+       0x07f1110b,
+       0x04b607e0,
        0x0002d006,
        0x00f804bd,
-/* 0x058c: i2c_sense_scl */
-       0xf10132f4,
-       0xb607c437,
-       0x33cf0634,
-       0x0431fd00,
-       0xf4060bf4,
-/* 0x05a2: i2c_sense_scl_done */
-       0x00f80131,
-/* 0x05a4: i2c_sense_sda */
-       0xf10132f4,
-       0xb607c437,
-       0x33cf0634,
-       0x0432fd00,
-       0xf4060bf4,
-/* 0x05ba: i2c_sense_sda_done */
-       0x00f80131,
-/* 0x05bc: i2c_raise_scl */
-       0x47f140f9,
-       0x37f00898,
-       0x4821f501,
-/* 0x05c9: i2c_raise_scl_wait */
-       0xe8e7f105,
-       0x7f21f403,
-       0x058c21f5,
-       0xb60901f4,
-       0x1bf40142,
-/* 0x05dd: i2c_raise_scl_done */
-       0xf840fcef,
-/* 0x05e1: i2c_start */
-       0x8c21f500,
-       0x0d11f405,
-       0x05a421f5,
-       0xf40611f4,
-/* 0x05f2: i2c_start_rep */
-       0x37f0300e,
-       0x4821f500,
-       0x0137f005,
-       0x056a21f5,
-       0xb60076bb,
-       0x50f90465,
-       0xbb046594,
-       0x50bd0256,
-       0xfc0475fd,
-       0xbc21f550,
-       0x0464b605,
-/* 0x061f: i2c_start_send */
-       0xf01f11f4,
+/* 0x071c: i2c_drive_sda_lo */
+       0x07e407f1,
+       0xd00604b6,
+       0x04bd0002,
+/* 0x072a: i2c_sense_scl */
+       0x32f400f8,
+       0xc437f101,
+       0x0634b607,
+       0xfd0033cf,
+       0x0bf40431,
+       0x0131f406,
+/* 0x0740: i2c_sense_scl_done */
+/* 0x0742: i2c_sense_sda */
+       0x32f400f8,
+       0xc437f101,
+       0x0634b607,
+       0xfd0033cf,
+       0x0bf40432,
+       0x0131f406,
+/* 0x0758: i2c_sense_sda_done */
+/* 0x075a: i2c_raise_scl */
+       0x40f900f8,
+       0x089847f1,
+       0xf50137f0,
+/* 0x0767: i2c_raise_scl_wait */
+       0xf106e621,
+       0xf403e8e7,
+       0x21f57f21,
+       0x01f4072a,
+       0x0142b609,
+/* 0x077b: i2c_raise_scl_done */
+       0xfcef1bf4,
+/* 0x077f: i2c_start */
+       0xf500f840,
+       0xf4072a21,
+       0x21f50d11,
+       0x11f40742,
+       0x300ef406,
+/* 0x0790: i2c_start_rep */
+       0xf50037f0,
+       0xf006e621,
+       0x21f50137,
+       0x76bb0708,
+       0x0465b600,
+       0x659450f9,
+       0x0256bb04,
+       0x75fd50bd,
+       0xf550fc04,
+       0xb6075a21,
+       0x11f40464,
+/* 0x07bd: i2c_start_send */
+       0x0037f01f,
+       0x070821f5,
+       0x1388e7f1,
+       0xf07f21f4,
        0x21f50037,
-       0xe7f1056a,
+       0xe7f106e6,
        0x21f41388,
-       0x0037f07f,
-       0x054821f5,
-       0x1388e7f1,
-/* 0x063b: i2c_start_out */
-       0xf87f21f4,
-/* 0x063d: i2c_stop */
-       0x0037f000,
-       0x054821f5,
-       0xf50037f0,
-       0xf1056a21,
-       0xf403e8e7,
-       0x37f07f21,
-       0x4821f501,
-       0x88e7f105,
-       0x7f21f413,
+/* 0x07d9: i2c_start_out */
+/* 0x07db: i2c_stop */
+       0xf000f87f,
+       0x21f50037,
+       0x37f006e6,
+       0x0821f500,
+       0xe8e7f107,
+       0x7f21f403,
        0xf50137f0,
-       0xf1056a21,
+       0xf106e621,
        0xf41388e7,
-       0x00f87f21,
-/* 0x0670: i2c_bitw */
-       0x056a21f5,
-       0x03e8e7f1,
-       0xbb7f21f4,
-       0x65b60076,
-       0x9450f904,
-       0x56bb0465,
-       0xfd50bd02,
-       0x50fc0475,
-       0x05bc21f5,
-       0xf40464b6,
-       0xe7f11811,
-       0x21f41388,
-       0x0037f07f,
-       0x054821f5,
-       0x1388e7f1,
-/* 0x06af: i2c_bitw_out */
-       0xf87f21f4,
-/* 0x06b1: i2c_bitr */
-       0x0137f000,
-       0x056a21f5,
-       0x03e8e7f1,
-       0xbb7f21f4,
-       0x65b60076,
-       0x9450f904,
-       0x56bb0465,
-       0xfd50bd02,
-       0x50fc0475,
-       0x05bc21f5,
-       0xf40464b6,
-       0x21f51b11,
-       0x37f005a4,
-       0x4821f500,
-       0x88e7f105,
+       0x37f07f21,
+       0x0821f501,
+       0x88e7f107,
        0x7f21f413,
-       0xf4013cf0,
-/* 0x06f6: i2c_bitr_done */
-       0x00f80131,
-/* 0x06f8: i2c_get_byte */
-       0xf00057f0,
-/* 0x06fe: i2c_get_byte_next */
-       0x54b60847,
-       0x0076bb01,
+/* 0x080e: i2c_bitw */
+       0x21f500f8,
+       0xe7f10708,
+       0x21f403e8,
+       0x0076bb7f,
        0xf90465b6,
        0x04659450,
        0xbd0256bb,
        0x0475fd50,
        0x21f550fc,
-       0x64b606b1,
-       0x2b11f404,
-       0xb60553fd,
-       0x1bf40142,
-       0x0137f0d8,
-       0xb60076bb,
-       0x50f90465,
-       0xbb046594,
-       0x50bd0256,
-       0xfc0475fd,
-       0x7021f550,
-       0x0464b606,
-/* 0x0748: i2c_get_byte_done */
-/* 0x074a: i2c_put_byte */
-       0x47f000f8,
-/* 0x074d: i2c_put_byte_next */
-       0x0142b608,
-       0xbb3854ff,
+       0x64b6075a,
+       0x1811f404,
+       0x1388e7f1,
+       0xf07f21f4,
+       0x21f50037,
+       0xe7f106e6,
+       0x21f41388,
+/* 0x084d: i2c_bitw_out */
+/* 0x084f: i2c_bitr */
+       0xf000f87f,
+       0x21f50137,
+       0xe7f10708,
+       0x21f403e8,
+       0x0076bb7f,
+       0xf90465b6,
+       0x04659450,
+       0xbd0256bb,
+       0x0475fd50,
+       0x21f550fc,
+       0x64b6075a,
+       0x1b11f404,
+       0x074221f5,
+       0xf50037f0,
+       0xf106e621,
+       0xf41388e7,
+       0x3cf07f21,
+       0x0131f401,
+/* 0x0894: i2c_bitr_done */
+/* 0x0896: i2c_get_byte */
+       0x57f000f8,
+       0x0847f000,
+/* 0x089c: i2c_get_byte_next */
+       0xbb0154b6,
        0x65b60076,
        0x9450f904,
        0x56bb0465,
        0xfd50bd02,
        0x50fc0475,
-       0x067021f5,
+       0x084f21f5,
        0xf40464b6,
-       0x46b03411,
-       0xd81bf400,
-       0xb60076bb,
-       0x50f90465,
-       0xbb046594,
-       0x50bd0256,
-       0xfc0475fd,
-       0xb121f550,
-       0x0464b606,
-       0xbb0f11f4,
-       0x36b00076,
-       0x061bf401,
-/* 0x07a3: i2c_put_byte_done */
-       0xf80132f4,
-/* 0x07a5: i2c_addr */
-       0x0076bb00,
+       0x53fd2b11,
+       0x0142b605,
+       0xf0d81bf4,
+       0x76bb0137,
+       0x0465b600,
+       0x659450f9,
+       0x0256bb04,
+       0x75fd50bd,
+       0xf550fc04,
+       0xb6080e21,
+/* 0x08e6: i2c_get_byte_done */
+       0x00f80464,
+/* 0x08e8: i2c_put_byte */
+/* 0x08eb: i2c_put_byte_next */
+       0xb60847f0,
+       0x54ff0142,
+       0x0076bb38,
        0xf90465b6,
        0x04659450,
        0xbd0256bb,
        0x0475fd50,
        0x21f550fc,
-       0x64b605e1,
-       0x2911f404,
-       0x012ec3e7,
-       0xfd0134b6,
-       0x76bb0553,
+       0x64b6080e,
+       0x3411f404,
+       0xf40046b0,
+       0x76bbd81b,
        0x0465b600,
        0x659450f9,
        0x0256bb04,
        0x75fd50bd,
        0xf550fc04,
-       0xb6074a21,
-/* 0x07ea: i2c_addr_done */
-       0x00f80464,
-/* 0x07ec: i2c_acquire_addr */
-       0xb6f8cec7,
-       0xe0b702e4,
-       0xee980bfc,
-/* 0x07fb: i2c_acquire */
-       0xf500f800,
-       0xf407ec21,
-       0xd9f00421,
-       0x3f21f403,
-/* 0x080a: i2c_release */
-       0x21f500f8,
-       0x21f407ec,
-       0x03daf004,
-       0xf83f21f4,
-/* 0x0819: i2c_recv */
-       0x0132f400,
-       0xb6f8c1c7,
-       0x16b00214,
-       0x3a1ff528,
-       0xd413a001,
-       0x0032980b,
-       0x0bac13a0,
-       0xf4003198,
-       0xd0f90231,
-       0xd0f9e0f9,
-       0x000067f1,
-       0x100063f1,
-       0xbb016792,
+       0xb6084f21,
+       0x11f40464,
+       0x0076bb0f,
+       0xf40136b0,
+       0x32f4061b,
+/* 0x0941: i2c_put_byte_done */
+/* 0x0943: i2c_addr */
+       0xbb00f801,
        0x65b60076,
        0x9450f904,
        0x56bb0465,
        0xfd50bd02,
        0x50fc0475,
-       0x07fb21f5,
-       0xfc0464b6,
-       0x00d6b0d0,
-       0x00b31bf5,
-       0xbb0057f0,
-       0x65b60076,
-       0x9450f904,
-       0x56bb0465,
-       0xfd50bd02,
-       0x50fc0475,
-       0x07a521f5,
-       0xf50464b6,
-       0xc700d011,
-       0x76bbe0c5,
-       0x0465b600,
-       0x659450f9,
-       0x0256bb04,
-       0x75fd50bd,
-       0xf550fc04,
-       0xb6074a21,
-       0x11f50464,
-       0x57f000ad,
+       0x077f21f5,
+       0xf40464b6,
+       0xc3e72911,
+       0x34b6012e,
+       0x0553fd01,
+       0xb60076bb,
+       0x50f90465,
+       0xbb046594,
+       0x50bd0256,
+       0xfc0475fd,
+       0xe821f550,
+       0x0464b608,
+/* 0x0988: i2c_addr_done */
+/* 0x098a: i2c_acquire_addr */
+       0xcec700f8,
+       0x02e4b6f8,
+       0x0c10e0b7,
+       0xf800ee98,
+/* 0x0999: i2c_acquire */
+       0x8a21f500,
+       0x0421f409,
+       0xf403d9f0,
+       0x00f83f21,
+/* 0x09a8: i2c_release */
+       0x098a21f5,
+       0xf00421f4,
+       0x21f403da,
+/* 0x09b7: i2c_recv */
+       0xf400f83f,
+       0xc1c70132,
+       0x0214b6f8,
+       0xf52816b0,
+       0xa0013a1f,
+       0x980be813,
+       0x13a00032,
+       0x31980bc0,
+       0x0231f400,
+       0xe0f9d0f9,
+       0x67f1d0f9,
+       0x63f10000,
+       0x67921000,
        0x0076bb01,
        0xf90465b6,
        0x04659450,
        0xbd0256bb,
        0x0475fd50,
        0x21f550fc,
-       0x64b607a5,
-       0x8a11f504,
+       0x64b60999,
+       0xb0d0fc04,
+       0x1bf500d6,
+       0x57f000b3,
        0x0076bb00,
        0xf90465b6,
        0x04659450,
        0xbd0256bb,
        0x0475fd50,
        0x21f550fc,
-       0x64b606f8,
-       0x6a11f404,
-       0xbbe05bcb,
+       0x64b60943,
+       0xd011f504,
+       0xe0c5c700,
+       0xb60076bb,
+       0x50f90465,
+       0xbb046594,
+       0x50bd0256,
+       0xfc0475fd,
+       0xe821f550,
+       0x0464b608,
+       0x00ad11f5,
+       0xbb0157f0,
        0x65b60076,
        0x9450f904,
        0x56bb0465,
        0xfd50bd02,
        0x50fc0475,
-       0x063d21f5,
-       0xb90464b6,
-       0x74bd025b,
-/* 0x091f: i2c_recv_not_rd08 */
-       0xb0430ef4,
-       0x1bf401d6,
-       0x0057f03d,
-       0x07a521f5,
-       0xc73311f4,
-       0x21f5e0c5,
-       0x11f4074a,
-       0x0057f029,
-       0x07a521f5,
-       0xc71f11f4,
-       0x21f5e0b5,
-       0x11f4074a,
-       0x3d21f515,
-       0xc774bd06,
-       0x1bf408c5,
-       0x0232f409,
-/* 0x095f: i2c_recv_not_wr08 */
-/* 0x095f: i2c_recv_done */
-       0xc7030ef4,
-       0x21f5f8ce,
-       0xe0fc080a,
-       0x12f4d0fc,
-       0x027cb90a,
-       0x02b921f5,
-/* 0x0974: i2c_recv_exit */
-/* 0x0976: i2c_init */
-       0x00f800f8,
-/* 0x0978: test_recv */
-       0x05d817f1,
+       0x094321f5,
+       0xf50464b6,
+       0xbb008a11,
+       0x65b60076,
+       0x9450f904,
+       0x56bb0465,
+       0xfd50bd02,
+       0x50fc0475,
+       0x089621f5,
+       0xf40464b6,
+       0x5bcb6a11,
+       0x0076bbe0,
+       0xf90465b6,
+       0x04659450,
+       0xbd0256bb,
+       0x0475fd50,
+       0x21f550fc,
+       0x64b607db,
+       0x025bb904,
+       0x0ef474bd,
+/* 0x0abd: i2c_recv_not_rd08 */
+       0x01d6b043,
+       0xf03d1bf4,
+       0x21f50057,
+       0x11f40943,
+       0xe0c5c733,
+       0x08e821f5,
+       0xf02911f4,
+       0x21f50057,
+       0x11f40943,
+       0xe0b5c71f,
+       0x08e821f5,
+       0xf51511f4,
+       0xbd07db21,
+       0x08c5c774,
+       0xf4091bf4,
+       0x0ef40232,
+/* 0x0afd: i2c_recv_not_wr08 */
+/* 0x0afd: i2c_recv_done */
+       0xf8cec703,
+       0x09a821f5,
+       0xd0fce0fc,
+       0xb90a12f4,
+       0x21f5027c,
+/* 0x0b12: i2c_recv_exit */
+       0x00f80342,
+/* 0x0b14: i2c_init */
+/* 0x0b16: test_recv */
+       0x17f100f8,
+       0x14b605d8,
+       0x0011cf06,
+       0xf10110b6,
+       0xb605d807,
+       0x01d00604,
+       0xf104bd00,
+       0xf1d900e7,
+       0xf5134fe3,
+       0xf8026221,
+/* 0x0b3d: test_init */
+       0x00e7f100,
+       0x6221f508,
+/* 0x0b47: idle_recv */
+       0xf800f802,
+/* 0x0b49: idle */
+       0x0031f400,
+       0x05d417f1,
        0xcf0614b6,
        0x10b60011,
-       0xd807f101,
+       0xd407f101,
        0x0604b605,
        0xbd0001d0,
-       0x00e7f104,
-       0x4fe3f1d9,
-       0xf521f513,
-/* 0x099f: test_init */
-       0xf100f801,
-       0xf50800e7,
-       0xf801f521,
-/* 0x09a9: idle_recv */
-/* 0x09ab: idle */
-       0xf400f800,
-       0x17f10031,
-       0x14b605d4,
-       0x0011cf06,
-       0xf10110b6,
-       0xb605d407,
-       0x01d00604,
-/* 0x09c7: idle_loop */
-       0xf004bd00,
-       0x32f45817,
-/* 0x09cd: idle_proc */
-/* 0x09cd: idle_proc_exec */
-       0xb910f902,
-       0x21f5021e,
-       0x10fc02c2,
-       0xf40911f4,
-       0x0ef40231,
-/* 0x09e1: idle_proc_next */
-       0x5810b6ef,
-       0xf4061fb8,
-       0x02f4e61b,
-       0x0028f4dd,
-       0x00bb0ef4,
+/* 0x0b65: idle_loop */
+       0x5817f004,
+/* 0x0b6b: idle_proc */
+/* 0x0b6b: idle_proc_exec */
+       0xf90232f4,
+       0x021eb910,
+       0x034b21f5,
+       0x11f410fc,
+       0x0231f409,
+/* 0x0b7f: idle_proc_next */
+       0xb6ef0ef4,
+       0x1fb85810,
+       0xe61bf406,
+       0xf4dd02f4,
+       0x0ef40028,
+       0x000000bb,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
        0x00000000,
        0x00000000,
        0x00000000,
index 48f79434a4491f30c61f95755d43c37097f73249..21bf8cc7618f8459ed43e1699ee28278400a4ce5 100644 (file)
@@ -23,6 +23,7 @@
  */
 
 #define NVKM_PPWR_CHIPSET GF100
+#define HW_TICKS_PER_US 203 // should be 202.5
 
 //#define NVKM_FALCON_PC24
 //#define NVKM_FALCON_UNSHIFTED_IO
@@ -34,6 +35,7 @@
 .section #nvc0_pwr_data
 #define INCLUDE_PROC
 #include "kernel.fuc"
+#include "arith.fuc"
 #include "host.fuc"
 #include "memx.fuc"
 #include "perf.fuc"
@@ -44,6 +46,7 @@
 
 #define INCLUDE_DATA
 #include "kernel.fuc"
+#include "arith.fuc"
 #include "host.fuc"
 #include "memx.fuc"
 #include "perf.fuc"
@@ -56,6 +59,7 @@
 .section #nvc0_pwr_code
 #define INCLUDE_CODE
 #include "kernel.fuc"
+#include "arith.fuc"
 #include "host.fuc"
 #include "memx.fuc"
 #include "perf.fuc"
index 0773ff0e3dc34b1cd1a22dc2381f0dac4ed7e0d6..ca30fa4011b55907bb1f5d7b207b3291689f55e2 100644 (file)
@@ -24,8 +24,8 @@ uint32_t nvc0_pwr_data[] = {
        0x00000000,
 /* 0x0058: proc_list_head */
        0x54534f48,
-       0x00000430,
-       0x000003cd,
+       0x00000512,
+       0x000004af,
        0x00000000,
        0x00000000,
        0x00000000,
@@ -46,8 +46,8 @@ uint32_t nvc0_pwr_data[] = {
        0x00000000,
        0x00000000,
        0x584d454d,
-       0x00000542,
-       0x00000534,
+       0x0000074b,
+       0x0000073d,
        0x00000000,
        0x00000000,
        0x00000000,
@@ -68,8 +68,8 @@ uint32_t nvc0_pwr_data[] = {
        0x00000000,
        0x00000000,
        0x46524550,
-       0x00000546,
-       0x00000544,
+       0x0000074f,
+       0x0000074d,
        0x00000000,
        0x00000000,
        0x00000000,
@@ -90,8 +90,8 @@ uint32_t nvc0_pwr_data[] = {
        0x00000000,
        0x00000000,
        0x5f433249,
-       0x00000976,
-       0x00000819,
+       0x00000b7f,
+       0x00000a22,
        0x00000000,
        0x00000000,
        0x00000000,
@@ -112,8 +112,8 @@ uint32_t nvc0_pwr_data[] = {
        0x00000000,
        0x00000000,
        0x54534554,
-       0x0000099f,
-       0x00000978,
+       0x00000ba8,
+       0x00000b81,
        0x00000000,
        0x00000000,
        0x00000000,
@@ -134,8 +134,8 @@ uint32_t nvc0_pwr_data[] = {
        0x00000000,
        0x00000000,
        0x454c4449,
-       0x000009ab,
-       0x000009a9,
+       0x00000bb4,
+       0x00000bb2,
        0x00000000,
        0x00000000,
        0x00000000,
@@ -227,25 +227,31 @@ uint32_t nvc0_pwr_data[] = {
        0x00000000,
        0x00000000,
 /* 0x0370: memx_func_head */
-       0x00010000,
-       0x00000000,
-       0x0000046f,
-/* 0x037c: memx_func_next */
        0x00000001,
        0x00000000,
-       0x00000496,
+       0x00000551,
+/* 0x037c: memx_func_next */
        0x00000002,
+       0x00000000,
+       0x000005db,
+       0x00000003,
        0x00000002,
-       0x000004b7,
-       0x00040003,
+       0x000006a5,
+       0x00040004,
+       0x00000000,
+       0x000006c1,
+       0x00010005,
+       0x00000000,
+       0x000006de,
+       0x00010006,
        0x00000000,
-       0x000004d3,
-       0x00010004,
+       0x00000663,
+/* 0x03b8: memx_func_tail */
+/* 0x03b8: memx_ts_start */
        0x00000000,
-       0x000004f0,
-/* 0x03ac: memx_func_tail */
-/* 0x03ac: memx_data_head */
+/* 0x03bc: memx_ts_end */
        0x00000000,
+/* 0x03c0: memx_data_head */
        0x00000000,
        0x00000000,
        0x00000000,
@@ -757,8 +763,9 @@ uint32_t nvc0_pwr_data[] = {
        0x00000000,
        0x00000000,
        0x00000000,
-/* 0x0bac: memx_data_tail */
-/* 0x0bac: i2c_scl_map */
+       0x00000000,
+/* 0x0bc0: memx_data_tail */
+/* 0x0bc0: i2c_scl_map */
        0x00001000,
        0x00004000,
        0x00010000,
@@ -769,7 +776,7 @@ uint32_t nvc0_pwr_data[] = {
        0x01000000,
        0x04000000,
        0x10000000,
-/* 0x0bd4: i2c_sda_map */
+/* 0x0be8: i2c_sda_map */
        0x00002000,
        0x00008000,
        0x00020000,
@@ -780,7 +787,7 @@ uint32_t nvc0_pwr_data[] = {
        0x02000000,
        0x08000000,
        0x20000000,
-/* 0x0bfc: i2c_ctrl */
+/* 0x0c10: i2c_ctrl */
        0x0000e138,
        0x0000e150,
        0x0000e168,
@@ -841,15 +848,10 @@ uint32_t nvc0_pwr_data[] = {
        0x00000000,
        0x00000000,
        0x00000000,
-       0x00000000,
-       0x00000000,
-       0x00000000,
-       0x00000000,
-       0x00000000,
 };
 
 uint32_t nvc0_pwr_code[] = {
-       0x030d0ef5,
+       0x039e0ef5,
 /* 0x0004: rd32 */
        0x07a007f1,
        0xd00604b6,
@@ -885,19 +887,22 @@ uint32_t nvc0_pwr_code[] = {
        0xd4f100dd,
        0x1bf47000,
 /* 0x007f: nsec */
-       0xf000f8f2,
+       0xf900f8f2,
+       0xf080f990,
        0x84b62c87,
        0x0088cf06,
-/* 0x0088: nsec_loop */
+/* 0x008c: nsec_loop */
        0xb62c97f0,
        0x99cf0694,
        0x0298bb00,
        0xf4069eb8,
-       0x00f8f11e,
-/* 0x009c: wait */
+       0x80fcf11e,
+       0x00f890fc,
+/* 0x00a4: wait */
+       0x80f990f9,
        0xb62c87f0,
        0x88cf0684,
-/* 0x00a5: wait_loop */
+/* 0x00b1: wait_loop */
        0x02eeb900,
        0xb90421f4,
        0xadfd02da,
@@ -907,28 +912,29 @@ uint32_t nvc0_pwr_code[] = {
        0x0099cf06,
        0xb80298bb,
        0x1ef4069b,
-/* 0x00c9: wait_done */
-/* 0x00cb: intr_watchdog */
-       0x9800f8df,
+/* 0x00d5: wait_done */
+       0xfc80fcdf,
+/* 0x00db: intr_watchdog */
+       0x9800f890,
        0x96b003e9,
        0x2a0bf400,
        0xbb9a0a98,
        0x1cf4029a,
        0x01d7f00f,
-       0x025421f5,
+       0x02dd21f5,
        0x0ef494bd,
-/* 0x00e9: intr_watchdog_next_time */
+/* 0x00f9: intr_watchdog_next_time */
        0x9b0a9815,
        0xf400a6b0,
        0x9ab8090b,
        0x061cf406,
-/* 0x00f8: intr_watchdog_next_time_set */
-/* 0x00fb: intr_watchdog_next_proc */
+/* 0x0108: intr_watchdog_next_time_set */
+/* 0x010b: intr_watchdog_next_proc */
        0x809b0980,
        0xe0b603e9,
        0x68e6b158,
        0xc61bf402,
-/* 0x010a: intr */
+/* 0x011a: intr */
        0x00f900f8,
        0x80f904bd,
        0xa0f990f9,
@@ -948,13 +954,13 @@ uint32_t nvc0_pwr_code[] = {
        0xf40289c4,
        0x0080230b,
        0x58e7f09b,
-       0x98cb21f4,
+       0x98db21f4,
        0x96b09b09,
        0x110bf400,
        0xb63407f0,
        0x09d00604,
        0x8004bd00,
-/* 0x016e: intr_skip_watchdog */
+/* 0x017e: intr_skip_watchdog */
        0x89e49a09,
        0x0bf40800,
        0x8897f148,
@@ -967,22 +973,22 @@ uint32_t nvc0_pwr_code[] = {
        0x48e7f1c0,
        0x53e3f14f,
        0x00d7f054,
-       0x02b921f5,
+       0x034221f5,
        0x07f1c0fc,
        0x04b604c0,
        0x000cd006,
-/* 0x01ae: intr_subintr_skip_fifo */
+/* 0x01be: intr_subintr_skip_fifo */
        0x07f104bd,
        0x04b60688,
        0x0009d006,
-/* 0x01ba: intr_skip_subintr */
+/* 0x01ca: intr_skip_subintr */
        0x89c404bd,
        0x070bf420,
        0xffbfa4f1,
-/* 0x01c4: intr_skip_pause */
+/* 0x01d4: intr_skip_pause */
        0xf44089c4,
        0xa4f1070b,
-/* 0x01ce: intr_skip_user0 */
+/* 0x01de: intr_skip_user0 */
        0x07f0ffbf,
        0x0604b604,
        0xbd0008d0,
@@ -993,597 +999,733 @@ uint32_t nvc0_pwr_code[] = {
        0x90fca0fc,
        0x00fc80fc,
        0xf80032f4,
-/* 0x01f5: timer */
-       0x1032f401,
-       0xb003f898,
-       0x1cf40086,
-       0x03fe8051,
+/* 0x0205: ticks_from_ns */
+       0xf9c0f901,
+       0xcbd7f1b0,
+       0x00d3f000,
+       0x041321f5,
+       0x03e8ccec,
+       0xf400b4b0,
+       0xeeec120b,
+       0xd7f103e8,
+       0xd3f000cb,
+       0x1321f500,
+/* 0x022d: ticks_from_ns_quit */
+       0x02ceb904,
+       0xc0fcb0fc,
+/* 0x0236: ticks_from_us */
+       0xc0f900f8,
+       0xd7f1b0f9,
+       0xd3f000cb,
+       0x1321f500,
+       0x02ceb904,
+       0xf400b4b0,
+       0xe4bd050b,
+/* 0x0250: ticks_from_us_quit */
+       0xc0fcb0fc,
+/* 0x0256: ticks_to_us */
+       0xd7f100f8,
+       0xd3f000cb,
+       0xecedff00,
+/* 0x0262: timer */
+       0x90f900f8,
+       0x32f480f9,
+       0x03f89810,
+       0xf40086b0,
+       0x84bd651c,
        0xb63807f0,
        0x08d00604,
        0xf004bd00,
-       0x84b60887,
+       0x84b63487,
        0x0088cf06,
-       0xf40284f0,
-       0x87f0261b,
-       0x0684b634,
-       0xb80088cf,
-       0x0bf406e0,
-       0x06e8b809,
-/* 0x0233: timer_reset */
-       0xf01f1ef4,
-       0x04b63407,
-       0x000ed006,
-       0x0e8004bd,
-/* 0x0241: timer_enable */
-       0x0187f09a,
+       0xbb9a0998,
+       0xe9bb0298,
+       0x03fe8000,
+       0xb60887f0,
+       0x88cf0684,
+       0x0284f000,
+       0xf0261bf4,
+       0x84b63487,
+       0x0088cf06,
+       0xf406e0b8,
+       0xe8b8090b,
+       0x111cf406,
+/* 0x02b8: timer_reset */
+       0xb63407f0,
+       0x0ed00604,
+       0x8004bd00,
+/* 0x02c6: timer_enable */
+       0x87f09a0e,
+       0x3807f001,
+       0xd00604b6,
+       0x04bd0008,
+/* 0x02d4: timer_done */
+       0xfc1031f4,
+       0xf890fc80,
+/* 0x02dd: send_proc */
+       0xf980f900,
+       0x05e89890,
+       0xf004e998,
+       0x89b80486,
+       0x2a0bf406,
+       0x940398c4,
+       0x80b60488,
+       0x008ebb18,
+       0x8000fa98,
+       0x8d80008a,
+       0x028c8001,
+       0xb6038b80,
+       0x94f00190,
+       0x04e98007,
+/* 0x0317: send_done */
+       0xfc0231f4,
+       0xf880fc90,
+/* 0x031d: find */
+       0xf080f900,
+       0x31f45887,
+/* 0x0325: find_loop */
+       0x008a9801,
+       0xf406aeb8,
+       0x80b6100b,
+       0x6886b158,
+       0xf01bf402,
+/* 0x033b: find_done */
+       0xb90132f4,
+       0x80fc028e,
+/* 0x0342: send */
+       0x21f500f8,
+       0x01f4031d,
+/* 0x034b: recv */
+       0xf900f897,
+       0x9880f990,
+       0xe99805e8,
+       0x0132f404,
+       0xf40689b8,
+       0x89c43d0b,
+       0x0180b603,
+       0x800784f0,
+       0xea9805e8,
+       0xfef0f902,
+       0xf0f9018f,
+       0x9402efb9,
+       0xe9bb0499,
+       0x18e0b600,
+       0x9803eb98,
+       0xed9802ec,
+       0x00ee9801,
+       0xf0fca5f9,
+       0xf400f8fe,
+       0xf0fc0131,
+/* 0x0398: recv_done */
+       0x90fc80fc,
+/* 0x039e: init */
+       0x17f100f8,
+       0x14b60108,
+       0x0011cf06,
+       0x010911e7,
+       0xfe0814b6,
+       0x17f10014,
+       0x13f000e0,
+       0x1c07f000,
+       0xd00604b6,
+       0x04bd0001,
+       0xf0ff17f0,
+       0x04b61407,
+       0x0001d006,
+       0x17f004bd,
+       0x0015f102,
+       0x1007f008,
+       0xd00604b6,
+       0x04bd0001,
+       0x011a17f1,
+       0xfe0013f0,
+       0x31f40010,
+       0x0117f010,
        0xb63807f0,
-       0x08d00604,
-/* 0x024f: timer_done */
-       0xf404bd00,
-       0x00f81031,
-/* 0x0254: send_proc */
-       0x90f980f9,
-       0x9805e898,
-       0x86f004e9,
-       0x0689b804,
-       0xc42a0bf4,
-       0x88940398,
-       0x1880b604,
-       0x98008ebb,
-       0x8a8000fa,
-       0x018d8000,
-       0x80028c80,
-       0x90b6038b,
-       0x0794f001,
-       0xf404e980,
-/* 0x028e: send_done */
-       0x90fc0231,
-       0x00f880fc,
-/* 0x0294: find */
-       0x87f080f9,
-       0x0131f458,
-/* 0x029c: find_loop */
-       0xb8008a98,
-       0x0bf406ae,
-       0x5880b610,
-       0x026886b1,
-       0xf4f01bf4,
-/* 0x02b2: find_done */
-       0x8eb90132,
-       0xf880fc02,
-/* 0x02b9: send */
-       0x9421f500,
-       0x9701f402,
-/* 0x02c2: recv */
-       0xe89800f8,
-       0x04e99805,
-       0xb80132f4,
-       0x0bf40689,
-       0x0389c43d,
-       0xf00180b6,
-       0xe8800784,
-       0x02ea9805,
-       0x8ffef0f9,
-       0xb9f0f901,
-       0x999402ef,
-       0x00e9bb04,
-       0x9818e0b6,
-       0xec9803eb,
-       0x01ed9802,
-       0xf900ee98,
-       0xfef0fca5,
-       0x31f400f8,
-/* 0x030b: recv_done */
-       0xf8f0fc01,
-/* 0x030d: init */
-       0x0817f100,
-       0x0614b601,
-       0xe70011cf,
-       0xb6010911,
-       0x14fe0814,
-       0xe017f100,
-       0x0013f000,
-       0xb61c07f0,
        0x01d00604,
        0xf004bd00,
-       0x07f0ff17,
-       0x0604b614,
-       0xbd0001d0,
-       0x0217f004,
-       0x080015f1,
-       0xb61007f0,
-       0x01d00604,
-       0xf104bd00,
-       0xf0010a17,
-       0x10fe0013,
-       0x1031f400,
-       0xf00117f0,
-       0x04b63807,
-       0x0001d006,
-       0xf7f004bd,
-/* 0x0371: init_proc */
-       0x01f19858,
-       0xf40016b0,
-       0x15f9fa0b,
-       0xf458f0b6,
-/* 0x0382: host_send */
-       0x17f1f20e,
-       0x14b604b0,
-       0x0011cf06,
-       0x04a027f1,
-       0xcf0624b6,
-       0x12b80022,
-       0x320bf406,
-       0x94071ec4,
-       0xe0b704ee,
-       0xeb980270,
-       0x02ec9803,
-       0x9801ed98,
-       0x21f500ee,
-       0x10b602b9,
-       0x0f1ec401,
-       0x04b007f1,
-       0xd00604b6,
-       0x04bd000e,
-/* 0x03cb: host_send_done */
-       0xf8ba0ef4,
-/* 0x03cd: host_recv */
-       0x4917f100,
-       0x5413f14e,
-       0x06e1b852,
-/* 0x03db: host_recv_wait */
-       0xf1aa0bf4,
-       0xb604cc17,
-       0x11cf0614,
-       0xc827f100,
-       0x0624b604,
-       0xf00022cf,
-       0x12b80816,
-       0xe60bf406,
-       0xb60723c4,
-       0x30b70434,
-       0x3b8002f0,
-       0x023c8003,
-       0x80013d80,
-       0x20b6003e,
-       0x0f24f001,
-       0x04c807f1,
+/* 0x0402: init_proc */
+       0xf19858f7,
+       0x0016b001,
+       0xf9fa0bf4,
+       0x58f0b615,
+/* 0x0413: mulu32_32_64 */
+       0xf9f20ef4,
+       0xf920f910,
+       0x9540f930,
+       0xd29510e1,
+       0xbdc4bd10,
+       0xc0edffb4,
+       0xb9301dff,
+       0x34f10234,
+       0x34b6ffff,
+       0x1045b610,
+       0xbb00c3bb,
+       0xe2ff01b4,
+       0x0234b930,
+       0xffff34f1,
+       0xb61034b6,
+       0xc3bb1045,
+       0x01b4bb00,
+       0xbb3012ff,
+       0x40fc00b3,
+       0x20fc30fc,
+       0x00f810fc,
+/* 0x0464: host_send */
+       0x04b017f1,
+       0xcf0614b6,
+       0x27f10011,
+       0x24b604a0,
+       0x0022cf06,
+       0xf40612b8,
+       0x1ec4320b,
+       0x04ee9407,
+       0x0270e0b7,
+       0x9803eb98,
+       0xed9802ec,
+       0x00ee9801,
+       0x034221f5,
+       0xc40110b6,
+       0x07f10f1e,
+       0x04b604b0,
+       0x000ed006,
+       0x0ef404bd,
+/* 0x04ad: host_send_done */
+/* 0x04af: host_recv */
+       0xf100f8ba,
+       0xf14e4917,
+       0xb8525413,
+       0x0bf406e1,
+/* 0x04bd: host_recv_wait */
+       0xcc17f1aa,
+       0x0614b604,
+       0xf10011cf,
+       0xb604c827,
+       0x22cf0624,
+       0x0816f000,
+       0xf40612b8,
+       0x23c4e60b,
+       0x0434b607,
+       0x02f030b7,
+       0x80033b80,
+       0x3d80023c,
+       0x003e8001,
+       0xf00120b6,
+       0x07f10f24,
+       0x04b604c8,
+       0x0002d006,
+       0x27f004bd,
+       0x0007f040,
        0xd00604b6,
        0x04bd0002,
-       0xf04027f0,
-       0x04b60007,
-       0x0002d006,
-       0x00f804bd,
-/* 0x0430: host_init */
-       0x008017f1,
-       0xf11014b6,
-       0xf1027015,
-       0xb604d007,
-       0x01d00604,
-       0xf104bd00,
-       0xb6008017,
-       0x15f11014,
-       0x07f102f0,
-       0x04b604dc,
-       0x0001d006,
-       0x17f004bd,
-       0xc407f101,
+/* 0x0512: host_init */
+       0x17f100f8,
+       0x14b60080,
+       0x7015f110,
+       0xd007f102,
        0x0604b604,
        0xbd0001d0,
-/* 0x046f: memx_func_enter */
-       0xf000f804,
+       0x8017f104,
+       0x1014b600,
+       0x02f015f1,
+       0x04dc07f1,
+       0xd00604b6,
+       0x04bd0001,
+       0xf10117f0,
+       0xb604c407,
+       0x01d00604,
+       0xf804bd00,
+/* 0x0551: memx_func_enter */
+       0x2067f100,
+       0x5d77f116,
+       0xff73f1f5,
+       0x026eb9ff,
+       0xb90421f4,
+       0x87fd02d8,
+       0xf960f904,
+       0xfcd0fc80,
+       0x3f21f4e0,
+       0xfffe77f1,
+       0xffff73f1,
+       0xf4026eb9,
+       0xd8b90421,
+       0x0487fd02,
+       0x80f960f9,
+       0xe0fcd0fc,
+       0xf13f21f4,
+       0xb926f067,
+       0x21f4026e,
+       0x02d8b904,
+       0xf90487fd,
+       0xfc80f960,
+       0xf4e0fcd0,
+       0x67f03f21,
+       0xe007f104,
+       0x0604b607,
+       0xbd0006d0,
+/* 0x05bd: memx_func_enter_wait */
+       0xc067f104,
+       0x0664b607,
+       0xf00066cf,
+       0x0bf40464,
+       0x2c67f0f3,
+       0xcf0664b6,
+       0x06800066,
+/* 0x05db: memx_func_leave */
+       0xf000f8ee,
+       0x64b62c67,
+       0x0066cf06,
+       0xf0ef0680,
        0x07f10467,
-       0x04b607e0,
+       0x04b607e4,
        0x0006d006,
-/* 0x047e: memx_func_enter_wait */
+/* 0x05f6: memx_func_leave_wait */
        0x67f104bd,
        0x64b607c0,
        0x0066cf06,
        0xf40464f0,
-       0x1698f30b,
+       0x67f1f31b,
+       0x77f126f0,
+       0x73f00001,
+       0x026eb900,
+       0xb90421f4,
+       0x87fd02d8,
+       0xf960f905,
+       0xfcd0fc80,
+       0x3f21f4e0,
+       0x162067f1,
+       0xf4026eb9,
+       0xd8b90421,
+       0x0587fd02,
+       0x80f960f9,
+       0xe0fcd0fc,
+       0xf13f21f4,
+       0xf00aa277,
+       0x6eb90073,
+       0x0421f402,
+       0xfd02d8b9,
+       0x60f90587,
+       0xd0fc80f9,
+       0x21f4e0fc,
+/* 0x0663: memx_func_wait_vblank */
+       0x9800f83f,
+       0x66b00016,
+       0x130bf400,
+       0xf40166b0,
+       0x0ef4060b,
+/* 0x0675: memx_func_wait_vblank_head1 */
+       0x2077f12e,
+       0x070ef400,
+/* 0x067c: memx_func_wait_vblank_head0 */
+       0x000877f1,
+/* 0x0680: memx_func_wait_vblank_0 */
+       0x07c467f1,
+       0xcf0664b6,
+       0x67fd0066,
+       0xf31bf404,
+/* 0x0690: memx_func_wait_vblank_1 */
+       0x07c467f1,
+       0xcf0664b6,
+       0x67fd0066,
+       0xf30bf404,
+/* 0x06a0: memx_func_wait_vblank_fini */
+       0xf80410b6,
+/* 0x06a5: memx_func_wr32 */
+       0x00169800,
+       0xb6011598,
+       0x60f90810,
+       0xd0fc50f9,
+       0x21f4e0fc,
+       0x0242b63f,
+       0xf8e91bf4,
+/* 0x06c1: memx_func_wait */
+       0x2c87f000,
+       0xcf0684b6,
+       0x1e980088,
+       0x011d9800,
+       0x98021c98,
+       0x10b6031b,
+       0xa421f410,
+/* 0x06de: memx_func_delay */
+       0x1e9800f8,
        0x0410b600,
-/* 0x0496: memx_func_leave */
-       0x67f000f8,
-       0xe407f104,
+       0xf87f21f4,
+/* 0x06e9: memx_exec */
+       0xf9e0f900,
+       0x02c1b9d0,
+/* 0x06f3: memx_exec_next */
+       0x9802b2b9,
+       0x10b60013,
+       0xf034e704,
+       0xe033e701,
+       0x0132b601,
+       0x980c30f0,
+       0x55f9de35,
+       0xf40612b8,
+       0x0b98e41e,
+       0xef0c98ee,
+       0xf102cbbb,
+       0xb607c4b7,
+       0xbbcf06b4,
+       0xfcd0fc00,
+       0x4221f5e0,
+/* 0x072f: memx_info */
+       0xf100f803,
+       0xf103c0c7,
+       0xf50800b7,
+       0xf8034221,
+/* 0x073d: memx_recv */
+       0x01d6b000,
+       0xb0a90bf4,
+       0x0bf400d6,
+/* 0x074b: memx_init */
+       0xf800f8e9,
+/* 0x074d: perf_recv */
+/* 0x074f: perf_init */
+       0xf800f800,
+/* 0x0751: i2c_drive_scl */
+       0x0036b000,
+       0xf1110bf4,
+       0xb607e007,
+       0x01d00604,
+       0xf804bd00,
+/* 0x0765: i2c_drive_scl_lo */
+       0xe407f100,
        0x0604b607,
-       0xbd0006d0,
-/* 0x04a5: memx_func_leave_wait */
-       0xc067f104,
-       0x0664b607,
-       0xf00066cf,
-       0x1bf40464,
-/* 0x04b7: memx_func_wr32 */
-       0x9800f8f3,
-       0x15980016,
-       0x0810b601,
-       0x50f960f9,
-       0xe0fcd0fc,
-       0xb63f21f4,
-       0x1bf40242,
-/* 0x04d3: memx_func_wait */
-       0xf000f8e9,
-       0x84b62c87,
-       0x0088cf06,
-       0x98001e98,
-       0x1c98011d,
-       0x031b9802,
-       0xf41010b6,
-       0x00f89c21,
-/* 0x04f0: memx_func_delay */
-       0xb6001e98,
-       0x21f40410,
-/* 0x04fb: memx_exec */
-       0xf900f87f,
-       0xb9d0f9e0,
-       0xb2b902c1,
-/* 0x0505: memx_exec_next */
-       0x00139802,
-       0x950410b6,
-       0x30f01034,
-       0xde35980c,
-       0x12b855f9,
-       0xec1ef406,
-       0xe0fcd0fc,
-       0x02b921f5,
-/* 0x0526: memx_info */
-       0xc7f100f8,
-       0xb7f103ac,
-       0x21f50800,
-       0x00f802b9,
-/* 0x0534: memx_recv */
-       0xf401d6b0,
-       0xd6b0c40b,
-       0xe90bf400,
-/* 0x0542: memx_init */
-       0x00f800f8,
-/* 0x0544: perf_recv */
-/* 0x0546: perf_init */
-       0x00f800f8,
-/* 0x0548: i2c_drive_scl */
-       0xf40036b0,
-       0x07f1110b,
-       0x04b607e0,
-       0x0001d006,
-       0x00f804bd,
-/* 0x055c: i2c_drive_scl_lo */
-       0x07e407f1,
-       0xd00604b6,
-       0x04bd0001,
-/* 0x056a: i2c_drive_sda */
-       0x36b000f8,
-       0x110bf400,
-       0x07e007f1,
-       0xd00604b6,
-       0x04bd0002,
-/* 0x057e: i2c_drive_sda_lo */
-       0x07f100f8,
-       0x04b607e4,
-       0x0002d006,
-       0x00f804bd,
-/* 0x058c: i2c_sense_scl */
-       0xf10132f4,
-       0xb607c437,
-       0x33cf0634,
-       0x0431fd00,
-       0xf4060bf4,
-/* 0x05a2: i2c_sense_scl_done */
-       0x00f80131,
-/* 0x05a4: i2c_sense_sda */
-       0xf10132f4,
-       0xb607c437,
-       0x33cf0634,
-       0x0432fd00,
-       0xf4060bf4,
-/* 0x05ba: i2c_sense_sda_done */
-       0x00f80131,
-/* 0x05bc: i2c_raise_scl */
-       0x47f140f9,
-       0x37f00898,
-       0x4821f501,
-/* 0x05c9: i2c_raise_scl_wait */
-       0xe8e7f105,
-       0x7f21f403,
-       0x058c21f5,
-       0xb60901f4,
-       0x1bf40142,
-/* 0x05dd: i2c_raise_scl_done */
-       0xf840fcef,
-/* 0x05e1: i2c_start */
-       0x8c21f500,
-       0x0d11f405,
-       0x05a421f5,
-       0xf40611f4,
-/* 0x05f2: i2c_start_rep */
-       0x37f0300e,
-       0x4821f500,
-       0x0137f005,
-       0x056a21f5,
-       0xb60076bb,
-       0x50f90465,
-       0xbb046594,
-       0x50bd0256,
-       0xfc0475fd,
-       0xbc21f550,
-       0x0464b605,
-/* 0x061f: i2c_start_send */
-       0xf01f11f4,
+       0xbd0001d0,
+/* 0x0773: i2c_drive_sda */
+       0xb000f804,
+       0x0bf40036,
+       0xe007f111,
+       0x0604b607,
+       0xbd0002d0,
+/* 0x0787: i2c_drive_sda_lo */
+       0xf100f804,
+       0xb607e407,
+       0x02d00604,
+       0xf804bd00,
+/* 0x0795: i2c_sense_scl */
+       0x0132f400,
+       0x07c437f1,
+       0xcf0634b6,
+       0x31fd0033,
+       0x060bf404,
+/* 0x07ab: i2c_sense_scl_done */
+       0xf80131f4,
+/* 0x07ad: i2c_sense_sda */
+       0x0132f400,
+       0x07c437f1,
+       0xcf0634b6,
+       0x32fd0033,
+       0x060bf404,
+/* 0x07c3: i2c_sense_sda_done */
+       0xf80131f4,
+/* 0x07c5: i2c_raise_scl */
+       0xf140f900,
+       0xf0089847,
+       0x21f50137,
+/* 0x07d2: i2c_raise_scl_wait */
+       0xe7f10751,
+       0x21f403e8,
+       0x9521f57f,
+       0x0901f407,
+       0xf40142b6,
+/* 0x07e6: i2c_raise_scl_done */
+       0x40fcef1b,
+/* 0x07ea: i2c_start */
+       0x21f500f8,
+       0x11f40795,
+       0xad21f50d,
+       0x0611f407,
+/* 0x07fb: i2c_start_rep */
+       0xf0300ef4,
        0x21f50037,
-       0xe7f1056a,
-       0x21f41388,
-       0x0037f07f,
-       0x054821f5,
-       0x1388e7f1,
-/* 0x063b: i2c_start_out */
-       0xf87f21f4,
-/* 0x063d: i2c_stop */
-       0x0037f000,
-       0x054821f5,
+       0x37f00751,
+       0x7321f501,
+       0x0076bb07,
+       0xf90465b6,
+       0x04659450,
+       0xbd0256bb,
+       0x0475fd50,
+       0x21f550fc,
+       0x64b607c5,
+       0x1f11f404,
+/* 0x0828: i2c_start_send */
        0xf50037f0,
-       0xf1056a21,
-       0xf403e8e7,
+       0xf1077321,
+       0xf41388e7,
        0x37f07f21,
-       0x4821f501,
-       0x88e7f105,
+       0x5121f500,
+       0x88e7f107,
        0x7f21f413,
-       0xf50137f0,
-       0xf1056a21,
-       0xf41388e7,
-       0x00f87f21,
-/* 0x0670: i2c_bitw */
-       0x056a21f5,
+/* 0x0844: i2c_start_out */
+/* 0x0846: i2c_stop */
+       0x37f000f8,
+       0x5121f500,
+       0x0037f007,
+       0x077321f5,
        0x03e8e7f1,
-       0xbb7f21f4,
-       0x65b60076,
-       0x9450f904,
-       0x56bb0465,
-       0xfd50bd02,
-       0x50fc0475,
-       0x05bc21f5,
-       0xf40464b6,
-       0xe7f11811,
+       0xf07f21f4,
+       0x21f50137,
+       0xe7f10751,
        0x21f41388,
-       0x0037f07f,
-       0x054821f5,
+       0x0137f07f,
+       0x077321f5,
        0x1388e7f1,
-/* 0x06af: i2c_bitw_out */
        0xf87f21f4,
-/* 0x06b1: i2c_bitr */
-       0x0137f000,
-       0x056a21f5,
-       0x03e8e7f1,
-       0xbb7f21f4,
-       0x65b60076,
-       0x9450f904,
-       0x56bb0465,
-       0xfd50bd02,
-       0x50fc0475,
-       0x05bc21f5,
-       0xf40464b6,
-       0x21f51b11,
-       0x37f005a4,
-       0x4821f500,
-       0x88e7f105,
+/* 0x0879: i2c_bitw */
+       0x7321f500,
+       0xe8e7f107,
+       0x7f21f403,
+       0xb60076bb,
+       0x50f90465,
+       0xbb046594,
+       0x50bd0256,
+       0xfc0475fd,
+       0xc521f550,
+       0x0464b607,
+       0xf11811f4,
+       0xf41388e7,
+       0x37f07f21,
+       0x5121f500,
+       0x88e7f107,
        0x7f21f413,
-       0xf4013cf0,
-/* 0x06f6: i2c_bitr_done */
-       0x00f80131,
-/* 0x06f8: i2c_get_byte */
-       0xf00057f0,
-/* 0x06fe: i2c_get_byte_next */
-       0x54b60847,
+/* 0x08b8: i2c_bitw_out */
+/* 0x08ba: i2c_bitr */
+       0x37f000f8,
+       0x7321f501,
+       0xe8e7f107,
+       0x7f21f403,
+       0xb60076bb,
+       0x50f90465,
+       0xbb046594,
+       0x50bd0256,
+       0xfc0475fd,
+       0xc521f550,
+       0x0464b607,
+       0xf51b11f4,
+       0xf007ad21,
+       0x21f50037,
+       0xe7f10751,
+       0x21f41388,
+       0x013cf07f,
+/* 0x08ff: i2c_bitr_done */
+       0xf80131f4,
+/* 0x0901: i2c_get_byte */
+       0x0057f000,
+/* 0x0907: i2c_get_byte_next */
+       0xb60847f0,
+       0x76bb0154,
+       0x0465b600,
+       0x659450f9,
+       0x0256bb04,
+       0x75fd50bd,
+       0xf550fc04,
+       0xb608ba21,
+       0x11f40464,
+       0x0553fd2b,
+       0xf40142b6,
+       0x37f0d81b,
        0x0076bb01,
        0xf90465b6,
        0x04659450,
        0xbd0256bb,
        0x0475fd50,
        0x21f550fc,
-       0x64b606b1,
-       0x2b11f404,
-       0xb60553fd,
-       0x1bf40142,
-       0x0137f0d8,
-       0xb60076bb,
-       0x50f90465,
-       0xbb046594,
-       0x50bd0256,
-       0xfc0475fd,
-       0x7021f550,
-       0x0464b606,
-/* 0x0748: i2c_get_byte_done */
-/* 0x074a: i2c_put_byte */
-       0x47f000f8,
-/* 0x074d: i2c_put_byte_next */
-       0x0142b608,
-       0xbb3854ff,
-       0x65b60076,
-       0x9450f904,
-       0x56bb0465,
-       0xfd50bd02,
-       0x50fc0475,
-       0x067021f5,
-       0xf40464b6,
-       0x46b03411,
-       0xd81bf400,
+       0x64b60879,
+/* 0x0951: i2c_get_byte_done */
+/* 0x0953: i2c_put_byte */
+       0xf000f804,
+/* 0x0956: i2c_put_byte_next */
+       0x42b60847,
+       0x3854ff01,
        0xb60076bb,
        0x50f90465,
        0xbb046594,
        0x50bd0256,
        0xfc0475fd,
-       0xb121f550,
-       0x0464b606,
-       0xbb0f11f4,
-       0x36b00076,
-       0x061bf401,
-/* 0x07a3: i2c_put_byte_done */
-       0xf80132f4,
-/* 0x07a5: i2c_addr */
-       0x0076bb00,
+       0x7921f550,
+       0x0464b608,
+       0xb03411f4,
+       0x1bf40046,
+       0x0076bbd8,
        0xf90465b6,
        0x04659450,
        0xbd0256bb,
        0x0475fd50,
        0x21f550fc,
-       0x64b605e1,
-       0x2911f404,
-       0x012ec3e7,
-       0xfd0134b6,
-       0x76bb0553,
+       0x64b608ba,
+       0x0f11f404,
+       0xb00076bb,
+       0x1bf40136,
+       0x0132f406,
+/* 0x09ac: i2c_put_byte_done */
+/* 0x09ae: i2c_addr */
+       0x76bb00f8,
        0x0465b600,
        0x659450f9,
        0x0256bb04,
        0x75fd50bd,
        0xf550fc04,
-       0xb6074a21,
-/* 0x07ea: i2c_addr_done */
-       0x00f80464,
-/* 0x07ec: i2c_acquire_addr */
-       0xb6f8cec7,
-       0xe0b702e4,
-       0xee980bfc,
-/* 0x07fb: i2c_acquire */
-       0xf500f800,
-       0xf407ec21,
-       0xd9f00421,
-       0x3f21f403,
-/* 0x080a: i2c_release */
-       0x21f500f8,
-       0x21f407ec,
-       0x03daf004,
-       0xf83f21f4,
-/* 0x0819: i2c_recv */
-       0x0132f400,
-       0xb6f8c1c7,
-       0x16b00214,
-       0x3a1ff528,
-       0xd413a001,
-       0x0032980b,
-       0x0bac13a0,
-       0xf4003198,
-       0xd0f90231,
-       0xd0f9e0f9,
-       0x000067f1,
-       0x100063f1,
-       0xbb016792,
+       0xb607ea21,
+       0x11f40464,
+       0x2ec3e729,
+       0x0134b601,
+       0xbb0553fd,
        0x65b60076,
        0x9450f904,
        0x56bb0465,
        0xfd50bd02,
        0x50fc0475,
-       0x07fb21f5,
-       0xfc0464b6,
-       0x00d6b0d0,
-       0x00b31bf5,
-       0xbb0057f0,
+       0x095321f5,
+/* 0x09f3: i2c_addr_done */
+       0xf80464b6,
+/* 0x09f5: i2c_acquire_addr */
+       0xf8cec700,
+       0xb702e4b6,
+       0x980c10e0,
+       0x00f800ee,
+/* 0x0a04: i2c_acquire */
+       0x09f521f5,
+       0xf00421f4,
+       0x21f403d9,
+/* 0x0a13: i2c_release */
+       0xf500f83f,
+       0xf409f521,
+       0xdaf00421,
+       0x3f21f403,
+/* 0x0a22: i2c_recv */
+       0x32f400f8,
+       0xf8c1c701,
+       0xb00214b6,
+       0x1ff52816,
+       0x13a0013a,
+       0x32980be8,
+       0xc013a000,
+       0x0031980b,
+       0xf90231f4,
+       0xf9e0f9d0,
+       0x0067f1d0,
+       0x0063f100,
+       0x01679210,
+       0xb60076bb,
+       0x50f90465,
+       0xbb046594,
+       0x50bd0256,
+       0xfc0475fd,
+       0x0421f550,
+       0x0464b60a,
+       0xd6b0d0fc,
+       0xb31bf500,
+       0x0057f000,
+       0xb60076bb,
+       0x50f90465,
+       0xbb046594,
+       0x50bd0256,
+       0xfc0475fd,
+       0xae21f550,
+       0x0464b609,
+       0x00d011f5,
+       0xbbe0c5c7,
        0x65b60076,
        0x9450f904,
        0x56bb0465,
        0xfd50bd02,
        0x50fc0475,
-       0x07a521f5,
+       0x095321f5,
        0xf50464b6,
-       0xc700d011,
-       0x76bbe0c5,
+       0xf000ad11,
+       0x76bb0157,
        0x0465b600,
        0x659450f9,
        0x0256bb04,
        0x75fd50bd,
        0xf550fc04,
-       0xb6074a21,
+       0xb609ae21,
        0x11f50464,
-       0x57f000ad,
-       0x0076bb01,
-       0xf90465b6,
-       0x04659450,
-       0xbd0256bb,
-       0x0475fd50,
-       0x21f550fc,
-       0x64b607a5,
-       0x8a11f504,
-       0x0076bb00,
-       0xf90465b6,
-       0x04659450,
-       0xbd0256bb,
-       0x0475fd50,
-       0x21f550fc,
-       0x64b606f8,
-       0x6a11f404,
-       0xbbe05bcb,
-       0x65b60076,
-       0x9450f904,
-       0x56bb0465,
-       0xfd50bd02,
-       0x50fc0475,
-       0x063d21f5,
-       0xb90464b6,
-       0x74bd025b,
-/* 0x091f: i2c_recv_not_rd08 */
-       0xb0430ef4,
-       0x1bf401d6,
-       0x0057f03d,
-       0x07a521f5,
-       0xc73311f4,
-       0x21f5e0c5,
-       0x11f4074a,
-       0x0057f029,
-       0x07a521f5,
-       0xc71f11f4,
-       0x21f5e0b5,
-       0x11f4074a,
-       0x3d21f515,
-       0xc774bd06,
-       0x1bf408c5,
-       0x0232f409,
-/* 0x095f: i2c_recv_not_wr08 */
-/* 0x095f: i2c_recv_done */
-       0xc7030ef4,
-       0x21f5f8ce,
-       0xe0fc080a,
-       0x12f4d0fc,
-       0x027cb90a,
-       0x02b921f5,
-/* 0x0974: i2c_recv_exit */
-/* 0x0976: i2c_init */
+       0x76bb008a,
+       0x0465b600,
+       0x659450f9,
+       0x0256bb04,
+       0x75fd50bd,
+       0xf550fc04,
+       0xb6090121,
+       0x11f40464,
+       0xe05bcb6a,
+       0xb60076bb,
+       0x50f90465,
+       0xbb046594,
+       0x50bd0256,
+       0xfc0475fd,
+       0x4621f550,
+       0x0464b608,
+       0xbd025bb9,
+       0x430ef474,
+/* 0x0b28: i2c_recv_not_rd08 */
+       0xf401d6b0,
+       0x57f03d1b,
+       0xae21f500,
+       0x3311f409,
+       0xf5e0c5c7,
+       0xf4095321,
+       0x57f02911,
+       0xae21f500,
+       0x1f11f409,
+       0xf5e0b5c7,
+       0xf4095321,
+       0x21f51511,
+       0x74bd0846,
+       0xf408c5c7,
+       0x32f4091b,
+       0x030ef402,
+/* 0x0b68: i2c_recv_not_wr08 */
+/* 0x0b68: i2c_recv_done */
+       0xf5f8cec7,
+       0xfc0a1321,
+       0xf4d0fce0,
+       0x7cb90a12,
+       0x4221f502,
+/* 0x0b7d: i2c_recv_exit */
+/* 0x0b7f: i2c_init */
+       0xf800f803,
+/* 0x0b81: test_recv */
+       0xd817f100,
+       0x0614b605,
+       0xb60011cf,
+       0x07f10110,
+       0x04b605d8,
+       0x0001d006,
+       0xe7f104bd,
+       0xe3f1d900,
+       0x21f5134f,
+       0x00f80262,
+/* 0x0ba8: test_init */
+       0x0800e7f1,
+       0x026221f5,
+/* 0x0bb2: idle_recv */
        0x00f800f8,
-/* 0x0978: test_recv */
-       0x05d817f1,
-       0xcf0614b6,
-       0x10b60011,
-       0xd807f101,
-       0x0604b605,
-       0xbd0001d0,
-       0x00e7f104,
-       0x4fe3f1d9,
-       0xf521f513,
-/* 0x099f: test_init */
-       0xf100f801,
-       0xf50800e7,
-       0xf801f521,
-/* 0x09a9: idle_recv */
-/* 0x09ab: idle */
-       0xf400f800,
-       0x17f10031,
-       0x14b605d4,
-       0x0011cf06,
-       0xf10110b6,
-       0xb605d407,
-       0x01d00604,
-/* 0x09c7: idle_loop */
-       0xf004bd00,
-       0x32f45817,
-/* 0x09cd: idle_proc */
-/* 0x09cd: idle_proc_exec */
-       0xb910f902,
-       0x21f5021e,
-       0x10fc02c2,
-       0xf40911f4,
-       0x0ef40231,
-/* 0x09e1: idle_proc_next */
-       0x5810b6ef,
-       0xf4061fb8,
-       0x02f4e61b,
-       0x0028f4dd,
-       0x00bb0ef4,
-       0x00000000,
-       0x00000000,
+/* 0x0bb4: idle */
+       0xf10031f4,
+       0xb605d417,
+       0x11cf0614,
+       0x0110b600,
+       0x05d407f1,
+       0xd00604b6,
+       0x04bd0001,
+/* 0x0bd0: idle_loop */
+       0xf45817f0,
+/* 0x0bd6: idle_proc */
+/* 0x0bd6: idle_proc_exec */
+       0x10f90232,
+       0xf5021eb9,
+       0xfc034b21,
+       0x0911f410,
+       0xf40231f4,
+/* 0x0bea: idle_proc_next */
+       0x10b6ef0e,
+       0x061fb858,
+       0xf4e61bf4,
+       0x28f4dd02,
+       0xbb0ef400,
        0x00000000,
 };
index 8a89dfe41ce1ba8ddf7b808ef5534e5eefd418a9..b85443261569aaec41f786c3c31e72103a31af98 100644 (file)
@@ -23,6 +23,7 @@
  */
 
 #define NVKM_PPWR_CHIPSET GF119
+#define HW_TICKS_PER_US 324
 
 //#define NVKM_FALCON_PC24
 #define NVKM_FALCON_UNSHIFTED_IO
@@ -34,6 +35,7 @@
 .section #nvd0_pwr_data
 #define INCLUDE_PROC
 #include "kernel.fuc"
+#include "arith.fuc"
 #include "host.fuc"
 #include "memx.fuc"
 #include "perf.fuc"
@@ -44,6 +46,7 @@
 
 #define INCLUDE_DATA
 #include "kernel.fuc"
+#include "arith.fuc"
 #include "host.fuc"
 #include "memx.fuc"
 #include "perf.fuc"
@@ -56,6 +59,7 @@
 .section #nvd0_pwr_code
 #define INCLUDE_CODE
 #include "kernel.fuc"
+#include "arith.fuc"
 #include "host.fuc"
 #include "memx.fuc"
 #include "perf.fuc"
index 8d369b3faabaea2492fef19f55e4ee15ed30166d..12d86f72ad105a191f152d38c1f0b4363c856ba1 100644 (file)
@@ -24,8 +24,8 @@ uint32_t nvd0_pwr_data[] = {
        0x00000000,
 /* 0x0058: proc_list_head */
        0x54534f48,
-       0x000003be,
-       0x00000367,
+       0x0000049d,
+       0x00000446,
        0x00000000,
        0x00000000,
        0x00000000,
@@ -46,8 +46,8 @@ uint32_t nvd0_pwr_data[] = {
        0x00000000,
        0x00000000,
        0x584d454d,
-       0x000004b8,
-       0x000004aa,
+       0x00000678,
+       0x0000066a,
        0x00000000,
        0x00000000,
        0x00000000,
@@ -68,8 +68,8 @@ uint32_t nvd0_pwr_data[] = {
        0x00000000,
        0x00000000,
        0x46524550,
-       0x000004bc,
-       0x000004ba,
+       0x0000067c,
+       0x0000067a,
        0x00000000,
        0x00000000,
        0x00000000,
@@ -90,8 +90,8 @@ uint32_t nvd0_pwr_data[] = {
        0x00000000,
        0x00000000,
        0x5f433249,
-       0x000008d7,
-       0x0000077a,
+       0x00000a97,
+       0x0000093a,
        0x00000000,
        0x00000000,
        0x00000000,
@@ -112,8 +112,8 @@ uint32_t nvd0_pwr_data[] = {
        0x00000000,
        0x00000000,
        0x54534554,
-       0x000008fa,
-       0x000008d9,
+       0x00000aba,
+       0x00000a99,
        0x00000000,
        0x00000000,
        0x00000000,
@@ -134,8 +134,8 @@ uint32_t nvd0_pwr_data[] = {
        0x00000000,
        0x00000000,
        0x454c4449,
-       0x00000906,
-       0x00000904,
+       0x00000ac6,
+       0x00000ac4,
        0x00000000,
        0x00000000,
        0x00000000,
@@ -227,24 +227,31 @@ uint32_t nvd0_pwr_data[] = {
        0x00000000,
        0x00000000,
 /* 0x0370: memx_func_head */
-       0x00010000,
-       0x00000000,
-       0x000003f4,
-/* 0x037c: memx_func_next */
        0x00000001,
        0x00000000,
-       0x00000415,
+       0x000004d3,
+/* 0x037c: memx_func_next */
        0x00000002,
+       0x00000000,
+       0x00000554,
+       0x00000003,
        0x00000002,
-       0x00000430,
-       0x00040003,
+       0x000005d8,
+       0x00040004,
+       0x00000000,
+       0x000005f4,
+       0x00010005,
+       0x00000000,
+       0x0000060e,
+       0x00010006,
+       0x00000000,
+       0x000005d3,
+/* 0x03b8: memx_func_tail */
+/* 0x03b8: memx_ts_start */
        0x00000000,
-       0x0000044c,
-       0x00010004,
+/* 0x03bc: memx_ts_end */
        0x00000000,
-       0x00000466,
-/* 0x03ac: memx_func_tail */
-/* 0x03ac: memx_data_head */
+/* 0x03c0: memx_data_head */
        0x00000000,
        0x00000000,
        0x00000000,
@@ -757,8 +764,8 @@ uint32_t nvd0_pwr_data[] = {
        0x00000000,
        0x00000000,
        0x00000000,
-/* 0x0bac: memx_data_tail */
-/* 0x0bac: i2c_scl_map */
+/* 0x0bc0: memx_data_tail */
+/* 0x0bc0: i2c_scl_map */
        0x00000400,
        0x00000800,
        0x00001000,
@@ -769,7 +776,7 @@ uint32_t nvd0_pwr_data[] = {
        0x00020000,
        0x00040000,
        0x00080000,
-/* 0x0bd4: i2c_sda_map */
+/* 0x0be8: i2c_sda_map */
        0x00100000,
        0x00200000,
        0x00400000,
@@ -781,10 +788,69 @@ uint32_t nvd0_pwr_data[] = {
        0x10000000,
        0x20000000,
        0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
 };
 
 uint32_t nvd0_pwr_code[] = {
-       0x02bf0ef5,
+       0x034d0ef5,
 /* 0x0004: rd32 */
        0x07a007f1,
        0xbd000ed0,
@@ -814,17 +880,20 @@ uint32_t nvd0_pwr_code[] = {
        0xd4f100dd,
        0x1bf47000,
 /* 0x0067: nsec */
-       0xf000f8f5,
+       0xf900f8f5,
+       0xf080f990,
        0x88cf2c87,
-/* 0x006d: nsec_loop */
+/* 0x0071: nsec_loop */
        0x2c97f000,
        0xbb0099cf,
        0x9eb80298,
        0xf41ef406,
-/* 0x007e: wait */
-       0x87f000f8,
+       0x90fc80fc,
+/* 0x0086: wait */
+       0x90f900f8,
+       0x87f080f9,
        0x0088cf2c,
-/* 0x0084: wait_loop */
+/* 0x0090: wait_loop */
        0xf402eeb9,
        0xdab90421,
        0x04adfd02,
@@ -833,28 +902,29 @@ uint32_t nvd0_pwr_code[] = {
        0x0099cf2c,
        0xb80298bb,
        0x1ef4069b,
-/* 0x00a5: wait_done */
-/* 0x00a7: intr_watchdog */
-       0x9800f8e2,
+/* 0x00b1: wait_done */
+       0xfc80fce2,
+/* 0x00b7: intr_watchdog */
+       0x9800f890,
        0x96b003e9,
        0x2a0bf400,
        0xbb9a0a98,
        0x1cf4029a,
        0x01d7f00f,
-       0x020621f5,
+       0x028c21f5,
        0x0ef494bd,
-/* 0x00c5: intr_watchdog_next_time */
+/* 0x00d5: intr_watchdog_next_time */
        0x9b0a9815,
        0xf400a6b0,
        0x9ab8090b,
        0x061cf406,
-/* 0x00d4: intr_watchdog_next_time_set */
-/* 0x00d7: intr_watchdog_next_proc */
+/* 0x00e4: intr_watchdog_next_time_set */
+/* 0x00e7: intr_watchdog_next_proc */
        0x809b0980,
        0xe0b603e9,
        0x68e6b158,
        0xc61bf402,
-/* 0x00e6: intr */
+/* 0x00f6: intr */
        0x00f900f8,
        0x80f904bd,
        0xa0f990f9,
@@ -872,12 +942,12 @@ uint32_t nvd0_pwr_code[] = {
        0x0bf40289,
        0x9b008020,
        0xf458e7f0,
-       0x0998a721,
+       0x0998b721,
        0x0096b09b,
        0xf00e0bf4,
        0x09d03407,
        0x8004bd00,
-/* 0x013e: intr_skip_watchdog */
+/* 0x014e: intr_skip_watchdog */
        0x89e49a09,
        0x0bf40800,
        0x8897f13c,
@@ -889,20 +959,20 @@ uint32_t nvd0_pwr_code[] = {
        0xf14f48e7,
        0xf05453e3,
        0x21f500d7,
-       0xc0fc026b,
+       0xc0fc02f1,
        0x04c007f1,
        0xbd000cd0,
-/* 0x0175: intr_subintr_skip_fifo */
+/* 0x0185: intr_subintr_skip_fifo */
        0x8807f104,
        0x0009d006,
-/* 0x017e: intr_skip_subintr */
+/* 0x018e: intr_skip_subintr */
        0x89c404bd,
        0x070bf420,
        0xffbfa4f1,
-/* 0x0188: intr_skip_pause */
+/* 0x0198: intr_skip_pause */
        0xf44089c4,
        0xa4f1070b,
-/* 0x0192: intr_skip_user0 */
+/* 0x01a2: intr_skip_user0 */
        0x07f0ffbf,
        0x0008d004,
        0x80fc04bd,
@@ -912,189 +982,298 @@ uint32_t nvd0_pwr_code[] = {
        0xfca0fcb0,
        0xfc80fc90,
        0x0032f400,
-/* 0x01b6: timer */
-       0x32f401f8,
-       0x03f89810,
-       0xf40086b0,
-       0xfe80421c,
-       0x3807f003,
+/* 0x01c6: ticks_from_ns */
+       0xc0f901f8,
+       0xd7f1b0f9,
+       0xd3f00144,
+       0xb321f500,
+       0xe8ccec03,
+       0x00b4b003,
+       0xec120bf4,
+       0xf103e8ee,
+       0xf00144d7,
+       0x21f500d3,
+/* 0x01ee: ticks_from_ns_quit */
+       0xceb903b3,
+       0xfcb0fc02,
+/* 0x01f7: ticks_from_us */
+       0xf900f8c0,
+       0xf1b0f9c0,
+       0xf00144d7,
+       0x21f500d3,
+       0xceb903b3,
+       0x00b4b002,
+       0xbd050bf4,
+/* 0x0211: ticks_from_us_quit */
+       0xfcb0fce4,
+/* 0x0217: ticks_to_us */
+       0xf100f8c0,
+       0xf00144d7,
+       0xedff00d3,
+/* 0x0223: timer */
+       0xf900f8ec,
+       0xf480f990,
+       0xf8981032,
+       0x0086b003,
+       0xbd531cf4,
+       0x3807f084,
        0xbd0008d0,
-       0x0887f004,
-       0xf00088cf,
-       0x1bf40284,
-       0x3487f020,
-       0xb80088cf,
-       0x0bf406e0,
-       0x06e8b809,
-/* 0x01eb: timer_reset */
-       0xf0191ef4,
-       0x0ed03407,
-       0x8004bd00,
-/* 0x01f6: timer_enable */
-       0x87f09a0e,
-       0x3807f001,
-       0xbd0008d0,
-/* 0x0201: timer_done */
-       0x1031f404,
-/* 0x0206: send_proc */
-       0x80f900f8,
-       0xe89890f9,
+       0x3487f004,
+       0x980088cf,
+       0x98bb9a09,
+       0x00e9bb02,
+       0xf003fe80,
+       0x88cf0887,
+       0x0284f000,
+       0xf0201bf4,
+       0x88cf3487,
+       0x06e0b800,
+       0xb8090bf4,
+       0x1cf406e8,
+/* 0x026d: timer_reset */
+       0x3407f00e,
+       0xbd000ed0,
+       0x9a0e8004,
+/* 0x0278: timer_enable */
+       0xf00187f0,
+       0x08d03807,
+/* 0x0283: timer_done */
+       0xf404bd00,
+       0x80fc1031,
+       0x00f890fc,
+/* 0x028c: send_proc */
+       0x90f980f9,
+       0x9805e898,
+       0x86f004e9,
+       0x0689b804,
+       0xc42a0bf4,
+       0x88940398,
+       0x1880b604,
+       0x98008ebb,
+       0x8a8000fa,
+       0x018d8000,
+       0x80028c80,
+       0x90b6038b,
+       0x0794f001,
+       0xf404e980,
+/* 0x02c6: send_done */
+       0x90fc0231,
+       0x00f880fc,
+/* 0x02cc: find */
+       0x87f080f9,
+       0x0131f458,
+/* 0x02d4: find_loop */
+       0xb8008a98,
+       0x0bf406ae,
+       0x5880b610,
+       0x026886b1,
+       0xf4f01bf4,
+/* 0x02ea: find_done */
+       0x8eb90132,
+       0xf880fc02,
+/* 0x02f1: send */
+       0xcc21f500,
+       0x9701f402,
+/* 0x02fa: recv */
+       0x90f900f8,
+       0xe89880f9,
        0x04e99805,
-       0xb80486f0,
+       0xb80132f4,
        0x0bf40689,
-       0x0398c42a,
-       0xb6048894,
-       0x8ebb1880,
-       0x00fa9800,
-       0x80008a80,
-       0x8c80018d,
-       0x038b8002,
-       0xf00190b6,
-       0xe9800794,
-       0x0231f404,
-/* 0x0240: send_done */
-       0x80fc90fc,
-/* 0x0246: find */
-       0x80f900f8,
-       0xf45887f0,
-/* 0x024e: find_loop */
-       0x8a980131,
-       0x06aeb800,
-       0xb6100bf4,
-       0x86b15880,
-       0x1bf40268,
-       0x0132f4f0,
-/* 0x0264: find_done */
-       0xfc028eb9,
-/* 0x026b: send */
-       0xf500f880,
-       0xf4024621,
-       0x00f89701,
-/* 0x0274: recv */
-       0x9805e898,
-       0x32f404e9,
-       0x0689b801,
-       0xc43d0bf4,
-       0x80b60389,
-       0x0784f001,
-       0x9805e880,
-       0xf0f902ea,
-       0xf9018ffe,
-       0x02efb9f0,
-       0xbb049994,
-       0xe0b600e9,
-       0x03eb9818,
-       0x9802ec98,
-       0xee9801ed,
-       0xfca5f900,
-       0x00f8fef0,
-       0xfc0131f4,
-/* 0x02bd: recv_done */
-/* 0x02bf: init */
-       0xf100f8f0,
-       0xcf010817,
-       0x11e70011,
-       0x14b60109,
-       0x0014fe08,
-       0x00e017f1,
-       0xf00013f0,
-       0x01d01c07,
-       0xf004bd00,
-       0x07f0ff17,
-       0x0001d014,
-       0x17f004bd,
-       0x0015f102,
-       0x1007f008,
-       0xbd0001d0,
-       0xe617f104,
-       0x0013f000,
-       0xf40010fe,
-       0x17f01031,
-       0x3807f001,
-       0xbd0001d0,
-       0x58f7f004,
-/* 0x0314: init_proc */
-       0xb001f198,
-       0x0bf40016,
-       0xb615f9fa,
-       0x0ef458f0,
-/* 0x0325: host_send */
-       0xb017f1f2,
-       0x0011cf04,
-       0x04a027f1,
-       0xb80022cf,
-       0x0bf40612,
-       0x071ec42f,
-       0xb704ee94,
-       0x980270e0,
+       0x0389c43d,
+       0xf00180b6,
+       0xe8800784,
+       0x02ea9805,
+       0x8ffef0f9,
+       0xb9f0f901,
+       0x999402ef,
+       0x00e9bb04,
+       0x9818e0b6,
        0xec9803eb,
        0x01ed9802,
-       0xf500ee98,
-       0xb6026b21,
-       0x1ec40110,
-       0xb007f10f,
-       0x000ed004,
-       0x0ef404bd,
-/* 0x0365: host_send_done */
-/* 0x0367: host_recv */
-       0xf100f8c3,
-       0xf14e4917,
-       0xb8525413,
-       0x0bf406e1,
-/* 0x0375: host_recv_wait */
-       0xcc17f1b3,
-       0x0011cf04,
-       0x04c827f1,
-       0xf00022cf,
-       0x12b80816,
-       0xec0bf406,
-       0xb60723c4,
-       0x30b70434,
-       0x3b8002f0,
-       0x023c8003,
-       0x80013d80,
-       0x20b6003e,
-       0x0f24f001,
-       0x04c807f1,
-       0xbd0002d0,
-       0x4027f004,
-       0xd00007f0,
-       0x04bd0002,
-/* 0x03be: host_init */
+       0xf900ee98,
+       0xfef0fca5,
+       0x31f400f8,
+/* 0x0347: recv_done */
+       0xfcf0fc01,
+       0xf890fc80,
+/* 0x034d: init */
+       0x0817f100,
+       0x0011cf01,
+       0x010911e7,
+       0xfe0814b6,
+       0x17f10014,
+       0x13f000e0,
+       0x1c07f000,
+       0xbd0001d0,
+       0xff17f004,
+       0xd01407f0,
+       0x04bd0001,
+       0xf10217f0,
+       0xf0080015,
+       0x01d01007,
+       0xf104bd00,
+       0xf000f617,
+       0x10fe0013,
+       0x1031f400,
+       0xf00117f0,
+       0x01d03807,
+       0xf004bd00,
+/* 0x03a2: init_proc */
+       0xf19858f7,
+       0x0016b001,
+       0xf9fa0bf4,
+       0x58f0b615,
+/* 0x03b3: mulu32_32_64 */
+       0xf9f20ef4,
+       0xf920f910,
+       0x9540f930,
+       0xd29510e1,
+       0xbdc4bd10,
+       0xc0edffb4,
+       0xb9301dff,
+       0x34f10234,
+       0x34b6ffff,
+       0x1045b610,
+       0xbb00c3bb,
+       0xe2ff01b4,
+       0x0234b930,
+       0xffff34f1,
+       0xb61034b6,
+       0xc3bb1045,
+       0x01b4bb00,
+       0xbb3012ff,
+       0x40fc00b3,
+       0x20fc30fc,
+       0x00f810fc,
+/* 0x0404: host_send */
+       0x04b017f1,
+       0xf10011cf,
+       0xcf04a027,
+       0x12b80022,
+       0x2f0bf406,
+       0x94071ec4,
+       0xe0b704ee,
+       0xeb980270,
+       0x02ec9803,
+       0x9801ed98,
+       0x21f500ee,
+       0x10b602f1,
+       0x0f1ec401,
+       0x04b007f1,
+       0xbd000ed0,
+       0xc30ef404,
+/* 0x0444: host_send_done */
+/* 0x0446: host_recv */
        0x17f100f8,
-       0x14b60080,
-       0x7015f110,
-       0xd007f102,
-       0x0001d004,
-       0x17f104bd,
-       0x14b60080,
-       0xf015f110,
-       0xdc07f102,
-       0x0001d004,
-       0x17f004bd,
-       0xc407f101,
-       0x0001d004,
-       0x00f804bd,
-/* 0x03f4: memx_func_enter */
+       0x13f14e49,
+       0xe1b85254,
+       0xb30bf406,
+/* 0x0454: host_recv_wait */
+       0x04cc17f1,
+       0xf10011cf,
+       0xcf04c827,
+       0x16f00022,
+       0x0612b808,
+       0xc4ec0bf4,
+       0x34b60723,
+       0xf030b704,
+       0x033b8002,
+       0x80023c80,
+       0x3e80013d,
+       0x0120b600,
+       0xf10f24f0,
+       0xd004c807,
+       0x04bd0002,
+       0xf04027f0,
+       0x02d00007,
+       0xf804bd00,
+/* 0x049d: host_init */
+       0x8017f100,
+       0x1014b600,
+       0x027015f1,
+       0x04d007f1,
+       0xbd0001d0,
+       0x8017f104,
+       0x1014b600,
+       0x02f015f1,
+       0x04dc07f1,
+       0xbd0001d0,
+       0x0117f004,
+       0x04c407f1,
+       0xbd0001d0,
+/* 0x04d3: memx_func_enter */
+       0xf100f804,
+       0xf1162067,
+       0xf1f55d77,
+       0xb9ffff73,
+       0x21f4026e,
+       0x02d8b904,
+       0xf90487fd,
+       0xfc80f960,
+       0xf4e0fcd0,
+       0x77f13321,
+       0x73f1fffe,
+       0x6eb9ffff,
+       0x0421f402,
+       0xfd02d8b9,
+       0x60f90487,
+       0xd0fc80f9,
+       0x21f4e0fc,
+       0xf067f133,
+       0x026eb926,
+       0xb90421f4,
+       0x87fd02d8,
+       0xf960f904,
+       0xfcd0fc80,
+       0x3321f4e0,
        0xf10467f0,
        0xd007e007,
        0x04bd0006,
-/* 0x0400: memx_func_enter_wait */
+/* 0x053c: memx_func_enter_wait */
        0x07c067f1,
        0xf00066cf,
        0x0bf40464,
-       0x001698f6,
-       0xf80410b6,
-/* 0x0415: memx_func_leave */
-       0x0467f000,
+       0x2c67f0f6,
+       0x800066cf,
+       0x00f8ee06,
+/* 0x0554: memx_func_leave */
+       0xcf2c67f0,
+       0x06800066,
+       0x0467f0ef,
        0x07e407f1,
        0xbd0006d0,
-/* 0x0421: memx_func_leave_wait */
+/* 0x0569: memx_func_leave_wait */
        0xc067f104,
        0x0066cf07,
        0xf40464f0,
-       0x00f8f61b,
-/* 0x0430: memx_func_wr32 */
+       0x67f1f61b,
+       0x77f126f0,
+       0x73f00001,
+       0x026eb900,
+       0xb90421f4,
+       0x87fd02d8,
+       0xf960f905,
+       0xfcd0fc80,
+       0x3321f4e0,
+       0x162067f1,
+       0xf4026eb9,
+       0xd8b90421,
+       0x0587fd02,
+       0x80f960f9,
+       0xe0fcd0fc,
+       0xf13321f4,
+       0xf00aa277,
+       0x6eb90073,
+       0x0421f402,
+       0xfd02d8b9,
+       0x60f90587,
+       0xd0fc80f9,
+       0x21f4e0fc,
+/* 0x05d3: memx_func_wait_vblank */
+       0xb600f833,
+       0x00f80410,
+/* 0x05d8: memx_func_wr32 */
        0x98001698,
        0x10b60115,
        0xf960f908,
@@ -1102,131 +1281,137 @@ uint32_t nvd0_pwr_code[] = {
        0x3321f4e0,
        0xf40242b6,
        0x00f8e91b,
-/* 0x044c: memx_func_wait */
+/* 0x05f4: memx_func_wait */
        0xcf2c87f0,
        0x1e980088,
        0x011d9800,
        0x98021c98,
        0x10b6031b,
-       0x7e21f410,
-/* 0x0466: memx_func_delay */
+       0x8621f410,
+/* 0x060e: memx_func_delay */
        0x1e9800f8,
        0x0410b600,
        0xf86721f4,
-/* 0x0471: memx_exec */
+/* 0x0619: memx_exec */
        0xf9e0f900,
        0x02c1b9d0,
-/* 0x047b: memx_exec_next */
+/* 0x0623: memx_exec_next */
        0x9802b2b9,
        0x10b60013,
-       0x10349504,
+       0xf034e704,
+       0xe033e701,
+       0x0132b601,
        0x980c30f0,
        0x55f9de35,
        0xf40612b8,
-       0xd0fcec1e,
+       0x0b98e41e,
+       0xef0c98ee,
+       0xf102cbbb,
+       0xcf07c4b7,
+       0xd0fc00bb,
        0x21f5e0fc,
-       0x00f8026b,
-/* 0x049c: memx_info */
-       0x03acc7f1,
+       0x00f802f1,
+/* 0x065c: memx_info */
+       0x03c0c7f1,
        0x0800b7f1,
-       0x026b21f5,
-/* 0x04aa: memx_recv */
+       0x02f121f5,
+/* 0x066a: memx_recv */
        0xd6b000f8,
-       0xc40bf401,
+       0xac0bf401,
        0xf400d6b0,
        0x00f8e90b,
-/* 0x04b8: memx_init */
-/* 0x04ba: perf_recv */
+/* 0x0678: memx_init */
+/* 0x067a: perf_recv */
        0x00f800f8,
-/* 0x04bc: perf_init */
-/* 0x04be: i2c_drive_scl */
+/* 0x067c: perf_init */
+/* 0x067e: i2c_drive_scl */
        0x36b000f8,
        0x0e0bf400,
        0x07e007f1,
        0xbd0001d0,
-/* 0x04cf: i2c_drive_scl_lo */
+/* 0x068f: i2c_drive_scl_lo */
        0xf100f804,
        0xd007e407,
        0x04bd0001,
-/* 0x04da: i2c_drive_sda */
+/* 0x069a: i2c_drive_sda */
        0x36b000f8,
        0x0e0bf400,
        0x07e007f1,
        0xbd0002d0,
-/* 0x04eb: i2c_drive_sda_lo */
+/* 0x06ab: i2c_drive_sda_lo */
        0xf100f804,
        0xd007e407,
        0x04bd0002,
-/* 0x04f6: i2c_sense_scl */
+/* 0x06b6: i2c_sense_scl */
        0x32f400f8,
        0xc437f101,
        0x0033cf07,
        0xf40431fd,
        0x31f4060b,
-/* 0x0509: i2c_sense_scl_done */
-/* 0x050b: i2c_sense_sda */
+/* 0x06c9: i2c_sense_scl_done */
+/* 0x06cb: i2c_sense_sda */
        0xf400f801,
        0x37f10132,
        0x33cf07c4,
        0x0432fd00,
        0xf4060bf4,
-/* 0x051e: i2c_sense_sda_done */
+/* 0x06de: i2c_sense_sda_done */
        0x00f80131,
-/* 0x0520: i2c_raise_scl */
+/* 0x06e0: i2c_raise_scl */
        0x47f140f9,
        0x37f00898,
-       0xbe21f501,
-/* 0x052d: i2c_raise_scl_wait */
-       0xe8e7f104,
+       0x7e21f501,
+/* 0x06ed: i2c_raise_scl_wait */
+       0xe8e7f106,
        0x6721f403,
-       0x04f621f5,
+       0x06b621f5,
        0xb60901f4,
        0x1bf40142,
-/* 0x0541: i2c_raise_scl_done */
+/* 0x0701: i2c_raise_scl_done */
        0xf840fcef,
-/* 0x0545: i2c_start */
-       0xf621f500,
-       0x0d11f404,
-       0x050b21f5,
+/* 0x0705: i2c_start */
+       0xb621f500,
+       0x0d11f406,
+       0x06cb21f5,
        0xf40611f4,
-/* 0x0556: i2c_start_rep */
+/* 0x0716: i2c_start_rep */
        0x37f0300e,
-       0xbe21f500,
-       0x0137f004,
-       0x04da21f5,
+       0x7e21f500,
+       0x0137f006,
+       0x069a21f5,
        0xb60076bb,
        0x50f90465,
        0xbb046594,
        0x50bd0256,
        0xfc0475fd,
-       0x2021f550,
-       0x0464b605,
-/* 0x0583: i2c_start_send */
+       0xe021f550,
+       0x0464b606,
+/* 0x0743: i2c_start_send */
        0xf01f11f4,
        0x21f50037,
-       0xe7f104da,
+       0xe7f1069a,
        0x21f41388,
        0x0037f067,
-       0x04be21f5,
+       0x067e21f5,
        0x1388e7f1,
-/* 0x059f: i2c_start_out */
+/* 0x075f: i2c_start_out */
        0xf86721f4,
-/* 0x05a1: i2c_stop */
+/* 0x0761: i2c_stop */
        0x0037f000,
-       0x04be21f5,
+       0x067e21f5,
        0xf50037f0,
-       0xf104da21,
+       0xf1069a21,
        0xf403e8e7,
        0x37f06721,
-       0xbe21f501,
-       0x88e7f104,
+       0x7e21f501,
+       0x88e7f106,
        0x6721f413,
        0xf50137f0,
-       0xf104da21,
+       0xf1069a21,
        0xf41388e7,
        0x00f86721,
-/* 0x05d4: i2c_bitw */
-       0x04da21f5,
+/* 0x0794: i2c_bitw */
+       0x069a21f5,
        0x03e8e7f1,
        0xbb6721f4,
        0x65b60076,
@@ -1234,18 +1419,18 @@ uint32_t nvd0_pwr_code[] = {
        0x56bb0465,
        0xfd50bd02,
        0x50fc0475,
-       0x052021f5,
+       0x06e021f5,
        0xf40464b6,
        0xe7f11811,
        0x21f41388,
        0x0037f067,
-       0x04be21f5,
+       0x067e21f5,
        0x1388e7f1,
-/* 0x0613: i2c_bitw_out */
+/* 0x07d3: i2c_bitw_out */
        0xf86721f4,
-/* 0x0615: i2c_bitr */
+/* 0x07d5: i2c_bitr */
        0x0137f000,
-       0x04da21f5,
+       0x069a21f5,
        0x03e8e7f1,
        0xbb6721f4,
        0x65b60076,
@@ -1253,19 +1438,19 @@ uint32_t nvd0_pwr_code[] = {
        0x56bb0465,
        0xfd50bd02,
        0x50fc0475,
-       0x052021f5,
+       0x06e021f5,
        0xf40464b6,
        0x21f51b11,
-       0x37f0050b,
-       0xbe21f500,
-       0x88e7f104,
+       0x37f006cb,
+       0x7e21f500,
+       0x88e7f106,
        0x6721f413,
        0xf4013cf0,
-/* 0x065a: i2c_bitr_done */
+/* 0x081a: i2c_bitr_done */
        0x00f80131,
-/* 0x065c: i2c_get_byte */
+/* 0x081c: i2c_get_byte */
        0xf00057f0,
-/* 0x0662: i2c_get_byte_next */
+/* 0x0822: i2c_get_byte_next */
        0x54b60847,
        0x0076bb01,
        0xf90465b6,
@@ -1273,7 +1458,7 @@ uint32_t nvd0_pwr_code[] = {
        0xbd0256bb,
        0x0475fd50,
        0x21f550fc,
-       0x64b60615,
+       0x64b607d5,
        0x2b11f404,
        0xb60553fd,
        0x1bf40142,
@@ -1283,12 +1468,12 @@ uint32_t nvd0_pwr_code[] = {
        0xbb046594,
        0x50bd0256,
        0xfc0475fd,
-       0xd421f550,
-       0x0464b605,
-/* 0x06ac: i2c_get_byte_done */
-/* 0x06ae: i2c_put_byte */
+       0x9421f550,
+       0x0464b607,
+/* 0x086c: i2c_get_byte_done */
+/* 0x086e: i2c_put_byte */
        0x47f000f8,
-/* 0x06b1: i2c_put_byte_next */
+/* 0x0871: i2c_put_byte_next */
        0x0142b608,
        0xbb3854ff,
        0x65b60076,
@@ -1296,7 +1481,7 @@ uint32_t nvd0_pwr_code[] = {
        0x56bb0465,
        0xfd50bd02,
        0x50fc0475,
-       0x05d421f5,
+       0x079421f5,
        0xf40464b6,
        0x46b03411,
        0xd81bf400,
@@ -1305,21 +1490,21 @@ uint32_t nvd0_pwr_code[] = {
        0xbb046594,
        0x50bd0256,
        0xfc0475fd,
-       0x1521f550,
-       0x0464b606,
+       0xd521f550,
+       0x0464b607,
        0xbb0f11f4,
        0x36b00076,
        0x061bf401,
-/* 0x0707: i2c_put_byte_done */
+/* 0x08c7: i2c_put_byte_done */
        0xf80132f4,
-/* 0x0709: i2c_addr */
+/* 0x08c9: i2c_addr */
        0x0076bb00,
        0xf90465b6,
        0x04659450,
        0xbd0256bb,
        0x0475fd50,
        0x21f550fc,
-       0x64b60545,
+       0x64b60705,
        0x2911f404,
        0x012ec3e7,
        0xfd0134b6,
@@ -1329,30 +1514,30 @@ uint32_t nvd0_pwr_code[] = {
        0x0256bb04,
        0x75fd50bd,
        0xf550fc04,
-       0xb606ae21,
-/* 0x074e: i2c_addr_done */
+       0xb6086e21,
+/* 0x090e: i2c_addr_done */
        0x00f80464,
-/* 0x0750: i2c_acquire_addr */
+/* 0x0910: i2c_acquire_addr */
        0xb6f8cec7,
        0xe0b705e4,
        0x00f8d014,
-/* 0x075c: i2c_acquire */
-       0x075021f5,
+/* 0x091c: i2c_acquire */
+       0x091021f5,
        0xf00421f4,
        0x21f403d9,
-/* 0x076b: i2c_release */
+/* 0x092b: i2c_release */
        0xf500f833,
-       0xf4075021,
+       0xf4091021,
        0xdaf00421,
        0x3321f403,
-/* 0x077a: i2c_recv */
+/* 0x093a: i2c_recv */
        0x32f400f8,
        0xf8c1c701,
        0xb00214b6,
        0x1ff52816,
        0x13a0013a,
-       0x32980bd4,
-       0xac13a000,
+       0x32980be8,
+       0xc013a000,
        0x0031980b,
        0xf90231f4,
        0xf9e0f9d0,
@@ -1364,8 +1549,8 @@ uint32_t nvd0_pwr_code[] = {
        0xbb046594,
        0x50bd0256,
        0xfc0475fd,
-       0x5c21f550,
-       0x0464b607,
+       0x1c21f550,
+       0x0464b609,
        0xd6b0d0fc,
        0xb31bf500,
        0x0057f000,
@@ -1374,8 +1559,8 @@ uint32_t nvd0_pwr_code[] = {
        0xbb046594,
        0x50bd0256,
        0xfc0475fd,
-       0x0921f550,
-       0x0464b607,
+       0xc921f550,
+       0x0464b608,
        0x00d011f5,
        0xbbe0c5c7,
        0x65b60076,
@@ -1383,7 +1568,7 @@ uint32_t nvd0_pwr_code[] = {
        0x56bb0465,
        0xfd50bd02,
        0x50fc0475,
-       0x06ae21f5,
+       0x086e21f5,
        0xf50464b6,
        0xf000ad11,
        0x76bb0157,
@@ -1392,7 +1577,7 @@ uint32_t nvd0_pwr_code[] = {
        0x0256bb04,
        0x75fd50bd,
        0xf550fc04,
-       0xb6070921,
+       0xb608c921,
        0x11f50464,
        0x76bb008a,
        0x0465b600,
@@ -1400,7 +1585,7 @@ uint32_t nvd0_pwr_code[] = {
        0x0256bb04,
        0x75fd50bd,
        0xf550fc04,
-       0xb6065c21,
+       0xb6081c21,
        0x11f40464,
        0xe05bcb6a,
        0xb60076bb,
@@ -1408,38 +1593,38 @@ uint32_t nvd0_pwr_code[] = {
        0xbb046594,
        0x50bd0256,
        0xfc0475fd,
-       0xa121f550,
-       0x0464b605,
+       0x6121f550,
+       0x0464b607,
        0xbd025bb9,
        0x430ef474,
-/* 0x0880: i2c_recv_not_rd08 */
+/* 0x0a40: i2c_recv_not_rd08 */
        0xf401d6b0,
        0x57f03d1b,
-       0x0921f500,
-       0x3311f407,
+       0xc921f500,
+       0x3311f408,
        0xf5e0c5c7,
-       0xf406ae21,
+       0xf4086e21,
        0x57f02911,
-       0x0921f500,
-       0x1f11f407,
+       0xc921f500,
+       0x1f11f408,
        0xf5e0b5c7,
-       0xf406ae21,
+       0xf4086e21,
        0x21f51511,
-       0x74bd05a1,
+       0x74bd0761,
        0xf408c5c7,
        0x32f4091b,
        0x030ef402,
-/* 0x08c0: i2c_recv_not_wr08 */
-/* 0x08c0: i2c_recv_done */
+/* 0x0a80: i2c_recv_not_wr08 */
+/* 0x0a80: i2c_recv_done */
        0xf5f8cec7,
-       0xfc076b21,
+       0xfc092b21,
        0xf4d0fce0,
        0x7cb90a12,
-       0x6b21f502,
-/* 0x08d5: i2c_recv_exit */
-/* 0x08d7: i2c_init */
+       0xf121f502,
+/* 0x0a95: i2c_recv_exit */
+/* 0x0a97: i2c_init */
        0xf800f802,
-/* 0x08d9: test_recv */
+/* 0x0a99: test_recv */
        0xd817f100,
        0x0011cf05,
        0xf10110b6,
@@ -1447,29 +1632,29 @@ uint32_t nvd0_pwr_code[] = {
        0x04bd0001,
        0xd900e7f1,
        0x134fe3f1,
-       0x01b621f5,
-/* 0x08fa: test_init */
+       0x022321f5,
+/* 0x0aba: test_init */
        0xe7f100f8,
        0x21f50800,
-       0x00f801b6,
-/* 0x0904: idle_recv */
-/* 0x0906: idle */
+       0x00f80223,
+/* 0x0ac4: idle_recv */
+/* 0x0ac6: idle */
        0x31f400f8,
        0xd417f100,
        0x0011cf05,
        0xf10110b6,
        0xd005d407,
        0x04bd0001,
-/* 0x091c: idle_loop */
+/* 0x0adc: idle_loop */
        0xf45817f0,
-/* 0x0922: idle_proc */
-/* 0x0922: idle_proc_exec */
+/* 0x0ae2: idle_proc */
+/* 0x0ae2: idle_proc_exec */
        0x10f90232,
        0xf5021eb9,
-       0xfc027421,
+       0xfc02fa21,
        0x0911f410,
        0xf40231f4,
-/* 0x0936: idle_proc_next */
+/* 0x0af6: idle_proc_next */
        0x10b6ef0e,
        0x061fb858,
        0xf4e61bf4,
@@ -1521,4 +1706,20 @@ uint32_t nvd0_pwr_code[] = {
        0x00000000,
        0x00000000,
        0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
 };
index 574acfa44c8c78f327dcd9d59cc7e1b6e9b2bc1f..522e3079f82428e401030c8d34c7124865ec7a3d 100644 (file)
 #define MEMX_MSG_EXEC 1
 
 /* MEMX: script opcode definitions */
-#define MEMX_ENTER  0
-#define MEMX_LEAVE  1
-#define MEMX_WR32   2
-#define MEMX_WAIT   3
-#define MEMX_DELAY  4
+#define MEMX_ENTER  1
+#define MEMX_LEAVE  2
+#define MEMX_WR32   3
+#define MEMX_WAIT   4
+#define MEMX_DELAY  5
+#define MEMX_VBLANK 6
 
 /* I2C_: message identifiers */
 #define I2C__MSG_RD08 0
index def6a9ac68cfa5b6db7c52897df5e4af19c3a5c2..65eaa2546cad2ce5abbcbc32eea9ac008c8bfd2f 100644 (file)
@@ -20,10 +20,11 @@ memx_out(struct nouveau_memx *memx)
        struct nouveau_pwr *ppwr = memx->ppwr;
        int i;
 
-       if (memx->c.size) {
+       if (memx->c.mthd) {
                nv_wr32(ppwr, 0x10a1c4, (memx->c.size << 16) | memx->c.mthd);
                for (i = 0; i < memx->c.size; i++)
                        nv_wr32(ppwr, 0x10a1c4, memx->c.data[i]);
+               memx->c.mthd = 0;
                memx->c.size = 0;
        }
 }
@@ -32,7 +33,7 @@ static void
 memx_cmd(struct nouveau_memx *memx, u32 mthd, u32 size, u32 data[])
 {
        if ((memx->c.size + size >= ARRAY_SIZE(memx->c.data)) ||
-           (memx->c.size && memx->c.mthd != mthd))
+           (memx->c.mthd && memx->c.mthd != mthd))
                memx_out(memx);
        memcpy(&memx->c.data[memx->c.size], data, size * sizeof(data[0]));
        memx->c.size += size;
@@ -62,8 +63,7 @@ nouveau_memx_init(struct nouveau_pwr *ppwr, struct nouveau_memx **pmemx)
                nv_wr32(ppwr, 0x10a580, 0x00000003);
        } while (nv_rd32(ppwr, 0x10a580) != 0x00000003);
        nv_wr32(ppwr, 0x10a1c0, 0x01000000 | memx->base);
-       nv_wr32(ppwr, 0x10a1c4, 0x00010000 | MEMX_ENTER);
-       nv_wr32(ppwr, 0x10a1c4, 0x00000000);
+
        return 0;
 }
 
@@ -78,7 +78,6 @@ nouveau_memx_fini(struct nouveau_memx **pmemx, bool exec)
        memx_out(memx);
 
        /* release data segment access */
-       nv_wr32(ppwr, 0x10a1c4, 0x00000000 | MEMX_LEAVE);
        finish = nv_rd32(ppwr, 0x10a1c0) & 0x00ffffff;
        nv_wr32(ppwr, 0x10a580, 0x00000000);
 
@@ -88,6 +87,8 @@ nouveau_memx_fini(struct nouveau_memx **pmemx, bool exec)
                                 memx->base, finish);
        }
 
+       nv_debug(memx->ppwr, "Exec took %uns, PPWR_IN %08x\n",
+                reply[0], reply[1]);
        kfree(memx);
        return 0;
 }
@@ -117,4 +118,51 @@ nouveau_memx_nsec(struct nouveau_memx *memx, u32 nsec)
        memx_out(memx); /* fuc can't handle multiple */
 }
 
+void
+nouveau_memx_wait_vblank(struct nouveau_memx *memx)
+{
+       struct nouveau_pwr *ppwr = memx->ppwr;
+       u32 heads, x, y, px = 0;
+       int i, head_sync;
+
+       if (nv_device(ppwr)->chipset < 0xd0) {
+               heads = nv_rd32(ppwr, 0x610050);
+               for (i = 0; i < 2; i++) {
+                       /* Heuristic: sync to head with biggest resolution */
+                       if (heads & (2 << (i << 3))) {
+                               x = nv_rd32(ppwr, 0x610b40 + (0x540 * i));
+                               y = (x & 0xffff0000) >> 16;
+                               x &= 0x0000ffff;
+                               if ((x * y) > px) {
+                                       px = (x * y);
+                                       head_sync = i;
+                               }
+                       }
+               }
+       }
+
+       if (px == 0) {
+               nv_debug(memx->ppwr, "WAIT VBLANK !NO ACTIVE HEAD\n");
+               return;
+       }
+
+       nv_debug(memx->ppwr, "WAIT VBLANK HEAD%d\n", head_sync);
+       memx_cmd(memx, MEMX_VBLANK, 1, (u32[]){ head_sync });
+       memx_out(memx); /* fuc can't handle multiple */
+}
+
+void
+nouveau_memx_block(struct nouveau_memx *memx)
+{
+       nv_debug(memx->ppwr, "   HOST BLOCKED\n");
+       memx_cmd(memx, MEMX_ENTER, 0, NULL);
+}
+
+void
+nouveau_memx_unblock(struct nouveau_memx *memx)
+{
+       nv_debug(memx->ppwr, "   HOST UNBLOCKED\n");
+       memx_cmd(memx, MEMX_LEAVE, 0, NULL);
+}
+
 #endif
index 016990a8252c682f7bc7c93ead9fa8a9c5394979..3656d605168fce2295d86f64d5eff0da2bc5dede 100644 (file)
@@ -31,6 +31,8 @@
 #include <subdev/gpio.h>
 #include <subdev/timer.h>
 
+#include <subdev/bios/fan.h>
+
 static int
 nouveau_fan_update(struct nouveau_fan *fan, bool immediate, int target)
 {
@@ -275,8 +277,11 @@ nouveau_therm_fan_ctor(struct nouveau_therm *therm)
        /* other random init... */
        nouveau_therm_fan_set_defaults(therm);
        nvbios_perf_fan_parse(bios, &priv->fan->perf);
-       if (nvbios_therm_fan_parse(bios, &priv->fan->bios))
-               nv_error(therm, "parsing the thermal table failed\n");
+       if (!nvbios_fan_parse(bios, &priv->fan->bios)) {
+               nv_debug(therm, "parsing the fan table failed\n");
+               if (nvbios_therm_fan_parse(bios, &priv->fan->bios))
+                       nv_error(therm, "parsing both fan tables failed\n");
+       }
        nouveau_therm_fan_safety_checks(therm);
        return 0;
 }
index 9a5c07340263305f1310d1e6a3520808c2606049..c629d7f2a6a44025224e4123c5273b4705a2cf68 100644 (file)
@@ -25,6 +25,8 @@
 
 #include <core/option.h>
 #include <subdev/gpio.h>
+#include <subdev/bios.h>
+#include <subdev/bios/fan.h>
 
 #include "priv.h"
 
@@ -86,11 +88,15 @@ nouveau_fanpwm_create(struct nouveau_therm *therm, struct dcb_gpio_func *func)
 {
        struct nouveau_device *device = nv_device(therm);
        struct nouveau_therm_priv *tpriv = (void *)therm;
+       struct nouveau_bios *bios = nouveau_bios(therm);
        struct nouveau_fanpwm_priv *priv;
+       struct nvbios_therm_fan fan;
        u32 divs, duty;
 
+       nvbios_fan_parse(bios, &fan);
+
        if (!nouveau_boolopt(device->cfgopt, "NvFanPWM", func->param) ||
-           !therm->pwm_ctrl ||
+           !therm->pwm_ctrl || fan.type == NVBIOS_THERM_FAN_TOGGLE ||
             therm->pwm_get(therm, func->line, &divs, &duty) == -ENODEV)
                return -ENODEV;
 
diff --git a/drivers/gpu/drm/nouveau/core/subdev/therm/gm107.c b/drivers/gpu/drm/nouveau/core/subdev/therm/gm107.c
new file mode 100644 (file)
index 0000000..668cf33
--- /dev/null
@@ -0,0 +1,93 @@
+/*
+ * Copyright 2014 Martin Peres
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Martin Peres
+ */
+
+#include "priv.h"
+
+struct gm107_therm_priv {
+       struct nouveau_therm_priv base;
+};
+
+static int
+gm107_fan_pwm_ctrl(struct nouveau_therm *therm, int line, bool enable)
+{
+       /* nothing to do, it seems hardwired */
+       return 0;
+}
+
+static int
+gm107_fan_pwm_get(struct nouveau_therm *therm, int line, u32 *divs, u32 *duty)
+{
+       *divs = nv_rd32(therm, 0x10eb20) & 0x1fff;
+       *duty = nv_rd32(therm, 0x10eb24) & 0x1fff;
+       return 0;
+}
+
+static int
+gm107_fan_pwm_set(struct nouveau_therm *therm, int line, u32 divs, u32 duty)
+{
+       nv_mask(therm, 0x10eb10, 0x1fff, divs); /* keep the high bits */
+       nv_wr32(therm, 0x10eb14, duty | 0x80000000);
+       return 0;
+}
+
+static int
+gm107_fan_pwm_clock(struct nouveau_therm *therm, int line)
+{
+       return nv_device(therm)->crystal * 1000;
+}
+
+static int
+gm107_therm_ctor(struct nouveau_object *parent,
+               struct nouveau_object *engine,
+               struct nouveau_oclass *oclass, void *data, u32 size,
+               struct nouveau_object **pobject)
+{
+       struct gm107_therm_priv *priv;
+       int ret;
+
+       ret = nouveau_therm_create(parent, engine, oclass, &priv);
+       *pobject = nv_object(priv);
+       if (ret)
+               return ret;
+
+       priv->base.base.pwm_ctrl = gm107_fan_pwm_ctrl;
+       priv->base.base.pwm_get = gm107_fan_pwm_get;
+       priv->base.base.pwm_set = gm107_fan_pwm_set;
+       priv->base.base.pwm_clock = gm107_fan_pwm_clock;
+       priv->base.base.temp_get = nv84_temp_get;
+       priv->base.base.fan_sense = nva3_therm_fan_sense;
+       priv->base.sensor.program_alarms = nouveau_therm_program_alarms_polling;
+       return nouveau_therm_preinit(&priv->base.base);
+}
+
+struct nouveau_oclass
+gm107_therm_oclass = {
+       .handle = NV_SUBDEV(THERM, 0x117),
+       .ofuncs = &(struct nouveau_ofuncs) {
+               .ctor = gm107_therm_ctor,
+               .dtor = _nouveau_therm_dtor,
+               .init = nvd0_therm_init,
+               .fini = nv84_therm_fini,
+       },
+};
index 1d15c52fad0c3030e4a2c103a2a69b3529aa1b19..14e2e09bfc24ce8ae8cf05b554a7eae637d82f44 100644 (file)
@@ -24,6 +24,7 @@
  */
 
 #include "priv.h"
+#include <subdev/fuse.h>
 
 struct nv84_therm_priv {
        struct nouveau_therm_priv base;
@@ -32,7 +33,25 @@ struct nv84_therm_priv {
 int
 nv84_temp_get(struct nouveau_therm *therm)
 {
-       return nv_rd32(therm, 0x20400);
+       struct nouveau_fuse *fuse = nouveau_fuse(therm);
+
+       if (nv_ro32(fuse, 0x1a8) == 1)
+               return nv_rd32(therm, 0x20400);
+       else
+               return -ENODEV;
+}
+
+void
+nv84_sensor_setup(struct nouveau_therm *therm)
+{
+       struct nouveau_fuse *fuse = nouveau_fuse(therm);
+
+       /* enable temperature reading for cards with insane defaults */
+       if (nv_ro32(fuse, 0x1a8) == 1) {
+               nv_mask(therm, 0x20008, 0x80008000, 0x80000000);
+               nv_mask(therm, 0x2000c, 0x80000003, 0x00000000);
+               mdelay(20); /* wait for the temperature to stabilize */
+       }
 }
 
 static void
@@ -170,6 +189,21 @@ nv84_therm_intr(struct nouveau_subdev *subdev)
        spin_unlock_irqrestore(&priv->sensor.alarm_program_lock, flags);
 }
 
+static int
+nv84_therm_init(struct nouveau_object *object)
+{
+       struct nv84_therm_priv *priv = (void *)object;
+       int ret;
+
+       ret = nouveau_therm_init(&priv->base.base);
+       if (ret)
+               return ret;
+
+       nv84_sensor_setup(&priv->base.base);
+
+       return 0;
+}
+
 static int
 nv84_therm_ctor(struct nouveau_object *parent,
                struct nouveau_object *engine,
@@ -228,7 +262,7 @@ nv84_therm_oclass = {
        .ofuncs = &(struct nouveau_ofuncs) {
                .ctor = nv84_therm_ctor,
                .dtor = _nouveau_therm_dtor,
-               .init = _nouveau_therm_init,
+               .init = nv84_therm_init,
                .fini = nv84_therm_fini,
        },
 };
index 0478b2e3fb1de76ee34e40a56e0d6209ffff1d60..7893357a7e9f474c1d777527933406a27c4f3330 100644 (file)
@@ -51,6 +51,8 @@ nva3_therm_init(struct nouveau_object *object)
        if (ret)
                return ret;
 
+       nv84_sensor_setup(&priv->base.base);
+
        /* enable fan tach, count revolutions per-second */
        nv_mask(priv, 0x00e720, 0x00000003, 0x00000002);
        if (tach->func != DCB_GPIO_UNUSED) {
index bbf117be572f4617cff0fd06907fb2a13977ae93..b70f7cc649b87a8973456ca4a5f4f3bd28f4f3b6 100644 (file)
@@ -114,7 +114,7 @@ nvd0_fan_pwm_clock(struct nouveau_therm *therm, int line)
                return nv_device(therm)->crystal * 1000 / 10;
 }
 
-static int
+int
 nvd0_therm_init(struct nouveau_object *object)
 {
        struct nvd0_therm_priv *priv = (void *)object;
@@ -150,6 +150,8 @@ nvd0_therm_ctor(struct nouveau_object *parent,
        if (ret)
                return ret;
 
+       nv84_sensor_setup(&priv->base.base);
+
        priv->base.base.pwm_ctrl = nvd0_fan_pwm_ctrl;
        priv->base.base.pwm_get = nvd0_fan_pwm_get;
        priv->base.base.pwm_set = nvd0_fan_pwm_set;
index 916fca5c78162488a23e65e11188cda9b2d0e0eb..7dba8c281a0b3fe8a19ec2d93bb38c104f811ec7 100644 (file)
@@ -145,10 +145,13 @@ int nv50_fan_pwm_get(struct nouveau_therm *, int, u32 *, u32 *);
 int nv50_fan_pwm_set(struct nouveau_therm *, int, u32, u32);
 int nv50_fan_pwm_clock(struct nouveau_therm *, int);
 int nv84_temp_get(struct nouveau_therm *therm);
+void nv84_sensor_setup(struct nouveau_therm *therm);
 int nv84_therm_fini(struct nouveau_object *object, bool suspend);
 
 int nva3_therm_fan_sense(struct nouveau_therm *);
 
+int nvd0_therm_init(struct nouveau_object *object);
+
 int nouveau_fanpwm_create(struct nouveau_therm *, struct dcb_gpio_func *);
 int nouveau_fantog_create(struct nouveau_therm *, struct dcb_gpio_func *);
 int nouveau_fannil_create(struct nouveau_therm *);
index 7dd680ff2f6f63683f34e39a1d7821f3c73c140c..f75a683bd47a6ddf38e3ec13260f657a8c525c65 100644 (file)
@@ -296,7 +296,7 @@ nouveau_vm_get(struct nouveau_vm *vm, u64 size, u32 page_shift,
        int ret;
 
        mutex_lock(&nv_subdev(vmm)->mutex);
-       ret = nouveau_mm_head(&vm->mm, page_shift, msize, msize, align,
+       ret = nouveau_mm_head(&vm->mm, 0, page_shift, msize, msize, align,
                             &vma->node);
        if (unlikely(ret != 0)) {
                mutex_unlock(&nv_subdev(vmm)->mutex);
index b90aa5c1f90a1790cc5a2b83cdc40f006a6663b9..fca6a1f9c20c5f9957f8f66a1a399a73d54f3873 100644 (file)
@@ -1127,7 +1127,7 @@ nv04_crtc_create(struct drm_device *dev, int crtc_num)
        drm_mode_crtc_set_gamma_size(&nv_crtc->base, 256);
 
        ret = nouveau_bo_new(dev, 64*64*4, 0x100, TTM_PL_FLAG_VRAM,
-                            0, 0x0000, NULL, &nv_crtc->cursor.nvbo);
+                            0, 0x0000, NULL, NULL, &nv_crtc->cursor.nvbo);
        if (!ret) {
                ret = nouveau_bo_pin(nv_crtc->cursor.nvbo, TTM_PL_FLAG_VRAM);
                if (!ret) {
index b36afcbbc83febc9ccdee1cc63442b1a3ed8a46c..1e9056a8df945917750e9d7effb576e69a9351d9 100644 (file)
@@ -97,7 +97,8 @@ nv10_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
                  uint32_t src_w, uint32_t src_h)
 {
        struct nvif_device *dev = &nouveau_drm(plane->dev)->device;
-       struct nouveau_plane *nv_plane = (struct nouveau_plane *)plane;
+       struct nouveau_plane *nv_plane =
+               container_of(plane, struct nouveau_plane, base);
        struct nouveau_framebuffer *nv_fb = nouveau_framebuffer(fb);
        struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
        struct nouveau_bo *cur = nv_plane->cur;
@@ -173,7 +174,8 @@ static int
 nv10_disable_plane(struct drm_plane *plane)
 {
        struct nvif_device *dev = &nouveau_drm(plane->dev)->device;
-       struct nouveau_plane *nv_plane = (struct nouveau_plane *)plane;
+       struct nouveau_plane *nv_plane =
+               container_of(plane, struct nouveau_plane, base);
 
        nvif_wr32(dev, NV_PVIDEO_STOP, 1);
        if (nv_plane->cur) {
@@ -224,7 +226,8 @@ nv_set_property(struct drm_plane *plane,
                struct drm_property *property,
                uint64_t value)
 {
-       struct nouveau_plane *nv_plane = (struct nouveau_plane *)plane;
+       struct nouveau_plane *nv_plane =
+               container_of(plane, struct nouveau_plane, base);
 
        if (property == nv_plane->props.colorkey)
                nv_plane->colorkey = value;
@@ -344,7 +347,8 @@ nv04_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
                  uint32_t src_w, uint32_t src_h)
 {
        struct nvif_device *dev = &nouveau_drm(plane->dev)->device;
-       struct nouveau_plane *nv_plane = (struct nouveau_plane *)plane;
+       struct nouveau_plane *nv_plane =
+               container_of(plane, struct nouveau_plane, base);
        struct nouveau_framebuffer *nv_fb = nouveau_framebuffer(fb);
        struct nouveau_bo *cur = nv_plane->cur;
        uint32_t overlay = 1;
@@ -423,7 +427,8 @@ static int
 nv04_disable_plane(struct drm_plane *plane)
 {
        struct nvif_device *dev = &nouveau_drm(plane->dev)->device;
-       struct nouveau_plane *nv_plane = (struct nouveau_plane *)plane;
+       struct nouveau_plane *nv_plane =
+               container_of(plane, struct nouveau_plane, base);
 
        nvif_mask(dev, NV_PVIDEO_OVERLAY, 1, 0);
        nvif_wr32(dev, NV_PVIDEO_OE_STATE, 0);
index 615714c1727d6b6870b3ec2698bc204c74ab196a..a24faa5e2a2ae67a5075cb2f9506b9f93fa66083 100644 (file)
@@ -448,7 +448,7 @@ nouveau_abi16_ioctl_notifierobj_alloc(ABI16_IOCTL_ARGS)
        list_add(&ntfy->head, &chan->notifiers);
        ntfy->handle = info->handle;
 
-       ret = nouveau_mm_head(&chan->heap, 1, info->size, info->size, 1,
+       ret = nouveau_mm_head(&chan->heap, 0, 1, info->size, info->size, 1,
                              &ntfy->node);
        if (ret)
                goto done;
index 01da508625f27e4ad1c27393b8eaa928634564aa..3d474ac03f8847c7985c2c664a88bed1cfa189b0 100644 (file)
@@ -88,13 +88,13 @@ nv10_bo_get_tile_region(struct drm_device *dev, int i)
 
 static void
 nv10_bo_put_tile_region(struct drm_device *dev, struct nouveau_drm_tile *tile,
-                       struct nouveau_fence *fence)
+                       struct fence *fence)
 {
        struct nouveau_drm *drm = nouveau_drm(dev);
 
        if (tile) {
                spin_lock(&drm->tile.lock);
-               tile->fence = nouveau_fence_ref(fence);
+               tile->fence = (struct nouveau_fence *)fence_get(fence);
                tile->used = false;
                spin_unlock(&drm->tile.lock);
        }
@@ -181,7 +181,7 @@ nouveau_bo_fixup_align(struct nouveau_bo *nvbo, u32 flags,
 int
 nouveau_bo_new(struct drm_device *dev, int size, int align,
               uint32_t flags, uint32_t tile_mode, uint32_t tile_flags,
-              struct sg_table *sg,
+              struct sg_table *sg, struct reservation_object *robj,
               struct nouveau_bo **pnvbo)
 {
        struct nouveau_drm *drm = nouveau_drm(dev);
@@ -230,7 +230,7 @@ nouveau_bo_new(struct drm_device *dev, int size, int align,
        ret = ttm_bo_init(&drm->ttm.bdev, &nvbo->bo, size,
                          type, &nvbo->placement,
                          align >> PAGE_SHIFT, false, NULL, acc_size, sg,
-                         nouveau_bo_del_ttm);
+                         robj, nouveau_bo_del_ttm);
        if (ret) {
                /* ttm will call nouveau_bo_del_ttm if it fails.. */
                return ret;
@@ -241,16 +241,16 @@ nouveau_bo_new(struct drm_device *dev, int size, int align,
 }
 
 static void
-set_placement_list(uint32_t *pl, unsigned *n, uint32_t type, uint32_t flags)
+set_placement_list(struct ttm_place *pl, unsigned *n, uint32_t type, uint32_t flags)
 {
        *n = 0;
 
        if (type & TTM_PL_FLAG_VRAM)
-               pl[(*n)++] = TTM_PL_FLAG_VRAM | flags;
+               pl[(*n)++].flags = TTM_PL_FLAG_VRAM | flags;
        if (type & TTM_PL_FLAG_TT)
-               pl[(*n)++] = TTM_PL_FLAG_TT | flags;
+               pl[(*n)++].flags = TTM_PL_FLAG_TT | flags;
        if (type & TTM_PL_FLAG_SYSTEM)
-               pl[(*n)++] = TTM_PL_FLAG_SYSTEM | flags;
+               pl[(*n)++].flags = TTM_PL_FLAG_SYSTEM | flags;
 }
 
 static void
@@ -258,6 +258,7 @@ set_placement_range(struct nouveau_bo *nvbo, uint32_t type)
 {
        struct nouveau_drm *drm = nouveau_bdev(nvbo->bo.bdev);
        u32 vram_pages = drm->device.info.ram_size >> PAGE_SHIFT;
+       unsigned i, fpfn, lpfn;
 
        if (drm->device.info.family == NV_DEVICE_INFO_V0_CELSIUS &&
            nvbo->tile_mode && (type & TTM_PL_FLAG_VRAM) &&
@@ -269,11 +270,19 @@ set_placement_range(struct nouveau_bo *nvbo, uint32_t type)
                 * at the same time.
                 */
                if (nvbo->tile_flags & NOUVEAU_GEM_TILE_ZETA) {
-                       nvbo->placement.fpfn = vram_pages / 2;
-                       nvbo->placement.lpfn = ~0;
+                       fpfn = vram_pages / 2;
+                       lpfn = ~0;
                } else {
-                       nvbo->placement.fpfn = 0;
-                       nvbo->placement.lpfn = vram_pages / 2;
+                       fpfn = 0;
+                       lpfn = vram_pages / 2;
+               }
+               for (i = 0; i < nvbo->placement.num_placement; ++i) {
+                       nvbo->placements[i].fpfn = fpfn;
+                       nvbo->placements[i].lpfn = lpfn;
+               }
+               for (i = 0; i < nvbo->placement.num_busy_placement; ++i) {
+                       nvbo->busy_placements[i].fpfn = fpfn;
+                       nvbo->busy_placements[i].lpfn = lpfn;
                }
        }
 }
@@ -961,13 +970,14 @@ nouveau_bo_move_m2mf(struct ttm_buffer_object *bo, int evict, bool intr,
        }
 
        mutex_lock_nested(&cli->mutex, SINGLE_DEPTH_NESTING);
-       ret = nouveau_fence_sync(bo->sync_obj, chan);
+       ret = nouveau_fence_sync(nouveau_bo(bo), chan, true, intr);
        if (ret == 0) {
                ret = drm->ttm.move(chan, bo, &bo->mem, new_mem);
                if (ret == 0) {
                        ret = nouveau_fence_new(chan, false, &fence);
                        if (ret == 0) {
-                               ret = ttm_bo_move_accel_cleanup(bo, fence,
+                               ret = ttm_bo_move_accel_cleanup(bo,
+                                                               &fence->base,
                                                                evict,
                                                                no_wait_gpu,
                                                                new_mem);
@@ -1041,12 +1051,15 @@ static int
 nouveau_bo_move_flipd(struct ttm_buffer_object *bo, bool evict, bool intr,
                      bool no_wait_gpu, struct ttm_mem_reg *new_mem)
 {
-       u32 placement_memtype = TTM_PL_FLAG_TT | TTM_PL_MASK_CACHING;
+       struct ttm_place placement_memtype = {
+               .fpfn = 0,
+               .lpfn = 0,
+               .flags = TTM_PL_FLAG_TT | TTM_PL_MASK_CACHING
+       };
        struct ttm_placement placement;
        struct ttm_mem_reg tmp_mem;
        int ret;
 
-       placement.fpfn = placement.lpfn = 0;
        placement.num_placement = placement.num_busy_placement = 1;
        placement.placement = placement.busy_placement = &placement_memtype;
 
@@ -1074,12 +1087,15 @@ static int
 nouveau_bo_move_flips(struct ttm_buffer_object *bo, bool evict, bool intr,
                      bool no_wait_gpu, struct ttm_mem_reg *new_mem)
 {
-       u32 placement_memtype = TTM_PL_FLAG_TT | TTM_PL_MASK_CACHING;
+       struct ttm_place placement_memtype = {
+               .fpfn = 0,
+               .lpfn = 0,
+               .flags = TTM_PL_FLAG_TT | TTM_PL_MASK_CACHING
+       };
        struct ttm_placement placement;
        struct ttm_mem_reg tmp_mem;
        int ret;
 
-       placement.fpfn = placement.lpfn = 0;
        placement.num_placement = placement.num_busy_placement = 1;
        placement.placement = placement.busy_placement = &placement_memtype;
 
@@ -1152,8 +1168,9 @@ nouveau_bo_vm_cleanup(struct ttm_buffer_object *bo,
 {
        struct nouveau_drm *drm = nouveau_bdev(bo->bdev);
        struct drm_device *dev = drm->dev;
+       struct fence *fence = reservation_object_get_excl(bo->resv);
 
-       nv10_bo_put_tile_region(dev, *old_tile, bo->sync_obj);
+       nv10_bo_put_tile_region(dev, *old_tile, fence);
        *old_tile = new_tile;
 }
 
@@ -1197,9 +1214,7 @@ nouveau_bo_move(struct ttm_buffer_object *bo, bool evict, bool intr,
        }
 
        /* Fallback to software copy. */
-       spin_lock(&bo->bdev->fence_lock);
        ret = ttm_bo_wait(bo, true, intr, no_wait_gpu);
-       spin_unlock(&bo->bdev->fence_lock);
        if (ret == 0)
                ret = ttm_bo_move_memcpy(bo, evict, no_wait_gpu, new_mem);
 
@@ -1294,7 +1309,7 @@ nouveau_ttm_fault_reserve_notify(struct ttm_buffer_object *bo)
        struct nouveau_bo *nvbo = nouveau_bo(bo);
        struct nvif_device *device = &drm->device;
        u32 mappable = nv_device_resource_len(nvkm_device(device), 1) >> PAGE_SHIFT;
-       int ret;
+       int i, ret;
 
        /* as long as the bo isn't in vram, and isn't tiled, we've got
         * nothing to do here.
@@ -1319,9 +1334,16 @@ nouveau_ttm_fault_reserve_notify(struct ttm_buffer_object *bo)
            bo->mem.start + bo->mem.num_pages < mappable)
                return 0;
 
+       for (i = 0; i < nvbo->placement.num_placement; ++i) {
+               nvbo->placements[i].fpfn = 0;
+               nvbo->placements[i].lpfn = mappable;
+       }
+
+       for (i = 0; i < nvbo->placement.num_busy_placement; ++i) {
+               nvbo->busy_placements[i].fpfn = 0;
+               nvbo->busy_placements[i].lpfn = mappable;
+       }
 
-       nvbo->placement.fpfn = 0;
-       nvbo->placement.lpfn = mappable;
        nouveau_bo_placement_set(nvbo, TTM_PL_FLAG_VRAM, 0);
        return nouveau_bo_validate(nvbo, false, false);
 }
@@ -1436,47 +1458,14 @@ nouveau_ttm_tt_unpopulate(struct ttm_tt *ttm)
 }
 
 void
-nouveau_bo_fence(struct nouveau_bo *nvbo, struct nouveau_fence *fence)
-{
-       struct nouveau_fence *new_fence = nouveau_fence_ref(fence);
-       struct nouveau_fence *old_fence = NULL;
-
-       spin_lock(&nvbo->bo.bdev->fence_lock);
-       old_fence = nvbo->bo.sync_obj;
-       nvbo->bo.sync_obj = new_fence;
-       spin_unlock(&nvbo->bo.bdev->fence_lock);
-
-       nouveau_fence_unref(&old_fence);
-}
-
-static void
-nouveau_bo_fence_unref(void **sync_obj)
-{
-       nouveau_fence_unref((struct nouveau_fence **)sync_obj);
-}
-
-static void *
-nouveau_bo_fence_ref(void *sync_obj)
+nouveau_bo_fence(struct nouveau_bo *nvbo, struct nouveau_fence *fence, bool exclusive)
 {
-       return nouveau_fence_ref(sync_obj);
-}
+       struct reservation_object *resv = nvbo->bo.resv;
 
-static bool
-nouveau_bo_fence_signalled(void *sync_obj)
-{
-       return nouveau_fence_done(sync_obj);
-}
-
-static int
-nouveau_bo_fence_wait(void *sync_obj, bool lazy, bool intr)
-{
-       return nouveau_fence_wait(sync_obj, lazy, intr);
-}
-
-static int
-nouveau_bo_fence_flush(void *sync_obj)
-{
-       return 0;
+       if (exclusive)
+               reservation_object_add_excl_fence(resv, &fence->base);
+       else if (fence)
+               reservation_object_add_shared_fence(resv, &fence->base);
 }
 
 struct ttm_bo_driver nouveau_bo_driver = {
@@ -1489,11 +1478,6 @@ struct ttm_bo_driver nouveau_bo_driver = {
        .move_notify = nouveau_bo_move_ntfy,
        .move = nouveau_bo_move,
        .verify_access = nouveau_bo_verify_access,
-       .sync_obj_signaled = nouveau_bo_fence_signalled,
-       .sync_obj_wait = nouveau_bo_fence_wait,
-       .sync_obj_flush = nouveau_bo_fence_flush,
-       .sync_obj_unref = nouveau_bo_fence_unref,
-       .sync_obj_ref = nouveau_bo_fence_ref,
        .fault_reserve_notify = &nouveau_ttm_fault_reserve_notify,
        .io_mem_reserve = &nouveau_ttm_io_mem_reserve,
        .io_mem_free = &nouveau_ttm_io_mem_free,
index ff17c1f432fc9e9312ace42491385bb76226b381..22d2c764d80bd17c9fe755abc56b225722eee513 100644 (file)
@@ -1,6 +1,8 @@
 #ifndef __NOUVEAU_BO_H__
 #define __NOUVEAU_BO_H__
 
+#include <drm/drm_gem.h>
+
 struct nouveau_channel;
 struct nouveau_fence;
 struct nouveau_vma;
@@ -9,8 +11,8 @@ struct nouveau_bo {
        struct ttm_buffer_object bo;
        struct ttm_placement placement;
        u32 valid_domains;
-       u32 placements[3];
-       u32 busy_placements[3];
+       struct ttm_place placements[3];
+       struct ttm_place busy_placements[3];
        struct ttm_bo_kmap_obj kmap;
        struct list_head head;
 
@@ -68,6 +70,7 @@ extern struct ttm_bo_driver nouveau_bo_driver;
 void nouveau_bo_move_init(struct nouveau_drm *);
 int  nouveau_bo_new(struct drm_device *, int size, int align, u32 flags,
                    u32 tile_mode, u32 tile_flags, struct sg_table *sg,
+                   struct reservation_object *robj,
                    struct nouveau_bo **);
 int  nouveau_bo_pin(struct nouveau_bo *, u32 flags);
 int  nouveau_bo_unpin(struct nouveau_bo *);
@@ -78,7 +81,7 @@ u16  nouveau_bo_rd16(struct nouveau_bo *, unsigned index);
 void nouveau_bo_wr16(struct nouveau_bo *, unsigned index, u16 val);
 u32  nouveau_bo_rd32(struct nouveau_bo *, unsigned index);
 void nouveau_bo_wr32(struct nouveau_bo *, unsigned index, u32 val);
-void nouveau_bo_fence(struct nouveau_bo *, struct nouveau_fence *);
+void nouveau_bo_fence(struct nouveau_bo *, struct nouveau_fence *, bool exclusive);
 int  nouveau_bo_validate(struct nouveau_bo *, bool interruptible,
                         bool no_wait_gpu);
 
index 3440fc999f2f3290b3557ea495a26afb65fda874..589dbb582da200c543b2ee04e9296d58e0d70e1f 100644 (file)
@@ -36,7 +36,7 @@
 #include "nouveau_abi16.h"
 
 MODULE_PARM_DESC(vram_pushbuf, "Create DMA push buffers in VRAM");
-static int nouveau_vram_pushbuf;
+int nouveau_vram_pushbuf;
 module_param_named(vram_pushbuf, nouveau_vram_pushbuf, int, 0400);
 
 int
@@ -106,7 +106,7 @@ nouveau_channel_prep(struct nouveau_drm *drm, struct nvif_device *device,
        if (nouveau_vram_pushbuf)
                target = TTM_PL_FLAG_VRAM;
 
-       ret = nouveau_bo_new(drm->dev, size, 0, target, 0, 0, NULL,
+       ret = nouveau_bo_new(drm->dev, size, 0, target, 0, 0, NULL, NULL,
                            &chan->push.buffer);
        if (ret == 0) {
                ret = nouveau_bo_pin(chan->push.buffer, target);
index 20163709d608c788707658000b51c019dbb4b7d5..8309c24ee6981f63e3dc5257235ce122e5840de5 100644 (file)
@@ -47,4 +47,6 @@ int  nouveau_channel_new(struct nouveau_drm *, struct nvif_device *,
 void nouveau_channel_del(struct nouveau_channel **);
 int  nouveau_channel_idle(struct nouveau_channel *);
 
+extern int nouveau_vram_pushbuf;
+
 #endif
index 1ec44c83e91932ffe82237143ea93ca6b94546c4..c8ac9482cf2ed12de114636b004bdd66813bc4ba 100644 (file)
 #include <nvif/event.h>
 
 MODULE_PARM_DESC(tv_disable, "Disable TV-out detection");
-static int nouveau_tv_disable = 0;
+int nouveau_tv_disable = 0;
 module_param_named(tv_disable, nouveau_tv_disable, int, 0400);
 
 MODULE_PARM_DESC(ignorelid, "Ignore ACPI lid status");
-static int nouveau_ignorelid = 0;
+int nouveau_ignorelid = 0;
 module_param_named(ignorelid, nouveau_ignorelid, int, 0400);
 
 MODULE_PARM_DESC(duallink, "Allow dual-link TMDS (default: enabled)");
-static int nouveau_duallink = 1;
+int nouveau_duallink = 1;
 module_param_named(duallink, nouveau_duallink, int, 0400);
 
 struct nouveau_encoder *
index 68029d041dd2fd856e636fe6e6b48a0971c625c4..629a380c708555b26522987036b458a01fb2983f 100644 (file)
@@ -105,4 +105,8 @@ nouveau_crtc_connector_get(struct nouveau_crtc *nv_crtc)
 struct drm_connector *
 nouveau_connector_create(struct drm_device *, int index);
 
+extern int nouveau_tv_disable;
+extern int nouveau_ignorelid;
+extern int nouveau_duallink;
+
 #endif /* __NOUVEAU_CONNECTOR_H__ */
index 4a21b2b06ce29beece2bcd102d30f005fcbc1307..a88e6927f5713e29a0db95a769dd16401f9f920f 100644 (file)
@@ -126,7 +126,7 @@ nouveau_display_scanoutpos_head(struct drm_crtc *crtc, int *vpos, int *hpos,
        if (etime) *etime = ns_to_ktime(args.scan.time[1]);
 
        if (*vpos < 0)
-               ret |= DRM_SCANOUTPOS_INVBL;
+               ret |= DRM_SCANOUTPOS_IN_VBLANK;
        return ret;
 }
 
@@ -657,7 +657,7 @@ nouveau_page_flip_emit(struct nouveau_channel *chan,
        spin_unlock_irqrestore(&dev->event_lock, flags);
 
        /* Synchronize with the old framebuffer */
-       ret = nouveau_fence_sync(old_bo->bo.sync_obj, chan);
+       ret = nouveau_fence_sync(old_bo, chan, false, false);
        if (ret)
                goto fail;
 
@@ -716,19 +716,24 @@ nouveau_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb,
        }
 
        mutex_lock(&cli->mutex);
-
-       /* synchronise rendering channel with the kernel's channel */
-       spin_lock(&new_bo->bo.bdev->fence_lock);
-       fence = nouveau_fence_ref(new_bo->bo.sync_obj);
-       spin_unlock(&new_bo->bo.bdev->fence_lock);
-       ret = nouveau_fence_sync(fence, chan);
-       nouveau_fence_unref(&fence);
+       ret = ttm_bo_reserve(&new_bo->bo, true, false, false, NULL);
        if (ret)
                goto fail_unpin;
 
-       ret = ttm_bo_reserve(&old_bo->bo, true, false, false, NULL);
-       if (ret)
+       /* synchronise rendering channel with the kernel's channel */
+       ret = nouveau_fence_sync(new_bo, chan, false, true);
+       if (ret) {
+               ttm_bo_unreserve(&new_bo->bo);
                goto fail_unpin;
+       }
+
+       if (new_bo != old_bo) {
+               ttm_bo_unreserve(&new_bo->bo);
+
+               ret = ttm_bo_reserve(&old_bo->bo, true, false, false, NULL);
+               if (ret)
+                       goto fail_unpin;
+       }
 
        /* Initialize a page flip struct */
        *s = (struct nouveau_page_flip_state)
@@ -774,7 +779,7 @@ nouveau_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb,
        /* Update the crtc struct and cleanup */
        crtc->primary->fb = fb;
 
-       nouveau_bo_fence(old_bo, fence);
+       nouveau_bo_fence(old_bo, fence, false);
        ttm_bo_unreserve(&old_bo->bo);
        if (old_bo != new_bo)
                nouveau_bo_unpin(old_bo);
index 3ed32dd9030364cd2a366726f9e6af09b05f21e3..57238076049f6fe16717ba6626bca954b1910aeb 100644 (file)
@@ -51,6 +51,7 @@
 #include "nouveau_fence.h"
 #include "nouveau_debugfs.h"
 #include "nouveau_usif.h"
+#include "nouveau_connector.h"
 
 MODULE_PARM_DESC(config, "option string to pass to driver core");
 static char *nouveau_config;
@@ -73,7 +74,9 @@ MODULE_PARM_DESC(runpm, "disable (0), force enable (1), optimus only default (-1
 int nouveau_runtime_pm = -1;
 module_param_named(runpm, nouveau_runtime_pm, int, 0400);
 
-static struct drm_driver driver;
+static struct drm_driver driver_stub;
+static struct drm_driver driver_pci;
+static struct drm_driver driver_platform;
 
 static u64
 nouveau_pci_name(struct pci_dev *pdev)
@@ -322,7 +325,7 @@ static int nouveau_drm_probe(struct pci_dev *pdev,
 
        pci_set_master(pdev);
 
-       ret = drm_get_pci_dev(pdev, pent, &driver);
+       ret = drm_get_pci_dev(pdev, pent, &driver_pci);
        if (ret) {
                nouveau_object_ref(NULL, (struct nouveau_object **)&device);
                return ret;
@@ -831,7 +834,7 @@ nouveau_driver_fops = {
 };
 
 static struct drm_driver
-driver = {
+driver_stub = {
        .driver_features =
                DRIVER_USE_AGP |
                DRIVER_GEM | DRIVER_MODESET | DRIVER_PRIME | DRIVER_RENDER,
@@ -1002,6 +1005,23 @@ static int nouveau_pmops_runtime_idle(struct device *dev)
        return 1;
 }
 
+static void nouveau_display_options(void)
+{
+       DRM_DEBUG_DRIVER("Loading Nouveau with parameters:\n");
+
+       DRM_DEBUG_DRIVER("... tv_disable   : %d\n", nouveau_tv_disable);
+       DRM_DEBUG_DRIVER("... ignorelid    : %d\n", nouveau_ignorelid);
+       DRM_DEBUG_DRIVER("... duallink     : %d\n", nouveau_duallink);
+       DRM_DEBUG_DRIVER("... nofbaccel    : %d\n", nouveau_nofbaccel);
+       DRM_DEBUG_DRIVER("... config       : %s\n", nouveau_config);
+       DRM_DEBUG_DRIVER("... debug        : %s\n", nouveau_debug);
+       DRM_DEBUG_DRIVER("... noaccel      : %d\n", nouveau_noaccel);
+       DRM_DEBUG_DRIVER("... modeset      : %d\n", nouveau_modeset);
+       DRM_DEBUG_DRIVER("... runpm        : %d\n", nouveau_runtime_pm);
+       DRM_DEBUG_DRIVER("... vram_pushbuf : %d\n", nouveau_vram_pushbuf);
+       DRM_DEBUG_DRIVER("... pstate       : %d\n", nouveau_pstate);
+}
+
 static const struct dev_pm_ops nouveau_pm_ops = {
        .suspend = nouveau_pmops_suspend,
        .resume = nouveau_pmops_resume,
@@ -1037,7 +1057,7 @@ nouveau_platform_device_create_(struct platform_device *pdev, int size,
        if (err)
                return ERR_PTR(err);
 
-       drm = drm_dev_alloc(&driver, &pdev->dev);
+       drm = drm_dev_alloc(&driver_platform, &pdev->dev);
        if (!drm) {
                err = -ENOMEM;
                goto err_free;
@@ -1062,6 +1082,13 @@ EXPORT_SYMBOL(nouveau_platform_device_create_);
 static int __init
 nouveau_drm_init(void)
 {
+       driver_pci = driver_stub;
+       driver_pci.set_busid = drm_pci_set_busid;
+       driver_platform = driver_stub;
+       driver_platform.set_busid = drm_platform_set_busid;
+
+       nouveau_display_options();
+
        if (nouveau_modeset == -1) {
 #ifdef CONFIG_VGA_CONSOLE
                if (vgacon_text_force())
@@ -1073,7 +1100,7 @@ nouveau_drm_init(void)
                return 0;
 
        nouveau_register_dsm_handler();
-       return drm_pci_init(&driver, &nouveau_drm_pci_driver);
+       return drm_pci_init(&driver_pci, &nouveau_drm_pci_driver);
 }
 
 static void __exit
@@ -1082,7 +1109,7 @@ nouveau_drm_exit(void)
        if (!nouveau_modeset)
                return;
 
-       drm_pci_exit(&driver, &nouveau_drm_pci_driver);
+       drm_pci_exit(&driver_pci, &nouveau_drm_pci_driver);
        nouveau_unregister_dsm_handler();
 }
 
index b02b02452c854c5fdab9ddd985dc12ce0f12e7af..8ae36f265fb8867b6092a48fcde8b06450148b40 100644 (file)
@@ -10,7 +10,7 @@
 
 #define DRIVER_MAJOR           1
 #define DRIVER_MINOR           2
-#define DRIVER_PATCHLEVEL      0
+#define DRIVER_PATCHLEVEL      1
 
 /*
  * 1.1.1:
@@ -26,6 +26,8 @@
  * 1.2.0:
  *     - object api exposed to userspace
  *     - fermi,kepler,maxwell zbc
+ * 1.2.1:
+ *      - allow concurrent access to bo's mapped read/write.
  */
 
 #include <nvif/client.h>
index 49fe6075cc7c50c79d47d2ac24c273e536ac3159..593ef8a2a069e16b4fdf96e9c95b67ca8ebd1b95 100644 (file)
@@ -52,7 +52,7 @@
 #include "nouveau_crtc.h"
 
 MODULE_PARM_DESC(nofbaccel, "Disable fbcon acceleration");
-static int nouveau_nofbaccel = 0;
+int nouveau_nofbaccel = 0;
 module_param_named(nofbaccel, nouveau_nofbaccel, int, 0400);
 
 static void
@@ -308,7 +308,8 @@ static int
 nouveau_fbcon_create(struct drm_fb_helper *helper,
                     struct drm_fb_helper_surface_size *sizes)
 {
-       struct nouveau_fbdev *fbcon = (struct nouveau_fbdev *)helper;
+       struct nouveau_fbdev *fbcon =
+               container_of(helper, struct nouveau_fbdev, helper);
        struct drm_device *dev = fbcon->dev;
        struct nouveau_drm *drm = nouveau_drm(dev);
        struct nvif_device *device = &drm->device;
index 0b465c7d3907cb1a07667b667032dbe3b052c71b..6208e70e4a1cfdd16a949db884a605466d0ced38 100644 (file)
@@ -73,5 +73,8 @@ void nouveau_fbcon_accel_save_disable(struct drm_device *dev);
 void nouveau_fbcon_accel_restore(struct drm_device *dev);
 
 void nouveau_fbcon_output_poll_changed(struct drm_device *dev);
+
+extern int nouveau_nofbaccel;
+
 #endif /* __NV50_FBCON_H__ */
 
index 0a93114158cde37b41a311d612e6205eb7a98ccb..515cd9aebb9982d1c0c0c06f1deaf4d0c7bf3e5c 100644 (file)
@@ -28,6 +28,7 @@
 
 #include <linux/ktime.h>
 #include <linux/hrtimer.h>
+#include <trace/events/fence.h>
 
 #include <nvif/notify.h>
 #include <nvif/event.h>
 #include "nouveau_dma.h"
 #include "nouveau_fence.h"
 
-struct fence_work {
-       struct work_struct base;
-       struct list_head head;
-       void (*func)(void *);
-       void *data;
-};
+static const struct fence_ops nouveau_fence_ops_uevent;
+static const struct fence_ops nouveau_fence_ops_legacy;
+
+static inline struct nouveau_fence *
+from_fence(struct fence *fence)
+{
+       return container_of(fence, struct nouveau_fence, base);
+}
+
+static inline struct nouveau_fence_chan *
+nouveau_fctx(struct nouveau_fence *fence)
+{
+       return container_of(fence->base.lock, struct nouveau_fence_chan, lock);
+}
 
 static void
 nouveau_fence_signal(struct nouveau_fence *fence)
 {
-       struct fence_work *work, *temp;
+       fence_signal_locked(&fence->base);
+       list_del(&fence->head);
+
+       if (test_bit(FENCE_FLAG_USER_BITS, &fence->base.flags)) {
+               struct nouveau_fence_chan *fctx = nouveau_fctx(fence);
 
-       list_for_each_entry_safe(work, temp, &fence->work, head) {
-               schedule_work(&work->base);
-               list_del(&work->head);
+               if (!--fctx->notify_ref)
+                       nvif_notify_put(&fctx->notify);
        }
 
-       fence->channel = NULL;
-       list_del(&fence->head);
+       fence_put(&fence->base);
+}
+
+static struct nouveau_fence *
+nouveau_local_fence(struct fence *fence, struct nouveau_drm *drm) {
+       struct nouveau_fence_priv *priv = (void*)drm->fence;
+
+       if (fence->ops != &nouveau_fence_ops_legacy &&
+           fence->ops != &nouveau_fence_ops_uevent)
+               return NULL;
+
+       if (fence->context < priv->context_base ||
+           fence->context >= priv->context_base + priv->contexts)
+               return NULL;
+
+       return from_fence(fence);
 }
 
 void
 nouveau_fence_context_del(struct nouveau_fence_chan *fctx)
 {
-       struct nouveau_fence *fence, *fnext;
-       spin_lock(&fctx->lock);
-       list_for_each_entry_safe(fence, fnext, &fctx->pending, head) {
+       struct nouveau_fence *fence;
+
+       nvif_notify_fini(&fctx->notify);
+
+       spin_lock_irq(&fctx->lock);
+       while (!list_empty(&fctx->pending)) {
+               fence = list_entry(fctx->pending.next, typeof(*fence), head);
+
                nouveau_fence_signal(fence);
+               fence->channel = NULL;
        }
-       spin_unlock(&fctx->lock);
+       spin_unlock_irq(&fctx->lock);
+}
+
+static void
+nouveau_fence_context_put(struct kref *fence_ref)
+{
+       kfree(container_of(fence_ref, struct nouveau_fence_chan, fence_ref));
 }
 
 void
-nouveau_fence_context_new(struct nouveau_fence_chan *fctx)
+nouveau_fence_context_free(struct nouveau_fence_chan *fctx)
+{
+       kref_put(&fctx->fence_ref, nouveau_fence_context_put);
+}
+
+static void
+nouveau_fence_update(struct nouveau_channel *chan, struct nouveau_fence_chan *fctx)
+{
+       struct nouveau_fence *fence;
+
+       u32 seq = fctx->read(chan);
+
+       while (!list_empty(&fctx->pending)) {
+               fence = list_entry(fctx->pending.next, typeof(*fence), head);
+
+               if ((int)(seq - fence->base.seqno) < 0)
+                       return;
+
+               nouveau_fence_signal(fence);
+       }
+}
+
+static int
+nouveau_fence_wait_uevent_handler(struct nvif_notify *notify)
 {
+       struct nouveau_fence_chan *fctx =
+               container_of(notify, typeof(*fctx), notify);
+       unsigned long flags;
+
+       spin_lock_irqsave(&fctx->lock, flags);
+       if (!list_empty(&fctx->pending)) {
+               struct nouveau_fence *fence;
+
+               fence = list_entry(fctx->pending.next, typeof(*fence), head);
+               nouveau_fence_update(fence->channel, fctx);
+       }
+       spin_unlock_irqrestore(&fctx->lock, flags);
+
+       /* Always return keep here. NVIF refcount is handled with nouveau_fence_update */
+       return NVIF_NOTIFY_KEEP;
+}
+
+void
+nouveau_fence_context_new(struct nouveau_channel *chan, struct nouveau_fence_chan *fctx)
+{
+       struct nouveau_fence_priv *priv = (void*)chan->drm->fence;
+       struct nouveau_cli *cli = (void *)nvif_client(chan->object);
+       int ret;
+
        INIT_LIST_HEAD(&fctx->flip);
        INIT_LIST_HEAD(&fctx->pending);
        spin_lock_init(&fctx->lock);
+       fctx->context = priv->context_base + chan->chid;
+
+       if (chan == chan->drm->cechan)
+               strcpy(fctx->name, "copy engine channel");
+       else if (chan == chan->drm->channel)
+               strcpy(fctx->name, "generic kernel channel");
+       else
+               strcpy(fctx->name, nvkm_client(&cli->base)->name);
+
+       kref_init(&fctx->fence_ref);
+       if (!priv->uevent)
+               return;
+
+       ret = nvif_notify_init(chan->object, NULL,
+                        nouveau_fence_wait_uevent_handler, false,
+                        G82_CHANNEL_DMA_V0_NTFY_UEVENT,
+                        &(struct nvif_notify_uevent_req) { },
+                        sizeof(struct nvif_notify_uevent_req),
+                        sizeof(struct nvif_notify_uevent_rep),
+                        &fctx->notify);
+
+       WARN_ON(ret);
 }
 
+struct nouveau_fence_work {
+       struct work_struct work;
+       struct fence_cb cb;
+       void (*func)(void *);
+       void *data;
+};
+
 static void
 nouveau_fence_work_handler(struct work_struct *kwork)
 {
-       struct fence_work *work = container_of(kwork, typeof(*work), base);
+       struct nouveau_fence_work *work = container_of(kwork, typeof(*work), work);
        work->func(work->data);
        kfree(work);
 }
 
+static void nouveau_fence_work_cb(struct fence *fence, struct fence_cb *cb)
+{
+       struct nouveau_fence_work *work = container_of(cb, typeof(*work), cb);
+
+       schedule_work(&work->work);
+}
+
 void
-nouveau_fence_work(struct nouveau_fence *fence,
+nouveau_fence_work(struct fence *fence,
                   void (*func)(void *), void *data)
 {
-       struct nouveau_channel *chan = fence->channel;
-       struct nouveau_fence_chan *fctx;
-       struct fence_work *work = NULL;
+       struct nouveau_fence_work *work;
 
-       if (nouveau_fence_done(fence)) {
-               func(data);
-               return;
-       }
+       if (fence_is_signaled(fence))
+               goto err;
 
-       fctx = chan->fence;
        work = kmalloc(sizeof(*work), GFP_KERNEL);
        if (!work) {
-               WARN_ON(nouveau_fence_wait(fence, false, false));
-               func(data);
-               return;
-       }
-
-       spin_lock(&fctx->lock);
-       if (!fence->channel) {
-               spin_unlock(&fctx->lock);
-               kfree(work);
-               func(data);
-               return;
+               /*
+                * this might not be a nouveau fence any more,
+                * so force a lazy wait here
+                */
+               WARN_ON(nouveau_fence_wait((struct nouveau_fence *)fence,
+                                          true, false));
+               goto err;
        }
 
-       INIT_WORK(&work->base, nouveau_fence_work_handler);
+       INIT_WORK(&work->work, nouveau_fence_work_handler);
        work->func = func;
        work->data = data;
-       list_add(&work->head, &fence->work);
-       spin_unlock(&fctx->lock);
-}
-
-static void
-nouveau_fence_update(struct nouveau_channel *chan)
-{
-       struct nouveau_fence_chan *fctx = chan->fence;
-       struct nouveau_fence *fence, *fnext;
 
-       spin_lock(&fctx->lock);
-       list_for_each_entry_safe(fence, fnext, &fctx->pending, head) {
-               if (fctx->read(chan) < fence->sequence)
-                       break;
+       if (fence_add_callback(fence, &work->cb, nouveau_fence_work_cb) < 0)
+               goto err_free;
+       return;
 
-               nouveau_fence_signal(fence);
-               nouveau_fence_unref(&fence);
-       }
-       spin_unlock(&fctx->lock);
+err_free:
+       kfree(work);
+err:
+       func(data);
 }
 
 int
 nouveau_fence_emit(struct nouveau_fence *fence, struct nouveau_channel *chan)
 {
        struct nouveau_fence_chan *fctx = chan->fence;
+       struct nouveau_fence_priv *priv = (void*)chan->drm->fence;
        int ret;
 
        fence->channel  = chan;
        fence->timeout  = jiffies + (15 * HZ);
-       fence->sequence = ++fctx->sequence;
 
+       if (priv->uevent)
+               fence_init(&fence->base, &nouveau_fence_ops_uevent,
+                          &fctx->lock, fctx->context, ++fctx->sequence);
+       else
+               fence_init(&fence->base, &nouveau_fence_ops_legacy,
+                          &fctx->lock, fctx->context, ++fctx->sequence);
+       kref_get(&fctx->fence_ref);
+
+       trace_fence_emit(&fence->base);
        ret = fctx->emit(fence);
        if (!ret) {
-               kref_get(&fence->kref);
-               spin_lock(&fctx->lock);
+               fence_get(&fence->base);
+               spin_lock_irq(&fctx->lock);
+               nouveau_fence_update(chan, fctx);
                list_add_tail(&fence->head, &fctx->pending);
-               spin_unlock(&fctx->lock);
+               spin_unlock_irq(&fctx->lock);
        }
 
        return ret;
@@ -161,114 +273,70 @@ nouveau_fence_emit(struct nouveau_fence *fence, struct nouveau_channel *chan)
 bool
 nouveau_fence_done(struct nouveau_fence *fence)
 {
-       if (fence->channel)
-               nouveau_fence_update(fence->channel);
-       return !fence->channel;
-}
+       if (fence->base.ops == &nouveau_fence_ops_legacy ||
+           fence->base.ops == &nouveau_fence_ops_uevent) {
+               struct nouveau_fence_chan *fctx = nouveau_fctx(fence);
+               unsigned long flags;
 
-struct nouveau_fence_wait {
-       struct nouveau_fence_priv *priv;
-       struct nvif_notify notify;
-};
+               if (test_bit(FENCE_FLAG_SIGNALED_BIT, &fence->base.flags))
+                       return true;
 
-static int
-nouveau_fence_wait_uevent_handler(struct nvif_notify *notify)
-{
-       struct nouveau_fence_wait *wait =
-               container_of(notify, typeof(*wait), notify);
-       wake_up_all(&wait->priv->waiting);
-       return NVIF_NOTIFY_KEEP;
+               spin_lock_irqsave(&fctx->lock, flags);
+               nouveau_fence_update(fence->channel, fctx);
+               spin_unlock_irqrestore(&fctx->lock, flags);
+       }
+       return fence_is_signaled(&fence->base);
 }
 
-static int
-nouveau_fence_wait_uevent(struct nouveau_fence *fence, bool intr)
-
+static long
+nouveau_fence_wait_legacy(struct fence *f, bool intr, long wait)
 {
-       struct nouveau_channel *chan = fence->channel;
-       struct nouveau_fence_priv *priv = chan->drm->fence;
-       struct nouveau_fence_wait wait = { .priv = priv };
-       int ret = 0;
+       struct nouveau_fence *fence = from_fence(f);
+       unsigned long sleep_time = NSEC_PER_MSEC / 1000;
+       unsigned long t = jiffies, timeout = t + wait;
 
-       ret = nvif_notify_init(chan->object, NULL,
-                              nouveau_fence_wait_uevent_handler, false,
-                              G82_CHANNEL_DMA_V0_NTFY_UEVENT,
-                              &(struct nvif_notify_uevent_req) {
-                              },
-                              sizeof(struct nvif_notify_uevent_req),
-                              sizeof(struct nvif_notify_uevent_rep),
-                              &wait.notify);
-       if (ret)
-               return ret;
+       while (!nouveau_fence_done(fence)) {
+               ktime_t kt;
 
-       nvif_notify_get(&wait.notify);
-
-       if (fence->timeout) {
-               unsigned long timeout = fence->timeout - jiffies;
-
-               if (time_before(jiffies, fence->timeout)) {
-                       if (intr) {
-                               ret = wait_event_interruptible_timeout(
-                                               priv->waiting,
-                                               nouveau_fence_done(fence),
-                                               timeout);
-                       } else {
-                               ret = wait_event_timeout(priv->waiting,
-                                               nouveau_fence_done(fence),
-                                               timeout);
-                       }
-               }
+               t = jiffies;
 
-               if (ret >= 0) {
-                       fence->timeout = jiffies + ret;
-                       if (time_after_eq(jiffies, fence->timeout))
-                               ret = -EBUSY;
-               }
-       } else {
-               if (intr) {
-                       ret = wait_event_interruptible(priv->waiting,
-                                       nouveau_fence_done(fence));
-               } else {
-                       wait_event(priv->waiting, nouveau_fence_done(fence));
+               if (wait != MAX_SCHEDULE_TIMEOUT && time_after_eq(t, timeout)) {
+                       __set_current_state(TASK_RUNNING);
+                       return 0;
                }
+
+               __set_current_state(intr ? TASK_INTERRUPTIBLE :
+                                          TASK_UNINTERRUPTIBLE);
+
+               kt = ktime_set(0, sleep_time);
+               schedule_hrtimeout(&kt, HRTIMER_MODE_REL);
+               sleep_time *= 2;
+               if (sleep_time > NSEC_PER_MSEC)
+                       sleep_time = NSEC_PER_MSEC;
+
+               if (intr && signal_pending(current))
+                       return -ERESTARTSYS;
        }
 
-       nvif_notify_fini(&wait.notify);
-       if (unlikely(ret < 0))
-               return ret;
+       __set_current_state(TASK_RUNNING);
 
-       return 0;
+       return timeout - t;
 }
 
-int
-nouveau_fence_wait(struct nouveau_fence *fence, bool lazy, bool intr)
+static int
+nouveau_fence_wait_busy(struct nouveau_fence *fence, bool intr)
 {
-       struct nouveau_channel *chan = fence->channel;
-       struct nouveau_fence_priv *priv = chan ? chan->drm->fence : NULL;
-       unsigned long sleep_time = NSEC_PER_MSEC / 1000;
-       ktime_t t;
        int ret = 0;
 
-       while (priv && priv->uevent && lazy && !nouveau_fence_done(fence)) {
-               ret = nouveau_fence_wait_uevent(fence, intr);
-               if (ret < 0)
-                       return ret;
-       }
-
        while (!nouveau_fence_done(fence)) {
-               if (fence->timeout && time_after_eq(jiffies, fence->timeout)) {
+               if (time_after_eq(jiffies, fence->timeout)) {
                        ret = -EBUSY;
                        break;
                }
 
-               __set_current_state(intr ? TASK_INTERRUPTIBLE :
-                                          TASK_UNINTERRUPTIBLE);
-               if (lazy) {
-                       t = ktime_set(0, sleep_time);
-                       schedule_hrtimeout(&t, HRTIMER_MODE_REL);
-                       sleep_time *= 2;
-                       if (sleep_time > NSEC_PER_MSEC)
-                               sleep_time = NSEC_PER_MSEC;
-               }
+               __set_current_state(intr ?
+                                   TASK_INTERRUPTIBLE :
+                                   TASK_UNINTERRUPTIBLE);
 
                if (intr && signal_pending(current)) {
                        ret = -ERESTARTSYS;
@@ -281,47 +349,86 @@ nouveau_fence_wait(struct nouveau_fence *fence, bool lazy, bool intr)
 }
 
 int
-nouveau_fence_sync(struct nouveau_fence *fence, struct nouveau_channel *chan)
+nouveau_fence_wait(struct nouveau_fence *fence, bool lazy, bool intr)
 {
-       struct nouveau_fence_chan *fctx = chan->fence;
-       struct nouveau_channel *prev;
-       int ret = 0;
+       long ret;
 
-       prev = fence ? fence->channel : NULL;
-       if (prev) {
-               if (unlikely(prev != chan && !nouveau_fence_done(fence))) {
-                       ret = fctx->sync(fence, prev, chan);
-                       if (unlikely(ret))
-                               ret = nouveau_fence_wait(fence, true, false);
-               }
-       }
+       if (!lazy)
+               return nouveau_fence_wait_busy(fence, intr);
 
-       return ret;
+       ret = fence_wait_timeout(&fence->base, intr, 15 * HZ);
+       if (ret < 0)
+               return ret;
+       else if (!ret)
+               return -EBUSY;
+       else
+               return 0;
 }
 
-static void
-nouveau_fence_del(struct kref *kref)
+int
+nouveau_fence_sync(struct nouveau_bo *nvbo, struct nouveau_channel *chan, bool exclusive, bool intr)
 {
-       struct nouveau_fence *fence = container_of(kref, typeof(*fence), kref);
-       kfree(fence);
+       struct nouveau_fence_chan *fctx = chan->fence;
+       struct fence *fence;
+       struct reservation_object *resv = nvbo->bo.resv;
+       struct reservation_object_list *fobj;
+       struct nouveau_fence *f;
+       int ret = 0, i;
+
+       if (!exclusive) {
+               ret = reservation_object_reserve_shared(resv);
+
+               if (ret)
+                       return ret;
+       }
+
+       fobj = reservation_object_get_list(resv);
+       fence = reservation_object_get_excl(resv);
+
+       if (fence && (!exclusive || !fobj || !fobj->shared_count)) {
+               struct nouveau_channel *prev = NULL;
+
+               f = nouveau_local_fence(fence, chan->drm);
+               if (f)
+                       prev = f->channel;
+
+               if (!prev || (prev != chan && (ret = fctx->sync(f, prev, chan))))
+                       ret = fence_wait(fence, intr);
+
+               return ret;
+       }
+
+       if (!exclusive || !fobj)
+               return ret;
+
+       for (i = 0; i < fobj->shared_count && !ret; ++i) {
+               struct nouveau_channel *prev = NULL;
+
+               fence = rcu_dereference_protected(fobj->shared[i],
+                                               reservation_object_held(resv));
+
+               f = nouveau_local_fence(fence, chan->drm);
+               if (f)
+                       prev = f->channel;
+
+               if (!prev || (prev != chan && (ret = fctx->sync(f, prev, chan))))
+                       ret = fence_wait(fence, intr);
+
+               if (ret)
+                       break;
+       }
+
+       return ret;
 }
 
 void
 nouveau_fence_unref(struct nouveau_fence **pfence)
 {
        if (*pfence)
-               kref_put(&(*pfence)->kref, nouveau_fence_del);
+               fence_put(&(*pfence)->base);
        *pfence = NULL;
 }
 
-struct nouveau_fence *
-nouveau_fence_ref(struct nouveau_fence *fence)
-{
-       if (fence)
-               kref_get(&fence->kref);
-       return fence;
-}
-
 int
 nouveau_fence_new(struct nouveau_channel *chan, bool sysmem,
                  struct nouveau_fence **pfence)
@@ -336,9 +443,7 @@ nouveau_fence_new(struct nouveau_channel *chan, bool sysmem,
        if (!fence)
                return -ENOMEM;
 
-       INIT_LIST_HEAD(&fence->work);
        fence->sysmem = sysmem;
-       kref_init(&fence->kref);
 
        ret = nouveau_fence_emit(fence, chan);
        if (ret)
@@ -347,3 +452,101 @@ nouveau_fence_new(struct nouveau_channel *chan, bool sysmem,
        *pfence = fence;
        return ret;
 }
+
+static const char *nouveau_fence_get_get_driver_name(struct fence *fence)
+{
+       return "nouveau";
+}
+
+static const char *nouveau_fence_get_timeline_name(struct fence *f)
+{
+       struct nouveau_fence *fence = from_fence(f);
+       struct nouveau_fence_chan *fctx = nouveau_fctx(fence);
+
+       return fence->channel ? fctx->name : "dead channel";
+}
+
+/*
+ * In an ideal world, read would not assume the channel context is still alive.
+ * This function may be called from another device, running into free memory as a
+ * result. The drm node should still be there, so we can derive the index from
+ * the fence context.
+ */
+static bool nouveau_fence_is_signaled(struct fence *f)
+{
+       struct nouveau_fence *fence = from_fence(f);
+       struct nouveau_fence_chan *fctx = nouveau_fctx(fence);
+       struct nouveau_channel *chan = fence->channel;
+
+       return (int)(fctx->read(chan) - fence->base.seqno) >= 0;
+}
+
+static bool nouveau_fence_no_signaling(struct fence *f)
+{
+       struct nouveau_fence *fence = from_fence(f);
+
+       /*
+        * caller should have a reference on the fence,
+        * else fence could get freed here
+        */
+       WARN_ON(atomic_read(&fence->base.refcount.refcount) <= 1);
+
+       /*
+        * This needs uevents to work correctly, but fence_add_callback relies on
+        * being able to enable signaling. It will still get signaled eventually,
+        * just not right away.
+        */
+       if (nouveau_fence_is_signaled(f)) {
+               list_del(&fence->head);
+
+               fence_put(&fence->base);
+               return false;
+       }
+
+       return true;
+}
+
+static void nouveau_fence_release(struct fence *f)
+{
+       struct nouveau_fence *fence = from_fence(f);
+       struct nouveau_fence_chan *fctx = nouveau_fctx(fence);
+
+       kref_put(&fctx->fence_ref, nouveau_fence_context_put);
+       fence_free(&fence->base);
+}
+
+static const struct fence_ops nouveau_fence_ops_legacy = {
+       .get_driver_name = nouveau_fence_get_get_driver_name,
+       .get_timeline_name = nouveau_fence_get_timeline_name,
+       .enable_signaling = nouveau_fence_no_signaling,
+       .signaled = nouveau_fence_is_signaled,
+       .wait = nouveau_fence_wait_legacy,
+       .release = nouveau_fence_release
+};
+
+static bool nouveau_fence_enable_signaling(struct fence *f)
+{
+       struct nouveau_fence *fence = from_fence(f);
+       struct nouveau_fence_chan *fctx = nouveau_fctx(fence);
+       bool ret;
+
+       if (!fctx->notify_ref++)
+               nvif_notify_get(&fctx->notify);
+
+       ret = nouveau_fence_no_signaling(f);
+       if (ret)
+               set_bit(FENCE_FLAG_USER_BITS, &fence->base.flags);
+       else if (!--fctx->notify_ref)
+               nvif_notify_put(&fctx->notify);
+
+       return ret;
+}
+
+static const struct fence_ops nouveau_fence_ops_uevent = {
+       .get_driver_name = nouveau_fence_get_get_driver_name,
+       .get_timeline_name = nouveau_fence_get_timeline_name,
+       .enable_signaling = nouveau_fence_enable_signaling,
+       .signaled = nouveau_fence_is_signaled,
+       .wait = fence_default_wait,
+       .release = NULL
+};
index c57bb61da58c162d241be806028dcf78809ff4eb..943b0b17b1fc760296eccea9b409f03696a644fc 100644 (file)
@@ -1,33 +1,37 @@
 #ifndef __NOUVEAU_FENCE_H__
 #define __NOUVEAU_FENCE_H__
 
+#include <linux/fence.h>
+#include <nvif/notify.h>
+
 struct nouveau_drm;
+struct nouveau_bo;
 
 struct nouveau_fence {
+       struct fence base;
+
        struct list_head head;
-       struct list_head work;
-       struct kref kref;
 
        bool sysmem;
 
        struct nouveau_channel *channel;
        unsigned long timeout;
-       u32 sequence;
 };
 
 int  nouveau_fence_new(struct nouveau_channel *, bool sysmem,
                       struct nouveau_fence **);
-struct nouveau_fence *
-nouveau_fence_ref(struct nouveau_fence *);
 void nouveau_fence_unref(struct nouveau_fence **);
 
 int  nouveau_fence_emit(struct nouveau_fence *, struct nouveau_channel *);
 bool nouveau_fence_done(struct nouveau_fence *);
-void nouveau_fence_work(struct nouveau_fence *, void (*)(void *), void *);
+void nouveau_fence_work(struct fence *, void (*)(void *), void *);
 int  nouveau_fence_wait(struct nouveau_fence *, bool lazy, bool intr);
-int  nouveau_fence_sync(struct nouveau_fence *, struct nouveau_channel *);
+int  nouveau_fence_sync(struct nouveau_bo *, struct nouveau_channel *, bool exclusive, bool intr);
 
 struct nouveau_fence_chan {
+       spinlock_t lock;
+       struct kref fence_ref;
+
        struct list_head pending;
        struct list_head flip;
 
@@ -38,8 +42,12 @@ struct nouveau_fence_chan {
        int  (*emit32)(struct nouveau_channel *, u64, u32);
        int  (*sync32)(struct nouveau_channel *, u64, u32);
 
-       spinlock_t lock;
        u32 sequence;
+       u32 context;
+       char name[32];
+
+       struct nvif_notify notify;
+       int notify_ref;
 };
 
 struct nouveau_fence_priv {
@@ -49,14 +57,15 @@ struct nouveau_fence_priv {
        int  (*context_new)(struct nouveau_channel *);
        void (*context_del)(struct nouveau_channel *);
 
-       wait_queue_head_t waiting;
+       u32 contexts, context_base;
        bool uevent;
 };
 
 #define nouveau_fence(drm) ((struct nouveau_fence_priv *)(drm)->fence)
 
-void nouveau_fence_context_new(struct nouveau_fence_chan *);
+void nouveau_fence_context_new(struct nouveau_channel *, struct nouveau_fence_chan *);
 void nouveau_fence_context_del(struct nouveau_fence_chan *);
+void nouveau_fence_context_free(struct nouveau_fence_chan *);
 
 int nv04_fence_create(struct nouveau_drm *);
 int nv04_fence_mthd(struct nouveau_channel *, u32, u32, u32);
index 292a677bfed4ebc649d5ae283a96343773befcfb..36951ee4b1571807d9a1f85c796f00b232e043d6 100644 (file)
@@ -98,17 +98,23 @@ static void
 nouveau_gem_object_unmap(struct nouveau_bo *nvbo, struct nouveau_vma *vma)
 {
        const bool mapped = nvbo->bo.mem.mem_type != TTM_PL_SYSTEM;
-       struct nouveau_fence *fence = NULL;
+       struct reservation_object *resv = nvbo->bo.resv;
+       struct reservation_object_list *fobj;
+       struct fence *fence = NULL;
+
+       fobj = reservation_object_get_list(resv);
 
        list_del(&vma->head);
 
-       if (mapped) {
-               spin_lock(&nvbo->bo.bdev->fence_lock);
-               fence = nouveau_fence_ref(nvbo->bo.sync_obj);
-               spin_unlock(&nvbo->bo.bdev->fence_lock);
-       }
+       if (fobj && fobj->shared_count > 1)
+               ttm_bo_wait(&nvbo->bo, true, false, false);
+       else if (fobj && fobj->shared_count == 1)
+               fence = rcu_dereference_protected(fobj->shared[0],
+                                               reservation_object_held(resv));
+       else
+               fence = reservation_object_get_excl(nvbo->bo.resv);
 
-       if (fence) {
+       if (fence && mapped) {
                nouveau_fence_work(fence, nouveau_gem_object_delete, vma);
        } else {
                if (mapped)
@@ -116,7 +122,6 @@ nouveau_gem_object_unmap(struct nouveau_bo *nvbo, struct nouveau_vma *vma)
                nouveau_vm_put(vma);
                kfree(vma);
        }
-       nouveau_fence_unref(&fence);
 }
 
 void
@@ -160,7 +165,7 @@ nouveau_gem_new(struct drm_device *dev, int size, int align, uint32_t domain,
                flags |= TTM_PL_FLAG_SYSTEM;
 
        ret = nouveau_bo_new(dev, size, align, flags, tile_mode,
-                            tile_flags, NULL, pnvbo);
+                            tile_flags, NULL, NULL, pnvbo);
        if (ret)
                return ret;
        nvbo = *pnvbo;
@@ -288,24 +293,23 @@ nouveau_gem_set_domain(struct drm_gem_object *gem, uint32_t read_domains,
 }
 
 struct validate_op {
-       struct list_head vram_list;
-       struct list_head gart_list;
-       struct list_head both_list;
+       struct list_head list;
        struct ww_acquire_ctx ticket;
 };
 
 static void
-validate_fini_list(struct list_head *list, struct nouveau_fence *fence,
-                  struct ww_acquire_ctx *ticket)
+validate_fini_no_ticket(struct validate_op *op, struct nouveau_fence *fence,
+                       struct drm_nouveau_gem_pushbuf_bo *pbbo)
 {
-       struct list_head *entry, *tmp;
        struct nouveau_bo *nvbo;
+       struct drm_nouveau_gem_pushbuf_bo *b;
 
-       list_for_each_safe(entry, tmp, list) {
-               nvbo = list_entry(entry, struct nouveau_bo, entry);
+       while (!list_empty(&op->list)) {
+               nvbo = list_entry(op->list.next, struct nouveau_bo, entry);
+               b = &pbbo[nvbo->pbbo_index];
 
                if (likely(fence))
-                       nouveau_bo_fence(nvbo, fence);
+                       nouveau_bo_fence(nvbo, fence, !!b->write_domains);
 
                if (unlikely(nvbo->validate_mapped)) {
                        ttm_bo_kunmap(&nvbo->kmap);
@@ -314,23 +318,16 @@ validate_fini_list(struct list_head *list, struct nouveau_fence *fence,
 
                list_del(&nvbo->entry);
                nvbo->reserved_by = NULL;
-               ttm_bo_unreserve_ticket(&nvbo->bo, ticket);
+               ttm_bo_unreserve_ticket(&nvbo->bo, &op->ticket);
                drm_gem_object_unreference_unlocked(&nvbo->gem);
        }
 }
 
 static void
-validate_fini_no_ticket(struct validate_op *op, struct nouveau_fence *fence)
+validate_fini(struct validate_op *op, struct nouveau_fence *fence,
+             struct drm_nouveau_gem_pushbuf_bo *pbbo)
 {
-       validate_fini_list(&op->vram_list, fence, &op->ticket);
-       validate_fini_list(&op->gart_list, fence, &op->ticket);
-       validate_fini_list(&op->both_list, fence, &op->ticket);
-}
-
-static void
-validate_fini(struct validate_op *op, struct nouveau_fence *fence)
-{
-       validate_fini_no_ticket(op, fence);
+       validate_fini_no_ticket(op, fence, pbbo);
        ww_acquire_fini(&op->ticket);
 }
 
@@ -344,6 +341,9 @@ validate_init(struct nouveau_channel *chan, struct drm_file *file_priv,
        int trycnt = 0;
        int ret, i;
        struct nouveau_bo *res_bo = NULL;
+       LIST_HEAD(gart_list);
+       LIST_HEAD(vram_list);
+       LIST_HEAD(both_list);
 
        ww_acquire_init(&op->ticket, &reservation_ww_class);
 retry:
@@ -360,9 +360,8 @@ retry:
                gem = drm_gem_object_lookup(dev, file_priv, b->handle);
                if (!gem) {
                        NV_PRINTK(error, cli, "Unknown handle 0x%08x\n", b->handle);
-                       ww_acquire_done(&op->ticket);
-                       validate_fini(op, NULL);
-                       return -ENOENT;
+                       ret = -ENOENT;
+                       break;
                }
                nvbo = nouveau_gem_object(gem);
                if (nvbo == res_bo) {
@@ -375,14 +374,16 @@ retry:
                        NV_PRINTK(error, cli, "multiple instances of buffer %d on "
                                      "validation list\n", b->handle);
                        drm_gem_object_unreference_unlocked(gem);
-                       ww_acquire_done(&op->ticket);
-                       validate_fini(op, NULL);
-                       return -EINVAL;
+                       ret = -EINVAL;
+                       break;
                }
 
                ret = ttm_bo_reserve(&nvbo->bo, true, false, true, &op->ticket);
                if (ret) {
-                       validate_fini_no_ticket(op, NULL);
+                       list_splice_tail_init(&vram_list, &op->list);
+                       list_splice_tail_init(&gart_list, &op->list);
+                       list_splice_tail_init(&both_list, &op->list);
+                       validate_fini_no_ticket(op, NULL, NULL);
                        if (unlikely(ret == -EDEADLK)) {
                                ret = ttm_bo_reserve_slowpath(&nvbo->bo, true,
                                                              &op->ticket);
@@ -390,12 +391,9 @@ retry:
                                        res_bo = nvbo;
                        }
                        if (unlikely(ret)) {
-                               ww_acquire_done(&op->ticket);
-                               ww_acquire_fini(&op->ticket);
-                               drm_gem_object_unreference_unlocked(gem);
                                if (ret != -ERESTARTSYS)
                                        NV_PRINTK(error, cli, "fail reserve\n");
-                               return ret;
+                               break;
                        }
                }
 
@@ -404,45 +402,32 @@ retry:
                nvbo->pbbo_index = i;
                if ((b->valid_domains & NOUVEAU_GEM_DOMAIN_VRAM) &&
                    (b->valid_domains & NOUVEAU_GEM_DOMAIN_GART))
-                       list_add_tail(&nvbo->entry, &op->both_list);
+                       list_add_tail(&nvbo->entry, &both_list);
                else
                if (b->valid_domains & NOUVEAU_GEM_DOMAIN_VRAM)
-                       list_add_tail(&nvbo->entry, &op->vram_list);
+                       list_add_tail(&nvbo->entry, &vram_list);
                else
                if (b->valid_domains & NOUVEAU_GEM_DOMAIN_GART)
-                       list_add_tail(&nvbo->entry, &op->gart_list);
+                       list_add_tail(&nvbo->entry, &gart_list);
                else {
                        NV_PRINTK(error, cli, "invalid valid domains: 0x%08x\n",
                                 b->valid_domains);
-                       list_add_tail(&nvbo->entry, &op->both_list);
-                       ww_acquire_done(&op->ticket);
-                       validate_fini(op, NULL);
-                       return -EINVAL;
+                       list_add_tail(&nvbo->entry, &both_list);
+                       ret = -EINVAL;
+                       break;
                }
                if (nvbo == res_bo)
                        goto retry;
        }
 
        ww_acquire_done(&op->ticket);
-       return 0;
-}
-
-static int
-validate_sync(struct nouveau_channel *chan, struct nouveau_bo *nvbo)
-{
-       struct nouveau_fence *fence = NULL;
-       int ret = 0;
-
-       spin_lock(&nvbo->bo.bdev->fence_lock);
-       fence = nouveau_fence_ref(nvbo->bo.sync_obj);
-       spin_unlock(&nvbo->bo.bdev->fence_lock);
-
-       if (fence) {
-               ret = nouveau_fence_sync(fence, chan);
-               nouveau_fence_unref(&fence);
-       }
-
+       list_splice_tail(&vram_list, &op->list);
+       list_splice_tail(&gart_list, &op->list);
+       list_splice_tail(&both_list, &op->list);
+       if (ret)
+               validate_fini(op, NULL, NULL);
        return ret;
+
 }
 
 static int
@@ -474,9 +459,10 @@ validate_list(struct nouveau_channel *chan, struct nouveau_cli *cli,
                        return ret;
                }
 
-               ret = validate_sync(chan, nvbo);
+               ret = nouveau_fence_sync(nvbo, chan, !!b->write_domains, true);
                if (unlikely(ret)) {
-                       NV_PRINTK(error, cli, "fail post-validate sync\n");
+                       if (ret != -ERESTARTSYS)
+                               NV_PRINTK(error, cli, "fail post-validate sync\n");
                        return ret;
                }
 
@@ -513,11 +499,9 @@ nouveau_gem_pushbuf_validate(struct nouveau_channel *chan,
                             struct validate_op *op, int *apply_relocs)
 {
        struct nouveau_cli *cli = nouveau_cli(file_priv);
-       int ret, relocs = 0;
+       int ret;
 
-       INIT_LIST_HEAD(&op->vram_list);
-       INIT_LIST_HEAD(&op->gart_list);
-       INIT_LIST_HEAD(&op->both_list);
+       INIT_LIST_HEAD(&op->list);
 
        if (nr_buffers == 0)
                return 0;
@@ -529,34 +513,14 @@ nouveau_gem_pushbuf_validate(struct nouveau_channel *chan,
                return ret;
        }
 
-       ret = validate_list(chan, cli, &op->vram_list, pbbo, user_buffers);
-       if (unlikely(ret < 0)) {
-               if (ret != -ERESTARTSYS)
-                       NV_PRINTK(error, cli, "validate vram_list\n");
-               validate_fini(op, NULL);
-               return ret;
-       }
-       relocs += ret;
-
-       ret = validate_list(chan, cli, &op->gart_list, pbbo, user_buffers);
-       if (unlikely(ret < 0)) {
-               if (ret != -ERESTARTSYS)
-                       NV_PRINTK(error, cli, "validate gart_list\n");
-               validate_fini(op, NULL);
-               return ret;
-       }
-       relocs += ret;
-
-       ret = validate_list(chan, cli, &op->both_list, pbbo, user_buffers);
+       ret = validate_list(chan, cli, &op->list, pbbo, user_buffers);
        if (unlikely(ret < 0)) {
                if (ret != -ERESTARTSYS)
-                       NV_PRINTK(error, cli, "validate both_list\n");
-               validate_fini(op, NULL);
+                       NV_PRINTK(error, cli, "validating bo list\n");
+               validate_fini(op, NULL, NULL);
                return ret;
        }
-       relocs += ret;
-
-       *apply_relocs = relocs;
+       *apply_relocs = ret;
        return 0;
 }
 
@@ -659,9 +623,7 @@ nouveau_gem_pushbuf_reloc_apply(struct nouveau_cli *cli,
                                data |= r->vor;
                }
 
-               spin_lock(&nvbo->bo.bdev->fence_lock);
-               ret = ttm_bo_wait(&nvbo->bo, false, false, false);
-               spin_unlock(&nvbo->bo.bdev->fence_lock);
+               ret = ttm_bo_wait(&nvbo->bo, true, false, false);
                if (ret) {
                        NV_PRINTK(error, cli, "reloc wait_idle failed: %d\n", ret);
                        break;
@@ -839,7 +801,7 @@ nouveau_gem_ioctl_pushbuf(struct drm_device *dev, void *data,
        }
 
 out:
-       validate_fini(&op, fence);
+       validate_fini(&op, fence, bo);
        nouveau_fence_unref(&fence);
 
 out_prevalid:
@@ -884,17 +846,29 @@ nouveau_gem_ioctl_cpu_prep(struct drm_device *dev, void *data,
        struct drm_gem_object *gem;
        struct nouveau_bo *nvbo;
        bool no_wait = !!(req->flags & NOUVEAU_GEM_CPU_PREP_NOWAIT);
-       int ret = -EINVAL;
+       bool write = !!(req->flags & NOUVEAU_GEM_CPU_PREP_WRITE);
+       int ret;
 
        gem = drm_gem_object_lookup(dev, file_priv, req->handle);
        if (!gem)
                return -ENOENT;
        nvbo = nouveau_gem_object(gem);
 
-       spin_lock(&nvbo->bo.bdev->fence_lock);
-       ret = ttm_bo_wait(&nvbo->bo, true, true, no_wait);
-       spin_unlock(&nvbo->bo.bdev->fence_lock);
+       if (no_wait)
+               ret = reservation_object_test_signaled_rcu(nvbo->bo.resv, write) ? 0 : -EBUSY;
+       else {
+               long lret;
+
+               lret = reservation_object_wait_timeout_rcu(nvbo->bo.resv, write, true, 30 * HZ);
+               if (!lret)
+                       ret = -EBUSY;
+               else if (lret > 0)
+                       ret = 0;
+               else
+                       ret = lret;
+       }
        drm_gem_object_unreference_unlocked(gem);
+
        return ret;
 }
 
index ddab762d81fef78d269729aa8c906934ef9e1d3b..e4049faca780453f07dccbf034950a8215fa786e 100644 (file)
@@ -39,7 +39,7 @@ struct reservation_object *nouveau_gem_prime_res_obj(struct drm_gem_object *);
 extern void nouveau_gem_prime_unpin(struct drm_gem_object *);
 extern struct sg_table *nouveau_gem_prime_get_sg_table(struct drm_gem_object *);
 extern struct drm_gem_object *nouveau_gem_prime_import_sg_table(
-       struct drm_device *, size_t size, struct sg_table *);
+       struct drm_device *, struct dma_buf_attachment *, struct sg_table *);
 extern void *nouveau_gem_prime_vmap(struct drm_gem_object *);
 extern void nouveau_gem_prime_vunmap(struct drm_gem_object *, void *);
 
index 47ca886237530c50fa9f6788ba86ac288487800b..6544b84f03034716e6e465f97366cba1151707ff 100644 (file)
 #include "nouveau_usif.h"
 
 static void
-nvkm_client_unmap(void *priv, void *ptr, u32 size)
+nvkm_client_unmap(void *priv, void __iomem *ptr, u32 size)
 {
        iounmap(ptr);
 }
 
-static void *
+static void __iomem *
 nvkm_client_map(void *priv, u64 handle, u32 size)
 {
        return ioremap(handle, size);
index 1f51008e4d26e4511a6260d606ca515ed025d160..228226ab27fc1b55883d9d7bcf6066f5c3852bc5 100644 (file)
@@ -23,6 +23,7 @@
  */
 
 #include <drm/drmP.h>
+#include <linux/dma-buf.h>
 
 #include "nouveau_drm.h"
 #include "nouveau_gem.h"
@@ -56,17 +57,20 @@ void nouveau_gem_prime_vunmap(struct drm_gem_object *obj, void *vaddr)
 }
 
 struct drm_gem_object *nouveau_gem_prime_import_sg_table(struct drm_device *dev,
-                                                        size_t size,
+                                                        struct dma_buf_attachment *attach,
                                                         struct sg_table *sg)
 {
        struct nouveau_bo *nvbo;
+       struct reservation_object *robj = attach->dmabuf->resv;
        u32 flags = 0;
        int ret;
 
        flags = TTM_PL_FLAG_TT;
 
-       ret = nouveau_bo_new(dev, size, 0, flags, 0, 0,
-                            sg, &nvbo);
+       ww_mutex_lock(&robj->lock, NULL);
+       ret = nouveau_bo_new(dev, attach->dmabuf->size, 0, flags, 0, 0,
+                            sg, robj, &nvbo);
+       ww_mutex_unlock(&robj->lock);
        if (ret)
                return ERR_PTR(ret);
 
index 3c6962d15b26c2099bc4f2e1d840f5377b809227..8fbbf3093d8611e9497eaacdad73ec698bf42b10 100644 (file)
@@ -29,7 +29,7 @@
 #include "nouveau_sysfs.h"
 
 MODULE_PARM_DESC(pstate, "enable sysfs pstate file, which will be moved in the future");
-static int nouveau_pstate;
+int nouveau_pstate;
 module_param_named(pstate, nouveau_pstate, int, 0400);
 
 static inline struct drm_device *
index f973378160f8ca3410f06ad1fc1f4f7da6bd1816..4e5ea9241b2871bb2edcdf6a0dd9ef3d42e70933 100644 (file)
@@ -16,4 +16,6 @@ nouveau_sysfs(struct drm_device *dev)
 int  nouveau_sysfs_init(struct drm_device *);
 void nouveau_sysfs_fini(struct drm_device *);
 
+extern int nouveau_pstate;
+
 #endif
index 53874b76b031081b38853a400eaa2f1dc2f199e2..753a6def61e7ce474d73b21b9affe84ae8b1a861 100644 (file)
@@ -71,8 +71,7 @@ nouveau_vram_manager_del(struct ttm_mem_type_manager *man,
 static int
 nouveau_vram_manager_new(struct ttm_mem_type_manager *man,
                         struct ttm_buffer_object *bo,
-                        struct ttm_placement *placement,
-                        uint32_t flags,
+                        const struct ttm_place *place,
                         struct ttm_mem_reg *mem)
 {
        struct nouveau_drm *drm = nouveau_bdev(man->bdev);
@@ -158,8 +157,7 @@ nouveau_gart_manager_del(struct ttm_mem_type_manager *man,
 static int
 nouveau_gart_manager_new(struct ttm_mem_type_manager *man,
                         struct ttm_buffer_object *bo,
-                        struct ttm_placement *placement,
-                        uint32_t flags,
+                        const struct ttm_place *place,
                         struct ttm_mem_reg *mem)
 {
        struct nouveau_drm *drm = nouveau_bdev(bo->bdev);
@@ -239,8 +237,7 @@ nv04_gart_manager_del(struct ttm_mem_type_manager *man, struct ttm_mem_reg *mem)
 static int
 nv04_gart_manager_new(struct ttm_mem_type_manager *man,
                      struct ttm_buffer_object *bo,
-                     struct ttm_placement *placement,
-                     uint32_t flags,
+                     const struct ttm_place *place,
                      struct ttm_mem_reg *mem)
 {
        struct nouveau_mem *node;
@@ -284,7 +281,7 @@ nouveau_ttm_mmap(struct file *filp, struct vm_area_struct *vma)
        struct nouveau_drm *drm = nouveau_drm(file_priv->minor->dev);
 
        if (unlikely(vma->vm_pgoff < DRM_FILE_PAGE_OFFSET))
-               return drm_mmap(filp, vma);
+               return -EINVAL;
 
        return ttm_bo_mmap(filp, vma, &drm->ttm.bdev);
 }
index 239c2c5a96159498f2ea2fee1ff235db6c9ecf56..f9859deb108a460d34e3740746c691e628cbea4d 100644 (file)
@@ -41,7 +41,7 @@ nv04_fence_emit(struct nouveau_fence *fence)
        int ret = RING_SPACE(chan, 2);
        if (ret == 0) {
                BEGIN_NV04(chan, NvSubSw, 0x0150, 1);
-               OUT_RING  (chan, fence->sequence);
+               OUT_RING  (chan, fence->base.seqno);
                FIRE_RING (chan);
        }
        return ret;
@@ -67,7 +67,7 @@ nv04_fence_context_del(struct nouveau_channel *chan)
        struct nv04_fence_chan *fctx = chan->fence;
        nouveau_fence_context_del(&fctx->base);
        chan->fence = NULL;
-       kfree(fctx);
+       nouveau_fence_context_free(&fctx->base);
 }
 
 static int
@@ -75,7 +75,7 @@ nv04_fence_context_new(struct nouveau_channel *chan)
 {
        struct nv04_fence_chan *fctx = kzalloc(sizeof(*fctx), GFP_KERNEL);
        if (fctx) {
-               nouveau_fence_context_new(&fctx->base);
+               nouveau_fence_context_new(chan, &fctx->base);
                fctx->base.emit = nv04_fence_emit;
                fctx->base.sync = nv04_fence_sync;
                fctx->base.read = nv04_fence_read;
@@ -105,5 +105,7 @@ nv04_fence_create(struct nouveau_drm *drm)
        priv->base.dtor = nv04_fence_destroy;
        priv->base.context_new = nv04_fence_context_new;
        priv->base.context_del = nv04_fence_context_del;
+       priv->base.contexts = 15;
+       priv->base.context_base = fence_context_alloc(priv->base.contexts);
        return 0;
 }
index 4faaf0acf5d7d919769650662e1788aa861904e2..5e1ea1cdce75e907ccc75b25830be9b969daa339 100644 (file)
@@ -33,7 +33,7 @@ nv10_fence_emit(struct nouveau_fence *fence)
        int ret = RING_SPACE(chan, 2);
        if (ret == 0) {
                BEGIN_NV04(chan, 0, NV10_SUBCHAN_REF_CNT, 1);
-               OUT_RING  (chan, fence->sequence);
+               OUT_RING  (chan, fence->base.seqno);
                FIRE_RING (chan);
        }
        return ret;
@@ -63,7 +63,7 @@ nv10_fence_context_del(struct nouveau_channel *chan)
                nvif_object_fini(&fctx->head[i]);
        nvif_object_fini(&fctx->sema);
        chan->fence = NULL;
-       kfree(fctx);
+       nouveau_fence_context_free(&fctx->base);
 }
 
 int
@@ -75,7 +75,7 @@ nv10_fence_context_new(struct nouveau_channel *chan)
        if (!fctx)
                return -ENOMEM;
 
-       nouveau_fence_context_new(&fctx->base);
+       nouveau_fence_context_new(chan, &fctx->base);
        fctx->base.emit = nv10_fence_emit;
        fctx->base.read = nv10_fence_read;
        fctx->base.sync = nv10_fence_sync;
@@ -106,6 +106,8 @@ nv10_fence_create(struct nouveau_drm *drm)
        priv->base.dtor = nv10_fence_destroy;
        priv->base.context_new = nv10_fence_context_new;
        priv->base.context_del = nv10_fence_context_del;
+       priv->base.contexts = 31;
+       priv->base.context_base = fence_context_alloc(priv->base.contexts);
        spin_lock_init(&priv->lock);
        return 0;
 }
index ca907479f92fc6c42ee0647c11e1881e079ea74d..40b461c7d5c565c0471c5f3b80f09221a7d42a8b 100644 (file)
@@ -84,7 +84,7 @@ nv17_fence_context_new(struct nouveau_channel *chan)
        if (!fctx)
                return -ENOMEM;
 
-       nouveau_fence_context_new(&fctx->base);
+       nouveau_fence_context_new(chan, &fctx->base);
        fctx->base.emit = nv10_fence_emit;
        fctx->base.read = nv10_fence_read;
        fctx->base.sync = nv17_fence_sync;
@@ -124,10 +124,12 @@ nv17_fence_create(struct nouveau_drm *drm)
        priv->base.resume = nv17_fence_resume;
        priv->base.context_new = nv17_fence_context_new;
        priv->base.context_del = nv10_fence_context_del;
+       priv->base.contexts = 31;
+       priv->base.context_base = fence_context_alloc(priv->base.contexts);
        spin_lock_init(&priv->lock);
 
        ret = nouveau_bo_new(drm->dev, 4096, 0x1000, TTM_PL_FLAG_VRAM,
-                            0, 0x0000, NULL, &priv->bo);
+                            0, 0x0000, NULL, NULL, &priv->bo);
        if (!ret) {
                ret = nouveau_bo_pin(priv->bo, TTM_PL_FLAG_VRAM);
                if (!ret) {
index 03949eaa629f772e976070f09da30c58063022d0..ae873d1a8d463f7cd55da92b550eec1c44d31e25 100644 (file)
@@ -1066,7 +1066,7 @@ nv50_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *umode,
        u32 vscan = (mode->flags & DRM_MODE_FLAG_DBLSCAN) ? 2 : 1;
        u32 hactive, hsynce, hbackp, hfrontp, hblanke, hblanks;
        u32 vactive, vsynce, vbackp, vfrontp, vblanke, vblanks;
-       u32 vblan2e = 0, vblan2s = 1;
+       u32 vblan2e = 0, vblan2s = 1, vblankus = 0;
        u32 *push;
        int ret;
 
@@ -1083,6 +1083,11 @@ nv50_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *umode,
        vblanke = vsynce + vbackp;
        vfrontp = (mode->vsync_start - mode->vdisplay) * vscan / ilace;
        vblanks = vactive - vfrontp - 1;
+       /* XXX: Safe underestimate, even "0" works */
+       vblankus = (vactive - mode->vdisplay - 2) * hactive;
+       vblankus *= 1000;
+       vblankus /= mode->clock;
+
        if (mode->flags & DRM_MODE_FLAG_INTERLACE) {
                vblan2e = vactive + vsynce + vbackp;
                vblan2s = vblan2e + (mode->vdisplay * vscan / ilace);
@@ -1099,14 +1104,14 @@ nv50_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *umode,
                        evo_mthd(push, 0x0804 + (nv_crtc->index * 0x400), 2);
                        evo_data(push, 0x00800000 | mode->clock);
                        evo_data(push, (ilace == 2) ? 2 : 0);
-                       evo_mthd(push, 0x0810 + (nv_crtc->index * 0x400), 6);
+                       evo_mthd(push, 0x0810 + (nv_crtc->index * 0x400), 8);
                        evo_data(push, 0x00000000);
                        evo_data(push, (vactive << 16) | hactive);
                        evo_data(push, ( vsynce << 16) | hsynce);
                        evo_data(push, (vblanke << 16) | hblanke);
                        evo_data(push, (vblanks << 16) | hblanks);
                        evo_data(push, (vblan2e << 16) | vblan2s);
-                       evo_mthd(push, 0x082c + (nv_crtc->index * 0x400), 1);
+                       evo_data(push, vblankus);
                        evo_data(push, 0x00000000);
                        evo_mthd(push, 0x0900 + (nv_crtc->index * 0x400), 2);
                        evo_data(push, 0x00000311);
@@ -1378,7 +1383,7 @@ nv50_crtc_create(struct drm_device *dev, int index)
        drm_mode_crtc_set_gamma_size(crtc, 256);
 
        ret = nouveau_bo_new(dev, 8192, 0x100, TTM_PL_FLAG_VRAM,
-                            0, 0x0000, NULL, &head->base.lut.nvbo);
+                            0, 0x0000, NULL, NULL, &head->base.lut.nvbo);
        if (!ret) {
                ret = nouveau_bo_pin(head->base.lut.nvbo, TTM_PL_FLAG_VRAM);
                if (!ret) {
@@ -1401,7 +1406,7 @@ nv50_crtc_create(struct drm_device *dev, int index)
                goto out;
 
        ret = nouveau_bo_new(dev, 64 * 64 * 4, 0x100, TTM_PL_FLAG_VRAM,
-                            0, 0x0000, NULL, &head->base.cursor.nvbo);
+                            0, 0x0000, NULL, NULL, &head->base.cursor.nvbo);
        if (!ret) {
                ret = nouveau_bo_pin(head->base.cursor.nvbo, TTM_PL_FLAG_VRAM);
                if (!ret) {
@@ -1651,17 +1656,21 @@ static void
 nv50_audio_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode)
 {
        struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
+       struct nouveau_crtc *nv_crtc = nouveau_crtc(encoder->crtc);
        struct nouveau_connector *nv_connector;
        struct nv50_disp *disp = nv50_disp(encoder->dev);
-       struct {
-               struct nv50_disp_mthd_v1 base;
-               struct nv50_disp_sor_hda_eld_v0 eld;
+       struct __packed {
+               struct {
+                       struct nv50_disp_mthd_v1 mthd;
+                       struct nv50_disp_sor_hda_eld_v0 eld;
+               } base;
                u8 data[sizeof(nv_connector->base.eld)];
        } args = {
-               .base.version = 1,
-               .base.method  = NV50_DISP_MTHD_V1_SOR_HDA_ELD,
-               .base.hasht   = nv_encoder->dcb->hasht,
-               .base.hashm   = nv_encoder->dcb->hashm,
+               .base.mthd.version = 1,
+               .base.mthd.method  = NV50_DISP_MTHD_V1_SOR_HDA_ELD,
+               .base.mthd.hasht   = nv_encoder->dcb->hasht,
+               .base.mthd.hashm   = (0xf0ff & nv_encoder->dcb->hashm) |
+                                    (0x0100 << nv_crtc->index),
        };
 
        nv_connector = nouveau_encoder_connector_get(nv_encoder);
@@ -1671,11 +1680,11 @@ nv50_audio_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode)
        drm_edid_to_eld(&nv_connector->base, nv_connector->edid);
        memcpy(args.data, nv_connector->base.eld, sizeof(args.data));
 
-       nvif_mthd(disp->disp, 0, &args, sizeof(args));
+       nvif_mthd(disp->disp, 0, &args, sizeof(args.base) + args.data[2] * 4);
 }
 
 static void
-nv50_audio_disconnect(struct drm_encoder *encoder)
+nv50_audio_disconnect(struct drm_encoder *encoder, struct nouveau_crtc *nv_crtc)
 {
        struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
        struct nv50_disp *disp = nv50_disp(encoder->dev);
@@ -1686,7 +1695,8 @@ nv50_audio_disconnect(struct drm_encoder *encoder)
                .base.version = 1,
                .base.method  = NV50_DISP_MTHD_V1_SOR_HDA_ELD,
                .base.hasht   = nv_encoder->dcb->hasht,
-               .base.hashm   = nv_encoder->dcb->hashm,
+               .base.hashm   = (0xf0ff & nv_encoder->dcb->hashm) |
+                               (0x0100 << nv_crtc->index),
        };
 
        nvif_mthd(disp->disp, 0, &args, sizeof(args));
@@ -1745,8 +1755,6 @@ nv50_hdmi_disconnect(struct drm_encoder *encoder, struct nouveau_crtc *nv_crtc)
                               (0x0100 << nv_crtc->index),
        };
 
-       nv50_audio_disconnect(encoder);
-
        nvif_mthd(disp->disp, 0, &args, sizeof(args));
 }
 
@@ -1855,6 +1863,7 @@ nv50_sor_disconnect(struct drm_encoder *encoder)
        if (nv_crtc) {
                nv50_crtc_prepare(&nv_crtc->base);
                nv50_sor_ctrl(nv_encoder, 1 << nv_crtc->index, 0);
+               nv50_audio_disconnect(encoder, nv_crtc);
                nv50_hdmi_disconnect(&nv_encoder->base.base, nv_crtc);
        }
 }
@@ -1954,6 +1963,7 @@ nv50_sor_mode_set(struct drm_encoder *encoder, struct drm_display_mode *umode,
                        proto = 0x8;
                else
                        proto = 0x9;
+               nv50_audio_mode_set(encoder, mode);
                break;
        default:
                BUG_ON(1);
@@ -2458,7 +2468,7 @@ nv50_display_create(struct drm_device *dev)
 
        /* small shared memory area we use for notifiers and semaphores */
        ret = nouveau_bo_new(dev, 4096, 0x1000, TTM_PL_FLAG_VRAM,
-                            0, 0x0000, NULL, &disp->sync);
+                            0, 0x0000, NULL, NULL, &disp->sync);
        if (!ret) {
                ret = nouveau_bo_pin(disp->sync, TTM_PL_FLAG_VRAM);
                if (!ret) {
index 195cf51a7c31e187717f11b5542656247905a28b..22d242b37962cc14990174bc97f6876a30e31781 100644 (file)
@@ -46,7 +46,7 @@ nv50_fence_context_new(struct nouveau_channel *chan)
        if (!fctx)
                return -ENOMEM;
 
-       nouveau_fence_context_new(&fctx->base);
+       nouveau_fence_context_new(chan, &fctx->base);
        fctx->base.emit = nv10_fence_emit;
        fctx->base.read = nv10_fence_read;
        fctx->base.sync = nv17_fence_sync;
@@ -95,10 +95,12 @@ nv50_fence_create(struct nouveau_drm *drm)
        priv->base.resume = nv17_fence_resume;
        priv->base.context_new = nv50_fence_context_new;
        priv->base.context_del = nv10_fence_context_del;
+       priv->base.contexts = 127;
+       priv->base.context_base = fence_context_alloc(priv->base.contexts);
        spin_lock_init(&priv->lock);
 
        ret = nouveau_bo_new(drm->dev, 4096, 0x1000, TTM_PL_FLAG_VRAM,
-                            0, 0x0000, NULL, &priv->bo);
+                            0, 0x0000, NULL, NULL, &priv->bo);
        if (!ret) {
                ret = nouveau_bo_pin(priv->bo, TTM_PL_FLAG_VRAM);
                if (!ret) {
index 933a779c93ab7c132b82eed2f0e2bb5692462cc0..d6c6c87c3f07e2e929e49cf8ca7d41145f8c164b 100644 (file)
@@ -82,7 +82,7 @@ nv84_fence_emit(struct nouveau_fence *fence)
        else
                addr += fctx->vma.offset;
 
-       return fctx->base.emit32(chan, addr, fence->sequence);
+       return fctx->base.emit32(chan, addr, fence->base.seqno);
 }
 
 static int
@@ -97,7 +97,7 @@ nv84_fence_sync(struct nouveau_fence *fence,
        else
                addr += fctx->vma.offset;
 
-       return fctx->base.sync32(chan, addr, fence->sequence);
+       return fctx->base.sync32(chan, addr, fence->base.seqno);
 }
 
 static u32
@@ -120,11 +120,12 @@ nv84_fence_context_del(struct nouveau_channel *chan)
                nouveau_bo_vma_del(bo, &fctx->dispc_vma[i]);
        }
 
+       nouveau_bo_wr32(priv->bo, chan->chid * 16 / 4, fctx->base.sequence);
        nouveau_bo_vma_del(priv->bo, &fctx->vma_gart);
        nouveau_bo_vma_del(priv->bo, &fctx->vma);
        nouveau_fence_context_del(&fctx->base);
        chan->fence = NULL;
-       kfree(fctx);
+       nouveau_fence_context_free(&fctx->base);
 }
 
 int
@@ -139,12 +140,13 @@ nv84_fence_context_new(struct nouveau_channel *chan)
        if (!fctx)
                return -ENOMEM;
 
-       nouveau_fence_context_new(&fctx->base);
+       nouveau_fence_context_new(chan, &fctx->base);
        fctx->base.emit = nv84_fence_emit;
        fctx->base.sync = nv84_fence_sync;
        fctx->base.read = nv84_fence_read;
        fctx->base.emit32 = nv84_fence_emit32;
        fctx->base.sync32 = nv84_fence_sync32;
+       fctx->base.sequence = nv84_fence_read(chan);
 
        ret = nouveau_bo_vma_add(priv->bo, cli->vm, &fctx->vma);
        if (ret == 0) {
@@ -158,8 +160,6 @@ nv84_fence_context_new(struct nouveau_channel *chan)
                ret = nouveau_bo_vma_add(bo, cli->vm, &fctx->dispc_vma[i]);
        }
 
-       nouveau_bo_wr32(priv->bo, chan->chid * 16/4, 0x00000000);
-
        if (ret)
                nv84_fence_context_del(chan);
        return ret;
@@ -168,13 +168,12 @@ nv84_fence_context_new(struct nouveau_channel *chan)
 static bool
 nv84_fence_suspend(struct nouveau_drm *drm)
 {
-       struct nouveau_fifo *pfifo = nvkm_fifo(&drm->device);
        struct nv84_fence_priv *priv = drm->fence;
        int i;
 
-       priv->suspend = vmalloc((pfifo->max + 1) * sizeof(u32));
+       priv->suspend = vmalloc(priv->base.contexts * sizeof(u32));
        if (priv->suspend) {
-               for (i = 0; i <= pfifo->max; i++)
+               for (i = 0; i < priv->base.contexts; i++)
                        priv->suspend[i] = nouveau_bo_rd32(priv->bo, i*4);
        }
 
@@ -184,12 +183,11 @@ nv84_fence_suspend(struct nouveau_drm *drm)
 static void
 nv84_fence_resume(struct nouveau_drm *drm)
 {
-       struct nouveau_fifo *pfifo = nvkm_fifo(&drm->device);
        struct nv84_fence_priv *priv = drm->fence;
        int i;
 
        if (priv->suspend) {
-               for (i = 0; i <= pfifo->max; i++)
+               for (i = 0; i < priv->base.contexts; i++)
                        nouveau_bo_wr32(priv->bo, i*4, priv->suspend[i]);
                vfree(priv->suspend);
                priv->suspend = NULL;
@@ -229,11 +227,12 @@ nv84_fence_create(struct nouveau_drm *drm)
        priv->base.context_new = nv84_fence_context_new;
        priv->base.context_del = nv84_fence_context_del;
 
-       init_waitqueue_head(&priv->base.waiting);
+       priv->base.contexts = pfifo->max + 1;
+       priv->base.context_base = fence_context_alloc(priv->base.contexts);
        priv->base.uevent = true;
 
-       ret = nouveau_bo_new(drm->dev, 16 * (pfifo->max + 1), 0,
-                            TTM_PL_FLAG_VRAM, 0, 0, NULL, &priv->bo);
+       ret = nouveau_bo_new(drm->dev, 16 * priv->base.contexts, 0,
+                            TTM_PL_FLAG_VRAM, 0, 0, NULL, NULL, &priv->bo);
        if (ret == 0) {
                ret = nouveau_bo_pin(priv->bo, TTM_PL_FLAG_VRAM);
                if (ret == 0) {
@@ -246,8 +245,8 @@ nv84_fence_create(struct nouveau_drm *drm)
        }
 
        if (ret == 0)
-               ret = nouveau_bo_new(drm->dev, 16 * (pfifo->max + 1), 0,
-                                    TTM_PL_FLAG_TT, 0, 0, NULL,
+               ret = nouveau_bo_new(drm->dev, 16 * priv->base.contexts, 0,
+                                    TTM_PL_FLAG_TT, 0, 0, NULL, NULL,
                                     &priv->bo_gart);
        if (ret == 0) {
                ret = nouveau_bo_pin(priv->bo_gart, TTM_PL_FLAG_TT);
index 573491f847921bfc6eec27245b370096664de122..e5a27df0672b5db5d0b21c11f8e46344eb706fa4 100644 (file)
@@ -479,6 +479,8 @@ struct nv50_disp_core_channel_dma_v0 {
        __u32 pushbuf;
 };
 
+#define NV50_DISP_CORE_CHANNEL_DMA_V0_NTFY_UEVENT                          0x00
+
 /* cursor immediate */
 struct nv50_disp_cursor_v0 {
        __u8  version;
@@ -486,6 +488,8 @@ struct nv50_disp_cursor_v0 {
        __u8  pad02[6];
 };
 
+#define NV50_DISP_CURSOR_V0_NTFY_UEVENT                                    0x00
+
 /* base */
 struct nv50_disp_base_channel_dma_v0 {
        __u8  version;
@@ -494,6 +498,8 @@ struct nv50_disp_base_channel_dma_v0 {
        __u32 pushbuf;
 };
 
+#define NV50_DISP_BASE_CHANNEL_DMA_V0_NTFY_UEVENT                          0x00
+
 /* overlay */
 struct nv50_disp_overlay_channel_dma_v0 {
        __u8  version;
@@ -502,6 +508,8 @@ struct nv50_disp_overlay_channel_dma_v0 {
        __u32 pushbuf;
 };
 
+#define NV50_DISP_OVERLAY_CHANNEL_DMA_V0_NTFY_UEVENT                       0x00
+
 /* overlay immediate */
 struct nv50_disp_overlay_v0 {
        __u8  version;
@@ -509,6 +517,7 @@ struct nv50_disp_overlay_v0 {
        __u8  pad02[6];
 };
 
+#define NV50_DISP_OVERLAY_V0_NTFY_UEVENT                                   0x00
 
 /*******************************************************************************
  * fermi
index b72a8f0c2758e56ce866717cb0e1a90d0aa027d0..ac4bdb3ea506c518cf87eefc3c2e793cbc8bc23f 100644 (file)
@@ -9,8 +9,8 @@ struct nvif_driver {
        int (*suspend)(void *priv);
        int (*resume)(void *priv);
        int (*ioctl)(void *priv, bool super, void *data, u32 size, void **hack);
-       void *(*map)(void *priv, u64 handle, u32 size);
-       void (*unmap)(void *priv, void *ptr, u32 size);
+       void __iomem *(*map)(void *priv, u64 handle, u32 size);
+       void (*unmap)(void *priv, void __iomem *ptr, u32 size);
        bool keep;
 };
 
index fac3a3bbec44e15b9cc8f7a673f86a6550486635..fe519179b76c7d146d0a882400431dd1f44ec53b 100644 (file)
@@ -14,7 +14,7 @@ struct nvif_object {
        void *priv; /*XXX: hack */
        void (*dtor)(struct nvif_object *);
        struct {
-               void *ptr;
+               void __iomem *ptr;
                u32 size;
        } map;
 };
@@ -42,7 +42,7 @@ void nvif_object_unmap(struct nvif_object *);
        struct nvif_object *_object = nvif_object(a);                          \
        u32 _data;                                                             \
        if (likely(_object->map.ptr))                                          \
-               _data = ioread##b##_native((u8 *)_object->map.ptr + (c));      \
+               _data = ioread##b##_native((u8 __iomem *)_object->map.ptr + (c));      \
        else                                                                   \
                _data = nvif_object_rd(_object, (b) / 8, (c));                 \
        _data;                                                                 \
@@ -50,7 +50,7 @@ void nvif_object_unmap(struct nvif_object *);
 #define nvif_wr(a,b,c,d) ({                                                    \
        struct nvif_object *_object = nvif_object(a);                          \
        if (likely(_object->map.ptr))                                          \
-               iowrite##b##_native((d), (u8 *)_object->map.ptr + (c));        \
+               iowrite##b##_native((d), (u8 __iomem *)_object->map.ptr + (c));        \
        else                                                                   \
                nvif_object_wr(_object, (b) / 8, (c), (d));                    \
 })
index 002b9721e85a348077f09285c99bbb7600ecce32..862ba03c236ca1c42766cd8f94d4f4b93ceb5cdc 100644 (file)
@@ -629,6 +629,7 @@ static struct drm_driver omap_drm_driver = {
                .lastclose = dev_lastclose,
                .preclose = dev_preclose,
                .postclose = dev_postclose,
+               .set_busid = drm_platform_set_busid,
                .get_vblank_counter = drm_vblank_count,
                .enable_vblank = omap_irq_enable_vblank,
                .disable_vblank = omap_irq_disable_vblank,
index 84d73a61b34b7fad41973f8a0f3051b799928c87..60e47b33c8017a788669bd604795438d63794648 100644 (file)
@@ -26,6 +26,7 @@
 #include <drm/drmP.h>
 #include <drm/drm_crtc_helper.h>
 #include <drm/omap_drm.h>
+#include <drm/drm_gem.h>
 #include <linux/platform_data/omap_drm.h>
 
 
index 4ce1db0a68ff5754c37cb1eace4edccc6d6f03db..23de22f8c82078a11a4c9a7815c8aa099d74ddf9 100644 (file)
@@ -352,6 +352,30 @@ static const struct panel_desc auo_b101aw03 = {
        },
 };
 
+static const struct drm_display_mode auo_b101xtn01_mode = {
+       .clock = 72000,
+       .hdisplay = 1366,
+       .hsync_start = 1366 + 20,
+       .hsync_end = 1366 + 20 + 70,
+       .htotal = 1366 + 20 + 70,
+       .vdisplay = 768,
+       .vsync_start = 768 + 14,
+       .vsync_end = 768 + 14 + 42,
+       .vtotal = 768 + 14 + 42,
+       .vrefresh = 60,
+       .flags = DRM_MODE_FLAG_NVSYNC | DRM_MODE_FLAG_NHSYNC,
+};
+
+static const struct panel_desc auo_b101xtn01 = {
+       .modes = &auo_b101xtn01_mode,
+       .num_modes = 1,
+       .bpc = 6,
+       .size = {
+               .width = 223,
+               .height = 125,
+       },
+};
+
 static const struct drm_display_mode auo_b133xtn01_mode = {
        .clock = 69500,
        .hdisplay = 1366,
@@ -615,6 +639,9 @@ static const struct of_device_id platform_of_match[] = {
        {
                .compatible = "auo,b101aw03",
                .data = &auo_b101aw03,
+       }, {
+               .compatible = "auo,b101xtn01",
+               .data = &auo_b101xtn01,
        }, {
                .compatible = "auo,b133htn01",
                .data = &auo_b133htn01,
index ea046ba691d2efd8aa8083fc9a23f7aa54fcc399..bacc4aff120107c6f69610f4845502decd5d87c8 100644 (file)
@@ -4,6 +4,6 @@
 
 ccflags-y := -Iinclude/drm
 
-qxl-y := qxl_drv.o qxl_kms.o qxl_display.o qxl_ttm.o qxl_fb.o qxl_object.o qxl_gem.o qxl_cmd.o qxl_image.o qxl_draw.o qxl_debugfs.o qxl_irq.o qxl_dumb.o qxl_ioctl.o qxl_fence.o qxl_release.o
+qxl-y := qxl_drv.o qxl_kms.o qxl_display.o qxl_ttm.o qxl_fb.o qxl_object.o qxl_gem.o qxl_cmd.o qxl_image.o qxl_draw.o qxl_debugfs.o qxl_irq.o qxl_dumb.o qxl_ioctl.o qxl_release.o qxl_prime.o
 
 obj-$(CONFIG_DRM_QXL)+= qxl.o
index eb89653a7a1710adf2842a2d2fb811cbe6c62737..97823644d34743a285d025c810a5168ed8c8f142 100644 (file)
@@ -620,17 +620,10 @@ static int qxl_reap_surf(struct qxl_device *qdev, struct qxl_bo *surf, bool stal
        if (ret == -EBUSY)
                return -EBUSY;
 
-       if (surf->fence.num_active_releases > 0 && stall == false) {
-               qxl_bo_unreserve(surf);
-               return -EBUSY;
-       }
-
        if (stall)
                mutex_unlock(&qdev->surf_evict_mutex);
 
-       spin_lock(&surf->tbo.bdev->fence_lock);
        ret = ttm_bo_wait(&surf->tbo, true, true, !stall);
-       spin_unlock(&surf->tbo.bdev->fence_lock);
 
        if (stall)
                mutex_lock(&qdev->surf_evict_mutex);
index c3c2bbdc667496ef61cc9878e64544df0efd403a..6911b8c444928fdaa04f2f2d82b1180def5aba09 100644 (file)
@@ -58,9 +58,17 @@ qxl_debugfs_buffers_info(struct seq_file *m, void *data)
        struct qxl_bo *bo;
 
        list_for_each_entry(bo, &qdev->gem.objects, list) {
-               seq_printf(m, "size %ld, pc %d, sync obj %p, num releases %d\n",
-                          (unsigned long)bo->gem_base.size, bo->pin_count,
-                          bo->tbo.sync_obj, bo->fence.num_active_releases);
+               struct reservation_object_list *fobj;
+               int rel;
+
+               rcu_read_lock();
+               fobj = rcu_dereference(bo->tbo.resv->fence);
+               rel = fobj ? fobj->shared_count : 0;
+               rcu_read_unlock();
+
+               seq_printf(m, "size %ld, pc %d, num releases %d\n",
+                          (unsigned long)bo->gem_base.size,
+                          bo->pin_count, rel);
        }
        return 0;
 }
index b8ced08b62916b643436375aa853a82c2560a947..af9e785466883ae52a9812620421221af0630894 100644 (file)
@@ -187,6 +187,54 @@ static void qxl_crtc_destroy(struct drm_crtc *crtc)
        kfree(qxl_crtc);
 }
 
+static int qxl_crtc_page_flip(struct drm_crtc *crtc,
+                              struct drm_framebuffer *fb,
+                              struct drm_pending_vblank_event *event,
+                              uint32_t page_flip_flags)
+{
+       struct drm_device *dev = crtc->dev;
+       struct qxl_device *qdev = dev->dev_private;
+       struct qxl_crtc *qcrtc = to_qxl_crtc(crtc);
+       struct qxl_framebuffer *qfb_src = to_qxl_framebuffer(fb);
+       struct qxl_framebuffer *qfb_old = to_qxl_framebuffer(crtc->primary->fb);
+       struct qxl_bo *bo_old = gem_to_qxl_bo(qfb_old->obj);
+       struct qxl_bo *bo = gem_to_qxl_bo(qfb_src->obj);
+       unsigned long flags;
+       struct drm_clip_rect norect = {
+           .x1 = 0,
+           .y1 = 0,
+           .x2 = fb->width,
+           .y2 = fb->height
+       };
+       int inc = 1;
+       int one_clip_rect = 1;
+       int ret = 0;
+
+       crtc->primary->fb = fb;
+       bo_old->is_primary = false;
+       bo->is_primary = true;
+
+       ret = qxl_bo_reserve(bo, false);
+       if (ret)
+               return ret;
+
+       qxl_draw_dirty_fb(qdev, qfb_src, bo, 0, 0,
+                         &norect, one_clip_rect, inc);
+
+       drm_vblank_get(dev, qcrtc->index);
+
+       if (event) {
+               spin_lock_irqsave(&dev->event_lock, flags);
+               drm_send_vblank_event(dev, qcrtc->index, event);
+               spin_unlock_irqrestore(&dev->event_lock, flags);
+       }
+       drm_vblank_put(dev, qcrtc->index);
+
+       qxl_bo_unreserve(bo);
+
+       return 0;
+}
+
 static int
 qxl_hide_cursor(struct qxl_device *qdev)
 {
@@ -374,6 +422,7 @@ static const struct drm_crtc_funcs qxl_crtc_funcs = {
        .cursor_move = qxl_crtc_cursor_move,
        .set_config = drm_crtc_helper_set_config,
        .destroy = qxl_crtc_destroy,
+       .page_flip = qxl_crtc_page_flip,
 };
 
 static void qxl_user_framebuffer_destroy(struct drm_framebuffer *fb)
index a3fd92029a14b6050e8f91cbeeb9a735bc6f3299..1d9b80c91a152585ba8c4380825e5964fe5e4cf0 100644 (file)
@@ -84,6 +84,7 @@ static const struct file_operations qxl_fops = {
        .release = drm_release,
        .unlocked_ioctl = drm_ioctl,
        .poll = drm_poll,
+       .read = drm_read,
        .mmap = qxl_mmap,
 };
 
@@ -195,6 +196,20 @@ static int qxl_pm_restore(struct device *dev)
        return qxl_drm_resume(drm_dev, false);
 }
 
+static u32 qxl_noop_get_vblank_counter(struct drm_device *dev, int crtc)
+{
+       return dev->vblank[crtc].count.counter;
+}
+
+static int qxl_noop_enable_vblank(struct drm_device *dev, int crtc)
+{
+       return 0;
+}
+
+static void qxl_noop_disable_vblank(struct drm_device *dev, int crtc)
+{
+}
+
 static const struct dev_pm_ops qxl_pm_ops = {
        .suspend = qxl_pm_suspend,
        .resume = qxl_pm_resume,
@@ -212,10 +227,15 @@ static struct pci_driver qxl_pci_driver = {
 };
 
 static struct drm_driver qxl_driver = {
-       .driver_features = DRIVER_GEM | DRIVER_MODESET |
+       .driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_PRIME |
                           DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED,
        .load = qxl_driver_load,
        .unload = qxl_driver_unload,
+       .get_vblank_counter = qxl_noop_get_vblank_counter,
+       .enable_vblank = qxl_noop_enable_vblank,
+       .disable_vblank = qxl_noop_disable_vblank,
+
+       .set_busid = drm_pci_set_busid,
 
        .dumb_create = qxl_mode_dumb_create,
        .dumb_map_offset = qxl_mode_dumb_mmap,
@@ -224,6 +244,17 @@ static struct drm_driver qxl_driver = {
        .debugfs_init = qxl_debugfs_init,
        .debugfs_cleanup = qxl_debugfs_takedown,
 #endif
+       .prime_handle_to_fd = drm_gem_prime_handle_to_fd,
+       .prime_fd_to_handle = drm_gem_prime_fd_to_handle,
+       .gem_prime_export = drm_gem_prime_export,
+       .gem_prime_import = drm_gem_prime_import,
+       .gem_prime_pin = qxl_gem_prime_pin,
+       .gem_prime_unpin = qxl_gem_prime_unpin,
+       .gem_prime_get_sg_table = qxl_gem_prime_get_sg_table,
+       .gem_prime_import_sg_table = qxl_gem_prime_import_sg_table,
+       .gem_prime_vmap = qxl_gem_prime_vmap,
+       .gem_prime_vunmap = qxl_gem_prime_vunmap,
+       .gem_prime_mmap = qxl_gem_prime_mmap,
        .gem_free_object = qxl_gem_object_free,
        .gem_open_object = qxl_gem_object_open,
        .gem_close_object = qxl_gem_object_close,
index 36ed40ba773f8149d88eacef4c0633614e09eb83..7c6cafe21f5f5fd2b354c8d34494fff51fc84d3b 100644 (file)
@@ -31,6 +31,7 @@
  * Definitions taken from spice-protocol, plus kernel driver specific bits.
  */
 
+#include <linux/fence.h>
 #include <linux/workqueue.h>
 #include <linux/firmware.h>
 #include <linux/platform_device.h>
@@ -42,6 +43,8 @@
 #include <ttm/ttm_placement.h>
 #include <ttm/ttm_module.h>
 
+#include <drm/drm_gem.h>
+
 /* just for ttm_validate_buffer */
 #include <ttm/ttm_execbuf_util.h>
 
@@ -95,31 +98,24 @@ enum {
        QXL_INTERRUPT_IO_CMD |\
        QXL_INTERRUPT_CLIENT_MONITORS_CONFIG)
 
-struct qxl_fence {
-       struct qxl_device *qdev;
-       uint32_t num_active_releases;
-       uint32_t *release_ids;
-       struct radix_tree_root tree;
-};
-
 struct qxl_bo {
        /* Protected by gem.mutex */
        struct list_head                list;
        /* Protected by tbo.reserved */
-       u32                             placements[3];
+       struct ttm_place                placements[3];
        struct ttm_placement            placement;
        struct ttm_buffer_object        tbo;
        struct ttm_bo_kmap_obj          kmap;
        unsigned                        pin_count;
        void                            *kptr;
        int                             type;
+
        /* Constant after initialization */
        struct drm_gem_object           gem_base;
        bool is_primary; /* is this now a primary surface */
        bool hw_surf_alloc;
        struct qxl_surface surf;
        uint32_t surface_id;
-       struct qxl_fence fence; /* per bo fence  - list of releases */
        struct qxl_release *surf_create;
 };
 #define gem_to_qxl_bo(gobj) container_of((gobj), struct qxl_bo, gem_base)
@@ -191,6 +187,8 @@ enum {
  * spice-protocol/qxl_dev.h */
 #define QXL_MAX_RES 96
 struct qxl_release {
+       struct fence base;
+
        int id;
        int type;
        uint32_t release_offset;
@@ -284,7 +282,9 @@ struct qxl_device {
        uint8_t         slot_gen_bits;
        uint64_t        va_slot_mask;
 
+       spinlock_t      release_lock;
        struct idr      release_idr;
+       uint32_t        release_seqno;
        spinlock_t release_idr_lock;
        struct mutex    async_io_mutex;
        unsigned int last_sent_io_cmd;
@@ -532,6 +532,18 @@ int qxl_garbage_collect(struct qxl_device *qdev);
 int qxl_debugfs_init(struct drm_minor *minor);
 void qxl_debugfs_takedown(struct drm_minor *minor);
 
+/* qxl_prime.c */
+int qxl_gem_prime_pin(struct drm_gem_object *obj);
+void qxl_gem_prime_unpin(struct drm_gem_object *obj);
+struct sg_table *qxl_gem_prime_get_sg_table(struct drm_gem_object *obj);
+struct drm_gem_object *qxl_gem_prime_import_sg_table(
+       struct drm_device *dev, struct dma_buf_attachment *attach,
+       struct sg_table *sgt);
+void *qxl_gem_prime_vmap(struct drm_gem_object *obj);
+void qxl_gem_prime_vunmap(struct drm_gem_object *obj, void *vaddr);
+int qxl_gem_prime_mmap(struct drm_gem_object *obj,
+                               struct vm_area_struct *vma);
+
 /* qxl_irq.c */
 int qxl_irq_init(struct qxl_device *qdev);
 irqreturn_t qxl_irq_handler(int irq, void *arg);
@@ -561,10 +573,4 @@ qxl_surface_lookup(struct drm_device *dev, int surface_id);
 void qxl_surface_evict(struct qxl_device *qdev, struct qxl_bo *surf, bool freeing);
 int qxl_update_surface(struct qxl_device *qdev, struct qxl_bo *surf);
 
-/* qxl_fence.c */
-void qxl_fence_add_release_locked(struct qxl_fence *qfence, uint32_t rel_id);
-int qxl_fence_remove_release(struct qxl_fence *qfence, uint32_t rel_id);
-int qxl_fence_init(struct qxl_device *qdev, struct qxl_fence *qfence);
-void qxl_fence_fini(struct qxl_fence *qfence);
-
 #endif
index df567888bb1e3e04ef73b3b3f38a8a9e75e1fc5d..3d7c1d00a424cfbdbdf53881421f2f4e193f247e 100644 (file)
@@ -625,7 +625,8 @@ static int qxl_fb_find_or_create_single(
                struct drm_fb_helper *helper,
                struct drm_fb_helper_surface_size *sizes)
 {
-       struct qxl_fbdev *qfbdev = (struct qxl_fbdev *)helper;
+       struct qxl_fbdev *qfbdev =
+               container_of(helper, struct qxl_fbdev, helper);
        int new_fb = 0;
        int ret;
 
diff --git a/drivers/gpu/drm/qxl/qxl_fence.c b/drivers/gpu/drm/qxl/qxl_fence.c
deleted file mode 100644 (file)
index ae59e91..0000000
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * Copyright 2013 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Dave Airlie
- *          Alon Levy
- */
-
-
-#include "qxl_drv.h"
-
-/* QXL fencing-
-
-   When we submit operations to the GPU we pass a release reference to the GPU
-   with them, the release reference is then added to the release ring when
-   the GPU is finished with that particular operation and has removed it from
-   its tree.
-
-   So we have can have multiple outstanding non linear fences per object.
-
-   From a TTM POV we only care if the object has any outstanding releases on
-   it.
-
-   we wait until all outstanding releases are processeed.
-
-   sync object is just a list of release ids that represent that fence on
-   that buffer.
-
-   we just add new releases onto the sync object attached to the object.
-
-   This currently uses a radix tree to store the list of release ids.
-
-   For some reason every so often qxl hw fails to release, things go wrong.
-*/
-/* must be called with the fence lock held */
-void qxl_fence_add_release_locked(struct qxl_fence *qfence, uint32_t rel_id)
-{
-       radix_tree_insert(&qfence->tree, rel_id, qfence);
-       qfence->num_active_releases++;
-}
-
-int qxl_fence_remove_release(struct qxl_fence *qfence, uint32_t rel_id)
-{
-       void *ret;
-       int retval = 0;
-       struct qxl_bo *bo = container_of(qfence, struct qxl_bo, fence);
-
-       spin_lock(&bo->tbo.bdev->fence_lock);
-
-       ret = radix_tree_delete(&qfence->tree, rel_id);
-       if (ret == qfence)
-               qfence->num_active_releases--;
-       else {
-               DRM_DEBUG("didn't find fence in radix tree for %d\n", rel_id);
-               retval = -ENOENT;
-       }
-       spin_unlock(&bo->tbo.bdev->fence_lock);
-       return retval;
-}
-
-
-int qxl_fence_init(struct qxl_device *qdev, struct qxl_fence *qfence)
-{
-       qfence->qdev = qdev;
-       qfence->num_active_releases = 0;
-       INIT_RADIX_TREE(&qfence->tree, GFP_ATOMIC);
-       return 0;
-}
-
-void qxl_fence_fini(struct qxl_fence *qfence)
-{
-       kfree(qfence->release_ids);
-       qfence->num_active_releases = 0;
-}
index fd88eb4a3f79d1be5b5478ef04a3c77dde2dbb71..b2977a18193589250f1c0e69814eb72ec05ef05e 100644 (file)
@@ -223,6 +223,7 @@ static int qxl_device_init(struct qxl_device *qdev,
 
        idr_init(&qdev->release_idr);
        spin_lock_init(&qdev->release_idr_lock);
+       spin_lock_init(&qdev->release_lock);
 
        idr_init(&qdev->surf_id_idr);
        spin_lock_init(&qdev->surf_id_idr_lock);
@@ -297,6 +298,9 @@ int qxl_driver_unload(struct drm_device *dev)
 
        if (qdev == NULL)
                return 0;
+
+       drm_vblank_cleanup(dev);
+
        qxl_modeset_fini(qdev);
        qxl_device_fini(qdev);
 
@@ -324,15 +328,20 @@ int qxl_driver_load(struct drm_device *dev, unsigned long flags)
        if (r)
                goto out;
 
+       r = drm_vblank_init(dev, 1);
+       if (r)
+               goto unload;
+
        r = qxl_modeset_init(qdev);
-       if (r) {
-               qxl_driver_unload(dev);
-               goto out;
-       }
+       if (r)
+               goto unload;
 
        drm_kms_helper_poll_init(qdev->ddev);
 
        return 0;
+unload:
+       qxl_driver_unload(dev);
+
 out:
        kfree(qdev);
        return r;
index b95f144f0b4934abbb034e22c5d057a065bcecd6..cdeaf08fdc745a9b27600e78edc200e97e53c620 100644 (file)
@@ -36,7 +36,6 @@ static void qxl_ttm_bo_destroy(struct ttm_buffer_object *tbo)
        qdev = (struct qxl_device *)bo->gem_base.dev->dev_private;
 
        qxl_surface_evict(qdev, bo, false);
-       qxl_fence_fini(&bo->fence);
        mutex_lock(&qdev->gem.mutex);
        list_del_init(&bo->list);
        mutex_unlock(&qdev->gem.mutex);
@@ -55,21 +54,24 @@ void qxl_ttm_placement_from_domain(struct qxl_bo *qbo, u32 domain, bool pinned)
 {
        u32 c = 0;
        u32 pflag = pinned ? TTM_PL_FLAG_NO_EVICT : 0;
+       unsigned i;
 
-       qbo->placement.fpfn = 0;
-       qbo->placement.lpfn = 0;
        qbo->placement.placement = qbo->placements;
        qbo->placement.busy_placement = qbo->placements;
        if (domain == QXL_GEM_DOMAIN_VRAM)
-               qbo->placements[c++] = TTM_PL_FLAG_CACHED | TTM_PL_FLAG_VRAM | pflag;
+               qbo->placements[c++].flags = TTM_PL_FLAG_CACHED | TTM_PL_FLAG_VRAM | pflag;
        if (domain == QXL_GEM_DOMAIN_SURFACE)
-               qbo->placements[c++] = TTM_PL_FLAG_CACHED | TTM_PL_FLAG_PRIV0 | pflag;
+               qbo->placements[c++].flags = TTM_PL_FLAG_CACHED | TTM_PL_FLAG_PRIV0 | pflag;
        if (domain == QXL_GEM_DOMAIN_CPU)
-               qbo->placements[c++] = TTM_PL_MASK_CACHING | TTM_PL_FLAG_SYSTEM | pflag;
+               qbo->placements[c++].flags = TTM_PL_MASK_CACHING | TTM_PL_FLAG_SYSTEM | pflag;
        if (!c)
-               qbo->placements[c++] = TTM_PL_MASK_CACHING | TTM_PL_FLAG_SYSTEM;
+               qbo->placements[c++].flags = TTM_PL_MASK_CACHING | TTM_PL_FLAG_SYSTEM;
        qbo->placement.num_placement = c;
        qbo->placement.num_busy_placement = c;
+       for (i = 0; i < c; ++i) {
+               qbo->placements[i].fpfn = 0;
+               qbo->placements[i].lpfn = 0;
+       }
 }
 
 
@@ -99,7 +101,6 @@ int qxl_bo_create(struct qxl_device *qdev,
        bo->type = domain;
        bo->pin_count = pinned ? 1 : 0;
        bo->surface_id = 0;
-       qxl_fence_init(qdev, &bo->fence);
        INIT_LIST_HEAD(&bo->list);
 
        if (surf)
@@ -109,7 +110,7 @@ int qxl_bo_create(struct qxl_device *qdev,
 
        r = ttm_bo_init(&qdev->mman.bdev, &bo->tbo, size, type,
                        &bo->placement, 0, !kernel, NULL, size,
-                       NULL, &qxl_ttm_bo_destroy);
+                       NULL, NULL, &qxl_ttm_bo_destroy);
        if (unlikely(r != 0)) {
                if (r != -ERESTARTSYS)
                        dev_err(qdev->dev,
@@ -259,7 +260,7 @@ int qxl_bo_unpin(struct qxl_bo *bo)
        if (bo->pin_count)
                return 0;
        for (i = 0; i < bo->placement.num_placement; i++)
-               bo->placements[i] &= ~TTM_PL_FLAG_NO_EVICT;
+               bo->placements[i].flags &= ~TTM_PL_FLAG_NO_EVICT;
        r = ttm_bo_validate(&bo->tbo, &bo->placement, false, false);
        if (unlikely(r != 0))
                dev_err(qdev->dev, "%p validate failed for unpin\n", bo);
index 83a423293afd67a66079dac61ec8bbc48f254edb..37af1bc0dd00102431e1f9415e0af7cf39b4edf8 100644 (file)
@@ -76,12 +76,10 @@ static inline int qxl_bo_wait(struct qxl_bo *bo, u32 *mem_type,
                }
                return r;
        }
-       spin_lock(&bo->tbo.bdev->fence_lock);
        if (mem_type)
                *mem_type = bo->tbo.mem.mem_type;
-       if (bo->tbo.sync_obj)
-               r = ttm_bo_wait(&bo->tbo, true, true, no_wait);
-       spin_unlock(&bo->tbo.bdev->fence_lock);
+
+       r = ttm_bo_wait(&bo->tbo, true, true, no_wait);
        ttm_bo_unreserve(&bo->tbo);
        return r;
 }
diff --git a/drivers/gpu/drm/qxl/qxl_prime.c b/drivers/gpu/drm/qxl/qxl_prime.c
new file mode 100644 (file)
index 0000000..3d031b5
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+ * Copyright 2014 Canonical
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Andreas Pokorny
+ */
+
+#include "qxl_drv.h"
+
+/* Empty Implementations as there should not be any other driver for a virtual
+ * device that might share buffers with qxl */
+
+int qxl_gem_prime_pin(struct drm_gem_object *obj)
+{
+       WARN_ONCE(1, "not implemented");
+       return -ENOSYS;
+}
+
+void qxl_gem_prime_unpin(struct drm_gem_object *obj)
+{
+       WARN_ONCE(1, "not implemented");
+}
+
+
+struct sg_table *qxl_gem_prime_get_sg_table(struct drm_gem_object *obj)
+{
+       WARN_ONCE(1, "not implemented");
+       return ERR_PTR(-ENOSYS);
+}
+
+struct drm_gem_object *qxl_gem_prime_import_sg_table(
+       struct drm_device *dev, struct dma_buf_attachment *attach,
+       struct sg_table *table)
+{
+       WARN_ONCE(1, "not implemented");
+       return ERR_PTR(-ENOSYS);
+}
+
+void *qxl_gem_prime_vmap(struct drm_gem_object *obj)
+{
+       WARN_ONCE(1, "not implemented");
+       return ERR_PTR(-ENOSYS);
+}
+
+void qxl_gem_prime_vunmap(struct drm_gem_object *obj, void *vaddr)
+{
+       WARN_ONCE(1, "not implemented");
+}
+
+int qxl_gem_prime_mmap(struct drm_gem_object *obj,
+                      struct vm_area_struct *area)
+{
+       WARN_ONCE(1, "not implemented");
+       return ENOSYS;
+}
index 14e776f1d14e3bf099259d8d6b8f94ac9896f63b..446e71ca36cb111c5d47aad5b4928eb6548a68c5 100644 (file)
@@ -21,6 +21,7 @@
  */
 #include "qxl_drv.h"
 #include "qxl_object.h"
+#include <trace/events/fence.h>
 
 /*
  * drawable cmd cache - allocate a bunch of VRAM pages, suballocate
 static const int release_size_per_bo[] = { RELEASE_SIZE, SURFACE_RELEASE_SIZE, RELEASE_SIZE };
 static const int releases_per_bo[] = { RELEASES_PER_BO, SURFACE_RELEASES_PER_BO, RELEASES_PER_BO };
 
+static const char *qxl_get_driver_name(struct fence *fence)
+{
+       return "qxl";
+}
+
+static const char *qxl_get_timeline_name(struct fence *fence)
+{
+       return "release";
+}
+
+static bool qxl_nop_signaling(struct fence *fence)
+{
+       /* fences are always automatically signaled, so just pretend we did this.. */
+       return true;
+}
+
+static long qxl_fence_wait(struct fence *fence, bool intr, signed long timeout)
+{
+       struct qxl_device *qdev;
+       struct qxl_release *release;
+       int count = 0, sc = 0;
+       bool have_drawable_releases;
+       unsigned long cur, end = jiffies + timeout;
+
+       qdev = container_of(fence->lock, struct qxl_device, release_lock);
+       release = container_of(fence, struct qxl_release, base);
+       have_drawable_releases = release->type == QXL_RELEASE_DRAWABLE;
+
+retry:
+       sc++;
+
+       if (fence_is_signaled(fence))
+               goto signaled;
+
+       qxl_io_notify_oom(qdev);
+
+       for (count = 0; count < 11; count++) {
+               if (!qxl_queue_garbage_collect(qdev, true))
+                       break;
+
+               if (fence_is_signaled(fence))
+                       goto signaled;
+       }
+
+       if (fence_is_signaled(fence))
+               goto signaled;
+
+       if (have_drawable_releases || sc < 4) {
+               if (sc > 2)
+                       /* back off */
+                       usleep_range(500, 1000);
+
+               if (time_after(jiffies, end))
+                       return 0;
+
+               if (have_drawable_releases && sc > 300) {
+                       FENCE_WARN(fence, "failed to wait on release %d "
+                                         "after spincount %d\n",
+                                         fence->context & ~0xf0000000, sc);
+                       goto signaled;
+               }
+               goto retry;
+       }
+       /*
+        * yeah, original sync_obj_wait gave up after 3 spins when
+        * have_drawable_releases is not set.
+        */
+
+signaled:
+       cur = jiffies;
+       if (time_after(cur, end))
+               return 0;
+       return end - cur;
+}
+
+static const struct fence_ops qxl_fence_ops = {
+       .get_driver_name = qxl_get_driver_name,
+       .get_timeline_name = qxl_get_timeline_name,
+       .enable_signaling = qxl_nop_signaling,
+       .wait = qxl_fence_wait,
+};
+
 static uint64_t
 qxl_release_alloc(struct qxl_device *qdev, int type,
                  struct qxl_release **ret)
@@ -46,13 +129,13 @@ qxl_release_alloc(struct qxl_device *qdev, int type,
        struct qxl_release *release;
        int handle;
        size_t size = sizeof(*release);
-       int idr_ret;
 
        release = kmalloc(size, GFP_KERNEL);
        if (!release) {
                DRM_ERROR("Out of memory\n");
                return 0;
        }
+       release->base.ops = NULL;
        release->type = type;
        release->release_offset = 0;
        release->surface_release_id = 0;
@@ -60,44 +143,61 @@ qxl_release_alloc(struct qxl_device *qdev, int type,
 
        idr_preload(GFP_KERNEL);
        spin_lock(&qdev->release_idr_lock);
-       idr_ret = idr_alloc(&qdev->release_idr, release, 1, 0, GFP_NOWAIT);
+       handle = idr_alloc(&qdev->release_idr, release, 1, 0, GFP_NOWAIT);
+       release->base.seqno = ++qdev->release_seqno;
        spin_unlock(&qdev->release_idr_lock);
        idr_preload_end();
-       handle = idr_ret;
-       if (idr_ret < 0)
-               goto release_fail;
+       if (handle < 0) {
+               kfree(release);
+               *ret = NULL;
+               return handle;
+       }
        *ret = release;
        QXL_INFO(qdev, "allocated release %lld\n", handle);
        release->id = handle;
-release_fail:
-
        return handle;
 }
 
+static void
+qxl_release_free_list(struct qxl_release *release)
+{
+       while (!list_empty(&release->bos)) {
+               struct qxl_bo_list *entry;
+               struct qxl_bo *bo;
+
+               entry = container_of(release->bos.next,
+                                    struct qxl_bo_list, tv.head);
+               bo = to_qxl_bo(entry->tv.bo);
+               qxl_bo_unref(&bo);
+               list_del(&entry->tv.head);
+               kfree(entry);
+       }
+}
+
 void
 qxl_release_free(struct qxl_device *qdev,
                 struct qxl_release *release)
 {
-       struct qxl_bo_list *entry, *tmp;
        QXL_INFO(qdev, "release %d, type %d\n", release->id,
                 release->type);
 
        if (release->surface_release_id)
                qxl_surface_id_dealloc(qdev, release->surface_release_id);
 
-       list_for_each_entry_safe(entry, tmp, &release->bos, tv.head) {
-               struct qxl_bo *bo = to_qxl_bo(entry->tv.bo);
-               QXL_INFO(qdev, "release %llx\n",
-                       drm_vma_node_offset_addr(&entry->tv.bo->vma_node)
-                                               - DRM_FILE_OFFSET);
-               qxl_fence_remove_release(&bo->fence, release->id);
-               qxl_bo_unref(&bo);
-               kfree(entry);
-       }
        spin_lock(&qdev->release_idr_lock);
        idr_remove(&qdev->release_idr, release->id);
        spin_unlock(&qdev->release_idr_lock);
-       kfree(release);
+
+       if (release->base.ops) {
+               WARN_ON(list_empty(&release->bos));
+               qxl_release_free_list(release);
+
+               fence_signal(&release->base);
+               fence_put(&release->base);
+       } else {
+               qxl_release_free_list(release);
+               kfree(release);
+       }
 }
 
 static int qxl_release_bo_alloc(struct qxl_device *qdev,
@@ -126,6 +226,7 @@ int qxl_release_list_add(struct qxl_release *release, struct qxl_bo *bo)
 
        qxl_bo_ref(bo);
        entry->tv.bo = &bo->tbo;
+       entry->tv.shared = false;
        list_add_tail(&entry->tv.head, &release->bos);
        return 0;
 }
@@ -142,6 +243,10 @@ static int qxl_release_validate_bo(struct qxl_bo *bo)
                        return ret;
        }
 
+       ret = reservation_object_reserve_shared(bo->tbo.resv);
+       if (ret)
+               return ret;
+
        /* allocate a surface for reserved + validated buffers */
        ret = qxl_bo_check_id(bo->gem_base.dev->dev_private, bo);
        if (ret)
@@ -159,7 +264,7 @@ int qxl_release_reserve_list(struct qxl_release *release, bool no_intr)
        if (list_is_singular(&release->bos))
                return 0;
 
-       ret = ttm_eu_reserve_buffers(&release->ticket, &release->bos);
+       ret = ttm_eu_reserve_buffers(&release->ticket, &release->bos, !no_intr);
        if (ret)
                return ret;
 
@@ -199,6 +304,8 @@ int qxl_alloc_surface_release_reserved(struct qxl_device *qdev,
 
                /* stash the release after the create command */
                idr_ret = qxl_release_alloc(qdev, QXL_RELEASE_SURFACE_CMD, release);
+               if (idr_ret < 0)
+                       return idr_ret;
                bo = qxl_bo_ref(to_qxl_bo(entry->tv.bo));
 
                (*release)->release_offset = create_rel->release_offset + 64;
@@ -239,6 +346,11 @@ int qxl_alloc_release_reserved(struct qxl_device *qdev, unsigned long size,
        }
 
        idr_ret = qxl_release_alloc(qdev, type, release);
+       if (idr_ret < 0) {
+               if (rbo)
+                       *rbo = NULL;
+               return idr_ret;
+       }
 
        mutex_lock(&qdev->release_mutex);
        if (qdev->current_release_bo_offset[cur_idx] + 1 >= releases_per_bo[cur_idx]) {
@@ -319,40 +431,44 @@ void qxl_release_unmap(struct qxl_device *qdev,
 
 void qxl_release_fence_buffer_objects(struct qxl_release *release)
 {
-       struct ttm_validate_buffer *entry;
        struct ttm_buffer_object *bo;
        struct ttm_bo_global *glob;
        struct ttm_bo_device *bdev;
        struct ttm_bo_driver *driver;
        struct qxl_bo *qbo;
+       struct ttm_validate_buffer *entry;
+       struct qxl_device *qdev;
 
        /* if only one object on the release its the release itself
           since these objects are pinned no need to reserve */
-       if (list_is_singular(&release->bos))
+       if (list_is_singular(&release->bos) || list_empty(&release->bos))
                return;
 
        bo = list_first_entry(&release->bos, struct ttm_validate_buffer, head)->bo;
        bdev = bo->bdev;
+       qdev = container_of(bdev, struct qxl_device, mman.bdev);
+
+       /*
+        * Since we never really allocated a context and we don't want to conflict,
+        * set the highest bits. This will break if we really allow exporting of dma-bufs.
+        */
+       fence_init(&release->base, &qxl_fence_ops, &qdev->release_lock,
+                  release->id | 0xf0000000, release->base.seqno);
+       trace_fence_emit(&release->base);
+
        driver = bdev->driver;
        glob = bo->glob;
 
        spin_lock(&glob->lru_lock);
-       spin_lock(&bdev->fence_lock);
 
        list_for_each_entry(entry, &release->bos, head) {
                bo = entry->bo;
                qbo = to_qxl_bo(bo);
 
-               if (!entry->bo->sync_obj)
-                       entry->bo->sync_obj = &qbo->fence;
-
-               qxl_fence_add_release_locked(&qbo->fence, release->id);
-
+               reservation_object_add_shared_fence(bo->resv, &release->base);
                ttm_bo_add_to_lru(bo);
                __ttm_bo_unreserve(bo);
-               entry->reserved = false;
        }
-       spin_unlock(&bdev->fence_lock);
        spin_unlock(&glob->lru_lock);
        ww_acquire_fini(&release->ticket);
 }
index 71a1baeac14edc4ceabb8ab397d0dfe2c23b335b..0cbc4c9871643eb5da5cf210fc8b301dee912feb 100644 (file)
@@ -127,7 +127,7 @@ int qxl_mmap(struct file *filp, struct vm_area_struct *vma)
        if (unlikely(vma->vm_pgoff < DRM_FILE_PAGE_OFFSET)) {
                pr_info("%s: vma->vm_pgoff (%ld) < DRM_FILE_PAGE_OFFSET\n",
                        __func__, vma->vm_pgoff);
-               return drm_mmap(filp, vma);
+               return -EINVAL;
        }
 
        file_priv = filp->private_data;
@@ -188,11 +188,13 @@ static void qxl_evict_flags(struct ttm_buffer_object *bo,
                                struct ttm_placement *placement)
 {
        struct qxl_bo *qbo;
-       static u32 placements = TTM_PL_MASK_CACHING | TTM_PL_FLAG_SYSTEM;
+       static struct ttm_place placements = {
+               .fpfn = 0,
+               .lpfn = 0,
+               .flags = TTM_PL_MASK_CACHING | TTM_PL_FLAG_SYSTEM
+       };
 
        if (!qxl_ttm_bo_is_qxl_bo(bo)) {
-               placement->fpfn = 0;
-               placement->lpfn = 0;
                placement->placement = &placements;
                placement->busy_placement = &placements;
                placement->num_placement = 1;
@@ -355,92 +357,6 @@ static int qxl_bo_move(struct ttm_buffer_object *bo,
        return ttm_bo_move_memcpy(bo, evict, no_wait_gpu, new_mem);
 }
 
-
-static int qxl_sync_obj_wait(void *sync_obj,
-                            bool lazy, bool interruptible)
-{
-       struct qxl_fence *qfence = (struct qxl_fence *)sync_obj;
-       int count = 0, sc = 0;
-       struct qxl_bo *bo = container_of(qfence, struct qxl_bo, fence);
-
-       if (qfence->num_active_releases == 0)
-               return 0;
-
-retry:
-       if (sc == 0) {
-               if (bo->type == QXL_GEM_DOMAIN_SURFACE)
-                       qxl_update_surface(qfence->qdev, bo);
-       } else if (sc >= 1) {
-               qxl_io_notify_oom(qfence->qdev);
-       }
-
-       sc++;
-
-       for (count = 0; count < 10; count++) {
-               bool ret;
-               ret = qxl_queue_garbage_collect(qfence->qdev, true);
-               if (ret == false)
-                       break;
-
-               if (qfence->num_active_releases == 0)
-                       return 0;
-       }
-
-       if (qfence->num_active_releases) {
-               bool have_drawable_releases = false;
-               void **slot;
-               struct radix_tree_iter iter;
-               int release_id;
-
-               radix_tree_for_each_slot(slot, &qfence->tree, &iter, 0) {
-                       struct qxl_release *release;
-
-                       release_id = iter.index;
-                       release = qxl_release_from_id_locked(qfence->qdev, release_id);
-                       if (release == NULL)
-                               continue;
-
-                       if (release->type == QXL_RELEASE_DRAWABLE)
-                               have_drawable_releases = true;
-               }
-
-               qxl_queue_garbage_collect(qfence->qdev, true);
-
-               if (have_drawable_releases || sc < 4) {
-                       if (sc > 2)
-                               /* back off */
-                               usleep_range(500, 1000);
-                       if (have_drawable_releases && sc > 300) {
-                               WARN(1, "sync obj %d still has outstanding releases %d %d %d %ld %d\n", sc, bo->surface_id, bo->is_primary, bo->pin_count, (unsigned long)bo->gem_base.size, qfence->num_active_releases);
-                               return -EBUSY;
-                       }
-                       goto retry;
-               }
-       }
-       return 0;
-}
-
-static int qxl_sync_obj_flush(void *sync_obj)
-{
-       return 0;
-}
-
-static void qxl_sync_obj_unref(void **sync_obj)
-{
-       *sync_obj = NULL;
-}
-
-static void *qxl_sync_obj_ref(void *sync_obj)
-{
-       return sync_obj;
-}
-
-static bool qxl_sync_obj_signaled(void *sync_obj)
-{
-       struct qxl_fence *qfence = (struct qxl_fence *)sync_obj;
-       return (qfence->num_active_releases == 0);
-}
-
 static void qxl_bo_move_notify(struct ttm_buffer_object *bo,
                               struct ttm_mem_reg *new_mem)
 {
@@ -467,16 +383,9 @@ static struct ttm_bo_driver qxl_bo_driver = {
        .verify_access = &qxl_verify_access,
        .io_mem_reserve = &qxl_ttm_io_mem_reserve,
        .io_mem_free = &qxl_ttm_io_mem_free,
-       .sync_obj_signaled = &qxl_sync_obj_signaled,
-       .sync_obj_wait = &qxl_sync_obj_wait,
-       .sync_obj_flush = &qxl_sync_obj_flush,
-       .sync_obj_unref = &qxl_sync_obj_unref,
-       .sync_obj_ref = &qxl_sync_obj_ref,
        .move_notify = &qxl_bo_move_notify,
 };
 
-
-
 int qxl_ttm_init(struct qxl_device *qdev)
 {
        int r;
index 59459fe4e8c57b9c367887daa945324ac7f4eb34..2c45ac9c1dc3afc7d956387c8acd337797edacc9 100644 (file)
@@ -452,7 +452,7 @@ static int r128_do_init_cce(struct drm_device *dev, drm_r128_init_t *init)
        dev_priv->span_pitch_offset_c = (((dev_priv->depth_pitch / 8) << 21) |
                                         (dev_priv->span_offset >> 5));
 
-       dev_priv->sarea = drm_getsarea(dev);
+       dev_priv->sarea = drm_legacy_getsarea(dev);
        if (!dev_priv->sarea) {
                DRM_ERROR("could not find sarea!\n");
                dev->dev_private = (void *)dev_priv;
@@ -460,21 +460,21 @@ static int r128_do_init_cce(struct drm_device *dev, drm_r128_init_t *init)
                return -EINVAL;
        }
 
-       dev_priv->mmio = drm_core_findmap(dev, init->mmio_offset);
+       dev_priv->mmio = drm_legacy_findmap(dev, init->mmio_offset);
        if (!dev_priv->mmio) {
                DRM_ERROR("could not find mmio region!\n");
                dev->dev_private = (void *)dev_priv;
                r128_do_cleanup_cce(dev);
                return -EINVAL;
        }
-       dev_priv->cce_ring = drm_core_findmap(dev, init->ring_offset);
+       dev_priv->cce_ring = drm_legacy_findmap(dev, init->ring_offset);
        if (!dev_priv->cce_ring) {
                DRM_ERROR("could not find cce ring region!\n");
                dev->dev_private = (void *)dev_priv;
                r128_do_cleanup_cce(dev);
                return -EINVAL;
        }
-       dev_priv->ring_rptr = drm_core_findmap(dev, init->ring_rptr_offset);
+       dev_priv->ring_rptr = drm_legacy_findmap(dev, init->ring_rptr_offset);
        if (!dev_priv->ring_rptr) {
                DRM_ERROR("could not find ring read pointer!\n");
                dev->dev_private = (void *)dev_priv;
@@ -482,7 +482,7 @@ static int r128_do_init_cce(struct drm_device *dev, drm_r128_init_t *init)
                return -EINVAL;
        }
        dev->agp_buffer_token = init->buffers_offset;
-       dev->agp_buffer_map = drm_core_findmap(dev, init->buffers_offset);
+       dev->agp_buffer_map = drm_legacy_findmap(dev, init->buffers_offset);
        if (!dev->agp_buffer_map) {
                DRM_ERROR("could not find dma buffer region!\n");
                dev->dev_private = (void *)dev_priv;
@@ -492,7 +492,7 @@ static int r128_do_init_cce(struct drm_device *dev, drm_r128_init_t *init)
 
        if (!dev_priv->is_pci) {
                dev_priv->agp_textures =
-                   drm_core_findmap(dev, init->agp_textures_offset);
+                   drm_legacy_findmap(dev, init->agp_textures_offset);
                if (!dev_priv->agp_textures) {
                        DRM_ERROR("could not find agp texture region!\n");
                        dev->dev_private = (void *)dev_priv;
@@ -507,9 +507,9 @@ static int r128_do_init_cce(struct drm_device *dev, drm_r128_init_t *init)
 
 #if __OS_HAS_AGP
        if (!dev_priv->is_pci) {
-               drm_core_ioremap_wc(dev_priv->cce_ring, dev);
-               drm_core_ioremap_wc(dev_priv->ring_rptr, dev);
-               drm_core_ioremap_wc(dev->agp_buffer_map, dev);
+               drm_legacy_ioremap_wc(dev_priv->cce_ring, dev);
+               drm_legacy_ioremap_wc(dev_priv->ring_rptr, dev);
+               drm_legacy_ioremap_wc(dev->agp_buffer_map, dev);
                if (!dev_priv->cce_ring->handle ||
                    !dev_priv->ring_rptr->handle ||
                    !dev->agp_buffer_map->handle) {
@@ -603,11 +603,11 @@ int r128_do_cleanup_cce(struct drm_device *dev)
 #if __OS_HAS_AGP
                if (!dev_priv->is_pci) {
                        if (dev_priv->cce_ring != NULL)
-                               drm_core_ioremapfree(dev_priv->cce_ring, dev);
+                               drm_legacy_ioremapfree(dev_priv->cce_ring, dev);
                        if (dev_priv->ring_rptr != NULL)
-                               drm_core_ioremapfree(dev_priv->ring_rptr, dev);
+                               drm_legacy_ioremapfree(dev_priv->ring_rptr, dev);
                        if (dev->agp_buffer_map != NULL) {
-                               drm_core_ioremapfree(dev->agp_buffer_map, dev);
+                               drm_legacy_ioremapfree(dev->agp_buffer_map, dev);
                                dev->agp_buffer_map = NULL;
                        }
                } else
index 5bd307cd8da129316db121ad0e41736a10338322..c57b4de63caf5f633edda167a83009f6fb6a8484 100644 (file)
@@ -46,7 +46,7 @@ static const struct file_operations r128_driver_fops = {
        .open = drm_open,
        .release = drm_release,
        .unlocked_ioctl = drm_ioctl,
-       .mmap = drm_mmap,
+       .mmap = drm_legacy_mmap,
        .poll = drm_poll,
 #ifdef CONFIG_COMPAT
        .compat_ioctl = r128_compat_ioctl,
@@ -62,6 +62,7 @@ static struct drm_driver driver = {
        .load = r128_driver_load,
        .preclose = r128_driver_preclose,
        .lastclose = r128_driver_lastclose,
+       .set_busid = drm_pci_set_busid,
        .get_vblank_counter = r128_get_vblank_counter,
        .enable_vblank = r128_enable_vblank,
        .disable_vblank = r128_disable_vblank,
index 5bf3f5ff805d941b74e05ab26f5119b8f154c057..723e5d6f10a4b96ed1a7db6f5f71f6c51d6a1f3c 100644 (file)
@@ -35,6 +35,9 @@
 #ifndef __R128_DRV_H__
 #define __R128_DRV_H__
 
+#include <drm/ati_pcigart.h>
+#include <drm/drm_legacy.h>
+
 /* General customization:
  */
 #define DRIVER_AUTHOR          "Gareth Hughes, VA Linux Systems Inc."
index f77b7135ee4cde8e07b96c619f0bca8f94cdc37b..d01b87991422588c24b8f477a1050641cb683aa1 100644 (file)
@@ -60,7 +60,7 @@ radeon-y := radeon_drv.o
 
 # add UMS driver
 radeon-$(CONFIG_DRM_RADEON_UMS)+= radeon_cp.o radeon_state.o radeon_mem.o \
-       radeon_irq.o r300_cmdbuf.o r600_cp.o r600_blit.o
+       radeon_irq.o r300_cmdbuf.o r600_cp.o r600_blit.o drm_buffer.o
 
 # add KMS driver
 radeon-y += radeon_device.o radeon_asic.o radeon_kms.o \
@@ -72,7 +72,7 @@ radeon-y += radeon_device.o radeon_asic.o radeon_kms.o \
        radeon_cs.o radeon_bios.o radeon_benchmark.o r100.o r300.o r420.o \
        rs400.o rs600.o rs690.o rv515.o r520.o r600.o rv770.o radeon_test.o \
        r200.o radeon_legacy_tv.o r600_cs.o r600_blit_shaders.o \
-       radeon_pm.o atombios_dp.o r600_audio.o r600_hdmi.o dce3_1_afmt.o \
+       radeon_pm.o atombios_dp.o r600_hdmi.o dce3_1_afmt.o \
        evergreen.o evergreen_cs.o evergreen_blit_shaders.o \
        evergreen_hdmi.o radeon_trace_points.o ni.o cayman_blit_shaders.o \
        atombios_encoders.o radeon_semaphore.o radeon_sa.o atombios_i2c.o si.o \
@@ -80,7 +80,7 @@ radeon-y += radeon_device.o radeon_asic.o radeon_kms.o \
        r600_dpm.o rs780_dpm.o rv6xx_dpm.o rv770_dpm.o rv730_dpm.o rv740_dpm.o \
        rv770_smc.o cypress_dpm.o btc_dpm.o sumo_dpm.o sumo_smc.o trinity_dpm.o \
        trinity_smc.o ni_dpm.o si_smc.o si_dpm.o kv_smc.o kv_dpm.o ci_smc.o \
-       ci_dpm.o dce6_afmt.o radeon_vm.o radeon_ucode.o radeon_ib.o
+       ci_dpm.o dce6_afmt.o radeon_vm.o radeon_ucode.o radeon_ib.o radeon_mn.o
 
 # add async DMA block
 radeon-y += \
index ac14b67621d36f7a068de85103e06ba644915ea3..95d5d4ab3335edd2c86146c487c9cbd7bc269182 100644 (file)
@@ -232,8 +232,8 @@ void radeon_dp_aux_init(struct radeon_connector *radeon_connector)
 
 /***** general DP utility functions *****/
 
-#define DP_VOLTAGE_MAX         DP_TRAIN_VOLTAGE_SWING_1200
-#define DP_PRE_EMPHASIS_MAX    DP_TRAIN_PRE_EMPHASIS_9_5
+#define DP_VOLTAGE_MAX         DP_TRAIN_VOLTAGE_SWING_LEVEL_3
+#define DP_PRE_EMPHASIS_MAX    DP_TRAIN_PRE_EMPH_LEVEL_3
 
 static void dp_get_adjust_train(u8 link_status[DP_LINK_STATUS_SIZE],
                                int lane_count,
index a7f2ddf09a9d20024a0cca95e70d3f3b8ff5fc12..b8cd7975f797e7d09bb3792ff3af15462cba68a6 100644 (file)
@@ -291,29 +291,6 @@ static void radeon_atom_backlight_exit(struct radeon_encoder *encoder)
 bool radeon_atom_get_tv_timings(struct radeon_device *rdev, int index,
                                struct drm_display_mode *mode);
 
-
-static inline bool radeon_encoder_is_digital(struct drm_encoder *encoder)
-{
-       struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
-       switch (radeon_encoder->encoder_id) {
-       case ENCODER_OBJECT_ID_INTERNAL_LVDS:
-       case ENCODER_OBJECT_ID_INTERNAL_TMDS1:
-       case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1:
-       case ENCODER_OBJECT_ID_INTERNAL_LVTM1:
-       case ENCODER_OBJECT_ID_INTERNAL_DVO1:
-       case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1:
-       case ENCODER_OBJECT_ID_INTERNAL_DDI:
-       case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
-       case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA:
-       case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
-       case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
-       case ENCODER_OBJECT_ID_INTERNAL_UNIPHY3:
-               return true;
-       default:
-               return false;
-       }
-}
-
 static bool radeon_atom_mode_fixup(struct drm_encoder *encoder,
                                   const struct drm_display_mode *mode,
                                   struct drm_display_mode *adjusted_mode)
index f81d7ca134db19d12782f2005177639e64b6a44c..300d971187c4fca19f5b9676cb92d74c6b712969 100644 (file)
@@ -1170,23 +1170,6 @@ static const struct radeon_blacklist_clocks btc_blacklist_clocks[] =
         { 25000, 30000, RADEON_SCLK_UP }
 };
 
-void btc_get_max_clock_from_voltage_dependency_table(struct radeon_clock_voltage_dependency_table *table,
-                                                    u32 *max_clock)
-{
-       u32 i, clock = 0;
-
-       if ((table == NULL) || (table->count == 0)) {
-               *max_clock = clock;
-               return;
-       }
-
-       for (i = 0; i < table->count; i++) {
-               if (clock < table->entries[i].clk)
-                       clock = table->entries[i].clk;
-       }
-       *max_clock = clock;
-}
-
 void btc_apply_voltage_dependency_rules(struct radeon_clock_voltage_dependency_table *table,
                                        u32 clock, u16 max_voltage, u16 *voltage)
 {
@@ -2099,7 +2082,6 @@ static void btc_apply_state_adjust_rules(struct radeon_device *rdev,
        bool disable_mclk_switching;
        u32 mclk, sclk;
        u16 vddc, vddci;
-       u32 max_sclk_vddc, max_mclk_vddci, max_mclk_vddc;
 
        if ((rdev->pm.dpm.new_active_crtc_count > 1) ||
            btc_dpm_vblank_too_short(rdev))
@@ -2141,39 +2123,6 @@ static void btc_apply_state_adjust_rules(struct radeon_device *rdev,
                        ps->low.vddci = max_limits->vddci;
        }
 
-       /* limit clocks to max supported clocks based on voltage dependency tables */
-       btc_get_max_clock_from_voltage_dependency_table(&rdev->pm.dpm.dyn_state.vddc_dependency_on_sclk,
-                                                       &max_sclk_vddc);
-       btc_get_max_clock_from_voltage_dependency_table(&rdev->pm.dpm.dyn_state.vddci_dependency_on_mclk,
-                                                       &max_mclk_vddci);
-       btc_get_max_clock_from_voltage_dependency_table(&rdev->pm.dpm.dyn_state.vddc_dependency_on_mclk,
-                                                       &max_mclk_vddc);
-
-       if (max_sclk_vddc) {
-               if (ps->low.sclk > max_sclk_vddc)
-                       ps->low.sclk = max_sclk_vddc;
-               if (ps->medium.sclk > max_sclk_vddc)
-                       ps->medium.sclk = max_sclk_vddc;
-               if (ps->high.sclk > max_sclk_vddc)
-                       ps->high.sclk = max_sclk_vddc;
-       }
-       if (max_mclk_vddci) {
-               if (ps->low.mclk > max_mclk_vddci)
-                       ps->low.mclk = max_mclk_vddci;
-               if (ps->medium.mclk > max_mclk_vddci)
-                       ps->medium.mclk = max_mclk_vddci;
-               if (ps->high.mclk > max_mclk_vddci)
-                       ps->high.mclk = max_mclk_vddci;
-       }
-       if (max_mclk_vddc) {
-               if (ps->low.mclk > max_mclk_vddc)
-                       ps->low.mclk = max_mclk_vddc;
-               if (ps->medium.mclk > max_mclk_vddc)
-                       ps->medium.mclk = max_mclk_vddc;
-               if (ps->high.mclk > max_mclk_vddc)
-                       ps->high.mclk = max_mclk_vddc;
-       }
-
        /* XXX validate the min clocks required for display */
 
        if (disable_mclk_switching) {
index 3b6f12b7760ba48066f2144b73e0dc82c6521946..1a15e0e41950604ec8c27df9b11c6933c43d622d 100644 (file)
@@ -46,8 +46,6 @@ void btc_adjust_clock_combinations(struct radeon_device *rdev,
                                   struct rv7xx_pl *pl);
 void btc_apply_voltage_dependency_rules(struct radeon_clock_voltage_dependency_table *table,
                                        u32 clock, u16 max_voltage, u16 *voltage);
-void btc_get_max_clock_from_voltage_dependency_table(struct radeon_clock_voltage_dependency_table *table,
-                                                    u32 *max_clock);
 void btc_apply_voltage_delta_rules(struct radeon_device *rdev,
                                   u16 max_vddc, u16 max_vddci,
                                   u16 *vddc, u16 *vddci);
index d416bb2ff48dae0376b15e4789652799ff0638c3..f5c8c0445a94bd1b75a48c38be49a09301e8674b 100644 (file)
@@ -162,8 +162,6 @@ static const struct ci_pt_config_reg didt_config_ci[] =
 };
 
 extern u8 rv770_get_memory_module_index(struct radeon_device *rdev);
-extern void btc_get_max_clock_from_voltage_dependency_table(struct radeon_clock_voltage_dependency_table *table,
-                                                           u32 *max_clock);
 extern int ni_copy_and_switch_arb_sets(struct radeon_device *rdev,
                                       u32 arb_freq_src, u32 arb_freq_dest);
 extern u8 si_get_ddr3_mclk_frequency_ratio(u32 memory_clock);
@@ -748,7 +746,6 @@ static void ci_apply_state_adjust_rules(struct radeon_device *rdev,
        struct radeon_clock_and_voltage_limits *max_limits;
        bool disable_mclk_switching;
        u32 sclk, mclk;
-       u32 max_sclk_vddc, max_mclk_vddci, max_mclk_vddc;
        int i;
 
        if (rps->vce_active) {
@@ -784,29 +781,6 @@ static void ci_apply_state_adjust_rules(struct radeon_device *rdev,
                }
        }
 
-       /* limit clocks to max supported clocks based on voltage dependency tables */
-       btc_get_max_clock_from_voltage_dependency_table(&rdev->pm.dpm.dyn_state.vddc_dependency_on_sclk,
-                                                       &max_sclk_vddc);
-       btc_get_max_clock_from_voltage_dependency_table(&rdev->pm.dpm.dyn_state.vddci_dependency_on_mclk,
-                                                       &max_mclk_vddci);
-       btc_get_max_clock_from_voltage_dependency_table(&rdev->pm.dpm.dyn_state.vddc_dependency_on_mclk,
-                                                       &max_mclk_vddc);
-
-       for (i = 0; i < ps->performance_level_count; i++) {
-               if (max_sclk_vddc) {
-                       if (ps->performance_levels[i].sclk > max_sclk_vddc)
-                               ps->performance_levels[i].sclk = max_sclk_vddc;
-               }
-               if (max_mclk_vddci) {
-                       if (ps->performance_levels[i].mclk > max_mclk_vddci)
-                               ps->performance_levels[i].mclk = max_mclk_vddci;
-               }
-               if (max_mclk_vddc) {
-                       if (ps->performance_levels[i].mclk > max_mclk_vddc)
-                               ps->performance_levels[i].mclk = max_mclk_vddc;
-               }
-       }
-
        /* XXX validate the min clocks required for display */
 
        if (disable_mclk_switching) {
@@ -5293,9 +5267,13 @@ int ci_dpm_init(struct radeon_device *rdev)
 void ci_dpm_debugfs_print_current_performance_level(struct radeon_device *rdev,
                                                    struct seq_file *m)
 {
+       struct ci_power_info *pi = ci_get_pi(rdev);
+       struct radeon_ps *rps = &pi->current_rps;
        u32 sclk = ci_get_average_sclk_freq(rdev);
        u32 mclk = ci_get_average_mclk_freq(rdev);
 
+       seq_printf(m, "uvd    %sabled\n", pi->uvd_enabled ? "en" : "dis");
+       seq_printf(m, "vce    %sabled\n", rps->vce_active ? "en" : "dis");
        seq_printf(m, "power level avg    sclk: %u mclk: %u\n",
                   sclk, mclk);
 }
index 3d546c606b43b6fd366a1257c751b16b5aaa2df5..377afa504d2bd045cfdc5f2eed06599610c30920 100644 (file)
@@ -3959,18 +3959,19 @@ bool cik_semaphore_ring_emit(struct radeon_device *rdev,
  * @src_offset: src GPU address
  * @dst_offset: dst GPU address
  * @num_gpu_pages: number of GPU pages to xfer
- * @fence: radeon fence object
+ * @resv: reservation object to sync to
  *
  * Copy GPU paging using the CP DMA engine (CIK+).
  * Used by the radeon ttm implementation to move pages if
  * registered as the asic copy callback.
  */
-int cik_copy_cpdma(struct radeon_device *rdev,
-                  uint64_t src_offset, uint64_t dst_offset,
-                  unsigned num_gpu_pages,
-                  struct radeon_fence **fence)
+struct radeon_fence *cik_copy_cpdma(struct radeon_device *rdev,
+                                   uint64_t src_offset, uint64_t dst_offset,
+                                   unsigned num_gpu_pages,
+                                   struct reservation_object *resv)
 {
        struct radeon_semaphore *sem = NULL;
+       struct radeon_fence *fence;
        int ring_index = rdev->asic->copy.blit_ring_index;
        struct radeon_ring *ring = &rdev->ring[ring_index];
        u32 size_in_bytes, cur_size_in_bytes, control;
@@ -3980,7 +3981,7 @@ int cik_copy_cpdma(struct radeon_device *rdev,
        r = radeon_semaphore_create(rdev, &sem);
        if (r) {
                DRM_ERROR("radeon: moving bo (%d).\n", r);
-               return r;
+               return ERR_PTR(r);
        }
 
        size_in_bytes = (num_gpu_pages << RADEON_GPU_PAGE_SHIFT);
@@ -3989,10 +3990,10 @@ int cik_copy_cpdma(struct radeon_device *rdev,
        if (r) {
                DRM_ERROR("radeon: moving bo (%d).\n", r);
                radeon_semaphore_free(rdev, &sem, NULL);
-               return r;
+               return ERR_PTR(r);
        }
 
-       radeon_semaphore_sync_to(sem, *fence);
+       radeon_semaphore_sync_resv(rdev, sem, resv, false);
        radeon_semaphore_sync_rings(rdev, sem, ring->idx);
 
        for (i = 0; i < num_loops; i++) {
@@ -4014,17 +4015,17 @@ int cik_copy_cpdma(struct radeon_device *rdev,
                dst_offset += cur_size_in_bytes;
        }
 
-       r = radeon_fence_emit(rdev, fence, ring->idx);
+       r = radeon_fence_emit(rdev, &fence, ring->idx);
        if (r) {
                radeon_ring_unlock_undo(rdev, ring);
                radeon_semaphore_free(rdev, &sem, NULL);
-               return r;
+               return ERR_PTR(r);
        }
 
        radeon_ring_unlock_commit(rdev, ring, false);
-       radeon_semaphore_free(rdev, &sem, *fence);
+       radeon_semaphore_free(rdev, &sem, fence);
 
-       return r;
+       return fence;
 }
 
 /*
@@ -4234,7 +4235,7 @@ static int cik_cp_gfx_load_microcode(struct radeon_device *rdev)
                WREG32(CP_PFP_UCODE_ADDR, 0);
                for (i = 0; i < fw_size; i++)
                        WREG32(CP_PFP_UCODE_DATA, le32_to_cpup(fw_data++));
-               WREG32(CP_PFP_UCODE_ADDR, 0);
+               WREG32(CP_PFP_UCODE_ADDR, le32_to_cpu(pfp_hdr->header.ucode_version));
 
                /* CE */
                fw_data = (const __le32 *)
@@ -4243,7 +4244,7 @@ static int cik_cp_gfx_load_microcode(struct radeon_device *rdev)
                WREG32(CP_CE_UCODE_ADDR, 0);
                for (i = 0; i < fw_size; i++)
                        WREG32(CP_CE_UCODE_DATA, le32_to_cpup(fw_data++));
-               WREG32(CP_CE_UCODE_ADDR, 0);
+               WREG32(CP_CE_UCODE_ADDR, le32_to_cpu(ce_hdr->header.ucode_version));
 
                /* ME */
                fw_data = (const __be32 *)
@@ -4252,7 +4253,8 @@ static int cik_cp_gfx_load_microcode(struct radeon_device *rdev)
                WREG32(CP_ME_RAM_WADDR, 0);
                for (i = 0; i < fw_size; i++)
                        WREG32(CP_ME_RAM_DATA, le32_to_cpup(fw_data++));
-               WREG32(CP_ME_RAM_WADDR, 0);
+               WREG32(CP_ME_RAM_WADDR, le32_to_cpu(me_hdr->header.ucode_version));
+               WREG32(CP_ME_RAM_RADDR, le32_to_cpu(me_hdr->header.ucode_version));
        } else {
                const __be32 *fw_data;
 
@@ -4278,10 +4280,6 @@ static int cik_cp_gfx_load_microcode(struct radeon_device *rdev)
                WREG32(CP_ME_RAM_WADDR, 0);
        }
 
-       WREG32(CP_PFP_UCODE_ADDR, 0);
-       WREG32(CP_CE_UCODE_ADDR, 0);
-       WREG32(CP_ME_RAM_WADDR, 0);
-       WREG32(CP_ME_RAM_RADDR, 0);
        return 0;
 }
 
@@ -4563,7 +4561,7 @@ static int cik_cp_compute_load_microcode(struct radeon_device *rdev)
                WREG32(CP_MEC_ME1_UCODE_ADDR, 0);
                for (i = 0; i < fw_size; i++)
                        WREG32(CP_MEC_ME1_UCODE_DATA, le32_to_cpup(fw_data++));
-               WREG32(CP_MEC_ME1_UCODE_ADDR, 0);
+               WREG32(CP_MEC_ME1_UCODE_ADDR, le32_to_cpu(mec_hdr->header.ucode_version));
 
                /* MEC2 */
                if (rdev->family == CHIP_KAVERI) {
@@ -4577,7 +4575,7 @@ static int cik_cp_compute_load_microcode(struct radeon_device *rdev)
                        WREG32(CP_MEC_ME2_UCODE_ADDR, 0);
                        for (i = 0; i < fw_size; i++)
                                WREG32(CP_MEC_ME2_UCODE_DATA, le32_to_cpup(fw_data++));
-                       WREG32(CP_MEC_ME2_UCODE_ADDR, 0);
+                       WREG32(CP_MEC_ME2_UCODE_ADDR, le32_to_cpu(mec2_hdr->header.ucode_version));
                }
        } else {
                const __be32 *fw_data;
@@ -4689,7 +4687,7 @@ static int cik_mec_init(struct radeon_device *rdev)
                r = radeon_bo_create(rdev,
                                     rdev->mec.num_mec *rdev->mec.num_pipe * MEC_HPD_SIZE * 2,
                                     PAGE_SIZE, true,
-                                    RADEON_GEM_DOMAIN_GTT, 0, NULL,
+                                    RADEON_GEM_DOMAIN_GTT, 0, NULL, NULL,
                                     &rdev->mec.hpd_eop_obj);
                if (r) {
                        dev_warn(rdev->dev, "(%d) create HDP EOP bo failed\n", r);
@@ -4860,7 +4858,7 @@ static int cik_cp_compute_resume(struct radeon_device *rdev)
                                             sizeof(struct bonaire_mqd),
                                             PAGE_SIZE, true,
                                             RADEON_GEM_DOMAIN_GTT, 0, NULL,
-                                            &rdev->ring[idx].mqd_obj);
+                                            NULL, &rdev->ring[idx].mqd_obj);
                        if (r) {
                                dev_warn(rdev->dev, "(%d) create MQD bo failed\n", r);
                                return r;
@@ -6226,7 +6224,7 @@ static int cik_rlc_resume(struct radeon_device *rdev)
                WREG32(RLC_GPM_UCODE_ADDR, 0);
                for (i = 0; i < size; i++)
                        WREG32(RLC_GPM_UCODE_DATA, le32_to_cpup(fw_data++));
-               WREG32(RLC_GPM_UCODE_ADDR, 0);
+               WREG32(RLC_GPM_UCODE_ADDR, le32_to_cpu(hdr->header.ucode_version));
        } else {
                const __be32 *fw_data;
 
@@ -8255,8 +8253,10 @@ restart_ih:
        }
        if (queue_hotplug)
                schedule_work(&rdev->hotplug_work);
-       if (queue_reset)
-               schedule_work(&rdev->reset_work);
+       if (queue_reset) {
+               rdev->needs_reset = true;
+               wake_up_all(&rdev->fence_queue);
+       }
        if (queue_thermal)
                schedule_work(&rdev->pm.dpm.thermal.work);
        rdev->ih.rptr = rptr;
index c4ffa54b1e3df503dc5dd9645765b2f0927e87b2..c77dad1a45769b151526377fac7e601129ee9221 100644 (file)
@@ -530,18 +530,19 @@ void cik_sdma_fini(struct radeon_device *rdev)
  * @src_offset: src GPU address
  * @dst_offset: dst GPU address
  * @num_gpu_pages: number of GPU pages to xfer
- * @fence: radeon fence object
+ * @resv: reservation object to sync to
  *
  * Copy GPU paging using the DMA engine (CIK).
  * Used by the radeon ttm implementation to move pages if
  * registered as the asic copy callback.
  */
-int cik_copy_dma(struct radeon_device *rdev,
-                uint64_t src_offset, uint64_t dst_offset,
-                unsigned num_gpu_pages,
-                struct radeon_fence **fence)
+struct radeon_fence *cik_copy_dma(struct radeon_device *rdev,
+                                 uint64_t src_offset, uint64_t dst_offset,
+                                 unsigned num_gpu_pages,
+                                 struct reservation_object *resv)
 {
        struct radeon_semaphore *sem = NULL;
+       struct radeon_fence *fence;
        int ring_index = rdev->asic->copy.dma_ring_index;
        struct radeon_ring *ring = &rdev->ring[ring_index];
        u32 size_in_bytes, cur_size_in_bytes;
@@ -551,7 +552,7 @@ int cik_copy_dma(struct radeon_device *rdev,
        r = radeon_semaphore_create(rdev, &sem);
        if (r) {
                DRM_ERROR("radeon: moving bo (%d).\n", r);
-               return r;
+               return ERR_PTR(r);
        }
 
        size_in_bytes = (num_gpu_pages << RADEON_GPU_PAGE_SHIFT);
@@ -560,10 +561,10 @@ int cik_copy_dma(struct radeon_device *rdev,
        if (r) {
                DRM_ERROR("radeon: moving bo (%d).\n", r);
                radeon_semaphore_free(rdev, &sem, NULL);
-               return r;
+               return ERR_PTR(r);
        }
 
-       radeon_semaphore_sync_to(sem, *fence);
+       radeon_semaphore_sync_resv(rdev, sem, resv, false);
        radeon_semaphore_sync_rings(rdev, sem, ring->idx);
 
        for (i = 0; i < num_loops; i++) {
@@ -582,17 +583,17 @@ int cik_copy_dma(struct radeon_device *rdev,
                dst_offset += cur_size_in_bytes;
        }
 
-       r = radeon_fence_emit(rdev, fence, ring->idx);
+       r = radeon_fence_emit(rdev, &fence, ring->idx);
        if (r) {
                radeon_ring_unlock_undo(rdev, ring);
                radeon_semaphore_free(rdev, &sem, NULL);
-               return r;
+               return ERR_PTR(r);
        }
 
        radeon_ring_unlock_commit(rdev, ring, false);
-       radeon_semaphore_free(rdev, &sem, *fence);
+       radeon_semaphore_free(rdev, &sem, fence);
 
-       return r;
+       return fence;
 }
 
 /**
index 51800e340a57d5c6e5294aaeaa35f1422b606d4e..950af153f30e7a53748a0cdb943b9457db468f26 100644 (file)
@@ -165,7 +165,7 @@ void dce3_1_hdmi_setmode(struct drm_encoder *encoder, struct drm_display_mode *m
 
        /* disable audio prior to setting up hw */
        dig->afmt->pin = r600_audio_get_pin(rdev);
-       r600_audio_enable(rdev, dig->afmt->pin, false);
+       r600_audio_enable(rdev, dig->afmt->pin, 0);
 
        r600_audio_set_dto(encoder, mode->clock);
 
@@ -240,5 +240,5 @@ void dce3_1_hdmi_setmode(struct drm_encoder *encoder, struct drm_display_mode *m
        r600_hdmi_audio_workaround(encoder);
 
        /* enable audio after to setting up hw */
-       r600_audio_enable(rdev, dig->afmt->pin, true);
+       r600_audio_enable(rdev, dig->afmt->pin, 0xf);
 }
index ab29f953a767318c5e06de2115a9cfde017a9c82..c0bbf68dbc274f4d2055ea8f19850cdf3f6c747f 100644 (file)
@@ -284,13 +284,13 @@ static int dce6_audio_chipset_supported(struct radeon_device *rdev)
 
 void dce6_audio_enable(struct radeon_device *rdev,
                       struct r600_audio_pin *pin,
-                      bool enable)
+                      u8 enable_mask)
 {
        if (!pin)
                return;
 
-       WREG32_ENDPOINT(pin->offset, AZ_F0_CODEC_PIN_CONTROL_HOTPLUG_CONTROL,
-                       enable ? AUDIO_ENABLED : 0);
+       WREG32_ENDPOINT(pin->offset, AZ_F0_CODEC_PIN_CONTROL_HOT_PLUG_CONTROL,
+                       enable_mask ? AUDIO_ENABLED : 0);
 }
 
 static const u32 pin_offsets[7] =
diff --git a/drivers/gpu/drm/radeon/drm_buffer.c b/drivers/gpu/drm/radeon/drm_buffer.c
new file mode 100644 (file)
index 0000000..f4e0f3a
--- /dev/null
@@ -0,0 +1,177 @@
+/**************************************************************************
+ *
+ * Copyright 2010 Pauli Nieminen.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS 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.
+ *
+ *
+ **************************************************************************/
+/*
+ * Multipart buffer for coping data which is larger than the page size.
+ *
+ * Authors:
+ * Pauli Nieminen <suokkos-at-gmail-dot-com>
+ */
+
+#include <linux/export.h>
+#include "drm_buffer.h"
+
+/**
+ * Allocate the drm buffer object.
+ *
+ *   buf: Pointer to a pointer where the object is stored.
+ *   size: The number of bytes to allocate.
+ */
+int drm_buffer_alloc(struct drm_buffer **buf, int size)
+{
+       int nr_pages = size / PAGE_SIZE + 1;
+       int idx;
+
+       /* Allocating pointer table to end of structure makes drm_buffer
+        * variable sized */
+       *buf = kzalloc(sizeof(struct drm_buffer) + nr_pages*sizeof(char *),
+                       GFP_KERNEL);
+
+       if (*buf == NULL) {
+               DRM_ERROR("Failed to allocate drm buffer object to hold"
+                               " %d bytes in %d pages.\n",
+                               size, nr_pages);
+               return -ENOMEM;
+       }
+
+       (*buf)->size = size;
+
+       for (idx = 0; idx < nr_pages; ++idx) {
+
+               (*buf)->data[idx] =
+                       kmalloc(min(PAGE_SIZE, size - idx * PAGE_SIZE),
+                               GFP_KERNEL);
+
+
+               if ((*buf)->data[idx] == NULL) {
+                       DRM_ERROR("Failed to allocate %dth page for drm"
+                                       " buffer with %d bytes and %d pages.\n",
+                                       idx + 1, size, nr_pages);
+                       goto error_out;
+               }
+
+       }
+
+       return 0;
+
+error_out:
+
+       for (; idx >= 0; --idx)
+               kfree((*buf)->data[idx]);
+
+       kfree(*buf);
+       return -ENOMEM;
+}
+
+/**
+ * Copy the user data to the begin of the buffer and reset the processing
+ * iterator.
+ *
+ *   user_data: A pointer the data that is copied to the buffer.
+ *   size: The Number of bytes to copy.
+ */
+int drm_buffer_copy_from_user(struct drm_buffer *buf,
+                             void __user *user_data, int size)
+{
+       int nr_pages = size / PAGE_SIZE + 1;
+       int idx;
+
+       if (size > buf->size) {
+               DRM_ERROR("Requesting to copy %d bytes to a drm buffer with"
+                               " %d bytes space\n",
+                               size, buf->size);
+               return -EFAULT;
+       }
+
+       for (idx = 0; idx < nr_pages; ++idx) {
+
+               if (copy_from_user(buf->data[idx],
+                       user_data + idx * PAGE_SIZE,
+                       min(PAGE_SIZE, size - idx * PAGE_SIZE))) {
+                       DRM_ERROR("Failed to copy user data (%p) to drm buffer"
+                                       " (%p) %dth page.\n",
+                                       user_data, buf, idx);
+                       return -EFAULT;
+
+               }
+       }
+       buf->iterator = 0;
+       return 0;
+}
+
+/**
+ * Free the drm buffer object
+ */
+void drm_buffer_free(struct drm_buffer *buf)
+{
+
+       if (buf != NULL) {
+
+               int nr_pages = buf->size / PAGE_SIZE + 1;
+               int idx;
+               for (idx = 0; idx < nr_pages; ++idx)
+                       kfree(buf->data[idx]);
+
+               kfree(buf);
+       }
+}
+
+/**
+ * Read an object from buffer that may be split to multiple parts. If object
+ * is not split function just returns the pointer to object in buffer. But in
+ * case of split object data is copied to given stack object that is suplied
+ * by caller.
+ *
+ * The processing location of the buffer is also advanced to the next byte
+ * after the object.
+ *
+ *   objsize: The size of the objet in bytes.
+ *   stack_obj: A pointer to a memory location where object can be copied.
+ */
+void *drm_buffer_read_object(struct drm_buffer *buf,
+               int objsize, void *stack_obj)
+{
+       int idx = drm_buffer_index(buf);
+       int page = drm_buffer_page(buf);
+       void *obj = NULL;
+
+       if (idx + objsize <= PAGE_SIZE) {
+               obj = &buf->data[page][idx];
+       } else {
+               /* The object is split which forces copy to temporary object.*/
+               int beginsz = PAGE_SIZE - idx;
+               memcpy(stack_obj, &buf->data[page][idx], beginsz);
+
+               memcpy(stack_obj + beginsz, &buf->data[page + 1][0],
+                               objsize - beginsz);
+
+               obj = stack_obj;
+       }
+
+       drm_buffer_advance(buf, objsize);
+       return obj;
+}
diff --git a/drivers/gpu/drm/radeon/drm_buffer.h b/drivers/gpu/drm/radeon/drm_buffer.h
new file mode 100644 (file)
index 0000000..c80d3a3
--- /dev/null
@@ -0,0 +1,148 @@
+/**************************************************************************
+ *
+ * Copyright 2010 Pauli Nieminen.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS 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.
+ *
+ *
+ **************************************************************************/
+/*
+ * Multipart buffer for coping data which is larger than the page size.
+ *
+ * Authors:
+ * Pauli Nieminen <suokkos-at-gmail-dot-com>
+ */
+
+#ifndef _DRM_BUFFER_H_
+#define _DRM_BUFFER_H_
+
+#include <drm/drmP.h>
+
+struct drm_buffer {
+       int iterator;
+       int size;
+       char *data[];
+};
+
+
+/**
+ * Return the index of page that buffer is currently pointing at.
+ */
+static inline int drm_buffer_page(struct drm_buffer *buf)
+{
+       return buf->iterator / PAGE_SIZE;
+}
+/**
+ * Return the index of the current byte in the page
+ */
+static inline int drm_buffer_index(struct drm_buffer *buf)
+{
+       return buf->iterator & (PAGE_SIZE - 1);
+}
+/**
+ * Return number of bytes that is left to process
+ */
+static inline int drm_buffer_unprocessed(struct drm_buffer *buf)
+{
+       return buf->size - buf->iterator;
+}
+
+/**
+ * Advance the buffer iterator number of bytes that is given.
+ */
+static inline void drm_buffer_advance(struct drm_buffer *buf, int bytes)
+{
+       buf->iterator += bytes;
+}
+
+/**
+ * Allocate the drm buffer object.
+ *
+ *   buf: A pointer to a pointer where the object is stored.
+ *   size: The number of bytes to allocate.
+ */
+extern int drm_buffer_alloc(struct drm_buffer **buf, int size);
+
+/**
+ * Copy the user data to the begin of the buffer and reset the processing
+ * iterator.
+ *
+ *   user_data: A pointer the data that is copied to the buffer.
+ *   size: The Number of bytes to copy.
+ */
+extern int drm_buffer_copy_from_user(struct drm_buffer *buf,
+               void __user *user_data, int size);
+
+/**
+ * Free the drm buffer object
+ */
+extern void drm_buffer_free(struct drm_buffer *buf);
+
+/**
+ * Read an object from buffer that may be split to multiple parts. If object
+ * is not split function just returns the pointer to object in buffer. But in
+ * case of split object data is copied to given stack object that is suplied
+ * by caller.
+ *
+ * The processing location of the buffer is also advanced to the next byte
+ * after the object.
+ *
+ *   objsize: The size of the objet in bytes.
+ *   stack_obj: A pointer to a memory location where object can be copied.
+ */
+extern void *drm_buffer_read_object(struct drm_buffer *buf,
+               int objsize, void *stack_obj);
+
+/**
+ * Returns the pointer to the dword which is offset number of elements from the
+ * current processing location.
+ *
+ * Caller must make sure that dword is not split in the buffer. This
+ * requirement is easily met if all the sizes of objects in buffer are
+ * multiples of dword and PAGE_SIZE is multiple dword.
+ *
+ * Call to this function doesn't change the processing location.
+ *
+ *   offset: The index of the dword relative to the internat iterator.
+ */
+static inline void *drm_buffer_pointer_to_dword(struct drm_buffer *buffer,
+               int offset)
+{
+       int iter = buffer->iterator + offset * 4;
+       return &buffer->data[iter / PAGE_SIZE][iter & (PAGE_SIZE - 1)];
+}
+/**
+ * Returns the pointer to the dword which is offset number of elements from
+ * the current processing location.
+ *
+ * Call to this function doesn't change the processing location.
+ *
+ *   offset: The index of the byte relative to the internat iterator.
+ */
+static inline void *drm_buffer_pointer_to_byte(struct drm_buffer *buffer,
+               int offset)
+{
+       int iter = buffer->iterator + offset;
+       return &buffer->data[iter / PAGE_SIZE][iter & (PAGE_SIZE - 1)];
+}
+
+#endif
index e50807c29f696a6b8eb23cf1e5dd9ab7f58412ca..a31f1ca40c6a7e81d06309e82bba86d3192a3562 100644 (file)
@@ -22,7 +22,6 @@
  * Authors: Alex Deucher
  */
 #include <linux/firmware.h>
-#include <linux/platform_device.h>
 #include <linux/slab.h>
 #include <drm/drmP.h>
 #include "radeon.h"
@@ -4023,7 +4022,7 @@ int sumo_rlc_init(struct radeon_device *rdev)
                if (rdev->rlc.save_restore_obj == NULL) {
                        r = radeon_bo_create(rdev, dws * 4, PAGE_SIZE, true,
                                             RADEON_GEM_DOMAIN_VRAM, 0, NULL,
-                                            &rdev->rlc.save_restore_obj);
+                                            NULL, &rdev->rlc.save_restore_obj);
                        if (r) {
                                dev_warn(rdev->dev, "(%d) create RLC sr bo failed\n", r);
                                return r;
@@ -4102,7 +4101,7 @@ int sumo_rlc_init(struct radeon_device *rdev)
                if (rdev->rlc.clear_state_obj == NULL) {
                        r = radeon_bo_create(rdev, dws * 4, PAGE_SIZE, true,
                                             RADEON_GEM_DOMAIN_VRAM, 0, NULL,
-                                            &rdev->rlc.clear_state_obj);
+                                            NULL, &rdev->rlc.clear_state_obj);
                        if (r) {
                                dev_warn(rdev->dev, "(%d) create RLC c bo failed\n", r);
                                sumo_rlc_fini(rdev);
@@ -4179,7 +4178,7 @@ int sumo_rlc_init(struct radeon_device *rdev)
                        r = radeon_bo_create(rdev, rdev->rlc.cp_table_size,
                                             PAGE_SIZE, true,
                                             RADEON_GEM_DOMAIN_VRAM, 0, NULL,
-                                            &rdev->rlc.cp_table_obj);
+                                            NULL, &rdev->rlc.cp_table_obj);
                        if (r) {
                                dev_warn(rdev->dev, "(%d) create RLC cp table bo failed\n", r);
                                sumo_rlc_fini(rdev);
index afaba388c36dec2fcd6cd5b986a9ab4d70406385..66bcfadeedd1a56265ea2f8121df864ecad4574e 100644 (file)
@@ -104,12 +104,14 @@ void evergreen_dma_ring_ib_execute(struct radeon_device *rdev,
  * Used by the radeon ttm implementation to move pages if
  * registered as the asic copy callback.
  */
-int evergreen_copy_dma(struct radeon_device *rdev,
-                      uint64_t src_offset, uint64_t dst_offset,
-                      unsigned num_gpu_pages,
-                      struct radeon_fence **fence)
+struct radeon_fence *evergreen_copy_dma(struct radeon_device *rdev,
+                                       uint64_t src_offset,
+                                       uint64_t dst_offset,
+                                       unsigned num_gpu_pages,
+                                       struct reservation_object *resv)
 {
        struct radeon_semaphore *sem = NULL;
+       struct radeon_fence *fence;
        int ring_index = rdev->asic->copy.dma_ring_index;
        struct radeon_ring *ring = &rdev->ring[ring_index];
        u32 size_in_dw, cur_size_in_dw;
@@ -119,7 +121,7 @@ int evergreen_copy_dma(struct radeon_device *rdev,
        r = radeon_semaphore_create(rdev, &sem);
        if (r) {
                DRM_ERROR("radeon: moving bo (%d).\n", r);
-               return r;
+               return ERR_PTR(r);
        }
 
        size_in_dw = (num_gpu_pages << RADEON_GPU_PAGE_SHIFT) / 4;
@@ -128,10 +130,10 @@ int evergreen_copy_dma(struct radeon_device *rdev,
        if (r) {
                DRM_ERROR("radeon: moving bo (%d).\n", r);
                radeon_semaphore_free(rdev, &sem, NULL);
-               return r;
+               return ERR_PTR(r);
        }
 
-       radeon_semaphore_sync_to(sem, *fence);
+       radeon_semaphore_sync_resv(rdev, sem, resv, false);
        radeon_semaphore_sync_rings(rdev, sem, ring->idx);
 
        for (i = 0; i < num_loops; i++) {
@@ -148,17 +150,17 @@ int evergreen_copy_dma(struct radeon_device *rdev,
                dst_offset += cur_size_in_dw * 4;
        }
 
-       r = radeon_fence_emit(rdev, fence, ring->idx);
+       r = radeon_fence_emit(rdev, &fence, ring->idx);
        if (r) {
                radeon_ring_unlock_undo(rdev, ring);
                radeon_semaphore_free(rdev, &sem, NULL);
-               return r;
+               return ERR_PTR(r);
        }
 
        radeon_ring_unlock_commit(rdev, ring, false);
-       radeon_semaphore_free(rdev, &sem, *fence);
+       radeon_semaphore_free(rdev, &sem, fence);
 
-       return r;
+       return fence;
 }
 
 /**
index 278c7a139d748f770467a53d4cf19a920c9bb2ef..2514d659b1ba1783fb4c6474ea6e45d0b3a1b941 100644 (file)
@@ -38,6 +38,37 @@ extern void dce6_afmt_select_pin(struct drm_encoder *encoder);
 extern void dce6_afmt_write_latency_fields(struct drm_encoder *encoder,
                                           struct drm_display_mode *mode);
 
+/* enable the audio stream */
+static void dce4_audio_enable(struct radeon_device *rdev,
+                             struct r600_audio_pin *pin,
+                             u8 enable_mask)
+{
+       u32 tmp = RREG32(AZ_HOT_PLUG_CONTROL);
+
+       if (!pin)
+               return;
+
+       if (enable_mask) {
+               tmp |= AUDIO_ENABLED;
+               if (enable_mask & 1)
+                       tmp |= PIN0_AUDIO_ENABLED;
+               if (enable_mask & 2)
+                       tmp |= PIN1_AUDIO_ENABLED;
+               if (enable_mask & 4)
+                       tmp |= PIN2_AUDIO_ENABLED;
+               if (enable_mask & 8)
+                       tmp |= PIN3_AUDIO_ENABLED;
+       } else {
+               tmp &= ~(AUDIO_ENABLED |
+                        PIN0_AUDIO_ENABLED |
+                        PIN1_AUDIO_ENABLED |
+                        PIN2_AUDIO_ENABLED |
+                        PIN3_AUDIO_ENABLED);
+       }
+
+       WREG32(AZ_HOT_PLUG_CONTROL, tmp);
+}
+
 /*
  * update the N and CTS parameters for a given pixel clock rate
  */
@@ -318,10 +349,10 @@ void evergreen_hdmi_setmode(struct drm_encoder *encoder, struct drm_display_mode
        /* disable audio prior to setting up hw */
        if (ASIC_IS_DCE6(rdev)) {
                dig->afmt->pin = dce6_audio_get_pin(rdev);
-               dce6_audio_enable(rdev, dig->afmt->pin, false);
+               dce6_audio_enable(rdev, dig->afmt->pin, 0);
        } else {
                dig->afmt->pin = r600_audio_get_pin(rdev);
-               r600_audio_enable(rdev, dig->afmt->pin, false);
+               dce4_audio_enable(rdev, dig->afmt->pin, 0);
        }
 
        evergreen_audio_set_dto(encoder, mode->clock);
@@ -463,13 +494,15 @@ void evergreen_hdmi_setmode(struct drm_encoder *encoder, struct drm_display_mode
 
        /* enable audio after to setting up hw */
        if (ASIC_IS_DCE6(rdev))
-               dce6_audio_enable(rdev, dig->afmt->pin, true);
+               dce6_audio_enable(rdev, dig->afmt->pin, 1);
        else
-               r600_audio_enable(rdev, dig->afmt->pin, true);
+               dce4_audio_enable(rdev, dig->afmt->pin, 0xf);
 }
 
 void evergreen_hdmi_enable(struct drm_encoder *encoder, bool enable)
 {
+       struct drm_device *dev = encoder->dev;
+       struct radeon_device *rdev = dev->dev_private;
        struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
        struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
 
@@ -482,6 +515,14 @@ void evergreen_hdmi_enable(struct drm_encoder *encoder, bool enable)
        if (!enable && !dig->afmt->enabled)
                return;
 
+       if (!enable && dig->afmt->pin) {
+               if (ASIC_IS_DCE6(rdev))
+                       dce6_audio_enable(rdev, dig->afmt->pin, 0);
+               else
+                       dce4_audio_enable(rdev, dig->afmt->pin, 0);
+               dig->afmt->pin = NULL;
+       }
+
        dig->afmt->enabled = enable;
 
        DRM_DEBUG("%sabling HDMI interface @ 0x%04X for encoder 0x%x\n",
index 67cb472d188ce05ec36c5a812ae5751fbb618254..1dd976f447faccd700fcfeac3ebc14cebbdd1320 100644 (file)
@@ -2787,6 +2787,8 @@ void kv_dpm_debugfs_print_current_performance_level(struct radeon_device *rdev,
                tmp = (RREG32_SMC(SMU_VOLTAGE_STATUS) & SMU_VOLTAGE_CURRENT_LEVEL_MASK) >>
                        SMU_VOLTAGE_CURRENT_LEVEL_SHIFT;
                vddc = kv_convert_8bit_index_to_voltage(rdev, (u16)tmp);
+               seq_printf(m, "uvd    %sabled\n", pi->uvd_power_gated ? "dis" : "en");
+               seq_printf(m, "vce    %sabled\n", pi->vce_power_gated ? "dis" : "en");
                seq_printf(m, "power level %d    sclk: %u vddc: %u\n",
                           current_index, sclk, vddc);
        }
index 01fc4888e6fea26b7f64fc9d02f73304f0b25a92..715b181c6243503228bb638f39c36a60ac4acf2a 100644 (file)
@@ -789,7 +789,6 @@ static void ni_apply_state_adjust_rules(struct radeon_device *rdev,
        bool disable_mclk_switching;
        u32 mclk;
        u16 vddci;
-       u32 max_sclk_vddc, max_mclk_vddci, max_mclk_vddc;
        int i;
 
        if ((rdev->pm.dpm.new_active_crtc_count > 1) ||
@@ -816,29 +815,6 @@ static void ni_apply_state_adjust_rules(struct radeon_device *rdev,
                }
        }
 
-       /* limit clocks to max supported clocks based on voltage dependency tables */
-       btc_get_max_clock_from_voltage_dependency_table(&rdev->pm.dpm.dyn_state.vddc_dependency_on_sclk,
-                                                       &max_sclk_vddc);
-       btc_get_max_clock_from_voltage_dependency_table(&rdev->pm.dpm.dyn_state.vddci_dependency_on_mclk,
-                                                       &max_mclk_vddci);
-       btc_get_max_clock_from_voltage_dependency_table(&rdev->pm.dpm.dyn_state.vddc_dependency_on_mclk,
-                                                       &max_mclk_vddc);
-
-       for (i = 0; i < ps->performance_level_count; i++) {
-               if (max_sclk_vddc) {
-                       if (ps->performance_levels[i].sclk > max_sclk_vddc)
-                               ps->performance_levels[i].sclk = max_sclk_vddc;
-               }
-               if (max_mclk_vddci) {
-                       if (ps->performance_levels[i].mclk > max_mclk_vddci)
-                               ps->performance_levels[i].mclk = max_mclk_vddci;
-               }
-               if (max_mclk_vddc) {
-                       if (ps->performance_levels[i].mclk > max_mclk_vddc)
-                               ps->performance_levels[i].mclk = max_mclk_vddc;
-               }
-       }
-
        /* XXX validate the min clocks required for display */
 
        /* adjust low state */
index b0098e792e62337a6b4d511ca62baa7f37bc4eba..10f8be0ee1736394acaf9bac24eb516707917fd2 100644 (file)
@@ -869,13 +869,14 @@ bool r100_semaphore_ring_emit(struct radeon_device *rdev,
        return false;
 }
 
-int r100_copy_blit(struct radeon_device *rdev,
-                  uint64_t src_offset,
-                  uint64_t dst_offset,
-                  unsigned num_gpu_pages,
-                  struct radeon_fence **fence)
+struct radeon_fence *r100_copy_blit(struct radeon_device *rdev,
+                                   uint64_t src_offset,
+                                   uint64_t dst_offset,
+                                   unsigned num_gpu_pages,
+                                   struct reservation_object *resv)
 {
        struct radeon_ring *ring = &rdev->ring[RADEON_RING_TYPE_GFX_INDEX];
+       struct radeon_fence *fence;
        uint32_t cur_pages;
        uint32_t stride_bytes = RADEON_GPU_PAGE_SIZE;
        uint32_t pitch;
@@ -896,7 +897,7 @@ int r100_copy_blit(struct radeon_device *rdev,
        r = radeon_ring_lock(rdev, ring, ndw);
        if (r) {
                DRM_ERROR("radeon: moving bo (%d) asking for %u dw.\n", r, ndw);
-               return -EINVAL;
+               return ERR_PTR(-EINVAL);
        }
        while (num_gpu_pages > 0) {
                cur_pages = num_gpu_pages;
@@ -936,11 +937,13 @@ int r100_copy_blit(struct radeon_device *rdev,
                          RADEON_WAIT_2D_IDLECLEAN |
                          RADEON_WAIT_HOST_IDLECLEAN |
                          RADEON_WAIT_DMA_GUI_IDLE);
-       if (fence) {
-               r = radeon_fence_emit(rdev, fence, RADEON_RING_TYPE_GFX_INDEX);
+       r = radeon_fence_emit(rdev, &fence, RADEON_RING_TYPE_GFX_INDEX);
+       if (r) {
+               radeon_ring_unlock_undo(rdev, ring);
+               return ERR_PTR(r);
        }
        radeon_ring_unlock_commit(rdev, ring, false);
-       return r;
+       return fence;
 }
 
 static int r100_cp_wait_for_idle(struct radeon_device *rdev)
index 67780374a65203fc57736510685f917b14d4ce89..732d4938aab75f91d1666960de2c0275de38d4a2 100644 (file)
@@ -80,13 +80,14 @@ static int r200_get_vtx_size_0(uint32_t vtx_fmt_0)
        return vtx_size;
 }
 
-int r200_copy_dma(struct radeon_device *rdev,
-                 uint64_t src_offset,
-                 uint64_t dst_offset,
-                 unsigned num_gpu_pages,
-                 struct radeon_fence **fence)
+struct radeon_fence *r200_copy_dma(struct radeon_device *rdev,
+                                  uint64_t src_offset,
+                                  uint64_t dst_offset,
+                                  unsigned num_gpu_pages,
+                                  struct reservation_object *resv)
 {
        struct radeon_ring *ring = &rdev->ring[RADEON_RING_TYPE_GFX_INDEX];
+       struct radeon_fence *fence;
        uint32_t size;
        uint32_t cur_size;
        int i, num_loops;
@@ -98,7 +99,7 @@ int r200_copy_dma(struct radeon_device *rdev,
        r = radeon_ring_lock(rdev, ring, num_loops * 4 + 64);
        if (r) {
                DRM_ERROR("radeon: moving bo (%d).\n", r);
-               return r;
+               return ERR_PTR(r);
        }
        /* Must wait for 2D idle & clean before DMA or hangs might happen */
        radeon_ring_write(ring, PACKET0(RADEON_WAIT_UNTIL, 0));
@@ -118,11 +119,13 @@ int r200_copy_dma(struct radeon_device *rdev,
        }
        radeon_ring_write(ring, PACKET0(RADEON_WAIT_UNTIL, 0));
        radeon_ring_write(ring, RADEON_WAIT_DMA_GUI_IDLE);
-       if (fence) {
-               r = radeon_fence_emit(rdev, fence, RADEON_RING_TYPE_GFX_INDEX);
+       r = radeon_fence_emit(rdev, &fence, RADEON_RING_TYPE_GFX_INDEX);
+       if (r) {
+               radeon_ring_unlock_undo(rdev, ring);
+               return ERR_PTR(r);
        }
        radeon_ring_unlock_commit(rdev, ring, false);
-       return r;
+       return fence;
 }
 
 
index 84b1d5367a11f6950026337f76117bbb8edda0bb..9418e388b04544e39e016a54fcd33324590d0feb 100644 (file)
  */
 
 #include <drm/drmP.h>
-#include <drm/drm_buffer.h>
 #include <drm/radeon_drm.h>
 #include "radeon_drv.h"
 #include "r300_reg.h"
+#include "drm_buffer.h"
 
 #include <asm/unaligned.h>
 
index ea5c9af722ef9f5d322d61a9d0ff628f8daa151f..56b02927cd3de5901da653bbea13cfcc7e9858ab 100644 (file)
@@ -122,6 +122,94 @@ u32 r600_get_xclk(struct radeon_device *rdev)
 
 int r600_set_uvd_clocks(struct radeon_device *rdev, u32 vclk, u32 dclk)
 {
+       unsigned fb_div = 0, ref_div, vclk_div = 0, dclk_div = 0;
+       int r;
+
+       /* bypass vclk and dclk with bclk */
+       WREG32_P(CG_UPLL_FUNC_CNTL_2,
+                VCLK_SRC_SEL(1) | DCLK_SRC_SEL(1),
+                ~(VCLK_SRC_SEL_MASK | DCLK_SRC_SEL_MASK));
+
+       /* assert BYPASS_EN, deassert UPLL_RESET, UPLL_SLEEP and UPLL_CTLREQ */
+       WREG32_P(CG_UPLL_FUNC_CNTL, UPLL_BYPASS_EN_MASK, ~(
+                UPLL_RESET_MASK | UPLL_SLEEP_MASK | UPLL_CTLREQ_MASK));
+
+       if (rdev->family >= CHIP_RS780)
+               WREG32_P(GFX_MACRO_BYPASS_CNTL, UPLL_BYPASS_CNTL,
+                        ~UPLL_BYPASS_CNTL);
+
+       if (!vclk || !dclk) {
+               /* keep the Bypass mode, put PLL to sleep */
+               WREG32_P(CG_UPLL_FUNC_CNTL, UPLL_SLEEP_MASK, ~UPLL_SLEEP_MASK);
+               return 0;
+       }
+
+       if (rdev->clock.spll.reference_freq == 10000)
+               ref_div = 34;
+       else
+               ref_div = 4;
+
+       r = radeon_uvd_calc_upll_dividers(rdev, vclk, dclk, 50000, 160000,
+                                         ref_div + 1, 0xFFF, 2, 30, ~0,
+                                         &fb_div, &vclk_div, &dclk_div);
+       if (r)
+               return r;
+
+       if (rdev->family >= CHIP_RV670 && rdev->family < CHIP_RS780)
+               fb_div >>= 1;
+       else
+               fb_div |= 1;
+
+       r = radeon_uvd_send_upll_ctlreq(rdev, CG_UPLL_FUNC_CNTL);
+        if (r)
+                return r;
+
+       /* assert PLL_RESET */
+       WREG32_P(CG_UPLL_FUNC_CNTL, UPLL_RESET_MASK, ~UPLL_RESET_MASK);
+
+       /* For RS780 we have to choose ref clk */
+       if (rdev->family >= CHIP_RS780)
+               WREG32_P(CG_UPLL_FUNC_CNTL, UPLL_REFCLK_SRC_SEL_MASK,
+                        ~UPLL_REFCLK_SRC_SEL_MASK);
+
+       /* set the required fb, ref and post divder values */
+       WREG32_P(CG_UPLL_FUNC_CNTL,
+                UPLL_FB_DIV(fb_div) |
+                UPLL_REF_DIV(ref_div),
+                ~(UPLL_FB_DIV_MASK | UPLL_REF_DIV_MASK));
+       WREG32_P(CG_UPLL_FUNC_CNTL_2,
+                UPLL_SW_HILEN(vclk_div >> 1) |
+                UPLL_SW_LOLEN((vclk_div >> 1) + (vclk_div & 1)) |
+                UPLL_SW_HILEN2(dclk_div >> 1) |
+                UPLL_SW_LOLEN2((dclk_div >> 1) + (dclk_div & 1)) |
+                UPLL_DIVEN_MASK | UPLL_DIVEN2_MASK,
+                ~UPLL_SW_MASK);
+
+       /* give the PLL some time to settle */
+       mdelay(15);
+
+       /* deassert PLL_RESET */
+       WREG32_P(CG_UPLL_FUNC_CNTL, 0, ~UPLL_RESET_MASK);
+
+       mdelay(15);
+
+       /* deassert BYPASS EN */
+       WREG32_P(CG_UPLL_FUNC_CNTL, 0, ~UPLL_BYPASS_EN_MASK);
+
+       if (rdev->family >= CHIP_RS780)
+               WREG32_P(GFX_MACRO_BYPASS_CNTL, 0, ~UPLL_BYPASS_CNTL);
+
+       r = radeon_uvd_send_upll_ctlreq(rdev, CG_UPLL_FUNC_CNTL);
+       if (r)
+               return r;
+
+       /* switch VCLK and DCLK selection */
+       WREG32_P(CG_UPLL_FUNC_CNTL_2,
+                VCLK_SRC_SEL(2) | DCLK_SRC_SEL(2),
+                ~(VCLK_SRC_SEL_MASK | DCLK_SRC_SEL_MASK));
+
+       mdelay(100);
+
        return 0;
 }
 
@@ -992,6 +1080,8 @@ static int r600_pcie_gart_enable(struct radeon_device *rdev)
        WREG32(MC_VM_L1_TLB_MCB_WR_GFX_CNTL, tmp);
        WREG32(MC_VM_L1_TLB_MCB_RD_PDMA_CNTL, tmp);
        WREG32(MC_VM_L1_TLB_MCB_WR_PDMA_CNTL, tmp);
+       WREG32(MC_VM_L1_TLB_MCB_RD_UVD_CNTL, tmp);
+       WREG32(MC_VM_L1_TLB_MCB_WR_UVD_CNTL, tmp);
        WREG32(MC_VM_L1_TLB_MCB_RD_SEM_CNTL, tmp | ENABLE_SEMAPHORE_MODE);
        WREG32(MC_VM_L1_TLB_MCB_WR_SEM_CNTL, tmp | ENABLE_SEMAPHORE_MODE);
        WREG32(VM_CONTEXT0_PAGE_TABLE_START_ADDR, rdev->mc.gtt_start >> 12);
@@ -1042,6 +1132,8 @@ static void r600_pcie_gart_disable(struct radeon_device *rdev)
        WREG32(MC_VM_L1_TLB_MCB_WR_SYS_CNTL, tmp);
        WREG32(MC_VM_L1_TLB_MCB_RD_HDP_CNTL, tmp);
        WREG32(MC_VM_L1_TLB_MCB_WR_HDP_CNTL, tmp);
+       WREG32(MC_VM_L1_TLB_MCB_RD_UVD_CNTL, tmp);
+       WREG32(MC_VM_L1_TLB_MCB_WR_UVD_CNTL, tmp);
        radeon_gart_table_vram_unpin(rdev);
 }
 
@@ -1338,7 +1430,7 @@ int r600_vram_scratch_init(struct radeon_device *rdev)
        if (rdev->vram_scratch.robj == NULL) {
                r = radeon_bo_create(rdev, RADEON_GPU_PAGE_SIZE,
                                     PAGE_SIZE, true, RADEON_GEM_DOMAIN_VRAM,
-                                    0, NULL, &rdev->vram_scratch.robj);
+                                    0, NULL, NULL, &rdev->vram_scratch.robj);
                if (r) {
                        return r;
                }
@@ -2792,12 +2884,13 @@ bool r600_semaphore_ring_emit(struct radeon_device *rdev,
  * Used by the radeon ttm implementation to move pages if
  * registered as the asic copy callback.
  */
-int r600_copy_cpdma(struct radeon_device *rdev,
-                   uint64_t src_offset, uint64_t dst_offset,
-                   unsigned num_gpu_pages,
-                   struct radeon_fence **fence)
+struct radeon_fence *r600_copy_cpdma(struct radeon_device *rdev,
+                                    uint64_t src_offset, uint64_t dst_offset,
+                                    unsigned num_gpu_pages,
+                                    struct reservation_object *resv)
 {
        struct radeon_semaphore *sem = NULL;
+       struct radeon_fence *fence;
        int ring_index = rdev->asic->copy.blit_ring_index;
        struct radeon_ring *ring = &rdev->ring[ring_index];
        u32 size_in_bytes, cur_size_in_bytes, tmp;
@@ -2807,7 +2900,7 @@ int r600_copy_cpdma(struct radeon_device *rdev,
        r = radeon_semaphore_create(rdev, &sem);
        if (r) {
                DRM_ERROR("radeon: moving bo (%d).\n", r);
-               return r;
+               return ERR_PTR(r);
        }
 
        size_in_bytes = (num_gpu_pages << RADEON_GPU_PAGE_SHIFT);
@@ -2816,10 +2909,10 @@ int r600_copy_cpdma(struct radeon_device *rdev,
        if (r) {
                DRM_ERROR("radeon: moving bo (%d).\n", r);
                radeon_semaphore_free(rdev, &sem, NULL);
-               return r;
+               return ERR_PTR(r);
        }
 
-       radeon_semaphore_sync_to(sem, *fence);
+       radeon_semaphore_sync_resv(rdev, sem, resv, false);
        radeon_semaphore_sync_rings(rdev, sem, ring->idx);
 
        radeon_ring_write(ring, PACKET3(PACKET3_SET_CONFIG_REG, 1));
@@ -2846,17 +2939,17 @@ int r600_copy_cpdma(struct radeon_device *rdev,
        radeon_ring_write(ring, (WAIT_UNTIL - PACKET3_SET_CONFIG_REG_OFFSET) >> 2);
        radeon_ring_write(ring, WAIT_CP_DMA_IDLE_bit);
 
-       r = radeon_fence_emit(rdev, fence, ring->idx);
+       r = radeon_fence_emit(rdev, &fence, ring->idx);
        if (r) {
                radeon_ring_unlock_undo(rdev, ring);
                radeon_semaphore_free(rdev, &sem, NULL);
-               return r;
+               return ERR_PTR(r);
        }
 
        radeon_ring_unlock_commit(rdev, ring, false);
-       radeon_semaphore_free(rdev, &sem, *fence);
+       radeon_semaphore_free(rdev, &sem, fence);
 
-       return r;
+       return fence;
 }
 
 int r600_set_surface_reg(struct radeon_device *rdev, int reg,
@@ -2907,6 +3000,18 @@ static int r600_startup(struct radeon_device *rdev)
                return r;
        }
 
+       if (rdev->has_uvd) {
+               r = uvd_v1_0_resume(rdev);
+               if (!r) {
+                       r = radeon_fence_driver_start_ring(rdev, R600_RING_TYPE_UVD_INDEX);
+                       if (r) {
+                               dev_err(rdev->dev, "failed initializing UVD fences (%d).\n", r);
+                       }
+               }
+               if (r)
+                       rdev->ring[R600_RING_TYPE_UVD_INDEX].ring_size = 0;
+       }
+
        /* Enable IRQ */
        if (!rdev->irq.installed) {
                r = radeon_irq_kms_init(rdev);
@@ -2935,6 +3040,18 @@ static int r600_startup(struct radeon_device *rdev)
        if (r)
                return r;
 
+       if (rdev->has_uvd) {
+               ring = &rdev->ring[R600_RING_TYPE_UVD_INDEX];
+               if (ring->ring_size) {
+                       r = radeon_ring_init(rdev, ring, ring->ring_size, 0,
+                                            RADEON_CP_PACKET2);
+                       if (!r)
+                               r = uvd_v1_0_init(rdev);
+                       if (r)
+                               DRM_ERROR("radeon: failed initializing UVD (%d).\n", r);
+               }
+       }
+
        r = radeon_ib_pool_init(rdev);
        if (r) {
                dev_err(rdev->dev, "IB initialization failed (%d).\n", r);
@@ -2994,6 +3111,10 @@ int r600_suspend(struct radeon_device *rdev)
        radeon_pm_suspend(rdev);
        r600_audio_fini(rdev);
        r600_cp_stop(rdev);
+       if (rdev->has_uvd) {
+               uvd_v1_0_fini(rdev);
+               radeon_uvd_suspend(rdev);
+       }
        r600_irq_suspend(rdev);
        radeon_wb_disable(rdev);
        r600_pcie_gart_disable(rdev);
@@ -3073,6 +3194,14 @@ int r600_init(struct radeon_device *rdev)
        rdev->ring[RADEON_RING_TYPE_GFX_INDEX].ring_obj = NULL;
        r600_ring_init(rdev, &rdev->ring[RADEON_RING_TYPE_GFX_INDEX], 1024 * 1024);
 
+       if (rdev->has_uvd) {
+               r = radeon_uvd_init(rdev);
+               if (!r) {
+                       rdev->ring[R600_RING_TYPE_UVD_INDEX].ring_obj = NULL;
+                       r600_ring_init(rdev, &rdev->ring[R600_RING_TYPE_UVD_INDEX], 4096);
+               }
+       }
+
        rdev->ih.ring_obj = NULL;
        r600_ih_ring_init(rdev, 64 * 1024);
 
@@ -3102,6 +3231,10 @@ void r600_fini(struct radeon_device *rdev)
        r600_audio_fini(rdev);
        r600_cp_fini(rdev);
        r600_irq_fini(rdev);
+       if (rdev->has_uvd) {
+               uvd_v1_0_fini(rdev);
+               radeon_uvd_fini(rdev);
+       }
        radeon_wb_fini(rdev);
        radeon_ib_pool_fini(rdev);
        radeon_irq_kms_fini(rdev);
@@ -3235,7 +3368,7 @@ int r600_ih_ring_alloc(struct radeon_device *rdev)
                r = radeon_bo_create(rdev, rdev->ih.ring_size,
                                     PAGE_SIZE, true,
                                     RADEON_GEM_DOMAIN_GTT, 0,
-                                    NULL, &rdev->ih.ring_obj);
+                                    NULL, NULL, &rdev->ih.ring_obj);
                if (r) {
                        DRM_ERROR("radeon: failed to create ih ring buffer (%d).\n", r);
                        return r;
diff --git a/drivers/gpu/drm/radeon/r600_audio.c b/drivers/gpu/drm/radeon/r600_audio.c
deleted file mode 100644 (file)
index bffac10..0000000
+++ /dev/null
@@ -1,207 +0,0 @@
-/*
- * Copyright 2008 Advanced Micro Devices, Inc.
- * Copyright 2008 Red Hat Inc.
- * Copyright 2009 Christian König.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Christian König
- */
-#include <drm/drmP.h>
-#include "radeon.h"
-#include "radeon_reg.h"
-#include "radeon_asic.h"
-#include "atom.h"
-
-/*
- * check if enc_priv stores radeon_encoder_atom_dig
- */
-static bool radeon_dig_encoder(struct drm_encoder *encoder)
-{
-       struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
-       switch (radeon_encoder->encoder_id) {
-       case ENCODER_OBJECT_ID_INTERNAL_LVDS:
-       case ENCODER_OBJECT_ID_INTERNAL_TMDS1:
-       case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1:
-       case ENCODER_OBJECT_ID_INTERNAL_LVTM1:
-       case ENCODER_OBJECT_ID_INTERNAL_DVO1:
-       case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1:
-       case ENCODER_OBJECT_ID_INTERNAL_DDI:
-       case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
-       case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA:
-       case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
-       case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
-               return true;
-       }
-       return false;
-}
-
-/*
- * check if the chipset is supported
- */
-static int r600_audio_chipset_supported(struct radeon_device *rdev)
-{
-       return ASIC_IS_DCE2(rdev) && !ASIC_IS_NODCE(rdev);
-}
-
-struct r600_audio_pin r600_audio_status(struct radeon_device *rdev)
-{
-       struct r600_audio_pin status;
-       uint32_t value;
-
-       value = RREG32(R600_AUDIO_RATE_BPS_CHANNEL);
-
-       /* number of channels */
-       status.channels = (value & 0x7) + 1;
-
-       /* bits per sample */
-       switch ((value & 0xF0) >> 4) {
-       case 0x0:
-               status.bits_per_sample = 8;
-               break;
-       case 0x1:
-               status.bits_per_sample = 16;
-               break;
-       case 0x2:
-               status.bits_per_sample = 20;
-               break;
-       case 0x3:
-               status.bits_per_sample = 24;
-               break;
-       case 0x4:
-               status.bits_per_sample = 32;
-               break;
-       default:
-               dev_err(rdev->dev, "Unknown bits per sample 0x%x, using 16\n",
-                       (int)value);
-               status.bits_per_sample = 16;
-       }
-
-       /* current sampling rate in HZ */
-       if (value & 0x4000)
-               status.rate = 44100;
-       else
-               status.rate = 48000;
-       status.rate *= ((value >> 11) & 0x7) + 1;
-       status.rate /= ((value >> 8) & 0x7) + 1;
-
-       value = RREG32(R600_AUDIO_STATUS_BITS);
-
-       /* iec 60958 status bits */
-       status.status_bits = value & 0xff;
-
-       /* iec 60958 category code */
-       status.category_code = (value >> 8) & 0xff;
-
-       return status;
-}
-
-/*
- * update all hdmi interfaces with current audio parameters
- */
-void r600_audio_update_hdmi(struct work_struct *work)
-{
-       struct radeon_device *rdev = container_of(work, struct radeon_device,
-                                                 audio_work);
-       struct drm_device *dev = rdev->ddev;
-       struct r600_audio_pin audio_status = r600_audio_status(rdev);
-       struct drm_encoder *encoder;
-       bool changed = false;
-
-       if (rdev->audio.pin[0].channels != audio_status.channels ||
-           rdev->audio.pin[0].rate != audio_status.rate ||
-           rdev->audio.pin[0].bits_per_sample != audio_status.bits_per_sample ||
-           rdev->audio.pin[0].status_bits != audio_status.status_bits ||
-           rdev->audio.pin[0].category_code != audio_status.category_code) {
-               rdev->audio.pin[0] = audio_status;
-               changed = true;
-       }
-
-       list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
-               if (!radeon_dig_encoder(encoder))
-                       continue;
-               if (changed || r600_hdmi_buffer_status_changed(encoder))
-                       r600_hdmi_update_audio_settings(encoder);
-       }
-}
-
-/* enable the audio stream */
-void r600_audio_enable(struct radeon_device *rdev,
-                      struct r600_audio_pin *pin,
-                      bool enable)
-{
-       u32 value = 0;
-
-       if (!pin)
-               return;
-
-       if (ASIC_IS_DCE4(rdev)) {
-               if (enable) {
-                       value |= 0x81000000; /* Required to enable audio */
-                       value |= 0x0e1000f0; /* fglrx sets that too */
-               }
-               WREG32(EVERGREEN_AUDIO_ENABLE, value);
-       } else {
-               WREG32_P(R600_AUDIO_ENABLE,
-                        enable ? 0x81000000 : 0x0, ~0x81000000);
-       }
-}
-
-/*
- * initialize the audio vars
- */
-int r600_audio_init(struct radeon_device *rdev)
-{
-       if (!radeon_audio || !r600_audio_chipset_supported(rdev))
-               return 0;
-
-       rdev->audio.enabled = true;
-
-       rdev->audio.num_pins = 1;
-       rdev->audio.pin[0].channels = -1;
-       rdev->audio.pin[0].rate = -1;
-       rdev->audio.pin[0].bits_per_sample = -1;
-       rdev->audio.pin[0].status_bits = 0;
-       rdev->audio.pin[0].category_code = 0;
-       rdev->audio.pin[0].id = 0;
-       /* disable audio.  it will be set up later */
-       r600_audio_enable(rdev, &rdev->audio.pin[0], false);
-
-       return 0;
-}
-
-/*
- * release the audio timer
- * TODO: How to do this correctly on SMP systems?
- */
-void r600_audio_fini(struct radeon_device *rdev)
-{
-       if (!rdev->audio.enabled)
-               return;
-
-       r600_audio_enable(rdev, &rdev->audio.pin[0], false);
-
-       rdev->audio.enabled = false;
-}
-
-struct r600_audio_pin *r600_audio_get_pin(struct radeon_device *rdev)
-{
-       /* only one pin on 6xx-NI */
-       return &rdev->audio.pin[0];
-}
index 8c9b7e26533c6c81635a9dafa20e7cecb164b167..09e3f39925faa832661e59333bed740981c10621 100644 (file)
@@ -1949,15 +1949,15 @@ int r600_do_cleanup_cp(struct drm_device *dev)
 #if __OS_HAS_AGP
        if (dev_priv->flags & RADEON_IS_AGP) {
                if (dev_priv->cp_ring != NULL) {
-                       drm_core_ioremapfree(dev_priv->cp_ring, dev);
+                       drm_legacy_ioremapfree(dev_priv->cp_ring, dev);
                        dev_priv->cp_ring = NULL;
                }
                if (dev_priv->ring_rptr != NULL) {
-                       drm_core_ioremapfree(dev_priv->ring_rptr, dev);
+                       drm_legacy_ioremapfree(dev_priv->ring_rptr, dev);
                        dev_priv->ring_rptr = NULL;
                }
                if (dev->agp_buffer_map != NULL) {
-                       drm_core_ioremapfree(dev->agp_buffer_map, dev);
+                       drm_legacy_ioremapfree(dev->agp_buffer_map, dev);
                        dev->agp_buffer_map = NULL;
                }
        } else
@@ -1968,7 +1968,7 @@ int r600_do_cleanup_cp(struct drm_device *dev)
                        r600_page_table_cleanup(dev, &dev_priv->gart_info);
 
                if (dev_priv->gart_info.gart_table_location == DRM_ATI_GART_FB) {
-                       drm_core_ioremapfree(&dev_priv->gart_info.mapping, dev);
+                       drm_legacy_ioremapfree(&dev_priv->gart_info.mapping, dev);
                        dev_priv->gart_info.addr = NULL;
                }
        }
@@ -2052,27 +2052,27 @@ int r600_do_init_cp(struct drm_device *dev, drm_radeon_init_t *init,
        dev_priv->buffers_offset = init->buffers_offset;
        dev_priv->gart_textures_offset = init->gart_textures_offset;
 
-       master_priv->sarea = drm_getsarea(dev);
+       master_priv->sarea = drm_legacy_getsarea(dev);
        if (!master_priv->sarea) {
                DRM_ERROR("could not find sarea!\n");
                r600_do_cleanup_cp(dev);
                return -EINVAL;
        }
 
-       dev_priv->cp_ring = drm_core_findmap(dev, init->ring_offset);
+       dev_priv->cp_ring = drm_legacy_findmap(dev, init->ring_offset);
        if (!dev_priv->cp_ring) {
                DRM_ERROR("could not find cp ring region!\n");
                r600_do_cleanup_cp(dev);
                return -EINVAL;
        }
-       dev_priv->ring_rptr = drm_core_findmap(dev, init->ring_rptr_offset);
+       dev_priv->ring_rptr = drm_legacy_findmap(dev, init->ring_rptr_offset);
        if (!dev_priv->ring_rptr) {
                DRM_ERROR("could not find ring read pointer!\n");
                r600_do_cleanup_cp(dev);
                return -EINVAL;
        }
        dev->agp_buffer_token = init->buffers_offset;
-       dev->agp_buffer_map = drm_core_findmap(dev, init->buffers_offset);
+       dev->agp_buffer_map = drm_legacy_findmap(dev, init->buffers_offset);
        if (!dev->agp_buffer_map) {
                DRM_ERROR("could not find dma buffer region!\n");
                r600_do_cleanup_cp(dev);
@@ -2081,7 +2081,7 @@ int r600_do_init_cp(struct drm_device *dev, drm_radeon_init_t *init,
 
        if (init->gart_textures_offset) {
                dev_priv->gart_textures =
-                   drm_core_findmap(dev, init->gart_textures_offset);
+                   drm_legacy_findmap(dev, init->gart_textures_offset);
                if (!dev_priv->gart_textures) {
                        DRM_ERROR("could not find GART texture region!\n");
                        r600_do_cleanup_cp(dev);
@@ -2092,9 +2092,9 @@ int r600_do_init_cp(struct drm_device *dev, drm_radeon_init_t *init,
 #if __OS_HAS_AGP
        /* XXX */
        if (dev_priv->flags & RADEON_IS_AGP) {
-               drm_core_ioremap_wc(dev_priv->cp_ring, dev);
-               drm_core_ioremap_wc(dev_priv->ring_rptr, dev);
-               drm_core_ioremap_wc(dev->agp_buffer_map, dev);
+               drm_legacy_ioremap_wc(dev_priv->cp_ring, dev);
+               drm_legacy_ioremap_wc(dev_priv->ring_rptr, dev);
+               drm_legacy_ioremap_wc(dev->agp_buffer_map, dev);
                if (!dev_priv->cp_ring->handle ||
                    !dev_priv->ring_rptr->handle ||
                    !dev->agp_buffer_map->handle) {
@@ -2235,7 +2235,7 @@ int r600_do_init_cp(struct drm_device *dev, drm_radeon_init_t *init,
                dev_priv->gart_info.mapping.size =
                        dev_priv->gart_info.table_size;
 
-               drm_core_ioremap_wc(&dev_priv->gart_info.mapping, dev);
+               drm_legacy_ioremap_wc(&dev_priv->gart_info.mapping, dev);
                if (!dev_priv->gart_info.mapping.handle) {
                        DRM_ERROR("ioremap failed.\n");
                        r600_do_cleanup_cp(dev);
index a908daa006d23980bd51fe50d93e94ea3464aac5..100189ec5fa85133b840851d4def58bbbae6ffc0 100644 (file)
@@ -427,18 +427,19 @@ void r600_dma_ring_ib_execute(struct radeon_device *rdev, struct radeon_ib *ib)
  * @src_offset: src GPU address
  * @dst_offset: dst GPU address
  * @num_gpu_pages: number of GPU pages to xfer
- * @fence: radeon fence object
+ * @resv: reservation object to sync to
  *
  * Copy GPU paging using the DMA engine (r6xx).
  * Used by the radeon ttm implementation to move pages if
  * registered as the asic copy callback.
  */
-int r600_copy_dma(struct radeon_device *rdev,
-                 uint64_t src_offset, uint64_t dst_offset,
-                 unsigned num_gpu_pages,
-                 struct radeon_fence **fence)
+struct radeon_fence *r600_copy_dma(struct radeon_device *rdev,
+                                  uint64_t src_offset, uint64_t dst_offset,
+                                  unsigned num_gpu_pages,
+                                  struct reservation_object *resv)
 {
        struct radeon_semaphore *sem = NULL;
+       struct radeon_fence *fence;
        int ring_index = rdev->asic->copy.dma_ring_index;
        struct radeon_ring *ring = &rdev->ring[ring_index];
        u32 size_in_dw, cur_size_in_dw;
@@ -448,7 +449,7 @@ int r600_copy_dma(struct radeon_device *rdev,
        r = radeon_semaphore_create(rdev, &sem);
        if (r) {
                DRM_ERROR("radeon: moving bo (%d).\n", r);
-               return r;
+               return ERR_PTR(r);
        }
 
        size_in_dw = (num_gpu_pages << RADEON_GPU_PAGE_SHIFT) / 4;
@@ -457,10 +458,10 @@ int r600_copy_dma(struct radeon_device *rdev,
        if (r) {
                DRM_ERROR("radeon: moving bo (%d).\n", r);
                radeon_semaphore_free(rdev, &sem, NULL);
-               return r;
+               return ERR_PTR(r);
        }
 
-       radeon_semaphore_sync_to(sem, *fence);
+       radeon_semaphore_sync_resv(rdev, sem, resv, false);
        radeon_semaphore_sync_rings(rdev, sem, ring->idx);
 
        for (i = 0; i < num_loops; i++) {
@@ -477,15 +478,15 @@ int r600_copy_dma(struct radeon_device *rdev,
                dst_offset += cur_size_in_dw * 4;
        }
 
-       r = radeon_fence_emit(rdev, fence, ring->idx);
+       r = radeon_fence_emit(rdev, &fence, ring->idx);
        if (r) {
                radeon_ring_unlock_undo(rdev, ring);
                radeon_semaphore_free(rdev, &sem, NULL);
-               return r;
+               return ERR_PTR(r);
        }
 
        radeon_ring_unlock_commit(rdev, ring, false);
-       radeon_semaphore_free(rdev, &sem, *fence);
+       radeon_semaphore_free(rdev, &sem, fence);
 
-       return r;
+       return fence;
 }
index 26ef8ced6f89fd5388f80d2eb408c1a064af3b0e..b90dc0eb08e6637623af76e3f76911ced593fba3 100644 (file)
@@ -71,6 +71,169 @@ static const struct radeon_hdmi_acr r600_hdmi_predefined_acr[] = {
 };
 
 
+/*
+ * check if the chipset is supported
+ */
+static int r600_audio_chipset_supported(struct radeon_device *rdev)
+{
+       return ASIC_IS_DCE2(rdev) && !ASIC_IS_NODCE(rdev);
+}
+
+static struct r600_audio_pin r600_audio_status(struct radeon_device *rdev)
+{
+       struct r600_audio_pin status;
+       uint32_t value;
+
+       value = RREG32(R600_AUDIO_RATE_BPS_CHANNEL);
+
+       /* number of channels */
+       status.channels = (value & 0x7) + 1;
+
+       /* bits per sample */
+       switch ((value & 0xF0) >> 4) {
+       case 0x0:
+               status.bits_per_sample = 8;
+               break;
+       case 0x1:
+               status.bits_per_sample = 16;
+               break;
+       case 0x2:
+               status.bits_per_sample = 20;
+               break;
+       case 0x3:
+               status.bits_per_sample = 24;
+               break;
+       case 0x4:
+               status.bits_per_sample = 32;
+               break;
+       default:
+               dev_err(rdev->dev, "Unknown bits per sample 0x%x, using 16\n",
+                       (int)value);
+               status.bits_per_sample = 16;
+       }
+
+       /* current sampling rate in HZ */
+       if (value & 0x4000)
+               status.rate = 44100;
+       else
+               status.rate = 48000;
+       status.rate *= ((value >> 11) & 0x7) + 1;
+       status.rate /= ((value >> 8) & 0x7) + 1;
+
+       value = RREG32(R600_AUDIO_STATUS_BITS);
+
+       /* iec 60958 status bits */
+       status.status_bits = value & 0xff;
+
+       /* iec 60958 category code */
+       status.category_code = (value >> 8) & 0xff;
+
+       return status;
+}
+
+/*
+ * update all hdmi interfaces with current audio parameters
+ */
+void r600_audio_update_hdmi(struct work_struct *work)
+{
+       struct radeon_device *rdev = container_of(work, struct radeon_device,
+                                                 audio_work);
+       struct drm_device *dev = rdev->ddev;
+       struct r600_audio_pin audio_status = r600_audio_status(rdev);
+       struct drm_encoder *encoder;
+       bool changed = false;
+
+       if (rdev->audio.pin[0].channels != audio_status.channels ||
+           rdev->audio.pin[0].rate != audio_status.rate ||
+           rdev->audio.pin[0].bits_per_sample != audio_status.bits_per_sample ||
+           rdev->audio.pin[0].status_bits != audio_status.status_bits ||
+           rdev->audio.pin[0].category_code != audio_status.category_code) {
+               rdev->audio.pin[0] = audio_status;
+               changed = true;
+       }
+
+       list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
+               if (!radeon_encoder_is_digital(encoder))
+                       continue;
+               if (changed || r600_hdmi_buffer_status_changed(encoder))
+                       r600_hdmi_update_audio_settings(encoder);
+       }
+}
+
+/* enable the audio stream */
+void r600_audio_enable(struct radeon_device *rdev,
+                      struct r600_audio_pin *pin,
+                      u8 enable_mask)
+{
+       u32 tmp = RREG32(AZ_HOT_PLUG_CONTROL);
+
+       if (!pin)
+               return;
+
+       if (enable_mask) {
+               tmp |= AUDIO_ENABLED;
+               if (enable_mask & 1)
+                       tmp |= PIN0_AUDIO_ENABLED;
+               if (enable_mask & 2)
+                       tmp |= PIN1_AUDIO_ENABLED;
+               if (enable_mask & 4)
+                       tmp |= PIN2_AUDIO_ENABLED;
+               if (enable_mask & 8)
+                       tmp |= PIN3_AUDIO_ENABLED;
+       } else {
+               tmp &= ~(AUDIO_ENABLED |
+                        PIN0_AUDIO_ENABLED |
+                        PIN1_AUDIO_ENABLED |
+                        PIN2_AUDIO_ENABLED |
+                        PIN3_AUDIO_ENABLED);
+       }
+
+       WREG32(AZ_HOT_PLUG_CONTROL, tmp);
+}
+
+/*
+ * initialize the audio vars
+ */
+int r600_audio_init(struct radeon_device *rdev)
+{
+       if (!radeon_audio || !r600_audio_chipset_supported(rdev))
+               return 0;
+
+       rdev->audio.enabled = true;
+
+       rdev->audio.num_pins = 1;
+       rdev->audio.pin[0].channels = -1;
+       rdev->audio.pin[0].rate = -1;
+       rdev->audio.pin[0].bits_per_sample = -1;
+       rdev->audio.pin[0].status_bits = 0;
+       rdev->audio.pin[0].category_code = 0;
+       rdev->audio.pin[0].id = 0;
+       /* disable audio.  it will be set up later */
+       r600_audio_enable(rdev, &rdev->audio.pin[0], 0);
+
+       return 0;
+}
+
+/*
+ * release the audio timer
+ * TODO: How to do this correctly on SMP systems?
+ */
+void r600_audio_fini(struct radeon_device *rdev)
+{
+       if (!rdev->audio.enabled)
+               return;
+
+       r600_audio_enable(rdev, &rdev->audio.pin[0], 0);
+
+       rdev->audio.enabled = false;
+}
+
+struct r600_audio_pin *r600_audio_get_pin(struct radeon_device *rdev)
+{
+       /* only one pin on 6xx-NI */
+       return &rdev->audio.pin[0];
+}
+
 /*
  * calculate CTS and N values if they are not found in the table
  */
@@ -357,7 +520,7 @@ void r600_hdmi_setmode(struct drm_encoder *encoder, struct drm_display_mode *mod
 
        /* disable audio prior to setting up hw */
        dig->afmt->pin = r600_audio_get_pin(rdev);
-       r600_audio_enable(rdev, dig->afmt->pin, false);
+       r600_audio_enable(rdev, dig->afmt->pin, 0xf);
 
        r600_audio_set_dto(encoder, mode->clock);
 
@@ -443,7 +606,7 @@ void r600_hdmi_setmode(struct drm_encoder *encoder, struct drm_display_mode *mod
        WREG32(HDMI0_RAMP_CONTROL3 + offset, 0x00000001);
 
        /* enable audio after to setting up hw */
-       r600_audio_enable(rdev, dig->afmt->pin, true);
+       r600_audio_enable(rdev, dig->afmt->pin, 0xf);
 }
 
 /**
@@ -528,6 +691,11 @@ void r600_hdmi_enable(struct drm_encoder *encoder, bool enable)
        if (!enable && !dig->afmt->enabled)
                return;
 
+       if (!enable && dig->afmt->pin) {
+               r600_audio_enable(rdev, dig->afmt->pin, 0);
+               dig->afmt->pin = NULL;
+       }
+
        /* Older chipsets require setting HDMI and routing manually */
        if (!ASIC_IS_DCE3(rdev)) {
                if (enable)
index 31e1052ad3e3780cec522ab8a2e04bb62698c573..1e8495cca41e9f5f611dfc3b84726104427969c7 100644 (file)
 #define        HDP_TILING_CONFIG                               0x2F3C
 #define HDP_DEBUG1                                      0x2F34
 
+#define MC_CONFIG                                      0x2000
 #define MC_VM_AGP_TOP                                  0x2184
 #define MC_VM_AGP_BOT                                  0x2188
 #define        MC_VM_AGP_BASE                                  0x218C
 #define MC_VM_FB_LOCATION                              0x2180
-#define MC_VM_L1_TLB_MCD_RD_A_CNTL                     0x219C
+#define MC_VM_L1_TLB_MCB_RD_UVD_CNTL                   0x2124
 #define        ENABLE_L1_TLB                                   (1 << 0)
 #define                ENABLE_L1_FRAGMENT_PROCESSING                   (1 << 1)
 #define                ENABLE_L1_STRICT_ORDERING                       (1 << 2)
 #define                EFFECTIVE_L1_QUEUE_SIZE(x)                      (((x) & 7) << 15)
 #define                EFFECTIVE_L1_QUEUE_SIZE_MASK                    0x00038000
 #define                EFFECTIVE_L1_QUEUE_SIZE_SHIFT                   15
+#define MC_VM_L1_TLB_MCD_RD_A_CNTL                     0x219C
 #define MC_VM_L1_TLB_MCD_RD_B_CNTL                     0x21A0
 #define MC_VM_L1_TLB_MCB_RD_GFX_CNTL                   0x21FC
 #define MC_VM_L1_TLB_MCB_RD_HDP_CNTL                   0x2204
 #define MC_VM_L1_TLB_MCB_RD_PDMA_CNTL                  0x2208
 #define MC_VM_L1_TLB_MCB_RD_SEM_CNTL                   0x220C
 #define        MC_VM_L1_TLB_MCB_RD_SYS_CNTL                    0x2200
+#define MC_VM_L1_TLB_MCB_WR_UVD_CNTL                   0x212c
 #define MC_VM_L1_TLB_MCD_WR_A_CNTL                     0x21A4
 #define MC_VM_L1_TLB_MCD_WR_B_CNTL                     0x21A8
 #define MC_VM_L1_TLB_MCB_WR_GFX_CNTL                   0x2210
 #define MC_VM_SYSTEM_APERTURE_HIGH_ADDR                        0x2194
 #define MC_VM_SYSTEM_APERTURE_DEFAULT_ADDR             0x2198
 
+#define RS_DQ_RD_RET_CONF                              0x2348
+
 #define        PA_CL_ENHANCE                                   0x8A14
 #define                CLIP_VTX_REORDER_ENA                            (1 << 0)
 #define                NUM_CLIP_SEQ(x)                                 ((x) << 1)
 #       define TARGET_LINK_SPEED_MASK                     (0xf << 0)
 #       define SELECTABLE_DEEMPHASIS                      (1 << 6)
 
+/* Audio */
+#define AZ_HOT_PLUG_CONTROL               0x7300
+#       define AZ_FORCE_CODEC_WAKE        (1 << 0)
+#       define JACK_DETECTION_ENABLE      (1 << 4)
+#       define UNSOLICITED_RESPONSE_ENABLE (1 << 8)
+#       define CODEC_HOT_PLUG_ENABLE      (1 << 12)
+#       define AUDIO_ENABLED              (1 << 31)
+/* DCE3 adds */
+#       define PIN0_JACK_DETECTION_ENABLE (1 << 4)
+#       define PIN1_JACK_DETECTION_ENABLE (1 << 5)
+#       define PIN2_JACK_DETECTION_ENABLE (1 << 6)
+#       define PIN3_JACK_DETECTION_ENABLE (1 << 7)
+#       define PIN0_AUDIO_ENABLED         (1 << 24)
+#       define PIN1_AUDIO_ENABLED         (1 << 25)
+#       define PIN2_AUDIO_ENABLED         (1 << 26)
+#       define PIN3_AUDIO_ENABLED         (1 << 27)
+
 /* Audio clocks DCE 2.0/3.0 */
 #define AUDIO_DTO                         0x7340
 #       define AUDIO_DTO_PHASE(x)         (((x) & 0xffff) << 0)
 #define UVD_CGC_GATE                                   0xf4a8
 #define UVD_LMI_CTRL2                                  0xf4f4
 #define UVD_MASTINT_EN                                 0xf500
+#define UVD_FW_START                                   0xf51C
 #define UVD_LMI_ADDR_EXT                               0xf594
 #define UVD_LMI_CTRL                                   0xf598
 #define UVD_LMI_SWAP_CNTL                              0xf5b4
 #define UVD_MPC_SET_MUX                                        0xf5f4
 #define UVD_MPC_SET_ALU                                        0xf5f8
 
+#define UVD_VCPU_CACHE_OFFSET0                         0xf608
+#define UVD_VCPU_CACHE_SIZE0                           0xf60c
+#define UVD_VCPU_CACHE_OFFSET1                         0xf610
+#define UVD_VCPU_CACHE_SIZE1                           0xf614
+#define UVD_VCPU_CACHE_OFFSET2                         0xf618
+#define UVD_VCPU_CACHE_SIZE2                           0xf61c
+
 #define UVD_VCPU_CNTL                                  0xf660
 #define UVD_SOFT_RESET                                 0xf680
 #define                RBC_SOFT_RESET                                  (1<<0)
 
 #define UVD_CONTEXT_ID                                 0xf6f4
 
+/* rs780 only */
+#define        GFX_MACRO_BYPASS_CNTL                           0x30c0
+#define                SPLL_BYPASS_CNTL                        (1 << 0)
+#define                UPLL_BYPASS_CNTL                        (1 << 1)
+
+#define CG_UPLL_FUNC_CNTL                              0x7e0
+#      define UPLL_RESET_MASK                          0x00000001
+#      define UPLL_SLEEP_MASK                          0x00000002
+#      define UPLL_BYPASS_EN_MASK                      0x00000004
 #      define UPLL_CTLREQ_MASK                         0x00000008
+#      define UPLL_FB_DIV(x)                           ((x) << 4)
+#      define UPLL_FB_DIV_MASK                         0x0000FFF0
+#      define UPLL_REF_DIV(x)                          ((x) << 16)
+#      define UPLL_REF_DIV_MASK                        0x003F0000
+#      define UPLL_REFCLK_SRC_SEL_MASK                 0x20000000
 #      define UPLL_CTLACK_MASK                         0x40000000
 #      define UPLL_CTLACK2_MASK                        0x80000000
+#define CG_UPLL_FUNC_CNTL_2                            0x7e4
+#      define UPLL_SW_HILEN(x)                         ((x) << 0)
+#      define UPLL_SW_LOLEN(x)                         ((x) << 4)
+#      define UPLL_SW_HILEN2(x)                        ((x) << 8)
+#      define UPLL_SW_LOLEN2(x)                        ((x) << 12)
+#      define UPLL_DIVEN_MASK                          0x00010000
+#      define UPLL_DIVEN2_MASK                         0x00020000
+#      define UPLL_SW_MASK                             0x0003FFFF
+#      define VCLK_SRC_SEL(x)                          ((x) << 20)
+#      define VCLK_SRC_SEL_MASK                        0x01F00000
+#      define DCLK_SRC_SEL(x)                          ((x) << 25)
+#      define DCLK_SRC_SEL_MASK                        0x3E000000
 
 /*
  * PM4
index 3247bfd144106d54fa24161f898f24ae538f9a3c..f7c4b226a284a162fcd088210d85b7b3ff57a838 100644 (file)
@@ -65,6 +65,8 @@
 #include <linux/list.h>
 #include <linux/kref.h>
 #include <linux/interval_tree.h>
+#include <linux/hashtable.h>
+#include <linux/fence.h>
 
 #include <ttm/ttm_bo_api.h>
 #include <ttm/ttm_bo_driver.h>
@@ -72,6 +74,8 @@
 #include <ttm/ttm_module.h>
 #include <ttm/ttm_execbuf_util.h>
 
+#include <drm/drm_gem.h>
+
 #include "radeon_family.h"
 #include "radeon_mode.h"
 #include "radeon_reg.h"
@@ -120,9 +124,6 @@ extern int radeon_backlight;
 #define RADEONFB_CONN_LIMIT                    4
 #define RADEON_BIOS_NUM_SCRATCH                        8
 
-/* fence seq are set to this number when signaled */
-#define RADEON_FENCE_SIGNALED_SEQ              0LL
-
 /* internal ring indices */
 /* r1xx+ has gfx CP ring */
 #define RADEON_RING_TYPE_GFX_INDEX             0
@@ -350,28 +351,32 @@ extern void evergreen_tiling_fields(unsigned tiling_flags, unsigned *bankw,
  * Fences.
  */
 struct radeon_fence_driver {
+       struct radeon_device            *rdev;
        uint32_t                        scratch_reg;
        uint64_t                        gpu_addr;
        volatile uint32_t               *cpu_addr;
        /* sync_seq is protected by ring emission lock */
        uint64_t                        sync_seq[RADEON_NUM_RINGS];
        atomic64_t                      last_seq;
-       bool                            initialized;
+       bool                            initialized, delayed_irq;
+       struct delayed_work             lockup_work;
 };
 
 struct radeon_fence {
+       struct fence base;
+
        struct radeon_device            *rdev;
-       struct kref                     kref;
-       /* protected by radeon_fence.lock */
        uint64_t                        seq;
        /* RB, DMA, etc. */
        unsigned                        ring;
+
+       wait_queue_t                    fence_wake;
 };
 
 int radeon_fence_driver_start_ring(struct radeon_device *rdev, int ring);
 int radeon_fence_driver_init(struct radeon_device *rdev);
 void radeon_fence_driver_fini(struct radeon_device *rdev);
-void radeon_fence_driver_force_completion(struct radeon_device *rdev);
+void radeon_fence_driver_force_completion(struct radeon_device *rdev, int ring);
 int radeon_fence_emit(struct radeon_device *rdev, struct radeon_fence **fence, int ring);
 void radeon_fence_process(struct radeon_device *rdev, int ring);
 bool radeon_fence_signaled(struct radeon_fence *fence);
@@ -469,7 +474,7 @@ struct radeon_bo {
        struct list_head                list;
        /* Protected by tbo.reserved */
        u32                             initial_domain;
-       u32                             placements[3];
+       struct ttm_place                placements[3];
        struct ttm_placement            placement;
        struct ttm_buffer_object        tbo;
        struct ttm_bo_kmap_obj          kmap;
@@ -489,6 +494,9 @@ struct radeon_bo {
 
        struct ttm_bo_kmap_obj          dma_buf_vmap;
        pid_t                           pid;
+
+       struct radeon_mn                *mn;
+       struct interval_tree_node       mn_it;
 };
 #define gem_to_radeon_bo(gobj) container_of((gobj), struct radeon_bo, gem_base)
 
@@ -580,8 +588,12 @@ bool radeon_semaphore_emit_signal(struct radeon_device *rdev, int ring,
                                  struct radeon_semaphore *semaphore);
 bool radeon_semaphore_emit_wait(struct radeon_device *rdev, int ring,
                                struct radeon_semaphore *semaphore);
-void radeon_semaphore_sync_to(struct radeon_semaphore *semaphore,
-                             struct radeon_fence *fence);
+void radeon_semaphore_sync_fence(struct radeon_semaphore *semaphore,
+                                struct radeon_fence *fence);
+int radeon_semaphore_sync_resv(struct radeon_device *rdev,
+                              struct radeon_semaphore *semaphore,
+                              struct reservation_object *resv,
+                              bool shared);
 int radeon_semaphore_sync_rings(struct radeon_device *rdev,
                                struct radeon_semaphore *semaphore,
                                int waiting_ring);
@@ -702,7 +714,7 @@ struct radeon_flip_work {
        uint64_t                        base;
        struct drm_pending_vblank_event *event;
        struct radeon_bo                *old_rbo;
-       struct radeon_fence             *fence;
+       struct fence                    *fence;
 };
 
 struct r500_irq_stat_regs {
@@ -780,6 +792,7 @@ struct radeon_irq {
 int radeon_irq_kms_init(struct radeon_device *rdev);
 void radeon_irq_kms_fini(struct radeon_device *rdev);
 void radeon_irq_kms_sw_irq_get(struct radeon_device *rdev, int ring);
+bool radeon_irq_kms_sw_irq_get_delayed(struct radeon_device *rdev, int ring);
 void radeon_irq_kms_sw_irq_put(struct radeon_device *rdev, int ring);
 void radeon_irq_kms_pflip_irq_get(struct radeon_device *rdev, int crtc);
 void radeon_irq_kms_pflip_irq_put(struct radeon_device *rdev, int crtc);
@@ -1642,7 +1655,8 @@ int radeon_uvd_get_create_msg(struct radeon_device *rdev, int ring,
                              uint32_t handle, struct radeon_fence **fence);
 int radeon_uvd_get_destroy_msg(struct radeon_device *rdev, int ring,
                               uint32_t handle, struct radeon_fence **fence);
-void radeon_uvd_force_into_uvd_segment(struct radeon_bo *rbo);
+void radeon_uvd_force_into_uvd_segment(struct radeon_bo *rbo,
+                                      uint32_t allowed_domains);
 void radeon_uvd_free_handles(struct radeon_device *rdev,
                             struct drm_file *filp);
 int radeon_uvd_cs_parse(struct radeon_cs_parser *parser);
@@ -1731,6 +1745,11 @@ void radeon_test_ring_sync(struct radeon_device *rdev,
                           struct radeon_ring *cpB);
 void radeon_test_syncing(struct radeon_device *rdev);
 
+/*
+ * MMU Notifier
+ */
+int radeon_mn_register(struct radeon_bo *bo, unsigned long addr);
+void radeon_mn_unregister(struct radeon_bo *bo);
 
 /*
  * Debugfs
@@ -1845,24 +1864,24 @@ struct radeon_asic {
        } display;
        /* copy functions for bo handling */
        struct {
-               int (*blit)(struct radeon_device *rdev,
-                           uint64_t src_offset,
-                           uint64_t dst_offset,
-                           unsigned num_gpu_pages,
-                           struct radeon_fence **fence);
+               struct radeon_fence *(*blit)(struct radeon_device *rdev,
+                                            uint64_t src_offset,
+                                            uint64_t dst_offset,
+                                            unsigned num_gpu_pages,
+                                            struct reservation_object *resv);
                u32 blit_ring_index;
-               int (*dma)(struct radeon_device *rdev,
-                          uint64_t src_offset,
-                          uint64_t dst_offset,
-                          unsigned num_gpu_pages,
-                          struct radeon_fence **fence);
+               struct radeon_fence *(*dma)(struct radeon_device *rdev,
+                                           uint64_t src_offset,
+                                           uint64_t dst_offset,
+                                           unsigned num_gpu_pages,
+                                           struct reservation_object *resv);
                u32 dma_ring_index;
                /* method used for bo copy */
-               int (*copy)(struct radeon_device *rdev,
-                           uint64_t src_offset,
-                           uint64_t dst_offset,
-                           unsigned num_gpu_pages,
-                           struct radeon_fence **fence);
+               struct radeon_fence *(*copy)(struct radeon_device *rdev,
+                                            uint64_t src_offset,
+                                            uint64_t dst_offset,
+                                            unsigned num_gpu_pages,
+                                            struct reservation_object *resv);
                /* ring used for bo copies */
                u32 copy_ring_index;
        } copy;
@@ -2144,6 +2163,8 @@ int radeon_gem_info_ioctl(struct drm_device *dev, void *data,
                          struct drm_file *filp);
 int radeon_gem_create_ioctl(struct drm_device *dev, void *data,
                            struct drm_file *filp);
+int radeon_gem_userptr_ioctl(struct drm_device *dev, void *data,
+                            struct drm_file *filp);
 int radeon_gem_pin_ioctl(struct drm_device *dev, void *data,
                         struct drm_file *file_priv);
 int radeon_gem_unpin_ioctl(struct drm_device *dev, void *data,
@@ -2300,6 +2321,7 @@ struct radeon_device {
        struct radeon_mman              mman;
        struct radeon_fence_driver      fence_drv[RADEON_NUM_RINGS];
        wait_queue_head_t               fence_queue;
+       unsigned                        fence_context;
        struct mutex                    ring_lock;
        struct radeon_ring              ring[RADEON_NUM_RINGS];
        bool                            ib_pool_ready;
@@ -2318,7 +2340,7 @@ struct radeon_device {
        bool                            need_dma32;
        bool                            accel_working;
        bool                            fastfb_working; /* IGP feature*/
-       bool                            needs_reset;
+       bool                            needs_reset, in_reset;
        struct radeon_surface_reg surface_regs[RADEON_GEM_MAX_SURFACES];
        const struct firmware *me_fw;   /* all family ME firmware */
        const struct firmware *pfp_fw;  /* r6/700 PFP firmware */
@@ -2339,7 +2361,6 @@ struct radeon_device {
        struct radeon_mec mec;
        struct work_struct hotplug_work;
        struct work_struct audio_work;
-       struct work_struct reset_work;
        int num_crtc; /* number of crtcs */
        struct mutex dc_hw_i2c_mutex; /* display controller hw i2c mutex */
        bool has_uvd;
@@ -2376,6 +2397,9 @@ struct radeon_device {
        /* tracking pinned memory */
        u64 vram_pin_size;
        u64 gart_pin_size;
+
+       struct mutex    mn_lock;
+       DECLARE_HASHTABLE(mn_hash, 7);
 };
 
 bool radeon_is_px(struct drm_device *dev);
@@ -2431,7 +2455,17 @@ void cik_mm_wdoorbell(struct radeon_device *rdev, u32 index, u32 v);
 /*
  * Cast helper
  */
-#define to_radeon_fence(p) ((struct radeon_fence *)(p))
+extern const struct fence_ops radeon_fence_ops;
+
+static inline struct radeon_fence *to_radeon_fence(struct fence *f)
+{
+       struct radeon_fence *__f = container_of(f, struct radeon_fence, base);
+
+       if (__f->base.ops == &radeon_fence_ops)
+               return __f;
+
+       return NULL;
+}
 
 /*
  * Registers read & write functions.
@@ -2751,18 +2785,25 @@ void radeon_atombios_fini(struct radeon_device *rdev);
 /*
  * RING helpers.
  */
-#if DRM_DEBUG_CODE == 0
+
+/**
+ * radeon_ring_write - write a value to the ring
+ *
+ * @ring: radeon_ring structure holding ring information
+ * @v: dword (dw) value to write
+ *
+ * Write a value to the requested ring buffer (all asics).
+ */
 static inline void radeon_ring_write(struct radeon_ring *ring, uint32_t v)
 {
+       if (ring->count_dw <= 0)
+               DRM_ERROR("radeon: writing more dwords to the ring than expected!\n");
+
        ring->ring[ring->wptr++] = v;
        ring->wptr &= ring->ptr_mask;
        ring->count_dw--;
        ring->ring_free_dw--;
 }
-#else
-/* With debugging this is just too big to inline */
-void radeon_ring_write(struct radeon_ring *ring, uint32_t v);
-#endif
 
 /*
  * ASICs macro.
@@ -2801,9 +2842,9 @@ void radeon_ring_write(struct radeon_ring *ring, uint32_t v);
 #define radeon_hdmi_setmode(rdev, e, m) (rdev)->asic->display.hdmi_setmode((e), (m))
 #define radeon_fence_ring_emit(rdev, r, fence) (rdev)->asic->ring[(r)]->emit_fence((rdev), (fence))
 #define radeon_semaphore_ring_emit(rdev, r, cp, semaphore, emit_wait) (rdev)->asic->ring[(r)]->emit_semaphore((rdev), (cp), (semaphore), (emit_wait))
-#define radeon_copy_blit(rdev, s, d, np, f) (rdev)->asic->copy.blit((rdev), (s), (d), (np), (f))
-#define radeon_copy_dma(rdev, s, d, np, f) (rdev)->asic->copy.dma((rdev), (s), (d), (np), (f))
-#define radeon_copy(rdev, s, d, np, f) (rdev)->asic->copy.copy((rdev), (s), (d), (np), (f))
+#define radeon_copy_blit(rdev, s, d, np, resv) (rdev)->asic->copy.blit((rdev), (s), (d), (np), (resv))
+#define radeon_copy_dma(rdev, s, d, np, resv) (rdev)->asic->copy.dma((rdev), (s), (d), (np), (resv))
+#define radeon_copy(rdev, s, d, np, resv) (rdev)->asic->copy.copy((rdev), (s), (d), (np), (resv))
 #define radeon_copy_blit_ring_index(rdev) (rdev)->asic->copy.blit_ring_index
 #define radeon_copy_dma_ring_index(rdev) (rdev)->asic->copy.dma_ring_index
 #define radeon_copy_ring_index(rdev) (rdev)->asic->copy.copy_ring_index
@@ -2877,6 +2918,10 @@ extern void radeon_legacy_set_clock_gating(struct radeon_device *rdev, int enabl
 extern void radeon_atom_set_clock_gating(struct radeon_device *rdev, int enable);
 extern void radeon_ttm_placement_from_domain(struct radeon_bo *rbo, u32 domain);
 extern bool radeon_ttm_bo_is_radeon_bo(struct ttm_buffer_object *bo);
+extern int radeon_ttm_tt_set_userptr(struct ttm_tt *ttm, uint64_t addr,
+                                    uint32_t flags);
+extern bool radeon_ttm_tt_has_userptr(struct ttm_tt *ttm);
+extern bool radeon_ttm_tt_is_readonly(struct ttm_tt *ttm);
 extern void radeon_vram_location(struct radeon_device *rdev, struct radeon_mc *mc, u64 base);
 extern void radeon_gtt_location(struct radeon_device *rdev, struct radeon_mc *mc);
 extern int radeon_resume_kms(struct drm_device *dev, bool resume, bool fbcon);
@@ -2934,10 +2979,10 @@ struct r600_audio_pin *r600_audio_get_pin(struct radeon_device *rdev);
 struct r600_audio_pin *dce6_audio_get_pin(struct radeon_device *rdev);
 void r600_audio_enable(struct radeon_device *rdev,
                       struct r600_audio_pin *pin,
-                      bool enable);
+                      u8 enable_mask);
 void dce6_audio_enable(struct radeon_device *rdev,
                       struct r600_audio_pin *pin,
-                      bool enable);
+                      u8 enable_mask);
 
 /*
  * R600 vram scratch functions
index 2dd5847f9b98e8a428e63b9ff9563f52b94d2709..850de57069bec0effcadd4a55c6b1abead242314 100644 (file)
@@ -963,6 +963,19 @@ static struct radeon_asic r600_asic = {
        },
 };
 
+static struct radeon_asic_ring rv6xx_uvd_ring = {
+       .ib_execute = &uvd_v1_0_ib_execute,
+       .emit_fence = &uvd_v1_0_fence_emit,
+       .emit_semaphore = &uvd_v1_0_semaphore_emit,
+       .cs_parse = &radeon_uvd_cs_parse,
+       .ring_test = &uvd_v1_0_ring_test,
+       .ib_test = &uvd_v1_0_ib_test,
+       .is_lockup = &radeon_ring_test_lockup,
+       .get_rptr = &uvd_v1_0_get_rptr,
+       .get_wptr = &uvd_v1_0_get_wptr,
+       .set_wptr = &uvd_v1_0_set_wptr,
+};
+
 static struct radeon_asic rv6xx_asic = {
        .init = &r600_init,
        .fini = &r600_fini,
@@ -982,6 +995,7 @@ static struct radeon_asic rv6xx_asic = {
        .ring = {
                [RADEON_RING_TYPE_GFX_INDEX] = &r600_gfx_ring,
                [R600_RING_TYPE_DMA_INDEX] = &r600_dma_ring,
+               [R600_RING_TYPE_UVD_INDEX] = &rv6xx_uvd_ring,
        },
        .irq = {
                .set = &r600_irq_set,
@@ -1072,6 +1086,7 @@ static struct radeon_asic rs780_asic = {
        .ring = {
                [RADEON_RING_TYPE_GFX_INDEX] = &r600_gfx_ring,
                [R600_RING_TYPE_DMA_INDEX] = &r600_dma_ring,
+               [R600_RING_TYPE_UVD_INDEX] = &rv6xx_uvd_ring,
        },
        .irq = {
                .set = &r600_irq_set,
@@ -2296,7 +2311,15 @@ int radeon_asic_init(struct radeon_device *rdev)
        case CHIP_RS780:
        case CHIP_RS880:
                rdev->asic = &rs780_asic;
-               rdev->has_uvd = true;
+               /* 760G/780V/880V don't have UVD */
+               if ((rdev->pdev->device == 0x9616)||
+                   (rdev->pdev->device == 0x9611)||
+                   (rdev->pdev->device == 0x9613)||
+                   (rdev->pdev->device == 0x9711)||
+                   (rdev->pdev->device == 0x9713))
+                       rdev->has_uvd = false;
+               else
+                       rdev->has_uvd = true;
                break;
        case CHIP_RV770:
        case CHIP_RV730:
index 7756bc1e1cd3ef088ac4bb96fa04a9ab632ad088..d8ace5b28a5b2e1455b5776129022300b3d1be3e 100644 (file)
@@ -81,11 +81,11 @@ bool r100_semaphore_ring_emit(struct radeon_device *rdev,
 int r100_cs_parse(struct radeon_cs_parser *p);
 void r100_pll_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v);
 uint32_t r100_pll_rreg(struct radeon_device *rdev, uint32_t reg);
-int r100_copy_blit(struct radeon_device *rdev,
-                  uint64_t src_offset,
-                  uint64_t dst_offset,
-                  unsigned num_gpu_pages,
-                  struct radeon_fence **fence);
+struct radeon_fence *r100_copy_blit(struct radeon_device *rdev,
+                                   uint64_t src_offset,
+                                   uint64_t dst_offset,
+                                   unsigned num_gpu_pages,
+                                   struct reservation_object *resv);
 int r100_set_surface_reg(struct radeon_device *rdev, int reg,
                         uint32_t tiling_flags, uint32_t pitch,
                         uint32_t offset, uint32_t obj_size);
@@ -152,11 +152,11 @@ void r100_gfx_set_wptr(struct radeon_device *rdev,
 /*
  * r200,rv250,rs300,rv280
  */
-extern int r200_copy_dma(struct radeon_device *rdev,
-                        uint64_t src_offset,
-                        uint64_t dst_offset,
-                        unsigned num_gpu_pages,
-                        struct radeon_fence **fence);
+struct radeon_fence *r200_copy_dma(struct radeon_device *rdev,
+                                  uint64_t src_offset,
+                                  uint64_t dst_offset,
+                                  unsigned num_gpu_pages,
+                                  struct reservation_object *resv);
 void r200_set_safe_registers(struct radeon_device *rdev);
 
 /*
@@ -340,12 +340,14 @@ int r600_dma_ib_test(struct radeon_device *rdev, struct radeon_ring *ring);
 void r600_ring_ib_execute(struct radeon_device *rdev, struct radeon_ib *ib);
 int r600_ring_test(struct radeon_device *rdev, struct radeon_ring *cp);
 int r600_dma_ring_test(struct radeon_device *rdev, struct radeon_ring *cp);
-int r600_copy_cpdma(struct radeon_device *rdev,
-                   uint64_t src_offset, uint64_t dst_offset,
-                   unsigned num_gpu_pages, struct radeon_fence **fence);
-int r600_copy_dma(struct radeon_device *rdev,
-                 uint64_t src_offset, uint64_t dst_offset,
-                 unsigned num_gpu_pages, struct radeon_fence **fence);
+struct radeon_fence *r600_copy_cpdma(struct radeon_device *rdev,
+                                    uint64_t src_offset, uint64_t dst_offset,
+                                    unsigned num_gpu_pages,
+                                    struct reservation_object *resv);
+struct radeon_fence *r600_copy_dma(struct radeon_device *rdev,
+                                  uint64_t src_offset, uint64_t dst_offset,
+                                  unsigned num_gpu_pages,
+                                  struct reservation_object *resv);
 void r600_hpd_init(struct radeon_device *rdev);
 void r600_hpd_fini(struct radeon_device *rdev);
 bool r600_hpd_sense(struct radeon_device *rdev, enum radeon_hpd_id hpd);
@@ -389,7 +391,6 @@ void r600_disable_interrupts(struct radeon_device *rdev);
 void r600_rlc_stop(struct radeon_device *rdev);
 /* r600 audio */
 int r600_audio_init(struct radeon_device *rdev);
-struct r600_audio_pin r600_audio_status(struct radeon_device *rdev);
 void r600_audio_fini(struct radeon_device *rdev);
 void r600_audio_set_dto(struct drm_encoder *encoder, u32 clock);
 void r600_hdmi_update_avi_infoframe(struct drm_encoder *encoder, void *buffer,
@@ -461,10 +462,10 @@ bool rv770_page_flip_pending(struct radeon_device *rdev, int crtc);
 void r700_vram_gtt_location(struct radeon_device *rdev, struct radeon_mc *mc);
 void r700_cp_stop(struct radeon_device *rdev);
 void r700_cp_fini(struct radeon_device *rdev);
-int rv770_copy_dma(struct radeon_device *rdev,
-                 uint64_t src_offset, uint64_t dst_offset,
-                 unsigned num_gpu_pages,
-                  struct radeon_fence **fence);
+struct radeon_fence *rv770_copy_dma(struct radeon_device *rdev,
+                                   uint64_t src_offset, uint64_t dst_offset,
+                                   unsigned num_gpu_pages,
+                                   struct reservation_object *resv);
 u32 rv770_get_xclk(struct radeon_device *rdev);
 int rv770_set_uvd_clocks(struct radeon_device *rdev, u32 vclk, u32 dclk);
 int rv770_get_temp(struct radeon_device *rdev);
@@ -535,10 +536,10 @@ void evergreen_dma_fence_ring_emit(struct radeon_device *rdev,
                                   struct radeon_fence *fence);
 void evergreen_dma_ring_ib_execute(struct radeon_device *rdev,
                                   struct radeon_ib *ib);
-int evergreen_copy_dma(struct radeon_device *rdev,
-                      uint64_t src_offset, uint64_t dst_offset,
-                      unsigned num_gpu_pages,
-                      struct radeon_fence **fence);
+struct radeon_fence *evergreen_copy_dma(struct radeon_device *rdev,
+                                       uint64_t src_offset, uint64_t dst_offset,
+                                       unsigned num_gpu_pages,
+                                       struct reservation_object *resv);
 void evergreen_hdmi_enable(struct drm_encoder *encoder, bool enable);
 void evergreen_hdmi_setmode(struct drm_encoder *encoder, struct drm_display_mode *mode);
 int evergreen_get_temp(struct radeon_device *rdev);
@@ -700,10 +701,10 @@ int si_vm_init(struct radeon_device *rdev);
 void si_vm_fini(struct radeon_device *rdev);
 void si_vm_flush(struct radeon_device *rdev, int ridx, struct radeon_vm *vm);
 int si_ib_parse(struct radeon_device *rdev, struct radeon_ib *ib);
-int si_copy_dma(struct radeon_device *rdev,
-               uint64_t src_offset, uint64_t dst_offset,
-               unsigned num_gpu_pages,
-               struct radeon_fence **fence);
+struct radeon_fence *si_copy_dma(struct radeon_device *rdev,
+                                uint64_t src_offset, uint64_t dst_offset,
+                                unsigned num_gpu_pages,
+                                struct reservation_object *resv);
 
 void si_dma_vm_copy_pages(struct radeon_device *rdev,
                          struct radeon_ib *ib,
@@ -759,14 +760,14 @@ bool cik_sdma_semaphore_ring_emit(struct radeon_device *rdev,
                                  struct radeon_semaphore *semaphore,
                                  bool emit_wait);
 void cik_sdma_ring_ib_execute(struct radeon_device *rdev, struct radeon_ib *ib);
-int cik_copy_dma(struct radeon_device *rdev,
-                uint64_t src_offset, uint64_t dst_offset,
-                unsigned num_gpu_pages,
-                struct radeon_fence **fence);
-int cik_copy_cpdma(struct radeon_device *rdev,
-                  uint64_t src_offset, uint64_t dst_offset,
-                  unsigned num_gpu_pages,
-                  struct radeon_fence **fence);
+struct radeon_fence *cik_copy_dma(struct radeon_device *rdev,
+                                 uint64_t src_offset, uint64_t dst_offset,
+                                 unsigned num_gpu_pages,
+                                 struct reservation_object *resv);
+struct radeon_fence *cik_copy_cpdma(struct radeon_device *rdev,
+                                   uint64_t src_offset, uint64_t dst_offset,
+                                   unsigned num_gpu_pages,
+                                   struct reservation_object *resv);
 int cik_sdma_ring_test(struct radeon_device *rdev, struct radeon_ring *ring);
 int cik_sdma_ib_test(struct radeon_device *rdev, struct radeon_ring *ring);
 bool cik_sdma_is_lockup(struct radeon_device *rdev, struct radeon_ring *ring);
@@ -882,6 +883,7 @@ uint32_t uvd_v1_0_get_wptr(struct radeon_device *rdev,
                            struct radeon_ring *ring);
 void uvd_v1_0_set_wptr(struct radeon_device *rdev,
                        struct radeon_ring *ring);
+int uvd_v1_0_resume(struct radeon_device *rdev);
 
 int uvd_v1_0_init(struct radeon_device *rdev);
 void uvd_v1_0_fini(struct radeon_device *rdev);
@@ -889,6 +891,8 @@ int uvd_v1_0_start(struct radeon_device *rdev);
 void uvd_v1_0_stop(struct radeon_device *rdev);
 
 int uvd_v1_0_ring_test(struct radeon_device *rdev, struct radeon_ring *ring);
+void uvd_v1_0_fence_emit(struct radeon_device *rdev,
+                        struct radeon_fence *fence);
 int uvd_v1_0_ib_test(struct radeon_device *rdev, struct radeon_ring *ring);
 bool uvd_v1_0_semaphore_emit(struct radeon_device *rdev,
                             struct radeon_ring *ring,
index e74c7e387ddebfbb74d32866b39d2046d2632540..df69b92ba164158cc5e7ae79f7b59db65305dd49 100644 (file)
@@ -458,7 +458,7 @@ static bool radeon_atom_apply_quirks(struct drm_device *dev,
        return true;
 }
 
-const int supported_devices_connector_convert[] = {
+static const int supported_devices_connector_convert[] = {
        DRM_MODE_CONNECTOR_Unknown,
        DRM_MODE_CONNECTOR_VGA,
        DRM_MODE_CONNECTOR_DVII,
@@ -477,7 +477,7 @@ const int supported_devices_connector_convert[] = {
        DRM_MODE_CONNECTOR_DisplayPort
 };
 
-const uint16_t supported_devices_connector_object_id_convert[] = {
+static const uint16_t supported_devices_connector_object_id_convert[] = {
        CONNECTOR_OBJECT_ID_NONE,
        CONNECTOR_OBJECT_ID_VGA,
        CONNECTOR_OBJECT_ID_DUAL_LINK_DVI_I, /* not all boards support DL */
@@ -494,7 +494,7 @@ const uint16_t supported_devices_connector_object_id_convert[] = {
        CONNECTOR_OBJECT_ID_SVIDEO
 };
 
-const int object_connector_convert[] = {
+static const int object_connector_convert[] = {
        DRM_MODE_CONNECTOR_Unknown,
        DRM_MODE_CONNECTOR_DVII,
        DRM_MODE_CONNECTOR_DVII,
index 69f5695bdab9b42a3efad5332be67a9866b3336e..9e7f23dd14bd5992d73b72ddec32d084ee906aed 100644 (file)
@@ -45,33 +45,29 @@ static int radeon_benchmark_do_move(struct radeon_device *rdev, unsigned size,
        for (i = 0; i < n; i++) {
                switch (flag) {
                case RADEON_BENCHMARK_COPY_DMA:
-                       r = radeon_copy_dma(rdev, saddr, daddr,
-                                           size / RADEON_GPU_PAGE_SIZE,
-                                           &fence);
+                       fence = radeon_copy_dma(rdev, saddr, daddr,
+                                               size / RADEON_GPU_PAGE_SIZE,
+                                               NULL);
                        break;
                case RADEON_BENCHMARK_COPY_BLIT:
-                       r = radeon_copy_blit(rdev, saddr, daddr,
-                                            size / RADEON_GPU_PAGE_SIZE,
-                                            &fence);
+                       fence = radeon_copy_blit(rdev, saddr, daddr,
+                                                size / RADEON_GPU_PAGE_SIZE,
+                                                NULL);
                        break;
                default:
                        DRM_ERROR("Unknown copy method\n");
-                       r = -EINVAL;
+                       return -EINVAL;
                }
-               if (r)
-                       goto exit_do_move;
+               if (IS_ERR(fence))
+                       return PTR_ERR(fence);
+
                r = radeon_fence_wait(fence, false);
-               if (r)
-                       goto exit_do_move;
                radeon_fence_unref(&fence);
+               if (r)
+                       return r;
        }
        end_jiffies = jiffies;
-       r = jiffies_to_msecs(end_jiffies - start_jiffies);
-
-exit_do_move:
-       if (fence)
-               radeon_fence_unref(&fence);
-       return r;
+       return jiffies_to_msecs(end_jiffies - start_jiffies);
 }
 
 
@@ -97,7 +93,7 @@ static void radeon_benchmark_move(struct radeon_device *rdev, unsigned size,
        int time;
 
        n = RADEON_BENCHMARK_ITERATIONS;
-       r = radeon_bo_create(rdev, size, PAGE_SIZE, true, sdomain, 0, NULL, &sobj);
+       r = radeon_bo_create(rdev, size, PAGE_SIZE, true, sdomain, 0, NULL, NULL, &sobj);
        if (r) {
                goto out_cleanup;
        }
@@ -109,7 +105,7 @@ static void radeon_benchmark_move(struct radeon_device *rdev, unsigned size,
        if (r) {
                goto out_cleanup;
        }
-       r = radeon_bo_create(rdev, size, PAGE_SIZE, true, ddomain, 0, NULL, &dobj);
+       r = radeon_bo_create(rdev, size, PAGE_SIZE, true, ddomain, 0, NULL, NULL, &dobj);
        if (r) {
                goto out_cleanup;
        }
index 6651177110f08cd5afb9088f4849ad3f987f5a1b..3e5f6b71f3adad72b0aae490ede2ae1f426c9ff5 100644 (file)
@@ -116,7 +116,7 @@ enum radeon_combios_connector {
        CONNECTOR_UNSUPPORTED_LEGACY
 };
 
-const int legacy_connector_convert[] = {
+static const int legacy_connector_convert[] = {
        DRM_MODE_CONNECTOR_Unknown,
        DRM_MODE_CONNECTOR_DVID,
        DRM_MODE_CONNECTOR_VGA,
index bb0d5c3a8311bf0dc274c2b47930078d7e657852..ea134a7d51a51f8adb92856bb98a4e442a21e7f8 100644 (file)
@@ -1298,27 +1298,27 @@ static int radeon_do_init_cp(struct drm_device *dev, drm_radeon_init_t *init,
        dev_priv->buffers_offset = init->buffers_offset;
        dev_priv->gart_textures_offset = init->gart_textures_offset;
 
-       master_priv->sarea = drm_getsarea(dev);
+       master_priv->sarea = drm_legacy_getsarea(dev);
        if (!master_priv->sarea) {
                DRM_ERROR("could not find sarea!\n");
                radeon_do_cleanup_cp(dev);
                return -EINVAL;
        }
 
-       dev_priv->cp_ring = drm_core_findmap(dev, init->ring_offset);
+       dev_priv->cp_ring = drm_legacy_findmap(dev, init->ring_offset);
        if (!dev_priv->cp_ring) {
                DRM_ERROR("could not find cp ring region!\n");
                radeon_do_cleanup_cp(dev);
                return -EINVAL;
        }
-       dev_priv->ring_rptr = drm_core_findmap(dev, init->ring_rptr_offset);
+       dev_priv->ring_rptr = drm_legacy_findmap(dev, init->ring_rptr_offset);
        if (!dev_priv->ring_rptr) {
                DRM_ERROR("could not find ring read pointer!\n");
                radeon_do_cleanup_cp(dev);
                return -EINVAL;
        }
        dev->agp_buffer_token = init->buffers_offset;
-       dev->agp_buffer_map = drm_core_findmap(dev, init->buffers_offset);
+       dev->agp_buffer_map = drm_legacy_findmap(dev, init->buffers_offset);
        if (!dev->agp_buffer_map) {
                DRM_ERROR("could not find dma buffer region!\n");
                radeon_do_cleanup_cp(dev);
@@ -1327,7 +1327,7 @@ static int radeon_do_init_cp(struct drm_device *dev, drm_radeon_init_t *init,
 
        if (init->gart_textures_offset) {
                dev_priv->gart_textures =
-                   drm_core_findmap(dev, init->gart_textures_offset);
+                   drm_legacy_findmap(dev, init->gart_textures_offset);
                if (!dev_priv->gart_textures) {
                        DRM_ERROR("could not find GART texture region!\n");
                        radeon_do_cleanup_cp(dev);
@@ -1337,9 +1337,9 @@ static int radeon_do_init_cp(struct drm_device *dev, drm_radeon_init_t *init,
 
 #if __OS_HAS_AGP
        if (dev_priv->flags & RADEON_IS_AGP) {
-               drm_core_ioremap_wc(dev_priv->cp_ring, dev);
-               drm_core_ioremap_wc(dev_priv->ring_rptr, dev);
-               drm_core_ioremap_wc(dev->agp_buffer_map, dev);
+               drm_legacy_ioremap_wc(dev_priv->cp_ring, dev);
+               drm_legacy_ioremap_wc(dev_priv->ring_rptr, dev);
+               drm_legacy_ioremap_wc(dev->agp_buffer_map, dev);
                if (!dev_priv->cp_ring->handle ||
                    !dev_priv->ring_rptr->handle ||
                    !dev->agp_buffer_map->handle) {
@@ -1475,7 +1475,7 @@ static int radeon_do_init_cp(struct drm_device *dev, drm_radeon_init_t *init,
                        dev_priv->gart_info.mapping.size =
                            dev_priv->gart_info.table_size;
 
-                       drm_core_ioremap_wc(&dev_priv->gart_info.mapping, dev);
+                       drm_legacy_ioremap_wc(&dev_priv->gart_info.mapping, dev);
                        dev_priv->gart_info.addr =
                            dev_priv->gart_info.mapping.handle;
 
@@ -1569,15 +1569,15 @@ static int radeon_do_cleanup_cp(struct drm_device * dev)
 #if __OS_HAS_AGP
        if (dev_priv->flags & RADEON_IS_AGP) {
                if (dev_priv->cp_ring != NULL) {
-                       drm_core_ioremapfree(dev_priv->cp_ring, dev);
+                       drm_legacy_ioremapfree(dev_priv->cp_ring, dev);
                        dev_priv->cp_ring = NULL;
                }
                if (dev_priv->ring_rptr != NULL) {
-                       drm_core_ioremapfree(dev_priv->ring_rptr, dev);
+                       drm_legacy_ioremapfree(dev_priv->ring_rptr, dev);
                        dev_priv->ring_rptr = NULL;
                }
                if (dev->agp_buffer_map != NULL) {
-                       drm_core_ioremapfree(dev->agp_buffer_map, dev);
+                       drm_legacy_ioremapfree(dev->agp_buffer_map, dev);
                        dev->agp_buffer_map = NULL;
                }
        } else
@@ -1597,7 +1597,7 @@ static int radeon_do_cleanup_cp(struct drm_device * dev)
 
                if (dev_priv->gart_info.gart_table_location == DRM_ATI_GART_FB)
                {
-                       drm_core_ioremapfree(&dev_priv->gart_info.mapping, dev);
+                       drm_legacy_ioremapfree(&dev_priv->gart_info.mapping, dev);
                        dev_priv->gart_info.addr = NULL;
                }
        }
@@ -2106,9 +2106,9 @@ int radeon_driver_load(struct drm_device *dev, unsigned long flags)
        else
                dev_priv->flags |= RADEON_IS_PCI;
 
-       ret = drm_addmap(dev, pci_resource_start(dev->pdev, 2),
-                        pci_resource_len(dev->pdev, 2), _DRM_REGISTERS,
-                        _DRM_READ_ONLY | _DRM_DRIVER, &dev_priv->mmio);
+       ret = drm_legacy_addmap(dev, pci_resource_start(dev->pdev, 2),
+                               pci_resource_len(dev->pdev, 2), _DRM_REGISTERS,
+                               _DRM_READ_ONLY | _DRM_DRIVER, &dev_priv->mmio);
        if (ret != 0)
                return ret;
 
@@ -2135,8 +2135,8 @@ int radeon_master_create(struct drm_device *dev, struct drm_master *master)
 
        /* prebuild the SAREA */
        sareapage = max_t(unsigned long, SAREA_MAX, PAGE_SIZE);
-       ret = drm_addmap(dev, 0, sareapage, _DRM_SHM, _DRM_CONTAINS_LOCK,
-                        &master_priv->sarea);
+       ret = drm_legacy_addmap(dev, 0, sareapage, _DRM_SHM, _DRM_CONTAINS_LOCK,
+                               &master_priv->sarea);
        if (ret) {
                DRM_ERROR("SAREA setup failed\n");
                kfree(master_priv);
@@ -2162,7 +2162,7 @@ void radeon_master_destroy(struct drm_device *dev, struct drm_master *master)
 
        master_priv->sarea_priv = NULL;
        if (master_priv->sarea)
-               drm_rmmap_locked(dev, master_priv->sarea);
+               drm_legacy_rmmap_locked(dev, master_priv->sarea);
 
        kfree(master_priv);
 
@@ -2181,9 +2181,9 @@ int radeon_driver_firstopen(struct drm_device *dev)
        dev_priv->gart_info.table_size = RADEON_PCIGART_TABLE_SIZE;
 
        dev_priv->fb_aper_offset = pci_resource_start(dev->pdev, 0);
-       ret = drm_addmap(dev, dev_priv->fb_aper_offset,
-                        pci_resource_len(dev->pdev, 0), _DRM_FRAME_BUFFER,
-                        _DRM_WRITE_COMBINING, &map);
+       ret = drm_legacy_addmap(dev, dev_priv->fb_aper_offset,
+                               pci_resource_len(dev->pdev, 0),
+                               _DRM_FRAME_BUFFER, _DRM_WRITE_COMBINING, &map);
        if (ret != 0)
                return ret;
 
@@ -2196,7 +2196,7 @@ int radeon_driver_unload(struct drm_device *dev)
 
        DRM_DEBUG("\n");
 
-       drm_rmmap(dev, dev_priv->mmio);
+       drm_legacy_rmmap(dev, dev_priv->mmio);
 
        kfree(dev_priv);
 
index 83f382e8e40e35cb380d4fc6fd835a7ddac9c01a..1c893447d7cd60fff05fa029dd9d3260d9495c11 100644 (file)
@@ -78,7 +78,8 @@ static int radeon_cs_parser_relocs(struct radeon_cs_parser *p)
        struct radeon_cs_chunk *chunk;
        struct radeon_cs_buckets buckets;
        unsigned i, j;
-       bool duplicate;
+       bool duplicate, need_mmap_lock = false;
+       int r;
 
        if (p->chunk_relocs_idx == -1) {
                return 0;
@@ -136,10 +137,13 @@ static int radeon_cs_parser_relocs(struct radeon_cs_parser *p)
                           + !!r->write_domain;
 
                /* the first reloc of an UVD job is the msg and that must be in
-                  VRAM, also but everything into VRAM on AGP cards to avoid
-                  image corruptions */
+                  VRAM, also but everything into VRAM on AGP cards and older
+                  IGP chips to avoid image corruptions */
                if (p->ring == R600_RING_TYPE_UVD_INDEX &&
-                   (i == 0 || drm_pci_device_is_agp(p->rdev->ddev))) {
+                   (i == 0 || drm_pci_device_is_agp(p->rdev->ddev) ||
+                    p->rdev->family == CHIP_RS780 ||
+                    p->rdev->family == CHIP_RS880)) {
+
                        /* TODO: is this still needed for NI+ ? */
                        p->relocs[i].prefered_domains =
                                RADEON_GEM_DOMAIN_VRAM;
@@ -165,7 +169,21 @@ static int radeon_cs_parser_relocs(struct radeon_cs_parser *p)
                        p->relocs[i].allowed_domains = domain;
                }
 
+               if (radeon_ttm_tt_has_userptr(p->relocs[i].robj->tbo.ttm)) {
+                       uint32_t domain = p->relocs[i].prefered_domains;
+                       if (!(domain & RADEON_GEM_DOMAIN_GTT)) {
+                               DRM_ERROR("Only RADEON_GEM_DOMAIN_GTT is "
+                                         "allowed for userptr BOs\n");
+                               return -EINVAL;
+                       }
+                       need_mmap_lock = true;
+                       domain = RADEON_GEM_DOMAIN_GTT;
+                       p->relocs[i].prefered_domains = domain;
+                       p->relocs[i].allowed_domains = domain;
+               }
+
                p->relocs[i].tv.bo = &p->relocs[i].robj->tbo;
+               p->relocs[i].tv.shared = !r->write_domain;
                p->relocs[i].handle = r->handle;
 
                radeon_cs_buckets_add(&buckets, &p->relocs[i].tv.head,
@@ -177,8 +195,15 @@ static int radeon_cs_parser_relocs(struct radeon_cs_parser *p)
        if (p->cs_flags & RADEON_CS_USE_VM)
                p->vm_bos = radeon_vm_get_bos(p->rdev, p->ib.vm,
                                              &p->validated);
+       if (need_mmap_lock)
+               down_read(&current->mm->mmap_sem);
 
-       return radeon_bo_list_validate(p->rdev, &p->ticket, &p->validated, p->ring);
+       r = radeon_bo_list_validate(p->rdev, &p->ticket, &p->validated, p->ring);
+
+       if (need_mmap_lock)
+               up_read(&current->mm->mmap_sem);
+
+       return r;
 }
 
 static int radeon_cs_get_ring(struct radeon_cs_parser *p, u32 ring, s32 priority)
@@ -224,17 +249,24 @@ static int radeon_cs_get_ring(struct radeon_cs_parser *p, u32 ring, s32 priority
        return 0;
 }
 
-static void radeon_cs_sync_rings(struct radeon_cs_parser *p)
+static int radeon_cs_sync_rings(struct radeon_cs_parser *p)
 {
-       int i;
+       int i, r = 0;
 
        for (i = 0; i < p->nrelocs; i++) {
+               struct reservation_object *resv;
+
                if (!p->relocs[i].robj)
                        continue;
 
-               radeon_semaphore_sync_to(p->ib.semaphore,
-                                        p->relocs[i].robj->tbo.sync_obj);
+               resv = p->relocs[i].robj->tbo.resv;
+               r = radeon_semaphore_sync_resv(p->rdev, p->ib.semaphore, resv,
+                                              p->relocs[i].tv.shared);
+
+               if (r)
+                       break;
        }
+       return r;
 }
 
 /* XXX: note that this is called from the legacy UMS CS ioctl as well */
@@ -403,7 +435,7 @@ static void radeon_cs_parser_fini(struct radeon_cs_parser *parser, int error, bo
 
                ttm_eu_fence_buffer_objects(&parser->ticket,
                                            &parser->validated,
-                                           parser->ib.fence);
+                                           &parser->ib.fence->base);
        } else if (backoff) {
                ttm_eu_backoff_reservation(&parser->ticket,
                                           &parser->validated);
@@ -444,13 +476,19 @@ static int radeon_cs_ib_chunk(struct radeon_device *rdev,
                return r;
        }
 
+       r = radeon_cs_sync_rings(parser);
+       if (r) {
+               if (r != -ERESTARTSYS)
+                       DRM_ERROR("Failed to sync rings: %i\n", r);
+               return r;
+       }
+
        if (parser->ring == R600_RING_TYPE_UVD_INDEX)
                radeon_uvd_note_usage(rdev);
        else if ((parser->ring == TN_RING_TYPE_VCE1_INDEX) ||
                 (parser->ring == TN_RING_TYPE_VCE2_INDEX))
                radeon_vce_note_usage(rdev);
 
-       radeon_cs_sync_rings(parser);
        r = radeon_ib_schedule(rdev, &parser->ib, NULL, true);
        if (r) {
                DRM_ERROR("Failed to schedule IB !\n");
@@ -537,8 +575,14 @@ static int radeon_cs_ib_vm_chunk(struct radeon_device *rdev,
        if (r) {
                goto out;
        }
-       radeon_cs_sync_rings(parser);
-       radeon_semaphore_sync_to(parser->ib.semaphore, vm->fence);
+
+       r = radeon_cs_sync_rings(parser);
+       if (r) {
+               if (r != -ERESTARTSYS)
+                       DRM_ERROR("Failed to sync rings: %i\n", r);
+               goto out;
+       }
+       radeon_semaphore_sync_fence(parser->ib.semaphore, vm->fence);
 
        if ((rdev->family >= CHIP_TAHITI) &&
            (parser->chunk_const_ib_idx != -1)) {
@@ -629,6 +673,13 @@ int radeon_cs_ioctl(struct drm_device *dev, void *data, struct drm_file *filp)
                up_read(&rdev->exclusive_lock);
                return -EBUSY;
        }
+       if (rdev->in_reset) {
+               up_read(&rdev->exclusive_lock);
+               r = radeon_gpu_reset(rdev);
+               if (!r)
+                       r = -EAGAIN;
+               return r;
+       }
        /* initialize parser */
        memset(&parser, 0, sizeof(struct radeon_cs_parser));
        parser.filp = filp;
index 12c8329644c4af4e8fe5224fbbad5d888d580f28..f41cc1538e4851fcafcec22e29ffcfb07d7b0c98 100644 (file)
@@ -434,7 +434,7 @@ int radeon_wb_init(struct radeon_device *rdev)
 
        if (rdev->wb.wb_obj == NULL) {
                r = radeon_bo_create(rdev, RADEON_GPU_PAGE_SIZE, PAGE_SIZE, true,
-                                    RADEON_GEM_DOMAIN_GTT, 0, NULL,
+                                    RADEON_GEM_DOMAIN_GTT, 0, NULL, NULL,
                                     &rdev->wb.wb_obj);
                if (r) {
                        dev_warn(rdev->dev, "(%d) create WB bo failed\n", r);
@@ -1257,6 +1257,7 @@ int radeon_device_init(struct radeon_device *rdev,
        for (i = 0; i < RADEON_NUM_RINGS; i++) {
                rdev->ring[i].idx = i;
        }
+       rdev->fence_context = fence_context_alloc(RADEON_NUM_RINGS);
 
        DRM_INFO("initializing kernel modesetting (%s 0x%04X:0x%04X 0x%04X:0x%04X).\n",
                radeon_family_name[rdev->family], pdev->vendor, pdev->device,
@@ -1274,6 +1275,8 @@ int radeon_device_init(struct radeon_device *rdev,
        init_rwsem(&rdev->pm.mclk_lock);
        init_rwsem(&rdev->exclusive_lock);
        init_waitqueue_head(&rdev->irq.vblank_queue);
+       mutex_init(&rdev->mn_lock);
+       hash_init(rdev->mn_hash);
        r = radeon_gem_init(rdev);
        if (r)
                return r;
@@ -1399,10 +1402,6 @@ int radeon_device_init(struct radeon_device *rdev,
        if (r)
                goto failed;
 
-       r = radeon_ib_ring_tests(rdev);
-       if (r)
-               DRM_ERROR("ib ring test failed (%d).\n", r);
-
        r = radeon_gem_debugfs_init(rdev);
        if (r) {
                DRM_ERROR("registering gem debugfs failed (%d).\n", r);
@@ -1420,6 +1419,10 @@ int radeon_device_init(struct radeon_device *rdev,
                        goto failed;
        }
 
+       r = radeon_ib_ring_tests(rdev);
+       if (r)
+               DRM_ERROR("ib ring test failed (%d).\n", r);
+
        if ((radeon_testing & 1)) {
                if (rdev->accel_working)
                        radeon_test_moves(rdev);
@@ -1497,7 +1500,6 @@ int radeon_suspend_kms(struct drm_device *dev, bool suspend, bool fbcon)
        struct drm_crtc *crtc;
        struct drm_connector *connector;
        int i, r;
-       bool force_completion = false;
 
        if (dev == NULL || dev->dev_private == NULL) {
                return -ENODEV;
@@ -1541,12 +1543,9 @@ int radeon_suspend_kms(struct drm_device *dev, bool suspend, bool fbcon)
                r = radeon_fence_wait_empty(rdev, i);
                if (r) {
                        /* delay GPU reset to resume */
-                       force_completion = true;
+                       radeon_fence_driver_force_completion(rdev, i);
                }
        }
-       if (force_completion) {
-               radeon_fence_driver_force_completion(rdev);
-       }
 
        radeon_save_bios_scratch_regs(rdev);
 
@@ -1686,8 +1685,6 @@ int radeon_gpu_reset(struct radeon_device *rdev)
                return 0;
        }
 
-       rdev->needs_reset = false;
-
        radeon_save_bios_scratch_regs(rdev);
        /* block TTM */
        resched = ttm_bo_lock_delayed_workqueue(&rdev->mman.bdev);
@@ -1704,7 +1701,6 @@ int radeon_gpu_reset(struct radeon_device *rdev)
                }
        }
 
-retry:
        r = radeon_asic_reset(rdev);
        if (!r) {
                dev_info(rdev->dev, "GPU reset succeeded, trying to resume\n");
@@ -1713,26 +1709,12 @@ retry:
 
        radeon_restore_bios_scratch_regs(rdev);
 
-       if (!r) {
-               for (i = 0; i < RADEON_NUM_RINGS; ++i) {
+       for (i = 0; i < RADEON_NUM_RINGS; ++i) {
+               if (!r && ring_data[i]) {
                        radeon_ring_restore(rdev, &rdev->ring[i],
                                            ring_sizes[i], ring_data[i]);
-                       ring_sizes[i] = 0;
-                       ring_data[i] = NULL;
-               }
-
-               r = radeon_ib_ring_tests(rdev);
-               if (r) {
-                       dev_err(rdev->dev, "ib ring test failed (%d).\n", r);
-                       if (saved) {
-                               saved = false;
-                               radeon_suspend(rdev);
-                               goto retry;
-                       }
-               }
-       } else {
-               radeon_fence_driver_force_completion(rdev);
-               for (i = 0; i < RADEON_NUM_RINGS; ++i) {
+               } else {
+                       radeon_fence_driver_force_completion(rdev, i);
                        kfree(ring_data[i]);
                }
        }
@@ -1764,19 +1746,32 @@ retry:
        /* reset hpd state */
        radeon_hpd_init(rdev);
 
+       ttm_bo_unlock_delayed_workqueue(&rdev->mman.bdev, resched);
+
+       rdev->in_reset = true;
+       rdev->needs_reset = false;
+
+       downgrade_write(&rdev->exclusive_lock);
+
        drm_helper_resume_force_mode(rdev->ddev);
 
        /* set the power state here in case we are a PX system or headless */
        if ((rdev->pm.pm_method == PM_METHOD_DPM) && rdev->pm.dpm_enabled)
                radeon_pm_compute_clocks(rdev);
 
-       ttm_bo_unlock_delayed_workqueue(&rdev->mman.bdev, resched);
-       if (r) {
+       if (!r) {
+               r = radeon_ib_ring_tests(rdev);
+               if (r && saved)
+                       r = -EAGAIN;
+       } else {
                /* bad news, how to tell it to userspace ? */
                dev_info(rdev->dev, "GPU reset failed\n");
        }
 
-       up_write(&rdev->exclusive_lock);
+       rdev->needs_reset = r == -EAGAIN;
+       rdev->in_reset = false;
+
+       up_read(&rdev->exclusive_lock);
        return r;
 }
 
index 3fdf87318069f1a6b26e1e37f9fd504641b19132..00ead8c2758a972debddf97234e206d211db5d7a 100644 (file)
@@ -402,12 +402,21 @@ static void radeon_flip_work_func(struct work_struct *__work)
 
         down_read(&rdev->exclusive_lock);
        if (work->fence) {
-               r = radeon_fence_wait(work->fence, false);
-               if (r == -EDEADLK) {
-                       up_read(&rdev->exclusive_lock);
-                       r = radeon_gpu_reset(rdev);
-                       down_read(&rdev->exclusive_lock);
-               }
+               struct radeon_fence *fence;
+
+               fence = to_radeon_fence(work->fence);
+               if (fence && fence->rdev == rdev) {
+                       r = radeon_fence_wait(fence, false);
+                       if (r == -EDEADLK) {
+                               up_read(&rdev->exclusive_lock);
+                               do {
+                                       r = radeon_gpu_reset(rdev);
+                               } while (r == -EAGAIN);
+                               down_read(&rdev->exclusive_lock);
+                       }
+               } else
+                       r = fence_wait(work->fence, false);
+
                if (r)
                        DRM_ERROR("failed to wait on page flip fence (%d)!\n", r);
 
@@ -416,7 +425,8 @@ static void radeon_flip_work_func(struct work_struct *__work)
                 * confused about which BO the CRTC is scanning out
                 */
 
-               radeon_fence_unref(&work->fence);
+               fence_put(work->fence);
+               work->fence = NULL;
        }
 
        /* We borrow the event spin lock for protecting flip_status */
@@ -474,11 +484,6 @@ static int radeon_crtc_page_flip(struct drm_crtc *crtc,
        obj = new_radeon_fb->obj;
        new_rbo = gem_to_radeon_bo(obj);
 
-       spin_lock(&new_rbo->tbo.bdev->fence_lock);
-       if (new_rbo->tbo.sync_obj)
-               work->fence = radeon_fence_ref(new_rbo->tbo.sync_obj);
-       spin_unlock(&new_rbo->tbo.bdev->fence_lock);
-
        /* pin the new buffer */
        DRM_DEBUG_DRIVER("flip-ioctl() cur_rbo = %p, new_rbo = %p\n",
                         work->old_rbo, new_rbo);
@@ -497,6 +502,7 @@ static int radeon_crtc_page_flip(struct drm_crtc *crtc,
                DRM_ERROR("failed to pin new rbo buffer before flip\n");
                goto cleanup;
        }
+       work->fence = fence_get(reservation_object_get_excl(new_rbo->tbo.resv));
        radeon_bo_get_tiling_flags(new_rbo, &tiling_flags, NULL);
        radeon_bo_unreserve(new_rbo);
 
@@ -578,9 +584,8 @@ pflip_cleanup:
 
 cleanup:
        drm_gem_object_unreference_unlocked(&work->old_rbo->gem_base);
-       radeon_fence_unref(&work->fence);
+       fence_put(work->fence);
        kfree(work);
-
        return r;
 }
 
@@ -1917,7 +1922,7 @@ int radeon_get_crtc_scanoutpos(struct drm_device *dev, int crtc, unsigned int fl
 
        /* In vblank? */
        if (in_vbl)
-               ret |= DRM_SCANOUTPOS_INVBL;
+               ret |= DRM_SCANOUTPOS_IN_VBLANK;
 
        /* Is vpos outside nominal vblank area, but less than
         * 1/100 of a frame height away from start of vblank?
index f9d17b29b343443de2f986b6008a9991085ff518..dcffa30ee2db3d2b990abc4089967c204984be5d 100644 (file)
@@ -38,6 +38,8 @@
 #include <linux/module.h>
 #include <linux/pm_runtime.h>
 #include <linux/vga_switcheroo.h>
+#include <drm/drm_gem.h>
+
 #include "drm_crtc_helper.h"
 /*
  * KMS wrapper.
@@ -114,6 +116,9 @@ int radeon_gem_object_open(struct drm_gem_object *obj,
                                struct drm_file *file_priv);
 void radeon_gem_object_close(struct drm_gem_object *obj,
                                struct drm_file *file_priv);
+struct dma_buf *radeon_gem_prime_export(struct drm_device *dev,
+                                       struct drm_gem_object *gobj,
+                                       int flags);
 extern int radeon_get_crtc_scanoutpos(struct drm_device *dev, int crtc,
                                      unsigned int flags,
                                      int *vpos, int *hpos, ktime_t *stime,
@@ -130,7 +135,7 @@ int radeon_mode_dumb_create(struct drm_file *file_priv,
                            struct drm_mode_create_dumb *args);
 struct sg_table *radeon_gem_prime_get_sg_table(struct drm_gem_object *obj);
 struct drm_gem_object *radeon_gem_prime_import_sg_table(struct drm_device *dev,
-                                                       size_t size,
+                                                       struct dma_buf_attachment *,
                                                        struct sg_table *sg);
 int radeon_gem_prime_pin(struct drm_gem_object *obj);
 void radeon_gem_prime_unpin(struct drm_gem_object *obj);
@@ -309,7 +314,7 @@ static const struct file_operations radeon_driver_old_fops = {
        .open = drm_open,
        .release = drm_release,
        .unlocked_ioctl = drm_ioctl,
-       .mmap = drm_mmap,
+       .mmap = drm_legacy_mmap,
        .poll = drm_poll,
        .read = drm_read,
 #ifdef CONFIG_COMPAT
@@ -329,6 +334,7 @@ static struct drm_driver driver_old = {
        .preclose = radeon_driver_preclose,
        .postclose = radeon_driver_postclose,
        .lastclose = radeon_driver_lastclose,
+       .set_busid = drm_pci_set_busid,
        .unload = radeon_driver_unload,
        .suspend = radeon_suspend,
        .resume = radeon_resume,
@@ -553,6 +559,7 @@ static struct drm_driver kms_driver = {
        .preclose = radeon_driver_preclose_kms,
        .postclose = radeon_driver_postclose_kms,
        .lastclose = radeon_driver_lastclose_kms,
+       .set_busid = drm_pci_set_busid,
        .unload = radeon_driver_unload_kms,
        .get_vblank_counter = radeon_get_vblank_counter_kms,
        .enable_vblank = radeon_enable_vblank_kms,
@@ -578,7 +585,7 @@ static struct drm_driver kms_driver = {
 
        .prime_handle_to_fd = drm_gem_prime_handle_to_fd,
        .prime_fd_to_handle = drm_gem_prime_fd_to_handle,
-       .gem_prime_export = drm_gem_prime_export,
+       .gem_prime_export = radeon_gem_prime_export,
        .gem_prime_import = drm_gem_prime_import,
        .gem_prime_pin = radeon_gem_prime_pin,
        .gem_prime_unpin = radeon_gem_prime_unpin,
index dafd812e45710b0ffed36c33f3e37de20ec64733..46bd3938282ca84a6a19338f476daee049575ce7 100644 (file)
@@ -33,7 +33,9 @@
 
 #include <linux/firmware.h>
 #include <linux/platform_device.h>
+#include <drm/drm_legacy.h>
 
+#include <drm/ati_pcigart.h>
 #include "radeon_family.h"
 
 /* General customization:
index 15edf23b465c2ba90cca2f2ffb7c242971bda2bf..9a19e52cc655bf8b3c697a7116e52e81b8060096 100644 (file)
@@ -410,3 +410,24 @@ bool radeon_dig_monitor_is_duallink(struct drm_encoder *encoder,
        }
 }
 
+bool radeon_encoder_is_digital(struct drm_encoder *encoder)
+{
+       struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
+       switch (radeon_encoder->encoder_id) {
+       case ENCODER_OBJECT_ID_INTERNAL_LVDS:
+       case ENCODER_OBJECT_ID_INTERNAL_TMDS1:
+       case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1:
+       case ENCODER_OBJECT_ID_INTERNAL_LVTM1:
+       case ENCODER_OBJECT_ID_INTERNAL_DVO1:
+       case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1:
+       case ENCODER_OBJECT_ID_INTERNAL_DDI:
+       case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
+       case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA:
+       case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
+       case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
+       case ENCODER_OBJECT_ID_INTERNAL_UNIPHY3:
+               return true;
+       default:
+               return false;
+       }
+}
index 94b0f2aa3d7c870b41bdf28be5d7bca5fecf4ff2..0ea1db83d57390e70874f3182893b277b56c6f94 100644 (file)
@@ -189,7 +189,8 @@ out_unref:
 static int radeonfb_create(struct drm_fb_helper *helper,
                           struct drm_fb_helper_surface_size *sizes)
 {
-       struct radeon_fbdev *rfbdev = (struct radeon_fbdev *)helper;
+       struct radeon_fbdev *rfbdev =
+               container_of(helper, struct radeon_fbdev, helper);
        struct radeon_device *rdev = rfbdev->rdev;
        struct fb_info *info;
        struct drm_framebuffer *fb = NULL;
index 913787085dfadf56cfd21ed5b771c072c78cd072..995167025282a13ff7fdbbe7a1555f0d228a751b 100644 (file)
@@ -97,6 +97,25 @@ static u32 radeon_fence_read(struct radeon_device *rdev, int ring)
        return seq;
 }
 
+/**
+ * radeon_fence_schedule_check - schedule lockup check
+ *
+ * @rdev: radeon_device pointer
+ * @ring: ring index we should work with
+ *
+ * Queues a delayed work item to check for lockups.
+ */
+static void radeon_fence_schedule_check(struct radeon_device *rdev, int ring)
+{
+       /*
+        * Do not reset the timer here with mod_delayed_work,
+        * this can livelock in an interaction with TTM delayed destroy.
+        */
+       queue_delayed_work(system_power_efficient_wq,
+                          &rdev->fence_drv[ring].lockup_work,
+                          RADEON_FENCE_JIFFIES_TIMEOUT);
+}
+
 /**
  * radeon_fence_emit - emit a fence on the requested ring
  *
@@ -111,30 +130,70 @@ int radeon_fence_emit(struct radeon_device *rdev,
                      struct radeon_fence **fence,
                      int ring)
 {
+       u64 seq = ++rdev->fence_drv[ring].sync_seq[ring];
+
        /* we are protected by the ring emission mutex */
        *fence = kmalloc(sizeof(struct radeon_fence), GFP_KERNEL);
        if ((*fence) == NULL) {
                return -ENOMEM;
        }
-       kref_init(&((*fence)->kref));
        (*fence)->rdev = rdev;
-       (*fence)->seq = ++rdev->fence_drv[ring].sync_seq[ring];
+       (*fence)->seq = seq;
        (*fence)->ring = ring;
+       fence_init(&(*fence)->base, &radeon_fence_ops,
+                  &rdev->fence_queue.lock, rdev->fence_context + ring, seq);
        radeon_fence_ring_emit(rdev, ring, *fence);
        trace_radeon_fence_emit(rdev->ddev, ring, (*fence)->seq);
+       radeon_fence_schedule_check(rdev, ring);
        return 0;
 }
 
 /**
- * radeon_fence_process - process a fence
+ * radeon_fence_check_signaled - callback from fence_queue
+ *
+ * this function is called with fence_queue lock held, which is also used
+ * for the fence locking itself, so unlocked variants are used for
+ * fence_signal, and remove_wait_queue.
+ */
+static int radeon_fence_check_signaled(wait_queue_t *wait, unsigned mode, int flags, void *key)
+{
+       struct radeon_fence *fence;
+       u64 seq;
+
+       fence = container_of(wait, struct radeon_fence, fence_wake);
+
+       /*
+        * We cannot use radeon_fence_process here because we're already
+        * in the waitqueue, in a call from wake_up_all.
+        */
+       seq = atomic64_read(&fence->rdev->fence_drv[fence->ring].last_seq);
+       if (seq >= fence->seq) {
+               int ret = fence_signal_locked(&fence->base);
+
+               if (!ret)
+                       FENCE_TRACE(&fence->base, "signaled from irq context\n");
+               else
+                       FENCE_TRACE(&fence->base, "was already signaled\n");
+
+               radeon_irq_kms_sw_irq_put(fence->rdev, fence->ring);
+               __remove_wait_queue(&fence->rdev->fence_queue, &fence->fence_wake);
+               fence_put(&fence->base);
+       } else
+               FENCE_TRACE(&fence->base, "pending\n");
+       return 0;
+}
+
+/**
+ * radeon_fence_activity - check for fence activity
  *
  * @rdev: radeon_device pointer
  * @ring: ring index the fence is associated with
  *
- * Checks the current fence value and wakes the fence queue
- * if the sequence number has increased (all asics).
+ * Checks the current fence value and calculates the last
+ * signalled fence value. Returns true if activity occured
+ * on the ring, and the fence_queue should be waken up.
  */
-void radeon_fence_process(struct radeon_device *rdev, int ring)
+static bool radeon_fence_activity(struct radeon_device *rdev, int ring)
 {
        uint64_t seq, last_seq, last_emitted;
        unsigned count_loop = 0;
@@ -190,23 +249,77 @@ void radeon_fence_process(struct radeon_device *rdev, int ring)
                }
        } while (atomic64_xchg(&rdev->fence_drv[ring].last_seq, seq) > seq);
 
-       if (wake)
-               wake_up_all(&rdev->fence_queue);
+       if (seq < last_emitted)
+               radeon_fence_schedule_check(rdev, ring);
+
+       return wake;
 }
 
 /**
- * radeon_fence_destroy - destroy a fence
+ * radeon_fence_check_lockup - check for hardware lockup
  *
- * @kref: fence kref
+ * @work: delayed work item
  *
- * Frees the fence object (all asics).
+ * Checks for fence activity and if there is none probe
+ * the hardware if a lockup occured.
  */
-static void radeon_fence_destroy(struct kref *kref)
+static void radeon_fence_check_lockup(struct work_struct *work)
 {
-       struct radeon_fence *fence;
+       struct radeon_fence_driver *fence_drv;
+       struct radeon_device *rdev;
+       int ring;
+
+       fence_drv = container_of(work, struct radeon_fence_driver,
+                                lockup_work.work);
+       rdev = fence_drv->rdev;
+       ring = fence_drv - &rdev->fence_drv[0];
+
+       if (!down_read_trylock(&rdev->exclusive_lock)) {
+               /* just reschedule the check if a reset is going on */
+               radeon_fence_schedule_check(rdev, ring);
+               return;
+       }
+
+       if (fence_drv->delayed_irq && rdev->ddev->irq_enabled) {
+               unsigned long irqflags;
+
+               fence_drv->delayed_irq = false;
+               spin_lock_irqsave(&rdev->irq.lock, irqflags);
+               radeon_irq_set(rdev);
+               spin_unlock_irqrestore(&rdev->irq.lock, irqflags);
+       }
+
+       if (radeon_fence_activity(rdev, ring))
+               wake_up_all(&rdev->fence_queue);
 
-       fence = container_of(kref, struct radeon_fence, kref);
-       kfree(fence);
+       else if (radeon_ring_is_lockup(rdev, ring, &rdev->ring[ring])) {
+
+               /* good news we believe it's a lockup */
+               dev_warn(rdev->dev, "GPU lockup (current fence id "
+                        "0x%016llx last fence id 0x%016llx on ring %d)\n",
+                        (uint64_t)atomic64_read(&fence_drv->last_seq),
+                        fence_drv->sync_seq[ring], ring);
+
+               /* remember that we need an reset */
+               rdev->needs_reset = true;
+               wake_up_all(&rdev->fence_queue);
+       }
+       up_read(&rdev->exclusive_lock);
+}
+
+/**
+ * radeon_fence_process - process a fence
+ *
+ * @rdev: radeon_device pointer
+ * @ring: ring index the fence is associated with
+ *
+ * Checks the current fence value and wakes the fence queue
+ * if the sequence number has increased (all asics).
+ */
+void radeon_fence_process(struct radeon_device *rdev, int ring)
+{
+       if (radeon_fence_activity(rdev, ring))
+               wake_up_all(&rdev->fence_queue);
 }
 
 /**
@@ -237,6 +350,75 @@ static bool radeon_fence_seq_signaled(struct radeon_device *rdev,
        return false;
 }
 
+static bool radeon_fence_is_signaled(struct fence *f)
+{
+       struct radeon_fence *fence = to_radeon_fence(f);
+       struct radeon_device *rdev = fence->rdev;
+       unsigned ring = fence->ring;
+       u64 seq = fence->seq;
+
+       if (atomic64_read(&rdev->fence_drv[ring].last_seq) >= seq) {
+               return true;
+       }
+
+       if (down_read_trylock(&rdev->exclusive_lock)) {
+               radeon_fence_process(rdev, ring);
+               up_read(&rdev->exclusive_lock);
+
+               if (atomic64_read(&rdev->fence_drv[ring].last_seq) >= seq) {
+                       return true;
+               }
+       }
+       return false;
+}
+
+/**
+ * radeon_fence_enable_signaling - enable signalling on fence
+ * @fence: fence
+ *
+ * This function is called with fence_queue lock held, and adds a callback
+ * to fence_queue that checks if this fence is signaled, and if so it
+ * signals the fence and removes itself.
+ */
+static bool radeon_fence_enable_signaling(struct fence *f)
+{
+       struct radeon_fence *fence = to_radeon_fence(f);
+       struct radeon_device *rdev = fence->rdev;
+
+       if (atomic64_read(&rdev->fence_drv[fence->ring].last_seq) >= fence->seq)
+               return false;
+
+       if (down_read_trylock(&rdev->exclusive_lock)) {
+               radeon_irq_kms_sw_irq_get(rdev, fence->ring);
+
+               if (radeon_fence_activity(rdev, fence->ring))
+                       wake_up_all_locked(&rdev->fence_queue);
+
+               /* did fence get signaled after we enabled the sw irq? */
+               if (atomic64_read(&rdev->fence_drv[fence->ring].last_seq) >= fence->seq) {
+                       radeon_irq_kms_sw_irq_put(rdev, fence->ring);
+                       up_read(&rdev->exclusive_lock);
+                       return false;
+               }
+
+               up_read(&rdev->exclusive_lock);
+       } else {
+               /* we're probably in a lockup, lets not fiddle too much */
+               if (radeon_irq_kms_sw_irq_get_delayed(rdev, fence->ring))
+                       rdev->fence_drv[fence->ring].delayed_irq = true;
+               radeon_fence_schedule_check(rdev, fence->ring);
+       }
+
+       fence->fence_wake.flags = 0;
+       fence->fence_wake.private = NULL;
+       fence->fence_wake.func = radeon_fence_check_signaled;
+       __add_wait_queue(&rdev->fence_queue, &fence->fence_wake);
+       fence_get(f);
+
+       FENCE_TRACE(&fence->base, "armed on ring %i!\n", fence->ring);
+       return true;
+}
+
 /**
  * radeon_fence_signaled - check if a fence has signaled
  *
@@ -247,14 +429,15 @@ static bool radeon_fence_seq_signaled(struct radeon_device *rdev,
  */
 bool radeon_fence_signaled(struct radeon_fence *fence)
 {
-       if (!fence) {
+       if (!fence)
                return true;
-       }
-       if (fence->seq == RADEON_FENCE_SIGNALED_SEQ) {
-               return true;
-       }
+
        if (radeon_fence_seq_signaled(fence->rdev, fence->seq, fence->ring)) {
-               fence->seq = RADEON_FENCE_SIGNALED_SEQ;
+               int ret;
+
+               ret = fence_signal(&fence->base);
+               if (!ret)
+                       FENCE_TRACE(&fence->base, "signaled from radeon_fence_signaled\n");
                return true;
        }
        return false;
@@ -283,110 +466,70 @@ static bool radeon_fence_any_seq_signaled(struct radeon_device *rdev, u64 *seq)
 }
 
 /**
- * radeon_fence_wait_seq - wait for a specific sequence numbers
+ * radeon_fence_wait_seq_timeout - wait for a specific sequence numbers
  *
  * @rdev: radeon device pointer
  * @target_seq: sequence number(s) we want to wait for
  * @intr: use interruptable sleep
+ * @timeout: maximum time to wait, or MAX_SCHEDULE_TIMEOUT for infinite wait
  *
  * Wait for the requested sequence number(s) to be written by any ring
  * (all asics).  Sequnce number array is indexed by ring id.
  * @intr selects whether to use interruptable (true) or non-interruptable
  * (false) sleep when waiting for the sequence number.  Helper function
  * for radeon_fence_wait_*().
- * Returns 0 if the sequence number has passed, error for all other cases.
+ * Returns remaining time if the sequence number has passed, 0 when
+ * the wait timeout, or an error for all other cases.
  * -EDEADLK is returned when a GPU lockup has been detected.
  */
-static int radeon_fence_wait_seq(struct radeon_device *rdev, u64 *target_seq,
-                                bool intr)
+static long radeon_fence_wait_seq_timeout(struct radeon_device *rdev,
+                                         u64 *target_seq, bool intr,
+                                         long timeout)
 {
-       uint64_t last_seq[RADEON_NUM_RINGS];
-       bool signaled;
-       int i, r;
-
-       while (!radeon_fence_any_seq_signaled(rdev, target_seq)) {
+       long r;
+       int i;
 
-               /* Save current sequence values, used to check for GPU lockups */
-               for (i = 0; i < RADEON_NUM_RINGS; ++i) {
-                       if (!target_seq[i])
-                               continue;
+       if (radeon_fence_any_seq_signaled(rdev, target_seq))
+               return timeout;
 
-                       last_seq[i] = atomic64_read(&rdev->fence_drv[i].last_seq);
-                       trace_radeon_fence_wait_begin(rdev->ddev, i, target_seq[i]);
-                       radeon_irq_kms_sw_irq_get(rdev, i);
-               }
+       /* enable IRQs and tracing */
+       for (i = 0; i < RADEON_NUM_RINGS; ++i) {
+               if (!target_seq[i])
+                       continue;
 
-               if (intr) {
-                       r = wait_event_interruptible_timeout(rdev->fence_queue, (
-                               (signaled = radeon_fence_any_seq_signaled(rdev, target_seq))
-                                || rdev->needs_reset), RADEON_FENCE_JIFFIES_TIMEOUT);
-               } else {
-                       r = wait_event_timeout(rdev->fence_queue, (
-                               (signaled = radeon_fence_any_seq_signaled(rdev, target_seq))
-                                || rdev->needs_reset), RADEON_FENCE_JIFFIES_TIMEOUT);
-               }
+               trace_radeon_fence_wait_begin(rdev->ddev, i, target_seq[i]);
+               radeon_irq_kms_sw_irq_get(rdev, i);
+       }
 
-               for (i = 0; i < RADEON_NUM_RINGS; ++i) {
-                       if (!target_seq[i])
-                               continue;
+       if (intr) {
+               r = wait_event_interruptible_timeout(rdev->fence_queue, (
+                       radeon_fence_any_seq_signaled(rdev, target_seq)
+                        || rdev->needs_reset), timeout);
+       } else {
+               r = wait_event_timeout(rdev->fence_queue, (
+                       radeon_fence_any_seq_signaled(rdev, target_seq)
+                        || rdev->needs_reset), timeout);
+       }
 
-                       radeon_irq_kms_sw_irq_put(rdev, i);
-                       trace_radeon_fence_wait_end(rdev->ddev, i, target_seq[i]);
-               }
+       if (rdev->needs_reset)
+               r = -EDEADLK;
 
-               if (unlikely(r < 0))
-                       return r;
+       for (i = 0; i < RADEON_NUM_RINGS; ++i) {
+               if (!target_seq[i])
+                       continue;
 
-               if (unlikely(!signaled)) {
-                       if (rdev->needs_reset)
-                               return -EDEADLK;
-
-                       /* we were interrupted for some reason and fence
-                        * isn't signaled yet, resume waiting */
-                       if (r)
-                               continue;
-
-                       for (i = 0; i < RADEON_NUM_RINGS; ++i) {
-                               if (!target_seq[i])
-                                       continue;
-
-                               if (last_seq[i] != atomic64_read(&rdev->fence_drv[i].last_seq))
-                                       break;
-                       }
-
-                       if (i != RADEON_NUM_RINGS)
-                               continue;
-
-                       for (i = 0; i < RADEON_NUM_RINGS; ++i) {
-                               if (!target_seq[i])
-                                       continue;
-
-                               if (radeon_ring_is_lockup(rdev, i, &rdev->ring[i]))
-                                       break;
-                       }
-
-                       if (i < RADEON_NUM_RINGS) {
-                               /* good news we believe it's a lockup */
-                               dev_warn(rdev->dev, "GPU lockup (waiting for "
-                                        "0x%016llx last fence id 0x%016llx on"
-                                        " ring %d)\n",
-                                        target_seq[i], last_seq[i], i);
-
-                               /* remember that we need an reset */
-                               rdev->needs_reset = true;
-                               wake_up_all(&rdev->fence_queue);
-                               return -EDEADLK;
-                       }
-               }
+               radeon_irq_kms_sw_irq_put(rdev, i);
+               trace_radeon_fence_wait_end(rdev->ddev, i, target_seq[i]);
        }
-       return 0;
+
+       return r;
 }
 
 /**
  * radeon_fence_wait - wait for a fence to signal
  *
  * @fence: radeon fence object
- * @intr: use interruptable sleep
+ * @intr: use interruptible sleep
  *
  * Wait for the requested fence to signal (all asics).
  * @intr selects whether to use interruptable (true) or non-interruptable
@@ -396,22 +539,26 @@ static int radeon_fence_wait_seq(struct radeon_device *rdev, u64 *target_seq,
 int radeon_fence_wait(struct radeon_fence *fence, bool intr)
 {
        uint64_t seq[RADEON_NUM_RINGS] = {};
-       int r;
+       long r;
 
-       if (fence == NULL) {
-               WARN(1, "Querying an invalid fence : %p !\n", fence);
-               return -EINVAL;
-       }
+       /*
+        * This function should not be called on !radeon fences.
+        * If this is the case, it would mean this function can
+        * also be called on radeon fences belonging to another card.
+        * exclusive_lock is not held in that case.
+        */
+       if (WARN_ON_ONCE(!to_radeon_fence(&fence->base)))
+               return fence_wait(&fence->base, intr);
 
        seq[fence->ring] = fence->seq;
-       if (seq[fence->ring] == RADEON_FENCE_SIGNALED_SEQ)
-               return 0;
-
-       r = radeon_fence_wait_seq(fence->rdev, seq, intr);
-       if (r)
+       r = radeon_fence_wait_seq_timeout(fence->rdev, seq, intr, MAX_SCHEDULE_TIMEOUT);
+       if (r < 0) {
                return r;
+       }
 
-       fence->seq = RADEON_FENCE_SIGNALED_SEQ;
+       r = fence_signal(&fence->base);
+       if (!r)
+               FENCE_TRACE(&fence->base, "signaled from fence_wait\n");
        return 0;
 }
 
@@ -434,7 +581,7 @@ int radeon_fence_wait_any(struct radeon_device *rdev,
 {
        uint64_t seq[RADEON_NUM_RINGS];
        unsigned i, num_rings = 0;
-       int r;
+       long r;
 
        for (i = 0; i < RADEON_NUM_RINGS; ++i) {
                seq[i] = 0;
@@ -445,18 +592,14 @@ int radeon_fence_wait_any(struct radeon_device *rdev,
 
                seq[i] = fences[i]->seq;
                ++num_rings;
-
-               /* test if something was allready signaled */
-               if (seq[i] == RADEON_FENCE_SIGNALED_SEQ)
-                       return 0;
        }
 
        /* nothing to wait for ? */
        if (num_rings == 0)
                return -ENOENT;
 
-       r = radeon_fence_wait_seq(rdev, seq, intr);
-       if (r) {
+       r = radeon_fence_wait_seq_timeout(rdev, seq, intr, MAX_SCHEDULE_TIMEOUT);
+       if (r < 0) {
                return r;
        }
        return 0;
@@ -475,6 +618,7 @@ int radeon_fence_wait_any(struct radeon_device *rdev,
 int radeon_fence_wait_next(struct radeon_device *rdev, int ring)
 {
        uint64_t seq[RADEON_NUM_RINGS] = {};
+       long r;
 
        seq[ring] = atomic64_read(&rdev->fence_drv[ring].last_seq) + 1ULL;
        if (seq[ring] >= rdev->fence_drv[ring].sync_seq[ring]) {
@@ -482,7 +626,10 @@ int radeon_fence_wait_next(struct radeon_device *rdev, int ring)
                   already the last emited fence */
                return -ENOENT;
        }
-       return radeon_fence_wait_seq(rdev, seq, false);
+       r = radeon_fence_wait_seq_timeout(rdev, seq, false, MAX_SCHEDULE_TIMEOUT);
+       if (r < 0)
+               return r;
+       return 0;
 }
 
 /**
@@ -498,18 +645,18 @@ int radeon_fence_wait_next(struct radeon_device *rdev, int ring)
 int radeon_fence_wait_empty(struct radeon_device *rdev, int ring)
 {
        uint64_t seq[RADEON_NUM_RINGS] = {};
-       int r;
+       long r;
 
        seq[ring] = rdev->fence_drv[ring].sync_seq[ring];
        if (!seq[ring])
                return 0;
 
-       r = radeon_fence_wait_seq(rdev, seq, false);
-       if (r) {
+       r = radeon_fence_wait_seq_timeout(rdev, seq, false, MAX_SCHEDULE_TIMEOUT);
+       if (r < 0) {
                if (r == -EDEADLK)
                        return -EDEADLK;
 
-               dev_err(rdev->dev, "error waiting for ring[%d] to become idle (%d)\n",
+               dev_err(rdev->dev, "error waiting for ring[%d] to become idle (%ld)\n",
                        ring, r);
        }
        return 0;
@@ -525,7 +672,7 @@ int radeon_fence_wait_empty(struct radeon_device *rdev, int ring)
  */
 struct radeon_fence *radeon_fence_ref(struct radeon_fence *fence)
 {
-       kref_get(&fence->kref);
+       fence_get(&fence->base);
        return fence;
 }
 
@@ -542,7 +689,7 @@ void radeon_fence_unref(struct radeon_fence **fence)
 
        *fence = NULL;
        if (tmp) {
-               kref_put(&tmp->kref, radeon_fence_destroy);
+               fence_put(&tmp->base);
        }
 }
 
@@ -711,6 +858,9 @@ static void radeon_fence_driver_init_ring(struct radeon_device *rdev, int ring)
                rdev->fence_drv[ring].sync_seq[i] = 0;
        atomic64_set(&rdev->fence_drv[ring].last_seq, 0);
        rdev->fence_drv[ring].initialized = false;
+       INIT_DELAYED_WORK(&rdev->fence_drv[ring].lockup_work,
+                         radeon_fence_check_lockup);
+       rdev->fence_drv[ring].rdev = rdev;
 }
 
 /**
@@ -758,8 +908,9 @@ void radeon_fence_driver_fini(struct radeon_device *rdev)
                r = radeon_fence_wait_empty(rdev, ring);
                if (r) {
                        /* no need to trigger GPU reset as we are unloading */
-                       radeon_fence_driver_force_completion(rdev);
+                       radeon_fence_driver_force_completion(rdev, ring);
                }
+               cancel_delayed_work_sync(&rdev->fence_drv[ring].lockup_work);
                wake_up_all(&rdev->fence_queue);
                radeon_scratch_free(rdev, rdev->fence_drv[ring].scratch_reg);
                rdev->fence_drv[ring].initialized = false;
@@ -771,18 +922,16 @@ void radeon_fence_driver_fini(struct radeon_device *rdev)
  * radeon_fence_driver_force_completion - force all fence waiter to complete
  *
  * @rdev: radeon device pointer
+ * @ring: the ring to complete
  *
  * In case of GPU reset failure make sure no process keep waiting on fence
  * that will never complete.
  */
-void radeon_fence_driver_force_completion(struct radeon_device *rdev)
+void radeon_fence_driver_force_completion(struct radeon_device *rdev, int ring)
 {
-       int ring;
-
-       for (ring = 0; ring < RADEON_NUM_RINGS; ring++) {
-               if (!rdev->fence_drv[ring].initialized)
-                       continue;
+       if (rdev->fence_drv[ring].initialized) {
                radeon_fence_write(rdev, rdev->fence_drv[ring].sync_seq[ring], ring);
+               cancel_delayed_work_sync(&rdev->fence_drv[ring].lockup_work);
        }
 }
 
@@ -833,6 +982,7 @@ static int radeon_debugfs_gpu_reset(struct seq_file *m, void *data)
        down_read(&rdev->exclusive_lock);
        seq_printf(m, "%d\n", rdev->needs_reset);
        rdev->needs_reset = true;
+       wake_up_all(&rdev->fence_queue);
        up_read(&rdev->exclusive_lock);
 
        return 0;
@@ -852,3 +1002,72 @@ int radeon_debugfs_fence_init(struct radeon_device *rdev)
        return 0;
 #endif
 }
+
+static const char *radeon_fence_get_driver_name(struct fence *fence)
+{
+       return "radeon";
+}
+
+static const char *radeon_fence_get_timeline_name(struct fence *f)
+{
+       struct radeon_fence *fence = to_radeon_fence(f);
+       switch (fence->ring) {
+       case RADEON_RING_TYPE_GFX_INDEX: return "radeon.gfx";
+       case CAYMAN_RING_TYPE_CP1_INDEX: return "radeon.cp1";
+       case CAYMAN_RING_TYPE_CP2_INDEX: return "radeon.cp2";
+       case R600_RING_TYPE_DMA_INDEX: return "radeon.dma";
+       case CAYMAN_RING_TYPE_DMA1_INDEX: return "radeon.dma1";
+       case R600_RING_TYPE_UVD_INDEX: return "radeon.uvd";
+       case TN_RING_TYPE_VCE1_INDEX: return "radeon.vce1";
+       case TN_RING_TYPE_VCE2_INDEX: return "radeon.vce2";
+       default: WARN_ON_ONCE(1); return "radeon.unk";
+       }
+}
+
+static inline bool radeon_test_signaled(struct radeon_fence *fence)
+{
+       return test_bit(FENCE_FLAG_SIGNALED_BIT, &fence->base.flags);
+}
+
+static signed long radeon_fence_default_wait(struct fence *f, bool intr,
+                                            signed long t)
+{
+       struct radeon_fence *fence = to_radeon_fence(f);
+       struct radeon_device *rdev = fence->rdev;
+       bool signaled;
+
+       fence_enable_sw_signaling(&fence->base);
+
+       /*
+        * This function has to return -EDEADLK, but cannot hold
+        * exclusive_lock during the wait because some callers
+        * may already hold it. This means checking needs_reset without
+        * lock, and not fiddling with any gpu internals.
+        *
+        * The callback installed with fence_enable_sw_signaling will
+        * run before our wait_event_*timeout call, so we will see
+        * both the signaled fence and the changes to needs_reset.
+        */
+
+       if (intr)
+               t = wait_event_interruptible_timeout(rdev->fence_queue,
+                       ((signaled = radeon_test_signaled(fence)) ||
+                        rdev->needs_reset), t);
+       else
+               t = wait_event_timeout(rdev->fence_queue,
+                       ((signaled = radeon_test_signaled(fence)) ||
+                        rdev->needs_reset), t);
+
+       if (t > 0 && !signaled)
+               return -EDEADLK;
+       return t;
+}
+
+const struct fence_ops radeon_fence_ops = {
+       .get_driver_name = radeon_fence_get_driver_name,
+       .get_timeline_name = radeon_fence_get_timeline_name,
+       .enable_signaling = radeon_fence_enable_signaling,
+       .signaled = radeon_fence_is_signaled,
+       .wait = radeon_fence_default_wait,
+       .release = NULL,
+};
index a053a0779aac35e907ab4e52ed8c71746a0c30c9..84146d5901aa5aacad168255c14d72cafce5cf15 100644 (file)
@@ -128,7 +128,7 @@ int radeon_gart_table_vram_alloc(struct radeon_device *rdev)
        if (rdev->gart.robj == NULL) {
                r = radeon_bo_create(rdev, rdev->gart.table_size,
                                     PAGE_SIZE, true, RADEON_GEM_DOMAIN_VRAM,
-                                    0, NULL, &rdev->gart.robj);
+                                    0, NULL, NULL, &rdev->gart.robj);
                if (r) {
                        return r;
                }
index bfd7e1b0ff3f88b19a6e2d4ec636c3c8dd9c95a4..c194497aa586e16c5c17776d5baa5959f3eac7c5 100644 (file)
@@ -67,7 +67,7 @@ int radeon_gem_object_create(struct radeon_device *rdev, unsigned long size,
 
 retry:
        r = radeon_bo_create(rdev, size, alignment, kernel, initial_domain,
-                            flags, NULL, &robj);
+                            flags, NULL, NULL, &robj);
        if (r) {
                if (r != -ERESTARTSYS) {
                        if (initial_domain == RADEON_GEM_DOMAIN_VRAM) {
@@ -94,7 +94,7 @@ static int radeon_gem_set_domain(struct drm_gem_object *gobj,
 {
        struct radeon_bo *robj;
        uint32_t domain;
-       int r;
+       long r;
 
        /* FIXME: reeimplement */
        robj = gem_to_radeon_bo(gobj);
@@ -110,9 +110,12 @@ static int radeon_gem_set_domain(struct drm_gem_object *gobj,
        }
        if (domain == RADEON_GEM_DOMAIN_CPU) {
                /* Asking for cpu access wait for object idle */
-               r = radeon_bo_wait(robj, NULL, false);
-               if (r) {
-                       printk(KERN_ERR "Failed to wait for object !\n");
+               r = reservation_object_wait_timeout_rcu(robj->tbo.resv, true, true, 30 * HZ);
+               if (!r)
+                       r = -EBUSY;
+
+               if (r < 0 && r != -EINTR) {
+                       printk(KERN_ERR "Failed to wait for object: %li\n", r);
                        return r;
                }
        }
@@ -272,6 +275,94 @@ int radeon_gem_create_ioctl(struct drm_device *dev, void *data,
        return 0;
 }
 
+int radeon_gem_userptr_ioctl(struct drm_device *dev, void *data,
+                            struct drm_file *filp)
+{
+       struct radeon_device *rdev = dev->dev_private;
+       struct drm_radeon_gem_userptr *args = data;
+       struct drm_gem_object *gobj;
+       struct radeon_bo *bo;
+       uint32_t handle;
+       int r;
+
+       if (offset_in_page(args->addr | args->size))
+               return -EINVAL;
+
+       /* reject unknown flag values */
+       if (args->flags & ~(RADEON_GEM_USERPTR_READONLY |
+           RADEON_GEM_USERPTR_ANONONLY | RADEON_GEM_USERPTR_VALIDATE |
+           RADEON_GEM_USERPTR_REGISTER))
+               return -EINVAL;
+
+       if (args->flags & RADEON_GEM_USERPTR_READONLY) {
+               /* readonly pages not tested on older hardware */
+               if (rdev->family < CHIP_R600)
+                       return -EINVAL;
+
+       } else if (!(args->flags & RADEON_GEM_USERPTR_ANONONLY) ||
+                  !(args->flags & RADEON_GEM_USERPTR_REGISTER)) {
+
+               /* if we want to write to it we must require anonymous
+                  memory and install a MMU notifier */
+               return -EACCES;
+       }
+
+       down_read(&rdev->exclusive_lock);
+
+       /* create a gem object to contain this object in */
+       r = radeon_gem_object_create(rdev, args->size, 0,
+                                    RADEON_GEM_DOMAIN_CPU, 0,
+                                    false, &gobj);
+       if (r)
+               goto handle_lockup;
+
+       bo = gem_to_radeon_bo(gobj);
+       r = radeon_ttm_tt_set_userptr(bo->tbo.ttm, args->addr, args->flags);
+       if (r)
+               goto release_object;
+
+       if (args->flags & RADEON_GEM_USERPTR_REGISTER) {
+               r = radeon_mn_register(bo, args->addr);
+               if (r)
+                       goto release_object;
+       }
+
+       if (args->flags & RADEON_GEM_USERPTR_VALIDATE) {
+               down_read(&current->mm->mmap_sem);
+               r = radeon_bo_reserve(bo, true);
+               if (r) {
+                       up_read(&current->mm->mmap_sem);
+                       goto release_object;
+               }
+
+               radeon_ttm_placement_from_domain(bo, RADEON_GEM_DOMAIN_GTT);
+               r = ttm_bo_validate(&bo->tbo, &bo->placement, true, false);
+               radeon_bo_unreserve(bo);
+               up_read(&current->mm->mmap_sem);
+               if (r)
+                       goto release_object;
+       }
+
+       r = drm_gem_handle_create(filp, gobj, &handle);
+       /* drop reference from allocate - handle holds it now */
+       drm_gem_object_unreference_unlocked(gobj);
+       if (r)
+               goto handle_lockup;
+
+       args->handle = handle;
+       up_read(&rdev->exclusive_lock);
+       return 0;
+
+release_object:
+       drm_gem_object_unreference_unlocked(gobj);
+
+handle_lockup:
+       up_read(&rdev->exclusive_lock);
+       r = radeon_gem_handle_lockup(rdev, r);
+
+       return r;
+}
+
 int radeon_gem_set_domain_ioctl(struct drm_device *dev, void *data,
                                struct drm_file *filp)
 {
@@ -315,6 +406,10 @@ int radeon_mode_dumb_mmap(struct drm_file *filp,
                return -ENOENT;
        }
        robj = gem_to_radeon_bo(gobj);
+       if (radeon_ttm_tt_has_userptr(robj->tbo.ttm)) {
+               drm_gem_object_unreference_unlocked(gobj);
+               return -EPERM;
+       }
        *offset_p = radeon_bo_mmap_offset(robj);
        drm_gem_object_unreference_unlocked(gobj);
        return 0;
@@ -357,15 +452,22 @@ int radeon_gem_wait_idle_ioctl(struct drm_device *dev, void *data,
        struct drm_radeon_gem_wait_idle *args = data;
        struct drm_gem_object *gobj;
        struct radeon_bo *robj;
-       int r;
+       int r = 0;
        uint32_t cur_placement = 0;
+       long ret;
 
        gobj = drm_gem_object_lookup(dev, filp, args->handle);
        if (gobj == NULL) {
                return -ENOENT;
        }
        robj = gem_to_radeon_bo(gobj);
-       r = radeon_bo_wait(robj, &cur_placement, false);
+
+       ret = reservation_object_wait_timeout_rcu(robj->tbo.resv, true, true, 30 * HZ);
+       if (ret == 0)
+               r = -EBUSY;
+       else if (ret < 0)
+               r = ret;
+
        /* Flush HDP cache via MMIO if necessary */
        if (rdev->asic->mmio_hdp_flush &&
            radeon_mem_type_to_domain(cur_placement) == RADEON_GEM_DOMAIN_VRAM)
@@ -532,6 +634,11 @@ int radeon_gem_op_ioctl(struct drm_device *dev, void *data,
                return -ENOENT;
        }
        robj = gem_to_radeon_bo(gobj);
+
+       r = -EPERM;
+       if (radeon_ttm_tt_has_userptr(robj->tbo.ttm))
+               goto out;
+
        r = radeon_bo_reserve(robj, false);
        if (unlikely(r))
                goto out;
index 5bf2c0a05827f57b459ca1be85e268af0bbf32ce..3f39fcca4d0744ec666630be4e3672ada57cba08 100644 (file)
@@ -145,7 +145,7 @@ int radeon_ib_schedule(struct radeon_device *rdev, struct radeon_ib *ib,
        if (ib->vm) {
                struct radeon_fence *vm_id_fence;
                vm_id_fence = radeon_vm_grab_id(rdev, ib->vm, ib->ring);
-               radeon_semaphore_sync_to(ib->semaphore, vm_id_fence);
+               radeon_semaphore_sync_fence(ib->semaphore, vm_id_fence);
        }
 
        /* sync with other rings */
@@ -269,6 +269,7 @@ int radeon_ib_ring_tests(struct radeon_device *rdev)
 
                r = radeon_ib_test(rdev, i, ring);
                if (r) {
+                       radeon_fence_driver_force_completion(rdev, i);
                        ring->ready = false;
                        rdev->needs_reset = false;
 
index 16807afab362509f8432bf4a021d3954e747c301..7784911d78ef6fc54d6aeea23950f4585d3c74c4 100644 (file)
@@ -87,23 +87,6 @@ static void radeon_hotplug_work_func(struct work_struct *work)
        drm_helper_hpd_irq_event(dev);
 }
 
-/**
- * radeon_irq_reset_work_func - execute gpu reset
- *
- * @work: work struct
- *
- * Execute scheduled gpu reset (cayman+).
- * This function is called when the irq handler
- * thinks we need a gpu reset.
- */
-static void radeon_irq_reset_work_func(struct work_struct *work)
-{
-       struct radeon_device *rdev = container_of(work, struct radeon_device,
-                                                 reset_work);
-
-       radeon_gpu_reset(rdev);
-}
-
 /**
  * radeon_driver_irq_preinstall_kms - drm irq preinstall callback
  *
@@ -284,7 +267,6 @@ int radeon_irq_kms_init(struct radeon_device *rdev)
 
        INIT_WORK(&rdev->hotplug_work, radeon_hotplug_work_func);
        INIT_WORK(&rdev->audio_work, r600_audio_update_hdmi);
-       INIT_WORK(&rdev->reset_work, radeon_irq_reset_work_func);
 
        rdev->irq.installed = true;
        r = drm_irq_install(rdev->ddev, rdev->ddev->pdev->irq);
@@ -341,6 +323,21 @@ void radeon_irq_kms_sw_irq_get(struct radeon_device *rdev, int ring)
        }
 }
 
+/**
+ * radeon_irq_kms_sw_irq_get_delayed - enable software interrupt
+ *
+ * @rdev: radeon device pointer
+ * @ring: ring whose interrupt you want to enable
+ *
+ * Enables the software interrupt for a specific ring (all asics).
+ * The software interrupt is generally used to signal a fence on
+ * a particular ring.
+ */
+bool radeon_irq_kms_sw_irq_get_delayed(struct radeon_device *rdev, int ring)
+{
+       return atomic_inc_return(&rdev->irq.ring_int[ring]) == 1;
+}
+
 /**
  * radeon_irq_kms_sw_irq_put - disable software interrupt
  *
index eb7164d07985668a7c698a44d4d2e9e29668dfb8..8309b11e674d8506bfeb3f05530407ede4b60642 100644 (file)
@@ -885,5 +885,6 @@ const struct drm_ioctl_desc radeon_ioctls_kms[] = {
        DRM_IOCTL_DEF_DRV(RADEON_GEM_BUSY, radeon_gem_busy_ioctl, DRM_AUTH|DRM_UNLOCKED|DRM_RENDER_ALLOW),
        DRM_IOCTL_DEF_DRV(RADEON_GEM_VA, radeon_gem_va_ioctl, DRM_AUTH|DRM_UNLOCKED|DRM_RENDER_ALLOW),
        DRM_IOCTL_DEF_DRV(RADEON_GEM_OP, radeon_gem_op_ioctl, DRM_AUTH|DRM_UNLOCKED|DRM_RENDER_ALLOW),
+       DRM_IOCTL_DEF_DRV(RADEON_GEM_USERPTR, radeon_gem_userptr_ioctl, DRM_AUTH|DRM_UNLOCKED|DRM_RENDER_ALLOW),
 };
 int radeon_max_kms_ioctl = ARRAY_SIZE(radeon_ioctls_kms);
diff --git a/drivers/gpu/drm/radeon/radeon_mn.c b/drivers/gpu/drm/radeon/radeon_mn.c
new file mode 100644 (file)
index 0000000..a69bd44
--- /dev/null
@@ -0,0 +1,274 @@
+/*
+ * Copyright 2014 Advanced Micro Devices, Inc.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * THE 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 NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS 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.
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ */
+/*
+ * Authors:
+ *    Christian König <christian.koenig@amd.com>
+ */
+
+#include <linux/firmware.h>
+#include <linux/module.h>
+#include <linux/mmu_notifier.h>
+#include <drm/drmP.h>
+#include <drm/drm.h>
+
+#include "radeon.h"
+
+struct radeon_mn {
+       /* constant after initialisation */
+       struct radeon_device    *rdev;
+       struct mm_struct        *mm;
+       struct mmu_notifier     mn;
+
+       /* only used on destruction */
+       struct work_struct      work;
+
+       /* protected by rdev->mn_lock */
+       struct hlist_node       node;
+
+       /* objects protected by lock */
+       struct mutex            lock;
+       struct rb_root          objects;
+};
+
+/**
+ * radeon_mn_destroy - destroy the rmn
+ *
+ * @work: previously sheduled work item
+ *
+ * Lazy destroys the notifier from a work item
+ */
+static void radeon_mn_destroy(struct work_struct *work)
+{
+       struct radeon_mn *rmn = container_of(work, struct radeon_mn, work);
+       struct radeon_device *rdev = rmn->rdev;
+       struct radeon_bo *bo, *next;
+
+       mutex_lock(&rdev->mn_lock);
+       mutex_lock(&rmn->lock);
+       hash_del(&rmn->node);
+       rbtree_postorder_for_each_entry_safe(bo, next, &rmn->objects, mn_it.rb) {
+               interval_tree_remove(&bo->mn_it, &rmn->objects);
+               bo->mn = NULL;
+       }
+       mutex_unlock(&rmn->lock);
+       mutex_unlock(&rdev->mn_lock);
+       mmu_notifier_unregister(&rmn->mn, rmn->mm);
+       kfree(rmn);
+}
+
+/**
+ * radeon_mn_release - callback to notify about mm destruction
+ *
+ * @mn: our notifier
+ * @mn: the mm this callback is about
+ *
+ * Shedule a work item to lazy destroy our notifier.
+ */
+static void radeon_mn_release(struct mmu_notifier *mn,
+                             struct mm_struct *mm)
+{
+       struct radeon_mn *rmn = container_of(mn, struct radeon_mn, mn);
+       INIT_WORK(&rmn->work, radeon_mn_destroy);
+       schedule_work(&rmn->work);
+}
+
+/**
+ * radeon_mn_invalidate_range_start - callback to notify about mm change
+ *
+ * @mn: our notifier
+ * @mn: the mm this callback is about
+ * @start: start of updated range
+ * @end: end of updated range
+ *
+ * We block for all BOs between start and end to be idle and
+ * unmap them by move them into system domain again.
+ */
+static void radeon_mn_invalidate_range_start(struct mmu_notifier *mn,
+                                            struct mm_struct *mm,
+                                            unsigned long start,
+                                            unsigned long end)
+{
+       struct radeon_mn *rmn = container_of(mn, struct radeon_mn, mn);
+       struct interval_tree_node *it;
+
+       /* notification is exclusive, but interval is inclusive */
+       end -= 1;
+
+       mutex_lock(&rmn->lock);
+
+       it = interval_tree_iter_first(&rmn->objects, start, end);
+       while (it) {
+               struct radeon_bo *bo;
+               struct fence *fence;
+               int r;
+
+               bo = container_of(it, struct radeon_bo, mn_it);
+               it = interval_tree_iter_next(it, start, end);
+
+               r = radeon_bo_reserve(bo, true);
+               if (r) {
+                       DRM_ERROR("(%d) failed to reserve user bo\n", r);
+                       continue;
+               }
+
+               fence = reservation_object_get_excl(bo->tbo.resv);
+               if (fence) {
+                       r = radeon_fence_wait((struct radeon_fence *)fence, false);
+                       if (r)
+                               DRM_ERROR("(%d) failed to wait for user bo\n", r);
+               }
+
+               radeon_ttm_placement_from_domain(bo, RADEON_GEM_DOMAIN_CPU);
+               r = ttm_bo_validate(&bo->tbo, &bo->placement, false, false);
+               if (r)
+                       DRM_ERROR("(%d) failed to validate user bo\n", r);
+
+               radeon_bo_unreserve(bo);
+       }
+       
+       mutex_unlock(&rmn->lock);
+}
+
+static const struct mmu_notifier_ops radeon_mn_ops = {
+       .release = radeon_mn_release,
+       .invalidate_range_start = radeon_mn_invalidate_range_start,
+};
+
+/**
+ * radeon_mn_get - create notifier context
+ *
+ * @rdev: radeon device pointer
+ *
+ * Creates a notifier context for current->mm.
+ */
+static struct radeon_mn *radeon_mn_get(struct radeon_device *rdev)
+{
+       struct mm_struct *mm = current->mm;
+       struct radeon_mn *rmn;
+       int r;
+
+       down_write(&mm->mmap_sem);
+       mutex_lock(&rdev->mn_lock);
+
+       hash_for_each_possible(rdev->mn_hash, rmn, node, (unsigned long)mm)
+               if (rmn->mm == mm)
+                       goto release_locks;
+
+       rmn = kzalloc(sizeof(*rmn), GFP_KERNEL);
+       if (!rmn) {
+               rmn = ERR_PTR(-ENOMEM);
+               goto release_locks;
+       }
+
+       rmn->rdev = rdev;
+       rmn->mm = mm;
+       rmn->mn.ops = &radeon_mn_ops;
+       mutex_init(&rmn->lock);
+       rmn->objects = RB_ROOT;
+       
+       r = __mmu_notifier_register(&rmn->mn, mm);
+       if (r)
+               goto free_rmn;
+
+       hash_add(rdev->mn_hash, &rmn->node, (unsigned long)mm);
+
+release_locks:
+       mutex_unlock(&rdev->mn_lock);
+       up_write(&mm->mmap_sem);
+
+       return rmn;
+
+free_rmn:
+       mutex_unlock(&rdev->mn_lock);
+       up_write(&mm->mmap_sem);
+       kfree(rmn);
+
+       return ERR_PTR(r);
+}
+
+/**
+ * radeon_mn_register - register a BO for notifier updates
+ *
+ * @bo: radeon buffer object
+ * @addr: userptr addr we should monitor
+ *
+ * Registers an MMU notifier for the given BO at the specified address.
+ * Returns 0 on success, -ERRNO if anything goes wrong.
+ */
+int radeon_mn_register(struct radeon_bo *bo, unsigned long addr)
+{
+       unsigned long end = addr + radeon_bo_size(bo) - 1;
+       struct radeon_device *rdev = bo->rdev;
+       struct radeon_mn *rmn;
+       struct interval_tree_node *it;
+
+       rmn = radeon_mn_get(rdev);
+       if (IS_ERR(rmn))
+               return PTR_ERR(rmn);
+
+       mutex_lock(&rmn->lock);
+
+       it = interval_tree_iter_first(&rmn->objects, addr, end);
+       if (it) {
+               mutex_unlock(&rmn->lock);
+               return -EEXIST;
+       }
+
+       bo->mn = rmn;
+       bo->mn_it.start = addr;
+       bo->mn_it.last = end;
+       interval_tree_insert(&bo->mn_it, &rmn->objects);
+
+       mutex_unlock(&rmn->lock);
+
+       return 0;
+}
+
+/**
+ * radeon_mn_unregister - unregister a BO for notifier updates
+ *
+ * @bo: radeon buffer object
+ *
+ * Remove any registration of MMU notifier updates from the buffer object.
+ */
+void radeon_mn_unregister(struct radeon_bo *bo)
+{
+       struct radeon_device *rdev = bo->rdev;
+       struct radeon_mn *rmn;
+
+       mutex_lock(&rdev->mn_lock);
+       rmn = bo->mn;
+       if (rmn == NULL) {
+               mutex_unlock(&rdev->mn_lock);
+               return;
+       }
+
+       mutex_lock(&rmn->lock);
+       interval_tree_remove(&bo->mn_it, &rmn->objects);
+       bo->mn = NULL;
+       mutex_unlock(&rmn->lock);
+       mutex_unlock(&rdev->mn_lock);
+}
index e27608c29c112f5e8d164214ca7b56855ef15593..04db2fdd869271f81482e75913d6ec4002ffecac 100644 (file)
@@ -777,6 +777,7 @@ extern void atombios_digital_setup(struct drm_encoder *encoder, int action);
 extern int atombios_get_encoder_mode(struct drm_encoder *encoder);
 extern bool atombios_set_edp_panel_power(struct drm_connector *connector, int action);
 extern void radeon_encoder_set_active_device(struct drm_encoder *encoder);
+extern bool radeon_encoder_is_digital(struct drm_encoder *encoder);
 
 extern void radeon_crtc_load_lut(struct drm_crtc *crtc);
 extern int atombios_crtc_set_base(struct drm_crtc *crtc, int x, int y,
index 480c87d8edc50cc46aad4c612b1f6f4942d9a8a1..99a960a4f30265c893a411763843a260d38e6a41 100644 (file)
@@ -75,6 +75,7 @@ static void radeon_ttm_bo_destroy(struct ttm_buffer_object *tbo)
        bo = container_of(tbo, struct radeon_bo, tbo);
 
        radeon_update_memory_usage(bo, bo->tbo.mem.mem_type, -1);
+       radeon_mn_unregister(bo);
 
        mutex_lock(&bo->rdev->gem.mutex);
        list_del_init(&bo->list);
@@ -96,55 +97,80 @@ void radeon_ttm_placement_from_domain(struct radeon_bo *rbo, u32 domain)
 {
        u32 c = 0, i;
 
-       rbo->placement.fpfn = 0;
-       rbo->placement.lpfn = 0;
        rbo->placement.placement = rbo->placements;
        rbo->placement.busy_placement = rbo->placements;
        if (domain & RADEON_GEM_DOMAIN_VRAM)
-               rbo->placements[c++] = TTM_PL_FLAG_WC | TTM_PL_FLAG_UNCACHED |
-                                       TTM_PL_FLAG_VRAM;
+               rbo->placements[c++].flags = TTM_PL_FLAG_WC |
+                                            TTM_PL_FLAG_UNCACHED |
+                                            TTM_PL_FLAG_VRAM;
+
        if (domain & RADEON_GEM_DOMAIN_GTT) {
                if (rbo->flags & RADEON_GEM_GTT_UC) {
-                       rbo->placements[c++] = TTM_PL_FLAG_UNCACHED | TTM_PL_FLAG_TT;
+                       rbo->placements[c++].flags = TTM_PL_FLAG_UNCACHED |
+                               TTM_PL_FLAG_TT;
+
                } else if ((rbo->flags & RADEON_GEM_GTT_WC) ||
                           (rbo->rdev->flags & RADEON_IS_AGP)) {
-                       rbo->placements[c++] = TTM_PL_FLAG_WC | TTM_PL_FLAG_UNCACHED |
+                       rbo->placements[c++].flags = TTM_PL_FLAG_WC |
+                               TTM_PL_FLAG_UNCACHED |
                                TTM_PL_FLAG_TT;
                } else {
-                       rbo->placements[c++] = TTM_PL_FLAG_CACHED | TTM_PL_FLAG_TT;
+                       rbo->placements[c++].flags = TTM_PL_FLAG_CACHED |
+                                                    TTM_PL_FLAG_TT;
                }
        }
+
        if (domain & RADEON_GEM_DOMAIN_CPU) {
                if (rbo->flags & RADEON_GEM_GTT_UC) {
-                       rbo->placements[c++] = TTM_PL_FLAG_UNCACHED | TTM_PL_FLAG_SYSTEM;
+                       rbo->placements[c++].flags = TTM_PL_FLAG_UNCACHED |
+                               TTM_PL_FLAG_SYSTEM;
+
                } else if ((rbo->flags & RADEON_GEM_GTT_WC) ||
                    rbo->rdev->flags & RADEON_IS_AGP) {
-                       rbo->placements[c++] = TTM_PL_FLAG_WC | TTM_PL_FLAG_UNCACHED |
+                       rbo->placements[c++].flags = TTM_PL_FLAG_WC |
+                               TTM_PL_FLAG_UNCACHED |
                                TTM_PL_FLAG_SYSTEM;
                } else {
-                       rbo->placements[c++] = TTM_PL_FLAG_CACHED | TTM_PL_FLAG_SYSTEM;
+                       rbo->placements[c++].flags = TTM_PL_FLAG_CACHED |
+                                                    TTM_PL_FLAG_SYSTEM;
                }
        }
        if (!c)
-               rbo->placements[c++] = TTM_PL_MASK_CACHING | TTM_PL_FLAG_SYSTEM;
+               rbo->placements[c++].flags = TTM_PL_MASK_CACHING |
+                                            TTM_PL_FLAG_SYSTEM;
+
        rbo->placement.num_placement = c;
        rbo->placement.num_busy_placement = c;
 
+       for (i = 0; i < c; ++i) {
+               rbo->placements[i].fpfn = 0;
+               if ((rbo->flags & RADEON_GEM_CPU_ACCESS) &&
+                   (rbo->placements[i].flags & TTM_PL_FLAG_VRAM))
+                       rbo->placements[i].lpfn =
+                               rbo->rdev->mc.visible_vram_size >> PAGE_SHIFT;
+               else
+                       rbo->placements[i].lpfn = 0;
+       }
+
        /*
         * Use two-ended allocation depending on the buffer size to
         * improve fragmentation quality.
         * 512kb was measured as the most optimal number.
         */
-       if (rbo->tbo.mem.size > 512 * 1024) {
+       if (!((rbo->flags & RADEON_GEM_CPU_ACCESS) &&
+             (rbo->placements[i].flags & TTM_PL_FLAG_VRAM)) &&
+           rbo->tbo.mem.size > 512 * 1024) {
                for (i = 0; i < c; i++) {
-                       rbo->placements[i] |= TTM_PL_FLAG_TOPDOWN;
+                       rbo->placements[i].flags |= TTM_PL_FLAG_TOPDOWN;
                }
        }
 }
 
 int radeon_bo_create(struct radeon_device *rdev,
-                    unsigned long size, int byte_align, bool kernel, u32 domain,
-                    u32 flags, struct sg_table *sg, struct radeon_bo **bo_ptr)
+                    unsigned long size, int byte_align, bool kernel,
+                    u32 domain, u32 flags, struct sg_table *sg,
+                    struct reservation_object *resv,
+                    struct radeon_bo **bo_ptr)
 {
        struct radeon_bo *bo;
        enum ttm_bo_type type;
@@ -192,7 +218,7 @@ int radeon_bo_create(struct radeon_device *rdev,
        down_read(&rdev->pm.mclk_lock);
        r = ttm_bo_init(&rdev->mman.bdev, &bo->tbo, size, type,
                        &bo->placement, page_align, !kernel, NULL,
-                       acc_size, sg, &radeon_ttm_bo_destroy);
+                       acc_size, sg, resv, &radeon_ttm_bo_destroy);
        up_read(&rdev->pm.mclk_lock);
        if (unlikely(r != 0)) {
                return r;
@@ -264,6 +290,9 @@ int radeon_bo_pin_restricted(struct radeon_bo *bo, u32 domain, u64 max_offset,
 {
        int r, i;
 
+       if (radeon_ttm_tt_has_userptr(bo->tbo.ttm))
+               return -EPERM;
+
        if (bo->pin_count) {
                bo->pin_count++;
                if (gpu_addr)
@@ -283,21 +312,19 @@ int radeon_bo_pin_restricted(struct radeon_bo *bo, u32 domain, u64 max_offset,
                return 0;
        }
        radeon_ttm_placement_from_domain(bo, domain);
-       if (domain == RADEON_GEM_DOMAIN_VRAM) {
+       for (i = 0; i < bo->placement.num_placement; i++) {
                /* force to pin into visible video ram */
-               bo->placement.lpfn = bo->rdev->mc.visible_vram_size >> PAGE_SHIFT;
-       }
-       if (max_offset) {
-               u64 lpfn = max_offset >> PAGE_SHIFT;
-
-               if (!bo->placement.lpfn)
-                       bo->placement.lpfn = bo->rdev->mc.gtt_size >> PAGE_SHIFT;
+               if ((bo->placements[i].flags & TTM_PL_FLAG_VRAM) &&
+                   !(bo->flags & RADEON_GEM_NO_CPU_ACCESS) &&
+                   (!max_offset || max_offset > bo->rdev->mc.visible_vram_size))
+                       bo->placements[i].lpfn =
+                               bo->rdev->mc.visible_vram_size >> PAGE_SHIFT;
+               else
+                       bo->placements[i].lpfn = max_offset >> PAGE_SHIFT;
 
-               if (lpfn < bo->placement.lpfn)
-                       bo->placement.lpfn = lpfn;
+               bo->placements[i].flags |= TTM_PL_FLAG_NO_EVICT;
        }
-       for (i = 0; i < bo->placement.num_placement; i++)
-               bo->placements[i] |= TTM_PL_FLAG_NO_EVICT;
+
        r = ttm_bo_validate(&bo->tbo, &bo->placement, false, false);
        if (likely(r == 0)) {
                bo->pin_count = 1;
@@ -329,8 +356,10 @@ int radeon_bo_unpin(struct radeon_bo *bo)
        bo->pin_count--;
        if (bo->pin_count)
                return 0;
-       for (i = 0; i < bo->placement.num_placement; i++)
-               bo->placements[i] &= ~TTM_PL_FLAG_NO_EVICT;
+       for (i = 0; i < bo->placement.num_placement; i++) {
+               bo->placements[i].lpfn = 0;
+               bo->placements[i].flags &= ~TTM_PL_FLAG_NO_EVICT;
+       }
        r = ttm_bo_validate(&bo->tbo, &bo->placement, false, false);
        if (likely(r == 0)) {
                if (bo->tbo.mem.mem_type == TTM_PL_VRAM)
@@ -459,7 +488,7 @@ int radeon_bo_list_validate(struct radeon_device *rdev,
        u64 bytes_moved = 0, initial_bytes_moved;
        u64 bytes_moved_threshold = radeon_bo_get_threshold_for_moves(rdev);
 
-       r = ttm_eu_reserve_buffers(ticket, head);
+       r = ttm_eu_reserve_buffers(ticket, head, true);
        if (unlikely(r != 0)) {
                return r;
        }
@@ -468,6 +497,7 @@ int radeon_bo_list_validate(struct radeon_device *rdev,
                bo = lobj->robj;
                if (!bo->pin_count) {
                        u32 domain = lobj->prefered_domains;
+                       u32 allowed = lobj->allowed_domains;
                        u32 current_domain =
                                radeon_mem_type_to_domain(bo->tbo.mem.mem_type);
 
@@ -479,7 +509,7 @@ int radeon_bo_list_validate(struct radeon_device *rdev,
                         * into account. We don't want to disallow buffer moves
                         * completely.
                         */
-                       if ((lobj->allowed_domains & current_domain) != 0 &&
+                       if ((allowed & current_domain) != 0 &&
                            (domain & current_domain) == 0 && /* will be moved */
                            bytes_moved > bytes_moved_threshold) {
                                /* don't move it */
@@ -489,7 +519,7 @@ int radeon_bo_list_validate(struct radeon_device *rdev,
                retry:
                        radeon_ttm_placement_from_domain(bo, domain);
                        if (ring == R600_RING_TYPE_UVD_INDEX)
-                               radeon_uvd_force_into_uvd_segment(bo);
+                               radeon_uvd_force_into_uvd_segment(bo, allowed);
 
                        initial_bytes_moved = atomic64_read(&rdev->num_bytes_moved);
                        r = ttm_bo_validate(&bo->tbo, &bo->placement, true, false);
@@ -731,7 +761,7 @@ int radeon_bo_fault_reserve_notify(struct ttm_buffer_object *bo)
 
        /* hurrah the memory is not visible ! */
        radeon_ttm_placement_from_domain(rbo, RADEON_GEM_DOMAIN_VRAM);
-       rbo->placement.lpfn = rdev->mc.visible_vram_size >> PAGE_SHIFT;
+       rbo->placements[0].lpfn = rdev->mc.visible_vram_size >> PAGE_SHIFT;
        r = ttm_bo_validate(bo, &rbo->placement, false, false);
        if (unlikely(r == -ENOMEM)) {
                radeon_ttm_placement_from_domain(rbo, RADEON_GEM_DOMAIN_GTT);
@@ -755,12 +785,10 @@ int radeon_bo_wait(struct radeon_bo *bo, u32 *mem_type, bool no_wait)
        r = ttm_bo_reserve(&bo->tbo, true, no_wait, false, NULL);
        if (unlikely(r != 0))
                return r;
-       spin_lock(&bo->tbo.bdev->fence_lock);
        if (mem_type)
                *mem_type = bo->tbo.mem.mem_type;
-       if (bo->tbo.sync_obj)
-               r = ttm_bo_wait(&bo->tbo, true, true, no_wait);
-       spin_unlock(&bo->tbo.bdev->fence_lock);
+
+       r = ttm_bo_wait(&bo->tbo, true, true, no_wait);
        ttm_bo_unreserve(&bo->tbo);
        return r;
 }
index 98a47fdf362510284d21b864f1e5e565b5388604..1b8ec7917154809e10336fb346c6aacbafa72939 100644 (file)
@@ -126,6 +126,7 @@ extern int radeon_bo_create(struct radeon_device *rdev,
                            unsigned long size, int byte_align,
                            bool kernel, u32 domain, u32 flags,
                            struct sg_table *sg,
+                           struct reservation_object *resv,
                            struct radeon_bo **bo_ptr);
 extern int radeon_bo_kmap(struct radeon_bo *bo, void **ptr);
 extern void radeon_bo_kunmap(struct radeon_bo *bo);
index 164898b0010c68b350c175b705ef3534af5be69a..32522cc940a127c4b413c9928121c2b9258457fd 100644 (file)
@@ -1556,7 +1556,7 @@ static bool radeon_pm_in_vbl(struct radeon_device *rdev)
                if (rdev->pm.active_crtcs & (1 << crtc)) {
                        vbl_status = radeon_get_crtc_scanoutpos(rdev->ddev, crtc, 0, &vpos, &hpos, NULL, NULL);
                        if ((vbl_status & DRM_SCANOUTPOS_VALID) &&
-                           !(vbl_status & DRM_SCANOUTPOS_INVBL))
+                           !(vbl_status & DRM_SCANOUTPOS_IN_VBLANK))
                                in_vbl = false;
                }
        }
index 0b16f2cbcf170b5a9a6d23b6683eedb827b890b4..f3609c97496b2f56bf35cfbe2cf52f76b30b9f79 100644 (file)
@@ -27,6 +27,7 @@
 
 #include "radeon.h"
 #include <drm/radeon_drm.h>
+#include <linux/dma-buf.h>
 
 struct sg_table *radeon_gem_prime_get_sg_table(struct drm_gem_object *obj)
 {
@@ -57,15 +58,18 @@ void radeon_gem_prime_vunmap(struct drm_gem_object *obj, void *vaddr)
 }
 
 struct drm_gem_object *radeon_gem_prime_import_sg_table(struct drm_device *dev,
-                                                       size_t size,
+                                                       struct dma_buf_attachment *attach,
                                                        struct sg_table *sg)
 {
+       struct reservation_object *resv = attach->dmabuf->resv;
        struct radeon_device *rdev = dev->dev_private;
        struct radeon_bo *bo;
        int ret;
 
-       ret = radeon_bo_create(rdev, size, PAGE_SIZE, false,
-                              RADEON_GEM_DOMAIN_GTT, 0, sg, &bo);
+       ww_mutex_lock(&resv->lock, NULL);
+       ret = radeon_bo_create(rdev, attach->dmabuf->size, PAGE_SIZE, false,
+                              RADEON_GEM_DOMAIN_GTT, 0, sg, resv, &bo);
+       ww_mutex_unlock(&resv->lock);
        if (ret)
                return ERR_PTR(ret);
 
@@ -111,3 +115,13 @@ struct reservation_object *radeon_gem_prime_res_obj(struct drm_gem_object *obj)
 
        return bo->tbo.resv;
 }
+
+struct dma_buf *radeon_gem_prime_export(struct drm_device *dev,
+                                       struct drm_gem_object *gobj,
+                                       int flags)
+{
+       struct radeon_bo *bo = gem_to_radeon_bo(gobj);
+       if (radeon_ttm_tt_has_userptr(bo->tbo.ttm))
+               return ERR_PTR(-EPERM);
+       return drm_gem_prime_export(dev, gobj, flags);
+}
index d65607902537f41a7ede21261eb111ddbf257e63..3d17af34afa73265eea6ed31210e265acae6eb1a 100644 (file)
  */
 static int radeon_debugfs_ring_init(struct radeon_device *rdev, struct radeon_ring *ring);
 
-/**
- * radeon_ring_write - write a value to the ring
- *
- * @ring: radeon_ring structure holding ring information
- * @v: dword (dw) value to write
- *
- * Write a value to the requested ring buffer (all asics).
- */
-void radeon_ring_write(struct radeon_ring *ring, uint32_t v)
-{
-#if DRM_DEBUG_CODE
-       if (ring->count_dw <= 0) {
-               DRM_ERROR("radeon: writing more dwords to the ring than expected!\n");
-       }
-#endif
-       ring->ring[ring->wptr++] = v;
-       ring->wptr &= ring->ptr_mask;
-       ring->count_dw--;
-       ring->ring_free_dw--;
-}
-
 /**
  * radeon_ring_supports_scratch_reg - check if the ring supports
  * writing to scratch registers
@@ -404,7 +383,7 @@ int radeon_ring_init(struct radeon_device *rdev, struct radeon_ring *ring, unsig
        /* Allocate ring buffer */
        if (ring->ring_obj == NULL) {
                r = radeon_bo_create(rdev, ring->ring_size, PAGE_SIZE, true,
-                                    RADEON_GEM_DOMAIN_GTT, 0,
+                                    RADEON_GEM_DOMAIN_GTT, 0, NULL,
                                     NULL, &ring->ring_obj);
                if (r) {
                        dev_err(rdev->dev, "(%d) ring create failed\n", r);
index b84f97c8718cd1b7b1f46137b1646af1691f8d4e..c507896aca45a43a3fe271b79b84e7db61bfb85a 100644 (file)
@@ -65,7 +65,7 @@ int radeon_sa_bo_manager_init(struct radeon_device *rdev,
        }
 
        r = radeon_bo_create(rdev, size, align, true,
-                            domain, flags, NULL, &sa_manager->bo);
+                            domain, flags, NULL, NULL, &sa_manager->bo);
        if (r) {
                dev_err(rdev->dev, "(%d) failed to allocate bo for manager\n", r);
                return r;
index abd6753a570afa119ac1e68255231c99f7b27995..6deb08f045b758a9cbaefec886177b86c950a567 100644 (file)
@@ -96,15 +96,15 @@ bool radeon_semaphore_emit_wait(struct radeon_device *rdev, int ridx,
 }
 
 /**
- * radeon_semaphore_sync_to - use the semaphore to sync to a fence
+ * radeon_semaphore_sync_fence - use the semaphore to sync to a fence
  *
  * @semaphore: semaphore object to add fence to
  * @fence: fence to sync to
  *
  * Sync to the fence using this semaphore object
  */
-void radeon_semaphore_sync_to(struct radeon_semaphore *semaphore,
-                             struct radeon_fence *fence)
+void radeon_semaphore_sync_fence(struct radeon_semaphore *semaphore,
+                                struct radeon_fence *fence)
 {
         struct radeon_fence *other;
 
@@ -115,6 +115,53 @@ void radeon_semaphore_sync_to(struct radeon_semaphore *semaphore,
         semaphore->sync_to[fence->ring] = radeon_fence_later(fence, other);
 }
 
+/**
+ * radeon_semaphore_sync_to - use the semaphore to sync to a reservation object
+ *
+ * @sema: semaphore object to add fence from reservation object to
+ * @resv: reservation object with embedded fence
+ * @shared: true if we should onyl sync to the exclusive fence
+ *
+ * Sync to the fence using this semaphore object
+ */
+int radeon_semaphore_sync_resv(struct radeon_device *rdev,
+                              struct radeon_semaphore *sema,
+                              struct reservation_object *resv,
+                              bool shared)
+{
+       struct reservation_object_list *flist;
+       struct fence *f;
+       struct radeon_fence *fence;
+       unsigned i;
+       int r = 0;
+
+       /* always sync to the exclusive fence */
+       f = reservation_object_get_excl(resv);
+       fence = f ? to_radeon_fence(f) : NULL;
+       if (fence && fence->rdev == rdev)
+               radeon_semaphore_sync_fence(sema, fence);
+       else if (f)
+               r = fence_wait(f, true);
+
+       flist = reservation_object_get_list(resv);
+       if (shared || !flist || r)
+               return r;
+
+       for (i = 0; i < flist->shared_count; ++i) {
+               f = rcu_dereference_protected(flist->shared[i],
+                                             reservation_object_held(resv));
+               fence = to_radeon_fence(f);
+               if (fence && fence->rdev == rdev)
+                       radeon_semaphore_sync_fence(sema, fence);
+               else
+                       r = fence_wait(f, true);
+
+               if (r)
+                       break;
+       }
+       return r;
+}
+
 /**
  * radeon_semaphore_sync_rings - sync ring to all registered fences
  *
index 23bb64fd775f674cae5091013b4d63979f62ebeb..535403e0c8a28c20011261decb68eeb3d47b6846 100644 (file)
@@ -30,9 +30,9 @@
  */
 
 #include <drm/drmP.h>
-#include <drm/drm_buffer.h>
 #include <drm/radeon_drm.h>
 #include "radeon_drv.h"
+#include "drm_buffer.h"
 
 /* ================================================================
  * Helper functions for client state checking and fixup
index 17bc3dced9f1db921a11f80b1167f520261ed0b1..07b506b410080f482b4d41948c3bd627ae4bb39e 100644 (file)
@@ -67,7 +67,7 @@ static void radeon_do_test_moves(struct radeon_device *rdev, int flag)
        }
 
        r = radeon_bo_create(rdev, size, PAGE_SIZE, true, RADEON_GEM_DOMAIN_VRAM,
-                            0, NULL, &vram_obj);
+                            0, NULL, NULL, &vram_obj);
        if (r) {
                DRM_ERROR("Failed to create VRAM object\n");
                goto out_cleanup;
@@ -87,7 +87,8 @@ static void radeon_do_test_moves(struct radeon_device *rdev, int flag)
                struct radeon_fence *fence = NULL;
 
                r = radeon_bo_create(rdev, size, PAGE_SIZE, true,
-                                    RADEON_GEM_DOMAIN_GTT, 0, NULL, gtt_obj + i);
+                                    RADEON_GEM_DOMAIN_GTT, 0, NULL, NULL,
+                                    gtt_obj + i);
                if (r) {
                        DRM_ERROR("Failed to create GTT object %d\n", i);
                        goto out_lclean;
@@ -116,11 +117,16 @@ static void radeon_do_test_moves(struct radeon_device *rdev, int flag)
                radeon_bo_kunmap(gtt_obj[i]);
 
                if (ring == R600_RING_TYPE_DMA_INDEX)
-                       r = radeon_copy_dma(rdev, gtt_addr, vram_addr, size / RADEON_GPU_PAGE_SIZE, &fence);
+                       fence = radeon_copy_dma(rdev, gtt_addr, vram_addr,
+                                               size / RADEON_GPU_PAGE_SIZE,
+                                               NULL);
                else
-                       r = radeon_copy_blit(rdev, gtt_addr, vram_addr, size / RADEON_GPU_PAGE_SIZE, &fence);
-               if (r) {
+                       fence = radeon_copy_blit(rdev, gtt_addr, vram_addr,
+                                                size / RADEON_GPU_PAGE_SIZE,
+                                                NULL);
+               if (IS_ERR(fence)) {
                        DRM_ERROR("Failed GTT->VRAM copy %d\n", i);
+                       r = PTR_ERR(fence);
                        goto out_lclean_unpin;
                }
 
@@ -162,11 +168,16 @@ static void radeon_do_test_moves(struct radeon_device *rdev, int flag)
                radeon_bo_kunmap(vram_obj);
 
                if (ring == R600_RING_TYPE_DMA_INDEX)
-                       r = radeon_copy_dma(rdev, vram_addr, gtt_addr, size / RADEON_GPU_PAGE_SIZE, &fence);
+                       fence = radeon_copy_dma(rdev, vram_addr, gtt_addr,
+                                               size / RADEON_GPU_PAGE_SIZE,
+                                               NULL);
                else
-                       r = radeon_copy_blit(rdev, vram_addr, gtt_addr, size / RADEON_GPU_PAGE_SIZE, &fence);
-               if (r) {
+                       fence = radeon_copy_blit(rdev, vram_addr, gtt_addr,
+                                                size / RADEON_GPU_PAGE_SIZE,
+                                                NULL);
+               if (IS_ERR(fence)) {
                        DRM_ERROR("Failed VRAM->GTT copy %d\n", i);
+                       r = PTR_ERR(fence);
                        goto out_lclean_unpin;
                }
 
@@ -222,7 +233,7 @@ out_lclean:
                        radeon_bo_unreserve(gtt_obj[i]);
                        radeon_bo_unref(&gtt_obj[i]);
                }
-               if (fence)
+               if (fence && !IS_ERR(fence))
                        radeon_fence_unref(&fence);
                break;
        }
index 72afe82a95c906f58387196390258b5ebb902b4e..8624979afb65f55ecba4ffb888aa09d0b3c8b39d 100644 (file)
@@ -39,6 +39,8 @@
 #include <linux/seq_file.h>
 #include <linux/slab.h>
 #include <linux/swiotlb.h>
+#include <linux/swap.h>
+#include <linux/pagemap.h>
 #include <linux/debugfs.h>
 #include "radeon_reg.h"
 #include "radeon.h"
@@ -176,12 +178,15 @@ static int radeon_init_mem_type(struct ttm_bo_device *bdev, uint32_t type,
 static void radeon_evict_flags(struct ttm_buffer_object *bo,
                                struct ttm_placement *placement)
 {
+       static struct ttm_place placements = {
+               .fpfn = 0,
+               .lpfn = 0,
+               .flags = TTM_PL_MASK_CACHING | TTM_PL_FLAG_SYSTEM
+       };
+
        struct radeon_bo *rbo;
-       static u32 placements = TTM_PL_MASK_CACHING | TTM_PL_FLAG_SYSTEM;
 
        if (!radeon_ttm_bo_is_radeon_bo(bo)) {
-               placement->fpfn = 0;
-               placement->lpfn = 0;
                placement->placement = &placements;
                placement->busy_placement = &placements;
                placement->num_placement = 1;
@@ -228,6 +233,7 @@ static int radeon_move_blit(struct ttm_buffer_object *bo,
        struct radeon_device *rdev;
        uint64_t old_start, new_start;
        struct radeon_fence *fence;
+       unsigned num_pages;
        int r, ridx;
 
        rdev = radeon_get_rdev(bo->bdev);
@@ -264,13 +270,12 @@ static int radeon_move_blit(struct ttm_buffer_object *bo,
 
        BUILD_BUG_ON((PAGE_SIZE % RADEON_GPU_PAGE_SIZE) != 0);
 
-       /* sync other rings */
-       fence = bo->sync_obj;
-       r = radeon_copy(rdev, old_start, new_start,
-                       new_mem->num_pages * (PAGE_SIZE / RADEON_GPU_PAGE_SIZE), /* GPU pages */
-                       &fence);
-       /* FIXME: handle copy error */
-       r = ttm_bo_move_accel_cleanup(bo, (void *)fence,
+       num_pages = new_mem->num_pages * (PAGE_SIZE / RADEON_GPU_PAGE_SIZE);
+       fence = radeon_copy(rdev, old_start, new_start, num_pages, bo->resv);
+       if (IS_ERR(fence))
+               return PTR_ERR(fence);
+
+       r = ttm_bo_move_accel_cleanup(bo, &fence->base,
                                      evict, no_wait_gpu, new_mem);
        radeon_fence_unref(&fence);
        return r;
@@ -284,20 +289,20 @@ static int radeon_move_vram_ram(struct ttm_buffer_object *bo,
        struct radeon_device *rdev;
        struct ttm_mem_reg *old_mem = &bo->mem;
        struct ttm_mem_reg tmp_mem;
-       u32 placements;
+       struct ttm_place placements;
        struct ttm_placement placement;
        int r;
 
        rdev = radeon_get_rdev(bo->bdev);
        tmp_mem = *new_mem;
        tmp_mem.mm_node = NULL;
-       placement.fpfn = 0;
-       placement.lpfn = 0;
        placement.num_placement = 1;
        placement.placement = &placements;
        placement.num_busy_placement = 1;
        placement.busy_placement = &placements;
-       placements = TTM_PL_MASK_CACHING | TTM_PL_FLAG_TT;
+       placements.fpfn = 0;
+       placements.lpfn = 0;
+       placements.flags = TTM_PL_MASK_CACHING | TTM_PL_FLAG_TT;
        r = ttm_bo_mem_space(bo, &placement, &tmp_mem,
                             interruptible, no_wait_gpu);
        if (unlikely(r)) {
@@ -332,19 +337,19 @@ static int radeon_move_ram_vram(struct ttm_buffer_object *bo,
        struct ttm_mem_reg *old_mem = &bo->mem;
        struct ttm_mem_reg tmp_mem;
        struct ttm_placement placement;
-       u32 placements;
+       struct ttm_place placements;
        int r;
 
        rdev = radeon_get_rdev(bo->bdev);
        tmp_mem = *new_mem;
        tmp_mem.mm_node = NULL;
-       placement.fpfn = 0;
-       placement.lpfn = 0;
        placement.num_placement = 1;
        placement.placement = &placements;
        placement.num_busy_placement = 1;
        placement.busy_placement = &placements;
-       placements = TTM_PL_MASK_CACHING | TTM_PL_FLAG_TT;
+       placements.fpfn = 0;
+       placements.lpfn = 0;
+       placements.flags = TTM_PL_MASK_CACHING | TTM_PL_FLAG_TT;
        r = ttm_bo_mem_space(bo, &placement, &tmp_mem,
                             interruptible, no_wait_gpu);
        if (unlikely(r)) {
@@ -483,39 +488,108 @@ static void radeon_ttm_io_mem_free(struct ttm_bo_device *bdev, struct ttm_mem_re
 {
 }
 
-static int radeon_sync_obj_wait(void *sync_obj, bool lazy, bool interruptible)
-{
-       return radeon_fence_wait((struct radeon_fence *)sync_obj, interruptible);
-}
+/*
+ * TTM backend functions.
+ */
+struct radeon_ttm_tt {
+       struct ttm_dma_tt               ttm;
+       struct radeon_device            *rdev;
+       u64                             offset;
 
-static int radeon_sync_obj_flush(void *sync_obj)
+       uint64_t                        userptr;
+       struct mm_struct                *usermm;
+       uint32_t                        userflags;
+};
+
+/* prepare the sg table with the user pages */
+static int radeon_ttm_tt_pin_userptr(struct ttm_tt *ttm)
 {
+       struct radeon_device *rdev = radeon_get_rdev(ttm->bdev);
+       struct radeon_ttm_tt *gtt = (void *)ttm;
+       unsigned pinned = 0, nents;
+       int r;
+
+       int write = !(gtt->userflags & RADEON_GEM_USERPTR_READONLY);
+       enum dma_data_direction direction = write ?
+               DMA_BIDIRECTIONAL : DMA_TO_DEVICE;
+
+       if (current->mm != gtt->usermm)
+               return -EPERM;
+
+       if (gtt->userflags & RADEON_GEM_USERPTR_ANONONLY) {
+               /* check that we only pin down anonymous memory
+                  to prevent problems with writeback */
+               unsigned long end = gtt->userptr + ttm->num_pages * PAGE_SIZE;
+               struct vm_area_struct *vma;
+               vma = find_vma(gtt->usermm, gtt->userptr);
+               if (!vma || vma->vm_file || vma->vm_end < end)
+                       return -EPERM;
+       }
+
+       do {
+               unsigned num_pages = ttm->num_pages - pinned;
+               uint64_t userptr = gtt->userptr + pinned * PAGE_SIZE;
+               struct page **pages = ttm->pages + pinned;
+
+               r = get_user_pages(current, current->mm, userptr, num_pages,
+                                  write, 0, pages, NULL);
+               if (r < 0)
+                       goto release_pages;
+
+               pinned += r;
+
+       } while (pinned < ttm->num_pages);
+
+       r = sg_alloc_table_from_pages(ttm->sg, ttm->pages, ttm->num_pages, 0,
+                                     ttm->num_pages << PAGE_SHIFT,
+                                     GFP_KERNEL);
+       if (r)
+               goto release_sg;
+
+       r = -ENOMEM;
+       nents = dma_map_sg(rdev->dev, ttm->sg->sgl, ttm->sg->nents, direction);
+       if (nents != ttm->sg->nents)
+               goto release_sg;
+
+       drm_prime_sg_to_page_addr_arrays(ttm->sg, ttm->pages,
+                                        gtt->ttm.dma_address, ttm->num_pages);
+
        return 0;
-}
 
-static void radeon_sync_obj_unref(void **sync_obj)
-{
-       radeon_fence_unref((struct radeon_fence **)sync_obj);
-}
+release_sg:
+       kfree(ttm->sg);
 
-static void *radeon_sync_obj_ref(void *sync_obj)
-{
-       return radeon_fence_ref((struct radeon_fence *)sync_obj);
+release_pages:
+       release_pages(ttm->pages, pinned, 0);
+       return r;
 }
 
-static bool radeon_sync_obj_signaled(void *sync_obj)
+static void radeon_ttm_tt_unpin_userptr(struct ttm_tt *ttm)
 {
-       return radeon_fence_signaled((struct radeon_fence *)sync_obj);
-}
+       struct radeon_device *rdev = radeon_get_rdev(ttm->bdev);
+       struct radeon_ttm_tt *gtt = (void *)ttm;
+       struct scatterlist *sg;
+       int i;
 
-/*
- * TTM backend functions.
- */
-struct radeon_ttm_tt {
-       struct ttm_dma_tt               ttm;
-       struct radeon_device            *rdev;
-       u64                             offset;
-};
+       int write = !(gtt->userflags & RADEON_GEM_USERPTR_READONLY);
+       enum dma_data_direction direction = write ?
+               DMA_BIDIRECTIONAL : DMA_TO_DEVICE;
+
+       /* free the sg table and pages again */
+       dma_unmap_sg(rdev->dev, ttm->sg->sgl, ttm->sg->nents, direction);
+
+       for_each_sg(ttm->sg->sgl, sg, ttm->sg->nents, i) {
+               struct page *page = sg_page(sg);
+
+               if (!(gtt->userflags & RADEON_GEM_USERPTR_READONLY))
+                       set_page_dirty(page);
+
+               mark_page_accessed(page);
+               page_cache_release(page);
+       }
+
+       sg_free_table(ttm->sg);
+}
 
 static int radeon_ttm_backend_bind(struct ttm_tt *ttm,
                                   struct ttm_mem_reg *bo_mem)
@@ -525,6 +599,11 @@ static int radeon_ttm_backend_bind(struct ttm_tt *ttm,
                RADEON_GART_PAGE_WRITE;
        int r;
 
+       if (gtt->userptr) {
+               radeon_ttm_tt_pin_userptr(ttm);
+               flags &= ~RADEON_GART_PAGE_WRITE;
+       }
+
        gtt->offset = (unsigned long)(bo_mem->start << PAGE_SHIFT);
        if (!ttm->num_pages) {
                WARN(1, "nothing to bind %lu pages for mreg %p back %p!\n",
@@ -547,6 +626,10 @@ static int radeon_ttm_backend_unbind(struct ttm_tt *ttm)
        struct radeon_ttm_tt *gtt = (void *)ttm;
 
        radeon_gart_unbind(gtt->rdev, gtt->offset, ttm->num_pages);
+
+       if (gtt->userptr)
+               radeon_ttm_tt_unpin_userptr(ttm);
+
        return 0;
 }
 
@@ -592,10 +675,17 @@ static struct ttm_tt *radeon_ttm_tt_create(struct ttm_bo_device *bdev,
        return &gtt->ttm.ttm;
 }
 
+static struct radeon_ttm_tt *radeon_ttm_tt_to_gtt(struct ttm_tt *ttm)
+{
+       if (!ttm || ttm->func != &radeon_backend_func)
+               return NULL;
+       return (struct radeon_ttm_tt *)ttm;
+}
+
 static int radeon_ttm_tt_populate(struct ttm_tt *ttm)
 {
+       struct radeon_ttm_tt *gtt = radeon_ttm_tt_to_gtt(ttm);
        struct radeon_device *rdev;
-       struct radeon_ttm_tt *gtt = (void *)ttm;
        unsigned i;
        int r;
        bool slave = !!(ttm->page_flags & TTM_PAGE_FLAG_SG);
@@ -603,6 +693,16 @@ static int radeon_ttm_tt_populate(struct ttm_tt *ttm)
        if (ttm->state != tt_unpopulated)
                return 0;
 
+       if (gtt && gtt->userptr) {
+               ttm->sg = kcalloc(1, sizeof(struct sg_table), GFP_KERNEL);
+               if (!ttm->sg)
+                       return -ENOMEM;
+
+               ttm->page_flags |= TTM_PAGE_FLAG_SG;
+               ttm->state = tt_unbound;
+               return 0;
+       }
+
        if (slave && ttm->sg) {
                drm_prime_sg_to_page_addr_arrays(ttm->sg, ttm->pages,
                                                 gtt->ttm.dma_address, ttm->num_pages);
@@ -648,10 +748,16 @@ static int radeon_ttm_tt_populate(struct ttm_tt *ttm)
 static void radeon_ttm_tt_unpopulate(struct ttm_tt *ttm)
 {
        struct radeon_device *rdev;
-       struct radeon_ttm_tt *gtt = (void *)ttm;
+       struct radeon_ttm_tt *gtt = radeon_ttm_tt_to_gtt(ttm);
        unsigned i;
        bool slave = !!(ttm->page_flags & TTM_PAGE_FLAG_SG);
 
+       if (gtt && gtt->userptr) {
+               kfree(ttm->sg);
+               ttm->page_flags &= ~TTM_PAGE_FLAG_SG;
+               return;
+       }
+
        if (slave)
                return;
 
@@ -680,6 +786,40 @@ static void radeon_ttm_tt_unpopulate(struct ttm_tt *ttm)
        ttm_pool_unpopulate(ttm);
 }
 
+int radeon_ttm_tt_set_userptr(struct ttm_tt *ttm, uint64_t addr,
+                             uint32_t flags)
+{
+       struct radeon_ttm_tt *gtt = radeon_ttm_tt_to_gtt(ttm);
+
+       if (gtt == NULL)
+               return -EINVAL;
+
+       gtt->userptr = addr;
+       gtt->usermm = current->mm;
+       gtt->userflags = flags;
+       return 0;
+}
+
+bool radeon_ttm_tt_has_userptr(struct ttm_tt *ttm)
+{
+       struct radeon_ttm_tt *gtt = radeon_ttm_tt_to_gtt(ttm);
+
+       if (gtt == NULL)
+               return false;
+
+       return !!gtt->userptr;
+}
+
+bool radeon_ttm_tt_is_readonly(struct ttm_tt *ttm)
+{
+       struct radeon_ttm_tt *gtt = radeon_ttm_tt_to_gtt(ttm);
+
+       if (gtt == NULL)
+               return false;
+
+       return !!(gtt->userflags & RADEON_GEM_USERPTR_READONLY);
+}
+
 static struct ttm_bo_driver radeon_bo_driver = {
        .ttm_tt_create = &radeon_ttm_tt_create,
        .ttm_tt_populate = &radeon_ttm_tt_populate,
@@ -689,11 +829,6 @@ static struct ttm_bo_driver radeon_bo_driver = {
        .evict_flags = &radeon_evict_flags,
        .move = &radeon_bo_move,
        .verify_access = &radeon_verify_access,
-       .sync_obj_signaled = &radeon_sync_obj_signaled,
-       .sync_obj_wait = &radeon_sync_obj_wait,
-       .sync_obj_flush = &radeon_sync_obj_flush,
-       .sync_obj_unref = &radeon_sync_obj_unref,
-       .sync_obj_ref = &radeon_sync_obj_ref,
        .move_notify = &radeon_bo_move_notify,
        .fault_reserve_notify = &radeon_bo_fault_reserve_notify,
        .io_mem_reserve = &radeon_ttm_io_mem_reserve,
@@ -730,7 +865,7 @@ int radeon_ttm_init(struct radeon_device *rdev)
        radeon_ttm_set_active_vram_size(rdev, rdev->mc.visible_vram_size);
 
        r = radeon_bo_create(rdev, 256 * 1024, PAGE_SIZE, true,
-                            RADEON_GEM_DOMAIN_VRAM, 0,
+                            RADEON_GEM_DOMAIN_VRAM, 0, NULL,
                             NULL, &rdev->stollen_vga_memory);
        if (r) {
                return r;
@@ -828,7 +963,7 @@ int radeon_mmap(struct file *filp, struct vm_area_struct *vma)
        int r;
 
        if (unlikely(vma->vm_pgoff < DRM_FILE_PAGE_OFFSET)) {
-               return drm_mmap(filp, vma);
+               return -EINVAL;
        }
 
        file_priv = filp->private_data;
index 341848a143761dd8236edc7862f79482d5d2d19d..11b6624692536c13dbea4cc4e9b4c75b46902d1d 100644 (file)
 #define UVD_IDLE_TIMEOUT_MS    1000
 
 /* Firmware Names */
+#define FIRMWARE_R600          "radeon/R600_uvd.bin"
+#define FIRMWARE_RS780         "radeon/RS780_uvd.bin"
+#define FIRMWARE_RV770         "radeon/RV770_uvd.bin"
 #define FIRMWARE_RV710         "radeon/RV710_uvd.bin"
 #define FIRMWARE_CYPRESS       "radeon/CYPRESS_uvd.bin"
 #define FIRMWARE_SUMO          "radeon/SUMO_uvd.bin"
 #define FIRMWARE_TAHITI                "radeon/TAHITI_uvd.bin"
 #define FIRMWARE_BONAIRE       "radeon/BONAIRE_uvd.bin"
 
+MODULE_FIRMWARE(FIRMWARE_R600);
+MODULE_FIRMWARE(FIRMWARE_RS780);
+MODULE_FIRMWARE(FIRMWARE_RV770);
 MODULE_FIRMWARE(FIRMWARE_RV710);
 MODULE_FIRMWARE(FIRMWARE_CYPRESS);
 MODULE_FIRMWARE(FIRMWARE_SUMO);
@@ -63,6 +69,23 @@ int radeon_uvd_init(struct radeon_device *rdev)
        INIT_DELAYED_WORK(&rdev->uvd.idle_work, radeon_uvd_idle_work_handler);
 
        switch (rdev->family) {
+       case CHIP_RV610:
+       case CHIP_RV630:
+       case CHIP_RV670:
+       case CHIP_RV620:
+       case CHIP_RV635:
+               fw_name = FIRMWARE_R600;
+               break;
+
+       case CHIP_RS780:
+       case CHIP_RS880:
+               fw_name = FIRMWARE_RS780;
+               break;
+
+       case CHIP_RV770:
+               fw_name = FIRMWARE_RV770;
+               break;
+
        case CHIP_RV710:
        case CHIP_RV730:
        case CHIP_RV740:
@@ -115,9 +138,11 @@ int radeon_uvd_init(struct radeon_device *rdev)
        }
 
        bo_size = RADEON_GPU_PAGE_ALIGN(rdev->uvd_fw->size + 8) +
-                 RADEON_UVD_STACK_SIZE + RADEON_UVD_HEAP_SIZE;
+                 RADEON_UVD_STACK_SIZE + RADEON_UVD_HEAP_SIZE +
+                 RADEON_GPU_PAGE_SIZE;
        r = radeon_bo_create(rdev, bo_size, PAGE_SIZE, true,
-                            RADEON_GEM_DOMAIN_VRAM, 0, NULL, &rdev->uvd.vcpu_bo);
+                            RADEON_GEM_DOMAIN_VRAM, 0, NULL,
+                            NULL, &rdev->uvd.vcpu_bo);
        if (r) {
                dev_err(rdev->dev, "(%d) failed to allocate UVD bo\n", r);
                return r;
@@ -231,10 +256,30 @@ int radeon_uvd_resume(struct radeon_device *rdev)
        return 0;
 }
 
-void radeon_uvd_force_into_uvd_segment(struct radeon_bo *rbo)
+void radeon_uvd_force_into_uvd_segment(struct radeon_bo *rbo,
+                                      uint32_t allowed_domains)
 {
-       rbo->placement.fpfn = 0 >> PAGE_SHIFT;
-       rbo->placement.lpfn = (256 * 1024 * 1024) >> PAGE_SHIFT;
+       int i;
+
+       for (i = 0; i < rbo->placement.num_placement; ++i) {
+               rbo->placements[i].fpfn = 0 >> PAGE_SHIFT;
+               rbo->placements[i].lpfn = (256 * 1024 * 1024) >> PAGE_SHIFT;
+       }
+
+       /* If it must be in VRAM it must be in the first segment as well */
+       if (allowed_domains == RADEON_GEM_DOMAIN_VRAM)
+               return;
+
+       /* abort if we already have more than one placement */
+       if (rbo->placement.num_placement > 1)
+               return;
+
+       /* add another 256MB segment */
+       rbo->placements[1] = rbo->placements[0];
+       rbo->placements[1].fpfn += (256 * 1024 * 1024) >> PAGE_SHIFT;
+       rbo->placements[1].lpfn += (256 * 1024 * 1024) >> PAGE_SHIFT;
+       rbo->placement.num_placement++;
+       rbo->placement.num_busy_placement++;
 }
 
 void radeon_uvd_free_handles(struct radeon_device *rdev, struct drm_file *filp)
@@ -356,6 +401,7 @@ static int radeon_uvd_cs_msg(struct radeon_cs_parser *p, struct radeon_bo *bo,
 {
        int32_t *msg, msg_type, handle;
        unsigned img_size = 0;
+       struct fence *f;
        void *ptr;
 
        int i, r;
@@ -365,8 +411,9 @@ static int radeon_uvd_cs_msg(struct radeon_cs_parser *p, struct radeon_bo *bo,
                return -EINVAL;
        }
 
-       if (bo->tbo.sync_obj) {
-               r = radeon_fence_wait(bo->tbo.sync_obj, false);
+       f = reservation_object_get_excl(bo->tbo.resv);
+       if (f) {
+               r = radeon_fence_wait((struct radeon_fence *)f, false);
                if (r) {
                        DRM_ERROR("Failed waiting for UVD message (%d)!\n", r);
                        return r;
@@ -604,38 +651,16 @@ int radeon_uvd_cs_parse(struct radeon_cs_parser *p)
 }
 
 static int radeon_uvd_send_msg(struct radeon_device *rdev,
-                              int ring, struct radeon_bo *bo,
+                              int ring, uint64_t addr,
                               struct radeon_fence **fence)
 {
-       struct ttm_validate_buffer tv;
-       struct ww_acquire_ctx ticket;
-       struct list_head head;
        struct radeon_ib ib;
-       uint64_t addr;
        int i, r;
 
-       memset(&tv, 0, sizeof(tv));
-       tv.bo = &bo->tbo;
-
-       INIT_LIST_HEAD(&head);
-       list_add(&tv.head, &head);
-
-       r = ttm_eu_reserve_buffers(&ticket, &head);
-       if (r)
-               return r;
-
-       radeon_ttm_placement_from_domain(bo, RADEON_GEM_DOMAIN_VRAM);
-       radeon_uvd_force_into_uvd_segment(bo);
-
-       r = ttm_bo_validate(&bo->tbo, &bo->placement, true, false);
-       if (r) 
-               goto err;
-
        r = radeon_ib_get(rdev, ring, &ib, NULL, 64);
        if (r)
-               goto err;
+               return r;
 
-       addr = radeon_bo_gpu_offset(bo);
        ib.ptr[0] = PACKET0(UVD_GPCOM_VCPU_DATA0, 0);
        ib.ptr[1] = addr;
        ib.ptr[2] = PACKET0(UVD_GPCOM_VCPU_DATA1, 0);
@@ -647,19 +672,11 @@ static int radeon_uvd_send_msg(struct radeon_device *rdev,
        ib.length_dw = 16;
 
        r = radeon_ib_schedule(rdev, &ib, NULL, false);
-       if (r)
-               goto err;
-       ttm_eu_fence_buffer_objects(&ticket, &head, ib.fence);
 
        if (fence)
                *fence = radeon_fence_ref(ib.fence);
 
        radeon_ib_free(rdev, &ib);
-       radeon_bo_unref(&bo);
-       return 0;
-
-err:
-       ttm_eu_backoff_reservation(&ticket, &head);
        return r;
 }
 
@@ -669,27 +686,18 @@ err:
 int radeon_uvd_get_create_msg(struct radeon_device *rdev, int ring,
                              uint32_t handle, struct radeon_fence **fence)
 {
-       struct radeon_bo *bo;
-       uint32_t *msg;
-       int r, i;
+       /* we use the last page of the vcpu bo for the UVD message */
+       uint64_t offs = radeon_bo_size(rdev->uvd.vcpu_bo) -
+               RADEON_GPU_PAGE_SIZE;
 
-       r = radeon_bo_create(rdev, 1024, PAGE_SIZE, true,
-                            RADEON_GEM_DOMAIN_VRAM, 0, NULL, &bo);
-       if (r)
-               return r;
+       uint32_t *msg = rdev->uvd.cpu_addr + offs;
+       uint64_t addr = rdev->uvd.gpu_addr + offs;
 
-       r = radeon_bo_reserve(bo, false);
-       if (r) {
-               radeon_bo_unref(&bo);
-               return r;
-       }
+       int r, i;
 
-       r = radeon_bo_kmap(bo, (void **)&msg);
-       if (r) {
-               radeon_bo_unreserve(bo);
-               radeon_bo_unref(&bo);
+       r = radeon_bo_reserve(rdev->uvd.vcpu_bo, true);
+       if (r)
                return r;
-       }
 
        /* stitch together an UVD create msg */
        msg[0] = cpu_to_le32(0x00000de4);
@@ -706,36 +714,26 @@ int radeon_uvd_get_create_msg(struct radeon_device *rdev, int ring,
        for (i = 11; i < 1024; ++i)
                msg[i] = cpu_to_le32(0x0);
 
-       radeon_bo_kunmap(bo);
-       radeon_bo_unreserve(bo);
-
-       return radeon_uvd_send_msg(rdev, ring, bo, fence);
+       r = radeon_uvd_send_msg(rdev, ring, addr, fence);
+       radeon_bo_unreserve(rdev->uvd.vcpu_bo);
+       return r;
 }
 
 int radeon_uvd_get_destroy_msg(struct radeon_device *rdev, int ring,
                               uint32_t handle, struct radeon_fence **fence)
 {
-       struct radeon_bo *bo;
-       uint32_t *msg;
-       int r, i;
+       /* we use the last page of the vcpu bo for the UVD message */
+       uint64_t offs = radeon_bo_size(rdev->uvd.vcpu_bo) -
+               RADEON_GPU_PAGE_SIZE;
 
-       r = radeon_bo_create(rdev, 1024, PAGE_SIZE, true,
-                            RADEON_GEM_DOMAIN_VRAM, 0, NULL, &bo);
-       if (r)
-               return r;
+       uint32_t *msg = rdev->uvd.cpu_addr + offs;
+       uint64_t addr = rdev->uvd.gpu_addr + offs;
 
-       r = radeon_bo_reserve(bo, false);
-       if (r) {
-               radeon_bo_unref(&bo);
-               return r;
-       }
+       int r, i;
 
-       r = radeon_bo_kmap(bo, (void **)&msg);
-       if (r) {
-               radeon_bo_unreserve(bo);
-               radeon_bo_unref(&bo);
+       r = radeon_bo_reserve(rdev->uvd.vcpu_bo, true);
+       if (r)
                return r;
-       }
 
        /* stitch together an UVD destroy msg */
        msg[0] = cpu_to_le32(0x00000de4);
@@ -745,10 +743,9 @@ int radeon_uvd_get_destroy_msg(struct radeon_device *rdev, int ring,
        for (i = 4; i < 1024; ++i)
                msg[i] = cpu_to_le32(0x0);
 
-       radeon_bo_kunmap(bo);
-       radeon_bo_unreserve(bo);
-
-       return radeon_uvd_send_msg(rdev, ring, bo, fence);
+       r = radeon_uvd_send_msg(rdev, ring, addr, fence);
+       radeon_bo_unreserve(rdev->uvd.vcpu_bo);
+       return r;
 }
 
 /**
index c7190aadbd8981bee97c0c4ed4d923cdf7880b52..9e85757d55991a6cd0e077cada024d87f0484c08 100644 (file)
@@ -126,7 +126,8 @@ int radeon_vce_init(struct radeon_device *rdev)
        size = RADEON_GPU_PAGE_ALIGN(rdev->vce_fw->size) +
               RADEON_VCE_STACK_SIZE + RADEON_VCE_HEAP_SIZE;
        r = radeon_bo_create(rdev, size, PAGE_SIZE, true,
-                            RADEON_GEM_DOMAIN_VRAM, 0, NULL, &rdev->vce.vcpu_bo);
+                            RADEON_GEM_DOMAIN_VRAM, 0, NULL, NULL,
+                            &rdev->vce.vcpu_bo);
        if (r) {
                dev_err(rdev->dev, "(%d) failed to allocate VCE bo\n", r);
                return r;
index 088ffdc2f577c06519e2a31bc90bbd402c940125..4532cc76a0a66094cd1cff8449f8957dd60152bf 100644 (file)
@@ -143,6 +143,7 @@ struct radeon_cs_reloc *radeon_vm_get_bos(struct radeon_device *rdev,
        list[0].prefered_domains = RADEON_GEM_DOMAIN_VRAM;
        list[0].allowed_domains = RADEON_GEM_DOMAIN_VRAM;
        list[0].tv.bo = &vm->page_directory->tbo;
+       list[0].tv.shared = false;
        list[0].tiling_flags = 0;
        list[0].handle = 0;
        list_add(&list[0].tv.head, head);
@@ -156,6 +157,7 @@ struct radeon_cs_reloc *radeon_vm_get_bos(struct radeon_device *rdev,
                list[idx].prefered_domains = RADEON_GEM_DOMAIN_VRAM;
                list[idx].allowed_domains = RADEON_GEM_DOMAIN_VRAM;
                list[idx].tv.bo = &list[idx].robj->tbo;
+               list[idx].tv.shared = false;
                list[idx].tiling_flags = 0;
                list[idx].handle = 0;
                list_add(&list[idx++].tv.head, head);
@@ -395,11 +397,12 @@ static int radeon_vm_clear_bo(struct radeon_device *rdev,
 
         memset(&tv, 0, sizeof(tv));
         tv.bo = &bo->tbo;
+       tv.shared = false;
 
         INIT_LIST_HEAD(&head);
         list_add(&tv.head, &head);
 
-        r = ttm_eu_reserve_buffers(&ticket, &head);
+        r = ttm_eu_reserve_buffers(&ticket, &head, true);
         if (r)
                return r;
 
@@ -424,7 +427,7 @@ static int radeon_vm_clear_bo(struct radeon_device *rdev,
        if (r)
                 goto error;
 
-       ttm_eu_fence_buffer_objects(&ticket, &head, ib.fence);
+       ttm_eu_fence_buffer_objects(&ticket, &head, &ib.fence->base);
        radeon_ib_free(rdev, &ib);
 
        return 0;
@@ -545,7 +548,8 @@ int radeon_vm_bo_set_addr(struct radeon_device *rdev,
 
                r = radeon_bo_create(rdev, RADEON_VM_PTE_COUNT * 8,
                                     RADEON_GPU_PAGE_SIZE, true,
-                                    RADEON_GEM_DOMAIN_VRAM, 0, NULL, &pt);
+                                    RADEON_GEM_DOMAIN_VRAM, 0,
+                                    NULL, NULL, &pt);
                if (r)
                        return r;
 
@@ -694,8 +698,9 @@ int radeon_vm_update_page_directory(struct radeon_device *rdev,
 
        if (ib.length_dw != 0) {
                radeon_asic_vm_pad_ib(rdev, &ib);
-               radeon_semaphore_sync_to(ib.semaphore, pd->tbo.sync_obj);
-               radeon_semaphore_sync_to(ib.semaphore, vm->last_id_use);
+
+               radeon_semaphore_sync_resv(rdev, ib.semaphore, pd->tbo.resv, false);
+               radeon_semaphore_sync_fence(ib.semaphore, vm->last_id_use);
                WARN_ON(ib.length_dw > ndw);
                r = radeon_ib_schedule(rdev, &ib, NULL, false);
                if (r) {
@@ -821,7 +826,7 @@ static void radeon_vm_update_ptes(struct radeon_device *rdev,
                unsigned nptes;
                uint64_t pte;
 
-               radeon_semaphore_sync_to(ib->semaphore, pt->tbo.sync_obj);
+               radeon_semaphore_sync_resv(rdev, ib->semaphore, pt->tbo.resv, false);
 
                if ((addr & ~mask) == (end & ~mask))
                        nptes = end - addr;
@@ -892,6 +897,9 @@ int radeon_vm_bo_update(struct radeon_device *rdev,
        bo_va->flags &= ~RADEON_VM_PAGE_VALID;
        bo_va->flags &= ~RADEON_VM_PAGE_SYSTEM;
        bo_va->flags &= ~RADEON_VM_PAGE_SNOOPED;
+       if (bo_va->bo && radeon_ttm_tt_is_readonly(bo_va->bo->tbo.ttm))
+               bo_va->flags &= ~RADEON_VM_PAGE_WRITEABLE;
+
        if (mem) {
                addr = mem->start << PAGE_SHIFT;
                if (mem->mem_type != TTM_PL_SYSTEM) {
@@ -960,7 +968,7 @@ int radeon_vm_bo_update(struct radeon_device *rdev,
        radeon_asic_vm_pad_ib(rdev, &ib);
        WARN_ON(ib.length_dw > ndw);
 
-       radeon_semaphore_sync_to(ib.semaphore, vm->fence);
+       radeon_semaphore_sync_fence(ib.semaphore, vm->fence);
        r = radeon_ib_schedule(rdev, &ib, NULL, false);
        if (r) {
                radeon_ib_free(rdev, &ib);
@@ -1120,7 +1128,7 @@ int radeon_vm_init(struct radeon_device *rdev, struct radeon_vm *vm)
 
        r = radeon_bo_create(rdev, pd_size, align, true,
                             RADEON_GEM_DOMAIN_VRAM, 0, NULL,
-                            &vm->page_directory);
+                            NULL, &vm->page_directory);
        if (r)
                return r;
 
index d9f5ce715c9bfe5ff18be2a428809c1b7b217c58..372016e266d0add52a44b3a9a012d21415d77eea 100644 (file)
@@ -26,7 +26,6 @@
  *          Jerome Glisse
  */
 #include <linux/firmware.h>
-#include <linux/platform_device.h>
 #include <linux/slab.h>
 #include <drm/drmP.h>
 #include "radeon.h"
index 74426ac2bb5c2f39a26fb07eb76538afcc7061a9..7f34bad2e724d6e657203cfde55f85ddb48fa8da 100644 (file)
  * @src_offset: src GPU address
  * @dst_offset: dst GPU address
  * @num_gpu_pages: number of GPU pages to xfer
- * @fence: radeon fence object
+ * @resv: reservation object to sync to
  *
  * Copy GPU paging using the DMA engine (r7xx).
  * Used by the radeon ttm implementation to move pages if
  * registered as the asic copy callback.
  */
-int rv770_copy_dma(struct radeon_device *rdev,
-                 uint64_t src_offset, uint64_t dst_offset,
-                 unsigned num_gpu_pages,
-                 struct radeon_fence **fence)
+struct radeon_fence *rv770_copy_dma(struct radeon_device *rdev,
+                                   uint64_t src_offset, uint64_t dst_offset,
+                                   unsigned num_gpu_pages,
+                                   struct reservation_object *resv)
 {
        struct radeon_semaphore *sem = NULL;
+       struct radeon_fence *fence;
        int ring_index = rdev->asic->copy.dma_ring_index;
        struct radeon_ring *ring = &rdev->ring[ring_index];
        u32 size_in_dw, cur_size_in_dw;
@@ -54,7 +55,7 @@ int rv770_copy_dma(struct radeon_device *rdev,
        r = radeon_semaphore_create(rdev, &sem);
        if (r) {
                DRM_ERROR("radeon: moving bo (%d).\n", r);
-               return r;
+               return ERR_PTR(r);
        }
 
        size_in_dw = (num_gpu_pages << RADEON_GPU_PAGE_SHIFT) / 4;
@@ -63,10 +64,10 @@ int rv770_copy_dma(struct radeon_device *rdev,
        if (r) {
                DRM_ERROR("radeon: moving bo (%d).\n", r);
                radeon_semaphore_free(rdev, &sem, NULL);
-               return r;
+               return ERR_PTR(r);
        }
 
-       radeon_semaphore_sync_to(sem, *fence);
+       radeon_semaphore_sync_resv(rdev, sem, resv, false);
        radeon_semaphore_sync_rings(rdev, sem, ring->idx);
 
        for (i = 0; i < num_loops; i++) {
@@ -83,15 +84,15 @@ int rv770_copy_dma(struct radeon_device *rdev,
                dst_offset += cur_size_in_dw * 4;
        }
 
-       r = radeon_fence_emit(rdev, fence, ring->idx);
+       r = radeon_fence_emit(rdev, &fence, ring->idx);
        if (r) {
                radeon_ring_unlock_undo(rdev, ring);
                radeon_semaphore_free(rdev, &sem, NULL);
-               return r;
+               return ERR_PTR(r);
        }
 
        radeon_ring_unlock_commit(rdev, ring, false);
-       radeon_semaphore_free(rdev, &sem, *fence);
+       radeon_semaphore_free(rdev, &sem, fence);
 
-       return r;
+       return fence;
 }
index 3a0b973e8a96ef9f9b9aefb6e39a0459fd03ceff..eeea5b6a1775ee002f36682b7d092ab3b449d913 100644 (file)
@@ -4684,7 +4684,7 @@ static int si_vm_packet3_compute_check(struct radeon_device *rdev,
 int si_ib_parse(struct radeon_device *rdev, struct radeon_ib *ib)
 {
        int ret = 0;
-       u32 idx = 0;
+       u32 idx = 0, i;
        struct radeon_cs_packet pkt;
 
        do {
@@ -4695,6 +4695,12 @@ int si_ib_parse(struct radeon_device *rdev, struct radeon_ib *ib)
                switch (pkt.type) {
                case RADEON_PACKET_TYPE0:
                        dev_err(rdev->dev, "Packet0 not allowed!\n");
+                       for (i = 0; i < ib->length_dw; i++) {
+                               if (i == idx)
+                                       printk("\t0x%08x <---\n", ib->ptr[i]);
+                               else
+                                       printk("\t0x%08x\n", ib->ptr[i]);
+                       }
                        ret = -EINVAL;
                        break;
                case RADEON_PACKET_TYPE2:
index 7c22baaf94dbf9ac598f745bfb35b2f5ba5138f2..b58f12b762d797c3c4db418712987cf0da43718d 100644 (file)
@@ -218,18 +218,19 @@ void si_dma_vm_flush(struct radeon_device *rdev, int ridx, struct radeon_vm *vm)
  * @src_offset: src GPU address
  * @dst_offset: dst GPU address
  * @num_gpu_pages: number of GPU pages to xfer
- * @fence: radeon fence object
+ * @resv: reservation object to sync to
  *
  * Copy GPU paging using the DMA engine (SI).
  * Used by the radeon ttm implementation to move pages if
  * registered as the asic copy callback.
  */
-int si_copy_dma(struct radeon_device *rdev,
-               uint64_t src_offset, uint64_t dst_offset,
-               unsigned num_gpu_pages,
-               struct radeon_fence **fence)
+struct radeon_fence *si_copy_dma(struct radeon_device *rdev,
+                                uint64_t src_offset, uint64_t dst_offset,
+                                unsigned num_gpu_pages,
+                                struct reservation_object *resv)
 {
        struct radeon_semaphore *sem = NULL;
+       struct radeon_fence *fence;
        int ring_index = rdev->asic->copy.dma_ring_index;
        struct radeon_ring *ring = &rdev->ring[ring_index];
        u32 size_in_bytes, cur_size_in_bytes;
@@ -239,7 +240,7 @@ int si_copy_dma(struct radeon_device *rdev,
        r = radeon_semaphore_create(rdev, &sem);
        if (r) {
                DRM_ERROR("radeon: moving bo (%d).\n", r);
-               return r;
+               return ERR_PTR(r);
        }
 
        size_in_bytes = (num_gpu_pages << RADEON_GPU_PAGE_SHIFT);
@@ -248,10 +249,10 @@ int si_copy_dma(struct radeon_device *rdev,
        if (r) {
                DRM_ERROR("radeon: moving bo (%d).\n", r);
                radeon_semaphore_free(rdev, &sem, NULL);
-               return r;
+               return ERR_PTR(r);
        }
 
-       radeon_semaphore_sync_to(sem, *fence);
+       radeon_semaphore_sync_resv(rdev, sem, resv, false);
        radeon_semaphore_sync_rings(rdev, sem, ring->idx);
 
        for (i = 0; i < num_loops; i++) {
@@ -268,16 +269,16 @@ int si_copy_dma(struct radeon_device *rdev,
                dst_offset += cur_size_in_bytes;
        }
 
-       r = radeon_fence_emit(rdev, fence, ring->idx);
+       r = radeon_fence_emit(rdev, &fence, ring->idx);
        if (r) {
                radeon_ring_unlock_undo(rdev, ring);
                radeon_semaphore_free(rdev, &sem, NULL);
-               return r;
+               return ERR_PTR(r);
        }
 
        radeon_ring_unlock_commit(rdev, ring, false);
-       radeon_semaphore_free(rdev, &sem, *fence);
+       radeon_semaphore_free(rdev, &sem, fence);
 
-       return r;
+       return fence;
 }
 
index 70e61ffeace245aca431cc13c4fa5f833b0580de..9e4d5d7d348f280881f7065862990095e5cee9df 100644 (file)
@@ -2916,7 +2916,6 @@ static void si_apply_state_adjust_rules(struct radeon_device *rdev,
        bool disable_sclk_switching = false;
        u32 mclk, sclk;
        u16 vddc, vddci;
-       u32 max_sclk_vddc, max_mclk_vddci, max_mclk_vddc;
        int i;
 
        if ((rdev->pm.dpm.new_active_crtc_count > 1) ||
@@ -2950,29 +2949,6 @@ static void si_apply_state_adjust_rules(struct radeon_device *rdev,
                }
        }
 
-       /* limit clocks to max supported clocks based on voltage dependency tables */
-       btc_get_max_clock_from_voltage_dependency_table(&rdev->pm.dpm.dyn_state.vddc_dependency_on_sclk,
-                                                       &max_sclk_vddc);
-       btc_get_max_clock_from_voltage_dependency_table(&rdev->pm.dpm.dyn_state.vddci_dependency_on_mclk,
-                                                       &max_mclk_vddci);
-       btc_get_max_clock_from_voltage_dependency_table(&rdev->pm.dpm.dyn_state.vddc_dependency_on_mclk,
-                                                       &max_mclk_vddc);
-
-       for (i = 0; i < ps->performance_level_count; i++) {
-               if (max_sclk_vddc) {
-                       if (ps->performance_levels[i].sclk > max_sclk_vddc)
-                               ps->performance_levels[i].sclk = max_sclk_vddc;
-               }
-               if (max_mclk_vddci) {
-                       if (ps->performance_levels[i].mclk > max_mclk_vddci)
-                               ps->performance_levels[i].mclk = max_mclk_vddci;
-               }
-               if (max_mclk_vddc) {
-                       if (ps->performance_levels[i].mclk > max_mclk_vddc)
-                               ps->performance_levels[i].mclk = max_mclk_vddc;
-               }
-       }
-
        /* XXX validate the min clocks required for display */
 
        if (disable_mclk_switching) {
index fd414d34d885791ce8b85d303249805eb061ecbe..6635da9ec986f9b4eadfa50021f4f35cafe25a61 100644 (file)
 #       define DESCRIPTION16(x)                          (((x) & 0xff) << 0)
 #       define DESCRIPTION17(x)                          (((x) & 0xff) << 8)
 
-#define AZ_F0_CODEC_PIN_CONTROL_HOTPLUG_CONTROL          0x54
+#define AZ_F0_CODEC_PIN_CONTROL_HOT_PLUG_CONTROL         0x54
 #       define AUDIO_ENABLED                             (1 << 31)
 
 #define AZ_F0_CODEC_PIN_CONTROL_RESPONSE_CONFIGURATION_DEFAULT  0x56
index cda391347286c3545bdd952234b3b5fb7186a5d9..e72b3cb593589876cc8999e8ab913cbf886b64f3 100644 (file)
@@ -22,6 +22,7 @@
  * Authors: Christian König <christian.koenig@amd.com>
  */
 
+#include <linux/firmware.h>
 #include <drm/drmP.h>
 #include "radeon.h"
 #include "radeon_asic.h"
@@ -69,6 +70,82 @@ void uvd_v1_0_set_wptr(struct radeon_device *rdev,
        WREG32(UVD_RBC_RB_WPTR, ring->wptr);
 }
 
+/**
+ * uvd_v1_0_fence_emit - emit an fence & trap command
+ *
+ * @rdev: radeon_device pointer
+ * @fence: fence to emit
+ *
+ * Write a fence and a trap command to the ring.
+ */
+void uvd_v1_0_fence_emit(struct radeon_device *rdev,
+                        struct radeon_fence *fence)
+{
+       struct radeon_ring *ring = &rdev->ring[fence->ring];
+       uint64_t addr = rdev->fence_drv[fence->ring].gpu_addr;
+
+       radeon_ring_write(ring, PACKET0(UVD_GPCOM_VCPU_DATA0, 0));
+       radeon_ring_write(ring, addr & 0xffffffff);
+       radeon_ring_write(ring, PACKET0(UVD_GPCOM_VCPU_DATA1, 0));
+       radeon_ring_write(ring, fence->seq);
+       radeon_ring_write(ring, PACKET0(UVD_GPCOM_VCPU_CMD, 0));
+       radeon_ring_write(ring, 0);
+
+       radeon_ring_write(ring, PACKET0(UVD_GPCOM_VCPU_DATA0, 0));
+       radeon_ring_write(ring, 0);
+       radeon_ring_write(ring, PACKET0(UVD_GPCOM_VCPU_DATA1, 0));
+       radeon_ring_write(ring, 0);
+       radeon_ring_write(ring, PACKET0(UVD_GPCOM_VCPU_CMD, 0));
+       radeon_ring_write(ring, 2);
+       return;
+}
+
+/**
+ * uvd_v1_0_resume - memory controller programming
+ *
+ * @rdev: radeon_device pointer
+ *
+ * Let the UVD memory controller know it's offsets
+ */
+int uvd_v1_0_resume(struct radeon_device *rdev)
+{
+       uint64_t addr;
+       uint32_t size;
+       int r;
+
+       r = radeon_uvd_resume(rdev);
+       if (r)
+               return r;
+
+       /* programm the VCPU memory controller bits 0-27 */
+       addr = (rdev->uvd.gpu_addr >> 3) + 16;
+       size = RADEON_GPU_PAGE_ALIGN(rdev->uvd_fw->size) >> 3;
+       WREG32(UVD_VCPU_CACHE_OFFSET0, addr);
+       WREG32(UVD_VCPU_CACHE_SIZE0, size);
+
+       addr += size;
+       size = RADEON_UVD_STACK_SIZE >> 3;
+       WREG32(UVD_VCPU_CACHE_OFFSET1, addr);
+       WREG32(UVD_VCPU_CACHE_SIZE1, size);
+
+       addr += size;
+       size = RADEON_UVD_HEAP_SIZE >> 3;
+       WREG32(UVD_VCPU_CACHE_OFFSET2, addr);
+       WREG32(UVD_VCPU_CACHE_SIZE2, size);
+
+       /* bits 28-31 */
+       addr = (rdev->uvd.gpu_addr >> 28) & 0xF;
+       WREG32(UVD_LMI_ADDR_EXT, (addr << 12) | (addr << 0));
+
+       /* bits 32-39 */
+       addr = (rdev->uvd.gpu_addr >> 32) & 0xFF;
+       WREG32(UVD_LMI_EXT40_ADDR, addr | (0x9 << 16) | (0x1 << 31));
+
+       WREG32(UVD_FW_START, *((uint32_t*)rdev->uvd.cpu_addr));
+
+       return 0;
+}
+
 /**
  * uvd_v1_0_init - start and test UVD block
  *
@@ -130,8 +207,32 @@ done:
        /* lower clocks again */
        radeon_set_uvd_clocks(rdev, 0, 0);
 
-       if (!r)
+       if (!r) {
+               switch (rdev->family) {
+               case CHIP_RV610:
+               case CHIP_RV630:
+               case CHIP_RV620:
+                       /* 64byte granularity workaround */
+                       WREG32(MC_CONFIG, 0);
+                       WREG32(MC_CONFIG, 1 << 4);
+                       WREG32(RS_DQ_RD_RET_CONF, 0x3f);
+                       WREG32(MC_CONFIG, 0x1f);
+
+                       /* fall through */
+               case CHIP_RV670:
+               case CHIP_RV635:
+
+                       /* write clean workaround */
+                       WREG32_P(UVD_VCPU_CNTL, 0x10, ~0x10);
+                       break;
+
+               default:
+                       /* TODO: Do we need more? */
+                       break;
+               }
+
                DRM_INFO("UVD initialized successfully.\n");
+       }
 
        return r;
 }
@@ -218,12 +319,12 @@ int uvd_v1_0_start(struct radeon_device *rdev)
        /* enable UMC */
        WREG32_P(UVD_LMI_CTRL2, 0, ~(1 << 8));
 
+       WREG32_P(UVD_RB_ARB_CTRL, 0, ~(1 << 3));
+
        /* boot up the VCPU */
        WREG32(UVD_SOFT_RESET, 0);
        mdelay(10);
 
-       WREG32_P(UVD_RB_ARB_CTRL, 0, ~(1 << 3));
-
        for (i = 0; i < 10; ++i) {
                uint32_t status;
                for (j = 0; j < 100; ++j) {
index 8bfdadd5659881d6a47b10ff888592c96417ebee..89193519f8a1faf32fd7fe9013ddd8107cafd977 100644 (file)
@@ -72,6 +72,10 @@ int uvd_v2_2_resume(struct radeon_device *rdev)
        uint32_t chip_id, size;
        int r;
 
+       /* RV770 uses V1.0 MC */
+       if (rdev->family == CHIP_RV770)
+               return uvd_v1_0_resume(rdev);
+
        r = radeon_uvd_resume(rdev);
        if (r)
                return r;
index 2e3d7b5b0ad7d8363c11c7f7942858a88b03f4ed..c96f6089f8bf195377a933a8b1632565ebe49930 100644 (file)
@@ -6,6 +6,7 @@ config DRM_RCAR_DU
        select DRM_KMS_CMA_HELPER
        select DRM_GEM_CMA_HELPER
        select DRM_KMS_FB_HELPER
+       select VIDEOMODE_HELPERS
        help
          Choose this option if you have an R-Car chipset.
          If M is selected the module will be called rcar-du-drm.
index 299267db2898634fae3830c7be1180b1188ec737..148b505891813f65dee9019e24741fd003c4b41c 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * rcar_du_crtc.c  --  R-Car Display Unit CRTCs
  *
- * Copyright (C) 2013 Renesas Corporation
+ * Copyright (C) 2013-2014 Renesas Electronics Corporation
  *
  * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com)
  *
index 43e7575c700c26354d9971ea211ef84a4db2cfc9..e97ae502dec5ffaa50311d84f96d66b17e69ea8b 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * rcar_du_crtc.h  --  R-Car Display Unit CRTCs
  *
- * Copyright (C) 2013 Renesas Corporation
+ * Copyright (C) 2013-2014 Renesas Electronics Corporation
  *
  * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com)
  *
index fda64b7b73e816f80716f0a33b2764a7b4711af1..d212efa6a49510db6b51f60a77357e5b6c5e09a9 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * rcar_du_drv.c  --  R-Car Display Unit DRM driver
  *
- * Copyright (C) 2013 Renesas Corporation
+ * Copyright (C) 2013-2014 Renesas Electronics Corporation
  *
  * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com)
  *
@@ -15,6 +15,7 @@
 #include <linux/io.h>
 #include <linux/mm.h>
 #include <linux/module.h>
+#include <linux/of_device.h>
 #include <linux/platform_device.h>
 #include <linux/pm.h>
 #include <linux/slab.h>
 #include "rcar_du_kms.h"
 #include "rcar_du_regs.h"
 
+/* -----------------------------------------------------------------------------
+ * Device Information
+ */
+
+static const struct rcar_du_device_info rcar_du_r8a7779_info = {
+       .features = 0,
+       .num_crtcs = 2,
+       .routes = {
+               /* R8A7779 has two RGB outputs and one (currently unsupported)
+                * TCON output.
+                */
+               [RCAR_DU_OUTPUT_DPAD0] = {
+                       .possible_crtcs = BIT(0),
+                       .encoder_type = DRM_MODE_ENCODER_NONE,
+                       .port = 0,
+               },
+               [RCAR_DU_OUTPUT_DPAD1] = {
+                       .possible_crtcs = BIT(1) | BIT(0),
+                       .encoder_type = DRM_MODE_ENCODER_NONE,
+                       .port = 1,
+               },
+       },
+       .num_lvds = 0,
+};
+
+static const struct rcar_du_device_info rcar_du_r8a7790_info = {
+       .features = RCAR_DU_FEATURE_CRTC_IRQ_CLOCK | RCAR_DU_FEATURE_DEFR8,
+       .quirks = RCAR_DU_QUIRK_ALIGN_128B | RCAR_DU_QUIRK_LVDS_LANES,
+       .num_crtcs = 3,
+       .routes = {
+               /* R8A7790 has one RGB output, two LVDS outputs and one
+                * (currently unsupported) TCON output.
+                */
+               [RCAR_DU_OUTPUT_DPAD0] = {
+                       .possible_crtcs = BIT(2) | BIT(1) | BIT(0),
+                       .encoder_type = DRM_MODE_ENCODER_NONE,
+                       .port = 0,
+               },
+               [RCAR_DU_OUTPUT_LVDS0] = {
+                       .possible_crtcs = BIT(0),
+                       .encoder_type = DRM_MODE_ENCODER_LVDS,
+                       .port = 1,
+               },
+               [RCAR_DU_OUTPUT_LVDS1] = {
+                       .possible_crtcs = BIT(2) | BIT(1),
+                       .encoder_type = DRM_MODE_ENCODER_LVDS,
+                       .port = 2,
+               },
+       },
+       .num_lvds = 2,
+};
+
+static const struct rcar_du_device_info rcar_du_r8a7791_info = {
+       .features = RCAR_DU_FEATURE_CRTC_IRQ_CLOCK | RCAR_DU_FEATURE_DEFR8,
+       .num_crtcs = 2,
+       .routes = {
+               /* R8A7791 has one RGB output, one LVDS output and one
+                * (currently unsupported) TCON output.
+                */
+               [RCAR_DU_OUTPUT_DPAD0] = {
+                       .possible_crtcs = BIT(1),
+                       .encoder_type = DRM_MODE_ENCODER_NONE,
+                       .port = 0,
+               },
+               [RCAR_DU_OUTPUT_LVDS0] = {
+                       .possible_crtcs = BIT(0),
+                       .encoder_type = DRM_MODE_ENCODER_LVDS,
+                       .port = 1,
+               },
+       },
+       .num_lvds = 1,
+};
+
+static const struct platform_device_id rcar_du_id_table[] = {
+       { "rcar-du-r8a7779", (kernel_ulong_t)&rcar_du_r8a7779_info },
+       { "rcar-du-r8a7790", (kernel_ulong_t)&rcar_du_r8a7790_info },
+       { "rcar-du-r8a7791", (kernel_ulong_t)&rcar_du_r8a7791_info },
+       { }
+};
+
+MODULE_DEVICE_TABLE(platform, rcar_du_id_table);
+
+static const struct of_device_id rcar_du_of_table[] = {
+       { .compatible = "renesas,du-r8a7779", .data = &rcar_du_r8a7779_info },
+       { .compatible = "renesas,du-r8a7790", .data = &rcar_du_r8a7790_info },
+       { .compatible = "renesas,du-r8a7791", .data = &rcar_du_r8a7791_info },
+       { }
+};
+
+MODULE_DEVICE_TABLE(of, rcar_du_of_table);
+
 /* -----------------------------------------------------------------------------
  * DRM operations
  */
@@ -53,12 +145,13 @@ static int rcar_du_unload(struct drm_device *dev)
 static int rcar_du_load(struct drm_device *dev, unsigned long flags)
 {
        struct platform_device *pdev = dev->platformdev;
+       struct device_node *np = pdev->dev.of_node;
        struct rcar_du_platform_data *pdata = pdev->dev.platform_data;
        struct rcar_du_device *rcdu;
        struct resource *mem;
        int ret;
 
-       if (pdata == NULL) {
+       if (pdata == NULL && np == NULL) {
                dev_err(dev->dev, "no platform data\n");
                return -ENODEV;
        }
@@ -71,7 +164,8 @@ static int rcar_du_load(struct drm_device *dev, unsigned long flags)
 
        rcdu->dev = &pdev->dev;
        rcdu->pdata = pdata;
-       rcdu->info = (struct rcar_du_device_info *)pdev->id_entry->driver_data;
+       rcdu->info = np ? of_match_device(rcar_du_of_table, rcdu->dev)->data
+                  : (void *)platform_get_device_id(pdev)->driver_data;
        rcdu->ddev = dev;
        dev->dev_private = rcdu;
 
@@ -158,6 +252,7 @@ static struct drm_driver rcar_du_driver = {
        .unload                 = rcar_du_unload,
        .preclose               = rcar_du_preclose,
        .lastclose              = rcar_du_lastclose,
+       .set_busid              = drm_platform_set_busid,
        .get_vblank_counter     = drm_vblank_count,
        .enable_vblank          = rcar_du_enable_vblank,
        .disable_vblank         = rcar_du_disable_vblank,
@@ -231,77 +326,6 @@ static int rcar_du_remove(struct platform_device *pdev)
        return 0;
 }
 
-static const struct rcar_du_device_info rcar_du_r8a7779_info = {
-       .features = 0,
-       .num_crtcs = 2,
-       .routes = {
-               /* R8A7779 has two RGB outputs and one (currently unsupported)
-                * TCON output.
-                */
-               [RCAR_DU_OUTPUT_DPAD0] = {
-                       .possible_crtcs = BIT(0),
-                       .encoder_type = DRM_MODE_ENCODER_NONE,
-               },
-               [RCAR_DU_OUTPUT_DPAD1] = {
-                       .possible_crtcs = BIT(1) | BIT(0),
-                       .encoder_type = DRM_MODE_ENCODER_NONE,
-               },
-       },
-       .num_lvds = 0,
-};
-
-static const struct rcar_du_device_info rcar_du_r8a7790_info = {
-       .features = RCAR_DU_FEATURE_CRTC_IRQ_CLOCK | RCAR_DU_FEATURE_DEFR8,
-       .quirks = RCAR_DU_QUIRK_ALIGN_128B | RCAR_DU_QUIRK_LVDS_LANES,
-       .num_crtcs = 3,
-       .routes = {
-               /* R8A7790 has one RGB output, two LVDS outputs and one
-                * (currently unsupported) TCON output.
-                */
-               [RCAR_DU_OUTPUT_DPAD0] = {
-                       .possible_crtcs = BIT(2) | BIT(1) | BIT(0),
-                       .encoder_type = DRM_MODE_ENCODER_NONE,
-               },
-               [RCAR_DU_OUTPUT_LVDS0] = {
-                       .possible_crtcs = BIT(0),
-                       .encoder_type = DRM_MODE_ENCODER_LVDS,
-               },
-               [RCAR_DU_OUTPUT_LVDS1] = {
-                       .possible_crtcs = BIT(2) | BIT(1),
-                       .encoder_type = DRM_MODE_ENCODER_LVDS,
-               },
-       },
-       .num_lvds = 2,
-};
-
-static const struct rcar_du_device_info rcar_du_r8a7791_info = {
-       .features = RCAR_DU_FEATURE_CRTC_IRQ_CLOCK | RCAR_DU_FEATURE_DEFR8,
-       .num_crtcs = 2,
-       .routes = {
-               /* R8A7791 has one RGB output, one LVDS output and one
-                * (currently unsupported) TCON output.
-                */
-               [RCAR_DU_OUTPUT_DPAD0] = {
-                       .possible_crtcs = BIT(1),
-                       .encoder_type = DRM_MODE_ENCODER_NONE,
-               },
-               [RCAR_DU_OUTPUT_LVDS0] = {
-                       .possible_crtcs = BIT(0),
-                       .encoder_type = DRM_MODE_ENCODER_LVDS,
-               },
-       },
-       .num_lvds = 1,
-};
-
-static const struct platform_device_id rcar_du_id_table[] = {
-       { "rcar-du-r8a7779", (kernel_ulong_t)&rcar_du_r8a7779_info },
-       { "rcar-du-r8a7790", (kernel_ulong_t)&rcar_du_r8a7790_info },
-       { "rcar-du-r8a7791", (kernel_ulong_t)&rcar_du_r8a7791_info },
-       { }
-};
-
-MODULE_DEVICE_TABLE(platform, rcar_du_id_table);
-
 static struct platform_driver rcar_du_platform_driver = {
        .probe          = rcar_du_probe,
        .remove         = rcar_du_remove,
@@ -309,6 +333,7 @@ static struct platform_driver rcar_du_platform_driver = {
                .owner  = THIS_MODULE,
                .name   = "rcar-du",
                .pm     = &rcar_du_pm_ops,
+               .of_match_table = rcar_du_of_table,
        },
        .id_table       = rcar_du_id_table,
 };
index e31b735d3f258b69b65ab97320ddfe7440d7d6b9..8e494633c3b36325b99833dfd7ed294cab975962 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * rcar_du_drv.h  --  R-Car Display Unit DRM driver
  *
- * Copyright (C) 2013 Renesas Corporation
+ * Copyright (C) 2013-2014 Renesas Electronics Corporation
  *
  * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com)
  *
@@ -37,6 +37,7 @@ struct rcar_du_lvdsenc;
  * struct rcar_du_output_routing - Output routing specification
  * @possible_crtcs: bitmask of possible CRTCs for the output
  * @encoder_type: DRM type of the internal encoder associated with the output
+ * @port: device tree port number corresponding to this output route
  *
  * The DU has 5 possible outputs (DPAD0/1, LVDS0/1, TCON). Output routing data
  * specify the valid SoC outputs, which CRTCs can drive the output, and the type
@@ -45,6 +46,7 @@ struct rcar_du_lvdsenc;
 struct rcar_du_output_routing {
        unsigned int possible_crtcs;
        unsigned int encoder_type;
+       unsigned int port;
 };
 
 /*
index 3daa7a168dc689dba73804863998c5c1de4946ca..7c0ec95915eff1b1a46fb0319f5ae7eea353c26a 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * rcar_du_encoder.c  --  R-Car Display Unit Encoder
  *
- * Copyright (C) 2013 Renesas Corporation
+ * Copyright (C) 2013-2014 Renesas Electronics Corporation
  *
  * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com)
  *
@@ -142,7 +142,8 @@ static const struct drm_encoder_funcs encoder_funcs = {
 int rcar_du_encoder_init(struct rcar_du_device *rcdu,
                         enum rcar_du_encoder_type type,
                         enum rcar_du_output output,
-                        const struct rcar_du_encoder_data *data)
+                        const struct rcar_du_encoder_data *data,
+                        struct device_node *np)
 {
        struct rcar_du_encoder *renc;
        unsigned int encoder_type;
@@ -189,9 +190,11 @@ int rcar_du_encoder_init(struct rcar_du_device *rcdu,
        drm_encoder_helper_add(&renc->encoder, &encoder_helper_funcs);
 
        switch (encoder_type) {
-       case DRM_MODE_ENCODER_LVDS:
-               return rcar_du_lvds_connector_init(rcdu, renc,
-                                                  &data->connector.lvds.panel);
+       case DRM_MODE_ENCODER_LVDS: {
+               const struct rcar_du_panel_data *pdata =
+                       data ? &data->connector.lvds.panel : NULL;
+               return rcar_du_lvds_connector_init(rcdu, renc, pdata, np);
+       }
 
        case DRM_MODE_ENCODER_DAC:
                return rcar_du_vga_connector_init(rcdu, renc);
index 0e5a65e45d0e598d338399b838d1e60d2291f97e..bd624135ef1fbfed3257bc4377b1e17a441b2021 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * rcar_du_encoder.h  --  R-Car Display Unit Encoder
  *
- * Copyright (C) 2013 Renesas Corporation
+ * Copyright (C) 2013-2014 Renesas Electronics Corporation
  *
  * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com)
  *
@@ -44,6 +44,7 @@ rcar_du_connector_best_encoder(struct drm_connector *connector);
 int rcar_du_encoder_init(struct rcar_du_device *rcdu,
                         enum rcar_du_encoder_type type,
                         enum rcar_du_output output,
-                        const struct rcar_du_encoder_data *data);
+                        const struct rcar_du_encoder_data *data,
+                        struct device_node *np);
 
 #endif /* __RCAR_DU_ENCODER_H__ */
index eb53cd97e8c6c3ac282bd5ccd09cd8a637275026..4e7614b145db550d1364723e76dd27ffd36b404f 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * rcar_du_group.c  --  R-Car Display Unit Channels Pair
  *
- * Copyright (C) 2013 Renesas Corporation
+ * Copyright (C) 2013-2014 Renesas Electronics Corporation
  *
  * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com)
  *
index 5025930972ecdd36c2eb652e2931dcfff6788651..0c38cdcda4cae9a0880bf354b7ffd167c16be870 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * rcar_du_group.c  --  R-Car Display Unit Planes and CRTCs Group
  *
- * Copyright (C) 2013 Renesas Corporation
+ * Copyright (C) 2013-2014 Renesas Electronics Corporation
  *
  * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com)
  *
index 76026104d000170838fd5bf34361d30a8b1efa52..6c24ad7d03ef300077cc992b9d3b95fccec2cac1 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * rcar_du_kms.c  --  R-Car Display Unit Mode Setting
  *
- * Copyright (C) 2013 Renesas Corporation
+ * Copyright (C) 2013-2014 Renesas Electronics Corporation
  *
  * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com)
  *
@@ -17,6 +17,8 @@
 #include <drm/drm_fb_cma_helper.h>
 #include <drm/drm_gem_cma_helper.h>
 
+#include <linux/of_graph.h>
+
 #include "rcar_du_crtc.h"
 #include "rcar_du_drv.h"
 #include "rcar_du_encoder.h"
@@ -188,6 +190,205 @@ static const struct drm_mode_config_funcs rcar_du_mode_config_funcs = {
        .output_poll_changed = rcar_du_output_poll_changed,
 };
 
+static int rcar_du_encoders_init_pdata(struct rcar_du_device *rcdu)
+{
+       unsigned int num_encoders = 0;
+       unsigned int i;
+       int ret;
+
+       for (i = 0; i < rcdu->pdata->num_encoders; ++i) {
+               const struct rcar_du_encoder_data *pdata =
+                       &rcdu->pdata->encoders[i];
+               const struct rcar_du_output_routing *route =
+                       &rcdu->info->routes[pdata->output];
+
+               if (pdata->type == RCAR_DU_ENCODER_UNUSED)
+                       continue;
+
+               if (pdata->output >= RCAR_DU_OUTPUT_MAX ||
+                   route->possible_crtcs == 0) {
+                       dev_warn(rcdu->dev,
+                                "encoder %u references unexisting output %u, skipping\n",
+                                i, pdata->output);
+                       continue;
+               }
+
+               ret = rcar_du_encoder_init(rcdu, pdata->type, pdata->output,
+                                          pdata, NULL);
+               if (ret < 0)
+                       return ret;
+
+               num_encoders++;
+       }
+
+       return num_encoders;
+}
+
+static int rcar_du_encoders_init_dt_one(struct rcar_du_device *rcdu,
+                                       enum rcar_du_output output,
+                                       struct of_endpoint *ep)
+{
+       static const struct {
+               const char *compatible;
+               enum rcar_du_encoder_type type;
+       } encoders[] = {
+               { "adi,adv7123", RCAR_DU_ENCODER_VGA },
+               { "thine,thc63lvdm83d", RCAR_DU_ENCODER_LVDS },
+       };
+
+       enum rcar_du_encoder_type enc_type = RCAR_DU_ENCODER_NONE;
+       struct device_node *connector = NULL;
+       struct device_node *encoder = NULL;
+       struct device_node *prev = NULL;
+       struct device_node *entity_ep_node;
+       struct device_node *entity;
+       int ret;
+
+       /*
+        * Locate the connected entity and infer its type from the number of
+        * endpoints.
+        */
+       entity = of_graph_get_remote_port_parent(ep->local_node);
+       if (!entity) {
+               dev_dbg(rcdu->dev, "unconnected endpoint %s, skipping\n",
+                       ep->local_node->full_name);
+               return 0;
+       }
+
+       entity_ep_node = of_parse_phandle(ep->local_node, "remote-endpoint", 0);
+
+       while (1) {
+               struct device_node *ep_node;
+
+               ep_node = of_graph_get_next_endpoint(entity, prev);
+               of_node_put(prev);
+               prev = ep_node;
+
+               if (!ep_node)
+                       break;
+
+               if (ep_node == entity_ep_node)
+                       continue;
+
+               /*
+                * We've found one endpoint other than the input, this must
+                * be an encoder. Locate the connector.
+                */
+               encoder = entity;
+               connector = of_graph_get_remote_port_parent(ep_node);
+               of_node_put(ep_node);
+
+               if (!connector) {
+                       dev_warn(rcdu->dev,
+                                "no connector for encoder %s, skipping\n",
+                                encoder->full_name);
+                       of_node_put(entity_ep_node);
+                       of_node_put(encoder);
+                       return 0;
+               }
+
+               break;
+       }
+
+       of_node_put(entity_ep_node);
+
+       if (encoder) {
+               /*
+                * If an encoder has been found, get its type based on its
+                * compatible string.
+                */
+               unsigned int i;
+
+               for (i = 0; i < ARRAY_SIZE(encoders); ++i) {
+                       if (of_device_is_compatible(encoder,
+                                                   encoders[i].compatible)) {
+                               enc_type = encoders[i].type;
+                               break;
+                       }
+               }
+
+               if (i == ARRAY_SIZE(encoders)) {
+                       dev_warn(rcdu->dev,
+                                "unknown encoder type for %s, skipping\n",
+                                encoder->full_name);
+                       of_node_put(encoder);
+                       of_node_put(connector);
+                       return 0;
+               }
+       } else {
+               /*
+                * If no encoder has been found the entity must be the
+                * connector.
+                */
+               connector = entity;
+       }
+
+       ret = rcar_du_encoder_init(rcdu, enc_type, output, NULL, connector);
+       of_node_put(encoder);
+       of_node_put(connector);
+
+       return ret < 0 ? ret : 1;
+}
+
+static int rcar_du_encoders_init_dt(struct rcar_du_device *rcdu)
+{
+       struct device_node *np = rcdu->dev->of_node;
+       struct device_node *prev = NULL;
+       unsigned int num_encoders = 0;
+
+       /*
+        * Iterate over the endpoints and create one encoder for each output
+        * pipeline.
+        */
+       while (1) {
+               struct device_node *ep_node;
+               enum rcar_du_output output;
+               struct of_endpoint ep;
+               unsigned int i;
+               int ret;
+
+               ep_node = of_graph_get_next_endpoint(np, prev);
+               of_node_put(prev);
+               prev = ep_node;
+
+               if (ep_node == NULL)
+                       break;
+
+               ret = of_graph_parse_endpoint(ep_node, &ep);
+               if (ret < 0) {
+                       of_node_put(ep_node);
+                       return ret;
+               }
+
+               /* Find the output route corresponding to the port number. */
+               for (i = 0; i < RCAR_DU_OUTPUT_MAX; ++i) {
+                       if (rcdu->info->routes[i].possible_crtcs &&
+                           rcdu->info->routes[i].port == ep.port) {
+                               output = i;
+                               break;
+                       }
+               }
+
+               if (i == RCAR_DU_OUTPUT_MAX) {
+                       dev_warn(rcdu->dev,
+                                "port %u references unexisting output, skipping\n",
+                                ep.port);
+                       continue;
+               }
+
+               /* Process the output pipeline. */
+               ret = rcar_du_encoders_init_dt_one(rcdu, output, &ep);
+               if (ret < 0) {
+                       of_node_put(ep_node);
+                       return ret;
+               }
+
+               num_encoders += ret;
+       }
+
+       return num_encoders;
+}
+
 int rcar_du_modeset_init(struct rcar_du_device *rcdu)
 {
        static const unsigned int mmio_offsets[] = {
@@ -197,6 +398,7 @@ int rcar_du_modeset_init(struct rcar_du_device *rcdu)
        struct drm_device *dev = rcdu->ddev;
        struct drm_encoder *encoder;
        struct drm_fbdev_cma *fbdev;
+       unsigned int num_encoders;
        unsigned int num_groups;
        unsigned int i;
        int ret;
@@ -240,28 +442,15 @@ int rcar_du_modeset_init(struct rcar_du_device *rcdu)
        if (ret < 0)
                return ret;
 
-       for (i = 0; i < rcdu->pdata->num_encoders; ++i) {
-               const struct rcar_du_encoder_data *pdata =
-                       &rcdu->pdata->encoders[i];
-               const struct rcar_du_output_routing *route =
-                       &rcdu->info->routes[pdata->output];
-
-               if (pdata->type == RCAR_DU_ENCODER_UNUSED)
-                       continue;
+       if (rcdu->pdata)
+               ret = rcar_du_encoders_init_pdata(rcdu);
+       else
+               ret = rcar_du_encoders_init_dt(rcdu);
 
-               if (pdata->output >= RCAR_DU_OUTPUT_MAX ||
-                   route->possible_crtcs == 0) {
-                       dev_warn(rcdu->dev,
-                                "encoder %u references unexisting output %u, skipping\n",
-                                i, pdata->output);
-                       continue;
-               }
+       if (ret < 0)
+               return ret;
 
-               ret = rcar_du_encoder_init(rcdu, pdata->type, pdata->output,
-                                          pdata);
-               if (ret < 0)
-                       return ret;
-       }
+       num_encoders = ret;
 
        /* Set the possible CRTCs and possible clones. There's always at least
         * one way for all encoders to clone each other, set all bits in the
@@ -273,7 +462,7 @@ int rcar_du_modeset_init(struct rcar_du_device *rcdu)
                        &rcdu->info->routes[renc->output];
 
                encoder->possible_crtcs = route->possible_crtcs;
-               encoder->possible_clones = (1 << rcdu->pdata->num_encoders) - 1;
+               encoder->possible_clones = (1 << num_encoders) - 1;
        }
 
        /* Now that the CRTCs have been initialized register the planes. */
index 5750e6af56557b36b4821953fced65372170fa09..07951d5fe38b92d5b5256a8166dde2498cd1a98a 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * rcar_du_kms.h  --  R-Car Display Unit Mode Setting
  *
- * Copyright (C) 2013 Renesas Corporation
+ * Copyright (C) 2013-2014 Renesas Electronics Corporation
  *
  * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com)
  *
index 21426bd234eb1d24ac2038e8ed58fd813ac61990..115eed20db12abc421eddf7a20db0707c291c4a5 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * rcar_du_lvdscon.c  --  R-Car Display Unit LVDS Connector
  *
- * Copyright (C) 2013 Renesas Corporation
+ * Copyright (C) 2013-2014 Renesas Electronics Corporation
  *
  * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com)
  *
 #include <drm/drm_crtc.h>
 #include <drm/drm_crtc_helper.h>
 
+#include <video/display_timing.h>
+#include <video/of_display_timing.h>
+#include <video/videomode.h>
+
 #include "rcar_du_drv.h"
 #include "rcar_du_encoder.h"
 #include "rcar_du_kms.h"
@@ -23,7 +27,7 @@
 struct rcar_du_lvds_connector {
        struct rcar_du_connector connector;
 
-       const struct rcar_du_panel_data *panel;
+       struct rcar_du_panel_data panel;
 };
 
 #define to_rcar_lvds_connector(c) \
@@ -40,18 +44,9 @@ static int rcar_du_lvds_connector_get_modes(struct drm_connector *connector)
                return 0;
 
        mode->type = DRM_MODE_TYPE_PREFERRED | DRM_MODE_TYPE_DRIVER;
-       mode->clock = lvdscon->panel->mode.clock;
-       mode->hdisplay = lvdscon->panel->mode.hdisplay;
-       mode->hsync_start = lvdscon->panel->mode.hsync_start;
-       mode->hsync_end = lvdscon->panel->mode.hsync_end;
-       mode->htotal = lvdscon->panel->mode.htotal;
-       mode->vdisplay = lvdscon->panel->mode.vdisplay;
-       mode->vsync_start = lvdscon->panel->mode.vsync_start;
-       mode->vsync_end = lvdscon->panel->mode.vsync_end;
-       mode->vtotal = lvdscon->panel->mode.vtotal;
-       mode->flags = lvdscon->panel->mode.flags;
-
-       drm_mode_set_name(mode);
+
+       drm_display_mode_from_videomode(&lvdscon->panel.mode, mode);
+
        drm_mode_probed_add(connector, mode);
 
        return 1;
@@ -83,7 +78,8 @@ static const struct drm_connector_funcs connector_funcs = {
 
 int rcar_du_lvds_connector_init(struct rcar_du_device *rcdu,
                                struct rcar_du_encoder *renc,
-                               const struct rcar_du_panel_data *panel)
+                               const struct rcar_du_panel_data *panel,
+                               /* TODO const */ struct device_node *np)
 {
        struct rcar_du_lvds_connector *lvdscon;
        struct drm_connector *connector;
@@ -93,11 +89,24 @@ int rcar_du_lvds_connector_init(struct rcar_du_device *rcdu,
        if (lvdscon == NULL)
                return -ENOMEM;
 
-       lvdscon->panel = panel;
+       if (panel) {
+               lvdscon->panel = *panel;
+       } else {
+               struct display_timing timing;
+
+               ret = of_get_display_timing(np, "panel-timing", &timing);
+               if (ret < 0)
+                       return ret;
+
+               videomode_from_timing(&timing, &lvdscon->panel.mode);
+
+               of_property_read_u32(np, "width-mm", &lvdscon->panel.width_mm);
+               of_property_read_u32(np, "height-mm", &lvdscon->panel.height_mm);
+       }
 
        connector = &lvdscon->connector.connector;
-       connector->display_info.width_mm = panel->width_mm;
-       connector->display_info.height_mm = panel->height_mm;
+       connector->display_info.width_mm = lvdscon->panel.width_mm;
+       connector->display_info.height_mm = lvdscon->panel.height_mm;
 
        ret = drm_connector_init(rcdu->ddev, connector, &connector_funcs,
                                 DRM_MODE_CONNECTOR_LVDS);
index bff8683699cadd9e996dfa7c98f42dfed4c669c6..d11424d537f90334fe30e9dd7ddd8faf430d9790 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * rcar_du_lvdscon.h  --  R-Car Display Unit LVDS Connector
  *
- * Copyright (C) 2013 Renesas Corporation
+ * Copyright (C) 2013-2014 Renesas Electronics Corporation
  *
  * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com)
  *
@@ -20,6 +20,7 @@ struct rcar_du_panel_data;
 
 int rcar_du_lvds_connector_init(struct rcar_du_device *rcdu,
                                struct rcar_du_encoder *renc,
-                               const struct rcar_du_panel_data *panel);
+                               const struct rcar_du_panel_data *panel,
+                               struct device_node *np);
 
 #endif /* __RCAR_DU_LVDSCON_H__ */
index df30a075d793ce5d97c550c80a2f01ce172fbdc1..7cfb48ce1791a2526c4c8afc33d7c864cabc3094 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * rcar_du_lvdsenc.c  --  R-Car Display Unit LVDS Encoder
  *
- * Copyright (C) 2013 Renesas Corporation
+ * Copyright (C) 2013-2014 Renesas Electronics Corporation
  *
  * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com)
  *
index 7051c6de19ae2ba2eac298e82f71b6d0df0b2c22..3303a55cec79dcfb28b4dff7e53d6ac5e4c1fb2b 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * rcar_du_lvdsenc.h  --  R-Car Display Unit LVDS Encoder
  *
- * Copyright (C) 2013 Renesas Corporation
+ * Copyright (C) 2013-2014 Renesas Electronics Corporation
  *
  * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com)
  *
index 3fb69d9ae61bd15fdea9e1801a5e0c69a19d13df..72a7cb47bd9f8a2e18d846185e9b7a0ee77dcefb 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * rcar_du_plane.c  --  R-Car Display Unit Planes
  *
- * Copyright (C) 2013 Renesas Corporation
+ * Copyright (C) 2013-2014 Renesas Electronics Corporation
  *
  * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com)
  *
index f94f9ce84998782c9720661d068b78dfacc65dc3..3021288b1a892db231024ce8c9adf4d4be939267 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * rcar_du_plane.h  --  R-Car Display Unit Planes
  *
- * Copyright (C) 2013 Renesas Corporation
+ * Copyright (C) 2013-2014 Renesas Electronics Corporation
  *
  * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com)
  *
index 8af3944d31b9a3900afd3b86ec73b86e470a5d3c..564a723ede0374e5def036e085b009bef4b1a954 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * rcar_du_vgacon.c  --  R-Car Display Unit VGA Connector
  *
- * Copyright (C) 2013 Renesas Corporation
+ * Copyright (C) 2013-2014 Renesas Electronics Corporation
  *
  * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com)
  *
index b12b0cf7f117671d585394109a8c274cd553d8e9..112f50316e01d82e1ffe95301d87a5aef3a96c45 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * rcar_du_vgacon.h  --  R-Car Display Unit VGA Connector
  *
- * Copyright (C) 2013 Renesas Corporation
+ * Copyright (C) 2013-2014 Renesas Electronics Corporation
  *
  * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com)
  *
index c97cdc9ab2397696456b5caa58615499e8e67b96..d47dff95fe5283a22e3736d33c399d9adecfb357 100644 (file)
@@ -556,7 +556,7 @@ int savage_driver_load(struct drm_device *dev, unsigned long chipset)
 /*
  * Initialize mappings. On Savage4 and SavageIX the alignment
  * and size of the aperture is not suitable for automatic MTRR setup
- * in drm_addmap. Therefore we add them manually before the maps are
+ * in drm_legacy_addmap. Therefore we add them manually before the maps are
  * initialized, and tear them down on last close.
  */
 int savage_driver_firstopen(struct drm_device *dev)
@@ -624,19 +624,20 @@ int savage_driver_firstopen(struct drm_device *dev)
                /* Automatic MTRR setup will do the right thing. */
        }
 
-       ret = drm_addmap(dev, mmio_base, SAVAGE_MMIO_SIZE, _DRM_REGISTERS,
-                        _DRM_READ_ONLY, &dev_priv->mmio);
+       ret = drm_legacy_addmap(dev, mmio_base, SAVAGE_MMIO_SIZE,
+                               _DRM_REGISTERS, _DRM_READ_ONLY,
+                               &dev_priv->mmio);
        if (ret)
                return ret;
 
-       ret = drm_addmap(dev, fb_base, fb_size, _DRM_FRAME_BUFFER,
-                        _DRM_WRITE_COMBINING, &dev_priv->fb);
+       ret = drm_legacy_addmap(dev, fb_base, fb_size, _DRM_FRAME_BUFFER,
+                               _DRM_WRITE_COMBINING, &dev_priv->fb);
        if (ret)
                return ret;
 
-       ret = drm_addmap(dev, aperture_base, SAVAGE_APERTURE_SIZE,
-                        _DRM_FRAME_BUFFER, _DRM_WRITE_COMBINING,
-                        &dev_priv->aperture);
+       ret = drm_legacy_addmap(dev, aperture_base, SAVAGE_APERTURE_SIZE,
+                               _DRM_FRAME_BUFFER, _DRM_WRITE_COMBINING,
+                               &dev_priv->aperture);
        return ret;
 }
 
@@ -698,14 +699,14 @@ static int savage_do_init_bci(struct drm_device * dev, drm_savage_init_t * init)
        dev_priv->texture_offset = init->texture_offset;
        dev_priv->texture_size = init->texture_size;
 
-       dev_priv->sarea = drm_getsarea(dev);
+       dev_priv->sarea = drm_legacy_getsarea(dev);
        if (!dev_priv->sarea) {
                DRM_ERROR("could not find sarea!\n");
                savage_do_cleanup_bci(dev);
                return -EINVAL;
        }
        if (init->status_offset != 0) {
-               dev_priv->status = drm_core_findmap(dev, init->status_offset);
+               dev_priv->status = drm_legacy_findmap(dev, init->status_offset);
                if (!dev_priv->status) {
                        DRM_ERROR("could not find shadow status region!\n");
                        savage_do_cleanup_bci(dev);
@@ -716,14 +717,14 @@ static int savage_do_init_bci(struct drm_device * dev, drm_savage_init_t * init)
        }
        if (dev_priv->dma_type == SAVAGE_DMA_AGP && init->buffers_offset) {
                dev->agp_buffer_token = init->buffers_offset;
-               dev->agp_buffer_map = drm_core_findmap(dev,
+               dev->agp_buffer_map = drm_legacy_findmap(dev,
                                                       init->buffers_offset);
                if (!dev->agp_buffer_map) {
                        DRM_ERROR("could not find DMA buffer region!\n");
                        savage_do_cleanup_bci(dev);
                        return -EINVAL;
                }
-               drm_core_ioremap(dev->agp_buffer_map, dev);
+               drm_legacy_ioremap(dev->agp_buffer_map, dev);
                if (!dev->agp_buffer_map->handle) {
                        DRM_ERROR("failed to ioremap DMA buffer region!\n");
                        savage_do_cleanup_bci(dev);
@@ -732,7 +733,7 @@ static int savage_do_init_bci(struct drm_device * dev, drm_savage_init_t * init)
        }
        if (init->agp_textures_offset) {
                dev_priv->agp_textures =
-                   drm_core_findmap(dev, init->agp_textures_offset);
+                   drm_legacy_findmap(dev, init->agp_textures_offset);
                if (!dev_priv->agp_textures) {
                        DRM_ERROR("could not find agp texture region!\n");
                        savage_do_cleanup_bci(dev);
@@ -755,7 +756,7 @@ static int savage_do_init_bci(struct drm_device * dev, drm_savage_init_t * init)
                        savage_do_cleanup_bci(dev);
                        return -EINVAL;
                }
-               dev_priv->cmd_dma = drm_core_findmap(dev, init->cmd_dma_offset);
+               dev_priv->cmd_dma = drm_legacy_findmap(dev, init->cmd_dma_offset);
                if (!dev_priv->cmd_dma) {
                        DRM_ERROR("could not find command DMA region!\n");
                        savage_do_cleanup_bci(dev);
@@ -768,7 +769,7 @@ static int savage_do_init_bci(struct drm_device * dev, drm_savage_init_t * init)
                                savage_do_cleanup_bci(dev);
                                return -EINVAL;
                        }
-                       drm_core_ioremap(dev_priv->cmd_dma, dev);
+                       drm_legacy_ioremap(dev_priv->cmd_dma, dev);
                        if (!dev_priv->cmd_dma->handle) {
                                DRM_ERROR("failed to ioremap command "
                                          "DMA region!\n");
@@ -894,11 +895,11 @@ static int savage_do_cleanup_bci(struct drm_device * dev)
        } else if (dev_priv->cmd_dma && dev_priv->cmd_dma->handle &&
                   dev_priv->cmd_dma->type == _DRM_AGP &&
                   dev_priv->dma_type == SAVAGE_DMA_AGP)
-               drm_core_ioremapfree(dev_priv->cmd_dma, dev);
+               drm_legacy_ioremapfree(dev_priv->cmd_dma, dev);
 
        if (dev_priv->dma_type == SAVAGE_DMA_AGP &&
            dev->agp_buffer_map && dev->agp_buffer_map->handle) {
-               drm_core_ioremapfree(dev->agp_buffer_map, dev);
+               drm_legacy_ioremapfree(dev->agp_buffer_map, dev);
                /* make sure the next instance (which may be running
                 * in PCI mode) doesn't try to use an old
                 * agp_buffer_map. */
@@ -1050,7 +1051,7 @@ void savage_reclaim_buffers(struct drm_device *dev, struct drm_file *file_priv)
                return;
 
        if (file_priv->master && file_priv->master->lock.hw_lock) {
-               drm_idlelock_take(&file_priv->master->lock);
+               drm_legacy_idlelock_take(&file_priv->master->lock);
                release_idlelock = 1;
        }
 
@@ -1069,7 +1070,7 @@ void savage_reclaim_buffers(struct drm_device *dev, struct drm_file *file_priv)
        }
 
        if (release_idlelock)
-               drm_idlelock_release(&file_priv->master->lock);
+               drm_legacy_idlelock_release(&file_priv->master->lock);
 }
 
 const struct drm_ioctl_desc savage_ioctls[] = {
index 3c030216e8888a14078af5d67b26399f7dfbf585..21aed1febeb4d12f6fd4d48ff1d257497dc04bc5 100644 (file)
@@ -40,7 +40,7 @@ static const struct file_operations savage_driver_fops = {
        .open = drm_open,
        .release = drm_release,
        .unlocked_ioctl = drm_ioctl,
-       .mmap = drm_mmap,
+       .mmap = drm_legacy_mmap,
        .poll = drm_poll,
 #ifdef CONFIG_COMPAT
        .compat_ioctl = drm_compat_ioctl,
@@ -57,6 +57,7 @@ static struct drm_driver driver = {
        .preclose = savage_reclaim_buffers,
        .lastclose = savage_driver_lastclose,
        .unload = savage_driver_unload,
+       .set_busid = drm_pci_set_busid,
        .ioctls = savage_ioctls,
        .dma_ioctl = savage_bci_buffers,
        .fops = &savage_driver_fops,
index 335f8fcf10416476b3707c37b0779c276f6781ab..37b699571ad0e81d4e40e204bacc551fa94be164 100644 (file)
@@ -26,6 +26,8 @@
 #ifndef __SAVAGE_DRV_H__
 #define __SAVAGE_DRV_H__
 
+#include <drm/drm_legacy.h>
+
 #define DRIVER_AUTHOR  "Felix Kuehling"
 
 #define DRIVER_NAME    "savage"
index 463aee18f77489c3340727293fd0a3d9d1146a2c..33dd41afea0e3d3a5c45b38c7104cfe1d482b588 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * shmob_drm_backlight.c  --  SH Mobile DRM Backlight
  *
- * Copyright (C) 2012 Renesas Corporation
+ * Copyright (C) 2012 Renesas Electronics Corporation
  *
  * Laurent Pinchart (laurent.pinchart@ideasonboard.com)
  *
index 9477595d2ff3aaa1c833e4160820edd206b59bc7..bac719ecc3011c04052ae87800200ad589162acd 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * shmob_drm_backlight.h  --  SH Mobile DRM Backlight
  *
- * Copyright (C) 2012 Renesas Corporation
+ * Copyright (C) 2012 Renesas Electronics Corporation
  *
  * Laurent Pinchart (laurent.pinchart@ideasonboard.com)
  *
index 47875de89010d7a29a5b62e3752ec40d4c201b2c..0ddce4d046d977549650c62de63e559cb999e4ec 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * shmob_drm_crtc.c  --  SH Mobile DRM CRTCs
  *
- * Copyright (C) 2012 Renesas Corporation
+ * Copyright (C) 2012 Renesas Electronics Corporation
  *
  * Laurent Pinchart (laurent.pinchart@ideasonboard.com)
  *
index e5bd109c4c3861fd7adb5b0bc3fa25c6559afcff..eddad6dcc88ab00110057fc27771912f1f14566f 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * shmob_drm_crtc.h  --  SH Mobile DRM CRTCs
  *
- * Copyright (C) 2012 Renesas Corporation
+ * Copyright (C) 2012 Renesas Electronics Corporation
  *
  * Laurent Pinchart (laurent.pinchart@ideasonboard.com)
  *
index ff4ba483b6020798aac9dfb31254dd3067e50a22..e62cbde81e50c05d3551eff25c76d872be6f70e9 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * shmob_drm_drv.c  --  SH Mobile DRM driver
  *
- * Copyright (C) 2012 Renesas Corporation
+ * Copyright (C) 2012 Renesas Electronics Corporation
  *
  * Laurent Pinchart (laurent.pinchart@ideasonboard.com)
  *
@@ -267,6 +267,7 @@ static struct drm_driver shmob_drm_driver = {
        .load                   = shmob_drm_load,
        .unload                 = shmob_drm_unload,
        .preclose               = shmob_drm_preclose,
+       .set_busid              = drm_platform_set_busid,
        .irq_handler            = shmob_drm_irq,
        .get_vblank_counter     = drm_vblank_count,
        .enable_vblank          = shmob_drm_enable_vblank,
index 4d46b811b5a7e7a80c4cc7444404484da48be21e..02ea315ba69ac3a7ec16c5dd2184aaf93f856b74 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * shmob_drm.h  --  SH Mobile DRM driver
  *
- * Copyright (C) 2012 Renesas Corporation
+ * Copyright (C) 2012 Renesas Electronics Corporation
  *
  * Laurent Pinchart (laurent.pinchart@ideasonboard.com)
  *
index fc0ef0ca7d0468694952fc77b022706cc829ae33..aaf98ace4a90cbf87512b35de190e27ddf22efd6 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * shmob_drm_kms.c  --  SH Mobile DRM Mode Setting
  *
- * Copyright (C) 2012 Renesas Corporation
+ * Copyright (C) 2012 Renesas Electronics Corporation
  *
  * Laurent Pinchart (laurent.pinchart@ideasonboard.com)
  *
index 9495c9111308c66b92162a973f43b359b536522b..06d5b7caa0265d64b54913fe2bddf84ea8c3bbc1 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * shmob_drm_kms.h  --  SH Mobile DRM Mode Setting
  *
- * Copyright (C) 2012 Renesas Corporation
+ * Copyright (C) 2012 Renesas Electronics Corporation
  *
  * Laurent Pinchart (laurent.pinchart@ideasonboard.com)
  *
index 060ae03e5f9b7e26ae13ac1fd27c8c11b5e95570..1805bb23b1134c732ff10a415f821106eddab6e4 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * shmob_drm_plane.c  --  SH Mobile DRM Planes
  *
- * Copyright (C) 2012 Renesas Corporation
+ * Copyright (C) 2012 Renesas Electronics Corporation
  *
  * Laurent Pinchart (laurent.pinchart@ideasonboard.com)
  *
index 99623d05e3b0a2e1b7a01180475c45543cf4f27f..a58cc1fc3240a2ec86a97409924061cb12ebf1ae 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * shmob_drm_plane.h  --  SH Mobile DRM Planes
  *
- * Copyright (C) 2012 Renesas Corporation
+ * Copyright (C) 2012 Renesas Electronics Corporation
  *
  * Laurent Pinchart (laurent.pinchart@ideasonboard.com)
  *
index 7923cdd6368e42c7990933b9edb6f8c3e1bb80fc..ea17d4415b9e02c027c5a8cf714d16026321ed45 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * shmob_drm_regs.h  --  SH Mobile DRM registers
  *
- * Copyright (C) 2012 Renesas Corporation
+ * Copyright (C) 2012 Renesas Electronics Corporation
  *
  * Laurent Pinchart (laurent.pinchart@ideasonboard.com)
  *
index 756f787b71439ac42af2b6a723916207165b2382..79bce76cb8f71cc49ca99933cc9dc767d4689151 100644 (file)
@@ -70,7 +70,7 @@ static const struct file_operations sis_driver_fops = {
        .open = drm_open,
        .release = drm_release,
        .unlocked_ioctl = drm_ioctl,
-       .mmap = drm_mmap,
+       .mmap = drm_legacy_mmap,
        .poll = drm_poll,
 #ifdef CONFIG_COMPAT
        .compat_ioctl = drm_compat_ioctl,
@@ -108,6 +108,7 @@ static struct drm_driver driver = {
        .open = sis_driver_open,
        .preclose = sis_reclaim_buffers_locked,
        .postclose = sis_driver_postclose,
+       .set_busid = drm_pci_set_busid,
        .dma_quiescent = sis_idle,
        .lastclose = sis_lastclose,
        .ioctls = sis_ioctls,
index c31c0253054dccda6dcf570abf99c8564f5fc5d8..16f972b2a76a09c8bee6d8b1ce110b0b4572c00c 100644 (file)
@@ -28,6 +28,8 @@
 #ifndef _SIS_DRV_H_
 #define _SIS_DRV_H_
 
+#include <drm/drm_legacy.h>
+
 /* General customization:
  */
 
index 77f288e4a0a63a1ec558e376138230cfed2be7fb..93ad8a5704d19233c173c91d235b26a1f605e535 100644 (file)
@@ -319,12 +319,12 @@ void sis_reclaim_buffers_locked(struct drm_device *dev,
        if (!(file->minor->master && file->master->lock.hw_lock))
                return;
 
-       drm_idlelock_take(&file->master->lock);
+       drm_legacy_idlelock_take(&file->master->lock);
 
        mutex_lock(&dev->struct_mutex);
        if (list_empty(&file_priv->obj_list)) {
                mutex_unlock(&dev->struct_mutex);
-               drm_idlelock_release(&file->master->lock);
+               drm_legacy_idlelock_release(&file->master->lock);
 
                return;
        }
@@ -345,7 +345,7 @@ void sis_reclaim_buffers_locked(struct drm_device *dev,
        }
        mutex_unlock(&dev->struct_mutex);
 
-       drm_idlelock_release(&file->master->lock);
+       drm_legacy_idlelock_release(&file->master->lock);
 
        return;
 }
index 82a51d4884341fac791ad0d41f9371387f6f4666..97bcdac23ae1f0733d87b3cc6f3b071834d1bdba 100644 (file)
@@ -56,8 +56,16 @@ struct sti_vtac_mode {
        u32 phyts_per_pixel;
 };
 
-static const struct sti_vtac_mode vtac_mode_main = {0x2, 0x2, VTAC_5_PPP};
-static const struct sti_vtac_mode vtac_mode_aux = {0x1, 0x0, VTAC_17_PPP};
+static const struct sti_vtac_mode vtac_mode_main = {
+       .vid_in_width = 0x2,
+       .phyts_width = 0x2,
+       .phyts_per_pixel = VTAC_5_PPP,
+};
+static const struct sti_vtac_mode vtac_mode_aux = {
+       .vid_in_width = 0x1,
+       .phyts_width = 0x0,
+       .phyts_per_pixel = VTAC_17_PPP,
+};
 
 /**
  * VTAC structure
index 3492ca5c46d323b6932ee8d917a00af3544bebf2..fab5ebcb0fef09dbaafd4eade233151350d26278 100644 (file)
@@ -36,6 +36,7 @@
 #include "tdfx_drv.h"
 
 #include <drm/drm_pciids.h>
+#include <drm/drm_legacy.h>
 
 static struct pci_device_id pciidlist[] = {
        tdfx_PCI_IDS
@@ -46,7 +47,7 @@ static const struct file_operations tdfx_driver_fops = {
        .open = drm_open,
        .release = drm_release,
        .unlocked_ioctl = drm_ioctl,
-       .mmap = drm_mmap,
+       .mmap = drm_legacy_mmap,
        .poll = drm_poll,
 #ifdef CONFIG_COMPAT
        .compat_ioctl = drm_compat_ioctl,
@@ -55,6 +56,7 @@ static const struct file_operations tdfx_driver_fops = {
 };
 
 static struct drm_driver driver = {
+       .set_busid = drm_pci_set_busid,
        .fops = &tdfx_driver_fops,
        .name = DRIVER_NAME,
        .desc = DRIVER_DESC,
index 708f783ead47682f8ef76e17ebc435a1850f9eb6..d6b55e3e3716c8bcaf9e10d2f6625fbfee981797 100644 (file)
@@ -533,9 +533,9 @@ int tegra_dpaux_train(struct tegra_dpaux *dpaux, struct drm_dp_link *link,
 
        for (i = 0; i < link->num_lanes; i++)
                values[i] = DP_TRAIN_MAX_PRE_EMPHASIS_REACHED |
-                           DP_TRAIN_PRE_EMPHASIS_0 |
+                           DP_TRAIN_PRE_EMPH_LEVEL_0 |
                            DP_TRAIN_MAX_SWING_REACHED |
-                           DP_TRAIN_VOLTAGE_SWING_400;
+                           DP_TRAIN_VOLTAGE_SWING_LEVEL_0;
 
        err = drm_dp_dpcd_write(&dpaux->aux, DP_TRAINING_LANE0_SET, values,
                                link->num_lanes);
index 43a25c853357d4e9b2d51b2049b8a12794bfc714..6538b56780c2a916e817d44080e952c37bba8a89 100644 (file)
@@ -15,6 +15,7 @@
 
 #include <drm/drm.h>
 #include <drm/drmP.h>
+#include <drm/drm_gem.h>
 
 #define TEGRA_BO_BOTTOM_UP (1 << 0)
 
index 6be623b4a86fda98867ee08f1c68428b2cb35687..79a34cbd29f5260df24da1ae86d460e1a0df3c6f 100644 (file)
@@ -84,6 +84,7 @@ static int modeset_init(struct drm_device *dev)
        if ((priv->num_encoders == 0) || (priv->num_connectors == 0)) {
                /* oh nos! */
                dev_err(dev->dev, "no encoders/connectors found\n");
+               drm_mode_config_cleanup(dev);
                return -ENXIO;
        }
 
@@ -172,33 +173,37 @@ static int tilcdc_load(struct drm_device *dev, unsigned long flags)
        dev->dev_private = priv;
 
        priv->wq = alloc_ordered_workqueue("tilcdc", 0);
+       if (!priv->wq) {
+               ret = -ENOMEM;
+               goto fail_free_priv;
+       }
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        if (!res) {
                dev_err(dev->dev, "failed to get memory resource\n");
                ret = -EINVAL;
-               goto fail;
+               goto fail_free_wq;
        }
 
        priv->mmio = ioremap_nocache(res->start, resource_size(res));
        if (!priv->mmio) {
                dev_err(dev->dev, "failed to ioremap\n");
                ret = -ENOMEM;
-               goto fail;
+               goto fail_free_wq;
        }
 
        priv->clk = clk_get(dev->dev, "fck");
        if (IS_ERR(priv->clk)) {
                dev_err(dev->dev, "failed to get functional clock\n");
                ret = -ENODEV;
-               goto fail;
+               goto fail_iounmap;
        }
 
        priv->disp_clk = clk_get(dev->dev, "dpll_disp_ck");
        if (IS_ERR(priv->clk)) {
                dev_err(dev->dev, "failed to get display clock\n");
                ret = -ENODEV;
-               goto fail;
+               goto fail_put_clk;
        }
 
 #ifdef CONFIG_CPU_FREQ
@@ -208,7 +213,7 @@ static int tilcdc_load(struct drm_device *dev, unsigned long flags)
                        CPUFREQ_TRANSITION_NOTIFIER);
        if (ret) {
                dev_err(dev->dev, "failed to register cpufreq notifier\n");
-               goto fail;
+               goto fail_put_disp_clk;
        }
 #endif
 
@@ -253,13 +258,13 @@ static int tilcdc_load(struct drm_device *dev, unsigned long flags)
        ret = modeset_init(dev);
        if (ret < 0) {
                dev_err(dev->dev, "failed to initialize mode setting\n");
-               goto fail;
+               goto fail_cpufreq_unregister;
        }
 
        ret = drm_vblank_init(dev, 1);
        if (ret < 0) {
                dev_err(dev->dev, "failed to initialize vblank\n");
-               goto fail;
+               goto fail_mode_config_cleanup;
        }
 
        pm_runtime_get_sync(dev->dev);
@@ -267,7 +272,7 @@ static int tilcdc_load(struct drm_device *dev, unsigned long flags)
        pm_runtime_put_sync(dev->dev);
        if (ret < 0) {
                dev_err(dev->dev, "failed to install IRQ handler\n");
-               goto fail;
+               goto fail_vblank_cleanup;
        }
 
        platform_set_drvdata(pdev, dev);
@@ -283,13 +288,48 @@ static int tilcdc_load(struct drm_device *dev, unsigned long flags)
        priv->fbdev = drm_fbdev_cma_init(dev, bpp,
                        dev->mode_config.num_crtc,
                        dev->mode_config.num_connector);
+       if (IS_ERR(priv->fbdev)) {
+               ret = PTR_ERR(priv->fbdev);
+               goto fail_irq_uninstall;
+       }
 
        drm_kms_helper_poll_init(dev);
 
        return 0;
 
-fail:
-       tilcdc_unload(dev);
+fail_irq_uninstall:
+       pm_runtime_get_sync(dev->dev);
+       drm_irq_uninstall(dev);
+       pm_runtime_put_sync(dev->dev);
+
+fail_vblank_cleanup:
+       drm_vblank_cleanup(dev);
+
+fail_mode_config_cleanup:
+       drm_mode_config_cleanup(dev);
+
+fail_cpufreq_unregister:
+       pm_runtime_disable(dev->dev);
+#ifdef CONFIG_CPU_FREQ
+       cpufreq_unregister_notifier(&priv->freq_transition,
+                       CPUFREQ_TRANSITION_NOTIFIER);
+fail_put_disp_clk:
+       clk_put(priv->disp_clk);
+#endif
+
+fail_put_clk:
+       clk_put(priv->clk);
+
+fail_iounmap:
+       iounmap(priv->mmio);
+
+fail_free_wq:
+       flush_workqueue(priv->wq);
+       destroy_workqueue(priv->wq);
+
+fail_free_priv:
+       dev->dev_private = NULL;
+       kfree(priv);
        return ret;
 }
 
@@ -502,6 +542,7 @@ static struct drm_driver tilcdc_driver = {
        .unload             = tilcdc_unload,
        .preclose           = tilcdc_preclose,
        .lastclose          = tilcdc_lastclose,
+       .set_busid          = drm_platform_set_busid,
        .irq_handler        = tilcdc_irq,
        .irq_preinstall     = tilcdc_irq_preinstall,
        .irq_postinstall    = tilcdc_irq_postinstall,
index 4c7aa1d8134fa8736c0f31ba28b0f99a9d7259ab..7a0315855e90130d5eaa2f00e76750e59a68853f 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/pinctrl/pinmux.h>
 #include <linux/pinctrl/consumer.h>
 #include <linux/backlight.h>
+#include <linux/gpio/consumer.h>
 #include <video/display_timing.h>
 #include <video/of_display_timing.h>
 #include <video/videomode.h>
@@ -29,6 +30,7 @@ struct panel_module {
        struct tilcdc_panel_info *info;
        struct display_timings *timings;
        struct backlight_device *backlight;
+       struct gpio_desc *enable_gpio;
 };
 #define to_panel_module(x) container_of(x, struct panel_module, base)
 
@@ -55,13 +57,17 @@ static void panel_encoder_dpms(struct drm_encoder *encoder, int mode)
 {
        struct panel_encoder *panel_encoder = to_panel_encoder(encoder);
        struct backlight_device *backlight = panel_encoder->mod->backlight;
+       struct gpio_desc *gpio = panel_encoder->mod->enable_gpio;
 
-       if (!backlight)
-               return;
+       if (backlight) {
+               backlight->props.power = mode == DRM_MODE_DPMS_ON ?
+                                        FB_BLANK_UNBLANK : FB_BLANK_POWERDOWN;
+               backlight_update_status(backlight);
+       }
 
-       backlight->props.power = mode == DRM_MODE_DPMS_ON
-                                    ? FB_BLANK_UNBLANK : FB_BLANK_POWERDOWN;
-       backlight_update_status(backlight);
+       if (gpio)
+               gpiod_set_value_cansleep(gpio,
+                                        mode == DRM_MODE_DPMS_ON ? 1 : 0);
 }
 
 static bool panel_encoder_mode_fixup(struct drm_encoder *encoder,
@@ -311,6 +317,7 @@ static struct tilcdc_panel_info *of_get_panel_info(struct device_node *np)
        info = kzalloc(sizeof(*info), GFP_KERNEL);
        if (!info) {
                pr_err("%s: allocation failed\n", __func__);
+               of_node_put(info_np);
                return NULL;
        }
 
@@ -331,22 +338,21 @@ static struct tilcdc_panel_info *of_get_panel_info(struct device_node *np)
        if (ret) {
                pr_err("%s: error reading panel-info properties\n", __func__);
                kfree(info);
+               of_node_put(info_np);
                return NULL;
        }
+       of_node_put(info_np);
 
        return info;
 }
 
-static struct of_device_id panel_of_match[];
-
 static int panel_probe(struct platform_device *pdev)
 {
-       struct device_node *node = pdev->dev.of_node;
+       struct device_node *bl_node, *node = pdev->dev.of_node;
        struct panel_module *panel_mod;
        struct tilcdc_module *mod;
        struct pinctrl *pinctrl;
-       int ret = -EINVAL;
-
+       int ret;
 
        /* bail out early if no DT data: */
        if (!node) {
@@ -354,10 +360,40 @@ static int panel_probe(struct platform_device *pdev)
                return -ENXIO;
        }
 
-       panel_mod = kzalloc(sizeof(*panel_mod), GFP_KERNEL);
+       panel_mod = devm_kzalloc(&pdev->dev, sizeof(*panel_mod), GFP_KERNEL);
        if (!panel_mod)
                return -ENOMEM;
 
+       bl_node = of_parse_phandle(node, "backlight", 0);
+       if (bl_node) {
+               panel_mod->backlight = of_find_backlight_by_node(bl_node);
+               of_node_put(bl_node);
+
+               if (!panel_mod->backlight)
+                       return -EPROBE_DEFER;
+
+               dev_info(&pdev->dev, "found backlight\n");
+       }
+
+       panel_mod->enable_gpio = devm_gpiod_get(&pdev->dev, "enable");
+       if (IS_ERR(panel_mod->enable_gpio)) {
+               ret = PTR_ERR(panel_mod->enable_gpio);
+               if (ret != -ENOENT) {
+                       dev_err(&pdev->dev, "failed to request enable GPIO\n");
+                       goto fail_backlight;
+               }
+
+               /* Optional GPIO is not here, continue silently. */
+               panel_mod->enable_gpio = NULL;
+       } else {
+               ret = gpiod_direction_output(panel_mod->enable_gpio, 0);
+               if (ret < 0) {
+                       dev_err(&pdev->dev, "failed to setup GPIO\n");
+                       goto fail_backlight;
+               }
+               dev_info(&pdev->dev, "found enable GPIO\n");
+       }
+
        mod = &panel_mod->base;
        pdev->dev.platform_data = mod;
 
@@ -370,29 +406,30 @@ static int panel_probe(struct platform_device *pdev)
        panel_mod->timings = of_get_display_timings(node);
        if (!panel_mod->timings) {
                dev_err(&pdev->dev, "could not get panel timings\n");
+               ret = -EINVAL;
                goto fail_free;
        }
 
        panel_mod->info = of_get_panel_info(node);
        if (!panel_mod->info) {
                dev_err(&pdev->dev, "could not get panel info\n");
+               ret = -EINVAL;
                goto fail_timings;
        }
 
        mod->preferred_bpp = panel_mod->info->bpp;
 
-       panel_mod->backlight = of_find_backlight_by_node(node);
-       if (panel_mod->backlight)
-               dev_info(&pdev->dev, "found backlight\n");
-
        return 0;
 
 fail_timings:
        display_timings_release(panel_mod->timings);
 
 fail_free:
-       kfree(panel_mod);
        tilcdc_module_cleanup(mod);
+
+fail_backlight:
+       if (panel_mod->backlight)
+               put_device(&panel_mod->backlight->dev);
        return ret;
 }
 
@@ -400,12 +437,15 @@ static int panel_remove(struct platform_device *pdev)
 {
        struct tilcdc_module *mod = dev_get_platdata(&pdev->dev);
        struct panel_module *panel_mod = to_panel_module(mod);
+       struct backlight_device *backlight = panel_mod->backlight;
+
+       if (backlight)
+               put_device(&backlight->dev);
 
        display_timings_release(panel_mod->timings);
 
        tilcdc_module_cleanup(mod);
        kfree(panel_mod->info);
-       kfree(panel_mod);
 
        return 0;
 }
index 3da89d5dab60493ebc0b06811cab2800c266967e..8f5cec67c47dd6b8976af0709bae49105b67ed49 100644 (file)
@@ -40,6 +40,7 @@
 #include <linux/file.h>
 #include <linux/module.h>
 #include <linux/atomic.h>
+#include <linux/reservation.h>
 
 #define TTM_ASSERT_LOCKED(param)
 #define TTM_DEBUG(fmt, arg...)
@@ -53,12 +54,13 @@ static struct attribute ttm_bo_count = {
        .mode = S_IRUGO
 };
 
-static inline int ttm_mem_type_from_flags(uint32_t flags, uint32_t *mem_type)
+static inline int ttm_mem_type_from_place(const struct ttm_place *place,
+                                         uint32_t *mem_type)
 {
        int i;
 
        for (i = 0; i <= TTM_PL_PRIV5; i++)
-               if (flags & (1 << i)) {
+               if (place->flags & (1 << i)) {
                        *mem_type = i;
                        return 0;
                }
@@ -89,12 +91,12 @@ static void ttm_bo_mem_space_debug(struct ttm_buffer_object *bo,
               bo, bo->mem.num_pages, bo->mem.size >> 10,
               bo->mem.size >> 20);
        for (i = 0; i < placement->num_placement; i++) {
-               ret = ttm_mem_type_from_flags(placement->placement[i],
+               ret = ttm_mem_type_from_place(&placement->placement[i],
                                                &mem_type);
                if (ret)
                        return;
                pr_err("  placement[%d]=0x%08X (%d)\n",
-                      i, placement->placement[i], mem_type);
+                      i, placement->placement[i].flags, mem_type);
                ttm_mem_type_debug(bo->bdev, mem_type);
        }
 }
@@ -141,7 +143,6 @@ static void ttm_bo_release_list(struct kref *list_kref)
        BUG_ON(atomic_read(&bo->list_kref.refcount));
        BUG_ON(atomic_read(&bo->kref.refcount));
        BUG_ON(atomic_read(&bo->cpu_writers));
-       BUG_ON(bo->sync_obj != NULL);
        BUG_ON(bo->mem.mm_node != NULL);
        BUG_ON(!list_empty(&bo->lru));
        BUG_ON(!list_empty(&bo->ddestroy));
@@ -402,36 +403,48 @@ static void ttm_bo_cleanup_memtype_use(struct ttm_buffer_object *bo)
        ww_mutex_unlock (&bo->resv->lock);
 }
 
+static void ttm_bo_flush_all_fences(struct ttm_buffer_object *bo)
+{
+       struct reservation_object_list *fobj;
+       struct fence *fence;
+       int i;
+
+       fobj = reservation_object_get_list(bo->resv);
+       fence = reservation_object_get_excl(bo->resv);
+       if (fence && !fence->ops->signaled)
+               fence_enable_sw_signaling(fence);
+
+       for (i = 0; fobj && i < fobj->shared_count; ++i) {
+               fence = rcu_dereference_protected(fobj->shared[i],
+                                       reservation_object_held(bo->resv));
+
+               if (!fence->ops->signaled)
+                       fence_enable_sw_signaling(fence);
+       }
+}
+
 static void ttm_bo_cleanup_refs_or_queue(struct ttm_buffer_object *bo)
 {
        struct ttm_bo_device *bdev = bo->bdev;
        struct ttm_bo_global *glob = bo->glob;
-       struct ttm_bo_driver *driver = bdev->driver;
-       void *sync_obj = NULL;
        int put_count;
        int ret;
 
        spin_lock(&glob->lru_lock);
        ret = __ttm_bo_reserve(bo, false, true, false, NULL);
 
-       spin_lock(&bdev->fence_lock);
-       (void) ttm_bo_wait(bo, false, false, true);
-       if (!ret && !bo->sync_obj) {
-               spin_unlock(&bdev->fence_lock);
-               put_count = ttm_bo_del_from_lru(bo);
-
-               spin_unlock(&glob->lru_lock);
-               ttm_bo_cleanup_memtype_use(bo);
+       if (!ret) {
+               if (!ttm_bo_wait(bo, false, false, true)) {
+                       put_count = ttm_bo_del_from_lru(bo);
 
-               ttm_bo_list_ref_sub(bo, put_count, true);
+                       spin_unlock(&glob->lru_lock);
+                       ttm_bo_cleanup_memtype_use(bo);
 
-               return;
-       }
-       if (bo->sync_obj)
-               sync_obj = driver->sync_obj_ref(bo->sync_obj);
-       spin_unlock(&bdev->fence_lock);
+                       ttm_bo_list_ref_sub(bo, put_count, true);
 
-       if (!ret) {
+                       return;
+               } else
+                       ttm_bo_flush_all_fences(bo);
 
                /*
                 * Make NO_EVICT bos immediately available to
@@ -450,10 +463,6 @@ static void ttm_bo_cleanup_refs_or_queue(struct ttm_buffer_object *bo)
        list_add_tail(&bo->ddestroy, &bdev->ddestroy);
        spin_unlock(&glob->lru_lock);
 
-       if (sync_obj) {
-               driver->sync_obj_flush(sync_obj);
-               driver->sync_obj_unref(&sync_obj);
-       }
        schedule_delayed_work(&bdev->wq,
                              ((HZ / 100) < 1) ? 1 : HZ / 100);
 }
@@ -474,44 +483,26 @@ static int ttm_bo_cleanup_refs_and_unlock(struct ttm_buffer_object *bo,
                                          bool interruptible,
                                          bool no_wait_gpu)
 {
-       struct ttm_bo_device *bdev = bo->bdev;
-       struct ttm_bo_driver *driver = bdev->driver;
        struct ttm_bo_global *glob = bo->glob;
        int put_count;
        int ret;
 
-       spin_lock(&bdev->fence_lock);
        ret = ttm_bo_wait(bo, false, false, true);
 
        if (ret && !no_wait_gpu) {
-               void *sync_obj;
-
-               /*
-                * Take a reference to the fence and unreserve,
-                * at this point the buffer should be dead, so
-                * no new sync objects can be attached.
-                */
-               sync_obj = driver->sync_obj_ref(bo->sync_obj);
-               spin_unlock(&bdev->fence_lock);
-
-               __ttm_bo_unreserve(bo);
+               long lret;
+               ww_mutex_unlock(&bo->resv->lock);
                spin_unlock(&glob->lru_lock);
 
-               ret = driver->sync_obj_wait(sync_obj, false, interruptible);
-               driver->sync_obj_unref(&sync_obj);
-               if (ret)
-                       return ret;
+               lret = reservation_object_wait_timeout_rcu(bo->resv,
+                                                          true,
+                                                          interruptible,
+                                                          30 * HZ);
 
-               /*
-                * remove sync_obj with ttm_bo_wait, the wait should be
-                * finished, and no new wait object should have been added.
-                */
-               spin_lock(&bdev->fence_lock);
-               ret = ttm_bo_wait(bo, false, false, true);
-               WARN_ON(ret);
-               spin_unlock(&bdev->fence_lock);
-               if (ret)
-                       return ret;
+               if (lret < 0)
+                       return lret;
+               else if (lret == 0)
+                       return -EBUSY;
 
                spin_lock(&glob->lru_lock);
                ret = __ttm_bo_reserve(bo, false, true, false, NULL);
@@ -528,8 +519,14 @@ static int ttm_bo_cleanup_refs_and_unlock(struct ttm_buffer_object *bo,
                        spin_unlock(&glob->lru_lock);
                        return 0;
                }
-       } else
-               spin_unlock(&bdev->fence_lock);
+
+               /*
+                * remove sync_obj with ttm_bo_wait, the wait should be
+                * finished, and no new wait object should have been added.
+                */
+               ret = ttm_bo_wait(bo, false, false, true);
+               WARN_ON(ret);
+       }
 
        if (ret || unlikely(list_empty(&bo->ddestroy))) {
                __ttm_bo_unreserve(bo);
@@ -667,9 +664,7 @@ static int ttm_bo_evict(struct ttm_buffer_object *bo, bool interruptible,
        struct ttm_placement placement;
        int ret = 0;
 
-       spin_lock(&bdev->fence_lock);
        ret = ttm_bo_wait(bo, false, interruptible, no_wait_gpu);
-       spin_unlock(&bdev->fence_lock);
 
        if (unlikely(ret != 0)) {
                if (ret != -ERESTARTSYS) {
@@ -685,8 +680,6 @@ static int ttm_bo_evict(struct ttm_buffer_object *bo, bool interruptible,
        evict_mem.bus.io_reserved_vm = false;
        evict_mem.bus.io_reserved_count = 0;
 
-       placement.fpfn = 0;
-       placement.lpfn = 0;
        placement.num_placement = 0;
        placement.num_busy_placement = 0;
        bdev->driver->evict_flags(bo, &placement);
@@ -774,7 +767,7 @@ EXPORT_SYMBOL(ttm_bo_mem_put);
  */
 static int ttm_bo_mem_force_space(struct ttm_buffer_object *bo,
                                        uint32_t mem_type,
-                                       struct ttm_placement *placement,
+                                       const struct ttm_place *place,
                                        struct ttm_mem_reg *mem,
                                        bool interruptible,
                                        bool no_wait_gpu)
@@ -784,7 +777,7 @@ static int ttm_bo_mem_force_space(struct ttm_buffer_object *bo,
        int ret;
 
        do {
-               ret = (*man->func->get_node)(man, bo, placement, 0, mem);
+               ret = (*man->func->get_node)(man, bo, place, mem);
                if (unlikely(ret != 0))
                        return ret;
                if (mem->mm_node)
@@ -827,18 +820,18 @@ static uint32_t ttm_bo_select_caching(struct ttm_mem_type_manager *man,
 
 static bool ttm_bo_mt_compatible(struct ttm_mem_type_manager *man,
                                 uint32_t mem_type,
-                                uint32_t proposed_placement,
+                                const struct ttm_place *place,
                                 uint32_t *masked_placement)
 {
        uint32_t cur_flags = ttm_bo_type_flags(mem_type);
 
-       if ((cur_flags & proposed_placement & TTM_PL_MASK_MEM) == 0)
+       if ((cur_flags & place->flags & TTM_PL_MASK_MEM) == 0)
                return false;
 
-       if ((proposed_placement & man->available_caching) == 0)
+       if ((place->flags & man->available_caching) == 0)
                return false;
 
-       cur_flags |= (proposed_placement & man->available_caching);
+       cur_flags |= (place->flags & man->available_caching);
 
        *masked_placement = cur_flags;
        return true;
@@ -869,15 +862,14 @@ int ttm_bo_mem_space(struct ttm_buffer_object *bo,
 
        mem->mm_node = NULL;
        for (i = 0; i < placement->num_placement; ++i) {
-               ret = ttm_mem_type_from_flags(placement->placement[i],
-                                               &mem_type);
+               const struct ttm_place *place = &placement->placement[i];
+
+               ret = ttm_mem_type_from_place(place, &mem_type);
                if (ret)
                        return ret;
                man = &bdev->man[mem_type];
 
-               type_ok = ttm_bo_mt_compatible(man,
-                                               mem_type,
-                                               placement->placement[i],
+               type_ok = ttm_bo_mt_compatible(man, mem_type, place,
                                                &cur_flags);
 
                if (!type_ok)
@@ -889,7 +881,7 @@ int ttm_bo_mem_space(struct ttm_buffer_object *bo,
                 * Use the access and other non-mapping-related flag bits from
                 * the memory placement flags to the current flags
                 */
-               ttm_flag_masked(&cur_flags, placement->placement[i],
+               ttm_flag_masked(&cur_flags, place->flags,
                                ~TTM_PL_MASK_MEMTYPE);
 
                if (mem_type == TTM_PL_SYSTEM)
@@ -897,8 +889,7 @@ int ttm_bo_mem_space(struct ttm_buffer_object *bo,
 
                if (man->has_type && man->use_type) {
                        type_found = true;
-                       ret = (*man->func->get_node)(man, bo, placement,
-                                                    cur_flags, mem);
+                       ret = (*man->func->get_node)(man, bo, place, mem);
                        if (unlikely(ret))
                                return ret;
                }
@@ -916,17 +907,15 @@ int ttm_bo_mem_space(struct ttm_buffer_object *bo,
                return -EINVAL;
 
        for (i = 0; i < placement->num_busy_placement; ++i) {
-               ret = ttm_mem_type_from_flags(placement->busy_placement[i],
-                                               &mem_type);
+               const struct ttm_place *place = &placement->busy_placement[i];
+
+               ret = ttm_mem_type_from_place(place, &mem_type);
                if (ret)
                        return ret;
                man = &bdev->man[mem_type];
                if (!man->has_type)
                        continue;
-               if (!ttm_bo_mt_compatible(man,
-                                               mem_type,
-                                               placement->busy_placement[i],
-                                               &cur_flags))
+               if (!ttm_bo_mt_compatible(man, mem_type, place, &cur_flags))
                        continue;
 
                cur_flags = ttm_bo_select_caching(man, bo->mem.placement,
@@ -935,7 +924,7 @@ int ttm_bo_mem_space(struct ttm_buffer_object *bo,
                 * Use the access and other non-mapping-related flag bits from
                 * the memory placement flags to the current flags
                 */
-               ttm_flag_masked(&cur_flags, placement->busy_placement[i],
+               ttm_flag_masked(&cur_flags, place->flags,
                                ~TTM_PL_MASK_MEMTYPE);
 
                if (mem_type == TTM_PL_SYSTEM) {
@@ -945,7 +934,7 @@ int ttm_bo_mem_space(struct ttm_buffer_object *bo,
                        return 0;
                }
 
-               ret = ttm_bo_mem_force_space(bo, mem_type, placement, mem,
+               ret = ttm_bo_mem_force_space(bo, mem_type, place, mem,
                                                interruptible, no_wait_gpu);
                if (ret == 0 && mem->mm_node) {
                        mem->placement = cur_flags;
@@ -966,7 +955,6 @@ static int ttm_bo_move_buffer(struct ttm_buffer_object *bo,
 {
        int ret = 0;
        struct ttm_mem_reg mem;
-       struct ttm_bo_device *bdev = bo->bdev;
 
        lockdep_assert_held(&bo->resv->lock.base);
 
@@ -975,9 +963,7 @@ static int ttm_bo_move_buffer(struct ttm_buffer_object *bo,
         * Have the driver move function wait for idle when necessary,
         * instead of doing it here.
         */
-       spin_lock(&bdev->fence_lock);
        ret = ttm_bo_wait(bo, false, interruptible, no_wait_gpu);
-       spin_unlock(&bdev->fence_lock);
        if (ret)
                return ret;
        mem.num_pages = bo->num_pages;
@@ -1006,20 +992,27 @@ static bool ttm_bo_mem_compat(struct ttm_placement *placement,
 {
        int i;
 
-       if (mem->mm_node && placement->lpfn != 0 &&
-           (mem->start < placement->fpfn ||
-            mem->start + mem->num_pages > placement->lpfn))
-               return false;
-
        for (i = 0; i < placement->num_placement; i++) {
-               *new_flags = placement->placement[i];
+               const struct ttm_place *heap = &placement->placement[i];
+               if (mem->mm_node && heap->lpfn != 0 &&
+                   (mem->start < heap->fpfn ||
+                    mem->start + mem->num_pages > heap->lpfn))
+                       continue;
+
+               *new_flags = heap->flags;
                if ((*new_flags & mem->placement & TTM_PL_MASK_CACHING) &&
                    (*new_flags & mem->placement & TTM_PL_MASK_MEM))
                        return true;
        }
 
        for (i = 0; i < placement->num_busy_placement; i++) {
-               *new_flags = placement->busy_placement[i];
+               const struct ttm_place *heap = &placement->busy_placement[i];
+               if (mem->mm_node && heap->lpfn != 0 &&
+                   (mem->start < heap->fpfn ||
+                    mem->start + mem->num_pages > heap->lpfn))
+                       continue;
+
+               *new_flags = heap->flags;
                if ((*new_flags & mem->placement & TTM_PL_MASK_CACHING) &&
                    (*new_flags & mem->placement & TTM_PL_MASK_MEM))
                        return true;
@@ -1037,11 +1030,6 @@ int ttm_bo_validate(struct ttm_buffer_object *bo,
        uint32_t new_flags;
 
        lockdep_assert_held(&bo->resv->lock.base);
-       /* Check that range is valid */
-       if (placement->lpfn || placement->fpfn)
-               if (placement->fpfn > placement->lpfn ||
-                       (placement->lpfn - placement->fpfn) < bo->num_pages)
-                       return -EINVAL;
        /*
         * Check whether we need to move buffer.
         */
@@ -1070,15 +1058,6 @@ int ttm_bo_validate(struct ttm_buffer_object *bo,
 }
 EXPORT_SYMBOL(ttm_bo_validate);
 
-int ttm_bo_check_placement(struct ttm_buffer_object *bo,
-                               struct ttm_placement *placement)
-{
-       BUG_ON((placement->fpfn || placement->lpfn) &&
-              (bo->mem.num_pages > (placement->lpfn - placement->fpfn)));
-
-       return 0;
-}
-
 int ttm_bo_init(struct ttm_bo_device *bdev,
                struct ttm_buffer_object *bo,
                unsigned long size,
@@ -1089,6 +1068,7 @@ int ttm_bo_init(struct ttm_bo_device *bdev,
                struct file *persistent_swap_storage,
                size_t acc_size,
                struct sg_table *sg,
+               struct reservation_object *resv,
                void (*destroy) (struct ttm_buffer_object *))
 {
        int ret = 0;
@@ -1142,30 +1122,38 @@ int ttm_bo_init(struct ttm_bo_device *bdev,
        bo->persistent_swap_storage = persistent_swap_storage;
        bo->acc_size = acc_size;
        bo->sg = sg;
-       bo->resv = &bo->ttm_resv;
-       reservation_object_init(bo->resv);
+       if (resv) {
+               bo->resv = resv;
+               lockdep_assert_held(&bo->resv->lock.base);
+       } else {
+               bo->resv = &bo->ttm_resv;
+               reservation_object_init(&bo->ttm_resv);
+       }
        atomic_inc(&bo->glob->bo_count);
        drm_vma_node_reset(&bo->vma_node);
 
-       ret = ttm_bo_check_placement(bo, placement);
-
        /*
         * For ttm_bo_type_device buffers, allocate
         * address space from the device.
         */
-       if (likely(!ret) &&
-           (bo->type == ttm_bo_type_device ||
-            bo->type == ttm_bo_type_sg))
+       if (bo->type == ttm_bo_type_device ||
+           bo->type == ttm_bo_type_sg)
                ret = drm_vma_offset_add(&bdev->vma_manager, &bo->vma_node,
                                         bo->mem.num_pages);
 
-       locked = ww_mutex_trylock(&bo->resv->lock);
-       WARN_ON(!locked);
+       /* passed reservation objects should already be locked,
+        * since otherwise lockdep will be angered in radeon.
+        */
+       if (!resv) {
+               locked = ww_mutex_trylock(&bo->resv->lock);
+               WARN_ON(!locked);
+       }
 
        if (likely(!ret))
                ret = ttm_bo_validate(bo, placement, interruptible, false);
 
-       ttm_bo_unreserve(bo);
+       if (!resv)
+               ttm_bo_unreserve(bo);
 
        if (unlikely(ret))
                ttm_bo_unref(&bo);
@@ -1223,7 +1211,7 @@ int ttm_bo_create(struct ttm_bo_device *bdev,
        acc_size = ttm_bo_acc_size(bdev, size, sizeof(struct ttm_buffer_object));
        ret = ttm_bo_init(bdev, bo, size, type, placement, page_alignment,
                          interruptible, persistent_swap_storage, acc_size,
-                         NULL, NULL);
+                         NULL, NULL, NULL);
        if (likely(ret == 0))
                *p_bo = bo;
 
@@ -1477,7 +1465,6 @@ int ttm_bo_device_init(struct ttm_bo_device *bdev,
        bdev->glob = glob;
        bdev->need_dma32 = need_dma32;
        bdev->val_seq = 0;
-       spin_lock_init(&bdev->fence_lock);
        mutex_lock(&glob->device_list_mutex);
        list_add_tail(&bdev->device_list, &glob->device_list);
        mutex_unlock(&glob->device_list_mutex);
@@ -1530,65 +1517,56 @@ void ttm_bo_unmap_virtual(struct ttm_buffer_object *bo)
 
 EXPORT_SYMBOL(ttm_bo_unmap_virtual);
 
-
 int ttm_bo_wait(struct ttm_buffer_object *bo,
                bool lazy, bool interruptible, bool no_wait)
 {
-       struct ttm_bo_driver *driver = bo->bdev->driver;
-       struct ttm_bo_device *bdev = bo->bdev;
-       void *sync_obj;
-       int ret = 0;
-
-       if (likely(bo->sync_obj == NULL))
-               return 0;
+       struct reservation_object_list *fobj;
+       struct reservation_object *resv;
+       struct fence *excl;
+       long timeout = 15 * HZ;
+       int i;
 
-       while (bo->sync_obj) {
+       resv = bo->resv;
+       fobj = reservation_object_get_list(resv);
+       excl = reservation_object_get_excl(resv);
+       if (excl) {
+               if (!fence_is_signaled(excl)) {
+                       if (no_wait)
+                               return -EBUSY;
 
-               if (driver->sync_obj_signaled(bo->sync_obj)) {
-                       void *tmp_obj = bo->sync_obj;
-                       bo->sync_obj = NULL;
-                       clear_bit(TTM_BO_PRIV_FLAG_MOVING, &bo->priv_flags);
-                       spin_unlock(&bdev->fence_lock);
-                       driver->sync_obj_unref(&tmp_obj);
-                       spin_lock(&bdev->fence_lock);
-                       continue;
+                       timeout = fence_wait_timeout(excl,
+                                                    interruptible, timeout);
                }
+       }
 
-               if (no_wait)
-                       return -EBUSY;
+       for (i = 0; fobj && timeout > 0 && i < fobj->shared_count; ++i) {
+               struct fence *fence;
+               fence = rcu_dereference_protected(fobj->shared[i],
+                                               reservation_object_held(resv));
 
-               sync_obj = driver->sync_obj_ref(bo->sync_obj);
-               spin_unlock(&bdev->fence_lock);
-               ret = driver->sync_obj_wait(sync_obj,
-                                           lazy, interruptible);
-               if (unlikely(ret != 0)) {
-                       driver->sync_obj_unref(&sync_obj);
-                       spin_lock(&bdev->fence_lock);
-                       return ret;
-               }
-               spin_lock(&bdev->fence_lock);
-               if (likely(bo->sync_obj == sync_obj)) {
-                       void *tmp_obj = bo->sync_obj;
-                       bo->sync_obj = NULL;
-                       clear_bit(TTM_BO_PRIV_FLAG_MOVING,
-                                 &bo->priv_flags);
-                       spin_unlock(&bdev->fence_lock);
-                       driver->sync_obj_unref(&sync_obj);
-                       driver->sync_obj_unref(&tmp_obj);
-                       spin_lock(&bdev->fence_lock);
-               } else {
-                       spin_unlock(&bdev->fence_lock);
-                       driver->sync_obj_unref(&sync_obj);
-                       spin_lock(&bdev->fence_lock);
+               if (!fence_is_signaled(fence)) {
+                       if (no_wait)
+                               return -EBUSY;
+
+                       timeout = fence_wait_timeout(fence,
+                                                    interruptible, timeout);
                }
        }
+
+       if (timeout < 0)
+               return timeout;
+
+       if (timeout == 0)
+               return -EBUSY;
+
+       reservation_object_add_excl_fence(resv, NULL);
+       clear_bit(TTM_BO_PRIV_FLAG_MOVING, &bo->priv_flags);
        return 0;
 }
 EXPORT_SYMBOL(ttm_bo_wait);
 
 int ttm_bo_synccpu_write_grab(struct ttm_buffer_object *bo, bool no_wait)
 {
-       struct ttm_bo_device *bdev = bo->bdev;
        int ret = 0;
 
        /*
@@ -1598,9 +1576,7 @@ int ttm_bo_synccpu_write_grab(struct ttm_buffer_object *bo, bool no_wait)
        ret = ttm_bo_reserve(bo, true, no_wait, false, NULL);
        if (unlikely(ret != 0))
                return ret;
-       spin_lock(&bdev->fence_lock);
        ret = ttm_bo_wait(bo, false, true, no_wait);
-       spin_unlock(&bdev->fence_lock);
        if (likely(ret == 0))
                atomic_inc(&bo->cpu_writers);
        ttm_bo_unreserve(bo);
@@ -1657,9 +1633,7 @@ static int ttm_bo_swapout(struct ttm_mem_shrink *shrink)
         * Wait for GPU, then move to system cached.
         */
 
-       spin_lock(&bo->bdev->fence_lock);
        ret = ttm_bo_wait(bo, false, false, false);
-       spin_unlock(&bo->bdev->fence_lock);
 
        if (unlikely(ret != 0))
                goto out;
index 9e103a4875c820d07d8a99484a865e40f9ec3850..964387fc5c8f860544704ae3ce21d50084448361 100644 (file)
@@ -49,8 +49,7 @@ struct ttm_range_manager {
 
 static int ttm_bo_man_get_node(struct ttm_mem_type_manager *man,
                               struct ttm_buffer_object *bo,
-                              struct ttm_placement *placement,
-                              uint32_t flags,
+                              const struct ttm_place *place,
                               struct ttm_mem_reg *mem)
 {
        struct ttm_range_manager *rman = (struct ttm_range_manager *) man->priv;
@@ -60,7 +59,7 @@ static int ttm_bo_man_get_node(struct ttm_mem_type_manager *man,
        unsigned long lpfn;
        int ret;
 
-       lpfn = placement->lpfn;
+       lpfn = place->lpfn;
        if (!lpfn)
                lpfn = man->size;
 
@@ -68,13 +67,13 @@ static int ttm_bo_man_get_node(struct ttm_mem_type_manager *man,
        if (!node)
                return -ENOMEM;
 
-       if (flags & TTM_PL_FLAG_TOPDOWN)
+       if (place->flags & TTM_PL_FLAG_TOPDOWN)
                aflags = DRM_MM_CREATE_TOP;
 
        spin_lock(&rman->lock);
        ret = drm_mm_insert_node_in_range_generic(mm, node, mem->num_pages,
                                          mem->page_alignment, 0,
-                                         placement->fpfn, lpfn,
+                                         place->fpfn, lpfn,
                                          DRM_MM_SEARCH_BEST,
                                          aflags);
        spin_unlock(&rman->lock);
index 30e5d90cb7bc6e17980d4da275d35416d131e012..882cccdad27249c8e3afa992419fb0fb16bec97b 100644 (file)
@@ -37,6 +37,7 @@
 #include <linux/slab.h>
 #include <linux/vmalloc.h>
 #include <linux/module.h>
+#include <linux/reservation.h>
 
 void ttm_bo_free_old_node(struct ttm_buffer_object *bo)
 {
@@ -444,8 +445,6 @@ static int ttm_buffer_object_transfer(struct ttm_buffer_object *bo,
                                      struct ttm_buffer_object **new_obj)
 {
        struct ttm_buffer_object *fbo;
-       struct ttm_bo_device *bdev = bo->bdev;
-       struct ttm_bo_driver *driver = bdev->driver;
        int ret;
 
        fbo = kmalloc(sizeof(*fbo), GFP_KERNEL);
@@ -466,12 +465,6 @@ static int ttm_buffer_object_transfer(struct ttm_buffer_object *bo,
        drm_vma_node_reset(&fbo->vma_node);
        atomic_set(&fbo->cpu_writers, 0);
 
-       spin_lock(&bdev->fence_lock);
-       if (bo->sync_obj)
-               fbo->sync_obj = driver->sync_obj_ref(bo->sync_obj);
-       else
-               fbo->sync_obj = NULL;
-       spin_unlock(&bdev->fence_lock);
        kref_init(&fbo->list_kref);
        kref_init(&fbo->kref);
        fbo->destroy = &ttm_transfered_destroy;
@@ -487,28 +480,24 @@ static int ttm_buffer_object_transfer(struct ttm_buffer_object *bo,
 
 pgprot_t ttm_io_prot(uint32_t caching_flags, pgprot_t tmp)
 {
+       /* Cached mappings need no adjustment */
+       if (caching_flags & TTM_PL_FLAG_CACHED)
+               return tmp;
+
 #if defined(__i386__) || defined(__x86_64__)
        if (caching_flags & TTM_PL_FLAG_WC)
                tmp = pgprot_writecombine(tmp);
        else if (boot_cpu_data.x86 > 3)
                tmp = pgprot_noncached(tmp);
-
-#elif defined(__powerpc__)
-       if (!(caching_flags & TTM_PL_FLAG_CACHED)) {
-               pgprot_val(tmp) |= _PAGE_NO_CACHE;
-               if (caching_flags & TTM_PL_FLAG_UNCACHED)
-                       pgprot_val(tmp) |= _PAGE_GUARDED;
-       }
 #endif
-#if defined(__ia64__) || defined(__arm__)
+#if defined(__ia64__) || defined(__arm__) || defined(__powerpc__)
        if (caching_flags & TTM_PL_FLAG_WC)
                tmp = pgprot_writecombine(tmp);
        else
                tmp = pgprot_noncached(tmp);
 #endif
 #if defined(__sparc__) || defined(__mips__)
-       if (!(caching_flags & TTM_PL_FLAG_CACHED))
-               tmp = pgprot_noncached(tmp);
+       tmp = pgprot_noncached(tmp);
 #endif
        return tmp;
 }
@@ -567,9 +556,7 @@ static int ttm_bo_kmap_ttm(struct ttm_buffer_object *bo,
                 * We need to use vmap to get the desired page protection
                 * or to make the buffer object look contiguous.
                 */
-               prot = (mem->placement & TTM_PL_FLAG_CACHED) ?
-                       PAGE_KERNEL :
-                       ttm_io_prot(mem->placement, PAGE_KERNEL);
+               prot = ttm_io_prot(mem->placement, PAGE_KERNEL);
                map->bo_kmap_type = ttm_bo_map_vmap;
                map->virtual = vmap(ttm->pages + start_page, num_pages,
                                    0, prot);
@@ -644,30 +631,20 @@ void ttm_bo_kunmap(struct ttm_bo_kmap_obj *map)
 EXPORT_SYMBOL(ttm_bo_kunmap);
 
 int ttm_bo_move_accel_cleanup(struct ttm_buffer_object *bo,
-                             void *sync_obj,
+                             struct fence *fence,
                              bool evict,
                              bool no_wait_gpu,
                              struct ttm_mem_reg *new_mem)
 {
        struct ttm_bo_device *bdev = bo->bdev;
-       struct ttm_bo_driver *driver = bdev->driver;
        struct ttm_mem_type_manager *man = &bdev->man[new_mem->mem_type];
        struct ttm_mem_reg *old_mem = &bo->mem;
        int ret;
        struct ttm_buffer_object *ghost_obj;
-       void *tmp_obj = NULL;
 
-       spin_lock(&bdev->fence_lock);
-       if (bo->sync_obj) {
-               tmp_obj = bo->sync_obj;
-               bo->sync_obj = NULL;
-       }
-       bo->sync_obj = driver->sync_obj_ref(sync_obj);
+       reservation_object_add_excl_fence(bo->resv, fence);
        if (evict) {
                ret = ttm_bo_wait(bo, false, false, false);
-               spin_unlock(&bdev->fence_lock);
-               if (tmp_obj)
-                       driver->sync_obj_unref(&tmp_obj);
                if (ret)
                        return ret;
 
@@ -688,14 +665,13 @@ int ttm_bo_move_accel_cleanup(struct ttm_buffer_object *bo,
                 */
 
                set_bit(TTM_BO_PRIV_FLAG_MOVING, &bo->priv_flags);
-               spin_unlock(&bdev->fence_lock);
-               if (tmp_obj)
-                       driver->sync_obj_unref(&tmp_obj);
 
                ret = ttm_buffer_object_transfer(bo, &ghost_obj);
                if (ret)
                        return ret;
 
+               reservation_object_add_excl_fence(ghost_obj->resv, fence);
+
                /**
                 * If we're not moving to fixed memory, the TTM object
                 * needs to stay alive. Otherwhise hang it on the ghost
index 0ce48e5a9cb4a70b56461f0ceb529e2c48ed58aa..8fb7213277cc9029d101f2006e7bc50289ab51df 100644 (file)
@@ -45,10 +45,8 @@ static int ttm_bo_vm_fault_idle(struct ttm_buffer_object *bo,
                                struct vm_area_struct *vma,
                                struct vm_fault *vmf)
 {
-       struct ttm_bo_device *bdev = bo->bdev;
        int ret = 0;
 
-       spin_lock(&bdev->fence_lock);
        if (likely(!test_bit(TTM_BO_PRIV_FLAG_MOVING, &bo->priv_flags)))
                goto out_unlock;
 
@@ -82,7 +80,6 @@ static int ttm_bo_vm_fault_idle(struct ttm_buffer_object *bo,
                        VM_FAULT_NOPAGE;
 
 out_unlock:
-       spin_unlock(&bdev->fence_lock);
        return ret;
 }
 
@@ -200,9 +197,8 @@ static int ttm_bo_vm_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
                                                cvma.vm_page_prot);
        } else {
                ttm = bo->ttm;
-               if (!(bo->mem.placement & TTM_PL_FLAG_CACHED))
-                       cvma.vm_page_prot = ttm_io_prot(bo->mem.placement,
-                                                       cvma.vm_page_prot);
+               cvma.vm_page_prot = ttm_io_prot(bo->mem.placement,
+                                               cvma.vm_page_prot);
 
                /* Allocate all page at once, most common usage */
                if (ttm->bdev->driver->ttm_tt_populate(ttm)) {
index e8dac87585285ae6e0de09175384c52d8ea330fa..8ce508e76208a0f5ce8c12b1da9e54111aac7ad6 100644 (file)
 #include <linux/sched.h>
 #include <linux/module.h>
 
-static void ttm_eu_backoff_reservation_locked(struct list_head *list)
+static void ttm_eu_backoff_reservation_reverse(struct list_head *list,
+                                             struct ttm_validate_buffer *entry)
 {
-       struct ttm_validate_buffer *entry;
-
-       list_for_each_entry(entry, list, head) {
+       list_for_each_entry_continue_reverse(entry, list, head) {
                struct ttm_buffer_object *bo = entry->bo;
-               if (!entry->reserved)
-                       continue;
 
-               entry->reserved = false;
-               if (entry->removed) {
-                       ttm_bo_add_to_lru(bo);
-                       entry->removed = false;
-               }
                __ttm_bo_unreserve(bo);
        }
 }
@@ -56,27 +48,9 @@ static void ttm_eu_del_from_lru_locked(struct list_head *list)
 
        list_for_each_entry(entry, list, head) {
                struct ttm_buffer_object *bo = entry->bo;
-               if (!entry->reserved)
-                       continue;
-
-               if (!entry->removed) {
-                       entry->put_count = ttm_bo_del_from_lru(bo);
-                       entry->removed = true;
-               }
-       }
-}
-
-static void ttm_eu_list_ref_sub(struct list_head *list)
-{
-       struct ttm_validate_buffer *entry;
-
-       list_for_each_entry(entry, list, head) {
-               struct ttm_buffer_object *bo = entry->bo;
+               unsigned put_count = ttm_bo_del_from_lru(bo);
 
-               if (entry->put_count) {
-                       ttm_bo_list_ref_sub(bo, entry->put_count, true);
-                       entry->put_count = 0;
-               }
+               ttm_bo_list_ref_sub(bo, put_count, true);
        }
 }
 
@@ -91,11 +65,18 @@ void ttm_eu_backoff_reservation(struct ww_acquire_ctx *ticket,
 
        entry = list_first_entry(list, struct ttm_validate_buffer, head);
        glob = entry->bo->glob;
+
        spin_lock(&glob->lru_lock);
-       ttm_eu_backoff_reservation_locked(list);
+       list_for_each_entry(entry, list, head) {
+               struct ttm_buffer_object *bo = entry->bo;
+
+               ttm_bo_add_to_lru(bo);
+               __ttm_bo_unreserve(bo);
+       }
+       spin_unlock(&glob->lru_lock);
+
        if (ticket)
                ww_acquire_fini(ticket);
-       spin_unlock(&glob->lru_lock);
 }
 EXPORT_SYMBOL(ttm_eu_backoff_reservation);
 
@@ -112,7 +93,7 @@ EXPORT_SYMBOL(ttm_eu_backoff_reservation);
  */
 
 int ttm_eu_reserve_buffers(struct ww_acquire_ctx *ticket,
-                          struct list_head *list)
+                          struct list_head *list, bool intr)
 {
        struct ttm_bo_global *glob;
        struct ttm_validate_buffer *entry;
@@ -121,60 +102,64 @@ int ttm_eu_reserve_buffers(struct ww_acquire_ctx *ticket,
        if (list_empty(list))
                return 0;
 
-       list_for_each_entry(entry, list, head) {
-               entry->reserved = false;
-               entry->put_count = 0;
-               entry->removed = false;
-       }
-
        entry = list_first_entry(list, struct ttm_validate_buffer, head);
        glob = entry->bo->glob;
 
        if (ticket)
                ww_acquire_init(ticket, &reservation_ww_class);
-retry:
+
        list_for_each_entry(entry, list, head) {
                struct ttm_buffer_object *bo = entry->bo;
 
-               /* already slowpath reserved? */
-               if (entry->reserved)
-                       continue;
-
-               ret = __ttm_bo_reserve(bo, true, (ticket == NULL), true,
+               ret = __ttm_bo_reserve(bo, intr, (ticket == NULL), true,
                                       ticket);
+               if (!ret && unlikely(atomic_read(&bo->cpu_writers) > 0)) {
+                       __ttm_bo_unreserve(bo);
+
+                       ret = -EBUSY;
+               }
 
-               if (ret == -EDEADLK) {
-                       /* uh oh, we lost out, drop every reservation and try
-                        * to only reserve this buffer, then start over if
-                        * this succeeds.
-                        */
-                       BUG_ON(ticket == NULL);
-                       spin_lock(&glob->lru_lock);
-                       ttm_eu_backoff_reservation_locked(list);
-                       spin_unlock(&glob->lru_lock);
-                       ttm_eu_list_ref_sub(list);
+               if (!ret) {
+                       if (!entry->shared)
+                               continue;
+
+                       ret = reservation_object_reserve_shared(bo->resv);
+                       if (!ret)
+                               continue;
+               }
+
+               /* uh oh, we lost out, drop every reservation and try
+                * to only reserve this buffer, then start over if
+                * this succeeds.
+                */
+               ttm_eu_backoff_reservation_reverse(list, entry);
+
+               if (ret == -EDEADLK && intr) {
                        ret = ww_mutex_lock_slow_interruptible(&bo->resv->lock,
                                                               ticket);
-                       if (unlikely(ret != 0)) {
-                               if (ret == -EINTR)
-                                       ret = -ERESTARTSYS;
-                               goto err_fini;
-                       }
+               } else if (ret == -EDEADLK) {
+                       ww_mutex_lock_slow(&bo->resv->lock, ticket);
+                       ret = 0;
+               }
 
-                       entry->reserved = true;
-                       if (unlikely(atomic_read(&bo->cpu_writers) > 0)) {
-                               ret = -EBUSY;
-                               goto err;
-                       }
-                       goto retry;
-               } else if (ret)
-                       goto err;
+               if (!ret && entry->shared)
+                       ret = reservation_object_reserve_shared(bo->resv);
 
-               entry->reserved = true;
-               if (unlikely(atomic_read(&bo->cpu_writers) > 0)) {
-                       ret = -EBUSY;
-                       goto err;
+               if (unlikely(ret != 0)) {
+                       if (ret == -EINTR)
+                               ret = -ERESTARTSYS;
+                       if (ticket) {
+                               ww_acquire_done(ticket);
+                               ww_acquire_fini(ticket);
+                       }
+                       return ret;
                }
+
+               /* move this item to the front of the list,
+                * forces correct iteration of the loop without keeping track
+                */
+               list_del(&entry->head);
+               list_add(&entry->head, list);
        }
 
        if (ticket)
@@ -182,25 +167,12 @@ retry:
        spin_lock(&glob->lru_lock);
        ttm_eu_del_from_lru_locked(list);
        spin_unlock(&glob->lru_lock);
-       ttm_eu_list_ref_sub(list);
        return 0;
-
-err:
-       spin_lock(&glob->lru_lock);
-       ttm_eu_backoff_reservation_locked(list);
-       spin_unlock(&glob->lru_lock);
-       ttm_eu_list_ref_sub(list);
-err_fini:
-       if (ticket) {
-               ww_acquire_done(ticket);
-               ww_acquire_fini(ticket);
-       }
-       return ret;
 }
 EXPORT_SYMBOL(ttm_eu_reserve_buffers);
 
 void ttm_eu_fence_buffer_objects(struct ww_acquire_ctx *ticket,
-                                struct list_head *list, void *sync_obj)
+                                struct list_head *list, struct fence *fence)
 {
        struct ttm_validate_buffer *entry;
        struct ttm_buffer_object *bo;
@@ -217,24 +189,18 @@ void ttm_eu_fence_buffer_objects(struct ww_acquire_ctx *ticket,
        glob = bo->glob;
 
        spin_lock(&glob->lru_lock);
-       spin_lock(&bdev->fence_lock);
 
        list_for_each_entry(entry, list, head) {
                bo = entry->bo;
-               entry->old_sync_obj = bo->sync_obj;
-               bo->sync_obj = driver->sync_obj_ref(sync_obj);
+               if (entry->shared)
+                       reservation_object_add_shared_fence(bo->resv, fence);
+               else
+                       reservation_object_add_excl_fence(bo->resv, fence);
                ttm_bo_add_to_lru(bo);
                __ttm_bo_unreserve(bo);
-               entry->reserved = false;
        }
-       spin_unlock(&bdev->fence_lock);
        spin_unlock(&glob->lru_lock);
        if (ticket)
                ww_acquire_fini(ticket);
-
-       list_for_each_entry(entry, list, head) {
-               if (entry->old_sync_obj)
-                       driver->sync_obj_unref(&entry->old_sync_obj);
-       }
 }
 EXPORT_SYMBOL(ttm_eu_fence_buffer_objects);
index dbc2def887cdbb6008d1d3ec7bec9f188d570b1a..a1803fbcc898a9f347b696ac454442592bc22004 100644 (file)
@@ -300,7 +300,8 @@ static int ttm_mem_init_highmem_zone(struct ttm_mem_global *glob,
        zone->glob = glob;
        glob->zone_highmem = zone;
        ret = kobject_init_and_add(
-               &zone->kobj, &ttm_mem_zone_kobj_type, &glob->kobj, zone->name);
+               &zone->kobj, &ttm_mem_zone_kobj_type, &glob->kobj, "%s",
+               zone->name);
        if (unlikely(ret != 0)) {
                kobject_put(&zone->kobj);
                return ret;
index f02528686cd524745e9ad058f12b7b8cc56a7620..613ab0622d6e4a2dfbfeaf3efee59bfb6c17b7f7 100644 (file)
@@ -1,8 +1,9 @@
 config DRM_UDL
        tristate "DisplayLink"
        depends on DRM
+       depends on USB_SUPPORT
        depends on USB_ARCH_HAS_HCD
-       select DRM_USB
+       select USB
        select FB_SYS_FILLRECT
        select FB_SYS_COPYAREA
        select FB_SYS_IMAGEBLIT
index e026a9e2942a249c1e6914ae6ba12a8f9c4be37c..0110d95522f325d25d3ec9b079a827fc5cc82789 100644 (file)
@@ -34,8 +34,8 @@ static u8 *udl_get_edid(struct udl_device *udl)
                goto error;
 
        for (i = 0; i < EDID_LENGTH; i++) {
-               ret = usb_control_msg(udl->ddev->usbdev,
-                                     usb_rcvctrlpipe(udl->ddev->usbdev, 0), (0x02),
+               ret = usb_control_msg(udl->udev,
+                                     usb_rcvctrlpipe(udl->udev, 0), (0x02),
                                      (0x80 | (0x02 << 5)), i << 8, 0xA1, rbuf, 2,
                                      HZ);
                if (ret < 1) {
index 3ddd6cd98ac12d0d8cbf9124556f6688b677c9f8..8607e9e513db0d94129ea524b9a4abe5dd9653af 100644 (file)
@@ -7,48 +7,13 @@
  */
 
 #include <linux/module.h>
-#include <drm/drm_usb.h>
+#include <drm/drmP.h>
 #include <drm/drm_crtc_helper.h>
 #include "udl_drv.h"
 
-static struct drm_driver driver;
-
-/*
- * There are many DisplayLink-based graphics products, all with unique PIDs.
- * So we match on DisplayLink's VID + Vendor-Defined Interface Class (0xff)
- * We also require a match on SubClass (0x00) and Protocol (0x00),
- * which is compatible with all known USB 2.0 era graphics chips and firmware,
- * but allows DisplayLink to increment those for any future incompatible chips
- */
-static struct usb_device_id id_table[] = {
-       {.idVendor = 0x17e9, .bInterfaceClass = 0xff,
-        .bInterfaceSubClass = 0x00,
-        .bInterfaceProtocol = 0x00,
-        .match_flags = USB_DEVICE_ID_MATCH_VENDOR |
-                       USB_DEVICE_ID_MATCH_INT_CLASS |
-                       USB_DEVICE_ID_MATCH_INT_SUBCLASS |
-                       USB_DEVICE_ID_MATCH_INT_PROTOCOL,},
-       {},
-};
-MODULE_DEVICE_TABLE(usb, id_table);
-
-MODULE_LICENSE("GPL");
-
-static int udl_usb_probe(struct usb_interface *interface,
-                        const struct usb_device_id *id)
+static int udl_driver_set_busid(struct drm_device *d, struct drm_master *m)
 {
-       return drm_get_usb_dev(interface, id, &driver);
-}
-
-static void udl_usb_disconnect(struct usb_interface *interface)
-{
-       struct drm_device *dev = usb_get_intfdata(interface);
-
-       drm_kms_helper_poll_disable(dev);
-       drm_connector_unplug_all(dev);
-       udl_fbdev_unplug(dev);
-       udl_drop_usb(dev);
-       drm_unplug_dev(dev);
+       return 0;
 }
 
 static const struct vm_operations_struct udl_gem_vm_ops = {
@@ -75,6 +40,7 @@ static struct drm_driver driver = {
        .driver_features = DRIVER_MODESET | DRIVER_GEM | DRIVER_PRIME,
        .load = udl_driver_load,
        .unload = udl_driver_unload,
+       .set_busid = udl_driver_set_busid,
 
        /* gem hooks */
        .gem_free_object = udl_gem_free_object,
@@ -96,6 +62,61 @@ static struct drm_driver driver = {
        .patchlevel = DRIVER_PATCHLEVEL,
 };
 
+static int udl_usb_probe(struct usb_interface *interface,
+                        const struct usb_device_id *id)
+{
+       struct usb_device *udev = interface_to_usbdev(interface);
+       struct drm_device *dev;
+       int r;
+
+       dev = drm_dev_alloc(&driver, &interface->dev);
+       if (!dev)
+               return -ENOMEM;
+
+       r = drm_dev_register(dev, (unsigned long)udev);
+       if (r)
+               goto err_free;
+
+       usb_set_intfdata(interface, dev);
+       DRM_INFO("Initialized udl on minor %d\n", dev->primary->index);
+
+       return 0;
+
+err_free:
+       drm_dev_unref(dev);
+       return r;
+}
+
+static void udl_usb_disconnect(struct usb_interface *interface)
+{
+       struct drm_device *dev = usb_get_intfdata(interface);
+
+       drm_kms_helper_poll_disable(dev);
+       drm_connector_unplug_all(dev);
+       udl_fbdev_unplug(dev);
+       udl_drop_usb(dev);
+       drm_unplug_dev(dev);
+}
+
+/*
+ * There are many DisplayLink-based graphics products, all with unique PIDs.
+ * So we match on DisplayLink's VID + Vendor-Defined Interface Class (0xff)
+ * We also require a match on SubClass (0x00) and Protocol (0x00),
+ * which is compatible with all known USB 2.0 era graphics chips and firmware,
+ * but allows DisplayLink to increment those for any future incompatible chips
+ */
+static struct usb_device_id id_table[] = {
+       {.idVendor = 0x17e9, .bInterfaceClass = 0xff,
+        .bInterfaceSubClass = 0x00,
+        .bInterfaceProtocol = 0x00,
+        .match_flags = USB_DEVICE_ID_MATCH_VENDOR |
+                       USB_DEVICE_ID_MATCH_INT_CLASS |
+                       USB_DEVICE_ID_MATCH_INT_SUBCLASS |
+                       USB_DEVICE_ID_MATCH_INT_PROTOCOL,},
+       {},
+};
+MODULE_DEVICE_TABLE(usb, id_table);
+
 static struct usb_driver udl_driver = {
        .name = "udl",
        .probe = udl_usb_probe,
@@ -105,13 +126,14 @@ static struct usb_driver udl_driver = {
 
 static int __init udl_init(void)
 {
-       return drm_usb_init(&driver, &udl_driver);
+       return usb_register(&udl_driver);
 }
 
 static void __exit udl_exit(void)
 {
-       drm_usb_exit(&driver, &udl_driver);
+       usb_deregister(&udl_driver);
 }
 
 module_init(udl_init);
 module_exit(udl_exit);
+MODULE_LICENSE("GPL");
index 1fbf7b357f16ba1c9b6a8baea1fd54292398e041..c7490a2489a750c2bc884761300b6b324c5b572a 100644 (file)
@@ -15,6 +15,7 @@
 #define UDL_DRV_H
 
 #include <linux/usb.h>
+#include <drm/drm_gem.h>
 
 #define DRIVER_NAME            "udl"
 #define DRIVER_DESC            "DisplayLink"
@@ -47,6 +48,7 @@ struct udl_fbdev;
 struct udl_device {
        struct device *dev;
        struct drm_device *ddev;
+       struct usb_device *udev;
 
        int sku_pixel_limit;
 
index d1da339843cafb263b21030bc546b5f3d285b394..8cbcb4589bd34db8fd35e8186eed1700dd9ba8cb 100644 (file)
@@ -472,7 +472,8 @@ udl_framebuffer_init(struct drm_device *dev,
 static int udlfb_create(struct drm_fb_helper *helper,
                        struct drm_fb_helper_surface_size *sizes)
 {
-       struct udl_fbdev *ufbdev = (struct udl_fbdev *)helper;
+       struct udl_fbdev *ufbdev =
+               container_of(helper, struct udl_fbdev, helper);
        struct drm_device *dev = ufbdev->helper.dev;
        struct fb_info *info;
        struct device *device = dev->dev;
index 42795674bc0783d12807e76d751c27acb3b200fb..33dbfb2c47486ee3b7a88cc318d3e6230b4dc0f1 100644 (file)
@@ -202,7 +202,7 @@ static int udl_alloc_urb_list(struct drm_device *dev, int count, size_t size)
                }
                unode->urb = urb;
 
-               buf = usb_alloc_coherent(udl->ddev->usbdev, MAX_TRANSFER, GFP_KERNEL,
+               buf = usb_alloc_coherent(udl->udev, MAX_TRANSFER, GFP_KERNEL,
                                         &urb->transfer_dma);
                if (!buf) {
                        kfree(unode);
@@ -211,7 +211,7 @@ static int udl_alloc_urb_list(struct drm_device *dev, int count, size_t size)
                }
 
                /* urb->transfer_buffer_length set to actual before submit */
-               usb_fill_bulk_urb(urb, udl->ddev->usbdev, usb_sndbulkpipe(udl->ddev->usbdev, 1),
+               usb_fill_bulk_urb(urb, udl->udev, usb_sndbulkpipe(udl->udev, 1),
                        buf, size, udl_urb_completion, unode);
                urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
 
@@ -282,6 +282,7 @@ int udl_submit_urb(struct drm_device *dev, struct urb *urb, size_t len)
 
 int udl_driver_load(struct drm_device *dev, unsigned long flags)
 {
+       struct usb_device *udev = (void*)flags;
        struct udl_device *udl;
        int ret = -ENOMEM;
 
@@ -290,10 +291,11 @@ int udl_driver_load(struct drm_device *dev, unsigned long flags)
        if (!udl)
                return -ENOMEM;
 
+       udl->udev = udev;
        udl->ddev = dev;
        dev->dev_private = udl;
 
-       if (!udl_parse_vendor_descriptor(dev, dev->usbdev)) {
+       if (!udl_parse_vendor_descriptor(dev, udl->udev)) {
                ret = -ENODEV;
                DRM_ERROR("firmware not recognized. Assume incompatible device\n");
                goto err;
index 6fc0648dd37f6644c62968ae05d3209edbf5b6fd..d17d8f245c1aead596e19a2335e6db480129b694 100644 (file)
@@ -161,7 +161,7 @@ int via_dma_cleanup(struct drm_device *dev)
                if (dev_priv->ring.virtual_start) {
                        via_cmdbuf_reset(dev_priv);
 
-                       drm_core_ioremapfree(&dev_priv->ring.map, dev);
+                       drm_legacy_ioremapfree(&dev_priv->ring.map, dev);
                        dev_priv->ring.virtual_start = NULL;
                }
 
@@ -200,7 +200,7 @@ static int via_initialize(struct drm_device *dev,
        dev_priv->ring.map.flags = 0;
        dev_priv->ring.map.mtrr = 0;
 
-       drm_core_ioremap(&dev_priv->ring.map, dev);
+       drm_legacy_ioremap(&dev_priv->ring.map, dev);
 
        if (dev_priv->ring.map.handle == NULL) {
                via_dma_cleanup(dev);
index 50abc2adfaee495730337a94b4fc931bcdd40f37..ed8aa8ff861a14f1cc42ef636e505fc0ba816085 100644 (file)
@@ -62,7 +62,7 @@ static const struct file_operations via_driver_fops = {
        .open = drm_open,
        .release = drm_release,
        .unlocked_ioctl = drm_ioctl,
-       .mmap = drm_mmap,
+       .mmap = drm_legacy_mmap,
        .poll = drm_poll,
 #ifdef CONFIG_COMPAT
        .compat_ioctl = drm_compat_ioctl,
@@ -79,6 +79,7 @@ static struct drm_driver driver = {
        .open = via_driver_open,
        .preclose = via_reclaim_buffers_locked,
        .postclose = via_driver_postclose,
+       .set_busid = drm_pci_set_busid,
        .context_dtor = via_final_context,
        .get_vblank_counter = via_get_vblank_counter,
        .enable_vblank = via_enable_vblank,
index ad0273256beb58b3bd4ff65c3c6b230427543a17..ef8c500b4a006e4f63d848b6e5c43d81959c5439 100644 (file)
@@ -25,6 +25,8 @@
 #define _VIA_DRV_H_
 
 #include <drm/drm_mm.h>
+#include <drm/drm_legacy.h>
+
 #define DRIVER_AUTHOR  "Various"
 
 #define DRIVER_NAME            "via"
index d0ab3fb32acd7228cf6494223309d1d94e30e086..0b3522dba6e862829c0a4b2abe5e1fefbc461515 100644 (file)
@@ -31,7 +31,7 @@ static int via_do_init_map(struct drm_device *dev, drm_via_init_t *init)
 
        DRM_DEBUG("\n");
 
-       dev_priv->sarea = drm_getsarea(dev);
+       dev_priv->sarea = drm_legacy_getsarea(dev);
        if (!dev_priv->sarea) {
                DRM_ERROR("could not find sarea!\n");
                dev->dev_private = (void *)dev_priv;
@@ -39,14 +39,14 @@ static int via_do_init_map(struct drm_device *dev, drm_via_init_t *init)
                return -EINVAL;
        }
 
-       dev_priv->fb = drm_core_findmap(dev, init->fb_offset);
+       dev_priv->fb = drm_legacy_findmap(dev, init->fb_offset);
        if (!dev_priv->fb) {
                DRM_ERROR("could not find framebuffer!\n");
                dev->dev_private = (void *)dev_priv;
                via_do_cleanup_map(dev);
                return -EINVAL;
        }
-       dev_priv->mmio = drm_core_findmap(dev, init->mmio_offset);
+       dev_priv->mmio = drm_legacy_findmap(dev, init->mmio_offset);
        if (!dev_priv->mmio) {
                DRM_ERROR("could not find mmio region!\n");
                dev->dev_private = (void *)dev_priv;
index d70b1e1544bf68f7d99c1c756d00080f435e0815..4f20742e7788c4fe0626782c18b888795d5179c8 100644 (file)
@@ -211,12 +211,12 @@ void via_reclaim_buffers_locked(struct drm_device *dev,
        if (!(file->minor->master && file->master->lock.hw_lock))
                return;
 
-       drm_idlelock_take(&file->master->lock);
+       drm_legacy_idlelock_take(&file->master->lock);
 
        mutex_lock(&dev->struct_mutex);
        if (list_empty(&file_priv->obj_list)) {
                mutex_unlock(&dev->struct_mutex);
-               drm_idlelock_release(&file->master->lock);
+               drm_legacy_idlelock_release(&file->master->lock);
 
                return;
        }
@@ -231,7 +231,7 @@ void via_reclaim_buffers_locked(struct drm_device *dev,
        }
        mutex_unlock(&dev->struct_mutex);
 
-       drm_idlelock_release(&file->master->lock);
+       drm_legacy_idlelock_release(&file->master->lock);
 
        return;
 }
index 9dbc92bd15121ce42b0ec158a5c1738e87cd0415..0677bbf4ec7e3af5300e923ebb99b2593dd7b6e1 100644 (file)
@@ -31,6 +31,7 @@
 #include "via_3d_reg.h"
 #include <drm/drmP.h>
 #include <drm/via_drm.h>
+#include <drm/drm_legacy.h>
 #include "via_verifier.h"
 #include "via_drv.h"
 
index 6327cfc36805f46364402a004ce76cd9bb19ecd5..cff2bf9db9d254c6ea3e268c9e7237bb5c8c6c48 100644 (file)
 #include <drm/ttm/ttm_placement.h>
 #include <drm/ttm/ttm_page_alloc.h>
 
-static uint32_t vram_placement_flags = TTM_PL_FLAG_VRAM |
-       TTM_PL_FLAG_CACHED;
-
-static uint32_t vram_ne_placement_flags = TTM_PL_FLAG_VRAM |
-       TTM_PL_FLAG_CACHED |
-       TTM_PL_FLAG_NO_EVICT;
+static struct ttm_place vram_placement_flags = {
+       .fpfn = 0,
+       .lpfn = 0,
+       .flags = TTM_PL_FLAG_VRAM | TTM_PL_FLAG_CACHED
+};
 
-static uint32_t sys_placement_flags = TTM_PL_FLAG_SYSTEM |
-       TTM_PL_FLAG_CACHED;
+static struct ttm_place vram_ne_placement_flags = {
+       .fpfn = 0,
+       .lpfn = 0,
+       .flags = TTM_PL_FLAG_VRAM | TTM_PL_FLAG_CACHED | TTM_PL_FLAG_NO_EVICT
+};
 
-static uint32_t sys_ne_placement_flags = TTM_PL_FLAG_SYSTEM |
-       TTM_PL_FLAG_CACHED |
-       TTM_PL_FLAG_NO_EVICT;
+static struct ttm_place sys_placement_flags = {
+       .fpfn = 0,
+       .lpfn = 0,
+       .flags = TTM_PL_FLAG_SYSTEM | TTM_PL_FLAG_CACHED
+};
 
-static uint32_t gmr_placement_flags = VMW_PL_FLAG_GMR |
-       TTM_PL_FLAG_CACHED;
+static struct ttm_place sys_ne_placement_flags = {
+       .fpfn = 0,
+       .lpfn = 0,
+       .flags = TTM_PL_FLAG_SYSTEM | TTM_PL_FLAG_CACHED | TTM_PL_FLAG_NO_EVICT
+};
 
-static uint32_t gmr_ne_placement_flags = VMW_PL_FLAG_GMR |
-       TTM_PL_FLAG_CACHED |
-       TTM_PL_FLAG_NO_EVICT;
+static struct ttm_place gmr_placement_flags = {
+       .fpfn = 0,
+       .lpfn = 0,
+       .flags = VMW_PL_FLAG_GMR | TTM_PL_FLAG_CACHED
+};
 
-static uint32_t mob_placement_flags = VMW_PL_FLAG_MOB |
-       TTM_PL_FLAG_CACHED;
+static struct ttm_place gmr_ne_placement_flags = {
+       .fpfn = 0,
+       .lpfn = 0,
+       .flags = VMW_PL_FLAG_GMR | TTM_PL_FLAG_CACHED | TTM_PL_FLAG_NO_EVICT
+};
 
-struct ttm_placement vmw_vram_placement = {
+static struct ttm_place mob_placement_flags = {
        .fpfn = 0,
        .lpfn = 0,
+       .flags = VMW_PL_FLAG_MOB | TTM_PL_FLAG_CACHED
+};
+
+struct ttm_placement vmw_vram_placement = {
        .num_placement = 1,
        .placement = &vram_placement_flags,
        .num_busy_placement = 1,
        .busy_placement = &vram_placement_flags
 };
 
-static uint32_t vram_gmr_placement_flags[] = {
-       TTM_PL_FLAG_VRAM | TTM_PL_FLAG_CACHED,
-       VMW_PL_FLAG_GMR | TTM_PL_FLAG_CACHED
+static struct ttm_place vram_gmr_placement_flags[] = {
+       {
+               .fpfn = 0,
+               .lpfn = 0,
+               .flags = TTM_PL_FLAG_VRAM | TTM_PL_FLAG_CACHED
+       }, {
+               .fpfn = 0,
+               .lpfn = 0,
+               .flags = VMW_PL_FLAG_GMR | TTM_PL_FLAG_CACHED
+       }
 };
 
-static uint32_t gmr_vram_placement_flags[] = {
-       VMW_PL_FLAG_GMR | TTM_PL_FLAG_CACHED,
-       TTM_PL_FLAG_VRAM | TTM_PL_FLAG_CACHED
+static struct ttm_place gmr_vram_placement_flags[] = {
+       {
+               .fpfn = 0,
+               .lpfn = 0,
+               .flags = VMW_PL_FLAG_GMR | TTM_PL_FLAG_CACHED
+       }, {
+               .fpfn = 0,
+               .lpfn = 0,
+               .flags = TTM_PL_FLAG_VRAM | TTM_PL_FLAG_CACHED
+       }
 };
 
 struct ttm_placement vmw_vram_gmr_placement = {
-       .fpfn = 0,
-       .lpfn = 0,
        .num_placement = 2,
        .placement = vram_gmr_placement_flags,
        .num_busy_placement = 1,
        .busy_placement = &gmr_placement_flags
 };
 
-static uint32_t vram_gmr_ne_placement_flags[] = {
-       TTM_PL_FLAG_VRAM | TTM_PL_FLAG_CACHED | TTM_PL_FLAG_NO_EVICT,
-       VMW_PL_FLAG_GMR | TTM_PL_FLAG_CACHED | TTM_PL_FLAG_NO_EVICT
+static struct ttm_place vram_gmr_ne_placement_flags[] = {
+       {
+               .fpfn = 0,
+               .lpfn = 0,
+               .flags = TTM_PL_FLAG_VRAM | TTM_PL_FLAG_CACHED |
+                        TTM_PL_FLAG_NO_EVICT
+       }, {
+               .fpfn = 0,
+               .lpfn = 0,
+               .flags = VMW_PL_FLAG_GMR | TTM_PL_FLAG_CACHED |
+                        TTM_PL_FLAG_NO_EVICT
+       }
 };
 
 struct ttm_placement vmw_vram_gmr_ne_placement = {
-       .fpfn = 0,
-       .lpfn = 0,
        .num_placement = 2,
        .placement = vram_gmr_ne_placement_flags,
        .num_busy_placement = 1,
@@ -97,8 +132,6 @@ struct ttm_placement vmw_vram_gmr_ne_placement = {
 };
 
 struct ttm_placement vmw_vram_sys_placement = {
-       .fpfn = 0,
-       .lpfn = 0,
        .num_placement = 1,
        .placement = &vram_placement_flags,
        .num_busy_placement = 1,
@@ -106,8 +139,6 @@ struct ttm_placement vmw_vram_sys_placement = {
 };
 
 struct ttm_placement vmw_vram_ne_placement = {
-       .fpfn = 0,
-       .lpfn = 0,
        .num_placement = 1,
        .placement = &vram_ne_placement_flags,
        .num_busy_placement = 1,
@@ -115,8 +146,6 @@ struct ttm_placement vmw_vram_ne_placement = {
 };
 
 struct ttm_placement vmw_sys_placement = {
-       .fpfn = 0,
-       .lpfn = 0,
        .num_placement = 1,
        .placement = &sys_placement_flags,
        .num_busy_placement = 1,
@@ -124,24 +153,33 @@ struct ttm_placement vmw_sys_placement = {
 };
 
 struct ttm_placement vmw_sys_ne_placement = {
-       .fpfn = 0,
-       .lpfn = 0,
        .num_placement = 1,
        .placement = &sys_ne_placement_flags,
        .num_busy_placement = 1,
        .busy_placement = &sys_ne_placement_flags
 };
 
-static uint32_t evictable_placement_flags[] = {
-       TTM_PL_FLAG_SYSTEM | TTM_PL_FLAG_CACHED,
-       TTM_PL_FLAG_VRAM | TTM_PL_FLAG_CACHED,
-       VMW_PL_FLAG_GMR | TTM_PL_FLAG_CACHED,
-       VMW_PL_FLAG_MOB | TTM_PL_FLAG_CACHED
+static struct ttm_place evictable_placement_flags[] = {
+       {
+               .fpfn = 0,
+               .lpfn = 0,
+               .flags = TTM_PL_FLAG_SYSTEM | TTM_PL_FLAG_CACHED
+       }, {
+               .fpfn = 0,
+               .lpfn = 0,
+               .flags = TTM_PL_FLAG_VRAM | TTM_PL_FLAG_CACHED
+       }, {
+               .fpfn = 0,
+               .lpfn = 0,
+               .flags = VMW_PL_FLAG_GMR | TTM_PL_FLAG_CACHED
+       }, {
+               .fpfn = 0,
+               .lpfn = 0,
+               .flags = VMW_PL_FLAG_MOB | TTM_PL_FLAG_CACHED
+       }
 };
 
 struct ttm_placement vmw_evictable_placement = {
-       .fpfn = 0,
-       .lpfn = 0,
        .num_placement = 4,
        .placement = evictable_placement_flags,
        .num_busy_placement = 1,
@@ -149,8 +187,6 @@ struct ttm_placement vmw_evictable_placement = {
 };
 
 struct ttm_placement vmw_srf_placement = {
-       .fpfn = 0,
-       .lpfn = 0,
        .num_placement = 1,
        .num_busy_placement = 2,
        .placement = &gmr_placement_flags,
@@ -158,8 +194,6 @@ struct ttm_placement vmw_srf_placement = {
 };
 
 struct ttm_placement vmw_mob_placement = {
-       .fpfn = 0,
-       .lpfn = 0,
        .num_placement = 1,
        .num_busy_placement = 1,
        .placement = &mob_placement_flags,
@@ -767,44 +801,6 @@ static int vmw_ttm_fault_reserve_notify(struct ttm_buffer_object *bo)
        return 0;
 }
 
-/**
- * FIXME: We're using the old vmware polling method to sync.
- * Do this with fences instead.
- */
-
-static void *vmw_sync_obj_ref(void *sync_obj)
-{
-
-       return (void *)
-               vmw_fence_obj_reference((struct vmw_fence_obj *) sync_obj);
-}
-
-static void vmw_sync_obj_unref(void **sync_obj)
-{
-       vmw_fence_obj_unreference((struct vmw_fence_obj **) sync_obj);
-}
-
-static int vmw_sync_obj_flush(void *sync_obj)
-{
-       vmw_fence_obj_flush((struct vmw_fence_obj *) sync_obj);
-       return 0;
-}
-
-static bool vmw_sync_obj_signaled(void *sync_obj)
-{
-       return  vmw_fence_obj_signaled((struct vmw_fence_obj *) sync_obj,
-                                      DRM_VMW_FENCE_FLAG_EXEC);
-
-}
-
-static int vmw_sync_obj_wait(void *sync_obj, bool lazy, bool interruptible)
-{
-       return vmw_fence_obj_wait((struct vmw_fence_obj *) sync_obj,
-                                 DRM_VMW_FENCE_FLAG_EXEC,
-                                 lazy, interruptible,
-                                 VMW_FENCE_WAIT_TIMEOUT);
-}
-
 /**
  * vmw_move_notify - TTM move_notify_callback
  *
@@ -829,11 +825,7 @@ static void vmw_move_notify(struct ttm_buffer_object *bo,
  */
 static void vmw_swap_notify(struct ttm_buffer_object *bo)
 {
-       struct ttm_bo_device *bdev = bo->bdev;
-
-       spin_lock(&bdev->fence_lock);
        ttm_bo_wait(bo, false, false, false);
-       spin_unlock(&bdev->fence_lock);
 }
 
 
@@ -846,11 +838,6 @@ struct ttm_bo_driver vmw_bo_driver = {
        .evict_flags = vmw_evict_flags,
        .move = NULL,
        .verify_access = vmw_verify_access,
-       .sync_obj_signaled = vmw_sync_obj_signaled,
-       .sync_obj_wait = vmw_sync_obj_wait,
-       .sync_obj_flush = vmw_sync_obj_flush,
-       .sync_obj_unref = vmw_sync_obj_unref,
-       .sync_obj_ref = vmw_sync_obj_ref,
        .move_notify = vmw_move_notify,
        .swap_notify = vmw_swap_notify,
        .fault_reserve_notify = &vmw_ttm_fault_reserve_notify,
index ed1d51006ab1e3054dc8cab075db1b776d204cc7..914b375763dcaf753da1763bba14b1718f37fa9b 100644 (file)
@@ -198,13 +198,19 @@ int vmw_dmabuf_to_start_of_vram(struct vmw_private *dev_priv,
 {
        struct ttm_buffer_object *bo = &buf->base;
        struct ttm_placement placement;
+       struct ttm_place place;
        int ret = 0;
 
        if (pin)
-               placement = vmw_vram_ne_placement;
+               place = vmw_vram_ne_placement.placement[0];
        else
-               placement = vmw_vram_placement;
-       placement.lpfn = bo->num_pages;
+               place = vmw_vram_placement.placement[0];
+       place.lpfn = bo->num_pages;
+
+       placement.num_placement = 1;
+       placement.placement = &place;
+       placement.num_busy_placement = 1;
+       placement.busy_placement = &place;
 
        ret = ttm_write_lock(&dev_priv->reservation_sem, interruptible);
        if (unlikely(ret != 0))
@@ -293,21 +299,23 @@ void vmw_bo_get_guest_ptr(const struct ttm_buffer_object *bo,
  */
 void vmw_bo_pin(struct ttm_buffer_object *bo, bool pin)
 {
-       uint32_t pl_flags;
+       struct ttm_place pl;
        struct ttm_placement placement;
        uint32_t old_mem_type = bo->mem.mem_type;
        int ret;
 
        lockdep_assert_held(&bo->resv->lock.base);
 
-       pl_flags = TTM_PL_FLAG_VRAM | VMW_PL_FLAG_GMR | VMW_PL_FLAG_MOB
+       pl.fpfn = 0;
+       pl.lpfn = 0;
+       pl.flags = TTM_PL_FLAG_VRAM | VMW_PL_FLAG_GMR | VMW_PL_FLAG_MOB
                | TTM_PL_FLAG_SYSTEM | TTM_PL_FLAG_CACHED;
        if (pin)
-               pl_flags |= TTM_PL_FLAG_NO_EVICT;
+               pl.flags |= TTM_PL_FLAG_NO_EVICT;
 
        memset(&placement, 0, sizeof(placement));
        placement.num_placement = 1;
-       placement.placement = &pl_flags;
+       placement.placement = &pl;
 
        ret = ttm_bo_validate(bo, &placement, false, true);
 
index 18b54acacfbb813335c00964117613a232840c94..7197af15731383c817728e155c09621c4c954fb0 100644 (file)
@@ -1418,6 +1418,7 @@ static struct drm_driver driver = {
        .open = vmw_driver_open,
        .preclose = vmw_preclose,
        .postclose = vmw_postclose,
+       .set_busid = drm_pci_set_busid,
 
        .dumb_create = vmw_dumb_create,
        .dumb_map_offset = vmw_dumb_map_offset,
index 99f731757c4bf6748ec4584103a2d5527f4618eb..4ee799b43d5dfc40a8077e60e9f34b17a8dddcf9 100644 (file)
@@ -342,7 +342,6 @@ struct vmw_sw_context{
        uint32_t *cmd_bounce;
        uint32_t cmd_bounce_size;
        struct list_head resource_list;
-       uint32_t fence_flags;
        struct ttm_buffer_object *cur_query_bo;
        struct list_head res_relocations;
        uint32_t *buf_start;
@@ -704,6 +703,7 @@ extern void *vmw_fifo_reserve(struct vmw_private *dev_priv, uint32_t bytes);
 extern void vmw_fifo_commit(struct vmw_private *dev_priv, uint32_t bytes);
 extern int vmw_fifo_send_fence(struct vmw_private *dev_priv,
                               uint32_t *seqno);
+extern void vmw_fifo_ping_host_locked(struct vmw_private *, uint32_t reason);
 extern void vmw_fifo_ping_host(struct vmw_private *dev_priv, uint32_t reason);
 extern bool vmw_fifo_have_3d(struct vmw_private *dev_priv);
 extern bool vmw_fifo_have_pitchlock(struct vmw_private *dev_priv);
index 36b871686d3c6147a7b033b9db45a07ed39e9530..596cd6dafd338c2f2e21a6461eb9c93676c487b3 100644 (file)
@@ -346,13 +346,11 @@ static int vmw_bo_to_validate_list(struct vmw_sw_context *sw_context,
                ++sw_context->cur_val_buf;
                val_buf = &vval_buf->base;
                val_buf->bo = ttm_bo_reference(bo);
-               val_buf->reserved = false;
+               val_buf->shared = false;
                list_add_tail(&val_buf->head, &sw_context->validate_nodes);
                vval_buf->validate_as_mob = validate_as_mob;
        }
 
-       sw_context->fence_flags |= DRM_VMW_FENCE_FLAG_EXEC;
-
        if (p_val_node)
                *p_val_node = val_node;
 
@@ -2337,13 +2335,9 @@ int vmw_execbuf_fence_commands(struct drm_file *file_priv,
 
        if (p_handle != NULL)
                ret = vmw_user_fence_create(file_priv, dev_priv->fman,
-                                           sequence,
-                                           DRM_VMW_FENCE_FLAG_EXEC,
-                                           p_fence, p_handle);
+                                           sequence, p_fence, p_handle);
        else
-               ret = vmw_fence_create(dev_priv->fman, sequence,
-                                      DRM_VMW_FENCE_FLAG_EXEC,
-                                      p_fence);
+               ret = vmw_fence_create(dev_priv->fman, sequence, p_fence);
 
        if (unlikely(ret != 0 && !synced)) {
                (void) vmw_fallback_wait(dev_priv, false, false,
@@ -2395,7 +2389,7 @@ vmw_execbuf_copy_fence_user(struct vmw_private *dev_priv,
                BUG_ON(fence == NULL);
 
                fence_rep.handle = fence_handle;
-               fence_rep.seqno = fence->seqno;
+               fence_rep.seqno = fence->base.seqno;
                vmw_update_seqno(dev_priv, &dev_priv->fifo);
                fence_rep.passed_seqno = dev_priv->last_read_seqno;
        }
@@ -2416,8 +2410,7 @@ vmw_execbuf_copy_fence_user(struct vmw_private *dev_priv,
                ttm_ref_object_base_unref(vmw_fp->tfile,
                                          fence_handle, TTM_REF_USAGE);
                DRM_ERROR("Fence copy error. Syncing.\n");
-               (void) vmw_fence_obj_wait(fence, fence->signal_mask,
-                                         false, false,
+               (void) vmw_fence_obj_wait(fence, false, false,
                                          VMW_FENCE_WAIT_TIMEOUT);
        }
 }
@@ -2469,7 +2462,6 @@ int vmw_execbuf_process(struct drm_file *file_priv,
        sw_context->fp = vmw_fpriv(file_priv);
        sw_context->cur_reloc = 0;
        sw_context->cur_val_buf = 0;
-       sw_context->fence_flags = 0;
        INIT_LIST_HEAD(&sw_context->resource_list);
        sw_context->cur_query_bo = dev_priv->pinned_bo;
        sw_context->last_query_ctx = NULL;
@@ -2495,7 +2487,7 @@ int vmw_execbuf_process(struct drm_file *file_priv,
        if (unlikely(ret != 0))
                goto out_err_nores;
 
-       ret = ttm_eu_reserve_buffers(&ticket, &sw_context->validate_nodes);
+       ret = ttm_eu_reserve_buffers(&ticket, &sw_context->validate_nodes, true);
        if (unlikely(ret != 0))
                goto out_err;
 
@@ -2678,15 +2670,14 @@ void __vmw_execbuf_release_pinned_bo(struct vmw_private *dev_priv,
        INIT_LIST_HEAD(&validate_list);
 
        pinned_val.bo = ttm_bo_reference(dev_priv->pinned_bo);
+       pinned_val.shared = false;
        list_add_tail(&pinned_val.head, &validate_list);
 
        query_val.bo = ttm_bo_reference(dev_priv->dummy_query_bo);
+       query_val.shared = false;
        list_add_tail(&query_val.head, &validate_list);
 
-       do {
-               ret = ttm_eu_reserve_buffers(&ticket, &validate_list);
-       } while (ret == -ERESTARTSYS);
-
+       ret = ttm_eu_reserve_buffers(&ticket, &validate_list, false);
        if (unlikely(ret != 0)) {
                vmw_execbuf_unpin_panic(dev_priv);
                goto out_no_reserve;
index b031b48dbb3cdcbbd48824096ac82650aa08ec87..0a474f391fad0157d8a51e5aa2e50d6c4aec69ec 100644 (file)
@@ -374,10 +374,16 @@ static int vmw_fb_create_bo(struct vmw_private *vmw_priv,
                            size_t size, struct vmw_dma_buffer **out)
 {
        struct vmw_dma_buffer *vmw_bo;
-       struct ttm_placement ne_placement = vmw_vram_ne_placement;
+       struct ttm_place ne_place = vmw_vram_ne_placement.placement[0];
+       struct ttm_placement ne_placement;
        int ret;
 
-       ne_placement.lpfn = (size + PAGE_SIZE - 1) >> PAGE_SHIFT;
+       ne_placement.num_placement = 1;
+       ne_placement.placement = &ne_place;
+       ne_placement.num_busy_placement = 1;
+       ne_placement.busy_placement = &ne_place;
+
+       ne_place.lpfn = (size + PAGE_SIZE - 1) >> PAGE_SHIFT;
 
        (void) ttm_write_lock(&vmw_priv->reservation_sem, false);
 
index 436b013b42316a06296dd62cb0dda23f5095c075..197164fd7803730c1759728ae9d53fa586f739da 100644 (file)
@@ -35,7 +35,7 @@ struct vmw_fence_manager {
        struct vmw_private *dev_priv;
        spinlock_t lock;
        struct list_head fence_list;
-       struct work_struct work;
+       struct work_struct work, ping_work;
        u32 user_fence_size;
        u32 fence_size;
        u32 event_fence_action_size;
@@ -46,6 +46,7 @@ struct vmw_fence_manager {
        bool goal_irq_on; /* Protected by @goal_irq_mutex */
        bool seqno_valid; /* Protected by @lock, and may not be set to true
                             without the @goal_irq_mutex held. */
+       unsigned ctx;
 };
 
 struct vmw_user_fence {
@@ -80,6 +81,12 @@ struct vmw_event_fence_action {
        uint32_t *tv_usec;
 };
 
+static struct vmw_fence_manager *
+fman_from_fence(struct vmw_fence_obj *fence)
+{
+       return container_of(fence->base.lock, struct vmw_fence_manager, lock);
+}
+
 /**
  * Note on fencing subsystem usage of irqs:
  * Typically the vmw_fences_update function is called
@@ -102,25 +109,143 @@ struct vmw_event_fence_action {
  * objects with actions attached to them.
  */
 
-static void vmw_fence_obj_destroy_locked(struct kref *kref)
+static void vmw_fence_obj_destroy(struct fence *f)
 {
        struct vmw_fence_obj *fence =
-               container_of(kref, struct vmw_fence_obj, kref);
+               container_of(f, struct vmw_fence_obj, base);
 
-       struct vmw_fence_manager *fman = fence->fman;
-       unsigned int num_fences;
+       struct vmw_fence_manager *fman = fman_from_fence(fence);
+       unsigned long irq_flags;
 
+       spin_lock_irqsave(&fman->lock, irq_flags);
        list_del_init(&fence->head);
-       num_fences = --fman->num_fence_objects;
-       spin_unlock_irq(&fman->lock);
-       if (fence->destroy)
-               fence->destroy(fence);
-       else
-               kfree(fence);
+       --fman->num_fence_objects;
+       spin_unlock_irqrestore(&fman->lock, irq_flags);
+       fence->destroy(fence);
+}
 
-       spin_lock_irq(&fman->lock);
+static const char *vmw_fence_get_driver_name(struct fence *f)
+{
+       return "vmwgfx";
+}
+
+static const char *vmw_fence_get_timeline_name(struct fence *f)
+{
+       return "svga";
+}
+
+static void vmw_fence_ping_func(struct work_struct *work)
+{
+       struct vmw_fence_manager *fman =
+               container_of(work, struct vmw_fence_manager, ping_work);
+
+       vmw_fifo_ping_host(fman->dev_priv, SVGA_SYNC_GENERIC);
+}
+
+static bool vmw_fence_enable_signaling(struct fence *f)
+{
+       struct vmw_fence_obj *fence =
+               container_of(f, struct vmw_fence_obj, base);
+
+       struct vmw_fence_manager *fman = fman_from_fence(fence);
+       struct vmw_private *dev_priv = fman->dev_priv;
+
+       __le32 __iomem *fifo_mem = dev_priv->mmio_virt;
+       u32 seqno = ioread32(fifo_mem + SVGA_FIFO_FENCE);
+       if (seqno - fence->base.seqno < VMW_FENCE_WRAP)
+               return false;
+
+       if (mutex_trylock(&dev_priv->hw_mutex)) {
+               vmw_fifo_ping_host_locked(dev_priv, SVGA_SYNC_GENERIC);
+               mutex_unlock(&dev_priv->hw_mutex);
+       } else
+               schedule_work(&fman->ping_work);
+
+       return true;
+}
+
+struct vmwgfx_wait_cb {
+       struct fence_cb base;
+       struct task_struct *task;
+};
+
+static void
+vmwgfx_wait_cb(struct fence *fence, struct fence_cb *cb)
+{
+       struct vmwgfx_wait_cb *wait =
+               container_of(cb, struct vmwgfx_wait_cb, base);
+
+       wake_up_process(wait->task);
+}
+
+static void __vmw_fences_update(struct vmw_fence_manager *fman);
+
+static long vmw_fence_wait(struct fence *f, bool intr, signed long timeout)
+{
+       struct vmw_fence_obj *fence =
+               container_of(f, struct vmw_fence_obj, base);
+
+       struct vmw_fence_manager *fman = fman_from_fence(fence);
+       struct vmw_private *dev_priv = fman->dev_priv;
+       struct vmwgfx_wait_cb cb;
+       long ret = timeout;
+       unsigned long irq_flags;
+
+       if (likely(vmw_fence_obj_signaled(fence)))
+               return timeout;
+
+       vmw_fifo_ping_host(dev_priv, SVGA_SYNC_GENERIC);
+       vmw_seqno_waiter_add(dev_priv);
+
+       spin_lock_irqsave(f->lock, irq_flags);
+
+       if (intr && signal_pending(current)) {
+               ret = -ERESTARTSYS;
+               goto out;
+       }
+
+       cb.base.func = vmwgfx_wait_cb;
+       cb.task = current;
+       list_add(&cb.base.node, &f->cb_list);
+
+       while (ret > 0) {
+               __vmw_fences_update(fman);
+               if (test_bit(FENCE_FLAG_SIGNALED_BIT, &f->flags))
+                       break;
+
+               if (intr)
+                       __set_current_state(TASK_INTERRUPTIBLE);
+               else
+                       __set_current_state(TASK_UNINTERRUPTIBLE);
+               spin_unlock_irqrestore(f->lock, irq_flags);
+
+               ret = schedule_timeout(ret);
+
+               spin_lock_irqsave(f->lock, irq_flags);
+               if (ret > 0 && intr && signal_pending(current))
+                       ret = -ERESTARTSYS;
+       }
+
+       if (!list_empty(&cb.base.node))
+               list_del(&cb.base.node);
+       __set_current_state(TASK_RUNNING);
+
+out:
+       spin_unlock_irqrestore(f->lock, irq_flags);
+
+       vmw_seqno_waiter_remove(dev_priv);
+
+       return ret;
 }
 
+static struct fence_ops vmw_fence_ops = {
+       .get_driver_name = vmw_fence_get_driver_name,
+       .get_timeline_name = vmw_fence_get_timeline_name,
+       .enable_signaling = vmw_fence_enable_signaling,
+       .wait = vmw_fence_wait,
+       .release = vmw_fence_obj_destroy,
+};
+
 
 /**
  * Execute signal actions on fences recently signaled.
@@ -180,12 +305,14 @@ struct vmw_fence_manager *vmw_fence_manager_init(struct vmw_private *dev_priv)
        INIT_LIST_HEAD(&fman->fence_list);
        INIT_LIST_HEAD(&fman->cleanup_list);
        INIT_WORK(&fman->work, &vmw_fence_work_func);
+       INIT_WORK(&fman->ping_work, &vmw_fence_ping_func);
        fman->fifo_down = true;
        fman->user_fence_size = ttm_round_pot(sizeof(struct vmw_user_fence));
        fman->fence_size = ttm_round_pot(sizeof(struct vmw_fence_obj));
        fman->event_fence_action_size =
                ttm_round_pot(sizeof(struct vmw_event_fence_action));
        mutex_init(&fman->goal_irq_mutex);
+       fman->ctx = fence_context_alloc(1);
 
        return fman;
 }
@@ -196,6 +323,7 @@ void vmw_fence_manager_takedown(struct vmw_fence_manager *fman)
        bool lists_empty;
 
        (void) cancel_work_sync(&fman->work);
+       (void) cancel_work_sync(&fman->ping_work);
 
        spin_lock_irqsave(&fman->lock, irq_flags);
        lists_empty = list_empty(&fman->fence_list) &&
@@ -207,23 +335,16 @@ void vmw_fence_manager_takedown(struct vmw_fence_manager *fman)
 }
 
 static int vmw_fence_obj_init(struct vmw_fence_manager *fman,
-                             struct vmw_fence_obj *fence,
-                             u32 seqno,
-                             uint32_t mask,
+                             struct vmw_fence_obj *fence, u32 seqno,
                              void (*destroy) (struct vmw_fence_obj *fence))
 {
        unsigned long irq_flags;
-       unsigned int num_fences;
        int ret = 0;
 
-       fence->seqno = seqno;
+       fence_init(&fence->base, &vmw_fence_ops, &fman->lock,
+                  fman->ctx, seqno);
        INIT_LIST_HEAD(&fence->seq_passed_actions);
-       fence->fman = fman;
-       fence->signaled = 0;
-       fence->signal_mask = mask;
-       kref_init(&fence->kref);
        fence->destroy = destroy;
-       init_waitqueue_head(&fence->queue);
 
        spin_lock_irqsave(&fman->lock, irq_flags);
        if (unlikely(fman->fifo_down)) {
@@ -231,7 +352,7 @@ static int vmw_fence_obj_init(struct vmw_fence_manager *fman,
                goto out_unlock;
        }
        list_add_tail(&fence->head, &fman->fence_list);
-       num_fences = ++fman->num_fence_objects;
+       ++fman->num_fence_objects;
 
 out_unlock:
        spin_unlock_irqrestore(&fman->lock, irq_flags);
@@ -239,38 +360,6 @@ out_unlock:
 
 }
 
-struct vmw_fence_obj *vmw_fence_obj_reference(struct vmw_fence_obj *fence)
-{
-       if (unlikely(fence == NULL))
-               return NULL;
-
-       kref_get(&fence->kref);
-       return fence;
-}
-
-/**
- * vmw_fence_obj_unreference
- *
- * Note that this function may not be entered with disabled irqs since
- * it may re-enable them in the destroy function.
- *
- */
-void vmw_fence_obj_unreference(struct vmw_fence_obj **fence_p)
-{
-       struct vmw_fence_obj *fence = *fence_p;
-       struct vmw_fence_manager *fman;
-
-       if (unlikely(fence == NULL))
-               return;
-
-       fman = fence->fman;
-       *fence_p = NULL;
-       spin_lock_irq(&fman->lock);
-       BUG_ON(atomic_read(&fence->kref.refcount) == 0);
-       kref_put(&fence->kref, vmw_fence_obj_destroy_locked);
-       spin_unlock_irq(&fman->lock);
-}
-
 static void vmw_fences_perform_actions(struct vmw_fence_manager *fman,
                                struct list_head *list)
 {
@@ -326,7 +415,7 @@ static bool vmw_fence_goal_new_locked(struct vmw_fence_manager *fman,
        list_for_each_entry(fence, &fman->fence_list, head) {
                if (!list_empty(&fence->seq_passed_actions)) {
                        fman->seqno_valid = true;
-                       iowrite32(fence->seqno,
+                       iowrite32(fence->base.seqno,
                                  fifo_mem + SVGA_FIFO_FENCE_GOAL);
                        break;
                }
@@ -353,27 +442,27 @@ static bool vmw_fence_goal_new_locked(struct vmw_fence_manager *fman,
  */
 static bool vmw_fence_goal_check_locked(struct vmw_fence_obj *fence)
 {
+       struct vmw_fence_manager *fman = fman_from_fence(fence);
        u32 goal_seqno;
        __le32 __iomem *fifo_mem;
 
-       if (fence->signaled & DRM_VMW_FENCE_FLAG_EXEC)
+       if (fence_is_signaled_locked(&fence->base))
                return false;
 
-       fifo_mem = fence->fman->dev_priv->mmio_virt;
+       fifo_mem = fman->dev_priv->mmio_virt;
        goal_seqno = ioread32(fifo_mem + SVGA_FIFO_FENCE_GOAL);
-       if (likely(fence->fman->seqno_valid &&
-                  goal_seqno - fence->seqno < VMW_FENCE_WRAP))
+       if (likely(fman->seqno_valid &&
+                  goal_seqno - fence->base.seqno < VMW_FENCE_WRAP))
                return false;
 
-       iowrite32(fence->seqno, fifo_mem + SVGA_FIFO_FENCE_GOAL);
-       fence->fman->seqno_valid = true;
+       iowrite32(fence->base.seqno, fifo_mem + SVGA_FIFO_FENCE_GOAL);
+       fman->seqno_valid = true;
 
        return true;
 }
 
-void vmw_fences_update(struct vmw_fence_manager *fman)
+static void __vmw_fences_update(struct vmw_fence_manager *fman)
 {
-       unsigned long flags;
        struct vmw_fence_obj *fence, *next_fence;
        struct list_head action_list;
        bool needs_rerun;
@@ -382,32 +471,25 @@ void vmw_fences_update(struct vmw_fence_manager *fman)
 
        seqno = ioread32(fifo_mem + SVGA_FIFO_FENCE);
 rerun:
-       spin_lock_irqsave(&fman->lock, flags);
        list_for_each_entry_safe(fence, next_fence, &fman->fence_list, head) {
-               if (seqno - fence->seqno < VMW_FENCE_WRAP) {
+               if (seqno - fence->base.seqno < VMW_FENCE_WRAP) {
                        list_del_init(&fence->head);
-                       fence->signaled |= DRM_VMW_FENCE_FLAG_EXEC;
+                       fence_signal_locked(&fence->base);
                        INIT_LIST_HEAD(&action_list);
                        list_splice_init(&fence->seq_passed_actions,
                                         &action_list);
                        vmw_fences_perform_actions(fman, &action_list);
-                       wake_up_all(&fence->queue);
                } else
                        break;
        }
 
-       needs_rerun = vmw_fence_goal_new_locked(fman, seqno);
-
-       if (!list_empty(&fman->cleanup_list))
-               (void) schedule_work(&fman->work);
-       spin_unlock_irqrestore(&fman->lock, flags);
-
        /*
         * Rerun if the fence goal seqno was updated, and the
         * hardware might have raced with that update, so that
         * we missed a fence_goal irq.
         */
 
+       needs_rerun = vmw_fence_goal_new_locked(fman, seqno);
        if (unlikely(needs_rerun)) {
                new_seqno = ioread32(fifo_mem + SVGA_FIFO_FENCE);
                if (new_seqno != seqno) {
@@ -415,79 +497,58 @@ rerun:
                        goto rerun;
                }
        }
+
+       if (!list_empty(&fman->cleanup_list))
+               (void) schedule_work(&fman->work);
 }
 
-bool vmw_fence_obj_signaled(struct vmw_fence_obj *fence,
-                           uint32_t flags)
+void vmw_fences_update(struct vmw_fence_manager *fman)
 {
-       struct vmw_fence_manager *fman = fence->fman;
        unsigned long irq_flags;
-       uint32_t signaled;
 
        spin_lock_irqsave(&fman->lock, irq_flags);
-       signaled = fence->signaled;
+       __vmw_fences_update(fman);
        spin_unlock_irqrestore(&fman->lock, irq_flags);
+}
 
-       flags &= fence->signal_mask;
-       if ((signaled & flags) == flags)
-               return 1;
+bool vmw_fence_obj_signaled(struct vmw_fence_obj *fence)
+{
+       struct vmw_fence_manager *fman = fman_from_fence(fence);
 
-       if ((signaled & DRM_VMW_FENCE_FLAG_EXEC) == 0)
-               vmw_fences_update(fman);
+       if (test_bit(FENCE_FLAG_SIGNALED_BIT, &fence->base.flags))
+               return 1;
 
-       spin_lock_irqsave(&fman->lock, irq_flags);
-       signaled = fence->signaled;
-       spin_unlock_irqrestore(&fman->lock, irq_flags);
+       vmw_fences_update(fman);
 
-       return ((signaled & flags) == flags);
+       return fence_is_signaled(&fence->base);
 }
 
-int vmw_fence_obj_wait(struct vmw_fence_obj *fence,
-                      uint32_t flags, bool lazy,
+int vmw_fence_obj_wait(struct vmw_fence_obj *fence, bool lazy,
                       bool interruptible, unsigned long timeout)
 {
-       struct vmw_private *dev_priv = fence->fman->dev_priv;
-       long ret;
+       long ret = fence_wait_timeout(&fence->base, interruptible, timeout);
 
-       if (likely(vmw_fence_obj_signaled(fence, flags)))
+       if (likely(ret > 0))
                return 0;
-
-       vmw_fifo_ping_host(dev_priv, SVGA_SYNC_GENERIC);
-       vmw_seqno_waiter_add(dev_priv);
-
-       if (interruptible)
-               ret = wait_event_interruptible_timeout
-                       (fence->queue,
-                        vmw_fence_obj_signaled(fence, flags),
-                        timeout);
+       else if (ret == 0)
+               return -EBUSY;
        else
-               ret = wait_event_timeout
-                       (fence->queue,
-                        vmw_fence_obj_signaled(fence, flags),
-                        timeout);
-
-       vmw_seqno_waiter_remove(dev_priv);
-
-       if (unlikely(ret == 0))
-               ret = -EBUSY;
-       else if (likely(ret > 0))
-               ret = 0;
-
-       return ret;
+               return ret;
 }
 
 void vmw_fence_obj_flush(struct vmw_fence_obj *fence)
 {
-       struct vmw_private *dev_priv = fence->fman->dev_priv;
+       struct vmw_private *dev_priv = fman_from_fence(fence)->dev_priv;
 
        vmw_fifo_ping_host(dev_priv, SVGA_SYNC_GENERIC);
 }
 
 static void vmw_fence_destroy(struct vmw_fence_obj *fence)
 {
-       struct vmw_fence_manager *fman = fence->fman;
+       struct vmw_fence_manager *fman = fman_from_fence(fence);
+
+       fence_free(&fence->base);
 
-       kfree(fence);
        /*
         * Free kernel space accounting.
         */
@@ -497,7 +558,6 @@ static void vmw_fence_destroy(struct vmw_fence_obj *fence)
 
 int vmw_fence_create(struct vmw_fence_manager *fman,
                     uint32_t seqno,
-                    uint32_t mask,
                     struct vmw_fence_obj **p_fence)
 {
        struct ttm_mem_global *mem_glob = vmw_mem_glob(fman->dev_priv);
@@ -515,7 +575,7 @@ int vmw_fence_create(struct vmw_fence_manager *fman,
                goto out_no_object;
        }
 
-       ret = vmw_fence_obj_init(fman, fence, seqno, mask,
+       ret = vmw_fence_obj_init(fman, fence, seqno,
                                 vmw_fence_destroy);
        if (unlikely(ret != 0))
                goto out_err_init;
@@ -535,7 +595,7 @@ static void vmw_user_fence_destroy(struct vmw_fence_obj *fence)
 {
        struct vmw_user_fence *ufence =
                container_of(fence, struct vmw_user_fence, fence);
-       struct vmw_fence_manager *fman = fence->fman;
+       struct vmw_fence_manager *fman = fman_from_fence(fence);
 
        ttm_base_object_kfree(ufence, base);
        /*
@@ -559,7 +619,6 @@ static void vmw_user_fence_base_release(struct ttm_base_object **p_base)
 int vmw_user_fence_create(struct drm_file *file_priv,
                          struct vmw_fence_manager *fman,
                          uint32_t seqno,
-                         uint32_t mask,
                          struct vmw_fence_obj **p_fence,
                          uint32_t *p_handle)
 {
@@ -586,7 +645,7 @@ int vmw_user_fence_create(struct drm_file *file_priv,
        }
 
        ret = vmw_fence_obj_init(fman, &ufence->fence, seqno,
-                                mask, vmw_user_fence_destroy);
+                                vmw_user_fence_destroy);
        if (unlikely(ret != 0)) {
                kfree(ufence);
                goto out_no_object;
@@ -629,7 +688,6 @@ out_no_object:
 
 void vmw_fence_fifo_down(struct vmw_fence_manager *fman)
 {
-       unsigned long irq_flags;
        struct list_head action_list;
        int ret;
 
@@ -638,35 +696,32 @@ void vmw_fence_fifo_down(struct vmw_fence_manager *fman)
         * restart when we've released the fman->lock.
         */
 
-       spin_lock_irqsave(&fman->lock, irq_flags);
+       spin_lock_irq(&fman->lock);
        fman->fifo_down = true;
        while (!list_empty(&fman->fence_list)) {
                struct vmw_fence_obj *fence =
                        list_entry(fman->fence_list.prev, struct vmw_fence_obj,
                                   head);
-               kref_get(&fence->kref);
+               fence_get(&fence->base);
                spin_unlock_irq(&fman->lock);
 
-               ret = vmw_fence_obj_wait(fence, fence->signal_mask,
-                                        false, false,
+               ret = vmw_fence_obj_wait(fence, false, false,
                                         VMW_FENCE_WAIT_TIMEOUT);
 
                if (unlikely(ret != 0)) {
                        list_del_init(&fence->head);
-                       fence->signaled |= DRM_VMW_FENCE_FLAG_EXEC;
+                       fence_signal(&fence->base);
                        INIT_LIST_HEAD(&action_list);
                        list_splice_init(&fence->seq_passed_actions,
                                         &action_list);
                        vmw_fences_perform_actions(fman, &action_list);
-                       wake_up_all(&fence->queue);
                }
 
-               spin_lock_irq(&fman->lock);
-
                BUG_ON(!list_empty(&fence->head));
-               kref_put(&fence->kref, vmw_fence_obj_destroy_locked);
+               fence_put(&fence->base);
+               spin_lock_irq(&fman->lock);
        }
-       spin_unlock_irqrestore(&fman->lock, irq_flags);
+       spin_unlock_irq(&fman->lock);
 }
 
 void vmw_fence_fifo_up(struct vmw_fence_manager *fman)
@@ -716,14 +771,14 @@ int vmw_fence_obj_wait_ioctl(struct drm_device *dev, void *data,
 
        timeout = jiffies;
        if (time_after_eq(timeout, (unsigned long)arg->kernel_cookie)) {
-               ret = ((vmw_fence_obj_signaled(fence, arg->flags)) ?
+               ret = ((vmw_fence_obj_signaled(fence)) ?
                       0 : -EBUSY);
                goto out;
        }
 
        timeout = (unsigned long)arg->kernel_cookie - timeout;
 
-       ret = vmw_fence_obj_wait(fence, arg->flags, arg->lazy, true, timeout);
+       ret = vmw_fence_obj_wait(fence, arg->lazy, true, timeout);
 
 out:
        ttm_base_object_unref(&base);
@@ -758,12 +813,12 @@ int vmw_fence_obj_signaled_ioctl(struct drm_device *dev, void *data,
        }
 
        fence = &(container_of(base, struct vmw_user_fence, base)->fence);
-       fman = fence->fman;
+       fman = fman_from_fence(fence);
 
-       arg->signaled = vmw_fence_obj_signaled(fence, arg->flags);
-       spin_lock_irq(&fman->lock);
+       arg->signaled = vmw_fence_obj_signaled(fence);
 
-       arg->signaled_flags = fence->signaled;
+       arg->signaled_flags = arg->flags;
+       spin_lock_irq(&fman->lock);
        arg->passed_seqno = dev_priv->last_read_seqno;
        spin_unlock_irq(&fman->lock);
 
@@ -876,7 +931,7 @@ static void vmw_event_fence_action_cleanup(struct vmw_fence_action *action)
 {
        struct vmw_event_fence_action *eaction =
                container_of(action, struct vmw_event_fence_action, action);
-       struct vmw_fence_manager *fman = eaction->fence->fman;
+       struct vmw_fence_manager *fman = fman_from_fence(eaction->fence);
        unsigned long irq_flags;
 
        spin_lock_irqsave(&fman->lock, irq_flags);
@@ -900,7 +955,7 @@ static void vmw_event_fence_action_cleanup(struct vmw_fence_action *action)
 static void vmw_fence_obj_add_action(struct vmw_fence_obj *fence,
                              struct vmw_fence_action *action)
 {
-       struct vmw_fence_manager *fman = fence->fman;
+       struct vmw_fence_manager *fman = fman_from_fence(fence);
        unsigned long irq_flags;
        bool run_update = false;
 
@@ -908,7 +963,7 @@ static void vmw_fence_obj_add_action(struct vmw_fence_obj *fence,
        spin_lock_irqsave(&fman->lock, irq_flags);
 
        fman->pending_actions[action->type]++;
-       if (fence->signaled & DRM_VMW_FENCE_FLAG_EXEC) {
+       if (fence_is_signaled_locked(&fence->base)) {
                struct list_head action_list;
 
                INIT_LIST_HEAD(&action_list);
@@ -960,7 +1015,7 @@ int vmw_event_fence_action_queue(struct drm_file *file_priv,
                                 bool interruptible)
 {
        struct vmw_event_fence_action *eaction;
-       struct vmw_fence_manager *fman = fence->fman;
+       struct vmw_fence_manager *fman = fman_from_fence(fence);
        struct vmw_fpriv *vmw_fp = vmw_fpriv(file_priv);
        unsigned long irq_flags;
 
@@ -1000,7 +1055,8 @@ static int vmw_event_fence_action_create(struct drm_file *file_priv,
                                  bool interruptible)
 {
        struct vmw_event_fence_pending *event;
-       struct drm_device *dev = fence->fman->dev_priv->dev;
+       struct vmw_fence_manager *fman = fman_from_fence(fence);
+       struct drm_device *dev = fman->dev_priv->dev;
        unsigned long irq_flags;
        int ret;
 
index faf2e7873860a388e4f5323e30636a53a9c2d366..26a4add392085531c2dc5d2c77c4072177a0be1d 100644 (file)
@@ -27,6 +27,8 @@
 
 #ifndef _VMWGFX_FENCE_H_
 
+#include <linux/fence.h>
+
 #define VMW_FENCE_WAIT_TIMEOUT (5*HZ)
 
 struct vmw_private;
@@ -50,16 +52,11 @@ struct vmw_fence_action {
 };
 
 struct vmw_fence_obj {
-       struct kref kref;
-       u32 seqno;
+       struct fence base;
 
-       struct vmw_fence_manager *fman;
        struct list_head head;
-       uint32_t signaled;
-       uint32_t signal_mask;
        struct list_head seq_passed_actions;
        void (*destroy)(struct vmw_fence_obj *fence);
-       wait_queue_head_t queue;
 };
 
 extern struct vmw_fence_manager *
@@ -67,17 +64,29 @@ vmw_fence_manager_init(struct vmw_private *dev_priv);
 
 extern void vmw_fence_manager_takedown(struct vmw_fence_manager *fman);
 
-extern void vmw_fence_obj_unreference(struct vmw_fence_obj **fence_p);
+static inline void
+vmw_fence_obj_unreference(struct vmw_fence_obj **fence_p)
+{
+       struct vmw_fence_obj *fence = *fence_p;
+
+       *fence_p = NULL;
+       if (fence)
+               fence_put(&fence->base);
+}
 
-extern struct vmw_fence_obj *
-vmw_fence_obj_reference(struct vmw_fence_obj *fence);
+static inline struct vmw_fence_obj *
+vmw_fence_obj_reference(struct vmw_fence_obj *fence)
+{
+       if (fence)
+               fence_get(&fence->base);
+       return fence;
+}
 
 extern void vmw_fences_update(struct vmw_fence_manager *fman);
 
-extern bool vmw_fence_obj_signaled(struct vmw_fence_obj *fence,
-                                  uint32_t flags);
+extern bool vmw_fence_obj_signaled(struct vmw_fence_obj *fence);
 
-extern int vmw_fence_obj_wait(struct vmw_fence_obj *fence, uint32_t flags,
+extern int vmw_fence_obj_wait(struct vmw_fence_obj *fence,
                              bool lazy,
                              bool interruptible, unsigned long timeout);
 
@@ -85,13 +94,11 @@ extern void vmw_fence_obj_flush(struct vmw_fence_obj *fence);
 
 extern int vmw_fence_create(struct vmw_fence_manager *fman,
                            uint32_t seqno,
-                           uint32_t mask,
                            struct vmw_fence_obj **p_fence);
 
 extern int vmw_user_fence_create(struct drm_file *file_priv,
                                 struct vmw_fence_manager *fman,
                                 uint32_t sequence,
-                                uint32_t mask,
                                 struct vmw_fence_obj **p_fence,
                                 uint32_t *p_handle);
 
index 6eae14d2a3f73511143a42da95757418edf01207..09e10aefcd8eb94e6a22182b59591cdb30cbcd36 100644 (file)
@@ -160,16 +160,21 @@ int vmw_fifo_init(struct vmw_private *dev_priv, struct vmw_fifo_state *fifo)
        return vmw_fifo_send_fence(dev_priv, &dummy);
 }
 
-void vmw_fifo_ping_host(struct vmw_private *dev_priv, uint32_t reason)
+void vmw_fifo_ping_host_locked(struct vmw_private *dev_priv, uint32_t reason)
 {
        __le32 __iomem *fifo_mem = dev_priv->mmio_virt;
 
-       mutex_lock(&dev_priv->hw_mutex);
-
        if (unlikely(ioread32(fifo_mem + SVGA_FIFO_BUSY) == 0)) {
                iowrite32(1, fifo_mem + SVGA_FIFO_BUSY);
                vmw_write(dev_priv, SVGA_REG_SYNC, reason);
        }
+}
+
+void vmw_fifo_ping_host(struct vmw_private *dev_priv, uint32_t reason)
+{
+       mutex_lock(&dev_priv->hw_mutex);
+
+       vmw_fifo_ping_host_locked(dev_priv, reason);
 
        mutex_unlock(&dev_priv->hw_mutex);
 }
index 26f8bdde3529b8a5b222a52aa34ebc8da185232a..170b61be1e4ece3069a9f9c20e7c90d1f9558ae9 100644 (file)
@@ -46,8 +46,7 @@ struct vmwgfx_gmrid_man {
 
 static int vmw_gmrid_man_get_node(struct ttm_mem_type_manager *man,
                                  struct ttm_buffer_object *bo,
-                                 struct ttm_placement *placement,
-                                 uint32_t flags,
+                                 const struct ttm_place *place,
                                  struct ttm_mem_reg *mem)
 {
        struct vmwgfx_gmrid_man *gman =
index a432c0db257c10aad67a7bbfad688e31b6781e86..026de7cea0f662bd75e92cf4ad1dfde057c7775e 100644 (file)
@@ -133,6 +133,7 @@ static void vmw_resource_release(struct kref *kref)
                        struct ttm_validate_buffer val_buf;
 
                        val_buf.bo = bo;
+                       val_buf.shared = false;
                        res->func->unbind(res, false, &val_buf);
                }
                res->backup_dirty = false;
@@ -429,7 +430,7 @@ int vmw_dmabuf_init(struct vmw_private *dev_priv,
        ret = ttm_bo_init(bdev, &vmw_bo->base, size,
                          ttm_bo_type_device, placement,
                          0, interruptible,
-                         NULL, acc_size, NULL, bo_free);
+                         NULL, acc_size, NULL, NULL, bo_free);
        return ret;
 }
 
@@ -567,13 +568,18 @@ static int vmw_user_dmabuf_synccpu_grab(struct vmw_user_dma_buffer *user_bo,
        int ret;
 
        if (flags & drm_vmw_synccpu_allow_cs) {
-               struct ttm_bo_device *bdev = bo->bdev;
+               bool nonblock = !!(flags & drm_vmw_synccpu_dontblock);
+               long lret;
 
-               spin_lock(&bdev->fence_lock);
-               ret = ttm_bo_wait(bo, false, true,
-                                 !!(flags & drm_vmw_synccpu_dontblock));
-               spin_unlock(&bdev->fence_lock);
-               return ret;
+               if (nonblock)
+                       return reservation_object_test_signaled_rcu(bo->resv, true) ? 0 : -EBUSY;
+
+               lret = reservation_object_wait_timeout_rcu(bo->resv, true, true, MAX_SCHEDULE_TIMEOUT);
+               if (!lret)
+                       return -EBUSY;
+               else if (lret < 0)
+                       return lret;
+               return 0;
        }
 
        ret = ttm_bo_synccpu_write_grab
@@ -1214,8 +1220,9 @@ vmw_resource_check_buffer(struct vmw_resource *res,
 
        INIT_LIST_HEAD(&val_list);
        val_buf->bo = ttm_bo_reference(&res->backup->base);
+       val_buf->shared = false;
        list_add_tail(&val_buf->head, &val_list);
-       ret = ttm_eu_reserve_buffers(NULL, &val_list);
+       ret = ttm_eu_reserve_buffers(NULL, &val_list, interruptible);
        if (unlikely(ret != 0))
                goto out_no_reserve;
 
@@ -1307,6 +1314,7 @@ int vmw_resource_do_evict(struct vmw_resource *res, bool interruptible)
        BUG_ON(!func->may_evict);
 
        val_buf.bo = NULL;
+       val_buf.shared = false;
        ret = vmw_resource_check_buffer(res, interruptible, &val_buf);
        if (unlikely(ret != 0))
                return ret;
@@ -1352,6 +1360,7 @@ int vmw_resource_validate(struct vmw_resource *res)
                return 0;
 
        val_buf.bo = NULL;
+       val_buf.shared = false;
        if (res->backup)
                val_buf.bo = &res->backup->base;
        do {
@@ -1419,25 +1428,16 @@ void vmw_fence_single_bo(struct ttm_buffer_object *bo,
                         struct vmw_fence_obj *fence)
 {
        struct ttm_bo_device *bdev = bo->bdev;
-       struct ttm_bo_driver *driver = bdev->driver;
-       struct vmw_fence_obj *old_fence_obj;
+
        struct vmw_private *dev_priv =
                container_of(bdev, struct vmw_private, bdev);
 
-       if (fence == NULL)
+       if (fence == NULL) {
                vmw_execbuf_fence_commands(NULL, dev_priv, &fence, NULL);
-       else
-               driver->sync_obj_ref(fence);
-
-       spin_lock(&bdev->fence_lock);
-
-       old_fence_obj = bo->sync_obj;
-       bo->sync_obj = fence;
-
-       spin_unlock(&bdev->fence_lock);
-
-       if (old_fence_obj)
-               vmw_fence_obj_unreference(&old_fence_obj);
+               reservation_object_add_excl_fence(bo->resv, &fence->base);
+               fence_put(&fence->base);
+       } else
+               reservation_object_add_excl_fence(bo->resv, &fence->base);
 }
 
 /**
@@ -1475,10 +1475,10 @@ void vmw_resource_move_notify(struct ttm_buffer_object *bo,
 
        if (mem->mem_type != VMW_PL_MOB) {
                struct vmw_resource *res, *n;
-               struct ttm_bo_device *bdev = bo->bdev;
                struct ttm_validate_buffer val_buf;
 
                val_buf.bo = bo;
+               val_buf.shared = false;
 
                list_for_each_entry_safe(res, n, &dma_buf->res_list, mob_head) {
 
@@ -1491,9 +1491,7 @@ void vmw_resource_move_notify(struct ttm_buffer_object *bo,
                        list_del_init(&res->mob_head);
                }
 
-               spin_lock(&bdev->fence_lock);
                (void) ttm_bo_wait(bo, false, false, false);
-               spin_unlock(&bdev->fence_lock);
        }
 }
 
index 2f228a2f2a4849fc8afaf87ff7feade756d222ce..aefdff95356da4782258f09797a8d8845fd35eaf 100644 (file)
@@ -1,7 +1,8 @@
 config IMX_IPUV3_CORE
        tristate "IPUv3 core support"
-       depends on SOC_IMX5 || SOC_IMX6Q || SOC_IMX6SL || ARCH_MULTIPLATFORM
+       depends on SOC_IMX5 || SOC_IMX6Q || ARCH_MULTIPLATFORM
        depends on RESET_CONTROLLER
+       select GENERIC_IRQ_CHIP
        help
          Choose this if you have a i.MX5/6 system and want to use the Image
          Processing Unit. This option only enables IPU base support.
index 0b42836caae1eb1b5a6d8cc26120279f3f2fc234..107ec236a4a6fb633d5c6974c037c02360dc7eab 100644 (file)
@@ -1,4 +1,4 @@
 obj-$(CONFIG_IMX_IPUV3_CORE) += imx-ipu-v3.o
 
-imx-ipu-v3-objs := ipu-common.o ipu-cpmem.o ipu-dc.o ipu-di.o \
-               ipu-dp.o ipu-dmfc.o ipu-smfc.o
+imx-ipu-v3-objs := ipu-common.o ipu-cpmem.o ipu-csi.o ipu-dc.o ipu-di.o \
+               ipu-dp.o ipu-dmfc.o ipu-ic.o ipu-smfc.o
index 5978e7aab8ed16a4a8c7b1762765599b234bf4ab..f707d25ae78faab593adb4c4efd5f6a8a36b113a 100644 (file)
@@ -74,6 +74,12 @@ enum ipu_color_space ipu_drm_fourcc_to_colorspace(u32 drm_fourcc)
        case DRM_FORMAT_UYVY:
        case DRM_FORMAT_YUV420:
        case DRM_FORMAT_YVU420:
+       case DRM_FORMAT_YUV422:
+       case DRM_FORMAT_YVU422:
+       case DRM_FORMAT_NV12:
+       case DRM_FORMAT_NV21:
+       case DRM_FORMAT_NV16:
+       case DRM_FORMAT_NV61:
                return IPUV3_COLORSPACE_YUV;
        default:
                return IPUV3_COLORSPACE_UNKNOWN;
@@ -86,8 +92,13 @@ enum ipu_color_space ipu_pixelformat_to_colorspace(u32 pixelformat)
        switch (pixelformat) {
        case V4L2_PIX_FMT_YUV420:
        case V4L2_PIX_FMT_YVU420:
+       case V4L2_PIX_FMT_YUV422P:
        case V4L2_PIX_FMT_UYVY:
        case V4L2_PIX_FMT_YUYV:
+       case V4L2_PIX_FMT_NV12:
+       case V4L2_PIX_FMT_NV21:
+       case V4L2_PIX_FMT_NV16:
+       case V4L2_PIX_FMT_NV61:
                return IPUV3_COLORSPACE_YUV;
        case V4L2_PIX_FMT_RGB32:
        case V4L2_PIX_FMT_BGR32:
@@ -101,6 +112,135 @@ enum ipu_color_space ipu_pixelformat_to_colorspace(u32 pixelformat)
 }
 EXPORT_SYMBOL_GPL(ipu_pixelformat_to_colorspace);
 
+bool ipu_pixelformat_is_planar(u32 pixelformat)
+{
+       switch (pixelformat) {
+       case V4L2_PIX_FMT_YUV420:
+       case V4L2_PIX_FMT_YVU420:
+       case V4L2_PIX_FMT_YUV422P:
+       case V4L2_PIX_FMT_NV12:
+       case V4L2_PIX_FMT_NV21:
+       case V4L2_PIX_FMT_NV16:
+       case V4L2_PIX_FMT_NV61:
+               return true;
+       }
+
+       return false;
+}
+EXPORT_SYMBOL_GPL(ipu_pixelformat_is_planar);
+
+enum ipu_color_space ipu_mbus_code_to_colorspace(u32 mbus_code)
+{
+       switch (mbus_code & 0xf000) {
+       case 0x1000:
+               return IPUV3_COLORSPACE_RGB;
+       case 0x2000:
+               return IPUV3_COLORSPACE_YUV;
+       default:
+               return IPUV3_COLORSPACE_UNKNOWN;
+       }
+}
+EXPORT_SYMBOL_GPL(ipu_mbus_code_to_colorspace);
+
+int ipu_stride_to_bytes(u32 pixel_stride, u32 pixelformat)
+{
+       switch (pixelformat) {
+       case V4L2_PIX_FMT_YUV420:
+       case V4L2_PIX_FMT_YVU420:
+       case V4L2_PIX_FMT_YUV422P:
+       case V4L2_PIX_FMT_NV12:
+       case V4L2_PIX_FMT_NV21:
+       case V4L2_PIX_FMT_NV16:
+       case V4L2_PIX_FMT_NV61:
+               /*
+                * for the planar YUV formats, the stride passed to
+                * cpmem must be the stride in bytes of the Y plane.
+                * And all the planar YUV formats have an 8-bit
+                * Y component.
+                */
+               return (8 * pixel_stride) >> 3;
+       case V4L2_PIX_FMT_RGB565:
+       case V4L2_PIX_FMT_YUYV:
+       case V4L2_PIX_FMT_UYVY:
+               return (16 * pixel_stride) >> 3;
+       case V4L2_PIX_FMT_BGR24:
+       case V4L2_PIX_FMT_RGB24:
+               return (24 * pixel_stride) >> 3;
+       case V4L2_PIX_FMT_BGR32:
+       case V4L2_PIX_FMT_RGB32:
+               return (32 * pixel_stride) >> 3;
+       default:
+               break;
+       }
+
+       return -EINVAL;
+}
+EXPORT_SYMBOL_GPL(ipu_stride_to_bytes);
+
+int ipu_degrees_to_rot_mode(enum ipu_rotate_mode *mode, int degrees,
+                           bool hflip, bool vflip)
+{
+       u32 r90, vf, hf;
+
+       switch (degrees) {
+       case 0:
+               vf = hf = r90 = 0;
+               break;
+       case 90:
+               vf = hf = 0;
+               r90 = 1;
+               break;
+       case 180:
+               vf = hf = 1;
+               r90 = 0;
+               break;
+       case 270:
+               vf = hf = r90 = 1;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       hf ^= (u32)hflip;
+       vf ^= (u32)vflip;
+
+       *mode = (enum ipu_rotate_mode)((r90 << 2) | (hf << 1) | vf);
+       return 0;
+}
+EXPORT_SYMBOL_GPL(ipu_degrees_to_rot_mode);
+
+int ipu_rot_mode_to_degrees(int *degrees, enum ipu_rotate_mode mode,
+                           bool hflip, bool vflip)
+{
+       u32 r90, vf, hf;
+
+       r90 = ((u32)mode >> 2) & 0x1;
+       hf = ((u32)mode >> 1) & 0x1;
+       vf = ((u32)mode >> 0) & 0x1;
+       hf ^= (u32)hflip;
+       vf ^= (u32)vflip;
+
+       switch ((enum ipu_rotate_mode)((r90 << 2) | (hf << 1) | vf)) {
+       case IPU_ROTATE_NONE:
+               *degrees = 0;
+               break;
+       case IPU_ROTATE_90_RIGHT:
+               *degrees = 90;
+               break;
+       case IPU_ROTATE_180:
+               *degrees = 180;
+               break;
+       case IPU_ROTATE_90_LEFT:
+               *degrees = 270;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(ipu_rot_mode_to_degrees);
+
 struct ipuv3_channel *ipu_idmac_get(struct ipu_soc *ipu, unsigned num)
 {
        struct ipuv3_channel *channel;
@@ -143,7 +283,26 @@ void ipu_idmac_put(struct ipuv3_channel *channel)
 }
 EXPORT_SYMBOL_GPL(ipu_idmac_put);
 
-#define idma_mask(ch)                  (1 << (ch & 0x1f))
+#define idma_mask(ch)                  (1 << ((ch) & 0x1f))
+
+/*
+ * This is an undocumented feature, a write one to a channel bit in
+ * IPU_CHA_CUR_BUF and IPU_CHA_TRIPLE_CUR_BUF will reset the channel's
+ * internal current buffer pointer so that transfers start from buffer
+ * 0 on the next channel enable (that's the theory anyway, the imx6 TRM
+ * only says these are read-only registers). This operation is required
+ * for channel linking to work correctly, for instance video capture
+ * pipelines that carry out image rotations will fail after the first
+ * streaming unless this function is called for each channel before
+ * re-enabling the channels.
+ */
+static void __ipu_idmac_reset_current_buffer(struct ipuv3_channel *channel)
+{
+       struct ipu_soc *ipu = channel->ipu;
+       unsigned int chno = channel->num;
+
+       ipu_cm_write(ipu, idma_mask(chno), IPU_CHA_CUR_BUF(chno));
+}
 
 void ipu_idmac_set_double_buffer(struct ipuv3_channel *channel,
                bool doublebuffer)
@@ -161,10 +320,81 @@ void ipu_idmac_set_double_buffer(struct ipuv3_channel *channel,
                reg &= ~idma_mask(channel->num);
        ipu_cm_write(ipu, reg, IPU_CHA_DB_MODE_SEL(channel->num));
 
+       __ipu_idmac_reset_current_buffer(channel);
+
        spin_unlock_irqrestore(&ipu->lock, flags);
 }
 EXPORT_SYMBOL_GPL(ipu_idmac_set_double_buffer);
 
+static const struct {
+       int chnum;
+       u32 reg;
+       int shift;
+} idmac_lock_en_info[] = {
+       { .chnum =  5, .reg = IDMAC_CH_LOCK_EN_1, .shift =  0, },
+       { .chnum = 11, .reg = IDMAC_CH_LOCK_EN_1, .shift =  2, },
+       { .chnum = 12, .reg = IDMAC_CH_LOCK_EN_1, .shift =  4, },
+       { .chnum = 14, .reg = IDMAC_CH_LOCK_EN_1, .shift =  6, },
+       { .chnum = 15, .reg = IDMAC_CH_LOCK_EN_1, .shift =  8, },
+       { .chnum = 20, .reg = IDMAC_CH_LOCK_EN_1, .shift = 10, },
+       { .chnum = 21, .reg = IDMAC_CH_LOCK_EN_1, .shift = 12, },
+       { .chnum = 22, .reg = IDMAC_CH_LOCK_EN_1, .shift = 14, },
+       { .chnum = 23, .reg = IDMAC_CH_LOCK_EN_1, .shift = 16, },
+       { .chnum = 27, .reg = IDMAC_CH_LOCK_EN_1, .shift = 18, },
+       { .chnum = 28, .reg = IDMAC_CH_LOCK_EN_1, .shift = 20, },
+       { .chnum = 45, .reg = IDMAC_CH_LOCK_EN_2, .shift =  0, },
+       { .chnum = 46, .reg = IDMAC_CH_LOCK_EN_2, .shift =  2, },
+       { .chnum = 47, .reg = IDMAC_CH_LOCK_EN_2, .shift =  4, },
+       { .chnum = 48, .reg = IDMAC_CH_LOCK_EN_2, .shift =  6, },
+       { .chnum = 49, .reg = IDMAC_CH_LOCK_EN_2, .shift =  8, },
+       { .chnum = 50, .reg = IDMAC_CH_LOCK_EN_2, .shift = 10, },
+};
+
+int ipu_idmac_lock_enable(struct ipuv3_channel *channel, int num_bursts)
+{
+       struct ipu_soc *ipu = channel->ipu;
+       unsigned long flags;
+       u32 bursts, regval;
+       int i;
+
+       switch (num_bursts) {
+       case 0:
+       case 1:
+               bursts = 0x00; /* locking disabled */
+               break;
+       case 2:
+               bursts = 0x01;
+               break;
+       case 4:
+               bursts = 0x02;
+               break;
+       case 8:
+               bursts = 0x03;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       for (i = 0; i < ARRAY_SIZE(idmac_lock_en_info); i++) {
+               if (channel->num == idmac_lock_en_info[i].chnum)
+                       break;
+       }
+       if (i >= ARRAY_SIZE(idmac_lock_en_info))
+               return -EINVAL;
+
+       spin_lock_irqsave(&ipu->lock, flags);
+
+       regval = ipu_idmac_read(ipu, idmac_lock_en_info[i].reg);
+       regval &= ~(0x03 << idmac_lock_en_info[i].shift);
+       regval |= (bursts << idmac_lock_en_info[i].shift);
+       ipu_idmac_write(ipu, regval, idmac_lock_en_info[i].reg);
+
+       spin_unlock_irqrestore(&ipu->lock, flags);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(ipu_idmac_lock_enable);
+
 int ipu_module_enable(struct ipu_soc *ipu, u32 mask)
 {
        unsigned long lock_flags;
@@ -217,30 +447,6 @@ int ipu_module_disable(struct ipu_soc *ipu, u32 mask)
 }
 EXPORT_SYMBOL_GPL(ipu_module_disable);
 
-int ipu_csi_enable(struct ipu_soc *ipu, int csi)
-{
-       return ipu_module_enable(ipu, csi ? IPU_CONF_CSI1_EN : IPU_CONF_CSI0_EN);
-}
-EXPORT_SYMBOL_GPL(ipu_csi_enable);
-
-int ipu_csi_disable(struct ipu_soc *ipu, int csi)
-{
-       return ipu_module_disable(ipu, csi ? IPU_CONF_CSI1_EN : IPU_CONF_CSI0_EN);
-}
-EXPORT_SYMBOL_GPL(ipu_csi_disable);
-
-int ipu_smfc_enable(struct ipu_soc *ipu)
-{
-       return ipu_module_enable(ipu, IPU_CONF_SMFC_EN);
-}
-EXPORT_SYMBOL_GPL(ipu_smfc_enable);
-
-int ipu_smfc_disable(struct ipu_soc *ipu)
-{
-       return ipu_module_disable(ipu, IPU_CONF_SMFC_EN);
-}
-EXPORT_SYMBOL_GPL(ipu_smfc_disable);
-
 int ipu_idmac_get_current_buffer(struct ipuv3_channel *channel)
 {
        struct ipu_soc *ipu = channel->ipu;
@@ -250,6 +456,30 @@ int ipu_idmac_get_current_buffer(struct ipuv3_channel *channel)
 }
 EXPORT_SYMBOL_GPL(ipu_idmac_get_current_buffer);
 
+bool ipu_idmac_buffer_is_ready(struct ipuv3_channel *channel, u32 buf_num)
+{
+       struct ipu_soc *ipu = channel->ipu;
+       unsigned long flags;
+       u32 reg = 0;
+
+       spin_lock_irqsave(&ipu->lock, flags);
+       switch (buf_num) {
+       case 0:
+               reg = ipu_cm_read(ipu, IPU_CHA_BUF0_RDY(channel->num));
+               break;
+       case 1:
+               reg = ipu_cm_read(ipu, IPU_CHA_BUF1_RDY(channel->num));
+               break;
+       case 2:
+               reg = ipu_cm_read(ipu, IPU_CHA_BUF2_RDY(channel->num));
+               break;
+       }
+       spin_unlock_irqrestore(&ipu->lock, flags);
+
+       return ((reg & idma_mask(channel->num)) != 0);
+}
+EXPORT_SYMBOL_GPL(ipu_idmac_buffer_is_ready);
+
 void ipu_idmac_select_buffer(struct ipuv3_channel *channel, u32 buf_num)
 {
        struct ipu_soc *ipu = channel->ipu;
@@ -268,6 +498,34 @@ void ipu_idmac_select_buffer(struct ipuv3_channel *channel, u32 buf_num)
 }
 EXPORT_SYMBOL_GPL(ipu_idmac_select_buffer);
 
+void ipu_idmac_clear_buffer(struct ipuv3_channel *channel, u32 buf_num)
+{
+       struct ipu_soc *ipu = channel->ipu;
+       unsigned int chno = channel->num;
+       unsigned long flags;
+
+       spin_lock_irqsave(&ipu->lock, flags);
+
+       ipu_cm_write(ipu, 0xF0300000, IPU_GPR); /* write one to clear */
+       switch (buf_num) {
+       case 0:
+               ipu_cm_write(ipu, idma_mask(chno), IPU_CHA_BUF0_RDY(chno));
+               break;
+       case 1:
+               ipu_cm_write(ipu, idma_mask(chno), IPU_CHA_BUF1_RDY(chno));
+               break;
+       case 2:
+               ipu_cm_write(ipu, idma_mask(chno), IPU_CHA_BUF2_RDY(chno));
+               break;
+       default:
+               break;
+       }
+       ipu_cm_write(ipu, 0x0, IPU_GPR); /* write one to set */
+
+       spin_unlock_irqrestore(&ipu->lock, flags);
+}
+EXPORT_SYMBOL_GPL(ipu_idmac_clear_buffer);
+
 int ipu_idmac_enable_channel(struct ipuv3_channel *channel)
 {
        struct ipu_soc *ipu = channel->ipu;
@@ -338,6 +596,8 @@ int ipu_idmac_disable_channel(struct ipuv3_channel *channel)
        val &= ~idma_mask(channel->num);
        ipu_idmac_write(ipu, val, IDMAC_CHA_EN(channel->num));
 
+       __ipu_idmac_reset_current_buffer(channel);
+
        /* Set channel buffers NOT to be ready */
        ipu_cm_write(ipu, 0xf0000000, IPU_GPR); /* write one to clear */
 
@@ -366,6 +626,31 @@ int ipu_idmac_disable_channel(struct ipuv3_channel *channel)
 }
 EXPORT_SYMBOL_GPL(ipu_idmac_disable_channel);
 
+/*
+ * The imx6 rev. D TRM says that enabling the WM feature will increase
+ * a channel's priority. Refer to Table 36-8 Calculated priority value.
+ * The sub-module that is the sink or source for the channel must enable
+ * watermark signal for this to take effect (SMFC_WM for instance).
+ */
+void ipu_idmac_enable_watermark(struct ipuv3_channel *channel, bool enable)
+{
+       struct ipu_soc *ipu = channel->ipu;
+       unsigned long flags;
+       u32 val;
+
+       spin_lock_irqsave(&ipu->lock, flags);
+
+       val = ipu_idmac_read(ipu, IDMAC_WM_EN(channel->num));
+       if (enable)
+               val |= 1 << (channel->num % 32);
+       else
+               val &= ~(1 << (channel->num % 32));
+       ipu_idmac_write(ipu, val, IDMAC_WM_EN(channel->num));
+
+       spin_unlock_irqrestore(&ipu->lock, flags);
+}
+EXPORT_SYMBOL_GPL(ipu_idmac_enable_watermark);
+
 static int ipu_memory_reset(struct ipu_soc *ipu)
 {
        unsigned long timeout;
@@ -382,12 +667,66 @@ static int ipu_memory_reset(struct ipu_soc *ipu)
        return 0;
 }
 
+/*
+ * Set the source mux for the given CSI. Selects either parallel or
+ * MIPI CSI2 sources.
+ */
+void ipu_set_csi_src_mux(struct ipu_soc *ipu, int csi_id, bool mipi_csi2)
+{
+       unsigned long flags;
+       u32 val, mask;
+
+       mask = (csi_id == 1) ? IPU_CONF_CSI1_DATA_SOURCE :
+               IPU_CONF_CSI0_DATA_SOURCE;
+
+       spin_lock_irqsave(&ipu->lock, flags);
+
+       val = ipu_cm_read(ipu, IPU_CONF);
+       if (mipi_csi2)
+               val |= mask;
+       else
+               val &= ~mask;
+       ipu_cm_write(ipu, val, IPU_CONF);
+
+       spin_unlock_irqrestore(&ipu->lock, flags);
+}
+EXPORT_SYMBOL_GPL(ipu_set_csi_src_mux);
+
+/*
+ * Set the source mux for the IC. Selects either CSI[01] or the VDI.
+ */
+void ipu_set_ic_src_mux(struct ipu_soc *ipu, int csi_id, bool vdi)
+{
+       unsigned long flags;
+       u32 val;
+
+       spin_lock_irqsave(&ipu->lock, flags);
+
+       val = ipu_cm_read(ipu, IPU_CONF);
+       if (vdi) {
+               val |= IPU_CONF_IC_INPUT;
+       } else {
+               val &= ~IPU_CONF_IC_INPUT;
+               if (csi_id == 1)
+                       val |= IPU_CONF_CSI_SEL;
+               else
+                       val &= ~IPU_CONF_CSI_SEL;
+       }
+       ipu_cm_write(ipu, val, IPU_CONF);
+
+       spin_unlock_irqrestore(&ipu->lock, flags);
+}
+EXPORT_SYMBOL_GPL(ipu_set_ic_src_mux);
+
 struct ipu_devtype {
        const char *name;
        unsigned long cm_ofs;
        unsigned long cpmem_ofs;
        unsigned long srm_ofs;
        unsigned long tpm_ofs;
+       unsigned long csi0_ofs;
+       unsigned long csi1_ofs;
+       unsigned long ic_ofs;
        unsigned long disp0_ofs;
        unsigned long disp1_ofs;
        unsigned long dc_tmpl_ofs;
@@ -401,6 +740,9 @@ static struct ipu_devtype ipu_type_imx51 = {
        .cpmem_ofs = 0x1f000000,
        .srm_ofs = 0x1f040000,
        .tpm_ofs = 0x1f060000,
+       .csi0_ofs = 0x1f030000,
+       .csi1_ofs = 0x1f038000,
+       .ic_ofs = 0x1f020000,
        .disp0_ofs = 0x1e040000,
        .disp1_ofs = 0x1e048000,
        .dc_tmpl_ofs = 0x1f080000,
@@ -414,6 +756,9 @@ static struct ipu_devtype ipu_type_imx53 = {
        .cpmem_ofs = 0x07000000,
        .srm_ofs = 0x07040000,
        .tpm_ofs = 0x07060000,
+       .csi0_ofs = 0x07030000,
+       .csi1_ofs = 0x07038000,
+       .ic_ofs = 0x07020000,
        .disp0_ofs = 0x06040000,
        .disp1_ofs = 0x06048000,
        .dc_tmpl_ofs = 0x07080000,
@@ -427,6 +772,9 @@ static struct ipu_devtype ipu_type_imx6q = {
        .cpmem_ofs = 0x00300000,
        .srm_ofs = 0x00340000,
        .tpm_ofs = 0x00360000,
+       .csi0_ofs = 0x00230000,
+       .csi1_ofs = 0x00238000,
+       .ic_ofs = 0x00220000,
        .disp0_ofs = 0x00240000,
        .disp1_ofs = 0x00248000,
        .dc_tmpl_ofs = 0x00380000,
@@ -457,8 +805,30 @@ static int ipu_submodules_init(struct ipu_soc *ipu,
                goto err_cpmem;
        }
 
+       ret = ipu_csi_init(ipu, dev, 0, ipu_base + devtype->csi0_ofs,
+                          IPU_CONF_CSI0_EN, ipu_clk);
+       if (ret) {
+               unit = "csi0";
+               goto err_csi_0;
+       }
+
+       ret = ipu_csi_init(ipu, dev, 1, ipu_base + devtype->csi1_ofs,
+                          IPU_CONF_CSI1_EN, ipu_clk);
+       if (ret) {
+               unit = "csi1";
+               goto err_csi_1;
+       }
+
+       ret = ipu_ic_init(ipu, dev,
+                         ipu_base + devtype->ic_ofs,
+                         ipu_base + devtype->tpm_ofs);
+       if (ret) {
+               unit = "ic";
+               goto err_ic;
+       }
+
        ret = ipu_di_init(ipu, dev, 0, ipu_base + devtype->disp0_ofs,
-                       IPU_CONF_DI0_EN, ipu_clk);
+                         IPU_CONF_DI0_EN, ipu_clk);
        if (ret) {
                unit = "di0";
                goto err_di_0;
@@ -511,6 +881,12 @@ err_dc:
 err_di_1:
        ipu_di_exit(ipu, 0);
 err_di_0:
+       ipu_ic_exit(ipu);
+err_ic:
+       ipu_csi_exit(ipu, 1);
+err_csi_1:
+       ipu_csi_exit(ipu, 0);
+err_csi_0:
        ipu_cpmem_exit(ipu);
 err_cpmem:
        dev_err(&pdev->dev, "init %s failed with %d\n", unit, ret);
@@ -589,6 +965,9 @@ static void ipu_submodules_exit(struct ipu_soc *ipu)
        ipu_dc_exit(ipu);
        ipu_di_exit(ipu, 1);
        ipu_di_exit(ipu, 0);
+       ipu_ic_exit(ipu);
+       ipu_csi_exit(ipu, 1);
+       ipu_csi_exit(ipu, 0);
        ipu_cpmem_exit(ipu);
 }
 
@@ -681,8 +1060,10 @@ static int ipu_add_client_devices(struct ipu_soc *ipu, unsigned long ipu_base)
                                id++, &reg->pdata, sizeof(reg->pdata));
                }
 
-               if (IS_ERR(pdev))
+               if (IS_ERR(pdev)) {
+                       ret = PTR_ERR(pdev);
                        goto err_register;
+               }
        }
 
        return 0;
@@ -766,6 +1147,44 @@ static void ipu_irq_exit(struct ipu_soc *ipu)
        irq_domain_remove(ipu->domain);
 }
 
+void ipu_dump(struct ipu_soc *ipu)
+{
+       int i;
+
+       dev_dbg(ipu->dev, "IPU_CONF = \t0x%08X\n",
+               ipu_cm_read(ipu, IPU_CONF));
+       dev_dbg(ipu->dev, "IDMAC_CONF = \t0x%08X\n",
+               ipu_idmac_read(ipu, IDMAC_CONF));
+       dev_dbg(ipu->dev, "IDMAC_CHA_EN1 = \t0x%08X\n",
+               ipu_idmac_read(ipu, IDMAC_CHA_EN(0)));
+       dev_dbg(ipu->dev, "IDMAC_CHA_EN2 = \t0x%08X\n",
+               ipu_idmac_read(ipu, IDMAC_CHA_EN(32)));
+       dev_dbg(ipu->dev, "IDMAC_CHA_PRI1 = \t0x%08X\n",
+               ipu_idmac_read(ipu, IDMAC_CHA_PRI(0)));
+       dev_dbg(ipu->dev, "IDMAC_CHA_PRI2 = \t0x%08X\n",
+               ipu_idmac_read(ipu, IDMAC_CHA_PRI(32)));
+       dev_dbg(ipu->dev, "IDMAC_BAND_EN1 = \t0x%08X\n",
+               ipu_idmac_read(ipu, IDMAC_BAND_EN(0)));
+       dev_dbg(ipu->dev, "IDMAC_BAND_EN2 = \t0x%08X\n",
+               ipu_idmac_read(ipu, IDMAC_BAND_EN(32)));
+       dev_dbg(ipu->dev, "IPU_CHA_DB_MODE_SEL0 = \t0x%08X\n",
+               ipu_cm_read(ipu, IPU_CHA_DB_MODE_SEL(0)));
+       dev_dbg(ipu->dev, "IPU_CHA_DB_MODE_SEL1 = \t0x%08X\n",
+               ipu_cm_read(ipu, IPU_CHA_DB_MODE_SEL(32)));
+       dev_dbg(ipu->dev, "IPU_FS_PROC_FLOW1 = \t0x%08X\n",
+               ipu_cm_read(ipu, IPU_FS_PROC_FLOW1));
+       dev_dbg(ipu->dev, "IPU_FS_PROC_FLOW2 = \t0x%08X\n",
+               ipu_cm_read(ipu, IPU_FS_PROC_FLOW2));
+       dev_dbg(ipu->dev, "IPU_FS_PROC_FLOW3 = \t0x%08X\n",
+               ipu_cm_read(ipu, IPU_FS_PROC_FLOW3));
+       dev_dbg(ipu->dev, "IPU_FS_DISP_FLOW1 = \t0x%08X\n",
+               ipu_cm_read(ipu, IPU_FS_DISP_FLOW1));
+       for (i = 0; i < 15; i++)
+               dev_dbg(ipu->dev, "IPU_INT_CTRL(%d) = \t%08X\n", i,
+                       ipu_cm_read(ipu, IPU_INT_CTRL(i)));
+}
+EXPORT_SYMBOL_GPL(ipu_dump);
+
 static int ipu_probe(struct platform_device *pdev)
 {
        const struct of_device_id *of_id =
@@ -808,6 +1227,12 @@ static int ipu_probe(struct platform_device *pdev)
                        ipu_base + devtype->cm_ofs + IPU_CM_IDMAC_REG_OFS);
        dev_dbg(&pdev->dev, "cpmem:    0x%08lx\n",
                        ipu_base + devtype->cpmem_ofs);
+       dev_dbg(&pdev->dev, "csi0:    0x%08lx\n",
+                       ipu_base + devtype->csi0_ofs);
+       dev_dbg(&pdev->dev, "csi1:    0x%08lx\n",
+                       ipu_base + devtype->csi1_ofs);
+       dev_dbg(&pdev->dev, "ic:      0x%08lx\n",
+                       ipu_base + devtype->ic_ofs);
        dev_dbg(&pdev->dev, "disp0:    0x%08lx\n",
                        ipu_base + devtype->disp0_ofs);
        dev_dbg(&pdev->dev, "disp1:    0x%08lx\n",
index 7adfa78a48bc820b3193f8287a83fce719c5ac70..3bf05bc4ab67b03c82187666eaf0c3fee022ae60 100644 (file)
@@ -64,6 +64,7 @@ struct ipu_cpmem {
 #define IPU_FIELD_BNDM         IPU_CPMEM_WORD(0, 114, 3)
 #define IPU_FIELD_BM           IPU_CPMEM_WORD(0, 117, 2)
 #define IPU_FIELD_ROT          IPU_CPMEM_WORD(0, 119, 1)
+#define IPU_FIELD_ROT_HF_VF    IPU_CPMEM_WORD(0, 119, 3)
 #define IPU_FIELD_HF           IPU_CPMEM_WORD(0, 120, 1)
 #define IPU_FIELD_VF           IPU_CPMEM_WORD(0, 121, 1)
 #define IPU_FIELD_THE          IPU_CPMEM_WORD(0, 122, 1)
@@ -192,8 +193,14 @@ static int v4l2_pix_fmt_to_drm_fourcc(u32 pixelformat)
                return DRM_FORMAT_YUYV;
        case V4L2_PIX_FMT_YUV420:
                return DRM_FORMAT_YUV420;
+       case V4L2_PIX_FMT_YUV422P:
+               return DRM_FORMAT_YUV422;
        case V4L2_PIX_FMT_YVU420:
                return DRM_FORMAT_YVU420;
+       case V4L2_PIX_FMT_NV12:
+               return DRM_FORMAT_NV12;
+       case V4L2_PIX_FMT_NV16:
+               return DRM_FORMAT_NV16;
        }
 
        return -EINVAL;
@@ -254,12 +261,34 @@ void ipu_cpmem_interlaced_scan(struct ipuv3_channel *ch, int stride)
 };
 EXPORT_SYMBOL_GPL(ipu_cpmem_interlaced_scan);
 
+void ipu_cpmem_set_axi_id(struct ipuv3_channel *ch, u32 id)
+{
+       id &= 0x3;
+       ipu_ch_param_write_field(ch, IPU_FIELD_ID, id);
+}
+EXPORT_SYMBOL_GPL(ipu_cpmem_set_axi_id);
+
 void ipu_cpmem_set_burstsize(struct ipuv3_channel *ch, int burstsize)
 {
        ipu_ch_param_write_field(ch, IPU_FIELD_NPB, burstsize - 1);
 };
 EXPORT_SYMBOL_GPL(ipu_cpmem_set_burstsize);
 
+void ipu_cpmem_set_block_mode(struct ipuv3_channel *ch)
+{
+       ipu_ch_param_write_field(ch, IPU_FIELD_BM, 1);
+}
+EXPORT_SYMBOL_GPL(ipu_cpmem_set_block_mode);
+
+void ipu_cpmem_set_rotation(struct ipuv3_channel *ch,
+                           enum ipu_rotate_mode rot)
+{
+       u32 temp_rot = bitrev8(rot) >> 5;
+
+       ipu_ch_param_write_field(ch, IPU_FIELD_ROT_HF_VF, temp_rot);
+}
+EXPORT_SYMBOL_GPL(ipu_cpmem_set_rotation);
+
 int ipu_cpmem_set_format_rgb(struct ipuv3_channel *ch,
                             const struct ipu_rgb *rgb)
 {
@@ -371,6 +400,7 @@ void ipu_cpmem_set_yuv_planar_full(struct ipuv3_channel *ch,
 {
        switch (pixel_format) {
        case V4L2_PIX_FMT_YUV420:
+       case V4L2_PIX_FMT_YUV422P:
                ipu_ch_param_write_field(ch, IPU_FIELD_SLUV, (stride / 2) - 1);
                ipu_ch_param_write_field(ch, IPU_FIELD_UBO, u_offset / 8);
                ipu_ch_param_write_field(ch, IPU_FIELD_VBO, v_offset / 8);
@@ -380,6 +410,12 @@ void ipu_cpmem_set_yuv_planar_full(struct ipuv3_channel *ch,
                ipu_ch_param_write_field(ch, IPU_FIELD_UBO, v_offset / 8);
                ipu_ch_param_write_field(ch, IPU_FIELD_VBO, u_offset / 8);
                break;
+       case V4L2_PIX_FMT_NV12:
+       case V4L2_PIX_FMT_NV16:
+               ipu_ch_param_write_field(ch, IPU_FIELD_SLUV, stride - 1);
+               ipu_ch_param_write_field(ch, IPU_FIELD_UBO, u_offset / 8);
+               ipu_ch_param_write_field(ch, IPU_FIELD_VBO, u_offset / 8);
+               break;
        }
 }
 EXPORT_SYMBOL_GPL(ipu_cpmem_set_yuv_planar_full);
@@ -399,6 +435,19 @@ void ipu_cpmem_set_yuv_planar(struct ipuv3_channel *ch,
                ipu_cpmem_set_yuv_planar_full(ch, pixel_format, stride,
                                              u_offset, v_offset);
                break;
+       case V4L2_PIX_FMT_YUV422P:
+               uv_stride = stride / 2;
+               u_offset = stride * height;
+               v_offset = u_offset + (uv_stride * height);
+               ipu_cpmem_set_yuv_planar_full(ch, pixel_format, stride,
+                                             u_offset, v_offset);
+               break;
+       case V4L2_PIX_FMT_NV12:
+       case V4L2_PIX_FMT_NV16:
+               u_offset = stride * height;
+               ipu_cpmem_set_yuv_planar_full(ch, pixel_format, stride,
+                                             u_offset, 0);
+               break;
        }
 }
 EXPORT_SYMBOL_GPL(ipu_cpmem_set_yuv_planar);
@@ -452,11 +501,20 @@ static const struct ipu_rgb def_bgr_16 = {
 };
 
 #define Y_OFFSET(pix, x, y)    ((x) + pix->width * (y))
-#define U_OFFSET(pix, x, y)    ((pix->width * pix->height) + \
-                                       (pix->width * (y) / 4) + (x) / 2)
-#define V_OFFSET(pix, x, y)    ((pix->width * pix->height) + \
-                                       (pix->width * pix->height / 4) + \
-                                       (pix->width * (y) / 4) + (x) / 2)
+#define U_OFFSET(pix, x, y)    ((pix->width * pix->height) +           \
+                                (pix->width * (y) / 4) + (x) / 2)
+#define V_OFFSET(pix, x, y)    ((pix->width * pix->height) +           \
+                                (pix->width * pix->height / 4) +       \
+                                (pix->width * (y) / 4) + (x) / 2)
+#define U2_OFFSET(pix, x, y)   ((pix->width * pix->height) +           \
+                                (pix->width * (y) / 2) + (x) / 2)
+#define V2_OFFSET(pix, x, y)   ((pix->width * pix->height) +           \
+                                (pix->width * pix->height / 2) +       \
+                                (pix->width * (y) / 2) + (x) / 2)
+#define UV_OFFSET(pix, x, y)   ((pix->width * pix->height) +   \
+                                (pix->width * (y) / 2) + (x))
+#define UV2_OFFSET(pix, x, y)  ((pix->width * pix->height) +   \
+                                (pix->width * y) + (x))
 
 int ipu_cpmem_set_fmt(struct ipuv3_channel *ch, u32 drm_fourcc)
 {
@@ -468,6 +526,25 @@ int ipu_cpmem_set_fmt(struct ipuv3_channel *ch, u32 drm_fourcc)
                /* burst size */
                ipu_ch_param_write_field(ch, IPU_FIELD_NPB, 31);
                break;
+       case DRM_FORMAT_YUV422:
+       case DRM_FORMAT_YVU422:
+               /* pix format */
+               ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 1);
+               /* burst size */
+               ipu_ch_param_write_field(ch, IPU_FIELD_NPB, 31);
+               break;
+       case DRM_FORMAT_NV12:
+               /* pix format */
+               ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 4);
+               /* burst size */
+               ipu_ch_param_write_field(ch, IPU_FIELD_NPB, 31);
+               break;
+       case DRM_FORMAT_NV16:
+               /* pix format */
+               ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 3);
+               /* burst size */
+               ipu_ch_param_write_field(ch, IPU_FIELD_NPB, 31);
+               break;
        case DRM_FORMAT_UYVY:
                /* bits/pixel */
                ipu_ch_param_write_field(ch, IPU_FIELD_BPP, 3);
@@ -515,7 +592,7 @@ EXPORT_SYMBOL_GPL(ipu_cpmem_set_fmt);
 int ipu_cpmem_set_image(struct ipuv3_channel *ch, struct ipu_image *image)
 {
        struct v4l2_pix_format *pix = &image->pix;
-       int y_offset, u_offset, v_offset;
+       int offset, u_offset, v_offset;
 
        pr_debug("%s: resolution: %dx%d stride: %d\n",
                 __func__, pix->width, pix->height,
@@ -529,47 +606,137 @@ int ipu_cpmem_set_image(struct ipuv3_channel *ch, struct ipu_image *image)
        switch (pix->pixelformat) {
        case V4L2_PIX_FMT_YUV420:
        case V4L2_PIX_FMT_YVU420:
-               y_offset = Y_OFFSET(pix, image->rect.left, image->rect.top);
+               offset = Y_OFFSET(pix, image->rect.left, image->rect.top);
                u_offset = U_OFFSET(pix, image->rect.left,
-                                   image->rect.top) - y_offset;
+                                   image->rect.top) - offset;
                v_offset = V_OFFSET(pix, image->rect.left,
-                                   image->rect.top) - y_offset;
+                                   image->rect.top) - offset;
+
+               ipu_cpmem_set_yuv_planar_full(ch, pix->pixelformat,
+                                             pix->bytesperline,
+                                             u_offset, v_offset);
+               break;
+       case V4L2_PIX_FMT_YUV422P:
+               offset = Y_OFFSET(pix, image->rect.left, image->rect.top);
+               u_offset = U2_OFFSET(pix, image->rect.left,
+                                    image->rect.top) - offset;
+               v_offset = V2_OFFSET(pix, image->rect.left,
+                                    image->rect.top) - offset;
 
                ipu_cpmem_set_yuv_planar_full(ch, pix->pixelformat,
-                               pix->bytesperline, u_offset, v_offset);
-               ipu_cpmem_set_buffer(ch, 0, image->phys + y_offset);
+                                             pix->bytesperline,
+                                             u_offset, v_offset);
+               break;
+       case V4L2_PIX_FMT_NV12:
+               offset = Y_OFFSET(pix, image->rect.left, image->rect.top);
+               u_offset = UV_OFFSET(pix, image->rect.left,
+                                    image->rect.top) - offset;
+               v_offset = 0;
+
+               ipu_cpmem_set_yuv_planar_full(ch, pix->pixelformat,
+                                             pix->bytesperline,
+                                             u_offset, v_offset);
+               break;
+       case V4L2_PIX_FMT_NV16:
+               offset = Y_OFFSET(pix, image->rect.left, image->rect.top);
+               u_offset = UV2_OFFSET(pix, image->rect.left,
+                                     image->rect.top) - offset;
+               v_offset = 0;
+
+               ipu_cpmem_set_yuv_planar_full(ch, pix->pixelformat,
+                                             pix->bytesperline,
+                                             u_offset, v_offset);
                break;
        case V4L2_PIX_FMT_UYVY:
        case V4L2_PIX_FMT_YUYV:
-               ipu_cpmem_set_buffer(ch, 0, image->phys +
-                                    image->rect.left * 2 +
-                                    image->rect.top * image->pix.bytesperline);
+       case V4L2_PIX_FMT_RGB565:
+               offset = image->rect.left * 2 +
+                       image->rect.top * pix->bytesperline;
                break;
        case V4L2_PIX_FMT_RGB32:
        case V4L2_PIX_FMT_BGR32:
-               ipu_cpmem_set_buffer(ch, 0, image->phys +
-                                    image->rect.left * 4 +
-                                    image->rect.top * image->pix.bytesperline);
-               break;
-       case V4L2_PIX_FMT_RGB565:
-               ipu_cpmem_set_buffer(ch, 0, image->phys +
-                                    image->rect.left * 2 +
-                                    image->rect.top * image->pix.bytesperline);
+               offset = image->rect.left * 4 +
+                       image->rect.top * pix->bytesperline;
                break;
        case V4L2_PIX_FMT_RGB24:
        case V4L2_PIX_FMT_BGR24:
-               ipu_cpmem_set_buffer(ch, 0, image->phys +
-                                    image->rect.left * 3 +
-                                    image->rect.top * image->pix.bytesperline);
+               offset = image->rect.left * 3 +
+                       image->rect.top * pix->bytesperline;
                break;
        default:
                return -EINVAL;
        }
 
+       ipu_cpmem_set_buffer(ch, 0, image->phys0 + offset);
+       ipu_cpmem_set_buffer(ch, 1, image->phys1 + offset);
+
        return 0;
 }
 EXPORT_SYMBOL_GPL(ipu_cpmem_set_image);
 
+void ipu_cpmem_dump(struct ipuv3_channel *ch)
+{
+       struct ipu_ch_param __iomem *p = ipu_get_cpmem(ch);
+       struct ipu_soc *ipu = ch->ipu;
+       int chno = ch->num;
+
+       dev_dbg(ipu->dev, "ch %d word 0 - %08X %08X %08X %08X %08X\n", chno,
+               readl(&p->word[0].data[0]),
+               readl(&p->word[0].data[1]),
+               readl(&p->word[0].data[2]),
+               readl(&p->word[0].data[3]),
+               readl(&p->word[0].data[4]));
+       dev_dbg(ipu->dev, "ch %d word 1 - %08X %08X %08X %08X %08X\n", chno,
+               readl(&p->word[1].data[0]),
+               readl(&p->word[1].data[1]),
+               readl(&p->word[1].data[2]),
+               readl(&p->word[1].data[3]),
+               readl(&p->word[1].data[4]));
+       dev_dbg(ipu->dev, "PFS 0x%x, ",
+                ipu_ch_param_read_field(ch, IPU_FIELD_PFS));
+       dev_dbg(ipu->dev, "BPP 0x%x, ",
+               ipu_ch_param_read_field(ch, IPU_FIELD_BPP));
+       dev_dbg(ipu->dev, "NPB 0x%x\n",
+                ipu_ch_param_read_field(ch, IPU_FIELD_NPB));
+
+       dev_dbg(ipu->dev, "FW %d, ",
+                ipu_ch_param_read_field(ch, IPU_FIELD_FW));
+       dev_dbg(ipu->dev, "FH %d, ",
+                ipu_ch_param_read_field(ch, IPU_FIELD_FH));
+       dev_dbg(ipu->dev, "EBA0 0x%x\n",
+                ipu_ch_param_read_field(ch, IPU_FIELD_EBA0) << 3);
+       dev_dbg(ipu->dev, "EBA1 0x%x\n",
+                ipu_ch_param_read_field(ch, IPU_FIELD_EBA1) << 3);
+       dev_dbg(ipu->dev, "Stride %d\n",
+                ipu_ch_param_read_field(ch, IPU_FIELD_SL));
+       dev_dbg(ipu->dev, "scan_order %d\n",
+                ipu_ch_param_read_field(ch, IPU_FIELD_SO));
+       dev_dbg(ipu->dev, "uv_stride %d\n",
+                ipu_ch_param_read_field(ch, IPU_FIELD_SLUV));
+       dev_dbg(ipu->dev, "u_offset 0x%x\n",
+                ipu_ch_param_read_field(ch, IPU_FIELD_UBO) << 3);
+       dev_dbg(ipu->dev, "v_offset 0x%x\n",
+                ipu_ch_param_read_field(ch, IPU_FIELD_VBO) << 3);
+
+       dev_dbg(ipu->dev, "Width0 %d+1, ",
+                ipu_ch_param_read_field(ch, IPU_FIELD_WID0));
+       dev_dbg(ipu->dev, "Width1 %d+1, ",
+                ipu_ch_param_read_field(ch, IPU_FIELD_WID1));
+       dev_dbg(ipu->dev, "Width2 %d+1, ",
+                ipu_ch_param_read_field(ch, IPU_FIELD_WID2));
+       dev_dbg(ipu->dev, "Width3 %d+1, ",
+                ipu_ch_param_read_field(ch, IPU_FIELD_WID3));
+       dev_dbg(ipu->dev, "Offset0 %d, ",
+                ipu_ch_param_read_field(ch, IPU_FIELD_OFS0));
+       dev_dbg(ipu->dev, "Offset1 %d, ",
+                ipu_ch_param_read_field(ch, IPU_FIELD_OFS1));
+       dev_dbg(ipu->dev, "Offset2 %d, ",
+                ipu_ch_param_read_field(ch, IPU_FIELD_OFS2));
+       dev_dbg(ipu->dev, "Offset3 %d\n",
+                ipu_ch_param_read_field(ch, IPU_FIELD_OFS3));
+}
+EXPORT_SYMBOL_GPL(ipu_cpmem_dump);
+
 int ipu_cpmem_init(struct ipu_soc *ipu, struct device *dev, unsigned long base)
 {
        struct ipu_cpmem *cpmem;
diff --git a/drivers/gpu/ipu-v3/ipu-csi.c b/drivers/gpu/ipu-v3/ipu-csi.c
new file mode 100644 (file)
index 0000000..d6f5647
--- /dev/null
@@ -0,0 +1,741 @@
+/*
+ * Copyright (C) 2012-2014 Mentor Graphics Inc.
+ * Copyright (C) 2005-2009 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * 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/export.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/videodev2.h>
+#include <uapi/linux/v4l2-mediabus.h>
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/clkdev.h>
+
+#include "ipu-prv.h"
+
+struct ipu_csi {
+       void __iomem *base;
+       int id;
+       u32 module;
+       struct clk *clk_ipu;    /* IPU bus clock */
+       spinlock_t lock;
+       bool inuse;
+       struct ipu_soc *ipu;
+};
+
+/* CSI Register Offsets */
+#define CSI_SENS_CONF          0x0000
+#define CSI_SENS_FRM_SIZE      0x0004
+#define CSI_ACT_FRM_SIZE       0x0008
+#define CSI_OUT_FRM_CTRL       0x000c
+#define CSI_TST_CTRL           0x0010
+#define CSI_CCIR_CODE_1                0x0014
+#define CSI_CCIR_CODE_2                0x0018
+#define CSI_CCIR_CODE_3                0x001c
+#define CSI_MIPI_DI            0x0020
+#define CSI_SKIP               0x0024
+#define CSI_CPD_CTRL           0x0028
+#define CSI_CPD_RC(n)          (0x002c + ((n)*4))
+#define CSI_CPD_RS(n)          (0x004c + ((n)*4))
+#define CSI_CPD_GRC(n)         (0x005c + ((n)*4))
+#define CSI_CPD_GRS(n)         (0x007c + ((n)*4))
+#define CSI_CPD_GBC(n)         (0x008c + ((n)*4))
+#define CSI_CPD_GBS(n)         (0x00Ac + ((n)*4))
+#define CSI_CPD_BC(n)          (0x00Bc + ((n)*4))
+#define CSI_CPD_BS(n)          (0x00Dc + ((n)*4))
+#define CSI_CPD_OFFSET1                0x00ec
+#define CSI_CPD_OFFSET2                0x00f0
+
+/* CSI Register Fields */
+#define CSI_SENS_CONF_DATA_FMT_SHIFT           8
+#define CSI_SENS_CONF_DATA_FMT_MASK            0x00000700
+#define CSI_SENS_CONF_DATA_FMT_RGB_YUV444      0L
+#define CSI_SENS_CONF_DATA_FMT_YUV422_YUYV     1L
+#define CSI_SENS_CONF_DATA_FMT_YUV422_UYVY     2L
+#define CSI_SENS_CONF_DATA_FMT_BAYER           3L
+#define CSI_SENS_CONF_DATA_FMT_RGB565          4L
+#define CSI_SENS_CONF_DATA_FMT_RGB555          5L
+#define CSI_SENS_CONF_DATA_FMT_RGB444          6L
+#define CSI_SENS_CONF_DATA_FMT_JPEG            7L
+
+#define CSI_SENS_CONF_VSYNC_POL_SHIFT          0
+#define CSI_SENS_CONF_HSYNC_POL_SHIFT          1
+#define CSI_SENS_CONF_DATA_POL_SHIFT           2
+#define CSI_SENS_CONF_PIX_CLK_POL_SHIFT                3
+#define CSI_SENS_CONF_SENS_PRTCL_MASK          0x00000070
+#define CSI_SENS_CONF_SENS_PRTCL_SHIFT         4
+#define CSI_SENS_CONF_PACK_TIGHT_SHIFT         7
+#define CSI_SENS_CONF_DATA_WIDTH_SHIFT         11
+#define CSI_SENS_CONF_EXT_VSYNC_SHIFT          15
+#define CSI_SENS_CONF_DIVRATIO_SHIFT           16
+
+#define CSI_SENS_CONF_DIVRATIO_MASK            0x00ff0000
+#define CSI_SENS_CONF_DATA_DEST_SHIFT          24
+#define CSI_SENS_CONF_DATA_DEST_MASK           0x07000000
+#define CSI_SENS_CONF_JPEG8_EN_SHIFT           27
+#define CSI_SENS_CONF_JPEG_EN_SHIFT            28
+#define CSI_SENS_CONF_FORCE_EOF_SHIFT          29
+#define CSI_SENS_CONF_DATA_EN_POL_SHIFT                31
+
+#define CSI_DATA_DEST_IC                       2
+#define CSI_DATA_DEST_IDMAC                    4
+
+#define CSI_CCIR_ERR_DET_EN                    0x01000000
+#define CSI_HORI_DOWNSIZE_EN                   0x80000000
+#define CSI_VERT_DOWNSIZE_EN                   0x40000000
+#define CSI_TEST_GEN_MODE_EN                   0x01000000
+
+#define CSI_HSC_MASK                           0x1fff0000
+#define CSI_HSC_SHIFT                          16
+#define CSI_VSC_MASK                           0x00000fff
+#define CSI_VSC_SHIFT                          0
+
+#define CSI_TEST_GEN_R_MASK                    0x000000ff
+#define CSI_TEST_GEN_R_SHIFT                   0
+#define CSI_TEST_GEN_G_MASK                    0x0000ff00
+#define CSI_TEST_GEN_G_SHIFT                   8
+#define CSI_TEST_GEN_B_MASK                    0x00ff0000
+#define CSI_TEST_GEN_B_SHIFT                   16
+
+#define CSI_MAX_RATIO_SKIP_SMFC_MASK           0x00000007
+#define CSI_MAX_RATIO_SKIP_SMFC_SHIFT          0
+#define CSI_SKIP_SMFC_MASK                     0x000000f8
+#define CSI_SKIP_SMFC_SHIFT                    3
+#define CSI_ID_2_SKIP_MASK                     0x00000300
+#define CSI_ID_2_SKIP_SHIFT                    8
+
+#define CSI_COLOR_FIRST_ROW_MASK               0x00000002
+#define CSI_COLOR_FIRST_COMP_MASK              0x00000001
+
+/* MIPI CSI-2 data types */
+#define MIPI_DT_YUV420         0x18 /* YYY.../UYVY.... */
+#define MIPI_DT_YUV420_LEGACY  0x1a /* UYY.../VYY...   */
+#define MIPI_DT_YUV422         0x1e /* UYVY...         */
+#define MIPI_DT_RGB444         0x20
+#define MIPI_DT_RGB555         0x21
+#define MIPI_DT_RGB565         0x22
+#define MIPI_DT_RGB666         0x23
+#define MIPI_DT_RGB888         0x24
+#define MIPI_DT_RAW6           0x28
+#define MIPI_DT_RAW7           0x29
+#define MIPI_DT_RAW8           0x2a
+#define MIPI_DT_RAW10          0x2b
+#define MIPI_DT_RAW12          0x2c
+#define MIPI_DT_RAW14          0x2d
+
+/*
+ * Bitfield of CSI bus signal polarities and modes.
+ */
+struct ipu_csi_bus_config {
+       unsigned data_width:4;
+       unsigned clk_mode:3;
+       unsigned ext_vsync:1;
+       unsigned vsync_pol:1;
+       unsigned hsync_pol:1;
+       unsigned pixclk_pol:1;
+       unsigned data_pol:1;
+       unsigned sens_clksrc:1;
+       unsigned pack_tight:1;
+       unsigned force_eof:1;
+       unsigned data_en_pol:1;
+
+       unsigned data_fmt;
+       unsigned mipi_dt;
+};
+
+/*
+ * Enumeration of CSI data bus widths.
+ */
+enum ipu_csi_data_width {
+       IPU_CSI_DATA_WIDTH_4   = 0,
+       IPU_CSI_DATA_WIDTH_8   = 1,
+       IPU_CSI_DATA_WIDTH_10  = 3,
+       IPU_CSI_DATA_WIDTH_12  = 5,
+       IPU_CSI_DATA_WIDTH_16  = 9,
+};
+
+/*
+ * Enumeration of CSI clock modes.
+ */
+enum ipu_csi_clk_mode {
+       IPU_CSI_CLK_MODE_GATED_CLK,
+       IPU_CSI_CLK_MODE_NONGATED_CLK,
+       IPU_CSI_CLK_MODE_CCIR656_PROGRESSIVE,
+       IPU_CSI_CLK_MODE_CCIR656_INTERLACED,
+       IPU_CSI_CLK_MODE_CCIR1120_PROGRESSIVE_DDR,
+       IPU_CSI_CLK_MODE_CCIR1120_PROGRESSIVE_SDR,
+       IPU_CSI_CLK_MODE_CCIR1120_INTERLACED_DDR,
+       IPU_CSI_CLK_MODE_CCIR1120_INTERLACED_SDR,
+};
+
+static inline u32 ipu_csi_read(struct ipu_csi *csi, unsigned offset)
+{
+       return readl(csi->base + offset);
+}
+
+static inline void ipu_csi_write(struct ipu_csi *csi, u32 value,
+                                unsigned offset)
+{
+       writel(value, csi->base + offset);
+}
+
+/*
+ * Set mclk division ratio for generating test mode mclk. Only used
+ * for test generator.
+ */
+static int ipu_csi_set_testgen_mclk(struct ipu_csi *csi, u32 pixel_clk,
+                                       u32 ipu_clk)
+{
+       u32 temp;
+       u32 div_ratio;
+
+       div_ratio = (ipu_clk / pixel_clk) - 1;
+
+       if (div_ratio > 0xFF || div_ratio < 0) {
+               dev_err(csi->ipu->dev,
+                       "value of pixel_clk extends normal range\n");
+               return -EINVAL;
+       }
+
+       temp = ipu_csi_read(csi, CSI_SENS_CONF);
+       temp &= ~CSI_SENS_CONF_DIVRATIO_MASK;
+       ipu_csi_write(csi, temp | (div_ratio << CSI_SENS_CONF_DIVRATIO_SHIFT),
+                         CSI_SENS_CONF);
+
+       return 0;
+}
+
+/*
+ * Find the CSI data format and data width for the given V4L2 media
+ * bus pixel format code.
+ */
+static int mbus_code_to_bus_cfg(struct ipu_csi_bus_config *cfg, u32 mbus_code)
+{
+       switch (mbus_code) {
+       case V4L2_MBUS_FMT_BGR565_2X8_BE:
+       case V4L2_MBUS_FMT_BGR565_2X8_LE:
+       case V4L2_MBUS_FMT_RGB565_2X8_BE:
+       case V4L2_MBUS_FMT_RGB565_2X8_LE:
+               cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_RGB565;
+               cfg->mipi_dt = MIPI_DT_RGB565;
+               cfg->data_width = IPU_CSI_DATA_WIDTH_8;
+               break;
+       case V4L2_MBUS_FMT_RGB444_2X8_PADHI_BE:
+       case V4L2_MBUS_FMT_RGB444_2X8_PADHI_LE:
+               cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_RGB444;
+               cfg->mipi_dt = MIPI_DT_RGB444;
+               cfg->data_width = IPU_CSI_DATA_WIDTH_8;
+               break;
+       case V4L2_MBUS_FMT_RGB555_2X8_PADHI_BE:
+       case V4L2_MBUS_FMT_RGB555_2X8_PADHI_LE:
+               cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_RGB555;
+               cfg->mipi_dt = MIPI_DT_RGB555;
+               cfg->data_width = IPU_CSI_DATA_WIDTH_8;
+               break;
+       case V4L2_MBUS_FMT_UYVY8_2X8:
+               cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_YUV422_UYVY;
+               cfg->mipi_dt = MIPI_DT_YUV422;
+               cfg->data_width = IPU_CSI_DATA_WIDTH_8;
+               break;
+       case V4L2_MBUS_FMT_YUYV8_2X8:
+               cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_YUV422_YUYV;
+               cfg->mipi_dt = MIPI_DT_YUV422;
+               cfg->data_width = IPU_CSI_DATA_WIDTH_8;
+               break;
+       case V4L2_MBUS_FMT_UYVY8_1X16:
+               cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_YUV422_UYVY;
+               cfg->mipi_dt = MIPI_DT_YUV422;
+               cfg->data_width = IPU_CSI_DATA_WIDTH_16;
+               break;
+       case V4L2_MBUS_FMT_YUYV8_1X16:
+               cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_YUV422_YUYV;
+               cfg->mipi_dt = MIPI_DT_YUV422;
+               cfg->data_width = IPU_CSI_DATA_WIDTH_16;
+               break;
+       case V4L2_MBUS_FMT_SBGGR8_1X8:
+       case V4L2_MBUS_FMT_SGBRG8_1X8:
+       case V4L2_MBUS_FMT_SGRBG8_1X8:
+       case V4L2_MBUS_FMT_SRGGB8_1X8:
+               cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_BAYER;
+               cfg->mipi_dt = MIPI_DT_RAW8;
+               cfg->data_width = IPU_CSI_DATA_WIDTH_8;
+               break;
+       case V4L2_MBUS_FMT_SBGGR10_DPCM8_1X8:
+       case V4L2_MBUS_FMT_SGBRG10_DPCM8_1X8:
+       case V4L2_MBUS_FMT_SGRBG10_DPCM8_1X8:
+       case V4L2_MBUS_FMT_SRGGB10_DPCM8_1X8:
+       case V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_BE:
+       case V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_LE:
+       case V4L2_MBUS_FMT_SBGGR10_2X8_PADLO_BE:
+       case V4L2_MBUS_FMT_SBGGR10_2X8_PADLO_LE:
+               cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_BAYER;
+               cfg->mipi_dt = MIPI_DT_RAW10;
+               cfg->data_width = IPU_CSI_DATA_WIDTH_8;
+               break;
+       case V4L2_MBUS_FMT_SBGGR10_1X10:
+       case V4L2_MBUS_FMT_SGBRG10_1X10:
+       case V4L2_MBUS_FMT_SGRBG10_1X10:
+       case V4L2_MBUS_FMT_SRGGB10_1X10:
+               cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_BAYER;
+               cfg->mipi_dt = MIPI_DT_RAW10;
+               cfg->data_width = IPU_CSI_DATA_WIDTH_10;
+               break;
+       case V4L2_MBUS_FMT_SBGGR12_1X12:
+       case V4L2_MBUS_FMT_SGBRG12_1X12:
+       case V4L2_MBUS_FMT_SGRBG12_1X12:
+       case V4L2_MBUS_FMT_SRGGB12_1X12:
+               cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_BAYER;
+               cfg->mipi_dt = MIPI_DT_RAW12;
+               cfg->data_width = IPU_CSI_DATA_WIDTH_12;
+               break;
+       case V4L2_MBUS_FMT_JPEG_1X8:
+               /* TODO */
+               cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_JPEG;
+               cfg->mipi_dt = MIPI_DT_RAW8;
+               cfg->data_width = IPU_CSI_DATA_WIDTH_8;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+/*
+ * Fill a CSI bus config struct from mbus_config and mbus_framefmt.
+ */
+static void fill_csi_bus_cfg(struct ipu_csi_bus_config *csicfg,
+                                struct v4l2_mbus_config *mbus_cfg,
+                                struct v4l2_mbus_framefmt *mbus_fmt)
+{
+       memset(csicfg, 0, sizeof(*csicfg));
+
+       mbus_code_to_bus_cfg(csicfg, mbus_fmt->code);
+
+       switch (mbus_cfg->type) {
+       case V4L2_MBUS_PARALLEL:
+               csicfg->ext_vsync = 1;
+               csicfg->vsync_pol = (mbus_cfg->flags &
+                                    V4L2_MBUS_VSYNC_ACTIVE_LOW) ? 1 : 0;
+               csicfg->hsync_pol = (mbus_cfg->flags &
+                                    V4L2_MBUS_HSYNC_ACTIVE_LOW) ? 1 : 0;
+               csicfg->pixclk_pol = (mbus_cfg->flags &
+                                     V4L2_MBUS_PCLK_SAMPLE_FALLING) ? 1 : 0;
+               csicfg->clk_mode = IPU_CSI_CLK_MODE_GATED_CLK;
+               break;
+       case V4L2_MBUS_BT656:
+               csicfg->ext_vsync = 0;
+               if (V4L2_FIELD_HAS_BOTH(mbus_fmt->field))
+                       csicfg->clk_mode = IPU_CSI_CLK_MODE_CCIR656_INTERLACED;
+               else
+                       csicfg->clk_mode = IPU_CSI_CLK_MODE_CCIR656_PROGRESSIVE;
+               break;
+       case V4L2_MBUS_CSI2:
+               /*
+                * MIPI CSI-2 requires non gated clock mode, all other
+                * parameters are not applicable for MIPI CSI-2 bus.
+                */
+               csicfg->clk_mode = IPU_CSI_CLK_MODE_NONGATED_CLK;
+               break;
+       default:
+               /* will never get here, keep compiler quiet */
+               break;
+       }
+}
+
+int ipu_csi_init_interface(struct ipu_csi *csi,
+                          struct v4l2_mbus_config *mbus_cfg,
+                          struct v4l2_mbus_framefmt *mbus_fmt)
+{
+       struct ipu_csi_bus_config cfg;
+       unsigned long flags;
+       u32 data = 0;
+
+       fill_csi_bus_cfg(&cfg, mbus_cfg, mbus_fmt);
+
+       /* Set the CSI_SENS_CONF register remaining fields */
+       data |= cfg.data_width << CSI_SENS_CONF_DATA_WIDTH_SHIFT |
+               cfg.data_fmt << CSI_SENS_CONF_DATA_FMT_SHIFT |
+               cfg.data_pol << CSI_SENS_CONF_DATA_POL_SHIFT |
+               cfg.vsync_pol << CSI_SENS_CONF_VSYNC_POL_SHIFT |
+               cfg.hsync_pol << CSI_SENS_CONF_HSYNC_POL_SHIFT |
+               cfg.pixclk_pol << CSI_SENS_CONF_PIX_CLK_POL_SHIFT |
+               cfg.ext_vsync << CSI_SENS_CONF_EXT_VSYNC_SHIFT |
+               cfg.clk_mode << CSI_SENS_CONF_SENS_PRTCL_SHIFT |
+               cfg.pack_tight << CSI_SENS_CONF_PACK_TIGHT_SHIFT |
+               cfg.force_eof << CSI_SENS_CONF_FORCE_EOF_SHIFT |
+               cfg.data_en_pol << CSI_SENS_CONF_DATA_EN_POL_SHIFT;
+
+       spin_lock_irqsave(&csi->lock, flags);
+
+       ipu_csi_write(csi, data, CSI_SENS_CONF);
+
+       /* Setup sensor frame size */
+       ipu_csi_write(csi,
+                     (mbus_fmt->width - 1) | ((mbus_fmt->height - 1) << 16),
+                     CSI_SENS_FRM_SIZE);
+
+       /* Set CCIR registers */
+
+       switch (cfg.clk_mode) {
+       case IPU_CSI_CLK_MODE_CCIR656_PROGRESSIVE:
+               ipu_csi_write(csi, 0x40030, CSI_CCIR_CODE_1);
+               ipu_csi_write(csi, 0xFF0000, CSI_CCIR_CODE_3);
+               break;
+       case IPU_CSI_CLK_MODE_CCIR656_INTERLACED:
+               if (mbus_fmt->width == 720 && mbus_fmt->height == 576) {
+                       /*
+                        * PAL case
+                        *
+                        * Field0BlankEnd = 0x6, Field0BlankStart = 0x2,
+                        * Field0ActiveEnd = 0x4, Field0ActiveStart = 0
+                        * Field1BlankEnd = 0x7, Field1BlankStart = 0x3,
+                        * Field1ActiveEnd = 0x5, Field1ActiveStart = 0x1
+                        */
+                       ipu_csi_write(csi, 0x40596 | CSI_CCIR_ERR_DET_EN,
+                                         CSI_CCIR_CODE_1);
+                       ipu_csi_write(csi, 0xD07DF, CSI_CCIR_CODE_2);
+                       ipu_csi_write(csi, 0xFF0000, CSI_CCIR_CODE_3);
+
+               } else if (mbus_fmt->width == 720 && mbus_fmt->height == 480) {
+                       /*
+                        * NTSC case
+                        *
+                        * Field0BlankEnd = 0x7, Field0BlankStart = 0x3,
+                        * Field0ActiveEnd = 0x5, Field0ActiveStart = 0x1
+                        * Field1BlankEnd = 0x6, Field1BlankStart = 0x2,
+                        * Field1ActiveEnd = 0x4, Field1ActiveStart = 0
+                        */
+                       ipu_csi_write(csi, 0xD07DF | CSI_CCIR_ERR_DET_EN,
+                                         CSI_CCIR_CODE_1);
+                       ipu_csi_write(csi, 0x40596, CSI_CCIR_CODE_2);
+                       ipu_csi_write(csi, 0xFF0000, CSI_CCIR_CODE_3);
+               } else {
+                       dev_err(csi->ipu->dev,
+                               "Unsupported CCIR656 interlaced video mode\n");
+                       spin_unlock_irqrestore(&csi->lock, flags);
+                       return -EINVAL;
+               }
+               break;
+       case IPU_CSI_CLK_MODE_CCIR1120_PROGRESSIVE_DDR:
+       case IPU_CSI_CLK_MODE_CCIR1120_PROGRESSIVE_SDR:
+       case IPU_CSI_CLK_MODE_CCIR1120_INTERLACED_DDR:
+       case IPU_CSI_CLK_MODE_CCIR1120_INTERLACED_SDR:
+               ipu_csi_write(csi, 0x40030 | CSI_CCIR_ERR_DET_EN,
+                                  CSI_CCIR_CODE_1);
+               ipu_csi_write(csi, 0xFF0000, CSI_CCIR_CODE_3);
+               break;
+       case IPU_CSI_CLK_MODE_GATED_CLK:
+       case IPU_CSI_CLK_MODE_NONGATED_CLK:
+               ipu_csi_write(csi, 0, CSI_CCIR_CODE_1);
+               break;
+       }
+
+       dev_dbg(csi->ipu->dev, "CSI_SENS_CONF = 0x%08X\n",
+               ipu_csi_read(csi, CSI_SENS_CONF));
+       dev_dbg(csi->ipu->dev, "CSI_ACT_FRM_SIZE = 0x%08X\n",
+               ipu_csi_read(csi, CSI_ACT_FRM_SIZE));
+
+       spin_unlock_irqrestore(&csi->lock, flags);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(ipu_csi_init_interface);
+
+bool ipu_csi_is_interlaced(struct ipu_csi *csi)
+{
+       unsigned long flags;
+       u32 sensor_protocol;
+
+       spin_lock_irqsave(&csi->lock, flags);
+       sensor_protocol =
+               (ipu_csi_read(csi, CSI_SENS_CONF) &
+                CSI_SENS_CONF_SENS_PRTCL_MASK) >>
+               CSI_SENS_CONF_SENS_PRTCL_SHIFT;
+       spin_unlock_irqrestore(&csi->lock, flags);
+
+       switch (sensor_protocol) {
+       case IPU_CSI_CLK_MODE_GATED_CLK:
+       case IPU_CSI_CLK_MODE_NONGATED_CLK:
+       case IPU_CSI_CLK_MODE_CCIR656_PROGRESSIVE:
+       case IPU_CSI_CLK_MODE_CCIR1120_PROGRESSIVE_DDR:
+       case IPU_CSI_CLK_MODE_CCIR1120_PROGRESSIVE_SDR:
+               return false;
+       case IPU_CSI_CLK_MODE_CCIR656_INTERLACED:
+       case IPU_CSI_CLK_MODE_CCIR1120_INTERLACED_DDR:
+       case IPU_CSI_CLK_MODE_CCIR1120_INTERLACED_SDR:
+               return true;
+       default:
+               dev_err(csi->ipu->dev,
+                       "CSI %d sensor protocol unsupported\n", csi->id);
+               return false;
+       }
+}
+EXPORT_SYMBOL_GPL(ipu_csi_is_interlaced);
+
+void ipu_csi_get_window(struct ipu_csi *csi, struct v4l2_rect *w)
+{
+       unsigned long flags;
+       u32 reg;
+
+       spin_lock_irqsave(&csi->lock, flags);
+
+       reg = ipu_csi_read(csi, CSI_ACT_FRM_SIZE);
+       w->width = (reg & 0xFFFF) + 1;
+       w->height = (reg >> 16 & 0xFFFF) + 1;
+
+       reg = ipu_csi_read(csi, CSI_OUT_FRM_CTRL);
+       w->left = (reg & CSI_HSC_MASK) >> CSI_HSC_SHIFT;
+       w->top = (reg & CSI_VSC_MASK) >> CSI_VSC_SHIFT;
+
+       spin_unlock_irqrestore(&csi->lock, flags);
+}
+EXPORT_SYMBOL_GPL(ipu_csi_get_window);
+
+void ipu_csi_set_window(struct ipu_csi *csi, struct v4l2_rect *w)
+{
+       unsigned long flags;
+       u32 reg;
+
+       spin_lock_irqsave(&csi->lock, flags);
+
+       ipu_csi_write(csi, (w->width - 1) | ((w->height - 1) << 16),
+                         CSI_ACT_FRM_SIZE);
+
+       reg = ipu_csi_read(csi, CSI_OUT_FRM_CTRL);
+       reg &= ~(CSI_HSC_MASK | CSI_VSC_MASK);
+       reg |= ((w->top << CSI_VSC_SHIFT) | (w->left << CSI_HSC_SHIFT));
+       ipu_csi_write(csi, reg, CSI_OUT_FRM_CTRL);
+
+       spin_unlock_irqrestore(&csi->lock, flags);
+}
+EXPORT_SYMBOL_GPL(ipu_csi_set_window);
+
+void ipu_csi_set_test_generator(struct ipu_csi *csi, bool active,
+                               u32 r_value, u32 g_value, u32 b_value,
+                               u32 pix_clk)
+{
+       unsigned long flags;
+       u32 ipu_clk = clk_get_rate(csi->clk_ipu);
+       u32 temp;
+
+       spin_lock_irqsave(&csi->lock, flags);
+
+       temp = ipu_csi_read(csi, CSI_TST_CTRL);
+
+       if (active == false) {
+               temp &= ~CSI_TEST_GEN_MODE_EN;
+               ipu_csi_write(csi, temp, CSI_TST_CTRL);
+       } else {
+               /* Set sensb_mclk div_ratio */
+               ipu_csi_set_testgen_mclk(csi, pix_clk, ipu_clk);
+
+               temp &= ~(CSI_TEST_GEN_R_MASK | CSI_TEST_GEN_G_MASK |
+                         CSI_TEST_GEN_B_MASK);
+               temp |= CSI_TEST_GEN_MODE_EN;
+               temp |= (r_value << CSI_TEST_GEN_R_SHIFT) |
+                       (g_value << CSI_TEST_GEN_G_SHIFT) |
+                       (b_value << CSI_TEST_GEN_B_SHIFT);
+               ipu_csi_write(csi, temp, CSI_TST_CTRL);
+       }
+
+       spin_unlock_irqrestore(&csi->lock, flags);
+}
+EXPORT_SYMBOL_GPL(ipu_csi_set_test_generator);
+
+int ipu_csi_set_mipi_datatype(struct ipu_csi *csi, u32 vc,
+                             struct v4l2_mbus_framefmt *mbus_fmt)
+{
+       struct ipu_csi_bus_config cfg;
+       unsigned long flags;
+       u32 temp;
+
+       if (vc > 3)
+               return -EINVAL;
+
+       mbus_code_to_bus_cfg(&cfg, mbus_fmt->code);
+
+       spin_lock_irqsave(&csi->lock, flags);
+
+       temp = ipu_csi_read(csi, CSI_MIPI_DI);
+       temp &= ~(0xff << (vc * 8));
+       temp |= (cfg.mipi_dt << (vc * 8));
+       ipu_csi_write(csi, temp, CSI_MIPI_DI);
+
+       spin_unlock_irqrestore(&csi->lock, flags);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(ipu_csi_set_mipi_datatype);
+
+int ipu_csi_set_skip_smfc(struct ipu_csi *csi, u32 skip,
+                         u32 max_ratio, u32 id)
+{
+       unsigned long flags;
+       u32 temp;
+
+       if (max_ratio > 5 || id > 3)
+               return -EINVAL;
+
+       spin_lock_irqsave(&csi->lock, flags);
+
+       temp = ipu_csi_read(csi, CSI_SKIP);
+       temp &= ~(CSI_MAX_RATIO_SKIP_SMFC_MASK | CSI_ID_2_SKIP_MASK |
+                 CSI_SKIP_SMFC_MASK);
+       temp |= (max_ratio << CSI_MAX_RATIO_SKIP_SMFC_SHIFT) |
+               (id << CSI_ID_2_SKIP_SHIFT) |
+               (skip << CSI_SKIP_SMFC_SHIFT);
+       ipu_csi_write(csi, temp, CSI_SKIP);
+
+       spin_unlock_irqrestore(&csi->lock, flags);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(ipu_csi_set_skip_smfc);
+
+int ipu_csi_set_dest(struct ipu_csi *csi, enum ipu_csi_dest csi_dest)
+{
+       unsigned long flags;
+       u32 csi_sens_conf, dest;
+
+       if (csi_dest == IPU_CSI_DEST_IDMAC)
+               dest = CSI_DATA_DEST_IDMAC;
+       else
+               dest = CSI_DATA_DEST_IC; /* IC or VDIC */
+
+       spin_lock_irqsave(&csi->lock, flags);
+
+       csi_sens_conf = ipu_csi_read(csi, CSI_SENS_CONF);
+       csi_sens_conf &= ~CSI_SENS_CONF_DATA_DEST_MASK;
+       csi_sens_conf |= (dest << CSI_SENS_CONF_DATA_DEST_SHIFT);
+       ipu_csi_write(csi, csi_sens_conf, CSI_SENS_CONF);
+
+       spin_unlock_irqrestore(&csi->lock, flags);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(ipu_csi_set_dest);
+
+int ipu_csi_enable(struct ipu_csi *csi)
+{
+       ipu_module_enable(csi->ipu, csi->module);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(ipu_csi_enable);
+
+int ipu_csi_disable(struct ipu_csi *csi)
+{
+       ipu_module_disable(csi->ipu, csi->module);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(ipu_csi_disable);
+
+struct ipu_csi *ipu_csi_get(struct ipu_soc *ipu, int id)
+{
+       unsigned long flags;
+       struct ipu_csi *csi, *ret;
+
+       if (id > 1)
+               return ERR_PTR(-EINVAL);
+
+       csi = ipu->csi_priv[id];
+       ret = csi;
+
+       spin_lock_irqsave(&csi->lock, flags);
+
+       if (csi->inuse) {
+               ret = ERR_PTR(-EBUSY);
+               goto unlock;
+       }
+
+       csi->inuse = true;
+unlock:
+       spin_unlock_irqrestore(&csi->lock, flags);
+       return ret;
+}
+EXPORT_SYMBOL_GPL(ipu_csi_get);
+
+void ipu_csi_put(struct ipu_csi *csi)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&csi->lock, flags);
+       csi->inuse = false;
+       spin_unlock_irqrestore(&csi->lock, flags);
+}
+EXPORT_SYMBOL_GPL(ipu_csi_put);
+
+int ipu_csi_init(struct ipu_soc *ipu, struct device *dev, int id,
+                unsigned long base, u32 module, struct clk *clk_ipu)
+{
+       struct ipu_csi *csi;
+
+       if (id > 1)
+               return -ENODEV;
+
+       csi = devm_kzalloc(dev, sizeof(*csi), GFP_KERNEL);
+       if (!csi)
+               return -ENOMEM;
+
+       ipu->csi_priv[id] = csi;
+
+       spin_lock_init(&csi->lock);
+       csi->module = module;
+       csi->id = id;
+       csi->clk_ipu = clk_ipu;
+       csi->base = devm_ioremap(dev, base, PAGE_SIZE);
+       if (!csi->base)
+               return -ENOMEM;
+
+       dev_dbg(dev, "CSI%d base: 0x%08lx remapped to %p\n",
+               id, base, csi->base);
+       csi->ipu = ipu;
+
+       return 0;
+}
+
+void ipu_csi_exit(struct ipu_soc *ipu, int id)
+{
+}
+
+void ipu_csi_dump(struct ipu_csi *csi)
+{
+       dev_dbg(csi->ipu->dev, "CSI_SENS_CONF:     %08x\n",
+               ipu_csi_read(csi, CSI_SENS_CONF));
+       dev_dbg(csi->ipu->dev, "CSI_SENS_FRM_SIZE: %08x\n",
+               ipu_csi_read(csi, CSI_SENS_FRM_SIZE));
+       dev_dbg(csi->ipu->dev, "CSI_ACT_FRM_SIZE:  %08x\n",
+               ipu_csi_read(csi, CSI_ACT_FRM_SIZE));
+       dev_dbg(csi->ipu->dev, "CSI_OUT_FRM_CTRL:  %08x\n",
+               ipu_csi_read(csi, CSI_OUT_FRM_CTRL));
+       dev_dbg(csi->ipu->dev, "CSI_TST_CTRL:      %08x\n",
+               ipu_csi_read(csi, CSI_TST_CTRL));
+       dev_dbg(csi->ipu->dev, "CSI_CCIR_CODE_1:   %08x\n",
+               ipu_csi_read(csi, CSI_CCIR_CODE_1));
+       dev_dbg(csi->ipu->dev, "CSI_CCIR_CODE_2:   %08x\n",
+               ipu_csi_read(csi, CSI_CCIR_CODE_2));
+       dev_dbg(csi->ipu->dev, "CSI_CCIR_CODE_3:   %08x\n",
+               ipu_csi_read(csi, CSI_CCIR_CODE_3));
+       dev_dbg(csi->ipu->dev, "CSI_MIPI_DI:       %08x\n",
+               ipu_csi_read(csi, CSI_MIPI_DI));
+       dev_dbg(csi->ipu->dev, "CSI_SKIP:          %08x\n",
+               ipu_csi_read(csi, CSI_SKIP));
+}
+EXPORT_SYMBOL_GPL(ipu_csi_dump);
diff --git a/drivers/gpu/ipu-v3/ipu-ic.c b/drivers/gpu/ipu-v3/ipu-ic.c
new file mode 100644 (file)
index 0000000..ad75588
--- /dev/null
@@ -0,0 +1,778 @@
+/*
+ * Copyright (C) 2012-2014 Mentor Graphics Inc.
+ * Copyright 2005-2012 Freescale Semiconductor, Inc. All Rights Reserved.
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/spinlock.h>
+#include <linux/bitrev.h>
+#include <linux/io.h>
+#include <linux/err.h>
+#include "ipu-prv.h"
+
+/* IC Register Offsets */
+#define IC_CONF                 0x0000
+#define IC_PRP_ENC_RSC          0x0004
+#define IC_PRP_VF_RSC           0x0008
+#define IC_PP_RSC               0x000C
+#define IC_CMBP_1               0x0010
+#define IC_CMBP_2               0x0014
+#define IC_IDMAC_1              0x0018
+#define IC_IDMAC_2              0x001C
+#define IC_IDMAC_3              0x0020
+#define IC_IDMAC_4              0x0024
+
+/* IC Register Fields */
+#define IC_CONF_PRPENC_EN       (1 << 0)
+#define IC_CONF_PRPENC_CSC1     (1 << 1)
+#define IC_CONF_PRPENC_ROT_EN   (1 << 2)
+#define IC_CONF_PRPVF_EN        (1 << 8)
+#define IC_CONF_PRPVF_CSC1      (1 << 9)
+#define IC_CONF_PRPVF_CSC2      (1 << 10)
+#define IC_CONF_PRPVF_CMB       (1 << 11)
+#define IC_CONF_PRPVF_ROT_EN    (1 << 12)
+#define IC_CONF_PP_EN           (1 << 16)
+#define IC_CONF_PP_CSC1         (1 << 17)
+#define IC_CONF_PP_CSC2         (1 << 18)
+#define IC_CONF_PP_CMB          (1 << 19)
+#define IC_CONF_PP_ROT_EN       (1 << 20)
+#define IC_CONF_IC_GLB_LOC_A    (1 << 28)
+#define IC_CONF_KEY_COLOR_EN    (1 << 29)
+#define IC_CONF_RWS_EN          (1 << 30)
+#define IC_CONF_CSI_MEM_WR_EN   (1 << 31)
+
+#define IC_IDMAC_1_CB0_BURST_16         (1 << 0)
+#define IC_IDMAC_1_CB1_BURST_16         (1 << 1)
+#define IC_IDMAC_1_CB2_BURST_16         (1 << 2)
+#define IC_IDMAC_1_CB3_BURST_16         (1 << 3)
+#define IC_IDMAC_1_CB4_BURST_16         (1 << 4)
+#define IC_IDMAC_1_CB5_BURST_16         (1 << 5)
+#define IC_IDMAC_1_CB6_BURST_16         (1 << 6)
+#define IC_IDMAC_1_CB7_BURST_16         (1 << 7)
+#define IC_IDMAC_1_PRPENC_ROT_MASK      (0x7 << 11)
+#define IC_IDMAC_1_PRPENC_ROT_OFFSET    11
+#define IC_IDMAC_1_PRPVF_ROT_MASK       (0x7 << 14)
+#define IC_IDMAC_1_PRPVF_ROT_OFFSET     14
+#define IC_IDMAC_1_PP_ROT_MASK          (0x7 << 17)
+#define IC_IDMAC_1_PP_ROT_OFFSET        17
+#define IC_IDMAC_1_PP_FLIP_RS           (1 << 22)
+#define IC_IDMAC_1_PRPVF_FLIP_RS        (1 << 21)
+#define IC_IDMAC_1_PRPENC_FLIP_RS       (1 << 20)
+
+#define IC_IDMAC_2_PRPENC_HEIGHT_MASK   (0x3ff << 0)
+#define IC_IDMAC_2_PRPENC_HEIGHT_OFFSET 0
+#define IC_IDMAC_2_PRPVF_HEIGHT_MASK    (0x3ff << 10)
+#define IC_IDMAC_2_PRPVF_HEIGHT_OFFSET  10
+#define IC_IDMAC_2_PP_HEIGHT_MASK       (0x3ff << 20)
+#define IC_IDMAC_2_PP_HEIGHT_OFFSET     20
+
+#define IC_IDMAC_3_PRPENC_WIDTH_MASK    (0x3ff << 0)
+#define IC_IDMAC_3_PRPENC_WIDTH_OFFSET  0
+#define IC_IDMAC_3_PRPVF_WIDTH_MASK     (0x3ff << 10)
+#define IC_IDMAC_3_PRPVF_WIDTH_OFFSET   10
+#define IC_IDMAC_3_PP_WIDTH_MASK        (0x3ff << 20)
+#define IC_IDMAC_3_PP_WIDTH_OFFSET      20
+
+struct ic_task_regoffs {
+       u32 rsc;
+       u32 tpmem_csc[2];
+};
+
+struct ic_task_bitfields {
+       u32 ic_conf_en;
+       u32 ic_conf_rot_en;
+       u32 ic_conf_cmb_en;
+       u32 ic_conf_csc1_en;
+       u32 ic_conf_csc2_en;
+       u32 ic_cmb_galpha_bit;
+};
+
+static const struct ic_task_regoffs ic_task_reg[IC_NUM_TASKS] = {
+       [IC_TASK_ENCODER] = {
+               .rsc = IC_PRP_ENC_RSC,
+               .tpmem_csc = {0x2008, 0},
+       },
+       [IC_TASK_VIEWFINDER] = {
+               .rsc = IC_PRP_VF_RSC,
+               .tpmem_csc = {0x4028, 0x4040},
+       },
+       [IC_TASK_POST_PROCESSOR] = {
+               .rsc = IC_PP_RSC,
+               .tpmem_csc = {0x6060, 0x6078},
+       },
+};
+
+static const struct ic_task_bitfields ic_task_bit[IC_NUM_TASKS] = {
+       [IC_TASK_ENCODER] = {
+               .ic_conf_en = IC_CONF_PRPENC_EN,
+               .ic_conf_rot_en = IC_CONF_PRPENC_ROT_EN,
+               .ic_conf_cmb_en = 0,    /* NA */
+               .ic_conf_csc1_en = IC_CONF_PRPENC_CSC1,
+               .ic_conf_csc2_en = 0,   /* NA */
+               .ic_cmb_galpha_bit = 0, /* NA */
+       },
+       [IC_TASK_VIEWFINDER] = {
+               .ic_conf_en = IC_CONF_PRPVF_EN,
+               .ic_conf_rot_en = IC_CONF_PRPVF_ROT_EN,
+               .ic_conf_cmb_en = IC_CONF_PRPVF_CMB,
+               .ic_conf_csc1_en = IC_CONF_PRPVF_CSC1,
+               .ic_conf_csc2_en = IC_CONF_PRPVF_CSC2,
+               .ic_cmb_galpha_bit = 0,
+       },
+       [IC_TASK_POST_PROCESSOR] = {
+               .ic_conf_en = IC_CONF_PP_EN,
+               .ic_conf_rot_en = IC_CONF_PP_ROT_EN,
+               .ic_conf_cmb_en = IC_CONF_PP_CMB,
+               .ic_conf_csc1_en = IC_CONF_PP_CSC1,
+               .ic_conf_csc2_en = IC_CONF_PP_CSC2,
+               .ic_cmb_galpha_bit = 8,
+       },
+};
+
+struct ipu_ic_priv;
+
+struct ipu_ic {
+       enum ipu_ic_task task;
+       const struct ic_task_regoffs *reg;
+       const struct ic_task_bitfields *bit;
+
+       enum ipu_color_space in_cs, g_in_cs;
+       enum ipu_color_space out_cs;
+       bool graphics;
+       bool rotation;
+       bool in_use;
+
+       struct ipu_ic_priv *priv;
+};
+
+struct ipu_ic_priv {
+       void __iomem *base;
+       void __iomem *tpmem_base;
+       spinlock_t lock;
+       struct ipu_soc *ipu;
+       int use_count;
+       struct ipu_ic task[IC_NUM_TASKS];
+};
+
+static inline u32 ipu_ic_read(struct ipu_ic *ic, unsigned offset)
+{
+       return readl(ic->priv->base + offset);
+}
+
+static inline void ipu_ic_write(struct ipu_ic *ic, u32 value, unsigned offset)
+{
+       writel(value, ic->priv->base + offset);
+}
+
+struct ic_csc_params {
+       s16 coeff[3][3];        /* signed 9-bit integer coefficients */
+       s16 offset[3];          /* signed 11+2-bit fixed point offset */
+       u8 scale:2;             /* scale coefficients * 2^(scale-1) */
+       bool sat:1;             /* saturate to (16, 235(Y) / 240(U, V)) */
+};
+
+/*
+ * Y = R *  .299 + G *  .587 + B *  .114;
+ * U = R * -.169 + G * -.332 + B *  .500 + 128.;
+ * V = R *  .500 + G * -.419 + B * -.0813 + 128.;
+ */
+static const struct ic_csc_params ic_csc_rgb2ycbcr = {
+       .coeff = {
+               { 77, 150, 29 },
+               { 469, 427, 128 },
+               { 128, 405, 491 },
+       },
+       .offset = { 0, 512, 512 },
+       .scale = 1,
+};
+
+/* transparent RGB->RGB matrix for graphics combining */
+static const struct ic_csc_params ic_csc_rgb2rgb = {
+       .coeff = {
+               { 128, 0, 0 },
+               { 0, 128, 0 },
+               { 0, 0, 128 },
+       },
+       .scale = 2,
+};
+
+/*
+ * R = (1.164 * (Y - 16)) + (1.596 * (Cr - 128));
+ * G = (1.164 * (Y - 16)) - (0.392 * (Cb - 128)) - (0.813 * (Cr - 128));
+ * B = (1.164 * (Y - 16)) + (2.017 * (Cb - 128);
+ */
+static const struct ic_csc_params ic_csc_ycbcr2rgb = {
+       .coeff = {
+               { 149, 0, 204 },
+               { 149, 462, 408 },
+               { 149, 255, 0 },
+       },
+       .offset = { -446, 266, -554 },
+       .scale = 2,
+};
+
+static int init_csc(struct ipu_ic *ic,
+                   enum ipu_color_space inf,
+                   enum ipu_color_space outf,
+                   int csc_index)
+{
+       struct ipu_ic_priv *priv = ic->priv;
+       const struct ic_csc_params *params;
+       u32 __iomem *base;
+       const u16 (*c)[3];
+       const u16 *a;
+       u32 param;
+
+       base = (u32 __iomem *)
+               (priv->tpmem_base + ic->reg->tpmem_csc[csc_index]);
+
+       if (inf == IPUV3_COLORSPACE_YUV && outf == IPUV3_COLORSPACE_RGB)
+               params = &ic_csc_ycbcr2rgb;
+       else if (inf == IPUV3_COLORSPACE_RGB && outf == IPUV3_COLORSPACE_YUV)
+               params = &ic_csc_rgb2ycbcr;
+       else if (inf == IPUV3_COLORSPACE_RGB && outf == IPUV3_COLORSPACE_RGB)
+               params = &ic_csc_rgb2rgb;
+       else {
+               dev_err(priv->ipu->dev, "Unsupported color space conversion\n");
+               return -EINVAL;
+       }
+
+       /* Cast to unsigned */
+       c = (const u16 (*)[3])params->coeff;
+       a = (const u16 *)params->offset;
+
+       param = ((a[0] & 0x1f) << 27) | ((c[0][0] & 0x1ff) << 18) |
+               ((c[1][1] & 0x1ff) << 9) | (c[2][2] & 0x1ff);
+       writel(param, base++);
+
+       param = ((a[0] & 0x1fe0) >> 5) | (params->scale << 8) |
+               (params->sat << 9);
+       writel(param, base++);
+
+       param = ((a[1] & 0x1f) << 27) | ((c[0][1] & 0x1ff) << 18) |
+               ((c[1][0] & 0x1ff) << 9) | (c[2][0] & 0x1ff);
+       writel(param, base++);
+
+       param = ((a[1] & 0x1fe0) >> 5);
+       writel(param, base++);
+
+       param = ((a[2] & 0x1f) << 27) | ((c[0][2] & 0x1ff) << 18) |
+               ((c[1][2] & 0x1ff) << 9) | (c[2][1] & 0x1ff);
+       writel(param, base++);
+
+       param = ((a[2] & 0x1fe0) >> 5);
+       writel(param, base++);
+
+       return 0;
+}
+
+static int calc_resize_coeffs(struct ipu_ic *ic,
+                             u32 in_size, u32 out_size,
+                             u32 *resize_coeff,
+                             u32 *downsize_coeff)
+{
+       struct ipu_ic_priv *priv = ic->priv;
+       struct ipu_soc *ipu = priv->ipu;
+       u32 temp_size, temp_downsize;
+
+       /*
+        * Input size cannot be more than 4096, and output size cannot
+        * be more than 1024
+        */
+       if (in_size > 4096) {
+               dev_err(ipu->dev, "Unsupported resize (in_size > 4096)\n");
+               return -EINVAL;
+       }
+       if (out_size > 1024) {
+               dev_err(ipu->dev, "Unsupported resize (out_size > 1024)\n");
+               return -EINVAL;
+       }
+
+       /* Cannot downsize more than 8:1 */
+       if ((out_size << 3) < in_size) {
+               dev_err(ipu->dev, "Unsupported downsize\n");
+               return -EINVAL;
+       }
+
+       /* Compute downsizing coefficient */
+       temp_downsize = 0;
+       temp_size = in_size;
+       while (((temp_size > 1024) || (temp_size >= out_size * 2)) &&
+              (temp_downsize < 2)) {
+               temp_size >>= 1;
+               temp_downsize++;
+       }
+       *downsize_coeff = temp_downsize;
+
+       /*
+        * compute resizing coefficient using the following equation:
+        * resize_coeff = M * (SI - 1) / (SO - 1)
+        * where M = 2^13, SI = input size, SO = output size
+        */
+       *resize_coeff = (8192L * (temp_size - 1)) / (out_size - 1);
+       if (*resize_coeff >= 16384L) {
+               dev_err(ipu->dev, "Warning! Overflow on resize coeff.\n");
+               *resize_coeff = 0x3FFF;
+       }
+
+       return 0;
+}
+
+void ipu_ic_task_enable(struct ipu_ic *ic)
+{
+       struct ipu_ic_priv *priv = ic->priv;
+       unsigned long flags;
+       u32 ic_conf;
+
+       spin_lock_irqsave(&priv->lock, flags);
+
+       ic_conf = ipu_ic_read(ic, IC_CONF);
+
+       ic_conf |= ic->bit->ic_conf_en;
+
+       if (ic->rotation)
+               ic_conf |= ic->bit->ic_conf_rot_en;
+
+       if (ic->in_cs != ic->out_cs)
+               ic_conf |= ic->bit->ic_conf_csc1_en;
+
+       if (ic->graphics) {
+               ic_conf |= ic->bit->ic_conf_cmb_en;
+               ic_conf |= ic->bit->ic_conf_csc1_en;
+
+               if (ic->g_in_cs != ic->out_cs)
+                       ic_conf |= ic->bit->ic_conf_csc2_en;
+       }
+
+       ipu_ic_write(ic, ic_conf, IC_CONF);
+
+       spin_unlock_irqrestore(&priv->lock, flags);
+}
+EXPORT_SYMBOL_GPL(ipu_ic_task_enable);
+
+void ipu_ic_task_disable(struct ipu_ic *ic)
+{
+       struct ipu_ic_priv *priv = ic->priv;
+       unsigned long flags;
+       u32 ic_conf;
+
+       spin_lock_irqsave(&priv->lock, flags);
+
+       ic_conf = ipu_ic_read(ic, IC_CONF);
+
+       ic_conf &= ~(ic->bit->ic_conf_en |
+                    ic->bit->ic_conf_csc1_en |
+                    ic->bit->ic_conf_rot_en);
+       if (ic->bit->ic_conf_csc2_en)
+               ic_conf &= ~ic->bit->ic_conf_csc2_en;
+       if (ic->bit->ic_conf_cmb_en)
+               ic_conf &= ~ic->bit->ic_conf_cmb_en;
+
+       ipu_ic_write(ic, ic_conf, IC_CONF);
+
+       ic->rotation = ic->graphics = false;
+
+       spin_unlock_irqrestore(&priv->lock, flags);
+}
+EXPORT_SYMBOL_GPL(ipu_ic_task_disable);
+
+int ipu_ic_task_graphics_init(struct ipu_ic *ic,
+                             enum ipu_color_space in_g_cs,
+                             bool galpha_en, u32 galpha,
+                             bool colorkey_en, u32 colorkey)
+{
+       struct ipu_ic_priv *priv = ic->priv;
+       unsigned long flags;
+       u32 reg, ic_conf;
+       int ret = 0;
+
+       if (ic->task == IC_TASK_ENCODER)
+               return -EINVAL;
+
+       spin_lock_irqsave(&priv->lock, flags);
+
+       ic_conf = ipu_ic_read(ic, IC_CONF);
+
+       if (!(ic_conf & ic->bit->ic_conf_csc1_en)) {
+               /* need transparent CSC1 conversion */
+               ret = init_csc(ic, IPUV3_COLORSPACE_RGB,
+                              IPUV3_COLORSPACE_RGB, 0);
+               if (ret)
+                       goto unlock;
+       }
+
+       ic->g_in_cs = in_g_cs;
+
+       if (ic->g_in_cs != ic->out_cs) {
+               ret = init_csc(ic, ic->g_in_cs, ic->out_cs, 1);
+               if (ret)
+                       goto unlock;
+       }
+
+       if (galpha_en) {
+               ic_conf |= IC_CONF_IC_GLB_LOC_A;
+               reg = ipu_ic_read(ic, IC_CMBP_1);
+               reg &= ~(0xff << ic->bit->ic_cmb_galpha_bit);
+               reg |= (galpha << ic->bit->ic_cmb_galpha_bit);
+               ipu_ic_write(ic, reg, IC_CMBP_1);
+       } else
+               ic_conf &= ~IC_CONF_IC_GLB_LOC_A;
+
+       if (colorkey_en) {
+               ic_conf |= IC_CONF_KEY_COLOR_EN;
+               ipu_ic_write(ic, colorkey, IC_CMBP_2);
+       } else
+               ic_conf &= ~IC_CONF_KEY_COLOR_EN;
+
+       ipu_ic_write(ic, ic_conf, IC_CONF);
+
+       ic->graphics = true;
+unlock:
+       spin_unlock_irqrestore(&priv->lock, flags);
+       return ret;
+}
+EXPORT_SYMBOL_GPL(ipu_ic_task_graphics_init);
+
+int ipu_ic_task_init(struct ipu_ic *ic,
+                    int in_width, int in_height,
+                    int out_width, int out_height,
+                    enum ipu_color_space in_cs,
+                    enum ipu_color_space out_cs)
+{
+       struct ipu_ic_priv *priv = ic->priv;
+       u32 reg, downsize_coeff, resize_coeff;
+       unsigned long flags;
+       int ret = 0;
+
+       /* Setup vertical resizing */
+       ret = calc_resize_coeffs(ic, in_height, out_height,
+                                &resize_coeff, &downsize_coeff);
+       if (ret)
+               return ret;
+
+       reg = (downsize_coeff << 30) | (resize_coeff << 16);
+
+       /* Setup horizontal resizing */
+       ret = calc_resize_coeffs(ic, in_width, out_width,
+                                &resize_coeff, &downsize_coeff);
+       if (ret)
+               return ret;
+
+       reg |= (downsize_coeff << 14) | resize_coeff;
+
+       spin_lock_irqsave(&priv->lock, flags);
+
+       ipu_ic_write(ic, reg, ic->reg->rsc);
+
+       /* Setup color space conversion */
+       ic->in_cs = in_cs;
+       ic->out_cs = out_cs;
+
+       if (ic->in_cs != ic->out_cs) {
+               ret = init_csc(ic, ic->in_cs, ic->out_cs, 0);
+               if (ret)
+                       goto unlock;
+       }
+
+unlock:
+       spin_unlock_irqrestore(&priv->lock, flags);
+       return ret;
+}
+EXPORT_SYMBOL_GPL(ipu_ic_task_init);
+
+int ipu_ic_task_idma_init(struct ipu_ic *ic, struct ipuv3_channel *channel,
+                         u32 width, u32 height, int burst_size,
+                         enum ipu_rotate_mode rot)
+{
+       struct ipu_ic_priv *priv = ic->priv;
+       struct ipu_soc *ipu = priv->ipu;
+       u32 ic_idmac_1, ic_idmac_2, ic_idmac_3;
+       u32 temp_rot = bitrev8(rot) >> 5;
+       bool need_hor_flip = false;
+       unsigned long flags;
+       int ret = 0;
+
+       if ((burst_size != 8) && (burst_size != 16)) {
+               dev_err(ipu->dev, "Illegal burst length for IC\n");
+               return -EINVAL;
+       }
+
+       width--;
+       height--;
+
+       if (temp_rot & 0x2)     /* Need horizontal flip */
+               need_hor_flip = true;
+
+       spin_lock_irqsave(&priv->lock, flags);
+
+       ic_idmac_1 = ipu_ic_read(ic, IC_IDMAC_1);
+       ic_idmac_2 = ipu_ic_read(ic, IC_IDMAC_2);
+       ic_idmac_3 = ipu_ic_read(ic, IC_IDMAC_3);
+
+       switch (channel->num) {
+       case IPUV3_CHANNEL_IC_PP_MEM:
+               if (burst_size == 16)
+                       ic_idmac_1 |= IC_IDMAC_1_CB2_BURST_16;
+               else
+                       ic_idmac_1 &= ~IC_IDMAC_1_CB2_BURST_16;
+
+               if (need_hor_flip)
+                       ic_idmac_1 |= IC_IDMAC_1_PP_FLIP_RS;
+               else
+                       ic_idmac_1 &= ~IC_IDMAC_1_PP_FLIP_RS;
+
+               ic_idmac_2 &= ~IC_IDMAC_2_PP_HEIGHT_MASK;
+               ic_idmac_2 |= height << IC_IDMAC_2_PP_HEIGHT_OFFSET;
+
+               ic_idmac_3 &= ~IC_IDMAC_3_PP_WIDTH_MASK;
+               ic_idmac_3 |= width << IC_IDMAC_3_PP_WIDTH_OFFSET;
+               break;
+       case IPUV3_CHANNEL_MEM_IC_PP:
+               if (burst_size == 16)
+                       ic_idmac_1 |= IC_IDMAC_1_CB5_BURST_16;
+               else
+                       ic_idmac_1 &= ~IC_IDMAC_1_CB5_BURST_16;
+               break;
+       case IPUV3_CHANNEL_MEM_ROT_PP:
+               ic_idmac_1 &= ~IC_IDMAC_1_PP_ROT_MASK;
+               ic_idmac_1 |= temp_rot << IC_IDMAC_1_PP_ROT_OFFSET;
+               break;
+       case IPUV3_CHANNEL_MEM_IC_PRP_VF:
+               if (burst_size == 16)
+                       ic_idmac_1 |= IC_IDMAC_1_CB6_BURST_16;
+               else
+                       ic_idmac_1 &= ~IC_IDMAC_1_CB6_BURST_16;
+               break;
+       case IPUV3_CHANNEL_IC_PRP_ENC_MEM:
+               if (burst_size == 16)
+                       ic_idmac_1 |= IC_IDMAC_1_CB0_BURST_16;
+               else
+                       ic_idmac_1 &= ~IC_IDMAC_1_CB0_BURST_16;
+
+               if (need_hor_flip)
+                       ic_idmac_1 |= IC_IDMAC_1_PRPENC_FLIP_RS;
+               else
+                       ic_idmac_1 &= ~IC_IDMAC_1_PRPENC_FLIP_RS;
+
+               ic_idmac_2 &= ~IC_IDMAC_2_PRPENC_HEIGHT_MASK;
+               ic_idmac_2 |= height << IC_IDMAC_2_PRPENC_HEIGHT_OFFSET;
+
+               ic_idmac_3 &= ~IC_IDMAC_3_PRPENC_WIDTH_MASK;
+               ic_idmac_3 |= width << IC_IDMAC_3_PRPENC_WIDTH_OFFSET;
+               break;
+       case IPUV3_CHANNEL_MEM_ROT_ENC:
+               ic_idmac_1 &= ~IC_IDMAC_1_PRPENC_ROT_MASK;
+               ic_idmac_1 |= temp_rot << IC_IDMAC_1_PRPENC_ROT_OFFSET;
+               break;
+       case IPUV3_CHANNEL_IC_PRP_VF_MEM:
+               if (burst_size == 16)
+                       ic_idmac_1 |= IC_IDMAC_1_CB1_BURST_16;
+               else
+                       ic_idmac_1 &= ~IC_IDMAC_1_CB1_BURST_16;
+
+               if (need_hor_flip)
+                       ic_idmac_1 |= IC_IDMAC_1_PRPVF_FLIP_RS;
+               else
+                       ic_idmac_1 &= ~IC_IDMAC_1_PRPVF_FLIP_RS;
+
+               ic_idmac_2 &= ~IC_IDMAC_2_PRPVF_HEIGHT_MASK;
+               ic_idmac_2 |= height << IC_IDMAC_2_PRPVF_HEIGHT_OFFSET;
+
+               ic_idmac_3 &= ~IC_IDMAC_3_PRPVF_WIDTH_MASK;
+               ic_idmac_3 |= width << IC_IDMAC_3_PRPVF_WIDTH_OFFSET;
+               break;
+       case IPUV3_CHANNEL_MEM_ROT_VF:
+               ic_idmac_1 &= ~IC_IDMAC_1_PRPVF_ROT_MASK;
+               ic_idmac_1 |= temp_rot << IC_IDMAC_1_PRPVF_ROT_OFFSET;
+               break;
+       case IPUV3_CHANNEL_G_MEM_IC_PRP_VF:
+               if (burst_size == 16)
+                       ic_idmac_1 |= IC_IDMAC_1_CB3_BURST_16;
+               else
+                       ic_idmac_1 &= ~IC_IDMAC_1_CB3_BURST_16;
+               break;
+       case IPUV3_CHANNEL_G_MEM_IC_PP:
+               if (burst_size == 16)
+                       ic_idmac_1 |= IC_IDMAC_1_CB4_BURST_16;
+               else
+                       ic_idmac_1 &= ~IC_IDMAC_1_CB4_BURST_16;
+               break;
+       case IPUV3_CHANNEL_VDI_MEM_IC_VF:
+               if (burst_size == 16)
+                       ic_idmac_1 |= IC_IDMAC_1_CB7_BURST_16;
+               else
+                       ic_idmac_1 &= ~IC_IDMAC_1_CB7_BURST_16;
+               break;
+       default:
+               goto unlock;
+       }
+
+       ipu_ic_write(ic, ic_idmac_1, IC_IDMAC_1);
+       ipu_ic_write(ic, ic_idmac_2, IC_IDMAC_2);
+       ipu_ic_write(ic, ic_idmac_3, IC_IDMAC_3);
+
+       if (rot >= IPU_ROTATE_90_RIGHT)
+               ic->rotation = true;
+
+unlock:
+       spin_unlock_irqrestore(&priv->lock, flags);
+       return ret;
+}
+EXPORT_SYMBOL_GPL(ipu_ic_task_idma_init);
+
+int ipu_ic_enable(struct ipu_ic *ic)
+{
+       struct ipu_ic_priv *priv = ic->priv;
+       unsigned long flags;
+       u32 module = IPU_CONF_IC_EN;
+
+       spin_lock_irqsave(&priv->lock, flags);
+
+       if (ic->rotation)
+               module |= IPU_CONF_ROT_EN;
+
+       if (!priv->use_count)
+               ipu_module_enable(priv->ipu, module);
+
+       priv->use_count++;
+
+       spin_unlock_irqrestore(&priv->lock, flags);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(ipu_ic_enable);
+
+int ipu_ic_disable(struct ipu_ic *ic)
+{
+       struct ipu_ic_priv *priv = ic->priv;
+       unsigned long flags;
+       u32 module = IPU_CONF_IC_EN | IPU_CONF_ROT_EN;
+
+       spin_lock_irqsave(&priv->lock, flags);
+
+       priv->use_count--;
+
+       if (!priv->use_count)
+               ipu_module_disable(priv->ipu, module);
+
+       if (priv->use_count < 0)
+               priv->use_count = 0;
+
+       spin_unlock_irqrestore(&priv->lock, flags);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(ipu_ic_disable);
+
+struct ipu_ic *ipu_ic_get(struct ipu_soc *ipu, enum ipu_ic_task task)
+{
+       struct ipu_ic_priv *priv = ipu->ic_priv;
+       unsigned long flags;
+       struct ipu_ic *ic, *ret;
+
+       if (task >= IC_NUM_TASKS)
+               return ERR_PTR(-EINVAL);
+
+       ic = &priv->task[task];
+
+       spin_lock_irqsave(&priv->lock, flags);
+
+       if (ic->in_use) {
+               ret = ERR_PTR(-EBUSY);
+               goto unlock;
+       }
+
+       ic->in_use = true;
+       ret = ic;
+
+unlock:
+       spin_unlock_irqrestore(&priv->lock, flags);
+       return ret;
+}
+EXPORT_SYMBOL_GPL(ipu_ic_get);
+
+void ipu_ic_put(struct ipu_ic *ic)
+{
+       struct ipu_ic_priv *priv = ic->priv;
+       unsigned long flags;
+
+       spin_lock_irqsave(&priv->lock, flags);
+       ic->in_use = false;
+       spin_unlock_irqrestore(&priv->lock, flags);
+}
+EXPORT_SYMBOL_GPL(ipu_ic_put);
+
+int ipu_ic_init(struct ipu_soc *ipu, struct device *dev,
+               unsigned long base, unsigned long tpmem_base)
+{
+       struct ipu_ic_priv *priv;
+       int i;
+
+       priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+       if (!priv)
+               return -ENOMEM;
+
+       ipu->ic_priv = priv;
+
+       spin_lock_init(&priv->lock);
+       priv->base = devm_ioremap(dev, base, PAGE_SIZE);
+       if (!priv->base)
+               return -ENOMEM;
+       priv->tpmem_base = devm_ioremap(dev, tpmem_base, SZ_64K);
+       if (!priv->tpmem_base)
+               return -ENOMEM;
+
+       dev_dbg(dev, "IC base: 0x%08lx remapped to %p\n", base, priv->base);
+
+       priv->ipu = ipu;
+
+       for (i = 0; i < IC_NUM_TASKS; i++) {
+               priv->task[i].task = i;
+               priv->task[i].priv = priv;
+               priv->task[i].reg = &ic_task_reg[i];
+               priv->task[i].bit = &ic_task_bit[i];
+       }
+
+       return 0;
+}
+
+void ipu_ic_exit(struct ipu_soc *ipu)
+{
+}
+
+void ipu_ic_dump(struct ipu_ic *ic)
+{
+       struct ipu_ic_priv *priv = ic->priv;
+       struct ipu_soc *ipu = priv->ipu;
+
+       dev_dbg(ipu->dev, "IC_CONF = \t0x%08X\n",
+               ipu_ic_read(ic, IC_CONF));
+       dev_dbg(ipu->dev, "IC_PRP_ENC_RSC = \t0x%08X\n",
+               ipu_ic_read(ic, IC_PRP_ENC_RSC));
+       dev_dbg(ipu->dev, "IC_PRP_VF_RSC = \t0x%08X\n",
+               ipu_ic_read(ic, IC_PRP_VF_RSC));
+       dev_dbg(ipu->dev, "IC_PP_RSC = \t0x%08X\n",
+               ipu_ic_read(ic, IC_PP_RSC));
+       dev_dbg(ipu->dev, "IC_CMBP_1 = \t0x%08X\n",
+               ipu_ic_read(ic, IC_CMBP_1));
+       dev_dbg(ipu->dev, "IC_CMBP_2 = \t0x%08X\n",
+               ipu_ic_read(ic, IC_CMBP_2));
+       dev_dbg(ipu->dev, "IC_IDMAC_1 = \t0x%08X\n",
+               ipu_ic_read(ic, IC_IDMAC_1));
+       dev_dbg(ipu->dev, "IC_IDMAC_2 = \t0x%08X\n",
+               ipu_ic_read(ic, IC_IDMAC_2));
+       dev_dbg(ipu->dev, "IC_IDMAC_3 = \t0x%08X\n",
+               ipu_ic_read(ic, IC_IDMAC_3));
+       dev_dbg(ipu->dev, "IC_IDMAC_4 = \t0x%08X\n",
+               ipu_ic_read(ic, IC_IDMAC_4));
+}
+EXPORT_SYMBOL_GPL(ipu_ic_dump);
index 0a7b2adaba39ea97037b313c5a4b41736e2811bd..bfb1e8a4483fdbf7afbcc15311b90e3be986ffb1 100644 (file)
@@ -24,23 +24,6 @@ struct ipu_soc;
 
 #include <video/imx-ipu-v3.h>
 
-#define IPUV3_CHANNEL_CSI0                      0
-#define IPUV3_CHANNEL_CSI1                      1
-#define IPUV3_CHANNEL_CSI2                      2
-#define IPUV3_CHANNEL_CSI3                      3
-#define IPUV3_CHANNEL_MEM_BG_SYNC              23
-#define IPUV3_CHANNEL_MEM_FG_SYNC              27
-#define IPUV3_CHANNEL_MEM_DC_SYNC              28
-#define IPUV3_CHANNEL_MEM_FG_SYNC_ALPHA                31
-#define IPUV3_CHANNEL_MEM_DC_ASYNC             41
-#define IPUV3_CHANNEL_ROT_ENC_MEM              45
-#define IPUV3_CHANNEL_ROT_VF_MEM               46
-#define IPUV3_CHANNEL_ROT_PP_MEM               47
-#define IPUV3_CHANNEL_ROT_ENC_MEM_OUT          48
-#define IPUV3_CHANNEL_ROT_VF_MEM_OUT           49
-#define IPUV3_CHANNEL_ROT_PP_MEM_OUT           50
-#define IPUV3_CHANNEL_MEM_BG_SYNC_ALPHA                51
-
 #define IPU_MCU_T_DEFAULT      8
 #define IPU_CM_IDMAC_REG_OFS   0x00008000
 #define IPU_CM_IC_REG_OFS      0x00020000
@@ -85,6 +68,7 @@ struct ipu_soc;
 #define IPU_DISP_TASK_STAT             IPU_CM_REG(0x0254)
 #define IPU_CHA_BUF0_RDY(ch)           IPU_CM_REG(0x0268 + 4 * ((ch) / 32))
 #define IPU_CHA_BUF1_RDY(ch)           IPU_CM_REG(0x0270 + 4 * ((ch) / 32))
+#define IPU_CHA_BUF2_RDY(ch)           IPU_CM_REG(0x0288 + 4 * ((ch) / 32))
 #define IPU_ALT_CHA_BUF0_RDY(ch)       IPU_CM_REG(0x0278 + 4 * ((ch) / 32))
 #define IPU_ALT_CHA_BUF1_RDY(ch)       IPU_CM_REG(0x0280 + 4 * ((ch) / 32))
 
@@ -149,9 +133,11 @@ struct ipuv3_channel {
 };
 
 struct ipu_cpmem;
+struct ipu_csi;
 struct ipu_dc_priv;
 struct ipu_dmfc_priv;
 struct ipu_di;
+struct ipu_ic_priv;
 struct ipu_smfc_priv;
 
 struct ipu_devtype;
@@ -181,6 +167,8 @@ struct ipu_soc {
        struct ipu_dp_priv      *dp_priv;
        struct ipu_dmfc_priv    *dmfc_priv;
        struct ipu_di           *di_priv[2];
+       struct ipu_csi          *csi_priv[2];
+       struct ipu_ic_priv      *ic_priv;
        struct ipu_smfc_priv    *smfc_priv;
 };
 
@@ -203,6 +191,14 @@ int ipu_module_disable(struct ipu_soc *ipu, u32 mask);
 bool ipu_idmac_channel_busy(struct ipu_soc *ipu, unsigned int chno);
 int ipu_wait_interrupt(struct ipu_soc *ipu, int irq, int ms);
 
+int ipu_csi_init(struct ipu_soc *ipu, struct device *dev, int id,
+                unsigned long base, u32 module, struct clk *clk_ipu);
+void ipu_csi_exit(struct ipu_soc *ipu, int id);
+
+int ipu_ic_init(struct ipu_soc *ipu, struct device *dev,
+               unsigned long base, unsigned long tpmem_base);
+void ipu_ic_exit(struct ipu_soc *ipu);
+
 int ipu_di_init(struct ipu_soc *ipu, struct device *dev, int id,
                unsigned long base, u32 module, struct clk *ipu_clk);
 void ipu_di_exit(struct ipu_soc *ipu, int id);
index e4f85ad286fc10a27aeadb51a842951b60e4efd5..4ef910991413019503d95d2e3868ce06e70f7e05 100644 (file)
@@ -8,7 +8,6 @@
  * http://www.opensource.org/licenses/gpl-license.html
  * http://www.gnu.org/copyleft/gpl.html
  */
-#define DEBUG
 #include <linux/export.h>
 #include <linux/types.h>
 #include <linux/init.h>
 
 #include "ipu-prv.h"
 
+struct ipu_smfc {
+       struct ipu_smfc_priv *priv;
+       int chno;
+       bool inuse;
+};
+
 struct ipu_smfc_priv {
        void __iomem *base;
        spinlock_t lock;
+       struct ipu_soc *ipu;
+       struct ipu_smfc channel[4];
+       int use_count;
 };
 
 /*SMFC Registers */
@@ -31,63 +39,166 @@ struct ipu_smfc_priv {
 #define SMFC_WMC       0x0004
 #define SMFC_BS                0x0008
 
-int ipu_smfc_set_burstsize(struct ipu_soc *ipu, int channel, int burstsize)
+int ipu_smfc_set_burstsize(struct ipu_smfc *smfc, int burstsize)
 {
-       struct ipu_smfc_priv *smfc = ipu->smfc_priv;
+       struct ipu_smfc_priv *priv = smfc->priv;
        unsigned long flags;
        u32 val, shift;
 
-       spin_lock_irqsave(&smfc->lock, flags);
+       spin_lock_irqsave(&priv->lock, flags);
 
-       shift = channel * 4;
-       val = readl(smfc->base + SMFC_BS);
+       shift = smfc->chno * 4;
+       val = readl(priv->base + SMFC_BS);
        val &= ~(0xf << shift);
        val |= burstsize << shift;
-       writel(val, smfc->base + SMFC_BS);
+       writel(val, priv->base + SMFC_BS);
 
-       spin_unlock_irqrestore(&smfc->lock, flags);
+       spin_unlock_irqrestore(&priv->lock, flags);
 
        return 0;
 }
 EXPORT_SYMBOL_GPL(ipu_smfc_set_burstsize);
 
-int ipu_smfc_map_channel(struct ipu_soc *ipu, int channel, int csi_id, int mipi_id)
+int ipu_smfc_map_channel(struct ipu_smfc *smfc, int csi_id, int mipi_id)
 {
-       struct ipu_smfc_priv *smfc = ipu->smfc_priv;
+       struct ipu_smfc_priv *priv = smfc->priv;
        unsigned long flags;
        u32 val, shift;
 
-       spin_lock_irqsave(&smfc->lock, flags);
+       spin_lock_irqsave(&priv->lock, flags);
 
-       shift = channel * 3;
-       val = readl(smfc->base + SMFC_MAP);
+       shift = smfc->chno * 3;
+       val = readl(priv->base + SMFC_MAP);
        val &= ~(0x7 << shift);
        val |= ((csi_id << 2) | mipi_id) << shift;
-       writel(val, smfc->base + SMFC_MAP);
+       writel(val, priv->base + SMFC_MAP);
 
-       spin_unlock_irqrestore(&smfc->lock, flags);
+       spin_unlock_irqrestore(&priv->lock, flags);
 
        return 0;
 }
 EXPORT_SYMBOL_GPL(ipu_smfc_map_channel);
 
+int ipu_smfc_set_watermark(struct ipu_smfc *smfc, u32 set_level, u32 clr_level)
+{
+       struct ipu_smfc_priv *priv = smfc->priv;
+       unsigned long flags;
+       u32 val, shift;
+
+       spin_lock_irqsave(&priv->lock, flags);
+
+       shift = smfc->chno * 6 + (smfc->chno > 1 ? 4 : 0);
+       val = readl(priv->base + SMFC_WMC);
+       val &= ~(0x3f << shift);
+       val |= ((clr_level << 3) | set_level) << shift;
+       writel(val, priv->base + SMFC_WMC);
+
+       spin_unlock_irqrestore(&priv->lock, flags);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(ipu_smfc_set_watermark);
+
+int ipu_smfc_enable(struct ipu_smfc *smfc)
+{
+       struct ipu_smfc_priv *priv = smfc->priv;
+       unsigned long flags;
+
+       spin_lock_irqsave(&priv->lock, flags);
+
+       if (!priv->use_count)
+               ipu_module_enable(priv->ipu, IPU_CONF_SMFC_EN);
+
+       priv->use_count++;
+
+       spin_unlock_irqrestore(&priv->lock, flags);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(ipu_smfc_enable);
+
+int ipu_smfc_disable(struct ipu_smfc *smfc)
+{
+       struct ipu_smfc_priv *priv = smfc->priv;
+       unsigned long flags;
+
+       spin_lock_irqsave(&priv->lock, flags);
+
+       priv->use_count--;
+
+       if (!priv->use_count)
+               ipu_module_disable(priv->ipu, IPU_CONF_SMFC_EN);
+
+       if (priv->use_count < 0)
+               priv->use_count = 0;
+
+       spin_unlock_irqrestore(&priv->lock, flags);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(ipu_smfc_disable);
+
+struct ipu_smfc *ipu_smfc_get(struct ipu_soc *ipu, unsigned int chno)
+{
+       struct ipu_smfc_priv *priv = ipu->smfc_priv;
+       struct ipu_smfc *smfc, *ret;
+       unsigned long flags;
+
+       if (chno >= 4)
+               return ERR_PTR(-EINVAL);
+
+       smfc = &priv->channel[chno];
+       ret = smfc;
+
+       spin_lock_irqsave(&priv->lock, flags);
+
+       if (smfc->inuse) {
+               ret = ERR_PTR(-EBUSY);
+               goto unlock;
+       }
+
+       smfc->inuse = true;
+unlock:
+       spin_unlock_irqrestore(&priv->lock, flags);
+       return ret;
+}
+EXPORT_SYMBOL_GPL(ipu_smfc_get);
+
+void ipu_smfc_put(struct ipu_smfc *smfc)
+{
+       struct ipu_smfc_priv *priv = smfc->priv;
+       unsigned long flags;
+
+       spin_lock_irqsave(&priv->lock, flags);
+       smfc->inuse = false;
+       spin_unlock_irqrestore(&priv->lock, flags);
+}
+EXPORT_SYMBOL_GPL(ipu_smfc_put);
+
 int ipu_smfc_init(struct ipu_soc *ipu, struct device *dev,
                  unsigned long base)
 {
-       struct ipu_smfc_priv *smfc;
+       struct ipu_smfc_priv *priv;
+       int i;
 
-       smfc = devm_kzalloc(dev, sizeof(*smfc), GFP_KERNEL);
-       if (!smfc)
+       priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+       if (!priv)
                return -ENOMEM;
 
-       ipu->smfc_priv = smfc;
-       spin_lock_init(&smfc->lock);
+       ipu->smfc_priv = priv;
+       spin_lock_init(&priv->lock);
+       priv->ipu = ipu;
 
-       smfc->base = devm_ioremap(dev, base, PAGE_SIZE);
-       if (!smfc->base)
+       priv->base = devm_ioremap(dev, base, PAGE_SIZE);
+       if (!priv->base)
                return -ENOMEM;
 
-       pr_debug("%s: ioremap 0x%08lx -> %p\n", __func__, base, smfc->base);
+       for (i = 0; i < 4; i++) {
+               priv->channel[i].priv = priv;
+               priv->channel[i].chno = i;
+       }
+
+       pr_debug("%s: ioremap 0x%08lx -> %p\n", __func__, base, priv->base);
 
        return 0;
 }
index 77711623b9739526f8605fef680120424e4f9a59..7bcbf863656ec6f2c1e76d6156365fc0548230ff 100644 (file)
@@ -400,7 +400,6 @@ int vga_get(struct pci_dev *pdev, unsigned int rsrc, int interruptible)
                }
                schedule();
                remove_wait_queue(&vga_wait_queue, &wait);
-               set_current_state(TASK_RUNNING);
        }
        return rc;
 }
index f00d048aa583591c45aca5a7e683002c5bbc4721..5286d7ce1f9eb77a4a92902317411a7bda069490 100644 (file)
@@ -280,8 +280,8 @@ config SENSORS_K10TEMP
          If you say yes here you get support for the temperature
          sensor(s) inside your CPU. Supported are later revisions of
          the AMD Family 10h and all revisions of the AMD Family 11h,
-         12h (Llano), 14h (Brazos), 15h (Bulldozer/Trinity/Kaveri) and
-         16h (Kabini/Mullins) microarchitectures.
+         12h (Llano), 14h (Brazos), 15h (Bulldozer/Trinity/Kaveri/Carrizo)
+         and 16h (Kabini/Mullins) microarchitectures.
 
          This driver can also be built as a module.  If so, the module
          will be called k10temp.
@@ -839,6 +839,16 @@ config SENSORS_MCP3021
          This driver can also be built as a module.  If so, the module
          will be called mcp3021.
 
+config SENSORS_MENF21BMC_HWMON
+       tristate "MEN 14F021P00 BMC Hardware Monitoring"
+       depends on MFD_MENF21BMC
+       help
+         Say Y here to include support for the MEN 14F021P00 BMC
+         hardware monitoring.
+
+         This driver can also be built as a module. If so the module
+         will be called menf21bmc_hwmon.
+
 config SENSORS_ADCXX
        tristate "National Semiconductor ADCxxxSxxx"
        depends on SPI_MASTER
@@ -1077,6 +1087,7 @@ config SENSORS_PC87427
 config SENSORS_NTC_THERMISTOR
        tristate "NTC thermistor support from Murata"
        depends on !OF || IIO=n || IIO
+       depends on THERMAL || !THERMAL_OF
        help
          This driver supports NTC thermistors sensor reading and its
          interpretation. The driver can also monitor the temperature and
index be28152c9848806391f58abecce93914f7edf384..c90a7611efaabc26c35c8b66cc90fbe50b4e9c96 100644 (file)
@@ -115,6 +115,7 @@ obj-$(CONFIG_SENSORS_MAX6650)       += max6650.o
 obj-$(CONFIG_SENSORS_MAX6697)  += max6697.o
 obj-$(CONFIG_SENSORS_MC13783_ADC)+= mc13783-adc.o
 obj-$(CONFIG_SENSORS_MCP3021)  += mcp3021.o
+obj-$(CONFIG_SENSORS_MENF21BMC_HWMON) += menf21bmc_hwmon.o
 obj-$(CONFIG_SENSORS_NCT6683)  += nct6683.o
 obj-$(CONFIG_SENSORS_NCT6775)  += nct6775.o
 obj-$(CONFIG_SENSORS_NTC_THERMISTOR)   += ntc_thermistor.o
index d844dc806853d2cbc06760af1a92790dd1392faa..8b6a4f4c8774b10322ecfb56c6bbe992b693dab2 100644 (file)
@@ -6,7 +6,7 @@
  *
  * When the AB8500 thermal warning temperature is reached (threshold cannot
  * be changed by SW), an interrupt is set, and if no further action is taken
- * within a certain time frame, pm_power off will be called.
+ * within a certain time frame, kernel_power_off will be called.
  *
  * When AB8500 thermal shutdown temperature is reached a hardware shutdown of
  * the AB8500 will occur.
@@ -21,6 +21,7 @@
 #include <linux/module.h>
 #include <linux/platform_device.h>
 #include <linux/power/ab8500.h>
+#include <linux/reboot.h>
 #include <linux/slab.h>
 #include <linux/sysfs.h>
 #include "abx500.h"
@@ -106,7 +107,7 @@ static void ab8500_thermal_power_off(struct work_struct *work)
 
        dev_warn(&abx500_data->pdev->dev, "Power off due to critical temp\n");
 
-       pm_power_off();
+       kernel_power_off();
 }
 
 static ssize_t ab8500_show_name(struct device *dev,
index 126516414c114f309161924e49d5dbef3d60d3bb..f155b83804819ff97455ba5312f62de7f14991e2 100644 (file)
@@ -184,20 +184,18 @@ static int ads1015_get_channels_config_of(struct i2c_client *client)
                return -EINVAL;
 
        for_each_child_of_node(client->dev.of_node, node) {
-               const __be32 *property;
-               int len;
+               u32 pval;
                unsigned int channel;
                unsigned int pga = ADS1015_DEFAULT_PGA;
                unsigned int data_rate = ADS1015_DEFAULT_DATA_RATE;
 
-               property = of_get_property(node, "reg", &len);
-               if (!property || len != sizeof(int)) {
+               if (of_property_read_u32(node, "reg", &pval)) {
                        dev_err(&client->dev, "invalid reg on %s\n",
                                node->full_name);
                        continue;
                }
 
-               channel = be32_to_cpup(property);
+               channel = pval;
                if (channel >= ADS1015_CHANNELS) {
                        dev_err(&client->dev,
                                "invalid channel index %d on %s\n",
@@ -205,20 +203,17 @@ static int ads1015_get_channels_config_of(struct i2c_client *client)
                        continue;
                }
 
-               property = of_get_property(node, "ti,gain", &len);
-               if (property && len == sizeof(int)) {
-                       pga = be32_to_cpup(property);
+               if (!of_property_read_u32(node, "ti,gain", &pval)) {
+                       pga = pval;
                        if (pga > 6) {
-                               dev_err(&client->dev,
-                                       "invalid gain on %s\n",
+                               dev_err(&client->dev, "invalid gain on %s\n",
                                        node->full_name);
                                return -EINVAL;
                        }
                }
 
-               property = of_get_property(node, "ti,datarate", &len);
-               if (property && len == sizeof(int)) {
-                       data_rate = be32_to_cpup(property);
+               if (!of_property_read_u32(node, "ti,datarate", &pval)) {
+                       data_rate = pval;
                        if (data_rate > 7) {
                                dev_err(&client->dev,
                                        "invalid data_rate on %s\n",
index d14ab3c45daa32c88c7423f8508b38ed015aad49..692b3f34d88c92fcee79231fc013093f169ff7ce 100644 (file)
@@ -26,7 +26,6 @@
 
 struct da9052_hwmon {
        struct da9052   *da9052;
-       struct device   *class_device;
        struct mutex    hwmon_lock;
 };
 
@@ -190,13 +189,6 @@ static ssize_t da9052_read_vbbat(struct device *dev,
        return sprintf(buf, "%d\n", vbbat_reg_to_mv(ret));
 }
 
-static ssize_t da9052_hwmon_show_name(struct device *dev,
-                                     struct device_attribute *devattr,
-                                     char *buf)
-{
-       return sprintf(buf, "da9052\n");
-}
-
 static ssize_t show_label(struct device *dev,
                          struct device_attribute *devattr, char *buf)
 {
@@ -243,10 +235,7 @@ static SENSOR_DEVICE_ATTR(temp8_input, S_IRUGO, da9052_read_tjunc, NULL,
 static SENSOR_DEVICE_ATTR(temp8_label, S_IRUGO, show_label, NULL,
                          DA9052_ADC_TJUNC);
 
-static DEVICE_ATTR(name, S_IRUGO, da9052_hwmon_show_name, NULL);
-
-static struct attribute *da9052_attr[] = {
-       &dev_attr_name.attr,
+static struct attribute *da9052_attrs[] = {
        &sensor_dev_attr_in0_input.dev_attr.attr,
        &sensor_dev_attr_in0_label.dev_attr.attr,
        &sensor_dev_attr_in3_input.dev_attr.attr,
@@ -268,54 +257,29 @@ static struct attribute *da9052_attr[] = {
        NULL
 };
 
-static const struct attribute_group da9052_attr_group = {.attrs = da9052_attr};
+ATTRIBUTE_GROUPS(da9052);
 
 static int da9052_hwmon_probe(struct platform_device *pdev)
 {
+       struct device *dev = &pdev->dev;
        struct da9052_hwmon *hwmon;
-       int ret;
+       struct device *hwmon_dev;
 
-       hwmon = devm_kzalloc(&pdev->dev, sizeof(struct da9052_hwmon),
-                            GFP_KERNEL);
+       hwmon = devm_kzalloc(dev, sizeof(struct da9052_hwmon), GFP_KERNEL);
        if (!hwmon)
                return -ENOMEM;
 
        mutex_init(&hwmon->hwmon_lock);
        hwmon->da9052 = dev_get_drvdata(pdev->dev.parent);
 
-       platform_set_drvdata(pdev, hwmon);
-
-       ret = sysfs_create_group(&pdev->dev.kobj, &da9052_attr_group);
-       if (ret)
-               goto err_mem;
-
-       hwmon->class_device = hwmon_device_register(&pdev->dev);
-       if (IS_ERR(hwmon->class_device)) {
-               ret = PTR_ERR(hwmon->class_device);
-               goto err_sysfs;
-       }
-
-       return 0;
-
-err_sysfs:
-       sysfs_remove_group(&pdev->dev.kobj, &da9052_attr_group);
-err_mem:
-       return ret;
-}
-
-static int da9052_hwmon_remove(struct platform_device *pdev)
-{
-       struct da9052_hwmon *hwmon = platform_get_drvdata(pdev);
-
-       hwmon_device_unregister(hwmon->class_device);
-       sysfs_remove_group(&pdev->dev.kobj, &da9052_attr_group);
-
-       return 0;
+       hwmon_dev = devm_hwmon_device_register_with_groups(dev, "da9052",
+                                                          hwmon,
+                                                          da9052_groups);
+       return PTR_ERR_OR_ZERO(hwmon_dev);
 }
 
 static struct platform_driver da9052_hwmon_driver = {
        .probe = da9052_hwmon_probe,
-       .remove = da9052_hwmon_remove,
        .driver = {
                .name = "da9052-hwmon",
                .owner = THIS_MODULE,
index 35eb7738d7119cf2d706d5cd60323b04e9e76988..9916a3fb4bb9d4eb8221db0ea264eae184dcb42b 100644 (file)
@@ -36,7 +36,6 @@
 
 struct da9055_hwmon {
        struct da9055   *da9055;
-       struct device   *class_device;
        struct mutex    hwmon_lock;
        struct mutex    irq_lock;
        struct completion done;
@@ -200,13 +199,6 @@ static ssize_t da9055_read_tjunc(struct device *dev,
                                                        + 3076332, 10000));
 }
 
-static ssize_t da9055_hwmon_show_name(struct device *dev,
-                                     struct device_attribute *devattr,
-                                     char *buf)
-{
-       return sprintf(buf, "da9055\n");
-}
-
 static ssize_t show_label(struct device *dev,
                          struct device_attribute *devattr, char *buf)
 {
@@ -236,10 +228,7 @@ static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, da9055_read_tjunc, NULL,
 static SENSOR_DEVICE_ATTR(temp1_label, S_IRUGO, show_label, NULL,
                          DA9055_ADC_TJUNC);
 
-static DEVICE_ATTR(name, S_IRUGO, da9055_hwmon_show_name, NULL);
-
-static struct attribute *da9055_attr[] = {
-       &dev_attr_name.attr,
+static struct attribute *da9055_attrs[] = {
        &sensor_dev_attr_in0_input.dev_attr.attr,
        &sensor_dev_attr_in0_label.dev_attr.attr,
        &sensor_dev_attr_in1_input.dev_attr.attr,
@@ -254,15 +243,16 @@ static struct attribute *da9055_attr[] = {
        NULL
 };
 
-static const struct attribute_group da9055_attr_group = {.attrs = da9055_attr};
+ATTRIBUTE_GROUPS(da9055);
 
 static int da9055_hwmon_probe(struct platform_device *pdev)
 {
+       struct device *dev = &pdev->dev;
        struct da9055_hwmon *hwmon;
+       struct device *hwmon_dev;
        int hwmon_irq, ret;
 
-       hwmon = devm_kzalloc(&pdev->dev, sizeof(struct da9055_hwmon),
-                            GFP_KERNEL);
+       hwmon = devm_kzalloc(dev, sizeof(struct da9055_hwmon), GFP_KERNEL);
        if (!hwmon)
                return -ENOMEM;
 
@@ -272,8 +262,6 @@ static int da9055_hwmon_probe(struct platform_device *pdev)
        init_completion(&hwmon->done);
        hwmon->da9055 = dev_get_drvdata(pdev->dev.parent);
 
-       platform_set_drvdata(pdev, hwmon);
-
        hwmon_irq = platform_get_irq_byname(pdev, "HWMON");
        if (hwmon_irq < 0)
                return hwmon_irq;
@@ -288,36 +276,14 @@ static int da9055_hwmon_probe(struct platform_device *pdev)
                return ret;
        }
 
-       ret = sysfs_create_group(&pdev->dev.kobj, &da9055_attr_group);
-       if (ret)
-               return ret;
-
-       hwmon->class_device = hwmon_device_register(&pdev->dev);
-       if (IS_ERR(hwmon->class_device)) {
-               ret = PTR_ERR(hwmon->class_device);
-               goto err;
-       }
-
-       return 0;
-
-err:
-       sysfs_remove_group(&pdev->dev.kobj, &da9055_attr_group);
-       return ret;
-}
-
-static int da9055_hwmon_remove(struct platform_device *pdev)
-{
-       struct da9055_hwmon *hwmon = platform_get_drvdata(pdev);
-
-       sysfs_remove_group(&pdev->dev.kobj, &da9055_attr_group);
-       hwmon_device_unregister(hwmon->class_device);
-
-       return 0;
+       hwmon_dev = devm_hwmon_device_register_with_groups(dev, "da9055",
+                                                          hwmon,
+                                                          da9055_groups);
+       return PTR_ERR_OR_ZERO(hwmon_dev);
 }
 
 static struct platform_driver da9055_hwmon_driver = {
        .probe = da9055_hwmon_probe,
-       .remove = da9055_hwmon_remove,
        .driver = {
                .name = "da9055-hwmon",
                .owner = THIS_MODULE,
index f7b46f68ef43aeaa838fdee97227b097b8bbc453..1e7bdcdcb2955d22e0c9492d55b29eb11255cd1b 100644 (file)
@@ -33,6 +33,9 @@ static bool force;
 module_param(force, bool, 0444);
 MODULE_PARM_DESC(force, "force loading on processors with erratum 319");
 
+/* Provide lock for writing to NB_SMU_IND_ADDR */
+static DEFINE_MUTEX(nb_smu_ind_mutex);
+
 /* CPUID function 0x80000001, ebx */
 #define CPUID_PKGTYPE_MASK     0xf0000000
 #define CPUID_PKGTYPE_F                0x00000000
@@ -51,13 +54,38 @@ MODULE_PARM_DESC(force, "force loading on processors with erratum 319");
 #define REG_NORTHBRIDGE_CAPABILITIES   0xe8
 #define  NB_CAP_HTC                    0x00000400
 
+/*
+ * For F15h M60h, functionality of REG_REPORTED_TEMPERATURE
+ * has been moved to D0F0xBC_xD820_0CA4 [Reported Temperature
+ * Control]
+ */
+#define F15H_M60H_REPORTED_TEMP_CTRL_OFFSET    0xd8200ca4
+#define PCI_DEVICE_ID_AMD_15H_M60H_NB_F3       0x1573
+
+static void amd_nb_smu_index_read(struct pci_dev *pdev, unsigned int devfn,
+                                 int offset, u32 *val)
+{
+       mutex_lock(&nb_smu_ind_mutex);
+       pci_bus_write_config_dword(pdev->bus, devfn,
+                                  0xb8, offset);
+       pci_bus_read_config_dword(pdev->bus, devfn,
+                                 0xbc, val);
+       mutex_unlock(&nb_smu_ind_mutex);
+}
+
 static ssize_t show_temp(struct device *dev,
                         struct device_attribute *attr, char *buf)
 {
        u32 regval;
-
-       pci_read_config_dword(to_pci_dev(dev),
-                             REG_REPORTED_TEMPERATURE, &regval);
+       struct pci_dev *pdev = dev_get_drvdata(dev);
+
+       if (boot_cpu_data.x86 == 0x15 && boot_cpu_data.x86_model == 0x60) {
+               amd_nb_smu_index_read(pdev, PCI_DEVFN(0, 0),
+                                     F15H_M60H_REPORTED_TEMP_CTRL_OFFSET,
+                                     &regval);
+       } else {
+               pci_read_config_dword(pdev, REG_REPORTED_TEMPERATURE, &regval);
+       }
        return sprintf(buf, "%u\n", (regval >> 21) * 125);
 }
 
@@ -75,7 +103,7 @@ static ssize_t show_temp_crit(struct device *dev,
        u32 regval;
        int value;
 
-       pci_read_config_dword(to_pci_dev(dev),
+       pci_read_config_dword(dev_get_drvdata(dev),
                              REG_HARDWARE_THERMAL_CONTROL, &regval);
        value = ((regval >> 16) & 0x7f) * 500 + 52000;
        if (show_hyst)
@@ -83,17 +111,43 @@ static ssize_t show_temp_crit(struct device *dev,
        return sprintf(buf, "%d\n", value);
 }
 
-static ssize_t show_name(struct device *dev,
-                        struct device_attribute *attr, char *buf)
-{
-       return sprintf(buf, "k10temp\n");
-}
-
 static DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL);
 static DEVICE_ATTR(temp1_max, S_IRUGO, show_temp_max, NULL);
 static SENSOR_DEVICE_ATTR(temp1_crit, S_IRUGO, show_temp_crit, NULL, 0);
 static SENSOR_DEVICE_ATTR(temp1_crit_hyst, S_IRUGO, show_temp_crit, NULL, 1);
-static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
+
+static umode_t k10temp_is_visible(struct kobject *kobj,
+                                 struct attribute *attr, int index)
+{
+       struct device *dev = container_of(kobj, struct device, kobj);
+       struct pci_dev *pdev = dev_get_drvdata(dev);
+
+       if (index >= 2) {
+               u32 reg_caps, reg_htc;
+
+               pci_read_config_dword(pdev, REG_NORTHBRIDGE_CAPABILITIES,
+                                     &reg_caps);
+               pci_read_config_dword(pdev, REG_HARDWARE_THERMAL_CONTROL,
+                                     &reg_htc);
+               if (!(reg_caps & NB_CAP_HTC) || !(reg_htc & HTC_ENABLE))
+                       return 0;
+       }
+       return attr->mode;
+}
+
+static struct attribute *k10temp_attrs[] = {
+       &dev_attr_temp1_input.attr,
+       &dev_attr_temp1_max.attr,
+       &sensor_dev_attr_temp1_crit.dev_attr.attr,
+       &sensor_dev_attr_temp1_crit_hyst.dev_attr.attr,
+       NULL
+};
+
+static const struct attribute_group k10temp_group = {
+       .attrs = k10temp_attrs,
+       .is_visible = k10temp_is_visible,
+};
+__ATTRIBUTE_GROUPS(k10temp);
 
 static bool has_erratum_319(struct pci_dev *pdev)
 {
@@ -132,76 +186,23 @@ static bool has_erratum_319(struct pci_dev *pdev)
 static int k10temp_probe(struct pci_dev *pdev,
                                   const struct pci_device_id *id)
 {
-       struct device *hwmon_dev;
-       u32 reg_caps, reg_htc;
        int unreliable = has_erratum_319(pdev);
-       int err;
-
-       if (unreliable && !force) {
-               dev_err(&pdev->dev,
-                       "unreliable CPU thermal sensor; monitoring disabled\n");
-               err = -ENODEV;
-               goto exit;
-       }
-
-       err = device_create_file(&pdev->dev, &dev_attr_temp1_input);
-       if (err)
-               goto exit;
-       err = device_create_file(&pdev->dev, &dev_attr_temp1_max);
-       if (err)
-               goto exit_remove;
-
-       pci_read_config_dword(pdev, REG_NORTHBRIDGE_CAPABILITIES, &reg_caps);
-       pci_read_config_dword(pdev, REG_HARDWARE_THERMAL_CONTROL, &reg_htc);
-       if ((reg_caps & NB_CAP_HTC) && (reg_htc & HTC_ENABLE)) {
-               err = device_create_file(&pdev->dev,
-                               &sensor_dev_attr_temp1_crit.dev_attr);
-               if (err)
-                       goto exit_remove;
-               err = device_create_file(&pdev->dev,
-                               &sensor_dev_attr_temp1_crit_hyst.dev_attr);
-               if (err)
-                       goto exit_remove;
-       }
-
-       err = device_create_file(&pdev->dev, &dev_attr_name);
-       if (err)
-               goto exit_remove;
-
-       hwmon_dev = hwmon_device_register(&pdev->dev);
-       if (IS_ERR(hwmon_dev)) {
-               err = PTR_ERR(hwmon_dev);
-               goto exit_remove;
-       }
-       pci_set_drvdata(pdev, hwmon_dev);
+       struct device *dev = &pdev->dev;
+       struct device *hwmon_dev;
 
-       if (unreliable && force)
-               dev_warn(&pdev->dev,
+       if (unreliable) {
+               if (!force) {
+                       dev_err(dev,
+                               "unreliable CPU thermal sensor; monitoring disabled\n");
+                       return -ENODEV;
+               }
+               dev_warn(dev,
                         "unreliable CPU thermal sensor; check erratum 319\n");
-       return 0;
-
-exit_remove:
-       device_remove_file(&pdev->dev, &dev_attr_name);
-       device_remove_file(&pdev->dev, &dev_attr_temp1_input);
-       device_remove_file(&pdev->dev, &dev_attr_temp1_max);
-       device_remove_file(&pdev->dev,
-                          &sensor_dev_attr_temp1_crit.dev_attr);
-       device_remove_file(&pdev->dev,
-                          &sensor_dev_attr_temp1_crit_hyst.dev_attr);
-exit:
-       return err;
-}
+       }
 
-static void k10temp_remove(struct pci_dev *pdev)
-{
-       hwmon_device_unregister(pci_get_drvdata(pdev));
-       device_remove_file(&pdev->dev, &dev_attr_name);
-       device_remove_file(&pdev->dev, &dev_attr_temp1_input);
-       device_remove_file(&pdev->dev, &dev_attr_temp1_max);
-       device_remove_file(&pdev->dev,
-                          &sensor_dev_attr_temp1_crit.dev_attr);
-       device_remove_file(&pdev->dev,
-                          &sensor_dev_attr_temp1_crit_hyst.dev_attr);
+       hwmon_dev = devm_hwmon_device_register_with_groups(dev, "k10temp", pdev,
+                                                          k10temp_groups);
+       return PTR_ERR_OR_ZERO(hwmon_dev);
 }
 
 static const struct pci_device_id k10temp_id_table[] = {
@@ -211,6 +212,7 @@ static const struct pci_device_id k10temp_id_table[] = {
        { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_15H_NB_F3) },
        { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_15H_M10H_F3) },
        { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_15H_M30H_NB_F3) },
+       { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_15H_M60H_NB_F3) },
        { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_16H_NB_F3) },
        { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_16H_M30H_NB_F3) },
        {}
@@ -221,7 +223,6 @@ static struct pci_driver k10temp_driver = {
        .name = "k10temp",
        .id_table = k10temp_id_table,
        .probe = k10temp_probe,
-       .remove = k10temp_remove,
 };
 
 module_pci_driver(k10temp_driver);
diff --git a/drivers/hwmon/menf21bmc_hwmon.c b/drivers/hwmon/menf21bmc_hwmon.c
new file mode 100644 (file)
index 0000000..c92229d
--- /dev/null
@@ -0,0 +1,230 @@
+/*
+ *  MEN 14F021P00 Board Management Controller (BMC) hwmon driver.
+ *
+ *  This is the core hwmon driver of the MEN 14F021P00 BMC.
+ *  The BMC monitors the board voltages which can be access with this
+ *  driver through sysfs.
+ *
+ *  Copyright (C) 2014 MEN Mikro Elektronik Nuernberg GmbH
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/jiffies.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+
+#define DRV_NAME  "menf21bmc_hwmon"
+
+#define BMC_VOLT_COUNT 5
+#define MENF21BMC_V33  0
+#define MENF21BMC_V5   1
+#define MENF21BMC_V12  2
+#define MENF21BMC_V5_SB        3
+#define MENF21BMC_VBAT 4
+
+#define IDX_TO_VOLT_MIN_CMD(idx) (0x40 + idx)
+#define IDX_TO_VOLT_MAX_CMD(idx) (0x50 + idx)
+#define IDX_TO_VOLT_INP_CMD(idx) (0x60 + idx)
+
+struct menf21bmc_hwmon {
+       bool valid;
+       struct i2c_client *i2c_client;
+       unsigned long last_update;
+       int in_val[BMC_VOLT_COUNT];
+       int in_min[BMC_VOLT_COUNT];
+       int in_max[BMC_VOLT_COUNT];
+};
+
+static const char *const input_names[] = {
+       [MENF21BMC_V33]         = "MON_3_3V",
+       [MENF21BMC_V5]          = "MON_5V",
+       [MENF21BMC_V12]         = "MON_12V",
+       [MENF21BMC_V5_SB]       = "5V_STANDBY",
+       [MENF21BMC_VBAT]        = "VBAT"
+};
+
+static struct menf21bmc_hwmon *menf21bmc_hwmon_update(struct device *dev)
+{
+       int i;
+       int val;
+       struct menf21bmc_hwmon *drv_data = dev_get_drvdata(dev);
+       struct menf21bmc_hwmon *data_ret = drv_data;
+
+       if (time_after(jiffies, drv_data->last_update + HZ)
+           || !drv_data->valid) {
+               for (i = 0; i < BMC_VOLT_COUNT; i++) {
+                       val = i2c_smbus_read_word_data(drv_data->i2c_client,
+                                                      IDX_TO_VOLT_INP_CMD(i));
+                       if (val < 0) {
+                               data_ret = ERR_PTR(val);
+                               goto abort;
+                       }
+                       drv_data->in_val[i] = val;
+               }
+               drv_data->last_update = jiffies;
+               drv_data->valid = true;
+       }
+abort:
+       return data_ret;
+}
+
+static int menf21bmc_hwmon_get_volt_limits(struct menf21bmc_hwmon *drv_data)
+{
+       int i, val;
+
+       for (i = 0; i < BMC_VOLT_COUNT; i++) {
+               val = i2c_smbus_read_word_data(drv_data->i2c_client,
+                                              IDX_TO_VOLT_MIN_CMD(i));
+               if (val < 0)
+                       return val;
+
+               drv_data->in_min[i] = val;
+
+               val = i2c_smbus_read_word_data(drv_data->i2c_client,
+                                              IDX_TO_VOLT_MAX_CMD(i));
+               if (val < 0)
+                       return val;
+
+               drv_data->in_max[i] = val;
+       }
+       return 0;
+}
+
+static ssize_t
+show_label(struct device *dev, struct device_attribute *devattr, char *buf)
+{
+       struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+
+       return sprintf(buf, "%s\n", input_names[attr->index]);
+}
+
+static ssize_t
+show_in(struct device *dev, struct device_attribute *devattr, char *buf)
+{
+       struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+       struct menf21bmc_hwmon *drv_data = menf21bmc_hwmon_update(dev);
+
+       if (IS_ERR(drv_data))
+               return PTR_ERR(drv_data);
+
+       return sprintf(buf, "%d\n", drv_data->in_val[attr->index]);
+}
+
+static ssize_t
+show_min(struct device *dev, struct device_attribute *devattr, char *buf)
+{
+       struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+       struct menf21bmc_hwmon *drv_data = dev_get_drvdata(dev);
+
+       return sprintf(buf, "%d\n", drv_data->in_min[attr->index]);
+}
+
+static ssize_t
+show_max(struct device *dev, struct device_attribute *devattr, char *buf)
+{
+       struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+       struct menf21bmc_hwmon *drv_data = dev_get_drvdata(dev);
+
+       return sprintf(buf, "%d\n", drv_data->in_max[attr->index]);
+}
+
+#define create_voltage_sysfs(idx)                      \
+static SENSOR_DEVICE_ATTR(in##idx##_input, S_IRUGO,    \
+                       show_in, NULL, idx);            \
+static SENSOR_DEVICE_ATTR(in##idx##_min, S_IRUGO,      \
+                       show_min, NULL, idx);           \
+static SENSOR_DEVICE_ATTR(in##idx##_max, S_IRUGO,      \
+                       show_max, NULL, idx);           \
+static SENSOR_DEVICE_ATTR(in##idx##_label, S_IRUGO,    \
+                       show_label, NULL, idx);
+
+create_voltage_sysfs(0);
+create_voltage_sysfs(1);
+create_voltage_sysfs(2);
+create_voltage_sysfs(3);
+create_voltage_sysfs(4);
+
+static struct attribute *menf21bmc_hwmon_attrs[] = {
+       &sensor_dev_attr_in0_input.dev_attr.attr,
+       &sensor_dev_attr_in0_min.dev_attr.attr,
+       &sensor_dev_attr_in0_max.dev_attr.attr,
+       &sensor_dev_attr_in0_label.dev_attr.attr,
+
+       &sensor_dev_attr_in1_input.dev_attr.attr,
+       &sensor_dev_attr_in1_min.dev_attr.attr,
+       &sensor_dev_attr_in1_max.dev_attr.attr,
+       &sensor_dev_attr_in1_label.dev_attr.attr,
+
+       &sensor_dev_attr_in2_input.dev_attr.attr,
+       &sensor_dev_attr_in2_min.dev_attr.attr,
+       &sensor_dev_attr_in2_max.dev_attr.attr,
+       &sensor_dev_attr_in2_label.dev_attr.attr,
+
+       &sensor_dev_attr_in3_input.dev_attr.attr,
+       &sensor_dev_attr_in3_min.dev_attr.attr,
+       &sensor_dev_attr_in3_max.dev_attr.attr,
+       &sensor_dev_attr_in3_label.dev_attr.attr,
+
+       &sensor_dev_attr_in4_input.dev_attr.attr,
+       &sensor_dev_attr_in4_min.dev_attr.attr,
+       &sensor_dev_attr_in4_max.dev_attr.attr,
+       &sensor_dev_attr_in4_label.dev_attr.attr,
+       NULL
+};
+
+ATTRIBUTE_GROUPS(menf21bmc_hwmon);
+
+static int menf21bmc_hwmon_probe(struct platform_device *pdev)
+{
+       int ret;
+       struct menf21bmc_hwmon *drv_data;
+       struct i2c_client *i2c_client = to_i2c_client(pdev->dev.parent);
+       struct device *hwmon_dev;
+
+       drv_data = devm_kzalloc(&pdev->dev, sizeof(struct menf21bmc_hwmon),
+                               GFP_KERNEL);
+       if (!drv_data)
+               return -ENOMEM;
+
+       drv_data->i2c_client = i2c_client;
+
+       ret = menf21bmc_hwmon_get_volt_limits(drv_data);
+       if (ret) {
+               dev_err(&pdev->dev, "failed to read sensor limits");
+               return ret;
+       }
+
+       hwmon_dev = devm_hwmon_device_register_with_groups(&pdev->dev,
+                                                  "menf21bmc", drv_data,
+                                                  menf21bmc_hwmon_groups);
+       if (IS_ERR(hwmon_dev))
+               return PTR_ERR(hwmon_dev);
+
+       dev_info(&pdev->dev, "MEN 14F021P00 BMC hwmon device enabled");
+
+       return 0;
+}
+
+static struct platform_driver menf21bmc_hwmon = {
+       .probe          = menf21bmc_hwmon_probe,
+       .driver         = {
+               .name           = DRV_NAME,
+               .owner          = THIS_MODULE,
+       },
+};
+
+module_platform_driver(menf21bmc_hwmon);
+
+MODULE_AUTHOR("Andreas Werner <andreas.werner@men.de>");
+MODULE_DESCRIPTION("MEN 14F021P00 BMC hwmon");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:menf21bmc_hwmon");
index bd410722cd4bacef0eae6401e5c12f044dd94102..4ff89b2482e48ae12a4f48d2dd269613e1f2c58b 100644 (file)
@@ -38,6 +38,7 @@
 
 #include <linux/hwmon.h>
 #include <linux/hwmon-sysfs.h>
+#include <linux/thermal.h>
 
 struct ntc_compensation {
        int             temp_c;
@@ -182,6 +183,7 @@ struct ntc_data {
        struct device *dev;
        int n_comp;
        char name[PLATFORM_NAME_SIZE];
+       struct thermal_zone_device *tz;
 };
 
 #if defined(CONFIG_OF) && IS_ENABLED(CONFIG_IIO)
@@ -428,6 +430,20 @@ static int ntc_thermistor_get_ohm(struct ntc_data *data)
        return -EINVAL;
 }
 
+static int ntc_read_temp(void *dev, long *temp)
+{
+       struct ntc_data *data = dev_get_drvdata(dev);
+       int ohm;
+
+       ohm = ntc_thermistor_get_ohm(data);
+       if (ohm < 0)
+               return ohm;
+
+       *temp = get_temp_mc(data, ohm);
+
+       return 0;
+}
+
 static ssize_t ntc_show_name(struct device *dev,
                struct device_attribute *attr, char *buf)
 {
@@ -562,6 +578,13 @@ static int ntc_thermistor_probe(struct platform_device *pdev)
        dev_info(&pdev->dev, "Thermistor type: %s successfully probed.\n",
                                                                pdev_id->name);
 
+       data->tz = thermal_zone_of_sensor_register(data->dev, 0, data->dev,
+                                               ntc_read_temp, NULL);
+       if (IS_ERR(data->tz)) {
+               dev_dbg(&pdev->dev, "Failed to register to thermal fw.\n");
+               data->tz = NULL;
+       }
+
        return 0;
 err_after_sysfs:
        sysfs_remove_group(&data->dev->kobj, &ntc_attr_group);
@@ -578,6 +601,8 @@ static int ntc_thermistor_remove(struct platform_device *pdev)
        sysfs_remove_group(&data->dev->kobj, &ntc_attr_group);
        ntc_iio_channel_release(pdata);
 
+       thermal_zone_of_sensor_unregister(data->dev, data->tz);
+
        return 0;
 }
 
index bd89e87bd6ae3297b655609e92f6e1f62c98afbf..221f0931bf1c26af626a6720085b5a0460a6540f 100644 (file)
@@ -100,8 +100,6 @@ static u8 smsc47b397_reg_temp[] = {0x25, 0x26, 0x27, 0x80};
 
 struct smsc47b397_data {
        unsigned short addr;
-       const char *name;
-       struct device *hwmon_dev;
        struct mutex lock;
 
        struct mutex update_lock;
@@ -202,15 +200,7 @@ static SENSOR_DEVICE_ATTR(fan2_input, S_IRUGO, show_fan, NULL, 1);
 static SENSOR_DEVICE_ATTR(fan3_input, S_IRUGO, show_fan, NULL, 2);
 static SENSOR_DEVICE_ATTR(fan4_input, S_IRUGO, show_fan, NULL, 3);
 
-static ssize_t show_name(struct device *dev, struct device_attribute
-                        *devattr, char *buf)
-{
-       struct smsc47b397_data *data = dev_get_drvdata(dev);
-       return sprintf(buf, "%s\n", data->name);
-}
-static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
-
-static struct attribute *smsc47b397_attributes[] = {
+static struct attribute *smsc47b397_attrs[] = {
        &sensor_dev_attr_temp1_input.dev_attr.attr,
        &sensor_dev_attr_temp2_input.dev_attr.attr,
        &sensor_dev_attr_temp3_input.dev_attr.attr,
@@ -220,23 +210,10 @@ static struct attribute *smsc47b397_attributes[] = {
        &sensor_dev_attr_fan3_input.dev_attr.attr,
        &sensor_dev_attr_fan4_input.dev_attr.attr,
 
-       &dev_attr_name.attr,
        NULL
 };
 
-static const struct attribute_group smsc47b397_group = {
-       .attrs = smsc47b397_attributes,
-};
-
-static int smsc47b397_remove(struct platform_device *pdev)
-{
-       struct smsc47b397_data *data = platform_get_drvdata(pdev);
-
-       hwmon_device_unregister(data->hwmon_dev);
-       sysfs_remove_group(&pdev->dev.kobj, &smsc47b397_group);
-
-       return 0;
-}
+ATTRIBUTE_GROUPS(smsc47b397);
 
 static int smsc47b397_probe(struct platform_device *pdev);
 
@@ -246,15 +223,14 @@ static struct platform_driver smsc47b397_driver = {
                .name   = DRVNAME,
        },
        .probe          = smsc47b397_probe,
-       .remove         = smsc47b397_remove,
 };
 
 static int smsc47b397_probe(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
        struct smsc47b397_data *data;
+       struct device *hwmon_dev;
        struct resource *res;
-       int err = 0;
 
        res = platform_get_resource(pdev, IORESOURCE_IO, 0);
        if (!devm_request_region(dev, res->start, SMSC_EXTENT,
@@ -270,26 +246,13 @@ static int smsc47b397_probe(struct platform_device *pdev)
                return -ENOMEM;
 
        data->addr = res->start;
-       data->name = "smsc47b397";
        mutex_init(&data->lock);
        mutex_init(&data->update_lock);
-       platform_set_drvdata(pdev, data);
-
-       err = sysfs_create_group(&dev->kobj, &smsc47b397_group);
-       if (err)
-               return err;
 
-       data->hwmon_dev = hwmon_device_register(dev);
-       if (IS_ERR(data->hwmon_dev)) {
-               err = PTR_ERR(data->hwmon_dev);
-               goto error_remove;
-       }
-
-       return 0;
-
-error_remove:
-       sysfs_remove_group(&dev->kobj, &smsc47b397_group);
-       return err;
+       hwmon_dev = devm_hwmon_device_register_with_groups(dev, "smsc47b397",
+                                                          data,
+                                                          smsc47b397_groups);
+       return PTR_ERR_OR_ZERO(hwmon_dev);
 }
 
 static int __init smsc47b397_device_add(unsigned short address)
index e0c404bdc4a8333d60cef68189e8d2513d7ccc1a..4977082e081f2303542d34ef230c5d199b2b2f31 100644 (file)
@@ -82,7 +82,6 @@ static int create_file(const char *name, umode_t mode,
 {
        int error;
 
-       *dentry = NULL;
        mutex_lock(&parent->d_inode->i_mutex);
        *dentry = lookup_one_len(name, parent, strlen(name));
        if (!IS_ERR(*dentry))
index cab610ccd50e3d2cdf5efaf220dfd8ad5a95cc06..81854586c081fee37e0b3933a26d08e5e8b4e815 100644 (file)
@@ -89,7 +89,6 @@ static int create_file(const char *name, umode_t mode,
 {
        int error;
 
-       *dentry = NULL;
        mutex_lock(&parent->d_inode->i_mutex);
        *dentry = lookup_one_len(name, parent, strlen(name));
        if (!IS_ERR(*dentry))
index d28a8c284da90d57092577f648964d7bdb5731d1..7206547c13ce0dc8dda59458658d843d64520327 100644 (file)
@@ -3574,7 +3574,7 @@ static int srpt_parse_i_port_id(u8 i_port_id[16], const char *name)
        int ret, rc;
 
        p = name;
-       if (strnicmp(p, "0x", 2) == 0)
+       if (strncasecmp(p, "0x", 2) == 0)
                p += 2;
        ret = -EINVAL;
        len = strlen(p);
index fbfdc10573be00bd471b440be7860b24f261caaa..1af28b06c713b80aafc1edbf6ff31cc49d5a5fe5 100644 (file)
@@ -365,12 +365,13 @@ static const struct xenbus_device_id xenkbd_ids[] = {
        { "" }
 };
 
-static DEFINE_XENBUS_DRIVER(xenkbd, ,
+static struct xenbus_driver xenkbd_driver = {
+       .ids = xenkbd_ids,
        .probe = xenkbd_probe,
        .remove = xenkbd_remove,
        .resume = xenkbd_resume,
        .otherend_changed = xenkbd_backend_changed,
-);
+};
 
 static int __init xenkbd_init(void)
 {
index 8857d5b9be71dc03d4494562383fc76c779003ef..ee3434f1e949200ba9224669dd3a1c68045ad557 100644 (file)
@@ -812,7 +812,7 @@ static int edt_ft5x06_ts_identify(struct i2c_client *client,
        /* if we find something consistent, stay with that assumption
         * at least M09 won't send 3 bytes here
         */
-       if (!(strnicmp(rdbuf + 1, "EP0", 3))) {
+       if (!(strncasecmp(rdbuf + 1, "EP0", 3))) {
                tsdata->version = M06;
 
                /* remove last '$' end marker */
index 90e108f9e22ee29b04c94da98d74460eac4a7ff6..a210338cfeb182f6cb255041a0a120db7bafdce6 100644 (file)
@@ -468,6 +468,15 @@ config LEDS_OT200
          This option enables support for the LEDs on the Bachmann OT200.
          Say Y to enable LEDs on the Bachmann OT200.
 
+config LEDS_MENF21BMC
+       tristate "LED support for the MEN 14F021P00 BMC"
+       depends on LEDS_CLASS && MFD_MENF21BMC
+       help
+         Say Y here to include support for the MEN 14F021P00 BMC LEDs.
+
+         This driver can also be built as a module. If so the module
+         will be called leds-menf21bmc.
+
 comment "LED driver for blink(1) USB RGB LED is under Special HID drivers (HID_THINGM)"
 
 config LEDS_BLINKM
index 822dd83ef97a7c904439d42b66ebd07049497f0b..a2b1647414655a8e3ec69a7e82eb8e26e8ba72eb 100644 (file)
@@ -55,6 +55,7 @@ obj-$(CONFIG_LEDS_LM355x)             += leds-lm355x.o
 obj-$(CONFIG_LEDS_BLINKM)              += leds-blinkm.o
 obj-$(CONFIG_LEDS_SYSCON)              += leds-syscon.o
 obj-$(CONFIG_LEDS_VERSATILE)           += leds-versatile.o
+obj-$(CONFIG_LEDS_MENF21BMC)           += leds-menf21bmc.o
 
 # LED SPI Drivers
 obj-$(CONFIG_LEDS_DAC124S085)          += leds-dac124s085.o
diff --git a/drivers/leds/leds-menf21bmc.c b/drivers/leds/leds-menf21bmc.c
new file mode 100644 (file)
index 0000000..89dd577
--- /dev/null
@@ -0,0 +1,131 @@
+/*
+ *  MEN 14F021P00 Board Management Controller (BMC) LEDs Driver.
+ *
+ *  This is the core LED driver of the MEN 14F021P00 BMC.
+ *  There are four LEDs available which can be switched on and off.
+ *  STATUS LED, HOT SWAP LED, USER LED 1, USER LED 2
+ *
+ *  Copyright (C) 2014 MEN Mikro Elektronik Nuernberg GmbH
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/leds.h>
+#include <linux/i2c.h>
+
+#define BMC_CMD_LED_GET_SET    0xA0
+#define BMC_BIT_LED_STATUS     BIT(0)
+#define BMC_BIT_LED_HOTSWAP    BIT(1)
+#define BMC_BIT_LED_USER1      BIT(2)
+#define BMC_BIT_LED_USER2      BIT(3)
+
+struct menf21bmc_led {
+       struct led_classdev cdev;
+       u8 led_bit;
+       const char *name;
+       struct i2c_client *i2c_client;
+};
+
+static struct menf21bmc_led leds[] = {
+       {
+               .name = "menf21bmc:led_status",
+               .led_bit = BMC_BIT_LED_STATUS,
+       },
+       {
+               .name = "menf21bmc:led_hotswap",
+               .led_bit = BMC_BIT_LED_HOTSWAP,
+       },
+       {
+               .name = "menf21bmc:led_user1",
+               .led_bit = BMC_BIT_LED_USER1,
+       },
+       {
+               .name = "menf21bmc:led_user2",
+               .led_bit = BMC_BIT_LED_USER2,
+       }
+};
+
+static DEFINE_MUTEX(led_lock);
+
+static void
+menf21bmc_led_set(struct led_classdev *led_cdev, enum led_brightness value)
+{
+       int led_val;
+       struct menf21bmc_led *led = container_of(led_cdev,
+                                       struct menf21bmc_led, cdev);
+
+       mutex_lock(&led_lock);
+       led_val = i2c_smbus_read_byte_data(led->i2c_client,
+                                          BMC_CMD_LED_GET_SET);
+       if (led_val < 0)
+               goto err_out;
+
+       if (value == LED_OFF)
+               led_val &= ~led->led_bit;
+       else
+               led_val |= led->led_bit;
+
+       i2c_smbus_write_byte_data(led->i2c_client,
+                                 BMC_CMD_LED_GET_SET, led_val);
+err_out:
+       mutex_unlock(&led_lock);
+}
+
+static int menf21bmc_led_probe(struct platform_device *pdev)
+{
+       int i;
+       int ret;
+       struct i2c_client *i2c_client = to_i2c_client(pdev->dev.parent);
+
+       for (i = 0; i < ARRAY_SIZE(leds); i++) {
+               leds[i].cdev.name = leds[i].name;
+               leds[i].cdev.brightness_set = menf21bmc_led_set;
+               leds[i].i2c_client = i2c_client;
+               ret = led_classdev_register(&pdev->dev, &leds[i].cdev);
+               if (ret < 0)
+                       goto err_free_leds;
+       }
+       dev_info(&pdev->dev, "MEN 140F21P00 BMC LED device enabled\n");
+
+       return 0;
+
+err_free_leds:
+       dev_err(&pdev->dev, "failed to register LED device\n");
+
+       for (i = i - 1; i >= 0; i--)
+               led_classdev_unregister(&leds[i].cdev);
+
+       return ret;
+}
+
+static int menf21bmc_led_remove(struct platform_device *pdev)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(leds); i++)
+               led_classdev_unregister(&leds[i].cdev);
+
+       return 0;
+}
+
+static struct platform_driver menf21bmc_led = {
+       .probe          = menf21bmc_led_probe,
+       .remove         = menf21bmc_led_remove,
+       .driver         = {
+               .name           = "menf21bmc_led",
+               .owner          = THIS_MODULE,
+       },
+};
+
+module_platform_driver(menf21bmc_led);
+
+MODULE_AUTHOR("Andreas Werner <andreas.werner@men.de>");
+MODULE_DESCRIPTION("MEN 14F021P00 BMC led driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:menf21bmc_led");
index 9e9c56758a0897ab5c7e7b0dfc14ac690e1bb043..226179b975a04eade83480bf94adad14c3b8373e 100644 (file)
@@ -411,6 +411,7 @@ adb_poll(void)
                return;
        adb_controller->poll();
 }
+EXPORT_SYMBOL(adb_poll);
 
 static void adb_sync_req_done(struct adb_request *req)
 {
@@ -460,6 +461,7 @@ adb_request(struct adb_request *req, void (*done)(struct adb_request *),
 
        return rc;
 }
+EXPORT_SYMBOL(adb_request);
 
  /* Ultimately this should return the number of devices with
     the given default id.
@@ -495,6 +497,7 @@ adb_register(int default_id, int handler_id, struct adb_ids *ids,
        mutex_unlock(&adb_handler_mutex);
        return ids->nids;
 }
+EXPORT_SYMBOL(adb_register);
 
 int
 adb_unregister(int index)
@@ -516,6 +519,7 @@ adb_unregister(int index)
        mutex_unlock(&adb_handler_mutex);
        return ret;
 }
+EXPORT_SYMBOL(adb_unregister);
 
 void
 adb_input(unsigned char *buf, int nb, int autopoll)
@@ -582,6 +586,7 @@ adb_try_handler_change(int address, int new_id)
        mutex_unlock(&adb_handler_mutex);
        return ret;
 }
+EXPORT_SYMBOL(adb_try_handler_change);
 
 int
 adb_get_infos(int address, int *original_address, int *handler_id)
index d61f271d22078ac13166e49a79d9c03c94d5f71c..bad18130f125f94fc23281e3edbcade0b39871d1 100644 (file)
@@ -379,6 +379,7 @@ cuda_request(struct adb_request *req, void (*done)(struct adb_request *),
     req->reply_expected = 1;
     return cuda_write(req);
 }
+EXPORT_SYMBOL(cuda_request);
 
 static int
 cuda_write(struct adb_request *req)
@@ -441,6 +442,7 @@ cuda_poll(void)
     if (cuda_irq)
        enable_irq(cuda_irq);
 }
+EXPORT_SYMBOL(cuda_poll);
 
 static irqreturn_t
 cuda_interrupt(int irq, void *arg)
index ab472c557d18c060d8230bbfcadbd747b36f0fd0..0505559f0965abb6cd5ce459034eb2ee31800d56 100644 (file)
@@ -720,7 +720,6 @@ static void __wait_for_free_buffer(struct dm_bufio_client *c)
 
        io_schedule();
 
-       set_task_state(current, TASK_RUNNING);
        remove_wait_queue(&c->free_buffer_wait, &wait);
 
        dm_bufio_lock(c);
index 897b10c85ad9273b75b9cb911b2f0c2853b9a167..8942bdacbf61befba5640d845d95d00e566cbc42 100644 (file)
@@ -4,7 +4,7 @@
  * see flexcop.c for copyright information
  */
 #ifndef __FLEXCOP_H__
-#define __FLEXCOP_H___
+#define __FLEXCOP_H__
 
 #define FC_LOG_PREFIX "b2c2-flexcop"
 #include "flexcop-common.h"
index 6c47f3fe9b0fc2ba2f8eb9263a2f0e9d0396d870..b7d63933dae61a6adbac2d95edfe1bb19c6aacf1 100644 (file)
@@ -311,7 +311,6 @@ static int fops_mmap(struct file *file, struct vm_area_struct * vma)
                }
        default:
                BUG();
-               return 0;
        }
 
        if (mutex_lock_interruptible(vdev->lock))
@@ -399,7 +398,6 @@ static ssize_t fops_read(struct file *file, char __user *data, size_t count, lof
                return -EINVAL;
        default:
                BUG();
-               return 0;
        }
 }
 
@@ -423,7 +421,6 @@ static ssize_t fops_write(struct file *file, const char __user *data, size_t cou
                return -EINVAL;
        default:
                BUG();
-               return -EINVAL;
        }
 }
 
index 82769993eeb7b390cc5441cffc9bf5096b6411a9..82c7a1289f053313bb7f866bb08a9288e2a67db6 100644 (file)
@@ -157,6 +157,12 @@ static struct sms_board sms_boards[] = {
                .type = SMS_DENVER_2160,
                .default_mode = DEVICE_MODE_DAB_TDMB,
        },
+       [SMS1XXX_BOARD_PCTV_77E] = {
+               .name   = "Hauppauge microStick 77e",
+               .type   = SMS_NOVA_B0,
+               .fw[DEVICE_MODE_DVBT_BDA] = SMS_FW_DVB_NOVA_12MHZ_B0,
+               .default_mode = DEVICE_MODE_DVBT_BDA,
+       },
 };
 
 struct sms_board *sms_get_board(unsigned id)
index c63b544c49c5b721769131d8065f044eebd76e91..4c4caddf986984e2aa94ce2da8bf7f1229718767 100644 (file)
@@ -45,6 +45,7 @@
 #define SMS1XXX_BOARD_SIANO_RIO                18
 #define SMS1XXX_BOARD_SIANO_DENVER_1530        19
 #define SMS1XXX_BOARD_SIANO_DENVER_2160 20
+#define SMS1XXX_BOARD_PCTV_77E         21
 
 struct sms_board_gpio_cfg {
        int lna_vhf_exist;
index 050984c5b1e3701aa00ea0d074bca9700754d9d3..a3677438205e8c88824e6f10f854168755725da9 100644 (file)
@@ -2129,8 +2129,6 @@ int smscore_gpio_get_level(struct smscore_device_t *coredev, u8 pin_num,
 
 static int __init smscore_module_init(void)
 {
-       int rc = 0;
-
        INIT_LIST_HEAD(&g_smscore_notifyees);
        INIT_LIST_HEAD(&g_smscore_devices);
        kmutex_init(&g_smscore_deviceslock);
@@ -2138,7 +2136,7 @@ static int __init smscore_module_init(void)
        INIT_LIST_HEAD(&g_smscore_registry);
        kmutex_init(&g_smscore_registrylock);
 
-       return rc;
+       return 0;
 }
 
 static void __exit smscore_module_exit(void)
index c0363f1b6c90e06c34409766e4a69c56fb98164f..abff803ad69a7e9e55818e5fd42d04ff475cd2d5 100644 (file)
@@ -1087,8 +1087,8 @@ static unsigned int dvb_demux_poll(struct file *file, poll_table *wait)
        struct dmxdev_filter *dmxdevfilter = file->private_data;
        unsigned int mask = 0;
 
-       if (!dmxdevfilter)
-               return -EINVAL;
+       if ((!dmxdevfilter) || dmxdevfilter->dev->exit)
+               return POLLERR;
 
        poll_wait(file, &dmxdevfilter->buffer.queue, wait);
 
@@ -1181,6 +1181,9 @@ static unsigned int dvb_dvr_poll(struct file *file, poll_table *wait)
 
        dprintk("function : %s\n", __func__);
 
+       if (dmxdev->exit)
+               return POLLERR;
+
        poll_wait(file, &dmxdev->dvr_buffer.queue, wait);
 
        if ((file->f_flags & O_ACCMODE) == O_RDONLY) {
index 12ce19c98ded144bc37da6d7498edb5381b0d5ee..e07a84e7bc56d494ac795895b1b0a2ca4682bb2d 100644 (file)
 #define USB_PID_ITETECH_IT9135                         0x9135
 #define USB_PID_ITETECH_IT9135_9005                    0x9005
 #define USB_PID_ITETECH_IT9135_9006                    0x9006
+#define USB_PID_ITETECH_IT9303                         0x9306
 #define USB_PID_KWORLD_399U                            0xe399
 #define USB_PID_KWORLD_399U_2                          0xe400
 #define USB_PID_KWORLD_395U                            0xe396
 #define USB_PID_TECHNOTREND_CONNECT_S2400               0x3006
 #define USB_PID_TECHNOTREND_CONNECT_S2400_8KEEPROM     0x3009
 #define USB_PID_TECHNOTREND_CONNECT_CT3650             0x300d
+#define USB_PID_TECHNOTREND_CONNECT_CT2_4650_CI                0x3012
 #define USB_PID_TECHNOTREND_TVSTICK_CT2_4400           0x3014
 #define USB_PID_TERRATEC_CINERGY_DT_XS_DIVERSITY       0x005a
 #define USB_PID_TERRATEC_CINERGY_DT_XS_DIVERSITY_2     0x0081
index c2a6a0a858130b4db284ca845134656afcffc2f0..b8579ee68bd603567fa8a8827b279683f00a7928 100644 (file)
@@ -1934,15 +1934,13 @@ static int dvb_frontend_ioctl_properties(struct file *file,
        struct dtv_frontend_properties *c = &fe->dtv_property_cache;
        int err = 0;
 
-       struct dtv_properties *tvps = NULL;
+       struct dtv_properties *tvps = parg;
        struct dtv_property *tvp = NULL;
        int i;
 
        dev_dbg(fe->dvb->device, "%s:\n", __func__);
 
-       if(cmd == FE_SET_PROPERTY) {
-               tvps = (struct dtv_properties __user *)parg;
-
+       if (cmd == FE_SET_PROPERTY) {
                dev_dbg(fe->dvb->device, "%s: properties.num = %d\n", __func__, tvps->num);
                dev_dbg(fe->dvb->device, "%s: properties.props = %p\n", __func__, tvps->props);
 
@@ -1957,7 +1955,8 @@ static int dvb_frontend_ioctl_properties(struct file *file,
                        goto out;
                }
 
-               if (copy_from_user(tvp, tvps->props, tvps->num * sizeof(struct dtv_property))) {
+               if (copy_from_user(tvp, (void __user *)tvps->props,
+                                  tvps->num * sizeof(struct dtv_property))) {
                        err = -EFAULT;
                        goto out;
                }
@@ -1972,10 +1971,7 @@ static int dvb_frontend_ioctl_properties(struct file *file,
                if (c->state == DTV_TUNE)
                        dev_dbg(fe->dvb->device, "%s: Property cache is full, tuning\n", __func__);
 
-       } else
-       if(cmd == FE_GET_PROPERTY) {
-               tvps = (struct dtv_properties __user *)parg;
-
+       } else if (cmd == FE_GET_PROPERTY) {
                dev_dbg(fe->dvb->device, "%s: properties.num = %d\n", __func__, tvps->num);
                dev_dbg(fe->dvb->device, "%s: properties.props = %p\n", __func__, tvps->props);
 
@@ -1990,7 +1986,8 @@ static int dvb_frontend_ioctl_properties(struct file *file,
                        goto out;
                }
 
-               if (copy_from_user(tvp, tvps->props, tvps->num * sizeof(struct dtv_property))) {
+               if (copy_from_user(tvp, (void __user *)tvps->props,
+                                  tvps->num * sizeof(struct dtv_property))) {
                        err = -EFAULT;
                        goto out;
                }
@@ -2012,7 +2009,8 @@ static int dvb_frontend_ioctl_properties(struct file *file,
                        (tvp + i)->result = err;
                }
 
-               if (copy_to_user(tvps->props, tvp, tvps->num * sizeof(struct dtv_property))) {
+               if (copy_to_user((void __user *)tvps->props, tvp,
+                                tvps->num * sizeof(struct dtv_property))) {
                        err = -EFAULT;
                        goto out;
                }
@@ -2072,6 +2070,23 @@ static int dtv_set_frontend(struct dvb_frontend *fe)
        case SYS_DVBC_ANNEX_C:
                rolloff = 113;
                break;
+       case SYS_DVBS:
+       case SYS_TURBO:
+               rolloff = 135;
+               break;
+       case SYS_DVBS2:
+               switch (c->rolloff) {
+               case ROLLOFF_20:
+                       rolloff = 120;
+                       break;
+               case ROLLOFF_25:
+                       rolloff = 125;
+                       break;
+               default:
+               case ROLLOFF_35:
+                       rolloff = 135;
+               }
+               break;
        default:
                break;
        }
@@ -2550,7 +2565,9 @@ int dvb_frontend_suspend(struct dvb_frontend *fe)
        dev_dbg(fe->dvb->device, "%s: adap=%d fe=%d\n", __func__, fe->dvb->num,
                        fe->id);
 
-       if (fe->ops.tuner_ops.sleep)
+       if (fe->ops.tuner_ops.suspend)
+               ret = fe->ops.tuner_ops.suspend(fe);
+       else if (fe->ops.tuner_ops.sleep)
                ret = fe->ops.tuner_ops.sleep(fe);
 
        if (fe->ops.sleep)
@@ -2572,7 +2589,9 @@ int dvb_frontend_resume(struct dvb_frontend *fe)
        if (fe->ops.init)
                ret = fe->ops.init(fe);
 
-       if (fe->ops.tuner_ops.init)
+       if (fe->ops.tuner_ops.resume)
+               ret = fe->ops.tuner_ops.resume(fe);
+       else if (fe->ops.tuner_ops.init)
                ret = fe->ops.tuner_ops.init(fe);
 
        fe->exit = DVB_FE_NO_EXIT;
index d398de4b6ef468cb7639ed8ce649ea0c4869291c..816269e5f7068b639a852651f4ad16817aea80a1 100644 (file)
@@ -201,6 +201,8 @@ struct dvb_tuner_ops {
        int (*release)(struct dvb_frontend *fe);
        int (*init)(struct dvb_frontend *fe);
        int (*sleep)(struct dvb_frontend *fe);
+       int (*suspend)(struct dvb_frontend *fe);
+       int (*resume)(struct dvb_frontend *fe);
 
        /** This is for simple PLLs - set all parameters in one go. */
        int (*set_params)(struct dvb_frontend *fe);
index a5712cd7c65ff084845cc86599d63f802ac81722..1100e98a7b1d36eaefe4440767d823d49d1ebf3b 100644 (file)
@@ -166,6 +166,31 @@ ssize_t dvb_ringbuffer_write(struct dvb_ringbuffer *rbuf, const u8 *buf, size_t
        return len;
 }
 
+ssize_t dvb_ringbuffer_write_user(struct dvb_ringbuffer *rbuf,
+                                 const u8 __user *buf, size_t len)
+{
+       int status;
+       size_t todo = len;
+       size_t split;
+
+       split = (rbuf->pwrite + len > rbuf->size) ? rbuf->size - rbuf->pwrite : 0;
+
+       if (split > 0) {
+               status = copy_from_user(rbuf->data+rbuf->pwrite, buf, split);
+               if (status)
+                       return len - todo;
+               buf += split;
+               todo -= split;
+               rbuf->pwrite = 0;
+       }
+       status = copy_from_user(rbuf->data+rbuf->pwrite, buf, todo);
+       if (status)
+               return len - todo;
+       rbuf->pwrite = (rbuf->pwrite + todo) % rbuf->size;
+
+       return len;
+}
+
 ssize_t dvb_ringbuffer_pkt_write(struct dvb_ringbuffer *rbuf, u8* buf, size_t len)
 {
        int status;
@@ -297,3 +322,4 @@ EXPORT_SYMBOL(dvb_ringbuffer_flush_spinlock_wakeup);
 EXPORT_SYMBOL(dvb_ringbuffer_read_user);
 EXPORT_SYMBOL(dvb_ringbuffer_read);
 EXPORT_SYMBOL(dvb_ringbuffer_write);
+EXPORT_SYMBOL(dvb_ringbuffer_write_user);
index 41f04dae69b618badd91e783a1ad463b6bd0a393..9e1e11b7c39cb24113084234537cdf4c82254002 100644 (file)
@@ -133,6 +133,8 @@ extern void dvb_ringbuffer_read(struct dvb_ringbuffer *rbuf,
 */
 extern ssize_t dvb_ringbuffer_write(struct dvb_ringbuffer *rbuf, const u8 *buf,
                                    size_t len);
+extern ssize_t dvb_ringbuffer_write_user(struct dvb_ringbuffer *rbuf,
+                                        const u8 __user *buf, size_t len);
 
 
 /**
index fe0ddcca192c0f33f0bb7c3224bf0954b9fb5a35..5a134547e32579c3c6c59668c90986599982e82f 100644 (file)
@@ -471,6 +471,11 @@ config DVB_SI2168
        help
          Say Y when you want to support this frontend.
 
+config DVB_AS102_FE
+       tristate
+       depends on DVB_CORE
+       default DVB_AS102
+
 comment "DVB-C (cable) frontends"
        depends on DVB_CORE
 
@@ -643,6 +648,14 @@ config DVB_MB86A20S
          A driver for Fujitsu mb86a20s ISDB-T/ISDB-Tsb demodulator.
          Say Y when you want to support this frontend.
 
+config DVB_TC90522
+       tristate "Toshiba TC90522"
+       depends on DVB_CORE && I2C
+       default m if !MEDIA_SUBDRV_AUTOSELECT
+       help
+         A Toshiba TC90522 2xISDB-T + 2xISDB-S demodulator.
+         Say Y when you want to support this frontend.
+
 comment "Digital terrestrial only tuners/PLL"
        depends on DVB_CORE
 
@@ -720,6 +733,13 @@ config DVB_A8293
        depends on DVB_CORE && I2C
        default m if !MEDIA_SUBDRV_AUTOSELECT
 
+config DVB_SP2
+       tristate "CIMaX SP2"
+       depends on DVB_CORE && I2C
+       default m if !MEDIA_SUBDRV_AUTOSELECT
+       help
+         CIMaX SP2/SP2HF Common Interface module.
+
 config DVB_LGS8GL5
        tristate "Silicon Legend LGS-8GL5 demodulator (OFDM)"
        depends on DVB_CORE && I2C
index edf103d45920238df61e41917fb64126f9983eb1..ba59df63d05082062ca03bb2f4ca6ffe2418e7b0 100644 (file)
@@ -107,10 +107,12 @@ obj-$(CONFIG_DVB_DRXK) += drxk.o
 obj-$(CONFIG_DVB_TDA18271C2DD) += tda18271c2dd.o
 obj-$(CONFIG_DVB_SI2165) += si2165.o
 obj-$(CONFIG_DVB_A8293) += a8293.o
+obj-$(CONFIG_DVB_SP2) += sp2.o
 obj-$(CONFIG_DVB_TDA10071) += tda10071.o
 obj-$(CONFIG_DVB_RTL2830) += rtl2830.o
 obj-$(CONFIG_DVB_RTL2832) += rtl2832.o
 obj-$(CONFIG_DVB_RTL2832_SDR) += rtl2832_sdr.o
 obj-$(CONFIG_DVB_M88RS2000) += m88rs2000.o
 obj-$(CONFIG_DVB_AF9033) += af9033.o
-
+obj-$(CONFIG_DVB_AS102_FE) += as102_fe.o
+obj-$(CONFIG_DVB_TC90522) += tc90522.o
index ecf6388d2200608bd5d4f5327d7349e55a0ad6ed..8001690d7576c21579db9f0a8ac08846a5981328 100644 (file)
@@ -683,7 +683,7 @@ static int af9013_set_frontend(struct dvb_frontend *fe)
 
        switch (c->transmission_mode) {
        case TRANSMISSION_MODE_AUTO:
-               auto_mode = 1;
+               auto_mode = true;
                break;
        case TRANSMISSION_MODE_2K:
                break;
@@ -693,12 +693,12 @@ static int af9013_set_frontend(struct dvb_frontend *fe)
        default:
                dev_dbg(&state->i2c->dev, "%s: invalid transmission_mode\n",
                                __func__);
-               auto_mode = 1;
+               auto_mode = true;
        }
 
        switch (c->guard_interval) {
        case GUARD_INTERVAL_AUTO:
-               auto_mode = 1;
+               auto_mode = true;
                break;
        case GUARD_INTERVAL_1_32:
                break;
@@ -714,12 +714,12 @@ static int af9013_set_frontend(struct dvb_frontend *fe)
        default:
                dev_dbg(&state->i2c->dev, "%s: invalid guard_interval\n",
                                __func__);
-               auto_mode = 1;
+               auto_mode = true;
        }
 
        switch (c->hierarchy) {
        case HIERARCHY_AUTO:
-               auto_mode = 1;
+               auto_mode = true;
                break;
        case HIERARCHY_NONE:
                break;
@@ -734,12 +734,12 @@ static int af9013_set_frontend(struct dvb_frontend *fe)
                break;
        default:
                dev_dbg(&state->i2c->dev, "%s: invalid hierarchy\n", __func__);
-               auto_mode = 1;
+               auto_mode = true;
        }
 
        switch (c->modulation) {
        case QAM_AUTO:
-               auto_mode = 1;
+               auto_mode = true;
                break;
        case QPSK:
                break;
@@ -751,7 +751,7 @@ static int af9013_set_frontend(struct dvb_frontend *fe)
                break;
        default:
                dev_dbg(&state->i2c->dev, "%s: invalid modulation\n", __func__);
-               auto_mode = 1;
+               auto_mode = true;
        }
 
        /* Use HP. How and which case we can switch to LP? */
@@ -759,7 +759,7 @@ static int af9013_set_frontend(struct dvb_frontend *fe)
 
        switch (c->code_rate_HP) {
        case FEC_AUTO:
-               auto_mode = 1;
+               auto_mode = true;
                break;
        case FEC_1_2:
                break;
@@ -778,12 +778,12 @@ static int af9013_set_frontend(struct dvb_frontend *fe)
        default:
                dev_dbg(&state->i2c->dev, "%s: invalid code_rate_HP\n",
                                __func__);
-               auto_mode = 1;
+               auto_mode = true;
        }
 
        switch (c->code_rate_LP) {
        case FEC_AUTO:
-               auto_mode = 1;
+               auto_mode = true;
                break;
        case FEC_1_2:
                break;
@@ -804,7 +804,7 @@ static int af9013_set_frontend(struct dvb_frontend *fe)
        default:
                dev_dbg(&state->i2c->dev, "%s: invalid code_rate_LP\n",
                                __func__);
-               auto_mode = 1;
+               auto_mode = true;
        }
 
        switch (c->bandwidth_hz) {
index 5c90ea683a7e732d3431c8973e43b4ffea649c55..63a89c1c59ff7454293f24604fecbe562cf3cabe 100644 (file)
 /* Max transfer size done by I2C transfer functions */
 #define MAX_XFER_SIZE  64
 
-struct af9033_state {
-       struct i2c_adapter *i2c;
+struct af9033_dev {
+       struct i2c_client *client;
        struct dvb_frontend fe;
        struct af9033_config cfg;
+       bool is_af9035;
+       bool is_it9135;
 
        u32 bandwidth_hz;
        bool ts_mode_parallel;
        bool ts_mode_serial;
 
-       u32 ber;
-       u32 ucb;
-       unsigned long last_stat_check;
+       fe_status_t fe_status;
+       u64 post_bit_error_prev; /* for old read_ber we return (curr - prev) */
+       u64 post_bit_error;
+       u64 post_bit_count;
+       u64 error_block_count;
+       u64 total_block_count;
+       struct delayed_work stat_work;
 };
 
 /* write multiple registers */
-static int af9033_wr_regs(struct af9033_state *state, u32 reg, const u8 *val,
+static int af9033_wr_regs(struct af9033_dev *dev, u32 reg, const u8 *val,
                int len)
 {
        int ret;
        u8 buf[MAX_XFER_SIZE];
        struct i2c_msg msg[1] = {
                {
-                       .addr = state->cfg.i2c_addr,
+                       .addr = dev->client->addr,
                        .flags = 0,
                        .len = 3 + len,
                        .buf = buf,
@@ -54,9 +60,9 @@ static int af9033_wr_regs(struct af9033_state *state, u32 reg, const u8 *val,
        };
 
        if (3 + len > sizeof(buf)) {
-               dev_warn(&state->i2c->dev,
-                        "%s: i2c wr reg=%04x: len=%d is too big!\n",
-                        KBUILD_MODNAME, reg, len);
+               dev_warn(&dev->client->dev,
+                               "i2c wr reg=%04x: len=%d is too big!\n",
+                               reg, len);
                return -EINVAL;
        }
 
@@ -65,12 +71,12 @@ static int af9033_wr_regs(struct af9033_state *state, u32 reg, const u8 *val,
        buf[2] = (reg >>  0) & 0xff;
        memcpy(&buf[3], val, len);
 
-       ret = i2c_transfer(state->i2c, msg, 1);
+       ret = i2c_transfer(dev->client->adapter, msg, 1);
        if (ret == 1) {
                ret = 0;
        } else {
-               dev_warn(&state->i2c->dev, "%s: i2c wr failed=%d reg=%06x " \
-                               "len=%d\n", KBUILD_MODNAME, ret, reg, len);
+               dev_warn(&dev->client->dev, "i2c wr failed=%d reg=%06x len=%d\n",
+                               ret, reg, len);
                ret = -EREMOTEIO;
        }
 
@@ -78,31 +84,31 @@ static int af9033_wr_regs(struct af9033_state *state, u32 reg, const u8 *val,
 }
 
 /* read multiple registers */
-static int af9033_rd_regs(struct af9033_state *state, u32 reg, u8 *val, int len)
+static int af9033_rd_regs(struct af9033_dev *dev, u32 reg, u8 *val, int len)
 {
        int ret;
        u8 buf[3] = { (reg >> 16) & 0xff, (reg >> 8) & 0xff,
                        (reg >> 0) & 0xff };
        struct i2c_msg msg[2] = {
                {
-                       .addr = state->cfg.i2c_addr,
+                       .addr = dev->client->addr,
                        .flags = 0,
                        .len = sizeof(buf),
                        .buf = buf
                }, {
-                       .addr = state->cfg.i2c_addr,
+                       .addr = dev->client->addr,
                        .flags = I2C_M_RD,
                        .len = len,
                        .buf = val
                }
        };
 
-       ret = i2c_transfer(state->i2c, msg, 2);
+       ret = i2c_transfer(dev->client->adapter, msg, 2);
        if (ret == 2) {
                ret = 0;
        } else {
-               dev_warn(&state->i2c->dev, "%s: i2c rd failed=%d reg=%06x " \
-                               "len=%d\n", KBUILD_MODNAME, ret, reg, len);
+               dev_warn(&dev->client->dev, "i2c rd failed=%d reg=%06x len=%d\n",
+                               ret, reg, len);
                ret = -EREMOTEIO;
        }
 
@@ -111,19 +117,19 @@ static int af9033_rd_regs(struct af9033_state *state, u32 reg, u8 *val, int len)
 
 
 /* write single register */
-static int af9033_wr_reg(struct af9033_state *state, u32 reg, u8 val)
+static int af9033_wr_reg(struct af9033_dev *dev, u32 reg, u8 val)
 {
-       return af9033_wr_regs(state, reg, &val, 1);
+       return af9033_wr_regs(dev, reg, &val, 1);
 }
 
 /* read single register */
-static int af9033_rd_reg(struct af9033_state *state, u32 reg, u8 *val)
+static int af9033_rd_reg(struct af9033_dev *dev, u32 reg, u8 *val)
 {
-       return af9033_rd_regs(state, reg, val, 1);
+       return af9033_rd_regs(dev, reg, val, 1);
 }
 
 /* write single register with mask */
-static int af9033_wr_reg_mask(struct af9033_state *state, u32 reg, u8 val,
+static int af9033_wr_reg_mask(struct af9033_dev *dev, u32 reg, u8 val,
                u8 mask)
 {
        int ret;
@@ -131,7 +137,7 @@ static int af9033_wr_reg_mask(struct af9033_state *state, u32 reg, u8 val,
 
        /* no need for read if whole reg is written */
        if (mask != 0xff) {
-               ret = af9033_rd_regs(state, reg, &tmp, 1);
+               ret = af9033_rd_regs(dev, reg, &tmp, 1);
                if (ret)
                        return ret;
 
@@ -140,17 +146,17 @@ static int af9033_wr_reg_mask(struct af9033_state *state, u32 reg, u8 val,
                val |= tmp;
        }
 
-       return af9033_wr_regs(state, reg, &val, 1);
+       return af9033_wr_regs(dev, reg, &val, 1);
 }
 
 /* read single register with mask */
-static int af9033_rd_reg_mask(struct af9033_state *state, u32 reg, u8 *val,
+static int af9033_rd_reg_mask(struct af9033_dev *dev, u32 reg, u8 *val,
                u8 mask)
 {
        int ret, i;
        u8 tmp;
 
-       ret = af9033_rd_regs(state, reg, &tmp, 1);
+       ret = af9033_rd_regs(dev, reg, &tmp, 1);
        if (ret)
                return ret;
 
@@ -167,18 +173,17 @@ static int af9033_rd_reg_mask(struct af9033_state *state, u32 reg, u8 *val,
 }
 
 /* write reg val table using reg addr auto increment */
-static int af9033_wr_reg_val_tab(struct af9033_state *state,
+static int af9033_wr_reg_val_tab(struct af9033_dev *dev,
                const struct reg_val *tab, int tab_len)
 {
 #define MAX_TAB_LEN 212
        int ret, i, j;
        u8 buf[1 + MAX_TAB_LEN];
 
-       dev_dbg(&state->i2c->dev, "%s: tab_len=%d\n", __func__, tab_len);
+       dev_dbg(&dev->client->dev, "tab_len=%d\n", tab_len);
 
        if (tab_len > sizeof(buf)) {
-               dev_warn(&state->i2c->dev, "%s: tab len %d is too big\n",
-                               KBUILD_MODNAME, tab_len);
+               dev_warn(&dev->client->dev, "tab len %d is too big\n", tab_len);
                return -EINVAL;
        }
 
@@ -186,7 +191,7 @@ static int af9033_wr_reg_val_tab(struct af9033_state *state,
                buf[j] = tab[i].val;
 
                if (i == tab_len - 1 || tab[i].reg != tab[i + 1].reg - 1) {
-                       ret = af9033_wr_regs(state, tab[i].reg - j, buf, j + 1);
+                       ret = af9033_wr_regs(dev, tab[i].reg - j, buf, j + 1);
                        if (ret < 0)
                                goto err;
 
@@ -199,16 +204,16 @@ static int af9033_wr_reg_val_tab(struct af9033_state *state,
        return 0;
 
 err:
-       dev_dbg(&state->i2c->dev, "%s: failed=%d\n", __func__, ret);
+       dev_dbg(&dev->client->dev, "failed=%d\n", ret);
 
        return ret;
 }
 
-static u32 af9033_div(struct af9033_state *state, u32 a, u32 b, u32 x)
+static u32 af9033_div(struct af9033_dev *dev, u32 a, u32 b, u32 x)
 {
        u32 r = 0, c = 0, i;
 
-       dev_dbg(&state->i2c->dev, "%s: a=%d b=%d x=%d\n", __func__, a, b, x);
+       dev_dbg(&dev->client->dev, "a=%d b=%d x=%d\n", a, b, x);
 
        if (a > b) {
                c = a / b;
@@ -225,22 +230,15 @@ static u32 af9033_div(struct af9033_state *state, u32 a, u32 b, u32 x)
        }
        r = (c << (u32)x) + r;
 
-       dev_dbg(&state->i2c->dev, "%s: a=%d b=%d x=%d r=%d r=%x\n",
-                       __func__, a, b, x, r, r);
+       dev_dbg(&dev->client->dev, "a=%d b=%d x=%d r=%d r=%x\n", a, b, x, r, r);
 
        return r;
 }
 
-static void af9033_release(struct dvb_frontend *fe)
-{
-       struct af9033_state *state = fe->demodulator_priv;
-
-       kfree(state);
-}
-
 static int af9033_init(struct dvb_frontend *fe)
 {
-       struct af9033_state *state = fe->demodulator_priv;
+       struct af9033_dev *dev = fe->demodulator_priv;
+       struct dtv_frontend_properties *c = &fe->dtv_property_cache;
        int ret, i, len;
        const struct reg_val *init;
        u8 buf[4];
@@ -248,7 +246,7 @@ static int af9033_init(struct dvb_frontend *fe)
        struct reg_val_mask tab[] = {
                { 0x80fb24, 0x00, 0x08 },
                { 0x80004c, 0x00, 0xff },
-               { 0x00f641, state->cfg.tuner, 0xff },
+               { 0x00f641, dev->cfg.tuner, 0xff },
                { 0x80f5ca, 0x01, 0x01 },
                { 0x80f715, 0x01, 0x01 },
                { 0x00f41f, 0x04, 0x04 },
@@ -267,88 +265,82 @@ static int af9033_init(struct dvb_frontend *fe)
                { 0x00d830, 0x01, 0xff },
                { 0x00d831, 0x00, 0xff },
                { 0x00d832, 0x00, 0xff },
-               { 0x80f985, state->ts_mode_serial, 0x01 },
-               { 0x80f986, state->ts_mode_parallel, 0x01 },
+               { 0x80f985, dev->ts_mode_serial, 0x01 },
+               { 0x80f986, dev->ts_mode_parallel, 0x01 },
                { 0x00d827, 0x00, 0xff },
                { 0x00d829, 0x00, 0xff },
-               { 0x800045, state->cfg.adc_multiplier, 0xff },
+               { 0x800045, dev->cfg.adc_multiplier, 0xff },
        };
 
        /* program clock control */
-       clock_cw = af9033_div(state, state->cfg.clock, 1000000ul, 19ul);
+       clock_cw = af9033_div(dev, dev->cfg.clock, 1000000ul, 19ul);
        buf[0] = (clock_cw >>  0) & 0xff;
        buf[1] = (clock_cw >>  8) & 0xff;
        buf[2] = (clock_cw >> 16) & 0xff;
        buf[3] = (clock_cw >> 24) & 0xff;
 
-       dev_dbg(&state->i2c->dev, "%s: clock=%d clock_cw=%08x\n",
-                       __func__, state->cfg.clock, clock_cw);
+       dev_dbg(&dev->client->dev, "clock=%d clock_cw=%08x\n",
+                       dev->cfg.clock, clock_cw);
 
-       ret = af9033_wr_regs(state, 0x800025, buf, 4);
+       ret = af9033_wr_regs(dev, 0x800025, buf, 4);
        if (ret < 0)
                goto err;
 
        /* program ADC control */
        for (i = 0; i < ARRAY_SIZE(clock_adc_lut); i++) {
-               if (clock_adc_lut[i].clock == state->cfg.clock)
+               if (clock_adc_lut[i].clock == dev->cfg.clock)
                        break;
        }
 
-       adc_cw = af9033_div(state, clock_adc_lut[i].adc, 1000000ul, 19ul);
+       adc_cw = af9033_div(dev, clock_adc_lut[i].adc, 1000000ul, 19ul);
        buf[0] = (adc_cw >>  0) & 0xff;
        buf[1] = (adc_cw >>  8) & 0xff;
        buf[2] = (adc_cw >> 16) & 0xff;
 
-       dev_dbg(&state->i2c->dev, "%s: adc=%d adc_cw=%06x\n",
-                       __func__, clock_adc_lut[i].adc, adc_cw);
+       dev_dbg(&dev->client->dev, "adc=%d adc_cw=%06x\n",
+                       clock_adc_lut[i].adc, adc_cw);
 
-       ret = af9033_wr_regs(state, 0x80f1cd, buf, 3);
+       ret = af9033_wr_regs(dev, 0x80f1cd, buf, 3);
        if (ret < 0)
                goto err;
 
        /* program register table */
        for (i = 0; i < ARRAY_SIZE(tab); i++) {
-               ret = af9033_wr_reg_mask(state, tab[i].reg, tab[i].val,
+               ret = af9033_wr_reg_mask(dev, tab[i].reg, tab[i].val,
                                tab[i].mask);
                if (ret < 0)
                        goto err;
        }
 
-       /* feed clock to RF tuner */
-       switch (state->cfg.tuner) {
-       case AF9033_TUNER_IT9135_38:
-       case AF9033_TUNER_IT9135_51:
-       case AF9033_TUNER_IT9135_52:
-       case AF9033_TUNER_IT9135_60:
-       case AF9033_TUNER_IT9135_61:
-       case AF9033_TUNER_IT9135_62:
-               ret = af9033_wr_reg(state, 0x80fba8, 0x00);
+       /* clock output */
+       if (dev->cfg.dyn0_clk) {
+               ret = af9033_wr_reg(dev, 0x80fba8, 0x00);
                if (ret < 0)
                        goto err;
        }
 
        /* settings for TS interface */
-       if (state->cfg.ts_mode == AF9033_TS_MODE_USB) {
-               ret = af9033_wr_reg_mask(state, 0x80f9a5, 0x00, 0x01);
+       if (dev->cfg.ts_mode == AF9033_TS_MODE_USB) {
+               ret = af9033_wr_reg_mask(dev, 0x80f9a5, 0x00, 0x01);
                if (ret < 0)
                        goto err;
 
-               ret = af9033_wr_reg_mask(state, 0x80f9b5, 0x01, 0x01);
+               ret = af9033_wr_reg_mask(dev, 0x80f9b5, 0x01, 0x01);
                if (ret < 0)
                        goto err;
        } else {
-               ret = af9033_wr_reg_mask(state, 0x80f990, 0x00, 0x01);
+               ret = af9033_wr_reg_mask(dev, 0x80f990, 0x00, 0x01);
                if (ret < 0)
                        goto err;
 
-               ret = af9033_wr_reg_mask(state, 0x80f9b5, 0x00, 0x01);
+               ret = af9033_wr_reg_mask(dev, 0x80f9b5, 0x00, 0x01);
                if (ret < 0)
                        goto err;
        }
 
        /* load OFSM settings */
-       dev_dbg(&state->i2c->dev, "%s: load ofsm settings\n", __func__);
-       switch (state->cfg.tuner) {
+       dev_dbg(&dev->client->dev, "load ofsm settings\n");
+       switch (dev->cfg.tuner) {
        case AF9033_TUNER_IT9135_38:
        case AF9033_TUNER_IT9135_51:
        case AF9033_TUNER_IT9135_52:
@@ -367,14 +359,13 @@ static int af9033_init(struct dvb_frontend *fe)
                break;
        }
 
-       ret = af9033_wr_reg_val_tab(state, init, len);
+       ret = af9033_wr_reg_val_tab(dev, init, len);
        if (ret < 0)
                goto err;
 
        /* load tuner specific settings */
-       dev_dbg(&state->i2c->dev, "%s: load tuner specific settings\n",
-                       __func__);
-       switch (state->cfg.tuner) {
+       dev_dbg(&dev->client->dev, "load tuner specific settings\n");
+       switch (dev->cfg.tuner) {
        case AF9033_TUNER_TUA9001:
                len = ARRAY_SIZE(tuner_init_tua9001);
                init = tuner_init_tua9001;
@@ -424,90 +415,108 @@ static int af9033_init(struct dvb_frontend *fe)
                init = tuner_init_it9135_62;
                break;
        default:
-               dev_dbg(&state->i2c->dev, "%s: unsupported tuner ID=%d\n",
-                               __func__, state->cfg.tuner);
+               dev_dbg(&dev->client->dev, "unsupported tuner ID=%d\n",
+                               dev->cfg.tuner);
                ret = -ENODEV;
                goto err;
        }
 
-       ret = af9033_wr_reg_val_tab(state, init, len);
+       ret = af9033_wr_reg_val_tab(dev, init, len);
        if (ret < 0)
                goto err;
 
-       if (state->cfg.ts_mode == AF9033_TS_MODE_SERIAL) {
-               ret = af9033_wr_reg_mask(state, 0x00d91c, 0x01, 0x01);
+       if (dev->cfg.ts_mode == AF9033_TS_MODE_SERIAL) {
+               ret = af9033_wr_reg_mask(dev, 0x00d91c, 0x01, 0x01);
                if (ret < 0)
                        goto err;
 
-               ret = af9033_wr_reg_mask(state, 0x00d917, 0x00, 0x01);
+               ret = af9033_wr_reg_mask(dev, 0x00d917, 0x00, 0x01);
                if (ret < 0)
                        goto err;
 
-               ret = af9033_wr_reg_mask(state, 0x00d916, 0x00, 0x01);
+               ret = af9033_wr_reg_mask(dev, 0x00d916, 0x00, 0x01);
                if (ret < 0)
                        goto err;
        }
 
-       switch (state->cfg.tuner) {
+       switch (dev->cfg.tuner) {
        case AF9033_TUNER_IT9135_60:
        case AF9033_TUNER_IT9135_61:
        case AF9033_TUNER_IT9135_62:
-               ret = af9033_wr_reg(state, 0x800000, 0x01);
+               ret = af9033_wr_reg(dev, 0x800000, 0x01);
                if (ret < 0)
                        goto err;
        }
 
-       state->bandwidth_hz = 0; /* force to program all parameters */
+       dev->bandwidth_hz = 0; /* force to program all parameters */
+       /* init stats here in order signal app which stats are supported */
+       c->strength.len = 1;
+       c->strength.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+       c->cnr.len = 1;
+       c->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+       c->block_count.len = 1;
+       c->block_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+       c->block_error.len = 1;
+       c->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+       c->post_bit_count.len = 1;
+       c->post_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+       c->post_bit_error.len = 1;
+       c->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+       /* start statistics polling */
+       schedule_delayed_work(&dev->stat_work, msecs_to_jiffies(2000));
 
        return 0;
 
 err:
-       dev_dbg(&state->i2c->dev, "%s: failed=%d\n", __func__, ret);
+       dev_dbg(&dev->client->dev, "failed=%d\n", ret);
 
        return ret;
 }
 
 static int af9033_sleep(struct dvb_frontend *fe)
 {
-       struct af9033_state *state = fe->demodulator_priv;
+       struct af9033_dev *dev = fe->demodulator_priv;
        int ret, i;
        u8 tmp;
 
-       ret = af9033_wr_reg(state, 0x80004c, 1);
+       /* stop statistics polling */
+       cancel_delayed_work_sync(&dev->stat_work);
+
+       ret = af9033_wr_reg(dev, 0x80004c, 1);
        if (ret < 0)
                goto err;
 
-       ret = af9033_wr_reg(state, 0x800000, 0);
+       ret = af9033_wr_reg(dev, 0x800000, 0);
        if (ret < 0)
                goto err;
 
        for (i = 100, tmp = 1; i && tmp; i--) {
-               ret = af9033_rd_reg(state, 0x80004c, &tmp);
+               ret = af9033_rd_reg(dev, 0x80004c, &tmp);
                if (ret < 0)
                        goto err;
 
                usleep_range(200, 10000);
        }
 
-       dev_dbg(&state->i2c->dev, "%s: loop=%d\n", __func__, i);
+       dev_dbg(&dev->client->dev, "loop=%d\n", i);
 
        if (i == 0) {
                ret = -ETIMEDOUT;
                goto err;
        }
 
-       ret = af9033_wr_reg_mask(state, 0x80fb24, 0x08, 0x08);
+       ret = af9033_wr_reg_mask(dev, 0x80fb24, 0x08, 0x08);
        if (ret < 0)
                goto err;
 
        /* prevent current leak (?) */
-       if (state->cfg.ts_mode == AF9033_TS_MODE_SERIAL) {
+       if (dev->cfg.ts_mode == AF9033_TS_MODE_SERIAL) {
                /* enable parallel TS */
-               ret = af9033_wr_reg_mask(state, 0x00d917, 0x00, 0x01);
+               ret = af9033_wr_reg_mask(dev, 0x00d917, 0x00, 0x01);
                if (ret < 0)
                        goto err;
 
-               ret = af9033_wr_reg_mask(state, 0x00d916, 0x01, 0x01);
+               ret = af9033_wr_reg_mask(dev, 0x00d916, 0x01, 0x01);
                if (ret < 0)
                        goto err;
        }
@@ -515,7 +524,7 @@ static int af9033_sleep(struct dvb_frontend *fe)
        return 0;
 
 err:
-       dev_dbg(&state->i2c->dev, "%s: failed=%d\n", __func__, ret);
+       dev_dbg(&dev->client->dev, "failed=%d\n", ret);
 
        return ret;
 }
@@ -533,14 +542,14 @@ static int af9033_get_tune_settings(struct dvb_frontend *fe,
 
 static int af9033_set_frontend(struct dvb_frontend *fe)
 {
-       struct af9033_state *state = fe->demodulator_priv;
+       struct af9033_dev *dev = fe->demodulator_priv;
        struct dtv_frontend_properties *c = &fe->dtv_property_cache;
        int ret, i, spec_inv, sampling_freq;
        u8 tmp, buf[3], bandwidth_reg_val;
        u32 if_frequency, freq_cw, adc_freq;
 
-       dev_dbg(&state->i2c->dev, "%s: frequency=%d bandwidth_hz=%d\n",
-                       __func__, c->frequency, c->bandwidth_hz);
+       dev_dbg(&dev->client->dev, "frequency=%d bandwidth_hz=%d\n",
+                       c->frequency, c->bandwidth_hz);
 
        /* check bandwidth */
        switch (c->bandwidth_hz) {
@@ -554,8 +563,7 @@ static int af9033_set_frontend(struct dvb_frontend *fe)
                bandwidth_reg_val = 0x02;
                break;
        default:
-               dev_dbg(&state->i2c->dev, "%s: invalid bandwidth_hz\n",
-                               __func__);
+               dev_dbg(&dev->client->dev, "invalid bandwidth_hz\n");
                ret = -EINVAL;
                goto err;
        }
@@ -565,23 +573,23 @@ static int af9033_set_frontend(struct dvb_frontend *fe)
                fe->ops.tuner_ops.set_params(fe);
 
        /* program CFOE coefficients */
-       if (c->bandwidth_hz != state->bandwidth_hz) {
+       if (c->bandwidth_hz != dev->bandwidth_hz) {
                for (i = 0; i < ARRAY_SIZE(coeff_lut); i++) {
-                       if (coeff_lut[i].clock == state->cfg.clock &&
+                       if (coeff_lut[i].clock == dev->cfg.clock &&
                                coeff_lut[i].bandwidth_hz == c->bandwidth_hz) {
                                break;
                        }
                }
-               ret =  af9033_wr_regs(state, 0x800001,
+               ret =  af9033_wr_regs(dev, 0x800001,
                                coeff_lut[i].val, sizeof(coeff_lut[i].val));
        }
 
        /* program frequency control */
-       if (c->bandwidth_hz != state->bandwidth_hz) {
-               spec_inv = state->cfg.spec_inv ? -1 : 1;
+       if (c->bandwidth_hz != dev->bandwidth_hz) {
+               spec_inv = dev->cfg.spec_inv ? -1 : 1;
 
                for (i = 0; i < ARRAY_SIZE(clock_adc_lut); i++) {
-                       if (clock_adc_lut[i].clock == state->cfg.clock)
+                       if (clock_adc_lut[i].clock == dev->cfg.clock)
                                break;
                }
                adc_freq = clock_adc_lut[i].adc;
@@ -602,12 +610,12 @@ static int af9033_set_frontend(struct dvb_frontend *fe)
                else
                        sampling_freq *= -1;
 
-               freq_cw = af9033_div(state, sampling_freq, adc_freq, 23ul);
+               freq_cw = af9033_div(dev, sampling_freq, adc_freq, 23ul);
 
                if (spec_inv == -1)
                        freq_cw = 0x800000 - freq_cw;
 
-               if (state->cfg.adc_multiplier == AF9033_ADC_MULTIPLIER_2X)
+               if (dev->cfg.adc_multiplier == AF9033_ADC_MULTIPLIER_2X)
                        freq_cw /= 2;
 
                buf[0] = (freq_cw >>  0) & 0xff;
@@ -618,26 +626,26 @@ static int af9033_set_frontend(struct dvb_frontend *fe)
                if (if_frequency == 0)
                        buf[2] = 0;
 
-               ret = af9033_wr_regs(state, 0x800029, buf, 3);
+               ret = af9033_wr_regs(dev, 0x800029, buf, 3);
                if (ret < 0)
                        goto err;
 
-               state->bandwidth_hz = c->bandwidth_hz;
+               dev->bandwidth_hz = c->bandwidth_hz;
        }
 
-       ret = af9033_wr_reg_mask(state, 0x80f904, bandwidth_reg_val, 0x03);
+       ret = af9033_wr_reg_mask(dev, 0x80f904, bandwidth_reg_val, 0x03);
        if (ret < 0)
                goto err;
 
-       ret = af9033_wr_reg(state, 0x800040, 0x00);
+       ret = af9033_wr_reg(dev, 0x800040, 0x00);
        if (ret < 0)
                goto err;
 
-       ret = af9033_wr_reg(state, 0x800047, 0x00);
+       ret = af9033_wr_reg(dev, 0x800047, 0x00);
        if (ret < 0)
                goto err;
 
-       ret = af9033_wr_reg_mask(state, 0x80f999, 0x00, 0x01);
+       ret = af9033_wr_reg_mask(dev, 0x80f999, 0x00, 0x01);
        if (ret < 0)
                goto err;
 
@@ -646,33 +654,33 @@ static int af9033_set_frontend(struct dvb_frontend *fe)
        else
                tmp = 0x01; /* UHF */
 
-       ret = af9033_wr_reg(state, 0x80004b, tmp);
+       ret = af9033_wr_reg(dev, 0x80004b, tmp);
        if (ret < 0)
                goto err;
 
-       ret = af9033_wr_reg(state, 0x800000, 0x00);
+       ret = af9033_wr_reg(dev, 0x800000, 0x00);
        if (ret < 0)
                goto err;
 
        return 0;
 
 err:
-       dev_dbg(&state->i2c->dev, "%s: failed=%d\n", __func__, ret);
+       dev_dbg(&dev->client->dev, "failed=%d\n", ret);
 
        return ret;
 }
 
 static int af9033_get_frontend(struct dvb_frontend *fe)
 {
-       struct af9033_state *state = fe->demodulator_priv;
+       struct af9033_dev *dev = fe->demodulator_priv;
        struct dtv_frontend_properties *c = &fe->dtv_property_cache;
        int ret;
        u8 buf[8];
 
-       dev_dbg(&state->i2c->dev, "%s:\n", __func__);
+       dev_dbg(&dev->client->dev, "\n");
 
        /* read all needed registers */
-       ret = af9033_rd_regs(state, 0x80f900, buf, sizeof(buf));
+       ret = af9033_rd_regs(dev, 0x80f900, buf, sizeof(buf));
        if (ret < 0)
                goto err;
 
@@ -784,21 +792,21 @@ static int af9033_get_frontend(struct dvb_frontend *fe)
        return 0;
 
 err:
-       dev_dbg(&state->i2c->dev, "%s: failed=%d\n", __func__, ret);
+       dev_dbg(&dev->client->dev, "failed=%d\n", ret);
 
        return ret;
 }
 
 static int af9033_read_status(struct dvb_frontend *fe, fe_status_t *status)
 {
-       struct af9033_state *state = fe->demodulator_priv;
+       struct af9033_dev *dev = fe->demodulator_priv;
        int ret;
        u8 tmp;
 
        *status = 0;
 
        /* radio channel status, 0=no result, 1=has signal, 2=no signal */
-       ret = af9033_rd_reg(state, 0x800047, &tmp);
+       ret = af9033_rd_reg(dev, 0x800047, &tmp);
        if (ret < 0)
                goto err;
 
@@ -808,7 +816,7 @@ static int af9033_read_status(struct dvb_frontend *fe, fe_status_t *status)
 
        if (tmp != 0x02) {
                /* TPS lock */
-               ret = af9033_rd_reg_mask(state, 0x80f5a9, &tmp, 0x01);
+               ret = af9033_rd_reg_mask(dev, 0x80f5a9, &tmp, 0x01);
                if (ret < 0)
                        goto err;
 
@@ -817,7 +825,7 @@ static int af9033_read_status(struct dvb_frontend *fe, fe_status_t *status)
                                        FE_HAS_VITERBI;
 
                /* full lock */
-               ret = af9033_rd_reg_mask(state, 0x80f999, &tmp, 0x01);
+               ret = af9033_rd_reg_mask(dev, 0x80f999, &tmp, 0x01);
                if (ret < 0)
                        goto err;
 
@@ -827,76 +835,38 @@ static int af9033_read_status(struct dvb_frontend *fe, fe_status_t *status)
                                        FE_HAS_LOCK;
        }
 
+       dev->fe_status = *status;
+
        return 0;
 
 err:
-       dev_dbg(&state->i2c->dev, "%s: failed=%d\n", __func__, ret);
+       dev_dbg(&dev->client->dev, "failed=%d\n", ret);
 
        return ret;
 }
 
 static int af9033_read_snr(struct dvb_frontend *fe, u16 *snr)
 {
-       struct af9033_state *state = fe->demodulator_priv;
-       int ret, i, len;
-       u8 buf[3], tmp;
-       u32 snr_val;
-       const struct val_snr *uninitialized_var(snr_lut);
-
-       /* read value */
-       ret = af9033_rd_regs(state, 0x80002c, buf, 3);
-       if (ret < 0)
-               goto err;
+       struct af9033_dev *dev = fe->demodulator_priv;
+       struct dtv_frontend_properties *c = &dev->fe.dtv_property_cache;
 
-       snr_val = (buf[2] << 16) | (buf[1] << 8) | buf[0];
-
-       /* read current modulation */
-       ret = af9033_rd_reg(state, 0x80f903, &tmp);
-       if (ret < 0)
-               goto err;
-
-       switch ((tmp >> 0) & 3) {
-       case 0:
-               len = ARRAY_SIZE(qpsk_snr_lut);
-               snr_lut = qpsk_snr_lut;
-               break;
-       case 1:
-               len = ARRAY_SIZE(qam16_snr_lut);
-               snr_lut = qam16_snr_lut;
-               break;
-       case 2:
-               len = ARRAY_SIZE(qam64_snr_lut);
-               snr_lut = qam64_snr_lut;
-               break;
-       default:
-               goto err;
-       }
-
-       for (i = 0; i < len; i++) {
-               tmp = snr_lut[i].snr;
-
-               if (snr_val < snr_lut[i].val)
-                       break;
-       }
-
-       *snr = tmp * 10; /* dB/10 */
+       /* use DVBv5 CNR */
+       if (c->cnr.stat[0].scale == FE_SCALE_DECIBEL)
+               *snr = div_s64(c->cnr.stat[0].svalue, 100); /* 1000x => 10x */
+       else
+               *snr = 0;
 
        return 0;
-
-err:
-       dev_dbg(&state->i2c->dev, "%s: failed=%d\n", __func__, ret);
-
-       return ret;
 }
 
 static int af9033_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
 {
-       struct af9033_state *state = fe->demodulator_priv;
+       struct af9033_dev *dev = fe->demodulator_priv;
        int ret;
        u8 strength2;
 
        /* read signal strength of 0-100 scale */
-       ret = af9033_rd_reg(state, 0x800048, &strength2);
+       ret = af9033_rd_reg(dev, 0x800048, &strength2);
        if (ret < 0)
                goto err;
 
@@ -906,244 +876,225 @@ static int af9033_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
        return 0;
 
 err:
-       dev_dbg(&state->i2c->dev, "%s: failed=%d\n", __func__, ret);
-
-       return ret;
-}
-
-static int af9033_update_ch_stat(struct af9033_state *state)
-{
-       int ret = 0;
-       u32 err_cnt, bit_cnt;
-       u16 abort_cnt;
-       u8 buf[7];
-
-       /* only update data every half second */
-       if (time_after(jiffies, state->last_stat_check + msecs_to_jiffies(500))) {
-               ret = af9033_rd_regs(state, 0x800032, buf, sizeof(buf));
-               if (ret < 0)
-                       goto err;
-               /* in 8 byte packets? */
-               abort_cnt = (buf[1] << 8) + buf[0];
-               /* in bits */
-               err_cnt = (buf[4] << 16) + (buf[3] << 8) + buf[2];
-               /* in 8 byte packets? always(?) 0x2710 = 10000 */
-               bit_cnt = (buf[6] << 8) + buf[5];
-
-               if (bit_cnt < abort_cnt) {
-                       abort_cnt = 1000;
-                       state->ber = 0xffffffff;
-               } else {
-                       /* 8 byte packets, that have not been rejected already */
-                       bit_cnt -= (u32)abort_cnt;
-                       if (bit_cnt == 0) {
-                               state->ber = 0xffffffff;
-                       } else {
-                               err_cnt -= (u32)abort_cnt * 8 * 8;
-                               bit_cnt *= 8 * 8;
-                               state->ber = err_cnt * (0xffffffff / bit_cnt);
-                       }
-               }
-               state->ucb += abort_cnt;
-               state->last_stat_check = jiffies;
-       }
-
-       return 0;
-err:
-       dev_dbg(&state->i2c->dev, "%s: failed=%d\n", __func__, ret);
+       dev_dbg(&dev->client->dev, "failed=%d\n", ret);
 
        return ret;
 }
 
 static int af9033_read_ber(struct dvb_frontend *fe, u32 *ber)
 {
-       struct af9033_state *state = fe->demodulator_priv;
-       int ret;
-
-       ret = af9033_update_ch_stat(state);
-       if (ret < 0)
-               return ret;
+       struct af9033_dev *dev = fe->demodulator_priv;
 
-       *ber = state->ber;
+       *ber = (dev->post_bit_error - dev->post_bit_error_prev);
+       dev->post_bit_error_prev = dev->post_bit_error;
 
        return 0;
 }
 
 static int af9033_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
 {
-       struct af9033_state *state = fe->demodulator_priv;
-       int ret;
-
-       ret = af9033_update_ch_stat(state);
-       if (ret < 0)
-               return ret;
-
-       *ucblocks = state->ucb;
+       struct af9033_dev *dev = fe->demodulator_priv;
 
+       *ucblocks = dev->error_block_count;
        return 0;
 }
 
 static int af9033_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
 {
-       struct af9033_state *state = fe->demodulator_priv;
+       struct af9033_dev *dev = fe->demodulator_priv;
        int ret;
 
-       dev_dbg(&state->i2c->dev, "%s: enable=%d\n", __func__, enable);
+       dev_dbg(&dev->client->dev, "enable=%d\n", enable);
 
-       ret = af9033_wr_reg_mask(state, 0x00fa04, enable, 0x01);
+       ret = af9033_wr_reg_mask(dev, 0x00fa04, enable, 0x01);
        if (ret < 0)
                goto err;
 
        return 0;
 
 err:
-       dev_dbg(&state->i2c->dev, "%s: failed=%d\n", __func__, ret);
+       dev_dbg(&dev->client->dev, "failed=%d\n", ret);
 
        return ret;
 }
 
 static int af9033_pid_filter_ctrl(struct dvb_frontend *fe, int onoff)
 {
-       struct af9033_state *state = fe->demodulator_priv;
+       struct af9033_dev *dev = fe->demodulator_priv;
        int ret;
 
-       dev_dbg(&state->i2c->dev, "%s: onoff=%d\n", __func__, onoff);
+       dev_dbg(&dev->client->dev, "onoff=%d\n", onoff);
 
-       ret = af9033_wr_reg_mask(state, 0x80f993, onoff, 0x01);
+       ret = af9033_wr_reg_mask(dev, 0x80f993, onoff, 0x01);
        if (ret < 0)
                goto err;
 
        return 0;
 
 err:
-       dev_dbg(&state->i2c->dev, "%s: failed=%d\n", __func__, ret);
+       dev_dbg(&dev->client->dev, "failed=%d\n", ret);
 
        return ret;
 }
 
-static int af9033_pid_filter(struct dvb_frontend *fe, int index, u16 pid, int onoff)
+static int af9033_pid_filter(struct dvb_frontend *fe, int index, u16 pid,
+               int onoff)
 {
-       struct af9033_state *state = fe->demodulator_priv;
+       struct af9033_dev *dev = fe->demodulator_priv;
        int ret;
        u8 wbuf[2] = {(pid >> 0) & 0xff, (pid >> 8) & 0xff};
 
-       dev_dbg(&state->i2c->dev, "%s: index=%d pid=%04x onoff=%d\n",
-                       __func__, index, pid, onoff);
+       dev_dbg(&dev->client->dev, "index=%d pid=%04x onoff=%d\n",
+                       index, pid, onoff);
 
        if (pid > 0x1fff)
                return 0;
 
-       ret = af9033_wr_regs(state, 0x80f996, wbuf, 2);
+       ret = af9033_wr_regs(dev, 0x80f996, wbuf, 2);
        if (ret < 0)
                goto err;
 
-       ret = af9033_wr_reg(state, 0x80f994, onoff);
+       ret = af9033_wr_reg(dev, 0x80f994, onoff);
        if (ret < 0)
                goto err;
 
-       ret = af9033_wr_reg(state, 0x80f995, index);
+       ret = af9033_wr_reg(dev, 0x80f995, index);
        if (ret < 0)
                goto err;
 
        return 0;
 
 err:
-       dev_dbg(&state->i2c->dev, "%s: failed=%d\n", __func__, ret);
+       dev_dbg(&dev->client->dev, "failed=%d\n", ret);
 
        return ret;
 }
 
-static struct dvb_frontend_ops af9033_ops;
-
-struct dvb_frontend *af9033_attach(const struct af9033_config *config,
-                                  struct i2c_adapter *i2c,
-                                  struct af9033_ops *ops)
+static void af9033_stat_work(struct work_struct *work)
 {
-       int ret;
-       struct af9033_state *state;
-       u8 buf[8];
+       struct af9033_dev *dev = container_of(work, struct af9033_dev, stat_work.work);
+       struct dtv_frontend_properties *c = &dev->fe.dtv_property_cache;
+       int ret, tmp, i, len;
+       u8 u8tmp, buf[7];
+
+       dev_dbg(&dev->client->dev, "\n");
+
+       /* signal strength */
+       if (dev->fe_status & FE_HAS_SIGNAL) {
+               if (dev->is_af9035) {
+                       ret = af9033_rd_reg(dev, 0x80004a, &u8tmp);
+                       tmp = -u8tmp * 1000;
+               } else {
+                       ret = af9033_rd_reg(dev, 0x8000f7, &u8tmp);
+                       tmp = (u8tmp - 100) * 1000;
+               }
+               if (ret)
+                       goto err;
 
-       dev_dbg(&i2c->dev, "%s:\n", __func__);
+               c->strength.len = 1;
+               c->strength.stat[0].scale = FE_SCALE_DECIBEL;
+               c->strength.stat[0].svalue = tmp;
+       } else {
+               c->strength.len = 1;
+               c->strength.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+       }
 
-       /* allocate memory for the internal state */
-       state = kzalloc(sizeof(struct af9033_state), GFP_KERNEL);
-       if (state == NULL)
-               goto err;
+       /* CNR */
+       if (dev->fe_status & FE_HAS_VITERBI) {
+               u32 snr_val;
+               const struct val_snr *snr_lut;
 
-       /* setup the state */
-       state->i2c = i2c;
-       memcpy(&state->cfg, config, sizeof(struct af9033_config));
+               /* read value */
+               ret = af9033_rd_regs(dev, 0x80002c, buf, 3);
+               if (ret)
+                       goto err;
 
-       if (state->cfg.clock != 12000000) {
-               dev_err(&state->i2c->dev, "%s: af9033: unsupported clock=%d, " \
-                               "only 12000000 Hz is supported currently\n",
-                               KBUILD_MODNAME, state->cfg.clock);
-               goto err;
-       }
+               snr_val = (buf[2] << 16) | (buf[1] << 8) | (buf[0] << 0);
 
-       /* firmware version */
-       ret = af9033_rd_regs(state, 0x0083e9, &buf[0], 4);
-       if (ret < 0)
-               goto err;
+               /* read current modulation */
+               ret = af9033_rd_reg(dev, 0x80f903, &u8tmp);
+               if (ret)
+                       goto err;
 
-       ret = af9033_rd_regs(state, 0x804191, &buf[4], 4);
-       if (ret < 0)
-               goto err;
+               switch ((u8tmp >> 0) & 3) {
+               case 0:
+                       len = ARRAY_SIZE(qpsk_snr_lut);
+                       snr_lut = qpsk_snr_lut;
+                       break;
+               case 1:
+                       len = ARRAY_SIZE(qam16_snr_lut);
+                       snr_lut = qam16_snr_lut;
+                       break;
+               case 2:
+                       len = ARRAY_SIZE(qam64_snr_lut);
+                       snr_lut = qam64_snr_lut;
+                       break;
+               default:
+                       goto err_schedule_delayed_work;
+               }
 
-       dev_info(&state->i2c->dev, "%s: firmware version: LINK=%d.%d.%d.%d " \
-                       "OFDM=%d.%d.%d.%d\n", KBUILD_MODNAME, buf[0], buf[1],
-                       buf[2], buf[3], buf[4], buf[5], buf[6], buf[7]);
+               for (i = 0; i < len; i++) {
+                       tmp = snr_lut[i].snr * 1000;
+                       if (snr_val < snr_lut[i].val)
+                               break;
+               }
 
-       /* sleep */
-       switch (state->cfg.tuner) {
-       case AF9033_TUNER_IT9135_38:
-       case AF9033_TUNER_IT9135_51:
-       case AF9033_TUNER_IT9135_52:
-       case AF9033_TUNER_IT9135_60:
-       case AF9033_TUNER_IT9135_61:
-       case AF9033_TUNER_IT9135_62:
-               /* IT9135 did not like to sleep at that early */
-               break;
-       default:
-               ret = af9033_wr_reg(state, 0x80004c, 1);
-               if (ret < 0)
-                       goto err;
+               c->cnr.len = 1;
+               c->cnr.stat[0].scale = FE_SCALE_DECIBEL;
+               c->cnr.stat[0].svalue = tmp;
+       } else {
+               c->cnr.len = 1;
+               c->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+       }
 
-               ret = af9033_wr_reg(state, 0x800000, 0);
-               if (ret < 0)
+       /* UCB/PER/BER */
+       if (dev->fe_status & FE_HAS_LOCK) {
+               /* outer FEC, 204 byte packets */
+               u16 abort_packet_count, rsd_packet_count;
+               /* inner FEC, bits */
+               u32 rsd_bit_err_count;
+
+               /*
+                * Packet count used for measurement is 10000
+                * (rsd_packet_count). Maybe it should be increased?
+                */
+
+               ret = af9033_rd_regs(dev, 0x800032, buf, 7);
+               if (ret)
                        goto err;
-       }
 
-       /* configure internal TS mode */
-       switch (state->cfg.ts_mode) {
-       case AF9033_TS_MODE_PARALLEL:
-               state->ts_mode_parallel = true;
-               break;
-       case AF9033_TS_MODE_SERIAL:
-               state->ts_mode_serial = true;
-               break;
-       case AF9033_TS_MODE_USB:
-               /* usb mode for AF9035 */
-       default:
-               break;
-       }
+               abort_packet_count = (buf[1] << 8) | (buf[0] << 0);
+               rsd_bit_err_count = (buf[4] << 16) | (buf[3] << 8) | buf[2];
+               rsd_packet_count = (buf[6] << 8) | (buf[5] << 0);
 
-       /* create dvb_frontend */
-       memcpy(&state->fe.ops, &af9033_ops, sizeof(struct dvb_frontend_ops));
-       state->fe.demodulator_priv = state;
+               dev->error_block_count += abort_packet_count;
+               dev->total_block_count += rsd_packet_count;
+               dev->post_bit_error += rsd_bit_err_count;
+               dev->post_bit_count += rsd_packet_count * 204 * 8;
 
-       if (ops) {
-               ops->pid_filter = af9033_pid_filter;
-               ops->pid_filter_ctrl = af9033_pid_filter_ctrl;
-       }
+               c->block_count.len = 1;
+               c->block_count.stat[0].scale = FE_SCALE_COUNTER;
+               c->block_count.stat[0].uvalue = dev->total_block_count;
+
+               c->block_error.len = 1;
+               c->block_error.stat[0].scale = FE_SCALE_COUNTER;
+               c->block_error.stat[0].uvalue = dev->error_block_count;
+
+               c->post_bit_count.len = 1;
+               c->post_bit_count.stat[0].scale = FE_SCALE_COUNTER;
+               c->post_bit_count.stat[0].uvalue = dev->post_bit_count;
 
-       return &state->fe;
+               c->post_bit_error.len = 1;
+               c->post_bit_error.stat[0].scale = FE_SCALE_COUNTER;
+               c->post_bit_error.stat[0].uvalue = dev->post_bit_error;
+       }
 
+err_schedule_delayed_work:
+       schedule_delayed_work(&dev->stat_work, msecs_to_jiffies(2000));
+       return;
 err:
-       kfree(state);
-       return NULL;
+       dev_dbg(&dev->client->dev, "failed=%d\n", ret);
 }
-EXPORT_SYMBOL(af9033_attach);
 
 static struct dvb_frontend_ops af9033_ops = {
        .delsys = { SYS_DVBT },
@@ -1170,8 +1121,6 @@ static struct dvb_frontend_ops af9033_ops = {
                        FE_CAN_MUTE_TS
        },
 
-       .release = af9033_release,
-
        .init = af9033_init,
        .sleep = af9033_sleep,
 
@@ -1188,6 +1137,150 @@ static struct dvb_frontend_ops af9033_ops = {
        .i2c_gate_ctrl = af9033_i2c_gate_ctrl,
 };
 
+static int af9033_probe(struct i2c_client *client,
+               const struct i2c_device_id *id)
+{
+       struct af9033_config *cfg = client->dev.platform_data;
+       struct af9033_dev *dev;
+       int ret;
+       u8 buf[8];
+       u32 reg;
+
+       /* allocate memory for the internal state */
+       dev = kzalloc(sizeof(struct af9033_dev), GFP_KERNEL);
+       if (dev == NULL) {
+               ret = -ENOMEM;
+               dev_err(&client->dev, "Could not allocate memory for state\n");
+               goto err;
+       }
+
+       /* setup the state */
+       dev->client = client;
+       INIT_DELAYED_WORK(&dev->stat_work, af9033_stat_work);
+       memcpy(&dev->cfg, cfg, sizeof(struct af9033_config));
+
+       if (dev->cfg.clock != 12000000) {
+               ret = -ENODEV;
+               dev_err(&dev->client->dev,
+                               "unsupported clock %d Hz, only 12000000 Hz is supported currently\n",
+                               dev->cfg.clock);
+               goto err_kfree;
+       }
+
+       /* firmware version */
+       switch (dev->cfg.tuner) {
+       case AF9033_TUNER_IT9135_38:
+       case AF9033_TUNER_IT9135_51:
+       case AF9033_TUNER_IT9135_52:
+       case AF9033_TUNER_IT9135_60:
+       case AF9033_TUNER_IT9135_61:
+       case AF9033_TUNER_IT9135_62:
+               dev->is_it9135 = true;
+               reg = 0x004bfc;
+               break;
+       default:
+               dev->is_af9035 = true;
+               reg = 0x0083e9;
+               break;
+       }
+
+       ret = af9033_rd_regs(dev, reg, &buf[0], 4);
+       if (ret < 0)
+               goto err_kfree;
+
+       ret = af9033_rd_regs(dev, 0x804191, &buf[4], 4);
+       if (ret < 0)
+               goto err_kfree;
+
+       dev_info(&dev->client->dev,
+                       "firmware version: LINK %d.%d.%d.%d - OFDM %d.%d.%d.%d\n",
+                       buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6],
+                       buf[7]);
+
+       /* sleep */
+       switch (dev->cfg.tuner) {
+       case AF9033_TUNER_IT9135_38:
+       case AF9033_TUNER_IT9135_51:
+       case AF9033_TUNER_IT9135_52:
+       case AF9033_TUNER_IT9135_60:
+       case AF9033_TUNER_IT9135_61:
+       case AF9033_TUNER_IT9135_62:
+               /* IT9135 did not like to sleep at that early */
+               break;
+       default:
+               ret = af9033_wr_reg(dev, 0x80004c, 1);
+               if (ret < 0)
+                       goto err_kfree;
+
+               ret = af9033_wr_reg(dev, 0x800000, 0);
+               if (ret < 0)
+                       goto err_kfree;
+       }
+
+       /* configure internal TS mode */
+       switch (dev->cfg.ts_mode) {
+       case AF9033_TS_MODE_PARALLEL:
+               dev->ts_mode_parallel = true;
+               break;
+       case AF9033_TS_MODE_SERIAL:
+               dev->ts_mode_serial = true;
+               break;
+       case AF9033_TS_MODE_USB:
+               /* usb mode for AF9035 */
+       default:
+               break;
+       }
+
+       /* create dvb_frontend */
+       memcpy(&dev->fe.ops, &af9033_ops, sizeof(struct dvb_frontend_ops));
+       dev->fe.demodulator_priv = dev;
+       *cfg->fe = &dev->fe;
+       if (cfg->ops) {
+               cfg->ops->pid_filter = af9033_pid_filter;
+               cfg->ops->pid_filter_ctrl = af9033_pid_filter_ctrl;
+       }
+       i2c_set_clientdata(client, dev);
+
+       dev_info(&dev->client->dev, "Afatech AF9033 successfully attached\n");
+       return 0;
+err_kfree:
+       kfree(dev);
+err:
+       dev_dbg(&client->dev, "failed=%d\n", ret);
+       return ret;
+}
+
+static int af9033_remove(struct i2c_client *client)
+{
+       struct af9033_dev *dev = i2c_get_clientdata(client);
+
+       dev_dbg(&dev->client->dev, "\n");
+
+       dev->fe.ops.release = NULL;
+       dev->fe.demodulator_priv = NULL;
+       kfree(dev);
+
+       return 0;
+}
+
+static const struct i2c_device_id af9033_id_table[] = {
+       {"af9033", 0},
+       {}
+};
+MODULE_DEVICE_TABLE(i2c, af9033_id_table);
+
+static struct i2c_driver af9033_driver = {
+       .driver = {
+               .owner  = THIS_MODULE,
+               .name   = "af9033",
+       },
+       .probe          = af9033_probe,
+       .remove         = af9033_remove,
+       .id_table       = af9033_id_table,
+};
+
+module_i2c_driver(af9033_driver);
+
 MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
 MODULE_DESCRIPTION("Afatech AF9033 DVB-T demodulator driver");
 MODULE_LICENSE("GPL");
index 539f4db678b87f0076093f8f85b9139e182dc31d..6ad22b69a63605e6b14c5516614fc40640e9085e 100644 (file)
 
 #include <linux/kconfig.h>
 
+/*
+ * I2C address (TODO: are these in 8-bit format?)
+ * 0x38, 0x3a, 0x3c, 0x3e
+ */
 struct af9033_config {
-       /*
-        * I2C address
-        */
-       u8 i2c_addr;
-
        /*
         * clock Hz
         * 12000000, 22000000, 24000000, 34000000, 32000000, 28000000, 26000000,
@@ -75,8 +74,23 @@ struct af9033_config {
         * input spectrum inversion
         */
        bool spec_inv;
-};
 
+       /*
+        *
+        */
+       bool dyn0_clk;
+
+       /*
+        * PID filter ops
+        */
+       struct af9033_ops *ops;
+
+       /*
+        * frontend
+        * returned by that driver
+        */
+       struct dvb_frontend **fe;
+};
 
 struct af9033_ops {
        int (*pid_filter_ctrl)(struct dvb_frontend *fe, int onoff);
@@ -84,36 +98,4 @@ struct af9033_ops {
                          int onoff);
 };
 
-
-#if IS_ENABLED(CONFIG_DVB_AF9033)
-extern
-struct dvb_frontend *af9033_attach(const struct af9033_config *config,
-                                  struct i2c_adapter *i2c,
-                                  struct af9033_ops *ops);
-
-#else
-static inline
-struct dvb_frontend *af9033_attach(const struct af9033_config *config,
-                                  struct i2c_adapter *i2c,
-                                  struct af9033_ops *ops)
-{
-       pr_warn("%s: driver disabled by Kconfig\n", __func__);
-       return NULL;
-}
-
-static inline int af9033_pid_filter_ctrl(struct dvb_frontend *fe, int onoff)
-{
-       pr_warn("%s: driver disabled by Kconfig\n", __func__);
-       return -ENODEV;
-}
-
-static inline int af9033_pid_filter(struct dvb_frontend *fe, int index, u16 pid,
-       int onoff)
-{
-       pr_warn("%s: driver disabled by Kconfig\n", __func__);
-       return -ENODEV;
-}
-
-#endif
-
 #endif /* AF9033_H */
index ded7b67d7526cab8b9cd364dfe6ce19fdb3da36e..c12c92cb5855ae587f332f1d32673947ac90d912 100644 (file)
@@ -24,6 +24,7 @@
 
 #include "dvb_frontend.h"
 #include "af9033.h"
+#include <linux/math64.h>
 
 struct reg_val {
        u32 reg;
diff --git a/drivers/media/dvb-frontends/as102_fe.c b/drivers/media/dvb-frontends/as102_fe.c
new file mode 100644 (file)
index 0000000..4936658
--- /dev/null
@@ -0,0 +1,480 @@
+/*
+ * Abilis Systems Single DVB-T Receiver
+ * Copyright (C) 2008 Pierrick Hascoet <pierrick.hascoet@abilis.com>
+ * Copyright (C) 2010 Devin Heitmueller <dheitmueller@kernellabs.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, 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 <dvb_frontend.h>
+
+#include "as102_fe.h"
+
+struct as102_state {
+       struct dvb_frontend frontend;
+       struct as10x_demod_stats demod_stats;
+
+       const struct as102_fe_ops *ops;
+       void *priv;
+       uint8_t elna_cfg;
+
+       /* signal strength */
+       uint16_t signal_strength;
+       /* bit error rate */
+       uint32_t ber;
+};
+
+static uint8_t as102_fe_get_code_rate(fe_code_rate_t arg)
+{
+       uint8_t c;
+
+       switch (arg) {
+       case FEC_1_2:
+               c = CODE_RATE_1_2;
+               break;
+       case FEC_2_3:
+               c = CODE_RATE_2_3;
+               break;
+       case FEC_3_4:
+               c = CODE_RATE_3_4;
+               break;
+       case FEC_5_6:
+               c = CODE_RATE_5_6;
+               break;
+       case FEC_7_8:
+               c = CODE_RATE_7_8;
+               break;
+       default:
+               c = CODE_RATE_UNKNOWN;
+               break;
+       }
+
+       return c;
+}
+
+static int as102_fe_set_frontend(struct dvb_frontend *fe)
+{
+       struct as102_state *state = fe->demodulator_priv;
+       struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+       struct as10x_tune_args tune_args = { 0 };
+
+       /* set frequency */
+       tune_args.freq = c->frequency / 1000;
+
+       /* fix interleaving_mode */
+       tune_args.interleaving_mode = INTLV_NATIVE;
+
+       switch (c->bandwidth_hz) {
+       case 8000000:
+               tune_args.bandwidth = BW_8_MHZ;
+               break;
+       case 7000000:
+               tune_args.bandwidth = BW_7_MHZ;
+               break;
+       case 6000000:
+               tune_args.bandwidth = BW_6_MHZ;
+               break;
+       default:
+               tune_args.bandwidth = BW_8_MHZ;
+       }
+
+       switch (c->guard_interval) {
+       case GUARD_INTERVAL_1_32:
+               tune_args.guard_interval = GUARD_INT_1_32;
+               break;
+       case GUARD_INTERVAL_1_16:
+               tune_args.guard_interval = GUARD_INT_1_16;
+               break;
+       case GUARD_INTERVAL_1_8:
+               tune_args.guard_interval = GUARD_INT_1_8;
+               break;
+       case GUARD_INTERVAL_1_4:
+               tune_args.guard_interval = GUARD_INT_1_4;
+               break;
+       case GUARD_INTERVAL_AUTO:
+       default:
+               tune_args.guard_interval = GUARD_UNKNOWN;
+               break;
+       }
+
+       switch (c->modulation) {
+       case QPSK:
+               tune_args.modulation = CONST_QPSK;
+               break;
+       case QAM_16:
+               tune_args.modulation = CONST_QAM16;
+               break;
+       case QAM_64:
+               tune_args.modulation = CONST_QAM64;
+               break;
+       default:
+               tune_args.modulation = CONST_UNKNOWN;
+               break;
+       }
+
+       switch (c->transmission_mode) {
+       case TRANSMISSION_MODE_2K:
+               tune_args.transmission_mode = TRANS_MODE_2K;
+               break;
+       case TRANSMISSION_MODE_8K:
+               tune_args.transmission_mode = TRANS_MODE_8K;
+               break;
+       default:
+               tune_args.transmission_mode = TRANS_MODE_UNKNOWN;
+       }
+
+       switch (c->hierarchy) {
+       case HIERARCHY_NONE:
+               tune_args.hierarchy = HIER_NONE;
+               break;
+       case HIERARCHY_1:
+               tune_args.hierarchy = HIER_ALPHA_1;
+               break;
+       case HIERARCHY_2:
+               tune_args.hierarchy = HIER_ALPHA_2;
+               break;
+       case HIERARCHY_4:
+               tune_args.hierarchy = HIER_ALPHA_4;
+               break;
+       case HIERARCHY_AUTO:
+               tune_args.hierarchy = HIER_UNKNOWN;
+               break;
+       }
+
+       pr_debug("as102: tuner parameters: freq: %d  bw: 0x%02x  gi: 0x%02x\n",
+                       c->frequency,
+                       tune_args.bandwidth,
+                       tune_args.guard_interval);
+
+       /*
+        * Detect a hierarchy selection
+        * if HP/LP are both set to FEC_NONE, HP will be selected.
+        */
+       if ((tune_args.hierarchy != HIER_NONE) &&
+                      ((c->code_rate_LP == FEC_NONE) ||
+                       (c->code_rate_HP == FEC_NONE))) {
+
+               if (c->code_rate_LP == FEC_NONE) {
+                       tune_args.hier_select = HIER_HIGH_PRIORITY;
+                       tune_args.code_rate =
+                          as102_fe_get_code_rate(c->code_rate_HP);
+               }
+
+               if (c->code_rate_HP == FEC_NONE) {
+                       tune_args.hier_select = HIER_LOW_PRIORITY;
+                       tune_args.code_rate =
+                          as102_fe_get_code_rate(c->code_rate_LP);
+               }
+
+               pr_debug("as102: \thierarchy: 0x%02x  selected: %s  code_rate_%s: 0x%02x\n",
+                       tune_args.hierarchy,
+                       tune_args.hier_select == HIER_HIGH_PRIORITY ?
+                       "HP" : "LP",
+                       tune_args.hier_select == HIER_HIGH_PRIORITY ?
+                       "HP" : "LP",
+                       tune_args.code_rate);
+       } else {
+               tune_args.code_rate =
+                       as102_fe_get_code_rate(c->code_rate_HP);
+       }
+
+       /* Set frontend arguments */
+       return state->ops->set_tune(state->priv, &tune_args);
+}
+
+static int as102_fe_get_frontend(struct dvb_frontend *fe)
+{
+       struct as102_state *state = fe->demodulator_priv;
+       struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+       int ret = 0;
+       struct as10x_tps tps = { 0 };
+
+       /* send abilis command: GET_TPS */
+       ret = state->ops->get_tps(state->priv, &tps);
+       if (ret < 0)
+               return ret;
+
+       /* extract constellation */
+       switch (tps.modulation) {
+       case CONST_QPSK:
+               c->modulation = QPSK;
+               break;
+       case CONST_QAM16:
+               c->modulation = QAM_16;
+               break;
+       case CONST_QAM64:
+               c->modulation = QAM_64;
+               break;
+       }
+
+       /* extract hierarchy */
+       switch (tps.hierarchy) {
+       case HIER_NONE:
+               c->hierarchy = HIERARCHY_NONE;
+               break;
+       case HIER_ALPHA_1:
+               c->hierarchy = HIERARCHY_1;
+               break;
+       case HIER_ALPHA_2:
+               c->hierarchy = HIERARCHY_2;
+               break;
+       case HIER_ALPHA_4:
+               c->hierarchy = HIERARCHY_4;
+               break;
+       }
+
+       /* extract code rate HP */
+       switch (tps.code_rate_HP) {
+       case CODE_RATE_1_2:
+               c->code_rate_HP = FEC_1_2;
+               break;
+       case CODE_RATE_2_3:
+               c->code_rate_HP = FEC_2_3;
+               break;
+       case CODE_RATE_3_4:
+               c->code_rate_HP = FEC_3_4;
+               break;
+       case CODE_RATE_5_6:
+               c->code_rate_HP = FEC_5_6;
+               break;
+       case CODE_RATE_7_8:
+               c->code_rate_HP = FEC_7_8;
+               break;
+       }
+
+       /* extract code rate LP */
+       switch (tps.code_rate_LP) {
+       case CODE_RATE_1_2:
+               c->code_rate_LP = FEC_1_2;
+               break;
+       case CODE_RATE_2_3:
+               c->code_rate_LP = FEC_2_3;
+               break;
+       case CODE_RATE_3_4:
+               c->code_rate_LP = FEC_3_4;
+               break;
+       case CODE_RATE_5_6:
+               c->code_rate_LP = FEC_5_6;
+               break;
+       case CODE_RATE_7_8:
+               c->code_rate_LP = FEC_7_8;
+               break;
+       }
+
+       /* extract guard interval */
+       switch (tps.guard_interval) {
+       case GUARD_INT_1_32:
+               c->guard_interval = GUARD_INTERVAL_1_32;
+               break;
+       case GUARD_INT_1_16:
+               c->guard_interval = GUARD_INTERVAL_1_16;
+               break;
+       case GUARD_INT_1_8:
+               c->guard_interval = GUARD_INTERVAL_1_8;
+               break;
+       case GUARD_INT_1_4:
+               c->guard_interval = GUARD_INTERVAL_1_4;
+               break;
+       }
+
+       /* extract transmission mode */
+       switch (tps.transmission_mode) {
+       case TRANS_MODE_2K:
+               c->transmission_mode = TRANSMISSION_MODE_2K;
+               break;
+       case TRANS_MODE_8K:
+               c->transmission_mode = TRANSMISSION_MODE_8K;
+               break;
+       }
+
+       return 0;
+}
+
+static int as102_fe_get_tune_settings(struct dvb_frontend *fe,
+                       struct dvb_frontend_tune_settings *settings) {
+
+       settings->min_delay_ms = 1000;
+
+       return 0;
+}
+
+static int as102_fe_read_status(struct dvb_frontend *fe, fe_status_t *status)
+{
+       int ret = 0;
+       struct as102_state *state = fe->demodulator_priv;
+       struct as10x_tune_status tstate = { 0 };
+
+       /* send abilis command: GET_TUNE_STATUS */
+       ret = state->ops->get_status(state->priv, &tstate);
+       if (ret < 0)
+               return ret;
+
+       state->signal_strength  = tstate.signal_strength;
+       state->ber  = tstate.BER;
+
+       switch (tstate.tune_state) {
+       case TUNE_STATUS_SIGNAL_DVB_OK:
+               *status = FE_HAS_SIGNAL | FE_HAS_CARRIER;
+               break;
+       case TUNE_STATUS_STREAM_DETECTED:
+               *status = FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_SYNC |
+                         FE_HAS_VITERBI;
+               break;
+       case TUNE_STATUS_STREAM_TUNED:
+               *status = FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_SYNC |
+                         FE_HAS_LOCK | FE_HAS_VITERBI;
+               break;
+       default:
+               *status = TUNE_STATUS_NOT_TUNED;
+       }
+
+       pr_debug("as102: tuner status: 0x%02x, strength %d, per: %d, ber: %d\n",
+                tstate.tune_state, tstate.signal_strength,
+                tstate.PER, tstate.BER);
+
+       if (!(*status & FE_HAS_LOCK)) {
+               memset(&state->demod_stats, 0, sizeof(state->demod_stats));
+               return 0;
+       }
+
+       ret = state->ops->get_stats(state->priv, &state->demod_stats);
+       if (ret < 0)
+               memset(&state->demod_stats, 0, sizeof(state->demod_stats));
+
+       return ret;
+}
+
+/*
+ * Note:
+ * - in AS102 SNR=MER
+ *   - the SNR will be returned in linear terms, i.e. not in dB
+ *   - the accuracy equals Â±2dB for a SNR range from 4dB to 30dB
+ *   - the accuracy is >2dB for SNR values outside this range
+ */
+static int as102_fe_read_snr(struct dvb_frontend *fe, u16 *snr)
+{
+       struct as102_state *state = fe->demodulator_priv;
+
+       *snr = state->demod_stats.mer;
+
+       return 0;
+}
+
+static int as102_fe_read_ber(struct dvb_frontend *fe, u32 *ber)
+{
+       struct as102_state *state = fe->demodulator_priv;
+
+       *ber = state->ber;
+
+       return 0;
+}
+
+static int as102_fe_read_signal_strength(struct dvb_frontend *fe,
+                                        u16 *strength)
+{
+       struct as102_state *state = fe->demodulator_priv;
+
+       *strength = (((0xffff * 400) * state->signal_strength + 41000) * 2);
+
+       return 0;
+}
+
+static int as102_fe_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
+{
+       struct as102_state *state = fe->demodulator_priv;
+
+       if (state->demod_stats.has_started)
+               *ucblocks = state->demod_stats.bad_frame_count;
+       else
+               *ucblocks = 0;
+
+       return 0;
+}
+
+static int as102_fe_ts_bus_ctrl(struct dvb_frontend *fe, int acquire)
+{
+       struct as102_state *state = fe->demodulator_priv;
+
+       return state->ops->stream_ctrl(state->priv, acquire,
+                                     state->elna_cfg);
+}
+
+static void as102_fe_release(struct dvb_frontend *fe)
+{
+       struct as102_state *state = fe->demodulator_priv;
+
+       kfree(state);
+}
+
+
+static struct dvb_frontend_ops as102_fe_ops = {
+       .delsys = { SYS_DVBT },
+       .info = {
+               .name                   = "Abilis AS102 DVB-T",
+               .frequency_min          = 174000000,
+               .frequency_max          = 862000000,
+               .frequency_stepsize     = 166667,
+               .caps = FE_CAN_INVERSION_AUTO
+                       | FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4
+                       | FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO
+                       | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QPSK
+                       | FE_CAN_QAM_AUTO
+                       | FE_CAN_TRANSMISSION_MODE_AUTO
+                       | FE_CAN_GUARD_INTERVAL_AUTO
+                       | FE_CAN_HIERARCHY_AUTO
+                       | FE_CAN_RECOVER
+                       | FE_CAN_MUTE_TS
+       },
+
+       .set_frontend           = as102_fe_set_frontend,
+       .get_frontend           = as102_fe_get_frontend,
+       .get_tune_settings      = as102_fe_get_tune_settings,
+
+       .read_status            = as102_fe_read_status,
+       .read_snr               = as102_fe_read_snr,
+       .read_ber               = as102_fe_read_ber,
+       .read_signal_strength   = as102_fe_read_signal_strength,
+       .read_ucblocks          = as102_fe_read_ucblocks,
+       .ts_bus_ctrl            = as102_fe_ts_bus_ctrl,
+       .release                = as102_fe_release,
+};
+
+struct dvb_frontend *as102_attach(const char *name,
+                                 const struct as102_fe_ops *ops,
+                                 void *priv,
+                                 uint8_t elna_cfg)
+{
+       struct as102_state *state;
+       struct dvb_frontend *fe;
+
+       state = kzalloc(sizeof(struct as102_state), GFP_KERNEL);
+       if (state == NULL) {
+               pr_err("%s: unable to allocate memory for state\n", __func__);
+               return NULL;
+       }
+       fe = &state->frontend;
+       fe->demodulator_priv = state;
+       state->ops = ops;
+       state->priv = priv;
+       state->elna_cfg = elna_cfg;
+
+       /* init frontend callback ops */
+       memcpy(&fe->ops, &as102_fe_ops, sizeof(struct dvb_frontend_ops));
+       strncpy(fe->ops.info.name, name, sizeof(fe->ops.info.name));
+
+       return fe;
+
+}
+EXPORT_SYMBOL_GPL(as102_attach);
+
+MODULE_DESCRIPTION("as102-fe");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Pierrick Hascoet <pierrick.hascoet@abilis.com>");
diff --git a/drivers/media/dvb-frontends/as102_fe.h b/drivers/media/dvb-frontends/as102_fe.h
new file mode 100644 (file)
index 0000000..a7c9143
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ * Abilis Systems Single DVB-T Receiver
+ * Copyright (C) 2014 Mauro Carvalho Chehab <m.chehab@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, 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 "as102_fe_types.h"
+
+struct as102_fe_ops {
+       int (*set_tune)(void *priv, struct as10x_tune_args *tune_args);
+       int (*get_tps)(void *priv, struct as10x_tps *tps);
+       int (*get_status)(void *priv, struct as10x_tune_status *tstate);
+       int (*get_stats)(void *priv, struct as10x_demod_stats *demod_stats);
+       int (*stream_ctrl)(void *priv, int acquire, uint32_t elna_cfg);
+};
+
+struct dvb_frontend *as102_attach(const char *name,
+                                 const struct as102_fe_ops *ops,
+                                 void *priv,
+                                 uint8_t elna_cfg);
diff --git a/drivers/media/dvb-frontends/as102_fe_types.h b/drivers/media/dvb-frontends/as102_fe_types.h
new file mode 100644 (file)
index 0000000..80a5398
--- /dev/null
@@ -0,0 +1,188 @@
+/*
+ * Abilis Systems Single DVB-T Receiver
+ * Copyright (C) 2008 Pierrick Hascoet <pierrick.hascoet@abilis.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, 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 _AS10X_TYPES_H_
+#define _AS10X_TYPES_H_
+
+/*********************************/
+/*       MACRO DEFINITIONS       */
+/*********************************/
+
+/* bandwidth constant values */
+#define BW_5_MHZ               0x00
+#define BW_6_MHZ               0x01
+#define BW_7_MHZ               0x02
+#define BW_8_MHZ               0x03
+
+/* hierarchy priority selection values */
+#define HIER_NO_PRIORITY       0x00
+#define HIER_LOW_PRIORITY      0x01
+#define HIER_HIGH_PRIORITY     0x02
+
+/* constellation available values */
+#define CONST_QPSK             0x00
+#define CONST_QAM16            0x01
+#define CONST_QAM64            0x02
+#define CONST_UNKNOWN          0xFF
+
+/* hierarchy available values */
+#define HIER_NONE              0x00
+#define HIER_ALPHA_1           0x01
+#define HIER_ALPHA_2           0x02
+#define HIER_ALPHA_4           0x03
+#define HIER_UNKNOWN           0xFF
+
+/* interleaving available values */
+#define INTLV_NATIVE           0x00
+#define INTLV_IN_DEPTH         0x01
+#define INTLV_UNKNOWN          0xFF
+
+/* code rate available values */
+#define CODE_RATE_1_2          0x00
+#define CODE_RATE_2_3          0x01
+#define CODE_RATE_3_4          0x02
+#define CODE_RATE_5_6          0x03
+#define CODE_RATE_7_8          0x04
+#define CODE_RATE_UNKNOWN      0xFF
+
+/* guard interval available values */
+#define GUARD_INT_1_32         0x00
+#define GUARD_INT_1_16         0x01
+#define GUARD_INT_1_8          0x02
+#define GUARD_INT_1_4          0x03
+#define GUARD_UNKNOWN          0xFF
+
+/* transmission mode available values */
+#define TRANS_MODE_2K          0x00
+#define TRANS_MODE_8K          0x01
+#define TRANS_MODE_4K          0x02
+#define TRANS_MODE_UNKNOWN     0xFF
+
+/* DVBH signalling available values */
+#define TIMESLICING_PRESENT    0x01
+#define MPE_FEC_PRESENT                0x02
+
+/* tune state available */
+#define TUNE_STATUS_NOT_TUNED          0x00
+#define TUNE_STATUS_IDLE               0x01
+#define TUNE_STATUS_LOCKING            0x02
+#define TUNE_STATUS_SIGNAL_DVB_OK      0x03
+#define TUNE_STATUS_STREAM_DETECTED    0x04
+#define TUNE_STATUS_STREAM_TUNED       0x05
+#define TUNE_STATUS_ERROR              0xFF
+
+/* available TS FID filter types */
+#define TS_PID_TYPE_TS         0
+#define TS_PID_TYPE_PSI_SI     1
+#define TS_PID_TYPE_MPE                2
+
+/* number of echos available */
+#define MAX_ECHOS      15
+
+/* Context types */
+#define CONTEXT_LNA                    1010
+#define CONTEXT_ELNA_HYSTERESIS                4003
+#define CONTEXT_ELNA_GAIN              4004
+#define CONTEXT_MER_THRESHOLD          5005
+#define CONTEXT_MER_OFFSET             5006
+#define CONTEXT_IR_STATE               7000
+#define CONTEXT_TSOUT_MSB_FIRST                7004
+#define CONTEXT_TSOUT_FALLING_EDGE     7005
+
+/* Configuration modes */
+#define CFG_MODE_ON    0
+#define CFG_MODE_OFF   1
+#define CFG_MODE_AUTO  2
+
+struct as10x_tps {
+       uint8_t modulation;
+       uint8_t hierarchy;
+       uint8_t interleaving_mode;
+       uint8_t code_rate_HP;
+       uint8_t code_rate_LP;
+       uint8_t guard_interval;
+       uint8_t transmission_mode;
+       uint8_t DVBH_mask_HP;
+       uint8_t DVBH_mask_LP;
+       uint16_t cell_ID;
+} __packed;
+
+struct as10x_tune_args {
+       /* frequency */
+       uint32_t freq;
+       /* bandwidth */
+       uint8_t bandwidth;
+       /* hierarchy selection */
+       uint8_t hier_select;
+       /* constellation */
+       uint8_t modulation;
+       /* hierarchy */
+       uint8_t hierarchy;
+       /* interleaving mode */
+       uint8_t interleaving_mode;
+       /* code rate */
+       uint8_t code_rate;
+       /* guard interval */
+       uint8_t guard_interval;
+       /* transmission mode */
+       uint8_t transmission_mode;
+} __packed;
+
+struct as10x_tune_status {
+       /* tune status */
+       uint8_t tune_state;
+       /* signal strength */
+       int16_t signal_strength;
+       /* packet error rate 10^-4 */
+       uint16_t PER;
+       /* bit error rate 10^-4 */
+       uint16_t BER;
+} __packed;
+
+struct as10x_demod_stats {
+       /* frame counter */
+       uint32_t frame_count;
+       /* Bad frame counter */
+       uint32_t bad_frame_count;
+       /* Number of wrong bytes fixed by Reed-Solomon */
+       uint32_t bytes_fixed_by_rs;
+       /* Averaged MER */
+       uint16_t mer;
+       /* statistics calculation state indicator (started or not) */
+       uint8_t has_started;
+} __packed;
+
+struct as10x_ts_filter {
+       uint16_t pid;  /* valid PID value 0x00 : 0x2000 */
+       uint8_t  type; /* Red TS_PID_TYPE_<N> values */
+       uint8_t  idx;  /* index in filtering table */
+} __packed;
+
+struct as10x_register_value {
+       uint8_t mode;
+       union {
+               uint8_t  value8;   /* 8 bit value */
+               uint16_t value16;  /* 16 bit value */
+               uint32_t value32;  /* 32 bit value */
+       } __packed u;
+} __packed;
+
+struct as10x_register_addr {
+       /* register addr */
+       uint32_t addr;
+       /* register mode access */
+       uint8_t mode;
+};
+
+#endif
index 39a29dd29519cba8573fd7ce1837e46d7df1f73b..638c7aa0fb7e6ae90434d10d92c22879a89a860c 100644 (file)
@@ -639,12 +639,12 @@ static int bcm3510_download_firmware(struct dvb_frontend* fe)
                err("could not load firmware (%s): %d",BCM3510_DEFAULT_FIRMWARE,ret);
                return ret;
        }
-       deb_info("got firmware: %zd\n",fw->size);
+       deb_info("got firmware: %zu\n", fw->size);
 
        b = fw->data;
        for (i = 0; i < fw->size;) {
-               addr = le16_to_cpu( *( (u16 *)&b[i] ) );
-               len  = le16_to_cpu( *( (u16 *)&b[i+2] ) );
+               addr = le16_to_cpu(*((__le16 *)&b[i]));
+               len  = le16_to_cpu(*((__le16 *)&b[i+2]));
                deb_info("firmware chunk, addr: 0x%04x, len: 0x%04x, total length: 0x%04zx\n",addr,len,fw->size);
                if ((ret = bcm3510_write_ram(st,addr,&b[i+4],len)) < 0) {
                        err("firmware download failed: %d\n",ret);
index 0f4657e01cdeaa07d8f5b9b2c3e58b237e6058a1..149fdca3fb44e33fd60cda6c44de66041019c86c 100644 (file)
@@ -65,7 +65,7 @@ int cxd2820r_set_frontend_c(struct dvb_frontend *fe)
        }
 
        priv->delivery_system = SYS_DVBC_ANNEX_A;
-       priv->ber_running = 0; /* tune stops BER counter */
+       priv->ber_running = false; /* tune stops BER counter */
 
        /* program IF frequency */
        if (fe->ops.tuner_ops.get_if_frequency) {
@@ -168,7 +168,7 @@ int cxd2820r_read_ber_c(struct dvb_frontend *fe, u32 *ber)
                        start_ber = 1;
                }
        } else {
-               priv->ber_running = 1;
+               priv->ber_running = true;
                start_ber = 1;
        }
 
index 51ef893126151071c511cd7f9e77242507f6065b..422e84bbb008ffe685fb149f529c27ce4957cc70 100644 (file)
@@ -564,10 +564,10 @@ static enum dvbfe_search cxd2820r_search(struct dvb_frontend *fe)
 
        /* check if we have a valid signal */
        if (status & FE_HAS_LOCK) {
-               priv->last_tune_failed = 0;
+               priv->last_tune_failed = false;
                return DVBFE_ALGO_SEARCH_SUCCESS;
        } else {
-               priv->last_tune_failed = 1;
+               priv->last_tune_failed = true;
                return DVBFE_ALGO_SEARCH_AGAIN;
        }
 
index 9b5a45b907bcfca70f8e31ace191be9447da865c..51401d036530fbfd42d021c293a2a979b43af9c9 100644 (file)
@@ -89,7 +89,7 @@ int cxd2820r_set_frontend_t(struct dvb_frontend *fe)
        }
 
        priv->delivery_system = SYS_DVBT;
-       priv->ber_running = 0; /* tune stops BER counter */
+       priv->ber_running = false; /* tune stops BER counter */
 
        /* program IF frequency */
        if (fe->ops.tuner_ops.get_if_frequency) {
@@ -272,7 +272,7 @@ int cxd2820r_read_ber_t(struct dvb_frontend *fe, u32 *ber)
                        start_ber = 1;
                }
        } else {
-               priv->ber_running = 1;
+               priv->ber_running = true;
                start_ber = 1;
        }
 
index 661760d60232aa928015ad0cccbbd25c7a6d4948..589134e951758c1ab984be32e1becf88d3631ea5 100644 (file)
@@ -2559,7 +2559,7 @@ static void dib7090_setHostBusMux(struct dib7000p_state *state, int mode)
        dib7000p_write_word(state, 1288, reg_1288);
 }
 
-int dib7090_set_diversity_in(struct dvb_frontend *fe, int onoff)
+static int dib7090_set_diversity_in(struct dvb_frontend *fe, int onoff)
 {
        struct dib7000p_state *state = fe->demodulator_priv;
        u16 reg_1287;
index 7ca7a21df18330649ad23c255349423e33288871..5ec221ffdfcae3a05e88e971f9795785c680752a 100644 (file)
@@ -2174,7 +2174,7 @@ int drxj_dap_atomic_read_reg32(struct i2c_device_addr *dev_addr,
                                     u32 addr,
                                     u32 *data, u32 flags)
 {
-       u8 buf[sizeof(*data)];
+       u8 buf[sizeof(*data)] = { 0 };
        int rc = -EIO;
        u32 word = 0;
 
@@ -4193,7 +4193,7 @@ int drxj_dap_scu_atomic_read_reg16(struct i2c_device_addr *dev_addr,
                                         u32 addr,
                                         u16 *data, u32 flags)
 {
-       u8 buf[2];
+       u8 buf[2] = { 0 };
        int rc = -EIO;
        u16 word = 0;
 
@@ -10667,7 +10667,7 @@ ctrl_sig_quality(struct drx_demod_instance *demod,
        enum drx_standard standard = ext_attr->standard;
        int rc;
        u32 ber, cnt, err, pkt;
-       u16 mer, strength;
+       u16 mer, strength = 0;
 
        rc = get_sig_strength(demod, &strength);
        if (rc < 0) {
@@ -11602,7 +11602,7 @@ static u16 drx_u_code_compute_crc(u8 *block_data, u16 nr_words)
        u32 carry = 0;
 
        while (i < nr_words) {
-               crc_word |= (u32)be16_to_cpu(*(u32 *)(block_data));
+               crc_word |= (u32)be16_to_cpu(*(__be16 *)(block_data));
                for (j = 0; j < 16; j++) {
                        crc_word <<= 1;
                        if (carry != 0)
@@ -11629,7 +11629,7 @@ static int drx_check_firmware(struct drx_demod_instance *demod, u8 *mc_data,
        int i;
        unsigned count = 2 * sizeof(u16);
        u32 mc_dev_type, mc_version, mc_base_version;
-       u16 mc_nr_of_blks = be16_to_cpu(*(u32 *)(mc_data + sizeof(u16)));
+       u16 mc_nr_of_blks = be16_to_cpu(*(__be16 *)(mc_data + sizeof(u16)));
 
        /*
         * Scan microcode blocks first for version info
@@ -11647,13 +11647,13 @@ static int drx_check_firmware(struct drx_demod_instance *demod, u8 *mc_data,
                        goto eof;
 
                /* Process block header */
-               block_hdr.addr = be32_to_cpu(*(u32 *)(mc_data + count));
+               block_hdr.addr = be32_to_cpu(*(__be32 *)(mc_data + count));
                count += sizeof(u32);
-               block_hdr.size = be16_to_cpu(*(u32 *)(mc_data + count));
+               block_hdr.size = be16_to_cpu(*(__be16 *)(mc_data + count));
                count += sizeof(u16);
-               block_hdr.flags = be16_to_cpu(*(u32 *)(mc_data + count));
+               block_hdr.flags = be16_to_cpu(*(__be16 *)(mc_data + count));
                count += sizeof(u16);
-               block_hdr.CRC = be16_to_cpu(*(u32 *)(mc_data + count));
+               block_hdr.CRC = be16_to_cpu(*(__be16 *)(mc_data + count));
                count += sizeof(u16);
 
                pr_debug("%u: addr %u, size %u, flags 0x%04x, CRC 0x%04x\n",
@@ -11667,7 +11667,7 @@ static int drx_check_firmware(struct drx_demod_instance *demod, u8 *mc_data,
                        if (block_hdr.addr + sizeof(u16) > size)
                                goto eof;
 
-                       auxtype = be16_to_cpu(*(u32 *)(auxblk));
+                       auxtype = be16_to_cpu(*(__be16 *)(auxblk));
 
                        /* Aux block. Check type */
                        if (DRX_ISMCVERTYPE(auxtype)) {
@@ -11675,11 +11675,11 @@ static int drx_check_firmware(struct drx_demod_instance *demod, u8 *mc_data,
                                        goto eof;
 
                                auxblk += sizeof(u16);
-                               mc_dev_type = be32_to_cpu(*(u32 *)(auxblk));
+                               mc_dev_type = be32_to_cpu(*(__be32 *)(auxblk));
                                auxblk += sizeof(u32);
-                               mc_version = be32_to_cpu(*(u32 *)(auxblk));
+                               mc_version = be32_to_cpu(*(__be32 *)(auxblk));
                                auxblk += sizeof(u32);
-                               mc_base_version = be32_to_cpu(*(u32 *)(auxblk));
+                               mc_base_version = be32_to_cpu(*(__be32 *)(auxblk));
 
                                DRX_ATTR_MCRECORD(demod).aux_type = auxtype;
                                DRX_ATTR_MCRECORD(demod).mc_dev_type = mc_dev_type;
@@ -11765,9 +11765,9 @@ static int drx_ctrl_u_code(struct drx_demod_instance *demod,
 
        mc_data = (void *)mc_data_init;
        /* Check data */
-       mc_magic_word = be16_to_cpu(*(u32 *)(mc_data));
+       mc_magic_word = be16_to_cpu(*(__be16 *)(mc_data));
        mc_data += sizeof(u16);
-       mc_nr_of_blks = be16_to_cpu(*(u32 *)(mc_data));
+       mc_nr_of_blks = be16_to_cpu(*(__be16 *)(mc_data));
        mc_data += sizeof(u16);
 
        if ((mc_magic_word != DRX_UCODE_MAGIC_WORD) || (mc_nr_of_blks == 0)) {
@@ -11791,13 +11791,13 @@ static int drx_ctrl_u_code(struct drx_demod_instance *demod,
                u16 mc_block_nr_bytes = 0;
 
                /* Process block header */
-               block_hdr.addr = be32_to_cpu(*(u32 *)(mc_data));
+               block_hdr.addr = be32_to_cpu(*(__be32 *)(mc_data));
                mc_data += sizeof(u32);
-               block_hdr.size = be16_to_cpu(*(u32 *)(mc_data));
+               block_hdr.size = be16_to_cpu(*(__be16 *)(mc_data));
                mc_data += sizeof(u16);
-               block_hdr.flags = be16_to_cpu(*(u32 *)(mc_data));
+               block_hdr.flags = be16_to_cpu(*(__be16 *)(mc_data));
                mc_data += sizeof(u16);
-               block_hdr.CRC = be16_to_cpu(*(u32 *)(mc_data));
+               block_hdr.CRC = be16_to_cpu(*(__be16 *)(mc_data));
                mc_data += sizeof(u16);
 
                pr_debug("%u: addr %u, size %u, flags 0x%04x, CRC 0x%04x\n",
index ae2276db77bc8ff448aeb50a4314e1723619b470..687e893d29fec6e0429e603832bc26eab3b2cbeb 100644 (file)
@@ -2628,10 +2628,11 @@ static int DRXD_init(struct drxd_state *state, const u8 *fw, u32 fw_size)
                        break;
 
                /* Apply I2c address patch to B1 */
-               if (!state->type_A && state->m_HiI2cPatch != NULL)
+               if (!state->type_A && state->m_HiI2cPatch != NULL) {
                        status = WriteTable(state, state->m_HiI2cPatch);
                        if (status < 0)
                                break;
+               }
 
                if (state->type_A) {
                        /* HI firmware patch for UIO readout,
@@ -2830,14 +2831,8 @@ static int drxd_read_status(struct dvb_frontend *fe, fe_status_t * status)
 static int drxd_init(struct dvb_frontend *fe)
 {
        struct drxd_state *state = fe->demodulator_priv;
-       int err = 0;
 
-/*     if (request_firmware(&state->fw, "drxd.fw", state->dev)<0) */
        return DRXD_init(state, NULL, 0);
-
-       err = DRXD_init(state, state->fw->data, state->fw->size);
-       release_firmware(state->fw);
-       return err;
 }
 
 static int drxd_config_i2c(struct dvb_frontend *fe, int onoff)
index cce94a75b2e1f74c4dc05c0715f6320f130fe988..672195147d015778cefbfefd5fdbf1126e1e67be 100644 (file)
@@ -1028,7 +1028,7 @@ static int hi_command(struct drxk_state *state, u16 cmd, u16 *p_result)
                    ((state->m_hi_cfg_ctrl) &
                     SIO_HI_RA_RAM_PAR_5_CFG_SLEEP__M) ==
                    SIO_HI_RA_RAM_PAR_5_CFG_SLEEP_ZZZ);
-       if (powerdown_cmd == false) {
+       if (!powerdown_cmd) {
                /* Wait until command rdy */
                u32 retry_count = 0;
                u16 wait_cmd;
@@ -1129,7 +1129,7 @@ static int mpegts_configure_pins(struct drxk_state *state, bool mpeg_enable)
        if (status < 0)
                goto error;
 
-       if (mpeg_enable == false) {
+       if (!mpeg_enable) {
                /*  Set MPEG TS pads to inputmode */
                status = write16(state, SIO_PDR_MSTRT_CFG__A, 0x0000);
                if (status < 0)
@@ -1190,7 +1190,7 @@ static int mpegts_configure_pins(struct drxk_state *state, bool mpeg_enable)
                if (status < 0)
                        goto error;
 
-               if (state->m_enable_parallel == true) {
+               if (state->m_enable_parallel) {
                        /* parallel -> enable MD1 to MD7 */
                        status = write16(state, SIO_PDR_MD1_CFG__A,
                                         sio_pdr_mdx_cfg);
@@ -1392,7 +1392,7 @@ static int dvbt_enable_ofdm_token_ring(struct drxk_state *state, bool enable)
 
        dprintk(1, "\n");
 
-       if (enable == false) {
+       if (!enable) {
                desired_ctrl = SIO_OFDM_SH_OFDM_RING_ENABLE_OFF;
                desired_status = SIO_OFDM_SH_OFDM_RING_STATUS_DOWN;
        }
@@ -2012,7 +2012,7 @@ static int mpegts_dto_setup(struct drxk_state *state,
                goto error;
        fec_oc_reg_mode &= (~FEC_OC_MODE_PARITY__M);
        fec_oc_reg_ipr_mode &= (~FEC_OC_IPR_MODE_MVAL_DIS_PAR__M);
-       if (state->m_insert_rs_byte == true) {
+       if (state->m_insert_rs_byte) {
                /* enable parity symbol forward */
                fec_oc_reg_mode |= FEC_OC_MODE_PARITY__M;
                /* MVAL disable during parity bytes */
@@ -2023,7 +2023,7 @@ static int mpegts_dto_setup(struct drxk_state *state,
 
        /* Check serial or parallel output */
        fec_oc_reg_ipr_mode &= (~(FEC_OC_IPR_MODE_SERIAL__M));
-       if (state->m_enable_parallel == false) {
+       if (!state->m_enable_parallel) {
                /* MPEG data output is serial -> set ipr_mode[0] */
                fec_oc_reg_ipr_mode |= FEC_OC_IPR_MODE_SERIAL__M;
        }
@@ -2136,19 +2136,19 @@ static int mpegts_configure_polarity(struct drxk_state *state)
 
        /* Control selective inversion of output bits */
        fec_oc_reg_ipr_invert &= (~(invert_data_mask));
-       if (state->m_invert_data == true)
+       if (state->m_invert_data)
                fec_oc_reg_ipr_invert |= invert_data_mask;
        fec_oc_reg_ipr_invert &= (~(FEC_OC_IPR_INVERT_MERR__M));
-       if (state->m_invert_err == true)
+       if (state->m_invert_err)
                fec_oc_reg_ipr_invert |= FEC_OC_IPR_INVERT_MERR__M;
        fec_oc_reg_ipr_invert &= (~(FEC_OC_IPR_INVERT_MSTRT__M));
-       if (state->m_invert_str == true)
+       if (state->m_invert_str)
                fec_oc_reg_ipr_invert |= FEC_OC_IPR_INVERT_MSTRT__M;
        fec_oc_reg_ipr_invert &= (~(FEC_OC_IPR_INVERT_MVAL__M));
-       if (state->m_invert_val == true)
+       if (state->m_invert_val)
                fec_oc_reg_ipr_invert |= FEC_OC_IPR_INVERT_MVAL__M;
        fec_oc_reg_ipr_invert &= (~(FEC_OC_IPR_INVERT_MCLK__M));
-       if (state->m_invert_clk == true)
+       if (state->m_invert_clk)
                fec_oc_reg_ipr_invert |= FEC_OC_IPR_INVERT_MCLK__M;
 
        return write16(state, FEC_OC_IPR_INVERT__A, fec_oc_reg_ipr_invert);
@@ -2220,12 +2220,13 @@ static int set_agc_rf(struct drxk_state *state,
                }
 
                /* Set TOP, only if IF-AGC is in AUTO mode */
-               if (p_if_agc_settings->ctrl_mode == DRXK_AGC_CTRL_AUTO)
+               if (p_if_agc_settings->ctrl_mode == DRXK_AGC_CTRL_AUTO) {
                        status = write16(state,
                                         SCU_RAM_AGC_IF_IACCU_HI_TGT_MAX__A,
                                         p_agc_cfg->top);
                        if (status < 0)
                                goto error;
+               }
 
                /* Cut-Off current */
                status = write16(state, SCU_RAM_AGC_RF_IACCU_HI_CO__A,
@@ -3352,7 +3353,7 @@ static int dvbt_ctrl_set_inc_enable(struct drxk_state *state, bool *enabled)
        int status;
 
        dprintk(1, "\n");
-       if (*enabled == true)
+       if (*enabled)
                status = write16(state, IQM_CF_BYPASSDET__A, 0);
        else
                status = write16(state, IQM_CF_BYPASSDET__A, 1);
@@ -3368,7 +3369,7 @@ static int dvbt_ctrl_set_fr_enable(struct drxk_state *state, bool *enabled)
        int status;
 
        dprintk(1, "\n");
-       if (*enabled == true) {
+       if (*enabled) {
                /* write mask to 1 */
                status = write16(state, OFDM_SC_RA_RAM_FR_THRES_8K__A,
                                   DEFAULT_FR_THRES_8K);
@@ -6794,11 +6795,11 @@ struct dvb_frontend *drxk_attach(const struct drxk_config *config,
        state->enable_merr_cfg = config->enable_merr_cfg;
 
        if (config->dynamic_clk) {
-               state->m_dvbt_static_clk = 0;
-               state->m_dvbc_static_clk = 0;
+               state->m_dvbt_static_clk = false;
+               state->m_dvbc_static_clk = false;
        } else {
-               state->m_dvbt_static_clk = 1;
-               state->m_dvbc_static_clk = 1;
+               state->m_dvbt_static_clk = true;
+               state->m_dvbc_static_clk = true;
        }
 
 
index dfe0c2f7f1efc749b7b409cbc7bb00262e9eca37..81657e94c5a44dccb4ccea6e3164f02c67db05b5 100644 (file)
@@ -159,6 +159,7 @@ static int m88ds3103_wr_reg_val_tab(struct m88ds3103_priv *priv,
 {
        int ret, i, j;
        u8 buf[83];
+
        dev_dbg(&priv->i2c->dev, "%s: tab_len=%d\n", __func__, tab_len);
 
        if (tab_len > 83) {
@@ -247,8 +248,9 @@ static int m88ds3103_set_frontend(struct dvb_frontend *fe)
        u8 u8tmp, u8tmp1, u8tmp2;
        u8 buf[2];
        u16 u16tmp, divide_ratio;
-       u32 tuner_frequency, target_mclk, ts_clk;
+       u32 tuner_frequency, target_mclk;
        s32 s32tmp;
+
        dev_dbg(&priv->i2c->dev,
                        "%s: delivery_system=%d modulation=%d frequency=%d symbol_rate=%d inversion=%d pilot=%d rolloff=%d\n",
                        __func__, c->delivery_system,
@@ -316,9 +318,6 @@ static int m88ds3103_set_frontend(struct dvb_frontend *fe)
                                target_mclk = 144000;
                        break;
                case M88DS3103_TS_PARALLEL:
-               case M88DS3103_TS_PARALLEL_12:
-               case M88DS3103_TS_PARALLEL_16:
-               case M88DS3103_TS_PARALLEL_19_2:
                case M88DS3103_TS_CI:
                        if (c->symbol_rate < 18000000)
                                target_mclk = 96000;
@@ -352,33 +351,17 @@ static int m88ds3103_set_frontend(struct dvb_frontend *fe)
        switch (priv->cfg->ts_mode) {
        case M88DS3103_TS_SERIAL:
                u8tmp1 = 0x00;
-               ts_clk = 0;
-               u8tmp = 0x46;
+               u8tmp = 0x06;
                break;
        case M88DS3103_TS_SERIAL_D7:
                u8tmp1 = 0x20;
-               ts_clk = 0;
-               u8tmp = 0x46;
+               u8tmp = 0x06;
                break;
        case M88DS3103_TS_PARALLEL:
-               ts_clk = 24000;
-               u8tmp = 0x42;
-               break;
-       case M88DS3103_TS_PARALLEL_12:
-               ts_clk = 12000;
-               u8tmp = 0x42;
-               break;
-       case M88DS3103_TS_PARALLEL_16:
-               ts_clk = 16000;
-               u8tmp = 0x42;
-               break;
-       case M88DS3103_TS_PARALLEL_19_2:
-               ts_clk = 19200;
-               u8tmp = 0x42;
+               u8tmp = 0x02;
                break;
        case M88DS3103_TS_CI:
-               ts_clk = 6000;
-               u8tmp = 0x43;
+               u8tmp = 0x03;
                break;
        default:
                dev_dbg(&priv->i2c->dev, "%s: invalid ts_mode\n", __func__);
@@ -386,6 +369,9 @@ static int m88ds3103_set_frontend(struct dvb_frontend *fe)
                goto err;
        }
 
+       if (priv->cfg->ts_clk_pol)
+               u8tmp |= 0x40;
+
        /* TS mode */
        ret = m88ds3103_wr_reg(priv, 0xfd, u8tmp);
        if (ret)
@@ -399,8 +385,8 @@ static int m88ds3103_set_frontend(struct dvb_frontend *fe)
                        goto err;
        }
 
-       if (ts_clk) {
-               divide_ratio = DIV_ROUND_UP(target_mclk, ts_clk);
+       if (priv->cfg->ts_clk) {
+               divide_ratio = DIV_ROUND_UP(target_mclk, priv->cfg->ts_clk);
                u8tmp1 = divide_ratio / 2;
                u8tmp2 = DIV_ROUND_UP(divide_ratio, 2);
        } else {
@@ -411,7 +397,7 @@ static int m88ds3103_set_frontend(struct dvb_frontend *fe)
 
        dev_dbg(&priv->i2c->dev,
                        "%s: target_mclk=%d ts_clk=%d divide_ratio=%d\n",
-                       __func__, target_mclk, ts_clk, divide_ratio);
+                       __func__, target_mclk, priv->cfg->ts_clk, divide_ratio);
 
        u8tmp1--;
        u8tmp2--;
@@ -536,6 +522,7 @@ static int m88ds3103_init(struct dvb_frontend *fe)
        const struct firmware *fw = NULL;
        u8 *fw_file = M88DS3103_FIRMWARE;
        u8 u8tmp;
+
        dev_dbg(&priv->i2c->dev, "%s:\n", __func__);
 
        /* set cold state by default */
@@ -648,6 +635,7 @@ static int m88ds3103_sleep(struct dvb_frontend *fe)
 {
        struct m88ds3103_priv *priv = fe->demodulator_priv;
        int ret;
+
        dev_dbg(&priv->i2c->dev, "%s:\n", __func__);
 
        priv->delivery_system = SYS_UNDEFINED;
@@ -682,6 +670,7 @@ static int m88ds3103_get_frontend(struct dvb_frontend *fe)
        struct dtv_frontend_properties *c = &fe->dtv_property_cache;
        int ret;
        u8 buf[3];
+
        dev_dbg(&priv->i2c->dev, "%s:\n", __func__);
 
        if (!priv->warm || !(priv->fe_status & FE_HAS_LOCK)) {
@@ -857,6 +846,7 @@ static int m88ds3103_read_snr(struct dvb_frontend *fe, u16 *snr)
        u8 buf[3];
        u16 noise, signal;
        u32 noise_tot, signal_tot;
+
        dev_dbg(&priv->i2c->dev, "%s:\n", __func__);
        /* reports SNR in resolution of 0.1 dB */
 
@@ -933,6 +923,7 @@ static int m88ds3103_read_ber(struct dvb_frontend *fe, u32 *ber)
        int ret;
        unsigned int utmp;
        u8 buf[3], u8tmp;
+
        dev_dbg(&priv->i2c->dev, "%s:\n", __func__);
 
        switch (c->delivery_system) {
@@ -1013,6 +1004,7 @@ static int m88ds3103_set_tone(struct dvb_frontend *fe,
        struct m88ds3103_priv *priv = fe->demodulator_priv;
        int ret;
        u8 u8tmp, tone, reg_a1_mask;
+
        dev_dbg(&priv->i2c->dev, "%s: fe_sec_tone_mode=%d\n", __func__,
                        fe_sec_tone_mode);
 
@@ -1053,12 +1045,64 @@ err:
        return ret;
 }
 
+static int m88ds3103_set_voltage(struct dvb_frontend *fe,
+       fe_sec_voltage_t fe_sec_voltage)
+{
+       struct m88ds3103_priv *priv = fe->demodulator_priv;
+       int ret;
+       u8 u8tmp;
+       bool voltage_sel, voltage_dis;
+
+       dev_dbg(&priv->i2c->dev, "%s: fe_sec_voltage=%d\n", __func__,
+                       fe_sec_voltage);
+
+       if (!priv->warm) {
+               ret = -EAGAIN;
+               goto err;
+       }
+
+       switch (fe_sec_voltage) {
+       case SEC_VOLTAGE_18:
+               voltage_sel = true;
+               voltage_dis = false;
+               break;
+       case SEC_VOLTAGE_13:
+               voltage_sel = false;
+               voltage_dis = false;
+               break;
+       case SEC_VOLTAGE_OFF:
+               voltage_sel = false;
+               voltage_dis = true;
+               break;
+       default:
+               dev_dbg(&priv->i2c->dev, "%s: invalid fe_sec_voltage\n",
+                               __func__);
+               ret = -EINVAL;
+               goto err;
+       }
+
+       /* output pin polarity */
+       voltage_sel ^= priv->cfg->lnb_hv_pol;
+       voltage_dis ^= priv->cfg->lnb_en_pol;
+
+       u8tmp = voltage_dis << 1 | voltage_sel << 0;
+       ret = m88ds3103_wr_reg_mask(priv, 0xa2, u8tmp, 0x03);
+       if (ret)
+               goto err;
+
+       return 0;
+err:
+       dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret);
+       return ret;
+}
+
 static int m88ds3103_diseqc_send_master_cmd(struct dvb_frontend *fe,
                struct dvb_diseqc_master_cmd *diseqc_cmd)
 {
        struct m88ds3103_priv *priv = fe->demodulator_priv;
        int ret, i;
        u8 u8tmp;
+
        dev_dbg(&priv->i2c->dev, "%s: msg=%*ph\n", __func__,
                        diseqc_cmd->msg_len, diseqc_cmd->msg);
 
@@ -1130,6 +1174,7 @@ static int m88ds3103_diseqc_send_burst(struct dvb_frontend *fe,
        struct m88ds3103_priv *priv = fe->demodulator_priv;
        int ret, i;
        u8 u8tmp, burst;
+
        dev_dbg(&priv->i2c->dev, "%s: fe_sec_mini_cmd=%d\n", __func__,
                        fe_sec_mini_cmd);
 
@@ -1202,6 +1247,7 @@ static int m88ds3103_get_tune_settings(struct dvb_frontend *fe,
 static void m88ds3103_release(struct dvb_frontend *fe)
 {
        struct m88ds3103_priv *priv = fe->demodulator_priv;
+
        i2c_del_mux_adapter(priv->i2c_adapter);
        kfree(priv);
 }
@@ -1370,6 +1416,7 @@ static struct dvb_frontend_ops m88ds3103_ops = {
        .diseqc_send_burst = m88ds3103_diseqc_send_burst,
 
        .set_tone = m88ds3103_set_tone,
+       .set_voltage = m88ds3103_set_voltage,
 };
 
 MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
index bbb7e3aa56755f886db48ffb6e4c34897b31cb2e..9b3b4962da7c1653171c56d8f2f0dd6693a6c59d 100644 (file)
@@ -47,13 +47,22 @@ struct m88ds3103_config {
         */
 #define M88DS3103_TS_SERIAL             0 /* TS output pin D0, normal */
 #define M88DS3103_TS_SERIAL_D7          1 /* TS output pin D7 */
-#define M88DS3103_TS_PARALLEL           2 /* 24 MHz, normal */
-#define M88DS3103_TS_PARALLEL_12        3 /* 12 MHz */
-#define M88DS3103_TS_PARALLEL_16        4 /* 16 MHz */
-#define M88DS3103_TS_PARALLEL_19_2      5 /* 19.2 MHz */
-#define M88DS3103_TS_CI                 6 /* 6 MHz */
+#define M88DS3103_TS_PARALLEL           2 /* TS Parallel mode */
+#define M88DS3103_TS_CI                 3 /* TS CI Mode */
        u8 ts_mode;
 
+       /*
+        * TS clk in KHz
+        * Default: 0.
+        */
+       u32 ts_clk;
+
+       /*
+        * TS clk polarity.
+        * Default: 0. 1-active at falling edge; 0-active at rising edge.
+        */
+       u8 ts_clk_pol:1;
+
        /*
         * spectrum inversion
         * Default: 0
@@ -86,6 +95,22 @@ struct m88ds3103_config {
         * Default: none, must set
         */
        u8 agc;
+
+       /*
+        * LNB H/V pin polarity
+        * Default: 0.
+        * 1: pin high set to VOLTAGE_13, pin low to set VOLTAGE_18.
+        * 0: pin high set to VOLTAGE_18, pin low to set VOLTAGE_13.
+        */
+       u8 lnb_hv_pol:1;
+
+       /*
+        * LNB enable pin polarity
+        * Default: 0.
+        * 1: pin high to enable, pin low to disable.
+        * 0: pin high to disable, pin low to enable.
+        */
+       u8 lnb_en_pol:1;
 };
 
 /*
index 9ae40abfd71a170fe6940e372edefb1e0e558720..3ddea4471d2b6668f633a963115d02cdad067f24 100644 (file)
@@ -28,7 +28,7 @@
 #include "mb86a16.h"
 #include "mb86a16_priv.h"
 
-unsigned int verbose = 5;
+static unsigned int verbose = 5;
 module_param(verbose, int, 0644);
 
 #define ABS(x)         ((x) < 0 ? (-x) : (x))
@@ -115,9 +115,11 @@ static int mb86a16_read(struct mb86a16_state *state, u8 reg, u8 *val)
        };
        ret = i2c_transfer(state->i2c_adap, msg, 2);
        if (ret != 2) {
-               dprintk(verbose, MB86A16_ERROR, 1, "read error(reg=0x%02x, ret=0x%i)",
+               dprintk(verbose, MB86A16_ERROR, 1, "read error(reg=0x%02x, ret=%i)",
                        reg, ret);
 
+               if (ret < 0)
+                       return ret;
                return -EREMOTEIO;
        }
        *val = b1[0];
index b931179c70a48e767848f2fdc43e37ed2aaba5bf..e6f165a5b90d7630a3543966c2b679db4128cf5c 100644 (file)
@@ -33,7 +33,7 @@ enum mb86a20s_bandwidth {
        MB86A20S_3SEG = 3,
 };
 
-u8 mb86a20s_subchannel[] = {
+static u8 mb86a20s_subchannel[] = {
        0xb0, 0xc0, 0xd0, 0xe0,
        0xf0, 0x00, 0x10, 0x20,
 };
@@ -1228,7 +1228,7 @@ struct linear_segments {
  * All tables below return a dB/1000 measurement
  */
 
-static struct linear_segments cnr_to_db_table[] = {
+static const struct linear_segments cnr_to_db_table[] = {
        { 19648,     0},
        { 18187,  1000},
        { 16534,  2000},
@@ -1262,7 +1262,7 @@ static struct linear_segments cnr_to_db_table[] = {
        {   788, 30000},
 };
 
-static struct linear_segments cnr_64qam_table[] = {
+static const struct linear_segments cnr_64qam_table[] = {
        { 3922688,     0},
        { 3920384,  1000},
        { 3902720,  2000},
@@ -1296,7 +1296,7 @@ static struct linear_segments cnr_64qam_table[] = {
        {  388864, 30000},
 };
 
-static struct linear_segments cnr_16qam_table[] = {
+static const struct linear_segments cnr_16qam_table[] = {
        { 5314816,     0},
        { 5219072,  1000},
        { 5118720,  2000},
@@ -1330,7 +1330,7 @@ static struct linear_segments cnr_16qam_table[] = {
        {   95744, 30000},
 };
 
-struct linear_segments cnr_qpsk_table[] = {
+static const struct linear_segments cnr_qpsk_table[] = {
        { 2834176,     0},
        { 2683648,  1000},
        { 2536960,  2000},
@@ -1364,7 +1364,7 @@ struct linear_segments cnr_qpsk_table[] = {
        {   11520, 30000},
 };
 
-static u32 interpolate_value(u32 value, struct linear_segments *segments,
+static u32 interpolate_value(u32 value, const struct linear_segments *segments,
                             unsigned len)
 {
        u64 tmp64;
@@ -1448,7 +1448,7 @@ static int mb86a20s_get_blk_error_layer_CNR(struct dvb_frontend *fe)
        struct dtv_frontend_properties *c = &fe->dtv_property_cache;
        u32 mer, cnr;
        int rc, val, layer;
-       struct linear_segments *segs;
+       const struct linear_segments *segs;
        unsigned segs_len;
 
        dev_dbg(&state->i2c->dev, "%s called.\n", __func__);
index a74ac0ddb83310ab619870a0f465771ca451eb7a..2163490c1e6b23758cf8efcf3c14e60413e8ed45 100644 (file)
@@ -103,7 +103,7 @@ static int mt312_write(struct mt312_state *state, const enum mt312_reg_addr reg,
 
        if (1 + count > sizeof(buf)) {
                printk(KERN_WARNING
-                      "mt312: write: len=%zd is too big!\n", count);
+                      "mt312: write: len=%zu is too big!\n", count);
                return -EINVAL;
        }
 
index 10cfc05791689323b0d4ab5b967eb22ff7e9e1db..873ea1da844b3b89940cff3a3082c9172b76b629 100644 (file)
@@ -111,7 +111,7 @@ static int or51211_load_firmware (struct dvb_frontend* fe,
        u8 tudata[585];
        int i;
 
-       dprintk("Firmware is %zd bytes\n",fw->size);
+       dprintk("Firmware is %zu bytes\n", fw->size);
 
        /* Get eprom data */
        tudata[0] = 17;
index fdbed35c87fa08472dbce4c2b016a7edd6231dd2..eb737cf29a36bf2487d97e6ae2462a15defe3e78 100644 (file)
@@ -936,7 +936,7 @@ static void rtl2832_i2c_gate_work(struct work_struct *work)
        if (ret != 1)
                goto err;
 
-       priv->i2c_gate_state = 0;
+       priv->i2c_gate_state = false;
 
        return;
 err:
index 023e0f49c786e732450b346ce50df9c7a1985e50..7bf98cf6bbe172715b3b2923fe771c35b5c5247b 100644 (file)
@@ -329,7 +329,7 @@ static int rtl2832_sdr_rd_reg_mask(struct rtl2832_sdr_state *s, u16 reg,
 static struct rtl2832_sdr_frame_buf *rtl2832_sdr_get_next_fill_buf(
                struct rtl2832_sdr_state *s)
 {
-       unsigned long flags = 0;
+       unsigned long flags;
        struct rtl2832_sdr_frame_buf *buf = NULL;
 
        spin_lock_irqsave(&s->queued_bufs_lock, flags);
@@ -365,17 +365,19 @@ static unsigned int rtl2832_sdr_convert_stream(struct rtl2832_sdr_state *s,
                dst_len = 0;
        }
 
-       /* calculate samping rate and output it in 10 seconds intervals */
+       /* calculate sample rate and output it in 10 seconds intervals */
        if (unlikely(time_is_before_jiffies(s->jiffies_next))) {
-#define MSECS 10000UL
+               #define MSECS 10000UL
+               unsigned int msecs = jiffies_to_msecs(jiffies -
+                               s->jiffies_next + msecs_to_jiffies(MSECS));
                unsigned int samples = s->sample - s->sample_measured;
 
                s->jiffies_next = jiffies + msecs_to_jiffies(MSECS);
                s->sample_measured = s->sample;
                dev_dbg(&s->udev->dev,
-                               "slen=%d samples=%u msecs=%lu sampling rate=%lu\n",
-                               src_len, samples, MSECS,
-                               samples * 1000UL / MSECS);
+                               "slen=%u samples=%u msecs=%u sample rate=%lu\n",
+                               src_len, samples, msecs,
+                               samples * 1000UL / msecs);
        }
 
        /* total number of I+Q pairs */
@@ -394,8 +396,8 @@ static void rtl2832_sdr_urb_complete(struct urb *urb)
        struct rtl2832_sdr_frame_buf *fbuf;
 
        dev_dbg_ratelimited(&s->udev->dev,
-                       "%s: status=%d length=%d/%d errors=%d\n",
-                       __func__, urb->status, urb->actual_length,
+                       "status=%d length=%d/%d errors=%d\n",
+                       urb->status, urb->actual_length,
                        urb->transfer_buffer_length, urb->error_count);
 
        switch (urb->status) {
@@ -443,7 +445,7 @@ static int rtl2832_sdr_kill_urbs(struct rtl2832_sdr_state *s)
        int i;
 
        for (i = s->urbs_submitted - 1; i >= 0; i--) {
-               dev_dbg(&s->udev->dev, "%s: kill urb=%d\n", __func__, i);
+               dev_dbg(&s->udev->dev, "kill urb=%d\n", i);
                /* stop the URB */
                usb_kill_urb(s->urb_list[i]);
        }
@@ -457,7 +459,7 @@ static int rtl2832_sdr_submit_urbs(struct rtl2832_sdr_state *s)
        int i, ret;
 
        for (i = 0; i < s->urbs_initialized; i++) {
-               dev_dbg(&s->udev->dev, "%s: submit urb=%d\n", __func__, i);
+               dev_dbg(&s->udev->dev, "submit urb=%d\n", i);
                ret = usb_submit_urb(s->urb_list[i], GFP_ATOMIC);
                if (ret) {
                        dev_err(&s->udev->dev,
@@ -477,8 +479,7 @@ static int rtl2832_sdr_free_stream_bufs(struct rtl2832_sdr_state *s)
        if (s->flags & USB_STATE_URB_BUF) {
                while (s->buf_num) {
                        s->buf_num--;
-                       dev_dbg(&s->udev->dev, "%s: free buf=%d\n",
-                                       __func__, s->buf_num);
+                       dev_dbg(&s->udev->dev, "free buf=%d\n", s->buf_num);
                        usb_free_coherent(s->udev, s->buf_size,
                                          s->buf_list[s->buf_num],
                                          s->dma_addr[s->buf_num]);
@@ -494,24 +495,22 @@ static int rtl2832_sdr_alloc_stream_bufs(struct rtl2832_sdr_state *s)
        s->buf_num = 0;
        s->buf_size = BULK_BUFFER_SIZE;
 
-       dev_dbg(&s->udev->dev,
-                       "%s: all in all I will use %u bytes for streaming\n",
-                       __func__,  MAX_BULK_BUFS * BULK_BUFFER_SIZE);
+       dev_dbg(&s->udev->dev, "all in all I will use %u bytes for streaming\n",
+                       MAX_BULK_BUFS * BULK_BUFFER_SIZE);
 
        for (s->buf_num = 0; s->buf_num < MAX_BULK_BUFS; s->buf_num++) {
                s->buf_list[s->buf_num] = usb_alloc_coherent(s->udev,
                                BULK_BUFFER_SIZE, GFP_ATOMIC,
                                &s->dma_addr[s->buf_num]);
                if (!s->buf_list[s->buf_num]) {
-                       dev_dbg(&s->udev->dev, "%s: alloc buf=%d failed\n",
-                                       __func__, s->buf_num);
+                       dev_dbg(&s->udev->dev, "alloc buf=%d failed\n",
+                                       s->buf_num);
                        rtl2832_sdr_free_stream_bufs(s);
                        return -ENOMEM;
                }
 
-               dev_dbg(&s->udev->dev, "%s: alloc buf=%d %p (dma %llu)\n",
-                               __func__, s->buf_num,
-                               s->buf_list[s->buf_num],
+               dev_dbg(&s->udev->dev, "alloc buf=%d %p (dma %llu)\n",
+                               s->buf_num, s->buf_list[s->buf_num],
                                (long long)s->dma_addr[s->buf_num]);
                s->flags |= USB_STATE_URB_BUF;
        }
@@ -527,8 +526,7 @@ static int rtl2832_sdr_free_urbs(struct rtl2832_sdr_state *s)
 
        for (i = s->urbs_initialized - 1; i >= 0; i--) {
                if (s->urb_list[i]) {
-                       dev_dbg(&s->udev->dev, "%s: free urb=%d\n",
-                                       __func__, i);
+                       dev_dbg(&s->udev->dev, "free urb=%d\n", i);
                        /* free the URBs */
                        usb_free_urb(s->urb_list[i]);
                }
@@ -544,10 +542,10 @@ static int rtl2832_sdr_alloc_urbs(struct rtl2832_sdr_state *s)
 
        /* allocate the URBs */
        for (i = 0; i < MAX_BULK_BUFS; i++) {
-               dev_dbg(&s->udev->dev, "%s: alloc urb=%d\n", __func__, i);
+               dev_dbg(&s->udev->dev, "alloc urb=%d\n", i);
                s->urb_list[i] = usb_alloc_urb(0, GFP_ATOMIC);
                if (!s->urb_list[i]) {
-                       dev_dbg(&s->udev->dev, "%s: failed\n", __func__);
+                       dev_dbg(&s->udev->dev, "failed\n");
                        for (j = 0; j < i; j++)
                                usb_free_urb(s->urb_list[j]);
                        return -ENOMEM;
@@ -570,9 +568,9 @@ static int rtl2832_sdr_alloc_urbs(struct rtl2832_sdr_state *s)
 /* Must be called with vb_queue_lock hold */
 static void rtl2832_sdr_cleanup_queued_bufs(struct rtl2832_sdr_state *s)
 {
-       unsigned long flags = 0;
+       unsigned long flags;
 
-       dev_dbg(&s->udev->dev, "%s:\n", __func__);
+       dev_dbg(&s->udev->dev, "\n");
 
        spin_lock_irqsave(&s->queued_bufs_lock, flags);
        while (!list_empty(&s->queued_bufs)) {
@@ -591,7 +589,7 @@ static void rtl2832_sdr_release_sec(struct dvb_frontend *fe)
 {
        struct rtl2832_sdr_state *s = fe->sec_priv;
 
-       dev_dbg(&s->udev->dev, "%s:\n", __func__);
+       dev_dbg(&s->udev->dev, "\n");
 
        mutex_lock(&s->vb_queue_lock);
        mutex_lock(&s->v4l2_lock);
@@ -613,7 +611,7 @@ static int rtl2832_sdr_querycap(struct file *file, void *fh,
 {
        struct rtl2832_sdr_state *s = video_drvdata(file);
 
-       dev_dbg(&s->udev->dev, "%s:\n", __func__);
+       dev_dbg(&s->udev->dev, "\n");
 
        strlcpy(cap->driver, KBUILD_MODNAME, sizeof(cap->driver));
        strlcpy(cap->card, s->vdev.name, sizeof(cap->card));
@@ -631,15 +629,15 @@ static int rtl2832_sdr_queue_setup(struct vb2_queue *vq,
 {
        struct rtl2832_sdr_state *s = vb2_get_drv_priv(vq);
 
-       dev_dbg(&s->udev->dev, "%s: *nbuffers=%d\n", __func__, *nbuffers);
+       dev_dbg(&s->udev->dev, "nbuffers=%d\n", *nbuffers);
 
        /* Need at least 8 buffers */
        if (vq->num_buffers + *nbuffers < 8)
                *nbuffers = 8 - vq->num_buffers;
        *nplanes = 1;
        sizes[0] = PAGE_ALIGN(s->buffersize);
-       dev_dbg(&s->udev->dev, "%s: nbuffers=%d sizes[0]=%d\n",
-                       __func__, *nbuffers, sizes[0]);
+       dev_dbg(&s->udev->dev, "nbuffers=%d sizes[0]=%d\n",
+                       *nbuffers, sizes[0]);
        return 0;
 }
 
@@ -659,7 +657,7 @@ static void rtl2832_sdr_buf_queue(struct vb2_buffer *vb)
        struct rtl2832_sdr_state *s = vb2_get_drv_priv(vb->vb2_queue);
        struct rtl2832_sdr_frame_buf *buf =
                        container_of(vb, struct rtl2832_sdr_frame_buf, vb);
-       unsigned long flags = 0;
+       unsigned long flags;
 
        /* Check the device has not disconnected between prep and queuing */
        if (!s->udev) {
@@ -681,7 +679,7 @@ static int rtl2832_sdr_set_adc(struct rtl2832_sdr_state *s)
        u64 u64tmp;
        u32 u32tmp;
 
-       dev_dbg(&s->udev->dev, "%s: f_adc=%u\n", __func__, s->f_adc);
+       dev_dbg(&s->udev->dev, "f_adc=%u\n", s->f_adc);
 
        if (!test_bit(POWER_ON, &s->flags))
                return 0;
@@ -715,8 +713,7 @@ static int rtl2832_sdr_set_adc(struct rtl2832_sdr_state *s)
        u64tmp = -u64tmp;
        u32tmp = u64tmp & 0x3fffff;
 
-       dev_dbg(&s->udev->dev, "%s: f_if=%u if_ctl=%08x\n",
-                       __func__, f_if, u32tmp);
+       dev_dbg(&s->udev->dev, "f_if=%u if_ctl=%08x\n", f_if, u32tmp);
 
        buf[0] = (u32tmp >> 16) & 0xff;
        buf[1] = (u32tmp >>  8) & 0xff;
@@ -903,7 +900,7 @@ static void rtl2832_sdr_unset_adc(struct rtl2832_sdr_state *s)
 {
        int ret;
 
-       dev_dbg(&s->udev->dev, "%s:\n", __func__);
+       dev_dbg(&s->udev->dev, "\n");
 
        /* PID filter */
        ret = rtl2832_sdr_wr_regs(s, 0x061, "\xe0", 1);
@@ -964,8 +961,8 @@ static int rtl2832_sdr_set_tuner_freq(struct rtl2832_sdr_state *s)
        c->frequency = s->f_tuner;
        c->delivery_system = SYS_DVBT;
 
-       dev_dbg(&s->udev->dev, "%s: frequency=%u bandwidth=%d\n",
-                       __func__, c->frequency, c->bandwidth_hz);
+       dev_dbg(&s->udev->dev, "frequency=%u bandwidth=%d\n",
+                       c->frequency, c->bandwidth_hz);
 
        if (!test_bit(POWER_ON, &s->flags))
                return 0;
@@ -980,7 +977,7 @@ static int rtl2832_sdr_set_tuner(struct rtl2832_sdr_state *s)
 {
        struct dvb_frontend *fe = s->fe;
 
-       dev_dbg(&s->udev->dev, "%s:\n", __func__);
+       dev_dbg(&s->udev->dev, "\n");
 
        if (fe->ops.tuner_ops.init)
                fe->ops.tuner_ops.init(fe);
@@ -992,7 +989,7 @@ static void rtl2832_sdr_unset_tuner(struct rtl2832_sdr_state *s)
 {
        struct dvb_frontend *fe = s->fe;
 
-       dev_dbg(&s->udev->dev, "%s:\n", __func__);
+       dev_dbg(&s->udev->dev, "\n");
 
        if (fe->ops.tuner_ops.sleep)
                fe->ops.tuner_ops.sleep(fe);
@@ -1005,7 +1002,7 @@ static int rtl2832_sdr_start_streaming(struct vb2_queue *vq, unsigned int count)
        struct rtl2832_sdr_state *s = vb2_get_drv_priv(vq);
        int ret;
 
-       dev_dbg(&s->udev->dev, "%s:\n", __func__);
+       dev_dbg(&s->udev->dev, "\n");
 
        if (!s->udev)
                return -ENODEV;
@@ -1054,7 +1051,7 @@ static void rtl2832_sdr_stop_streaming(struct vb2_queue *vq)
 {
        struct rtl2832_sdr_state *s = vb2_get_drv_priv(vq);
 
-       dev_dbg(&s->udev->dev, "%s:\n", __func__);
+       dev_dbg(&s->udev->dev, "\n");
 
        mutex_lock(&s->v4l2_lock);
 
@@ -1088,8 +1085,7 @@ static int rtl2832_sdr_g_tuner(struct file *file, void *priv,
 {
        struct rtl2832_sdr_state *s = video_drvdata(file);
 
-       dev_dbg(&s->udev->dev, "%s: index=%d type=%d\n",
-                       __func__, v->index, v->type);
+       dev_dbg(&s->udev->dev, "index=%d type=%d\n", v->index, v->type);
 
        if (v->index == 0) {
                strlcpy(v->name, "ADC: Realtek RTL2832", sizeof(v->name));
@@ -1115,7 +1111,7 @@ static int rtl2832_sdr_s_tuner(struct file *file, void *priv,
 {
        struct rtl2832_sdr_state *s = video_drvdata(file);
 
-       dev_dbg(&s->udev->dev, "%s:\n", __func__);
+       dev_dbg(&s->udev->dev, "\n");
 
        if (v->index > 1)
                return -EINVAL;
@@ -1127,8 +1123,8 @@ static int rtl2832_sdr_enum_freq_bands(struct file *file, void *priv,
 {
        struct rtl2832_sdr_state *s = video_drvdata(file);
 
-       dev_dbg(&s->udev->dev, "%s: tuner=%d type=%d index=%d\n",
-                       __func__, band->tuner, band->type, band->index);
+       dev_dbg(&s->udev->dev, "tuner=%d type=%d index=%d\n",
+                       band->tuner, band->type, band->index);
 
        if (band->tuner == 0) {
                if (band->index >= ARRAY_SIZE(bands_adc))
@@ -1153,8 +1149,8 @@ static int rtl2832_sdr_g_frequency(struct file *file, void *priv,
        struct rtl2832_sdr_state *s = video_drvdata(file);
        int ret  = 0;
 
-       dev_dbg(&s->udev->dev, "%s: tuner=%d type=%d\n",
-                       __func__, f->tuner, f->type);
+       dev_dbg(&s->udev->dev, "tuner=%d type=%d\n",
+                       f->tuner, f->type);
 
        if (f->tuner == 0) {
                f->frequency = s->f_adc;
@@ -1175,8 +1171,8 @@ static int rtl2832_sdr_s_frequency(struct file *file, void *priv,
        struct rtl2832_sdr_state *s = video_drvdata(file);
        int ret, band;
 
-       dev_dbg(&s->udev->dev, "%s: tuner=%d type=%d frequency=%u\n",
-                       __func__, f->tuner, f->type, f->frequency);
+       dev_dbg(&s->udev->dev, "tuner=%d type=%d frequency=%u\n",
+                       f->tuner, f->type, f->frequency);
 
        /* ADC band midpoints */
        #define BAND_ADC_0 ((bands_adc[0].rangehigh + bands_adc[1].rangelow) / 2)
@@ -1194,15 +1190,13 @@ static int rtl2832_sdr_s_frequency(struct file *file, void *priv,
                                bands_adc[band].rangelow,
                                bands_adc[band].rangehigh);
 
-               dev_dbg(&s->udev->dev, "%s: ADC frequency=%u Hz\n",
-                               __func__, s->f_adc);
+               dev_dbg(&s->udev->dev, "ADC frequency=%u Hz\n", s->f_adc);
                ret = rtl2832_sdr_set_adc(s);
        } else if (f->tuner == 1) {
                s->f_tuner = clamp_t(unsigned int, f->frequency,
                                bands_fm[0].rangelow,
                                bands_fm[0].rangehigh);
-               dev_dbg(&s->udev->dev, "%s: RF frequency=%u Hz\n",
-                               __func__, f->frequency);
+               dev_dbg(&s->udev->dev, "RF frequency=%u Hz\n", f->frequency);
 
                ret = rtl2832_sdr_set_tuner_freq(s);
        } else {
@@ -1217,7 +1211,7 @@ static int rtl2832_sdr_enum_fmt_sdr_cap(struct file *file, void *priv,
 {
        struct rtl2832_sdr_state *s = video_drvdata(file);
 
-       dev_dbg(&s->udev->dev, "%s:\n", __func__);
+       dev_dbg(&s->udev->dev, "\n");
 
        if (f->index >= s->num_formats)
                return -EINVAL;
@@ -1233,7 +1227,7 @@ static int rtl2832_sdr_g_fmt_sdr_cap(struct file *file, void *priv,
 {
        struct rtl2832_sdr_state *s = video_drvdata(file);
 
-       dev_dbg(&s->udev->dev, "%s:\n", __func__);
+       dev_dbg(&s->udev->dev, "\n");
 
        f->fmt.sdr.pixelformat = s->pixelformat;
        f->fmt.sdr.buffersize = s->buffersize;
@@ -1250,7 +1244,7 @@ static int rtl2832_sdr_s_fmt_sdr_cap(struct file *file, void *priv,
        struct vb2_queue *q = &s->vb_queue;
        int i;
 
-       dev_dbg(&s->udev->dev, "%s: pixelformat fourcc %4.4s\n", __func__,
+       dev_dbg(&s->udev->dev, "pixelformat fourcc %4.4s\n",
                        (char *)&f->fmt.sdr.pixelformat);
 
        if (vb2_is_busy(q))
@@ -1280,7 +1274,7 @@ static int rtl2832_sdr_try_fmt_sdr_cap(struct file *file, void *priv,
        struct rtl2832_sdr_state *s = video_drvdata(file);
        int i;
 
-       dev_dbg(&s->udev->dev, "%s: pixelformat fourcc %4.4s\n", __func__,
+       dev_dbg(&s->udev->dev, "pixelformat fourcc %4.4s\n",
                        (char *)&f->fmt.sdr.pixelformat);
 
        memset(f->fmt.sdr.reserved, 0, sizeof(f->fmt.sdr.reserved));
@@ -1354,8 +1348,8 @@ static int rtl2832_sdr_s_ctrl(struct v4l2_ctrl *ctrl)
        int ret;
 
        dev_dbg(&s->udev->dev,
-                       "%s: id=%d name=%s val=%d min=%lld max=%lld step=%lld\n",
-                       __func__, ctrl->id, ctrl->name, ctrl->val,
+                       "id=%d name=%s val=%d min=%lld max=%lld step=%lld\n",
+                       ctrl->id, ctrl->name, ctrl->val,
                        ctrl->minimum, ctrl->maximum, ctrl->step);
 
        switch (ctrl->id) {
@@ -1432,7 +1426,7 @@ struct dvb_frontend *rtl2832_sdr_attach(struct dvb_frontend *fe,
        s->pixelformat = formats[0].pixelformat;
        s->buffersize = formats[0].buffersize;
        s->num_formats = NUM_FORMATS;
-       if (rtl2832_sdr_emulated_fmt == false)
+       if (!rtl2832_sdr_emulated_fmt)
                s->num_formats -= 1;
 
        mutex_init(&s->v4l2_lock);
index 3a2d6c5aded6b450be22afe3e54443f254d78c95..98ddb49ad52b1a27a268ef6fabab3d3de97496e7 100644 (file)
@@ -1,5 +1,5 @@
 /*
-    Driver for Silicon Labs SI2165 DVB-C/-T Demodulator
+    Driver for Silicon Labs Si2161 DVB-T and Si2165 DVB-C/-T Demodulator
 
     Copyright (C) 2013-2014 Matthias Schwarzott <zzam@gentoo.org>
 
@@ -44,9 +44,7 @@ struct si2165_state {
 
        struct si2165_config config;
 
-       /* chip revision */
-       u8 revcode;
-       /* chip type */
+       u8 chip_revcode;
        u8 chip_type;
 
        /* calculated by xtal and div settings */
@@ -312,7 +310,7 @@ static u32 si2165_get_fe_clk(struct si2165_state *state)
        return state->adc_clk;
 }
 
-static bool si2165_wait_init_done(struct si2165_state *state)
+static int si2165_wait_init_done(struct si2165_state *state)
 {
        int ret = -EINVAL;
        u8 val = 0;
@@ -407,7 +405,7 @@ static int si2165_upload_firmware(struct si2165_state *state)
        int ret;
 
        const struct firmware *fw = NULL;
-       u8 *fw_file = SI2165_FIRMWARE;
+       u8 *fw_file;
        const u8 *data;
        u32 len;
        u32 offset;
@@ -415,10 +413,20 @@ static int si2165_upload_firmware(struct si2165_state *state)
        u8 block_count;
        u16 crc_expected;
 
+       switch (state->chip_revcode) {
+       case 0x03: /* revision D */
+               fw_file = SI2165_FIRMWARE_REV_D;
+               break;
+       default:
+               dev_info(&state->i2c->dev, "%s: no firmware file for revision=%d\n",
+                       KBUILD_MODNAME, state->chip_revcode);
+               return 0;
+       }
+
        /* request the firmware, this will block and timeout */
        ret = request_firmware(&fw, fw_file, state->i2c->dev.parent);
        if (ret) {
-               dev_warn(&state->i2c->dev, "%s: firmare file '%s' not found\n",
+               dev_warn(&state->i2c->dev, "%s: firmware file '%s' not found\n",
                                KBUILD_MODNAME, fw_file);
                goto error;
        }
@@ -908,7 +916,7 @@ static void si2165_release(struct dvb_frontend *fe)
 
 static struct dvb_frontend_ops si2165_ops = {
        .info = {
-               .name = "Silicon Labs Si2165",
+               .name = "Silicon Labs ",
                .caps = FE_CAN_FEC_1_2 |
                        FE_CAN_FEC_2_3 |
                        FE_CAN_FEC_3_4 |
@@ -948,6 +956,8 @@ struct dvb_frontend *si2165_attach(const struct si2165_config *config,
        int n;
        int io_ret;
        u8 val;
+       char rev_char;
+       const char *chip_name;
 
        if (config == NULL || i2c == NULL)
                goto error;
@@ -984,7 +994,7 @@ struct dvb_frontend *si2165_attach(const struct si2165_config *config,
        if (val != state->config.chip_mode)
                goto error;
 
-       io_ret = si2165_readreg8(state, 0x0023 , &state->revcode);
+       io_ret = si2165_readreg8(state, 0x0023, &state->chip_revcode);
        if (io_ret < 0)
                goto error;
 
@@ -997,22 +1007,35 @@ struct dvb_frontend *si2165_attach(const struct si2165_config *config,
        if (io_ret < 0)
                goto error;
 
-       dev_info(&state->i2c->dev, "%s: hardware revision 0x%02x, chip type 0x%02x\n",
-                KBUILD_MODNAME, state->revcode, state->chip_type);
+       if (state->chip_revcode < 26)
+               rev_char = 'A' + state->chip_revcode;
+       else
+               rev_char = '?';
 
-       /* It is a guess that register 0x0118 (chip type?) can be used to
-        * differ between si2161, si2163 and si2165
-        * Only si2165 has been tested.
-        */
-       if (state->revcode == 0x03 && state->chip_type == 0x07) {
+       switch (state->chip_type) {
+       case 0x06:
+               chip_name = "Si2161";
+               state->has_dvbt = true;
+               break;
+       case 0x07:
+               chip_name = "Si2165";
                state->has_dvbt = true;
                state->has_dvbc = true;
-       } else {
-               dev_err(&state->i2c->dev, "%s: Unsupported chip.\n",
-                       KBUILD_MODNAME);
+               break;
+       default:
+               dev_err(&state->i2c->dev, "%s: Unsupported Silicon Labs chip (type %d, rev %d)\n",
+                       KBUILD_MODNAME, state->chip_type, state->chip_revcode);
                goto error;
        }
 
+       dev_info(&state->i2c->dev,
+               "%s: Detected Silicon Labs %s-%c (type %d, rev %d)\n",
+               KBUILD_MODNAME, chip_name, rev_char, state->chip_type,
+               state->chip_revcode);
+
+       strlcat(state->frontend.ops.info.name, chip_name,
+                       sizeof(state->frontend.ops.info.name));
+
        n = 0;
        if (state->has_dvbt) {
                state->frontend.ops.delsys[n++] = SYS_DVBT;
@@ -1037,4 +1060,4 @@ MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
 MODULE_DESCRIPTION("Silicon Labs Si2165 DVB-C/-T Demodulator driver");
 MODULE_AUTHOR("Matthias Schwarzott <zzam@gentoo.org>");
 MODULE_LICENSE("GPL");
-MODULE_FIRMWARE(SI2165_FIRMWARE);
+MODULE_FIRMWARE(SI2165_FIRMWARE_REV_D);
index d4cc93fe1096ea31f5d67d7820c845986f4184c4..2b70cf12cd797799eaa1c7bfd7299428a562446a 100644 (file)
@@ -18,6 +18,6 @@
 #ifndef _DVB_SI2165_PRIV
 #define _DVB_SI2165_PRIV
 
-#define SI2165_FIRMWARE "dvb-demod-si2165.fw"
+#define SI2165_FIRMWARE_REV_D "dvb-demod-si2165.fw"
 
 #endif /* _DVB_SI2165_PRIV */
index 8f81d979de30541b31fb6f56559ef2c56aeb62ea..1cd93be281ed4d42194d15d2535bd86dd5eb638d 100644 (file)
@@ -55,8 +55,7 @@ static int si2168_cmd_execute(struct si2168 *s, struct si2168_cmd *cmd)
                                break;
                }
 
-               dev_dbg(&s->client->dev, "%s: cmd execution took %d ms\n",
-                               __func__,
+               dev_dbg(&s->client->dev, "cmd execution took %d ms\n",
                                jiffies_to_msecs(jiffies) -
                                (jiffies_to_msecs(timeout) - TIMEOUT));
 
@@ -75,7 +74,7 @@ err_mutex_unlock:
 
        return 0;
 err:
-       dev_dbg(&s->client->dev, "%s: failed=%d\n", __func__, ret);
+       dev_dbg(&s->client->dev, "failed=%d\n", ret);
        return ret;
 }
 
@@ -150,12 +149,12 @@ static int si2168_read_status(struct dvb_frontend *fe, fe_status_t *status)
                c->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
        }
 
-       dev_dbg(&s->client->dev, "%s: status=%02x args=%*ph\n",
-                       __func__, *status, cmd.rlen, cmd.args);
+       dev_dbg(&s->client->dev, "status=%02x args=%*ph\n",
+                       *status, cmd.rlen, cmd.args);
 
        return 0;
 err:
-       dev_dbg(&s->client->dev, "%s: failed=%d\n", __func__, ret);
+       dev_dbg(&s->client->dev, "failed=%d\n", ret);
        return ret;
 }
 
@@ -168,10 +167,10 @@ static int si2168_set_frontend(struct dvb_frontend *fe)
        u8 bandwidth, delivery_system;
 
        dev_dbg(&s->client->dev,
-                       "%s: delivery_system=%u modulation=%u frequency=%u bandwidth_hz=%u symbol_rate=%u inversion=%u\n",
-                       __func__, c->delivery_system, c->modulation,
+                       "delivery_system=%u modulation=%u frequency=%u bandwidth_hz=%u symbol_rate=%u inversion=%u, stream_id=%d\n",
+                       c->delivery_system, c->modulation,
                        c->frequency, c->bandwidth_hz, c->symbol_rate,
-                       c->inversion);
+                       c->inversion, c->stream_id);
 
        if (!s->active) {
                ret = -EAGAIN;
@@ -235,6 +234,18 @@ static int si2168_set_frontend(struct dvb_frontend *fe)
        if (ret)
                goto err;
 
+       if (c->delivery_system == SYS_DVBT2) {
+               /* select PLP */
+               cmd.args[0] = 0x52;
+               cmd.args[1] = c->stream_id & 0xff;
+               cmd.args[2] = c->stream_id == NO_STREAM_ID_FILTER ? 0 : 1;
+               cmd.wlen = 3;
+               cmd.rlen = 1;
+               ret = si2168_cmd_execute(s, &cmd);
+               if (ret)
+                       goto err;
+       }
+
        memcpy(cmd.args, "\x51\x03", 2);
        cmd.wlen = 2;
        cmd.rlen = 12;
@@ -297,13 +308,6 @@ static int si2168_set_frontend(struct dvb_frontend *fe)
        if (ret)
                goto err;
 
-       memcpy(cmd.args, "\x14\x00\x01\x10\x16\x00", 6);
-       cmd.wlen = 6;
-       cmd.rlen = 4;
-       ret = si2168_cmd_execute(s, &cmd);
-       if (ret)
-               goto err;
-
        memcpy(cmd.args, "\x14\x00\x09\x10\xe3\x18", 6);
        cmd.wlen = 6;
        cmd.rlen = 4;
@@ -343,7 +347,7 @@ static int si2168_set_frontend(struct dvb_frontend *fe)
 
        return 0;
 err:
-       dev_dbg(&s->client->dev, "%s: failed=%d\n", __func__, ret);
+       dev_dbg(&s->client->dev, "failed=%d\n", ret);
        return ret;
 }
 
@@ -357,8 +361,9 @@ static int si2168_init(struct dvb_frontend *fe)
        struct si2168_cmd cmd;
        unsigned int chip_id;
 
-       dev_dbg(&s->client->dev, "%s:\n", __func__);
+       dev_dbg(&s->client->dev, "\n");
 
+       /* initialize */
        memcpy(cmd.args, "\xc0\x12\x00\x0c\x00\x0d\x16\x00\x00\x00\x00\x00\x00", 13);
        cmd.wlen = 13;
        cmd.rlen = 0;
@@ -366,6 +371,26 @@ static int si2168_init(struct dvb_frontend *fe)
        if (ret)
                goto err;
 
+       if (s->fw_loaded) {
+               /* resume */
+               memcpy(cmd.args, "\xc0\x06\x08\x0f\x00\x20\x21\x01", 8);
+               cmd.wlen = 8;
+               cmd.rlen = 1;
+               ret = si2168_cmd_execute(s, &cmd);
+               if (ret)
+                       goto err;
+
+               memcpy(cmd.args, "\x85", 1);
+               cmd.wlen = 1;
+               cmd.rlen = 1;
+               ret = si2168_cmd_execute(s, &cmd);
+               if (ret)
+                       goto err;
+
+               goto warm;
+       }
+
+       /* power up */
        memcpy(cmd.args, "\xc0\x06\x01\x0f\x00\x20\x20\x01", 8);
        cmd.wlen = 8;
        cmd.rlen = 1;
@@ -400,16 +425,16 @@ static int si2168_init(struct dvb_frontend *fe)
                break;
        default:
                dev_err(&s->client->dev,
-                               "%s: unkown chip version Si21%d-%c%c%c\n",
-                               KBUILD_MODNAME, cmd.args[2], cmd.args[1],
+                               "unknown chip version Si21%d-%c%c%c\n",
+                               cmd.args[2], cmd.args[1],
                                cmd.args[3], cmd.args[4]);
                ret = -EINVAL;
                goto err;
        }
 
        /* cold state - try to download firmware */
-       dev_info(&s->client->dev, "%s: found a '%s' in cold state\n",
-                       KBUILD_MODNAME, si2168_ops.info.name);
+       dev_info(&s->client->dev, "found a '%s' in cold state\n",
+                       si2168_ops.info.name);
 
        /* request the firmware, this will block and timeout */
        ret = request_firmware(&fw, fw_file, &s->client->dev);
@@ -422,18 +447,18 @@ static int si2168_init(struct dvb_frontend *fe)
 
                if (ret == 0) {
                        dev_notice(&s->client->dev,
-                                       "%s: please install firmware file '%s'\n",
-                                       KBUILD_MODNAME, SI2168_B40_FIRMWARE);
+                                       "please install firmware file '%s'\n",
+                                       SI2168_B40_FIRMWARE);
                } else {
                        dev_err(&s->client->dev,
-                                       "%s: firmware file '%s' not found\n",
-                                       KBUILD_MODNAME, fw_file);
+                                       "firmware file '%s' not found\n",
+                                       fw_file);
                        goto err;
                }
        }
 
-       dev_info(&s->client->dev, "%s: downloading firmware from file '%s'\n",
-                       KBUILD_MODNAME, fw_file);
+       dev_info(&s->client->dev, "downloading firmware from file '%s'\n",
+                       fw_file);
 
        for (remaining = fw->size; remaining > 0; remaining -= i2c_wr_max) {
                len = remaining;
@@ -446,8 +471,8 @@ static int si2168_init(struct dvb_frontend *fe)
                ret = si2168_cmd_execute(s, &cmd);
                if (ret) {
                        dev_err(&s->client->dev,
-                                       "%s: firmware download failed=%d\n",
-                                       KBUILD_MODNAME, ret);
+                                       "firmware download failed=%d\n",
+                                       ret);
                        goto err;
                }
        }
@@ -462,8 +487,20 @@ static int si2168_init(struct dvb_frontend *fe)
        if (ret)
                goto err;
 
-       dev_info(&s->client->dev, "%s: found a '%s' in warm state\n",
-                       KBUILD_MODNAME, si2168_ops.info.name);
+       /* set ts mode */
+       memcpy(cmd.args, "\x14\x00\x01\x10\x10\x00", 6);
+       cmd.args[4] |= s->ts_mode;
+       cmd.wlen = 6;
+       cmd.rlen = 4;
+       ret = si2168_cmd_execute(s, &cmd);
+       if (ret)
+               goto err;
+
+       s->fw_loaded = true;
+
+warm:
+       dev_info(&s->client->dev, "found a '%s' in warm state\n",
+                       si2168_ops.info.name);
 
        s->active = true;
 
@@ -472,7 +509,7 @@ err:
        if (fw)
                release_firmware(fw);
 
-       dev_dbg(&s->client->dev, "%s: failed=%d\n", __func__, ret);
+       dev_dbg(&s->client->dev, "failed=%d\n", ret);
        return ret;
 }
 
@@ -482,7 +519,7 @@ static int si2168_sleep(struct dvb_frontend *fe)
        int ret;
        struct si2168_cmd cmd;
 
-       dev_dbg(&s->client->dev, "%s:\n", __func__);
+       dev_dbg(&s->client->dev, "\n");
 
        s->active = false;
 
@@ -495,7 +532,7 @@ static int si2168_sleep(struct dvb_frontend *fe)
 
        return 0;
 err:
-       dev_dbg(&s->client->dev, "%s: failed=%d\n", __func__, ret);
+       dev_dbg(&s->client->dev, "failed=%d\n", ret);
        return ret;
 }
 
@@ -528,8 +565,7 @@ static int si2168_select(struct i2c_adapter *adap, void *mux_priv, u32 chan)
        /* open tuner I2C gate */
        ret = __i2c_transfer(s->client->adapter, &gate_open_msg, 1);
        if (ret != 1) {
-               dev_warn(&s->client->dev, "%s: i2c write failed=%d\n",
-                               KBUILD_MODNAME, ret);
+               dev_warn(&s->client->dev, "i2c write failed=%d\n", ret);
                if (ret >= 0)
                        ret = -EREMOTEIO;
        } else {
@@ -553,8 +589,7 @@ static int si2168_deselect(struct i2c_adapter *adap, void *mux_priv, u32 chan)
        /* close tuner I2C gate */
        ret = __i2c_transfer(s->client->adapter, &gate_close_msg, 1);
        if (ret != 1) {
-               dev_warn(&s->client->dev, "%s: i2c write failed=%d\n",
-                               KBUILD_MODNAME, ret);
+               dev_warn(&s->client->dev, "i2c write failed=%d\n", ret);
                if (ret >= 0)
                        ret = -EREMOTEIO;
        } else {
@@ -587,7 +622,8 @@ static const struct dvb_frontend_ops si2168_ops = {
                        FE_CAN_GUARD_INTERVAL_AUTO |
                        FE_CAN_HIERARCHY_AUTO |
                        FE_CAN_MUTE_TS |
-                       FE_CAN_2G_MODULATION
+                       FE_CAN_2G_MODULATION |
+                       FE_CAN_MULTISTREAM
        },
 
        .get_tune_settings = si2168_get_tune_settings,
@@ -607,12 +643,12 @@ static int si2168_probe(struct i2c_client *client,
        struct si2168 *s;
        int ret;
 
-       dev_dbg(&client->dev, "%s:\n", __func__);
+       dev_dbg(&client->dev, "\n");
 
        s = kzalloc(sizeof(struct si2168), GFP_KERNEL);
        if (!s) {
                ret = -ENOMEM;
-               dev_err(&client->dev, "%s: kzalloc() failed\n", KBUILD_MODNAME);
+               dev_err(&client->dev, "kzalloc() failed\n");
                goto err;
        }
 
@@ -633,16 +669,17 @@ static int si2168_probe(struct i2c_client *client,
 
        *config->i2c_adapter = s->adapter;
        *config->fe = &s->fe;
+       s->ts_mode = config->ts_mode;
+       s->fw_loaded = false;
 
        i2c_set_clientdata(client, s);
 
        dev_info(&s->client->dev,
-                       "%s: Silicon Labs Si2168 successfully attached\n",
-                       KBUILD_MODNAME);
+                       "Silicon Labs Si2168 successfully attached\n");
        return 0;
 err:
        kfree(s);
-       dev_dbg(&client->dev, "%s: failed=%d\n", __func__, ret);
+       dev_dbg(&client->dev, "failed=%d\n", ret);
        return ret;
 }
 
@@ -650,7 +687,7 @@ static int si2168_remove(struct i2c_client *client)
 {
        struct si2168 *s = i2c_get_clientdata(client);
 
-       dev_dbg(&client->dev, "%s:\n", __func__);
+       dev_dbg(&client->dev, "\n");
 
        i2c_del_mux_adapter(s->adapter);
 
index 3c5b5ab01796c69c2cf955e81756ccda08a3108e..e086d671945167046f18a62e4f6cac6131950bda 100644 (file)
@@ -34,6 +34,12 @@ struct si2168_config {
         * returned by driver
         */
        struct i2c_adapter **i2c_adapter;
+
+       /* TS mode */
+       u8 ts_mode;
 };
 
+#define SI2168_TS_PARALLEL     0x06
+#define SI2168_TS_SERIAL       0x03
+
 #endif
index ebbf502ec313cff28deecb7c2531ac8a04cbc75c..e13983ed4be1a077e3b04b896c46870e8aad7a60 100644 (file)
@@ -36,6 +36,8 @@ struct si2168 {
        fe_delivery_system_t delivery_system;
        fe_status_t fe_status;
        bool active;
+       bool fw_loaded;
+       u8 ts_mode;
 };
 
 /* firmare command struct */
index 73b47cc6a13b3b8c2f6ca85d0ee1d9eee71120c1..16850e2bf02fe37bccc4c54af466a43f5dd61b85 100644 (file)
@@ -236,6 +236,9 @@ static int si21_writeregs(struct si21xx_state *state, u8 reg1,
                                .len = len + 1
        };
 
+       if (len > sizeof(buf) - 1)
+               return -EINVAL;
+
        msg.buf[0] =  reg1;
        memcpy(msg.buf + 1, data, len);
 
diff --git a/drivers/media/dvb-frontends/sp2.c b/drivers/media/dvb-frontends/sp2.c
new file mode 100644 (file)
index 0000000..9b684d5
--- /dev/null
@@ -0,0 +1,441 @@
+/*
+ * CIMaX SP2/SP2HF (Atmel T90FJR) CI driver
+ *
+ * Copyright (C) 2014 Olli Salonen <olli.salonen@iki.fi>
+ *
+ * Heavily based on CIMax2(R) SP2 driver in conjunction with NetUp Dual
+ * DVB-S2 CI card (cimax2) with following copyrights:
+ *
+ *  Copyright (C) 2009 NetUP Inc.
+ *  Copyright (C) 2009 Igor M. Liplianin <liplianin@netup.ru>
+ *  Copyright (C) 2009 Abylay Ospan <aospan@netup.ru>
+ *
+ *    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 "sp2_priv.h"
+
+static int sp2_read_i2c(struct sp2 *s, u8 reg, u8 *buf, int len)
+{
+       int ret;
+       struct i2c_client *client = s->client;
+       struct i2c_adapter *adap = client->adapter;
+       struct i2c_msg msg[] = {
+               {
+                       .addr = client->addr,
+                       .flags = 0,
+                       .buf = &reg,
+                       .len = 1
+               }, {
+                       .addr = client->addr,
+                       .flags  = I2C_M_RD,
+                       .buf = buf,
+                       .len = len
+               }
+       };
+
+       ret = i2c_transfer(adap, msg, 2);
+
+       if (ret != 2) {
+               dev_err(&client->dev, "i2c read error, reg = 0x%02x, status = %d\n",
+                               reg, ret);
+               if (ret < 0)
+                       return ret;
+               else
+                       return -EIO;
+       }
+
+       dev_dbg(&s->client->dev, "addr=0x%04x, reg = 0x%02x, data = %02x\n",
+                               client->addr, reg, buf[0]);
+
+       return 0;
+}
+
+static int sp2_write_i2c(struct sp2 *s, u8 reg, u8 *buf, int len)
+{
+       int ret;
+       u8 buffer[35];
+       struct i2c_client *client = s->client;
+       struct i2c_adapter *adap = client->adapter;
+       struct i2c_msg msg = {
+               .addr = client->addr,
+               .flags = 0,
+               .buf = &buffer[0],
+               .len = len + 1
+       };
+
+       if ((len + 1) > sizeof(buffer)) {
+               dev_err(&client->dev, "i2c wr reg=%02x: len=%d is too big!\n",
+                               reg, len);
+               return -EINVAL;
+       }
+
+       buffer[0] = reg;
+       memcpy(&buffer[1], buf, len);
+
+       ret = i2c_transfer(adap, &msg, 1);
+
+       if (ret != 1) {
+               dev_err(&client->dev, "i2c write error, reg = 0x%02x, status = %d\n",
+                               reg, ret);
+               if (ret < 0)
+                       return ret;
+               else
+                       return -EIO;
+       }
+
+       return 0;
+}
+
+static int sp2_ci_op_cam(struct dvb_ca_en50221 *en50221, int slot, u8 acs,
+                       u8 read, int addr, u8 data)
+{
+       struct sp2 *s = en50221->data;
+       u8 store;
+       int mem, ret;
+       int (*ci_op_cam)(void*, u8, int, u8, int*) = s->ci_control;
+
+       dev_dbg(&s->client->dev, "slot=%d, acs=0x%02x, addr=0x%04x, data = 0x%02x",
+                       slot, acs, addr, data);
+
+       if (slot != 0)
+               return -EINVAL;
+
+       /*
+        * change module access type between IO space and attribute memory
+        * when needed
+        */
+       if (s->module_access_type != acs) {
+               ret = sp2_read_i2c(s, 0x00, &store, 1);
+
+               if (ret)
+                       return ret;
+
+               store &= ~(SP2_MOD_CTL_ACS1 | SP2_MOD_CTL_ACS0);
+               store |= acs;
+
+               ret = sp2_write_i2c(s, 0x00, &store, 1);
+               if (ret)
+                       return ret;
+       }
+
+       s->module_access_type = acs;
+
+       /* implementation of ci_op_cam is device specific */
+       if (ci_op_cam) {
+               ret = ci_op_cam(s->priv, read, addr, data, &mem);
+       } else {
+               dev_err(&s->client->dev, "callback not defined");
+               return -EINVAL;
+       }
+
+       if (ret)
+               return ret;
+
+       if (read) {
+               dev_dbg(&s->client->dev, "cam read, addr=0x%04x, data = 0x%04x",
+                               addr, mem);
+               return mem;
+       } else {
+               return 0;
+       }
+}
+
+int sp2_ci_read_attribute_mem(struct dvb_ca_en50221 *en50221,
+                               int slot, int addr)
+{
+       return sp2_ci_op_cam(en50221, slot, SP2_CI_ATTR_ACS,
+                       SP2_CI_RD, addr, 0);
+}
+
+int sp2_ci_write_attribute_mem(struct dvb_ca_en50221 *en50221,
+                               int slot, int addr, u8 data)
+{
+       return sp2_ci_op_cam(en50221, slot, SP2_CI_ATTR_ACS,
+                       SP2_CI_WR, addr, data);
+}
+
+int sp2_ci_read_cam_control(struct dvb_ca_en50221 *en50221,
+                               int slot, u8 addr)
+{
+       return sp2_ci_op_cam(en50221, slot, SP2_CI_IO_ACS,
+                       SP2_CI_RD, addr, 0);
+}
+
+int sp2_ci_write_cam_control(struct dvb_ca_en50221 *en50221,
+                               int slot, u8 addr, u8 data)
+{
+       return sp2_ci_op_cam(en50221, slot, SP2_CI_IO_ACS,
+                       SP2_CI_WR, addr, data);
+}
+
+int sp2_ci_slot_reset(struct dvb_ca_en50221 *en50221, int slot)
+{
+       struct sp2 *s = en50221->data;
+       u8 buf;
+       int ret;
+
+       dev_dbg(&s->client->dev, "slot: %d\n", slot);
+
+       if (slot != 0)
+               return -EINVAL;
+
+       /* RST on */
+       buf = SP2_MOD_CTL_RST;
+       ret = sp2_write_i2c(s, 0x00, &buf, 1);
+
+       if (ret)
+               return ret;
+
+       usleep_range(500, 600);
+
+       /* RST off */
+       buf = 0x00;
+       ret = sp2_write_i2c(s, 0x00, &buf, 1);
+
+       if (ret)
+               return ret;
+
+       msleep(1000);
+
+       return 0;
+}
+
+int sp2_ci_slot_shutdown(struct dvb_ca_en50221 *en50221, int slot)
+{
+       struct sp2 *s = en50221->data;
+
+       dev_dbg(&s->client->dev, "slot:%d\n", slot);
+
+       /* not implemented */
+       return 0;
+}
+
+int sp2_ci_slot_ts_enable(struct dvb_ca_en50221 *en50221, int slot)
+{
+       struct sp2 *s = en50221->data;
+       u8 buf;
+
+       dev_dbg(&s->client->dev, "slot:%d\n", slot);
+
+       if (slot != 0)
+               return -EINVAL;
+
+       sp2_read_i2c(s, 0x00, &buf, 1);
+
+       /* disable bypass and enable TS */
+       buf |= (SP2_MOD_CTL_TSOEN | SP2_MOD_CTL_TSIEN);
+       return sp2_write_i2c(s, 0, &buf, 1);
+}
+
+int sp2_ci_poll_slot_status(struct dvb_ca_en50221 *en50221,
+                               int slot, int open)
+{
+       struct sp2 *s = en50221->data;
+       u8 buf[2];
+       int ret;
+
+       dev_dbg(&s->client->dev, "slot:%d open:%d\n", slot, open);
+
+       /*
+        * CAM module INSERT/REMOVE processing. Slow operation because of i2c
+        * transfers. Throttle read to one per sec.
+        */
+       if (time_after(jiffies, s->next_status_checked_time)) {
+               ret = sp2_read_i2c(s, 0x00, buf, 1);
+               s->next_status_checked_time = jiffies + msecs_to_jiffies(1000);
+
+               if (ret)
+                       return 0;
+
+               if (buf[0] & SP2_MOD_CTL_DET)
+                       s->status = DVB_CA_EN50221_POLL_CAM_PRESENT |
+                                       DVB_CA_EN50221_POLL_CAM_READY;
+               else
+                       s->status = 0;
+       }
+
+       return s->status;
+}
+
+int sp2_init(struct sp2 *s)
+{
+       int ret = 0;
+       u8 buf;
+       u8 cimax_init[34] = {
+               0x00, /* module A control*/
+               0x00, /* auto select mask high A */
+               0x00, /* auto select mask low A */
+               0x00, /* auto select pattern high A */
+               0x00, /* auto select pattern low A */
+               0x44, /* memory access time A, 600 ns */
+               0x00, /* invert input A */
+               0x00, /* RFU */
+               0x00, /* RFU */
+               0x00, /* module B control*/
+               0x00, /* auto select mask high B */
+               0x00, /* auto select mask low B */
+               0x00, /* auto select pattern high B */
+               0x00, /* auto select pattern low B */
+               0x44, /* memory access time B, 600 ns */
+               0x00, /* invert input B */
+               0x00, /* RFU */
+               0x00, /* RFU */
+               0x00, /* auto select mask high Ext */
+               0x00, /* auto select mask low Ext */
+               0x00, /* auto select pattern high Ext */
+               0x00, /* auto select pattern low Ext */
+               0x00, /* RFU */
+               0x02, /* destination - module A */
+               0x01, /* power control reg, VCC power on */
+               0x00, /* RFU */
+               0x00, /* int status read only */
+               0x00, /* Interrupt Mask Register */
+               0x05, /* EXTINT=active-high, INT=push-pull */
+               0x00, /* USCG1 */
+               0x04, /* ack active low */
+               0x00, /* LOCK = 0 */
+               0x22, /* unknown */
+               0x00, /* synchronization? */
+       };
+
+       dev_dbg(&s->client->dev, "\n");
+
+       s->ca.owner = THIS_MODULE;
+       s->ca.read_attribute_mem = sp2_ci_read_attribute_mem;
+       s->ca.write_attribute_mem = sp2_ci_write_attribute_mem;
+       s->ca.read_cam_control = sp2_ci_read_cam_control;
+       s->ca.write_cam_control = sp2_ci_write_cam_control;
+       s->ca.slot_reset = sp2_ci_slot_reset;
+       s->ca.slot_shutdown = sp2_ci_slot_shutdown;
+       s->ca.slot_ts_enable = sp2_ci_slot_ts_enable;
+       s->ca.poll_slot_status = sp2_ci_poll_slot_status;
+       s->ca.data = s;
+       s->module_access_type = 0;
+
+       /* initialize all regs */
+       ret = sp2_write_i2c(s, 0x00, &cimax_init[0], 34);
+       if (ret)
+               goto err;
+
+       /* lock registers */
+       buf = 1;
+       ret = sp2_write_i2c(s, 0x1f, &buf, 1);
+       if (ret)
+               goto err;
+
+       /* power on slots */
+       ret = sp2_write_i2c(s, 0x18, &buf, 1);
+       if (ret)
+               goto err;
+
+       ret = dvb_ca_en50221_init(s->dvb_adap, &s->ca, 0, 1);
+       if (ret)
+               goto err;
+
+       return 0;
+
+err:
+       dev_dbg(&s->client->dev, "init failed=%d\n", ret);
+       return ret;
+}
+
+int sp2_exit(struct i2c_client *client)
+{
+       struct sp2 *s;
+
+       dev_dbg(&client->dev, "\n");
+
+       if (client == NULL)
+               return 0;
+
+       s = i2c_get_clientdata(client);
+       if (s == NULL)
+               return 0;
+
+       if (s->ca.data == NULL)
+               return 0;
+
+       dvb_ca_en50221_release(&s->ca);
+
+       return 0;
+}
+
+static int sp2_probe(struct i2c_client *client,
+               const struct i2c_device_id *id)
+{
+       struct sp2_config *cfg = client->dev.platform_data;
+       struct sp2 *s;
+       int ret;
+
+       dev_dbg(&client->dev, "\n");
+
+       s = kzalloc(sizeof(struct sp2), GFP_KERNEL);
+       if (!s) {
+               ret = -ENOMEM;
+               dev_err(&client->dev, "kzalloc() failed\n");
+               goto err;
+       }
+
+       s->client = client;
+       s->dvb_adap = cfg->dvb_adap;
+       s->priv = cfg->priv;
+       s->ci_control = cfg->ci_control;
+
+       i2c_set_clientdata(client, s);
+
+       ret = sp2_init(s);
+       if (ret)
+               goto err;
+
+       dev_info(&s->client->dev, "CIMaX SP2 successfully attached\n");
+       return 0;
+err:
+       dev_dbg(&client->dev, "init failed=%d\n", ret);
+       kfree(s);
+
+       return ret;
+}
+
+static int sp2_remove(struct i2c_client *client)
+{
+       struct si2157 *s = i2c_get_clientdata(client);
+
+       dev_dbg(&client->dev, "\n");
+
+       sp2_exit(client);
+       if (s != NULL)
+               kfree(s);
+
+       return 0;
+}
+
+static const struct i2c_device_id sp2_id[] = {
+       {"sp2", 0},
+       {}
+};
+MODULE_DEVICE_TABLE(i2c, sp2_id);
+
+static struct i2c_driver sp2_driver = {
+       .driver = {
+               .owner  = THIS_MODULE,
+               .name   = "sp2",
+       },
+       .probe          = sp2_probe,
+       .remove         = sp2_remove,
+       .id_table       = sp2_id,
+};
+
+module_i2c_driver(sp2_driver);
+
+MODULE_DESCRIPTION("CIMaX SP2/HF CI driver");
+MODULE_AUTHOR("Olli Salonen <olli.salonen@iki.fi>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb-frontends/sp2.h b/drivers/media/dvb-frontends/sp2.h
new file mode 100644 (file)
index 0000000..6cceea0
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * CIMaX SP2/HF CI driver
+ *
+ * Copyright (C) 2014 Olli Salonen <olli.salonen@iki.fi>
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (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 SP2_H
+#define SP2_H
+
+#include <linux/kconfig.h>
+#include "dvb_ca_en50221.h"
+
+/*
+ * I2C address
+ * 0x40 (port 0)
+ * 0x41 (port 1)
+ */
+struct sp2_config {
+       /* dvb_adapter to attach the ci to */
+       struct dvb_adapter *dvb_adap;
+
+       /* function ci_control handles the device specific ci ops */
+       void *ci_control;
+
+       /* priv is passed back to function ci_control */
+       void *priv;
+};
+
+extern int sp2_ci_read_attribute_mem(struct dvb_ca_en50221 *en50221,
+                                       int slot, int addr);
+extern int sp2_ci_write_attribute_mem(struct dvb_ca_en50221 *en50221,
+                                       int slot, int addr, u8 data);
+extern int sp2_ci_read_cam_control(struct dvb_ca_en50221 *en50221,
+                                       int slot, u8 addr);
+extern int sp2_ci_write_cam_control(struct dvb_ca_en50221 *en50221,
+                                       int slot, u8 addr, u8 data);
+extern int sp2_ci_slot_reset(struct dvb_ca_en50221 *en50221, int slot);
+extern int sp2_ci_slot_shutdown(struct dvb_ca_en50221 *en50221, int slot);
+extern int sp2_ci_slot_ts_enable(struct dvb_ca_en50221 *en50221, int slot);
+extern int sp2_ci_poll_slot_status(struct dvb_ca_en50221 *en50221,
+                                       int slot, int open);
+
+#endif
diff --git a/drivers/media/dvb-frontends/sp2_priv.h b/drivers/media/dvb-frontends/sp2_priv.h
new file mode 100644 (file)
index 0000000..37fef7b
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * CIMaX SP2/HF CI driver
+ *
+ * Copyright (C) 2014 Olli Salonen <olli.salonen@iki.fi>
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (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 SP2_PRIV_H
+#define SP2_PRIV_H
+
+#include "sp2.h"
+#include "dvb_frontend.h"
+
+/* state struct */
+struct sp2 {
+       int status;
+       struct i2c_client *client;
+       struct dvb_adapter *dvb_adap;
+       struct dvb_ca_en50221 ca;
+       int module_access_type;
+       unsigned long next_status_checked_time;
+       void *priv;
+       void *ci_control;
+};
+
+#define SP2_CI_ATTR_ACS                0x00
+#define SP2_CI_IO_ACS          0x04
+#define SP2_CI_WR              0
+#define SP2_CI_RD              1
+
+/* Module control register (0x00 module A, 0x09 module B) bits */
+#define SP2_MOD_CTL_DET                0x01
+#define SP2_MOD_CTL_AUTO       0x02
+#define SP2_MOD_CTL_ACS0       0x04
+#define SP2_MOD_CTL_ACS1       0x08
+#define SP2_MOD_CTL_HAD                0x10
+#define SP2_MOD_CTL_TSIEN      0x20
+#define SP2_MOD_CTL_TSOEN      0x40
+#define SP2_MOD_CTL_RST                0x80
+
+#endif
index 2aa8ef76eba259efba6490590f5201f0882e5805..57dc2abaa87bc7d5e0cf881d3b30e3065a6dfc26 100644 (file)
@@ -394,8 +394,7 @@ static int sp8870_read_ber (struct dvb_frontend* fe, u32 * ber)
        if (ret < 0)
                return -EIO;
 
-        tmp = ret << 6;
-
+       tmp = ret << 6;
        if (tmp >= 0x3FFF0)
                tmp = ~0;
 
index 59b6e661acc085bd99e6c11ff8dc8f58c88de35f..b31ff265ff248996507a0766739bb5e10392a239 100644 (file)
@@ -59,7 +59,6 @@ struct stv0367cab_state {
        int locked;                     /* channel found                */
        u32 freq_khz;                   /* found frequency (in kHz)     */
        u32 symbol_rate;                /* found symbol rate (in Bds)   */
-       enum stv0367cab_mod modulation; /* modulation                   */
        fe_spectral_inversion_t spect_inv; /* Spectrum Inversion        */
 };
 
@@ -554,7 +553,7 @@ static struct st_register def0367ter[STV0367TER_NBREGS] = {
 #define RF_LOOKUP_TABLE_SIZE  31
 #define RF_LOOKUP_TABLE2_SIZE 16
 /* RF Level (for RF AGC->AGC1) Lookup Table, depends on the board and tuner.*/
-s32 stv0367cab_RF_LookUp1[RF_LOOKUP_TABLE_SIZE][RF_LOOKUP_TABLE_SIZE] = {
+static const s32 stv0367cab_RF_LookUp1[RF_LOOKUP_TABLE_SIZE][RF_LOOKUP_TABLE_SIZE] = {
        {/*AGC1*/
                48, 50, 51, 53, 54, 56, 57, 58, 60, 61, 62, 63,
                64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75,
@@ -566,7 +565,7 @@ s32 stv0367cab_RF_LookUp1[RF_LOOKUP_TABLE_SIZE][RF_LOOKUP_TABLE_SIZE] = {
        }
 };
 /* RF Level (for IF AGC->AGC2) Lookup Table, depends on the board and tuner.*/
-s32 stv0367cab_RF_LookUp2[RF_LOOKUP_TABLE2_SIZE][RF_LOOKUP_TABLE2_SIZE] = {
+static const s32 stv0367cab_RF_LookUp2[RF_LOOKUP_TABLE2_SIZE][RF_LOOKUP_TABLE2_SIZE] = {
        {/*AGC2*/
                28, 29, 31, 32, 34, 35, 36, 37,
                38, 39, 40, 41, 42, 43, 44, 45,
@@ -1935,8 +1934,6 @@ static int stv0367ter_get_frontend(struct dvb_frontend *fe)
        struct dtv_frontend_properties *p = &fe->dtv_property_cache;
        struct stv0367_state *state = fe->demodulator_priv;
        struct stv0367ter_state *ter_state = state->ter_state;
-
-       int error = 0;
        enum stv0367_ter_mode mode;
        int constell = 0,/* snr = 0,*/ Data = 0;
 
@@ -2020,7 +2017,7 @@ static int stv0367ter_get_frontend(struct dvb_frontend *fe)
 
        p->guard_interval = stv0367_readbits(state, F367TER_SYR_GUARD);
 
-       return error;
+       return 0;
 }
 
 static int stv0367ter_read_snr(struct dvb_frontend *fe, u16 *snr)
@@ -2999,7 +2996,6 @@ enum stv0367_cab_signal_type stv0367cab_algo(struct stv0367_state *state,
 
        if (QAMFEC_Lock) {
                signalType = FE_CAB_DATAOK;
-               cab_state->modulation = p->modulation;
                cab_state->spect_inv = stv0367_readbits(state,
                                                        F367CAB_QUAD_INV);
 #if 0
@@ -3165,7 +3161,7 @@ static int stv0367cab_get_frontend(struct dvb_frontend *fe)
        case FE_CAB_MOD_QAM128:
                p->modulation = QAM_128;
                break;
-       case QAM_256:
+       case FE_CAB_MOD_QAM256:
                p->modulation = QAM_256;
                break;
        default:
index e5a87b57d8550c39d7519282d1e6469a3c939b84..2c88abfab5313b5976b14f31637794ffa1017ba0 100644 (file)
@@ -1270,7 +1270,6 @@ enum fe_stv0900_error stv0900_st_dvbs2_single(struct stv0900_internal *intp,
                                        enum fe_stv0900_demod_mode LDPC_Mode,
                                        enum fe_stv0900_demod_num demod)
 {
-       enum fe_stv0900_error error = STV0900_NO_ERROR;
        s32 reg_ind;
 
        dprintk("%s\n", __func__);
@@ -1337,7 +1336,7 @@ enum fe_stv0900_error stv0900_st_dvbs2_single(struct stv0900_internal *intp,
                break;
        }
 
-       return error;
+       return STV0900_NO_ERROR;
 }
 
 static enum fe_stv0900_error stv0900_init_internal(struct dvb_frontend *fe,
@@ -1555,8 +1554,6 @@ static int stv0900_status(struct stv0900_internal *intp,
 static int stv0900_set_mis(struct stv0900_internal *intp,
                                enum fe_stv0900_demod_num demod, int mis)
 {
-       enum fe_stv0900_error error = STV0900_NO_ERROR;
-
        dprintk("%s\n", __func__);
 
        if (mis < 0 || mis > 255) {
@@ -1569,7 +1566,7 @@ static int stv0900_set_mis(struct stv0900_internal *intp,
                stv0900_write_reg(intp, ISIBITENA, 0xff);
        }
 
-       return error;
+       return STV0900_NO_ERROR;
 }
 
 
index 4ce1d260b3eba1b7e4acdce23345df8b2108e0f3..a0a7b1664c5339f36e97a296230dced6c4500dfb 100644 (file)
@@ -1733,9 +1733,10 @@ static void stv0900_set_search_standard(struct stv0900_internal *intp,
                break;
        case STV0900_SEARCH_DSS:
                dprintk("Search Standard = DSS\n");
-       case STV0900_SEARCH_DVBS2:
                break;
+       case STV0900_SEARCH_DVBS2:
                dprintk("Search Standard = DVBS2\n");
+               break;
        case STV0900_AUTO_SEARCH:
        default:
                dprintk("Search Standard = AUTO\n");
diff --git a/drivers/media/dvb-frontends/tc90522.c b/drivers/media/dvb-frontends/tc90522.c
new file mode 100644 (file)
index 0000000..d9905fb
--- /dev/null
@@ -0,0 +1,840 @@
+/*
+ * Toshiba TC90522 Demodulator
+ *
+ * Copyright (C) 2014 Akihiro Tsukada <tskd08@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2.
+ *
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+/*
+ * NOTICE:
+ * This driver is incomplete and lacks init/config of the chips,
+ * as the necessary info is not disclosed.
+ * It assumes that users of this driver (such as a PCI bridge of
+ * DTV receiver cards) properly init and configure the chip
+ * via I2C *before* calling this driver's init() function.
+ *
+ * Currently, PT3 driver is the only one that uses this driver,
+ * and contains init/config code in its firmware.
+ * Thus some part of the code might be dependent on PT3 specific config.
+ */
+
+#include <linux/kernel.h>
+#include <linux/math64.h>
+#include <linux/dvb/frontend.h>
+#include "dvb_math.h"
+#include "tc90522.h"
+
+#define TC90522_I2C_THRU_REG 0xfe
+
+#define TC90522_MODULE_IDX(addr) (((u8)(addr) & 0x02U) >> 1)
+
+struct tc90522_state {
+       struct tc90522_config cfg;
+       struct dvb_frontend fe;
+       struct i2c_client *i2c_client;
+       struct i2c_adapter tuner_i2c;
+
+       bool lna;
+};
+
+struct reg_val {
+       u8 reg;
+       u8 val;
+};
+
+static int
+reg_write(struct tc90522_state *state, const struct reg_val *regs, int num)
+{
+       int i, ret;
+       struct i2c_msg msg;
+
+       ret = 0;
+       msg.addr = state->i2c_client->addr;
+       msg.flags = 0;
+       msg.len = 2;
+       for (i = 0; i < num; i++) {
+               msg.buf = (u8 *)&regs[i];
+               ret = i2c_transfer(state->i2c_client->adapter, &msg, 1);
+               if (ret == 0)
+                       ret = -EIO;
+               if (ret < 0)
+                       return ret;
+       }
+       return 0;
+}
+
+static int reg_read(struct tc90522_state *state, u8 reg, u8 *val, u8 len)
+{
+       struct i2c_msg msgs[2] = {
+               {
+                       .addr = state->i2c_client->addr,
+                       .flags = 0,
+                       .buf = &reg,
+                       .len = 1,
+               },
+               {
+                       .addr = state->i2c_client->addr,
+                       .flags = I2C_M_RD,
+                       .buf = val,
+                       .len = len,
+               },
+       };
+       int ret;
+
+       ret = i2c_transfer(state->i2c_client->adapter, msgs, ARRAY_SIZE(msgs));
+       if (ret == ARRAY_SIZE(msgs))
+               ret = 0;
+       else if (ret >= 0)
+               ret = -EIO;
+       return ret;
+}
+
+static struct tc90522_state *cfg_to_state(struct tc90522_config *c)
+{
+       return container_of(c, struct tc90522_state, cfg);
+}
+
+
+static int tc90522s_set_tsid(struct dvb_frontend *fe)
+{
+       struct reg_val set_tsid[] = {
+               { 0x8f, 00 },
+               { 0x90, 00 }
+       };
+
+       set_tsid[0].val = (fe->dtv_property_cache.stream_id & 0xff00) >> 8;
+       set_tsid[1].val = fe->dtv_property_cache.stream_id & 0xff;
+       return reg_write(fe->demodulator_priv, set_tsid, ARRAY_SIZE(set_tsid));
+}
+
+static int tc90522t_set_layers(struct dvb_frontend *fe)
+{
+       struct reg_val rv;
+       u8 laysel;
+
+       laysel = ~fe->dtv_property_cache.isdbt_layer_enabled & 0x07;
+       laysel = (laysel & 0x01) << 2 | (laysel & 0x02) | (laysel & 0x04) >> 2;
+       rv.reg = 0x71;
+       rv.val = laysel;
+       return reg_write(fe->demodulator_priv, &rv, 1);
+}
+
+/* frontend ops */
+
+static int tc90522s_read_status(struct dvb_frontend *fe, fe_status_t *status)
+{
+       struct tc90522_state *state;
+       int ret;
+       u8 reg;
+
+       state = fe->demodulator_priv;
+       ret = reg_read(state, 0xc3, &reg, 1);
+       if (ret < 0)
+               return ret;
+
+       *status = 0;
+       if (reg & 0x80) /* input level under min ? */
+               return 0;
+       *status |= FE_HAS_SIGNAL;
+
+       if (reg & 0x60) /* carrier? */
+               return 0;
+       *status |= FE_HAS_CARRIER | FE_HAS_VITERBI | FE_HAS_SYNC;
+
+       if (reg & 0x10)
+               return 0;
+       if (reg_read(state, 0xc5, &reg, 1) < 0 || !(reg & 0x03))
+               return 0;
+       *status |= FE_HAS_LOCK;
+       return 0;
+}
+
+static int tc90522t_read_status(struct dvb_frontend *fe, fe_status_t *status)
+{
+       struct tc90522_state *state;
+       int ret;
+       u8 reg;
+
+       state = fe->demodulator_priv;
+       ret = reg_read(state, 0x96, &reg, 1);
+       if (ret < 0)
+               return ret;
+
+       *status = 0;
+       if (reg & 0xe0) {
+               *status = FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_VITERBI
+                               | FE_HAS_SYNC | FE_HAS_LOCK;
+               return 0;
+       }
+
+       ret = reg_read(state, 0x80, &reg, 1);
+       if (ret < 0)
+               return ret;
+
+       if (reg & 0xf0)
+               return 0;
+       *status |= FE_HAS_SIGNAL | FE_HAS_CARRIER;
+
+       if (reg & 0x0c)
+               return 0;
+       *status |= FE_HAS_SYNC | FE_HAS_VITERBI;
+
+       if (reg & 0x02)
+               return 0;
+       *status |= FE_HAS_LOCK;
+       return 0;
+}
+
+static const fe_code_rate_t fec_conv_sat[] = {
+       FEC_NONE, /* unused */
+       FEC_1_2, /* for BPSK */
+       FEC_1_2, FEC_2_3, FEC_3_4, FEC_5_6, FEC_7_8, /* for QPSK */
+       FEC_2_3, /* for 8PSK. (trellis code) */
+};
+
+static int tc90522s_get_frontend(struct dvb_frontend *fe)
+{
+       struct tc90522_state *state;
+       struct dtv_frontend_properties *c;
+       struct dtv_fe_stats *stats;
+       int ret, i;
+       int layers;
+       u8 val[10];
+       u32 cndat;
+
+       state = fe->demodulator_priv;
+       c = &fe->dtv_property_cache;
+       c->delivery_system = SYS_ISDBS;
+
+       layers = 0;
+       ret = reg_read(state, 0xe8, val, 3);
+       if (ret == 0) {
+               int slots;
+               u8 v;
+
+               /* high/single layer */
+               v = (val[0] & 0x70) >> 4;
+               c->modulation = (v == 7) ? PSK_8 : QPSK;
+               c->fec_inner = fec_conv_sat[v];
+               c->layer[0].fec = c->fec_inner;
+               c->layer[0].modulation = c->modulation;
+               c->layer[0].segment_count = val[1] & 0x3f; /* slots */
+
+               /* low layer */
+               v = (val[0] & 0x07);
+               c->layer[1].fec = fec_conv_sat[v];
+               if (v == 0)  /* no low layer */
+                       c->layer[1].segment_count = 0;
+               else
+                       c->layer[1].segment_count = val[2] & 0x3f; /* slots */
+               /* actually, BPSK if v==1, but not defined in fe_modulation_t */
+               c->layer[1].modulation = QPSK;
+               layers = (v > 0) ? 2 : 1;
+
+               slots =  c->layer[0].segment_count +  c->layer[1].segment_count;
+               c->symbol_rate = 28860000 * slots / 48;
+       }
+
+       /* statistics */
+
+       stats = &c->strength;
+       stats->len = 0;
+       /* let the connected tuner set RSSI property cache */
+       if (fe->ops.tuner_ops.get_rf_strength) {
+               u16 dummy;
+
+               fe->ops.tuner_ops.get_rf_strength(fe, &dummy);
+       }
+
+       stats = &c->cnr;
+       stats->len = 1;
+       stats->stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+       cndat = 0;
+       ret = reg_read(state, 0xbc, val, 2);
+       if (ret == 0)
+               cndat = val[0] << 8 | val[1];
+       if (cndat >= 3000) {
+               u32 p, p4;
+               s64 cn;
+
+               cndat -= 3000;  /* cndat: 4.12 fixed point float */
+               /*
+                * cnr[mdB] = -1634.6 * P^5 + 14341 * P^4 - 50259 * P^3
+                *                 + 88977 * P^2 - 89565 * P + 58857
+                *  (P = sqrt(cndat) / 64)
+                */
+               /* p := sqrt(cndat) << 8 = P << 14, 2.14 fixed  point float */
+               /* cn = cnr << 3 */
+               p = int_sqrt(cndat << 16);
+               p4 = cndat * cndat;
+               cn = div64_s64(-16346LL * p4 * p, 10) >> 35;
+               cn += (14341LL * p4) >> 21;
+               cn -= (50259LL * cndat * p) >> 23;
+               cn += (88977LL * cndat) >> 9;
+               cn -= (89565LL * p) >> 11;
+               cn += 58857  << 3;
+               stats->stat[0].svalue = cn >> 3;
+               stats->stat[0].scale = FE_SCALE_DECIBEL;
+       }
+
+       /* per-layer post viterbi BER (or PER? config dependent?) */
+       stats = &c->post_bit_error;
+       memset(stats, 0, sizeof(*stats));
+       stats->len = layers;
+       ret = reg_read(state, 0xeb, val, 10);
+       if (ret < 0)
+               for (i = 0; i < layers; i++)
+                       stats->stat[i].scale = FE_SCALE_NOT_AVAILABLE;
+       else {
+               for (i = 0; i < layers; i++) {
+                       stats->stat[i].scale = FE_SCALE_COUNTER;
+                       stats->stat[i].uvalue = val[i * 5] << 16
+                               | val[i * 5 + 1] << 8 | val[i * 5 + 2];
+               }
+       }
+       stats = &c->post_bit_count;
+       memset(stats, 0, sizeof(*stats));
+       stats->len = layers;
+       if (ret < 0)
+               for (i = 0; i < layers; i++)
+                       stats->stat[i].scale = FE_SCALE_NOT_AVAILABLE;
+       else {
+               for (i = 0; i < layers; i++) {
+                       stats->stat[i].scale = FE_SCALE_COUNTER;
+                       stats->stat[i].uvalue =
+                               val[i * 5 + 3] << 8 | val[i * 5 + 4];
+                       stats->stat[i].uvalue *= 204 * 8;
+               }
+       }
+
+       return 0;
+}
+
+
+static const fe_transmit_mode_t tm_conv[] = {
+       TRANSMISSION_MODE_2K,
+       TRANSMISSION_MODE_4K,
+       TRANSMISSION_MODE_8K,
+       0
+};
+
+static const fe_code_rate_t fec_conv_ter[] = {
+       FEC_1_2, FEC_2_3, FEC_3_4, FEC_5_6, FEC_7_8, 0, 0, 0
+};
+
+static const fe_modulation_t mod_conv[] = {
+       DQPSK, QPSK, QAM_16, QAM_64, 0, 0, 0, 0
+};
+
+static int tc90522t_get_frontend(struct dvb_frontend *fe)
+{
+       struct tc90522_state *state;
+       struct dtv_frontend_properties *c;
+       struct dtv_fe_stats *stats;
+       int ret, i;
+       int layers;
+       u8 val[15], mode;
+       u32 cndat;
+
+       state = fe->demodulator_priv;
+       c = &fe->dtv_property_cache;
+       c->delivery_system = SYS_ISDBT;
+       c->bandwidth_hz = 6000000;
+       mode = 1;
+       ret = reg_read(state, 0xb0, val, 1);
+       if (ret == 0) {
+               mode = (val[0] & 0xc0) >> 2;
+               c->transmission_mode = tm_conv[mode];
+               c->guard_interval = (val[0] & 0x30) >> 4;
+       }
+
+       ret = reg_read(state, 0xb2, val, 6);
+       layers = 0;
+       if (ret == 0) {
+               u8 v;
+
+               c->isdbt_partial_reception = val[0] & 0x01;
+               c->isdbt_sb_mode = (val[0] & 0xc0) == 0x01;
+
+               /* layer A */
+               v = (val[2] & 0x78) >> 3;
+               if (v == 0x0f)
+                       c->layer[0].segment_count = 0;
+               else {
+                       layers++;
+                       c->layer[0].segment_count = v;
+                       c->layer[0].fec = fec_conv_ter[(val[1] & 0x1c) >> 2];
+                       c->layer[0].modulation = mod_conv[(val[1] & 0xe0) >> 5];
+                       v = (val[1] & 0x03) << 1 | (val[2] & 0x80) >> 7;
+                       c->layer[0].interleaving = v;
+               }
+
+               /* layer B */
+               v = (val[3] & 0x03) << 1 | (val[4] & 0xc0) >> 6;
+               if (v == 0x0f)
+                       c->layer[1].segment_count = 0;
+               else {
+                       layers++;
+                       c->layer[1].segment_count = v;
+                       c->layer[1].fec = fec_conv_ter[(val[3] & 0xe0) >> 5];
+                       c->layer[1].modulation = mod_conv[(val[2] & 0x07)];
+                       c->layer[1].interleaving = (val[3] & 0x1c) >> 2;
+               }
+
+               /* layer C */
+               v = (val[5] & 0x1e) >> 1;
+               if (v == 0x0f)
+                       c->layer[2].segment_count = 0;
+               else {
+                       layers++;
+                       c->layer[2].segment_count = v;
+                       c->layer[2].fec = fec_conv_ter[(val[4] & 0x07)];
+                       c->layer[2].modulation = mod_conv[(val[4] & 0x38) >> 3];
+                       c->layer[2].interleaving = (val[5] & 0xe0) >> 5;
+               }
+       }
+
+       /* statistics */
+
+       stats = &c->strength;
+       stats->len = 0;
+       /* let the connected tuner set RSSI property cache */
+       if (fe->ops.tuner_ops.get_rf_strength) {
+               u16 dummy;
+
+               fe->ops.tuner_ops.get_rf_strength(fe, &dummy);
+       }
+
+       stats = &c->cnr;
+       stats->len = 1;
+       stats->stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+       cndat = 0;
+       ret = reg_read(state, 0x8b, val, 3);
+       if (ret == 0)
+               cndat = val[0] << 16 | val[1] << 8 | val[2];
+       if (cndat != 0) {
+               u32 p, tmp;
+               s64 cn;
+
+               /*
+                * cnr[mdB] = 0.024 P^4 - 1.6 P^3 + 39.8 P^2 + 549.1 P + 3096.5
+                * (P = 10log10(5505024/cndat))
+                */
+               /* cn = cnr << 3 (61.3 fixed point float */
+               /* p = 10log10(5505024/cndat) << 24  (8.24 fixed point float)*/
+               p = intlog10(5505024) - intlog10(cndat);
+               p *= 10;
+
+               cn = 24772;
+               cn += div64_s64(43827LL * p, 10) >> 24;
+               tmp = p >> 8;
+               cn += div64_s64(3184LL * tmp * tmp, 10) >> 32;
+               tmp = p >> 13;
+               cn -= div64_s64(128LL * tmp * tmp * tmp, 10) >> 33;
+               tmp = p >> 18;
+               cn += div64_s64(192LL * tmp * tmp * tmp * tmp, 1000) >> 24;
+
+               stats->stat[0].svalue = cn >> 3;
+               stats->stat[0].scale = FE_SCALE_DECIBEL;
+       }
+
+       /* per-layer post viterbi BER (or PER? config dependent?) */
+       stats = &c->post_bit_error;
+       memset(stats, 0, sizeof(*stats));
+       stats->len = layers;
+       ret = reg_read(state, 0x9d, val, 15);
+       if (ret < 0)
+               for (i = 0; i < layers; i++)
+                       stats->stat[i].scale = FE_SCALE_NOT_AVAILABLE;
+       else {
+               for (i = 0; i < layers; i++) {
+                       stats->stat[i].scale = FE_SCALE_COUNTER;
+                       stats->stat[i].uvalue = val[i * 3] << 16
+                               | val[i * 3 + 1] << 8 | val[i * 3 + 2];
+               }
+       }
+       stats = &c->post_bit_count;
+       memset(stats, 0, sizeof(*stats));
+       stats->len = layers;
+       if (ret < 0)
+               for (i = 0; i < layers; i++)
+                       stats->stat[i].scale = FE_SCALE_NOT_AVAILABLE;
+       else {
+               for (i = 0; i < layers; i++) {
+                       stats->stat[i].scale = FE_SCALE_COUNTER;
+                       stats->stat[i].uvalue =
+                               val[9 + i * 2] << 8 | val[9 + i * 2 + 1];
+                       stats->stat[i].uvalue *= 204 * 8;
+               }
+       }
+
+       return 0;
+}
+
+static const struct reg_val reset_sat = { 0x03, 0x01 };
+static const struct reg_val reset_ter = { 0x01, 0x40 };
+
+static int tc90522_set_frontend(struct dvb_frontend *fe)
+{
+       struct tc90522_state *state;
+       int ret;
+
+       state = fe->demodulator_priv;
+
+       if (fe->ops.tuner_ops.set_params)
+               ret = fe->ops.tuner_ops.set_params(fe);
+       else
+               ret = -ENODEV;
+       if (ret < 0)
+               goto failed;
+
+       if (fe->ops.delsys[0] == SYS_ISDBS) {
+               ret = tc90522s_set_tsid(fe);
+               if (ret < 0)
+                       goto failed;
+               ret = reg_write(state, &reset_sat, 1);
+       } else {
+               ret = tc90522t_set_layers(fe);
+               if (ret < 0)
+                       goto failed;
+               ret = reg_write(state, &reset_ter, 1);
+       }
+       if (ret < 0)
+               goto failed;
+
+       return 0;
+
+failed:
+       dev_warn(&state->tuner_i2c.dev, "(%s) failed. [adap%d-fe%d]\n",
+                       __func__, fe->dvb->num, fe->id);
+       return ret;
+}
+
+static int tc90522_get_tune_settings(struct dvb_frontend *fe,
+       struct dvb_frontend_tune_settings *settings)
+{
+       if (fe->ops.delsys[0] == SYS_ISDBS) {
+               settings->min_delay_ms = 250;
+               settings->step_size = 1000;
+               settings->max_drift = settings->step_size * 2;
+       } else {
+               settings->min_delay_ms = 400;
+               settings->step_size = 142857;
+               settings->max_drift = settings->step_size;
+       }
+       return 0;
+}
+
+static int tc90522_set_if_agc(struct dvb_frontend *fe, bool on)
+{
+       struct reg_val agc_sat[] = {
+               { 0x0a, 0x00 },
+               { 0x10, 0x30 },
+               { 0x11, 0x00 },
+               { 0x03, 0x01 },
+       };
+       struct reg_val agc_ter[] = {
+               { 0x25, 0x00 },
+               { 0x23, 0x4c },
+               { 0x01, 0x40 },
+       };
+       struct tc90522_state *state;
+       struct reg_val *rv;
+       int num;
+
+       state = fe->demodulator_priv;
+       if (fe->ops.delsys[0] == SYS_ISDBS) {
+               agc_sat[0].val = on ? 0xff : 0x00;
+               agc_sat[1].val |= 0x80;
+               agc_sat[1].val |= on ? 0x01 : 0x00;
+               agc_sat[2].val |= on ? 0x40 : 0x00;
+               rv = agc_sat;
+               num = ARRAY_SIZE(agc_sat);
+       } else {
+               agc_ter[0].val = on ? 0x40 : 0x00;
+               agc_ter[1].val |= on ? 0x00 : 0x01;
+               rv = agc_ter;
+               num = ARRAY_SIZE(agc_ter);
+       }
+       return reg_write(state, rv, num);
+}
+
+static const struct reg_val sleep_sat = { 0x17, 0x01 };
+static const struct reg_val sleep_ter = { 0x03, 0x90 };
+
+static int tc90522_sleep(struct dvb_frontend *fe)
+{
+       struct tc90522_state *state;
+       int ret;
+
+       state = fe->demodulator_priv;
+       if (fe->ops.delsys[0] == SYS_ISDBS)
+               ret = reg_write(state, &sleep_sat, 1);
+       else {
+               ret = reg_write(state, &sleep_ter, 1);
+               if (ret == 0 && fe->ops.set_lna &&
+                   fe->dtv_property_cache.lna == LNA_AUTO) {
+                       fe->dtv_property_cache.lna = 0;
+                       ret = fe->ops.set_lna(fe);
+                       fe->dtv_property_cache.lna = LNA_AUTO;
+               }
+       }
+       if (ret < 0)
+               dev_warn(&state->tuner_i2c.dev,
+                       "(%s) failed. [adap%d-fe%d]\n",
+                       __func__, fe->dvb->num, fe->id);
+       return ret;
+}
+
+static const struct reg_val wakeup_sat = { 0x17, 0x00 };
+static const struct reg_val wakeup_ter = { 0x03, 0x80 };
+
+static int tc90522_init(struct dvb_frontend *fe)
+{
+       struct tc90522_state *state;
+       int ret;
+
+       /*
+        * Because the init sequence is not public,
+        * the parent device/driver should have init'ed the device before.
+        * just wake up the device here.
+        */
+
+       state = fe->demodulator_priv;
+       if (fe->ops.delsys[0] == SYS_ISDBS)
+               ret = reg_write(state, &wakeup_sat, 1);
+       else {
+               ret = reg_write(state, &wakeup_ter, 1);
+               if (ret == 0 && fe->ops.set_lna &&
+                   fe->dtv_property_cache.lna == LNA_AUTO) {
+                       fe->dtv_property_cache.lna = 1;
+                       ret = fe->ops.set_lna(fe);
+                       fe->dtv_property_cache.lna = LNA_AUTO;
+               }
+       }
+       if (ret < 0) {
+               dev_warn(&state->tuner_i2c.dev,
+                       "(%s) failed. [adap%d-fe%d]\n",
+                       __func__, fe->dvb->num, fe->id);
+               return ret;
+       }
+
+       /* prefer 'all-layers' to 'none' as a default */
+       if (fe->dtv_property_cache.isdbt_layer_enabled == 0)
+               fe->dtv_property_cache.isdbt_layer_enabled = 7;
+       return tc90522_set_if_agc(fe, true);
+}
+
+
+/*
+ * tuner I2C adapter functions
+ */
+
+static int
+tc90522_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
+{
+       struct tc90522_state *state;
+       struct i2c_msg *new_msgs;
+       int i, j;
+       int ret, rd_num;
+       u8 wbuf[256];
+       u8 *p, *bufend;
+
+       if (num <= 0)
+               return -EINVAL;
+
+       rd_num = 0;
+       for (i = 0; i < num; i++)
+               if (msgs[i].flags & I2C_M_RD)
+                       rd_num++;
+       new_msgs = kmalloc(sizeof(*new_msgs) * (num + rd_num), GFP_KERNEL);
+       if (!new_msgs)
+               return -ENOMEM;
+
+       state = i2c_get_adapdata(adap);
+       p = wbuf;
+       bufend = wbuf + sizeof(wbuf);
+       for (i = 0, j = 0; i < num; i++, j++) {
+               new_msgs[j].addr = state->i2c_client->addr;
+               new_msgs[j].flags = msgs[i].flags;
+
+               if (msgs[i].flags & I2C_M_RD) {
+                       new_msgs[j].flags &= ~I2C_M_RD;
+                       if (p + 2 > bufend)
+                               break;
+                       p[0] = TC90522_I2C_THRU_REG;
+                       p[1] = msgs[i].addr << 1 | 0x01;
+                       new_msgs[j].buf = p;
+                       new_msgs[j].len = 2;
+                       p += 2;
+                       j++;
+                       new_msgs[j].addr = state->i2c_client->addr;
+                       new_msgs[j].flags = msgs[i].flags;
+                       new_msgs[j].buf = msgs[i].buf;
+                       new_msgs[j].len = msgs[i].len;
+                       continue;
+               }
+
+               if (p + msgs[i].len + 2 > bufend)
+                       break;
+               p[0] = TC90522_I2C_THRU_REG;
+               p[1] = msgs[i].addr << 1;
+               memcpy(p + 2, msgs[i].buf, msgs[i].len);
+               new_msgs[j].buf = p;
+               new_msgs[j].len = msgs[i].len + 2;
+               p += new_msgs[j].len;
+       }
+
+       if (i < num)
+               ret = -ENOMEM;
+       else
+               ret = i2c_transfer(state->i2c_client->adapter, new_msgs, j);
+       if (ret >= 0 && ret < j)
+               ret = -EIO;
+       kfree(new_msgs);
+       return (ret == j) ? num : ret;
+}
+
+static u32 tc90522_functionality(struct i2c_adapter *adap)
+{
+       return I2C_FUNC_I2C;
+}
+
+static const struct i2c_algorithm tc90522_tuner_i2c_algo = {
+       .master_xfer   = &tc90522_master_xfer,
+       .functionality = &tc90522_functionality,
+};
+
+
+/*
+ * I2C driver functions
+ */
+
+static const struct dvb_frontend_ops tc90522_ops_sat = {
+       .delsys = { SYS_ISDBS },
+       .info = {
+               .name = "Toshiba TC90522 ISDB-S module",
+               .frequency_min =  950000,
+               .frequency_max = 2150000,
+               .caps = FE_CAN_INVERSION_AUTO | FE_CAN_FEC_AUTO |
+                       FE_CAN_QAM_AUTO | FE_CAN_TRANSMISSION_MODE_AUTO |
+                       FE_CAN_GUARD_INTERVAL_AUTO | FE_CAN_HIERARCHY_AUTO,
+       },
+
+       .init = tc90522_init,
+       .sleep = tc90522_sleep,
+       .set_frontend = tc90522_set_frontend,
+       .get_tune_settings = tc90522_get_tune_settings,
+
+       .get_frontend = tc90522s_get_frontend,
+       .read_status = tc90522s_read_status,
+};
+
+static const struct dvb_frontend_ops tc90522_ops_ter = {
+       .delsys = { SYS_ISDBT },
+       .info = {
+               .name = "Toshiba TC90522 ISDB-T module",
+               .frequency_min = 470000000,
+               .frequency_max = 770000000,
+               .frequency_stepsize = 142857,
+               .caps = FE_CAN_INVERSION_AUTO |
+                       FE_CAN_FEC_1_2  | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
+                       FE_CAN_FEC_5_6  | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
+                       FE_CAN_QPSK     | FE_CAN_QAM_16 | FE_CAN_QAM_64 |
+                       FE_CAN_QAM_AUTO | FE_CAN_TRANSMISSION_MODE_AUTO |
+                       FE_CAN_GUARD_INTERVAL_AUTO | FE_CAN_RECOVER |
+                       FE_CAN_HIERARCHY_AUTO,
+       },
+
+       .init = tc90522_init,
+       .sleep = tc90522_sleep,
+       .set_frontend = tc90522_set_frontend,
+       .get_tune_settings = tc90522_get_tune_settings,
+
+       .get_frontend = tc90522t_get_frontend,
+       .read_status = tc90522t_read_status,
+};
+
+
+static int tc90522_probe(struct i2c_client *client,
+                        const struct i2c_device_id *id)
+{
+       struct tc90522_state *state;
+       struct tc90522_config *cfg;
+       const struct dvb_frontend_ops *ops;
+       struct i2c_adapter *adap;
+       int ret;
+
+       state = kzalloc(sizeof(*state), GFP_KERNEL);
+       if (!state)
+               return -ENOMEM;
+       state->i2c_client = client;
+
+       cfg = client->dev.platform_data;
+       memcpy(&state->cfg, cfg, sizeof(state->cfg));
+       cfg->fe = state->cfg.fe = &state->fe;
+       ops =  id->driver_data == 0 ? &tc90522_ops_sat : &tc90522_ops_ter;
+       memcpy(&state->fe.ops, ops, sizeof(*ops));
+       state->fe.demodulator_priv = state;
+
+       adap = &state->tuner_i2c;
+       adap->owner = THIS_MODULE;
+       adap->algo = &tc90522_tuner_i2c_algo;
+       adap->dev.parent = &client->dev;
+       strlcpy(adap->name, "tc90522_sub", sizeof(adap->name));
+       i2c_set_adapdata(adap, state);
+       ret = i2c_add_adapter(adap);
+       if (ret < 0)
+               goto err;
+       cfg->tuner_i2c = state->cfg.tuner_i2c = adap;
+
+       i2c_set_clientdata(client, &state->cfg);
+       dev_info(&client->dev, "Toshiba TC90522 attached.\n");
+       return 0;
+
+err:
+       kfree(state);
+       return ret;
+}
+
+static int tc90522_remove(struct i2c_client *client)
+{
+       struct tc90522_state *state;
+
+       state = cfg_to_state(i2c_get_clientdata(client));
+       i2c_del_adapter(&state->tuner_i2c);
+       kfree(state);
+       return 0;
+}
+
+
+static const struct i2c_device_id tc90522_id[] = {
+       { TC90522_I2C_DEV_SAT, 0 },
+       { TC90522_I2C_DEV_TER, 1 },
+       {}
+};
+MODULE_DEVICE_TABLE(i2c, tc90522_id);
+
+static struct i2c_driver tc90522_driver = {
+       .driver = {
+               .name   = "tc90522",
+       },
+       .probe          = tc90522_probe,
+       .remove         = tc90522_remove,
+       .id_table       = tc90522_id,
+};
+
+module_i2c_driver(tc90522_driver);
+
+MODULE_DESCRIPTION("Toshiba TC90522 frontend");
+MODULE_AUTHOR("Akihiro TSUKADA");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb-frontends/tc90522.h b/drivers/media/dvb-frontends/tc90522.h
new file mode 100644 (file)
index 0000000..b1cbddf
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * Toshiba TC90522 Demodulator
+ *
+ * Copyright (C) 2014 Akihiro Tsukada <tskd08@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2.
+ *
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+/*
+ * The demod has 4 input (2xISDB-T and 2xISDB-S),
+ * and provides independent sub modules for each input.
+ * As the sub modules work in parallel and have the separate i2c addr's,
+ * this driver treats each sub module as one demod device.
+ */
+
+#ifndef TC90522_H
+#define TC90522_H
+
+#include <linux/i2c.h>
+#include "dvb_frontend.h"
+
+/* I2C device types */
+#define TC90522_I2C_DEV_SAT "tc90522sat"
+#define TC90522_I2C_DEV_TER "tc90522ter"
+
+struct tc90522_config {
+       /* [OUT] frontend returned by driver */
+       struct dvb_frontend *fe;
+
+       /* [OUT] tuner I2C adapter returned by driver */
+       struct i2c_adapter *tuner_i2c;
+};
+
+#endif /* TC90522_H */
index 9619be5d48271827b28052c080f01fc5631224b7..4a19b85995f17f47018732e8c82a67847c15e0d6 100644 (file)
@@ -1037,7 +1037,7 @@ static int tda10071_init(struct dvb_frontend *fe)
                        ret = -EFAULT;
                        goto error;
                } else {
-                       priv->warm = 1;
+                       priv->warm = true;
                }
 
                cmd.args[0] = CMD_GET_FW_VERSION;
index 91b6b2e9b79228b6c497f7c7aba65dd36415f9da..ee09ec26c553ef7aa4e8387f4ba7bcab3948db37 100644 (file)
@@ -111,7 +111,7 @@ static int zl10039_write(struct zl10039_state *state,
 
        if (1 + count > sizeof(buf)) {
                printk(KERN_WARNING
-                      "%s: i2c wr reg=%04x: len=%zd is too big!\n",
+                      "%s: i2c wr reg=%04x: len=%zu is too big!\n",
                       KBUILD_MODNAME, reg, count);
                return -EINVAL;
        }
index d1a1a1324ef87018e030ba0aa149de3c79856085..251a556112a99586288f680e018103c0b9eef90c 100644 (file)
@@ -1157,6 +1157,10 @@ int avc_ca_pmt(struct firedtv *fdtv, char *msg, int length)
                if (pmt_cmd_id != 1 && pmt_cmd_id != 4)
                        dev_err(fdtv->device,
                                "invalid pmt_cmd_id %d\n", pmt_cmd_id);
+               if (program_info_length > sizeof(c->operand) - 4 - write_pos) {
+                       ret = -EINVAL;
+                       goto out;
+               }
 
                memcpy(&c->operand[write_pos], &msg[read_pos],
                       program_info_length);
@@ -1180,6 +1184,12 @@ int avc_ca_pmt(struct firedtv *fdtv, char *msg, int length)
                                dev_err(fdtv->device, "invalid pmt_cmd_id %d "
                                        "at stream level\n", pmt_cmd_id);
 
+                       if (es_info_length > sizeof(c->operand) - 4 -
+                                            write_pos) {
+                               ret = -EINVAL;
+                               goto out;
+                       }
+
                        memcpy(&c->operand[write_pos], &msg[read_pos],
                               es_info_length);
                        read_pos += es_info_length;
index 4466067643465563dfbe0db7057b2f50c4e9d2e3..2f04ce4b9118a43c39d2d8c8c5f6a7e1eb4ce6c7 100644 (file)
@@ -13,7 +13,7 @@
  * GNU General Public License for more details.
  */
 
-#ifndef ADV7343_REG_H
+#ifndef ADV7343_REGS_H
 #define ADV7343_REGS_H
 
 struct adv7343_std_info {
index de88b980a8370bea73e380da85eb33fe50610761..47795ff716882ba5fddb929529c94d0acf5a84bc 100644 (file)
@@ -1593,7 +1593,7 @@ static int adv7604_query_dv_timings(struct v4l2_subdev *sd,
                        bt->height += hdmi_read16(sd, 0x0b, 0xfff);
                        bt->il_vfrontporch = hdmi_read16(sd, 0x2c, 0x1fff) / 2;
                        bt->il_vsync = hdmi_read16(sd, 0x30, 0x1fff) / 2;
-                       bt->vbackporch = hdmi_read16(sd, 0x34, 0x1fff) / 2;
+                       bt->il_vbackporch = hdmi_read16(sd, 0x34, 0x1fff) / 2;
                }
                adv7604_fill_optional_dv_timings_fields(sd, timings);
        } else {
index 0d554919cdd52726f52deda278414aa62bb6e47c..48b628bc6714ecae53144f4bf90fa64d0454c90e 100644 (file)
@@ -1435,6 +1435,8 @@ static int adv7842_query_dv_timings(struct v4l2_subdev *sd,
 
        v4l2_dbg(1, debug, sd, "%s:\n", __func__);
 
+       memset(timings, 0, sizeof(struct v4l2_dv_timings));
+
        /* SDP block */
        if (state->mode == ADV7842_MODE_SDP)
                return -ENODATA;
@@ -1483,7 +1485,7 @@ static int adv7842_query_dv_timings(struct v4l2_subdev *sd,
                                        hdmi_read(sd, 0x2d)) / 2;
                        bt->il_vsync = ((hdmi_read(sd, 0x30) & 0x1f) * 256 +
                                        hdmi_read(sd, 0x31)) / 2;
-                       bt->vbackporch = ((hdmi_read(sd, 0x34) & 0x1f) * 256 +
+                       bt->il_vbackporch = ((hdmi_read(sd, 0x34) & 0x1f) * 256 +
                                        hdmi_read(sd, 0x35)) / 2;
                }
                adv7842_fill_optional_dv_timings_fields(sd, timings);
index c23de593c17d5572ff2123403ad6e4e006d21e55..d9ece4b2d047067dc19921e1e79a52fd80ad130e 100644 (file)
@@ -100,14 +100,14 @@ static int lm3560_enable_ctrl(struct lm3560_flash *flash,
        int rval;
 
        if (led_no == LM3560_LED0) {
-               if (on == true)
+               if (on)
                        rval = regmap_update_bits(flash->regmap,
                                                  REG_ENABLE, 0x08, 0x08);
                else
                        rval = regmap_update_bits(flash->regmap,
                                                  REG_ENABLE, 0x08, 0x00);
        } else {
-               if (on == true)
+               if (on)
                        rval = regmap_update_bits(flash->regmap,
                                                  REG_ENABLE, 0x10, 0x10);
                else
index cdd7c1b7259b008e873cc711294a3f0cecba422a..dd3db2458a4fc8fff9512b695c6b2b40651d5921 100644 (file)
@@ -19,6 +19,7 @@
 #include <media/v4l2-device.h>
 #include <media/v4l2-ctrls.h>
 #include <media/v4l2-mediabus.h>
+#include <media/v4l2-image-sizes.h>
 #include <media/ov7670.h>
 
 MODULE_AUTHOR("Jonathan Corbet <corbet@lwn.net>");
@@ -29,19 +30,6 @@ static bool debug;
 module_param(debug, bool, 0644);
 MODULE_PARM_DESC(debug, "Debug level (0-1)");
 
-/*
- * Basic window sizes.  These probably belong somewhere more globally
- * useful.
- */
-#define VGA_WIDTH      640
-#define VGA_HEIGHT     480
-#define QVGA_WIDTH     320
-#define QVGA_HEIGHT    240
-#define CIF_WIDTH      352
-#define CIF_HEIGHT     288
-#define QCIF_WIDTH     176
-#define        QCIF_HEIGHT     144
-
 /*
  * The 7670 sits on i2c with ID 0x42
  */
index 564f05f2c9efbe54d569c5030c7152ddc2f0390f..0e461a6fd0654cb3d97ef52d72e9b7c586f044b2 100644 (file)
@@ -816,7 +816,7 @@ static void s5k5baf_hw_find_min_fiv(struct s5k5baf *state)
                                 "error setting frame interval: %d\n", err);
                        state->error = -EINVAL;
                }
-       };
+       }
        v4l2_err(&state->sd, "cannot find correct frame interval\n");
        state->error = -ERANGE;
 }
index 04e9e55018a5044ff194f4d72f3bc01314ff75c4..4024ea6f1371ad48c1bd744a8a662bd545c53eb1 100644 (file)
@@ -660,7 +660,7 @@ static const struct v4l2_subdev_ops saa6752hs_ops = {
 static int saa6752hs_probe(struct i2c_client *client,
                const struct i2c_device_id *id)
 {
-       struct saa6752hs_state *h = kzalloc(sizeof(*h), GFP_KERNEL);
+       struct saa6752hs_state *h;
        struct v4l2_subdev *sd;
        struct v4l2_ctrl_handler *hdl;
        u8 addr = 0x13;
@@ -668,6 +668,8 @@ static int saa6752hs_probe(struct i2c_client *client,
 
        v4l_info(client, "chip found @ 0x%x (%s)\n",
                        client->addr << 1, client->adapter->name);
+
+       h = devm_kzalloc(&client->dev, sizeof(*h), GFP_KERNEL);
        if (h == NULL)
                return -ENOMEM;
        sd = &h->sd;
@@ -752,7 +754,6 @@ static int saa6752hs_probe(struct i2c_client *client,
                int err = hdl->error;
 
                v4l2_ctrl_handler_free(hdl);
-               kfree(h);
                return err;
        }
        v4l2_ctrl_cluster(3, &h->video_bitrate_mode);
@@ -767,7 +768,6 @@ static int saa6752hs_remove(struct i2c_client *client)
 
        v4l2_device_unregister_subdev(sd);
        v4l2_ctrl_handler_free(&to_state(sd)->hdl);
-       kfree(to_state(sd));
        return 0;
 }
 
index 62acb10630f9b2a1b12c114eddad10995308389e..932ed9be9ff3d756fb35948e8183e09faaa60c34 100644 (file)
@@ -31,8 +31,9 @@
 #include <linux/device.h>
 #include <linux/gpio.h>
 #include <linux/module.h>
-#include <linux/slab.h>
 #include <linux/regulator/consumer.h>
+#include <linux/slab.h>
+#include <linux/smiapp.h>
 #include <linux/v4l2-mediabus.h>
 #include <media/v4l2-device.h>
 
@@ -297,8 +298,9 @@ static int smiapp_pll_update(struct smiapp_sensor *sensor)
        if (rval < 0)
                return rval;
 
-       *sensor->pixel_rate_parray->p_cur.p_s64 = pll->vt_pix_clk_freq_hz;
-       *sensor->pixel_rate_csi->p_cur.p_s64 = pll->pixel_rate_csi;
+       __v4l2_ctrl_s_ctrl_int64(sensor->pixel_rate_parray,
+                                pll->vt_pix_clk_freq_hz);
+       __v4l2_ctrl_s_ctrl_int64(sensor->pixel_rate_csi, pll->pixel_rate_csi);
 
        return 0;
 }
@@ -319,13 +321,7 @@ static void __smiapp_update_exposure_limits(struct smiapp_sensor *sensor)
                + sensor->vblank->val
                - sensor->limits[SMIAPP_LIMIT_COARSE_INTEGRATION_TIME_MAX_MARGIN];
 
-       ctrl->maximum = max;
-       if (ctrl->default_value > max)
-               ctrl->default_value = max;
-       if (ctrl->val > max)
-               ctrl->val = max;
-       if (ctrl->cur.val > max)
-               ctrl->cur.val = max;
+       __v4l2_ctrl_modify_range(ctrl, ctrl->minimum, max, ctrl->step, max);
 }
 
 /*
@@ -404,6 +400,14 @@ static void smiapp_update_mbus_formats(struct smiapp_sensor *sensor)
                pixel_order_str[pixel_order]);
 }
 
+static const char * const smiapp_test_patterns[] = {
+       "Disabled",
+       "Solid Colour",
+       "Eight Vertical Colour Bars",
+       "Colour Bars With Fade to Grey",
+       "Pseudorandom Sequence (PN9)",
+};
+
 static int smiapp_set_ctrl(struct v4l2_ctrl *ctrl)
 {
        struct smiapp_sensor *sensor =
@@ -477,6 +481,39 @@ static int smiapp_set_ctrl(struct v4l2_ctrl *ctrl)
 
                return smiapp_pll_update(sensor);
 
+       case V4L2_CID_TEST_PATTERN: {
+               unsigned int i;
+
+               for (i = 0; i < ARRAY_SIZE(sensor->test_data); i++)
+                       v4l2_ctrl_activate(
+                               sensor->test_data[i],
+                               ctrl->val ==
+                               V4L2_SMIAPP_TEST_PATTERN_MODE_SOLID_COLOUR);
+
+               return smiapp_write(
+                       sensor, SMIAPP_REG_U16_TEST_PATTERN_MODE, ctrl->val);
+       }
+
+       case V4L2_CID_TEST_PATTERN_RED:
+               return smiapp_write(
+                       sensor, SMIAPP_REG_U16_TEST_DATA_RED, ctrl->val);
+
+       case V4L2_CID_TEST_PATTERN_GREENR:
+               return smiapp_write(
+                       sensor, SMIAPP_REG_U16_TEST_DATA_GREENR, ctrl->val);
+
+       case V4L2_CID_TEST_PATTERN_BLUE:
+               return smiapp_write(
+                       sensor, SMIAPP_REG_U16_TEST_DATA_BLUE, ctrl->val);
+
+       case V4L2_CID_TEST_PATTERN_GREENB:
+               return smiapp_write(
+                       sensor, SMIAPP_REG_U16_TEST_DATA_GREENB, ctrl->val);
+
+       case V4L2_CID_PIXEL_RATE:
+               /* For v4l2_ctrl_s_ctrl_int64() used internally. */
+               return 0;
+
        default:
                return -EINVAL;
        }
@@ -489,10 +526,10 @@ static const struct v4l2_ctrl_ops smiapp_ctrl_ops = {
 static int smiapp_init_controls(struct smiapp_sensor *sensor)
 {
        struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd);
-       unsigned int max;
+       unsigned int max, i;
        int rval;
 
-       rval = v4l2_ctrl_handler_init(&sensor->pixel_array->ctrl_handler, 7);
+       rval = v4l2_ctrl_handler_init(&sensor->pixel_array->ctrl_handler, 12);
        if (rval)
                return rval;
        sensor->pixel_array->ctrl_handler.lock = &sensor->mutex;
@@ -535,6 +572,20 @@ static int smiapp_init_controls(struct smiapp_sensor *sensor)
                &sensor->pixel_array->ctrl_handler, &smiapp_ctrl_ops,
                V4L2_CID_PIXEL_RATE, 1, INT_MAX, 1, 1);
 
+       v4l2_ctrl_new_std_menu_items(&sensor->pixel_array->ctrl_handler,
+                                    &smiapp_ctrl_ops, V4L2_CID_TEST_PATTERN,
+                                    ARRAY_SIZE(smiapp_test_patterns) - 1,
+                                    0, 0, smiapp_test_patterns);
+
+       for (i = 0; i < ARRAY_SIZE(sensor->test_data); i++) {
+               int max_value = (1 << sensor->csi_format->width) - 1;
+               sensor->test_data[i] =
+                       v4l2_ctrl_new_std(
+                               &sensor->pixel_array->ctrl_handler,
+                               &smiapp_ctrl_ops, V4L2_CID_TEST_PATTERN_RED + i,
+                               0, max_value, 1, max_value);
+       }
+
        if (sensor->pixel_array->ctrl_handler.error) {
                dev_err(&client->dev,
                        "pixel array controls initialization failed (%d)\n",
@@ -782,36 +833,25 @@ static void smiapp_update_blanking(struct smiapp_sensor *sensor)
 {
        struct v4l2_ctrl *vblank = sensor->vblank;
        struct v4l2_ctrl *hblank = sensor->hblank;
+       int min, max;
 
-       vblank->minimum =
-               max_t(int,
-                     sensor->limits[SMIAPP_LIMIT_MIN_FRAME_BLANKING_LINES],
-                     sensor->limits[SMIAPP_LIMIT_MIN_FRAME_LENGTH_LINES_BIN] -
-                     sensor->pixel_array->crop[SMIAPP_PA_PAD_SRC].height);
-       vblank->maximum =
-               sensor->limits[SMIAPP_LIMIT_MAX_FRAME_LENGTH_LINES_BIN] -
+       min = max_t(int,
+                   sensor->limits[SMIAPP_LIMIT_MIN_FRAME_BLANKING_LINES],
+                   sensor->limits[SMIAPP_LIMIT_MIN_FRAME_LENGTH_LINES_BIN] -
+                   sensor->pixel_array->crop[SMIAPP_PA_PAD_SRC].height);
+       max = sensor->limits[SMIAPP_LIMIT_MAX_FRAME_LENGTH_LINES_BIN] -
                sensor->pixel_array->crop[SMIAPP_PA_PAD_SRC].height;
 
-       vblank->val = clamp_t(int, vblank->val,
-                             vblank->minimum, vblank->maximum);
-       vblank->default_value = vblank->minimum;
-       vblank->val = vblank->val;
-       vblank->cur.val = vblank->val;
-
-       hblank->minimum =
-               max_t(int,
-                     sensor->limits[SMIAPP_LIMIT_MIN_LINE_LENGTH_PCK_BIN] -
-                     sensor->pixel_array->crop[SMIAPP_PA_PAD_SRC].width,
-                     sensor->limits[SMIAPP_LIMIT_MIN_LINE_BLANKING_PCK_BIN]);
-       hblank->maximum =
-               sensor->limits[SMIAPP_LIMIT_MAX_LINE_LENGTH_PCK_BIN] -
+       __v4l2_ctrl_modify_range(vblank, min, max, vblank->step, min);
+
+       min = max_t(int,
+                   sensor->limits[SMIAPP_LIMIT_MIN_LINE_LENGTH_PCK_BIN] -
+                   sensor->pixel_array->crop[SMIAPP_PA_PAD_SRC].width,
+                   sensor->limits[SMIAPP_LIMIT_MIN_LINE_BLANKING_PCK_BIN]);
+       max = sensor->limits[SMIAPP_LIMIT_MAX_LINE_LENGTH_PCK_BIN] -
                sensor->pixel_array->crop[SMIAPP_PA_PAD_SRC].width;
 
-       hblank->val = clamp_t(int, hblank->val,
-                             hblank->minimum, hblank->maximum);
-       hblank->default_value = hblank->minimum;
-       hblank->val = hblank->val;
-       hblank->cur.val = hblank->val;
+       __v4l2_ctrl_modify_range(hblank, min, max, hblank->step, min);
 
        __smiapp_update_exposure_limits(sensor);
 }
@@ -1272,7 +1312,7 @@ static void smiapp_power_off(struct smiapp_sensor *sensor)
                clk_disable_unprepare(sensor->ext_clk);
        usleep_range(5000, 5000);
        regulator_disable(sensor->vana);
-       sensor->streaming = 0;
+       sensor->streaming = false;
 }
 
 static int smiapp_set_power(struct v4l2_subdev *subdev, int on)
@@ -1462,13 +1502,13 @@ static int smiapp_set_stream(struct v4l2_subdev *subdev, int enable)
                return 0;
 
        if (enable) {
-               sensor->streaming = 1;
+               sensor->streaming = true;
                rval = smiapp_start_streaming(sensor);
                if (rval < 0)
-                       sensor->streaming = 0;
+                       sensor->streaming = false;
        } else {
                rval = smiapp_stop_streaming(sensor);
-               sensor->streaming = 0;
+               sensor->streaming = false;
        }
 
        return rval;
@@ -1664,17 +1704,34 @@ static int smiapp_set_format(struct v4l2_subdev *subdev,
        if (fmt->pad == ssd->source_pad) {
                u32 code = fmt->format.code;
                int rval = __smiapp_get_format(subdev, fh, fmt);
+               bool range_changed = false;
+               unsigned int i;
 
                if (!rval && subdev == &sensor->src->sd) {
                        const struct smiapp_csi_data_format *csi_format =
                                smiapp_validate_csi_data_format(sensor, code);
-                       if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE)
+
+                       if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
+                               if (csi_format->width !=
+                                   sensor->csi_format->width)
+                                       range_changed = true;
+
                                sensor->csi_format = csi_format;
+                       }
+
                        fmt->format.code = csi_format->code;
                }
 
                mutex_unlock(&sensor->mutex);
-               return rval;
+               if (rval || !range_changed)
+                       return rval;
+
+               for (i = 0; i < ARRAY_SIZE(sensor->test_data); i++)
+                       v4l2_ctrl_modify_range(
+                               sensor->test_data[i],
+                               0, (1 << sensor->csi_format->width) - 1, 1, 0);
+
+               return 0;
        }
 
        /* Sink pad. Width and height are changeable here. */
index 7cc5aae662fda5e0ef1ed6ba0b3534fafb4378c4..874b49ffd88f020e1e78ec2d39f7b8041559265e 100644 (file)
@@ -54,6 +54,8 @@
        (1000 + (SMIAPP_RESET_DELAY_CLOCKS * 1000       \
                 + (clk) / 1000 - 1) / ((clk) / 1000))
 
+#define SMIAPP_COLOUR_COMPONENTS       4
+
 #include "smiapp-limits.h"
 
 struct smiapp_quirk;
@@ -241,6 +243,8 @@ struct smiapp_sensor {
        /* src controls */
        struct v4l2_ctrl *link_freq;
        struct v4l2_ctrl *pixel_rate_csi;
+       /* test pattern colour components */
+       struct v4l2_ctrl *test_data[SMIAPP_COLOUR_COMPONENTS];
 };
 
 #define to_smiapp_subdev(_sd)                          \
index 46f431a13782800c04198547ebf906394086e20c..996d7b4007a52a9c3360d8238ada92c08b3a750c 100644 (file)
@@ -29,6 +29,7 @@
 #include <media/soc_camera.h>
 #include <media/v4l2-clk.h>
 #include <media/v4l2-common.h>
+#include <media/v4l2-image-sizes.h>
 
 /* you can check PLL/clock info */
 /* #define EXT_CLOCK 24000000 */
@@ -42,9 +43,6 @@
 #define MAX_WIDTH   2048
 #define MAX_HEIGHT  1536
 
-#define VGA_WIDTH   640
-#define VGA_HEIGHT  480
-
 /*
  * macro of read/write
  */
index 7f2b3c8926afbfade0fca5c58bea1e9356dc9d3b..970a04e1e56e694602f4a87261079646c517875f 100644 (file)
@@ -29,6 +29,7 @@
 #include <media/v4l2-clk.h>
 #include <media/v4l2-ctrls.h>
 #include <media/v4l2-subdev.h>
+#include <media/v4l2-image-sizes.h>
 
 /*
  * register offset
 #define SCAL0_ACTRL     0x08 /* Auto scaling factor control */
 #define SCAL1_2_ACTRL   0x04 /* Auto scaling factor control */
 
-#define VGA_WIDTH              640
-#define VGA_HEIGHT             480
-#define QVGA_WIDTH             320
-#define QVGA_HEIGHT            240
 #define OV772X_MAX_WIDTH       VGA_WIDTH
 #define OV772X_MAX_HEIGHT      VGA_HEIGHT
 
index ea76863dfdb44e22bb265d3ee6928a0611e60f63..ee9eb635d5403acbf88fb116b939e3f5cbc77152 100644 (file)
@@ -564,13 +564,13 @@ static int ov9740_set_res(struct i2c_client *client, u32 width, u32 height)
        u32 y_start;
        u32 x_end;
        u32 y_end;
-       bool scaling = 0;
+       bool scaling = false;
        u32 scale_input_x;
        u32 scale_input_y;
        int ret;
 
        if ((width != OV9740_MAX_WIDTH) || (height != OV9740_MAX_HEIGHT))
-               scaling = 1;
+               scaling = true;
 
        /*
         * Try to use as much of the sensor area as possible when supporting
index 72af644fa05127f89548b9782cee62367823d445..cf93021a650092d8dee0710c592ba6b00611769a 100644 (file)
@@ -293,7 +293,7 @@ static int tda7432_s_ctrl(struct v4l2_ctrl *ctrl)
                if (t->mute->val) {
                        lf |= TDA7432_MUTE;
                        lr |= TDA7432_MUTE;
-                       lf |= TDA7432_MUTE;
+                       rf |= TDA7432_MUTE;
                        rr |= TDA7432_MUTE;
                }
                /* Mute & update balance*/
index 11f2387e1dabe8235ec1857352068ca1a10848bc..51bac762638b7aca70ba204d86588a38eae997c4 100644 (file)
@@ -775,25 +775,20 @@ static int tvp7002_enum_mbus_fmt(struct v4l2_subdev *sd, unsigned index,
 static int tvp7002_s_stream(struct v4l2_subdev *sd, int enable)
 {
        struct tvp7002 *device = to_tvp7002(sd);
-       int error = 0;
+       int error;
 
        if (device->streaming == enable)
                return 0;
 
-       if (enable) {
-               /* Set output state on (low impedance means stream on) */
-               error = tvp7002_write(sd, TVP7002_MISC_CTL_2, 0x00);
-               device->streaming = enable;
-       } else {
-               /* Set output state off (high impedance means stream off) */
-               error = tvp7002_write(sd, TVP7002_MISC_CTL_2, 0x03);
-               if (error)
-                       v4l2_dbg(1, debug, sd, "Unable to stop streaming\n");
-
-               device->streaming = enable;
+       /* low impedance: on, high impedance: off */
+       error = tvp7002_write(sd, TVP7002_MISC_CTL_2, enable ? 0x00 : 0x03);
+       if (error) {
+               v4l2_dbg(1, debug, sd, "Fail to set streaming\n");
+               return error;
        }
 
-       return error;
+       device->streaming = enable;
+       return 0;
 }
 
 /*
index 23f4f65fccd7ac19b43bc33fb377bdf0cc9bd8af..373f2df524924aa8b754b428a57cc5915c4b7bb4 100644 (file)
 #include <media/v4l2-ctrls.h>
 #include <media/v4l2-device.h>
 #include <media/v4l2-mediabus.h>
+#include <media/v4l2-image-sizes.h>
 
 #include "vs6624_regs.h"
 
-#define VGA_WIDTH       640
-#define VGA_HEIGHT      480
-#define QVGA_WIDTH      320
-#define QVGA_HEIGHT     240
-#define QQVGA_WIDTH     160
-#define QQVGA_HEIGHT    120
-#define CIF_WIDTH       352
-#define CIF_HEIGHT      288
-#define QCIF_WIDTH      176
-#define QCIF_HEIGHT     144
-#define QQCIF_WIDTH     88
-#define QQCIF_HEIGHT    72
-
 #define MAX_FRAME_RATE  30
 
 struct vs6624 {
index 73a432934bd8d1ee8bad5c2e07689cca9ed1a1d3..7b39440192d61a7f91b0896c406beea751d8d515 100644 (file)
@@ -103,10 +103,8 @@ static long media_device_enum_entities(struct media_device *mdev,
                return -EINVAL;
 
        u_ent.id = ent->id;
-       if (ent->name) {
-               strncpy(u_ent.name, ent->name, sizeof(u_ent.name));
-               u_ent.name[sizeof(u_ent.name) - 1] = '\0';
-       }
+       if (ent->name)
+               strlcpy(u_ent.name, ent->name, sizeof(u_ent.name));
        u_ent.type = ent->type;
        u_ent.revision = ent->revision;
        u_ent.flags = ent->flags;
index 7acd19c881debe4de5e98e9658108489d4c98c10..ebf9626e5ae5a709f2cb76b3a1c173d7ddb106ba 100644 (file)
@@ -192,7 +192,6 @@ static int media_open(struct inode *inode, struct file *filp)
 static int media_release(struct inode *inode, struct file *filp)
 {
        struct media_devnode *mdev = media_devnode_data(filp);
-       int ret = 0;
 
        if (mdev->fops->release)
                mdev->fops->release(filp);
@@ -201,7 +200,7 @@ static int media_release(struct inode *inode, struct file *filp)
           return value is ignored. */
        put_device(&mdev->dev);
        filp->private_data = NULL;
-       return ret;
+       return 0;
 }
 
 static const struct file_operations media_devnode_fops = {
index 9bc105b3db1bcec5dbb775f591188d7ec34e1adf..e6b497528ceaca5dcc671ad7a92d080936a2a316 100644 (file)
@@ -629,11 +629,15 @@ static int pms_capture(struct pms *dev, char __user *buf, int rgb555, int count)
 {
        int y;
        int dw = 2 * dev->width;
-       char tmp[dw + 32]; /* using a temp buffer is faster than direct  */
+       char *tmp; /* using a temp buffer is faster than direct  */
        int cnt = 0;
        int len = 0;
        unsigned char r8 = 0x5;  /* value for reg8  */
 
+       tmp = kmalloc(dw + 32, GFP_KERNEL);
+       if (!tmp)
+               return 0;
+
        if (rgb555)
                r8 |= 0x20; /* else use untranslated rgb = 565 */
        mvv_write(dev, 0x08, r8); /* capture rgb555/565, init DRAM, PC enable */
@@ -664,6 +668,7 @@ static int pms_capture(struct pms *dev, char __user *buf, int rgb555, int count)
                        len += dt;
                }
        }
+       kfree(tmp);
        return len;
 }
 
index 5c16c9c2203ef4e1a9fdd931ec3ecff5c2dc498a..f8cec8e8cf8243902db375d52ae5745efafbbccb 100644 (file)
@@ -20,6 +20,7 @@ source "drivers/media/pci/ivtv/Kconfig"
 source "drivers/media/pci/zoran/Kconfig"
 source "drivers/media/pci/saa7146/Kconfig"
 source "drivers/media/pci/solo6x10/Kconfig"
+source "drivers/media/pci/tw68/Kconfig"
 endif
 
 if MEDIA_ANALOG_TV_SUPPORT || MEDIA_DIGITAL_TV_SUPPORT
@@ -41,6 +42,7 @@ source "drivers/media/pci/b2c2/Kconfig"
 source "drivers/media/pci/pluto2/Kconfig"
 source "drivers/media/pci/dm1105/Kconfig"
 source "drivers/media/pci/pt1/Kconfig"
+source "drivers/media/pci/pt3/Kconfig"
 source "drivers/media/pci/mantis/Kconfig"
 source "drivers/media/pci/ngene/Kconfig"
 source "drivers/media/pci/ddbridge/Kconfig"
index e5b53fb569efaf038d4f86a010ec83e90c06d5e6..a12926e4b51f3afc44cba9a9199886d5a52e1fae 100644 (file)
@@ -7,10 +7,10 @@ obj-y        +=       ttpci/          \
                pluto2/         \
                dm1105/         \
                pt1/            \
+               pt3/            \
                mantis/         \
                ngene/          \
                ddbridge/       \
-               b2c2/           \
                saa7146/
 
 obj-$(CONFIG_VIDEO_IVTV) += ivtv/
@@ -22,6 +22,7 @@ obj-$(CONFIG_VIDEO_CX88) += cx88/
 obj-$(CONFIG_VIDEO_BT848) += bt8xx/
 obj-$(CONFIG_VIDEO_SAA7134) += saa7134/
 obj-$(CONFIG_VIDEO_SAA7164) += saa7164/
+obj-$(CONFIG_VIDEO_TW68) += tw68/
 obj-$(CONFIG_VIDEO_MEYE) += meye/
 obj-$(CONFIG_STA2X11_VIP) += sta2x11/
 obj-$(CONFIG_VIDEO_SOLO6X10) += solo6x10/
index 970e542d3a51fabcc17f2be4e371b9ccdd55cc36..4a8176c09fc9429eea49c2e49e811618354c78b0 100644 (file)
@@ -1531,7 +1531,6 @@ bttv_switch_overlay(struct bttv *btv, struct bttv_fh *fh,
 {
        struct bttv_buffer *old;
        unsigned long flags;
-       int retval = 0;
 
        dprintk("switch_overlay: enter [new=%p]\n", new);
        if (new)
@@ -1551,7 +1550,7 @@ bttv_switch_overlay(struct bttv *btv, struct bttv_fh *fh,
        if (NULL == new)
                free_btres_lock(btv,fh,RESOURCE_OVERLAY);
        dprintk("switch_overlay: done\n");
-       return retval;
+       return 0;
 }
 
 /* ----------------------------------------------------------------------- */
@@ -3856,7 +3855,7 @@ static irqreturn_t bttv_irq(int irq, void *dev_id)
 
                                btwrite(btread(BT848_INT_MASK) & (-1 ^ BT848_INT_GPINT),
                                                BT848_INT_MASK);
-                       };
+                       }
 
                        bttv_print_irqbits(stat,astat);
 
index 0e788fca992cf1e27579dd689a12cfc2b0da2f38..c22c4ae0684491266406fd0dea3001b992ae101f 100644 (file)
@@ -674,11 +674,9 @@ static int dst_ca_release(struct inode *inode, struct file *file)
 
 static ssize_t dst_ca_read(struct file *file, char __user *buffer, size_t length, loff_t *offset)
 {
-       ssize_t bytes_read = 0;
-
        dprintk(verbose, DST_CA_DEBUG, 1, " Device read.");
 
-       return bytes_read;
+       return 0;
 }
 
 static ssize_t dst_ca_write(struct file *file, const char __user *buffer, size_t length, loff_t *offset)
index 180077c49123fe11159ec3cd8480995586cf7fbf..ffb6acdc575f65993f231d9f600f3ab0f7682883 100644 (file)
@@ -80,7 +80,7 @@ void cx18_alsa_announce_pcm_data(struct snd_cx18_card *cxsc, u8 *pcm_data,
        int period_elapsed = 0;
        int length;
 
-       dprintk("cx18 alsa announce ptr=%p data=%p num_bytes=%zd\n", cxsc,
+       dprintk("cx18 alsa announce ptr=%p data=%p num_bytes=%zu\n", cxsc,
                pcm_data, num_bytes);
 
        substream = cxsc->capture_pcm_substream;
index a1c1cec05f98e4693bdc3dacfa073a64adec1d32..c6c83445f8bfb93605990d6726b9d2755d0d4f24 100644 (file)
@@ -130,7 +130,7 @@ static int load_cpu_fw_direct(const char *fn, u8 __iomem *mem, struct cx18 *cx)
                }
        }
        if (!test_bit(CX18_F_I_LOADED_FW, &cx->i_flags))
-               CX18_INFO("loaded %s firmware (%zd bytes)\n", fn, fw->size);
+               CX18_INFO("loaded %s firmware (%zu bytes)\n", fn, fw->size);
        size = fw->size;
        release_firmware(fw);
        cx18_setup_page(cx, SCB_OFFSET);
@@ -164,7 +164,7 @@ static int load_apu_fw_direct(const char *fn, u8 __iomem *dst, struct cx18 *cx,
 
        apu_version = (vers[0] << 24) | (vers[4] << 16) | vers[32];
        while (offset + sizeof(seghdr) < fw->size) {
-               const u32 *shptr = src + offset / 4;
+               const __le32 *shptr = (__force __le32 *)src + offset / 4;
 
                seghdr.sync1 = le32_to_cpu(shptr[0]);
                seghdr.sync2 = le32_to_cpu(shptr[1]);
@@ -202,7 +202,7 @@ static int load_apu_fw_direct(const char *fn, u8 __iomem *dst, struct cx18 *cx,
                offset += seghdr.size;
        }
        if (!test_bit(CX18_F_I_LOADED_FW, &cx->i_flags))
-               CX18_INFO("loaded %s firmware V%08x (%zd bytes)\n",
+               CX18_INFO("loaded %s firmware V%08x (%zu bytes)\n",
                                fn, apu_version, fw->size);
        size = fw->size;
        release_firmware(fw);
index 8884537bd62f9bf4685ea1a48c89f970cbb6f8b7..2a247d264b87740f6af9bb23ee411a799beb1020 100644 (file)
@@ -364,7 +364,7 @@ int cx18_stream_alloc(struct cx18_stream *s)
                                        ((char __iomem *)cx->scb->cpu_mdl));
 
                CX18_ERR("Too many buffers, cannot fit in SCB area\n");
-               CX18_ERR("Max buffers = %zd\n",
+               CX18_ERR("Max buffers = %zu\n",
                        bufsz / sizeof(struct cx18_mdl_ent));
                return -ENOMEM;
        }
index e12c006e6e2dc3be8470e454f64c5a055258791c..f613314b360ba735a048cfec56cb3324075f3f69 100644 (file)
@@ -3,12 +3,11 @@ config VIDEO_CX23885
        depends on DVB_CORE && VIDEO_DEV && PCI && I2C && INPUT && SND
        select SND_PCM
        select I2C_ALGOBIT
-       select VIDEO_BTCX
        select VIDEO_TUNER
        select VIDEO_TVEEPROM
        depends on RC_CORE
-       select VIDEOBUF_DVB
-       select VIDEOBUF_DMA_SG
+       select VIDEOBUF2_DVB
+       select VIDEOBUF2_DMA_SG
        select VIDEO_CX25840
        select VIDEO_CX2341X
        select DVB_DIB7000P if MEDIA_SUBDRV_AUTOSELECT
@@ -32,12 +31,16 @@ config VIDEO_CX23885
        select DVB_A8293 if MEDIA_SUBDRV_AUTOSELECT
        select DVB_MB86A20S if MEDIA_SUBDRV_AUTOSELECT
        select DVB_SI2165 if MEDIA_SUBDRV_AUTOSELECT
+       select DVB_SI2168 if MEDIA_SUBDRV_AUTOSELECT
+       select DVB_M88DS3103 if MEDIA_SUBDRV_AUTOSELECT
        select MEDIA_TUNER_MT2063 if MEDIA_SUBDRV_AUTOSELECT
        select MEDIA_TUNER_MT2131 if MEDIA_SUBDRV_AUTOSELECT
        select MEDIA_TUNER_XC2028 if MEDIA_SUBDRV_AUTOSELECT
        select MEDIA_TUNER_TDA8290 if MEDIA_SUBDRV_AUTOSELECT
        select MEDIA_TUNER_TDA18271 if MEDIA_SUBDRV_AUTOSELECT
        select MEDIA_TUNER_XC5000 if MEDIA_SUBDRV_AUTOSELECT
+       select MEDIA_TUNER_SI2157 if MEDIA_SUBDRV_AUTOSELECT
+       select MEDIA_TUNER_M88TS2022 if MEDIA_SUBDRV_AUTOSELECT
        select DVB_TUNER_DIB0070 if MEDIA_SUBDRV_AUTOSELECT
        ---help---
          This is a video4linux driver for Conexant 23885 based
index 2a2cafb8cf5be31b48daf3c881aa50871e9a90fa..a2cbdcf15a8c48fde4cd79c43b33dd92c81a8def 100644 (file)
@@ -8,7 +8,6 @@ obj-$(CONFIG_VIDEO_CX23885) += cx23885.o
 obj-$(CONFIG_MEDIA_ALTERA_CI) += altera-ci.o
 
 ccflags-y += -Idrivers/media/i2c
-ccflags-y += -Idrivers/media/common
 ccflags-y += -Idrivers/media/tuners
 ccflags-y += -Idrivers/media/dvb-core
 ccflags-y += -Idrivers/media/dvb-frontends
index 2926f7fadccdcdeba7ca6b3a5cd5e99ba84e4bb7..2bbbf545b0422d0eca0548e4e30989c22bc5a0dc 100644 (file)
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  *
  * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
 /*
@@ -52,8 +48,8 @@
  * |  DATA7|  DATA6|  DATA5|  DATA4|  DATA3|  DATA2|  DATA1|  DATA0|
  * +-------+-------+-------+-------+-------+-------+-------+-------+
  */
-#include <media/videobuf-dma-sg.h>
-#include <media/videobuf-dvb.h>
+#include <dvb_demux.h>
+#include <dvb_frontend.h>
 #include "altera-ci.h"
 #include "dvb_ca_en50221.h"
 
index 4998c96caebee5cb8e3d38fa2962b7b8ec642839..5028f0cf83f43a87b7e93270c0d6fb8c277bb584 100644 (file)
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  *
  * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 #ifndef __ALTERA_CI_H
 #define __ALTERA_CI_H
index 16fa7ea4d4aa7d472ff9f59f6b0131ead21c2902..631e4f24aea6424ef265fa1dcb8b4d81a5966eb3 100644 (file)
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  *
  * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
 #include "cx23885.h"
index 518744a4c8a5e41c82b8091bbee2f2d71166e6b6..565e958f6f8d2de35bfc15701961d387e8a8c68e 100644 (file)
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  *
  * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
 #ifndef CIMAX2_H
index bf89fc88692eb1ac081b34fc24691737e08c3951..3948db386fb5624c7a67e73a08bc5454fcd05e88 100644 (file)
  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
 #include <linux/module.h>
@@ -865,6 +861,11 @@ static int cx23885_api_cmd(struct cx23885_dev *dev,
        return err;
 }
 
+static int cx23885_api_func(void *priv, u32 cmd, int in, int out, u32 data[CX2341X_MBOX_MAX_DATA])
+{
+       return cx23885_mbox_func(priv, cmd, in, out, data);
+}
+
 static int cx23885_find_mailbox(struct cx23885_dev *dev)
 {
        u32 signature[4] = {
@@ -941,7 +942,7 @@ static int cx23885_load_firmware(struct cx23885_dev *dev)
 
        if (firmware->size != CX23885_FIRM_IMAGE_SIZE) {
                printk(KERN_ERR "ERROR: Firmware size mismatch "
-                       "(have %zd, expected %d)\n",
+                       "(have %zu, expected %d)\n",
                        firmware->size, CX23885_FIRM_IMAGE_SIZE);
                release_firmware(firmware);
                return -1;
@@ -1033,12 +1034,12 @@ static void cx23885_codec_settings(struct cx23885_dev *dev)
        cx23885_api_cmd(dev, CX2341X_ENC_SET_FRAME_SIZE, 2, 0,
                                dev->ts1.height, dev->ts1.width);
 
-       dev->mpeg_params.width = dev->ts1.width;
-       dev->mpeg_params.height = dev->ts1.height;
-       dev->mpeg_params.is_50hz =
+       dev->cxhdl.width = dev->ts1.width;
+       dev->cxhdl.height = dev->ts1.height;
+       dev->cxhdl.is_50hz =
                (dev->encodernorm.id & V4L2_STD_625_50) != 0;
 
-       cx2341x_update(dev, cx23885_mbox_func, NULL, &dev->mpeg_params);
+       cx2341x_handler_setup(&dev->cxhdl);
 
        cx23885_api_cmd(dev, CX2341X_ENC_MISC, 2, 0, 3, 1);
        cx23885_api_cmd(dev, CX2341X_ENC_MISC, 2, 0, 4, 1);
@@ -1137,85 +1138,107 @@ static int cx23885_initialize_codec(struct cx23885_dev *dev, int startencoder)
 
 /* ------------------------------------------------------------------ */
 
-static int bb_buf_setup(struct videobuf_queue *q,
-       unsigned int *count, unsigned int *size)
+static int queue_setup(struct vb2_queue *q, const struct v4l2_format *fmt,
+                          unsigned int *num_buffers, unsigned int *num_planes,
+                          unsigned int sizes[], void *alloc_ctxs[])
 {
-       struct cx23885_fh *fh = q->priv_data;
-
-       fh->dev->ts1.ts_packet_size  = mpeglinesize;
-       fh->dev->ts1.ts_packet_count = mpeglines;
-
-       *size = fh->dev->ts1.ts_packet_size * fh->dev->ts1.ts_packet_count;
-       *count = mpegbufs;
+       struct cx23885_dev *dev = q->drv_priv;
 
+       dev->ts1.ts_packet_size  = mpeglinesize;
+       dev->ts1.ts_packet_count = mpeglines;
+       *num_planes = 1;
+       sizes[0] = mpeglinesize * mpeglines;
+       *num_buffers = mpegbufs;
        return 0;
 }
 
-static int bb_buf_prepare(struct videobuf_queue *q,
-       struct videobuf_buffer *vb, enum v4l2_field field)
+static int buffer_prepare(struct vb2_buffer *vb)
 {
-       struct cx23885_fh *fh = q->priv_data;
-       return cx23885_buf_prepare(q, &fh->dev->ts1,
-               (struct cx23885_buffer *)vb,
-               field);
+       struct cx23885_dev *dev = vb->vb2_queue->drv_priv;
+       struct cx23885_buffer *buf =
+               container_of(vb, struct cx23885_buffer, vb);
+
+       return cx23885_buf_prepare(buf, &dev->ts1);
 }
 
-static void bb_buf_queue(struct videobuf_queue *q,
-       struct videobuf_buffer *vb)
+static void buffer_finish(struct vb2_buffer *vb)
 {
-       struct cx23885_fh *fh = q->priv_data;
-       cx23885_buf_queue(&fh->dev->ts1, (struct cx23885_buffer *)vb);
+       struct cx23885_dev *dev = vb->vb2_queue->drv_priv;
+       struct cx23885_buffer *buf = container_of(vb,
+               struct cx23885_buffer, vb);
+       struct sg_table *sgt = vb2_dma_sg_plane_desc(vb, 0);
+
+       cx23885_free_buffer(dev, buf);
+
+       dma_unmap_sg(&dev->pci->dev, sgt->sgl, sgt->nents, DMA_FROM_DEVICE);
 }
 
-static void bb_buf_release(struct videobuf_queue *q,
-       struct videobuf_buffer *vb)
+static void buffer_queue(struct vb2_buffer *vb)
 {
-       cx23885_free_buffer(q, (struct cx23885_buffer *)vb);
-}
+       struct cx23885_dev *dev = vb->vb2_queue->drv_priv;
+       struct cx23885_buffer   *buf = container_of(vb,
+               struct cx23885_buffer, vb);
 
-static struct videobuf_queue_ops cx23885_qops = {
-       .buf_setup    = bb_buf_setup,
-       .buf_prepare  = bb_buf_prepare,
-       .buf_queue    = bb_buf_queue,
-       .buf_release  = bb_buf_release,
-};
+       cx23885_buf_queue(&dev->ts1, buf);
+}
 
-/* ------------------------------------------------------------------ */
+static int cx23885_start_streaming(struct vb2_queue *q, unsigned int count)
+{
+       struct cx23885_dev *dev = q->drv_priv;
+       struct cx23885_dmaqueue *dmaq = &dev->ts1.mpegq;
+       unsigned long flags;
+       int ret;
+
+       ret = cx23885_initialize_codec(dev, 1);
+       if (ret == 0) {
+               struct cx23885_buffer *buf = list_entry(dmaq->active.next,
+                       struct cx23885_buffer, queue);
+
+               cx23885_start_dma(&dev->ts1, dmaq, buf);
+               return 0;
+       }
+       spin_lock_irqsave(&dev->slock, flags);
+       while (!list_empty(&dmaq->active)) {
+               struct cx23885_buffer *buf = list_entry(dmaq->active.next,
+                       struct cx23885_buffer, queue);
 
-static const u32 *ctrl_classes[] = {
-       cx2341x_mpeg_ctrls,
-       NULL
-};
+               list_del(&buf->queue);
+               vb2_buffer_done(&buf->vb, VB2_BUF_STATE_QUEUED);
+       }
+       spin_unlock_irqrestore(&dev->slock, flags);
+       return ret;
+}
 
-static int cx23885_queryctrl(struct cx23885_dev *dev,
-       struct v4l2_queryctrl *qctrl)
+static void cx23885_stop_streaming(struct vb2_queue *q)
 {
-       qctrl->id = v4l2_ctrl_next(ctrl_classes, qctrl->id);
-       if (qctrl->id == 0)
-               return -EINVAL;
+       struct cx23885_dev *dev = q->drv_priv;
 
-       /* MPEG V4L2 controls */
-       if (cx2341x_ctrl_query(&dev->mpeg_params, qctrl))
-               qctrl->flags |= V4L2_CTRL_FLAG_DISABLED;
+       /* stop mpeg capture */
+       cx23885_api_cmd(dev, CX2341X_ENC_STOP_CAPTURE, 3, 0,
+                       CX23885_END_NOW, CX23885_MPEG_CAPTURE,
+                       CX23885_RAW_BITS_NONE);
 
-       return 0;
+       msleep(500);
+       cx23885_417_check_encoder(dev);
+       cx23885_cancel_buffers(&dev->ts1);
 }
 
-static int cx23885_querymenu(struct cx23885_dev *dev,
-       struct v4l2_querymenu *qmenu)
-{
-       struct v4l2_queryctrl qctrl;
+static struct vb2_ops cx23885_qops = {
+       .queue_setup    = queue_setup,
+       .buf_prepare  = buffer_prepare,
+       .buf_finish = buffer_finish,
+       .buf_queue    = buffer_queue,
+       .wait_prepare = vb2_ops_wait_prepare,
+       .wait_finish = vb2_ops_wait_finish,
+       .start_streaming = cx23885_start_streaming,
+       .stop_streaming = cx23885_stop_streaming,
+};
 
-       qctrl.id = qmenu->id;
-       cx23885_queryctrl(dev, &qctrl);
-       return v4l2_ctrl_query_menu(qmenu, &qctrl,
-               cx2341x_ctrl_get_menu(&dev->mpeg_params, qmenu->id));
-}
+/* ------------------------------------------------------------------ */
 
 static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *id)
 {
-       struct cx23885_fh  *fh  = file->private_data;
-       struct cx23885_dev *dev = fh->dev;
+       struct cx23885_dev *dev = video_drvdata(file);
 
        *id = dev->tvnorm;
        return 0;
@@ -1223,29 +1246,26 @@ static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *id)
 
 static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id id)
 {
-       struct cx23885_fh  *fh  = file->private_data;
-       struct cx23885_dev *dev = fh->dev;
+       struct cx23885_dev *dev = video_drvdata(file);
        unsigned int i;
+       int ret;
 
        for (i = 0; i < ARRAY_SIZE(cx23885_tvnorms); i++)
                if (id & cx23885_tvnorms[i].id)
                        break;
        if (i == ARRAY_SIZE(cx23885_tvnorms))
                return -EINVAL;
-       dev->encodernorm = cx23885_tvnorms[i];
 
-       /* Have the drier core notify the subdevices */
-       mutex_lock(&dev->lock);
-       cx23885_set_tvnorm(dev, id);
-       mutex_unlock(&dev->lock);
-
-       return 0;
+       ret = cx23885_set_tvnorm(dev, id);
+       if (!ret)
+               dev->encodernorm = cx23885_tvnorms[i];
+       return ret;
 }
 
 static int vidioc_enum_input(struct file *file, void *priv,
        struct v4l2_input *i)
 {
-       struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev;
+       struct cx23885_dev *dev = video_drvdata(file);
        dprintk(1, "%s()\n", __func__);
        return cx23885_enum_input(dev, i);
 }
@@ -1263,8 +1283,7 @@ static int vidioc_s_input(struct file *file, void *priv, unsigned int i)
 static int vidioc_g_tuner(struct file *file, void *priv,
                                struct v4l2_tuner *t)
 {
-       struct cx23885_fh  *fh  = file->private_data;
-       struct cx23885_dev *dev = fh->dev;
+       struct cx23885_dev *dev = video_drvdata(file);
 
        if (dev->tuner_type == TUNER_ABSENT)
                return -EINVAL;
@@ -1281,8 +1300,7 @@ static int vidioc_g_tuner(struct file *file, void *priv,
 static int vidioc_s_tuner(struct file *file, void *priv,
                                const struct v4l2_tuner *t)
 {
-       struct cx23885_fh  *fh  = file->private_data;
-       struct cx23885_dev *dev = fh->dev;
+       struct cx23885_dev *dev = video_drvdata(file);
 
        if (dev->tuner_type == TUNER_ABSENT)
                return -EINVAL;
@@ -1296,8 +1314,7 @@ static int vidioc_s_tuner(struct file *file, void *priv,
 static int vidioc_g_frequency(struct file *file, void *priv,
                                struct v4l2_frequency *f)
 {
-       struct cx23885_fh  *fh  = file->private_data;
-       struct cx23885_dev *dev = fh->dev;
+       struct cx23885_dev *dev = video_drvdata(file);
 
        if (dev->tuner_type == TUNER_ABSENT)
                return -EINVAL;
@@ -1315,27 +1332,10 @@ static int vidioc_s_frequency(struct file *file, void *priv,
        return cx23885_set_frequency(file, priv, f);
 }
 
-static int vidioc_g_ctrl(struct file *file, void *priv,
-       struct v4l2_control *ctl)
-{
-       struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev;
-
-       return cx23885_get_control(dev, ctl);
-}
-
-static int vidioc_s_ctrl(struct file *file, void *priv,
-       struct v4l2_control *ctl)
-{
-       struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev;
-
-       return cx23885_set_control(dev, ctl);
-}
-
 static int vidioc_querycap(struct file *file, void  *priv,
                                struct v4l2_capability *cap)
 {
-       struct cx23885_fh  *fh  = file->private_data;
-       struct cx23885_dev *dev = fh->dev;
+       struct cx23885_dev *dev = video_drvdata(file);
        struct cx23885_tsport  *tsport = &dev->ts1;
 
        strlcpy(cap->driver, dev->name, sizeof(cap->driver));
@@ -1368,8 +1368,7 @@ static int vidioc_enum_fmt_vid_cap(struct file *file, void  *priv,
 static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
                                struct v4l2_format *f)
 {
-       struct cx23885_fh  *fh  = file->private_data;
-       struct cx23885_dev *dev = fh->dev;
+       struct cx23885_dev *dev = video_drvdata(file);
 
        f->fmt.pix.pixelformat  = V4L2_PIX_FMT_MPEG;
        f->fmt.pix.bytesperline = 0;
@@ -1378,285 +1377,63 @@ static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
        f->fmt.pix.colorspace   = 0;
        f->fmt.pix.width        = dev->ts1.width;
        f->fmt.pix.height       = dev->ts1.height;
-       f->fmt.pix.field        = fh->mpegq.field;
-       dprintk(1, "VIDIOC_G_FMT: w: %d, h: %d, f: %d\n",
-               dev->ts1.width, dev->ts1.height, fh->mpegq.field);
+       f->fmt.pix.field        = V4L2_FIELD_INTERLACED;
+       dprintk(1, "VIDIOC_G_FMT: w: %d, h: %d\n",
+               dev->ts1.width, dev->ts1.height);
        return 0;
 }
 
 static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
                                struct v4l2_format *f)
 {
-       struct cx23885_fh  *fh  = file->private_data;
-       struct cx23885_dev *dev = fh->dev;
+       struct cx23885_dev *dev = video_drvdata(file);
 
        f->fmt.pix.pixelformat  = V4L2_PIX_FMT_MPEG;
        f->fmt.pix.bytesperline = 0;
        f->fmt.pix.sizeimage    =
                dev->ts1.ts_packet_size * dev->ts1.ts_packet_count;
        f->fmt.pix.colorspace   = 0;
-       dprintk(1, "VIDIOC_TRY_FMT: w: %d, h: %d, f: %d\n",
-               dev->ts1.width, dev->ts1.height, fh->mpegq.field);
+       f->fmt.pix.field        = V4L2_FIELD_INTERLACED;
+       dprintk(1, "VIDIOC_TRY_FMT: w: %d, h: %d\n",
+               dev->ts1.width, dev->ts1.height);
        return 0;
 }
 
 static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
                                struct v4l2_format *f)
 {
-       struct cx23885_fh  *fh  = file->private_data;
-       struct cx23885_dev *dev = fh->dev;
+       struct cx23885_dev *dev = video_drvdata(file);
 
        f->fmt.pix.pixelformat  = V4L2_PIX_FMT_MPEG;
        f->fmt.pix.bytesperline = 0;
        f->fmt.pix.sizeimage    =
                dev->ts1.ts_packet_size * dev->ts1.ts_packet_count;
        f->fmt.pix.colorspace   = 0;
+       f->fmt.pix.field        = V4L2_FIELD_INTERLACED;
        dprintk(1, "VIDIOC_S_FMT: w: %d, h: %d, f: %d\n",
                f->fmt.pix.width, f->fmt.pix.height, f->fmt.pix.field);
        return 0;
 }
 
-static int vidioc_reqbufs(struct file *file, void *priv,
-                               struct v4l2_requestbuffers *p)
-{
-       struct cx23885_fh  *fh  = file->private_data;
-
-       return videobuf_reqbufs(&fh->mpegq, p);
-}
-
-static int vidioc_querybuf(struct file *file, void *priv,
-                               struct v4l2_buffer *p)
-{
-       struct cx23885_fh  *fh  = file->private_data;
-
-       return videobuf_querybuf(&fh->mpegq, p);
-}
-
-static int vidioc_qbuf(struct file *file, void *priv,
-                               struct v4l2_buffer *p)
-{
-       struct cx23885_fh  *fh  = file->private_data;
-
-       return videobuf_qbuf(&fh->mpegq, p);
-}
-
-static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b)
-{
-       struct cx23885_fh  *fh  = priv;
-
-       return videobuf_dqbuf(&fh->mpegq, b, file->f_flags & O_NONBLOCK);
-}
-
-
-static int vidioc_streamon(struct file *file, void *priv,
-                               enum v4l2_buf_type i)
-{
-       struct cx23885_fh  *fh  = file->private_data;
-
-       return videobuf_streamon(&fh->mpegq);
-}
-
-static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
-{
-       struct cx23885_fh  *fh  = file->private_data;
-
-       return videobuf_streamoff(&fh->mpegq);
-}
-
-static int vidioc_g_ext_ctrls(struct file *file, void *priv,
-                               struct v4l2_ext_controls *f)
-{
-       struct cx23885_fh  *fh  = priv;
-       struct cx23885_dev *dev = fh->dev;
-
-       if (f->ctrl_class != V4L2_CTRL_CLASS_MPEG)
-               return -EINVAL;
-       return cx2341x_ext_ctrls(&dev->mpeg_params, 0, f, VIDIOC_G_EXT_CTRLS);
-}
-
-static int vidioc_s_ext_ctrls(struct file *file, void *priv,
-                               struct v4l2_ext_controls *f)
-{
-       struct cx23885_fh  *fh  = priv;
-       struct cx23885_dev *dev = fh->dev;
-       struct cx2341x_mpeg_params p;
-       int err;
-
-       if (f->ctrl_class != V4L2_CTRL_CLASS_MPEG)
-               return -EINVAL;
-
-       p = dev->mpeg_params;
-       err = cx2341x_ext_ctrls(&p, 0, f, VIDIOC_S_EXT_CTRLS);
-
-       if (err == 0) {
-               err = cx2341x_update(dev, cx23885_mbox_func,
-                       &dev->mpeg_params, &p);
-               dev->mpeg_params = p;
-       }
-       return err;
-}
-
-static int vidioc_try_ext_ctrls(struct file *file, void *priv,
-                               struct v4l2_ext_controls *f)
-{
-       struct cx23885_fh  *fh  = priv;
-       struct cx23885_dev *dev = fh->dev;
-       struct cx2341x_mpeg_params p;
-       int err;
-
-       if (f->ctrl_class != V4L2_CTRL_CLASS_MPEG)
-               return -EINVAL;
-
-       p = dev->mpeg_params;
-       err = cx2341x_ext_ctrls(&p, 0, f, VIDIOC_TRY_EXT_CTRLS);
-       return err;
-}
-
 static int vidioc_log_status(struct file *file, void *priv)
 {
-       struct cx23885_fh  *fh  = priv;
-       struct cx23885_dev *dev = fh->dev;
+       struct cx23885_dev *dev = video_drvdata(file);
        char name[32 + 2];
 
        snprintf(name, sizeof(name), "%s/2", dev->name);
-       printk(KERN_INFO
-               "%s/2: ============  START LOG STATUS  ============\n",
-              dev->name);
        call_all(dev, core, log_status);
-       cx2341x_log_status(&dev->mpeg_params, name);
-       printk(KERN_INFO
-               "%s/2: =============  END LOG STATUS  =============\n",
-              dev->name);
+       v4l2_ctrl_handler_log_status(&dev->cxhdl.hdl, name);
        return 0;
 }
 
-static int vidioc_querymenu(struct file *file, void *priv,
-                               struct v4l2_querymenu *a)
-{
-       struct cx23885_fh  *fh  = priv;
-       struct cx23885_dev *dev = fh->dev;
-
-       return cx23885_querymenu(dev, a);
-}
-
-static int vidioc_queryctrl(struct file *file, void *priv,
-                               struct v4l2_queryctrl *c)
-{
-       struct cx23885_fh  *fh  = priv;
-       struct cx23885_dev *dev = fh->dev;
-
-       return cx23885_queryctrl(dev, c);
-}
-
-static int mpeg_open(struct file *file)
-{
-       struct cx23885_dev *dev = video_drvdata(file);
-       struct cx23885_fh *fh;
-
-       dprintk(2, "%s()\n", __func__);
-
-       /* allocate + initialize per filehandle data */
-       fh = kzalloc(sizeof(*fh), GFP_KERNEL);
-       if (!fh)
-               return -ENOMEM;
-
-       file->private_data = fh;
-       fh->dev      = dev;
-
-       videobuf_queue_sg_init(&fh->mpegq, &cx23885_qops,
-                           &dev->pci->dev, &dev->ts1.slock,
-                           V4L2_BUF_TYPE_VIDEO_CAPTURE,
-                           V4L2_FIELD_INTERLACED,
-                           sizeof(struct cx23885_buffer),
-                           fh, NULL);
-       return 0;
-}
-
-static int mpeg_release(struct file *file)
-{
-       struct cx23885_fh  *fh  = file->private_data;
-       struct cx23885_dev *dev = fh->dev;
-
-       dprintk(2, "%s()\n", __func__);
-
-       /* FIXME: Review this crap */
-       /* Shut device down on last close */
-       if (atomic_cmpxchg(&fh->v4l_reading, 1, 0) == 1) {
-               if (atomic_dec_return(&dev->v4l_reader_count) == 0) {
-                       /* stop mpeg capture */
-                       cx23885_api_cmd(fh->dev, CX2341X_ENC_STOP_CAPTURE, 3, 0,
-                               CX23885_END_NOW, CX23885_MPEG_CAPTURE,
-                               CX23885_RAW_BITS_NONE);
-
-                       msleep(500);
-                       cx23885_417_check_encoder(dev);
-
-                       cx23885_cancel_buffers(&fh->dev->ts1);
-               }
-       }
-
-       if (fh->mpegq.streaming)
-               videobuf_streamoff(&fh->mpegq);
-       if (fh->mpegq.reading)
-               videobuf_read_stop(&fh->mpegq);
-
-       videobuf_mmap_free(&fh->mpegq);
-       file->private_data = NULL;
-       kfree(fh);
-
-       return 0;
-}
-
-static ssize_t mpeg_read(struct file *file, char __user *data,
-       size_t count, loff_t *ppos)
-{
-       struct cx23885_fh *fh = file->private_data;
-       struct cx23885_dev *dev = fh->dev;
-
-       dprintk(2, "%s()\n", __func__);
-
-       /* Deal w/ A/V decoder * and mpeg encoder sync issues. */
-       /* Start mpeg encoder on first read. */
-       if (atomic_cmpxchg(&fh->v4l_reading, 0, 1) == 0) {
-               if (atomic_inc_return(&dev->v4l_reader_count) == 1) {
-                       if (cx23885_initialize_codec(dev, 1) < 0)
-                               return -EINVAL;
-               }
-       }
-
-       return videobuf_read_stream(&fh->mpegq, data, count, ppos, 0,
-                                   file->f_flags & O_NONBLOCK);
-}
-
-static unsigned int mpeg_poll(struct file *file,
-       struct poll_table_struct *wait)
-{
-       struct cx23885_fh *fh = file->private_data;
-       struct cx23885_dev *dev = fh->dev;
-
-       dprintk(2, "%s\n", __func__);
-
-       return videobuf_poll_stream(file, &fh->mpegq, wait);
-}
-
-static int mpeg_mmap(struct file *file, struct vm_area_struct *vma)
-{
-       struct cx23885_fh *fh = file->private_data;
-       struct cx23885_dev *dev = fh->dev;
-
-       dprintk(2, "%s()\n", __func__);
-
-       return videobuf_mmap_mapper(&fh->mpegq, vma);
-}
-
 static struct v4l2_file_operations mpeg_fops = {
        .owner         = THIS_MODULE,
-       .open          = mpeg_open,
-       .release       = mpeg_release,
-       .read          = mpeg_read,
-       .poll          = mpeg_poll,
-       .mmap          = mpeg_mmap,
-       .ioctl         = video_ioctl2,
+       .open           = v4l2_fh_open,
+       .release        = vb2_fop_release,
+       .read           = vb2_fop_read,
+       .poll           = vb2_fop_poll,
+       .unlocked_ioctl = video_ioctl2,
+       .mmap           = vb2_fop_mmap,
 };
 
 static const struct v4l2_ioctl_ops mpeg_ioctl_ops = {
@@ -1669,25 +1446,19 @@ static const struct v4l2_ioctl_ops mpeg_ioctl_ops = {
        .vidioc_s_tuner          = vidioc_s_tuner,
        .vidioc_g_frequency      = vidioc_g_frequency,
        .vidioc_s_frequency      = vidioc_s_frequency,
-       .vidioc_s_ctrl           = vidioc_s_ctrl,
-       .vidioc_g_ctrl           = vidioc_g_ctrl,
        .vidioc_querycap         = vidioc_querycap,
        .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap,
        .vidioc_g_fmt_vid_cap    = vidioc_g_fmt_vid_cap,
        .vidioc_try_fmt_vid_cap  = vidioc_try_fmt_vid_cap,
        .vidioc_s_fmt_vid_cap    = vidioc_s_fmt_vid_cap,
-       .vidioc_reqbufs          = vidioc_reqbufs,
-       .vidioc_querybuf         = vidioc_querybuf,
-       .vidioc_qbuf             = vidioc_qbuf,
-       .vidioc_dqbuf            = vidioc_dqbuf,
-       .vidioc_streamon         = vidioc_streamon,
-       .vidioc_streamoff        = vidioc_streamoff,
-       .vidioc_g_ext_ctrls      = vidioc_g_ext_ctrls,
-       .vidioc_s_ext_ctrls      = vidioc_s_ext_ctrls,
-       .vidioc_try_ext_ctrls    = vidioc_try_ext_ctrls,
+       .vidioc_reqbufs       = vb2_ioctl_reqbufs,
+       .vidioc_prepare_buf   = vb2_ioctl_prepare_buf,
+       .vidioc_querybuf      = vb2_ioctl_querybuf,
+       .vidioc_qbuf          = vb2_ioctl_qbuf,
+       .vidioc_dqbuf         = vb2_ioctl_dqbuf,
+       .vidioc_streamon      = vb2_ioctl_streamon,
+       .vidioc_streamoff     = vb2_ioctl_streamoff,
        .vidioc_log_status       = vidioc_log_status,
-       .vidioc_querymenu        = vidioc_querymenu,
-       .vidioc_queryctrl        = vidioc_queryctrl,
 #ifdef CONFIG_VIDEO_ADV_DEBUG
        .vidioc_g_chip_info      = cx23885_g_chip_info,
        .vidioc_g_register       = cx23885_g_register,
@@ -1711,6 +1482,7 @@ void cx23885_417_unregister(struct cx23885_dev *dev)
                        video_unregister_device(dev->v4l_device);
                else
                        video_device_release(dev->v4l_device);
+               v4l2_ctrl_handler_free(&dev->cxhdl.hdl);
                dev->v4l_device = NULL;
        }
 }
@@ -1742,6 +1514,7 @@ int cx23885_417_register(struct cx23885_dev *dev)
        /* FIXME: Port1 hardcoded here */
        int err = -ENODEV;
        struct cx23885_tsport *tsport = &dev->ts1;
+       struct vb2_queue *q;
 
        dprintk(1, "%s()\n", __func__);
 
@@ -1757,14 +1530,36 @@ int cx23885_417_register(struct cx23885_dev *dev)
                tsport->height = 576;
 
        tsport->width = 720;
-       cx2341x_fill_defaults(&dev->mpeg_params);
-
-       dev->mpeg_params.port = CX2341X_PORT_SERIAL;
+       dev->cxhdl.port = CX2341X_PORT_SERIAL;
+       err = cx2341x_handler_init(&dev->cxhdl, 50);
+       if (err)
+               return err;
+       dev->cxhdl.priv = dev;
+       dev->cxhdl.func = cx23885_api_func;
+       cx2341x_handler_set_50hz(&dev->cxhdl, tsport->height == 576);
+       v4l2_ctrl_add_handler(&dev->ctrl_handler, &dev->cxhdl.hdl, NULL);
 
        /* Allocate and initialize V4L video device */
        dev->v4l_device = cx23885_video_dev_alloc(tsport,
                dev->pci, &cx23885_mpeg_template, "mpeg");
+       q = &dev->vb2_mpegq;
+       q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+       q->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF | VB2_READ;
+       q->gfp_flags = GFP_DMA32;
+       q->min_buffers_needed = 2;
+       q->drv_priv = dev;
+       q->buf_struct_size = sizeof(struct cx23885_buffer);
+       q->ops = &cx23885_qops;
+       q->mem_ops = &vb2_dma_sg_memops;
+       q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
+       q->lock = &dev->lock;
+
+       err = vb2_queue_init(q);
+       if (err < 0)
+               return err;
        video_set_drvdata(dev->v4l_device, dev);
+       dev->v4l_device->lock = &dev->lock;
+       dev->v4l_device->queue = q;
        err = video_register_device(dev->v4l_device,
                VFL_TYPE_GRABBER, -1);
        if (err < 0) {
index 554798dcedd09b3a1ad86961b2fd5fde691df254..ae7c2e89ad1cd6b9aebe8f0baea24d76e9065b79 100644 (file)
  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
 #include <linux/module.h>
@@ -84,6 +80,82 @@ MODULE_PARM_DESC(audio_debug, "enable debug messages [analog audio]");
 #define AUD_INT_MCHG_IRQ        (1 << 21)
 #define GP_COUNT_CONTROL_RESET 0x3
 
+static int cx23885_alsa_dma_init(struct cx23885_audio_dev *chip, int nr_pages)
+{
+       struct cx23885_audio_buffer *buf = chip->buf;
+       struct page *pg;
+       int i;
+
+       buf->vaddr = vmalloc_32(nr_pages << PAGE_SHIFT);
+       if (NULL == buf->vaddr) {
+               dprintk(1, "vmalloc_32(%d pages) failed\n", nr_pages);
+               return -ENOMEM;
+       }
+
+       dprintk(1, "vmalloc is at addr 0x%08lx, size=%d\n",
+                               (unsigned long)buf->vaddr,
+                               nr_pages << PAGE_SHIFT);
+
+       memset(buf->vaddr, 0, nr_pages << PAGE_SHIFT);
+       buf->nr_pages = nr_pages;
+
+       buf->sglist = vzalloc(buf->nr_pages * sizeof(*buf->sglist));
+       if (NULL == buf->sglist)
+               goto vzalloc_err;
+
+       sg_init_table(buf->sglist, buf->nr_pages);
+       for (i = 0; i < buf->nr_pages; i++) {
+               pg = vmalloc_to_page(buf->vaddr + i * PAGE_SIZE);
+               if (NULL == pg)
+                       goto vmalloc_to_page_err;
+               sg_set_page(&buf->sglist[i], pg, PAGE_SIZE, 0);
+       }
+       return 0;
+
+vmalloc_to_page_err:
+       vfree(buf->sglist);
+       buf->sglist = NULL;
+vzalloc_err:
+       vfree(buf->vaddr);
+       buf->vaddr = NULL;
+       return -ENOMEM;
+}
+
+static int cx23885_alsa_dma_map(struct cx23885_audio_dev *dev)
+{
+       struct cx23885_audio_buffer *buf = dev->buf;
+
+       buf->sglen = dma_map_sg(&dev->pci->dev, buf->sglist,
+                       buf->nr_pages, PCI_DMA_FROMDEVICE);
+
+       if (0 == buf->sglen) {
+               pr_warn("%s: cx23885_alsa_map_sg failed\n", __func__);
+               return -ENOMEM;
+       }
+       return 0;
+}
+
+static int cx23885_alsa_dma_unmap(struct cx23885_audio_dev *dev)
+{
+       struct cx23885_audio_buffer *buf = dev->buf;
+
+       if (!buf->sglen)
+               return 0;
+
+       dma_unmap_sg(&dev->pci->dev, buf->sglist, buf->sglen, PCI_DMA_FROMDEVICE);
+       buf->sglen = 0;
+       return 0;
+}
+
+static int cx23885_alsa_dma_free(struct cx23885_audio_buffer *buf)
+{
+       vfree(buf->sglist);
+       buf->sglist = NULL;
+       vfree(buf->vaddr);
+       buf->vaddr = NULL;
+       return 0;
+}
+
 /*
  * BOARD Specific: Sets audio DMA
  */
@@ -198,15 +270,18 @@ int cx23885_audio_irq(struct cx23885_dev *dev, u32 status, u32 mask)
 
 static int dsp_buffer_free(struct cx23885_audio_dev *chip)
 {
+       struct cx23885_riscmem *risc;
+
        BUG_ON(!chip->dma_size);
 
        dprintk(2, "Freeing buffer\n");
-       videobuf_dma_unmap(&chip->pci->dev, chip->dma_risc);
-       videobuf_dma_free(chip->dma_risc);
-       btcx_riscmem_free(chip->pci, &chip->buf->risc);
+       cx23885_alsa_dma_unmap(chip);
+       cx23885_alsa_dma_free(chip->buf);
+       risc = &chip->buf->risc;
+       pci_free_consistent(chip->pci, risc->size, risc->cpu, risc->dma);
        kfree(chip->buf);
 
-       chip->dma_risc = NULL;
+       chip->buf = NULL;
        chip->dma_size = 0;
 
        return 0;
@@ -289,6 +364,7 @@ static int snd_cx23885_close(struct snd_pcm_substream *substream)
        return 0;
 }
 
+
 /*
  * hw_params callback
  */
@@ -296,8 +372,6 @@ static int snd_cx23885_hw_params(struct snd_pcm_substream *substream,
                              struct snd_pcm_hw_params *hw_params)
 {
        struct cx23885_audio_dev *chip = snd_pcm_substream_chip(substream);
-       struct videobuf_dmabuf *dma;
-
        struct cx23885_audio_buffer *buf;
        int ret;
 
@@ -318,19 +392,18 @@ static int snd_cx23885_hw_params(struct snd_pcm_substream *substream,
                return -ENOMEM;
 
        buf->bpl = chip->period_size;
+       chip->buf = buf;
 
-       dma = &buf->dma;
-       videobuf_dma_init(dma);
-       ret = videobuf_dma_init_kernel(dma, PCI_DMA_FROMDEVICE,
+       ret = cx23885_alsa_dma_init(chip,
                        (PAGE_ALIGN(chip->dma_size) >> PAGE_SHIFT));
        if (ret < 0)
                goto error;
 
-       ret = videobuf_dma_map(&chip->pci->dev, dma);
+       ret = cx23885_alsa_dma_map(chip);
        if (ret < 0)
                goto error;
 
-       ret = cx23885_risc_databuffer(chip->pci, &buf->risc, dma->sglist,
+       ret = cx23885_risc_databuffer(chip->pci, &buf->risc, buf->sglist,
                                   chip->period_size, chip->num_periods, 1);
        if (ret < 0)
                goto error;
@@ -340,10 +413,7 @@ static int snd_cx23885_hw_params(struct snd_pcm_substream *substream,
        buf->risc.jmp[1] = cpu_to_le32(buf->risc.dma);
        buf->risc.jmp[2] = cpu_to_le32(0); /* bits 63-32 */
 
-       chip->buf = buf;
-       chip->dma_risc = dma;
-
-       substream->runtime->dma_area = chip->dma_risc->vaddr;
+       substream->runtime->dma_area = chip->buf->vaddr;
        substream->runtime->dma_bytes = chip->dma_size;
        substream->runtime->dma_addr = 0;
 
@@ -351,6 +421,7 @@ static int snd_cx23885_hw_params(struct snd_pcm_substream *substream,
 
 error:
        kfree(buf);
+       chip->buf = NULL;
        return ret;
 }
 
index c443b7ac5adfeb29806fd0cc345ac9b8d64c0c16..877dad89107ec5348cb0e21323122af8202f8365 100644 (file)
  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- *  02110-1301, USA.
  */
 
 #include "cx23885.h"
index d2915c3e53a29d87ed9ea220c482d4434e9e33e7..97f232f8efb918fdb238c36ddff56c3a85ff0634 100644 (file)
  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- *  02110-1301, USA.
  */
 
 #ifndef _CX23885_AV_H_
index c2b6080071908722706cd335917e6c99b4064dee..88c257d1161b1629294150e9bb9bc49bf887f52e 100644 (file)
  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  *
  *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
 #include <linux/init.h>
@@ -679,6 +675,11 @@ struct cx23885_board cx23885_boards[] = {
                        .amux   = CX25840_AUDIO7,
                } },
        },
+       [CX23885_BOARD_DVBSKY_T9580] = {
+               .name           = "DVBSky T9580",
+               .portb          = CX23885_MPEG_DVB,
+               .portc          = CX23885_MPEG_DVB,
+       },
 };
 const unsigned int cx23885_bcount = ARRAY_SIZE(cx23885_boards);
 
@@ -934,6 +935,10 @@ struct cx23885_subid cx23885_subids[] = {
                .subvendor = 0x18ac,
                .subdevice = 0xdb98,
                .card      = CX23885_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL_EXP2,
+       }, {
+               .subvendor = 0x4254,
+               .subdevice = 0x9580,
+               .card      = CX23885_BOARD_DVBSKY_T9580,
        },
 };
 const unsigned int cx23885_idcount = ARRAY_SIZE(cx23885_subids);
@@ -1528,6 +1533,14 @@ void cx23885_gpio_setup(struct cx23885_dev *dev)
                cx_set(GP0_IO, 0x00040004);
                mdelay(60);
                break;
+       case CX23885_BOARD_DVBSKY_T9580:
+               /* enable GPIO3-18 pins */
+               cx_write(MC417_CTL, 0x00000037);
+               cx23885_gpio_enable(dev, GPIO_2 | GPIO_11, 1);
+               cx23885_gpio_clear(dev, GPIO_2 | GPIO_11);
+               mdelay(100);
+               cx23885_gpio_set(dev, GPIO_2 | GPIO_11);
+               break;
        }
 }
 
@@ -1851,6 +1864,14 @@ void cx23885_card_setup(struct cx23885_dev *dev)
                ts2->ts_clk_en_val = 0x1; /* Enable TS_CLK */
                ts2->src_sel_val   = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO;
                break;
+       case CX23885_BOARD_DVBSKY_T9580:
+               ts1->gen_ctrl_val  = 0x5; /* Parallel */
+               ts1->ts_clk_en_val = 0x1; /* Enable TS_CLK */
+               ts1->src_sel_val   = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO;
+               ts2->gen_ctrl_val  = 0x8; /* Serial bus */
+               ts2->ts_clk_en_val = 0x1; /* Enable TS_CLK */
+               ts2->src_sel_val   = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO;
+               break;
        case CX23885_BOARD_HAUPPAUGE_HVR1250:
        case CX23885_BOARD_HAUPPAUGE_HVR1500:
        case CX23885_BOARD_HAUPPAUGE_HVR1500Q:
@@ -1913,6 +1934,7 @@ void cx23885_card_setup(struct cx23885_dev *dev)
        case CX23885_BOARD_AVERMEDIA_HC81R:
        case CX23885_BOARD_TBS_6980:
        case CX23885_BOARD_TBS_6981:
+       case CX23885_BOARD_DVBSKY_T9580:
                dev->sd_cx25840 = v4l2_i2c_new_subdev(&dev->v4l2_dev,
                                &dev->i2c_bus[2].i2c_adap,
                                "cx25840", 0x88 >> 1, NULL);
@@ -1970,5 +1992,3 @@ void cx23885_card_setup(struct cx23885_dev *dev)
        }
        }
 }
-
-/* ------------------------------------------------------------------ */
index edcd79db1e4ebc5d8ba6319b2ccb3c900a3024b4..331eddac7222ae7f62fb757148f90c8881b5ef4c 100644 (file)
  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  *
  *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
 #include <linux/init.h>
@@ -420,39 +416,23 @@ static int cx23885_risc_decode(u32 risc)
        return incr[risc >> 28] ? incr[risc >> 28] : 1;
 }
 
-void cx23885_wakeup(struct cx23885_tsport *port,
+static void cx23885_wakeup(struct cx23885_tsport *port,
                           struct cx23885_dmaqueue *q, u32 count)
 {
        struct cx23885_dev *dev = port->dev;
        struct cx23885_buffer *buf;
-       int bc;
-
-       for (bc = 0;; bc++) {
-               if (list_empty(&q->active))
-                       break;
-               buf = list_entry(q->active.next,
-                                struct cx23885_buffer, vb.queue);
-
-               /* count comes from the hw and is is 16bit wide --
-                * this trick handles wrap-arounds correctly for
-                * up to 32767 buffers in flight... */
-               if ((s16) (count - buf->count) < 0)
-                       break;
 
-               v4l2_get_timestamp(&buf->vb.ts);
-               dprintk(2, "[%p/%d] wakeup reg=%d buf=%d\n", buf, buf->vb.i,
-                       count, buf->count);
-               buf->vb.state = VIDEOBUF_DONE;
-               list_del(&buf->vb.queue);
-               wake_up(&buf->vb.done);
-       }
        if (list_empty(&q->active))
-               del_timer(&q->timeout);
-       else
-               mod_timer(&q->timeout, jiffies + BUFFER_TIMEOUT);
-       if (bc != 1)
-               printk(KERN_WARNING "%s: %d buffers handled (should be 1)\n",
-                      __func__, bc);
+               return;
+       buf = list_entry(q->active.next,
+                        struct cx23885_buffer, queue);
+
+       v4l2_get_timestamp(&buf->vb.v4l2_buf.timestamp);
+       buf->vb.v4l2_buf.sequence = q->count++;
+       dprintk(1, "[%p/%d] wakeup reg=%d buf=%d\n", buf, buf->vb.v4l2_buf.index,
+               count, q->count);
+       list_del(&buf->queue);
+       vb2_buffer_done(&buf->vb, VB2_BUF_STATE_DONE);
 }
 
 int cx23885_sram_channel_setup(struct cx23885_dev *dev,
@@ -482,8 +462,8 @@ int cx23885_sram_channel_setup(struct cx23885_dev *dev,
                lines = 6;
        BUG_ON(lines < 2);
 
-       cx_write(8 + 0, RISC_JUMP | RISC_IRQ1 | RISC_CNT_INC);
-       cx_write(8 + 4, 8);
+       cx_write(8 + 0, RISC_JUMP | RISC_CNT_RESET);
+       cx_write(8 + 4, 12);
        cx_write(8 + 8, 0);
 
        /* write CDT */
@@ -590,7 +570,7 @@ void cx23885_sram_channel_dump(struct cx23885_dev *dev,
 }
 
 static void cx23885_risc_disasm(struct cx23885_tsport *port,
-                               struct btcx_riscmem *risc)
+                               struct cx23885_riscmem *risc)
 {
        struct cx23885_dev *dev = port->dev;
        unsigned int i, j, n;
@@ -699,10 +679,6 @@ static int get_resources(struct cx23885_dev *dev)
        return -EBUSY;
 }
 
-static void cx23885_timeout(unsigned long data);
-int cx23885_risc_stopper(struct pci_dev *pci, struct btcx_riscmem *risc,
-                               u32 reg, u32 mask, u32 value);
-
 static int cx23885_init_tsport(struct cx23885_dev *dev,
        struct cx23885_tsport *port, int portno)
 {
@@ -719,11 +695,6 @@ static int cx23885_init_tsport(struct cx23885_dev *dev,
        port->nr = portno;
 
        INIT_LIST_HEAD(&port->mpegq.active);
-       INIT_LIST_HEAD(&port->mpegq.queued);
-       port->mpegq.timeout.function = cx23885_timeout;
-       port->mpegq.timeout.data = (unsigned long)port;
-       init_timer(&port->mpegq.timeout);
-
        mutex_init(&port->frontends.lock);
        INIT_LIST_HEAD(&port->frontends.felist);
        port->frontends.active_fe_id = 0;
@@ -776,9 +747,6 @@ static int cx23885_init_tsport(struct cx23885_dev *dev,
                BUG();
        }
 
-       cx23885_risc_stopper(dev->pci, &port->mpegq.stopper,
-                    port->reg_dma_ctl, port->dma_ctl_val, 0x00);
-
        return 0;
 }
 
@@ -1089,11 +1057,18 @@ static void cx23885_dev_unregister(struct cx23885_dev *dev)
 static __le32 *cx23885_risc_field(__le32 *rp, struct scatterlist *sglist,
                               unsigned int offset, u32 sync_line,
                               unsigned int bpl, unsigned int padding,
-                              unsigned int lines,  unsigned int lpi)
+                              unsigned int lines,  unsigned int lpi, bool jump)
 {
        struct scatterlist *sg;
        unsigned int line, todo, sol;
 
+
+       if (jump) {
+               *(rp++) = cpu_to_le32(RISC_JUMP);
+               *(rp++) = cpu_to_le32(0);
+               *(rp++) = cpu_to_le32(0); /* bits 63-32 */
+       }
+
        /* sync instruction */
        if (sync_line != NO_SYNC_LINE)
                *(rp++) = cpu_to_le32(RISC_RESYNC | sync_line);
@@ -1146,14 +1121,13 @@ static __le32 *cx23885_risc_field(__le32 *rp, struct scatterlist *sglist,
        return rp;
 }
 
-int cx23885_risc_buffer(struct pci_dev *pci, struct btcx_riscmem *risc,
+int cx23885_risc_buffer(struct pci_dev *pci, struct cx23885_riscmem *risc,
                        struct scatterlist *sglist, unsigned int top_offset,
                        unsigned int bottom_offset, unsigned int bpl,
                        unsigned int padding, unsigned int lines)
 {
        u32 instructions, fields;
        __le32 *rp;
-       int rc;
 
        fields = 0;
        if (UNSET != top_offset)
@@ -1168,19 +1142,20 @@ int cx23885_risc_buffer(struct pci_dev *pci, struct btcx_riscmem *risc,
        /* write and jump need and extra dword */
        instructions  = fields * (1 + ((bpl + padding) * lines)
                / PAGE_SIZE + lines);
-       instructions += 2;
-       rc = btcx_riscmem_alloc(pci, risc, instructions*12);
-       if (rc < 0)
-               return rc;
+       instructions += 5;
+       risc->size = instructions * 12;
+       risc->cpu = pci_alloc_consistent(pci, risc->size, &risc->dma);
+       if (risc->cpu == NULL)
+               return -ENOMEM;
 
        /* write risc instructions */
        rp = risc->cpu;
        if (UNSET != top_offset)
                rp = cx23885_risc_field(rp, sglist, top_offset, 0,
-                                       bpl, padding, lines, 0);
+                                       bpl, padding, lines, 0, true);
        if (UNSET != bottom_offset)
                rp = cx23885_risc_field(rp, sglist, bottom_offset, 0x200,
-                                       bpl, padding, lines, 0);
+                                       bpl, padding, lines, 0, UNSET == top_offset);
 
        /* save pointer to jmp instruction address */
        risc->jmp = rp;
@@ -1189,14 +1164,13 @@ int cx23885_risc_buffer(struct pci_dev *pci, struct btcx_riscmem *risc,
 }
 
 int cx23885_risc_databuffer(struct pci_dev *pci,
-                                  struct btcx_riscmem *risc,
+                                  struct cx23885_riscmem *risc,
                                   struct scatterlist *sglist,
                                   unsigned int bpl,
                                   unsigned int lines, unsigned int lpi)
 {
        u32 instructions;
        __le32 *rp;
-       int rc;
 
        /* estimate risc mem: worst case is one write per page border +
           one write per scan line + syncs + jump (all 2 dwords).  Here
@@ -1204,16 +1178,17 @@ int cx23885_risc_databuffer(struct pci_dev *pci,
           than PAGE_SIZE */
        /* Jump and write need an extra dword */
        instructions  = 1 + (bpl * lines) / PAGE_SIZE + lines;
-       instructions += 1;
+       instructions += 4;
 
-       rc = btcx_riscmem_alloc(pci, risc, instructions*12);
-       if (rc < 0)
-               return rc;
+       risc->size = instructions * 12;
+       risc->cpu = pci_alloc_consistent(pci, risc->size, &risc->dma);
+       if (risc->cpu == NULL)
+               return -ENOMEM;
 
        /* write risc instructions */
        rp = risc->cpu;
        rp = cx23885_risc_field(rp, sglist, 0, NO_SYNC_LINE,
-                               bpl, 0, lines, lpi);
+                               bpl, 0, lines, lpi, lpi == 0);
 
        /* save pointer to jmp instruction address */
        risc->jmp = rp;
@@ -1221,14 +1196,13 @@ int cx23885_risc_databuffer(struct pci_dev *pci,
        return 0;
 }
 
-int cx23885_risc_vbibuffer(struct pci_dev *pci, struct btcx_riscmem *risc,
+int cx23885_risc_vbibuffer(struct pci_dev *pci, struct cx23885_riscmem *risc,
                        struct scatterlist *sglist, unsigned int top_offset,
                        unsigned int bottom_offset, unsigned int bpl,
                        unsigned int padding, unsigned int lines)
 {
        u32 instructions, fields;
        __le32 *rp;
-       int rc;
 
        fields = 0;
        if (UNSET != top_offset)
@@ -1243,22 +1217,23 @@ int cx23885_risc_vbibuffer(struct pci_dev *pci, struct btcx_riscmem *risc,
        /* write and jump need and extra dword */
        instructions  = fields * (1 + ((bpl + padding) * lines)
                / PAGE_SIZE + lines);
-       instructions += 2;
-       rc = btcx_riscmem_alloc(pci, risc, instructions*12);
-       if (rc < 0)
-               return rc;
+       instructions += 5;
+       risc->size = instructions * 12;
+       risc->cpu = pci_alloc_consistent(pci, risc->size, &risc->dma);
+       if (risc->cpu == NULL)
+               return -ENOMEM;
        /* write risc instructions */
        rp = risc->cpu;
 
        /* Sync to line 6, so US CC line 21 will appear in line '12'
         * in the userland vbi payload */
        if (UNSET != top_offset)
-               rp = cx23885_risc_field(rp, sglist, top_offset, 6,
-                                       bpl, padding, lines, 0);
+               rp = cx23885_risc_field(rp, sglist, top_offset, 0,
+                                       bpl, padding, lines, 0, true);
 
        if (UNSET != bottom_offset)
-               rp = cx23885_risc_field(rp, sglist, bottom_offset, 0x207,
-                                       bpl, padding, lines, 0);
+               rp = cx23885_risc_field(rp, sglist, bottom_offset, 0x200,
+                                       bpl, padding, lines, 0, UNSET == top_offset);
 
 
 
@@ -1269,38 +1244,12 @@ int cx23885_risc_vbibuffer(struct pci_dev *pci, struct btcx_riscmem *risc,
 }
 
 
-int cx23885_risc_stopper(struct pci_dev *pci, struct btcx_riscmem *risc,
-                               u32 reg, u32 mask, u32 value)
+void cx23885_free_buffer(struct cx23885_dev *dev, struct cx23885_buffer *buf)
 {
-       __le32 *rp;
-       int rc;
-
-       rc = btcx_riscmem_alloc(pci, risc, 4*16);
-       if (rc < 0)
-               return rc;
-
-       /* write risc instructions */
-       rp = risc->cpu;
-       *(rp++) = cpu_to_le32(RISC_WRITECR  | RISC_IRQ2);
-       *(rp++) = cpu_to_le32(reg);
-       *(rp++) = cpu_to_le32(value);
-       *(rp++) = cpu_to_le32(mask);
-       *(rp++) = cpu_to_le32(RISC_JUMP);
-       *(rp++) = cpu_to_le32(risc->dma);
-       *(rp++) = cpu_to_le32(0); /* bits 63-32 */
-       return 0;
-}
-
-void cx23885_free_buffer(struct videobuf_queue *q, struct cx23885_buffer *buf)
-{
-       struct videobuf_dmabuf *dma = videobuf_to_dma(&buf->vb);
+       struct cx23885_riscmem *risc = &buf->risc;
 
        BUG_ON(in_interrupt());
-       videobuf_waiton(q, &buf->vb, 0, 0);
-       videobuf_dma_unmap(q->dev, dma);
-       videobuf_dma_free(dma);
-       btcx_riscmem_free(to_pci_dev(q->dev), &buf->risc);
-       buf->vb.state = VIDEOBUF_NEEDS_INIT;
+       pci_free_consistent(dev->pci, risc->size, risc->cpu, risc->dma);
 }
 
 static void cx23885_tsport_reg_dump(struct cx23885_tsport *port)
@@ -1355,7 +1304,7 @@ static void cx23885_tsport_reg_dump(struct cx23885_tsport *port)
                port->reg_ts_int_msk, cx_read(port->reg_ts_int_msk));
 }
 
-static int cx23885_start_dma(struct cx23885_tsport *port,
+int cx23885_start_dma(struct cx23885_tsport *port,
                             struct cx23885_dmaqueue *q,
                             struct cx23885_buffer   *buf)
 {
@@ -1363,7 +1312,7 @@ static int cx23885_start_dma(struct cx23885_tsport *port,
        u32 reg;
 
        dprintk(1, "%s() w: %d, h: %d, f: %d\n", __func__,
-               buf->vb.width, buf->vb.height, buf->vb.field);
+               dev->width, dev->height, dev->field);
 
        /* Stop the fifo and risc engine for this port */
        cx_clear(port->reg_dma_ctl, port->dma_ctl_val);
@@ -1379,7 +1328,7 @@ static int cx23885_start_dma(struct cx23885_tsport *port,
        }
 
        /* write TS length to chip */
-       cx_write(port->reg_lngth, buf->vb.width);
+       cx_write(port->reg_lngth, port->ts_packet_size);
 
        if ((!(cx23885_boards[dev->board].portb & CX23885_MPEG_DVB)) &&
                (!(cx23885_boards[dev->board].portc & CX23885_MPEG_DVB))) {
@@ -1408,7 +1357,7 @@ static int cx23885_start_dma(struct cx23885_tsport *port,
        /* NOTE: this is 2 (reserved) for portb, does it matter? */
        /* reset counter to zero */
        cx_write(port->reg_gpcnt_ctl, 3);
-       q->count = 1;
+       q->count = 0;
 
        /* Set VIDB pins to input */
        if (cx23885_boards[dev->board].portb == CX23885_MPEG_DVB) {
@@ -1497,134 +1446,83 @@ static int cx23885_stop_dma(struct cx23885_tsport *port)
        return 0;
 }
 
-int cx23885_restart_queue(struct cx23885_tsport *port,
-                               struct cx23885_dmaqueue *q)
-{
-       struct cx23885_dev *dev = port->dev;
-       struct cx23885_buffer *buf;
-
-       dprintk(5, "%s()\n", __func__);
-       if (list_empty(&q->active)) {
-               struct cx23885_buffer *prev;
-               prev = NULL;
-
-               dprintk(5, "%s() queue is empty\n", __func__);
-
-               for (;;) {
-                       if (list_empty(&q->queued))
-                               return 0;
-                       buf = list_entry(q->queued.next, struct cx23885_buffer,
-                                        vb.queue);
-                       if (NULL == prev) {
-                               list_move_tail(&buf->vb.queue, &q->active);
-                               cx23885_start_dma(port, q, buf);
-                               buf->vb.state = VIDEOBUF_ACTIVE;
-                               buf->count    = q->count++;
-                               mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT);
-                               dprintk(5, "[%p/%d] restart_queue - f/active\n",
-                                       buf, buf->vb.i);
-
-                       } else if (prev->vb.width  == buf->vb.width  &&
-                                  prev->vb.height == buf->vb.height &&
-                                  prev->fmt       == buf->fmt) {
-                               list_move_tail(&buf->vb.queue, &q->active);
-                               buf->vb.state = VIDEOBUF_ACTIVE;
-                               buf->count    = q->count++;
-                               prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma);
-                               /* 64 bit bits 63-32 */
-                               prev->risc.jmp[2] = cpu_to_le32(0);
-                               dprintk(5, "[%p/%d] restart_queue - m/active\n",
-                                       buf, buf->vb.i);
-                       } else {
-                               return 0;
-                       }
-                       prev = buf;
-               }
-               return 0;
-       }
-
-       buf = list_entry(q->active.next, struct cx23885_buffer, vb.queue);
-       dprintk(2, "restart_queue [%p/%d]: restart dma\n",
-               buf, buf->vb.i);
-       cx23885_start_dma(port, q, buf);
-       list_for_each_entry(buf, &q->active, vb.queue)
-               buf->count = q->count++;
-       mod_timer(&q->timeout, jiffies + BUFFER_TIMEOUT);
-       return 0;
-}
-
 /* ------------------------------------------------------------------ */
 
-int cx23885_buf_prepare(struct videobuf_queue *q, struct cx23885_tsport *port,
-                       struct cx23885_buffer *buf, enum v4l2_field field)
+int cx23885_buf_prepare(struct cx23885_buffer *buf, struct cx23885_tsport *port)
 {
        struct cx23885_dev *dev = port->dev;
        int size = port->ts_packet_size * port->ts_packet_count;
+       struct sg_table *sgt = vb2_dma_sg_plane_desc(&buf->vb, 0);
        int rc;
 
        dprintk(1, "%s: %p\n", __func__, buf);
-       if (0 != buf->vb.baddr  &&  buf->vb.bsize < size)
+       if (vb2_plane_size(&buf->vb, 0) < size)
                return -EINVAL;
+       vb2_set_plane_payload(&buf->vb, 0, size);
 
-       if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
-               buf->vb.width  = port->ts_packet_size;
-               buf->vb.height = port->ts_packet_count;
-               buf->vb.size   = size;
-               buf->vb.field  = field /*V4L2_FIELD_TOP*/;
-
-               rc = videobuf_iolock(q, &buf->vb, NULL);
-               if (0 != rc)
-                       goto fail;
-               cx23885_risc_databuffer(dev->pci, &buf->risc,
-                                       videobuf_to_dma(&buf->vb)->sglist,
-                                       buf->vb.width, buf->vb.height, 0);
-       }
-       buf->vb.state = VIDEOBUF_PREPARED;
-       return 0;
+       rc = dma_map_sg(&dev->pci->dev, sgt->sgl, sgt->nents, DMA_FROM_DEVICE);
+       if (!rc)
+               return -EIO;
 
- fail:
-       cx23885_free_buffer(q, buf);
-       return rc;
+       cx23885_risc_databuffer(dev->pci, &buf->risc,
+                               sgt->sgl,
+                               port->ts_packet_size, port->ts_packet_count, 0);
+       return 0;
 }
 
+/*
+ * The risc program for each buffer works as follows: it starts with a simple
+ * 'JUMP to addr + 12', which is effectively a NOP. Then the code to DMA the
+ * buffer follows and at the end we have a JUMP back to the start + 12 (skipping
+ * the initial JUMP).
+ *
+ * This is the risc program of the first buffer to be queued if the active list
+ * is empty and it just keeps DMAing this buffer without generating any
+ * interrupts.
+ *
+ * If a new buffer is added then the initial JUMP in the code for that buffer
+ * will generate an interrupt which signals that the previous buffer has been
+ * DMAed successfully and that it can be returned to userspace.
+ *
+ * It also sets the final jump of the previous buffer to the start of the new
+ * buffer, thus chaining the new buffer into the DMA chain. This is a single
+ * atomic u32 write, so there is no race condition.
+ *
+ * The end-result of all this that you only get an interrupt when a buffer
+ * is ready, so the control flow is very easy.
+ */
 void cx23885_buf_queue(struct cx23885_tsport *port, struct cx23885_buffer *buf)
 {
        struct cx23885_buffer    *prev;
        struct cx23885_dev *dev = port->dev;
        struct cx23885_dmaqueue  *cx88q = &port->mpegq;
+       unsigned long flags;
 
-       /* add jump to stopper */
-       buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP | RISC_IRQ1 | RISC_CNT_INC);
-       buf->risc.jmp[1] = cpu_to_le32(cx88q->stopper.dma);
+       buf->risc.cpu[1] = cpu_to_le32(buf->risc.dma + 12);
+       buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP | RISC_CNT_INC);
+       buf->risc.jmp[1] = cpu_to_le32(buf->risc.dma + 12);
        buf->risc.jmp[2] = cpu_to_le32(0); /* bits 63-32 */
 
+       spin_lock_irqsave(&dev->slock, flags);
        if (list_empty(&cx88q->active)) {
-               dprintk(1, "queue is empty - first active\n");
-               list_add_tail(&buf->vb.queue, &cx88q->active);
-               cx23885_start_dma(port, cx88q, buf);
-               buf->vb.state = VIDEOBUF_ACTIVE;
-               buf->count    = cx88q->count++;
-               mod_timer(&cx88q->timeout, jiffies + BUFFER_TIMEOUT);
+               list_add_tail(&buf->queue, &cx88q->active);
                dprintk(1, "[%p/%d] %s - first active\n",
-                       buf, buf->vb.i, __func__);
+                       buf, buf->vb.v4l2_buf.index, __func__);
        } else {
-               dprintk(1, "queue is not empty - append to active\n");
+               buf->risc.cpu[0] |= cpu_to_le32(RISC_IRQ1);
                prev = list_entry(cx88q->active.prev, struct cx23885_buffer,
-                                 vb.queue);
-               list_add_tail(&buf->vb.queue, &cx88q->active);
-               buf->vb.state = VIDEOBUF_ACTIVE;
-               buf->count    = cx88q->count++;
+                                 queue);
+               list_add_tail(&buf->queue, &cx88q->active);
                prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma);
-               prev->risc.jmp[2] = cpu_to_le32(0); /* 64 bit bits 63-32 */
                dprintk(1, "[%p/%d] %s - append to active\n",
-                        buf, buf->vb.i, __func__);
+                        buf, buf->vb.v4l2_buf.index, __func__);
        }
+       spin_unlock_irqrestore(&dev->slock, flags);
 }
 
 /* ----------------------------------------------------------- */
 
-static void do_cancel_buffers(struct cx23885_tsport *port, char *reason,
-                             int restart)
+static void do_cancel_buffers(struct cx23885_tsport *port, char *reason)
 {
        struct cx23885_dev *dev = port->dev;
        struct cx23885_dmaqueue *q = &port->mpegq;
@@ -1634,16 +1532,11 @@ static void do_cancel_buffers(struct cx23885_tsport *port, char *reason,
        spin_lock_irqsave(&port->slock, flags);
        while (!list_empty(&q->active)) {
                buf = list_entry(q->active.next, struct cx23885_buffer,
-                                vb.queue);
-               list_del(&buf->vb.queue);
-               buf->vb.state = VIDEOBUF_ERROR;
-               wake_up(&buf->vb.done);
+                                queue);
+               list_del(&buf->queue);
+               vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR);
                dprintk(1, "[%p/%d] %s - dma=0x%08lx\n",
-                       buf, buf->vb.i, reason, (unsigned long)buf->risc.dma);
-       }
-       if (restart) {
-               dprintk(1, "restarting queue\n");
-               cx23885_restart_queue(port, q);
+                       buf, buf->vb.v4l2_buf.index, reason, (unsigned long)buf->risc.dma);
        }
        spin_unlock_irqrestore(&port->slock, flags);
 }
@@ -1651,27 +1544,10 @@ static void do_cancel_buffers(struct cx23885_tsport *port, char *reason,
 void cx23885_cancel_buffers(struct cx23885_tsport *port)
 {
        struct cx23885_dev *dev = port->dev;
-       struct cx23885_dmaqueue *q = &port->mpegq;
-
-       dprintk(1, "%s()\n", __func__);
-       del_timer_sync(&q->timeout);
-       cx23885_stop_dma(port);
-       do_cancel_buffers(port, "cancel", 0);
-}
-
-static void cx23885_timeout(unsigned long data)
-{
-       struct cx23885_tsport *port = (struct cx23885_tsport *)data;
-       struct cx23885_dev *dev = port->dev;
 
        dprintk(1, "%s()\n", __func__);
-
-       if (debug > 5)
-               cx23885_sram_channel_dump(dev,
-                       &dev->sram_channels[port->sram_chno]);
-
        cx23885_stop_dma(port);
-       do_cancel_buffers(port, "timeout", 1);
+       do_cancel_buffers(port, "cancel");
 }
 
 int cx23885_irq_417(struct cx23885_dev *dev, u32 status)
@@ -1721,11 +1597,6 @@ int cx23885_irq_417(struct cx23885_dev *dev, u32 status)
                spin_lock(&port->slock);
                cx23885_wakeup(port, &port->mpegq, count);
                spin_unlock(&port->slock);
-       } else if (status & VID_B_MSK_RISCI2) {
-               dprintk(7, "        VID_B_MSK_RISCI2\n");
-               spin_lock(&port->slock);
-               cx23885_restart_queue(port, &port->mpegq);
-               spin_unlock(&port->slock);
        }
        if (status) {
                cx_write(port->reg_ts_int_stat, status);
@@ -1777,14 +1648,6 @@ static int cx23885_irq_ts(struct cx23885_tsport *port, u32 status)
                cx23885_wakeup(port, &port->mpegq, count);
                spin_unlock(&port->slock);
 
-       } else if (status & VID_BC_MSK_RISCI2) {
-
-               dprintk(7, " (RISCI2            0x%08x)\n", VID_BC_MSK_RISCI2);
-
-               spin_lock(&port->slock);
-               cx23885_restart_queue(port, &port->mpegq);
-               spin_unlock(&port->slock);
-
        }
        if (status) {
                cx_write(port->reg_ts_int_stat, status);
@@ -2087,6 +1950,7 @@ static int cx23885_initdev(struct pci_dev *pci_dev,
                           const struct pci_device_id *pci_id)
 {
        struct cx23885_dev *dev;
+       struct v4l2_ctrl_handler *hdl;
        int err;
 
        dev = kzalloc(sizeof(*dev), GFP_KERNEL);
@@ -2097,6 +1961,14 @@ static int cx23885_initdev(struct pci_dev *pci_dev,
        if (err < 0)
                goto fail_free;
 
+       hdl = &dev->ctrl_handler;
+       v4l2_ctrl_handler_init(hdl, 6);
+       if (hdl->error) {
+               err = hdl->error;
+               goto fail_ctrl;
+       }
+       dev->v4l2_dev.ctrl_handler = hdl;
+
        /* Prepare to handle notifications from subdevices */
        cx23885_v4l2_dev_notify_init(dev);
 
@@ -2104,12 +1976,12 @@ static int cx23885_initdev(struct pci_dev *pci_dev,
        dev->pci = pci_dev;
        if (pci_enable_device(pci_dev)) {
                err = -EIO;
-               goto fail_unreg;
+               goto fail_ctrl;
        }
 
        if (cx23885_dev_setup(dev) < 0) {
                err = -EINVAL;
-               goto fail_unreg;
+               goto fail_ctrl;
        }
 
        /* print pci info */
@@ -2157,7 +2029,8 @@ static int cx23885_initdev(struct pci_dev *pci_dev,
 
 fail_irq:
        cx23885_dev_unregister(dev);
-fail_unreg:
+fail_ctrl:
+       v4l2_ctrl_handler_free(hdl);
        v4l2_device_unregister(&dev->v4l2_dev);
 fail_free:
        kfree(dev);
@@ -2180,6 +2053,7 @@ static void cx23885_finidev(struct pci_dev *pci_dev)
        free_irq(pci_dev->irq, dev);
 
        cx23885_dev_unregister(dev);
+       v4l2_ctrl_handler_free(&dev->ctrl_handler);
        v4l2_device_unregister(v4l2_dev);
        kfree(dev);
 }
index 968fecc32f9cad35413945e0af9f7ce9edbde5bb..13734b8c791724e8a84dc27cd5949aeaf6a3b1ca 100644 (file)
  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  *
  *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
 #include <linux/module.h>
 #include "a8293.h"
 #include "mb86a20s.h"
 #include "si2165.h"
+#include "si2168.h"
+#include "si2157.h"
+#include "m88ds3103.h"
+#include "m88ts2022.h"
 
 static unsigned int debug;
 
@@ -91,59 +91,95 @@ DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
 
 /* ------------------------------------------------------------------ */
 
-static int dvb_buf_setup(struct videobuf_queue *q,
-                        unsigned int *count, unsigned int *size)
+static int queue_setup(struct vb2_queue *q, const struct v4l2_format *fmt,
+                          unsigned int *num_buffers, unsigned int *num_planes,
+                          unsigned int sizes[], void *alloc_ctxs[])
 {
-       struct cx23885_tsport *port = q->priv_data;
+       struct cx23885_tsport *port = q->drv_priv;
 
        port->ts_packet_size  = 188 * 4;
        port->ts_packet_count = 32;
-
-       *size  = port->ts_packet_size * port->ts_packet_count;
-       *count = 32;
+       *num_planes = 1;
+       sizes[0] = port->ts_packet_size * port->ts_packet_count;
+       *num_buffers = 32;
        return 0;
 }
 
-static int dvb_buf_prepare(struct videobuf_queue *q,
-                          struct videobuf_buffer *vb, enum v4l2_field field)
+
+static int buffer_prepare(struct vb2_buffer *vb)
 {
-       struct cx23885_tsport *port = q->priv_data;
-       return cx23885_buf_prepare(q, port, (struct cx23885_buffer *)vb, field);
+       struct cx23885_tsport *port = vb->vb2_queue->drv_priv;
+       struct cx23885_buffer *buf =
+               container_of(vb, struct cx23885_buffer, vb);
+
+       return cx23885_buf_prepare(buf, port);
 }
 
-static void dvb_buf_queue(struct videobuf_queue *q, struct videobuf_buffer *vb)
+static void buffer_finish(struct vb2_buffer *vb)
 {
-       struct cx23885_tsport *port = q->priv_data;
-       cx23885_buf_queue(port, (struct cx23885_buffer *)vb);
+       struct cx23885_tsport *port = vb->vb2_queue->drv_priv;
+       struct cx23885_dev *dev = port->dev;
+       struct cx23885_buffer *buf = container_of(vb,
+               struct cx23885_buffer, vb);
+       struct sg_table *sgt = vb2_dma_sg_plane_desc(vb, 0);
+
+       cx23885_free_buffer(dev, buf);
+
+       dma_unmap_sg(&dev->pci->dev, sgt->sgl, sgt->nents, DMA_FROM_DEVICE);
 }
 
-static void dvb_buf_release(struct videobuf_queue *q,
-                           struct videobuf_buffer *vb)
+static void buffer_queue(struct vb2_buffer *vb)
 {
-       cx23885_free_buffer(q, (struct cx23885_buffer *)vb);
+       struct cx23885_tsport *port = vb->vb2_queue->drv_priv;
+       struct cx23885_buffer   *buf = container_of(vb,
+               struct cx23885_buffer, vb);
+
+       cx23885_buf_queue(port, buf);
 }
 
 static void cx23885_dvb_gate_ctrl(struct cx23885_tsport  *port, int open)
 {
-       struct videobuf_dvb_frontends *f;
-       struct videobuf_dvb_frontend *fe;
+       struct vb2_dvb_frontends *f;
+       struct vb2_dvb_frontend *fe;
 
        f = &port->frontends;
 
        if (f->gate <= 1) /* undefined or fe0 */
-               fe = videobuf_dvb_get_frontend(f, 1);
+               fe = vb2_dvb_get_frontend(f, 1);
        else
-               fe = videobuf_dvb_get_frontend(f, f->gate);
+               fe = vb2_dvb_get_frontend(f, f->gate);
 
        if (fe && fe->dvb.frontend && fe->dvb.frontend->ops.i2c_gate_ctrl)
                fe->dvb.frontend->ops.i2c_gate_ctrl(fe->dvb.frontend, open);
 }
 
-static struct videobuf_queue_ops dvb_qops = {
-       .buf_setup    = dvb_buf_setup,
-       .buf_prepare  = dvb_buf_prepare,
-       .buf_queue    = dvb_buf_queue,
-       .buf_release  = dvb_buf_release,
+static int cx23885_start_streaming(struct vb2_queue *q, unsigned int count)
+{
+       struct cx23885_tsport *port = q->drv_priv;
+       struct cx23885_dmaqueue *dmaq = &port->mpegq;
+       struct cx23885_buffer *buf = list_entry(dmaq->active.next,
+                       struct cx23885_buffer, queue);
+
+       cx23885_start_dma(port, dmaq, buf);
+       return 0;
+}
+
+static void cx23885_stop_streaming(struct vb2_queue *q)
+{
+       struct cx23885_tsport *port = q->drv_priv;
+
+       cx23885_cancel_buffers(port);
+}
+
+static struct vb2_ops dvb_qops = {
+       .queue_setup    = queue_setup,
+       .buf_prepare  = buffer_prepare,
+       .buf_finish = buffer_finish,
+       .buf_queue    = buffer_queue,
+       .wait_prepare = vb2_ops_wait_prepare,
+       .wait_finish = vb2_ops_wait_finish,
+       .start_streaming = cx23885_start_streaming,
+       .stop_streaming = cx23885_stop_streaming,
 };
 
 static struct s5h1409_config hauppauge_generic_config = {
@@ -551,6 +587,35 @@ static int p8000_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
        return 0;
 }
 
+static int dvbsky_t9580_set_voltage(struct dvb_frontend *fe,
+                                       fe_sec_voltage_t voltage)
+{
+       struct cx23885_tsport *port = fe->dvb->priv;
+       struct cx23885_dev *dev = port->dev;
+
+       cx23885_gpio_enable(dev, GPIO_0 | GPIO_1, 1);
+
+       switch (voltage) {
+       case SEC_VOLTAGE_13:
+               cx23885_gpio_set(dev, GPIO_1);
+               cx23885_gpio_clear(dev, GPIO_0);
+               break;
+       case SEC_VOLTAGE_18:
+               cx23885_gpio_set(dev, GPIO_1);
+               cx23885_gpio_set(dev, GPIO_0);
+               break;
+       case SEC_VOLTAGE_OFF:
+               cx23885_gpio_clear(dev, GPIO_1);
+               cx23885_gpio_clear(dev, GPIO_0);
+               break;
+       }
+
+       /* call the frontend set_voltage function */
+       port->fe_set_voltage(fe, voltage);
+
+       return 0;
+}
+
 static int cx23885_dvb_set_frontend(struct dvb_frontend *fe)
 {
        struct dtv_frontend_properties *p = &fe->dtv_property_cache;
@@ -715,6 +780,19 @@ static const struct si2165_config hauppauge_hvr4400_si2165_config = {
        .ref_freq_Hz    = 16000000,
 };
 
+static const struct m88ds3103_config dvbsky_t9580_m88ds3103_config = {
+       .i2c_addr = 0x68,
+       .clock = 27000000,
+       .i2c_wr_max = 33,
+       .clock_out = 0,
+       .ts_mode = M88DS3103_TS_PARALLEL,
+       .ts_clk = 16000,
+       .ts_clk_pol = 1,
+       .lnb_en_pol = 1,
+       .lnb_hv_pol = 0,
+       .agc = 0x99,
+};
+
 static int netup_altera_fpga_rw(void *device, int flag, int data, int read)
 {
        struct cx23885_dev *dev = (struct cx23885_dev *)device;
@@ -863,16 +941,23 @@ static int dvb_register(struct cx23885_tsport *port)
        struct dib7000p_ops dib7000p_ops;
        struct cx23885_dev *dev = port->dev;
        struct cx23885_i2c *i2c_bus = NULL, *i2c_bus2 = NULL;
-       struct videobuf_dvb_frontend *fe0, *fe1 = NULL;
+       struct vb2_dvb_frontend *fe0, *fe1 = NULL;
+       struct si2168_config si2168_config;
+       struct si2157_config si2157_config;
+       struct m88ts2022_config m88ts2022_config;
+       struct i2c_board_info info;
+       struct i2c_adapter *adapter;
+       struct i2c_client *client_demod;
+       struct i2c_client *client_tuner;
        int mfe_shared = 0; /* bus not shared by default */
        int ret;
 
        /* Get the first frontend */
-       fe0 = videobuf_dvb_get_frontend(&port->frontends, 1);
+       fe0 = vb2_dvb_get_frontend(&port->frontends, 1);
        if (!fe0)
                return -EINVAL;
 
-       /* init struct videobuf_dvb */
+       /* init struct vb2_dvb */
        fe0->dvb.name = dev->name;
 
        /* multi-frontend gate control is undefined or defaults to fe0 */
@@ -1392,7 +1477,7 @@ static int dvb_register(struct cx23885_tsport *port)
                        fe0->dvb.frontend->ops.tuner_ops.init(fe0->dvb.frontend);
                }
                /* MFE frontend 2 */
-               fe1 = videobuf_dvb_get_frontend(&port->frontends, 2);
+               fe1 = vb2_dvb_get_frontend(&port->frontends, 2);
                if (fe1 == NULL)
                        goto frontend_detach;
                /* DVB-C init */
@@ -1491,7 +1576,7 @@ static int dvb_register(struct cx23885_tsport *port)
                                        &hauppauge_hvr4400_si2165_config,
                                        &i2c_bus->i2c_adap);
                        if (fe0->dvb.frontend != NULL) {
-                               fe0->dvb.frontend->ops.i2c_gate_ctrl = 0;
+                               fe0->dvb.frontend->ops.i2c_gate_ctrl = NULL;
                                if (!dvb_attach(tda18271_attach,
                                                fe0->dvb.frontend,
                                                0x60, &i2c_bus2->i2c_adap,
@@ -1501,6 +1586,97 @@ static int dvb_register(struct cx23885_tsport *port)
                        break;
                }
                break;
+       case CX23885_BOARD_DVBSKY_T9580:
+               i2c_bus = &dev->i2c_bus[0];
+               i2c_bus2 = &dev->i2c_bus[1];
+               switch (port->nr) {
+               /* port b - satellite */
+               case 1:
+                       /* attach frontend */
+                       fe0->dvb.frontend = dvb_attach(m88ds3103_attach,
+                                       &dvbsky_t9580_m88ds3103_config,
+                                       &i2c_bus2->i2c_adap, &adapter);
+                       if (fe0->dvb.frontend == NULL)
+                               break;
+
+                       /* attach tuner */
+                       m88ts2022_config.fe = fe0->dvb.frontend;
+                       m88ts2022_config.clock = 27000000;
+                       memset(&info, 0, sizeof(struct i2c_board_info));
+                       strlcpy(info.type, "m88ts2022", I2C_NAME_SIZE);
+                       info.addr = 0x60;
+                       info.platform_data = &m88ts2022_config;
+                       request_module(info.type);
+                       client_tuner = i2c_new_device(adapter, &info);
+                       if (client_tuner == NULL ||
+                                       client_tuner->dev.driver == NULL)
+                               goto frontend_detach;
+                       if (!try_module_get(client_tuner->dev.driver->owner)) {
+                               i2c_unregister_device(client_tuner);
+                               goto frontend_detach;
+                       }
+
+                       /* delegate signal strength measurement to tuner */
+                       fe0->dvb.frontend->ops.read_signal_strength =
+                               fe0->dvb.frontend->ops.tuner_ops.get_rf_strength;
+
+                       /*
+                        * for setting the voltage we need to set GPIOs on
+                        * the card.
+                        */
+                       port->fe_set_voltage =
+                               fe0->dvb.frontend->ops.set_voltage;
+                       fe0->dvb.frontend->ops.set_voltage =
+                               dvbsky_t9580_set_voltage;
+
+                       port->i2c_client_tuner = client_tuner;
+
+                       break;
+               /* port c - terrestrial/cable */
+               case 2:
+                       /* attach frontend */
+                       si2168_config.i2c_adapter = &adapter;
+                       si2168_config.fe = &fe0->dvb.frontend;
+                       si2168_config.ts_mode = SI2168_TS_SERIAL;
+                       memset(&info, 0, sizeof(struct i2c_board_info));
+                       strlcpy(info.type, "si2168", I2C_NAME_SIZE);
+                       info.addr = 0x64;
+                       info.platform_data = &si2168_config;
+                       request_module(info.type);
+                       client_demod = i2c_new_device(&i2c_bus->i2c_adap, &info);
+                       if (client_demod == NULL ||
+                                       client_demod->dev.driver == NULL)
+                               goto frontend_detach;
+                       if (!try_module_get(client_demod->dev.driver->owner)) {
+                               i2c_unregister_device(client_demod);
+                               goto frontend_detach;
+                       }
+                       port->i2c_client_demod = client_demod;
+
+                       /* attach tuner */
+                       si2157_config.fe = fe0->dvb.frontend;
+                       memset(&info, 0, sizeof(struct i2c_board_info));
+                       strlcpy(info.type, "si2157", I2C_NAME_SIZE);
+                       info.addr = 0x60;
+                       info.platform_data = &si2157_config;
+                       request_module(info.type);
+                       client_tuner = i2c_new_device(adapter, &info);
+                       if (client_tuner == NULL ||
+                                       client_tuner->dev.driver == NULL) {
+                               module_put(client_demod->dev.driver->owner);
+                               i2c_unregister_device(client_demod);
+                               goto frontend_detach;
+                       }
+                       if (!try_module_get(client_tuner->dev.driver->owner)) {
+                               i2c_unregister_device(client_tuner);
+                               module_put(client_demod->dev.driver->owner);
+                               i2c_unregister_device(client_demod);
+                               goto frontend_detach;
+                       }
+                       port->i2c_client_tuner = client_tuner;
+                       break;
+               }
+               break;
        default:
                printk(KERN_INFO "%s: The frontend of your DVB/ATSC card "
                        " isn't supported yet\n",
@@ -1532,7 +1708,7 @@ static int dvb_register(struct cx23885_tsport *port)
                fe0->dvb.frontend->ops.analog_ops.standby(fe0->dvb.frontend);
 
        /* register everything */
-       ret = videobuf_dvb_register_bus(&port->frontends, THIS_MODULE, port,
+       ret = vb2_dvb_register_bus(&port->frontends, THIS_MODULE, port,
                                        &dev->pci->dev, adapter_nr, mfe_shared);
        if (ret)
                goto frontend_detach;
@@ -1575,20 +1751,36 @@ static int dvb_register(struct cx23885_tsport *port)
                memcpy(port->frontends.adapter.proposed_mac, eeprom + 0xa0, 6);
                break;
                }
+       case CX23885_BOARD_DVBSKY_T9580: {
+               u8 eeprom[256]; /* 24C02 i2c eeprom */
+
+               if (port->nr > 2)
+                       break;
+
+               /* Read entire EEPROM */
+               dev->i2c_bus[0].i2c_client.addr = 0xa0 >> 1;
+               tveeprom_read(&dev->i2c_bus[0].i2c_client, eeprom,
+                               sizeof(eeprom));
+               printk(KERN_INFO "DVBSky T9580 port %d MAC address: %pM\n",
+                       port->nr, eeprom + 0xc0 + (port->nr-1) * 8);
+               memcpy(port->frontends.adapter.proposed_mac, eeprom + 0xc0 +
+                       (port->nr-1) * 8, 6);
+               break;
+               }
        }
 
        return ret;
 
 frontend_detach:
        port->gate_ctrl = NULL;
-       videobuf_dvb_dealloc_frontends(&port->frontends);
+       vb2_dvb_dealloc_frontends(&port->frontends);
        return -EINVAL;
 }
 
 int cx23885_dvb_register(struct cx23885_tsport *port)
 {
 
-       struct videobuf_dvb_frontend *fe0;
+       struct vb2_dvb_frontend *fe0;
        struct cx23885_dev *dev = port->dev;
        int err, i;
 
@@ -1605,13 +1797,15 @@ int cx23885_dvb_register(struct cx23885_tsport *port)
                port->num_frontends);
 
        for (i = 1; i <= port->num_frontends; i++) {
-               if (videobuf_dvb_alloc_frontend(
+               struct vb2_queue *q;
+
+               if (vb2_dvb_alloc_frontend(
                        &port->frontends, i) == NULL) {
                        printk(KERN_ERR "%s() failed to alloc\n", __func__);
                        return -ENOMEM;
                }
 
-               fe0 = videobuf_dvb_get_frontend(&port->frontends, i);
+               fe0 = vb2_dvb_get_frontend(&port->frontends, i);
                if (!fe0)
                        err = -EINVAL;
 
@@ -1627,10 +1821,21 @@ int cx23885_dvb_register(struct cx23885_tsport *port)
                /* dvb stuff */
                /* We have to init the queue for each frontend on a port. */
                printk(KERN_INFO "%s: cx23885 based dvb card\n", dev->name);
-               videobuf_queue_sg_init(&fe0->dvb.dvbq, &dvb_qops,
-                           &dev->pci->dev, &port->slock,
-                           V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FIELD_TOP,
-                           sizeof(struct cx23885_buffer), port, NULL);
+               q = &fe0->dvb.dvbq;
+               q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+               q->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF | VB2_READ;
+               q->gfp_flags = GFP_DMA32;
+               q->min_buffers_needed = 2;
+               q->drv_priv = port;
+               q->buf_struct_size = sizeof(struct cx23885_buffer);
+               q->ops = &dvb_qops;
+               q->mem_ops = &vb2_dma_sg_memops;
+               q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
+               q->lock = &dev->lock;
+
+               err = vb2_queue_init(q);
+               if (err < 0)
+                       return err;
        }
        err = dvb_register(port);
        if (err != 0)
@@ -1642,18 +1847,27 @@ int cx23885_dvb_register(struct cx23885_tsport *port)
 
 int cx23885_dvb_unregister(struct cx23885_tsport *port)
 {
-       struct videobuf_dvb_frontend *fe0;
-
-       /* FIXME: in an error condition where the we have
-        * an expected number of frontends (attach problem)
-        * then this might not clean up correctly, if 1
-        * is invalid.
-        * This comment only applies to future boards IF they
-        * implement MFE support.
-        */
-       fe0 = videobuf_dvb_get_frontend(&port->frontends, 1);
+       struct vb2_dvb_frontend *fe0;
+       struct i2c_client *client;
+
+       /* remove I2C client for tuner */
+       client = port->i2c_client_tuner;
+       if (client) {
+               module_put(client->dev.driver->owner);
+               i2c_unregister_device(client);
+       }
+
+       /* remove I2C client for demodulator */
+       client = port->i2c_client_demod;
+       if (client) {
+               module_put(client->dev.driver->owner);
+               i2c_unregister_device(client);
+       }
+
+       fe0 = vb2_dvb_get_frontend(&port->frontends, 1);
+
        if (fe0 && fe0->dvb.frontend)
-               videobuf_dvb_unregister_bus(&port->frontends);
+               vb2_dvb_unregister_bus(&port->frontends);
 
        switch (port->dev->board) {
        case CX23885_BOARD_NETUP_DUAL_DVBS2_CI:
@@ -1668,4 +1882,3 @@ int cx23885_dvb_unregister(struct cx23885_tsport *port)
 
        return 0;
 }
-
index 5444cc526008706d1a6b7a4c87e4aa0da923a22f..6f817d8732da8ca6a19ed7f742b78d85f66c4da9 100644 (file)
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  *
  * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
 #include "cx23885.h"
index 4887314339cbfa9071db9a898e985fae2495a9c8..fd71306af6e2f8facfc64964a8c05eb88fe3c146 100644 (file)
  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  *
  *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
 #include <linux/module.h>
@@ -386,11 +382,3 @@ void cx23885_av_clk(struct cx23885_dev *dev, int enable)
 
        i2c_xfer(&dev->i2c_bus[2].i2c_adap, &msg, 1);
 }
-
-/* ----------------------------------------------------------------------- */
-
-/*
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
index 1940c18e186cfbb6d0fbac1b579bdee75a040231..9d37fe6616913f268cd52499f3c7d089831aeb1c 100644 (file)
  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- *  02110-1301, USA.
  */
 
 #include <linux/slab.h>
index 87dc44e69977e2d38fb9c168711a0bf04c54f671..6199c7e86e83133779d1c07f7055599aab4a21de 100644 (file)
  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- *  02110-1301, USA.
  */
 
 #ifndef _CX23885_INPUT_H_
index 271d69d1ca8c7c0a4c0796151353e97c4961ab3e..d2cdd40f79f54611b9b6aa46ad7a0d5a9b00d9f0 100644 (file)
  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  *
  *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
 #include "cx23885.h"
@@ -28,7 +24,7 @@
 int cx23885_g_chip_info(struct file *file, void *fh,
                         struct v4l2_dbg_chip_info *chip)
 {
-       struct cx23885_dev *dev = ((struct cx23885_fh *)fh)->dev;
+       struct cx23885_dev *dev = video_drvdata(file);
 
        if (chip->match.addr > 1)
                return -EINVAL;
@@ -64,7 +60,7 @@ static int cx23417_g_register(struct cx23885_dev *dev,
 int cx23885_g_register(struct file *file, void *fh,
                       struct v4l2_dbg_register *reg)
 {
-       struct cx23885_dev *dev = ((struct cx23885_fh *)fh)->dev;
+       struct cx23885_dev *dev = video_drvdata(file);
 
        if (reg->match.addr > 1)
                return -EINVAL;
@@ -96,7 +92,7 @@ static int cx23417_s_register(struct cx23885_dev *dev,
 int cx23885_s_register(struct file *file, void *fh,
                       const struct v4l2_dbg_register *reg)
 {
-       struct cx23885_dev *dev = ((struct cx23885_fh *)fh)->dev;
+       struct cx23885_dev *dev = video_drvdata(file);
 
        if (reg->match.addr > 1)
                return -EINVAL;
index 92d9f077436679d0402b416a70384e9775923f96..cc5dbb6c1afccc54cc43deaf2db4c1abd4b1d56a 100644 (file)
  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  *
  *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
 #ifndef _CX23885_IOCTL_H_
index bfef193592916dd46ed734dac478ac03e1eab653..89dc4cc3e1cea427d3aef91201548e38e91e9cda 100644 (file)
  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- *  02110-1301, USA.
  */
 
 #include <media/v4l2-device.h>
index 0c9d8bda9e2895d1640c96c6b89e16cb95f499ec..8e93d1f10ae0d89398e6c5b9421d332ddec55c83 100644 (file)
  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- *  02110-1301, USA.
  */
 
 #ifndef _CX23885_IR_H_
index a99936e0cbc270c5d9fe5ad29eeafd0101c4304d..2d3cbafe24023420162a9a947234e0924aa7aaf7 100644 (file)
  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  *
  *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
 #ifndef _CX23885_REG_H_
index a1154f035bc185daa692f6ac5443a5067ff46169..a7c6ef8f3ea3a7f1e96ce9a7642e3056ea27543c 100644 (file)
  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  *
  *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
 #include <linux/kernel.h>
@@ -42,33 +38,32 @@ MODULE_PARM_DESC(vbi_debug, "enable debug messages [vbi]");
 /* ------------------------------------------------------------------ */
 
 #define VBI_LINE_LENGTH 1440
-#define NTSC_VBI_START_LINE 10        /* line 10 - 21 */
-#define NTSC_VBI_END_LINE   21
-#define NTSC_VBI_LINES      (NTSC_VBI_END_LINE - NTSC_VBI_START_LINE + 1)
+#define VBI_NTSC_LINE_COUNT 12
+#define VBI_PAL_LINE_COUNT 18
 
 
 int cx23885_vbi_fmt(struct file *file, void *priv,
        struct v4l2_format *f)
 {
-       struct cx23885_fh *fh = priv;
-       struct cx23885_dev *dev = fh->dev;
+       struct cx23885_dev *dev = video_drvdata(file);
 
+       f->fmt.vbi.sampling_rate = 27000000;
+       f->fmt.vbi.samples_per_line = VBI_LINE_LENGTH;
+       f->fmt.vbi.sample_format = V4L2_PIX_FMT_GREY;
+       f->fmt.vbi.offset = 0;
+       f->fmt.vbi.flags = 0;
        if (dev->tvnorm & V4L2_STD_525_60) {
                /* ntsc */
-               f->fmt.vbi.samples_per_line = VBI_LINE_LENGTH;
-               f->fmt.vbi.sampling_rate = 27000000;
-               f->fmt.vbi.sample_format = V4L2_PIX_FMT_GREY;
-               f->fmt.vbi.offset = 0;
-               f->fmt.vbi.flags = 0;
-               f->fmt.vbi.start[0] = 10;
-               f->fmt.vbi.count[0] = 17;
-               f->fmt.vbi.start[1] = 263 + 10 + 1;
-               f->fmt.vbi.count[1] = 17;
+               f->fmt.vbi.start[0] = V4L2_VBI_ITU_525_F1_START + 9;
+               f->fmt.vbi.start[1] = V4L2_VBI_ITU_525_F2_START + 9;
+               f->fmt.vbi.count[0] = VBI_NTSC_LINE_COUNT;
+               f->fmt.vbi.count[1] = VBI_NTSC_LINE_COUNT;
        } else if (dev->tvnorm & V4L2_STD_625_50) {
                /* pal */
-               f->fmt.vbi.sampling_rate = 35468950;
-               f->fmt.vbi.start[0] = 7 - 1;
-               f->fmt.vbi.start[1] = 319 - 1;
+               f->fmt.vbi.start[0] = V4L2_VBI_ITU_625_F1_START + 5;
+               f->fmt.vbi.start[1] = V4L2_VBI_ITU_625_F2_START + 5;
+               f->fmt.vbi.count[0] = VBI_PAL_LINE_COUNT;
+               f->fmt.vbi.count[1] = VBI_PAL_LINE_COUNT;
        }
 
        return 0;
@@ -94,15 +89,6 @@ int cx23885_vbi_irq(struct cx23885_dev *dev, u32 status)
                handled++;
        }
 
-       if (status & VID_BC_MSK_VBI_RISCI2) {
-               dprintk(1, "%s() VID_BC_MSK_VBI_RISCI2\n", __func__);
-               dprintk(2, "stopper vbi\n");
-               spin_lock(&dev->slock);
-               cx23885_restart_vbi_queue(dev, &dev->vbiq);
-               spin_unlock(&dev->slock);
-               handled++;
-       }
-
        return handled;
 }
 
@@ -114,13 +100,13 @@ static int cx23885_start_vbi_dma(struct cx23885_dev    *dev,
 
        /* setup fifo + format */
        cx23885_sram_channel_setup(dev, &dev->sram_channels[SRAM_CH02],
-                               buf->vb.width, buf->risc.dma);
+                               VBI_LINE_LENGTH, buf->risc.dma);
 
        /* reset counter */
        cx_write(VID_A_GPCNT_CTL, 3);
        cx_write(VID_A_VBI_CTRL, 3);
        cx_write(VBI_A_GPCNT_CTL, 3);
-       q->count = 1;
+       q->count = 0;
 
        /* enable irq */
        cx23885_irq_add_enable(dev, 0x01);
@@ -133,163 +119,153 @@ static int cx23885_start_vbi_dma(struct cx23885_dev    *dev,
        return 0;
 }
 
+/* ------------------------------------------------------------------ */
 
-int cx23885_restart_vbi_queue(struct cx23885_dev    *dev,
-                            struct cx23885_dmaqueue *q)
+static int queue_setup(struct vb2_queue *q, const struct v4l2_format *fmt,
+                          unsigned int *num_buffers, unsigned int *num_planes,
+                          unsigned int sizes[], void *alloc_ctxs[])
 {
-       struct cx23885_buffer *buf;
-       struct list_head *item;
-
-       if (list_empty(&q->active))
-               return 0;
-
-       buf = list_entry(q->active.next, struct cx23885_buffer, vb.queue);
-       dprintk(2, "restart_queue [%p/%d]: restart dma\n",
-               buf, buf->vb.i);
-       cx23885_start_vbi_dma(dev, q, buf);
-       list_for_each(item, &q->active) {
-               buf = list_entry(item, struct cx23885_buffer, vb.queue);
-               buf->count = q->count++;
-       }
-       mod_timer(&q->timeout, jiffies + (BUFFER_TIMEOUT / 30));
+       struct cx23885_dev *dev = q->drv_priv;
+       unsigned lines = VBI_PAL_LINE_COUNT;
+
+       if (dev->tvnorm & V4L2_STD_525_60)
+               lines = VBI_NTSC_LINE_COUNT;
+       *num_planes = 1;
+       sizes[0] = lines * VBI_LINE_LENGTH * 2;
        return 0;
 }
 
-void cx23885_vbi_timeout(unsigned long data)
+static int buffer_prepare(struct vb2_buffer *vb)
 {
-       struct cx23885_dev *dev = (struct cx23885_dev *)data;
-       struct cx23885_dmaqueue *q = &dev->vbiq;
-       struct cx23885_buffer *buf;
-       unsigned long flags;
+       struct cx23885_dev *dev = vb->vb2_queue->drv_priv;
+       struct cx23885_buffer *buf = container_of(vb,
+               struct cx23885_buffer, vb);
+       struct sg_table *sgt = vb2_dma_sg_plane_desc(vb, 0);
+       unsigned lines = VBI_PAL_LINE_COUNT;
+       int ret;
 
-       /* Stop the VBI engine */
-       cx_clear(VID_A_DMA_CTL, 0x22);
+       if (dev->tvnorm & V4L2_STD_525_60)
+               lines = VBI_NTSC_LINE_COUNT;
 
-       spin_lock_irqsave(&dev->slock, flags);
-       while (!list_empty(&q->active)) {
-               buf = list_entry(q->active.next, struct cx23885_buffer,
-                       vb.queue);
-               list_del(&buf->vb.queue);
-               buf->vb.state = VIDEOBUF_ERROR;
-               wake_up(&buf->vb.done);
-               printk("%s/0: [%p/%d] timeout - dma=0x%08lx\n", dev->name,
-                      buf, buf->vb.i, (unsigned long)buf->risc.dma);
-       }
-       cx23885_restart_vbi_queue(dev, q);
-       spin_unlock_irqrestore(&dev->slock, flags);
-}
+       if (vb2_plane_size(vb, 0) < lines * VBI_LINE_LENGTH * 2)
+               return -EINVAL;
+       vb2_set_plane_payload(vb, 0, lines * VBI_LINE_LENGTH * 2);
 
-/* ------------------------------------------------------------------ */
-#define VBI_LINE_LENGTH 1440
-#define VBI_LINE_COUNT 17
+       ret = dma_map_sg(&dev->pci->dev, sgt->sgl, sgt->nents, DMA_FROM_DEVICE);
+       if (!ret)
+               return -EIO;
 
-static int
-vbi_setup(struct videobuf_queue *q, unsigned int *count, unsigned int *size)
-{
-       *size = VBI_LINE_COUNT * VBI_LINE_LENGTH * 2;
-       if (0 == *count)
-               *count = vbibufs;
-       if (*count < 2)
-               *count = 2;
-       if (*count > 32)
-               *count = 32;
+       cx23885_risc_vbibuffer(dev->pci, &buf->risc,
+                        sgt->sgl,
+                        0, VBI_LINE_LENGTH * lines,
+                        VBI_LINE_LENGTH, 0,
+                        lines);
        return 0;
 }
 
-static int
-vbi_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,
-           enum v4l2_field field)
+static void buffer_finish(struct vb2_buffer *vb)
 {
-       struct cx23885_fh *fh  = q->priv_data;
-       struct cx23885_dev *dev = fh->dev;
+       struct cx23885_dev *dev = vb->vb2_queue->drv_priv;
        struct cx23885_buffer *buf = container_of(vb,
                struct cx23885_buffer, vb);
-       struct videobuf_dmabuf *dma = videobuf_to_dma(&buf->vb);
-       unsigned int size;
-       int rc;
-
-       size = VBI_LINE_COUNT * VBI_LINE_LENGTH * 2;
-       if (0 != buf->vb.baddr  &&  buf->vb.bsize < size)
-               return -EINVAL;
+       struct sg_table *sgt = vb2_dma_sg_plane_desc(vb, 0);
 
-       if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
-               buf->vb.width  = VBI_LINE_LENGTH;
-               buf->vb.height = VBI_LINE_COUNT;
-               buf->vb.size   = size;
-               buf->vb.field  = V4L2_FIELD_SEQ_TB;
-
-               rc = videobuf_iolock(q, &buf->vb, NULL);
-               if (0 != rc)
-                       goto fail;
-               cx23885_risc_vbibuffer(dev->pci, &buf->risc,
-                                dma->sglist,
-                                0, buf->vb.width * buf->vb.height,
-                                buf->vb.width, 0,
-                                buf->vb.height);
-       }
-       buf->vb.state = VIDEOBUF_PREPARED;
-       return 0;
+       cx23885_free_buffer(vb->vb2_queue->drv_priv, buf);
 
- fail:
-       cx23885_free_buffer(q, buf);
-       return rc;
+       dma_unmap_sg(&dev->pci->dev, sgt->sgl, sgt->nents, DMA_FROM_DEVICE);
 }
 
-static void
-vbi_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
+/*
+ * The risc program for each buffer works as follows: it starts with a simple
+ * 'JUMP to addr + 12', which is effectively a NOP. Then the code to DMA the
+ * buffer follows and at the end we have a JUMP back to the start + 12 (skipping
+ * the initial JUMP).
+ *
+ * This is the risc program of the first buffer to be queued if the active list
+ * is empty and it just keeps DMAing this buffer without generating any
+ * interrupts.
+ *
+ * If a new buffer is added then the initial JUMP in the code for that buffer
+ * will generate an interrupt which signals that the previous buffer has been
+ * DMAed successfully and that it can be returned to userspace.
+ *
+ * It also sets the final jump of the previous buffer to the start of the new
+ * buffer, thus chaining the new buffer into the DMA chain. This is a single
+ * atomic u32 write, so there is no race condition.
+ *
+ * The end-result of all this that you only get an interrupt when a buffer
+ * is ready, so the control flow is very easy.
+ */
+static void buffer_queue(struct vb2_buffer *vb)
 {
-       struct cx23885_buffer   *buf =
-               container_of(vb, struct cx23885_buffer, vb);
-       struct cx23885_buffer   *prev;
-       struct cx23885_fh       *fh   = vq->priv_data;
-       struct cx23885_dev      *dev  = fh->dev;
-       struct cx23885_dmaqueue *q    = &dev->vbiq;
-
-       /* add jump to stopper */
-       buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP | RISC_IRQ1 | RISC_CNT_INC);
-       buf->risc.jmp[1] = cpu_to_le32(q->stopper.dma);
+       struct cx23885_dev *dev = vb->vb2_queue->drv_priv;
+       struct cx23885_buffer *buf = container_of(vb, struct cx23885_buffer, vb);
+       struct cx23885_buffer *prev;
+       struct cx23885_dmaqueue *q = &dev->vbiq;
+       unsigned long flags;
+
+       buf->risc.cpu[1] = cpu_to_le32(buf->risc.dma + 12);
+       buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP | RISC_CNT_INC);
+       buf->risc.jmp[1] = cpu_to_le32(buf->risc.dma + 12);
        buf->risc.jmp[2] = cpu_to_le32(0); /* bits 63-32 */
 
        if (list_empty(&q->active)) {
-               list_add_tail(&buf->vb.queue, &q->active);
-               cx23885_start_vbi_dma(dev, q, buf);
-               buf->vb.state = VIDEOBUF_ACTIVE;
-               buf->count    = q->count++;
-               mod_timer(&q->timeout, jiffies + (BUFFER_TIMEOUT / 30));
+               spin_lock_irqsave(&dev->slock, flags);
+               list_add_tail(&buf->queue, &q->active);
+               spin_unlock_irqrestore(&dev->slock, flags);
                dprintk(2, "[%p/%d] vbi_queue - first active\n",
-                       buf, buf->vb.i);
+                       buf, buf->vb.v4l2_buf.index);
 
        } else {
+               buf->risc.cpu[0] |= cpu_to_le32(RISC_IRQ1);
                prev = list_entry(q->active.prev, struct cx23885_buffer,
-                       vb.queue);
-               list_add_tail(&buf->vb.queue, &q->active);
-               buf->vb.state = VIDEOBUF_ACTIVE;
-               buf->count    = q->count++;
+                       queue);
+               spin_lock_irqsave(&dev->slock, flags);
+               list_add_tail(&buf->queue, &q->active);
+               spin_unlock_irqrestore(&dev->slock, flags);
                prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma);
-               prev->risc.jmp[2] = cpu_to_le32(0); /* Bits 63-32 */
                dprintk(2, "[%p/%d] buffer_queue - append to active\n",
-                       buf, buf->vb.i);
+                       buf, buf->vb.v4l2_buf.index);
        }
 }
 
-static void vbi_release(struct videobuf_queue *q, struct videobuf_buffer *vb)
+static int cx23885_start_streaming(struct vb2_queue *q, unsigned int count)
 {
-       struct cx23885_buffer *buf =
-               container_of(vb, struct cx23885_buffer, vb);
+       struct cx23885_dev *dev = q->drv_priv;
+       struct cx23885_dmaqueue *dmaq = &dev->vbiq;
+       struct cx23885_buffer *buf = list_entry(dmaq->active.next,
+                       struct cx23885_buffer, queue);
 
-       cx23885_free_buffer(q, buf);
+       cx23885_start_vbi_dma(dev, dmaq, buf);
+       return 0;
 }
 
-struct videobuf_queue_ops cx23885_vbi_qops = {
-       .buf_setup    = vbi_setup,
-       .buf_prepare  = vbi_prepare,
-       .buf_queue    = vbi_queue,
-       .buf_release  = vbi_release,
-};
+static void cx23885_stop_streaming(struct vb2_queue *q)
+{
+       struct cx23885_dev *dev = q->drv_priv;
+       struct cx23885_dmaqueue *dmaq = &dev->vbiq;
+       unsigned long flags;
 
-/* ------------------------------------------------------------------ */
-/*
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
+       cx_clear(VID_A_DMA_CTL, 0x22); /* FIFO and RISC enable */
+       spin_lock_irqsave(&dev->slock, flags);
+       while (!list_empty(&dmaq->active)) {
+               struct cx23885_buffer *buf = list_entry(dmaq->active.next,
+                       struct cx23885_buffer, queue);
+
+               list_del(&buf->queue);
+               vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR);
+       }
+       spin_unlock_irqrestore(&dev->slock, flags);
+}
+
+
+struct vb2_ops cx23885_vbi_qops = {
+       .queue_setup    = queue_setup,
+       .buf_prepare  = buffer_prepare,
+       .buf_finish = buffer_finish,
+       .buf_queue    = buffer_queue,
+       .wait_prepare = vb2_ops_wait_prepare,
+       .wait_finish = vb2_ops_wait_finish,
+       .start_streaming = cx23885_start_streaming,
+       .stop_streaming = cx23885_stop_streaming,
+};
index 91e4cb457296ccdef2b1b777e6f8594341a71a1d..682a4f95df6bd09f062d0c58e7ac3185b158db6f 100644 (file)
  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  *
  *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
 #include <linux/init.h>
@@ -35,6 +31,7 @@
 #include "cx23885-video.h"
 #include <media/v4l2-common.h>
 #include <media/v4l2-ioctl.h>
+#include <media/v4l2-event.h>
 #include "cx23885-ioctl.h"
 #include "tuner-xc2028.h"
 
@@ -48,15 +45,12 @@ MODULE_LICENSE("GPL");
 
 static unsigned int video_nr[] = {[0 ... (CX23885_MAXBOARDS - 1)] = UNSET };
 static unsigned int vbi_nr[]   = {[0 ... (CX23885_MAXBOARDS - 1)] = UNSET };
-static unsigned int radio_nr[] = {[0 ... (CX23885_MAXBOARDS - 1)] = UNSET };
 
 module_param_array(video_nr, int, NULL, 0444);
 module_param_array(vbi_nr,   int, NULL, 0444);
-module_param_array(radio_nr, int, NULL, 0444);
 
 MODULE_PARM_DESC(video_nr, "video device numbers");
 MODULE_PARM_DESC(vbi_nr, "vbi device numbers");
-MODULE_PARM_DESC(radio_nr, "radio device numbers");
 
 static unsigned int video_debug;
 module_param(video_debug, int, 0644);
@@ -79,77 +73,14 @@ MODULE_PARM_DESC(vid_limit, "capture memory limit in megabytes");
 /* static data                                                         */
 
 #define FORMAT_FLAGS_PACKED       0x01
-#if 0
-static struct cx23885_fmt formats[] = {
-       {
-               .name     = "8 bpp, gray",
-               .fourcc   = V4L2_PIX_FMT_GREY,
-               .depth    = 8,
-               .flags    = FORMAT_FLAGS_PACKED,
-       }, {
-               .name     = "15 bpp RGB, le",
-               .fourcc   = V4L2_PIX_FMT_RGB555,
-               .depth    = 16,
-               .flags    = FORMAT_FLAGS_PACKED,
-       }, {
-               .name     = "15 bpp RGB, be",
-               .fourcc   = V4L2_PIX_FMT_RGB555X,
-               .depth    = 16,
-               .flags    = FORMAT_FLAGS_PACKED,
-       }, {
-               .name     = "16 bpp RGB, le",
-               .fourcc   = V4L2_PIX_FMT_RGB565,
-               .depth    = 16,
-               .flags    = FORMAT_FLAGS_PACKED,
-       }, {
-               .name     = "16 bpp RGB, be",
-               .fourcc   = V4L2_PIX_FMT_RGB565X,
-               .depth    = 16,
-               .flags    = FORMAT_FLAGS_PACKED,
-       }, {
-               .name     = "24 bpp RGB, le",
-               .fourcc   = V4L2_PIX_FMT_BGR24,
-               .depth    = 24,
-               .flags    = FORMAT_FLAGS_PACKED,
-       }, {
-               .name     = "32 bpp RGB, le",
-               .fourcc   = V4L2_PIX_FMT_BGR32,
-               .depth    = 32,
-               .flags    = FORMAT_FLAGS_PACKED,
-       }, {
-               .name     = "32 bpp RGB, be",
-               .fourcc   = V4L2_PIX_FMT_RGB32,
-               .depth    = 32,
-               .flags    = FORMAT_FLAGS_PACKED,
-       }, {
-               .name     = "4:2:2, packed, YUYV",
-               .fourcc   = V4L2_PIX_FMT_YUYV,
-               .depth    = 16,
-               .flags    = FORMAT_FLAGS_PACKED,
-       }, {
-               .name     = "4:2:2, packed, UYVY",
-               .fourcc   = V4L2_PIX_FMT_UYVY,
-               .depth    = 16,
-               .flags    = FORMAT_FLAGS_PACKED,
-       },
-};
-#else
 static struct cx23885_fmt formats[] = {
        {
-#if 0
-               .name     = "4:2:2, packed, UYVY",
-               .fourcc   = V4L2_PIX_FMT_UYVY,
-               .depth    = 16,
-               .flags    = FORMAT_FLAGS_PACKED,
-       }, {
-#endif
                .name     = "4:2:2, packed, YUYV",
                .fourcc   = V4L2_PIX_FMT_YUYV,
                .depth    = 16,
                .flags    = FORMAT_FLAGS_PACKED,
        }
 };
-#endif
 
 static struct cx23885_fmt *format_by_fourcc(unsigned int fourcc)
 {
@@ -158,163 +89,27 @@ static struct cx23885_fmt *format_by_fourcc(unsigned int fourcc)
        for (i = 0; i < ARRAY_SIZE(formats); i++)
                if (formats[i].fourcc == fourcc)
                        return formats+i;
-
-       printk(KERN_ERR "%s(%c%c%c%c) NOT FOUND\n", __func__,
-               (fourcc & 0xff),
-               ((fourcc >> 8) & 0xff),
-               ((fourcc >> 16) & 0xff),
-               ((fourcc >> 24) & 0xff)
-               );
        return NULL;
 }
 
 /* ------------------------------------------------------------------- */
 
-static const struct v4l2_queryctrl no_ctl = {
-       .name  = "42",
-       .flags = V4L2_CTRL_FLAG_DISABLED,
-};
-
-static struct cx23885_ctrl cx23885_ctls[] = {
-       /* --- video --- */
-       {
-               .v = {
-                       .id            = V4L2_CID_BRIGHTNESS,
-                       .name          = "Brightness",
-                       .minimum       = 0x00,
-                       .maximum       = 0xff,
-                       .step          = 1,
-                       .default_value = 0x7f,
-                       .type          = V4L2_CTRL_TYPE_INTEGER,
-               },
-               .off                   = 128,
-               .reg                   = LUMA_CTRL,
-               .mask                  = 0x00ff,
-               .shift                 = 0,
-       }, {
-               .v = {
-                       .id            = V4L2_CID_CONTRAST,
-                       .name          = "Contrast",
-                       .minimum       = 0,
-                       .maximum       = 0x7f,
-                       .step          = 1,
-                       .default_value = 0x3f,
-                       .type          = V4L2_CTRL_TYPE_INTEGER,
-               },
-               .off                   = 0,
-               .reg                   = LUMA_CTRL,
-               .mask                  = 0xff00,
-               .shift                 = 8,
-       }, {
-               .v = {
-                       .id            = V4L2_CID_HUE,
-                       .name          = "Hue",
-                       .minimum       = -127,
-                       .maximum       = 128,
-                       .step          = 1,
-                       .default_value = 0x0,
-                       .type          = V4L2_CTRL_TYPE_INTEGER,
-               },
-               .off                   = 128,
-               .reg                   = CHROMA_CTRL,
-               .mask                  = 0xff0000,
-               .shift                 = 16,
-       }, {
-               /* strictly, this only describes only U saturation.
-                * V saturation is handled specially through code.
-                */
-               .v = {
-                       .id            = V4L2_CID_SATURATION,
-                       .name          = "Saturation",
-                       .minimum       = 0,
-                       .maximum       = 0x7f,
-                       .step          = 1,
-                       .default_value = 0x3f,
-                       .type          = V4L2_CTRL_TYPE_INTEGER,
-               },
-               .off                   = 0,
-               .reg                   = CHROMA_CTRL,
-               .mask                  = 0x00ff,
-               .shift                 = 0,
-       }, {
-       /* --- audio --- */
-               .v = {
-                       .id            = V4L2_CID_AUDIO_MUTE,
-                       .name          = "Mute",
-                       .minimum       = 0,
-                       .maximum       = 1,
-                       .default_value = 1,
-                       .type          = V4L2_CTRL_TYPE_BOOLEAN,
-               },
-               .reg                   = PATH1_CTL1,
-               .mask                  = (0x1f << 24),
-               .shift                 = 24,
-       }, {
-               .v = {
-                       .id            = V4L2_CID_AUDIO_VOLUME,
-                       .name          = "Volume",
-                       .minimum       = 0,
-                       .maximum       = 65535,
-                       .step          = 65535 / 100,
-                       .default_value = 65535,
-                       .type          = V4L2_CTRL_TYPE_INTEGER,
-               },
-               .reg                   = PATH1_VOL_CTL,
-               .mask                  = 0xff,
-               .shift                 = 0,
-       }
-};
-static const int CX23885_CTLS = ARRAY_SIZE(cx23885_ctls);
-
-/* Must be sorted from low to high control ID! */
-static const u32 cx23885_user_ctrls[] = {
-       V4L2_CID_USER_CLASS,
-       V4L2_CID_BRIGHTNESS,
-       V4L2_CID_CONTRAST,
-       V4L2_CID_SATURATION,
-       V4L2_CID_HUE,
-       V4L2_CID_AUDIO_VOLUME,
-       V4L2_CID_AUDIO_MUTE,
-       0
-};
-
-static const u32 *ctrl_classes[] = {
-       cx23885_user_ctrls,
-       NULL
-};
-
 void cx23885_video_wakeup(struct cx23885_dev *dev,
        struct cx23885_dmaqueue *q, u32 count)
 {
        struct cx23885_buffer *buf;
-       int bc;
-
-       for (bc = 0;; bc++) {
-               if (list_empty(&q->active))
-                       break;
-               buf = list_entry(q->active.next,
-                                struct cx23885_buffer, vb.queue);
-
-               /* count comes from the hw and is is 16bit wide --
-                * this trick handles wrap-arounds correctly for
-                * up to 32767 buffers in flight... */
-               if ((s16) (count - buf->count) < 0)
-                       break;
-
-               v4l2_get_timestamp(&buf->vb.ts);
-               dprintk(2, "[%p/%d] wakeup reg=%d buf=%d\n", buf, buf->vb.i,
-                       count, buf->count);
-               buf->vb.state = VIDEOBUF_DONE;
-               list_del(&buf->vb.queue);
-               wake_up(&buf->vb.done);
-       }
+
        if (list_empty(&q->active))
-               del_timer(&q->timeout);
-       else
-               mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT);
-       if (bc != 1)
-               printk(KERN_ERR "%s: %d buffers handled (should be 1)\n",
-                       __func__, bc);
+               return;
+       buf = list_entry(q->active.next,
+                       struct cx23885_buffer, queue);
+
+       buf->vb.v4l2_buf.sequence = q->count++;
+       v4l2_get_timestamp(&buf->vb.v4l2_buf.timestamp);
+       dprintk(2, "[%p/%d] wakeup reg=%d buf=%d\n", buf, buf->vb.v4l2_buf.index,
+                       count, q->count);
+       list_del(&buf->queue);
+       vb2_buffer_done(&buf->vb, VB2_BUF_STATE_DONE);
 }
 
 int cx23885_set_tvnorm(struct cx23885_dev *dev, v4l2_std_id norm)
@@ -324,6 +119,12 @@ int cx23885_set_tvnorm(struct cx23885_dev *dev, v4l2_std_id norm)
                (unsigned int)norm,
                v4l2_norm_to_name(norm));
 
+       if (dev->tvnorm != norm) {
+               if (vb2_is_busy(&dev->vb2_vidq) || vb2_is_busy(&dev->vb2_vbiq) ||
+                   vb2_is_busy(&dev->vb2_mpegq))
+                       return -EBUSY;
+       }
+
        dev->tvnorm = norm;
 
        call_all(dev, video, s_std, norm);
@@ -345,79 +146,13 @@ static struct video_device *cx23885_vdev_init(struct cx23885_dev *dev,
        *vfd = *template;
        vfd->v4l2_dev = &dev->v4l2_dev;
        vfd->release = video_device_release;
+       vfd->lock = &dev->lock;
        snprintf(vfd->name, sizeof(vfd->name), "%s (%s)",
                 cx23885_boards[dev->board].name, type);
        video_set_drvdata(vfd, dev);
        return vfd;
 }
 
-static int cx23885_ctrl_query(struct v4l2_queryctrl *qctrl)
-{
-       int i;
-
-       if (qctrl->id < V4L2_CID_BASE ||
-           qctrl->id >= V4L2_CID_LASTP1)
-               return -EINVAL;
-       for (i = 0; i < CX23885_CTLS; i++)
-               if (cx23885_ctls[i].v.id == qctrl->id)
-                       break;
-       if (i == CX23885_CTLS) {
-               *qctrl = no_ctl;
-               return 0;
-       }
-       *qctrl = cx23885_ctls[i].v;
-       return 0;
-}
-
-/* ------------------------------------------------------------------- */
-/* resource management                                                 */
-
-static int res_get(struct cx23885_dev *dev, struct cx23885_fh *fh,
-       unsigned int bit)
-{
-       dprintk(1, "%s()\n", __func__);
-       if (fh->resources & bit)
-               /* have it already allocated */
-               return 1;
-
-       /* is it free? */
-       mutex_lock(&dev->lock);
-       if (dev->resources & bit) {
-               /* no, someone else uses it */
-               mutex_unlock(&dev->lock);
-               return 0;
-       }
-       /* it's free, grab it */
-       fh->resources  |= bit;
-       dev->resources |= bit;
-       dprintk(1, "res: get %d\n", bit);
-       mutex_unlock(&dev->lock);
-       return 1;
-}
-
-static int res_check(struct cx23885_fh *fh, unsigned int bit)
-{
-       return fh->resources & bit;
-}
-
-static int res_locked(struct cx23885_dev *dev, unsigned int bit)
-{
-       return dev->resources & bit;
-}
-
-static void res_free(struct cx23885_dev *dev, struct cx23885_fh *fh,
-       unsigned int bits)
-{
-       BUG_ON((fh->resources & bits) != bits);
-       dprintk(1, "%s()\n", __func__);
-
-       mutex_lock(&dev->lock);
-       fh->resources  &= ~bits;
-       dev->resources &= ~bits;
-       dprintk(1, "res: put %d\n", bits);
-       mutex_unlock(&dev->lock);
-}
-
 int cx23885_flatiron_write(struct cx23885_dev *dev, u8 reg, u8 data)
 {
        /* 8 bit registers, 8 bit values */
@@ -567,7 +302,7 @@ static int cx23885_start_video_dma(struct cx23885_dev *dev,
 
        /* reset counter */
        cx_write(VID_A_GPCNT_CTL, 3);
-       q->count = 1;
+       q->count = 0;
 
        /* enable irq */
        cx23885_irq_add_enable(dev, 0x01);
@@ -580,479 +315,206 @@ static int cx23885_start_video_dma(struct cx23885_dev *dev,
        return 0;
 }
 
-
-static int cx23885_restart_video_queue(struct cx23885_dev *dev,
-                              struct cx23885_dmaqueue *q)
-{
-       struct cx23885_buffer *buf, *prev;
-       struct list_head *item;
-       dprintk(1, "%s()\n", __func__);
-
-       if (!list_empty(&q->active)) {
-               buf = list_entry(q->active.next, struct cx23885_buffer,
-                       vb.queue);
-               dprintk(2, "restart_queue [%p/%d]: restart dma\n",
-                       buf, buf->vb.i);
-               cx23885_start_video_dma(dev, q, buf);
-               list_for_each(item, &q->active) {
-                       buf = list_entry(item, struct cx23885_buffer,
-                               vb.queue);
-                       buf->count    = q->count++;
-               }
-               mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT);
-               return 0;
-       }
-
-       prev = NULL;
-       for (;;) {
-               if (list_empty(&q->queued))
-                       return 0;
-               buf = list_entry(q->queued.next, struct cx23885_buffer,
-                       vb.queue);
-               if (NULL == prev) {
-                       list_move_tail(&buf->vb.queue, &q->active);
-                       cx23885_start_video_dma(dev, q, buf);
-                       buf->vb.state = VIDEOBUF_ACTIVE;
-                       buf->count    = q->count++;
-                       mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT);
-                       dprintk(2, "[%p/%d] restart_queue - first active\n",
-                               buf, buf->vb.i);
-
-               } else if (prev->vb.width  == buf->vb.width  &&
-                          prev->vb.height == buf->vb.height &&
-                          prev->fmt       == buf->fmt) {
-                       list_move_tail(&buf->vb.queue, &q->active);
-                       buf->vb.state = VIDEOBUF_ACTIVE;
-                       buf->count    = q->count++;
-                       prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma);
-                       prev->risc.jmp[2] = cpu_to_le32(0); /* Bits 63 - 32 */
-                       dprintk(2, "[%p/%d] restart_queue - move to active\n",
-                               buf, buf->vb.i);
-               } else {
-                       return 0;
-               }
-               prev = buf;
-       }
-}
-
-static int buffer_setup(struct videobuf_queue *q, unsigned int *count,
-       unsigned int *size)
+static int queue_setup(struct vb2_queue *q, const struct v4l2_format *fmt,
+                          unsigned int *num_buffers, unsigned int *num_planes,
+                          unsigned int sizes[], void *alloc_ctxs[])
 {
-       struct cx23885_fh *fh = q->priv_data;
+       struct cx23885_dev *dev = q->drv_priv;
 
-       *size = fh->fmt->depth*fh->width*fh->height >> 3;
-       if (0 == *count)
-               *count = 32;
-       if (*size * *count > vid_limit * 1024 * 1024)
-               *count = (vid_limit * 1024 * 1024) / *size;
+       *num_planes = 1;
+       sizes[0] = (dev->fmt->depth * dev->width * dev->height) >> 3;
        return 0;
 }
 
-static int buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,
-              enum v4l2_field field)
+static int buffer_prepare(struct vb2_buffer *vb)
 {
-       struct cx23885_fh *fh  = q->priv_data;
-       struct cx23885_dev *dev = fh->dev;
+       struct cx23885_dev *dev = vb->vb2_queue->drv_priv;
        struct cx23885_buffer *buf =
                container_of(vb, struct cx23885_buffer, vb);
-       int rc, init_buffer = 0;
        u32 line0_offset, line1_offset;
-       struct videobuf_dmabuf *dma = videobuf_to_dma(&buf->vb);
+       struct sg_table *sgt = vb2_dma_sg_plane_desc(vb, 0);
        int field_tff;
+       int ret;
 
-       BUG_ON(NULL == fh->fmt);
-       if (fh->width  < 48 || fh->width  > norm_maxw(dev->tvnorm) ||
-           fh->height < 32 || fh->height > norm_maxh(dev->tvnorm))
-               return -EINVAL;
-       buf->vb.size = (fh->width * fh->height * fh->fmt->depth) >> 3;
-       if (0 != buf->vb.baddr  &&  buf->vb.bsize < buf->vb.size)
+       buf->bpl = (dev->width * dev->fmt->depth) >> 3;
+
+       if (vb2_plane_size(vb, 0) < dev->height * buf->bpl)
                return -EINVAL;
+       vb2_set_plane_payload(vb, 0, dev->height * buf->bpl);
 
-       if (buf->fmt       != fh->fmt    ||
-           buf->vb.width  != fh->width  ||
-           buf->vb.height != fh->height ||
-           buf->vb.field  != field) {
-               buf->fmt       = fh->fmt;
-               buf->vb.width  = fh->width;
-               buf->vb.height = fh->height;
-               buf->vb.field  = field;
-               init_buffer = 1;
-       }
+       ret = dma_map_sg(&dev->pci->dev, sgt->sgl, sgt->nents, DMA_FROM_DEVICE);
+       if (!ret)
+               return -EIO;
 
-       if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
-               init_buffer = 1;
-               rc = videobuf_iolock(q, &buf->vb, NULL);
-               if (0 != rc)
-                       goto fail;
-       }
+       switch (dev->field) {
+       case V4L2_FIELD_TOP:
+               cx23885_risc_buffer(dev->pci, &buf->risc,
+                               sgt->sgl, 0, UNSET,
+                               buf->bpl, 0, dev->height);
+               break;
+       case V4L2_FIELD_BOTTOM:
+               cx23885_risc_buffer(dev->pci, &buf->risc,
+                               sgt->sgl, UNSET, 0,
+                               buf->bpl, 0, dev->height);
+               break;
+       case V4L2_FIELD_INTERLACED:
+               if (dev->tvnorm & V4L2_STD_525_60)
+                       /* NTSC or  */
+                       field_tff = 1;
+               else
+                       field_tff = 0;
+
+               if (cx23885_boards[dev->board].force_bff)
+                       /* PAL / SECAM OR 888 in NTSC MODE */
+                       field_tff = 0;
 
-       if (init_buffer) {
-               buf->bpl = buf->vb.width * buf->fmt->depth >> 3;
-               switch (buf->vb.field) {
-               case V4L2_FIELD_TOP:
-                       cx23885_risc_buffer(dev->pci, &buf->risc,
-                                        dma->sglist, 0, UNSET,
-                                        buf->bpl, 0, buf->vb.height);
-                       break;
-               case V4L2_FIELD_BOTTOM:
-                       cx23885_risc_buffer(dev->pci, &buf->risc,
-                                        dma->sglist, UNSET, 0,
-                                        buf->bpl, 0, buf->vb.height);
-                       break;
-               case V4L2_FIELD_INTERLACED:
-                       if (dev->tvnorm & V4L2_STD_NTSC)
-                               /* NTSC or  */
-                               field_tff = 1;
-                       else
-                               field_tff = 0;
-
-                       if (cx23885_boards[dev->board].force_bff)
-                               /* PAL / SECAM OR 888 in NTSC MODE */
-                               field_tff = 0;
-
-                       if (field_tff) {
-                               /* cx25840 transmits NTSC bottom field first */
-                               dprintk(1, "%s() Creating TFF/NTSC risc\n",
+               if (field_tff) {
+                       /* cx25840 transmits NTSC bottom field first */
+                       dprintk(1, "%s() Creating TFF/NTSC risc\n",
                                        __func__);
-                               line0_offset = buf->bpl;
-                               line1_offset = 0;
-                       } else {
-                               /* All other formats are top field first */
-                               dprintk(1, "%s() Creating BFF/PAL/SECAM risc\n",
+                       line0_offset = buf->bpl;
+                       line1_offset = 0;
+               } else {
+                       /* All other formats are top field first */
+                       dprintk(1, "%s() Creating BFF/PAL/SECAM risc\n",
                                        __func__);
-                               line0_offset = 0;
-                               line1_offset = buf->bpl;
-                       }
-                       cx23885_risc_buffer(dev->pci, &buf->risc,
-                                       dma->sglist, line0_offset,
-                                       line1_offset,
-                                       buf->bpl, buf->bpl,
-                                       buf->vb.height >> 1);
-                       break;
-               case V4L2_FIELD_SEQ_TB:
-                       cx23885_risc_buffer(dev->pci, &buf->risc,
-                                        dma->sglist,
-                                        0, buf->bpl * (buf->vb.height >> 1),
-                                        buf->bpl, 0,
-                                        buf->vb.height >> 1);
-                       break;
-               case V4L2_FIELD_SEQ_BT:
-                       cx23885_risc_buffer(dev->pci, &buf->risc,
-                                        dma->sglist,
-                                        buf->bpl * (buf->vb.height >> 1), 0,
-                                        buf->bpl, 0,
-                                        buf->vb.height >> 1);
-                       break;
-               default:
-                       BUG();
+                       line0_offset = 0;
+                       line1_offset = buf->bpl;
                }
+               cx23885_risc_buffer(dev->pci, &buf->risc,
+                               sgt->sgl, line0_offset,
+                               line1_offset,
+                               buf->bpl, buf->bpl,
+                               dev->height >> 1);
+               break;
+       case V4L2_FIELD_SEQ_TB:
+               cx23885_risc_buffer(dev->pci, &buf->risc,
+                               sgt->sgl,
+                               0, buf->bpl * (dev->height >> 1),
+                               buf->bpl, 0,
+                               dev->height >> 1);
+               break;
+       case V4L2_FIELD_SEQ_BT:
+               cx23885_risc_buffer(dev->pci, &buf->risc,
+                               sgt->sgl,
+                               buf->bpl * (dev->height >> 1), 0,
+                               buf->bpl, 0,
+                               dev->height >> 1);
+               break;
+       default:
+               BUG();
        }
-       dprintk(2, "[%p/%d] buffer_prep - %dx%d %dbpp \"%s\" - dma=0x%08lx\n",
-               buf, buf->vb.i,
-               fh->width, fh->height, fh->fmt->depth, fh->fmt->name,
+       dprintk(2, "[%p/%d] buffer_init - %dx%d %dbpp \"%s\" - dma=0x%08lx\n",
+               buf, buf->vb.v4l2_buf.index,
+               dev->width, dev->height, dev->fmt->depth, dev->fmt->name,
                (unsigned long)buf->risc.dma);
-
-       buf->vb.state = VIDEOBUF_PREPARED;
        return 0;
+}
+
+static void buffer_finish(struct vb2_buffer *vb)
+{
+       struct cx23885_dev *dev = vb->vb2_queue->drv_priv;
+       struct cx23885_buffer *buf = container_of(vb,
+               struct cx23885_buffer, vb);
+       struct sg_table *sgt = vb2_dma_sg_plane_desc(vb, 0);
+
+       cx23885_free_buffer(vb->vb2_queue->drv_priv, buf);
 
- fail:
-       cx23885_free_buffer(q, buf);
-       return rc;
+       dma_unmap_sg(&dev->pci->dev, sgt->sgl, sgt->nents, DMA_FROM_DEVICE);
 }
 
-static void buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
+/*
+ * The risc program for each buffer works as follows: it starts with a simple
+ * 'JUMP to addr + 12', which is effectively a NOP. Then the code to DMA the
+ * buffer follows and at the end we have a JUMP back to the start + 12 (skipping
+ * the initial JUMP).
+ *
+ * This is the risc program of the first buffer to be queued if the active list
+ * is empty and it just keeps DMAing this buffer without generating any
+ * interrupts.
+ *
+ * If a new buffer is added then the initial JUMP in the code for that buffer
+ * will generate an interrupt which signals that the previous buffer has been
+ * DMAed successfully and that it can be returned to userspace.
+ *
+ * It also sets the final jump of the previous buffer to the start of the new
+ * buffer, thus chaining the new buffer into the DMA chain. This is a single
+ * atomic u32 write, so there is no race condition.
+ *
+ * The end-result of all this that you only get an interrupt when a buffer
+ * is ready, so the control flow is very easy.
+ */
+static void buffer_queue(struct vb2_buffer *vb)
 {
+       struct cx23885_dev *dev = vb->vb2_queue->drv_priv;
        struct cx23885_buffer   *buf = container_of(vb,
                struct cx23885_buffer, vb);
        struct cx23885_buffer   *prev;
-       struct cx23885_fh       *fh   = vq->priv_data;
-       struct cx23885_dev      *dev  = fh->dev;
        struct cx23885_dmaqueue *q    = &dev->vidq;
+       unsigned long flags;
 
-       /* add jump to stopper */
-       buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP | RISC_IRQ1 | RISC_CNT_INC);
-       buf->risc.jmp[1] = cpu_to_le32(q->stopper.dma);
+       /* add jump to start */
+       buf->risc.cpu[1] = cpu_to_le32(buf->risc.dma + 12);
+       buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP | RISC_CNT_INC);
+       buf->risc.jmp[1] = cpu_to_le32(buf->risc.dma + 12);
        buf->risc.jmp[2] = cpu_to_le32(0); /* bits 63-32 */
 
-       if (!list_empty(&q->queued)) {
-               list_add_tail(&buf->vb.queue, &q->queued);
-               buf->vb.state = VIDEOBUF_QUEUED;
-               dprintk(2, "[%p/%d] buffer_queue - append to queued\n",
-                       buf, buf->vb.i);
-
-       } else if (list_empty(&q->active)) {
-               list_add_tail(&buf->vb.queue, &q->active);
-               cx23885_start_video_dma(dev, q, buf);
-               buf->vb.state = VIDEOBUF_ACTIVE;
-               buf->count    = q->count++;
-               mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT);
+       spin_lock_irqsave(&dev->slock, flags);
+       if (list_empty(&q->active)) {
+               list_add_tail(&buf->queue, &q->active);
                dprintk(2, "[%p/%d] buffer_queue - first active\n",
-                       buf, buf->vb.i);
-
+                       buf, buf->vb.v4l2_buf.index);
        } else {
+               buf->risc.cpu[0] |= cpu_to_le32(RISC_IRQ1);
                prev = list_entry(q->active.prev, struct cx23885_buffer,
-                       vb.queue);
-               if (prev->vb.width  == buf->vb.width  &&
-                   prev->vb.height == buf->vb.height &&
-                   prev->fmt       == buf->fmt) {
-                       list_add_tail(&buf->vb.queue, &q->active);
-                       buf->vb.state = VIDEOBUF_ACTIVE;
-                       buf->count    = q->count++;
-                       prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma);
-                       /* 64 bit bits 63-32 */
-                       prev->risc.jmp[2] = cpu_to_le32(0);
-                       dprintk(2, "[%p/%d] buffer_queue - append to active\n",
-                               buf, buf->vb.i);
-
-               } else {
-                       list_add_tail(&buf->vb.queue, &q->queued);
-                       buf->vb.state = VIDEOBUF_QUEUED;
-                       dprintk(2, "[%p/%d] buffer_queue - first queued\n",
-                               buf, buf->vb.i);
-               }
-       }
-}
-
-static void buffer_release(struct videobuf_queue *q,
-       struct videobuf_buffer *vb)
-{
-       struct cx23885_buffer *buf = container_of(vb,
-               struct cx23885_buffer, vb);
-
-       cx23885_free_buffer(q, buf);
-}
-
-static struct videobuf_queue_ops cx23885_video_qops = {
-       .buf_setup    = buffer_setup,
-       .buf_prepare  = buffer_prepare,
-       .buf_queue    = buffer_queue,
-       .buf_release  = buffer_release,
-};
-
-static struct videobuf_queue *get_queue(struct cx23885_fh *fh)
-{
-       switch (fh->type) {
-       case V4L2_BUF_TYPE_VIDEO_CAPTURE:
-               return &fh->vidq;
-       case V4L2_BUF_TYPE_VBI_CAPTURE:
-               return &fh->vbiq;
-       default:
-               BUG();
-               return NULL;
-       }
-}
-
-static int get_resource(struct cx23885_fh *fh)
-{
-       switch (fh->type) {
-       case V4L2_BUF_TYPE_VIDEO_CAPTURE:
-               return RESOURCE_VIDEO;
-       case V4L2_BUF_TYPE_VBI_CAPTURE:
-               return RESOURCE_VBI;
-       default:
-               BUG();
-               return 0;
+                       queue);
+               list_add_tail(&buf->queue, &q->active);
+               prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma);
+               dprintk(2, "[%p/%d] buffer_queue - append to active\n",
+                               buf, buf->vb.v4l2_buf.index);
        }
+       spin_unlock_irqrestore(&dev->slock, flags);
 }
 
-static int video_open(struct file *file)
+static int cx23885_start_streaming(struct vb2_queue *q, unsigned int count)
 {
-       struct video_device *vdev = video_devdata(file);
-       struct cx23885_dev *dev = video_drvdata(file);
-       struct cx23885_fh *fh;
-       enum v4l2_buf_type type = 0;
-       int radio = 0;
-
-       switch (vdev->vfl_type) {
-       case VFL_TYPE_GRABBER:
-               type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-               break;
-       case VFL_TYPE_VBI:
-               type = V4L2_BUF_TYPE_VBI_CAPTURE;
-               break;
-       case VFL_TYPE_RADIO:
-               radio = 1;
-               break;
-       }
-
-       dprintk(1, "open dev=%s radio=%d type=%s\n",
-               video_device_node_name(vdev), radio, v4l2_type_names[type]);
-
-       /* allocate + initialize per filehandle data */
-       fh = kzalloc(sizeof(*fh), GFP_KERNEL);
-       if (NULL == fh)
-               return -ENOMEM;
-
-       file->private_data = fh;
-       fh->dev      = dev;
-       fh->radio    = radio;
-       fh->type     = type;
-       fh->width    = 320;
-       fh->height   = 240;
-       fh->fmt      = format_by_fourcc(V4L2_PIX_FMT_YUYV);
-
-       videobuf_queue_sg_init(&fh->vidq, &cx23885_video_qops,
-                           &dev->pci->dev, &dev->slock,
-                           V4L2_BUF_TYPE_VIDEO_CAPTURE,
-                           V4L2_FIELD_INTERLACED,
-                           sizeof(struct cx23885_buffer),
-                           fh, NULL);
-
-       videobuf_queue_sg_init(&fh->vbiq, &cx23885_vbi_qops,
-               &dev->pci->dev, &dev->slock,
-               V4L2_BUF_TYPE_VBI_CAPTURE,
-               V4L2_FIELD_SEQ_TB,
-               sizeof(struct cx23885_buffer),
-               fh, NULL);
-
-
-       dprintk(1, "post videobuf_queue_init()\n");
+       struct cx23885_dev *dev = q->drv_priv;
+       struct cx23885_dmaqueue *dmaq = &dev->vidq;
+       struct cx23885_buffer *buf = list_entry(dmaq->active.next,
+                       struct cx23885_buffer, queue);
 
+       cx23885_start_video_dma(dev, dmaq, buf);
        return 0;
 }
 
-static ssize_t video_read(struct file *file, char __user *data,
-       size_t count, loff_t *ppos)
+static void cx23885_stop_streaming(struct vb2_queue *q)
 {
-       struct cx23885_fh *fh = file->private_data;
-
-       switch (fh->type) {
-       case V4L2_BUF_TYPE_VIDEO_CAPTURE:
-               if (res_locked(fh->dev, RESOURCE_VIDEO))
-                       return -EBUSY;
-               return videobuf_read_one(&fh->vidq, data, count, ppos,
-                                        file->f_flags & O_NONBLOCK);
-       case V4L2_BUF_TYPE_VBI_CAPTURE:
-               if (!res_get(fh->dev, fh, RESOURCE_VBI))
-                       return -EBUSY;
-               return videobuf_read_stream(&fh->vbiq, data, count, ppos, 1,
-                                           file->f_flags & O_NONBLOCK);
-       default:
-               BUG();
-               return 0;
-       }
-}
-
-static unsigned int video_poll(struct file *file,
-       struct poll_table_struct *wait)
-{
-       struct cx23885_fh *fh = file->private_data;
-       struct cx23885_buffer *buf;
-       unsigned int rc = POLLERR;
-
-       if (V4L2_BUF_TYPE_VBI_CAPTURE == fh->type) {
-               if (!res_get(fh->dev, fh, RESOURCE_VBI))
-                       return POLLERR;
-               return videobuf_poll_stream(file, &fh->vbiq, wait);
-       }
-
-       mutex_lock(&fh->vidq.vb_lock);
-       if (res_check(fh, RESOURCE_VIDEO)) {
-               /* streaming capture */
-               if (list_empty(&fh->vidq.stream))
-                       goto done;
-               buf = list_entry(fh->vidq.stream.next,
-                       struct cx23885_buffer, vb.stream);
-       } else {
-               /* read() capture */
-               buf = (struct cx23885_buffer *)fh->vidq.read_buf;
-               if (NULL == buf)
-                       goto done;
-       }
-       poll_wait(file, &buf->vb.done, wait);
-       if (buf->vb.state == VIDEOBUF_DONE ||
-           buf->vb.state == VIDEOBUF_ERROR)
-               rc =  POLLIN|POLLRDNORM;
-       else
-               rc = 0;
-done:
-       mutex_unlock(&fh->vidq.vb_lock);
-       return rc;
-}
-
-static int video_release(struct file *file)
-{
-       struct cx23885_fh *fh = file->private_data;
-       struct cx23885_dev *dev = fh->dev;
-
-       /* turn off overlay */
-       if (res_check(fh, RESOURCE_OVERLAY)) {
-               /* FIXME */
-               res_free(dev, fh, RESOURCE_OVERLAY);
-       }
+       struct cx23885_dev *dev = q->drv_priv;
+       struct cx23885_dmaqueue *dmaq = &dev->vidq;
+       unsigned long flags;
 
-       /* stop video capture */
-       if (res_check(fh, RESOURCE_VIDEO)) {
-               videobuf_queue_cancel(&fh->vidq);
-               res_free(dev, fh, RESOURCE_VIDEO);
-       }
-       if (fh->vidq.read_buf) {
-               buffer_release(&fh->vidq, fh->vidq.read_buf);
-               kfree(fh->vidq.read_buf);
-       }
+       cx_clear(VID_A_DMA_CTL, 0x11);
+       spin_lock_irqsave(&dev->slock, flags);
+       while (!list_empty(&dmaq->active)) {
+               struct cx23885_buffer *buf = list_entry(dmaq->active.next,
+                       struct cx23885_buffer, queue);
 
-       /* stop vbi capture */
-       if (res_check(fh, RESOURCE_VBI)) {
-               if (fh->vbiq.streaming)
-                       videobuf_streamoff(&fh->vbiq);
-               if (fh->vbiq.reading)
-                       videobuf_read_stop(&fh->vbiq);
-               res_free(dev, fh, RESOURCE_VBI);
+               list_del(&buf->queue);
+               vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR);
        }
-
-       videobuf_mmap_free(&fh->vidq);
-       videobuf_mmap_free(&fh->vbiq);
-
-       file->private_data = NULL;
-       kfree(fh);
-
-       /* We are not putting the tuner to sleep here on exit, because
-        * we want to use the mpeg encoder in another session to capture
-        * tuner video. Closing this will result in no video to the encoder.
-        */
-
-       return 0;
-}
-
-static int video_mmap(struct file *file, struct vm_area_struct *vma)
-{
-       struct cx23885_fh *fh = file->private_data;
-
-       return videobuf_mmap_mapper(get_queue(fh), vma);
-}
-
-/* ------------------------------------------------------------------ */
-/* VIDEO CTRL IOCTLS                                                  */
-
-int cx23885_get_control(struct cx23885_dev *dev,
-       struct v4l2_control *ctl)
-{
-       dprintk(1, "%s() calling cx25840(VIDIOC_G_CTRL)\n", __func__);
-       call_all(dev, core, g_ctrl, ctl);
-       return 0;
-}
-
-int cx23885_set_control(struct cx23885_dev *dev,
-       struct v4l2_control *ctl)
-{
-       dprintk(1, "%s() calling cx25840(VIDIOC_S_CTRL)\n", __func__);
-       call_all(dev, core, s_ctrl, ctl);
-
-       return 0;
+       spin_unlock_irqrestore(&dev->slock, flags);
 }
 
-static void init_controls(struct cx23885_dev *dev)
-{
-       struct v4l2_control ctrl;
-       int i;
-
-       for (i = 0; i < CX23885_CTLS; i++) {
-               ctrl.id = cx23885_ctls[i].v.id;
-               ctrl.value = cx23885_ctls[i].v.default_value;
-
-               cx23885_set_control(dev, &ctrl);
-       }
-}
+static struct vb2_ops cx23885_video_qops = {
+       .queue_setup    = queue_setup,
+       .buf_prepare  = buffer_prepare,
+       .buf_finish = buffer_finish,
+       .buf_queue    = buffer_queue,
+       .wait_prepare = vb2_ops_wait_prepare,
+       .wait_finish = vb2_ops_wait_finish,
+       .start_streaming = cx23885_start_streaming,
+       .stop_streaming = cx23885_stop_streaming,
+};
 
 /* ------------------------------------------------------------------ */
 /* VIDEO IOCTLS                                                       */
@@ -1060,16 +522,17 @@ static void init_controls(struct cx23885_dev *dev)
 static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
        struct v4l2_format *f)
 {
-       struct cx23885_fh *fh   = priv;
+       struct cx23885_dev *dev = video_drvdata(file);
 
-       f->fmt.pix.width        = fh->width;
-       f->fmt.pix.height       = fh->height;
-       f->fmt.pix.field        = fh->vidq.field;
-       f->fmt.pix.pixelformat  = fh->fmt->fourcc;
+       f->fmt.pix.width        = dev->width;
+       f->fmt.pix.height       = dev->height;
+       f->fmt.pix.field        = dev->field;
+       f->fmt.pix.pixelformat  = dev->fmt->fourcc;
        f->fmt.pix.bytesperline =
-               (f->fmt.pix.width * fh->fmt->depth) >> 3;
+               (f->fmt.pix.width * dev->fmt->depth) >> 3;
        f->fmt.pix.sizeimage =
                f->fmt.pix.height * f->fmt.pix.bytesperline;
+       f->fmt.pix.colorspace   = V4L2_COLORSPACE_SMPTE170M;
 
        return 0;
 }
@@ -1077,7 +540,7 @@ static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
 static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
        struct v4l2_format *f)
 {
-       struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev;
+       struct cx23885_dev *dev = video_drvdata(file);
        struct cx23885_fmt *fmt;
        enum v4l2_field   field;
        unsigned int      maxw, maxh;
@@ -1102,9 +565,12 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
                maxh = maxh / 2;
                break;
        case V4L2_FIELD_INTERLACED:
+       case V4L2_FIELD_SEQ_TB:
+       case V4L2_FIELD_SEQ_BT:
                break;
        default:
-               return -EINVAL;
+               field = V4L2_FIELD_INTERLACED;
+               break;
        }
 
        f->fmt.pix.field = field;
@@ -1114,6 +580,7 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
                (f->fmt.pix.width * fmt->depth) >> 3;
        f->fmt.pix.sizeimage =
                f->fmt.pix.height * f->fmt.pix.bytesperline;
+       f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
 
        return 0;
 }
@@ -1121,8 +588,7 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
 static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
        struct v4l2_format *f)
 {
-       struct cx23885_fh *fh = priv;
-       struct cx23885_dev *dev  = ((struct cx23885_fh *)priv)->dev;
+       struct cx23885_dev *dev = video_drvdata(file);
        struct v4l2_mbus_framefmt mbus_fmt;
        int err;
 
@@ -1131,34 +597,44 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
 
        if (0 != err)
                return err;
-       fh->fmt        = format_by_fourcc(f->fmt.pix.pixelformat);
-       fh->width      = f->fmt.pix.width;
-       fh->height     = f->fmt.pix.height;
-       fh->vidq.field = f->fmt.pix.field;
+
+       if (vb2_is_busy(&dev->vb2_vidq) || vb2_is_busy(&dev->vb2_vbiq) ||
+           vb2_is_busy(&dev->vb2_mpegq))
+               return -EBUSY;
+
+       dev->fmt        = format_by_fourcc(f->fmt.pix.pixelformat);
+       dev->width      = f->fmt.pix.width;
+       dev->height     = f->fmt.pix.height;
+       dev->field      = f->fmt.pix.field;
        dprintk(2, "%s() width=%d height=%d field=%d\n", __func__,
-               fh->width, fh->height, fh->vidq.field);
+               dev->width, dev->height, dev->field);
        v4l2_fill_mbus_format(&mbus_fmt, &f->fmt.pix, V4L2_MBUS_FMT_FIXED);
        call_all(dev, video, s_mbus_fmt, &mbus_fmt);
        v4l2_fill_pix_format(&f->fmt.pix, &mbus_fmt);
+       /* s_mbus_fmt overwrites f->fmt.pix.field, restore it */
+       f->fmt.pix.field = dev->field;
        return 0;
 }
 
 static int vidioc_querycap(struct file *file, void  *priv,
        struct v4l2_capability *cap)
 {
-       struct cx23885_dev *dev  = ((struct cx23885_fh *)priv)->dev;
+       struct cx23885_dev *dev = video_drvdata(file);
+       struct video_device *vdev = video_devdata(file);
 
        strcpy(cap->driver, "cx23885");
        strlcpy(cap->card, cx23885_boards[dev->board].name,
                sizeof(cap->card));
        sprintf(cap->bus_info, "PCIe:%s", pci_name(dev->pci));
-       cap->capabilities =
-               V4L2_CAP_VIDEO_CAPTURE |
-               V4L2_CAP_READWRITE     |
-               V4L2_CAP_STREAMING     |
-               V4L2_CAP_VBI_CAPTURE;
+       cap->device_caps = V4L2_CAP_READWRITE | V4L2_CAP_STREAMING | V4L2_CAP_AUDIO;
        if (dev->tuner_type != TUNER_ABSENT)
-               cap->capabilities |= V4L2_CAP_TUNER;
+               cap->device_caps |= V4L2_CAP_TUNER;
+       if (vdev->vfl_type == VFL_TYPE_VBI)
+               cap->device_caps |= V4L2_CAP_VBI_CAPTURE;
+       else
+               cap->device_caps |= V4L2_CAP_VIDEO_CAPTURE;
+       cap->capabilities = cap->device_caps | V4L2_CAP_VBI_CAPTURE |
+               V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_DEVICE_CAPS;
        return 0;
 }
 
@@ -1175,85 +651,9 @@ static int vidioc_enum_fmt_vid_cap(struct file *file, void  *priv,
        return 0;
 }
 
-static int vidioc_reqbufs(struct file *file, void *priv,
-       struct v4l2_requestbuffers *p)
-{
-       struct cx23885_fh *fh = priv;
-       return videobuf_reqbufs(get_queue(fh), p);
-}
-
-static int vidioc_querybuf(struct file *file, void *priv,
-       struct v4l2_buffer *p)
-{
-       struct cx23885_fh *fh = priv;
-       return videobuf_querybuf(get_queue(fh), p);
-}
-
-static int vidioc_qbuf(struct file *file, void *priv,
-       struct v4l2_buffer *p)
-{
-       struct cx23885_fh *fh = priv;
-       return videobuf_qbuf(get_queue(fh), p);
-}
-
-static int vidioc_dqbuf(struct file *file, void *priv,
-       struct v4l2_buffer *p)
-{
-       struct cx23885_fh *fh = priv;
-       return videobuf_dqbuf(get_queue(fh), p,
-                               file->f_flags & O_NONBLOCK);
-}
-
-static int vidioc_streamon(struct file *file, void *priv,
-       enum v4l2_buf_type i)
-{
-       struct cx23885_fh *fh = priv;
-       struct cx23885_dev *dev = fh->dev;
-       dprintk(1, "%s()\n", __func__);
-
-       if ((fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) &&
-               (fh->type != V4L2_BUF_TYPE_VBI_CAPTURE))
-               return -EINVAL;
-       if (unlikely(i != fh->type))
-               return -EINVAL;
-
-       if (unlikely(!res_get(dev, fh, get_resource(fh))))
-               return -EBUSY;
-
-       /* Don't start VBI streaming unless vida streaming
-        * has already started.
-        */
-       if ((fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) &&
-               ((cx_read(VID_A_DMA_CTL) & 0x11) == 0))
-               return -EINVAL;
-
-       return videobuf_streamon(get_queue(fh));
-}
-
-static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
-{
-       struct cx23885_fh *fh = priv;
-       struct cx23885_dev *dev = fh->dev;
-       int err, res;
-       dprintk(1, "%s()\n", __func__);
-
-       if ((fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) &&
-               (fh->type != V4L2_BUF_TYPE_VBI_CAPTURE))
-               return -EINVAL;
-       if (i != fh->type)
-               return -EINVAL;
-
-       res = get_resource(fh);
-       err = videobuf_streamoff(get_queue(fh));
-       if (err < 0)
-               return err;
-       res_free(dev, fh, res);
-       return 0;
-}
-
 static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *id)
 {
-       struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev;
+       struct cx23885_dev *dev = video_drvdata(file);
        dprintk(1, "%s()\n", __func__);
 
        *id = dev->tvnorm;
@@ -1262,14 +662,10 @@ static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *id)
 
 static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id tvnorms)
 {
-       struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev;
+       struct cx23885_dev *dev = video_drvdata(file);
        dprintk(1, "%s()\n", __func__);
 
-       mutex_lock(&dev->lock);
-       cx23885_set_tvnorm(dev, tvnorms);
-       mutex_unlock(&dev->lock);
-
-       return 0;
+       return cx23885_set_tvnorm(dev, tvnorms);
 }
 
 int cx23885_enum_input(struct cx23885_dev *dev, struct v4l2_input *i)
@@ -1299,16 +695,16 @@ int cx23885_enum_input(struct cx23885_dev *dev, struct v4l2_input *i)
        i->index = n;
        i->type  = V4L2_INPUT_TYPE_CAMERA;
        strcpy(i->name, iname[INPUT(n)->type]);
+       i->std = CX23885_NORMS;
        if ((CX23885_VMUX_TELEVISION == INPUT(n)->type) ||
                (CX23885_VMUX_CABLE == INPUT(n)->type)) {
                i->type = V4L2_INPUT_TYPE_TUNER;
-               i->std = CX23885_NORMS;
+               i->audioset = 4;
+       } else {
+               /* Two selectable audio inputs for non-tv inputs */
+               i->audioset = 3;
        }
 
-       /* Two selectable audio inputs for non-tv inputs */
-       if (INPUT(n)->type != CX23885_VMUX_TELEVISION)
-               i->audioset = 0x3;
-
        if (dev->input == n) {
                /* enum'd input matches our configured input.
                 * Ask the video decoder to process the call
@@ -1324,14 +720,14 @@ int cx23885_enum_input(struct cx23885_dev *dev, struct v4l2_input *i)
 static int vidioc_enum_input(struct file *file, void *priv,
                                struct v4l2_input *i)
 {
-       struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev;
+       struct cx23885_dev *dev = video_drvdata(file);
        dprintk(1, "%s()\n", __func__);
        return cx23885_enum_input(dev, i);
 }
 
 int cx23885_get_input(struct file *file, void *priv, unsigned int *i)
 {
-       struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev;
+       struct cx23885_dev *dev = video_drvdata(file);
 
        *i = dev->input;
        dprintk(1, "%s() returns %d\n", __func__, *i);
@@ -1345,7 +741,7 @@ static int vidioc_g_input(struct file *file, void *priv, unsigned int *i)
 
 int cx23885_set_input(struct file *file, void *priv, unsigned int i)
 {
-       struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev;
+       struct cx23885_dev *dev = video_drvdata(file);
 
        dprintk(1, "%s(%d)\n", __func__, i);
 
@@ -1357,13 +753,11 @@ int cx23885_set_input(struct file *file, void *priv, unsigned int i)
        if (INPUT(i)->type == 0)
                return -EINVAL;
 
-       mutex_lock(&dev->lock);
        cx23885_video_mux(dev, i);
 
        /* By default establish the default audio input for the card also */
        /* Caller is free to use VIDIOC_S_AUDIO to override afterwards */
        cx23885_audio_mux(dev, i);
-       mutex_unlock(&dev->lock);
        return 0;
 }
 
@@ -1374,39 +768,32 @@ static int vidioc_s_input(struct file *file, void *priv, unsigned int i)
 
 static int vidioc_log_status(struct file *file, void *priv)
 {
-       struct cx23885_fh  *fh  = priv;
-       struct cx23885_dev *dev = fh->dev;
+       struct cx23885_dev *dev = video_drvdata(file);
 
-       printk(KERN_INFO
-               "%s/0: ============  START LOG STATUS  ============\n",
-               dev->name);
        call_all(dev, core, log_status);
-       printk(KERN_INFO
-               "%s/0: =============  END LOG STATUS  =============\n",
-               dev->name);
        return 0;
 }
 
 static int cx23885_query_audinput(struct file *file, void *priv,
        struct v4l2_audio *i)
 {
-       struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev;
+       struct cx23885_dev *dev = video_drvdata(file);
        static const char *iname[] = {
                [0] = "Baseband L/R 1",
                [1] = "Baseband L/R 2",
+               [2] = "TV",
        };
        unsigned int n;
        dprintk(1, "%s()\n", __func__);
 
        n = i->index;
-       if (n >= 2)
+       if (n >= 3)
                return -EINVAL;
 
        memset(i, 0, sizeof(*i));
        i->index = n;
        strcpy(i->name, iname[n]);
-       i->capability  = V4L2_AUDCAP_STEREO;
-       i->mode  = V4L2_AUDMODE_AVL;
+       i->capability = V4L2_AUDCAP_STEREO;
        return 0;
 
 }
@@ -1420,9 +807,13 @@ static int vidioc_enum_audinput(struct file *file, void *priv,
 static int vidioc_g_audinput(struct file *file, void *priv,
        struct v4l2_audio *i)
 {
-       struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev;
+       struct cx23885_dev *dev = video_drvdata(file);
 
-       i->index = dev->audinput;
+       if ((CX23885_VMUX_TELEVISION == INPUT(dev->input)->type) ||
+               (CX23885_VMUX_CABLE == INPUT(dev->input)->type))
+               i->index = 2;
+       else
+               i->index = dev->audinput;
        dprintk(1, "%s(input=%d)\n", __func__, i->index);
 
        return cx23885_query_audinput(file, priv, i);
@@ -1431,8 +822,13 @@ static int vidioc_g_audinput(struct file *file, void *priv,
 static int vidioc_s_audinput(struct file *file, void *priv,
        const struct v4l2_audio *i)
 {
-       struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev;
-       if (i->index >= 2)
+       struct cx23885_dev *dev = video_drvdata(file);
+
+       if ((CX23885_VMUX_TELEVISION == INPUT(dev->input)->type) ||
+               (CX23885_VMUX_CABLE == INPUT(dev->input)->type)) {
+               return i->index != 2 ? -EINVAL : 0;
+       }
+       if (i->index > 1)
                return -EINVAL;
 
        dprintk(1, "%s(%d)\n", __func__, i->index);
@@ -1445,35 +841,10 @@ static int vidioc_s_audinput(struct file *file, void *priv,
        return 0;
 }
 
-static int vidioc_queryctrl(struct file *file, void *priv,
-                               struct v4l2_queryctrl *qctrl)
-{
-       qctrl->id = v4l2_ctrl_next(ctrl_classes, qctrl->id);
-       if (unlikely(qctrl->id == 0))
-               return -EINVAL;
-       return cx23885_ctrl_query(qctrl);
-}
-
-static int vidioc_g_ctrl(struct file *file, void *priv,
-                               struct v4l2_control *ctl)
-{
-       struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev;
-
-       return cx23885_get_control(dev, ctl);
-}
-
-static int vidioc_s_ctrl(struct file *file, void *priv,
-                               struct v4l2_control *ctl)
-{
-       struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev;
-
-       return cx23885_set_control(dev, ctl);
-}
-
 static int vidioc_g_tuner(struct file *file, void *priv,
                                struct v4l2_tuner *t)
 {
-       struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev;
+       struct cx23885_dev *dev = video_drvdata(file);
 
        if (dev->tuner_type == TUNER_ABSENT)
                return -EINVAL;
@@ -1489,7 +860,7 @@ static int vidioc_g_tuner(struct file *file, void *priv,
 static int vidioc_s_tuner(struct file *file, void *priv,
                                const struct v4l2_tuner *t)
 {
-       struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev;
+       struct cx23885_dev *dev = video_drvdata(file);
 
        if (dev->tuner_type == TUNER_ABSENT)
                return -EINVAL;
@@ -1504,14 +875,12 @@ static int vidioc_s_tuner(struct file *file, void *priv,
 static int vidioc_g_frequency(struct file *file, void *priv,
                                struct v4l2_frequency *f)
 {
-       struct cx23885_fh *fh = priv;
-       struct cx23885_dev *dev = fh->dev;
+       struct cx23885_dev *dev = video_drvdata(file);
 
        if (dev->tuner_type == TUNER_ABSENT)
                return -EINVAL;
 
-       /* f->type = fh->radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV; */
-       f->type = fh->radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV;
+       f->type = V4L2_TUNER_ANALOG_TV;
        f->frequency = dev->freq;
 
        call_all(dev, tuner, g_frequency, f);
@@ -1521,20 +890,23 @@ static int vidioc_g_frequency(struct file *file, void *priv,
 
 static int cx23885_set_freq(struct cx23885_dev *dev, const struct v4l2_frequency *f)
 {
-       struct v4l2_control ctrl;
+       struct v4l2_ctrl *mute;
+       int old_mute_val = 1;
 
        if (dev->tuner_type == TUNER_ABSENT)
                return -EINVAL;
        if (unlikely(f->tuner != 0))
                return -EINVAL;
 
-       mutex_lock(&dev->lock);
        dev->freq = f->frequency;
 
        /* I need to mute audio here */
-       ctrl.id = V4L2_CID_AUDIO_MUTE;
-       ctrl.value = 1;
-       cx23885_set_control(dev, &ctrl);
+       mute = v4l2_ctrl_find(&dev->ctrl_handler, V4L2_CID_AUDIO_MUTE);
+       if (mute) {
+               old_mute_val = v4l2_ctrl_g_ctrl(mute);
+               if (!old_mute_val)
+                       v4l2_ctrl_s_ctrl(mute, 1);
+       }
 
        call_all(dev, tuner, s_frequency, f);
 
@@ -1542,10 +914,8 @@ static int cx23885_set_freq(struct cx23885_dev *dev, const struct v4l2_frequency
        msleep(100);
 
        /* I need to unmute audio here */
-       ctrl.value = 0;
-       cx23885_set_control(dev, &ctrl);
-
-       mutex_unlock(&dev->lock);
+       if (old_mute_val == 0)
+               v4l2_ctrl_s_ctrl(mute, old_mute_val);
 
        return 0;
 }
@@ -1553,8 +923,9 @@ static int cx23885_set_freq(struct cx23885_dev *dev, const struct v4l2_frequency
 static int cx23885_set_freq_via_ops(struct cx23885_dev *dev,
        const struct v4l2_frequency *f)
 {
-       struct v4l2_control ctrl;
-       struct videobuf_dvb_frontend *vfe;
+       struct v4l2_ctrl *mute;
+       int old_mute_val = 1;
+       struct vb2_dvb_frontend *vfe;
        struct dvb_frontend *fe;
 
        struct analog_parameters params = {
@@ -1564,21 +935,22 @@ static int cx23885_set_freq_via_ops(struct cx23885_dev *dev,
                .frequency = f->frequency
        };
 
-       mutex_lock(&dev->lock);
        dev->freq = f->frequency;
 
        /* I need to mute audio here */
-       ctrl.id = V4L2_CID_AUDIO_MUTE;
-       ctrl.value = 1;
-       cx23885_set_control(dev, &ctrl);
+       mute = v4l2_ctrl_find(&dev->ctrl_handler, V4L2_CID_AUDIO_MUTE);
+       if (mute) {
+               old_mute_val = v4l2_ctrl_g_ctrl(mute);
+               if (!old_mute_val)
+                       v4l2_ctrl_s_ctrl(mute, 1);
+       }
 
        /* If HVR1850 */
        dprintk(1, "%s() frequency=%d tuner=%d std=0x%llx\n", __func__,
                params.frequency, f->tuner, params.std);
 
-       vfe = videobuf_dvb_get_frontend(&dev->ts2.frontends, 1);
+       vfe = vb2_dvb_get_frontend(&dev->ts2.frontends, 1);
        if (!vfe) {
-               mutex_unlock(&dev->lock);
                return -EINVAL;
        }
 
@@ -1600,10 +972,8 @@ static int cx23885_set_freq_via_ops(struct cx23885_dev *dev,
        msleep(100);
 
        /* I need to unmute audio here */
-       ctrl.value = 0;
-       cx23885_set_control(dev, &ctrl);
-
-       mutex_unlock(&dev->lock);
+       if (old_mute_val == 0)
+               v4l2_ctrl_s_ctrl(mute, old_mute_val);
 
        return 0;
 }
@@ -1611,8 +981,7 @@ static int cx23885_set_freq_via_ops(struct cx23885_dev *dev,
 int cx23885_set_frequency(struct file *file, void *priv,
        const struct v4l2_frequency *f)
 {
-       struct cx23885_fh *fh = priv;
-       struct cx23885_dev *dev = fh->dev;
+       struct cx23885_dev *dev = video_drvdata(file);
        int ret;
 
        switch (dev->board) {
@@ -1636,28 +1005,6 @@ static int vidioc_s_frequency(struct file *file, void *priv,
 
 /* ----------------------------------------------------------- */
 
-static void cx23885_vid_timeout(unsigned long data)
-{
-       struct cx23885_dev *dev = (struct cx23885_dev *)data;
-       struct cx23885_dmaqueue *q = &dev->vidq;
-       struct cx23885_buffer *buf;
-       unsigned long flags;
-
-       spin_lock_irqsave(&dev->slock, flags);
-       while (!list_empty(&q->active)) {
-               buf = list_entry(q->active.next,
-                       struct cx23885_buffer, vb.queue);
-               list_del(&buf->vb.queue);
-               buf->vb.state = VIDEOBUF_ERROR;
-               wake_up(&buf->vb.done);
-               printk(KERN_ERR "%s: [%p/%d] timeout - dma=0x%08lx\n",
-                       dev->name, buf, buf->vb.i,
-                       (unsigned long)buf->risc.dma);
-       }
-       cx23885_restart_video_queue(dev, q);
-       spin_unlock_irqrestore(&dev->slock, flags);
-}
-
 int cx23885_video_irq(struct cx23885_dev *dev, u32 status)
 {
        u32 mask, count;
@@ -1702,13 +1049,6 @@ int cx23885_video_irq(struct cx23885_dev *dev, u32 status)
                spin_unlock(&dev->slock);
                handled++;
        }
-       if (status & VID_BC_MSK_RISCI2) {
-               dprintk(2, "stopper video\n");
-               spin_lock(&dev->slock);
-               cx23885_restart_video_queue(dev, &dev->vidq);
-               spin_unlock(&dev->slock);
-               handled++;
-       }
 
        /* Allow the VBI framework to process it's payload */
        handled += cx23885_vbi_irq(dev, status);
@@ -1721,12 +1061,12 @@ int cx23885_video_irq(struct cx23885_dev *dev, u32 status)
 
 static const struct v4l2_file_operations video_fops = {
        .owner         = THIS_MODULE,
-       .open          = video_open,
-       .release       = video_release,
-       .read          = video_read,
-       .poll          = video_poll,
-       .mmap          = video_mmap,
-       .ioctl         = video_ioctl2,
+       .open           = v4l2_fh_open,
+       .release        = vb2_fop_release,
+       .read           = vb2_fop_read,
+       .poll           = vb2_fop_poll,
+       .unlocked_ioctl = video_ioctl2,
+       .mmap           = vb2_fop_mmap,
 };
 
 static const struct v4l2_ioctl_ops video_ioctl_ops = {
@@ -1738,21 +1078,19 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = {
        .vidioc_g_fmt_vbi_cap     = cx23885_vbi_fmt,
        .vidioc_try_fmt_vbi_cap   = cx23885_vbi_fmt,
        .vidioc_s_fmt_vbi_cap     = cx23885_vbi_fmt,
-       .vidioc_reqbufs       = vidioc_reqbufs,
-       .vidioc_querybuf      = vidioc_querybuf,
-       .vidioc_qbuf          = vidioc_qbuf,
-       .vidioc_dqbuf         = vidioc_dqbuf,
+       .vidioc_reqbufs       = vb2_ioctl_reqbufs,
+       .vidioc_prepare_buf   = vb2_ioctl_prepare_buf,
+       .vidioc_querybuf      = vb2_ioctl_querybuf,
+       .vidioc_qbuf          = vb2_ioctl_qbuf,
+       .vidioc_dqbuf         = vb2_ioctl_dqbuf,
+       .vidioc_streamon      = vb2_ioctl_streamon,
+       .vidioc_streamoff     = vb2_ioctl_streamoff,
        .vidioc_s_std         = vidioc_s_std,
        .vidioc_g_std         = vidioc_g_std,
        .vidioc_enum_input    = vidioc_enum_input,
        .vidioc_g_input       = vidioc_g_input,
        .vidioc_s_input       = vidioc_s_input,
        .vidioc_log_status    = vidioc_log_status,
-       .vidioc_queryctrl     = vidioc_queryctrl,
-       .vidioc_g_ctrl        = vidioc_g_ctrl,
-       .vidioc_s_ctrl        = vidioc_s_ctrl,
-       .vidioc_streamon      = vidioc_streamon,
-       .vidioc_streamoff     = vidioc_streamoff,
        .vidioc_g_tuner       = vidioc_g_tuner,
        .vidioc_s_tuner       = vidioc_s_tuner,
        .vidioc_g_frequency   = vidioc_g_frequency,
@@ -1765,6 +1103,8 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = {
        .vidioc_enumaudio     = vidioc_enum_audinput,
        .vidioc_g_audio       = vidioc_g_audinput,
        .vidioc_s_audio       = vidioc_s_audinput,
+       .vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
+       .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
 };
 
 static struct video_device cx23885_vbi_template;
@@ -1775,14 +1115,6 @@ static struct video_device cx23885_video_template = {
        .tvnorms              = CX23885_NORMS,
 };
 
-static const struct v4l2_file_operations radio_fops = {
-       .owner         = THIS_MODULE,
-       .open          = video_open,
-       .release       = video_release,
-       .ioctl         = video_ioctl2,
-};
-
-
 void cx23885_video_unregister(struct cx23885_dev *dev)
 {
        dprintk(1, "%s()\n", __func__);
@@ -1794,7 +1126,6 @@ void cx23885_video_unregister(struct cx23885_dev *dev)
                else
                        video_device_release(dev->vbi_dev);
                dev->vbi_dev = NULL;
-               btcx_riscmem_free(dev->pci, &dev->vbiq.stopper);
        }
        if (dev->video_dev) {
                if (video_is_registered(dev->video_dev))
@@ -1802,8 +1133,6 @@ void cx23885_video_unregister(struct cx23885_dev *dev)
                else
                        video_device_release(dev->video_dev);
                dev->video_dev = NULL;
-
-               btcx_riscmem_free(dev->pci, &dev->vidq.stopper);
        }
 
        if (dev->audio_dev)
@@ -1812,6 +1141,7 @@ void cx23885_video_unregister(struct cx23885_dev *dev)
 
 int cx23885_video_register(struct cx23885_dev *dev)
 {
+       struct vb2_queue *q;
        int err;
 
        dprintk(1, "%s()\n", __func__);
@@ -1822,24 +1152,16 @@ int cx23885_video_register(struct cx23885_dev *dev)
        strcpy(cx23885_vbi_template.name, "cx23885-vbi");
 
        dev->tvnorm = V4L2_STD_NTSC_M;
+       dev->fmt = format_by_fourcc(V4L2_PIX_FMT_YUYV);
+       dev->field = V4L2_FIELD_INTERLACED;
+       dev->width = 720;
+       dev->height = norm_maxh(dev->tvnorm);
 
        /* init video dma queues */
        INIT_LIST_HEAD(&dev->vidq.active);
-       INIT_LIST_HEAD(&dev->vidq.queued);
-       dev->vidq.timeout.function = cx23885_vid_timeout;
-       dev->vidq.timeout.data = (unsigned long)dev;
-       init_timer(&dev->vidq.timeout);
-       cx23885_risc_stopper(dev->pci, &dev->vidq.stopper,
-               VID_A_DMA_CTL, 0x11, 0x00);
 
        /* init vbi dma queues */
        INIT_LIST_HEAD(&dev->vbiq.active);
-       INIT_LIST_HEAD(&dev->vbiq.queued);
-       dev->vbiq.timeout.function = cx23885_vbi_timeout;
-       dev->vbiq.timeout.data = (unsigned long)dev;
-       init_timer(&dev->vbiq.timeout);
-       cx23885_risc_stopper(dev->pci, &dev->vbiq.stopper,
-               VID_A_DMA_CTL, 0x22, 0x00);
 
        cx23885_irq_add_enable(dev, 0x01);
 
@@ -1893,9 +1215,49 @@ int cx23885_video_register(struct cx23885_dev *dev)
                }
        }
 
+       /* initial device configuration */
+       mutex_lock(&dev->lock);
+       cx23885_set_tvnorm(dev, dev->tvnorm);
+       cx23885_video_mux(dev, 0);
+       cx23885_audio_mux(dev, 0);
+       mutex_unlock(&dev->lock);
+
+       q = &dev->vb2_vidq;
+       q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+       q->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF | VB2_READ;
+       q->gfp_flags = GFP_DMA32;
+       q->min_buffers_needed = 2;
+       q->drv_priv = dev;
+       q->buf_struct_size = sizeof(struct cx23885_buffer);
+       q->ops = &cx23885_video_qops;
+       q->mem_ops = &vb2_dma_sg_memops;
+       q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
+       q->lock = &dev->lock;
+
+       err = vb2_queue_init(q);
+       if (err < 0)
+               goto fail_unreg;
+
+       q = &dev->vb2_vbiq;
+       q->type = V4L2_BUF_TYPE_VBI_CAPTURE;
+       q->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF | VB2_READ;
+       q->gfp_flags = GFP_DMA32;
+       q->min_buffers_needed = 2;
+       q->drv_priv = dev;
+       q->buf_struct_size = sizeof(struct cx23885_buffer);
+       q->ops = &cx23885_vbi_qops;
+       q->mem_ops = &vb2_dma_sg_memops;
+       q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
+       q->lock = &dev->lock;
+
+       err = vb2_queue_init(q);
+       if (err < 0)
+               goto fail_unreg;
+
        /* register Video device */
        dev->video_dev = cx23885_vdev_init(dev, dev->pci,
                &cx23885_video_template, "video");
+       dev->video_dev->queue = &dev->vb2_vidq;
        err = video_register_device(dev->video_dev, VFL_TYPE_GRABBER,
                                    video_nr[dev->nr]);
        if (err < 0) {
@@ -1909,6 +1271,7 @@ int cx23885_video_register(struct cx23885_dev *dev)
        /* register VBI device */
        dev->vbi_dev = cx23885_vdev_init(dev, dev->pci,
                &cx23885_vbi_template, "vbi");
+       dev->vbi_dev->queue = &dev->vb2_vbiq;
        err = video_register_device(dev->vbi_dev, VFL_TYPE_VBI,
                                    vbi_nr[dev->nr]);
        if (err < 0) {
@@ -1922,18 +1285,9 @@ int cx23885_video_register(struct cx23885_dev *dev)
        /* Register ALSA audio device */
        dev->audio_dev = cx23885_audio_register(dev);
 
-       /* initial device configuration */
-       mutex_lock(&dev->lock);
-       cx23885_set_tvnorm(dev, dev->tvnorm);
-       init_controls(dev);
-       cx23885_video_mux(dev, 0);
-       cx23885_audio_mux(dev, 0);
-       mutex_unlock(&dev->lock);
-
        return 0;
 
 fail_unreg:
        cx23885_video_unregister(dev);
        return err;
 }
-
index c961a2b0de0ffa8c51ecffe0cbebb89085f3d330..291e8f3189f0ce1def25c2896dd5eaf1f8bbd696 100644 (file)
  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- *  02110-1301, USA.
  */
 
 #ifndef _CX23885_VIDEO_H_
index 0e086c03da672ae241f0501aa72b85cd9f3b79f1..6c35e61159696ad4be7ee930d42a74e4636b98a1 100644 (file)
  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  *
  *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
 #include <linux/pci.h>
 #include <linux/slab.h>
 
 #include <media/v4l2-device.h>
+#include <media/v4l2-fh.h>
+#include <media/v4l2-ctrls.h>
 #include <media/tuner.h>
 #include <media/tveeprom.h>
-#include <media/videobuf-dma-sg.h>
-#include <media/videobuf-dvb.h>
+#include <media/videobuf2-dma-sg.h>
+#include <media/videobuf2-dvb.h>
 #include <media/rc-core.h>
 
-#include "btcx-risc.h"
 #include "cx23885-reg.h"
 #include "media/cx2341x.h"
 
 #include <linux/mutex.h>
 
-#define CX23885_VERSION "0.0.3"
+#define CX23885_VERSION "0.0.4"
 
 #define UNSET (-1U)
 
@@ -46,9 +43,6 @@
 /* Max number of inputs by card */
 #define MAX_CX23885_INPUT 8
 #define INPUT(nr) (&cx23885_boards[dev->board].input[nr])
-#define RESOURCE_OVERLAY       1
-#define RESOURCE_VIDEO         2
-#define RESOURCE_VBI           4
 
 #define BUFFER_TIMEOUT     (HZ)  /* 0.5 seconds */
 
@@ -98,6 +92,7 @@
 #define CX23885_BOARD_LEADTEK_WINFAST_PXPVR2200 42
 #define CX23885_BOARD_HAUPPAUGE_IMPACTVCBE     43
 #define CX23885_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL_EXP2 44
+#define CX23885_BOARD_DVBSKY_T9580             45
 
 #define GPIO_0 0x00000001
 #define GPIO_1 0x00000002
@@ -131,14 +126,6 @@ struct cx23885_fmt {
        u32   cxformat;
 };
 
-struct cx23885_ctrl {
-       struct v4l2_queryctrl v;
-       u32                   off;
-       u32                   reg;
-       u32                   mask;
-       u32                   shift;
-};
-
 struct cx23885_tvnorm {
        char            *name;
        v4l2_std_id     id;
@@ -146,30 +133,6 @@ struct cx23885_tvnorm {
        u32             cxoformat;
 };
 
-struct cx23885_fh {
-       struct cx23885_dev         *dev;
-       enum v4l2_buf_type         type;
-       int                        radio;
-       u32                        resources;
-
-       /* video overlay */
-       struct v4l2_window         win;
-       struct v4l2_clip           *clips;
-       unsigned int               nclips;
-
-       /* video capture */
-       struct cx23885_fmt         *fmt;
-       unsigned int               width, height;
-
-       /* vbi capture */
-       struct videobuf_queue      vidq;
-       struct videobuf_queue      vbiq;
-
-       /* MPEG Encoder specifics ONLY */
-       struct videobuf_queue      mpegq;
-       atomic_t                   v4l_reading;
-};
-
 enum cx23885_itype {
        CX23885_VMUX_COMPOSITE1 = 1,
        CX23885_VMUX_COMPOSITE2,
@@ -189,14 +152,22 @@ enum cx23885_src_sel_type {
        CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO
 };
 
+struct cx23885_riscmem {
+       unsigned int   size;
+       __le32         *cpu;
+       __le32         *jmp;
+       dma_addr_t     dma;
+};
+
 /* buffer for one video frame */
 struct cx23885_buffer {
        /* common v4l buffer stuff -- must be first */
-       struct videobuf_buffer vb;
+       struct vb2_buffer vb;
+       struct list_head queue;
 
        /* cx23885 specific */
        unsigned int           bpl;
-       struct btcx_riscmem    risc;
+       struct cx23885_riscmem risc;
        struct cx23885_fmt     *fmt;
        u32                    count;
 };
@@ -268,9 +239,6 @@ struct cx23885_i2c {
 
 struct cx23885_dmaqueue {
        struct list_head       active;
-       struct list_head       queued;
-       struct timer_list      timeout;
-       struct btcx_riscmem    stopper;
        u32                    count;
 };
 
@@ -280,7 +248,7 @@ struct cx23885_tsport {
        int                        nr;
        int                        sram_chno;
 
-       struct videobuf_dvb_frontends frontends;
+       struct vb2_dvb_frontends   frontends;
 
        /* dma queues */
        struct cx23885_dmaqueue    mpegq;
@@ -326,7 +294,12 @@ struct cx23885_tsport {
        /* Workaround for a temp dvb_frontend that the tuner can attached to */
        struct dvb_frontend analog_fe;
 
+       struct i2c_client *i2c_client_demod;
+       struct i2c_client *i2c_client_tuner;
+
        int (*set_frontend)(struct dvb_frontend *fe);
+       int (*fe_set_voltage)(struct dvb_frontend *fe,
+                               fe_sec_voltage_t voltage);
 };
 
 struct cx23885_kernel_ir {
@@ -339,8 +312,11 @@ struct cx23885_kernel_ir {
 
 struct cx23885_audio_buffer {
        unsigned int            bpl;
-       struct btcx_riscmem     risc;
-       struct videobuf_dmabuf  dma;
+       struct cx23885_riscmem  risc;
+       void                    *vaddr;
+       struct scatterlist      *sglist;
+       int                     sglen;
+       int                     nr_pages;
 };
 
 struct cx23885_audio_dev {
@@ -358,8 +334,6 @@ struct cx23885_audio_dev {
        unsigned int            period_size;
        unsigned int            num_periods;
 
-       struct videobuf_dmabuf  *dma_risc;
-
        struct cx23885_audio_buffer   *buf;
 
        struct snd_pcm_substream *substream;
@@ -368,6 +342,7 @@ struct cx23885_audio_dev {
 struct cx23885_dev {
        atomic_t                   refcount;
        struct v4l2_device         v4l2_dev;
+       struct v4l2_ctrl_handler   ctrl_handler;
 
        /* pci stuff */
        struct pci_dev             *pci;
@@ -407,7 +382,6 @@ struct cx23885_dev {
        } bridge;
 
        /* Analog video */
-       u32                        resources;
        unsigned int               input;
        unsigned int               audinput; /* Selectable audio input */
        u32                        tvaudio;
@@ -417,7 +391,6 @@ struct cx23885_dev {
        unsigned int               tuner_bus;
        unsigned int               radio_type;
        unsigned char              radio_addr;
-       unsigned int               has_radio;
        struct v4l2_subdev         *sd_cx25840;
        struct work_struct         cx25840_work;
 
@@ -435,17 +408,24 @@ struct cx23885_dev {
        u32                        freq;
        struct video_device        *video_dev;
        struct video_device        *vbi_dev;
-       struct video_device        *radio_dev;
+
+       /* video capture */
+       struct cx23885_fmt         *fmt;
+       unsigned int               width, height;
+       unsigned                   field;
 
        struct cx23885_dmaqueue    vidq;
+       struct vb2_queue           vb2_vidq;
        struct cx23885_dmaqueue    vbiq;
+       struct vb2_queue           vb2_vbiq;
+
        spinlock_t                 slock;
 
        /* MPEG Encoder ONLY settings */
        u32                        cx23417_mailbox;
-       struct cx2341x_mpeg_params mpeg_params;
+       struct cx2341x_handler     cxhdl;
        struct video_device        *v4l_device;
-       atomic_t                   v4l_reader_count;
+       struct vb2_queue           vb2_mpegq;
        struct cx23885_tvnorm      encodernorm;
 
        /* Analog raw audio */
@@ -521,26 +501,21 @@ extern int cx23885_sram_channel_setup(struct cx23885_dev *dev,
 extern void cx23885_sram_channel_dump(struct cx23885_dev *dev,
        struct sram_channel *ch);
 
-extern int cx23885_risc_stopper(struct pci_dev *pci, struct btcx_riscmem *risc,
-       u32 reg, u32 mask, u32 value);
-
-extern int cx23885_risc_buffer(struct pci_dev *pci, struct btcx_riscmem *risc,
+extern int cx23885_risc_buffer(struct pci_dev *pci, struct cx23885_riscmem *risc,
        struct scatterlist *sglist,
        unsigned int top_offset, unsigned int bottom_offset,
        unsigned int bpl, unsigned int padding, unsigned int lines);
 
 extern int cx23885_risc_vbibuffer(struct pci_dev *pci,
-       struct btcx_riscmem *risc, struct scatterlist *sglist,
+       struct cx23885_riscmem *risc, struct scatterlist *sglist,
        unsigned int top_offset, unsigned int bottom_offset,
        unsigned int bpl, unsigned int padding, unsigned int lines);
 
+int cx23885_start_dma(struct cx23885_tsport *port,
+                            struct cx23885_dmaqueue *q,
+                            struct cx23885_buffer   *buf);
 void cx23885_cancel_buffers(struct cx23885_tsport *port);
 
-extern int cx23885_restart_queue(struct cx23885_tsport *port,
-                               struct cx23885_dmaqueue *q);
-
-extern void cx23885_wakeup(struct cx23885_tsport *port,
-                          struct cx23885_dmaqueue *q, u32 count);
 
 extern void cx23885_gpio_set(struct cx23885_dev *dev, u32 mask);
 extern void cx23885_gpio_clear(struct cx23885_dev *dev, u32 mask);
@@ -574,13 +549,11 @@ extern void cx23885_card_setup_pre_i2c(struct cx23885_dev *dev);
 extern int cx23885_dvb_register(struct cx23885_tsport *port);
 extern int cx23885_dvb_unregister(struct cx23885_tsport *port);
 
-extern int cx23885_buf_prepare(struct videobuf_queue *q,
-                              struct cx23885_tsport *port,
-                              struct cx23885_buffer *buf,
-                              enum v4l2_field field);
+extern int cx23885_buf_prepare(struct cx23885_buffer *buf,
+                              struct cx23885_tsport *port);
 extern void cx23885_buf_queue(struct cx23885_tsport *port,
                              struct cx23885_buffer *buf);
-extern void cx23885_free_buffer(struct videobuf_queue *q,
+extern void cx23885_free_buffer(struct cx23885_dev *dev,
                                struct cx23885_buffer *buf);
 
 /* ----------------------------------------------------------- */
@@ -595,8 +568,6 @@ int cx23885_enum_input(struct cx23885_dev *dev, struct v4l2_input *i);
 int cx23885_set_input(struct file *file, void *priv, unsigned int i);
 int cx23885_get_input(struct file *file, void *priv, unsigned int *i);
 int cx23885_set_frequency(struct file *file, void *priv, const struct v4l2_frequency *f);
-int cx23885_set_control(struct cx23885_dev *dev, struct v4l2_control *ctl);
-int cx23885_get_control(struct cx23885_dev *dev, struct v4l2_control *ctl);
 int cx23885_set_tvnorm(struct cx23885_dev *dev, v4l2_std_id norm);
 
 /* ----------------------------------------------------------- */
@@ -604,9 +575,7 @@ int cx23885_set_tvnorm(struct cx23885_dev *dev, v4l2_std_id norm);
 extern int cx23885_vbi_fmt(struct file *file, void *priv,
        struct v4l2_format *f);
 extern void cx23885_vbi_timeout(unsigned long data);
-extern struct videobuf_queue_ops cx23885_vbi_qops;
-extern int cx23885_restart_vbi_queue(struct cx23885_dev *dev,
-       struct cx23885_dmaqueue *q);
+extern struct vb2_ops cx23885_vbi_qops;
 extern int cx23885_vbi_irq(struct cx23885_dev *dev, u32 status);
 
 /* cx23885-i2c.c                                                */
@@ -638,7 +607,7 @@ extern struct cx23885_audio_dev *cx23885_audio_register(
 extern void cx23885_audio_unregister(struct cx23885_dev *dev);
 extern int cx23885_audio_irq(struct cx23885_dev *dev, u32 status, u32 mask);
 extern int cx23885_risc_databuffer(struct pci_dev *pci,
-                                  struct btcx_riscmem *risc,
+                                  struct cx23885_riscmem *risc,
                                   struct scatterlist *sglist,
                                   unsigned int bpl,
                                   unsigned int lines,
@@ -649,15 +618,10 @@ extern int cx23885_risc_databuffer(struct pci_dev *pci,
 
 static inline unsigned int norm_maxw(v4l2_std_id norm)
 {
-       return (norm & (V4L2_STD_MN & ~V4L2_STD_PAL_Nc)) ? 720 : 768;
+       return (norm & V4L2_STD_525_60) ? 720 : 768;
 }
 
 static inline unsigned int norm_maxh(v4l2_std_id norm)
 {
-       return (norm & V4L2_STD_625_50) ? 576 : 480;
-}
-
-static inline unsigned int norm_swidth(v4l2_std_id norm)
-{
-       return (norm & (V4L2_STD_MN & ~V4L2_STD_PAL_Nc)) ? 754 : 922;
+       return (norm & V4L2_STD_525_60) ? 480 : 576;
 }
index c2ff5fc01157c51e72ca2147a73f447f20be2e86..c1aa888af705434148f3915c42b70a07a01d361b 100644 (file)
  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- *  02110-1301, USA.
  */
 
 #include <linux/kfifo.h>
index d2de41caaf1d6e902354adfacb6e8611cc7948d3..ff74a93575d681fee7a83856ab53b775cb7db04e 100644 (file)
  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- *  02110-1301, USA.
  */
 
 #ifndef _CX23888_IR_H_
index 98a48f500684ce1f6256763a0d9c6cceef11c868..b6542ee4385b1dab71a644c965d4d090ded69f97 100644 (file)
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  *
  * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
 #
index 13926e18febae16fdad84acd7bbdefd61f266f4b..90cac5b655d5dbbe6d05ff3fee79a3b8d5377373 100644 (file)
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  *
  * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
 #ifndef NETUP_EEPROM_H
index 0044fef7ca24e2adac4d08f55f6d32bc9b08ed5d..76d9487aafc85c8c07bc8cb1dae59efd10fb2d10 100644 (file)
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  *
  * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
 #include "cx23885.h"
index d26ae4b1590ece5c745576466ca32a49ed96bd76..daaa212adfbab900c8a8801b99d40fa64a1b343e 100644 (file)
@@ -17,9 +17,5 @@
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  *
  * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 extern void netup_initialize(struct cx23885_dev *dev);
index 1f43be0b04c8e91dc5012275d3d040eb0bd92a2d..a664997e1958dccdba7fbf6315d1d5b4606ca084 100644 (file)
@@ -330,8 +330,9 @@ int cx25821_write_frame(struct cx25821_channel *chan,
 
        if (frame_size - curpos < count)
                count = frame_size - curpos;
-       memcpy((char *)out->_data_buf_virt_addr + frame_offset + curpos,
-                       data, count);
+       if (copy_from_user((__force char *)out->_data_buf_virt_addr + frame_offset + curpos,
+                               data, count))
+               return -EFAULT;
        curpos += count;
        if (curpos == frame_size) {
                out->_frame_count++;
index e18a7ace08b1b1a41667e10e5eb47d31f07deb91..851754bf1291475f6dc1c383401d753edb864edf 100644 (file)
@@ -78,19 +78,19 @@ static const struct cx88_board cx88_boards[] = {
                .radio_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
-               .input          = {{
+               .input          = { {
                        .type   = CX88_VMUX_COMPOSITE1,
                        .vmux   = 0,
-               },{
+               }, {
                        .type   = CX88_VMUX_COMPOSITE2,
                        .vmux   = 1,
-               },{
+               }, {
                        .type   = CX88_VMUX_COMPOSITE3,
                        .vmux   = 2,
-               },{
+               }, {
                        .type   = CX88_VMUX_COMPOSITE4,
                        .vmux   = 3,
-               }},
+               } },
        },
        [CX88_BOARD_HAUPPAUGE] = {
                .name           = "Hauppauge WinTV 34xxx models",
@@ -99,23 +99,23 @@ static const struct cx88_board cx88_boards[] = {
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
                .tda9887_conf   = TDA9887_PRESENT,
-               .input          = {{
+               .input          = { {
                        .type   = CX88_VMUX_TELEVISION,
                        .vmux   = 0,
                        .gpio0  = 0xff00,  // internal decoder
-               },{
+               }, {
                        .type   = CX88_VMUX_DEBUG,
                        .vmux   = 0,
                        .gpio0  = 0xff01,  // mono from tuner chip
-               },{
+               }, {
                        .type   = CX88_VMUX_COMPOSITE1,
                        .vmux   = 1,
                        .gpio0  = 0xff02,
-               },{
+               }, {
                        .type   = CX88_VMUX_SVIDEO,
                        .vmux   = 2,
                        .gpio0  = 0xff02,
-               }},
+               } },
                .radio = {
                        .type   = CX88_RADIO,
                        .gpio0  = 0xff01,
@@ -127,13 +127,13 @@ static const struct cx88_board cx88_boards[] = {
                .radio_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
-               .input          = {{
+               .input          = { {
                        .type   = CX88_VMUX_TELEVISION,
                        .vmux   = 0,
-               },{
+               }, {
                        .type   = CX88_VMUX_SVIDEO,
                        .vmux   = 2,
-               }},
+               } },
        },
        [CX88_BOARD_PIXELVIEW] = {
                .name           = "PixelView",
@@ -141,17 +141,17 @@ static const struct cx88_board cx88_boards[] = {
                .radio_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
-               .input          = {{
+               .input          = { {
                        .type   = CX88_VMUX_TELEVISION,
                        .vmux   = 0,
                        .gpio0  = 0xff00,  // internal decoder
-               },{
+               }, {
                        .type   = CX88_VMUX_COMPOSITE1,
                        .vmux   = 1,
-               },{
+               }, {
                        .type   = CX88_VMUX_SVIDEO,
                        .vmux   = 2,
-               }},
+               } },
                .radio = {
                         .type  = CX88_RADIO,
                         .gpio0 = 0xff10,
@@ -164,19 +164,19 @@ static const struct cx88_board cx88_boards[] = {
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
                .tda9887_conf   = TDA9887_PRESENT | TDA9887_INTERCARRIER,
-               .input          = {{
+               .input          = { {
                        .type   = CX88_VMUX_TELEVISION,
                        .vmux   = 0,
                        .gpio0  = 0x03ff,
-               },{
+               }, {
                        .type   = CX88_VMUX_COMPOSITE1,
                        .vmux   = 1,
                        .gpio0  = 0x03fe,
-               },{
+               }, {
                        .type   = CX88_VMUX_SVIDEO,
                        .vmux   = 2,
                        .gpio0  = 0x03fe,
-               }},
+               } },
        },
        [CX88_BOARD_WINFAST2000XP_EXPERT] = {
                .name           = "Leadtek Winfast 2000XP Expert",
@@ -185,28 +185,28 @@ static const struct cx88_board cx88_boards[] = {
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
                .tda9887_conf   = TDA9887_PRESENT,
-               .input          = {{
+               .input          = { {
                        .type   = CX88_VMUX_TELEVISION,
                        .vmux   = 0,
                        .gpio0  = 0x00F5e700,
                        .gpio1  = 0x00003004,
                        .gpio2  = 0x00F5e700,
                        .gpio3  = 0x02000000,
-               },{
+               }, {
                        .type   = CX88_VMUX_COMPOSITE1,
                        .vmux   = 1,
                        .gpio0  = 0x00F5c700,
                        .gpio1  = 0x00003004,
                        .gpio2  = 0x00F5c700,
                        .gpio3  = 0x02000000,
-               },{
+               }, {
                        .type   = CX88_VMUX_SVIDEO,
                        .vmux   = 2,
                        .gpio0  = 0x00F5c700,
                        .gpio1  = 0x00003004,
                        .gpio2  = 0x00F5c700,
                        .gpio3  = 0x02000000,
-               }},
+               } },
                .radio = {
                        .type   = CX88_RADIO,
                        .gpio0  = 0x00F5d700,
@@ -222,19 +222,19 @@ static const struct cx88_board cx88_boards[] = {
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
                .tda9887_conf   = TDA9887_PRESENT,
-               .input          = {{
+               .input          = { {
                        .type   = CX88_VMUX_TELEVISION,
                        .vmux   = 0,
                        .gpio1  = 0xe09f,
-               },{
+               }, {
                        .type   = CX88_VMUX_COMPOSITE1,
                        .vmux   = 1,
                        .gpio1  = 0xe05f,
-               },{
+               }, {
                        .type   = CX88_VMUX_SVIDEO,
                        .vmux   = 2,
                        .gpio1  = 0xe05f,
-               }},
+               } },
                .radio = {
                        .gpio1  = 0xe0df,
                        .type   = CX88_RADIO,
@@ -249,25 +249,25 @@ static const struct cx88_board cx88_boards[] = {
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
                .tda9887_conf   = TDA9887_PRESENT | TDA9887_INTERCARRIER_NTSC,
-               .input          = {{
+               .input          = { {
                        .type   = CX88_VMUX_TELEVISION,
                        .vmux   = 0,
                        .gpio0  = 0x000040bf,
                        .gpio1  = 0x000080c0,
                        .gpio2  = 0x0000ff40,
-               },{
+               }, {
                        .type   = CX88_VMUX_COMPOSITE1,
                        .vmux   = 1,
                        .gpio0  = 0x000040bf,
                        .gpio1  = 0x000080c0,
                        .gpio2  = 0x0000ff40,
-               },{
+               }, {
                        .type   = CX88_VMUX_SVIDEO,
                        .vmux   = 2,
                        .gpio0  = 0x000040bf,
                        .gpio1  = 0x000080c0,
                        .gpio2  = 0x0000ff40,
-               }},
+               } },
                .radio = {
                         .type   = CX88_RADIO,
                         .vmux   = 3,
@@ -283,14 +283,14 @@ static const struct cx88_board cx88_boards[] = {
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
                .tda9887_conf   = TDA9887_PRESENT,
-               .input          = {{
+               .input          = { {
                        .type   = CX88_VMUX_TELEVISION,
                        .vmux   = 0,
                        .gpio0  = 0x0035e700,
                        .gpio1  = 0x00003004,
                        .gpio2  = 0x0035e700,
                        .gpio3  = 0x02000000,
-               },{
+               }, {
 
                        .type   = CX88_VMUX_COMPOSITE1,
                        .vmux   = 1,
@@ -298,14 +298,14 @@ static const struct cx88_board cx88_boards[] = {
                        .gpio1  = 0x00003004,
                        .gpio2  = 0x0035c700,
                        .gpio3  = 0x02000000,
-               },{
+               }, {
                        .type   = CX88_VMUX_SVIDEO,
                        .vmux   = 2,
                        .gpio0  = 0x0035c700,
                        .gpio1  = 0x0035c700,
                        .gpio2  = 0x02000000,
                        .gpio3  = 0x02000000,
-               }},
+               } },
                .radio = {
                        .type   = CX88_RADIO,
                        .gpio0  = 0x0035d700,
@@ -322,22 +322,22 @@ static const struct cx88_board cx88_boards[] = {
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
                .tda9887_conf   = TDA9887_PRESENT,
-               .input          = {{
+               .input          = { {
                        .type   = CX88_VMUX_TELEVISION,
                        .vmux   = 0,
                        .gpio0  = 0x0000bde2,
                        .audioroute = 1,
-               },{
+               }, {
                        .type   = CX88_VMUX_COMPOSITE1,
                        .vmux   = 1,
                        .gpio0  = 0x0000bde6,
                        .audioroute = 1,
-               },{
+               }, {
                        .type   = CX88_VMUX_SVIDEO,
                        .vmux   = 2,
                        .gpio0  = 0x0000bde6,
                        .audioroute = 1,
-               }},
+               } },
                .radio = {
                        .type   = CX88_RADIO,
                        .gpio0  = 0x0000bd62,
@@ -351,16 +351,16 @@ static const struct cx88_board cx88_boards[] = {
                .radio_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
-               .input          = {{
+               .input          = { {
                        .type   = CX88_VMUX_COMPOSITE1,
                        .vmux   = 0,
-               },{
+               }, {
                        .type   = CX88_VMUX_COMPOSITE2,
                        .vmux   = 1,
-               },{
+               }, {
                        .type   = CX88_VMUX_SVIDEO,
                        .vmux   = 2,
-               }},
+               } },
        },
        [CX88_BOARD_PROLINK_PLAYTVPVR] = {
                .name           = "Prolink PlayTV PVR",
@@ -369,19 +369,19 @@ static const struct cx88_board cx88_boards[] = {
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
                .tda9887_conf   = TDA9887_PRESENT,
-               .input          = {{
+               .input          = { {
                        .type   = CX88_VMUX_TELEVISION,
                        .vmux   = 0,
                        .gpio0  = 0xbff0,
-               },{
+               }, {
                        .type   = CX88_VMUX_COMPOSITE1,
                        .vmux   = 1,
                        .gpio0  = 0xbff3,
-               },{
+               }, {
                        .type   = CX88_VMUX_SVIDEO,
                        .vmux   = 2,
                        .gpio0  = 0xbff3,
-               }},
+               } },
                .radio = {
                        .type   = CX88_RADIO,
                        .gpio0  = 0xbff0,
@@ -394,16 +394,16 @@ static const struct cx88_board cx88_boards[] = {
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
                .tda9887_conf   = TDA9887_PRESENT,
-               .input          = {{
+               .input          = { {
                        .type   = CX88_VMUX_TELEVISION,
                        .vmux   = 0,
                        .gpio0  = 0x0000fde6,
-               },{
+               }, {
                        .type   = CX88_VMUX_SVIDEO,
                        .vmux   = 2,
                        .gpio0  = 0x0000fde6, // 0x0000fda6 L,R RCA audio in?
                        .audioroute = 1,
-               }},
+               } },
                .radio = {
                        .type   = CX88_RADIO,
                        .gpio0  = 0x0000fde2,
@@ -417,22 +417,22 @@ static const struct cx88_board cx88_boards[] = {
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
                .tda9887_conf   = TDA9887_PRESENT,
-               .input          = {{
+               .input          = { {
                        .type   = CX88_VMUX_TELEVISION,
                        .vmux   = 0,
                        .gpio0  = 0x00000fbf,
                        .gpio2  = 0x0000fc08,
-               },{
+               }, {
                        .type   = CX88_VMUX_COMPOSITE1,
                        .vmux   = 1,
                        .gpio0  = 0x00000fbf,
                        .gpio2  = 0x0000fc68,
-               },{
+               }, {
                        .type   = CX88_VMUX_SVIDEO,
                        .vmux   = 2,
                        .gpio0  = 0x00000fbf,
                        .gpio2  = 0x0000fc68,
-               }},
+               } },
        },
        [CX88_BOARD_KWORLD_DVB_T] = {
                .name           = "KWorld/VStream XPert DVB-T",
@@ -440,17 +440,17 @@ static const struct cx88_board cx88_boards[] = {
                .radio_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
-               .input          = {{
+               .input          = { {
                        .type   = CX88_VMUX_COMPOSITE1,
                        .vmux   = 1,
                        .gpio0  = 0x0700,
                        .gpio2  = 0x0101,
-               },{
+               }, {
                        .type   = CX88_VMUX_SVIDEO,
                        .vmux   = 2,
                        .gpio0  = 0x0700,
                        .gpio2  = 0x0101,
-               }},
+               } },
                .mpeg           = CX88_MPEG_DVB,
        },
        [CX88_BOARD_DVICO_FUSIONHDTV_DVB_T1] = {
@@ -459,15 +459,15 @@ static const struct cx88_board cx88_boards[] = {
                .radio_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
-               .input          = {{
+               .input          = { {
                        .type   = CX88_VMUX_COMPOSITE1,
                        .vmux   = 1,
                        .gpio0  = 0x000027df,
-               },{
+               }, {
                        .type   = CX88_VMUX_SVIDEO,
                        .vmux   = 2,
                        .gpio0  = 0x000027df,
-               }},
+               } },
                .mpeg           = CX88_MPEG_DVB,
        },
        [CX88_BOARD_KWORLD_LTV883] = {
@@ -476,23 +476,23 @@ static const struct cx88_board cx88_boards[] = {
                .radio_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
-               .input          = {{
+               .input          = { {
                        .type   = CX88_VMUX_TELEVISION,
                        .vmux   = 0,
                        .gpio0  = 0x07f8,
-               },{
+               }, {
                        .type   = CX88_VMUX_DEBUG,
                        .vmux   = 0,
                        .gpio0  = 0x07f9,  // mono from tuner chip
-               },{
+               }, {
                        .type   = CX88_VMUX_COMPOSITE1,
                        .vmux   = 1,
                        .gpio0  = 0x000007fa,
-               },{
+               }, {
                        .type   = CX88_VMUX_SVIDEO,
                        .vmux   = 2,
                        .gpio0  = 0x000007fa,
-               }},
+               } },
                .radio = {
                        .type   = CX88_RADIO,
                        .gpio0  = 0x000007f8,
@@ -521,23 +521,23 @@ static const struct cx88_board cx88_boards[] = {
                    0 - normal RF
                    1 - high RF
                */
-               .input          = {{
+               .input          = { {
                        .type   = CX88_VMUX_TELEVISION,
                        .vmux   = 0,
                        .gpio0  = 0x0f0d,
-               },{
+               }, {
                        .type   = CX88_VMUX_CABLE,
                        .vmux   = 0,
                        .gpio0  = 0x0f05,
-               },{
+               }, {
                        .type   = CX88_VMUX_COMPOSITE1,
                        .vmux   = 1,
                        .gpio0  = 0x0f00,
-               },{
+               }, {
                        .type   = CX88_VMUX_SVIDEO,
                        .vmux   = 2,
                        .gpio0  = 0x0f00,
-               }},
+               } },
                .mpeg           = CX88_MPEG_DVB,
        },
        [CX88_BOARD_HAUPPAUGE_DVB_T1] = {
@@ -546,10 +546,10 @@ static const struct cx88_board cx88_boards[] = {
                .radio_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
-               .input          = {{
+               .input          = { {
                        .type   = CX88_VMUX_DVB,
                        .vmux   = 0,
-               }},
+               } },
                .mpeg           = CX88_MPEG_DVB,
        },
        [CX88_BOARD_CONEXANT_DVB_T1] = {
@@ -558,10 +558,10 @@ static const struct cx88_board cx88_boards[] = {
                .radio_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
-               .input          = {{
+               .input          = { {
                        .type   = CX88_VMUX_DVB,
                        .vmux   = 0,
-               }},
+               } },
                .mpeg           = CX88_MPEG_DVB,
        },
        [CX88_BOARD_PROVIDEO_PV259] = {
@@ -570,11 +570,11 @@ static const struct cx88_board cx88_boards[] = {
                .radio_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
-               .input          = {{
+               .input          = { {
                        .type   = CX88_VMUX_TELEVISION,
                        .vmux   = 0,
                        .audioroute = 1,
-               }},
+               } },
                .mpeg           = CX88_MPEG_BLACKBIRD,
        },
        [CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PLUS] = {
@@ -583,15 +583,15 @@ static const struct cx88_board cx88_boards[] = {
                .radio_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
-               .input          = {{
+               .input          = { {
                        .type   = CX88_VMUX_COMPOSITE1,
                        .vmux   = 1,
                        .gpio0  = 0x000027df,
-               },{
+               }, {
                        .type   = CX88_VMUX_SVIDEO,
                        .vmux   = 2,
                        .gpio0  = 0x000027df,
-               }},
+               } },
                .mpeg           = CX88_MPEG_DVB,
        },
        [CX88_BOARD_DNTV_LIVE_DVB_T] = {
@@ -600,17 +600,17 @@ static const struct cx88_board cx88_boards[] = {
                .radio_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
-               .input          = {{
+               .input          = { {
                        .type   = CX88_VMUX_COMPOSITE1,
                        .vmux   = 1,
                        .gpio0  = 0x00000700,
                        .gpio2  = 0x00000101,
-               },{
+               }, {
                        .type   = CX88_VMUX_SVIDEO,
                        .vmux   = 2,
                        .gpio0  = 0x00000700,
                        .gpio2  = 0x00000101,
-               }},
+               } },
                .mpeg           = CX88_MPEG_DVB,
        },
        [CX88_BOARD_PCHDTV_HD3000] = {
@@ -632,19 +632,19 @@ static const struct cx88_board cx88_boards[] = {
                 *
                 * GPIO[16] = Remote control input
                 */
-               .input          = {{
+               .input          = { {
                        .type   = CX88_VMUX_TELEVISION,
                        .vmux   = 0,
                        .gpio0  = 0x00008484,
-               },{
+               }, {
                        .type   = CX88_VMUX_COMPOSITE1,
                        .vmux   = 1,
                        .gpio0  = 0x00008400,
-               },{
+               }, {
                        .type   = CX88_VMUX_SVIDEO,
                        .vmux   = 2,
                        .gpio0  = 0x00008400,
-               }},
+               } },
                .radio = {
                        .type   = CX88_RADIO,
                        .gpio0  = 0x00008404,
@@ -659,25 +659,25 @@ static const struct cx88_board cx88_boards[] = {
                .radio_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
-               .input          = {{
+               .input          = { {
                        .type   = CX88_VMUX_TELEVISION,
                        .vmux   = 0,
                        .gpio0  = 0xed1a,
                        .gpio2  = 0x00ff,
-               },{
+               }, {
                        .type   = CX88_VMUX_DEBUG,
                        .vmux   = 0,
                        .gpio0  = 0xff01,
-               },{
+               }, {
                        .type   = CX88_VMUX_COMPOSITE1,
                        .vmux   = 1,
                        .gpio0  = 0xff02,
-               },{
+               }, {
                        .type   = CX88_VMUX_SVIDEO,
                        .vmux   = 2,
                        .gpio0  = 0xed92,
                        .gpio2  = 0x00ff,
-               }},
+               } },
                .radio = {
                         .type   = CX88_RADIO,
                         .gpio0  = 0xed96,
@@ -692,22 +692,22 @@ static const struct cx88_board cx88_boards[] = {
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
                .tda9887_conf   = TDA9887_PRESENT,
-               .input          = {{
+               .input          = { {
                        .type   = CX88_VMUX_TELEVISION,
                        .vmux   = 0,
                        .gpio0  = 0x00009d80,
                        .audioroute = 1,
-               },{
+               }, {
                        .type   = CX88_VMUX_COMPOSITE1,
                        .vmux   = 1,
                        .gpio0  = 0x00009d76,
                        .audioroute = 1,
-               },{
+               }, {
                        .type   = CX88_VMUX_SVIDEO,
                        .vmux   = 2,
                        .gpio0  = 0x00009d76,
                        .audioroute = 1,
-               }},
+               } },
                .radio = {
                        .type   = CX88_RADIO,
                        .gpio0  = 0x00009d00,
@@ -722,19 +722,19 @@ static const struct cx88_board cx88_boards[] = {
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
                .tda9887_conf   = TDA9887_PRESENT,
-               .input          = {{
+               .input          = { {
                        .type   = CX88_VMUX_TELEVISION,
                        .vmux   = 1,
                        .gpio1  = 0x0000e03f,
-               },{
+               }, {
                        .type   = CX88_VMUX_COMPOSITE1,
                        .vmux   = 2,
                        .gpio1  = 0x0000e07f,
-               },{
+               }, {
                        .type   = CX88_VMUX_SVIDEO,
                        .vmux   = 3,
                        .gpio1  = 0x0000e07f,
-               }}
+               } }
        },
        [CX88_BOARD_PIXELVIEW_PLAYTV_ULTRA_PRO] = {
                .name           = "PixelView PlayTV Ultra Pro (Stereo)",
@@ -745,19 +745,19 @@ static const struct cx88_board cx88_boards[] = {
                .radio_addr     = ADDR_UNSET,
                /* Some variants use a tda9874 and so need the tvaudio module. */
                .audio_chip     = CX88_AUDIO_TVAUDIO,
-               .input          = {{
+               .input          = { {
                        .type   = CX88_VMUX_TELEVISION,
                        .vmux   = 0,
                        .gpio0  = 0xbf61,  /* internal decoder */
-               },{
+               }, {
                        .type   = CX88_VMUX_COMPOSITE1,
                        .vmux   = 1,
                        .gpio0  = 0xbf63,
-               },{
+               }, {
                        .type   = CX88_VMUX_SVIDEO,
                        .vmux   = 2,
                        .gpio0  = 0xbf63,
-               }},
+               } },
                .radio = {
                         .type  = CX88_RADIO,
                         .gpio0 = 0xbf60,
@@ -770,19 +770,19 @@ static const struct cx88_board cx88_boards[] = {
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
                .tda9887_conf   = TDA9887_PRESENT,
-               .input          = {{
+               .input          = { {
                        .type   = CX88_VMUX_TELEVISION,
                        .vmux   = 0,
                        .gpio0  = 0x97ed,
-               },{
+               }, {
                        .type   = CX88_VMUX_COMPOSITE1,
                        .vmux   = 1,
                        .gpio0  = 0x97e9,
-               },{
+               }, {
                        .type   = CX88_VMUX_SVIDEO,
                        .vmux   = 2,
                        .gpio0  = 0x97e9,
-               }},
+               } },
                .mpeg           = CX88_MPEG_DVB,
        },
        [CX88_BOARD_ADSTECH_DVB_T_PCI] = {
@@ -791,32 +791,32 @@ static const struct cx88_board cx88_boards[] = {
                .radio_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
-               .input          = {{
+               .input          = { {
                        .type   = CX88_VMUX_COMPOSITE1,
                        .vmux   = 1,
                        .gpio0  = 0x0700,
                        .gpio2  = 0x0101,
-               },{
+               }, {
                        .type   = CX88_VMUX_SVIDEO,
                        .vmux   = 2,
                        .gpio0  = 0x0700,
                        .gpio2  = 0x0101,
-               }},
+               } },
                .mpeg           = CX88_MPEG_DVB,
        },
        [CX88_BOARD_TERRATEC_CINERGY_1400_DVB_T1] = {
                .name           = "TerraTec Cinergy 1400 DVB-T",
                .tuner_type     = TUNER_ABSENT,
-               .input          = {{
+               .input          = { {
                        .type   = CX88_VMUX_DVB,
                        .vmux   = 0,
-               },{
+               }, {
                        .type   = CX88_VMUX_COMPOSITE1,
                        .vmux   = 2,
-               },{
+               }, {
                        .type   = CX88_VMUX_SVIDEO,
                        .vmux   = 2,
-               }},
+               } },
                .mpeg           = CX88_MPEG_DVB,
        },
        [CX88_BOARD_DVICO_FUSIONHDTV_5_GOLD] = {
@@ -826,19 +826,19 @@ static const struct cx88_board cx88_boards[] = {
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
                .tda9887_conf   = TDA9887_PRESENT,
-               .input          = {{
+               .input          = { {
                        .type   = CX88_VMUX_TELEVISION,
                        .vmux   = 0,
                        .gpio0  = 0x87fd,
-               },{
+               }, {
                        .type   = CX88_VMUX_COMPOSITE1,
                        .vmux   = 1,
                        .gpio0  = 0x87f9,
-               },{
+               }, {
                        .type   = CX88_VMUX_SVIDEO,
                        .vmux   = 2,
                        .gpio0  = 0x87f9,
-               }},
+               } },
                .mpeg           = CX88_MPEG_DVB,
        },
        [CX88_BOARD_AVERMEDIA_ULTRATV_MC_550] = {
@@ -848,22 +848,22 @@ static const struct cx88_board cx88_boards[] = {
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
                .tda9887_conf   = TDA9887_PRESENT,
-               .input          = {{
+               .input          = { {
                        .type   = CX88_VMUX_COMPOSITE1,
                        .vmux   = 0,
                        .gpio0  = 0x0000cd73,
                        .audioroute = 1,
-               },{
+               }, {
                        .type   = CX88_VMUX_SVIDEO,
                        .vmux   = 1,
                        .gpio0  = 0x0000cd73,
                        .audioroute = 1,
-               },{
+               }, {
                        .type   = CX88_VMUX_TELEVISION,
                        .vmux   = 3,
                        .gpio0  = 0x0000cdb3,
                        .audioroute = 1,
-               }},
+               } },
                .radio = {
                        .type   = CX88_RADIO,
                        .vmux   = 2,
@@ -876,21 +876,21 @@ static const struct cx88_board cx88_boards[] = {
                 /* Alexander Wold <awold@bigfoot.com> */
                 .name           = "Kworld V-Stream Xpert DVD",
                 .tuner_type     = UNSET,
-                .input          = {{
+                .input          = { {
                         .type   = CX88_VMUX_COMPOSITE1,
                         .vmux   = 1,
                         .gpio0  = 0x03000000,
                         .gpio1  = 0x01000000,
                         .gpio2  = 0x02000000,
                         .gpio3  = 0x00100000,
-                },{
+                }, {
                         .type   = CX88_VMUX_SVIDEO,
                         .vmux   = 2,
                         .gpio0  = 0x03000000,
                         .gpio1  = 0x01000000,
                         .gpio2  = 0x02000000,
                         .gpio3  = 0x00100000,
-                }},
+                } },
        },
        [CX88_BOARD_ATI_HDTVWONDER] = {
                .name           = "ATI HDTV Wonder",
@@ -898,28 +898,28 @@ static const struct cx88_board cx88_boards[] = {
                .radio_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
-               .input          = {{
+               .input          = { {
                        .type   = CX88_VMUX_TELEVISION,
                        .vmux   = 0,
                        .gpio0  = 0x00000ff7,
                        .gpio1  = 0x000000ff,
                        .gpio2  = 0x00000001,
                        .gpio3  = 0x00000000,
-               },{
+               }, {
                        .type   = CX88_VMUX_COMPOSITE1,
                        .vmux   = 1,
                        .gpio0  = 0x00000ffe,
                        .gpio1  = 0x000000ff,
                        .gpio2  = 0x00000001,
                        .gpio3  = 0x00000000,
-               },{
+               }, {
                        .type   = CX88_VMUX_SVIDEO,
                        .vmux   = 2,
                        .gpio0  = 0x00000ffe,
                        .gpio1  = 0x000000ff,
                        .gpio2  = 0x00000001,
                        .gpio3  = 0x00000000,
-               }},
+               } },
                .mpeg           = CX88_MPEG_DVB,
        },
        [CX88_BOARD_WINFAST_DTV1000] = {
@@ -928,16 +928,16 @@ static const struct cx88_board cx88_boards[] = {
                .radio_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
-               .input          = {{
+               .input          = { {
                        .type   = CX88_VMUX_DVB,
                        .vmux   = 0,
-               },{
+               }, {
                        .type   = CX88_VMUX_COMPOSITE1,
                        .vmux   = 1,
-               },{
+               }, {
                        .type   = CX88_VMUX_SVIDEO,
                        .vmux   = 2,
-               }},
+               } },
                .mpeg           = CX88_MPEG_DVB,
        },
        [CX88_BOARD_AVERTV_303] = {
@@ -947,28 +947,28 @@ static const struct cx88_board cx88_boards[] = {
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
                .tda9887_conf   = TDA9887_PRESENT,
-               .input          = {{
+               .input          = { {
                        .type   = CX88_VMUX_TELEVISION,
                        .vmux   = 0,
                        .gpio0  = 0x00ff,
                        .gpio1  = 0xe09f,
                        .gpio2  = 0x0010,
                        .gpio3  = 0x0000,
-               },{
+               }, {
                        .type   = CX88_VMUX_COMPOSITE1,
                        .vmux   = 1,
                        .gpio0  = 0x00ff,
                        .gpio1  = 0xe05f,
                        .gpio2  = 0x0010,
                        .gpio3  = 0x0000,
-               },{
+               }, {
                        .type   = CX88_VMUX_SVIDEO,
                        .vmux   = 2,
                        .gpio0  = 0x00ff,
                        .gpio1  = 0xe05f,
                        .gpio2  = 0x0010,
                        .gpio3  = 0x0000,
-               }},
+               } },
        },
        [CX88_BOARD_HAUPPAUGE_NOVASPLUS_S1] = {
                .name           = "Hauppauge Nova-S-Plus DVB-S",
@@ -978,22 +978,22 @@ static const struct cx88_board cx88_boards[] = {
                .radio_addr     = ADDR_UNSET,
                .audio_chip     = CX88_AUDIO_WM8775,
                .i2sinputcntl   = 2,
-               .input          = {{
+               .input          = { {
                        .type   = CX88_VMUX_DVB,
                        .vmux   = 0,
                        /* 2: Line-In */
                        .audioroute = 2,
-               },{
+               }, {
                        .type   = CX88_VMUX_COMPOSITE1,
                        .vmux   = 1,
                        /* 2: Line-In */
                        .audioroute = 2,
-               },{
+               }, {
                        .type   = CX88_VMUX_SVIDEO,
                        .vmux   = 2,
                        /* 2: Line-In */
                        .audioroute = 2,
-               }},
+               } },
                .mpeg           = CX88_MPEG_DVB,
        },
        [CX88_BOARD_HAUPPAUGE_NOVASE2_S1] = {
@@ -1002,10 +1002,10 @@ static const struct cx88_board cx88_boards[] = {
                .radio_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
-               .input          = {{
+               .input          = { {
                        .type   = CX88_VMUX_DVB,
                        .vmux   = 0,
-               }},
+               } },
                .mpeg           = CX88_MPEG_DVB,
        },
        [CX88_BOARD_KWORLD_DVBS_100] = {
@@ -1015,22 +1015,22 @@ static const struct cx88_board cx88_boards[] = {
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
                .audio_chip = CX88_AUDIO_WM8775,
-               .input          = {{
+               .input          = { {
                        .type   = CX88_VMUX_DVB,
                        .vmux   = 0,
                        /* 2: Line-In */
                        .audioroute = 2,
-               },{
+               }, {
                        .type   = CX88_VMUX_COMPOSITE1,
                        .vmux   = 1,
                        /* 2: Line-In */
                        .audioroute = 2,
-               },{
+               }, {
                        .type   = CX88_VMUX_SVIDEO,
                        .vmux   = 2,
                        /* 2: Line-In */
                        .audioroute = 2,
-               }},
+               } },
                .mpeg           = CX88_MPEG_DVB,
        },
        [CX88_BOARD_HAUPPAUGE_HVR1100] = {
@@ -1040,16 +1040,16 @@ static const struct cx88_board cx88_boards[] = {
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
                .tda9887_conf   = TDA9887_PRESENT,
-               .input          = {{
+               .input          = { {
                        .type   = CX88_VMUX_TELEVISION,
                        .vmux   = 0,
-               },{
+               }, {
                        .type   = CX88_VMUX_COMPOSITE1,
                        .vmux   = 1,
-               },{
+               }, {
                        .type   = CX88_VMUX_SVIDEO,
                        .vmux   = 2,
-               }},
+               } },
                /* fixme: Add radio support */
                .mpeg           = CX88_MPEG_DVB,
        },
@@ -1060,13 +1060,13 @@ static const struct cx88_board cx88_boards[] = {
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
                .tda9887_conf   = TDA9887_PRESENT,
-               .input          = {{
+               .input          = { {
                        .type   = CX88_VMUX_TELEVISION,
                        .vmux   = 0,
-               },{
+               }, {
                        .type   = CX88_VMUX_COMPOSITE1,
                        .vmux   = 1,
-               }},
+               } },
                /* fixme: Add radio support */
                .mpeg           = CX88_MPEG_DVB,
        },
@@ -1078,19 +1078,19 @@ static const struct cx88_board cx88_boards[] = {
                .radio_addr     = ADDR_UNSET,
                .tda9887_conf   = TDA9887_PRESENT | TDA9887_PORT1_ACTIVE |
                                  TDA9887_PORT2_ACTIVE,
-               .input          = {{
+               .input          = { {
                        .type   = CX88_VMUX_TELEVISION,
                        .vmux   = 0,
                        .gpio0  = 0xf80808,
-               },{
+               }, {
                        .type   = CX88_VMUX_COMPOSITE1,
                        .vmux   = 1,
                        .gpio0  = 0xf80808,
-               },{
+               }, {
                        .type   = CX88_VMUX_SVIDEO,
                        .vmux   = 2,
                        .gpio0  = 0xf80808,
-               }},
+               } },
                .radio = {
                         .type  = CX88_RADIO,
                         .gpio0 = 0xf80808,
@@ -1106,17 +1106,17 @@ static const struct cx88_board cx88_boards[] = {
                .radio_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
-               .input          = {{
+               .input          = { {
                        .type   = CX88_VMUX_COMPOSITE1,
                        .vmux   = 1,
                        .gpio0  = 0x0700,
                        .gpio2  = 0x0101,
-               },{
+               }, {
                        .type   = CX88_VMUX_SVIDEO,
                        .vmux   = 2,
                        .gpio0  = 0x0700,
                        .gpio2  = 0x0101,
-               }},
+               } },
                .mpeg           = CX88_MPEG_DVB,
        },
        [CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL] = {
@@ -1125,15 +1125,15 @@ static const struct cx88_board cx88_boards[] = {
                .radio_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
-               .input          = {{
+               .input          = { {
                        .type   = CX88_VMUX_COMPOSITE1,
                        .vmux   = 1,
                        .gpio0  = 0x000067df,
-                },{
+                }, {
                        .type   = CX88_VMUX_SVIDEO,
                        .vmux   = 2,
                        .gpio0  = 0x000067df,
-               }},
+               } },
                .mpeg           = CX88_MPEG_DVB,
        },
        [CX88_BOARD_KWORLD_HARDWARE_MPEG_TV_XPERT] = {
@@ -1142,22 +1142,22 @@ static const struct cx88_board cx88_boards[] = {
                .radio_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
-               .input          = {{
+               .input          = { {
                        .type   = CX88_VMUX_TELEVISION,
                        .vmux   = 0,
                        .gpio0  = 0x3de2,
                        .gpio2  = 0x00ff,
-               },{
+               }, {
                        .type   = CX88_VMUX_COMPOSITE1,
                        .vmux   = 1,
                        .gpio0  = 0x3de6,
                        .audioroute = 1,
-               },{
+               }, {
                        .type   = CX88_VMUX_SVIDEO,
                        .vmux   = 2,
                        .gpio0  = 0x3de6,
                        .audioroute = 1,
-               }},
+               } },
                .radio = {
                        .type   = CX88_RADIO,
                        .gpio0  = 0x3de6,
@@ -1171,19 +1171,19 @@ static const struct cx88_board cx88_boards[] = {
                .radio_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
-               .input          = {{
+               .input          = { {
                        .type   = CX88_VMUX_TELEVISION,
                        .vmux   = 0,
                        .gpio0  = 0x0000a75f,
-               },{
+               }, {
                        .type   = CX88_VMUX_COMPOSITE1,
                        .vmux   = 1,
                        .gpio0  = 0x0000a75b,
-               },{
+               }, {
                        .type   = CX88_VMUX_SVIDEO,
                        .vmux   = 2,
                        .gpio0  = 0x0000a75b,
-               }},
+               } },
                .mpeg           = CX88_MPEG_DVB,
        },
        [CX88_BOARD_PCHDTV_HD5500] = {
@@ -1193,19 +1193,19 @@ static const struct cx88_board cx88_boards[] = {
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
                .tda9887_conf   = TDA9887_PRESENT,
-               .input          = {{
+               .input          = { {
                        .type   = CX88_VMUX_TELEVISION,
                        .vmux   = 0,
                        .gpio0  = 0x87fd,
-               },{
+               }, {
                        .type   = CX88_VMUX_COMPOSITE1,
                        .vmux   = 1,
                        .gpio0  = 0x87f9,
-               },{
+               }, {
                        .type   = CX88_VMUX_SVIDEO,
                        .vmux   = 2,
                        .gpio0  = 0x87f9,
-               }},
+               } },
                .mpeg           = CX88_MPEG_DVB,
        },
        [CX88_BOARD_KWORLD_MCE200_DELUXE] = {
@@ -1217,11 +1217,11 @@ static const struct cx88_board cx88_boards[] = {
                .tda9887_conf   = TDA9887_PRESENT,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
-               .input          = {{
+               .input          = { {
                        .type   = CX88_VMUX_TELEVISION,
                        .vmux   = 0,
                        .gpio0  = 0x0000BDE6
-               }},
+               } },
                .mpeg           = CX88_MPEG_BLACKBIRD,
        },
        [CX88_BOARD_PIXELVIEW_PLAYTV_P7000] = {
@@ -1233,11 +1233,11 @@ static const struct cx88_board cx88_boards[] = {
                .radio_addr     = ADDR_UNSET,
                .tda9887_conf   = TDA9887_PRESENT | TDA9887_PORT1_ACTIVE |
                                  TDA9887_PORT2_ACTIVE,
-               .input          = {{
+               .input          = { {
                        .type   = CX88_VMUX_TELEVISION,
                        .vmux   = 0,
                        .gpio0  = 0x5da6,
-               }},
+               } },
                .mpeg           = CX88_MPEG_BLACKBIRD,
        },
        [CX88_BOARD_NPGTECH_REALTV_TOP10FM] = {
@@ -1246,19 +1246,19 @@ static const struct cx88_board cx88_boards[] = {
                .radio_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
-               .input          = {{
+               .input          = { {
                        .type   = CX88_VMUX_TELEVISION,
                        .vmux   = 0,
                        .gpio0  = 0x0788,
-               },{
+               }, {
                        .type   = CX88_VMUX_COMPOSITE1,
                        .vmux   = 1,
                        .gpio0  = 0x078b,
-               },{
+               }, {
                        .type   = CX88_VMUX_SVIDEO,
                        .vmux   = 2,
                        .gpio0  = 0x078b,
-               }},
+               } },
                .radio = {
                         .type  = CX88_RADIO,
                         .gpio0 = 0x074a,
@@ -1271,7 +1271,7 @@ static const struct cx88_board cx88_boards[] = {
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
                .tda9887_conf   = TDA9887_PRESENT,
-               .input          = {{
+               .input          = { {
                        .type   = CX88_VMUX_TELEVISION,
                        .vmux   = 0,
                        .gpio0  = 0x00017304,
@@ -1299,7 +1299,7 @@ static const struct cx88_board cx88_boards[] = {
                        .gpio1  = 0x0000b207,
                        .gpio2  = 0x0001d701,
                        .gpio3  = 0x02000000,
-               }},
+               } },
                .radio = {
                         .type  = CX88_RADIO,
                         .gpio0 = 0x00015702,
@@ -1316,35 +1316,35 @@ static const struct cx88_board cx88_boards[] = {
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
                .tda9887_conf   = TDA9887_PRESENT,
-               .input          = {{
+               .input          = { {
                        .type   = CX88_VMUX_TELEVISION,
                        .vmux   = 0,
                        .gpio0  = 0x00017300,
                        .gpio1  = 0x00008207,
                        .gpio2  = 0x00000000,
                        .gpio3  = 0x02000000,
-               },{
+               }, {
                        .type   = CX88_VMUX_TELEVISION,
                        .vmux   = 0,
                        .gpio0  = 0x00018300,
                        .gpio1  = 0x0000f207,
                        .gpio2  = 0x00017304,
                        .gpio3  = 0x02000000,
-               },{
+               }, {
                        .type   = CX88_VMUX_COMPOSITE1,
                        .vmux   = 1,
                        .gpio0  = 0x00018301,
                        .gpio1  = 0x0000f207,
                        .gpio2  = 0x00017304,
                        .gpio3  = 0x02000000,
-               },{
+               }, {
                        .type   = CX88_VMUX_SVIDEO,
                        .vmux   = 2,
                        .gpio0  = 0x00018301,
                        .gpio1  = 0x0000f207,
                        .gpio2  = 0x00017304,
                        .gpio3  = 0x02000000,
-               }},
+               } },
                .radio = {
                         .type  = CX88_RADIO,
                         .gpio0 = 0x00015702,
@@ -1360,13 +1360,13 @@ static const struct cx88_board cx88_boards[] = {
                .radio_type    = UNSET,
                .tuner_addr    = ADDR_UNSET,
                .radio_addr    = ADDR_UNSET,
-               .input  = {{
+               .input  = { {
                        .type  = CX88_VMUX_DVB,
                        .vmux  = 0,
-               },{
+               }, {
                        .type  = CX88_VMUX_COMPOSITE1,
                        .vmux  = 1,
-               }},
+               } },
                .mpeg           = CX88_MPEG_DVB,
        },
        [CX88_BOARD_HAUPPAUGE_HVR3000] = {
@@ -1377,25 +1377,25 @@ static const struct cx88_board cx88_boards[] = {
                .radio_addr     = ADDR_UNSET,
                .tda9887_conf   = TDA9887_PRESENT,
                .audio_chip     = CX88_AUDIO_WM8775,
-               .input          = {{
+               .input          = { {
                        .type   = CX88_VMUX_TELEVISION,
                        .vmux   = 0,
                        .gpio0  = 0x84bf,
                        /* 1: TV Audio / FM Mono */
                        .audioroute = 1,
-               },{
+               }, {
                        .type   = CX88_VMUX_COMPOSITE1,
                        .vmux   = 1,
                        .gpio0  = 0x84bf,
                        /* 2: Line-In */
                        .audioroute = 2,
-               },{
+               }, {
                        .type   = CX88_VMUX_SVIDEO,
                        .vmux   = 2,
                        .gpio0  = 0x84bf,
                        /* 2: Line-In */
                        .audioroute = 2,
-               }},
+               } },
                .radio = {
                        .type   = CX88_RADIO,
                        .gpio0  = 0x84bf,
@@ -1411,19 +1411,19 @@ static const struct cx88_board cx88_boards[] = {
                .radio_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
-               .input          = {{
+               .input          = { {
                        .type   = CX88_VMUX_TELEVISION,
                        .vmux   = 0,
                        .gpio0  = 0x0709,
-               },{
+               }, {
                        .type   = CX88_VMUX_COMPOSITE1,
                        .vmux   = 1,
                        .gpio0  = 0x070b,
-               },{
+               }, {
                        .type   = CX88_VMUX_SVIDEO,
                        .vmux   = 2,
                        .gpio0  = 0x070b,
-               }},
+               } },
        },
        [CX88_BOARD_TE_DTV_250_OEM_SWANN] = {
                .name           = "Shenzhen Tungsten Ages Tech TE-DTV-250 / Swann OEM",
@@ -1431,28 +1431,28 @@ static const struct cx88_board cx88_boards[] = {
                .radio_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
-               .input          = {{
+               .input          = { {
                        .type   = CX88_VMUX_TELEVISION,
                        .vmux   = 0,
                        .gpio0  = 0x003fffff,
                        .gpio1  = 0x00e00000,
                        .gpio2  = 0x003fffff,
                        .gpio3  = 0x02000000,
-               },{
+               }, {
                        .type   = CX88_VMUX_COMPOSITE1,
                        .vmux   = 1,
                        .gpio0  = 0x003fffff,
                        .gpio1  = 0x00e00000,
                        .gpio2  = 0x003fffff,
                        .gpio3  = 0x02000000,
-               },{
+               }, {
                        .type   = CX88_VMUX_SVIDEO,
                        .vmux   = 2,
                        .gpio0  = 0x003fffff,
                        .gpio1  = 0x00e00000,
                        .gpio2  = 0x003fffff,
                        .gpio3  = 0x02000000,
-               }},
+               } },
        },
        [CX88_BOARD_HAUPPAUGE_HVR1300] = {
                .name           = "Hauppauge WinTV-HVR1300 DVB-T/Hybrid MPEG Encoder",
@@ -1465,25 +1465,25 @@ static const struct cx88_board cx88_boards[] = {
                /*
                 * gpio0 as reported by Mike Crash <mike AT mikecrash.com>
                 */
-               .input          = {{
+               .input          = { {
                        .type   = CX88_VMUX_TELEVISION,
                        .vmux   = 0,
                        .gpio0  = 0xef88,
                        /* 1: TV Audio / FM Mono */
                        .audioroute = 1,
-               },{
+               }, {
                        .type   = CX88_VMUX_COMPOSITE1,
                        .vmux   = 1,
                        .gpio0  = 0xef88,
                        /* 2: Line-In */
                        .audioroute = 2,
-               },{
+               }, {
                        .type   = CX88_VMUX_SVIDEO,
                        .vmux   = 2,
                        .gpio0  = 0xef88,
                        /* 2: Line-In */
                        .audioroute = 2,
-               }},
+               } },
                .mpeg           = CX88_MPEG_DVB | CX88_MPEG_BLACKBIRD,
                .radio = {
                        .type   = CX88_RADIO,
@@ -1510,19 +1510,19 @@ static const struct cx88_board cx88_boards[] = {
                .radio_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
-               .input          = {{
+               .input          = { {
                        .type   = CX88_VMUX_DEBUG,
                        .vmux   = 3,
                        .gpio0  = 0x04ff,
-               },{
+               }, {
                        .type   = CX88_VMUX_COMPOSITE1,
                        .vmux   = 1,
                        .gpio0  = 0x07fa,
-               },{
+               }, {
                        .type   = CX88_VMUX_SVIDEO,
                        .vmux   = 2,
                        .gpio0  = 0x07fa,
-               }},
+               } },
        },
        [CX88_BOARD_PINNACLE_PCTV_HD_800i] = {
                .name           = "Pinnacle PCTV HD 800i",
@@ -1530,24 +1530,24 @@ static const struct cx88_board cx88_boards[] = {
                .radio_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
-               .input          = {{
+               .input          = { {
                        .type   = CX88_VMUX_TELEVISION,
                        .vmux   = 0,
                        .gpio0  = 0x04fb,
                        .gpio1  = 0x10ff,
-               },{
+               }, {
                        .type   = CX88_VMUX_COMPOSITE1,
                        .vmux   = 1,
                        .gpio0  = 0x04fb,
                        .gpio1  = 0x10ef,
                        .audioroute = 1,
-               },{
+               }, {
                        .type   = CX88_VMUX_SVIDEO,
                        .vmux   = 2,
                        .gpio0  = 0x04fb,
                        .gpio1  = 0x10ef,
                        .audioroute = 1,
-               }},
+               } },
                .mpeg           = CX88_MPEG_DVB,
        },
        [CX88_BOARD_DVICO_FUSIONHDTV_5_PCI_NANO] = {
@@ -1557,7 +1557,7 @@ static const struct cx88_board cx88_boards[] = {
                .radio_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
-               .input          = {{
+               .input          = { {
                        .type   = CX88_VMUX_TELEVISION,
                        .vmux   = 0,
                        .gpio0  = 0x000027df, /* Unconfirmed */
@@ -1815,19 +1815,19 @@ static const struct cx88_board cx88_boards[] = {
                .radio_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
-               .input          = {{
+               .input          = { {
                        .type   = CX88_VMUX_TELEVISION,
                        .vmux   = 0,
                        .gpio0  = 0x10df,
-               },{
+               }, {
                        .type   = CX88_VMUX_COMPOSITE1,
                        .vmux   = 1,
                        .gpio0  = 0x16d9,
-               },{
+               }, {
                        .type   = CX88_VMUX_SVIDEO,
                        .vmux   = 2,
                        .gpio0  = 0x16d9,
-               }},
+               } },
                .mpeg           = CX88_MPEG_DVB,
        },
        [CX88_BOARD_PROLINK_PV_8000GT] = {
@@ -1967,7 +1967,7 @@ static const struct cx88_board cx88_boards[] = {
                 * 3: Line-In Expansion
                 * 4: FM Stereo
                 */
-               .input          = {{
+               .input          = { {
                        .type   = CX88_VMUX_TELEVISION,
                        .vmux   = 0,
                        .gpio0  = 0xc4bf,
@@ -2001,7 +2001,7 @@ static const struct cx88_board cx88_boards[] = {
                .radio_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
-               .input          = {{
+               .input          = { {
                        .type   = CX88_VMUX_DVB,
                        .vmux   = 0,
                } },
@@ -2013,7 +2013,7 @@ static const struct cx88_board cx88_boards[] = {
                .radio_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
-               .input          = {{
+               .input          = { {
                        .type   = CX88_VMUX_DVB,
                        .vmux   = 0,
                } },
@@ -2025,7 +2025,7 @@ static const struct cx88_board cx88_boards[] = {
                .radio_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
-               .input          = {{
+               .input          = { {
                        .type   = CX88_VMUX_DVB,
                        .vmux   = 0,
                } },
@@ -2037,7 +2037,7 @@ static const struct cx88_board cx88_boards[] = {
                .radio_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
-               .input          = {{
+               .input          = { {
                        .type   = CX88_VMUX_DVB,
                        .vmux   = 0,
                } },
@@ -2049,7 +2049,7 @@ static const struct cx88_board cx88_boards[] = {
                .radio_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
-               .input          = {{
+               .input          = { {
                        .type   = CX88_VMUX_DVB,
                        .vmux   = 0,
                } },
@@ -2061,7 +2061,7 @@ static const struct cx88_board cx88_boards[] = {
                .radio_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
-               .input          = {{
+               .input          = { {
                        .type   = CX88_VMUX_DVB,
                        .vmux   = 0,
                } },
@@ -2073,7 +2073,7 @@ static const struct cx88_board cx88_boards[] = {
                .radio_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
-               .input          = {{
+               .input          = { {
                        .type   = CX88_VMUX_DVB,
                        .vmux   = 0,
                        .gpio0  = 0x8080,
@@ -2086,7 +2086,7 @@ static const struct cx88_board cx88_boards[] = {
                .radio_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
-               .input          = {{
+               .input          = { {
                        .type   = CX88_VMUX_DVB,
                        .vmux   = 0,
                } },
@@ -2098,7 +2098,7 @@ static const struct cx88_board cx88_boards[] = {
                .radio_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
-               .input          = {{
+               .input          = { {
                        .type   = CX88_VMUX_DVB,
                        .vmux   = 0,
                } },
@@ -2110,7 +2110,7 @@ static const struct cx88_board cx88_boards[] = {
                .radio_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
-               .input          = {{
+               .input          = { {
                        .type   = CX88_VMUX_DVB,
                        .vmux   = 0,
                } },
@@ -2170,7 +2170,7 @@ static const struct cx88_board cx88_boards[] = {
                 * 13: audio source (0=tuner audio,1=line in)
                 * 14: FM (0=on,1=off ???)
                 */
-               .input          = {{
+               .input          = { {
                        .type   = CX88_VMUX_TELEVISION,
                        .vmux   = 0,
                        .gpio0  = 0x0400,       /* pin 2 = 0 */
@@ -2211,7 +2211,7 @@ static const struct cx88_board cx88_boards[] = {
                 * 13: audio source (0=tuner audio,1=line in)
                 * 14: FM (0=on,1=off ???)
                 */
-               .input          = {{
+               .input          = { {
                        .type   = CX88_VMUX_TELEVISION,
                        .vmux   = 0,
                        .gpio0  = 0x0400,       /* pin 2 = 0 */
@@ -2229,7 +2229,7 @@ static const struct cx88_board cx88_boards[] = {
                        .gpio0  = 0x0400,       /* pin 2 = 0 */
                        .gpio1  = 0x6060,       /* pin 13 = 1, pin 14 = 1 */
                        .gpio2  = 0x0000,
-               }},
+               } },
                .radio = {
                        .type   = CX88_RADIO,
                        .gpio0  = 0x0400,       /* pin 2 = 0 */
@@ -2252,7 +2252,7 @@ static const struct cx88_board cx88_boards[] = {
                 *  14: 0: FM radio
                 *  16: 0: RF input is cable
                 */
-               .input          = {{
+               .input          = { {
                        .type   = CX88_VMUX_TELEVISION,
                        .vmux   = 0,
                        .gpio0  = 0x0403,
@@ -2280,7 +2280,7 @@ static const struct cx88_board cx88_boards[] = {
                        .gpio1  = 0xF0F7,
                        .gpio2  = 0x0101,
                        .gpio3  = 0x0000,
-               }},
+               } },
                .radio = {
                        .type   = CX88_RADIO,
                        .gpio0  = 0x0403,
@@ -2308,7 +2308,7 @@ static const struct cx88_board cx88_boards[] = {
                .radio_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
-               .input          = {{
+               .input          = { {
                       .type   = CX88_VMUX_DVB,
                       .vmux   = 0,
                } },
@@ -2324,19 +2324,19 @@ static const struct cx88_subid cx88_subids[] = {
                .subvendor = 0x0070,
                .subdevice = 0x3400,
                .card      = CX88_BOARD_HAUPPAUGE,
-       },{
+       }, {
                .subvendor = 0x0070,
                .subdevice = 0x3401,
                .card      = CX88_BOARD_HAUPPAUGE,
-       },{
+       }, {
                .subvendor = 0x14c7,
                .subdevice = 0x0106,
                .card      = CX88_BOARD_GDI,
-       },{
+       }, {
                .subvendor = 0x14c7,
                .subdevice = 0x0107, /* with mpeg encoder */
                .card      = CX88_BOARD_GDI,
-       },{
+       }, {
                .subvendor = PCI_VENDOR_ID_ATI,
                .subdevice = 0x00f8,
                .card      = CX88_BOARD_ATI_WONDER_PRO,
@@ -2348,176 +2348,176 @@ static const struct cx88_subid cx88_subids[] = {
                .subvendor = 0x107d,
                .subdevice = 0x6611,
                .card      = CX88_BOARD_WINFAST2000XP_EXPERT,
-       },{
+       }, {
                .subvendor = 0x107d,
                .subdevice = 0x6613,    /* NTSC */
                .card      = CX88_BOARD_WINFAST2000XP_EXPERT,
-       },{
+       }, {
                .subvendor = 0x107d,
                .subdevice = 0x6620,
                .card      = CX88_BOARD_WINFAST_DV2000,
-       },{
+       }, {
                .subvendor = 0x107d,
                .subdevice = 0x663b,
                .card      = CX88_BOARD_LEADTEK_PVR2000,
-       },{
+       }, {
                .subvendor = 0x107d,
                .subdevice = 0x663c,
                .card      = CX88_BOARD_LEADTEK_PVR2000,
-       },{
+       }, {
                .subvendor = 0x1461,
                .subdevice = 0x000b,
                .card      = CX88_BOARD_AVERTV_STUDIO_303,
-       },{
+       }, {
                .subvendor = 0x1462,
                .subdevice = 0x8606,
                .card      = CX88_BOARD_MSI_TVANYWHERE_MASTER,
-       },{
+       }, {
                .subvendor = 0x10fc,
                .subdevice = 0xd003,
                .card      = CX88_BOARD_IODATA_GVVCP3PCI,
-       },{
+       }, {
                .subvendor = 0x1043,
                .subdevice = 0x4823,  /* with mpeg encoder */
                .card      = CX88_BOARD_ASUS_PVR_416,
-       },{
+       }, {
                .subvendor = 0x17de,
                .subdevice = 0x08a6,
                .card      = CX88_BOARD_KWORLD_DVB_T,
-       },{
+       }, {
                .subvendor = 0x18ac,
                .subdevice = 0xd810,
                .card      = CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_Q,
-       },{
+       }, {
                .subvendor = 0x18ac,
                .subdevice = 0xd820,
                .card      = CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_T,
-       },{
+       }, {
                .subvendor = 0x18ac,
                .subdevice = 0xdb00,
                .card      = CX88_BOARD_DVICO_FUSIONHDTV_DVB_T1,
-       },{
+       }, {
                .subvendor = 0x0070,
                .subdevice = 0x9002,
                .card      = CX88_BOARD_HAUPPAUGE_DVB_T1,
-       },{
+       }, {
                .subvendor = 0x14f1,
                .subdevice = 0x0187,
                .card      = CX88_BOARD_CONEXANT_DVB_T1,
-       },{
+       }, {
                .subvendor = 0x1540,
                .subdevice = 0x2580,
                .card      = CX88_BOARD_PROVIDEO_PV259,
-       },{
+       }, {
                .subvendor = 0x18ac,
                .subdevice = 0xdb10,
                .card      = CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PLUS,
-       },{
+       }, {
                .subvendor = 0x1554,
                .subdevice = 0x4811,
                .card      = CX88_BOARD_PIXELVIEW,
-       },{
+       }, {
                .subvendor = 0x7063,
                .subdevice = 0x3000, /* HD-3000 card */
                .card      = CX88_BOARD_PCHDTV_HD3000,
-       },{
+       }, {
                .subvendor = 0x17de,
                .subdevice = 0xa8a6,
                .card      = CX88_BOARD_DNTV_LIVE_DVB_T,
-       },{
+       }, {
                .subvendor = 0x0070,
                .subdevice = 0x2801,
                .card      = CX88_BOARD_HAUPPAUGE_ROSLYN,
-       },{
+       }, {
                .subvendor = 0x14f1,
                .subdevice = 0x0342,
                .card      = CX88_BOARD_DIGITALLOGIC_MEC,
-       },{
+       }, {
                .subvendor = 0x10fc,
                .subdevice = 0xd035,
                .card      = CX88_BOARD_IODATA_GVBCTV7E,
-       },{
+       }, {
                .subvendor = 0x1421,
                .subdevice = 0x0334,
                .card      = CX88_BOARD_ADSTECH_DVB_T_PCI,
-       },{
+       }, {
                .subvendor = 0x153b,
                .subdevice = 0x1166,
                .card      = CX88_BOARD_TERRATEC_CINERGY_1400_DVB_T1,
-       },{
+       }, {
                .subvendor = 0x18ac,
                .subdevice = 0xd500,
                .card      = CX88_BOARD_DVICO_FUSIONHDTV_5_GOLD,
-       },{
+       }, {
                .subvendor = 0x1461,
                .subdevice = 0x8011,
                .card      = CX88_BOARD_AVERMEDIA_ULTRATV_MC_550,
-       },{
+       }, {
                .subvendor = PCI_VENDOR_ID_ATI,
                .subdevice = 0xa101,
                .card      = CX88_BOARD_ATI_HDTVWONDER,
-       },{
+       }, {
                .subvendor = 0x107d,
                .subdevice = 0x665f,
                .card      = CX88_BOARD_WINFAST_DTV1000,
-       },{
+       }, {
                .subvendor = 0x1461,
                .subdevice = 0x000a,
                .card      = CX88_BOARD_AVERTV_303,
-       },{
+       }, {
                .subvendor = 0x0070,
                .subdevice = 0x9200,
                .card      = CX88_BOARD_HAUPPAUGE_NOVASE2_S1,
-       },{
+       }, {
                .subvendor = 0x0070,
                .subdevice = 0x9201,
                .card      = CX88_BOARD_HAUPPAUGE_NOVASPLUS_S1,
-       },{
+       }, {
                .subvendor = 0x0070,
                .subdevice = 0x9202,
                .card      = CX88_BOARD_HAUPPAUGE_NOVASPLUS_S1,
-       },{
+       }, {
                .subvendor = 0x17de,
                .subdevice = 0x08b2,
                .card      = CX88_BOARD_KWORLD_DVBS_100,
-       },{
+       }, {
                .subvendor = 0x0070,
                .subdevice = 0x9400,
                .card      = CX88_BOARD_HAUPPAUGE_HVR1100,
-       },{
+       }, {
                .subvendor = 0x0070,
                .subdevice = 0x9402,
                .card      = CX88_BOARD_HAUPPAUGE_HVR1100,
-       },{
+       }, {
                .subvendor = 0x0070,
                .subdevice = 0x9800,
                .card      = CX88_BOARD_HAUPPAUGE_HVR1100LP,
-       },{
+       }, {
                .subvendor = 0x0070,
                .subdevice = 0x9802,
                .card      = CX88_BOARD_HAUPPAUGE_HVR1100LP,
-       },{
+       }, {
                .subvendor = 0x0070,
                .subdevice = 0x9001,
                .card      = CX88_BOARD_HAUPPAUGE_DVB_T1,
-       },{
+       }, {
                .subvendor = 0x1822,
                .subdevice = 0x0025,
                .card      = CX88_BOARD_DNTV_LIVE_DVB_T_PRO,
-       },{
+       }, {
                .subvendor = 0x17de,
                .subdevice = 0x08a1,
                .card      = CX88_BOARD_KWORLD_DVB_T_CX22702,
-       },{
+       }, {
                .subvendor = 0x18ac,
                .subdevice = 0xdb50,
                .card      = CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL,
-       },{
+       }, {
                .subvendor = 0x18ac,
                .subdevice = 0xdb54,
                .card      = CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL,
                /* Re-branded DViCO: DigitalNow DVB-T Dual */
-       },{
+       }, {
                .subvendor = 0x18ac,
                .subdevice = 0xdb11,
                .card      = CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PLUS,
@@ -2530,55 +2530,55 @@ static const struct cx88_subid cx88_subids[] = {
                .subvendor = 0x17de,
                .subdevice = 0x0840,
                .card      = CX88_BOARD_KWORLD_HARDWARE_MPEG_TV_XPERT,
-       },{
+       }, {
                .subvendor = 0x1421,
                .subdevice = 0x0305,
                .card      = CX88_BOARD_KWORLD_HARDWARE_MPEG_TV_XPERT,
-       },{
+       }, {
                .subvendor = 0x18ac,
                .subdevice = 0xdb40,
                .card      = CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_HYBRID,
-       },{
+       }, {
                .subvendor = 0x18ac,
                .subdevice = 0xdb44,
                .card      = CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_HYBRID,
-       },{
+       }, {
                .subvendor = 0x7063,
                .subdevice = 0x5500,
                .card      = CX88_BOARD_PCHDTV_HD5500,
-       },{
+       }, {
                .subvendor = 0x17de,
                .subdevice = 0x0841,
                .card      = CX88_BOARD_KWORLD_MCE200_DELUXE,
-       },{
+       }, {
                .subvendor = 0x1822,
                .subdevice = 0x0019,
                .card      = CX88_BOARD_DNTV_LIVE_DVB_T_PRO,
-       },{
+       }, {
                .subvendor = 0x1554,
                .subdevice = 0x4813,
                .card      = CX88_BOARD_PIXELVIEW_PLAYTV_P7000,
-       },{
+       }, {
                .subvendor = 0x14f1,
                .subdevice = 0x0842,
                .card      = CX88_BOARD_NPGTECH_REALTV_TOP10FM,
-       },{
+       }, {
                .subvendor = 0x107d,
                .subdevice = 0x665e,
                .card      = CX88_BOARD_WINFAST_DTV2000H,
-       },{
+       }, {
                .subvendor = 0x107d,
                .subdevice = 0x6f2b,
                .card      = CX88_BOARD_WINFAST_DTV2000H_J,
-       },{
+       }, {
                .subvendor = 0x18ac,
                .subdevice = 0xd800, /* FusionHDTV 3 Gold (original revision) */
                .card      = CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_Q,
-       },{
+       }, {
                .subvendor = 0x14f1,
                .subdevice = 0x0084,
                .card      = CX88_BOARD_GENIATECH_DVBS,
-       },{
+       }, {
                .subvendor = 0x0070,
                .subdevice = 0x1404,
                .card      = CX88_BOARD_HAUPPAUGE_HVR3000,
@@ -2590,60 +2590,60 @@ static const struct cx88_subid cx88_subids[] = {
                .subvendor = 0x18ac,
                .subdevice = 0xdccd,
                .card      = CX88_BOARD_SAMSUNG_SMT_7020,
-       },{
+       }, {
                .subvendor = 0x1461,
                .subdevice = 0xc111, /* AverMedia M150-D */
                /* This board is known to work with the ASUS PVR416 config */
                .card      = CX88_BOARD_ASUS_PVR_416,
-       },{
+       }, {
                .subvendor = 0xc180,
                .subdevice = 0xc980,
                .card      = CX88_BOARD_TE_DTV_250_OEM_SWANN,
-       },{
+       }, {
                .subvendor = 0x0070,
                .subdevice = 0x9600,
                .card      = CX88_BOARD_HAUPPAUGE_HVR1300,
-       },{
+       }, {
                .subvendor = 0x0070,
                .subdevice = 0x9601,
                .card      = CX88_BOARD_HAUPPAUGE_HVR1300,
-       },{
+       }, {
                .subvendor = 0x0070,
                .subdevice = 0x9602,
                .card      = CX88_BOARD_HAUPPAUGE_HVR1300,
-       },{
+       }, {
                .subvendor = 0x107d,
                .subdevice = 0x6632,
                .card      = CX88_BOARD_LEADTEK_PVR2000,
-       },{
+       }, {
                .subvendor = 0x12ab,
                .subdevice = 0x2300, /* Club3D Zap TV2100 */
                .card      = CX88_BOARD_KWORLD_DVB_T_CX22702,
-       },{
+       }, {
                .subvendor = 0x0070,
                .subdevice = 0x9000,
                .card      = CX88_BOARD_HAUPPAUGE_DVB_T1,
-       },{
+       }, {
                .subvendor = 0x0070,
                .subdevice = 0x1400,
                .card      = CX88_BOARD_HAUPPAUGE_HVR3000,
-       },{
+       }, {
                .subvendor = 0x0070,
                .subdevice = 0x1401,
                .card      = CX88_BOARD_HAUPPAUGE_HVR3000,
-       },{
+       }, {
                .subvendor = 0x0070,
                .subdevice = 0x1402,
                .card      = CX88_BOARD_HAUPPAUGE_HVR3000,
-       },{
+       }, {
                .subvendor = 0x1421,
                .subdevice = 0x0341, /* ADS Tech InstantTV DVB-S */
                .card      = CX88_BOARD_KWORLD_DVBS_100,
-       },{
+       }, {
                .subvendor = 0x1421,
                .subdevice = 0x0390,
                .card      = CX88_BOARD_ADSTECH_PTV_390,
-       },{
+       }, {
                .subvendor = 0x11bd,
                .subdevice = 0x0051,
                .card      = CX88_BOARD_PINNACLE_PCTV_HD_800i,
index ed8cb9037b6f30f0876ea377c42db799a8dd0e51..ce27e6d4f16ea21df367c0e59930d2446ea82798 100644 (file)
@@ -696,7 +696,6 @@ static struct videobuf_queue *get_queue(struct file *file)
                return &fh->vbiq;
        default:
                BUG();
-               return NULL;
        }
 }
 
@@ -711,7 +710,6 @@ static int get_resource(struct file *file)
                return RESOURCE_VBI;
        default:
                BUG();
-               return 0;
        }
 }
 
@@ -812,7 +810,6 @@ video_read(struct file *file, char __user *data, size_t count, loff_t *ppos)
                                            file->f_flags & O_NONBLOCK);
        default:
                BUG();
-               return 0;
        }
 }
 
index da8f848be3b801cfee8ac6a1bba76b8de3da584f..c82e855a0814c87cf03782f1521915276686569a 100644 (file)
@@ -149,7 +149,7 @@ static u32 ddb_i2c_functionality(struct i2c_adapter *adap)
        return I2C_FUNC_SMBUS_EMUL;
 }
 
-struct i2c_algorithm ddb_i2c_algo = {
+static struct i2c_algorithm ddb_i2c_algo = {
        .master_xfer   = ddb_i2c_master_xfer,
        .functionality = ddb_i2c_functionality,
 };
@@ -266,7 +266,7 @@ static void io_free(struct pci_dev *pdev, u8 **vbuf,
        for (i = 0; i < num; i++) {
                if (vbuf[i]) {
                        pci_free_consistent(pdev, size, vbuf[i], pbuf[i]);
-                       vbuf[i] = 0;
+                       vbuf[i] = NULL;
                }
        }
 }
@@ -440,7 +440,7 @@ static u32 ddb_output_free(struct ddb_output *output)
 }
 
 static ssize_t ddb_output_write(struct ddb_output *output,
-                               const u8 *buf, size_t count)
+                               const __user u8 *buf, size_t count)
 {
        struct ddb *dev = output->port->dev;
        u32 idx, off, stat = output->stat;
@@ -506,7 +506,7 @@ static u32 ddb_input_avail(struct ddb_input *input)
        return 0;
 }
 
-static ssize_t ddb_input_read(struct ddb_input *input, u8 *buf, size_t count)
+static ssize_t ddb_input_read(struct ddb_input *input, __user u8 *buf, size_t count)
 {
        struct ddb *dev = input->port->dev;
        u32 left = count;
@@ -849,7 +849,7 @@ static int dvb_input_attach(struct ddb_input *input)
                return ret;
        input->attached = 4;
 
-       input->fe = 0;
+       input->fe = NULL;
        switch (port->type) {
        case DDB_TUNER_DVBS_ST:
                if (demod_attach_stv0900(input, 0) < 0)
@@ -895,7 +895,7 @@ static int dvb_input_attach(struct ddb_input *input)
 /****************************************************************************/
 /****************************************************************************/
 
-static ssize_t ts_write(struct file *file, const char *buf,
+static ssize_t ts_write(struct file *file, const __user char *buf,
                        size_t count, loff_t *ppos)
 {
        struct dvb_device *dvbdev = file->private_data;
@@ -920,7 +920,7 @@ static ssize_t ts_write(struct file *file, const char *buf,
        return (left == count) ? -EAGAIN : (count - left);
 }
 
-static ssize_t ts_read(struct file *file, char *buf,
+static ssize_t ts_read(struct file *file, __user char *buf,
                       size_t count, loff_t *ppos)
 {
        struct dvb_device *dvbdev = file->private_data;
@@ -975,11 +975,9 @@ static const struct file_operations ci_fops = {
        .open    = dvb_generic_open,
        .release = dvb_generic_release,
        .poll    = ts_poll,
-       .mmap    = 0,
 };
 
 static struct dvb_device dvbdev_ci = {
-       .priv    = 0,
        .readers = -1,
        .writers = -1,
        .users   = -1,
@@ -1038,7 +1036,7 @@ static void output_tasklet(unsigned long data)
 }
 
 
-struct cxd2099_cfg cxd_cfg = {
+static struct cxd2099_cfg cxd_cfg = {
        .bitrate =  62000,
        .adr     =  0x40,
        .polarity = 1,
@@ -1127,7 +1125,7 @@ static void ddb_ports_detach(struct ddb *dev)
                                ddb_output_stop(port->output);
                                dvb_ca_en50221_release(port->en);
                                kfree(port->en);
-                               port->en = 0;
+                               port->en = NULL;
                                dvb_unregister_adapter(&port->output->adap);
                        }
                        break;
@@ -1413,9 +1411,9 @@ static int flashio(struct ddb *dev, u8 *wbuf, u32 wlen, u8 *rbuf, u32 rlen)
 #define DDB_MAGIC 'd'
 
 struct ddb_flashio {
-       __u8 *write_buf;
+       __user __u8 *write_buf;
        __u32 write_len;
-       __u8 *read_buf;
+       __user __u8 *read_buf;
        __u32 read_len;
 };
 
@@ -1439,7 +1437,7 @@ static int ddb_open(struct inode *inode, struct file *file)
 static long ddb_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 {
        struct ddb *dev = file->private_data;
-       void *parg = (void *)arg;
+       __user void *parg = (__user void *)arg;
        int res;
 
        switch (cmd) {
@@ -1558,7 +1556,7 @@ static void ddb_remove(struct pci_dev *pdev)
        ddb_device_destroy(dev);
 
        ddb_unmap(dev);
-       pci_set_drvdata(pdev, 0);
+       pci_set_drvdata(pdev, NULL);
        pci_disable_device(pdev);
 }
 
@@ -1637,7 +1635,7 @@ fail1:
 fail:
        printk(KERN_ERR "fail\n");
        ddb_unmap(dev);
-       pci_set_drvdata(pdev, 0);
+       pci_set_drvdata(pdev, NULL);
        pci_disable_device(pdev);
        return -1;
 }
index 8b1b41d2a52d4d465b233d57755fc724d5f9ab56..be87fbd9045646214f61aeda2f573ba1e62b1462 100644 (file)
@@ -156,7 +156,7 @@ struct ddb_port {
 
 struct ddb {
        struct pci_dev        *pdev;
-       unsigned char         *regs;
+       unsigned char __iomem *regs;
        struct ddb_port        port[DDB_MAX_PORT];
        struct ddb_i2c         i2c[DDB_MAX_I2C];
        struct ddb_input       input[DDB_MAX_INPUT];
@@ -173,12 +173,10 @@ struct ddb {
 /****************************************************************************/
 
 #define ddbwritel(_val, _adr)        writel((_val), \
-                                    (char *) (dev->regs+(_adr)))
-#define ddbreadl(_adr)               readl((char *) (dev->regs+(_adr)))
-#define ddbcpyto(_adr, _src, _count) memcpy_toio((char *)      \
-                                    (dev->regs+(_adr)), (_src), (_count))
-#define ddbcpyfrom(_dst, _adr, _count) memcpy_fromio((_dst), (char *) \
-                                      (dev->regs+(_adr)), (_count))
+                                    dev->regs+(_adr))
+#define ddbreadl(_adr)               readl(dev->regs+(_adr))
+#define ddbcpyto(_adr, _src, _count) memcpy_toio(dev->regs+(_adr), (_src), (_count))
+#define ddbcpyfrom(_dst, _adr, _count) memcpy_fromio((_dst), dev->regs+(_adr), (_count))
 
 /****************************************************************************/
 
index e8826c535ccdb2980fc6e931831f2826bcb51161..ed11716731e95cdb6a51ce90b7df6c4de267e44d 100644 (file)
@@ -614,7 +614,7 @@ static int dm1105_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
 
 static void dm1105_set_dma_addr(struct dm1105_dev *dev)
 {
-       dm_writel(DM1105_STADR, cpu_to_le32(dev->dma_addr));
+       dm_writel(DM1105_STADR, (__force u32)cpu_to_le32(dev->dma_addr));
 }
 
 static int dm1105_dma_map(struct dm1105_dev *dev)
index 7a9b98bc208bc252ae9d1dc334fabb48bf39c5f5..7bf9cbca4fa64fe3e63c3d17ea7432e661069e85 100644 (file)
@@ -81,7 +81,7 @@ static void ivtv_alsa_announce_pcm_data(struct snd_ivtv_card *itvsc,
        int period_elapsed = 0;
        int length;
 
-       dprintk("ivtv alsa announce ptr=%p data=%p num_bytes=%zd\n", itvsc,
+       dprintk("ivtv alsa announce ptr=%p data=%p num_bytes=%zu\n", itvsc,
                pcm_data, num_bytes);
 
        substream = itvsc->capture_pcm_substream;
index ed73edd2bcd308e310197ac3ff9bff2559905bd5..4b0e758a7bce38d68deab9d55a1445e21fee201e 100644 (file)
@@ -65,7 +65,7 @@ retry:
                           the wrong file was sometimes loaded. So we check filesizes to
                           see if at least the right-sized file was loaded. If not, then we
                           retry. */
-                       IVTV_INFO("Retry: file loaded was not %s (expected size %ld, got %zd)\n", fn, size, fw->size);
+                       IVTV_INFO("Retry: file loaded was not %s (expected size %ld, got %zu)\n", fn, size, fw->size);
                        release_firmware(fw);
                        retries--;
                        goto retry;
@@ -76,7 +76,7 @@ retry:
                        dst++;
                        src++;
                }
-               IVTV_INFO("Loaded %s firmware (%zd bytes)\n", fn, fw->size);
+               IVTV_INFO("Loaded %s firmware (%zu bytes)\n", fn, fw->size);
                release_firmware(fw);
                return size;
        }
index 19a7c9b990a393b93adb27818d069560f1027bda..ab6d5d25aa6fdd1a757814c18318dc5881e47a41 100644 (file)
@@ -192,11 +192,11 @@ static int stream_enc_dma_append(struct ivtv_stream *s, u32 data[CX2341X_MBOX_MA
                if (itv->has_cx23415 && (s->type == IVTV_ENC_STREAM_TYPE_PCM ||
                    s->type == IVTV_DEC_STREAM_TYPE_VBI)) {
                        s->pending_backup = read_dec(offset - IVTV_DECODER_OFFSET);
-                       write_dec_sync(cpu_to_le32(DMA_MAGIC_COOKIE), offset - IVTV_DECODER_OFFSET);
+                       write_dec_sync(DMA_MAGIC_COOKIE, offset - IVTV_DECODER_OFFSET);
                }
                else {
                        s->pending_backup = read_enc(offset);
-                       write_enc_sync(cpu_to_le32(DMA_MAGIC_COOKIE), offset);
+                       write_enc_sync(DMA_MAGIC_COOKIE, offset);
                }
                s->pending_offset = offset;
        }
@@ -275,13 +275,11 @@ static void dma_post(struct ivtv_stream *s)
 
                if (x == 0 && ivtv_use_dma(s)) {
                        offset = s->dma_last_offset;
-                       if (u32buf[offset / 4] != DMA_MAGIC_COOKIE)
+                       if (le32_to_cpu(u32buf[offset / 4]) != DMA_MAGIC_COOKIE)
                        {
-                               for (offset = 0; offset < 64; offset++) {
-                                       if (u32buf[offset] == DMA_MAGIC_COOKIE) {
+                               for (offset = 0; offset < 64; offset++)
+                                       if (le32_to_cpu(u32buf[offset]) == DMA_MAGIC_COOKIE)
                                                break;
-                                       }
-                               }
                                offset *= 4;
                                if (offset == 256) {
                                        IVTV_DEBUG_WARN("%s: Couldn't find start of buffer within the first 256 bytes\n", s->name);
index 68a29f8bdf732b1e7bad70cba5afb5f365c86e6e..1032db6bb789548633cf9c62cac0d8b7307fe1a7 100644 (file)
@@ -34,7 +34,7 @@
 #include "mantis_dvb.h"
 #include "hopper_vp3028.h"
 
-struct zl10353_config hopper_vp3028_config = {
+static struct zl10353_config hopper_vp3028_config = {
        .demod_address  = 0x0f,
 };
 
index f2410cf0a6bf0ec980b475f8785d5afb7a58ec52..8ff448bb792d796f6a58273ca247a34487f7e459 100644 (file)
@@ -127,7 +127,7 @@ struct mantis_pci {
        u32                     last_block;
        u8                      *buf_cpu;
        dma_addr_t              buf_dma;
-       u32                     *risc_cpu;
+       __le32                  *risc_cpu;
        dma_addr_t              risc_dma;
 
        struct tasklet_struct   tasklet;
index 115003e8d19d453f30a2db59664d3a561c614116..12a6adb2bd7e167cc575abc04588ca018a4b39b7 100644 (file)
@@ -35,7 +35,7 @@
 #include "mantis_vp1033.h"
 #include "mantis_reg.h"
 
-u8 lgtdqcs001f_inittab[] = {
+static u8 lgtdqcs001f_inittab[] = {
        0x01, 0x15,
        0x02, 0x30,
        0x03, 0x00,
@@ -150,7 +150,7 @@ static int lgtdqcs001f_set_symbol_rate(struct dvb_frontend *fe,
        return 0;
 }
 
-struct stv0299_config lgtdqcs001f_config = {
+static struct stv0299_config lgtdqcs001f_config = {
        .demod_address          = 0x68,
        .inittab                = lgtdqcs001f_inittab,
        .mclk                   = 88000000UL,
index 430ae84ce528dd99545b061929928233950dc845..7c1bd167225c28b3bf6c9819e7294e7e197a833d 100644 (file)
@@ -36,7 +36,7 @@
 #include "mantis_vp1034.h"
 #include "mantis_reg.h"
 
-struct mb86a16_config vp1034_mb86a16_config = {
+static struct mb86a16_config vp1034_mb86a16_config = {
        .demod_address  = 0x08,
        .set_voltage    = vp1034_set_voltage,
 };
index 07a20748b707ef5356bd40fac96dc891d974716e..7082fcbc94a1001d6412b3b704673c807144f8c1 100644 (file)
@@ -263,7 +263,7 @@ static const struct stb0899_s1_reg vp1041_stb0899_s1_init_3[] = {
        { 0xffff                        , 0xff },
 };
 
-struct stb0899_config vp1041_stb0899_config = {
+static struct stb0899_config vp1041_stb0899_config = {
        .init_dev               = vp1041_stb0899_s1_init_1,
        .init_s2_demod          = stb0899_s2_init_2,
        .init_s1_demod          = vp1041_stb0899_s1_init_3,
@@ -300,7 +300,7 @@ struct stb0899_config vp1041_stb0899_config = {
        .tuner_set_rfsiggain    = NULL,
 };
 
-struct stb6100_config vp1041_stb6100_config = {
+static struct stb6100_config vp1041_stb6100_config = {
        .tuner_address  = 0x60,
        .refclock       = 27000000,
 };
index 1ca6837fbe468a8da8f82fe7818a4240880e5004..8d48b5abe04a5eb42d3eb0586b85e6884751ca9f 100644 (file)
 #define MANTIS_MODEL_NAME      "VP-2033"
 #define MANTIS_DEV_TYPE                "DVB-C"
 
-struct tda1002x_config vp2033_tda1002x_cu1216_config = {
+static struct tda1002x_config vp2033_tda1002x_cu1216_config = {
        .demod_address = 0x18 >> 1,
        .invert = 1,
 };
 
-struct tda10023_config vp2033_tda10023_cu1216_config = {
+static struct tda10023_config vp2033_tda10023_cu1216_config = {
        .demod_address = 0x18 >> 1,
        .invert = 1,
 };
index d480741afd786dc3e13420077d43f4567f38e666..8dd17d7c08819b83dedf4110571223daa12f1025 100644 (file)
 #define MANTIS_MODEL_NAME      "VP-2040"
 #define MANTIS_DEV_TYPE                "DVB-C"
 
-struct tda1002x_config vp2040_tda1002x_cu1216_config = {
+static struct tda1002x_config vp2040_tda1002x_cu1216_config = {
        .demod_address  = 0x18 >> 1,
        .invert         = 1,
 };
 
-struct tda10023_config vp2040_tda10023_cu1216_config = {
+static struct tda10023_config vp2040_tda10023_cu1216_config = {
        .demod_address  = 0x18 >> 1,
        .invert         = 1,
 };
index c09308cd3ac677e0d53ace29e525039e3482dc04..5c1dd925bdd5000ed61dd59c6bcd24c76d5717c0 100644 (file)
 #include "mantis_dvb.h"
 #include "mantis_vp3030.h"
 
-struct zl10353_config mantis_vp3030_config = {
+static struct zl10353_config mantis_vp3030_config = {
        .demod_address          = 0x0f,
 };
 
-struct tda665x_config env57h12d5_config = {
+static struct tda665x_config env57h12d5_config = {
        .name                   = "ENV57H12D5 (ET-50DT)",
        .addr                   = 0x60,
        .frequency_min          =  47000000,
index 9e82d2105d5365659be6dd7560927066f6427235..039bed3cc919d2f5624e1635327e126abdfca064 100644 (file)
@@ -696,7 +696,7 @@ static struct ngene_info ngene_info_m780 = {
        .demod_attach   = { NULL, demod_attach_lg330x },
 
        /* Ensure these are NULL else the frame will call them (as funcs) */
-       .tuner_attach   = { 0, 0, 0, 0 },
+       .tuner_attach   = { NULL, NULL, NULL, NULL },
        .fe_config      = { NULL, &aver_m780 },
        .avf            = { 0 },
 
index 4930b55fd5f4f855399ebb6c828daece0c579ce8..e29bc3af4bafe3ad25a8e059c9d0697b12940874 100644 (file)
@@ -57,15 +57,13 @@ DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
 
 #define dprintk        if (debug) printk
 
-#define ngwriteb(dat, adr)         writeb((dat), (char *)(dev->iomem + (adr)))
-#define ngwritel(dat, adr)         writel((dat), (char *)(dev->iomem + (adr)))
-#define ngwriteb(dat, adr)         writeb((dat), (char *)(dev->iomem + (adr)))
+#define ngwriteb(dat, adr)         writeb((dat), dev->iomem + (adr))
+#define ngwritel(dat, adr)         writel((dat), dev->iomem + (adr))
+#define ngwriteb(dat, adr)         writeb((dat), dev->iomem + (adr))
 #define ngreadl(adr)               readl(dev->iomem + (adr))
 #define ngreadb(adr)               readb(dev->iomem + (adr))
-#define ngcpyto(adr, src, count)   memcpy_toio((char *) \
-                                  (dev->iomem + (adr)), (src), (count))
-#define ngcpyfrom(dst, adr, count) memcpy_fromio((dst), (char *) \
-                                  (dev->iomem + (adr)), (count))
+#define ngcpyto(adr, src, count)   memcpy_toio(dev->iomem + (adr), (src), (count))
+#define ngcpyfrom(dst, adr, count) memcpy_fromio((dst), dev->iomem + (adr), (count))
 
 /****************************************************************************/
 /* nGene interrupt handler **************************************************/
@@ -1592,7 +1590,7 @@ static void cxd_detach(struct ngene *dev)
 
        dvb_ca_en50221_release(ci->en);
        kfree(ci->en);
-       ci->en = 0;
+       ci->en = NULL;
 }
 
 /***********************************/
index fcb16a615aab002768f80b3e7d6c5cf66ac5f123..59bb2858c8d0127c8779f3323b8f1d1a25b832e2 100644 (file)
@@ -47,7 +47,7 @@
 /* COMMAND API interface ****************************************************/
 /****************************************************************************/
 
-static ssize_t ts_write(struct file *file, const char *buf,
+static ssize_t ts_write(struct file *file, const char __user *buf,
                        size_t count, loff_t *ppos)
 {
        struct dvb_device *dvbdev = file->private_data;
@@ -59,12 +59,12 @@ static ssize_t ts_write(struct file *file, const char *buf,
                                     (&dev->tsout_rbuf) >= count) < 0)
                return 0;
 
-       dvb_ringbuffer_write(&dev->tsout_rbuf, buf, count);
+       dvb_ringbuffer_write_user(&dev->tsout_rbuf, buf, count);
 
        return count;
 }
 
-static ssize_t ts_read(struct file *file, char *buf,
+static ssize_t ts_read(struct file *file, char __user *buf,
                       size_t count, loff_t *ppos)
 {
        struct dvb_device *dvbdev = file->private_data;
@@ -97,7 +97,6 @@ static const struct file_operations ci_fops = {
 };
 
 struct dvb_device ngene_dvbdev_ci = {
-       .priv    = 0,
        .readers = -1,
        .writers = -1,
        .users   = -1,
index 22c39ff6bfa0e90c278d08c0cbc84d156c8e5732..51e2fbd18b1b1532cd3d7c1ef83c3b258c75219d 100644 (file)
@@ -737,7 +737,7 @@ typedef void (tx_cb_t)(struct ngene *, u32);
 struct ngene {
        int                   nr;
        struct pci_dev       *pci_dev;
-       unsigned char        *iomem;
+       unsigned char __iomem *iomem;
 
        /*struct i2c_adapter  i2c_adapter;*/
 
diff --git a/drivers/media/pci/pt3/Kconfig b/drivers/media/pci/pt3/Kconfig
new file mode 100644 (file)
index 0000000..16c208a
--- /dev/null
@@ -0,0 +1,10 @@
+config DVB_PT3
+       tristate "Earthsoft PT3 cards"
+       depends on DVB_CORE && PCI && I2C
+       select DVB_TC90522 if MEDIA_SUBDRV_AUTOSELECT
+       select MEDIA_TUNER_QM1D1C0042 if MEDIA_SUBDRV_AUTOSELECT
+       select MEDIA_TUNER_MXL301RF if MEDIA_SUBDRV_AUTOSELECT
+       help
+         Support for Earthsoft PT3 PCIe cards.
+
+         Say Y or M if you own such a device and want to use it.
diff --git a/drivers/media/pci/pt3/Makefile b/drivers/media/pci/pt3/Makefile
new file mode 100644 (file)
index 0000000..396f146
--- /dev/null
@@ -0,0 +1,8 @@
+
+earth-pt3-objs += pt3.o pt3_i2c.o pt3_dma.o
+
+obj-$(CONFIG_DVB_PT3) += earth-pt3.o
+
+ccflags-y += -Idrivers/media/dvb-core
+ccflags-y += -Idrivers/media/dvb-frontends
+ccflags-y += -Idrivers/media/tuners
diff --git a/drivers/media/pci/pt3/pt3.c b/drivers/media/pci/pt3/pt3.c
new file mode 100644 (file)
index 0000000..1fdeac1
--- /dev/null
@@ -0,0 +1,876 @@
+/*
+ * Earthsoft PT3 driver
+ *
+ * Copyright (C) 2014 Akihiro Tsukada <tskd08@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2.
+ *
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/freezer.h>
+#include <linux/kernel.h>
+#include <linux/kthread.h>
+#include <linux/mutex.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/string.h>
+
+#include "dmxdev.h"
+#include "dvbdev.h"
+#include "dvb_demux.h"
+#include "dvb_frontend.h"
+
+#include "pt3.h"
+
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
+static bool one_adapter;
+module_param(one_adapter, bool, 0444);
+MODULE_PARM_DESC(one_adapter, "Place FE's together under one adapter.");
+
+static int num_bufs = 4;
+module_param(num_bufs, int, 0444);
+MODULE_PARM_DESC(num_bufs, "Number of DMA buffer (188KiB) per FE.");
+
+
+static const struct i2c_algorithm pt3_i2c_algo = {
+       .master_xfer   = &pt3_i2c_master_xfer,
+       .functionality = &pt3_i2c_functionality,
+};
+
+static const struct pt3_adap_config adap_conf[PT3_NUM_FE] = {
+       {
+               .demod_info = {
+                       I2C_BOARD_INFO(TC90522_I2C_DEV_SAT, 0x11),
+               },
+               .tuner_info = {
+                       I2C_BOARD_INFO("qm1d1c0042", 0x63),
+               },
+               .tuner_cfg.qm1d1c0042 = {
+                       .lpf = 1,
+               },
+               .init_freq = 1049480 - 300,
+       },
+       {
+               .demod_info = {
+                       I2C_BOARD_INFO(TC90522_I2C_DEV_TER, 0x10),
+               },
+               .tuner_info = {
+                       I2C_BOARD_INFO("mxl301rf", 0x62),
+               },
+               .init_freq = 515142857,
+       },
+       {
+               .demod_info = {
+                       I2C_BOARD_INFO(TC90522_I2C_DEV_SAT, 0x13),
+               },
+               .tuner_info = {
+                       I2C_BOARD_INFO("qm1d1c0042", 0x60),
+               },
+               .tuner_cfg.qm1d1c0042 = {
+                       .lpf = 1,
+               },
+               .init_freq = 1049480 + 300,
+       },
+       {
+               .demod_info = {
+                       I2C_BOARD_INFO(TC90522_I2C_DEV_TER, 0x12),
+               },
+               .tuner_info = {
+                       I2C_BOARD_INFO("mxl301rf", 0x61),
+               },
+               .init_freq = 521142857,
+       },
+};
+
+
+struct reg_val {
+       u8 reg;
+       u8 val;
+};
+
+static int
+pt3_demod_write(struct pt3_adapter *adap, const struct reg_val *data, int num)
+{
+       struct i2c_msg msg;
+       int i, ret;
+
+       ret = 0;
+       msg.addr = adap->i2c_demod->addr;
+       msg.flags = 0;
+       msg.len = 2;
+       for (i = 0; i < num; i++) {
+               msg.buf = (u8 *)&data[i];
+               ret = i2c_transfer(adap->i2c_demod->adapter, &msg, 1);
+               if (ret == 0)
+                       ret = -EREMOTE;
+               if (ret < 0)
+                       return ret;
+       }
+       return 0;
+}
+
+static inline void pt3_lnb_ctrl(struct pt3_board *pt3, bool on)
+{
+       iowrite32((on ? 0x0f : 0x0c), pt3->regs[0] + REG_SYSTEM_W);
+}
+
+static inline struct pt3_adapter *pt3_find_adapter(struct dvb_frontend *fe)
+{
+       struct pt3_board *pt3;
+       int i;
+
+       if (one_adapter) {
+               pt3 = fe->dvb->priv;
+               for (i = 0; i < PT3_NUM_FE; i++)
+                       if (pt3->adaps[i]->fe == fe)
+                               return pt3->adaps[i];
+       }
+       return container_of(fe->dvb, struct pt3_adapter, dvb_adap);
+}
+
+/*
+ * all 4 tuners in PT3 are packaged in a can module (Sharp VA4M6JC2103).
+ * it seems that they share the power lines and Amp power line and
+ * adaps[3] controls those powers.
+ */
+static int
+pt3_set_tuner_power(struct pt3_board *pt3, bool tuner_on, bool amp_on)
+{
+       struct reg_val rv = { 0x1e, 0x99 };
+
+       if (tuner_on)
+               rv.val |= 0x40;
+       if (amp_on)
+               rv.val |= 0x04;
+       return pt3_demod_write(pt3->adaps[PT3_NUM_FE - 1], &rv, 1);
+}
+
+static int pt3_set_lna(struct dvb_frontend *fe)
+{
+       struct pt3_adapter *adap;
+       struct pt3_board *pt3;
+       u32 val;
+       int ret;
+
+       /* LNA is shared btw. 2 TERR-tuners */
+
+       adap = pt3_find_adapter(fe);
+       val = fe->dtv_property_cache.lna;
+       if (val == LNA_AUTO || val == adap->cur_lna)
+               return 0;
+
+       pt3 = adap->dvb_adap.priv;
+       if (mutex_lock_interruptible(&pt3->lock))
+               return -ERESTARTSYS;
+       if (val)
+               pt3->lna_on_cnt++;
+       else
+               pt3->lna_on_cnt--;
+
+       if (val && pt3->lna_on_cnt <= 1) {
+               pt3->lna_on_cnt = 1;
+               ret = pt3_set_tuner_power(pt3, true, true);
+       } else if (!val && pt3->lna_on_cnt <= 0) {
+               pt3->lna_on_cnt = 0;
+               ret = pt3_set_tuner_power(pt3, true, false);
+       } else
+               ret = 0;
+       mutex_unlock(&pt3->lock);
+       adap->cur_lna = (val != 0);
+       return ret;
+}
+
+static int pt3_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t volt)
+{
+       struct pt3_adapter *adap;
+       struct pt3_board *pt3;
+       bool on;
+
+       /* LNB power is shared btw. 2 SAT-tuners */
+
+       adap = pt3_find_adapter(fe);
+       on = (volt != SEC_VOLTAGE_OFF);
+       if (on == adap->cur_lnb)
+               return 0;
+       adap->cur_lnb = on;
+       pt3 = adap->dvb_adap.priv;
+       if (mutex_lock_interruptible(&pt3->lock))
+               return -ERESTARTSYS;
+       if (on)
+               pt3->lnb_on_cnt++;
+       else
+               pt3->lnb_on_cnt--;
+
+       if (on && pt3->lnb_on_cnt <= 1) {
+               pt3->lnb_on_cnt = 1;
+               pt3_lnb_ctrl(pt3, true);
+       } else if (!on && pt3->lnb_on_cnt <= 0) {
+               pt3->lnb_on_cnt = 0;
+               pt3_lnb_ctrl(pt3, false);
+       }
+       mutex_unlock(&pt3->lock);
+       return 0;
+}
+
+/* register values used in pt3_fe_init() */
+
+static const struct reg_val init0_sat[] = {
+       { 0x03, 0x01 },
+       { 0x1e, 0x10 },
+};
+static const struct reg_val init0_ter[] = {
+       { 0x01, 0x40 },
+       { 0x1c, 0x10 },
+};
+static const struct reg_val cfg_sat[] = {
+       { 0x1c, 0x15 },
+       { 0x1f, 0x04 },
+};
+static const struct reg_val cfg_ter[] = {
+       { 0x1d, 0x01 },
+};
+
+/*
+ * pt3_fe_init: initialize demod sub modules and ISDB-T tuners all at once.
+ *
+ * As for demod IC (TC90522) and ISDB-T tuners (MxL301RF),
+ * the i2c sequences for init'ing them are not public and hidden in a ROM,
+ * and include the board specific configurations as well.
+ * They are stored in a lump and cannot be taken out / accessed separately,
+ * thus cannot be moved to the FE/tuner driver.
+ */
+static int pt3_fe_init(struct pt3_board *pt3)
+{
+       int i, ret;
+       struct dvb_frontend *fe;
+
+       pt3_i2c_reset(pt3);
+       ret = pt3_init_all_demods(pt3);
+       if (ret < 0) {
+               dev_warn(&pt3->pdev->dev, "Failed to init demod chips.");
+               return ret;
+       }
+
+       /* additional config? */
+       for (i = 0; i < PT3_NUM_FE; i++) {
+               fe = pt3->adaps[i]->fe;
+
+               if (fe->ops.delsys[0] == SYS_ISDBS)
+                       ret = pt3_demod_write(pt3->adaps[i],
+                                             init0_sat, ARRAY_SIZE(init0_sat));
+               else
+                       ret = pt3_demod_write(pt3->adaps[i],
+                                             init0_ter, ARRAY_SIZE(init0_ter));
+               if (ret < 0) {
+                       dev_warn(&pt3->pdev->dev,
+                                "demod[%d] faild in init sequence0.", i);
+                       return ret;
+               }
+               ret = fe->ops.init(fe);
+               if (ret < 0)
+                       return ret;
+       }
+
+       usleep_range(2000, 4000);
+       ret = pt3_set_tuner_power(pt3, true, false);
+       if (ret < 0) {
+               dev_warn(&pt3->pdev->dev, "Failed to control tuner module.");
+               return ret;
+       }
+
+       /* output pin configuration */
+       for (i = 0; i < PT3_NUM_FE; i++) {
+               fe = pt3->adaps[i]->fe;
+               if (fe->ops.delsys[0] == SYS_ISDBS)
+                       ret = pt3_demod_write(pt3->adaps[i],
+                                               cfg_sat, ARRAY_SIZE(cfg_sat));
+               else
+                       ret = pt3_demod_write(pt3->adaps[i],
+                                               cfg_ter, ARRAY_SIZE(cfg_ter));
+               if (ret < 0) {
+                       dev_warn(&pt3->pdev->dev,
+                                "demod[%d] faild in init sequence1.", i);
+                       return ret;
+               }
+       }
+       usleep_range(4000, 6000);
+
+       for (i = 0; i < PT3_NUM_FE; i++) {
+               fe = pt3->adaps[i]->fe;
+               if (fe->ops.delsys[0] != SYS_ISDBS)
+                       continue;
+               /* init and wake-up ISDB-S tuners */
+               ret = fe->ops.tuner_ops.init(fe);
+               if (ret < 0) {
+                       dev_warn(&pt3->pdev->dev,
+                                "Failed to init SAT-tuner[%d].", i);
+                       return ret;
+               }
+       }
+       ret = pt3_init_all_mxl301rf(pt3);
+       if (ret < 0) {
+               dev_warn(&pt3->pdev->dev, "Failed to init TERR-tuners.");
+               return ret;
+       }
+
+       ret = pt3_set_tuner_power(pt3, true, true);
+       if (ret < 0) {
+               dev_warn(&pt3->pdev->dev, "Failed to control tuner module.");
+               return ret;
+       }
+
+       /* Wake up all tuners and make an initial tuning,
+        * in order to avoid interference among the tuners in the module,
+        * according to the doc from the manufacturer.
+        */
+       for (i = 0; i < PT3_NUM_FE; i++) {
+               fe = pt3->adaps[i]->fe;
+               ret = 0;
+               if (fe->ops.delsys[0] == SYS_ISDBT)
+                       ret = fe->ops.tuner_ops.init(fe);
+               /* set only when called from pt3_probe(), not resume() */
+               if (ret == 0 && fe->dtv_property_cache.frequency == 0) {
+                       fe->dtv_property_cache.frequency =
+                                               adap_conf[i].init_freq;
+                       ret = fe->ops.tuner_ops.set_params(fe);
+               }
+               if (ret < 0) {
+                       dev_warn(&pt3->pdev->dev,
+                                "Failed in initial tuning of tuner[%d].", i);
+                       return ret;
+               }
+       }
+
+       /* and sleep again, waiting to be opened by users. */
+       for (i = 0; i < PT3_NUM_FE; i++) {
+               fe = pt3->adaps[i]->fe;
+               if (fe->ops.tuner_ops.sleep)
+                       ret = fe->ops.tuner_ops.sleep(fe);
+               if (ret < 0)
+                       break;
+               if (fe->ops.sleep)
+                       ret = fe->ops.sleep(fe);
+               if (ret < 0)
+                       break;
+               if (fe->ops.delsys[0] == SYS_ISDBS)
+                       fe->ops.set_voltage = &pt3_set_voltage;
+               else
+                       fe->ops.set_lna = &pt3_set_lna;
+       }
+       if (i < PT3_NUM_FE) {
+               dev_warn(&pt3->pdev->dev, "FE[%d] failed to standby.", i);
+               return ret;
+       }
+       return 0;
+}
+
+
+static int pt3_attach_fe(struct pt3_board *pt3, int i)
+{
+       struct i2c_board_info info;
+       struct tc90522_config cfg;
+       struct i2c_client *cl;
+       struct dvb_adapter *dvb_adap;
+       int ret;
+
+       info = adap_conf[i].demod_info;
+       cfg = adap_conf[i].demod_cfg;
+       cfg.tuner_i2c = NULL;
+       info.platform_data = &cfg;
+
+       ret = -ENODEV;
+       request_module("tc90522");
+       cl = i2c_new_device(&pt3->i2c_adap, &info);
+       if (!cl || !cl->dev.driver)
+               return -ENODEV;
+       pt3->adaps[i]->i2c_demod = cl;
+       if (!try_module_get(cl->dev.driver->owner))
+               goto err_demod_i2c_unregister_device;
+
+       if (!strncmp(cl->name, TC90522_I2C_DEV_SAT, sizeof(cl->name))) {
+               struct qm1d1c0042_config tcfg;
+
+               tcfg = adap_conf[i].tuner_cfg.qm1d1c0042;
+               tcfg.fe = cfg.fe;
+               info = adap_conf[i].tuner_info;
+               info.platform_data = &tcfg;
+               request_module("qm1d1c0042");
+               cl = i2c_new_device(cfg.tuner_i2c, &info);
+       } else {
+               struct mxl301rf_config tcfg;
+
+               tcfg = adap_conf[i].tuner_cfg.mxl301rf;
+               tcfg.fe = cfg.fe;
+               info = adap_conf[i].tuner_info;
+               info.platform_data = &tcfg;
+               request_module("mxl301rf");
+               cl = i2c_new_device(cfg.tuner_i2c, &info);
+       }
+       if (!cl || !cl->dev.driver)
+               goto err_demod_module_put;
+       pt3->adaps[i]->i2c_tuner = cl;
+       if (!try_module_get(cl->dev.driver->owner))
+               goto err_tuner_i2c_unregister_device;
+
+       dvb_adap = &pt3->adaps[one_adapter ? 0 : i]->dvb_adap;
+       ret = dvb_register_frontend(dvb_adap, cfg.fe);
+       if (ret < 0)
+               goto err_tuner_module_put;
+       pt3->adaps[i]->fe = cfg.fe;
+       return 0;
+
+err_tuner_module_put:
+       module_put(pt3->adaps[i]->i2c_tuner->dev.driver->owner);
+err_tuner_i2c_unregister_device:
+       i2c_unregister_device(pt3->adaps[i]->i2c_tuner);
+err_demod_module_put:
+       module_put(pt3->adaps[i]->i2c_demod->dev.driver->owner);
+err_demod_i2c_unregister_device:
+       i2c_unregister_device(pt3->adaps[i]->i2c_demod);
+
+       return ret;
+}
+
+
+static int pt3_fetch_thread(void *data)
+{
+       struct pt3_adapter *adap = data;
+       ktime_t delay;
+       bool was_frozen;
+
+#define PT3_INITIAL_BUF_DROPS 4
+#define PT3_FETCH_DELAY 10
+#define PT3_FETCH_DELAY_DELTA 2
+
+       pt3_init_dmabuf(adap);
+       adap->num_discard = PT3_INITIAL_BUF_DROPS;
+
+       dev_dbg(adap->dvb_adap.device,
+               "PT3: [%s] started.\n", adap->thread->comm);
+       set_freezable();
+       while (!kthread_freezable_should_stop(&was_frozen)) {
+               if (was_frozen)
+                       adap->num_discard = PT3_INITIAL_BUF_DROPS;
+
+               pt3_proc_dma(adap);
+
+               delay = ktime_set(0, PT3_FETCH_DELAY * NSEC_PER_MSEC);
+               set_current_state(TASK_UNINTERRUPTIBLE);
+               freezable_schedule_hrtimeout_range(&delay,
+                                       PT3_FETCH_DELAY_DELTA * NSEC_PER_MSEC,
+                                       HRTIMER_MODE_REL);
+       }
+       dev_dbg(adap->dvb_adap.device,
+               "PT3: [%s] exited.\n", adap->thread->comm);
+       adap->thread = NULL;
+       return 0;
+}
+
+static int pt3_start_streaming(struct pt3_adapter *adap)
+{
+       struct task_struct *thread;
+
+       /* start fetching thread */
+       thread = kthread_run(pt3_fetch_thread, adap, "pt3-ad%i-dmx%i",
+                               adap->dvb_adap.num, adap->dmxdev.dvbdev->id);
+       if (IS_ERR(thread)) {
+               int ret = PTR_ERR(thread);
+
+               dev_warn(adap->dvb_adap.device,
+                       "PT3 (adap:%d, dmx:%d): failed to start kthread.\n",
+                       adap->dvb_adap.num, adap->dmxdev.dvbdev->id);
+               return ret;
+       }
+       adap->thread = thread;
+
+       return pt3_start_dma(adap);
+}
+
+static int pt3_stop_streaming(struct pt3_adapter *adap)
+{
+       int ret;
+
+       ret = pt3_stop_dma(adap);
+       if (ret)
+               dev_warn(adap->dvb_adap.device,
+                       "PT3: failed to stop streaming of adap:%d/FE:%d\n",
+                       adap->dvb_adap.num, adap->fe->id);
+
+       /* kill the fetching thread */
+       ret = kthread_stop(adap->thread);
+       return ret;
+}
+
+static int pt3_start_feed(struct dvb_demux_feed *feed)
+{
+       struct pt3_adapter *adap;
+
+       if (signal_pending(current))
+               return -EINTR;
+
+       adap = container_of(feed->demux, struct pt3_adapter, demux);
+       adap->num_feeds++;
+       if (adap->thread)
+               return 0;
+       if (adap->num_feeds != 1) {
+               dev_warn(adap->dvb_adap.device,
+                       "%s: unmatched start/stop_feed in adap:%i/dmx:%i.\n",
+                       __func__, adap->dvb_adap.num, adap->dmxdev.dvbdev->id);
+               adap->num_feeds = 1;
+       }
+
+       return pt3_start_streaming(adap);
+
+}
+
+static int pt3_stop_feed(struct dvb_demux_feed *feed)
+{
+       struct pt3_adapter *adap;
+
+       adap = container_of(feed->demux, struct pt3_adapter, demux);
+
+       adap->num_feeds--;
+       if (adap->num_feeds > 0 || !adap->thread)
+               return 0;
+       adap->num_feeds = 0;
+
+       return pt3_stop_streaming(adap);
+}
+
+
+static int pt3_alloc_adapter(struct pt3_board *pt3, int index)
+{
+       int ret;
+       struct pt3_adapter *adap;
+       struct dvb_adapter *da;
+
+       adap = kzalloc(sizeof(*adap), GFP_KERNEL);
+       if (!adap) {
+               dev_err(&pt3->pdev->dev, "failed to alloc mem for adapter.\n");
+               return -ENOMEM;
+       }
+       pt3->adaps[index] = adap;
+       adap->adap_idx = index;
+
+       if (index == 0 || !one_adapter) {
+               ret = dvb_register_adapter(&adap->dvb_adap, "PT3 DVB",
+                               THIS_MODULE, &pt3->pdev->dev, adapter_nr);
+               if (ret < 0) {
+                       dev_err(&pt3->pdev->dev,
+                               "failed to register adapter dev.\n");
+                       goto err_mem;
+               }
+               da = &adap->dvb_adap;
+       } else
+               da = &pt3->adaps[0]->dvb_adap;
+
+       adap->dvb_adap.priv = pt3;
+       adap->demux.dmx.capabilities = DMX_TS_FILTERING | DMX_SECTION_FILTERING;
+       adap->demux.priv = adap;
+       adap->demux.feednum = 256;
+       adap->demux.filternum = 256;
+       adap->demux.start_feed = pt3_start_feed;
+       adap->demux.stop_feed = pt3_stop_feed;
+       ret = dvb_dmx_init(&adap->demux);
+       if (ret < 0) {
+               dev_err(&pt3->pdev->dev, "failed to init dmx dev.\n");
+               goto err_adap;
+       }
+
+       adap->dmxdev.filternum = 256;
+       adap->dmxdev.demux = &adap->demux.dmx;
+       ret = dvb_dmxdev_init(&adap->dmxdev, da);
+       if (ret < 0) {
+               dev_err(&pt3->pdev->dev, "failed to init dmxdev.\n");
+               goto err_demux;
+       }
+
+       ret = pt3_alloc_dmabuf(adap);
+       if (ret) {
+               dev_err(&pt3->pdev->dev, "failed to alloc DMA buffers.\n");
+               goto err_dmabuf;
+       }
+
+       return 0;
+
+err_dmabuf:
+       pt3_free_dmabuf(adap);
+       dvb_dmxdev_release(&adap->dmxdev);
+err_demux:
+       dvb_dmx_release(&adap->demux);
+err_adap:
+       if (index == 0 || !one_adapter)
+               dvb_unregister_adapter(da);
+err_mem:
+       kfree(adap);
+       pt3->adaps[index] = NULL;
+       return ret;
+}
+
+static void pt3_cleanup_adapter(struct pt3_board *pt3, int index)
+{
+       struct pt3_adapter *adap;
+       struct dmx_demux *dmx;
+
+       adap = pt3->adaps[index];
+       if (adap == NULL)
+               return;
+
+       /* stop demux kthread */
+       if (adap->thread)
+               pt3_stop_streaming(adap);
+
+       dmx = &adap->demux.dmx;
+       dmx->close(dmx);
+       if (adap->fe) {
+               adap->fe->callback = NULL;
+               if (adap->fe->frontend_priv)
+                       dvb_unregister_frontend(adap->fe);
+               if (adap->i2c_tuner) {
+                       module_put(adap->i2c_tuner->dev.driver->owner);
+                       i2c_unregister_device(adap->i2c_tuner);
+               }
+               if (adap->i2c_demod) {
+                       module_put(adap->i2c_demod->dev.driver->owner);
+                       i2c_unregister_device(adap->i2c_demod);
+               }
+       }
+       pt3_free_dmabuf(adap);
+       dvb_dmxdev_release(&adap->dmxdev);
+       dvb_dmx_release(&adap->demux);
+       if (index == 0 || !one_adapter)
+               dvb_unregister_adapter(&adap->dvb_adap);
+       kfree(adap);
+       pt3->adaps[index] = NULL;
+}
+
+#ifdef CONFIG_PM_SLEEP
+
+static int pt3_suspend(struct device *dev)
+{
+       struct pci_dev *pdev = to_pci_dev(dev);
+       struct pt3_board *pt3 = pci_get_drvdata(pdev);
+       int i;
+       struct pt3_adapter *adap;
+
+       for (i = 0; i < PT3_NUM_FE; i++) {
+               adap = pt3->adaps[i];
+               if (adap->num_feeds > 0)
+                       pt3_stop_dma(adap);
+               dvb_frontend_suspend(adap->fe);
+               pt3_free_dmabuf(adap);
+       }
+
+       pt3_lnb_ctrl(pt3, false);
+       pt3_set_tuner_power(pt3, false, false);
+       return 0;
+}
+
+static int pt3_resume(struct device *dev)
+{
+       struct pci_dev *pdev = to_pci_dev(dev);
+       struct pt3_board *pt3 = pci_get_drvdata(pdev);
+       int i, ret;
+       struct pt3_adapter *adap;
+
+       ret = pt3_fe_init(pt3);
+       if (ret)
+               return ret;
+
+       if (pt3->lna_on_cnt > 0)
+               pt3_set_tuner_power(pt3, true, true);
+       if (pt3->lnb_on_cnt > 0)
+               pt3_lnb_ctrl(pt3, true);
+
+       for (i = 0; i < PT3_NUM_FE; i++) {
+               adap = pt3->adaps[i];
+               dvb_frontend_resume(adap->fe);
+               ret = pt3_alloc_dmabuf(adap);
+               if (ret) {
+                       dev_err(&pt3->pdev->dev, "failed to alloc DMA bufs.\n");
+                       continue;
+               }
+               if (adap->num_feeds > 0)
+                       pt3_start_dma(adap);
+       }
+
+       return 0;
+}
+
+#endif /* CONFIG_PM_SLEEP */
+
+
+static void pt3_remove(struct pci_dev *pdev)
+{
+       struct pt3_board *pt3;
+       int i;
+
+       pt3 = pci_get_drvdata(pdev);
+       for (i = PT3_NUM_FE - 1; i >= 0; i--)
+               pt3_cleanup_adapter(pt3, i);
+       i2c_del_adapter(&pt3->i2c_adap);
+       kfree(pt3->i2c_buf);
+       pci_iounmap(pt3->pdev, pt3->regs[0]);
+       pci_iounmap(pt3->pdev, pt3->regs[1]);
+       pci_release_regions(pdev);
+       pci_disable_device(pdev);
+       kfree(pt3);
+}
+
+static int pt3_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+       u8 rev;
+       u32 ver;
+       int i, ret;
+       struct pt3_board *pt3;
+       struct i2c_adapter *i2c;
+
+       if (pci_read_config_byte(pdev, PCI_REVISION_ID, &rev) || rev != 1)
+               return -ENODEV;
+
+       ret = pci_enable_device(pdev);
+       if (ret < 0)
+               return -ENODEV;
+       pci_set_master(pdev);
+
+       ret = pci_request_regions(pdev, DRV_NAME);
+       if (ret < 0)
+               goto err_disable_device;
+
+       ret = dma_set_mask(&pdev->dev, DMA_BIT_MASK(64));
+       if (ret == 0)
+               dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(64));
+       else {
+               ret = dma_set_mask(&pdev->dev, DMA_BIT_MASK(32));
+               if (ret == 0)
+                       dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32));
+               else {
+                       dev_err(&pdev->dev, "Failed to set DMA mask.\n");
+                       goto err_release_regions;
+               }
+               dev_info(&pdev->dev, "Use 32bit DMA.\n");
+       }
+
+       pt3 = kzalloc(sizeof(*pt3), GFP_KERNEL);
+       if (!pt3) {
+               dev_err(&pdev->dev, "Failed to alloc mem for this dev.\n");
+               ret = -ENOMEM;
+               goto err_release_regions;
+       }
+       pci_set_drvdata(pdev, pt3);
+       pt3->pdev = pdev;
+       mutex_init(&pt3->lock);
+       pt3->regs[0] = pci_ioremap_bar(pdev, 0);
+       pt3->regs[1] = pci_ioremap_bar(pdev, 2);
+       if (pt3->regs[0] == NULL || pt3->regs[1] == NULL) {
+               dev_err(&pdev->dev, "Failed to ioremap.\n");
+               ret = -ENOMEM;
+               goto err_kfree;
+       }
+
+       ver = ioread32(pt3->regs[0] + REG_VERSION);
+       if ((ver >> 16) != 0x0301) {
+               dev_warn(&pdev->dev, "PT%d, I/F-ver.:%d not supported",
+                       ver >> 24, (ver & 0x00ff0000) >> 16);
+               ret = -ENODEV;
+               goto err_iounmap;
+       }
+
+       pt3->num_bufs = clamp_val(num_bufs, MIN_DATA_BUFS, MAX_DATA_BUFS);
+
+       pt3->i2c_buf = kmalloc(sizeof(*pt3->i2c_buf), GFP_KERNEL);
+       if (pt3->i2c_buf == NULL) {
+               dev_err(&pdev->dev, "Failed to alloc mem for i2c.\n");
+               ret = -ENOMEM;
+               goto err_iounmap;
+       }
+       i2c = &pt3->i2c_adap;
+       i2c->owner = THIS_MODULE;
+       i2c->algo = &pt3_i2c_algo;
+       i2c->algo_data = NULL;
+       i2c->dev.parent = &pdev->dev;
+       strlcpy(i2c->name, DRV_NAME, sizeof(i2c->name));
+       i2c_set_adapdata(i2c, pt3);
+       ret = i2c_add_adapter(i2c);
+       if (ret < 0) {
+               dev_err(&pdev->dev, "Failed to add i2c adapter.\n");
+               goto err_i2cbuf;
+       }
+
+       for (i = 0; i < PT3_NUM_FE; i++) {
+               ret = pt3_alloc_adapter(pt3, i);
+               if (ret < 0)
+                       break;
+
+               ret = pt3_attach_fe(pt3, i);
+               if (ret < 0)
+                       break;
+       }
+       if (i < PT3_NUM_FE) {
+               dev_err(&pdev->dev, "Failed to create FE%d.\n", i);
+               goto err_cleanup_adapters;
+       }
+
+       ret = pt3_fe_init(pt3);
+       if (ret < 0) {
+               dev_err(&pdev->dev, "Failed to init frontends.\n");
+               i = PT3_NUM_FE - 1;
+               goto err_cleanup_adapters;
+       }
+
+       dev_info(&pdev->dev,
+               "successfully init'ed PT%d (fw:0x%02x, I/F:0x%02x).\n",
+               ver >> 24, (ver >> 8) & 0xff, (ver >> 16) & 0xff);
+       return 0;
+
+err_cleanup_adapters:
+       while (i >= 0)
+               pt3_cleanup_adapter(pt3, i--);
+       i2c_del_adapter(i2c);
+err_i2cbuf:
+       kfree(pt3->i2c_buf);
+err_iounmap:
+       if (pt3->regs[0])
+               pci_iounmap(pdev, pt3->regs[0]);
+       if (pt3->regs[1])
+               pci_iounmap(pdev, pt3->regs[1]);
+err_kfree:
+       kfree(pt3);
+err_release_regions:
+       pci_release_regions(pdev);
+err_disable_device:
+       pci_disable_device(pdev);
+       return ret;
+
+}
+
+static const struct pci_device_id pt3_id_table[] = {
+       { PCI_DEVICE_SUB(0x1172, 0x4c15, 0xee8d, 0x0368) },
+       { },
+};
+MODULE_DEVICE_TABLE(pci, pt3_id_table);
+
+static SIMPLE_DEV_PM_OPS(pt3_pm_ops, pt3_suspend, pt3_resume);
+
+static struct pci_driver pt3_driver = {
+       .name           = DRV_NAME,
+       .probe          = pt3_probe,
+       .remove         = pt3_remove,
+       .id_table       = pt3_id_table,
+
+       .driver.pm      = &pt3_pm_ops,
+};
+
+module_pci_driver(pt3_driver);
+
+MODULE_DESCRIPTION("Earthsoft PT3 Driver");
+MODULE_AUTHOR("Akihiro TSUKADA");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/pci/pt3/pt3.h b/drivers/media/pci/pt3/pt3.h
new file mode 100644 (file)
index 0000000..1b3f2ad
--- /dev/null
@@ -0,0 +1,186 @@
+/*
+ * Earthsoft PT3 driver
+ *
+ * Copyright (C) 2014 Akihiro Tsukada <tskd08@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2.
+ *
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef PT3_H
+#define PT3_H
+
+#include <linux/atomic.h>
+#include <linux/types.h>
+
+#include "dvb_demux.h"
+#include "dvb_frontend.h"
+#include "dmxdev.h"
+
+#include "tc90522.h"
+#include "mxl301rf.h"
+#include "qm1d1c0042.h"
+
+#define DRV_NAME KBUILD_MODNAME
+
+#define PT3_NUM_FE 4
+
+/*
+ * register index of the FPGA chip
+ */
+#define REG_VERSION    0x00
+#define REG_BUS                0x04
+#define REG_SYSTEM_W   0x08
+#define REG_SYSTEM_R   0x0c
+#define REG_I2C_W      0x10
+#define REG_I2C_R      0x14
+#define REG_RAM_W      0x18
+#define REG_RAM_R      0x1c
+#define REG_DMA_BASE   0x40    /* regs for FE[i] = REG_DMA_BASE + 0x18 * i */
+#define OFST_DMA_DESC_L        0x00
+#define OFST_DMA_DESC_H        0x04
+#define OFST_DMA_CTL   0x08
+#define OFST_TS_CTL    0x0c
+#define OFST_STATUS    0x10
+#define OFST_TS_ERR    0x14
+
+/*
+ * internal buffer for I2C
+ */
+#define PT3_I2C_MAX 4091
+struct pt3_i2cbuf {
+       u8  data[PT3_I2C_MAX];
+       u8  tmp;
+       u32 num_cmds;
+};
+
+/*
+ * DMA things
+ */
+#define TS_PACKET_SZ  188
+/* DMA transfers must not cross 4GiB, so use one page / transfer */
+#define DATA_XFER_SZ   4096
+#define DATA_BUF_XFERS 47
+/* (num_bufs * DATA_BUF_SZ) % TS_PACKET_SZ must be 0 */
+#define DATA_BUF_SZ    (DATA_BUF_XFERS * DATA_XFER_SZ)
+#define MAX_DATA_BUFS  16
+#define MIN_DATA_BUFS   2
+
+#define DESCS_IN_PAGE (PAGE_SIZE / sizeof(struct xfer_desc))
+#define MAX_NUM_XFERS (MAX_DATA_BUFS * DATA_BUF_XFERS)
+#define MAX_DESC_BUFS DIV_ROUND_UP(MAX_NUM_XFERS, DESCS_IN_PAGE)
+
+/* DMA transfer description.
+ * device is passed a pointer to this struct, dma-reads it,
+ * and gets the DMA buffer ring for storing TS data.
+ */
+struct xfer_desc {
+       u32 addr_l; /* bus address of target data buffer */
+       u32 addr_h;
+       u32 size;
+       u32 next_l; /* bus adddress of the next xfer_desc */
+       u32 next_h;
+};
+
+/* A DMA mapping of a page containing xfer_desc's */
+struct xfer_desc_buffer {
+       dma_addr_t b_addr;
+       struct xfer_desc *descs; /* PAGE_SIZE (xfer_desc[DESCS_IN_PAGE]) */
+};
+
+/* A DMA mapping of a data buffer */
+struct dma_data_buffer {
+       dma_addr_t b_addr;
+       u8 *data; /* size: u8[PAGE_SIZE] */
+};
+
+/*
+ * device things
+ */
+struct pt3_adap_config {
+       struct i2c_board_info demod_info;
+       struct tc90522_config demod_cfg;
+
+       struct i2c_board_info tuner_info;
+       union tuner_config {
+               struct qm1d1c0042_config qm1d1c0042;
+               struct mxl301rf_config   mxl301rf;
+       } tuner_cfg;
+       u32 init_freq;
+};
+
+struct pt3_adapter {
+       struct dvb_adapter  dvb_adap;  /* dvb_adap.priv => struct pt3_board */
+       int adap_idx;
+
+       struct dvb_demux    demux;
+       struct dmxdev       dmxdev;
+       struct dvb_frontend *fe;
+       struct i2c_client   *i2c_demod;
+       struct i2c_client   *i2c_tuner;
+
+       /* data fetch thread */
+       struct task_struct *thread;
+       int num_feeds;
+
+       bool cur_lna;
+       bool cur_lnb; /* current LNB power status (on/off) */
+
+       /* items below are for DMA */
+       struct dma_data_buffer buffer[MAX_DATA_BUFS];
+       int buf_idx;
+       int buf_ofs;
+       int num_bufs;  /* == pt3_board->num_bufs */
+       int num_discard; /* how many access units to discard initially */
+
+       struct xfer_desc_buffer desc_buf[MAX_DESC_BUFS];
+       int num_desc_bufs;  /* == num_bufs * DATA_BUF_XFERS / DESCS_IN_PAGE */
+};
+
+
+struct pt3_board {
+       struct pci_dev *pdev;
+       void __iomem *regs[2];
+       /* regs[0]: registers, regs[1]: internal memory, used for I2C */
+
+       struct mutex lock;
+
+       /* LNB power shared among sat-FEs */
+       int lnb_on_cnt; /* LNB power on count */
+
+       /* LNA shared among terr-FEs */
+       int lna_on_cnt; /* booster enabled count */
+
+       int num_bufs;  /* number of DMA buffers allocated/mapped per FE */
+
+       struct i2c_adapter i2c_adap;
+       struct pt3_i2cbuf *i2c_buf;
+
+       struct pt3_adapter *adaps[PT3_NUM_FE];
+};
+
+
+/*
+ * prototypes
+ */
+extern int  pt3_alloc_dmabuf(struct pt3_adapter *adap);
+extern void pt3_init_dmabuf(struct pt3_adapter *adap);
+extern void pt3_free_dmabuf(struct pt3_adapter *adap);
+extern int  pt3_start_dma(struct pt3_adapter *adap);
+extern int  pt3_stop_dma(struct pt3_adapter *adap);
+extern int  pt3_proc_dma(struct pt3_adapter *adap);
+
+extern int  pt3_i2c_master_xfer(struct i2c_adapter *adap,
+                               struct i2c_msg *msgs, int num);
+extern u32  pt3_i2c_functionality(struct i2c_adapter *adap);
+extern void pt3_i2c_reset(struct pt3_board *pt3);
+extern int  pt3_init_all_demods(struct pt3_board *pt3);
+extern int  pt3_init_all_mxl301rf(struct pt3_board *pt3);
+#endif /* PT3_H */
diff --git a/drivers/media/pci/pt3/pt3_dma.c b/drivers/media/pci/pt3/pt3_dma.c
new file mode 100644 (file)
index 0000000..f0ce904
--- /dev/null
@@ -0,0 +1,225 @@
+/*
+ * Earthsoft PT3 driver
+ *
+ * Copyright (C) 2014 Akihiro Tsukada <tskd08@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2.
+ *
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#include <linux/dma-mapping.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+
+#include "pt3.h"
+
+#define PT3_ACCESS_UNIT (TS_PACKET_SZ * 128)
+#define PT3_BUF_CANARY  (0x74)
+
+static u32 get_dma_base(int idx)
+{
+       int i;
+
+       i = (idx == 1 || idx == 2) ? 3 - idx : idx;
+       return REG_DMA_BASE + 0x18 * i;
+}
+
+int pt3_stop_dma(struct pt3_adapter *adap)
+{
+       struct pt3_board *pt3 = adap->dvb_adap.priv;
+       u32 base;
+       u32 stat;
+       int retry;
+
+       base = get_dma_base(adap->adap_idx);
+       stat = ioread32(pt3->regs[0] + base + OFST_STATUS);
+       if (!(stat & 0x01))
+               return 0;
+
+       iowrite32(0x02, pt3->regs[0] + base + OFST_DMA_CTL);
+       for (retry = 0; retry < 5; retry++) {
+               stat = ioread32(pt3->regs[0] + base + OFST_STATUS);
+               if (!(stat & 0x01))
+                       return 0;
+               msleep(50);
+       }
+       return -EIO;
+}
+
+int pt3_start_dma(struct pt3_adapter *adap)
+{
+       struct pt3_board *pt3 = adap->dvb_adap.priv;
+       u32 base = get_dma_base(adap->adap_idx);
+
+       iowrite32(0x02, pt3->regs[0] + base + OFST_DMA_CTL);
+       iowrite32(lower_32_bits(adap->desc_buf[0].b_addr),
+                       pt3->regs[0] + base + OFST_DMA_DESC_L);
+       iowrite32(upper_32_bits(adap->desc_buf[0].b_addr),
+                       pt3->regs[0] + base + OFST_DMA_DESC_H);
+       iowrite32(0x01, pt3->regs[0] + base + OFST_DMA_CTL);
+       return 0;
+}
+
+
+static u8 *next_unit(struct pt3_adapter *adap, int *idx, int *ofs)
+{
+       *ofs += PT3_ACCESS_UNIT;
+       if (*ofs >= DATA_BUF_SZ) {
+               *ofs -= DATA_BUF_SZ;
+               (*idx)++;
+               if (*idx == adap->num_bufs)
+                       *idx = 0;
+       }
+       return &adap->buffer[*idx].data[*ofs];
+}
+
+int pt3_proc_dma(struct pt3_adapter *adap)
+{
+       int idx, ofs;
+
+       idx = adap->buf_idx;
+       ofs = adap->buf_ofs;
+
+       if (adap->buffer[idx].data[ofs] == PT3_BUF_CANARY)
+               return 0;
+
+       while (*next_unit(adap, &idx, &ofs) != PT3_BUF_CANARY) {
+               u8 *p;
+
+               p = &adap->buffer[adap->buf_idx].data[adap->buf_ofs];
+               if (adap->num_discard > 0)
+                       adap->num_discard--;
+               else if (adap->buf_ofs + PT3_ACCESS_UNIT > DATA_BUF_SZ) {
+                       dvb_dmx_swfilter_packets(&adap->demux, p,
+                               (DATA_BUF_SZ - adap->buf_ofs) / TS_PACKET_SZ);
+                       dvb_dmx_swfilter_packets(&adap->demux,
+                               adap->buffer[idx].data, ofs / TS_PACKET_SZ);
+               } else
+                       dvb_dmx_swfilter_packets(&adap->demux, p,
+                               PT3_ACCESS_UNIT / TS_PACKET_SZ);
+
+               *p = PT3_BUF_CANARY;
+               adap->buf_idx = idx;
+               adap->buf_ofs = ofs;
+       }
+       return 0;
+}
+
+void pt3_init_dmabuf(struct pt3_adapter *adap)
+{
+       int idx, ofs;
+       u8 *p;
+
+       idx = 0;
+       ofs = 0;
+       p = adap->buffer[0].data;
+       /* mark the whole buffers as "not written yet" */
+       while (idx < adap->num_bufs) {
+               p[ofs] = PT3_BUF_CANARY;
+               ofs += PT3_ACCESS_UNIT;
+               if (ofs >= DATA_BUF_SZ) {
+                       ofs -= DATA_BUF_SZ;
+                       idx++;
+                       p = adap->buffer[idx].data;
+               }
+       }
+       adap->buf_idx = 0;
+       adap->buf_ofs = 0;
+}
+
+void pt3_free_dmabuf(struct pt3_adapter *adap)
+{
+       struct pt3_board *pt3;
+       int i;
+
+       pt3 = adap->dvb_adap.priv;
+       for (i = 0; i < adap->num_bufs; i++)
+               dma_free_coherent(&pt3->pdev->dev, DATA_BUF_SZ,
+                       adap->buffer[i].data, adap->buffer[i].b_addr);
+       adap->num_bufs = 0;
+
+       for (i = 0; i < adap->num_desc_bufs; i++)
+               dma_free_coherent(&pt3->pdev->dev, PAGE_SIZE,
+                       adap->desc_buf[i].descs, adap->desc_buf[i].b_addr);
+       adap->num_desc_bufs = 0;
+}
+
+
+int pt3_alloc_dmabuf(struct pt3_adapter *adap)
+{
+       struct pt3_board *pt3;
+       void *p;
+       int i, j;
+       int idx, ofs;
+       int num_desc_bufs;
+       dma_addr_t data_addr, desc_addr;
+       struct xfer_desc *d;
+
+       pt3 = adap->dvb_adap.priv;
+       adap->num_bufs = 0;
+       adap->num_desc_bufs = 0;
+       for (i = 0; i < pt3->num_bufs; i++) {
+               p = dma_alloc_coherent(&pt3->pdev->dev, DATA_BUF_SZ,
+                                       &adap->buffer[i].b_addr, GFP_KERNEL);
+               if (p == NULL)
+                       goto failed;
+               adap->buffer[i].data = p;
+               adap->num_bufs++;
+       }
+       pt3_init_dmabuf(adap);
+
+       /* build circular-linked pointers (xfer_desc) to the data buffers*/
+       idx = 0;
+       ofs = 0;
+       num_desc_bufs =
+               DIV_ROUND_UP(adap->num_bufs * DATA_BUF_XFERS, DESCS_IN_PAGE);
+       for (i = 0; i < num_desc_bufs; i++) {
+               p = dma_alloc_coherent(&pt3->pdev->dev, PAGE_SIZE,
+                                       &desc_addr, GFP_KERNEL);
+               if (p == NULL)
+                       goto failed;
+               adap->num_desc_bufs++;
+               adap->desc_buf[i].descs = p;
+               adap->desc_buf[i].b_addr = desc_addr;
+
+               if (i > 0) {
+                       d = &adap->desc_buf[i - 1].descs[DESCS_IN_PAGE - 1];
+                       d->next_l = lower_32_bits(desc_addr);
+                       d->next_h = upper_32_bits(desc_addr);
+               }
+               for (j = 0; j < DESCS_IN_PAGE; j++) {
+                       data_addr = adap->buffer[idx].b_addr + ofs;
+                       d = &adap->desc_buf[i].descs[j];
+                       d->addr_l = lower_32_bits(data_addr);
+                       d->addr_h = upper_32_bits(data_addr);
+                       d->size = DATA_XFER_SZ;
+
+                       desc_addr += sizeof(struct xfer_desc);
+                       d->next_l = lower_32_bits(desc_addr);
+                       d->next_h = upper_32_bits(desc_addr);
+
+                       ofs += DATA_XFER_SZ;
+                       if (ofs >= DATA_BUF_SZ) {
+                               ofs -= DATA_BUF_SZ;
+                               idx++;
+                               if (idx >= adap->num_bufs) {
+                                       desc_addr = adap->desc_buf[0].b_addr;
+                                       d->next_l = lower_32_bits(desc_addr);
+                                       d->next_h = upper_32_bits(desc_addr);
+                                       return 0;
+                               }
+                       }
+               }
+       }
+       return 0;
+
+failed:
+       pt3_free_dmabuf(adap);
+       return -ENOMEM;
+}
diff --git a/drivers/media/pci/pt3/pt3_i2c.c b/drivers/media/pci/pt3/pt3_i2c.c
new file mode 100644 (file)
index 0000000..ec6a8a2
--- /dev/null
@@ -0,0 +1,240 @@
+/*
+ * Earthsoft PT3 driver
+ *
+ * Copyright (C) 2014 Akihiro Tsukada <tskd08@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2.
+ *
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/i2c.h>
+#include <linux/io.h>
+#include <linux/pci.h>
+
+#include "pt3.h"
+
+#define PT3_I2C_BASE  2048
+#define PT3_CMD_ADDR_NORMAL 0
+#define PT3_CMD_ADDR_INIT_DEMOD  4096
+#define PT3_CMD_ADDR_INIT_TUNER  (4096 + 2042)
+
+/* masks for I2C status register */
+#define STAT_SEQ_RUNNING 0x1
+#define STAT_SEQ_ERROR   0x6
+#define STAT_NO_SEQ      0x8
+
+#define PT3_I2C_RUN   (1 << 16)
+#define PT3_I2C_RESET (1 << 17)
+
+enum ctl_cmd {
+       I_END,
+       I_ADDRESS,
+       I_CLOCK_L,
+       I_CLOCK_H,
+       I_DATA_L,
+       I_DATA_H,
+       I_RESET,
+       I_SLEEP,
+       I_DATA_L_NOP  = 0x08,
+       I_DATA_H_NOP  = 0x0c,
+       I_DATA_H_READ = 0x0d,
+       I_DATA_H_ACK0 = 0x0e,
+       I_DATA_H_ACK1 = 0x0f,
+};
+
+
+static void cmdbuf_add(struct pt3_i2cbuf *cbuf, enum ctl_cmd cmd)
+{
+       int buf_idx;
+
+       if ((cbuf->num_cmds % 2) == 0)
+               cbuf->tmp = cmd;
+       else {
+               cbuf->tmp |= cmd << 4;
+               buf_idx = cbuf->num_cmds / 2;
+               if (buf_idx < ARRAY_SIZE(cbuf->data))
+                       cbuf->data[buf_idx] = cbuf->tmp;
+       }
+       cbuf->num_cmds++;
+}
+
+static void put_end(struct pt3_i2cbuf *cbuf)
+{
+       cmdbuf_add(cbuf, I_END);
+       if (cbuf->num_cmds % 2)
+               cmdbuf_add(cbuf, I_END);
+}
+
+static void put_start(struct pt3_i2cbuf *cbuf)
+{
+       cmdbuf_add(cbuf, I_DATA_H);
+       cmdbuf_add(cbuf, I_CLOCK_H);
+       cmdbuf_add(cbuf, I_DATA_L);
+       cmdbuf_add(cbuf, I_CLOCK_L);
+}
+
+static void put_byte_write(struct pt3_i2cbuf *cbuf, u8 val)
+{
+       u8 mask;
+
+       mask = 0x80;
+       for (mask = 0x80; mask > 0; mask >>= 1)
+               cmdbuf_add(cbuf, (val & mask) ? I_DATA_H_NOP : I_DATA_L_NOP);
+       cmdbuf_add(cbuf, I_DATA_H_ACK0);
+}
+
+static void put_byte_read(struct pt3_i2cbuf *cbuf, u32 size)
+{
+       int i, j;
+
+       for (i = 0; i < size; i++) {
+               for (j = 0; j < 8; j++)
+                       cmdbuf_add(cbuf, I_DATA_H_READ);
+               cmdbuf_add(cbuf, (i == size - 1) ? I_DATA_H_NOP : I_DATA_L_NOP);
+       }
+}
+
+static void put_stop(struct pt3_i2cbuf *cbuf)
+{
+       cmdbuf_add(cbuf, I_DATA_L);
+       cmdbuf_add(cbuf, I_CLOCK_H);
+       cmdbuf_add(cbuf, I_DATA_H);
+}
+
+
+/* translates msgs to internal commands for bit-banging */
+static void translate(struct pt3_i2cbuf *cbuf, struct i2c_msg *msgs, int num)
+{
+       int i, j;
+       bool rd;
+
+       cbuf->num_cmds = 0;
+       for (i = 0; i < num; i++) {
+               rd = !!(msgs[i].flags & I2C_M_RD);
+               put_start(cbuf);
+               put_byte_write(cbuf, msgs[i].addr << 1 | rd);
+               if (rd)
+                       put_byte_read(cbuf, msgs[i].len);
+               else
+                       for (j = 0; j < msgs[i].len; j++)
+                               put_byte_write(cbuf, msgs[i].buf[j]);
+       }
+       if (num > 0) {
+               put_stop(cbuf);
+               put_end(cbuf);
+       }
+}
+
+static int wait_i2c_result(struct pt3_board *pt3, u32 *result, int max_wait)
+{
+       int i;
+       u32 v;
+
+       for (i = 0; i < max_wait; i++) {
+               v = ioread32(pt3->regs[0] + REG_I2C_R);
+               if (!(v & STAT_SEQ_RUNNING))
+                       break;
+               usleep_range(500, 750);
+       }
+       if (i >= max_wait)
+               return -EIO;
+       if (result)
+               *result = v;
+       return 0;
+}
+
+/* send [pre-]translated i2c msgs stored at addr */
+static int send_i2c_cmd(struct pt3_board *pt3, u32 addr)
+{
+       u32 ret;
+
+       /* make sure that previous transactions had finished */
+       if (wait_i2c_result(pt3, NULL, 50)) {
+               dev_warn(&pt3->pdev->dev, "(%s) prev. transaction stalled\n",
+                               __func__);
+               return -EIO;
+       }
+
+       iowrite32(PT3_I2C_RUN | addr, pt3->regs[0] + REG_I2C_W);
+       usleep_range(200, 300);
+       /* wait for the current transaction to finish */
+       if (wait_i2c_result(pt3, &ret, 500) || (ret & STAT_SEQ_ERROR)) {
+               dev_warn(&pt3->pdev->dev, "(%s) failed.\n", __func__);
+               return -EIO;
+       }
+       return 0;
+}
+
+
+/* init commands for each demod are combined into one transaction
+ *  and hidden in ROM with the address PT3_CMD_ADDR_INIT_DEMOD.
+ */
+int  pt3_init_all_demods(struct pt3_board *pt3)
+{
+       ioread32(pt3->regs[0] + REG_I2C_R);
+       return send_i2c_cmd(pt3, PT3_CMD_ADDR_INIT_DEMOD);
+}
+
+/* init commands for two ISDB-T tuners are hidden in ROM. */
+int  pt3_init_all_mxl301rf(struct pt3_board *pt3)
+{
+       usleep_range(1000, 2000);
+       return send_i2c_cmd(pt3, PT3_CMD_ADDR_INIT_TUNER);
+}
+
+void pt3_i2c_reset(struct pt3_board *pt3)
+{
+       iowrite32(PT3_I2C_RESET, pt3->regs[0] + REG_I2C_W);
+}
+
+/*
+ * I2C algorithm
+ */
+int
+pt3_i2c_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
+{
+       struct pt3_board *pt3;
+       struct pt3_i2cbuf *cbuf;
+       int i;
+       void __iomem *p;
+
+       pt3 = i2c_get_adapdata(adap);
+       cbuf = pt3->i2c_buf;
+
+       for (i = 0; i < num; i++)
+               if (msgs[i].flags & I2C_M_RECV_LEN) {
+                       dev_warn(&pt3->pdev->dev,
+                               "(%s) I2C_M_RECV_LEN not supported.\n",
+                               __func__);
+                       return -EINVAL;
+               }
+
+       translate(cbuf, msgs, num);
+       memcpy_toio(pt3->regs[1] + PT3_I2C_BASE + PT3_CMD_ADDR_NORMAL / 2,
+                       cbuf->data, cbuf->num_cmds);
+
+       if (send_i2c_cmd(pt3, PT3_CMD_ADDR_NORMAL) < 0)
+               return -EIO;
+
+       p = pt3->regs[1] + PT3_I2C_BASE;
+       for (i = 0; i < num; i++)
+               if ((msgs[i].flags & I2C_M_RD) && msgs[i].len > 0) {
+                       memcpy_fromio(msgs[i].buf, p, msgs[i].len);
+                       p += msgs[i].len;
+               }
+
+       return num;
+}
+
+u32 pt3_i2c_functionality(struct i2c_adapter *adap)
+{
+       return I2C_FUNC_I2C;
+}
index 18ae75546302daf04f66c0d3d213046bb092b1d0..b44e0d70907e2d876facc467e42608fc7fcb5760 100644 (file)
@@ -63,3 +63,11 @@ config VIDEO_SAA7134_DVB
 
          To compile this driver as a module, choose M here: the
          module will be called saa7134-dvb.
+
+config VIDEO_SAA7134_GO7007
+       tristate "go7007 support for saa7134 based TV cards"
+       depends on VIDEO_SAA7134
+       depends on VIDEO_GO7007
+       ---help---
+         Enables saa7134 driver support for boards with go7007
+         MPEG encoder (WIS Voyager or compatible).
index 58de9b085689bc101b01b2641db9e8f91f5a1b1c..09c43da675883058a581c96da0fe031feb73aa1f 100644 (file)
@@ -5,6 +5,7 @@ saa7134-y +=    saa7134-video.o
 saa7134-$(CONFIG_VIDEO_SAA7134_RC) += saa7134-input.o
 
 obj-$(CONFIG_VIDEO_SAA7134) +=  saa7134.o saa7134-empress.o
+obj-$(CONFIG_VIDEO_SAA7134_GO7007) += saa7134-go7007.o
 
 obj-$(CONFIG_VIDEO_SAA7134_ALSA) += saa7134-alsa.o
 
@@ -14,3 +15,4 @@ ccflags-y += -I$(srctree)/drivers/media/i2c
 ccflags-y += -I$(srctree)/drivers/media/tuners
 ccflags-y += -I$(srctree)/drivers/media/dvb-core
 ccflags-y += -I$(srctree)/drivers/media/dvb-frontends
+ccflags-y += -I$(srctree)/drivers/media/usb/go7007
index 6e4bdb90aa92e63c13d0d00c5bba90b4b4f09325..3ca078057755bd9a9384ca5f3c4886e7e35345d6 100644 (file)
@@ -5827,6 +5827,29 @@ struct saa7134_board saa7134_boards[] = {
                        .gpio = 0x0000800,
                },
        },
+       [SAA7134_BOARD_WIS_VOYAGER] = {
+               .name           = "WIS Voyager or compatible",
+               .audio_clock    = 0x00200000,
+               .tuner_type     = TUNER_PHILIPS_TDA8290,
+               .radio_type     = UNSET,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .mpeg           = SAA7134_MPEG_GO7007,
+               .inputs         = { {
+                       .name = name_comp1,
+                       .vmux = 0,
+                       .amux = LINE2,
+               }, {
+                       .name = name_tv,
+                       .vmux = 3,
+                       .amux = TV,
+                       .tv   = 1,
+               }, {
+                       .name = name_svideo,
+                       .vmux = 6,
+               .amux = LINE1,
+               } },
+       },
 
 };
 
@@ -7079,6 +7102,12 @@ struct pci_device_id saa7134_pci_tbl[] = {
                .subvendor    = 0x1461, /* Avermedia Technologies Inc */
                .subdevice    = 0x2055, /* AverTV Satellite Hybrid+FM A706 */
                .driver_data  = SAA7134_BOARD_AVERMEDIA_A706,
+       }, {
+               .vendor       = PCI_VENDOR_ID_PHILIPS,
+               .device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+               .subvendor    = 0x1905, /* WIS */
+               .subdevice    = 0x7007,
+               .driver_data  = SAA7134_BOARD_WIS_VOYAGER,
        }, {
                /* --- boards without eeprom + subsystem ID --- */
                .vendor       = PCI_VENDOR_ID_PHILIPS,
index 9ff03a69ced46f3bda31d10c7ac527c04064b68d..236ed725f933c141386d7f430747062a9ef7f473 100644 (file)
@@ -160,6 +160,8 @@ static void request_module_async(struct work_struct *work){
                request_module("saa7134-empress");
        if (card_is_dvb(dev))
                request_module("saa7134-dvb");
+       if (card_is_go7007(dev))
+               request_module("saa7134-go7007");
        if (alsa) {
                if (dev->pci->device != PCI_DEVICE_ID_PHILIPS_SAA7130)
                        request_module("saa7134-alsa");
@@ -563,8 +565,12 @@ static irqreturn_t saa7134_irq(int irq, void *dev_id)
                        saa7134_irq_vbi_done(dev,status);
 
                if ((report & SAA7134_IRQ_REPORT_DONE_RA2) &&
-                   card_has_mpeg(dev))
-                       saa7134_irq_ts_done(dev,status);
+                   card_has_mpeg(dev)) {
+                       if (dev->mops->irq_ts_done != NULL)
+                               dev->mops->irq_ts_done(dev, status);
+                       else
+                               saa7134_irq_ts_done(dev, status);
+               }
 
                if (report & SAA7134_IRQ_REPORT_GPIO16) {
                        switch (dev->has_remote) {
diff --git a/drivers/media/pci/saa7134/saa7134-go7007.c b/drivers/media/pci/saa7134/saa7134-go7007.c
new file mode 100644 (file)
index 0000000..54e650b
--- /dev/null
@@ -0,0 +1,531 @@
+/*
+ * Copyright (C) 2005-2006 Micronas USA 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.
+ *
+ * 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/init.h>
+#include <linux/spinlock.h>
+#include <linux/wait.h>
+#include <linux/list.h>
+#include <linux/slab.h>
+#include <linux/time.h>
+#include <linux/mm.h>
+#include <linux/usb.h>
+#include <linux/i2c.h>
+#include <asm/byteorder.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-subdev.h>
+
+#include "saa7134.h"
+#include "saa7134-reg.h"
+#include "go7007-priv.h"
+
+/*#define GO7007_HPI_DEBUG*/
+
+enum hpi_address {
+       HPI_ADDR_VIDEO_BUFFER = 0xe4,
+       HPI_ADDR_INIT_BUFFER = 0xea,
+       HPI_ADDR_INTR_RET_VALUE = 0xee,
+       HPI_ADDR_INTR_RET_DATA = 0xec,
+       HPI_ADDR_INTR_STATUS = 0xf4,
+       HPI_ADDR_INTR_WR_PARAM = 0xf6,
+       HPI_ADDR_INTR_WR_INDEX = 0xf8,
+};
+
+enum gpio_command {
+       GPIO_COMMAND_RESET = 0x00, /* 000b */
+       GPIO_COMMAND_REQ1  = 0x04, /* 001b */
+       GPIO_COMMAND_WRITE = 0x20, /* 010b */
+       GPIO_COMMAND_REQ2  = 0x24, /* 011b */
+       GPIO_COMMAND_READ  = 0x80, /* 100b */
+       GPIO_COMMAND_VIDEO = 0x84, /* 101b */
+       GPIO_COMMAND_IDLE  = 0xA0, /* 110b */
+       GPIO_COMMAND_ADDR  = 0xA4, /* 111b */
+};
+
+struct saa7134_go7007 {
+       struct v4l2_subdev sd;
+       struct saa7134_dev *dev;
+       u8 *top;
+       u8 *bottom;
+       dma_addr_t top_dma;
+       dma_addr_t bottom_dma;
+};
+
+static inline struct saa7134_go7007 *to_state(struct v4l2_subdev *sd)
+{
+       return container_of(sd, struct saa7134_go7007, sd);
+}
+
+static const struct go7007_board_info board_voyager = {
+       .flags           = 0,
+       .sensor_flags    = GO7007_SENSOR_656 |
+                               GO7007_SENSOR_VALID_ENABLE |
+                               GO7007_SENSOR_TV |
+                               GO7007_SENSOR_VBI,
+       .audio_flags    = GO7007_AUDIO_I2S_MODE_1 |
+                               GO7007_AUDIO_WORD_16,
+       .audio_rate      = 48000,
+       .audio_bclk_div  = 8,
+       .audio_main_div  = 2,
+       .hpi_buffer_cap  = 7,
+       .num_inputs      = 1,
+       .inputs          = {
+               {
+                       .name           = "SAA7134",
+               },
+       },
+};
+
+/********************* Driver for GPIO HPI interface *********************/
+
+static int gpio_write(struct saa7134_dev *dev, u8 addr, u16 data)
+{
+       saa_writeb(SAA7134_GPIO_GPMODE0, 0xff);
+
+       /* Write HPI address */
+       saa_writeb(SAA7134_GPIO_GPSTATUS0, addr);
+       saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_ADDR);
+       saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_IDLE);
+
+       /* Write low byte */
+       saa_writeb(SAA7134_GPIO_GPSTATUS0, data & 0xff);
+       saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_WRITE);
+       saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_IDLE);
+
+       /* Write high byte */
+       saa_writeb(SAA7134_GPIO_GPSTATUS0, data >> 8);
+       saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_WRITE);
+       saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_IDLE);
+
+       return 0;
+}
+
+static int gpio_read(struct saa7134_dev *dev, u8 addr, u16 *data)
+{
+       saa_writeb(SAA7134_GPIO_GPMODE0, 0xff);
+
+       /* Write HPI address */
+       saa_writeb(SAA7134_GPIO_GPSTATUS0, addr);
+       saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_ADDR);
+       saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_IDLE);
+
+       saa_writeb(SAA7134_GPIO_GPMODE0, 0x00);
+
+       /* Read low byte */
+       saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_READ);
+       saa_clearb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN);
+       saa_setb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN);
+       *data = saa_readb(SAA7134_GPIO_GPSTATUS0);
+       saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_IDLE);
+
+       /* Read high byte */
+       saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_READ);
+       saa_clearb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN);
+       saa_setb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN);
+       *data |= saa_readb(SAA7134_GPIO_GPSTATUS0) << 8;
+       saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_IDLE);
+
+       return 0;
+}
+
+static int saa7134_go7007_interface_reset(struct go7007 *go)
+{
+       struct saa7134_go7007 *saa = go->hpi_context;
+       struct saa7134_dev *dev = saa->dev;
+       u16 intr_val, intr_data;
+       int count = 20;
+
+       saa_clearb(SAA7134_TS_PARALLEL, 0x80); /* Disable TS interface */
+       saa_writeb(SAA7134_GPIO_GPMODE2, 0xa4);
+       saa_writeb(SAA7134_GPIO_GPMODE0, 0xff);
+
+       saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_REQ1);
+       saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_RESET);
+       msleep(1);
+       saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_REQ1);
+       saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_REQ2);
+       msleep(10);
+
+       saa_clearb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN);
+       saa_setb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN);
+
+       saa_readb(SAA7134_GPIO_GPSTATUS2);
+       /*pr_debug("status is %s\n", saa_readb(SAA7134_GPIO_GPSTATUS2) & 0x40 ? "OK" : "not OK"); */
+
+       /* enter command mode...(?) */
+       saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_REQ1);
+       saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_REQ2);
+
+       do {
+               saa_clearb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN);
+               saa_setb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN);
+               saa_readb(SAA7134_GPIO_GPSTATUS2);
+               /*pr_info("gpio is %08x\n", saa_readl(SAA7134_GPIO_GPSTATUS0 >> 2)); */
+       } while (--count > 0);
+
+       /* Wait for an interrupt to indicate successful hardware reset */
+       if (go7007_read_interrupt(go, &intr_val, &intr_data) < 0 ||
+                       (intr_val & ~0x1) != 0x55aa) {
+               pr_err("saa7134-go7007: unable to reset the GO7007\n");
+               return -1;
+       }
+       return 0;
+}
+
+static int saa7134_go7007_write_interrupt(struct go7007 *go, int addr, int data)
+{
+       struct saa7134_go7007 *saa = go->hpi_context;
+       struct saa7134_dev *dev = saa->dev;
+       int i;
+       u16 status_reg;
+
+#ifdef GO7007_HPI_DEBUG
+       pr_debug("saa7134-go7007: WriteInterrupt: %04x %04x\n", addr, data);
+#endif
+
+       for (i = 0; i < 100; ++i) {
+               gpio_read(dev, HPI_ADDR_INTR_STATUS, &status_reg);
+               if (!(status_reg & 0x0010))
+                       break;
+               msleep(10);
+       }
+       if (i == 100) {
+               pr_err("saa7134-go7007: device is hung, status reg = 0x%04x\n",
+                       status_reg);
+               return -1;
+       }
+       gpio_write(dev, HPI_ADDR_INTR_WR_PARAM, data);
+       gpio_write(dev, HPI_ADDR_INTR_WR_INDEX, addr);
+
+       return 0;
+}
+
+static int saa7134_go7007_read_interrupt(struct go7007 *go)
+{
+       struct saa7134_go7007 *saa = go->hpi_context;
+       struct saa7134_dev *dev = saa->dev;
+
+       /* XXX we need to wait if there is no interrupt available */
+       go->interrupt_available = 1;
+       gpio_read(dev, HPI_ADDR_INTR_RET_VALUE, &go->interrupt_value);
+       gpio_read(dev, HPI_ADDR_INTR_RET_DATA, &go->interrupt_data);
+#ifdef GO7007_HPI_DEBUG
+       pr_debug("saa7134-go7007: ReadInterrupt: %04x %04x\n",
+                       go->interrupt_value, go->interrupt_data);
+#endif
+       return 0;
+}
+
+static void saa7134_go7007_irq_ts_done(struct saa7134_dev *dev,
+                                               unsigned long status)
+{
+       struct go7007 *go = video_get_drvdata(dev->empress_dev);
+       struct saa7134_go7007 *saa = go->hpi_context;
+
+       if (!vb2_is_streaming(&go->vidq))
+               return;
+       if (0 != (status & 0x000f0000))
+               pr_debug("saa7134-go7007: irq: lost %ld\n",
+                               (status >> 16) & 0x0f);
+       if (status & 0x100000) {
+               dma_sync_single_for_cpu(&dev->pci->dev,
+                                       saa->bottom_dma, PAGE_SIZE, DMA_FROM_DEVICE);
+               go7007_parse_video_stream(go, saa->bottom, PAGE_SIZE);
+               saa_writel(SAA7134_RS_BA2(5), saa->bottom_dma);
+       } else {
+               dma_sync_single_for_cpu(&dev->pci->dev,
+                                       saa->top_dma, PAGE_SIZE, DMA_FROM_DEVICE);
+               go7007_parse_video_stream(go, saa->top, PAGE_SIZE);
+               saa_writel(SAA7134_RS_BA1(5), saa->top_dma);
+       }
+}
+
+static int saa7134_go7007_stream_start(struct go7007 *go)
+{
+       struct saa7134_go7007 *saa = go->hpi_context;
+       struct saa7134_dev *dev = saa->dev;
+
+       saa->top_dma = dma_map_page(&dev->pci->dev, virt_to_page(saa->top),
+                       0, PAGE_SIZE, DMA_FROM_DEVICE);
+       if (dma_mapping_error(&dev->pci->dev, saa->top_dma))
+               return -ENOMEM;
+       saa->bottom_dma = dma_map_page(&dev->pci->dev,
+                       virt_to_page(saa->bottom),
+                       0, PAGE_SIZE, DMA_FROM_DEVICE);
+       if (dma_mapping_error(&dev->pci->dev, saa->bottom_dma)) {
+               dma_unmap_page(&dev->pci->dev, saa->top_dma, PAGE_SIZE,
+                               DMA_FROM_DEVICE);
+               return -ENOMEM;
+       }
+
+       saa_writel(SAA7134_VIDEO_PORT_CTRL0 >> 2, 0xA300B000);
+       saa_writel(SAA7134_VIDEO_PORT_CTRL4 >> 2, 0x40000200);
+
+       /* Set HPI interface for video */
+       saa_writeb(SAA7134_GPIO_GPMODE0, 0xff);
+       saa_writeb(SAA7134_GPIO_GPSTATUS0, HPI_ADDR_VIDEO_BUFFER);
+       saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_ADDR);
+       saa_writeb(SAA7134_GPIO_GPMODE0, 0x00);
+
+       /* Enable TS interface */
+       saa_writeb(SAA7134_TS_PARALLEL, 0xe6);
+
+       /* Reset TS interface */
+       saa_setb(SAA7134_TS_SERIAL1, 0x01);
+       saa_clearb(SAA7134_TS_SERIAL1, 0x01);
+
+       /* Set up transfer block size */
+       saa_writeb(SAA7134_TS_PARALLEL_SERIAL, 128 - 1);
+       saa_writeb(SAA7134_TS_DMA0, (PAGE_SIZE >> 7) - 1);
+       saa_writeb(SAA7134_TS_DMA1, 0);
+       saa_writeb(SAA7134_TS_DMA2, 0);
+
+       /* Enable video streaming mode */
+       saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_VIDEO);
+
+       saa_writel(SAA7134_RS_BA1(5), saa->top_dma);
+       saa_writel(SAA7134_RS_BA2(5), saa->bottom_dma);
+       saa_writel(SAA7134_RS_PITCH(5), 128);
+       saa_writel(SAA7134_RS_CONTROL(5), SAA7134_RS_CONTROL_BURST_MAX);
+
+       /* Enable TS FIFO */
+       saa_setl(SAA7134_MAIN_CTRL, SAA7134_MAIN_CTRL_TE5);
+
+       /* Enable DMA IRQ */
+       saa_setl(SAA7134_IRQ1,
+                       SAA7134_IRQ1_INTE_RA2_1 | SAA7134_IRQ1_INTE_RA2_0);
+
+       return 0;
+}
+
+static int saa7134_go7007_stream_stop(struct go7007 *go)
+{
+       struct saa7134_go7007 *saa = go->hpi_context;
+       struct saa7134_dev *dev;
+
+       if (!saa)
+               return -EINVAL;
+       dev = saa->dev;
+       if (!dev)
+               return -EINVAL;
+
+       /* Shut down TS FIFO */
+       saa_clearl(SAA7134_MAIN_CTRL, SAA7134_MAIN_CTRL_TE5);
+
+       /* Disable DMA IRQ */
+       saa_clearl(SAA7134_IRQ1,
+                       SAA7134_IRQ1_INTE_RA2_1 | SAA7134_IRQ1_INTE_RA2_0);
+
+       /* Disable TS interface */
+       saa_clearb(SAA7134_TS_PARALLEL, 0x80);
+
+       dma_unmap_page(&dev->pci->dev, saa->top_dma, PAGE_SIZE,
+                       DMA_FROM_DEVICE);
+       dma_unmap_page(&dev->pci->dev, saa->bottom_dma, PAGE_SIZE,
+                       DMA_FROM_DEVICE);
+
+       return 0;
+}
+
+static int saa7134_go7007_send_firmware(struct go7007 *go, u8 *data, int len)
+{
+       struct saa7134_go7007 *saa = go->hpi_context;
+       struct saa7134_dev *dev = saa->dev;
+       u16 status_reg;
+       int i;
+
+#ifdef GO7007_HPI_DEBUG
+       pr_debug("saa7134-go7007: DownloadBuffer sending %d bytes\n", len);
+#endif
+
+       while (len > 0) {
+               i = len > 64 ? 64 : len;
+               saa_writeb(SAA7134_GPIO_GPMODE0, 0xff);
+               saa_writeb(SAA7134_GPIO_GPSTATUS0, HPI_ADDR_INIT_BUFFER);
+               saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_ADDR);
+               saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_IDLE);
+               while (i-- > 0) {
+                       saa_writeb(SAA7134_GPIO_GPSTATUS0, *data);
+                       saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_WRITE);
+                       saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_IDLE);
+                       ++data;
+                       --len;
+               }
+               for (i = 0; i < 100; ++i) {
+                       gpio_read(dev, HPI_ADDR_INTR_STATUS, &status_reg);
+                       if (!(status_reg & 0x0002))
+                               break;
+               }
+               if (i == 100) {
+                       pr_err("saa7134-go7007: device is hung, status reg = 0x%04x\n",
+                              status_reg);
+                       return -1;
+               }
+       }
+       return 0;
+}
+
+static struct go7007_hpi_ops saa7134_go7007_hpi_ops = {
+       .interface_reset        = saa7134_go7007_interface_reset,
+       .write_interrupt        = saa7134_go7007_write_interrupt,
+       .read_interrupt         = saa7134_go7007_read_interrupt,
+       .stream_start           = saa7134_go7007_stream_start,
+       .stream_stop            = saa7134_go7007_stream_stop,
+       .send_firmware          = saa7134_go7007_send_firmware,
+};
+MODULE_FIRMWARE("go7007/go7007tv.bin");
+
+/* --------------------------------------------------------------------------*/
+
+static int saa7134_go7007_s_std(struct v4l2_subdev *sd, v4l2_std_id norm)
+{
+#if 0
+       struct saa7134_go7007 *saa = to_state(sd);
+       struct saa7134_dev *dev = saa->dev;
+
+       return saa7134_s_std_internal(dev, NULL, norm);
+#else
+       return 0;
+#endif
+}
+
+static const struct v4l2_subdev_video_ops saa7134_go7007_video_ops = {
+       .s_std = saa7134_go7007_s_std,
+};
+
+static const struct v4l2_subdev_ops saa7134_go7007_sd_ops = {
+       .video = &saa7134_go7007_video_ops,
+};
+
+/* --------------------------------------------------------------------------*/
+
+
+/********************* Add/remove functions *********************/
+
+static int saa7134_go7007_init(struct saa7134_dev *dev)
+{
+       struct go7007 *go;
+       struct saa7134_go7007 *saa;
+       struct v4l2_subdev *sd;
+
+       pr_debug("saa7134-go7007: probing new SAA713X board\n");
+
+       go = go7007_alloc(&board_voyager, &dev->pci->dev);
+       if (go == NULL)
+               return -ENOMEM;
+
+       saa = kzalloc(sizeof(struct saa7134_go7007), GFP_KERNEL);
+       if (saa == NULL) {
+               kfree(go);
+               return -ENOMEM;
+       }
+
+       go->board_id = GO7007_BOARDID_PCI_VOYAGER;
+       snprintf(go->bus_info, sizeof(go->bus_info), "PCI:%s", pci_name(dev->pci));
+       strlcpy(go->name, saa7134_boards[dev->board].name, sizeof(go->name));
+       go->hpi_ops = &saa7134_go7007_hpi_ops;
+       go->hpi_context = saa;
+       saa->dev = dev;
+
+       /* Init the subdevice interface */
+       sd = &saa->sd;
+       v4l2_subdev_init(sd, &saa7134_go7007_sd_ops);
+       v4l2_set_subdevdata(sd, saa);
+       strncpy(sd->name, "saa7134-go7007", sizeof(sd->name));
+
+       /* Allocate a couple pages for receiving the compressed stream */
+       saa->top = (u8 *)get_zeroed_page(GFP_KERNEL);
+       if (!saa->top)
+               goto allocfail;
+       saa->bottom = (u8 *)get_zeroed_page(GFP_KERNEL);
+       if (!saa->bottom)
+               goto allocfail;
+
+       /* Boot the GO7007 */
+       if (go7007_boot_encoder(go, go->board_info->flags &
+                                       GO7007_BOARD_USE_ONBOARD_I2C) < 0)
+               goto allocfail;
+
+       /* Do any final GO7007 initialization, then register the
+        * V4L2 and ALSA interfaces */
+       if (go7007_register_encoder(go, go->board_info->num_i2c_devs) < 0)
+               goto allocfail;
+
+       /* Register the subdevice interface with the go7007 device */
+       if (v4l2_device_register_subdev(&go->v4l2_dev, sd) < 0)
+               pr_info("saa7134-go7007: register subdev failed\n");
+
+       dev->empress_dev = &go->vdev;
+
+       go->status = STATUS_ONLINE;
+       return 0;
+
+allocfail:
+       if (saa->top)
+               free_page((unsigned long)saa->top);
+       if (saa->bottom)
+               free_page((unsigned long)saa->bottom);
+       kfree(saa);
+       kfree(go);
+       return -ENOMEM;
+}
+
+static int saa7134_go7007_fini(struct saa7134_dev *dev)
+{
+       struct go7007 *go;
+       struct saa7134_go7007 *saa;
+
+       if (NULL == dev->empress_dev)
+               return 0;
+
+       go = video_get_drvdata(dev->empress_dev);
+       if (go->audio_enabled)
+               go7007_snd_remove(go);
+
+       saa = go->hpi_context;
+       go->status = STATUS_SHUTDOWN;
+       free_page((unsigned long)saa->top);
+       free_page((unsigned long)saa->bottom);
+       v4l2_device_unregister_subdev(&saa->sd);
+       kfree(saa);
+       video_unregister_device(&go->vdev);
+
+       v4l2_device_put(&go->v4l2_dev);
+       dev->empress_dev = NULL;
+
+       return 0;
+}
+
+static struct saa7134_mpeg_ops saa7134_go7007_ops = {
+       .type          = SAA7134_MPEG_GO7007,
+       .init          = saa7134_go7007_init,
+       .fini          = saa7134_go7007_fini,
+       .irq_ts_done   = saa7134_go7007_irq_ts_done,
+};
+
+static int __init saa7134_go7007_mod_init(void)
+{
+       return saa7134_ts_register(&saa7134_go7007_ops);
+}
+
+static void __exit saa7134_go7007_mod_cleanup(void)
+{
+       saa7134_ts_unregister(&saa7134_go7007_ops);
+}
+
+module_init(saa7134_go7007_mod_init);
+module_exit(saa7134_go7007_mod_cleanup);
+
+MODULE_LICENSE("GPL v2");
index c06dbe17a87f03303dc72b2e2500dc037c87ad4d..4f0b1012e4f39d308b445ae198ce30231509a8f1 100644 (file)
@@ -43,7 +43,7 @@ MODULE_PARM_DESC(vbibufs,"number of vbi buffers, range 2-32");
 
 /* ------------------------------------------------------------------ */
 
-#define VBI_LINE_COUNT     16
+#define VBI_LINE_COUNT     17
 #define VBI_LINE_LENGTH  2048
 #define VBI_SCALE       0x200
 
index 0cfa2ca6a32ad2c1e3a03a952792fdcb590cc146..fc4a427cb51fed9bea0cf9ec16bab44e5408ec70 100644 (file)
@@ -201,7 +201,7 @@ static struct saa7134_format formats[] = {
                .video_v_start = 24,    \
                .video_v_stop  = 311,   \
                .vbi_v_start_0 = 7,     \
-               .vbi_v_stop_0  = 22,    \
+               .vbi_v_stop_0  = 23,    \
                .vbi_v_start_1 = 319,   \
                .src_timing    = 4
 
index e47edd4b57ce30c2c8fee0fdba8153bc1f37eaed..1a82dd07205b9dfb2b1457939d0be7027937873a 100644 (file)
@@ -338,6 +338,7 @@ struct saa7134_card_ir {
 #define SAA7134_BOARD_ASUSTeK_PS3_100      190
 #define SAA7134_BOARD_HAWELL_HW_9004V1      191
 #define SAA7134_BOARD_AVERMEDIA_A706           192
+#define SAA7134_BOARD_WIS_VOYAGER           193
 
 #define SAA7134_MAXBOARDS 32
 #define SAA7134_INPUT_MAX 8
@@ -368,6 +369,7 @@ enum saa7134_mpeg_type {
        SAA7134_MPEG_UNUSED,
        SAA7134_MPEG_EMPRESS,
        SAA7134_MPEG_DVB,
+       SAA7134_MPEG_GO7007,
 };
 
 enum saa7134_mpeg_ts_type {
@@ -407,6 +409,7 @@ struct saa7134_board {
 #define card_has_radio(dev)   (NULL != saa7134_boards[dev->board].radio.name)
 #define card_is_empress(dev)  (SAA7134_MPEG_EMPRESS == saa7134_boards[dev->board].mpeg)
 #define card_is_dvb(dev)      (SAA7134_MPEG_DVB     == saa7134_boards[dev->board].mpeg)
+#define card_is_go7007(dev)   (SAA7134_MPEG_GO7007  == saa7134_boards[dev->board].mpeg)
 #define card_has_mpeg(dev)    (SAA7134_MPEG_UNUSED  != saa7134_boards[dev->board].mpeg)
 #define card(dev)             (saa7134_boards[dev->board])
 #define card_in(dev,n)        (saa7134_boards[dev->board].inputs[n])
@@ -522,6 +525,8 @@ struct saa7134_mpeg_ops {
        int                        (*init)(struct saa7134_dev *dev);
        int                        (*fini)(struct saa7134_dev *dev);
        void                       (*signal_change)(struct saa7134_dev *dev);
+       void                       (*irq_ts_done)(struct saa7134_dev *dev,
+                                                 unsigned long status);
 };
 
 /* global device status */
index e042963d377d0c8dc9b7c6d94225f1ccb5983549..4f3b1dd18ba4db4335ab87c34b02fc1ea5f2e012 100644 (file)
@@ -680,7 +680,6 @@ static int saa7164_api_set_dif(struct saa7164_port *port, u8 reg, u8 val)
 int saa7164_api_configure_dif(struct saa7164_port *port, u32 std)
 {
        struct saa7164_dev *dev = port->dev;
-       int ret = 0;
        u8 agc_disable;
 
        dprintk(DBGLVL_API, "%s(nr=%d, 0x%x)\n", __func__, port->nr, std);
@@ -733,7 +732,7 @@ int saa7164_api_configure_dif(struct saa7164_port *port, u32 std)
        saa7164_api_set_dif(port, 0x04, 0x00); /* Active (again) */
        msleep(100);
 
-       return ret;
+       return 0;
 }
 
 /* Ensure the dif is in the correct state for the operating mode
index 1bf06970ca3e8e180cb6a2f20d732c983af820b2..cc1be8a7a4510259b9dcb271f02f85325c3d7826 100644 (file)
@@ -52,7 +52,7 @@ unsigned int saa_debug;
 module_param_named(debug, saa_debug, int, 0644);
 MODULE_PARM_DESC(debug, "enable debug messages");
 
-unsigned int fw_debug;
+static unsigned int fw_debug;
 module_param(fw_debug, int, 0644);
 MODULE_PARM_DESC(fw_debug, "Firmware debug level def:2");
 
@@ -72,7 +72,7 @@ static unsigned int card[]  = {[0 ... (SAA7164_MAXBOARDS - 1)] = UNSET };
 module_param_array(card,  int, NULL, 0444);
 MODULE_PARM_DESC(card, "card type");
 
-unsigned int print_histogram = 64;
+static unsigned int print_histogram = 64;
 module_param(print_histogram, int, 0644);
 MODULE_PARM_DESC(print_histogram, "print histogram values once");
 
@@ -80,7 +80,7 @@ unsigned int crc_checking = 1;
 module_param(crc_checking, int, 0644);
 MODULE_PARM_DESC(crc_checking, "enable crc sanity checking on buffers");
 
-unsigned int guard_checking = 1;
+static unsigned int guard_checking = 1;
 module_param(guard_checking, int, 0644);
 MODULE_PARM_DESC(guard_checking,
        "enable dma sanity checking for buffer overruns");
index d9e06a6bf1ebc1a7de4b498361bac87f9cabe9d4..0fb91dc7ca73529eda55bb894287cbdc084e8fd0 100644 (file)
@@ -1,6 +1,7 @@
 config VIDEO_SOLO6X10
        tristate "Bluecherry / Softlogic 6x10 capture cards (MPEG-4/H.264)"
        depends on PCI && VIDEO_DEV && SND && I2C
+       depends on HAS_DMA
        select BITREVERSE
        select FONT_SUPPORT
        select FONT_8x16
index 5ea9cac03968ee6d1b87d17f129cc4a8d37c85dc..11c98f0625e49bfaecf6e26cb5ade05b50796e25 100644 (file)
@@ -172,7 +172,7 @@ static void solo_vout_config(struct solo_dev *solo_dev)
 static int solo_dma_vin_region(struct solo_dev *solo_dev, u32 off,
                               u16 val, int reg_size)
 {
-       u16 *buf;
+       __le16 *buf;
        const int n = 64, size = n * sizeof(*buf);
        int i, ret = 0;
 
@@ -211,7 +211,7 @@ int solo_set_motion_block(struct solo_dev *solo_dev, u8 ch,
 {
        const unsigned size = sizeof(u16) * 64;
        u32 off = SOLO_MOT_FLAG_AREA + ch * SOLO_MOT_THRESH_SIZE * 2;
-       u16 *buf;
+       __le16 *buf;
        int x, y;
        int ret = 0;
 
index af40b3aba41006cc4565555845c34a177dfe42df..da25ce4a69526187520ffa790f8fe6e50e04aba7 100644 (file)
@@ -100,7 +100,7 @@ unsigned int solo_eeprom_ewen(struct solo_dev *solo_dev, int w_en)
        return retval;
 }
 
-unsigned short solo_eeprom_read(struct solo_dev *solo_dev, int loc)
+__be16 solo_eeprom_read(struct solo_dev *solo_dev, int loc)
 {
        int read_cmd = loc | (EE_READ_CMD << ADDR_LEN);
        unsigned short retval = 0;
@@ -117,11 +117,11 @@ unsigned short solo_eeprom_read(struct solo_dev *solo_dev, int loc)
 
        solo_eeprom_reg_write(solo_dev, ~EE_CS);
 
-       return retval;
+       return (__force __be16)retval;
 }
 
 int solo_eeprom_write(struct solo_dev *solo_dev, int loc,
-                     unsigned short data)
+                     __be16 data)
 {
        int write_cmd = loc | (EE_WRITE_CMD << ADDR_LEN);
        unsigned int retval;
@@ -130,7 +130,7 @@ int solo_eeprom_write(struct solo_dev *solo_dev, int loc,
        solo_eeprom_cmd(solo_dev, write_cmd);
 
        for (i = 15; i >= 0; i--) {
-               unsigned int dataval = (data >> i) & 1;
+               unsigned int dataval = ((__force unsigned)data >> i) & 1;
 
                solo_eeprom_reg_write(solo_dev, EE_ENB);
                solo_eeprom_reg_write(solo_dev,
index c6154b00fcbd9250e4b9b50bfb0ded1b56701731..72017b7f0a753d1161dcced8ffe5fa3cc3679503 100644 (file)
@@ -394,9 +394,9 @@ int solo_osd_print(struct solo_enc_dev *solo_enc);
 
 /* EEPROM commands */
 unsigned int solo_eeprom_ewen(struct solo_dev *solo_dev, int w_en);
-unsigned short solo_eeprom_read(struct solo_dev *solo_dev, int loc);
+__be16 solo_eeprom_read(struct solo_dev *solo_dev, int loc);
 int solo_eeprom_write(struct solo_dev *solo_dev, int loc,
-                     unsigned short data);
+                     __be16 data);
 
 /* JPEG Qp functions */
 void solo_s_jpeg_qp(struct solo_dev *solo_dev, unsigned int ch,
index 03130157db83c28001d2d3ac2986117869f8bc7b..f6f30abc088ba26e4ce547b7f2cf9bac12122be7 100644 (file)
@@ -1,6 +1,7 @@
 config STA2X11_VIP
        tristate "STA2X11 VIP Video For Linux"
        depends on STA2X11
+       depends on HAS_DMA
        select VIDEO_ADV7180 if MEDIA_SUBDRV_AUTOSELECT
        select VIDEOBUF2_DMA_CONTIG
        depends on PCI && VIDEO_V4L2 && VIRT_TO_BUS
index 365bd21301baa494744238eea568fea16ec29e5d..22450f583da1750e743b27aeb1fa4b7ce7f805f8 100644 (file)
@@ -152,7 +152,7 @@ struct sta2x11_vip {
        int tcount, bcount;
        int overflow;
 
-       void *iomem;    /* I/O Memory */
+       void __iomem *iomem;    /* I/O Memory */
        struct vip_config *config;
 };
 
index 0dcb8cd7767698d101860c111f65751c3951461e..7b83151ed6c48dd665a021c43438e61b453f2cce 100644 (file)
@@ -1,8 +1,12 @@
+config DVB_AV7110_IR
+       bool
+
 config DVB_AV7110
        tristate "AV7110 cards"
        depends on DVB_CORE && PCI && I2C
        select TTPCI_EEPROM
        select VIDEO_SAA7146_VV
+       select DVB_AV7110_IR if INPUT_EVDEV=y || INPUT_EVDEV=DVB_AV7110
        depends on VIDEO_DEV    # dependencies of VIDEO_SAA7146_VV
        select DVB_VES1820 if MEDIA_SUBDRV_AUTOSELECT
        select DVB_VES1X93 if MEDIA_SUBDRV_AUTOSELECT
index 98905963ff085c0b0e265b7bf26ae0d892aa6a83..49f71b1eaf14b529689f82e658d44a09b285ddbf 100644 (file)
@@ -5,7 +5,7 @@
 
 dvb-ttpci-objs := av7110_hw.o av7110_v4l.o av7110_av.o av7110_ca.o av7110.o av7110_ipack.o
 
-ifdef CONFIG_INPUT_EVDEV
+ifdef CONFIG_DVB_AV7110_IR
 dvb-ttpci-objs += av7110_ir.o
 endif
 
index f38329d29daa8c41a83823deb0d2f87de7a079ff..c1f0617a69733df52b924668457a955ab39806f1 100644 (file)
@@ -235,7 +235,7 @@ static void recover_arm(struct av7110 *av7110)
 
        restart_feeds(av7110);
 
-#if IS_ENABLED(CONFIG_INPUT_EVDEV)
+#if IS_ENABLED(CONFIG_DVB_AV7110_IR)
        av7110_check_ir_config(av7110, true);
 #endif
 }
@@ -268,7 +268,7 @@ static int arm_thread(void *data)
                if (!av7110->arm_ready)
                        continue;
 
-#if IS_ENABLED(CONFIG_INPUT_EVDEV)
+#if IS_ENABLED(CONFIG_DVB_AV7110_IR)
                av7110_check_ir_config(av7110, false);
 #endif
 
@@ -2725,7 +2725,7 @@ static int av7110_attach(struct saa7146_dev* dev,
 
        mutex_init(&av7110->ioctl_mutex);
 
-#if IS_ENABLED(CONFIG_INPUT_EVDEV)
+#if IS_ENABLED(CONFIG_DVB_AV7110_IR)
        av7110_ir_init(av7110);
 #endif
        printk(KERN_INFO "dvb-ttpci: found av7110-%d.\n", av7110_num);
@@ -2768,7 +2768,7 @@ static int av7110_detach(struct saa7146_dev* saa)
        struct av7110 *av7110 = saa->ext_priv;
        dprintk(4, "%p\n", av7110);
 
-#if IS_ENABLED(CONFIG_INPUT_EVDEV)
+#if IS_ENABLED(CONFIG_DVB_AV7110_IR)
        av7110_ir_exit(av7110);
 #endif
        if (budgetpatch || av7110->full_ts) {
diff --git a/drivers/media/pci/tw68/Kconfig b/drivers/media/pci/tw68/Kconfig
new file mode 100644 (file)
index 0000000..5425ba1
--- /dev/null
@@ -0,0 +1,10 @@
+config VIDEO_TW68
+       tristate "Techwell tw68x Video For Linux"
+       depends on VIDEO_DEV && PCI && VIDEO_V4L2
+       select I2C_ALGOBIT
+       select VIDEOBUF2_DMA_SG
+       ---help---
+         Support for Techwell tw68xx based frame grabber boards.
+
+         To compile this driver as a module, choose M here: the
+         module will be called tw68.
diff --git a/drivers/media/pci/tw68/Makefile b/drivers/media/pci/tw68/Makefile
new file mode 100644 (file)
index 0000000..3d02f28
--- /dev/null
@@ -0,0 +1,3 @@
+tw68-objs := tw68-core.o tw68-video.o tw68-risc.o
+
+obj-$(CONFIG_VIDEO_TW68) += tw68.o
diff --git a/drivers/media/pci/tw68/tw68-core.c b/drivers/media/pci/tw68/tw68-core.c
new file mode 100644 (file)
index 0000000..a6fb48c
--- /dev/null
@@ -0,0 +1,434 @@
+/*
+ *  tw68-core.c
+ *  Core functions for the Techwell 68xx driver
+ *
+ *  Much of this code is derived from the cx88 and sa7134 drivers, which
+ *  were in turn derived from the bt87x driver.  The original work was by
+ *  Gerd Knorr; more recently the code was enhanced by Mauro Carvalho Chehab,
+ *  Hans Verkuil, Andy Walls and many others.  Their work is gratefully
+ *  acknowledged.  Full credit goes to them - any problems within this code
+ *  are mine.
+ *
+ *  Copyright (C) 2009  William M. Brack
+ *
+ *  Refactored and updated to the latest v4l core frameworks:
+ *
+ *  Copyright (C) 2014 Hans Verkuil <hverkuil@xs4all.nl>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ */
+
+#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/kmod.h>
+#include <linux/sound.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/mutex.h>
+#include <linux/dma-mapping.h>
+#include <linux/pm.h>
+
+#include <media/v4l2-dev.h>
+#include "tw68.h"
+#include "tw68-reg.h"
+
+MODULE_DESCRIPTION("v4l2 driver module for tw6800 based video capture cards");
+MODULE_AUTHOR("William M. Brack");
+MODULE_AUTHOR("Hans Verkuil <hverkuil@xs4all.nl>");
+MODULE_LICENSE("GPL");
+
+static unsigned int latency = UNSET;
+module_param(latency, int, 0444);
+MODULE_PARM_DESC(latency, "pci latency timer");
+
+static unsigned int video_nr[] = {[0 ... (TW68_MAXBOARDS - 1)] = UNSET };
+module_param_array(video_nr, int, NULL, 0444);
+MODULE_PARM_DESC(video_nr, "video device number");
+
+static unsigned int card[] = {[0 ... (TW68_MAXBOARDS - 1)] = UNSET };
+module_param_array(card, int, NULL, 0444);
+MODULE_PARM_DESC(card, "card type");
+
+static atomic_t tw68_instance = ATOMIC_INIT(0);
+
+/* ------------------------------------------------------------------ */
+
+/*
+ * Please add any new PCI IDs to: http://pci-ids.ucw.cz.  This keeps
+ * the PCI ID database up to date.  Note that the entries must be
+ * added under vendor 0x1797 (Techwell Inc.) as subsystem IDs.
+ */
+static const struct pci_device_id tw68_pci_tbl[] = {
+       {PCI_DEVICE(PCI_VENDOR_ID_TECHWELL, PCI_DEVICE_ID_6800)},
+       {PCI_DEVICE(PCI_VENDOR_ID_TECHWELL, PCI_DEVICE_ID_6801)},
+       {PCI_DEVICE(PCI_VENDOR_ID_TECHWELL, PCI_DEVICE_ID_6804)},
+       {PCI_DEVICE(PCI_VENDOR_ID_TECHWELL, PCI_DEVICE_ID_6816_1)},
+       {PCI_DEVICE(PCI_VENDOR_ID_TECHWELL, PCI_DEVICE_ID_6816_2)},
+       {PCI_DEVICE(PCI_VENDOR_ID_TECHWELL, PCI_DEVICE_ID_6816_3)},
+       {PCI_DEVICE(PCI_VENDOR_ID_TECHWELL, PCI_DEVICE_ID_6816_4)},
+       {0,}
+};
+
+/* ------------------------------------------------------------------ */
+
+
+/*
+ * The device is given a "soft reset". According to the specifications,
+ * after this "all register content remain unchanged", so we also write
+ * to all specified registers manually as well (mostly to manufacturer's
+ * specified reset values)
+ */
+static int tw68_hw_init1(struct tw68_dev *dev)
+{
+       /* Assure all interrupts are disabled */
+       tw_writel(TW68_INTMASK, 0);             /* 020 */
+       /* Clear any pending interrupts */
+       tw_writel(TW68_INTSTAT, 0xffffffff);    /* 01C */
+       /* Stop risc processor, set default buffer level */
+       tw_writel(TW68_DMAC, 0x1600);
+
+       tw_writeb(TW68_ACNTL, 0x80);    /* 218  soft reset */
+       msleep(100);
+
+       tw_writeb(TW68_INFORM, 0x40);   /* 208  mux0, 27mhz xtal */
+       tw_writeb(TW68_OPFORM, 0x04);   /* 20C  analog line-lock */
+       tw_writeb(TW68_HSYNC, 0);       /* 210  color-killer high sens */
+       tw_writeb(TW68_ACNTL, 0x42);    /* 218  int vref #2, chroma adc off */
+
+       tw_writeb(TW68_CROP_HI, 0x02);  /* 21C  Hactive m.s. bits */
+       tw_writeb(TW68_VDELAY_LO, 0x12);/* 220  Mfg specified reset value */
+       tw_writeb(TW68_VACTIVE_LO, 0xf0);
+       tw_writeb(TW68_HDELAY_LO, 0x0f);
+       tw_writeb(TW68_HACTIVE_LO, 0xd0);
+
+       tw_writeb(TW68_CNTRL1, 0xcd);   /* 230  Wide Chroma BPF B/W
+                                        *      Secam reduction, Adap comb for
+                                        *      NTSC, Op Mode 1 */
+
+       tw_writeb(TW68_VSCALE_LO, 0);   /* 234 */
+       tw_writeb(TW68_SCALE_HI, 0x11); /* 238 */
+       tw_writeb(TW68_HSCALE_LO, 0);   /* 23c */
+       tw_writeb(TW68_BRIGHT, 0);      /* 240 */
+       tw_writeb(TW68_CONTRAST, 0x5c); /* 244 */
+       tw_writeb(TW68_SHARPNESS, 0x51);/* 248 */
+       tw_writeb(TW68_SAT_U, 0x80);    /* 24C */
+       tw_writeb(TW68_SAT_V, 0x80);    /* 250 */
+       tw_writeb(TW68_HUE, 0x00);      /* 254 */
+
+       /* TODO - Check that none of these are set by control defaults */
+       tw_writeb(TW68_SHARP2, 0x53);   /* 258  Mfg specified reset val */
+       tw_writeb(TW68_VSHARP, 0x80);   /* 25C  Sharpness Coring val 8 */
+       tw_writeb(TW68_CORING, 0x44);   /* 260  CTI and Vert Peak coring */
+       tw_writeb(TW68_CNTRL2, 0x00);   /* 268  No power saving enabled */
+       tw_writeb(TW68_SDT, 0x07);      /* 270  Enable shadow reg, auto-det */
+       tw_writeb(TW68_SDTR, 0x7f);     /* 274  All stds recog, don't start */
+       tw_writeb(TW68_CLMPG, 0x50);    /* 280  Clamp end at 40 sys clocks */
+       tw_writeb(TW68_IAGC, 0x22);     /* 284  Mfg specified reset val */
+       tw_writeb(TW68_AGCGAIN, 0xf0);  /* 288  AGC gain when loop disabled */
+       tw_writeb(TW68_PEAKWT, 0xd8);   /* 28C  White peak threshold */
+       tw_writeb(TW68_CLMPL, 0x3c);    /* 290  Y channel clamp level */
+/*     tw_writeb(TW68_SYNCT, 0x38);*/  /* 294  Sync amplitude */
+       tw_writeb(TW68_SYNCT, 0x30);    /* 294  Sync amplitude */
+       tw_writeb(TW68_MISSCNT, 0x44);  /* 298  Horiz sync, VCR detect sens */
+       tw_writeb(TW68_PCLAMP, 0x28);   /* 29C  Clamp pos from PLL sync */
+       /* Bit DETV of VCNTL1 helps sync multi cams/chip board */
+       tw_writeb(TW68_VCNTL1, 0x04);   /* 2A0 */
+       tw_writeb(TW68_VCNTL2, 0);      /* 2A4 */
+       tw_writeb(TW68_CKILL, 0x68);    /* 2A8  Mfg specified reset val */
+       tw_writeb(TW68_COMB, 0x44);     /* 2AC  Mfg specified reset val */
+       tw_writeb(TW68_LDLY, 0x30);     /* 2B0  Max positive luma delay */
+       tw_writeb(TW68_MISC1, 0x14);    /* 2B4  Mfg specified reset val */
+       tw_writeb(TW68_LOOP, 0xa5);     /* 2B8  Mfg specified reset val */
+       tw_writeb(TW68_MISC2, 0xe0);    /* 2BC  Enable colour killer */
+       tw_writeb(TW68_MVSN, 0);        /* 2C0 */
+       tw_writeb(TW68_CLMD, 0x05);     /* 2CC  slice level auto, clamp med. */
+       tw_writeb(TW68_IDCNTL, 0);      /* 2D0  Writing zero to this register
+                                        *      selects NTSC ID detection,
+                                        *      but doesn't change the
+                                        *      sensitivity (which has a reset
+                                        *      value of 1E).  Since we are
+                                        *      not doing auto-detection, it
+                                        *      has no real effect */
+       tw_writeb(TW68_CLCNTL1, 0);     /* 2D4 */
+       tw_writel(TW68_VBIC, 0x03);     /* 010 */
+       tw_writel(TW68_CAP_CTL, 0x03);  /* 040  Enable both even & odd flds */
+       tw_writel(TW68_DMAC, 0x2000);   /* patch set had 0x2080 */
+       tw_writel(TW68_TESTREG, 0);     /* 02C */
+
+       /*
+        * Some common boards, especially inexpensive single-chip models,
+        * use the GPIO bits 0-3 to control an on-board video-output mux.
+        * For these boards, we need to set up the GPIO register into
+        * "normal" mode, set bits 0-3 as output, and then set those bits
+        * zero.
+        *
+        * Eventually, it would be nice if we could identify these boards
+        * uniquely, and only do this initialisation if the board has been
+        * identify.  For the moment, however, it shouldn't hurt anything
+        * to do these steps.
+        */
+       tw_writel(TW68_GPIOC, 0);       /* Set the GPIO to "normal", no ints */
+       tw_writel(TW68_GPOE, 0x0f);     /* Set bits 0-3 to "output" */
+       tw_writel(TW68_GPDATA, 0);      /* Set all bits to low state */
+
+       /* Initialize the device control structures */
+       mutex_init(&dev->lock);
+       spin_lock_init(&dev->slock);
+
+       /* Initialize any subsystems */
+       tw68_video_init1(dev);
+       return 0;
+}
+
+static irqreturn_t tw68_irq(int irq, void *dev_id)
+{
+       struct tw68_dev *dev = dev_id;
+       u32 status, orig;
+       int loop;
+
+       status = orig = tw_readl(TW68_INTSTAT) & dev->pci_irqmask;
+       /* Check if anything to do */
+       if (0 == status)
+               return IRQ_NONE;        /* Nope - return */
+       for (loop = 0; loop < 10; loop++) {
+               if (status & dev->board_virqmask)       /* video interrupt */
+                       tw68_irq_video_done(dev, status);
+               status = tw_readl(TW68_INTSTAT) & dev->pci_irqmask;
+               if (0 == status)
+                       return IRQ_HANDLED;
+       }
+       dev_dbg(&dev->pci->dev, "%s: **** INTERRUPT NOT HANDLED - clearing mask (orig 0x%08x, cur 0x%08x)",
+                       dev->name, orig, tw_readl(TW68_INTSTAT));
+       dev_dbg(&dev->pci->dev, "%s: pci_irqmask 0x%08x; board_virqmask 0x%08x ****\n",
+                       dev->name, dev->pci_irqmask, dev->board_virqmask);
+       tw_clearl(TW68_INTMASK, dev->pci_irqmask);
+       return IRQ_HANDLED;
+}
+
+static int tw68_initdev(struct pci_dev *pci_dev,
+                                    const struct pci_device_id *pci_id)
+{
+       struct tw68_dev *dev;
+       int vidnr = -1;
+       int err;
+
+       dev = devm_kzalloc(&pci_dev->dev, sizeof(*dev), GFP_KERNEL);
+       if (NULL == dev)
+               return -ENOMEM;
+
+       dev->instance = v4l2_device_set_name(&dev->v4l2_dev, "tw68",
+                                               &tw68_instance);
+
+       err = v4l2_device_register(&pci_dev->dev, &dev->v4l2_dev);
+       if (err)
+               return err;
+
+       /* pci init */
+       dev->pci = pci_dev;
+       if (pci_enable_device(pci_dev)) {
+               err = -EIO;
+               goto fail1;
+       }
+
+       dev->name = dev->v4l2_dev.name;
+
+       if (UNSET != latency) {
+               pr_info("%s: setting pci latency timer to %d\n",
+                      dev->name, latency);
+               pci_write_config_byte(pci_dev, PCI_LATENCY_TIMER, latency);
+       }
+
+       /* print pci info */
+       pci_read_config_byte(pci_dev, PCI_CLASS_REVISION, &dev->pci_rev);
+       pci_read_config_byte(pci_dev, PCI_LATENCY_TIMER,  &dev->pci_lat);
+       pr_info("%s: found at %s, rev: %d, irq: %d, latency: %d, mmio: 0x%llx\n",
+               dev->name, pci_name(pci_dev), dev->pci_rev, pci_dev->irq,
+               dev->pci_lat, (u64)pci_resource_start(pci_dev, 0));
+       pci_set_master(pci_dev);
+       if (!pci_dma_supported(pci_dev, DMA_BIT_MASK(32))) {
+               pr_info("%s: Oops: no 32bit PCI DMA ???\n", dev->name);
+               err = -EIO;
+               goto fail1;
+       }
+
+       switch (pci_id->device) {
+       case PCI_DEVICE_ID_6800:        /* TW6800 */
+               dev->vdecoder = TW6800;
+               dev->board_virqmask = TW68_VID_INTS;
+               break;
+       case PCI_DEVICE_ID_6801:        /* Video decoder for TW6802 */
+               dev->vdecoder = TW6801;
+               dev->board_virqmask = TW68_VID_INTS | TW68_VID_INTSX;
+               break;
+       case PCI_DEVICE_ID_6804:        /* Video decoder for TW6804 */
+               dev->vdecoder = TW6804;
+               dev->board_virqmask = TW68_VID_INTS | TW68_VID_INTSX;
+               break;
+       default:
+               dev->vdecoder = TWXXXX; /* To be announced */
+               dev->board_virqmask = TW68_VID_INTS | TW68_VID_INTSX;
+               break;
+       }
+
+       /* get mmio */
+       if (!request_mem_region(pci_resource_start(pci_dev, 0),
+                               pci_resource_len(pci_dev, 0),
+                               dev->name)) {
+               err = -EBUSY;
+               pr_err("%s: can't get MMIO memory @ 0x%llx\n",
+                       dev->name,
+                       (unsigned long long)pci_resource_start(pci_dev, 0));
+               goto fail1;
+       }
+       dev->lmmio = ioremap(pci_resource_start(pci_dev, 0),
+                            pci_resource_len(pci_dev, 0));
+       dev->bmmio = (__u8 __iomem *)dev->lmmio;
+       if (NULL == dev->lmmio) {
+               err = -EIO;
+               pr_err("%s: can't ioremap() MMIO memory\n",
+                      dev->name);
+               goto fail2;
+       }
+       /* initialize hardware #1 */
+       /* Then do any initialisation wanted before interrupts are on */
+       tw68_hw_init1(dev);
+
+       /* get irq */
+       err = devm_request_irq(&pci_dev->dev, pci_dev->irq, tw68_irq,
+                         IRQF_SHARED | IRQF_DISABLED, dev->name, dev);
+       if (err < 0) {
+               pr_err("%s: can't get IRQ %d\n",
+                      dev->name, pci_dev->irq);
+               goto fail3;
+       }
+
+       /*
+        *  Now do remainder of initialisation, first for
+        *  things unique for this card, then for general board
+        */
+       if (dev->instance < TW68_MAXBOARDS)
+               vidnr = video_nr[dev->instance];
+       /* initialise video function first */
+       err = tw68_video_init2(dev, vidnr);
+       if (err < 0) {
+               pr_err("%s: can't register video device\n",
+                      dev->name);
+               goto fail4;
+       }
+       tw_setl(TW68_INTMASK, dev->pci_irqmask);
+
+       pr_info("%s: registered device %s\n",
+              dev->name, video_device_node_name(&dev->vdev));
+
+       return 0;
+
+fail4:
+       video_unregister_device(&dev->vdev);
+fail3:
+       iounmap(dev->lmmio);
+fail2:
+       release_mem_region(pci_resource_start(pci_dev, 0),
+                          pci_resource_len(pci_dev, 0));
+fail1:
+       v4l2_device_unregister(&dev->v4l2_dev);
+       return err;
+}
+
+static void tw68_finidev(struct pci_dev *pci_dev)
+{
+       struct v4l2_device *v4l2_dev = pci_get_drvdata(pci_dev);
+       struct tw68_dev *dev =
+               container_of(v4l2_dev, struct tw68_dev, v4l2_dev);
+
+       /* shutdown subsystems */
+       tw_clearl(TW68_DMAC, TW68_DMAP_EN | TW68_FIFO_EN);
+       tw_writel(TW68_INTMASK, 0);
+
+       /* unregister */
+       video_unregister_device(&dev->vdev);
+       v4l2_ctrl_handler_free(&dev->hdl);
+
+       /* release resources */
+       iounmap(dev->lmmio);
+       release_mem_region(pci_resource_start(pci_dev, 0),
+                          pci_resource_len(pci_dev, 0));
+
+       v4l2_device_unregister(&dev->v4l2_dev);
+}
+
+#ifdef CONFIG_PM
+
+static int tw68_suspend(struct pci_dev *pci_dev , pm_message_t state)
+{
+       struct v4l2_device *v4l2_dev = pci_get_drvdata(pci_dev);
+       struct tw68_dev *dev = container_of(v4l2_dev,
+                               struct tw68_dev, v4l2_dev);
+
+       tw_clearl(TW68_DMAC, TW68_DMAP_EN | TW68_FIFO_EN);
+       dev->pci_irqmask &= ~TW68_VID_INTS;
+       tw_writel(TW68_INTMASK, 0);
+
+       synchronize_irq(pci_dev->irq);
+
+       pci_save_state(pci_dev);
+       pci_set_power_state(pci_dev, pci_choose_state(pci_dev, state));
+       vb2_discard_done(&dev->vidq);
+
+       return 0;
+}
+
+static int tw68_resume(struct pci_dev *pci_dev)
+{
+       struct v4l2_device *v4l2_dev = pci_get_drvdata(pci_dev);
+       struct tw68_dev *dev = container_of(v4l2_dev,
+                                           struct tw68_dev, v4l2_dev);
+       struct tw68_buf *buf;
+       unsigned long flags;
+
+       pci_set_power_state(pci_dev, PCI_D0);
+       pci_restore_state(pci_dev);
+
+       /* Do things that are done in tw68_initdev ,
+               except of initializing memory structures.*/
+
+       msleep(100);
+
+       tw68_set_tvnorm_hw(dev);
+
+       /*resume unfinished buffer(s)*/
+       spin_lock_irqsave(&dev->slock, flags);
+       buf = container_of(dev->active.next, struct tw68_buf, list);
+
+       tw68_video_start_dma(dev, buf);
+
+       spin_unlock_irqrestore(&dev->slock, flags);
+
+       return 0;
+}
+#endif
+
+/* ----------------------------------------------------------- */
+
+static struct pci_driver tw68_pci_driver = {
+       .name     = "tw68",
+       .id_table = tw68_pci_tbl,
+       .probe    = tw68_initdev,
+       .remove   = tw68_finidev,
+#ifdef CONFIG_PM
+       .suspend  = tw68_suspend,
+       .resume   = tw68_resume
+#endif
+};
+
+module_pci_driver(tw68_pci_driver);
diff --git a/drivers/media/pci/tw68/tw68-reg.h b/drivers/media/pci/tw68/tw68-reg.h
new file mode 100644 (file)
index 0000000..f60b3a8
--- /dev/null
@@ -0,0 +1,195 @@
+/*
+ *  tw68-reg.h - TW68xx register offsets
+ *
+ *  Much of this code is derived from the cx88 and sa7134 drivers, which
+ *  were in turn derived from the bt87x driver.  The original work was by
+ *  Gerd Knorr; more recently the code was enhanced by Mauro Carvalho Chehab,
+ *  Hans Verkuil, Andy Walls and many others.  Their work is gratefully
+ *  acknowledged.  Full credit goes to them - any problems within this code
+ *  are mine.
+ *
+ *  Copyright (C) William M. Brack
+ *
+ *  Refactored and updated to the latest v4l core frameworks:
+ *
+ *  Copyright (C) 2014 Hans Verkuil <hverkuil@xs4all.nl>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+*/
+
+#ifndef _TW68_REG_H_
+#define _TW68_REG_H_
+
+/* ---------------------------------------------------------------------- */
+#define        TW68_DMAC               0x000
+#define        TW68_DMAP_SA            0x004
+#define        TW68_DMAP_EXE           0x008
+#define        TW68_DMAP_PP            0x00c
+#define        TW68_VBIC               0x010
+#define        TW68_SBUSC              0x014
+#define        TW68_SBUSSD             0x018
+#define        TW68_INTSTAT            0x01C
+#define        TW68_INTMASK            0x020
+#define        TW68_GPIOC              0x024
+#define        TW68_GPOE               0x028
+#define        TW68_TESTREG            0x02C
+#define        TW68_SBUSRD             0x030
+#define        TW68_SBUS_TRIG          0x034
+#define        TW68_CAP_CTL            0x040
+#define        TW68_SUBSYS             0x054
+#define        TW68_I2C_RST            0x064
+#define        TW68_VBIINST            0x06C
+/* define bits in FIFO and DMAP Control reg */
+#define        TW68_DMAP_EN            (1 << 0)
+#define        TW68_FIFO_EN            (1 << 1)
+/* define the Interrupt Status Register bits */
+#define        TW68_SBDONE             (1 << 0)
+#define        TW68_DMAPI              (1 << 1)
+#define        TW68_GPINT              (1 << 2)
+#define        TW68_FFOF               (1 << 3)
+#define        TW68_FDMIS              (1 << 4)
+#define        TW68_DMAPERR            (1 << 5)
+#define        TW68_PABORT             (1 << 6)
+#define        TW68_SBDONE2            (1 << 12)
+#define        TW68_SBERR2             (1 << 13)
+#define        TW68_PPERR              (1 << 14)
+#define        TW68_FFERR              (1 << 15)
+#define        TW68_DET50              (1 << 16)
+#define        TW68_FLOCK              (1 << 17)
+#define        TW68_CCVALID            (1 << 18)
+#define        TW68_VLOCK              (1 << 19)
+#define        TW68_FIELD              (1 << 20)
+#define        TW68_SLOCK              (1 << 21)
+#define        TW68_HLOCK              (1 << 22)
+#define        TW68_VDLOSS             (1 << 23)
+#define        TW68_SBERR              (1 << 24)
+/* define the i2c control register bits */
+#define        TW68_SBMODE             (0)
+#define        TW68_WREN               (1)
+#define        TW68_SSCLK              (6)
+#define        TW68_SSDAT              (7)
+#define        TW68_SBCLK              (8)
+#define        TW68_WDLEN              (16)
+#define        TW68_RDLEN              (20)
+#define        TW68_SBRW               (24)
+#define        TW68_SBDEV              (25)
+
+#define        TW68_SBMODE_B           (1 << TW68_SBMODE)
+#define        TW68_WREN_B             (1 << TW68_WREN)
+#define        TW68_SSCLK_B            (1 << TW68_SSCLK)
+#define        TW68_SSDAT_B            (1 << TW68_SSDAT)
+#define        TW68_SBRW_B             (1 << TW68_SBRW)
+
+#define        TW68_GPDATA             0x100
+#define        TW68_STATUS1            0x204
+#define        TW68_INFORM             0x208
+#define        TW68_OPFORM             0x20C
+#define        TW68_HSYNC              0x210
+#define        TW68_ACNTL              0x218
+#define        TW68_CROP_HI            0x21C
+#define        TW68_VDELAY_LO          0x220
+#define        TW68_VACTIVE_LO         0x224
+#define        TW68_HDELAY_LO          0x228
+#define        TW68_HACTIVE_LO         0x22C
+#define        TW68_CNTRL1             0x230
+#define        TW68_VSCALE_LO          0x234
+#define        TW68_SCALE_HI           0x238
+#define        TW68_HSCALE_LO          0x23C
+#define        TW68_BRIGHT             0x240
+#define        TW68_CONTRAST           0x244
+#define        TW68_SHARPNESS          0x248
+#define        TW68_SAT_U              0x24C
+#define        TW68_SAT_V              0x250
+#define        TW68_HUE                0x254
+#define        TW68_SHARP2             0x258
+#define        TW68_VSHARP             0x25C
+#define        TW68_CORING             0x260
+#define        TW68_VBICNTL            0x264
+#define        TW68_CNTRL2             0x268
+#define        TW68_CC_DATA            0x26C
+#define        TW68_SDT                0x270
+#define        TW68_SDTR               0x274
+#define        TW68_RESERV2            0x278
+#define        TW68_RESERV3            0x27C
+#define        TW68_CLMPG              0x280
+#define        TW68_IAGC               0x284
+#define        TW68_AGCGAIN            0x288
+#define        TW68_PEAKWT             0x28C
+#define        TW68_CLMPL              0x290
+#define        TW68_SYNCT              0x294
+#define        TW68_MISSCNT            0x298
+#define        TW68_PCLAMP             0x29C
+#define        TW68_VCNTL1             0x2A0
+#define        TW68_VCNTL2             0x2A4
+#define        TW68_CKILL              0x2A8
+#define        TW68_COMB               0x2AC
+#define        TW68_LDLY               0x2B0
+#define        TW68_MISC1              0x2B4
+#define        TW68_LOOP               0x2B8
+#define        TW68_MISC2              0x2BC
+#define        TW68_MVSN               0x2C0
+#define        TW68_STATUS2            0x2C4
+#define        TW68_HFREF              0x2C8
+#define        TW68_CLMD               0x2CC
+#define        TW68_IDCNTL             0x2D0
+#define        TW68_CLCNTL1            0x2D4
+
+/* Audio */
+#define        TW68_ACKI1              0x300
+#define        TW68_ACKI2              0x304
+#define        TW68_ACKI3              0x308
+#define        TW68_ACKN1              0x30C
+#define        TW68_ACKN2              0x310
+#define        TW68_ACKN3              0x314
+#define        TW68_SDIV               0x318
+#define        TW68_LRDIV              0x31C
+#define        TW68_ACCNTL             0x320
+
+#define        TW68_VSCTL              0x3B8
+#define        TW68_CHROMAGVAL         0x3BC
+
+#define        TW68_F2CROP_HI          0x3DC
+#define        TW68_F2VDELAY_LO        0x3E0
+#define        TW68_F2VACTIVE_LO       0x3E4
+#define        TW68_F2HDELAY_LO        0x3E8
+#define        TW68_F2HACTIVE_LO       0x3EC
+#define        TW68_F2CNT              0x3F0
+#define        TW68_F2VSCALE_LO        0x3F4
+#define        TW68_F2SCALE_HI         0x3F8
+#define        TW68_F2HSCALE_LO        0x3FC
+
+#define        RISC_INT_BIT            0x08000000
+#define        RISC_SYNCO              0xC0000000
+#define        RISC_SYNCE              0xD0000000
+#define        RISC_JUMP               0xB0000000
+#define        RISC_LINESTART          0x90000000
+#define        RISC_INLINE             0xA0000000
+
+#define VideoFormatNTSC                 0
+#define VideoFormatNTSCJapan    0
+#define VideoFormatPALBDGHI     1
+#define VideoFormatSECAM        2
+#define VideoFormatNTSC443      3
+#define VideoFormatPALM                 4
+#define VideoFormatPALN                 5
+#define VideoFormatPALNC        5
+#define VideoFormatPAL60        6
+#define VideoFormatAuto                 7
+
+#define ColorFormatRGB32        0x00
+#define ColorFormatRGB24        0x10
+#define ColorFormatRGB16        0x20
+#define ColorFormatRGB15        0x30
+#define ColorFormatYUY2                 0x40
+#define ColorFormatBSWAP         0x04
+#define ColorFormatWSWAP         0x08
+#define ColorFormatGamma         0x80
+#endif
diff --git a/drivers/media/pci/tw68/tw68-risc.c b/drivers/media/pci/tw68/tw68-risc.c
new file mode 100644 (file)
index 0000000..7439db2
--- /dev/null
@@ -0,0 +1,230 @@
+/*
+ *  tw68_risc.c
+ *  Part of the device driver for Techwell 68xx based cards
+ *
+ *  Much of this code is derived from the cx88 and sa7134 drivers, which
+ *  were in turn derived from the bt87x driver.  The original work was by
+ *  Gerd Knorr; more recently the code was enhanced by Mauro Carvalho Chehab,
+ *  Hans Verkuil, Andy Walls and many others.  Their work is gratefully
+ *  acknowledged.  Full credit goes to them - any problems within this code
+ *  are mine.
+ *
+ *  Copyright (C) 2009  William M. Brack
+ *
+ *  Refactored and updated to the latest v4l core frameworks:
+ *
+ *  Copyright (C) 2014 Hans Verkuil <hverkuil@xs4all.nl>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ */
+
+#include "tw68.h"
+
+/**
+ *  @rp                pointer to current risc program position
+ *  @sglist    pointer to "scatter-gather list" of buffer pointers
+ *  @offset    offset to target memory buffer
+ *  @sync_line 0 -> no sync, 1 -> odd sync, 2 -> even sync
+ *  @bpl       number of bytes per scan line
+ *  @padding   number of bytes of padding to add
+ *  @lines     number of lines in field
+ *  @jump      insert a jump at the start
+ */
+static __le32 *tw68_risc_field(__le32 *rp, struct scatterlist *sglist,
+                           unsigned int offset, u32 sync_line,
+                           unsigned int bpl, unsigned int padding,
+                           unsigned int lines, bool jump)
+{
+       struct scatterlist *sg;
+       unsigned int line, todo, done;
+
+       if (jump) {
+               *(rp++) = cpu_to_le32(RISC_JUMP);
+               *(rp++) = 0;
+       }
+
+       /* sync instruction */
+       if (sync_line == 1)
+               *(rp++) = cpu_to_le32(RISC_SYNCO);
+       else
+               *(rp++) = cpu_to_le32(RISC_SYNCE);
+       *(rp++) = 0;
+
+       /* scan lines */
+       sg = sglist;
+       for (line = 0; line < lines; line++) {
+               /* calculate next starting position */
+               while (offset && offset >= sg_dma_len(sg)) {
+                       offset -= sg_dma_len(sg);
+                       sg = sg_next(sg);
+               }
+               if (bpl <= sg_dma_len(sg) - offset) {
+                       /* fits into current chunk */
+                       *(rp++) = cpu_to_le32(RISC_LINESTART |
+                                             /* (offset<<12) |*/  bpl);
+                       *(rp++) = cpu_to_le32(sg_dma_address(sg) + offset);
+                       offset += bpl;
+               } else {
+                       /*
+                        * scanline needs to be split.  Put the start in
+                        * whatever memory remains using RISC_LINESTART,
+                        * then the remainder into following addresses
+                        * given by the scatter-gather list.
+                        */
+                       todo = bpl;     /* one full line to be done */
+                       /* first fragment */
+                       done = (sg_dma_len(sg) - offset);
+                       *(rp++) = cpu_to_le32(RISC_LINESTART |
+                                               (7 << 24) |
+                                               done);
+                       *(rp++) = cpu_to_le32(sg_dma_address(sg) + offset);
+                       todo -= done;
+                       sg = sg_next(sg);
+                       /* succeeding fragments have no offset */
+                       while (todo > sg_dma_len(sg)) {
+                               *(rp++) = cpu_to_le32(RISC_INLINE |
+                                               (done << 12) |
+                                               sg_dma_len(sg));
+                               *(rp++) = cpu_to_le32(sg_dma_address(sg));
+                               todo -= sg_dma_len(sg);
+                               sg = sg_next(sg);
+                               done += sg_dma_len(sg);
+                       }
+                       if (todo) {
+                               /* final chunk - offset 0, count 'todo' */
+                               *(rp++) = cpu_to_le32(RISC_INLINE |
+                                                       (done << 12) |
+                                                       todo);
+                               *(rp++) = cpu_to_le32(sg_dma_address(sg));
+                       }
+                       offset = todo;
+               }
+               offset += padding;
+       }
+
+       return rp;
+}
+
+/**
+ * tw68_risc_buffer
+ *
+ *     This routine is called by tw68-video.  It allocates
+ *     memory for the dma controller "program" and then fills in that
+ *     memory with the appropriate "instructions".
+ *
+ *     @pci_dev        structure with info about the pci
+ *                     slot which our device is in.
+ *     @risc           structure with info about the memory
+ *                     used for our controller program.
+ *     @sglist         scatter-gather list entry
+ *     @top_offset     offset within the risc program area for the
+ *                     first odd frame line
+ *     @bottom_offset  offset within the risc program area for the
+ *                     first even frame line
+ *     @bpl            number of data bytes per scan line
+ *     @padding        number of extra bytes to add at end of line
+ *     @lines          number of scan lines
+ */
+int tw68_risc_buffer(struct pci_dev *pci,
+                       struct tw68_buf *buf,
+                       struct scatterlist *sglist,
+                       unsigned int top_offset,
+                       unsigned int bottom_offset,
+                       unsigned int bpl,
+                       unsigned int padding,
+                       unsigned int lines)
+{
+       u32 instructions, fields;
+       __le32 *rp;
+
+       fields = 0;
+       if (UNSET != top_offset)
+               fields++;
+       if (UNSET != bottom_offset)
+               fields++;
+       /*
+        * estimate risc mem: worst case is one write per page border +
+        * one write per scan line + syncs + 2 jumps (all 2 dwords).
+        * Padding can cause next bpl to start close to a page border.
+        * First DMA region may be smaller than PAGE_SIZE
+        */
+       instructions  = fields * (1 + (((bpl + padding) * lines) /
+                        PAGE_SIZE) + lines) + 4;
+       buf->size = instructions * 8;
+       buf->cpu = pci_alloc_consistent(pci, buf->size, &buf->dma);
+       if (buf->cpu == NULL)
+               return -ENOMEM;
+
+       /* write risc instructions */
+       rp = buf->cpu;
+       if (UNSET != top_offset)        /* generates SYNCO */
+               rp = tw68_risc_field(rp, sglist, top_offset, 1,
+                                    bpl, padding, lines, true);
+       if (UNSET != bottom_offset)     /* generates SYNCE */
+               rp = tw68_risc_field(rp, sglist, bottom_offset, 2,
+                                    bpl, padding, lines, top_offset == UNSET);
+
+       /* save pointer to jmp instruction address */
+       buf->jmp = rp;
+       buf->cpu[1] = cpu_to_le32(buf->dma + 8);
+       /* assure risc buffer hasn't overflowed */
+       BUG_ON((buf->jmp - buf->cpu + 2) * sizeof(buf->cpu[0]) > buf->size);
+       return 0;
+}
+
+#if 0
+/* ------------------------------------------------------------------ */
+/* debug helper code                                                  */
+
+static void tw68_risc_decode(u32 risc, u32 addr)
+{
+#define        RISC_OP(reg)    (((reg) >> 28) & 7)
+       static struct instr_details {
+               char *name;
+               u8 has_data_type;
+               u8 has_byte_info;
+               u8 has_addr;
+       } instr[8] = {
+               [RISC_OP(RISC_SYNCO)]     = {"syncOdd", 0, 0, 0},
+               [RISC_OP(RISC_SYNCE)]     = {"syncEven", 0, 0, 0},
+               [RISC_OP(RISC_JUMP)]      = {"jump", 0, 0, 1},
+               [RISC_OP(RISC_LINESTART)] = {"lineStart", 1, 1, 1},
+               [RISC_OP(RISC_INLINE)]    = {"inline", 1, 1, 1},
+       };
+       u32 p;
+
+       p = RISC_OP(risc);
+       if (!(risc & 0x80000000) || !instr[p].name) {
+               pr_debug("0x%08x [ INVALID ]\n", risc);
+               return;
+       }
+       pr_debug("0x%08x %-9s IRQ=%d",
+               risc, instr[p].name, (risc >> 27) & 1);
+       if (instr[p].has_data_type)
+               pr_debug(" Type=%d", (risc >> 24) & 7);
+       if (instr[p].has_byte_info)
+               pr_debug(" Start=0x%03x Count=%03u",
+                       (risc >> 12) & 0xfff, risc & 0xfff);
+       if (instr[p].has_addr)
+               pr_debug(" StartAddr=0x%08x", addr);
+       pr_debug("\n");
+}
+
+void tw68_risc_program_dump(struct tw68_core *core, struct tw68_buf *buf)
+{
+       const __le32 *addr;
+
+       pr_debug("%s: risc_program_dump: risc=%p, buf->cpu=0x%p, buf->jmp=0x%p\n",
+                 core->name, buf, buf->cpu, buf->jmp);
+       for (addr = buf->cpu; addr <= buf->jmp; addr += 2)
+               tw68_risc_decode(*addr, *(addr+1));
+}
+#endif
diff --git a/drivers/media/pci/tw68/tw68-video.c b/drivers/media/pci/tw68/tw68-video.c
new file mode 100644 (file)
index 0000000..5c94ac7
--- /dev/null
@@ -0,0 +1,1051 @@
+/*
+ *  tw68 functions to handle video data
+ *
+ *  Much of this code is derived from the cx88 and sa7134 drivers, which
+ *  were in turn derived from the bt87x driver.  The original work was by
+ *  Gerd Knorr; more recently the code was enhanced by Mauro Carvalho Chehab,
+ *  Hans Verkuil, Andy Walls and many others.  Their work is gratefully
+ *  acknowledged.  Full credit goes to them - any problems within this code
+ *  are mine.
+ *
+ *  Copyright (C) 2009  William M. Brack
+ *
+ *  Refactored and updated to the latest v4l core frameworks:
+ *
+ *  Copyright (C) 2014 Hans Verkuil <hverkuil@xs4all.nl>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-event.h>
+#include <media/videobuf2-dma-sg.h>
+
+#include "tw68.h"
+#include "tw68-reg.h"
+
+/* ------------------------------------------------------------------ */
+/* data structs for video                                             */
+/*
+ * FIXME -
+ * Note that the saa7134 has formats, e.g. YUV420, which are classified
+ * as "planar".  These affect overlay mode, and are flagged with a field
+ * ".planar" in the format.  Do we need to implement this in this driver?
+ */
+static const struct tw68_format formats[] = {
+       {
+               .name           = "15 bpp RGB, le",
+               .fourcc         = V4L2_PIX_FMT_RGB555,
+               .depth          = 16,
+               .twformat       = ColorFormatRGB15,
+       }, {
+               .name           = "15 bpp RGB, be",
+               .fourcc         = V4L2_PIX_FMT_RGB555X,
+               .depth          = 16,
+               .twformat       = ColorFormatRGB15 | ColorFormatBSWAP,
+       }, {
+               .name           = "16 bpp RGB, le",
+               .fourcc         = V4L2_PIX_FMT_RGB565,
+               .depth          = 16,
+               .twformat       = ColorFormatRGB16,
+       }, {
+               .name           = "16 bpp RGB, be",
+               .fourcc         = V4L2_PIX_FMT_RGB565X,
+               .depth          = 16,
+               .twformat       = ColorFormatRGB16 | ColorFormatBSWAP,
+       }, {
+               .name           = "24 bpp RGB, le",
+               .fourcc         = V4L2_PIX_FMT_BGR24,
+               .depth          = 24,
+               .twformat       = ColorFormatRGB24,
+       }, {
+               .name           = "24 bpp RGB, be",
+               .fourcc         = V4L2_PIX_FMT_RGB24,
+               .depth          = 24,
+               .twformat       = ColorFormatRGB24 | ColorFormatBSWAP,
+       }, {
+               .name           = "32 bpp RGB, le",
+               .fourcc         = V4L2_PIX_FMT_BGR32,
+               .depth          = 32,
+               .twformat       = ColorFormatRGB32,
+       }, {
+               .name           = "32 bpp RGB, be",
+               .fourcc         = V4L2_PIX_FMT_RGB32,
+               .depth          = 32,
+               .twformat       = ColorFormatRGB32 | ColorFormatBSWAP |
+                                 ColorFormatWSWAP,
+       }, {
+               .name           = "4:2:2 packed, YUYV",
+               .fourcc         = V4L2_PIX_FMT_YUYV,
+               .depth          = 16,
+               .twformat       = ColorFormatYUY2,
+       }, {
+               .name           = "4:2:2 packed, UYVY",
+               .fourcc         = V4L2_PIX_FMT_UYVY,
+               .depth          = 16,
+               .twformat       = ColorFormatYUY2 | ColorFormatBSWAP,
+       }
+};
+#define FORMATS ARRAY_SIZE(formats)
+
+#define NORM_625_50                    \
+               .h_delay        = 3,    \
+               .h_delay0       = 133,  \
+               .h_start        = 0,    \
+               .h_stop         = 719,  \
+               .v_delay        = 24,   \
+               .vbi_v_start_0  = 7,    \
+               .vbi_v_stop_0   = 22,   \
+               .video_v_start  = 24,   \
+               .video_v_stop   = 311,  \
+               .vbi_v_start_1  = 319
+
+#define NORM_525_60                    \
+               .h_delay        = 8,    \
+               .h_delay0       = 138,  \
+               .h_start        = 0,    \
+               .h_stop         = 719,  \
+               .v_delay        = 22,   \
+               .vbi_v_start_0  = 10,   \
+               .vbi_v_stop_0   = 21,   \
+               .video_v_start  = 22,   \
+               .video_v_stop   = 262,  \
+               .vbi_v_start_1  = 273
+
+/*
+ * The following table is searched by tw68_s_std, first for a specific
+ * match, then for an entry which contains the desired id.  The table
+ * entries should therefore be ordered in ascending order of specificity.
+ */
+static const struct tw68_tvnorm tvnorms[] = {
+       {
+               .name           = "PAL", /* autodetect */
+               .id             = V4L2_STD_PAL,
+               NORM_625_50,
+
+               .sync_control   = 0x18,
+               .luma_control   = 0x40,
+               .chroma_ctrl1   = 0x81,
+               .chroma_gain    = 0x2a,
+               .chroma_ctrl2   = 0x06,
+               .vgate_misc     = 0x1c,
+               .format         = VideoFormatPALBDGHI,
+       }, {
+               .name           = "NTSC",
+               .id             = V4L2_STD_NTSC,
+               NORM_525_60,
+
+               .sync_control   = 0x59,
+               .luma_control   = 0x40,
+               .chroma_ctrl1   = 0x89,
+               .chroma_gain    = 0x2a,
+               .chroma_ctrl2   = 0x0e,
+               .vgate_misc     = 0x18,
+               .format         = VideoFormatNTSC,
+       }, {
+               .name           = "SECAM",
+               .id             = V4L2_STD_SECAM,
+               NORM_625_50,
+
+               .sync_control   = 0x18,
+               .luma_control   = 0x1b,
+               .chroma_ctrl1   = 0xd1,
+               .chroma_gain    = 0x80,
+               .chroma_ctrl2   = 0x00,
+               .vgate_misc     = 0x1c,
+               .format         = VideoFormatSECAM,
+       }, {
+               .name           = "PAL-M",
+               .id             = V4L2_STD_PAL_M,
+               NORM_525_60,
+
+               .sync_control   = 0x59,
+               .luma_control   = 0x40,
+               .chroma_ctrl1   = 0xb9,
+               .chroma_gain    = 0x2a,
+               .chroma_ctrl2   = 0x0e,
+               .vgate_misc     = 0x18,
+               .format         = VideoFormatPALM,
+       }, {
+               .name           = "PAL-Nc",
+               .id             = V4L2_STD_PAL_Nc,
+               NORM_625_50,
+
+               .sync_control   = 0x18,
+               .luma_control   = 0x40,
+               .chroma_ctrl1   = 0xa1,
+               .chroma_gain    = 0x2a,
+               .chroma_ctrl2   = 0x06,
+               .vgate_misc     = 0x1c,
+               .format         = VideoFormatPALNC,
+       }, {
+               .name           = "PAL-60",
+               .id             = V4L2_STD_PAL_60,
+               .h_delay        = 186,
+               .h_start        = 0,
+               .h_stop         = 719,
+               .v_delay        = 26,
+               .video_v_start  = 23,
+               .video_v_stop   = 262,
+               .vbi_v_start_0  = 10,
+               .vbi_v_stop_0   = 21,
+               .vbi_v_start_1  = 273,
+
+               .sync_control   = 0x18,
+               .luma_control   = 0x40,
+               .chroma_ctrl1   = 0x81,
+               .chroma_gain    = 0x2a,
+               .chroma_ctrl2   = 0x06,
+               .vgate_misc     = 0x1c,
+               .format         = VideoFormatPAL60,
+       }
+};
+#define TVNORMS ARRAY_SIZE(tvnorms)
+
+static const struct tw68_format *format_by_fourcc(unsigned int fourcc)
+{
+       unsigned int i;
+
+       for (i = 0; i < FORMATS; i++)
+               if (formats[i].fourcc == fourcc)
+                       return formats+i;
+       return NULL;
+}
+
+
+/* ------------------------------------------------------------------ */
+/*
+ * Note that the cropping rectangles are described in terms of a single
+ * frame, i.e. line positions are only 1/2 the interlaced equivalent
+ */
+static void set_tvnorm(struct tw68_dev *dev, const struct tw68_tvnorm *norm)
+{
+       if (norm != dev->tvnorm) {
+               dev->width = 720;
+               dev->height = (norm->id & V4L2_STD_525_60) ? 480 : 576;
+               dev->tvnorm = norm;
+               tw68_set_tvnorm_hw(dev);
+       }
+}
+
+/*
+ * tw68_set_scale
+ *
+ * Scaling and Cropping for video decoding
+ *
+ * We are working with 3 values for horizontal and vertical - scale,
+ * delay and active.
+ *
+ * HACTIVE represent the actual number of pixels in the "usable" image,
+ * before scaling.  HDELAY represents the number of pixels skipped
+ * between the start of the horizontal sync and the start of the image.
+ * HSCALE is calculated using the formula
+ *     HSCALE = (HACTIVE / (#pixels desired)) * 256
+ *
+ * The vertical registers are similar, except based upon the total number
+ * of lines in the image, and the first line of the image (i.e. ignoring
+ * vertical sync and VBI).
+ *
+ * Note that the number of bytes reaching the FIFO (and hence needing
+ * to be processed by the DMAP program) is completely dependent upon
+ * these values, especially HSCALE.
+ *
+ * Parameters:
+ *     @dev            pointer to the device structure, needed for
+ *                     getting current norm (as well as debug print)
+ *     @width          actual image width (from user buffer)
+ *     @height         actual image height
+ *     @field          indicates Top, Bottom or Interlaced
+ */
+static int tw68_set_scale(struct tw68_dev *dev, unsigned int width,
+                         unsigned int height, enum v4l2_field field)
+{
+       const struct tw68_tvnorm *norm = dev->tvnorm;
+       /* set individually for debugging clarity */
+       int hactive, hdelay, hscale;
+       int vactive, vdelay, vscale;
+       int comb;
+
+       if (V4L2_FIELD_HAS_BOTH(field)) /* if field is interlaced */
+               height /= 2;            /* we must set for 1-frame */
+
+       pr_debug("%s: width=%d, height=%d, both=%d\n"
+                "  tvnorm h_delay=%d, h_start=%d, h_stop=%d, "
+                "v_delay=%d, v_start=%d, v_stop=%d\n" , __func__,
+               width, height, V4L2_FIELD_HAS_BOTH(field),
+               norm->h_delay, norm->h_start, norm->h_stop,
+               norm->v_delay, norm->video_v_start,
+               norm->video_v_stop);
+
+       switch (dev->vdecoder) {
+       case TW6800:
+               hdelay = norm->h_delay0;
+               break;
+       default:
+               hdelay = norm->h_delay;
+               break;
+       }
+
+       hdelay += norm->h_start;
+       hactive = norm->h_stop - norm->h_start + 1;
+
+       hscale = (hactive * 256) / (width);
+
+       vdelay = norm->v_delay;
+       vactive = ((norm->id & V4L2_STD_525_60) ? 524 : 624) / 2 - norm->video_v_start;
+       vscale = (vactive * 256) / height;
+
+       pr_debug("%s: %dx%d [%s%s,%s]\n", __func__,
+               width, height,
+               V4L2_FIELD_HAS_TOP(field)    ? "T" : "",
+               V4L2_FIELD_HAS_BOTTOM(field) ? "B" : "",
+               v4l2_norm_to_name(dev->tvnorm->id));
+       pr_debug("%s: hactive=%d, hdelay=%d, hscale=%d; "
+               "vactive=%d, vdelay=%d, vscale=%d\n", __func__,
+               hactive, hdelay, hscale, vactive, vdelay, vscale);
+
+       comb =  ((vdelay & 0x300)  >> 2) |
+               ((vactive & 0x300) >> 4) |
+               ((hdelay & 0x300)  >> 6) |
+               ((hactive & 0x300) >> 8);
+       pr_debug("%s: setting CROP_HI=%02x, VDELAY_LO=%02x, "
+               "VACTIVE_LO=%02x, HDELAY_LO=%02x, HACTIVE_LO=%02x\n",
+               __func__, comb, vdelay, vactive, hdelay, hactive);
+       tw_writeb(TW68_CROP_HI, comb);
+       tw_writeb(TW68_VDELAY_LO, vdelay & 0xff);
+       tw_writeb(TW68_VACTIVE_LO, vactive & 0xff);
+       tw_writeb(TW68_HDELAY_LO, hdelay & 0xff);
+       tw_writeb(TW68_HACTIVE_LO, hactive & 0xff);
+
+       comb = ((vscale & 0xf00) >> 4) | ((hscale & 0xf00) >> 8);
+       pr_debug("%s: setting SCALE_HI=%02x, VSCALE_LO=%02x, "
+               "HSCALE_LO=%02x\n", __func__, comb, vscale, hscale);
+       tw_writeb(TW68_SCALE_HI, comb);
+       tw_writeb(TW68_VSCALE_LO, vscale);
+       tw_writeb(TW68_HSCALE_LO, hscale);
+
+       return 0;
+}
+
+/* ------------------------------------------------------------------ */
+
+int tw68_video_start_dma(struct tw68_dev *dev, struct tw68_buf *buf)
+{
+       /* Set cropping and scaling */
+       tw68_set_scale(dev, dev->width, dev->height, dev->field);
+       /*
+        *  Set start address for RISC program.  Note that if the DMAP
+        *  processor is currently running, it must be stopped before
+        *  a new address can be set.
+        */
+       tw_clearl(TW68_DMAC, TW68_DMAP_EN);
+       tw_writel(TW68_DMAP_SA, buf->dma);
+       /* Clear any pending interrupts */
+       tw_writel(TW68_INTSTAT, dev->board_virqmask);
+       /* Enable the risc engine and the fifo */
+       tw_andorl(TW68_DMAC, 0xff, dev->fmt->twformat |
+               ColorFormatGamma | TW68_DMAP_EN | TW68_FIFO_EN);
+       dev->pci_irqmask |= dev->board_virqmask;
+       tw_setl(TW68_INTMASK, dev->pci_irqmask);
+       return 0;
+}
+
+/* ------------------------------------------------------------------ */
+
+/* calc max # of buffers from size (must not exceed the 4MB virtual
+ * address space per DMA channel) */
+static int tw68_buffer_count(unsigned int size, unsigned int count)
+{
+       unsigned int maxcount;
+
+       maxcount = (4 * 1024 * 1024) / roundup(size, PAGE_SIZE);
+       if (count > maxcount)
+               count = maxcount;
+       return count;
+}
+
+/* ------------------------------------------------------------- */
+/* vb2 queue operations                                          */
+
+static int tw68_queue_setup(struct vb2_queue *q, const struct v4l2_format *fmt,
+                          unsigned int *num_buffers, unsigned int *num_planes,
+                          unsigned int sizes[], void *alloc_ctxs[])
+{
+       struct tw68_dev *dev = vb2_get_drv_priv(q);
+       unsigned tot_bufs = q->num_buffers + *num_buffers;
+
+       sizes[0] = (dev->fmt->depth * dev->width * dev->height) >> 3;
+       /*
+        * We allow create_bufs, but only if the sizeimage is the same as the
+        * current sizeimage. The tw68_buffer_count calculation becomes quite
+        * difficult otherwise.
+        */
+       if (fmt && fmt->fmt.pix.sizeimage < sizes[0])
+               return -EINVAL;
+       *num_planes = 1;
+       if (tot_bufs < 2)
+               tot_bufs = 2;
+       tot_bufs = tw68_buffer_count(sizes[0], tot_bufs);
+       *num_buffers = tot_bufs - q->num_buffers;
+
+       return 0;
+}
+
+/*
+ * The risc program for each buffers works as follows: it starts with a simple
+ * 'JUMP to addr + 8', which is effectively a NOP. Then the program to DMA the
+ * buffer follows and at the end we have a JUMP back to the start + 8 (skipping
+ * the initial JUMP).
+ *
+ * This is the program of the first buffer to be queued if the active list is
+ * empty and it just keeps DMAing this buffer without generating any interrupts.
+ *
+ * If a new buffer is added then the initial JUMP in the program generates an
+ * interrupt as well which signals that the previous buffer has been DMAed
+ * successfully and that it can be returned to userspace.
+ *
+ * It also sets the final jump of the previous buffer to the start of the new
+ * buffer, thus chaining the new buffer into the DMA chain. This is a single
+ * atomic u32 write, so there is no race condition.
+ *
+ * The end-result of all this that you only get an interrupt when a buffer
+ * is ready, so the control flow is very easy.
+ */
+static void tw68_buf_queue(struct vb2_buffer *vb)
+{
+       struct vb2_queue *vq = vb->vb2_queue;
+       struct tw68_dev *dev = vb2_get_drv_priv(vq);
+       struct tw68_buf *buf = container_of(vb, struct tw68_buf, vb);
+       struct tw68_buf *prev;
+       unsigned long flags;
+
+       spin_lock_irqsave(&dev->slock, flags);
+
+       /* append a 'JUMP to start of buffer' to the buffer risc program */
+       buf->jmp[0] = cpu_to_le32(RISC_JUMP);
+       buf->jmp[1] = cpu_to_le32(buf->dma + 8);
+
+       if (!list_empty(&dev->active)) {
+               prev = list_entry(dev->active.prev, struct tw68_buf, list);
+               buf->cpu[0] |= cpu_to_le32(RISC_INT_BIT);
+               prev->jmp[1] = cpu_to_le32(buf->dma);
+       }
+       list_add_tail(&buf->list, &dev->active);
+       spin_unlock_irqrestore(&dev->slock, flags);
+}
+
+/*
+ * buffer_prepare
+ *
+ * Set the ancilliary information into the buffer structure.  This
+ * includes generating the necessary risc program if it hasn't already
+ * been done for the current buffer format.
+ * The structure fh contains the details of the format requested by the
+ * user - type, width, height and #fields.  This is compared with the
+ * last format set for the current buffer.  If they differ, the risc
+ * code (which controls the filling of the buffer) is (re-)generated.
+ */
+static int tw68_buf_prepare(struct vb2_buffer *vb)
+{
+       struct vb2_queue *vq = vb->vb2_queue;
+       struct tw68_dev *dev = vb2_get_drv_priv(vq);
+       struct tw68_buf *buf = container_of(vb, struct tw68_buf, vb);
+       struct sg_table *dma = vb2_dma_sg_plane_desc(vb, 0);
+       unsigned size, bpl;
+       int rc;
+
+       size = (dev->width * dev->height * dev->fmt->depth) >> 3;
+       if (vb2_plane_size(vb, 0) < size)
+               return -EINVAL;
+       vb2_set_plane_payload(vb, 0, size);
+
+       rc = dma_map_sg(&dev->pci->dev, dma->sgl, dma->nents, DMA_FROM_DEVICE);
+       if (!rc)
+               return -EIO;
+
+       bpl = (dev->width * dev->fmt->depth) >> 3;
+       switch (dev->field) {
+       case V4L2_FIELD_TOP:
+               tw68_risc_buffer(dev->pci, buf, dma->sgl,
+                                0, UNSET, bpl, 0, dev->height);
+               break;
+       case V4L2_FIELD_BOTTOM:
+               tw68_risc_buffer(dev->pci, buf, dma->sgl,
+                                UNSET, 0, bpl, 0, dev->height);
+               break;
+       case V4L2_FIELD_SEQ_TB:
+               tw68_risc_buffer(dev->pci, buf, dma->sgl,
+                                0, bpl * (dev->height >> 1),
+                                bpl, 0, dev->height >> 1);
+               break;
+       case V4L2_FIELD_SEQ_BT:
+               tw68_risc_buffer(dev->pci, buf, dma->sgl,
+                                bpl * (dev->height >> 1), 0,
+                                bpl, 0, dev->height >> 1);
+               break;
+       case V4L2_FIELD_INTERLACED:
+       default:
+               tw68_risc_buffer(dev->pci, buf, dma->sgl,
+                                0, bpl, bpl, bpl, dev->height >> 1);
+               break;
+       }
+       return 0;
+}
+
+static void tw68_buf_finish(struct vb2_buffer *vb)
+{
+       struct vb2_queue *vq = vb->vb2_queue;
+       struct tw68_dev *dev = vb2_get_drv_priv(vq);
+       struct sg_table *dma = vb2_dma_sg_plane_desc(vb, 0);
+       struct tw68_buf *buf = container_of(vb, struct tw68_buf, vb);
+
+       dma_unmap_sg(&dev->pci->dev, dma->sgl, dma->nents, DMA_FROM_DEVICE);
+
+       pci_free_consistent(dev->pci, buf->size, buf->cpu, buf->dma);
+}
+
+static int tw68_start_streaming(struct vb2_queue *q, unsigned int count)
+{
+       struct tw68_dev *dev = vb2_get_drv_priv(q);
+       struct tw68_buf *buf =
+               container_of(dev->active.next, struct tw68_buf, list);
+
+       dev->seqnr = 0;
+       tw68_video_start_dma(dev, buf);
+       return 0;
+}
+
+static void tw68_stop_streaming(struct vb2_queue *q)
+{
+       struct tw68_dev *dev = vb2_get_drv_priv(q);
+
+       /* Stop risc & fifo */
+       tw_clearl(TW68_DMAC, TW68_DMAP_EN | TW68_FIFO_EN);
+       while (!list_empty(&dev->active)) {
+               struct tw68_buf *buf =
+                       container_of(dev->active.next, struct tw68_buf, list);
+
+               list_del(&buf->list);
+               vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR);
+       }
+}
+
+static struct vb2_ops tw68_video_qops = {
+       .queue_setup    = tw68_queue_setup,
+       .buf_queue      = tw68_buf_queue,
+       .buf_prepare    = tw68_buf_prepare,
+       .buf_finish     = tw68_buf_finish,
+       .start_streaming = tw68_start_streaming,
+       .stop_streaming = tw68_stop_streaming,
+       .wait_prepare   = vb2_ops_wait_prepare,
+       .wait_finish    = vb2_ops_wait_finish,
+};
+
+/* ------------------------------------------------------------------ */
+
+static int tw68_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+       struct tw68_dev *dev =
+               container_of(ctrl->handler, struct tw68_dev, hdl);
+
+       switch (ctrl->id) {
+       case V4L2_CID_BRIGHTNESS:
+               tw_writeb(TW68_BRIGHT, ctrl->val);
+               break;
+       case V4L2_CID_HUE:
+               tw_writeb(TW68_HUE, ctrl->val);
+               break;
+       case V4L2_CID_CONTRAST:
+               tw_writeb(TW68_CONTRAST, ctrl->val);
+               break;
+       case V4L2_CID_SATURATION:
+               tw_writeb(TW68_SAT_U, ctrl->val);
+               tw_writeb(TW68_SAT_V, ctrl->val);
+               break;
+       case V4L2_CID_COLOR_KILLER:
+               if (ctrl->val)
+                       tw_andorb(TW68_MISC2, 0xe0, 0xe0);
+               else
+                       tw_andorb(TW68_MISC2, 0xe0, 0x00);
+               break;
+       case V4L2_CID_CHROMA_AGC:
+               if (ctrl->val)
+                       tw_andorb(TW68_LOOP, 0x30, 0x20);
+               else
+                       tw_andorb(TW68_LOOP, 0x30, 0x00);
+               break;
+       }
+       return 0;
+}
+
+/* ------------------------------------------------------------------ */
+
+/*
+ * Note that this routine returns what is stored in the fh structure, and
+ * does not interrogate any of the device registers.
+ */
+static int tw68_g_fmt_vid_cap(struct file *file, void *priv,
+                               struct v4l2_format *f)
+{
+       struct tw68_dev *dev = video_drvdata(file);
+
+       f->fmt.pix.width        = dev->width;
+       f->fmt.pix.height       = dev->height;
+       f->fmt.pix.field        = dev->field;
+       f->fmt.pix.pixelformat  = dev->fmt->fourcc;
+       f->fmt.pix.bytesperline =
+               (f->fmt.pix.width * (dev->fmt->depth)) >> 3;
+       f->fmt.pix.sizeimage =
+               f->fmt.pix.height * f->fmt.pix.bytesperline;
+       f->fmt.pix.colorspace   = V4L2_COLORSPACE_SMPTE170M;
+       f->fmt.pix.priv = 0;
+       return 0;
+}
+
+static int tw68_try_fmt_vid_cap(struct file *file, void *priv,
+                                               struct v4l2_format *f)
+{
+       struct tw68_dev *dev = video_drvdata(file);
+       const struct tw68_format *fmt;
+       enum v4l2_field field;
+       unsigned int maxh;
+
+       fmt = format_by_fourcc(f->fmt.pix.pixelformat);
+       if (NULL == fmt)
+               return -EINVAL;
+
+       field = f->fmt.pix.field;
+       maxh  = (dev->tvnorm->id & V4L2_STD_525_60) ? 480 : 576;
+
+       switch (field) {
+       case V4L2_FIELD_TOP:
+       case V4L2_FIELD_BOTTOM:
+               break;
+       case V4L2_FIELD_INTERLACED:
+       case V4L2_FIELD_SEQ_BT:
+       case V4L2_FIELD_SEQ_TB:
+               maxh = maxh * 2;
+               break;
+       default:
+               field = (f->fmt.pix.height > maxh / 2)
+                       ? V4L2_FIELD_INTERLACED
+                       : V4L2_FIELD_BOTTOM;
+               break;
+       }
+
+       f->fmt.pix.field = field;
+       if (f->fmt.pix.width  < 48)
+               f->fmt.pix.width  = 48;
+       if (f->fmt.pix.height < 32)
+               f->fmt.pix.height = 32;
+       if (f->fmt.pix.width > 720)
+               f->fmt.pix.width = 720;
+       if (f->fmt.pix.height > maxh)
+               f->fmt.pix.height = maxh;
+       f->fmt.pix.width &= ~0x03;
+       f->fmt.pix.bytesperline =
+               (f->fmt.pix.width * (fmt->depth)) >> 3;
+       f->fmt.pix.sizeimage =
+               f->fmt.pix.height * f->fmt.pix.bytesperline;
+       f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
+       return 0;
+}
+
+/*
+ * Note that tw68_s_fmt_vid_cap sets the information into the fh structure,
+ * and it will be used for all future new buffers.  However, there could be
+ * some number of buffers on the "active" chain which will be filled before
+ * the change takes place.
+ */
+static int tw68_s_fmt_vid_cap(struct file *file, void *priv,
+                                       struct v4l2_format *f)
+{
+       struct tw68_dev *dev = video_drvdata(file);
+       int err;
+
+       err = tw68_try_fmt_vid_cap(file, priv, f);
+       if (0 != err)
+               return err;
+
+       dev->fmt = format_by_fourcc(f->fmt.pix.pixelformat);
+       dev->width = f->fmt.pix.width;
+       dev->height = f->fmt.pix.height;
+       dev->field = f->fmt.pix.field;
+       return 0;
+}
+
+static int tw68_enum_input(struct file *file, void *priv,
+                                       struct v4l2_input *i)
+{
+       struct tw68_dev *dev = video_drvdata(file);
+       unsigned int n;
+
+       n = i->index;
+       if (n >= TW68_INPUT_MAX)
+               return -EINVAL;
+       i->index = n;
+       i->type = V4L2_INPUT_TYPE_CAMERA;
+       snprintf(i->name, sizeof(i->name), "Composite %d", n);
+
+       /* If the query is for the current input, get live data */
+       if (n == dev->input) {
+               int v1 = tw_readb(TW68_STATUS1);
+               int v2 = tw_readb(TW68_MVSN);
+
+               if (0 != (v1 & (1 << 7)))
+                       i->status |= V4L2_IN_ST_NO_SYNC;
+               if (0 != (v1 & (1 << 6)))
+                       i->status |= V4L2_IN_ST_NO_H_LOCK;
+               if (0 != (v1 & (1 << 2)))
+                       i->status |= V4L2_IN_ST_NO_SIGNAL;
+               if (0 != (v1 & 1 << 1))
+                       i->status |= V4L2_IN_ST_NO_COLOR;
+               if (0 != (v2 & (1 << 2)))
+                       i->status |= V4L2_IN_ST_MACROVISION;
+       }
+       i->std = video_devdata(file)->tvnorms;
+       return 0;
+}
+
+static int tw68_g_input(struct file *file, void *priv, unsigned int *i)
+{
+       struct tw68_dev *dev = video_drvdata(file);
+
+       *i = dev->input;
+       return 0;
+}
+
+static int tw68_s_input(struct file *file, void *priv, unsigned int i)
+{
+       struct tw68_dev *dev = video_drvdata(file);
+
+       if (i >= TW68_INPUT_MAX)
+               return -EINVAL;
+       dev->input = i;
+       tw_andorb(TW68_INFORM, 0x03 << 2, dev->input << 2);
+       return 0;
+}
+
+static int tw68_querycap(struct file *file, void  *priv,
+                                       struct v4l2_capability *cap)
+{
+       struct tw68_dev *dev = video_drvdata(file);
+
+       strcpy(cap->driver, "tw68");
+       strlcpy(cap->card, "Techwell Capture Card",
+               sizeof(cap->card));
+       sprintf(cap->bus_info, "PCI:%s", pci_name(dev->pci));
+       cap->device_caps =
+               V4L2_CAP_VIDEO_CAPTURE |
+               V4L2_CAP_READWRITE |
+               V4L2_CAP_STREAMING;
+
+       cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
+       return 0;
+}
+
+static int tw68_s_std(struct file *file, void *priv, v4l2_std_id id)
+{
+       struct tw68_dev *dev = video_drvdata(file);
+       unsigned int i;
+
+       if (vb2_is_busy(&dev->vidq))
+               return -EBUSY;
+
+       /* Look for match on complete norm id (may have mult bits) */
+       for (i = 0; i < TVNORMS; i++) {
+               if (id == tvnorms[i].id)
+                       break;
+       }
+
+       /* If no exact match, look for norm which contains this one */
+       if (i == TVNORMS) {
+               for (i = 0; i < TVNORMS; i++)
+                       if (id & tvnorms[i].id)
+                               break;
+       }
+       /* If still not matched, give up */
+       if (i == TVNORMS)
+               return -EINVAL;
+
+       set_tvnorm(dev, &tvnorms[i]);   /* do the actual setting */
+       return 0;
+}
+
+static int tw68_g_std(struct file *file, void *priv, v4l2_std_id *id)
+{
+       struct tw68_dev *dev = video_drvdata(file);
+
+       *id = dev->tvnorm->id;
+       return 0;
+}
+
+static int tw68_enum_fmt_vid_cap(struct file *file, void  *priv,
+                                       struct v4l2_fmtdesc *f)
+{
+       if (f->index >= FORMATS)
+               return -EINVAL;
+
+       strlcpy(f->description, formats[f->index].name,
+               sizeof(f->description));
+
+       f->pixelformat = formats[f->index].fourcc;
+
+       return 0;
+}
+
+/*
+ * Used strictly for internal development and debugging, this routine
+ * prints out the current register contents for the tw68xx device.
+ */
+static void tw68_dump_regs(struct tw68_dev *dev)
+{
+       unsigned char line[80];
+       int i, j, k;
+       unsigned char *cptr;
+
+       pr_info("Full dump of TW68 registers:\n");
+       /* First we do the PCI regs, 8 4-byte regs per line */
+       for (i = 0; i < 0x100; i += 32) {
+               cptr = line;
+               cptr += sprintf(cptr, "%03x  ", i);
+               /* j steps through the next 4 words */
+               for (j = i; j < i + 16; j += 4)
+                       cptr += sprintf(cptr, "%08x ", tw_readl(j));
+               *cptr++ = ' ';
+               for (; j < i + 32; j += 4)
+                       cptr += sprintf(cptr, "%08x ", tw_readl(j));
+               *cptr++ = '\n';
+               *cptr = 0;
+               pr_info("%s", line);
+       }
+       /* Next the control regs, which are single-byte, address mod 4 */
+       while (i < 0x400) {
+               cptr = line;
+               cptr += sprintf(cptr, "%03x ", i);
+               /* Print out 4 groups of 4 bytes */
+               for (j = 0; j < 4; j++) {
+                       for (k = 0; k < 4; k++) {
+                               cptr += sprintf(cptr, "%02x ",
+                                       tw_readb(i));
+                               i += 4;
+                       }
+                       *cptr++ = ' ';
+               }
+               *cptr++ = '\n';
+               *cptr = 0;
+               pr_info("%s", line);
+       }
+}
+
+static int vidioc_log_status(struct file *file, void *priv)
+{
+       struct tw68_dev *dev = video_drvdata(file);
+
+       tw68_dump_regs(dev);
+       return v4l2_ctrl_log_status(file, priv);
+}
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+static int vidioc_g_register(struct file *file, void *priv,
+                             struct v4l2_dbg_register *reg)
+{
+       struct tw68_dev *dev = video_drvdata(file);
+
+       if (reg->size == 1)
+               reg->val = tw_readb(reg->reg);
+       else
+               reg->val = tw_readl(reg->reg);
+       return 0;
+}
+
+static int vidioc_s_register(struct file *file, void *priv,
+                               const struct v4l2_dbg_register *reg)
+{
+       struct tw68_dev *dev = video_drvdata(file);
+
+       if (reg->size == 1)
+               tw_writeb(reg->reg, reg->val);
+       else
+               tw_writel(reg->reg & 0xffff, reg->val);
+       return 0;
+}
+#endif
+
+static const struct v4l2_ctrl_ops tw68_ctrl_ops = {
+       .s_ctrl = tw68_s_ctrl,
+};
+
+static const struct v4l2_file_operations video_fops = {
+       .owner                  = THIS_MODULE,
+       .open                   = v4l2_fh_open,
+       .release                = vb2_fop_release,
+       .read                   = vb2_fop_read,
+       .poll                   = vb2_fop_poll,
+       .mmap                   = vb2_fop_mmap,
+       .unlocked_ioctl         = video_ioctl2,
+};
+
+static const struct v4l2_ioctl_ops video_ioctl_ops = {
+       .vidioc_querycap                = tw68_querycap,
+       .vidioc_enum_fmt_vid_cap        = tw68_enum_fmt_vid_cap,
+       .vidioc_reqbufs                 = vb2_ioctl_reqbufs,
+       .vidioc_create_bufs             = vb2_ioctl_create_bufs,
+       .vidioc_querybuf                = vb2_ioctl_querybuf,
+       .vidioc_qbuf                    = vb2_ioctl_qbuf,
+       .vidioc_dqbuf                   = vb2_ioctl_dqbuf,
+       .vidioc_s_std                   = tw68_s_std,
+       .vidioc_g_std                   = tw68_g_std,
+       .vidioc_enum_input              = tw68_enum_input,
+       .vidioc_g_input                 = tw68_g_input,
+       .vidioc_s_input                 = tw68_s_input,
+       .vidioc_streamon                = vb2_ioctl_streamon,
+       .vidioc_streamoff               = vb2_ioctl_streamoff,
+       .vidioc_g_fmt_vid_cap           = tw68_g_fmt_vid_cap,
+       .vidioc_try_fmt_vid_cap         = tw68_try_fmt_vid_cap,
+       .vidioc_s_fmt_vid_cap           = tw68_s_fmt_vid_cap,
+       .vidioc_log_status              = vidioc_log_status,
+       .vidioc_subscribe_event         = v4l2_ctrl_subscribe_event,
+       .vidioc_unsubscribe_event       = v4l2_event_unsubscribe,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+       .vidioc_g_register              = vidioc_g_register,
+       .vidioc_s_register              = vidioc_s_register,
+#endif
+};
+
+static struct video_device tw68_video_template = {
+       .name                   = "tw68_video",
+       .fops                   = &video_fops,
+       .ioctl_ops              = &video_ioctl_ops,
+       .release                = video_device_release_empty,
+       .tvnorms                = TW68_NORMS,
+};
+
+/* ------------------------------------------------------------------ */
+/* exported stuff                                                     */
+void tw68_set_tvnorm_hw(struct tw68_dev *dev)
+{
+       tw_andorb(TW68_SDT, 0x07, dev->tvnorm->format);
+}
+
+int tw68_video_init1(struct tw68_dev *dev)
+{
+       struct v4l2_ctrl_handler *hdl = &dev->hdl;
+
+       v4l2_ctrl_handler_init(hdl, 6);
+       v4l2_ctrl_new_std(hdl, &tw68_ctrl_ops,
+                       V4L2_CID_BRIGHTNESS, -128, 127, 1, 20);
+       v4l2_ctrl_new_std(hdl, &tw68_ctrl_ops,
+                       V4L2_CID_CONTRAST, 0, 255, 1, 100);
+       v4l2_ctrl_new_std(hdl, &tw68_ctrl_ops,
+                       V4L2_CID_SATURATION, 0, 255, 1, 128);
+       /* NTSC only */
+       v4l2_ctrl_new_std(hdl, &tw68_ctrl_ops,
+                       V4L2_CID_HUE, -128, 127, 1, 0);
+       v4l2_ctrl_new_std(hdl, &tw68_ctrl_ops,
+                       V4L2_CID_COLOR_KILLER, 0, 1, 1, 0);
+       v4l2_ctrl_new_std(hdl, &tw68_ctrl_ops,
+                       V4L2_CID_CHROMA_AGC, 0, 1, 1, 1);
+       if (hdl->error) {
+               v4l2_ctrl_handler_free(hdl);
+               return hdl->error;
+       }
+       dev->v4l2_dev.ctrl_handler = hdl;
+       v4l2_ctrl_handler_setup(hdl);
+       return 0;
+}
+
+int tw68_video_init2(struct tw68_dev *dev, int video_nr)
+{
+       int ret;
+
+       set_tvnorm(dev, &tvnorms[0]);
+
+       dev->fmt      = format_by_fourcc(V4L2_PIX_FMT_BGR24);
+       dev->width    = 720;
+       dev->height   = 576;
+       dev->field    = V4L2_FIELD_INTERLACED;
+
+       INIT_LIST_HEAD(&dev->active);
+       dev->vidq.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+       dev->vidq.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
+       dev->vidq.io_modes = VB2_MMAP | VB2_USERPTR | VB2_READ | VB2_DMABUF;
+       dev->vidq.ops = &tw68_video_qops;
+       dev->vidq.mem_ops = &vb2_dma_sg_memops;
+       dev->vidq.drv_priv = dev;
+       dev->vidq.gfp_flags = __GFP_DMA32;
+       dev->vidq.buf_struct_size = sizeof(struct tw68_buf);
+       dev->vidq.lock = &dev->lock;
+       dev->vidq.min_buffers_needed = 2;
+       ret = vb2_queue_init(&dev->vidq);
+       if (ret)
+               return ret;
+       dev->vdev = tw68_video_template;
+       dev->vdev.v4l2_dev = &dev->v4l2_dev;
+       dev->vdev.lock = &dev->lock;
+       dev->vdev.queue = &dev->vidq;
+       video_set_drvdata(&dev->vdev, dev);
+       return video_register_device(&dev->vdev, VFL_TYPE_GRABBER, video_nr);
+}
+
+/*
+ * tw68_irq_video_done
+ */
+void tw68_irq_video_done(struct tw68_dev *dev, unsigned long status)
+{
+       __u32 reg;
+
+       /* reset interrupts handled by this routine */
+       tw_writel(TW68_INTSTAT, status);
+       /*
+        * Check most likely first
+        *
+        * DMAPI shows we have reached the end of the risc code
+        * for the current buffer.
+        */
+       if (status & TW68_DMAPI) {
+               struct tw68_buf *buf;
+
+               spin_lock(&dev->slock);
+               buf = list_entry(dev->active.next, struct tw68_buf, list);
+               list_del(&buf->list);
+               spin_unlock(&dev->slock);
+               v4l2_get_timestamp(&buf->vb.v4l2_buf.timestamp);
+               buf->vb.v4l2_buf.field = dev->field;
+               buf->vb.v4l2_buf.sequence = dev->seqnr++;
+               vb2_buffer_done(&buf->vb, VB2_BUF_STATE_DONE);
+               status &= ~(TW68_DMAPI);
+               if (0 == status)
+                       return;
+       }
+       if (status & (TW68_VLOCK | TW68_HLOCK))
+               dev_dbg(&dev->pci->dev, "Lost sync\n");
+       if (status & TW68_PABORT)
+               dev_err(&dev->pci->dev, "PABORT interrupt\n");
+       if (status & TW68_DMAPERR)
+               dev_err(&dev->pci->dev, "DMAPERR interrupt\n");
+       /*
+        * On TW6800, FDMIS is apparently generated if video input is switched
+        * during operation.  Therefore, it is not enabled for that chip.
+        */
+       if (status & TW68_FDMIS)
+               dev_dbg(&dev->pci->dev, "FDMIS interrupt\n");
+       if (status & TW68_FFOF) {
+               /* probably a logic error */
+               reg = tw_readl(TW68_DMAC) & TW68_FIFO_EN;
+               tw_clearl(TW68_DMAC, TW68_FIFO_EN);
+               dev_dbg(&dev->pci->dev, "FFOF interrupt\n");
+               tw_setl(TW68_DMAC, reg);
+       }
+       if (status & TW68_FFERR)
+               dev_dbg(&dev->pci->dev, "FFERR interrupt\n");
+}
diff --git a/drivers/media/pci/tw68/tw68.h b/drivers/media/pci/tw68/tw68.h
new file mode 100644 (file)
index 0000000..2c8abe2
--- /dev/null
@@ -0,0 +1,231 @@
+/*
+ *  tw68 driver common header file
+ *
+ *  Much of this code is derived from the cx88 and sa7134 drivers, which
+ *  were in turn derived from the bt87x driver.  The original work was by
+ *  Gerd Knorr; more recently the code was enhanced by Mauro Carvalho Chehab,
+ *  Hans Verkuil, Andy Walls and many others.  Their work is gratefully
+ *  acknowledged.  Full credit goes to them - any problems within this code
+ *  are mine.
+ *
+ *  Copyright (C) 2009  William M. Brack
+ *
+ *  Refactored and updated to the latest v4l core frameworks:
+ *
+ *  Copyright (C) 2014 Hans Verkuil <hverkuil@xs4all.nl>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ */
+
+#include <linux/version.h>
+#include <linux/pci.h>
+#include <linux/videodev2.h>
+#include <linux/notifier.h>
+#include <linux/delay.h>
+#include <linux/mutex.h>
+#include <linux/io.h>
+
+#include <media/v4l2-common.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-device.h>
+#include <media/videobuf2-dma-sg.h>
+
+#include "tw68-reg.h"
+
+#define        UNSET   (-1U)
+
+/* system vendor and device ID's */
+#define        PCI_VENDOR_ID_TECHWELL  0x1797
+#define        PCI_DEVICE_ID_6800      0x6800
+#define        PCI_DEVICE_ID_6801      0x6801
+#define        PCI_DEVICE_ID_AUDIO2    0x6802
+#define        PCI_DEVICE_ID_TS3       0x6803
+#define        PCI_DEVICE_ID_6804      0x6804
+#define        PCI_DEVICE_ID_AUDIO5    0x6805
+#define        PCI_DEVICE_ID_TS6       0x6806
+
+/* tw6816 based cards */
+#define        PCI_DEVICE_ID_6816_1   0x6810
+#define        PCI_DEVICE_ID_6816_2   0x6811
+#define        PCI_DEVICE_ID_6816_3   0x6812
+#define        PCI_DEVICE_ID_6816_4   0x6813
+
+#define TW68_NORMS ( \
+       V4L2_STD_NTSC    | V4L2_STD_PAL       | V4L2_STD_SECAM    | \
+       V4L2_STD_PAL_M   | V4L2_STD_PAL_Nc    | V4L2_STD_PAL_60)
+
+#define        TW68_VID_INTS   (TW68_FFERR | TW68_PABORT | TW68_DMAPERR | \
+                        TW68_FFOF   | TW68_DMAPI)
+/* TW6800 chips have trouble with these, so we don't set them for that chip */
+#define        TW68_VID_INTSX  (TW68_FDMIS | TW68_HLOCK | TW68_VLOCK)
+
+#define        TW68_I2C_INTS   (TW68_SBERR | TW68_SBDONE | TW68_SBERR2  | \
+                        TW68_SBDONE2)
+
+enum tw68_decoder_type {
+       TW6800,
+       TW6801,
+       TW6804,
+       TWXXXX,
+};
+
+/* ----------------------------------------------------------- */
+/* static data                                                 */
+
+struct tw68_tvnorm {
+       char            *name;
+       v4l2_std_id     id;
+
+       /* video decoder */
+       u32     sync_control;
+       u32     luma_control;
+       u32     chroma_ctrl1;
+       u32     chroma_gain;
+       u32     chroma_ctrl2;
+       u32     vgate_misc;
+
+       /* video scaler */
+       u32     h_delay;
+       u32     h_delay0;       /* for TW6800 */
+       u32     h_start;
+       u32     h_stop;
+       u32     v_delay;
+       u32     video_v_start;
+       u32     video_v_stop;
+       u32     vbi_v_start_0;
+       u32     vbi_v_stop_0;
+       u32     vbi_v_start_1;
+
+       /* Techwell specific */
+       u32     format;
+};
+
+struct tw68_format {
+       char    *name;
+       u32     fourcc;
+       u32     depth;
+       u32     twformat;
+};
+
+/* ----------------------------------------------------------- */
+/* card configuration                                    */
+
+#define TW68_BOARD_NOAUTO              UNSET
+#define TW68_BOARD_UNKNOWN             0
+#define        TW68_BOARD_GENERIC_6802         1
+
+#define        TW68_MAXBOARDS                  16
+#define        TW68_INPUT_MAX                  4
+
+/* ----------------------------------------------------------- */
+/* device / file handle status                                 */
+
+#define        BUFFER_TIMEOUT  msecs_to_jiffies(500)   /* 0.5 seconds */
+
+struct tw68_dev;       /* forward delclaration */
+
+/* buffer for one video/vbi/ts frame */
+struct tw68_buf {
+       struct vb2_buffer vb;
+       struct list_head list;
+
+       unsigned int   size;
+       __le32         *cpu;
+       __le32         *jmp;
+       dma_addr_t     dma;
+};
+
+struct tw68_fmt {
+       char                    *name;
+       u32                     fourcc; /* v4l2 format id */
+       int                     depth;
+       int                     flags;
+       u32                     twformat;
+};
+
+/* global device status */
+struct tw68_dev {
+       struct mutex            lock;
+       spinlock_t              slock;
+       u16                     instance;
+       struct v4l2_device      v4l2_dev;
+
+       /* various device info */
+       enum tw68_decoder_type  vdecoder;
+       struct video_device     vdev;
+       struct v4l2_ctrl_handler hdl;
+
+       /* pci i/o */
+       char                    *name;
+       struct pci_dev          *pci;
+       unsigned char           pci_rev, pci_lat;
+       u32                     __iomem *lmmio;
+       u8                      __iomem *bmmio;
+       u32                     pci_irqmask;
+       /* The irq mask to be used will depend upon the chip type */
+       u32                     board_virqmask;
+
+       /* video capture */
+       const struct tw68_format *fmt;
+       unsigned                width, height;
+       unsigned                seqnr;
+       unsigned                field;
+       struct vb2_queue        vidq;
+       struct list_head        active;
+
+       /* various v4l controls */
+       const struct tw68_tvnorm *tvnorm;       /* video */
+
+       int                     input;
+};
+
+/* ----------------------------------------------------------- */
+
+#define tw_readl(reg)          readl(dev->lmmio + ((reg) >> 2))
+#define        tw_readb(reg)           readb(dev->bmmio + (reg))
+#define tw_writel(reg, value)  writel((value), dev->lmmio + ((reg) >> 2))
+#define        tw_writeb(reg, value)   writeb((value), dev->bmmio + (reg))
+
+#define tw_andorl(reg, mask, value) \
+               writel((readl(dev->lmmio+((reg)>>2)) & ~(mask)) |\
+               ((value) & (mask)), dev->lmmio+((reg)>>2))
+#define        tw_andorb(reg, mask, value) \
+               writeb((readb(dev->bmmio + (reg)) & ~(mask)) |\
+               ((value) & (mask)), dev->bmmio+(reg))
+#define tw_setl(reg, bit)      tw_andorl((reg), (bit), (bit))
+#define        tw_setb(reg, bit)       tw_andorb((reg), (bit), (bit))
+#define        tw_clearl(reg, bit)     \
+               writel((readl(dev->lmmio + ((reg) >> 2)) & ~(bit)), \
+               dev->lmmio + ((reg) >> 2))
+#define        tw_clearb(reg, bit)     \
+               writeb((readb(dev->bmmio+(reg)) & ~(bit)), \
+               dev->bmmio + (reg))
+
+#define tw_wait(us) { udelay(us); }
+
+/* ----------------------------------------------------------- */
+/* tw68-video.c                                                */
+
+void tw68_set_tvnorm_hw(struct tw68_dev *dev);
+
+int tw68_video_init1(struct tw68_dev *dev);
+int tw68_video_init2(struct tw68_dev *dev, int video_nr);
+void tw68_irq_video_done(struct tw68_dev *dev, unsigned long status);
+int tw68_video_start_dma(struct tw68_dev *dev, struct tw68_buf *buf);
+
+/* ----------------------------------------------------------- */
+/* tw68-risc.c                                                 */
+
+int tw68_risc_buffer(struct pci_dev *pci, struct tw68_buf *buf,
+       struct scatterlist *sglist, unsigned int top_offset,
+       unsigned int bottom_offset, unsigned int bpl,
+       unsigned int padding, unsigned int lines);
index bf34b93f23ee84fee373057778b1692059b58a84..b6801e035ea451c59800a95456425c249e14dd83 100644 (file)
@@ -682,7 +682,7 @@ set_videobus_dir (struct zoran *zr,
        switch (zr->card.type) {
        case LML33:
        case LML33R10:
-               if (lml33dpath == 0)
+               if (!lml33dpath)
                        GPIO(zr, 5, val);
                else
                        GPIO(zr, 5, 1);
index 6d86646d97433e2436435d52884e2e92ed1c2e33..bee9074ebc138b28a0b12bc38c398d720eadb463 100644 (file)
@@ -56,7 +56,8 @@ config VIDEO_VIU
 
 config VIDEO_TIMBERDALE
        tristate "Support for timberdale Video In/LogiWIN"
-       depends on MFD_TIMBERDALE && VIDEO_V4L2 && I2C && DMADEVICES
+       depends on VIDEO_V4L2 && I2C && DMADEVICES
+       depends on MFD_TIMBERDALE || COMPILE_TEST
        select DMA_ENGINE
        select TIMB_DMA
        select VIDEO_ADV7180
@@ -74,7 +75,8 @@ config VIDEO_VINO
 
 config VIDEO_M32R_AR
        tristate "AR devices"
-       depends on M32R && VIDEO_V4L2
+       depends on VIDEO_V4L2
+       depends on M32R || COMPILE_TEST
        ---help---
          This is a video4linux driver for the Renesas AR (Artificial Retina)
          camera module.
@@ -94,6 +96,7 @@ config VIDEO_M32R_AR_M64278
 config VIDEO_OMAP3
        tristate "OMAP 3 Camera support"
        depends on VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API && ARCH_OMAP3
+       depends on HAS_DMA
        select ARM_DMA_USE_IOMMU
        select OMAP_IOMMU
        select VIDEOBUF2_DMA_CONTIG
@@ -109,7 +112,9 @@ config VIDEO_OMAP3_DEBUG
 config VIDEO_S3C_CAMIF
        tristate "Samsung S3C24XX/S3C64XX SoC Camera Interface driver"
        depends on VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API
-       depends on (ARCH_S3C64XX || PLAT_S3C24XX) && PM_RUNTIME
+       depends on PM_RUNTIME
+       depends on ARCH_S3C64XX || PLAT_S3C24XX || COMPILE_TEST
+       depends on HAS_DMA
        select VIDEOBUF2_DMA_CONTIG
        ---help---
          This is a v4l2 driver for s3c24xx and s3c64xx SoC series camera
@@ -140,6 +145,7 @@ if V4L_MEM2MEM_DRIVERS
 config VIDEO_CODA
        tristate "Chips&Media Coda multi-standard codec IP"
        depends on VIDEO_DEV && VIDEO_V4L2 && ARCH_MXC
+       depends on HAS_DMA
        select SRAM
        select VIDEOBUF2_DMA_CONTIG
        select V4L2_MEM2MEM_DEV
@@ -151,6 +157,7 @@ config VIDEO_CODA
 config VIDEO_MEM2MEM_DEINTERLACE
        tristate "Deinterlace support"
        depends on VIDEO_DEV && VIDEO_V4L2 && DMA_ENGINE
+       depends on HAS_DMA
        select VIDEOBUF2_DMA_CONTIG
        select V4L2_MEM2MEM_DEV
        help
@@ -158,7 +165,9 @@ config VIDEO_MEM2MEM_DEINTERLACE
 
 config VIDEO_SAMSUNG_S5P_G2D
        tristate "Samsung S5P and EXYNOS4 G2D 2d graphics accelerator driver"
-       depends on VIDEO_DEV && VIDEO_V4L2 && (PLAT_S5P || ARCH_EXYNOS)
+       depends on VIDEO_DEV && VIDEO_V4L2
+       depends on PLAT_S5P || ARCH_EXYNOS || COMPILE_TEST
+       depends on HAS_DMA
        select VIDEOBUF2_DMA_CONTIG
        select V4L2_MEM2MEM_DEV
        default n
@@ -168,7 +177,9 @@ config VIDEO_SAMSUNG_S5P_G2D
 
 config VIDEO_SAMSUNG_S5P_JPEG
        tristate "Samsung S5P/Exynos3250/Exynos4 JPEG codec driver"
-       depends on VIDEO_DEV && VIDEO_V4L2 && (PLAT_S5P || ARCH_EXYNOS)
+       depends on VIDEO_DEV && VIDEO_V4L2
+       depends on PLAT_S5P || ARCH_EXYNOS || COMPILE_TEST
+       depends on HAS_DMA
        select VIDEOBUF2_DMA_CONTIG
        select V4L2_MEM2MEM_DEV
        ---help---
@@ -177,7 +188,9 @@ config VIDEO_SAMSUNG_S5P_JPEG
 
 config VIDEO_SAMSUNG_S5P_MFC
        tristate "Samsung S5P MFC Video Codec"
-       depends on VIDEO_DEV && VIDEO_V4L2 && (PLAT_S5P || ARCH_EXYNOS)
+       depends on VIDEO_DEV && VIDEO_V4L2
+       depends on PLAT_S5P || ARCH_EXYNOS || COMPILE_TEST
+       depends on HAS_DMA
        select VIDEOBUF2_DMA_CONTIG
        default n
        help
@@ -185,7 +198,9 @@ config VIDEO_SAMSUNG_S5P_MFC
 
 config VIDEO_MX2_EMMAPRP
        tristate "MX2 eMMa-PrP support"
-       depends on VIDEO_DEV && VIDEO_V4L2 && SOC_IMX27
+       depends on VIDEO_DEV && VIDEO_V4L2
+       depends on SOC_IMX27 || COMPILE_TEST
+       depends on HAS_DMA
        select VIDEOBUF2_DMA_CONTIG
        select V4L2_MEM2MEM_DEV
        help
@@ -195,7 +210,9 @@ config VIDEO_MX2_EMMAPRP
 
 config VIDEO_SAMSUNG_EXYNOS_GSC
        tristate "Samsung Exynos G-Scaler driver"
-       depends on VIDEO_DEV && VIDEO_V4L2 && ARCH_EXYNOS5
+       depends on VIDEO_DEV && VIDEO_V4L2
+       depends on ARCH_EXYNOS5 || COMPILE_TEST
+       depends on HAS_DMA
        select VIDEOBUF2_DMA_CONTIG
        select V4L2_MEM2MEM_DEV
        help
@@ -204,6 +221,7 @@ config VIDEO_SAMSUNG_EXYNOS_GSC
 config VIDEO_SH_VEU
        tristate "SuperH VEU mem2mem video processing driver"
        depends on VIDEO_DEV && VIDEO_V4L2 && HAS_DMA
+       depends on HAS_DMA
        select VIDEOBUF2_DMA_CONTIG
        select V4L2_MEM2MEM_DEV
        help
@@ -213,6 +231,7 @@ config VIDEO_SH_VEU
 config VIDEO_RENESAS_VSP1
        tristate "Renesas VSP1 Video Processing Engine"
        depends on VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API && HAS_DMA
+       depends on ARCH_SHMOBILE || COMPILE_TEST
        select VIDEOBUF2_DMA_CONTIG
        ---help---
          This is a V4L2 driver for the Renesas VSP1 video processing engine.
@@ -222,7 +241,9 @@ config VIDEO_RENESAS_VSP1
 
 config VIDEO_TI_VPE
        tristate "TI VPE (Video Processing Engine) driver"
-       depends on VIDEO_DEV && VIDEO_V4L2 && SOC_DRA7XX
+       depends on VIDEO_DEV && VIDEO_V4L2
+       depends on SOC_DRA7XX || COMPILE_TEST
+       depends on HAS_DMA
        select VIDEOBUF2_DMA_CONTIG
        select V4L2_MEM2MEM_DEV
        default n
@@ -243,19 +264,8 @@ menuconfig V4L_TEST_DRIVERS
        depends on MEDIA_CAMERA_SUPPORT
 
 if V4L_TEST_DRIVERS
-config VIDEO_VIVI
-       tristate "Virtual Video Driver"
-       depends on VIDEO_DEV && VIDEO_V4L2 && !SPARC32 && !SPARC64
-       select FONT_SUPPORT
-       select FONT_8x16
-       select VIDEOBUF2_VMALLOC
-       default n
-       ---help---
-         Enables a virtual video driver. This device shows a color bar
-         and a timestamp, as a real device would generate by using V4L2
-         api.
-         Say Y here if you want to test video apps or debug V4L devices.
-         In doubt, say N.
+
+source "drivers/media/platform/vivid/Kconfig"
 
 config VIDEO_MEM2MEM_TESTDEV
        tristate "Virtual test device for mem2mem framework"
index e5269da91906bd0dea8760e361bb1d599d48b626..579046bc276fd23298b8c298ef1a1d0da8c1fdea 100644 (file)
@@ -15,14 +15,14 @@ obj-$(CONFIG_VIDEO_MMP_CAMERA) += marvell-ccic/
 obj-$(CONFIG_VIDEO_OMAP3)      += omap3isp/
 
 obj-$(CONFIG_VIDEO_VIU) += fsl-viu.o
-obj-$(CONFIG_VIDEO_VIVI) += vivi.o
 
+obj-$(CONFIG_VIDEO_VIVID)              += vivid/
 obj-$(CONFIG_VIDEO_MEM2MEM_TESTDEV) += mem2mem_testdev.o
 
 obj-$(CONFIG_VIDEO_TI_VPE)             += ti-vpe/
 
 obj-$(CONFIG_VIDEO_MX2_EMMAPRP)                += mx2_emmaprp.o
-obj-$(CONFIG_VIDEO_CODA)               += coda.o
+obj-$(CONFIG_VIDEO_CODA)               += coda/
 
 obj-$(CONFIG_VIDEO_SH_VEU)             += sh_veu.o
 
@@ -47,8 +47,6 @@ obj-$(CONFIG_SOC_CAMERA)              += soc_camera/
 
 obj-$(CONFIG_VIDEO_RENESAS_VSP1)       += vsp1/
 
-obj-y  += davinci/
-
-obj-$(CONFIG_ARCH_OMAP)        += omap/
+obj-y  += omap/
 
 ccflags-y += -I$(srctree)/drivers/media/i2c
index cc239972fa2c32283c4a9f523b2a6ba28d494adf..68fa90151b8f40f22146244ba1935cf7489ebdf6 100644 (file)
@@ -1,6 +1,7 @@
 config VIDEO_BLACKFIN_CAPTURE
        tristate "Blackfin Video Capture Driver"
        depends on VIDEO_V4L2 && BLACKFIN && I2C
+       depends on HAS_DMA
        select VIDEOBUF2_DMA_CONTIG
        help
          V4L2 bridge driver for Blackfin video capture device.
diff --git a/drivers/media/platform/coda.c b/drivers/media/platform/coda.c
deleted file mode 100644 (file)
index 3a6d1d2..0000000
+++ /dev/null
@@ -1,3933 +0,0 @@
-/*
- * Coda multi-standard codec IP
- *
- * Copyright (C) 2012 Vista Silicon S.L.
- *    Javier Martin, <javier.martin@vista-silicon.com>
- *    Xavier Duret
- *
- * 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/clk.h>
-#include <linux/debugfs.h>
-#include <linux/delay.h>
-#include <linux/firmware.h>
-#include <linux/genalloc.h>
-#include <linux/interrupt.h>
-#include <linux/io.h>
-#include <linux/irq.h>
-#include <linux/kfifo.h>
-#include <linux/module.h>
-#include <linux/of_device.h>
-#include <linux/platform_device.h>
-#include <linux/pm_runtime.h>
-#include <linux/slab.h>
-#include <linux/videodev2.h>
-#include <linux/of.h>
-#include <linux/platform_data/coda.h>
-#include <linux/reset.h>
-
-#include <media/v4l2-ctrls.h>
-#include <media/v4l2-device.h>
-#include <media/v4l2-event.h>
-#include <media/v4l2-ioctl.h>
-#include <media/v4l2-mem2mem.h>
-#include <media/videobuf2-core.h>
-#include <media/videobuf2-dma-contig.h>
-
-#include "coda.h"
-
-#define CODA_NAME              "coda"
-
-#define CODADX6_MAX_INSTANCES  4
-
-#define CODA_PARA_BUF_SIZE     (10 * 1024)
-#define CODA_ISRAM_SIZE        (2048 * 2)
-
-#define CODA7_PS_BUF_SIZE      0x28000
-#define CODA9_PS_SAVE_SIZE     (512 * 1024)
-
-#define CODA_MAX_FRAMEBUFFERS  8
-
-#define CODA_MAX_FRAME_SIZE    0x100000
-#define FMO_SLICE_SAVE_BUF_SIZE         (32)
-#define CODA_DEFAULT_GAMMA             4096
-#define CODA9_DEFAULT_GAMMA            24576   /* 0.75 * 32768 */
-
-#define MIN_W 176
-#define MIN_H 144
-
-#define S_ALIGN                1 /* multiple of 2 */
-#define W_ALIGN                1 /* multiple of 2 */
-#define H_ALIGN                1 /* multiple of 2 */
-
-#define fh_to_ctx(__fh)        container_of(__fh, struct coda_ctx, fh)
-
-static int coda_debug;
-module_param(coda_debug, int, 0644);
-MODULE_PARM_DESC(coda_debug, "Debug level (0-1)");
-
-enum {
-       V4L2_M2M_SRC = 0,
-       V4L2_M2M_DST = 1,
-};
-
-enum coda_inst_type {
-       CODA_INST_ENCODER,
-       CODA_INST_DECODER,
-};
-
-enum coda_product {
-       CODA_DX6 = 0xf001,
-       CODA_7541 = 0xf012,
-       CODA_960 = 0xf020,
-};
-
-struct coda_fmt {
-       char *name;
-       u32 fourcc;
-};
-
-struct coda_codec {
-       u32 mode;
-       u32 src_fourcc;
-       u32 dst_fourcc;
-       u32 max_w;
-       u32 max_h;
-};
-
-struct coda_devtype {
-       char                    *firmware;
-       enum coda_product       product;
-       struct coda_codec       *codecs;
-       unsigned int            num_codecs;
-       size_t                  workbuf_size;
-       size_t                  tempbuf_size;
-       size_t                  iram_size;
-};
-
-/* Per-queue, driver-specific private data */
-struct coda_q_data {
-       unsigned int            width;
-       unsigned int            height;
-       unsigned int            bytesperline;
-       unsigned int            sizeimage;
-       unsigned int            fourcc;
-       struct v4l2_rect        rect;
-};
-
-struct coda_aux_buf {
-       void                    *vaddr;
-       dma_addr_t              paddr;
-       u32                     size;
-       struct debugfs_blob_wrapper blob;
-       struct dentry           *dentry;
-};
-
-struct coda_dev {
-       struct v4l2_device      v4l2_dev;
-       struct video_device     vfd;
-       struct platform_device  *plat_dev;
-       const struct coda_devtype *devtype;
-
-       void __iomem            *regs_base;
-       struct clk              *clk_per;
-       struct clk              *clk_ahb;
-       struct reset_control    *rstc;
-
-       struct coda_aux_buf     codebuf;
-       struct coda_aux_buf     tempbuf;
-       struct coda_aux_buf     workbuf;
-       struct gen_pool         *iram_pool;
-       struct coda_aux_buf     iram;
-
-       spinlock_t              irqlock;
-       struct mutex            dev_mutex;
-       struct mutex            coda_mutex;
-       struct workqueue_struct *workqueue;
-       struct v4l2_m2m_dev     *m2m_dev;
-       struct vb2_alloc_ctx    *alloc_ctx;
-       struct list_head        instances;
-       unsigned long           instance_mask;
-       struct dentry           *debugfs_root;
-};
-
-struct coda_params {
-       u8                      rot_mode;
-       u8                      h264_intra_qp;
-       u8                      h264_inter_qp;
-       u8                      h264_min_qp;
-       u8                      h264_max_qp;
-       u8                      h264_deblk_enabled;
-       u8                      h264_deblk_alpha;
-       u8                      h264_deblk_beta;
-       u8                      mpeg4_intra_qp;
-       u8                      mpeg4_inter_qp;
-       u8                      gop_size;
-       int                     intra_refresh;
-       int                     codec_mode;
-       int                     codec_mode_aux;
-       enum v4l2_mpeg_video_multi_slice_mode slice_mode;
-       u32                     framerate;
-       u16                     bitrate;
-       u32                     slice_max_bits;
-       u32                     slice_max_mb;
-};
-
-struct coda_iram_info {
-       u32             axi_sram_use;
-       phys_addr_t     buf_bit_use;
-       phys_addr_t     buf_ip_ac_dc_use;
-       phys_addr_t     buf_dbk_y_use;
-       phys_addr_t     buf_dbk_c_use;
-       phys_addr_t     buf_ovl_use;
-       phys_addr_t     buf_btp_use;
-       phys_addr_t     search_ram_paddr;
-       int             search_ram_size;
-       int             remaining;
-       phys_addr_t     next_paddr;
-};
-
-struct gdi_tiled_map {
-       int xy2ca_map[16];
-       int xy2ba_map[16];
-       int xy2ra_map[16];
-       int rbc2axi_map[32];
-       int xy2rbc_config;
-       int map_type;
-#define GDI_LINEAR_FRAME_MAP 0
-};
-
-struct coda_timestamp {
-       struct list_head        list;
-       u32                     sequence;
-       struct v4l2_timecode    timecode;
-       struct timeval          timestamp;
-};
-
-struct coda_ctx {
-       struct coda_dev                 *dev;
-       struct mutex                    buffer_mutex;
-       struct list_head                list;
-       struct work_struct              pic_run_work;
-       struct work_struct              seq_end_work;
-       struct completion               completion;
-       int                             aborting;
-       int                             initialized;
-       int                             streamon_out;
-       int                             streamon_cap;
-       u32                             isequence;
-       u32                             qsequence;
-       u32                             osequence;
-       u32                             sequence_offset;
-       struct coda_q_data              q_data[2];
-       enum coda_inst_type             inst_type;
-       struct coda_codec               *codec;
-       enum v4l2_colorspace            colorspace;
-       struct coda_params              params;
-       struct v4l2_ctrl_handler        ctrls;
-       struct v4l2_fh                  fh;
-       int                             gopcounter;
-       int                             runcounter;
-       char                            vpu_header[3][64];
-       int                             vpu_header_size[3];
-       struct kfifo                    bitstream_fifo;
-       struct mutex                    bitstream_mutex;
-       struct coda_aux_buf             bitstream;
-       bool                            hold;
-       struct coda_aux_buf             parabuf;
-       struct coda_aux_buf             psbuf;
-       struct coda_aux_buf             slicebuf;
-       struct coda_aux_buf             internal_frames[CODA_MAX_FRAMEBUFFERS];
-       u32                             frame_types[CODA_MAX_FRAMEBUFFERS];
-       struct coda_timestamp           frame_timestamps[CODA_MAX_FRAMEBUFFERS];
-       u32                             frame_errors[CODA_MAX_FRAMEBUFFERS];
-       struct list_head                timestamp_list;
-       struct coda_aux_buf             workbuf;
-       int                             num_internal_frames;
-       int                             idx;
-       int                             reg_idx;
-       struct coda_iram_info           iram_info;
-       struct gdi_tiled_map            tiled_map;
-       u32                             bit_stream_param;
-       u32                             frm_dis_flg;
-       u32                             frame_mem_ctrl;
-       int                             display_idx;
-       struct dentry                   *debugfs_entry;
-};
-
-static const u8 coda_filler_nal[14] = { 0x00, 0x00, 0x00, 0x01, 0x0c, 0xff,
-                       0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80 };
-static const u8 coda_filler_size[8] = { 0, 7, 14, 13, 12, 11, 10, 9 };
-
-static inline void coda_write(struct coda_dev *dev, u32 data, u32 reg)
-{
-       v4l2_dbg(1, coda_debug, &dev->v4l2_dev,
-                "%s: data=0x%x, reg=0x%x\n", __func__, data, reg);
-       writel(data, dev->regs_base + reg);
-}
-
-static inline unsigned int coda_read(struct coda_dev *dev, u32 reg)
-{
-       u32 data;
-       data = readl(dev->regs_base + reg);
-       v4l2_dbg(1, coda_debug, &dev->v4l2_dev,
-                "%s: data=0x%x, reg=0x%x\n", __func__, data, reg);
-       return data;
-}
-
-static inline unsigned long coda_isbusy(struct coda_dev *dev)
-{
-       return coda_read(dev, CODA_REG_BIT_BUSY);
-}
-
-static inline int coda_is_initialized(struct coda_dev *dev)
-{
-       return (coda_read(dev, CODA_REG_BIT_CUR_PC) != 0);
-}
-
-static int coda_wait_timeout(struct coda_dev *dev)
-{
-       unsigned long timeout = jiffies + msecs_to_jiffies(1000);
-
-       while (coda_isbusy(dev)) {
-               if (time_after(jiffies, timeout))
-                       return -ETIMEDOUT;
-       }
-       return 0;
-}
-
-static void coda_command_async(struct coda_ctx *ctx, int cmd)
-{
-       struct coda_dev *dev = ctx->dev;
-
-       if (dev->devtype->product == CODA_960 ||
-           dev->devtype->product == CODA_7541) {
-               /* Restore context related registers to CODA */
-               coda_write(dev, ctx->bit_stream_param,
-                               CODA_REG_BIT_BIT_STREAM_PARAM);
-               coda_write(dev, ctx->frm_dis_flg,
-                               CODA_REG_BIT_FRM_DIS_FLG(ctx->reg_idx));
-               coda_write(dev, ctx->frame_mem_ctrl,
-                               CODA_REG_BIT_FRAME_MEM_CTRL);
-               coda_write(dev, ctx->workbuf.paddr, CODA_REG_BIT_WORK_BUF_ADDR);
-       }
-
-       if (dev->devtype->product == CODA_960) {
-               coda_write(dev, 1, CODA9_GDI_WPROT_ERR_CLR);
-               coda_write(dev, 0, CODA9_GDI_WPROT_RGN_EN);
-       }
-
-       coda_write(dev, CODA_REG_BIT_BUSY_FLAG, CODA_REG_BIT_BUSY);
-
-       coda_write(dev, ctx->idx, CODA_REG_BIT_RUN_INDEX);
-       coda_write(dev, ctx->params.codec_mode, CODA_REG_BIT_RUN_COD_STD);
-       coda_write(dev, ctx->params.codec_mode_aux, CODA7_REG_BIT_RUN_AUX_STD);
-
-       coda_write(dev, cmd, CODA_REG_BIT_RUN_COMMAND);
-}
-
-static int coda_command_sync(struct coda_ctx *ctx, int cmd)
-{
-       struct coda_dev *dev = ctx->dev;
-
-       coda_command_async(ctx, cmd);
-       return coda_wait_timeout(dev);
-}
-
-static int coda_hw_reset(struct coda_ctx *ctx)
-{
-       struct coda_dev *dev = ctx->dev;
-       unsigned long timeout;
-       unsigned int idx;
-       int ret;
-
-       if (!dev->rstc)
-               return -ENOENT;
-
-       idx = coda_read(dev, CODA_REG_BIT_RUN_INDEX);
-
-       timeout = jiffies + msecs_to_jiffies(100);
-       coda_write(dev, 0x11, CODA9_GDI_BUS_CTRL);
-       while (coda_read(dev, CODA9_GDI_BUS_STATUS) != 0x77) {
-               if (time_after(jiffies, timeout))
-                       return -ETIME;
-               cpu_relax();
-       }
-
-       ret = reset_control_reset(dev->rstc);
-       if (ret < 0)
-               return ret;
-
-       coda_write(dev, 0x00, CODA9_GDI_BUS_CTRL);
-       coda_write(dev, CODA_REG_BIT_BUSY_FLAG, CODA_REG_BIT_BUSY);
-       coda_write(dev, CODA_REG_RUN_ENABLE, CODA_REG_BIT_CODE_RUN);
-       ret = coda_wait_timeout(dev);
-       coda_write(dev, idx, CODA_REG_BIT_RUN_INDEX);
-
-       return ret;
-}
-
-static struct coda_q_data *get_q_data(struct coda_ctx *ctx,
-                                        enum v4l2_buf_type type)
-{
-       switch (type) {
-       case V4L2_BUF_TYPE_VIDEO_OUTPUT:
-               return &(ctx->q_data[V4L2_M2M_SRC]);
-       case V4L2_BUF_TYPE_VIDEO_CAPTURE:
-               return &(ctx->q_data[V4L2_M2M_DST]);
-       default:
-               return NULL;
-       }
-}
-
-/*
- * Array of all formats supported by any version of Coda:
- */
-static struct coda_fmt coda_formats[] = {
-       {
-               .name = "YUV 4:2:0 Planar, YCbCr",
-               .fourcc = V4L2_PIX_FMT_YUV420,
-       },
-       {
-               .name = "YUV 4:2:0 Planar, YCrCb",
-               .fourcc = V4L2_PIX_FMT_YVU420,
-       },
-       {
-               .name = "H264 Encoded Stream",
-               .fourcc = V4L2_PIX_FMT_H264,
-       },
-       {
-               .name = "MPEG4 Encoded Stream",
-               .fourcc = V4L2_PIX_FMT_MPEG4,
-       },
-};
-
-#define CODA_CODEC(mode, src_fourcc, dst_fourcc, max_w, max_h) \
-       { mode, src_fourcc, dst_fourcc, max_w, max_h }
-
-/*
- * Arrays of codecs supported by each given version of Coda:
- *  i.MX27 -> codadx6
- *  i.MX5x -> coda7
- *  i.MX6  -> coda960
- * Use V4L2_PIX_FMT_YUV420 as placeholder for all supported YUV 4:2:0 variants
- */
-static struct coda_codec codadx6_codecs[] = {
-       CODA_CODEC(CODADX6_MODE_ENCODE_H264, V4L2_PIX_FMT_YUV420, V4L2_PIX_FMT_H264,  720, 576),
-       CODA_CODEC(CODADX6_MODE_ENCODE_MP4,  V4L2_PIX_FMT_YUV420, V4L2_PIX_FMT_MPEG4, 720, 576),
-};
-
-static struct coda_codec coda7_codecs[] = {
-       CODA_CODEC(CODA7_MODE_ENCODE_H264, V4L2_PIX_FMT_YUV420, V4L2_PIX_FMT_H264,   1280, 720),
-       CODA_CODEC(CODA7_MODE_ENCODE_MP4,  V4L2_PIX_FMT_YUV420, V4L2_PIX_FMT_MPEG4,  1280, 720),
-       CODA_CODEC(CODA7_MODE_DECODE_H264, V4L2_PIX_FMT_H264,   V4L2_PIX_FMT_YUV420, 1920, 1080),
-       CODA_CODEC(CODA7_MODE_DECODE_MP4,  V4L2_PIX_FMT_MPEG4,  V4L2_PIX_FMT_YUV420, 1920, 1080),
-};
-
-static struct coda_codec coda9_codecs[] = {
-       CODA_CODEC(CODA9_MODE_ENCODE_H264, V4L2_PIX_FMT_YUV420, V4L2_PIX_FMT_H264,   1920, 1080),
-       CODA_CODEC(CODA9_MODE_ENCODE_MP4,  V4L2_PIX_FMT_YUV420, V4L2_PIX_FMT_MPEG4,  1920, 1080),
-       CODA_CODEC(CODA9_MODE_DECODE_H264, V4L2_PIX_FMT_H264,   V4L2_PIX_FMT_YUV420, 1920, 1080),
-       CODA_CODEC(CODA9_MODE_DECODE_MP4,  V4L2_PIX_FMT_MPEG4,  V4L2_PIX_FMT_YUV420, 1920, 1080),
-};
-
-static bool coda_format_is_yuv(u32 fourcc)
-{
-       switch (fourcc) {
-       case V4L2_PIX_FMT_YUV420:
-       case V4L2_PIX_FMT_YVU420:
-               return true;
-       default:
-               return false;
-       }
-}
-
-/*
- * Normalize all supported YUV 4:2:0 formats to the value used in the codec
- * tables.
- */
-static u32 coda_format_normalize_yuv(u32 fourcc)
-{
-       return coda_format_is_yuv(fourcc) ? V4L2_PIX_FMT_YUV420 : fourcc;
-}
-
-static struct coda_codec *coda_find_codec(struct coda_dev *dev, int src_fourcc,
-                                         int dst_fourcc)
-{
-       struct coda_codec *codecs = dev->devtype->codecs;
-       int num_codecs = dev->devtype->num_codecs;
-       int k;
-
-       src_fourcc = coda_format_normalize_yuv(src_fourcc);
-       dst_fourcc = coda_format_normalize_yuv(dst_fourcc);
-       if (src_fourcc == dst_fourcc)
-               return NULL;
-
-       for (k = 0; k < num_codecs; k++) {
-               if (codecs[k].src_fourcc == src_fourcc &&
-                   codecs[k].dst_fourcc == dst_fourcc)
-                       break;
-       }
-
-       if (k == num_codecs)
-               return NULL;
-
-       return &codecs[k];
-}
-
-static void coda_get_max_dimensions(struct coda_dev *dev,
-                                   struct coda_codec *codec,
-                                   int *max_w, int *max_h)
-{
-       struct coda_codec *codecs = dev->devtype->codecs;
-       int num_codecs = dev->devtype->num_codecs;
-       unsigned int w, h;
-       int k;
-
-       if (codec) {
-               w = codec->max_w;
-               h = codec->max_h;
-       } else {
-               for (k = 0, w = 0, h = 0; k < num_codecs; k++) {
-                       w = max(w, codecs[k].max_w);
-                       h = max(h, codecs[k].max_h);
-               }
-       }
-
-       if (max_w)
-               *max_w = w;
-       if (max_h)
-               *max_h = h;
-}
-
-static char *coda_product_name(int product)
-{
-       static char buf[9];
-
-       switch (product) {
-       case CODA_DX6:
-               return "CodaDx6";
-       case CODA_7541:
-               return "CODA7541";
-       case CODA_960:
-               return "CODA960";
-       default:
-               snprintf(buf, sizeof(buf), "(0x%04x)", product);
-               return buf;
-       }
-}
-
-/*
- * V4L2 ioctl() operations.
- */
-static int coda_querycap(struct file *file, void *priv,
-                        struct v4l2_capability *cap)
-{
-       struct coda_ctx *ctx = fh_to_ctx(priv);
-
-       strlcpy(cap->driver, CODA_NAME, sizeof(cap->driver));
-       strlcpy(cap->card, coda_product_name(ctx->dev->devtype->product),
-               sizeof(cap->card));
-       strlcpy(cap->bus_info, "platform:" CODA_NAME, sizeof(cap->bus_info));
-       /*
-        * This is only a mem-to-mem video device. The capture and output
-        * device capability flags are left only for backward compatibility
-        * and are scheduled for removal.
-        */
-       cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_OUTPUT |
-                          V4L2_CAP_VIDEO_M2M | V4L2_CAP_STREAMING;
-       cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
-
-       return 0;
-}
-
-static int enum_fmt(void *priv, struct v4l2_fmtdesc *f,
-                       enum v4l2_buf_type type, int src_fourcc)
-{
-       struct coda_ctx *ctx = fh_to_ctx(priv);
-       struct coda_codec *codecs = ctx->dev->devtype->codecs;
-       struct coda_fmt *formats = coda_formats;
-       struct coda_fmt *fmt;
-       int num_codecs = ctx->dev->devtype->num_codecs;
-       int num_formats = ARRAY_SIZE(coda_formats);
-       int i, k, num = 0;
-
-       for (i = 0; i < num_formats; i++) {
-               /* Both uncompressed formats are always supported */
-               if (coda_format_is_yuv(formats[i].fourcc) &&
-                   !coda_format_is_yuv(src_fourcc)) {
-                       if (num == f->index)
-                               break;
-                       ++num;
-                       continue;
-               }
-               /* Compressed formats may be supported, check the codec list */
-               for (k = 0; k < num_codecs; k++) {
-                       /* if src_fourcc is set, only consider matching codecs */
-                       if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE &&
-                           formats[i].fourcc == codecs[k].dst_fourcc &&
-                           (!src_fourcc || src_fourcc == codecs[k].src_fourcc))
-                               break;
-                       if (type == V4L2_BUF_TYPE_VIDEO_OUTPUT &&
-                           formats[i].fourcc == codecs[k].src_fourcc)
-                               break;
-               }
-               if (k < num_codecs) {
-                       if (num == f->index)
-                               break;
-                       ++num;
-               }
-       }
-
-       if (i < num_formats) {
-               fmt = &formats[i];
-               strlcpy(f->description, fmt->name, sizeof(f->description));
-               f->pixelformat = fmt->fourcc;
-               if (!coda_format_is_yuv(fmt->fourcc))
-                       f->flags |= V4L2_FMT_FLAG_COMPRESSED;
-               return 0;
-       }
-
-       /* Format not found */
-       return -EINVAL;
-}
-
-static int coda_enum_fmt_vid_cap(struct file *file, void *priv,
-                                struct v4l2_fmtdesc *f)
-{
-       struct coda_ctx *ctx = fh_to_ctx(priv);
-       struct vb2_queue *src_vq;
-       struct coda_q_data *q_data_src;
-
-       /* If the source format is already fixed, only list matching formats */
-       src_vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
-       if (vb2_is_streaming(src_vq)) {
-               q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
-
-               return enum_fmt(priv, f, V4L2_BUF_TYPE_VIDEO_CAPTURE,
-                               q_data_src->fourcc);
-       }
-
-       return enum_fmt(priv, f, V4L2_BUF_TYPE_VIDEO_CAPTURE, 0);
-}
-
-static int coda_enum_fmt_vid_out(struct file *file, void *priv,
-                                struct v4l2_fmtdesc *f)
-{
-       return enum_fmt(priv, f, V4L2_BUF_TYPE_VIDEO_OUTPUT, 0);
-}
-
-static int coda_g_fmt(struct file *file, void *priv,
-                     struct v4l2_format *f)
-{
-       struct coda_q_data *q_data;
-       struct coda_ctx *ctx = fh_to_ctx(priv);
-
-       q_data = get_q_data(ctx, f->type);
-       if (!q_data)
-               return -EINVAL;
-
-       f->fmt.pix.field        = V4L2_FIELD_NONE;
-       f->fmt.pix.pixelformat  = q_data->fourcc;
-       f->fmt.pix.width        = q_data->width;
-       f->fmt.pix.height       = q_data->height;
-       f->fmt.pix.bytesperline = q_data->bytesperline;
-
-       f->fmt.pix.sizeimage    = q_data->sizeimage;
-       f->fmt.pix.colorspace   = ctx->colorspace;
-
-       return 0;
-}
-
-static int coda_try_fmt(struct coda_ctx *ctx, struct coda_codec *codec,
-                       struct v4l2_format *f)
-{
-       struct coda_dev *dev = ctx->dev;
-       struct coda_q_data *q_data;
-       unsigned int max_w, max_h;
-       enum v4l2_field field;
-
-       field = f->fmt.pix.field;
-       if (field == V4L2_FIELD_ANY)
-               field = V4L2_FIELD_NONE;
-       else if (V4L2_FIELD_NONE != field)
-               return -EINVAL;
-
-       /* V4L2 specification suggests the driver corrects the format struct
-        * if any of the dimensions is unsupported */
-       f->fmt.pix.field = field;
-
-       coda_get_max_dimensions(dev, codec, &max_w, &max_h);
-       v4l_bound_align_image(&f->fmt.pix.width, MIN_W, max_w, W_ALIGN,
-                             &f->fmt.pix.height, MIN_H, max_h, H_ALIGN,
-                             S_ALIGN);
-
-       switch (f->fmt.pix.pixelformat) {
-       case V4L2_PIX_FMT_YUV420:
-       case V4L2_PIX_FMT_YVU420:
-       case V4L2_PIX_FMT_H264:
-       case V4L2_PIX_FMT_MPEG4:
-       case V4L2_PIX_FMT_JPEG:
-               break;
-       default:
-               q_data = get_q_data(ctx, f->type);
-               if (!q_data)
-                       return -EINVAL;
-               f->fmt.pix.pixelformat = q_data->fourcc;
-       }
-
-       switch (f->fmt.pix.pixelformat) {
-       case V4L2_PIX_FMT_YUV420:
-       case V4L2_PIX_FMT_YVU420:
-               /* Frame stride must be multiple of 8, but 16 for h.264 */
-               f->fmt.pix.bytesperline = round_up(f->fmt.pix.width, 16);
-               f->fmt.pix.sizeimage = f->fmt.pix.bytesperline *
-                                       f->fmt.pix.height * 3 / 2;
-               break;
-       case V4L2_PIX_FMT_H264:
-       case V4L2_PIX_FMT_MPEG4:
-       case V4L2_PIX_FMT_JPEG:
-               f->fmt.pix.bytesperline = 0;
-               f->fmt.pix.sizeimage = CODA_MAX_FRAME_SIZE;
-               break;
-       default:
-               BUG();
-       }
-
-       return 0;
-}
-
-static int coda_try_fmt_vid_cap(struct file *file, void *priv,
-                               struct v4l2_format *f)
-{
-       struct coda_ctx *ctx = fh_to_ctx(priv);
-       struct coda_codec *codec;
-       struct vb2_queue *src_vq;
-       int ret;
-
-       /*
-        * If the source format is already fixed, try to find a codec that
-        * converts to the given destination format
-        */
-       src_vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
-       if (vb2_is_streaming(src_vq)) {
-               struct coda_q_data *q_data_src;
-
-               q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
-               codec = coda_find_codec(ctx->dev, q_data_src->fourcc,
-                                       f->fmt.pix.pixelformat);
-               if (!codec)
-                       return -EINVAL;
-       } else {
-               /* Otherwise determine codec by encoded format, if possible */
-               codec = coda_find_codec(ctx->dev, V4L2_PIX_FMT_YUV420,
-                                       f->fmt.pix.pixelformat);
-       }
-
-       f->fmt.pix.colorspace = ctx->colorspace;
-
-       ret = coda_try_fmt(ctx, codec, f);
-       if (ret < 0)
-               return ret;
-
-       /* The h.264 decoder only returns complete 16x16 macroblocks */
-       if (codec && codec->src_fourcc == V4L2_PIX_FMT_H264) {
-               f->fmt.pix.width = f->fmt.pix.width;
-               f->fmt.pix.height = round_up(f->fmt.pix.height, 16);
-               f->fmt.pix.bytesperline = round_up(f->fmt.pix.width, 16);
-               f->fmt.pix.sizeimage = f->fmt.pix.bytesperline *
-                                      f->fmt.pix.height * 3 / 2;
-       }
-
-       return 0;
-}
-
-static int coda_try_fmt_vid_out(struct file *file, void *priv,
-                               struct v4l2_format *f)
-{
-       struct coda_ctx *ctx = fh_to_ctx(priv);
-       struct coda_codec *codec;
-
-       /* Determine codec by encoded format, returns NULL if raw or invalid */
-       codec = coda_find_codec(ctx->dev, f->fmt.pix.pixelformat,
-                               V4L2_PIX_FMT_YUV420);
-
-       if (!f->fmt.pix.colorspace)
-               f->fmt.pix.colorspace = V4L2_COLORSPACE_REC709;
-
-       return coda_try_fmt(ctx, codec, f);
-}
-
-static int coda_s_fmt(struct coda_ctx *ctx, struct v4l2_format *f)
-{
-       struct coda_q_data *q_data;
-       struct vb2_queue *vq;
-
-       vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type);
-       if (!vq)
-               return -EINVAL;
-
-       q_data = get_q_data(ctx, f->type);
-       if (!q_data)
-               return -EINVAL;
-
-       if (vb2_is_busy(vq)) {
-               v4l2_err(&ctx->dev->v4l2_dev, "%s queue busy\n", __func__);
-               return -EBUSY;
-       }
-
-       q_data->fourcc = f->fmt.pix.pixelformat;
-       q_data->width = f->fmt.pix.width;
-       q_data->height = f->fmt.pix.height;
-       q_data->bytesperline = f->fmt.pix.bytesperline;
-       q_data->sizeimage = f->fmt.pix.sizeimage;
-       q_data->rect.left = 0;
-       q_data->rect.top = 0;
-       q_data->rect.width = f->fmt.pix.width;
-       q_data->rect.height = f->fmt.pix.height;
-
-       v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev,
-               "Setting format for type %d, wxh: %dx%d, fmt: %d\n",
-               f->type, q_data->width, q_data->height, q_data->fourcc);
-
-       return 0;
-}
-
-static int coda_s_fmt_vid_cap(struct file *file, void *priv,
-                             struct v4l2_format *f)
-{
-       struct coda_ctx *ctx = fh_to_ctx(priv);
-       int ret;
-
-       ret = coda_try_fmt_vid_cap(file, priv, f);
-       if (ret)
-               return ret;
-
-       return coda_s_fmt(ctx, f);
-}
-
-static int coda_s_fmt_vid_out(struct file *file, void *priv,
-                             struct v4l2_format *f)
-{
-       struct coda_ctx *ctx = fh_to_ctx(priv);
-       int ret;
-
-       ret = coda_try_fmt_vid_out(file, priv, f);
-       if (ret)
-               return ret;
-
-       ret = coda_s_fmt(ctx, f);
-       if (ret)
-               ctx->colorspace = f->fmt.pix.colorspace;
-
-       return ret;
-}
-
-static int coda_qbuf(struct file *file, void *priv,
-                    struct v4l2_buffer *buf)
-{
-       struct coda_ctx *ctx = fh_to_ctx(priv);
-
-       return v4l2_m2m_qbuf(file, ctx->fh.m2m_ctx, buf);
-}
-
-static bool coda_buf_is_end_of_stream(struct coda_ctx *ctx,
-                                     struct v4l2_buffer *buf)
-{
-       struct vb2_queue *src_vq;
-
-       src_vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
-
-       return ((ctx->bit_stream_param & CODA_BIT_STREAM_END_FLAG) &&
-               (buf->sequence == (ctx->qsequence - 1)));
-}
-
-static int coda_dqbuf(struct file *file, void *priv,
-                     struct v4l2_buffer *buf)
-{
-       struct coda_ctx *ctx = fh_to_ctx(priv);
-       int ret;
-
-       ret = v4l2_m2m_dqbuf(file, ctx->fh.m2m_ctx, buf);
-
-       /* If this is the last capture buffer, emit an end-of-stream event */
-       if (buf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE &&
-           coda_buf_is_end_of_stream(ctx, buf)) {
-               const struct v4l2_event eos_event = {
-                       .type = V4L2_EVENT_EOS
-               };
-
-               v4l2_event_queue_fh(&ctx->fh, &eos_event);
-       }
-
-       return ret;
-}
-
-static int coda_g_selection(struct file *file, void *fh,
-                           struct v4l2_selection *s)
-{
-       struct coda_ctx *ctx = fh_to_ctx(fh);
-       struct coda_q_data *q_data;
-       struct v4l2_rect r, *rsel;
-
-       q_data = get_q_data(ctx, s->type);
-       if (!q_data)
-               return -EINVAL;
-
-       r.left = 0;
-       r.top = 0;
-       r.width = q_data->width;
-       r.height = q_data->height;
-       rsel = &q_data->rect;
-
-       switch (s->target) {
-       case V4L2_SEL_TGT_CROP_DEFAULT:
-       case V4L2_SEL_TGT_CROP_BOUNDS:
-               rsel = &r;
-               /* fallthrough */
-       case V4L2_SEL_TGT_CROP:
-               if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
-                       return -EINVAL;
-               break;
-       case V4L2_SEL_TGT_COMPOSE_BOUNDS:
-       case V4L2_SEL_TGT_COMPOSE_PADDED:
-               rsel = &r;
-               /* fallthrough */
-       case V4L2_SEL_TGT_COMPOSE:
-       case V4L2_SEL_TGT_COMPOSE_DEFAULT:
-               if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-                       return -EINVAL;
-               break;
-       default:
-               return -EINVAL;
-       }
-
-       s->r = *rsel;
-
-       return 0;
-}
-
-static int coda_try_decoder_cmd(struct file *file, void *fh,
-                               struct v4l2_decoder_cmd *dc)
-{
-       if (dc->cmd != V4L2_DEC_CMD_STOP)
-               return -EINVAL;
-
-       if (dc->flags & V4L2_DEC_CMD_STOP_TO_BLACK)
-               return -EINVAL;
-
-       if (!(dc->flags & V4L2_DEC_CMD_STOP_IMMEDIATELY) && (dc->stop.pts != 0))
-               return -EINVAL;
-
-       return 0;
-}
-
-static int coda_decoder_cmd(struct file *file, void *fh,
-                           struct v4l2_decoder_cmd *dc)
-{
-       struct coda_ctx *ctx = fh_to_ctx(fh);
-       struct coda_dev *dev = ctx->dev;
-       int ret;
-
-       ret = coda_try_decoder_cmd(file, fh, dc);
-       if (ret < 0)
-               return ret;
-
-       /* Ignore decoder stop command silently in encoder context */
-       if (ctx->inst_type != CODA_INST_DECODER)
-               return 0;
-
-       /* Set the strem-end flag on this context */
-       ctx->bit_stream_param |= CODA_BIT_STREAM_END_FLAG;
-
-       if ((dev->devtype->product == CODA_960) &&
-           coda_isbusy(dev) &&
-           (ctx->idx == coda_read(dev, CODA_REG_BIT_RUN_INDEX))) {
-               /* If this context is currently running, update the hardware flag */
-               coda_write(dev, ctx->bit_stream_param, CODA_REG_BIT_BIT_STREAM_PARAM);
-       }
-       ctx->hold = false;
-       v4l2_m2m_try_schedule(ctx->fh.m2m_ctx);
-
-       return 0;
-}
-
-static int coda_subscribe_event(struct v4l2_fh *fh,
-                               const struct v4l2_event_subscription *sub)
-{
-       switch (sub->type) {
-       case V4L2_EVENT_EOS:
-               return v4l2_event_subscribe(fh, sub, 0, NULL);
-       default:
-               return v4l2_ctrl_subscribe_event(fh, sub);
-       }
-}
-
-static const struct v4l2_ioctl_ops coda_ioctl_ops = {
-       .vidioc_querycap        = coda_querycap,
-
-       .vidioc_enum_fmt_vid_cap = coda_enum_fmt_vid_cap,
-       .vidioc_g_fmt_vid_cap   = coda_g_fmt,
-       .vidioc_try_fmt_vid_cap = coda_try_fmt_vid_cap,
-       .vidioc_s_fmt_vid_cap   = coda_s_fmt_vid_cap,
-
-       .vidioc_enum_fmt_vid_out = coda_enum_fmt_vid_out,
-       .vidioc_g_fmt_vid_out   = coda_g_fmt,
-       .vidioc_try_fmt_vid_out = coda_try_fmt_vid_out,
-       .vidioc_s_fmt_vid_out   = coda_s_fmt_vid_out,
-
-       .vidioc_reqbufs         = v4l2_m2m_ioctl_reqbufs,
-       .vidioc_querybuf        = v4l2_m2m_ioctl_querybuf,
-
-       .vidioc_qbuf            = coda_qbuf,
-       .vidioc_expbuf          = v4l2_m2m_ioctl_expbuf,
-       .vidioc_dqbuf           = coda_dqbuf,
-       .vidioc_create_bufs     = v4l2_m2m_ioctl_create_bufs,
-
-       .vidioc_streamon        = v4l2_m2m_ioctl_streamon,
-       .vidioc_streamoff       = v4l2_m2m_ioctl_streamoff,
-
-       .vidioc_g_selection     = coda_g_selection,
-
-       .vidioc_try_decoder_cmd = coda_try_decoder_cmd,
-       .vidioc_decoder_cmd     = coda_decoder_cmd,
-
-       .vidioc_subscribe_event = coda_subscribe_event,
-       .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
-};
-
-static int coda_start_decoding(struct coda_ctx *ctx);
-
-static inline int coda_get_bitstream_payload(struct coda_ctx *ctx)
-{
-       return kfifo_len(&ctx->bitstream_fifo);
-}
-
-static void coda_kfifo_sync_from_device(struct coda_ctx *ctx)
-{
-       struct __kfifo *kfifo = &ctx->bitstream_fifo.kfifo;
-       struct coda_dev *dev = ctx->dev;
-       u32 rd_ptr;
-
-       rd_ptr = coda_read(dev, CODA_REG_BIT_RD_PTR(ctx->reg_idx));
-       kfifo->out = (kfifo->in & ~kfifo->mask) |
-                     (rd_ptr - ctx->bitstream.paddr);
-       if (kfifo->out > kfifo->in)
-               kfifo->out -= kfifo->mask + 1;
-}
-
-static void coda_kfifo_sync_to_device_full(struct coda_ctx *ctx)
-{
-       struct __kfifo *kfifo = &ctx->bitstream_fifo.kfifo;
-       struct coda_dev *dev = ctx->dev;
-       u32 rd_ptr, wr_ptr;
-
-       rd_ptr = ctx->bitstream.paddr + (kfifo->out & kfifo->mask);
-       coda_write(dev, rd_ptr, CODA_REG_BIT_RD_PTR(ctx->reg_idx));
-       wr_ptr = ctx->bitstream.paddr + (kfifo->in & kfifo->mask);
-       coda_write(dev, wr_ptr, CODA_REG_BIT_WR_PTR(ctx->reg_idx));
-}
-
-static void coda_kfifo_sync_to_device_write(struct coda_ctx *ctx)
-{
-       struct __kfifo *kfifo = &ctx->bitstream_fifo.kfifo;
-       struct coda_dev *dev = ctx->dev;
-       u32 wr_ptr;
-
-       wr_ptr = ctx->bitstream.paddr + (kfifo->in & kfifo->mask);
-       coda_write(dev, wr_ptr, CODA_REG_BIT_WR_PTR(ctx->reg_idx));
-}
-
-static int coda_bitstream_queue(struct coda_ctx *ctx, struct vb2_buffer *src_buf)
-{
-       u32 src_size = vb2_get_plane_payload(src_buf, 0);
-       u32 n;
-
-       n = kfifo_in(&ctx->bitstream_fifo, vb2_plane_vaddr(src_buf, 0), src_size);
-       if (n < src_size)
-               return -ENOSPC;
-
-       dma_sync_single_for_device(&ctx->dev->plat_dev->dev, ctx->bitstream.paddr,
-                                  ctx->bitstream.size, DMA_TO_DEVICE);
-
-       src_buf->v4l2_buf.sequence = ctx->qsequence++;
-
-       return 0;
-}
-
-static bool coda_bitstream_try_queue(struct coda_ctx *ctx,
-                                    struct vb2_buffer *src_buf)
-{
-       int ret;
-
-       if (coda_get_bitstream_payload(ctx) +
-           vb2_get_plane_payload(src_buf, 0) + 512 >= ctx->bitstream.size)
-               return false;
-
-       if (vb2_plane_vaddr(src_buf, 0) == NULL) {
-               v4l2_err(&ctx->dev->v4l2_dev, "trying to queue empty buffer\n");
-               return true;
-       }
-
-       ret = coda_bitstream_queue(ctx, src_buf);
-       if (ret < 0) {
-               v4l2_err(&ctx->dev->v4l2_dev, "bitstream buffer overflow\n");
-               return false;
-       }
-       /* Sync read pointer to device */
-       if (ctx == v4l2_m2m_get_curr_priv(ctx->dev->m2m_dev))
-               coda_kfifo_sync_to_device_write(ctx);
-
-       ctx->hold = false;
-
-       return true;
-}
-
-static void coda_fill_bitstream(struct coda_ctx *ctx)
-{
-       struct vb2_buffer *src_buf;
-       struct coda_timestamp *ts;
-
-       while (v4l2_m2m_num_src_bufs_ready(ctx->fh.m2m_ctx) > 0) {
-               src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
-
-               if (coda_bitstream_try_queue(ctx, src_buf)) {
-                       /*
-                        * Source buffer is queued in the bitstream ringbuffer;
-                        * queue the timestamp and mark source buffer as done
-                        */
-                       src_buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
-
-                       ts = kmalloc(sizeof(*ts), GFP_KERNEL);
-                       if (ts) {
-                               ts->sequence = src_buf->v4l2_buf.sequence;
-                               ts->timecode = src_buf->v4l2_buf.timecode;
-                               ts->timestamp = src_buf->v4l2_buf.timestamp;
-                               list_add_tail(&ts->list, &ctx->timestamp_list);
-                       }
-
-                       v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_DONE);
-               } else {
-                       break;
-               }
-       }
-}
-
-static void coda_set_gdi_regs(struct coda_ctx *ctx)
-{
-       struct gdi_tiled_map *tiled_map = &ctx->tiled_map;
-       struct coda_dev *dev = ctx->dev;
-       int i;
-
-       for (i = 0; i < 16; i++)
-               coda_write(dev, tiled_map->xy2ca_map[i],
-                               CODA9_GDI_XY2_CAS_0 + 4 * i);
-       for (i = 0; i < 4; i++)
-               coda_write(dev, tiled_map->xy2ba_map[i],
-                               CODA9_GDI_XY2_BA_0 + 4 * i);
-       for (i = 0; i < 16; i++)
-               coda_write(dev, tiled_map->xy2ra_map[i],
-                               CODA9_GDI_XY2_RAS_0 + 4 * i);
-       coda_write(dev, tiled_map->xy2rbc_config, CODA9_GDI_XY2_RBC_CONFIG);
-       for (i = 0; i < 32; i++)
-               coda_write(dev, tiled_map->rbc2axi_map[i],
-                               CODA9_GDI_RBC2_AXI_0 + 4 * i);
-}
-
-/*
- * Mem-to-mem operations.
- */
-static int coda_prepare_decode(struct coda_ctx *ctx)
-{
-       struct vb2_buffer *dst_buf;
-       struct coda_dev *dev = ctx->dev;
-       struct coda_q_data *q_data_dst;
-       u32 stridey, height;
-       u32 picture_y, picture_cb, picture_cr;
-
-       dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
-       q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE);
-
-       if (ctx->params.rot_mode & CODA_ROT_90) {
-               stridey = q_data_dst->height;
-               height = q_data_dst->width;
-       } else {
-               stridey = q_data_dst->width;
-               height = q_data_dst->height;
-       }
-
-       /* Try to copy source buffer contents into the bitstream ringbuffer */
-       mutex_lock(&ctx->bitstream_mutex);
-       coda_fill_bitstream(ctx);
-       mutex_unlock(&ctx->bitstream_mutex);
-
-       if (coda_get_bitstream_payload(ctx) < 512 &&
-           (!(ctx->bit_stream_param & CODA_BIT_STREAM_END_FLAG))) {
-               v4l2_dbg(1, coda_debug, &dev->v4l2_dev,
-                        "bitstream payload: %d, skipping\n",
-                        coda_get_bitstream_payload(ctx));
-               v4l2_m2m_job_finish(ctx->dev->m2m_dev, ctx->fh.m2m_ctx);
-               return -EAGAIN;
-       }
-
-       /* Run coda_start_decoding (again) if not yet initialized */
-       if (!ctx->initialized) {
-               int ret = coda_start_decoding(ctx);
-               if (ret < 0) {
-                       v4l2_err(&dev->v4l2_dev, "failed to start decoding\n");
-                       v4l2_m2m_job_finish(ctx->dev->m2m_dev, ctx->fh.m2m_ctx);
-                       return -EAGAIN;
-               } else {
-                       ctx->initialized = 1;
-               }
-       }
-
-       if (dev->devtype->product == CODA_960)
-               coda_set_gdi_regs(ctx);
-
-       /* Set rotator output */
-       picture_y = vb2_dma_contig_plane_dma_addr(dst_buf, 0);
-       if (q_data_dst->fourcc == V4L2_PIX_FMT_YVU420) {
-               /* Switch Cr and Cb for YVU420 format */
-               picture_cr = picture_y + stridey * height;
-               picture_cb = picture_cr + stridey / 2 * height / 2;
-       } else {
-               picture_cb = picture_y + stridey * height;
-               picture_cr = picture_cb + stridey / 2 * height / 2;
-       }
-
-       if (dev->devtype->product == CODA_960) {
-               /*
-                * The CODA960 seems to have an internal list of buffers with
-                * 64 entries that includes the registered frame buffers as
-                * well as the rotator buffer output.
-                * ROT_INDEX needs to be < 0x40, but > ctx->num_internal_frames.
-                */
-               coda_write(dev, CODA_MAX_FRAMEBUFFERS + dst_buf->v4l2_buf.index,
-                               CODA9_CMD_DEC_PIC_ROT_INDEX);
-               coda_write(dev, picture_y, CODA9_CMD_DEC_PIC_ROT_ADDR_Y);
-               coda_write(dev, picture_cb, CODA9_CMD_DEC_PIC_ROT_ADDR_CB);
-               coda_write(dev, picture_cr, CODA9_CMD_DEC_PIC_ROT_ADDR_CR);
-               coda_write(dev, stridey, CODA9_CMD_DEC_PIC_ROT_STRIDE);
-       } else {
-               coda_write(dev, picture_y, CODA_CMD_DEC_PIC_ROT_ADDR_Y);
-               coda_write(dev, picture_cb, CODA_CMD_DEC_PIC_ROT_ADDR_CB);
-               coda_write(dev, picture_cr, CODA_CMD_DEC_PIC_ROT_ADDR_CR);
-               coda_write(dev, stridey, CODA_CMD_DEC_PIC_ROT_STRIDE);
-       }
-       coda_write(dev, CODA_ROT_MIR_ENABLE | ctx->params.rot_mode,
-                       CODA_CMD_DEC_PIC_ROT_MODE);
-
-       switch (dev->devtype->product) {
-       case CODA_DX6:
-               /* TBD */
-       case CODA_7541:
-               coda_write(dev, CODA_PRE_SCAN_EN, CODA_CMD_DEC_PIC_OPTION);
-               break;
-       case CODA_960:
-               coda_write(dev, (1 << 10), CODA_CMD_DEC_PIC_OPTION); /* 'hardcode to use interrupt disable mode'? */
-               break;
-       }
-
-       coda_write(dev, 0, CODA_CMD_DEC_PIC_SKIP_NUM);
-
-       coda_write(dev, 0, CODA_CMD_DEC_PIC_BB_START);
-       coda_write(dev, 0, CODA_CMD_DEC_PIC_START_BYTE);
-
-       return 0;
-}
-
-static void coda_prepare_encode(struct coda_ctx *ctx)
-{
-       struct coda_q_data *q_data_src, *q_data_dst;
-       struct vb2_buffer *src_buf, *dst_buf;
-       struct coda_dev *dev = ctx->dev;
-       int force_ipicture;
-       int quant_param = 0;
-       u32 picture_y, picture_cb, picture_cr;
-       u32 pic_stream_buffer_addr, pic_stream_buffer_size;
-       u32 dst_fourcc;
-
-       src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
-       dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
-       q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
-       q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE);
-       dst_fourcc = q_data_dst->fourcc;
-
-       src_buf->v4l2_buf.sequence = ctx->osequence;
-       dst_buf->v4l2_buf.sequence = ctx->osequence;
-       ctx->osequence++;
-
-       /*
-        * Workaround coda firmware BUG that only marks the first
-        * frame as IDR. This is a problem for some decoders that can't
-        * recover when a frame is lost.
-        */
-       if (src_buf->v4l2_buf.sequence % ctx->params.gop_size) {
-               src_buf->v4l2_buf.flags |= V4L2_BUF_FLAG_PFRAME;
-               src_buf->v4l2_buf.flags &= ~V4L2_BUF_FLAG_KEYFRAME;
-       } else {
-               src_buf->v4l2_buf.flags |= V4L2_BUF_FLAG_KEYFRAME;
-               src_buf->v4l2_buf.flags &= ~V4L2_BUF_FLAG_PFRAME;
-       }
-
-       if (dev->devtype->product == CODA_960)
-               coda_set_gdi_regs(ctx);
-
-       /*
-        * Copy headers at the beginning of the first frame for H.264 only.
-        * In MPEG4 they are already copied by the coda.
-        */
-       if (src_buf->v4l2_buf.sequence == 0) {
-               pic_stream_buffer_addr =
-                       vb2_dma_contig_plane_dma_addr(dst_buf, 0) +
-                       ctx->vpu_header_size[0] +
-                       ctx->vpu_header_size[1] +
-                       ctx->vpu_header_size[2];
-               pic_stream_buffer_size = CODA_MAX_FRAME_SIZE -
-                       ctx->vpu_header_size[0] -
-                       ctx->vpu_header_size[1] -
-                       ctx->vpu_header_size[2];
-               memcpy(vb2_plane_vaddr(dst_buf, 0),
-                      &ctx->vpu_header[0][0], ctx->vpu_header_size[0]);
-               memcpy(vb2_plane_vaddr(dst_buf, 0) + ctx->vpu_header_size[0],
-                      &ctx->vpu_header[1][0], ctx->vpu_header_size[1]);
-               memcpy(vb2_plane_vaddr(dst_buf, 0) + ctx->vpu_header_size[0] +
-                       ctx->vpu_header_size[1], &ctx->vpu_header[2][0],
-                       ctx->vpu_header_size[2]);
-       } else {
-               pic_stream_buffer_addr =
-                       vb2_dma_contig_plane_dma_addr(dst_buf, 0);
-               pic_stream_buffer_size = CODA_MAX_FRAME_SIZE;
-       }
-
-       if (src_buf->v4l2_buf.flags & V4L2_BUF_FLAG_KEYFRAME) {
-               force_ipicture = 1;
-               switch (dst_fourcc) {
-               case V4L2_PIX_FMT_H264:
-                       quant_param = ctx->params.h264_intra_qp;
-                       break;
-               case V4L2_PIX_FMT_MPEG4:
-                       quant_param = ctx->params.mpeg4_intra_qp;
-                       break;
-               default:
-                       v4l2_warn(&ctx->dev->v4l2_dev,
-                               "cannot set intra qp, fmt not supported\n");
-                       break;
-               }
-       } else {
-               force_ipicture = 0;
-               switch (dst_fourcc) {
-               case V4L2_PIX_FMT_H264:
-                       quant_param = ctx->params.h264_inter_qp;
-                       break;
-               case V4L2_PIX_FMT_MPEG4:
-                       quant_param = ctx->params.mpeg4_inter_qp;
-                       break;
-               default:
-                       v4l2_warn(&ctx->dev->v4l2_dev,
-                               "cannot set inter qp, fmt not supported\n");
-                       break;
-               }
-       }
-
-       /* submit */
-       coda_write(dev, CODA_ROT_MIR_ENABLE | ctx->params.rot_mode, CODA_CMD_ENC_PIC_ROT_MODE);
-       coda_write(dev, quant_param, CODA_CMD_ENC_PIC_QS);
-
-
-       picture_y = vb2_dma_contig_plane_dma_addr(src_buf, 0);
-       switch (q_data_src->fourcc) {
-       case V4L2_PIX_FMT_YVU420:
-               /* Switch Cb and Cr for YVU420 format */
-               picture_cr = picture_y + q_data_src->bytesperline *
-                               q_data_src->height;
-               picture_cb = picture_cr + q_data_src->bytesperline / 2 *
-                               q_data_src->height / 2;
-               break;
-       case V4L2_PIX_FMT_YUV420:
-       default:
-               picture_cb = picture_y + q_data_src->bytesperline *
-                               q_data_src->height;
-               picture_cr = picture_cb + q_data_src->bytesperline / 2 *
-                               q_data_src->height / 2;
-               break;
-       }
-
-       if (dev->devtype->product == CODA_960) {
-               coda_write(dev, 4/*FIXME: 0*/, CODA9_CMD_ENC_PIC_SRC_INDEX);
-               coda_write(dev, q_data_src->width, CODA9_CMD_ENC_PIC_SRC_STRIDE);
-               coda_write(dev, 0, CODA9_CMD_ENC_PIC_SUB_FRAME_SYNC);
-
-               coda_write(dev, picture_y, CODA9_CMD_ENC_PIC_SRC_ADDR_Y);
-               coda_write(dev, picture_cb, CODA9_CMD_ENC_PIC_SRC_ADDR_CB);
-               coda_write(dev, picture_cr, CODA9_CMD_ENC_PIC_SRC_ADDR_CR);
-       } else {
-               coda_write(dev, picture_y, CODA_CMD_ENC_PIC_SRC_ADDR_Y);
-               coda_write(dev, picture_cb, CODA_CMD_ENC_PIC_SRC_ADDR_CB);
-               coda_write(dev, picture_cr, CODA_CMD_ENC_PIC_SRC_ADDR_CR);
-       }
-       coda_write(dev, force_ipicture << 1 & 0x2,
-                  CODA_CMD_ENC_PIC_OPTION);
-
-       coda_write(dev, pic_stream_buffer_addr, CODA_CMD_ENC_PIC_BB_START);
-       coda_write(dev, pic_stream_buffer_size / 1024,
-                  CODA_CMD_ENC_PIC_BB_SIZE);
-
-       if (!ctx->streamon_out) {
-               /* After streamoff on the output side, set the stream end flag */
-               ctx->bit_stream_param |= CODA_BIT_STREAM_END_FLAG;
-               coda_write(dev, ctx->bit_stream_param, CODA_REG_BIT_BIT_STREAM_PARAM);
-       }
-}
-
-static void coda_device_run(void *m2m_priv)
-{
-       struct coda_ctx *ctx = m2m_priv;
-       struct coda_dev *dev = ctx->dev;
-
-       queue_work(dev->workqueue, &ctx->pic_run_work);
-}
-
-static void coda_free_framebuffers(struct coda_ctx *ctx);
-static void coda_free_context_buffers(struct coda_ctx *ctx);
-
-static void coda_seq_end_work(struct work_struct *work)
-{
-       struct coda_ctx *ctx = container_of(work, struct coda_ctx, seq_end_work);
-       struct coda_dev *dev = ctx->dev;
-
-       mutex_lock(&ctx->buffer_mutex);
-       mutex_lock(&dev->coda_mutex);
-
-       v4l2_dbg(1, coda_debug, &dev->v4l2_dev,
-                "%d: %s: sent command 'SEQ_END' to coda\n", ctx->idx, __func__);
-       if (coda_command_sync(ctx, CODA_COMMAND_SEQ_END)) {
-               v4l2_err(&dev->v4l2_dev,
-                        "CODA_COMMAND_SEQ_END failed\n");
-       }
-
-       kfifo_init(&ctx->bitstream_fifo,
-               ctx->bitstream.vaddr, ctx->bitstream.size);
-
-       coda_free_framebuffers(ctx);
-       coda_free_context_buffers(ctx);
-
-       mutex_unlock(&dev->coda_mutex);
-       mutex_unlock(&ctx->buffer_mutex);
-}
-
-static void coda_finish_decode(struct coda_ctx *ctx);
-static void coda_finish_encode(struct coda_ctx *ctx);
-
-static void coda_pic_run_work(struct work_struct *work)
-{
-       struct coda_ctx *ctx = container_of(work, struct coda_ctx, pic_run_work);
-       struct coda_dev *dev = ctx->dev;
-       int ret;
-
-       mutex_lock(&ctx->buffer_mutex);
-       mutex_lock(&dev->coda_mutex);
-
-       if (ctx->inst_type == CODA_INST_DECODER) {
-               ret = coda_prepare_decode(ctx);
-               if (ret < 0) {
-                       mutex_unlock(&dev->coda_mutex);
-                       mutex_unlock(&ctx->buffer_mutex);
-                       /* job_finish scheduled by prepare_decode */
-                       return;
-               }
-       } else {
-               coda_prepare_encode(ctx);
-       }
-
-       if (dev->devtype->product != CODA_DX6)
-               coda_write(dev, ctx->iram_info.axi_sram_use,
-                               CODA7_REG_BIT_AXI_SRAM_USE);
-
-       if (ctx->inst_type == CODA_INST_DECODER)
-               coda_kfifo_sync_to_device_full(ctx);
-       coda_command_async(ctx, CODA_COMMAND_PIC_RUN);
-
-       if (!wait_for_completion_timeout(&ctx->completion, msecs_to_jiffies(1000))) {
-               dev_err(&dev->plat_dev->dev, "CODA PIC_RUN timeout\n");
-
-               ctx->hold = true;
-
-               coda_hw_reset(ctx);
-       } else if (!ctx->aborting) {
-               if (ctx->inst_type == CODA_INST_DECODER)
-                       coda_finish_decode(ctx);
-               else
-                       coda_finish_encode(ctx);
-       }
-
-       if (ctx->aborting || (!ctx->streamon_cap && !ctx->streamon_out))
-               queue_work(dev->workqueue, &ctx->seq_end_work);
-
-       mutex_unlock(&dev->coda_mutex);
-       mutex_unlock(&ctx->buffer_mutex);
-
-       v4l2_m2m_job_finish(ctx->dev->m2m_dev, ctx->fh.m2m_ctx);
-}
-
-static int coda_job_ready(void *m2m_priv)
-{
-       struct coda_ctx *ctx = m2m_priv;
-
-       /*
-        * For both 'P' and 'key' frame cases 1 picture
-        * and 1 frame are needed. In the decoder case,
-        * the compressed frame can be in the bitstream.
-        */
-       if (!v4l2_m2m_num_src_bufs_ready(ctx->fh.m2m_ctx) &&
-           ctx->inst_type != CODA_INST_DECODER) {
-               v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev,
-                        "not ready: not enough video buffers.\n");
-               return 0;
-       }
-
-       if (!v4l2_m2m_num_dst_bufs_ready(ctx->fh.m2m_ctx)) {
-               v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev,
-                        "not ready: not enough video capture buffers.\n");
-               return 0;
-       }
-
-       if (ctx->hold ||
-           ((ctx->inst_type == CODA_INST_DECODER) &&
-            (coda_get_bitstream_payload(ctx) < 512) &&
-            !(ctx->bit_stream_param & CODA_BIT_STREAM_END_FLAG))) {
-               v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev,
-                        "%d: not ready: not enough bitstream data.\n",
-                        ctx->idx);
-               return 0;
-       }
-
-       if (ctx->aborting) {
-               v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev,
-                        "not ready: aborting\n");
-               return 0;
-       }
-
-       v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev,
-                       "job ready\n");
-       return 1;
-}
-
-static void coda_job_abort(void *priv)
-{
-       struct coda_ctx *ctx = priv;
-
-       ctx->aborting = 1;
-
-       v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev,
-                "Aborting task\n");
-}
-
-static void coda_lock(void *m2m_priv)
-{
-       struct coda_ctx *ctx = m2m_priv;
-       struct coda_dev *pcdev = ctx->dev;
-       mutex_lock(&pcdev->dev_mutex);
-}
-
-static void coda_unlock(void *m2m_priv)
-{
-       struct coda_ctx *ctx = m2m_priv;
-       struct coda_dev *pcdev = ctx->dev;
-       mutex_unlock(&pcdev->dev_mutex);
-}
-
-static struct v4l2_m2m_ops coda_m2m_ops = {
-       .device_run     = coda_device_run,
-       .job_ready      = coda_job_ready,
-       .job_abort      = coda_job_abort,
-       .lock           = coda_lock,
-       .unlock         = coda_unlock,
-};
-
-static void coda_set_tiled_map_type(struct coda_ctx *ctx, int tiled_map_type)
-{
-       struct gdi_tiled_map *tiled_map = &ctx->tiled_map;
-       int luma_map, chro_map, i;
-
-       memset(tiled_map, 0, sizeof(*tiled_map));
-
-       luma_map = 64;
-       chro_map = 64;
-       tiled_map->map_type = tiled_map_type;
-       for (i = 0; i < 16; i++)
-               tiled_map->xy2ca_map[i] = luma_map << 8 | chro_map;
-       for (i = 0; i < 4; i++)
-               tiled_map->xy2ba_map[i] = luma_map << 8 | chro_map;
-       for (i = 0; i < 16; i++)
-               tiled_map->xy2ra_map[i] = luma_map << 8 | chro_map;
-
-       if (tiled_map_type == GDI_LINEAR_FRAME_MAP) {
-               tiled_map->xy2rbc_config = 0;
-       } else {
-               dev_err(&ctx->dev->plat_dev->dev, "invalid map type: %d\n",
-                       tiled_map_type);
-               return;
-       }
-}
-
-static void set_default_params(struct coda_ctx *ctx)
-{
-       int max_w;
-       int max_h;
-
-       ctx->codec = &ctx->dev->devtype->codecs[0];
-       max_w = ctx->codec->max_w;
-       max_h = ctx->codec->max_h;
-
-       ctx->params.codec_mode = CODA_MODE_INVALID;
-       ctx->colorspace = V4L2_COLORSPACE_REC709;
-       ctx->params.framerate = 30;
-       ctx->aborting = 0;
-
-       /* Default formats for output and input queues */
-       ctx->q_data[V4L2_M2M_SRC].fourcc = ctx->codec->src_fourcc;
-       ctx->q_data[V4L2_M2M_DST].fourcc = ctx->codec->dst_fourcc;
-       ctx->q_data[V4L2_M2M_SRC].width = max_w;
-       ctx->q_data[V4L2_M2M_SRC].height = max_h;
-       ctx->q_data[V4L2_M2M_SRC].bytesperline = max_w;
-       ctx->q_data[V4L2_M2M_SRC].sizeimage = (max_w * max_h * 3) / 2;
-       ctx->q_data[V4L2_M2M_DST].width = max_w;
-       ctx->q_data[V4L2_M2M_DST].height = max_h;
-       ctx->q_data[V4L2_M2M_DST].bytesperline = 0;
-       ctx->q_data[V4L2_M2M_DST].sizeimage = CODA_MAX_FRAME_SIZE;
-       ctx->q_data[V4L2_M2M_SRC].rect.width = max_w;
-       ctx->q_data[V4L2_M2M_SRC].rect.height = max_h;
-       ctx->q_data[V4L2_M2M_DST].rect.width = max_w;
-       ctx->q_data[V4L2_M2M_DST].rect.height = max_h;
-
-       if (ctx->dev->devtype->product == CODA_960)
-               coda_set_tiled_map_type(ctx, GDI_LINEAR_FRAME_MAP);
-}
-
-/*
- * Queue operations
- */
-static int coda_queue_setup(struct vb2_queue *vq,
-                               const struct v4l2_format *fmt,
-                               unsigned int *nbuffers, unsigned int *nplanes,
-                               unsigned int sizes[], void *alloc_ctxs[])
-{
-       struct coda_ctx *ctx = vb2_get_drv_priv(vq);
-       struct coda_q_data *q_data;
-       unsigned int size;
-
-       q_data = get_q_data(ctx, vq->type);
-       size = q_data->sizeimage;
-
-       *nplanes = 1;
-       sizes[0] = size;
-
-       alloc_ctxs[0] = ctx->dev->alloc_ctx;
-
-       v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev,
-                "get %d buffer(s) of size %d each.\n", *nbuffers, size);
-
-       return 0;
-}
-
-static int coda_buf_prepare(struct vb2_buffer *vb)
-{
-       struct coda_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
-       struct coda_q_data *q_data;
-
-       q_data = get_q_data(ctx, vb->vb2_queue->type);
-
-       if (vb2_plane_size(vb, 0) < q_data->sizeimage) {
-               v4l2_warn(&ctx->dev->v4l2_dev,
-                         "%s data will not fit into plane (%lu < %lu)\n",
-                         __func__, vb2_plane_size(vb, 0),
-                         (long)q_data->sizeimage);
-               return -EINVAL;
-       }
-
-       return 0;
-}
-
-static void coda_buf_queue(struct vb2_buffer *vb)
-{
-       struct coda_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
-       struct coda_dev *dev = ctx->dev;
-       struct coda_q_data *q_data;
-
-       q_data = get_q_data(ctx, vb->vb2_queue->type);
-
-       /*
-        * In the decoder case, immediately try to copy the buffer into the
-        * bitstream ringbuffer and mark it as ready to be dequeued.
-        */
-       if (q_data->fourcc == V4L2_PIX_FMT_H264 &&
-           vb->vb2_queue->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) {
-               /*
-                * For backwards compatibility, queuing an empty buffer marks
-                * the stream end
-                */
-               if (vb2_get_plane_payload(vb, 0) == 0) {
-                       ctx->bit_stream_param |= CODA_BIT_STREAM_END_FLAG;
-                       if ((dev->devtype->product == CODA_960) &&
-                           coda_isbusy(dev) &&
-                           (ctx->idx == coda_read(dev, CODA_REG_BIT_RUN_INDEX))) {
-                               /* if this decoder instance is running, set the stream end flag */
-                               coda_write(dev, ctx->bit_stream_param, CODA_REG_BIT_BIT_STREAM_PARAM);
-                       }
-               }
-               mutex_lock(&ctx->bitstream_mutex);
-               v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vb);
-               coda_fill_bitstream(ctx);
-               mutex_unlock(&ctx->bitstream_mutex);
-       } else {
-               v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vb);
-       }
-}
-
-static void coda_parabuf_write(struct coda_ctx *ctx, int index, u32 value)
-{
-       struct coda_dev *dev = ctx->dev;
-       u32 *p = ctx->parabuf.vaddr;
-
-       if (dev->devtype->product == CODA_DX6)
-               p[index] = value;
-       else
-               p[index ^ 1] = value;
-}
-
-static int coda_alloc_aux_buf(struct coda_dev *dev,
-                             struct coda_aux_buf *buf, size_t size,
-                             const char *name, struct dentry *parent)
-{
-       buf->vaddr = dma_alloc_coherent(&dev->plat_dev->dev, size, &buf->paddr,
-                                       GFP_KERNEL);
-       if (!buf->vaddr)
-               return -ENOMEM;
-
-       buf->size = size;
-
-       if (name && parent) {
-               buf->blob.data = buf->vaddr;
-               buf->blob.size = size;
-               buf->dentry = debugfs_create_blob(name, 0644, parent, &buf->blob);
-               if (!buf->dentry)
-                       dev_warn(&dev->plat_dev->dev,
-                                "failed to create debugfs entry %s\n", name);
-       }
-
-       return 0;
-}
-
-static inline int coda_alloc_context_buf(struct coda_ctx *ctx,
-                                        struct coda_aux_buf *buf, size_t size,
-                                        const char *name)
-{
-       return coda_alloc_aux_buf(ctx->dev, buf, size, name, ctx->debugfs_entry);
-}
-
-static void coda_free_aux_buf(struct coda_dev *dev,
-                             struct coda_aux_buf *buf)
-{
-       if (buf->vaddr) {
-               dma_free_coherent(&dev->plat_dev->dev, buf->size,
-                                 buf->vaddr, buf->paddr);
-               buf->vaddr = NULL;
-               buf->size = 0;
-       }
-       debugfs_remove(buf->dentry);
-}
-
-static void coda_free_framebuffers(struct coda_ctx *ctx)
-{
-       int i;
-
-       for (i = 0; i < CODA_MAX_FRAMEBUFFERS; i++)
-               coda_free_aux_buf(ctx->dev, &ctx->internal_frames[i]);
-}
-
-static int coda_alloc_framebuffers(struct coda_ctx *ctx, struct coda_q_data *q_data, u32 fourcc)
-{
-       struct coda_dev *dev = ctx->dev;
-       int width, height;
-       dma_addr_t paddr;
-       int ysize;
-       int ret;
-       int i;
-
-       if (ctx->codec && (ctx->codec->src_fourcc == V4L2_PIX_FMT_H264 ||
-            ctx->codec->dst_fourcc == V4L2_PIX_FMT_H264)) {
-               width = round_up(q_data->width, 16);
-               height = round_up(q_data->height, 16);
-       } else {
-               width = round_up(q_data->width, 8);
-               height = q_data->height;
-       }
-       ysize = width * height;
-
-       /* Allocate frame buffers */
-       for (i = 0; i < ctx->num_internal_frames; i++) {
-               size_t size;
-               char *name;
-
-               size = ysize + ysize / 2;
-               if (ctx->codec->src_fourcc == V4L2_PIX_FMT_H264 &&
-                   dev->devtype->product != CODA_DX6)
-                       size += ysize / 4;
-               name = kasprintf(GFP_KERNEL, "fb%d", i);
-               ret = coda_alloc_context_buf(ctx, &ctx->internal_frames[i],
-                                            size, name);
-               kfree(name);
-               if (ret < 0) {
-                       coda_free_framebuffers(ctx);
-                       return ret;
-               }
-       }
-
-       /* Register frame buffers in the parameter buffer */
-       for (i = 0; i < ctx->num_internal_frames; i++) {
-               paddr = ctx->internal_frames[i].paddr;
-               coda_parabuf_write(ctx, i * 3 + 0, paddr); /* Y */
-               coda_parabuf_write(ctx, i * 3 + 1, paddr + ysize); /* Cb */
-               coda_parabuf_write(ctx, i * 3 + 2, paddr + ysize + ysize/4); /* Cr */
-
-               /* mvcol buffer for h.264 */
-               if (ctx->codec->src_fourcc == V4L2_PIX_FMT_H264 &&
-                   dev->devtype->product != CODA_DX6)
-                       coda_parabuf_write(ctx, 96 + i,
-                                          ctx->internal_frames[i].paddr +
-                                          ysize + ysize/4 + ysize/4);
-       }
-
-       /* mvcol buffer for mpeg4 */
-       if ((dev->devtype->product != CODA_DX6) &&
-           (ctx->codec->src_fourcc == V4L2_PIX_FMT_MPEG4))
-               coda_parabuf_write(ctx, 97, ctx->internal_frames[i].paddr +
-                                           ysize + ysize/4 + ysize/4);
-
-       return 0;
-}
-
-static int coda_h264_padding(int size, char *p)
-{
-       int nal_size;
-       int diff;
-
-       diff = size - (size & ~0x7);
-       if (diff == 0)
-               return 0;
-
-       nal_size = coda_filler_size[diff];
-       memcpy(p, coda_filler_nal, nal_size);
-
-       /* Add rbsp stop bit and trailing at the end */
-       *(p + nal_size - 1) = 0x80;
-
-       return nal_size;
-}
-
-static phys_addr_t coda_iram_alloc(struct coda_iram_info *iram, size_t size)
-{
-       phys_addr_t ret;
-
-       size = round_up(size, 1024);
-       if (size > iram->remaining)
-               return 0;
-       iram->remaining -= size;
-
-       ret = iram->next_paddr;
-       iram->next_paddr += size;
-
-       return ret;
-}
-
-static void coda_setup_iram(struct coda_ctx *ctx)
-{
-       struct coda_iram_info *iram_info = &ctx->iram_info;
-       struct coda_dev *dev = ctx->dev;
-       int mb_width;
-       int dbk_bits;
-       int bit_bits;
-       int ip_bits;
-
-       memset(iram_info, 0, sizeof(*iram_info));
-       iram_info->next_paddr = dev->iram.paddr;
-       iram_info->remaining = dev->iram.size;
-
-       switch (dev->devtype->product) {
-       case CODA_7541:
-               dbk_bits = CODA7_USE_HOST_DBK_ENABLE | CODA7_USE_DBK_ENABLE;
-               bit_bits = CODA7_USE_HOST_BIT_ENABLE | CODA7_USE_BIT_ENABLE;
-               ip_bits = CODA7_USE_HOST_IP_ENABLE | CODA7_USE_IP_ENABLE;
-               break;
-       case CODA_960:
-               dbk_bits = CODA9_USE_HOST_DBK_ENABLE | CODA9_USE_DBK_ENABLE;
-               bit_bits = CODA9_USE_HOST_BIT_ENABLE | CODA7_USE_BIT_ENABLE;
-               ip_bits = CODA9_USE_HOST_IP_ENABLE | CODA7_USE_IP_ENABLE;
-               break;
-       default: /* CODA_DX6 */
-               return;
-       }
-
-       if (ctx->inst_type == CODA_INST_ENCODER) {
-               struct coda_q_data *q_data_src;
-
-               q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
-               mb_width = DIV_ROUND_UP(q_data_src->width, 16);
-
-               /* Prioritize in case IRAM is too small for everything */
-               if (dev->devtype->product == CODA_7541) {
-                       iram_info->search_ram_size = round_up(mb_width * 16 *
-                                                             36 + 2048, 1024);
-                       iram_info->search_ram_paddr = coda_iram_alloc(iram_info,
-                                                       iram_info->search_ram_size);
-                       if (!iram_info->search_ram_paddr) {
-                               pr_err("IRAM is smaller than the search ram size\n");
-                               goto out;
-                       }
-                       iram_info->axi_sram_use |= CODA7_USE_HOST_ME_ENABLE |
-                                                  CODA7_USE_ME_ENABLE;
-               }
-
-               /* Only H.264BP and H.263P3 are considered */
-               iram_info->buf_dbk_y_use = coda_iram_alloc(iram_info, 64 * mb_width);
-               iram_info->buf_dbk_c_use = coda_iram_alloc(iram_info, 64 * mb_width);
-               if (!iram_info->buf_dbk_c_use)
-                       goto out;
-               iram_info->axi_sram_use |= dbk_bits;
-
-               iram_info->buf_bit_use = coda_iram_alloc(iram_info, 128 * mb_width);
-               if (!iram_info->buf_bit_use)
-                       goto out;
-               iram_info->axi_sram_use |= bit_bits;
-
-               iram_info->buf_ip_ac_dc_use = coda_iram_alloc(iram_info, 128 * mb_width);
-               if (!iram_info->buf_ip_ac_dc_use)
-                       goto out;
-               iram_info->axi_sram_use |= ip_bits;
-
-               /* OVL and BTP disabled for encoder */
-       } else if (ctx->inst_type == CODA_INST_DECODER) {
-               struct coda_q_data *q_data_dst;
-
-               q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE);
-               mb_width = DIV_ROUND_UP(q_data_dst->width, 16);
-
-               iram_info->buf_dbk_y_use = coda_iram_alloc(iram_info, 128 * mb_width);
-               iram_info->buf_dbk_c_use = coda_iram_alloc(iram_info, 128 * mb_width);
-               if (!iram_info->buf_dbk_c_use)
-                       goto out;
-               iram_info->axi_sram_use |= dbk_bits;
-
-               iram_info->buf_bit_use = coda_iram_alloc(iram_info, 128 * mb_width);
-               if (!iram_info->buf_bit_use)
-                       goto out;
-               iram_info->axi_sram_use |= bit_bits;
-
-               iram_info->buf_ip_ac_dc_use = coda_iram_alloc(iram_info, 128 * mb_width);
-               if (!iram_info->buf_ip_ac_dc_use)
-                       goto out;
-               iram_info->axi_sram_use |= ip_bits;
-
-               /* OVL and BTP unused as there is no VC1 support yet */
-       }
-
-out:
-       if (!(iram_info->axi_sram_use & CODA7_USE_HOST_IP_ENABLE))
-               v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev,
-                        "IRAM smaller than needed\n");
-
-       if (dev->devtype->product == CODA_7541) {
-               /* TODO - Enabling these causes picture errors on CODA7541 */
-               if (ctx->inst_type == CODA_INST_DECODER) {
-                       /* fw 1.4.50 */
-                       iram_info->axi_sram_use &= ~(CODA7_USE_HOST_IP_ENABLE |
-                                                    CODA7_USE_IP_ENABLE);
-               } else {
-                       /* fw 13.4.29 */
-                       iram_info->axi_sram_use &= ~(CODA7_USE_HOST_IP_ENABLE |
-                                                    CODA7_USE_HOST_DBK_ENABLE |
-                                                    CODA7_USE_IP_ENABLE |
-                                                    CODA7_USE_DBK_ENABLE);
-               }
-       }
-}
-
-static void coda_free_context_buffers(struct coda_ctx *ctx)
-{
-       struct coda_dev *dev = ctx->dev;
-
-       coda_free_aux_buf(dev, &ctx->slicebuf);
-       coda_free_aux_buf(dev, &ctx->psbuf);
-       if (dev->devtype->product != CODA_DX6)
-               coda_free_aux_buf(dev, &ctx->workbuf);
-}
-
-static int coda_alloc_context_buffers(struct coda_ctx *ctx,
-                                     struct coda_q_data *q_data)
-{
-       struct coda_dev *dev = ctx->dev;
-       size_t size;
-       int ret;
-
-       if (dev->devtype->product == CODA_DX6)
-               return 0;
-
-       if (ctx->psbuf.vaddr) {
-               v4l2_err(&dev->v4l2_dev, "psmembuf still allocated\n");
-               return -EBUSY;
-       }
-       if (ctx->slicebuf.vaddr) {
-               v4l2_err(&dev->v4l2_dev, "slicebuf still allocated\n");
-               return -EBUSY;
-       }
-       if (ctx->workbuf.vaddr) {
-               v4l2_err(&dev->v4l2_dev, "context buffer still allocated\n");
-               ret = -EBUSY;
-               return -ENOMEM;
-       }
-
-       if (q_data->fourcc == V4L2_PIX_FMT_H264) {
-               /* worst case slice size */
-               size = (DIV_ROUND_UP(q_data->width, 16) *
-                       DIV_ROUND_UP(q_data->height, 16)) * 3200 / 8 + 512;
-               ret = coda_alloc_context_buf(ctx, &ctx->slicebuf, size, "slicebuf");
-               if (ret < 0) {
-                       v4l2_err(&dev->v4l2_dev, "failed to allocate %d byte slice buffer",
-                                ctx->slicebuf.size);
-                       return ret;
-               }
-       }
-
-       if (dev->devtype->product == CODA_7541) {
-               ret = coda_alloc_context_buf(ctx, &ctx->psbuf, CODA7_PS_BUF_SIZE, "psbuf");
-               if (ret < 0) {
-                       v4l2_err(&dev->v4l2_dev, "failed to allocate psmem buffer");
-                       goto err;
-               }
-       }
-
-       size = dev->devtype->workbuf_size;
-       if (dev->devtype->product == CODA_960 &&
-           q_data->fourcc == V4L2_PIX_FMT_H264)
-               size += CODA9_PS_SAVE_SIZE;
-       ret = coda_alloc_context_buf(ctx, &ctx->workbuf, size, "workbuf");
-       if (ret < 0) {
-               v4l2_err(&dev->v4l2_dev, "failed to allocate %d byte context buffer",
-                        ctx->workbuf.size);
-               goto err;
-       }
-
-       return 0;
-
-err:
-       coda_free_context_buffers(ctx);
-       return ret;
-}
-
-static int coda_start_decoding(struct coda_ctx *ctx)
-{
-       struct coda_q_data *q_data_src, *q_data_dst;
-       u32 bitstream_buf, bitstream_size;
-       struct coda_dev *dev = ctx->dev;
-       int width, height;
-       u32 src_fourcc;
-       u32 val;
-       int ret;
-
-       /* Start decoding */
-       q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
-       q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE);
-       bitstream_buf = ctx->bitstream.paddr;
-       bitstream_size = ctx->bitstream.size;
-       src_fourcc = q_data_src->fourcc;
-
-       coda_write(dev, ctx->parabuf.paddr, CODA_REG_BIT_PARA_BUF_ADDR);
-
-       /* Update coda bitstream read and write pointers from kfifo */
-       coda_kfifo_sync_to_device_full(ctx);
-
-       ctx->display_idx = -1;
-       ctx->frm_dis_flg = 0;
-       coda_write(dev, 0, CODA_REG_BIT_FRM_DIS_FLG(ctx->reg_idx));
-
-       coda_write(dev, CODA_BIT_DEC_SEQ_INIT_ESCAPE,
-                       CODA_REG_BIT_BIT_STREAM_PARAM);
-
-       coda_write(dev, bitstream_buf, CODA_CMD_DEC_SEQ_BB_START);
-       coda_write(dev, bitstream_size / 1024, CODA_CMD_DEC_SEQ_BB_SIZE);
-       val = 0;
-       if ((dev->devtype->product == CODA_7541) ||
-           (dev->devtype->product == CODA_960))
-               val |= CODA_REORDER_ENABLE;
-       coda_write(dev, val, CODA_CMD_DEC_SEQ_OPTION);
-
-       ctx->params.codec_mode = ctx->codec->mode;
-       if (dev->devtype->product == CODA_960 &&
-           src_fourcc == V4L2_PIX_FMT_MPEG4)
-               ctx->params.codec_mode_aux = CODA_MP4_AUX_MPEG4;
-       else
-               ctx->params.codec_mode_aux = 0;
-       if (src_fourcc == V4L2_PIX_FMT_H264) {
-               if (dev->devtype->product == CODA_7541) {
-                       coda_write(dev, ctx->psbuf.paddr,
-                                       CODA_CMD_DEC_SEQ_PS_BB_START);
-                       coda_write(dev, (CODA7_PS_BUF_SIZE / 1024),
-                                       CODA_CMD_DEC_SEQ_PS_BB_SIZE);
-               }
-               if (dev->devtype->product == CODA_960) {
-                       coda_write(dev, 0, CODA_CMD_DEC_SEQ_X264_MV_EN);
-                       coda_write(dev, 512, CODA_CMD_DEC_SEQ_SPP_CHUNK_SIZE);
-               }
-       }
-       if (dev->devtype->product != CODA_960) {
-               coda_write(dev, 0, CODA_CMD_DEC_SEQ_SRC_SIZE);
-       }
-
-       if (coda_command_sync(ctx, CODA_COMMAND_SEQ_INIT)) {
-               v4l2_err(&dev->v4l2_dev, "CODA_COMMAND_SEQ_INIT timeout\n");
-               coda_write(dev, 0, CODA_REG_BIT_BIT_STREAM_PARAM);
-               return -ETIMEDOUT;
-       }
-
-       /* Update kfifo out pointer from coda bitstream read pointer */
-       coda_kfifo_sync_from_device(ctx);
-
-       coda_write(dev, 0, CODA_REG_BIT_BIT_STREAM_PARAM);
-
-       if (coda_read(dev, CODA_RET_DEC_SEQ_SUCCESS) == 0) {
-               v4l2_err(&dev->v4l2_dev,
-                       "CODA_COMMAND_SEQ_INIT failed, error code = %d\n",
-                       coda_read(dev, CODA_RET_DEC_SEQ_ERR_REASON));
-               return -EAGAIN;
-       }
-
-       val = coda_read(dev, CODA_RET_DEC_SEQ_SRC_SIZE);
-       if (dev->devtype->product == CODA_DX6) {
-               width = (val >> CODADX6_PICWIDTH_OFFSET) & CODADX6_PICWIDTH_MASK;
-               height = val & CODADX6_PICHEIGHT_MASK;
-       } else {
-               width = (val >> CODA7_PICWIDTH_OFFSET) & CODA7_PICWIDTH_MASK;
-               height = val & CODA7_PICHEIGHT_MASK;
-       }
-
-       if (width > q_data_dst->width || height > q_data_dst->height) {
-               v4l2_err(&dev->v4l2_dev, "stream is %dx%d, not %dx%d\n",
-                        width, height, q_data_dst->width, q_data_dst->height);
-               return -EINVAL;
-       }
-
-       width = round_up(width, 16);
-       height = round_up(height, 16);
-
-       v4l2_dbg(1, coda_debug, &dev->v4l2_dev, "%s instance %d now: %dx%d\n",
-                __func__, ctx->idx, width, height);
-
-       ctx->num_internal_frames = coda_read(dev, CODA_RET_DEC_SEQ_FRAME_NEED);
-       if (ctx->num_internal_frames > CODA_MAX_FRAMEBUFFERS) {
-               v4l2_err(&dev->v4l2_dev,
-                        "not enough framebuffers to decode (%d < %d)\n",
-                        CODA_MAX_FRAMEBUFFERS, ctx->num_internal_frames);
-               return -EINVAL;
-       }
-
-       if (src_fourcc == V4L2_PIX_FMT_H264) {
-               u32 left_right;
-               u32 top_bottom;
-
-               left_right = coda_read(dev, CODA_RET_DEC_SEQ_CROP_LEFT_RIGHT);
-               top_bottom = coda_read(dev, CODA_RET_DEC_SEQ_CROP_TOP_BOTTOM);
-
-               q_data_dst->rect.left = (left_right >> 10) & 0x3ff;
-               q_data_dst->rect.top = (top_bottom >> 10) & 0x3ff;
-               q_data_dst->rect.width = width - q_data_dst->rect.left -
-                                        (left_right & 0x3ff);
-               q_data_dst->rect.height = height - q_data_dst->rect.top -
-                                         (top_bottom & 0x3ff);
-       }
-
-       ret = coda_alloc_framebuffers(ctx, q_data_dst, src_fourcc);
-       if (ret < 0)
-               return ret;
-
-       /* Tell the decoder how many frame buffers we allocated. */
-       coda_write(dev, ctx->num_internal_frames, CODA_CMD_SET_FRAME_BUF_NUM);
-       coda_write(dev, width, CODA_CMD_SET_FRAME_BUF_STRIDE);
-
-       if (dev->devtype->product != CODA_DX6) {
-               /* Set secondary AXI IRAM */
-               coda_setup_iram(ctx);
-
-               coda_write(dev, ctx->iram_info.buf_bit_use,
-                               CODA7_CMD_SET_FRAME_AXI_BIT_ADDR);
-               coda_write(dev, ctx->iram_info.buf_ip_ac_dc_use,
-                               CODA7_CMD_SET_FRAME_AXI_IPACDC_ADDR);
-               coda_write(dev, ctx->iram_info.buf_dbk_y_use,
-                               CODA7_CMD_SET_FRAME_AXI_DBKY_ADDR);
-               coda_write(dev, ctx->iram_info.buf_dbk_c_use,
-                               CODA7_CMD_SET_FRAME_AXI_DBKC_ADDR);
-               coda_write(dev, ctx->iram_info.buf_ovl_use,
-                               CODA7_CMD_SET_FRAME_AXI_OVL_ADDR);
-               if (dev->devtype->product == CODA_960)
-                       coda_write(dev, ctx->iram_info.buf_btp_use,
-                                       CODA9_CMD_SET_FRAME_AXI_BTP_ADDR);
-       }
-
-       if (dev->devtype->product == CODA_960) {
-               coda_write(dev, -1, CODA9_CMD_SET_FRAME_DELAY);
-
-               coda_write(dev, 0x20262024, CODA9_CMD_SET_FRAME_CACHE_SIZE);
-               coda_write(dev, 2 << CODA9_CACHE_PAGEMERGE_OFFSET |
-                               32 << CODA9_CACHE_LUMA_BUFFER_SIZE_OFFSET |
-                               8 << CODA9_CACHE_CB_BUFFER_SIZE_OFFSET |
-                               8 << CODA9_CACHE_CR_BUFFER_SIZE_OFFSET,
-                               CODA9_CMD_SET_FRAME_CACHE_CONFIG);
-       }
-
-       if (src_fourcc == V4L2_PIX_FMT_H264) {
-               coda_write(dev, ctx->slicebuf.paddr,
-                               CODA_CMD_SET_FRAME_SLICE_BB_START);
-               coda_write(dev, ctx->slicebuf.size / 1024,
-                               CODA_CMD_SET_FRAME_SLICE_BB_SIZE);
-       }
-
-       if (dev->devtype->product == CODA_7541) {
-               int max_mb_x = 1920 / 16;
-               int max_mb_y = 1088 / 16;
-               int max_mb_num = max_mb_x * max_mb_y;
-
-               coda_write(dev, max_mb_num << 16 | max_mb_x << 8 | max_mb_y,
-                               CODA7_CMD_SET_FRAME_MAX_DEC_SIZE);
-       } else if (dev->devtype->product == CODA_960) {
-               int max_mb_x = 1920 / 16;
-               int max_mb_y = 1088 / 16;
-               int max_mb_num = max_mb_x * max_mb_y;
-
-               coda_write(dev, max_mb_num << 16 | max_mb_x << 8 | max_mb_y,
-                               CODA9_CMD_SET_FRAME_MAX_DEC_SIZE);
-       }
-
-       if (coda_command_sync(ctx, CODA_COMMAND_SET_FRAME_BUF)) {
-               v4l2_err(&ctx->dev->v4l2_dev,
-                        "CODA_COMMAND_SET_FRAME_BUF timeout\n");
-               return -ETIMEDOUT;
-       }
-
-       return 0;
-}
-
-static int coda_encode_header(struct coda_ctx *ctx, struct vb2_buffer *buf,
-                             int header_code, u8 *header, int *size)
-{
-       struct coda_dev *dev = ctx->dev;
-       size_t bufsize;
-       int ret;
-       int i;
-
-       if (dev->devtype->product == CODA_960)
-               memset(vb2_plane_vaddr(buf, 0), 0, 64);
-
-       coda_write(dev, vb2_dma_contig_plane_dma_addr(buf, 0),
-                  CODA_CMD_ENC_HEADER_BB_START);
-       bufsize = vb2_plane_size(buf, 0);
-       if (dev->devtype->product == CODA_960)
-               bufsize /= 1024;
-       coda_write(dev, bufsize, CODA_CMD_ENC_HEADER_BB_SIZE);
-       coda_write(dev, header_code, CODA_CMD_ENC_HEADER_CODE);
-       ret = coda_command_sync(ctx, CODA_COMMAND_ENCODE_HEADER);
-       if (ret < 0) {
-               v4l2_err(&dev->v4l2_dev, "CODA_COMMAND_ENCODE_HEADER timeout\n");
-               return ret;
-       }
-
-       if (dev->devtype->product == CODA_960) {
-               for (i = 63; i > 0; i--)
-                       if (((char *)vb2_plane_vaddr(buf, 0))[i] != 0)
-                               break;
-               *size = i + 1;
-       } else {
-               *size = coda_read(dev, CODA_REG_BIT_WR_PTR(ctx->reg_idx)) -
-                       coda_read(dev, CODA_CMD_ENC_HEADER_BB_START);
-       }
-       memcpy(header, vb2_plane_vaddr(buf, 0), *size);
-
-       return 0;
-}
-
-static int coda_start_encoding(struct coda_ctx *ctx);
-
-static int coda_start_streaming(struct vb2_queue *q, unsigned int count)
-{
-       struct coda_ctx *ctx = vb2_get_drv_priv(q);
-       struct v4l2_device *v4l2_dev = &ctx->dev->v4l2_dev;
-       struct coda_dev *dev = ctx->dev;
-       struct coda_q_data *q_data_src, *q_data_dst;
-       u32 dst_fourcc;
-       int ret = 0;
-
-       q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
-       if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) {
-               if (q_data_src->fourcc == V4L2_PIX_FMT_H264) {
-                       if (coda_get_bitstream_payload(ctx) < 512)
-                               return -EINVAL;
-               } else {
-                       if (count < 1)
-                               return -EINVAL;
-               }
-
-               ctx->streamon_out = 1;
-
-               if (coda_format_is_yuv(q_data_src->fourcc))
-                       ctx->inst_type = CODA_INST_ENCODER;
-               else
-                       ctx->inst_type = CODA_INST_DECODER;
-       } else {
-               if (count < 1)
-                       return -EINVAL;
-
-               ctx->streamon_cap = 1;
-       }
-
-       /* Don't start the coda unless both queues are on */
-       if (!(ctx->streamon_out & ctx->streamon_cap))
-               return 0;
-
-       /* Allow decoder device_run with no new buffers queued */
-       if (ctx->inst_type == CODA_INST_DECODER)
-               v4l2_m2m_set_src_buffered(ctx->fh.m2m_ctx, true);
-
-       ctx->gopcounter = ctx->params.gop_size - 1;
-       q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE);
-       dst_fourcc = q_data_dst->fourcc;
-
-       ctx->codec = coda_find_codec(ctx->dev, q_data_src->fourcc,
-                                    q_data_dst->fourcc);
-       if (!ctx->codec) {
-               v4l2_err(v4l2_dev, "couldn't tell instance type.\n");
-               return -EINVAL;
-       }
-
-       /* Allocate per-instance buffers */
-       ret = coda_alloc_context_buffers(ctx, q_data_src);
-       if (ret < 0)
-               return ret;
-
-       if (ctx->inst_type == CODA_INST_DECODER) {
-               mutex_lock(&dev->coda_mutex);
-               ret = coda_start_decoding(ctx);
-               mutex_unlock(&dev->coda_mutex);
-               if (ret == -EAGAIN)
-                       return 0;
-               else if (ret < 0)
-                       return ret;
-       } else {
-               ret = coda_start_encoding(ctx);
-       }
-
-       ctx->initialized = 1;
-       return ret;
-}
-
-static int coda_start_encoding(struct coda_ctx *ctx)
-{
-       struct coda_dev *dev = ctx->dev;
-       struct v4l2_device *v4l2_dev = &dev->v4l2_dev;
-       struct coda_q_data *q_data_src, *q_data_dst;
-       u32 bitstream_buf, bitstream_size;
-       struct vb2_buffer *buf;
-       int gamma, ret, value;
-       u32 dst_fourcc;
-
-       q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
-       q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE);
-       dst_fourcc = q_data_dst->fourcc;
-
-       buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
-       bitstream_buf = vb2_dma_contig_plane_dma_addr(buf, 0);
-       bitstream_size = q_data_dst->sizeimage;
-
-       if (!coda_is_initialized(dev)) {
-               v4l2_err(v4l2_dev, "coda is not initialized.\n");
-               return -EFAULT;
-       }
-
-       mutex_lock(&dev->coda_mutex);
-
-       coda_write(dev, ctx->parabuf.paddr, CODA_REG_BIT_PARA_BUF_ADDR);
-       coda_write(dev, bitstream_buf, CODA_REG_BIT_RD_PTR(ctx->reg_idx));
-       coda_write(dev, bitstream_buf, CODA_REG_BIT_WR_PTR(ctx->reg_idx));
-       switch (dev->devtype->product) {
-       case CODA_DX6:
-               coda_write(dev, CODADX6_STREAM_BUF_DYNALLOC_EN |
-                       CODADX6_STREAM_BUF_PIC_RESET, CODA_REG_BIT_STREAM_CTRL);
-               break;
-       case CODA_960:
-               coda_write(dev, 0, CODA9_GDI_WPROT_RGN_EN);
-               /* fallthrough */
-       case CODA_7541:
-               coda_write(dev, CODA7_STREAM_BUF_DYNALLOC_EN |
-                       CODA7_STREAM_BUF_PIC_RESET, CODA_REG_BIT_STREAM_CTRL);
-               break;
-       }
-
-       value = coda_read(dev, CODA_REG_BIT_FRAME_MEM_CTRL);
-       value &= ~(1 << 2 | 0x7 << 9);
-       ctx->frame_mem_ctrl = value;
-       coda_write(dev, value, CODA_REG_BIT_FRAME_MEM_CTRL);
-
-       if (dev->devtype->product == CODA_DX6) {
-               /* Configure the coda */
-               coda_write(dev, dev->iram.paddr, CODADX6_REG_BIT_SEARCH_RAM_BASE_ADDR);
-       }
-
-       /* Could set rotation here if needed */
-       switch (dev->devtype->product) {
-       case CODA_DX6:
-               value = (q_data_src->width & CODADX6_PICWIDTH_MASK) << CODADX6_PICWIDTH_OFFSET;
-               value |= (q_data_src->height & CODADX6_PICHEIGHT_MASK) << CODA_PICHEIGHT_OFFSET;
-               break;
-       case CODA_7541:
-               if (dst_fourcc == V4L2_PIX_FMT_H264) {
-                       value = (round_up(q_data_src->width, 16) &
-                                CODA7_PICWIDTH_MASK) << CODA7_PICWIDTH_OFFSET;
-                       value |= (round_up(q_data_src->height, 16) &
-                                 CODA7_PICHEIGHT_MASK) << CODA_PICHEIGHT_OFFSET;
-                       break;
-               }
-               /* fallthrough */
-       case CODA_960:
-               value = (q_data_src->width & CODA7_PICWIDTH_MASK) << CODA7_PICWIDTH_OFFSET;
-               value |= (q_data_src->height & CODA7_PICHEIGHT_MASK) << CODA_PICHEIGHT_OFFSET;
-       }
-       coda_write(dev, value, CODA_CMD_ENC_SEQ_SRC_SIZE);
-       coda_write(dev, ctx->params.framerate,
-                  CODA_CMD_ENC_SEQ_SRC_F_RATE);
-
-       ctx->params.codec_mode = ctx->codec->mode;
-       switch (dst_fourcc) {
-       case V4L2_PIX_FMT_MPEG4:
-               if (dev->devtype->product == CODA_960)
-                       coda_write(dev, CODA9_STD_MPEG4, CODA_CMD_ENC_SEQ_COD_STD);
-               else
-                       coda_write(dev, CODA_STD_MPEG4, CODA_CMD_ENC_SEQ_COD_STD);
-               coda_write(dev, 0, CODA_CMD_ENC_SEQ_MP4_PARA);
-               break;
-       case V4L2_PIX_FMT_H264:
-               if (dev->devtype->product == CODA_960)
-                       coda_write(dev, CODA9_STD_H264, CODA_CMD_ENC_SEQ_COD_STD);
-               else
-                       coda_write(dev, CODA_STD_H264, CODA_CMD_ENC_SEQ_COD_STD);
-               if (ctx->params.h264_deblk_enabled) {
-                       value = ((ctx->params.h264_deblk_alpha &
-                                 CODA_264PARAM_DEBLKFILTEROFFSETALPHA_MASK) <<
-                                CODA_264PARAM_DEBLKFILTEROFFSETALPHA_OFFSET) |
-                               ((ctx->params.h264_deblk_beta &
-                                 CODA_264PARAM_DEBLKFILTEROFFSETBETA_MASK) <<
-                                CODA_264PARAM_DEBLKFILTEROFFSETBETA_OFFSET);
-               } else {
-                       value = 1 << CODA_264PARAM_DISABLEDEBLK_OFFSET;
-               }
-               coda_write(dev, value, CODA_CMD_ENC_SEQ_264_PARA);
-               break;
-       default:
-               v4l2_err(v4l2_dev,
-                        "dst format (0x%08x) invalid.\n", dst_fourcc);
-               ret = -EINVAL;
-               goto out;
-       }
-
-       switch (ctx->params.slice_mode) {
-       case V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE:
-               value = 0;
-               break;
-       case V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_MB:
-               value  = (ctx->params.slice_max_mb & CODA_SLICING_SIZE_MASK) << CODA_SLICING_SIZE_OFFSET;
-               value |= (1 & CODA_SLICING_UNIT_MASK) << CODA_SLICING_UNIT_OFFSET;
-               value |=  1 & CODA_SLICING_MODE_MASK;
-               break;
-       case V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_BYTES:
-               value  = (ctx->params.slice_max_bits & CODA_SLICING_SIZE_MASK) << CODA_SLICING_SIZE_OFFSET;
-               value |= (0 & CODA_SLICING_UNIT_MASK) << CODA_SLICING_UNIT_OFFSET;
-               value |=  1 & CODA_SLICING_MODE_MASK;
-               break;
-       }
-       coda_write(dev, value, CODA_CMD_ENC_SEQ_SLICE_MODE);
-       value = ctx->params.gop_size & CODA_GOP_SIZE_MASK;
-       coda_write(dev, value, CODA_CMD_ENC_SEQ_GOP_SIZE);
-
-       if (ctx->params.bitrate) {
-               /* Rate control enabled */
-               value = (ctx->params.bitrate & CODA_RATECONTROL_BITRATE_MASK) << CODA_RATECONTROL_BITRATE_OFFSET;
-               value |=  1 & CODA_RATECONTROL_ENABLE_MASK;
-               if (dev->devtype->product == CODA_960)
-                       value |= BIT(31); /* disable autoskip */
-       } else {
-               value = 0;
-       }
-       coda_write(dev, value, CODA_CMD_ENC_SEQ_RC_PARA);
-
-       coda_write(dev, 0, CODA_CMD_ENC_SEQ_RC_BUF_SIZE);
-       coda_write(dev, ctx->params.intra_refresh,
-                  CODA_CMD_ENC_SEQ_INTRA_REFRESH);
-
-       coda_write(dev, bitstream_buf, CODA_CMD_ENC_SEQ_BB_START);
-       coda_write(dev, bitstream_size / 1024, CODA_CMD_ENC_SEQ_BB_SIZE);
-
-
-       value = 0;
-       if (dev->devtype->product == CODA_960)
-               gamma = CODA9_DEFAULT_GAMMA;
-       else
-               gamma = CODA_DEFAULT_GAMMA;
-       if (gamma > 0) {
-               coda_write(dev, (gamma & CODA_GAMMA_MASK) << CODA_GAMMA_OFFSET,
-                          CODA_CMD_ENC_SEQ_RC_GAMMA);
-       }
-
-       if (ctx->params.h264_min_qp || ctx->params.h264_max_qp) {
-               coda_write(dev,
-                          ctx->params.h264_min_qp << CODA_QPMIN_OFFSET |
-                          ctx->params.h264_max_qp << CODA_QPMAX_OFFSET,
-                          CODA_CMD_ENC_SEQ_RC_QP_MIN_MAX);
-       }
-       if (dev->devtype->product == CODA_960) {
-               if (ctx->params.h264_max_qp)
-                       value |= 1 << CODA9_OPTION_RCQPMAX_OFFSET;
-               if (CODA_DEFAULT_GAMMA > 0)
-                       value |= 1 << CODA9_OPTION_GAMMA_OFFSET;
-       } else {
-               if (CODA_DEFAULT_GAMMA > 0) {
-                       if (dev->devtype->product == CODA_DX6)
-                               value |= 1 << CODADX6_OPTION_GAMMA_OFFSET;
-                       else
-                               value |= 1 << CODA7_OPTION_GAMMA_OFFSET;
-               }
-               if (ctx->params.h264_min_qp)
-                       value |= 1 << CODA7_OPTION_RCQPMIN_OFFSET;
-               if (ctx->params.h264_max_qp)
-                       value |= 1 << CODA7_OPTION_RCQPMAX_OFFSET;
-       }
-       coda_write(dev, value, CODA_CMD_ENC_SEQ_OPTION);
-
-       coda_write(dev, 0, CODA_CMD_ENC_SEQ_RC_INTERVAL_MODE);
-
-       coda_setup_iram(ctx);
-
-       if (dst_fourcc == V4L2_PIX_FMT_H264) {
-               switch (dev->devtype->product) {
-               case CODA_DX6:
-                       value = FMO_SLICE_SAVE_BUF_SIZE << 7;
-                       coda_write(dev, value, CODADX6_CMD_ENC_SEQ_FMO);
-                       break;
-               case CODA_7541:
-                       coda_write(dev, ctx->iram_info.search_ram_paddr,
-                                       CODA7_CMD_ENC_SEQ_SEARCH_BASE);
-                       coda_write(dev, ctx->iram_info.search_ram_size,
-                                       CODA7_CMD_ENC_SEQ_SEARCH_SIZE);
-                       break;
-               case CODA_960:
-                       coda_write(dev, 0, CODA9_CMD_ENC_SEQ_ME_OPTION);
-                       coda_write(dev, 0, CODA9_CMD_ENC_SEQ_INTRA_WEIGHT);
-               }
-       }
-
-       ret = coda_command_sync(ctx, CODA_COMMAND_SEQ_INIT);
-       if (ret < 0) {
-               v4l2_err(v4l2_dev, "CODA_COMMAND_SEQ_INIT timeout\n");
-               goto out;
-       }
-
-       if (coda_read(dev, CODA_RET_ENC_SEQ_SUCCESS) == 0) {
-               v4l2_err(v4l2_dev, "CODA_COMMAND_SEQ_INIT failed\n");
-               ret = -EFAULT;
-               goto out;
-       }
-
-       if (dev->devtype->product == CODA_960)
-               ctx->num_internal_frames = 4;
-       else
-               ctx->num_internal_frames = 2;
-       ret = coda_alloc_framebuffers(ctx, q_data_src, dst_fourcc);
-       if (ret < 0) {
-               v4l2_err(v4l2_dev, "failed to allocate framebuffers\n");
-               goto out;
-       }
-
-       coda_write(dev, ctx->num_internal_frames, CODA_CMD_SET_FRAME_BUF_NUM);
-       coda_write(dev, q_data_src->bytesperline,
-                       CODA_CMD_SET_FRAME_BUF_STRIDE);
-       if (dev->devtype->product == CODA_7541) {
-               coda_write(dev, q_data_src->bytesperline,
-                               CODA7_CMD_SET_FRAME_SOURCE_BUF_STRIDE);
-       }
-       if (dev->devtype->product != CODA_DX6) {
-               coda_write(dev, ctx->iram_info.buf_bit_use,
-                               CODA7_CMD_SET_FRAME_AXI_BIT_ADDR);
-               coda_write(dev, ctx->iram_info.buf_ip_ac_dc_use,
-                               CODA7_CMD_SET_FRAME_AXI_IPACDC_ADDR);
-               coda_write(dev, ctx->iram_info.buf_dbk_y_use,
-                               CODA7_CMD_SET_FRAME_AXI_DBKY_ADDR);
-               coda_write(dev, ctx->iram_info.buf_dbk_c_use,
-                               CODA7_CMD_SET_FRAME_AXI_DBKC_ADDR);
-               coda_write(dev, ctx->iram_info.buf_ovl_use,
-                               CODA7_CMD_SET_FRAME_AXI_OVL_ADDR);
-               if (dev->devtype->product == CODA_960) {
-                       coda_write(dev, ctx->iram_info.buf_btp_use,
-                                       CODA9_CMD_SET_FRAME_AXI_BTP_ADDR);
-
-                       /* FIXME */
-                       coda_write(dev, ctx->internal_frames[2].paddr, CODA9_CMD_SET_FRAME_SUBSAMP_A);
-                       coda_write(dev, ctx->internal_frames[3].paddr, CODA9_CMD_SET_FRAME_SUBSAMP_B);
-               }
-       }
-
-       ret = coda_command_sync(ctx, CODA_COMMAND_SET_FRAME_BUF);
-       if (ret < 0) {
-               v4l2_err(v4l2_dev, "CODA_COMMAND_SET_FRAME_BUF timeout\n");
-               goto out;
-       }
-
-       /* Save stream headers */
-       buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
-       switch (dst_fourcc) {
-       case V4L2_PIX_FMT_H264:
-               /*
-                * Get SPS in the first frame and copy it to an
-                * intermediate buffer.
-                */
-               ret = coda_encode_header(ctx, buf, CODA_HEADER_H264_SPS,
-                                        &ctx->vpu_header[0][0],
-                                        &ctx->vpu_header_size[0]);
-               if (ret < 0)
-                       goto out;
-
-               /*
-                * Get PPS in the first frame and copy it to an
-                * intermediate buffer.
-                */
-               ret = coda_encode_header(ctx, buf, CODA_HEADER_H264_PPS,
-                                        &ctx->vpu_header[1][0],
-                                        &ctx->vpu_header_size[1]);
-               if (ret < 0)
-                       goto out;
-
-               /*
-                * Length of H.264 headers is variable and thus it might not be
-                * aligned for the coda to append the encoded frame. In that is
-                * the case a filler NAL must be added to header 2.
-                */
-               ctx->vpu_header_size[2] = coda_h264_padding(
-                                       (ctx->vpu_header_size[0] +
-                                        ctx->vpu_header_size[1]),
-                                        ctx->vpu_header[2]);
-               break;
-       case V4L2_PIX_FMT_MPEG4:
-               /*
-                * Get VOS in the first frame and copy it to an
-                * intermediate buffer
-                */
-               ret = coda_encode_header(ctx, buf, CODA_HEADER_MP4V_VOS,
-                                        &ctx->vpu_header[0][0],
-                                        &ctx->vpu_header_size[0]);
-               if (ret < 0)
-                       goto out;
-
-               ret = coda_encode_header(ctx, buf, CODA_HEADER_MP4V_VIS,
-                                        &ctx->vpu_header[1][0],
-                                        &ctx->vpu_header_size[1]);
-               if (ret < 0)
-                       goto out;
-
-               ret = coda_encode_header(ctx, buf, CODA_HEADER_MP4V_VOL,
-                                        &ctx->vpu_header[2][0],
-                                        &ctx->vpu_header_size[2]);
-               if (ret < 0)
-                       goto out;
-               break;
-       default:
-               /* No more formats need to save headers at the moment */
-               break;
-       }
-
-out:
-       mutex_unlock(&dev->coda_mutex);
-       return ret;
-}
-
-static void coda_stop_streaming(struct vb2_queue *q)
-{
-       struct coda_ctx *ctx = vb2_get_drv_priv(q);
-       struct coda_dev *dev = ctx->dev;
-
-       if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) {
-               v4l2_dbg(1, coda_debug, &dev->v4l2_dev,
-                        "%s: output\n", __func__);
-               ctx->streamon_out = 0;
-
-               if (ctx->inst_type == CODA_INST_DECODER &&
-                   coda_isbusy(dev) && ctx->idx == coda_read(dev, CODA_REG_BIT_RUN_INDEX)) {
-                       /* if this decoder instance is running, set the stream end flag */
-                       if (dev->devtype->product == CODA_960) {
-                               u32 val = coda_read(dev, CODA_REG_BIT_BIT_STREAM_PARAM);
-
-                               val |= CODA_BIT_STREAM_END_FLAG;
-                               coda_write(dev, val, CODA_REG_BIT_BIT_STREAM_PARAM);
-                               ctx->bit_stream_param = val;
-                       }
-               }
-               ctx->bit_stream_param |= CODA_BIT_STREAM_END_FLAG;
-
-               ctx->isequence = 0;
-       } else {
-               v4l2_dbg(1, coda_debug, &dev->v4l2_dev,
-                        "%s: capture\n", __func__);
-               ctx->streamon_cap = 0;
-
-               ctx->osequence = 0;
-               ctx->sequence_offset = 0;
-       }
-
-       if (!ctx->streamon_out && !ctx->streamon_cap) {
-               struct coda_timestamp *ts;
-
-               while (!list_empty(&ctx->timestamp_list)) {
-                       ts = list_first_entry(&ctx->timestamp_list,
-                                             struct coda_timestamp, list);
-                       list_del(&ts->list);
-                       kfree(ts);
-               }
-               kfifo_init(&ctx->bitstream_fifo,
-                       ctx->bitstream.vaddr, ctx->bitstream.size);
-               ctx->runcounter = 0;
-       }
-}
-
-static struct vb2_ops coda_qops = {
-       .queue_setup            = coda_queue_setup,
-       .buf_prepare            = coda_buf_prepare,
-       .buf_queue              = coda_buf_queue,
-       .start_streaming        = coda_start_streaming,
-       .stop_streaming         = coda_stop_streaming,
-       .wait_prepare           = vb2_ops_wait_prepare,
-       .wait_finish            = vb2_ops_wait_finish,
-};
-
-static int coda_s_ctrl(struct v4l2_ctrl *ctrl)
-{
-       struct coda_ctx *ctx =
-                       container_of(ctrl->handler, struct coda_ctx, ctrls);
-
-       v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev,
-                "s_ctrl: id = %d, val = %d\n", ctrl->id, ctrl->val);
-
-       switch (ctrl->id) {
-       case V4L2_CID_HFLIP:
-               if (ctrl->val)
-                       ctx->params.rot_mode |= CODA_MIR_HOR;
-               else
-                       ctx->params.rot_mode &= ~CODA_MIR_HOR;
-               break;
-       case V4L2_CID_VFLIP:
-               if (ctrl->val)
-                       ctx->params.rot_mode |= CODA_MIR_VER;
-               else
-                       ctx->params.rot_mode &= ~CODA_MIR_VER;
-               break;
-       case V4L2_CID_MPEG_VIDEO_BITRATE:
-               ctx->params.bitrate = ctrl->val / 1000;
-               break;
-       case V4L2_CID_MPEG_VIDEO_GOP_SIZE:
-               ctx->params.gop_size = ctrl->val;
-               break;
-       case V4L2_CID_MPEG_VIDEO_H264_I_FRAME_QP:
-               ctx->params.h264_intra_qp = ctrl->val;
-               break;
-       case V4L2_CID_MPEG_VIDEO_H264_P_FRAME_QP:
-               ctx->params.h264_inter_qp = ctrl->val;
-               break;
-       case V4L2_CID_MPEG_VIDEO_H264_MIN_QP:
-               ctx->params.h264_min_qp = ctrl->val;
-               break;
-       case V4L2_CID_MPEG_VIDEO_H264_MAX_QP:
-               ctx->params.h264_max_qp = ctrl->val;
-               break;
-       case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_ALPHA:
-               ctx->params.h264_deblk_alpha = ctrl->val;
-               break;
-       case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_BETA:
-               ctx->params.h264_deblk_beta = ctrl->val;
-               break;
-       case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE:
-               ctx->params.h264_deblk_enabled = (ctrl->val ==
-                               V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_ENABLED);
-               break;
-       case V4L2_CID_MPEG_VIDEO_MPEG4_I_FRAME_QP:
-               ctx->params.mpeg4_intra_qp = ctrl->val;
-               break;
-       case V4L2_CID_MPEG_VIDEO_MPEG4_P_FRAME_QP:
-               ctx->params.mpeg4_inter_qp = ctrl->val;
-               break;
-       case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE:
-               ctx->params.slice_mode = ctrl->val;
-               break;
-       case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_MB:
-               ctx->params.slice_max_mb = ctrl->val;
-               break;
-       case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_BYTES:
-               ctx->params.slice_max_bits = ctrl->val * 8;
-               break;
-       case V4L2_CID_MPEG_VIDEO_HEADER_MODE:
-               break;
-       case V4L2_CID_MPEG_VIDEO_CYCLIC_INTRA_REFRESH_MB:
-               ctx->params.intra_refresh = ctrl->val;
-               break;
-       default:
-               v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev,
-                       "Invalid control, id=%d, val=%d\n",
-                       ctrl->id, ctrl->val);
-               return -EINVAL;
-       }
-
-       return 0;
-}
-
-static struct v4l2_ctrl_ops coda_ctrl_ops = {
-       .s_ctrl = coda_s_ctrl,
-};
-
-static int coda_ctrls_setup(struct coda_ctx *ctx)
-{
-       v4l2_ctrl_handler_init(&ctx->ctrls, 9);
-
-       v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops,
-               V4L2_CID_HFLIP, 0, 1, 1, 0);
-       v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops,
-               V4L2_CID_VFLIP, 0, 1, 1, 0);
-       v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops,
-               V4L2_CID_MPEG_VIDEO_BITRATE, 0, 32767000, 1, 0);
-       v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops,
-               V4L2_CID_MPEG_VIDEO_GOP_SIZE, 1, 60, 1, 16);
-       v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops,
-               V4L2_CID_MPEG_VIDEO_H264_I_FRAME_QP, 0, 51, 1, 25);
-       v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops,
-               V4L2_CID_MPEG_VIDEO_H264_P_FRAME_QP, 0, 51, 1, 25);
-       if (ctx->dev->devtype->product != CODA_960) {
-               v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops,
-                       V4L2_CID_MPEG_VIDEO_H264_MIN_QP, 0, 51, 1, 12);
-       }
-       v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops,
-               V4L2_CID_MPEG_VIDEO_H264_MAX_QP, 0, 51, 1, 51);
-       v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops,
-               V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_ALPHA, 0, 15, 1, 0);
-       v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops,
-               V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_BETA, 0, 15, 1, 0);
-       v4l2_ctrl_new_std_menu(&ctx->ctrls, &coda_ctrl_ops,
-               V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE,
-               V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_DISABLED, 0x0,
-               V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_ENABLED);
-       v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops,
-               V4L2_CID_MPEG_VIDEO_MPEG4_I_FRAME_QP, 1, 31, 1, 2);
-       v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops,
-               V4L2_CID_MPEG_VIDEO_MPEG4_P_FRAME_QP, 1, 31, 1, 2);
-       v4l2_ctrl_new_std_menu(&ctx->ctrls, &coda_ctrl_ops,
-               V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE,
-               V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_BYTES, 0x0,
-               V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE);
-       v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops,
-               V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_MB, 1, 0x3fffffff, 1, 1);
-       v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops,
-               V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_BYTES, 1, 0x3fffffff, 1, 500);
-       v4l2_ctrl_new_std_menu(&ctx->ctrls, &coda_ctrl_ops,
-               V4L2_CID_MPEG_VIDEO_HEADER_MODE,
-               V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_1ST_FRAME,
-               (1 << V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE),
-               V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_1ST_FRAME);
-       v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops,
-               V4L2_CID_MPEG_VIDEO_CYCLIC_INTRA_REFRESH_MB, 0, 1920 * 1088 / 256, 1, 0);
-
-       if (ctx->ctrls.error) {
-               v4l2_err(&ctx->dev->v4l2_dev, "control initialization error (%d)",
-                       ctx->ctrls.error);
-               return -EINVAL;
-       }
-
-       return v4l2_ctrl_handler_setup(&ctx->ctrls);
-}
-
-static int coda_queue_init(void *priv, struct vb2_queue *src_vq,
-                     struct vb2_queue *dst_vq)
-{
-       struct coda_ctx *ctx = priv;
-       int ret;
-
-       src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
-       src_vq->io_modes = VB2_DMABUF | VB2_MMAP | VB2_USERPTR;
-       src_vq->drv_priv = ctx;
-       src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
-       src_vq->ops = &coda_qops;
-       src_vq->mem_ops = &vb2_dma_contig_memops;
-       src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
-       src_vq->lock = &ctx->dev->dev_mutex;
-
-       ret = vb2_queue_init(src_vq);
-       if (ret)
-               return ret;
-
-       dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-       dst_vq->io_modes = VB2_DMABUF | VB2_MMAP | VB2_USERPTR;
-       dst_vq->drv_priv = ctx;
-       dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
-       dst_vq->ops = &coda_qops;
-       dst_vq->mem_ops = &vb2_dma_contig_memops;
-       dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
-       dst_vq->lock = &ctx->dev->dev_mutex;
-
-       return vb2_queue_init(dst_vq);
-}
-
-static int coda_next_free_instance(struct coda_dev *dev)
-{
-       int idx = ffz(dev->instance_mask);
-
-       if ((idx < 0) ||
-           (dev->devtype->product == CODA_DX6 && idx > CODADX6_MAX_INSTANCES))
-               return -EBUSY;
-
-       return idx;
-}
-
-static int coda_open(struct file *file)
-{
-       struct coda_dev *dev = video_drvdata(file);
-       struct coda_ctx *ctx = NULL;
-       char *name;
-       int ret;
-       int idx;
-
-       ctx = kzalloc(sizeof *ctx, GFP_KERNEL);
-       if (!ctx)
-               return -ENOMEM;
-
-       idx = coda_next_free_instance(dev);
-       if (idx < 0) {
-               ret = idx;
-               goto err_coda_max;
-       }
-       set_bit(idx, &dev->instance_mask);
-
-       name = kasprintf(GFP_KERNEL, "context%d", idx);
-       ctx->debugfs_entry = debugfs_create_dir(name, dev->debugfs_root);
-       kfree(name);
-
-       init_completion(&ctx->completion);
-       INIT_WORK(&ctx->pic_run_work, coda_pic_run_work);
-       INIT_WORK(&ctx->seq_end_work, coda_seq_end_work);
-       v4l2_fh_init(&ctx->fh, video_devdata(file));
-       file->private_data = &ctx->fh;
-       v4l2_fh_add(&ctx->fh);
-       ctx->dev = dev;
-       ctx->idx = idx;
-       switch (dev->devtype->product) {
-       case CODA_7541:
-       case CODA_960:
-               ctx->reg_idx = 0;
-               break;
-       default:
-               ctx->reg_idx = idx;
-       }
-
-       /* Power up and upload firmware if necessary */
-       ret = pm_runtime_get_sync(&dev->plat_dev->dev);
-       if (ret < 0) {
-               v4l2_err(&dev->v4l2_dev, "failed to power up: %d\n", ret);
-               goto err_pm_get;
-       }
-
-       ret = clk_prepare_enable(dev->clk_per);
-       if (ret)
-               goto err_clk_per;
-
-       ret = clk_prepare_enable(dev->clk_ahb);
-       if (ret)
-               goto err_clk_ahb;
-
-       set_default_params(ctx);
-       ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(dev->m2m_dev, ctx,
-                                        &coda_queue_init);
-       if (IS_ERR(ctx->fh.m2m_ctx)) {
-               ret = PTR_ERR(ctx->fh.m2m_ctx);
-
-               v4l2_err(&dev->v4l2_dev, "%s return error (%d)\n",
-                        __func__, ret);
-               goto err_ctx_init;
-       }
-
-       ret = coda_ctrls_setup(ctx);
-       if (ret) {
-               v4l2_err(&dev->v4l2_dev, "failed to setup coda controls\n");
-               goto err_ctrls_setup;
-       }
-
-       ctx->fh.ctrl_handler = &ctx->ctrls;
-
-       ret = coda_alloc_context_buf(ctx, &ctx->parabuf, CODA_PARA_BUF_SIZE,
-                                    "parabuf");
-       if (ret < 0) {
-               v4l2_err(&dev->v4l2_dev, "failed to allocate parabuf");
-               goto err_dma_alloc;
-       }
-
-       ctx->bitstream.size = CODA_MAX_FRAME_SIZE;
-       ctx->bitstream.vaddr = dma_alloc_writecombine(&dev->plat_dev->dev,
-                       ctx->bitstream.size, &ctx->bitstream.paddr, GFP_KERNEL);
-       if (!ctx->bitstream.vaddr) {
-               v4l2_err(&dev->v4l2_dev, "failed to allocate bitstream ringbuffer");
-               ret = -ENOMEM;
-               goto err_dma_writecombine;
-       }
-       kfifo_init(&ctx->bitstream_fifo,
-               ctx->bitstream.vaddr, ctx->bitstream.size);
-       mutex_init(&ctx->bitstream_mutex);
-       mutex_init(&ctx->buffer_mutex);
-       INIT_LIST_HEAD(&ctx->timestamp_list);
-
-       coda_lock(ctx);
-       list_add(&ctx->list, &dev->instances);
-       coda_unlock(ctx);
-
-       v4l2_dbg(1, coda_debug, &dev->v4l2_dev, "Created instance %d (%p)\n",
-                ctx->idx, ctx);
-
-       return 0;
-
-err_dma_writecombine:
-       coda_free_context_buffers(ctx);
-       if (ctx->dev->devtype->product == CODA_DX6)
-               coda_free_aux_buf(dev, &ctx->workbuf);
-       coda_free_aux_buf(dev, &ctx->parabuf);
-err_dma_alloc:
-       v4l2_ctrl_handler_free(&ctx->ctrls);
-err_ctrls_setup:
-       v4l2_m2m_ctx_release(ctx->fh.m2m_ctx);
-err_ctx_init:
-       clk_disable_unprepare(dev->clk_ahb);
-err_clk_ahb:
-       clk_disable_unprepare(dev->clk_per);
-err_clk_per:
-       pm_runtime_put_sync(&dev->plat_dev->dev);
-err_pm_get:
-       v4l2_fh_del(&ctx->fh);
-       v4l2_fh_exit(&ctx->fh);
-       clear_bit(ctx->idx, &dev->instance_mask);
-err_coda_max:
-       kfree(ctx);
-       return ret;
-}
-
-static int coda_release(struct file *file)
-{
-       struct coda_dev *dev = video_drvdata(file);
-       struct coda_ctx *ctx = fh_to_ctx(file->private_data);
-
-       v4l2_dbg(1, coda_debug, &dev->v4l2_dev, "Releasing instance %p\n",
-                ctx);
-
-       debugfs_remove_recursive(ctx->debugfs_entry);
-
-       /* If this instance is running, call .job_abort and wait for it to end */
-       v4l2_m2m_ctx_release(ctx->fh.m2m_ctx);
-
-       /* In case the instance was not running, we still need to call SEQ_END */
-       if (ctx->initialized) {
-               queue_work(dev->workqueue, &ctx->seq_end_work);
-               flush_work(&ctx->seq_end_work);
-       }
-
-       coda_free_framebuffers(ctx);
-
-       coda_lock(ctx);
-       list_del(&ctx->list);
-       coda_unlock(ctx);
-
-       dma_free_writecombine(&dev->plat_dev->dev, ctx->bitstream.size,
-               ctx->bitstream.vaddr, ctx->bitstream.paddr);
-       coda_free_context_buffers(ctx);
-       if (ctx->dev->devtype->product == CODA_DX6)
-               coda_free_aux_buf(dev, &ctx->workbuf);
-
-       coda_free_aux_buf(dev, &ctx->parabuf);
-       v4l2_ctrl_handler_free(&ctx->ctrls);
-       clk_disable_unprepare(dev->clk_ahb);
-       clk_disable_unprepare(dev->clk_per);
-       pm_runtime_put_sync(&dev->plat_dev->dev);
-       v4l2_fh_del(&ctx->fh);
-       v4l2_fh_exit(&ctx->fh);
-       clear_bit(ctx->idx, &dev->instance_mask);
-       kfree(ctx);
-
-       return 0;
-}
-
-static const struct v4l2_file_operations coda_fops = {
-       .owner          = THIS_MODULE,
-       .open           = coda_open,
-       .release        = coda_release,
-       .poll           = v4l2_m2m_fop_poll,
-       .unlocked_ioctl = video_ioctl2,
-       .mmap           = v4l2_m2m_fop_mmap,
-};
-
-static void coda_finish_decode(struct coda_ctx *ctx)
-{
-       struct coda_dev *dev = ctx->dev;
-       struct coda_q_data *q_data_src;
-       struct coda_q_data *q_data_dst;
-       struct vb2_buffer *dst_buf;
-       struct coda_timestamp *ts;
-       int width, height;
-       int decoded_idx;
-       int display_idx;
-       u32 src_fourcc;
-       int success;
-       u32 err_mb;
-       u32 val;
-
-       dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
-
-       /* Update kfifo out pointer from coda bitstream read pointer */
-       coda_kfifo_sync_from_device(ctx);
-
-       /*
-        * in stream-end mode, the read pointer can overshoot the write pointer
-        * by up to 512 bytes
-        */
-       if (ctx->bit_stream_param & CODA_BIT_STREAM_END_FLAG) {
-               if (coda_get_bitstream_payload(ctx) >= 0x100000 - 512)
-                       kfifo_init(&ctx->bitstream_fifo,
-                               ctx->bitstream.vaddr, ctx->bitstream.size);
-       }
-
-       q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
-       src_fourcc = q_data_src->fourcc;
-
-       val = coda_read(dev, CODA_RET_DEC_PIC_SUCCESS);
-       if (val != 1)
-               pr_err("DEC_PIC_SUCCESS = %d\n", val);
-
-       success = val & 0x1;
-       if (!success)
-               v4l2_err(&dev->v4l2_dev, "decode failed\n");
-
-       if (src_fourcc == V4L2_PIX_FMT_H264) {
-               if (val & (1 << 3))
-                       v4l2_err(&dev->v4l2_dev,
-                                "insufficient PS buffer space (%d bytes)\n",
-                                ctx->psbuf.size);
-               if (val & (1 << 2))
-                       v4l2_err(&dev->v4l2_dev,
-                                "insufficient slice buffer space (%d bytes)\n",
-                                ctx->slicebuf.size);
-       }
-
-       val = coda_read(dev, CODA_RET_DEC_PIC_SIZE);
-       width = (val >> 16) & 0xffff;
-       height = val & 0xffff;
-
-       q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE);
-
-       /* frame crop information */
-       if (src_fourcc == V4L2_PIX_FMT_H264) {
-               u32 left_right;
-               u32 top_bottom;
-
-               left_right = coda_read(dev, CODA_RET_DEC_PIC_CROP_LEFT_RIGHT);
-               top_bottom = coda_read(dev, CODA_RET_DEC_PIC_CROP_TOP_BOTTOM);
-
-               if (left_right == 0xffffffff && top_bottom == 0xffffffff) {
-                       /* Keep current crop information */
-               } else {
-                       struct v4l2_rect *rect = &q_data_dst->rect;
-
-                       rect->left = left_right >> 16 & 0xffff;
-                       rect->top = top_bottom >> 16 & 0xffff;
-                       rect->width = width - rect->left -
-                                     (left_right & 0xffff);
-                       rect->height = height - rect->top -
-                                      (top_bottom & 0xffff);
-               }
-       } else {
-               /* no cropping */
-       }
-
-       err_mb = coda_read(dev, CODA_RET_DEC_PIC_ERR_MB);
-       if (err_mb > 0)
-               v4l2_err(&dev->v4l2_dev,
-                        "errors in %d macroblocks\n", err_mb);
-
-       if (dev->devtype->product == CODA_7541) {
-               val = coda_read(dev, CODA_RET_DEC_PIC_OPTION);
-               if (val == 0) {
-                       /* not enough bitstream data */
-                       v4l2_dbg(1, coda_debug, &dev->v4l2_dev,
-                                "prescan failed: %d\n", val);
-                       ctx->hold = true;
-                       return;
-               }
-       }
-
-       ctx->frm_dis_flg = coda_read(dev, CODA_REG_BIT_FRM_DIS_FLG(ctx->reg_idx));
-
-       /*
-        * The previous display frame was copied out by the rotator,
-        * now it can be overwritten again
-        */
-       if (ctx->display_idx >= 0 &&
-           ctx->display_idx < ctx->num_internal_frames) {
-               ctx->frm_dis_flg &= ~(1 << ctx->display_idx);
-               coda_write(dev, ctx->frm_dis_flg,
-                               CODA_REG_BIT_FRM_DIS_FLG(ctx->reg_idx));
-       }
-
-       /*
-        * The index of the last decoded frame, not necessarily in
-        * display order, and the index of the next display frame.
-        * The latter could have been decoded in a previous run.
-        */
-       decoded_idx = coda_read(dev, CODA_RET_DEC_PIC_CUR_IDX);
-       display_idx = coda_read(dev, CODA_RET_DEC_PIC_FRAME_IDX);
-
-       if (decoded_idx == -1) {
-               /* no frame was decoded, but we might have a display frame */
-               if (display_idx >= 0 && display_idx < ctx->num_internal_frames)
-                       ctx->sequence_offset++;
-               else if (ctx->display_idx < 0)
-                       ctx->hold = true;
-       } else if (decoded_idx == -2) {
-               /* no frame was decoded, we still return the remaining buffers */
-       } else if (decoded_idx < 0 || decoded_idx >= ctx->num_internal_frames) {
-               v4l2_err(&dev->v4l2_dev,
-                        "decoded frame index out of range: %d\n", decoded_idx);
-       } else {
-               ts = list_first_entry(&ctx->timestamp_list,
-                                     struct coda_timestamp, list);
-               list_del(&ts->list);
-               val = coda_read(dev, CODA_RET_DEC_PIC_FRAME_NUM) - 1;
-               val -= ctx->sequence_offset;
-               if (val != (ts->sequence & 0xffff)) {
-                       v4l2_err(&dev->v4l2_dev,
-                                "sequence number mismatch (%d(%d) != %d)\n",
-                                val, ctx->sequence_offset, ts->sequence);
-               }
-               ctx->frame_timestamps[decoded_idx] = *ts;
-               kfree(ts);
-
-               val = coda_read(dev, CODA_RET_DEC_PIC_TYPE) & 0x7;
-               if (val == 0)
-                       ctx->frame_types[decoded_idx] = V4L2_BUF_FLAG_KEYFRAME;
-               else if (val == 1)
-                       ctx->frame_types[decoded_idx] = V4L2_BUF_FLAG_PFRAME;
-               else
-                       ctx->frame_types[decoded_idx] = V4L2_BUF_FLAG_BFRAME;
-
-               ctx->frame_errors[decoded_idx] = err_mb;
-       }
-
-       if (display_idx == -1) {
-               /*
-                * no more frames to be decoded, but there could still
-                * be rotator output to dequeue
-                */
-               ctx->hold = true;
-       } else if (display_idx == -3) {
-               /* possibly prescan failure */
-       } else if (display_idx < 0 || display_idx >= ctx->num_internal_frames) {
-               v4l2_err(&dev->v4l2_dev,
-                        "presentation frame index out of range: %d\n",
-                        display_idx);
-       }
-
-       /* If a frame was copied out, return it */
-       if (ctx->display_idx >= 0 &&
-           ctx->display_idx < ctx->num_internal_frames) {
-               dst_buf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
-               dst_buf->v4l2_buf.sequence = ctx->osequence++;
-
-               dst_buf->v4l2_buf.flags &= ~(V4L2_BUF_FLAG_KEYFRAME |
-                                            V4L2_BUF_FLAG_PFRAME |
-                                            V4L2_BUF_FLAG_BFRAME);
-               dst_buf->v4l2_buf.flags |= ctx->frame_types[ctx->display_idx];
-               ts = &ctx->frame_timestamps[ctx->display_idx];
-               dst_buf->v4l2_buf.timecode = ts->timecode;
-               dst_buf->v4l2_buf.timestamp = ts->timestamp;
-
-               vb2_set_plane_payload(dst_buf, 0, width * height * 3 / 2);
-
-               v4l2_m2m_buf_done(dst_buf, ctx->frame_errors[display_idx] ?
-                                 VB2_BUF_STATE_ERROR : VB2_BUF_STATE_DONE);
-
-               v4l2_dbg(1, coda_debug, &dev->v4l2_dev,
-                       "job finished: decoding frame (%d) (%s)\n",
-                       dst_buf->v4l2_buf.sequence,
-                       (dst_buf->v4l2_buf.flags & V4L2_BUF_FLAG_KEYFRAME) ?
-                       "KEYFRAME" : "PFRAME");
-       } else {
-               v4l2_dbg(1, coda_debug, &dev->v4l2_dev,
-                       "job finished: no frame decoded\n");
-       }
-
-       /* The rotator will copy the current display frame next time */
-       ctx->display_idx = display_idx;
-}
-
-static void coda_finish_encode(struct coda_ctx *ctx)
-{
-       struct vb2_buffer *src_buf, *dst_buf;
-       struct coda_dev *dev = ctx->dev;
-       u32 wr_ptr, start_ptr;
-
-       src_buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
-       dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
-
-       /* Get results from the coda */
-       start_ptr = coda_read(dev, CODA_CMD_ENC_PIC_BB_START);
-       wr_ptr = coda_read(dev, CODA_REG_BIT_WR_PTR(ctx->reg_idx));
-
-       /* Calculate bytesused field */
-       if (dst_buf->v4l2_buf.sequence == 0) {
-               vb2_set_plane_payload(dst_buf, 0, wr_ptr - start_ptr +
-                                       ctx->vpu_header_size[0] +
-                                       ctx->vpu_header_size[1] +
-                                       ctx->vpu_header_size[2]);
-       } else {
-               vb2_set_plane_payload(dst_buf, 0, wr_ptr - start_ptr);
-       }
-
-       v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev, "frame size = %u\n",
-                wr_ptr - start_ptr);
-
-       coda_read(dev, CODA_RET_ENC_PIC_SLICE_NUM);
-       coda_read(dev, CODA_RET_ENC_PIC_FLAG);
-
-       if (coda_read(dev, CODA_RET_ENC_PIC_TYPE) == 0) {
-               dst_buf->v4l2_buf.flags |= V4L2_BUF_FLAG_KEYFRAME;
-               dst_buf->v4l2_buf.flags &= ~V4L2_BUF_FLAG_PFRAME;
-       } else {
-               dst_buf->v4l2_buf.flags |= V4L2_BUF_FLAG_PFRAME;
-               dst_buf->v4l2_buf.flags &= ~V4L2_BUF_FLAG_KEYFRAME;
-       }
-
-       dst_buf->v4l2_buf.timestamp = src_buf->v4l2_buf.timestamp;
-       dst_buf->v4l2_buf.flags &= ~V4L2_BUF_FLAG_TSTAMP_SRC_MASK;
-       dst_buf->v4l2_buf.flags |=
-               src_buf->v4l2_buf.flags & V4L2_BUF_FLAG_TSTAMP_SRC_MASK;
-       dst_buf->v4l2_buf.timecode = src_buf->v4l2_buf.timecode;
-
-       v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_DONE);
-
-       dst_buf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
-       v4l2_m2m_buf_done(dst_buf, VB2_BUF_STATE_DONE);
-
-       ctx->gopcounter--;
-       if (ctx->gopcounter < 0)
-               ctx->gopcounter = ctx->params.gop_size - 1;
-
-       v4l2_dbg(1, coda_debug, &dev->v4l2_dev,
-               "job finished: encoding frame (%d) (%s)\n",
-               dst_buf->v4l2_buf.sequence,
-               (dst_buf->v4l2_buf.flags & V4L2_BUF_FLAG_KEYFRAME) ?
-               "KEYFRAME" : "PFRAME");
-}
-
-static irqreturn_t coda_irq_handler(int irq, void *data)
-{
-       struct coda_dev *dev = data;
-       struct coda_ctx *ctx;
-
-       /* read status register to attend the IRQ */
-       coda_read(dev, CODA_REG_BIT_INT_STATUS);
-       coda_write(dev, CODA_REG_BIT_INT_CLEAR_SET,
-                     CODA_REG_BIT_INT_CLEAR);
-
-       ctx = v4l2_m2m_get_curr_priv(dev->m2m_dev);
-       if (ctx == NULL) {
-               v4l2_err(&dev->v4l2_dev, "Instance released before the end of transaction\n");
-               mutex_unlock(&dev->coda_mutex);
-               return IRQ_HANDLED;
-       }
-
-       if (ctx->aborting) {
-               v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev,
-                        "task has been aborted\n");
-       }
-
-       if (coda_isbusy(ctx->dev)) {
-               v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev,
-                        "coda is still busy!!!!\n");
-               return IRQ_NONE;
-       }
-
-       complete(&ctx->completion);
-
-       return IRQ_HANDLED;
-}
-
-static u32 coda_supported_firmwares[] = {
-       CODA_FIRMWARE_VERNUM(CODA_DX6, 2, 2, 5),
-       CODA_FIRMWARE_VERNUM(CODA_7541, 1, 4, 50),
-       CODA_FIRMWARE_VERNUM(CODA_960, 2, 1, 5),
-};
-
-static bool coda_firmware_supported(u32 vernum)
-{
-       int i;
-
-       for (i = 0; i < ARRAY_SIZE(coda_supported_firmwares); i++)
-               if (vernum == coda_supported_firmwares[i])
-                       return true;
-       return false;
-}
-
-static int coda_hw_init(struct coda_dev *dev)
-{
-       u32 data;
-       u16 *p;
-       int i, ret;
-
-       ret = clk_prepare_enable(dev->clk_per);
-       if (ret)
-               goto err_clk_per;
-
-       ret = clk_prepare_enable(dev->clk_ahb);
-       if (ret)
-               goto err_clk_ahb;
-
-       if (dev->rstc)
-               reset_control_reset(dev->rstc);
-
-       /*
-        * Copy the first CODA_ISRAM_SIZE in the internal SRAM.
-        * The 16-bit chars in the code buffer are in memory access
-        * order, re-sort them to CODA order for register download.
-        * Data in this SRAM survives a reboot.
-        */
-       p = (u16 *)dev->codebuf.vaddr;
-       if (dev->devtype->product == CODA_DX6) {
-               for (i = 0; i < (CODA_ISRAM_SIZE / 2); i++)  {
-                       data = CODA_DOWN_ADDRESS_SET(i) |
-                               CODA_DOWN_DATA_SET(p[i ^ 1]);
-                       coda_write(dev, data, CODA_REG_BIT_CODE_DOWN);
-               }
-       } else {
-               for (i = 0; i < (CODA_ISRAM_SIZE / 2); i++) {
-                       data = CODA_DOWN_ADDRESS_SET(i) |
-                               CODA_DOWN_DATA_SET(p[round_down(i, 4) +
-                                                       3 - (i % 4)]);
-                       coda_write(dev, data, CODA_REG_BIT_CODE_DOWN);
-               }
-       }
-
-       /* Clear registers */
-       for (i = 0; i < 64; i++)
-               coda_write(dev, 0, CODA_REG_BIT_CODE_BUF_ADDR + i * 4);
-
-       /* Tell the BIT where to find everything it needs */
-       if (dev->devtype->product == CODA_960 ||
-           dev->devtype->product == CODA_7541) {
-               coda_write(dev, dev->tempbuf.paddr,
-                               CODA_REG_BIT_TEMP_BUF_ADDR);
-               coda_write(dev, 0, CODA_REG_BIT_BIT_STREAM_PARAM);
-       } else {
-               coda_write(dev, dev->workbuf.paddr,
-                             CODA_REG_BIT_WORK_BUF_ADDR);
-       }
-       coda_write(dev, dev->codebuf.paddr,
-                     CODA_REG_BIT_CODE_BUF_ADDR);
-       coda_write(dev, 0, CODA_REG_BIT_CODE_RUN);
-
-       /* Set default values */
-       switch (dev->devtype->product) {
-       case CODA_DX6:
-               coda_write(dev, CODADX6_STREAM_BUF_PIC_FLUSH, CODA_REG_BIT_STREAM_CTRL);
-               break;
-       default:
-               coda_write(dev, CODA7_STREAM_BUF_PIC_FLUSH, CODA_REG_BIT_STREAM_CTRL);
-       }
-       if (dev->devtype->product == CODA_960)
-               coda_write(dev, 1 << 12, CODA_REG_BIT_FRAME_MEM_CTRL);
-       else
-               coda_write(dev, 0, CODA_REG_BIT_FRAME_MEM_CTRL);
-
-       if (dev->devtype->product != CODA_DX6)
-               coda_write(dev, 0, CODA7_REG_BIT_AXI_SRAM_USE);
-
-       coda_write(dev, CODA_INT_INTERRUPT_ENABLE,
-                     CODA_REG_BIT_INT_ENABLE);
-
-       /* Reset VPU and start processor */
-       data = coda_read(dev, CODA_REG_BIT_CODE_RESET);
-       data |= CODA_REG_RESET_ENABLE;
-       coda_write(dev, data, CODA_REG_BIT_CODE_RESET);
-       udelay(10);
-       data &= ~CODA_REG_RESET_ENABLE;
-       coda_write(dev, data, CODA_REG_BIT_CODE_RESET);
-       coda_write(dev, CODA_REG_RUN_ENABLE, CODA_REG_BIT_CODE_RUN);
-
-       clk_disable_unprepare(dev->clk_ahb);
-       clk_disable_unprepare(dev->clk_per);
-
-       return 0;
-
-err_clk_ahb:
-       clk_disable_unprepare(dev->clk_per);
-err_clk_per:
-       return ret;
-}
-
-static int coda_check_firmware(struct coda_dev *dev)
-{
-       u16 product, major, minor, release;
-       u32 data;
-       int ret;
-
-       ret = clk_prepare_enable(dev->clk_per);
-       if (ret)
-               goto err_clk_per;
-
-       ret = clk_prepare_enable(dev->clk_ahb);
-       if (ret)
-               goto err_clk_ahb;
-
-       coda_write(dev, 0, CODA_CMD_FIRMWARE_VERNUM);
-       coda_write(dev, CODA_REG_BIT_BUSY_FLAG, CODA_REG_BIT_BUSY);
-       coda_write(dev, 0, CODA_REG_BIT_RUN_INDEX);
-       coda_write(dev, 0, CODA_REG_BIT_RUN_COD_STD);
-       coda_write(dev, CODA_COMMAND_FIRMWARE_GET, CODA_REG_BIT_RUN_COMMAND);
-       if (coda_wait_timeout(dev)) {
-               v4l2_err(&dev->v4l2_dev, "firmware get command error\n");
-               ret = -EIO;
-               goto err_run_cmd;
-       }
-
-       if (dev->devtype->product == CODA_960) {
-               data = coda_read(dev, CODA9_CMD_FIRMWARE_CODE_REV);
-               v4l2_info(&dev->v4l2_dev, "Firmware code revision: %d\n",
-                         data);
-       }
-
-       /* Check we are compatible with the loaded firmware */
-       data = coda_read(dev, CODA_CMD_FIRMWARE_VERNUM);
-       product = CODA_FIRMWARE_PRODUCT(data);
-       major = CODA_FIRMWARE_MAJOR(data);
-       minor = CODA_FIRMWARE_MINOR(data);
-       release = CODA_FIRMWARE_RELEASE(data);
-
-       clk_disable_unprepare(dev->clk_per);
-       clk_disable_unprepare(dev->clk_ahb);
-
-       if (product != dev->devtype->product) {
-               v4l2_err(&dev->v4l2_dev, "Wrong firmware. Hw: %s, Fw: %s,"
-                        " Version: %u.%u.%u\n",
-                        coda_product_name(dev->devtype->product),
-                        coda_product_name(product), major, minor, release);
-               return -EINVAL;
-       }
-
-       v4l2_info(&dev->v4l2_dev, "Initialized %s.\n",
-                 coda_product_name(product));
-
-       if (coda_firmware_supported(data)) {
-               v4l2_info(&dev->v4l2_dev, "Firmware version: %u.%u.%u\n",
-                         major, minor, release);
-       } else {
-               v4l2_warn(&dev->v4l2_dev, "Unsupported firmware version: "
-                         "%u.%u.%u\n", major, minor, release);
-       }
-
-       return 0;
-
-err_run_cmd:
-       clk_disable_unprepare(dev->clk_ahb);
-err_clk_ahb:
-       clk_disable_unprepare(dev->clk_per);
-err_clk_per:
-       return ret;
-}
-
-static void coda_fw_callback(const struct firmware *fw, void *context)
-{
-       struct coda_dev *dev = context;
-       struct platform_device *pdev = dev->plat_dev;
-       int ret;
-
-       if (!fw) {
-               v4l2_err(&dev->v4l2_dev, "firmware request failed\n");
-               return;
-       }
-
-       /* allocate auxiliary per-device code buffer for the BIT processor */
-       ret = coda_alloc_aux_buf(dev, &dev->codebuf, fw->size, "codebuf",
-                                dev->debugfs_root);
-       if (ret < 0) {
-               dev_err(&pdev->dev, "failed to allocate code buffer\n");
-               return;
-       }
-
-       /* Copy the whole firmware image to the code buffer */
-       memcpy(dev->codebuf.vaddr, fw->data, fw->size);
-       release_firmware(fw);
-
-       if (pm_runtime_enabled(&pdev->dev) && pdev->dev.pm_domain) {
-               /*
-                * Enabling power temporarily will cause coda_hw_init to be
-                * called via coda_runtime_resume by the pm domain.
-                */
-               ret = pm_runtime_get_sync(&dev->plat_dev->dev);
-               if (ret < 0) {
-                       v4l2_err(&dev->v4l2_dev, "failed to power on: %d\n",
-                                ret);
-                       return;
-               }
-
-               ret = coda_check_firmware(dev);
-               if (ret < 0)
-                       return;
-
-               pm_runtime_put_sync(&dev->plat_dev->dev);
-       } else {
-               /*
-                * If runtime pm is disabled or pm_domain is not set,
-                * initialize once manually.
-                */
-               ret = coda_hw_init(dev);
-               if (ret < 0) {
-                       v4l2_err(&dev->v4l2_dev, "HW initialization failed\n");
-                       return;
-               }
-
-               ret = coda_check_firmware(dev);
-               if (ret < 0)
-                       return;
-       }
-
-       dev->vfd.fops   = &coda_fops,
-       dev->vfd.ioctl_ops      = &coda_ioctl_ops;
-       dev->vfd.release        = video_device_release_empty,
-       dev->vfd.lock   = &dev->dev_mutex;
-       dev->vfd.v4l2_dev       = &dev->v4l2_dev;
-       dev->vfd.vfl_dir        = VFL_DIR_M2M;
-       snprintf(dev->vfd.name, sizeof(dev->vfd.name), "%s", CODA_NAME);
-       video_set_drvdata(&dev->vfd, dev);
-
-       dev->alloc_ctx = vb2_dma_contig_init_ctx(&pdev->dev);
-       if (IS_ERR(dev->alloc_ctx)) {
-               v4l2_err(&dev->v4l2_dev, "Failed to alloc vb2 context\n");
-               return;
-       }
-
-       dev->m2m_dev = v4l2_m2m_init(&coda_m2m_ops);
-       if (IS_ERR(dev->m2m_dev)) {
-               v4l2_err(&dev->v4l2_dev, "Failed to init mem2mem device\n");
-               goto rel_ctx;
-       }
-
-       ret = video_register_device(&dev->vfd, VFL_TYPE_GRABBER, 0);
-       if (ret) {
-               v4l2_err(&dev->v4l2_dev, "Failed to register video device\n");
-               goto rel_m2m;
-       }
-       v4l2_info(&dev->v4l2_dev, "codec registered as /dev/video%d\n",
-                 dev->vfd.num);
-
-       return;
-
-rel_m2m:
-       v4l2_m2m_release(dev->m2m_dev);
-rel_ctx:
-       vb2_dma_contig_cleanup_ctx(dev->alloc_ctx);
-}
-
-static int coda_firmware_request(struct coda_dev *dev)
-{
-       char *fw = dev->devtype->firmware;
-
-       dev_dbg(&dev->plat_dev->dev, "requesting firmware '%s' for %s\n", fw,
-               coda_product_name(dev->devtype->product));
-
-       return request_firmware_nowait(THIS_MODULE, true,
-               fw, &dev->plat_dev->dev, GFP_KERNEL, dev, coda_fw_callback);
-}
-
-enum coda_platform {
-       CODA_IMX27,
-       CODA_IMX53,
-       CODA_IMX6Q,
-       CODA_IMX6DL,
-};
-
-static const struct coda_devtype coda_devdata[] = {
-       [CODA_IMX27] = {
-               .firmware     = "v4l-codadx6-imx27.bin",
-               .product      = CODA_DX6,
-               .codecs       = codadx6_codecs,
-               .num_codecs   = ARRAY_SIZE(codadx6_codecs),
-               .workbuf_size = 288 * 1024 + FMO_SLICE_SAVE_BUF_SIZE * 8 * 1024,
-               .iram_size    = 0xb000,
-       },
-       [CODA_IMX53] = {
-               .firmware     = "v4l-coda7541-imx53.bin",
-               .product      = CODA_7541,
-               .codecs       = coda7_codecs,
-               .num_codecs   = ARRAY_SIZE(coda7_codecs),
-               .workbuf_size = 128 * 1024,
-               .tempbuf_size = 304 * 1024,
-               .iram_size    = 0x14000,
-       },
-       [CODA_IMX6Q] = {
-               .firmware     = "v4l-coda960-imx6q.bin",
-               .product      = CODA_960,
-               .codecs       = coda9_codecs,
-               .num_codecs   = ARRAY_SIZE(coda9_codecs),
-               .workbuf_size = 80 * 1024,
-               .tempbuf_size = 204 * 1024,
-               .iram_size    = 0x21000,
-       },
-       [CODA_IMX6DL] = {
-               .firmware     = "v4l-coda960-imx6dl.bin",
-               .product      = CODA_960,
-               .codecs       = coda9_codecs,
-               .num_codecs   = ARRAY_SIZE(coda9_codecs),
-               .workbuf_size = 80 * 1024,
-               .tempbuf_size = 204 * 1024,
-               .iram_size    = 0x20000,
-       },
-};
-
-static struct platform_device_id coda_platform_ids[] = {
-       { .name = "coda-imx27", .driver_data = CODA_IMX27 },
-       { .name = "coda-imx53", .driver_data = CODA_IMX53 },
-       { /* sentinel */ }
-};
-MODULE_DEVICE_TABLE(platform, coda_platform_ids);
-
-#ifdef CONFIG_OF
-static const struct of_device_id coda_dt_ids[] = {
-       { .compatible = "fsl,imx27-vpu", .data = &coda_devdata[CODA_IMX27] },
-       { .compatible = "fsl,imx53-vpu", .data = &coda_devdata[CODA_IMX53] },
-       { .compatible = "fsl,imx6q-vpu", .data = &coda_devdata[CODA_IMX6Q] },
-       { .compatible = "fsl,imx6dl-vpu", .data = &coda_devdata[CODA_IMX6DL] },
-       { /* sentinel */ }
-};
-MODULE_DEVICE_TABLE(of, coda_dt_ids);
-#endif
-
-static int coda_probe(struct platform_device *pdev)
-{
-       const struct of_device_id *of_id =
-                       of_match_device(of_match_ptr(coda_dt_ids), &pdev->dev);
-       const struct platform_device_id *pdev_id;
-       struct coda_platform_data *pdata = pdev->dev.platform_data;
-       struct device_node *np = pdev->dev.of_node;
-       struct gen_pool *pool;
-       struct coda_dev *dev;
-       struct resource *res;
-       int ret, irq;
-
-       dev = devm_kzalloc(&pdev->dev, sizeof *dev, GFP_KERNEL);
-       if (!dev) {
-               dev_err(&pdev->dev, "Not enough memory for %s\n",
-                       CODA_NAME);
-               return -ENOMEM;
-       }
-
-       spin_lock_init(&dev->irqlock);
-       INIT_LIST_HEAD(&dev->instances);
-
-       dev->plat_dev = pdev;
-       dev->clk_per = devm_clk_get(&pdev->dev, "per");
-       if (IS_ERR(dev->clk_per)) {
-               dev_err(&pdev->dev, "Could not get per clock\n");
-               return PTR_ERR(dev->clk_per);
-       }
-
-       dev->clk_ahb = devm_clk_get(&pdev->dev, "ahb");
-       if (IS_ERR(dev->clk_ahb)) {
-               dev_err(&pdev->dev, "Could not get ahb clock\n");
-               return PTR_ERR(dev->clk_ahb);
-       }
-
-       /* Get  memory for physical registers */
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       dev->regs_base = devm_ioremap_resource(&pdev->dev, res);
-       if (IS_ERR(dev->regs_base))
-               return PTR_ERR(dev->regs_base);
-
-       /* IRQ */
-       irq = platform_get_irq(pdev, 0);
-       if (irq < 0) {
-               dev_err(&pdev->dev, "failed to get irq resource\n");
-               return irq;
-       }
-
-       ret = devm_request_threaded_irq(&pdev->dev, irq, NULL, coda_irq_handler,
-                       IRQF_ONESHOT, dev_name(&pdev->dev), dev);
-       if (ret < 0) {
-               dev_err(&pdev->dev, "failed to request irq: %d\n", ret);
-               return ret;
-       }
-
-       dev->rstc = devm_reset_control_get_optional(&pdev->dev, NULL);
-       if (IS_ERR(dev->rstc)) {
-               ret = PTR_ERR(dev->rstc);
-               if (ret == -ENOENT || ret == -ENOSYS) {
-                       dev->rstc = NULL;
-               } else {
-                       dev_err(&pdev->dev, "failed get reset control: %d\n", ret);
-                       return ret;
-               }
-       }
-
-       /* Get IRAM pool from device tree or platform data */
-       pool = of_get_named_gen_pool(np, "iram", 0);
-       if (!pool && pdata)
-               pool = dev_get_gen_pool(pdata->iram_dev);
-       if (!pool) {
-               dev_err(&pdev->dev, "iram pool not available\n");
-               return -ENOMEM;
-       }
-       dev->iram_pool = pool;
-
-       ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev);
-       if (ret)
-               return ret;
-
-       mutex_init(&dev->dev_mutex);
-       mutex_init(&dev->coda_mutex);
-
-       pdev_id = of_id ? of_id->data : platform_get_device_id(pdev);
-
-       if (of_id) {
-               dev->devtype = of_id->data;
-       } else if (pdev_id) {
-               dev->devtype = &coda_devdata[pdev_id->driver_data];
-       } else {
-               v4l2_device_unregister(&dev->v4l2_dev);
-               return -EINVAL;
-       }
-
-       dev->debugfs_root = debugfs_create_dir("coda", NULL);
-       if (!dev->debugfs_root)
-               dev_warn(&pdev->dev, "failed to create debugfs root\n");
-
-       /* allocate auxiliary per-device buffers for the BIT processor */
-       if (dev->devtype->product == CODA_DX6) {
-               ret = coda_alloc_aux_buf(dev, &dev->workbuf,
-                                        dev->devtype->workbuf_size, "workbuf",
-                                        dev->debugfs_root);
-               if (ret < 0) {
-                       dev_err(&pdev->dev, "failed to allocate work buffer\n");
-                       v4l2_device_unregister(&dev->v4l2_dev);
-                       return ret;
-               }
-       }
-
-       if (dev->devtype->tempbuf_size) {
-               ret = coda_alloc_aux_buf(dev, &dev->tempbuf,
-                                        dev->devtype->tempbuf_size, "tempbuf",
-                                        dev->debugfs_root);
-               if (ret < 0) {
-                       dev_err(&pdev->dev, "failed to allocate temp buffer\n");
-                       v4l2_device_unregister(&dev->v4l2_dev);
-                       return ret;
-               }
-       }
-
-       dev->iram.size = dev->devtype->iram_size;
-       dev->iram.vaddr = gen_pool_dma_alloc(dev->iram_pool, dev->iram.size,
-                                            &dev->iram.paddr);
-       if (!dev->iram.vaddr) {
-               dev_err(&pdev->dev, "unable to alloc iram\n");
-               return -ENOMEM;
-       }
-
-       dev->iram.blob.data = dev->iram.vaddr;
-       dev->iram.blob.size = dev->iram.size;
-       dev->iram.dentry = debugfs_create_blob("iram", 0644, dev->debugfs_root,
-                                              &dev->iram.blob);
-
-       dev->workqueue = alloc_workqueue("coda", WQ_UNBOUND | WQ_MEM_RECLAIM, 1);
-       if (!dev->workqueue) {
-               dev_err(&pdev->dev, "unable to alloc workqueue\n");
-               return -ENOMEM;
-       }
-
-       platform_set_drvdata(pdev, dev);
-
-       pm_runtime_enable(&pdev->dev);
-
-       return coda_firmware_request(dev);
-}
-
-static int coda_remove(struct platform_device *pdev)
-{
-       struct coda_dev *dev = platform_get_drvdata(pdev);
-
-       video_unregister_device(&dev->vfd);
-       if (dev->m2m_dev)
-               v4l2_m2m_release(dev->m2m_dev);
-       pm_runtime_disable(&pdev->dev);
-       if (dev->alloc_ctx)
-               vb2_dma_contig_cleanup_ctx(dev->alloc_ctx);
-       v4l2_device_unregister(&dev->v4l2_dev);
-       destroy_workqueue(dev->workqueue);
-       if (dev->iram.vaddr)
-               gen_pool_free(dev->iram_pool, (unsigned long)dev->iram.vaddr,
-                             dev->iram.size);
-       coda_free_aux_buf(dev, &dev->codebuf);
-       coda_free_aux_buf(dev, &dev->tempbuf);
-       coda_free_aux_buf(dev, &dev->workbuf);
-       debugfs_remove_recursive(dev->debugfs_root);
-       return 0;
-}
-
-#ifdef CONFIG_PM_RUNTIME
-static int coda_runtime_resume(struct device *dev)
-{
-       struct coda_dev *cdev = dev_get_drvdata(dev);
-       int ret = 0;
-
-       if (dev->pm_domain) {
-               ret = coda_hw_init(cdev);
-               if (ret)
-                       v4l2_err(&cdev->v4l2_dev, "HW initialization failed\n");
-       }
-
-       return ret;
-}
-#endif
-
-static const struct dev_pm_ops coda_pm_ops = {
-       SET_RUNTIME_PM_OPS(NULL, coda_runtime_resume, NULL)
-};
-
-static struct platform_driver coda_driver = {
-       .probe  = coda_probe,
-       .remove = coda_remove,
-       .driver = {
-               .name   = CODA_NAME,
-               .owner  = THIS_MODULE,
-               .of_match_table = of_match_ptr(coda_dt_ids),
-               .pm     = &coda_pm_ops,
-       },
-       .id_table = coda_platform_ids,
-};
-
-module_platform_driver(coda_driver);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Javier Martin <javier.martin@vista-silicon.com>");
-MODULE_DESCRIPTION("Coda multi-standard codec V4L2 driver");
diff --git a/drivers/media/platform/coda.h b/drivers/media/platform/coda.h
deleted file mode 100644 (file)
index c791275..0000000
+++ /dev/null
@@ -1,447 +0,0 @@
-/*
- * linux/drivers/media/platform/coda/coda_regs.h
- *
- * Copyright (C) 2012 Vista Silicon SL
- *    Javier Martin <javier.martin@vista-silicon.com>
- *    Xavier Duret
- *
- * 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 _REGS_CODA_H_
-#define _REGS_CODA_H_
-
-/* HW registers */
-#define CODA_REG_BIT_CODE_RUN                  0x000
-#define                CODA_REG_RUN_ENABLE             (1 << 0)
-#define CODA_REG_BIT_CODE_DOWN                 0x004
-#define                CODA_DOWN_ADDRESS_SET(x)        (((x) & 0xffff) << 16)
-#define                CODA_DOWN_DATA_SET(x)           ((x) & 0xffff)
-#define CODA_REG_BIT_HOST_IN_REQ               0x008
-#define CODA_REG_BIT_INT_CLEAR                 0x00c
-#define                CODA_REG_BIT_INT_CLEAR_SET      0x1
-#define CODA_REG_BIT_INT_STATUS                0x010
-#define CODA_REG_BIT_CODE_RESET                0x014
-#define                CODA_REG_RESET_ENABLE           (1 << 0)
-#define CODA_REG_BIT_CUR_PC                    0x018
-#define CODA9_REG_BIT_SW_RESET                 0x024
-#define                CODA9_SW_RESET_BPU_CORE   0x008
-#define                CODA9_SW_RESET_BPU_BUS    0x010
-#define                CODA9_SW_RESET_VCE_CORE   0x020
-#define                CODA9_SW_RESET_VCE_BUS    0x040
-#define                CODA9_SW_RESET_GDI_CORE   0x080
-#define                CODA9_SW_RESET_GDI_BUS    0x100
-#define CODA9_REG_BIT_SW_RESET_STATUS          0x034
-
-/* Static SW registers */
-#define CODA_REG_BIT_CODE_BUF_ADDR             0x100
-#define CODA_REG_BIT_WORK_BUF_ADDR             0x104
-#define CODA_REG_BIT_PARA_BUF_ADDR             0x108
-#define CODA_REG_BIT_STREAM_CTRL               0x10c
-#define                CODA7_STREAM_BUF_PIC_RESET      (1 << 4)
-#define                CODADX6_STREAM_BUF_PIC_RESET    (1 << 3)
-#define                CODA7_STREAM_BUF_PIC_FLUSH      (1 << 3)
-#define                CODADX6_STREAM_BUF_PIC_FLUSH    (1 << 2)
-#define                CODA7_STREAM_BUF_DYNALLOC_EN    (1 << 5)
-#define                CODADX6_STREAM_BUF_DYNALLOC_EN  (1 << 4)
-#define                CODADX6_STREAM_CHKDIS_OFFSET    (1 << 1)
-#define                CODA7_STREAM_SEL_64BITS_ENDIAN  (1 << 1)
-#define                CODA_STREAM_ENDIAN_SELECT       (1 << 0)
-#define CODA_REG_BIT_FRAME_MEM_CTRL            0x110
-#define                CODA_FRAME_CHROMA_INTERLEAVE    (1 << 2)
-#define                CODA_IMAGE_ENDIAN_SELECT        (1 << 0)
-#define CODA_REG_BIT_BIT_STREAM_PARAM          0x114
-#define                CODA_BIT_STREAM_END_FLAG        (1 << 2)
-#define                CODA_BIT_DEC_SEQ_INIT_ESCAPE    (1 << 0)
-#define CODA_REG_BIT_TEMP_BUF_ADDR             0x118
-#define CODA_REG_BIT_RD_PTR(x)                 (0x120 + 8 * (x))
-#define CODA_REG_BIT_WR_PTR(x)                 (0x124 + 8 * (x))
-#define CODA_REG_BIT_FRM_DIS_FLG(x)            (0x150 + 4 * (x))
-#define CODADX6_REG_BIT_SEARCH_RAM_BASE_ADDR   0x140
-#define CODA7_REG_BIT_AXI_SRAM_USE             0x140
-#define                CODA9_USE_HOST_BTP_ENABLE       (1 << 13)
-#define                CODA9_USE_HOST_OVL_ENABLE       (1 << 12)
-#define                CODA7_USE_HOST_ME_ENABLE        (1 << 11)
-#define                CODA9_USE_HOST_DBK_ENABLE       (3 << 10)
-#define                CODA7_USE_HOST_OVL_ENABLE       (1 << 10)
-#define                CODA7_USE_HOST_DBK_ENABLE       (1 << 9)
-#define                CODA9_USE_HOST_IP_ENABLE        (1 << 9)
-#define                CODA7_USE_HOST_IP_ENABLE        (1 << 8)
-#define                CODA9_USE_HOST_BIT_ENABLE       (1 << 8)
-#define                CODA7_USE_HOST_BIT_ENABLE       (1 << 7)
-#define                CODA9_USE_BTP_ENABLE            (1 << 5)
-#define                CODA7_USE_ME_ENABLE             (1 << 4)
-#define                CODA9_USE_OVL_ENABLE            (1 << 4)
-#define                CODA7_USE_OVL_ENABLE            (1 << 3)
-#define                CODA9_USE_DBK_ENABLE            (3 << 2)
-#define                CODA7_USE_DBK_ENABLE            (1 << 2)
-#define                CODA7_USE_IP_ENABLE             (1 << 1)
-#define                CODA7_USE_BIT_ENABLE            (1 << 0)
-
-#define CODA_REG_BIT_BUSY                      0x160
-#define                CODA_REG_BIT_BUSY_FLAG          1
-#define CODA_REG_BIT_RUN_COMMAND               0x164
-#define                CODA_COMMAND_SEQ_INIT           1
-#define                CODA_COMMAND_SEQ_END            2
-#define                CODA_COMMAND_PIC_RUN            3
-#define                CODA_COMMAND_SET_FRAME_BUF      4
-#define                CODA_COMMAND_ENCODE_HEADER      5
-#define                CODA_COMMAND_ENC_PARA_SET       6
-#define                CODA_COMMAND_DEC_PARA_SET       7
-#define                CODA_COMMAND_DEC_BUF_FLUSH      8
-#define                CODA_COMMAND_RC_CHANGE_PARAMETER 9
-#define                CODA_COMMAND_FIRMWARE_GET       0xf
-#define CODA_REG_BIT_RUN_INDEX                 0x168
-#define                CODA_INDEX_SET(x)               ((x) & 0x3)
-#define CODA_REG_BIT_RUN_COD_STD               0x16c
-#define                CODADX6_MODE_DECODE_MP4         0
-#define                CODADX6_MODE_ENCODE_MP4         1
-#define                CODADX6_MODE_DECODE_H264        2
-#define                CODADX6_MODE_ENCODE_H264        3
-#define                CODA7_MODE_DECODE_H264          0
-#define                CODA7_MODE_DECODE_VC1           1
-#define                CODA7_MODE_DECODE_MP2           2
-#define                CODA7_MODE_DECODE_MP4           3
-#define                CODA7_MODE_DECODE_DV3           3
-#define                CODA7_MODE_DECODE_RV            4
-#define                CODA7_MODE_DECODE_MJPG          5
-#define                CODA7_MODE_ENCODE_H264          8
-#define                CODA7_MODE_ENCODE_MP4           11
-#define                CODA7_MODE_ENCODE_MJPG          13
-#define                CODA9_MODE_DECODE_H264          0
-#define                CODA9_MODE_DECODE_VC1           1
-#define                CODA9_MODE_DECODE_MP2           2
-#define                CODA9_MODE_DECODE_MP4           3
-#define                CODA9_MODE_DECODE_DV3           3
-#define                CODA9_MODE_DECODE_RV            4
-#define                CODA9_MODE_DECODE_AVS           5
-#define                CODA9_MODE_DECODE_MJPG          6
-#define                CODA9_MODE_DECODE_VPX           7
-#define                CODA9_MODE_ENCODE_H264          8
-#define                CODA9_MODE_ENCODE_MP4           11
-#define                CODA9_MODE_ENCODE_MJPG          13
-#define        CODA_MODE_INVALID               0xffff
-#define CODA_REG_BIT_INT_ENABLE                0x170
-#define                CODA_INT_INTERRUPT_ENABLE       (1 << 3)
-#define CODA_REG_BIT_INT_REASON                        0x174
-#define CODA7_REG_BIT_RUN_AUX_STD              0x178
-#define                CODA_MP4_AUX_MPEG4              0
-#define                CODA_MP4_AUX_DIVX3              1
-#define                CODA_VPX_AUX_THO                0
-#define                CODA_VPX_AUX_VP6                1
-#define                CODA_VPX_AUX_VP8                2
-#define                CODA_H264_AUX_AVC               0
-#define                CODA_H264_AUX_MVC               1
-
-/*
- * Commands' mailbox:
- * registers with offsets in the range 0x180-0x1d0
- * have different meaning depending on the command being
- * issued.
- */
-
-/* Decoder Sequence Initialization */
-#define CODA_CMD_DEC_SEQ_BB_START              0x180
-#define CODA_CMD_DEC_SEQ_BB_SIZE               0x184
-#define CODA_CMD_DEC_SEQ_OPTION                        0x188
-#define                CODA_REORDER_ENABLE                     (1 << 1)
-#define                CODADX6_QP_REPORT                       (1 << 0)
-#define                CODA7_MP4_DEBLK_ENABLE                  (1 << 0)
-#define CODA_CMD_DEC_SEQ_SRC_SIZE              0x18c
-#define CODA_CMD_DEC_SEQ_START_BYTE            0x190
-#define CODA_CMD_DEC_SEQ_PS_BB_START           0x194
-#define CODA_CMD_DEC_SEQ_PS_BB_SIZE            0x198
-#define CODA_CMD_DEC_SEQ_MP4_ASP_CLASS         0x19c
-#define CODA_CMD_DEC_SEQ_X264_MV_EN            0x19c
-#define CODA_CMD_DEC_SEQ_SPP_CHUNK_SIZE                0x1a0
-
-#define CODA7_RET_DEC_SEQ_ASPECT               0x1b0
-#define CODA9_RET_DEC_SEQ_BITRATE              0x1b4
-#define CODA_RET_DEC_SEQ_SUCCESS               0x1c0
-#define CODA_RET_DEC_SEQ_SRC_FMT               0x1c4 /* SRC_SIZE on CODA7 */
-#define CODA_RET_DEC_SEQ_SRC_SIZE              0x1c4
-#define CODA_RET_DEC_SEQ_SRC_F_RATE            0x1c8
-#define CODA9_RET_DEC_SEQ_ASPECT               0x1c8
-#define CODA_RET_DEC_SEQ_FRAME_NEED            0x1cc
-#define CODA_RET_DEC_SEQ_FRAME_DELAY           0x1d0
-#define CODA_RET_DEC_SEQ_INFO                  0x1d4
-#define CODA_RET_DEC_SEQ_CROP_LEFT_RIGHT       0x1d8
-#define CODA_RET_DEC_SEQ_CROP_TOP_BOTTOM       0x1dc
-#define CODA_RET_DEC_SEQ_NEXT_FRAME_NUM                0x1e0
-#define CODA_RET_DEC_SEQ_ERR_REASON            0x1e0
-#define CODA_RET_DEC_SEQ_FRATE_NR              0x1e4
-#define CODA_RET_DEC_SEQ_FRATE_DR              0x1e8
-#define CODA_RET_DEC_SEQ_JPG_PARA              0x1e4
-#define CODA_RET_DEC_SEQ_JPG_THUMB_IND         0x1e8
-#define CODA9_RET_DEC_SEQ_HEADER_REPORT                0x1ec
-
-/* Decoder Picture Run */
-#define CODA_CMD_DEC_PIC_ROT_MODE              0x180
-#define CODA_CMD_DEC_PIC_ROT_ADDR_Y            0x184
-#define CODA9_CMD_DEC_PIC_ROT_INDEX            0x184
-#define CODA_CMD_DEC_PIC_ROT_ADDR_CB           0x188
-#define CODA9_CMD_DEC_PIC_ROT_ADDR_Y           0x188
-#define CODA_CMD_DEC_PIC_ROT_ADDR_CR           0x18c
-#define CODA9_CMD_DEC_PIC_ROT_ADDR_CB          0x18c
-#define CODA_CMD_DEC_PIC_ROT_STRIDE            0x190
-#define CODA9_CMD_DEC_PIC_ROT_ADDR_CR          0x190
-#define CODA9_CMD_DEC_PIC_ROT_STRIDE           0x1b8
-
-#define CODA_CMD_DEC_PIC_OPTION                        0x194
-#define                CODA_PRE_SCAN_EN                        (1 << 0)
-#define                CODA_PRE_SCAN_MODE_DECODE               (0 << 1)
-#define                CODA_PRE_SCAN_MODE_RETURN               (1 << 1)
-#define                CODA_IFRAME_SEARCH_EN                   (1 << 2)
-#define                CODA_SKIP_FRAME_MODE                    (0x3 << 3)
-#define CODA_CMD_DEC_PIC_SKIP_NUM              0x198
-#define CODA_CMD_DEC_PIC_CHUNK_SIZE            0x19c
-#define CODA_CMD_DEC_PIC_BB_START              0x1a0
-#define CODA_CMD_DEC_PIC_START_BYTE            0x1a4
-#define CODA_RET_DEC_PIC_SIZE                  0x1bc
-#define CODA_RET_DEC_PIC_FRAME_NUM             0x1c0
-#define CODA_RET_DEC_PIC_FRAME_IDX             0x1c4
-#define CODA_RET_DEC_PIC_ERR_MB                        0x1c8
-#define CODA_RET_DEC_PIC_TYPE                  0x1cc
-#define                CODA_PIC_TYPE_MASK                      0x7
-#define                CODA_PIC_TYPE_MASK_VC1                  0x3f
-#define                CODA9_PIC_TYPE_FIRST_MASK               (0x7 << 3)
-#define                CODA9_PIC_TYPE_IDR_MASK                 (0x3 << 6)
-#define                CODA7_PIC_TYPE_H264_NPF_MASK            (0x3 << 16)
-#define                CODA7_PIC_TYPE_INTERLACED               (1 << 18)
-#define CODA_RET_DEC_PIC_POST                  0x1d0
-#define CODA_RET_DEC_PIC_MVC_REPORT            0x1d0
-#define CODA_RET_DEC_PIC_OPTION                        0x1d4
-#define CODA_RET_DEC_PIC_SUCCESS               0x1d8
-#define CODA_RET_DEC_PIC_CUR_IDX               0x1dc
-#define CODA_RET_DEC_PIC_CROP_LEFT_RIGHT       0x1e0
-#define CODA_RET_DEC_PIC_CROP_TOP_BOTTOM       0x1e4
-#define CODA_RET_DEC_PIC_FRAME_NEED            0x1ec
-
-#define CODA9_RET_DEC_PIC_VP8_PIC_REPORT       0x1e8
-#define CODA9_RET_DEC_PIC_ASPECT               0x1f0
-#define CODA9_RET_DEC_PIC_VP8_SCALE_INFO       0x1f0
-#define CODA9_RET_DEC_PIC_FRATE_NR             0x1f4
-#define CODA9_RET_DEC_PIC_FRATE_DR             0x1f8
-
-/* Encoder Sequence Initialization */
-#define CODA_CMD_ENC_SEQ_BB_START                              0x180
-#define CODA_CMD_ENC_SEQ_BB_SIZE                               0x184
-#define CODA_CMD_ENC_SEQ_OPTION                                0x188
-#define                CODA7_OPTION_AVCINTRA16X16ONLY_OFFSET           9
-#define                CODA9_OPTION_MVC_PREFIX_NAL_OFFSET              9
-#define                CODA7_OPTION_GAMMA_OFFSET                       8
-#define                CODA9_OPTION_MVC_PARASET_REFRESH_OFFSET         8
-#define                CODA7_OPTION_RCQPMAX_OFFSET                     7
-#define                CODA9_OPTION_GAMMA_OFFSET                       7
-#define                CODADX6_OPTION_GAMMA_OFFSET                     7
-#define                CODA7_OPTION_RCQPMIN_OFFSET                     6
-#define                CODA9_OPTION_RCQPMAX_OFFSET                     6
-#define                CODA_OPTION_LIMITQP_OFFSET                      6
-#define                CODA_OPTION_RCINTRAQP_OFFSET                    5
-#define                CODA_OPTION_FMO_OFFSET                          4
-#define                CODA9_OPTION_MVC_INTERVIEW_OFFSET               4
-#define                CODA_OPTION_AVC_AUD_OFFSET                      2
-#define                CODA_OPTION_SLICEREPORT_OFFSET                  1
-#define CODA_CMD_ENC_SEQ_COD_STD                               0x18c
-#define                CODA_STD_MPEG4                                  0
-#define                CODA9_STD_H264                                  0
-#define                CODA_STD_H263                                   1
-#define                CODA_STD_H264                                   2
-#define                CODA_STD_MJPG                                   3
-#define                CODA9_STD_MPEG4                                 3
-
-#define CODA_CMD_ENC_SEQ_SRC_SIZE                              0x190
-#define                CODA7_PICWIDTH_OFFSET                           16
-#define                CODA7_PICWIDTH_MASK                             0xffff
-#define                CODADX6_PICWIDTH_OFFSET                         10
-#define                CODADX6_PICWIDTH_MASK                           0x3ff
-#define                CODA_PICHEIGHT_OFFSET                           0
-#define                CODADX6_PICHEIGHT_MASK                          0x3ff
-#define                CODA7_PICHEIGHT_MASK                            0xffff
-#define CODA_CMD_ENC_SEQ_SRC_F_RATE                            0x194
-#define CODA_CMD_ENC_SEQ_MP4_PARA                              0x198
-#define                CODA_MP4PARAM_VERID_OFFSET                      6
-#define                CODA_MP4PARAM_VERID_MASK                        0x01
-#define                CODA_MP4PARAM_INTRADCVLCTHR_OFFSET              2
-#define                CODA_MP4PARAM_INTRADCVLCTHR_MASK                0x07
-#define                CODA_MP4PARAM_REVERSIBLEVLCENABLE_OFFSET        1
-#define                CODA_MP4PARAM_REVERSIBLEVLCENABLE_MASK          0x01
-#define                CODA_MP4PARAM_DATAPARTITIONENABLE_OFFSET        0
-#define                CODA_MP4PARAM_DATAPARTITIONENABLE_MASK          0x01
-#define CODA_CMD_ENC_SEQ_263_PARA                              0x19c
-#define                CODA_263PARAM_ANNEXJENABLE_OFFSET               2
-#define                CODA_263PARAM_ANNEXJENABLE_MASK         0x01
-#define                CODA_263PARAM_ANNEXKENABLE_OFFSET               1
-#define                CODA_263PARAM_ANNEXKENABLE_MASK         0x01
-#define                CODA_263PARAM_ANNEXTENABLE_OFFSET               0
-#define                CODA_263PARAM_ANNEXTENABLE_MASK         0x01
-#define CODA_CMD_ENC_SEQ_264_PARA                              0x1a0
-#define                CODA_264PARAM_DEBLKFILTEROFFSETBETA_OFFSET      12
-#define                CODA_264PARAM_DEBLKFILTEROFFSETBETA_MASK        0x0f
-#define                CODA_264PARAM_DEBLKFILTEROFFSETALPHA_OFFSET     8
-#define                CODA_264PARAM_DEBLKFILTEROFFSETALPHA_MASK       0x0f
-#define                CODA_264PARAM_DISABLEDEBLK_OFFSET               6
-#define                CODA_264PARAM_DISABLEDEBLK_MASK         0x01
-#define                CODA_264PARAM_CONSTRAINEDINTRAPREDFLAG_OFFSET   5
-#define                CODA_264PARAM_CONSTRAINEDINTRAPREDFLAG_MASK     0x01
-#define                CODA_264PARAM_CHROMAQPOFFSET_OFFSET             0
-#define                CODA_264PARAM_CHROMAQPOFFSET_MASK               0x1f
-#define CODA_CMD_ENC_SEQ_SLICE_MODE                            0x1a4
-#define                CODA_SLICING_SIZE_OFFSET                        2
-#define                CODA_SLICING_SIZE_MASK                          0x3fffffff
-#define                CODA_SLICING_UNIT_OFFSET                        1
-#define                CODA_SLICING_UNIT_MASK                          0x01
-#define                CODA_SLICING_MODE_OFFSET                        0
-#define                CODA_SLICING_MODE_MASK                          0x01
-#define CODA_CMD_ENC_SEQ_GOP_SIZE                              0x1a8
-#define                CODA_GOP_SIZE_OFFSET                            0
-#define                CODA_GOP_SIZE_MASK                              0x3f
-#define CODA_CMD_ENC_SEQ_RC_PARA                               0x1ac
-#define                CODA_RATECONTROL_AUTOSKIP_OFFSET                31
-#define                CODA_RATECONTROL_AUTOSKIP_MASK                  0x01
-#define                CODA_RATECONTROL_INITIALDELAY_OFFSET            16
-#define                CODA_RATECONTROL_INITIALDELAY_MASK              0x7f
-#define                CODA_RATECONTROL_BITRATE_OFFSET         1
-#define                CODA_RATECONTROL_BITRATE_MASK                   0x7f
-#define                CODA_RATECONTROL_ENABLE_OFFSET                  0
-#define                CODA_RATECONTROL_ENABLE_MASK                    0x01
-#define CODA_CMD_ENC_SEQ_RC_BUF_SIZE                           0x1b0
-#define CODA_CMD_ENC_SEQ_INTRA_REFRESH                         0x1b4
-#define CODADX6_CMD_ENC_SEQ_FMO                                        0x1b8
-#define                CODA_FMOPARAM_TYPE_OFFSET                       4
-#define                CODA_FMOPARAM_TYPE_MASK                         1
-#define                CODA_FMOPARAM_SLICENUM_OFFSET                   0
-#define                CODA_FMOPARAM_SLICENUM_MASK                     0x0f
-#define CODADX6_CMD_ENC_SEQ_INTRA_QP                           0x1bc
-#define CODA7_CMD_ENC_SEQ_SEARCH_BASE                          0x1b8
-#define CODA7_CMD_ENC_SEQ_SEARCH_SIZE                          0x1bc
-#define CODA7_CMD_ENC_SEQ_INTRA_QP                             0x1c4
-#define CODA_CMD_ENC_SEQ_RC_QP_MIN_MAX                         0x1c8
-#define                CODA_QPMIN_OFFSET                               8
-#define                CODA_QPMIN_MASK                                 0x3f
-#define                CODA_QPMAX_OFFSET                               0
-#define                CODA_QPMAX_MASK                                 0x3f
-#define CODA_CMD_ENC_SEQ_RC_GAMMA                              0x1cc
-#define                CODA_GAMMA_OFFSET                               0
-#define                CODA_GAMMA_MASK                                 0xffff
-#define CODA_CMD_ENC_SEQ_RC_INTERVAL_MODE                      0x1d0
-#define CODA9_CMD_ENC_SEQ_INTRA_WEIGHT                         0x1d4
-#define CODA9_CMD_ENC_SEQ_ME_OPTION                            0x1d8
-#define CODA_RET_ENC_SEQ_SUCCESS                               0x1c0
-
-/* Encoder Picture Run */
-#define CODA9_CMD_ENC_PIC_SRC_INDEX            0x180
-#define CODA9_CMD_ENC_PIC_SRC_STRIDE           0x184
-#define CODA9_CMD_ENC_PIC_SUB_FRAME_SYNC       0x1a4
-#define CODA9_CMD_ENC_PIC_SRC_ADDR_Y           0x1a8
-#define CODA9_CMD_ENC_PIC_SRC_ADDR_CB          0x1ac
-#define CODA9_CMD_ENC_PIC_SRC_ADDR_CR          0x1b0
-#define CODA_CMD_ENC_PIC_SRC_ADDR_Y    0x180
-#define CODA_CMD_ENC_PIC_SRC_ADDR_CB   0x184
-#define CODA_CMD_ENC_PIC_SRC_ADDR_CR   0x188
-#define CODA_CMD_ENC_PIC_QS            0x18c
-#define CODA_CMD_ENC_PIC_ROT_MODE      0x190
-#define                CODA_ROT_MIR_ENABLE                             (1 << 4)
-#define                CODA_ROT_0                                      (0x0 << 0)
-#define                CODA_ROT_90                                     (0x1 << 0)
-#define                CODA_ROT_180                                    (0x2 << 0)
-#define                CODA_ROT_270                                    (0x3 << 0)
-#define                CODA_MIR_NONE                                   (0x0 << 2)
-#define                CODA_MIR_VER                                    (0x1 << 2)
-#define                CODA_MIR_HOR                                    (0x2 << 2)
-#define                CODA_MIR_VER_HOR                                (0x3 << 2)
-#define CODA_CMD_ENC_PIC_OPTION                0x194
-#define                CODA_FORCE_IPICTURE                             BIT(1)
-#define                CODA_REPORT_MB_INFO                             BIT(3)
-#define                CODA_REPORT_MV_INFO                             BIT(4)
-#define                CODA_REPORT_SLICE_INFO                          BIT(5)
-#define CODA_CMD_ENC_PIC_BB_START      0x198
-#define CODA_CMD_ENC_PIC_BB_SIZE       0x19c
-#define CODA_RET_ENC_FRAME_NUM         0x1c0
-#define CODA_RET_ENC_PIC_TYPE          0x1c4
-#define CODA_RET_ENC_PIC_FRAME_IDX     0x1c8
-#define CODA_RET_ENC_PIC_SLICE_NUM     0x1cc
-#define CODA_RET_ENC_PIC_FLAG          0x1d0
-#define CODA_RET_ENC_PIC_SUCCESS       0x1d8
-
-/* Set Frame Buffer */
-#define CODA_CMD_SET_FRAME_BUF_NUM             0x180
-#define CODA_CMD_SET_FRAME_BUF_STRIDE          0x184
-#define CODA_CMD_SET_FRAME_SLICE_BB_START      0x188
-#define CODA_CMD_SET_FRAME_SLICE_BB_SIZE       0x18c
-#define CODA9_CMD_SET_FRAME_SUBSAMP_A          0x188
-#define CODA9_CMD_SET_FRAME_SUBSAMP_B          0x18c
-#define CODA7_CMD_SET_FRAME_AXI_BIT_ADDR       0x190
-#define CODA7_CMD_SET_FRAME_AXI_IPACDC_ADDR    0x194
-#define CODA7_CMD_SET_FRAME_AXI_DBKY_ADDR      0x198
-#define CODA7_CMD_SET_FRAME_AXI_DBKC_ADDR      0x19c
-#define CODA7_CMD_SET_FRAME_AXI_OVL_ADDR       0x1a0
-#define CODA7_CMD_SET_FRAME_MAX_DEC_SIZE       0x1a4
-#define CODA9_CMD_SET_FRAME_AXI_BTP_ADDR       0x1a4
-#define CODA7_CMD_SET_FRAME_SOURCE_BUF_STRIDE  0x1a8
-#define CODA9_CMD_SET_FRAME_CACHE_SIZE         0x1a8
-#define CODA9_CMD_SET_FRAME_CACHE_CONFIG       0x1ac
-#define                CODA9_CACHE_BYPASS_OFFSET               28
-#define                CODA9_CACHE_DUALCONF_OFFSET             26
-#define                CODA9_CACHE_PAGEMERGE_OFFSET            24
-#define                CODA9_CACHE_LUMA_BUFFER_SIZE_OFFSET     16
-#define                CODA9_CACHE_CB_BUFFER_SIZE_OFFSET       8
-#define                CODA9_CACHE_CR_BUFFER_SIZE_OFFSET       0
-#define CODA9_CMD_SET_FRAME_SUBSAMP_A_MVC      0x1b0
-#define CODA9_CMD_SET_FRAME_SUBSAMP_B_MVC      0x1b4
-#define CODA9_CMD_SET_FRAME_DP_BUF_BASE                0x1b0
-#define CODA9_CMD_SET_FRAME_DP_BUF_SIZE                0x1b4
-#define CODA9_CMD_SET_FRAME_MAX_DEC_SIZE       0x1b8
-#define CODA9_CMD_SET_FRAME_DELAY              0x1bc
-
-/* Encoder Header */
-#define CODA_CMD_ENC_HEADER_CODE       0x180
-#define                CODA_GAMMA_OFFSET       0
-#define                CODA_HEADER_H264_SPS    0
-#define                CODA_HEADER_H264_PPS    1
-#define                CODA_HEADER_MP4V_VOL    0
-#define                CODA_HEADER_MP4V_VOS    1
-#define                CODA_HEADER_MP4V_VIS    2
-#define                CODA9_HEADER_FRAME_CROP (1 << 3)
-#define CODA_CMD_ENC_HEADER_BB_START   0x184
-#define CODA_CMD_ENC_HEADER_BB_SIZE    0x188
-#define CODA9_CMD_ENC_HEADER_FRAME_CROP_H      0x18c
-#define CODA9_CMD_ENC_HEADER_FRAME_CROP_V      0x190
-
-/* Get Version */
-#define CODA_CMD_FIRMWARE_VERNUM               0x1c0
-#define                CODA_FIRMWARE_PRODUCT(x)        (((x) >> 16) & 0xffff)
-#define                CODA_FIRMWARE_MAJOR(x)          (((x) >> 12) & 0x0f)
-#define                CODA_FIRMWARE_MINOR(x)          (((x) >> 8) & 0x0f)
-#define                CODA_FIRMWARE_RELEASE(x)        ((x) & 0xff)
-#define                CODA_FIRMWARE_VERNUM(product, major, minor, release)    \
-                       ((product) << 16 | ((major) << 12) |            \
-                       ((minor) << 8) | (release))
-#define CODA9_CMD_FIRMWARE_CODE_REV            0x1c4
-
-#define CODA9_GDMA_BASE                                0x1000
-#define CODA9_GDI_WPROT_ERR_CLR                        (CODA9_GDMA_BASE + 0x0a0)
-#define CODA9_GDI_WPROT_RGN_EN                 (CODA9_GDMA_BASE + 0x0ac)
-
-#define CODA9_GDI_BUS_CTRL                     (CODA9_GDMA_BASE + 0x0f0)
-#define CODA9_GDI_BUS_STATUS                   (CODA9_GDMA_BASE + 0x0f4)
-
-#define CODA9_GDI_XY2_CAS_0                    (CODA9_GDMA_BASE + 0x800)
-#define CODA9_GDI_XY2_CAS_F                    (CODA9_GDMA_BASE + 0x83c)
-
-#define CODA9_GDI_XY2_BA_0                     (CODA9_GDMA_BASE + 0x840)
-#define CODA9_GDI_XY2_BA_1                     (CODA9_GDMA_BASE + 0x844)
-#define CODA9_GDI_XY2_BA_2                     (CODA9_GDMA_BASE + 0x848)
-#define CODA9_GDI_XY2_BA_3                     (CODA9_GDMA_BASE + 0x84c)
-
-#define CODA9_GDI_XY2_RAS_0                    (CODA9_GDMA_BASE + 0x850)
-#define CODA9_GDI_XY2_RAS_F                    (CODA9_GDMA_BASE + 0x88c)
-
-#define CODA9_GDI_XY2_RBC_CONFIG               (CODA9_GDMA_BASE + 0x890)
-#define CODA9_GDI_RBC2_AXI_0                   (CODA9_GDMA_BASE + 0x8a0)
-#define CODA9_GDI_RBC2_AXI_1F                  (CODA9_GDMA_BASE + 0x91c)
-
-#endif
diff --git a/drivers/media/platform/coda/Makefile b/drivers/media/platform/coda/Makefile
new file mode 100644 (file)
index 0000000..3543291
--- /dev/null
@@ -0,0 +1,3 @@
+coda-objs := coda-common.o coda-bit.o coda-h264.o
+
+obj-$(CONFIG_VIDEO_CODA) += coda.o
diff --git a/drivers/media/platform/coda/coda-bit.c b/drivers/media/platform/coda/coda-bit.c
new file mode 100644 (file)
index 0000000..9b8ea8b
--- /dev/null
@@ -0,0 +1,1861 @@
+/*
+ * Coda multi-standard codec IP - BIT processor functions
+ *
+ * Copyright (C) 2012 Vista Silicon S.L.
+ *    Javier Martin, <javier.martin@vista-silicon.com>
+ *    Xavier Duret
+ * Copyright (C) 2012-2014 Philipp Zabel, Pengutronix
+ *
+ * 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/clk.h>
+#include <linux/irqreturn.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/reset.h>
+#include <linux/slab.h>
+#include <linux/videodev2.h>
+
+#include <media/v4l2-common.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-fh.h>
+#include <media/v4l2-mem2mem.h>
+#include <media/videobuf2-core.h>
+#include <media/videobuf2-dma-contig.h>
+#include <media/videobuf2-vmalloc.h>
+
+#include "coda.h"
+
+#define CODA7_PS_BUF_SIZE      0x28000
+#define CODA9_PS_SAVE_SIZE     (512 * 1024)
+
+#define CODA_DEFAULT_GAMMA     4096
+#define CODA9_DEFAULT_GAMMA    24576   /* 0.75 * 32768 */
+
+static inline int coda_is_initialized(struct coda_dev *dev)
+{
+       return coda_read(dev, CODA_REG_BIT_CUR_PC) != 0;
+}
+
+static inline unsigned long coda_isbusy(struct coda_dev *dev)
+{
+       return coda_read(dev, CODA_REG_BIT_BUSY);
+}
+
+static int coda_wait_timeout(struct coda_dev *dev)
+{
+       unsigned long timeout = jiffies + msecs_to_jiffies(1000);
+
+       while (coda_isbusy(dev)) {
+               if (time_after(jiffies, timeout))
+                       return -ETIMEDOUT;
+       }
+       return 0;
+}
+
+static void coda_command_async(struct coda_ctx *ctx, int cmd)
+{
+       struct coda_dev *dev = ctx->dev;
+
+       if (dev->devtype->product == CODA_960 ||
+           dev->devtype->product == CODA_7541) {
+               /* Restore context related registers to CODA */
+               coda_write(dev, ctx->bit_stream_param,
+                               CODA_REG_BIT_BIT_STREAM_PARAM);
+               coda_write(dev, ctx->frm_dis_flg,
+                               CODA_REG_BIT_FRM_DIS_FLG(ctx->reg_idx));
+               coda_write(dev, ctx->frame_mem_ctrl,
+                               CODA_REG_BIT_FRAME_MEM_CTRL);
+               coda_write(dev, ctx->workbuf.paddr, CODA_REG_BIT_WORK_BUF_ADDR);
+       }
+
+       if (dev->devtype->product == CODA_960) {
+               coda_write(dev, 1, CODA9_GDI_WPROT_ERR_CLR);
+               coda_write(dev, 0, CODA9_GDI_WPROT_RGN_EN);
+       }
+
+       coda_write(dev, CODA_REG_BIT_BUSY_FLAG, CODA_REG_BIT_BUSY);
+
+       coda_write(dev, ctx->idx, CODA_REG_BIT_RUN_INDEX);
+       coda_write(dev, ctx->params.codec_mode, CODA_REG_BIT_RUN_COD_STD);
+       coda_write(dev, ctx->params.codec_mode_aux, CODA7_REG_BIT_RUN_AUX_STD);
+
+       coda_write(dev, cmd, CODA_REG_BIT_RUN_COMMAND);
+}
+
+static int coda_command_sync(struct coda_ctx *ctx, int cmd)
+{
+       struct coda_dev *dev = ctx->dev;
+
+       coda_command_async(ctx, cmd);
+       return coda_wait_timeout(dev);
+}
+
+int coda_hw_reset(struct coda_ctx *ctx)
+{
+       struct coda_dev *dev = ctx->dev;
+       unsigned long timeout;
+       unsigned int idx;
+       int ret;
+
+       if (!dev->rstc)
+               return -ENOENT;
+
+       idx = coda_read(dev, CODA_REG_BIT_RUN_INDEX);
+
+       if (dev->devtype->product == CODA_960) {
+               timeout = jiffies + msecs_to_jiffies(100);
+               coda_write(dev, 0x11, CODA9_GDI_BUS_CTRL);
+               while (coda_read(dev, CODA9_GDI_BUS_STATUS) != 0x77) {
+                       if (time_after(jiffies, timeout))
+                               return -ETIME;
+                       cpu_relax();
+               }
+       }
+
+       ret = reset_control_reset(dev->rstc);
+       if (ret < 0)
+               return ret;
+
+       if (dev->devtype->product == CODA_960)
+               coda_write(dev, 0x00, CODA9_GDI_BUS_CTRL);
+       coda_write(dev, CODA_REG_BIT_BUSY_FLAG, CODA_REG_BIT_BUSY);
+       coda_write(dev, CODA_REG_RUN_ENABLE, CODA_REG_BIT_CODE_RUN);
+       ret = coda_wait_timeout(dev);
+       coda_write(dev, idx, CODA_REG_BIT_RUN_INDEX);
+
+       return ret;
+}
+
+static void coda_kfifo_sync_from_device(struct coda_ctx *ctx)
+{
+       struct __kfifo *kfifo = &ctx->bitstream_fifo.kfifo;
+       struct coda_dev *dev = ctx->dev;
+       u32 rd_ptr;
+
+       rd_ptr = coda_read(dev, CODA_REG_BIT_RD_PTR(ctx->reg_idx));
+       kfifo->out = (kfifo->in & ~kfifo->mask) |
+                     (rd_ptr - ctx->bitstream.paddr);
+       if (kfifo->out > kfifo->in)
+               kfifo->out -= kfifo->mask + 1;
+}
+
+static void coda_kfifo_sync_to_device_full(struct coda_ctx *ctx)
+{
+       struct __kfifo *kfifo = &ctx->bitstream_fifo.kfifo;
+       struct coda_dev *dev = ctx->dev;
+       u32 rd_ptr, wr_ptr;
+
+       rd_ptr = ctx->bitstream.paddr + (kfifo->out & kfifo->mask);
+       coda_write(dev, rd_ptr, CODA_REG_BIT_RD_PTR(ctx->reg_idx));
+       wr_ptr = ctx->bitstream.paddr + (kfifo->in & kfifo->mask);
+       coda_write(dev, wr_ptr, CODA_REG_BIT_WR_PTR(ctx->reg_idx));
+}
+
+static void coda_kfifo_sync_to_device_write(struct coda_ctx *ctx)
+{
+       struct __kfifo *kfifo = &ctx->bitstream_fifo.kfifo;
+       struct coda_dev *dev = ctx->dev;
+       u32 wr_ptr;
+
+       wr_ptr = ctx->bitstream.paddr + (kfifo->in & kfifo->mask);
+       coda_write(dev, wr_ptr, CODA_REG_BIT_WR_PTR(ctx->reg_idx));
+}
+
+static int coda_bitstream_queue(struct coda_ctx *ctx,
+                               struct vb2_buffer *src_buf)
+{
+       u32 src_size = vb2_get_plane_payload(src_buf, 0);
+       u32 n;
+
+       n = kfifo_in(&ctx->bitstream_fifo, vb2_plane_vaddr(src_buf, 0),
+                    src_size);
+       if (n < src_size)
+               return -ENOSPC;
+
+       dma_sync_single_for_device(&ctx->dev->plat_dev->dev,
+                                  ctx->bitstream.paddr, ctx->bitstream.size,
+                                  DMA_TO_DEVICE);
+
+       src_buf->v4l2_buf.sequence = ctx->qsequence++;
+
+       return 0;
+}
+
+static bool coda_bitstream_try_queue(struct coda_ctx *ctx,
+                                    struct vb2_buffer *src_buf)
+{
+       int ret;
+
+       if (coda_get_bitstream_payload(ctx) +
+           vb2_get_plane_payload(src_buf, 0) + 512 >= ctx->bitstream.size)
+               return false;
+
+       if (vb2_plane_vaddr(src_buf, 0) == NULL) {
+               v4l2_err(&ctx->dev->v4l2_dev, "trying to queue empty buffer\n");
+               return true;
+       }
+
+       ret = coda_bitstream_queue(ctx, src_buf);
+       if (ret < 0) {
+               v4l2_err(&ctx->dev->v4l2_dev, "bitstream buffer overflow\n");
+               return false;
+       }
+       /* Sync read pointer to device */
+       if (ctx == v4l2_m2m_get_curr_priv(ctx->dev->m2m_dev))
+               coda_kfifo_sync_to_device_write(ctx);
+
+       ctx->hold = false;
+
+       return true;
+}
+
+void coda_fill_bitstream(struct coda_ctx *ctx)
+{
+       struct vb2_buffer *src_buf;
+       struct coda_timestamp *ts;
+
+       while (v4l2_m2m_num_src_bufs_ready(ctx->fh.m2m_ctx) > 0) {
+               src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
+
+               if (coda_bitstream_try_queue(ctx, src_buf)) {
+                       /*
+                        * Source buffer is queued in the bitstream ringbuffer;
+                        * queue the timestamp and mark source buffer as done
+                        */
+                       src_buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
+
+                       ts = kmalloc(sizeof(*ts), GFP_KERNEL);
+                       if (ts) {
+                               ts->sequence = src_buf->v4l2_buf.sequence;
+                               ts->timecode = src_buf->v4l2_buf.timecode;
+                               ts->timestamp = src_buf->v4l2_buf.timestamp;
+                               list_add_tail(&ts->list, &ctx->timestamp_list);
+                       }
+
+                       v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_DONE);
+               } else {
+                       break;
+               }
+       }
+}
+
+void coda_bit_stream_end_flag(struct coda_ctx *ctx)
+{
+       struct coda_dev *dev = ctx->dev;
+
+       ctx->bit_stream_param |= CODA_BIT_STREAM_END_FLAG;
+
+       /* If this context is currently running, update the hardware flag */
+       if ((dev->devtype->product == CODA_960) &&
+           coda_isbusy(dev) &&
+           (ctx->idx == coda_read(dev, CODA_REG_BIT_RUN_INDEX))) {
+               coda_write(dev, ctx->bit_stream_param,
+                          CODA_REG_BIT_BIT_STREAM_PARAM);
+       }
+}
+
+static void coda_parabuf_write(struct coda_ctx *ctx, int index, u32 value)
+{
+       struct coda_dev *dev = ctx->dev;
+       u32 *p = ctx->parabuf.vaddr;
+
+       if (dev->devtype->product == CODA_DX6)
+               p[index] = value;
+       else
+               p[index ^ 1] = value;
+}
+
+static void coda_free_framebuffers(struct coda_ctx *ctx)
+{
+       int i;
+
+       for (i = 0; i < CODA_MAX_FRAMEBUFFERS; i++)
+               coda_free_aux_buf(ctx->dev, &ctx->internal_frames[i]);
+}
+
+static int coda_alloc_framebuffers(struct coda_ctx *ctx,
+                                  struct coda_q_data *q_data, u32 fourcc)
+{
+       struct coda_dev *dev = ctx->dev;
+       int width, height;
+       dma_addr_t paddr;
+       int ysize;
+       int ret;
+       int i;
+
+       if (ctx->codec && (ctx->codec->src_fourcc == V4L2_PIX_FMT_H264 ||
+            ctx->codec->dst_fourcc == V4L2_PIX_FMT_H264)) {
+               width = round_up(q_data->width, 16);
+               height = round_up(q_data->height, 16);
+       } else {
+               width = round_up(q_data->width, 8);
+               height = q_data->height;
+       }
+       ysize = width * height;
+
+       /* Allocate frame buffers */
+       for (i = 0; i < ctx->num_internal_frames; i++) {
+               size_t size;
+               char *name;
+
+               size = ysize + ysize / 2;
+               if (ctx->codec->src_fourcc == V4L2_PIX_FMT_H264 &&
+                   dev->devtype->product != CODA_DX6)
+                       size += ysize / 4;
+               name = kasprintf(GFP_KERNEL, "fb%d", i);
+               ret = coda_alloc_context_buf(ctx, &ctx->internal_frames[i],
+                                            size, name);
+               kfree(name);
+               if (ret < 0) {
+                       coda_free_framebuffers(ctx);
+                       return ret;
+               }
+       }
+
+       /* Register frame buffers in the parameter buffer */
+       for (i = 0; i < ctx->num_internal_frames; i++) {
+               paddr = ctx->internal_frames[i].paddr;
+               /* Start addresses of Y, Cb, Cr planes */
+               coda_parabuf_write(ctx, i * 3 + 0, paddr);
+               coda_parabuf_write(ctx, i * 3 + 1, paddr + ysize);
+               coda_parabuf_write(ctx, i * 3 + 2, paddr + ysize + ysize / 4);
+
+               /* mvcol buffer for h.264 */
+               if (ctx->codec->src_fourcc == V4L2_PIX_FMT_H264 &&
+                   dev->devtype->product != CODA_DX6)
+                       coda_parabuf_write(ctx, 96 + i,
+                                          ctx->internal_frames[i].paddr +
+                                          ysize + ysize/4 + ysize/4);
+       }
+
+       /* mvcol buffer for mpeg4 */
+       if ((dev->devtype->product != CODA_DX6) &&
+           (ctx->codec->src_fourcc == V4L2_PIX_FMT_MPEG4))
+               coda_parabuf_write(ctx, 97, ctx->internal_frames[i].paddr +
+                                           ysize + ysize/4 + ysize/4);
+
+       return 0;
+}
+
+static void coda_free_context_buffers(struct coda_ctx *ctx)
+{
+       struct coda_dev *dev = ctx->dev;
+
+       coda_free_aux_buf(dev, &ctx->slicebuf);
+       coda_free_aux_buf(dev, &ctx->psbuf);
+       if (dev->devtype->product != CODA_DX6)
+               coda_free_aux_buf(dev, &ctx->workbuf);
+}
+
+static int coda_alloc_context_buffers(struct coda_ctx *ctx,
+                                     struct coda_q_data *q_data)
+{
+       struct coda_dev *dev = ctx->dev;
+       size_t size;
+       int ret;
+
+       if (dev->devtype->product == CODA_DX6)
+               return 0;
+
+       if (ctx->psbuf.vaddr) {
+               v4l2_err(&dev->v4l2_dev, "psmembuf still allocated\n");
+               return -EBUSY;
+       }
+       if (ctx->slicebuf.vaddr) {
+               v4l2_err(&dev->v4l2_dev, "slicebuf still allocated\n");
+               return -EBUSY;
+       }
+       if (ctx->workbuf.vaddr) {
+               v4l2_err(&dev->v4l2_dev, "context buffer still allocated\n");
+               ret = -EBUSY;
+               return -ENOMEM;
+       }
+
+       if (q_data->fourcc == V4L2_PIX_FMT_H264) {
+               /* worst case slice size */
+               size = (DIV_ROUND_UP(q_data->width, 16) *
+                       DIV_ROUND_UP(q_data->height, 16)) * 3200 / 8 + 512;
+               ret = coda_alloc_context_buf(ctx, &ctx->slicebuf, size,
+                                            "slicebuf");
+               if (ret < 0) {
+                       v4l2_err(&dev->v4l2_dev,
+                                "failed to allocate %d byte slice buffer",
+                                ctx->slicebuf.size);
+                       return ret;
+               }
+       }
+
+       if (dev->devtype->product == CODA_7541) {
+               ret = coda_alloc_context_buf(ctx, &ctx->psbuf,
+                                            CODA7_PS_BUF_SIZE, "psbuf");
+               if (ret < 0) {
+                       v4l2_err(&dev->v4l2_dev,
+                                "failed to allocate psmem buffer");
+                       goto err;
+               }
+       }
+
+       size = dev->devtype->workbuf_size;
+       if (dev->devtype->product == CODA_960 &&
+           q_data->fourcc == V4L2_PIX_FMT_H264)
+               size += CODA9_PS_SAVE_SIZE;
+       ret = coda_alloc_context_buf(ctx, &ctx->workbuf, size, "workbuf");
+       if (ret < 0) {
+               v4l2_err(&dev->v4l2_dev,
+                        "failed to allocate %d byte context buffer",
+                        ctx->workbuf.size);
+               goto err;
+       }
+
+       return 0;
+
+err:
+       coda_free_context_buffers(ctx);
+       return ret;
+}
+
+static int coda_encode_header(struct coda_ctx *ctx, struct vb2_buffer *buf,
+                             int header_code, u8 *header, int *size)
+{
+       struct coda_dev *dev = ctx->dev;
+       size_t bufsize;
+       int ret;
+       int i;
+
+       if (dev->devtype->product == CODA_960)
+               memset(vb2_plane_vaddr(buf, 0), 0, 64);
+
+       coda_write(dev, vb2_dma_contig_plane_dma_addr(buf, 0),
+                  CODA_CMD_ENC_HEADER_BB_START);
+       bufsize = vb2_plane_size(buf, 0);
+       if (dev->devtype->product == CODA_960)
+               bufsize /= 1024;
+       coda_write(dev, bufsize, CODA_CMD_ENC_HEADER_BB_SIZE);
+       coda_write(dev, header_code, CODA_CMD_ENC_HEADER_CODE);
+       ret = coda_command_sync(ctx, CODA_COMMAND_ENCODE_HEADER);
+       if (ret < 0) {
+               v4l2_err(&dev->v4l2_dev, "CODA_COMMAND_ENCODE_HEADER timeout\n");
+               return ret;
+       }
+
+       if (dev->devtype->product == CODA_960) {
+               for (i = 63; i > 0; i--)
+                       if (((char *)vb2_plane_vaddr(buf, 0))[i] != 0)
+                               break;
+               *size = i + 1;
+       } else {
+               *size = coda_read(dev, CODA_REG_BIT_WR_PTR(ctx->reg_idx)) -
+                       coda_read(dev, CODA_CMD_ENC_HEADER_BB_START);
+       }
+       memcpy(header, vb2_plane_vaddr(buf, 0), *size);
+
+       return 0;
+}
+
+static phys_addr_t coda_iram_alloc(struct coda_iram_info *iram, size_t size)
+{
+       phys_addr_t ret;
+
+       size = round_up(size, 1024);
+       if (size > iram->remaining)
+               return 0;
+       iram->remaining -= size;
+
+       ret = iram->next_paddr;
+       iram->next_paddr += size;
+
+       return ret;
+}
+
+static void coda_setup_iram(struct coda_ctx *ctx)
+{
+       struct coda_iram_info *iram_info = &ctx->iram_info;
+       struct coda_dev *dev = ctx->dev;
+       int w64, w128;
+       int mb_width;
+       int dbk_bits;
+       int bit_bits;
+       int ip_bits;
+
+       memset(iram_info, 0, sizeof(*iram_info));
+       iram_info->next_paddr = dev->iram.paddr;
+       iram_info->remaining = dev->iram.size;
+
+       if (!dev->iram.vaddr)
+               return;
+
+       switch (dev->devtype->product) {
+       case CODA_7541:
+               dbk_bits = CODA7_USE_HOST_DBK_ENABLE | CODA7_USE_DBK_ENABLE;
+               bit_bits = CODA7_USE_HOST_BIT_ENABLE | CODA7_USE_BIT_ENABLE;
+               ip_bits = CODA7_USE_HOST_IP_ENABLE | CODA7_USE_IP_ENABLE;
+               break;
+       case CODA_960:
+               dbk_bits = CODA9_USE_HOST_DBK_ENABLE | CODA9_USE_DBK_ENABLE;
+               bit_bits = CODA9_USE_HOST_BIT_ENABLE | CODA7_USE_BIT_ENABLE;
+               ip_bits = CODA9_USE_HOST_IP_ENABLE | CODA7_USE_IP_ENABLE;
+               break;
+       default: /* CODA_DX6 */
+               return;
+       }
+
+       if (ctx->inst_type == CODA_INST_ENCODER) {
+               struct coda_q_data *q_data_src;
+
+               q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
+               mb_width = DIV_ROUND_UP(q_data_src->width, 16);
+               w128 = mb_width * 128;
+               w64 = mb_width * 64;
+
+               /* Prioritize in case IRAM is too small for everything */
+               if (dev->devtype->product == CODA_7541) {
+                       iram_info->search_ram_size = round_up(mb_width * 16 *
+                                                             36 + 2048, 1024);
+                       iram_info->search_ram_paddr = coda_iram_alloc(iram_info,
+                                               iram_info->search_ram_size);
+                       if (!iram_info->search_ram_paddr) {
+                               pr_err("IRAM is smaller than the search ram size\n");
+                               goto out;
+                       }
+                       iram_info->axi_sram_use |= CODA7_USE_HOST_ME_ENABLE |
+                                                  CODA7_USE_ME_ENABLE;
+               }
+
+               /* Only H.264BP and H.263P3 are considered */
+               iram_info->buf_dbk_y_use = coda_iram_alloc(iram_info, w64);
+               iram_info->buf_dbk_c_use = coda_iram_alloc(iram_info, w64);
+               if (!iram_info->buf_dbk_c_use)
+                       goto out;
+               iram_info->axi_sram_use |= dbk_bits;
+
+               iram_info->buf_bit_use = coda_iram_alloc(iram_info, w128);
+               if (!iram_info->buf_bit_use)
+                       goto out;
+               iram_info->axi_sram_use |= bit_bits;
+
+               iram_info->buf_ip_ac_dc_use = coda_iram_alloc(iram_info, w128);
+               if (!iram_info->buf_ip_ac_dc_use)
+                       goto out;
+               iram_info->axi_sram_use |= ip_bits;
+
+               /* OVL and BTP disabled for encoder */
+       } else if (ctx->inst_type == CODA_INST_DECODER) {
+               struct coda_q_data *q_data_dst;
+
+               q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE);
+               mb_width = DIV_ROUND_UP(q_data_dst->width, 16);
+               w128 = mb_width * 128;
+
+               iram_info->buf_dbk_y_use = coda_iram_alloc(iram_info, w128);
+               iram_info->buf_dbk_c_use = coda_iram_alloc(iram_info, w128);
+               if (!iram_info->buf_dbk_c_use)
+                       goto out;
+               iram_info->axi_sram_use |= dbk_bits;
+
+               iram_info->buf_bit_use = coda_iram_alloc(iram_info, w128);
+               if (!iram_info->buf_bit_use)
+                       goto out;
+               iram_info->axi_sram_use |= bit_bits;
+
+               iram_info->buf_ip_ac_dc_use = coda_iram_alloc(iram_info, w128);
+               if (!iram_info->buf_ip_ac_dc_use)
+                       goto out;
+               iram_info->axi_sram_use |= ip_bits;
+
+               /* OVL and BTP unused as there is no VC1 support yet */
+       }
+
+out:
+       if (!(iram_info->axi_sram_use & CODA7_USE_HOST_IP_ENABLE))
+               v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev,
+                        "IRAM smaller than needed\n");
+
+       if (dev->devtype->product == CODA_7541) {
+               /* TODO - Enabling these causes picture errors on CODA7541 */
+               if (ctx->inst_type == CODA_INST_DECODER) {
+                       /* fw 1.4.50 */
+                       iram_info->axi_sram_use &= ~(CODA7_USE_HOST_IP_ENABLE |
+                                                    CODA7_USE_IP_ENABLE);
+               } else {
+                       /* fw 13.4.29 */
+                       iram_info->axi_sram_use &= ~(CODA7_USE_HOST_IP_ENABLE |
+                                                    CODA7_USE_HOST_DBK_ENABLE |
+                                                    CODA7_USE_IP_ENABLE |
+                                                    CODA7_USE_DBK_ENABLE);
+               }
+       }
+}
+
+static u32 coda_supported_firmwares[] = {
+       CODA_FIRMWARE_VERNUM(CODA_DX6, 2, 2, 5),
+       CODA_FIRMWARE_VERNUM(CODA_7541, 1, 4, 50),
+       CODA_FIRMWARE_VERNUM(CODA_960, 2, 1, 5),
+};
+
+static bool coda_firmware_supported(u32 vernum)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(coda_supported_firmwares); i++)
+               if (vernum == coda_supported_firmwares[i])
+                       return true;
+       return false;
+}
+
+int coda_check_firmware(struct coda_dev *dev)
+{
+       u16 product, major, minor, release;
+       u32 data;
+       int ret;
+
+       ret = clk_prepare_enable(dev->clk_per);
+       if (ret)
+               goto err_clk_per;
+
+       ret = clk_prepare_enable(dev->clk_ahb);
+       if (ret)
+               goto err_clk_ahb;
+
+       coda_write(dev, 0, CODA_CMD_FIRMWARE_VERNUM);
+       coda_write(dev, CODA_REG_BIT_BUSY_FLAG, CODA_REG_BIT_BUSY);
+       coda_write(dev, 0, CODA_REG_BIT_RUN_INDEX);
+       coda_write(dev, 0, CODA_REG_BIT_RUN_COD_STD);
+       coda_write(dev, CODA_COMMAND_FIRMWARE_GET, CODA_REG_BIT_RUN_COMMAND);
+       if (coda_wait_timeout(dev)) {
+               v4l2_err(&dev->v4l2_dev, "firmware get command error\n");
+               ret = -EIO;
+               goto err_run_cmd;
+       }
+
+       if (dev->devtype->product == CODA_960) {
+               data = coda_read(dev, CODA9_CMD_FIRMWARE_CODE_REV);
+               v4l2_info(&dev->v4l2_dev, "Firmware code revision: %d\n",
+                         data);
+       }
+
+       /* Check we are compatible with the loaded firmware */
+       data = coda_read(dev, CODA_CMD_FIRMWARE_VERNUM);
+       product = CODA_FIRMWARE_PRODUCT(data);
+       major = CODA_FIRMWARE_MAJOR(data);
+       minor = CODA_FIRMWARE_MINOR(data);
+       release = CODA_FIRMWARE_RELEASE(data);
+
+       clk_disable_unprepare(dev->clk_per);
+       clk_disable_unprepare(dev->clk_ahb);
+
+       if (product != dev->devtype->product) {
+               v4l2_err(&dev->v4l2_dev,
+                        "Wrong firmware. Hw: %s, Fw: %s, Version: %u.%u.%u\n",
+                        coda_product_name(dev->devtype->product),
+                        coda_product_name(product), major, minor, release);
+               return -EINVAL;
+       }
+
+       v4l2_info(&dev->v4l2_dev, "Initialized %s.\n",
+                 coda_product_name(product));
+
+       if (coda_firmware_supported(data)) {
+               v4l2_info(&dev->v4l2_dev, "Firmware version: %u.%u.%u\n",
+                         major, minor, release);
+       } else {
+               v4l2_warn(&dev->v4l2_dev,
+                         "Unsupported firmware version: %u.%u.%u\n",
+                         major, minor, release);
+       }
+
+       return 0;
+
+err_run_cmd:
+       clk_disable_unprepare(dev->clk_ahb);
+err_clk_ahb:
+       clk_disable_unprepare(dev->clk_per);
+err_clk_per:
+       return ret;
+}
+
+/*
+ * Encoder context operations
+ */
+
+static int coda_start_encoding(struct coda_ctx *ctx)
+{
+       struct coda_dev *dev = ctx->dev;
+       struct v4l2_device *v4l2_dev = &dev->v4l2_dev;
+       struct coda_q_data *q_data_src, *q_data_dst;
+       u32 bitstream_buf, bitstream_size;
+       struct vb2_buffer *buf;
+       int gamma, ret, value;
+       u32 dst_fourcc;
+
+       q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
+       q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE);
+       dst_fourcc = q_data_dst->fourcc;
+
+       /* Allocate per-instance buffers */
+       ret = coda_alloc_context_buffers(ctx, q_data_src);
+       if (ret < 0)
+               return ret;
+
+       buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
+       bitstream_buf = vb2_dma_contig_plane_dma_addr(buf, 0);
+       bitstream_size = q_data_dst->sizeimage;
+
+       if (!coda_is_initialized(dev)) {
+               v4l2_err(v4l2_dev, "coda is not initialized.\n");
+               return -EFAULT;
+       }
+
+       mutex_lock(&dev->coda_mutex);
+
+       coda_write(dev, ctx->parabuf.paddr, CODA_REG_BIT_PARA_BUF_ADDR);
+       coda_write(dev, bitstream_buf, CODA_REG_BIT_RD_PTR(ctx->reg_idx));
+       coda_write(dev, bitstream_buf, CODA_REG_BIT_WR_PTR(ctx->reg_idx));
+       switch (dev->devtype->product) {
+       case CODA_DX6:
+               coda_write(dev, CODADX6_STREAM_BUF_DYNALLOC_EN |
+                       CODADX6_STREAM_BUF_PIC_RESET, CODA_REG_BIT_STREAM_CTRL);
+               break;
+       case CODA_960:
+               coda_write(dev, 0, CODA9_GDI_WPROT_RGN_EN);
+               /* fallthrough */
+       case CODA_7541:
+               coda_write(dev, CODA7_STREAM_BUF_DYNALLOC_EN |
+                       CODA7_STREAM_BUF_PIC_RESET, CODA_REG_BIT_STREAM_CTRL);
+               break;
+       }
+
+       value = coda_read(dev, CODA_REG_BIT_FRAME_MEM_CTRL);
+       value &= ~(1 << 2 | 0x7 << 9);
+       ctx->frame_mem_ctrl = value;
+       coda_write(dev, value, CODA_REG_BIT_FRAME_MEM_CTRL);
+
+       if (dev->devtype->product == CODA_DX6) {
+               /* Configure the coda */
+               coda_write(dev, dev->iram.paddr,
+                          CODADX6_REG_BIT_SEARCH_RAM_BASE_ADDR);
+       }
+
+       /* Could set rotation here if needed */
+       switch (dev->devtype->product) {
+       case CODA_DX6:
+               value = (q_data_src->width & CODADX6_PICWIDTH_MASK)
+                       << CODADX6_PICWIDTH_OFFSET;
+               value |= (q_data_src->height & CODADX6_PICHEIGHT_MASK)
+                        << CODA_PICHEIGHT_OFFSET;
+               break;
+       case CODA_7541:
+               if (dst_fourcc == V4L2_PIX_FMT_H264) {
+                       value = (round_up(q_data_src->width, 16) &
+                                CODA7_PICWIDTH_MASK) << CODA7_PICWIDTH_OFFSET;
+                       value |= (round_up(q_data_src->height, 16) &
+                                CODA7_PICHEIGHT_MASK) << CODA_PICHEIGHT_OFFSET;
+                       break;
+               }
+               /* fallthrough */
+       case CODA_960:
+               value = (q_data_src->width & CODA7_PICWIDTH_MASK)
+                       << CODA7_PICWIDTH_OFFSET;
+               value |= (q_data_src->height & CODA7_PICHEIGHT_MASK)
+                        << CODA_PICHEIGHT_OFFSET;
+       }
+       coda_write(dev, value, CODA_CMD_ENC_SEQ_SRC_SIZE);
+       coda_write(dev, ctx->params.framerate,
+                  CODA_CMD_ENC_SEQ_SRC_F_RATE);
+
+       ctx->params.codec_mode = ctx->codec->mode;
+       switch (dst_fourcc) {
+       case V4L2_PIX_FMT_MPEG4:
+               if (dev->devtype->product == CODA_960)
+                       coda_write(dev, CODA9_STD_MPEG4,
+                                  CODA_CMD_ENC_SEQ_COD_STD);
+               else
+                       coda_write(dev, CODA_STD_MPEG4,
+                                  CODA_CMD_ENC_SEQ_COD_STD);
+               coda_write(dev, 0, CODA_CMD_ENC_SEQ_MP4_PARA);
+               break;
+       case V4L2_PIX_FMT_H264:
+               if (dev->devtype->product == CODA_960)
+                       coda_write(dev, CODA9_STD_H264,
+                                  CODA_CMD_ENC_SEQ_COD_STD);
+               else
+                       coda_write(dev, CODA_STD_H264,
+                                  CODA_CMD_ENC_SEQ_COD_STD);
+               if (ctx->params.h264_deblk_enabled) {
+                       value = ((ctx->params.h264_deblk_alpha &
+                                 CODA_264PARAM_DEBLKFILTEROFFSETALPHA_MASK) <<
+                                CODA_264PARAM_DEBLKFILTEROFFSETALPHA_OFFSET) |
+                               ((ctx->params.h264_deblk_beta &
+                                 CODA_264PARAM_DEBLKFILTEROFFSETBETA_MASK) <<
+                                CODA_264PARAM_DEBLKFILTEROFFSETBETA_OFFSET);
+               } else {
+                       value = 1 << CODA_264PARAM_DISABLEDEBLK_OFFSET;
+               }
+               coda_write(dev, value, CODA_CMD_ENC_SEQ_264_PARA);
+               break;
+       default:
+               v4l2_err(v4l2_dev,
+                        "dst format (0x%08x) invalid.\n", dst_fourcc);
+               ret = -EINVAL;
+               goto out;
+       }
+
+       switch (ctx->params.slice_mode) {
+       case V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE:
+               value = 0;
+               break;
+       case V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_MB:
+               value  = (ctx->params.slice_max_mb & CODA_SLICING_SIZE_MASK)
+                        << CODA_SLICING_SIZE_OFFSET;
+               value |= (1 & CODA_SLICING_UNIT_MASK)
+                        << CODA_SLICING_UNIT_OFFSET;
+               value |=  1 & CODA_SLICING_MODE_MASK;
+               break;
+       case V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_BYTES:
+               value  = (ctx->params.slice_max_bits & CODA_SLICING_SIZE_MASK)
+                        << CODA_SLICING_SIZE_OFFSET;
+               value |= (0 & CODA_SLICING_UNIT_MASK)
+                        << CODA_SLICING_UNIT_OFFSET;
+               value |=  1 & CODA_SLICING_MODE_MASK;
+               break;
+       }
+       coda_write(dev, value, CODA_CMD_ENC_SEQ_SLICE_MODE);
+       value = ctx->params.gop_size & CODA_GOP_SIZE_MASK;
+       coda_write(dev, value, CODA_CMD_ENC_SEQ_GOP_SIZE);
+
+       if (ctx->params.bitrate) {
+               /* Rate control enabled */
+               value = (ctx->params.bitrate & CODA_RATECONTROL_BITRATE_MASK)
+                       << CODA_RATECONTROL_BITRATE_OFFSET;
+               value |=  1 & CODA_RATECONTROL_ENABLE_MASK;
+               if (dev->devtype->product == CODA_960)
+                       value |= BIT(31); /* disable autoskip */
+       } else {
+               value = 0;
+       }
+       coda_write(dev, value, CODA_CMD_ENC_SEQ_RC_PARA);
+
+       coda_write(dev, 0, CODA_CMD_ENC_SEQ_RC_BUF_SIZE);
+       coda_write(dev, ctx->params.intra_refresh,
+                  CODA_CMD_ENC_SEQ_INTRA_REFRESH);
+
+       coda_write(dev, bitstream_buf, CODA_CMD_ENC_SEQ_BB_START);
+       coda_write(dev, bitstream_size / 1024, CODA_CMD_ENC_SEQ_BB_SIZE);
+
+
+       value = 0;
+       if (dev->devtype->product == CODA_960)
+               gamma = CODA9_DEFAULT_GAMMA;
+       else
+               gamma = CODA_DEFAULT_GAMMA;
+       if (gamma > 0) {
+               coda_write(dev, (gamma & CODA_GAMMA_MASK) << CODA_GAMMA_OFFSET,
+                          CODA_CMD_ENC_SEQ_RC_GAMMA);
+       }
+
+       if (ctx->params.h264_min_qp || ctx->params.h264_max_qp) {
+               coda_write(dev,
+                          ctx->params.h264_min_qp << CODA_QPMIN_OFFSET |
+                          ctx->params.h264_max_qp << CODA_QPMAX_OFFSET,
+                          CODA_CMD_ENC_SEQ_RC_QP_MIN_MAX);
+       }
+       if (dev->devtype->product == CODA_960) {
+               if (ctx->params.h264_max_qp)
+                       value |= 1 << CODA9_OPTION_RCQPMAX_OFFSET;
+               if (CODA_DEFAULT_GAMMA > 0)
+                       value |= 1 << CODA9_OPTION_GAMMA_OFFSET;
+       } else {
+               if (CODA_DEFAULT_GAMMA > 0) {
+                       if (dev->devtype->product == CODA_DX6)
+                               value |= 1 << CODADX6_OPTION_GAMMA_OFFSET;
+                       else
+                               value |= 1 << CODA7_OPTION_GAMMA_OFFSET;
+               }
+               if (ctx->params.h264_min_qp)
+                       value |= 1 << CODA7_OPTION_RCQPMIN_OFFSET;
+               if (ctx->params.h264_max_qp)
+                       value |= 1 << CODA7_OPTION_RCQPMAX_OFFSET;
+       }
+       coda_write(dev, value, CODA_CMD_ENC_SEQ_OPTION);
+
+       coda_write(dev, 0, CODA_CMD_ENC_SEQ_RC_INTERVAL_MODE);
+
+       coda_setup_iram(ctx);
+
+       if (dst_fourcc == V4L2_PIX_FMT_H264) {
+               switch (dev->devtype->product) {
+               case CODA_DX6:
+                       value = FMO_SLICE_SAVE_BUF_SIZE << 7;
+                       coda_write(dev, value, CODADX6_CMD_ENC_SEQ_FMO);
+                       break;
+               case CODA_7541:
+                       coda_write(dev, ctx->iram_info.search_ram_paddr,
+                                       CODA7_CMD_ENC_SEQ_SEARCH_BASE);
+                       coda_write(dev, ctx->iram_info.search_ram_size,
+                                       CODA7_CMD_ENC_SEQ_SEARCH_SIZE);
+                       break;
+               case CODA_960:
+                       coda_write(dev, 0, CODA9_CMD_ENC_SEQ_ME_OPTION);
+                       coda_write(dev, 0, CODA9_CMD_ENC_SEQ_INTRA_WEIGHT);
+               }
+       }
+
+       ret = coda_command_sync(ctx, CODA_COMMAND_SEQ_INIT);
+       if (ret < 0) {
+               v4l2_err(v4l2_dev, "CODA_COMMAND_SEQ_INIT timeout\n");
+               goto out;
+       }
+
+       if (coda_read(dev, CODA_RET_ENC_SEQ_SUCCESS) == 0) {
+               v4l2_err(v4l2_dev, "CODA_COMMAND_SEQ_INIT failed\n");
+               ret = -EFAULT;
+               goto out;
+       }
+
+       if (dev->devtype->product == CODA_960)
+               ctx->num_internal_frames = 4;
+       else
+               ctx->num_internal_frames = 2;
+       ret = coda_alloc_framebuffers(ctx, q_data_src, dst_fourcc);
+       if (ret < 0) {
+               v4l2_err(v4l2_dev, "failed to allocate framebuffers\n");
+               goto out;
+       }
+
+       coda_write(dev, ctx->num_internal_frames, CODA_CMD_SET_FRAME_BUF_NUM);
+       coda_write(dev, q_data_src->bytesperline,
+                       CODA_CMD_SET_FRAME_BUF_STRIDE);
+       if (dev->devtype->product == CODA_7541) {
+               coda_write(dev, q_data_src->bytesperline,
+                               CODA7_CMD_SET_FRAME_SOURCE_BUF_STRIDE);
+       }
+       if (dev->devtype->product != CODA_DX6) {
+               coda_write(dev, ctx->iram_info.buf_bit_use,
+                               CODA7_CMD_SET_FRAME_AXI_BIT_ADDR);
+               coda_write(dev, ctx->iram_info.buf_ip_ac_dc_use,
+                               CODA7_CMD_SET_FRAME_AXI_IPACDC_ADDR);
+               coda_write(dev, ctx->iram_info.buf_dbk_y_use,
+                               CODA7_CMD_SET_FRAME_AXI_DBKY_ADDR);
+               coda_write(dev, ctx->iram_info.buf_dbk_c_use,
+                               CODA7_CMD_SET_FRAME_AXI_DBKC_ADDR);
+               coda_write(dev, ctx->iram_info.buf_ovl_use,
+                               CODA7_CMD_SET_FRAME_AXI_OVL_ADDR);
+               if (dev->devtype->product == CODA_960) {
+                       coda_write(dev, ctx->iram_info.buf_btp_use,
+                                       CODA9_CMD_SET_FRAME_AXI_BTP_ADDR);
+
+                       /* FIXME */
+                       coda_write(dev, ctx->internal_frames[2].paddr,
+                                  CODA9_CMD_SET_FRAME_SUBSAMP_A);
+                       coda_write(dev, ctx->internal_frames[3].paddr,
+                                  CODA9_CMD_SET_FRAME_SUBSAMP_B);
+               }
+       }
+
+       ret = coda_command_sync(ctx, CODA_COMMAND_SET_FRAME_BUF);
+       if (ret < 0) {
+               v4l2_err(v4l2_dev, "CODA_COMMAND_SET_FRAME_BUF timeout\n");
+               goto out;
+       }
+
+       /* Save stream headers */
+       buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
+       switch (dst_fourcc) {
+       case V4L2_PIX_FMT_H264:
+               /*
+                * Get SPS in the first frame and copy it to an
+                * intermediate buffer.
+                */
+               ret = coda_encode_header(ctx, buf, CODA_HEADER_H264_SPS,
+                                        &ctx->vpu_header[0][0],
+                                        &ctx->vpu_header_size[0]);
+               if (ret < 0)
+                       goto out;
+
+               /*
+                * Get PPS in the first frame and copy it to an
+                * intermediate buffer.
+                */
+               ret = coda_encode_header(ctx, buf, CODA_HEADER_H264_PPS,
+                                        &ctx->vpu_header[1][0],
+                                        &ctx->vpu_header_size[1]);
+               if (ret < 0)
+                       goto out;
+
+               /*
+                * Length of H.264 headers is variable and thus it might not be
+                * aligned for the coda to append the encoded frame. In that is
+                * the case a filler NAL must be added to header 2.
+                */
+               ctx->vpu_header_size[2] = coda_h264_padding(
+                                       (ctx->vpu_header_size[0] +
+                                        ctx->vpu_header_size[1]),
+                                        ctx->vpu_header[2]);
+               break;
+       case V4L2_PIX_FMT_MPEG4:
+               /*
+                * Get VOS in the first frame and copy it to an
+                * intermediate buffer
+                */
+               ret = coda_encode_header(ctx, buf, CODA_HEADER_MP4V_VOS,
+                                        &ctx->vpu_header[0][0],
+                                        &ctx->vpu_header_size[0]);
+               if (ret < 0)
+                       goto out;
+
+               ret = coda_encode_header(ctx, buf, CODA_HEADER_MP4V_VIS,
+                                        &ctx->vpu_header[1][0],
+                                        &ctx->vpu_header_size[1]);
+               if (ret < 0)
+                       goto out;
+
+               ret = coda_encode_header(ctx, buf, CODA_HEADER_MP4V_VOL,
+                                        &ctx->vpu_header[2][0],
+                                        &ctx->vpu_header_size[2]);
+               if (ret < 0)
+                       goto out;
+               break;
+       default:
+               /* No more formats need to save headers at the moment */
+               break;
+       }
+
+out:
+       mutex_unlock(&dev->coda_mutex);
+       return ret;
+}
+
+static int coda_prepare_encode(struct coda_ctx *ctx)
+{
+       struct coda_q_data *q_data_src, *q_data_dst;
+       struct vb2_buffer *src_buf, *dst_buf;
+       struct coda_dev *dev = ctx->dev;
+       int force_ipicture;
+       int quant_param = 0;
+       u32 picture_y, picture_cb, picture_cr;
+       u32 pic_stream_buffer_addr, pic_stream_buffer_size;
+       u32 dst_fourcc;
+
+       src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
+       dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
+       q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
+       q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE);
+       dst_fourcc = q_data_dst->fourcc;
+
+       src_buf->v4l2_buf.sequence = ctx->osequence;
+       dst_buf->v4l2_buf.sequence = ctx->osequence;
+       ctx->osequence++;
+
+       /*
+        * Workaround coda firmware BUG that only marks the first
+        * frame as IDR. This is a problem for some decoders that can't
+        * recover when a frame is lost.
+        */
+       if (src_buf->v4l2_buf.sequence % ctx->params.gop_size) {
+               src_buf->v4l2_buf.flags |= V4L2_BUF_FLAG_PFRAME;
+               src_buf->v4l2_buf.flags &= ~V4L2_BUF_FLAG_KEYFRAME;
+       } else {
+               src_buf->v4l2_buf.flags |= V4L2_BUF_FLAG_KEYFRAME;
+               src_buf->v4l2_buf.flags &= ~V4L2_BUF_FLAG_PFRAME;
+       }
+
+       if (dev->devtype->product == CODA_960)
+               coda_set_gdi_regs(ctx);
+
+       /*
+        * Copy headers at the beginning of the first frame for H.264 only.
+        * In MPEG4 they are already copied by the coda.
+        */
+       if (src_buf->v4l2_buf.sequence == 0) {
+               pic_stream_buffer_addr =
+                       vb2_dma_contig_plane_dma_addr(dst_buf, 0) +
+                       ctx->vpu_header_size[0] +
+                       ctx->vpu_header_size[1] +
+                       ctx->vpu_header_size[2];
+               pic_stream_buffer_size = CODA_MAX_FRAME_SIZE -
+                       ctx->vpu_header_size[0] -
+                       ctx->vpu_header_size[1] -
+                       ctx->vpu_header_size[2];
+               memcpy(vb2_plane_vaddr(dst_buf, 0),
+                      &ctx->vpu_header[0][0], ctx->vpu_header_size[0]);
+               memcpy(vb2_plane_vaddr(dst_buf, 0) + ctx->vpu_header_size[0],
+                      &ctx->vpu_header[1][0], ctx->vpu_header_size[1]);
+               memcpy(vb2_plane_vaddr(dst_buf, 0) + ctx->vpu_header_size[0] +
+                       ctx->vpu_header_size[1], &ctx->vpu_header[2][0],
+                       ctx->vpu_header_size[2]);
+       } else {
+               pic_stream_buffer_addr =
+                       vb2_dma_contig_plane_dma_addr(dst_buf, 0);
+               pic_stream_buffer_size = CODA_MAX_FRAME_SIZE;
+       }
+
+       if (src_buf->v4l2_buf.flags & V4L2_BUF_FLAG_KEYFRAME) {
+               force_ipicture = 1;
+               switch (dst_fourcc) {
+               case V4L2_PIX_FMT_H264:
+                       quant_param = ctx->params.h264_intra_qp;
+                       break;
+               case V4L2_PIX_FMT_MPEG4:
+                       quant_param = ctx->params.mpeg4_intra_qp;
+                       break;
+               default:
+                       v4l2_warn(&ctx->dev->v4l2_dev,
+                               "cannot set intra qp, fmt not supported\n");
+                       break;
+               }
+       } else {
+               force_ipicture = 0;
+               switch (dst_fourcc) {
+               case V4L2_PIX_FMT_H264:
+                       quant_param = ctx->params.h264_inter_qp;
+                       break;
+               case V4L2_PIX_FMT_MPEG4:
+                       quant_param = ctx->params.mpeg4_inter_qp;
+                       break;
+               default:
+                       v4l2_warn(&ctx->dev->v4l2_dev,
+                               "cannot set inter qp, fmt not supported\n");
+                       break;
+               }
+       }
+
+       /* submit */
+       coda_write(dev, CODA_ROT_MIR_ENABLE | ctx->params.rot_mode,
+                  CODA_CMD_ENC_PIC_ROT_MODE);
+       coda_write(dev, quant_param, CODA_CMD_ENC_PIC_QS);
+
+
+       picture_y = vb2_dma_contig_plane_dma_addr(src_buf, 0);
+       switch (q_data_src->fourcc) {
+       case V4L2_PIX_FMT_YVU420:
+               /* Switch Cb and Cr for YVU420 format */
+               picture_cr = picture_y + q_data_src->bytesperline *
+                               q_data_src->height;
+               picture_cb = picture_cr + q_data_src->bytesperline / 2 *
+                               q_data_src->height / 2;
+               break;
+       case V4L2_PIX_FMT_YUV420:
+       default:
+               picture_cb = picture_y + q_data_src->bytesperline *
+                               q_data_src->height;
+               picture_cr = picture_cb + q_data_src->bytesperline / 2 *
+                               q_data_src->height / 2;
+               break;
+       }
+
+       if (dev->devtype->product == CODA_960) {
+               coda_write(dev, 4/*FIXME: 0*/, CODA9_CMD_ENC_PIC_SRC_INDEX);
+               coda_write(dev, q_data_src->width, CODA9_CMD_ENC_PIC_SRC_STRIDE);
+               coda_write(dev, 0, CODA9_CMD_ENC_PIC_SUB_FRAME_SYNC);
+
+               coda_write(dev, picture_y, CODA9_CMD_ENC_PIC_SRC_ADDR_Y);
+               coda_write(dev, picture_cb, CODA9_CMD_ENC_PIC_SRC_ADDR_CB);
+               coda_write(dev, picture_cr, CODA9_CMD_ENC_PIC_SRC_ADDR_CR);
+       } else {
+               coda_write(dev, picture_y, CODA_CMD_ENC_PIC_SRC_ADDR_Y);
+               coda_write(dev, picture_cb, CODA_CMD_ENC_PIC_SRC_ADDR_CB);
+               coda_write(dev, picture_cr, CODA_CMD_ENC_PIC_SRC_ADDR_CR);
+       }
+       coda_write(dev, force_ipicture << 1 & 0x2,
+                  CODA_CMD_ENC_PIC_OPTION);
+
+       coda_write(dev, pic_stream_buffer_addr, CODA_CMD_ENC_PIC_BB_START);
+       coda_write(dev, pic_stream_buffer_size / 1024,
+                  CODA_CMD_ENC_PIC_BB_SIZE);
+
+       if (!ctx->streamon_out) {
+               /* After streamoff on the output side, set stream end flag */
+               ctx->bit_stream_param |= CODA_BIT_STREAM_END_FLAG;
+               coda_write(dev, ctx->bit_stream_param,
+                          CODA_REG_BIT_BIT_STREAM_PARAM);
+       }
+
+       if (dev->devtype->product != CODA_DX6)
+               coda_write(dev, ctx->iram_info.axi_sram_use,
+                               CODA7_REG_BIT_AXI_SRAM_USE);
+
+       coda_command_async(ctx, CODA_COMMAND_PIC_RUN);
+
+       return 0;
+}
+
+static void coda_finish_encode(struct coda_ctx *ctx)
+{
+       struct vb2_buffer *src_buf, *dst_buf;
+       struct coda_dev *dev = ctx->dev;
+       u32 wr_ptr, start_ptr;
+
+       src_buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
+       dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
+
+       /* Get results from the coda */
+       start_ptr = coda_read(dev, CODA_CMD_ENC_PIC_BB_START);
+       wr_ptr = coda_read(dev, CODA_REG_BIT_WR_PTR(ctx->reg_idx));
+
+       /* Calculate bytesused field */
+       if (dst_buf->v4l2_buf.sequence == 0) {
+               vb2_set_plane_payload(dst_buf, 0, wr_ptr - start_ptr +
+                                       ctx->vpu_header_size[0] +
+                                       ctx->vpu_header_size[1] +
+                                       ctx->vpu_header_size[2]);
+       } else {
+               vb2_set_plane_payload(dst_buf, 0, wr_ptr - start_ptr);
+       }
+
+       v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev, "frame size = %u\n",
+                wr_ptr - start_ptr);
+
+       coda_read(dev, CODA_RET_ENC_PIC_SLICE_NUM);
+       coda_read(dev, CODA_RET_ENC_PIC_FLAG);
+
+       if (coda_read(dev, CODA_RET_ENC_PIC_TYPE) == 0) {
+               dst_buf->v4l2_buf.flags |= V4L2_BUF_FLAG_KEYFRAME;
+               dst_buf->v4l2_buf.flags &= ~V4L2_BUF_FLAG_PFRAME;
+       } else {
+               dst_buf->v4l2_buf.flags |= V4L2_BUF_FLAG_PFRAME;
+               dst_buf->v4l2_buf.flags &= ~V4L2_BUF_FLAG_KEYFRAME;
+       }
+
+       dst_buf->v4l2_buf.timestamp = src_buf->v4l2_buf.timestamp;
+       dst_buf->v4l2_buf.flags &= ~V4L2_BUF_FLAG_TSTAMP_SRC_MASK;
+       dst_buf->v4l2_buf.flags |=
+               src_buf->v4l2_buf.flags & V4L2_BUF_FLAG_TSTAMP_SRC_MASK;
+       dst_buf->v4l2_buf.timecode = src_buf->v4l2_buf.timecode;
+
+       v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_DONE);
+
+       dst_buf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
+       v4l2_m2m_buf_done(dst_buf, VB2_BUF_STATE_DONE);
+
+       ctx->gopcounter--;
+       if (ctx->gopcounter < 0)
+               ctx->gopcounter = ctx->params.gop_size - 1;
+
+       v4l2_dbg(1, coda_debug, &dev->v4l2_dev,
+               "job finished: encoding frame (%d) (%s)\n",
+               dst_buf->v4l2_buf.sequence,
+               (dst_buf->v4l2_buf.flags & V4L2_BUF_FLAG_KEYFRAME) ?
+               "KEYFRAME" : "PFRAME");
+}
+
+static void coda_seq_end_work(struct work_struct *work)
+{
+       struct coda_ctx *ctx = container_of(work, struct coda_ctx, seq_end_work);
+       struct coda_dev *dev = ctx->dev;
+
+       mutex_lock(&ctx->buffer_mutex);
+       mutex_lock(&dev->coda_mutex);
+
+       v4l2_dbg(1, coda_debug, &dev->v4l2_dev,
+                "%d: %s: sent command 'SEQ_END' to coda\n", ctx->idx,
+                __func__);
+       if (coda_command_sync(ctx, CODA_COMMAND_SEQ_END)) {
+               v4l2_err(&dev->v4l2_dev,
+                        "CODA_COMMAND_SEQ_END failed\n");
+       }
+
+       kfifo_init(&ctx->bitstream_fifo,
+               ctx->bitstream.vaddr, ctx->bitstream.size);
+
+       coda_free_framebuffers(ctx);
+       coda_free_context_buffers(ctx);
+
+       mutex_unlock(&dev->coda_mutex);
+       mutex_unlock(&ctx->buffer_mutex);
+}
+
+static void coda_bit_release(struct coda_ctx *ctx)
+{
+       coda_free_framebuffers(ctx);
+       coda_free_context_buffers(ctx);
+}
+
+const struct coda_context_ops coda_bit_encode_ops = {
+       .queue_init = coda_encoder_queue_init,
+       .start_streaming = coda_start_encoding,
+       .prepare_run = coda_prepare_encode,
+       .finish_run = coda_finish_encode,
+       .seq_end_work = coda_seq_end_work,
+       .release = coda_bit_release,
+};
+
+/*
+ * Decoder context operations
+ */
+
+static int __coda_start_decoding(struct coda_ctx *ctx)
+{
+       struct coda_q_data *q_data_src, *q_data_dst;
+       u32 bitstream_buf, bitstream_size;
+       struct coda_dev *dev = ctx->dev;
+       int width, height;
+       u32 src_fourcc;
+       u32 val;
+       int ret;
+
+       /* Start decoding */
+       q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
+       q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE);
+       bitstream_buf = ctx->bitstream.paddr;
+       bitstream_size = ctx->bitstream.size;
+       src_fourcc = q_data_src->fourcc;
+
+       /* Allocate per-instance buffers */
+       ret = coda_alloc_context_buffers(ctx, q_data_src);
+       if (ret < 0)
+               return ret;
+
+       coda_write(dev, ctx->parabuf.paddr, CODA_REG_BIT_PARA_BUF_ADDR);
+
+       /* Update coda bitstream read and write pointers from kfifo */
+       coda_kfifo_sync_to_device_full(ctx);
+
+       ctx->display_idx = -1;
+       ctx->frm_dis_flg = 0;
+       coda_write(dev, 0, CODA_REG_BIT_FRM_DIS_FLG(ctx->reg_idx));
+
+       coda_write(dev, CODA_BIT_DEC_SEQ_INIT_ESCAPE,
+                       CODA_REG_BIT_BIT_STREAM_PARAM);
+
+       coda_write(dev, bitstream_buf, CODA_CMD_DEC_SEQ_BB_START);
+       coda_write(dev, bitstream_size / 1024, CODA_CMD_DEC_SEQ_BB_SIZE);
+       val = 0;
+       if ((dev->devtype->product == CODA_7541) ||
+           (dev->devtype->product == CODA_960))
+               val |= CODA_REORDER_ENABLE;
+       coda_write(dev, val, CODA_CMD_DEC_SEQ_OPTION);
+
+       ctx->params.codec_mode = ctx->codec->mode;
+       if (dev->devtype->product == CODA_960 &&
+           src_fourcc == V4L2_PIX_FMT_MPEG4)
+               ctx->params.codec_mode_aux = CODA_MP4_AUX_MPEG4;
+       else
+               ctx->params.codec_mode_aux = 0;
+       if (src_fourcc == V4L2_PIX_FMT_H264) {
+               if (dev->devtype->product == CODA_7541) {
+                       coda_write(dev, ctx->psbuf.paddr,
+                                       CODA_CMD_DEC_SEQ_PS_BB_START);
+                       coda_write(dev, (CODA7_PS_BUF_SIZE / 1024),
+                                       CODA_CMD_DEC_SEQ_PS_BB_SIZE);
+               }
+               if (dev->devtype->product == CODA_960) {
+                       coda_write(dev, 0, CODA_CMD_DEC_SEQ_X264_MV_EN);
+                       coda_write(dev, 512, CODA_CMD_DEC_SEQ_SPP_CHUNK_SIZE);
+               }
+       }
+       if (dev->devtype->product != CODA_960)
+               coda_write(dev, 0, CODA_CMD_DEC_SEQ_SRC_SIZE);
+
+       if (coda_command_sync(ctx, CODA_COMMAND_SEQ_INIT)) {
+               v4l2_err(&dev->v4l2_dev, "CODA_COMMAND_SEQ_INIT timeout\n");
+               coda_write(dev, 0, CODA_REG_BIT_BIT_STREAM_PARAM);
+               return -ETIMEDOUT;
+       }
+
+       /* Update kfifo out pointer from coda bitstream read pointer */
+       coda_kfifo_sync_from_device(ctx);
+
+       coda_write(dev, 0, CODA_REG_BIT_BIT_STREAM_PARAM);
+
+       if (coda_read(dev, CODA_RET_DEC_SEQ_SUCCESS) == 0) {
+               v4l2_err(&dev->v4l2_dev,
+                       "CODA_COMMAND_SEQ_INIT failed, error code = %d\n",
+                       coda_read(dev, CODA_RET_DEC_SEQ_ERR_REASON));
+               return -EAGAIN;
+       }
+
+       val = coda_read(dev, CODA_RET_DEC_SEQ_SRC_SIZE);
+       if (dev->devtype->product == CODA_DX6) {
+               width = (val >> CODADX6_PICWIDTH_OFFSET) & CODADX6_PICWIDTH_MASK;
+               height = val & CODADX6_PICHEIGHT_MASK;
+       } else {
+               width = (val >> CODA7_PICWIDTH_OFFSET) & CODA7_PICWIDTH_MASK;
+               height = val & CODA7_PICHEIGHT_MASK;
+       }
+
+       if (width > q_data_dst->width || height > q_data_dst->height) {
+               v4l2_err(&dev->v4l2_dev, "stream is %dx%d, not %dx%d\n",
+                        width, height, q_data_dst->width, q_data_dst->height);
+               return -EINVAL;
+       }
+
+       width = round_up(width, 16);
+       height = round_up(height, 16);
+
+       v4l2_dbg(1, coda_debug, &dev->v4l2_dev, "%s instance %d now: %dx%d\n",
+                __func__, ctx->idx, width, height);
+
+       ctx->num_internal_frames = coda_read(dev, CODA_RET_DEC_SEQ_FRAME_NEED);
+       if (ctx->num_internal_frames > CODA_MAX_FRAMEBUFFERS) {
+               v4l2_err(&dev->v4l2_dev,
+                        "not enough framebuffers to decode (%d < %d)\n",
+                        CODA_MAX_FRAMEBUFFERS, ctx->num_internal_frames);
+               return -EINVAL;
+       }
+
+       if (src_fourcc == V4L2_PIX_FMT_H264) {
+               u32 left_right;
+               u32 top_bottom;
+
+               left_right = coda_read(dev, CODA_RET_DEC_SEQ_CROP_LEFT_RIGHT);
+               top_bottom = coda_read(dev, CODA_RET_DEC_SEQ_CROP_TOP_BOTTOM);
+
+               q_data_dst->rect.left = (left_right >> 10) & 0x3ff;
+               q_data_dst->rect.top = (top_bottom >> 10) & 0x3ff;
+               q_data_dst->rect.width = width - q_data_dst->rect.left -
+                                        (left_right & 0x3ff);
+               q_data_dst->rect.height = height - q_data_dst->rect.top -
+                                         (top_bottom & 0x3ff);
+       }
+
+       ret = coda_alloc_framebuffers(ctx, q_data_dst, src_fourcc);
+       if (ret < 0) {
+               v4l2_err(&dev->v4l2_dev, "failed to allocate framebuffers\n");
+               return ret;
+       }
+
+       /* Tell the decoder how many frame buffers we allocated. */
+       coda_write(dev, ctx->num_internal_frames, CODA_CMD_SET_FRAME_BUF_NUM);
+       coda_write(dev, width, CODA_CMD_SET_FRAME_BUF_STRIDE);
+
+       if (dev->devtype->product != CODA_DX6) {
+               /* Set secondary AXI IRAM */
+               coda_setup_iram(ctx);
+
+               coda_write(dev, ctx->iram_info.buf_bit_use,
+                               CODA7_CMD_SET_FRAME_AXI_BIT_ADDR);
+               coda_write(dev, ctx->iram_info.buf_ip_ac_dc_use,
+                               CODA7_CMD_SET_FRAME_AXI_IPACDC_ADDR);
+               coda_write(dev, ctx->iram_info.buf_dbk_y_use,
+                               CODA7_CMD_SET_FRAME_AXI_DBKY_ADDR);
+               coda_write(dev, ctx->iram_info.buf_dbk_c_use,
+                               CODA7_CMD_SET_FRAME_AXI_DBKC_ADDR);
+               coda_write(dev, ctx->iram_info.buf_ovl_use,
+                               CODA7_CMD_SET_FRAME_AXI_OVL_ADDR);
+               if (dev->devtype->product == CODA_960)
+                       coda_write(dev, ctx->iram_info.buf_btp_use,
+                                       CODA9_CMD_SET_FRAME_AXI_BTP_ADDR);
+       }
+
+       if (dev->devtype->product == CODA_960) {
+               coda_write(dev, -1, CODA9_CMD_SET_FRAME_DELAY);
+
+               coda_write(dev, 0x20262024, CODA9_CMD_SET_FRAME_CACHE_SIZE);
+               coda_write(dev, 2 << CODA9_CACHE_PAGEMERGE_OFFSET |
+                               32 << CODA9_CACHE_LUMA_BUFFER_SIZE_OFFSET |
+                               8 << CODA9_CACHE_CB_BUFFER_SIZE_OFFSET |
+                               8 << CODA9_CACHE_CR_BUFFER_SIZE_OFFSET,
+                               CODA9_CMD_SET_FRAME_CACHE_CONFIG);
+       }
+
+       if (src_fourcc == V4L2_PIX_FMT_H264) {
+               coda_write(dev, ctx->slicebuf.paddr,
+                               CODA_CMD_SET_FRAME_SLICE_BB_START);
+               coda_write(dev, ctx->slicebuf.size / 1024,
+                               CODA_CMD_SET_FRAME_SLICE_BB_SIZE);
+       }
+
+       if (dev->devtype->product == CODA_7541) {
+               int max_mb_x = 1920 / 16;
+               int max_mb_y = 1088 / 16;
+               int max_mb_num = max_mb_x * max_mb_y;
+
+               coda_write(dev, max_mb_num << 16 | max_mb_x << 8 | max_mb_y,
+                               CODA7_CMD_SET_FRAME_MAX_DEC_SIZE);
+       } else if (dev->devtype->product == CODA_960) {
+               int max_mb_x = 1920 / 16;
+               int max_mb_y = 1088 / 16;
+               int max_mb_num = max_mb_x * max_mb_y;
+
+               coda_write(dev, max_mb_num << 16 | max_mb_x << 8 | max_mb_y,
+                               CODA9_CMD_SET_FRAME_MAX_DEC_SIZE);
+       }
+
+       if (coda_command_sync(ctx, CODA_COMMAND_SET_FRAME_BUF)) {
+               v4l2_err(&ctx->dev->v4l2_dev,
+                        "CODA_COMMAND_SET_FRAME_BUF timeout\n");
+               return -ETIMEDOUT;
+       }
+
+       return 0;
+}
+
+static int coda_start_decoding(struct coda_ctx *ctx)
+{
+       struct coda_dev *dev = ctx->dev;
+       int ret;
+
+       mutex_lock(&dev->coda_mutex);
+       ret = __coda_start_decoding(ctx);
+       mutex_unlock(&dev->coda_mutex);
+
+       return ret;
+}
+
+static int coda_prepare_decode(struct coda_ctx *ctx)
+{
+       struct vb2_buffer *dst_buf;
+       struct coda_dev *dev = ctx->dev;
+       struct coda_q_data *q_data_dst;
+       u32 stridey, height;
+       u32 picture_y, picture_cb, picture_cr;
+
+       dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
+       q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE);
+
+       if (ctx->params.rot_mode & CODA_ROT_90) {
+               stridey = q_data_dst->height;
+               height = q_data_dst->width;
+       } else {
+               stridey = q_data_dst->width;
+               height = q_data_dst->height;
+       }
+
+       /* Try to copy source buffer contents into the bitstream ringbuffer */
+       mutex_lock(&ctx->bitstream_mutex);
+       coda_fill_bitstream(ctx);
+       mutex_unlock(&ctx->bitstream_mutex);
+
+       if (coda_get_bitstream_payload(ctx) < 512 &&
+           (!(ctx->bit_stream_param & CODA_BIT_STREAM_END_FLAG))) {
+               v4l2_dbg(1, coda_debug, &dev->v4l2_dev,
+                        "bitstream payload: %d, skipping\n",
+                        coda_get_bitstream_payload(ctx));
+               v4l2_m2m_job_finish(ctx->dev->m2m_dev, ctx->fh.m2m_ctx);
+               return -EAGAIN;
+       }
+
+       /* Run coda_start_decoding (again) if not yet initialized */
+       if (!ctx->initialized) {
+               int ret = __coda_start_decoding(ctx);
+
+               if (ret < 0) {
+                       v4l2_err(&dev->v4l2_dev, "failed to start decoding\n");
+                       v4l2_m2m_job_finish(ctx->dev->m2m_dev, ctx->fh.m2m_ctx);
+                       return -EAGAIN;
+               } else {
+                       ctx->initialized = 1;
+               }
+       }
+
+       if (dev->devtype->product == CODA_960)
+               coda_set_gdi_regs(ctx);
+
+       /* Set rotator output */
+       picture_y = vb2_dma_contig_plane_dma_addr(dst_buf, 0);
+       if (q_data_dst->fourcc == V4L2_PIX_FMT_YVU420) {
+               /* Switch Cr and Cb for YVU420 format */
+               picture_cr = picture_y + stridey * height;
+               picture_cb = picture_cr + stridey / 2 * height / 2;
+       } else {
+               picture_cb = picture_y + stridey * height;
+               picture_cr = picture_cb + stridey / 2 * height / 2;
+       }
+
+       if (dev->devtype->product == CODA_960) {
+               /*
+                * The CODA960 seems to have an internal list of buffers with
+                * 64 entries that includes the registered frame buffers as
+                * well as the rotator buffer output.
+                * ROT_INDEX needs to be < 0x40, but > ctx->num_internal_frames.
+                */
+               coda_write(dev, CODA_MAX_FRAMEBUFFERS + dst_buf->v4l2_buf.index,
+                               CODA9_CMD_DEC_PIC_ROT_INDEX);
+               coda_write(dev, picture_y, CODA9_CMD_DEC_PIC_ROT_ADDR_Y);
+               coda_write(dev, picture_cb, CODA9_CMD_DEC_PIC_ROT_ADDR_CB);
+               coda_write(dev, picture_cr, CODA9_CMD_DEC_PIC_ROT_ADDR_CR);
+               coda_write(dev, stridey, CODA9_CMD_DEC_PIC_ROT_STRIDE);
+       } else {
+               coda_write(dev, picture_y, CODA_CMD_DEC_PIC_ROT_ADDR_Y);
+               coda_write(dev, picture_cb, CODA_CMD_DEC_PIC_ROT_ADDR_CB);
+               coda_write(dev, picture_cr, CODA_CMD_DEC_PIC_ROT_ADDR_CR);
+               coda_write(dev, stridey, CODA_CMD_DEC_PIC_ROT_STRIDE);
+       }
+       coda_write(dev, CODA_ROT_MIR_ENABLE | ctx->params.rot_mode,
+                       CODA_CMD_DEC_PIC_ROT_MODE);
+
+       switch (dev->devtype->product) {
+       case CODA_DX6:
+               /* TBD */
+       case CODA_7541:
+               coda_write(dev, CODA_PRE_SCAN_EN, CODA_CMD_DEC_PIC_OPTION);
+               break;
+       case CODA_960:
+               /* 'hardcode to use interrupt disable mode'? */
+               coda_write(dev, (1 << 10), CODA_CMD_DEC_PIC_OPTION);
+               break;
+       }
+
+       coda_write(dev, 0, CODA_CMD_DEC_PIC_SKIP_NUM);
+
+       coda_write(dev, 0, CODA_CMD_DEC_PIC_BB_START);
+       coda_write(dev, 0, CODA_CMD_DEC_PIC_START_BYTE);
+
+       if (dev->devtype->product != CODA_DX6)
+               coda_write(dev, ctx->iram_info.axi_sram_use,
+                               CODA7_REG_BIT_AXI_SRAM_USE);
+
+       coda_kfifo_sync_to_device_full(ctx);
+
+       coda_command_async(ctx, CODA_COMMAND_PIC_RUN);
+
+       return 0;
+}
+
+static void coda_finish_decode(struct coda_ctx *ctx)
+{
+       struct coda_dev *dev = ctx->dev;
+       struct coda_q_data *q_data_src;
+       struct coda_q_data *q_data_dst;
+       struct vb2_buffer *dst_buf;
+       struct coda_timestamp *ts;
+       int width, height;
+       int decoded_idx;
+       int display_idx;
+       u32 src_fourcc;
+       int success;
+       u32 err_mb;
+       u32 val;
+
+       /* Update kfifo out pointer from coda bitstream read pointer */
+       coda_kfifo_sync_from_device(ctx);
+
+       /*
+        * in stream-end mode, the read pointer can overshoot the write pointer
+        * by up to 512 bytes
+        */
+       if (ctx->bit_stream_param & CODA_BIT_STREAM_END_FLAG) {
+               if (coda_get_bitstream_payload(ctx) >= CODA_MAX_FRAME_SIZE - 512)
+                       kfifo_init(&ctx->bitstream_fifo,
+                               ctx->bitstream.vaddr, ctx->bitstream.size);
+       }
+
+       q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
+       src_fourcc = q_data_src->fourcc;
+
+       val = coda_read(dev, CODA_RET_DEC_PIC_SUCCESS);
+       if (val != 1)
+               pr_err("DEC_PIC_SUCCESS = %d\n", val);
+
+       success = val & 0x1;
+       if (!success)
+               v4l2_err(&dev->v4l2_dev, "decode failed\n");
+
+       if (src_fourcc == V4L2_PIX_FMT_H264) {
+               if (val & (1 << 3))
+                       v4l2_err(&dev->v4l2_dev,
+                                "insufficient PS buffer space (%d bytes)\n",
+                                ctx->psbuf.size);
+               if (val & (1 << 2))
+                       v4l2_err(&dev->v4l2_dev,
+                                "insufficient slice buffer space (%d bytes)\n",
+                                ctx->slicebuf.size);
+       }
+
+       val = coda_read(dev, CODA_RET_DEC_PIC_SIZE);
+       width = (val >> 16) & 0xffff;
+       height = val & 0xffff;
+
+       q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE);
+
+       /* frame crop information */
+       if (src_fourcc == V4L2_PIX_FMT_H264) {
+               u32 left_right;
+               u32 top_bottom;
+
+               left_right = coda_read(dev, CODA_RET_DEC_PIC_CROP_LEFT_RIGHT);
+               top_bottom = coda_read(dev, CODA_RET_DEC_PIC_CROP_TOP_BOTTOM);
+
+               if (left_right == 0xffffffff && top_bottom == 0xffffffff) {
+                       /* Keep current crop information */
+               } else {
+                       struct v4l2_rect *rect = &q_data_dst->rect;
+
+                       rect->left = left_right >> 16 & 0xffff;
+                       rect->top = top_bottom >> 16 & 0xffff;
+                       rect->width = width - rect->left -
+                                     (left_right & 0xffff);
+                       rect->height = height - rect->top -
+                                      (top_bottom & 0xffff);
+               }
+       } else {
+               /* no cropping */
+       }
+
+       err_mb = coda_read(dev, CODA_RET_DEC_PIC_ERR_MB);
+       if (err_mb > 0)
+               v4l2_err(&dev->v4l2_dev,
+                        "errors in %d macroblocks\n", err_mb);
+
+       if (dev->devtype->product == CODA_7541) {
+               val = coda_read(dev, CODA_RET_DEC_PIC_OPTION);
+               if (val == 0) {
+                       /* not enough bitstream data */
+                       v4l2_dbg(1, coda_debug, &dev->v4l2_dev,
+                                "prescan failed: %d\n", val);
+                       ctx->hold = true;
+                       return;
+               }
+       }
+
+       ctx->frm_dis_flg = coda_read(dev,
+                                    CODA_REG_BIT_FRM_DIS_FLG(ctx->reg_idx));
+
+       /*
+        * The previous display frame was copied out by the rotator,
+        * now it can be overwritten again
+        */
+       if (ctx->display_idx >= 0 &&
+           ctx->display_idx < ctx->num_internal_frames) {
+               ctx->frm_dis_flg &= ~(1 << ctx->display_idx);
+               coda_write(dev, ctx->frm_dis_flg,
+                               CODA_REG_BIT_FRM_DIS_FLG(ctx->reg_idx));
+       }
+
+       /*
+        * The index of the last decoded frame, not necessarily in
+        * display order, and the index of the next display frame.
+        * The latter could have been decoded in a previous run.
+        */
+       decoded_idx = coda_read(dev, CODA_RET_DEC_PIC_CUR_IDX);
+       display_idx = coda_read(dev, CODA_RET_DEC_PIC_FRAME_IDX);
+
+       if (decoded_idx == -1) {
+               /* no frame was decoded, but we might have a display frame */
+               if (display_idx >= 0 && display_idx < ctx->num_internal_frames)
+                       ctx->sequence_offset++;
+               else if (ctx->display_idx < 0)
+                       ctx->hold = true;
+       } else if (decoded_idx == -2) {
+               /* no frame was decoded, we still return remaining buffers */
+       } else if (decoded_idx < 0 || decoded_idx >= ctx->num_internal_frames) {
+               v4l2_err(&dev->v4l2_dev,
+                        "decoded frame index out of range: %d\n", decoded_idx);
+       } else {
+               val = coda_read(dev, CODA_RET_DEC_PIC_FRAME_NUM) - 1;
+               val -= ctx->sequence_offset;
+               mutex_lock(&ctx->bitstream_mutex);
+               if (!list_empty(&ctx->timestamp_list)) {
+                       ts = list_first_entry(&ctx->timestamp_list,
+                                             struct coda_timestamp, list);
+                       list_del(&ts->list);
+                       if (val != (ts->sequence & 0xffff)) {
+                               v4l2_err(&dev->v4l2_dev,
+                                        "sequence number mismatch (%d(%d) != %d)\n",
+                                        val, ctx->sequence_offset,
+                                        ts->sequence);
+                       }
+                       ctx->frame_timestamps[decoded_idx] = *ts;
+                       kfree(ts);
+               } else {
+                       v4l2_err(&dev->v4l2_dev, "empty timestamp list!\n");
+                       memset(&ctx->frame_timestamps[decoded_idx], 0,
+                              sizeof(struct coda_timestamp));
+                       ctx->frame_timestamps[decoded_idx].sequence = val;
+               }
+               mutex_unlock(&ctx->bitstream_mutex);
+
+               val = coda_read(dev, CODA_RET_DEC_PIC_TYPE) & 0x7;
+               if (val == 0)
+                       ctx->frame_types[decoded_idx] = V4L2_BUF_FLAG_KEYFRAME;
+               else if (val == 1)
+                       ctx->frame_types[decoded_idx] = V4L2_BUF_FLAG_PFRAME;
+               else
+                       ctx->frame_types[decoded_idx] = V4L2_BUF_FLAG_BFRAME;
+
+               ctx->frame_errors[decoded_idx] = err_mb;
+       }
+
+       if (display_idx == -1) {
+               /*
+                * no more frames to be decoded, but there could still
+                * be rotator output to dequeue
+                */
+               ctx->hold = true;
+       } else if (display_idx == -3) {
+               /* possibly prescan failure */
+       } else if (display_idx < 0 || display_idx >= ctx->num_internal_frames) {
+               v4l2_err(&dev->v4l2_dev,
+                        "presentation frame index out of range: %d\n",
+                        display_idx);
+       }
+
+       /* If a frame was copied out, return it */
+       if (ctx->display_idx >= 0 &&
+           ctx->display_idx < ctx->num_internal_frames) {
+               dst_buf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
+               dst_buf->v4l2_buf.sequence = ctx->osequence++;
+
+               dst_buf->v4l2_buf.flags &= ~(V4L2_BUF_FLAG_KEYFRAME |
+                                            V4L2_BUF_FLAG_PFRAME |
+                                            V4L2_BUF_FLAG_BFRAME);
+               dst_buf->v4l2_buf.flags |= ctx->frame_types[ctx->display_idx];
+               ts = &ctx->frame_timestamps[ctx->display_idx];
+               dst_buf->v4l2_buf.timecode = ts->timecode;
+               dst_buf->v4l2_buf.timestamp = ts->timestamp;
+
+               vb2_set_plane_payload(dst_buf, 0, width * height * 3 / 2);
+
+               v4l2_m2m_buf_done(dst_buf, ctx->frame_errors[display_idx] ?
+                                 VB2_BUF_STATE_ERROR : VB2_BUF_STATE_DONE);
+
+               v4l2_dbg(1, coda_debug, &dev->v4l2_dev,
+                       "job finished: decoding frame (%d) (%s)\n",
+                       dst_buf->v4l2_buf.sequence,
+                       (dst_buf->v4l2_buf.flags & V4L2_BUF_FLAG_KEYFRAME) ?
+                       "KEYFRAME" : "PFRAME");
+       } else {
+               v4l2_dbg(1, coda_debug, &dev->v4l2_dev,
+                       "job finished: no frame decoded\n");
+       }
+
+       /* The rotator will copy the current display frame next time */
+       ctx->display_idx = display_idx;
+}
+
+const struct coda_context_ops coda_bit_decode_ops = {
+       .queue_init = coda_decoder_queue_init,
+       .start_streaming = coda_start_decoding,
+       .prepare_run = coda_prepare_decode,
+       .finish_run = coda_finish_decode,
+       .seq_end_work = coda_seq_end_work,
+       .release = coda_bit_release,
+};
+
+irqreturn_t coda_irq_handler(int irq, void *data)
+{
+       struct coda_dev *dev = data;
+       struct coda_ctx *ctx;
+
+       /* read status register to attend the IRQ */
+       coda_read(dev, CODA_REG_BIT_INT_STATUS);
+       coda_write(dev, CODA_REG_BIT_INT_CLEAR_SET,
+                     CODA_REG_BIT_INT_CLEAR);
+
+       ctx = v4l2_m2m_get_curr_priv(dev->m2m_dev);
+       if (ctx == NULL) {
+               v4l2_err(&dev->v4l2_dev,
+                        "Instance released before the end of transaction\n");
+               mutex_unlock(&dev->coda_mutex);
+               return IRQ_HANDLED;
+       }
+
+       if (ctx->aborting) {
+               v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev,
+                        "task has been aborted\n");
+       }
+
+       if (coda_isbusy(ctx->dev)) {
+               v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev,
+                        "coda is still busy!!!!\n");
+               return IRQ_NONE;
+       }
+
+       complete(&ctx->completion);
+
+       return IRQ_HANDLED;
+}
diff --git a/drivers/media/platform/coda/coda-common.c b/drivers/media/platform/coda/coda-common.c
new file mode 100644 (file)
index 0000000..ced4760
--- /dev/null
@@ -0,0 +1,2052 @@
+/*
+ * Coda multi-standard codec IP
+ *
+ * Copyright (C) 2012 Vista Silicon S.L.
+ *    Javier Martin, <javier.martin@vista-silicon.com>
+ *    Xavier Duret
+ *
+ * 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/clk.h>
+#include <linux/debugfs.h>
+#include <linux/delay.h>
+#include <linux/firmware.h>
+#include <linux/genalloc.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/kfifo.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/slab.h>
+#include <linux/videodev2.h>
+#include <linux/of.h>
+#include <linux/platform_data/coda.h>
+#include <linux/reset.h>
+
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-event.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-mem2mem.h>
+#include <media/videobuf2-core.h>
+#include <media/videobuf2-dma-contig.h>
+
+#include "coda.h"
+
+#define CODA_NAME              "coda"
+
+#define CODADX6_MAX_INSTANCES  4
+
+#define CODA_PARA_BUF_SIZE     (10 * 1024)
+#define CODA_ISRAM_SIZE        (2048 * 2)
+
+#define MIN_W 176
+#define MIN_H 144
+
+#define S_ALIGN                1 /* multiple of 2 */
+#define W_ALIGN                1 /* multiple of 2 */
+#define H_ALIGN                1 /* multiple of 2 */
+
+#define fh_to_ctx(__fh)        container_of(__fh, struct coda_ctx, fh)
+
+int coda_debug;
+module_param(coda_debug, int, 0644);
+MODULE_PARM_DESC(coda_debug, "Debug level (0-2)");
+
+struct coda_fmt {
+       char *name;
+       u32 fourcc;
+};
+
+void coda_write(struct coda_dev *dev, u32 data, u32 reg)
+{
+       v4l2_dbg(2, coda_debug, &dev->v4l2_dev,
+                "%s: data=0x%x, reg=0x%x\n", __func__, data, reg);
+       writel(data, dev->regs_base + reg);
+}
+
+unsigned int coda_read(struct coda_dev *dev, u32 reg)
+{
+       u32 data;
+
+       data = readl(dev->regs_base + reg);
+       v4l2_dbg(2, coda_debug, &dev->v4l2_dev,
+                "%s: data=0x%x, reg=0x%x\n", __func__, data, reg);
+       return data;
+}
+
+/*
+ * Array of all formats supported by any version of Coda:
+ */
+static const struct coda_fmt coda_formats[] = {
+       {
+               .name = "YUV 4:2:0 Planar, YCbCr",
+               .fourcc = V4L2_PIX_FMT_YUV420,
+       },
+       {
+               .name = "YUV 4:2:0 Planar, YCrCb",
+               .fourcc = V4L2_PIX_FMT_YVU420,
+       },
+       {
+               .name = "H264 Encoded Stream",
+               .fourcc = V4L2_PIX_FMT_H264,
+       },
+       {
+               .name = "MPEG4 Encoded Stream",
+               .fourcc = V4L2_PIX_FMT_MPEG4,
+       },
+};
+
+#define CODA_CODEC(mode, src_fourcc, dst_fourcc, max_w, max_h) \
+       { mode, src_fourcc, dst_fourcc, max_w, max_h }
+
+/*
+ * Arrays of codecs supported by each given version of Coda:
+ *  i.MX27 -> codadx6
+ *  i.MX5x -> coda7
+ *  i.MX6  -> coda960
+ * Use V4L2_PIX_FMT_YUV420 as placeholder for all supported YUV 4:2:0 variants
+ */
+static const struct coda_codec codadx6_codecs[] = {
+       CODA_CODEC(CODADX6_MODE_ENCODE_H264, V4L2_PIX_FMT_YUV420, V4L2_PIX_FMT_H264,  720, 576),
+       CODA_CODEC(CODADX6_MODE_ENCODE_MP4,  V4L2_PIX_FMT_YUV420, V4L2_PIX_FMT_MPEG4, 720, 576),
+};
+
+static const struct coda_codec coda7_codecs[] = {
+       CODA_CODEC(CODA7_MODE_ENCODE_H264, V4L2_PIX_FMT_YUV420, V4L2_PIX_FMT_H264,   1280, 720),
+       CODA_CODEC(CODA7_MODE_ENCODE_MP4,  V4L2_PIX_FMT_YUV420, V4L2_PIX_FMT_MPEG4,  1280, 720),
+       CODA_CODEC(CODA7_MODE_DECODE_H264, V4L2_PIX_FMT_H264,   V4L2_PIX_FMT_YUV420, 1920, 1088),
+       CODA_CODEC(CODA7_MODE_DECODE_MP4,  V4L2_PIX_FMT_MPEG4,  V4L2_PIX_FMT_YUV420, 1920, 1088),
+};
+
+static const struct coda_codec coda9_codecs[] = {
+       CODA_CODEC(CODA9_MODE_ENCODE_H264, V4L2_PIX_FMT_YUV420, V4L2_PIX_FMT_H264,   1920, 1088),
+       CODA_CODEC(CODA9_MODE_ENCODE_MP4,  V4L2_PIX_FMT_YUV420, V4L2_PIX_FMT_MPEG4,  1920, 1088),
+       CODA_CODEC(CODA9_MODE_DECODE_H264, V4L2_PIX_FMT_H264,   V4L2_PIX_FMT_YUV420, 1920, 1088),
+       CODA_CODEC(CODA9_MODE_DECODE_MP4,  V4L2_PIX_FMT_MPEG4,  V4L2_PIX_FMT_YUV420, 1920, 1088),
+};
+
+static bool coda_format_is_yuv(u32 fourcc)
+{
+       switch (fourcc) {
+       case V4L2_PIX_FMT_YUV420:
+       case V4L2_PIX_FMT_YVU420:
+               return true;
+       default:
+               return false;
+       }
+}
+
+/*
+ * Normalize all supported YUV 4:2:0 formats to the value used in the codec
+ * tables.
+ */
+static u32 coda_format_normalize_yuv(u32 fourcc)
+{
+       return coda_format_is_yuv(fourcc) ? V4L2_PIX_FMT_YUV420 : fourcc;
+}
+
+static const struct coda_codec *coda_find_codec(struct coda_dev *dev,
+                                               int src_fourcc, int dst_fourcc)
+{
+       const struct coda_codec *codecs = dev->devtype->codecs;
+       int num_codecs = dev->devtype->num_codecs;
+       int k;
+
+       src_fourcc = coda_format_normalize_yuv(src_fourcc);
+       dst_fourcc = coda_format_normalize_yuv(dst_fourcc);
+       if (src_fourcc == dst_fourcc)
+               return NULL;
+
+       for (k = 0; k < num_codecs; k++) {
+               if (codecs[k].src_fourcc == src_fourcc &&
+                   codecs[k].dst_fourcc == dst_fourcc)
+                       break;
+       }
+
+       if (k == num_codecs)
+               return NULL;
+
+       return &codecs[k];
+}
+
+static void coda_get_max_dimensions(struct coda_dev *dev,
+                                   const struct coda_codec *codec,
+                                   int *max_w, int *max_h)
+{
+       const struct coda_codec *codecs = dev->devtype->codecs;
+       int num_codecs = dev->devtype->num_codecs;
+       unsigned int w, h;
+       int k;
+
+       if (codec) {
+               w = codec->max_w;
+               h = codec->max_h;
+       } else {
+               for (k = 0, w = 0, h = 0; k < num_codecs; k++) {
+                       w = max(w, codecs[k].max_w);
+                       h = max(h, codecs[k].max_h);
+               }
+       }
+
+       if (max_w)
+               *max_w = w;
+       if (max_h)
+               *max_h = h;
+}
+
+const char *coda_product_name(int product)
+{
+       static char buf[9];
+
+       switch (product) {
+       case CODA_DX6:
+               return "CodaDx6";
+       case CODA_7541:
+               return "CODA7541";
+       case CODA_960:
+               return "CODA960";
+       default:
+               snprintf(buf, sizeof(buf), "(0x%04x)", product);
+               return buf;
+       }
+}
+
+/*
+ * V4L2 ioctl() operations.
+ */
+static int coda_querycap(struct file *file, void *priv,
+                        struct v4l2_capability *cap)
+{
+       struct coda_ctx *ctx = fh_to_ctx(priv);
+
+       strlcpy(cap->driver, CODA_NAME, sizeof(cap->driver));
+       strlcpy(cap->card, coda_product_name(ctx->dev->devtype->product),
+               sizeof(cap->card));
+       strlcpy(cap->bus_info, "platform:" CODA_NAME, sizeof(cap->bus_info));
+       cap->device_caps = V4L2_CAP_VIDEO_M2M | V4L2_CAP_STREAMING;
+       cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
+
+       return 0;
+}
+
+static int coda_enum_fmt(struct file *file, void *priv,
+                        struct v4l2_fmtdesc *f)
+{
+       struct coda_ctx *ctx = fh_to_ctx(priv);
+       const struct coda_codec *codecs = ctx->dev->devtype->codecs;
+       const struct coda_fmt *formats = coda_formats;
+       const struct coda_fmt *fmt;
+       int num_codecs = ctx->dev->devtype->num_codecs;
+       int num_formats = ARRAY_SIZE(coda_formats);
+       int i, k, num = 0;
+       bool yuv;
+
+       if (ctx->inst_type == CODA_INST_ENCODER)
+               yuv = (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT);
+       else
+               yuv = (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE);
+
+       for (i = 0; i < num_formats; i++) {
+               /* Skip either raw or compressed formats */
+               if (yuv != coda_format_is_yuv(formats[i].fourcc))
+                       continue;
+               /* All uncompressed formats are always supported */
+               if (yuv) {
+                       if (num == f->index)
+                               break;
+                       ++num;
+                       continue;
+               }
+               /* Compressed formats may be supported, check the codec list */
+               for (k = 0; k < num_codecs; k++) {
+                       if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE &&
+                           formats[i].fourcc == codecs[k].dst_fourcc)
+                               break;
+                       if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT &&
+                           formats[i].fourcc == codecs[k].src_fourcc)
+                               break;
+               }
+               if (k < num_codecs) {
+                       if (num == f->index)
+                               break;
+                       ++num;
+               }
+       }
+
+       if (i < num_formats) {
+               fmt = &formats[i];
+               strlcpy(f->description, fmt->name, sizeof(f->description));
+               f->pixelformat = fmt->fourcc;
+               if (!yuv)
+                       f->flags |= V4L2_FMT_FLAG_COMPRESSED;
+               return 0;
+       }
+
+       /* Format not found */
+       return -EINVAL;
+}
+
+static int coda_g_fmt(struct file *file, void *priv,
+                     struct v4l2_format *f)
+{
+       struct coda_q_data *q_data;
+       struct coda_ctx *ctx = fh_to_ctx(priv);
+
+       q_data = get_q_data(ctx, f->type);
+       if (!q_data)
+               return -EINVAL;
+
+       f->fmt.pix.field        = V4L2_FIELD_NONE;
+       f->fmt.pix.pixelformat  = q_data->fourcc;
+       f->fmt.pix.width        = q_data->width;
+       f->fmt.pix.height       = q_data->height;
+       f->fmt.pix.bytesperline = q_data->bytesperline;
+
+       f->fmt.pix.sizeimage    = q_data->sizeimage;
+       f->fmt.pix.colorspace   = ctx->colorspace;
+
+       return 0;
+}
+
+static int coda_try_fmt(struct coda_ctx *ctx, const struct coda_codec *codec,
+                       struct v4l2_format *f)
+{
+       struct coda_dev *dev = ctx->dev;
+       struct coda_q_data *q_data;
+       unsigned int max_w, max_h;
+       enum v4l2_field field;
+
+       field = f->fmt.pix.field;
+       if (field == V4L2_FIELD_ANY)
+               field = V4L2_FIELD_NONE;
+       else if (V4L2_FIELD_NONE != field)
+               return -EINVAL;
+
+       /* V4L2 specification suggests the driver corrects the format struct
+        * if any of the dimensions is unsupported */
+       f->fmt.pix.field = field;
+
+       coda_get_max_dimensions(dev, codec, &max_w, &max_h);
+       v4l_bound_align_image(&f->fmt.pix.width, MIN_W, max_w, W_ALIGN,
+                             &f->fmt.pix.height, MIN_H, max_h, H_ALIGN,
+                             S_ALIGN);
+
+       switch (f->fmt.pix.pixelformat) {
+       case V4L2_PIX_FMT_YUV420:
+       case V4L2_PIX_FMT_YVU420:
+       case V4L2_PIX_FMT_H264:
+       case V4L2_PIX_FMT_MPEG4:
+       case V4L2_PIX_FMT_JPEG:
+               break;
+       default:
+               q_data = get_q_data(ctx, f->type);
+               if (!q_data)
+                       return -EINVAL;
+               f->fmt.pix.pixelformat = q_data->fourcc;
+       }
+
+       switch (f->fmt.pix.pixelformat) {
+       case V4L2_PIX_FMT_YUV420:
+       case V4L2_PIX_FMT_YVU420:
+               /* Frame stride must be multiple of 8, but 16 for h.264 */
+               f->fmt.pix.bytesperline = round_up(f->fmt.pix.width, 16);
+               f->fmt.pix.sizeimage = f->fmt.pix.bytesperline *
+                                       f->fmt.pix.height * 3 / 2;
+               break;
+       case V4L2_PIX_FMT_H264:
+       case V4L2_PIX_FMT_MPEG4:
+       case V4L2_PIX_FMT_JPEG:
+               f->fmt.pix.bytesperline = 0;
+               f->fmt.pix.sizeimage = CODA_MAX_FRAME_SIZE;
+               break;
+       default:
+               BUG();
+       }
+
+       return 0;
+}
+
+static int coda_try_fmt_vid_cap(struct file *file, void *priv,
+                               struct v4l2_format *f)
+{
+       struct coda_ctx *ctx = fh_to_ctx(priv);
+       const struct coda_codec *codec = NULL;
+       struct vb2_queue *src_vq;
+       int ret;
+
+       /*
+        * If the source format is already fixed, try to find a codec that
+        * converts to the given destination format
+        */
+       src_vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
+       if (vb2_is_streaming(src_vq)) {
+               struct coda_q_data *q_data_src;
+
+               q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
+               codec = coda_find_codec(ctx->dev, q_data_src->fourcc,
+                                       f->fmt.pix.pixelformat);
+               if (!codec)
+                       return -EINVAL;
+
+               f->fmt.pix.width = q_data_src->width;
+               f->fmt.pix.height = q_data_src->height;
+       } else {
+               /* Otherwise determine codec by encoded format, if possible */
+               codec = coda_find_codec(ctx->dev, V4L2_PIX_FMT_YUV420,
+                                       f->fmt.pix.pixelformat);
+       }
+
+       f->fmt.pix.colorspace = ctx->colorspace;
+
+       ret = coda_try_fmt(ctx, codec, f);
+       if (ret < 0)
+               return ret;
+
+       /* The h.264 decoder only returns complete 16x16 macroblocks */
+       if (codec && codec->src_fourcc == V4L2_PIX_FMT_H264) {
+               f->fmt.pix.width = f->fmt.pix.width;
+               f->fmt.pix.height = round_up(f->fmt.pix.height, 16);
+               f->fmt.pix.bytesperline = round_up(f->fmt.pix.width, 16);
+               f->fmt.pix.sizeimage = f->fmt.pix.bytesperline *
+                                      f->fmt.pix.height * 3 / 2;
+       }
+
+       return 0;
+}
+
+static int coda_try_fmt_vid_out(struct file *file, void *priv,
+                               struct v4l2_format *f)
+{
+       struct coda_ctx *ctx = fh_to_ctx(priv);
+       const struct coda_codec *codec = NULL;
+
+       /* Determine codec by encoded format, returns NULL if raw or invalid */
+       if (ctx->inst_type == CODA_INST_DECODER) {
+               codec = coda_find_codec(ctx->dev, f->fmt.pix.pixelformat,
+                                       V4L2_PIX_FMT_YUV420);
+               if (!codec)
+                       codec = coda_find_codec(ctx->dev, V4L2_PIX_FMT_H264,
+                                               V4L2_PIX_FMT_YUV420);
+               if (!codec)
+                       return -EINVAL;
+       }
+
+       if (!f->fmt.pix.colorspace)
+               f->fmt.pix.colorspace = V4L2_COLORSPACE_REC709;
+
+       return coda_try_fmt(ctx, codec, f);
+}
+
+static int coda_s_fmt(struct coda_ctx *ctx, struct v4l2_format *f)
+{
+       struct coda_q_data *q_data;
+       struct vb2_queue *vq;
+
+       vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type);
+       if (!vq)
+               return -EINVAL;
+
+       q_data = get_q_data(ctx, f->type);
+       if (!q_data)
+               return -EINVAL;
+
+       if (vb2_is_busy(vq)) {
+               v4l2_err(&ctx->dev->v4l2_dev, "%s queue busy\n", __func__);
+               return -EBUSY;
+       }
+
+       q_data->fourcc = f->fmt.pix.pixelformat;
+       q_data->width = f->fmt.pix.width;
+       q_data->height = f->fmt.pix.height;
+       q_data->bytesperline = f->fmt.pix.bytesperline;
+       q_data->sizeimage = f->fmt.pix.sizeimage;
+       q_data->rect.left = 0;
+       q_data->rect.top = 0;
+       q_data->rect.width = f->fmt.pix.width;
+       q_data->rect.height = f->fmt.pix.height;
+
+       v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev,
+               "Setting format for type %d, wxh: %dx%d, fmt: %d\n",
+               f->type, q_data->width, q_data->height, q_data->fourcc);
+
+       return 0;
+}
+
+static int coda_s_fmt_vid_cap(struct file *file, void *priv,
+                             struct v4l2_format *f)
+{
+       struct coda_ctx *ctx = fh_to_ctx(priv);
+       int ret;
+
+       ret = coda_try_fmt_vid_cap(file, priv, f);
+       if (ret)
+               return ret;
+
+       return coda_s_fmt(ctx, f);
+}
+
+static int coda_s_fmt_vid_out(struct file *file, void *priv,
+                             struct v4l2_format *f)
+{
+       struct coda_ctx *ctx = fh_to_ctx(priv);
+       struct v4l2_format f_cap;
+       int ret;
+
+       ret = coda_try_fmt_vid_out(file, priv, f);
+       if (ret)
+               return ret;
+
+       ret = coda_s_fmt(ctx, f);
+       if (ret)
+               return ret;
+
+       ctx->colorspace = f->fmt.pix.colorspace;
+
+       f_cap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+       coda_g_fmt(file, priv, &f_cap);
+       f_cap.fmt.pix.width = f->fmt.pix.width;
+       f_cap.fmt.pix.height = f->fmt.pix.height;
+
+       ret = coda_try_fmt_vid_cap(file, priv, &f_cap);
+       if (ret)
+               return ret;
+
+       return coda_s_fmt(ctx, &f_cap);
+}
+
+static int coda_qbuf(struct file *file, void *priv,
+                    struct v4l2_buffer *buf)
+{
+       struct coda_ctx *ctx = fh_to_ctx(priv);
+
+       return v4l2_m2m_qbuf(file, ctx->fh.m2m_ctx, buf);
+}
+
+static bool coda_buf_is_end_of_stream(struct coda_ctx *ctx,
+                                     struct v4l2_buffer *buf)
+{
+       struct vb2_queue *src_vq;
+
+       src_vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
+
+       return ((ctx->bit_stream_param & CODA_BIT_STREAM_END_FLAG) &&
+               (buf->sequence == (ctx->qsequence - 1)));
+}
+
+static int coda_dqbuf(struct file *file, void *priv,
+                     struct v4l2_buffer *buf)
+{
+       struct coda_ctx *ctx = fh_to_ctx(priv);
+       int ret;
+
+       ret = v4l2_m2m_dqbuf(file, ctx->fh.m2m_ctx, buf);
+
+       /* If this is the last capture buffer, emit an end-of-stream event */
+       if (buf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE &&
+           coda_buf_is_end_of_stream(ctx, buf)) {
+               const struct v4l2_event eos_event = {
+                       .type = V4L2_EVENT_EOS
+               };
+
+               v4l2_event_queue_fh(&ctx->fh, &eos_event);
+       }
+
+       return ret;
+}
+
+static int coda_g_selection(struct file *file, void *fh,
+                           struct v4l2_selection *s)
+{
+       struct coda_ctx *ctx = fh_to_ctx(fh);
+       struct coda_q_data *q_data;
+       struct v4l2_rect r, *rsel;
+
+       q_data = get_q_data(ctx, s->type);
+       if (!q_data)
+               return -EINVAL;
+
+       r.left = 0;
+       r.top = 0;
+       r.width = q_data->width;
+       r.height = q_data->height;
+       rsel = &q_data->rect;
+
+       switch (s->target) {
+       case V4L2_SEL_TGT_CROP_DEFAULT:
+       case V4L2_SEL_TGT_CROP_BOUNDS:
+               rsel = &r;
+               /* fallthrough */
+       case V4L2_SEL_TGT_CROP:
+               if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
+                       return -EINVAL;
+               break;
+       case V4L2_SEL_TGT_COMPOSE_BOUNDS:
+       case V4L2_SEL_TGT_COMPOSE_PADDED:
+               rsel = &r;
+               /* fallthrough */
+       case V4L2_SEL_TGT_COMPOSE:
+       case V4L2_SEL_TGT_COMPOSE_DEFAULT:
+               if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+                       return -EINVAL;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       s->r = *rsel;
+
+       return 0;
+}
+
+static int coda_try_decoder_cmd(struct file *file, void *fh,
+                               struct v4l2_decoder_cmd *dc)
+{
+       if (dc->cmd != V4L2_DEC_CMD_STOP)
+               return -EINVAL;
+
+       if (dc->flags & V4L2_DEC_CMD_STOP_TO_BLACK)
+               return -EINVAL;
+
+       if (!(dc->flags & V4L2_DEC_CMD_STOP_IMMEDIATELY) && (dc->stop.pts != 0))
+               return -EINVAL;
+
+       return 0;
+}
+
+static int coda_decoder_cmd(struct file *file, void *fh,
+                           struct v4l2_decoder_cmd *dc)
+{
+       struct coda_ctx *ctx = fh_to_ctx(fh);
+       int ret;
+
+       ret = coda_try_decoder_cmd(file, fh, dc);
+       if (ret < 0)
+               return ret;
+
+       /* Ignore decoder stop command silently in encoder context */
+       if (ctx->inst_type != CODA_INST_DECODER)
+               return 0;
+
+       /* Set the stream-end flag on this context */
+       coda_bit_stream_end_flag(ctx);
+       ctx->hold = false;
+       v4l2_m2m_try_schedule(ctx->fh.m2m_ctx);
+
+       return 0;
+}
+
+static int coda_subscribe_event(struct v4l2_fh *fh,
+                               const struct v4l2_event_subscription *sub)
+{
+       switch (sub->type) {
+       case V4L2_EVENT_EOS:
+               return v4l2_event_subscribe(fh, sub, 0, NULL);
+       default:
+               return v4l2_ctrl_subscribe_event(fh, sub);
+       }
+}
+
+static const struct v4l2_ioctl_ops coda_ioctl_ops = {
+       .vidioc_querycap        = coda_querycap,
+
+       .vidioc_enum_fmt_vid_cap = coda_enum_fmt,
+       .vidioc_g_fmt_vid_cap   = coda_g_fmt,
+       .vidioc_try_fmt_vid_cap = coda_try_fmt_vid_cap,
+       .vidioc_s_fmt_vid_cap   = coda_s_fmt_vid_cap,
+
+       .vidioc_enum_fmt_vid_out = coda_enum_fmt,
+       .vidioc_g_fmt_vid_out   = coda_g_fmt,
+       .vidioc_try_fmt_vid_out = coda_try_fmt_vid_out,
+       .vidioc_s_fmt_vid_out   = coda_s_fmt_vid_out,
+
+       .vidioc_reqbufs         = v4l2_m2m_ioctl_reqbufs,
+       .vidioc_querybuf        = v4l2_m2m_ioctl_querybuf,
+
+       .vidioc_qbuf            = coda_qbuf,
+       .vidioc_expbuf          = v4l2_m2m_ioctl_expbuf,
+       .vidioc_dqbuf           = coda_dqbuf,
+       .vidioc_create_bufs     = v4l2_m2m_ioctl_create_bufs,
+
+       .vidioc_streamon        = v4l2_m2m_ioctl_streamon,
+       .vidioc_streamoff       = v4l2_m2m_ioctl_streamoff,
+
+       .vidioc_g_selection     = coda_g_selection,
+
+       .vidioc_try_decoder_cmd = coda_try_decoder_cmd,
+       .vidioc_decoder_cmd     = coda_decoder_cmd,
+
+       .vidioc_subscribe_event = coda_subscribe_event,
+       .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
+};
+
+void coda_set_gdi_regs(struct coda_ctx *ctx)
+{
+       struct gdi_tiled_map *tiled_map = &ctx->tiled_map;
+       struct coda_dev *dev = ctx->dev;
+       int i;
+
+       for (i = 0; i < 16; i++)
+               coda_write(dev, tiled_map->xy2ca_map[i],
+                               CODA9_GDI_XY2_CAS_0 + 4 * i);
+       for (i = 0; i < 4; i++)
+               coda_write(dev, tiled_map->xy2ba_map[i],
+                               CODA9_GDI_XY2_BA_0 + 4 * i);
+       for (i = 0; i < 16; i++)
+               coda_write(dev, tiled_map->xy2ra_map[i],
+                               CODA9_GDI_XY2_RAS_0 + 4 * i);
+       coda_write(dev, tiled_map->xy2rbc_config, CODA9_GDI_XY2_RBC_CONFIG);
+       for (i = 0; i < 32; i++)
+               coda_write(dev, tiled_map->rbc2axi_map[i],
+                               CODA9_GDI_RBC2_AXI_0 + 4 * i);
+}
+
+/*
+ * Mem-to-mem operations.
+ */
+
+static void coda_device_run(void *m2m_priv)
+{
+       struct coda_ctx *ctx = m2m_priv;
+       struct coda_dev *dev = ctx->dev;
+
+       queue_work(dev->workqueue, &ctx->pic_run_work);
+}
+
+static void coda_pic_run_work(struct work_struct *work)
+{
+       struct coda_ctx *ctx = container_of(work, struct coda_ctx, pic_run_work);
+       struct coda_dev *dev = ctx->dev;
+       int ret;
+
+       mutex_lock(&ctx->buffer_mutex);
+       mutex_lock(&dev->coda_mutex);
+
+       ret = ctx->ops->prepare_run(ctx);
+       if (ret < 0 && ctx->inst_type == CODA_INST_DECODER) {
+               mutex_unlock(&dev->coda_mutex);
+               mutex_unlock(&ctx->buffer_mutex);
+               /* job_finish scheduled by prepare_decode */
+               return;
+       }
+
+       if (!wait_for_completion_timeout(&ctx->completion,
+                                        msecs_to_jiffies(1000))) {
+               dev_err(&dev->plat_dev->dev, "CODA PIC_RUN timeout\n");
+
+               ctx->hold = true;
+
+               coda_hw_reset(ctx);
+       } else if (!ctx->aborting) {
+               ctx->ops->finish_run(ctx);
+       }
+
+       if (ctx->aborting || (!ctx->streamon_cap && !ctx->streamon_out))
+               queue_work(dev->workqueue, &ctx->seq_end_work);
+
+       mutex_unlock(&dev->coda_mutex);
+       mutex_unlock(&ctx->buffer_mutex);
+
+       v4l2_m2m_job_finish(ctx->dev->m2m_dev, ctx->fh.m2m_ctx);
+}
+
+static int coda_job_ready(void *m2m_priv)
+{
+       struct coda_ctx *ctx = m2m_priv;
+
+       /*
+        * For both 'P' and 'key' frame cases 1 picture
+        * and 1 frame are needed. In the decoder case,
+        * the compressed frame can be in the bitstream.
+        */
+       if (!v4l2_m2m_num_src_bufs_ready(ctx->fh.m2m_ctx) &&
+           ctx->inst_type != CODA_INST_DECODER) {
+               v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev,
+                        "not ready: not enough video buffers.\n");
+               return 0;
+       }
+
+       if (!v4l2_m2m_num_dst_bufs_ready(ctx->fh.m2m_ctx)) {
+               v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev,
+                        "not ready: not enough video capture buffers.\n");
+               return 0;
+       }
+
+       if (ctx->hold ||
+           ((ctx->inst_type == CODA_INST_DECODER) &&
+            (coda_get_bitstream_payload(ctx) < 512) &&
+            !(ctx->bit_stream_param & CODA_BIT_STREAM_END_FLAG))) {
+               v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev,
+                        "%d: not ready: not enough bitstream data.\n",
+                        ctx->idx);
+               return 0;
+       }
+
+       if (ctx->aborting) {
+               v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev,
+                        "not ready: aborting\n");
+               return 0;
+       }
+
+       v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev,
+                       "job ready\n");
+       return 1;
+}
+
+static void coda_job_abort(void *priv)
+{
+       struct coda_ctx *ctx = priv;
+
+       ctx->aborting = 1;
+
+       v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev,
+                "Aborting task\n");
+}
+
+static void coda_lock(void *m2m_priv)
+{
+       struct coda_ctx *ctx = m2m_priv;
+       struct coda_dev *pcdev = ctx->dev;
+
+       mutex_lock(&pcdev->dev_mutex);
+}
+
+static void coda_unlock(void *m2m_priv)
+{
+       struct coda_ctx *ctx = m2m_priv;
+       struct coda_dev *pcdev = ctx->dev;
+
+       mutex_unlock(&pcdev->dev_mutex);
+}
+
+static const struct v4l2_m2m_ops coda_m2m_ops = {
+       .device_run     = coda_device_run,
+       .job_ready      = coda_job_ready,
+       .job_abort      = coda_job_abort,
+       .lock           = coda_lock,
+       .unlock         = coda_unlock,
+};
+
+static void coda_set_tiled_map_type(struct coda_ctx *ctx, int tiled_map_type)
+{
+       struct gdi_tiled_map *tiled_map = &ctx->tiled_map;
+       int luma_map, chro_map, i;
+
+       memset(tiled_map, 0, sizeof(*tiled_map));
+
+       luma_map = 64;
+       chro_map = 64;
+       tiled_map->map_type = tiled_map_type;
+       for (i = 0; i < 16; i++)
+               tiled_map->xy2ca_map[i] = luma_map << 8 | chro_map;
+       for (i = 0; i < 4; i++)
+               tiled_map->xy2ba_map[i] = luma_map << 8 | chro_map;
+       for (i = 0; i < 16; i++)
+               tiled_map->xy2ra_map[i] = luma_map << 8 | chro_map;
+
+       if (tiled_map_type == GDI_LINEAR_FRAME_MAP) {
+               tiled_map->xy2rbc_config = 0;
+       } else {
+               dev_err(&ctx->dev->plat_dev->dev, "invalid map type: %d\n",
+                       tiled_map_type);
+               return;
+       }
+}
+
+static void set_default_params(struct coda_ctx *ctx)
+{
+       u32 src_fourcc, dst_fourcc;
+       int max_w;
+       int max_h;
+
+       if (ctx->inst_type == CODA_INST_ENCODER) {
+               src_fourcc = V4L2_PIX_FMT_YUV420;
+               dst_fourcc = V4L2_PIX_FMT_H264;
+       } else {
+               src_fourcc = V4L2_PIX_FMT_H264;
+               dst_fourcc = V4L2_PIX_FMT_YUV420;
+       }
+       ctx->codec = coda_find_codec(ctx->dev, src_fourcc, dst_fourcc);
+       max_w = ctx->codec->max_w;
+       max_h = ctx->codec->max_h;
+
+       ctx->params.codec_mode = ctx->codec->mode;
+       ctx->colorspace = V4L2_COLORSPACE_REC709;
+       ctx->params.framerate = 30;
+       ctx->aborting = 0;
+
+       /* Default formats for output and input queues */
+       ctx->q_data[V4L2_M2M_SRC].fourcc = ctx->codec->src_fourcc;
+       ctx->q_data[V4L2_M2M_DST].fourcc = ctx->codec->dst_fourcc;
+       ctx->q_data[V4L2_M2M_SRC].width = max_w;
+       ctx->q_data[V4L2_M2M_SRC].height = max_h;
+       ctx->q_data[V4L2_M2M_DST].width = max_w;
+       ctx->q_data[V4L2_M2M_DST].height = max_h;
+       if (ctx->codec->src_fourcc == V4L2_PIX_FMT_YUV420) {
+               ctx->q_data[V4L2_M2M_SRC].bytesperline = max_w;
+               ctx->q_data[V4L2_M2M_SRC].sizeimage = (max_w * max_h * 3) / 2;
+               ctx->q_data[V4L2_M2M_DST].bytesperline = 0;
+               ctx->q_data[V4L2_M2M_DST].sizeimage = CODA_MAX_FRAME_SIZE;
+       } else {
+               ctx->q_data[V4L2_M2M_SRC].bytesperline = 0;
+               ctx->q_data[V4L2_M2M_SRC].sizeimage = CODA_MAX_FRAME_SIZE;
+               ctx->q_data[V4L2_M2M_DST].bytesperline = max_w;
+               ctx->q_data[V4L2_M2M_DST].sizeimage = (max_w * max_h * 3) / 2;
+       }
+       ctx->q_data[V4L2_M2M_SRC].rect.width = max_w;
+       ctx->q_data[V4L2_M2M_SRC].rect.height = max_h;
+       ctx->q_data[V4L2_M2M_DST].rect.width = max_w;
+       ctx->q_data[V4L2_M2M_DST].rect.height = max_h;
+
+       if (ctx->dev->devtype->product == CODA_960)
+               coda_set_tiled_map_type(ctx, GDI_LINEAR_FRAME_MAP);
+}
+
+/*
+ * Queue operations
+ */
+static int coda_queue_setup(struct vb2_queue *vq,
+                               const struct v4l2_format *fmt,
+                               unsigned int *nbuffers, unsigned int *nplanes,
+                               unsigned int sizes[], void *alloc_ctxs[])
+{
+       struct coda_ctx *ctx = vb2_get_drv_priv(vq);
+       struct coda_q_data *q_data;
+       unsigned int size;
+
+       q_data = get_q_data(ctx, vq->type);
+       size = q_data->sizeimage;
+
+       *nplanes = 1;
+       sizes[0] = size;
+
+       alloc_ctxs[0] = ctx->dev->alloc_ctx;
+
+       v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev,
+                "get %d buffer(s) of size %d each.\n", *nbuffers, size);
+
+       return 0;
+}
+
+static int coda_buf_prepare(struct vb2_buffer *vb)
+{
+       struct coda_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
+       struct coda_q_data *q_data;
+
+       q_data = get_q_data(ctx, vb->vb2_queue->type);
+
+       if (vb2_plane_size(vb, 0) < q_data->sizeimage) {
+               v4l2_warn(&ctx->dev->v4l2_dev,
+                         "%s data will not fit into plane (%lu < %lu)\n",
+                         __func__, vb2_plane_size(vb, 0),
+                         (long)q_data->sizeimage);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static void coda_buf_queue(struct vb2_buffer *vb)
+{
+       struct coda_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
+       struct coda_q_data *q_data;
+
+       q_data = get_q_data(ctx, vb->vb2_queue->type);
+
+       /*
+        * In the decoder case, immediately try to copy the buffer into the
+        * bitstream ringbuffer and mark it as ready to be dequeued.
+        */
+       if (q_data->fourcc == V4L2_PIX_FMT_H264 &&
+           vb->vb2_queue->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) {
+               /*
+                * For backwards compatibility, queuing an empty buffer marks
+                * the stream end
+                */
+               if (vb2_get_plane_payload(vb, 0) == 0)
+                       coda_bit_stream_end_flag(ctx);
+               mutex_lock(&ctx->bitstream_mutex);
+               v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vb);
+               if (vb2_is_streaming(vb->vb2_queue))
+                       coda_fill_bitstream(ctx);
+               mutex_unlock(&ctx->bitstream_mutex);
+       } else {
+               v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vb);
+       }
+}
+
+int coda_alloc_aux_buf(struct coda_dev *dev, struct coda_aux_buf *buf,
+                      size_t size, const char *name, struct dentry *parent)
+{
+       buf->vaddr = dma_alloc_coherent(&dev->plat_dev->dev, size, &buf->paddr,
+                                       GFP_KERNEL);
+       if (!buf->vaddr) {
+               v4l2_err(&dev->v4l2_dev,
+                        "Failed to allocate %s buffer of size %u\n",
+                        name, size);
+               return -ENOMEM;
+       }
+
+       buf->size = size;
+
+       if (name && parent) {
+               buf->blob.data = buf->vaddr;
+               buf->blob.size = size;
+               buf->dentry = debugfs_create_blob(name, 0644, parent,
+                                                 &buf->blob);
+               if (!buf->dentry)
+                       dev_warn(&dev->plat_dev->dev,
+                                "failed to create debugfs entry %s\n", name);
+       }
+
+       return 0;
+}
+
+void coda_free_aux_buf(struct coda_dev *dev,
+                      struct coda_aux_buf *buf)
+{
+       if (buf->vaddr) {
+               dma_free_coherent(&dev->plat_dev->dev, buf->size,
+                                 buf->vaddr, buf->paddr);
+               buf->vaddr = NULL;
+               buf->size = 0;
+       }
+       debugfs_remove(buf->dentry);
+}
+
+static int coda_start_streaming(struct vb2_queue *q, unsigned int count)
+{
+       struct coda_ctx *ctx = vb2_get_drv_priv(q);
+       struct v4l2_device *v4l2_dev = &ctx->dev->v4l2_dev;
+       struct coda_q_data *q_data_src, *q_data_dst;
+       struct vb2_buffer *buf;
+       u32 dst_fourcc;
+       int ret = 0;
+
+       q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
+       if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) {
+               if (q_data_src->fourcc == V4L2_PIX_FMT_H264) {
+                       /* copy the buffers that where queued before streamon */
+                       mutex_lock(&ctx->bitstream_mutex);
+                       coda_fill_bitstream(ctx);
+                       mutex_unlock(&ctx->bitstream_mutex);
+
+                       if (coda_get_bitstream_payload(ctx) < 512) {
+                               ret = -EINVAL;
+                               goto err;
+                       }
+               } else {
+                       if (count < 1) {
+                               ret = -EINVAL;
+                               goto err;
+                       }
+               }
+
+               ctx->streamon_out = 1;
+       } else {
+               if (count < 1) {
+                       ret = -EINVAL;
+                       goto err;
+               }
+
+               ctx->streamon_cap = 1;
+       }
+
+       /* Don't start the coda unless both queues are on */
+       if (!(ctx->streamon_out & ctx->streamon_cap))
+               return 0;
+
+       /* Allow decoder device_run with no new buffers queued */
+       if (ctx->inst_type == CODA_INST_DECODER)
+               v4l2_m2m_set_src_buffered(ctx->fh.m2m_ctx, true);
+
+       ctx->gopcounter = ctx->params.gop_size - 1;
+       q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE);
+       dst_fourcc = q_data_dst->fourcc;
+
+       ctx->codec = coda_find_codec(ctx->dev, q_data_src->fourcc,
+                                    q_data_dst->fourcc);
+       if (!ctx->codec) {
+               v4l2_err(v4l2_dev, "couldn't tell instance type.\n");
+               ret = -EINVAL;
+               goto err;
+       }
+
+       ret = ctx->ops->start_streaming(ctx);
+       if (ctx->inst_type == CODA_INST_DECODER) {
+               if (ret == -EAGAIN)
+                       return 0;
+               else if (ret < 0)
+                       goto err;
+       }
+
+       ctx->initialized = 1;
+       return ret;
+
+err:
+       if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) {
+               while ((buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx)))
+                       v4l2_m2m_buf_done(buf, VB2_BUF_STATE_DEQUEUED);
+       } else {
+               while ((buf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx)))
+                       v4l2_m2m_buf_done(buf, VB2_BUF_STATE_DEQUEUED);
+       }
+       return ret;
+}
+
+static void coda_stop_streaming(struct vb2_queue *q)
+{
+       struct coda_ctx *ctx = vb2_get_drv_priv(q);
+       struct coda_dev *dev = ctx->dev;
+       struct vb2_buffer *buf;
+
+       if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) {
+               v4l2_dbg(1, coda_debug, &dev->v4l2_dev,
+                        "%s: output\n", __func__);
+               ctx->streamon_out = 0;
+
+               coda_bit_stream_end_flag(ctx);
+
+               ctx->isequence = 0;
+
+               while ((buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx)))
+                       v4l2_m2m_buf_done(buf, VB2_BUF_STATE_ERROR);
+       } else {
+               v4l2_dbg(1, coda_debug, &dev->v4l2_dev,
+                        "%s: capture\n", __func__);
+               ctx->streamon_cap = 0;
+
+               ctx->osequence = 0;
+               ctx->sequence_offset = 0;
+
+               while ((buf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx)))
+                       v4l2_m2m_buf_done(buf, VB2_BUF_STATE_ERROR);
+       }
+
+       if (!ctx->streamon_out && !ctx->streamon_cap) {
+               struct coda_timestamp *ts;
+
+               mutex_lock(&ctx->bitstream_mutex);
+               while (!list_empty(&ctx->timestamp_list)) {
+                       ts = list_first_entry(&ctx->timestamp_list,
+                                             struct coda_timestamp, list);
+                       list_del(&ts->list);
+                       kfree(ts);
+               }
+               mutex_unlock(&ctx->bitstream_mutex);
+               kfifo_init(&ctx->bitstream_fifo,
+                       ctx->bitstream.vaddr, ctx->bitstream.size);
+               ctx->runcounter = 0;
+       }
+}
+
+static const struct vb2_ops coda_qops = {
+       .queue_setup            = coda_queue_setup,
+       .buf_prepare            = coda_buf_prepare,
+       .buf_queue              = coda_buf_queue,
+       .start_streaming        = coda_start_streaming,
+       .stop_streaming         = coda_stop_streaming,
+       .wait_prepare           = vb2_ops_wait_prepare,
+       .wait_finish            = vb2_ops_wait_finish,
+};
+
+static int coda_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+       struct coda_ctx *ctx =
+                       container_of(ctrl->handler, struct coda_ctx, ctrls);
+
+       v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev,
+                "s_ctrl: id = %d, val = %d\n", ctrl->id, ctrl->val);
+
+       switch (ctrl->id) {
+       case V4L2_CID_HFLIP:
+               if (ctrl->val)
+                       ctx->params.rot_mode |= CODA_MIR_HOR;
+               else
+                       ctx->params.rot_mode &= ~CODA_MIR_HOR;
+               break;
+       case V4L2_CID_VFLIP:
+               if (ctrl->val)
+                       ctx->params.rot_mode |= CODA_MIR_VER;
+               else
+                       ctx->params.rot_mode &= ~CODA_MIR_VER;
+               break;
+       case V4L2_CID_MPEG_VIDEO_BITRATE:
+               ctx->params.bitrate = ctrl->val / 1000;
+               break;
+       case V4L2_CID_MPEG_VIDEO_GOP_SIZE:
+               ctx->params.gop_size = ctrl->val;
+               break;
+       case V4L2_CID_MPEG_VIDEO_H264_I_FRAME_QP:
+               ctx->params.h264_intra_qp = ctrl->val;
+               break;
+       case V4L2_CID_MPEG_VIDEO_H264_P_FRAME_QP:
+               ctx->params.h264_inter_qp = ctrl->val;
+               break;
+       case V4L2_CID_MPEG_VIDEO_H264_MIN_QP:
+               ctx->params.h264_min_qp = ctrl->val;
+               break;
+       case V4L2_CID_MPEG_VIDEO_H264_MAX_QP:
+               ctx->params.h264_max_qp = ctrl->val;
+               break;
+       case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_ALPHA:
+               ctx->params.h264_deblk_alpha = ctrl->val;
+               break;
+       case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_BETA:
+               ctx->params.h264_deblk_beta = ctrl->val;
+               break;
+       case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE:
+               ctx->params.h264_deblk_enabled = (ctrl->val ==
+                               V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_ENABLED);
+               break;
+       case V4L2_CID_MPEG_VIDEO_MPEG4_I_FRAME_QP:
+               ctx->params.mpeg4_intra_qp = ctrl->val;
+               break;
+       case V4L2_CID_MPEG_VIDEO_MPEG4_P_FRAME_QP:
+               ctx->params.mpeg4_inter_qp = ctrl->val;
+               break;
+       case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE:
+               ctx->params.slice_mode = ctrl->val;
+               break;
+       case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_MB:
+               ctx->params.slice_max_mb = ctrl->val;
+               break;
+       case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_BYTES:
+               ctx->params.slice_max_bits = ctrl->val * 8;
+               break;
+       case V4L2_CID_MPEG_VIDEO_HEADER_MODE:
+               break;
+       case V4L2_CID_MPEG_VIDEO_CYCLIC_INTRA_REFRESH_MB:
+               ctx->params.intra_refresh = ctrl->val;
+               break;
+       default:
+               v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev,
+                       "Invalid control, id=%d, val=%d\n",
+                       ctrl->id, ctrl->val);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static const struct v4l2_ctrl_ops coda_ctrl_ops = {
+       .s_ctrl = coda_s_ctrl,
+};
+
+static int coda_ctrls_setup(struct coda_ctx *ctx)
+{
+       v4l2_ctrl_handler_init(&ctx->ctrls, 9);
+
+       v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops,
+               V4L2_CID_HFLIP, 0, 1, 1, 0);
+       v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops,
+               V4L2_CID_VFLIP, 0, 1, 1, 0);
+       v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops,
+               V4L2_CID_MPEG_VIDEO_BITRATE, 0, 32767000, 1, 0);
+       v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops,
+               V4L2_CID_MPEG_VIDEO_GOP_SIZE, 1, 60, 1, 16);
+       v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops,
+               V4L2_CID_MPEG_VIDEO_H264_I_FRAME_QP, 0, 51, 1, 25);
+       v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops,
+               V4L2_CID_MPEG_VIDEO_H264_P_FRAME_QP, 0, 51, 1, 25);
+       if (ctx->dev->devtype->product != CODA_960) {
+               v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops,
+                       V4L2_CID_MPEG_VIDEO_H264_MIN_QP, 0, 51, 1, 12);
+       }
+       v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops,
+               V4L2_CID_MPEG_VIDEO_H264_MAX_QP, 0, 51, 1, 51);
+       v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops,
+               V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_ALPHA, 0, 15, 1, 0);
+       v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops,
+               V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_BETA, 0, 15, 1, 0);
+       v4l2_ctrl_new_std_menu(&ctx->ctrls, &coda_ctrl_ops,
+               V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE,
+               V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_DISABLED, 0x0,
+               V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_ENABLED);
+       v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops,
+               V4L2_CID_MPEG_VIDEO_MPEG4_I_FRAME_QP, 1, 31, 1, 2);
+       v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops,
+               V4L2_CID_MPEG_VIDEO_MPEG4_P_FRAME_QP, 1, 31, 1, 2);
+       v4l2_ctrl_new_std_menu(&ctx->ctrls, &coda_ctrl_ops,
+               V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE,
+               V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_BYTES, 0x0,
+               V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE);
+       v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops,
+               V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_MB, 1, 0x3fffffff, 1, 1);
+       v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops,
+               V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_BYTES, 1, 0x3fffffff, 1,
+               500);
+       v4l2_ctrl_new_std_menu(&ctx->ctrls, &coda_ctrl_ops,
+               V4L2_CID_MPEG_VIDEO_HEADER_MODE,
+               V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_1ST_FRAME,
+               (1 << V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE),
+               V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_1ST_FRAME);
+       v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops,
+               V4L2_CID_MPEG_VIDEO_CYCLIC_INTRA_REFRESH_MB, 0,
+               1920 * 1088 / 256, 1, 0);
+
+       if (ctx->ctrls.error) {
+               v4l2_err(&ctx->dev->v4l2_dev,
+                       "control initialization error (%d)",
+                       ctx->ctrls.error);
+               return -EINVAL;
+       }
+
+       return v4l2_ctrl_handler_setup(&ctx->ctrls);
+}
+
+static int coda_queue_init(struct coda_ctx *ctx, struct vb2_queue *vq)
+{
+       vq->drv_priv = ctx;
+       vq->ops = &coda_qops;
+       vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
+       vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
+       vq->lock = &ctx->dev->dev_mutex;
+
+       return vb2_queue_init(vq);
+}
+
+int coda_encoder_queue_init(void *priv, struct vb2_queue *src_vq,
+                           struct vb2_queue *dst_vq)
+{
+       int ret;
+
+       src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
+       src_vq->io_modes = VB2_DMABUF | VB2_MMAP;
+       src_vq->mem_ops = &vb2_dma_contig_memops;
+
+       ret = coda_queue_init(priv, src_vq);
+       if (ret)
+               return ret;
+
+       dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+       dst_vq->io_modes = VB2_DMABUF | VB2_MMAP;
+       dst_vq->mem_ops = &vb2_dma_contig_memops;
+
+       return coda_queue_init(priv, dst_vq);
+}
+
+int coda_decoder_queue_init(void *priv, struct vb2_queue *src_vq,
+                           struct vb2_queue *dst_vq)
+{
+       int ret;
+
+       src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
+       src_vq->io_modes = VB2_DMABUF | VB2_MMAP;
+       src_vq->mem_ops = &vb2_dma_contig_memops;
+
+       ret = coda_queue_init(priv, src_vq);
+       if (ret)
+               return ret;
+
+       dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+       dst_vq->io_modes = VB2_DMABUF | VB2_MMAP;
+       dst_vq->mem_ops = &vb2_dma_contig_memops;
+
+       return coda_queue_init(priv, dst_vq);
+}
+
+static int coda_next_free_instance(struct coda_dev *dev)
+{
+       int idx = ffz(dev->instance_mask);
+
+       if ((idx < 0) ||
+           (dev->devtype->product == CODA_DX6 && idx > CODADX6_MAX_INSTANCES))
+               return -EBUSY;
+
+       return idx;
+}
+
+static int coda_open(struct file *file, enum coda_inst_type inst_type,
+                    const struct coda_context_ops *ctx_ops)
+{
+       struct coda_dev *dev = video_drvdata(file);
+       struct coda_ctx *ctx = NULL;
+       char *name;
+       int ret;
+       int idx;
+
+       ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
+       if (!ctx)
+               return -ENOMEM;
+
+       idx = coda_next_free_instance(dev);
+       if (idx < 0) {
+               ret = idx;
+               goto err_coda_max;
+       }
+       set_bit(idx, &dev->instance_mask);
+
+       name = kasprintf(GFP_KERNEL, "context%d", idx);
+       ctx->debugfs_entry = debugfs_create_dir(name, dev->debugfs_root);
+       kfree(name);
+
+       ctx->inst_type = inst_type;
+       ctx->ops = ctx_ops;
+       init_completion(&ctx->completion);
+       INIT_WORK(&ctx->pic_run_work, coda_pic_run_work);
+       INIT_WORK(&ctx->seq_end_work, ctx->ops->seq_end_work);
+       v4l2_fh_init(&ctx->fh, video_devdata(file));
+       file->private_data = &ctx->fh;
+       v4l2_fh_add(&ctx->fh);
+       ctx->dev = dev;
+       ctx->idx = idx;
+       switch (dev->devtype->product) {
+       case CODA_7541:
+       case CODA_960:
+               ctx->reg_idx = 0;
+               break;
+       default:
+               ctx->reg_idx = idx;
+       }
+
+       /* Power up and upload firmware if necessary */
+       ret = pm_runtime_get_sync(&dev->plat_dev->dev);
+       if (ret < 0) {
+               v4l2_err(&dev->v4l2_dev, "failed to power up: %d\n", ret);
+               goto err_pm_get;
+       }
+
+       ret = clk_prepare_enable(dev->clk_per);
+       if (ret)
+               goto err_clk_per;
+
+       ret = clk_prepare_enable(dev->clk_ahb);
+       if (ret)
+               goto err_clk_ahb;
+
+       set_default_params(ctx);
+       ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(dev->m2m_dev, ctx,
+                                           ctx->ops->queue_init);
+       if (IS_ERR(ctx->fh.m2m_ctx)) {
+               ret = PTR_ERR(ctx->fh.m2m_ctx);
+
+               v4l2_err(&dev->v4l2_dev, "%s return error (%d)\n",
+                        __func__, ret);
+               goto err_ctx_init;
+       }
+
+       ret = coda_ctrls_setup(ctx);
+       if (ret) {
+               v4l2_err(&dev->v4l2_dev, "failed to setup coda controls\n");
+               goto err_ctrls_setup;
+       }
+
+       ctx->fh.ctrl_handler = &ctx->ctrls;
+
+       ret = coda_alloc_context_buf(ctx, &ctx->parabuf, CODA_PARA_BUF_SIZE,
+                                    "parabuf");
+       if (ret < 0) {
+               v4l2_err(&dev->v4l2_dev, "failed to allocate parabuf");
+               goto err_dma_alloc;
+       }
+
+       ctx->bitstream.size = CODA_MAX_FRAME_SIZE;
+       ctx->bitstream.vaddr = dma_alloc_writecombine(&dev->plat_dev->dev,
+                       ctx->bitstream.size, &ctx->bitstream.paddr, GFP_KERNEL);
+       if (!ctx->bitstream.vaddr) {
+               v4l2_err(&dev->v4l2_dev,
+                        "failed to allocate bitstream ringbuffer");
+               ret = -ENOMEM;
+               goto err_dma_writecombine;
+       }
+       kfifo_init(&ctx->bitstream_fifo,
+               ctx->bitstream.vaddr, ctx->bitstream.size);
+       mutex_init(&ctx->bitstream_mutex);
+       mutex_init(&ctx->buffer_mutex);
+       INIT_LIST_HEAD(&ctx->timestamp_list);
+
+       coda_lock(ctx);
+       list_add(&ctx->list, &dev->instances);
+       coda_unlock(ctx);
+
+       v4l2_dbg(1, coda_debug, &dev->v4l2_dev, "Created instance %d (%p)\n",
+                ctx->idx, ctx);
+
+       return 0;
+
+err_dma_writecombine:
+       if (ctx->dev->devtype->product == CODA_DX6)
+               coda_free_aux_buf(dev, &ctx->workbuf);
+       coda_free_aux_buf(dev, &ctx->parabuf);
+err_dma_alloc:
+       v4l2_ctrl_handler_free(&ctx->ctrls);
+err_ctrls_setup:
+       v4l2_m2m_ctx_release(ctx->fh.m2m_ctx);
+err_ctx_init:
+       clk_disable_unprepare(dev->clk_ahb);
+err_clk_ahb:
+       clk_disable_unprepare(dev->clk_per);
+err_clk_per:
+       pm_runtime_put_sync(&dev->plat_dev->dev);
+err_pm_get:
+       v4l2_fh_del(&ctx->fh);
+       v4l2_fh_exit(&ctx->fh);
+       clear_bit(ctx->idx, &dev->instance_mask);
+err_coda_max:
+       kfree(ctx);
+       return ret;
+}
+
+static int coda_encoder_open(struct file *file)
+{
+       return coda_open(file, CODA_INST_ENCODER, &coda_bit_encode_ops);
+}
+
+static int coda_decoder_open(struct file *file)
+{
+       return coda_open(file, CODA_INST_DECODER, &coda_bit_decode_ops);
+}
+
+static int coda_release(struct file *file)
+{
+       struct coda_dev *dev = video_drvdata(file);
+       struct coda_ctx *ctx = fh_to_ctx(file->private_data);
+
+       v4l2_dbg(1, coda_debug, &dev->v4l2_dev, "Releasing instance %p\n",
+                ctx);
+
+       debugfs_remove_recursive(ctx->debugfs_entry);
+
+       /* If this instance is running, call .job_abort and wait for it to end */
+       v4l2_m2m_ctx_release(ctx->fh.m2m_ctx);
+
+       /* In case the instance was not running, we still need to call SEQ_END */
+       if (ctx->initialized) {
+               queue_work(dev->workqueue, &ctx->seq_end_work);
+               flush_work(&ctx->seq_end_work);
+       }
+
+       coda_lock(ctx);
+       list_del(&ctx->list);
+       coda_unlock(ctx);
+
+       dma_free_writecombine(&dev->plat_dev->dev, ctx->bitstream.size,
+               ctx->bitstream.vaddr, ctx->bitstream.paddr);
+       if (ctx->dev->devtype->product == CODA_DX6)
+               coda_free_aux_buf(dev, &ctx->workbuf);
+
+       coda_free_aux_buf(dev, &ctx->parabuf);
+       v4l2_ctrl_handler_free(&ctx->ctrls);
+       clk_disable_unprepare(dev->clk_ahb);
+       clk_disable_unprepare(dev->clk_per);
+       pm_runtime_put_sync(&dev->plat_dev->dev);
+       v4l2_fh_del(&ctx->fh);
+       v4l2_fh_exit(&ctx->fh);
+       clear_bit(ctx->idx, &dev->instance_mask);
+       if (ctx->ops->release)
+               ctx->ops->release(ctx);
+       kfree(ctx);
+
+       return 0;
+}
+
+static const struct v4l2_file_operations coda_encoder_fops = {
+       .owner          = THIS_MODULE,
+       .open           = coda_encoder_open,
+       .release        = coda_release,
+       .poll           = v4l2_m2m_fop_poll,
+       .unlocked_ioctl = video_ioctl2,
+       .mmap           = v4l2_m2m_fop_mmap,
+};
+
+static const struct v4l2_file_operations coda_decoder_fops = {
+       .owner          = THIS_MODULE,
+       .open           = coda_decoder_open,
+       .release        = coda_release,
+       .poll           = v4l2_m2m_fop_poll,
+       .unlocked_ioctl = video_ioctl2,
+       .mmap           = v4l2_m2m_fop_mmap,
+};
+
+static int coda_hw_init(struct coda_dev *dev)
+{
+       u32 data;
+       u16 *p;
+       int i, ret;
+
+       ret = clk_prepare_enable(dev->clk_per);
+       if (ret)
+               goto err_clk_per;
+
+       ret = clk_prepare_enable(dev->clk_ahb);
+       if (ret)
+               goto err_clk_ahb;
+
+       if (dev->rstc)
+               reset_control_reset(dev->rstc);
+
+       /*
+        * Copy the first CODA_ISRAM_SIZE in the internal SRAM.
+        * The 16-bit chars in the code buffer are in memory access
+        * order, re-sort them to CODA order for register download.
+        * Data in this SRAM survives a reboot.
+        */
+       p = (u16 *)dev->codebuf.vaddr;
+       if (dev->devtype->product == CODA_DX6) {
+               for (i = 0; i < (CODA_ISRAM_SIZE / 2); i++)  {
+                       data = CODA_DOWN_ADDRESS_SET(i) |
+                               CODA_DOWN_DATA_SET(p[i ^ 1]);
+                       coda_write(dev, data, CODA_REG_BIT_CODE_DOWN);
+               }
+       } else {
+               for (i = 0; i < (CODA_ISRAM_SIZE / 2); i++) {
+                       data = CODA_DOWN_ADDRESS_SET(i) |
+                               CODA_DOWN_DATA_SET(p[round_down(i, 4) +
+                                                       3 - (i % 4)]);
+                       coda_write(dev, data, CODA_REG_BIT_CODE_DOWN);
+               }
+       }
+
+       /* Clear registers */
+       for (i = 0; i < 64; i++)
+               coda_write(dev, 0, CODA_REG_BIT_CODE_BUF_ADDR + i * 4);
+
+       /* Tell the BIT where to find everything it needs */
+       if (dev->devtype->product == CODA_960 ||
+           dev->devtype->product == CODA_7541) {
+               coda_write(dev, dev->tempbuf.paddr,
+                               CODA_REG_BIT_TEMP_BUF_ADDR);
+               coda_write(dev, 0, CODA_REG_BIT_BIT_STREAM_PARAM);
+       } else {
+               coda_write(dev, dev->workbuf.paddr,
+                             CODA_REG_BIT_WORK_BUF_ADDR);
+       }
+       coda_write(dev, dev->codebuf.paddr,
+                     CODA_REG_BIT_CODE_BUF_ADDR);
+       coda_write(dev, 0, CODA_REG_BIT_CODE_RUN);
+
+       /* Set default values */
+       switch (dev->devtype->product) {
+       case CODA_DX6:
+               coda_write(dev, CODADX6_STREAM_BUF_PIC_FLUSH,
+                          CODA_REG_BIT_STREAM_CTRL);
+               break;
+       default:
+               coda_write(dev, CODA7_STREAM_BUF_PIC_FLUSH,
+                          CODA_REG_BIT_STREAM_CTRL);
+       }
+       if (dev->devtype->product == CODA_960)
+               coda_write(dev, 1 << 12, CODA_REG_BIT_FRAME_MEM_CTRL);
+       else
+               coda_write(dev, 0, CODA_REG_BIT_FRAME_MEM_CTRL);
+
+       if (dev->devtype->product != CODA_DX6)
+               coda_write(dev, 0, CODA7_REG_BIT_AXI_SRAM_USE);
+
+       coda_write(dev, CODA_INT_INTERRUPT_ENABLE,
+                     CODA_REG_BIT_INT_ENABLE);
+
+       /* Reset VPU and start processor */
+       data = coda_read(dev, CODA_REG_BIT_CODE_RESET);
+       data |= CODA_REG_RESET_ENABLE;
+       coda_write(dev, data, CODA_REG_BIT_CODE_RESET);
+       udelay(10);
+       data &= ~CODA_REG_RESET_ENABLE;
+       coda_write(dev, data, CODA_REG_BIT_CODE_RESET);
+       coda_write(dev, CODA_REG_RUN_ENABLE, CODA_REG_BIT_CODE_RUN);
+
+       clk_disable_unprepare(dev->clk_ahb);
+       clk_disable_unprepare(dev->clk_per);
+
+       return 0;
+
+err_clk_ahb:
+       clk_disable_unprepare(dev->clk_per);
+err_clk_per:
+       return ret;
+}
+
+static int coda_register_device(struct coda_dev *dev, struct video_device *vfd)
+{
+       vfd->release    = video_device_release_empty,
+       vfd->lock       = &dev->dev_mutex;
+       vfd->v4l2_dev   = &dev->v4l2_dev;
+       vfd->vfl_dir    = VFL_DIR_M2M;
+       video_set_drvdata(vfd, dev);
+
+       /* Not applicable, use the selection API instead */
+       v4l2_disable_ioctl(vfd, VIDIOC_CROPCAP);
+       v4l2_disable_ioctl(vfd, VIDIOC_G_CROP);
+       v4l2_disable_ioctl(vfd, VIDIOC_S_CROP);
+
+       return video_register_device(vfd, VFL_TYPE_GRABBER, 0);
+}
+
+static void coda_fw_callback(const struct firmware *fw, void *context)
+{
+       struct coda_dev *dev = context;
+       struct platform_device *pdev = dev->plat_dev;
+       int ret;
+
+       if (!fw) {
+               v4l2_err(&dev->v4l2_dev, "firmware request failed\n");
+               goto put_pm;
+       }
+
+       /* allocate auxiliary per-device code buffer for the BIT processor */
+       ret = coda_alloc_aux_buf(dev, &dev->codebuf, fw->size, "codebuf",
+                                dev->debugfs_root);
+       if (ret < 0) {
+               dev_err(&pdev->dev, "failed to allocate code buffer\n");
+               goto put_pm;
+       }
+
+       /* Copy the whole firmware image to the code buffer */
+       memcpy(dev->codebuf.vaddr, fw->data, fw->size);
+       release_firmware(fw);
+
+       ret = coda_hw_init(dev);
+       if (ret < 0) {
+               v4l2_err(&dev->v4l2_dev, "HW initialization failed\n");
+               goto put_pm;
+       }
+
+       ret = coda_check_firmware(dev);
+       if (ret < 0)
+               goto put_pm;
+
+       dev->alloc_ctx = vb2_dma_contig_init_ctx(&pdev->dev);
+       if (IS_ERR(dev->alloc_ctx)) {
+               v4l2_err(&dev->v4l2_dev, "Failed to alloc vb2 context\n");
+               goto put_pm;
+       }
+
+       dev->m2m_dev = v4l2_m2m_init(&coda_m2m_ops);
+       if (IS_ERR(dev->m2m_dev)) {
+               v4l2_err(&dev->v4l2_dev, "Failed to init mem2mem device\n");
+               goto rel_ctx;
+       }
+
+       dev->vfd[0].fops      = &coda_encoder_fops,
+       dev->vfd[0].ioctl_ops = &coda_ioctl_ops;
+       snprintf(dev->vfd[0].name, sizeof(dev->vfd[0].name), "coda-encoder");
+       ret = coda_register_device(dev, &dev->vfd[0]);
+       if (ret) {
+               v4l2_err(&dev->v4l2_dev,
+                        "Failed to register encoder video device\n");
+               goto rel_m2m;
+       }
+
+       dev->vfd[1].fops      = &coda_decoder_fops,
+       dev->vfd[1].ioctl_ops = &coda_ioctl_ops;
+       snprintf(dev->vfd[1].name, sizeof(dev->vfd[1].name), "coda-decoder");
+       ret = coda_register_device(dev, &dev->vfd[1]);
+       if (ret) {
+               v4l2_err(&dev->v4l2_dev,
+                        "Failed to register decoder video device\n");
+               goto rel_m2m;
+       }
+
+       v4l2_info(&dev->v4l2_dev, "codec registered as /dev/video[%d-%d]\n",
+                 dev->vfd[0].num, dev->vfd[1].num);
+
+       pm_runtime_put_sync(&pdev->dev);
+       return;
+
+rel_m2m:
+       v4l2_m2m_release(dev->m2m_dev);
+rel_ctx:
+       vb2_dma_contig_cleanup_ctx(dev->alloc_ctx);
+put_pm:
+       pm_runtime_put_sync(&pdev->dev);
+}
+
+static int coda_firmware_request(struct coda_dev *dev)
+{
+       char *fw = dev->devtype->firmware;
+
+       dev_dbg(&dev->plat_dev->dev, "requesting firmware '%s' for %s\n", fw,
+               coda_product_name(dev->devtype->product));
+
+       return request_firmware_nowait(THIS_MODULE, true,
+               fw, &dev->plat_dev->dev, GFP_KERNEL, dev, coda_fw_callback);
+}
+
+enum coda_platform {
+       CODA_IMX27,
+       CODA_IMX53,
+       CODA_IMX6Q,
+       CODA_IMX6DL,
+};
+
+static const struct coda_devtype coda_devdata[] = {
+       [CODA_IMX27] = {
+               .firmware     = "v4l-codadx6-imx27.bin",
+               .product      = CODA_DX6,
+               .codecs       = codadx6_codecs,
+               .num_codecs   = ARRAY_SIZE(codadx6_codecs),
+               .workbuf_size = 288 * 1024 + FMO_SLICE_SAVE_BUF_SIZE * 8 * 1024,
+               .iram_size    = 0xb000,
+       },
+       [CODA_IMX53] = {
+               .firmware     = "v4l-coda7541-imx53.bin",
+               .product      = CODA_7541,
+               .codecs       = coda7_codecs,
+               .num_codecs   = ARRAY_SIZE(coda7_codecs),
+               .workbuf_size = 128 * 1024,
+               .tempbuf_size = 304 * 1024,
+               .iram_size    = 0x14000,
+       },
+       [CODA_IMX6Q] = {
+               .firmware     = "v4l-coda960-imx6q.bin",
+               .product      = CODA_960,
+               .codecs       = coda9_codecs,
+               .num_codecs   = ARRAY_SIZE(coda9_codecs),
+               .workbuf_size = 80 * 1024,
+               .tempbuf_size = 204 * 1024,
+               .iram_size    = 0x21000,
+       },
+       [CODA_IMX6DL] = {
+               .firmware     = "v4l-coda960-imx6dl.bin",
+               .product      = CODA_960,
+               .codecs       = coda9_codecs,
+               .num_codecs   = ARRAY_SIZE(coda9_codecs),
+               .workbuf_size = 80 * 1024,
+               .tempbuf_size = 204 * 1024,
+               .iram_size    = 0x20000,
+       },
+};
+
+static struct platform_device_id coda_platform_ids[] = {
+       { .name = "coda-imx27", .driver_data = CODA_IMX27 },
+       { .name = "coda-imx53", .driver_data = CODA_IMX53 },
+       { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(platform, coda_platform_ids);
+
+#ifdef CONFIG_OF
+static const struct of_device_id coda_dt_ids[] = {
+       { .compatible = "fsl,imx27-vpu", .data = &coda_devdata[CODA_IMX27] },
+       { .compatible = "fsl,imx53-vpu", .data = &coda_devdata[CODA_IMX53] },
+       { .compatible = "fsl,imx6q-vpu", .data = &coda_devdata[CODA_IMX6Q] },
+       { .compatible = "fsl,imx6dl-vpu", .data = &coda_devdata[CODA_IMX6DL] },
+       { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, coda_dt_ids);
+#endif
+
+static int coda_probe(struct platform_device *pdev)
+{
+       const struct of_device_id *of_id =
+                       of_match_device(of_match_ptr(coda_dt_ids), &pdev->dev);
+       const struct platform_device_id *pdev_id;
+       struct coda_platform_data *pdata = pdev->dev.platform_data;
+       struct device_node *np = pdev->dev.of_node;
+       struct gen_pool *pool;
+       struct coda_dev *dev;
+       struct resource *res;
+       int ret, irq;
+
+       dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL);
+       if (!dev) {
+               dev_err(&pdev->dev, "Not enough memory for %s\n",
+                       CODA_NAME);
+               return -ENOMEM;
+       }
+
+       spin_lock_init(&dev->irqlock);
+       INIT_LIST_HEAD(&dev->instances);
+
+       dev->plat_dev = pdev;
+       dev->clk_per = devm_clk_get(&pdev->dev, "per");
+       if (IS_ERR(dev->clk_per)) {
+               dev_err(&pdev->dev, "Could not get per clock\n");
+               return PTR_ERR(dev->clk_per);
+       }
+
+       dev->clk_ahb = devm_clk_get(&pdev->dev, "ahb");
+       if (IS_ERR(dev->clk_ahb)) {
+               dev_err(&pdev->dev, "Could not get ahb clock\n");
+               return PTR_ERR(dev->clk_ahb);
+       }
+
+       /* Get  memory for physical registers */
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       dev->regs_base = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(dev->regs_base))
+               return PTR_ERR(dev->regs_base);
+
+       /* IRQ */
+       irq = platform_get_irq_byname(pdev, "bit");
+       if (irq < 0)
+               irq = platform_get_irq(pdev, 0);
+       if (irq < 0) {
+               dev_err(&pdev->dev, "failed to get irq resource\n");
+               return irq;
+       }
+
+       ret = devm_request_threaded_irq(&pdev->dev, irq, NULL, coda_irq_handler,
+                       IRQF_ONESHOT, dev_name(&pdev->dev), dev);
+       if (ret < 0) {
+               dev_err(&pdev->dev, "failed to request irq: %d\n", ret);
+               return ret;
+       }
+
+       dev->rstc = devm_reset_control_get_optional(&pdev->dev, NULL);
+       if (IS_ERR(dev->rstc)) {
+               ret = PTR_ERR(dev->rstc);
+               if (ret == -ENOENT || ret == -ENOSYS) {
+                       dev->rstc = NULL;
+               } else {
+                       dev_err(&pdev->dev, "failed get reset control: %d\n",
+                               ret);
+                       return ret;
+               }
+       }
+
+       /* Get IRAM pool from device tree or platform data */
+       pool = of_get_named_gen_pool(np, "iram", 0);
+       if (!pool && pdata)
+               pool = dev_get_gen_pool(pdata->iram_dev);
+       if (!pool) {
+               dev_err(&pdev->dev, "iram pool not available\n");
+               return -ENOMEM;
+       }
+       dev->iram_pool = pool;
+
+       ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev);
+       if (ret)
+               return ret;
+
+       mutex_init(&dev->dev_mutex);
+       mutex_init(&dev->coda_mutex);
+
+       pdev_id = of_id ? of_id->data : platform_get_device_id(pdev);
+
+       if (of_id) {
+               dev->devtype = of_id->data;
+       } else if (pdev_id) {
+               dev->devtype = &coda_devdata[pdev_id->driver_data];
+       } else {
+               v4l2_device_unregister(&dev->v4l2_dev);
+               return -EINVAL;
+       }
+
+       dev->debugfs_root = debugfs_create_dir("coda", NULL);
+       if (!dev->debugfs_root)
+               dev_warn(&pdev->dev, "failed to create debugfs root\n");
+
+       /* allocate auxiliary per-device buffers for the BIT processor */
+       if (dev->devtype->product == CODA_DX6) {
+               ret = coda_alloc_aux_buf(dev, &dev->workbuf,
+                                        dev->devtype->workbuf_size, "workbuf",
+                                        dev->debugfs_root);
+               if (ret < 0) {
+                       dev_err(&pdev->dev, "failed to allocate work buffer\n");
+                       v4l2_device_unregister(&dev->v4l2_dev);
+                       return ret;
+               }
+       }
+
+       if (dev->devtype->tempbuf_size) {
+               ret = coda_alloc_aux_buf(dev, &dev->tempbuf,
+                                        dev->devtype->tempbuf_size, "tempbuf",
+                                        dev->debugfs_root);
+               if (ret < 0) {
+                       dev_err(&pdev->dev, "failed to allocate temp buffer\n");
+                       v4l2_device_unregister(&dev->v4l2_dev);
+                       return ret;
+               }
+       }
+
+       dev->iram.size = dev->devtype->iram_size;
+       dev->iram.vaddr = gen_pool_dma_alloc(dev->iram_pool, dev->iram.size,
+                                            &dev->iram.paddr);
+       if (!dev->iram.vaddr) {
+               dev_warn(&pdev->dev, "unable to alloc iram\n");
+       } else {
+               dev->iram.blob.data = dev->iram.vaddr;
+               dev->iram.blob.size = dev->iram.size;
+               dev->iram.dentry = debugfs_create_blob("iram", 0644,
+                                                      dev->debugfs_root,
+                                                      &dev->iram.blob);
+       }
+
+       dev->workqueue = alloc_workqueue("coda", WQ_UNBOUND | WQ_MEM_RECLAIM, 1);
+       if (!dev->workqueue) {
+               dev_err(&pdev->dev, "unable to alloc workqueue\n");
+               return -ENOMEM;
+       }
+
+       platform_set_drvdata(pdev, dev);
+
+       /*
+        * Start activated so we can directly call coda_hw_init in
+        * coda_fw_callback regardless of whether CONFIG_PM_RUNTIME is
+        * enabled or whether the device is associated with a PM domain.
+        */
+       pm_runtime_get_noresume(&pdev->dev);
+       pm_runtime_set_active(&pdev->dev);
+       pm_runtime_enable(&pdev->dev);
+
+       return coda_firmware_request(dev);
+}
+
+static int coda_remove(struct platform_device *pdev)
+{
+       struct coda_dev *dev = platform_get_drvdata(pdev);
+
+       video_unregister_device(&dev->vfd[0]);
+       video_unregister_device(&dev->vfd[1]);
+       if (dev->m2m_dev)
+               v4l2_m2m_release(dev->m2m_dev);
+       pm_runtime_disable(&pdev->dev);
+       if (dev->alloc_ctx)
+               vb2_dma_contig_cleanup_ctx(dev->alloc_ctx);
+       v4l2_device_unregister(&dev->v4l2_dev);
+       destroy_workqueue(dev->workqueue);
+       if (dev->iram.vaddr)
+               gen_pool_free(dev->iram_pool, (unsigned long)dev->iram.vaddr,
+                             dev->iram.size);
+       coda_free_aux_buf(dev, &dev->codebuf);
+       coda_free_aux_buf(dev, &dev->tempbuf);
+       coda_free_aux_buf(dev, &dev->workbuf);
+       debugfs_remove_recursive(dev->debugfs_root);
+       return 0;
+}
+
+#ifdef CONFIG_PM_RUNTIME
+static int coda_runtime_resume(struct device *dev)
+{
+       struct coda_dev *cdev = dev_get_drvdata(dev);
+       int ret = 0;
+
+       if (dev->pm_domain && cdev->codebuf.vaddr) {
+               ret = coda_hw_init(cdev);
+               if (ret)
+                       v4l2_err(&cdev->v4l2_dev, "HW initialization failed\n");
+       }
+
+       return ret;
+}
+#endif
+
+static const struct dev_pm_ops coda_pm_ops = {
+       SET_RUNTIME_PM_OPS(NULL, coda_runtime_resume, NULL)
+};
+
+static struct platform_driver coda_driver = {
+       .probe  = coda_probe,
+       .remove = coda_remove,
+       .driver = {
+               .name   = CODA_NAME,
+               .owner  = THIS_MODULE,
+               .of_match_table = of_match_ptr(coda_dt_ids),
+               .pm     = &coda_pm_ops,
+       },
+       .id_table = coda_platform_ids,
+};
+
+module_platform_driver(coda_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Javier Martin <javier.martin@vista-silicon.com>");
+MODULE_DESCRIPTION("Coda multi-standard codec V4L2 driver");
diff --git a/drivers/media/platform/coda/coda-h264.c b/drivers/media/platform/coda/coda-h264.c
new file mode 100644 (file)
index 0000000..456773a
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * Coda multi-standard codec IP - H.264 helper functions
+ *
+ * Copyright (C) 2012 Vista Silicon S.L.
+ *    Javier Martin, <javier.martin@vista-silicon.com>
+ *    Xavier Duret
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/kernel.h>
+#include <linux/string.h>
+
+static const u8 coda_filler_nal[14] = { 0x00, 0x00, 0x00, 0x01, 0x0c, 0xff,
+                       0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80 };
+static const u8 coda_filler_size[8] = { 0, 7, 14, 13, 12, 11, 10, 9 };
+
+int coda_h264_padding(int size, char *p)
+{
+       int nal_size;
+       int diff;
+
+       diff = size - (size & ~0x7);
+       if (diff == 0)
+               return 0;
+
+       nal_size = coda_filler_size[diff];
+       memcpy(p, coda_filler_nal, nal_size);
+
+       /* Add rbsp stop bit and trailing at the end */
+       *(p + nal_size - 1) = 0x80;
+
+       return nal_size;
+}
diff --git a/drivers/media/platform/coda/coda.h b/drivers/media/platform/coda/coda.h
new file mode 100644 (file)
index 0000000..bbc18c0
--- /dev/null
@@ -0,0 +1,287 @@
+/*
+ * Coda multi-standard codec IP
+ *
+ * Copyright (C) 2012 Vista Silicon S.L.
+ *    Javier Martin, <javier.martin@vista-silicon.com>
+ *    Xavier Duret
+ * Copyright (C) 2012-2014 Philipp Zabel, Pengutronix
+ *
+ * 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/debugfs.h>
+#include <linux/irqreturn.h>
+#include <linux/mutex.h>
+#include <linux/kfifo.h>
+#include <linux/videodev2.h>
+
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-fh.h>
+#include <media/videobuf2-core.h>
+
+#include "coda_regs.h"
+
+#define CODA_MAX_FRAMEBUFFERS  8
+#define CODA_MAX_FRAME_SIZE    0x100000
+#define FMO_SLICE_SAVE_BUF_SIZE        (32)
+
+enum {
+       V4L2_M2M_SRC = 0,
+       V4L2_M2M_DST = 1,
+};
+
+enum coda_inst_type {
+       CODA_INST_ENCODER,
+       CODA_INST_DECODER,
+};
+
+enum coda_product {
+       CODA_DX6 = 0xf001,
+       CODA_7541 = 0xf012,
+       CODA_960 = 0xf020,
+};
+
+struct coda_devtype {
+       char                    *firmware;
+       enum coda_product       product;
+       const struct coda_codec *codecs;
+       unsigned int            num_codecs;
+       size_t                  workbuf_size;
+       size_t                  tempbuf_size;
+       size_t                  iram_size;
+};
+
+struct coda_aux_buf {
+       void                    *vaddr;
+       dma_addr_t              paddr;
+       u32                     size;
+       struct debugfs_blob_wrapper blob;
+       struct dentry           *dentry;
+};
+
+struct coda_dev {
+       struct v4l2_device      v4l2_dev;
+       struct video_device     vfd[2];
+       struct platform_device  *plat_dev;
+       const struct coda_devtype *devtype;
+
+       void __iomem            *regs_base;
+       struct clk              *clk_per;
+       struct clk              *clk_ahb;
+       struct reset_control    *rstc;
+
+       struct coda_aux_buf     codebuf;
+       struct coda_aux_buf     tempbuf;
+       struct coda_aux_buf     workbuf;
+       struct gen_pool         *iram_pool;
+       struct coda_aux_buf     iram;
+
+       spinlock_t              irqlock;
+       struct mutex            dev_mutex;
+       struct mutex            coda_mutex;
+       struct workqueue_struct *workqueue;
+       struct v4l2_m2m_dev     *m2m_dev;
+       struct vb2_alloc_ctx    *alloc_ctx;
+       struct list_head        instances;
+       unsigned long           instance_mask;
+       struct dentry           *debugfs_root;
+};
+
+struct coda_codec {
+       u32 mode;
+       u32 src_fourcc;
+       u32 dst_fourcc;
+       u32 max_w;
+       u32 max_h;
+};
+
+struct coda_huff_tab;
+
+struct coda_params {
+       u8                      rot_mode;
+       u8                      h264_intra_qp;
+       u8                      h264_inter_qp;
+       u8                      h264_min_qp;
+       u8                      h264_max_qp;
+       u8                      h264_deblk_enabled;
+       u8                      h264_deblk_alpha;
+       u8                      h264_deblk_beta;
+       u8                      mpeg4_intra_qp;
+       u8                      mpeg4_inter_qp;
+       u8                      gop_size;
+       int                     intra_refresh;
+       int                     codec_mode;
+       int                     codec_mode_aux;
+       enum v4l2_mpeg_video_multi_slice_mode slice_mode;
+       u32                     framerate;
+       u16                     bitrate;
+       u32                     slice_max_bits;
+       u32                     slice_max_mb;
+};
+
+struct coda_timestamp {
+       struct list_head        list;
+       u32                     sequence;
+       struct v4l2_timecode    timecode;
+       struct timeval          timestamp;
+};
+
+/* Per-queue, driver-specific private data */
+struct coda_q_data {
+       unsigned int            width;
+       unsigned int            height;
+       unsigned int            bytesperline;
+       unsigned int            sizeimage;
+       unsigned int            fourcc;
+       struct v4l2_rect        rect;
+};
+
+struct coda_iram_info {
+       u32             axi_sram_use;
+       phys_addr_t     buf_bit_use;
+       phys_addr_t     buf_ip_ac_dc_use;
+       phys_addr_t     buf_dbk_y_use;
+       phys_addr_t     buf_dbk_c_use;
+       phys_addr_t     buf_ovl_use;
+       phys_addr_t     buf_btp_use;
+       phys_addr_t     search_ram_paddr;
+       int             search_ram_size;
+       int             remaining;
+       phys_addr_t     next_paddr;
+};
+
+struct gdi_tiled_map {
+       int xy2ca_map[16];
+       int xy2ba_map[16];
+       int xy2ra_map[16];
+       int rbc2axi_map[32];
+       int xy2rbc_config;
+       int map_type;
+#define GDI_LINEAR_FRAME_MAP 0
+};
+
+struct coda_ctx;
+
+struct coda_context_ops {
+       int (*queue_init)(void *priv, struct vb2_queue *src_vq,
+                         struct vb2_queue *dst_vq);
+       int (*start_streaming)(struct coda_ctx *ctx);
+       int (*prepare_run)(struct coda_ctx *ctx);
+       void (*finish_run)(struct coda_ctx *ctx);
+       void (*seq_end_work)(struct work_struct *work);
+       void (*release)(struct coda_ctx *ctx);
+};
+
+struct coda_ctx {
+       struct coda_dev                 *dev;
+       struct mutex                    buffer_mutex;
+       struct list_head                list;
+       struct work_struct              pic_run_work;
+       struct work_struct              seq_end_work;
+       struct completion               completion;
+       const struct coda_context_ops   *ops;
+       int                             aborting;
+       int                             initialized;
+       int                             streamon_out;
+       int                             streamon_cap;
+       u32                             isequence;
+       u32                             qsequence;
+       u32                             osequence;
+       u32                             sequence_offset;
+       struct coda_q_data              q_data[2];
+       enum coda_inst_type             inst_type;
+       const struct coda_codec         *codec;
+       enum v4l2_colorspace            colorspace;
+       struct coda_params              params;
+       struct v4l2_ctrl_handler        ctrls;
+       struct v4l2_fh                  fh;
+       int                             gopcounter;
+       int                             runcounter;
+       char                            vpu_header[3][64];
+       int                             vpu_header_size[3];
+       struct kfifo                    bitstream_fifo;
+       struct mutex                    bitstream_mutex;
+       struct coda_aux_buf             bitstream;
+       bool                            hold;
+       struct coda_aux_buf             parabuf;
+       struct coda_aux_buf             psbuf;
+       struct coda_aux_buf             slicebuf;
+       struct coda_aux_buf             internal_frames[CODA_MAX_FRAMEBUFFERS];
+       u32                             frame_types[CODA_MAX_FRAMEBUFFERS];
+       struct coda_timestamp           frame_timestamps[CODA_MAX_FRAMEBUFFERS];
+       u32                             frame_errors[CODA_MAX_FRAMEBUFFERS];
+       struct list_head                timestamp_list;
+       struct coda_aux_buf             workbuf;
+       int                             num_internal_frames;
+       int                             idx;
+       int                             reg_idx;
+       struct coda_iram_info           iram_info;
+       struct gdi_tiled_map            tiled_map;
+       u32                             bit_stream_param;
+       u32                             frm_dis_flg;
+       u32                             frame_mem_ctrl;
+       int                             display_idx;
+       struct dentry                   *debugfs_entry;
+};
+
+extern int coda_debug;
+
+void coda_write(struct coda_dev *dev, u32 data, u32 reg);
+unsigned int coda_read(struct coda_dev *dev, u32 reg);
+
+int coda_alloc_aux_buf(struct coda_dev *dev, struct coda_aux_buf *buf,
+                      size_t size, const char *name, struct dentry *parent);
+void coda_free_aux_buf(struct coda_dev *dev, struct coda_aux_buf *buf);
+
+static inline int coda_alloc_context_buf(struct coda_ctx *ctx,
+                                        struct coda_aux_buf *buf, size_t size,
+                                        const char *name)
+{
+       return coda_alloc_aux_buf(ctx->dev, buf, size, name, ctx->debugfs_entry);
+}
+
+int coda_encoder_queue_init(void *priv, struct vb2_queue *src_vq,
+                           struct vb2_queue *dst_vq);
+int coda_decoder_queue_init(void *priv, struct vb2_queue *src_vq,
+                           struct vb2_queue *dst_vq);
+
+int coda_hw_reset(struct coda_ctx *ctx);
+
+void coda_fill_bitstream(struct coda_ctx *ctx);
+
+void coda_set_gdi_regs(struct coda_ctx *ctx);
+
+static inline struct coda_q_data *get_q_data(struct coda_ctx *ctx,
+                                            enum v4l2_buf_type type)
+{
+       switch (type) {
+       case V4L2_BUF_TYPE_VIDEO_OUTPUT:
+               return &(ctx->q_data[V4L2_M2M_SRC]);
+       case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+               return &(ctx->q_data[V4L2_M2M_DST]);
+       default:
+               return NULL;
+       }
+}
+
+const char *coda_product_name(int product);
+
+int coda_check_firmware(struct coda_dev *dev);
+
+static inline int coda_get_bitstream_payload(struct coda_ctx *ctx)
+{
+       return kfifo_len(&ctx->bitstream_fifo);
+}
+
+void coda_bit_stream_end_flag(struct coda_ctx *ctx);
+
+int coda_h264_padding(int size, char *p);
+
+extern const struct coda_context_ops coda_bit_encode_ops;
+extern const struct coda_context_ops coda_bit_decode_ops;
+
+irqreturn_t coda_irq_handler(int irq, void *data);
diff --git a/drivers/media/platform/coda/coda_regs.h b/drivers/media/platform/coda/coda_regs.h
new file mode 100644 (file)
index 0000000..c791275
--- /dev/null
@@ -0,0 +1,447 @@
+/*
+ * linux/drivers/media/platform/coda/coda_regs.h
+ *
+ * Copyright (C) 2012 Vista Silicon SL
+ *    Javier Martin <javier.martin@vista-silicon.com>
+ *    Xavier Duret
+ *
+ * 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 _REGS_CODA_H_
+#define _REGS_CODA_H_
+
+/* HW registers */
+#define CODA_REG_BIT_CODE_RUN                  0x000
+#define                CODA_REG_RUN_ENABLE             (1 << 0)
+#define CODA_REG_BIT_CODE_DOWN                 0x004
+#define                CODA_DOWN_ADDRESS_SET(x)        (((x) & 0xffff) << 16)
+#define                CODA_DOWN_DATA_SET(x)           ((x) & 0xffff)
+#define CODA_REG_BIT_HOST_IN_REQ               0x008
+#define CODA_REG_BIT_INT_CLEAR                 0x00c
+#define                CODA_REG_BIT_INT_CLEAR_SET      0x1
+#define CODA_REG_BIT_INT_STATUS                0x010
+#define CODA_REG_BIT_CODE_RESET                0x014
+#define                CODA_REG_RESET_ENABLE           (1 << 0)
+#define CODA_REG_BIT_CUR_PC                    0x018
+#define CODA9_REG_BIT_SW_RESET                 0x024
+#define                CODA9_SW_RESET_BPU_CORE   0x008
+#define                CODA9_SW_RESET_BPU_BUS    0x010
+#define                CODA9_SW_RESET_VCE_CORE   0x020
+#define                CODA9_SW_RESET_VCE_BUS    0x040
+#define                CODA9_SW_RESET_GDI_CORE   0x080
+#define                CODA9_SW_RESET_GDI_BUS    0x100
+#define CODA9_REG_BIT_SW_RESET_STATUS          0x034
+
+/* Static SW registers */
+#define CODA_REG_BIT_CODE_BUF_ADDR             0x100
+#define CODA_REG_BIT_WORK_BUF_ADDR             0x104
+#define CODA_REG_BIT_PARA_BUF_ADDR             0x108
+#define CODA_REG_BIT_STREAM_CTRL               0x10c
+#define                CODA7_STREAM_BUF_PIC_RESET      (1 << 4)
+#define                CODADX6_STREAM_BUF_PIC_RESET    (1 << 3)
+#define                CODA7_STREAM_BUF_PIC_FLUSH      (1 << 3)
+#define                CODADX6_STREAM_BUF_PIC_FLUSH    (1 << 2)
+#define                CODA7_STREAM_BUF_DYNALLOC_EN    (1 << 5)
+#define                CODADX6_STREAM_BUF_DYNALLOC_EN  (1 << 4)
+#define                CODADX6_STREAM_CHKDIS_OFFSET    (1 << 1)
+#define                CODA7_STREAM_SEL_64BITS_ENDIAN  (1 << 1)
+#define                CODA_STREAM_ENDIAN_SELECT       (1 << 0)
+#define CODA_REG_BIT_FRAME_MEM_CTRL            0x110
+#define                CODA_FRAME_CHROMA_INTERLEAVE    (1 << 2)
+#define                CODA_IMAGE_ENDIAN_SELECT        (1 << 0)
+#define CODA_REG_BIT_BIT_STREAM_PARAM          0x114
+#define                CODA_BIT_STREAM_END_FLAG        (1 << 2)
+#define                CODA_BIT_DEC_SEQ_INIT_ESCAPE    (1 << 0)
+#define CODA_REG_BIT_TEMP_BUF_ADDR             0x118
+#define CODA_REG_BIT_RD_PTR(x)                 (0x120 + 8 * (x))
+#define CODA_REG_BIT_WR_PTR(x)                 (0x124 + 8 * (x))
+#define CODA_REG_BIT_FRM_DIS_FLG(x)            (0x150 + 4 * (x))
+#define CODADX6_REG_BIT_SEARCH_RAM_BASE_ADDR   0x140
+#define CODA7_REG_BIT_AXI_SRAM_USE             0x140
+#define                CODA9_USE_HOST_BTP_ENABLE       (1 << 13)
+#define                CODA9_USE_HOST_OVL_ENABLE       (1 << 12)
+#define                CODA7_USE_HOST_ME_ENABLE        (1 << 11)
+#define                CODA9_USE_HOST_DBK_ENABLE       (3 << 10)
+#define                CODA7_USE_HOST_OVL_ENABLE       (1 << 10)
+#define                CODA7_USE_HOST_DBK_ENABLE       (1 << 9)
+#define                CODA9_USE_HOST_IP_ENABLE        (1 << 9)
+#define                CODA7_USE_HOST_IP_ENABLE        (1 << 8)
+#define                CODA9_USE_HOST_BIT_ENABLE       (1 << 8)
+#define                CODA7_USE_HOST_BIT_ENABLE       (1 << 7)
+#define                CODA9_USE_BTP_ENABLE            (1 << 5)
+#define                CODA7_USE_ME_ENABLE             (1 << 4)
+#define                CODA9_USE_OVL_ENABLE            (1 << 4)
+#define                CODA7_USE_OVL_ENABLE            (1 << 3)
+#define                CODA9_USE_DBK_ENABLE            (3 << 2)
+#define                CODA7_USE_DBK_ENABLE            (1 << 2)
+#define                CODA7_USE_IP_ENABLE             (1 << 1)
+#define                CODA7_USE_BIT_ENABLE            (1 << 0)
+
+#define CODA_REG_BIT_BUSY                      0x160
+#define                CODA_REG_BIT_BUSY_FLAG          1
+#define CODA_REG_BIT_RUN_COMMAND               0x164
+#define                CODA_COMMAND_SEQ_INIT           1
+#define                CODA_COMMAND_SEQ_END            2
+#define                CODA_COMMAND_PIC_RUN            3
+#define                CODA_COMMAND_SET_FRAME_BUF      4
+#define                CODA_COMMAND_ENCODE_HEADER      5
+#define                CODA_COMMAND_ENC_PARA_SET       6
+#define                CODA_COMMAND_DEC_PARA_SET       7
+#define                CODA_COMMAND_DEC_BUF_FLUSH      8
+#define                CODA_COMMAND_RC_CHANGE_PARAMETER 9
+#define                CODA_COMMAND_FIRMWARE_GET       0xf
+#define CODA_REG_BIT_RUN_INDEX                 0x168
+#define                CODA_INDEX_SET(x)               ((x) & 0x3)
+#define CODA_REG_BIT_RUN_COD_STD               0x16c
+#define                CODADX6_MODE_DECODE_MP4         0
+#define                CODADX6_MODE_ENCODE_MP4         1
+#define                CODADX6_MODE_DECODE_H264        2
+#define                CODADX6_MODE_ENCODE_H264        3
+#define                CODA7_MODE_DECODE_H264          0
+#define                CODA7_MODE_DECODE_VC1           1
+#define                CODA7_MODE_DECODE_MP2           2
+#define                CODA7_MODE_DECODE_MP4           3
+#define                CODA7_MODE_DECODE_DV3           3
+#define                CODA7_MODE_DECODE_RV            4
+#define                CODA7_MODE_DECODE_MJPG          5
+#define                CODA7_MODE_ENCODE_H264          8
+#define                CODA7_MODE_ENCODE_MP4           11
+#define                CODA7_MODE_ENCODE_MJPG          13
+#define                CODA9_MODE_DECODE_H264          0
+#define                CODA9_MODE_DECODE_VC1           1
+#define                CODA9_MODE_DECODE_MP2           2
+#define                CODA9_MODE_DECODE_MP4           3
+#define                CODA9_MODE_DECODE_DV3           3
+#define                CODA9_MODE_DECODE_RV            4
+#define                CODA9_MODE_DECODE_AVS           5
+#define                CODA9_MODE_DECODE_MJPG          6
+#define                CODA9_MODE_DECODE_VPX           7
+#define                CODA9_MODE_ENCODE_H264          8
+#define                CODA9_MODE_ENCODE_MP4           11
+#define                CODA9_MODE_ENCODE_MJPG          13
+#define        CODA_MODE_INVALID               0xffff
+#define CODA_REG_BIT_INT_ENABLE                0x170
+#define                CODA_INT_INTERRUPT_ENABLE       (1 << 3)
+#define CODA_REG_BIT_INT_REASON                        0x174
+#define CODA7_REG_BIT_RUN_AUX_STD              0x178
+#define                CODA_MP4_AUX_MPEG4              0
+#define                CODA_MP4_AUX_DIVX3              1
+#define                CODA_VPX_AUX_THO                0
+#define                CODA_VPX_AUX_VP6                1
+#define                CODA_VPX_AUX_VP8                2
+#define                CODA_H264_AUX_AVC               0
+#define                CODA_H264_AUX_MVC               1
+
+/*
+ * Commands' mailbox:
+ * registers with offsets in the range 0x180-0x1d0
+ * have different meaning depending on the command being
+ * issued.
+ */
+
+/* Decoder Sequence Initialization */
+#define CODA_CMD_DEC_SEQ_BB_START              0x180
+#define CODA_CMD_DEC_SEQ_BB_SIZE               0x184
+#define CODA_CMD_DEC_SEQ_OPTION                        0x188
+#define                CODA_REORDER_ENABLE                     (1 << 1)
+#define                CODADX6_QP_REPORT                       (1 << 0)
+#define                CODA7_MP4_DEBLK_ENABLE                  (1 << 0)
+#define CODA_CMD_DEC_SEQ_SRC_SIZE              0x18c
+#define CODA_CMD_DEC_SEQ_START_BYTE            0x190
+#define CODA_CMD_DEC_SEQ_PS_BB_START           0x194
+#define CODA_CMD_DEC_SEQ_PS_BB_SIZE            0x198
+#define CODA_CMD_DEC_SEQ_MP4_ASP_CLASS         0x19c
+#define CODA_CMD_DEC_SEQ_X264_MV_EN            0x19c
+#define CODA_CMD_DEC_SEQ_SPP_CHUNK_SIZE                0x1a0
+
+#define CODA7_RET_DEC_SEQ_ASPECT               0x1b0
+#define CODA9_RET_DEC_SEQ_BITRATE              0x1b4
+#define CODA_RET_DEC_SEQ_SUCCESS               0x1c0
+#define CODA_RET_DEC_SEQ_SRC_FMT               0x1c4 /* SRC_SIZE on CODA7 */
+#define CODA_RET_DEC_SEQ_SRC_SIZE              0x1c4
+#define CODA_RET_DEC_SEQ_SRC_F_RATE            0x1c8
+#define CODA9_RET_DEC_SEQ_ASPECT               0x1c8
+#define CODA_RET_DEC_SEQ_FRAME_NEED            0x1cc
+#define CODA_RET_DEC_SEQ_FRAME_DELAY           0x1d0
+#define CODA_RET_DEC_SEQ_INFO                  0x1d4
+#define CODA_RET_DEC_SEQ_CROP_LEFT_RIGHT       0x1d8
+#define CODA_RET_DEC_SEQ_CROP_TOP_BOTTOM       0x1dc
+#define CODA_RET_DEC_SEQ_NEXT_FRAME_NUM                0x1e0
+#define CODA_RET_DEC_SEQ_ERR_REASON            0x1e0
+#define CODA_RET_DEC_SEQ_FRATE_NR              0x1e4
+#define CODA_RET_DEC_SEQ_FRATE_DR              0x1e8
+#define CODA_RET_DEC_SEQ_JPG_PARA              0x1e4
+#define CODA_RET_DEC_SEQ_JPG_THUMB_IND         0x1e8
+#define CODA9_RET_DEC_SEQ_HEADER_REPORT                0x1ec
+
+/* Decoder Picture Run */
+#define CODA_CMD_DEC_PIC_ROT_MODE              0x180
+#define CODA_CMD_DEC_PIC_ROT_ADDR_Y            0x184
+#define CODA9_CMD_DEC_PIC_ROT_INDEX            0x184
+#define CODA_CMD_DEC_PIC_ROT_ADDR_CB           0x188
+#define CODA9_CMD_DEC_PIC_ROT_ADDR_Y           0x188
+#define CODA_CMD_DEC_PIC_ROT_ADDR_CR           0x18c
+#define CODA9_CMD_DEC_PIC_ROT_ADDR_CB          0x18c
+#define CODA_CMD_DEC_PIC_ROT_STRIDE            0x190
+#define CODA9_CMD_DEC_PIC_ROT_ADDR_CR          0x190
+#define CODA9_CMD_DEC_PIC_ROT_STRIDE           0x1b8
+
+#define CODA_CMD_DEC_PIC_OPTION                        0x194
+#define                CODA_PRE_SCAN_EN                        (1 << 0)
+#define                CODA_PRE_SCAN_MODE_DECODE               (0 << 1)
+#define                CODA_PRE_SCAN_MODE_RETURN               (1 << 1)
+#define                CODA_IFRAME_SEARCH_EN                   (1 << 2)
+#define                CODA_SKIP_FRAME_MODE                    (0x3 << 3)
+#define CODA_CMD_DEC_PIC_SKIP_NUM              0x198
+#define CODA_CMD_DEC_PIC_CHUNK_SIZE            0x19c
+#define CODA_CMD_DEC_PIC_BB_START              0x1a0
+#define CODA_CMD_DEC_PIC_START_BYTE            0x1a4
+#define CODA_RET_DEC_PIC_SIZE                  0x1bc
+#define CODA_RET_DEC_PIC_FRAME_NUM             0x1c0
+#define CODA_RET_DEC_PIC_FRAME_IDX             0x1c4
+#define CODA_RET_DEC_PIC_ERR_MB                        0x1c8
+#define CODA_RET_DEC_PIC_TYPE                  0x1cc
+#define                CODA_PIC_TYPE_MASK                      0x7
+#define                CODA_PIC_TYPE_MASK_VC1                  0x3f
+#define                CODA9_PIC_TYPE_FIRST_MASK               (0x7 << 3)
+#define                CODA9_PIC_TYPE_IDR_MASK                 (0x3 << 6)
+#define                CODA7_PIC_TYPE_H264_NPF_MASK            (0x3 << 16)
+#define                CODA7_PIC_TYPE_INTERLACED               (1 << 18)
+#define CODA_RET_DEC_PIC_POST                  0x1d0
+#define CODA_RET_DEC_PIC_MVC_REPORT            0x1d0
+#define CODA_RET_DEC_PIC_OPTION                        0x1d4
+#define CODA_RET_DEC_PIC_SUCCESS               0x1d8
+#define CODA_RET_DEC_PIC_CUR_IDX               0x1dc
+#define CODA_RET_DEC_PIC_CROP_LEFT_RIGHT       0x1e0
+#define CODA_RET_DEC_PIC_CROP_TOP_BOTTOM       0x1e4
+#define CODA_RET_DEC_PIC_FRAME_NEED            0x1ec
+
+#define CODA9_RET_DEC_PIC_VP8_PIC_REPORT       0x1e8
+#define CODA9_RET_DEC_PIC_ASPECT               0x1f0
+#define CODA9_RET_DEC_PIC_VP8_SCALE_INFO       0x1f0
+#define CODA9_RET_DEC_PIC_FRATE_NR             0x1f4
+#define CODA9_RET_DEC_PIC_FRATE_DR             0x1f8
+
+/* Encoder Sequence Initialization */
+#define CODA_CMD_ENC_SEQ_BB_START                              0x180
+#define CODA_CMD_ENC_SEQ_BB_SIZE                               0x184
+#define CODA_CMD_ENC_SEQ_OPTION                                0x188
+#define                CODA7_OPTION_AVCINTRA16X16ONLY_OFFSET           9
+#define                CODA9_OPTION_MVC_PREFIX_NAL_OFFSET              9
+#define                CODA7_OPTION_GAMMA_OFFSET                       8
+#define                CODA9_OPTION_MVC_PARASET_REFRESH_OFFSET         8
+#define                CODA7_OPTION_RCQPMAX_OFFSET                     7
+#define                CODA9_OPTION_GAMMA_OFFSET                       7
+#define                CODADX6_OPTION_GAMMA_OFFSET                     7
+#define                CODA7_OPTION_RCQPMIN_OFFSET                     6
+#define                CODA9_OPTION_RCQPMAX_OFFSET                     6
+#define                CODA_OPTION_LIMITQP_OFFSET                      6
+#define                CODA_OPTION_RCINTRAQP_OFFSET                    5
+#define                CODA_OPTION_FMO_OFFSET                          4
+#define                CODA9_OPTION_MVC_INTERVIEW_OFFSET               4
+#define                CODA_OPTION_AVC_AUD_OFFSET                      2
+#define                CODA_OPTION_SLICEREPORT_OFFSET                  1
+#define CODA_CMD_ENC_SEQ_COD_STD                               0x18c
+#define                CODA_STD_MPEG4                                  0
+#define                CODA9_STD_H264                                  0
+#define                CODA_STD_H263                                   1
+#define                CODA_STD_H264                                   2
+#define                CODA_STD_MJPG                                   3
+#define                CODA9_STD_MPEG4                                 3
+
+#define CODA_CMD_ENC_SEQ_SRC_SIZE                              0x190
+#define                CODA7_PICWIDTH_OFFSET                           16
+#define                CODA7_PICWIDTH_MASK                             0xffff
+#define                CODADX6_PICWIDTH_OFFSET                         10
+#define                CODADX6_PICWIDTH_MASK                           0x3ff
+#define                CODA_PICHEIGHT_OFFSET                           0
+#define                CODADX6_PICHEIGHT_MASK                          0x3ff
+#define                CODA7_PICHEIGHT_MASK                            0xffff
+#define CODA_CMD_ENC_SEQ_SRC_F_RATE                            0x194
+#define CODA_CMD_ENC_SEQ_MP4_PARA                              0x198
+#define                CODA_MP4PARAM_VERID_OFFSET                      6
+#define                CODA_MP4PARAM_VERID_MASK                        0x01
+#define                CODA_MP4PARAM_INTRADCVLCTHR_OFFSET              2
+#define                CODA_MP4PARAM_INTRADCVLCTHR_MASK                0x07
+#define                CODA_MP4PARAM_REVERSIBLEVLCENABLE_OFFSET        1
+#define                CODA_MP4PARAM_REVERSIBLEVLCENABLE_MASK          0x01
+#define                CODA_MP4PARAM_DATAPARTITIONENABLE_OFFSET        0
+#define                CODA_MP4PARAM_DATAPARTITIONENABLE_MASK          0x01
+#define CODA_CMD_ENC_SEQ_263_PARA                              0x19c
+#define                CODA_263PARAM_ANNEXJENABLE_OFFSET               2
+#define                CODA_263PARAM_ANNEXJENABLE_MASK         0x01
+#define                CODA_263PARAM_ANNEXKENABLE_OFFSET               1
+#define                CODA_263PARAM_ANNEXKENABLE_MASK         0x01
+#define                CODA_263PARAM_ANNEXTENABLE_OFFSET               0
+#define                CODA_263PARAM_ANNEXTENABLE_MASK         0x01
+#define CODA_CMD_ENC_SEQ_264_PARA                              0x1a0
+#define                CODA_264PARAM_DEBLKFILTEROFFSETBETA_OFFSET      12
+#define                CODA_264PARAM_DEBLKFILTEROFFSETBETA_MASK        0x0f
+#define                CODA_264PARAM_DEBLKFILTEROFFSETALPHA_OFFSET     8
+#define                CODA_264PARAM_DEBLKFILTEROFFSETALPHA_MASK       0x0f
+#define                CODA_264PARAM_DISABLEDEBLK_OFFSET               6
+#define                CODA_264PARAM_DISABLEDEBLK_MASK         0x01
+#define                CODA_264PARAM_CONSTRAINEDINTRAPREDFLAG_OFFSET   5
+#define                CODA_264PARAM_CONSTRAINEDINTRAPREDFLAG_MASK     0x01
+#define                CODA_264PARAM_CHROMAQPOFFSET_OFFSET             0
+#define                CODA_264PARAM_CHROMAQPOFFSET_MASK               0x1f
+#define CODA_CMD_ENC_SEQ_SLICE_MODE                            0x1a4
+#define                CODA_SLICING_SIZE_OFFSET                        2
+#define                CODA_SLICING_SIZE_MASK                          0x3fffffff
+#define                CODA_SLICING_UNIT_OFFSET                        1
+#define                CODA_SLICING_UNIT_MASK                          0x01
+#define                CODA_SLICING_MODE_OFFSET                        0
+#define                CODA_SLICING_MODE_MASK                          0x01
+#define CODA_CMD_ENC_SEQ_GOP_SIZE                              0x1a8
+#define                CODA_GOP_SIZE_OFFSET                            0
+#define                CODA_GOP_SIZE_MASK                              0x3f
+#define CODA_CMD_ENC_SEQ_RC_PARA                               0x1ac
+#define                CODA_RATECONTROL_AUTOSKIP_OFFSET                31
+#define                CODA_RATECONTROL_AUTOSKIP_MASK                  0x01
+#define                CODA_RATECONTROL_INITIALDELAY_OFFSET            16
+#define                CODA_RATECONTROL_INITIALDELAY_MASK              0x7f
+#define                CODA_RATECONTROL_BITRATE_OFFSET         1
+#define                CODA_RATECONTROL_BITRATE_MASK                   0x7f
+#define                CODA_RATECONTROL_ENABLE_OFFSET                  0
+#define                CODA_RATECONTROL_ENABLE_MASK                    0x01
+#define CODA_CMD_ENC_SEQ_RC_BUF_SIZE                           0x1b0
+#define CODA_CMD_ENC_SEQ_INTRA_REFRESH                         0x1b4
+#define CODADX6_CMD_ENC_SEQ_FMO                                        0x1b8
+#define                CODA_FMOPARAM_TYPE_OFFSET                       4
+#define                CODA_FMOPARAM_TYPE_MASK                         1
+#define                CODA_FMOPARAM_SLICENUM_OFFSET                   0
+#define                CODA_FMOPARAM_SLICENUM_MASK                     0x0f
+#define CODADX6_CMD_ENC_SEQ_INTRA_QP                           0x1bc
+#define CODA7_CMD_ENC_SEQ_SEARCH_BASE                          0x1b8
+#define CODA7_CMD_ENC_SEQ_SEARCH_SIZE                          0x1bc
+#define CODA7_CMD_ENC_SEQ_INTRA_QP                             0x1c4
+#define CODA_CMD_ENC_SEQ_RC_QP_MIN_MAX                         0x1c8
+#define                CODA_QPMIN_OFFSET                               8
+#define                CODA_QPMIN_MASK                                 0x3f
+#define                CODA_QPMAX_OFFSET                               0
+#define                CODA_QPMAX_MASK                                 0x3f
+#define CODA_CMD_ENC_SEQ_RC_GAMMA                              0x1cc
+#define                CODA_GAMMA_OFFSET                               0
+#define                CODA_GAMMA_MASK                                 0xffff
+#define CODA_CMD_ENC_SEQ_RC_INTERVAL_MODE                      0x1d0
+#define CODA9_CMD_ENC_SEQ_INTRA_WEIGHT                         0x1d4
+#define CODA9_CMD_ENC_SEQ_ME_OPTION                            0x1d8
+#define CODA_RET_ENC_SEQ_SUCCESS                               0x1c0
+
+/* Encoder Picture Run */
+#define CODA9_CMD_ENC_PIC_SRC_INDEX            0x180
+#define CODA9_CMD_ENC_PIC_SRC_STRIDE           0x184
+#define CODA9_CMD_ENC_PIC_SUB_FRAME_SYNC       0x1a4
+#define CODA9_CMD_ENC_PIC_SRC_ADDR_Y           0x1a8
+#define CODA9_CMD_ENC_PIC_SRC_ADDR_CB          0x1ac
+#define CODA9_CMD_ENC_PIC_SRC_ADDR_CR          0x1b0
+#define CODA_CMD_ENC_PIC_SRC_ADDR_Y    0x180
+#define CODA_CMD_ENC_PIC_SRC_ADDR_CB   0x184
+#define CODA_CMD_ENC_PIC_SRC_ADDR_CR   0x188
+#define CODA_CMD_ENC_PIC_QS            0x18c
+#define CODA_CMD_ENC_PIC_ROT_MODE      0x190
+#define                CODA_ROT_MIR_ENABLE                             (1 << 4)
+#define                CODA_ROT_0                                      (0x0 << 0)
+#define                CODA_ROT_90                                     (0x1 << 0)
+#define                CODA_ROT_180                                    (0x2 << 0)
+#define                CODA_ROT_270                                    (0x3 << 0)
+#define                CODA_MIR_NONE                                   (0x0 << 2)
+#define                CODA_MIR_VER                                    (0x1 << 2)
+#define                CODA_MIR_HOR                                    (0x2 << 2)
+#define                CODA_MIR_VER_HOR                                (0x3 << 2)
+#define CODA_CMD_ENC_PIC_OPTION                0x194
+#define                CODA_FORCE_IPICTURE                             BIT(1)
+#define                CODA_REPORT_MB_INFO                             BIT(3)
+#define                CODA_REPORT_MV_INFO                             BIT(4)
+#define                CODA_REPORT_SLICE_INFO                          BIT(5)
+#define CODA_CMD_ENC_PIC_BB_START      0x198
+#define CODA_CMD_ENC_PIC_BB_SIZE       0x19c
+#define CODA_RET_ENC_FRAME_NUM         0x1c0
+#define CODA_RET_ENC_PIC_TYPE          0x1c4
+#define CODA_RET_ENC_PIC_FRAME_IDX     0x1c8
+#define CODA_RET_ENC_PIC_SLICE_NUM     0x1cc
+#define CODA_RET_ENC_PIC_FLAG          0x1d0
+#define CODA_RET_ENC_PIC_SUCCESS       0x1d8
+
+/* Set Frame Buffer */
+#define CODA_CMD_SET_FRAME_BUF_NUM             0x180
+#define CODA_CMD_SET_FRAME_BUF_STRIDE          0x184
+#define CODA_CMD_SET_FRAME_SLICE_BB_START      0x188
+#define CODA_CMD_SET_FRAME_SLICE_BB_SIZE       0x18c
+#define CODA9_CMD_SET_FRAME_SUBSAMP_A          0x188
+#define CODA9_CMD_SET_FRAME_SUBSAMP_B          0x18c
+#define CODA7_CMD_SET_FRAME_AXI_BIT_ADDR       0x190
+#define CODA7_CMD_SET_FRAME_AXI_IPACDC_ADDR    0x194
+#define CODA7_CMD_SET_FRAME_AXI_DBKY_ADDR      0x198
+#define CODA7_CMD_SET_FRAME_AXI_DBKC_ADDR      0x19c
+#define CODA7_CMD_SET_FRAME_AXI_OVL_ADDR       0x1a0
+#define CODA7_CMD_SET_FRAME_MAX_DEC_SIZE       0x1a4
+#define CODA9_CMD_SET_FRAME_AXI_BTP_ADDR       0x1a4
+#define CODA7_CMD_SET_FRAME_SOURCE_BUF_STRIDE  0x1a8
+#define CODA9_CMD_SET_FRAME_CACHE_SIZE         0x1a8
+#define CODA9_CMD_SET_FRAME_CACHE_CONFIG       0x1ac
+#define                CODA9_CACHE_BYPASS_OFFSET               28
+#define                CODA9_CACHE_DUALCONF_OFFSET             26
+#define                CODA9_CACHE_PAGEMERGE_OFFSET            24
+#define                CODA9_CACHE_LUMA_BUFFER_SIZE_OFFSET     16
+#define                CODA9_CACHE_CB_BUFFER_SIZE_OFFSET       8
+#define                CODA9_CACHE_CR_BUFFER_SIZE_OFFSET       0
+#define CODA9_CMD_SET_FRAME_SUBSAMP_A_MVC      0x1b0
+#define CODA9_CMD_SET_FRAME_SUBSAMP_B_MVC      0x1b4
+#define CODA9_CMD_SET_FRAME_DP_BUF_BASE                0x1b0
+#define CODA9_CMD_SET_FRAME_DP_BUF_SIZE                0x1b4
+#define CODA9_CMD_SET_FRAME_MAX_DEC_SIZE       0x1b8
+#define CODA9_CMD_SET_FRAME_DELAY              0x1bc
+
+/* Encoder Header */
+#define CODA_CMD_ENC_HEADER_CODE       0x180
+#define                CODA_GAMMA_OFFSET       0
+#define                CODA_HEADER_H264_SPS    0
+#define                CODA_HEADER_H264_PPS    1
+#define                CODA_HEADER_MP4V_VOL    0
+#define                CODA_HEADER_MP4V_VOS    1
+#define                CODA_HEADER_MP4V_VIS    2
+#define                CODA9_HEADER_FRAME_CROP (1 << 3)
+#define CODA_CMD_ENC_HEADER_BB_START   0x184
+#define CODA_CMD_ENC_HEADER_BB_SIZE    0x188
+#define CODA9_CMD_ENC_HEADER_FRAME_CROP_H      0x18c
+#define CODA9_CMD_ENC_HEADER_FRAME_CROP_V      0x190
+
+/* Get Version */
+#define CODA_CMD_FIRMWARE_VERNUM               0x1c0
+#define                CODA_FIRMWARE_PRODUCT(x)        (((x) >> 16) & 0xffff)
+#define                CODA_FIRMWARE_MAJOR(x)          (((x) >> 12) & 0x0f)
+#define                CODA_FIRMWARE_MINOR(x)          (((x) >> 8) & 0x0f)
+#define                CODA_FIRMWARE_RELEASE(x)        ((x) & 0xff)
+#define                CODA_FIRMWARE_VERNUM(product, major, minor, release)    \
+                       ((product) << 16 | ((major) << 12) |            \
+                       ((minor) << 8) | (release))
+#define CODA9_CMD_FIRMWARE_CODE_REV            0x1c4
+
+#define CODA9_GDMA_BASE                                0x1000
+#define CODA9_GDI_WPROT_ERR_CLR                        (CODA9_GDMA_BASE + 0x0a0)
+#define CODA9_GDI_WPROT_RGN_EN                 (CODA9_GDMA_BASE + 0x0ac)
+
+#define CODA9_GDI_BUS_CTRL                     (CODA9_GDMA_BASE + 0x0f0)
+#define CODA9_GDI_BUS_STATUS                   (CODA9_GDMA_BASE + 0x0f4)
+
+#define CODA9_GDI_XY2_CAS_0                    (CODA9_GDMA_BASE + 0x800)
+#define CODA9_GDI_XY2_CAS_F                    (CODA9_GDMA_BASE + 0x83c)
+
+#define CODA9_GDI_XY2_BA_0                     (CODA9_GDMA_BASE + 0x840)
+#define CODA9_GDI_XY2_BA_1                     (CODA9_GDMA_BASE + 0x844)
+#define CODA9_GDI_XY2_BA_2                     (CODA9_GDMA_BASE + 0x848)
+#define CODA9_GDI_XY2_BA_3                     (CODA9_GDMA_BASE + 0x84c)
+
+#define CODA9_GDI_XY2_RAS_0                    (CODA9_GDMA_BASE + 0x850)
+#define CODA9_GDI_XY2_RAS_F                    (CODA9_GDMA_BASE + 0x88c)
+
+#define CODA9_GDI_XY2_RBC_CONFIG               (CODA9_GDMA_BASE + 0x890)
+#define CODA9_GDI_RBC2_AXI_0                   (CODA9_GDMA_BASE + 0x8a0)
+#define CODA9_GDI_RBC2_AXI_1F                  (CODA9_GDMA_BASE + 0x91c)
+
+#endif
index afb3aec1320e8262351a31cf1efe6f7fcbe695be..d9e1ddb586b190e99da9cd0b97f60163549e655c 100644 (file)
@@ -1,6 +1,8 @@
 config VIDEO_DAVINCI_VPIF_DISPLAY
        tristate "TI DaVinci VPIF V4L2-Display driver"
-       depends on VIDEO_DEV && ARCH_DAVINCI
+       depends on VIDEO_DEV
+       depends on ARCH_DAVINCI || COMPILE_TEST
+       depends on HAS_DMA
        select VIDEOBUF2_DMA_CONTIG
        select VIDEO_ADV7343 if MEDIA_SUBDRV_AUTOSELECT
        select VIDEO_THS7303 if MEDIA_SUBDRV_AUTOSELECT
@@ -14,7 +16,9 @@ config VIDEO_DAVINCI_VPIF_DISPLAY
 
 config VIDEO_DAVINCI_VPIF_CAPTURE
        tristate "TI DaVinci VPIF video capture driver"
-       depends on VIDEO_DEV && ARCH_DAVINCI
+       depends on VIDEO_DEV
+       depends on ARCH_DAVINCI || COMPILE_TEST
+       depends on HAS_DMA
        select VIDEOBUF2_DMA_CONTIG
        help
          Enables Davinci VPIF module used for capture devices.
@@ -26,7 +30,9 @@ config VIDEO_DAVINCI_VPIF_CAPTURE
 
 config VIDEO_DM6446_CCDC
        tristate "TI DM6446 CCDC video capture driver"
-       depends on VIDEO_V4L2 && (ARCH_DAVINCI || ARCH_OMAP3)
+       depends on VIDEO_V4L2
+       depends on ARCH_DAVINCI || COMPILE_TEST
+       depends on HAS_DMA
        select VIDEOBUF_DMA_CONTIG
        help
           Enables DaVinci CCD hw module. DaVinci CCDC hw interfaces
@@ -40,7 +46,9 @@ config VIDEO_DM6446_CCDC
 
 config VIDEO_DM355_CCDC
        tristate "TI DM355 CCDC video capture driver"
-       depends on VIDEO_V4L2 && ARCH_DAVINCI
+       depends on VIDEO_V4L2
+       depends on ARCH_DAVINCI || COMPILE_TEST
+       depends on HAS_DMA
        select VIDEOBUF_DMA_CONTIG
        help
           Enables DM355 CCD hw module. DM355 CCDC hw interfaces
@@ -55,6 +63,7 @@ config VIDEO_DM355_CCDC
 config VIDEO_DM365_ISIF
        tristate "TI DM365 ISIF video capture driver"
        depends on VIDEO_V4L2 && ARCH_DAVINCI
+       depends on HAS_DMA
        select VIDEOBUF_DMA_CONTIG
        help
           Enables ISIF hw module. This is the hardware module for
@@ -67,6 +76,7 @@ config VIDEO_DM365_ISIF
 config VIDEO_DAVINCI_VPBE_DISPLAY
        tristate "TI DaVinci VPBE V4L2-Display driver"
        depends on ARCH_DAVINCI
+       depends on HAS_DMA
        select VIDEOBUF2_DMA_CONTIG
        help
            Enables Davinci VPBE module used for display devices.
index 05f8fb7f7b70a335c89eade3925fca309a79ab5d..3f44deb5b7a76182ad7d637340f989e618ee5a30 100644 (file)
@@ -460,7 +460,7 @@ static void ccdc_config_black_compense(struct ccdc_black_compensation *bcomp)
  * ccdc_write_dfc_entry()
  * write an entry in the dfc table.
  */
-int ccdc_write_dfc_entry(int index, struct ccdc_vertical_dft *dfc)
+static int ccdc_write_dfc_entry(int index, struct ccdc_vertical_dft *dfc)
 {
 /* TODO This is to be re-visited and adjusted */
 #define DFC_WRITE_WAIT_COUNT   1000
index 07e98df3d86797710dda4b1555dedf84e461f9e2..62a0ebb01056cf867d1400132379dfe0c275ec4f 100644 (file)
@@ -130,9 +130,9 @@ static void ccdc_enable_vport(int flag)
  * This function will configure the window size
  * to be capture in CCDC reg
  */
-void ccdc_setwin(struct v4l2_rect *image_win,
-               enum ccdc_frmfmt frm_fmt,
-               int ppc)
+static void ccdc_setwin(struct v4l2_rect *image_win,
+                       enum ccdc_frmfmt frm_fmt,
+                       int ppc)
 {
        int horz_start, horz_nr_pixels;
        int vert_start, vert_nr_lines;
@@ -291,7 +291,7 @@ static int ccdc_update_raw_params(struct ccdc_config_params_raw *raw_params)
                dev_dbg(ccdc_cfg.dev, "\n copy_from_user failed");
                return -EFAULT;
        }
-       config_params->fault_pxl.fpc_table_addr = (unsigned int)fpc_physaddr;
+       config_params->fault_pxl.fpc_table_addr = (unsigned long)fpc_physaddr;
        return 0;
 }
 
@@ -370,7 +370,7 @@ static int ccdc_set_params(void __user *params)
  * ccdc_config_ycbcr()
  * This function will configure CCDC for YCbCr video capture
  */
-void ccdc_config_ycbcr(void)
+static void ccdc_config_ycbcr(void)
 {
        struct ccdc_params_ycbcr *params = &ccdc_cfg.ycbcr;
        u32 syn_mode;
@@ -506,7 +506,7 @@ static void ccdc_config_fpc(struct ccdc_fault_pixel *fpc)
 
        /* Configure Fault pixel if needed */
        regw(fpc->fpc_table_addr, CCDC_FPC_ADDR);
-       dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to FPC_ADDR...\n",
+       dev_dbg(ccdc_cfg.dev, "\nWriting 0x%lx to FPC_ADDR...\n",
                       (fpc->fpc_table_addr));
        /* Write the FPC params with FPC disable */
        val = fpc->fp_num & CCDC_FPC_FPC_NUM_MASK;
@@ -523,7 +523,7 @@ static void ccdc_config_fpc(struct ccdc_fault_pixel *fpc)
  * ccdc_config_raw()
  * This function will configure CCDC for Raw capture mode
  */
-void ccdc_config_raw(void)
+static void ccdc_config_raw(void)
 {
        struct ccdc_params_raw *params = &ccdc_cfg.bayer;
        struct ccdc_config_params_raw *config_params =
index ea7661a27479f4ef7cc7580b4e9fd11db7aceb9e..de55f47a77dba1b3bcd90196ed86392fc3fcdf11 100644 (file)
@@ -125,7 +125,7 @@ static DEFINE_MUTEX(ccdc_lock);
 /* ccdc configuration */
 static struct ccdc_config *ccdc_cfg;
 
-const struct vpfe_standard vpfe_standards[] = {
+static const struct vpfe_standard vpfe_standards[] = {
        {V4L2_STD_525_60, 720, 480, {11, 10}, 1},
        {V4L2_STD_625_50, 720, 576, {54, 59}, 1},
 };
@@ -442,11 +442,10 @@ static int vpfe_config_image_format(struct vpfe_device *vpfe_dev,
                return ret;
 
        /* Update the values of sizeimage and bytesperline */
-       if (!ret) {
-               pix->bytesperline = ccdc_dev->hw_ops.get_line_length();
-               pix->sizeimage = pix->bytesperline * pix->height;
-       }
-       return ret;
+       pix->bytesperline = ccdc_dev->hw_ops.get_line_length();
+       pix->sizeimage = pix->bytesperline * pix->height;
+
+       return 0;
 }
 
 static int vpfe_initialize_device(struct vpfe_device *vpfe_dev)
@@ -943,12 +942,11 @@ static int vpfe_g_fmt_vid_cap(struct file *file, void *priv,
                                struct v4l2_format *fmt)
 {
        struct vpfe_device *vpfe_dev = video_drvdata(file);
-       int ret = 0;
 
        v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_g_fmt_vid_cap\n");
        /* Fill in the information about format */
        *fmt = vpfe_dev->fmt;
-       return ret;
+       return 0;
 }
 
 static int vpfe_enum_fmt_vid_cap(struct file *file, void  *priv,
@@ -1914,7 +1912,7 @@ static int vpfe_probe(struct platform_device *pdev)
        v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev,
                "trying to register vpfe device.\n");
        v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev,
-               "video_dev=%x\n", (int)&vpfe_dev->video_dev);
+               "video_dev=%p\n", &vpfe_dev->video_dev);
        vpfe_dev->fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
        ret = video_register_device(vpfe_dev->video_dev,
                                    VFL_TYPE_GRABBER, -1);
index cd08e5248387038f333eee4726775b139988973b..3dad5bd7fe0a8aaad40bdf17b2ac9f6c776d9b44 100644 (file)
@@ -38,6 +38,7 @@ MODULE_LICENSE("GPL");
 #define VPIF_CH3_MAX_MODES     2
 
 spinlock_t vpif_lock;
+EXPORT_SYMBOL_GPL(vpif_lock);
 
 void __iomem *vpif_base;
 EXPORT_SYMBOL_GPL(vpif_base);
index b054b7eec53dc5a98dd43ba02dd8e343bbc19005..3ccb26ff43c8dfa31935c3f8f1eed6dee126c3c5 100644 (file)
@@ -213,8 +213,6 @@ static int vpif_start_streaming(struct vb2_queue *vq, unsigned int count)
        /* Remove buffer from the buffer queue */
        list_del(&common->cur_frm->list);
        spin_unlock_irqrestore(&common->irqlock, flags);
-       /* Mark state of the current frame to active */
-       common->cur_frm->vb.state = VB2_BUF_STATE_ACTIVE;
 
        addr = vb2_dma_contig_plane_dma_addr(&common->cur_frm->vb, 0);
 
@@ -350,7 +348,6 @@ static void vpif_schedule_next_buffer(struct common_obj *common)
        /* Remove that buffer from the buffer queue */
        list_del(&common->next_frm->list);
        spin_unlock(&common->irqlock);
-       common->next_frm->vb.state = VB2_BUF_STATE_ACTIVE;
        addr = vb2_dma_contig_plane_dma_addr(&common->next_frm->vb, 0);
 
        /* Set top and bottom field addresses in VPIF registers */
@@ -373,7 +370,6 @@ static irqreturn_t vpif_channel_isr(int irq, void *dev_id)
        struct vpif_device *dev = &vpif_obj;
        struct common_obj *common;
        struct channel_obj *ch;
-       enum v4l2_field field;
        int channel_id = 0;
        int fid = -1, i;
 
@@ -383,8 +379,6 @@ static irqreturn_t vpif_channel_isr(int irq, void *dev_id)
 
        ch = dev->dev[channel_id];
 
-       field = ch->common[VPIF_VIDEO_INDEX].fmt.fmt.pix.field;
-
        for (i = 0; i < VPIF_NUMBER_OF_OBJECTS; i++) {
                common = &ch->common[i];
                /* skip If streaming is not started in this channel */
@@ -533,7 +527,7 @@ static int vpif_update_std_info(struct channel_obj *ch)
  */
 static void vpif_calculate_offsets(struct channel_obj *ch)
 {
-       unsigned int hpitch, vpitch, sizeimage;
+       unsigned int hpitch, sizeimage;
        struct video_obj *vid_ch = &(ch->video);
        struct vpif_params *vpifparams = &ch->vpifparams;
        struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
@@ -552,7 +546,6 @@ static void vpif_calculate_offsets(struct channel_obj *ch)
        sizeimage = common->fmt.fmt.pix.sizeimage;
 
        hpitch = common->fmt.fmt.pix.bytesperline;
-       vpitch = sizeimage / (hpitch * 2);
 
        if ((V4L2_FIELD_NONE == vid_ch->buf_field) ||
            (V4L2_FIELD_INTERLACED == vid_ch->buf_field)) {
@@ -1603,7 +1596,7 @@ static int vpif_suspend(struct device *dev)
                ch = vpif_obj.dev[i];
                common = &ch->common[VPIF_VIDEO_INDEX];
 
-               if (!vb2_is_streaming(&common->buffer_queue))
+               if (!vb2_start_streaming_called(&common->buffer_queue))
                        continue;
 
                mutex_lock(&common->lock);
@@ -1637,7 +1630,7 @@ static int vpif_resume(struct device *dev)
                ch = vpif_obj.dev[i];
                common = &ch->common[VPIF_VIDEO_INDEX];
 
-               if (!vb2_is_streaming(&common->buffer_queue))
+               if (!vb2_start_streaming_called(&common->buffer_queue))
                        continue;
 
                mutex_lock(&common->lock);
index a03ec7381cfef734da18537f822e34ed959af55f..8d6ced56253c1f9fba99230fdd871f63d5cb0832 100644 (file)
@@ -196,8 +196,6 @@ static int vpif_start_streaming(struct vb2_queue *vq, unsigned int count)
 
        list_del(&common->cur_frm->list);
        spin_unlock_irqrestore(&common->irqlock, flags);
-       /* Mark state of the current frame to active */
-       common->cur_frm->vb.state = VB2_BUF_STATE_ACTIVE;
 
        addr = vb2_dma_contig_plane_dma_addr(&common->cur_frm->vb, 0);
        common->set_addr((addr + common->ytop_off),
@@ -306,8 +304,6 @@ static void process_progressive_mode(struct common_obj *common)
        /* Remove that buffer from the buffer queue */
        list_del(&common->next_frm->list);
        spin_unlock(&common->irqlock);
-       /* Mark status of the buffer as active */
-       common->next_frm->vb.state = VB2_BUF_STATE_ACTIVE;
 
        /* Set top and bottom field addrs in VPIF registers */
        addr = vb2_dma_contig_plane_dma_addr(&common->next_frm->vb, 0);
@@ -360,7 +356,6 @@ static irqreturn_t vpif_channel_isr(int irq, void *dev_id)
        struct vpif_device *dev = &vpif_obj;
        struct channel_obj *ch;
        struct common_obj *common;
-       enum v4l2_field field;
        int fid = -1, i;
        int channel_id = 0;
 
@@ -369,7 +364,6 @@ static irqreturn_t vpif_channel_isr(int irq, void *dev_id)
                return IRQ_NONE;
 
        ch = dev->dev[channel_id];
-       field = ch->common[VPIF_VIDEO_INDEX].fmt.fmt.pix.field;
        for (i = 0; i < VPIF_NUMOBJECTS; i++) {
                common = &ch->common[i];
                /* If streaming is started in this channel */
@@ -502,7 +496,7 @@ static void vpif_calculate_offsets(struct channel_obj *ch)
        struct vpif_params *vpifparams = &ch->vpifparams;
        enum v4l2_field field = common->fmt.fmt.pix.field;
        struct video_obj *vid_ch = &ch->video;
-       unsigned int hpitch, vpitch, sizeimage;
+       unsigned int hpitch, sizeimage;
 
        if (V4L2_FIELD_ANY == common->fmt.fmt.pix.field) {
                if (ch->vpifparams.std_info.frm_fmt)
@@ -516,7 +510,6 @@ static void vpif_calculate_offsets(struct channel_obj *ch)
        sizeimage = common->fmt.fmt.pix.sizeimage;
 
        hpitch = common->fmt.fmt.pix.bytesperline;
-       vpitch = sizeimage / (hpitch * 2);
        if ((V4L2_FIELD_NONE == vid_ch->buf_field) ||
            (V4L2_FIELD_INTERLACED == vid_ch->buf_field)) {
                common->ytop_off = 0;
@@ -813,17 +806,14 @@ static int vpif_set_output(struct vpif_display_config *vpif_cfg,
 {
        struct vpif_display_chan_config *chan_cfg =
                &vpif_cfg->chan_config[ch->channel_id];
-       struct vpif_subdev_info *subdev_info = NULL;
        struct v4l2_subdev *sd = NULL;
        u32 input = 0, output = 0;
        int sd_index;
        int ret;
 
        sd_index = vpif_output_to_subdev(vpif_cfg, chan_cfg, index);
-       if (sd_index >= 0) {
+       if (sd_index >= 0)
                sd = vpif_obj.sd[sd_index];
-               subdev_info = &vpif_cfg->subdevinfo[sd_index];
-       }
 
        if (sd) {
                input = chan_cfg->outputs[index].input_route;
@@ -1210,8 +1200,8 @@ static int vpif_probe_complete(void)
                INIT_LIST_HEAD(&common->dma_queue);
 
                /* register video device */
-               vpif_dbg(1, debug, "channel=%x,channel->video_dev=%x\n",
-                        (int)ch, (int)&ch->video_dev);
+               vpif_dbg(1, debug, "channel=%p,channel->video_dev=%p\n",
+                        ch, &ch->video_dev);
 
                /* Initialize the video_device structure */
                vdev = ch->video_dev;
@@ -1410,7 +1400,7 @@ static int vpif_suspend(struct device *dev)
                ch = vpif_obj.dev[i];
                common = &ch->common[VPIF_VIDEO_INDEX];
 
-               if (!vb2_is_streaming(&common->buffer_queue))
+               if (!vb2_start_streaming_called(&common->buffer_queue))
                        continue;
 
                mutex_lock(&common->lock);
@@ -1442,7 +1432,7 @@ static int vpif_resume(struct device *dev)
                ch = vpif_obj.dev[i];
                common = &ch->common[VPIF_VIDEO_INDEX];
 
-               if (!vb2_is_streaming(&common->buffer_queue))
+               if (!vb2_start_streaming_called(&common->buffer_queue))
                        continue;
 
                mutex_lock(&common->lock);
index 9d0cc04d7ab7ee1ffc2e41db4bb14436f9c15e80..b4c9f1d089684f316215803018541a47d0f4270b 100644 (file)
@@ -852,8 +852,8 @@ int gsc_prepare_addr(struct gsc_ctx *ctx, struct vb2_buffer *vb,
                (frame->fmt->pixelformat == V4L2_PIX_FMT_YVU420M))
                swap(addr->cb, addr->cr);
 
-       pr_debug("ADDR: y= 0x%X  cb= 0x%X cr= 0x%X ret= %d",
-               addr->y, addr->cb, addr->cr, ret);
+       pr_debug("ADDR: y= %pad  cb= %pad cr= %pad ret= %d",
+               &addr->y, &addr->cb, &addr->cr, ret);
 
        return ret;
 }
@@ -1086,7 +1086,7 @@ static int gsc_probe(struct platform_device *pdev)
        else
                gsc->id = pdev->id;
 
-       if (gsc->id < 0 || gsc->id >= drv_data->num_entities) {
+       if (gsc->id >= drv_data->num_entities) {
                dev_err(dev, "Invalid platform device id: %d\n", gsc->id);
                return -EINVAL;
        }
index e434f1f03d7b3a4458e0543923d9189b2992b8a3..74e1de637e8f65fdb0f8b784e8e24e63374fd43a 100644 (file)
@@ -362,7 +362,6 @@ static int gsc_m2m_reqbufs(struct file *file, void *fh,
 {
        struct gsc_ctx *ctx = fh_to_ctx(fh);
        struct gsc_dev *gsc = ctx->gsc_dev;
-       struct gsc_frame *frame;
        u32 max_cnt;
 
        max_cnt = (reqbufs->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) ?
@@ -376,8 +375,6 @@ static int gsc_m2m_reqbufs(struct file *file, void *fh,
                        gsc_ctx_state_lock_clear(GSC_DST_FMT, ctx);
        }
 
-       frame = ctx_get_frame(ctx, reqbufs->type);
-
        return v4l2_m2m_reqbufs(file, ctx->m2m_ctx, reqbufs);
 }
 
index e22d147a6940fee9969fe3ebcabf3ed6b701900c..ce12a11005115e1196244de742b41740d9040200 100644 (file)
@@ -90,8 +90,8 @@ void gsc_hw_set_output_buf_masking(struct gsc_dev *dev, u32 shift,
 void gsc_hw_set_input_addr(struct gsc_dev *dev, struct gsc_addr *addr,
                                int index)
 {
-       pr_debug("src_buf[%d]: 0x%X, cb: 0x%X, cr: 0x%X", index,
-                       addr->y, addr->cb, addr->cr);
+       pr_debug("src_buf[%d]: %pad, cb: %pad, cr: %pad", index,
+                       &addr->y, &addr->cb, &addr->cr);
        writel(addr->y, dev->regs + GSC_IN_BASE_ADDR_Y(index));
        writel(addr->cb, dev->regs + GSC_IN_BASE_ADDR_CB(index));
        writel(addr->cr, dev->regs + GSC_IN_BASE_ADDR_CR(index));
@@ -101,8 +101,8 @@ void gsc_hw_set_input_addr(struct gsc_dev *dev, struct gsc_addr *addr,
 void gsc_hw_set_output_addr(struct gsc_dev *dev,
                             struct gsc_addr *addr, int index)
 {
-       pr_debug("dst_buf[%d]: 0x%X, cb: 0x%X, cr: 0x%X",
-                       index, addr->y, addr->cb, addr->cr);
+       pr_debug("dst_buf[%d]: %pad, cb: %pad, cr: %pad",
+                       index, &addr->y, &addr->cb, &addr->cr);
        writel(addr->y, dev->regs + GSC_OUT_BASE_ADDR_Y(index));
        writel(addr->cb, dev->regs + GSC_OUT_BASE_ADDR_CB(index));
        writel(addr->cr, dev->regs + GSC_OUT_BASE_ADDR_CR(index));
index 5dcaa0a805403c5e23372ee12bf3af06e49d35b7..77c95123774409ac491d45d8db465fdb9c72360b 100644 (file)
@@ -2,7 +2,7 @@
 config VIDEO_SAMSUNG_EXYNOS4_IS
        bool "Samsung S5P/EXYNOS4 SoC series Camera Subsystem driver"
        depends on VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API
-       depends on (PLAT_S5P || ARCH_EXYNOS)
+       depends on (PLAT_S5P || ARCH_EXYNOS || COMPILE_TEST)
        depends on OF && COMMON_CLK
        help
          Say Y here to enable camera host interface devices for
@@ -16,6 +16,7 @@ config VIDEO_EXYNOS4_IS_COMMON
 config VIDEO_S5P_FIMC
        tristate "S5P/EXYNOS4 FIMC/CAMIF camera interface driver"
        depends on I2C
+       depends on HAS_DMA
        select VIDEOBUF2_DMA_CONTIG
        select V4L2_MEM2MEM_DEV
        select MFD_SYSCON
@@ -43,6 +44,7 @@ if SOC_EXYNOS4212 || SOC_EXYNOS4412 || SOC_EXYNOS5250
 config VIDEO_EXYNOS_FIMC_LITE
        tristate "EXYNOS FIMC-LITE camera interface driver"
        depends on I2C
+       depends on HAS_DMA
        select VIDEOBUF2_DMA_CONTIG
        select VIDEO_EXYNOS4_IS_COMMON
        help
@@ -55,6 +57,7 @@ endif
 
 config VIDEO_EXYNOS4_FIMC_IS
        tristate "EXYNOS4x12 FIMC-IS (Imaging Subsystem) driver"
+       depends on HAS_DMA
        select VIDEOBUF2_DMA_CONTIG
        depends on OF
        select FW_LOADER
index e8519e151c1ac0bca0391c51dafde78bbcebcd87..e050e63fe358683c61e1c0c0e00e21e5e25f41d5 100644 (file)
@@ -15,7 +15,7 @@
 
 #include "fimc-is-errno.h"
 
-const char * const fimc_is_param_strerr(unsigned int error)
+const char *fimc_is_param_strerr(unsigned int error)
 {
        switch (error) {
        case ERROR_COMMON_CMD:
@@ -146,7 +146,7 @@ const char * const fimc_is_param_strerr(unsigned int error)
        }
 }
 
-const char * const fimc_is_strerr(unsigned int error)
+const char *fimc_is_strerr(unsigned int error)
 {
        error &= ~IS_ERROR_TIME_OUT_FLAG;
 
index 3de6f6da6f87058e9c0bc8e12a6658b8764d96b7..ef981e74513a9f5f60df574e1045627915b3f0be 100644 (file)
@@ -242,7 +242,7 @@ enum fimc_is_error {
        ERROR_SCALER_FLIP                               = 521,
 };
 
-const char * const fimc_is_strerr(unsigned int error);
-const char * const fimc_is_param_strerr(unsigned int error);
+const char *fimc_is_strerr(unsigned int error);
+const char *fimc_is_param_strerr(unsigned int error);
 
 #endif /* FIMC_IS_ERR_H_ */
index bf1465d1bf6d709b266862bef57b61b257f22bfc..72b9b436c5c0a149601f9caa9d53d95e53084a74 100644 (file)
@@ -667,7 +667,6 @@ void __is_set_fd_config_orientation_val(struct fimc_is *is, u32 val)
 void fimc_is_set_initial_params(struct fimc_is *is)
 {
        struct global_param *global;
-       struct sensor_param *sensor;
        struct isp_param *isp;
        struct drc_param *drc;
        struct fd_param *fd;
@@ -676,7 +675,6 @@ void fimc_is_set_initial_params(struct fimc_is *is)
 
        index = is->config_index;
        global = &is->config[index].global;
-       sensor = &is->config[index].sensor;
        isp = &is->config[index].isp;
        drc = &is->config[index].drc;
        fd = &is->config[index].fd;
index 5476dce3ad293716fc940b130d1cf9f4aaa219c5..22162b2567dae446947dce4e7193cff9cfbb0940 100644 (file)
@@ -388,7 +388,7 @@ static void fimc_is_load_firmware(const struct firmware *fw, void *context)
        mutex_lock(&is->lock);
 
        if (fw->size < FIMC_IS_FW_SIZE_MIN || fw->size > FIMC_IS_FW_SIZE_MAX) {
-               dev_err(dev, "wrong firmware size: %d\n", fw->size);
+               dev_err(dev, "wrong firmware size: %zu\n", fw->size);
                goto done;
        }
 
@@ -416,7 +416,7 @@ static void fimc_is_load_firmware(const struct firmware *fw, void *context)
 
        dev_info(dev, "loaded firmware: %s, rev. %s\n",
                 is->fw.info, is->fw.version);
-       dev_dbg(dev, "FW size: %d, paddr: %#x\n", fw->size, is->memory.paddr);
+       dev_dbg(dev, "FW size: %zu, paddr: %pad\n", fw->size, &is->memory.paddr);
 
        is->is_shared_region->chip_id = 0xe4412;
        is->is_shared_region->chip_rev_no = 1;
@@ -693,9 +693,9 @@ int fimc_is_hw_initialize(struct fimc_is *is)
                return -EIO;
        }
 
-       pr_debug("shared region: %#x, parameter region: %#x\n",
-                is->memory.paddr + FIMC_IS_SHARED_REGION_OFFSET,
-                is->is_dma_p_region);
+       pr_debug("shared region: %pad, parameter region: %pad\n",
+                &is->memory.paddr + FIMC_IS_SHARED_REGION_OFFSET,
+                &is->is_dma_p_region);
 
        is->setfile.sub_index = 0;
 
index 93f9cf2ebcd67293d5565c9900b37f949e86c4be..76b6b4d146169824593170c08f79a89a2b18c06f 100644 (file)
@@ -219,9 +219,9 @@ static void isp_video_capture_buffer_queue(struct vb2_buffer *vb)
                                                        ivb->dma_addr[i];
 
                        isp_dbg(2, &video->ve.vdev,
-                               "dma_buf %d (%d/%d/%d) addr: %#x\n",
-                               buf_index, ivb->index, i, vb->v4l2_buf.index,
-                               ivb->dma_addr[i]);
+                               "dma_buf %pad (%d/%d/%d) addr: %pad\n",
+                               &buf_index, ivb->index, i, vb->v4l2_buf.index,
+                               &ivb->dma_addr[i]);
                }
 
                if (++video->buf_count < video->reqbufs_count)
@@ -313,7 +313,6 @@ static int isp_video_release(struct file *file)
        struct fimc_is_video *ivc = &isp->video_capture;
        struct media_entity *entity = &ivc->ve.vdev.entity;
        struct media_device *mdev = entity->parent;
-       int ret = 0;
 
        mutex_lock(&isp->video_lock);
 
@@ -335,7 +334,7 @@ static int isp_video_release(struct file *file)
        pm_runtime_put(&isp->pdev->dev);
        mutex_unlock(&isp->video_lock);
 
-       return ret;
+       return 0;
 }
 
 static const struct v4l2_file_operations isp_video_fops = {
index 344718df5c62885866d8c6ec0953163c7d99c60a..54c49d5e769021fa4036b2efe5dd02b9805ada5c 100644 (file)
@@ -1098,8 +1098,10 @@ static int fimc_md_link_notify(struct media_link *link, unsigned int flags,
        if (notification == MEDIA_DEV_NOTIFY_PRE_LINK_CH) {
                if (!(flags & MEDIA_LNK_FL_ENABLED))
                        ret = __fimc_md_modify_pipelines(sink, false);
+#if 0
                else
-                       ; /* TODO: Link state change validation */
+                       /* TODO: Link state change validation */
+#endif
        /* After link activation */
        } else if (notification == MEDIA_DEV_NOTIFY_POST_LINK_CH &&
                   (link->flags & MEDIA_LNK_FL_ENABLED)) {
index ae54ef5f535d9c105f643d76e3f78c72ee341095..db6fd14d19366b6a43f89bc363a7586783dd55f7 100644 (file)
@@ -25,6 +25,7 @@
 #include <linux/platform_device.h>
 #include <linux/pm_runtime.h>
 #include <linux/regulator/consumer.h>
+#include <linux/sizes.h>
 #include <linux/slab.h>
 #include <linux/spinlock.h>
 #include <linux/videodev2.h>
@@ -752,7 +753,7 @@ static int s5pcsis_parse_dt(struct platform_device *pdev,
        v4l2_of_parse_endpoint(node, &endpoint);
 
        state->index = endpoint.base.port - FIMC_INPUT_MIPI_CSI2_0;
-       if (state->index < 0 || state->index >= CSIS_MAX_ENTITIES)
+       if (state->index >= CSIS_MAX_ENTITIES)
                return -ENXIO;
 
        /* Get MIPI CSI-2 bus configration from the endpoint node. */
index bf739e3b33984c0ef36d262fa5b70426c74f41ce..6265d36adcebcb893ca9345765fac5337d8835e3 100644 (file)
@@ -1,6 +1,7 @@
 config VIDEO_CAFE_CCIC
        tristate "Marvell 88ALP01 (Cafe) CMOS Camera Controller support"
        depends on PCI && I2C && VIDEO_V4L2
+       depends on HAS_DMA
        select VIDEO_OV7670
        select VIDEOBUF2_VMALLOC
        select VIDEOBUF2_DMA_CONTIG
@@ -12,6 +13,7 @@ config VIDEO_CAFE_CCIC
 config VIDEO_MMP_CAMERA
        tristate "Marvell Armada 610 integrated camera controller support"
        depends on ARCH_MMP && I2C && VIDEO_V4L2
+       depends on HAS_DMA
        select VIDEO_OV7670
        select I2C_GPIO
        select VIDEOBUF2_DMA_SG
index be4b51212106e41d1420b6c27b1fb68c041782cc..7a86c77bffa08257d35713361deaadb2e91bc1d8 100644 (file)
@@ -67,7 +67,7 @@ MODULE_PARM_DESC(dma_buf_size,
                "parameters require larger buffers, an attempt to reallocate "
                "will be made.");
 #else /* MCAM_MODE_VMALLOC */
-static const bool alloc_bufs_at_read = 0;
+static const bool alloc_bufs_at_read;
 static const int n_dma_bufs = 3;  /* Used by S/G_PARM */
 #endif /* MCAM_MODE_VMALLOC */
 
index fa8f7cabe364d4d36b20009d462eab02ff95f78f..4971ff21f82b6b46a5a2c43e25a40adfd6611ab8 100644 (file)
@@ -27,7 +27,7 @@
 #include <media/v4l2-device.h>
 #include <media/v4l2-ioctl.h>
 #include <media/videobuf2-dma-contig.h>
-#include <asm/sizes.h>
+#include <linux/sizes.h>
 
 #define EMMAPRP_MODULE_NAME "mem2mem-emmaprp"
 
index 37ad446b35b309acc1f40099f9e71503785e5640..05de442d24e42ca6a2273b55271ea8425efb6a73 100644 (file)
@@ -3,7 +3,7 @@ config VIDEO_OMAP2_VOUT_VRFB
 
 config VIDEO_OMAP2_VOUT
        tristate "OMAP2/OMAP3 V4L2-Display driver"
-       depends on ARCH_OMAP2 || ARCH_OMAP3
+       depends on ARCH_OMAP2 || ARCH_OMAP3 || (COMPILE_TEST && HAS_MMU)
        select VIDEOBUF_GEN
        select VIDEOBUF_DMA_CONTIG
        select OMAP2_DSS if HAS_IOMEM && ARCH_OMAP2PLUS
index 2d177fa5847168f65d58b33b664c4e40ee3dd638..64ab6fb06b9c6ed478661a93f7fdf8424422237a 100644 (file)
@@ -369,7 +369,7 @@ static int omapvid_setup_overlay(struct omap_vout_device *vout,
 {
        int ret = 0;
        struct omap_overlay_info info;
-       int cropheight, cropwidth, pixheight, pixwidth;
+       int cropheight, cropwidth, pixwidth;
 
        if ((ovl->caps & OMAP_DSS_OVL_CAP_SCALE) == 0 &&
                        (outw != vout->pix.width || outh != vout->pix.height)) {
@@ -389,12 +389,10 @@ static int omapvid_setup_overlay(struct omap_vout_device *vout,
        if (is_rotation_90_or_270(vout)) {
                cropheight = vout->crop.width;
                cropwidth = vout->crop.height;
-               pixheight = vout->pix.width;
                pixwidth = vout->pix.height;
        } else {
                cropheight = vout->crop.height;
                cropwidth = vout->crop.width;
-               pixheight = vout->pix.height;
                pixwidth = vout->pix.width;
        }
 
@@ -991,7 +989,7 @@ static int omap_vout_release(struct file *file)
                mask = DISPC_IRQ_VSYNC | DISPC_IRQ_EVSYNC_EVEN |
                        DISPC_IRQ_EVSYNC_ODD | DISPC_IRQ_VSYNC2;
                omap_dispc_unregister_isr(omap_vout_isr, vout, mask);
-               vout->streaming = 0;
+               vout->streaming = false;
 
                videobuf_streamoff(q);
                videobuf_queue_cancel(q);
@@ -1451,12 +1449,10 @@ static int vidioc_s_ctrl(struct file *file, void *fh, struct v4l2_control *a)
        }
        case V4L2_CID_VFLIP:
        {
-               struct omap_overlay *ovl;
                struct omapvideo_info *ovid;
                unsigned int  mirror = a->value;
 
                ovid = &vout->vid_info;
-               ovl = ovid->overlays[0];
 
                mutex_lock(&vout->lock);
                if (mirror && ovid->rotation_type == VOUT_ROT_NONE) {
@@ -1489,7 +1485,7 @@ static int vidioc_reqbufs(struct file *file, void *fh,
        struct omap_vout_device *vout = fh;
        struct videobuf_queue *q = &vout->vbq;
 
-       if ((req->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) || (req->count < 0))
+       if (req->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
                return -EINVAL;
        /* if memory is not mmp or userptr
           return error */
@@ -1648,7 +1644,7 @@ static int vidioc_streamon(struct file *file, void *fh, enum v4l2_buf_type i)
        vout->field_id = 0;
 
        /* set flag here. Next QBUF will start DMA */
-       vout->streaming = 1;
+       vout->streaming = true;
 
        vout->first_int = 1;
 
@@ -1708,7 +1704,7 @@ static int vidioc_streamoff(struct file *file, void *fh, enum v4l2_buf_type i)
        if (!vout->streaming)
                return -EINVAL;
 
-       vout->streaming = 0;
+       vout->streaming = false;
        mask = DISPC_IRQ_VSYNC | DISPC_IRQ_EVSYNC_EVEN | DISPC_IRQ_EVSYNC_ODD
                | DISPC_IRQ_VSYNC2;
 
@@ -1916,7 +1912,7 @@ static int __init omap_vout_setup_video_data(struct omap_vout_device *vout)
        control[0].id = V4L2_CID_ROTATE;
        control[0].value = 0;
        vout->rotation = 0;
-       vout->mirror = 0;
+       vout->mirror = false;
        vout->control[2].id = V4L2_CID_HFLIP;
        vout->control[2].value = 0;
        if (vout->vid_info.rotation_type == VOUT_ROT_VRFB)
index 62e7e5783ce809c52f8905d482bb7aa232a3c287..aa39306afc73ac84439655314460acfa3202b43d 100644 (file)
@@ -148,7 +148,7 @@ int omap_vout_setup_vrfb_bufs(struct platform_device *pdev, int vid_num,
                        ret =  -ENOMEM;
                        goto release_vrfb_ctx;
                }
-               vout->vrfb_static_allocation = 1;
+               vout->vrfb_static_allocation = true;
        }
        return 0;
 
@@ -336,7 +336,7 @@ void omap_vout_calculate_vrfb_offset(struct omap_vout_device *vout)
                offset = vout->vrfb_context[0].yoffset *
                        vout->vrfb_context[0].bytespp;
                temp_ps = ps / vr_ps;
-               if (mirroring == 0) {
+               if (!mirroring) {
                        *cropped_offset = offset + line_length *
                                temp_ps * cleft + crop->top * temp_ps;
                } else {
@@ -350,7 +350,7 @@ void omap_vout_calculate_vrfb_offset(struct omap_vout_device *vout)
                        vout->vrfb_context[0].bytespp) +
                        (vout->vrfb_context[0].xoffset *
                        vout->vrfb_context[0].bytespp));
-               if (mirroring == 0) {
+               if (!mirroring) {
                        *cropped_offset = offset + (line_length * ps * ctop) +
                                (cleft / vr_ps) * ps;
 
@@ -364,7 +364,7 @@ void omap_vout_calculate_vrfb_offset(struct omap_vout_device *vout)
                offset = MAX_PIXELS_PER_LINE * vout->vrfb_context[0].xoffset *
                        vout->vrfb_context[0].bytespp;
                temp_ps = ps / vr_ps;
-               if (mirroring == 0) {
+               if (!mirroring) {
                        *cropped_offset = offset + line_length *
                            temp_ps * crop->left + ctop * ps;
                } else {
@@ -375,7 +375,7 @@ void omap_vout_calculate_vrfb_offset(struct omap_vout_device *vout)
                }
                break;
        case dss_rotation_0_degree:
-               if (mirroring == 0) {
+               if (!mirroring) {
                        *cropped_offset = (line_length * ps) *
                                crop->top + (crop->left / vr_ps) * ps;
                } else {
index ffde741e0590813c754dda94dc4ee0c9277484bc..4c2314839b487768a9257d61ac3e9a30a46da2c6 100644 (file)
@@ -23,18 +23,18 @@ int omap_vout_prepare_vrfb(struct omap_vout_device *vout,
                        struct videobuf_buffer *vb);
 void omap_vout_calculate_vrfb_offset(struct omap_vout_device *vout);
 #else
-void omap_vout_free_vrfb_buffers(struct omap_vout_device *vout) { }
-int omap_vout_setup_vrfb_bufs(struct platform_device *pdev, int vid_num,
+static inline void omap_vout_free_vrfb_buffers(struct omap_vout_device *vout) { };
+static inline int omap_vout_setup_vrfb_bufs(struct platform_device *pdev, int vid_num,
                        u32 static_vrfb_allocation)
-               { return 0; }
-void omap_vout_release_vrfb(struct omap_vout_device *vout) { }
-int omap_vout_vrfb_buffer_setup(struct omap_vout_device *vout,
+               { return 0; };
+static inline void omap_vout_release_vrfb(struct omap_vout_device *vout) { };
+static inline int omap_vout_vrfb_buffer_setup(struct omap_vout_device *vout,
                        unsigned int *count, unsigned int startindex)
-               { return 0; }
-int omap_vout_prepare_vrfb(struct omap_vout_device *vout,
+               { return 0; };
+static inline int omap_vout_prepare_vrfb(struct omap_vout_device *vout,
                        struct videobuf_buffer *vb)
-               { return 0; }
-void omap_vout_calculate_vrfb_offset(struct omap_vout_device *vout) { }
+               { return 0; };
+static inline void omap_vout_calculate_vrfb_offset(struct omap_vout_device *vout) { };
 #endif
 
 #endif
index c84df0706f3e098542d822e8fefc0755b010d836..e75b0eb2519b77f260e49acb84451ca99edd124c 100644 (file)
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
  * version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA
  */
 
 { 244, 0, 247,   0,  12,  27,  36, 247, 250,   0,  27,   0,   4, 250,  12, 244,
index 78deebf7d9650df80a2011c8a175db7124ce4fa5..3b507078016d1e8b9f74f7ee6cd8633a1514ac3e 100644 (file)
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA
  */
 
   0,   0,   1,   2,   3,   3,   4,   5,   6,   8,  10,  12,  14,  16,  18,  20,
index 2c7aa67205693f36287756296aaa6e8debf0bc1c..72265e58ca6090add9643759a8ad92a79e4f03bc 100644 (file)
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA
  */
 
 #include <asm/cacheflush.h>
@@ -999,16 +989,14 @@ static int isp_pipeline_disable(struct isp_pipeline *pipe)
                                         video, s_stream, 0);
                }
 
-               v4l2_subdev_call(subdev, video, s_stream, 0);
+               ret = v4l2_subdev_call(subdev, video, s_stream, 0);
 
                if (subdev == &isp->isp_res.subdev)
-                       ret = isp_pipeline_wait(isp, isp_pipeline_wait_resizer);
+                       ret |= isp_pipeline_wait(isp, isp_pipeline_wait_resizer);
                else if (subdev == &isp->isp_prev.subdev)
-                       ret = isp_pipeline_wait(isp, isp_pipeline_wait_preview);
+                       ret |= isp_pipeline_wait(isp, isp_pipeline_wait_preview);
                else if (subdev == &isp->isp_ccdc.subdev)
-                       ret = isp_pipeline_wait(isp, isp_pipeline_wait_ccdc);
-               else
-                       ret = 0;
+                       ret |= isp_pipeline_wait(isp, isp_pipeline_wait_ccdc);
 
                /* Handle stop failures. An entity that fails to stop can
                 * usually just be restarted. Flag the stop failure nonetheless
index 2c314eea125275942db5076c34ac4613d4d02537..cfdfc8714b6b8f7fb7d633a75b48b82971b0e482 100644 (file)
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA
  */
 
 #ifndef OMAP3_ISP_CORE_H
index 9f727d20f06d98298dcf36a4e0a9e8390ad2d9da..81a9dc053d5883e13844b78d99339cedc5cd7482 100644 (file)
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA
  */
 
 #include <linux/module.h>
@@ -491,14 +481,13 @@ done:
 static inline int ccdc_lsc_is_configured(struct isp_ccdc_device *ccdc)
 {
        unsigned long flags;
+       int ret;
 
        spin_lock_irqsave(&ccdc->lsc.req_lock, flags);
-       if (ccdc->lsc.active) {
-               spin_unlock_irqrestore(&ccdc->lsc.req_lock, flags);
-               return 1;
-       }
+       ret = ccdc->lsc.active != NULL;
        spin_unlock_irqrestore(&ccdc->lsc.req_lock, flags);
-       return 0;
+
+       return ret;
 }
 
 static int ccdc_lsc_enable(struct isp_ccdc_device *ccdc)
@@ -818,29 +807,48 @@ static void ccdc_config_vp(struct isp_ccdc_device *ccdc)
        struct isp_pipeline *pipe = to_isp_pipeline(&ccdc->subdev.entity);
        struct isp_device *isp = to_isp_device(ccdc);
        const struct isp_format_info *info;
+       struct v4l2_mbus_framefmt *format;
        unsigned long l3_ick = pipe->l3_ick;
        unsigned int max_div = isp->revision == ISP_REVISION_15_0 ? 64 : 8;
        unsigned int div = 0;
-       u32 fmtcfg_vp;
+       u32 fmtcfg = ISPCCDC_FMTCFG_VPEN;
+
+       format = &ccdc->formats[CCDC_PAD_SOURCE_VP];
+
+       if (!format->code) {
+               /* Disable the video port when the input format isn't supported.
+                * This is indicated by a pixel code set to 0.
+                */
+               isp_reg_writel(isp, 0, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_FMTCFG);
+               return;
+       }
+
+       isp_reg_writel(isp, (0 << ISPCCDC_FMT_HORZ_FMTSPH_SHIFT) |
+                      (format->width << ISPCCDC_FMT_HORZ_FMTLNH_SHIFT),
+                      OMAP3_ISP_IOMEM_CCDC, ISPCCDC_FMT_HORZ);
+       isp_reg_writel(isp, (0 << ISPCCDC_FMT_VERT_FMTSLV_SHIFT) |
+                      ((format->height + 1) << ISPCCDC_FMT_VERT_FMTLNV_SHIFT),
+                      OMAP3_ISP_IOMEM_CCDC, ISPCCDC_FMT_VERT);
 
-       fmtcfg_vp = isp_reg_readl(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_FMTCFG)
-                 & ~(ISPCCDC_FMTCFG_VPIN_MASK | ISPCCDC_FMTCFG_VPIF_FRQ_MASK);
+       isp_reg_writel(isp, (format->width << ISPCCDC_VP_OUT_HORZ_NUM_SHIFT) |
+                      (format->height << ISPCCDC_VP_OUT_VERT_NUM_SHIFT),
+                      OMAP3_ISP_IOMEM_CCDC, ISPCCDC_VP_OUT);
 
        info = omap3isp_video_format_info(ccdc->formats[CCDC_PAD_SINK].code);
 
        switch (info->width) {
        case 8:
        case 10:
-               fmtcfg_vp |= ISPCCDC_FMTCFG_VPIN_9_0;
+               fmtcfg |= ISPCCDC_FMTCFG_VPIN_9_0;
                break;
        case 11:
-               fmtcfg_vp |= ISPCCDC_FMTCFG_VPIN_10_1;
+               fmtcfg |= ISPCCDC_FMTCFG_VPIN_10_1;
                break;
        case 12:
-               fmtcfg_vp |= ISPCCDC_FMTCFG_VPIN_11_2;
+               fmtcfg |= ISPCCDC_FMTCFG_VPIN_11_2;
                break;
        case 13:
-               fmtcfg_vp |= ISPCCDC_FMTCFG_VPIN_12_3;
+               fmtcfg |= ISPCCDC_FMTCFG_VPIN_12_3;
                break;
        }
 
@@ -850,75 +858,59 @@ static void ccdc_config_vp(struct isp_ccdc_device *ccdc)
                div = l3_ick / pipe->external_rate;
 
        div = clamp(div, 2U, max_div);
-       fmtcfg_vp |= (div - 2) << ISPCCDC_FMTCFG_VPIF_FRQ_SHIFT;
+       fmtcfg |= (div - 2) << ISPCCDC_FMTCFG_VPIF_FRQ_SHIFT;
 
-       isp_reg_writel(isp, fmtcfg_vp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_FMTCFG);
-}
-
-/*
- * ccdc_enable_vp - Enable Video Port.
- * @ccdc: Pointer to ISP CCDC device.
- * @enable: 0 Disables VP, 1 Enables VP
- *
- * This is needed for outputting image to Preview, H3A and HIST ISP submodules.
- */
-static void ccdc_enable_vp(struct isp_ccdc_device *ccdc, u8 enable)
-{
-       struct isp_device *isp = to_isp_device(ccdc);
-
-       isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_FMTCFG,
-                       ISPCCDC_FMTCFG_VPEN, enable ? ISPCCDC_FMTCFG_VPEN : 0);
+       isp_reg_writel(isp, fmtcfg, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_FMTCFG);
 }
 
 /*
  * ccdc_config_outlineoffset - Configure memory saving output line offset
  * @ccdc: Pointer to ISP CCDC device.
- * @offset: Address offset to start a new line. Must be twice the
- *          Output width and aligned on 32 byte boundary
- * @oddeven: Specifies the odd/even line pattern to be chosen to store the
- *           output.
- * @numlines: Set the value 0-3 for +1-4lines, 4-7 for -1-4lines.
+ * @bpl: Number of bytes per line when stored in memory.
+ * @field: Field order when storing interlaced formats in memory.
+ *
+ * Configure the offsets for the line output control:
+ *
+ * - The horizontal line offset is defined as the number of bytes between the
+ *   start of two consecutive lines in memory. Set it to the given bytes per
+ *   line value.
+ *
+ * - The field offset value is defined as the number of lines to offset the
+ *   start of the field identified by FID = 1. Set it to one.
  *
- * - Configures the output line offset when stored in memory
- * - Sets the odd/even line pattern to store the output
- *    (EVENEVEN (1), ODDEVEN (2), EVENODD (3), ODDODD (4))
- * - Configures the number of even and odd line fields in case of rearranging
- * the lines.
+ * - The line offset values are defined as the number of lines (as defined by
+ *   the horizontal line offset) between the start of two consecutive lines for
+ *   all combinations of odd/even lines in odd/even fields. When interleaving
+ *   fields set them all to two lines, and to one line otherwise.
  */
 static void ccdc_config_outlineoffset(struct isp_ccdc_device *ccdc,
-                                       u32 offset, u8 oddeven, u8 numlines)
+                                     unsigned int bpl,
+                                     enum v4l2_field field)
 {
        struct isp_device *isp = to_isp_device(ccdc);
+       u32 sdofst = 0;
 
-       isp_reg_writel(isp, offset & 0xffff,
-                      OMAP3_ISP_IOMEM_CCDC, ISPCCDC_HSIZE_OFF);
+       isp_reg_writel(isp, bpl & 0xffff, OMAP3_ISP_IOMEM_CCDC,
+                      ISPCCDC_HSIZE_OFF);
 
-       isp_reg_clr(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SDOFST,
-                   ISPCCDC_SDOFST_FINV);
-
-       isp_reg_clr(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SDOFST,
-                   ISPCCDC_SDOFST_FOFST_4L);
-
-       switch (oddeven) {
-       case EVENEVEN:
-               isp_reg_set(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SDOFST,
-                           (numlines & 0x7) << ISPCCDC_SDOFST_LOFST0_SHIFT);
-               break;
-       case ODDEVEN:
-               isp_reg_set(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SDOFST,
-                           (numlines & 0x7) << ISPCCDC_SDOFST_LOFST1_SHIFT);
-               break;
-       case EVENODD:
-               isp_reg_set(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SDOFST,
-                           (numlines & 0x7) << ISPCCDC_SDOFST_LOFST2_SHIFT);
-               break;
-       case ODDODD:
-               isp_reg_set(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SDOFST,
-                           (numlines & 0x7) << ISPCCDC_SDOFST_LOFST3_SHIFT);
+       switch (field) {
+       case V4L2_FIELD_INTERLACED_TB:
+       case V4L2_FIELD_INTERLACED_BT:
+               /* When interleaving fields in memory offset field one by one
+                * line and set the line offset to two lines.
+                */
+               sdofst |= (1 << ISPCCDC_SDOFST_LOFST0_SHIFT)
+                      |  (1 << ISPCCDC_SDOFST_LOFST1_SHIFT)
+                      |  (1 << ISPCCDC_SDOFST_LOFST2_SHIFT)
+                      |  (1 << ISPCCDC_SDOFST_LOFST3_SHIFT);
                break;
+
        default:
+               /* In all other cases set the line offsets to one line. */
                break;
        }
+
+       isp_reg_writel(isp, sdofst, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SDOFST);
 }
 
 /*
@@ -981,10 +973,16 @@ static void ccdc_config_sync_if(struct isp_ccdc_device *ccdc,
 
        if (format->code == V4L2_MBUS_FMT_YUYV8_2X8 ||
            format->code == V4L2_MBUS_FMT_UYVY8_2X8) {
-               /* The bridge is enabled for YUV8 formats. Configure the input
-                * mode accordingly.
+               /* According to the OMAP3 TRM the input mode only affects SYNC
+                * mode, enabling BT.656 mode should take precedence. However,
+                * in practice setting the input mode to YCbCr data on 8 bits
+                * seems to be required in BT.656 mode. In SYNC mode set it to
+                * YCbCr on 16 bits as the bridge is enabled in that case.
                 */
-               syn_mode |= ISPCCDC_SYN_MODE_INPMOD_YCBCR16;
+               if (ccdc->bt656)
+                       syn_mode |= ISPCCDC_SYN_MODE_INPMOD_YCBCR8;
+               else
+                       syn_mode |= ISPCCDC_SYN_MODE_INPMOD_YCBCR16;
        }
 
        switch (data_size) {
@@ -1008,9 +1006,15 @@ static void ccdc_config_sync_if(struct isp_ccdc_device *ccdc,
        if (pdata && pdata->hs_pol)
                syn_mode |= ISPCCDC_SYN_MODE_HDPOL;
 
-       if (pdata && pdata->vs_pol)
+       /* The polarity of the vertical sync signal output by the BT.656
+        * decoder is not documented and seems to be active low.
+        */
+       if ((pdata && pdata->vs_pol) || ccdc->bt656)
                syn_mode |= ISPCCDC_SYN_MODE_VDPOL;
 
+       if (pdata && pdata->fld_pol)
+               syn_mode |= ISPCCDC_SYN_MODE_FLDPOL;
+
        isp_reg_writel(isp, syn_mode, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SYN_MODE);
 
        /* The CCDC_CFG.Y8POS bit is used in YCbCr8 input mode only. The
@@ -1023,8 +1027,16 @@ static void ccdc_config_sync_if(struct isp_ccdc_device *ccdc,
                isp_reg_clr(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_CFG,
                            ISPCCDC_CFG_Y8POS);
 
-       isp_reg_clr(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_REC656IF,
-                   ISPCCDC_REC656IF_R656ON);
+       /* Enable or disable BT.656 mode, including error correction for the
+        * synchronization codes.
+        */
+       if (ccdc->bt656)
+               isp_reg_set(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_REC656IF,
+                           ISPCCDC_REC656IF_R656ON | ISPCCDC_REC656IF_ECCFVH);
+       else
+               isp_reg_clr(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_REC656IF,
+                           ISPCCDC_REC656IF_R656ON | ISPCCDC_REC656IF_ECCFVH);
+
 }
 
 /* CCDC formats descriptions */
@@ -1115,17 +1127,33 @@ static void ccdc_configure(struct isp_ccdc_device *ccdc)
        unsigned long flags;
        unsigned int bridge;
        unsigned int shift;
+       unsigned int nph;
+       unsigned int sph;
        u32 syn_mode;
        u32 ccdc_pattern;
 
+       ccdc->bt656 = false;
+       ccdc->fields = 0;
+
        pad = media_entity_remote_pad(&ccdc->pads[CCDC_PAD_SINK]);
        sensor = media_entity_to_v4l2_subdev(pad->entity);
-       if (ccdc->input == CCDC_INPUT_PARALLEL)
+       if (ccdc->input == CCDC_INPUT_PARALLEL) {
+               struct v4l2_mbus_config cfg;
+               int ret;
+
+               ret = v4l2_subdev_call(sensor, video, g_mbus_config, &cfg);
+               if (!ret)
+                       ccdc->bt656 = cfg.type == V4L2_MBUS_BT656;
+
                pdata = &((struct isp_v4l2_subdevs_group *)sensor->host_priv)
                        ->bus.parallel;
+       }
+
+       /* CCDC_PAD_SINK */
+       format = &ccdc->formats[CCDC_PAD_SINK];
 
        /* Compute the lane shifter shift value and enable the bridge when the
-        * input format is YUV.
+        * input format is a non-BT.656 YUV variant.
         */
        fmt_src.pad = pad->index;
        fmt_src.which = V4L2_SUBDEV_FORMAT_ACTIVE;
@@ -1134,12 +1162,13 @@ static void ccdc_configure(struct isp_ccdc_device *ccdc)
                depth_in = fmt_info->width;
        }
 
-       fmt_info = omap3isp_video_format_info
-               (isp->isp_ccdc.formats[CCDC_PAD_SINK].code);
+       fmt_info = omap3isp_video_format_info(format->code);
        depth_out = fmt_info->width;
        shift = depth_in - depth_out;
 
-       if (fmt_info->code == V4L2_MBUS_FMT_YUYV8_2X8)
+       if (ccdc->bt656)
+               bridge = ISPCTRL_PAR_BRIDGE_DISABLE;
+       else if (fmt_info->code == V4L2_MBUS_FMT_YUYV8_2X8)
                bridge = ISPCTRL_PAR_BRIDGE_LENDIAN;
        else if (fmt_info->code == V4L2_MBUS_FMT_UYVY8_2X8)
                bridge = ISPCTRL_PAR_BRIDGE_BENDIAN;
@@ -1148,6 +1177,7 @@ static void ccdc_configure(struct isp_ccdc_device *ccdc)
 
        omap3isp_configure_bridge(isp, ccdc->input, pdata, shift, bridge);
 
+       /* Configure the sync interface. */
        ccdc_config_sync_if(ccdc, pdata, depth_out);
 
        syn_mode = isp_reg_readl(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SYN_MODE);
@@ -1167,9 +1197,6 @@ static void ccdc_configure(struct isp_ccdc_device *ccdc)
        else
                syn_mode &= ~ISPCCDC_SYN_MODE_SDR2RSZ;
 
-       /* CCDC_PAD_SINK */
-       format = &ccdc->formats[CCDC_PAD_SINK];
-
        /* Mosaic filter */
        switch (format->code) {
        case V4L2_MBUS_FMT_SRGGB10_1X10:
@@ -1202,16 +1229,40 @@ static void ccdc_configure(struct isp_ccdc_device *ccdc)
        format = &ccdc->formats[CCDC_PAD_SOURCE_OF];
        crop = &ccdc->crop;
 
-       isp_reg_writel(isp, (crop->left << ISPCCDC_HORZ_INFO_SPH_SHIFT) |
-                      ((crop->width - 1) << ISPCCDC_HORZ_INFO_NPH_SHIFT),
+       /* The horizontal coordinates are expressed in pixel clock cycles. We
+        * need two cycles per pixel in BT.656 mode, and one cycle per pixel in
+        * SYNC mode regardless of the format as the bridge is enabled for YUV
+        * formats in that case.
+        */
+       if (ccdc->bt656) {
+               sph = crop->left * 2;
+               nph = crop->width * 2 - 1;
+       } else {
+               sph = crop->left;
+               nph = crop->width - 1;
+       }
+
+       isp_reg_writel(isp, (sph << ISPCCDC_HORZ_INFO_SPH_SHIFT) |
+                      (nph << ISPCCDC_HORZ_INFO_NPH_SHIFT),
                       OMAP3_ISP_IOMEM_CCDC, ISPCCDC_HORZ_INFO);
-       isp_reg_writel(isp, crop->top << ISPCCDC_VERT_START_SLV0_SHIFT,
+       isp_reg_writel(isp, (crop->top << ISPCCDC_VERT_START_SLV0_SHIFT) |
+                      (crop->top << ISPCCDC_VERT_START_SLV1_SHIFT),
                       OMAP3_ISP_IOMEM_CCDC, ISPCCDC_VERT_START);
        isp_reg_writel(isp, (crop->height - 1)
                        << ISPCCDC_VERT_LINES_NLV_SHIFT,
                       OMAP3_ISP_IOMEM_CCDC, ISPCCDC_VERT_LINES);
 
-       ccdc_config_outlineoffset(ccdc, ccdc->video_out.bpl_value, 0, 0);
+       ccdc_config_outlineoffset(ccdc, ccdc->video_out.bpl_value,
+                                 format->field);
+
+       /* When interleaving fields enable processing of the field input signal.
+        * This will cause the line output control module to apply the field
+        * offset to field 1.
+        */
+       if (ccdc->formats[CCDC_PAD_SINK].field == V4L2_FIELD_ALTERNATE &&
+           (format->field == V4L2_FIELD_INTERLACED_TB ||
+            format->field == V4L2_FIELD_INTERLACED_BT))
+               syn_mode |= ISPCCDC_SYN_MODE_FLDMODE;
 
        /* The CCDC outputs data in UYVY order by default. Swap bytes to get
         * YUYV.
@@ -1223,8 +1274,11 @@ static void ccdc_configure(struct isp_ccdc_device *ccdc)
                isp_reg_clr(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_CFG,
                            ISPCCDC_CFG_BSWD);
 
-       /* Use PACK8 mode for 1byte per pixel formats. */
-       if (omap3isp_video_format_info(format->code)->width <= 8)
+       /* Use PACK8 mode for 1byte per pixel formats. Check for BT.656 mode
+        * explicitly as the driver reports 1X16 instead of 2X8 at the OF pad
+        * for simplicity.
+        */
+       if (omap3isp_video_format_info(format->code)->width <= 8 || ccdc->bt656)
                syn_mode |= ISPCCDC_SYN_MODE_PACK8;
        else
                syn_mode &= ~ISPCCDC_SYN_MODE_PACK8;
@@ -1232,18 +1286,7 @@ static void ccdc_configure(struct isp_ccdc_device *ccdc)
        isp_reg_writel(isp, syn_mode, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SYN_MODE);
 
        /* CCDC_PAD_SOURCE_VP */
-       format = &ccdc->formats[CCDC_PAD_SOURCE_VP];
-
-       isp_reg_writel(isp, (0 << ISPCCDC_FMT_HORZ_FMTSPH_SHIFT) |
-                      (format->width << ISPCCDC_FMT_HORZ_FMTLNH_SHIFT),
-                      OMAP3_ISP_IOMEM_CCDC, ISPCCDC_FMT_HORZ);
-       isp_reg_writel(isp, (0 << ISPCCDC_FMT_VERT_FMTSLV_SHIFT) |
-                      ((format->height + 1) << ISPCCDC_FMT_VERT_FMTLNV_SHIFT),
-                      OMAP3_ISP_IOMEM_CCDC, ISPCCDC_FMT_VERT);
-
-       isp_reg_writel(isp, (format->width << ISPCCDC_VP_OUT_HORZ_NUM_SHIFT) |
-                      (format->height << ISPCCDC_VP_OUT_VERT_NUM_SHIFT),
-                      OMAP3_ISP_IOMEM_CCDC, ISPCCDC_VP_OUT);
+       ccdc_config_vp(ccdc);
 
        /* Lens shading correction. */
        spin_lock_irqsave(&ccdc->lsc.req_lock, flags);
@@ -1277,6 +1320,8 @@ static void __ccdc_enable(struct isp_ccdc_device *ccdc, int enable)
 
        isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_PCR,
                        ISPCCDC_PCR_EN, enable ? ISPCCDC_PCR_EN : 0);
+
+       ccdc->running = enable;
 }
 
 static int ccdc_disable(struct isp_ccdc_device *ccdc)
@@ -1287,6 +1332,8 @@ static int ccdc_disable(struct isp_ccdc_device *ccdc)
        spin_lock_irqsave(&ccdc->lock, flags);
        if (ccdc->state == ISP_PIPELINE_STREAM_CONTINUOUS)
                ccdc->stopping = CCDC_STOP_REQUEST;
+       if (!ccdc->running)
+               ccdc->stopping = CCDC_STOP_FINISHED;
        spin_unlock_irqrestore(&ccdc->lock, flags);
 
        ret = wait_event_timeout(ccdc->wait,
@@ -1369,14 +1416,14 @@ static int ccdc_sbl_wait_idle(struct isp_ccdc_device *ccdc,
        return -EBUSY;
 }
 
-/* __ccdc_handle_stopping - Handle CCDC and/or LSC stopping sequence
+/* ccdc_handle_stopping - Handle CCDC and/or LSC stopping sequence
  * @ccdc: Pointer to ISP CCDC device.
  * @event: Pointing which event trigger handler
  *
  * Return 1 when the event and stopping request combination is satisfied,
  * zero otherwise.
  */
-static int __ccdc_handle_stopping(struct isp_ccdc_device *ccdc, u32 event)
+static int ccdc_handle_stopping(struct isp_ccdc_device *ccdc, u32 event)
 {
        int rval = 0;
 
@@ -1458,7 +1505,7 @@ static void ccdc_lsc_isr(struct isp_ccdc_device *ccdc, u32 events)
        if (ccdc->lsc.state == LSC_STATE_STOPPING)
                ccdc->lsc.state = LSC_STATE_STOPPED;
 
-       if (__ccdc_handle_stopping(ccdc, CCDC_EVENT_LSC_DONE))
+       if (ccdc_handle_stopping(ccdc, CCDC_EVENT_LSC_DONE))
                goto done;
 
        if (ccdc->lsc.state != LSC_STATE_RECONFIG)
@@ -1486,12 +1533,59 @@ done:
        spin_unlock_irqrestore(&ccdc->lsc.req_lock, flags);
 }
 
+/*
+ * Check whether the CCDC has captured all fields necessary to complete the
+ * buffer.
+ */
+static bool ccdc_has_all_fields(struct isp_ccdc_device *ccdc)
+{
+       struct isp_pipeline *pipe = to_isp_pipeline(&ccdc->subdev.entity);
+       struct isp_device *isp = to_isp_device(ccdc);
+       enum v4l2_field of_field = ccdc->formats[CCDC_PAD_SOURCE_OF].field;
+       enum v4l2_field field;
+
+       /* When the input is progressive fields don't matter. */
+       if (of_field == V4L2_FIELD_NONE)
+               return true;
+
+       /* Read the current field identifier. */
+       field = isp_reg_readl(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SYN_MODE)
+             & ISPCCDC_SYN_MODE_FLDSTAT
+             ? V4L2_FIELD_BOTTOM : V4L2_FIELD_TOP;
+
+       /* When capturing fields in alternate order just store the current field
+        * identifier in the pipeline.
+        */
+       if (of_field == V4L2_FIELD_ALTERNATE) {
+               pipe->field = field;
+               return true;
+       }
+
+       /* The format is interlaced. Make sure we've captured both fields. */
+       ccdc->fields |= field == V4L2_FIELD_BOTTOM
+                     ? CCDC_FIELD_BOTTOM : CCDC_FIELD_TOP;
+
+       if (ccdc->fields != CCDC_FIELD_BOTH)
+               return false;
+
+       /* Verify that the field just captured corresponds to the last field
+        * needed based on the desired field order.
+        */
+       if ((of_field == V4L2_FIELD_INTERLACED_TB && field == V4L2_FIELD_TOP) ||
+           (of_field == V4L2_FIELD_INTERLACED_BT && field == V4L2_FIELD_BOTTOM))
+               return false;
+
+       /* The buffer can be completed, reset the fields for the next buffer. */
+       ccdc->fields = 0;
+
+       return true;
+}
+
 static int ccdc_isr_buffer(struct isp_ccdc_device *ccdc)
 {
        struct isp_pipeline *pipe = to_isp_pipeline(&ccdc->subdev.entity);
        struct isp_device *isp = to_isp_device(ccdc);
        struct isp_buffer *buffer;
-       int restart = 0;
 
        /* The CCDC generates VD0 interrupts even when disabled (the datasheet
         * doesn't explicitly state if that's supposed to happen or not, so it
@@ -1500,30 +1594,31 @@ static int ccdc_isr_buffer(struct isp_ccdc_device *ccdc)
         * would thus not be enough, we need to handle the situation explicitly.
         */
        if (list_empty(&ccdc->video_out.dmaqueue))
-               goto done;
+               return 0;
 
        /* We're in continuous mode, and memory writes were disabled due to a
         * buffer underrun. Reenable them now that we have a buffer. The buffer
         * address has been set in ccdc_video_queue.
         */
        if (ccdc->state == ISP_PIPELINE_STREAM_CONTINUOUS && ccdc->underrun) {
-               restart = 1;
                ccdc->underrun = 0;
-               goto done;
+               return 1;
        }
 
+       /* Wait for the CCDC to become idle. */
        if (ccdc_sbl_wait_idle(ccdc, 1000)) {
                dev_info(isp->dev, "CCDC won't become idle!\n");
                isp->crashed |= 1U << ccdc->subdev.entity.id;
                omap3isp_pipeline_cancel_stream(pipe);
-               goto done;
+               return 0;
        }
 
+       if (!ccdc_has_all_fields(ccdc))
+               return 1;
+
        buffer = omap3isp_video_buffer_next(&ccdc->video_out);
-       if (buffer != NULL) {
+       if (buffer != NULL)
                ccdc_set_outaddr(ccdc, buffer->dma);
-               restart = 1;
-       }
 
        pipe->state |= ISP_PIPELINE_IDLE_OUTPUT;
 
@@ -1532,8 +1627,7 @@ static int ccdc_isr_buffer(struct isp_ccdc_device *ccdc)
                omap3isp_pipeline_set_stream(pipe,
                                        ISP_PIPELINE_STREAM_SINGLESHOT);
 
-done:
-       return restart;
+       return buffer != NULL;
 }
 
 /*
@@ -1547,11 +1641,38 @@ static void ccdc_vd0_isr(struct isp_ccdc_device *ccdc)
        unsigned long flags;
        int restart = 0;
 
+       /* In BT.656 mode the CCDC doesn't generate an HS/VS interrupt. We thus
+        * need to increment the frame counter here.
+        */
+       if (ccdc->bt656) {
+               struct isp_pipeline *pipe =
+                       to_isp_pipeline(&ccdc->subdev.entity);
+
+               atomic_inc(&pipe->frame_number);
+       }
+
+       /* Emulate a VD1 interrupt for BT.656 mode, as we can't stop the CCDC in
+        * the VD1 interrupt handler in that mode without risking a CCDC stall
+        * if a short frame is received.
+        */
+       if (ccdc->bt656) {
+               spin_lock_irqsave(&ccdc->lock, flags);
+               if (ccdc->state == ISP_PIPELINE_STREAM_CONTINUOUS &&
+                   ccdc->output & CCDC_OUTPUT_MEMORY) {
+                       if (ccdc->lsc.state != LSC_STATE_STOPPED)
+                               __ccdc_lsc_enable(ccdc, 0);
+                       __ccdc_enable(ccdc, 0);
+               }
+               ccdc_handle_stopping(ccdc, CCDC_EVENT_VD1);
+               spin_unlock_irqrestore(&ccdc->lock, flags);
+       }
+
        if (ccdc->output & CCDC_OUTPUT_MEMORY)
                restart = ccdc_isr_buffer(ccdc);
 
        spin_lock_irqsave(&ccdc->lock, flags);
-       if (__ccdc_handle_stopping(ccdc, CCDC_EVENT_VD0)) {
+
+       if (ccdc_handle_stopping(ccdc, CCDC_EVENT_VD0)) {
                spin_unlock_irqrestore(&ccdc->lock, flags);
                return;
        }
@@ -1572,6 +1693,18 @@ static void ccdc_vd1_isr(struct isp_ccdc_device *ccdc)
 {
        unsigned long flags;
 
+       /* In BT.656 mode the synchronization signals are generated by the CCDC
+        * from the embedded sync codes. The VD0 and VD1 interrupts are thus
+        * only triggered when the CCDC is enabled, unlike external sync mode
+        * where the line counter runs even when the CCDC is stopped. We can't
+        * disable the CCDC at VD1 time, as no VD0 interrupt would be generated
+        * for a short frame, which would result in the CCDC being stopped and
+        * no VD interrupt generated anymore. The CCDC is stopped from the VD0
+        * interrupt handler instead for BT.656.
+        */
+       if (ccdc->bt656)
+               return;
+
        spin_lock_irqsave(&ccdc->lsc.req_lock, flags);
 
        /*
@@ -1601,7 +1734,7 @@ static void ccdc_vd1_isr(struct isp_ccdc_device *ccdc)
                break;
        }
 
-       if (__ccdc_handle_stopping(ccdc, CCDC_EVENT_VD1))
+       if (ccdc_handle_stopping(ccdc, CCDC_EVENT_VD1))
                goto done;
 
        if (ccdc->lsc.request == NULL)
@@ -1656,6 +1789,8 @@ int omap3isp_ccdc_isr(struct isp_ccdc_device *ccdc, u32 events)
 static int ccdc_video_queue(struct isp_video *video, struct isp_buffer *buffer)
 {
        struct isp_ccdc_device *ccdc = &video->isp->isp_ccdc;
+       unsigned long flags;
+       bool restart = false;
 
        if (!(ccdc->output & CCDC_OUTPUT_MEMORY))
                return -ENODEV;
@@ -1664,9 +1799,20 @@ static int ccdc_video_queue(struct isp_video *video, struct isp_buffer *buffer)
 
        /* We now have a buffer queued on the output, restart the pipeline
         * on the next CCDC interrupt if running in continuous mode (or when
-        * starting the stream).
+        * starting the stream) in external sync mode, or immediately in BT.656
+        * sync mode as no CCDC interrupt is generated when the CCDC is stopped
+        * in that case.
         */
-       ccdc->underrun = 1;
+       spin_lock_irqsave(&ccdc->lock, flags);
+       if (ccdc->state == ISP_PIPELINE_STREAM_CONTINUOUS && !ccdc->running &&
+           ccdc->bt656)
+               restart = true;
+       else
+               ccdc->underrun = 1;
+       spin_unlock_irqrestore(&ccdc->lock, flags);
+
+       if (restart)
+               ccdc_enable(ccdc);
 
        return 0;
 }
@@ -1753,11 +1899,6 @@ static int ccdc_set_stream(struct v4l2_subdev *sd, int enable)
 
                ccdc_configure(ccdc);
 
-               /* TODO: Don't configure the video port if all of its output
-                * links are inactive.
-                */
-               ccdc_config_vp(ccdc);
-               ccdc_enable_vp(ccdc, 1);
                ccdc_print_status(ccdc);
        }
 
@@ -1830,6 +1971,7 @@ ccdc_try_format(struct isp_ccdc_device *ccdc, struct v4l2_subdev_fh *fh,
        unsigned int width = fmt->width;
        unsigned int height = fmt->height;
        struct v4l2_rect *crop;
+       enum v4l2_field field;
        unsigned int i;
 
        switch (pad) {
@@ -1846,14 +1988,24 @@ ccdc_try_format(struct isp_ccdc_device *ccdc, struct v4l2_subdev_fh *fh,
                /* Clamp the input size. */
                fmt->width = clamp_t(u32, width, 32, 4096);
                fmt->height = clamp_t(u32, height, 32, 4096);
+
+               /* Default to progressive field order. */
+               if (fmt->field == V4L2_FIELD_ANY)
+                       fmt->field = V4L2_FIELD_NONE;
+
                break;
 
        case CCDC_PAD_SOURCE_OF:
                pixelcode = fmt->code;
+               field = fmt->field;
                *fmt = *__ccdc_get_format(ccdc, fh, CCDC_PAD_SINK, which);
 
-               /* YUV formats are converted from 2X8 to 1X16 by the bridge and
-                * can be byte-swapped.
+               /* In SYNC mode the bridge converts YUV formats from 2X8 to
+                * 1X16. In BT.656 no such conversion occurs. As we don't know
+                * at this point whether the source will use SYNC or BT.656 mode
+                * let's pretend the conversion always occurs. The CCDC will be
+                * configured to pack bytes in BT.656, hiding the inaccuracy.
+                * In all cases bytes can be swapped.
                 */
                if (fmt->code == V4L2_MBUS_FMT_YUYV8_2X8 ||
                    fmt->code == V4L2_MBUS_FMT_UYVY8_2X8) {
@@ -1874,6 +2026,17 @@ ccdc_try_format(struct isp_ccdc_device *ccdc, struct v4l2_subdev_fh *fh,
                crop = __ccdc_get_crop(ccdc, fh, which);
                fmt->width = crop->width;
                fmt->height = crop->height;
+
+               /* When input format is interlaced with alternating fields the
+                * CCDC can interleave the fields.
+                */
+               if (fmt->field == V4L2_FIELD_ALTERNATE &&
+                   (field == V4L2_FIELD_INTERLACED_TB ||
+                    field == V4L2_FIELD_INTERLACED_BT)) {
+                       fmt->field = field;
+                       fmt->height *= 2;
+               }
+
                break;
 
        case CCDC_PAD_SOURCE_VP:
@@ -1901,7 +2064,6 @@ ccdc_try_format(struct isp_ccdc_device *ccdc, struct v4l2_subdev_fh *fh,
         * stored on 2 bytes.
         */
        fmt->colorspace = V4L2_COLORSPACE_SRGB;
-       fmt->field = V4L2_FIELD_NONE;
 }
 
 /*
index f65061602c71e585695503d30c4d9f340af1a27a..3440a709794001a68513ba9300e677808b43e401 100644 (file)
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA
  */
 
 #ifndef OMAP3_ISP_CCDC_H
@@ -103,6 +93,10 @@ struct ispccdc_lsc {
 #define CCDC_PAD_SOURCE_VP             2
 #define CCDC_PADS_NUM                  3
 
+#define CCDC_FIELD_TOP                 1
+#define CCDC_FIELD_BOTTOM              2
+#define CCDC_FIELD_BOTH                        3
+
 /*
  * struct isp_ccdc_device - Structure for the CCDC module to store its own
  *                         information
@@ -123,11 +117,14 @@ struct ispccdc_lsc {
  * @lsc: Lens shading compensation configuration
  * @update: Bitmask of controls to update during the next interrupt
  * @shadow_update: Controls update in progress by userspace
+ * @bt656: Whether the input interface uses BT.656 synchronization
+ * @fields: The fields (CCDC_FIELD_*) stored in the current buffer
  * @underrun: A buffer underrun occurred and a new buffer has been queued
  * @state: Streaming state
  * @lock: Serializes shadow_update with interrupt handler
  * @wait: Wait queue used to stop the module
  * @stopping: Stopping state
+ * @running: Is the CCDC hardware running
  * @ioctl_lock: Serializes ioctl calls and LSC requests freeing
  */
 struct isp_ccdc_device {
@@ -151,11 +148,15 @@ struct isp_ccdc_device {
        unsigned int update;
        unsigned int shadow_update;
 
+       bool bt656;
+       unsigned int fields;
+
        unsigned int underrun:1;
        enum isp_pipeline_stream_state state;
        spinlock_t lock;
        wait_queue_head_t wait;
        unsigned int stopping;
+       bool running;
        struct mutex ioctl_lock;
 };
 
index f3801db9095ca301bf53e564e9d9f4eb33a13327..9cb49b3c04bd2d596093bf6486f2b46c9cd99b3e 100644 (file)
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA
  */
 
 #include <linux/delay.h>
index 76d65f4576ef017d6ca2dad854a0697e4799e35c..4662bffa79e31a0044e09efe8f09c9042f97869d 100644 (file)
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA
  */
 
 #ifndef OMAP3_ISP_CCP2_H
index 5a2e47e58b846543f651d38acf5fba05012e2c3e..6530b255f1038cdb7f7cf46aa87a81d2ecbde586 100644 (file)
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA
  */
 #include <linux/delay.h>
 #include <media/v4l2-common.h>
index c57729b7e86e44c0ad74fe3bdb73a2645cff4fd4..453ed62fe3946c7a3dc7fb7cdc2399804fcfc7e1 100644 (file)
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA
  */
 
 #ifndef OMAP3_ISP_CSI2_H
index c09de32f986a5d797b01ab4ac5f679078e39eb85..e033f2237a72f4383236556d984b6bd773b3832d 100644 (file)
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA
  */
 
 #include <linux/delay.h>
index 14551fd7769780d3f319c6d5d146ed4742b291ac..e17c88beab92630722fdd6cc48d9a084d0bcfd8e 100644 (file)
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA
  */
 
 #ifndef OMAP3_ISP_CSI_PHY_H
index fb09fd4ca7559f744ed49a4554a00e38f2d88933..e5b28d0f3b0f49a9069a9c50855e7064bfbb564d 100644 (file)
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA
  */
 
 #ifndef OMAP3_ISP_H3A_H
index d6811ce263eb113102cceb7611a42e4c5f21f11d..b208c5417146e081facc8675f345f221e346f567 100644 (file)
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA
  */
 
 #include <linux/slab.h>
index 6fc960cd30f57accab300b749aa7049dcf5efd28..8a83e195f3e30443dc914a4d10dc12edc90f02a9 100644 (file)
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA
  */
 
 /* Linux specific include files */
index 06a5f8164eaa0a4e5aa9b3e8b64674d83a5f3042..ce822c34c843a7d9c92c020ccd9d19526ac32af1 100644 (file)
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA
  */
 
 #include <linux/delay.h>
index 0b2a38ec94c4af59bb9c30750d7574d24c4b1dc5..3b5415517dcda6992914b90d3532e80586d87bb9 100644 (file)
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA
  */
 
 #ifndef OMAP3_ISP_HIST_H
index 720809b07e75f4779f20da64aa1b0af498bad012..605f57ef0a493a82439d3055c233c68015dfaba3 100644 (file)
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA
  */
 
 #include <linux/device.h>
index f66923407f8c5a90f2a4280201cb21460ad2fab6..16fdc03a3d43bfb114d3ee64e6a5e04521cb5357 100644 (file)
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA
  */
 
 #ifndef OMAP3_ISP_PREVIEW_H
index b7d90e6fb01dc043c240a20bd27ae444dd96fc79..b5ea8da0b904cbb0498ab7001e1e1e98acb4707a 100644 (file)
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA
  */
 
 #ifndef OMAP3_ISP_REG_H
 
 #define ISPCCDC_HSIZE_OFF_SHIFT                        0
 
-#define ISPCCDC_SDOFST_FINV                    (1 << 14)
-#define ISPCCDC_SDOFST_FOFST_1L                        0
-#define ISPCCDC_SDOFST_FOFST_4L                        (3 << 12)
+#define ISPCCDC_SDOFST_FIINV                   (1 << 14)
+#define ISPCCDC_SDOFST_FOFST_SHIFT             12
+#define ISPCCDC_SDOFST_FOFST_MASK              (3 << 12)
 #define ISPCCDC_SDOFST_LOFST3_SHIFT            0
 #define ISPCCDC_SDOFST_LOFST2_SHIFT            3
 #define ISPCCDC_SDOFST_LOFST1_SHIFT            6
 #define ISPCCDC_SDOFST_LOFST0_SHIFT            9
-#define EVENEVEN                               1
-#define ODDEVEN                                        2
-#define EVENODD                                        3
-#define ODDODD                                 4
 
 #define ISPCCDC_CLAMP_OBGAIN_SHIFT             0
 #define ISPCCDC_CLAMP_OBST_SHIFT               10
index 6f077c2377db6a7b785f1f8a4b688c2996c0d2b1..05d1ace57451a67536e0d7b7821f953ef5515e7f 100644 (file)
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA
  */
 
 #include <linux/device.h>
@@ -239,7 +229,7 @@ static void resizer_set_phase(struct isp_res_device *res, u32 h_phase,
                              u32 v_phase)
 {
        struct isp_device *isp = to_isp_device(res);
-       u32 rgval = 0;
+       u32 rgval;
 
        rgval = isp_reg_readl(isp, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT) &
              ~(ISPRSZ_CNT_HSTPH_MASK | ISPRSZ_CNT_VSTPH_MASK);
@@ -275,7 +265,7 @@ static void resizer_set_luma(struct isp_res_device *res,
                             struct resizer_luma_yenh *luma)
 {
        struct isp_device *isp = to_isp_device(res);
-       u32 rgval = 0;
+       u32 rgval;
 
        rgval  = (luma->algo << ISPRSZ_YENH_ALGO_SHIFT)
                  & ISPRSZ_YENH_ALGO_MASK;
@@ -322,7 +312,7 @@ static void resizer_set_ratio(struct isp_res_device *res,
 {
        struct isp_device *isp = to_isp_device(res);
        const u16 *h_filter, *v_filter;
-       u32 rgval = 0;
+       u32 rgval;
 
        rgval = isp_reg_readl(isp, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT) &
                              ~(ISPRSZ_CNT_HRSZ_MASK | ISPRSZ_CNT_VRSZ_MASK);
@@ -365,9 +355,8 @@ static void resizer_set_output_size(struct isp_res_device *res,
                                    u32 width, u32 height)
 {
        struct isp_device *isp = to_isp_device(res);
-       u32 rgval = 0;
+       u32 rgval;
 
-       dev_dbg(isp->dev, "Output size[w/h]: %dx%d\n", width, height);
        rgval  = (width << ISPRSZ_OUT_SIZE_HORZ_SHIFT)
                 & ISPRSZ_OUT_SIZE_HORZ_MASK;
        rgval |= (height << ISPRSZ_OUT_SIZE_VERT_SHIFT)
@@ -409,7 +398,7 @@ static void resizer_set_output_offset(struct isp_res_device *res, u32 offset)
 static void resizer_set_start(struct isp_res_device *res, u32 left, u32 top)
 {
        struct isp_device *isp = to_isp_device(res);
-       u32 rgval = 0;
+       u32 rgval;
 
        rgval = (left << ISPRSZ_IN_START_HORZ_ST_SHIFT)
                & ISPRSZ_IN_START_HORZ_ST_MASK;
@@ -429,9 +418,7 @@ static void resizer_set_input_size(struct isp_res_device *res,
                                   u32 width, u32 height)
 {
        struct isp_device *isp = to_isp_device(res);
-       u32 rgval = 0;
-
-       dev_dbg(isp->dev, "Input size[w/h]: %dx%d\n", width, height);
+       u32 rgval;
 
        rgval = (width << ISPRSZ_IN_SIZE_HORZ_SHIFT)
                & ISPRSZ_IN_SIZE_HORZ_MASK;
@@ -1075,10 +1062,13 @@ static void resizer_isr_buffer(struct isp_res_device *res)
 void omap3isp_resizer_isr(struct isp_res_device *res)
 {
        struct v4l2_mbus_framefmt *informat, *outformat;
+       unsigned long flags;
 
        if (omap3isp_module_sync_is_stopping(&res->wait, &res->stopping))
                return;
 
+       spin_lock_irqsave(&res->lock, flags);
+
        if (res->applycrop) {
                outformat = __resizer_get_format(res, NULL, RESZ_PAD_SOURCE,
                                              V4L2_SUBDEV_FORMAT_ACTIVE);
@@ -1088,6 +1078,8 @@ void omap3isp_resizer_isr(struct isp_res_device *res)
                res->applycrop = 0;
        }
 
+       spin_unlock_irqrestore(&res->lock, flags);
+
        resizer_isr_buffer(res);
 }
 
@@ -1290,8 +1282,10 @@ static int resizer_set_selection(struct v4l2_subdev *sd,
 {
        struct isp_res_device *res = v4l2_get_subdevdata(sd);
        struct isp_device *isp = to_isp_device(res);
-       struct v4l2_mbus_framefmt *format_sink, *format_source;
+       const struct v4l2_mbus_framefmt *format_sink;
+       struct v4l2_mbus_framefmt format_source;
        struct resizer_ratio ratio;
+       unsigned long flags;
 
        if (sel->target != V4L2_SEL_TGT_CROP ||
            sel->pad != RESZ_PAD_SINK)
@@ -1299,16 +1293,14 @@ static int resizer_set_selection(struct v4l2_subdev *sd,
 
        format_sink = __resizer_get_format(res, fh, RESZ_PAD_SINK,
                                           sel->which);
-       format_source = __resizer_get_format(res, fh, RESZ_PAD_SOURCE,
-                                            sel->which);
-
-       dev_dbg(isp->dev, "%s: L=%d,T=%d,W=%d,H=%d,which=%d\n", __func__,
-               sel->r.left, sel->r.top, sel->r.width, sel->r.height,
-               sel->which);
+       format_source = *__resizer_get_format(res, fh, RESZ_PAD_SOURCE,
+                                             sel->which);
 
-       dev_dbg(isp->dev, "%s: input=%dx%d, output=%dx%d\n", __func__,
+       dev_dbg(isp->dev, "%s(%s): req %ux%u -> (%d,%d)/%ux%u -> %ux%u\n",
+               __func__, sel->which == V4L2_SUBDEV_FORMAT_TRY ? "try" : "act",
                format_sink->width, format_sink->height,
-               format_source->width, format_source->height);
+               sel->r.left, sel->r.top, sel->r.width, sel->r.height,
+               format_source.width, format_source.height);
 
        /* Clamp the crop rectangle to the bounds, and then mangle it further to
         * fulfill the TRM equations. Store the clamped but otherwise unmangled
@@ -1318,23 +1310,39 @@ static int resizer_set_selection(struct v4l2_subdev *sd,
         * smaller input crop rectangle every time the output size is set if we
         * stored the mangled rectangle.
         */
-       resizer_try_crop(format_sink, format_source, &sel->r);
+       resizer_try_crop(format_sink, &format_source, &sel->r);
        *__resizer_get_crop(res, fh, sel->which) = sel->r;
-       resizer_calc_ratios(res, &sel->r, format_source, &ratio);
+       resizer_calc_ratios(res, &sel->r, &format_source, &ratio);
 
-       if (sel->which == V4L2_SUBDEV_FORMAT_TRY)
+       dev_dbg(isp->dev, "%s(%s): got %ux%u -> (%d,%d)/%ux%u -> %ux%u\n",
+               __func__, sel->which == V4L2_SUBDEV_FORMAT_TRY ? "try" : "act",
+               format_sink->width, format_sink->height,
+               sel->r.left, sel->r.top, sel->r.width, sel->r.height,
+               format_source.width, format_source.height);
+
+       if (sel->which == V4L2_SUBDEV_FORMAT_TRY) {
+               *__resizer_get_format(res, fh, RESZ_PAD_SOURCE, sel->which) =
+                       format_source;
                return 0;
+       }
+
+       /* Update the source format, resizing ratios and crop rectangle. If
+        * streaming is on the IRQ handler will reprogram the resizer after the
+        * current frame. We thus we need to protect against race conditions.
+        */
+       spin_lock_irqsave(&res->lock, flags);
+
+       *__resizer_get_format(res, fh, RESZ_PAD_SOURCE, sel->which) =
+               format_source;
 
        res->ratio = ratio;
        res->crop.active = sel->r;
 
-       /*
-        * set_selection can be called while streaming is on. In this case the
-        * crop values will be set in the next IRQ.
-        */
        if (res->state != ISP_PIPELINE_STREAM_STOPPED)
                res->applycrop = 1;
 
+       spin_unlock_irqrestore(&res->lock, flags);
+
        return 0;
 }
 
@@ -1781,6 +1789,8 @@ int omap3isp_resizer_init(struct isp_device *isp)
 
        init_waitqueue_head(&res->wait);
        atomic_set(&res->stopping, 0);
+       spin_lock_init(&res->lock);
+
        return resizer_init_entities(res);
 }
 
index 9b01e9047c15d8ce98d177760ff82a3f588c3071..5414542912e2723b39f0ec034293af10ab7c279c 100644 (file)
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA
  */
 
 #ifndef OMAP3_ISP_RESIZER_H
 #define OMAP3_ISP_RESIZER_H
 
+#include <linux/spinlock.h>
 #include <linux/types.h>
 
 /*
@@ -96,6 +87,7 @@ enum resizer_input_entity {
 
 /*
  * struct isp_res_device - OMAP3 ISP resizer module
+ * @lock: Protects formats and crop rectangles between set_selection and IRQ
  * @crop.request: Crop rectangle requested by the user
  * @crop.active: Active crop rectangle (based on hardware requirements)
  */
@@ -116,6 +108,7 @@ struct isp_res_device {
        enum isp_pipeline_stream_state state;
        wait_queue_head_t wait;
        atomic_t stopping;
+       spinlock_t lock;
 
        struct {
                struct v4l2_rect request;
index e6cbc1eaf4cab03fa5c29ab1ffba1de8d7bb6cec..a94e8340508f703efea86f51232578e30912f496 100644 (file)
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA
  */
 
 #include <linux/dma-mapping.h>
index 58d6ac7cb6648ce18f2e8284cc85fe9d96199242..b32b29677e2c48f3fc3bd4dbe9d9208452ee1cf5 100644 (file)
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA
  */
 
 #ifndef OMAP3_ISP_STAT_H
index e36bac26476c0fd7ac382f5e85effc07a7a0b202..bc38c88c7bd9cc179de2afd0b120aa00dc139833 100644 (file)
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA
  */
 
 #include <asm/cacheflush.h>
@@ -319,10 +309,11 @@ isp_video_check_format(struct isp_video *video, struct isp_video_fh *vfh)
            vfh->format.fmt.pix.height != format.fmt.pix.height ||
            vfh->format.fmt.pix.width != format.fmt.pix.width ||
            vfh->format.fmt.pix.bytesperline != format.fmt.pix.bytesperline ||
-           vfh->format.fmt.pix.sizeimage != format.fmt.pix.sizeimage)
+           vfh->format.fmt.pix.sizeimage != format.fmt.pix.sizeimage ||
+           vfh->format.fmt.pix.field != format.fmt.pix.field)
                return -EINVAL;
 
-       return ret;
+       return 0;
 }
 
 /* -----------------------------------------------------------------------------
@@ -491,6 +482,11 @@ struct isp_buffer *omap3isp_video_buffer_next(struct isp_video *video)
        else
                buf->vb.v4l2_buf.sequence = atomic_read(&pipe->frame_number);
 
+       if (pipe->field != V4L2_FIELD_NONE)
+               buf->vb.v4l2_buf.sequence /= 2;
+
+       buf->vb.v4l2_buf.field = pipe->field;
+
        /* Report pipeline errors to userspace on the capture device side. */
        if (video->type == V4L2_BUF_TYPE_VIDEO_CAPTURE && pipe->error) {
                state = VB2_BUF_STATE_ERROR;
@@ -641,7 +637,40 @@ isp_video_set_format(struct file *file, void *fh, struct v4l2_format *format)
        if (format->type != video->type)
                return -EINVAL;
 
-       mutex_lock(&video->mutex);
+       /* Replace unsupported field orders with sane defaults. */
+       switch (format->fmt.pix.field) {
+       case V4L2_FIELD_NONE:
+               /* Progressive is supported everywhere. */
+               break;
+       case V4L2_FIELD_ALTERNATE:
+               /* ALTERNATE is not supported on output nodes. */
+               if (video->type == V4L2_BUF_TYPE_VIDEO_OUTPUT)
+                       format->fmt.pix.field = V4L2_FIELD_NONE;
+               break;
+       case V4L2_FIELD_INTERLACED:
+               /* The ISP has no concept of video standard, select the
+                * top-bottom order when the unqualified interlaced order is
+                * requested.
+                */
+               format->fmt.pix.field = V4L2_FIELD_INTERLACED_TB;
+               /* Fall-through */
+       case V4L2_FIELD_INTERLACED_TB:
+       case V4L2_FIELD_INTERLACED_BT:
+               /* Interlaced orders are only supported at the CCDC output. */
+               if (video != &video->isp->isp_ccdc.video_out)
+                       format->fmt.pix.field = V4L2_FIELD_NONE;
+               break;
+       case V4L2_FIELD_TOP:
+       case V4L2_FIELD_BOTTOM:
+       case V4L2_FIELD_SEQ_TB:
+       case V4L2_FIELD_SEQ_BT:
+       default:
+               /* All other field orders are currently unsupported, default to
+                * progressive.
+                */
+               format->fmt.pix.field = V4L2_FIELD_NONE;
+               break;
+       }
 
        /* Fill the bytesperline and sizeimage fields by converting to media bus
         * format and back to pixel format.
@@ -649,9 +678,10 @@ isp_video_set_format(struct file *file, void *fh, struct v4l2_format *format)
        isp_video_pix_to_mbus(&format->fmt.pix, &fmt);
        isp_video_mbus_to_pix(video, &fmt, &format->fmt.pix);
 
+       mutex_lock(&video->mutex);
        vfh->format = *format;
-
        mutex_unlock(&video->mutex);
+
        return 0;
 }
 
@@ -1039,6 +1069,7 @@ isp_video_streamon(struct file *file, void *fh, enum v4l2_buf_type type)
        video->queue = &vfh->queue;
        INIT_LIST_HEAD(&video->dmaqueue);
        atomic_set(&pipe->frame_number, -1);
+       pipe->field = vfh->format.fmt.pix.field;
 
        mutex_lock(&video->queue_lock);
        ret = vb2_streamon(&vfh->queue, type);
index 7d2e82122ecda431d417ae10ba8193b9fb9154ec..0b7efedc3da990945bddc7e32389b55693df1ab3 100644 (file)
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA
  */
 
 #ifndef OMAP3_ISP_VIDEO_H
@@ -88,6 +78,7 @@ enum isp_pipeline_state {
 
 /*
  * struct isp_pipeline - An ISP hardware pipeline
+ * @field: The field being processed by the pipeline
  * @error: A hardware error occurred during capture
  * @entities: Bitmask of entities in the pipeline (indexed by entity ID)
  */
@@ -101,6 +92,7 @@ struct isp_pipeline {
        u32 entities;
        unsigned long l3_ick;
        unsigned int max_rate;
+       enum v4l2_field field;
        atomic_t frame_number;
        bool do_propagation; /* of frame number */
        bool error;
index 098b45e2280f064fc3a304555e3925c1b61ee841..81c5b1566469f16587c319907bf30d6d860243f7 100644 (file)
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA
  */
 
 1047552, 1047552, 1047552, 1047552, 1047552, 1047552, 1047552, 1047552,
index d50451a4a2424616915e6c40b18ecb0b8f2454f2..5073f98479379cf3dde0c8ddb47fac14c49ac6fb 100644 (file)
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA
  */
 
 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
index f33641384e15adf817542a689bb5df57082fe812..4f81b4c9d113f1a61aa8d10751d2f898dd70228d 100644 (file)
@@ -280,8 +280,8 @@ static int camif_prepare_addr(struct camif_vp *vp, struct vb2_buffer *vb,
                return -EINVAL;
        }
 
-       pr_debug("DMA address: y: %#x  cb: %#x cr: %#x\n",
-                paddr->y, paddr->cb, paddr->cr);
+       pr_debug("DMA address: y: %pad  cb: %pad cr: %pad\n",
+                &paddr->y, &paddr->cb, &paddr->cr);
 
        return 0;
 }
index ebf5b184cce427a1b4274328f7683bd5408af03a..6e0c9988a1919df0ea9b89fb0349f77d7db66e55 100644 (file)
@@ -214,8 +214,8 @@ void camif_hw_set_output_addr(struct camif_vp *vp,
                                                                paddr->cr);
        }
 
-       pr_debug("dst_buf[%d]: %#X, cb: %#X, cr: %#X\n",
-                i, paddr->y, paddr->cb, paddr->cr);
+       pr_debug("dst_buf[%d]: %pad, cb: %pad, cr: %pad\n",
+                i, &paddr->y, &paddr->cb, &paddr->cr);
 }
 
 static void camif_hw_set_out_dma_size(struct camif_vp *vp)
index 357af1ebaeda2791667e8f5c32b12fe7f45bf18a..d79e214ce8ce3e7526027aea3141c16f9a609a39 100644 (file)
@@ -490,14 +490,13 @@ static void job_abort(void *prv)
 {
        struct g2d_ctx *ctx = prv;
        struct g2d_dev *dev = ctx->dev;
-       int ret;
 
        if (dev->curr == NULL) /* No job currently running */
                return;
 
-       ret = wait_event_timeout(dev->irq_queue,
-               dev->curr == NULL,
-               msecs_to_jiffies(G2D_TIMEOUT));
+       wait_event_timeout(dev->irq_queue,
+                          dev->curr == NULL,
+                          msecs_to_jiffies(G2D_TIMEOUT));
 }
 
 static void device_run(void *prv)
index e66acbc2a82d7dcca7dbe106de82b19a68633a51..e525a7c8d885770c7f0e85e3219a387f432a13c2 100644 (file)
@@ -729,7 +729,7 @@ static inline void exynos4_jpeg_set_qtbl_chr(void __iomem *regs, int quality)
                             ARRAY_SIZE(qtbl_chrominance[quality]));
 }
 
-void exynos4_jpeg_set_huff_tbl(void __iomem *base)
+static void exynos4_jpeg_set_huff_tbl(void __iomem *base)
 {
        exynos4_jpeg_set_tbl(base, hdctbl0, EXYNOS4_HUFF_TBL_HDCLL,
                                                        ARRAY_SIZE(hdctbl0));
index d26e1f8465536614201a2a3a66035f3061f95d93..e8c2cad9396272ed9fa6f43c0fbab2699ba0073e 100644 (file)
@@ -233,6 +233,7 @@ void exynos3250_jpeg_set_x(void __iomem *regs, unsigned int x)
        writel(reg, regs + EXYNOS3250_JPGX);
 }
 
+#if 0  /* Currently unused */
 unsigned int exynos3250_jpeg_get_y(void __iomem *regs)
 {
        return readl(regs + EXYNOS3250_JPGY);
@@ -242,6 +243,7 @@ unsigned int exynos3250_jpeg_get_x(void __iomem *regs)
 {
        return readl(regs + EXYNOS3250_JPGX);
 }
+#endif
 
 void exynos3250_jpeg_interrupts_enable(void __iomem *regs)
 {
index da8d6a1a984f84be834c49e0fe21c0a5710ebd89..ab6d6f43c96f1a81361a98b7acc6faa160e368d1 100644 (file)
@@ -23,7 +23,7 @@ void exynos4_jpeg_sw_reset(void __iomem *base)
        reg = readl(base + EXYNOS4_JPEG_CNTL_REG);
        writel(reg & ~EXYNOS4_SOFT_RESET_HI, base + EXYNOS4_JPEG_CNTL_REG);
 
-       ndelay(100000);
+       udelay(100);
 
        writel(reg | EXYNOS4_SOFT_RESET_HI, base + EXYNOS4_JPEG_CNTL_REG);
 }
@@ -151,9 +151,6 @@ void exynos4_jpeg_set_enc_out_fmt(void __iomem *base, unsigned int out_fmt)
 
 void exynos4_jpeg_set_interrupt(void __iomem *base)
 {
-       unsigned int reg;
-
-       reg = readl(base + EXYNOS4_INT_EN_REG) & ~EXYNOS4_INT_EN_MASK;
        writel(EXYNOS4_INT_EN_ALL, base + EXYNOS4_INT_EN_REG);
 }
 
@@ -185,7 +182,7 @@ void exynos4_jpeg_set_huf_table_enable(void __iomem *base, int value)
                writel(reg | EXYNOS4_HUF_TBL_EN,
                                        base + EXYNOS4_JPEG_CNTL_REG);
        else
-               writel(reg | ~EXYNOS4_HUF_TBL_EN,
+               writel(reg & ~EXYNOS4_HUF_TBL_EN,
                                        base + EXYNOS4_JPEG_CNTL_REG);
 }
 
@@ -196,9 +193,9 @@ void exynos4_jpeg_set_sys_int_enable(void __iomem *base, int value)
        reg = readl(base + EXYNOS4_JPEG_CNTL_REG) & ~(EXYNOS4_SYS_INT_EN);
 
        if (value == 1)
-               writel(EXYNOS4_SYS_INT_EN, base + EXYNOS4_JPEG_CNTL_REG);
+               writel(reg | EXYNOS4_SYS_INT_EN, base + EXYNOS4_JPEG_CNTL_REG);
        else
-               writel(~EXYNOS4_SYS_INT_EN, base + EXYNOS4_JPEG_CNTL_REG);
+               writel(reg & ~EXYNOS4_SYS_INT_EN, base + EXYNOS4_JPEG_CNTL_REG);
 }
 
 void exynos4_jpeg_set_stream_buf_address(void __iomem *base,
index 52407d7907267e520b81bcc540420f1f2ff34544..e3b8e67e005f12fa21a37045844fce373aef134d 100644 (file)
@@ -324,11 +324,9 @@ int s5p_jpeg_stream_stat_ok(void __iomem *regs)
 
 void s5p_jpeg_clear_int(void __iomem *regs)
 {
-       unsigned long reg;
-
-       reg = readl(regs + S5P_JPGINTST);
+       readl(regs + S5P_JPGINTST);
        writel(S5P_INT_RELEASE, regs + S5P_JPGCOM);
-       reg = readl(regs + S5P_JPGOPR);
+       readl(regs + S5P_JPGOPR);
 }
 
 unsigned int s5p_jpeg_compressed_size(void __iomem *regs)
index d35b0418ab371ec132760182a3f35fe71662e279..165bc86c596267f701cf6997422f953ec412227a 100644 (file)
@@ -37,8 +37,8 @@
 #define S5P_MFC_DEC_NAME       "s5p-mfc-dec"
 #define S5P_MFC_ENC_NAME       "s5p-mfc-enc"
 
-int debug;
-module_param(debug, int, S_IRUGO | S_IWUSR);
+int mfc_debug_level;
+module_param_named(debug, mfc_debug_level, int, S_IRUGO | S_IWUSR);
 MODULE_PARM_DESC(debug, "Debug level - higher value produces more verbose messages");
 
 /* Helper functions for interrupt processing */
@@ -150,10 +150,10 @@ static void s5p_mfc_watchdog_worker(struct work_struct *work)
                if (!ctx)
                        continue;
                ctx->state = MFCINST_ERROR;
-               s5p_mfc_hw_call(dev->mfc_ops, cleanup_queue, &ctx->dst_queue,
-                               &ctx->vq_dst);
-               s5p_mfc_hw_call(dev->mfc_ops, cleanup_queue, &ctx->src_queue,
-                               &ctx->vq_src);
+               s5p_mfc_hw_call_void(dev->mfc_ops, cleanup_queue,
+                                               &ctx->dst_queue, &ctx->vq_dst);
+               s5p_mfc_hw_call_void(dev->mfc_ops, cleanup_queue,
+                                               &ctx->src_queue, &ctx->vq_src);
                clear_work_bit(ctx);
                wake_up_ctx(ctx, S5P_MFC_R2H_CMD_ERR_RET, 0);
        }
@@ -264,7 +264,12 @@ static void s5p_mfc_handle_frame_new(struct s5p_mfc_ctx *ctx, unsigned int err)
        unsigned int frame_type;
 
        dspl_y_addr = s5p_mfc_hw_call(dev->mfc_ops, get_dspl_y_adr, dev);
-       frame_type = s5p_mfc_hw_call(dev->mfc_ops, get_disp_frame_type, ctx);
+       if (IS_MFCV6_PLUS(dev))
+               frame_type = s5p_mfc_hw_call(dev->mfc_ops,
+                       get_disp_frame_type, ctx);
+       else
+               frame_type = s5p_mfc_hw_call(dev->mfc_ops,
+                       get_dec_frame_type, dev);
 
        /* If frame is same as previous then skip and do not dequeue */
        if (frame_type == S5P_FIMV_DECODE_FRAME_SKIPPED) {
@@ -327,12 +332,12 @@ static void s5p_mfc_handle_frame(struct s5p_mfc_ctx *ctx,
        if (res_change == S5P_FIMV_RES_INCREASE ||
                res_change == S5P_FIMV_RES_DECREASE) {
                ctx->state = MFCINST_RES_CHANGE_INIT;
-               s5p_mfc_hw_call(dev->mfc_ops, clear_int_flags, dev);
+               s5p_mfc_hw_call_void(dev->mfc_ops, clear_int_flags, dev);
                wake_up_ctx(ctx, reason, err);
                if (test_and_clear_bit(0, &dev->hw_lock) == 0)
                        BUG();
                s5p_mfc_clock_off();
-               s5p_mfc_hw_call(dev->mfc_ops, try_run, dev);
+               s5p_mfc_hw_call_void(dev->mfc_ops, try_run, dev);
                return;
        }
        if (ctx->dpb_flush_flag)
@@ -400,7 +405,7 @@ leave_handle_frame:
        if ((ctx->src_queue_cnt == 0 && ctx->state != MFCINST_FINISHING)
                                    || ctx->dst_queue_cnt < ctx->pb_count)
                clear_work_bit(ctx);
-       s5p_mfc_hw_call(dev->mfc_ops, clear_int_flags, dev);
+       s5p_mfc_hw_call_void(dev->mfc_ops, clear_int_flags, dev);
        wake_up_ctx(ctx, reason, err);
        if (test_and_clear_bit(0, &dev->hw_lock) == 0)
                BUG();
@@ -409,7 +414,7 @@ leave_handle_frame:
        if (test_bit(0, &dev->enter_suspend))
                wake_up_dev(dev, reason, err);
        else
-               s5p_mfc_hw_call(dev->mfc_ops, try_run, dev);
+               s5p_mfc_hw_call_void(dev->mfc_ops, try_run, dev);
 }
 
 /* Error handling for interrupt */
@@ -435,10 +440,10 @@ static void s5p_mfc_handle_error(struct s5p_mfc_dev *dev,
                        ctx->state = MFCINST_ERROR;
                        /* Mark all dst buffers as having an error */
                        spin_lock_irqsave(&dev->irqlock, flags);
-                       s5p_mfc_hw_call(dev->mfc_ops, cleanup_queue,
+                       s5p_mfc_hw_call_void(dev->mfc_ops, cleanup_queue,
                                                &ctx->dst_queue, &ctx->vq_dst);
                        /* Mark all src buffers as having an error */
-                       s5p_mfc_hw_call(dev->mfc_ops, cleanup_queue,
+                       s5p_mfc_hw_call_void(dev->mfc_ops, cleanup_queue,
                                                &ctx->src_queue, &ctx->vq_src);
                        spin_unlock_irqrestore(&dev->irqlock, flags);
                        wake_up_ctx(ctx, reason, err);
@@ -452,7 +457,7 @@ static void s5p_mfc_handle_error(struct s5p_mfc_dev *dev,
        }
        if (test_and_clear_bit(0, &dev->hw_lock) == 0)
                BUG();
-       s5p_mfc_hw_call(dev->mfc_ops, clear_int_flags, dev);
+       s5p_mfc_hw_call_void(dev->mfc_ops, clear_int_flags, dev);
        s5p_mfc_clock_off();
        wake_up_dev(dev, reason, err);
        return;
@@ -476,7 +481,7 @@ static void s5p_mfc_handle_seq_done(struct s5p_mfc_ctx *ctx,
                ctx->img_height = s5p_mfc_hw_call(dev->mfc_ops, get_img_height,
                                dev);
 
-               s5p_mfc_hw_call(dev->mfc_ops, dec_calc_dpb_size, ctx);
+               s5p_mfc_hw_call_void(dev->mfc_ops, dec_calc_dpb_size, ctx);
 
                ctx->pb_count = s5p_mfc_hw_call(dev->mfc_ops, get_dpb_count,
                                dev);
@@ -503,12 +508,12 @@ static void s5p_mfc_handle_seq_done(struct s5p_mfc_ctx *ctx,
                        ctx->head_processed = 1;
                }
        }
-       s5p_mfc_hw_call(dev->mfc_ops, clear_int_flags, dev);
+       s5p_mfc_hw_call_void(dev->mfc_ops, clear_int_flags, dev);
        clear_work_bit(ctx);
        if (test_and_clear_bit(0, &dev->hw_lock) == 0)
                BUG();
        s5p_mfc_clock_off();
-       s5p_mfc_hw_call(dev->mfc_ops, try_run, dev);
+       s5p_mfc_hw_call_void(dev->mfc_ops, try_run, dev);
        wake_up_ctx(ctx, reason, err);
 }
 
@@ -523,7 +528,7 @@ static void s5p_mfc_handle_init_buffers(struct s5p_mfc_ctx *ctx,
        if (ctx == NULL)
                return;
        dev = ctx->dev;
-       s5p_mfc_hw_call(dev->mfc_ops, clear_int_flags, dev);
+       s5p_mfc_hw_call_void(dev->mfc_ops, clear_int_flags, dev);
        ctx->int_type = reason;
        ctx->int_err = err;
        ctx->int_cond = 1;
@@ -550,7 +555,7 @@ static void s5p_mfc_handle_init_buffers(struct s5p_mfc_ctx *ctx,
                s5p_mfc_clock_off();
 
                wake_up(&ctx->queue);
-               s5p_mfc_hw_call(dev->mfc_ops, try_run, dev);
+               s5p_mfc_hw_call_void(dev->mfc_ops, try_run, dev);
        } else {
                if (test_and_clear_bit(0, &dev->hw_lock) == 0)
                        BUG();
@@ -591,7 +596,7 @@ static void s5p_mfc_handle_stream_complete(struct s5p_mfc_ctx *ctx,
 
        s5p_mfc_clock_off();
        wake_up(&ctx->queue);
-       s5p_mfc_hw_call(dev->mfc_ops, try_run, dev);
+       s5p_mfc_hw_call_void(dev->mfc_ops, try_run, dev);
 }
 
 /* Interrupt processing */
@@ -628,12 +633,12 @@ static irqreturn_t s5p_mfc_irq(int irq, void *priv)
                if (ctx->c_ops->post_frame_start) {
                        if (ctx->c_ops->post_frame_start(ctx))
                                mfc_err("post_frame_start() failed\n");
-                       s5p_mfc_hw_call(dev->mfc_ops, clear_int_flags, dev);
+                       s5p_mfc_hw_call_void(dev->mfc_ops, clear_int_flags, dev);
                        wake_up_ctx(ctx, reason, err);
                        if (test_and_clear_bit(0, &dev->hw_lock) == 0)
                                BUG();
                        s5p_mfc_clock_off();
-                       s5p_mfc_hw_call(dev->mfc_ops, try_run, dev);
+                       s5p_mfc_hw_call_void(dev->mfc_ops, try_run, dev);
                } else {
                        s5p_mfc_handle_frame(ctx, reason, err);
                }
@@ -663,7 +668,7 @@ static irqreturn_t s5p_mfc_irq(int irq, void *priv)
        case S5P_MFC_R2H_CMD_WAKEUP_RET:
                if (ctx)
                        clear_work_bit(ctx);
-               s5p_mfc_hw_call(dev->mfc_ops, clear_int_flags, dev);
+               s5p_mfc_hw_call_void(dev->mfc_ops, clear_int_flags, dev);
                wake_up_dev(dev, reason, err);
                clear_bit(0, &dev->hw_lock);
                clear_bit(0, &dev->enter_suspend);
@@ -685,12 +690,12 @@ static irqreturn_t s5p_mfc_irq(int irq, void *priv)
 
        default:
                mfc_debug(2, "Unknown int reason\n");
-               s5p_mfc_hw_call(dev->mfc_ops, clear_int_flags, dev);
+               s5p_mfc_hw_call_void(dev->mfc_ops, clear_int_flags, dev);
        }
        mfc_debug_leave();
        return IRQ_HANDLED;
 irq_cleanup_hw:
-       s5p_mfc_hw_call(dev->mfc_ops, clear_int_flags, dev);
+       s5p_mfc_hw_call_void(dev->mfc_ops, clear_int_flags, dev);
        ctx->int_type = reason;
        ctx->int_err = err;
        ctx->int_cond = 1;
@@ -699,7 +704,7 @@ irq_cleanup_hw:
 
        s5p_mfc_clock_off();
 
-       s5p_mfc_hw_call(dev->mfc_ops, try_run, dev);
+       s5p_mfc_hw_call_void(dev->mfc_ops, try_run, dev);
        mfc_debug(2, "Exit via irq_cleanup_hw\n");
        return IRQ_HANDLED;
 }
@@ -1311,11 +1316,9 @@ static int s5p_mfc_runtime_resume(struct device *dev)
 {
        struct platform_device *pdev = to_platform_device(dev);
        struct s5p_mfc_dev *m_dev = platform_get_drvdata(pdev);
-       int pre_power;
 
        if (!m_dev->alloc_ctx)
                return 0;
-       pre_power = atomic_read(&m_dev->pm.power);
        atomic_set(&m_dev->pm.power, 1);
        return 0;
 }
@@ -1328,20 +1331,20 @@ static const struct dev_pm_ops s5p_mfc_pm_ops = {
                           NULL)
 };
 
-struct s5p_mfc_buf_size_v5 mfc_buf_size_v5 = {
+static struct s5p_mfc_buf_size_v5 mfc_buf_size_v5 = {
        .h264_ctx       = MFC_H264_CTX_BUF_SIZE,
        .non_h264_ctx   = MFC_CTX_BUF_SIZE,
        .dsc            = DESC_BUF_SIZE,
        .shm            = SHARED_BUF_SIZE,
 };
 
-struct s5p_mfc_buf_size buf_size_v5 = {
+static struct s5p_mfc_buf_size buf_size_v5 = {
        .fw     = MAX_FW_SIZE,
        .cpb    = MAX_CPB_SIZE,
        .priv   = &mfc_buf_size_v5,
 };
 
-struct s5p_mfc_buf_align mfc_buf_align_v5 = {
+static struct s5p_mfc_buf_align mfc_buf_align_v5 = {
        .base = MFC_BASE_ALIGN_ORDER,
 };
 
@@ -1354,7 +1357,7 @@ static struct s5p_mfc_variant mfc_drvdata_v5 = {
        .fw_name[0]     = "s5p-mfc.fw",
 };
 
-struct s5p_mfc_buf_size_v6 mfc_buf_size_v6 = {
+static struct s5p_mfc_buf_size_v6 mfc_buf_size_v6 = {
        .dev_ctx        = MFC_CTX_BUF_SIZE_V6,
        .h264_dec_ctx   = MFC_H264_DEC_CTX_BUF_SIZE_V6,
        .other_dec_ctx  = MFC_OTHER_DEC_CTX_BUF_SIZE_V6,
@@ -1362,13 +1365,13 @@ struct s5p_mfc_buf_size_v6 mfc_buf_size_v6 = {
        .other_enc_ctx  = MFC_OTHER_ENC_CTX_BUF_SIZE_V6,
 };
 
-struct s5p_mfc_buf_size buf_size_v6 = {
+static struct s5p_mfc_buf_size buf_size_v6 = {
        .fw     = MAX_FW_SIZE_V6,
        .cpb    = MAX_CPB_SIZE_V6,
        .priv   = &mfc_buf_size_v6,
 };
 
-struct s5p_mfc_buf_align mfc_buf_align_v6 = {
+static struct s5p_mfc_buf_align mfc_buf_align_v6 = {
        .base = 0,
 };
 
@@ -1386,7 +1389,7 @@ static struct s5p_mfc_variant mfc_drvdata_v6 = {
        .fw_name[1]     = "s5p-mfc-v6-v2.fw",
 };
 
-struct s5p_mfc_buf_size_v6 mfc_buf_size_v7 = {
+static struct s5p_mfc_buf_size_v6 mfc_buf_size_v7 = {
        .dev_ctx        = MFC_CTX_BUF_SIZE_V7,
        .h264_dec_ctx   = MFC_H264_DEC_CTX_BUF_SIZE_V7,
        .other_dec_ctx  = MFC_OTHER_DEC_CTX_BUF_SIZE_V7,
@@ -1394,13 +1397,13 @@ struct s5p_mfc_buf_size_v6 mfc_buf_size_v7 = {
        .other_enc_ctx  = MFC_OTHER_ENC_CTX_BUF_SIZE_V7,
 };
 
-struct s5p_mfc_buf_size buf_size_v7 = {
+static struct s5p_mfc_buf_size buf_size_v7 = {
        .fw     = MAX_FW_SIZE_V7,
        .cpb    = MAX_CPB_SIZE_V7,
        .priv   = &mfc_buf_size_v7,
 };
 
-struct s5p_mfc_buf_align mfc_buf_align_v7 = {
+static struct s5p_mfc_buf_align mfc_buf_align_v7 = {
        .base = 0,
 };
 
@@ -1413,7 +1416,7 @@ static struct s5p_mfc_variant mfc_drvdata_v7 = {
        .fw_name[0]     = "s5p-mfc-v7.fw",
 };
 
-struct s5p_mfc_buf_size_v6 mfc_buf_size_v8 = {
+static struct s5p_mfc_buf_size_v6 mfc_buf_size_v8 = {
        .dev_ctx        = MFC_CTX_BUF_SIZE_V8,
        .h264_dec_ctx   = MFC_H264_DEC_CTX_BUF_SIZE_V8,
        .other_dec_ctx  = MFC_OTHER_DEC_CTX_BUF_SIZE_V8,
@@ -1421,13 +1424,13 @@ struct s5p_mfc_buf_size_v6 mfc_buf_size_v8 = {
        .other_enc_ctx  = MFC_OTHER_ENC_CTX_BUF_SIZE_V8,
 };
 
-struct s5p_mfc_buf_size buf_size_v8 = {
+static struct s5p_mfc_buf_size buf_size_v8 = {
        .fw     = MAX_FW_SIZE_V8,
        .cpb    = MAX_CPB_SIZE_V8,
        .priv   = &mfc_buf_size_v8,
 };
 
-struct s5p_mfc_buf_align mfc_buf_align_v8 = {
+static struct s5p_mfc_buf_align mfc_buf_align_v8 = {
        .base = 0,
 };
 
index 9a6efd6c13292dec6ab9ba3ba3c052ea9772f24c..8c4739ca16d67d55b0556c1f8880092759232b56 100644 (file)
@@ -14,6 +14,7 @@
 #include "s5p_mfc_cmd.h"
 #include "s5p_mfc_common.h"
 #include "s5p_mfc_debug.h"
+#include "s5p_mfc_cmd_v5.h"
 
 /* This function is used to send a command to the MFC */
 static int s5p_mfc_cmd_host2risc_v5(struct s5p_mfc_dev *dev, int cmd,
index ec1a5947ed7d00649dcdaf3a7e8b151695fd6902..f17609669b96a275d06001a3053f43f97fa74406 100644 (file)
@@ -16,6 +16,7 @@
 #include "s5p_mfc_debug.h"
 #include "s5p_mfc_intr.h"
 #include "s5p_mfc_opr.h"
+#include "s5p_mfc_cmd_v6.h"
 
 static int s5p_mfc_cmd_host2risc_v6(struct s5p_mfc_dev *dev, int cmd,
                                struct s5p_mfc_cmd_args *args)
index 01816ffb384b8834fe816e899f9d38d3ea61d472..3e41ca1293ed364088f75c830f0a4ee5d7c502d0 100644 (file)
@@ -698,6 +698,12 @@ struct mfc_control {
 #define s5p_mfc_hw_call(f, op, args...) \
        ((f && f->op) ? f->op(args) : -ENODEV)
 
+#define s5p_mfc_hw_call_void(f, op, args...) \
+do { \
+       if (f && f->op) \
+               f->op(args); \
+} while (0)
+
 #define fh_to_ctx(__fh) container_of(__fh, struct s5p_mfc_ctx, fh)
 #define ctrl_to_ctx(__ctrl) \
        container_of((__ctrl)->handler, struct s5p_mfc_ctx, ctrl_handler)
index ca9f789228329c9d2f0de9b6fadc34d957f2cadb..0c885a8a0e9fcd4341103991f5da3e788defbc89 100644 (file)
@@ -21,6 +21,7 @@
 #include "s5p_mfc_intr.h"
 #include "s5p_mfc_opr.h"
 #include "s5p_mfc_pm.h"
+#include "s5p_mfc_ctrl.h"
 
 /* Allocate memory for firmware */
 int s5p_mfc_alloc_firmware(struct s5p_mfc_dev *dev)
@@ -188,12 +189,12 @@ static inline void s5p_mfc_init_memctrl(struct s5p_mfc_dev *dev)
 {
        if (IS_MFCV6_PLUS(dev)) {
                mfc_write(dev, dev->bank1, S5P_FIMV_RISC_BASE_ADDRESS_V6);
-               mfc_debug(2, "Base Address : %08x\n", dev->bank1);
+               mfc_debug(2, "Base Address : %pad\n", &dev->bank1);
        } else {
                mfc_write(dev, dev->bank1, S5P_FIMV_MC_DRAMBASE_ADR_A);
                mfc_write(dev, dev->bank2, S5P_FIMV_MC_DRAMBASE_ADR_B);
-               mfc_debug(2, "Bank1: %08x, Bank2: %08x\n",
-                               dev->bank1, dev->bank2);
+               mfc_debug(2, "Bank1: %pad, Bank2: %pad\n",
+                               &dev->bank1, &dev->bank2);
        }
 }
 
@@ -257,9 +258,9 @@ int s5p_mfc_init_hw(struct s5p_mfc_dev *dev)
                s5p_mfc_clock_off();
                return ret;
        }
-       mfc_debug(2, "Ok, now will write a command to init the system\n");
+       mfc_debug(2, "Ok, now will wait for completion of hardware init\n");
        if (s5p_mfc_wait_for_done_dev(dev, S5P_MFC_R2H_CMD_SYS_INIT_RET)) {
-               mfc_err("Failed to load firmware\n");
+               mfc_err("Failed to init hardware\n");
                s5p_mfc_reset(dev);
                s5p_mfc_clock_off();
                return -EIO;
@@ -293,7 +294,7 @@ void s5p_mfc_deinit_hw(struct s5p_mfc_dev *dev)
        s5p_mfc_clock_on();
 
        s5p_mfc_reset(dev);
-       s5p_mfc_hw_call(dev->mfc_ops, release_dev_context_buffer, dev);
+       s5p_mfc_hw_call_void(dev->mfc_ops, release_dev_context_buffer, dev);
 
        s5p_mfc_clock_off();
 }
@@ -396,7 +397,7 @@ int s5p_mfc_open_mfc_inst(struct s5p_mfc_dev *dev, struct s5p_mfc_ctx *ctx)
 
        set_work_bit_irqsave(ctx);
        s5p_mfc_clean_ctx_int_flags(ctx);
-       s5p_mfc_hw_call(dev->mfc_ops, try_run, dev);
+       s5p_mfc_hw_call_void(dev->mfc_ops, try_run, dev);
        if (s5p_mfc_wait_for_done_ctx(ctx,
                S5P_MFC_R2H_CMD_OPEN_INSTANCE_RET, 0)) {
                /* Error or timeout */
@@ -410,9 +411,9 @@ int s5p_mfc_open_mfc_inst(struct s5p_mfc_dev *dev, struct s5p_mfc_ctx *ctx)
 
 err_free_desc_buf:
        if (ctx->type == MFCINST_DECODER)
-               s5p_mfc_hw_call(dev->mfc_ops, release_dec_desc_buffer, ctx);
+               s5p_mfc_hw_call_void(dev->mfc_ops, release_dec_desc_buffer, ctx);
 err_free_inst_buf:
-       s5p_mfc_hw_call(dev->mfc_ops, release_instance_buffer, ctx);
+       s5p_mfc_hw_call_void(dev->mfc_ops, release_instance_buffer, ctx);
 err:
        return ret;
 }
@@ -422,17 +423,17 @@ void s5p_mfc_close_mfc_inst(struct s5p_mfc_dev *dev, struct s5p_mfc_ctx *ctx)
        ctx->state = MFCINST_RETURN_INST;
        set_work_bit_irqsave(ctx);
        s5p_mfc_clean_ctx_int_flags(ctx);
-       s5p_mfc_hw_call(dev->mfc_ops, try_run, dev);
+       s5p_mfc_hw_call_void(dev->mfc_ops, try_run, dev);
        /* Wait until instance is returned or timeout occurred */
        if (s5p_mfc_wait_for_done_ctx(ctx,
                                S5P_MFC_R2H_CMD_CLOSE_INSTANCE_RET, 0))
                mfc_err("Err returning instance\n");
 
        /* Free resources */
-       s5p_mfc_hw_call(dev->mfc_ops, release_codec_buffers, ctx);
-       s5p_mfc_hw_call(dev->mfc_ops, release_instance_buffer, ctx);
+       s5p_mfc_hw_call_void(dev->mfc_ops, release_codec_buffers, ctx);
+       s5p_mfc_hw_call_void(dev->mfc_ops, release_instance_buffer, ctx);
        if (ctx->type == MFCINST_DECODER)
-               s5p_mfc_hw_call(dev->mfc_ops, release_dec_desc_buffer, ctx);
+               s5p_mfc_hw_call_void(dev->mfc_ops, release_dec_desc_buffer, ctx);
 
        ctx->inst_no = MFC_NO_INSTANCE_SET;
        ctx->state = MFCINST_FREE;
index 8e608f5aa0d7c866009a06f7b203c51d136040f1..5936923c631c9f9e1c2d6173cd13ce88adf2a9a6 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * drivers/media/platform/samsung/mfc5/s5p_mfc_debug.h
+ * drivers/media/platform/s5p-mfc/s5p_mfc_debug.h
  *
  * Header file for Samsung MFC (Multi Function Codec - FIMV) driver
  * This file contains debug macros
 #define DEBUG
 
 #ifdef DEBUG
-extern int debug;
+extern int mfc_debug_level;
 
 #define mfc_debug(level, fmt, args...)                         \
        do {                                                    \
-               if (debug >= level)                             \
+               if (mfc_debug_level >= level)                   \
                        printk(KERN_DEBUG "%s:%d: " fmt,        \
                                __func__, __LINE__, ##args);    \
        } while (0)
index 9103258b7df386b8434d7b89e2e92240be1feb5f..a98fe023deaf79e5879d3d9ae5e2317bd44204e8 100644 (file)
@@ -283,17 +283,13 @@ static int vidioc_querycap(struct file *file, void *priv,
 
 /* Enumerate format */
 static int vidioc_enum_fmt(struct file *file, struct v4l2_fmtdesc *f,
-                                                       bool mplane, bool out)
+                                                       bool out)
 {
        struct s5p_mfc_dev *dev = video_drvdata(file);
        struct s5p_mfc_fmt *fmt;
        int i, j = 0;
 
        for (i = 0; i < ARRAY_SIZE(formats); ++i) {
-               if (mplane && formats[i].num_planes == 1)
-                       continue;
-               else if (!mplane && formats[i].num_planes > 1)
-                       continue;
                if (out && formats[i].type != MFC_FMT_DEC)
                        continue;
                else if (!out && formats[i].type != MFC_FMT_RAW)
@@ -313,28 +309,16 @@ static int vidioc_enum_fmt(struct file *file, struct v4l2_fmtdesc *f,
        return 0;
 }
 
-static int vidioc_enum_fmt_vid_cap(struct file *file, void *pirv,
-                                                       struct v4l2_fmtdesc *f)
-{
-       return vidioc_enum_fmt(file, f, false, false);
-}
-
 static int vidioc_enum_fmt_vid_cap_mplane(struct file *file, void *pirv,
                                                        struct v4l2_fmtdesc *f)
 {
-       return vidioc_enum_fmt(file, f, true, false);
-}
-
-static int vidioc_enum_fmt_vid_out(struct file *file, void *priv,
-                                                       struct v4l2_fmtdesc *f)
-{
-       return vidioc_enum_fmt(file, f, false, true);
+       return vidioc_enum_fmt(file, f, false);
 }
 
 static int vidioc_enum_fmt_vid_out_mplane(struct file *file, void *priv,
                                                        struct v4l2_fmtdesc *f)
 {
-       return vidioc_enum_fmt(file, f, true, true);
+       return vidioc_enum_fmt(file, f, true);
 }
 
 /* Get format */
@@ -543,7 +527,7 @@ static int reqbufs_capture(struct s5p_mfc_dev *dev, struct s5p_mfc_ctx *ctx,
                ret = vb2_reqbufs(&ctx->vq_dst, reqbufs);
                if (ret)
                        goto out;
-               s5p_mfc_hw_call(dev->mfc_ops, release_codec_buffers, ctx);
+               s5p_mfc_hw_call_void(dev->mfc_ops, release_codec_buffers, ctx);
                ctx->dst_bufs_cnt = 0;
        } else if (ctx->capture_state == QUEUE_FREE) {
                WARN_ON(ctx->dst_bufs_cnt != 0);
@@ -571,7 +555,7 @@ static int reqbufs_capture(struct s5p_mfc_dev *dev, struct s5p_mfc_ctx *ctx,
 
                if (s5p_mfc_ctx_ready(ctx))
                        set_work_bit_irqsave(ctx);
-               s5p_mfc_hw_call(dev->mfc_ops, try_run, dev);
+               s5p_mfc_hw_call_void(dev->mfc_ops, try_run, dev);
                s5p_mfc_wait_for_done_ctx(ctx, S5P_MFC_R2H_CMD_INIT_BUFFERS_RET,
                                          0);
        } else {
@@ -823,8 +807,8 @@ static int vidioc_g_crop(struct file *file, void *priv,
        return 0;
 }
 
-int vidioc_decoder_cmd(struct file *file, void *priv,
-                                               struct v4l2_decoder_cmd *cmd)
+static int vidioc_decoder_cmd(struct file *file, void *priv,
+                             struct v4l2_decoder_cmd *cmd)
 {
        struct s5p_mfc_ctx *ctx = fh_to_ctx(priv);
        struct s5p_mfc_dev *dev = ctx->dev;
@@ -846,7 +830,7 @@ int vidioc_decoder_cmd(struct file *file, void *priv,
                        if (s5p_mfc_ctx_ready(ctx))
                                set_work_bit_irqsave(ctx);
                        spin_unlock_irqrestore(&dev->irqlock, flags);
-                       s5p_mfc_hw_call(dev->mfc_ops, try_run, dev);
+                       s5p_mfc_hw_call_void(dev->mfc_ops, try_run, dev);
                } else {
                        mfc_err("EOS: marking last buffer of stream");
                        buf = list_entry(ctx->src_queue.prev,
@@ -881,9 +865,7 @@ static int vidioc_subscribe_event(struct v4l2_fh *fh,
 /* v4l2_ioctl_ops */
 static const struct v4l2_ioctl_ops s5p_mfc_dec_ioctl_ops = {
        .vidioc_querycap = vidioc_querycap,
-       .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap,
        .vidioc_enum_fmt_vid_cap_mplane = vidioc_enum_fmt_vid_cap_mplane,
-       .vidioc_enum_fmt_vid_out = vidioc_enum_fmt_vid_out,
        .vidioc_enum_fmt_vid_out_mplane = vidioc_enum_fmt_vid_out_mplane,
        .vidioc_g_fmt_vid_cap_mplane = vidioc_g_fmt,
        .vidioc_g_fmt_vid_out_mplane = vidioc_g_fmt,
@@ -990,7 +972,7 @@ static int s5p_mfc_buf_init(struct vb2_buffer *vb)
        if (vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
                if (ctx->capture_state == QUEUE_BUFS_MMAPED)
                        return 0;
-               for (i = 0; i <= ctx->src_fmt->num_planes ; i++) {
+               for (i = 0; i < ctx->dst_fmt->num_planes; i++) {
                        if (IS_ERR_OR_NULL(ERR_PTR(
                                        vb2_dma_contig_plane_dma_addr(vb, i)))) {
                                mfc_err("Plane mem not allocated\n");
@@ -1044,7 +1026,7 @@ static int s5p_mfc_start_streaming(struct vb2_queue *q, unsigned int count)
        /* If context is ready then dev = work->data;schedule it to run */
        if (s5p_mfc_ctx_ready(ctx))
                set_work_bit_irqsave(ctx);
-       s5p_mfc_hw_call(dev->mfc_ops, try_run, dev);
+       s5p_mfc_hw_call_void(dev->mfc_ops, try_run, dev);
        return 0;
 }
 
@@ -1065,8 +1047,8 @@ static void s5p_mfc_stop_streaming(struct vb2_queue *q)
        }
        if (q->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
                spin_lock_irqsave(&dev->irqlock, flags);
-               s5p_mfc_hw_call(dev->mfc_ops, cleanup_queue, &ctx->dst_queue,
-                               &ctx->vq_dst);
+               s5p_mfc_hw_call_void(dev->mfc_ops, cleanup_queue,
+                                               &ctx->dst_queue, &ctx->vq_dst);
                INIT_LIST_HEAD(&ctx->dst_queue);
                ctx->dst_queue_cnt = 0;
                ctx->dpb_flush_flag = 1;
@@ -1076,7 +1058,7 @@ static void s5p_mfc_stop_streaming(struct vb2_queue *q)
                        ctx->state = MFCINST_FLUSH;
                        set_work_bit_irqsave(ctx);
                        s5p_mfc_clean_ctx_int_flags(ctx);
-                       s5p_mfc_hw_call(dev->mfc_ops, try_run, dev);
+                       s5p_mfc_hw_call_void(dev->mfc_ops, try_run, dev);
                        if (s5p_mfc_wait_for_done_ctx(ctx,
                                S5P_MFC_R2H_CMD_DPB_FLUSH_RET, 0))
                                mfc_err("Err flushing buffers\n");
@@ -1084,8 +1066,8 @@ static void s5p_mfc_stop_streaming(struct vb2_queue *q)
        }
        if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
                spin_lock_irqsave(&dev->irqlock, flags);
-               s5p_mfc_hw_call(dev->mfc_ops, cleanup_queue, &ctx->src_queue,
-                               &ctx->vq_src);
+               s5p_mfc_hw_call_void(dev->mfc_ops, cleanup_queue,
+                                               &ctx->src_queue, &ctx->vq_src);
                INIT_LIST_HEAD(&ctx->src_queue);
                ctx->src_queue_cnt = 0;
                spin_unlock_irqrestore(&dev->irqlock, flags);
@@ -1124,7 +1106,7 @@ static void s5p_mfc_buf_queue(struct vb2_buffer *vb)
        }
        if (s5p_mfc_ctx_ready(ctx))
                set_work_bit_irqsave(ctx);
-       s5p_mfc_hw_call(dev->mfc_ops, try_run, dev);
+       s5p_mfc_hw_call_void(dev->mfc_ops, try_run, dev);
 }
 
 static struct vb2_ops s5p_mfc_dec_qops = {
@@ -1220,7 +1202,7 @@ void s5p_mfc_dec_init(struct s5p_mfc_ctx *ctx)
        else
                f.fmt.pix_mp.pixelformat = V4L2_PIX_FMT_NV12MT;
        ctx->dst_fmt = find_format(&f, MFC_FMT_RAW);
-       mfc_debug(2, "Default src_fmt is %x, dest_fmt is %x\n",
-                       (unsigned int)ctx->src_fmt, (unsigned int)ctx->dst_fmt);
+       mfc_debug(2, "Default src_fmt is %p, dest_fmt is %p\n",
+                       ctx->src_fmt, ctx->dst_fmt);
 }
 
index d26b2484ca10b04576e56437c47e4b38473b4cd8..a904a1c7bb21e70bf8b29719a0c537b87bc0e465 100644 (file)
@@ -739,14 +739,11 @@ static int s5p_mfc_ctx_ready(struct s5p_mfc_ctx *ctx)
 static void cleanup_ref_queue(struct s5p_mfc_ctx *ctx)
 {
        struct s5p_mfc_buf *mb_entry;
-       unsigned long mb_y_addr, mb_c_addr;
 
        /* move buffers in ref queue to src queue */
        while (!list_empty(&ctx->ref_queue)) {
                mb_entry = list_entry((&ctx->ref_queue)->next,
                                                struct s5p_mfc_buf, list);
-               mb_y_addr = vb2_dma_contig_plane_dma_addr(mb_entry->b, 0);
-               mb_c_addr = vb2_dma_contig_plane_dma_addr(mb_entry->b, 1);
                list_del(&mb_entry->list);
                ctx->ref_queue_cnt--;
                list_add_tail(&mb_entry->list, &ctx->src_queue);
@@ -770,7 +767,7 @@ static int enc_pre_seq_start(struct s5p_mfc_ctx *ctx)
        dst_mb = list_entry(ctx->dst_queue.next, struct s5p_mfc_buf, list);
        dst_addr = vb2_dma_contig_plane_dma_addr(dst_mb->b, 0);
        dst_size = vb2_plane_size(dst_mb->b, 0);
-       s5p_mfc_hw_call(dev->mfc_ops, set_enc_stream_buffer, ctx, dst_addr,
+       s5p_mfc_hw_call_void(dev->mfc_ops, set_enc_stream_buffer, ctx, dst_addr,
                        dst_size);
        spin_unlock_irqrestore(&dev->irqlock, flags);
        return 0;
@@ -803,7 +800,7 @@ static int enc_post_seq_start(struct s5p_mfc_ctx *ctx)
                ctx->state = MFCINST_RUNNING;
                if (s5p_mfc_ctx_ready(ctx))
                        set_work_bit_irqsave(ctx);
-               s5p_mfc_hw_call(dev->mfc_ops, try_run, dev);
+               s5p_mfc_hw_call_void(dev->mfc_ops, try_run, dev);
        } else {
                enc_pb_count = s5p_mfc_hw_call(dev->mfc_ops,
                                get_enc_dpb_count, dev);
@@ -828,15 +825,15 @@ static int enc_pre_frame_start(struct s5p_mfc_ctx *ctx)
        src_mb = list_entry(ctx->src_queue.next, struct s5p_mfc_buf, list);
        src_y_addr = vb2_dma_contig_plane_dma_addr(src_mb->b, 0);
        src_c_addr = vb2_dma_contig_plane_dma_addr(src_mb->b, 1);
-       s5p_mfc_hw_call(dev->mfc_ops, set_enc_frame_buffer, ctx, src_y_addr,
-                       src_c_addr);
+       s5p_mfc_hw_call_void(dev->mfc_ops, set_enc_frame_buffer, ctx,
+                                                       src_y_addr, src_c_addr);
        spin_unlock_irqrestore(&dev->irqlock, flags);
 
        spin_lock_irqsave(&dev->irqlock, flags);
        dst_mb = list_entry(ctx->dst_queue.next, struct s5p_mfc_buf, list);
        dst_addr = vb2_dma_contig_plane_dma_addr(dst_mb->b, 0);
        dst_size = vb2_plane_size(dst_mb->b, 0);
-       s5p_mfc_hw_call(dev->mfc_ops, set_enc_stream_buffer, ctx, dst_addr,
+       s5p_mfc_hw_call_void(dev->mfc_ops, set_enc_stream_buffer, ctx, dst_addr,
                        dst_size);
        spin_unlock_irqrestore(&dev->irqlock, flags);
 
@@ -861,7 +858,7 @@ static int enc_post_frame_start(struct s5p_mfc_ctx *ctx)
                  mfc_read(dev, S5P_FIMV_ENC_SI_PIC_CNT));
        spin_lock_irqsave(&dev->irqlock, flags);
        if (slice_type >= 0) {
-               s5p_mfc_hw_call(dev->mfc_ops, get_enc_frame_buffer, ctx,
+               s5p_mfc_hw_call_void(dev->mfc_ops, get_enc_frame_buffer, ctx,
                                &enc_y_addr, &enc_c_addr);
                list_for_each_entry(mb_entry, &ctx->src_queue, list) {
                        mb_y_addr = vb2_dma_contig_plane_dma_addr(mb_entry->b, 0);
@@ -954,17 +951,13 @@ static int vidioc_querycap(struct file *file, void *priv,
 }
 
 static int vidioc_enum_fmt(struct file *file, struct v4l2_fmtdesc *f,
-                                                       bool mplane, bool out)
+                                                       bool out)
 {
        struct s5p_mfc_dev *dev = video_drvdata(file);
        struct s5p_mfc_fmt *fmt;
        int i, j = 0;
 
        for (i = 0; i < ARRAY_SIZE(formats); ++i) {
-               if (mplane && formats[i].num_planes == 1)
-                       continue;
-               else if (!mplane && formats[i].num_planes > 1)
-                       continue;
                if (out && formats[i].type != MFC_FMT_RAW)
                        continue;
                else if (!out && formats[i].type != MFC_FMT_ENC)
@@ -984,28 +977,16 @@ static int vidioc_enum_fmt(struct file *file, struct v4l2_fmtdesc *f,
        return -EINVAL;
 }
 
-static int vidioc_enum_fmt_vid_cap(struct file *file, void *pirv,
-                                  struct v4l2_fmtdesc *f)
-{
-       return vidioc_enum_fmt(file, f, false, false);
-}
-
 static int vidioc_enum_fmt_vid_cap_mplane(struct file *file, void *pirv,
                                          struct v4l2_fmtdesc *f)
 {
-       return vidioc_enum_fmt(file, f, true, false);
-}
-
-static int vidioc_enum_fmt_vid_out(struct file *file, void *prov,
-                                  struct v4l2_fmtdesc *f)
-{
-       return vidioc_enum_fmt(file, f, false, true);
+       return vidioc_enum_fmt(file, f, false);
 }
 
 static int vidioc_enum_fmt_vid_out_mplane(struct file *file, void *prov,
                                          struct v4l2_fmtdesc *f)
 {
-       return vidioc_enum_fmt(file, f, true, true);
+       return vidioc_enum_fmt(file, f, true);
 }
 
 static int vidioc_g_fmt(struct file *file, void *priv, struct v4l2_format *f)
@@ -1127,7 +1108,7 @@ static int vidioc_s_fmt(struct file *file, void *priv, struct v4l2_format *f)
                        pix_fmt_mp->width, pix_fmt_mp->height,
                        ctx->img_width, ctx->img_height);
 
-               s5p_mfc_hw_call(dev->mfc_ops, enc_calc_src_size, ctx);
+               s5p_mfc_hw_call_void(dev->mfc_ops, enc_calc_src_size, ctx);
                pix_fmt_mp->plane_fmt[0].sizeimage = ctx->luma_size;
                pix_fmt_mp->plane_fmt[0].bytesperline = ctx->buf_width;
                pix_fmt_mp->plane_fmt[1].sizeimage = ctx->chroma_size;
@@ -1681,8 +1662,8 @@ static int vidioc_g_parm(struct file *file, void *priv,
        return 0;
 }
 
-int vidioc_encoder_cmd(struct file *file, void *priv,
-                                               struct v4l2_encoder_cmd *cmd)
+static int vidioc_encoder_cmd(struct file *file, void *priv,
+                             struct v4l2_encoder_cmd *cmd)
 {
        struct s5p_mfc_ctx *ctx = fh_to_ctx(priv);
        struct s5p_mfc_dev *dev = ctx->dev;
@@ -1704,7 +1685,7 @@ int vidioc_encoder_cmd(struct file *file, void *priv,
                        if (s5p_mfc_ctx_ready(ctx))
                                set_work_bit_irqsave(ctx);
                        spin_unlock_irqrestore(&dev->irqlock, flags);
-                       s5p_mfc_hw_call(dev->mfc_ops, try_run, dev);
+                       s5p_mfc_hw_call_void(dev->mfc_ops, try_run, dev);
                } else {
                        mfc_debug(2, "EOS: marking last buffer of stream\n");
                        buf = list_entry(ctx->src_queue.prev,
@@ -1736,9 +1717,7 @@ static int vidioc_subscribe_event(struct v4l2_fh *fh,
 
 static const struct v4l2_ioctl_ops s5p_mfc_enc_ioctl_ops = {
        .vidioc_querycap = vidioc_querycap,
-       .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap,
        .vidioc_enum_fmt_vid_cap_mplane = vidioc_enum_fmt_vid_cap_mplane,
-       .vidioc_enum_fmt_vid_out = vidioc_enum_fmt_vid_out,
        .vidioc_enum_fmt_vid_out_mplane = vidioc_enum_fmt_vid_out_mplane,
        .vidioc_g_fmt_vid_cap_mplane = vidioc_g_fmt,
        .vidioc_g_fmt_vid_out_mplane = vidioc_g_fmt,
@@ -1771,13 +1750,13 @@ static int check_vb_with_fmt(struct s5p_mfc_fmt *fmt, struct vb2_buffer *vb)
                return -EINVAL;
        }
        for (i = 0; i < fmt->num_planes; i++) {
-               if (!vb2_dma_contig_plane_dma_addr(vb, i)) {
+               dma_addr_t dma = vb2_dma_contig_plane_dma_addr(vb, i);
+               if (!dma) {
                        mfc_err("failed to get plane cookie\n");
                        return -EINVAL;
                }
-               mfc_debug(2, "index: %d, plane[%d] cookie: 0x%08zx\n",
-                         vb->v4l2_buf.index, i,
-                         vb2_dma_contig_plane_dma_addr(vb, i));
+               mfc_debug(2, "index: %d, plane[%d] cookie: %pad\n",
+                         vb->v4l2_buf.index, i, &dma);
        }
        return 0;
 }
@@ -1897,7 +1876,7 @@ static int s5p_mfc_buf_prepare(struct vb2_buffer *vb)
                ret = check_vb_with_fmt(ctx->dst_fmt, vb);
                if (ret < 0)
                        return ret;
-               mfc_debug(2, "plane size: %ld, dst size: %d\n",
+               mfc_debug(2, "plane size: %ld, dst size: %zu\n",
                        vb2_plane_size(vb, 0), ctx->enc_dst_buf_size);
                if (vb2_plane_size(vb, 0) < ctx->enc_dst_buf_size) {
                        mfc_err("plane size is too small for capture\n");
@@ -1948,7 +1927,7 @@ static int s5p_mfc_start_streaming(struct vb2_queue *q, unsigned int count)
        /* If context is ready then dev = work->data;schedule it to run */
        if (s5p_mfc_ctx_ready(ctx))
                set_work_bit_irqsave(ctx);
-       s5p_mfc_hw_call(dev->mfc_ops, try_run, dev);
+       s5p_mfc_hw_call_void(dev->mfc_ops, try_run, dev);
 
        return 0;
 }
@@ -1969,14 +1948,14 @@ static void s5p_mfc_stop_streaming(struct vb2_queue *q)
        ctx->state = MFCINST_FINISHED;
        spin_lock_irqsave(&dev->irqlock, flags);
        if (q->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
-               s5p_mfc_hw_call(dev->mfc_ops, cleanup_queue, &ctx->dst_queue,
-                               &ctx->vq_dst);
+               s5p_mfc_hw_call_void(dev->mfc_ops, cleanup_queue,
+                                               &ctx->dst_queue, &ctx->vq_dst);
                INIT_LIST_HEAD(&ctx->dst_queue);
                ctx->dst_queue_cnt = 0;
        }
        if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
                cleanup_ref_queue(ctx);
-               s5p_mfc_hw_call(dev->mfc_ops, cleanup_queue, &ctx->src_queue,
+               s5p_mfc_hw_call_void(dev->mfc_ops, cleanup_queue, &ctx->src_queue,
                                &ctx->vq_src);
                INIT_LIST_HEAD(&ctx->src_queue);
                ctx->src_queue_cnt = 0;
@@ -2017,7 +1996,7 @@ static void s5p_mfc_buf_queue(struct vb2_buffer *vb)
        }
        if (s5p_mfc_ctx_ready(ctx))
                set_work_bit_irqsave(ctx);
-       s5p_mfc_hw_call(dev->mfc_ops, try_run, dev);
+       s5p_mfc_hw_call_void(dev->mfc_ops, try_run, dev);
 }
 
 static struct vb2_ops s5p_mfc_enc_qops = {
index c9a227428e6ad38c99d7fa2e88c533cf8a39dadc..00a1d8b2a8c236195259885bc0aaaca7a549fd37 100644 (file)
@@ -41,7 +41,7 @@ int s5p_mfc_alloc_priv_buf(struct device *dev,
                                        struct s5p_mfc_priv_buf *b)
 {
 
-       mfc_debug(3, "Allocating priv: %d\n", b->size);
+       mfc_debug(3, "Allocating priv: %zu\n", b->size);
 
        b->virt = dma_alloc_coherent(dev, b->size, &b->dma, GFP_KERNEL);
 
@@ -50,7 +50,7 @@ int s5p_mfc_alloc_priv_buf(struct device *dev,
                return -ENOMEM;
        }
 
-       mfc_debug(3, "Allocated addr %p %08x\n", b->virt, b->dma);
+       mfc_debug(3, "Allocated addr %p %pad\n", b->virt, &b->dma);
        return 0;
 }
 
index 7a7ad32ee60883e81544cf5a036df33c08a5039d..de2b8c69daa535dd6ea906dcd476638e3185c72f 100644 (file)
 struct s5p_mfc_regs {
 
        /* codec common registers */
-       void *risc_on;
-       void *risc2host_int;
-       void *host2risc_int;
-       void *risc_base_address;
-       void *mfc_reset;
-       void *host2risc_command;
-       void *risc2host_command;
-       void *mfc_bus_reset_ctrl;
-       void *firmware_version;
-       void *instance_id;
-       void *codec_type;
-       void *context_mem_addr;
-       void *context_mem_size;
-       void *pixel_format;
-       void *metadata_enable;
-       void *mfc_version;
-       void *dbg_info_enable;
-       void *dbg_buffer_addr;
-       void *dbg_buffer_size;
-       void *hed_control;
-       void *mfc_timeout_value;
-       void *hed_shared_mem_addr;
-       void *dis_shared_mem_addr;/* only v7 */
-       void *ret_instance_id;
-       void *error_code;
-       void *dbg_buffer_output_size;
-       void *metadata_status;
-       void *metadata_addr_mb_info;
-       void *metadata_size_mb_info;
-       void *dbg_info_stage_counter;
+       volatile void __iomem *risc_on;
+       volatile void __iomem *risc2host_int;
+       volatile void __iomem *host2risc_int;
+       volatile void __iomem *risc_base_address;
+       volatile void __iomem *mfc_reset;
+       volatile void __iomem *host2risc_command;
+       volatile void __iomem *risc2host_command;
+       volatile void __iomem *mfc_bus_reset_ctrl;
+       volatile void __iomem *firmware_version;
+       volatile void __iomem *instance_id;
+       volatile void __iomem *codec_type;
+       volatile void __iomem *context_mem_addr;
+       volatile void __iomem *context_mem_size;
+       volatile void __iomem *pixel_format;
+       volatile void __iomem *metadata_enable;
+       volatile void __iomem *mfc_version;
+       volatile void __iomem *dbg_info_enable;
+       volatile void __iomem *dbg_buffer_addr;
+       volatile void __iomem *dbg_buffer_size;
+       volatile void __iomem *hed_control;
+       volatile void __iomem *mfc_timeout_value;
+       volatile void __iomem *hed_shared_mem_addr;
+       volatile void __iomem *dis_shared_mem_addr;/* only v7 */
+       volatile void __iomem *ret_instance_id;
+       volatile void __iomem *error_code;
+       volatile void __iomem *dbg_buffer_output_size;
+       volatile void __iomem *metadata_status;
+       volatile void __iomem *metadata_addr_mb_info;
+       volatile void __iomem *metadata_size_mb_info;
+       volatile void __iomem *dbg_info_stage_counter;
 
        /* decoder registers */
-       void *d_crc_ctrl;
-       void *d_dec_options;
-       void *d_display_delay;
-       void *d_set_frame_width;
-       void *d_set_frame_height;
-       void *d_sei_enable;
-       void *d_min_num_dpb;
-       void *d_min_first_plane_dpb_size;
-       void *d_min_second_plane_dpb_size;
-       void *d_min_third_plane_dpb_size;/* only v8 */
-       void *d_min_num_mv;
-       void *d_mvc_num_views;
-       void *d_min_num_dis;/* only v7 */
-       void *d_min_first_dis_size;/* only v7 */
-       void *d_min_second_dis_size;/* only v7 */
-       void *d_min_third_dis_size;/* only v7 */
-       void *d_post_filter_luma_dpb0;/*  v7 and v8 */
-       void *d_post_filter_luma_dpb1;/* v7 and v8 */
-       void *d_post_filter_luma_dpb2;/* only v7 */
-       void *d_post_filter_chroma_dpb0;/* v7 and v8 */
-       void *d_post_filter_chroma_dpb1;/* v7 and v8 */
-       void *d_post_filter_chroma_dpb2;/* only v7 */
-       void *d_num_dpb;
-       void *d_num_mv;
-       void *d_init_buffer_options;
-       void *d_first_plane_dpb_stride_size;/* only v8 */
-       void *d_second_plane_dpb_stride_size;/* only v8 */
-       void *d_third_plane_dpb_stride_size;/* only v8 */
-       void *d_first_plane_dpb_size;
-       void *d_second_plane_dpb_size;
-       void *d_third_plane_dpb_size;/* only v8 */
-       void *d_mv_buffer_size;
-       void *d_first_plane_dpb;
-       void *d_second_plane_dpb;
-       void *d_third_plane_dpb;
-       void *d_mv_buffer;
-       void *d_scratch_buffer_addr;
-       void *d_scratch_buffer_size;
-       void *d_metadata_buffer_addr;
-       void *d_metadata_buffer_size;
-       void *d_nal_start_options;/* v7 and v8 */
-       void *d_cpb_buffer_addr;
-       void *d_cpb_buffer_size;
-       void *d_available_dpb_flag_upper;
-       void *d_available_dpb_flag_lower;
-       void *d_cpb_buffer_offset;
-       void *d_slice_if_enable;
-       void *d_picture_tag;
-       void *d_stream_data_size;
-       void *d_dynamic_dpb_flag_upper;/* v7 and v8 */
-       void *d_dynamic_dpb_flag_lower;/* v7 and v8 */
-       void *d_display_frame_width;
-       void *d_display_frame_height;
-       void *d_display_status;
-       void *d_display_first_plane_addr;
-       void *d_display_second_plane_addr;
-       void *d_display_third_plane_addr;/* only v8 */
-       void *d_display_frame_type;
-       void *d_display_crop_info1;
-       void *d_display_crop_info2;
-       void *d_display_picture_profile;
-       void *d_display_luma_crc;/* v7 and v8 */
-       void *d_display_chroma0_crc;/* v7 and v8 */
-       void *d_display_chroma1_crc;/* only v8 */
-       void *d_display_luma_crc_top;/* only v6 */
-       void *d_display_chroma_crc_top;/* only v6 */
-       void *d_display_luma_crc_bot;/* only v6 */
-       void *d_display_chroma_crc_bot;/* only v6 */
-       void *d_display_aspect_ratio;
-       void *d_display_extended_ar;
-       void *d_decoded_frame_width;
-       void *d_decoded_frame_height;
-       void *d_decoded_status;
-       void *d_decoded_first_plane_addr;
-       void *d_decoded_second_plane_addr;
-       void *d_decoded_third_plane_addr;/* only v8 */
-       void *d_decoded_frame_type;
-       void *d_decoded_crop_info1;
-       void *d_decoded_crop_info2;
-       void *d_decoded_picture_profile;
-       void *d_decoded_nal_size;
-       void *d_decoded_luma_crc;
-       void *d_decoded_chroma0_crc;
-       void *d_decoded_chroma1_crc;/* only v8 */
-       void *d_ret_picture_tag_top;
-       void *d_ret_picture_tag_bot;
-       void *d_ret_picture_time_top;
-       void *d_ret_picture_time_bot;
-       void *d_chroma_format;
-       void *d_vc1_info;/* v7 and v8 */
-       void *d_mpeg4_info;
-       void *d_h264_info;
-       void *d_metadata_addr_concealed_mb;
-       void *d_metadata_size_concealed_mb;
-       void *d_metadata_addr_vc1_param;
-       void *d_metadata_size_vc1_param;
-       void *d_metadata_addr_sei_nal;
-       void *d_metadata_size_sei_nal;
-       void *d_metadata_addr_vui;
-       void *d_metadata_size_vui;
-       void *d_metadata_addr_mvcvui;/* v7 and v8 */
-       void *d_metadata_size_mvcvui;/* v7 and v8 */
-       void *d_mvc_view_id;
-       void *d_frame_pack_sei_avail;
-       void *d_frame_pack_arrgment_id;
-       void *d_frame_pack_sei_info;
-       void *d_frame_pack_grid_pos;
-       void *d_display_recovery_sei_info;/* v7 and v8 */
-       void *d_decoded_recovery_sei_info;/* v7 and v8 */
-       void *d_display_first_addr;/* only v7 */
-       void *d_display_second_addr;/* only v7 */
-       void *d_display_third_addr;/* only v7 */
-       void *d_decoded_first_addr;/* only v7 */
-       void *d_decoded_second_addr;/* only v7 */
-       void *d_decoded_third_addr;/* only v7 */
-       void *d_used_dpb_flag_upper;/* v7 and v8 */
-       void *d_used_dpb_flag_lower;/* v7 and v8 */
+       volatile void __iomem *d_crc_ctrl;
+       volatile void __iomem *d_dec_options;
+       volatile void __iomem *d_display_delay;
+       volatile void __iomem *d_set_frame_width;
+       volatile void __iomem *d_set_frame_height;
+       volatile void __iomem *d_sei_enable;
+       volatile void __iomem *d_min_num_dpb;
+       volatile void __iomem *d_min_first_plane_dpb_size;
+       volatile void __iomem *d_min_second_plane_dpb_size;
+       volatile void __iomem *d_min_third_plane_dpb_size;/* only v8 */
+       volatile void __iomem *d_min_num_mv;
+       volatile void __iomem *d_mvc_num_views;
+       volatile void __iomem *d_min_num_dis;/* only v7 */
+       volatile void __iomem *d_min_first_dis_size;/* only v7 */
+       volatile void __iomem *d_min_second_dis_size;/* only v7 */
+       volatile void __iomem *d_min_third_dis_size;/* only v7 */
+       volatile void __iomem *d_post_filter_luma_dpb0;/*  v7 and v8 */
+       volatile void __iomem *d_post_filter_luma_dpb1;/* v7 and v8 */
+       volatile void __iomem *d_post_filter_luma_dpb2;/* only v7 */
+       volatile void __iomem *d_post_filter_chroma_dpb0;/* v7 and v8 */
+       volatile void __iomem *d_post_filter_chroma_dpb1;/* v7 and v8 */
+       volatile void __iomem *d_post_filter_chroma_dpb2;/* only v7 */
+       volatile void __iomem *d_num_dpb;
+       volatile void __iomem *d_num_mv;
+       volatile void __iomem *d_init_buffer_options;
+       volatile void __iomem *d_first_plane_dpb_stride_size;/* only v8 */
+       volatile void __iomem *d_second_plane_dpb_stride_size;/* only v8 */
+       volatile void __iomem *d_third_plane_dpb_stride_size;/* only v8 */
+       volatile void __iomem *d_first_plane_dpb_size;
+       volatile void __iomem *d_second_plane_dpb_size;
+       volatile void __iomem *d_third_plane_dpb_size;/* only v8 */
+       volatile void __iomem *d_mv_buffer_size;
+       volatile void __iomem *d_first_plane_dpb;
+       volatile void __iomem *d_second_plane_dpb;
+       volatile void __iomem *d_third_plane_dpb;
+       volatile void __iomem *d_mv_buffer;
+       volatile void __iomem *d_scratch_buffer_addr;
+       volatile void __iomem *d_scratch_buffer_size;
+       volatile void __iomem *d_metadata_buffer_addr;
+       volatile void __iomem *d_metadata_buffer_size;
+       volatile void __iomem *d_nal_start_options;/* v7 and v8 */
+       volatile void __iomem *d_cpb_buffer_addr;
+       volatile void __iomem *d_cpb_buffer_size;
+       volatile void __iomem *d_available_dpb_flag_upper;
+       volatile void __iomem *d_available_dpb_flag_lower;
+       volatile void __iomem *d_cpb_buffer_offset;
+       volatile void __iomem *d_slice_if_enable;
+       volatile void __iomem *d_picture_tag;
+       volatile void __iomem *d_stream_data_size;
+       volatile void __iomem *d_dynamic_dpb_flag_upper;/* v7 and v8 */
+       volatile void __iomem *d_dynamic_dpb_flag_lower;/* v7 and v8 */
+       volatile void __iomem *d_display_frame_width;
+       volatile void __iomem *d_display_frame_height;
+       volatile void __iomem *d_display_status;
+       volatile void __iomem *d_display_first_plane_addr;
+       volatile void __iomem *d_display_second_plane_addr;
+       volatile void __iomem *d_display_third_plane_addr;/* only v8 */
+       volatile void __iomem *d_display_frame_type;
+       volatile void __iomem *d_display_crop_info1;
+       volatile void __iomem *d_display_crop_info2;
+       volatile void __iomem *d_display_picture_profile;
+       volatile void __iomem *d_display_luma_crc;/* v7 and v8 */
+       volatile void __iomem *d_display_chroma0_crc;/* v7 and v8 */
+       volatile void __iomem *d_display_chroma1_crc;/* only v8 */
+       volatile void __iomem *d_display_luma_crc_top;/* only v6 */
+       volatile void __iomem *d_display_chroma_crc_top;/* only v6 */
+       volatile void __iomem *d_display_luma_crc_bot;/* only v6 */
+       volatile void __iomem *d_display_chroma_crc_bot;/* only v6 */
+       volatile void __iomem *d_display_aspect_ratio;
+       volatile void __iomem *d_display_extended_ar;
+       volatile void __iomem *d_decoded_frame_width;
+       volatile void __iomem *d_decoded_frame_height;
+       volatile void __iomem *d_decoded_status;
+       volatile void __iomem *d_decoded_first_plane_addr;
+       volatile void __iomem *d_decoded_second_plane_addr;
+       volatile void __iomem *d_decoded_third_plane_addr;/* only v8 */
+       volatile void __iomem *d_decoded_frame_type;
+       volatile void __iomem *d_decoded_crop_info1;
+       volatile void __iomem *d_decoded_crop_info2;
+       volatile void __iomem *d_decoded_picture_profile;
+       volatile void __iomem *d_decoded_nal_size;
+       volatile void __iomem *d_decoded_luma_crc;
+       volatile void __iomem *d_decoded_chroma0_crc;
+       volatile void __iomem *d_decoded_chroma1_crc;/* only v8 */
+       volatile void __iomem *d_ret_picture_tag_top;
+       volatile void __iomem *d_ret_picture_tag_bot;
+       volatile void __iomem *d_ret_picture_time_top;
+       volatile void __iomem *d_ret_picture_time_bot;
+       volatile void __iomem *d_chroma_format;
+       volatile void __iomem *d_vc1_info;/* v7 and v8 */
+       volatile void __iomem *d_mpeg4_info;
+       volatile void __iomem *d_h264_info;
+       volatile void __iomem *d_metadata_addr_concealed_mb;
+       volatile void __iomem *d_metadata_size_concealed_mb;
+       volatile void __iomem *d_metadata_addr_vc1_param;
+       volatile void __iomem *d_metadata_size_vc1_param;
+       volatile void __iomem *d_metadata_addr_sei_nal;
+       volatile void __iomem *d_metadata_size_sei_nal;
+       volatile void __iomem *d_metadata_addr_vui;
+       volatile void __iomem *d_metadata_size_vui;
+       volatile void __iomem *d_metadata_addr_mvcvui;/* v7 and v8 */
+       volatile void __iomem *d_metadata_size_mvcvui;/* v7 and v8 */
+       volatile void __iomem *d_mvc_view_id;
+       volatile void __iomem *d_frame_pack_sei_avail;
+       volatile void __iomem *d_frame_pack_arrgment_id;
+       volatile void __iomem *d_frame_pack_sei_info;
+       volatile void __iomem *d_frame_pack_grid_pos;
+       volatile void __iomem *d_display_recovery_sei_info;/* v7 and v8 */
+       volatile void __iomem *d_decoded_recovery_sei_info;/* v7 and v8 */
+       volatile void __iomem *d_display_first_addr;/* only v7 */
+       volatile void __iomem *d_display_second_addr;/* only v7 */
+       volatile void __iomem *d_display_third_addr;/* only v7 */
+       volatile void __iomem *d_decoded_first_addr;/* only v7 */
+       volatile void __iomem *d_decoded_second_addr;/* only v7 */
+       volatile void __iomem *d_decoded_third_addr;/* only v7 */
+       volatile void __iomem *d_used_dpb_flag_upper;/* v7 and v8 */
+       volatile void __iomem *d_used_dpb_flag_lower;/* v7 and v8 */
 
        /* encoder registers */
-       void *e_frame_width;
-       void *e_frame_height;
-       void *e_cropped_frame_width;
-       void *e_cropped_frame_height;
-       void *e_frame_crop_offset;
-       void *e_enc_options;
-       void *e_picture_profile;
-       void *e_vbv_buffer_size;
-       void *e_vbv_init_delay;
-       void *e_fixed_picture_qp;
-       void *e_rc_config;
-       void *e_rc_qp_bound;
-       void *e_rc_qp_bound_pb;/* v7 and v8 */
-       void *e_rc_mode;
-       void *e_mb_rc_config;
-       void *e_padding_ctrl;
-       void *e_air_threshold;
-       void *e_mv_hor_range;
-       void *e_mv_ver_range;
-       void *e_num_dpb;
-       void *e_luma_dpb;
-       void *e_chroma_dpb;
-       void *e_me_buffer;
-       void *e_scratch_buffer_addr;
-       void *e_scratch_buffer_size;
-       void *e_tmv_buffer0;
-       void *e_tmv_buffer1;
-       void *e_ir_buffer_addr;/* v7 and v8 */
-       void *e_source_first_plane_addr;
-       void *e_source_second_plane_addr;
-       void *e_source_third_plane_addr;/* v7 and v8 */
-       void *e_source_first_plane_stride;/* v7 and v8 */
-       void *e_source_second_plane_stride;/* v7 and v8 */
-       void *e_source_third_plane_stride;/* v7 and v8 */
-       void *e_stream_buffer_addr;
-       void *e_stream_buffer_size;
-       void *e_roi_buffer_addr;
-       void *e_param_change;
-       void *e_ir_size;
-       void *e_gop_config;
-       void *e_mslice_mode;
-       void *e_mslice_size_mb;
-       void *e_mslice_size_bits;
-       void *e_frame_insertion;
-       void *e_rc_frame_rate;
-       void *e_rc_bit_rate;
-       void *e_rc_roi_ctrl;
-       void *e_picture_tag;
-       void *e_bit_count_enable;
-       void *e_max_bit_count;
-       void *e_min_bit_count;
-       void *e_metadata_buffer_addr;
-       void *e_metadata_buffer_size;
-       void *e_encoded_source_first_plane_addr;
-       void *e_encoded_source_second_plane_addr;
-       void *e_encoded_source_third_plane_addr;/* v7 and v8 */
-       void *e_stream_size;
-       void *e_slice_type;
-       void *e_picture_count;
-       void *e_ret_picture_tag;
-       void *e_stream_buffer_write_pointer; /*  only v6 */
-       void *e_recon_luma_dpb_addr;
-       void *e_recon_chroma_dpb_addr;
-       void *e_metadata_addr_enc_slice;
-       void *e_metadata_size_enc_slice;
-       void *e_mpeg4_options;
-       void *e_mpeg4_hec_period;
-       void *e_aspect_ratio;
-       void *e_extended_sar;
-       void *e_h264_options;
-       void *e_h264_options_2;/* v7 and v8 */
-       void *e_h264_lf_alpha_offset;
-       void *e_h264_lf_beta_offset;
-       void *e_h264_i_period;
-       void *e_h264_fmo_slice_grp_map_type;
-       void *e_h264_fmo_num_slice_grp_minus1;
-       void *e_h264_fmo_slice_grp_change_dir;
-       void *e_h264_fmo_slice_grp_change_rate_minus1;
-       void *e_h264_fmo_run_length_minus1_0;
-       void *e_h264_aso_slice_order_0;
-       void *e_h264_chroma_qp_offset;
-       void *e_h264_num_t_layer;
-       void *e_h264_hierarchical_qp_layer0;
-       void *e_h264_frame_packing_sei_info;
-       void *e_h264_nal_control;/* v7 and v8 */
-       void *e_mvc_frame_qp_view1;
-       void *e_mvc_rc_bit_rate_view1;
-       void *e_mvc_rc_qbound_view1;
-       void *e_mvc_rc_mode_view1;
-       void *e_mvc_inter_view_prediction_on;
-       void *e_vp8_options;/* v7 and v8 */
-       void *e_vp8_filter_options;/* v7 and v8 */
-       void *e_vp8_golden_frame_option;/* v7 and v8 */
-       void *e_vp8_num_t_layer;/* v7 and v8 */
-       void *e_vp8_hierarchical_qp_layer0;/* v7 and v8 */
-       void *e_vp8_hierarchical_qp_layer1;/* v7 and v8 */
-       void *e_vp8_hierarchical_qp_layer2;/* v7 and v8 */
+       volatile void __iomem *e_frame_width;
+       volatile void __iomem *e_frame_height;
+       volatile void __iomem *e_cropped_frame_width;
+       volatile void __iomem *e_cropped_frame_height;
+       volatile void __iomem *e_frame_crop_offset;
+       volatile void __iomem *e_enc_options;
+       volatile void __iomem *e_picture_profile;
+       volatile void __iomem *e_vbv_buffer_size;
+       volatile void __iomem *e_vbv_init_delay;
+       volatile void __iomem *e_fixed_picture_qp;
+       volatile void __iomem *e_rc_config;
+       volatile void __iomem *e_rc_qp_bound;
+       volatile void __iomem *e_rc_qp_bound_pb;/* v7 and v8 */
+       volatile void __iomem *e_rc_mode;
+       volatile void __iomem *e_mb_rc_config;
+       volatile void __iomem *e_padding_ctrl;
+       volatile void __iomem *e_air_threshold;
+       volatile void __iomem *e_mv_hor_range;
+       volatile void __iomem *e_mv_ver_range;
+       volatile void __iomem *e_num_dpb;
+       volatile void __iomem *e_luma_dpb;
+       volatile void __iomem *e_chroma_dpb;
+       volatile void __iomem *e_me_buffer;
+       volatile void __iomem *e_scratch_buffer_addr;
+       volatile void __iomem *e_scratch_buffer_size;
+       volatile void __iomem *e_tmv_buffer0;
+       volatile void __iomem *e_tmv_buffer1;
+       volatile void __iomem *e_ir_buffer_addr;/* v7 and v8 */
+       volatile void __iomem *e_source_first_plane_addr;
+       volatile void __iomem *e_source_second_plane_addr;
+       volatile void __iomem *e_source_third_plane_addr;/* v7 and v8 */
+       volatile void __iomem *e_source_first_plane_stride;/* v7 and v8 */
+       volatile void __iomem *e_source_second_plane_stride;/* v7 and v8 */
+       volatile void __iomem *e_source_third_plane_stride;/* v7 and v8 */
+       volatile void __iomem *e_stream_buffer_addr;
+       volatile void __iomem *e_stream_buffer_size;
+       volatile void __iomem *e_roi_buffer_addr;
+       volatile void __iomem *e_param_change;
+       volatile void __iomem *e_ir_size;
+       volatile void __iomem *e_gop_config;
+       volatile void __iomem *e_mslice_mode;
+       volatile void __iomem *e_mslice_size_mb;
+       volatile void __iomem *e_mslice_size_bits;
+       volatile void __iomem *e_frame_insertion;
+       volatile void __iomem *e_rc_frame_rate;
+       volatile void __iomem *e_rc_bit_rate;
+       volatile void __iomem *e_rc_roi_ctrl;
+       volatile void __iomem *e_picture_tag;
+       volatile void __iomem *e_bit_count_enable;
+       volatile void __iomem *e_max_bit_count;
+       volatile void __iomem *e_min_bit_count;
+       volatile void __iomem *e_metadata_buffer_addr;
+       volatile void __iomem *e_metadata_buffer_size;
+       volatile void __iomem *e_encoded_source_first_plane_addr;
+       volatile void __iomem *e_encoded_source_second_plane_addr;
+       volatile void __iomem *e_encoded_source_third_plane_addr;/* v7 and v8 */
+       volatile void __iomem *e_stream_size;
+       volatile void __iomem *e_slice_type;
+       volatile void __iomem *e_picture_count;
+       volatile void __iomem *e_ret_picture_tag;
+       volatile void __iomem *e_stream_buffer_write_pointer; /*  only v6 */
+       volatile void __iomem *e_recon_luma_dpb_addr;
+       volatile void __iomem *e_recon_chroma_dpb_addr;
+       volatile void __iomem *e_metadata_addr_enc_slice;
+       volatile void __iomem *e_metadata_size_enc_slice;
+       volatile void __iomem *e_mpeg4_options;
+       volatile void __iomem *e_mpeg4_hec_period;
+       volatile void __iomem *e_aspect_ratio;
+       volatile void __iomem *e_extended_sar;
+       volatile void __iomem *e_h264_options;
+       volatile void __iomem *e_h264_options_2;/* v7 and v8 */
+       volatile void __iomem *e_h264_lf_alpha_offset;
+       volatile void __iomem *e_h264_lf_beta_offset;
+       volatile void __iomem *e_h264_i_period;
+       volatile void __iomem *e_h264_fmo_slice_grp_map_type;
+       volatile void __iomem *e_h264_fmo_num_slice_grp_minus1;
+       volatile void __iomem *e_h264_fmo_slice_grp_change_dir;
+       volatile void __iomem *e_h264_fmo_slice_grp_change_rate_minus1;
+       volatile void __iomem *e_h264_fmo_run_length_minus1_0;
+       volatile void __iomem *e_h264_aso_slice_order_0;
+       volatile void __iomem *e_h264_chroma_qp_offset;
+       volatile void __iomem *e_h264_num_t_layer;
+       volatile void __iomem *e_h264_hierarchical_qp_layer0;
+       volatile void __iomem *e_h264_frame_packing_sei_info;
+       volatile void __iomem *e_h264_nal_control;/* v7 and v8 */
+       volatile void __iomem *e_mvc_frame_qp_view1;
+       volatile void __iomem *e_mvc_rc_bit_rate_view1;
+       volatile void __iomem *e_mvc_rc_qbound_view1;
+       volatile void __iomem *e_mvc_rc_mode_view1;
+       volatile void __iomem *e_mvc_inter_view_prediction_on;
+       volatile void __iomem *e_vp8_options;/* v7 and v8 */
+       volatile void __iomem *e_vp8_filter_options;/* v7 and v8 */
+       volatile void __iomem *e_vp8_golden_frame_option;/* v7 and v8 */
+       volatile void __iomem *e_vp8_num_t_layer;/* v7 and v8 */
+       volatile void __iomem *e_vp8_hierarchical_qp_layer0;/* v7 and v8 */
+       volatile void __iomem *e_vp8_hierarchical_qp_layer1;/* v7 and v8 */
+       volatile void __iomem *e_vp8_hierarchical_qp_layer2;/* v7 and v8 */
 };
 
 struct s5p_mfc_hw_ops {
index 58ec7bb26ebc715f11b145f72149b9a4535a9297..7cf07963187dd33e254cc3d89db849f2ae877faf 100644 (file)
@@ -228,6 +228,7 @@ static int s5p_mfc_alloc_instance_buffer_v5(struct s5p_mfc_ctx *ctx)
        ret = s5p_mfc_alloc_priv_buf(dev->mem_dev_l, &ctx->shm);
        if (ret) {
                mfc_err("Failed to allocate shared memory buffer\n");
+               s5p_mfc_release_priv_buf(dev->mem_dev_l, &ctx->ctx);
                return ret;
        }
 
@@ -262,7 +263,7 @@ static void s5p_mfc_release_dev_context_buffer_v5(struct s5p_mfc_dev *dev)
 static void s5p_mfc_write_info_v5(struct s5p_mfc_ctx *ctx, unsigned int data,
                        unsigned int ofs)
 {
-       writel(data, (ctx->shm.virt + ofs));
+       writel(data, (volatile void __iomem *)(ctx->shm.virt + ofs));
        wmb();
 }
 
@@ -270,7 +271,7 @@ static unsigned int s5p_mfc_read_info_v5(struct s5p_mfc_ctx *ctx,
                                unsigned int ofs)
 {
        rmb();
-       return readl(ctx->shm.virt + ofs);
+       return readl((volatile void __iomem *)(ctx->shm.virt + ofs));
 }
 
 static void s5p_mfc_dec_calc_dpb_size_v5(struct s5p_mfc_ctx *ctx)
@@ -377,7 +378,7 @@ static int s5p_mfc_set_dec_stream_buffer_v5(struct s5p_mfc_ctx *ctx,
 /* Set decoding frame buffer */
 static int s5p_mfc_set_dec_frame_buffer_v5(struct s5p_mfc_ctx *ctx)
 {
-       unsigned int frame_size, i;
+       unsigned int frame_size_lu, i;
        unsigned int frame_size_ch, frame_size_mv;
        struct s5p_mfc_dev *dev = ctx->dev;
        unsigned int dpb;
@@ -465,23 +466,23 @@ static int s5p_mfc_set_dec_frame_buffer_v5(struct s5p_mfc_ctx *ctx)
                        ctx->codec_mode);
                return -EINVAL;
        }
-       frame_size = ctx->luma_size;
+       frame_size_lu = ctx->luma_size;
        frame_size_ch = ctx->chroma_size;
        frame_size_mv = ctx->mv_size;
-       mfc_debug(2, "Frm size: %d ch: %d mv: %d\n", frame_size, frame_size_ch,
+       mfc_debug(2, "Frm size: %d ch: %d mv: %d\n", frame_size_lu, frame_size_ch,
                                                                frame_size_mv);
        for (i = 0; i < ctx->total_dpb_count; i++) {
                /* Bank2 */
-               mfc_debug(2, "Luma %d: %x\n", i,
+               mfc_debug(2, "Luma %d: %zx\n", i,
                                        ctx->dst_bufs[i].cookie.raw.luma);
                mfc_write(dev, OFFSETB(ctx->dst_bufs[i].cookie.raw.luma),
                                                S5P_FIMV_DEC_LUMA_ADR + i * 4);
-               mfc_debug(2, "\tChroma %d: %x\n", i,
+               mfc_debug(2, "\tChroma %d: %zx\n", i,
                                        ctx->dst_bufs[i].cookie.raw.chroma);
                mfc_write(dev, OFFSETA(ctx->dst_bufs[i].cookie.raw.chroma),
                                               S5P_FIMV_DEC_CHROMA_ADR + i * 4);
                if (ctx->codec_mode == S5P_MFC_CODEC_H264_DEC) {
-                       mfc_debug(2, "\tBuf2: %x, size: %d\n",
+                       mfc_debug(2, "\tBuf2: %zx, size: %d\n",
                                                        buf_addr2, buf_size2);
                        mfc_write(dev, OFFSETB(buf_addr2),
                                                S5P_FIMV_H264_MV_ADR + i * 4);
@@ -489,14 +490,14 @@ static int s5p_mfc_set_dec_frame_buffer_v5(struct s5p_mfc_ctx *ctx)
                        buf_size2 -= frame_size_mv;
                }
        }
-       mfc_debug(2, "Buf1: %u, buf_size1: %d\n", buf_addr1, buf_size1);
+       mfc_debug(2, "Buf1: %zu, buf_size1: %d\n", buf_addr1, buf_size1);
        mfc_debug(2, "Buf 1/2 size after: %d/%d (frames %d)\n",
                        buf_size1,  buf_size2, ctx->total_dpb_count);
        if (buf_size1 < 0 || buf_size2 < 0) {
                mfc_debug(2, "Not enough memory has been allocated\n");
                return -ENOMEM;
        }
-       s5p_mfc_write_info_v5(ctx, frame_size, ALLOC_LUMA_DPB_SIZE);
+       s5p_mfc_write_info_v5(ctx, frame_size_lu, ALLOC_LUMA_DPB_SIZE);
        s5p_mfc_write_info_v5(ctx, frame_size_ch, ALLOC_CHROMA_DPB_SIZE);
        if (ctx->codec_mode == S5P_MFC_CODEC_H264_DEC)
                s5p_mfc_write_info_v5(ctx, frame_size_mv, ALLOC_MV_SIZE);
@@ -566,7 +567,7 @@ static int s5p_mfc_set_enc_ref_buffer_v5(struct s5p_mfc_ctx *ctx)
                enc_ref_c_size = ALIGN(guard_width * guard_height,
                                       S5P_FIMV_NV12MT_SALIGN);
        }
-       mfc_debug(2, "buf_size1: %d, buf_size2: %d\n", buf_size1, buf_size2);
+       mfc_debug(2, "buf_size1: %zu, buf_size2: %zu\n", buf_size1, buf_size2);
        switch (ctx->codec_mode) {
        case S5P_MFC_CODEC_H264_ENC:
                for (i = 0; i < 2; i++) {
@@ -605,7 +606,7 @@ static int s5p_mfc_set_enc_ref_buffer_v5(struct s5p_mfc_ctx *ctx)
                                        S5P_FIMV_H264_NBOR_INFO_ADR);
                buf_addr1 += S5P_FIMV_ENC_NBORINFO_SIZE;
                buf_size1 -= S5P_FIMV_ENC_NBORINFO_SIZE;
-               mfc_debug(2, "buf_size1: %d, buf_size2: %d\n",
+               mfc_debug(2, "buf_size1: %zu, buf_size2: %zu\n",
                        buf_size1, buf_size2);
                break;
        case S5P_MFC_CODEC_MPEG4_ENC:
@@ -636,7 +637,7 @@ static int s5p_mfc_set_enc_ref_buffer_v5(struct s5p_mfc_ctx *ctx)
                                                S5P_FIMV_MPEG4_ACDC_COEF_ADR);
                buf_addr1 += S5P_FIMV_ENC_ACDCCOEF_SIZE;
                buf_size1 -= S5P_FIMV_ENC_ACDCCOEF_SIZE;
-               mfc_debug(2, "buf_size1: %d, buf_size2: %d\n",
+               mfc_debug(2, "buf_size1: %zu, buf_size2: %zu\n",
                        buf_size1, buf_size2);
                break;
        case S5P_MFC_CODEC_H263_ENC:
@@ -662,7 +663,7 @@ static int s5p_mfc_set_enc_ref_buffer_v5(struct s5p_mfc_ctx *ctx)
                mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_H263_ACDC_COEF_ADR);
                buf_addr1 += S5P_FIMV_ENC_ACDCCOEF_SIZE;
                buf_size1 -= S5P_FIMV_ENC_ACDCCOEF_SIZE;
-               mfc_debug(2, "buf_size1: %d, buf_size2: %d\n",
+               mfc_debug(2, "buf_size1: %zu, buf_size2: %zu\n",
                        buf_size1, buf_size2);
                break;
        default:
@@ -1186,7 +1187,6 @@ static int s5p_mfc_run_dec_frame(struct s5p_mfc_ctx *ctx, int last_frame)
        struct s5p_mfc_dev *dev = ctx->dev;
        struct s5p_mfc_buf *temp_vb;
        unsigned long flags;
-       unsigned int index;
 
        if (ctx->state == MFCINST_FINISHING) {
                last_frame = MFC_DEC_LAST_FRAME;
@@ -1211,7 +1211,6 @@ static int s5p_mfc_run_dec_frame(struct s5p_mfc_ctx *ctx, int last_frame)
                vb2_dma_contig_plane_dma_addr(temp_vb->b, 0),
                ctx->consumed_stream, temp_vb->b->v4l2_planes[0].bytesused);
        spin_unlock_irqrestore(&dev->irqlock, flags);
-       index = temp_vb->b->v4l2_buf.index;
        dev->curr_ctx = ctx->num;
        s5p_mfc_clean_ctx_int_flags(ctx);
        if (temp_vb->b->v4l2_planes[0].bytesused == 0) {
index c1c12f8d8f68055352ccc3ef271524ec4d171beb..8798b14bacce8f1e85a658b578728a9976a549f0 100644 (file)
        } while (0)
 #endif /* S5P_MFC_DEBUG_REGWRITE */
 
-#define READL(reg) \
-       (WARN_ON_ONCE(!(reg)) ? 0 : readl(reg))
-#define WRITEL(data, reg) \
-       (WARN_ON_ONCE(!(reg)) ? 0 : writel((data), (reg)))
-
 #define IS_MFCV6_V2(dev) (!IS_MFCV7_PLUS(dev) && dev->fw_ver == MFC_FW_V2)
 
 /* Allocate temporary buffers for decoding */
@@ -105,7 +100,7 @@ static int s5p_mfc_alloc_codec_buffers_v6(struct s5p_mfc_ctx *ctx)
                                                mb_width, mb_height),
                                                S5P_FIMV_ME_BUFFER_ALIGN_V6);
 
-               mfc_debug(2, "recon luma size: %d chroma size: %d\n",
+               mfc_debug(2, "recon luma size: %zu chroma size: %zu\n",
                          ctx->luma_dpb_size, ctx->chroma_dpb_size);
        } else {
                return -EINVAL;
@@ -416,10 +411,10 @@ static int s5p_mfc_set_dec_stream_buffer_v6(struct s5p_mfc_ctx *ctx,
        mfc_debug(2, "inst_no: %d, buf_addr: 0x%08x,\n"
                "buf_size: 0x%08x (%d)\n",
                ctx->inst_no, buf_addr, strm_size, strm_size);
-       WRITEL(strm_size, mfc_regs->d_stream_data_size);
-       WRITEL(buf_addr, mfc_regs->d_cpb_buffer_addr);
-       WRITEL(buf_size->cpb, mfc_regs->d_cpb_buffer_size);
-       WRITEL(start_num_byte, mfc_regs->d_cpb_buffer_offset);
+       writel(strm_size, mfc_regs->d_stream_data_size);
+       writel(buf_addr, mfc_regs->d_cpb_buffer_addr);
+       writel(buf_size->cpb, mfc_regs->d_cpb_buffer_size);
+       writel(start_num_byte, mfc_regs->d_cpb_buffer_offset);
 
        mfc_debug_leave();
        return 0;
@@ -443,17 +438,17 @@ static int s5p_mfc_set_dec_frame_buffer_v6(struct s5p_mfc_ctx *ctx)
        mfc_debug(2, "Total DPB COUNT: %d\n", ctx->total_dpb_count);
        mfc_debug(2, "Setting display delay to %d\n", ctx->display_delay);
 
-       WRITEL(ctx->total_dpb_count, mfc_regs->d_num_dpb);
-       WRITEL(ctx->luma_size, mfc_regs->d_first_plane_dpb_size);
-       WRITEL(ctx->chroma_size, mfc_regs->d_second_plane_dpb_size);
+       writel(ctx->total_dpb_count, mfc_regs->d_num_dpb);
+       writel(ctx->luma_size, mfc_regs->d_first_plane_dpb_size);
+       writel(ctx->chroma_size, mfc_regs->d_second_plane_dpb_size);
 
-       WRITEL(buf_addr1, mfc_regs->d_scratch_buffer_addr);
-       WRITEL(ctx->scratch_buf_size, mfc_regs->d_scratch_buffer_size);
+       writel(buf_addr1, mfc_regs->d_scratch_buffer_addr);
+       writel(ctx->scratch_buf_size, mfc_regs->d_scratch_buffer_size);
 
        if (IS_MFCV8(dev)) {
-               WRITEL(ctx->img_width,
+               writel(ctx->img_width,
                        mfc_regs->d_first_plane_dpb_stride_size);
-               WRITEL(ctx->img_width,
+               writel(ctx->img_width,
                        mfc_regs->d_second_plane_dpb_stride_size);
        }
 
@@ -462,8 +457,8 @@ static int s5p_mfc_set_dec_frame_buffer_v6(struct s5p_mfc_ctx *ctx)
 
        if (ctx->codec_mode == S5P_FIMV_CODEC_H264_DEC ||
                        ctx->codec_mode == S5P_FIMV_CODEC_H264_MVC_DEC){
-               WRITEL(ctx->mv_size, mfc_regs->d_mv_buffer_size);
-               WRITEL(ctx->mv_count, mfc_regs->d_num_mv);
+               writel(ctx->mv_size, mfc_regs->d_mv_buffer_size);
+               writel(ctx->mv_count, mfc_regs->d_num_mv);
        }
 
        frame_size = ctx->luma_size;
@@ -474,13 +469,13 @@ static int s5p_mfc_set_dec_frame_buffer_v6(struct s5p_mfc_ctx *ctx)
 
        for (i = 0; i < ctx->total_dpb_count; i++) {
                /* Bank2 */
-               mfc_debug(2, "Luma %d: %x\n", i,
+               mfc_debug(2, "Luma %d: %zx\n", i,
                                        ctx->dst_bufs[i].cookie.raw.luma);
-               WRITEL(ctx->dst_bufs[i].cookie.raw.luma,
+               writel(ctx->dst_bufs[i].cookie.raw.luma,
                                mfc_regs->d_first_plane_dpb + i * 4);
-               mfc_debug(2, "\tChroma %d: %x\n", i,
+               mfc_debug(2, "\tChroma %d: %zx\n", i,
                                        ctx->dst_bufs[i].cookie.raw.chroma);
-               WRITEL(ctx->dst_bufs[i].cookie.raw.chroma,
+               writel(ctx->dst_bufs[i].cookie.raw.chroma,
                                mfc_regs->d_second_plane_dpb + i * 4);
        }
        if (ctx->codec_mode == S5P_MFC_CODEC_H264_DEC ||
@@ -492,23 +487,23 @@ static int s5p_mfc_set_dec_frame_buffer_v6(struct s5p_mfc_ctx *ctx)
                        align_gap = buf_addr1 - align_gap;
                        buf_size1 -= align_gap;
 
-                       mfc_debug(2, "\tBuf1: %x, size: %d\n",
+                       mfc_debug(2, "\tBuf1: %zx, size: %d\n",
                                        buf_addr1, buf_size1);
-                       WRITEL(buf_addr1, mfc_regs->d_mv_buffer + i * 4);
+                       writel(buf_addr1, mfc_regs->d_mv_buffer + i * 4);
                        buf_addr1 += frame_size_mv;
                        buf_size1 -= frame_size_mv;
                }
        }
 
-       mfc_debug(2, "Buf1: %u, buf_size1: %d (frames %d)\n",
+       mfc_debug(2, "Buf1: %zu, buf_size1: %d (frames %d)\n",
                        buf_addr1, buf_size1, ctx->total_dpb_count);
        if (buf_size1 < 0) {
                mfc_debug(2, "Not enough memory has been allocated.\n");
                return -ENOMEM;
        }
 
-       WRITEL(ctx->inst_no, mfc_regs->instance_id);
-       s5p_mfc_hw_call(dev->mfc_cmds, cmd_host2risc, dev,
+       writel(ctx->inst_no, mfc_regs->instance_id);
+       s5p_mfc_hw_call_void(dev->mfc_cmds, cmd_host2risc, dev,
                        S5P_FIMV_CH_INIT_BUFS_V6, NULL);
 
        mfc_debug(2, "After setting buffers.\n");
@@ -522,8 +517,8 @@ static int s5p_mfc_set_enc_stream_buffer_v6(struct s5p_mfc_ctx *ctx,
        struct s5p_mfc_dev *dev = ctx->dev;
        const struct s5p_mfc_regs *mfc_regs = dev->mfc_regs;
 
-       WRITEL(addr, mfc_regs->e_stream_buffer_addr); /* 16B align */
-       WRITEL(size, mfc_regs->e_stream_buffer_size);
+       writel(addr, mfc_regs->e_stream_buffer_addr); /* 16B align */
+       writel(size, mfc_regs->e_stream_buffer_size);
 
        mfc_debug(2, "stream buf addr: 0x%08lx, size: 0x%d\n",
                  addr, size);
@@ -537,8 +532,8 @@ static void s5p_mfc_set_enc_frame_buffer_v6(struct s5p_mfc_ctx *ctx,
        struct s5p_mfc_dev *dev = ctx->dev;
        const struct s5p_mfc_regs *mfc_regs = dev->mfc_regs;
 
-       WRITEL(y_addr, mfc_regs->e_source_first_plane_addr);
-       WRITEL(c_addr, mfc_regs->e_source_second_plane_addr);
+       writel(y_addr, mfc_regs->e_source_first_plane_addr);
+       writel(c_addr, mfc_regs->e_source_second_plane_addr);
 
        mfc_debug(2, "enc src y buf addr: 0x%08lx\n", y_addr);
        mfc_debug(2, "enc src c buf addr: 0x%08lx\n", c_addr);
@@ -551,11 +546,11 @@ static void s5p_mfc_get_enc_frame_buffer_v6(struct s5p_mfc_ctx *ctx,
        const struct s5p_mfc_regs *mfc_regs = dev->mfc_regs;
        unsigned long enc_recon_y_addr, enc_recon_c_addr;
 
-       *y_addr = READL(mfc_regs->e_encoded_source_first_plane_addr);
-       *c_addr = READL(mfc_regs->e_encoded_source_second_plane_addr);
+       *y_addr = readl(mfc_regs->e_encoded_source_first_plane_addr);
+       *c_addr = readl(mfc_regs->e_encoded_source_second_plane_addr);
 
-       enc_recon_y_addr = READL(mfc_regs->e_recon_luma_dpb_addr);
-       enc_recon_c_addr = READL(mfc_regs->e_recon_chroma_dpb_addr);
+       enc_recon_y_addr = readl(mfc_regs->e_recon_luma_dpb_addr);
+       enc_recon_c_addr = readl(mfc_regs->e_recon_chroma_dpb_addr);
 
        mfc_debug(2, "recon y addr: 0x%08lx\n", enc_recon_y_addr);
        mfc_debug(2, "recon c addr: 0x%08lx\n", enc_recon_c_addr);
@@ -577,36 +572,36 @@ static int s5p_mfc_set_enc_ref_buffer_v6(struct s5p_mfc_ctx *ctx)
        mfc_debug(2, "Buf1: %p (%d)\n", (void *)buf_addr1, buf_size1);
 
        for (i = 0; i < ctx->pb_count; i++) {
-               WRITEL(buf_addr1, mfc_regs->e_luma_dpb + (4 * i));
+               writel(buf_addr1, mfc_regs->e_luma_dpb + (4 * i));
                buf_addr1 += ctx->luma_dpb_size;
-               WRITEL(buf_addr1, mfc_regs->e_chroma_dpb + (4 * i));
+               writel(buf_addr1, mfc_regs->e_chroma_dpb + (4 * i));
                buf_addr1 += ctx->chroma_dpb_size;
-               WRITEL(buf_addr1, mfc_regs->e_me_buffer + (4 * i));
+               writel(buf_addr1, mfc_regs->e_me_buffer + (4 * i));
                buf_addr1 += ctx->me_buffer_size;
                buf_size1 -= (ctx->luma_dpb_size + ctx->chroma_dpb_size +
                        ctx->me_buffer_size);
        }
 
-       WRITEL(buf_addr1, mfc_regs->e_scratch_buffer_addr);
-       WRITEL(ctx->scratch_buf_size, mfc_regs->e_scratch_buffer_size);
+       writel(buf_addr1, mfc_regs->e_scratch_buffer_addr);
+       writel(ctx->scratch_buf_size, mfc_regs->e_scratch_buffer_size);
        buf_addr1 += ctx->scratch_buf_size;
        buf_size1 -= ctx->scratch_buf_size;
 
-       WRITEL(buf_addr1, mfc_regs->e_tmv_buffer0);
+       writel(buf_addr1, mfc_regs->e_tmv_buffer0);
        buf_addr1 += ctx->tmv_buffer_size >> 1;
-       WRITEL(buf_addr1, mfc_regs->e_tmv_buffer1);
+       writel(buf_addr1, mfc_regs->e_tmv_buffer1);
        buf_addr1 += ctx->tmv_buffer_size >> 1;
        buf_size1 -= ctx->tmv_buffer_size;
 
-       mfc_debug(2, "Buf1: %u, buf_size1: %d (ref frames %d)\n",
+       mfc_debug(2, "Buf1: %zu, buf_size1: %d (ref frames %d)\n",
                        buf_addr1, buf_size1, ctx->pb_count);
        if (buf_size1 < 0) {
                mfc_debug(2, "Not enough memory has been allocated.\n");
                return -ENOMEM;
        }
 
-       WRITEL(ctx->inst_no, mfc_regs->instance_id);
-       s5p_mfc_hw_call(dev->mfc_cmds, cmd_host2risc, dev,
+       writel(ctx->inst_no, mfc_regs->instance_id);
+       s5p_mfc_hw_call_void(dev->mfc_cmds, cmd_host2risc, dev,
                        S5P_FIMV_CH_INIT_BUFS_V6, NULL);
 
        mfc_debug_leave();
@@ -621,15 +616,15 @@ static int s5p_mfc_set_slice_mode(struct s5p_mfc_ctx *ctx)
 
        /* multi-slice control */
        /* multi-slice MB number or bit size */
-       WRITEL(ctx->slice_mode, mfc_regs->e_mslice_mode);
+       writel(ctx->slice_mode, mfc_regs->e_mslice_mode);
        if (ctx->slice_mode == V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_MB) {
-               WRITEL(ctx->slice_size.mb, mfc_regs->e_mslice_size_mb);
+               writel(ctx->slice_size.mb, mfc_regs->e_mslice_size_mb);
        } else if (ctx->slice_mode ==
                        V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_BYTES) {
-               WRITEL(ctx->slice_size.bits, mfc_regs->e_mslice_size_bits);
+               writel(ctx->slice_size.bits, mfc_regs->e_mslice_size_bits);
        } else {
-               WRITEL(0x0, mfc_regs->e_mslice_size_mb);
-               WRITEL(0x0, mfc_regs->e_mslice_size_bits);
+               writel(0x0, mfc_regs->e_mslice_size_mb);
+               writel(0x0, mfc_regs->e_mslice_size_bits);
        }
 
        return 0;
@@ -645,21 +640,21 @@ static int s5p_mfc_set_enc_params(struct s5p_mfc_ctx *ctx)
        mfc_debug_enter();
 
        /* width */
-       WRITEL(ctx->img_width, mfc_regs->e_frame_width); /* 16 align */
+       writel(ctx->img_width, mfc_regs->e_frame_width); /* 16 align */
        /* height */
-       WRITEL(ctx->img_height, mfc_regs->e_frame_height); /* 16 align */
+       writel(ctx->img_height, mfc_regs->e_frame_height); /* 16 align */
 
        /* cropped width */
-       WRITEL(ctx->img_width, mfc_regs->e_cropped_frame_width);
+       writel(ctx->img_width, mfc_regs->e_cropped_frame_width);
        /* cropped height */
-       WRITEL(ctx->img_height, mfc_regs->e_cropped_frame_height);
+       writel(ctx->img_height, mfc_regs->e_cropped_frame_height);
        /* cropped offset */
-       WRITEL(0x0, mfc_regs->e_frame_crop_offset);
+       writel(0x0, mfc_regs->e_frame_crop_offset);
 
        /* pictype : IDR period */
        reg = 0;
        reg |= p->gop_size & 0xFFFF;
-       WRITEL(reg, mfc_regs->e_gop_config);
+       writel(reg, mfc_regs->e_gop_config);
 
        /* multi-slice control */
        /* multi-slice MB number or bit size */
@@ -667,65 +662,65 @@ static int s5p_mfc_set_enc_params(struct s5p_mfc_ctx *ctx)
        reg = 0;
        if (p->slice_mode == V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_MB) {
                reg |= (0x1 << 3);
-               WRITEL(reg, mfc_regs->e_enc_options);
+               writel(reg, mfc_regs->e_enc_options);
                ctx->slice_size.mb = p->slice_mb;
        } else if (p->slice_mode == V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_BYTES) {
                reg |= (0x1 << 3);
-               WRITEL(reg, mfc_regs->e_enc_options);
+               writel(reg, mfc_regs->e_enc_options);
                ctx->slice_size.bits = p->slice_bit;
        } else {
                reg &= ~(0x1 << 3);
-               WRITEL(reg, mfc_regs->e_enc_options);
+               writel(reg, mfc_regs->e_enc_options);
        }
 
        s5p_mfc_set_slice_mode(ctx);
 
        /* cyclic intra refresh */
-       WRITEL(p->intra_refresh_mb, mfc_regs->e_ir_size);
-       reg = READL(mfc_regs->e_enc_options);
+       writel(p->intra_refresh_mb, mfc_regs->e_ir_size);
+       reg = readl(mfc_regs->e_enc_options);
        if (p->intra_refresh_mb == 0)
                reg &= ~(0x1 << 4);
        else
                reg |= (0x1 << 4);
-       WRITEL(reg, mfc_regs->e_enc_options);
+       writel(reg, mfc_regs->e_enc_options);
 
        /* 'NON_REFERENCE_STORE_ENABLE' for debugging */
-       reg = READL(mfc_regs->e_enc_options);
+       reg = readl(mfc_regs->e_enc_options);
        reg &= ~(0x1 << 9);
-       WRITEL(reg, mfc_regs->e_enc_options);
+       writel(reg, mfc_regs->e_enc_options);
 
        /* memory structure cur. frame */
        if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_NV12M) {
                /* 0: Linear, 1: 2D tiled*/
-               reg = READL(mfc_regs->e_enc_options);
+               reg = readl(mfc_regs->e_enc_options);
                reg &= ~(0x1 << 7);
-               WRITEL(reg, mfc_regs->e_enc_options);
+               writel(reg, mfc_regs->e_enc_options);
                /* 0: NV12(CbCr), 1: NV21(CrCb) */
-               WRITEL(0x0, mfc_regs->pixel_format);
+               writel(0x0, mfc_regs->pixel_format);
        } else if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_NV21M) {
                /* 0: Linear, 1: 2D tiled*/
-               reg = READL(mfc_regs->e_enc_options);
+               reg = readl(mfc_regs->e_enc_options);
                reg &= ~(0x1 << 7);
-               WRITEL(reg, mfc_regs->e_enc_options);
+               writel(reg, mfc_regs->e_enc_options);
                /* 0: NV12(CbCr), 1: NV21(CrCb) */
-               WRITEL(0x1, mfc_regs->pixel_format);
+               writel(0x1, mfc_regs->pixel_format);
        } else if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_NV12MT_16X16) {
                /* 0: Linear, 1: 2D tiled*/
-               reg = READL(mfc_regs->e_enc_options);
+               reg = readl(mfc_regs->e_enc_options);
                reg |= (0x1 << 7);
-               WRITEL(reg, mfc_regs->e_enc_options);
+               writel(reg, mfc_regs->e_enc_options);
                /* 0: NV12(CbCr), 1: NV21(CrCb) */
-               WRITEL(0x0, mfc_regs->pixel_format);
+               writel(0x0, mfc_regs->pixel_format);
        }
 
        /* memory structure recon. frame */
        /* 0: Linear, 1: 2D tiled */
-       reg = READL(mfc_regs->e_enc_options);
+       reg = readl(mfc_regs->e_enc_options);
        reg |= (0x1 << 8);
-       WRITEL(reg, mfc_regs->e_enc_options);
+       writel(reg, mfc_regs->e_enc_options);
 
        /* padding control & value */
-       WRITEL(0x0, mfc_regs->e_padding_ctrl);
+       writel(0x0, mfc_regs->e_padding_ctrl);
        if (p->pad) {
                reg = 0;
                /** enable */
@@ -736,64 +731,64 @@ static int s5p_mfc_set_enc_params(struct s5p_mfc_ctx *ctx)
                reg |= ((p->pad_cb & 0xFF) << 8);
                /** y value */
                reg |= p->pad_luma & 0xFF;
-               WRITEL(reg, mfc_regs->e_padding_ctrl);
+               writel(reg, mfc_regs->e_padding_ctrl);
        }
 
        /* rate control config. */
        reg = 0;
        /* frame-level rate control */
        reg |= ((p->rc_frame & 0x1) << 9);
-       WRITEL(reg, mfc_regs->e_rc_config);
+       writel(reg, mfc_regs->e_rc_config);
 
        /* bit rate */
        if (p->rc_frame)
-               WRITEL(p->rc_bitrate,
+               writel(p->rc_bitrate,
                        mfc_regs->e_rc_bit_rate);
        else
-               WRITEL(1, mfc_regs->e_rc_bit_rate);
+               writel(1, mfc_regs->e_rc_bit_rate);
 
        /* reaction coefficient */
        if (p->rc_frame) {
                if (p->rc_reaction_coeff < TIGHT_CBR_MAX) /* tight CBR */
-                       WRITEL(1, mfc_regs->e_rc_mode);
+                       writel(1, mfc_regs->e_rc_mode);
                else                                      /* loose CBR */
-                       WRITEL(2, mfc_regs->e_rc_mode);
+                       writel(2, mfc_regs->e_rc_mode);
        }
 
        /* seq header ctrl */
-       reg = READL(mfc_regs->e_enc_options);
+       reg = readl(mfc_regs->e_enc_options);
        reg &= ~(0x1 << 2);
        reg |= ((p->seq_hdr_mode & 0x1) << 2);
 
        /* frame skip mode */
        reg &= ~(0x3);
        reg |= (p->frame_skip_mode & 0x3);
-       WRITEL(reg, mfc_regs->e_enc_options);
+       writel(reg, mfc_regs->e_enc_options);
 
        /* 'DROP_CONTROL_ENABLE', disable */
-       reg = READL(mfc_regs->e_rc_config);
+       reg = readl(mfc_regs->e_rc_config);
        reg &= ~(0x1 << 10);
-       WRITEL(reg, mfc_regs->e_rc_config);
+       writel(reg, mfc_regs->e_rc_config);
 
        /* setting for MV range [16, 256] */
        reg = (p->mv_h_range & S5P_FIMV_E_MV_RANGE_V6_MASK);
-       WRITEL(reg, mfc_regs->e_mv_hor_range);
+       writel(reg, mfc_regs->e_mv_hor_range);
 
        reg = (p->mv_v_range & S5P_FIMV_E_MV_RANGE_V6_MASK);
-       WRITEL(reg, mfc_regs->e_mv_ver_range);
+       writel(reg, mfc_regs->e_mv_ver_range);
 
-       WRITEL(0x0, mfc_regs->e_frame_insertion);
-       WRITEL(0x0, mfc_regs->e_roi_buffer_addr);
-       WRITEL(0x0, mfc_regs->e_param_change);
-       WRITEL(0x0, mfc_regs->e_rc_roi_ctrl);
-       WRITEL(0x0, mfc_regs->e_picture_tag);
+       writel(0x0, mfc_regs->e_frame_insertion);
+       writel(0x0, mfc_regs->e_roi_buffer_addr);
+       writel(0x0, mfc_regs->e_param_change);
+       writel(0x0, mfc_regs->e_rc_roi_ctrl);
+       writel(0x0, mfc_regs->e_picture_tag);
 
-       WRITEL(0x0, mfc_regs->e_bit_count_enable);
-       WRITEL(0x0, mfc_regs->e_max_bit_count);
-       WRITEL(0x0, mfc_regs->e_min_bit_count);
+       writel(0x0, mfc_regs->e_bit_count_enable);
+       writel(0x0, mfc_regs->e_max_bit_count);
+       writel(0x0, mfc_regs->e_min_bit_count);
 
-       WRITEL(0x0, mfc_regs->e_metadata_buffer_addr);
-       WRITEL(0x0, mfc_regs->e_metadata_buffer_size);
+       writel(0x0, mfc_regs->e_metadata_buffer_addr);
+       writel(0x0, mfc_regs->e_metadata_buffer_size);
 
        mfc_debug_leave();
 
@@ -814,10 +809,10 @@ static int s5p_mfc_set_enc_params_h264(struct s5p_mfc_ctx *ctx)
        s5p_mfc_set_enc_params(ctx);
 
        /* pictype : number of B */
-       reg = READL(mfc_regs->e_gop_config);
+       reg = readl(mfc_regs->e_gop_config);
        reg &= ~(0x3 << 16);
        reg |= ((p->num_b_frame & 0x3) << 16);
-       WRITEL(reg, mfc_regs->e_gop_config);
+       writel(reg, mfc_regs->e_gop_config);
 
        /* profile & level */
        reg = 0;
@@ -825,19 +820,19 @@ static int s5p_mfc_set_enc_params_h264(struct s5p_mfc_ctx *ctx)
        reg |= ((p_h264->level & 0xFF) << 8);
        /** profile - 0 ~ 3 */
        reg |= p_h264->profile & 0x3F;
-       WRITEL(reg, mfc_regs->e_picture_profile);
+       writel(reg, mfc_regs->e_picture_profile);
 
        /* rate control config. */
-       reg = READL(mfc_regs->e_rc_config);
+       reg = readl(mfc_regs->e_rc_config);
        /** macroblock level rate control */
        reg &= ~(0x1 << 8);
        reg |= ((p->rc_mb & 0x1) << 8);
-       WRITEL(reg, mfc_regs->e_rc_config);
+       writel(reg, mfc_regs->e_rc_config);
 
        /** frame QP */
        reg &= ~(0x3F);
        reg |= p_h264->rc_frame_qp & 0x3F;
-       WRITEL(reg, mfc_regs->e_rc_config);
+       writel(reg, mfc_regs->e_rc_config);
 
        /* max & min value of QP */
        reg = 0;
@@ -845,16 +840,16 @@ static int s5p_mfc_set_enc_params_h264(struct s5p_mfc_ctx *ctx)
        reg |= ((p_h264->rc_max_qp & 0x3F) << 8);
        /** min QP */
        reg |= p_h264->rc_min_qp & 0x3F;
-       WRITEL(reg, mfc_regs->e_rc_qp_bound);
+       writel(reg, mfc_regs->e_rc_qp_bound);
 
        /* other QPs */
-       WRITEL(0x0, mfc_regs->e_fixed_picture_qp);
+       writel(0x0, mfc_regs->e_fixed_picture_qp);
        if (!p->rc_frame && !p->rc_mb) {
                reg = 0;
                reg |= ((p_h264->rc_b_frame_qp & 0x3F) << 16);
                reg |= ((p_h264->rc_p_frame_qp & 0x3F) << 8);
                reg |= p_h264->rc_frame_qp & 0x3F;
-               WRITEL(reg, mfc_regs->e_fixed_picture_qp);
+               writel(reg, mfc_regs->e_fixed_picture_qp);
        }
 
        /* frame rate */
@@ -862,38 +857,38 @@ static int s5p_mfc_set_enc_params_h264(struct s5p_mfc_ctx *ctx)
                reg = 0;
                reg |= ((p->rc_framerate_num & 0xFFFF) << 16);
                reg |= p->rc_framerate_denom & 0xFFFF;
-               WRITEL(reg, mfc_regs->e_rc_frame_rate);
+               writel(reg, mfc_regs->e_rc_frame_rate);
        }
 
        /* vbv buffer size */
        if (p->frame_skip_mode ==
                        V4L2_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE_BUF_LIMIT) {
-               WRITEL(p_h264->cpb_size & 0xFFFF,
+               writel(p_h264->cpb_size & 0xFFFF,
                                mfc_regs->e_vbv_buffer_size);
 
                if (p->rc_frame)
-                       WRITEL(p->vbv_delay, mfc_regs->e_vbv_init_delay);
+                       writel(p->vbv_delay, mfc_regs->e_vbv_init_delay);
        }
 
        /* interlace */
        reg = 0;
        reg |= ((p_h264->interlace & 0x1) << 3);
-       WRITEL(reg, mfc_regs->e_h264_options);
+       writel(reg, mfc_regs->e_h264_options);
 
        /* height */
        if (p_h264->interlace) {
-               WRITEL(ctx->img_height >> 1,
+               writel(ctx->img_height >> 1,
                                mfc_regs->e_frame_height); /* 32 align */
                /* cropped height */
-               WRITEL(ctx->img_height >> 1,
+               writel(ctx->img_height >> 1,
                                mfc_regs->e_cropped_frame_height);
        }
 
        /* loop filter ctrl */
-       reg = READL(mfc_regs->e_h264_options);
+       reg = readl(mfc_regs->e_h264_options);
        reg &= ~(0x3 << 1);
        reg |= ((p_h264->loop_filter_mode & 0x3) << 1);
-       WRITEL(reg, mfc_regs->e_h264_options);
+       writel(reg, mfc_regs->e_h264_options);
 
        /* loopfilter alpha offset */
        if (p_h264->loop_filter_alpha < 0) {
@@ -903,7 +898,7 @@ static int s5p_mfc_set_enc_params_h264(struct s5p_mfc_ctx *ctx)
                reg = 0x00;
                reg |= (p_h264->loop_filter_alpha & 0xF);
        }
-       WRITEL(reg, mfc_regs->e_h264_lf_alpha_offset);
+       writel(reg, mfc_regs->e_h264_lf_alpha_offset);
 
        /* loopfilter beta offset */
        if (p_h264->loop_filter_beta < 0) {
@@ -913,28 +908,28 @@ static int s5p_mfc_set_enc_params_h264(struct s5p_mfc_ctx *ctx)
                reg = 0x00;
                reg |= (p_h264->loop_filter_beta & 0xF);
        }
-       WRITEL(reg, mfc_regs->e_h264_lf_beta_offset);
+       writel(reg, mfc_regs->e_h264_lf_beta_offset);
 
        /* entropy coding mode */
-       reg = READL(mfc_regs->e_h264_options);
+       reg = readl(mfc_regs->e_h264_options);
        reg &= ~(0x1);
        reg |= p_h264->entropy_mode & 0x1;
-       WRITEL(reg, mfc_regs->e_h264_options);
+       writel(reg, mfc_regs->e_h264_options);
 
        /* number of ref. picture */
-       reg = READL(mfc_regs->e_h264_options);
+       reg = readl(mfc_regs->e_h264_options);
        reg &= ~(0x1 << 7);
        reg |= (((p_h264->num_ref_pic_4p - 1) & 0x1) << 7);
-       WRITEL(reg, mfc_regs->e_h264_options);
+       writel(reg, mfc_regs->e_h264_options);
 
        /* 8x8 transform enable */
-       reg = READL(mfc_regs->e_h264_options);
+       reg = readl(mfc_regs->e_h264_options);
        reg &= ~(0x3 << 12);
        reg |= ((p_h264->_8x8_transform & 0x3) << 12);
-       WRITEL(reg, mfc_regs->e_h264_options);
+       writel(reg, mfc_regs->e_h264_options);
 
        /* macroblock adaptive scaling features */
-       WRITEL(0x0, mfc_regs->e_mb_rc_config);
+       writel(0x0, mfc_regs->e_mb_rc_config);
        if (p->rc_mb) {
                reg = 0;
                /** dark region */
@@ -945,95 +940,95 @@ static int s5p_mfc_set_enc_params_h264(struct s5p_mfc_ctx *ctx)
                reg |= ((p_h264->rc_mb_static & 0x1) << 1);
                /** high activity region */
                reg |= p_h264->rc_mb_activity & 0x1;
-               WRITEL(reg, mfc_regs->e_mb_rc_config);
+               writel(reg, mfc_regs->e_mb_rc_config);
        }
 
        /* aspect ratio VUI */
-       READL(mfc_regs->e_h264_options);
+       readl(mfc_regs->e_h264_options);
        reg &= ~(0x1 << 5);
        reg |= ((p_h264->vui_sar & 0x1) << 5);
-       WRITEL(reg, mfc_regs->e_h264_options);
+       writel(reg, mfc_regs->e_h264_options);
 
-       WRITEL(0x0, mfc_regs->e_aspect_ratio);
-       WRITEL(0x0, mfc_regs->e_extended_sar);
+       writel(0x0, mfc_regs->e_aspect_ratio);
+       writel(0x0, mfc_regs->e_extended_sar);
        if (p_h264->vui_sar) {
                /* aspect ration IDC */
                reg = 0;
                reg |= p_h264->vui_sar_idc & 0xFF;
-               WRITEL(reg, mfc_regs->e_aspect_ratio);
+               writel(reg, mfc_regs->e_aspect_ratio);
                if (p_h264->vui_sar_idc == 0xFF) {
                        /* extended SAR */
                        reg = 0;
                        reg |= (p_h264->vui_ext_sar_width & 0xFFFF) << 16;
                        reg |= p_h264->vui_ext_sar_height & 0xFFFF;
-                       WRITEL(reg, mfc_regs->e_extended_sar);
+                       writel(reg, mfc_regs->e_extended_sar);
                }
        }
 
        /* intra picture period for H.264 open GOP */
        /* control */
-       READL(mfc_regs->e_h264_options);
+       readl(mfc_regs->e_h264_options);
        reg &= ~(0x1 << 4);
        reg |= ((p_h264->open_gop & 0x1) << 4);
-       WRITEL(reg, mfc_regs->e_h264_options);
+       writel(reg, mfc_regs->e_h264_options);
 
        /* value */
-       WRITEL(0x0, mfc_regs->e_h264_i_period);
+       writel(0x0, mfc_regs->e_h264_i_period);
        if (p_h264->open_gop) {
                reg = 0;
                reg |= p_h264->open_gop_size & 0xFFFF;
-               WRITEL(reg, mfc_regs->e_h264_i_period);
+               writel(reg, mfc_regs->e_h264_i_period);
        }
 
        /* 'WEIGHTED_BI_PREDICTION' for B is disable */
-       READL(mfc_regs->e_h264_options);
+       readl(mfc_regs->e_h264_options);
        reg &= ~(0x3 << 9);
-       WRITEL(reg, mfc_regs->e_h264_options);
+       writel(reg, mfc_regs->e_h264_options);
 
        /* 'CONSTRAINED_INTRA_PRED_ENABLE' is disable */
-       READL(mfc_regs->e_h264_options);
+       readl(mfc_regs->e_h264_options);
        reg &= ~(0x1 << 14);
-       WRITEL(reg, mfc_regs->e_h264_options);
+       writel(reg, mfc_regs->e_h264_options);
 
        /* ASO */
-       READL(mfc_regs->e_h264_options);
+       readl(mfc_regs->e_h264_options);
        reg &= ~(0x1 << 6);
        reg |= ((p_h264->aso & 0x1) << 6);
-       WRITEL(reg, mfc_regs->e_h264_options);
+       writel(reg, mfc_regs->e_h264_options);
 
        /* hier qp enable */
-       READL(mfc_regs->e_h264_options);
+       readl(mfc_regs->e_h264_options);
        reg &= ~(0x1 << 8);
        reg |= ((p_h264->open_gop & 0x1) << 8);
-       WRITEL(reg, mfc_regs->e_h264_options);
+       writel(reg, mfc_regs->e_h264_options);
        reg = 0;
        if (p_h264->hier_qp && p_h264->hier_qp_layer) {
                reg |= (p_h264->hier_qp_type & 0x1) << 0x3;
                reg |= p_h264->hier_qp_layer & 0x7;
-               WRITEL(reg, mfc_regs->e_h264_num_t_layer);
+               writel(reg, mfc_regs->e_h264_num_t_layer);
                /* QP value for each layer */
                for (i = 0; i < p_h264->hier_qp_layer &&
                                i < ARRAY_SIZE(p_h264->hier_qp_layer_qp); i++) {
-                       WRITEL(p_h264->hier_qp_layer_qp[i],
+                       writel(p_h264->hier_qp_layer_qp[i],
                                mfc_regs->e_h264_hierarchical_qp_layer0
                                + i * 4);
                }
        }
        /* number of coding layer should be zero when hierarchical is disable */
-       WRITEL(reg, mfc_regs->e_h264_num_t_layer);
+       writel(reg, mfc_regs->e_h264_num_t_layer);
 
        /* frame packing SEI generation */
-       READL(mfc_regs->e_h264_options);
+       readl(mfc_regs->e_h264_options);
        reg &= ~(0x1 << 25);
        reg |= ((p_h264->sei_frame_packing & 0x1) << 25);
-       WRITEL(reg, mfc_regs->e_h264_options);
+       writel(reg, mfc_regs->e_h264_options);
        if (p_h264->sei_frame_packing) {
                reg = 0;
                /** current frame0 flag */
                reg |= ((p_h264->sei_fp_curr_frame_0 & 0x1) << 2);
                /** arrangement type */
                reg |= p_h264->sei_fp_arrangement_type & 0x3;
-               WRITEL(reg, mfc_regs->e_h264_frame_packing_sei_info);
+               writel(reg, mfc_regs->e_h264_frame_packing_sei_info);
        }
 
        if (p_h264->fmo) {
@@ -1042,7 +1037,7 @@ static int s5p_mfc_set_enc_params_h264(struct s5p_mfc_ctx *ctx)
                        if (p_h264->fmo_slice_grp > 4)
                                p_h264->fmo_slice_grp = 4;
                        for (i = 0; i < (p_h264->fmo_slice_grp & 0xF); i++)
-                               WRITEL(p_h264->fmo_run_len[i] - 1,
+                               writel(p_h264->fmo_run_len[i] - 1,
                                        mfc_regs->e_h264_fmo_run_length_minus1_0
                                        + i * 4);
                        break;
@@ -1054,10 +1049,10 @@ static int s5p_mfc_set_enc_params_h264(struct s5p_mfc_ctx *ctx)
                case V4L2_MPEG_VIDEO_H264_FMO_MAP_TYPE_WIPE_SCAN:
                        if (p_h264->fmo_slice_grp > 2)
                                p_h264->fmo_slice_grp = 2;
-                       WRITEL(p_h264->fmo_chg_dir & 0x1,
+                       writel(p_h264->fmo_chg_dir & 0x1,
                                mfc_regs->e_h264_fmo_slice_grp_change_dir);
                        /* the valid range is 0 ~ number of macroblocks -1 */
-                       WRITEL(p_h264->fmo_chg_rate,
+                       writel(p_h264->fmo_chg_rate,
                        mfc_regs->e_h264_fmo_slice_grp_change_rate_minus1);
                        break;
                default:
@@ -1068,12 +1063,12 @@ static int s5p_mfc_set_enc_params_h264(struct s5p_mfc_ctx *ctx)
                        break;
                }
 
-               WRITEL(p_h264->fmo_map_type,
+               writel(p_h264->fmo_map_type,
                                mfc_regs->e_h264_fmo_slice_grp_map_type);
-               WRITEL(p_h264->fmo_slice_grp - 1,
+               writel(p_h264->fmo_slice_grp - 1,
                                mfc_regs->e_h264_fmo_num_slice_grp_minus1);
        } else {
-               WRITEL(0, mfc_regs->e_h264_fmo_num_slice_grp_minus1);
+               writel(0, mfc_regs->e_h264_fmo_num_slice_grp_minus1);
        }
 
        mfc_debug_leave();
@@ -1094,10 +1089,10 @@ static int s5p_mfc_set_enc_params_mpeg4(struct s5p_mfc_ctx *ctx)
        s5p_mfc_set_enc_params(ctx);
 
        /* pictype : number of B */
-       reg = READL(mfc_regs->e_gop_config);
+       reg = readl(mfc_regs->e_gop_config);
        reg &= ~(0x3 << 16);
        reg |= ((p->num_b_frame & 0x3) << 16);
-       WRITEL(reg, mfc_regs->e_gop_config);
+       writel(reg, mfc_regs->e_gop_config);
 
        /* profile & level */
        reg = 0;
@@ -1105,19 +1100,19 @@ static int s5p_mfc_set_enc_params_mpeg4(struct s5p_mfc_ctx *ctx)
        reg |= ((p_mpeg4->level & 0xFF) << 8);
        /** profile - 0 ~ 1 */
        reg |= p_mpeg4->profile & 0x3F;
-       WRITEL(reg, mfc_regs->e_picture_profile);
+       writel(reg, mfc_regs->e_picture_profile);
 
        /* rate control config. */
-       reg = READL(mfc_regs->e_rc_config);
+       reg = readl(mfc_regs->e_rc_config);
        /** macroblock level rate control */
        reg &= ~(0x1 << 8);
        reg |= ((p->rc_mb & 0x1) << 8);
-       WRITEL(reg, mfc_regs->e_rc_config);
+       writel(reg, mfc_regs->e_rc_config);
 
        /** frame QP */
        reg &= ~(0x3F);
        reg |= p_mpeg4->rc_frame_qp & 0x3F;
-       WRITEL(reg, mfc_regs->e_rc_config);
+       writel(reg, mfc_regs->e_rc_config);
 
        /* max & min value of QP */
        reg = 0;
@@ -1125,16 +1120,16 @@ static int s5p_mfc_set_enc_params_mpeg4(struct s5p_mfc_ctx *ctx)
        reg |= ((p_mpeg4->rc_max_qp & 0x3F) << 8);
        /** min QP */
        reg |= p_mpeg4->rc_min_qp & 0x3F;
-       WRITEL(reg, mfc_regs->e_rc_qp_bound);
+       writel(reg, mfc_regs->e_rc_qp_bound);
 
        /* other QPs */
-       WRITEL(0x0, mfc_regs->e_fixed_picture_qp);
+       writel(0x0, mfc_regs->e_fixed_picture_qp);
        if (!p->rc_frame && !p->rc_mb) {
                reg = 0;
                reg |= ((p_mpeg4->rc_b_frame_qp & 0x3F) << 16);
                reg |= ((p_mpeg4->rc_p_frame_qp & 0x3F) << 8);
                reg |= p_mpeg4->rc_frame_qp & 0x3F;
-               WRITEL(reg, mfc_regs->e_fixed_picture_qp);
+               writel(reg, mfc_regs->e_fixed_picture_qp);
        }
 
        /* frame rate */
@@ -1142,21 +1137,21 @@ static int s5p_mfc_set_enc_params_mpeg4(struct s5p_mfc_ctx *ctx)
                reg = 0;
                reg |= ((p->rc_framerate_num & 0xFFFF) << 16);
                reg |= p->rc_framerate_denom & 0xFFFF;
-               WRITEL(reg, mfc_regs->e_rc_frame_rate);
+               writel(reg, mfc_regs->e_rc_frame_rate);
        }
 
        /* vbv buffer size */
        if (p->frame_skip_mode ==
                        V4L2_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE_BUF_LIMIT) {
-               WRITEL(p->vbv_size & 0xFFFF, mfc_regs->e_vbv_buffer_size);
+               writel(p->vbv_size & 0xFFFF, mfc_regs->e_vbv_buffer_size);
 
                if (p->rc_frame)
-                       WRITEL(p->vbv_delay, mfc_regs->e_vbv_init_delay);
+                       writel(p->vbv_delay, mfc_regs->e_vbv_init_delay);
        }
 
        /* Disable HEC */
-       WRITEL(0x0, mfc_regs->e_mpeg4_options);
-       WRITEL(0x0, mfc_regs->e_mpeg4_hec_period);
+       writel(0x0, mfc_regs->e_mpeg4_options);
+       writel(0x0, mfc_regs->e_mpeg4_hec_period);
 
        mfc_debug_leave();
 
@@ -1179,19 +1174,19 @@ static int s5p_mfc_set_enc_params_h263(struct s5p_mfc_ctx *ctx)
        reg = 0;
        /** profile */
        reg |= (0x1 << 4);
-       WRITEL(reg, mfc_regs->e_picture_profile);
+       writel(reg, mfc_regs->e_picture_profile);
 
        /* rate control config. */
-       reg = READL(mfc_regs->e_rc_config);
+       reg = readl(mfc_regs->e_rc_config);
        /** macroblock level rate control */
        reg &= ~(0x1 << 8);
        reg |= ((p->rc_mb & 0x1) << 8);
-       WRITEL(reg, mfc_regs->e_rc_config);
+       writel(reg, mfc_regs->e_rc_config);
 
        /** frame QP */
        reg &= ~(0x3F);
        reg |= p_h263->rc_frame_qp & 0x3F;
-       WRITEL(reg, mfc_regs->e_rc_config);
+       writel(reg, mfc_regs->e_rc_config);
 
        /* max & min value of QP */
        reg = 0;
@@ -1199,16 +1194,16 @@ static int s5p_mfc_set_enc_params_h263(struct s5p_mfc_ctx *ctx)
        reg |= ((p_h263->rc_max_qp & 0x3F) << 8);
        /** min QP */
        reg |= p_h263->rc_min_qp & 0x3F;
-       WRITEL(reg, mfc_regs->e_rc_qp_bound);
+       writel(reg, mfc_regs->e_rc_qp_bound);
 
        /* other QPs */
-       WRITEL(0x0, mfc_regs->e_fixed_picture_qp);
+       writel(0x0, mfc_regs->e_fixed_picture_qp);
        if (!p->rc_frame && !p->rc_mb) {
                reg = 0;
                reg |= ((p_h263->rc_b_frame_qp & 0x3F) << 16);
                reg |= ((p_h263->rc_p_frame_qp & 0x3F) << 8);
                reg |= p_h263->rc_frame_qp & 0x3F;
-               WRITEL(reg, mfc_regs->e_fixed_picture_qp);
+               writel(reg, mfc_regs->e_fixed_picture_qp);
        }
 
        /* frame rate */
@@ -1216,16 +1211,16 @@ static int s5p_mfc_set_enc_params_h263(struct s5p_mfc_ctx *ctx)
                reg = 0;
                reg |= ((p->rc_framerate_num & 0xFFFF) << 16);
                reg |= p->rc_framerate_denom & 0xFFFF;
-               WRITEL(reg, mfc_regs->e_rc_frame_rate);
+               writel(reg, mfc_regs->e_rc_frame_rate);
        }
 
        /* vbv buffer size */
        if (p->frame_skip_mode ==
                        V4L2_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE_BUF_LIMIT) {
-               WRITEL(p->vbv_size & 0xFFFF, mfc_regs->e_vbv_buffer_size);
+               writel(p->vbv_size & 0xFFFF, mfc_regs->e_vbv_buffer_size);
 
                if (p->rc_frame)
-                       WRITEL(p->vbv_delay, mfc_regs->e_vbv_init_delay);
+                       writel(p->vbv_delay, mfc_regs->e_vbv_init_delay);
        }
 
        mfc_debug_leave();
@@ -1247,57 +1242,57 @@ static int s5p_mfc_set_enc_params_vp8(struct s5p_mfc_ctx *ctx)
        s5p_mfc_set_enc_params(ctx);
 
        /* pictype : number of B */
-       reg = READL(mfc_regs->e_gop_config);
+       reg = readl(mfc_regs->e_gop_config);
        reg &= ~(0x3 << 16);
        reg |= ((p->num_b_frame & 0x3) << 16);
-       WRITEL(reg, mfc_regs->e_gop_config);
+       writel(reg, mfc_regs->e_gop_config);
 
        /* profile - 0 ~ 3 */
        reg = p_vp8->profile & 0x3;
-       WRITEL(reg, mfc_regs->e_picture_profile);
+       writel(reg, mfc_regs->e_picture_profile);
 
        /* rate control config. */
-       reg = READL(mfc_regs->e_rc_config);
+       reg = readl(mfc_regs->e_rc_config);
        /** macroblock level rate control */
        reg &= ~(0x1 << 8);
        reg |= ((p->rc_mb & 0x1) << 8);
-       WRITEL(reg, mfc_regs->e_rc_config);
+       writel(reg, mfc_regs->e_rc_config);
 
        /* frame rate */
        if (p->rc_frame && p->rc_framerate_num && p->rc_framerate_denom) {
                reg = 0;
                reg |= ((p->rc_framerate_num & 0xFFFF) << 16);
                reg |= p->rc_framerate_denom & 0xFFFF;
-               WRITEL(reg, mfc_regs->e_rc_frame_rate);
+               writel(reg, mfc_regs->e_rc_frame_rate);
        }
 
        /* frame QP */
        reg &= ~(0x7F);
        reg |= p_vp8->rc_frame_qp & 0x7F;
-       WRITEL(reg, mfc_regs->e_rc_config);
+       writel(reg, mfc_regs->e_rc_config);
 
        /* other QPs */
-       WRITEL(0x0, mfc_regs->e_fixed_picture_qp);
+       writel(0x0, mfc_regs->e_fixed_picture_qp);
        if (!p->rc_frame && !p->rc_mb) {
                reg = 0;
                reg |= ((p_vp8->rc_p_frame_qp & 0x7F) << 8);
                reg |= p_vp8->rc_frame_qp & 0x7F;
-               WRITEL(reg, mfc_regs->e_fixed_picture_qp);
+               writel(reg, mfc_regs->e_fixed_picture_qp);
        }
 
        /* max QP */
        reg = ((p_vp8->rc_max_qp & 0x7F) << 8);
        /* min QP */
        reg |= p_vp8->rc_min_qp & 0x7F;
-       WRITEL(reg, mfc_regs->e_rc_qp_bound);
+       writel(reg, mfc_regs->e_rc_qp_bound);
 
        /* vbv buffer size */
        if (p->frame_skip_mode ==
                        V4L2_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE_BUF_LIMIT) {
-               WRITEL(p->vbv_size & 0xFFFF, mfc_regs->e_vbv_buffer_size);
+               writel(p->vbv_size & 0xFFFF, mfc_regs->e_vbv_buffer_size);
 
                if (p->rc_frame)
-                       WRITEL(p->vbv_delay, mfc_regs->e_vbv_init_delay);
+                       writel(p->vbv_delay, mfc_regs->e_vbv_init_delay);
        }
 
        /* VP8 specific params */
@@ -1319,7 +1314,7 @@ static int s5p_mfc_set_enc_params_vp8(struct s5p_mfc_ctx *ctx)
        }
        reg |= (val & 0xF) << 3;
        reg |= (p_vp8->num_ref & 0x2);
-       WRITEL(reg, mfc_regs->e_vp8_options);
+       writel(reg, mfc_regs->e_vp8_options);
 
        mfc_debug_leave();
 
@@ -1338,9 +1333,9 @@ static int s5p_mfc_init_decode_v6(struct s5p_mfc_ctx *ctx)
        mfc_debug(2, "InstNo: %d/%d\n", ctx->inst_no,
                        S5P_FIMV_CH_SEQ_HEADER_V6);
        mfc_debug(2, "BUFs: %08x %08x %08x\n",
-                 READL(mfc_regs->d_cpb_buffer_addr),
-                 READL(mfc_regs->d_cpb_buffer_addr),
-                 READL(mfc_regs->d_cpb_buffer_addr));
+                 readl(mfc_regs->d_cpb_buffer_addr),
+                 readl(mfc_regs->d_cpb_buffer_addr),
+                 readl(mfc_regs->d_cpb_buffer_addr));
 
        /* FMO_ASO_CTRL - 0: Enable, 1: Disable */
        reg |= (fmo_aso_ctrl << S5P_FIMV_D_OPT_FMO_ASO_CTRL_MASK_V6);
@@ -1351,11 +1346,11 @@ static int s5p_mfc_init_decode_v6(struct s5p_mfc_ctx *ctx)
         * set to negative value. */
        if (ctx->display_delay >= 0) {
                reg |= (0x1 << S5P_FIMV_D_OPT_DDELAY_EN_SHIFT_V6);
-               WRITEL(ctx->display_delay, mfc_regs->d_display_delay);
+               writel(ctx->display_delay, mfc_regs->d_display_delay);
        }
 
        if (IS_MFCV7_PLUS(dev) || IS_MFCV6_V2(dev)) {
-               WRITEL(reg, mfc_regs->d_dec_options);
+               writel(reg, mfc_regs->d_dec_options);
                reg = 0;
        }
 
@@ -1370,22 +1365,22 @@ static int s5p_mfc_init_decode_v6(struct s5p_mfc_ctx *ctx)
                reg |= (0x1 << S5P_FIMV_D_OPT_TILE_MODE_SHIFT_V6);
 
        if (IS_MFCV7_PLUS(dev) || IS_MFCV6_V2(dev))
-               WRITEL(reg, mfc_regs->d_init_buffer_options);
+               writel(reg, mfc_regs->d_init_buffer_options);
        else
-               WRITEL(reg, mfc_regs->d_dec_options);
+               writel(reg, mfc_regs->d_dec_options);
 
        /* 0: NV12(CbCr), 1: NV21(CrCb) */
        if (ctx->dst_fmt->fourcc == V4L2_PIX_FMT_NV21M)
-               WRITEL(0x1, mfc_regs->pixel_format);
+               writel(0x1, mfc_regs->pixel_format);
        else
-               WRITEL(0x0, mfc_regs->pixel_format);
+               writel(0x0, mfc_regs->pixel_format);
 
 
        /* sei parse */
-       WRITEL(ctx->sei_fp_parse & 0x1, mfc_regs->d_sei_enable);
+       writel(ctx->sei_fp_parse & 0x1, mfc_regs->d_sei_enable);
 
-       WRITEL(ctx->inst_no, mfc_regs->instance_id);
-       s5p_mfc_hw_call(dev->mfc_cmds, cmd_host2risc, dev,
+       writel(ctx->inst_no, mfc_regs->instance_id);
+       s5p_mfc_hw_call_void(dev->mfc_cmds, cmd_host2risc, dev,
                        S5P_FIMV_CH_SEQ_HEADER_V6, NULL);
 
        mfc_debug_leave();
@@ -1400,8 +1395,8 @@ static inline void s5p_mfc_set_flush(struct s5p_mfc_ctx *ctx, int flush)
        if (flush) {
                dev->curr_ctx = ctx->num;
                s5p_mfc_clean_ctx_int_flags(ctx);
-               WRITEL(ctx->inst_no, mfc_regs->instance_id);
-               s5p_mfc_hw_call(dev->mfc_cmds, cmd_host2risc, dev,
+               writel(ctx->inst_no, mfc_regs->instance_id);
+               s5p_mfc_hw_call_void(dev->mfc_cmds, cmd_host2risc, dev,
                                S5P_FIMV_H2R_CMD_FLUSH_V6, NULL);
        }
 }
@@ -1413,19 +1408,19 @@ static int s5p_mfc_decode_one_frame_v6(struct s5p_mfc_ctx *ctx,
        struct s5p_mfc_dev *dev = ctx->dev;
        const struct s5p_mfc_regs *mfc_regs = dev->mfc_regs;
 
-       WRITEL(ctx->dec_dst_flag, mfc_regs->d_available_dpb_flag_lower);
-       WRITEL(ctx->slice_interface & 0x1, mfc_regs->d_slice_if_enable);
+       writel(ctx->dec_dst_flag, mfc_regs->d_available_dpb_flag_lower);
+       writel(ctx->slice_interface & 0x1, mfc_regs->d_slice_if_enable);
 
-       WRITEL(ctx->inst_no, mfc_regs->instance_id);
+       writel(ctx->inst_no, mfc_regs->instance_id);
        /* Issue different commands to instance basing on whether it
         * is the last frame or not. */
        switch (last_frame) {
        case 0:
-               s5p_mfc_hw_call(dev->mfc_cmds, cmd_host2risc, dev,
+               s5p_mfc_hw_call_void(dev->mfc_cmds, cmd_host2risc, dev,
                                S5P_FIMV_CH_FRAME_START_V6, NULL);
                break;
        case 1:
-               s5p_mfc_hw_call(dev->mfc_cmds, cmd_host2risc, dev,
+               s5p_mfc_hw_call_void(dev->mfc_cmds, cmd_host2risc, dev,
                                S5P_FIMV_CH_LAST_FRAME_V6, NULL);
                break;
        default:
@@ -1458,12 +1453,12 @@ static int s5p_mfc_init_encode_v6(struct s5p_mfc_ctx *ctx)
 
        /* Set stride lengths for v7 & above */
        if (IS_MFCV7_PLUS(dev)) {
-               WRITEL(ctx->img_width, mfc_regs->e_source_first_plane_stride);
-               WRITEL(ctx->img_width, mfc_regs->e_source_second_plane_stride);
+               writel(ctx->img_width, mfc_regs->e_source_first_plane_stride);
+               writel(ctx->img_width, mfc_regs->e_source_second_plane_stride);
        }
 
-       WRITEL(ctx->inst_no, mfc_regs->instance_id);
-       s5p_mfc_hw_call(dev->mfc_cmds, cmd_host2risc, dev,
+       writel(ctx->inst_no, mfc_regs->instance_id);
+       s5p_mfc_hw_call_void(dev->mfc_cmds, cmd_host2risc, dev,
                        S5P_FIMV_CH_SEQ_HEADER_V6, NULL);
 
        return 0;
@@ -1479,7 +1474,7 @@ static int s5p_mfc_h264_set_aso_slice_order_v6(struct s5p_mfc_ctx *ctx)
 
        if (p_h264->aso) {
                for (i = 0; i < ARRAY_SIZE(p_h264->aso_slice_order); i++) {
-                       WRITEL(p_h264->aso_slice_order[i],
+                       writel(p_h264->aso_slice_order[i],
                                mfc_regs->e_h264_aso_slice_order_0 + i * 4);
                }
        }
@@ -1501,8 +1496,8 @@ static int s5p_mfc_encode_one_frame_v6(struct s5p_mfc_ctx *ctx)
 
        s5p_mfc_set_slice_mode(ctx);
 
-       WRITEL(ctx->inst_no, mfc_regs->instance_id);
-       s5p_mfc_hw_call(dev->mfc_cmds, cmd_host2risc, dev,
+       writel(ctx->inst_no, mfc_regs->instance_id);
+       s5p_mfc_hw_call_void(dev->mfc_cmds, cmd_host2risc, dev,
                        S5P_FIMV_CH_FRAME_START_V6, NULL);
 
        mfc_debug(2, "--\n");
@@ -1877,15 +1872,15 @@ static void s5p_mfc_cleanup_queue_v6(struct list_head *lh, struct vb2_queue *vq)
 static void s5p_mfc_clear_int_flags_v6(struct s5p_mfc_dev *dev)
 {
        const struct s5p_mfc_regs *mfc_regs = dev->mfc_regs;
-       WRITEL(0, mfc_regs->risc2host_command);
-       WRITEL(0, mfc_regs->risc2host_int);
+       writel(0, mfc_regs->risc2host_command);
+       writel(0, mfc_regs->risc2host_int);
 }
 
 static void s5p_mfc_write_info_v6(struct s5p_mfc_ctx *ctx, unsigned int data,
                unsigned int ofs)
 {
        s5p_mfc_clock_on();
-       WRITEL(data, (void *)ofs);
+       writel(data, (volatile void __iomem *)((unsigned long)ofs));
        s5p_mfc_clock_off();
 }
 
@@ -1895,7 +1890,7 @@ s5p_mfc_read_info_v6(struct s5p_mfc_ctx *ctx, unsigned int ofs)
        int ret;
 
        s5p_mfc_clock_on();
-       ret = READL((void *)ofs);
+       ret = readl((volatile void __iomem *)((unsigned long)ofs));
        s5p_mfc_clock_off();
 
        return ret;
@@ -1903,51 +1898,51 @@ s5p_mfc_read_info_v6(struct s5p_mfc_ctx *ctx, unsigned int ofs)
 
 static int s5p_mfc_get_dspl_y_adr_v6(struct s5p_mfc_dev *dev)
 {
-       return READL(dev->mfc_regs->d_display_first_plane_addr);
+       return readl(dev->mfc_regs->d_display_first_plane_addr);
 }
 
 static int s5p_mfc_get_dec_y_adr_v6(struct s5p_mfc_dev *dev)
 {
-       return READL(dev->mfc_regs->d_decoded_first_plane_addr);
+       return readl(dev->mfc_regs->d_decoded_first_plane_addr);
 }
 
 static int s5p_mfc_get_dspl_status_v6(struct s5p_mfc_dev *dev)
 {
-       return READL(dev->mfc_regs->d_display_status);
+       return readl(dev->mfc_regs->d_display_status);
 }
 
 static int s5p_mfc_get_dec_status_v6(struct s5p_mfc_dev *dev)
 {
-       return READL(dev->mfc_regs->d_decoded_status);
+       return readl(dev->mfc_regs->d_decoded_status);
 }
 
 static int s5p_mfc_get_dec_frame_type_v6(struct s5p_mfc_dev *dev)
 {
-       return READL(dev->mfc_regs->d_decoded_frame_type) &
+       return readl(dev->mfc_regs->d_decoded_frame_type) &
                S5P_FIMV_DECODE_FRAME_MASK_V6;
 }
 
 static int s5p_mfc_get_disp_frame_type_v6(struct s5p_mfc_ctx *ctx)
 {
        struct s5p_mfc_dev *dev = ctx->dev;
-       return READL(dev->mfc_regs->d_display_frame_type) &
+       return readl(dev->mfc_regs->d_display_frame_type) &
                S5P_FIMV_DECODE_FRAME_MASK_V6;
 }
 
 static int s5p_mfc_get_consumed_stream_v6(struct s5p_mfc_dev *dev)
 {
-       return READL(dev->mfc_regs->d_decoded_nal_size);
+       return readl(dev->mfc_regs->d_decoded_nal_size);
 }
 
 static int s5p_mfc_get_int_reason_v6(struct s5p_mfc_dev *dev)
 {
-       return READL(dev->mfc_regs->risc2host_command) &
+       return readl(dev->mfc_regs->risc2host_command) &
                S5P_FIMV_RISC2HOST_CMD_MASK;
 }
 
 static int s5p_mfc_get_int_err_v6(struct s5p_mfc_dev *dev)
 {
-       return READL(dev->mfc_regs->error_code);
+       return readl(dev->mfc_regs->error_code);
 }
 
 static int s5p_mfc_err_dec_v6(unsigned int err)
@@ -1962,87 +1957,87 @@ static int s5p_mfc_err_dspl_v6(unsigned int err)
 
 static int s5p_mfc_get_img_width_v6(struct s5p_mfc_dev *dev)
 {
-       return READL(dev->mfc_regs->d_display_frame_width);
+       return readl(dev->mfc_regs->d_display_frame_width);
 }
 
 static int s5p_mfc_get_img_height_v6(struct s5p_mfc_dev *dev)
 {
-       return READL(dev->mfc_regs->d_display_frame_height);
+       return readl(dev->mfc_regs->d_display_frame_height);
 }
 
 static int s5p_mfc_get_dpb_count_v6(struct s5p_mfc_dev *dev)
 {
-       return READL(dev->mfc_regs->d_min_num_dpb);
+       return readl(dev->mfc_regs->d_min_num_dpb);
 }
 
 static int s5p_mfc_get_mv_count_v6(struct s5p_mfc_dev *dev)
 {
-       return READL(dev->mfc_regs->d_min_num_mv);
+       return readl(dev->mfc_regs->d_min_num_mv);
 }
 
 static int s5p_mfc_get_inst_no_v6(struct s5p_mfc_dev *dev)
 {
-       return READL(dev->mfc_regs->ret_instance_id);
+       return readl(dev->mfc_regs->ret_instance_id);
 }
 
 static int s5p_mfc_get_enc_dpb_count_v6(struct s5p_mfc_dev *dev)
 {
-       return READL(dev->mfc_regs->e_num_dpb);
+       return readl(dev->mfc_regs->e_num_dpb);
 }
 
 static int s5p_mfc_get_enc_strm_size_v6(struct s5p_mfc_dev *dev)
 {
-       return READL(dev->mfc_regs->e_stream_size);
+       return readl(dev->mfc_regs->e_stream_size);
 }
 
 static int s5p_mfc_get_enc_slice_type_v6(struct s5p_mfc_dev *dev)
 {
-       return READL(dev->mfc_regs->e_slice_type);
+       return readl(dev->mfc_regs->e_slice_type);
 }
 
 static int s5p_mfc_get_enc_pic_count_v6(struct s5p_mfc_dev *dev)
 {
-       return READL(dev->mfc_regs->e_picture_count);
+       return readl(dev->mfc_regs->e_picture_count);
 }
 
 static int s5p_mfc_get_sei_avail_status_v6(struct s5p_mfc_ctx *ctx)
 {
        struct s5p_mfc_dev *dev = ctx->dev;
-       return READL(dev->mfc_regs->d_frame_pack_sei_avail);
+       return readl(dev->mfc_regs->d_frame_pack_sei_avail);
 }
 
 static int s5p_mfc_get_mvc_num_views_v6(struct s5p_mfc_dev *dev)
 {
-       return READL(dev->mfc_regs->d_mvc_num_views);
+       return readl(dev->mfc_regs->d_mvc_num_views);
 }
 
 static int s5p_mfc_get_mvc_view_id_v6(struct s5p_mfc_dev *dev)
 {
-       return READL(dev->mfc_regs->d_mvc_view_id);
+       return readl(dev->mfc_regs->d_mvc_view_id);
 }
 
 static unsigned int s5p_mfc_get_pic_type_top_v6(struct s5p_mfc_ctx *ctx)
 {
        return s5p_mfc_read_info_v6(ctx,
-               (unsigned int) ctx->dev->mfc_regs->d_ret_picture_tag_top);
+               (__force unsigned long) ctx->dev->mfc_regs->d_ret_picture_tag_top);
 }
 
 static unsigned int s5p_mfc_get_pic_type_bot_v6(struct s5p_mfc_ctx *ctx)
 {
        return s5p_mfc_read_info_v6(ctx,
-               (unsigned int) ctx->dev->mfc_regs->d_ret_picture_tag_bot);
+               (__force unsigned long) ctx->dev->mfc_regs->d_ret_picture_tag_bot);
 }
 
 static unsigned int s5p_mfc_get_crop_info_h_v6(struct s5p_mfc_ctx *ctx)
 {
        return s5p_mfc_read_info_v6(ctx,
-               (unsigned int) ctx->dev->mfc_regs->d_display_crop_info1);
+               (__force unsigned long) ctx->dev->mfc_regs->d_display_crop_info1);
 }
 
 static unsigned int s5p_mfc_get_crop_info_v_v6(struct s5p_mfc_ctx *ctx)
 {
        return s5p_mfc_read_info_v6(ctx,
-               (unsigned int) ctx->dev->mfc_regs->d_display_crop_info2);
+               (__force unsigned long) ctx->dev->mfc_regs->d_display_crop_info2);
 }
 
 static struct s5p_mfc_regs mfc_regs;
index b6a8be97a96c57715d2454518052351d43864340..826c48945bf50b188357c31d8108c627697bbac6 100644 (file)
@@ -21,7 +21,7 @@
 #include "s5p_mfc_pm.h"
 
 #define MFC_GATE_CLK_NAME      "mfc"
-#define MFC_SCLK_NAME          "sclk-mfc"
+#define MFC_SCLK_NAME          "sclk_mfc"
 #define MFC_SCLK_RATE          (200 * 1000000)
 
 #define CLK_DEBUG
index 369a4c191e18a8e80e63edcb57cb790df28394a3..a9d56f8936b4e576d2e4552b1d86323d15801da5 100644 (file)
@@ -8,7 +8,8 @@
 
 config VIDEO_SAMSUNG_S5P_TV
        bool "Samsung TV driver for S5P platform"
-       depends on (PLAT_S5P || ARCH_EXYNOS) && PM_RUNTIME
+       depends on PM_RUNTIME
+       depends on PLAT_S5P || ARCH_EXYNOS || COMPILE_TEST
        default n
        ---help---
          Say Y here to enable selecting the TV output devices for
@@ -70,6 +71,7 @@ config VIDEO_SAMSUNG_S5P_MIXER
        tristate "Samsung Mixer and Video Processor Driver"
        depends on VIDEO_DEV && VIDEO_V4L2
        depends on VIDEO_SAMSUNG_S5P_TV
+       depends on HAS_DMA
        select VIDEOBUF2_DMA_CONTIG
        help
          Say Y here if you want support for the Mixer in Samsung S5P SoCs.
index 754740f4b671db0a0749d3b21ee7afdf5c1fc8b1..37c8bd694c5f250c0e7d64f8a601cb14d5c93bcd 100644 (file)
@@ -615,7 +615,7 @@ static int hdmi_s_power(struct v4l2_subdev *sd, int on)
        else
                ret = pm_runtime_put_sync(hdev->dev);
        /* only values < 0 indicate errors */
-       return IS_ERR_VALUE(ret) ? ret : 0;
+       return ret < 0 ? ret : 0;
 }
 
 static int hdmi_s_dv_timings(struct v4l2_subdev *sd,
index 5a7c3796f22e349de4edf608bd5eb8ffee62d0dd..72cf892dd0089af58d9d2eac6bf533b881b1d6bd 100644 (file)
@@ -190,7 +190,7 @@ static int sdo_s_power(struct v4l2_subdev *sd, int on)
                ret = pm_runtime_put_sync(dev);
 
        /* only values < 0 indicate errors */
-       return IS_ERR_VALUE(ret) ? ret : 0;
+       return ret < 0 ? ret : 0;
 }
 
 static int sdo_streamon(struct sdo_device *sdev)
index 3dd762e5b67e8e53ff05d2fd57351c71e9471797..db8c17bb4aaaf357b6aa1c613e5aee570b953d5d 100644 (file)
@@ -289,7 +289,7 @@ static int sii9234_s_power(struct v4l2_subdev *sd, int on)
        else
                ret = pm_runtime_put(&ctx->client->dev);
        /* only values < 0 indicate errors */
-       return IS_ERR_VALUE(ret) ? ret : 0;
+       return ret < 0 ? ret : 0;
 }
 
 static int sii9234_s_stream(struct v4l2_subdev *sd, int enable)
index 8dc279d4d5610fac3219cb253aa9d383108ab3d4..be3b3bc71a0fcdd2f9e931a06127a71aa33555a9 100644 (file)
@@ -26,6 +26,7 @@
 #include <media/v4l2-device.h>
 #include <media/v4l2-ioctl.h>
 #include <media/v4l2-mem2mem.h>
+#include <media/v4l2-image-sizes.h>
 #include <media/videobuf2-dma-contig.h>
 
 #define VEU_STR 0x00 /* start register */
@@ -135,9 +136,6 @@ enum sh_veu_fmt_idx {
        SH_VEU_FMT_RGB24,
 };
 
-#define VGA_WIDTH      640
-#define VGA_HEIGHT     480
-
 #define DEFAULT_IN_WIDTH       VGA_WIDTH
 #define DEFAULT_IN_HEIGHT      VGA_HEIGHT
 #define DEFAULT_IN_FMTIDX      SH_VEU_FMT_NV12
index 6540847f4e1d3345cb90a73ef6ad8531c03f2150..f2776cd415ca81625df0972330adbb636db9d6d8 100644 (file)
@@ -20,6 +20,8 @@ config SOC_CAMERA_PLATFORM
 config VIDEO_MX3
        tristate "i.MX3x Camera Sensor Interface driver"
        depends on VIDEO_DEV && MX3_IPU && SOC_CAMERA
+       depends on MX3_IPU || COMPILE_TEST
+       depends on HAS_DMA
        select VIDEOBUF2_DMA_CONTIG
        ---help---
          This is a v4l2 driver for the i.MX3x Camera Sensor Interface
@@ -35,6 +37,7 @@ config VIDEO_RCAR_VIN
        tristate "R-Car Video Input (VIN) support"
        depends on VIDEO_DEV && SOC_CAMERA
        depends on ARCH_SHMOBILE || COMPILE_TEST
+       depends on HAS_DMA
        select VIDEOBUF2_DMA_CONTIG
        select SOC_CAMERA_SCALE_CROP
        ---help---
@@ -51,6 +54,7 @@ config VIDEO_SH_MOBILE_CEU
        tristate "SuperH Mobile CEU Interface driver"
        depends on VIDEO_DEV && SOC_CAMERA && HAS_DMA && HAVE_CLK
        depends on ARCH_SHMOBILE || SUPERH || COMPILE_TEST
+       depends on HAS_DMA
        select VIDEOBUF2_DMA_CONTIG
        select SOC_CAMERA_SCALE_CROP
        ---help---
@@ -58,7 +62,9 @@ config VIDEO_SH_MOBILE_CEU
 
 config VIDEO_OMAP1
        tristate "OMAP1 Camera Interface driver"
-       depends on VIDEO_DEV && ARCH_OMAP1 && SOC_CAMERA
+       depends on VIDEO_DEV && SOC_CAMERA
+       depends on ARCH_OMAP1
+       depends on HAS_DMA
        select VIDEOBUF_DMA_CONTIG
        select VIDEOBUF_DMA_SG
        ---help---
@@ -66,14 +72,18 @@ config VIDEO_OMAP1
 
 config VIDEO_MX2
        tristate "i.MX27 Camera Sensor Interface driver"
-       depends on VIDEO_DEV && SOC_CAMERA && SOC_IMX27
+       depends on VIDEO_DEV && SOC_CAMERA
+       depends on SOC_IMX27 || COMPILE_TEST
+       depends on HAS_DMA
        select VIDEOBUF2_DMA_CONTIG
        ---help---
          This is a v4l2 driver for the i.MX27 Camera Sensor Interface
 
 config VIDEO_ATMEL_ISI
        tristate "ATMEL Image Sensor Interface (ISI) support"
-       depends on VIDEO_DEV && SOC_CAMERA && ARCH_AT91
+       depends on VIDEO_DEV && SOC_CAMERA
+       depends on ARCH_AT91 || COMPILE_TEST
+       depends on HAS_DMA
        select VIDEOBUF2_DMA_CONTIG
        ---help---
          This module makes the ATMEL Image Sensor Interface available
index 3408b045b3f1cf2697715c4e552c0289284f3443..c5291b00105758b8452b0f9ef383780c794fbac7 100644 (file)
@@ -54,7 +54,7 @@ static void set_dma_ctrl(struct fbd *fb_desc, u32 ctrl)
 struct isi_dma_desc {
        struct list_head list;
        struct fbd *p_fbd;
-       u32 fbd_phys;
+       dma_addr_t fbd_phys;
 };
 
 /* Frame buffer data */
@@ -75,7 +75,7 @@ struct atmel_isi {
 
        /* Allocate descriptors for dma buffer use */
        struct fbd                      *p_fb_descriptors;
-       u32                             fb_descriptors_phys;
+       dma_addr_t                      fb_descriptors_phys;
        struct                          list_head dma_desc_head;
        struct isi_dma_desc             dma_desc[MAX_BUFFER_NUM];
 
@@ -169,7 +169,7 @@ static irqreturn_t atmel_isi_handle_streaming(struct atmel_isi *isi)
                isi->active = list_entry(isi->video_buffer_list.next,
                                        struct frame_buffer, list);
                isi_writel(isi, ISI_DMA_C_DSCR,
-                       isi->active->p_dma_desc->fbd_phys);
+                       (u32)isi->active->p_dma_desc->fbd_phys);
                isi_writel(isi, ISI_DMA_C_CTRL,
                        ISI_DMA_CTRL_FETCH | ISI_DMA_CTRL_DONE);
                isi_writel(isi, ISI_DMA_CHER, ISI_DMA_CHSR_C_CH);
@@ -346,7 +346,7 @@ static void start_dma(struct atmel_isi *isi, struct frame_buffer *buffer)
                return;
        }
 
-       isi_writel(isi, ISI_DMA_C_DSCR, buffer->p_dma_desc->fbd_phys);
+       isi_writel(isi, ISI_DMA_C_DSCR, (u32)buffer->p_dma_desc->fbd_phys);
        isi_writel(isi, ISI_DMA_C_CTRL, ISI_DMA_CTRL_FETCH | ISI_DMA_CTRL_DONE);
        isi_writel(isi, ISI_DMA_CHER, ISI_DMA_CHSR_C_CH);
 
@@ -384,7 +384,6 @@ static int start_streaming(struct vb2_queue *vq, unsigned int count)
        struct soc_camera_device *icd = soc_camera_from_vb2q(vq);
        struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
        struct atmel_isi *isi = ici->priv;
-       u32 sr = 0;
        int ret;
 
        /* Reset ISI */
@@ -394,11 +393,11 @@ static int start_streaming(struct vb2_queue *vq, unsigned int count)
                return ret;
        }
        /* Disable all interrupts */
-       isi_writel(isi, ISI_INTDIS, ~0UL);
+       isi_writel(isi, ISI_INTDIS, (u32)~0UL);
 
        spin_lock_irq(&isi->lock);
        /* Clear any pending interrupt */
-       sr = isi_readl(isi, ISI_STATUS);
+       isi_readl(isi, ISI_STATUS);
 
        if (count)
                start_dma(isi, isi->active);
index b40bc2e5ba47d6cbcf8ec942adc53a0797970ac7..2347612a4cc167a08af0bf831020d7b7dc932ebd 100644 (file)
@@ -809,10 +809,9 @@ static int mx2_camera_init_videobuf(struct vb2_queue *q,
 
 static int mx27_camera_emma_prp_reset(struct mx2_camera_dev *pcdev)
 {
-       u32 cntl;
        int count = 0;
 
-       cntl = readl(pcdev->base_emma + PRP_CNTL);
+       readl(pcdev->base_emma + PRP_CNTL);
        writel(PRP_CNTL_SWRST, pcdev->base_emma + PRP_CNTL);
        while (count++ < 100) {
                if (!(readl(pcdev->base_emma + PRP_CNTL) & PRP_CNTL_SWRST))
@@ -1003,7 +1002,7 @@ static int mx2_emmaprp_resize(struct mx2_camera_dev *pcdev,
                              struct v4l2_mbus_framefmt *mf_in,
                              struct v4l2_pix_format *pix_out, bool apply)
 {
-       int num, den;
+       unsigned int num, den;
        unsigned long m;
        int i, dir;
 
index 64dc80ccd6f932ded137ab36dd562bda860d2366..66178fc9f9ebf90b720430016321668ab5dbcfd8 100644 (file)
@@ -1694,7 +1694,7 @@ static int pxa_camera_pdata_from_dt(struct device *dev,
                break;
        default:
                break;
-       };
+       }
 
        if (ep.bus.parallel.flags & V4L2_MBUS_MASTER)
                pcdev->platform_flags |= PXA_CAMERA_MASTER;
index 85d579f65f5206d0558ed38e4ed6ccba5aa7f0e5..20defcb8b31b005fca81c2f4c0f4ad3b51ffd817 100644 (file)
@@ -981,7 +981,7 @@ static int rcar_vin_get_formats(struct soc_camera_device *icd, unsigned int idx,
 
                if (shift == 3) {
                        dev_err(dev,
-                               "Failed to configure the client below %ux%x\n",
+                               "Failed to configure the client below %ux%u\n",
                                mf.width, mf.height);
                        return -EIO;
                }
@@ -1502,7 +1502,7 @@ static int rcar_vin_probe(struct platform_device *pdev)
        } else {
                priv->ici.nr = of_alias_get_id(pdev->dev.of_node, "vin");
                priv->chip = (enum chip_id)match->data;
-       };
+       }
 
        spin_lock_init(&priv->lock);
        INIT_LIST_HEAD(&priv->capture);
index f4308fed54318625d6e802aac288b96bd8cecd68..8e61b976da19ed17fe09866eb3efd7d6544a02bd 100644 (file)
@@ -437,6 +437,22 @@ static int soc_camera_prepare_buf(struct file *file, void *priv,
                return vb2_prepare_buf(&icd->vb2_vidq, b);
 }
 
+static int soc_camera_expbuf(struct file *file, void *priv,
+                            struct v4l2_exportbuffer *p)
+{
+       struct soc_camera_device *icd = file->private_data;
+       struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+
+       if (icd->streamer != file)
+               return -EBUSY;
+
+       /* videobuf2 only */
+       if (ici->ops->init_videobuf)
+               return -EINVAL;
+       else
+               return vb2_expbuf(&icd->vb2_vidq, p);
+}
+
 /* Always entered with .host_lock held */
 static int soc_camera_init_user_formats(struct soc_camera_device *icd)
 {
@@ -1347,13 +1363,11 @@ static int soc_camera_i2c_init(struct soc_camera_device *icd,
                return -ENODEV;
        }
 
-       ssdd = kzalloc(sizeof(*ssdd), GFP_KERNEL);
+       ssdd = kmemdup(&sdesc->subdev_desc, sizeof(*ssdd), GFP_KERNEL);
        if (!ssdd) {
                ret = -ENOMEM;
                goto ealloc;
        }
-
-       memcpy(ssdd, &sdesc->subdev_desc, sizeof(*ssdd));
        /*
         * In synchronous case we request regulators ourselves in
         * soc_camera_pdrv_probe(), make sure the subdevice driver doesn't try
@@ -2085,6 +2099,7 @@ static const struct v4l2_ioctl_ops soc_camera_ioctl_ops = {
        .vidioc_dqbuf            = soc_camera_dqbuf,
        .vidioc_create_bufs      = soc_camera_create_bufs,
        .vidioc_prepare_buf      = soc_camera_prepare_buf,
+       .vidioc_expbuf           = soc_camera_expbuf,
        .vidioc_streamon         = soc_camera_streamon,
        .vidioc_streamoff        = soc_camera_streamoff,
        .vidioc_cropcap          = soc_camera_cropcap,
index a51a0135980534e6952db9f492b091128938eb1e..3e2e3a33e6ed850e4ceccd223f90f1c4eb956875 100644 (file)
@@ -329,7 +329,7 @@ int vpdma_alloc_desc_buf(struct vpdma_buf *buf, size_t size)
        if (!buf->addr)
                return -ENOMEM;
 
-       WARN_ON((u32) buf->addr & VPDMA_DESC_ALIGN);
+       WARN_ON(((unsigned long)buf->addr & VPDMA_DESC_ALIGN) != 0);
 
        return 0;
 }
@@ -584,7 +584,7 @@ static void dump_dtd(struct vpdma_dtd *dtd)
                pr_debug("word1: line_length = %d, xfer_height = %d\n",
                        dtd_get_line_length(dtd), dtd_get_xfer_height(dtd));
 
-       pr_debug("word2: start_addr = 0x%08x\n", dtd->start_addr);
+       pr_debug("word2: start_addr = %pad\n", &dtd->start_addr);
 
        pr_debug("word3: pkt_type = %d, mode = %d, dir = %d, chan = %d, "
                "pri = %d, next_chan = %d\n", dtd_get_pkt_type(dtd),
index 972f43f69206b8156dc492d6915f1ca97e8ba536..9a081c2911598502fb33e0d500d876a0361fcbc0 100644 (file)
@@ -31,6 +31,7 @@
 #include <linux/slab.h>
 #include <linux/videodev2.h>
 #include <linux/log2.h>
+#include <linux/sizes.h>
 
 #include <media/v4l2-common.h>
 #include <media/v4l2-ctrls.h>
@@ -138,12 +139,12 @@ struct vpe_dei_regs {
  * default expert DEI register values, unlikely to be modified.
  */
 static const struct vpe_dei_regs dei_regs = {
-       0x020C0804u,
-       0x0118100Fu,
-       0x08040200u,
-       0x1010100Cu,
-       0x10101010u,
-       0x10101010u,
+       .mdt_spacial_freq_thr_reg = 0x020C0804u,
+       .edi_config_reg = 0x0118100Fu,
+       .edi_lut_reg0 = 0x08040200u,
+       .edi_lut_reg1 = 0x1010100Cu,
+       .edi_lut_reg2 = 0x10101010u,
+       .edi_lut_reg3 = 0x10101010u,
 };
 
 /*
@@ -834,10 +835,10 @@ static int set_srcdst_params(struct vpe_ctx *ctx)
                                        VPDMA_STRIDE_ALIGN);
                mv_buf_size = bytes_per_line * s_q_data->height;
 
-               ctx->deinterlacing = 1;
+               ctx->deinterlacing = true;
                src_h <<= 1;
        } else {
-               ctx->deinterlacing = 0;
+               ctx->deinterlacing = false;
                mv_buf_size = 0;
        }
 
@@ -2343,8 +2344,7 @@ v4l2_dev_unreg:
 
 static int vpe_remove(struct platform_device *pdev)
 {
-       struct vpe_dev *dev =
-               (struct vpe_dev *) platform_get_drvdata(pdev);
+       struct vpe_dev *dev = platform_get_drvdata(pdev);
 
        v4l2_info(&dev->v4l2_dev, "Removing " VPE_MODULE_NAME);
 
index b4f9d03636e3e8067e7adefc50070318915e37d1..ae6870cb8339dbff2959c956e8a8229d96b598a3 100644 (file)
@@ -18,6 +18,7 @@
 #include <media/v4l2-device.h>
 #include <media/v4l2-ioctl.h>
 #include <media/v4l2-ctrls.h>
+#include <media/v4l2-image-sizes.h>
 #include <media/ov7670.h>
 #include <media/videobuf-dma-sg.h>
 #include <linux/delay.h>
@@ -48,14 +49,6 @@ MODULE_PARM_DESC(override_serial,
                "the XO 1.5 serial port is enabled.  Set this option "
                "to force-enable the camera.");
 
-/*
- * Basic window sizes.
- */
-#define VGA_WIDTH      640
-#define VGA_HEIGHT     480
-#define QCIF_WIDTH     176
-#define        QCIF_HEIGHT     144
-
 /*
  * The structure describing our camera.
  */
@@ -89,7 +82,7 @@ struct via_camera {
         * live in frame buffer memory, so we don't call them "DMA".
         */
        unsigned int cb_offsets[3];     /* offsets into fb mem */
-       u8 *cb_addrs[3];                /* Kernel-space addresses */
+       u8 __iomem *cb_addrs[3];                /* Kernel-space addresses */
        int n_cap_bufs;                 /* How many are we using? */
        int next_buf;
        struct videobuf_queue vb_queue;
@@ -1283,7 +1276,7 @@ static bool viacam_serial_is_enabled(void)
                        VIACAM_SERIAL_CREG, &cbyte);
        if ((cbyte & VIACAM_SERIAL_BIT) == 0)
                return false; /* Not enabled */
-       if (override_serial == 0) {
+       if (!override_serial) {
                printk(KERN_NOTICE "Via camera: serial port is enabled, " \
                                "refusing to load.\n");
                printk(KERN_NOTICE "Specify override_serial=1 to force " \
diff --git a/drivers/media/platform/vivi.c b/drivers/media/platform/vivi.c
deleted file mode 100644 (file)
index 8033371..0000000
+++ /dev/null
@@ -1,1542 +0,0 @@
-/*
- * Virtual Video driver - This code emulates a real video device with v4l2 api
- *
- * Copyright (c) 2006 by:
- *      Mauro Carvalho Chehab <mchehab--a.t--infradead.org>
- *      Ted Walther <ted--a.t--enumera.com>
- *      John Sokol <sokol--a.t--videotechnology.com>
- *      http://v4l.videotechnology.com/
- *
- *      Conversion to videobuf2 by Pawel Osciak & Marek Szyprowski
- *      Copyright (c) 2010 Samsung Electronics
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the BSD Licence, GNU General Public License
- * as published by the Free Software Foundation; either version 2 of the
- * License, or (at your option) any later version
- */
-#include <linux/module.h>
-#include <linux/errno.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/sched.h>
-#include <linux/slab.h>
-#include <linux/font.h>
-#include <linux/mutex.h>
-#include <linux/videodev2.h>
-#include <linux/kthread.h>
-#include <linux/freezer.h>
-#include <media/videobuf2-vmalloc.h>
-#include <media/v4l2-device.h>
-#include <media/v4l2-ioctl.h>
-#include <media/v4l2-ctrls.h>
-#include <media/v4l2-fh.h>
-#include <media/v4l2-event.h>
-#include <media/v4l2-common.h>
-
-#define VIVI_MODULE_NAME "vivi"
-
-/* Maximum allowed frame rate
- *
- * Vivi will allow setting timeperframe in [1/FPS_MAX - FPS_MAX/1] range.
- *
- * Ideally FPS_MAX should be infinity, i.e. practically UINT_MAX, but that
- * might hit application errors when they manipulate these values.
- *
- * Besides, for tpf < 1ms image-generation logic should be changed, to avoid
- * producing frames with equal content.
- */
-#define FPS_MAX 1000
-
-#define MAX_WIDTH 1920
-#define MAX_HEIGHT 1200
-
-#define VIVI_VERSION "0.8.1"
-
-MODULE_DESCRIPTION("Video Technology Magazine Virtual Video Capture Board");
-MODULE_AUTHOR("Mauro Carvalho Chehab, Ted Walther and John Sokol");
-MODULE_LICENSE("Dual BSD/GPL");
-MODULE_VERSION(VIVI_VERSION);
-
-static unsigned video_nr = -1;
-module_param(video_nr, uint, 0644);
-MODULE_PARM_DESC(video_nr, "videoX start number, -1 is autodetect");
-
-static unsigned n_devs = 1;
-module_param(n_devs, uint, 0644);
-MODULE_PARM_DESC(n_devs, "number of video devices to create");
-
-static unsigned debug;
-module_param(debug, uint, 0644);
-MODULE_PARM_DESC(debug, "activates debug info");
-
-/* Global font descriptor */
-static const u8 *font8x16;
-
-/* timeperframe: min/max and default */
-static const struct v4l2_fract
-       tpf_min     = {.numerator = 1,          .denominator = FPS_MAX},
-       tpf_max     = {.numerator = FPS_MAX,    .denominator = 1},
-       tpf_default = {.numerator = 1001,       .denominator = 30000};  /* NTSC */
-
-#define dprintk(dev, level, fmt, arg...) \
-       v4l2_dbg(level, debug, &dev->v4l2_dev, fmt, ## arg)
-
-/* ------------------------------------------------------------------
-       Basic structures
-   ------------------------------------------------------------------*/
-
-struct vivi_fmt {
-       const char *name;
-       u32   fourcc;          /* v4l2 format id */
-       u8    depth;
-       bool  is_yuv;
-};
-
-static const struct vivi_fmt formats[] = {
-       {
-               .name     = "4:2:2, packed, YUYV",
-               .fourcc   = V4L2_PIX_FMT_YUYV,
-               .depth    = 16,
-               .is_yuv   = true,
-       },
-       {
-               .name     = "4:2:2, packed, UYVY",
-               .fourcc   = V4L2_PIX_FMT_UYVY,
-               .depth    = 16,
-               .is_yuv   = true,
-       },
-       {
-               .name     = "4:2:2, packed, YVYU",
-               .fourcc   = V4L2_PIX_FMT_YVYU,
-               .depth    = 16,
-               .is_yuv   = true,
-       },
-       {
-               .name     = "4:2:2, packed, VYUY",
-               .fourcc   = V4L2_PIX_FMT_VYUY,
-               .depth    = 16,
-               .is_yuv   = true,
-       },
-       {
-               .name     = "RGB565 (LE)",
-               .fourcc   = V4L2_PIX_FMT_RGB565, /* gggbbbbb rrrrrggg */
-               .depth    = 16,
-       },
-       {
-               .name     = "RGB565 (BE)",
-               .fourcc   = V4L2_PIX_FMT_RGB565X, /* rrrrrggg gggbbbbb */
-               .depth    = 16,
-       },
-       {
-               .name     = "RGB555 (LE)",
-               .fourcc   = V4L2_PIX_FMT_RGB555, /* gggbbbbb arrrrrgg */
-               .depth    = 16,
-       },
-       {
-               .name     = "RGB555 (BE)",
-               .fourcc   = V4L2_PIX_FMT_RGB555X, /* arrrrrgg gggbbbbb */
-               .depth    = 16,
-       },
-       {
-               .name     = "RGB24 (LE)",
-               .fourcc   = V4L2_PIX_FMT_RGB24, /* rgb */
-               .depth    = 24,
-       },
-       {
-               .name     = "RGB24 (BE)",
-               .fourcc   = V4L2_PIX_FMT_BGR24, /* bgr */
-               .depth    = 24,
-       },
-       {
-               .name     = "RGB32 (LE)",
-               .fourcc   = V4L2_PIX_FMT_RGB32, /* argb */
-               .depth    = 32,
-       },
-       {
-               .name     = "RGB32 (BE)",
-               .fourcc   = V4L2_PIX_FMT_BGR32, /* bgra */
-               .depth    = 32,
-       },
-};
-
-static const struct vivi_fmt *__get_format(u32 pixelformat)
-{
-       const struct vivi_fmt *fmt;
-       unsigned int k;
-
-       for (k = 0; k < ARRAY_SIZE(formats); k++) {
-               fmt = &formats[k];
-               if (fmt->fourcc == pixelformat)
-                       break;
-       }
-
-       if (k == ARRAY_SIZE(formats))
-               return NULL;
-
-       return &formats[k];
-}
-
-static const struct vivi_fmt *get_format(struct v4l2_format *f)
-{
-       return __get_format(f->fmt.pix.pixelformat);
-}
-
-/* buffer for one video frame */
-struct vivi_buffer {
-       /* common v4l buffer stuff -- must be first */
-       struct vb2_buffer       vb;
-       struct list_head        list;
-};
-
-struct vivi_dmaqueue {
-       struct list_head       active;
-
-       /* thread for generating video stream*/
-       struct task_struct         *kthread;
-       wait_queue_head_t          wq;
-       /* Counters to control fps rate */
-       int                        frame;
-       int                        ini_jiffies;
-};
-
-static LIST_HEAD(vivi_devlist);
-
-struct vivi_dev {
-       struct list_head           vivi_devlist;
-       struct v4l2_device         v4l2_dev;
-       struct v4l2_ctrl_handler   ctrl_handler;
-       struct video_device        vdev;
-
-       /* controls */
-       struct v4l2_ctrl           *brightness;
-       struct v4l2_ctrl           *contrast;
-       struct v4l2_ctrl           *saturation;
-       struct v4l2_ctrl           *hue;
-       struct {
-               /* autogain/gain cluster */
-               struct v4l2_ctrl           *autogain;
-               struct v4l2_ctrl           *gain;
-       };
-       struct v4l2_ctrl           *volume;
-       struct v4l2_ctrl           *alpha;
-       struct v4l2_ctrl           *button;
-       struct v4l2_ctrl           *boolean;
-       struct v4l2_ctrl           *int32;
-       struct v4l2_ctrl           *int64;
-       struct v4l2_ctrl           *menu;
-       struct v4l2_ctrl           *string;
-       struct v4l2_ctrl           *bitmask;
-       struct v4l2_ctrl           *int_menu;
-
-       spinlock_t                 slock;
-       struct mutex               mutex;
-
-       struct vivi_dmaqueue       vidq;
-
-       /* Several counters */
-       unsigned                   ms;
-       unsigned long              jiffies;
-       unsigned                   button_pressed;
-
-       int                        mv_count;    /* Controls bars movement */
-
-       /* Input Number */
-       int                        input;
-
-       /* video capture */
-       const struct vivi_fmt      *fmt;
-       struct v4l2_fract          timeperframe;
-       unsigned int               width, height;
-       struct vb2_queue           vb_vidq;
-       unsigned int               seq_count;
-
-       u8                         bars[9][3];
-       u8                         line[MAX_WIDTH * 8] __attribute__((__aligned__(4)));
-       unsigned int               pixelsize;
-       u8                         alpha_component;
-       u32                        textfg, textbg;
-};
-
-/* ------------------------------------------------------------------
-       DMA and thread functions
-   ------------------------------------------------------------------*/
-
-/* Bars and Colors should match positions */
-
-enum colors {
-       WHITE,
-       AMBER,
-       CYAN,
-       GREEN,
-       MAGENTA,
-       RED,
-       BLUE,
-       BLACK,
-       TEXT_BLACK,
-};
-
-/* R   G   B */
-#define COLOR_WHITE    {204, 204, 204}
-#define COLOR_AMBER    {208, 208,   0}
-#define COLOR_CYAN     {  0, 206, 206}
-#define        COLOR_GREEN     {  0, 239,   0}
-#define COLOR_MAGENTA  {239,   0, 239}
-#define COLOR_RED      {205,   0,   0}
-#define COLOR_BLUE     {  0,   0, 255}
-#define COLOR_BLACK    {  0,   0,   0}
-
-struct bar_std {
-       u8 bar[9][3];
-};
-
-/* Maximum number of bars are 10 - otherwise, the input print code
-   should be modified */
-static const struct bar_std bars[] = {
-       {       /* Standard ITU-R color bar sequence */
-               { COLOR_WHITE, COLOR_AMBER, COLOR_CYAN, COLOR_GREEN,
-                 COLOR_MAGENTA, COLOR_RED, COLOR_BLUE, COLOR_BLACK, COLOR_BLACK }
-       }, {
-               { COLOR_WHITE, COLOR_AMBER, COLOR_BLACK, COLOR_WHITE,
-                 COLOR_AMBER, COLOR_BLACK, COLOR_WHITE, COLOR_AMBER, COLOR_BLACK }
-       }, {
-               { COLOR_WHITE, COLOR_CYAN, COLOR_BLACK, COLOR_WHITE,
-                 COLOR_CYAN, COLOR_BLACK, COLOR_WHITE, COLOR_CYAN, COLOR_BLACK }
-       }, {
-               { COLOR_WHITE, COLOR_GREEN, COLOR_BLACK, COLOR_WHITE,
-                 COLOR_GREEN, COLOR_BLACK, COLOR_WHITE, COLOR_GREEN, COLOR_BLACK }
-       },
-};
-
-#define NUM_INPUTS ARRAY_SIZE(bars)
-
-#define TO_Y(r, g, b) \
-       (((16829 * r + 33039 * g + 6416 * b  + 32768) >> 16) + 16)
-/* RGB to  V(Cr) Color transform */
-#define TO_V(r, g, b) \
-       (((28784 * r - 24103 * g - 4681 * b  + 32768) >> 16) + 128)
-/* RGB to  U(Cb) Color transform */
-#define TO_U(r, g, b) \
-       (((-9714 * r - 19070 * g + 28784 * b + 32768) >> 16) + 128)
-
-/* precalculate color bar values to speed up rendering */
-static void precalculate_bars(struct vivi_dev *dev)
-{
-       u8 r, g, b;
-       int k, is_yuv;
-
-       for (k = 0; k < 9; k++) {
-               r = bars[dev->input].bar[k][0];
-               g = bars[dev->input].bar[k][1];
-               b = bars[dev->input].bar[k][2];
-               is_yuv = dev->fmt->is_yuv;
-
-               switch (dev->fmt->fourcc) {
-               case V4L2_PIX_FMT_RGB565:
-               case V4L2_PIX_FMT_RGB565X:
-                       r >>= 3;
-                       g >>= 2;
-                       b >>= 3;
-                       break;
-               case V4L2_PIX_FMT_RGB555:
-               case V4L2_PIX_FMT_RGB555X:
-                       r >>= 3;
-                       g >>= 3;
-                       b >>= 3;
-                       break;
-               case V4L2_PIX_FMT_YUYV:
-               case V4L2_PIX_FMT_UYVY:
-               case V4L2_PIX_FMT_YVYU:
-               case V4L2_PIX_FMT_VYUY:
-               case V4L2_PIX_FMT_RGB24:
-               case V4L2_PIX_FMT_BGR24:
-               case V4L2_PIX_FMT_RGB32:
-               case V4L2_PIX_FMT_BGR32:
-                       break;
-               }
-
-               if (is_yuv) {
-                       dev->bars[k][0] = TO_Y(r, g, b);        /* Luma */
-                       dev->bars[k][1] = TO_U(r, g, b);        /* Cb */
-                       dev->bars[k][2] = TO_V(r, g, b);        /* Cr */
-               } else {
-                       dev->bars[k][0] = r;
-                       dev->bars[k][1] = g;
-                       dev->bars[k][2] = b;
-               }
-       }
-}
-
-/* 'odd' is true for pixels 1, 3, 5, etc. and false for pixels 0, 2, 4, etc. */
-static void gen_twopix(struct vivi_dev *dev, u8 *buf, int colorpos, bool odd)
-{
-       u8 r_y, g_u, b_v;
-       u8 alpha = dev->alpha_component;
-       int color;
-       u8 *p;
-
-       r_y = dev->bars[colorpos][0]; /* R or precalculated Y */
-       g_u = dev->bars[colorpos][1]; /* G or precalculated U */
-       b_v = dev->bars[colorpos][2]; /* B or precalculated V */
-
-       for (color = 0; color < dev->pixelsize; color++) {
-               p = buf + color;
-
-               switch (dev->fmt->fourcc) {
-               case V4L2_PIX_FMT_YUYV:
-                       switch (color) {
-                       case 0:
-                               *p = r_y;
-                               break;
-                       case 1:
-                               *p = odd ? b_v : g_u;
-                               break;
-                       }
-                       break;
-               case V4L2_PIX_FMT_UYVY:
-                       switch (color) {
-                       case 0:
-                               *p = odd ? b_v : g_u;
-                               break;
-                       case 1:
-                               *p = r_y;
-                               break;
-                       }
-                       break;
-               case V4L2_PIX_FMT_YVYU:
-                       switch (color) {
-                       case 0:
-                               *p = r_y;
-                               break;
-                       case 1:
-                               *p = odd ? g_u : b_v;
-                               break;
-                       }
-                       break;
-               case V4L2_PIX_FMT_VYUY:
-                       switch (color) {
-                       case 0:
-                               *p = odd ? g_u : b_v;
-                               break;
-                       case 1:
-                               *p = r_y;
-                               break;
-                       }
-                       break;
-               case V4L2_PIX_FMT_RGB565:
-                       switch (color) {
-                       case 0:
-                               *p = (g_u << 5) | b_v;
-                               break;
-                       case 1:
-                               *p = (r_y << 3) | (g_u >> 3);
-                               break;
-                       }
-                       break;
-               case V4L2_PIX_FMT_RGB565X:
-                       switch (color) {
-                       case 0:
-                               *p = (r_y << 3) | (g_u >> 3);
-                               break;
-                       case 1:
-                               *p = (g_u << 5) | b_v;
-                               break;
-                       }
-                       break;
-               case V4L2_PIX_FMT_RGB555:
-                       switch (color) {
-                       case 0:
-                               *p = (g_u << 5) | b_v;
-                               break;
-                       case 1:
-                               *p = (alpha & 0x80) | (r_y << 2) | (g_u >> 3);
-                               break;
-                       }
-                       break;
-               case V4L2_PIX_FMT_RGB555X:
-                       switch (color) {
-                       case 0:
-                               *p = (alpha & 0x80) | (r_y << 2) | (g_u >> 3);
-                               break;
-                       case 1:
-                               *p = (g_u << 5) | b_v;
-                               break;
-                       }
-                       break;
-               case V4L2_PIX_FMT_RGB24:
-                       switch (color) {
-                       case 0:
-                               *p = r_y;
-                               break;
-                       case 1:
-                               *p = g_u;
-                               break;
-                       case 2:
-                               *p = b_v;
-                               break;
-                       }
-                       break;
-               case V4L2_PIX_FMT_BGR24:
-                       switch (color) {
-                       case 0:
-                               *p = b_v;
-                               break;
-                       case 1:
-                               *p = g_u;
-                               break;
-                       case 2:
-                               *p = r_y;
-                               break;
-                       }
-                       break;
-               case V4L2_PIX_FMT_RGB32:
-                       switch (color) {
-                       case 0:
-                               *p = alpha;
-                               break;
-                       case 1:
-                               *p = r_y;
-                               break;
-                       case 2:
-                               *p = g_u;
-                               break;
-                       case 3:
-                               *p = b_v;
-                               break;
-                       }
-                       break;
-               case V4L2_PIX_FMT_BGR32:
-                       switch (color) {
-                       case 0:
-                               *p = b_v;
-                               break;
-                       case 1:
-                               *p = g_u;
-                               break;
-                       case 2:
-                               *p = r_y;
-                               break;
-                       case 3:
-                               *p = alpha;
-                               break;
-                       }
-                       break;
-               }
-       }
-}
-
-static void precalculate_line(struct vivi_dev *dev)
-{
-       unsigned pixsize  = dev->pixelsize;
-       unsigned pixsize2 = 2*pixsize;
-       int colorpos;
-       u8 *pos;
-
-       for (colorpos = 0; colorpos < 16; ++colorpos) {
-               u8 pix[8];
-               int wstart =  colorpos    * dev->width / 8;
-               int wend   = (colorpos+1) * dev->width / 8;
-               int w;
-
-               gen_twopix(dev, &pix[0],        colorpos % 8, 0);
-               gen_twopix(dev, &pix[pixsize],  colorpos % 8, 1);
-
-               for (w = wstart/2*2, pos = dev->line + w*pixsize; w < wend; w += 2, pos += pixsize2)
-                       memcpy(pos, pix, pixsize2);
-       }
-}
-
-/* need this to do rgb24 rendering */
-typedef struct { u16 __; u8 _; } __attribute__((packed)) x24;
-
-static void gen_text(struct vivi_dev *dev, char *basep,
-                                       int y, int x, char *text)
-{
-       int line;
-       unsigned int width = dev->width;
-
-       /* Checks if it is possible to show string */
-       if (y + 16 >= dev->height || x + strlen(text) * 8 >= width)
-               return;
-
-       /* Print stream time */
-#define PRINTSTR(PIXTYPE) do { \
-       PIXTYPE fg;     \
-       PIXTYPE bg;     \
-       memcpy(&fg, &dev->textfg, sizeof(PIXTYPE));     \
-       memcpy(&bg, &dev->textbg, sizeof(PIXTYPE));     \
-       \
-       for (line = 0; line < 16; line++) {     \
-               PIXTYPE *pos = (PIXTYPE *)( basep + ((y + line) * width + x) * sizeof(PIXTYPE) );       \
-               u8 *s;  \
-       \
-               for (s = text; *s; s++) {       \
-                       u8 chr = font8x16[*s * 16 + line];      \
-       \
-                       pos[0] = (chr & (0x01 << 7) ? fg : bg); \
-                       pos[1] = (chr & (0x01 << 6) ? fg : bg); \
-                       pos[2] = (chr & (0x01 << 5) ? fg : bg); \
-                       pos[3] = (chr & (0x01 << 4) ? fg : bg); \
-                       pos[4] = (chr & (0x01 << 3) ? fg : bg); \
-                       pos[5] = (chr & (0x01 << 2) ? fg : bg); \
-                       pos[6] = (chr & (0x01 << 1) ? fg : bg); \
-                       pos[7] = (chr & (0x01 << 0) ? fg : bg); \
-       \
-                       pos += 8;       \
-               }       \
-       }       \
-} while (0)
-
-       switch (dev->pixelsize) {
-       case 2:
-               PRINTSTR(u16); break;
-       case 4:
-               PRINTSTR(u32); break;
-       case 3:
-               PRINTSTR(x24); break;
-       }
-}
-
-static void vivi_fillbuff(struct vivi_dev *dev, struct vivi_buffer *buf)
-{
-       int stride = dev->width * dev->pixelsize;
-       int hmax = dev->height;
-       void *vbuf = vb2_plane_vaddr(&buf->vb, 0);
-       unsigned ms;
-       char str[100];
-       int h, line = 1;
-       u8 *linestart;
-       s32 gain;
-
-       if (!vbuf)
-               return;
-
-       linestart = dev->line + (dev->mv_count % dev->width) * dev->pixelsize;
-
-       for (h = 0; h < hmax; h++)
-               memcpy(vbuf + h * stride, linestart, stride);
-
-       /* Updates stream time */
-
-       gen_twopix(dev, (u8 *)&dev->textbg, TEXT_BLACK, /*odd=*/ 0);
-       gen_twopix(dev, (u8 *)&dev->textfg, WHITE, /*odd=*/ 0);
-
-       dev->ms += jiffies_to_msecs(jiffies - dev->jiffies);
-       dev->jiffies = jiffies;
-       ms = dev->ms;
-       snprintf(str, sizeof(str), " %02d:%02d:%02d:%03d ",
-                       (ms / (60 * 60 * 1000)) % 24,
-                       (ms / (60 * 1000)) % 60,
-                       (ms / 1000) % 60,
-                       ms % 1000);
-       gen_text(dev, vbuf, line++ * 16, 16, str);
-       snprintf(str, sizeof(str), " %dx%d, input %d ",
-                       dev->width, dev->height, dev->input);
-       gen_text(dev, vbuf, line++ * 16, 16, str);
-
-       gain = v4l2_ctrl_g_ctrl(dev->gain);
-       mutex_lock(dev->ctrl_handler.lock);
-       snprintf(str, sizeof(str), " brightness %3d, contrast %3d, saturation %3d, hue %d ",
-                       dev->brightness->cur.val,
-                       dev->contrast->cur.val,
-                       dev->saturation->cur.val,
-                       dev->hue->cur.val);
-       gen_text(dev, vbuf, line++ * 16, 16, str);
-       snprintf(str, sizeof(str), " autogain %d, gain %3d, volume %3d, alpha 0x%02x ",
-                       dev->autogain->cur.val, gain, dev->volume->cur.val,
-                       dev->alpha->cur.val);
-       gen_text(dev, vbuf, line++ * 16, 16, str);
-       snprintf(str, sizeof(str), " int32 %d, int64 %lld, bitmask %08x ",
-                       dev->int32->cur.val,
-                       *dev->int64->p_cur.p_s64,
-                       dev->bitmask->cur.val);
-       gen_text(dev, vbuf, line++ * 16, 16, str);
-       snprintf(str, sizeof(str), " boolean %d, menu %s, string \"%s\" ",
-                       dev->boolean->cur.val,
-                       dev->menu->qmenu[dev->menu->cur.val],
-                       dev->string->p_cur.p_char);
-       gen_text(dev, vbuf, line++ * 16, 16, str);
-       snprintf(str, sizeof(str), " integer_menu %lld, value %d ",
-                       dev->int_menu->qmenu_int[dev->int_menu->cur.val],
-                       dev->int_menu->cur.val);
-       gen_text(dev, vbuf, line++ * 16, 16, str);
-       mutex_unlock(dev->ctrl_handler.lock);
-       if (dev->button_pressed) {
-               dev->button_pressed--;
-               snprintf(str, sizeof(str), " button pressed!");
-               gen_text(dev, vbuf, line++ * 16, 16, str);
-       }
-
-       dev->mv_count += 2;
-
-       buf->vb.v4l2_buf.field = V4L2_FIELD_INTERLACED;
-       buf->vb.v4l2_buf.sequence = dev->seq_count++;
-       v4l2_get_timestamp(&buf->vb.v4l2_buf.timestamp);
-}
-
-static void vivi_thread_tick(struct vivi_dev *dev)
-{
-       struct vivi_dmaqueue *dma_q = &dev->vidq;
-       struct vivi_buffer *buf;
-       unsigned long flags = 0;
-
-       dprintk(dev, 1, "Thread tick\n");
-
-       spin_lock_irqsave(&dev->slock, flags);
-       if (list_empty(&dma_q->active)) {
-               dprintk(dev, 1, "No active queue to serve\n");
-               spin_unlock_irqrestore(&dev->slock, flags);
-               return;
-       }
-
-       buf = list_entry(dma_q->active.next, struct vivi_buffer, list);
-       list_del(&buf->list);
-       spin_unlock_irqrestore(&dev->slock, flags);
-
-       v4l2_get_timestamp(&buf->vb.v4l2_buf.timestamp);
-
-       /* Fill buffer */
-       vivi_fillbuff(dev, buf);
-       dprintk(dev, 1, "filled buffer %p\n", buf);
-
-       vb2_buffer_done(&buf->vb, VB2_BUF_STATE_DONE);
-       dprintk(dev, 2, "[%p/%d] done\n", buf, buf->vb.v4l2_buf.index);
-}
-
-#define frames_to_ms(dev, frames)                              \
-       ((frames * dev->timeperframe.numerator * 1000) / dev->timeperframe.denominator)
-
-static void vivi_sleep(struct vivi_dev *dev)
-{
-       struct vivi_dmaqueue *dma_q = &dev->vidq;
-       int timeout;
-       DECLARE_WAITQUEUE(wait, current);
-
-       dprintk(dev, 1, "%s dma_q=0x%08lx\n", __func__,
-               (unsigned long)dma_q);
-
-       add_wait_queue(&dma_q->wq, &wait);
-       if (kthread_should_stop())
-               goto stop_task;
-
-       /* Calculate time to wake up */
-       timeout = msecs_to_jiffies(frames_to_ms(dev, 1));
-
-       vivi_thread_tick(dev);
-
-       schedule_timeout_interruptible(timeout);
-
-stop_task:
-       remove_wait_queue(&dma_q->wq, &wait);
-       try_to_freeze();
-}
-
-static int vivi_thread(void *data)
-{
-       struct vivi_dev *dev = data;
-
-       dprintk(dev, 1, "thread started\n");
-
-       set_freezable();
-
-       for (;;) {
-               vivi_sleep(dev);
-
-               if (kthread_should_stop())
-                       break;
-       }
-       dprintk(dev, 1, "thread: exit\n");
-       return 0;
-}
-
-static int vivi_start_generating(struct vivi_dev *dev)
-{
-       struct vivi_dmaqueue *dma_q = &dev->vidq;
-
-       dprintk(dev, 1, "%s\n", __func__);
-
-       /* Resets frame counters */
-       dev->ms = 0;
-       dev->mv_count = 0;
-       dev->jiffies = jiffies;
-
-       dma_q->frame = 0;
-       dma_q->ini_jiffies = jiffies;
-       dma_q->kthread = kthread_run(vivi_thread, dev, "%s",
-                                    dev->v4l2_dev.name);
-
-       if (IS_ERR(dma_q->kthread)) {
-               v4l2_err(&dev->v4l2_dev, "kernel_thread() failed\n");
-               return PTR_ERR(dma_q->kthread);
-       }
-       /* Wakes thread */
-       wake_up_interruptible(&dma_q->wq);
-
-       dprintk(dev, 1, "returning from %s\n", __func__);
-       return 0;
-}
-
-static void vivi_stop_generating(struct vivi_dev *dev)
-{
-       struct vivi_dmaqueue *dma_q = &dev->vidq;
-
-       dprintk(dev, 1, "%s\n", __func__);
-
-       /* shutdown control thread */
-       if (dma_q->kthread) {
-               kthread_stop(dma_q->kthread);
-               dma_q->kthread = NULL;
-       }
-
-       /*
-        * Typical driver might need to wait here until dma engine stops.
-        * In this case we can abort imiedetly, so it's just a noop.
-        */
-
-       /* Release all active buffers */
-       while (!list_empty(&dma_q->active)) {
-               struct vivi_buffer *buf;
-               buf = list_entry(dma_q->active.next, struct vivi_buffer, list);
-               list_del(&buf->list);
-               vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR);
-               dprintk(dev, 2, "[%p/%d] done\n", buf, buf->vb.v4l2_buf.index);
-       }
-}
-/* ------------------------------------------------------------------
-       Videobuf operations
-   ------------------------------------------------------------------*/
-static int queue_setup(struct vb2_queue *vq, const struct v4l2_format *fmt,
-                               unsigned int *nbuffers, unsigned int *nplanes,
-                               unsigned int sizes[], void *alloc_ctxs[])
-{
-       struct vivi_dev *dev = vb2_get_drv_priv(vq);
-       unsigned long size;
-
-       size = dev->width * dev->height * dev->pixelsize;
-       if (fmt) {
-               if (fmt->fmt.pix.sizeimage < size)
-                       return -EINVAL;
-               size = fmt->fmt.pix.sizeimage;
-               /* check against insane over 8K resolution buffers */
-               if (size > 7680 * 4320 * dev->pixelsize)
-                       return -EINVAL;
-       }
-
-       *nplanes = 1;
-
-       sizes[0] = size;
-
-       /*
-        * videobuf2-vmalloc allocator is context-less so no need to set
-        * alloc_ctxs array.
-        */
-
-       dprintk(dev, 1, "%s, count=%d, size=%ld\n", __func__,
-               *nbuffers, size);
-
-       return 0;
-}
-
-static int buffer_prepare(struct vb2_buffer *vb)
-{
-       struct vivi_dev *dev = vb2_get_drv_priv(vb->vb2_queue);
-       struct vivi_buffer *buf = container_of(vb, struct vivi_buffer, vb);
-       unsigned long size;
-
-       dprintk(dev, 1, "%s, field=%d\n", __func__, vb->v4l2_buf.field);
-
-       BUG_ON(NULL == dev->fmt);
-
-       /*
-        * Theses properties only change when queue is idle, see s_fmt.
-        * The below checks should not be performed here, on each
-        * buffer_prepare (i.e. on each qbuf). Most of the code in this function
-        * should thus be moved to buffer_init and s_fmt.
-        */
-       if (dev->width  < 48 || dev->width  > MAX_WIDTH ||
-           dev->height < 32 || dev->height > MAX_HEIGHT)
-               return -EINVAL;
-
-       size = dev->width * dev->height * dev->pixelsize;
-       if (vb2_plane_size(vb, 0) < size) {
-               dprintk(dev, 1, "%s data will not fit into plane (%lu < %lu)\n",
-                               __func__, vb2_plane_size(vb, 0), size);
-               return -EINVAL;
-       }
-
-       vb2_set_plane_payload(&buf->vb, 0, size);
-
-       precalculate_bars(dev);
-       precalculate_line(dev);
-
-       return 0;
-}
-
-static void buffer_queue(struct vb2_buffer *vb)
-{
-       struct vivi_dev *dev = vb2_get_drv_priv(vb->vb2_queue);
-       struct vivi_buffer *buf = container_of(vb, struct vivi_buffer, vb);
-       struct vivi_dmaqueue *vidq = &dev->vidq;
-       unsigned long flags = 0;
-
-       dprintk(dev, 1, "%s\n", __func__);
-
-       spin_lock_irqsave(&dev->slock, flags);
-       list_add_tail(&buf->list, &vidq->active);
-       spin_unlock_irqrestore(&dev->slock, flags);
-}
-
-static int start_streaming(struct vb2_queue *vq, unsigned int count)
-{
-       struct vivi_dev *dev = vb2_get_drv_priv(vq);
-       int err;
-
-       dprintk(dev, 1, "%s\n", __func__);
-       dev->seq_count = 0;
-       err = vivi_start_generating(dev);
-       if (err) {
-               struct vivi_buffer *buf, *tmp;
-
-               list_for_each_entry_safe(buf, tmp, &dev->vidq.active, list) {
-                       list_del(&buf->list);
-                       vb2_buffer_done(&buf->vb, VB2_BUF_STATE_QUEUED);
-               }
-       }
-       return err;
-}
-
-/* abort streaming and wait for last buffer */
-static void stop_streaming(struct vb2_queue *vq)
-{
-       struct vivi_dev *dev = vb2_get_drv_priv(vq);
-       dprintk(dev, 1, "%s\n", __func__);
-       vivi_stop_generating(dev);
-}
-
-static void vivi_lock(struct vb2_queue *vq)
-{
-       struct vivi_dev *dev = vb2_get_drv_priv(vq);
-       mutex_lock(&dev->mutex);
-}
-
-static void vivi_unlock(struct vb2_queue *vq)
-{
-       struct vivi_dev *dev = vb2_get_drv_priv(vq);
-       mutex_unlock(&dev->mutex);
-}
-
-
-static const struct vb2_ops vivi_video_qops = {
-       .queue_setup            = queue_setup,
-       .buf_prepare            = buffer_prepare,
-       .buf_queue              = buffer_queue,
-       .start_streaming        = start_streaming,
-       .stop_streaming         = stop_streaming,
-       .wait_prepare           = vivi_unlock,
-       .wait_finish            = vivi_lock,
-};
-
-/* ------------------------------------------------------------------
-       IOCTL vidioc handling
-   ------------------------------------------------------------------*/
-static int vidioc_querycap(struct file *file, void  *priv,
-                                       struct v4l2_capability *cap)
-{
-       struct vivi_dev *dev = video_drvdata(file);
-
-       strcpy(cap->driver, "vivi");
-       strcpy(cap->card, "vivi");
-       snprintf(cap->bus_info, sizeof(cap->bus_info),
-                       "platform:%s", dev->v4l2_dev.name);
-       cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING |
-                           V4L2_CAP_READWRITE;
-       cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
-       return 0;
-}
-
-static int vidioc_enum_fmt_vid_cap(struct file *file, void  *priv,
-                                       struct v4l2_fmtdesc *f)
-{
-       const struct vivi_fmt *fmt;
-
-       if (f->index >= ARRAY_SIZE(formats))
-               return -EINVAL;
-
-       fmt = &formats[f->index];
-
-       strlcpy(f->description, fmt->name, sizeof(f->description));
-       f->pixelformat = fmt->fourcc;
-       return 0;
-}
-
-static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
-                                       struct v4l2_format *f)
-{
-       struct vivi_dev *dev = video_drvdata(file);
-
-       f->fmt.pix.width        = dev->width;
-       f->fmt.pix.height       = dev->height;
-       f->fmt.pix.field        = V4L2_FIELD_INTERLACED;
-       f->fmt.pix.pixelformat  = dev->fmt->fourcc;
-       f->fmt.pix.bytesperline =
-               (f->fmt.pix.width * dev->fmt->depth) >> 3;
-       f->fmt.pix.sizeimage =
-               f->fmt.pix.height * f->fmt.pix.bytesperline;
-       if (dev->fmt->is_yuv)
-               f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
-       else
-               f->fmt.pix.colorspace = V4L2_COLORSPACE_SRGB;
-       return 0;
-}
-
-static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
-                       struct v4l2_format *f)
-{
-       struct vivi_dev *dev = video_drvdata(file);
-       const struct vivi_fmt *fmt;
-
-       fmt = get_format(f);
-       if (!fmt) {
-               dprintk(dev, 1, "Fourcc format (0x%08x) unknown.\n",
-                       f->fmt.pix.pixelformat);
-               f->fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
-               fmt = get_format(f);
-       }
-
-       f->fmt.pix.field = V4L2_FIELD_INTERLACED;
-       v4l_bound_align_image(&f->fmt.pix.width, 48, MAX_WIDTH, 2,
-                             &f->fmt.pix.height, 32, MAX_HEIGHT, 0, 0);
-       f->fmt.pix.bytesperline =
-               (f->fmt.pix.width * fmt->depth) >> 3;
-       f->fmt.pix.sizeimage =
-               f->fmt.pix.height * f->fmt.pix.bytesperline;
-       if (fmt->is_yuv)
-               f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
-       else
-               f->fmt.pix.colorspace = V4L2_COLORSPACE_SRGB;
-       return 0;
-}
-
-static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
-                                       struct v4l2_format *f)
-{
-       struct vivi_dev *dev = video_drvdata(file);
-       struct vb2_queue *q = &dev->vb_vidq;
-
-       int ret = vidioc_try_fmt_vid_cap(file, priv, f);
-       if (ret < 0)
-               return ret;
-
-       if (vb2_is_busy(q)) {
-               dprintk(dev, 1, "%s device busy\n", __func__);
-               return -EBUSY;
-       }
-
-       dev->fmt = get_format(f);
-       dev->pixelsize = dev->fmt->depth / 8;
-       dev->width = f->fmt.pix.width;
-       dev->height = f->fmt.pix.height;
-
-       return 0;
-}
-
-static int vidioc_enum_framesizes(struct file *file, void *fh,
-                                        struct v4l2_frmsizeenum *fsize)
-{
-       static const struct v4l2_frmsize_stepwise sizes = {
-               48, MAX_WIDTH, 4,
-               32, MAX_HEIGHT, 1
-       };
-       int i;
-
-       if (fsize->index)
-               return -EINVAL;
-       for (i = 0; i < ARRAY_SIZE(formats); i++)
-               if (formats[i].fourcc == fsize->pixel_format)
-                       break;
-       if (i == ARRAY_SIZE(formats))
-               return -EINVAL;
-       fsize->type = V4L2_FRMSIZE_TYPE_STEPWISE;
-       fsize->stepwise = sizes;
-       return 0;
-}
-
-/* only one input in this sample driver */
-static int vidioc_enum_input(struct file *file, void *priv,
-                               struct v4l2_input *inp)
-{
-       if (inp->index >= NUM_INPUTS)
-               return -EINVAL;
-
-       inp->type = V4L2_INPUT_TYPE_CAMERA;
-       sprintf(inp->name, "Camera %u", inp->index);
-       return 0;
-}
-
-static int vidioc_g_input(struct file *file, void *priv, unsigned int *i)
-{
-       struct vivi_dev *dev = video_drvdata(file);
-
-       *i = dev->input;
-       return 0;
-}
-
-static int vidioc_s_input(struct file *file, void *priv, unsigned int i)
-{
-       struct vivi_dev *dev = video_drvdata(file);
-
-       if (i >= NUM_INPUTS)
-               return -EINVAL;
-
-       if (i == dev->input)
-               return 0;
-
-       dev->input = i;
-       /*
-        * Modify the brightness range depending on the input.
-        * This makes it easy to use vivi to test if applications can
-        * handle control range modifications and is also how this is
-        * typically used in practice as different inputs may be hooked
-        * up to different receivers with different control ranges.
-        */
-       v4l2_ctrl_modify_range(dev->brightness,
-                       128 * i, 255 + 128 * i, 1, 127 + 128 * i);
-       precalculate_bars(dev);
-       precalculate_line(dev);
-       return 0;
-}
-
-/* timeperframe is arbitrary and continuous */
-static int vidioc_enum_frameintervals(struct file *file, void *priv,
-                                            struct v4l2_frmivalenum *fival)
-{
-       const struct vivi_fmt *fmt;
-
-       if (fival->index)
-               return -EINVAL;
-
-       fmt = __get_format(fival->pixel_format);
-       if (!fmt)
-               return -EINVAL;
-
-       /* check for valid width/height */
-       if (fival->width < 48 || fival->width > MAX_WIDTH || (fival->width & 3))
-               return -EINVAL;
-       if (fival->height < 32 || fival->height > MAX_HEIGHT)
-               return -EINVAL;
-
-       fival->type = V4L2_FRMIVAL_TYPE_CONTINUOUS;
-
-       /* fill in stepwise (step=1.0 is required by V4L2 spec) */
-       fival->stepwise.min  = tpf_min;
-       fival->stepwise.max  = tpf_max;
-       fival->stepwise.step = (struct v4l2_fract) {1, 1};
-
-       return 0;
-}
-
-static int vidioc_g_parm(struct file *file, void *priv,
-                         struct v4l2_streamparm *parm)
-{
-       struct vivi_dev *dev = video_drvdata(file);
-
-       if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-               return -EINVAL;
-
-       parm->parm.capture.capability   = V4L2_CAP_TIMEPERFRAME;
-       parm->parm.capture.timeperframe = dev->timeperframe;
-       parm->parm.capture.readbuffers  = 1;
-       return 0;
-}
-
-#define FRACT_CMP(a, OP, b)    \
-       ((u64)(a).numerator * (b).denominator  OP  (u64)(b).numerator * (a).denominator)
-
-static int vidioc_s_parm(struct file *file, void *priv,
-                         struct v4l2_streamparm *parm)
-{
-       struct vivi_dev *dev = video_drvdata(file);
-       struct v4l2_fract tpf;
-
-       if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-               return -EINVAL;
-
-       tpf = parm->parm.capture.timeperframe;
-
-       /* tpf: {*, 0} resets timing; clip to [min, max]*/
-       tpf = tpf.denominator ? tpf : tpf_default;
-       tpf = FRACT_CMP(tpf, <, tpf_min) ? tpf_min : tpf;
-       tpf = FRACT_CMP(tpf, >, tpf_max) ? tpf_max : tpf;
-
-       dev->timeperframe = tpf;
-       parm->parm.capture.timeperframe = tpf;
-       parm->parm.capture.readbuffers  = 1;
-       return 0;
-}
-
-/* --- controls ---------------------------------------------- */
-
-static int vivi_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
-{
-       struct vivi_dev *dev = container_of(ctrl->handler, struct vivi_dev, ctrl_handler);
-
-       if (ctrl == dev->autogain)
-               dev->gain->val = jiffies & 0xff;
-       return 0;
-}
-
-static int vivi_s_ctrl(struct v4l2_ctrl *ctrl)
-{
-       struct vivi_dev *dev = container_of(ctrl->handler, struct vivi_dev, ctrl_handler);
-
-       switch (ctrl->id) {
-       case V4L2_CID_ALPHA_COMPONENT:
-               dev->alpha_component = ctrl->val;
-               break;
-       default:
-               if (ctrl == dev->button)
-                       dev->button_pressed = 30;
-               break;
-       }
-       return 0;
-}
-
-/* ------------------------------------------------------------------
-       File operations for the device
-   ------------------------------------------------------------------*/
-
-static const struct v4l2_ctrl_ops vivi_ctrl_ops = {
-       .g_volatile_ctrl = vivi_g_volatile_ctrl,
-       .s_ctrl = vivi_s_ctrl,
-};
-
-#define VIVI_CID_CUSTOM_BASE   (V4L2_CID_USER_BASE | 0xf000)
-
-static const struct v4l2_ctrl_config vivi_ctrl_button = {
-       .ops = &vivi_ctrl_ops,
-       .id = VIVI_CID_CUSTOM_BASE + 0,
-       .name = "Button",
-       .type = V4L2_CTRL_TYPE_BUTTON,
-};
-
-static const struct v4l2_ctrl_config vivi_ctrl_boolean = {
-       .ops = &vivi_ctrl_ops,
-       .id = VIVI_CID_CUSTOM_BASE + 1,
-       .name = "Boolean",
-       .type = V4L2_CTRL_TYPE_BOOLEAN,
-       .min = 0,
-       .max = 1,
-       .step = 1,
-       .def = 1,
-};
-
-static const struct v4l2_ctrl_config vivi_ctrl_int32 = {
-       .ops = &vivi_ctrl_ops,
-       .id = VIVI_CID_CUSTOM_BASE + 2,
-       .name = "Integer 32 Bits",
-       .type = V4L2_CTRL_TYPE_INTEGER,
-       .min = -0x80000000LL,
-       .max = 0x7fffffff,
-       .step = 1,
-};
-
-static const struct v4l2_ctrl_config vivi_ctrl_int64 = {
-       .ops = &vivi_ctrl_ops,
-       .id = VIVI_CID_CUSTOM_BASE + 3,
-       .name = "Integer 64 Bits",
-       .type = V4L2_CTRL_TYPE_INTEGER64,
-       .min = LLONG_MIN,
-       .max = LLONG_MAX,
-       .step = 1,
-};
-
-static const char * const vivi_ctrl_menu_strings[] = {
-       "Menu Item 0 (Skipped)",
-       "Menu Item 1",
-       "Menu Item 2 (Skipped)",
-       "Menu Item 3",
-       "Menu Item 4",
-       "Menu Item 5 (Skipped)",
-       NULL,
-};
-
-static const struct v4l2_ctrl_config vivi_ctrl_menu = {
-       .ops = &vivi_ctrl_ops,
-       .id = VIVI_CID_CUSTOM_BASE + 4,
-       .name = "Menu",
-       .type = V4L2_CTRL_TYPE_MENU,
-       .min = 1,
-       .max = 4,
-       .def = 3,
-       .menu_skip_mask = 0x04,
-       .qmenu = vivi_ctrl_menu_strings,
-};
-
-static const struct v4l2_ctrl_config vivi_ctrl_string = {
-       .ops = &vivi_ctrl_ops,
-       .id = VIVI_CID_CUSTOM_BASE + 5,
-       .name = "String",
-       .type = V4L2_CTRL_TYPE_STRING,
-       .min = 2,
-       .max = 4,
-       .step = 1,
-};
-
-static const struct v4l2_ctrl_config vivi_ctrl_bitmask = {
-       .ops = &vivi_ctrl_ops,
-       .id = VIVI_CID_CUSTOM_BASE + 6,
-       .name = "Bitmask",
-       .type = V4L2_CTRL_TYPE_BITMASK,
-       .def = 0x80002000,
-       .min = 0,
-       .max = 0x80402010,
-       .step = 0,
-};
-
-static const s64 vivi_ctrl_int_menu_values[] = {
-       1, 1, 2, 3, 5, 8, 13, 21, 42,
-};
-
-static const struct v4l2_ctrl_config vivi_ctrl_int_menu = {
-       .ops = &vivi_ctrl_ops,
-       .id = VIVI_CID_CUSTOM_BASE + 7,
-       .name = "Integer menu",
-       .type = V4L2_CTRL_TYPE_INTEGER_MENU,
-       .min = 1,
-       .max = 8,
-       .def = 4,
-       .menu_skip_mask = 0x02,
-       .qmenu_int = vivi_ctrl_int_menu_values,
-};
-
-static const struct v4l2_file_operations vivi_fops = {
-       .owner          = THIS_MODULE,
-       .open           = v4l2_fh_open,
-       .release        = vb2_fop_release,
-       .read           = vb2_fop_read,
-       .poll           = vb2_fop_poll,
-       .unlocked_ioctl = video_ioctl2, /* V4L2 ioctl handler */
-       .mmap           = vb2_fop_mmap,
-};
-
-static const struct v4l2_ioctl_ops vivi_ioctl_ops = {
-       .vidioc_querycap      = vidioc_querycap,
-       .vidioc_enum_fmt_vid_cap  = vidioc_enum_fmt_vid_cap,
-       .vidioc_g_fmt_vid_cap     = vidioc_g_fmt_vid_cap,
-       .vidioc_try_fmt_vid_cap   = vidioc_try_fmt_vid_cap,
-       .vidioc_s_fmt_vid_cap     = vidioc_s_fmt_vid_cap,
-       .vidioc_enum_framesizes   = vidioc_enum_framesizes,
-       .vidioc_reqbufs       = vb2_ioctl_reqbufs,
-       .vidioc_create_bufs   = vb2_ioctl_create_bufs,
-       .vidioc_prepare_buf   = vb2_ioctl_prepare_buf,
-       .vidioc_querybuf      = vb2_ioctl_querybuf,
-       .vidioc_qbuf          = vb2_ioctl_qbuf,
-       .vidioc_dqbuf         = vb2_ioctl_dqbuf,
-       .vidioc_enum_input    = vidioc_enum_input,
-       .vidioc_g_input       = vidioc_g_input,
-       .vidioc_s_input       = vidioc_s_input,
-       .vidioc_enum_frameintervals = vidioc_enum_frameintervals,
-       .vidioc_g_parm        = vidioc_g_parm,
-       .vidioc_s_parm        = vidioc_s_parm,
-       .vidioc_streamon      = vb2_ioctl_streamon,
-       .vidioc_streamoff     = vb2_ioctl_streamoff,
-       .vidioc_log_status    = v4l2_ctrl_log_status,
-       .vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
-       .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
-};
-
-static const struct video_device vivi_template = {
-       .name           = "vivi",
-       .fops           = &vivi_fops,
-       .ioctl_ops      = &vivi_ioctl_ops,
-       .release        = video_device_release_empty,
-};
-
-/* -----------------------------------------------------------------
-       Initialization and module stuff
-   ------------------------------------------------------------------*/
-
-static int vivi_release(void)
-{
-       struct vivi_dev *dev;
-       struct list_head *list;
-
-       while (!list_empty(&vivi_devlist)) {
-               list = vivi_devlist.next;
-               list_del(list);
-               dev = list_entry(list, struct vivi_dev, vivi_devlist);
-
-               v4l2_info(&dev->v4l2_dev, "unregistering %s\n",
-                       video_device_node_name(&dev->vdev));
-               video_unregister_device(&dev->vdev);
-               v4l2_device_unregister(&dev->v4l2_dev);
-               v4l2_ctrl_handler_free(&dev->ctrl_handler);
-               kfree(dev);
-       }
-
-       return 0;
-}
-
-static int __init vivi_create_instance(int inst)
-{
-       struct vivi_dev *dev;
-       struct video_device *vfd;
-       struct v4l2_ctrl_handler *hdl;
-       struct vb2_queue *q;
-       int ret;
-
-       dev = kzalloc(sizeof(*dev), GFP_KERNEL);
-       if (!dev)
-               return -ENOMEM;
-
-       snprintf(dev->v4l2_dev.name, sizeof(dev->v4l2_dev.name),
-                       "%s-%03d", VIVI_MODULE_NAME, inst);
-       ret = v4l2_device_register(NULL, &dev->v4l2_dev);
-       if (ret)
-               goto free_dev;
-
-       dev->fmt = &formats[0];
-       dev->timeperframe = tpf_default;
-       dev->width = 640;
-       dev->height = 480;
-       dev->pixelsize = dev->fmt->depth / 8;
-       hdl = &dev->ctrl_handler;
-       v4l2_ctrl_handler_init(hdl, 11);
-       dev->volume = v4l2_ctrl_new_std(hdl, &vivi_ctrl_ops,
-                       V4L2_CID_AUDIO_VOLUME, 0, 255, 1, 200);
-       dev->brightness = v4l2_ctrl_new_std(hdl, &vivi_ctrl_ops,
-                       V4L2_CID_BRIGHTNESS, 0, 255, 1, 127);
-       dev->contrast = v4l2_ctrl_new_std(hdl, &vivi_ctrl_ops,
-                       V4L2_CID_CONTRAST, 0, 255, 1, 16);
-       dev->saturation = v4l2_ctrl_new_std(hdl, &vivi_ctrl_ops,
-                       V4L2_CID_SATURATION, 0, 255, 1, 127);
-       dev->hue = v4l2_ctrl_new_std(hdl, &vivi_ctrl_ops,
-                       V4L2_CID_HUE, -128, 127, 1, 0);
-       dev->autogain = v4l2_ctrl_new_std(hdl, &vivi_ctrl_ops,
-                       V4L2_CID_AUTOGAIN, 0, 1, 1, 1);
-       dev->gain = v4l2_ctrl_new_std(hdl, &vivi_ctrl_ops,
-                       V4L2_CID_GAIN, 0, 255, 1, 100);
-       dev->alpha = v4l2_ctrl_new_std(hdl, &vivi_ctrl_ops,
-                       V4L2_CID_ALPHA_COMPONENT, 0, 255, 1, 0);
-       dev->button = v4l2_ctrl_new_custom(hdl, &vivi_ctrl_button, NULL);
-       dev->int32 = v4l2_ctrl_new_custom(hdl, &vivi_ctrl_int32, NULL);
-       dev->int64 = v4l2_ctrl_new_custom(hdl, &vivi_ctrl_int64, NULL);
-       dev->boolean = v4l2_ctrl_new_custom(hdl, &vivi_ctrl_boolean, NULL);
-       dev->menu = v4l2_ctrl_new_custom(hdl, &vivi_ctrl_menu, NULL);
-       dev->string = v4l2_ctrl_new_custom(hdl, &vivi_ctrl_string, NULL);
-       dev->bitmask = v4l2_ctrl_new_custom(hdl, &vivi_ctrl_bitmask, NULL);
-       dev->int_menu = v4l2_ctrl_new_custom(hdl, &vivi_ctrl_int_menu, NULL);
-       if (hdl->error) {
-               ret = hdl->error;
-               goto unreg_dev;
-       }
-       v4l2_ctrl_auto_cluster(2, &dev->autogain, 0, true);
-       dev->v4l2_dev.ctrl_handler = hdl;
-
-       /* initialize locks */
-       spin_lock_init(&dev->slock);
-
-       /* initialize queue */
-       q = &dev->vb_vidq;
-       q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-       q->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF | VB2_READ;
-       q->drv_priv = dev;
-       q->buf_struct_size = sizeof(struct vivi_buffer);
-       q->ops = &vivi_video_qops;
-       q->mem_ops = &vb2_vmalloc_memops;
-       q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
-
-       ret = vb2_queue_init(q);
-       if (ret)
-               goto unreg_dev;
-
-       mutex_init(&dev->mutex);
-
-       /* init video dma queues */
-       INIT_LIST_HEAD(&dev->vidq.active);
-       init_waitqueue_head(&dev->vidq.wq);
-
-       vfd = &dev->vdev;
-       *vfd = vivi_template;
-       vfd->debug = debug;
-       vfd->v4l2_dev = &dev->v4l2_dev;
-       vfd->queue = q;
-
-       /*
-        * Provide a mutex to v4l2 core. It will be used to protect
-        * all fops and v4l2 ioctls.
-        */
-       vfd->lock = &dev->mutex;
-       video_set_drvdata(vfd, dev);
-
-       ret = video_register_device(vfd, VFL_TYPE_GRABBER, video_nr);
-       if (ret < 0)
-               goto unreg_dev;
-
-       /* Now that everything is fine, let's add it to device list */
-       list_add_tail(&dev->vivi_devlist, &vivi_devlist);
-
-       v4l2_info(&dev->v4l2_dev, "V4L2 device registered as %s\n",
-                 video_device_node_name(vfd));
-       return 0;
-
-unreg_dev:
-       v4l2_ctrl_handler_free(hdl);
-       v4l2_device_unregister(&dev->v4l2_dev);
-free_dev:
-       kfree(dev);
-       return ret;
-}
-
-/* This routine allocates from 1 to n_devs virtual drivers.
-
-   The real maximum number of virtual drivers will depend on how many drivers
-   will succeed. This is limited to the maximum number of devices that
-   videodev supports, which is equal to VIDEO_NUM_DEVICES.
- */
-static int __init vivi_init(void)
-{
-       const struct font_desc *font = find_font("VGA8x16");
-       int ret = 0, i;
-
-       if (font == NULL) {
-               printk(KERN_ERR "vivi: could not find font\n");
-               return -ENODEV;
-       }
-       font8x16 = font->data;
-
-       if (n_devs <= 0)
-               n_devs = 1;
-
-       for (i = 0; i < n_devs; i++) {
-               ret = vivi_create_instance(i);
-               if (ret) {
-                       /* If some instantiations succeeded, keep driver */
-                       if (i)
-                               ret = 0;
-                       break;
-               }
-       }
-
-       if (ret < 0) {
-               printk(KERN_ERR "vivi: error %d while loading driver\n", ret);
-               return ret;
-       }
-
-       printk(KERN_INFO "Video Technology Magazine Virtual Video "
-                       "Capture Board ver %s successfully loaded.\n",
-                       VIVI_VERSION);
-
-       /* n_devs will reflect the actual number of allocated devices */
-       n_devs = i;
-
-       return ret;
-}
-
-static void __exit vivi_exit(void)
-{
-       vivi_release();
-}
-
-module_init(vivi_init);
-module_exit(vivi_exit);
diff --git a/drivers/media/platform/vivid/Kconfig b/drivers/media/platform/vivid/Kconfig
new file mode 100644 (file)
index 0000000..d71139a
--- /dev/null
@@ -0,0 +1,19 @@
+config VIDEO_VIVID
+       tristate "Virtual Video Test Driver"
+       depends on VIDEO_DEV && VIDEO_V4L2 && !SPARC32 && !SPARC64
+       select FONT_SUPPORT
+       select FONT_8x16
+       select VIDEOBUF2_VMALLOC
+       default n
+       ---help---
+         Enables a virtual video driver. This driver emulates a webcam,
+         TV, S-Video and HDMI capture hardware, including VBI support for
+         the SDTV inputs. Also video output, VBI output, radio receivers,
+         transmitters and software defined radio capture is emulated.
+
+         It is highly configurable and is ideal for testing applications.
+         Error injection is supported to test rare errors that are hard
+         to reproduce in real hardware.
+
+         Say Y here if you want to test video apps or debug V4L devices.
+         When in doubt, say N.
diff --git a/drivers/media/platform/vivid/Makefile b/drivers/media/platform/vivid/Makefile
new file mode 100644 (file)
index 0000000..756fc12
--- /dev/null
@@ -0,0 +1,6 @@
+vivid-objs := vivid-core.o vivid-ctrls.o vivid-vid-common.o vivid-vbi-gen.o \
+               vivid-vid-cap.o vivid-vid-out.o vivid-kthread-cap.o vivid-kthread-out.o \
+               vivid-radio-rx.o vivid-radio-tx.o vivid-radio-common.o \
+               vivid-rds-gen.o vivid-sdr-cap.o vivid-vbi-cap.o vivid-vbi-out.o \
+               vivid-osd.o vivid-tpg.o vivid-tpg-colors.o
+obj-$(CONFIG_VIDEO_VIVID) += vivid.o
diff --git a/drivers/media/platform/vivid/vivid-core.c b/drivers/media/platform/vivid/vivid-core.c
new file mode 100644 (file)
index 0000000..2c61a62
--- /dev/null
@@ -0,0 +1,1390 @@
+/*
+ * vivid-core.c - A Virtual Video Test Driver, core initialization
+ *
+ * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
+ *
+ * This program is free software; you may redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * 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/errno.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+#include <linux/font.h>
+#include <linux/mutex.h>
+#include <linux/videodev2.h>
+#include <linux/v4l2-dv-timings.h>
+#include <media/videobuf2-vmalloc.h>
+#include <media/v4l2-dv-timings.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-fh.h>
+#include <media/v4l2-event.h>
+
+#include "vivid-core.h"
+#include "vivid-vid-common.h"
+#include "vivid-vid-cap.h"
+#include "vivid-vid-out.h"
+#include "vivid-radio-common.h"
+#include "vivid-radio-rx.h"
+#include "vivid-radio-tx.h"
+#include "vivid-sdr-cap.h"
+#include "vivid-vbi-cap.h"
+#include "vivid-vbi-out.h"
+#include "vivid-osd.h"
+#include "vivid-ctrls.h"
+
+#define VIVID_MODULE_NAME "vivid"
+
+/* The maximum number of vivid devices */
+#define VIVID_MAX_DEVS 64
+
+MODULE_DESCRIPTION("Virtual Video Test Driver");
+MODULE_AUTHOR("Hans Verkuil");
+MODULE_LICENSE("GPL");
+
+static unsigned n_devs = 1;
+module_param(n_devs, uint, 0444);
+MODULE_PARM_DESC(n_devs, " number of driver instances to create");
+
+static int vid_cap_nr[VIVID_MAX_DEVS] = { [0 ... (VIVID_MAX_DEVS - 1)] = -1 };
+module_param_array(vid_cap_nr, int, NULL, 0444);
+MODULE_PARM_DESC(vid_cap_nr, " videoX start number, -1 is autodetect");
+
+static int vid_out_nr[VIVID_MAX_DEVS] = { [0 ... (VIVID_MAX_DEVS - 1)] = -1 };
+module_param_array(vid_out_nr, int, NULL, 0444);
+MODULE_PARM_DESC(vid_out_nr, " videoX start number, -1 is autodetect");
+
+static int vbi_cap_nr[VIVID_MAX_DEVS] = { [0 ... (VIVID_MAX_DEVS - 1)] = -1 };
+module_param_array(vbi_cap_nr, int, NULL, 0444);
+MODULE_PARM_DESC(vbi_cap_nr, " vbiX start number, -1 is autodetect");
+
+static int vbi_out_nr[VIVID_MAX_DEVS] = { [0 ... (VIVID_MAX_DEVS - 1)] = -1 };
+module_param_array(vbi_out_nr, int, NULL, 0444);
+MODULE_PARM_DESC(vbi_out_nr, " vbiX start number, -1 is autodetect");
+
+static int sdr_cap_nr[VIVID_MAX_DEVS] = { [0 ... (VIVID_MAX_DEVS - 1)] = -1 };
+module_param_array(sdr_cap_nr, int, NULL, 0444);
+MODULE_PARM_DESC(sdr_cap_nr, " swradioX start number, -1 is autodetect");
+
+static int radio_rx_nr[VIVID_MAX_DEVS] = { [0 ... (VIVID_MAX_DEVS - 1)] = -1 };
+module_param_array(radio_rx_nr, int, NULL, 0444);
+MODULE_PARM_DESC(radio_rx_nr, " radioX start number, -1 is autodetect");
+
+static int radio_tx_nr[VIVID_MAX_DEVS] = { [0 ... (VIVID_MAX_DEVS - 1)] = -1 };
+module_param_array(radio_tx_nr, int, NULL, 0444);
+MODULE_PARM_DESC(radio_tx_nr, " radioX start number, -1 is autodetect");
+
+static int ccs_cap_mode[VIVID_MAX_DEVS] = { [0 ... (VIVID_MAX_DEVS - 1)] = -1 };
+module_param_array(ccs_cap_mode, int, NULL, 0444);
+MODULE_PARM_DESC(ccs_cap_mode, " capture crop/compose/scale mode:\n"
+                          "\t\t    bit 0=crop, 1=compose, 2=scale,\n"
+                          "\t\t    -1=user-controlled (default)");
+
+static int ccs_out_mode[VIVID_MAX_DEVS] = { [0 ... (VIVID_MAX_DEVS - 1)] = -1 };
+module_param_array(ccs_out_mode, int, NULL, 0444);
+MODULE_PARM_DESC(ccs_out_mode, " output crop/compose/scale mode:\n"
+                          "\t\t    bit 0=crop, 1=compose, 2=scale,\n"
+                          "\t\t    -1=user-controlled (default)");
+
+static unsigned multiplanar[VIVID_MAX_DEVS];
+module_param_array(multiplanar, uint, NULL, 0444);
+MODULE_PARM_DESC(multiplanar, " 0 (default) is alternating single and multiplanar devices,\n"
+                             "\t\t    1 is single planar devices,\n"
+                             "\t\t    2 is multiplanar devices");
+
+/* Default: video + vbi-cap (raw and sliced) + radio rx + radio tx + sdr + vbi-out + vid-out */
+static unsigned node_types[VIVID_MAX_DEVS] = { [0 ... (VIVID_MAX_DEVS - 1)] = 0x1d3d };
+module_param_array(node_types, uint, NULL, 0444);
+MODULE_PARM_DESC(node_types, " node types, default is 0x1d3d. Bitmask with the following meaning:\n"
+                            "\t\t    bit 0: Video Capture node\n"
+                            "\t\t    bit 2-3: VBI Capture node: 0 = none, 1 = raw vbi, 2 = sliced vbi, 3 = both\n"
+                            "\t\t    bit 4: Radio Receiver node\n"
+                            "\t\t    bit 5: Software Defined Radio Receiver node\n"
+                            "\t\t    bit 8: Video Output node\n"
+                            "\t\t    bit 10-11: VBI Output node: 0 = none, 1 = raw vbi, 2 = sliced vbi, 3 = both\n"
+                            "\t\t    bit 12: Radio Transmitter node\n"
+                            "\t\t    bit 16: Framebuffer for testing overlays");
+
+/* Default: 4 inputs */
+static unsigned num_inputs[VIVID_MAX_DEVS] = { [0 ... (VIVID_MAX_DEVS - 1)] = 4 };
+module_param_array(num_inputs, uint, NULL, 0444);
+MODULE_PARM_DESC(num_inputs, " number of inputs, default is 4");
+
+/* Default: input 0 = WEBCAM, 1 = TV, 2 = SVID, 3 = HDMI */
+static unsigned input_types[VIVID_MAX_DEVS] = { [0 ... (VIVID_MAX_DEVS - 1)] = 0xe4 };
+module_param_array(input_types, uint, NULL, 0444);
+MODULE_PARM_DESC(input_types, " input types, default is 0xe4. Two bits per input,\n"
+                             "\t\t    bits 0-1 == input 0, bits 31-30 == input 15.\n"
+                             "\t\t    Type 0 == webcam, 1 == TV, 2 == S-Video, 3 == HDMI");
+
+/* Default: 2 outputs */
+static unsigned num_outputs[VIVID_MAX_DEVS] = { [0 ... (VIVID_MAX_DEVS - 1)] = 2 };
+module_param_array(num_outputs, uint, NULL, 0444);
+MODULE_PARM_DESC(num_outputs, " number of outputs, default is 2");
+
+/* Default: output 0 = SVID, 1 = HDMI */
+static unsigned output_types[VIVID_MAX_DEVS] = { [0 ... (VIVID_MAX_DEVS - 1)] = 2 };
+module_param_array(output_types, uint, NULL, 0444);
+MODULE_PARM_DESC(output_types, " output types, default is 0x02. One bit per output,\n"
+                             "\t\t    bit 0 == output 0, bit 15 == output 15.\n"
+                             "\t\t    Type 0 == S-Video, 1 == HDMI");
+
+unsigned vivid_debug;
+module_param(vivid_debug, uint, 0644);
+MODULE_PARM_DESC(vivid_debug, " activates debug info");
+
+static bool no_error_inj;
+module_param(no_error_inj, bool, 0444);
+MODULE_PARM_DESC(no_error_inj, " if set disable the error injecting controls");
+
+static struct vivid_dev *vivid_devs[VIVID_MAX_DEVS];
+
+const struct v4l2_rect vivid_min_rect = {
+       0, 0, MIN_WIDTH, MIN_HEIGHT
+};
+
+const struct v4l2_rect vivid_max_rect = {
+       0, 0, MAX_WIDTH * MAX_ZOOM, MAX_HEIGHT * MAX_ZOOM
+};
+
+static const u8 vivid_hdmi_edid[256] = {
+       0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,
+       0x63, 0x3a, 0xaa, 0x55, 0x00, 0x00, 0x00, 0x00,
+       0x0a, 0x18, 0x01, 0x03, 0x80, 0x10, 0x09, 0x78,
+       0x0e, 0x00, 0xb2, 0xa0, 0x57, 0x49, 0x9b, 0x26,
+       0x10, 0x48, 0x4f, 0x2f, 0xcf, 0x00, 0x31, 0x59,
+       0x45, 0x59, 0x81, 0x80, 0x81, 0x40, 0x90, 0x40,
+       0x95, 0x00, 0xa9, 0x40, 0xb3, 0x00, 0x02, 0x3a,
+       0x80, 0x18, 0x71, 0x38, 0x2d, 0x40, 0x58, 0x2c,
+       0x46, 0x00, 0x10, 0x09, 0x00, 0x00, 0x00, 0x1e,
+       0x00, 0x00, 0x00, 0xfd, 0x00, 0x18, 0x55, 0x18,
+       0x5e, 0x11, 0x00, 0x0a, 0x20, 0x20, 0x20, 0x20,
+       0x20, 0x20, 0x00, 0x00, 0x00, 0xfc, 0x00,  'v',
+       '4',   'l',  '2',  '-',  'h',  'd',  'm',  'i',
+       0x0a, 0x0a, 0x0a, 0x0a, 0x00, 0x00, 0x00, 0x10,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xf0,
+
+       0x02, 0x03, 0x1a, 0xc0, 0x48, 0xa2, 0x10, 0x04,
+       0x02, 0x01, 0x21, 0x14, 0x13, 0x23, 0x09, 0x07,
+       0x07, 0x65, 0x03, 0x0c, 0x00, 0x10, 0x00, 0xe2,
+       0x00, 0x2a, 0x01, 0x1d, 0x00, 0x80, 0x51, 0xd0,
+       0x1c, 0x20, 0x40, 0x80, 0x35, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x1e, 0x8c, 0x0a, 0xd0, 0x8a,
+       0x20, 0xe0, 0x2d, 0x10, 0x10, 0x3e, 0x96, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd7
+};
+
+void vivid_lock(struct vb2_queue *vq)
+{
+       struct vivid_dev *dev = vb2_get_drv_priv(vq);
+
+       mutex_lock(&dev->mutex);
+}
+
+void vivid_unlock(struct vb2_queue *vq)
+{
+       struct vivid_dev *dev = vb2_get_drv_priv(vq);
+
+       mutex_unlock(&dev->mutex);
+}
+
+static int vidioc_querycap(struct file *file, void  *priv,
+                                       struct v4l2_capability *cap)
+{
+       struct vivid_dev *dev = video_drvdata(file);
+       struct video_device *vdev = video_devdata(file);
+
+       strcpy(cap->driver, "vivid");
+       strcpy(cap->card, "vivid");
+       snprintf(cap->bus_info, sizeof(cap->bus_info),
+                       "platform:%s", dev->v4l2_dev.name);
+
+       if (vdev->vfl_type == VFL_TYPE_GRABBER && vdev->vfl_dir == VFL_DIR_RX)
+               cap->device_caps = dev->vid_cap_caps;
+       if (vdev->vfl_type == VFL_TYPE_GRABBER && vdev->vfl_dir == VFL_DIR_TX)
+               cap->device_caps = dev->vid_out_caps;
+       else if (vdev->vfl_type == VFL_TYPE_VBI && vdev->vfl_dir == VFL_DIR_RX)
+               cap->device_caps = dev->vbi_cap_caps;
+       else if (vdev->vfl_type == VFL_TYPE_VBI && vdev->vfl_dir == VFL_DIR_TX)
+               cap->device_caps = dev->vbi_out_caps;
+       else if (vdev->vfl_type == VFL_TYPE_SDR)
+               cap->device_caps = dev->sdr_cap_caps;
+       else if (vdev->vfl_type == VFL_TYPE_RADIO && vdev->vfl_dir == VFL_DIR_RX)
+               cap->device_caps = dev->radio_rx_caps;
+       else if (vdev->vfl_type == VFL_TYPE_RADIO && vdev->vfl_dir == VFL_DIR_TX)
+               cap->device_caps = dev->radio_tx_caps;
+       cap->capabilities = dev->vid_cap_caps | dev->vid_out_caps |
+               dev->vbi_cap_caps | dev->vbi_out_caps |
+               dev->radio_rx_caps | dev->radio_tx_caps |
+               dev->sdr_cap_caps | V4L2_CAP_DEVICE_CAPS;
+       return 0;
+}
+
+static int vidioc_s_hw_freq_seek(struct file *file, void *fh, const struct v4l2_hw_freq_seek *a)
+{
+       struct video_device *vdev = video_devdata(file);
+
+       if (vdev->vfl_type == VFL_TYPE_RADIO)
+               return vivid_radio_rx_s_hw_freq_seek(file, fh, a);
+       return -ENOTTY;
+}
+
+static int vidioc_enum_freq_bands(struct file *file, void *fh, struct v4l2_frequency_band *band)
+{
+       struct video_device *vdev = video_devdata(file);
+
+       if (vdev->vfl_type == VFL_TYPE_RADIO)
+               return vivid_radio_rx_enum_freq_bands(file, fh, band);
+       if (vdev->vfl_type == VFL_TYPE_SDR)
+               return vivid_sdr_enum_freq_bands(file, fh, band);
+       return -ENOTTY;
+}
+
+static int vidioc_g_tuner(struct file *file, void *fh, struct v4l2_tuner *vt)
+{
+       struct video_device *vdev = video_devdata(file);
+
+       if (vdev->vfl_type == VFL_TYPE_RADIO)
+               return vivid_radio_rx_g_tuner(file, fh, vt);
+       if (vdev->vfl_type == VFL_TYPE_SDR)
+               return vivid_sdr_g_tuner(file, fh, vt);
+       return vivid_video_g_tuner(file, fh, vt);
+}
+
+static int vidioc_s_tuner(struct file *file, void *fh, const struct v4l2_tuner *vt)
+{
+       struct video_device *vdev = video_devdata(file);
+
+       if (vdev->vfl_type == VFL_TYPE_RADIO)
+               return vivid_radio_rx_s_tuner(file, fh, vt);
+       if (vdev->vfl_type == VFL_TYPE_SDR)
+               return vivid_sdr_s_tuner(file, fh, vt);
+       return vivid_video_s_tuner(file, fh, vt);
+}
+
+static int vidioc_g_frequency(struct file *file, void *fh, struct v4l2_frequency *vf)
+{
+       struct vivid_dev *dev = video_drvdata(file);
+       struct video_device *vdev = video_devdata(file);
+
+       if (vdev->vfl_type == VFL_TYPE_RADIO)
+               return vivid_radio_g_frequency(file,
+                       vdev->vfl_dir == VFL_DIR_RX ?
+                       &dev->radio_rx_freq : &dev->radio_tx_freq, vf);
+       if (vdev->vfl_type == VFL_TYPE_SDR)
+               return vivid_sdr_g_frequency(file, fh, vf);
+       return vivid_video_g_frequency(file, fh, vf);
+}
+
+static int vidioc_s_frequency(struct file *file, void *fh, const struct v4l2_frequency *vf)
+{
+       struct vivid_dev *dev = video_drvdata(file);
+       struct video_device *vdev = video_devdata(file);
+
+       if (vdev->vfl_type == VFL_TYPE_RADIO)
+               return vivid_radio_s_frequency(file,
+                       vdev->vfl_dir == VFL_DIR_RX ?
+                       &dev->radio_rx_freq : &dev->radio_tx_freq, vf);
+       if (vdev->vfl_type == VFL_TYPE_SDR)
+               return vivid_sdr_s_frequency(file, fh, vf);
+       return vivid_video_s_frequency(file, fh, vf);
+}
+
+static int vidioc_overlay(struct file *file, void *fh, unsigned i)
+{
+       struct video_device *vdev = video_devdata(file);
+
+       if (vdev->vfl_dir == VFL_DIR_RX)
+               return vivid_vid_cap_overlay(file, fh, i);
+       return vivid_vid_out_overlay(file, fh, i);
+}
+
+static int vidioc_g_fbuf(struct file *file, void *fh, struct v4l2_framebuffer *a)
+{
+       struct video_device *vdev = video_devdata(file);
+
+       if (vdev->vfl_dir == VFL_DIR_RX)
+               return vivid_vid_cap_g_fbuf(file, fh, a);
+       return vivid_vid_out_g_fbuf(file, fh, a);
+}
+
+static int vidioc_s_fbuf(struct file *file, void *fh, const struct v4l2_framebuffer *a)
+{
+       struct video_device *vdev = video_devdata(file);
+
+       if (vdev->vfl_dir == VFL_DIR_RX)
+               return vivid_vid_cap_s_fbuf(file, fh, a);
+       return vivid_vid_out_s_fbuf(file, fh, a);
+}
+
+static int vidioc_s_std(struct file *file, void *fh, v4l2_std_id id)
+{
+       struct video_device *vdev = video_devdata(file);
+
+       if (vdev->vfl_dir == VFL_DIR_RX)
+               return vivid_vid_cap_s_std(file, fh, id);
+       return vivid_vid_out_s_std(file, fh, id);
+}
+
+static int vidioc_s_dv_timings(struct file *file, void *fh, struct v4l2_dv_timings *timings)
+{
+       struct video_device *vdev = video_devdata(file);
+
+       if (vdev->vfl_dir == VFL_DIR_RX)
+               return vivid_vid_cap_s_dv_timings(file, fh, timings);
+       return vivid_vid_out_s_dv_timings(file, fh, timings);
+}
+
+static int vidioc_cropcap(struct file *file, void *fh, struct v4l2_cropcap *cc)
+{
+       struct video_device *vdev = video_devdata(file);
+
+       if (vdev->vfl_dir == VFL_DIR_RX)
+               return vivid_vid_cap_cropcap(file, fh, cc);
+       return vivid_vid_out_cropcap(file, fh, cc);
+}
+
+static int vidioc_g_selection(struct file *file, void *fh,
+                             struct v4l2_selection *sel)
+{
+       struct video_device *vdev = video_devdata(file);
+
+       if (vdev->vfl_dir == VFL_DIR_RX)
+               return vivid_vid_cap_g_selection(file, fh, sel);
+       return vivid_vid_out_g_selection(file, fh, sel);
+}
+
+static int vidioc_s_selection(struct file *file, void *fh,
+                             struct v4l2_selection *sel)
+{
+       struct video_device *vdev = video_devdata(file);
+
+       if (vdev->vfl_dir == VFL_DIR_RX)
+               return vivid_vid_cap_s_selection(file, fh, sel);
+       return vivid_vid_out_s_selection(file, fh, sel);
+}
+
+static int vidioc_g_parm(struct file *file, void *fh,
+                         struct v4l2_streamparm *parm)
+{
+       struct video_device *vdev = video_devdata(file);
+
+       if (vdev->vfl_dir == VFL_DIR_RX)
+               return vivid_vid_cap_g_parm(file, fh, parm);
+       return vivid_vid_out_g_parm(file, fh, parm);
+}
+
+static int vidioc_s_parm(struct file *file, void *fh,
+                         struct v4l2_streamparm *parm)
+{
+       struct video_device *vdev = video_devdata(file);
+
+       if (vdev->vfl_dir == VFL_DIR_RX)
+               return vivid_vid_cap_s_parm(file, fh, parm);
+       return vivid_vid_out_g_parm(file, fh, parm);
+}
+
+static ssize_t vivid_radio_read(struct file *file, char __user *buf,
+                        size_t size, loff_t *offset)
+{
+       struct video_device *vdev = video_devdata(file);
+
+       if (vdev->vfl_dir == VFL_DIR_TX)
+               return -EINVAL;
+       return vivid_radio_rx_read(file, buf, size, offset);
+}
+
+static ssize_t vivid_radio_write(struct file *file, const char __user *buf,
+                         size_t size, loff_t *offset)
+{
+       struct video_device *vdev = video_devdata(file);
+
+       if (vdev->vfl_dir == VFL_DIR_RX)
+               return -EINVAL;
+       return vivid_radio_tx_write(file, buf, size, offset);
+}
+
+static unsigned int vivid_radio_poll(struct file *file, struct poll_table_struct *wait)
+{
+       struct video_device *vdev = video_devdata(file);
+
+       if (vdev->vfl_dir == VFL_DIR_RX)
+               return vivid_radio_rx_poll(file, wait);
+       return vivid_radio_tx_poll(file, wait);
+}
+
+static bool vivid_is_in_use(struct video_device *vdev)
+{
+       unsigned long flags;
+       bool res;
+
+       spin_lock_irqsave(&vdev->fh_lock, flags);
+       res = !list_empty(&vdev->fh_list);
+       spin_unlock_irqrestore(&vdev->fh_lock, flags);
+       return res;
+}
+
+static bool vivid_is_last_user(struct vivid_dev *dev)
+{
+       unsigned uses = vivid_is_in_use(&dev->vid_cap_dev) +
+                       vivid_is_in_use(&dev->vid_out_dev) +
+                       vivid_is_in_use(&dev->vbi_cap_dev) +
+                       vivid_is_in_use(&dev->vbi_out_dev) +
+                       vivid_is_in_use(&dev->sdr_cap_dev) +
+                       vivid_is_in_use(&dev->radio_rx_dev) +
+                       vivid_is_in_use(&dev->radio_tx_dev);
+
+       return uses == 1;
+}
+
+static int vivid_fop_release(struct file *file)
+{
+       struct vivid_dev *dev = video_drvdata(file);
+       struct video_device *vdev = video_devdata(file);
+
+       mutex_lock(&dev->mutex);
+       if (!no_error_inj && v4l2_fh_is_singular_file(file) &&
+           !video_is_registered(vdev) && vivid_is_last_user(dev)) {
+               /*
+                * I am the last user of this driver, and a disconnect
+                * was forced (since this video_device is unregistered),
+                * so re-register all video_device's again.
+                */
+               v4l2_info(&dev->v4l2_dev, "reconnect\n");
+               set_bit(V4L2_FL_REGISTERED, &dev->vid_cap_dev.flags);
+               set_bit(V4L2_FL_REGISTERED, &dev->vid_out_dev.flags);
+               set_bit(V4L2_FL_REGISTERED, &dev->vbi_cap_dev.flags);
+               set_bit(V4L2_FL_REGISTERED, &dev->vbi_out_dev.flags);
+               set_bit(V4L2_FL_REGISTERED, &dev->sdr_cap_dev.flags);
+               set_bit(V4L2_FL_REGISTERED, &dev->radio_rx_dev.flags);
+               set_bit(V4L2_FL_REGISTERED, &dev->radio_tx_dev.flags);
+       }
+       mutex_unlock(&dev->mutex);
+       if (file->private_data == dev->overlay_cap_owner)
+               dev->overlay_cap_owner = NULL;
+       if (file->private_data == dev->radio_rx_rds_owner) {
+               dev->radio_rx_rds_last_block = 0;
+               dev->radio_rx_rds_owner = NULL;
+       }
+       if (file->private_data == dev->radio_tx_rds_owner) {
+               dev->radio_tx_rds_last_block = 0;
+               dev->radio_tx_rds_owner = NULL;
+       }
+       if (vdev->queue)
+               return vb2_fop_release(file);
+       return v4l2_fh_release(file);
+}
+
+static const struct v4l2_file_operations vivid_fops = {
+       .owner          = THIS_MODULE,
+       .open           = v4l2_fh_open,
+       .release        = vivid_fop_release,
+       .read           = vb2_fop_read,
+       .write          = vb2_fop_write,
+       .poll           = vb2_fop_poll,
+       .unlocked_ioctl = video_ioctl2,
+       .mmap           = vb2_fop_mmap,
+};
+
+static const struct v4l2_file_operations vivid_radio_fops = {
+       .owner          = THIS_MODULE,
+       .open           = v4l2_fh_open,
+       .release        = vivid_fop_release,
+       .read           = vivid_radio_read,
+       .write          = vivid_radio_write,
+       .poll           = vivid_radio_poll,
+       .unlocked_ioctl = video_ioctl2,
+};
+
+static const struct v4l2_ioctl_ops vivid_ioctl_ops = {
+       .vidioc_querycap                = vidioc_querycap,
+
+       .vidioc_enum_fmt_vid_cap        = vidioc_enum_fmt_vid,
+       .vidioc_g_fmt_vid_cap           = vidioc_g_fmt_vid_cap,
+       .vidioc_try_fmt_vid_cap         = vidioc_try_fmt_vid_cap,
+       .vidioc_s_fmt_vid_cap           = vidioc_s_fmt_vid_cap,
+       .vidioc_enum_fmt_vid_cap_mplane = vidioc_enum_fmt_vid_mplane,
+       .vidioc_g_fmt_vid_cap_mplane    = vidioc_g_fmt_vid_cap_mplane,
+       .vidioc_try_fmt_vid_cap_mplane  = vidioc_try_fmt_vid_cap_mplane,
+       .vidioc_s_fmt_vid_cap_mplane    = vidioc_s_fmt_vid_cap_mplane,
+
+       .vidioc_enum_fmt_vid_out        = vidioc_enum_fmt_vid,
+       .vidioc_g_fmt_vid_out           = vidioc_g_fmt_vid_out,
+       .vidioc_try_fmt_vid_out         = vidioc_try_fmt_vid_out,
+       .vidioc_s_fmt_vid_out           = vidioc_s_fmt_vid_out,
+       .vidioc_enum_fmt_vid_out_mplane = vidioc_enum_fmt_vid_mplane,
+       .vidioc_g_fmt_vid_out_mplane    = vidioc_g_fmt_vid_out_mplane,
+       .vidioc_try_fmt_vid_out_mplane  = vidioc_try_fmt_vid_out_mplane,
+       .vidioc_s_fmt_vid_out_mplane    = vidioc_s_fmt_vid_out_mplane,
+
+       .vidioc_g_selection             = vidioc_g_selection,
+       .vidioc_s_selection             = vidioc_s_selection,
+       .vidioc_cropcap                 = vidioc_cropcap,
+
+       .vidioc_g_fmt_vbi_cap           = vidioc_g_fmt_vbi_cap,
+       .vidioc_try_fmt_vbi_cap         = vidioc_g_fmt_vbi_cap,
+       .vidioc_s_fmt_vbi_cap           = vidioc_s_fmt_vbi_cap,
+
+       .vidioc_g_fmt_sliced_vbi_cap    = vidioc_g_fmt_sliced_vbi_cap,
+       .vidioc_try_fmt_sliced_vbi_cap  = vidioc_try_fmt_sliced_vbi_cap,
+       .vidioc_s_fmt_sliced_vbi_cap    = vidioc_s_fmt_sliced_vbi_cap,
+       .vidioc_g_sliced_vbi_cap        = vidioc_g_sliced_vbi_cap,
+
+       .vidioc_g_fmt_vbi_out           = vidioc_g_fmt_vbi_out,
+       .vidioc_try_fmt_vbi_out         = vidioc_g_fmt_vbi_out,
+       .vidioc_s_fmt_vbi_out           = vidioc_s_fmt_vbi_out,
+
+       .vidioc_g_fmt_sliced_vbi_out    = vidioc_g_fmt_sliced_vbi_out,
+       .vidioc_try_fmt_sliced_vbi_out  = vidioc_try_fmt_sliced_vbi_out,
+       .vidioc_s_fmt_sliced_vbi_out    = vidioc_s_fmt_sliced_vbi_out,
+
+       .vidioc_enum_fmt_sdr_cap        = vidioc_enum_fmt_sdr_cap,
+       .vidioc_g_fmt_sdr_cap           = vidioc_g_fmt_sdr_cap,
+       .vidioc_try_fmt_sdr_cap         = vidioc_g_fmt_sdr_cap,
+       .vidioc_s_fmt_sdr_cap           = vidioc_g_fmt_sdr_cap,
+
+       .vidioc_overlay                 = vidioc_overlay,
+       .vidioc_enum_framesizes         = vidioc_enum_framesizes,
+       .vidioc_enum_frameintervals     = vidioc_enum_frameintervals,
+       .vidioc_g_parm                  = vidioc_g_parm,
+       .vidioc_s_parm                  = vidioc_s_parm,
+
+       .vidioc_enum_fmt_vid_overlay    = vidioc_enum_fmt_vid_overlay,
+       .vidioc_g_fmt_vid_overlay       = vidioc_g_fmt_vid_overlay,
+       .vidioc_try_fmt_vid_overlay     = vidioc_try_fmt_vid_overlay,
+       .vidioc_s_fmt_vid_overlay       = vidioc_s_fmt_vid_overlay,
+       .vidioc_g_fmt_vid_out_overlay   = vidioc_g_fmt_vid_out_overlay,
+       .vidioc_try_fmt_vid_out_overlay = vidioc_try_fmt_vid_out_overlay,
+       .vidioc_s_fmt_vid_out_overlay   = vidioc_s_fmt_vid_out_overlay,
+       .vidioc_g_fbuf                  = vidioc_g_fbuf,
+       .vidioc_s_fbuf                  = vidioc_s_fbuf,
+
+       .vidioc_reqbufs                 = vb2_ioctl_reqbufs,
+       .vidioc_create_bufs             = vb2_ioctl_create_bufs,
+       .vidioc_prepare_buf             = vb2_ioctl_prepare_buf,
+       .vidioc_querybuf                = vb2_ioctl_querybuf,
+       .vidioc_qbuf                    = vb2_ioctl_qbuf,
+       .vidioc_dqbuf                   = vb2_ioctl_dqbuf,
+/* Not yet     .vidioc_expbuf          = vb2_ioctl_expbuf,*/
+       .vidioc_streamon                = vb2_ioctl_streamon,
+       .vidioc_streamoff               = vb2_ioctl_streamoff,
+
+       .vidioc_enum_input              = vidioc_enum_input,
+       .vidioc_g_input                 = vidioc_g_input,
+       .vidioc_s_input                 = vidioc_s_input,
+       .vidioc_s_audio                 = vidioc_s_audio,
+       .vidioc_g_audio                 = vidioc_g_audio,
+       .vidioc_enumaudio               = vidioc_enumaudio,
+       .vidioc_s_frequency             = vidioc_s_frequency,
+       .vidioc_g_frequency             = vidioc_g_frequency,
+       .vidioc_s_tuner                 = vidioc_s_tuner,
+       .vidioc_g_tuner                 = vidioc_g_tuner,
+       .vidioc_s_modulator             = vidioc_s_modulator,
+       .vidioc_g_modulator             = vidioc_g_modulator,
+       .vidioc_s_hw_freq_seek          = vidioc_s_hw_freq_seek,
+       .vidioc_enum_freq_bands         = vidioc_enum_freq_bands,
+
+       .vidioc_enum_output             = vidioc_enum_output,
+       .vidioc_g_output                = vidioc_g_output,
+       .vidioc_s_output                = vidioc_s_output,
+       .vidioc_s_audout                = vidioc_s_audout,
+       .vidioc_g_audout                = vidioc_g_audout,
+       .vidioc_enumaudout              = vidioc_enumaudout,
+
+       .vidioc_querystd                = vidioc_querystd,
+       .vidioc_g_std                   = vidioc_g_std,
+       .vidioc_s_std                   = vidioc_s_std,
+       .vidioc_s_dv_timings            = vidioc_s_dv_timings,
+       .vidioc_g_dv_timings            = vidioc_g_dv_timings,
+       .vidioc_query_dv_timings        = vidioc_query_dv_timings,
+       .vidioc_enum_dv_timings         = vidioc_enum_dv_timings,
+       .vidioc_dv_timings_cap          = vidioc_dv_timings_cap,
+       .vidioc_g_edid                  = vidioc_g_edid,
+       .vidioc_s_edid                  = vidioc_s_edid,
+
+       .vidioc_log_status              = v4l2_ctrl_log_status,
+       .vidioc_subscribe_event         = vidioc_subscribe_event,
+       .vidioc_unsubscribe_event       = v4l2_event_unsubscribe,
+};
+
+/* -----------------------------------------------------------------
+       Initialization and module stuff
+   ------------------------------------------------------------------*/
+
+static int __init vivid_create_instance(int inst)
+{
+       static const struct v4l2_dv_timings def_dv_timings =
+                                       V4L2_DV_BT_CEA_1280X720P60;
+       unsigned in_type_counter[4] = { 0, 0, 0, 0 };
+       unsigned out_type_counter[4] = { 0, 0, 0, 0 };
+       int ccs_cap = ccs_cap_mode[inst];
+       int ccs_out = ccs_out_mode[inst];
+       bool has_tuner;
+       bool has_modulator;
+       struct vivid_dev *dev;
+       struct video_device *vfd;
+       struct vb2_queue *q;
+       unsigned node_type = node_types[inst];
+       v4l2_std_id tvnorms_cap = 0, tvnorms_out = 0;
+       int ret;
+       int i;
+
+       /* allocate main vivid state structure */
+       dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+       if (!dev)
+               return -ENOMEM;
+
+       dev->inst = inst;
+
+       /* register v4l2_device */
+       snprintf(dev->v4l2_dev.name, sizeof(dev->v4l2_dev.name),
+                       "%s-%03d", VIVID_MODULE_NAME, inst);
+       ret = v4l2_device_register(NULL, &dev->v4l2_dev);
+       if (ret)
+               goto free_dev;
+
+       /* start detecting feature set */
+
+       /* do we use single- or multi-planar? */
+       if (multiplanar[inst] == 0)
+               dev->multiplanar = inst & 1;
+       else
+               dev->multiplanar = multiplanar[inst] > 1;
+       v4l2_info(&dev->v4l2_dev, "using %splanar format API\n",
+                       dev->multiplanar ? "multi" : "single ");
+
+       /* how many inputs do we have and of what type? */
+       dev->num_inputs = num_inputs[inst];
+       if (dev->num_inputs < 1)
+               dev->num_inputs = 1;
+       if (dev->num_inputs >= MAX_INPUTS)
+               dev->num_inputs = MAX_INPUTS;
+       for (i = 0; i < dev->num_inputs; i++) {
+               dev->input_type[i] = (input_types[inst] >> (i * 2)) & 0x3;
+               dev->input_name_counter[i] = in_type_counter[dev->input_type[i]]++;
+       }
+       dev->has_audio_inputs = in_type_counter[TV] && in_type_counter[SVID];
+
+       /* how many outputs do we have and of what type? */
+       dev->num_outputs = num_outputs[inst];
+       if (dev->num_outputs < 1)
+               dev->num_outputs = 1;
+       if (dev->num_outputs >= MAX_OUTPUTS)
+               dev->num_outputs = MAX_OUTPUTS;
+       for (i = 0; i < dev->num_outputs; i++) {
+               dev->output_type[i] = ((output_types[inst] >> i) & 1) ? HDMI : SVID;
+               dev->output_name_counter[i] = out_type_counter[dev->output_type[i]]++;
+       }
+       dev->has_audio_outputs = out_type_counter[SVID];
+
+       /* do we create a video capture device? */
+       dev->has_vid_cap = node_type & 0x0001;
+
+       /* do we create a vbi capture device? */
+       if (in_type_counter[TV] || in_type_counter[SVID]) {
+               dev->has_raw_vbi_cap = node_type & 0x0004;
+               dev->has_sliced_vbi_cap = node_type & 0x0008;
+               dev->has_vbi_cap = dev->has_raw_vbi_cap | dev->has_sliced_vbi_cap;
+       }
+
+       /* do we create a video output device? */
+       dev->has_vid_out = node_type & 0x0100;
+
+       /* do we create a vbi output device? */
+       if (out_type_counter[SVID]) {
+               dev->has_raw_vbi_out = node_type & 0x0400;
+               dev->has_sliced_vbi_out = node_type & 0x0800;
+               dev->has_vbi_out = dev->has_raw_vbi_out | dev->has_sliced_vbi_out;
+       }
+
+       /* do we create a radio receiver device? */
+       dev->has_radio_rx = node_type & 0x0010;
+
+       /* do we create a radio transmitter device? */
+       dev->has_radio_tx = node_type & 0x1000;
+
+       /* do we create a software defined radio capture device? */
+       dev->has_sdr_cap = node_type & 0x0020;
+
+       /* do we have a tuner? */
+       has_tuner = ((dev->has_vid_cap || dev->has_vbi_cap) && in_type_counter[TV]) ||
+                   dev->has_radio_rx || dev->has_sdr_cap;
+
+       /* do we have a modulator? */
+       has_modulator = dev->has_radio_tx;
+
+       if (dev->has_vid_cap)
+               /* do we have a framebuffer for overlay testing? */
+               dev->has_fb = node_type & 0x10000;
+
+       /* can we do crop/compose/scaling while capturing? */
+       if (no_error_inj && ccs_cap == -1)
+               ccs_cap = 7;
+
+       /* if ccs_cap == -1, then the use can select it using controls */
+       if (ccs_cap != -1) {
+               dev->has_crop_cap = ccs_cap & 1;
+               dev->has_compose_cap = ccs_cap & 2;
+               dev->has_scaler_cap = ccs_cap & 4;
+               v4l2_info(&dev->v4l2_dev, "Capture Crop: %c Compose: %c Scaler: %c\n",
+                       dev->has_crop_cap ? 'Y' : 'N',
+                       dev->has_compose_cap ? 'Y' : 'N',
+                       dev->has_scaler_cap ? 'Y' : 'N');
+       }
+
+       /* can we do crop/compose/scaling with video output? */
+       if (no_error_inj && ccs_out == -1)
+               ccs_out = 7;
+
+       /* if ccs_out == -1, then the use can select it using controls */
+       if (ccs_out != -1) {
+               dev->has_crop_out = ccs_out & 1;
+               dev->has_compose_out = ccs_out & 2;
+               dev->has_scaler_out = ccs_out & 4;
+               v4l2_info(&dev->v4l2_dev, "Output Crop: %c Compose: %c Scaler: %c\n",
+                       dev->has_crop_out ? 'Y' : 'N',
+                       dev->has_compose_out ? 'Y' : 'N',
+                       dev->has_scaler_out ? 'Y' : 'N');
+       }
+
+       /* end detecting feature set */
+
+       if (dev->has_vid_cap) {
+               /* set up the capabilities of the video capture device */
+               dev->vid_cap_caps = dev->multiplanar ?
+                       V4L2_CAP_VIDEO_CAPTURE_MPLANE :
+                       V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_OVERLAY;
+               dev->vid_cap_caps |= V4L2_CAP_STREAMING | V4L2_CAP_READWRITE;
+               if (dev->has_audio_inputs)
+                       dev->vid_cap_caps |= V4L2_CAP_AUDIO;
+               if (in_type_counter[TV])
+                       dev->vid_cap_caps |= V4L2_CAP_TUNER;
+       }
+       if (dev->has_vid_out) {
+               /* set up the capabilities of the video output device */
+               dev->vid_out_caps = dev->multiplanar ?
+                       V4L2_CAP_VIDEO_OUTPUT_MPLANE :
+                       V4L2_CAP_VIDEO_OUTPUT;
+               if (dev->has_fb)
+                       dev->vid_out_caps |= V4L2_CAP_VIDEO_OUTPUT_OVERLAY;
+               dev->vid_out_caps |= V4L2_CAP_STREAMING | V4L2_CAP_READWRITE;
+               if (dev->has_audio_outputs)
+                       dev->vid_out_caps |= V4L2_CAP_AUDIO;
+       }
+       if (dev->has_vbi_cap) {
+               /* set up the capabilities of the vbi capture device */
+               dev->vbi_cap_caps = (dev->has_raw_vbi_cap ? V4L2_CAP_VBI_CAPTURE : 0) |
+                                   (dev->has_sliced_vbi_cap ? V4L2_CAP_SLICED_VBI_CAPTURE : 0);
+               dev->vbi_cap_caps |= V4L2_CAP_STREAMING | V4L2_CAP_READWRITE;
+               if (dev->has_audio_inputs)
+                       dev->vbi_cap_caps |= V4L2_CAP_AUDIO;
+               if (in_type_counter[TV])
+                       dev->vbi_cap_caps |= V4L2_CAP_TUNER;
+       }
+       if (dev->has_vbi_out) {
+               /* set up the capabilities of the vbi output device */
+               dev->vbi_out_caps = (dev->has_raw_vbi_out ? V4L2_CAP_VBI_OUTPUT : 0) |
+                                   (dev->has_sliced_vbi_out ? V4L2_CAP_SLICED_VBI_OUTPUT : 0);
+               dev->vbi_out_caps |= V4L2_CAP_STREAMING | V4L2_CAP_READWRITE;
+               if (dev->has_audio_outputs)
+                       dev->vbi_out_caps |= V4L2_CAP_AUDIO;
+       }
+       if (dev->has_sdr_cap) {
+               /* set up the capabilities of the sdr capture device */
+               dev->sdr_cap_caps = V4L2_CAP_SDR_CAPTURE | V4L2_CAP_TUNER;
+               dev->sdr_cap_caps |= V4L2_CAP_STREAMING | V4L2_CAP_READWRITE;
+       }
+       /* set up the capabilities of the radio receiver device */
+       if (dev->has_radio_rx)
+               dev->radio_rx_caps = V4L2_CAP_RADIO | V4L2_CAP_RDS_CAPTURE |
+                                    V4L2_CAP_HW_FREQ_SEEK | V4L2_CAP_TUNER |
+                                    V4L2_CAP_READWRITE;
+       /* set up the capabilities of the radio transmitter device */
+       if (dev->has_radio_tx)
+               dev->radio_tx_caps = V4L2_CAP_RDS_OUTPUT | V4L2_CAP_MODULATOR |
+                                    V4L2_CAP_READWRITE;
+
+       /* initialize the test pattern generator */
+       tpg_init(&dev->tpg, 640, 360);
+       if (tpg_alloc(&dev->tpg, MAX_ZOOM * MAX_WIDTH))
+               goto free_dev;
+       dev->scaled_line = vzalloc(MAX_ZOOM * MAX_WIDTH);
+       if (!dev->scaled_line)
+               goto free_dev;
+       dev->blended_line = vzalloc(MAX_ZOOM * MAX_WIDTH);
+       if (!dev->blended_line)
+               goto free_dev;
+
+       /* load the edid */
+       dev->edid = vmalloc(256 * 128);
+       if (!dev->edid)
+               goto free_dev;
+
+       /* create a string array containing the names of all the preset timings */
+       while (v4l2_dv_timings_presets[dev->query_dv_timings_size].bt.width)
+               dev->query_dv_timings_size++;
+       dev->query_dv_timings_qmenu = kmalloc(dev->query_dv_timings_size *
+                                          (sizeof(void *) + 32), GFP_KERNEL);
+       if (dev->query_dv_timings_qmenu == NULL)
+               goto free_dev;
+       for (i = 0; i < dev->query_dv_timings_size; i++) {
+               const struct v4l2_bt_timings *bt = &v4l2_dv_timings_presets[i].bt;
+               char *p = (char *)&dev->query_dv_timings_qmenu[dev->query_dv_timings_size];
+               u32 htot, vtot;
+
+               p += i * 32;
+               dev->query_dv_timings_qmenu[i] = p;
+
+               htot = V4L2_DV_BT_FRAME_WIDTH(bt);
+               vtot = V4L2_DV_BT_FRAME_HEIGHT(bt);
+               snprintf(p, 32, "%ux%u%s%u",
+                       bt->width, bt->height, bt->interlaced ? "i" : "p",
+                       (u32)bt->pixelclock / (htot * vtot));
+       }
+
+       /* disable invalid ioctls based on the feature set */
+       if (!dev->has_audio_inputs) {
+               v4l2_disable_ioctl(&dev->vid_cap_dev, VIDIOC_S_AUDIO);
+               v4l2_disable_ioctl(&dev->vid_cap_dev, VIDIOC_G_AUDIO);
+               v4l2_disable_ioctl(&dev->vid_cap_dev, VIDIOC_ENUMAUDIO);
+               v4l2_disable_ioctl(&dev->vbi_cap_dev, VIDIOC_S_AUDIO);
+               v4l2_disable_ioctl(&dev->vbi_cap_dev, VIDIOC_G_AUDIO);
+               v4l2_disable_ioctl(&dev->vbi_cap_dev, VIDIOC_ENUMAUDIO);
+       }
+       if (!dev->has_audio_outputs) {
+               v4l2_disable_ioctl(&dev->vid_out_dev, VIDIOC_S_AUDOUT);
+               v4l2_disable_ioctl(&dev->vid_out_dev, VIDIOC_G_AUDOUT);
+               v4l2_disable_ioctl(&dev->vid_out_dev, VIDIOC_ENUMAUDOUT);
+               v4l2_disable_ioctl(&dev->vbi_out_dev, VIDIOC_S_AUDOUT);
+               v4l2_disable_ioctl(&dev->vbi_out_dev, VIDIOC_G_AUDOUT);
+               v4l2_disable_ioctl(&dev->vbi_out_dev, VIDIOC_ENUMAUDOUT);
+       }
+       if (!in_type_counter[TV] && !in_type_counter[SVID]) {
+               v4l2_disable_ioctl(&dev->vid_cap_dev, VIDIOC_S_STD);
+               v4l2_disable_ioctl(&dev->vid_cap_dev, VIDIOC_G_STD);
+               v4l2_disable_ioctl(&dev->vid_cap_dev, VIDIOC_ENUMSTD);
+               v4l2_disable_ioctl(&dev->vid_cap_dev, VIDIOC_QUERYSTD);
+       }
+       if (!out_type_counter[SVID]) {
+               v4l2_disable_ioctl(&dev->vid_out_dev, VIDIOC_S_STD);
+               v4l2_disable_ioctl(&dev->vid_out_dev, VIDIOC_G_STD);
+               v4l2_disable_ioctl(&dev->vid_out_dev, VIDIOC_ENUMSTD);
+       }
+       if (!has_tuner && !has_modulator) {
+               v4l2_disable_ioctl(&dev->vid_cap_dev, VIDIOC_S_FREQUENCY);
+               v4l2_disable_ioctl(&dev->vid_cap_dev, VIDIOC_G_FREQUENCY);
+               v4l2_disable_ioctl(&dev->vbi_cap_dev, VIDIOC_S_FREQUENCY);
+               v4l2_disable_ioctl(&dev->vbi_cap_dev, VIDIOC_G_FREQUENCY);
+       }
+       if (!has_tuner) {
+               v4l2_disable_ioctl(&dev->vid_cap_dev, VIDIOC_S_TUNER);
+               v4l2_disable_ioctl(&dev->vid_cap_dev, VIDIOC_G_TUNER);
+               v4l2_disable_ioctl(&dev->vbi_cap_dev, VIDIOC_S_TUNER);
+               v4l2_disable_ioctl(&dev->vbi_cap_dev, VIDIOC_G_TUNER);
+       }
+       if (in_type_counter[HDMI] == 0) {
+               v4l2_disable_ioctl(&dev->vid_cap_dev, VIDIOC_S_EDID);
+               v4l2_disable_ioctl(&dev->vid_cap_dev, VIDIOC_G_EDID);
+               v4l2_disable_ioctl(&dev->vid_cap_dev, VIDIOC_DV_TIMINGS_CAP);
+               v4l2_disable_ioctl(&dev->vid_cap_dev, VIDIOC_G_DV_TIMINGS);
+               v4l2_disable_ioctl(&dev->vid_cap_dev, VIDIOC_S_DV_TIMINGS);
+               v4l2_disable_ioctl(&dev->vid_cap_dev, VIDIOC_ENUM_DV_TIMINGS);
+               v4l2_disable_ioctl(&dev->vid_cap_dev, VIDIOC_QUERY_DV_TIMINGS);
+       }
+       if (out_type_counter[HDMI] == 0) {
+               v4l2_disable_ioctl(&dev->vid_out_dev, VIDIOC_G_EDID);
+               v4l2_disable_ioctl(&dev->vid_out_dev, VIDIOC_DV_TIMINGS_CAP);
+               v4l2_disable_ioctl(&dev->vid_out_dev, VIDIOC_G_DV_TIMINGS);
+               v4l2_disable_ioctl(&dev->vid_out_dev, VIDIOC_S_DV_TIMINGS);
+               v4l2_disable_ioctl(&dev->vid_out_dev, VIDIOC_ENUM_DV_TIMINGS);
+       }
+       if (!dev->has_fb) {
+               v4l2_disable_ioctl(&dev->vid_out_dev, VIDIOC_G_FBUF);
+               v4l2_disable_ioctl(&dev->vid_out_dev, VIDIOC_S_FBUF);
+               v4l2_disable_ioctl(&dev->vid_out_dev, VIDIOC_OVERLAY);
+       }
+       v4l2_disable_ioctl(&dev->vid_cap_dev, VIDIOC_S_HW_FREQ_SEEK);
+       v4l2_disable_ioctl(&dev->vbi_cap_dev, VIDIOC_S_HW_FREQ_SEEK);
+       v4l2_disable_ioctl(&dev->sdr_cap_dev, VIDIOC_S_HW_FREQ_SEEK);
+       v4l2_disable_ioctl(&dev->vid_out_dev, VIDIOC_S_FREQUENCY);
+       v4l2_disable_ioctl(&dev->vid_out_dev, VIDIOC_G_FREQUENCY);
+       v4l2_disable_ioctl(&dev->vid_out_dev, VIDIOC_ENUM_FRAMESIZES);
+       v4l2_disable_ioctl(&dev->vid_out_dev, VIDIOC_ENUM_FRAMEINTERVALS);
+       v4l2_disable_ioctl(&dev->vbi_out_dev, VIDIOC_S_FREQUENCY);
+       v4l2_disable_ioctl(&dev->vbi_out_dev, VIDIOC_G_FREQUENCY);
+
+       /* configure internal data */
+       dev->fmt_cap = &vivid_formats[0];
+       dev->fmt_out = &vivid_formats[0];
+       if (!dev->multiplanar)
+               vivid_formats[0].data_offset[0] = 0;
+       dev->webcam_size_idx = 1;
+       dev->webcam_ival_idx = 3;
+       tpg_s_fourcc(&dev->tpg, dev->fmt_cap->fourcc);
+       dev->std_cap = V4L2_STD_PAL;
+       dev->std_out = V4L2_STD_PAL;
+       if (dev->input_type[0] == TV || dev->input_type[0] == SVID)
+               tvnorms_cap = V4L2_STD_ALL;
+       if (dev->output_type[0] == SVID)
+               tvnorms_out = V4L2_STD_ALL;
+       dev->dv_timings_cap = def_dv_timings;
+       dev->dv_timings_out = def_dv_timings;
+       dev->tv_freq = 2804 /* 175.25 * 16 */;
+       dev->tv_audmode = V4L2_TUNER_MODE_STEREO;
+       dev->tv_field_cap = V4L2_FIELD_INTERLACED;
+       dev->tv_field_out = V4L2_FIELD_INTERLACED;
+       dev->radio_rx_freq = 95000 * 16;
+       dev->radio_rx_audmode = V4L2_TUNER_MODE_STEREO;
+       if (dev->has_radio_tx) {
+               dev->radio_tx_freq = 95500 * 16;
+               dev->radio_rds_loop = false;
+       }
+       dev->radio_tx_subchans = V4L2_TUNER_SUB_STEREO | V4L2_TUNER_SUB_RDS;
+       dev->sdr_adc_freq = 300000;
+       dev->sdr_fm_freq = 50000000;
+       dev->edid_max_blocks = dev->edid_blocks = 2;
+       memcpy(dev->edid, vivid_hdmi_edid, sizeof(vivid_hdmi_edid));
+       ktime_get_ts(&dev->radio_rds_init_ts);
+
+       /* create all controls */
+       ret = vivid_create_controls(dev, ccs_cap == -1, ccs_out == -1, no_error_inj,
+                       in_type_counter[TV] || in_type_counter[SVID] ||
+                       out_type_counter[SVID],
+                       in_type_counter[HDMI] || out_type_counter[HDMI]);
+       if (ret)
+               goto unreg_dev;
+
+       /*
+        * update the capture and output formats to do a proper initial
+        * configuration.
+        */
+       vivid_update_format_cap(dev, false);
+       vivid_update_format_out(dev);
+
+       v4l2_ctrl_handler_setup(&dev->ctrl_hdl_vid_cap);
+       v4l2_ctrl_handler_setup(&dev->ctrl_hdl_vid_out);
+       v4l2_ctrl_handler_setup(&dev->ctrl_hdl_vbi_cap);
+       v4l2_ctrl_handler_setup(&dev->ctrl_hdl_vbi_out);
+       v4l2_ctrl_handler_setup(&dev->ctrl_hdl_radio_rx);
+       v4l2_ctrl_handler_setup(&dev->ctrl_hdl_radio_tx);
+       v4l2_ctrl_handler_setup(&dev->ctrl_hdl_sdr_cap);
+
+       /* initialize overlay */
+       dev->fb_cap.fmt.width = dev->src_rect.width;
+       dev->fb_cap.fmt.height = dev->src_rect.height;
+       dev->fb_cap.fmt.pixelformat = dev->fmt_cap->fourcc;
+       dev->fb_cap.fmt.bytesperline = dev->src_rect.width * tpg_g_twopixelsize(&dev->tpg, 0) / 2;
+       dev->fb_cap.fmt.sizeimage = dev->src_rect.height * dev->fb_cap.fmt.bytesperline;
+
+       /* initialize locks */
+       spin_lock_init(&dev->slock);
+       mutex_init(&dev->mutex);
+
+       /* init dma queues */
+       INIT_LIST_HEAD(&dev->vid_cap_active);
+       INIT_LIST_HEAD(&dev->vid_out_active);
+       INIT_LIST_HEAD(&dev->vbi_cap_active);
+       INIT_LIST_HEAD(&dev->vbi_out_active);
+       INIT_LIST_HEAD(&dev->sdr_cap_active);
+
+       /* start creating the vb2 queues */
+       if (dev->has_vid_cap) {
+               /* initialize vid_cap queue */
+               q = &dev->vb_vid_cap_q;
+               q->type = dev->multiplanar ? V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE :
+                       V4L2_BUF_TYPE_VIDEO_CAPTURE;
+               q->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF | VB2_READ;
+               q->drv_priv = dev;
+               q->buf_struct_size = sizeof(struct vivid_buffer);
+               q->ops = &vivid_vid_cap_qops;
+               q->mem_ops = &vb2_vmalloc_memops;
+               q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
+               q->min_buffers_needed = 2;
+
+               ret = vb2_queue_init(q);
+               if (ret)
+                       goto unreg_dev;
+       }
+
+       if (dev->has_vid_out) {
+               /* initialize vid_out queue */
+               q = &dev->vb_vid_out_q;
+               q->type = dev->multiplanar ? V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE :
+                       V4L2_BUF_TYPE_VIDEO_OUTPUT;
+               q->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF | VB2_WRITE;
+               q->drv_priv = dev;
+               q->buf_struct_size = sizeof(struct vivid_buffer);
+               q->ops = &vivid_vid_out_qops;
+               q->mem_ops = &vb2_vmalloc_memops;
+               q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
+               q->min_buffers_needed = 2;
+
+               ret = vb2_queue_init(q);
+               if (ret)
+                       goto unreg_dev;
+       }
+
+       if (dev->has_vbi_cap) {
+               /* initialize vbi_cap queue */
+               q = &dev->vb_vbi_cap_q;
+               q->type = dev->has_raw_vbi_cap ? V4L2_BUF_TYPE_VBI_CAPTURE :
+                                             V4L2_BUF_TYPE_SLICED_VBI_CAPTURE;
+               q->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF | VB2_READ;
+               q->drv_priv = dev;
+               q->buf_struct_size = sizeof(struct vivid_buffer);
+               q->ops = &vivid_vbi_cap_qops;
+               q->mem_ops = &vb2_vmalloc_memops;
+               q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
+               q->min_buffers_needed = 2;
+
+               ret = vb2_queue_init(q);
+               if (ret)
+                       goto unreg_dev;
+       }
+
+       if (dev->has_vbi_out) {
+               /* initialize vbi_out queue */
+               q = &dev->vb_vbi_out_q;
+               q->type = dev->has_raw_vbi_out ? V4L2_BUF_TYPE_VBI_OUTPUT :
+                                             V4L2_BUF_TYPE_SLICED_VBI_OUTPUT;
+               q->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF | VB2_WRITE;
+               q->drv_priv = dev;
+               q->buf_struct_size = sizeof(struct vivid_buffer);
+               q->ops = &vivid_vbi_out_qops;
+               q->mem_ops = &vb2_vmalloc_memops;
+               q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
+               q->min_buffers_needed = 2;
+
+               ret = vb2_queue_init(q);
+               if (ret)
+                       goto unreg_dev;
+       }
+
+       if (dev->has_sdr_cap) {
+               /* initialize sdr_cap queue */
+               q = &dev->vb_sdr_cap_q;
+               q->type = V4L2_BUF_TYPE_SDR_CAPTURE;
+               q->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF | VB2_READ;
+               q->drv_priv = dev;
+               q->buf_struct_size = sizeof(struct vivid_buffer);
+               q->ops = &vivid_sdr_cap_qops;
+               q->mem_ops = &vb2_vmalloc_memops;
+               q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
+               q->min_buffers_needed = 8;
+
+               ret = vb2_queue_init(q);
+               if (ret)
+                       goto unreg_dev;
+       }
+
+       if (dev->has_fb) {
+               /* Create framebuffer for testing capture/output overlay */
+               ret = vivid_fb_init(dev);
+               if (ret)
+                       goto unreg_dev;
+               v4l2_info(&dev->v4l2_dev, "Framebuffer device registered as fb%d\n",
+                               dev->fb_info.node);
+       }
+
+       /* finally start creating the device nodes */
+       if (dev->has_vid_cap) {
+               vfd = &dev->vid_cap_dev;
+               strlcpy(vfd->name, "vivid-vid-cap", sizeof(vfd->name));
+               vfd->fops = &vivid_fops;
+               vfd->ioctl_ops = &vivid_ioctl_ops;
+               vfd->release = video_device_release_empty;
+               vfd->v4l2_dev = &dev->v4l2_dev;
+               vfd->queue = &dev->vb_vid_cap_q;
+               vfd->tvnorms = tvnorms_cap;
+
+               /*
+                * Provide a mutex to v4l2 core. It will be used to protect
+                * all fops and v4l2 ioctls.
+                */
+               vfd->lock = &dev->mutex;
+               video_set_drvdata(vfd, dev);
+
+               ret = video_register_device(vfd, VFL_TYPE_GRABBER, vid_cap_nr[inst]);
+               if (ret < 0)
+                       goto unreg_dev;
+               v4l2_info(&dev->v4l2_dev, "V4L2 capture device registered as %s\n",
+                                         video_device_node_name(vfd));
+       }
+
+       if (dev->has_vid_out) {
+               vfd = &dev->vid_out_dev;
+               strlcpy(vfd->name, "vivid-vid-out", sizeof(vfd->name));
+               vfd->vfl_dir = VFL_DIR_TX;
+               vfd->fops = &vivid_fops;
+               vfd->ioctl_ops = &vivid_ioctl_ops;
+               vfd->release = video_device_release_empty;
+               vfd->v4l2_dev = &dev->v4l2_dev;
+               vfd->queue = &dev->vb_vid_out_q;
+               vfd->tvnorms = tvnorms_out;
+
+               /*
+                * Provide a mutex to v4l2 core. It will be used to protect
+                * all fops and v4l2 ioctls.
+                */
+               vfd->lock = &dev->mutex;
+               video_set_drvdata(vfd, dev);
+
+               ret = video_register_device(vfd, VFL_TYPE_GRABBER, vid_out_nr[inst]);
+               if (ret < 0)
+                       goto unreg_dev;
+               v4l2_info(&dev->v4l2_dev, "V4L2 output device registered as %s\n",
+                                         video_device_node_name(vfd));
+       }
+
+       if (dev->has_vbi_cap) {
+               vfd = &dev->vbi_cap_dev;
+               strlcpy(vfd->name, "vivid-vbi-cap", sizeof(vfd->name));
+               vfd->fops = &vivid_fops;
+               vfd->ioctl_ops = &vivid_ioctl_ops;
+               vfd->release = video_device_release_empty;
+               vfd->v4l2_dev = &dev->v4l2_dev;
+               vfd->queue = &dev->vb_vbi_cap_q;
+               vfd->lock = &dev->mutex;
+               vfd->tvnorms = tvnorms_cap;
+               video_set_drvdata(vfd, dev);
+
+               ret = video_register_device(vfd, VFL_TYPE_VBI, vbi_cap_nr[inst]);
+               if (ret < 0)
+                       goto unreg_dev;
+               v4l2_info(&dev->v4l2_dev, "V4L2 capture device registered as %s, supports %s VBI\n",
+                                         video_device_node_name(vfd),
+                                         (dev->has_raw_vbi_cap && dev->has_sliced_vbi_cap) ?
+                                         "raw and sliced" :
+                                         (dev->has_raw_vbi_cap ? "raw" : "sliced"));
+       }
+
+       if (dev->has_vbi_out) {
+               vfd = &dev->vbi_out_dev;
+               strlcpy(vfd->name, "vivid-vbi-out", sizeof(vfd->name));
+               vfd->vfl_dir = VFL_DIR_TX;
+               vfd->fops = &vivid_fops;
+               vfd->ioctl_ops = &vivid_ioctl_ops;
+               vfd->release = video_device_release_empty;
+               vfd->v4l2_dev = &dev->v4l2_dev;
+               vfd->queue = &dev->vb_vbi_out_q;
+               vfd->lock = &dev->mutex;
+               vfd->tvnorms = tvnorms_out;
+               video_set_drvdata(vfd, dev);
+
+               ret = video_register_device(vfd, VFL_TYPE_VBI, vbi_out_nr[inst]);
+               if (ret < 0)
+                       goto unreg_dev;
+               v4l2_info(&dev->v4l2_dev, "V4L2 output device registered as %s, supports %s VBI\n",
+                                         video_device_node_name(vfd),
+                                         (dev->has_raw_vbi_out && dev->has_sliced_vbi_out) ?
+                                         "raw and sliced" :
+                                         (dev->has_raw_vbi_out ? "raw" : "sliced"));
+       }
+
+       if (dev->has_sdr_cap) {
+               vfd = &dev->sdr_cap_dev;
+               strlcpy(vfd->name, "vivid-sdr-cap", sizeof(vfd->name));
+               vfd->fops = &vivid_fops;
+               vfd->ioctl_ops = &vivid_ioctl_ops;
+               vfd->release = video_device_release_empty;
+               vfd->v4l2_dev = &dev->v4l2_dev;
+               vfd->queue = &dev->vb_sdr_cap_q;
+               vfd->lock = &dev->mutex;
+               video_set_drvdata(vfd, dev);
+
+               ret = video_register_device(vfd, VFL_TYPE_SDR, sdr_cap_nr[inst]);
+               if (ret < 0)
+                       goto unreg_dev;
+               v4l2_info(&dev->v4l2_dev, "V4L2 capture device registered as %s\n",
+                                         video_device_node_name(vfd));
+       }
+
+       if (dev->has_radio_rx) {
+               vfd = &dev->radio_rx_dev;
+               strlcpy(vfd->name, "vivid-rad-rx", sizeof(vfd->name));
+               vfd->fops = &vivid_radio_fops;
+               vfd->ioctl_ops = &vivid_ioctl_ops;
+               vfd->release = video_device_release_empty;
+               vfd->v4l2_dev = &dev->v4l2_dev;
+               vfd->lock = &dev->mutex;
+               video_set_drvdata(vfd, dev);
+
+               ret = video_register_device(vfd, VFL_TYPE_RADIO, radio_rx_nr[inst]);
+               if (ret < 0)
+                       goto unreg_dev;
+               v4l2_info(&dev->v4l2_dev, "V4L2 receiver device registered as %s\n",
+                                         video_device_node_name(vfd));
+       }
+
+       if (dev->has_radio_tx) {
+               vfd = &dev->radio_tx_dev;
+               strlcpy(vfd->name, "vivid-rad-tx", sizeof(vfd->name));
+               vfd->vfl_dir = VFL_DIR_TX;
+               vfd->fops = &vivid_radio_fops;
+               vfd->ioctl_ops = &vivid_ioctl_ops;
+               vfd->release = video_device_release_empty;
+               vfd->v4l2_dev = &dev->v4l2_dev;
+               vfd->lock = &dev->mutex;
+               video_set_drvdata(vfd, dev);
+
+               ret = video_register_device(vfd, VFL_TYPE_RADIO, radio_tx_nr[inst]);
+               if (ret < 0)
+                       goto unreg_dev;
+               v4l2_info(&dev->v4l2_dev, "V4L2 transmitter device registered as %s\n",
+                                         video_device_node_name(vfd));
+       }
+
+       /* Now that everything is fine, let's add it to device list */
+       vivid_devs[inst] = dev;
+
+       return 0;
+
+unreg_dev:
+       video_unregister_device(&dev->radio_tx_dev);
+       video_unregister_device(&dev->radio_rx_dev);
+       video_unregister_device(&dev->sdr_cap_dev);
+       video_unregister_device(&dev->vbi_out_dev);
+       video_unregister_device(&dev->vbi_cap_dev);
+       video_unregister_device(&dev->vid_out_dev);
+       video_unregister_device(&dev->vid_cap_dev);
+       vivid_free_controls(dev);
+       v4l2_device_unregister(&dev->v4l2_dev);
+free_dev:
+       vfree(dev->scaled_line);
+       vfree(dev->blended_line);
+       vfree(dev->edid);
+       tpg_free(&dev->tpg);
+       kfree(dev->query_dv_timings_qmenu);
+       kfree(dev);
+       return ret;
+}
+
+/* This routine allocates from 1 to n_devs virtual drivers.
+
+   The real maximum number of virtual drivers will depend on how many drivers
+   will succeed. This is limited to the maximum number of devices that
+   videodev supports, which is equal to VIDEO_NUM_DEVICES.
+ */
+static int __init vivid_init(void)
+{
+       const struct font_desc *font = find_font("VGA8x16");
+       int ret = 0, i;
+
+       if (font == NULL) {
+               pr_err("vivid: could not find font\n");
+               return -ENODEV;
+       }
+
+       tpg_set_font(font->data);
+
+       n_devs = clamp_t(unsigned, n_devs, 1, VIVID_MAX_DEVS);
+
+       for (i = 0; i < n_devs; i++) {
+               ret = vivid_create_instance(i);
+               if (ret) {
+                       /* If some instantiations succeeded, keep driver */
+                       if (i)
+                               ret = 0;
+                       break;
+               }
+       }
+
+       if (ret < 0) {
+               pr_err("vivid: error %d while loading driver\n", ret);
+               return ret;
+       }
+
+       /* n_devs will reflect the actual number of allocated devices */
+       n_devs = i;
+
+       return ret;
+}
+
+static void __exit vivid_exit(void)
+{
+       struct vivid_dev *dev;
+       unsigned i;
+
+       for (i = 0; vivid_devs[i]; i++) {
+               dev = vivid_devs[i];
+
+               if (dev->has_vid_cap) {
+                       v4l2_info(&dev->v4l2_dev, "unregistering %s\n",
+                               video_device_node_name(&dev->vid_cap_dev));
+                       video_unregister_device(&dev->vid_cap_dev);
+               }
+               if (dev->has_vid_out) {
+                       v4l2_info(&dev->v4l2_dev, "unregistering %s\n",
+                               video_device_node_name(&dev->vid_out_dev));
+                       video_unregister_device(&dev->vid_out_dev);
+               }
+               if (dev->has_vbi_cap) {
+                       v4l2_info(&dev->v4l2_dev, "unregistering %s\n",
+                               video_device_node_name(&dev->vbi_cap_dev));
+                       video_unregister_device(&dev->vbi_cap_dev);
+               }
+               if (dev->has_vbi_out) {
+                       v4l2_info(&dev->v4l2_dev, "unregistering %s\n",
+                               video_device_node_name(&dev->vbi_out_dev));
+                       video_unregister_device(&dev->vbi_out_dev);
+               }
+               if (dev->has_sdr_cap) {
+                       v4l2_info(&dev->v4l2_dev, "unregistering %s\n",
+                               video_device_node_name(&dev->sdr_cap_dev));
+                       video_unregister_device(&dev->sdr_cap_dev);
+               }
+               if (dev->has_radio_rx) {
+                       v4l2_info(&dev->v4l2_dev, "unregistering %s\n",
+                               video_device_node_name(&dev->radio_rx_dev));
+                       video_unregister_device(&dev->radio_rx_dev);
+               }
+               if (dev->has_radio_tx) {
+                       v4l2_info(&dev->v4l2_dev, "unregistering %s\n",
+                               video_device_node_name(&dev->radio_tx_dev));
+                       video_unregister_device(&dev->radio_tx_dev);
+               }
+               if (dev->has_fb) {
+                       v4l2_info(&dev->v4l2_dev, "unregistering fb%d\n",
+                               dev->fb_info.node);
+                       unregister_framebuffer(&dev->fb_info);
+                       vivid_fb_release_buffers(dev);
+               }
+               v4l2_device_unregister(&dev->v4l2_dev);
+               vivid_free_controls(dev);
+               vfree(dev->scaled_line);
+               vfree(dev->blended_line);
+               vfree(dev->edid);
+               vfree(dev->bitmap_cap);
+               vfree(dev->bitmap_out);
+               tpg_free(&dev->tpg);
+               kfree(dev->query_dv_timings_qmenu);
+               kfree(dev);
+               vivid_devs[i] = NULL;
+       }
+}
+
+module_init(vivid_init);
+module_exit(vivid_exit);
diff --git a/drivers/media/platform/vivid/vivid-core.h b/drivers/media/platform/vivid/vivid-core.h
new file mode 100644 (file)
index 0000000..811c286
--- /dev/null
@@ -0,0 +1,520 @@
+/*
+ * vivid-core.h - core datastructures
+ *
+ * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
+ *
+ * This program is free software; you may redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * 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 _VIVID_CORE_H_
+#define _VIVID_CORE_H_
+
+#include <linux/fb.h>
+#include <media/videobuf2-core.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-dev.h>
+#include <media/v4l2-ctrls.h>
+#include "vivid-tpg.h"
+#include "vivid-rds-gen.h"
+#include "vivid-vbi-gen.h"
+
+#define dprintk(dev, level, fmt, arg...) \
+       v4l2_dbg(level, vivid_debug, &dev->v4l2_dev, fmt, ## arg)
+
+/* Maximum allowed frame rate
+ *
+ * vivid will allow setting timeperframe in [1/FPS_MAX - FPS_MAX/1] range.
+ *
+ * Ideally FPS_MAX should be infinity, i.e. practically UINT_MAX, but that
+ * might hit application errors when they manipulate these values.
+ *
+ * Besides, for tpf < 10ms image-generation logic should be changed, to avoid
+ * producing frames with equal content.
+ */
+#define FPS_MAX 100
+
+/* The maximum number of clip rectangles */
+#define MAX_CLIPS  16
+/* The maximum number of inputs */
+#define MAX_INPUTS 16
+/* The maximum number of outputs */
+#define MAX_OUTPUTS 16
+/* The maximum up or down scaling factor is 4 */
+#define MAX_ZOOM  4
+/* The maximum image width/height are set to 4K DMT */
+#define MAX_WIDTH  4096
+#define MAX_HEIGHT 2160
+/* The minimum image width/height */
+#define MIN_WIDTH  16
+#define MIN_HEIGHT 16
+/* The data_offset of plane 0 for the multiplanar formats */
+#define PLANE0_DATA_OFFSET 128
+
+/* The supported TV frequency range in MHz */
+#define MIN_TV_FREQ (44U * 16U)
+#define MAX_TV_FREQ (958U * 16U)
+
+/* The number of samples returned in every SDR buffer */
+#define SDR_CAP_SAMPLES_PER_BUF 0x4000
+
+/* used by the threads to know when to resync internal counters */
+#define JIFFIES_PER_DAY (3600U * 24U * HZ)
+#define JIFFIES_RESYNC (JIFFIES_PER_DAY * (0xf0000000U / JIFFIES_PER_DAY))
+
+extern const struct v4l2_rect vivid_min_rect;
+extern const struct v4l2_rect vivid_max_rect;
+extern unsigned vivid_debug;
+
+struct vivid_fmt {
+       const char *name;
+       u32     fourcc;          /* v4l2 format id */
+       u8      depth;
+       bool    is_yuv;
+       bool    can_do_overlay;
+       u32     alpha_mask;
+       u8      planes;
+       u32     data_offset[2];
+};
+
+extern struct vivid_fmt vivid_formats[];
+
+/* buffer for one video frame */
+struct vivid_buffer {
+       /* common v4l buffer stuff -- must be first */
+       struct vb2_buffer       vb;
+       struct list_head        list;
+};
+
+enum vivid_input {
+       WEBCAM,
+       TV,
+       SVID,
+       HDMI,
+};
+
+enum vivid_signal_mode {
+       CURRENT_DV_TIMINGS,
+       CURRENT_STD = CURRENT_DV_TIMINGS,
+       NO_SIGNAL,
+       NO_LOCK,
+       OUT_OF_RANGE,
+       SELECTED_DV_TIMINGS,
+       SELECTED_STD = SELECTED_DV_TIMINGS,
+       CYCLE_DV_TIMINGS,
+       CYCLE_STD = CYCLE_DV_TIMINGS,
+       CUSTOM_DV_TIMINGS,
+};
+
+#define VIVID_INVALID_SIGNAL(mode) \
+       ((mode) == NO_SIGNAL || (mode) == NO_LOCK || (mode) == OUT_OF_RANGE)
+
+struct vivid_dev {
+       unsigned                        inst;
+       struct v4l2_device              v4l2_dev;
+       struct v4l2_ctrl_handler        ctrl_hdl_user_gen;
+       struct v4l2_ctrl_handler        ctrl_hdl_user_vid;
+       struct v4l2_ctrl_handler        ctrl_hdl_user_aud;
+       struct v4l2_ctrl_handler        ctrl_hdl_streaming;
+       struct v4l2_ctrl_handler        ctrl_hdl_sdtv_cap;
+       struct v4l2_ctrl_handler        ctrl_hdl_loop_out;
+       struct video_device             vid_cap_dev;
+       struct v4l2_ctrl_handler        ctrl_hdl_vid_cap;
+       struct video_device             vid_out_dev;
+       struct v4l2_ctrl_handler        ctrl_hdl_vid_out;
+       struct video_device             vbi_cap_dev;
+       struct v4l2_ctrl_handler        ctrl_hdl_vbi_cap;
+       struct video_device             vbi_out_dev;
+       struct v4l2_ctrl_handler        ctrl_hdl_vbi_out;
+       struct video_device             radio_rx_dev;
+       struct v4l2_ctrl_handler        ctrl_hdl_radio_rx;
+       struct video_device             radio_tx_dev;
+       struct v4l2_ctrl_handler        ctrl_hdl_radio_tx;
+       struct video_device             sdr_cap_dev;
+       struct v4l2_ctrl_handler        ctrl_hdl_sdr_cap;
+       spinlock_t                      slock;
+       struct mutex                    mutex;
+
+       /* capabilities */
+       u32                             vid_cap_caps;
+       u32                             vid_out_caps;
+       u32                             vbi_cap_caps;
+       u32                             vbi_out_caps;
+       u32                             sdr_cap_caps;
+       u32                             radio_rx_caps;
+       u32                             radio_tx_caps;
+
+       /* supported features */
+       bool                            multiplanar;
+       unsigned                        num_inputs;
+       u8                              input_type[MAX_INPUTS];
+       u8                              input_name_counter[MAX_INPUTS];
+       unsigned                        num_outputs;
+       u8                              output_type[MAX_OUTPUTS];
+       u8                              output_name_counter[MAX_OUTPUTS];
+       bool                            has_audio_inputs;
+       bool                            has_audio_outputs;
+       bool                            has_vid_cap;
+       bool                            has_vid_out;
+       bool                            has_vbi_cap;
+       bool                            has_raw_vbi_cap;
+       bool                            has_sliced_vbi_cap;
+       bool                            has_vbi_out;
+       bool                            has_raw_vbi_out;
+       bool                            has_sliced_vbi_out;
+       bool                            has_radio_rx;
+       bool                            has_radio_tx;
+       bool                            has_sdr_cap;
+       bool                            has_fb;
+
+       bool                            can_loop_video;
+
+       /* controls */
+       struct v4l2_ctrl                *brightness;
+       struct v4l2_ctrl                *contrast;
+       struct v4l2_ctrl                *saturation;
+       struct v4l2_ctrl                *hue;
+       struct {
+               /* autogain/gain cluster */
+               struct v4l2_ctrl        *autogain;
+               struct v4l2_ctrl        *gain;
+       };
+       struct v4l2_ctrl                *volume;
+       struct v4l2_ctrl                *mute;
+       struct v4l2_ctrl                *alpha;
+       struct v4l2_ctrl                *button;
+       struct v4l2_ctrl                *boolean;
+       struct v4l2_ctrl                *int32;
+       struct v4l2_ctrl                *int64;
+       struct v4l2_ctrl                *menu;
+       struct v4l2_ctrl                *string;
+       struct v4l2_ctrl                *bitmask;
+       struct v4l2_ctrl                *int_menu;
+       struct v4l2_ctrl                *test_pattern;
+       struct v4l2_ctrl                *colorspace;
+       struct v4l2_ctrl                *rgb_range_cap;
+       struct v4l2_ctrl                *real_rgb_range_cap;
+       struct {
+               /* std_signal_mode/standard cluster */
+               struct v4l2_ctrl        *ctrl_std_signal_mode;
+               struct v4l2_ctrl        *ctrl_standard;
+       };
+       struct {
+               /* dv_timings_signal_mode/timings cluster */
+               struct v4l2_ctrl        *ctrl_dv_timings_signal_mode;
+               struct v4l2_ctrl        *ctrl_dv_timings;
+       };
+       struct v4l2_ctrl                *ctrl_has_crop_cap;
+       struct v4l2_ctrl                *ctrl_has_compose_cap;
+       struct v4l2_ctrl                *ctrl_has_scaler_cap;
+       struct v4l2_ctrl                *ctrl_has_crop_out;
+       struct v4l2_ctrl                *ctrl_has_compose_out;
+       struct v4l2_ctrl                *ctrl_has_scaler_out;
+       struct v4l2_ctrl                *ctrl_tx_mode;
+       struct v4l2_ctrl                *ctrl_tx_rgb_range;
+
+       struct v4l2_ctrl                *radio_tx_rds_pi;
+       struct v4l2_ctrl                *radio_tx_rds_pty;
+       struct v4l2_ctrl                *radio_tx_rds_mono_stereo;
+       struct v4l2_ctrl                *radio_tx_rds_art_head;
+       struct v4l2_ctrl                *radio_tx_rds_compressed;
+       struct v4l2_ctrl                *radio_tx_rds_dyn_pty;
+       struct v4l2_ctrl                *radio_tx_rds_ta;
+       struct v4l2_ctrl                *radio_tx_rds_tp;
+       struct v4l2_ctrl                *radio_tx_rds_ms;
+       struct v4l2_ctrl                *radio_tx_rds_psname;
+       struct v4l2_ctrl                *radio_tx_rds_radiotext;
+
+       struct v4l2_ctrl                *radio_rx_rds_pty;
+       struct v4l2_ctrl                *radio_rx_rds_ta;
+       struct v4l2_ctrl                *radio_rx_rds_tp;
+       struct v4l2_ctrl                *radio_rx_rds_ms;
+       struct v4l2_ctrl                *radio_rx_rds_psname;
+       struct v4l2_ctrl                *radio_rx_rds_radiotext;
+
+       unsigned                        input_brightness[MAX_INPUTS];
+       unsigned                        osd_mode;
+       unsigned                        button_pressed;
+       bool                            sensor_hflip;
+       bool                            sensor_vflip;
+       bool                            hflip;
+       bool                            vflip;
+       bool                            vbi_cap_interlaced;
+       bool                            loop_video;
+
+       /* Framebuffer */
+       unsigned long                   video_pbase;
+       void                            *video_vbase;
+       u32                             video_buffer_size;
+       int                             display_width;
+       int                             display_height;
+       int                             display_byte_stride;
+       int                             bits_per_pixel;
+       int                             bytes_per_pixel;
+       struct fb_info                  fb_info;
+       struct fb_var_screeninfo        fb_defined;
+       struct fb_fix_screeninfo        fb_fix;
+
+       /* Error injection */
+       bool                            queue_setup_error;
+       bool                            buf_prepare_error;
+       bool                            start_streaming_error;
+       bool                            dqbuf_error;
+       bool                            seq_wrap;
+       bool                            time_wrap;
+       __kernel_time_t                 time_wrap_offset;
+       unsigned                        perc_dropped_buffers;
+       enum vivid_signal_mode          std_signal_mode;
+       unsigned                        query_std_last;
+       v4l2_std_id                     query_std;
+       enum tpg_video_aspect           std_aspect_ratio;
+
+       enum vivid_signal_mode          dv_timings_signal_mode;
+       char                            **query_dv_timings_qmenu;
+       unsigned                        query_dv_timings_size;
+       unsigned                        query_dv_timings_last;
+       unsigned                        query_dv_timings;
+       enum tpg_video_aspect           dv_timings_aspect_ratio;
+
+       /* Input */
+       unsigned                        input;
+       v4l2_std_id                     std_cap;
+       struct v4l2_dv_timings          dv_timings_cap;
+       u32                             service_set_cap;
+       struct vivid_vbi_gen_data       vbi_gen;
+       u8                              *edid;
+       unsigned                        edid_blocks;
+       unsigned                        edid_max_blocks;
+       unsigned                        webcam_size_idx;
+       unsigned                        webcam_ival_idx;
+       unsigned                        tv_freq;
+       unsigned                        tv_audmode;
+       unsigned                        tv_field_cap;
+       unsigned                        tv_audio_input;
+
+       /* Capture Overlay */
+       struct v4l2_framebuffer         fb_cap;
+       struct v4l2_fh                  *overlay_cap_owner;
+       void                            *fb_vbase_cap;
+       int                             overlay_cap_top, overlay_cap_left;
+       enum v4l2_field                 overlay_cap_field;
+       void                            *bitmap_cap;
+       struct v4l2_clip                clips_cap[MAX_CLIPS];
+       struct v4l2_clip                try_clips_cap[MAX_CLIPS];
+       unsigned                        clipcount_cap;
+
+       /* Output */
+       unsigned                        output;
+       v4l2_std_id                     std_out;
+       struct v4l2_dv_timings          dv_timings_out;
+       u32                             colorspace_out;
+       u32                             service_set_out;
+       u32                             bytesperline_out[2];
+       unsigned                        tv_field_out;
+       unsigned                        tv_audio_output;
+       bool                            vbi_out_have_wss;
+       u8                              vbi_out_wss[2];
+       bool                            vbi_out_have_cc[2];
+       u8                              vbi_out_cc[2][2];
+       bool                            dvi_d_out;
+       u8                              *scaled_line;
+       u8                              *blended_line;
+       unsigned                        cur_scaled_line;
+
+       /* Output Overlay */
+       void                            *fb_vbase_out;
+       bool                            overlay_out_enabled;
+       int                             overlay_out_top, overlay_out_left;
+       void                            *bitmap_out;
+       struct v4l2_clip                clips_out[MAX_CLIPS];
+       struct v4l2_clip                try_clips_out[MAX_CLIPS];
+       unsigned                        clipcount_out;
+       unsigned                        fbuf_out_flags;
+       u32                             chromakey_out;
+       u8                              global_alpha_out;
+
+       /* video capture */
+       struct tpg_data                 tpg;
+       unsigned                        ms_vid_cap;
+       bool                            must_blank[VIDEO_MAX_FRAME];
+
+       const struct vivid_fmt          *fmt_cap;
+       struct v4l2_fract               timeperframe_vid_cap;
+       enum v4l2_field                 field_cap;
+       struct v4l2_rect                src_rect;
+       struct v4l2_rect                fmt_cap_rect;
+       struct v4l2_rect                crop_cap;
+       struct v4l2_rect                compose_cap;
+       struct v4l2_rect                crop_bounds_cap;
+       struct vb2_queue                vb_vid_cap_q;
+       struct list_head                vid_cap_active;
+       struct vb2_queue                vb_vbi_cap_q;
+       struct list_head                vbi_cap_active;
+
+       /* thread for generating video capture stream */
+       struct task_struct              *kthread_vid_cap;
+       unsigned long                   jiffies_vid_cap;
+       u32                             cap_seq_offset;
+       u32                             cap_seq_count;
+       bool                            cap_seq_resync;
+       u32                             vid_cap_seq_start;
+       u32                             vid_cap_seq_count;
+       bool                            vid_cap_streaming;
+       u32                             vbi_cap_seq_start;
+       u32                             vbi_cap_seq_count;
+       bool                            vbi_cap_streaming;
+       bool                            stream_sliced_vbi_cap;
+
+       /* video output */
+       const struct vivid_fmt          *fmt_out;
+       struct v4l2_fract               timeperframe_vid_out;
+       enum v4l2_field                 field_out;
+       struct v4l2_rect                sink_rect;
+       struct v4l2_rect                fmt_out_rect;
+       struct v4l2_rect                crop_out;
+       struct v4l2_rect                compose_out;
+       struct v4l2_rect                compose_bounds_out;
+       struct vb2_queue                vb_vid_out_q;
+       struct list_head                vid_out_active;
+       struct vb2_queue                vb_vbi_out_q;
+       struct list_head                vbi_out_active;
+
+       /* video loop precalculated rectangles */
+
+       /*
+        * Intersection between what the output side composes and the capture side
+        * crops. I.e., what actually needs to be copied from the output buffer to
+        * the capture buffer.
+        */
+       struct v4l2_rect                loop_vid_copy;
+       /* The part of the output buffer that (after scaling) corresponds to loop_vid_copy. */
+       struct v4l2_rect                loop_vid_out;
+       /* The part of the capture buffer that (after scaling) corresponds to loop_vid_copy. */
+       struct v4l2_rect                loop_vid_cap;
+       /*
+        * The intersection of the framebuffer, the overlay output window and
+        * loop_vid_copy. I.e., the part of the framebuffer that actually should be
+        * blended with the compose_out rectangle. This uses the framebuffer origin.
+        */
+       struct v4l2_rect                loop_fb_copy;
+       /* The same as loop_fb_copy but with compose_out origin. */
+       struct v4l2_rect                loop_vid_overlay;
+       /*
+        * The part of the capture buffer that (after scaling) corresponds
+        * to loop_vid_overlay.
+        */
+       struct v4l2_rect                loop_vid_overlay_cap;
+
+       /* thread for generating video output stream */
+       struct task_struct              *kthread_vid_out;
+       unsigned long                   jiffies_vid_out;
+       u32                             out_seq_offset;
+       u32                             out_seq_count;
+       bool                            out_seq_resync;
+       u32                             vid_out_seq_start;
+       u32                             vid_out_seq_count;
+       bool                            vid_out_streaming;
+       u32                             vbi_out_seq_start;
+       u32                             vbi_out_seq_count;
+       bool                            vbi_out_streaming;
+       bool                            stream_sliced_vbi_out;
+
+       /* SDR capture */
+       struct vb2_queue                vb_sdr_cap_q;
+       struct list_head                sdr_cap_active;
+       unsigned                        sdr_adc_freq;
+       unsigned                        sdr_fm_freq;
+       int                             sdr_fixp_src_phase;
+       int                             sdr_fixp_mod_phase;
+
+       bool                            tstamp_src_is_soe;
+       bool                            has_crop_cap;
+       bool                            has_compose_cap;
+       bool                            has_scaler_cap;
+       bool                            has_crop_out;
+       bool                            has_compose_out;
+       bool                            has_scaler_out;
+
+       /* thread for generating SDR stream */
+       struct task_struct              *kthread_sdr_cap;
+       unsigned long                   jiffies_sdr_cap;
+       u32                             sdr_cap_seq_offset;
+       u32                             sdr_cap_seq_count;
+       bool                            sdr_cap_seq_resync;
+
+       /* RDS generator */
+       struct vivid_rds_gen            rds_gen;
+
+       /* Radio receiver */
+       unsigned                        radio_rx_freq;
+       unsigned                        radio_rx_audmode;
+       int                             radio_rx_sig_qual;
+       unsigned                        radio_rx_hw_seek_mode;
+       bool                            radio_rx_hw_seek_prog_lim;
+       bool                            radio_rx_rds_controls;
+       bool                            radio_rx_rds_enabled;
+       unsigned                        radio_rx_rds_use_alternates;
+       unsigned                        radio_rx_rds_last_block;
+       struct v4l2_fh                  *radio_rx_rds_owner;
+
+       /* Radio transmitter */
+       unsigned                        radio_tx_freq;
+       unsigned                        radio_tx_subchans;
+       bool                            radio_tx_rds_controls;
+       unsigned                        radio_tx_rds_last_block;
+       struct v4l2_fh                  *radio_tx_rds_owner;
+
+       /* Shared between radio receiver and transmitter */
+       bool                            radio_rds_loop;
+       struct timespec                 radio_rds_init_ts;
+};
+
+static inline bool vivid_is_webcam(const struct vivid_dev *dev)
+{
+       return dev->input_type[dev->input] == WEBCAM;
+}
+
+static inline bool vivid_is_tv_cap(const struct vivid_dev *dev)
+{
+       return dev->input_type[dev->input] == TV;
+}
+
+static inline bool vivid_is_svid_cap(const struct vivid_dev *dev)
+{
+       return dev->input_type[dev->input] == SVID;
+}
+
+static inline bool vivid_is_hdmi_cap(const struct vivid_dev *dev)
+{
+       return dev->input_type[dev->input] == HDMI;
+}
+
+static inline bool vivid_is_sdtv_cap(const struct vivid_dev *dev)
+{
+       return vivid_is_tv_cap(dev) || vivid_is_svid_cap(dev);
+}
+
+static inline bool vivid_is_svid_out(const struct vivid_dev *dev)
+{
+       return dev->output_type[dev->output] == SVID;
+}
+
+static inline bool vivid_is_hdmi_out(const struct vivid_dev *dev)
+{
+       return dev->output_type[dev->output] == HDMI;
+}
+
+void vivid_lock(struct vb2_queue *vq);
+void vivid_unlock(struct vb2_queue *vq);
+
+#endif
diff --git a/drivers/media/platform/vivid/vivid-ctrls.c b/drivers/media/platform/vivid/vivid-ctrls.c
new file mode 100644 (file)
index 0000000..d5cbf00
--- /dev/null
@@ -0,0 +1,1502 @@
+/*
+ * vivid-ctrls.c - control support functions.
+ *
+ * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
+ *
+ * This program is free software; you may redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-event.h>
+#include <media/v4l2-common.h>
+
+#include "vivid-core.h"
+#include "vivid-vid-cap.h"
+#include "vivid-vid-out.h"
+#include "vivid-vid-common.h"
+#include "vivid-radio-common.h"
+#include "vivid-osd.h"
+#include "vivid-ctrls.h"
+
+#define VIVID_CID_CUSTOM_BASE          (V4L2_CID_USER_BASE | 0xf000)
+#define VIVID_CID_BUTTON               (VIVID_CID_CUSTOM_BASE + 0)
+#define VIVID_CID_BOOLEAN              (VIVID_CID_CUSTOM_BASE + 1)
+#define VIVID_CID_INTEGER              (VIVID_CID_CUSTOM_BASE + 2)
+#define VIVID_CID_INTEGER64            (VIVID_CID_CUSTOM_BASE + 3)
+#define VIVID_CID_MENU                 (VIVID_CID_CUSTOM_BASE + 4)
+#define VIVID_CID_STRING               (VIVID_CID_CUSTOM_BASE + 5)
+#define VIVID_CID_BITMASK              (VIVID_CID_CUSTOM_BASE + 6)
+#define VIVID_CID_INTMENU              (VIVID_CID_CUSTOM_BASE + 7)
+
+#define VIVID_CID_VIVID_BASE           (0x00f00000 | 0xf000)
+#define VIVID_CID_VIVID_CLASS          (0x00f00000 | 1)
+#define VIVID_CID_TEST_PATTERN         (VIVID_CID_VIVID_BASE + 0)
+#define VIVID_CID_OSD_TEXT_MODE                (VIVID_CID_VIVID_BASE + 1)
+#define VIVID_CID_HOR_MOVEMENT         (VIVID_CID_VIVID_BASE + 2)
+#define VIVID_CID_VERT_MOVEMENT                (VIVID_CID_VIVID_BASE + 3)
+#define VIVID_CID_SHOW_BORDER          (VIVID_CID_VIVID_BASE + 4)
+#define VIVID_CID_SHOW_SQUARE          (VIVID_CID_VIVID_BASE + 5)
+#define VIVID_CID_INSERT_SAV           (VIVID_CID_VIVID_BASE + 6)
+#define VIVID_CID_INSERT_EAV           (VIVID_CID_VIVID_BASE + 7)
+#define VIVID_CID_VBI_CAP_INTERLACED   (VIVID_CID_VIVID_BASE + 8)
+
+#define VIVID_CID_HFLIP                        (VIVID_CID_VIVID_BASE + 20)
+#define VIVID_CID_VFLIP                        (VIVID_CID_VIVID_BASE + 21)
+#define VIVID_CID_STD_ASPECT_RATIO     (VIVID_CID_VIVID_BASE + 22)
+#define VIVID_CID_DV_TIMINGS_ASPECT_RATIO      (VIVID_CID_VIVID_BASE + 23)
+#define VIVID_CID_TSTAMP_SRC           (VIVID_CID_VIVID_BASE + 24)
+#define VIVID_CID_COLORSPACE           (VIVID_CID_VIVID_BASE + 25)
+#define VIVID_CID_LIMITED_RGB_RANGE    (VIVID_CID_VIVID_BASE + 26)
+#define VIVID_CID_ALPHA_MODE           (VIVID_CID_VIVID_BASE + 27)
+#define VIVID_CID_HAS_CROP_CAP         (VIVID_CID_VIVID_BASE + 28)
+#define VIVID_CID_HAS_COMPOSE_CAP      (VIVID_CID_VIVID_BASE + 29)
+#define VIVID_CID_HAS_SCALER_CAP       (VIVID_CID_VIVID_BASE + 30)
+#define VIVID_CID_HAS_CROP_OUT         (VIVID_CID_VIVID_BASE + 31)
+#define VIVID_CID_HAS_COMPOSE_OUT      (VIVID_CID_VIVID_BASE + 32)
+#define VIVID_CID_HAS_SCALER_OUT       (VIVID_CID_VIVID_BASE + 33)
+#define VIVID_CID_LOOP_VIDEO           (VIVID_CID_VIVID_BASE + 34)
+#define VIVID_CID_SEQ_WRAP             (VIVID_CID_VIVID_BASE + 35)
+#define VIVID_CID_TIME_WRAP            (VIVID_CID_VIVID_BASE + 36)
+#define VIVID_CID_MAX_EDID_BLOCKS      (VIVID_CID_VIVID_BASE + 37)
+#define VIVID_CID_PERCENTAGE_FILL      (VIVID_CID_VIVID_BASE + 38)
+
+#define VIVID_CID_STD_SIGNAL_MODE      (VIVID_CID_VIVID_BASE + 60)
+#define VIVID_CID_STANDARD             (VIVID_CID_VIVID_BASE + 61)
+#define VIVID_CID_DV_TIMINGS_SIGNAL_MODE       (VIVID_CID_VIVID_BASE + 62)
+#define VIVID_CID_DV_TIMINGS           (VIVID_CID_VIVID_BASE + 63)
+#define VIVID_CID_PERC_DROPPED         (VIVID_CID_VIVID_BASE + 64)
+#define VIVID_CID_DISCONNECT           (VIVID_CID_VIVID_BASE + 65)
+#define VIVID_CID_DQBUF_ERROR          (VIVID_CID_VIVID_BASE + 66)
+#define VIVID_CID_QUEUE_SETUP_ERROR    (VIVID_CID_VIVID_BASE + 67)
+#define VIVID_CID_BUF_PREPARE_ERROR    (VIVID_CID_VIVID_BASE + 68)
+#define VIVID_CID_START_STR_ERROR      (VIVID_CID_VIVID_BASE + 69)
+#define VIVID_CID_QUEUE_ERROR          (VIVID_CID_VIVID_BASE + 70)
+#define VIVID_CID_CLEAR_FB             (VIVID_CID_VIVID_BASE + 71)
+
+#define VIVID_CID_RADIO_SEEK_MODE      (VIVID_CID_VIVID_BASE + 90)
+#define VIVID_CID_RADIO_SEEK_PROG_LIM  (VIVID_CID_VIVID_BASE + 91)
+#define VIVID_CID_RADIO_RX_RDS_RBDS    (VIVID_CID_VIVID_BASE + 92)
+#define VIVID_CID_RADIO_RX_RDS_BLOCKIO (VIVID_CID_VIVID_BASE + 93)
+
+#define VIVID_CID_RADIO_TX_RDS_BLOCKIO (VIVID_CID_VIVID_BASE + 94)
+
+
+/* General User Controls */
+
+static int vivid_user_gen_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+       struct vivid_dev *dev = container_of(ctrl->handler, struct vivid_dev, ctrl_hdl_user_gen);
+
+       switch (ctrl->id) {
+       case VIVID_CID_DISCONNECT:
+               v4l2_info(&dev->v4l2_dev, "disconnect\n");
+               clear_bit(V4L2_FL_REGISTERED, &dev->vid_cap_dev.flags);
+               clear_bit(V4L2_FL_REGISTERED, &dev->vid_out_dev.flags);
+               clear_bit(V4L2_FL_REGISTERED, &dev->vbi_cap_dev.flags);
+               clear_bit(V4L2_FL_REGISTERED, &dev->vbi_out_dev.flags);
+               clear_bit(V4L2_FL_REGISTERED, &dev->sdr_cap_dev.flags);
+               clear_bit(V4L2_FL_REGISTERED, &dev->radio_rx_dev.flags);
+               clear_bit(V4L2_FL_REGISTERED, &dev->radio_tx_dev.flags);
+               break;
+       case VIVID_CID_CLEAR_FB:
+               vivid_clear_fb(dev);
+               break;
+       case VIVID_CID_BUTTON:
+               dev->button_pressed = 30;
+               break;
+       }
+       return 0;
+}
+
+static const struct v4l2_ctrl_ops vivid_user_gen_ctrl_ops = {
+       .s_ctrl = vivid_user_gen_s_ctrl,
+};
+
+static const struct v4l2_ctrl_config vivid_ctrl_button = {
+       .ops = &vivid_user_gen_ctrl_ops,
+       .id = VIVID_CID_BUTTON,
+       .name = "Button",
+       .type = V4L2_CTRL_TYPE_BUTTON,
+};
+
+static const struct v4l2_ctrl_config vivid_ctrl_boolean = {
+       .ops = &vivid_user_gen_ctrl_ops,
+       .id = VIVID_CID_BOOLEAN,
+       .name = "Boolean",
+       .type = V4L2_CTRL_TYPE_BOOLEAN,
+       .min = 0,
+       .max = 1,
+       .step = 1,
+       .def = 1,
+};
+
+static const struct v4l2_ctrl_config vivid_ctrl_int32 = {
+       .ops = &vivid_user_gen_ctrl_ops,
+       .id = VIVID_CID_INTEGER,
+       .name = "Integer 32 Bits",
+       .type = V4L2_CTRL_TYPE_INTEGER,
+       .min = 0xffffffff80000000ULL,
+       .max = 0x7fffffff,
+       .step = 1,
+};
+
+static const struct v4l2_ctrl_config vivid_ctrl_int64 = {
+       .ops = &vivid_user_gen_ctrl_ops,
+       .id = VIVID_CID_INTEGER64,
+       .name = "Integer 64 Bits",
+       .type = V4L2_CTRL_TYPE_INTEGER64,
+       .min = 0x8000000000000000ULL,
+       .max = 0x7fffffffffffffffLL,
+       .step = 1,
+};
+
+static const char * const vivid_ctrl_menu_strings[] = {
+       "Menu Item 0 (Skipped)",
+       "Menu Item 1",
+       "Menu Item 2 (Skipped)",
+       "Menu Item 3",
+       "Menu Item 4",
+       "Menu Item 5 (Skipped)",
+       NULL,
+};
+
+static const struct v4l2_ctrl_config vivid_ctrl_menu = {
+       .ops = &vivid_user_gen_ctrl_ops,
+       .id = VIVID_CID_MENU,
+       .name = "Menu",
+       .type = V4L2_CTRL_TYPE_MENU,
+       .min = 1,
+       .max = 4,
+       .def = 3,
+       .menu_skip_mask = 0x04,
+       .qmenu = vivid_ctrl_menu_strings,
+};
+
+static const struct v4l2_ctrl_config vivid_ctrl_string = {
+       .ops = &vivid_user_gen_ctrl_ops,
+       .id = VIVID_CID_STRING,
+       .name = "String",
+       .type = V4L2_CTRL_TYPE_STRING,
+       .min = 2,
+       .max = 4,
+       .step = 1,
+};
+
+static const struct v4l2_ctrl_config vivid_ctrl_bitmask = {
+       .ops = &vivid_user_gen_ctrl_ops,
+       .id = VIVID_CID_BITMASK,
+       .name = "Bitmask",
+       .type = V4L2_CTRL_TYPE_BITMASK,
+       .def = 0x80002000,
+       .min = 0,
+       .max = 0x80402010,
+       .step = 0,
+};
+
+static const s64 vivid_ctrl_int_menu_values[] = {
+       1, 1, 2, 3, 5, 8, 13, 21, 42,
+};
+
+static const struct v4l2_ctrl_config vivid_ctrl_int_menu = {
+       .ops = &vivid_user_gen_ctrl_ops,
+       .id = VIVID_CID_INTMENU,
+       .name = "Integer Menu",
+       .type = V4L2_CTRL_TYPE_INTEGER_MENU,
+       .min = 1,
+       .max = 8,
+       .def = 4,
+       .menu_skip_mask = 0x02,
+       .qmenu_int = vivid_ctrl_int_menu_values,
+};
+
+static const struct v4l2_ctrl_config vivid_ctrl_disconnect = {
+       .ops = &vivid_user_gen_ctrl_ops,
+       .id = VIVID_CID_DISCONNECT,
+       .name = "Disconnect",
+       .type = V4L2_CTRL_TYPE_BUTTON,
+};
+
+static const struct v4l2_ctrl_config vivid_ctrl_clear_fb = {
+       .ops = &vivid_user_gen_ctrl_ops,
+       .id = VIVID_CID_CLEAR_FB,
+       .name = "Clear Framebuffer",
+       .type = V4L2_CTRL_TYPE_BUTTON,
+};
+
+
+/* Video User Controls */
+
+static int vivid_user_vid_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
+{
+       struct vivid_dev *dev = container_of(ctrl->handler, struct vivid_dev, ctrl_hdl_user_vid);
+
+       switch (ctrl->id) {
+       case V4L2_CID_AUTOGAIN:
+               dev->gain->val = dev->jiffies_vid_cap & 0xff;
+               break;
+       }
+       return 0;
+}
+
+static int vivid_user_vid_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+       struct vivid_dev *dev = container_of(ctrl->handler, struct vivid_dev, ctrl_hdl_user_vid);
+
+       switch (ctrl->id) {
+       case V4L2_CID_BRIGHTNESS:
+               dev->input_brightness[dev->input] = ctrl->val - dev->input * 128;
+               tpg_s_brightness(&dev->tpg, dev->input_brightness[dev->input]);
+               break;
+       case V4L2_CID_CONTRAST:
+               tpg_s_contrast(&dev->tpg, ctrl->val);
+               break;
+       case V4L2_CID_SATURATION:
+               tpg_s_saturation(&dev->tpg, ctrl->val);
+               break;
+       case V4L2_CID_HUE:
+               tpg_s_hue(&dev->tpg, ctrl->val);
+               break;
+       case V4L2_CID_HFLIP:
+               dev->hflip = ctrl->val;
+               tpg_s_hflip(&dev->tpg, dev->sensor_hflip ^ dev->hflip);
+               break;
+       case V4L2_CID_VFLIP:
+               dev->vflip = ctrl->val;
+               tpg_s_vflip(&dev->tpg, dev->sensor_vflip ^ dev->vflip);
+               break;
+       case V4L2_CID_ALPHA_COMPONENT:
+               tpg_s_alpha_component(&dev->tpg, ctrl->val);
+               break;
+       }
+       return 0;
+}
+
+static const struct v4l2_ctrl_ops vivid_user_vid_ctrl_ops = {
+       .g_volatile_ctrl = vivid_user_vid_g_volatile_ctrl,
+       .s_ctrl = vivid_user_vid_s_ctrl,
+};
+
+
+/* Video Capture Controls */
+
+static int vivid_vid_cap_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+       struct vivid_dev *dev = container_of(ctrl->handler, struct vivid_dev, ctrl_hdl_vid_cap);
+       unsigned i;
+
+       switch (ctrl->id) {
+       case VIVID_CID_TEST_PATTERN:
+               vivid_update_quality(dev);
+               tpg_s_pattern(&dev->tpg, ctrl->val);
+               break;
+       case VIVID_CID_COLORSPACE:
+               tpg_s_colorspace(&dev->tpg, ctrl->val);
+               vivid_send_source_change(dev, TV);
+               vivid_send_source_change(dev, SVID);
+               vivid_send_source_change(dev, HDMI);
+               vivid_send_source_change(dev, WEBCAM);
+               break;
+       case V4L2_CID_DV_RX_RGB_RANGE:
+               if (!vivid_is_hdmi_cap(dev))
+                       break;
+               tpg_s_rgb_range(&dev->tpg, ctrl->val);
+               break;
+       case VIVID_CID_LIMITED_RGB_RANGE:
+               tpg_s_real_rgb_range(&dev->tpg, ctrl->val ?
+                               V4L2_DV_RGB_RANGE_LIMITED : V4L2_DV_RGB_RANGE_FULL);
+               break;
+       case VIVID_CID_ALPHA_MODE:
+               tpg_s_alpha_mode(&dev->tpg, ctrl->val);
+               break;
+       case VIVID_CID_HOR_MOVEMENT:
+               tpg_s_mv_hor_mode(&dev->tpg, ctrl->val);
+               break;
+       case VIVID_CID_VERT_MOVEMENT:
+               tpg_s_mv_vert_mode(&dev->tpg, ctrl->val);
+               break;
+       case VIVID_CID_OSD_TEXT_MODE:
+               dev->osd_mode = ctrl->val;
+               break;
+       case VIVID_CID_PERCENTAGE_FILL:
+               tpg_s_perc_fill(&dev->tpg, ctrl->val);
+               for (i = 0; i < VIDEO_MAX_FRAME; i++)
+                       dev->must_blank[i] = ctrl->val < 100;
+               break;
+       case VIVID_CID_INSERT_SAV:
+               tpg_s_insert_sav(&dev->tpg, ctrl->val);
+               break;
+       case VIVID_CID_INSERT_EAV:
+               tpg_s_insert_eav(&dev->tpg, ctrl->val);
+               break;
+       case VIVID_CID_HFLIP:
+               dev->sensor_hflip = ctrl->val;
+               tpg_s_hflip(&dev->tpg, dev->sensor_hflip ^ dev->hflip);
+               break;
+       case VIVID_CID_VFLIP:
+               dev->sensor_vflip = ctrl->val;
+               tpg_s_vflip(&dev->tpg, dev->sensor_vflip ^ dev->vflip);
+               break;
+       case VIVID_CID_HAS_CROP_CAP:
+               dev->has_crop_cap = ctrl->val;
+               vivid_update_format_cap(dev, true);
+               break;
+       case VIVID_CID_HAS_COMPOSE_CAP:
+               dev->has_compose_cap = ctrl->val;
+               vivid_update_format_cap(dev, true);
+               break;
+       case VIVID_CID_HAS_SCALER_CAP:
+               dev->has_scaler_cap = ctrl->val;
+               vivid_update_format_cap(dev, true);
+               break;
+       case VIVID_CID_SHOW_BORDER:
+               tpg_s_show_border(&dev->tpg, ctrl->val);
+               break;
+       case VIVID_CID_SHOW_SQUARE:
+               tpg_s_show_square(&dev->tpg, ctrl->val);
+               break;
+       case VIVID_CID_STD_ASPECT_RATIO:
+               dev->std_aspect_ratio = ctrl->val;
+               tpg_s_video_aspect(&dev->tpg, vivid_get_video_aspect(dev));
+               break;
+       case VIVID_CID_DV_TIMINGS_SIGNAL_MODE:
+               dev->dv_timings_signal_mode = dev->ctrl_dv_timings_signal_mode->val;
+               if (dev->dv_timings_signal_mode == SELECTED_DV_TIMINGS)
+                       dev->query_dv_timings = dev->ctrl_dv_timings->val;
+               v4l2_ctrl_activate(dev->ctrl_dv_timings,
+                               dev->dv_timings_signal_mode == SELECTED_DV_TIMINGS);
+               vivid_update_quality(dev);
+               vivid_send_source_change(dev, HDMI);
+               break;
+       case VIVID_CID_DV_TIMINGS_ASPECT_RATIO:
+               dev->dv_timings_aspect_ratio = ctrl->val;
+               tpg_s_video_aspect(&dev->tpg, vivid_get_video_aspect(dev));
+               break;
+       case VIVID_CID_TSTAMP_SRC:
+               dev->tstamp_src_is_soe = ctrl->val;
+               dev->vb_vid_cap_q.timestamp_flags &= ~V4L2_BUF_FLAG_TSTAMP_SRC_MASK;
+               if (dev->tstamp_src_is_soe)
+                       dev->vb_vid_cap_q.timestamp_flags |= V4L2_BUF_FLAG_TSTAMP_SRC_SOE;
+               break;
+       case VIVID_CID_MAX_EDID_BLOCKS:
+               dev->edid_max_blocks = ctrl->val;
+               if (dev->edid_blocks > dev->edid_max_blocks)
+                       dev->edid_blocks = dev->edid_max_blocks;
+               break;
+       }
+       return 0;
+}
+
+static const struct v4l2_ctrl_ops vivid_vid_cap_ctrl_ops = {
+       .s_ctrl = vivid_vid_cap_s_ctrl,
+};
+
+static const char * const vivid_ctrl_hor_movement_strings[] = {
+       "Move Left Fast",
+       "Move Left",
+       "Move Left Slow",
+       "No Movement",
+       "Move Right Slow",
+       "Move Right",
+       "Move Right Fast",
+       NULL,
+};
+
+static const struct v4l2_ctrl_config vivid_ctrl_hor_movement = {
+       .ops = &vivid_vid_cap_ctrl_ops,
+       .id = VIVID_CID_HOR_MOVEMENT,
+       .name = "Horizontal Movement",
+       .type = V4L2_CTRL_TYPE_MENU,
+       .max = TPG_MOVE_POS_FAST,
+       .def = TPG_MOVE_NONE,
+       .qmenu = vivid_ctrl_hor_movement_strings,
+};
+
+static const char * const vivid_ctrl_vert_movement_strings[] = {
+       "Move Up Fast",
+       "Move Up",
+       "Move Up Slow",
+       "No Movement",
+       "Move Down Slow",
+       "Move Down",
+       "Move Down Fast",
+       NULL,
+};
+
+static const struct v4l2_ctrl_config vivid_ctrl_vert_movement = {
+       .ops = &vivid_vid_cap_ctrl_ops,
+       .id = VIVID_CID_VERT_MOVEMENT,
+       .name = "Vertical Movement",
+       .type = V4L2_CTRL_TYPE_MENU,
+       .max = TPG_MOVE_POS_FAST,
+       .def = TPG_MOVE_NONE,
+       .qmenu = vivid_ctrl_vert_movement_strings,
+};
+
+static const struct v4l2_ctrl_config vivid_ctrl_show_border = {
+       .ops = &vivid_vid_cap_ctrl_ops,
+       .id = VIVID_CID_SHOW_BORDER,
+       .name = "Show Border",
+       .type = V4L2_CTRL_TYPE_BOOLEAN,
+       .max = 1,
+       .step = 1,
+};
+
+static const struct v4l2_ctrl_config vivid_ctrl_show_square = {
+       .ops = &vivid_vid_cap_ctrl_ops,
+       .id = VIVID_CID_SHOW_SQUARE,
+       .name = "Show Square",
+       .type = V4L2_CTRL_TYPE_BOOLEAN,
+       .max = 1,
+       .step = 1,
+};
+
+static const char * const vivid_ctrl_osd_mode_strings[] = {
+       "All",
+       "Counters Only",
+       "None",
+       NULL,
+};
+
+static const struct v4l2_ctrl_config vivid_ctrl_osd_mode = {
+       .ops = &vivid_vid_cap_ctrl_ops,
+       .id = VIVID_CID_OSD_TEXT_MODE,
+       .name = "OSD Text Mode",
+       .type = V4L2_CTRL_TYPE_MENU,
+       .max = 2,
+       .qmenu = vivid_ctrl_osd_mode_strings,
+};
+
+static const struct v4l2_ctrl_config vivid_ctrl_perc_fill = {
+       .ops = &vivid_vid_cap_ctrl_ops,
+       .id = VIVID_CID_PERCENTAGE_FILL,
+       .name = "Fill Percentage of Frame",
+       .type = V4L2_CTRL_TYPE_INTEGER,
+       .min = 0,
+       .max = 100,
+       .def = 100,
+       .step = 1,
+};
+
+static const struct v4l2_ctrl_config vivid_ctrl_insert_sav = {
+       .ops = &vivid_vid_cap_ctrl_ops,
+       .id = VIVID_CID_INSERT_SAV,
+       .name = "Insert SAV Code in Image",
+       .type = V4L2_CTRL_TYPE_BOOLEAN,
+       .max = 1,
+       .step = 1,
+};
+
+static const struct v4l2_ctrl_config vivid_ctrl_insert_eav = {
+       .ops = &vivid_vid_cap_ctrl_ops,
+       .id = VIVID_CID_INSERT_EAV,
+       .name = "Insert EAV Code in Image",
+       .type = V4L2_CTRL_TYPE_BOOLEAN,
+       .max = 1,
+       .step = 1,
+};
+
+static const struct v4l2_ctrl_config vivid_ctrl_hflip = {
+       .ops = &vivid_vid_cap_ctrl_ops,
+       .id = VIVID_CID_HFLIP,
+       .name = "Sensor Flipped Horizontally",
+       .type = V4L2_CTRL_TYPE_BOOLEAN,
+       .max = 1,
+       .step = 1,
+};
+
+static const struct v4l2_ctrl_config vivid_ctrl_vflip = {
+       .ops = &vivid_vid_cap_ctrl_ops,
+       .id = VIVID_CID_VFLIP,
+       .name = "Sensor Flipped Vertically",
+       .type = V4L2_CTRL_TYPE_BOOLEAN,
+       .max = 1,
+       .step = 1,
+};
+
+static const struct v4l2_ctrl_config vivid_ctrl_has_crop_cap = {
+       .ops = &vivid_vid_cap_ctrl_ops,
+       .id = VIVID_CID_HAS_CROP_CAP,
+       .name = "Enable Capture Cropping",
+       .type = V4L2_CTRL_TYPE_BOOLEAN,
+       .max = 1,
+       .def = 1,
+       .step = 1,
+};
+
+static const struct v4l2_ctrl_config vivid_ctrl_has_compose_cap = {
+       .ops = &vivid_vid_cap_ctrl_ops,
+       .id = VIVID_CID_HAS_COMPOSE_CAP,
+       .name = "Enable Capture Composing",
+       .type = V4L2_CTRL_TYPE_BOOLEAN,
+       .max = 1,
+       .def = 1,
+       .step = 1,
+};
+
+static const struct v4l2_ctrl_config vivid_ctrl_has_scaler_cap = {
+       .ops = &vivid_vid_cap_ctrl_ops,
+       .id = VIVID_CID_HAS_SCALER_CAP,
+       .name = "Enable Capture Scaler",
+       .type = V4L2_CTRL_TYPE_BOOLEAN,
+       .max = 1,
+       .def = 1,
+       .step = 1,
+};
+
+static const char * const vivid_ctrl_tstamp_src_strings[] = {
+       "End of Frame",
+       "Start of Exposure",
+       NULL,
+};
+
+static const struct v4l2_ctrl_config vivid_ctrl_tstamp_src = {
+       .ops = &vivid_vid_cap_ctrl_ops,
+       .id = VIVID_CID_TSTAMP_SRC,
+       .name = "Timestamp Source",
+       .type = V4L2_CTRL_TYPE_MENU,
+       .max = 1,
+       .qmenu = vivid_ctrl_tstamp_src_strings,
+};
+
+static const struct v4l2_ctrl_config vivid_ctrl_std_aspect_ratio = {
+       .ops = &vivid_vid_cap_ctrl_ops,
+       .id = VIVID_CID_STD_ASPECT_RATIO,
+       .name = "Standard Aspect Ratio",
+       .type = V4L2_CTRL_TYPE_MENU,
+       .min = 1,
+       .max = 4,
+       .def = 1,
+       .qmenu = tpg_aspect_strings,
+};
+
+static const char * const vivid_ctrl_dv_timings_signal_mode_strings[] = {
+       "Current DV Timings",
+       "No Signal",
+       "No Lock",
+       "Out of Range",
+       "Selected DV Timings",
+       "Cycle Through All DV Timings",
+       "Custom DV Timings",
+       NULL,
+};
+
+static const struct v4l2_ctrl_config vivid_ctrl_dv_timings_signal_mode = {
+       .ops = &vivid_vid_cap_ctrl_ops,
+       .id = VIVID_CID_DV_TIMINGS_SIGNAL_MODE,
+       .name = "DV Timings Signal Mode",
+       .type = V4L2_CTRL_TYPE_MENU,
+       .max = 5,
+       .qmenu = vivid_ctrl_dv_timings_signal_mode_strings,
+};
+
+static const struct v4l2_ctrl_config vivid_ctrl_dv_timings_aspect_ratio = {
+       .ops = &vivid_vid_cap_ctrl_ops,
+       .id = VIVID_CID_DV_TIMINGS_ASPECT_RATIO,
+       .name = "DV Timings Aspect Ratio",
+       .type = V4L2_CTRL_TYPE_MENU,
+       .max = 3,
+       .qmenu = tpg_aspect_strings,
+};
+
+static const struct v4l2_ctrl_config vivid_ctrl_max_edid_blocks = {
+       .ops = &vivid_vid_cap_ctrl_ops,
+       .id = VIVID_CID_MAX_EDID_BLOCKS,
+       .name = "Maximum EDID Blocks",
+       .type = V4L2_CTRL_TYPE_INTEGER,
+       .min = 1,
+       .max = 256,
+       .def = 2,
+       .step = 1,
+};
+
+static const char * const vivid_ctrl_colorspace_strings[] = {
+       "",
+       "SMPTE 170M",
+       "SMPTE 240M",
+       "REC 709",
+       "", /* Skip Bt878 entry */
+       "470 System M",
+       "470 System BG",
+       "", /* Skip JPEG entry */
+       "sRGB",
+       NULL,
+};
+
+static const struct v4l2_ctrl_config vivid_ctrl_colorspace = {
+       .ops = &vivid_vid_cap_ctrl_ops,
+       .id = VIVID_CID_COLORSPACE,
+       .name = "Colorspace",
+       .type = V4L2_CTRL_TYPE_MENU,
+       .min = 1,
+       .max = 8,
+       .menu_skip_mask = (1 << 4) | (1 << 7),
+       .def = 8,
+       .qmenu = vivid_ctrl_colorspace_strings,
+};
+
+static const struct v4l2_ctrl_config vivid_ctrl_alpha_mode = {
+       .ops = &vivid_vid_cap_ctrl_ops,
+       .id = VIVID_CID_ALPHA_MODE,
+       .name = "Apply Alpha To Red Only",
+       .type = V4L2_CTRL_TYPE_BOOLEAN,
+       .max = 1,
+       .step = 1,
+};
+
+static const struct v4l2_ctrl_config vivid_ctrl_limited_rgb_range = {
+       .ops = &vivid_vid_cap_ctrl_ops,
+       .id = VIVID_CID_LIMITED_RGB_RANGE,
+       .name = "Limited RGB Range (16-235)",
+       .type = V4L2_CTRL_TYPE_BOOLEAN,
+       .max = 1,
+       .step = 1,
+};
+
+
+/* VBI Capture Control */
+
+static int vivid_vbi_cap_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+       struct vivid_dev *dev = container_of(ctrl->handler, struct vivid_dev, ctrl_hdl_vbi_cap);
+
+       switch (ctrl->id) {
+       case VIVID_CID_VBI_CAP_INTERLACED:
+               dev->vbi_cap_interlaced = ctrl->val;
+               break;
+       }
+       return 0;
+}
+
+static const struct v4l2_ctrl_ops vivid_vbi_cap_ctrl_ops = {
+       .s_ctrl = vivid_vbi_cap_s_ctrl,
+};
+
+static const struct v4l2_ctrl_config vivid_ctrl_vbi_cap_interlaced = {
+       .ops = &vivid_vbi_cap_ctrl_ops,
+       .id = VIVID_CID_VBI_CAP_INTERLACED,
+       .name = "Interlaced VBI Format",
+       .type = V4L2_CTRL_TYPE_BOOLEAN,
+       .max = 1,
+       .step = 1,
+};
+
+
+/* Video Output Controls */
+
+static int vivid_vid_out_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+       struct vivid_dev *dev = container_of(ctrl->handler, struct vivid_dev, ctrl_hdl_vid_out);
+       struct v4l2_bt_timings *bt = &dev->dv_timings_out.bt;
+
+       switch (ctrl->id) {
+       case VIVID_CID_HAS_CROP_OUT:
+               dev->has_crop_out = ctrl->val;
+               vivid_update_format_out(dev);
+               break;
+       case VIVID_CID_HAS_COMPOSE_OUT:
+               dev->has_compose_out = ctrl->val;
+               vivid_update_format_out(dev);
+               break;
+       case VIVID_CID_HAS_SCALER_OUT:
+               dev->has_scaler_out = ctrl->val;
+               vivid_update_format_out(dev);
+               break;
+       case V4L2_CID_DV_TX_MODE:
+               dev->dvi_d_out = ctrl->val == V4L2_DV_TX_MODE_DVI_D;
+               if (!vivid_is_hdmi_out(dev))
+                       break;
+               if (!dev->dvi_d_out && (bt->standards & V4L2_DV_BT_STD_CEA861)) {
+                       if (bt->width == 720 && bt->height <= 576)
+                               dev->colorspace_out = V4L2_COLORSPACE_SMPTE170M;
+                       else
+                               dev->colorspace_out = V4L2_COLORSPACE_REC709;
+               } else {
+                       dev->colorspace_out = V4L2_COLORSPACE_SRGB;
+               }
+               if (dev->loop_video)
+                       vivid_send_source_change(dev, HDMI);
+               break;
+       }
+       return 0;
+}
+
+static const struct v4l2_ctrl_ops vivid_vid_out_ctrl_ops = {
+       .s_ctrl = vivid_vid_out_s_ctrl,
+};
+
+static const struct v4l2_ctrl_config vivid_ctrl_has_crop_out = {
+       .ops = &vivid_vid_out_ctrl_ops,
+       .id = VIVID_CID_HAS_CROP_OUT,
+       .name = "Enable Output Cropping",
+       .type = V4L2_CTRL_TYPE_BOOLEAN,
+       .max = 1,
+       .def = 1,
+       .step = 1,
+};
+
+static const struct v4l2_ctrl_config vivid_ctrl_has_compose_out = {
+       .ops = &vivid_vid_out_ctrl_ops,
+       .id = VIVID_CID_HAS_COMPOSE_OUT,
+       .name = "Enable Output Composing",
+       .type = V4L2_CTRL_TYPE_BOOLEAN,
+       .max = 1,
+       .def = 1,
+       .step = 1,
+};
+
+static const struct v4l2_ctrl_config vivid_ctrl_has_scaler_out = {
+       .ops = &vivid_vid_out_ctrl_ops,
+       .id = VIVID_CID_HAS_SCALER_OUT,
+       .name = "Enable Output Scaler",
+       .type = V4L2_CTRL_TYPE_BOOLEAN,
+       .max = 1,
+       .def = 1,
+       .step = 1,
+};
+
+
+/* Streaming Controls */
+
+static int vivid_streaming_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+       struct vivid_dev *dev = container_of(ctrl->handler, struct vivid_dev, ctrl_hdl_streaming);
+       struct timeval tv;
+
+       switch (ctrl->id) {
+       case VIVID_CID_DQBUF_ERROR:
+               dev->dqbuf_error = true;
+               break;
+       case VIVID_CID_PERC_DROPPED:
+               dev->perc_dropped_buffers = ctrl->val;
+               break;
+       case VIVID_CID_QUEUE_SETUP_ERROR:
+               dev->queue_setup_error = true;
+               break;
+       case VIVID_CID_BUF_PREPARE_ERROR:
+               dev->buf_prepare_error = true;
+               break;
+       case VIVID_CID_START_STR_ERROR:
+               dev->start_streaming_error = true;
+               break;
+       case VIVID_CID_QUEUE_ERROR:
+               if (dev->vb_vid_cap_q.start_streaming_called)
+                       vb2_queue_error(&dev->vb_vid_cap_q);
+               if (dev->vb_vbi_cap_q.start_streaming_called)
+                       vb2_queue_error(&dev->vb_vbi_cap_q);
+               if (dev->vb_vid_out_q.start_streaming_called)
+                       vb2_queue_error(&dev->vb_vid_out_q);
+               if (dev->vb_vbi_out_q.start_streaming_called)
+                       vb2_queue_error(&dev->vb_vbi_out_q);
+               if (dev->vb_sdr_cap_q.start_streaming_called)
+                       vb2_queue_error(&dev->vb_sdr_cap_q);
+               break;
+       case VIVID_CID_SEQ_WRAP:
+               dev->seq_wrap = ctrl->val;
+               break;
+       case VIVID_CID_TIME_WRAP:
+               dev->time_wrap = ctrl->val;
+               if (ctrl->val == 0) {
+                       dev->time_wrap_offset = 0;
+                       break;
+               }
+               v4l2_get_timestamp(&tv);
+               dev->time_wrap_offset = -tv.tv_sec - 16;
+               break;
+       }
+       return 0;
+}
+
+static const struct v4l2_ctrl_ops vivid_streaming_ctrl_ops = {
+       .s_ctrl = vivid_streaming_s_ctrl,
+};
+
+static const struct v4l2_ctrl_config vivid_ctrl_dqbuf_error = {
+       .ops = &vivid_streaming_ctrl_ops,
+       .id = VIVID_CID_DQBUF_ERROR,
+       .name = "Inject V4L2_BUF_FLAG_ERROR",
+       .type = V4L2_CTRL_TYPE_BUTTON,
+};
+
+static const struct v4l2_ctrl_config vivid_ctrl_perc_dropped = {
+       .ops = &vivid_streaming_ctrl_ops,
+       .id = VIVID_CID_PERC_DROPPED,
+       .name = "Percentage of Dropped Buffers",
+       .type = V4L2_CTRL_TYPE_INTEGER,
+       .min = 0,
+       .max = 100,
+       .step = 1,
+};
+
+static const struct v4l2_ctrl_config vivid_ctrl_queue_setup_error = {
+       .ops = &vivid_streaming_ctrl_ops,
+       .id = VIVID_CID_QUEUE_SETUP_ERROR,
+       .name = "Inject VIDIOC_REQBUFS Error",
+       .type = V4L2_CTRL_TYPE_BUTTON,
+};
+
+static const struct v4l2_ctrl_config vivid_ctrl_buf_prepare_error = {
+       .ops = &vivid_streaming_ctrl_ops,
+       .id = VIVID_CID_BUF_PREPARE_ERROR,
+       .name = "Inject VIDIOC_QBUF Error",
+       .type = V4L2_CTRL_TYPE_BUTTON,
+};
+
+static const struct v4l2_ctrl_config vivid_ctrl_start_streaming_error = {
+       .ops = &vivid_streaming_ctrl_ops,
+       .id = VIVID_CID_START_STR_ERROR,
+       .name = "Inject VIDIOC_STREAMON Error",
+       .type = V4L2_CTRL_TYPE_BUTTON,
+};
+
+static const struct v4l2_ctrl_config vivid_ctrl_queue_error = {
+       .ops = &vivid_streaming_ctrl_ops,
+       .id = VIVID_CID_QUEUE_ERROR,
+       .name = "Inject Fatal Streaming Error",
+       .type = V4L2_CTRL_TYPE_BUTTON,
+};
+
+static const struct v4l2_ctrl_config vivid_ctrl_seq_wrap = {
+       .ops = &vivid_streaming_ctrl_ops,
+       .id = VIVID_CID_SEQ_WRAP,
+       .name = "Wrap Sequence Number",
+       .type = V4L2_CTRL_TYPE_BOOLEAN,
+       .max = 1,
+       .step = 1,
+};
+
+static const struct v4l2_ctrl_config vivid_ctrl_time_wrap = {
+       .ops = &vivid_streaming_ctrl_ops,
+       .id = VIVID_CID_TIME_WRAP,
+       .name = "Wrap Timestamp",
+       .type = V4L2_CTRL_TYPE_BOOLEAN,
+       .max = 1,
+       .step = 1,
+};
+
+
+/* SDTV Capture Controls */
+
+static int vivid_sdtv_cap_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+       struct vivid_dev *dev = container_of(ctrl->handler, struct vivid_dev, ctrl_hdl_sdtv_cap);
+
+       switch (ctrl->id) {
+       case VIVID_CID_STD_SIGNAL_MODE:
+               dev->std_signal_mode = dev->ctrl_std_signal_mode->val;
+               if (dev->std_signal_mode == SELECTED_STD)
+                       dev->query_std = vivid_standard[dev->ctrl_standard->val];
+               v4l2_ctrl_activate(dev->ctrl_standard, dev->std_signal_mode == SELECTED_STD);
+               vivid_update_quality(dev);
+               vivid_send_source_change(dev, TV);
+               vivid_send_source_change(dev, SVID);
+               break;
+       }
+       return 0;
+}
+
+static const struct v4l2_ctrl_ops vivid_sdtv_cap_ctrl_ops = {
+       .s_ctrl = vivid_sdtv_cap_s_ctrl,
+};
+
+static const char * const vivid_ctrl_std_signal_mode_strings[] = {
+       "Current Standard",
+       "No Signal",
+       "No Lock",
+       "",
+       "Selected Standard",
+       "Cycle Through All Standards",
+       NULL,
+};
+
+static const struct v4l2_ctrl_config vivid_ctrl_std_signal_mode = {
+       .ops = &vivid_sdtv_cap_ctrl_ops,
+       .id = VIVID_CID_STD_SIGNAL_MODE,
+       .name = "Standard Signal Mode",
+       .type = V4L2_CTRL_TYPE_MENU,
+       .max = 5,
+       .menu_skip_mask = 1 << 3,
+       .qmenu = vivid_ctrl_std_signal_mode_strings,
+};
+
+static const struct v4l2_ctrl_config vivid_ctrl_standard = {
+       .ops = &vivid_sdtv_cap_ctrl_ops,
+       .id = VIVID_CID_STANDARD,
+       .name = "Standard",
+       .type = V4L2_CTRL_TYPE_MENU,
+       .max = 14,
+       .qmenu = vivid_ctrl_standard_strings,
+};
+
+
+
+/* Radio Receiver Controls */
+
+static int vivid_radio_rx_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+       struct vivid_dev *dev = container_of(ctrl->handler, struct vivid_dev, ctrl_hdl_radio_rx);
+
+       switch (ctrl->id) {
+       case VIVID_CID_RADIO_SEEK_MODE:
+               dev->radio_rx_hw_seek_mode = ctrl->val;
+               break;
+       case VIVID_CID_RADIO_SEEK_PROG_LIM:
+               dev->radio_rx_hw_seek_prog_lim = ctrl->val;
+               break;
+       case VIVID_CID_RADIO_RX_RDS_RBDS:
+               dev->rds_gen.use_rbds = ctrl->val;
+               break;
+       case VIVID_CID_RADIO_RX_RDS_BLOCKIO:
+               dev->radio_rx_rds_controls = ctrl->val;
+               dev->radio_rx_caps &= ~V4L2_CAP_READWRITE;
+               dev->radio_rx_rds_use_alternates = false;
+               if (!dev->radio_rx_rds_controls) {
+                       dev->radio_rx_caps |= V4L2_CAP_READWRITE;
+                       __v4l2_ctrl_s_ctrl(dev->radio_rx_rds_pty, 0);
+                       __v4l2_ctrl_s_ctrl(dev->radio_rx_rds_ta, 0);
+                       __v4l2_ctrl_s_ctrl(dev->radio_rx_rds_tp, 0);
+                       __v4l2_ctrl_s_ctrl(dev->radio_rx_rds_ms, 0);
+                       __v4l2_ctrl_s_ctrl_string(dev->radio_rx_rds_psname, "");
+                       __v4l2_ctrl_s_ctrl_string(dev->radio_rx_rds_radiotext, "");
+               }
+               v4l2_ctrl_activate(dev->radio_rx_rds_pty, dev->radio_rx_rds_controls);
+               v4l2_ctrl_activate(dev->radio_rx_rds_psname, dev->radio_rx_rds_controls);
+               v4l2_ctrl_activate(dev->radio_rx_rds_radiotext, dev->radio_rx_rds_controls);
+               v4l2_ctrl_activate(dev->radio_rx_rds_ta, dev->radio_rx_rds_controls);
+               v4l2_ctrl_activate(dev->radio_rx_rds_tp, dev->radio_rx_rds_controls);
+               v4l2_ctrl_activate(dev->radio_rx_rds_ms, dev->radio_rx_rds_controls);
+               break;
+       case V4L2_CID_RDS_RECEPTION:
+               dev->radio_rx_rds_enabled = ctrl->val;
+               break;
+       }
+       return 0;
+}
+
+static const struct v4l2_ctrl_ops vivid_radio_rx_ctrl_ops = {
+       .s_ctrl = vivid_radio_rx_s_ctrl,
+};
+
+static const char * const vivid_ctrl_radio_rds_mode_strings[] = {
+       "Block I/O",
+       "Controls",
+       NULL,
+};
+
+static const struct v4l2_ctrl_config vivid_ctrl_radio_rx_rds_blockio = {
+       .ops = &vivid_radio_rx_ctrl_ops,
+       .id = VIVID_CID_RADIO_RX_RDS_BLOCKIO,
+       .name = "RDS Rx I/O Mode",
+       .type = V4L2_CTRL_TYPE_MENU,
+       .qmenu = vivid_ctrl_radio_rds_mode_strings,
+       .max = 1,
+};
+
+static const struct v4l2_ctrl_config vivid_ctrl_radio_rx_rds_rbds = {
+       .ops = &vivid_radio_rx_ctrl_ops,
+       .id = VIVID_CID_RADIO_RX_RDS_RBDS,
+       .name = "Generate RBDS Instead of RDS",
+       .type = V4L2_CTRL_TYPE_BOOLEAN,
+       .max = 1,
+       .step = 1,
+};
+
+static const char * const vivid_ctrl_radio_hw_seek_mode_strings[] = {
+       "Bounded",
+       "Wrap Around",
+       "Both",
+       NULL,
+};
+
+static const struct v4l2_ctrl_config vivid_ctrl_radio_hw_seek_mode = {
+       .ops = &vivid_radio_rx_ctrl_ops,
+       .id = VIVID_CID_RADIO_SEEK_MODE,
+       .name = "Radio HW Seek Mode",
+       .type = V4L2_CTRL_TYPE_MENU,
+       .max = 2,
+       .qmenu = vivid_ctrl_radio_hw_seek_mode_strings,
+};
+
+static const struct v4l2_ctrl_config vivid_ctrl_radio_hw_seek_prog_lim = {
+       .ops = &vivid_radio_rx_ctrl_ops,
+       .id = VIVID_CID_RADIO_SEEK_PROG_LIM,
+       .name = "Radio Programmable HW Seek",
+       .type = V4L2_CTRL_TYPE_BOOLEAN,
+       .max = 1,
+       .step = 1,
+};
+
+
+/* Radio Transmitter Controls */
+
+static int vivid_radio_tx_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+       struct vivid_dev *dev = container_of(ctrl->handler, struct vivid_dev, ctrl_hdl_radio_tx);
+
+       switch (ctrl->id) {
+       case VIVID_CID_RADIO_TX_RDS_BLOCKIO:
+               dev->radio_tx_rds_controls = ctrl->val;
+               dev->radio_tx_caps &= ~V4L2_CAP_READWRITE;
+               if (!dev->radio_tx_rds_controls)
+                       dev->radio_tx_caps |= V4L2_CAP_READWRITE;
+               break;
+       case V4L2_CID_RDS_TX_PTY:
+               if (dev->radio_rx_rds_controls)
+                       v4l2_ctrl_s_ctrl(dev->radio_rx_rds_pty, ctrl->val);
+               break;
+       case V4L2_CID_RDS_TX_PS_NAME:
+               if (dev->radio_rx_rds_controls)
+                       v4l2_ctrl_s_ctrl_string(dev->radio_rx_rds_psname, ctrl->p_new.p_char);
+               break;
+       case V4L2_CID_RDS_TX_RADIO_TEXT:
+               if (dev->radio_rx_rds_controls)
+                       v4l2_ctrl_s_ctrl_string(dev->radio_rx_rds_radiotext, ctrl->p_new.p_char);
+               break;
+       case V4L2_CID_RDS_TX_TRAFFIC_ANNOUNCEMENT:
+               if (dev->radio_rx_rds_controls)
+                       v4l2_ctrl_s_ctrl(dev->radio_rx_rds_ta, ctrl->val);
+               break;
+       case V4L2_CID_RDS_TX_TRAFFIC_PROGRAM:
+               if (dev->radio_rx_rds_controls)
+                       v4l2_ctrl_s_ctrl(dev->radio_rx_rds_tp, ctrl->val);
+               break;
+       case V4L2_CID_RDS_TX_MUSIC_SPEECH:
+               if (dev->radio_rx_rds_controls)
+                       v4l2_ctrl_s_ctrl(dev->radio_rx_rds_ms, ctrl->val);
+               break;
+       }
+       return 0;
+}
+
+static const struct v4l2_ctrl_ops vivid_radio_tx_ctrl_ops = {
+       .s_ctrl = vivid_radio_tx_s_ctrl,
+};
+
+static const struct v4l2_ctrl_config vivid_ctrl_radio_tx_rds_blockio = {
+       .ops = &vivid_radio_tx_ctrl_ops,
+       .id = VIVID_CID_RADIO_TX_RDS_BLOCKIO,
+       .name = "RDS Tx I/O Mode",
+       .type = V4L2_CTRL_TYPE_MENU,
+       .qmenu = vivid_ctrl_radio_rds_mode_strings,
+       .max = 1,
+       .def = 1,
+};
+
+
+
+/* Video Loop Control */
+
+static int vivid_loop_out_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+       struct vivid_dev *dev = container_of(ctrl->handler, struct vivid_dev, ctrl_hdl_loop_out);
+
+       switch (ctrl->id) {
+       case VIVID_CID_LOOP_VIDEO:
+               dev->loop_video = ctrl->val;
+               vivid_update_quality(dev);
+               vivid_send_source_change(dev, SVID);
+               vivid_send_source_change(dev, HDMI);
+               break;
+       }
+       return 0;
+}
+
+static const struct v4l2_ctrl_ops vivid_loop_out_ctrl_ops = {
+       .s_ctrl = vivid_loop_out_s_ctrl,
+};
+
+static const struct v4l2_ctrl_config vivid_ctrl_loop_video = {
+       .ops = &vivid_loop_out_ctrl_ops,
+       .id = VIVID_CID_LOOP_VIDEO,
+       .name = "Loop Video",
+       .type = V4L2_CTRL_TYPE_BOOLEAN,
+       .max = 1,
+       .step = 1,
+};
+
+
+static const struct v4l2_ctrl_config vivid_ctrl_class = {
+       .ops = &vivid_user_gen_ctrl_ops,
+       .flags = V4L2_CTRL_FLAG_READ_ONLY | V4L2_CTRL_FLAG_WRITE_ONLY,
+       .id = VIVID_CID_VIVID_CLASS,
+       .name = "Vivid Controls",
+       .type = V4L2_CTRL_TYPE_CTRL_CLASS,
+};
+
+int vivid_create_controls(struct vivid_dev *dev, bool show_ccs_cap,
+               bool show_ccs_out, bool no_error_inj,
+               bool has_sdtv, bool has_hdmi)
+{
+       struct v4l2_ctrl_handler *hdl_user_gen = &dev->ctrl_hdl_user_gen;
+       struct v4l2_ctrl_handler *hdl_user_vid = &dev->ctrl_hdl_user_vid;
+       struct v4l2_ctrl_handler *hdl_user_aud = &dev->ctrl_hdl_user_aud;
+       struct v4l2_ctrl_handler *hdl_streaming = &dev->ctrl_hdl_streaming;
+       struct v4l2_ctrl_handler *hdl_sdtv_cap = &dev->ctrl_hdl_sdtv_cap;
+       struct v4l2_ctrl_handler *hdl_loop_out = &dev->ctrl_hdl_loop_out;
+       struct v4l2_ctrl_handler *hdl_vid_cap = &dev->ctrl_hdl_vid_cap;
+       struct v4l2_ctrl_handler *hdl_vid_out = &dev->ctrl_hdl_vid_out;
+       struct v4l2_ctrl_handler *hdl_vbi_cap = &dev->ctrl_hdl_vbi_cap;
+       struct v4l2_ctrl_handler *hdl_vbi_out = &dev->ctrl_hdl_vbi_out;
+       struct v4l2_ctrl_handler *hdl_radio_rx = &dev->ctrl_hdl_radio_rx;
+       struct v4l2_ctrl_handler *hdl_radio_tx = &dev->ctrl_hdl_radio_tx;
+       struct v4l2_ctrl_handler *hdl_sdr_cap = &dev->ctrl_hdl_sdr_cap;
+       struct v4l2_ctrl_config vivid_ctrl_dv_timings = {
+               .ops = &vivid_vid_cap_ctrl_ops,
+               .id = VIVID_CID_DV_TIMINGS,
+               .name = "DV Timings",
+               .type = V4L2_CTRL_TYPE_MENU,
+       };
+       int i;
+
+       v4l2_ctrl_handler_init(hdl_user_gen, 10);
+       v4l2_ctrl_new_custom(hdl_user_gen, &vivid_ctrl_class, NULL);
+       v4l2_ctrl_handler_init(hdl_user_vid, 9);
+       v4l2_ctrl_new_custom(hdl_user_vid, &vivid_ctrl_class, NULL);
+       v4l2_ctrl_handler_init(hdl_user_aud, 2);
+       v4l2_ctrl_new_custom(hdl_user_aud, &vivid_ctrl_class, NULL);
+       v4l2_ctrl_handler_init(hdl_streaming, 8);
+       v4l2_ctrl_new_custom(hdl_streaming, &vivid_ctrl_class, NULL);
+       v4l2_ctrl_handler_init(hdl_sdtv_cap, 2);
+       v4l2_ctrl_new_custom(hdl_sdtv_cap, &vivid_ctrl_class, NULL);
+       v4l2_ctrl_handler_init(hdl_loop_out, 1);
+       v4l2_ctrl_new_custom(hdl_loop_out, &vivid_ctrl_class, NULL);
+       v4l2_ctrl_handler_init(hdl_vid_cap, 55);
+       v4l2_ctrl_new_custom(hdl_vid_cap, &vivid_ctrl_class, NULL);
+       v4l2_ctrl_handler_init(hdl_vid_out, 26);
+       v4l2_ctrl_new_custom(hdl_vid_out, &vivid_ctrl_class, NULL);
+       v4l2_ctrl_handler_init(hdl_vbi_cap, 21);
+       v4l2_ctrl_new_custom(hdl_vbi_cap, &vivid_ctrl_class, NULL);
+       v4l2_ctrl_handler_init(hdl_vbi_out, 19);
+       v4l2_ctrl_new_custom(hdl_vbi_out, &vivid_ctrl_class, NULL);
+       v4l2_ctrl_handler_init(hdl_radio_rx, 17);
+       v4l2_ctrl_new_custom(hdl_radio_rx, &vivid_ctrl_class, NULL);
+       v4l2_ctrl_handler_init(hdl_radio_tx, 17);
+       v4l2_ctrl_new_custom(hdl_radio_tx, &vivid_ctrl_class, NULL);
+       v4l2_ctrl_handler_init(hdl_sdr_cap, 18);
+       v4l2_ctrl_new_custom(hdl_sdr_cap, &vivid_ctrl_class, NULL);
+
+       /* User Controls */
+       dev->volume = v4l2_ctrl_new_std(hdl_user_aud, NULL,
+               V4L2_CID_AUDIO_VOLUME, 0, 255, 1, 200);
+       dev->mute = v4l2_ctrl_new_std(hdl_user_aud, NULL,
+               V4L2_CID_AUDIO_MUTE, 0, 1, 1, 0);
+       if (dev->has_vid_cap) {
+               dev->brightness = v4l2_ctrl_new_std(hdl_user_vid, &vivid_user_vid_ctrl_ops,
+                       V4L2_CID_BRIGHTNESS, 0, 255, 1, 128);
+               for (i = 0; i < MAX_INPUTS; i++)
+                       dev->input_brightness[i] = 128;
+               dev->contrast = v4l2_ctrl_new_std(hdl_user_vid, &vivid_user_vid_ctrl_ops,
+                       V4L2_CID_CONTRAST, 0, 255, 1, 128);
+               dev->saturation = v4l2_ctrl_new_std(hdl_user_vid, &vivid_user_vid_ctrl_ops,
+                       V4L2_CID_SATURATION, 0, 255, 1, 128);
+               dev->hue = v4l2_ctrl_new_std(hdl_user_vid, &vivid_user_vid_ctrl_ops,
+                       V4L2_CID_HUE, -128, 128, 1, 0);
+               v4l2_ctrl_new_std(hdl_user_vid, &vivid_user_vid_ctrl_ops,
+                       V4L2_CID_HFLIP, 0, 1, 1, 0);
+               v4l2_ctrl_new_std(hdl_user_vid, &vivid_user_vid_ctrl_ops,
+                       V4L2_CID_VFLIP, 0, 1, 1, 0);
+               dev->autogain = v4l2_ctrl_new_std(hdl_user_vid, &vivid_user_vid_ctrl_ops,
+                       V4L2_CID_AUTOGAIN, 0, 1, 1, 1);
+               dev->gain = v4l2_ctrl_new_std(hdl_user_vid, &vivid_user_vid_ctrl_ops,
+                       V4L2_CID_GAIN, 0, 255, 1, 100);
+               dev->alpha = v4l2_ctrl_new_std(hdl_user_vid, &vivid_user_vid_ctrl_ops,
+                       V4L2_CID_ALPHA_COMPONENT, 0, 255, 1, 0);
+       }
+       dev->button = v4l2_ctrl_new_custom(hdl_user_gen, &vivid_ctrl_button, NULL);
+       dev->int32 = v4l2_ctrl_new_custom(hdl_user_gen, &vivid_ctrl_int32, NULL);
+       dev->int64 = v4l2_ctrl_new_custom(hdl_user_gen, &vivid_ctrl_int64, NULL);
+       dev->boolean = v4l2_ctrl_new_custom(hdl_user_gen, &vivid_ctrl_boolean, NULL);
+       dev->menu = v4l2_ctrl_new_custom(hdl_user_gen, &vivid_ctrl_menu, NULL);
+       dev->string = v4l2_ctrl_new_custom(hdl_user_gen, &vivid_ctrl_string, NULL);
+       dev->bitmask = v4l2_ctrl_new_custom(hdl_user_gen, &vivid_ctrl_bitmask, NULL);
+       dev->int_menu = v4l2_ctrl_new_custom(hdl_user_gen, &vivid_ctrl_int_menu, NULL);
+
+       if (dev->has_vid_cap) {
+               /* Image Processing Controls */
+               struct v4l2_ctrl_config vivid_ctrl_test_pattern = {
+                       .ops = &vivid_vid_cap_ctrl_ops,
+                       .id = VIVID_CID_TEST_PATTERN,
+                       .name = "Test Pattern",
+                       .type = V4L2_CTRL_TYPE_MENU,
+                       .max = TPG_PAT_NOISE,
+                       .qmenu = tpg_pattern_strings,
+               };
+
+               dev->test_pattern = v4l2_ctrl_new_custom(hdl_vid_cap,
+                               &vivid_ctrl_test_pattern, NULL);
+               v4l2_ctrl_new_custom(hdl_vid_cap, &vivid_ctrl_perc_fill, NULL);
+               v4l2_ctrl_new_custom(hdl_vid_cap, &vivid_ctrl_hor_movement, NULL);
+               v4l2_ctrl_new_custom(hdl_vid_cap, &vivid_ctrl_vert_movement, NULL);
+               v4l2_ctrl_new_custom(hdl_vid_cap, &vivid_ctrl_osd_mode, NULL);
+               v4l2_ctrl_new_custom(hdl_vid_cap, &vivid_ctrl_show_border, NULL);
+               v4l2_ctrl_new_custom(hdl_vid_cap, &vivid_ctrl_show_square, NULL);
+               v4l2_ctrl_new_custom(hdl_vid_cap, &vivid_ctrl_hflip, NULL);
+               v4l2_ctrl_new_custom(hdl_vid_cap, &vivid_ctrl_vflip, NULL);
+               v4l2_ctrl_new_custom(hdl_vid_cap, &vivid_ctrl_insert_sav, NULL);
+               v4l2_ctrl_new_custom(hdl_vid_cap, &vivid_ctrl_insert_eav, NULL);
+               if (show_ccs_cap) {
+                       dev->ctrl_has_crop_cap = v4l2_ctrl_new_custom(hdl_vid_cap,
+                               &vivid_ctrl_has_crop_cap, NULL);
+                       dev->ctrl_has_compose_cap = v4l2_ctrl_new_custom(hdl_vid_cap,
+                               &vivid_ctrl_has_compose_cap, NULL);
+                       dev->ctrl_has_scaler_cap = v4l2_ctrl_new_custom(hdl_vid_cap,
+                               &vivid_ctrl_has_scaler_cap, NULL);
+               }
+
+               v4l2_ctrl_new_custom(hdl_vid_cap, &vivid_ctrl_tstamp_src, NULL);
+               dev->colorspace = v4l2_ctrl_new_custom(hdl_vid_cap,
+                       &vivid_ctrl_colorspace, NULL);
+               v4l2_ctrl_new_custom(hdl_vid_cap, &vivid_ctrl_alpha_mode, NULL);
+       }
+
+       if (dev->has_vid_out && show_ccs_out) {
+               dev->ctrl_has_crop_out = v4l2_ctrl_new_custom(hdl_vid_out,
+                       &vivid_ctrl_has_crop_out, NULL);
+               dev->ctrl_has_compose_out = v4l2_ctrl_new_custom(hdl_vid_out,
+                       &vivid_ctrl_has_compose_out, NULL);
+               dev->ctrl_has_scaler_out = v4l2_ctrl_new_custom(hdl_vid_out,
+                       &vivid_ctrl_has_scaler_out, NULL);
+       }
+
+       /*
+        * Testing this driver with v4l2-compliance will trigger the error
+        * injection controls, and after that nothing will work as expected.
+        * So we have a module option to drop these error injecting controls
+        * allowing us to run v4l2_compliance again.
+        */
+       if (!no_error_inj) {
+               v4l2_ctrl_new_custom(hdl_user_gen, &vivid_ctrl_disconnect, NULL);
+               v4l2_ctrl_new_custom(hdl_streaming, &vivid_ctrl_dqbuf_error, NULL);
+               v4l2_ctrl_new_custom(hdl_streaming, &vivid_ctrl_perc_dropped, NULL);
+               v4l2_ctrl_new_custom(hdl_streaming, &vivid_ctrl_queue_setup_error, NULL);
+               v4l2_ctrl_new_custom(hdl_streaming, &vivid_ctrl_buf_prepare_error, NULL);
+               v4l2_ctrl_new_custom(hdl_streaming, &vivid_ctrl_start_streaming_error, NULL);
+               v4l2_ctrl_new_custom(hdl_streaming, &vivid_ctrl_queue_error, NULL);
+               v4l2_ctrl_new_custom(hdl_streaming, &vivid_ctrl_seq_wrap, NULL);
+               v4l2_ctrl_new_custom(hdl_streaming, &vivid_ctrl_time_wrap, NULL);
+       }
+
+       if (has_sdtv && (dev->has_vid_cap || dev->has_vbi_cap)) {
+               if (dev->has_vid_cap)
+                       v4l2_ctrl_new_custom(hdl_vid_cap, &vivid_ctrl_std_aspect_ratio, NULL);
+               dev->ctrl_std_signal_mode = v4l2_ctrl_new_custom(hdl_sdtv_cap,
+                       &vivid_ctrl_std_signal_mode, NULL);
+               dev->ctrl_standard = v4l2_ctrl_new_custom(hdl_sdtv_cap,
+                       &vivid_ctrl_standard, NULL);
+               if (dev->ctrl_std_signal_mode)
+                       v4l2_ctrl_cluster(2, &dev->ctrl_std_signal_mode);
+               if (dev->has_raw_vbi_cap)
+                       v4l2_ctrl_new_custom(hdl_vbi_cap, &vivid_ctrl_vbi_cap_interlaced, NULL);
+       }
+
+       if (has_hdmi && dev->has_vid_cap) {
+               dev->ctrl_dv_timings_signal_mode = v4l2_ctrl_new_custom(hdl_vid_cap,
+                                       &vivid_ctrl_dv_timings_signal_mode, NULL);
+
+               vivid_ctrl_dv_timings.max = dev->query_dv_timings_size - 1;
+               vivid_ctrl_dv_timings.qmenu =
+                       (const char * const *)dev->query_dv_timings_qmenu;
+               dev->ctrl_dv_timings = v4l2_ctrl_new_custom(hdl_vid_cap,
+                       &vivid_ctrl_dv_timings, NULL);
+               if (dev->ctrl_dv_timings_signal_mode)
+                       v4l2_ctrl_cluster(2, &dev->ctrl_dv_timings_signal_mode);
+
+               v4l2_ctrl_new_custom(hdl_vid_cap, &vivid_ctrl_dv_timings_aspect_ratio, NULL);
+               v4l2_ctrl_new_custom(hdl_vid_cap, &vivid_ctrl_max_edid_blocks, NULL);
+               dev->real_rgb_range_cap = v4l2_ctrl_new_custom(hdl_vid_cap,
+                       &vivid_ctrl_limited_rgb_range, NULL);
+               dev->rgb_range_cap = v4l2_ctrl_new_std_menu(hdl_vid_cap,
+                       &vivid_vid_cap_ctrl_ops,
+                       V4L2_CID_DV_RX_RGB_RANGE, V4L2_DV_RGB_RANGE_FULL,
+                       0, V4L2_DV_RGB_RANGE_AUTO);
+       }
+       if (has_hdmi && dev->has_vid_out) {
+               /*
+                * We aren't doing anything with this at the moment, but
+                * HDMI outputs typically have this controls.
+                */
+               dev->ctrl_tx_rgb_range = v4l2_ctrl_new_std_menu(hdl_vid_out, NULL,
+                       V4L2_CID_DV_TX_RGB_RANGE, V4L2_DV_RGB_RANGE_FULL,
+                       0, V4L2_DV_RGB_RANGE_AUTO);
+               dev->ctrl_tx_mode = v4l2_ctrl_new_std_menu(hdl_vid_out, NULL,
+                       V4L2_CID_DV_TX_MODE, V4L2_DV_TX_MODE_HDMI,
+                       0, V4L2_DV_TX_MODE_HDMI);
+       }
+       if ((dev->has_vid_cap && dev->has_vid_out) ||
+           (dev->has_vbi_cap && dev->has_vbi_out))
+               v4l2_ctrl_new_custom(hdl_loop_out, &vivid_ctrl_loop_video, NULL);
+
+       if (dev->has_fb)
+               v4l2_ctrl_new_custom(hdl_user_gen, &vivid_ctrl_clear_fb, NULL);
+
+       if (dev->has_radio_rx) {
+               v4l2_ctrl_new_custom(hdl_radio_rx, &vivid_ctrl_radio_hw_seek_mode, NULL);
+               v4l2_ctrl_new_custom(hdl_radio_rx, &vivid_ctrl_radio_hw_seek_prog_lim, NULL);
+               v4l2_ctrl_new_custom(hdl_radio_rx, &vivid_ctrl_radio_rx_rds_blockio, NULL);
+               v4l2_ctrl_new_custom(hdl_radio_rx, &vivid_ctrl_radio_rx_rds_rbds, NULL);
+               v4l2_ctrl_new_std(hdl_radio_rx, &vivid_radio_rx_ctrl_ops,
+                       V4L2_CID_RDS_RECEPTION, 0, 1, 1, 1);
+               dev->radio_rx_rds_pty = v4l2_ctrl_new_std(hdl_radio_rx,
+                       &vivid_radio_rx_ctrl_ops,
+                       V4L2_CID_RDS_RX_PTY, 0, 31, 1, 0);
+               dev->radio_rx_rds_psname = v4l2_ctrl_new_std(hdl_radio_rx,
+                       &vivid_radio_rx_ctrl_ops,
+                       V4L2_CID_RDS_RX_PS_NAME, 0, 8, 8, 0);
+               dev->radio_rx_rds_radiotext = v4l2_ctrl_new_std(hdl_radio_rx,
+                       &vivid_radio_rx_ctrl_ops,
+                       V4L2_CID_RDS_RX_RADIO_TEXT, 0, 64, 64, 0);
+               dev->radio_rx_rds_ta = v4l2_ctrl_new_std(hdl_radio_rx,
+                       &vivid_radio_rx_ctrl_ops,
+                       V4L2_CID_RDS_RX_TRAFFIC_ANNOUNCEMENT, 0, 1, 1, 0);
+               dev->radio_rx_rds_tp = v4l2_ctrl_new_std(hdl_radio_rx,
+                       &vivid_radio_rx_ctrl_ops,
+                       V4L2_CID_RDS_RX_TRAFFIC_PROGRAM, 0, 1, 1, 0);
+               dev->radio_rx_rds_ms = v4l2_ctrl_new_std(hdl_radio_rx,
+                       &vivid_radio_rx_ctrl_ops,
+                       V4L2_CID_RDS_RX_MUSIC_SPEECH, 0, 1, 1, 1);
+       }
+       if (dev->has_radio_tx) {
+               v4l2_ctrl_new_custom(hdl_radio_tx,
+                       &vivid_ctrl_radio_tx_rds_blockio, NULL);
+               dev->radio_tx_rds_pi = v4l2_ctrl_new_std(hdl_radio_tx,
+                       &vivid_radio_tx_ctrl_ops,
+                       V4L2_CID_RDS_TX_PI, 0, 0xffff, 1, 0x8088);
+               dev->radio_tx_rds_pty = v4l2_ctrl_new_std(hdl_radio_tx,
+                       &vivid_radio_tx_ctrl_ops,
+                       V4L2_CID_RDS_TX_PTY, 0, 31, 1, 3);
+               dev->radio_tx_rds_psname = v4l2_ctrl_new_std(hdl_radio_tx,
+                       &vivid_radio_tx_ctrl_ops,
+                       V4L2_CID_RDS_TX_PS_NAME, 0, 8, 8, 0);
+               if (dev->radio_tx_rds_psname)
+                       v4l2_ctrl_s_ctrl_string(dev->radio_tx_rds_psname, "VIVID-TX");
+               dev->radio_tx_rds_radiotext = v4l2_ctrl_new_std(hdl_radio_tx,
+                       &vivid_radio_tx_ctrl_ops,
+                       V4L2_CID_RDS_TX_RADIO_TEXT, 0, 64 * 2, 64, 0);
+               if (dev->radio_tx_rds_radiotext)
+                       v4l2_ctrl_s_ctrl_string(dev->radio_tx_rds_radiotext,
+                              "This is a VIVID default Radio Text template text, change at will");
+               dev->radio_tx_rds_mono_stereo = v4l2_ctrl_new_std(hdl_radio_tx,
+                       &vivid_radio_tx_ctrl_ops,
+                       V4L2_CID_RDS_TX_MONO_STEREO, 0, 1, 1, 1);
+               dev->radio_tx_rds_art_head = v4l2_ctrl_new_std(hdl_radio_tx,
+                       &vivid_radio_tx_ctrl_ops,
+                       V4L2_CID_RDS_TX_ARTIFICIAL_HEAD, 0, 1, 1, 0);
+               dev->radio_tx_rds_compressed = v4l2_ctrl_new_std(hdl_radio_tx,
+                       &vivid_radio_tx_ctrl_ops,
+                       V4L2_CID_RDS_TX_COMPRESSED, 0, 1, 1, 0);
+               dev->radio_tx_rds_dyn_pty = v4l2_ctrl_new_std(hdl_radio_tx,
+                       &vivid_radio_tx_ctrl_ops,
+                       V4L2_CID_RDS_TX_DYNAMIC_PTY, 0, 1, 1, 0);
+               dev->radio_tx_rds_ta = v4l2_ctrl_new_std(hdl_radio_tx,
+                       &vivid_radio_tx_ctrl_ops,
+                       V4L2_CID_RDS_TX_TRAFFIC_ANNOUNCEMENT, 0, 1, 1, 0);
+               dev->radio_tx_rds_tp = v4l2_ctrl_new_std(hdl_radio_tx,
+                       &vivid_radio_tx_ctrl_ops,
+                       V4L2_CID_RDS_TX_TRAFFIC_PROGRAM, 0, 1, 1, 1);
+               dev->radio_tx_rds_ms = v4l2_ctrl_new_std(hdl_radio_tx,
+                       &vivid_radio_tx_ctrl_ops,
+                       V4L2_CID_RDS_TX_MUSIC_SPEECH, 0, 1, 1, 1);
+       }
+       if (hdl_user_gen->error)
+               return hdl_user_gen->error;
+       if (hdl_user_vid->error)
+               return hdl_user_vid->error;
+       if (hdl_user_aud->error)
+               return hdl_user_aud->error;
+       if (hdl_streaming->error)
+               return hdl_streaming->error;
+       if (hdl_sdr_cap->error)
+               return hdl_sdr_cap->error;
+       if (hdl_loop_out->error)
+               return hdl_loop_out->error;
+
+       if (dev->autogain)
+               v4l2_ctrl_auto_cluster(2, &dev->autogain, 0, true);
+
+       if (dev->has_vid_cap) {
+               v4l2_ctrl_add_handler(hdl_vid_cap, hdl_user_gen, NULL);
+               v4l2_ctrl_add_handler(hdl_vid_cap, hdl_user_vid, NULL);
+               v4l2_ctrl_add_handler(hdl_vid_cap, hdl_user_aud, NULL);
+               v4l2_ctrl_add_handler(hdl_vid_cap, hdl_streaming, NULL);
+               v4l2_ctrl_add_handler(hdl_vid_cap, hdl_sdtv_cap, NULL);
+               if (hdl_vid_cap->error)
+                       return hdl_vid_cap->error;
+               dev->vid_cap_dev.ctrl_handler = hdl_vid_cap;
+       }
+       if (dev->has_vid_out) {
+               v4l2_ctrl_add_handler(hdl_vid_out, hdl_user_gen, NULL);
+               v4l2_ctrl_add_handler(hdl_vid_out, hdl_user_aud, NULL);
+               v4l2_ctrl_add_handler(hdl_vid_out, hdl_streaming, NULL);
+               v4l2_ctrl_add_handler(hdl_vid_out, hdl_loop_out, NULL);
+               if (hdl_vid_out->error)
+                       return hdl_vid_out->error;
+               dev->vid_out_dev.ctrl_handler = hdl_vid_out;
+       }
+       if (dev->has_vbi_cap) {
+               v4l2_ctrl_add_handler(hdl_vbi_cap, hdl_user_gen, NULL);
+               v4l2_ctrl_add_handler(hdl_vbi_cap, hdl_streaming, NULL);
+               v4l2_ctrl_add_handler(hdl_vbi_cap, hdl_sdtv_cap, NULL);
+               if (hdl_vbi_cap->error)
+                       return hdl_vbi_cap->error;
+               dev->vbi_cap_dev.ctrl_handler = hdl_vbi_cap;
+       }
+       if (dev->has_vbi_out) {
+               v4l2_ctrl_add_handler(hdl_vbi_out, hdl_user_gen, NULL);
+               v4l2_ctrl_add_handler(hdl_vbi_out, hdl_streaming, NULL);
+               v4l2_ctrl_add_handler(hdl_vbi_out, hdl_loop_out, NULL);
+               if (hdl_vbi_out->error)
+                       return hdl_vbi_out->error;
+               dev->vbi_out_dev.ctrl_handler = hdl_vbi_out;
+       }
+       if (dev->has_radio_rx) {
+               v4l2_ctrl_add_handler(hdl_radio_rx, hdl_user_gen, NULL);
+               v4l2_ctrl_add_handler(hdl_radio_rx, hdl_user_aud, NULL);
+               if (hdl_radio_rx->error)
+                       return hdl_radio_rx->error;
+               dev->radio_rx_dev.ctrl_handler = hdl_radio_rx;
+       }
+       if (dev->has_radio_tx) {
+               v4l2_ctrl_add_handler(hdl_radio_tx, hdl_user_gen, NULL);
+               v4l2_ctrl_add_handler(hdl_radio_tx, hdl_user_aud, NULL);
+               if (hdl_radio_tx->error)
+                       return hdl_radio_tx->error;
+               dev->radio_tx_dev.ctrl_handler = hdl_radio_tx;
+       }
+       if (dev->has_sdr_cap) {
+               v4l2_ctrl_add_handler(hdl_sdr_cap, hdl_user_gen, NULL);
+               v4l2_ctrl_add_handler(hdl_sdr_cap, hdl_streaming, NULL);
+               if (hdl_sdr_cap->error)
+                       return hdl_sdr_cap->error;
+               dev->sdr_cap_dev.ctrl_handler = hdl_sdr_cap;
+       }
+       return 0;
+}
+
+void vivid_free_controls(struct vivid_dev *dev)
+{
+       v4l2_ctrl_handler_free(&dev->ctrl_hdl_vid_cap);
+       v4l2_ctrl_handler_free(&dev->ctrl_hdl_vid_out);
+       v4l2_ctrl_handler_free(&dev->ctrl_hdl_vbi_cap);
+       v4l2_ctrl_handler_free(&dev->ctrl_hdl_vbi_out);
+       v4l2_ctrl_handler_free(&dev->ctrl_hdl_radio_rx);
+       v4l2_ctrl_handler_free(&dev->ctrl_hdl_radio_tx);
+       v4l2_ctrl_handler_free(&dev->ctrl_hdl_sdr_cap);
+       v4l2_ctrl_handler_free(&dev->ctrl_hdl_user_gen);
+       v4l2_ctrl_handler_free(&dev->ctrl_hdl_user_vid);
+       v4l2_ctrl_handler_free(&dev->ctrl_hdl_user_aud);
+       v4l2_ctrl_handler_free(&dev->ctrl_hdl_streaming);
+       v4l2_ctrl_handler_free(&dev->ctrl_hdl_sdtv_cap);
+       v4l2_ctrl_handler_free(&dev->ctrl_hdl_loop_out);
+}
diff --git a/drivers/media/platform/vivid/vivid-ctrls.h b/drivers/media/platform/vivid/vivid-ctrls.h
new file mode 100644 (file)
index 0000000..9bcca9d
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * vivid-ctrls.h - control support functions.
+ *
+ * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
+ *
+ * This program is free software; you may redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * 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 _VIVID_CTRLS_H_
+#define _VIVID_CTRLS_H_
+
+enum vivid_hw_seek_modes {
+       VIVID_HW_SEEK_BOUNDED,
+       VIVID_HW_SEEK_WRAP,
+       VIVID_HW_SEEK_BOTH,
+};
+
+int vivid_create_controls(struct vivid_dev *dev, bool show_ccs_cap,
+               bool show_ccs_out, bool no_error_inj,
+               bool has_sdtv, bool has_hdmi);
+void vivid_free_controls(struct vivid_dev *dev);
+
+#endif
diff --git a/drivers/media/platform/vivid/vivid-kthread-cap.c b/drivers/media/platform/vivid/vivid-kthread-cap.c
new file mode 100644 (file)
index 0000000..39a67cf
--- /dev/null
@@ -0,0 +1,886 @@
+/*
+ * vivid-kthread-cap.h - video/vbi capture thread support functions.
+ *
+ * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
+ *
+ * This program is free software; you may redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * 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/errno.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/font.h>
+#include <linux/mutex.h>
+#include <linux/videodev2.h>
+#include <linux/kthread.h>
+#include <linux/freezer.h>
+#include <linux/random.h>
+#include <linux/v4l2-dv-timings.h>
+#include <asm/div64.h>
+#include <media/videobuf2-vmalloc.h>
+#include <media/v4l2-dv-timings.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-fh.h>
+#include <media/v4l2-event.h>
+
+#include "vivid-core.h"
+#include "vivid-vid-common.h"
+#include "vivid-vid-cap.h"
+#include "vivid-vid-out.h"
+#include "vivid-radio-common.h"
+#include "vivid-radio-rx.h"
+#include "vivid-radio-tx.h"
+#include "vivid-sdr-cap.h"
+#include "vivid-vbi-cap.h"
+#include "vivid-vbi-out.h"
+#include "vivid-osd.h"
+#include "vivid-ctrls.h"
+#include "vivid-kthread-cap.h"
+
+static inline v4l2_std_id vivid_get_std_cap(const struct vivid_dev *dev)
+{
+       if (vivid_is_sdtv_cap(dev))
+               return dev->std_cap;
+       return 0;
+}
+
+static void copy_pix(struct vivid_dev *dev, int win_y, int win_x,
+                       u16 *cap, const u16 *osd)
+{
+       u16 out;
+       int left = dev->overlay_out_left;
+       int top = dev->overlay_out_top;
+       int fb_x = win_x + left;
+       int fb_y = win_y + top;
+       int i;
+
+       out = *cap;
+       *cap = *osd;
+       if (dev->bitmap_out) {
+               const u8 *p = dev->bitmap_out;
+               unsigned stride = (dev->compose_out.width + 7) / 8;
+
+               win_x -= dev->compose_out.left;
+               win_y -= dev->compose_out.top;
+               if (!(p[stride * win_y + win_x / 8] & (1 << (win_x & 7))))
+                       return;
+       }
+
+       for (i = 0; i < dev->clipcount_out; i++) {
+               struct v4l2_rect *r = &dev->clips_out[i].c;
+
+               if (fb_y >= r->top && fb_y < r->top + r->height &&
+                   fb_x >= r->left && fb_x < r->left + r->width)
+                       return;
+       }
+       if ((dev->fbuf_out_flags & V4L2_FBUF_FLAG_CHROMAKEY) &&
+           *osd != dev->chromakey_out)
+               return;
+       if ((dev->fbuf_out_flags & V4L2_FBUF_FLAG_SRC_CHROMAKEY) &&
+           out == dev->chromakey_out)
+               return;
+       if (dev->fmt_cap->alpha_mask) {
+               if ((dev->fbuf_out_flags & V4L2_FBUF_FLAG_GLOBAL_ALPHA) &&
+                   dev->global_alpha_out)
+                       return;
+               if ((dev->fbuf_out_flags & V4L2_FBUF_FLAG_LOCAL_ALPHA) &&
+                   *cap & dev->fmt_cap->alpha_mask)
+                       return;
+               if ((dev->fbuf_out_flags & V4L2_FBUF_FLAG_LOCAL_INV_ALPHA) &&
+                   !(*cap & dev->fmt_cap->alpha_mask))
+                       return;
+       }
+       *cap = out;
+}
+
+static void blend_line(struct vivid_dev *dev, unsigned y_offset, unsigned x_offset,
+               u8 *vcapbuf, const u8 *vosdbuf,
+               unsigned width, unsigned pixsize)
+{
+       unsigned x;
+
+       for (x = 0; x < width; x++, vcapbuf += pixsize, vosdbuf += pixsize) {
+               copy_pix(dev, y_offset, x_offset + x,
+                        (u16 *)vcapbuf, (const u16 *)vosdbuf);
+       }
+}
+
+static void scale_line(const u8 *src, u8 *dst, unsigned srcw, unsigned dstw, unsigned twopixsize)
+{
+       /* Coarse scaling with Bresenham */
+       unsigned int_part;
+       unsigned fract_part;
+       unsigned src_x = 0;
+       unsigned error = 0;
+       unsigned x;
+
+       /*
+        * We always combine two pixels to prevent color bleed in the packed
+        * yuv case.
+        */
+       srcw /= 2;
+       dstw /= 2;
+       int_part = srcw / dstw;
+       fract_part = srcw % dstw;
+       for (x = 0; x < dstw; x++, dst += twopixsize) {
+               memcpy(dst, src + src_x * twopixsize, twopixsize);
+               src_x += int_part;
+               error += fract_part;
+               if (error >= dstw) {
+                       error -= dstw;
+                       src_x++;
+               }
+       }
+}
+
+/*
+ * Precalculate the rectangles needed to perform video looping:
+ *
+ * The nominal pipeline is that the video output buffer is cropped by
+ * crop_out, scaled to compose_out, overlaid with the output overlay,
+ * cropped on the capture side by crop_cap and scaled again to the video
+ * capture buffer using compose_cap.
+ *
+ * To keep things efficient we calculate the intersection of compose_out
+ * and crop_cap (since that's the only part of the video that will
+ * actually end up in the capture buffer), determine which part of the
+ * video output buffer that is and which part of the video capture buffer
+ * so we can scale the video straight from the output buffer to the capture
+ * buffer without any intermediate steps.
+ *
+ * If we need to deal with an output overlay, then there is no choice and
+ * that intermediate step still has to be taken. For the output overlay
+ * support we calculate the intersection of the framebuffer and the overlay
+ * window (which may be partially or wholly outside of the framebuffer
+ * itself) and the intersection of that with loop_vid_copy (i.e. the part of
+ * the actual looped video that will be overlaid). The result is calculated
+ * both in framebuffer coordinates (loop_fb_copy) and compose_out coordinates
+ * (loop_vid_overlay). Finally calculate the part of the capture buffer that
+ * will receive that overlaid video.
+ */
+static void vivid_precalc_copy_rects(struct vivid_dev *dev)
+{
+       /* Framebuffer rectangle */
+       struct v4l2_rect r_fb = {
+               0, 0, dev->display_width, dev->display_height
+       };
+       /* Overlay window rectangle in framebuffer coordinates */
+       struct v4l2_rect r_overlay = {
+               dev->overlay_out_left, dev->overlay_out_top,
+               dev->compose_out.width, dev->compose_out.height
+       };
+
+       dev->loop_vid_copy = rect_intersect(&dev->crop_cap, &dev->compose_out);
+
+       dev->loop_vid_out = dev->loop_vid_copy;
+       rect_scale(&dev->loop_vid_out, &dev->compose_out, &dev->crop_out);
+       dev->loop_vid_out.left += dev->crop_out.left;
+       dev->loop_vid_out.top += dev->crop_out.top;
+
+       dev->loop_vid_cap = dev->loop_vid_copy;
+       rect_scale(&dev->loop_vid_cap, &dev->crop_cap, &dev->compose_cap);
+
+       dprintk(dev, 1,
+               "loop_vid_copy: %dx%d@%dx%d loop_vid_out: %dx%d@%dx%d loop_vid_cap: %dx%d@%dx%d\n",
+               dev->loop_vid_copy.width, dev->loop_vid_copy.height,
+               dev->loop_vid_copy.left, dev->loop_vid_copy.top,
+               dev->loop_vid_out.width, dev->loop_vid_out.height,
+               dev->loop_vid_out.left, dev->loop_vid_out.top,
+               dev->loop_vid_cap.width, dev->loop_vid_cap.height,
+               dev->loop_vid_cap.left, dev->loop_vid_cap.top);
+
+       r_overlay = rect_intersect(&r_fb, &r_overlay);
+
+       /* shift r_overlay to the same origin as compose_out */
+       r_overlay.left += dev->compose_out.left - dev->overlay_out_left;
+       r_overlay.top += dev->compose_out.top - dev->overlay_out_top;
+
+       dev->loop_vid_overlay = rect_intersect(&r_overlay, &dev->loop_vid_copy);
+       dev->loop_fb_copy = dev->loop_vid_overlay;
+
+       /* shift dev->loop_fb_copy back again to the fb origin */
+       dev->loop_fb_copy.left -= dev->compose_out.left - dev->overlay_out_left;
+       dev->loop_fb_copy.top -= dev->compose_out.top - dev->overlay_out_top;
+
+       dev->loop_vid_overlay_cap = dev->loop_vid_overlay;
+       rect_scale(&dev->loop_vid_overlay_cap, &dev->crop_cap, &dev->compose_cap);
+
+       dprintk(dev, 1,
+               "loop_fb_copy: %dx%d@%dx%d loop_vid_overlay: %dx%d@%dx%d loop_vid_overlay_cap: %dx%d@%dx%d\n",
+               dev->loop_fb_copy.width, dev->loop_fb_copy.height,
+               dev->loop_fb_copy.left, dev->loop_fb_copy.top,
+               dev->loop_vid_overlay.width, dev->loop_vid_overlay.height,
+               dev->loop_vid_overlay.left, dev->loop_vid_overlay.top,
+               dev->loop_vid_overlay_cap.width, dev->loop_vid_overlay_cap.height,
+               dev->loop_vid_overlay_cap.left, dev->loop_vid_overlay_cap.top);
+}
+
+static int vivid_copy_buffer(struct vivid_dev *dev, unsigned p, u8 *vcapbuf,
+               struct vivid_buffer *vid_cap_buf)
+{
+       bool blank = dev->must_blank[vid_cap_buf->vb.v4l2_buf.index];
+       struct tpg_data *tpg = &dev->tpg;
+       struct vivid_buffer *vid_out_buf = NULL;
+       unsigned pixsize = tpg_g_twopixelsize(tpg, p) / 2;
+       unsigned img_width = dev->compose_cap.width;
+       unsigned img_height = dev->compose_cap.height;
+       unsigned stride_cap = tpg->bytesperline[p];
+       unsigned stride_out = dev->bytesperline_out[p];
+       unsigned stride_osd = dev->display_byte_stride;
+       unsigned hmax = (img_height * tpg->perc_fill) / 100;
+       u8 *voutbuf;
+       u8 *vosdbuf = NULL;
+       unsigned y;
+       bool blend = dev->bitmap_out || dev->clipcount_out || dev->fbuf_out_flags;
+       /* Coarse scaling with Bresenham */
+       unsigned vid_out_int_part;
+       unsigned vid_out_fract_part;
+       unsigned vid_out_y = 0;
+       unsigned vid_out_error = 0;
+       unsigned vid_overlay_int_part = 0;
+       unsigned vid_overlay_fract_part = 0;
+       unsigned vid_overlay_y = 0;
+       unsigned vid_overlay_error = 0;
+       unsigned vid_cap_right;
+       bool quick;
+
+       vid_out_int_part = dev->loop_vid_out.height / dev->loop_vid_cap.height;
+       vid_out_fract_part = dev->loop_vid_out.height % dev->loop_vid_cap.height;
+
+       if (!list_empty(&dev->vid_out_active))
+               vid_out_buf = list_entry(dev->vid_out_active.next,
+                                        struct vivid_buffer, list);
+       if (vid_out_buf == NULL)
+               return -ENODATA;
+
+       vid_cap_buf->vb.v4l2_buf.field = vid_out_buf->vb.v4l2_buf.field;
+
+       voutbuf = vb2_plane_vaddr(&vid_out_buf->vb, p) +
+                                 vid_out_buf->vb.v4l2_planes[p].data_offset;
+       voutbuf += dev->loop_vid_out.left * pixsize + dev->loop_vid_out.top * stride_out;
+       vcapbuf += dev->compose_cap.left * pixsize + dev->compose_cap.top * stride_cap;
+
+       if (dev->loop_vid_copy.width == 0 || dev->loop_vid_copy.height == 0) {
+               /*
+                * If there is nothing to copy, then just fill the capture window
+                * with black.
+                */
+               for (y = 0; y < hmax; y++, vcapbuf += stride_cap)
+                       memcpy(vcapbuf, tpg->black_line[p], img_width * pixsize);
+               return 0;
+       }
+
+       if (dev->overlay_out_enabled &&
+           dev->loop_vid_overlay.width && dev->loop_vid_overlay.height) {
+               vosdbuf = dev->video_vbase;
+               vosdbuf += dev->loop_fb_copy.left * pixsize +
+                          dev->loop_fb_copy.top * stride_osd;
+               vid_overlay_int_part = dev->loop_vid_overlay.height /
+                                      dev->loop_vid_overlay_cap.height;
+               vid_overlay_fract_part = dev->loop_vid_overlay.height %
+                                        dev->loop_vid_overlay_cap.height;
+       }
+
+       vid_cap_right = dev->loop_vid_cap.left + dev->loop_vid_cap.width;
+       /* quick is true if no video scaling is needed */
+       quick = dev->loop_vid_out.width == dev->loop_vid_cap.width;
+
+       dev->cur_scaled_line = dev->loop_vid_out.height;
+       for (y = 0; y < hmax; y++, vcapbuf += stride_cap) {
+               /* osdline is true if this line requires overlay blending */
+               bool osdline = vosdbuf && y >= dev->loop_vid_overlay_cap.top &&
+                         y < dev->loop_vid_overlay_cap.top + dev->loop_vid_overlay_cap.height;
+
+               /*
+                * If this line of the capture buffer doesn't get any video, then
+                * just fill with black.
+                */
+               if (y < dev->loop_vid_cap.top ||
+                   y >= dev->loop_vid_cap.top + dev->loop_vid_cap.height) {
+                       memcpy(vcapbuf, tpg->black_line[p], img_width * pixsize);
+                       continue;
+               }
+
+               /* fill the left border with black */
+               if (dev->loop_vid_cap.left)
+                       memcpy(vcapbuf, tpg->black_line[p], dev->loop_vid_cap.left * pixsize);
+
+               /* fill the right border with black */
+               if (vid_cap_right < img_width)
+                       memcpy(vcapbuf + vid_cap_right * pixsize,
+                               tpg->black_line[p], (img_width - vid_cap_right) * pixsize);
+
+               if (quick && !osdline) {
+                       memcpy(vcapbuf + dev->loop_vid_cap.left * pixsize,
+                              voutbuf + vid_out_y * stride_out,
+                              dev->loop_vid_cap.width * pixsize);
+                       goto update_vid_out_y;
+               }
+               if (dev->cur_scaled_line == vid_out_y) {
+                       memcpy(vcapbuf + dev->loop_vid_cap.left * pixsize,
+                              dev->scaled_line,
+                              dev->loop_vid_cap.width * pixsize);
+                       goto update_vid_out_y;
+               }
+               if (!osdline) {
+                       scale_line(voutbuf + vid_out_y * stride_out, dev->scaled_line,
+                               dev->loop_vid_out.width, dev->loop_vid_cap.width,
+                               tpg_g_twopixelsize(tpg, p));
+               } else {
+                       /*
+                        * Offset in bytes within loop_vid_copy to the start of the
+                        * loop_vid_overlay rectangle.
+                        */
+                       unsigned offset =
+                               (dev->loop_vid_overlay.left - dev->loop_vid_copy.left) * pixsize;
+                       u8 *osd = vosdbuf + vid_overlay_y * stride_osd;
+
+                       scale_line(voutbuf + vid_out_y * stride_out, dev->blended_line,
+                               dev->loop_vid_out.width, dev->loop_vid_copy.width,
+                               tpg_g_twopixelsize(tpg, p));
+                       if (blend)
+                               blend_line(dev, vid_overlay_y + dev->loop_vid_overlay.top,
+                                          dev->loop_vid_overlay.left,
+                                          dev->blended_line + offset, osd,
+                                          dev->loop_vid_overlay.width, pixsize);
+                       else
+                               memcpy(dev->blended_line + offset,
+                                      osd, dev->loop_vid_overlay.width * pixsize);
+                       scale_line(dev->blended_line, dev->scaled_line,
+                                       dev->loop_vid_copy.width, dev->loop_vid_cap.width,
+                                       tpg_g_twopixelsize(tpg, p));
+               }
+               dev->cur_scaled_line = vid_out_y;
+               memcpy(vcapbuf + dev->loop_vid_cap.left * pixsize,
+                      dev->scaled_line,
+                      dev->loop_vid_cap.width * pixsize);
+
+update_vid_out_y:
+               if (osdline) {
+                       vid_overlay_y += vid_overlay_int_part;
+                       vid_overlay_error += vid_overlay_fract_part;
+                       if (vid_overlay_error >= dev->loop_vid_overlay_cap.height) {
+                               vid_overlay_error -= dev->loop_vid_overlay_cap.height;
+                               vid_overlay_y++;
+                       }
+               }
+               vid_out_y += vid_out_int_part;
+               vid_out_error += vid_out_fract_part;
+               if (vid_out_error >= dev->loop_vid_cap.height) {
+                       vid_out_error -= dev->loop_vid_cap.height;
+                       vid_out_y++;
+               }
+       }
+
+       if (!blank)
+               return 0;
+       for (; y < img_height; y++, vcapbuf += stride_cap)
+               memcpy(vcapbuf, tpg->contrast_line[p], img_width * pixsize);
+       return 0;
+}
+
+static void vivid_fillbuff(struct vivid_dev *dev, struct vivid_buffer *buf)
+{
+       unsigned factor = V4L2_FIELD_HAS_T_OR_B(dev->field_cap) ? 2 : 1;
+       unsigned line_height = 16 / factor;
+       bool is_tv = vivid_is_sdtv_cap(dev);
+       bool is_60hz = is_tv && (dev->std_cap & V4L2_STD_525_60);
+       unsigned p;
+       int line = 1;
+       u8 *basep[TPG_MAX_PLANES][2];
+       unsigned ms;
+       char str[100];
+       s32 gain;
+       bool is_loop = false;
+
+       if (dev->loop_video && dev->can_loop_video &&
+           ((vivid_is_svid_cap(dev) && !VIVID_INVALID_SIGNAL(dev->std_signal_mode)) ||
+            (vivid_is_hdmi_cap(dev) && !VIVID_INVALID_SIGNAL(dev->dv_timings_signal_mode))))
+               is_loop = true;
+
+       buf->vb.v4l2_buf.sequence = dev->vid_cap_seq_count;
+       /*
+        * Take the timestamp now if the timestamp source is set to
+        * "Start of Exposure".
+        */
+       if (dev->tstamp_src_is_soe)
+               v4l2_get_timestamp(&buf->vb.v4l2_buf.timestamp);
+       if (dev->field_cap == V4L2_FIELD_ALTERNATE) {
+               /*
+                * 60 Hz standards start with the bottom field, 50 Hz standards
+                * with the top field. So if the 0-based seq_count is even,
+                * then the field is TOP for 50 Hz and BOTTOM for 60 Hz
+                * standards.
+                */
+               buf->vb.v4l2_buf.field = ((dev->vid_cap_seq_count & 1) ^ is_60hz) ?
+                       V4L2_FIELD_TOP : V4L2_FIELD_BOTTOM;
+               /*
+                * The sequence counter counts frames, not fields. So divide
+                * by two.
+                */
+               buf->vb.v4l2_buf.sequence /= 2;
+       } else {
+               buf->vb.v4l2_buf.field = dev->field_cap;
+       }
+       tpg_s_field(&dev->tpg, buf->vb.v4l2_buf.field);
+       tpg_s_perc_fill_blank(&dev->tpg, dev->must_blank[buf->vb.v4l2_buf.index]);
+
+       vivid_precalc_copy_rects(dev);
+
+       for (p = 0; p < tpg_g_planes(&dev->tpg); p++) {
+               void *vbuf = vb2_plane_vaddr(&buf->vb, p);
+
+               /*
+                * The first plane of a multiplanar format has a non-zero
+                * data_offset. This helps testing whether the application
+                * correctly supports non-zero data offsets.
+                */
+               if (dev->fmt_cap->data_offset[p]) {
+                       memset(vbuf, dev->fmt_cap->data_offset[p] & 0xff,
+                              dev->fmt_cap->data_offset[p]);
+                       vbuf += dev->fmt_cap->data_offset[p];
+               }
+               tpg_calc_text_basep(&dev->tpg, basep, p, vbuf);
+               if (!is_loop || vivid_copy_buffer(dev, p, vbuf, buf))
+                       tpg_fillbuffer(&dev->tpg, vivid_get_std_cap(dev), p, vbuf);
+       }
+       dev->must_blank[buf->vb.v4l2_buf.index] = false;
+
+       /* Updates stream time, only update at the start of a new frame. */
+       if (dev->field_cap != V4L2_FIELD_ALTERNATE || (buf->vb.v4l2_buf.sequence & 1) == 0)
+               dev->ms_vid_cap = jiffies_to_msecs(jiffies - dev->jiffies_vid_cap);
+
+       ms = dev->ms_vid_cap;
+       if (dev->osd_mode <= 1) {
+               snprintf(str, sizeof(str), " %02d:%02d:%02d:%03d %u%s",
+                               (ms / (60 * 60 * 1000)) % 24,
+                               (ms / (60 * 1000)) % 60,
+                               (ms / 1000) % 60,
+                               ms % 1000,
+                               buf->vb.v4l2_buf.sequence,
+                               (dev->field_cap == V4L2_FIELD_ALTERNATE) ?
+                                       (buf->vb.v4l2_buf.field == V4L2_FIELD_TOP ?
+                                        " top" : " bottom") : "");
+               tpg_gen_text(&dev->tpg, basep, line++ * line_height, 16, str);
+       }
+       if (dev->osd_mode == 0) {
+               snprintf(str, sizeof(str), " %dx%d, input %d ",
+                               dev->src_rect.width, dev->src_rect.height, dev->input);
+               tpg_gen_text(&dev->tpg, basep, line++ * line_height, 16, str);
+
+               gain = v4l2_ctrl_g_ctrl(dev->gain);
+               mutex_lock(dev->ctrl_hdl_user_vid.lock);
+               snprintf(str, sizeof(str),
+                       " brightness %3d, contrast %3d, saturation %3d, hue %d ",
+                       dev->brightness->cur.val,
+                       dev->contrast->cur.val,
+                       dev->saturation->cur.val,
+                       dev->hue->cur.val);
+               tpg_gen_text(&dev->tpg, basep, line++ * line_height, 16, str);
+               snprintf(str, sizeof(str),
+                       " autogain %d, gain %3d, alpha 0x%02x ",
+                       dev->autogain->cur.val, gain, dev->alpha->cur.val);
+               mutex_unlock(dev->ctrl_hdl_user_vid.lock);
+               tpg_gen_text(&dev->tpg, basep, line++ * line_height, 16, str);
+               mutex_lock(dev->ctrl_hdl_user_aud.lock);
+               snprintf(str, sizeof(str),
+                       " volume %3d, mute %d ",
+                       dev->volume->cur.val, dev->mute->cur.val);
+               mutex_unlock(dev->ctrl_hdl_user_aud.lock);
+               tpg_gen_text(&dev->tpg, basep, line++ * line_height, 16, str);
+               mutex_lock(dev->ctrl_hdl_user_gen.lock);
+               snprintf(str, sizeof(str), " int32 %d, int64 %lld, bitmask %08x ",
+                       dev->int32->cur.val,
+                       *dev->int64->p_cur.p_s64,
+                       dev->bitmask->cur.val);
+               tpg_gen_text(&dev->tpg, basep, line++ * line_height, 16, str);
+               snprintf(str, sizeof(str), " boolean %d, menu %s, string \"%s\" ",
+                       dev->boolean->cur.val,
+                       dev->menu->qmenu[dev->menu->cur.val],
+                       dev->string->p_cur.p_char);
+               tpg_gen_text(&dev->tpg, basep, line++ * line_height, 16, str);
+               snprintf(str, sizeof(str), " integer_menu %lld, value %d ",
+                       dev->int_menu->qmenu_int[dev->int_menu->cur.val],
+                       dev->int_menu->cur.val);
+               mutex_unlock(dev->ctrl_hdl_user_gen.lock);
+               tpg_gen_text(&dev->tpg, basep, line++ * line_height, 16, str);
+               if (dev->button_pressed) {
+                       dev->button_pressed--;
+                       snprintf(str, sizeof(str), " button pressed!");
+                       tpg_gen_text(&dev->tpg, basep, line++ * line_height, 16, str);
+               }
+       }
+
+       /*
+        * If "End of Frame" is specified at the timestamp source, then take
+        * the timestamp now.
+        */
+       if (!dev->tstamp_src_is_soe)
+               v4l2_get_timestamp(&buf->vb.v4l2_buf.timestamp);
+       buf->vb.v4l2_buf.timestamp.tv_sec += dev->time_wrap_offset;
+}
+
+/*
+ * Return true if this pixel coordinate is a valid video pixel.
+ */
+static bool valid_pix(struct vivid_dev *dev, int win_y, int win_x, int fb_y, int fb_x)
+{
+       int i;
+
+       if (dev->bitmap_cap) {
+               /*
+                * Only if the corresponding bit in the bitmap is set can
+                * the video pixel be shown. Coordinates are relative to
+                * the overlay window set by VIDIOC_S_FMT.
+                */
+               const u8 *p = dev->bitmap_cap;
+               unsigned stride = (dev->compose_cap.width + 7) / 8;
+
+               if (!(p[stride * win_y + win_x / 8] & (1 << (win_x & 7))))
+                       return false;
+       }
+
+       for (i = 0; i < dev->clipcount_cap; i++) {
+               /*
+                * Only if the framebuffer coordinate is not in any of the
+                * clip rectangles will be video pixel be shown.
+                */
+               struct v4l2_rect *r = &dev->clips_cap[i].c;
+
+               if (fb_y >= r->top && fb_y < r->top + r->height &&
+                   fb_x >= r->left && fb_x < r->left + r->width)
+                       return false;
+       }
+       return true;
+}
+
+/*
+ * Draw the image into the overlay buffer.
+ * Note that the combination of overlay and multiplanar is not supported.
+ */
+static void vivid_overlay(struct vivid_dev *dev, struct vivid_buffer *buf)
+{
+       struct tpg_data *tpg = &dev->tpg;
+       unsigned pixsize = tpg_g_twopixelsize(tpg, 0) / 2;
+       void *vbase = dev->fb_vbase_cap;
+       void *vbuf = vb2_plane_vaddr(&buf->vb, 0);
+       unsigned img_width = dev->compose_cap.width;
+       unsigned img_height = dev->compose_cap.height;
+       unsigned stride = tpg->bytesperline[0];
+       /* if quick is true, then valid_pix() doesn't have to be called */
+       bool quick = dev->bitmap_cap == NULL && dev->clipcount_cap == 0;
+       int x, y, w, out_x = 0;
+
+       if ((dev->overlay_cap_field == V4L2_FIELD_TOP ||
+            dev->overlay_cap_field == V4L2_FIELD_BOTTOM) &&
+           dev->overlay_cap_field != buf->vb.v4l2_buf.field)
+               return;
+
+       vbuf += dev->compose_cap.left * pixsize + dev->compose_cap.top * stride;
+       x = dev->overlay_cap_left;
+       w = img_width;
+       if (x < 0) {
+               out_x = -x;
+               w = w - out_x;
+               x = 0;
+       } else {
+               w = dev->fb_cap.fmt.width - x;
+               if (w > img_width)
+                       w = img_width;
+       }
+       if (w <= 0)
+               return;
+       if (dev->overlay_cap_top >= 0)
+               vbase += dev->overlay_cap_top * dev->fb_cap.fmt.bytesperline;
+       for (y = dev->overlay_cap_top;
+            y < dev->overlay_cap_top + (int)img_height;
+            y++, vbuf += stride) {
+               int px;
+
+               if (y < 0 || y > dev->fb_cap.fmt.height)
+                       continue;
+               if (quick) {
+                       memcpy(vbase + x * pixsize,
+                              vbuf + out_x * pixsize, w * pixsize);
+                       vbase += dev->fb_cap.fmt.bytesperline;
+                       continue;
+               }
+               for (px = 0; px < w; px++) {
+                       if (!valid_pix(dev, y - dev->overlay_cap_top,
+                                      px + out_x, y, px + x))
+                               continue;
+                       memcpy(vbase + (px + x) * pixsize,
+                              vbuf + (px + out_x) * pixsize,
+                              pixsize);
+               }
+               vbase += dev->fb_cap.fmt.bytesperline;
+       }
+}
+
+static void vivid_thread_vid_cap_tick(struct vivid_dev *dev, int dropped_bufs)
+{
+       struct vivid_buffer *vid_cap_buf = NULL;
+       struct vivid_buffer *vbi_cap_buf = NULL;
+
+       dprintk(dev, 1, "Video Capture Thread Tick\n");
+
+       while (dropped_bufs-- > 1)
+               tpg_update_mv_count(&dev->tpg,
+                               dev->field_cap == V4L2_FIELD_NONE ||
+                               dev->field_cap == V4L2_FIELD_ALTERNATE);
+
+       /* Drop a certain percentage of buffers. */
+       if (dev->perc_dropped_buffers &&
+           prandom_u32_max(100) < dev->perc_dropped_buffers)
+               goto update_mv;
+
+       spin_lock(&dev->slock);
+       if (!list_empty(&dev->vid_cap_active)) {
+               vid_cap_buf = list_entry(dev->vid_cap_active.next, struct vivid_buffer, list);
+               list_del(&vid_cap_buf->list);
+       }
+       if (!list_empty(&dev->vbi_cap_active)) {
+               if (dev->field_cap != V4L2_FIELD_ALTERNATE ||
+                   (dev->vbi_cap_seq_count & 1)) {
+                       vbi_cap_buf = list_entry(dev->vbi_cap_active.next,
+                                                struct vivid_buffer, list);
+                       list_del(&vbi_cap_buf->list);
+               }
+       }
+       spin_unlock(&dev->slock);
+
+       if (!vid_cap_buf && !vbi_cap_buf)
+               goto update_mv;
+
+       if (vid_cap_buf) {
+               /* Fill buffer */
+               vivid_fillbuff(dev, vid_cap_buf);
+               dprintk(dev, 1, "filled buffer %d\n",
+                       vid_cap_buf->vb.v4l2_buf.index);
+
+               /* Handle overlay */
+               if (dev->overlay_cap_owner && dev->fb_cap.base &&
+                               dev->fb_cap.fmt.pixelformat == dev->fmt_cap->fourcc)
+                       vivid_overlay(dev, vid_cap_buf);
+
+               vb2_buffer_done(&vid_cap_buf->vb, dev->dqbuf_error ?
+                               VB2_BUF_STATE_ERROR : VB2_BUF_STATE_DONE);
+               dprintk(dev, 2, "vid_cap buffer %d done\n",
+                               vid_cap_buf->vb.v4l2_buf.index);
+       }
+
+       if (vbi_cap_buf) {
+               if (dev->stream_sliced_vbi_cap)
+                       vivid_sliced_vbi_cap_process(dev, vbi_cap_buf);
+               else
+                       vivid_raw_vbi_cap_process(dev, vbi_cap_buf);
+               vb2_buffer_done(&vbi_cap_buf->vb, dev->dqbuf_error ?
+                               VB2_BUF_STATE_ERROR : VB2_BUF_STATE_DONE);
+               dprintk(dev, 2, "vbi_cap %d done\n",
+                               vbi_cap_buf->vb.v4l2_buf.index);
+       }
+       dev->dqbuf_error = false;
+
+update_mv:
+       /* Update the test pattern movement counters */
+       tpg_update_mv_count(&dev->tpg, dev->field_cap == V4L2_FIELD_NONE ||
+                                      dev->field_cap == V4L2_FIELD_ALTERNATE);
+}
+
+static int vivid_thread_vid_cap(void *data)
+{
+       struct vivid_dev *dev = data;
+       u64 numerators_since_start;
+       u64 buffers_since_start;
+       u64 next_jiffies_since_start;
+       unsigned long jiffies_since_start;
+       unsigned long cur_jiffies;
+       unsigned wait_jiffies;
+       unsigned numerator;
+       unsigned denominator;
+       int dropped_bufs;
+
+       dprintk(dev, 1, "Video Capture Thread Start\n");
+
+       set_freezable();
+
+       /* Resets frame counters */
+       dev->cap_seq_offset = 0;
+       dev->cap_seq_count = 0;
+       dev->cap_seq_resync = false;
+       dev->jiffies_vid_cap = jiffies;
+
+       for (;;) {
+               try_to_freeze();
+               if (kthread_should_stop())
+                       break;
+
+               mutex_lock(&dev->mutex);
+               cur_jiffies = jiffies;
+               if (dev->cap_seq_resync) {
+                       dev->jiffies_vid_cap = cur_jiffies;
+                       dev->cap_seq_offset = dev->cap_seq_count + 1;
+                       dev->cap_seq_count = 0;
+                       dev->cap_seq_resync = false;
+               }
+               numerator = dev->timeperframe_vid_cap.numerator;
+               denominator = dev->timeperframe_vid_cap.denominator;
+
+               if (dev->field_cap == V4L2_FIELD_ALTERNATE)
+                       denominator *= 2;
+
+               /* Calculate the number of jiffies since we started streaming */
+               jiffies_since_start = cur_jiffies - dev->jiffies_vid_cap;
+               /* Get the number of buffers streamed since the start */
+               buffers_since_start = (u64)jiffies_since_start * denominator +
+                                     (HZ * numerator) / 2;
+               do_div(buffers_since_start, HZ * numerator);
+
+               /*
+                * After more than 0xf0000000 (rounded down to a multiple of
+                * 'jiffies-per-day' to ease jiffies_to_msecs calculation)
+                * jiffies have passed since we started streaming reset the
+                * counters and keep track of the sequence offset.
+                */
+               if (jiffies_since_start > JIFFIES_RESYNC) {
+                       dev->jiffies_vid_cap = cur_jiffies;
+                       dev->cap_seq_offset = buffers_since_start;
+                       buffers_since_start = 0;
+               }
+               dropped_bufs = buffers_since_start + dev->cap_seq_offset - dev->cap_seq_count;
+               dev->cap_seq_count = buffers_since_start + dev->cap_seq_offset;
+               dev->vid_cap_seq_count = dev->cap_seq_count - dev->vid_cap_seq_start;
+               dev->vbi_cap_seq_count = dev->cap_seq_count - dev->vbi_cap_seq_start;
+
+               vivid_thread_vid_cap_tick(dev, dropped_bufs);
+
+               /*
+                * Calculate the number of 'numerators' streamed since we started,
+                * including the current buffer.
+                */
+               numerators_since_start = ++buffers_since_start * numerator;
+
+               /* And the number of jiffies since we started */
+               jiffies_since_start = jiffies - dev->jiffies_vid_cap;
+
+               mutex_unlock(&dev->mutex);
+
+               /*
+                * Calculate when that next buffer is supposed to start
+                * in jiffies since we started streaming.
+                */
+               next_jiffies_since_start = numerators_since_start * HZ +
+                                          denominator / 2;
+               do_div(next_jiffies_since_start, denominator);
+               /* If it is in the past, then just schedule asap */
+               if (next_jiffies_since_start < jiffies_since_start)
+                       next_jiffies_since_start = jiffies_since_start;
+
+               wait_jiffies = next_jiffies_since_start - jiffies_since_start;
+               schedule_timeout_interruptible(wait_jiffies ? wait_jiffies : 1);
+       }
+       dprintk(dev, 1, "Video Capture Thread End\n");
+       return 0;
+}
+
+static void vivid_grab_controls(struct vivid_dev *dev, bool grab)
+{
+       v4l2_ctrl_grab(dev->ctrl_has_crop_cap, grab);
+       v4l2_ctrl_grab(dev->ctrl_has_compose_cap, grab);
+       v4l2_ctrl_grab(dev->ctrl_has_scaler_cap, grab);
+}
+
+int vivid_start_generating_vid_cap(struct vivid_dev *dev, bool *pstreaming)
+{
+       dprintk(dev, 1, "%s\n", __func__);
+
+       if (dev->kthread_vid_cap) {
+               u32 seq_count = dev->cap_seq_count + dev->seq_wrap * 128;
+
+               if (pstreaming == &dev->vid_cap_streaming)
+                       dev->vid_cap_seq_start = seq_count;
+               else
+                       dev->vbi_cap_seq_start = seq_count;
+               *pstreaming = true;
+               return 0;
+       }
+
+       /* Resets frame counters */
+       tpg_init_mv_count(&dev->tpg);
+
+       dev->vid_cap_seq_start = dev->seq_wrap * 128;
+       dev->vbi_cap_seq_start = dev->seq_wrap * 128;
+
+       dev->kthread_vid_cap = kthread_run(vivid_thread_vid_cap, dev,
+                       "%s-vid-cap", dev->v4l2_dev.name);
+
+       if (IS_ERR(dev->kthread_vid_cap)) {
+               v4l2_err(&dev->v4l2_dev, "kernel_thread() failed\n");
+               return PTR_ERR(dev->kthread_vid_cap);
+       }
+       *pstreaming = true;
+       vivid_grab_controls(dev, true);
+
+       dprintk(dev, 1, "returning from %s\n", __func__);
+       return 0;
+}
+
+void vivid_stop_generating_vid_cap(struct vivid_dev *dev, bool *pstreaming)
+{
+       dprintk(dev, 1, "%s\n", __func__);
+
+       if (dev->kthread_vid_cap == NULL)
+               return;
+
+       *pstreaming = false;
+       if (pstreaming == &dev->vid_cap_streaming) {
+               /* Release all active buffers */
+               while (!list_empty(&dev->vid_cap_active)) {
+                       struct vivid_buffer *buf;
+
+                       buf = list_entry(dev->vid_cap_active.next,
+                                        struct vivid_buffer, list);
+                       list_del(&buf->list);
+                       vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR);
+                       dprintk(dev, 2, "vid_cap buffer %d done\n",
+                               buf->vb.v4l2_buf.index);
+               }
+       }
+
+       if (pstreaming == &dev->vbi_cap_streaming) {
+               while (!list_empty(&dev->vbi_cap_active)) {
+                       struct vivid_buffer *buf;
+
+                       buf = list_entry(dev->vbi_cap_active.next,
+                                        struct vivid_buffer, list);
+                       list_del(&buf->list);
+                       vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR);
+                       dprintk(dev, 2, "vbi_cap buffer %d done\n",
+                               buf->vb.v4l2_buf.index);
+               }
+       }
+
+       if (dev->vid_cap_streaming || dev->vbi_cap_streaming)
+               return;
+
+       /* shutdown control thread */
+       vivid_grab_controls(dev, false);
+       mutex_unlock(&dev->mutex);
+       kthread_stop(dev->kthread_vid_cap);
+       dev->kthread_vid_cap = NULL;
+       mutex_lock(&dev->mutex);
+}
diff --git a/drivers/media/platform/vivid/vivid-kthread-cap.h b/drivers/media/platform/vivid/vivid-kthread-cap.h
new file mode 100644 (file)
index 0000000..5b92fc9
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * vivid-kthread-cap.h - video/vbi capture thread support functions.
+ *
+ * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
+ *
+ * This program is free software; you may redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * 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 _VIVID_KTHREAD_CAP_H_
+#define _VIVID_KTHREAD_CAP_H_
+
+int vivid_start_generating_vid_cap(struct vivid_dev *dev, bool *pstreaming);
+void vivid_stop_generating_vid_cap(struct vivid_dev *dev, bool *pstreaming);
+
+#endif
diff --git a/drivers/media/platform/vivid/vivid-kthread-out.c b/drivers/media/platform/vivid/vivid-kthread-out.c
new file mode 100644 (file)
index 0000000..d9f36cc
--- /dev/null
@@ -0,0 +1,305 @@
+/*
+ * vivid-kthread-out.h - video/vbi output thread support functions.
+ *
+ * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
+ *
+ * This program is free software; you may redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * 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/errno.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/font.h>
+#include <linux/mutex.h>
+#include <linux/videodev2.h>
+#include <linux/kthread.h>
+#include <linux/freezer.h>
+#include <linux/random.h>
+#include <linux/v4l2-dv-timings.h>
+#include <asm/div64.h>
+#include <media/videobuf2-vmalloc.h>
+#include <media/v4l2-dv-timings.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-fh.h>
+#include <media/v4l2-event.h>
+
+#include "vivid-core.h"
+#include "vivid-vid-common.h"
+#include "vivid-vid-cap.h"
+#include "vivid-vid-out.h"
+#include "vivid-radio-common.h"
+#include "vivid-radio-rx.h"
+#include "vivid-radio-tx.h"
+#include "vivid-sdr-cap.h"
+#include "vivid-vbi-cap.h"
+#include "vivid-vbi-out.h"
+#include "vivid-osd.h"
+#include "vivid-ctrls.h"
+#include "vivid-kthread-out.h"
+
+static void vivid_thread_vid_out_tick(struct vivid_dev *dev)
+{
+       struct vivid_buffer *vid_out_buf = NULL;
+       struct vivid_buffer *vbi_out_buf = NULL;
+
+       dprintk(dev, 1, "Video Output Thread Tick\n");
+
+       /* Drop a certain percentage of buffers. */
+       if (dev->perc_dropped_buffers &&
+           prandom_u32_max(100) < dev->perc_dropped_buffers)
+               return;
+
+       spin_lock(&dev->slock);
+       /*
+        * Only dequeue buffer if there is at least one more pending.
+        * This makes video loopback possible.
+        */
+       if (!list_empty(&dev->vid_out_active) &&
+           !list_is_singular(&dev->vid_out_active)) {
+               vid_out_buf = list_entry(dev->vid_out_active.next,
+                                        struct vivid_buffer, list);
+               list_del(&vid_out_buf->list);
+       }
+       if (!list_empty(&dev->vbi_out_active) &&
+           (dev->field_out != V4L2_FIELD_ALTERNATE ||
+            (dev->vbi_out_seq_count & 1))) {
+               vbi_out_buf = list_entry(dev->vbi_out_active.next,
+                                        struct vivid_buffer, list);
+               list_del(&vbi_out_buf->list);
+       }
+       spin_unlock(&dev->slock);
+
+       if (!vid_out_buf && !vbi_out_buf)
+               return;
+
+       if (vid_out_buf) {
+               vid_out_buf->vb.v4l2_buf.sequence = dev->vid_out_seq_count;
+               if (dev->field_out == V4L2_FIELD_ALTERNATE) {
+                       /*
+                        * The sequence counter counts frames, not fields. So divide
+                        * by two.
+                        */
+                       vid_out_buf->vb.v4l2_buf.sequence /= 2;
+               }
+               v4l2_get_timestamp(&vid_out_buf->vb.v4l2_buf.timestamp);
+               vid_out_buf->vb.v4l2_buf.timestamp.tv_sec += dev->time_wrap_offset;
+               vb2_buffer_done(&vid_out_buf->vb, dev->dqbuf_error ?
+                               VB2_BUF_STATE_ERROR : VB2_BUF_STATE_DONE);
+               dprintk(dev, 2, "vid_out buffer %d done\n",
+                       vid_out_buf->vb.v4l2_buf.index);
+       }
+
+       if (vbi_out_buf) {
+               if (dev->stream_sliced_vbi_out)
+                       vivid_sliced_vbi_out_process(dev, vbi_out_buf);
+
+               vbi_out_buf->vb.v4l2_buf.sequence = dev->vbi_out_seq_count;
+               v4l2_get_timestamp(&vbi_out_buf->vb.v4l2_buf.timestamp);
+               vbi_out_buf->vb.v4l2_buf.timestamp.tv_sec += dev->time_wrap_offset;
+               vb2_buffer_done(&vbi_out_buf->vb, dev->dqbuf_error ?
+                               VB2_BUF_STATE_ERROR : VB2_BUF_STATE_DONE);
+               dprintk(dev, 2, "vbi_out buffer %d done\n",
+                       vbi_out_buf->vb.v4l2_buf.index);
+       }
+       dev->dqbuf_error = false;
+}
+
+static int vivid_thread_vid_out(void *data)
+{
+       struct vivid_dev *dev = data;
+       u64 numerators_since_start;
+       u64 buffers_since_start;
+       u64 next_jiffies_since_start;
+       unsigned long jiffies_since_start;
+       unsigned long cur_jiffies;
+       unsigned wait_jiffies;
+       unsigned numerator;
+       unsigned denominator;
+
+       dprintk(dev, 1, "Video Output Thread Start\n");
+
+       set_freezable();
+
+       /* Resets frame counters */
+       dev->out_seq_offset = 0;
+       if (dev->seq_wrap)
+               dev->out_seq_count = 0xffffff80U;
+       dev->jiffies_vid_out = jiffies;
+       dev->vid_out_seq_start = dev->vbi_out_seq_start = 0;
+       dev->out_seq_resync = false;
+
+       for (;;) {
+               try_to_freeze();
+               if (kthread_should_stop())
+                       break;
+
+               mutex_lock(&dev->mutex);
+               cur_jiffies = jiffies;
+               if (dev->out_seq_resync) {
+                       dev->jiffies_vid_out = cur_jiffies;
+                       dev->out_seq_offset = dev->out_seq_count + 1;
+                       dev->out_seq_count = 0;
+                       dev->out_seq_resync = false;
+               }
+               numerator = dev->timeperframe_vid_out.numerator;
+               denominator = dev->timeperframe_vid_out.denominator;
+
+               if (dev->field_out == V4L2_FIELD_ALTERNATE)
+                       denominator *= 2;
+
+               /* Calculate the number of jiffies since we started streaming */
+               jiffies_since_start = cur_jiffies - dev->jiffies_vid_out;
+               /* Get the number of buffers streamed since the start */
+               buffers_since_start = (u64)jiffies_since_start * denominator +
+                                     (HZ * numerator) / 2;
+               do_div(buffers_since_start, HZ * numerator);
+
+               /*
+                * After more than 0xf0000000 (rounded down to a multiple of
+                * 'jiffies-per-day' to ease jiffies_to_msecs calculation)
+                * jiffies have passed since we started streaming reset the
+                * counters and keep track of the sequence offset.
+                */
+               if (jiffies_since_start > JIFFIES_RESYNC) {
+                       dev->jiffies_vid_out = cur_jiffies;
+                       dev->out_seq_offset = buffers_since_start;
+                       buffers_since_start = 0;
+               }
+               dev->out_seq_count = buffers_since_start + dev->out_seq_offset;
+               dev->vid_out_seq_count = dev->out_seq_count - dev->vid_out_seq_start;
+               dev->vbi_out_seq_count = dev->out_seq_count - dev->vbi_out_seq_start;
+
+               vivid_thread_vid_out_tick(dev);
+               mutex_unlock(&dev->mutex);
+
+               /*
+                * Calculate the number of 'numerators' streamed since we started,
+                * not including the current buffer.
+                */
+               numerators_since_start = buffers_since_start * numerator;
+
+               /* And the number of jiffies since we started */
+               jiffies_since_start = jiffies - dev->jiffies_vid_out;
+
+               /* Increase by the 'numerator' of one buffer */
+               numerators_since_start += numerator;
+               /*
+                * Calculate when that next buffer is supposed to start
+                * in jiffies since we started streaming.
+                */
+               next_jiffies_since_start = numerators_since_start * HZ +
+                                          denominator / 2;
+               do_div(next_jiffies_since_start, denominator);
+               /* If it is in the past, then just schedule asap */
+               if (next_jiffies_since_start < jiffies_since_start)
+                       next_jiffies_since_start = jiffies_since_start;
+
+               wait_jiffies = next_jiffies_since_start - jiffies_since_start;
+               schedule_timeout_interruptible(wait_jiffies ? wait_jiffies : 1);
+       }
+       dprintk(dev, 1, "Video Output Thread End\n");
+       return 0;
+}
+
+static void vivid_grab_controls(struct vivid_dev *dev, bool grab)
+{
+       v4l2_ctrl_grab(dev->ctrl_has_crop_out, grab);
+       v4l2_ctrl_grab(dev->ctrl_has_compose_out, grab);
+       v4l2_ctrl_grab(dev->ctrl_has_scaler_out, grab);
+       v4l2_ctrl_grab(dev->ctrl_tx_mode, grab);
+       v4l2_ctrl_grab(dev->ctrl_tx_rgb_range, grab);
+}
+
+int vivid_start_generating_vid_out(struct vivid_dev *dev, bool *pstreaming)
+{
+       dprintk(dev, 1, "%s\n", __func__);
+
+       if (dev->kthread_vid_out) {
+               u32 seq_count = dev->out_seq_count + dev->seq_wrap * 128;
+
+               if (pstreaming == &dev->vid_out_streaming)
+                       dev->vid_out_seq_start = seq_count;
+               else
+                       dev->vbi_out_seq_start = seq_count;
+               *pstreaming = true;
+               return 0;
+       }
+
+       /* Resets frame counters */
+       dev->jiffies_vid_out = jiffies;
+       dev->vid_out_seq_start = dev->seq_wrap * 128;
+       dev->vbi_out_seq_start = dev->seq_wrap * 128;
+
+       dev->kthread_vid_out = kthread_run(vivid_thread_vid_out, dev,
+                       "%s-vid-out", dev->v4l2_dev.name);
+
+       if (IS_ERR(dev->kthread_vid_out)) {
+               v4l2_err(&dev->v4l2_dev, "kernel_thread() failed\n");
+               return PTR_ERR(dev->kthread_vid_out);
+       }
+       *pstreaming = true;
+       vivid_grab_controls(dev, true);
+
+       dprintk(dev, 1, "returning from %s\n", __func__);
+       return 0;
+}
+
+void vivid_stop_generating_vid_out(struct vivid_dev *dev, bool *pstreaming)
+{
+       dprintk(dev, 1, "%s\n", __func__);
+
+       if (dev->kthread_vid_out == NULL)
+               return;
+
+       *pstreaming = false;
+       if (pstreaming == &dev->vid_out_streaming) {
+               /* Release all active buffers */
+               while (!list_empty(&dev->vid_out_active)) {
+                       struct vivid_buffer *buf;
+
+                       buf = list_entry(dev->vid_out_active.next,
+                                        struct vivid_buffer, list);
+                       list_del(&buf->list);
+                       vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR);
+                       dprintk(dev, 2, "vid_out buffer %d done\n",
+                               buf->vb.v4l2_buf.index);
+               }
+       }
+
+       if (pstreaming == &dev->vbi_out_streaming) {
+               while (!list_empty(&dev->vbi_out_active)) {
+                       struct vivid_buffer *buf;
+
+                       buf = list_entry(dev->vbi_out_active.next,
+                                        struct vivid_buffer, list);
+                       list_del(&buf->list);
+                       vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR);
+                       dprintk(dev, 2, "vbi_out buffer %d done\n",
+                               buf->vb.v4l2_buf.index);
+               }
+       }
+
+       if (dev->vid_out_streaming || dev->vbi_out_streaming)
+               return;
+
+       /* shutdown control thread */
+       vivid_grab_controls(dev, false);
+       mutex_unlock(&dev->mutex);
+       kthread_stop(dev->kthread_vid_out);
+       dev->kthread_vid_out = NULL;
+       mutex_lock(&dev->mutex);
+}
diff --git a/drivers/media/platform/vivid/vivid-kthread-out.h b/drivers/media/platform/vivid/vivid-kthread-out.h
new file mode 100644 (file)
index 0000000..2bf04a1
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * vivid-kthread-out.h - video/vbi output thread support functions.
+ *
+ * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
+ *
+ * This program is free software; you may redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * 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 _VIVID_KTHREAD_OUT_H_
+#define _VIVID_KTHREAD_OUT_H_
+
+int vivid_start_generating_vid_out(struct vivid_dev *dev, bool *pstreaming);
+void vivid_stop_generating_vid_out(struct vivid_dev *dev, bool *pstreaming);
+
+#endif
diff --git a/drivers/media/platform/vivid/vivid-osd.c b/drivers/media/platform/vivid/vivid-osd.c
new file mode 100644 (file)
index 0000000..084d346
--- /dev/null
@@ -0,0 +1,400 @@
+/*
+ * vivid-osd.c - osd support for testing overlays.
+ *
+ * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
+ *
+ * This program is free software; you may redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * 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/errno.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/font.h>
+#include <linux/mutex.h>
+#include <linux/videodev2.h>
+#include <linux/kthread.h>
+#include <linux/freezer.h>
+#include <linux/fb.h>
+#include <media/videobuf2-vmalloc.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-fh.h>
+#include <media/v4l2-event.h>
+#include <media/v4l2-common.h>
+
+#include "vivid-core.h"
+#include "vivid-osd.h"
+
+#define MAX_OSD_WIDTH  720
+#define MAX_OSD_HEIGHT 576
+
+/*
+ * Order: white, yellow, cyan, green, magenta, red, blue, black,
+ * and same again with the alpha bit set (if any)
+ */
+static const u16 rgb555[16] = {
+       0x7fff, 0x7fe0, 0x03ff, 0x03e0, 0x7c1f, 0x7c00, 0x001f, 0x0000,
+       0xffff, 0xffe0, 0x83ff, 0x83e0, 0xfc1f, 0xfc00, 0x801f, 0x8000
+};
+
+static const u16 rgb565[16] = {
+       0xffff, 0xffe0, 0x07ff, 0x07e0, 0xf81f, 0xf800, 0x001f, 0x0000,
+       0xffff, 0xffe0, 0x07ff, 0x07e0, 0xf81f, 0xf800, 0x001f, 0x0000
+};
+
+void vivid_clear_fb(struct vivid_dev *dev)
+{
+       void *p = dev->video_vbase;
+       const u16 *rgb = rgb555;
+       unsigned x, y;
+
+       if (dev->fb_defined.green.length == 6)
+               rgb = rgb565;
+
+       for (y = 0; y < dev->display_height; y++) {
+               u16 *d = p;
+
+               for (x = 0; x < dev->display_width; x++)
+                       d[x] = rgb[(y / 16 + x / 16) % 16];
+               p += dev->display_byte_stride;
+       }
+}
+
+/* --------------------------------------------------------------------- */
+
+static int vivid_fb_ioctl(struct fb_info *info, unsigned cmd, unsigned long arg)
+{
+       struct vivid_dev *dev = (struct vivid_dev *)info->par;
+
+       switch (cmd) {
+       case FBIOGET_VBLANK: {
+               struct fb_vblank vblank;
+
+               vblank.flags = FB_VBLANK_HAVE_COUNT | FB_VBLANK_HAVE_VCOUNT |
+                       FB_VBLANK_HAVE_VSYNC;
+               vblank.count = 0;
+               vblank.vcount = 0;
+               vblank.hcount = 0;
+               if (copy_to_user((void __user *)arg, &vblank, sizeof(vblank)))
+                       return -EFAULT;
+               return 0;
+       }
+
+       default:
+               dprintk(dev, 1, "Unknown ioctl %08x\n", cmd);
+               return -EINVAL;
+       }
+       return 0;
+}
+
+/* Framebuffer device handling */
+
+static int vivid_fb_set_var(struct vivid_dev *dev, struct fb_var_screeninfo *var)
+{
+       dprintk(dev, 1, "vivid_fb_set_var\n");
+
+       if (var->bits_per_pixel != 16) {
+               dprintk(dev, 1, "vivid_fb_set_var - Invalid bpp\n");
+               return -EINVAL;
+       }
+       dev->display_byte_stride = var->xres * dev->bytes_per_pixel;
+
+       return 0;
+}
+
+static int vivid_fb_get_fix(struct vivid_dev *dev, struct fb_fix_screeninfo *fix)
+{
+       dprintk(dev, 1, "vivid_fb_get_fix\n");
+       memset(fix, 0, sizeof(struct fb_fix_screeninfo));
+       strlcpy(fix->id, "vioverlay fb", sizeof(fix->id));
+       fix->smem_start = dev->video_pbase;
+       fix->smem_len = dev->video_buffer_size;
+       fix->type = FB_TYPE_PACKED_PIXELS;
+       fix->visual = FB_VISUAL_TRUECOLOR;
+       fix->xpanstep = 1;
+       fix->ypanstep = 1;
+       fix->ywrapstep = 0;
+       fix->line_length = dev->display_byte_stride;
+       fix->accel = FB_ACCEL_NONE;
+       return 0;
+}
+
+/* Check the requested display mode, returning -EINVAL if we can't
+   handle it. */
+
+static int _vivid_fb_check_var(struct fb_var_screeninfo *var, struct vivid_dev *dev)
+{
+       dprintk(dev, 1, "vivid_fb_check_var\n");
+
+       var->bits_per_pixel = 16;
+       if (var->green.length == 5) {
+               var->red.offset = 10;
+               var->red.length = 5;
+               var->green.offset = 5;
+               var->green.length = 5;
+               var->blue.offset = 0;
+               var->blue.length = 5;
+               var->transp.offset = 15;
+               var->transp.length = 1;
+       } else {
+               var->red.offset = 11;
+               var->red.length = 5;
+               var->green.offset = 5;
+               var->green.length = 6;
+               var->blue.offset = 0;
+               var->blue.length = 5;
+               var->transp.offset = 0;
+               var->transp.length = 0;
+       }
+       var->xoffset = var->yoffset = 0;
+       var->left_margin = var->upper_margin = 0;
+       var->nonstd = 0;
+
+       var->vmode &= ~FB_VMODE_MASK;
+       var->vmode = FB_VMODE_NONINTERLACED;
+
+       /* Dummy values */
+       var->hsync_len = 24;
+       var->vsync_len = 2;
+       var->pixclock = 84316;
+       var->right_margin = 776;
+       var->lower_margin = 591;
+       return 0;
+}
+
+static int vivid_fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
+{
+       struct vivid_dev *dev = (struct vivid_dev *) info->par;
+
+       dprintk(dev, 1, "vivid_fb_check_var\n");
+       return _vivid_fb_check_var(var, dev);
+}
+
+static int vivid_fb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info)
+{
+       return 0;
+}
+
+static int vivid_fb_set_par(struct fb_info *info)
+{
+       int rc = 0;
+       struct vivid_dev *dev = (struct vivid_dev *) info->par;
+
+       dprintk(dev, 1, "vivid_fb_set_par\n");
+
+       rc = vivid_fb_set_var(dev, &info->var);
+       vivid_fb_get_fix(dev, &info->fix);
+       return rc;
+}
+
+static int vivid_fb_setcolreg(unsigned regno, unsigned red, unsigned green,
+                               unsigned blue, unsigned transp,
+                               struct fb_info *info)
+{
+       u32 color, *palette;
+
+       if (regno >= info->cmap.len)
+               return -EINVAL;
+
+       color = ((transp & 0xFF00) << 16) | ((red & 0xFF00) << 8) |
+                (green & 0xFF00) | ((blue & 0xFF00) >> 8);
+       if (regno >= 16)
+               return -EINVAL;
+
+       palette = info->pseudo_palette;
+       if (info->var.bits_per_pixel == 16) {
+               switch (info->var.green.length) {
+               case 6:
+                       color = (red & 0xf800) |
+                               ((green & 0xfc00) >> 5) |
+                               ((blue & 0xf800) >> 11);
+                       break;
+               case 5:
+                       color = ((red & 0xf800) >> 1) |
+                               ((green & 0xf800) >> 6) |
+                               ((blue & 0xf800) >> 11) |
+                               (transp ? 0x8000 : 0);
+                       break;
+               }
+       }
+       palette[regno] = color;
+       return 0;
+}
+
+/* We don't really support blanking. All this does is enable or
+   disable the OSD. */
+static int vivid_fb_blank(int blank_mode, struct fb_info *info)
+{
+       struct vivid_dev *dev = (struct vivid_dev *)info->par;
+
+       dprintk(dev, 1, "Set blanking mode : %d\n", blank_mode);
+       switch (blank_mode) {
+       case FB_BLANK_UNBLANK:
+               break;
+       case FB_BLANK_NORMAL:
+       case FB_BLANK_HSYNC_SUSPEND:
+       case FB_BLANK_VSYNC_SUSPEND:
+       case FB_BLANK_POWERDOWN:
+               break;
+       }
+       return 0;
+}
+
+static struct fb_ops vivid_fb_ops = {
+       .owner = THIS_MODULE,
+       .fb_check_var   = vivid_fb_check_var,
+       .fb_set_par     = vivid_fb_set_par,
+       .fb_setcolreg   = vivid_fb_setcolreg,
+       .fb_fillrect    = cfb_fillrect,
+       .fb_copyarea    = cfb_copyarea,
+       .fb_imageblit   = cfb_imageblit,
+       .fb_cursor      = NULL,
+       .fb_ioctl       = vivid_fb_ioctl,
+       .fb_pan_display = vivid_fb_pan_display,
+       .fb_blank       = vivid_fb_blank,
+};
+
+/* Initialization */
+
+
+/* Setup our initial video mode */
+static int vivid_fb_init_vidmode(struct vivid_dev *dev)
+{
+       struct v4l2_rect start_window;
+
+       /* Color mode */
+
+       dev->bits_per_pixel = 16;
+       dev->bytes_per_pixel = dev->bits_per_pixel / 8;
+
+       start_window.width = MAX_OSD_WIDTH;
+       start_window.left = 0;
+
+       dev->display_byte_stride = start_window.width * dev->bytes_per_pixel;
+
+       /* Vertical size & position */
+
+       start_window.height = MAX_OSD_HEIGHT;
+       start_window.top = 0;
+
+       dev->display_width = start_window.width;
+       dev->display_height = start_window.height;
+
+       /* Generate a valid fb_var_screeninfo */
+
+       dev->fb_defined.xres = dev->display_width;
+       dev->fb_defined.yres = dev->display_height;
+       dev->fb_defined.xres_virtual = dev->display_width;
+       dev->fb_defined.yres_virtual = dev->display_height;
+       dev->fb_defined.bits_per_pixel = dev->bits_per_pixel;
+       dev->fb_defined.vmode = FB_VMODE_NONINTERLACED;
+       dev->fb_defined.left_margin = start_window.left + 1;
+       dev->fb_defined.upper_margin = start_window.top + 1;
+       dev->fb_defined.accel_flags = FB_ACCEL_NONE;
+       dev->fb_defined.nonstd = 0;
+       /* set default to 1:5:5:5 */
+       dev->fb_defined.green.length = 5;
+
+       /* We've filled in the most data, let the usual mode check
+          routine fill in the rest. */
+       _vivid_fb_check_var(&dev->fb_defined, dev);
+
+       /* Generate valid fb_fix_screeninfo */
+
+       vivid_fb_get_fix(dev, &dev->fb_fix);
+
+       /* Generate valid fb_info */
+
+       dev->fb_info.node = -1;
+       dev->fb_info.flags = FBINFO_FLAG_DEFAULT;
+       dev->fb_info.fbops = &vivid_fb_ops;
+       dev->fb_info.par = dev;
+       dev->fb_info.var = dev->fb_defined;
+       dev->fb_info.fix = dev->fb_fix;
+       dev->fb_info.screen_base = (u8 __iomem *)dev->video_vbase;
+       dev->fb_info.fbops = &vivid_fb_ops;
+
+       /* Supply some monitor specs. Bogus values will do for now */
+       dev->fb_info.monspecs.hfmin = 8000;
+       dev->fb_info.monspecs.hfmax = 70000;
+       dev->fb_info.monspecs.vfmin = 10;
+       dev->fb_info.monspecs.vfmax = 100;
+
+       /* Allocate color map */
+       if (fb_alloc_cmap(&dev->fb_info.cmap, 256, 1)) {
+               pr_err("abort, unable to alloc cmap\n");
+               return -ENOMEM;
+       }
+
+       /* Allocate the pseudo palette */
+       dev->fb_info.pseudo_palette = kmalloc_array(16, sizeof(u32), GFP_KERNEL);
+
+       return dev->fb_info.pseudo_palette ? 0 : -ENOMEM;
+}
+
+/* Release any memory we've grabbed */
+void vivid_fb_release_buffers(struct vivid_dev *dev)
+{
+       if (dev->video_vbase == NULL)
+               return;
+
+       /* Release cmap */
+       if (dev->fb_info.cmap.len)
+               fb_dealloc_cmap(&dev->fb_info.cmap);
+
+       /* Release pseudo palette */
+       kfree(dev->fb_info.pseudo_palette);
+       kfree((void *)dev->video_vbase);
+}
+
+/* Initialize the specified card */
+
+int vivid_fb_init(struct vivid_dev *dev)
+{
+       int ret;
+
+       dev->video_buffer_size = MAX_OSD_HEIGHT * MAX_OSD_WIDTH * 2;
+       dev->video_vbase = kzalloc(dev->video_buffer_size, GFP_KERNEL | GFP_DMA32);
+       if (dev->video_vbase == NULL)
+               return -ENOMEM;
+       dev->video_pbase = virt_to_phys(dev->video_vbase);
+
+       pr_info("Framebuffer at 0x%lx, mapped to 0x%p, size %dk\n",
+                       dev->video_pbase, dev->video_vbase,
+                       dev->video_buffer_size / 1024);
+
+       /* Set the startup video mode information */
+       ret = vivid_fb_init_vidmode(dev);
+       if (ret) {
+               vivid_fb_release_buffers(dev);
+               return ret;
+       }
+
+       vivid_clear_fb(dev);
+
+       /* Register the framebuffer */
+       if (register_framebuffer(&dev->fb_info) < 0) {
+               vivid_fb_release_buffers(dev);
+               return -EINVAL;
+       }
+
+       /* Set the card to the requested mode */
+       vivid_fb_set_par(&dev->fb_info);
+       return 0;
+
+}
diff --git a/drivers/media/platform/vivid/vivid-osd.h b/drivers/media/platform/vivid/vivid-osd.h
new file mode 100644 (file)
index 0000000..57c9daa
--- /dev/null
@@ -0,0 +1,27 @@
+/*
+ * vivid-osd.h - output overlay support functions.
+ *
+ * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
+ *
+ * This program is free software; you may redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * 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 _VIVID_OSD_H_
+#define _VIVID_OSD_H_
+
+int vivid_fb_init(struct vivid_dev *dev);
+void vivid_fb_release_buffers(struct vivid_dev *dev);
+void vivid_clear_fb(struct vivid_dev *dev);
+
+#endif
diff --git a/drivers/media/platform/vivid/vivid-radio-common.c b/drivers/media/platform/vivid/vivid-radio-common.c
new file mode 100644 (file)
index 0000000..78c1e92
--- /dev/null
@@ -0,0 +1,189 @@
+/*
+ * vivid-radio-common.c - common radio rx/tx support functions.
+ *
+ * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
+ *
+ * This program is free software; you may redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/videodev2.h>
+
+#include "vivid-core.h"
+#include "vivid-ctrls.h"
+#include "vivid-radio-common.h"
+#include "vivid-rds-gen.h"
+
+/*
+ * These functions are shared between the vivid receiver and transmitter
+ * since both use the same frequency bands.
+ */
+
+const struct v4l2_frequency_band vivid_radio_bands[TOT_BANDS] = {
+       /* Band FM */
+       {
+               .type = V4L2_TUNER_RADIO,
+               .index = 0,
+               .capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO |
+                             V4L2_TUNER_CAP_FREQ_BANDS,
+               .rangelow   = FM_FREQ_RANGE_LOW,
+               .rangehigh  = FM_FREQ_RANGE_HIGH,
+               .modulation = V4L2_BAND_MODULATION_FM,
+       },
+       /* Band AM */
+       {
+               .type = V4L2_TUNER_RADIO,
+               .index = 1,
+               .capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_FREQ_BANDS,
+               .rangelow   = AM_FREQ_RANGE_LOW,
+               .rangehigh  = AM_FREQ_RANGE_HIGH,
+               .modulation = V4L2_BAND_MODULATION_AM,
+       },
+       /* Band SW */
+       {
+               .type = V4L2_TUNER_RADIO,
+               .index = 2,
+               .capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_FREQ_BANDS,
+               .rangelow   = SW_FREQ_RANGE_LOW,
+               .rangehigh  = SW_FREQ_RANGE_HIGH,
+               .modulation = V4L2_BAND_MODULATION_AM,
+       },
+};
+
+/*
+ * Initialize the RDS generator. If we can loop, then the RDS generator
+ * is set up with the values from the RDS TX controls, otherwise it
+ * will fill in standard values using one of two alternates.
+ */
+void vivid_radio_rds_init(struct vivid_dev *dev)
+{
+       struct vivid_rds_gen *rds = &dev->rds_gen;
+       bool alt = dev->radio_rx_rds_use_alternates;
+
+       /* Do nothing, blocks will be filled by the transmitter */
+       if (dev->radio_rds_loop && !dev->radio_tx_rds_controls)
+               return;
+
+       if (dev->radio_rds_loop) {
+               v4l2_ctrl_lock(dev->radio_tx_rds_pi);
+               rds->picode = dev->radio_tx_rds_pi->cur.val;
+               rds->pty = dev->radio_tx_rds_pty->cur.val;
+               rds->mono_stereo = dev->radio_tx_rds_mono_stereo->cur.val;
+               rds->art_head = dev->radio_tx_rds_art_head->cur.val;
+               rds->compressed = dev->radio_tx_rds_compressed->cur.val;
+               rds->dyn_pty = dev->radio_tx_rds_dyn_pty->cur.val;
+               rds->ta = dev->radio_tx_rds_ta->cur.val;
+               rds->tp = dev->radio_tx_rds_tp->cur.val;
+               rds->ms = dev->radio_tx_rds_ms->cur.val;
+               strlcpy(rds->psname,
+                       dev->radio_tx_rds_psname->p_cur.p_char,
+                       sizeof(rds->psname));
+               strlcpy(rds->radiotext,
+                       dev->radio_tx_rds_radiotext->p_cur.p_char + alt * 64,
+                       sizeof(rds->radiotext));
+               v4l2_ctrl_unlock(dev->radio_tx_rds_pi);
+       } else {
+               vivid_rds_gen_fill(rds, dev->radio_rx_freq, alt);
+       }
+       if (dev->radio_rx_rds_controls) {
+               v4l2_ctrl_s_ctrl(dev->radio_rx_rds_pty, rds->pty);
+               v4l2_ctrl_s_ctrl(dev->radio_rx_rds_ta, rds->ta);
+               v4l2_ctrl_s_ctrl(dev->radio_rx_rds_tp, rds->tp);
+               v4l2_ctrl_s_ctrl(dev->radio_rx_rds_ms, rds->ms);
+               v4l2_ctrl_s_ctrl_string(dev->radio_rx_rds_psname, rds->psname);
+               v4l2_ctrl_s_ctrl_string(dev->radio_rx_rds_radiotext, rds->radiotext);
+               if (!dev->radio_rds_loop)
+                       dev->radio_rx_rds_use_alternates = !dev->radio_rx_rds_use_alternates;
+       }
+       vivid_rds_generate(rds);
+}
+
+/*
+ * Calculate the emulated signal quality taking into account the frequency
+ * the transmitter is using.
+ */
+static void vivid_radio_calc_sig_qual(struct vivid_dev *dev)
+{
+       int mod = 16000;
+       int delta = 800;
+       int sig_qual, sig_qual_tx = mod;
+
+       /*
+        * For SW and FM there is a channel every 1000 kHz, for AM there is one
+        * every 100 kHz.
+        */
+       if (dev->radio_rx_freq <= AM_FREQ_RANGE_HIGH) {
+               mod /= 10;
+               delta /= 10;
+       }
+       sig_qual = (dev->radio_rx_freq + delta) % mod - delta;
+       if (dev->has_radio_tx)
+               sig_qual_tx = dev->radio_rx_freq - dev->radio_tx_freq;
+       if (abs(sig_qual_tx) <= abs(sig_qual)) {
+               sig_qual = sig_qual_tx;
+               /*
+                * Zero the internal rds buffer if we are going to loop
+                * rds blocks.
+                */
+               if (!dev->radio_rds_loop && !dev->radio_tx_rds_controls)
+                       memset(dev->rds_gen.data, 0,
+                              sizeof(dev->rds_gen.data));
+               dev->radio_rds_loop = dev->radio_rx_freq >= FM_FREQ_RANGE_LOW;
+       } else {
+               dev->radio_rds_loop = false;
+       }
+       if (dev->radio_rx_freq <= AM_FREQ_RANGE_HIGH)
+               sig_qual *= 10;
+       dev->radio_rx_sig_qual = sig_qual;
+}
+
+int vivid_radio_g_frequency(struct file *file, const unsigned *pfreq, struct v4l2_frequency *vf)
+{
+       if (vf->tuner != 0)
+               return -EINVAL;
+       vf->frequency = *pfreq;
+       return 0;
+}
+
+int vivid_radio_s_frequency(struct file *file, unsigned *pfreq, const struct v4l2_frequency *vf)
+{
+       struct vivid_dev *dev = video_drvdata(file);
+       unsigned freq;
+       unsigned band;
+
+       if (vf->tuner != 0)
+               return -EINVAL;
+
+       if (vf->frequency >= (FM_FREQ_RANGE_LOW + SW_FREQ_RANGE_HIGH) / 2)
+               band = BAND_FM;
+       else if (vf->frequency <= (AM_FREQ_RANGE_HIGH + SW_FREQ_RANGE_LOW) / 2)
+               band = BAND_AM;
+       else
+               band = BAND_SW;
+
+       freq = clamp_t(u32, vf->frequency, vivid_radio_bands[band].rangelow,
+                                          vivid_radio_bands[band].rangehigh);
+       *pfreq = freq;
+
+       /*
+        * For both receiver and transmitter recalculate the signal quality
+        * (since that depends on both frequencies) and re-init the rds
+        * generator.
+        */
+       vivid_radio_calc_sig_qual(dev);
+       vivid_radio_rds_init(dev);
+       return 0;
+}
diff --git a/drivers/media/platform/vivid/vivid-radio-common.h b/drivers/media/platform/vivid/vivid-radio-common.h
new file mode 100644 (file)
index 0000000..92fe589
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * vivid-radio-common.h - common radio rx/tx support functions.
+ *
+ * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
+ *
+ * This program is free software; you may redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * 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 _VIVID_RADIO_COMMON_H_
+#define _VIVID_RADIO_COMMON_H_
+
+/* The supported radio frequency ranges in kHz */
+#define FM_FREQ_RANGE_LOW       (64000U * 16U)
+#define FM_FREQ_RANGE_HIGH      (108000U * 16U)
+#define AM_FREQ_RANGE_LOW       (520U * 16U)
+#define AM_FREQ_RANGE_HIGH      (1710U * 16U)
+#define SW_FREQ_RANGE_LOW       (2300U * 16U)
+#define SW_FREQ_RANGE_HIGH      (26100U * 16U)
+
+enum { BAND_FM, BAND_AM, BAND_SW, TOT_BANDS };
+
+extern const struct v4l2_frequency_band vivid_radio_bands[TOT_BANDS];
+
+int vivid_radio_g_frequency(struct file *file, const unsigned *freq, struct v4l2_frequency *vf);
+int vivid_radio_s_frequency(struct file *file, unsigned *freq, const struct v4l2_frequency *vf);
+
+void vivid_radio_rds_init(struct vivid_dev *dev);
+
+#endif
diff --git a/drivers/media/platform/vivid/vivid-radio-rx.c b/drivers/media/platform/vivid/vivid-radio-rx.c
new file mode 100644 (file)
index 0000000..c7651a5
--- /dev/null
@@ -0,0 +1,287 @@
+/*
+ * vivid-radio-rx.c - radio receiver support functions.
+ *
+ * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
+ *
+ * This program is free software; you may redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/videodev2.h>
+#include <linux/v4l2-dv-timings.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-event.h>
+#include <media/v4l2-dv-timings.h>
+
+#include "vivid-core.h"
+#include "vivid-ctrls.h"
+#include "vivid-radio-common.h"
+#include "vivid-rds-gen.h"
+#include "vivid-radio-rx.h"
+
+ssize_t vivid_radio_rx_read(struct file *file, char __user *buf,
+                        size_t size, loff_t *offset)
+{
+       struct vivid_dev *dev = video_drvdata(file);
+       struct timespec ts;
+       struct v4l2_rds_data *data = dev->rds_gen.data;
+       bool use_alternates;
+       unsigned blk;
+       int perc;
+       int i;
+
+       if (dev->radio_rx_rds_controls)
+               return -EINVAL;
+       if (size < sizeof(*data))
+               return 0;
+       size = sizeof(*data) * (size / sizeof(*data));
+
+       if (mutex_lock_interruptible(&dev->mutex))
+               return -ERESTARTSYS;
+       if (dev->radio_rx_rds_owner &&
+           file->private_data != dev->radio_rx_rds_owner) {
+               mutex_unlock(&dev->mutex);
+               return -EBUSY;
+       }
+       if (dev->radio_rx_rds_owner == NULL) {
+               vivid_radio_rds_init(dev);
+               dev->radio_rx_rds_owner = file->private_data;
+       }
+
+retry:
+       ktime_get_ts(&ts);
+       use_alternates = ts.tv_sec % 10 >= 5;
+       if (dev->radio_rx_rds_last_block == 0 ||
+           dev->radio_rx_rds_use_alternates != use_alternates) {
+               dev->radio_rx_rds_use_alternates = use_alternates;
+               /* Re-init the RDS generator */
+               vivid_radio_rds_init(dev);
+       }
+       ts = timespec_sub(ts, dev->radio_rds_init_ts);
+       blk = ts.tv_sec * 100 + ts.tv_nsec / 10000000;
+       blk = (blk * VIVID_RDS_GEN_BLOCKS) / 500;
+       if (blk >= dev->radio_rx_rds_last_block + VIVID_RDS_GEN_BLOCKS)
+               dev->radio_rx_rds_last_block = blk - VIVID_RDS_GEN_BLOCKS + 1;
+
+       /*
+        * No data is available if there hasn't been time to get new data,
+        * or if the RDS receiver has been disabled, or if we use the data
+        * from the RDS transmitter and that RDS transmitter has been disabled,
+        * or if the signal quality is too weak.
+        */
+       if (blk == dev->radio_rx_rds_last_block || !dev->radio_rx_rds_enabled ||
+           (dev->radio_rds_loop && !(dev->radio_tx_subchans & V4L2_TUNER_SUB_RDS)) ||
+           abs(dev->radio_rx_sig_qual) > 200) {
+               mutex_unlock(&dev->mutex);
+               if (file->f_flags & O_NONBLOCK)
+                       return -EWOULDBLOCK;
+               if (msleep_interruptible(20) && signal_pending(current))
+                       return -EINTR;
+               if (mutex_lock_interruptible(&dev->mutex))
+                       return -ERESTARTSYS;
+               goto retry;
+       }
+
+       /* abs(dev->radio_rx_sig_qual) <= 200, map that to a 0-50% range */
+       perc = abs(dev->radio_rx_sig_qual) / 4;
+
+       for (i = 0; i < size && blk > dev->radio_rx_rds_last_block;
+                       dev->radio_rx_rds_last_block++) {
+               unsigned data_blk = dev->radio_rx_rds_last_block % VIVID_RDS_GEN_BLOCKS;
+               struct v4l2_rds_data rds = data[data_blk];
+
+               if (data_blk == 0 && dev->radio_rds_loop)
+                       vivid_radio_rds_init(dev);
+               if (perc && prandom_u32_max(100) < perc) {
+                       switch (prandom_u32_max(4)) {
+                       case 0:
+                               rds.block |= V4L2_RDS_BLOCK_CORRECTED;
+                               break;
+                       case 1:
+                               rds.block |= V4L2_RDS_BLOCK_INVALID;
+                               break;
+                       case 2:
+                               rds.block |= V4L2_RDS_BLOCK_ERROR;
+                               rds.lsb = prandom_u32_max(256);
+                               rds.msb = prandom_u32_max(256);
+                               break;
+                       case 3: /* Skip block altogether */
+                               if (i)
+                                       continue;
+                               /*
+                                * Must make sure at least one block is
+                                * returned, otherwise the application
+                                * might think that end-of-file occurred.
+                                */
+                               break;
+                       }
+               }
+               if (copy_to_user(buf + i, &rds, sizeof(rds))) {
+                       i = -EFAULT;
+                       break;
+               }
+               i += sizeof(rds);
+       }
+       mutex_unlock(&dev->mutex);
+       return i;
+}
+
+unsigned int vivid_radio_rx_poll(struct file *file, struct poll_table_struct *wait)
+{
+       return POLLIN | POLLRDNORM | v4l2_ctrl_poll(file, wait);
+}
+
+int vivid_radio_rx_enum_freq_bands(struct file *file, void *fh, struct v4l2_frequency_band *band)
+{
+       if (band->tuner != 0)
+               return -EINVAL;
+
+       if (band->index >= TOT_BANDS)
+               return -EINVAL;
+
+       *band = vivid_radio_bands[band->index];
+       return 0;
+}
+
+int vivid_radio_rx_s_hw_freq_seek(struct file *file, void *fh, const struct v4l2_hw_freq_seek *a)
+{
+       struct vivid_dev *dev = video_drvdata(file);
+       unsigned low, high;
+       unsigned freq;
+       unsigned spacing;
+       unsigned band;
+
+       if (a->tuner)
+               return -EINVAL;
+       if (a->wrap_around && dev->radio_rx_hw_seek_mode == VIVID_HW_SEEK_BOUNDED)
+               return -EINVAL;
+
+       if (!a->wrap_around && dev->radio_rx_hw_seek_mode == VIVID_HW_SEEK_WRAP)
+               return -EINVAL;
+       if (!a->rangelow ^ !a->rangehigh)
+               return -EINVAL;
+
+       if (file->f_flags & O_NONBLOCK)
+               return -EWOULDBLOCK;
+
+       if (a->rangelow) {
+               for (band = 0; band < TOT_BANDS; band++)
+                       if (a->rangelow >= vivid_radio_bands[band].rangelow &&
+                           a->rangehigh <= vivid_radio_bands[band].rangehigh)
+                               break;
+               if (band == TOT_BANDS)
+                       return -EINVAL;
+               if (!dev->radio_rx_hw_seek_prog_lim &&
+                   (a->rangelow != vivid_radio_bands[band].rangelow ||
+                    a->rangehigh != vivid_radio_bands[band].rangehigh))
+                       return -EINVAL;
+               low = a->rangelow;
+               high = a->rangehigh;
+       } else {
+               for (band = 0; band < TOT_BANDS; band++)
+                       if (dev->radio_rx_freq >= vivid_radio_bands[band].rangelow &&
+                           dev->radio_rx_freq <= vivid_radio_bands[band].rangehigh)
+                               break;
+               low = vivid_radio_bands[band].rangelow;
+               high = vivid_radio_bands[band].rangehigh;
+       }
+       spacing = band == BAND_AM ? 1600 : 16000;
+       freq = clamp(dev->radio_rx_freq, low, high);
+
+       if (a->seek_upward) {
+               freq = spacing * (freq / spacing) + spacing;
+               if (freq > high) {
+                       if (!a->wrap_around)
+                               return -ENODATA;
+                       freq = spacing * (low / spacing) + spacing;
+                       if (freq >= dev->radio_rx_freq)
+                               return -ENODATA;
+               }
+       } else {
+               freq = spacing * ((freq + spacing - 1) / spacing) - spacing;
+               if (freq < low) {
+                       if (!a->wrap_around)
+                               return -ENODATA;
+                       freq = spacing * ((high + spacing - 1) / spacing) - spacing;
+                       if (freq <= dev->radio_rx_freq)
+                               return -ENODATA;
+               }
+       }
+       return 0;
+}
+
+int vivid_radio_rx_g_tuner(struct file *file, void *fh, struct v4l2_tuner *vt)
+{
+       struct vivid_dev *dev = video_drvdata(file);
+       int delta = 800;
+       int sig_qual;
+
+       if (vt->index > 0)
+               return -EINVAL;
+
+       strlcpy(vt->name, "AM/FM/SW Receiver", sizeof(vt->name));
+       vt->capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO |
+                        V4L2_TUNER_CAP_FREQ_BANDS | V4L2_TUNER_CAP_RDS |
+                        (dev->radio_rx_rds_controls ?
+                               V4L2_TUNER_CAP_RDS_CONTROLS :
+                               V4L2_TUNER_CAP_RDS_BLOCK_IO) |
+                        (dev->radio_rx_hw_seek_prog_lim ?
+                               V4L2_TUNER_CAP_HWSEEK_PROG_LIM : 0);
+       switch (dev->radio_rx_hw_seek_mode) {
+       case VIVID_HW_SEEK_BOUNDED:
+               vt->capability |= V4L2_TUNER_CAP_HWSEEK_BOUNDED;
+               break;
+       case VIVID_HW_SEEK_WRAP:
+               vt->capability |= V4L2_TUNER_CAP_HWSEEK_WRAP;
+               break;
+       case VIVID_HW_SEEK_BOTH:
+               vt->capability |= V4L2_TUNER_CAP_HWSEEK_WRAP |
+                                 V4L2_TUNER_CAP_HWSEEK_BOUNDED;
+               break;
+       }
+       vt->rangelow = AM_FREQ_RANGE_LOW;
+       vt->rangehigh = FM_FREQ_RANGE_HIGH;
+       sig_qual = dev->radio_rx_sig_qual;
+       vt->signal = abs(sig_qual) > delta ? 0 :
+                    0xffff - (abs(sig_qual) * 0xffff) / delta;
+       vt->afc = sig_qual > delta ? 0 : sig_qual;
+       if (abs(sig_qual) > delta)
+               vt->rxsubchans = 0;
+       else if (dev->radio_rx_freq < FM_FREQ_RANGE_LOW || vt->signal < 0x8000)
+               vt->rxsubchans = V4L2_TUNER_SUB_MONO;
+       else if (dev->radio_rds_loop && !(dev->radio_tx_subchans & V4L2_TUNER_SUB_STEREO))
+               vt->rxsubchans = V4L2_TUNER_SUB_MONO;
+       else
+               vt->rxsubchans = V4L2_TUNER_SUB_STEREO;
+       if (dev->radio_rx_rds_enabled &&
+           (!dev->radio_rds_loop || (dev->radio_tx_subchans & V4L2_TUNER_SUB_RDS)) &&
+           dev->radio_rx_freq >= FM_FREQ_RANGE_LOW && vt->signal >= 0xc000)
+               vt->rxsubchans |= V4L2_TUNER_SUB_RDS;
+       if (dev->radio_rx_rds_controls)
+               vivid_radio_rds_init(dev);
+       vt->audmode = dev->radio_rx_audmode;
+       return 0;
+}
+
+int vivid_radio_rx_s_tuner(struct file *file, void *fh, const struct v4l2_tuner *vt)
+{
+       struct vivid_dev *dev = video_drvdata(file);
+
+       if (vt->index)
+               return -EINVAL;
+       dev->radio_rx_audmode = vt->audmode >= V4L2_TUNER_MODE_STEREO;
+       return 0;
+}
diff --git a/drivers/media/platform/vivid/vivid-radio-rx.h b/drivers/media/platform/vivid/vivid-radio-rx.h
new file mode 100644 (file)
index 0000000..1077d8f
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * vivid-radio-rx.h - radio receiver support functions.
+ *
+ * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
+ *
+ * This program is free software; you may redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * 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 _VIVID_RADIO_RX_H_
+#define _VIVID_RADIO_RX_H_
+
+ssize_t vivid_radio_rx_read(struct file *, char __user *, size_t, loff_t *);
+unsigned int vivid_radio_rx_poll(struct file *file, struct poll_table_struct *wait);
+
+int vivid_radio_rx_enum_freq_bands(struct file *file, void *fh, struct v4l2_frequency_band *band);
+int vivid_radio_rx_s_hw_freq_seek(struct file *file, void *fh, const struct v4l2_hw_freq_seek *a);
+int vivid_radio_rx_g_tuner(struct file *file, void *fh, struct v4l2_tuner *vt);
+int vivid_radio_rx_s_tuner(struct file *file, void *fh, const struct v4l2_tuner *vt);
+
+#endif
diff --git a/drivers/media/platform/vivid/vivid-radio-tx.c b/drivers/media/platform/vivid/vivid-radio-tx.c
new file mode 100644 (file)
index 0000000..8c59d4f
--- /dev/null
@@ -0,0 +1,141 @@
+/*
+ * vivid-radio-tx.c - radio transmitter support functions.
+ *
+ * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
+ *
+ * This program is free software; you may redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/videodev2.h>
+#include <linux/v4l2-dv-timings.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-event.h>
+#include <media/v4l2-dv-timings.h>
+
+#include "vivid-core.h"
+#include "vivid-ctrls.h"
+#include "vivid-radio-common.h"
+#include "vivid-radio-tx.h"
+
+ssize_t vivid_radio_tx_write(struct file *file, const char __user *buf,
+                         size_t size, loff_t *offset)
+{
+       struct vivid_dev *dev = video_drvdata(file);
+       struct v4l2_rds_data *data = dev->rds_gen.data;
+       struct timespec ts;
+       unsigned blk;
+       int i;
+
+       if (dev->radio_tx_rds_controls)
+               return -EINVAL;
+
+       if (size < sizeof(*data))
+               return -EINVAL;
+       size = sizeof(*data) * (size / sizeof(*data));
+
+       if (mutex_lock_interruptible(&dev->mutex))
+               return -ERESTARTSYS;
+       if (dev->radio_tx_rds_owner &&
+           file->private_data != dev->radio_tx_rds_owner) {
+               mutex_unlock(&dev->mutex);
+               return -EBUSY;
+       }
+       dev->radio_tx_rds_owner = file->private_data;
+
+retry:
+       ktime_get_ts(&ts);
+       ts = timespec_sub(ts, dev->radio_rds_init_ts);
+       blk = ts.tv_sec * 100 + ts.tv_nsec / 10000000;
+       blk = (blk * VIVID_RDS_GEN_BLOCKS) / 500;
+       if (blk - VIVID_RDS_GEN_BLOCKS >= dev->radio_tx_rds_last_block)
+               dev->radio_tx_rds_last_block = blk - VIVID_RDS_GEN_BLOCKS + 1;
+
+       /*
+        * No data is available if there hasn't been time to get new data,
+        * or if the RDS receiver has been disabled, or if we use the data
+        * from the RDS transmitter and that RDS transmitter has been disabled,
+        * or if the signal quality is too weak.
+        */
+       if (blk == dev->radio_tx_rds_last_block ||
+           !(dev->radio_tx_subchans & V4L2_TUNER_SUB_RDS)) {
+               mutex_unlock(&dev->mutex);
+               if (file->f_flags & O_NONBLOCK)
+                       return -EWOULDBLOCK;
+               if (msleep_interruptible(20) && signal_pending(current))
+                       return -EINTR;
+               if (mutex_lock_interruptible(&dev->mutex))
+                       return -ERESTARTSYS;
+               goto retry;
+       }
+
+       for (i = 0; i < size && blk > dev->radio_tx_rds_last_block;
+                       dev->radio_tx_rds_last_block++) {
+               unsigned data_blk = dev->radio_tx_rds_last_block % VIVID_RDS_GEN_BLOCKS;
+               struct v4l2_rds_data rds;
+
+               if (copy_from_user(&rds, buf + i, sizeof(rds))) {
+                       i = -EFAULT;
+                       break;
+               }
+               i += sizeof(rds);
+               if (!dev->radio_rds_loop)
+                       continue;
+               if ((rds.block & V4L2_RDS_BLOCK_MSK) == V4L2_RDS_BLOCK_INVALID ||
+                   (rds.block & V4L2_RDS_BLOCK_ERROR))
+                       continue;
+               rds.block &= V4L2_RDS_BLOCK_MSK;
+               data[data_blk] = rds;
+       }
+       mutex_unlock(&dev->mutex);
+       return i;
+}
+
+unsigned int vivid_radio_tx_poll(struct file *file, struct poll_table_struct *wait)
+{
+       return POLLOUT | POLLWRNORM | v4l2_ctrl_poll(file, wait);
+}
+
+int vidioc_g_modulator(struct file *file, void *fh, struct v4l2_modulator *a)
+{
+       struct vivid_dev *dev = video_drvdata(file);
+
+       if (a->index > 0)
+               return -EINVAL;
+
+       strlcpy(a->name, "AM/FM/SW Transmitter", sizeof(a->name));
+       a->capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO |
+                       V4L2_TUNER_CAP_FREQ_BANDS | V4L2_TUNER_CAP_RDS |
+                       (dev->radio_tx_rds_controls ?
+                               V4L2_TUNER_CAP_RDS_CONTROLS :
+                               V4L2_TUNER_CAP_RDS_BLOCK_IO);
+       a->rangelow = AM_FREQ_RANGE_LOW;
+       a->rangehigh = FM_FREQ_RANGE_HIGH;
+       a->txsubchans = dev->radio_tx_subchans;
+       return 0;
+}
+
+int vidioc_s_modulator(struct file *file, void *fh, const struct v4l2_modulator *a)
+{
+       struct vivid_dev *dev = video_drvdata(file);
+
+       if (a->index)
+               return -EINVAL;
+       if (a->txsubchans & ~0x13)
+               return -EINVAL;
+       dev->radio_tx_subchans = a->txsubchans;
+       return 0;
+}
diff --git a/drivers/media/platform/vivid/vivid-radio-tx.h b/drivers/media/platform/vivid/vivid-radio-tx.h
new file mode 100644 (file)
index 0000000..7f8ff75
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ * vivid-radio-tx.h - radio transmitter support functions.
+ *
+ * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
+ *
+ * This program is free software; you may redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * 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 _VIVID_RADIO_TX_H_
+#define _VIVID_RADIO_TX_H_
+
+ssize_t vivid_radio_tx_write(struct file *, const char __user *, size_t, loff_t *);
+unsigned int vivid_radio_tx_poll(struct file *file, struct poll_table_struct *wait);
+
+int vidioc_g_modulator(struct file *file, void *fh, struct v4l2_modulator *a);
+int vidioc_s_modulator(struct file *file, void *fh, const struct v4l2_modulator *a);
+
+#endif
diff --git a/drivers/media/platform/vivid/vivid-rds-gen.c b/drivers/media/platform/vivid/vivid-rds-gen.c
new file mode 100644 (file)
index 0000000..c382343
--- /dev/null
@@ -0,0 +1,166 @@
+/*
+ * vivid-rds-gen.c - rds (radio data system) generator support functions.
+ *
+ * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
+ *
+ * This program is free software; you may redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * 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/ktime.h>
+#include <linux/string.h>
+#include <linux/videodev2.h>
+
+#include "vivid-rds-gen.h"
+
+static u8 vivid_get_di(const struct vivid_rds_gen *rds, unsigned grp)
+{
+       switch (grp) {
+       case 0:
+               return (rds->dyn_pty << 2) | (grp & 3);
+       case 1:
+               return (rds->compressed << 2) | (grp & 3);
+       case 2:
+               return (rds->art_head << 2) | (grp & 3);
+       case 3:
+               return (rds->mono_stereo << 2) | (grp & 3);
+       }
+       return 0;
+}
+
+/*
+ * This RDS generator creates 57 RDS groups (one group == four RDS blocks).
+ * Groups 0-3, 22-25 and 44-47 (spaced 22 groups apart) are filled with a
+ * standard 0B group containing the PI code and PS name.
+ *
+ * Groups 4-19 and 26-41 use group 2A for the radio text.
+ *
+ * Group 56 contains the time (group 4A).
+ *
+ * All remaining groups use a filler group 15B block that just repeats
+ * the PI and PTY codes.
+ */
+void vivid_rds_generate(struct vivid_rds_gen *rds)
+{
+       struct v4l2_rds_data *data = rds->data;
+       unsigned grp;
+       struct tm tm;
+       unsigned date;
+       unsigned time;
+       int l;
+
+       for (grp = 0; grp < VIVID_RDS_GEN_GROUPS; grp++, data += VIVID_RDS_GEN_BLKS_PER_GRP) {
+               data[0].lsb = rds->picode & 0xff;
+               data[0].msb = rds->picode >> 8;
+               data[0].block = V4L2_RDS_BLOCK_A | (V4L2_RDS_BLOCK_A << 3);
+               data[1].lsb = rds->pty << 5;
+               data[1].msb = (rds->pty >> 3) | (rds->tp << 2);
+               data[1].block = V4L2_RDS_BLOCK_B | (V4L2_RDS_BLOCK_B << 3);
+               data[3].block = V4L2_RDS_BLOCK_D | (V4L2_RDS_BLOCK_D << 3);
+
+               switch (grp) {
+               case 0 ... 3:
+               case 22 ... 25:
+               case 44 ... 47: /* Group 0B */
+                       data[1].lsb |= (rds->ta << 4) | (rds->ms << 3);
+                       data[1].lsb |= vivid_get_di(rds, grp % 22);
+                       data[1].msb |= 1 << 3;
+                       data[2].lsb = rds->picode & 0xff;
+                       data[2].msb = rds->picode >> 8;
+                       data[2].block = V4L2_RDS_BLOCK_C_ALT | (V4L2_RDS_BLOCK_C_ALT << 3);
+                       data[3].lsb = rds->psname[2 * (grp % 22) + 1];
+                       data[3].msb = rds->psname[2 * (grp % 22)];
+                       break;
+               case 4 ... 19:
+               case 26 ... 41: /* Group 2A */
+                       data[1].lsb |= (grp - 4) % 22;
+                       data[1].msb |= 4 << 3;
+                       data[2].msb = rds->radiotext[4 * ((grp - 4) % 22)];
+                       data[2].lsb = rds->radiotext[4 * ((grp - 4) % 22) + 1];
+                       data[2].block = V4L2_RDS_BLOCK_C | (V4L2_RDS_BLOCK_C << 3);
+                       data[3].msb = rds->radiotext[4 * ((grp - 4) % 22) + 2];
+                       data[3].lsb = rds->radiotext[4 * ((grp - 4) % 22) + 3];
+                       break;
+               case 56:
+                       /*
+                        * Group 4A
+                        *
+                        * Uses the algorithm from Annex G of the RDS standard
+                        * EN 50067:1998 to convert a UTC date to an RDS Modified
+                        * Julian Day.
+                        */
+                       time_to_tm(get_seconds(), 0, &tm);
+                       l = tm.tm_mon <= 1;
+                       date = 14956 + tm.tm_mday + ((tm.tm_year - l) * 1461) / 4 +
+                               ((tm.tm_mon + 2 + l * 12) * 306001) / 10000;
+                       time = (tm.tm_hour << 12) |
+                              (tm.tm_min << 6) |
+                              (sys_tz.tz_minuteswest >= 0 ? 0x20 : 0) |
+                              (abs(sys_tz.tz_minuteswest) / 30);
+                       data[1].lsb &= ~3;
+                       data[1].lsb |= date >> 15;
+                       data[1].msb |= 8 << 3;
+                       data[2].lsb = (date << 1) & 0xfe;
+                       data[2].lsb |= (time >> 16) & 1;
+                       data[2].msb = (date >> 7) & 0xff;
+                       data[2].block = V4L2_RDS_BLOCK_C | (V4L2_RDS_BLOCK_C << 3);
+                       data[3].lsb = time & 0xff;
+                       data[3].msb = (time >> 8) & 0xff;
+                       break;
+               default: /* Group 15B */
+                       data[1].lsb |= (rds->ta << 4) | (rds->ms << 3);
+                       data[1].lsb |= vivid_get_di(rds, grp % 22);
+                       data[1].msb |= 0x1f << 3;
+                       data[2].lsb = rds->picode & 0xff;
+                       data[2].msb = rds->picode >> 8;
+                       data[2].block = V4L2_RDS_BLOCK_C_ALT | (V4L2_RDS_BLOCK_C_ALT << 3);
+                       data[3].lsb = rds->pty << 5;
+                       data[3].lsb |= (rds->ta << 4) | (rds->ms << 3);
+                       data[3].lsb |= vivid_get_di(rds, grp % 22);
+                       data[3].msb |= rds->pty >> 3;
+                       data[3].msb |= 0x1f << 3;
+                       break;
+               }
+       }
+}
+
+void vivid_rds_gen_fill(struct vivid_rds_gen *rds, unsigned freq,
+                         bool alt)
+{
+       /* Alternate PTY between Info and Weather */
+       if (rds->use_rbds) {
+               rds->picode = 0x2e75; /* 'KLNX' call sign */
+               rds->pty = alt ? 29 : 2;
+       } else {
+               rds->picode = 0x8088;
+               rds->pty = alt ? 16 : 3;
+       }
+       rds->mono_stereo = true;
+       rds->art_head = false;
+       rds->compressed = false;
+       rds->dyn_pty = false;
+       rds->tp = true;
+       rds->ta = alt;
+       rds->ms = true;
+       snprintf(rds->psname, sizeof(rds->psname), "%6d.%1d",
+                freq / 16, ((freq & 0xf) * 10) / 16);
+       if (alt)
+               strlcpy(rds->radiotext,
+                       " The Radio Data System can switch between different Radio Texts ",
+                       sizeof(rds->radiotext));
+       else
+               strlcpy(rds->radiotext,
+                       "An example of Radio Text as transmitted by the Radio Data System",
+                       sizeof(rds->radiotext));
+}
diff --git a/drivers/media/platform/vivid/vivid-rds-gen.h b/drivers/media/platform/vivid/vivid-rds-gen.h
new file mode 100644 (file)
index 0000000..eff4bf5
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * vivid-rds-gen.h - rds (radio data system) generator support functions.
+ *
+ * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
+ *
+ * This program is free software; you may redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * 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 _VIVID_RDS_GEN_H_
+#define _VIVID_RDS_GEN_H_
+
+/*
+ * It takes almost exactly 5 seconds to transmit 57 RDS groups.
+ * Each group has 4 blocks and each block has a payload of 16 bits + a
+ * block identification. The driver will generate the contents of these
+ * 57 groups only when necessary and it will just be played continuously.
+ */
+#define VIVID_RDS_GEN_GROUPS 57
+#define VIVID_RDS_GEN_BLKS_PER_GRP 4
+#define VIVID_RDS_GEN_BLOCKS (VIVID_RDS_GEN_BLKS_PER_GRP * VIVID_RDS_GEN_GROUPS)
+
+struct vivid_rds_gen {
+       struct v4l2_rds_data    data[VIVID_RDS_GEN_BLOCKS];
+       bool                    use_rbds;
+       u16                     picode;
+       u8                      pty;
+       bool                    mono_stereo;
+       bool                    art_head;
+       bool                    compressed;
+       bool                    dyn_pty;
+       bool                    ta;
+       bool                    tp;
+       bool                    ms;
+       char                    psname[8 + 1];
+       char                    radiotext[64 + 1];
+};
+
+void vivid_rds_gen_fill(struct vivid_rds_gen *rds, unsigned freq,
+                   bool use_alternate);
+void vivid_rds_generate(struct vivid_rds_gen *rds);
+
+#endif
diff --git a/drivers/media/platform/vivid/vivid-sdr-cap.c b/drivers/media/platform/vivid/vivid-sdr-cap.c
new file mode 100644 (file)
index 0000000..8c5d661
--- /dev/null
@@ -0,0 +1,499 @@
+/*
+ * vivid-sdr-cap.c - software defined radio support functions.
+ *
+ * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
+ *
+ * This program is free software; you may redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/kthread.h>
+#include <linux/freezer.h>
+#include <linux/videodev2.h>
+#include <linux/v4l2-dv-timings.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-event.h>
+#include <media/v4l2-dv-timings.h>
+
+#include "vivid-core.h"
+#include "vivid-ctrls.h"
+#include "vivid-sdr-cap.h"
+
+static const struct v4l2_frequency_band bands_adc[] = {
+       {
+               .tuner = 0,
+               .type = V4L2_TUNER_ADC,
+               .index = 0,
+               .capability = V4L2_TUNER_CAP_1HZ | V4L2_TUNER_CAP_FREQ_BANDS,
+               .rangelow   =  300000,
+               .rangehigh  =  300000,
+       },
+       {
+               .tuner = 0,
+               .type = V4L2_TUNER_ADC,
+               .index = 1,
+               .capability = V4L2_TUNER_CAP_1HZ | V4L2_TUNER_CAP_FREQ_BANDS,
+               .rangelow   =  900001,
+               .rangehigh  = 2800000,
+       },
+       {
+               .tuner = 0,
+               .type = V4L2_TUNER_ADC,
+               .index = 2,
+               .capability = V4L2_TUNER_CAP_1HZ | V4L2_TUNER_CAP_FREQ_BANDS,
+               .rangelow   = 3200000,
+               .rangehigh  = 3200000,
+       },
+};
+
+/* ADC band midpoints */
+#define BAND_ADC_0 ((bands_adc[0].rangehigh + bands_adc[1].rangelow) / 2)
+#define BAND_ADC_1 ((bands_adc[1].rangehigh + bands_adc[2].rangelow) / 2)
+
+static const struct v4l2_frequency_band bands_fm[] = {
+       {
+               .tuner = 1,
+               .type = V4L2_TUNER_RF,
+               .index = 0,
+               .capability = V4L2_TUNER_CAP_1HZ | V4L2_TUNER_CAP_FREQ_BANDS,
+               .rangelow   =    50000000,
+               .rangehigh  =  2000000000,
+       },
+};
+
+static void vivid_thread_sdr_cap_tick(struct vivid_dev *dev)
+{
+       struct vivid_buffer *sdr_cap_buf = NULL;
+
+       dprintk(dev, 1, "SDR Capture Thread Tick\n");
+
+       /* Drop a certain percentage of buffers. */
+       if (dev->perc_dropped_buffers &&
+           prandom_u32_max(100) < dev->perc_dropped_buffers)
+               return;
+
+       spin_lock(&dev->slock);
+       if (!list_empty(&dev->sdr_cap_active)) {
+               sdr_cap_buf = list_entry(dev->sdr_cap_active.next,
+                                        struct vivid_buffer, list);
+               list_del(&sdr_cap_buf->list);
+       }
+       spin_unlock(&dev->slock);
+
+       if (sdr_cap_buf) {
+               sdr_cap_buf->vb.v4l2_buf.sequence = dev->sdr_cap_seq_count;
+               vivid_sdr_cap_process(dev, sdr_cap_buf);
+               v4l2_get_timestamp(&sdr_cap_buf->vb.v4l2_buf.timestamp);
+               sdr_cap_buf->vb.v4l2_buf.timestamp.tv_sec += dev->time_wrap_offset;
+               vb2_buffer_done(&sdr_cap_buf->vb, dev->dqbuf_error ?
+                               VB2_BUF_STATE_ERROR : VB2_BUF_STATE_DONE);
+               dev->dqbuf_error = false;
+       }
+}
+
+static int vivid_thread_sdr_cap(void *data)
+{
+       struct vivid_dev *dev = data;
+       u64 samples_since_start;
+       u64 buffers_since_start;
+       u64 next_jiffies_since_start;
+       unsigned long jiffies_since_start;
+       unsigned long cur_jiffies;
+       unsigned wait_jiffies;
+
+       dprintk(dev, 1, "SDR Capture Thread Start\n");
+
+       set_freezable();
+
+       /* Resets frame counters */
+       dev->sdr_cap_seq_offset = 0;
+       if (dev->seq_wrap)
+               dev->sdr_cap_seq_offset = 0xffffff80U;
+       dev->jiffies_sdr_cap = jiffies;
+       dev->sdr_cap_seq_resync = false;
+
+       for (;;) {
+               try_to_freeze();
+               if (kthread_should_stop())
+                       break;
+
+               mutex_lock(&dev->mutex);
+               cur_jiffies = jiffies;
+               if (dev->sdr_cap_seq_resync) {
+                       dev->jiffies_sdr_cap = cur_jiffies;
+                       dev->sdr_cap_seq_offset = dev->sdr_cap_seq_count + 1;
+                       dev->sdr_cap_seq_count = 0;
+                       dev->sdr_cap_seq_resync = false;
+               }
+               /* Calculate the number of jiffies since we started streaming */
+               jiffies_since_start = cur_jiffies - dev->jiffies_sdr_cap;
+               /* Get the number of buffers streamed since the start */
+               buffers_since_start = (u64)jiffies_since_start * dev->sdr_adc_freq +
+                                     (HZ * SDR_CAP_SAMPLES_PER_BUF) / 2;
+               do_div(buffers_since_start, HZ * SDR_CAP_SAMPLES_PER_BUF);
+
+               /*
+                * After more than 0xf0000000 (rounded down to a multiple of
+                * 'jiffies-per-day' to ease jiffies_to_msecs calculation)
+                * jiffies have passed since we started streaming reset the
+                * counters and keep track of the sequence offset.
+                */
+               if (jiffies_since_start > JIFFIES_RESYNC) {
+                       dev->jiffies_sdr_cap = cur_jiffies;
+                       dev->sdr_cap_seq_offset = buffers_since_start;
+                       buffers_since_start = 0;
+               }
+               dev->sdr_cap_seq_count = buffers_since_start + dev->sdr_cap_seq_offset;
+
+               vivid_thread_sdr_cap_tick(dev);
+               mutex_unlock(&dev->mutex);
+
+               /*
+                * Calculate the number of samples streamed since we started,
+                * not including the current buffer.
+                */
+               samples_since_start = buffers_since_start * SDR_CAP_SAMPLES_PER_BUF;
+
+               /* And the number of jiffies since we started */
+               jiffies_since_start = jiffies - dev->jiffies_sdr_cap;
+
+               /* Increase by the number of samples in one buffer */
+               samples_since_start += SDR_CAP_SAMPLES_PER_BUF;
+               /*
+                * Calculate when that next buffer is supposed to start
+                * in jiffies since we started streaming.
+                */
+               next_jiffies_since_start = samples_since_start * HZ +
+                                          dev->sdr_adc_freq / 2;
+               do_div(next_jiffies_since_start, dev->sdr_adc_freq);
+               /* If it is in the past, then just schedule asap */
+               if (next_jiffies_since_start < jiffies_since_start)
+                       next_jiffies_since_start = jiffies_since_start;
+
+               wait_jiffies = next_jiffies_since_start - jiffies_since_start;
+               schedule_timeout_interruptible(wait_jiffies ? wait_jiffies : 1);
+       }
+       dprintk(dev, 1, "SDR Capture Thread End\n");
+       return 0;
+}
+
+static int sdr_cap_queue_setup(struct vb2_queue *vq, const struct v4l2_format *fmt,
+                      unsigned *nbuffers, unsigned *nplanes,
+                      unsigned sizes[], void *alloc_ctxs[])
+{
+       /* 2 = max 16-bit sample returned */
+       sizes[0] = SDR_CAP_SAMPLES_PER_BUF * 2;
+       *nplanes = 1;
+       return 0;
+}
+
+static int sdr_cap_buf_prepare(struct vb2_buffer *vb)
+{
+       struct vivid_dev *dev = vb2_get_drv_priv(vb->vb2_queue);
+       unsigned size = SDR_CAP_SAMPLES_PER_BUF * 2;
+
+       dprintk(dev, 1, "%s\n", __func__);
+
+       if (dev->buf_prepare_error) {
+               /*
+                * Error injection: test what happens if buf_prepare() returns
+                * an error.
+                */
+               dev->buf_prepare_error = false;
+               return -EINVAL;
+       }
+       if (vb2_plane_size(vb, 0) < size) {
+               dprintk(dev, 1, "%s data will not fit into plane (%lu < %u)\n",
+                               __func__, vb2_plane_size(vb, 0), size);
+               return -EINVAL;
+       }
+       vb2_set_plane_payload(vb, 0, size);
+
+       return 0;
+}
+
+static void sdr_cap_buf_queue(struct vb2_buffer *vb)
+{
+       struct vivid_dev *dev = vb2_get_drv_priv(vb->vb2_queue);
+       struct vivid_buffer *buf = container_of(vb, struct vivid_buffer, vb);
+
+       dprintk(dev, 1, "%s\n", __func__);
+
+       spin_lock(&dev->slock);
+       list_add_tail(&buf->list, &dev->sdr_cap_active);
+       spin_unlock(&dev->slock);
+}
+
+static int sdr_cap_start_streaming(struct vb2_queue *vq, unsigned count)
+{
+       struct vivid_dev *dev = vb2_get_drv_priv(vq);
+       int err = 0;
+
+       dprintk(dev, 1, "%s\n", __func__);
+       dev->sdr_cap_seq_count = 0;
+       if (dev->start_streaming_error) {
+               dev->start_streaming_error = false;
+               err = -EINVAL;
+       } else if (dev->kthread_sdr_cap == NULL) {
+               dev->kthread_sdr_cap = kthread_run(vivid_thread_sdr_cap, dev,
+                               "%s-sdr-cap", dev->v4l2_dev.name);
+
+               if (IS_ERR(dev->kthread_sdr_cap)) {
+                       v4l2_err(&dev->v4l2_dev, "kernel_thread() failed\n");
+                       err = PTR_ERR(dev->kthread_sdr_cap);
+                       dev->kthread_sdr_cap = NULL;
+               }
+       }
+       if (err) {
+               struct vivid_buffer *buf, *tmp;
+
+               list_for_each_entry_safe(buf, tmp, &dev->sdr_cap_active, list) {
+                       list_del(&buf->list);
+                       vb2_buffer_done(&buf->vb, VB2_BUF_STATE_QUEUED);
+               }
+       }
+       return err;
+}
+
+/* abort streaming and wait for last buffer */
+static void sdr_cap_stop_streaming(struct vb2_queue *vq)
+{
+       struct vivid_dev *dev = vb2_get_drv_priv(vq);
+
+       if (dev->kthread_sdr_cap == NULL)
+               return;
+
+       while (!list_empty(&dev->sdr_cap_active)) {
+               struct vivid_buffer *buf;
+
+               buf = list_entry(dev->sdr_cap_active.next, struct vivid_buffer, list);
+               list_del(&buf->list);
+               vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR);
+       }
+
+       /* shutdown control thread */
+       mutex_unlock(&dev->mutex);
+       kthread_stop(dev->kthread_sdr_cap);
+       dev->kthread_sdr_cap = NULL;
+       mutex_lock(&dev->mutex);
+}
+
+const struct vb2_ops vivid_sdr_cap_qops = {
+       .queue_setup            = sdr_cap_queue_setup,
+       .buf_prepare            = sdr_cap_buf_prepare,
+       .buf_queue              = sdr_cap_buf_queue,
+       .start_streaming        = sdr_cap_start_streaming,
+       .stop_streaming         = sdr_cap_stop_streaming,
+       .wait_prepare           = vivid_unlock,
+       .wait_finish            = vivid_lock,
+};
+
+int vivid_sdr_enum_freq_bands(struct file *file, void *fh, struct v4l2_frequency_band *band)
+{
+       switch (band->tuner) {
+       case 0:
+               if (band->index >= ARRAY_SIZE(bands_adc))
+                       return -EINVAL;
+               *band = bands_adc[band->index];
+               return 0;
+       case 1:
+               if (band->index >= ARRAY_SIZE(bands_fm))
+                       return -EINVAL;
+               *band = bands_fm[band->index];
+               return 0;
+       default:
+               return -EINVAL;
+       }
+}
+
+int vivid_sdr_g_frequency(struct file *file, void *fh, struct v4l2_frequency *vf)
+{
+       struct vivid_dev *dev = video_drvdata(file);
+
+       switch (vf->tuner) {
+       case 0:
+               vf->frequency = dev->sdr_adc_freq;
+               vf->type = V4L2_TUNER_ADC;
+               return 0;
+       case 1:
+               vf->frequency = dev->sdr_fm_freq;
+               vf->type = V4L2_TUNER_RF;
+               return 0;
+       default:
+               return -EINVAL;
+       }
+}
+
+int vivid_sdr_s_frequency(struct file *file, void *fh, const struct v4l2_frequency *vf)
+{
+       struct vivid_dev *dev = video_drvdata(file);
+       unsigned freq = vf->frequency;
+       unsigned band;
+
+       switch (vf->tuner) {
+       case 0:
+               if (vf->type != V4L2_TUNER_ADC)
+                       return -EINVAL;
+               if (freq < BAND_ADC_0)
+                       band = 0;
+               else if (freq < BAND_ADC_1)
+                       band = 1;
+               else
+                       band = 2;
+
+               freq = clamp_t(unsigned, freq,
+                               bands_adc[band].rangelow,
+                               bands_adc[band].rangehigh);
+
+               if (vb2_is_streaming(&dev->vb_sdr_cap_q) &&
+                   freq != dev->sdr_adc_freq) {
+                       /* resync the thread's timings */
+                       dev->sdr_cap_seq_resync = true;
+               }
+               dev->sdr_adc_freq = freq;
+               return 0;
+       case 1:
+               if (vf->type != V4L2_TUNER_RF)
+                       return -EINVAL;
+               dev->sdr_fm_freq = clamp_t(unsigned, freq,
+                               bands_fm[0].rangelow,
+                               bands_fm[0].rangehigh);
+               return 0;
+       default:
+               return -EINVAL;
+       }
+}
+
+int vivid_sdr_g_tuner(struct file *file, void *fh, struct v4l2_tuner *vt)
+{
+       switch (vt->index) {
+       case 0:
+               strlcpy(vt->name, "ADC", sizeof(vt->name));
+               vt->type = V4L2_TUNER_ADC;
+               vt->capability = V4L2_TUNER_CAP_1HZ | V4L2_TUNER_CAP_FREQ_BANDS;
+               vt->rangelow = bands_adc[0].rangelow;
+               vt->rangehigh = bands_adc[2].rangehigh;
+               return 0;
+       case 1:
+               strlcpy(vt->name, "RF", sizeof(vt->name));
+               vt->type = V4L2_TUNER_RF;
+               vt->capability = V4L2_TUNER_CAP_1HZ | V4L2_TUNER_CAP_FREQ_BANDS;
+               vt->rangelow = bands_fm[0].rangelow;
+               vt->rangehigh = bands_fm[0].rangehigh;
+               return 0;
+       default:
+               return -EINVAL;
+       }
+}
+
+int vivid_sdr_s_tuner(struct file *file, void *fh, const struct v4l2_tuner *vt)
+{
+       if (vt->index > 1)
+               return -EINVAL;
+       return 0;
+}
+
+int vidioc_enum_fmt_sdr_cap(struct file *file, void *fh, struct v4l2_fmtdesc *f)
+{
+       if (f->index)
+               return -EINVAL;
+       f->pixelformat = V4L2_SDR_FMT_CU8;
+       strlcpy(f->description, "IQ U8", sizeof(f->description));
+       return 0;
+}
+
+int vidioc_g_fmt_sdr_cap(struct file *file, void *fh, struct v4l2_format *f)
+{
+       f->fmt.sdr.pixelformat = V4L2_SDR_FMT_CU8;
+       f->fmt.sdr.buffersize = SDR_CAP_SAMPLES_PER_BUF * 2;
+       memset(f->fmt.sdr.reserved, 0, sizeof(f->fmt.sdr.reserved));
+       return 0;
+}
+
+#define FIXP_FRAC    (1 << 15)
+#define FIXP_PI      ((int)(FIXP_FRAC * 3.141592653589))
+
+/* cos() from cx88 driver: cx88-dsp.c */
+static s32 fixp_cos(unsigned int x)
+{
+       u32 t2, t4, t6, t8;
+       u16 period = x / FIXP_PI;
+
+       if (period % 2)
+               return -fixp_cos(x - FIXP_PI);
+       x = x % FIXP_PI;
+       if (x > FIXP_PI/2)
+               return -fixp_cos(FIXP_PI/2 - (x % (FIXP_PI/2)));
+       /* Now x is between 0 and FIXP_PI/2.
+        * To calculate cos(x) we use it's Taylor polinom. */
+       t2 = x*x/FIXP_FRAC/2;
+       t4 = t2*x/FIXP_FRAC*x/FIXP_FRAC/3/4;
+       t6 = t4*x/FIXP_FRAC*x/FIXP_FRAC/5/6;
+       t8 = t6*x/FIXP_FRAC*x/FIXP_FRAC/7/8;
+       return FIXP_FRAC-t2+t4-t6+t8;
+}
+
+static inline s32 fixp_sin(unsigned int x)
+{
+       return -fixp_cos(x + (FIXP_PI / 2));
+}
+
+void vivid_sdr_cap_process(struct vivid_dev *dev, struct vivid_buffer *buf)
+{
+       u8 *vbuf = vb2_plane_vaddr(&buf->vb, 0);
+       unsigned long i;
+       unsigned long plane_size = vb2_plane_size(&buf->vb, 0);
+       int fixp_src_phase_step, fixp_i, fixp_q;
+
+       /*
+        * TODO: Generated beep tone goes very crackly when sample rate is
+        * increased to ~1Msps or more. That is because of huge rounding error
+        * of phase angle caused by used cosine implementation.
+        */
+
+       /* calculate phase step */
+       #define BEEP_FREQ 1000 /* 1kHz beep */
+       fixp_src_phase_step = DIV_ROUND_CLOSEST(2 * FIXP_PI * BEEP_FREQ,
+                       dev->sdr_adc_freq);
+
+       for (i = 0; i < plane_size; i += 2) {
+               dev->sdr_fixp_mod_phase += fixp_cos(dev->sdr_fixp_src_phase);
+               dev->sdr_fixp_src_phase += fixp_src_phase_step;
+
+               /*
+                * Transfer phases to [0 / 2xPI] in order to avoid variable
+                * overflow and make it suitable for cosine implementation
+                * used, which does not support negative angles.
+                */
+               while (dev->sdr_fixp_mod_phase < (0 * FIXP_PI))
+                       dev->sdr_fixp_mod_phase += (2 * FIXP_PI);
+               while (dev->sdr_fixp_mod_phase > (2 * FIXP_PI))
+                       dev->sdr_fixp_mod_phase -= (2 * FIXP_PI);
+
+               while (dev->sdr_fixp_src_phase > (2 * FIXP_PI))
+                       dev->sdr_fixp_src_phase -= (2 * FIXP_PI);
+
+               fixp_i = fixp_cos(dev->sdr_fixp_mod_phase);
+               fixp_q = fixp_sin(dev->sdr_fixp_mod_phase);
+
+               /* convert 'fixp float' to u8 */
+               /* u8 = X * 127.5f + 127.5f; where X is float [-1.0 / +1.0] */
+               fixp_i = fixp_i * 1275 + FIXP_FRAC * 1275;
+               fixp_q = fixp_q * 1275 + FIXP_FRAC * 1275;
+               *vbuf++ = DIV_ROUND_CLOSEST(fixp_i, FIXP_FRAC * 10);
+               *vbuf++ = DIV_ROUND_CLOSEST(fixp_q, FIXP_FRAC * 10);
+       }
+}
diff --git a/drivers/media/platform/vivid/vivid-sdr-cap.h b/drivers/media/platform/vivid/vivid-sdr-cap.h
new file mode 100644 (file)
index 0000000..79c1890
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * vivid-sdr-cap.h - software defined radio support functions.
+ *
+ * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
+ *
+ * This program is free software; you may redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * 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 _VIVID_SDR_CAP_H_
+#define _VIVID_SDR_CAP_H_
+
+int vivid_sdr_enum_freq_bands(struct file *file, void *fh, struct v4l2_frequency_band *band);
+int vivid_sdr_g_frequency(struct file *file, void *fh, struct v4l2_frequency *vf);
+int vivid_sdr_s_frequency(struct file *file, void *fh, const struct v4l2_frequency *vf);
+int vivid_sdr_g_tuner(struct file *file, void *fh, struct v4l2_tuner *vt);
+int vivid_sdr_s_tuner(struct file *file, void *fh, const struct v4l2_tuner *vt);
+int vidioc_enum_fmt_sdr_cap(struct file *file, void *fh, struct v4l2_fmtdesc *f);
+int vidioc_g_fmt_sdr_cap(struct file *file, void *fh, struct v4l2_format *f);
+void vivid_sdr_cap_process(struct vivid_dev *dev, struct vivid_buffer *buf);
+
+extern const struct vb2_ops vivid_sdr_cap_qops;
+
+#endif
diff --git a/drivers/media/platform/vivid/vivid-tpg-colors.c b/drivers/media/platform/vivid/vivid-tpg-colors.c
new file mode 100644 (file)
index 0000000..2adddc0
--- /dev/null
@@ -0,0 +1,310 @@
+/*
+ * vivid-color.c - A table that converts colors to various colorspaces
+ *
+ * The test pattern generator uses the tpg_colors for its test patterns.
+ * For testing colorspaces the first 8 colors of that table need to be
+ * converted to their equivalent in the target colorspace.
+ *
+ * The tpg_csc_colors[] table is the result of that conversion and since
+ * it is precalculated the colorspace conversion is just a simple table
+ * lookup.
+ *
+ * This source also contains the code used to generate the tpg_csc_colors
+ * table. Run the following command to compile it:
+ *
+ *     gcc vivid-colors.c -DCOMPILE_APP -o gen-colors -lm
+ *
+ * and run the utility.
+ *
+ * Note that the converted colors are in the range 0x000-0xff0 (so times 16)
+ * in order to preserve precision.
+ *
+ * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
+ *
+ * This program is free software; you may redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * 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/videodev2.h>
+
+#include "vivid-tpg-colors.h"
+
+/* sRGB colors with range [0-255] */
+const struct color tpg_colors[TPG_COLOR_MAX] = {
+       /*
+        * Colors to test colorspace conversion: converting these colors
+        * to other colorspaces will never lead to out-of-gamut colors.
+        */
+       { 191, 191, 191 }, /* TPG_COLOR_CSC_WHITE */
+       { 191, 191,  50 }, /* TPG_COLOR_CSC_YELLOW */
+       {  50, 191, 191 }, /* TPG_COLOR_CSC_CYAN */
+       {  50, 191,  50 }, /* TPG_COLOR_CSC_GREEN */
+       { 191,  50, 191 }, /* TPG_COLOR_CSC_MAGENTA */
+       { 191,  50,  50 }, /* TPG_COLOR_CSC_RED */
+       {  50,  50, 191 }, /* TPG_COLOR_CSC_BLUE */
+       {  50,  50,  50 }, /* TPG_COLOR_CSC_BLACK */
+
+       /* 75% colors */
+       { 191, 191,   0 }, /* TPG_COLOR_75_YELLOW */
+       {   0, 191, 191 }, /* TPG_COLOR_75_CYAN */
+       {   0, 191,   0 }, /* TPG_COLOR_75_GREEN */
+       { 191,   0, 191 }, /* TPG_COLOR_75_MAGENTA */
+       { 191,   0,   0 }, /* TPG_COLOR_75_RED */
+       {   0,   0, 191 }, /* TPG_COLOR_75_BLUE */
+
+       /* 100% colors */
+       { 255, 255, 255 }, /* TPG_COLOR_100_WHITE */
+       { 255, 255,   0 }, /* TPG_COLOR_100_YELLOW */
+       {   0, 255, 255 }, /* TPG_COLOR_100_CYAN */
+       {   0, 255,   0 }, /* TPG_COLOR_100_GREEN */
+       { 255,   0, 255 }, /* TPG_COLOR_100_MAGENTA */
+       { 255,   0,   0 }, /* TPG_COLOR_100_RED */
+       {   0,   0, 255 }, /* TPG_COLOR_100_BLUE */
+       {   0,   0,   0 }, /* TPG_COLOR_100_BLACK */
+
+       {   0,   0,   0 }, /* TPG_COLOR_RANDOM placeholder */
+};
+
+#ifndef COMPILE_APP
+
+/* Generated table */
+const struct color16 tpg_csc_colors[V4L2_COLORSPACE_SRGB + 1][TPG_COLOR_CSC_BLACK + 1] = {
+       [V4L2_COLORSPACE_SMPTE170M][0] = { 2953, 2939, 2939 },
+       [V4L2_COLORSPACE_SMPTE170M][1] = { 2954, 2963, 585 },
+       [V4L2_COLORSPACE_SMPTE170M][2] = { 84, 2967, 2937 },
+       [V4L2_COLORSPACE_SMPTE170M][3] = { 93, 2990, 575 },
+       [V4L2_COLORSPACE_SMPTE170M][4] = { 3030, 259, 2933 },
+       [V4L2_COLORSPACE_SMPTE170M][5] = { 3031, 406, 557 },
+       [V4L2_COLORSPACE_SMPTE170M][6] = { 544, 428, 2931 },
+       [V4L2_COLORSPACE_SMPTE170M][7] = { 551, 547, 547 },
+       [V4L2_COLORSPACE_SMPTE240M][0] = { 2926, 2926, 2926 },
+       [V4L2_COLORSPACE_SMPTE240M][1] = { 2926, 2926, 857 },
+       [V4L2_COLORSPACE_SMPTE240M][2] = { 1594, 2901, 2901 },
+       [V4L2_COLORSPACE_SMPTE240M][3] = { 1594, 2901, 774 },
+       [V4L2_COLORSPACE_SMPTE240M][4] = { 2484, 618, 2858 },
+       [V4L2_COLORSPACE_SMPTE240M][5] = { 2484, 618, 617 },
+       [V4L2_COLORSPACE_SMPTE240M][6] = { 507, 507, 2832 },
+       [V4L2_COLORSPACE_SMPTE240M][7] = { 507, 507, 507 },
+       [V4L2_COLORSPACE_REC709][0] = { 2939, 2939, 2939 },
+       [V4L2_COLORSPACE_REC709][1] = { 2939, 2939, 547 },
+       [V4L2_COLORSPACE_REC709][2] = { 547, 2939, 2939 },
+       [V4L2_COLORSPACE_REC709][3] = { 547, 2939, 547 },
+       [V4L2_COLORSPACE_REC709][4] = { 2939, 547, 2939 },
+       [V4L2_COLORSPACE_REC709][5] = { 2939, 547, 547 },
+       [V4L2_COLORSPACE_REC709][6] = { 547, 547, 2939 },
+       [V4L2_COLORSPACE_REC709][7] = { 547, 547, 547 },
+       [V4L2_COLORSPACE_470_SYSTEM_M][0] = { 2894, 2988, 2808 },
+       [V4L2_COLORSPACE_470_SYSTEM_M][1] = { 2847, 3070, 843 },
+       [V4L2_COLORSPACE_470_SYSTEM_M][2] = { 1656, 2962, 2783 },
+       [V4L2_COLORSPACE_470_SYSTEM_M][3] = { 1572, 3045, 763 },
+       [V4L2_COLORSPACE_470_SYSTEM_M][4] = { 2477, 229, 2743 },
+       [V4L2_COLORSPACE_470_SYSTEM_M][5] = { 2422, 672, 614 },
+       [V4L2_COLORSPACE_470_SYSTEM_M][6] = { 725, 63, 2718 },
+       [V4L2_COLORSPACE_470_SYSTEM_M][7] = { 534, 561, 509 },
+       [V4L2_COLORSPACE_470_SYSTEM_BG][0] = { 2939, 2939, 2939 },
+       [V4L2_COLORSPACE_470_SYSTEM_BG][1] = { 2939, 2939, 621 },
+       [V4L2_COLORSPACE_470_SYSTEM_BG][2] = { 786, 2939, 2939 },
+       [V4L2_COLORSPACE_470_SYSTEM_BG][3] = { 786, 2939, 621 },
+       [V4L2_COLORSPACE_470_SYSTEM_BG][4] = { 2879, 547, 2923 },
+       [V4L2_COLORSPACE_470_SYSTEM_BG][5] = { 2879, 547, 547 },
+       [V4L2_COLORSPACE_470_SYSTEM_BG][6] = { 547, 547, 2923 },
+       [V4L2_COLORSPACE_470_SYSTEM_BG][7] = { 547, 547, 547 },
+       [V4L2_COLORSPACE_SRGB][0] = { 3056, 3056, 3056 },
+       [V4L2_COLORSPACE_SRGB][1] = { 3056, 3056, 800 },
+       [V4L2_COLORSPACE_SRGB][2] = { 800, 3056, 3056 },
+       [V4L2_COLORSPACE_SRGB][3] = { 800, 3056, 800 },
+       [V4L2_COLORSPACE_SRGB][4] = { 3056, 800, 3056 },
+       [V4L2_COLORSPACE_SRGB][5] = { 3056, 800, 800 },
+       [V4L2_COLORSPACE_SRGB][6] = { 800, 800, 3056 },
+       [V4L2_COLORSPACE_SRGB][7] = { 800, 800, 800 },
+};
+
+#else
+
+/* This code generates the table above */
+
+#include <math.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+static const double rec709_to_ntsc1953[3][3] = {
+       { 0.6698, 0.2678,  0.0323 },
+       { 0.0185, 1.0742, -0.0603 },
+       { 0.0162, 0.0432,  0.8551 }
+};
+
+static const double rec709_to_ebu[3][3] = {
+       { 0.9578, 0.0422, 0      },
+       { 0     , 1     , 0      },
+       { 0     , 0.0118, 0.9882 }
+};
+
+static const double rec709_to_170m[3][3] = {
+       {  1.0654, -0.0554, -0.0010 },
+       { -0.0196,  1.0364, -0.0167 },
+       {  0.0016,  0.0044,  0.9940 }
+};
+
+static const double rec709_to_240m[3][3] = {
+       { 0.7151, 0.2849, 0      },
+       { 0.0179, 0.9821, 0      },
+       { 0.0177, 0.0472, 0.9350 }
+};
+
+
+static void mult_matrix(double *r, double *g, double *b, const double m[3][3])
+{
+       double ir, ig, ib;
+
+       ir = m[0][0] * (*r) + m[0][1] * (*g) + m[0][2] * (*b);
+       ig = m[1][0] * (*r) + m[1][1] * (*g) + m[1][2] * (*b);
+       ib = m[2][0] * (*r) + m[2][1] * (*g) + m[2][2] * (*b);
+       *r = ir;
+       *g = ig;
+       *b = ib;
+}
+
+static double transfer_srgb_to_rgb(double v)
+{
+       return (v <= 0.03928) ? v / 12.92 : pow((v + 0.055) / 1.055, 2.4);
+}
+
+static double transfer_rgb_to_smpte240m(double v)
+{
+       return (v <= 0.0228) ? v * 4.0 : 1.1115 * pow(v, 0.45) - 0.1115;
+}
+
+static double transfer_rgb_to_rec709(double v)
+{
+       return (v < 0.018) ? v * 4.5 : 1.099 * pow(v, 0.45) - 0.099;
+}
+
+static double transfer_srgb_to_rec709(double v)
+{
+       return transfer_rgb_to_rec709(transfer_srgb_to_rgb(v));
+}
+
+static void csc(enum v4l2_colorspace colorspace, double *r, double *g, double *b)
+{
+       /* Convert the primaries of Rec. 709 Linear RGB */
+       switch (colorspace) {
+       case V4L2_COLORSPACE_SMPTE240M:
+               *r = transfer_srgb_to_rgb(*r);
+               *g = transfer_srgb_to_rgb(*g);
+               *b = transfer_srgb_to_rgb(*b);
+               mult_matrix(r, g, b, rec709_to_240m);
+               break;
+       case V4L2_COLORSPACE_SMPTE170M:
+               *r = transfer_srgb_to_rgb(*r);
+               *g = transfer_srgb_to_rgb(*g);
+               *b = transfer_srgb_to_rgb(*b);
+               mult_matrix(r, g, b, rec709_to_170m);
+               break;
+       case V4L2_COLORSPACE_470_SYSTEM_BG:
+               *r = transfer_srgb_to_rgb(*r);
+               *g = transfer_srgb_to_rgb(*g);
+               *b = transfer_srgb_to_rgb(*b);
+               mult_matrix(r, g, b, rec709_to_ebu);
+               break;
+       case V4L2_COLORSPACE_470_SYSTEM_M:
+               *r = transfer_srgb_to_rgb(*r);
+               *g = transfer_srgb_to_rgb(*g);
+               *b = transfer_srgb_to_rgb(*b);
+               mult_matrix(r, g, b, rec709_to_ntsc1953);
+               break;
+       case V4L2_COLORSPACE_SRGB:
+       case V4L2_COLORSPACE_REC709:
+       default:
+               break;
+       }
+
+       *r = ((*r) < 0) ? 0 : (((*r) > 1) ? 1 : (*r));
+       *g = ((*g) < 0) ? 0 : (((*g) > 1) ? 1 : (*g));
+       *b = ((*b) < 0) ? 0 : (((*b) > 1) ? 1 : (*b));
+
+       /* Encode to gamma corrected colorspace */
+       switch (colorspace) {
+       case V4L2_COLORSPACE_SMPTE240M:
+               *r = transfer_rgb_to_smpte240m(*r);
+               *g = transfer_rgb_to_smpte240m(*g);
+               *b = transfer_rgb_to_smpte240m(*b);
+               break;
+       case V4L2_COLORSPACE_SMPTE170M:
+       case V4L2_COLORSPACE_470_SYSTEM_M:
+       case V4L2_COLORSPACE_470_SYSTEM_BG:
+               *r = transfer_rgb_to_rec709(*r);
+               *g = transfer_rgb_to_rec709(*g);
+               *b = transfer_rgb_to_rec709(*b);
+               break;
+       case V4L2_COLORSPACE_SRGB:
+               break;
+       case V4L2_COLORSPACE_REC709:
+       default:
+               *r = transfer_srgb_to_rec709(*r);
+               *g = transfer_srgb_to_rec709(*g);
+               *b = transfer_srgb_to_rec709(*b);
+               break;
+       }
+}
+
+int main(int argc, char **argv)
+{
+       static const unsigned colorspaces[] = {
+               0,
+               V4L2_COLORSPACE_SMPTE170M,
+               V4L2_COLORSPACE_SMPTE240M,
+               V4L2_COLORSPACE_REC709,
+               0,
+               V4L2_COLORSPACE_470_SYSTEM_M,
+               V4L2_COLORSPACE_470_SYSTEM_BG,
+               0,
+               V4L2_COLORSPACE_SRGB,
+       };
+       static const char * const colorspace_names[] = {
+               "",
+               "V4L2_COLORSPACE_SMPTE170M",
+               "V4L2_COLORSPACE_SMPTE240M",
+               "V4L2_COLORSPACE_REC709",
+               "",
+               "V4L2_COLORSPACE_470_SYSTEM_M",
+               "V4L2_COLORSPACE_470_SYSTEM_BG",
+               "",
+               "V4L2_COLORSPACE_SRGB",
+       };
+       int i;
+       int c;
+
+       printf("/* Generated table */\n");
+       printf("const struct color16 tpg_csc_colors[V4L2_COLORSPACE_SRGB + 1][TPG_COLOR_CSC_BLACK + 1] = {\n");
+       for (c = 0; c <= V4L2_COLORSPACE_SRGB; c++) {
+               for (i = 0; i <= TPG_COLOR_CSC_BLACK; i++) {
+                       double r, g, b;
+
+                       if (colorspaces[c] == 0)
+                               continue;
+
+                       r = tpg_colors[i].r / 255.0;
+                       g = tpg_colors[i].g / 255.0;
+                       b = tpg_colors[i].b / 255.0;
+
+                       csc(c, &r, &g, &b);
+
+                       printf("\t[%s][%d] = { %d, %d, %d },\n", colorspace_names[c], i,
+                               (int)(r * 4080), (int)(g * 4080), (int)(b * 4080));
+               }
+       }
+       printf("};\n\n");
+       return 0;
+}
+
+#endif
diff --git a/drivers/media/platform/vivid/vivid-tpg-colors.h b/drivers/media/platform/vivid/vivid-tpg-colors.h
new file mode 100644 (file)
index 0000000..a2678fb
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ * vivid-color.h - Color definitions for the test pattern generator
+ *
+ * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
+ *
+ * This program is free software; you may redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * 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 _VIVID_COLORS_H_
+#define _VIVID_COLORS_H_
+
+struct color {
+       unsigned char r, g, b;
+};
+
+struct color16 {
+       int r, g, b;
+};
+
+enum tpg_color {
+       TPG_COLOR_CSC_WHITE,
+       TPG_COLOR_CSC_YELLOW,
+       TPG_COLOR_CSC_CYAN,
+       TPG_COLOR_CSC_GREEN,
+       TPG_COLOR_CSC_MAGENTA,
+       TPG_COLOR_CSC_RED,
+       TPG_COLOR_CSC_BLUE,
+       TPG_COLOR_CSC_BLACK,
+       TPG_COLOR_75_YELLOW,
+       TPG_COLOR_75_CYAN,
+       TPG_COLOR_75_GREEN,
+       TPG_COLOR_75_MAGENTA,
+       TPG_COLOR_75_RED,
+       TPG_COLOR_75_BLUE,
+       TPG_COLOR_100_WHITE,
+       TPG_COLOR_100_YELLOW,
+       TPG_COLOR_100_CYAN,
+       TPG_COLOR_100_GREEN,
+       TPG_COLOR_100_MAGENTA,
+       TPG_COLOR_100_RED,
+       TPG_COLOR_100_BLUE,
+       TPG_COLOR_100_BLACK,
+       TPG_COLOR_TEXTFG,
+       TPG_COLOR_TEXTBG,
+       TPG_COLOR_RANDOM,
+       TPG_COLOR_RAMP,
+       TPG_COLOR_MAX = TPG_COLOR_RAMP + 256
+};
+
+extern const struct color tpg_colors[TPG_COLOR_MAX];
+extern const struct color16 tpg_csc_colors[V4L2_COLORSPACE_SRGB + 1][TPG_COLOR_CSC_BLACK + 1];
+
+#endif
diff --git a/drivers/media/platform/vivid/vivid-tpg.c b/drivers/media/platform/vivid/vivid-tpg.c
new file mode 100644 (file)
index 0000000..0c6fa53
--- /dev/null
@@ -0,0 +1,1439 @@
+/*
+ * vivid-tpg.c - Test Pattern Generator
+ *
+ * Note: gen_twopix and tpg_gen_text are based on code from vivi.c. See the
+ * vivi.c source for the copyright information of those functions.
+ *
+ * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
+ *
+ * This program is free software; you may redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * 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 "vivid-tpg.h"
+
+/* Must remain in sync with enum tpg_pattern */
+const char * const tpg_pattern_strings[] = {
+       "75% Colorbar",
+       "100% Colorbar",
+       "CSC Colorbar",
+       "Horizontal 100% Colorbar",
+       "100% Color Squares",
+       "100% Black",
+       "100% White",
+       "100% Red",
+       "100% Green",
+       "100% Blue",
+       "16x16 Checkers",
+       "1x1 Checkers",
+       "Alternating Hor Lines",
+       "Alternating Vert Lines",
+       "One Pixel Wide Cross",
+       "Two Pixels Wide Cross",
+       "Ten Pixels Wide Cross",
+       "Gray Ramp",
+       "Noise",
+       NULL
+};
+
+/* Must remain in sync with enum tpg_aspect */
+const char * const tpg_aspect_strings[] = {
+       "Source Width x Height",
+       "4x3",
+       "14x9",
+       "16x9",
+       "16x9 Anamorphic",
+       NULL
+};
+
+/*
+ * Sine table: sin[0] = 127 * sin(-180 degrees)
+ *             sin[128] = 127 * sin(0 degrees)
+ *             sin[256] = 127 * sin(180 degrees)
+ */
+static const s8 sin[257] = {
+          0,   -4,   -7,  -11,  -13,  -18,  -20,  -22,  -26,  -29,  -33,  -35,  -37,  -41,  -43,  -48,
+        -50,  -52,  -56,  -58,  -62,  -63,  -65,  -69,  -71,  -75,  -76,  -78,  -82,  -83,  -87,  -88,
+        -90,  -93,  -94,  -97,  -99, -101, -103, -104, -107, -108, -110, -111, -112, -114, -115, -117,
+       -118, -119, -120, -121, -122, -123, -123, -124, -125, -125, -126, -126, -127, -127, -127, -127,
+       -127, -127, -127, -127, -126, -126, -125, -125, -124, -124, -123, -122, -121, -120, -119, -118,
+       -117, -116, -114, -113, -111, -110, -109, -107, -105, -103, -101, -100,  -97,  -96,  -93,  -91,
+        -90,  -87,  -85,  -82,  -80,  -76,  -75,  -73,  -69,  -67,  -63,  -62,  -60,  -56,  -54,  -50,
+        -48,  -46,  -41,  -39,  -35,  -33,  -31,  -26,  -24,  -20,  -18,  -15,  -11,   -9,   -4,   -2,
+          0,    2,    4,    9,   11,   15,   18,   20,   24,   26,   31,   33,   35,   39,   41,   46,
+         48,   50,   54,   56,   60,   62,   64,   67,   69,   73,   75,   76,   80,   82,   85,   87,
+         90,   91,   93,   96,   97,  100,  101,  103,  105,  107,  109,  110,  111,  113,  114,  116,
+        117,  118,  119,  120,  121,  122,  123,  124,  124,  125,  125,  126,  126,  127,  127,  127,
+        127,  127,  127,  127,  127,  126,  126,  125,  125,  124,  123,  123,  122,  121,  120,  119,
+        118,  117,  115,  114,  112,  111,  110,  108,  107,  104,  103,  101,   99,   97,   94,   93,
+         90,   88,   87,   83,   82,   78,   76,   75,   71,   69,   65,   64,   62,   58,   56,   52,
+         50,   48,   43,   41,   37,   35,   33,   29,   26,   22,   20,   18,   13,   11,    7,    4,
+          0,
+};
+
+#define cos(idx) sin[((idx) + 64) % sizeof(sin)]
+
+/* Global font descriptor */
+static const u8 *font8x16;
+
+void tpg_set_font(const u8 *f)
+{
+       font8x16 = f;
+}
+
+void tpg_init(struct tpg_data *tpg, unsigned w, unsigned h)
+{
+       memset(tpg, 0, sizeof(*tpg));
+       tpg->scaled_width = tpg->src_width = w;
+       tpg->src_height = tpg->buf_height = h;
+       tpg->crop.width = tpg->compose.width = w;
+       tpg->crop.height = tpg->compose.height = h;
+       tpg->recalc_colors = true;
+       tpg->recalc_square_border = true;
+       tpg->brightness = 128;
+       tpg->contrast = 128;
+       tpg->saturation = 128;
+       tpg->hue = 0;
+       tpg->mv_hor_mode = TPG_MOVE_NONE;
+       tpg->mv_vert_mode = TPG_MOVE_NONE;
+       tpg->field = V4L2_FIELD_NONE;
+       tpg_s_fourcc(tpg, V4L2_PIX_FMT_RGB24);
+       tpg->colorspace = V4L2_COLORSPACE_SRGB;
+       tpg->perc_fill = 100;
+}
+
+int tpg_alloc(struct tpg_data *tpg, unsigned max_w)
+{
+       unsigned pat;
+       unsigned plane;
+
+       tpg->max_line_width = max_w;
+       for (pat = 0; pat < TPG_MAX_PAT_LINES; pat++) {
+               for (plane = 0; plane < TPG_MAX_PLANES; plane++) {
+                       unsigned pixelsz = plane ? 1 : 4;
+
+                       tpg->lines[pat][plane] = vzalloc(max_w * 2 * pixelsz);
+                       if (!tpg->lines[pat][plane])
+                               return -ENOMEM;
+               }
+       }
+       for (plane = 0; plane < TPG_MAX_PLANES; plane++) {
+               unsigned pixelsz = plane ? 1 : 4;
+
+               tpg->contrast_line[plane] = vzalloc(max_w * pixelsz);
+               if (!tpg->contrast_line[plane])
+                       return -ENOMEM;
+               tpg->black_line[plane] = vzalloc(max_w * pixelsz);
+               if (!tpg->black_line[plane])
+                       return -ENOMEM;
+               tpg->random_line[plane] = vzalloc(max_w * pixelsz);
+               if (!tpg->random_line[plane])
+                       return -ENOMEM;
+       }
+       return 0;
+}
+
+void tpg_free(struct tpg_data *tpg)
+{
+       unsigned pat;
+       unsigned plane;
+
+       for (pat = 0; pat < TPG_MAX_PAT_LINES; pat++)
+               for (plane = 0; plane < TPG_MAX_PLANES; plane++) {
+                       vfree(tpg->lines[pat][plane]);
+                       tpg->lines[pat][plane] = NULL;
+               }
+       for (plane = 0; plane < TPG_MAX_PLANES; plane++) {
+               vfree(tpg->contrast_line[plane]);
+               vfree(tpg->black_line[plane]);
+               vfree(tpg->random_line[plane]);
+               tpg->contrast_line[plane] = NULL;
+               tpg->black_line[plane] = NULL;
+               tpg->random_line[plane] = NULL;
+       }
+}
+
+bool tpg_s_fourcc(struct tpg_data *tpg, u32 fourcc)
+{
+       tpg->fourcc = fourcc;
+       tpg->planes = 1;
+       tpg->recalc_colors = true;
+       switch (fourcc) {
+       case V4L2_PIX_FMT_RGB565:
+       case V4L2_PIX_FMT_RGB565X:
+       case V4L2_PIX_FMT_RGB555:
+       case V4L2_PIX_FMT_XRGB555:
+       case V4L2_PIX_FMT_ARGB555:
+       case V4L2_PIX_FMT_RGB555X:
+       case V4L2_PIX_FMT_RGB24:
+       case V4L2_PIX_FMT_BGR24:
+       case V4L2_PIX_FMT_RGB32:
+       case V4L2_PIX_FMT_BGR32:
+       case V4L2_PIX_FMT_XRGB32:
+       case V4L2_PIX_FMT_XBGR32:
+       case V4L2_PIX_FMT_ARGB32:
+       case V4L2_PIX_FMT_ABGR32:
+               tpg->is_yuv = false;
+               break;
+       case V4L2_PIX_FMT_NV16M:
+       case V4L2_PIX_FMT_NV61M:
+               tpg->planes = 2;
+               /* fall-through */
+       case V4L2_PIX_FMT_YUYV:
+       case V4L2_PIX_FMT_UYVY:
+       case V4L2_PIX_FMT_YVYU:
+       case V4L2_PIX_FMT_VYUY:
+               tpg->is_yuv = true;
+               break;
+       default:
+               return false;
+       }
+
+       switch (fourcc) {
+       case V4L2_PIX_FMT_RGB565:
+       case V4L2_PIX_FMT_RGB565X:
+       case V4L2_PIX_FMT_RGB555:
+       case V4L2_PIX_FMT_XRGB555:
+       case V4L2_PIX_FMT_ARGB555:
+       case V4L2_PIX_FMT_RGB555X:
+       case V4L2_PIX_FMT_YUYV:
+       case V4L2_PIX_FMT_UYVY:
+       case V4L2_PIX_FMT_YVYU:
+       case V4L2_PIX_FMT_VYUY:
+               tpg->twopixelsize[0] = 2 * 2;
+               break;
+       case V4L2_PIX_FMT_RGB24:
+       case V4L2_PIX_FMT_BGR24:
+               tpg->twopixelsize[0] = 2 * 3;
+               break;
+       case V4L2_PIX_FMT_RGB32:
+       case V4L2_PIX_FMT_BGR32:
+       case V4L2_PIX_FMT_XRGB32:
+       case V4L2_PIX_FMT_XBGR32:
+       case V4L2_PIX_FMT_ARGB32:
+       case V4L2_PIX_FMT_ABGR32:
+               tpg->twopixelsize[0] = 2 * 4;
+               break;
+       case V4L2_PIX_FMT_NV16M:
+       case V4L2_PIX_FMT_NV61M:
+               tpg->twopixelsize[0] = 2;
+               tpg->twopixelsize[1] = 2;
+               break;
+       }
+       return true;
+}
+
+void tpg_s_crop_compose(struct tpg_data *tpg, const struct v4l2_rect *crop,
+               const struct v4l2_rect *compose)
+{
+       tpg->crop = *crop;
+       tpg->compose = *compose;
+       tpg->scaled_width = (tpg->src_width * tpg->compose.width +
+                                tpg->crop.width - 1) / tpg->crop.width;
+       tpg->scaled_width &= ~1;
+       if (tpg->scaled_width > tpg->max_line_width)
+               tpg->scaled_width = tpg->max_line_width;
+       if (tpg->scaled_width < 2)
+               tpg->scaled_width = 2;
+       tpg->recalc_lines = true;
+}
+
+void tpg_reset_source(struct tpg_data *tpg, unsigned width, unsigned height,
+                      u32 field)
+{
+       unsigned p;
+
+       tpg->src_width = width;
+       tpg->src_height = height;
+       tpg->field = field;
+       tpg->buf_height = height;
+       if (V4L2_FIELD_HAS_T_OR_B(field))
+               tpg->buf_height /= 2;
+       tpg->scaled_width = width;
+       tpg->crop.top = tpg->crop.left = 0;
+       tpg->crop.width = width;
+       tpg->crop.height = height;
+       tpg->compose.top = tpg->compose.left = 0;
+       tpg->compose.width = width;
+       tpg->compose.height = tpg->buf_height;
+       for (p = 0; p < tpg->planes; p++)
+               tpg->bytesperline[p] = width * tpg->twopixelsize[p] / 2;
+       tpg->recalc_square_border = true;
+}
+
+static enum tpg_color tpg_get_textbg_color(struct tpg_data *tpg)
+{
+       switch (tpg->pattern) {
+       case TPG_PAT_BLACK:
+               return TPG_COLOR_100_WHITE;
+       case TPG_PAT_CSC_COLORBAR:
+               return TPG_COLOR_CSC_BLACK;
+       default:
+               return TPG_COLOR_100_BLACK;
+       }
+}
+
+static enum tpg_color tpg_get_textfg_color(struct tpg_data *tpg)
+{
+       switch (tpg->pattern) {
+       case TPG_PAT_75_COLORBAR:
+       case TPG_PAT_CSC_COLORBAR:
+               return TPG_COLOR_CSC_WHITE;
+       case TPG_PAT_BLACK:
+               return TPG_COLOR_100_BLACK;
+       default:
+               return TPG_COLOR_100_WHITE;
+       }
+}
+
+static u16 color_to_y(struct tpg_data *tpg, int r, int g, int b)
+{
+       switch (tpg->colorspace) {
+       case V4L2_COLORSPACE_SMPTE170M:
+       case V4L2_COLORSPACE_470_SYSTEM_M:
+       case V4L2_COLORSPACE_470_SYSTEM_BG:
+               return ((16829 * r + 33039 * g + 6416 * b + 16 * 32768) >> 16) + (16 << 4);
+       case V4L2_COLORSPACE_SMPTE240M:
+               return ((11932 * r + 39455 * g + 4897 * b + 16 * 32768) >> 16) + (16 << 4);
+       case V4L2_COLORSPACE_REC709:
+       case V4L2_COLORSPACE_SRGB:
+       default:
+               return ((11966 * r + 40254 * g + 4064 * b + 16 * 32768) >> 16) + (16 << 4);
+       }
+}
+
+static u16 color_to_cb(struct tpg_data *tpg, int r, int g, int b)
+{
+       switch (tpg->colorspace) {
+       case V4L2_COLORSPACE_SMPTE170M:
+       case V4L2_COLORSPACE_470_SYSTEM_M:
+       case V4L2_COLORSPACE_470_SYSTEM_BG:
+               return ((-9714 * r - 19070 * g + 28784 * b + 16 * 32768) >> 16) + (128 << 4);
+       case V4L2_COLORSPACE_SMPTE240M:
+               return ((-6684 * r - 22100 * g + 28784 * b + 16 * 32768) >> 16) + (128 << 4);
+       case V4L2_COLORSPACE_REC709:
+       case V4L2_COLORSPACE_SRGB:
+       default:
+               return ((-6596 * r - 22189 * g + 28784 * b + 16 * 32768) >> 16) + (128 << 4);
+       }
+}
+
+static u16 color_to_cr(struct tpg_data *tpg, int r, int g, int b)
+{
+       switch (tpg->colorspace) {
+       case V4L2_COLORSPACE_SMPTE170M:
+       case V4L2_COLORSPACE_470_SYSTEM_M:
+       case V4L2_COLORSPACE_470_SYSTEM_BG:
+               return ((28784 * r - 24103 * g - 4681 * b + 16 * 32768) >> 16) + (128 << 4);
+       case V4L2_COLORSPACE_SMPTE240M:
+               return ((28784 * r - 25606 * g - 3178 * b + 16 * 32768) >> 16) + (128 << 4);
+       case V4L2_COLORSPACE_REC709:
+       case V4L2_COLORSPACE_SRGB:
+       default:
+               return ((28784 * r - 26145 * g - 2639 * b + 16 * 32768) >> 16) + (128 << 4);
+       }
+}
+
+static u16 ycbcr_to_r(struct tpg_data *tpg, int y, int cb, int cr)
+{
+       int r;
+
+       y -= 16 << 4;
+       cb -= 128 << 4;
+       cr -= 128 << 4;
+       switch (tpg->colorspace) {
+       case V4L2_COLORSPACE_SMPTE170M:
+       case V4L2_COLORSPACE_470_SYSTEM_M:
+       case V4L2_COLORSPACE_470_SYSTEM_BG:
+               r = 4769 * y + 6537 * cr;
+               break;
+       case V4L2_COLORSPACE_SMPTE240M:
+               r = 4769 * y + 7376 * cr;
+               break;
+       case V4L2_COLORSPACE_REC709:
+       case V4L2_COLORSPACE_SRGB:
+       default:
+               r = 4769 * y + 7343 * cr;
+               break;
+       }
+       return clamp(r >> 12, 0, 0xff0);
+}
+
+static u16 ycbcr_to_g(struct tpg_data *tpg, int y, int cb, int cr)
+{
+       int g;
+
+       y -= 16 << 4;
+       cb -= 128 << 4;
+       cr -= 128 << 4;
+       switch (tpg->colorspace) {
+       case V4L2_COLORSPACE_SMPTE170M:
+       case V4L2_COLORSPACE_470_SYSTEM_M:
+       case V4L2_COLORSPACE_470_SYSTEM_BG:
+               g = 4769 * y - 1605 * cb - 3330 * cr;
+               break;
+       case V4L2_COLORSPACE_SMPTE240M:
+               g = 4769 * y - 1055 * cb - 2341 * cr;
+               break;
+       case V4L2_COLORSPACE_REC709:
+       case V4L2_COLORSPACE_SRGB:
+       default:
+               g = 4769 * y - 873 * cb - 2183 * cr;
+               break;
+       }
+       return clamp(g >> 12, 0, 0xff0);
+}
+
+static u16 ycbcr_to_b(struct tpg_data *tpg, int y, int cb, int cr)
+{
+       int b;
+
+       y -= 16 << 4;
+       cb -= 128 << 4;
+       cr -= 128 << 4;
+       switch (tpg->colorspace) {
+       case V4L2_COLORSPACE_SMPTE170M:
+       case V4L2_COLORSPACE_470_SYSTEM_M:
+       case V4L2_COLORSPACE_470_SYSTEM_BG:
+               b = 4769 * y + 7343 * cb;
+               break;
+       case V4L2_COLORSPACE_SMPTE240M:
+               b = 4769 * y + 8552 * cb;
+               break;
+       case V4L2_COLORSPACE_REC709:
+       case V4L2_COLORSPACE_SRGB:
+       default:
+               b = 4769 * y + 8652 * cb;
+               break;
+       }
+       return clamp(b >> 12, 0, 0xff0);
+}
+
+/* precalculate color bar values to speed up rendering */
+static void precalculate_color(struct tpg_data *tpg, int k)
+{
+       int col = k;
+       int r = tpg_colors[col].r;
+       int g = tpg_colors[col].g;
+       int b = tpg_colors[col].b;
+
+       if (k == TPG_COLOR_TEXTBG) {
+               col = tpg_get_textbg_color(tpg);
+
+               r = tpg_colors[col].r;
+               g = tpg_colors[col].g;
+               b = tpg_colors[col].b;
+       } else if (k == TPG_COLOR_TEXTFG) {
+               col = tpg_get_textfg_color(tpg);
+
+               r = tpg_colors[col].r;
+               g = tpg_colors[col].g;
+               b = tpg_colors[col].b;
+       } else if (tpg->pattern == TPG_PAT_NOISE) {
+               r = g = b = prandom_u32_max(256);
+       } else if (k == TPG_COLOR_RANDOM) {
+               r = g = b = tpg->qual_offset + prandom_u32_max(196);
+       } else if (k >= TPG_COLOR_RAMP) {
+               r = g = b = k - TPG_COLOR_RAMP;
+       }
+
+       if (tpg->pattern == TPG_PAT_CSC_COLORBAR && col <= TPG_COLOR_CSC_BLACK) {
+               r = tpg_csc_colors[tpg->colorspace][col].r;
+               g = tpg_csc_colors[tpg->colorspace][col].g;
+               b = tpg_csc_colors[tpg->colorspace][col].b;
+       } else {
+               r <<= 4;
+               g <<= 4;
+               b <<= 4;
+       }
+       if (tpg->qual == TPG_QUAL_GRAY)
+               r = g = b = color_to_y(tpg, r, g, b);
+
+       /*
+        * The assumption is that the RGB output is always full range,
+        * so only if the rgb_range overrides the 'real' rgb range do
+        * we need to convert the RGB values.
+        *
+        * Currently there is no way of signalling to userspace if you
+        * are actually giving it limited range RGB (or full range
+        * YUV for that matter).
+        *
+        * Remember that r, g and b are still in the 0 - 0xff0 range.
+        */
+       if (tpg->real_rgb_range == V4L2_DV_RGB_RANGE_LIMITED &&
+           tpg->rgb_range == V4L2_DV_RGB_RANGE_FULL) {
+               /*
+                * Convert from full range (which is what r, g and b are)
+                * to limited range (which is the 'real' RGB range), which
+                * is then interpreted as full range.
+                */
+               r = (r * 219) / 255 + (16 << 4);
+               g = (g * 219) / 255 + (16 << 4);
+               b = (b * 219) / 255 + (16 << 4);
+       } else if (tpg->real_rgb_range != V4L2_DV_RGB_RANGE_LIMITED &&
+                  tpg->rgb_range == V4L2_DV_RGB_RANGE_LIMITED) {
+               /*
+                * Clamp r, g and b to the limited range and convert to full
+                * range since that's what we deliver.
+                */
+               r = clamp(r, 16 << 4, 235 << 4);
+               g = clamp(g, 16 << 4, 235 << 4);
+               b = clamp(b, 16 << 4, 235 << 4);
+               r = (r - (16 << 4)) * 255 / 219;
+               g = (g - (16 << 4)) * 255 / 219;
+               b = (b - (16 << 4)) * 255 / 219;
+       }
+
+       if (tpg->brightness != 128 || tpg->contrast != 128 ||
+           tpg->saturation != 128 || tpg->hue) {
+               /* Implement these operations */
+
+               /* First convert to YCbCr */
+               int y = color_to_y(tpg, r, g, b);       /* Luma */
+               int cb = color_to_cb(tpg, r, g, b);     /* Cb */
+               int cr = color_to_cr(tpg, r, g, b);     /* Cr */
+               int tmp_cb, tmp_cr;
+
+               y = (16 << 4) + ((y - (16 << 4)) * tpg->contrast) / 128;
+               y += (tpg->brightness << 4) - (128 << 4);
+
+               cb -= 128 << 4;
+               cr -= 128 << 4;
+               tmp_cb = (cb * cos(128 + tpg->hue)) / 127 + (cr * sin[128 + tpg->hue]) / 127;
+               tmp_cr = (cr * cos(128 + tpg->hue)) / 127 - (cb * sin[128 + tpg->hue]) / 127;
+
+               cb = (128 << 4) + (tmp_cb * tpg->contrast * tpg->saturation) / (128 * 128);
+               cr = (128 << 4) + (tmp_cr * tpg->contrast * tpg->saturation) / (128 * 128);
+               if (tpg->is_yuv) {
+                       tpg->colors[k][0] = clamp(y >> 4, 1, 254);
+                       tpg->colors[k][1] = clamp(cb >> 4, 1, 254);
+                       tpg->colors[k][2] = clamp(cr >> 4, 1, 254);
+                       return;
+               }
+               r = ycbcr_to_r(tpg, y, cb, cr);
+               g = ycbcr_to_g(tpg, y, cb, cr);
+               b = ycbcr_to_b(tpg, y, cb, cr);
+       }
+
+       if (tpg->is_yuv) {
+               /* Convert to YCbCr */
+               u16 y = color_to_y(tpg, r, g, b);       /* Luma */
+               u16 cb = color_to_cb(tpg, r, g, b);     /* Cb */
+               u16 cr = color_to_cr(tpg, r, g, b);     /* Cr */
+
+               tpg->colors[k][0] = clamp(y >> 4, 1, 254);
+               tpg->colors[k][1] = clamp(cb >> 4, 1, 254);
+               tpg->colors[k][2] = clamp(cr >> 4, 1, 254);
+       } else {
+               switch (tpg->fourcc) {
+               case V4L2_PIX_FMT_RGB565:
+               case V4L2_PIX_FMT_RGB565X:
+                       r >>= 7;
+                       g >>= 6;
+                       b >>= 7;
+                       break;
+               case V4L2_PIX_FMT_RGB555:
+               case V4L2_PIX_FMT_XRGB555:
+               case V4L2_PIX_FMT_ARGB555:
+               case V4L2_PIX_FMT_RGB555X:
+                       r >>= 7;
+                       g >>= 7;
+                       b >>= 7;
+                       break;
+               default:
+                       r >>= 4;
+                       g >>= 4;
+                       b >>= 4;
+                       break;
+               }
+
+               tpg->colors[k][0] = r;
+               tpg->colors[k][1] = g;
+               tpg->colors[k][2] = b;
+       }
+}
+
+static void tpg_precalculate_colors(struct tpg_data *tpg)
+{
+       int k;
+
+       for (k = 0; k < TPG_COLOR_MAX; k++)
+               precalculate_color(tpg, k);
+}
+
+/* 'odd' is true for pixels 1, 3, 5, etc. and false for pixels 0, 2, 4, etc. */
+static void gen_twopix(struct tpg_data *tpg,
+               u8 buf[TPG_MAX_PLANES][8], int color, bool odd)
+{
+       unsigned offset = odd * tpg->twopixelsize[0] / 2;
+       u8 alpha = tpg->alpha_component;
+       u8 r_y, g_u, b_v;
+
+       if (tpg->alpha_red_only && color != TPG_COLOR_CSC_RED &&
+                                  color != TPG_COLOR_100_RED &&
+                                  color != TPG_COLOR_75_RED)
+               alpha = 0;
+       if (color == TPG_COLOR_RANDOM)
+               precalculate_color(tpg, color);
+       r_y = tpg->colors[color][0]; /* R or precalculated Y */
+       g_u = tpg->colors[color][1]; /* G or precalculated U */
+       b_v = tpg->colors[color][2]; /* B or precalculated V */
+
+       switch (tpg->fourcc) {
+       case V4L2_PIX_FMT_NV16M:
+               buf[0][offset] = r_y;
+               buf[1][offset] = odd ? b_v : g_u;
+               break;
+       case V4L2_PIX_FMT_NV61M:
+               buf[0][offset] = r_y;
+               buf[1][offset] = odd ? g_u : b_v;
+               break;
+
+       case V4L2_PIX_FMT_YUYV:
+               buf[0][offset] = r_y;
+               buf[0][offset + 1] = odd ? b_v : g_u;
+               break;
+       case V4L2_PIX_FMT_UYVY:
+               buf[0][offset] = odd ? b_v : g_u;
+               buf[0][offset + 1] = r_y;
+               break;
+       case V4L2_PIX_FMT_YVYU:
+               buf[0][offset] = r_y;
+               buf[0][offset + 1] = odd ? g_u : b_v;
+               break;
+       case V4L2_PIX_FMT_VYUY:
+               buf[0][offset] = odd ? g_u : b_v;
+               buf[0][offset + 1] = r_y;
+               break;
+       case V4L2_PIX_FMT_RGB565:
+               buf[0][offset] = (g_u << 5) | b_v;
+               buf[0][offset + 1] = (r_y << 3) | (g_u >> 3);
+               break;
+       case V4L2_PIX_FMT_RGB565X:
+               buf[0][offset] = (r_y << 3) | (g_u >> 3);
+               buf[0][offset + 1] = (g_u << 5) | b_v;
+               break;
+       case V4L2_PIX_FMT_RGB555:
+       case V4L2_PIX_FMT_XRGB555:
+               alpha = 0;
+               /* fall through */
+       case V4L2_PIX_FMT_ARGB555:
+               buf[0][offset] = (g_u << 5) | b_v;
+               buf[0][offset + 1] = (alpha & 0x80) | (r_y << 2) | (g_u >> 3);
+               break;
+       case V4L2_PIX_FMT_RGB555X:
+               buf[0][offset] = (alpha & 0x80) | (r_y << 2) | (g_u >> 3);
+               buf[0][offset + 1] = (g_u << 5) | b_v;
+               break;
+       case V4L2_PIX_FMT_RGB24:
+               buf[0][offset] = r_y;
+               buf[0][offset + 1] = g_u;
+               buf[0][offset + 2] = b_v;
+               break;
+       case V4L2_PIX_FMT_BGR24:
+               buf[0][offset] = b_v;
+               buf[0][offset + 1] = g_u;
+               buf[0][offset + 2] = r_y;
+               break;
+       case V4L2_PIX_FMT_RGB32:
+       case V4L2_PIX_FMT_XRGB32:
+               alpha = 0;
+               /* fall through */
+       case V4L2_PIX_FMT_ARGB32:
+               buf[0][offset] = alpha;
+               buf[0][offset + 1] = r_y;
+               buf[0][offset + 2] = g_u;
+               buf[0][offset + 3] = b_v;
+               break;
+       case V4L2_PIX_FMT_BGR32:
+       case V4L2_PIX_FMT_XBGR32:
+               alpha = 0;
+               /* fall through */
+       case V4L2_PIX_FMT_ABGR32:
+               buf[0][offset] = b_v;
+               buf[0][offset + 1] = g_u;
+               buf[0][offset + 2] = r_y;
+               buf[0][offset + 3] = alpha;
+               break;
+       }
+}
+
+/* Return how many pattern lines are used by the current pattern. */
+static unsigned tpg_get_pat_lines(struct tpg_data *tpg)
+{
+       switch (tpg->pattern) {
+       case TPG_PAT_CHECKERS_16X16:
+       case TPG_PAT_CHECKERS_1X1:
+       case TPG_PAT_ALTERNATING_HLINES:
+       case TPG_PAT_CROSS_1_PIXEL:
+       case TPG_PAT_CROSS_2_PIXELS:
+       case TPG_PAT_CROSS_10_PIXELS:
+               return 2;
+       case TPG_PAT_100_COLORSQUARES:
+       case TPG_PAT_100_HCOLORBAR:
+               return 8;
+       default:
+               return 1;
+       }
+}
+
+/* Which pattern line should be used for the given frame line. */
+static unsigned tpg_get_pat_line(struct tpg_data *tpg, unsigned line)
+{
+       switch (tpg->pattern) {
+       case TPG_PAT_CHECKERS_16X16:
+               return (line >> 4) & 1;
+       case TPG_PAT_CHECKERS_1X1:
+       case TPG_PAT_ALTERNATING_HLINES:
+               return line & 1;
+       case TPG_PAT_100_COLORSQUARES:
+       case TPG_PAT_100_HCOLORBAR:
+               return (line * 8) / tpg->src_height;
+       case TPG_PAT_CROSS_1_PIXEL:
+               return line == tpg->src_height / 2;
+       case TPG_PAT_CROSS_2_PIXELS:
+               return (line + 1) / 2 == tpg->src_height / 4;
+       case TPG_PAT_CROSS_10_PIXELS:
+               return (line + 10) / 20 == tpg->src_height / 40;
+       default:
+               return 0;
+       }
+}
+
+/*
+ * Which color should be used for the given pattern line and X coordinate.
+ * Note: x is in the range 0 to 2 * tpg->src_width.
+ */
+static enum tpg_color tpg_get_color(struct tpg_data *tpg, unsigned pat_line, unsigned x)
+{
+       /* Maximum number of bars are TPG_COLOR_MAX - otherwise, the input print code
+          should be modified */
+       static const enum tpg_color bars[3][8] = {
+               /* Standard ITU-R 75% color bar sequence */
+               { TPG_COLOR_CSC_WHITE,   TPG_COLOR_75_YELLOW,
+                 TPG_COLOR_75_CYAN,     TPG_COLOR_75_GREEN,
+                 TPG_COLOR_75_MAGENTA,  TPG_COLOR_75_RED,
+                 TPG_COLOR_75_BLUE,     TPG_COLOR_100_BLACK, },
+               /* Standard ITU-R 100% color bar sequence */
+               { TPG_COLOR_100_WHITE,   TPG_COLOR_100_YELLOW,
+                 TPG_COLOR_100_CYAN,    TPG_COLOR_100_GREEN,
+                 TPG_COLOR_100_MAGENTA, TPG_COLOR_100_RED,
+                 TPG_COLOR_100_BLUE,    TPG_COLOR_100_BLACK, },
+               /* Color bar sequence suitable to test CSC */
+               { TPG_COLOR_CSC_WHITE,   TPG_COLOR_CSC_YELLOW,
+                 TPG_COLOR_CSC_CYAN,    TPG_COLOR_CSC_GREEN,
+                 TPG_COLOR_CSC_MAGENTA, TPG_COLOR_CSC_RED,
+                 TPG_COLOR_CSC_BLUE,    TPG_COLOR_CSC_BLACK, },
+       };
+
+       switch (tpg->pattern) {
+       case TPG_PAT_75_COLORBAR:
+       case TPG_PAT_100_COLORBAR:
+       case TPG_PAT_CSC_COLORBAR:
+               return bars[tpg->pattern][((x * 8) / tpg->src_width) % 8];
+       case TPG_PAT_100_COLORSQUARES:
+               return bars[1][(pat_line + (x * 8) / tpg->src_width) % 8];
+       case TPG_PAT_100_HCOLORBAR:
+               return bars[1][pat_line];
+       case TPG_PAT_BLACK:
+               return TPG_COLOR_100_BLACK;
+       case TPG_PAT_WHITE:
+               return TPG_COLOR_100_WHITE;
+       case TPG_PAT_RED:
+               return TPG_COLOR_100_RED;
+       case TPG_PAT_GREEN:
+               return TPG_COLOR_100_GREEN;
+       case TPG_PAT_BLUE:
+               return TPG_COLOR_100_BLUE;
+       case TPG_PAT_CHECKERS_16X16:
+               return (((x >> 4) & 1) ^ (pat_line & 1)) ?
+                       TPG_COLOR_100_BLACK : TPG_COLOR_100_WHITE;
+       case TPG_PAT_CHECKERS_1X1:
+               return ((x & 1) ^ (pat_line & 1)) ?
+                       TPG_COLOR_100_WHITE : TPG_COLOR_100_BLACK;
+       case TPG_PAT_ALTERNATING_HLINES:
+               return pat_line ? TPG_COLOR_100_WHITE : TPG_COLOR_100_BLACK;
+       case TPG_PAT_ALTERNATING_VLINES:
+               return (x & 1) ? TPG_COLOR_100_WHITE : TPG_COLOR_100_BLACK;
+       case TPG_PAT_CROSS_1_PIXEL:
+               if (pat_line || (x % tpg->src_width) == tpg->src_width / 2)
+                       return TPG_COLOR_100_BLACK;
+               return TPG_COLOR_100_WHITE;
+       case TPG_PAT_CROSS_2_PIXELS:
+               if (pat_line || ((x % tpg->src_width) + 1) / 2 == tpg->src_width / 4)
+                       return TPG_COLOR_100_BLACK;
+               return TPG_COLOR_100_WHITE;
+       case TPG_PAT_CROSS_10_PIXELS:
+               if (pat_line || ((x % tpg->src_width) + 10) / 20 == tpg->src_width / 40)
+                       return TPG_COLOR_100_BLACK;
+               return TPG_COLOR_100_WHITE;
+       case TPG_PAT_GRAY_RAMP:
+               return TPG_COLOR_RAMP + ((x % tpg->src_width) * 256) / tpg->src_width;
+       default:
+               return TPG_COLOR_100_RED;
+       }
+}
+
+/*
+ * Given the pixel aspect ratio and video aspect ratio calculate the
+ * coordinates of a centered square and the coordinates of the border of
+ * the active video area. The coordinates are relative to the source
+ * frame rectangle.
+ */
+static void tpg_calculate_square_border(struct tpg_data *tpg)
+{
+       unsigned w = tpg->src_width;
+       unsigned h = tpg->src_height;
+       unsigned sq_w, sq_h;
+
+       sq_w = (w * 2 / 5) & ~1;
+       if (((w - sq_w) / 2) & 1)
+               sq_w += 2;
+       sq_h = sq_w;
+       tpg->square.width = sq_w;
+       if (tpg->vid_aspect == TPG_VIDEO_ASPECT_16X9_ANAMORPHIC) {
+               unsigned ana_sq_w = (sq_w / 4) * 3;
+
+               if (((w - ana_sq_w) / 2) & 1)
+                       ana_sq_w += 2;
+               tpg->square.width = ana_sq_w;
+       }
+       tpg->square.left = (w - tpg->square.width) / 2;
+       if (tpg->pix_aspect == TPG_PIXEL_ASPECT_NTSC)
+               sq_h = sq_w * 10 / 11;
+       else if (tpg->pix_aspect == TPG_PIXEL_ASPECT_PAL)
+               sq_h = sq_w * 59 / 54;
+       tpg->square.height = sq_h;
+       tpg->square.top = (h - sq_h) / 2;
+       tpg->border.left = 0;
+       tpg->border.width = w;
+       tpg->border.top = 0;
+       tpg->border.height = h;
+       switch (tpg->vid_aspect) {
+       case TPG_VIDEO_ASPECT_4X3:
+               if (tpg->pix_aspect)
+                       return;
+               if (3 * w >= 4 * h) {
+                       tpg->border.width = ((4 * h) / 3) & ~1;
+                       if (((w - tpg->border.width) / 2) & ~1)
+                               tpg->border.width -= 2;
+                       tpg->border.left = (w - tpg->border.width) / 2;
+                       break;
+               }
+               tpg->border.height = ((3 * w) / 4) & ~1;
+               tpg->border.top = (h - tpg->border.height) / 2;
+               break;
+       case TPG_VIDEO_ASPECT_14X9_CENTRE:
+               if (tpg->pix_aspect) {
+                       tpg->border.height = tpg->pix_aspect == TPG_PIXEL_ASPECT_NTSC ? 420 : 506;
+                       tpg->border.top = (h - tpg->border.height) / 2;
+                       break;
+               }
+               if (9 * w >= 14 * h) {
+                       tpg->border.width = ((14 * h) / 9) & ~1;
+                       if (((w - tpg->border.width) / 2) & ~1)
+                               tpg->border.width -= 2;
+                       tpg->border.left = (w - tpg->border.width) / 2;
+                       break;
+               }
+               tpg->border.height = ((9 * w) / 14) & ~1;
+               tpg->border.top = (h - tpg->border.height) / 2;
+               break;
+       case TPG_VIDEO_ASPECT_16X9_CENTRE:
+               if (tpg->pix_aspect) {
+                       tpg->border.height = tpg->pix_aspect == TPG_PIXEL_ASPECT_NTSC ? 368 : 442;
+                       tpg->border.top = (h - tpg->border.height) / 2;
+                       break;
+               }
+               if (9 * w >= 16 * h) {
+                       tpg->border.width = ((16 * h) / 9) & ~1;
+                       if (((w - tpg->border.width) / 2) & ~1)
+                               tpg->border.width -= 2;
+                       tpg->border.left = (w - tpg->border.width) / 2;
+                       break;
+               }
+               tpg->border.height = ((9 * w) / 16) & ~1;
+               tpg->border.top = (h - tpg->border.height) / 2;
+               break;
+       default:
+               break;
+       }
+}
+
+static void tpg_precalculate_line(struct tpg_data *tpg)
+{
+       enum tpg_color contrast;
+       unsigned pat;
+       unsigned p;
+       unsigned x;
+
+       switch (tpg->pattern) {
+       case TPG_PAT_GREEN:
+               contrast = TPG_COLOR_100_RED;
+               break;
+       case TPG_PAT_CSC_COLORBAR:
+               contrast = TPG_COLOR_CSC_GREEN;
+               break;
+       default:
+               contrast = TPG_COLOR_100_GREEN;
+               break;
+       }
+
+       for (pat = 0; pat < tpg_get_pat_lines(tpg); pat++) {
+               /* Coarse scaling with Bresenham */
+               unsigned int_part = tpg->src_width / tpg->scaled_width;
+               unsigned fract_part = tpg->src_width % tpg->scaled_width;
+               unsigned src_x = 0;
+               unsigned error = 0;
+
+               for (x = 0; x < tpg->scaled_width * 2; x += 2) {
+                       unsigned real_x = src_x;
+                       enum tpg_color color1, color2;
+                       u8 pix[TPG_MAX_PLANES][8];
+
+                       real_x = tpg->hflip ? tpg->src_width * 2 - real_x - 2 : real_x;
+                       color1 = tpg_get_color(tpg, pat, real_x);
+
+                       src_x += int_part;
+                       error += fract_part;
+                       if (error >= tpg->scaled_width) {
+                               error -= tpg->scaled_width;
+                               src_x++;
+                       }
+
+                       real_x = src_x;
+                       real_x = tpg->hflip ? tpg->src_width * 2 - real_x - 2 : real_x;
+                       color2 = tpg_get_color(tpg, pat, real_x);
+
+                       src_x += int_part;
+                       error += fract_part;
+                       if (error >= tpg->scaled_width) {
+                               error -= tpg->scaled_width;
+                               src_x++;
+                       }
+
+                       gen_twopix(tpg, pix, tpg->hflip ? color2 : color1, 0);
+                       gen_twopix(tpg, pix, tpg->hflip ? color1 : color2, 1);
+                       for (p = 0; p < tpg->planes; p++) {
+                               unsigned twopixsize = tpg->twopixelsize[p];
+                               u8 *pos = tpg->lines[pat][p] + x * twopixsize / 2;
+
+                               memcpy(pos, pix[p], twopixsize);
+                       }
+               }
+       }
+       for (x = 0; x < tpg->scaled_width; x += 2) {
+               u8 pix[TPG_MAX_PLANES][8];
+
+               gen_twopix(tpg, pix, contrast, 0);
+               gen_twopix(tpg, pix, contrast, 1);
+               for (p = 0; p < tpg->planes; p++) {
+                       unsigned twopixsize = tpg->twopixelsize[p];
+                       u8 *pos = tpg->contrast_line[p] + x * twopixsize / 2;
+
+                       memcpy(pos, pix[p], twopixsize);
+               }
+       }
+       for (x = 0; x < tpg->scaled_width; x += 2) {
+               u8 pix[TPG_MAX_PLANES][8];
+
+               gen_twopix(tpg, pix, TPG_COLOR_100_BLACK, 0);
+               gen_twopix(tpg, pix, TPG_COLOR_100_BLACK, 1);
+               for (p = 0; p < tpg->planes; p++) {
+                       unsigned twopixsize = tpg->twopixelsize[p];
+                       u8 *pos = tpg->black_line[p] + x * twopixsize / 2;
+
+                       memcpy(pos, pix[p], twopixsize);
+               }
+       }
+       for (x = 0; x < tpg->scaled_width * 2; x += 2) {
+               u8 pix[TPG_MAX_PLANES][8];
+
+               gen_twopix(tpg, pix, TPG_COLOR_RANDOM, 0);
+               gen_twopix(tpg, pix, TPG_COLOR_RANDOM, 1);
+               for (p = 0; p < tpg->planes; p++) {
+                       unsigned twopixsize = tpg->twopixelsize[p];
+                       u8 *pos = tpg->random_line[p] + x * twopixsize / 2;
+
+                       memcpy(pos, pix[p], twopixsize);
+               }
+       }
+       gen_twopix(tpg, tpg->textbg, TPG_COLOR_TEXTBG, 0);
+       gen_twopix(tpg, tpg->textbg, TPG_COLOR_TEXTBG, 1);
+       gen_twopix(tpg, tpg->textfg, TPG_COLOR_TEXTFG, 0);
+       gen_twopix(tpg, tpg->textfg, TPG_COLOR_TEXTFG, 1);
+}
+
+/* need this to do rgb24 rendering */
+typedef struct { u16 __; u8 _; } __packed x24;
+
+void tpg_gen_text(struct tpg_data *tpg, u8 *basep[TPG_MAX_PLANES][2],
+               int y, int x, char *text)
+{
+       int line;
+       unsigned step = V4L2_FIELD_HAS_T_OR_B(tpg->field) ? 2 : 1;
+       unsigned div = step;
+       unsigned first = 0;
+       unsigned len = strlen(text);
+       unsigned p;
+
+       if (font8x16 == NULL || basep == NULL)
+               return;
+
+       /* Checks if it is possible to show string */
+       if (y + 16 >= tpg->compose.height || x + 8 >= tpg->compose.width)
+               return;
+
+       if (len > (tpg->compose.width - x) / 8)
+               len = (tpg->compose.width - x) / 8;
+       if (tpg->vflip)
+               y = tpg->compose.height - y - 16;
+       if (tpg->hflip)
+               x = tpg->compose.width - x - 8;
+       y += tpg->compose.top;
+       x += tpg->compose.left;
+       if (tpg->field == V4L2_FIELD_BOTTOM)
+               first = 1;
+       else if (tpg->field == V4L2_FIELD_SEQ_TB || tpg->field == V4L2_FIELD_SEQ_BT)
+               div = 2;
+
+       for (p = 0; p < tpg->planes; p++) {
+               /* Print stream time */
+#define PRINTSTR(PIXTYPE) do { \
+       PIXTYPE fg;     \
+       PIXTYPE bg;     \
+       memcpy(&fg, tpg->textfg[p], sizeof(PIXTYPE));   \
+       memcpy(&bg, tpg->textbg[p], sizeof(PIXTYPE));   \
+       \
+       for (line = first; line < 16; line += step) {   \
+               int l = tpg->vflip ? 15 - line : line; \
+               PIXTYPE *pos = (PIXTYPE *)(basep[p][line & 1] + \
+                              ((y * step + l) / div) * tpg->bytesperline[p] + \
+                              x * sizeof(PIXTYPE));    \
+               unsigned s;     \
+       \
+               for (s = 0; s < len; s++) {     \
+                       u8 chr = font8x16[text[s] * 16 + line]; \
+       \
+                       if (tpg->hflip) { \
+                               pos[7] = (chr & (0x01 << 7) ? fg : bg); \
+                               pos[6] = (chr & (0x01 << 6) ? fg : bg); \
+                               pos[5] = (chr & (0x01 << 5) ? fg : bg); \
+                               pos[4] = (chr & (0x01 << 4) ? fg : bg); \
+                               pos[3] = (chr & (0x01 << 3) ? fg : bg); \
+                               pos[2] = (chr & (0x01 << 2) ? fg : bg); \
+                               pos[1] = (chr & (0x01 << 1) ? fg : bg); \
+                               pos[0] = (chr & (0x01 << 0) ? fg : bg); \
+                       } else { \
+                               pos[0] = (chr & (0x01 << 7) ? fg : bg); \
+                               pos[1] = (chr & (0x01 << 6) ? fg : bg); \
+                               pos[2] = (chr & (0x01 << 5) ? fg : bg); \
+                               pos[3] = (chr & (0x01 << 4) ? fg : bg); \
+                               pos[4] = (chr & (0x01 << 3) ? fg : bg); \
+                               pos[5] = (chr & (0x01 << 2) ? fg : bg); \
+                               pos[6] = (chr & (0x01 << 1) ? fg : bg); \
+                               pos[7] = (chr & (0x01 << 0) ? fg : bg); \
+                       } \
+       \
+                       pos += tpg->hflip ? -8 : 8;     \
+               }       \
+       }       \
+} while (0)
+
+               switch (tpg->twopixelsize[p]) {
+               case 2:
+                       PRINTSTR(u8); break;
+               case 4:
+                       PRINTSTR(u16); break;
+               case 6:
+                       PRINTSTR(x24); break;
+               case 8:
+                       PRINTSTR(u32); break;
+               }
+       }
+}
+
+void tpg_update_mv_step(struct tpg_data *tpg)
+{
+       int factor = tpg->mv_hor_mode > TPG_MOVE_NONE ? -1 : 1;
+
+       if (tpg->hflip)
+               factor = -factor;
+       switch (tpg->mv_hor_mode) {
+       case TPG_MOVE_NEG_FAST:
+       case TPG_MOVE_POS_FAST:
+               tpg->mv_hor_step = ((tpg->src_width + 319) / 320) * 4;
+               break;
+       case TPG_MOVE_NEG:
+       case TPG_MOVE_POS:
+               tpg->mv_hor_step = ((tpg->src_width + 639) / 640) * 4;
+               break;
+       case TPG_MOVE_NEG_SLOW:
+       case TPG_MOVE_POS_SLOW:
+               tpg->mv_hor_step = 2;
+               break;
+       case TPG_MOVE_NONE:
+               tpg->mv_hor_step = 0;
+               break;
+       }
+       if (factor < 0)
+               tpg->mv_hor_step = tpg->src_width - tpg->mv_hor_step;
+
+       factor = tpg->mv_vert_mode > TPG_MOVE_NONE ? -1 : 1;
+       switch (tpg->mv_vert_mode) {
+       case TPG_MOVE_NEG_FAST:
+       case TPG_MOVE_POS_FAST:
+               tpg->mv_vert_step = ((tpg->src_width + 319) / 320) * 4;
+               break;
+       case TPG_MOVE_NEG:
+       case TPG_MOVE_POS:
+               tpg->mv_vert_step = ((tpg->src_width + 639) / 640) * 4;
+               break;
+       case TPG_MOVE_NEG_SLOW:
+       case TPG_MOVE_POS_SLOW:
+               tpg->mv_vert_step = 1;
+               break;
+       case TPG_MOVE_NONE:
+               tpg->mv_vert_step = 0;
+               break;
+       }
+       if (factor < 0)
+               tpg->mv_vert_step = tpg->src_height - tpg->mv_vert_step;
+}
+
+/* Map the line number relative to the crop rectangle to a frame line number */
+static unsigned tpg_calc_frameline(struct tpg_data *tpg, unsigned src_y,
+                                   unsigned field)
+{
+       switch (field) {
+       case V4L2_FIELD_TOP:
+               return tpg->crop.top + src_y * 2;
+       case V4L2_FIELD_BOTTOM:
+               return tpg->crop.top + src_y * 2 + 1;
+       default:
+               return src_y + tpg->crop.top;
+       }
+}
+
+/*
+ * Map the line number relative to the compose rectangle to a destination
+ * buffer line number.
+ */
+static unsigned tpg_calc_buffer_line(struct tpg_data *tpg, unsigned y,
+                                   unsigned field)
+{
+       y += tpg->compose.top;
+       switch (field) {
+       case V4L2_FIELD_SEQ_TB:
+               if (y & 1)
+                       return tpg->buf_height / 2 + y / 2;
+               return y / 2;
+       case V4L2_FIELD_SEQ_BT:
+               if (y & 1)
+                       return y / 2;
+               return tpg->buf_height / 2 + y / 2;
+       default:
+               return y;
+       }
+}
+
+static void tpg_recalc(struct tpg_data *tpg)
+{
+       if (tpg->recalc_colors) {
+               tpg->recalc_colors = false;
+               tpg->recalc_lines = true;
+               tpg_precalculate_colors(tpg);
+       }
+       if (tpg->recalc_square_border) {
+               tpg->recalc_square_border = false;
+               tpg_calculate_square_border(tpg);
+       }
+       if (tpg->recalc_lines) {
+               tpg->recalc_lines = false;
+               tpg_precalculate_line(tpg);
+       }
+}
+
+void tpg_calc_text_basep(struct tpg_data *tpg,
+               u8 *basep[TPG_MAX_PLANES][2], unsigned p, u8 *vbuf)
+{
+       unsigned stride = tpg->bytesperline[p];
+
+       tpg_recalc(tpg);
+
+       basep[p][0] = vbuf;
+       basep[p][1] = vbuf;
+       if (tpg->field == V4L2_FIELD_SEQ_TB)
+               basep[p][1] += tpg->buf_height * stride / 2;
+       else if (tpg->field == V4L2_FIELD_SEQ_BT)
+               basep[p][0] += tpg->buf_height * stride / 2;
+}
+
+void tpg_fillbuffer(struct tpg_data *tpg, v4l2_std_id std, unsigned p, u8 *vbuf)
+{
+       bool is_tv = std;
+       bool is_60hz = is_tv && (std & V4L2_STD_525_60);
+       unsigned mv_hor_old = tpg->mv_hor_count % tpg->src_width;
+       unsigned mv_hor_new = (tpg->mv_hor_count + tpg->mv_hor_step) % tpg->src_width;
+       unsigned mv_vert_old = tpg->mv_vert_count % tpg->src_height;
+       unsigned mv_vert_new = (tpg->mv_vert_count + tpg->mv_vert_step) % tpg->src_height;
+       unsigned wss_width;
+       unsigned f;
+       int hmax = (tpg->compose.height * tpg->perc_fill) / 100;
+       int h;
+       unsigned twopixsize = tpg->twopixelsize[p];
+       unsigned img_width = tpg->compose.width * twopixsize / 2;
+       unsigned line_offset;
+       unsigned left_pillar_width = 0;
+       unsigned right_pillar_start = img_width;
+       unsigned stride = tpg->bytesperline[p];
+       unsigned factor = V4L2_FIELD_HAS_T_OR_B(tpg->field) ? 2 : 1;
+       u8 *orig_vbuf = vbuf;
+
+       /* Coarse scaling with Bresenham */
+       unsigned int_part = (tpg->crop.height / factor) / tpg->compose.height;
+       unsigned fract_part = (tpg->crop.height / factor) % tpg->compose.height;
+       unsigned src_y = 0;
+       unsigned error = 0;
+
+       tpg_recalc(tpg);
+
+       mv_hor_old = (mv_hor_old * tpg->scaled_width / tpg->src_width) & ~1;
+       mv_hor_new = (mv_hor_new * tpg->scaled_width / tpg->src_width) & ~1;
+       wss_width = tpg->crop.left < tpg->src_width / 2 ?
+                       tpg->src_width / 2 - tpg->crop.left : 0;
+       if (wss_width > tpg->crop.width)
+               wss_width = tpg->crop.width;
+       wss_width = wss_width * tpg->scaled_width / tpg->src_width;
+
+       vbuf += tpg->compose.left * twopixsize / 2;
+       line_offset = tpg->crop.left * tpg->scaled_width / tpg->src_width;
+       line_offset = (line_offset & ~1) * twopixsize / 2;
+       if (tpg->crop.left < tpg->border.left) {
+               left_pillar_width = tpg->border.left - tpg->crop.left;
+               if (left_pillar_width > tpg->crop.width)
+                       left_pillar_width = tpg->crop.width;
+               left_pillar_width = (left_pillar_width * tpg->scaled_width) / tpg->src_width;
+               left_pillar_width = (left_pillar_width & ~1) * twopixsize / 2;
+       }
+       if (tpg->crop.left + tpg->crop.width > tpg->border.left + tpg->border.width) {
+               right_pillar_start = tpg->border.left + tpg->border.width - tpg->crop.left;
+               right_pillar_start = (right_pillar_start * tpg->scaled_width) / tpg->src_width;
+               right_pillar_start = (right_pillar_start & ~1) * twopixsize / 2;
+               if (right_pillar_start > img_width)
+                       right_pillar_start = img_width;
+       }
+
+       f = tpg->field == (is_60hz ? V4L2_FIELD_TOP : V4L2_FIELD_BOTTOM);
+
+       for (h = 0; h < tpg->compose.height; h++) {
+               bool even;
+               bool fill_blank = false;
+               unsigned frame_line;
+               unsigned buf_line;
+               unsigned pat_line_old;
+               unsigned pat_line_new;
+               u8 *linestart_older;
+               u8 *linestart_newer;
+               u8 *linestart_top;
+               u8 *linestart_bottom;
+
+               frame_line = tpg_calc_frameline(tpg, src_y, tpg->field);
+               even = !(frame_line & 1);
+               buf_line = tpg_calc_buffer_line(tpg, h, tpg->field);
+               src_y += int_part;
+               error += fract_part;
+               if (error >= tpg->compose.height) {
+                       error -= tpg->compose.height;
+                       src_y++;
+               }
+
+               if (h >= hmax) {
+                       if (hmax == tpg->compose.height)
+                               continue;
+                       if (!tpg->perc_fill_blank)
+                               continue;
+                       fill_blank = true;
+               }
+
+               if (tpg->vflip)
+                       frame_line = tpg->src_height - frame_line - 1;
+
+               if (fill_blank) {
+                       linestart_older = tpg->contrast_line[p];
+                       linestart_newer = tpg->contrast_line[p];
+               } else if (tpg->qual != TPG_QUAL_NOISE &&
+                          (frame_line < tpg->border.top ||
+                           frame_line >= tpg->border.top + tpg->border.height)) {
+                       linestart_older = tpg->black_line[p];
+                       linestart_newer = tpg->black_line[p];
+               } else if (tpg->pattern == TPG_PAT_NOISE || tpg->qual == TPG_QUAL_NOISE) {
+                       linestart_older = tpg->random_line[p] +
+                                         twopixsize * prandom_u32_max(tpg->src_width / 2);
+                       linestart_newer = tpg->random_line[p] +
+                                         twopixsize * prandom_u32_max(tpg->src_width / 2);
+               } else {
+                       pat_line_old = tpg_get_pat_line(tpg,
+                                               (frame_line + mv_vert_old) % tpg->src_height);
+                       pat_line_new = tpg_get_pat_line(tpg,
+                                               (frame_line + mv_vert_new) % tpg->src_height);
+                       linestart_older = tpg->lines[pat_line_old][p] +
+                                         mv_hor_old * twopixsize / 2;
+                       linestart_newer = tpg->lines[pat_line_new][p] +
+                                         mv_hor_new * twopixsize / 2;
+                       linestart_older += line_offset;
+                       linestart_newer += line_offset;
+               }
+               if (is_60hz) {
+                       linestart_top = linestart_newer;
+                       linestart_bottom = linestart_older;
+               } else {
+                       linestart_top = linestart_older;
+                       linestart_bottom = linestart_newer;
+               }
+
+               switch (tpg->field) {
+               case V4L2_FIELD_INTERLACED:
+               case V4L2_FIELD_INTERLACED_TB:
+               case V4L2_FIELD_SEQ_TB:
+               case V4L2_FIELD_SEQ_BT:
+                       if (even)
+                               memcpy(vbuf + buf_line * stride, linestart_top, img_width);
+                       else
+                               memcpy(vbuf + buf_line * stride, linestart_bottom, img_width);
+                       break;
+               case V4L2_FIELD_INTERLACED_BT:
+                       if (even)
+                               memcpy(vbuf + buf_line * stride, linestart_bottom, img_width);
+                       else
+                               memcpy(vbuf + buf_line * stride, linestart_top, img_width);
+                       break;
+               case V4L2_FIELD_TOP:
+                       memcpy(vbuf + buf_line * stride, linestart_top, img_width);
+                       break;
+               case V4L2_FIELD_BOTTOM:
+                       memcpy(vbuf + buf_line * stride, linestart_bottom, img_width);
+                       break;
+               case V4L2_FIELD_NONE:
+               default:
+                       memcpy(vbuf + buf_line * stride, linestart_older, img_width);
+                       break;
+               }
+
+               if (is_tv && !is_60hz && frame_line == 0 && wss_width) {
+                       /*
+                        * Replace the first half of the top line of a 50 Hz frame
+                        * with random data to simulate a WSS signal.
+                        */
+                       u8 *wss = tpg->random_line[p] +
+                                 twopixsize * prandom_u32_max(tpg->src_width / 2);
+
+                       memcpy(vbuf + buf_line * stride, wss, wss_width * twopixsize / 2);
+               }
+       }
+
+       vbuf = orig_vbuf;
+       vbuf += tpg->compose.left * twopixsize / 2;
+       src_y = 0;
+       error = 0;
+       for (h = 0; h < tpg->compose.height; h++) {
+               unsigned frame_line = tpg_calc_frameline(tpg, src_y, tpg->field);
+               unsigned buf_line = tpg_calc_buffer_line(tpg, h, tpg->field);
+               const struct v4l2_rect *sq = &tpg->square;
+               const struct v4l2_rect *b = &tpg->border;
+               const struct v4l2_rect *c = &tpg->crop;
+
+               src_y += int_part;
+               error += fract_part;
+               if (error >= tpg->compose.height) {
+                       error -= tpg->compose.height;
+                       src_y++;
+               }
+
+               if (tpg->show_border && frame_line >= b->top &&
+                   frame_line < b->top + b->height) {
+                       unsigned bottom = b->top + b->height - 1;
+                       unsigned left = left_pillar_width;
+                       unsigned right = right_pillar_start;
+
+                       if (frame_line == b->top || frame_line == b->top + 1 ||
+                           frame_line == bottom || frame_line == bottom - 1) {
+                               memcpy(vbuf + buf_line * stride + left, tpg->contrast_line[p],
+                                               right - left);
+                       } else {
+                               if (b->left >= c->left &&
+                                   b->left < c->left + c->width)
+                                       memcpy(vbuf + buf_line * stride + left,
+                                               tpg->contrast_line[p], twopixsize);
+                               if (b->left + b->width > c->left &&
+                                   b->left + b->width <= c->left + c->width)
+                                       memcpy(vbuf + buf_line * stride + right - twopixsize,
+                                               tpg->contrast_line[p], twopixsize);
+                       }
+               }
+               if (tpg->qual != TPG_QUAL_NOISE && frame_line >= b->top &&
+                   frame_line < b->top + b->height) {
+                       memcpy(vbuf + buf_line * stride, tpg->black_line[p], left_pillar_width);
+                       memcpy(vbuf + buf_line * stride + right_pillar_start, tpg->black_line[p],
+                              img_width - right_pillar_start);
+               }
+               if (tpg->show_square && frame_line >= sq->top &&
+                   frame_line < sq->top + sq->height &&
+                   sq->left < c->left + c->width &&
+                   sq->left + sq->width >= c->left) {
+                       unsigned left = sq->left;
+                       unsigned width = sq->width;
+
+                       if (c->left > left) {
+                               width -= c->left - left;
+                               left = c->left;
+                       }
+                       if (c->left + c->width < left + width)
+                               width -= left + width - c->left - c->width;
+                       left -= c->left;
+                       left = (left * tpg->scaled_width) / tpg->src_width;
+                       left = (left & ~1) * twopixsize / 2;
+                       width = (width * tpg->scaled_width) / tpg->src_width;
+                       width = (width & ~1) * twopixsize / 2;
+                       memcpy(vbuf + buf_line * stride + left, tpg->contrast_line[p], width);
+               }
+               if (tpg->insert_sav) {
+                       unsigned offset = (tpg->compose.width / 6) * twopixsize;
+                       u8 *p = vbuf + buf_line * stride + offset;
+                       unsigned vact = 0, hact = 0;
+
+                       p[0] = 0xff;
+                       p[1] = 0;
+                       p[2] = 0;
+                       p[3] = 0x80 | (f << 6) | (vact << 5) | (hact << 4) |
+                               ((hact ^ vact) << 3) |
+                               ((hact ^ f) << 2) |
+                               ((f ^ vact) << 1) |
+                               (hact ^ vact ^ f);
+               }
+               if (tpg->insert_eav) {
+                       unsigned offset = (tpg->compose.width / 6) * 2 * twopixsize;
+                       u8 *p = vbuf + buf_line * stride + offset;
+                       unsigned vact = 0, hact = 1;
+
+                       p[0] = 0xff;
+                       p[1] = 0;
+                       p[2] = 0;
+                       p[3] = 0x80 | (f << 6) | (vact << 5) | (hact << 4) |
+                               ((hact ^ vact) << 3) |
+                               ((hact ^ f) << 2) |
+                               ((f ^ vact) << 1) |
+                               (hact ^ vact ^ f);
+               }
+       }
+}
diff --git a/drivers/media/platform/vivid/vivid-tpg.h b/drivers/media/platform/vivid/vivid-tpg.h
new file mode 100644 (file)
index 0000000..8ef3e52
--- /dev/null
@@ -0,0 +1,439 @@
+/*
+ * vivid-tpg.h - Test Pattern Generator
+ *
+ * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
+ *
+ * This program is free software; you may redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * 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 _VIVID_TPG_H_
+#define _VIVID_TPG_H_
+
+#include <linux/version.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/random.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+#include <linux/videodev2.h>
+
+#include "vivid-tpg-colors.h"
+
+enum tpg_pattern {
+       TPG_PAT_75_COLORBAR,
+       TPG_PAT_100_COLORBAR,
+       TPG_PAT_CSC_COLORBAR,
+       TPG_PAT_100_HCOLORBAR,
+       TPG_PAT_100_COLORSQUARES,
+       TPG_PAT_BLACK,
+       TPG_PAT_WHITE,
+       TPG_PAT_RED,
+       TPG_PAT_GREEN,
+       TPG_PAT_BLUE,
+       TPG_PAT_CHECKERS_16X16,
+       TPG_PAT_CHECKERS_1X1,
+       TPG_PAT_ALTERNATING_HLINES,
+       TPG_PAT_ALTERNATING_VLINES,
+       TPG_PAT_CROSS_1_PIXEL,
+       TPG_PAT_CROSS_2_PIXELS,
+       TPG_PAT_CROSS_10_PIXELS,
+       TPG_PAT_GRAY_RAMP,
+
+       /* Must be the last pattern */
+       TPG_PAT_NOISE,
+};
+
+extern const char * const tpg_pattern_strings[];
+
+enum tpg_quality {
+       TPG_QUAL_COLOR,
+       TPG_QUAL_GRAY,
+       TPG_QUAL_NOISE
+};
+
+enum tpg_video_aspect {
+       TPG_VIDEO_ASPECT_IMAGE,
+       TPG_VIDEO_ASPECT_4X3,
+       TPG_VIDEO_ASPECT_14X9_CENTRE,
+       TPG_VIDEO_ASPECT_16X9_CENTRE,
+       TPG_VIDEO_ASPECT_16X9_ANAMORPHIC,
+};
+
+enum tpg_pixel_aspect {
+       TPG_PIXEL_ASPECT_SQUARE,
+       TPG_PIXEL_ASPECT_NTSC,
+       TPG_PIXEL_ASPECT_PAL,
+};
+
+enum tpg_move_mode {
+       TPG_MOVE_NEG_FAST,
+       TPG_MOVE_NEG,
+       TPG_MOVE_NEG_SLOW,
+       TPG_MOVE_NONE,
+       TPG_MOVE_POS_SLOW,
+       TPG_MOVE_POS,
+       TPG_MOVE_POS_FAST,
+};
+
+extern const char * const tpg_aspect_strings[];
+
+#define TPG_MAX_PLANES 2
+#define TPG_MAX_PAT_LINES 8
+
+struct tpg_data {
+       /* Source frame size */
+       unsigned                        src_width, src_height;
+       /* Buffer height */
+       unsigned                        buf_height;
+       /* Scaled output frame size */
+       unsigned                        scaled_width;
+       u32                             field;
+       /* crop coordinates are frame-based */
+       struct v4l2_rect                crop;
+       /* compose coordinates are format-based */
+       struct v4l2_rect                compose;
+       /* border and square coordinates are frame-based */
+       struct v4l2_rect                border;
+       struct v4l2_rect                square;
+
+       /* Color-related fields */
+       enum tpg_quality                qual;
+       unsigned                        qual_offset;
+       u8                              alpha_component;
+       bool                            alpha_red_only;
+       u8                              brightness;
+       u8                              contrast;
+       u8                              saturation;
+       s16                             hue;
+       u32                             fourcc;
+       bool                            is_yuv;
+       u32                             colorspace;
+       enum tpg_video_aspect           vid_aspect;
+       enum tpg_pixel_aspect           pix_aspect;
+       unsigned                        rgb_range;
+       unsigned                        real_rgb_range;
+       unsigned                        planes;
+       /* Used to store the colors in native format, either RGB or YUV */
+       u8                              colors[TPG_COLOR_MAX][3];
+       u8                              textfg[TPG_MAX_PLANES][8], textbg[TPG_MAX_PLANES][8];
+       /* size in bytes for two pixels in each plane */
+       unsigned                        twopixelsize[TPG_MAX_PLANES];
+       unsigned                        bytesperline[TPG_MAX_PLANES];
+
+       /* Configuration */
+       enum tpg_pattern                pattern;
+       bool                            hflip;
+       bool                            vflip;
+       unsigned                        perc_fill;
+       bool                            perc_fill_blank;
+       bool                            show_border;
+       bool                            show_square;
+       bool                            insert_sav;
+       bool                            insert_eav;
+
+       /* Test pattern movement */
+       enum tpg_move_mode              mv_hor_mode;
+       int                             mv_hor_count;
+       int                             mv_hor_step;
+       enum tpg_move_mode              mv_vert_mode;
+       int                             mv_vert_count;
+       int                             mv_vert_step;
+
+       bool                            recalc_colors;
+       bool                            recalc_lines;
+       bool                            recalc_square_border;
+
+       /* Used to store TPG_MAX_PAT_LINES lines, each with up to two planes */
+       unsigned                        max_line_width;
+       u8                              *lines[TPG_MAX_PAT_LINES][TPG_MAX_PLANES];
+       u8                              *random_line[TPG_MAX_PLANES];
+       u8                              *contrast_line[TPG_MAX_PLANES];
+       u8                              *black_line[TPG_MAX_PLANES];
+};
+
+void tpg_init(struct tpg_data *tpg, unsigned w, unsigned h);
+int tpg_alloc(struct tpg_data *tpg, unsigned max_w);
+void tpg_free(struct tpg_data *tpg);
+void tpg_reset_source(struct tpg_data *tpg, unsigned width, unsigned height,
+                      u32 field);
+
+void tpg_set_font(const u8 *f);
+void tpg_gen_text(struct tpg_data *tpg,
+               u8 *basep[TPG_MAX_PLANES][2], int y, int x, char *text);
+void tpg_calc_text_basep(struct tpg_data *tpg,
+               u8 *basep[TPG_MAX_PLANES][2], unsigned p, u8 *vbuf);
+void tpg_fillbuffer(struct tpg_data *tpg, v4l2_std_id std, unsigned p, u8 *vbuf);
+bool tpg_s_fourcc(struct tpg_data *tpg, u32 fourcc);
+void tpg_s_crop_compose(struct tpg_data *tpg, const struct v4l2_rect *crop,
+               const struct v4l2_rect *compose);
+
+static inline void tpg_s_pattern(struct tpg_data *tpg, enum tpg_pattern pattern)
+{
+       if (tpg->pattern == pattern)
+               return;
+       tpg->pattern = pattern;
+       tpg->recalc_colors = true;
+}
+
+static inline void tpg_s_quality(struct tpg_data *tpg,
+                                   enum tpg_quality qual, unsigned qual_offset)
+{
+       if (tpg->qual == qual && tpg->qual_offset == qual_offset)
+               return;
+       tpg->qual = qual;
+       tpg->qual_offset = qual_offset;
+       tpg->recalc_colors = true;
+}
+
+static inline enum tpg_quality tpg_g_quality(const struct tpg_data *tpg)
+{
+       return tpg->qual;
+}
+
+static inline void tpg_s_alpha_component(struct tpg_data *tpg,
+                                           u8 alpha_component)
+{
+       if (tpg->alpha_component == alpha_component)
+               return;
+       tpg->alpha_component = alpha_component;
+       tpg->recalc_colors = true;
+}
+
+static inline void tpg_s_alpha_mode(struct tpg_data *tpg,
+                                           bool red_only)
+{
+       if (tpg->alpha_red_only == red_only)
+               return;
+       tpg->alpha_red_only = red_only;
+       tpg->recalc_colors = true;
+}
+
+static inline void tpg_s_brightness(struct tpg_data *tpg,
+                                       u8 brightness)
+{
+       if (tpg->brightness == brightness)
+               return;
+       tpg->brightness = brightness;
+       tpg->recalc_colors = true;
+}
+
+static inline void tpg_s_contrast(struct tpg_data *tpg,
+                                       u8 contrast)
+{
+       if (tpg->contrast == contrast)
+               return;
+       tpg->contrast = contrast;
+       tpg->recalc_colors = true;
+}
+
+static inline void tpg_s_saturation(struct tpg_data *tpg,
+                                       u8 saturation)
+{
+       if (tpg->saturation == saturation)
+               return;
+       tpg->saturation = saturation;
+       tpg->recalc_colors = true;
+}
+
+static inline void tpg_s_hue(struct tpg_data *tpg,
+                                       s16 hue)
+{
+       if (tpg->hue == hue)
+               return;
+       tpg->hue = hue;
+       tpg->recalc_colors = true;
+}
+
+static inline void tpg_s_rgb_range(struct tpg_data *tpg,
+                                       unsigned rgb_range)
+{
+       if (tpg->rgb_range == rgb_range)
+               return;
+       tpg->rgb_range = rgb_range;
+       tpg->recalc_colors = true;
+}
+
+static inline void tpg_s_real_rgb_range(struct tpg_data *tpg,
+                                       unsigned rgb_range)
+{
+       if (tpg->real_rgb_range == rgb_range)
+               return;
+       tpg->real_rgb_range = rgb_range;
+       tpg->recalc_colors = true;
+}
+
+static inline void tpg_s_colorspace(struct tpg_data *tpg, u32 colorspace)
+{
+       if (tpg->colorspace == colorspace)
+               return;
+       tpg->colorspace = colorspace;
+       tpg->recalc_colors = true;
+}
+
+static inline u32 tpg_g_colorspace(const struct tpg_data *tpg)
+{
+       return tpg->colorspace;
+}
+
+static inline unsigned tpg_g_planes(const struct tpg_data *tpg)
+{
+       return tpg->planes;
+}
+
+static inline unsigned tpg_g_twopixelsize(const struct tpg_data *tpg, unsigned plane)
+{
+       return tpg->twopixelsize[plane];
+}
+
+static inline unsigned tpg_g_bytesperline(const struct tpg_data *tpg, unsigned plane)
+{
+       return tpg->bytesperline[plane];
+}
+
+static inline void tpg_s_bytesperline(struct tpg_data *tpg, unsigned plane, unsigned bpl)
+{
+       tpg->bytesperline[plane] = bpl;
+}
+
+static inline void tpg_s_buf_height(struct tpg_data *tpg, unsigned h)
+{
+       tpg->buf_height = h;
+}
+
+static inline void tpg_s_field(struct tpg_data *tpg, unsigned field)
+{
+       tpg->field = field;
+}
+
+static inline void tpg_s_perc_fill(struct tpg_data *tpg,
+                                     unsigned perc_fill)
+{
+       tpg->perc_fill = perc_fill;
+}
+
+static inline unsigned tpg_g_perc_fill(const struct tpg_data *tpg)
+{
+       return tpg->perc_fill;
+}
+
+static inline void tpg_s_perc_fill_blank(struct tpg_data *tpg,
+                                        bool perc_fill_blank)
+{
+       tpg->perc_fill_blank = perc_fill_blank;
+}
+
+static inline void tpg_s_video_aspect(struct tpg_data *tpg,
+                                       enum tpg_video_aspect vid_aspect)
+{
+       if (tpg->vid_aspect == vid_aspect)
+               return;
+       tpg->vid_aspect = vid_aspect;
+       tpg->recalc_square_border = true;
+}
+
+static inline enum tpg_video_aspect tpg_g_video_aspect(const struct tpg_data *tpg)
+{
+       return tpg->vid_aspect;
+}
+
+static inline void tpg_s_pixel_aspect(struct tpg_data *tpg,
+                                       enum tpg_pixel_aspect pix_aspect)
+{
+       if (tpg->pix_aspect == pix_aspect)
+               return;
+       tpg->pix_aspect = pix_aspect;
+       tpg->recalc_square_border = true;
+}
+
+static inline void tpg_s_show_border(struct tpg_data *tpg,
+                                       bool show_border)
+{
+       tpg->show_border = show_border;
+}
+
+static inline void tpg_s_show_square(struct tpg_data *tpg,
+                                       bool show_square)
+{
+       tpg->show_square = show_square;
+}
+
+static inline void tpg_s_insert_sav(struct tpg_data *tpg, bool insert_sav)
+{
+       tpg->insert_sav = insert_sav;
+}
+
+static inline void tpg_s_insert_eav(struct tpg_data *tpg, bool insert_eav)
+{
+       tpg->insert_eav = insert_eav;
+}
+
+void tpg_update_mv_step(struct tpg_data *tpg);
+
+static inline void tpg_s_mv_hor_mode(struct tpg_data *tpg,
+                               enum tpg_move_mode mv_hor_mode)
+{
+       tpg->mv_hor_mode = mv_hor_mode;
+       tpg_update_mv_step(tpg);
+}
+
+static inline void tpg_s_mv_vert_mode(struct tpg_data *tpg,
+                               enum tpg_move_mode mv_vert_mode)
+{
+       tpg->mv_vert_mode = mv_vert_mode;
+       tpg_update_mv_step(tpg);
+}
+
+static inline void tpg_init_mv_count(struct tpg_data *tpg)
+{
+       tpg->mv_hor_count = tpg->mv_vert_count = 0;
+}
+
+static inline void tpg_update_mv_count(struct tpg_data *tpg, bool frame_is_field)
+{
+       tpg->mv_hor_count += tpg->mv_hor_step * (frame_is_field ? 1 : 2);
+       tpg->mv_vert_count += tpg->mv_vert_step * (frame_is_field ? 1 : 2);
+}
+
+static inline void tpg_s_hflip(struct tpg_data *tpg, bool hflip)
+{
+       if (tpg->hflip == hflip)
+               return;
+       tpg->hflip = hflip;
+       tpg_update_mv_step(tpg);
+       tpg->recalc_lines = true;
+}
+
+static inline bool tpg_g_hflip(const struct tpg_data *tpg)
+{
+       return tpg->hflip;
+}
+
+static inline void tpg_s_vflip(struct tpg_data *tpg, bool vflip)
+{
+       tpg->vflip = vflip;
+}
+
+static inline bool tpg_g_vflip(const struct tpg_data *tpg)
+{
+       return tpg->vflip;
+}
+
+static inline bool tpg_pattern_is_static(const struct tpg_data *tpg)
+{
+       return tpg->pattern != TPG_PAT_NOISE &&
+              tpg->mv_hor_mode == TPG_MOVE_NONE &&
+              tpg->mv_vert_mode == TPG_MOVE_NONE;
+}
+
+#endif
diff --git a/drivers/media/platform/vivid/vivid-vbi-cap.c b/drivers/media/platform/vivid/vivid-vbi-cap.c
new file mode 100644 (file)
index 0000000..2166d0b
--- /dev/null
@@ -0,0 +1,371 @@
+/*
+ * vivid-vbi-cap.c - vbi capture support functions.
+ *
+ * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
+ *
+ * This program is free software; you may redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-common.h>
+
+#include "vivid-core.h"
+#include "vivid-kthread-cap.h"
+#include "vivid-vbi-cap.h"
+#include "vivid-vbi-gen.h"
+
+static void vivid_sliced_vbi_cap_fill(struct vivid_dev *dev, unsigned seqnr)
+{
+       struct vivid_vbi_gen_data *vbi_gen = &dev->vbi_gen;
+       bool is_60hz = dev->std_cap & V4L2_STD_525_60;
+
+       vivid_vbi_gen_sliced(vbi_gen, is_60hz, seqnr);
+
+       if (!is_60hz) {
+               if (dev->loop_video) {
+                       if (dev->vbi_out_have_wss) {
+                               vbi_gen->data[12].data[0] = dev->vbi_out_wss[0];
+                               vbi_gen->data[12].data[1] = dev->vbi_out_wss[1];
+                       } else {
+                               vbi_gen->data[12].id = 0;
+                       }
+               } else {
+                       switch (tpg_g_video_aspect(&dev->tpg)) {
+                       case TPG_VIDEO_ASPECT_14X9_CENTRE:
+                               vbi_gen->data[12].data[0] = 0x01;
+                               break;
+                       case TPG_VIDEO_ASPECT_16X9_CENTRE:
+                               vbi_gen->data[12].data[0] = 0x0b;
+                               break;
+                       case TPG_VIDEO_ASPECT_16X9_ANAMORPHIC:
+                               vbi_gen->data[12].data[0] = 0x07;
+                               break;
+                       case TPG_VIDEO_ASPECT_4X3:
+                       default:
+                               vbi_gen->data[12].data[0] = 0x08;
+                               break;
+                       }
+               }
+       } else if (dev->loop_video && is_60hz) {
+               if (dev->vbi_out_have_cc[0]) {
+                       vbi_gen->data[0].data[0] = dev->vbi_out_cc[0][0];
+                       vbi_gen->data[0].data[1] = dev->vbi_out_cc[0][1];
+               } else {
+                       vbi_gen->data[0].id = 0;
+               }
+               if (dev->vbi_out_have_cc[1]) {
+                       vbi_gen->data[1].data[0] = dev->vbi_out_cc[1][0];
+                       vbi_gen->data[1].data[1] = dev->vbi_out_cc[1][1];
+               } else {
+                       vbi_gen->data[1].id = 0;
+               }
+       }
+}
+
+static void vivid_g_fmt_vbi_cap(struct vivid_dev *dev, struct v4l2_vbi_format *vbi)
+{
+       bool is_60hz = dev->std_cap & V4L2_STD_525_60;
+
+       vbi->sampling_rate = 27000000;
+       vbi->offset = 24;
+       vbi->samples_per_line = 1440;
+       vbi->sample_format = V4L2_PIX_FMT_GREY;
+       vbi->start[0] = is_60hz ? V4L2_VBI_ITU_525_F1_START + 9 : V4L2_VBI_ITU_625_F1_START + 5;
+       vbi->start[1] = is_60hz ? V4L2_VBI_ITU_525_F2_START + 9 : V4L2_VBI_ITU_625_F2_START + 5;
+       vbi->count[0] = vbi->count[1] = is_60hz ? 12 : 18;
+       vbi->flags = dev->vbi_cap_interlaced ? V4L2_VBI_INTERLACED : 0;
+       vbi->reserved[0] = 0;
+       vbi->reserved[1] = 0;
+}
+
+void vivid_raw_vbi_cap_process(struct vivid_dev *dev, struct vivid_buffer *buf)
+{
+       struct v4l2_vbi_format vbi;
+       u8 *vbuf = vb2_plane_vaddr(&buf->vb, 0);
+
+       vivid_g_fmt_vbi_cap(dev, &vbi);
+       buf->vb.v4l2_buf.sequence = dev->vbi_cap_seq_count;
+       if (dev->field_cap == V4L2_FIELD_ALTERNATE)
+               buf->vb.v4l2_buf.sequence /= 2;
+
+       vivid_sliced_vbi_cap_fill(dev, buf->vb.v4l2_buf.sequence);
+
+       memset(vbuf, 0x10, vb2_plane_size(&buf->vb, 0));
+
+       if (!VIVID_INVALID_SIGNAL(dev->std_signal_mode))
+               vivid_vbi_gen_raw(&dev->vbi_gen, &vbi, vbuf);
+
+       v4l2_get_timestamp(&buf->vb.v4l2_buf.timestamp);
+       buf->vb.v4l2_buf.timestamp.tv_sec += dev->time_wrap_offset;
+}
+
+
+void vivid_sliced_vbi_cap_process(struct vivid_dev *dev, struct vivid_buffer *buf)
+{
+       struct v4l2_sliced_vbi_data *vbuf = vb2_plane_vaddr(&buf->vb, 0);
+
+       buf->vb.v4l2_buf.sequence = dev->vbi_cap_seq_count;
+       if (dev->field_cap == V4L2_FIELD_ALTERNATE)
+               buf->vb.v4l2_buf.sequence /= 2;
+
+       vivid_sliced_vbi_cap_fill(dev, buf->vb.v4l2_buf.sequence);
+
+       memset(vbuf, 0, vb2_plane_size(&buf->vb, 0));
+       if (!VIVID_INVALID_SIGNAL(dev->std_signal_mode)) {
+               unsigned i;
+
+               for (i = 0; i < 25; i++)
+                       vbuf[i] = dev->vbi_gen.data[i];
+       }
+
+       v4l2_get_timestamp(&buf->vb.v4l2_buf.timestamp);
+       buf->vb.v4l2_buf.timestamp.tv_sec += dev->time_wrap_offset;
+}
+
+static int vbi_cap_queue_setup(struct vb2_queue *vq, const struct v4l2_format *fmt,
+                      unsigned *nbuffers, unsigned *nplanes,
+                      unsigned sizes[], void *alloc_ctxs[])
+{
+       struct vivid_dev *dev = vb2_get_drv_priv(vq);
+       bool is_60hz = dev->std_cap & V4L2_STD_525_60;
+       unsigned size = vq->type == V4L2_BUF_TYPE_SLICED_VBI_CAPTURE ?
+               36 * sizeof(struct v4l2_sliced_vbi_data) :
+               1440 * 2 * (is_60hz ? 12 : 18);
+
+       if (!vivid_is_sdtv_cap(dev))
+               return -EINVAL;
+
+       sizes[0] = size;
+
+       if (vq->num_buffers + *nbuffers < 2)
+               *nbuffers = 2 - vq->num_buffers;
+
+       *nplanes = 1;
+       return 0;
+}
+
+static int vbi_cap_buf_prepare(struct vb2_buffer *vb)
+{
+       struct vivid_dev *dev = vb2_get_drv_priv(vb->vb2_queue);
+       bool is_60hz = dev->std_cap & V4L2_STD_525_60;
+       unsigned size = vb->vb2_queue->type == V4L2_BUF_TYPE_SLICED_VBI_CAPTURE ?
+               36 * sizeof(struct v4l2_sliced_vbi_data) :
+               1440 * 2 * (is_60hz ? 12 : 18);
+
+       dprintk(dev, 1, "%s\n", __func__);
+
+       if (dev->buf_prepare_error) {
+               /*
+                * Error injection: test what happens if buf_prepare() returns
+                * an error.
+                */
+               dev->buf_prepare_error = false;
+               return -EINVAL;
+       }
+       if (vb2_plane_size(vb, 0) < size) {
+               dprintk(dev, 1, "%s data will not fit into plane (%lu < %u)\n",
+                               __func__, vb2_plane_size(vb, 0), size);
+               return -EINVAL;
+       }
+       vb2_set_plane_payload(vb, 0, size);
+
+       return 0;
+}
+
+static void vbi_cap_buf_queue(struct vb2_buffer *vb)
+{
+       struct vivid_dev *dev = vb2_get_drv_priv(vb->vb2_queue);
+       struct vivid_buffer *buf = container_of(vb, struct vivid_buffer, vb);
+
+       dprintk(dev, 1, "%s\n", __func__);
+
+       spin_lock(&dev->slock);
+       list_add_tail(&buf->list, &dev->vbi_cap_active);
+       spin_unlock(&dev->slock);
+}
+
+static int vbi_cap_start_streaming(struct vb2_queue *vq, unsigned count)
+{
+       struct vivid_dev *dev = vb2_get_drv_priv(vq);
+       int err;
+
+       dprintk(dev, 1, "%s\n", __func__);
+       dev->vbi_cap_seq_count = 0;
+       if (dev->start_streaming_error) {
+               dev->start_streaming_error = false;
+               err = -EINVAL;
+       } else {
+               err = vivid_start_generating_vid_cap(dev, &dev->vbi_cap_streaming);
+       }
+       if (err) {
+               struct vivid_buffer *buf, *tmp;
+
+               list_for_each_entry_safe(buf, tmp, &dev->vbi_cap_active, list) {
+                       list_del(&buf->list);
+                       vb2_buffer_done(&buf->vb, VB2_BUF_STATE_QUEUED);
+               }
+       }
+       return err;
+}
+
+/* abort streaming and wait for last buffer */
+static void vbi_cap_stop_streaming(struct vb2_queue *vq)
+{
+       struct vivid_dev *dev = vb2_get_drv_priv(vq);
+
+       dprintk(dev, 1, "%s\n", __func__);
+       vivid_stop_generating_vid_cap(dev, &dev->vbi_cap_streaming);
+}
+
+const struct vb2_ops vivid_vbi_cap_qops = {
+       .queue_setup            = vbi_cap_queue_setup,
+       .buf_prepare            = vbi_cap_buf_prepare,
+       .buf_queue              = vbi_cap_buf_queue,
+       .start_streaming        = vbi_cap_start_streaming,
+       .stop_streaming         = vbi_cap_stop_streaming,
+       .wait_prepare           = vivid_unlock,
+       .wait_finish            = vivid_lock,
+};
+
+int vidioc_g_fmt_vbi_cap(struct file *file, void *priv,
+                                       struct v4l2_format *f)
+{
+       struct vivid_dev *dev = video_drvdata(file);
+       struct v4l2_vbi_format *vbi = &f->fmt.vbi;
+
+       if (!vivid_is_sdtv_cap(dev) || !dev->has_raw_vbi_cap)
+               return -EINVAL;
+
+       vivid_g_fmt_vbi_cap(dev, vbi);
+       return 0;
+}
+
+int vidioc_s_fmt_vbi_cap(struct file *file, void *priv,
+                                       struct v4l2_format *f)
+{
+       struct vivid_dev *dev = video_drvdata(file);
+       int ret = vidioc_g_fmt_vbi_cap(file, priv, f);
+
+       if (ret)
+               return ret;
+       if (dev->stream_sliced_vbi_cap && vb2_is_busy(&dev->vb_vbi_cap_q))
+               return -EBUSY;
+       dev->stream_sliced_vbi_cap = false;
+       dev->vbi_cap_dev.queue->type = V4L2_BUF_TYPE_VBI_CAPTURE;
+       return 0;
+}
+
+void vivid_fill_service_lines(struct v4l2_sliced_vbi_format *vbi, u32 service_set)
+{
+       vbi->io_size = sizeof(struct v4l2_sliced_vbi_data) * 36;
+       vbi->service_set = service_set;
+       memset(vbi->service_lines, 0, sizeof(vbi->service_lines));
+       memset(vbi->reserved, 0, sizeof(vbi->reserved));
+
+       if (vbi->service_set == 0)
+               return;
+
+       if (vbi->service_set & V4L2_SLICED_CAPTION_525) {
+               vbi->service_lines[0][21] = V4L2_SLICED_CAPTION_525;
+               vbi->service_lines[1][21] = V4L2_SLICED_CAPTION_525;
+       }
+       if (vbi->service_set & V4L2_SLICED_WSS_625) {
+               unsigned i;
+
+               for (i = 7; i <= 18; i++)
+                       vbi->service_lines[0][i] =
+                       vbi->service_lines[1][i] = V4L2_SLICED_TELETEXT_B;
+               vbi->service_lines[0][23] = V4L2_SLICED_WSS_625;
+       }
+}
+
+int vidioc_g_fmt_sliced_vbi_cap(struct file *file, void *fh, struct v4l2_format *fmt)
+{
+       struct vivid_dev *dev = video_drvdata(file);
+       struct v4l2_sliced_vbi_format *vbi = &fmt->fmt.sliced;
+
+       if (!vivid_is_sdtv_cap(dev) || !dev->has_sliced_vbi_cap)
+               return -EINVAL;
+
+       vivid_fill_service_lines(vbi, dev->service_set_cap);
+       return 0;
+}
+
+int vidioc_try_fmt_sliced_vbi_cap(struct file *file, void *fh, struct v4l2_format *fmt)
+{
+       struct vivid_dev *dev = video_drvdata(file);
+       struct v4l2_sliced_vbi_format *vbi = &fmt->fmt.sliced;
+       bool is_60hz = dev->std_cap & V4L2_STD_525_60;
+       u32 service_set = vbi->service_set;
+
+       if (!vivid_is_sdtv_cap(dev) || !dev->has_sliced_vbi_cap)
+               return -EINVAL;
+
+       service_set &= is_60hz ? V4L2_SLICED_CAPTION_525 :
+                                V4L2_SLICED_WSS_625 | V4L2_SLICED_TELETEXT_B;
+       vivid_fill_service_lines(vbi, service_set);
+       return 0;
+}
+
+int vidioc_s_fmt_sliced_vbi_cap(struct file *file, void *fh, struct v4l2_format *fmt)
+{
+       struct vivid_dev *dev = video_drvdata(file);
+       struct v4l2_sliced_vbi_format *vbi = &fmt->fmt.sliced;
+       int ret = vidioc_try_fmt_sliced_vbi_cap(file, fh, fmt);
+
+       if (ret)
+               return ret;
+       if (!dev->stream_sliced_vbi_cap && vb2_is_busy(&dev->vb_vbi_cap_q))
+               return -EBUSY;
+       dev->service_set_cap = vbi->service_set;
+       dev->stream_sliced_vbi_cap = true;
+       dev->vbi_cap_dev.queue->type = V4L2_BUF_TYPE_SLICED_VBI_CAPTURE;
+       return 0;
+}
+
+int vidioc_g_sliced_vbi_cap(struct file *file, void *fh, struct v4l2_sliced_vbi_cap *cap)
+{
+       struct vivid_dev *dev = video_drvdata(file);
+       struct video_device *vdev = video_devdata(file);
+       bool is_60hz;
+
+       if (vdev->vfl_dir == VFL_DIR_RX) {
+               is_60hz = dev->std_cap & V4L2_STD_525_60;
+               if (!vivid_is_sdtv_cap(dev) || !dev->has_sliced_vbi_cap ||
+                   cap->type != V4L2_BUF_TYPE_SLICED_VBI_CAPTURE)
+                       return -EINVAL;
+       } else {
+               is_60hz = dev->std_out & V4L2_STD_525_60;
+               if (!vivid_is_svid_out(dev) || !dev->has_sliced_vbi_out ||
+                   cap->type != V4L2_BUF_TYPE_SLICED_VBI_OUTPUT)
+                       return -EINVAL;
+       }
+
+       cap->service_set = is_60hz ? V4L2_SLICED_CAPTION_525 :
+                                    V4L2_SLICED_WSS_625 | V4L2_SLICED_TELETEXT_B;
+       if (is_60hz) {
+               cap->service_lines[0][21] = V4L2_SLICED_CAPTION_525;
+               cap->service_lines[1][21] = V4L2_SLICED_CAPTION_525;
+       } else {
+               unsigned i;
+
+               for (i = 7; i <= 18; i++)
+                       cap->service_lines[0][i] =
+                       cap->service_lines[1][i] = V4L2_SLICED_TELETEXT_B;
+               cap->service_lines[0][23] = V4L2_SLICED_WSS_625;
+       }
+       return 0;
+}
diff --git a/drivers/media/platform/vivid/vivid-vbi-cap.h b/drivers/media/platform/vivid/vivid-vbi-cap.h
new file mode 100644 (file)
index 0000000..2d8ea0b
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * vivid-vbi-cap.h - vbi capture support functions.
+ *
+ * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
+ *
+ * This program is free software; you may redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * 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 _VIVID_VBI_CAP_H_
+#define _VIVID_VBI_CAP_H_
+
+void vivid_fill_time_of_day_packet(u8 *packet);
+void vivid_raw_vbi_cap_process(struct vivid_dev *dev, struct vivid_buffer *buf);
+void vivid_sliced_vbi_cap_process(struct vivid_dev *dev, struct vivid_buffer *buf);
+void vivid_sliced_vbi_out_process(struct vivid_dev *dev, struct vivid_buffer *buf);
+int vidioc_g_fmt_vbi_cap(struct file *file, void *priv,
+                                       struct v4l2_format *f);
+int vidioc_s_fmt_vbi_cap(struct file *file, void *priv,
+                                       struct v4l2_format *f);
+int vidioc_g_fmt_sliced_vbi_cap(struct file *file, void *fh, struct v4l2_format *fmt);
+int vidioc_try_fmt_sliced_vbi_cap(struct file *file, void *fh, struct v4l2_format *fmt);
+int vidioc_s_fmt_sliced_vbi_cap(struct file *file, void *fh, struct v4l2_format *fmt);
+int vidioc_g_sliced_vbi_cap(struct file *file, void *fh, struct v4l2_sliced_vbi_cap *cap);
+
+void vivid_fill_service_lines(struct v4l2_sliced_vbi_format *vbi, u32 service_set);
+
+extern const struct vb2_ops vivid_vbi_cap_qops;
+
+#endif
diff --git a/drivers/media/platform/vivid/vivid-vbi-gen.c b/drivers/media/platform/vivid/vivid-vbi-gen.c
new file mode 100644 (file)
index 0000000..a2159de
--- /dev/null
@@ -0,0 +1,323 @@
+/*
+ * vivid-vbi-gen.c - vbi generator support functions.
+ *
+ * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
+ *
+ * This program is free software; you may redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/ktime.h>
+#include <linux/string.h>
+#include <linux/videodev2.h>
+
+#include "vivid-vbi-gen.h"
+
+static void wss_insert(u8 *wss, u32 val, unsigned size)
+{
+       while (size--)
+               *wss++ = (val & (1 << size)) ? 0xc0 : 0x10;
+}
+
+static void vivid_vbi_gen_wss_raw(const struct v4l2_sliced_vbi_data *data,
+               u8 *buf, unsigned sampling_rate)
+{
+       const unsigned rate = 5000000;  /* WSS has a 5 MHz transmission rate */
+       u8 wss[29 + 24 + 24 + 24 + 18 + 18] = { 0 };
+       const unsigned zero = 0x07;
+       const unsigned one = 0x38;
+       unsigned bit = 0;
+       u16 wss_data;
+       int i;
+
+       wss_insert(wss + bit, 0x1f1c71c7, 29); bit += 29;
+       wss_insert(wss + bit, 0x1e3c1f, 24); bit += 24;
+
+       wss_data = (data->data[1] << 8) | data->data[0];
+       for (i = 0; i <= 13; i++, bit += 6)
+               wss_insert(wss + bit, (wss_data & (1 << i)) ? one : zero, 6);
+
+       for (i = 0, bit = 0; bit < sizeof(wss); bit++) {
+               unsigned n = ((bit + 1) * sampling_rate) / rate;
+
+               while (i < n)
+                       buf[i++] = wss[bit];
+       }
+}
+
+static void vivid_vbi_gen_teletext_raw(const struct v4l2_sliced_vbi_data *data,
+               u8 *buf, unsigned sampling_rate)
+{
+       const unsigned rate = 6937500 / 10;     /* Teletext has a 6.9375 MHz transmission rate */
+       u8 teletext[45] = { 0x55, 0x55, 0x27 };
+       unsigned bit = 0;
+       int i;
+
+       memcpy(teletext + 3, data->data, sizeof(teletext) - 3);
+       /* prevents 32 bit overflow */
+       sampling_rate /= 10;
+
+       for (i = 0, bit = 0; bit < sizeof(teletext) * 8; bit++) {
+               unsigned n = ((bit + 1) * sampling_rate) / rate;
+               u8 val = (teletext[bit / 8] & (1 << (bit & 7))) ? 0xc0 : 0x10;
+
+               while (i < n)
+                       buf[i++] = val;
+       }
+}
+
+static void cc_insert(u8 *cc, u8 ch)
+{
+       unsigned tot = 0;
+       unsigned i;
+
+       for (i = 0; i < 7; i++) {
+               cc[2 * i] = cc[2 * i + 1] = (ch & (1 << i)) ? 1 : 0;
+               tot += cc[2 * i];
+       }
+       cc[14] = cc[15] = !(tot & 1);
+}
+
+#define CC_PREAMBLE_BITS (14 + 4 + 2)
+
+static void vivid_vbi_gen_cc_raw(const struct v4l2_sliced_vbi_data *data,
+               u8 *buf, unsigned sampling_rate)
+{
+       const unsigned rate = 1000000;  /* CC has a 1 MHz transmission rate */
+
+       u8 cc[CC_PREAMBLE_BITS + 2 * 16] = {
+               /* Clock run-in: 7 cycles */
+               0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
+               /* 2 cycles of 0 */
+               0, 0, 0, 0,
+               /* Start bit of 1 (each bit is two cycles) */
+               1, 1
+       };
+       unsigned bit, i;
+
+       cc_insert(cc + CC_PREAMBLE_BITS, data->data[0]);
+       cc_insert(cc + CC_PREAMBLE_BITS + 16, data->data[1]);
+
+       for (i = 0, bit = 0; bit < sizeof(cc); bit++) {
+               unsigned n = ((bit + 1) * sampling_rate) / rate;
+
+               while (i < n)
+                       buf[i++] = cc[bit] ? 0xc0 : 0x10;
+       }
+}
+
+void vivid_vbi_gen_raw(const struct vivid_vbi_gen_data *vbi,
+               const struct v4l2_vbi_format *vbi_fmt, u8 *buf)
+{
+       unsigned idx;
+
+       for (idx = 0; idx < 25; idx++) {
+               const struct v4l2_sliced_vbi_data *data = vbi->data + idx;
+               unsigned start_2nd_field;
+               unsigned line = data->line;
+               u8 *linebuf = buf;
+
+               start_2nd_field = (data->id & V4L2_SLICED_VBI_525) ? 263 : 313;
+               if (data->field)
+                       line += start_2nd_field;
+               line -= vbi_fmt->start[data->field];
+
+               if (vbi_fmt->flags & V4L2_VBI_INTERLACED)
+                       linebuf += (line * 2 + data->field) *
+                               vbi_fmt->samples_per_line;
+               else
+                       linebuf += (line + data->field * vbi_fmt->count[0]) *
+                               vbi_fmt->samples_per_line;
+               if (data->id == V4L2_SLICED_CAPTION_525)
+                       vivid_vbi_gen_cc_raw(data, linebuf, vbi_fmt->sampling_rate);
+               else if (data->id == V4L2_SLICED_WSS_625)
+                       vivid_vbi_gen_wss_raw(data, linebuf, vbi_fmt->sampling_rate);
+               else if (data->id == V4L2_SLICED_TELETEXT_B)
+                       vivid_vbi_gen_teletext_raw(data, linebuf, vbi_fmt->sampling_rate);
+       }
+}
+
+static const u8 vivid_cc_sequence1[30] = {
+       0x14, 0x20,     /* Resume Caption Loading */
+       'H',  'e',
+       'l',  'l',
+       'o',  ' ',
+       'w',  'o',
+       'r',  'l',
+       'd',  '!',
+       0x14, 0x2f,     /* End of Caption */
+};
+
+static const u8 vivid_cc_sequence2[30] = {
+       0x14, 0x20,     /* Resume Caption Loading */
+       'C',  'l',
+       'o',  's',
+       'e',  'd',
+       ' ',  'c',
+       'a',  'p',
+       't',  'i',
+       'o',  'n',
+       's',  ' ',
+       't',  'e',
+       's',  't',
+       0x14, 0x2f,     /* End of Caption */
+};
+
+static u8 calc_parity(u8 val)
+{
+       unsigned i;
+       unsigned tot = 0;
+
+       for (i = 0; i < 7; i++)
+               tot += (val & (1 << i)) ? 1 : 0;
+       return val | ((tot & 1) ? 0 : 0x80);
+}
+
+static void vivid_vbi_gen_set_time_of_day(u8 *packet)
+{
+       struct tm tm;
+       u8 checksum, i;
+
+       time_to_tm(get_seconds(), 0, &tm);
+       packet[0] = calc_parity(0x07);
+       packet[1] = calc_parity(0x01);
+       packet[2] = calc_parity(0x40 | tm.tm_min);
+       packet[3] = calc_parity(0x40 | tm.tm_hour);
+       packet[4] = calc_parity(0x40 | tm.tm_mday);
+       if (tm.tm_mday == 1 && tm.tm_mon == 2 &&
+           sys_tz.tz_minuteswest > tm.tm_min + tm.tm_hour * 60)
+               packet[4] = calc_parity(0x60 | tm.tm_mday);
+       packet[5] = calc_parity(0x40 | (1 + tm.tm_mon));
+       packet[6] = calc_parity(0x40 | (1 + tm.tm_wday));
+       packet[7] = calc_parity(0x40 | ((tm.tm_year - 90) & 0x3f));
+       packet[8] = calc_parity(0x0f);
+       for (checksum = i = 0; i <= 8; i++)
+               checksum += packet[i] & 0x7f;
+       packet[9] = calc_parity(0x100 - checksum);
+       checksum = 0;
+       packet[10] = calc_parity(0x07);
+       packet[11] = calc_parity(0x04);
+       if (sys_tz.tz_minuteswest >= 0)
+               packet[12] = calc_parity(0x40 | ((sys_tz.tz_minuteswest / 60) & 0x1f));
+       else
+               packet[12] = calc_parity(0x40 | ((24 + sys_tz.tz_minuteswest / 60) & 0x1f));
+       packet[13] = calc_parity(0);
+       packet[14] = calc_parity(0x0f);
+       for (checksum = 0, i = 10; i <= 14; i++)
+               checksum += packet[i] & 0x7f;
+       packet[15] = calc_parity(0x100 - checksum);
+}
+
+static const u8 hamming[16] = {
+       0x15, 0x02, 0x49, 0x5e, 0x64, 0x73, 0x38, 0x2f,
+       0xd0, 0xc7, 0x8c, 0x9b, 0xa1, 0xb6, 0xfd, 0xea
+};
+
+static void vivid_vbi_gen_teletext(u8 *packet, unsigned line, unsigned frame)
+{
+       unsigned offset = 2;
+       unsigned i;
+
+       packet[0] = hamming[1 + ((line & 1) << 3)];
+       packet[1] = hamming[line >> 1];
+       memset(packet + 2, 0x20, 40);
+       if (line == 0) {
+               /* subcode */
+               packet[2] = hamming[frame % 10];
+               packet[3] = hamming[frame / 10];
+               packet[4] = hamming[0];
+               packet[5] = hamming[0];
+               packet[6] = hamming[0];
+               packet[7] = hamming[0];
+               packet[8] = hamming[0];
+               packet[9] = hamming[1];
+               offset = 10;
+       }
+       packet += offset;
+       memcpy(packet, "Page: 100 Row: 10", 17);
+       packet[7] = '0' + frame / 10;
+       packet[8] = '0' + frame % 10;
+       packet[15] = '0' + line / 10;
+       packet[16] = '0' + line % 10;
+       for (i = 0; i < 42 - offset; i++)
+               packet[i] = calc_parity(packet[i]);
+}
+
+void vivid_vbi_gen_sliced(struct vivid_vbi_gen_data *vbi,
+               bool is_60hz, unsigned seqnr)
+{
+       struct v4l2_sliced_vbi_data *data0 = vbi->data;
+       struct v4l2_sliced_vbi_data *data1 = vbi->data + 1;
+       unsigned frame = seqnr % 60;
+
+       memset(vbi->data, 0, sizeof(vbi->data));
+
+       if (!is_60hz) {
+               unsigned i;
+
+               for (i = 0; i <= 11; i++) {
+                       data0->id = V4L2_SLICED_TELETEXT_B;
+                       data0->line = 7 + i;
+                       vivid_vbi_gen_teletext(data0->data, i, frame);
+                       data0++;
+               }
+               data0->id = V4L2_SLICED_WSS_625;
+               data0->line = 23;
+               /* 4x3 video aspect ratio */
+               data0->data[0] = 0x08;
+               data0++;
+               for (i = 0; i <= 11; i++) {
+                       data0->id = V4L2_SLICED_TELETEXT_B;
+                       data0->field = 1;
+                       data0->line = 7 + i;
+                       vivid_vbi_gen_teletext(data0->data, 12 + i, frame);
+                       data0++;
+               }
+               return;
+       }
+
+       data0->id = V4L2_SLICED_CAPTION_525;
+       data0->line = 21;
+       data1->id = V4L2_SLICED_CAPTION_525;
+       data1->field = 1;
+       data1->line = 21;
+
+       if (frame < 15) {
+               data0->data[0] = calc_parity(vivid_cc_sequence1[2 * frame]);
+               data0->data[1] = calc_parity(vivid_cc_sequence1[2 * frame + 1]);
+       } else if (frame >= 30 && frame < 45) {
+               frame -= 30;
+               data0->data[0] = calc_parity(vivid_cc_sequence2[2 * frame]);
+               data0->data[1] = calc_parity(vivid_cc_sequence2[2 * frame + 1]);
+       } else {
+               data0->data[0] = calc_parity(0);
+               data0->data[1] = calc_parity(0);
+       }
+
+       frame = seqnr % (30 * 60);
+       switch (frame) {
+       case 0:
+               vivid_vbi_gen_set_time_of_day(vbi->time_of_day_packet);
+               /* fall through */
+       case 1 ... 7:
+               data1->data[0] = vbi->time_of_day_packet[frame * 2];
+               data1->data[1] = vbi->time_of_day_packet[frame * 2 + 1];
+               break;
+       default:
+               data1->data[0] = calc_parity(0);
+               data1->data[1] = calc_parity(0);
+               break;
+       }
+}
diff --git a/drivers/media/platform/vivid/vivid-vbi-gen.h b/drivers/media/platform/vivid/vivid-vbi-gen.h
new file mode 100644 (file)
index 0000000..8444abe
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * vivid-vbi-gen.h - vbi generator support functions.
+ *
+ * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
+ *
+ * This program is free software; you may redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * 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 _VIVID_VBI_GEN_H_
+#define _VIVID_VBI_GEN_H_
+
+struct vivid_vbi_gen_data {
+       struct v4l2_sliced_vbi_data data[25];
+       u8 time_of_day_packet[16];
+};
+
+void vivid_vbi_gen_sliced(struct vivid_vbi_gen_data *vbi,
+               bool is_60hz, unsigned seqnr);
+void vivid_vbi_gen_raw(const struct vivid_vbi_gen_data *vbi,
+               const struct v4l2_vbi_format *vbi_fmt, u8 *buf);
+
+#endif
diff --git a/drivers/media/platform/vivid/vivid-vbi-out.c b/drivers/media/platform/vivid/vivid-vbi-out.c
new file mode 100644 (file)
index 0000000..9d00a07
--- /dev/null
@@ -0,0 +1,248 @@
+/*
+ * vivid-vbi-out.c - vbi output support functions.
+ *
+ * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
+ *
+ * This program is free software; you may redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-common.h>
+
+#include "vivid-core.h"
+#include "vivid-kthread-out.h"
+#include "vivid-vbi-out.h"
+#include "vivid-vbi-cap.h"
+
+static int vbi_out_queue_setup(struct vb2_queue *vq, const struct v4l2_format *fmt,
+                      unsigned *nbuffers, unsigned *nplanes,
+                      unsigned sizes[], void *alloc_ctxs[])
+{
+       struct vivid_dev *dev = vb2_get_drv_priv(vq);
+       bool is_60hz = dev->std_out & V4L2_STD_525_60;
+       unsigned size = vq->type == V4L2_BUF_TYPE_SLICED_VBI_OUTPUT ?
+               36 * sizeof(struct v4l2_sliced_vbi_data) :
+               1440 * 2 * (is_60hz ? 12 : 18);
+
+       if (!vivid_is_svid_out(dev))
+               return -EINVAL;
+
+       sizes[0] = size;
+
+       if (vq->num_buffers + *nbuffers < 2)
+               *nbuffers = 2 - vq->num_buffers;
+
+       *nplanes = 1;
+       return 0;
+}
+
+static int vbi_out_buf_prepare(struct vb2_buffer *vb)
+{
+       struct vivid_dev *dev = vb2_get_drv_priv(vb->vb2_queue);
+       bool is_60hz = dev->std_out & V4L2_STD_525_60;
+       unsigned size = vb->vb2_queue->type == V4L2_BUF_TYPE_SLICED_VBI_OUTPUT ?
+               36 * sizeof(struct v4l2_sliced_vbi_data) :
+               1440 * 2 * (is_60hz ? 12 : 18);
+
+       dprintk(dev, 1, "%s\n", __func__);
+
+       if (dev->buf_prepare_error) {
+               /*
+                * Error injection: test what happens if buf_prepare() returns
+                * an error.
+                */
+               dev->buf_prepare_error = false;
+               return -EINVAL;
+       }
+       if (vb2_plane_size(vb, 0) < size) {
+               dprintk(dev, 1, "%s data will not fit into plane (%lu < %u)\n",
+                               __func__, vb2_plane_size(vb, 0), size);
+               return -EINVAL;
+       }
+       vb2_set_plane_payload(vb, 0, size);
+
+       return 0;
+}
+
+static void vbi_out_buf_queue(struct vb2_buffer *vb)
+{
+       struct vivid_dev *dev = vb2_get_drv_priv(vb->vb2_queue);
+       struct vivid_buffer *buf = container_of(vb, struct vivid_buffer, vb);
+
+       dprintk(dev, 1, "%s\n", __func__);
+
+       spin_lock(&dev->slock);
+       list_add_tail(&buf->list, &dev->vbi_out_active);
+       spin_unlock(&dev->slock);
+}
+
+static int vbi_out_start_streaming(struct vb2_queue *vq, unsigned count)
+{
+       struct vivid_dev *dev = vb2_get_drv_priv(vq);
+       int err;
+
+       dprintk(dev, 1, "%s\n", __func__);
+       dev->vbi_out_seq_count = 0;
+       if (dev->start_streaming_error) {
+               dev->start_streaming_error = false;
+               err = -EINVAL;
+       } else {
+               err = vivid_start_generating_vid_out(dev, &dev->vbi_out_streaming);
+       }
+       if (err) {
+               struct vivid_buffer *buf, *tmp;
+
+               list_for_each_entry_safe(buf, tmp, &dev->vbi_out_active, list) {
+                       list_del(&buf->list);
+                       vb2_buffer_done(&buf->vb, VB2_BUF_STATE_QUEUED);
+               }
+       }
+       return err;
+}
+
+/* abort streaming and wait for last buffer */
+static void vbi_out_stop_streaming(struct vb2_queue *vq)
+{
+       struct vivid_dev *dev = vb2_get_drv_priv(vq);
+
+       dprintk(dev, 1, "%s\n", __func__);
+       vivid_stop_generating_vid_out(dev, &dev->vbi_out_streaming);
+       dev->vbi_out_have_wss = false;
+       dev->vbi_out_have_cc[0] = false;
+       dev->vbi_out_have_cc[1] = false;
+}
+
+const struct vb2_ops vivid_vbi_out_qops = {
+       .queue_setup            = vbi_out_queue_setup,
+       .buf_prepare            = vbi_out_buf_prepare,
+       .buf_queue              = vbi_out_buf_queue,
+       .start_streaming        = vbi_out_start_streaming,
+       .stop_streaming         = vbi_out_stop_streaming,
+       .wait_prepare           = vivid_unlock,
+       .wait_finish            = vivid_lock,
+};
+
+int vidioc_g_fmt_vbi_out(struct file *file, void *priv,
+                                       struct v4l2_format *f)
+{
+       struct vivid_dev *dev = video_drvdata(file);
+       struct v4l2_vbi_format *vbi = &f->fmt.vbi;
+       bool is_60hz = dev->std_out & V4L2_STD_525_60;
+
+       if (!vivid_is_svid_out(dev) || !dev->has_raw_vbi_out)
+               return -EINVAL;
+
+       vbi->sampling_rate = 25000000;
+       vbi->offset = 24;
+       vbi->samples_per_line = 1440;
+       vbi->sample_format = V4L2_PIX_FMT_GREY;
+       vbi->start[0] = is_60hz ? V4L2_VBI_ITU_525_F1_START + 9 : V4L2_VBI_ITU_625_F1_START + 5;
+       vbi->start[1] = is_60hz ? V4L2_VBI_ITU_525_F2_START + 9 : V4L2_VBI_ITU_625_F2_START + 5;
+       vbi->count[0] = vbi->count[1] = is_60hz ? 12 : 18;
+       vbi->flags = dev->vbi_cap_interlaced ? V4L2_VBI_INTERLACED : 0;
+       vbi->reserved[0] = 0;
+       vbi->reserved[1] = 0;
+       return 0;
+}
+
+int vidioc_s_fmt_vbi_out(struct file *file, void *priv,
+                                       struct v4l2_format *f)
+{
+       struct vivid_dev *dev = video_drvdata(file);
+       int ret = vidioc_g_fmt_vbi_out(file, priv, f);
+
+       if (ret)
+               return ret;
+       if (vb2_is_busy(&dev->vb_vbi_out_q))
+               return -EBUSY;
+       dev->stream_sliced_vbi_out = false;
+       dev->vbi_out_dev.queue->type = V4L2_BUF_TYPE_VBI_OUTPUT;
+       return 0;
+}
+
+int vidioc_g_fmt_sliced_vbi_out(struct file *file, void *fh, struct v4l2_format *fmt)
+{
+       struct vivid_dev *dev = video_drvdata(file);
+       struct v4l2_sliced_vbi_format *vbi = &fmt->fmt.sliced;
+
+       if (!vivid_is_svid_out(dev) || !dev->has_sliced_vbi_out)
+               return -EINVAL;
+
+       vivid_fill_service_lines(vbi, dev->service_set_out);
+       return 0;
+}
+
+int vidioc_try_fmt_sliced_vbi_out(struct file *file, void *fh, struct v4l2_format *fmt)
+{
+       struct vivid_dev *dev = video_drvdata(file);
+       struct v4l2_sliced_vbi_format *vbi = &fmt->fmt.sliced;
+       bool is_60hz = dev->std_out & V4L2_STD_525_60;
+       u32 service_set = vbi->service_set;
+
+       if (!vivid_is_svid_out(dev) || !dev->has_sliced_vbi_out)
+               return -EINVAL;
+
+       service_set &= is_60hz ? V4L2_SLICED_CAPTION_525 :
+                                V4L2_SLICED_WSS_625 | V4L2_SLICED_TELETEXT_B;
+       vivid_fill_service_lines(vbi, service_set);
+       return 0;
+}
+
+int vidioc_s_fmt_sliced_vbi_out(struct file *file, void *fh, struct v4l2_format *fmt)
+{
+       struct vivid_dev *dev = video_drvdata(file);
+       struct v4l2_sliced_vbi_format *vbi = &fmt->fmt.sliced;
+       int ret = vidioc_try_fmt_sliced_vbi_out(file, fh, fmt);
+
+       if (ret)
+               return ret;
+       if (vb2_is_busy(&dev->vb_vbi_out_q))
+               return -EBUSY;
+       dev->service_set_out = vbi->service_set;
+       dev->stream_sliced_vbi_out = true;
+       dev->vbi_out_dev.queue->type = V4L2_BUF_TYPE_SLICED_VBI_OUTPUT;
+       return 0;
+}
+
+void vivid_sliced_vbi_out_process(struct vivid_dev *dev, struct vivid_buffer *buf)
+{
+       struct v4l2_sliced_vbi_data *vbi = vb2_plane_vaddr(&buf->vb, 0);
+       unsigned elems = vb2_get_plane_payload(&buf->vb, 0) / sizeof(*vbi);
+
+       dev->vbi_out_have_cc[0] = false;
+       dev->vbi_out_have_cc[1] = false;
+       dev->vbi_out_have_wss = false;
+       while (elems--) {
+               switch (vbi->id) {
+               case V4L2_SLICED_CAPTION_525:
+                       if ((dev->std_out & V4L2_STD_525_60) && vbi->line == 21) {
+                               dev->vbi_out_have_cc[!!vbi->field] = true;
+                               dev->vbi_out_cc[!!vbi->field][0] = vbi->data[0];
+                               dev->vbi_out_cc[!!vbi->field][1] = vbi->data[1];
+                       }
+                       break;
+               case V4L2_SLICED_WSS_625:
+                       if ((dev->std_out & V4L2_STD_625_50) &&
+                           vbi->field == 0 && vbi->line == 23) {
+                               dev->vbi_out_have_wss = true;
+                               dev->vbi_out_wss[0] = vbi->data[0];
+                               dev->vbi_out_wss[1] = vbi->data[1];
+                       }
+                       break;
+               }
+               vbi++;
+       }
+}
diff --git a/drivers/media/platform/vivid/vivid-vbi-out.h b/drivers/media/platform/vivid/vivid-vbi-out.h
new file mode 100644 (file)
index 0000000..6555ba9
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * vivid-vbi-out.h - vbi output support functions.
+ *
+ * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
+ *
+ * This program is free software; you may redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * 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 _VIVID_VBI_OUT_H_
+#define _VIVID_VBI_OUT_H_
+
+void vivid_sliced_vbi_out_process(struct vivid_dev *dev, struct vivid_buffer *buf);
+int vidioc_g_fmt_vbi_out(struct file *file, void *priv,
+                                       struct v4l2_format *f);
+int vidioc_s_fmt_vbi_out(struct file *file, void *priv,
+                                       struct v4l2_format *f);
+int vidioc_g_fmt_sliced_vbi_out(struct file *file, void *fh, struct v4l2_format *fmt);
+int vidioc_try_fmt_sliced_vbi_out(struct file *file, void *fh, struct v4l2_format *fmt);
+int vidioc_s_fmt_sliced_vbi_out(struct file *file, void *fh, struct v4l2_format *fmt);
+
+extern const struct vb2_ops vivid_vbi_out_qops;
+
+#endif
diff --git a/drivers/media/platform/vivid/vivid-vid-cap.c b/drivers/media/platform/vivid/vivid-vid-cap.c
new file mode 100644 (file)
index 0000000..331c544
--- /dev/null
@@ -0,0 +1,1730 @@
+/*
+ * vivid-vid-cap.c - video capture support functions.
+ *
+ * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
+ *
+ * This program is free software; you may redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/vmalloc.h>
+#include <linux/videodev2.h>
+#include <linux/v4l2-dv-timings.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-event.h>
+#include <media/v4l2-dv-timings.h>
+
+#include "vivid-core.h"
+#include "vivid-vid-common.h"
+#include "vivid-kthread-cap.h"
+#include "vivid-vid-cap.h"
+
+/* timeperframe: min/max and default */
+static const struct v4l2_fract
+       tpf_min     = {.numerator = 1,          .denominator = FPS_MAX},
+       tpf_max     = {.numerator = FPS_MAX,    .denominator = 1},
+       tpf_default = {.numerator = 1,          .denominator = 30};
+
+static const struct vivid_fmt formats_ovl[] = {
+       {
+               .name     = "RGB565 (LE)",
+               .fourcc   = V4L2_PIX_FMT_RGB565, /* gggbbbbb rrrrrggg */
+               .depth    = 16,
+               .planes   = 1,
+       },
+       {
+               .name     = "XRGB555 (LE)",
+               .fourcc   = V4L2_PIX_FMT_XRGB555, /* gggbbbbb arrrrrgg */
+               .depth    = 16,
+               .planes   = 1,
+       },
+       {
+               .name     = "ARGB555 (LE)",
+               .fourcc   = V4L2_PIX_FMT_ARGB555, /* gggbbbbb arrrrrgg */
+               .depth    = 16,
+               .planes   = 1,
+       },
+};
+
+/* The number of discrete webcam framesizes */
+#define VIVID_WEBCAM_SIZES 3
+/* The number of discrete webcam frameintervals */
+#define VIVID_WEBCAM_IVALS (VIVID_WEBCAM_SIZES * 2)
+
+/* Sizes must be in increasing order */
+static const struct v4l2_frmsize_discrete webcam_sizes[VIVID_WEBCAM_SIZES] = {
+       {  320, 180 },
+       {  640, 360 },
+       { 1280, 720 },
+};
+
+/*
+ * Intervals must be in increasing order and there must be twice as many
+ * elements in this array as there are in webcam_sizes.
+ */
+static const struct v4l2_fract webcam_intervals[VIVID_WEBCAM_IVALS] = {
+       {  1, 10 },
+       {  1, 15 },
+       {  1, 25 },
+       {  1, 30 },
+       {  1, 50 },
+       {  1, 60 },
+};
+
+static const struct v4l2_discrete_probe webcam_probe = {
+       webcam_sizes,
+       VIVID_WEBCAM_SIZES
+};
+
+static int vid_cap_queue_setup(struct vb2_queue *vq, const struct v4l2_format *fmt,
+                      unsigned *nbuffers, unsigned *nplanes,
+                      unsigned sizes[], void *alloc_ctxs[])
+{
+       struct vivid_dev *dev = vb2_get_drv_priv(vq);
+       unsigned planes = tpg_g_planes(&dev->tpg);
+       unsigned h = dev->fmt_cap_rect.height;
+       unsigned p;
+
+       if (dev->field_cap == V4L2_FIELD_ALTERNATE) {
+               /*
+                * You cannot use read() with FIELD_ALTERNATE since the field
+                * information (TOP/BOTTOM) cannot be passed back to the user.
+                */
+               if (vb2_fileio_is_active(vq))
+                       return -EINVAL;
+       }
+
+       if (dev->queue_setup_error) {
+               /*
+                * Error injection: test what happens if queue_setup() returns
+                * an error.
+                */
+               dev->queue_setup_error = false;
+               return -EINVAL;
+       }
+       if (fmt) {
+               const struct v4l2_pix_format_mplane *mp;
+               struct v4l2_format mp_fmt;
+               const struct vivid_fmt *vfmt;
+
+               if (!V4L2_TYPE_IS_MULTIPLANAR(fmt->type)) {
+                       fmt_sp2mp(fmt, &mp_fmt);
+                       fmt = &mp_fmt;
+               }
+               mp = &fmt->fmt.pix_mp;
+               /*
+                * Check if the number of planes in the specified format match
+                * the number of planes in the current format. You can't mix that.
+                */
+               if (mp->num_planes != planes)
+                       return -EINVAL;
+               vfmt = vivid_get_format(dev, mp->pixelformat);
+               for (p = 0; p < planes; p++) {
+                       sizes[p] = mp->plane_fmt[p].sizeimage;
+                       if (sizes[0] < tpg_g_bytesperline(&dev->tpg, 0) * h +
+                                                       vfmt->data_offset[p])
+                               return -EINVAL;
+               }
+       } else {
+               for (p = 0; p < planes; p++)
+                       sizes[p] = tpg_g_bytesperline(&dev->tpg, p) * h +
+                                       dev->fmt_cap->data_offset[p];
+       }
+
+       if (vq->num_buffers + *nbuffers < 2)
+               *nbuffers = 2 - vq->num_buffers;
+
+       *nplanes = planes;
+
+       /*
+        * videobuf2-vmalloc allocator is context-less so no need to set
+        * alloc_ctxs array.
+        */
+
+       if (planes == 2)
+               dprintk(dev, 1, "%s, count=%d, sizes=%u, %u\n", __func__,
+                       *nbuffers, sizes[0], sizes[1]);
+       else
+               dprintk(dev, 1, "%s, count=%d, size=%u\n", __func__,
+                       *nbuffers, sizes[0]);
+
+       return 0;
+}
+
+static int vid_cap_buf_prepare(struct vb2_buffer *vb)
+{
+       struct vivid_dev *dev = vb2_get_drv_priv(vb->vb2_queue);
+       unsigned long size;
+       unsigned planes = tpg_g_planes(&dev->tpg);
+       unsigned p;
+
+       dprintk(dev, 1, "%s\n", __func__);
+
+       if (WARN_ON(NULL == dev->fmt_cap))
+               return -EINVAL;
+
+       if (dev->buf_prepare_error) {
+               /*
+                * Error injection: test what happens if buf_prepare() returns
+                * an error.
+                */
+               dev->buf_prepare_error = false;
+               return -EINVAL;
+       }
+       for (p = 0; p < planes; p++) {
+               size = tpg_g_bytesperline(&dev->tpg, p) * dev->fmt_cap_rect.height +
+                       dev->fmt_cap->data_offset[p];
+
+               if (vb2_plane_size(vb, 0) < size) {
+                       dprintk(dev, 1, "%s data will not fit into plane %u (%lu < %lu)\n",
+                                       __func__, p, vb2_plane_size(vb, 0), size);
+                       return -EINVAL;
+               }
+
+               vb2_set_plane_payload(vb, p, size);
+               vb->v4l2_planes[p].data_offset = dev->fmt_cap->data_offset[p];
+       }
+
+       return 0;
+}
+
+static void vid_cap_buf_finish(struct vb2_buffer *vb)
+{
+       struct vivid_dev *dev = vb2_get_drv_priv(vb->vb2_queue);
+       struct v4l2_timecode *tc = &vb->v4l2_buf.timecode;
+       unsigned fps = 25;
+       unsigned seq = vb->v4l2_buf.sequence;
+
+       if (!vivid_is_sdtv_cap(dev))
+               return;
+
+       /*
+        * Set the timecode. Rarely used, so it is interesting to
+        * test this.
+        */
+       vb->v4l2_buf.flags |= V4L2_BUF_FLAG_TIMECODE;
+       if (dev->std_cap & V4L2_STD_525_60)
+               fps = 30;
+       tc->type = (fps == 30) ? V4L2_TC_TYPE_30FPS : V4L2_TC_TYPE_25FPS;
+       tc->flags = 0;
+       tc->frames = seq % fps;
+       tc->seconds = (seq / fps) % 60;
+       tc->minutes = (seq / (60 * fps)) % 60;
+       tc->hours = (seq / (60 * 60 * fps)) % 24;
+}
+
+static void vid_cap_buf_queue(struct vb2_buffer *vb)
+{
+       struct vivid_dev *dev = vb2_get_drv_priv(vb->vb2_queue);
+       struct vivid_buffer *buf = container_of(vb, struct vivid_buffer, vb);
+
+       dprintk(dev, 1, "%s\n", __func__);
+
+       spin_lock(&dev->slock);
+       list_add_tail(&buf->list, &dev->vid_cap_active);
+       spin_unlock(&dev->slock);
+}
+
+static int vid_cap_start_streaming(struct vb2_queue *vq, unsigned count)
+{
+       struct vivid_dev *dev = vb2_get_drv_priv(vq);
+       unsigned i;
+       int err;
+
+       if (vb2_is_streaming(&dev->vb_vid_out_q))
+               dev->can_loop_video = vivid_vid_can_loop(dev);
+
+       if (dev->kthread_vid_cap)
+               return 0;
+
+       dev->vid_cap_seq_count = 0;
+       dprintk(dev, 1, "%s\n", __func__);
+       for (i = 0; i < VIDEO_MAX_FRAME; i++)
+               dev->must_blank[i] = tpg_g_perc_fill(&dev->tpg) < 100;
+       if (dev->start_streaming_error) {
+               dev->start_streaming_error = false;
+               err = -EINVAL;
+       } else {
+               err = vivid_start_generating_vid_cap(dev, &dev->vid_cap_streaming);
+       }
+       if (err) {
+               struct vivid_buffer *buf, *tmp;
+
+               list_for_each_entry_safe(buf, tmp, &dev->vid_cap_active, list) {
+                       list_del(&buf->list);
+                       vb2_buffer_done(&buf->vb, VB2_BUF_STATE_QUEUED);
+               }
+       }
+       return err;
+}
+
+/* abort streaming and wait for last buffer */
+static void vid_cap_stop_streaming(struct vb2_queue *vq)
+{
+       struct vivid_dev *dev = vb2_get_drv_priv(vq);
+
+       dprintk(dev, 1, "%s\n", __func__);
+       vivid_stop_generating_vid_cap(dev, &dev->vid_cap_streaming);
+       dev->can_loop_video = false;
+}
+
+const struct vb2_ops vivid_vid_cap_qops = {
+       .queue_setup            = vid_cap_queue_setup,
+       .buf_prepare            = vid_cap_buf_prepare,
+       .buf_finish             = vid_cap_buf_finish,
+       .buf_queue              = vid_cap_buf_queue,
+       .start_streaming        = vid_cap_start_streaming,
+       .stop_streaming         = vid_cap_stop_streaming,
+       .wait_prepare           = vivid_unlock,
+       .wait_finish            = vivid_lock,
+};
+
+/*
+ * Determine the 'picture' quality based on the current TV frequency: either
+ * COLOR for a good 'signal', GRAY (grayscale picture) for a slightly off
+ * signal or NOISE for no signal.
+ */
+void vivid_update_quality(struct vivid_dev *dev)
+{
+       unsigned freq_modulus;
+
+       if (dev->loop_video && (vivid_is_svid_cap(dev) || vivid_is_hdmi_cap(dev))) {
+               /*
+                * The 'noise' will only be replaced by the actual video
+                * if the output video matches the input video settings.
+                */
+               tpg_s_quality(&dev->tpg, TPG_QUAL_NOISE, 0);
+               return;
+       }
+       if (vivid_is_hdmi_cap(dev) && VIVID_INVALID_SIGNAL(dev->dv_timings_signal_mode)) {
+               tpg_s_quality(&dev->tpg, TPG_QUAL_NOISE, 0);
+               return;
+       }
+       if (vivid_is_sdtv_cap(dev) && VIVID_INVALID_SIGNAL(dev->std_signal_mode)) {
+               tpg_s_quality(&dev->tpg, TPG_QUAL_NOISE, 0);
+               return;
+       }
+       if (!vivid_is_tv_cap(dev)) {
+               tpg_s_quality(&dev->tpg, TPG_QUAL_COLOR, 0);
+               return;
+       }
+
+       /*
+        * There is a fake channel every 6 MHz at 49.25, 55.25, etc.
+        * From +/- 0.25 MHz around the channel there is color, and from
+        * +/- 1 MHz there is grayscale (chroma is lost).
+        * Everywhere else it is just noise.
+        */
+       freq_modulus = (dev->tv_freq - 676 /* (43.25-1) * 16 */) % (6 * 16);
+       if (freq_modulus > 2 * 16) {
+               tpg_s_quality(&dev->tpg, TPG_QUAL_NOISE,
+                       next_pseudo_random32(dev->tv_freq ^ 0x55) & 0x3f);
+               return;
+       }
+       if (freq_modulus < 12 /*0.75 * 16*/ || freq_modulus > 20 /*1.25 * 16*/)
+               tpg_s_quality(&dev->tpg, TPG_QUAL_GRAY, 0);
+       else
+               tpg_s_quality(&dev->tpg, TPG_QUAL_COLOR, 0);
+}
+
+/*
+ * Get the current picture quality and the associated afc value.
+ */
+static enum tpg_quality vivid_get_quality(struct vivid_dev *dev, s32 *afc)
+{
+       unsigned freq_modulus;
+
+       if (afc)
+               *afc = 0;
+       if (tpg_g_quality(&dev->tpg) == TPG_QUAL_COLOR ||
+           tpg_g_quality(&dev->tpg) == TPG_QUAL_NOISE)
+               return tpg_g_quality(&dev->tpg);
+
+       /*
+        * There is a fake channel every 6 MHz at 49.25, 55.25, etc.
+        * From +/- 0.25 MHz around the channel there is color, and from
+        * +/- 1 MHz there is grayscale (chroma is lost).
+        * Everywhere else it is just gray.
+        */
+       freq_modulus = (dev->tv_freq - 676 /* (43.25-1) * 16 */) % (6 * 16);
+       if (afc)
+               *afc = freq_modulus - 1 * 16;
+       return TPG_QUAL_GRAY;
+}
+
+enum tpg_video_aspect vivid_get_video_aspect(const struct vivid_dev *dev)
+{
+       if (vivid_is_sdtv_cap(dev))
+               return dev->std_aspect_ratio;
+
+       if (vivid_is_hdmi_cap(dev))
+               return dev->dv_timings_aspect_ratio;
+
+       return TPG_VIDEO_ASPECT_IMAGE;
+}
+
+static enum tpg_pixel_aspect vivid_get_pixel_aspect(const struct vivid_dev *dev)
+{
+       if (vivid_is_sdtv_cap(dev))
+               return (dev->std_cap & V4L2_STD_525_60) ?
+                       TPG_PIXEL_ASPECT_NTSC : TPG_PIXEL_ASPECT_PAL;
+
+       if (vivid_is_hdmi_cap(dev) &&
+           dev->src_rect.width == 720 && dev->src_rect.height <= 576)
+               return dev->src_rect.height == 480 ?
+                       TPG_PIXEL_ASPECT_NTSC : TPG_PIXEL_ASPECT_PAL;
+
+       return TPG_PIXEL_ASPECT_SQUARE;
+}
+
+/*
+ * Called whenever the format has to be reset which can occur when
+ * changing inputs, standard, timings, etc.
+ */
+void vivid_update_format_cap(struct vivid_dev *dev, bool keep_controls)
+{
+       struct v4l2_bt_timings *bt = &dev->dv_timings_cap.bt;
+       unsigned size;
+
+       switch (dev->input_type[dev->input]) {
+       case WEBCAM:
+       default:
+               dev->src_rect.width = webcam_sizes[dev->webcam_size_idx].width;
+               dev->src_rect.height = webcam_sizes[dev->webcam_size_idx].height;
+               dev->timeperframe_vid_cap = webcam_intervals[dev->webcam_ival_idx];
+               dev->field_cap = V4L2_FIELD_NONE;
+               tpg_s_rgb_range(&dev->tpg, V4L2_DV_RGB_RANGE_AUTO);
+               break;
+       case TV:
+       case SVID:
+               dev->field_cap = dev->tv_field_cap;
+               dev->src_rect.width = 720;
+               if (dev->std_cap & V4L2_STD_525_60) {
+                       dev->src_rect.height = 480;
+                       dev->timeperframe_vid_cap = (struct v4l2_fract) { 1001, 30000 };
+                       dev->service_set_cap = V4L2_SLICED_CAPTION_525;
+               } else {
+                       dev->src_rect.height = 576;
+                       dev->timeperframe_vid_cap = (struct v4l2_fract) { 1000, 25000 };
+                       dev->service_set_cap = V4L2_SLICED_WSS_625 | V4L2_SLICED_TELETEXT_B;
+               }
+               tpg_s_rgb_range(&dev->tpg, V4L2_DV_RGB_RANGE_AUTO);
+               break;
+       case HDMI:
+               dev->src_rect.width = bt->width;
+               dev->src_rect.height = bt->height;
+               size = V4L2_DV_BT_FRAME_WIDTH(bt) * V4L2_DV_BT_FRAME_HEIGHT(bt);
+               dev->timeperframe_vid_cap = (struct v4l2_fract) {
+                       size / 100, (u32)bt->pixelclock / 100
+               };
+               if (bt->interlaced)
+                       dev->field_cap = V4L2_FIELD_ALTERNATE;
+               else
+                       dev->field_cap = V4L2_FIELD_NONE;
+
+               /*
+                * We can be called from within s_ctrl, in that case we can't
+                * set/get controls. Luckily we don't need to in that case.
+                */
+               if (keep_controls || !dev->colorspace)
+                       break;
+               if (bt->standards & V4L2_DV_BT_STD_CEA861) {
+                       if (bt->width == 720 && bt->height <= 576)
+                               v4l2_ctrl_s_ctrl(dev->colorspace, V4L2_COLORSPACE_SMPTE170M);
+                       else
+                               v4l2_ctrl_s_ctrl(dev->colorspace, V4L2_COLORSPACE_REC709);
+                       v4l2_ctrl_s_ctrl(dev->real_rgb_range_cap, 1);
+               } else {
+                       v4l2_ctrl_s_ctrl(dev->colorspace, V4L2_COLORSPACE_SRGB);
+                       v4l2_ctrl_s_ctrl(dev->real_rgb_range_cap, 0);
+               }
+               tpg_s_rgb_range(&dev->tpg, v4l2_ctrl_g_ctrl(dev->rgb_range_cap));
+               break;
+       }
+       vivid_update_quality(dev);
+       tpg_reset_source(&dev->tpg, dev->src_rect.width, dev->src_rect.height, dev->field_cap);
+       dev->crop_cap = dev->src_rect;
+       dev->crop_bounds_cap = dev->src_rect;
+       dev->compose_cap = dev->crop_cap;
+       if (V4L2_FIELD_HAS_T_OR_B(dev->field_cap))
+               dev->compose_cap.height /= 2;
+       dev->fmt_cap_rect = dev->compose_cap;
+       tpg_s_video_aspect(&dev->tpg, vivid_get_video_aspect(dev));
+       tpg_s_pixel_aspect(&dev->tpg, vivid_get_pixel_aspect(dev));
+       tpg_update_mv_step(&dev->tpg);
+}
+
+/* Map the field to something that is valid for the current input */
+static enum v4l2_field vivid_field_cap(struct vivid_dev *dev, enum v4l2_field field)
+{
+       if (vivid_is_sdtv_cap(dev)) {
+               switch (field) {
+               case V4L2_FIELD_INTERLACED_TB:
+               case V4L2_FIELD_INTERLACED_BT:
+               case V4L2_FIELD_SEQ_TB:
+               case V4L2_FIELD_SEQ_BT:
+               case V4L2_FIELD_TOP:
+               case V4L2_FIELD_BOTTOM:
+               case V4L2_FIELD_ALTERNATE:
+                       return field;
+               case V4L2_FIELD_INTERLACED:
+               default:
+                       return V4L2_FIELD_INTERLACED;
+               }
+       }
+       if (vivid_is_hdmi_cap(dev))
+               return dev->dv_timings_cap.bt.interlaced ? V4L2_FIELD_ALTERNATE :
+                                                      V4L2_FIELD_NONE;
+       return V4L2_FIELD_NONE;
+}
+
+static unsigned vivid_colorspace_cap(struct vivid_dev *dev)
+{
+       if (!dev->loop_video || vivid_is_webcam(dev) || vivid_is_tv_cap(dev))
+               return tpg_g_colorspace(&dev->tpg);
+       return dev->colorspace_out;
+}
+
+int vivid_g_fmt_vid_cap(struct file *file, void *priv,
+                                       struct v4l2_format *f)
+{
+       struct vivid_dev *dev = video_drvdata(file);
+       struct v4l2_pix_format_mplane *mp = &f->fmt.pix_mp;
+       unsigned p;
+
+       mp->width        = dev->fmt_cap_rect.width;
+       mp->height       = dev->fmt_cap_rect.height;
+       mp->field        = dev->field_cap;
+       mp->pixelformat  = dev->fmt_cap->fourcc;
+       mp->colorspace   = vivid_colorspace_cap(dev);
+       mp->num_planes = dev->fmt_cap->planes;
+       for (p = 0; p < mp->num_planes; p++) {
+               mp->plane_fmt[p].bytesperline = tpg_g_bytesperline(&dev->tpg, p);
+               mp->plane_fmt[p].sizeimage =
+                       mp->plane_fmt[p].bytesperline * mp->height +
+                       dev->fmt_cap->data_offset[p];
+       }
+       return 0;
+}
+
+int vivid_try_fmt_vid_cap(struct file *file, void *priv,
+                       struct v4l2_format *f)
+{
+       struct v4l2_pix_format_mplane *mp = &f->fmt.pix_mp;
+       struct v4l2_plane_pix_format *pfmt = mp->plane_fmt;
+       struct vivid_dev *dev = video_drvdata(file);
+       const struct vivid_fmt *fmt;
+       unsigned bytesperline, max_bpl;
+       unsigned factor = 1;
+       unsigned w, h;
+       unsigned p;
+
+       fmt = vivid_get_format(dev, mp->pixelformat);
+       if (!fmt) {
+               dprintk(dev, 1, "Fourcc format (0x%08x) unknown.\n",
+                       mp->pixelformat);
+               mp->pixelformat = V4L2_PIX_FMT_YUYV;
+               fmt = vivid_get_format(dev, mp->pixelformat);
+       }
+
+       mp->field = vivid_field_cap(dev, mp->field);
+       if (vivid_is_webcam(dev)) {
+               const struct v4l2_frmsize_discrete *sz =
+                       v4l2_find_nearest_format(&webcam_probe, mp->width, mp->height);
+
+               w = sz->width;
+               h = sz->height;
+       } else if (vivid_is_sdtv_cap(dev)) {
+               w = 720;
+               h = (dev->std_cap & V4L2_STD_525_60) ? 480 : 576;
+       } else {
+               w = dev->src_rect.width;
+               h = dev->src_rect.height;
+       }
+       if (V4L2_FIELD_HAS_T_OR_B(mp->field))
+               factor = 2;
+       if (vivid_is_webcam(dev) ||
+           (!dev->has_scaler_cap && !dev->has_crop_cap && !dev->has_compose_cap)) {
+               mp->width = w;
+               mp->height = h / factor;
+       } else {
+               struct v4l2_rect r = { 0, 0, mp->width, mp->height * factor };
+
+               rect_set_min_size(&r, &vivid_min_rect);
+               rect_set_max_size(&r, &vivid_max_rect);
+               if (dev->has_scaler_cap && !dev->has_compose_cap) {
+                       struct v4l2_rect max_r = { 0, 0, MAX_ZOOM * w, MAX_ZOOM * h };
+
+                       rect_set_max_size(&r, &max_r);
+               } else if (!dev->has_scaler_cap && dev->has_crop_cap && !dev->has_compose_cap) {
+                       rect_set_max_size(&r, &dev->src_rect);
+               } else if (!dev->has_scaler_cap && !dev->has_crop_cap) {
+                       rect_set_min_size(&r, &dev->src_rect);
+               }
+               mp->width = r.width;
+               mp->height = r.height / factor;
+       }
+
+       /* This driver supports custom bytesperline values */
+
+       /* Calculate the minimum supported bytesperline value */
+       bytesperline = (mp->width * fmt->depth) >> 3;
+       /* Calculate the maximum supported bytesperline value */
+       max_bpl = (MAX_ZOOM * MAX_WIDTH * fmt->depth) >> 3;
+       mp->num_planes = fmt->planes;
+       for (p = 0; p < mp->num_planes; p++) {
+               if (pfmt[p].bytesperline > max_bpl)
+                       pfmt[p].bytesperline = max_bpl;
+               if (pfmt[p].bytesperline < bytesperline)
+                       pfmt[p].bytesperline = bytesperline;
+               pfmt[p].sizeimage = pfmt[p].bytesperline * mp->height +
+                       fmt->data_offset[p];
+               memset(pfmt[p].reserved, 0, sizeof(pfmt[p].reserved));
+       }
+       mp->colorspace = vivid_colorspace_cap(dev);
+       memset(mp->reserved, 0, sizeof(mp->reserved));
+       return 0;
+}
+
+int vivid_s_fmt_vid_cap(struct file *file, void *priv,
+                                       struct v4l2_format *f)
+{
+       struct v4l2_pix_format_mplane *mp = &f->fmt.pix_mp;
+       struct vivid_dev *dev = video_drvdata(file);
+       struct v4l2_rect *crop = &dev->crop_cap;
+       struct v4l2_rect *compose = &dev->compose_cap;
+       struct vb2_queue *q = &dev->vb_vid_cap_q;
+       int ret = vivid_try_fmt_vid_cap(file, priv, f);
+       unsigned factor = 1;
+       unsigned i;
+
+       if (ret < 0)
+               return ret;
+
+       if (vb2_is_busy(q)) {
+               dprintk(dev, 1, "%s device busy\n", __func__);
+               return -EBUSY;
+       }
+
+       if (dev->overlay_cap_owner && dev->fb_cap.fmt.pixelformat != mp->pixelformat) {
+               dprintk(dev, 1, "overlay is active, can't change pixelformat\n");
+               return -EBUSY;
+       }
+
+       dev->fmt_cap = vivid_get_format(dev, mp->pixelformat);
+       if (V4L2_FIELD_HAS_T_OR_B(mp->field))
+               factor = 2;
+
+       /* Note: the webcam input doesn't support scaling, cropping or composing */
+
+       if (!vivid_is_webcam(dev) &&
+           (dev->has_scaler_cap || dev->has_crop_cap || dev->has_compose_cap)) {
+               struct v4l2_rect r = { 0, 0, mp->width, mp->height };
+
+               if (dev->has_scaler_cap) {
+                       if (dev->has_compose_cap)
+                               rect_map_inside(compose, &r);
+                       else
+                               *compose = r;
+                       if (dev->has_crop_cap && !dev->has_compose_cap) {
+                               struct v4l2_rect min_r = {
+                                       0, 0,
+                                       r.width / MAX_ZOOM,
+                                       factor * r.height / MAX_ZOOM
+                               };
+                               struct v4l2_rect max_r = {
+                                       0, 0,
+                                       r.width * MAX_ZOOM,
+                                       factor * r.height * MAX_ZOOM
+                               };
+
+                               rect_set_min_size(crop, &min_r);
+                               rect_set_max_size(crop, &max_r);
+                               rect_map_inside(crop, &dev->crop_bounds_cap);
+                       } else if (dev->has_crop_cap) {
+                               struct v4l2_rect min_r = {
+                                       0, 0,
+                                       compose->width / MAX_ZOOM,
+                                       factor * compose->height / MAX_ZOOM
+                               };
+                               struct v4l2_rect max_r = {
+                                       0, 0,
+                                       compose->width * MAX_ZOOM,
+                                       factor * compose->height * MAX_ZOOM
+                               };
+
+                               rect_set_min_size(crop, &min_r);
+                               rect_set_max_size(crop, &max_r);
+                               rect_map_inside(crop, &dev->crop_bounds_cap);
+                       }
+               } else if (dev->has_crop_cap && !dev->has_compose_cap) {
+                       r.height *= factor;
+                       rect_set_size_to(crop, &r);
+                       rect_map_inside(crop, &dev->crop_bounds_cap);
+                       r = *crop;
+                       r.height /= factor;
+                       rect_set_size_to(compose, &r);
+               } else if (!dev->has_crop_cap) {
+                       rect_map_inside(compose, &r);
+               } else {
+                       r.height *= factor;
+                       rect_set_max_size(crop, &r);
+                       rect_map_inside(crop, &dev->crop_bounds_cap);
+                       compose->top *= factor;
+                       compose->height *= factor;
+                       rect_set_size_to(compose, crop);
+                       rect_map_inside(compose, &r);
+                       compose->top /= factor;
+                       compose->height /= factor;
+               }
+       } else if (vivid_is_webcam(dev)) {
+               /* Guaranteed to be a match */
+               for (i = 0; i < ARRAY_SIZE(webcam_sizes); i++)
+                       if (webcam_sizes[i].width == mp->width &&
+                                       webcam_sizes[i].height == mp->height)
+                               break;
+               dev->webcam_size_idx = i;
+               if (dev->webcam_ival_idx >= 2 * (3 - i))
+                       dev->webcam_ival_idx = 2 * (3 - i) - 1;
+               vivid_update_format_cap(dev, false);
+       } else {
+               struct v4l2_rect r = { 0, 0, mp->width, mp->height };
+
+               rect_set_size_to(compose, &r);
+               r.height *= factor;
+               rect_set_size_to(crop, &r);
+       }
+
+       dev->fmt_cap_rect.width = mp->width;
+       dev->fmt_cap_rect.height = mp->height;
+       tpg_s_buf_height(&dev->tpg, mp->height);
+       tpg_s_bytesperline(&dev->tpg, 0, mp->plane_fmt[0].bytesperline);
+       if (tpg_g_planes(&dev->tpg) > 1)
+               tpg_s_bytesperline(&dev->tpg, 1, mp->plane_fmt[1].bytesperline);
+       dev->field_cap = mp->field;
+       tpg_s_field(&dev->tpg, dev->field_cap);
+       tpg_s_crop_compose(&dev->tpg, &dev->crop_cap, &dev->compose_cap);
+       tpg_s_fourcc(&dev->tpg, dev->fmt_cap->fourcc);
+       if (vivid_is_sdtv_cap(dev))
+               dev->tv_field_cap = mp->field;
+       tpg_update_mv_step(&dev->tpg);
+       return 0;
+}
+
+int vidioc_g_fmt_vid_cap_mplane(struct file *file, void *priv,
+                                       struct v4l2_format *f)
+{
+       struct vivid_dev *dev = video_drvdata(file);
+
+       if (!dev->multiplanar)
+               return -ENOTTY;
+       return vivid_g_fmt_vid_cap(file, priv, f);
+}
+
+int vidioc_try_fmt_vid_cap_mplane(struct file *file, void *priv,
+                       struct v4l2_format *f)
+{
+       struct vivid_dev *dev = video_drvdata(file);
+
+       if (!dev->multiplanar)
+               return -ENOTTY;
+       return vivid_try_fmt_vid_cap(file, priv, f);
+}
+
+int vidioc_s_fmt_vid_cap_mplane(struct file *file, void *priv,
+                       struct v4l2_format *f)
+{
+       struct vivid_dev *dev = video_drvdata(file);
+
+       if (!dev->multiplanar)
+               return -ENOTTY;
+       return vivid_s_fmt_vid_cap(file, priv, f);
+}
+
+int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
+                                       struct v4l2_format *f)
+{
+       struct vivid_dev *dev = video_drvdata(file);
+
+       if (dev->multiplanar)
+               return -ENOTTY;
+       return fmt_sp2mp_func(file, priv, f, vivid_g_fmt_vid_cap);
+}
+
+int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
+                       struct v4l2_format *f)
+{
+       struct vivid_dev *dev = video_drvdata(file);
+
+       if (dev->multiplanar)
+               return -ENOTTY;
+       return fmt_sp2mp_func(file, priv, f, vivid_try_fmt_vid_cap);
+}
+
+int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
+                       struct v4l2_format *f)
+{
+       struct vivid_dev *dev = video_drvdata(file);
+
+       if (dev->multiplanar)
+               return -ENOTTY;
+       return fmt_sp2mp_func(file, priv, f, vivid_s_fmt_vid_cap);
+}
+
+int vivid_vid_cap_g_selection(struct file *file, void *priv,
+                             struct v4l2_selection *sel)
+{
+       struct vivid_dev *dev = video_drvdata(file);
+
+       if (!dev->has_crop_cap && !dev->has_compose_cap)
+               return -ENOTTY;
+       if (sel->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               return -EINVAL;
+       if (vivid_is_webcam(dev))
+               return -EINVAL;
+
+       sel->r.left = sel->r.top = 0;
+       switch (sel->target) {
+       case V4L2_SEL_TGT_CROP:
+               if (!dev->has_crop_cap)
+                       return -EINVAL;
+               sel->r = dev->crop_cap;
+               break;
+       case V4L2_SEL_TGT_CROP_DEFAULT:
+       case V4L2_SEL_TGT_CROP_BOUNDS:
+               if (!dev->has_crop_cap)
+                       return -EINVAL;
+               sel->r = dev->src_rect;
+               break;
+       case V4L2_SEL_TGT_COMPOSE_BOUNDS:
+               if (!dev->has_compose_cap)
+                       return -EINVAL;
+               sel->r = vivid_max_rect;
+               break;
+       case V4L2_SEL_TGT_COMPOSE:
+               if (!dev->has_compose_cap)
+                       return -EINVAL;
+               sel->r = dev->compose_cap;
+               break;
+       case V4L2_SEL_TGT_COMPOSE_DEFAULT:
+               if (!dev->has_compose_cap)
+                       return -EINVAL;
+               sel->r = dev->fmt_cap_rect;
+               break;
+       default:
+               return -EINVAL;
+       }
+       return 0;
+}
+
+int vivid_vid_cap_s_selection(struct file *file, void *fh, struct v4l2_selection *s)
+{
+       struct vivid_dev *dev = video_drvdata(file);
+       struct v4l2_rect *crop = &dev->crop_cap;
+       struct v4l2_rect *compose = &dev->compose_cap;
+       unsigned factor = V4L2_FIELD_HAS_T_OR_B(dev->field_cap) ? 2 : 1;
+       int ret;
+
+       if (!dev->has_crop_cap && !dev->has_compose_cap)
+               return -ENOTTY;
+       if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               return -EINVAL;
+       if (vivid_is_webcam(dev))
+               return -EINVAL;
+
+       switch (s->target) {
+       case V4L2_SEL_TGT_CROP:
+               if (!dev->has_crop_cap)
+                       return -EINVAL;
+               ret = vivid_vid_adjust_sel(s->flags, &s->r);
+               if (ret)
+                       return ret;
+               rect_set_min_size(&s->r, &vivid_min_rect);
+               rect_set_max_size(&s->r, &dev->src_rect);
+               rect_map_inside(&s->r, &dev->crop_bounds_cap);
+               s->r.top /= factor;
+               s->r.height /= factor;
+               if (dev->has_scaler_cap) {
+                       struct v4l2_rect fmt = dev->fmt_cap_rect;
+                       struct v4l2_rect max_rect = {
+                               0, 0,
+                               s->r.width * MAX_ZOOM,
+                               s->r.height * MAX_ZOOM
+                       };
+                       struct v4l2_rect min_rect = {
+                               0, 0,
+                               s->r.width / MAX_ZOOM,
+                               s->r.height / MAX_ZOOM
+                       };
+
+                       rect_set_min_size(&fmt, &min_rect);
+                       if (!dev->has_compose_cap)
+                               rect_set_max_size(&fmt, &max_rect);
+                       if (!rect_same_size(&dev->fmt_cap_rect, &fmt) &&
+                           vb2_is_busy(&dev->vb_vid_cap_q))
+                               return -EBUSY;
+                       if (dev->has_compose_cap) {
+                               rect_set_min_size(compose, &min_rect);
+                               rect_set_max_size(compose, &max_rect);
+                       }
+                       dev->fmt_cap_rect = fmt;
+                       tpg_s_buf_height(&dev->tpg, fmt.height);
+               } else if (dev->has_compose_cap) {
+                       struct v4l2_rect fmt = dev->fmt_cap_rect;
+
+                       rect_set_min_size(&fmt, &s->r);
+                       if (!rect_same_size(&dev->fmt_cap_rect, &fmt) &&
+                           vb2_is_busy(&dev->vb_vid_cap_q))
+                               return -EBUSY;
+                       dev->fmt_cap_rect = fmt;
+                       tpg_s_buf_height(&dev->tpg, fmt.height);
+                       rect_set_size_to(compose, &s->r);
+                       rect_map_inside(compose, &dev->fmt_cap_rect);
+               } else {
+                       if (!rect_same_size(&s->r, &dev->fmt_cap_rect) &&
+                           vb2_is_busy(&dev->vb_vid_cap_q))
+                               return -EBUSY;
+                       rect_set_size_to(&dev->fmt_cap_rect, &s->r);
+                       rect_set_size_to(compose, &s->r);
+                       rect_map_inside(compose, &dev->fmt_cap_rect);
+                       tpg_s_buf_height(&dev->tpg, dev->fmt_cap_rect.height);
+               }
+               s->r.top *= factor;
+               s->r.height *= factor;
+               *crop = s->r;
+               break;
+       case V4L2_SEL_TGT_COMPOSE:
+               if (!dev->has_compose_cap)
+                       return -EINVAL;
+               ret = vivid_vid_adjust_sel(s->flags, &s->r);
+               if (ret)
+                       return ret;
+               rect_set_min_size(&s->r, &vivid_min_rect);
+               rect_set_max_size(&s->r, &dev->fmt_cap_rect);
+               if (dev->has_scaler_cap) {
+                       struct v4l2_rect max_rect = {
+                               0, 0,
+                               dev->src_rect.width * MAX_ZOOM,
+                               (dev->src_rect.height / factor) * MAX_ZOOM
+                       };
+
+                       rect_set_max_size(&s->r, &max_rect);
+                       if (dev->has_crop_cap) {
+                               struct v4l2_rect min_rect = {
+                                       0, 0,
+                                       s->r.width / MAX_ZOOM,
+                                       (s->r.height * factor) / MAX_ZOOM
+                               };
+                               struct v4l2_rect max_rect = {
+                                       0, 0,
+                                       s->r.width * MAX_ZOOM,
+                                       (s->r.height * factor) * MAX_ZOOM
+                               };
+
+                               rect_set_min_size(crop, &min_rect);
+                               rect_set_max_size(crop, &max_rect);
+                               rect_map_inside(crop, &dev->crop_bounds_cap);
+                       }
+               } else if (dev->has_crop_cap) {
+                       s->r.top *= factor;
+                       s->r.height *= factor;
+                       rect_set_max_size(&s->r, &dev->src_rect);
+                       rect_set_size_to(crop, &s->r);
+                       rect_map_inside(crop, &dev->crop_bounds_cap);
+                       s->r.top /= factor;
+                       s->r.height /= factor;
+               } else {
+                       rect_set_size_to(&s->r, &dev->src_rect);
+                       s->r.height /= factor;
+               }
+               rect_map_inside(&s->r, &dev->fmt_cap_rect);
+               if (dev->bitmap_cap && (compose->width != s->r.width ||
+                                       compose->height != s->r.height)) {
+                       kfree(dev->bitmap_cap);
+                       dev->bitmap_cap = NULL;
+               }
+               *compose = s->r;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       tpg_s_crop_compose(&dev->tpg, crop, compose);
+       return 0;
+}
+
+int vivid_vid_cap_cropcap(struct file *file, void *priv,
+                             struct v4l2_cropcap *cap)
+{
+       struct vivid_dev *dev = video_drvdata(file);
+
+       if (cap->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               return -EINVAL;
+
+       switch (vivid_get_pixel_aspect(dev)) {
+       case TPG_PIXEL_ASPECT_NTSC:
+               cap->pixelaspect.numerator = 11;
+               cap->pixelaspect.denominator = 10;
+               break;
+       case TPG_PIXEL_ASPECT_PAL:
+               cap->pixelaspect.numerator = 54;
+               cap->pixelaspect.denominator = 59;
+               break;
+       case TPG_PIXEL_ASPECT_SQUARE:
+               cap->pixelaspect.numerator = 1;
+               cap->pixelaspect.denominator = 1;
+               break;
+       }
+       return 0;
+}
+
+int vidioc_enum_fmt_vid_overlay(struct file *file, void  *priv,
+                                       struct v4l2_fmtdesc *f)
+{
+       const struct vivid_fmt *fmt;
+
+       if (f->index >= ARRAY_SIZE(formats_ovl))
+               return -EINVAL;
+
+       fmt = &formats_ovl[f->index];
+
+       strlcpy(f->description, fmt->name, sizeof(f->description));
+       f->pixelformat = fmt->fourcc;
+       return 0;
+}
+
+int vidioc_g_fmt_vid_overlay(struct file *file, void *priv,
+                                       struct v4l2_format *f)
+{
+       struct vivid_dev *dev = video_drvdata(file);
+       const struct v4l2_rect *compose = &dev->compose_cap;
+       struct v4l2_window *win = &f->fmt.win;
+       unsigned clipcount = win->clipcount;
+
+       win->w.top = dev->overlay_cap_top;
+       win->w.left = dev->overlay_cap_left;
+       win->w.width = compose->width;
+       win->w.height = compose->height;
+       win->field = dev->overlay_cap_field;
+       win->clipcount = dev->clipcount_cap;
+       if (clipcount > dev->clipcount_cap)
+               clipcount = dev->clipcount_cap;
+       if (dev->bitmap_cap == NULL)
+               win->bitmap = NULL;
+       else if (win->bitmap) {
+               if (copy_to_user(win->bitmap, dev->bitmap_cap,
+                   ((compose->width + 7) / 8) * compose->height))
+                       return -EFAULT;
+       }
+       if (clipcount && win->clips) {
+               if (copy_to_user(win->clips, dev->clips_cap,
+                                clipcount * sizeof(dev->clips_cap[0])))
+                       return -EFAULT;
+       }
+       return 0;
+}
+
+int vidioc_try_fmt_vid_overlay(struct file *file, void *priv,
+                                       struct v4l2_format *f)
+{
+       struct vivid_dev *dev = video_drvdata(file);
+       const struct v4l2_rect *compose = &dev->compose_cap;
+       struct v4l2_window *win = &f->fmt.win;
+       int i, j;
+
+       win->w.left = clamp_t(int, win->w.left,
+                             -dev->fb_cap.fmt.width, dev->fb_cap.fmt.width);
+       win->w.top = clamp_t(int, win->w.top,
+                            -dev->fb_cap.fmt.height, dev->fb_cap.fmt.height);
+       win->w.width = compose->width;
+       win->w.height = compose->height;
+       if (win->field != V4L2_FIELD_BOTTOM && win->field != V4L2_FIELD_TOP)
+               win->field = V4L2_FIELD_ANY;
+       win->chromakey = 0;
+       win->global_alpha = 0;
+       if (win->clipcount && !win->clips)
+               win->clipcount = 0;
+       if (win->clipcount > MAX_CLIPS)
+               win->clipcount = MAX_CLIPS;
+       if (win->clipcount) {
+               if (copy_from_user(dev->try_clips_cap, win->clips,
+                                  win->clipcount * sizeof(dev->clips_cap[0])))
+                       return -EFAULT;
+               for (i = 0; i < win->clipcount; i++) {
+                       struct v4l2_rect *r = &dev->try_clips_cap[i].c;
+
+                       r->top = clamp_t(s32, r->top, 0, dev->fb_cap.fmt.height - 1);
+                       r->height = clamp_t(s32, r->height, 1, dev->fb_cap.fmt.height - r->top);
+                       r->left = clamp_t(u32, r->left, 0, dev->fb_cap.fmt.width - 1);
+                       r->width = clamp_t(u32, r->width, 1, dev->fb_cap.fmt.width - r->left);
+               }
+               /*
+                * Yeah, so sue me, it's an O(n^2) algorithm. But n is a small
+                * number and it's typically a one-time deal.
+                */
+               for (i = 0; i < win->clipcount - 1; i++) {
+                       struct v4l2_rect *r1 = &dev->try_clips_cap[i].c;
+
+                       for (j = i + 1; j < win->clipcount; j++) {
+                               struct v4l2_rect *r2 = &dev->try_clips_cap[j].c;
+
+                               if (rect_overlap(r1, r2))
+                                       return -EINVAL;
+                       }
+               }
+               if (copy_to_user(win->clips, dev->try_clips_cap,
+                                win->clipcount * sizeof(dev->clips_cap[0])))
+                       return -EFAULT;
+       }
+       return 0;
+}
+
+int vidioc_s_fmt_vid_overlay(struct file *file, void *priv,
+                                       struct v4l2_format *f)
+{
+       struct vivid_dev *dev = video_drvdata(file);
+       const struct v4l2_rect *compose = &dev->compose_cap;
+       struct v4l2_window *win = &f->fmt.win;
+       int ret = vidioc_try_fmt_vid_overlay(file, priv, f);
+       unsigned bitmap_size = ((compose->width + 7) / 8) * compose->height;
+       unsigned clips_size = win->clipcount * sizeof(dev->clips_cap[0]);
+       void *new_bitmap = NULL;
+
+       if (ret)
+               return ret;
+
+       if (win->bitmap) {
+               new_bitmap = vzalloc(bitmap_size);
+
+               if (new_bitmap == NULL)
+                       return -ENOMEM;
+               if (copy_from_user(new_bitmap, win->bitmap, bitmap_size)) {
+                       vfree(new_bitmap);
+                       return -EFAULT;
+               }
+       }
+
+       dev->overlay_cap_top = win->w.top;
+       dev->overlay_cap_left = win->w.left;
+       dev->overlay_cap_field = win->field;
+       vfree(dev->bitmap_cap);
+       dev->bitmap_cap = new_bitmap;
+       dev->clipcount_cap = win->clipcount;
+       if (dev->clipcount_cap)
+               memcpy(dev->clips_cap, dev->try_clips_cap, clips_size);
+       return 0;
+}
+
+int vivid_vid_cap_overlay(struct file *file, void *fh, unsigned i)
+{
+       struct vivid_dev *dev = video_drvdata(file);
+
+       if (i && dev->fb_vbase_cap == NULL)
+               return -EINVAL;
+
+       if (i && dev->fb_cap.fmt.pixelformat != dev->fmt_cap->fourcc) {
+               dprintk(dev, 1, "mismatch between overlay and video capture pixelformats\n");
+               return -EINVAL;
+       }
+
+       if (dev->overlay_cap_owner && dev->overlay_cap_owner != fh)
+               return -EBUSY;
+       dev->overlay_cap_owner = i ? fh : NULL;
+       return 0;
+}
+
+int vivid_vid_cap_g_fbuf(struct file *file, void *fh,
+                               struct v4l2_framebuffer *a)
+{
+       struct vivid_dev *dev = video_drvdata(file);
+
+       *a = dev->fb_cap;
+       a->capability = V4L2_FBUF_CAP_BITMAP_CLIPPING |
+                       V4L2_FBUF_CAP_LIST_CLIPPING;
+       a->flags = V4L2_FBUF_FLAG_PRIMARY;
+       a->fmt.field = V4L2_FIELD_NONE;
+       a->fmt.colorspace = V4L2_COLORSPACE_SRGB;
+       a->fmt.priv = 0;
+       return 0;
+}
+
+int vivid_vid_cap_s_fbuf(struct file *file, void *fh,
+                               const struct v4l2_framebuffer *a)
+{
+       struct vivid_dev *dev = video_drvdata(file);
+       const struct vivid_fmt *fmt;
+
+       if (!capable(CAP_SYS_ADMIN) && !capable(CAP_SYS_RAWIO))
+               return -EPERM;
+
+       if (dev->overlay_cap_owner)
+               return -EBUSY;
+
+       if (a->base == NULL) {
+               dev->fb_cap.base = NULL;
+               dev->fb_vbase_cap = NULL;
+               return 0;
+       }
+
+       if (a->fmt.width < 48 || a->fmt.height < 32)
+               return -EINVAL;
+       fmt = vivid_get_format(dev, a->fmt.pixelformat);
+       if (!fmt || !fmt->can_do_overlay)
+               return -EINVAL;
+       if (a->fmt.bytesperline < (a->fmt.width * fmt->depth) / 8)
+               return -EINVAL;
+       if (a->fmt.height * a->fmt.bytesperline < a->fmt.sizeimage)
+               return -EINVAL;
+
+       dev->fb_vbase_cap = phys_to_virt((unsigned long)a->base);
+       dev->fb_cap = *a;
+       dev->overlay_cap_left = clamp_t(int, dev->overlay_cap_left,
+                                   -dev->fb_cap.fmt.width, dev->fb_cap.fmt.width);
+       dev->overlay_cap_top = clamp_t(int, dev->overlay_cap_top,
+                                  -dev->fb_cap.fmt.height, dev->fb_cap.fmt.height);
+       return 0;
+}
+
+static const struct v4l2_audio vivid_audio_inputs[] = {
+       { 0, "TV", V4L2_AUDCAP_STEREO },
+       { 1, "Line-In", V4L2_AUDCAP_STEREO },
+};
+
+int vidioc_enum_input(struct file *file, void *priv,
+                               struct v4l2_input *inp)
+{
+       struct vivid_dev *dev = video_drvdata(file);
+
+       if (inp->index >= dev->num_inputs)
+               return -EINVAL;
+
+       inp->type = V4L2_INPUT_TYPE_CAMERA;
+       switch (dev->input_type[inp->index]) {
+       case WEBCAM:
+               snprintf(inp->name, sizeof(inp->name), "Webcam %u",
+                               dev->input_name_counter[inp->index]);
+               inp->capabilities = 0;
+               break;
+       case TV:
+               snprintf(inp->name, sizeof(inp->name), "TV %u",
+                               dev->input_name_counter[inp->index]);
+               inp->type = V4L2_INPUT_TYPE_TUNER;
+               inp->std = V4L2_STD_ALL;
+               if (dev->has_audio_inputs)
+                       inp->audioset = (1 << ARRAY_SIZE(vivid_audio_inputs)) - 1;
+               inp->capabilities = V4L2_IN_CAP_STD;
+               break;
+       case SVID:
+               snprintf(inp->name, sizeof(inp->name), "S-Video %u",
+                               dev->input_name_counter[inp->index]);
+               inp->std = V4L2_STD_ALL;
+               if (dev->has_audio_inputs)
+                       inp->audioset = (1 << ARRAY_SIZE(vivid_audio_inputs)) - 1;
+               inp->capabilities = V4L2_IN_CAP_STD;
+               break;
+       case HDMI:
+               snprintf(inp->name, sizeof(inp->name), "HDMI %u",
+                               dev->input_name_counter[inp->index]);
+               inp->capabilities = V4L2_IN_CAP_DV_TIMINGS;
+               if (dev->edid_blocks == 0 ||
+                   dev->dv_timings_signal_mode == NO_SIGNAL)
+                       inp->status |= V4L2_IN_ST_NO_SIGNAL;
+               else if (dev->dv_timings_signal_mode == NO_LOCK ||
+                        dev->dv_timings_signal_mode == OUT_OF_RANGE)
+                       inp->status |= V4L2_IN_ST_NO_H_LOCK;
+               break;
+       }
+       if (dev->sensor_hflip)
+               inp->status |= V4L2_IN_ST_HFLIP;
+       if (dev->sensor_vflip)
+               inp->status |= V4L2_IN_ST_VFLIP;
+       if (dev->input == inp->index && vivid_is_sdtv_cap(dev)) {
+               if (dev->std_signal_mode == NO_SIGNAL) {
+                       inp->status |= V4L2_IN_ST_NO_SIGNAL;
+               } else if (dev->std_signal_mode == NO_LOCK) {
+                       inp->status |= V4L2_IN_ST_NO_H_LOCK;
+               } else if (vivid_is_tv_cap(dev)) {
+                       switch (tpg_g_quality(&dev->tpg)) {
+                       case TPG_QUAL_GRAY:
+                               inp->status |= V4L2_IN_ST_COLOR_KILL;
+                               break;
+                       case TPG_QUAL_NOISE:
+                               inp->status |= V4L2_IN_ST_NO_H_LOCK;
+                               break;
+                       default:
+                               break;
+                       }
+               }
+       }
+       return 0;
+}
+
+int vidioc_g_input(struct file *file, void *priv, unsigned *i)
+{
+       struct vivid_dev *dev = video_drvdata(file);
+
+       *i = dev->input;
+       return 0;
+}
+
+int vidioc_s_input(struct file *file, void *priv, unsigned i)
+{
+       struct vivid_dev *dev = video_drvdata(file);
+       struct v4l2_bt_timings *bt = &dev->dv_timings_cap.bt;
+       unsigned brightness;
+
+       if (i >= dev->num_inputs)
+               return -EINVAL;
+
+       if (i == dev->input)
+               return 0;
+
+       if (vb2_is_busy(&dev->vb_vid_cap_q) || vb2_is_busy(&dev->vb_vbi_cap_q))
+               return -EBUSY;
+
+       dev->input = i;
+       dev->vid_cap_dev.tvnorms = 0;
+       if (dev->input_type[i] == TV || dev->input_type[i] == SVID) {
+               dev->tv_audio_input = (dev->input_type[i] == TV) ? 0 : 1;
+               dev->vid_cap_dev.tvnorms = V4L2_STD_ALL;
+       }
+       dev->vbi_cap_dev.tvnorms = dev->vid_cap_dev.tvnorms;
+       vivid_update_format_cap(dev, false);
+
+       if (dev->colorspace) {
+               switch (dev->input_type[i]) {
+               case WEBCAM:
+                       v4l2_ctrl_s_ctrl(dev->colorspace, V4L2_COLORSPACE_SRGB);
+                       break;
+               case TV:
+               case SVID:
+                       v4l2_ctrl_s_ctrl(dev->colorspace, V4L2_COLORSPACE_SMPTE170M);
+                       break;
+               case HDMI:
+                       if (bt->standards & V4L2_DV_BT_STD_CEA861) {
+                               if (dev->src_rect.width == 720 && dev->src_rect.height <= 576)
+                                       v4l2_ctrl_s_ctrl(dev->colorspace, V4L2_COLORSPACE_SMPTE170M);
+                               else
+                                       v4l2_ctrl_s_ctrl(dev->colorspace, V4L2_COLORSPACE_REC709);
+                       } else {
+                               v4l2_ctrl_s_ctrl(dev->colorspace, V4L2_COLORSPACE_SRGB);
+                       }
+                       break;
+               }
+       }
+
+       /*
+        * Modify the brightness range depending on the input.
+        * This makes it easy to use vivid to test if applications can
+        * handle control range modifications and is also how this is
+        * typically used in practice as different inputs may be hooked
+        * up to different receivers with different control ranges.
+        */
+       brightness = 128 * i + dev->input_brightness[i];
+       v4l2_ctrl_modify_range(dev->brightness,
+                       128 * i, 255 + 128 * i, 1, 128 + 128 * i);
+       v4l2_ctrl_s_ctrl(dev->brightness, brightness);
+       return 0;
+}
+
+int vidioc_enumaudio(struct file *file, void *fh, struct v4l2_audio *vin)
+{
+       if (vin->index >= ARRAY_SIZE(vivid_audio_inputs))
+               return -EINVAL;
+       *vin = vivid_audio_inputs[vin->index];
+       return 0;
+}
+
+int vidioc_g_audio(struct file *file, void *fh, struct v4l2_audio *vin)
+{
+       struct vivid_dev *dev = video_drvdata(file);
+
+       if (!vivid_is_sdtv_cap(dev))
+               return -EINVAL;
+       *vin = vivid_audio_inputs[dev->tv_audio_input];
+       return 0;
+}
+
+int vidioc_s_audio(struct file *file, void *fh, const struct v4l2_audio *vin)
+{
+       struct vivid_dev *dev = video_drvdata(file);
+
+       if (!vivid_is_sdtv_cap(dev))
+               return -EINVAL;
+       if (vin->index >= ARRAY_SIZE(vivid_audio_inputs))
+               return -EINVAL;
+       dev->tv_audio_input = vin->index;
+       return 0;
+}
+
+int vivid_video_g_frequency(struct file *file, void *fh, struct v4l2_frequency *vf)
+{
+       struct vivid_dev *dev = video_drvdata(file);
+
+       if (vf->tuner != 0)
+               return -EINVAL;
+       vf->frequency = dev->tv_freq;
+       return 0;
+}
+
+int vivid_video_s_frequency(struct file *file, void *fh, const struct v4l2_frequency *vf)
+{
+       struct vivid_dev *dev = video_drvdata(file);
+
+       if (vf->tuner != 0)
+               return -EINVAL;
+       dev->tv_freq = clamp_t(unsigned, vf->frequency, MIN_TV_FREQ, MAX_TV_FREQ);
+       if (vivid_is_tv_cap(dev))
+               vivid_update_quality(dev);
+       return 0;
+}
+
+int vivid_video_s_tuner(struct file *file, void *fh, const struct v4l2_tuner *vt)
+{
+       struct vivid_dev *dev = video_drvdata(file);
+
+       if (vt->index != 0)
+               return -EINVAL;
+       if (vt->audmode > V4L2_TUNER_MODE_LANG1_LANG2)
+               return -EINVAL;
+       dev->tv_audmode = vt->audmode;
+       return 0;
+}
+
+int vivid_video_g_tuner(struct file *file, void *fh, struct v4l2_tuner *vt)
+{
+       struct vivid_dev *dev = video_drvdata(file);
+       enum tpg_quality qual;
+
+       if (vt->index != 0)
+               return -EINVAL;
+
+       vt->capability = V4L2_TUNER_CAP_NORM | V4L2_TUNER_CAP_STEREO |
+                        V4L2_TUNER_CAP_LANG1 | V4L2_TUNER_CAP_LANG2;
+       vt->audmode = dev->tv_audmode;
+       vt->rangelow = MIN_TV_FREQ;
+       vt->rangehigh = MAX_TV_FREQ;
+       qual = vivid_get_quality(dev, &vt->afc);
+       if (qual == TPG_QUAL_COLOR)
+               vt->signal = 0xffff;
+       else if (qual == TPG_QUAL_GRAY)
+               vt->signal = 0x8000;
+       else
+               vt->signal = 0;
+       if (qual == TPG_QUAL_NOISE) {
+               vt->rxsubchans = 0;
+       } else if (qual == TPG_QUAL_GRAY) {
+               vt->rxsubchans = V4L2_TUNER_SUB_MONO;
+       } else {
+               unsigned channel_nr = dev->tv_freq / (6 * 16);
+               unsigned options = (dev->std_cap & V4L2_STD_NTSC_M) ? 4 : 3;
+
+               switch (channel_nr % options) {
+               case 0:
+                       vt->rxsubchans = V4L2_TUNER_SUB_MONO;
+                       break;
+               case 1:
+                       vt->rxsubchans = V4L2_TUNER_SUB_STEREO;
+                       break;
+               case 2:
+                       if (dev->std_cap & V4L2_STD_NTSC_M)
+                               vt->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_SAP;
+                       else
+                               vt->rxsubchans = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2;
+                       break;
+               case 3:
+                       vt->rxsubchans = V4L2_TUNER_SUB_STEREO | V4L2_TUNER_SUB_SAP;
+                       break;
+               }
+       }
+       strlcpy(vt->name, "TV Tuner", sizeof(vt->name));
+       return 0;
+}
+
+/* Must remain in sync with the vivid_ctrl_standard_strings array */
+const v4l2_std_id vivid_standard[] = {
+       V4L2_STD_NTSC_M,
+       V4L2_STD_NTSC_M_JP,
+       V4L2_STD_NTSC_M_KR,
+       V4L2_STD_NTSC_443,
+       V4L2_STD_PAL_BG | V4L2_STD_PAL_H,
+       V4L2_STD_PAL_I,
+       V4L2_STD_PAL_DK,
+       V4L2_STD_PAL_M,
+       V4L2_STD_PAL_N,
+       V4L2_STD_PAL_Nc,
+       V4L2_STD_PAL_60,
+       V4L2_STD_SECAM_B | V4L2_STD_SECAM_G | V4L2_STD_SECAM_H,
+       V4L2_STD_SECAM_DK,
+       V4L2_STD_SECAM_L,
+       V4L2_STD_SECAM_LC,
+       V4L2_STD_UNKNOWN
+};
+
+/* Must remain in sync with the vivid_standard array */
+const char * const vivid_ctrl_standard_strings[] = {
+       "NTSC-M",
+       "NTSC-M-JP",
+       "NTSC-M-KR",
+       "NTSC-443",
+       "PAL-BGH",
+       "PAL-I",
+       "PAL-DK",
+       "PAL-M",
+       "PAL-N",
+       "PAL-Nc",
+       "PAL-60",
+       "SECAM-BGH",
+       "SECAM-DK",
+       "SECAM-L",
+       "SECAM-Lc",
+       NULL,
+};
+
+int vidioc_querystd(struct file *file, void *priv, v4l2_std_id *id)
+{
+       struct vivid_dev *dev = video_drvdata(file);
+
+       if (!vivid_is_sdtv_cap(dev))
+               return -ENODATA;
+       if (dev->std_signal_mode == NO_SIGNAL ||
+           dev->std_signal_mode == NO_LOCK) {
+               *id = V4L2_STD_UNKNOWN;
+               return 0;
+       }
+       if (vivid_is_tv_cap(dev) && tpg_g_quality(&dev->tpg) == TPG_QUAL_NOISE) {
+               *id = V4L2_STD_UNKNOWN;
+       } else if (dev->std_signal_mode == CURRENT_STD) {
+               *id = dev->std_cap;
+       } else if (dev->std_signal_mode == SELECTED_STD) {
+               *id = dev->query_std;
+       } else {
+               *id = vivid_standard[dev->query_std_last];
+               dev->query_std_last = (dev->query_std_last + 1) % ARRAY_SIZE(vivid_standard);
+       }
+
+       return 0;
+}
+
+int vivid_vid_cap_s_std(struct file *file, void *priv, v4l2_std_id id)
+{
+       struct vivid_dev *dev = video_drvdata(file);
+
+       if (!vivid_is_sdtv_cap(dev))
+               return -ENODATA;
+       if (dev->std_cap == id)
+               return 0;
+       if (vb2_is_busy(&dev->vb_vid_cap_q) || vb2_is_busy(&dev->vb_vbi_cap_q))
+               return -EBUSY;
+       dev->std_cap = id;
+       vivid_update_format_cap(dev, false);
+       return 0;
+}
+
+int vivid_vid_cap_s_dv_timings(struct file *file, void *_fh,
+                                   struct v4l2_dv_timings *timings)
+{
+       struct vivid_dev *dev = video_drvdata(file);
+
+       if (!vivid_is_hdmi_cap(dev))
+               return -ENODATA;
+       if (vb2_is_busy(&dev->vb_vid_cap_q))
+               return -EBUSY;
+       if (!v4l2_find_dv_timings_cap(timings, &vivid_dv_timings_cap,
+                               0, NULL, NULL))
+               return -EINVAL;
+       if (v4l2_match_dv_timings(timings, &dev->dv_timings_cap, 0))
+               return 0;
+       dev->dv_timings_cap = *timings;
+       vivid_update_format_cap(dev, false);
+       return 0;
+}
+
+int vidioc_query_dv_timings(struct file *file, void *_fh,
+                                   struct v4l2_dv_timings *timings)
+{
+       struct vivid_dev *dev = video_drvdata(file);
+
+       if (!vivid_is_hdmi_cap(dev))
+               return -ENODATA;
+       if (dev->dv_timings_signal_mode == NO_SIGNAL ||
+           dev->edid_blocks == 0)
+               return -ENOLINK;
+       if (dev->dv_timings_signal_mode == NO_LOCK)
+               return -ENOLCK;
+       if (dev->dv_timings_signal_mode == OUT_OF_RANGE) {
+               timings->bt.pixelclock = vivid_dv_timings_cap.bt.max_pixelclock * 2;
+               return -ERANGE;
+       }
+       if (dev->dv_timings_signal_mode == CURRENT_DV_TIMINGS) {
+               *timings = dev->dv_timings_cap;
+       } else if (dev->dv_timings_signal_mode == SELECTED_DV_TIMINGS) {
+               *timings = v4l2_dv_timings_presets[dev->query_dv_timings];
+       } else {
+               *timings = v4l2_dv_timings_presets[dev->query_dv_timings_last];
+               dev->query_dv_timings_last = (dev->query_dv_timings_last + 1) %
+                                               dev->query_dv_timings_size;
+       }
+       return 0;
+}
+
+int vidioc_s_edid(struct file *file, void *_fh,
+                        struct v4l2_edid *edid)
+{
+       struct vivid_dev *dev = video_drvdata(file);
+
+       memset(edid->reserved, 0, sizeof(edid->reserved));
+       if (edid->pad >= dev->num_inputs)
+               return -EINVAL;
+       if (dev->input_type[edid->pad] != HDMI || edid->start_block)
+               return -EINVAL;
+       if (edid->blocks == 0) {
+               dev->edid_blocks = 0;
+               return 0;
+       }
+       if (edid->blocks > dev->edid_max_blocks) {
+               edid->blocks = dev->edid_max_blocks;
+               return -E2BIG;
+       }
+       dev->edid_blocks = edid->blocks;
+       memcpy(dev->edid, edid->edid, edid->blocks * 128);
+       return 0;
+}
+
+int vidioc_enum_framesizes(struct file *file, void *fh,
+                                        struct v4l2_frmsizeenum *fsize)
+{
+       struct vivid_dev *dev = video_drvdata(file);
+
+       if (!vivid_is_webcam(dev) && !dev->has_scaler_cap)
+               return -EINVAL;
+       if (vivid_get_format(dev, fsize->pixel_format) == NULL)
+               return -EINVAL;
+       if (vivid_is_webcam(dev)) {
+               if (fsize->index >= ARRAY_SIZE(webcam_sizes))
+                       return -EINVAL;
+               fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE;
+               fsize->discrete = webcam_sizes[fsize->index];
+               return 0;
+       }
+       if (fsize->index)
+               return -EINVAL;
+       fsize->type = V4L2_FRMSIZE_TYPE_STEPWISE;
+       fsize->stepwise.min_width = MIN_WIDTH;
+       fsize->stepwise.max_width = MAX_WIDTH * MAX_ZOOM;
+       fsize->stepwise.step_width = 2;
+       fsize->stepwise.min_height = MIN_HEIGHT;
+       fsize->stepwise.max_height = MAX_HEIGHT * MAX_ZOOM;
+       fsize->stepwise.step_height = 2;
+       return 0;
+}
+
+/* timeperframe is arbitrary and continuous */
+int vidioc_enum_frameintervals(struct file *file, void *priv,
+                                            struct v4l2_frmivalenum *fival)
+{
+       struct vivid_dev *dev = video_drvdata(file);
+       const struct vivid_fmt *fmt;
+       int i;
+
+       fmt = vivid_get_format(dev, fival->pixel_format);
+       if (!fmt)
+               return -EINVAL;
+
+       if (!vivid_is_webcam(dev)) {
+               static const struct v4l2_fract step = { 1, 1 };
+
+               if (fival->index)
+                       return -EINVAL;
+               if (fival->width < MIN_WIDTH || fival->width > MAX_WIDTH * MAX_ZOOM)
+                       return -EINVAL;
+               if (fival->height < MIN_HEIGHT || fival->height > MAX_HEIGHT * MAX_ZOOM)
+                       return -EINVAL;
+               fival->type = V4L2_FRMIVAL_TYPE_CONTINUOUS;
+               fival->stepwise.min = tpf_min;
+               fival->stepwise.max = tpf_max;
+               fival->stepwise.step = step;
+               return 0;
+       }
+
+       for (i = 0; i < ARRAY_SIZE(webcam_sizes); i++)
+               if (fival->width == webcam_sizes[i].width &&
+                   fival->height == webcam_sizes[i].height)
+                       break;
+       if (i == ARRAY_SIZE(webcam_sizes))
+               return -EINVAL;
+       if (fival->index >= 2 * (3 - i))
+               return -EINVAL;
+       fival->type = V4L2_FRMIVAL_TYPE_DISCRETE;
+       fival->discrete = webcam_intervals[fival->index];
+       return 0;
+}
+
+int vivid_vid_cap_g_parm(struct file *file, void *priv,
+                         struct v4l2_streamparm *parm)
+{
+       struct vivid_dev *dev = video_drvdata(file);
+
+       if (parm->type != (dev->multiplanar ?
+                          V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE :
+                          V4L2_BUF_TYPE_VIDEO_CAPTURE))
+               return -EINVAL;
+
+       parm->parm.capture.capability   = V4L2_CAP_TIMEPERFRAME;
+       parm->parm.capture.timeperframe = dev->timeperframe_vid_cap;
+       parm->parm.capture.readbuffers  = 1;
+       return 0;
+}
+
+#define FRACT_CMP(a, OP, b)    \
+       ((u64)(a).numerator * (b).denominator  OP  (u64)(b).numerator * (a).denominator)
+
+int vivid_vid_cap_s_parm(struct file *file, void *priv,
+                         struct v4l2_streamparm *parm)
+{
+       struct vivid_dev *dev = video_drvdata(file);
+       unsigned ival_sz = 2 * (3 - dev->webcam_size_idx);
+       struct v4l2_fract tpf;
+       unsigned i;
+
+       if (parm->type != (dev->multiplanar ?
+                          V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE :
+                          V4L2_BUF_TYPE_VIDEO_CAPTURE))
+               return -EINVAL;
+       if (!vivid_is_webcam(dev))
+               return vivid_vid_cap_g_parm(file, priv, parm);
+
+       tpf = parm->parm.capture.timeperframe;
+
+       if (tpf.denominator == 0)
+               tpf = webcam_intervals[ival_sz - 1];
+       for (i = 0; i < ival_sz; i++)
+               if (FRACT_CMP(tpf, >=, webcam_intervals[i]))
+                       break;
+       if (i == ival_sz)
+               i = ival_sz - 1;
+       dev->webcam_ival_idx = i;
+       tpf = webcam_intervals[dev->webcam_ival_idx];
+       tpf = FRACT_CMP(tpf, <, tpf_min) ? tpf_min : tpf;
+       tpf = FRACT_CMP(tpf, >, tpf_max) ? tpf_max : tpf;
+
+       /* resync the thread's timings */
+       dev->cap_seq_resync = true;
+       dev->timeperframe_vid_cap = tpf;
+       parm->parm.capture.timeperframe = tpf;
+       parm->parm.capture.readbuffers  = 1;
+       return 0;
+}
diff --git a/drivers/media/platform/vivid/vivid-vid-cap.h b/drivers/media/platform/vivid/vivid-vid-cap.h
new file mode 100644 (file)
index 0000000..9407981
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+ * vivid-vid-cap.h - video capture support functions.
+ *
+ * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
+ *
+ * This program is free software; you may redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * 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 _VIVID_VID_CAP_H_
+#define _VIVID_VID_CAP_H_
+
+void vivid_update_quality(struct vivid_dev *dev);
+void vivid_update_format_cap(struct vivid_dev *dev, bool keep_controls);
+enum tpg_video_aspect vivid_get_video_aspect(const struct vivid_dev *dev);
+
+extern const v4l2_std_id vivid_standard[];
+extern const char * const vivid_ctrl_standard_strings[];
+
+extern const struct vb2_ops vivid_vid_cap_qops;
+
+int vivid_g_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f);
+int vivid_try_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f);
+int vivid_s_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f);
+int vidioc_g_fmt_vid_cap_mplane(struct file *file, void *priv, struct v4l2_format *f);
+int vidioc_try_fmt_vid_cap_mplane(struct file *file, void *priv, struct v4l2_format *f);
+int vidioc_s_fmt_vid_cap_mplane(struct file *file, void *priv, struct v4l2_format *f);
+int vidioc_g_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f);
+int vidioc_try_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f);
+int vidioc_s_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f);
+int vivid_vid_cap_g_selection(struct file *file, void *priv, struct v4l2_selection *sel);
+int vivid_vid_cap_s_selection(struct file *file, void *fh, struct v4l2_selection *s);
+int vivid_vid_cap_cropcap(struct file *file, void *priv, struct v4l2_cropcap *cap);
+int vidioc_enum_fmt_vid_overlay(struct file *file, void  *priv, struct v4l2_fmtdesc *f);
+int vidioc_g_fmt_vid_overlay(struct file *file, void *priv, struct v4l2_format *f);
+int vidioc_try_fmt_vid_overlay(struct file *file, void *priv, struct v4l2_format *f);
+int vidioc_s_fmt_vid_overlay(struct file *file, void *priv, struct v4l2_format *f);
+int vivid_vid_cap_overlay(struct file *file, void *fh, unsigned i);
+int vivid_vid_cap_g_fbuf(struct file *file, void *fh, struct v4l2_framebuffer *a);
+int vivid_vid_cap_s_fbuf(struct file *file, void *fh, const struct v4l2_framebuffer *a);
+int vidioc_enum_input(struct file *file, void *priv, struct v4l2_input *inp);
+int vidioc_g_input(struct file *file, void *priv, unsigned *i);
+int vidioc_s_input(struct file *file, void *priv, unsigned i);
+int vidioc_enumaudio(struct file *file, void *fh, struct v4l2_audio *vin);
+int vidioc_g_audio(struct file *file, void *fh, struct v4l2_audio *vin);
+int vidioc_s_audio(struct file *file, void *fh, const struct v4l2_audio *vin);
+int vivid_video_g_frequency(struct file *file, void *fh, struct v4l2_frequency *vf);
+int vivid_video_s_frequency(struct file *file, void *fh, const struct v4l2_frequency *vf);
+int vivid_video_s_tuner(struct file *file, void *fh, const struct v4l2_tuner *vt);
+int vivid_video_g_tuner(struct file *file, void *fh, struct v4l2_tuner *vt);
+int vidioc_querystd(struct file *file, void *priv, v4l2_std_id *id);
+int vivid_vid_cap_s_std(struct file *file, void *priv, v4l2_std_id id);
+int vivid_vid_cap_s_dv_timings(struct file *file, void *_fh, struct v4l2_dv_timings *timings);
+int vidioc_query_dv_timings(struct file *file, void *_fh, struct v4l2_dv_timings *timings);
+int vidioc_s_edid(struct file *file, void *_fh, struct v4l2_edid *edid);
+int vidioc_enum_framesizes(struct file *file, void *fh, struct v4l2_frmsizeenum *fsize);
+int vidioc_enum_frameintervals(struct file *file, void *priv, struct v4l2_frmivalenum *fival);
+int vivid_vid_cap_g_parm(struct file *file, void *priv, struct v4l2_streamparm *parm);
+int vivid_vid_cap_s_parm(struct file *file, void *priv, struct v4l2_streamparm *parm);
+
+#endif
diff --git a/drivers/media/platform/vivid/vivid-vid-common.c b/drivers/media/platform/vivid/vivid-vid-common.c
new file mode 100644 (file)
index 0000000..16cd6d2
--- /dev/null
@@ -0,0 +1,571 @@
+/*
+ * vivid-vid-common.c - common video support functions.
+ *
+ * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
+ *
+ * This program is free software; you may redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/videodev2.h>
+#include <linux/v4l2-dv-timings.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-event.h>
+#include <media/v4l2-dv-timings.h>
+
+#include "vivid-core.h"
+#include "vivid-vid-common.h"
+
+const struct v4l2_dv_timings_cap vivid_dv_timings_cap = {
+       .type = V4L2_DV_BT_656_1120,
+       /* keep this initialization for compatibility with GCC < 4.4.6 */
+       .reserved = { 0 },
+       V4L2_INIT_BT_TIMINGS(0, MAX_WIDTH, 0, MAX_HEIGHT, 25000000, 600000000,
+               V4L2_DV_BT_STD_CEA861 | V4L2_DV_BT_STD_DMT,
+               V4L2_DV_BT_CAP_PROGRESSIVE | V4L2_DV_BT_CAP_INTERLACED)
+};
+
+/* ------------------------------------------------------------------
+       Basic structures
+   ------------------------------------------------------------------*/
+
+struct vivid_fmt vivid_formats[] = {
+       {
+               .name     = "4:2:2, packed, YUYV",
+               .fourcc   = V4L2_PIX_FMT_YUYV,
+               .depth    = 16,
+               .is_yuv   = true,
+               .planes   = 1,
+               .data_offset = { PLANE0_DATA_OFFSET, 0 },
+       },
+       {
+               .name     = "4:2:2, packed, UYVY",
+               .fourcc   = V4L2_PIX_FMT_UYVY,
+               .depth    = 16,
+               .is_yuv   = true,
+               .planes   = 1,
+       },
+       {
+               .name     = "4:2:2, packed, YVYU",
+               .fourcc   = V4L2_PIX_FMT_YVYU,
+               .depth    = 16,
+               .is_yuv   = true,
+               .planes   = 1,
+       },
+       {
+               .name     = "4:2:2, packed, VYUY",
+               .fourcc   = V4L2_PIX_FMT_VYUY,
+               .depth    = 16,
+               .is_yuv   = true,
+               .planes   = 1,
+       },
+       {
+               .name     = "RGB565 (LE)",
+               .fourcc   = V4L2_PIX_FMT_RGB565, /* gggbbbbb rrrrrggg */
+               .depth    = 16,
+               .planes   = 1,
+               .can_do_overlay = true,
+       },
+       {
+               .name     = "RGB565 (BE)",
+               .fourcc   = V4L2_PIX_FMT_RGB565X, /* rrrrrggg gggbbbbb */
+               .depth    = 16,
+               .planes   = 1,
+               .can_do_overlay = true,
+       },
+       {
+               .name     = "RGB555 (LE)",
+               .fourcc   = V4L2_PIX_FMT_RGB555, /* gggbbbbb arrrrrgg */
+               .depth    = 16,
+               .planes   = 1,
+               .can_do_overlay = true,
+       },
+       {
+               .name     = "XRGB555 (LE)",
+               .fourcc   = V4L2_PIX_FMT_XRGB555, /* gggbbbbb arrrrrgg */
+               .depth    = 16,
+               .planes   = 1,
+               .can_do_overlay = true,
+       },
+       {
+               .name     = "ARGB555 (LE)",
+               .fourcc   = V4L2_PIX_FMT_ARGB555, /* gggbbbbb arrrrrgg */
+               .depth    = 16,
+               .planes   = 1,
+               .can_do_overlay = true,
+               .alpha_mask = 0x8000,
+       },
+       {
+               .name     = "RGB555 (BE)",
+               .fourcc   = V4L2_PIX_FMT_RGB555X, /* arrrrrgg gggbbbbb */
+               .depth    = 16,
+               .planes   = 1,
+               .can_do_overlay = true,
+       },
+       {
+               .name     = "RGB24 (LE)",
+               .fourcc   = V4L2_PIX_FMT_RGB24, /* rgb */
+               .depth    = 24,
+               .planes   = 1,
+       },
+       {
+               .name     = "RGB24 (BE)",
+               .fourcc   = V4L2_PIX_FMT_BGR24, /* bgr */
+               .depth    = 24,
+               .planes   = 1,
+       },
+       {
+               .name     = "RGB32 (LE)",
+               .fourcc   = V4L2_PIX_FMT_RGB32, /* argb */
+               .depth    = 32,
+               .planes   = 1,
+       },
+       {
+               .name     = "RGB32 (BE)",
+               .fourcc   = V4L2_PIX_FMT_BGR32, /* bgra */
+               .depth    = 32,
+               .planes   = 1,
+       },
+       {
+               .name     = "XRGB32 (LE)",
+               .fourcc   = V4L2_PIX_FMT_XRGB32, /* argb */
+               .depth    = 32,
+               .planes   = 1,
+       },
+       {
+               .name     = "XRGB32 (BE)",
+               .fourcc   = V4L2_PIX_FMT_XBGR32, /* bgra */
+               .depth    = 32,
+               .planes   = 1,
+       },
+       {
+               .name     = "ARGB32 (LE)",
+               .fourcc   = V4L2_PIX_FMT_ARGB32, /* argb */
+               .depth    = 32,
+               .planes   = 1,
+               .alpha_mask = 0x000000ff,
+       },
+       {
+               .name     = "ARGB32 (BE)",
+               .fourcc   = V4L2_PIX_FMT_ABGR32, /* bgra */
+               .depth    = 32,
+               .planes   = 1,
+               .alpha_mask = 0xff000000,
+       },
+       {
+               .name     = "4:2:2, planar, YUV",
+               .fourcc   = V4L2_PIX_FMT_NV16M,
+               .depth    = 8,
+               .is_yuv   = true,
+               .planes   = 2,
+               .data_offset = { PLANE0_DATA_OFFSET, 0 },
+       },
+       {
+               .name     = "4:2:2, planar, YVU",
+               .fourcc   = V4L2_PIX_FMT_NV61M,
+               .depth    = 8,
+               .is_yuv   = true,
+               .planes   = 2,
+               .data_offset = { 0, PLANE0_DATA_OFFSET },
+       },
+};
+
+/* There are 2 multiplanar formats in the list */
+#define VIVID_MPLANAR_FORMATS 2
+
+const struct vivid_fmt *vivid_get_format(struct vivid_dev *dev, u32 pixelformat)
+{
+       const struct vivid_fmt *fmt;
+       unsigned k;
+
+       for (k = 0; k < ARRAY_SIZE(vivid_formats); k++) {
+               fmt = &vivid_formats[k];
+               if (fmt->fourcc == pixelformat)
+                       if (fmt->planes == 1 || dev->multiplanar)
+                               return fmt;
+       }
+
+       return NULL;
+}
+
+bool vivid_vid_can_loop(struct vivid_dev *dev)
+{
+       if (dev->src_rect.width != dev->sink_rect.width ||
+           dev->src_rect.height != dev->sink_rect.height)
+               return false;
+       if (dev->fmt_cap->fourcc != dev->fmt_out->fourcc)
+               return false;
+       if (dev->field_cap != dev->field_out)
+               return false;
+       if (vivid_is_svid_cap(dev) && vivid_is_svid_out(dev)) {
+               if (!(dev->std_cap & V4L2_STD_525_60) !=
+                   !(dev->std_out & V4L2_STD_525_60))
+                       return false;
+               return true;
+       }
+       if (vivid_is_hdmi_cap(dev) && vivid_is_hdmi_out(dev))
+               return true;
+       return false;
+}
+
+void vivid_send_source_change(struct vivid_dev *dev, unsigned type)
+{
+       struct v4l2_event ev = {
+               .type = V4L2_EVENT_SOURCE_CHANGE,
+               .u.src_change.changes = V4L2_EVENT_SRC_CH_RESOLUTION,
+       };
+       unsigned i;
+
+       for (i = 0; i < dev->num_inputs; i++) {
+               ev.id = i;
+               if (dev->input_type[i] == type) {
+                       if (video_is_registered(&dev->vid_cap_dev) && dev->has_vid_cap)
+                               v4l2_event_queue(&dev->vid_cap_dev, &ev);
+                       if (video_is_registered(&dev->vbi_cap_dev) && dev->has_vbi_cap)
+                               v4l2_event_queue(&dev->vbi_cap_dev, &ev);
+               }
+       }
+}
+
+/*
+ * Conversion function that converts a single-planar format to a
+ * single-plane multiplanar format.
+ */
+void fmt_sp2mp(const struct v4l2_format *sp_fmt, struct v4l2_format *mp_fmt)
+{
+       struct v4l2_pix_format_mplane *mp = &mp_fmt->fmt.pix_mp;
+       struct v4l2_plane_pix_format *ppix = &mp->plane_fmt[0];
+       const struct v4l2_pix_format *pix = &sp_fmt->fmt.pix;
+       bool is_out = sp_fmt->type == V4L2_BUF_TYPE_VIDEO_OUTPUT;
+
+       memset(mp->reserved, 0, sizeof(mp->reserved));
+       mp_fmt->type = is_out ? V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE :
+                          V4L2_CAP_VIDEO_CAPTURE_MPLANE;
+       mp->width = pix->width;
+       mp->height = pix->height;
+       mp->pixelformat = pix->pixelformat;
+       mp->field = pix->field;
+       mp->colorspace = pix->colorspace;
+       mp->num_planes = 1;
+       mp->flags = pix->flags;
+       ppix->sizeimage = pix->sizeimage;
+       ppix->bytesperline = pix->bytesperline;
+       memset(ppix->reserved, 0, sizeof(ppix->reserved));
+}
+
+int fmt_sp2mp_func(struct file *file, void *priv,
+               struct v4l2_format *f, fmtfunc func)
+{
+       struct v4l2_format fmt;
+       struct v4l2_pix_format_mplane *mp = &fmt.fmt.pix_mp;
+       struct v4l2_plane_pix_format *ppix = &mp->plane_fmt[0];
+       struct v4l2_pix_format *pix = &f->fmt.pix;
+       int ret;
+
+       /* Converts to a mplane format */
+       fmt_sp2mp(f, &fmt);
+       /* Passes it to the generic mplane format function */
+       ret = func(file, priv, &fmt);
+       /* Copies back the mplane data to the single plane format */
+       pix->width = mp->width;
+       pix->height = mp->height;
+       pix->pixelformat = mp->pixelformat;
+       pix->field = mp->field;
+       pix->colorspace = mp->colorspace;
+       pix->sizeimage = ppix->sizeimage;
+       pix->bytesperline = ppix->bytesperline;
+       pix->flags = mp->flags;
+       return ret;
+}
+
+/* v4l2_rect helper function: copy the width/height values */
+void rect_set_size_to(struct v4l2_rect *r, const struct v4l2_rect *size)
+{
+       r->width = size->width;
+       r->height = size->height;
+}
+
+/* v4l2_rect helper function: width and height of r should be >= min_size */
+void rect_set_min_size(struct v4l2_rect *r, const struct v4l2_rect *min_size)
+{
+       if (r->width < min_size->width)
+               r->width = min_size->width;
+       if (r->height < min_size->height)
+               r->height = min_size->height;
+}
+
+/* v4l2_rect helper function: width and height of r should be <= max_size */
+void rect_set_max_size(struct v4l2_rect *r, const struct v4l2_rect *max_size)
+{
+       if (r->width > max_size->width)
+               r->width = max_size->width;
+       if (r->height > max_size->height)
+               r->height = max_size->height;
+}
+
+/* v4l2_rect helper function: r should be inside boundary */
+void rect_map_inside(struct v4l2_rect *r, const struct v4l2_rect *boundary)
+{
+       rect_set_max_size(r, boundary);
+       if (r->left < boundary->left)
+               r->left = boundary->left;
+       if (r->top < boundary->top)
+               r->top = boundary->top;
+       if (r->left + r->width > boundary->width)
+               r->left = boundary->width - r->width;
+       if (r->top + r->height > boundary->height)
+               r->top = boundary->height - r->height;
+}
+
+/* v4l2_rect helper function: return true if r1 has the same size as r2 */
+bool rect_same_size(const struct v4l2_rect *r1, const struct v4l2_rect *r2)
+{
+       return r1->width == r2->width && r1->height == r2->height;
+}
+
+/* v4l2_rect helper function: calculate the intersection of two rects */
+struct v4l2_rect rect_intersect(const struct v4l2_rect *a, const struct v4l2_rect *b)
+{
+       struct v4l2_rect r;
+       int right, bottom;
+
+       r.top = max(a->top, b->top);
+       r.left = max(a->left, b->left);
+       bottom = min(a->top + a->height, b->top + b->height);
+       right = min(a->left + a->width, b->left + b->width);
+       r.height = max(0, bottom - r.top);
+       r.width = max(0, right - r.left);
+       return r;
+}
+
+/*
+ * v4l2_rect helper function: scale rect r by to->width / from->width and
+ * to->height / from->height.
+ */
+void rect_scale(struct v4l2_rect *r, const struct v4l2_rect *from,
+                                    const struct v4l2_rect *to)
+{
+       if (from->width == 0 || from->height == 0) {
+               r->left = r->top = r->width = r->height = 0;
+               return;
+       }
+       r->left = (((r->left - from->left) * to->width) / from->width) & ~1;
+       r->width = ((r->width * to->width) / from->width) & ~1;
+       r->top = ((r->top - from->top) * to->height) / from->height;
+       r->height = (r->height * to->height) / from->height;
+}
+
+bool rect_overlap(const struct v4l2_rect *r1, const struct v4l2_rect *r2)
+{
+       /*
+        * IF the left side of r1 is to the right of the right side of r2 OR
+        *    the left side of r2 is to the right of the right side of r1 THEN
+        * they do not overlap.
+        */
+       if (r1->left >= r2->left + r2->width ||
+           r2->left >= r1->left + r1->width)
+               return false;
+       /*
+        * IF the top side of r1 is below the bottom of r2 OR
+        *    the top side of r2 is below the bottom of r1 THEN
+        * they do not overlap.
+        */
+       if (r1->top >= r2->top + r2->height ||
+           r2->top >= r1->top + r1->height)
+               return false;
+       return true;
+}
+int vivid_vid_adjust_sel(unsigned flags, struct v4l2_rect *r)
+{
+       unsigned w = r->width;
+       unsigned h = r->height;
+
+       if (!(flags & V4L2_SEL_FLAG_LE)) {
+               w++;
+               h++;
+               if (w < 2)
+                       w = 2;
+               if (h < 2)
+                       h = 2;
+       }
+       if (!(flags & V4L2_SEL_FLAG_GE)) {
+               if (w > MAX_WIDTH)
+                       w = MAX_WIDTH;
+               if (h > MAX_HEIGHT)
+                       h = MAX_HEIGHT;
+       }
+       w = w & ~1;
+       h = h & ~1;
+       if (w < 2 || h < 2)
+               return -ERANGE;
+       if (w > MAX_WIDTH || h > MAX_HEIGHT)
+               return -ERANGE;
+       if (r->top < 0)
+               r->top = 0;
+       if (r->left < 0)
+               r->left = 0;
+       r->left &= ~1;
+       r->top &= ~1;
+       if (r->left + w > MAX_WIDTH)
+               r->left = MAX_WIDTH - w;
+       if (r->top + h > MAX_HEIGHT)
+               r->top = MAX_HEIGHT - h;
+       if ((flags & (V4L2_SEL_FLAG_GE | V4L2_SEL_FLAG_LE)) ==
+                       (V4L2_SEL_FLAG_GE | V4L2_SEL_FLAG_LE) &&
+           (r->width != w || r->height != h))
+               return -ERANGE;
+       r->width = w;
+       r->height = h;
+       return 0;
+}
+
+int vivid_enum_fmt_vid(struct file *file, void  *priv,
+                                       struct v4l2_fmtdesc *f)
+{
+       struct vivid_dev *dev = video_drvdata(file);
+       const struct vivid_fmt *fmt;
+
+       if (f->index >= ARRAY_SIZE(vivid_formats) -
+           (dev->multiplanar ? 0 : VIVID_MPLANAR_FORMATS))
+               return -EINVAL;
+
+       fmt = &vivid_formats[f->index];
+
+       strlcpy(f->description, fmt->name, sizeof(f->description));
+       f->pixelformat = fmt->fourcc;
+       return 0;
+}
+
+int vidioc_enum_fmt_vid_mplane(struct file *file, void  *priv,
+                                       struct v4l2_fmtdesc *f)
+{
+       struct vivid_dev *dev = video_drvdata(file);
+
+       if (!dev->multiplanar)
+               return -ENOTTY;
+       return vivid_enum_fmt_vid(file, priv, f);
+}
+
+int vidioc_enum_fmt_vid(struct file *file, void  *priv,
+                                       struct v4l2_fmtdesc *f)
+{
+       struct vivid_dev *dev = video_drvdata(file);
+
+       if (dev->multiplanar)
+               return -ENOTTY;
+       return vivid_enum_fmt_vid(file, priv, f);
+}
+
+int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *id)
+{
+       struct vivid_dev *dev = video_drvdata(file);
+       struct video_device *vdev = video_devdata(file);
+
+       if (vdev->vfl_dir == VFL_DIR_RX) {
+               if (!vivid_is_sdtv_cap(dev))
+                       return -ENODATA;
+               *id = dev->std_cap;
+       } else {
+               if (!vivid_is_svid_out(dev))
+                       return -ENODATA;
+               *id = dev->std_out;
+       }
+       return 0;
+}
+
+int vidioc_g_dv_timings(struct file *file, void *_fh,
+                                   struct v4l2_dv_timings *timings)
+{
+       struct vivid_dev *dev = video_drvdata(file);
+       struct video_device *vdev = video_devdata(file);
+
+       if (vdev->vfl_dir == VFL_DIR_RX) {
+               if (!vivid_is_hdmi_cap(dev))
+                       return -ENODATA;
+               *timings = dev->dv_timings_cap;
+       } else {
+               if (!vivid_is_hdmi_out(dev))
+                       return -ENODATA;
+               *timings = dev->dv_timings_out;
+       }
+       return 0;
+}
+
+int vidioc_enum_dv_timings(struct file *file, void *_fh,
+                                   struct v4l2_enum_dv_timings *timings)
+{
+       struct vivid_dev *dev = video_drvdata(file);
+       struct video_device *vdev = video_devdata(file);
+
+       if (vdev->vfl_dir == VFL_DIR_RX) {
+               if (!vivid_is_hdmi_cap(dev))
+                       return -ENODATA;
+       } else {
+               if (!vivid_is_hdmi_out(dev))
+                       return -ENODATA;
+       }
+       return v4l2_enum_dv_timings_cap(timings, &vivid_dv_timings_cap,
+                       NULL, NULL);
+}
+
+int vidioc_dv_timings_cap(struct file *file, void *_fh,
+                                   struct v4l2_dv_timings_cap *cap)
+{
+       struct vivid_dev *dev = video_drvdata(file);
+       struct video_device *vdev = video_devdata(file);
+
+       if (vdev->vfl_dir == VFL_DIR_RX) {
+               if (!vivid_is_hdmi_cap(dev))
+                       return -ENODATA;
+       } else {
+               if (!vivid_is_hdmi_out(dev))
+                       return -ENODATA;
+       }
+       *cap = vivid_dv_timings_cap;
+       return 0;
+}
+
+int vidioc_g_edid(struct file *file, void *_fh,
+                        struct v4l2_edid *edid)
+{
+       struct vivid_dev *dev = video_drvdata(file);
+       struct video_device *vdev = video_devdata(file);
+
+       memset(edid->reserved, 0, sizeof(edid->reserved));
+       if (vdev->vfl_dir == VFL_DIR_RX) {
+               if (edid->pad >= dev->num_inputs)
+                       return -EINVAL;
+               if (dev->input_type[edid->pad] != HDMI)
+                       return -EINVAL;
+       } else {
+               if (edid->pad >= dev->num_outputs)
+                       return -EINVAL;
+               if (dev->output_type[edid->pad] != HDMI)
+                       return -EINVAL;
+       }
+       if (edid->start_block == 0 && edid->blocks == 0) {
+               edid->blocks = dev->edid_blocks;
+               return 0;
+       }
+       if (dev->edid_blocks == 0)
+               return -ENODATA;
+       if (edid->start_block >= dev->edid_blocks)
+               return -EINVAL;
+       if (edid->start_block + edid->blocks > dev->edid_blocks)
+               edid->blocks = dev->edid_blocks - edid->start_block;
+       memcpy(edid->edid, dev->edid, edid->blocks * 128);
+       return 0;
+}
diff --git a/drivers/media/platform/vivid/vivid-vid-common.h b/drivers/media/platform/vivid/vivid-vid-common.h
new file mode 100644 (file)
index 0000000..3ec4fa8
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * vivid-vid-common.h - common video support functions.
+ *
+ * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
+ *
+ * This program is free software; you may redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * 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 _VIVID_VID_COMMON_H_
+#define _VIVID_VID_COMMON_H_
+
+typedef int (*fmtfunc)(struct file *file, void *priv, struct v4l2_format *f);
+
+/*
+ * Conversion function that converts a single-planar format to a
+ * single-plane multiplanar format.
+ */
+void fmt_sp2mp(const struct v4l2_format *sp_fmt, struct v4l2_format *mp_fmt);
+int fmt_sp2mp_func(struct file *file, void *priv,
+               struct v4l2_format *f, fmtfunc func);
+
+extern const struct v4l2_dv_timings_cap vivid_dv_timings_cap;
+
+const struct vivid_fmt *vivid_get_format(struct vivid_dev *dev, u32 pixelformat);
+
+bool vivid_vid_can_loop(struct vivid_dev *dev);
+void vivid_send_source_change(struct vivid_dev *dev, unsigned type);
+
+bool rect_overlap(const struct v4l2_rect *r1, const struct v4l2_rect *r2);
+void rect_set_size_to(struct v4l2_rect *r, const struct v4l2_rect *size);
+void rect_set_min_size(struct v4l2_rect *r, const struct v4l2_rect *min_size);
+void rect_set_max_size(struct v4l2_rect *r, const struct v4l2_rect *max_size);
+void rect_map_inside(struct v4l2_rect *r, const struct v4l2_rect *boundary);
+bool rect_same_size(const struct v4l2_rect *r1, const struct v4l2_rect *r2);
+struct v4l2_rect rect_intersect(const struct v4l2_rect *a, const struct v4l2_rect *b);
+void rect_scale(struct v4l2_rect *r, const struct v4l2_rect *from,
+                                    const struct v4l2_rect *to);
+int vivid_vid_adjust_sel(unsigned flags, struct v4l2_rect *r);
+
+int vivid_enum_fmt_vid(struct file *file, void  *priv, struct v4l2_fmtdesc *f);
+int vidioc_enum_fmt_vid_mplane(struct file *file, void  *priv, struct v4l2_fmtdesc *f);
+int vidioc_enum_fmt_vid(struct file *file, void  *priv, struct v4l2_fmtdesc *f);
+int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *id);
+int vidioc_g_dv_timings(struct file *file, void *_fh, struct v4l2_dv_timings *timings);
+int vidioc_enum_dv_timings(struct file *file, void *_fh, struct v4l2_enum_dv_timings *timings);
+int vidioc_dv_timings_cap(struct file *file, void *_fh, struct v4l2_dv_timings_cap *cap);
+int vidioc_g_edid(struct file *file, void *_fh, struct v4l2_edid *edid);
+int vidioc_subscribe_event(struct v4l2_fh *fh, const struct v4l2_event_subscription *sub);
+
+#endif
diff --git a/drivers/media/platform/vivid/vivid-vid-out.c b/drivers/media/platform/vivid/vivid-vid-out.c
new file mode 100644 (file)
index 0000000..69c2dbd
--- /dev/null
@@ -0,0 +1,1146 @@
+/*
+ * vivid-vid-out.c - video output support functions.
+ *
+ * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
+ *
+ * This program is free software; you may redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/videodev2.h>
+#include <linux/v4l2-dv-timings.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-event.h>
+#include <media/v4l2-dv-timings.h>
+
+#include "vivid-core.h"
+#include "vivid-vid-common.h"
+#include "vivid-kthread-out.h"
+#include "vivid-vid-out.h"
+
+static int vid_out_queue_setup(struct vb2_queue *vq, const struct v4l2_format *fmt,
+                      unsigned *nbuffers, unsigned *nplanes,
+                      unsigned sizes[], void *alloc_ctxs[])
+{
+       struct vivid_dev *dev = vb2_get_drv_priv(vq);
+       unsigned planes = dev->fmt_out->planes;
+       unsigned h = dev->fmt_out_rect.height;
+       unsigned size = dev->bytesperline_out[0] * h;
+
+       if (dev->field_out == V4L2_FIELD_ALTERNATE) {
+               /*
+                * You cannot use write() with FIELD_ALTERNATE since the field
+                * information (TOP/BOTTOM) cannot be passed to the kernel.
+                */
+               if (vb2_fileio_is_active(vq))
+                       return -EINVAL;
+       }
+
+       if (dev->queue_setup_error) {
+               /*
+                * Error injection: test what happens if queue_setup() returns
+                * an error.
+                */
+               dev->queue_setup_error = false;
+               return -EINVAL;
+       }
+
+       if (fmt) {
+               const struct v4l2_pix_format_mplane *mp;
+               struct v4l2_format mp_fmt;
+
+               if (!V4L2_TYPE_IS_MULTIPLANAR(fmt->type)) {
+                       fmt_sp2mp(fmt, &mp_fmt);
+                       fmt = &mp_fmt;
+               }
+               mp = &fmt->fmt.pix_mp;
+               /*
+                * Check if the number of planes in the specified format match
+                * the number of planes in the current format. You can't mix that.
+                */
+               if (mp->num_planes != planes)
+                       return -EINVAL;
+               sizes[0] = mp->plane_fmt[0].sizeimage;
+               if (planes == 2) {
+                       sizes[1] = mp->plane_fmt[1].sizeimage;
+                       if (sizes[0] < dev->bytesperline_out[0] * h ||
+                           sizes[1] < dev->bytesperline_out[1] * h)
+                               return -EINVAL;
+               } else if (sizes[0] < size) {
+                       return -EINVAL;
+               }
+       } else {
+               if (planes == 2) {
+                       sizes[0] = dev->bytesperline_out[0] * h;
+                       sizes[1] = dev->bytesperline_out[1] * h;
+               } else {
+                       sizes[0] = size;
+               }
+       }
+
+       if (vq->num_buffers + *nbuffers < 2)
+               *nbuffers = 2 - vq->num_buffers;
+
+       *nplanes = planes;
+
+       /*
+        * videobuf2-vmalloc allocator is context-less so no need to set
+        * alloc_ctxs array.
+        */
+
+       if (planes == 2)
+               dprintk(dev, 1, "%s, count=%d, sizes=%u, %u\n", __func__,
+                       *nbuffers, sizes[0], sizes[1]);
+       else
+               dprintk(dev, 1, "%s, count=%d, size=%u\n", __func__,
+                       *nbuffers, sizes[0]);
+       return 0;
+}
+
+static int vid_out_buf_prepare(struct vb2_buffer *vb)
+{
+       struct vivid_dev *dev = vb2_get_drv_priv(vb->vb2_queue);
+       unsigned long size;
+       unsigned planes = dev->fmt_out->planes;
+       unsigned p;
+
+       dprintk(dev, 1, "%s\n", __func__);
+
+       if (WARN_ON(NULL == dev->fmt_out))
+               return -EINVAL;
+
+       if (dev->buf_prepare_error) {
+               /*
+                * Error injection: test what happens if buf_prepare() returns
+                * an error.
+                */
+               dev->buf_prepare_error = false;
+               return -EINVAL;
+       }
+
+       if (dev->field_out != V4L2_FIELD_ALTERNATE)
+               vb->v4l2_buf.field = dev->field_out;
+       else if (vb->v4l2_buf.field != V4L2_FIELD_TOP &&
+                vb->v4l2_buf.field != V4L2_FIELD_BOTTOM)
+               return -EINVAL;
+
+       for (p = 0; p < planes; p++) {
+               size = dev->bytesperline_out[p] * dev->fmt_out_rect.height +
+                       vb->v4l2_planes[p].data_offset;
+
+               if (vb2_get_plane_payload(vb, p) < size) {
+                       dprintk(dev, 1, "%s the payload is too small for plane %u (%lu < %lu)\n",
+                                       __func__, p, vb2_get_plane_payload(vb, p), size);
+                       return -EINVAL;
+               }
+       }
+
+       return 0;
+}
+
+static void vid_out_buf_queue(struct vb2_buffer *vb)
+{
+       struct vivid_dev *dev = vb2_get_drv_priv(vb->vb2_queue);
+       struct vivid_buffer *buf = container_of(vb, struct vivid_buffer, vb);
+
+       dprintk(dev, 1, "%s\n", __func__);
+
+       spin_lock(&dev->slock);
+       list_add_tail(&buf->list, &dev->vid_out_active);
+       spin_unlock(&dev->slock);
+}
+
+static int vid_out_start_streaming(struct vb2_queue *vq, unsigned count)
+{
+       struct vivid_dev *dev = vb2_get_drv_priv(vq);
+       int err;
+
+       if (vb2_is_streaming(&dev->vb_vid_cap_q))
+               dev->can_loop_video = vivid_vid_can_loop(dev);
+
+       if (dev->kthread_vid_out)
+               return 0;
+
+       dev->vid_out_seq_count = 0;
+       dprintk(dev, 1, "%s\n", __func__);
+       if (dev->start_streaming_error) {
+               dev->start_streaming_error = false;
+               err = -EINVAL;
+       } else {
+               err = vivid_start_generating_vid_out(dev, &dev->vid_out_streaming);
+       }
+       if (err) {
+               struct vivid_buffer *buf, *tmp;
+
+               list_for_each_entry_safe(buf, tmp, &dev->vid_out_active, list) {
+                       list_del(&buf->list);
+                       vb2_buffer_done(&buf->vb, VB2_BUF_STATE_QUEUED);
+               }
+       }
+       return err;
+}
+
+/* abort streaming and wait for last buffer */
+static void vid_out_stop_streaming(struct vb2_queue *vq)
+{
+       struct vivid_dev *dev = vb2_get_drv_priv(vq);
+
+       dprintk(dev, 1, "%s\n", __func__);
+       vivid_stop_generating_vid_out(dev, &dev->vid_out_streaming);
+       dev->can_loop_video = false;
+}
+
+const struct vb2_ops vivid_vid_out_qops = {
+       .queue_setup            = vid_out_queue_setup,
+       .buf_prepare            = vid_out_buf_prepare,
+       .buf_queue              = vid_out_buf_queue,
+       .start_streaming        = vid_out_start_streaming,
+       .stop_streaming         = vid_out_stop_streaming,
+       .wait_prepare           = vivid_unlock,
+       .wait_finish            = vivid_lock,
+};
+
+/*
+ * Called whenever the format has to be reset which can occur when
+ * changing outputs, standard, timings, etc.
+ */
+void vivid_update_format_out(struct vivid_dev *dev)
+{
+       struct v4l2_bt_timings *bt = &dev->dv_timings_out.bt;
+       unsigned size;
+
+       switch (dev->output_type[dev->output]) {
+       case SVID:
+       default:
+               dev->field_out = dev->tv_field_out;
+               dev->sink_rect.width = 720;
+               if (dev->std_out & V4L2_STD_525_60) {
+                       dev->sink_rect.height = 480;
+                       dev->timeperframe_vid_out = (struct v4l2_fract) { 1001, 30000 };
+                       dev->service_set_out = V4L2_SLICED_CAPTION_525;
+               } else {
+                       dev->sink_rect.height = 576;
+                       dev->timeperframe_vid_out = (struct v4l2_fract) { 1000, 25000 };
+                       dev->service_set_out = V4L2_SLICED_WSS_625 | V4L2_SLICED_TELETEXT_B;
+               }
+               dev->colorspace_out = V4L2_COLORSPACE_SMPTE170M;
+               break;
+       case HDMI:
+               dev->sink_rect.width = bt->width;
+               dev->sink_rect.height = bt->height;
+               size = V4L2_DV_BT_FRAME_WIDTH(bt) * V4L2_DV_BT_FRAME_HEIGHT(bt);
+               dev->timeperframe_vid_out = (struct v4l2_fract) {
+                       size / 100, (u32)bt->pixelclock / 100
+               };
+               if (bt->interlaced)
+                       dev->field_out = V4L2_FIELD_ALTERNATE;
+               else
+                       dev->field_out = V4L2_FIELD_NONE;
+               if (!dev->dvi_d_out && (bt->standards & V4L2_DV_BT_STD_CEA861)) {
+                       if (bt->width == 720 && bt->height <= 576)
+                               dev->colorspace_out = V4L2_COLORSPACE_SMPTE170M;
+                       else
+                               dev->colorspace_out = V4L2_COLORSPACE_REC709;
+               } else {
+                       dev->colorspace_out = V4L2_COLORSPACE_SRGB;
+               }
+               break;
+       }
+       dev->compose_out = dev->sink_rect;
+       dev->compose_bounds_out = dev->sink_rect;
+       dev->crop_out = dev->compose_out;
+       if (V4L2_FIELD_HAS_T_OR_B(dev->field_out))
+               dev->crop_out.height /= 2;
+       dev->fmt_out_rect = dev->crop_out;
+       dev->bytesperline_out[0] = (dev->sink_rect.width * dev->fmt_out->depth) / 8;
+       if (dev->fmt_out->planes == 2)
+               dev->bytesperline_out[1] = (dev->sink_rect.width * dev->fmt_out->depth) / 8;
+}
+
+/* Map the field to something that is valid for the current output */
+static enum v4l2_field vivid_field_out(struct vivid_dev *dev, enum v4l2_field field)
+{
+       if (vivid_is_svid_out(dev)) {
+               switch (field) {
+               case V4L2_FIELD_INTERLACED_TB:
+               case V4L2_FIELD_INTERLACED_BT:
+               case V4L2_FIELD_SEQ_TB:
+               case V4L2_FIELD_SEQ_BT:
+               case V4L2_FIELD_ALTERNATE:
+                       return field;
+               case V4L2_FIELD_INTERLACED:
+               default:
+                       return V4L2_FIELD_INTERLACED;
+               }
+       }
+       if (vivid_is_hdmi_out(dev))
+               return dev->dv_timings_out.bt.interlaced ? V4L2_FIELD_ALTERNATE :
+                                                      V4L2_FIELD_NONE;
+       return V4L2_FIELD_NONE;
+}
+
+static enum tpg_pixel_aspect vivid_get_pixel_aspect(const struct vivid_dev *dev)
+{
+       if (vivid_is_svid_out(dev))
+               return (dev->std_out & V4L2_STD_525_60) ?
+                       TPG_PIXEL_ASPECT_NTSC : TPG_PIXEL_ASPECT_PAL;
+
+       if (vivid_is_hdmi_out(dev) &&
+           dev->sink_rect.width == 720 && dev->sink_rect.height <= 576)
+               return dev->sink_rect.height == 480 ?
+                       TPG_PIXEL_ASPECT_NTSC : TPG_PIXEL_ASPECT_PAL;
+
+       return TPG_PIXEL_ASPECT_SQUARE;
+}
+
+int vivid_g_fmt_vid_out(struct file *file, void *priv,
+                                       struct v4l2_format *f)
+{
+       struct vivid_dev *dev = video_drvdata(file);
+       struct v4l2_pix_format_mplane *mp = &f->fmt.pix_mp;
+       unsigned p;
+
+       mp->width        = dev->fmt_out_rect.width;
+       mp->height       = dev->fmt_out_rect.height;
+       mp->field        = dev->field_out;
+       mp->pixelformat  = dev->fmt_out->fourcc;
+       mp->colorspace   = dev->colorspace_out;
+       mp->num_planes = dev->fmt_out->planes;
+       for (p = 0; p < mp->num_planes; p++) {
+               mp->plane_fmt[p].bytesperline = dev->bytesperline_out[p];
+               mp->plane_fmt[p].sizeimage =
+                       mp->plane_fmt[p].bytesperline * mp->height;
+       }
+       return 0;
+}
+
+int vivid_try_fmt_vid_out(struct file *file, void *priv,
+                       struct v4l2_format *f)
+{
+       struct vivid_dev *dev = video_drvdata(file);
+       struct v4l2_bt_timings *bt = &dev->dv_timings_out.bt;
+       struct v4l2_pix_format_mplane *mp = &f->fmt.pix_mp;
+       struct v4l2_plane_pix_format *pfmt = mp->plane_fmt;
+       const struct vivid_fmt *fmt;
+       unsigned bytesperline, max_bpl;
+       unsigned factor = 1;
+       unsigned w, h;
+       unsigned p;
+
+       fmt = vivid_get_format(dev, mp->pixelformat);
+       if (!fmt) {
+               dprintk(dev, 1, "Fourcc format (0x%08x) unknown.\n",
+                       mp->pixelformat);
+               mp->pixelformat = V4L2_PIX_FMT_YUYV;
+               fmt = vivid_get_format(dev, mp->pixelformat);
+       }
+
+       mp->field = vivid_field_out(dev, mp->field);
+       if (vivid_is_svid_out(dev)) {
+               w = 720;
+               h = (dev->std_out & V4L2_STD_525_60) ? 480 : 576;
+       } else {
+               w = dev->sink_rect.width;
+               h = dev->sink_rect.height;
+       }
+       if (V4L2_FIELD_HAS_T_OR_B(mp->field))
+               factor = 2;
+       if (!dev->has_scaler_out && !dev->has_crop_out && !dev->has_compose_out) {
+               mp->width = w;
+               mp->height = h / factor;
+       } else {
+               struct v4l2_rect r = { 0, 0, mp->width, mp->height * factor };
+
+               rect_set_min_size(&r, &vivid_min_rect);
+               rect_set_max_size(&r, &vivid_max_rect);
+               if (dev->has_scaler_out && !dev->has_crop_out) {
+                       struct v4l2_rect max_r = { 0, 0, MAX_ZOOM * w, MAX_ZOOM * h };
+
+                       rect_set_max_size(&r, &max_r);
+               } else if (!dev->has_scaler_out && dev->has_compose_out && !dev->has_crop_out) {
+                       rect_set_max_size(&r, &dev->sink_rect);
+               } else if (!dev->has_scaler_out && !dev->has_compose_out) {
+                       rect_set_min_size(&r, &dev->sink_rect);
+               }
+               mp->width = r.width;
+               mp->height = r.height / factor;
+       }
+
+       /* This driver supports custom bytesperline values */
+
+       /* Calculate the minimum supported bytesperline value */
+       bytesperline = (mp->width * fmt->depth) >> 3;
+       /* Calculate the maximum supported bytesperline value */
+       max_bpl = (MAX_ZOOM * MAX_WIDTH * fmt->depth) >> 3;
+       mp->num_planes = fmt->planes;
+       for (p = 0; p < mp->num_planes; p++) {
+               if (pfmt[p].bytesperline > max_bpl)
+                       pfmt[p].bytesperline = max_bpl;
+               if (pfmt[p].bytesperline < bytesperline)
+                       pfmt[p].bytesperline = bytesperline;
+               pfmt[p].sizeimage = pfmt[p].bytesperline * mp->height;
+               memset(pfmt[p].reserved, 0, sizeof(pfmt[p].reserved));
+       }
+       if (vivid_is_svid_out(dev))
+               mp->colorspace = V4L2_COLORSPACE_SMPTE170M;
+       else if (dev->dvi_d_out || !(bt->standards & V4L2_DV_BT_STD_CEA861))
+               mp->colorspace = V4L2_COLORSPACE_SRGB;
+       else if (bt->width == 720 && bt->height <= 576)
+               mp->colorspace = V4L2_COLORSPACE_SMPTE170M;
+       else if (mp->colorspace != V4L2_COLORSPACE_SMPTE170M &&
+                mp->colorspace != V4L2_COLORSPACE_REC709 &&
+                mp->colorspace != V4L2_COLORSPACE_SRGB)
+               mp->colorspace = V4L2_COLORSPACE_REC709;
+       memset(mp->reserved, 0, sizeof(mp->reserved));
+       return 0;
+}
+
+int vivid_s_fmt_vid_out(struct file *file, void *priv,
+                                       struct v4l2_format *f)
+{
+       struct v4l2_pix_format_mplane *mp = &f->fmt.pix_mp;
+       struct vivid_dev *dev = video_drvdata(file);
+       struct v4l2_rect *crop = &dev->crop_out;
+       struct v4l2_rect *compose = &dev->compose_out;
+       struct vb2_queue *q = &dev->vb_vid_out_q;
+       int ret = vivid_try_fmt_vid_out(file, priv, f);
+       unsigned factor = 1;
+
+       if (ret < 0)
+               return ret;
+
+       if (vb2_is_busy(q) &&
+           (vivid_is_svid_out(dev) ||
+            mp->width != dev->fmt_out_rect.width ||
+            mp->height != dev->fmt_out_rect.height ||
+            mp->pixelformat != dev->fmt_out->fourcc ||
+            mp->field != dev->field_out)) {
+               dprintk(dev, 1, "%s device busy\n", __func__);
+               return -EBUSY;
+       }
+
+       /*
+        * Allow for changing the colorspace on the fly. Useful for testing
+        * purposes, and it is something that HDMI transmitters are able
+        * to do.
+        */
+       if (vb2_is_busy(q))
+               goto set_colorspace;
+
+       dev->fmt_out = vivid_get_format(dev, mp->pixelformat);
+       if (V4L2_FIELD_HAS_T_OR_B(mp->field))
+               factor = 2;
+
+       if (dev->has_scaler_out || dev->has_crop_out || dev->has_compose_out) {
+               struct v4l2_rect r = { 0, 0, mp->width, mp->height };
+
+               if (dev->has_scaler_out) {
+                       if (dev->has_crop_out)
+                               rect_map_inside(crop, &r);
+                       else
+                               *crop = r;
+                       if (dev->has_compose_out && !dev->has_crop_out) {
+                               struct v4l2_rect min_r = {
+                                       0, 0,
+                                       r.width / MAX_ZOOM,
+                                       factor * r.height / MAX_ZOOM
+                               };
+                               struct v4l2_rect max_r = {
+                                       0, 0,
+                                       r.width * MAX_ZOOM,
+                                       factor * r.height * MAX_ZOOM
+                               };
+
+                               rect_set_min_size(compose, &min_r);
+                               rect_set_max_size(compose, &max_r);
+                               rect_map_inside(compose, &dev->compose_bounds_out);
+                       } else if (dev->has_compose_out) {
+                               struct v4l2_rect min_r = {
+                                       0, 0,
+                                       crop->width / MAX_ZOOM,
+                                       factor * crop->height / MAX_ZOOM
+                               };
+                               struct v4l2_rect max_r = {
+                                       0, 0,
+                                       crop->width * MAX_ZOOM,
+                                       factor * crop->height * MAX_ZOOM
+                               };
+
+                               rect_set_min_size(compose, &min_r);
+                               rect_set_max_size(compose, &max_r);
+                               rect_map_inside(compose, &dev->compose_bounds_out);
+                       }
+               } else if (dev->has_compose_out && !dev->has_crop_out) {
+                       rect_set_size_to(crop, &r);
+                       r.height *= factor;
+                       rect_set_size_to(compose, &r);
+                       rect_map_inside(compose, &dev->compose_bounds_out);
+               } else if (!dev->has_compose_out) {
+                       rect_map_inside(crop, &r);
+                       r.height /= factor;
+                       rect_set_size_to(compose, &r);
+               } else {
+                       r.height *= factor;
+                       rect_set_max_size(compose, &r);
+                       rect_map_inside(compose, &dev->compose_bounds_out);
+                       crop->top *= factor;
+                       crop->height *= factor;
+                       rect_set_size_to(crop, compose);
+                       rect_map_inside(crop, &r);
+                       crop->top /= factor;
+                       crop->height /= factor;
+               }
+       } else {
+               struct v4l2_rect r = { 0, 0, mp->width, mp->height };
+
+               rect_set_size_to(crop, &r);
+               r.height /= factor;
+               rect_set_size_to(compose, &r);
+       }
+
+       dev->fmt_out_rect.width = mp->width;
+       dev->fmt_out_rect.height = mp->height;
+       dev->bytesperline_out[0] = mp->plane_fmt[0].bytesperline;
+       if (mp->num_planes > 1)
+               dev->bytesperline_out[1] = mp->plane_fmt[1].bytesperline;
+       dev->field_out = mp->field;
+       if (vivid_is_svid_out(dev))
+               dev->tv_field_out = mp->field;
+
+set_colorspace:
+       dev->colorspace_out = mp->colorspace;
+       if (dev->loop_video) {
+               vivid_send_source_change(dev, SVID);
+               vivid_send_source_change(dev, HDMI);
+       }
+       return 0;
+}
+
+int vidioc_g_fmt_vid_out_mplane(struct file *file, void *priv,
+                                       struct v4l2_format *f)
+{
+       struct vivid_dev *dev = video_drvdata(file);
+
+       if (!dev->multiplanar)
+               return -ENOTTY;
+       return vivid_g_fmt_vid_out(file, priv, f);
+}
+
+int vidioc_try_fmt_vid_out_mplane(struct file *file, void *priv,
+                       struct v4l2_format *f)
+{
+       struct vivid_dev *dev = video_drvdata(file);
+
+       if (!dev->multiplanar)
+               return -ENOTTY;
+       return vivid_try_fmt_vid_out(file, priv, f);
+}
+
+int vidioc_s_fmt_vid_out_mplane(struct file *file, void *priv,
+                       struct v4l2_format *f)
+{
+       struct vivid_dev *dev = video_drvdata(file);
+
+       if (!dev->multiplanar)
+               return -ENOTTY;
+       return vivid_s_fmt_vid_out(file, priv, f);
+}
+
+int vidioc_g_fmt_vid_out(struct file *file, void *priv,
+                                       struct v4l2_format *f)
+{
+       struct vivid_dev *dev = video_drvdata(file);
+
+       if (dev->multiplanar)
+               return -ENOTTY;
+       return fmt_sp2mp_func(file, priv, f, vivid_g_fmt_vid_out);
+}
+
+int vidioc_try_fmt_vid_out(struct file *file, void *priv,
+                       struct v4l2_format *f)
+{
+       struct vivid_dev *dev = video_drvdata(file);
+
+       if (dev->multiplanar)
+               return -ENOTTY;
+       return fmt_sp2mp_func(file, priv, f, vivid_try_fmt_vid_out);
+}
+
+int vidioc_s_fmt_vid_out(struct file *file, void *priv,
+                       struct v4l2_format *f)
+{
+       struct vivid_dev *dev = video_drvdata(file);
+
+       if (dev->multiplanar)
+               return -ENOTTY;
+       return fmt_sp2mp_func(file, priv, f, vivid_s_fmt_vid_out);
+}
+
+int vivid_vid_out_g_selection(struct file *file, void *priv,
+                             struct v4l2_selection *sel)
+{
+       struct vivid_dev *dev = video_drvdata(file);
+
+       if (!dev->has_crop_out && !dev->has_compose_out)
+               return -ENOTTY;
+       if (sel->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
+               return -EINVAL;
+
+       sel->r.left = sel->r.top = 0;
+       switch (sel->target) {
+       case V4L2_SEL_TGT_CROP:
+               if (!dev->has_crop_out)
+                       return -EINVAL;
+               sel->r = dev->crop_out;
+               break;
+       case V4L2_SEL_TGT_CROP_DEFAULT:
+               if (!dev->has_crop_out)
+                       return -EINVAL;
+               sel->r = dev->fmt_out_rect;
+               break;
+       case V4L2_SEL_TGT_CROP_BOUNDS:
+               if (!dev->has_compose_out)
+                       return -EINVAL;
+               sel->r = vivid_max_rect;
+               break;
+       case V4L2_SEL_TGT_COMPOSE:
+               if (!dev->has_compose_out)
+                       return -EINVAL;
+               sel->r = dev->compose_out;
+               break;
+       case V4L2_SEL_TGT_COMPOSE_DEFAULT:
+       case V4L2_SEL_TGT_COMPOSE_BOUNDS:
+               if (!dev->has_compose_out)
+                       return -EINVAL;
+               sel->r = dev->sink_rect;
+               break;
+       default:
+               return -EINVAL;
+       }
+       return 0;
+}
+
+int vivid_vid_out_s_selection(struct file *file, void *fh, struct v4l2_selection *s)
+{
+       struct vivid_dev *dev = video_drvdata(file);
+       struct v4l2_rect *crop = &dev->crop_out;
+       struct v4l2_rect *compose = &dev->compose_out;
+       unsigned factor = V4L2_FIELD_HAS_T_OR_B(dev->field_out) ? 2 : 1;
+       int ret;
+
+       if (!dev->has_crop_out && !dev->has_compose_out)
+               return -ENOTTY;
+       if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
+               return -EINVAL;
+
+       switch (s->target) {
+       case V4L2_SEL_TGT_CROP:
+               if (!dev->has_crop_out)
+                       return -EINVAL;
+               ret = vivid_vid_adjust_sel(s->flags, &s->r);
+               if (ret)
+                       return ret;
+               rect_set_min_size(&s->r, &vivid_min_rect);
+               rect_set_max_size(&s->r, &dev->fmt_out_rect);
+               if (dev->has_scaler_out) {
+                       struct v4l2_rect max_rect = {
+                               0, 0,
+                               dev->sink_rect.width * MAX_ZOOM,
+                               (dev->sink_rect.height / factor) * MAX_ZOOM
+                       };
+
+                       rect_set_max_size(&s->r, &max_rect);
+                       if (dev->has_compose_out) {
+                               struct v4l2_rect min_rect = {
+                                       0, 0,
+                                       s->r.width / MAX_ZOOM,
+                                       (s->r.height * factor) / MAX_ZOOM
+                               };
+                               struct v4l2_rect max_rect = {
+                                       0, 0,
+                                       s->r.width * MAX_ZOOM,
+                                       (s->r.height * factor) * MAX_ZOOM
+                               };
+
+                               rect_set_min_size(compose, &min_rect);
+                               rect_set_max_size(compose, &max_rect);
+                               rect_map_inside(compose, &dev->compose_bounds_out);
+                       }
+               } else if (dev->has_compose_out) {
+                       s->r.top *= factor;
+                       s->r.height *= factor;
+                       rect_set_max_size(&s->r, &dev->sink_rect);
+                       rect_set_size_to(compose, &s->r);
+                       rect_map_inside(compose, &dev->compose_bounds_out);
+                       s->r.top /= factor;
+                       s->r.height /= factor;
+               } else {
+                       rect_set_size_to(&s->r, &dev->sink_rect);
+                       s->r.height /= factor;
+               }
+               rect_map_inside(&s->r, &dev->fmt_out_rect);
+               *crop = s->r;
+               break;
+       case V4L2_SEL_TGT_COMPOSE:
+               if (!dev->has_compose_out)
+                       return -EINVAL;
+               ret = vivid_vid_adjust_sel(s->flags, &s->r);
+               if (ret)
+                       return ret;
+               rect_set_min_size(&s->r, &vivid_min_rect);
+               rect_set_max_size(&s->r, &dev->sink_rect);
+               rect_map_inside(&s->r, &dev->compose_bounds_out);
+               s->r.top /= factor;
+               s->r.height /= factor;
+               if (dev->has_scaler_out) {
+                       struct v4l2_rect fmt = dev->fmt_out_rect;
+                       struct v4l2_rect max_rect = {
+                               0, 0,
+                               s->r.width * MAX_ZOOM,
+                               s->r.height * MAX_ZOOM
+                       };
+                       struct v4l2_rect min_rect = {
+                               0, 0,
+                               s->r.width / MAX_ZOOM,
+                               s->r.height / MAX_ZOOM
+                       };
+
+                       rect_set_min_size(&fmt, &min_rect);
+                       if (!dev->has_crop_out)
+                               rect_set_max_size(&fmt, &max_rect);
+                       if (!rect_same_size(&dev->fmt_out_rect, &fmt) &&
+                           vb2_is_busy(&dev->vb_vid_out_q))
+                               return -EBUSY;
+                       if (dev->has_crop_out) {
+                               rect_set_min_size(crop, &min_rect);
+                               rect_set_max_size(crop, &max_rect);
+                       }
+                       dev->fmt_out_rect = fmt;
+               } else if (dev->has_crop_out) {
+                       struct v4l2_rect fmt = dev->fmt_out_rect;
+
+                       rect_set_min_size(&fmt, &s->r);
+                       if (!rect_same_size(&dev->fmt_out_rect, &fmt) &&
+                           vb2_is_busy(&dev->vb_vid_out_q))
+                               return -EBUSY;
+                       dev->fmt_out_rect = fmt;
+                       rect_set_size_to(crop, &s->r);
+                       rect_map_inside(crop, &dev->fmt_out_rect);
+               } else {
+                       if (!rect_same_size(&s->r, &dev->fmt_out_rect) &&
+                           vb2_is_busy(&dev->vb_vid_out_q))
+                               return -EBUSY;
+                       rect_set_size_to(&dev->fmt_out_rect, &s->r);
+                       rect_set_size_to(crop, &s->r);
+                       crop->height /= factor;
+                       rect_map_inside(crop, &dev->fmt_out_rect);
+               }
+               s->r.top *= factor;
+               s->r.height *= factor;
+               if (dev->bitmap_out && (compose->width != s->r.width ||
+                                       compose->height != s->r.height)) {
+                       kfree(dev->bitmap_out);
+                       dev->bitmap_out = NULL;
+               }
+               *compose = s->r;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+int vivid_vid_out_cropcap(struct file *file, void *priv,
+                             struct v4l2_cropcap *cap)
+{
+       struct vivid_dev *dev = video_drvdata(file);
+
+       if (cap->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
+               return -EINVAL;
+
+       switch (vivid_get_pixel_aspect(dev)) {
+       case TPG_PIXEL_ASPECT_NTSC:
+               cap->pixelaspect.numerator = 11;
+               cap->pixelaspect.denominator = 10;
+               break;
+       case TPG_PIXEL_ASPECT_PAL:
+               cap->pixelaspect.numerator = 54;
+               cap->pixelaspect.denominator = 59;
+               break;
+       case TPG_PIXEL_ASPECT_SQUARE:
+               cap->pixelaspect.numerator = 1;
+               cap->pixelaspect.denominator = 1;
+               break;
+       }
+       return 0;
+}
+
+int vidioc_g_fmt_vid_out_overlay(struct file *file, void *priv,
+                                       struct v4l2_format *f)
+{
+       struct vivid_dev *dev = video_drvdata(file);
+       const struct v4l2_rect *compose = &dev->compose_out;
+       struct v4l2_window *win = &f->fmt.win;
+       unsigned clipcount = win->clipcount;
+
+       if (!dev->has_fb)
+               return -EINVAL;
+       win->w.top = dev->overlay_out_top;
+       win->w.left = dev->overlay_out_left;
+       win->w.width = compose->width;
+       win->w.height = compose->height;
+       win->clipcount = dev->clipcount_out;
+       win->field = V4L2_FIELD_ANY;
+       win->chromakey = dev->chromakey_out;
+       win->global_alpha = dev->global_alpha_out;
+       if (clipcount > dev->clipcount_out)
+               clipcount = dev->clipcount_out;
+       if (dev->bitmap_out == NULL)
+               win->bitmap = NULL;
+       else if (win->bitmap) {
+               if (copy_to_user(win->bitmap, dev->bitmap_out,
+                   ((dev->compose_out.width + 7) / 8) * dev->compose_out.height))
+                       return -EFAULT;
+       }
+       if (clipcount && win->clips) {
+               if (copy_to_user(win->clips, dev->clips_out,
+                                clipcount * sizeof(dev->clips_out[0])))
+                       return -EFAULT;
+       }
+       return 0;
+}
+
+int vidioc_try_fmt_vid_out_overlay(struct file *file, void *priv,
+                                       struct v4l2_format *f)
+{
+       struct vivid_dev *dev = video_drvdata(file);
+       const struct v4l2_rect *compose = &dev->compose_out;
+       struct v4l2_window *win = &f->fmt.win;
+       int i, j;
+
+       if (!dev->has_fb)
+               return -EINVAL;
+       win->w.left = clamp_t(int, win->w.left,
+                             -dev->display_width, dev->display_width);
+       win->w.top = clamp_t(int, win->w.top,
+                            -dev->display_height, dev->display_height);
+       win->w.width = compose->width;
+       win->w.height = compose->height;
+       /*
+        * It makes no sense for an OSD to overlay only top or bottom fields,
+        * so always set this to ANY.
+        */
+       win->field = V4L2_FIELD_ANY;
+       if (win->clipcount && !win->clips)
+               win->clipcount = 0;
+       if (win->clipcount > MAX_CLIPS)
+               win->clipcount = MAX_CLIPS;
+       if (win->clipcount) {
+               if (copy_from_user(dev->try_clips_out, win->clips,
+                                  win->clipcount * sizeof(dev->clips_out[0])))
+                       return -EFAULT;
+               for (i = 0; i < win->clipcount; i++) {
+                       struct v4l2_rect *r = &dev->try_clips_out[i].c;
+
+                       r->top = clamp_t(s32, r->top, 0, dev->display_height - 1);
+                       r->height = clamp_t(s32, r->height, 1, dev->display_height - r->top);
+                       r->left = clamp_t(u32, r->left, 0, dev->display_width - 1);
+                       r->width = clamp_t(u32, r->width, 1, dev->display_width - r->left);
+               }
+               /*
+                * Yeah, so sue me, it's an O(n^2) algorithm. But n is a small
+                * number and it's typically a one-time deal.
+                */
+               for (i = 0; i < win->clipcount - 1; i++) {
+                       struct v4l2_rect *r1 = &dev->try_clips_out[i].c;
+
+                       for (j = i + 1; j < win->clipcount; j++) {
+                               struct v4l2_rect *r2 = &dev->try_clips_out[j].c;
+
+                               if (rect_overlap(r1, r2))
+                                       return -EINVAL;
+                       }
+               }
+               if (copy_to_user(win->clips, dev->try_clips_out,
+                                win->clipcount * sizeof(dev->clips_out[0])))
+                       return -EFAULT;
+       }
+       return 0;
+}
+
+int vidioc_s_fmt_vid_out_overlay(struct file *file, void *priv,
+                                       struct v4l2_format *f)
+{
+       struct vivid_dev *dev = video_drvdata(file);
+       const struct v4l2_rect *compose = &dev->compose_out;
+       struct v4l2_window *win = &f->fmt.win;
+       int ret = vidioc_try_fmt_vid_out_overlay(file, priv, f);
+       unsigned bitmap_size = ((compose->width + 7) / 8) * compose->height;
+       unsigned clips_size = win->clipcount * sizeof(dev->clips_out[0]);
+       void *new_bitmap = NULL;
+
+       if (ret)
+               return ret;
+
+       if (win->bitmap) {
+               new_bitmap = memdup_user(win->bitmap, bitmap_size);
+
+               if (IS_ERR(new_bitmap))
+                       return PTR_ERR(new_bitmap);
+       }
+
+       dev->overlay_out_top = win->w.top;
+       dev->overlay_out_left = win->w.left;
+       kfree(dev->bitmap_out);
+       dev->bitmap_out = new_bitmap;
+       dev->clipcount_out = win->clipcount;
+       if (dev->clipcount_out)
+               memcpy(dev->clips_out, dev->try_clips_out, clips_size);
+       dev->chromakey_out = win->chromakey;
+       dev->global_alpha_out = win->global_alpha;
+       return ret;
+}
+
+int vivid_vid_out_overlay(struct file *file, void *fh, unsigned i)
+{
+       struct vivid_dev *dev = video_drvdata(file);
+
+       if (i && !dev->fmt_out->can_do_overlay) {
+               dprintk(dev, 1, "unsupported output format for output overlay\n");
+               return -EINVAL;
+       }
+
+       dev->overlay_out_enabled = i;
+       return 0;
+}
+
+int vivid_vid_out_g_fbuf(struct file *file, void *fh,
+                               struct v4l2_framebuffer *a)
+{
+       struct vivid_dev *dev = video_drvdata(file);
+
+       a->capability = V4L2_FBUF_CAP_EXTERNOVERLAY |
+                       V4L2_FBUF_CAP_BITMAP_CLIPPING |
+                       V4L2_FBUF_CAP_LIST_CLIPPING |
+                       V4L2_FBUF_CAP_CHROMAKEY |
+                       V4L2_FBUF_CAP_SRC_CHROMAKEY |
+                       V4L2_FBUF_CAP_GLOBAL_ALPHA |
+                       V4L2_FBUF_CAP_LOCAL_ALPHA |
+                       V4L2_FBUF_CAP_LOCAL_INV_ALPHA;
+       a->flags = V4L2_FBUF_FLAG_OVERLAY | dev->fbuf_out_flags;
+       a->base = (void *)dev->video_pbase;
+       a->fmt.width = dev->display_width;
+       a->fmt.height = dev->display_height;
+       if (dev->fb_defined.green.length == 5)
+               a->fmt.pixelformat = V4L2_PIX_FMT_ARGB555;
+       else
+               a->fmt.pixelformat = V4L2_PIX_FMT_RGB565;
+       a->fmt.bytesperline = dev->display_byte_stride;
+       a->fmt.sizeimage = a->fmt.height * a->fmt.bytesperline;
+       a->fmt.field = V4L2_FIELD_NONE;
+       a->fmt.colorspace = V4L2_COLORSPACE_SRGB;
+       a->fmt.priv = 0;
+       return 0;
+}
+
+int vivid_vid_out_s_fbuf(struct file *file, void *fh,
+                               const struct v4l2_framebuffer *a)
+{
+       struct vivid_dev *dev = video_drvdata(file);
+       const unsigned chroma_flags = V4L2_FBUF_FLAG_CHROMAKEY |
+                                     V4L2_FBUF_FLAG_SRC_CHROMAKEY;
+       const unsigned alpha_flags = V4L2_FBUF_FLAG_GLOBAL_ALPHA |
+                                    V4L2_FBUF_FLAG_LOCAL_ALPHA |
+                                    V4L2_FBUF_FLAG_LOCAL_INV_ALPHA;
+
+
+       if ((a->flags & chroma_flags) == chroma_flags)
+               return -EINVAL;
+       switch (a->flags & alpha_flags) {
+       case 0:
+       case V4L2_FBUF_FLAG_GLOBAL_ALPHA:
+       case V4L2_FBUF_FLAG_LOCAL_ALPHA:
+       case V4L2_FBUF_FLAG_LOCAL_INV_ALPHA:
+               break;
+       default:
+               return -EINVAL;
+       }
+       dev->fbuf_out_flags &= ~(chroma_flags | alpha_flags);
+       dev->fbuf_out_flags = a->flags & (chroma_flags | alpha_flags);
+       return 0;
+}
+
+static const struct v4l2_audioout vivid_audio_outputs[] = {
+       { 0, "Line-Out 1" },
+       { 1, "Line-Out 2" },
+};
+
+int vidioc_enum_output(struct file *file, void *priv,
+                               struct v4l2_output *out)
+{
+       struct vivid_dev *dev = video_drvdata(file);
+
+       if (out->index >= dev->num_outputs)
+               return -EINVAL;
+
+       out->type = V4L2_OUTPUT_TYPE_ANALOG;
+       switch (dev->output_type[out->index]) {
+       case SVID:
+               snprintf(out->name, sizeof(out->name), "S-Video %u",
+                               dev->output_name_counter[out->index]);
+               out->std = V4L2_STD_ALL;
+               if (dev->has_audio_outputs)
+                       out->audioset = (1 << ARRAY_SIZE(vivid_audio_outputs)) - 1;
+               out->capabilities = V4L2_OUT_CAP_STD;
+               break;
+       case HDMI:
+               snprintf(out->name, sizeof(out->name), "HDMI %u",
+                               dev->output_name_counter[out->index]);
+               out->capabilities = V4L2_OUT_CAP_DV_TIMINGS;
+               break;
+       }
+       return 0;
+}
+
+int vidioc_g_output(struct file *file, void *priv, unsigned *o)
+{
+       struct vivid_dev *dev = video_drvdata(file);
+
+       *o = dev->output;
+       return 0;
+}
+
+int vidioc_s_output(struct file *file, void *priv, unsigned o)
+{
+       struct vivid_dev *dev = video_drvdata(file);
+
+       if (o >= dev->num_outputs)
+               return -EINVAL;
+
+       if (o == dev->output)
+               return 0;
+
+       if (vb2_is_busy(&dev->vb_vid_out_q) || vb2_is_busy(&dev->vb_vbi_out_q))
+               return -EBUSY;
+
+       dev->output = o;
+       dev->tv_audio_output = 0;
+       if (dev->output_type[o] == SVID)
+               dev->vid_out_dev.tvnorms = V4L2_STD_ALL;
+       else
+               dev->vid_out_dev.tvnorms = 0;
+
+       dev->vbi_out_dev.tvnorms = dev->vid_out_dev.tvnorms;
+       vivid_update_format_out(dev);
+       return 0;
+}
+
+int vidioc_enumaudout(struct file *file, void *fh, struct v4l2_audioout *vout)
+{
+       if (vout->index >= ARRAY_SIZE(vivid_audio_outputs))
+               return -EINVAL;
+       *vout = vivid_audio_outputs[vout->index];
+       return 0;
+}
+
+int vidioc_g_audout(struct file *file, void *fh, struct v4l2_audioout *vout)
+{
+       struct vivid_dev *dev = video_drvdata(file);
+
+       if (!vivid_is_svid_out(dev))
+               return -EINVAL;
+       *vout = vivid_audio_outputs[dev->tv_audio_output];
+       return 0;
+}
+
+int vidioc_s_audout(struct file *file, void *fh, const struct v4l2_audioout *vout)
+{
+       struct vivid_dev *dev = video_drvdata(file);
+
+       if (!vivid_is_svid_out(dev))
+               return -EINVAL;
+       if (vout->index >= ARRAY_SIZE(vivid_audio_outputs))
+               return -EINVAL;
+       dev->tv_audio_output = vout->index;
+       return 0;
+}
+
+int vivid_vid_out_s_std(struct file *file, void *priv, v4l2_std_id id)
+{
+       struct vivid_dev *dev = video_drvdata(file);
+
+       if (!vivid_is_svid_out(dev))
+               return -ENODATA;
+       if (dev->std_out == id)
+               return 0;
+       if (vb2_is_busy(&dev->vb_vid_out_q) || vb2_is_busy(&dev->vb_vbi_out_q))
+               return -EBUSY;
+       dev->std_out = id;
+       vivid_update_format_out(dev);
+       return 0;
+}
+
+int vivid_vid_out_s_dv_timings(struct file *file, void *_fh,
+                                   struct v4l2_dv_timings *timings)
+{
+       struct vivid_dev *dev = video_drvdata(file);
+
+       if (!vivid_is_hdmi_out(dev))
+               return -ENODATA;
+       if (vb2_is_busy(&dev->vb_vid_out_q))
+               return -EBUSY;
+       if (!v4l2_find_dv_timings_cap(timings, &vivid_dv_timings_cap,
+                               0, NULL, NULL))
+               return -EINVAL;
+       if (v4l2_match_dv_timings(timings, &dev->dv_timings_out, 0))
+               return 0;
+       dev->dv_timings_out = *timings;
+       vivid_update_format_out(dev);
+       return 0;
+}
+
+int vivid_vid_out_g_parm(struct file *file, void *priv,
+                         struct v4l2_streamparm *parm)
+{
+       struct vivid_dev *dev = video_drvdata(file);
+
+       if (parm->type != (dev->multiplanar ?
+                          V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE :
+                          V4L2_BUF_TYPE_VIDEO_OUTPUT))
+               return -EINVAL;
+
+       parm->parm.output.capability   = V4L2_CAP_TIMEPERFRAME;
+       parm->parm.output.timeperframe = dev->timeperframe_vid_out;
+       parm->parm.output.writebuffers  = 1;
+return 0;
+}
+
+int vidioc_subscribe_event(struct v4l2_fh *fh,
+                       const struct v4l2_event_subscription *sub)
+{
+       switch (sub->type) {
+       case V4L2_EVENT_CTRL:
+               return v4l2_ctrl_subscribe_event(fh, sub);
+       case V4L2_EVENT_SOURCE_CHANGE:
+               if (fh->vdev->vfl_dir == VFL_DIR_RX)
+                       return v4l2_src_change_event_subscribe(fh, sub);
+               break;
+       default:
+               break;
+       }
+       return -EINVAL;
+}
diff --git a/drivers/media/platform/vivid/vivid-vid-out.h b/drivers/media/platform/vivid/vivid-vid-out.h
new file mode 100644 (file)
index 0000000..dfa84db
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ * vivid-vid-out.h - video output support functions.
+ *
+ * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
+ *
+ * This program is free software; you may redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * 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 _VIVID_VID_OUT_H_
+#define _VIVID_VID_OUT_H_
+
+extern const struct vb2_ops vivid_vid_out_qops;
+
+void vivid_update_format_out(struct vivid_dev *dev);
+
+int vivid_g_fmt_vid_out(struct file *file, void *priv, struct v4l2_format *f);
+int vivid_try_fmt_vid_out(struct file *file, void *priv, struct v4l2_format *f);
+int vivid_s_fmt_vid_out(struct file *file, void *priv, struct v4l2_format *f);
+int vidioc_g_fmt_vid_out_mplane(struct file *file, void *priv, struct v4l2_format *f);
+int vidioc_try_fmt_vid_out_mplane(struct file *file, void *priv, struct v4l2_format *f);
+int vidioc_s_fmt_vid_out_mplane(struct file *file, void *priv, struct v4l2_format *f);
+int vidioc_g_fmt_vid_out(struct file *file, void *priv, struct v4l2_format *f);
+int vidioc_try_fmt_vid_out(struct file *file, void *priv, struct v4l2_format *f);
+int vidioc_s_fmt_vid_out(struct file *file, void *priv, struct v4l2_format *f);
+int vivid_vid_out_g_selection(struct file *file, void *priv, struct v4l2_selection *sel);
+int vivid_vid_out_s_selection(struct file *file, void *fh, struct v4l2_selection *s);
+int vivid_vid_out_cropcap(struct file *file, void *fh, struct v4l2_cropcap *cap);
+int vidioc_enum_fmt_vid_out_overlay(struct file *file, void  *priv, struct v4l2_fmtdesc *f);
+int vidioc_g_fmt_vid_out_overlay(struct file *file, void *priv, struct v4l2_format *f);
+int vidioc_try_fmt_vid_out_overlay(struct file *file, void *priv, struct v4l2_format *f);
+int vidioc_s_fmt_vid_out_overlay(struct file *file, void *priv, struct v4l2_format *f);
+int vivid_vid_out_overlay(struct file *file, void *fh, unsigned i);
+int vivid_vid_out_g_fbuf(struct file *file, void *fh, struct v4l2_framebuffer *a);
+int vivid_vid_out_s_fbuf(struct file *file, void *fh, const struct v4l2_framebuffer *a);
+int vidioc_enum_output(struct file *file, void *priv, struct v4l2_output *out);
+int vidioc_g_output(struct file *file, void *priv, unsigned *i);
+int vidioc_s_output(struct file *file, void *priv, unsigned i);
+int vidioc_enumaudout(struct file *file, void *fh, struct v4l2_audioout *vout);
+int vidioc_g_audout(struct file *file, void *fh, struct v4l2_audioout *vout);
+int vidioc_s_audout(struct file *file, void *fh, const struct v4l2_audioout *vout);
+int vivid_vid_out_s_std(struct file *file, void *priv, v4l2_std_id id);
+int vivid_vid_out_s_dv_timings(struct file *file, void *_fh, struct v4l2_dv_timings *timings);
+int vivid_vid_out_g_parm(struct file *file, void *priv, struct v4l2_streamparm *parm);
+
+#endif
index 235c0e349820702cf53387f952262e506eee9e06..cff1eb144a5c71f5db9fa46f10c5c5363cf939d1 100644 (file)
@@ -332,7 +332,7 @@ static int __init gemtek_init(void)
 
 static void __exit gemtek_exit(void)
 {
-       hardmute = 1;   /* Turn off PLL */
+       hardmute = true;        /* Turn off PLL */
 #ifdef CONFIG_PNP
        pnp_unregister_driver(&gemtek_driver.pnp_driver);
 #endif
index d7ce8fe6b5ae1a89c5c578a9f2d88d20aaeecca7..28a89466cddc4a82985a6ab01785c093fa8c91ff 100644 (file)
@@ -56,7 +56,7 @@ struct fmi
 
 static struct fmi fmi_card;
 static struct pnp_dev *dev;
-bool pnp_attached;
+static bool pnp_attached;
 
 #define RSF16_MINFREQ (87U * 16000)
 #define RSF16_MAXFREQ (108U * 16000)
@@ -285,7 +285,7 @@ static int __init fmi_init(void)
                                io = isapnp_fmi_probe();
                                if (io < 0)
                                        continue;
-                               pnp_attached = 1;
+                               pnp_attached = true;
                        }
                        if (!request_region(io, 2, "radio-sf16fmi")) {
                                if (pnp_attached)
@@ -349,7 +349,7 @@ static int __init fmi_init(void)
        mutex_init(&fmi->lock);
 
        /* mute card and set default frequency */
-       fmi->mute = 1;
+       fmi->mute = true;
        fmi->curfreq = RSF16_MINFREQ;
        fmi_set_freq(fmi);
 
index 93d864eb830627898c82d3d33416466819ee5c76..b8d61cbc18cb5d7b9c2dd902c2900c32c399cf1a 100644 (file)
@@ -305,7 +305,7 @@ static void fmr2_pnp_remove(struct pnp_dev *pdev)
        pnp_set_drvdata(pdev, NULL);
 }
 
-struct isa_driver fmr2_isa_driver = {
+static struct isa_driver fmr2_isa_driver = {
        .match          = fmr2_isa_match,
        .remove         = fmr2_isa_remove,
        .driver         = {
@@ -313,7 +313,7 @@ struct isa_driver fmr2_isa_driver = {
        },
 };
 
-struct pnp_driver fmr2_pnp_driver = {
+static struct pnp_driver fmr2_pnp_driver = {
        .name           = "radio-sf16fmr2",
        .id_table       = fmr2_pnp_ids,
        .probe          = fmr2_pnp_probe,
index 925049654c5bc0f33429b45b5cab5fff3795f8e8..cc3990111411bd8b06b4d86ad3d4da9b72a54c94 100644 (file)
@@ -124,11 +124,11 @@ struct tea5764_regs {
 
 struct tea5764_write_regs {
        u8 intreg;                              /* INTMSK */
-       u16 frqset;                             /* FRQSETMSB & FRQSETLSB */
-       u16 tnctrl;                             /* TNCTRL1 & TNCTRL2 */
-       u16 testreg;                            /* TESTBITS & TESTMODE */
-       u16 rdsctrl;                            /* RDSCTRL1 & RDSCTRL2 */
-       u16 rdsbbl;                             /* PAUSEDET & RDSBBL */
+       __be16 frqset;                          /* FRQSETMSB & FRQSETLSB */
+       __be16 tnctrl;                          /* TNCTRL1 & TNCTRL2 */
+       __be16 testreg;                         /* TESTBITS & TESTMODE */
+       __be16 rdsctrl;                         /* RDSCTRL1 & RDSCTRL2 */
+       __be16 rdsbbl;                          /* PAUSEDET & RDSBBL */
 } __attribute__ ((packed));
 
 #ifdef CONFIG_RADIO_TEA5764_XTAL
@@ -165,7 +165,7 @@ static int tea5764_i2c_read(struct tea5764_device *radio)
        if (i2c_transfer(radio->i2c_client->adapter, msgs, 1) != 1)
                return -EIO;
        for (i = 0; i < sizeof(struct tea5764_regs) / sizeof(u16); i++)
-               p[i] = __be16_to_cpu(p[i]);
+               p[i] = __be16_to_cpu((__force __be16)p[i]);
 
        return 0;
 }
index 0e750aef656a6f8a053aafbd965b4e9e1fe64f23..909c3f92d83920de0561d9dc59aa31171826d973 100644 (file)
@@ -208,7 +208,7 @@ static int si470x_set_band(struct si470x_device *radio, int band)
 static int si470x_set_chan(struct si470x_device *radio, unsigned short chan)
 {
        int retval;
-       bool timed_out = 0;
+       bool timed_out = false;
 
        /* start tuning */
        radio->registers[CHANNEL] &= ~CHANNEL_CHAN;
@@ -300,7 +300,7 @@ static int si470x_set_seek(struct si470x_device *radio,
 {
        int band, retval;
        unsigned int freq;
-       bool timed_out = 0;
+       bool timed_out = false;
 
        /* set band */
        if (seek->rangelow || seek->rangehigh) {
index 494fac061306ed498a02dff4049cb0223d45f621..57f0bc3b60e7d3a54943ee685c17b295050f79e4 100644 (file)
@@ -607,9 +607,7 @@ static int si470x_usb_driver_probe(struct usb_interface *intf,
        /* Set up interrupt endpoint information. */
        for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
                endpoint = &iface_desc->endpoint[i].desc;
-               if (((endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK) ==
-                USB_DIR_IN) && ((endpoint->bmAttributes &
-                USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_INT))
+               if (usb_endpoint_is_int_in(endpoint))
                        radio->int_in_endpoint = endpoint;
        }
        if (!radio->int_in_endpoint) {
index 4b2e9e8298e1f6e962a468eeb1fba4b91b5c68bd..6f28f6e02ea57e947a2a8805ccccee4cfaa30cc2 100644 (file)
@@ -440,7 +440,7 @@ static int fm_send_cmd(struct fmdev *fmdev, u8 fm_op, u16 type,     void *payload,
                 * command with u16 payload - convert to be16
                 */
                if (payload != NULL)
-                       *(u16 *)payload = cpu_to_be16(*(u16 *)payload);
+                       *(__be16 *)payload = cpu_to_be16(*(u16 *)payload);
 
        } else if (payload != NULL) {
                fm_cb(skb)->fm_op = *((u8 *)payload + 2);
@@ -595,7 +595,7 @@ static void fm_irq_handle_flag_getcmd_resp(struct fmdev *fmdev)
        skb_pull(skb, sizeof(struct fm_event_msg_hdr));
        memcpy(&fmdev->irq_info.flag, skb->data, fm_evt_hdr->dlen);
 
-       fmdev->irq_info.flag = be16_to_cpu(fmdev->irq_info.flag);
+       fmdev->irq_info.flag = be16_to_cpu((__force __be16)fmdev->irq_info.flag);
        fmdbg("irq: flag register(0x%x)\n", fmdev->irq_info.flag);
 
        /* Continue next function in interrupt handler table */
@@ -764,7 +764,7 @@ static void fm_irq_handle_rdsdata_getcmd_resp(struct fmdev *fmdev)
                         * Extract PI code and store in local cache.
                         * We need this during AF switch processing.
                         */
-                       cur_picode = be16_to_cpu(rds_fmt.data.groupgeneral.pidata);
+                       cur_picode = be16_to_cpu((__force __be16)rds_fmt.data.groupgeneral.pidata);
                        if (fmdev->rx.stat_info.picode != cur_picode)
                                fmdev->rx.stat_info.picode = cur_picode;
 
@@ -989,7 +989,7 @@ static void fm_irq_afjump_rd_freq_resp(struct fmdev *fmdev)
        /* Skip header info and copy only response data */
        skb_pull(skb, sizeof(struct fm_event_msg_hdr));
        memcpy(&read_freq, skb->data, sizeof(read_freq));
-       read_freq = be16_to_cpu(read_freq);
+       read_freq = be16_to_cpu((__force __be16)read_freq);
        curr_freq = fmdev->rx.region.bot_freq + ((u32)read_freq * FM_FREQ_MUL);
 
        jumped_freq = fmdev->rx.stat_info.af_cache[fmdev->rx.afjump_idx];
@@ -1317,7 +1317,8 @@ static int load_default_rx_configuration(struct fmdev *fmdev)
 /* Does FM power on sequence */
 static int fm_power_up(struct fmdev *fmdev, u8 mode)
 {
-       u16 payload, asic_id, asic_ver;
+       u16 payload;
+       __be16 asic_id, asic_ver;
        int resp_len, ret;
        u8 fw_name[50];
 
index ebf09a3927deea0f34070d54aa6e3c65b7bd1742..09632cb26cb6980b06238fc1b09bc2b218343e32 100644 (file)
@@ -116,7 +116,7 @@ int fm_rx_set_freq(struct fmdev *fmdev, u32 freq)
        if (ret < 0)
                goto exit;
 
-       curr_frq = be16_to_cpu(curr_frq);
+       curr_frq = be16_to_cpu((__force __be16)curr_frq);
        curr_frq_in_khz = (fmdev->rx.region.bot_freq + ((u32)curr_frq * FM_FREQ_MUL));
 
        if (curr_frq_in_khz != freq) {
@@ -189,7 +189,7 @@ int fm_rx_seek(struct fmdev *fmdev, u32 seek_upward,
        if (ret < 0)
                return ret;
 
-       curr_frq = be16_to_cpu(curr_frq);
+       curr_frq = be16_to_cpu((__force __be16)curr_frq);
        last_frq = (fmdev->rx.region.top_freq - fmdev->rx.region.bot_freq) / FM_FREQ_MUL;
 
        /* Check the offset in order to be aligned to the channel spacing*/
@@ -285,7 +285,7 @@ again:
                if (ret < 0)
                        return ret;
 
-               curr_frq = be16_to_cpu(curr_frq);
+               curr_frq = be16_to_cpu((__force __be16)curr_frq);
                fmdev->rx.freq = (fmdev->rx.region.bot_freq +
                                ((u32)curr_frq * FM_FREQ_MUL));
 
@@ -517,7 +517,7 @@ int fm_rx_set_rfdepend_softmute(struct fmdev *fmdev, u8 rfdepend_mute)
 /* Returns the signal strength level of current channel */
 int fm_rx_get_rssi_level(struct fmdev *fmdev, u16 *rssilvl)
 {
-       u16 curr_rssi_lel;
+       __be16 curr_rssi_lel;
        u32 resp_len;
        int ret;
 
@@ -608,7 +608,7 @@ int fm_rx_set_stereo_mono(struct fmdev *fmdev, u16 mode)
 /* Gets current RX stereo/mono mode */
 int fm_rx_get_stereo_mono(struct fmdev *fmdev, u16 *mode)
 {
-       u16 curr_mode;
+       __be16 curr_mode;
        u32 resp_len;
        int ret;
 
index 6ea33e09d63b23b306979142ace913d6806f561f..839970b0f313522a31edfc0430f0d15652f47526 100644 (file)
@@ -374,7 +374,7 @@ int fm_tx_get_tune_cap_val(struct fmdev *fmdev)
        if (ret < 0)
                return ret;
 
-       curr_val = be16_to_cpu(curr_val);
+       curr_val = be16_to_cpu((__force __be16)curr_val);
 
        return curr_val;
 }
index 5e626af8e3130b0a7fbed625c1f7b1101f696270..8ce08107a69d5801d6de12b5ad0f5e9aa7daeacc 100644 (file)
@@ -164,6 +164,16 @@ config IR_ENE
           To compile this driver as a module, choose M here: the
           module will be called ene_ir.
 
+config IR_HIX5HD2
+       tristate "Hisilicon hix5hd2 IR remote control"
+       depends on RC_CORE
+       help
+        Say Y here if you want to use hisilicon hix5hd2 remote control.
+        To compile this driver as a module, choose M here: the module will be
+        called ir-hix5hd2.
+
+        If you're not sure, select N here
+
 config IR_IMON
        tristate "SoundGraph iMON Receiver and Display"
        depends on USB_ARCH_HAS_HCD
@@ -333,7 +343,8 @@ config IR_GPIO_CIR
 
 config RC_ST
        tristate "ST remote control receiver"
-       depends on ARCH_STI && RC_CORE
+       depends on RC_CORE
+       depends on ARCH_STI || COMPILE_TEST
        help
         Say Y here if you want support for ST remote control driver
         which allows both IR and UHF RX.
@@ -344,7 +355,7 @@ config RC_ST
 config IR_SUNXI
     tristate "SUNXI IR remote control"
     depends on RC_CORE
-    depends on ARCH_SUNXI
+    depends on ARCH_SUNXI || COMPILE_TEST
     ---help---
       Say Y if you want to use sunXi internal IR Controller
 
index 9f9843a1af5f2d61ee2ee851d4ef4519135e949c..0989f940e9cfa8d213706ca4989974584561117d 100644 (file)
@@ -17,6 +17,7 @@ obj-$(CONFIG_IR_XMP_DECODER) += ir-xmp-decoder.o
 
 # stand-alone IR receivers/transmitters
 obj-$(CONFIG_RC_ATI_REMOTE) += ati_remote.o
+obj-$(CONFIG_IR_HIX5HD2) += ir-hix5hd2.o
 obj-$(CONFIG_IR_IMON) += imon.o
 obj-$(CONFIG_IR_ITE_CIR) += ite-cir.o
 obj-$(CONFIG_IR_MCEUSB) += mceusb.o
index d16d9b496b92e4f1b1f66fa87b01af7d5757501e..e80f2c6c5f1abf040428f4f6c14666de271ee016 100644 (file)
@@ -979,7 +979,7 @@ static int ene_transmit(struct rc_dev *rdev, unsigned *buf, unsigned n)
        dev->tx_reg = 0;
        dev->tx_done = 0;
        dev->tx_sample = 0;
-       dev->tx_sample_pulse = 0;
+       dev->tx_sample_pulse = false;
 
        dbg("TX: %d samples", dev->tx_len);
 
index f0a1f7d31ee6578925308b9be608f762c5b37fde..b5167573240e3631cd8d3ae74ccc6ec1893eed08 100644 (file)
@@ -148,7 +148,6 @@ static int fintek_hw_detect(struct fintek_dev *fintek)
        u8 vendor_major, vendor_minor;
        u8 portsel, ir_class;
        u16 vendor, chip;
-       int ret = 0;
 
        fintek_config_mode_enable(fintek);
 
@@ -208,7 +207,7 @@ static int fintek_hw_detect(struct fintek_dev *fintek)
 
        spin_unlock_irqrestore(&fintek->fintek_lock, flags);
 
-       return ret;
+       return 0;
 }
 
 static void fintek_cir_ldev_init(struct fintek_dev *fintek)
@@ -644,7 +643,6 @@ static int fintek_suspend(struct pnp_dev *pdev, pm_message_t state)
 
 static int fintek_resume(struct pnp_dev *pdev)
 {
-       int ret = 0;
        struct fintek_dev *fintek = pnp_get_drvdata(pdev);
 
        fit_dbg("%s called", __func__);
@@ -661,7 +659,7 @@ static int fintek_resume(struct pnp_dev *pdev)
 
        fintek_cir_regs_init(fintek);
 
-       return ret;
+       return 0;
 }
 
 static void fintek_shutdown(struct pnp_dev *pdev)
index bfb282a714e8e2ca8bc77777ed375961d6e01a5f..ec49f94425fc757ddc107578adeaa257a1ebd77a 100644 (file)
 /* Decoders lock (only modified to preprocess them) */
 static DEFINE_SPINLOCK(img_ir_decoders_lock);
 
-extern struct img_ir_decoder img_ir_nec;
-extern struct img_ir_decoder img_ir_jvc;
-extern struct img_ir_decoder img_ir_sony;
-extern struct img_ir_decoder img_ir_sharp;
-extern struct img_ir_decoder img_ir_sanyo;
-
 static bool img_ir_decoders_preprocessed;
 static struct img_ir_decoder *img_ir_decoders[] = {
 #ifdef CONFIG_IR_IMG_NEC
index 3e40ce87b898047f511877c547c382898c7db40e..8fcc16c32c5bcd5ce1edc3a1744b30eeb2f1497a 100644 (file)
@@ -168,6 +168,12 @@ struct img_ir_decoder {
                      struct img_ir_filter *out, u64 protocols);
 };
 
+extern struct img_ir_decoder img_ir_nec;
+extern struct img_ir_decoder img_ir_jvc;
+extern struct img_ir_decoder img_ir_sony;
+extern struct img_ir_decoder img_ir_sharp;
+extern struct img_ir_decoder img_ir_sanyo;
+
 /**
  * struct img_ir_reg_timings - Reg values for decoder timings at clock rate.
  * @ctrl:      Processed control register value.
index 7115e68ba6978d36689e96ac0d32628646fc9664..b8837dd39bb2a52740a36765d69d75af464f51fa 100644 (file)
@@ -87,6 +87,18 @@ static ssize_t lcd_write(struct file *file, const char __user *buf,
 
 /*** G L O B A L S ***/
 
+struct imon_panel_key_table {
+       u64 hw_code;
+       u32 keycode;
+};
+
+struct imon_usb_dev_descr {
+       __u16 flags;
+#define IMON_NO_FLAGS 0
+#define IMON_NEED_20MS_PKT_DELAY 1
+       struct imon_panel_key_table key_table[];
+};
+
 struct imon_context {
        struct device *dev;
        /* Newer devices have two interfaces */
@@ -150,6 +162,8 @@ struct imon_context {
        struct timer_list ttimer;       /* touch screen timer */
        int touch_x;                    /* x coordinate on touchscreen */
        int touch_y;                    /* y coordinate on touchscreen */
+       struct imon_usb_dev_descr *dev_descr; /* device description with key
+                                                table for front panels */
 };
 
 #define TOUCH_TIMEOUT  (HZ/30)
@@ -186,8 +200,132 @@ enum {
        IMON_KEY_PANEL  = 2,
 };
 
-enum {
-       IMON_NEED_20MS_PKT_DELAY = 1
+static struct usb_class_driver imon_vfd_class = {
+       .name           = DEVICE_NAME,
+       .fops           = &vfd_fops,
+       .minor_base     = DISPLAY_MINOR_BASE,
+};
+
+static struct usb_class_driver imon_lcd_class = {
+       .name           = DEVICE_NAME,
+       .fops           = &lcd_fops,
+       .minor_base     = DISPLAY_MINOR_BASE,
+};
+
+/* imon receiver front panel/knob key table */
+static const struct imon_usb_dev_descr imon_default_table = {
+       .flags = IMON_NO_FLAGS,
+       .key_table = {
+               { 0x000000000f00ffeell, KEY_MEDIA }, /* Go */
+               { 0x000000001200ffeell, KEY_UP },
+               { 0x000000001300ffeell, KEY_DOWN },
+               { 0x000000001400ffeell, KEY_LEFT },
+               { 0x000000001500ffeell, KEY_RIGHT },
+               { 0x000000001600ffeell, KEY_ENTER },
+               { 0x000000001700ffeell, KEY_ESC },
+               { 0x000000001f00ffeell, KEY_AUDIO },
+               { 0x000000002000ffeell, KEY_VIDEO },
+               { 0x000000002100ffeell, KEY_CAMERA },
+               { 0x000000002700ffeell, KEY_DVD },
+               { 0x000000002300ffeell, KEY_TV },
+               { 0x000000002b00ffeell, KEY_EXIT },
+               { 0x000000002c00ffeell, KEY_SELECT },
+               { 0x000000002d00ffeell, KEY_MENU },
+               { 0x000000000500ffeell, KEY_PREVIOUS },
+               { 0x000000000700ffeell, KEY_REWIND },
+               { 0x000000000400ffeell, KEY_STOP },
+               { 0x000000003c00ffeell, KEY_PLAYPAUSE },
+               { 0x000000000800ffeell, KEY_FASTFORWARD },
+               { 0x000000000600ffeell, KEY_NEXT },
+               { 0x000000010000ffeell, KEY_RIGHT },
+               { 0x000001000000ffeell, KEY_LEFT },
+               { 0x000000003d00ffeell, KEY_SELECT },
+               { 0x000100000000ffeell, KEY_VOLUMEUP },
+               { 0x010000000000ffeell, KEY_VOLUMEDOWN },
+               { 0x000000000100ffeell, KEY_MUTE },
+               /* 0xffdc iMON MCE VFD */
+               { 0x00010000ffffffeell, KEY_VOLUMEUP },
+               { 0x01000000ffffffeell, KEY_VOLUMEDOWN },
+               { 0x00000001ffffffeell, KEY_MUTE },
+               { 0x0000000fffffffeell, KEY_MEDIA },
+               { 0x00000012ffffffeell, KEY_UP },
+               { 0x00000013ffffffeell, KEY_DOWN },
+               { 0x00000014ffffffeell, KEY_LEFT },
+               { 0x00000015ffffffeell, KEY_RIGHT },
+               { 0x00000016ffffffeell, KEY_ENTER },
+               { 0x00000017ffffffeell, KEY_ESC },
+               /* iMON Knob values */
+               { 0x000100ffffffffeell, KEY_VOLUMEUP },
+               { 0x010000ffffffffeell, KEY_VOLUMEDOWN },
+               { 0x000008ffffffffeell, KEY_MUTE },
+               { 0, KEY_RESERVED },
+       }
+};
+
+static const struct imon_usb_dev_descr imon_OEM_VFD = {
+       .flags = IMON_NEED_20MS_PKT_DELAY,
+       .key_table = {
+               { 0x000000000f00ffeell, KEY_MEDIA }, /* Go */
+               { 0x000000001200ffeell, KEY_UP },
+               { 0x000000001300ffeell, KEY_DOWN },
+               { 0x000000001400ffeell, KEY_LEFT },
+               { 0x000000001500ffeell, KEY_RIGHT },
+               { 0x000000001600ffeell, KEY_ENTER },
+               { 0x000000001700ffeell, KEY_ESC },
+               { 0x000000001f00ffeell, KEY_AUDIO },
+               { 0x000000002b00ffeell, KEY_EXIT },
+               { 0x000000002c00ffeell, KEY_SELECT },
+               { 0x000000002d00ffeell, KEY_MENU },
+               { 0x000000000500ffeell, KEY_PREVIOUS },
+               { 0x000000000700ffeell, KEY_REWIND },
+               { 0x000000000400ffeell, KEY_STOP },
+               { 0x000000003c00ffeell, KEY_PLAYPAUSE },
+               { 0x000000000800ffeell, KEY_FASTFORWARD },
+               { 0x000000000600ffeell, KEY_NEXT },
+               { 0x000000010000ffeell, KEY_RIGHT },
+               { 0x000001000000ffeell, KEY_LEFT },
+               { 0x000000003d00ffeell, KEY_SELECT },
+               { 0x000100000000ffeell, KEY_VOLUMEUP },
+               { 0x010000000000ffeell, KEY_VOLUMEDOWN },
+               { 0x000000000100ffeell, KEY_MUTE },
+               /* 0xffdc iMON MCE VFD */
+               { 0x00010000ffffffeell, KEY_VOLUMEUP },
+               { 0x01000000ffffffeell, KEY_VOLUMEDOWN },
+               { 0x00000001ffffffeell, KEY_MUTE },
+               { 0x0000000fffffffeell, KEY_MEDIA },
+               { 0x00000012ffffffeell, KEY_UP },
+               { 0x00000013ffffffeell, KEY_DOWN },
+               { 0x00000014ffffffeell, KEY_LEFT },
+               { 0x00000015ffffffeell, KEY_RIGHT },
+               { 0x00000016ffffffeell, KEY_ENTER },
+               { 0x00000017ffffffeell, KEY_ESC },
+               /* iMON Knob values */
+               { 0x000100ffffffffeell, KEY_VOLUMEUP },
+               { 0x010000ffffffffeell, KEY_VOLUMEDOWN },
+               { 0x000008ffffffffeell, KEY_MUTE },
+               { 0, KEY_RESERVED },
+       }
+};
+
+/* imon receiver front panel/knob key table for DH102*/
+static const struct imon_usb_dev_descr imon_DH102 = {
+       .flags = IMON_NO_FLAGS,
+       .key_table = {
+               { 0x000100000000ffeell, KEY_VOLUMEUP },
+               { 0x010000000000ffeell, KEY_VOLUMEDOWN },
+               { 0x000000010000ffeell, KEY_MUTE },
+               { 0x0000000f0000ffeell, KEY_MEDIA },
+               { 0x000000120000ffeell, KEY_UP },
+               { 0x000000130000ffeell, KEY_DOWN },
+               { 0x000000140000ffeell, KEY_LEFT },
+               { 0x000000150000ffeell, KEY_RIGHT },
+               { 0x000000160000ffeell, KEY_ENTER },
+               { 0x000000170000ffeell, KEY_ESC },
+               { 0x0000002b0000ffeell, KEY_EXIT },
+               { 0x0000002c0000ffeell, KEY_SELECT },
+               { 0x0000002d0000ffeell, KEY_MENU },
+               { 0, KEY_RESERVED }
+       }
 };
 
 /*
@@ -208,7 +346,8 @@ static struct usb_device_id imon_usb_id_table[] = {
         * SoundGraph iMON PAD (IR & LCD)
         * SoundGraph iMON Knob (IR only)
         */
-       { USB_DEVICE(0x15c2, 0xffdc) },
+       { USB_DEVICE(0x15c2, 0xffdc),
+         .driver_info = (unsigned long)&imon_default_table },
 
        /*
         * Newer devices, all driven by the latest iMON Windows driver, full
@@ -216,43 +355,62 @@ static struct usb_device_id imon_usb_id_table[] = {
         * Need user input to fill in details on unknown devices.
         */
        /* SoundGraph iMON OEM Touch LCD (IR & 7" VGA LCD) */
-       { USB_DEVICE(0x15c2, 0x0034) },
+       { USB_DEVICE(0x15c2, 0x0034),
+         .driver_info = (unsigned long)&imon_DH102 },
        /* SoundGraph iMON OEM Touch LCD (IR & 4.3" VGA LCD) */
-       { USB_DEVICE(0x15c2, 0x0035) },
+       { USB_DEVICE(0x15c2, 0x0035),
+         .driver_info = (unsigned long)&imon_default_table},
        /* SoundGraph iMON OEM VFD (IR & VFD) */
-       { USB_DEVICE(0x15c2, 0x0036), .driver_info = IMON_NEED_20MS_PKT_DELAY },
+       { USB_DEVICE(0x15c2, 0x0036),
+         .driver_info = (unsigned long)&imon_OEM_VFD },
        /* device specifics unknown */
-       { USB_DEVICE(0x15c2, 0x0037) },
+       { USB_DEVICE(0x15c2, 0x0037),
+         .driver_info = (unsigned long)&imon_default_table},
        /* SoundGraph iMON OEM LCD (IR & LCD) */
-       { USB_DEVICE(0x15c2, 0x0038) },
+       { USB_DEVICE(0x15c2, 0x0038),
+         .driver_info = (unsigned long)&imon_default_table},
        /* SoundGraph iMON UltraBay (IR & LCD) */
-       { USB_DEVICE(0x15c2, 0x0039) },
+       { USB_DEVICE(0x15c2, 0x0039),
+         .driver_info = (unsigned long)&imon_default_table},
        /* device specifics unknown */
-       { USB_DEVICE(0x15c2, 0x003a) },
+       { USB_DEVICE(0x15c2, 0x003a),
+         .driver_info = (unsigned long)&imon_default_table},
        /* device specifics unknown */
-       { USB_DEVICE(0x15c2, 0x003b) },
+       { USB_DEVICE(0x15c2, 0x003b),
+         .driver_info = (unsigned long)&imon_default_table},
        /* SoundGraph iMON OEM Inside (IR only) */
-       { USB_DEVICE(0x15c2, 0x003c) },
+       { USB_DEVICE(0x15c2, 0x003c),
+         .driver_info = (unsigned long)&imon_default_table},
        /* device specifics unknown */
-       { USB_DEVICE(0x15c2, 0x003d) },
+       { USB_DEVICE(0x15c2, 0x003d),
+         .driver_info = (unsigned long)&imon_default_table},
        /* device specifics unknown */
-       { USB_DEVICE(0x15c2, 0x003e) },
+       { USB_DEVICE(0x15c2, 0x003e),
+         .driver_info = (unsigned long)&imon_default_table},
        /* device specifics unknown */
-       { USB_DEVICE(0x15c2, 0x003f) },
+       { USB_DEVICE(0x15c2, 0x003f),
+         .driver_info = (unsigned long)&imon_default_table},
        /* device specifics unknown */
-       { USB_DEVICE(0x15c2, 0x0040) },
+       { USB_DEVICE(0x15c2, 0x0040),
+         .driver_info = (unsigned long)&imon_default_table},
        /* SoundGraph iMON MINI (IR only) */
-       { USB_DEVICE(0x15c2, 0x0041) },
+       { USB_DEVICE(0x15c2, 0x0041),
+         .driver_info = (unsigned long)&imon_default_table},
        /* Antec Veris Multimedia Station EZ External (IR only) */
-       { USB_DEVICE(0x15c2, 0x0042) },
+       { USB_DEVICE(0x15c2, 0x0042),
+         .driver_info = (unsigned long)&imon_default_table},
        /* Antec Veris Multimedia Station Basic Internal (IR only) */
-       { USB_DEVICE(0x15c2, 0x0043) },
+       { USB_DEVICE(0x15c2, 0x0043),
+         .driver_info = (unsigned long)&imon_default_table},
        /* Antec Veris Multimedia Station Elite (IR & VFD) */
-       { USB_DEVICE(0x15c2, 0x0044) },
+       { USB_DEVICE(0x15c2, 0x0044),
+         .driver_info = (unsigned long)&imon_default_table},
        /* Antec Veris Multimedia Station Premiere (IR & LCD) */
-       { USB_DEVICE(0x15c2, 0x0045) },
+       { USB_DEVICE(0x15c2, 0x0045),
+         .driver_info = (unsigned long)&imon_default_table},
        /* device specifics unknown */
-       { USB_DEVICE(0x15c2, 0x0046) },
+       { USB_DEVICE(0x15c2, 0x0046),
+         .driver_info = (unsigned long)&imon_default_table},
        {}
 };
 
@@ -266,67 +424,6 @@ static struct usb_driver imon_driver = {
        .id_table       = imon_usb_id_table,
 };
 
-static struct usb_class_driver imon_vfd_class = {
-       .name           = DEVICE_NAME,
-       .fops           = &vfd_fops,
-       .minor_base     = DISPLAY_MINOR_BASE,
-};
-
-static struct usb_class_driver imon_lcd_class = {
-       .name           = DEVICE_NAME,
-       .fops           = &lcd_fops,
-       .minor_base     = DISPLAY_MINOR_BASE,
-};
-
-/* imon receiver front panel/knob key table */
-static const struct {
-       u64 hw_code;
-       u32 keycode;
-} imon_panel_key_table[] = {
-       { 0x000000000f00ffeell, KEY_MEDIA }, /* Go */
-       { 0x000000001200ffeell, KEY_UP },
-       { 0x000000001300ffeell, KEY_DOWN },
-       { 0x000000001400ffeell, KEY_LEFT },
-       { 0x000000001500ffeell, KEY_RIGHT },
-       { 0x000000001600ffeell, KEY_ENTER },
-       { 0x000000001700ffeell, KEY_ESC },
-       { 0x000000001f00ffeell, KEY_AUDIO },
-       { 0x000000002000ffeell, KEY_VIDEO },
-       { 0x000000002100ffeell, KEY_CAMERA },
-       { 0x000000002700ffeell, KEY_DVD },
-       { 0x000000002300ffeell, KEY_TV },
-       { 0x000000002b00ffeell, KEY_EXIT },
-       { 0x000000002c00ffeell, KEY_SELECT },
-       { 0x000000002d00ffeell, KEY_MENU },
-       { 0x000000000500ffeell, KEY_PREVIOUS },
-       { 0x000000000700ffeell, KEY_REWIND },
-       { 0x000000000400ffeell, KEY_STOP },
-       { 0x000000003c00ffeell, KEY_PLAYPAUSE },
-       { 0x000000000800ffeell, KEY_FASTFORWARD },
-       { 0x000000000600ffeell, KEY_NEXT },
-       { 0x000000010000ffeell, KEY_RIGHT },
-       { 0x000001000000ffeell, KEY_LEFT },
-       { 0x000000003d00ffeell, KEY_SELECT },
-       { 0x000100000000ffeell, KEY_VOLUMEUP },
-       { 0x010000000000ffeell, KEY_VOLUMEDOWN },
-       { 0x000000000100ffeell, KEY_MUTE },
-       /* 0xffdc iMON MCE VFD */
-       { 0x00010000ffffffeell, KEY_VOLUMEUP },
-       { 0x01000000ffffffeell, KEY_VOLUMEDOWN },
-       { 0x00000001ffffffeell, KEY_MUTE },
-       { 0x0000000fffffffeell, KEY_MEDIA },
-       { 0x00000012ffffffeell, KEY_UP },
-       { 0x00000013ffffffeell, KEY_DOWN },
-       { 0x00000014ffffffeell, KEY_LEFT },
-       { 0x00000015ffffffeell, KEY_RIGHT },
-       { 0x00000016ffffffeell, KEY_ENTER },
-       { 0x00000017ffffffeell, KEY_ESC },
-       /* iMON Knob values */
-       { 0x000100ffffffffeell, KEY_VOLUMEUP },
-       { 0x010000ffffffffeell, KEY_VOLUMEDOWN },
-       { 0x000008ffffffffeell, KEY_MUTE },
-};
-
 /* to prevent races between open() and disconnect(), probing, etc */
 static DEFINE_MUTEX(driver_lock);
 
@@ -1210,18 +1307,19 @@ static u32 imon_mce_key_lookup(struct imon_context *ictx, u32 scancode)
        return keycode;
 }
 
-static u32 imon_panel_key_lookup(u64 code)
+static u32 imon_panel_key_lookup(struct imon_context *ictx, u64 code)
 {
        int i;
        u32 keycode = KEY_RESERVED;
+       struct imon_panel_key_table *key_table = ictx->dev_descr->key_table;
 
-       for (i = 0; i < ARRAY_SIZE(imon_panel_key_table); i++) {
-               if (imon_panel_key_table[i].hw_code == (code | 0xffee)) {
-                       keycode = imon_panel_key_table[i].keycode;
+       for (i = 0; key_table[i].hw_code != 0; i++) {
+               if (key_table[i].hw_code == (code | 0xffee)) {
+                       keycode = key_table[i].keycode;
                        break;
                }
        }
-
+       ictx->release_code = false;
        return keycode;
 }
 
@@ -1340,7 +1438,7 @@ static void imon_pad_to_keys(struct imon_context *ictx, unsigned char *buf)
                                }
                                buf[2] = dir & 0xFF;
                                buf[3] = (dir >> 8) & 0xFF;
-                               scancode = be32_to_cpu(*((u32 *)buf));
+                               scancode = be32_to_cpu(*((__be32 *)buf));
                        }
                } else {
                        /*
@@ -1404,7 +1502,7 @@ static void imon_pad_to_keys(struct imon_context *ictx, unsigned char *buf)
                        }
                        buf[2] = dir & 0xFF;
                        buf[3] = (dir >> 8) & 0xFF;
-                       scancode = be32_to_cpu(*((u32 *)buf));
+                       scancode = be32_to_cpu(*((__be32 *)buf));
                } else {
                        /*
                         * Hack alert: instead of using keycodes, we have
@@ -1509,11 +1607,12 @@ static void imon_incoming_packet(struct imon_context *ictx,
 
        /* Figure out what key was pressed */
        if (len == 8 && buf[7] == 0xee) {
-               scancode = be64_to_cpu(*((u64 *)buf));
+               scancode = be64_to_cpu(*((__be64 *)buf));
                ktype = IMON_KEY_PANEL;
-               kc = imon_panel_key_lookup(scancode);
+               kc = imon_panel_key_lookup(ictx, scancode);
+               ictx->release_code = false;
        } else {
-               scancode = be32_to_cpu(*((u32 *)buf));
+               scancode = be32_to_cpu(*((__be32 *)buf));
                if (ictx->rc_type == RC_BIT_RC6_MCE) {
                        ktype = IMON_KEY_IMON;
                        if (buf[0] == 0x80)
@@ -1908,6 +2007,7 @@ out:
 
 static struct input_dev *imon_init_idev(struct imon_context *ictx)
 {
+       struct imon_panel_key_table *key_table = ictx->dev_descr->key_table;
        struct input_dev *idev;
        int ret, i;
 
@@ -1933,8 +2033,8 @@ static struct input_dev *imon_init_idev(struct imon_context *ictx)
                BIT_MASK(REL_WHEEL);
 
        /* panel and/or knob code support */
-       for (i = 0; i < ARRAY_SIZE(imon_panel_key_table); i++) {
-               u32 kc = imon_panel_key_table[i].keycode;
+       for (i = 0; key_table[i].hw_code != 0; i++) {
+               u32 kc = key_table[i].keycode;
                __set_bit(kc, idev->keybit);
        }
 
@@ -2023,7 +2123,7 @@ static bool imon_find_endpoints(struct imon_context *ictx,
        for (i = 0; i < num_endpts && !(ir_ep_found && display_ep_found); ++i) {
                ep = &iface_desc->endpoint[i].desc;
                ep_dir = ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK;
-               ep_type = ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK;
+               ep_type = usb_endpoint_type(ep);
 
                if (!ir_ep_found && ep_dir == USB_DIR_IN &&
                    ep_type == USB_ENDPOINT_XFER_INT) {
@@ -2135,9 +2235,11 @@ static struct imon_context *imon_init_intf0(struct usb_interface *intf,
        ictx->vendor  = le16_to_cpu(ictx->usbdev_intf0->descriptor.idVendor);
        ictx->product = le16_to_cpu(ictx->usbdev_intf0->descriptor.idProduct);
 
+       /* save drive info for later accessing the panel/knob key table */
+       ictx->dev_descr = (struct imon_usb_dev_descr *)id->driver_info;
        /* default send_packet delay is 5ms but some devices need more */
-       ictx->send_packet_delay = id->driver_info & IMON_NEED_20MS_PKT_DELAY ?
-                                 20 : 5;
+       ictx->send_packet_delay = ictx->dev_descr->flags &
+                                 IMON_NEED_20MS_PKT_DELAY ? 20 : 5;
 
        ret = -ENODEV;
        iface_desc = intf->cur_altsetting;
@@ -2181,6 +2283,7 @@ idev_setup_failed:
        usb_kill_urb(ictx->rx_urb_intf0);
 urb_submit_failed:
 find_endpoint_failed:
+       usb_put_dev(ictx->usbdev_intf0);
        mutex_unlock(&ictx->lock);
        usb_free_urb(tx_urb);
 tx_urb_alloc_failed:
@@ -2253,6 +2356,7 @@ urb_submit_failed:
                input_unregister_device(ictx->touch);
 touch_setup_failed:
 find_endpoint_failed:
+       usb_put_dev(ictx->usbdev_intf1);
        mutex_unlock(&ictx->lock);
        usb_free_urb(rx_urb);
 rx_urb_alloc_failed:
@@ -2366,11 +2470,13 @@ static int imon_probe(struct usb_interface *interface,
                 usbdev->bus->busnum, usbdev->devnum);
 
        mutex_unlock(&driver_lock);
+       usb_put_dev(usbdev);
 
        return 0;
 
 fail:
        mutex_unlock(&driver_lock);
+       usb_put_dev(usbdev);
        dev_err(dev, "unable to register, err %d\n", ret);
 
        return ret;
@@ -2410,6 +2516,7 @@ static void imon_disconnect(struct usb_interface *interface)
        if (ifnum == 0) {
                ictx->dev_present_intf0 = false;
                usb_kill_urb(ictx->rx_urb_intf0);
+               usb_put_dev(ictx->usbdev_intf0);
                input_unregister_device(ictx->idev);
                rc_unregister_device(ictx->rdev);
                if (ictx->display_supported) {
@@ -2421,6 +2528,7 @@ static void imon_disconnect(struct usb_interface *interface)
        } else {
                ictx->dev_present_intf1 = false;
                usb_kill_urb(ictx->rx_urb_intf1);
+               usb_put_dev(ictx->usbdev_intf1);
                if (ictx->display_type == IMON_DISPLAY_TYPE_VGA) {
                        input_unregister_device(ictx->touch);
                        del_timer_sync(&ictx->ttimer);
diff --git a/drivers/media/rc/ir-hix5hd2.c b/drivers/media/rc/ir-hix5hd2.c
new file mode 100644 (file)
index 0000000..08bbd4f
--- /dev/null
@@ -0,0 +1,351 @@
+/*
+ * Copyright (c) 2014 Linaro Ltd.
+ * Copyright (c) 2014 Hisilicon Limited.
+ *
+ * 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.
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/mfd/syscon.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/regmap.h>
+#include <media/rc-core.h>
+
+/* Allow the driver to compile on all architectures */
+#ifndef writel_relaxed
+# define writel_relaxed writel
+#endif
+#ifndef readl_relaxed
+# define readl_relaxed readl
+#endif
+
+#define IR_ENABLE              0x00
+#define IR_CONFIG              0x04
+#define CNT_LEADS              0x08
+#define CNT_LEADE              0x0c
+#define CNT_SLEADE             0x10
+#define CNT0_B                 0x14
+#define CNT1_B                 0x18
+#define IR_BUSY                        0x1c
+#define IR_DATAH               0x20
+#define IR_DATAL               0x24
+#define IR_INTM                        0x28
+#define IR_INTS                        0x2c
+#define IR_INTC                        0x30
+#define IR_START               0x34
+
+/* interrupt mask */
+#define INTMS_SYMBRCV          (BIT(24) | BIT(8))
+#define INTMS_TIMEOUT          (BIT(25) | BIT(9))
+#define INTMS_OVERFLOW         (BIT(26) | BIT(10))
+#define INT_CLR_OVERFLOW       BIT(18)
+#define INT_CLR_TIMEOUT                BIT(17)
+#define INT_CLR_RCV            BIT(16)
+#define INT_CLR_RCVTIMEOUT     (BIT(16) | BIT(17))
+
+#define IR_CLK                 0x48
+#define IR_CLK_ENABLE          BIT(4)
+#define IR_CLK_RESET           BIT(5)
+
+#define IR_CFG_WIDTH_MASK      0xffff
+#define IR_CFG_WIDTH_SHIFT     16
+#define IR_CFG_FORMAT_MASK     0x3
+#define IR_CFG_FORMAT_SHIFT    14
+#define IR_CFG_INT_LEVEL_MASK  0x3f
+#define IR_CFG_INT_LEVEL_SHIFT 8
+/* only support raw mode */
+#define IR_CFG_MODE_RAW                BIT(7)
+#define IR_CFG_FREQ_MASK       0x7f
+#define IR_CFG_FREQ_SHIFT      0
+#define IR_CFG_INT_THRESHOLD   1
+/* symbol start from low to high, symbol stream end at high*/
+#define IR_CFG_SYMBOL_FMT      0
+#define IR_CFG_SYMBOL_MAXWIDTH 0x3e80
+
+#define IR_HIX5HD2_NAME                "hix5hd2-ir"
+
+struct hix5hd2_ir_priv {
+       int                     irq;
+       void volatile __iomem   *base;
+       struct device           *dev;
+       struct rc_dev           *rdev;
+       struct regmap           *regmap;
+       struct clk              *clock;
+       unsigned long           rate;
+};
+
+static void hix5hd2_ir_enable(struct hix5hd2_ir_priv *dev, bool on)
+{
+       u32 val;
+
+       regmap_read(dev->regmap, IR_CLK, &val);
+       if (on) {
+               val &= ~IR_CLK_RESET;
+               val |= IR_CLK_ENABLE;
+       } else {
+               val &= ~IR_CLK_ENABLE;
+               val |= IR_CLK_RESET;
+       }
+       regmap_write(dev->regmap, IR_CLK, val);
+}
+
+static int hix5hd2_ir_config(struct hix5hd2_ir_priv *priv)
+{
+       int timeout = 10000;
+       u32 val, rate;
+
+       writel_relaxed(0x01, priv->base + IR_ENABLE);
+       while (readl_relaxed(priv->base + IR_BUSY)) {
+               if (timeout--) {
+                       udelay(1);
+               } else {
+                       dev_err(priv->dev, "IR_BUSY timeout\n");
+                       return -ETIMEDOUT;
+               }
+       }
+
+       /* Now only support raw mode, with symbol start from low to high */
+       rate = DIV_ROUND_CLOSEST(priv->rate, 1000000);
+       val = IR_CFG_SYMBOL_MAXWIDTH & IR_CFG_WIDTH_MASK << IR_CFG_WIDTH_SHIFT;
+       val |= IR_CFG_SYMBOL_FMT & IR_CFG_FORMAT_MASK << IR_CFG_FORMAT_SHIFT;
+       val |= (IR_CFG_INT_THRESHOLD - 1) & IR_CFG_INT_LEVEL_MASK
+              << IR_CFG_INT_LEVEL_SHIFT;
+       val |= IR_CFG_MODE_RAW;
+       val |= (rate - 1) & IR_CFG_FREQ_MASK << IR_CFG_FREQ_SHIFT;
+       writel_relaxed(val, priv->base + IR_CONFIG);
+
+       writel_relaxed(0x00, priv->base + IR_INTM);
+       /* write arbitrary value to start  */
+       writel_relaxed(0x01, priv->base + IR_START);
+       return 0;
+}
+
+static int hix5hd2_ir_open(struct rc_dev *rdev)
+{
+       struct hix5hd2_ir_priv *priv = rdev->priv;
+
+       hix5hd2_ir_enable(priv, true);
+       return hix5hd2_ir_config(priv);
+}
+
+static void hix5hd2_ir_close(struct rc_dev *rdev)
+{
+       struct hix5hd2_ir_priv *priv = rdev->priv;
+
+       hix5hd2_ir_enable(priv, false);
+}
+
+static irqreturn_t hix5hd2_ir_rx_interrupt(int irq, void *data)
+{
+       u32 symb_num, symb_val, symb_time;
+       u32 data_l, data_h;
+       u32 irq_sr, i;
+       struct hix5hd2_ir_priv *priv = data;
+
+       irq_sr = readl_relaxed(priv->base + IR_INTS);
+       if (irq_sr & INTMS_OVERFLOW) {
+               /*
+                * we must read IR_DATAL first, then we can clean up
+                * IR_INTS availably since logic would not clear
+                * fifo when overflow, drv do the job
+                */
+               ir_raw_event_reset(priv->rdev);
+               symb_num = readl_relaxed(priv->base + IR_DATAH);
+               for (i = 0; i < symb_num; i++)
+                       readl_relaxed(priv->base + IR_DATAL);
+
+               writel_relaxed(INT_CLR_OVERFLOW, priv->base + IR_INTC);
+               dev_info(priv->dev, "overflow, level=%d\n",
+                        IR_CFG_INT_THRESHOLD);
+       }
+
+       if ((irq_sr & INTMS_SYMBRCV) || (irq_sr & INTMS_TIMEOUT)) {
+               DEFINE_IR_RAW_EVENT(ev);
+
+               symb_num = readl_relaxed(priv->base + IR_DATAH);
+               for (i = 0; i < symb_num; i++) {
+                       symb_val = readl_relaxed(priv->base + IR_DATAL);
+                       data_l = ((symb_val & 0xffff) * 10);
+                       data_h =  ((symb_val >> 16) & 0xffff) * 10;
+                       symb_time = (data_l + data_h) / 10;
+
+                       ev.duration = US_TO_NS(data_l);
+                       ev.pulse = true;
+                       ir_raw_event_store(priv->rdev, &ev);
+
+                       if (symb_time < IR_CFG_SYMBOL_MAXWIDTH) {
+                               ev.duration = US_TO_NS(data_h);
+                               ev.pulse = false;
+                               ir_raw_event_store(priv->rdev, &ev);
+                       } else {
+                               ir_raw_event_set_idle(priv->rdev, true);
+                       }
+               }
+
+               if (irq_sr & INTMS_SYMBRCV)
+                       writel_relaxed(INT_CLR_RCV, priv->base + IR_INTC);
+               if (irq_sr & INTMS_TIMEOUT)
+                       writel_relaxed(INT_CLR_TIMEOUT, priv->base + IR_INTC);
+       }
+
+       /* Empty software fifo */
+       ir_raw_event_handle(priv->rdev);
+       return IRQ_HANDLED;
+}
+
+static int hix5hd2_ir_probe(struct platform_device *pdev)
+{
+       struct rc_dev *rdev;
+       struct device *dev = &pdev->dev;
+       struct resource *res;
+       struct hix5hd2_ir_priv *priv;
+       struct device_node *node = pdev->dev.of_node;
+       const char *map_name;
+       int ret;
+
+       priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+       if (!priv)
+               return -ENOMEM;
+
+       priv->regmap = syscon_regmap_lookup_by_phandle(node,
+                                                      "hisilicon,power-syscon");
+       if (IS_ERR(priv->regmap)) {
+               dev_err(dev, "no power-reg\n");
+               return -EINVAL;
+       }
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       priv->base = devm_ioremap_resource(dev, res);
+       if (IS_ERR((__force void *)priv->base))
+               return PTR_ERR((__force void *)priv->base);
+
+       priv->irq = platform_get_irq(pdev, 0);
+       if (priv->irq < 0) {
+               dev_err(dev, "irq can not get\n");
+               return priv->irq;
+       }
+
+       rdev = rc_allocate_device();
+       if (!rdev)
+               return -ENOMEM;
+
+       priv->clock = devm_clk_get(dev, NULL);
+       if (IS_ERR(priv->clock)) {
+               dev_err(dev, "clock not found\n");
+               ret = PTR_ERR(priv->clock);
+               goto err;
+       }
+       clk_prepare_enable(priv->clock);
+       priv->rate = clk_get_rate(priv->clock);
+
+       rdev->driver_type = RC_DRIVER_IR_RAW;
+       rdev->allowed_protocols = RC_BIT_ALL;
+       rdev->priv = priv;
+       rdev->open = hix5hd2_ir_open;
+       rdev->close = hix5hd2_ir_close;
+       rdev->driver_name = IR_HIX5HD2_NAME;
+       map_name = of_get_property(node, "linux,rc-map-name", NULL);
+       rdev->map_name = map_name ?: RC_MAP_EMPTY;
+       rdev->input_name = IR_HIX5HD2_NAME;
+       rdev->input_phys = IR_HIX5HD2_NAME "/input0";
+       rdev->input_id.bustype = BUS_HOST;
+       rdev->input_id.vendor = 0x0001;
+       rdev->input_id.product = 0x0001;
+       rdev->input_id.version = 0x0100;
+       rdev->rx_resolution = US_TO_NS(10);
+       rdev->timeout = US_TO_NS(IR_CFG_SYMBOL_MAXWIDTH * 10);
+
+       ret = rc_register_device(rdev);
+       if (ret < 0)
+               goto clkerr;
+
+       if (devm_request_irq(dev, priv->irq, hix5hd2_ir_rx_interrupt,
+                            IRQF_NO_SUSPEND, pdev->name, priv) < 0) {
+               dev_err(dev, "IRQ %d register failed\n", priv->irq);
+               ret = -EINVAL;
+               goto regerr;
+       }
+
+       priv->rdev = rdev;
+       priv->dev = dev;
+       platform_set_drvdata(pdev, priv);
+
+       return ret;
+
+regerr:
+       rc_unregister_device(rdev);
+       rdev = NULL;
+clkerr:
+       clk_disable_unprepare(priv->clock);
+err:
+       rc_free_device(rdev);
+       dev_err(dev, "Unable to register device (%d)\n", ret);
+       return ret;
+}
+
+static int hix5hd2_ir_remove(struct platform_device *pdev)
+{
+       struct hix5hd2_ir_priv *priv = platform_get_drvdata(pdev);
+
+       clk_disable_unprepare(priv->clock);
+       rc_unregister_device(priv->rdev);
+       return 0;
+}
+
+#ifdef CONFIG_PM
+static int hix5hd2_ir_suspend(struct device *dev)
+{
+       struct hix5hd2_ir_priv *priv = dev_get_drvdata(dev);
+
+       clk_disable_unprepare(priv->clock);
+       hix5hd2_ir_enable(priv, false);
+
+       return 0;
+}
+
+static int hix5hd2_ir_resume(struct device *dev)
+{
+       struct hix5hd2_ir_priv *priv = dev_get_drvdata(dev);
+
+       hix5hd2_ir_enable(priv, true);
+       clk_prepare_enable(priv->clock);
+
+       writel_relaxed(0x01, priv->base + IR_ENABLE);
+       writel_relaxed(0x00, priv->base + IR_INTM);
+       writel_relaxed(0xff, priv->base + IR_INTC);
+       writel_relaxed(0x01, priv->base + IR_START);
+
+       return 0;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(hix5hd2_ir_pm_ops, hix5hd2_ir_suspend,
+                        hix5hd2_ir_resume);
+
+static struct of_device_id hix5hd2_ir_table[] = {
+       { .compatible = "hisilicon,hix5hd2-ir", },
+       {},
+};
+MODULE_DEVICE_TABLE(of, hix5hd2_ir_table);
+
+static struct platform_driver hix5hd2_ir_driver = {
+       .driver = {
+               .name = IR_HIX5HD2_NAME,
+               .of_match_table = hix5hd2_ir_table,
+               .pm     = &hix5hd2_ir_pm_ops,
+       },
+       .probe = hix5hd2_ir_probe,
+       .remove = hix5hd2_ir_remove,
+};
+
+module_platform_driver(hix5hd2_ir_driver);
+
+MODULE_DESCRIPTION("IR controller driver for hix5hd2 platforms");
+MODULE_AUTHOR("Guoxiong Yan <yanguoxiong@huawei.com>");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:hix5hd2-ir");
index 447fe35862dc2d5ad00cce91eb7fd61edaf9e4b5..56abf9120cc27491d20857958fa10b1111ce573e 100644 (file)
@@ -1666,7 +1666,6 @@ static int ite_suspend(struct pnp_dev *pdev, pm_message_t state)
 
 static int ite_resume(struct pnp_dev *pdev)
 {
-       int ret = 0;
        struct ite_dev *dev = pnp_get_drvdata(pdev);
        unsigned long flags;
 
@@ -1681,7 +1680,7 @@ static int ite_resume(struct pnp_dev *pdev)
 
        spin_unlock_irqrestore(&dev->lock, flags);
 
-       return ret;
+       return 0;
 }
 
 static void ite_shutdown(struct pnp_dev *pdev)
index 0b8c54919010cec79ac916700374f6eca5849f37..abf60794223d3607fce92d6d94aa1e064e23735c 100644 (file)
@@ -28,6 +28,7 @@ obj-$(CONFIG_RC_MAP) += rc-adstech-dvb-t-pci.o \
                        rc-dm1105-nec.o \
                        rc-dntv-live-dvb-t.o \
                        rc-dntv-live-dvbt-pro.o \
+                       rc-dvbsky.o \
                        rc-em-terratec.o \
                        rc-encore-enltv2.o \
                        rc-encore-enltv.o \
diff --git a/drivers/media/rc/keymaps/rc-dvbsky.c b/drivers/media/rc/keymaps/rc-dvbsky.c
new file mode 100644 (file)
index 0000000..c5115a1
--- /dev/null
@@ -0,0 +1,78 @@
+/* rc-dvbsky.c - Keytable for DVBSky Remote Controllers
+ *
+ * keymap imported from ir-keymaps.c
+ *
+ *
+ * Copyright (c) 2010-2012 by Nibble Max <nibble.max@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <media/rc-map.h>
+#include <linux/module.h>
+/*
+ * This table contains the complete RC5 code, instead of just the data part
+ */
+
+static struct rc_map_table rc5_dvbsky[] = {
+       { 0x0000, KEY_0 },
+       { 0x0001, KEY_1 },
+       { 0x0002, KEY_2 },
+       { 0x0003, KEY_3 },
+       { 0x0004, KEY_4 },
+       { 0x0005, KEY_5 },
+       { 0x0006, KEY_6 },
+       { 0x0007, KEY_7 },
+       { 0x0008, KEY_8 },
+       { 0x0009, KEY_9 },
+       { 0x000a, KEY_MUTE },
+       { 0x000d, KEY_OK },
+       { 0x000b, KEY_STOP },
+       { 0x000c, KEY_EXIT },
+       { 0x000e, KEY_CAMERA }, /*Snap shot*/
+       { 0x000f, KEY_SUBTITLE }, /*PIP*/
+       { 0x0010, KEY_VOLUMEUP },
+       { 0x0011, KEY_VOLUMEDOWN },
+       { 0x0012, KEY_FAVORITES },
+       { 0x0013, KEY_LIST }, /*Info*/
+       { 0x0016, KEY_PAUSE },
+       { 0x0017, KEY_PLAY },
+       { 0x001f, KEY_RECORD },
+       { 0x0020, KEY_CHANNELDOWN },
+       { 0x0021, KEY_CHANNELUP },
+       { 0x0025, KEY_POWER2 },
+       { 0x0026, KEY_REWIND },
+       { 0x0027, KEY_FASTFORWARD },
+       { 0x0029, KEY_LAST },
+       { 0x002b, KEY_MENU },
+       { 0x002c, KEY_EPG },
+       { 0x002d, KEY_ZOOM },
+};
+
+static struct rc_map_list rc5_dvbsky_map = {
+       .map = {
+               .scan    = rc5_dvbsky,
+               .size    = ARRAY_SIZE(rc5_dvbsky),
+               .rc_type = RC_TYPE_RC5,
+               .name    = RC_MAP_DVBSKY,
+       }
+};
+
+static int __init init_rc_map_rc5_dvbsky(void)
+{
+       return rc_map_register(&rc5_dvbsky_map);
+}
+
+static void __exit exit_rc_map_rc5_dvbsky(void)
+{
+       rc_map_unregister(&rc5_dvbsky_map);
+}
+
+module_init(init_rc_map_rc5_dvbsky)
+module_exit(exit_rc_map_rc5_dvbsky)
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Nibble Max <nibble.max@gmail.com>");
index dc5cbffcd5a26a4702b578e97c995e527b644236..249d2fbc8f3748b69fa95ff39e783a458cb18a8f 100644 (file)
@@ -595,7 +595,7 @@ long lirc_dev_fop_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 
        switch (cmd) {
        case LIRC_GET_FEATURES:
-               result = put_user(ir->d.features, (__u32 *)arg);
+               result = put_user(ir->d.features, (__u32 __user *)arg);
                break;
        case LIRC_GET_REC_MODE:
                if (!(ir->d.features & LIRC_CAN_REC_MASK)) {
@@ -605,7 +605,7 @@ long lirc_dev_fop_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 
                result = put_user(LIRC_REC2MODE
                                  (ir->d.features & LIRC_CAN_REC_MASK),
-                                 (__u32 *)arg);
+                                 (__u32 __user *)arg);
                break;
        case LIRC_SET_REC_MODE:
                if (!(ir->d.features & LIRC_CAN_REC_MASK)) {
@@ -613,7 +613,7 @@ long lirc_dev_fop_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
                        break;
                }
 
-               result = get_user(mode, (__u32 *)arg);
+               result = get_user(mode, (__u32 __user *)arg);
                if (!result && !(LIRC_MODE2REC(mode) & ir->d.features))
                        result = -EINVAL;
                /*
@@ -622,7 +622,7 @@ long lirc_dev_fop_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
                 */
                break;
        case LIRC_GET_LENGTH:
-               result = put_user(ir->d.code_length, (__u32 *)arg);
+               result = put_user(ir->d.code_length, (__u32 __user *)arg);
                break;
        case LIRC_GET_MIN_TIMEOUT:
                if (!(ir->d.features & LIRC_CAN_SET_REC_TIMEOUT) ||
@@ -631,7 +631,7 @@ long lirc_dev_fop_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
                        break;
                }
 
-               result = put_user(ir->d.min_timeout, (__u32 *)arg);
+               result = put_user(ir->d.min_timeout, (__u32 __user *)arg);
                break;
        case LIRC_GET_MAX_TIMEOUT:
                if (!(ir->d.features & LIRC_CAN_SET_REC_TIMEOUT) ||
@@ -640,7 +640,7 @@ long lirc_dev_fop_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
                        break;
                }
 
-               result = put_user(ir->d.max_timeout, (__u32 *)arg);
+               result = put_user(ir->d.max_timeout, (__u32 __user *)arg);
                break;
        default:
                result = -EINVAL;
@@ -736,7 +736,7 @@ ssize_t lirc_dev_fop_read(struct file *file,
                        }
                } else {
                        lirc_buffer_read(ir->buf, buf);
-                       ret = copy_to_user((void *)buffer+written, buf,
+                       ret = copy_to_user((void __user *)buffer+written, buf,
                                           ir->buf->chunk_size);
                        if (!ret)
                                written += ir->buf->chunk_size;
index 45b0894288e511209a9c63ba314614fc0c382bba..2cdb740cde481e2e8884b7ddb05c90f6f399a954 100644 (file)
@@ -397,6 +397,10 @@ static struct usb_device_id mceusb_dev_table[] = {
          .driver_info = HAUPPAUGE_CX_HYBRID_TV },
        { USB_DEVICE(VENDOR_HAUPPAUGE, 0xb131),
          .driver_info = HAUPPAUGE_CX_HYBRID_TV },
+       { USB_DEVICE(VENDOR_HAUPPAUGE, 0xb138),
+         .driver_info = HAUPPAUGE_CX_HYBRID_TV },
+       { USB_DEVICE(VENDOR_HAUPPAUGE, 0xb139),
+         .driver_info = HAUPPAUGE_CX_HYBRID_TV },
        { USB_DEVICE(VENDOR_PCTV, 0x0259),
          .driver_info = HAUPPAUGE_CX_HYBRID_TV },
        { USB_DEVICE(VENDOR_PCTV, 0x025e),
@@ -1198,10 +1202,9 @@ static void mceusb_flash_led(struct mceusb_dev *ir)
        mce_async_out(ir, FLASH_LED, sizeof(FLASH_LED));
 }
 
-static struct rc_dev *mceusb_init_rc_dev(struct mceusb_dev *ir,
-                                        struct usb_interface *intf)
+static struct rc_dev *mceusb_init_rc_dev(struct mceusb_dev *ir)
 {
-       struct usb_device *udev = usb_get_dev(interface_to_usbdev(intf));
+       struct usb_device *udev = ir->usbdev;
        struct device *dev = ir->dev;
        struct rc_dev *rc;
        int ret;
@@ -1341,7 +1344,7 @@ static int mceusb_dev_probe(struct usb_interface *intf,
        if (!ir->urb_in)
                goto urb_in_alloc_fail;
 
-       ir->usbdev = dev;
+       ir->usbdev = usb_get_dev(dev);
        ir->dev = &intf->dev;
        ir->len_in = maxp;
        ir->flags.microsoft_gen1 = is_microsoft_gen1;
@@ -1362,7 +1365,7 @@ static int mceusb_dev_probe(struct usb_interface *intf,
                snprintf(name + strlen(name), sizeof(name) - strlen(name),
                         " %s", buf);
 
-       ir->rc = mceusb_init_rc_dev(ir, intf);
+       ir->rc = mceusb_init_rc_dev(ir);
        if (!ir->rc)
                goto rc_dev_fail;
 
@@ -1408,6 +1411,7 @@ static int mceusb_dev_probe(struct usb_interface *intf,
 
        /* Error-handling path */
 rc_dev_fail:
+       usb_put_dev(ir->usbdev);
        usb_free_urb(ir->urb_in);
 urb_in_alloc_fail:
        usb_free_coherent(dev, maxp, ir->buf_in, ir->dma_in);
@@ -1435,6 +1439,7 @@ static void mceusb_dev_disconnect(struct usb_interface *intf)
        usb_kill_urb(ir->urb_in);
        usb_free_urb(ir->urb_in);
        usb_free_coherent(dev, ir->len_in, ir->buf_in, ir->dma_in);
+       usb_put_dev(dev);
 
        kfree(ir);
 }
index 7f4fd859bba5795e209a2c778de94be479e3b1c8..9c2c8635ff3326841178f8f04d65466886424e8b 100644 (file)
@@ -229,7 +229,6 @@ static int nvt_hw_detect(struct nvt_dev *nvt)
 {
        unsigned long flags;
        u8 chip_major, chip_minor;
-       int ret = 0;
        char chip_id[12];
        bool chip_unknown = false;
 
@@ -285,7 +284,7 @@ static int nvt_hw_detect(struct nvt_dev *nvt)
        nvt->chip_minor = chip_minor;
        spin_unlock_irqrestore(&nvt->nvt_lock, flags);
 
-       return ret;
+       return 0;
 }
 
 static void nvt_cir_ldev_init(struct nvt_dev *nvt)
@@ -1177,7 +1176,6 @@ static int nvt_suspend(struct pnp_dev *pdev, pm_message_t state)
 
 static int nvt_resume(struct pnp_dev *pdev)
 {
-       int ret = 0;
        struct nvt_dev *nvt = pnp_get_drvdata(pdev);
 
        nvt_dbg("%s called", __func__);
@@ -1195,7 +1193,7 @@ static int nvt_resume(struct pnp_dev *pdev)
        nvt_cir_regs_init(nvt);
        nvt_cir_wake_regs_init(nvt);
 
-       return ret;
+       return 0;
 }
 
 static void nvt_shutdown(struct pnp_dev *pdev)
index 5c151351afa4c72f48ccf9e48b88abe48cfc8331..0e758ae2e52978b0b76a026d43799a9b75c42fe0 100644 (file)
@@ -22,8 +22,8 @@ struct st_rc_device {
        int                             irq;
        int                             irq_wake;
        struct clk                      *sys_clock;
-       void                            *base;  /* Register base address */
-       void                            *rx_base;/* RX Register base address */
+       volatile void __iomem           *base;  /* Register base address */
+       volatile void __iomem           *rx_base;/* RX Register base address */
        struct rc_dev                   *rdev;
        bool                            overclocking;
        int                             sample_mult;
@@ -267,8 +267,8 @@ static int st_rc_probe(struct platform_device *pdev)
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 
        rc_dev->base = devm_ioremap_resource(dev, res);
-       if (IS_ERR(rc_dev->base)) {
-               ret = PTR_ERR(rc_dev->base);
+       if (IS_ERR((__force void *)rc_dev->base)) {
+               ret = PTR_ERR((__force void *)rc_dev->base);
                goto err;
        }
 
@@ -278,7 +278,7 @@ static int st_rc_probe(struct platform_device *pdev)
                rc_dev->rx_base = rc_dev->base;
 
 
-       rc_dev->rstc = reset_control_get(dev, NULL);
+       rc_dev->rstc = reset_control_get_optional(dev, NULL);
        if (IS_ERR(rc_dev->rstc))
                rc_dev->rstc = NULL;
 
@@ -376,9 +376,10 @@ static int st_rc_resume(struct device *dev)
        return 0;
 }
 
-static SIMPLE_DEV_PM_OPS(st_rc_pm_ops, st_rc_suspend, st_rc_resume);
 #endif
 
+static SIMPLE_DEV_PM_OPS(st_rc_pm_ops, st_rc_suspend, st_rc_resume);
+
 #ifdef CONFIG_OF
 static struct of_device_id st_rc_match[] = {
        { .compatible = "st,comms-irb", },
@@ -391,11 +392,8 @@ MODULE_DEVICE_TABLE(of, st_rc_match);
 static struct platform_driver st_rc_driver = {
        .driver = {
                .name = IR_ST_NAME,
-               .owner  = THIS_MODULE,
                .of_match_table = of_match_ptr(st_rc_match),
-#ifdef CONFIG_PM
                .pm     = &st_rc_pm_ops,
-#endif
        },
        .probe = st_rc_probe,
        .remove = st_rc_remove,
index 80c4feeb01ea7a47ea52e5b6ccc106b878d045d5..bf4a44272f0e3e00a01c0bc3fb44720e1732ec27 100644 (file)
@@ -362,16 +362,14 @@ static int streamzap_probe(struct usb_interface *intf,
        }
 
        sz->endpoint = &(iface_host->endpoint[0].desc);
-       if ((sz->endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK)
-           != USB_DIR_IN) {
+       if (!usb_endpoint_dir_in(sz->endpoint)) {
                dev_err(&intf->dev, "%s: endpoint doesn't match input device "
                        "02%02x\n", __func__, sz->endpoint->bEndpointAddress);
                retval = -ENODEV;
                goto free_sz;
        }
 
-       if ((sz->endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
-           != USB_ENDPOINT_XFER_INT) {
+       if (!usb_endpoint_xfer_int(sz->endpoint)) {
                dev_err(&intf->dev, "%s: endpoint attributes don't match xfer "
                        "02%02x\n", __func__, sz->endpoint->bmAttributes);
                retval = -ENODEV;
index d79fd1ce5a18b0953d405871cf0c9569adde562a..f039dc2a21cf0fb3538d57fc42905f676b2cbe17 100644 (file)
@@ -204,6 +204,7 @@ config MEDIA_TUNER_FC0013
 config MEDIA_TUNER_TDA18212
        tristate "NXP TDA18212 silicon tuner"
        depends on MEDIA_SUPPORT && I2C
+       select REGMAP_I2C
        default m if !MEDIA_SUBDRV_AUTOSELECT
        help
          NXP TDA18212 silicon tuner driver.
@@ -226,6 +227,7 @@ config MEDIA_TUNER_FC2580
 config MEDIA_TUNER_M88TS2022
        tristate "Montage M88TS2022 silicon tuner"
        depends on MEDIA_SUPPORT && I2C
+       select REGMAP_I2C
        default m if !MEDIA_SUBDRV_AUTOSELECT
        help
          Montage M88TS2022 silicon tuner driver.
@@ -247,6 +249,7 @@ config MEDIA_TUNER_SI2157
 config MEDIA_TUNER_IT913X
        tristate "ITE Tech IT913x silicon tuner"
        depends on MEDIA_SUPPORT && I2C
+       select REGMAP_I2C
        default m if !MEDIA_SUBDRV_AUTOSELECT
        help
          ITE Tech IT913x silicon tuner driver.
@@ -257,4 +260,18 @@ config MEDIA_TUNER_R820T
        default m if !MEDIA_SUBDRV_AUTOSELECT
        help
          Rafael Micro R820T silicon tuner driver.
+
+config MEDIA_TUNER_MXL301RF
+       tristate "MaxLinear MxL301RF tuner"
+       depends on MEDIA_SUPPORT && I2C
+       default m if !MEDIA_SUBDRV_AUTOSELECT
+       help
+         MaxLinear MxL301RF OFDM tuner driver.
+
+config MEDIA_TUNER_QM1D1C0042
+       tristate "Sharp QM1D1C0042 tuner"
+       depends on MEDIA_SUPPORT && I2C
+       default m if !MEDIA_SUBDRV_AUTOSELECT
+       help
+         Sharp QM1D1C0042 trellis coded 8PSK tuner driver.
 endmenu
index 5591699755baced61dc7247e476d605a18a1220e..49fcf8033848dcf2e1029349d624268b907c2fc2 100644 (file)
@@ -37,8 +37,10 @@ obj-$(CONFIG_MEDIA_TUNER_M88TS2022) += m88ts2022.o
 obj-$(CONFIG_MEDIA_TUNER_FC0011) += fc0011.o
 obj-$(CONFIG_MEDIA_TUNER_FC0012) += fc0012.o
 obj-$(CONFIG_MEDIA_TUNER_FC0013) += fc0013.o
-obj-$(CONFIG_MEDIA_TUNER_IT913X) += tuner_it913x.o
+obj-$(CONFIG_MEDIA_TUNER_IT913X) += it913x.o
 obj-$(CONFIG_MEDIA_TUNER_R820T) += r820t.o
+obj-$(CONFIG_MEDIA_TUNER_MXL301RF) += mxl301rf.o
+obj-$(CONFIG_MEDIA_TUNER_QM1D1C0042) += qm1d1c0042.o
 
 ccflags-y += -I$(srctree)/drivers/media/dvb-core
 ccflags-y += -I$(srctree)/drivers/media/dvb-frontends
index 90d93348f20c5f111aea684ba15b798bc683c6b1..510239f80c0d9f5bb173a8f71d2c784de8b60201 100644 (file)
@@ -26,7 +26,7 @@ static int e4000_init(struct dvb_frontend *fe)
        struct e4000 *s = fe->tuner_priv;
        int ret;
 
-       dev_dbg(&s->client->dev, "%s:\n", __func__);
+       dev_dbg(&s->client->dev, "\n");
 
        /* dummy I2C to ensure I2C wakes up */
        ret = regmap_write(s->regmap, 0x02, 0x40);
@@ -87,7 +87,7 @@ static int e4000_init(struct dvb_frontend *fe)
        s->active = true;
 err:
        if (ret)
-               dev_dbg(&s->client->dev, "%s: failed=%d\n", __func__, ret);
+               dev_dbg(&s->client->dev, "failed=%d\n", ret);
 
        return ret;
 }
@@ -97,7 +97,7 @@ static int e4000_sleep(struct dvb_frontend *fe)
        struct e4000 *s = fe->tuner_priv;
        int ret;
 
-       dev_dbg(&s->client->dev, "%s:\n", __func__);
+       dev_dbg(&s->client->dev, "\n");
 
        s->active = false;
 
@@ -106,7 +106,7 @@ static int e4000_sleep(struct dvb_frontend *fe)
                goto err;
 err:
        if (ret)
-               dev_dbg(&s->client->dev, "%s: failed=%d\n", __func__, ret);
+               dev_dbg(&s->client->dev, "failed=%d\n", ret);
 
        return ret;
 }
@@ -121,9 +121,8 @@ static int e4000_set_params(struct dvb_frontend *fe)
        u8 buf[5], i_data[4], q_data[4];
 
        dev_dbg(&s->client->dev,
-                       "%s: delivery_system=%d frequency=%u bandwidth_hz=%u\n",
-                       __func__, c->delivery_system, c->frequency,
-                       c->bandwidth_hz);
+                       "delivery_system=%d frequency=%u bandwidth_hz=%u\n",
+                       c->delivery_system, c->frequency, c->bandwidth_hz);
 
        /* gain control manual */
        ret = regmap_write(s->regmap, 0x1a, 0x00);
@@ -150,9 +149,8 @@ static int e4000_set_params(struct dvb_frontend *fe)
        buf[3] = 0x00;
        buf[4] = e4000_pll_lut[i].div;
 
-       dev_dbg(&s->client->dev,
-                       "%s: f_vco=%llu pll div=%d sigma_delta=%04x\n",
-                       __func__, f_vco, buf[0], sigma_delta);
+       dev_dbg(&s->client->dev, "f_vco=%llu pll div=%d sigma_delta=%04x\n",
+                       f_vco, buf[0], sigma_delta);
 
        ret = regmap_bulk_write(s->regmap, 0x09, buf, 5);
        if (ret)
@@ -253,7 +251,7 @@ static int e4000_set_params(struct dvb_frontend *fe)
                goto err;
 err:
        if (ret)
-               dev_dbg(&s->client->dev, "%s: failed=%d\n", __func__, ret);
+               dev_dbg(&s->client->dev, "failed=%d\n", ret);
 
        return ret;
 }
@@ -262,7 +260,7 @@ static int e4000_get_if_frequency(struct dvb_frontend *fe, u32 *frequency)
 {
        struct e4000 *s = fe->tuner_priv;
 
-       dev_dbg(&s->client->dev, "%s:\n", __func__);
+       dev_dbg(&s->client->dev, "\n");
 
        *frequency = 0; /* Zero-IF */
 
@@ -276,10 +274,9 @@ static int e4000_set_lna_gain(struct dvb_frontend *fe)
        int ret;
        u8 u8tmp;
 
-       dev_dbg(&s->client->dev, "%s: lna auto=%d->%d val=%d->%d\n",
-                       __func__, s->lna_gain_auto->cur.val,
-                       s->lna_gain_auto->val, s->lna_gain->cur.val,
-                       s->lna_gain->val);
+       dev_dbg(&s->client->dev, "lna auto=%d->%d val=%d->%d\n",
+                       s->lna_gain_auto->cur.val, s->lna_gain_auto->val,
+                       s->lna_gain->cur.val, s->lna_gain->val);
 
        if (s->lna_gain_auto->val && s->if_gain_auto->cur.val)
                u8tmp = 0x17;
@@ -301,7 +298,7 @@ static int e4000_set_lna_gain(struct dvb_frontend *fe)
        }
 err:
        if (ret)
-               dev_dbg(&s->client->dev, "%s: failed=%d\n", __func__, ret);
+               dev_dbg(&s->client->dev, "failed=%d\n", ret);
 
        return ret;
 }
@@ -312,10 +309,9 @@ static int e4000_set_mixer_gain(struct dvb_frontend *fe)
        int ret;
        u8 u8tmp;
 
-       dev_dbg(&s->client->dev, "%s: mixer auto=%d->%d val=%d->%d\n",
-                       __func__, s->mixer_gain_auto->cur.val,
-                       s->mixer_gain_auto->val, s->mixer_gain->cur.val,
-                       s->mixer_gain->val);
+       dev_dbg(&s->client->dev, "mixer auto=%d->%d val=%d->%d\n",
+                       s->mixer_gain_auto->cur.val, s->mixer_gain_auto->val,
+                       s->mixer_gain->cur.val, s->mixer_gain->val);
 
        if (s->mixer_gain_auto->val)
                u8tmp = 0x15;
@@ -333,7 +329,7 @@ static int e4000_set_mixer_gain(struct dvb_frontend *fe)
        }
 err:
        if (ret)
-               dev_dbg(&s->client->dev, "%s: failed=%d\n", __func__, ret);
+               dev_dbg(&s->client->dev, "failed=%d\n", ret);
 
        return ret;
 }
@@ -345,10 +341,9 @@ static int e4000_set_if_gain(struct dvb_frontend *fe)
        u8 buf[2];
        u8 u8tmp;
 
-       dev_dbg(&s->client->dev, "%s: if auto=%d->%d val=%d->%d\n",
-                       __func__, s->if_gain_auto->cur.val,
-                       s->if_gain_auto->val, s->if_gain->cur.val,
-                       s->if_gain->val);
+       dev_dbg(&s->client->dev, "if auto=%d->%d val=%d->%d\n",
+                       s->if_gain_auto->cur.val, s->if_gain_auto->val,
+                       s->if_gain->cur.val, s->if_gain->val);
 
        if (s->if_gain_auto->val && s->lna_gain_auto->cur.val)
                u8tmp = 0x17;
@@ -372,7 +367,7 @@ static int e4000_set_if_gain(struct dvb_frontend *fe)
        }
 err:
        if (ret)
-               dev_dbg(&s->client->dev, "%s: failed=%d\n", __func__, ret);
+               dev_dbg(&s->client->dev, "failed=%d\n", ret);
 
        return ret;
 }
@@ -390,7 +385,7 @@ static int e4000_pll_lock(struct dvb_frontend *fe)
        s->pll_lock->val = (utmp & 0x01);
 err:
        if (ret)
-               dev_dbg(&s->client->dev, "%s: failed=%d\n", __func__, ret);
+               dev_dbg(&s->client->dev, "failed=%d\n", ret);
 
        return ret;
 }
@@ -400,7 +395,7 @@ static int e4000_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
        struct e4000 *s = container_of(ctrl->handler, struct e4000, hdl);
        int ret;
 
-       if (s->active == false)
+       if (!s->active)
                return 0;
 
        switch (ctrl->id) {
@@ -408,8 +403,8 @@ static int e4000_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
                ret = e4000_pll_lock(s->fe);
                break;
        default:
-               dev_dbg(&s->client->dev, "%s: unknown ctrl: id=%d name=%s\n",
-                               __func__, ctrl->id, ctrl->name);
+               dev_dbg(&s->client->dev, "unknown ctrl: id=%d name=%s\n",
+                               ctrl->id, ctrl->name);
                ret = -EINVAL;
        }
 
@@ -423,7 +418,7 @@ static int e4000_s_ctrl(struct v4l2_ctrl *ctrl)
        struct dtv_frontend_properties *c = &fe->dtv_property_cache;
        int ret;
 
-       if (s->active == false)
+       if (!s->active)
                return 0;
 
        switch (ctrl->id) {
@@ -445,8 +440,8 @@ static int e4000_s_ctrl(struct v4l2_ctrl *ctrl)
                ret = e4000_set_if_gain(s->fe);
                break;
        default:
-               dev_dbg(&s->client->dev, "%s: unknown ctrl: id=%d name=%s\n",
-                               __func__, ctrl->id, ctrl->name);
+               dev_dbg(&s->client->dev, "unknown ctrl: id=%d name=%s\n",
+                               ctrl->id, ctrl->name);
                ret = -EINVAL;
        }
 
@@ -494,7 +489,7 @@ static int e4000_probe(struct i2c_client *client,
        s = kzalloc(sizeof(struct e4000), GFP_KERNEL);
        if (!s) {
                ret = -ENOMEM;
-               dev_err(&client->dev, "%s: kzalloc() failed\n", KBUILD_MODNAME);
+               dev_err(&client->dev, "kzalloc() failed\n");
                goto err;
        }
 
@@ -512,7 +507,7 @@ static int e4000_probe(struct i2c_client *client,
        if (ret)
                goto err;
 
-       dev_dbg(&s->client->dev, "%s: chip id=%02x\n", __func__, utmp);
+       dev_dbg(&s->client->dev, "chip id=%02x\n", utmp);
 
        if (utmp != 0x40) {
                ret = -ENODEV;
@@ -559,9 +554,7 @@ static int e4000_probe(struct i2c_client *client,
        s->sd.ctrl_handler = &s->hdl;
 #endif
 
-       dev_info(&s->client->dev,
-                       "%s: Elonics E4000 successfully identified\n",
-                       KBUILD_MODNAME);
+       dev_info(&s->client->dev, "Elonics E4000 successfully identified\n");
 
        fe->tuner_priv = s;
        memcpy(&fe->ops.tuner_ops, &e4000_tuner_ops,
@@ -573,7 +566,7 @@ static int e4000_probe(struct i2c_client *client,
        return 0;
 err:
        if (ret) {
-               dev_dbg(&client->dev, "%s: failed=%d\n", __func__, ret);
+               dev_dbg(&client->dev, "failed=%d\n", ret);
                kfree(s);
        }
 
@@ -586,7 +579,7 @@ static int e4000_remove(struct i2c_client *client)
        struct e4000 *s = container_of(sd, struct e4000, sd);
        struct dvb_frontend *fe = s->fe;
 
-       dev_dbg(&client->dev, "%s:\n", __func__);
+       dev_dbg(&client->dev, "\n");
 
 #if IS_ENABLED(CONFIG_VIDEO_V4L2)
        v4l2_ctrl_handler_free(&s->hdl);
diff --git a/drivers/media/tuners/it913x.c b/drivers/media/tuners/it913x.c
new file mode 100644 (file)
index 0000000..a076c87
--- /dev/null
@@ -0,0 +1,478 @@
+/*
+ * ITE IT913X silicon tuner driver
+ *
+ *  Copyright (C) 2011 Malcolm Priestley (tvboxspy@gmail.com)
+ *  IT9137 Copyright (C) ITE Tech 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.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.=
+ */
+
+#include "it913x.h"
+#include <linux/regmap.h>
+
+struct it913x_dev {
+       struct i2c_client *client;
+       struct regmap *regmap;
+       struct dvb_frontend *fe;
+       u8 chip_ver:2;
+       u8 role:2;
+       u16 xtal;
+       u8 fdiv;
+       u8 clk_mode;
+       u32 fn_min;
+       bool active;
+};
+
+static int it913x_init(struct dvb_frontend *fe)
+{
+       struct it913x_dev *dev = fe->tuner_priv;
+       int ret;
+       unsigned int utmp;
+       u8 iqik_m_cal, nv_val, buf[2];
+       static const u8 nv[] = {48, 32, 24, 16, 12, 8, 6, 4, 2};
+       unsigned long timeout;
+
+       dev_dbg(&dev->client->dev, "role %u\n", dev->role);
+
+       ret = regmap_write(dev->regmap, 0x80ec4c, 0x68);
+       if (ret)
+               goto err;
+
+       usleep_range(10000, 100000);
+
+       ret = regmap_read(dev->regmap, 0x80ec86, &utmp);
+       if (ret)
+               goto err;
+
+       switch (utmp) {
+       case 0:
+               /* 12.000 MHz */
+               dev->clk_mode = utmp;
+               dev->xtal = 2000;
+               dev->fdiv = 3;
+               iqik_m_cal = 16;
+               break;
+       case 1:
+               /* 20.480 MHz */
+               dev->clk_mode = utmp;
+               dev->xtal = 640;
+               dev->fdiv = 1;
+               iqik_m_cal = 6;
+               break;
+       default:
+               dev_err(&dev->client->dev, "unknown clock identifier %d\n", utmp);
+               goto err;
+       }
+
+       ret = regmap_read(dev->regmap, 0x80ed03,  &utmp);
+       if (ret)
+               goto err;
+
+       else if (utmp < ARRAY_SIZE(nv))
+               nv_val = nv[utmp];
+       else
+               nv_val = 2;
+
+       #define TIMEOUT 50
+       timeout = jiffies + msecs_to_jiffies(TIMEOUT);
+       while (!time_after(jiffies, timeout)) {
+               ret = regmap_bulk_read(dev->regmap, 0x80ed23, buf, 2);
+               if (ret)
+                       goto err;
+
+               utmp = (buf[1] << 8) | (buf[0] << 0);
+               if (utmp)
+                       break;
+       }
+
+       dev_dbg(&dev->client->dev, "r_fbc_m_bdry took %u ms, val %u\n",
+                       jiffies_to_msecs(jiffies) -
+                       (jiffies_to_msecs(timeout) - TIMEOUT), utmp);
+
+       dev->fn_min = dev->xtal * utmp;
+       dev->fn_min /= (dev->fdiv * nv_val);
+       dev->fn_min *= 1000;
+       dev_dbg(&dev->client->dev, "fn_min %u\n", dev->fn_min);
+
+       /*
+        * Chip version BX never sets that flag so we just wait 50ms in that
+        * case. It is possible poll BX similarly than AX and then timeout in
+        * order to get 50ms delay, but that causes about 120 extra I2C
+        * messages. As for now, we just wait and reduce IO.
+        */
+       if (dev->chip_ver == 1) {
+               #define TIMEOUT 50
+               timeout = jiffies + msecs_to_jiffies(TIMEOUT);
+               while (!time_after(jiffies, timeout)) {
+                       ret = regmap_read(dev->regmap, 0x80ec82, &utmp);
+                       if (ret)
+                               goto err;
+
+                       if (utmp)
+                               break;
+               }
+
+               dev_dbg(&dev->client->dev, "p_tsm_init_mode took %u ms, val %u\n",
+                               jiffies_to_msecs(jiffies) -
+                               (jiffies_to_msecs(timeout) - TIMEOUT), utmp);
+       } else {
+               msleep(50);
+       }
+
+       ret = regmap_write(dev->regmap, 0x80ed81, iqik_m_cal);
+       if (ret)
+               goto err;
+
+       ret = regmap_write(dev->regmap, 0x80ec57, 0x00);
+       if (ret)
+               goto err;
+
+       ret = regmap_write(dev->regmap, 0x80ec58, 0x00);
+       if (ret)
+               goto err;
+
+       ret = regmap_write(dev->regmap, 0x80ec40, 0x01);
+       if (ret)
+               goto err;
+
+       dev->active = true;
+
+       return 0;
+err:
+       dev_dbg(&dev->client->dev, "failed %d\n", ret);
+       return ret;
+}
+
+static int it913x_sleep(struct dvb_frontend *fe)
+{
+       struct it913x_dev *dev = fe->tuner_priv;
+       int ret, len;
+
+       dev_dbg(&dev->client->dev, "role %u\n", dev->role);
+
+       dev->active = false;
+
+       ret  = regmap_bulk_write(dev->regmap, 0x80ec40, "\x00", 1);
+       if (ret)
+               goto err;
+
+       /*
+        * Writing '0x00' to master tuner register '0x80ec08' causes slave tuner
+        * communication lost. Due to that, we cannot put master full sleep.
+        */
+       if (dev->role == IT913X_ROLE_DUAL_MASTER)
+               len = 4;
+       else
+               len = 15;
+
+       dev_dbg(&dev->client->dev, "role %u, len %d\n", dev->role, len);
+
+       ret = regmap_bulk_write(dev->regmap, 0x80ec02,
+                       "\x3f\x1f\x3f\x3e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
+                       len);
+       if (ret)
+               goto err;
+
+       ret = regmap_bulk_write(dev->regmap, 0x80ec12, "\x00\x00\x00\x00", 4);
+       if (ret)
+               goto err;
+
+       ret = regmap_bulk_write(dev->regmap, 0x80ec17,
+                       "\x00\x00\x00\x00\x00\x00\x00\x00\x00", 9);
+       if (ret)
+               goto err;
+
+       ret = regmap_bulk_write(dev->regmap, 0x80ec22,
+                       "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 10);
+       if (ret)
+               goto err;
+
+       ret = regmap_bulk_write(dev->regmap, 0x80ec20, "\x00", 1);
+       if (ret)
+               goto err;
+
+       ret = regmap_bulk_write(dev->regmap, 0x80ec3f, "\x01", 1);
+       if (ret)
+               goto err;
+
+       return 0;
+err:
+       dev_dbg(&dev->client->dev, "failed %d\n", ret);
+       return ret;
+}
+
+static int it913x_set_params(struct dvb_frontend *fe)
+{
+       struct it913x_dev *dev = fe->tuner_priv;
+       struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+       int ret;
+       unsigned int utmp;
+       u32 pre_lo_freq, t_cal_freq;
+       u16 iqik_m_cal, n_div;
+       u8 u8tmp, n, l_band, lna_band;
+
+       dev_dbg(&dev->client->dev, "role=%u, frequency %u, bandwidth_hz %u\n",
+                       dev->role, c->frequency, c->bandwidth_hz);
+
+       if (!dev->active) {
+               ret = -EINVAL;
+               goto err;
+       }
+
+       if (c->frequency <=         74000000) {
+               n_div = 48;
+               n = 0;
+       } else if (c->frequency <= 111000000) {
+               n_div = 32;
+               n = 1;
+       } else if (c->frequency <= 148000000) {
+               n_div = 24;
+               n = 2;
+       } else if (c->frequency <= 222000000) {
+               n_div = 16;
+               n = 3;
+       } else if (c->frequency <= 296000000) {
+               n_div = 12;
+               n = 4;
+       } else if (c->frequency <= 445000000) {
+               n_div = 8;
+               n = 5;
+       } else if (c->frequency <= dev->fn_min) {
+               n_div = 6;
+               n = 6;
+       } else if (c->frequency <= 950000000) {
+               n_div = 4;
+               n = 7;
+       } else {
+               n_div = 2;
+               n = 0;
+       }
+
+       ret = regmap_read(dev->regmap, 0x80ed81, &utmp);
+       if (ret)
+               goto err;
+
+       iqik_m_cal = utmp * n_div;
+
+       if (utmp < 0x20) {
+               if (dev->clk_mode == 0)
+                       iqik_m_cal = (iqik_m_cal * 9) >> 5;
+               else
+                       iqik_m_cal >>= 1;
+       } else {
+               iqik_m_cal = 0x40 - iqik_m_cal;
+               if (dev->clk_mode == 0)
+                       iqik_m_cal = ~((iqik_m_cal * 9) >> 5);
+               else
+                       iqik_m_cal = ~(iqik_m_cal >> 1);
+       }
+
+       t_cal_freq = (c->frequency / 1000) * n_div * dev->fdiv;
+       pre_lo_freq = t_cal_freq / dev->xtal;
+       utmp = pre_lo_freq * dev->xtal;
+
+       if ((t_cal_freq - utmp) >= (dev->xtal >> 1))
+               pre_lo_freq++;
+
+       pre_lo_freq += (u32) n << 13;
+       /* Frequency OMEGA_IQIK_M_CAL_MID*/
+       t_cal_freq = pre_lo_freq + (u32)iqik_m_cal;
+       dev_dbg(&dev->client->dev, "t_cal_freq %u, pre_lo_freq %u\n",
+                       t_cal_freq, pre_lo_freq);
+
+       if (c->frequency <=         440000000) {
+               l_band = 0;
+               lna_band = 0;
+       } else if (c->frequency <=  484000000) {
+               l_band = 1;
+               lna_band = 1;
+       } else if (c->frequency <=  533000000) {
+               l_band = 1;
+               lna_band = 2;
+       } else if (c->frequency <=  587000000) {
+               l_band = 1;
+               lna_band = 3;
+       } else if (c->frequency <=  645000000) {
+               l_band = 1;
+               lna_band = 4;
+       } else if (c->frequency <=  710000000) {
+               l_band = 1;
+               lna_band = 5;
+       } else if (c->frequency <=  782000000) {
+               l_band = 1;
+               lna_band = 6;
+       } else if (c->frequency <=  860000000) {
+               l_band = 1;
+               lna_band = 7;
+       } else if (c->frequency <= 1492000000) {
+               l_band = 1;
+               lna_band = 0;
+       } else if (c->frequency <= 1685000000) {
+               l_band = 1;
+               lna_band = 1;
+       } else {
+               ret = -EINVAL;
+               goto err;
+       }
+
+       /* XXX: latest windows driver does not set that at all */
+       ret = regmap_write(dev->regmap, 0x80ee06, lna_band);
+       if (ret)
+               goto err;
+
+       if (c->bandwidth_hz <=      5000000)
+               u8tmp = 0;
+       else if (c->bandwidth_hz <= 6000000)
+               u8tmp = 2;
+       else if (c->bandwidth_hz <= 7000000)
+               u8tmp = 4;
+       else
+               u8tmp = 6;       /* 8000000 */
+
+       ret = regmap_write(dev->regmap, 0x80ec56, u8tmp);
+       if (ret)
+               goto err;
+
+       /* XXX: latest windows driver sets different value (a8 != 68) */
+       ret = regmap_write(dev->regmap, 0x80ec4c, 0xa0 | (l_band << 3));
+       if (ret)
+               goto err;
+
+       ret = regmap_write(dev->regmap, 0x80ec4d, (t_cal_freq >> 0) & 0xff);
+       if (ret)
+               goto err;
+
+       ret = regmap_write(dev->regmap, 0x80ec4e, (t_cal_freq >> 8) & 0xff);
+       if (ret)
+               goto err;
+
+       ret = regmap_write(dev->regmap, 0x80011e, (pre_lo_freq >> 0) & 0xff);
+       if (ret)
+               goto err;
+
+       ret = regmap_write(dev->regmap, 0x80011f, (pre_lo_freq >> 8) & 0xff);
+       if (ret)
+               goto err;
+
+       return 0;
+err:
+       dev_dbg(&dev->client->dev, "failed %d\n", ret);
+       return ret;
+}
+
+static const struct dvb_tuner_ops it913x_tuner_ops = {
+       .info = {
+               .name           = "ITE IT913X",
+               .frequency_min  = 174000000,
+               .frequency_max  = 862000000,
+       },
+
+       .init = it913x_init,
+       .sleep = it913x_sleep,
+       .set_params = it913x_set_params,
+};
+
+static int it913x_probe(struct i2c_client *client,
+               const struct i2c_device_id *id)
+{
+       struct it913x_config *cfg = client->dev.platform_data;
+       struct dvb_frontend *fe = cfg->fe;
+       struct it913x_dev *dev;
+       int ret;
+       char *chip_ver_str;
+       static const struct regmap_config regmap_config = {
+               .reg_bits = 24,
+               .val_bits = 8,
+       };
+
+       dev = kzalloc(sizeof(struct it913x_dev), GFP_KERNEL);
+       if (dev == NULL) {
+               ret = -ENOMEM;
+               dev_err(&client->dev, "kzalloc() failed\n");
+               goto err;
+       }
+
+       dev->client = client;
+       dev->fe = cfg->fe;
+       dev->chip_ver = cfg->chip_ver;
+       dev->role = cfg->role;
+       dev->regmap = regmap_init_i2c(client, &regmap_config);
+       if (IS_ERR(dev->regmap)) {
+               ret = PTR_ERR(dev->regmap);
+               goto err_kfree;
+       }
+
+       fe->tuner_priv = dev;
+       memcpy(&fe->ops.tuner_ops, &it913x_tuner_ops,
+                       sizeof(struct dvb_tuner_ops));
+       i2c_set_clientdata(client, dev);
+
+       if (dev->chip_ver == 1)
+               chip_ver_str = "AX";
+       else if (dev->chip_ver == 2)
+               chip_ver_str = "BX";
+       else
+               chip_ver_str = "??";
+
+       dev_info(&dev->client->dev, "ITE IT913X %s successfully attached\n",
+                       chip_ver_str);
+       dev_dbg(&dev->client->dev, "chip_ver %u, role %u\n",
+                       dev->chip_ver, dev->role);
+       return 0;
+
+err_kfree:
+       kfree(dev);
+err:
+       dev_dbg(&client->dev, "failed %d\n", ret);
+       return ret;
+}
+
+static int it913x_remove(struct i2c_client *client)
+{
+       struct it913x_dev *dev = i2c_get_clientdata(client);
+       struct dvb_frontend *fe = dev->fe;
+
+       dev_dbg(&client->dev, "\n");
+
+       memset(&fe->ops.tuner_ops, 0, sizeof(struct dvb_tuner_ops));
+       fe->tuner_priv = NULL;
+       regmap_exit(dev->regmap);
+       kfree(dev);
+
+       return 0;
+}
+
+static const struct i2c_device_id it913x_id_table[] = {
+       {"it913x", 0},
+       {}
+};
+MODULE_DEVICE_TABLE(i2c, it913x_id_table);
+
+static struct i2c_driver it913x_driver = {
+       .driver = {
+               .owner  = THIS_MODULE,
+               .name   = "it913x",
+       },
+       .probe          = it913x_probe,
+       .remove         = it913x_remove,
+       .id_table       = it913x_id_table,
+};
+
+module_i2c_driver(it913x_driver);
+
+MODULE_DESCRIPTION("ITE IT913X silicon tuner driver");
+MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/tuners/it913x.h b/drivers/media/tuners/it913x.h
new file mode 100644 (file)
index 0000000..33de53d
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ * ITE Tech IT9137 silicon tuner driver
+ *
+ *  Copyright (C) 2011 Malcolm Priestley (tvboxspy@gmail.com)
+ *  IT9137 Copyright (C) ITE Tech 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.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.=
+ */
+
+#ifndef IT913X_H
+#define IT913X_H
+
+#include "dvb_frontend.h"
+
+/*
+ * I2C address
+ * 0x38, 0x3a, 0x3c, 0x3e
+ */
+struct it913x_config {
+       /*
+        * pointer to DVB frontend
+        */
+       struct dvb_frontend *fe;
+
+       /*
+        * chip version
+        * 1 = IT9135 AX
+        * 2 = IT9135 BX
+        */
+       unsigned int chip_ver:2;
+
+       /*
+        * tuner role
+        */
+#define IT913X_ROLE_SINGLE         0
+#define IT913X_ROLE_DUAL_MASTER    1
+#define IT913X_ROLE_DUAL_SLAVE     2
+       unsigned int role:2;
+};
+
+#endif
index 40c42dec721b9de556dacc6cadc12a80ba3cc06b..caa542346891f630074ec26d1aa11d046f85e261 100644 (file)
 
 #include "m88ts2022_priv.h"
 
-/* write multiple registers */
-static int m88ts2022_wr_regs(struct m88ts2022_priv *priv,
-               u8 reg, const u8 *val, int len)
+static int m88ts2022_cmd(struct m88ts2022_dev *dev, int op, int sleep, u8 reg,
+               u8 mask, u8 val, u8 *reg_val)
 {
-#define MAX_WR_LEN 3
-#define MAX_WR_XFER_LEN (MAX_WR_LEN + 1)
-       int ret;
-       u8 buf[MAX_WR_XFER_LEN];
-       struct i2c_msg msg[1] = {
-               {
-                       .addr = priv->client->addr,
-                       .flags = 0,
-                       .len = 1 + len,
-                       .buf = buf,
-               }
-       };
-
-       if (WARN_ON(len > MAX_WR_LEN))
-               return -EINVAL;
-
-       buf[0] = reg;
-       memcpy(&buf[1], val, len);
-
-       ret = i2c_transfer(priv->client->adapter, msg, 1);
-       if (ret == 1) {
-               ret = 0;
-       } else {
-               dev_warn(&priv->client->dev,
-                               "%s: i2c wr failed=%d reg=%02x len=%d\n",
-                               KBUILD_MODNAME, ret, reg, len);
-               ret = -EREMOTEIO;
-       }
-
-       return ret;
-}
-
-/* read multiple registers */
-static int m88ts2022_rd_regs(struct m88ts2022_priv *priv, u8 reg,
-               u8 *val, int len)
-{
-#define MAX_RD_LEN 1
-#define MAX_RD_XFER_LEN (MAX_RD_LEN)
-       int ret;
-       u8 buf[MAX_RD_XFER_LEN];
-       struct i2c_msg msg[2] = {
-               {
-                       .addr = priv->client->addr,
-                       .flags = 0,
-                       .len = 1,
-                       .buf = &reg,
-               }, {
-                       .addr = priv->client->addr,
-                       .flags = I2C_M_RD,
-                       .len = len,
-                       .buf = buf,
-               }
-       };
-
-       if (WARN_ON(len > MAX_RD_LEN))
-               return -EINVAL;
-
-       ret = i2c_transfer(priv->client->adapter, msg, 2);
-       if (ret == 2) {
-               memcpy(val, buf, len);
-               ret = 0;
-       } else {
-               dev_warn(&priv->client->dev,
-                               "%s: i2c rd failed=%d reg=%02x len=%d\n",
-                               KBUILD_MODNAME, ret, reg, len);
-               ret = -EREMOTEIO;
-       }
-
-       return ret;
-}
-
-/* write single register */
-static int m88ts2022_wr_reg(struct m88ts2022_priv *priv, u8 reg, u8 val)
-{
-       return m88ts2022_wr_regs(priv, reg, &val, 1);
-}
-
-/* read single register */
-static int m88ts2022_rd_reg(struct m88ts2022_priv *priv, u8 reg, u8 *val)
-{
-       return m88ts2022_rd_regs(priv, reg, val, 1);
-}
-
-/* write single register with mask */
-static int m88ts2022_wr_reg_mask(struct m88ts2022_priv *priv,
-               u8 reg, u8 val, u8 mask)
-{
-       int ret;
-       u8 u8tmp;
-
-       /* no need for read if whole reg is written */
-       if (mask != 0xff) {
-               ret = m88ts2022_rd_regs(priv, reg, &u8tmp, 1);
-               if (ret)
-                       return ret;
-
-               val &= mask;
-               u8tmp &= ~mask;
-               val |= u8tmp;
-       }
-
-       return m88ts2022_wr_regs(priv, reg, &val, 1);
-}
-
-static int m88ts2022_cmd(struct dvb_frontend *fe,
-               int op, int sleep, u8 reg, u8 mask, u8 val, u8 *reg_val)
-{
-       struct m88ts2022_priv *priv = fe->tuner_priv;
        int ret, i;
-       u8 u8tmp;
+       unsigned int utmp;
        struct m88ts2022_reg_val reg_vals[] = {
                {0x51, 0x1f - op},
                {0x51, 0x1f},
@@ -140,12 +31,12 @@ static int m88ts2022_cmd(struct dvb_frontend *fe,
        };
 
        for (i = 0; i < 2; i++) {
-               dev_dbg(&priv->client->dev,
-                               "%s: i=%d op=%02x reg=%02x mask=%02x val=%02x\n",
-                               __func__, i, op, reg, mask, val);
+               dev_dbg(&dev->client->dev,
+                               "i=%d op=%02x reg=%02x mask=%02x val=%02x\n",
+                               i, op, reg, mask, val);
 
                for (i = 0; i < ARRAY_SIZE(reg_vals); i++) {
-                       ret = m88ts2022_wr_reg(priv, reg_vals[i].reg,
+                       ret = regmap_write(dev->regmap, reg_vals[i].reg,
                                        reg_vals[i].val);
                        if (ret)
                                goto err;
@@ -153,37 +44,38 @@ static int m88ts2022_cmd(struct dvb_frontend *fe,
 
                usleep_range(sleep * 1000, sleep * 10000);
 
-               ret = m88ts2022_rd_reg(priv, reg, &u8tmp);
+               ret = regmap_read(dev->regmap, reg, &utmp);
                if (ret)
                        goto err;
 
-               if ((u8tmp & mask) != val)
+               if ((utmp & mask) != val)
                        break;
        }
 
        if (reg_val)
-               *reg_val = u8tmp;
+               *reg_val = utmp;
 err:
        return ret;
 }
 
 static int m88ts2022_set_params(struct dvb_frontend *fe)
 {
-       struct m88ts2022_priv *priv = fe->tuner_priv;
+       struct m88ts2022_dev *dev = fe->tuner_priv;
        struct dtv_frontend_properties *c = &fe->dtv_property_cache;
        int ret;
-       unsigned int frequency_khz, frequency_offset_khz, f_3db_hz;
+       unsigned int utmp, frequency_khz, frequency_offset_khz, f_3db_hz;
        unsigned int f_ref_khz, f_vco_khz, div_ref, div_out, pll_n, gdiv28;
        u8 buf[3], u8tmp, cap_code, lpf_gm, lpf_mxdiv, div_max, div_min;
        u16 u16tmp;
-       dev_dbg(&priv->client->dev,
-                       "%s: frequency=%d symbol_rate=%d rolloff=%d\n",
-                       __func__, c->frequency, c->symbol_rate, c->rolloff);
+
+       dev_dbg(&dev->client->dev,
+                       "frequency=%d symbol_rate=%d rolloff=%d\n",
+                       c->frequency, c->symbol_rate, c->rolloff);
        /*
         * Integer-N PLL synthesizer
         * kHz is used for all calculations to keep calculations within 32-bit
         */
-       f_ref_khz = DIV_ROUND_CLOSEST(priv->cfg.clock, 1000);
+       f_ref_khz = DIV_ROUND_CLOSEST(dev->cfg.clock, 1000);
        div_ref = DIV_ROUND_CLOSEST(f_ref_khz, 2000);
 
        if (c->symbol_rate < 5000000)
@@ -203,14 +95,14 @@ static int m88ts2022_set_params(struct dvb_frontend *fe)
 
        buf[0] = u8tmp;
        buf[1] = 0x40;
-       ret = m88ts2022_wr_regs(priv, 0x10, buf, 2);
+       ret = regmap_bulk_write(dev->regmap, 0x10, buf, 2);
        if (ret)
                goto err;
 
        f_vco_khz = frequency_khz * div_out;
        pll_n = f_vco_khz * div_ref / f_ref_khz;
        pll_n += pll_n % 2;
-       priv->frequency_khz = pll_n * f_ref_khz / div_ref / div_out;
+       dev->frequency_khz = pll_n * f_ref_khz / div_ref / div_out;
 
        if (pll_n < 4095)
                u16tmp = pll_n - 1024;
@@ -222,88 +114,87 @@ static int m88ts2022_set_params(struct dvb_frontend *fe)
        buf[0] = (u16tmp >> 8) & 0x3f;
        buf[1] = (u16tmp >> 0) & 0xff;
        buf[2] = div_ref - 8;
-       ret = m88ts2022_wr_regs(priv, 0x01, buf, 3);
+       ret = regmap_bulk_write(dev->regmap, 0x01, buf, 3);
        if (ret)
                goto err;
 
-       dev_dbg(&priv->client->dev,
-                       "%s: frequency=%u offset=%d f_vco_khz=%u pll_n=%u div_ref=%u div_out=%u\n",
-                       __func__, priv->frequency_khz,
-                       priv->frequency_khz - c->frequency, f_vco_khz, pll_n,
-                       div_ref, div_out);
+       dev_dbg(&dev->client->dev,
+                       "frequency=%u offset=%d f_vco_khz=%u pll_n=%u div_ref=%u div_out=%u\n",
+                       dev->frequency_khz, dev->frequency_khz - c->frequency,
+                       f_vco_khz, pll_n, div_ref, div_out);
 
-       ret = m88ts2022_cmd(fe, 0x10, 5, 0x15, 0x40, 0x00, NULL);
+       ret = m88ts2022_cmd(dev, 0x10, 5, 0x15, 0x40, 0x00, NULL);
        if (ret)
                goto err;
 
-       ret = m88ts2022_rd_reg(priv, 0x14, &u8tmp);
+       ret = regmap_read(dev->regmap, 0x14, &utmp);
        if (ret)
                goto err;
 
-       u8tmp &= 0x7f;
-       if (u8tmp < 64) {
-               ret = m88ts2022_wr_reg_mask(priv, 0x10, 0x80, 0x80);
+       utmp &= 0x7f;
+       if (utmp < 64) {
+               ret = regmap_update_bits(dev->regmap, 0x10, 0x80, 0x80);
                if (ret)
                        goto err;
 
-               ret = m88ts2022_wr_reg(priv, 0x11, 0x6f);
+               ret = regmap_write(dev->regmap, 0x11, 0x6f);
                if (ret)
                        goto err;
 
-               ret = m88ts2022_cmd(fe, 0x10, 5, 0x15, 0x40, 0x00, NULL);
+               ret = m88ts2022_cmd(dev, 0x10, 5, 0x15, 0x40, 0x00, NULL);
                if (ret)
                        goto err;
        }
 
-       ret = m88ts2022_rd_reg(priv, 0x14, &u8tmp);
+       ret = regmap_read(dev->regmap, 0x14, &utmp);
        if (ret)
                goto err;
 
-       u8tmp &= 0x1f;
-       if (u8tmp > 19) {
-               ret = m88ts2022_wr_reg_mask(priv, 0x10, 0x00, 0x02);
+       utmp &= 0x1f;
+       if (utmp > 19) {
+               ret = regmap_update_bits(dev->regmap, 0x10, 0x02, 0x00);
                if (ret)
                        goto err;
        }
 
-       ret = m88ts2022_cmd(fe, 0x08, 5, 0x3c, 0xff, 0x00, NULL);
+       ret = m88ts2022_cmd(dev, 0x08, 5, 0x3c, 0xff, 0x00, NULL);
        if (ret)
                goto err;
 
-       ret = m88ts2022_wr_reg(priv, 0x25, 0x00);
+       ret = regmap_write(dev->regmap, 0x25, 0x00);
        if (ret)
                goto err;
 
-       ret = m88ts2022_wr_reg(priv, 0x27, 0x70);
+       ret = regmap_write(dev->regmap, 0x27, 0x70);
        if (ret)
                goto err;
 
-       ret = m88ts2022_wr_reg(priv, 0x41, 0x09);
+       ret = regmap_write(dev->regmap, 0x41, 0x09);
        if (ret)
                goto err;
 
-       ret = m88ts2022_wr_reg(priv, 0x08, 0x0b);
+       ret = regmap_write(dev->regmap, 0x08, 0x0b);
        if (ret)
                goto err;
 
        /* filters */
        gdiv28 = DIV_ROUND_CLOSEST(f_ref_khz * 1694U, 1000000U);
 
-       ret = m88ts2022_wr_reg(priv, 0x04, gdiv28);
+       ret = regmap_write(dev->regmap, 0x04, gdiv28);
        if (ret)
                goto err;
 
-       ret = m88ts2022_cmd(fe, 0x04, 2, 0x26, 0xff, 0x00, &u8tmp);
+       ret = m88ts2022_cmd(dev, 0x04, 2, 0x26, 0xff, 0x00, &u8tmp);
        if (ret)
                goto err;
 
        cap_code = u8tmp & 0x3f;
 
-       ret = m88ts2022_wr_reg(priv, 0x41, 0x0d);
+       ret = regmap_write(dev->regmap, 0x41, 0x0d);
        if (ret)
                goto err;
 
-       ret = m88ts2022_cmd(fe, 0x04, 2, 0x26, 0xff, 0x00, &u8tmp);
+       ret = m88ts2022_cmd(dev, 0x04, 2, 0x26, 0xff, 0x00, &u8tmp);
        if (ret)
                goto err;
 
@@ -314,7 +205,7 @@ static int m88ts2022_set_params(struct dvb_frontend *fe)
        div_min = gdiv28 * 78 / 100;
        div_max = clamp_val(div_max, 0U, 63U);
 
-       f_3db_hz = c->symbol_rate * 135UL / 200UL;
+       f_3db_hz = mult_frac(c->symbol_rate, 135, 200);
        f_3db_hz +=  2000000U + (frequency_offset_khz * 1000U);
        f_3db_hz = clamp(f_3db_hz, 7000000U, 40000000U);
 
@@ -327,25 +218,25 @@ static int m88ts2022_set_params(struct dvb_frontend *fe)
                lpf_mxdiv = DIV_ROUND_CLOSEST(++lpf_gm * LPF_COEFF * f_ref_khz, f_3db_hz);
        lpf_mxdiv = clamp_val(lpf_mxdiv, 0U, div_max);
 
-       ret = m88ts2022_wr_reg(priv, 0x04, lpf_mxdiv);
+       ret = regmap_write(dev->regmap, 0x04, lpf_mxdiv);
        if (ret)
                goto err;
 
-       ret = m88ts2022_wr_reg(priv, 0x06, lpf_gm);
+       ret = regmap_write(dev->regmap, 0x06, lpf_gm);
        if (ret)
                goto err;
 
-       ret = m88ts2022_cmd(fe, 0x04, 2, 0x26, 0xff, 0x00, &u8tmp);
+       ret = m88ts2022_cmd(dev, 0x04, 2, 0x26, 0xff, 0x00, &u8tmp);
        if (ret)
                goto err;
 
        cap_code = u8tmp & 0x3f;
 
-       ret = m88ts2022_wr_reg(priv, 0x41, 0x09);
+       ret = regmap_write(dev->regmap, 0x41, 0x09);
        if (ret)
                goto err;
 
-       ret = m88ts2022_cmd(fe, 0x04, 2, 0x26, 0xff, 0x00, &u8tmp);
+       ret = m88ts2022_cmd(dev, 0x04, 2, 0x26, 0xff, 0x00, &u8tmp);
        if (ret)
                goto err;
 
@@ -353,31 +244,31 @@ static int m88ts2022_set_params(struct dvb_frontend *fe)
        cap_code = (cap_code + u8tmp) / 2;
 
        u8tmp = cap_code | 0x80;
-       ret = m88ts2022_wr_reg(priv, 0x25, u8tmp);
+       ret = regmap_write(dev->regmap, 0x25, u8tmp);
        if (ret)
                goto err;
 
-       ret = m88ts2022_wr_reg(priv, 0x27, 0x30);
+       ret = regmap_write(dev->regmap, 0x27, 0x30);
        if (ret)
                goto err;
 
-       ret = m88ts2022_wr_reg(priv, 0x08, 0x09);
+       ret = regmap_write(dev->regmap, 0x08, 0x09);
        if (ret)
                goto err;
 
-       ret = m88ts2022_cmd(fe, 0x01, 20, 0x21, 0xff, 0x00, NULL);
+       ret = m88ts2022_cmd(dev, 0x01, 20, 0x21, 0xff, 0x00, NULL);
        if (ret)
                goto err;
 err:
        if (ret)
-               dev_dbg(&priv->client->dev, "%s: failed=%d\n", __func__, ret);
+               dev_dbg(&dev->client->dev, "failed=%d\n", ret);
 
        return ret;
 }
 
 static int m88ts2022_init(struct dvb_frontend *fe)
 {
-       struct m88ts2022_priv *priv = fe->tuner_priv;
+       struct m88ts2022_dev *dev = fe->tuner_priv;
        int ret, i;
        u8 u8tmp;
        static const struct m88ts2022_reg_val reg_vals[] = {
@@ -393,23 +284,24 @@ static int m88ts2022_init(struct dvb_frontend *fe)
                {0x24, 0x02},
                {0x12, 0xa0},
        };
-       dev_dbg(&priv->client->dev, "%s:\n", __func__);
 
-       ret = m88ts2022_wr_reg(priv, 0x00, 0x01);
+       dev_dbg(&dev->client->dev, "\n");
+
+       ret = regmap_write(dev->regmap, 0x00, 0x01);
        if (ret)
                goto err;
 
-       ret = m88ts2022_wr_reg(priv, 0x00, 0x03);
+       ret = regmap_write(dev->regmap, 0x00, 0x03);
        if (ret)
                goto err;
 
-       switch (priv->cfg.clock_out) {
+       switch (dev->cfg.clock_out) {
        case M88TS2022_CLOCK_OUT_DISABLED:
                u8tmp = 0x60;
                break;
        case M88TS2022_CLOCK_OUT_ENABLED:
                u8tmp = 0x70;
-               ret = m88ts2022_wr_reg(priv, 0x05, priv->cfg.clock_out_div);
+               ret = regmap_write(dev->regmap, 0x05, dev->cfg.clock_out_div);
                if (ret)
                        goto err;
                break;
@@ -420,58 +312,61 @@ static int m88ts2022_init(struct dvb_frontend *fe)
                goto err;
        }
 
-       ret = m88ts2022_wr_reg(priv, 0x42, u8tmp);
+       ret = regmap_write(dev->regmap, 0x42, u8tmp);
        if (ret)
                goto err;
 
-       if (priv->cfg.loop_through)
+       if (dev->cfg.loop_through)
                u8tmp = 0xec;
        else
                u8tmp = 0x6c;
 
-       ret = m88ts2022_wr_reg(priv, 0x62, u8tmp);
+       ret = regmap_write(dev->regmap, 0x62, u8tmp);
        if (ret)
                goto err;
 
        for (i = 0; i < ARRAY_SIZE(reg_vals); i++) {
-               ret = m88ts2022_wr_reg(priv, reg_vals[i].reg, reg_vals[i].val);
+               ret = regmap_write(dev->regmap, reg_vals[i].reg, reg_vals[i].val);
                if (ret)
                        goto err;
        }
 err:
        if (ret)
-               dev_dbg(&priv->client->dev, "%s: failed=%d\n", __func__, ret);
+               dev_dbg(&dev->client->dev, "failed=%d\n", ret);
        return ret;
 }
 
 static int m88ts2022_sleep(struct dvb_frontend *fe)
 {
-       struct m88ts2022_priv *priv = fe->tuner_priv;
+       struct m88ts2022_dev *dev = fe->tuner_priv;
        int ret;
-       dev_dbg(&priv->client->dev, "%s:\n", __func__);
 
-       ret = m88ts2022_wr_reg(priv, 0x00, 0x00);
+       dev_dbg(&dev->client->dev, "\n");
+
+       ret = regmap_write(dev->regmap, 0x00, 0x00);
        if (ret)
                goto err;
 err:
        if (ret)
-               dev_dbg(&priv->client->dev, "%s: failed=%d\n", __func__, ret);
+               dev_dbg(&dev->client->dev, "failed=%d\n", ret);
        return ret;
 }
 
 static int m88ts2022_get_frequency(struct dvb_frontend *fe, u32 *frequency)
 {
-       struct m88ts2022_priv *priv = fe->tuner_priv;
-       dev_dbg(&priv->client->dev, "%s:\n", __func__);
+       struct m88ts2022_dev *dev = fe->tuner_priv;
 
-       *frequency = priv->frequency_khz;
+       dev_dbg(&dev->client->dev, "\n");
+
+       *frequency = dev->frequency_khz;
        return 0;
 }
 
 static int m88ts2022_get_if_frequency(struct dvb_frontend *fe, u32 *frequency)
 {
-       struct m88ts2022_priv *priv = fe->tuner_priv;
-       dev_dbg(&priv->client->dev, "%s:\n", __func__);
+       struct m88ts2022_dev *dev = fe->tuner_priv;
+
+       dev_dbg(&dev->client->dev, "\n");
 
        *frequency = 0; /* Zero-IF */
        return 0;
@@ -479,31 +374,30 @@ static int m88ts2022_get_if_frequency(struct dvb_frontend *fe, u32 *frequency)
 
 static int m88ts2022_get_rf_strength(struct dvb_frontend *fe, u16 *strength)
 {
-       struct m88ts2022_priv *priv = fe->tuner_priv;
+       struct m88ts2022_dev *dev = fe->tuner_priv;
        int ret;
-       u8 u8tmp;
        u16 gain, u16tmp;
-       unsigned int gain1, gain2, gain3;
+       unsigned int utmp, gain1, gain2, gain3;
 
-       ret = m88ts2022_rd_reg(priv, 0x3d, &u8tmp);
+       ret = regmap_read(dev->regmap, 0x3d, &utmp);
        if (ret)
                goto err;
 
-       gain1 = (u8tmp >> 0) & 0x1f;
+       gain1 = (utmp >> 0) & 0x1f;
        gain1 = clamp(gain1, 0U, 15U);
 
-       ret = m88ts2022_rd_reg(priv, 0x21, &u8tmp);
+       ret = regmap_read(dev->regmap, 0x21, &utmp);
        if (ret)
                goto err;
 
-       gain2 = (u8tmp >> 0) & 0x1f;
+       gain2 = (utmp >> 0) & 0x1f;
        gain2 = clamp(gain2, 2U, 16U);
 
-       ret = m88ts2022_rd_reg(priv, 0x66, &u8tmp);
+       ret = regmap_read(dev->regmap, 0x66, &utmp);
        if (ret)
                goto err;
 
-       gain3 = (u8tmp >> 3) & 0x07;
+       gain3 = (utmp >> 3) & 0x07;
        gain3 = clamp(gain3, 0U, 6U);
 
        gain = gain1 * 265 + gain2 * 338 + gain3 * 285;
@@ -515,7 +409,7 @@ static int m88ts2022_get_rf_strength(struct dvb_frontend *fe, u16 *strength)
        *strength = (u16tmp - 59000) * 0xffff / (61500 - 59000);
 err:
        if (ret)
-               dev_dbg(&priv->client->dev, "%s: failed=%d\n", __func__, ret);
+               dev_dbg(&dev->client->dev, "failed=%d\n", ret);
        return ret;
 }
 
@@ -540,46 +434,56 @@ static int m88ts2022_probe(struct i2c_client *client,
 {
        struct m88ts2022_config *cfg = client->dev.platform_data;
        struct dvb_frontend *fe = cfg->fe;
-       struct m88ts2022_priv *priv;
+       struct m88ts2022_dev *dev;
        int ret;
-       u8 chip_id, u8tmp;
+       u8 u8tmp;
+       unsigned int utmp;
+       static const struct regmap_config regmap_config = {
+               .reg_bits = 8,
+               .val_bits = 8,
+       };
 
-       priv = kzalloc(sizeof(*priv), GFP_KERNEL);
-       if (!priv) {
+       dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+       if (!dev) {
                ret = -ENOMEM;
-               dev_err(&client->dev, "%s: kzalloc() failed\n", KBUILD_MODNAME);
+               dev_err(&client->dev, "kzalloc() failed\n");
                goto err;
        }
 
-       memcpy(&priv->cfg, cfg, sizeof(struct m88ts2022_config));
-       priv->client = client;
+       memcpy(&dev->cfg, cfg, sizeof(struct m88ts2022_config));
+       dev->client = client;
+       dev->regmap = devm_regmap_init_i2c(client, &regmap_config);
+       if (IS_ERR(dev->regmap)) {
+               ret = PTR_ERR(dev->regmap);
+               goto err;
+       }
 
        /* check if the tuner is there */
-       ret = m88ts2022_rd_reg(priv, 0x00, &u8tmp);
+       ret = regmap_read(dev->regmap, 0x00, &utmp);
        if (ret)
                goto err;
 
-       if ((u8tmp & 0x03) == 0x00) {
-               ret = m88ts2022_wr_reg(priv, 0x00, 0x01);
-               if (ret < 0)
+       if ((utmp & 0x03) == 0x00) {
+               ret = regmap_write(dev->regmap, 0x00, 0x01);
+               if (ret)
                        goto err;
 
                usleep_range(2000, 50000);
        }
 
-       ret = m88ts2022_wr_reg(priv, 0x00, 0x03);
+       ret = regmap_write(dev->regmap, 0x00, 0x03);
        if (ret)
                goto err;
 
        usleep_range(2000, 50000);
 
-       ret = m88ts2022_rd_reg(priv, 0x00, &chip_id);
+       ret = regmap_read(dev->regmap, 0x00, &utmp);
        if (ret)
                goto err;
 
-       dev_dbg(&priv->client->dev, "%s: chip_id=%02x\n", __func__, chip_id);
+       dev_dbg(&dev->client->dev, "chip_id=%02x\n", utmp);
 
-       switch (chip_id) {
+       switch (utmp) {
        case 0xc3:
        case 0x83:
                break;
@@ -587,13 +491,13 @@ static int m88ts2022_probe(struct i2c_client *client,
                goto err;
        }
 
-       switch (priv->cfg.clock_out) {
+       switch (dev->cfg.clock_out) {
        case M88TS2022_CLOCK_OUT_DISABLED:
                u8tmp = 0x60;
                break;
        case M88TS2022_CLOCK_OUT_ENABLED:
                u8tmp = 0x70;
-               ret = m88ts2022_wr_reg(priv, 0x05, priv->cfg.clock_out_div);
+               ret = regmap_write(dev->regmap, 0x05, dev->cfg.clock_out_div);
                if (ret)
                        goto err;
                break;
@@ -604,49 +508,48 @@ static int m88ts2022_probe(struct i2c_client *client,
                goto err;
        }
 
-       ret = m88ts2022_wr_reg(priv, 0x42, u8tmp);
+       ret = regmap_write(dev->regmap, 0x42, u8tmp);
        if (ret)
                goto err;
 
-       if (priv->cfg.loop_through)
+       if (dev->cfg.loop_through)
                u8tmp = 0xec;
        else
                u8tmp = 0x6c;
 
-       ret = m88ts2022_wr_reg(priv, 0x62, u8tmp);
+       ret = regmap_write(dev->regmap, 0x62, u8tmp);
        if (ret)
                goto err;
 
        /* sleep */
-       ret = m88ts2022_wr_reg(priv, 0x00, 0x00);
+       ret = regmap_write(dev->regmap, 0x00, 0x00);
        if (ret)
                goto err;
 
-       dev_info(&priv->client->dev,
-                       "%s: Montage M88TS2022 successfully identified\n",
-                       KBUILD_MODNAME);
+       dev_info(&dev->client->dev, "Montage M88TS2022 successfully identified\n");
 
-       fe->tuner_priv = priv;
+       fe->tuner_priv = dev;
        memcpy(&fe->ops.tuner_ops, &m88ts2022_tuner_ops,
                        sizeof(struct dvb_tuner_ops));
 
-       i2c_set_clientdata(client, priv);
+       i2c_set_clientdata(client, dev);
        return 0;
 err:
-       dev_dbg(&client->dev, "%s: failed=%d\n", __func__, ret);
-       kfree(priv);
+       dev_dbg(&client->dev, "failed=%d\n", ret);
+       kfree(dev);
        return ret;
 }
 
 static int m88ts2022_remove(struct i2c_client *client)
 {
-       struct m88ts2022_priv *priv = i2c_get_clientdata(client);
-       struct dvb_frontend *fe = priv->cfg.fe;
-       dev_dbg(&client->dev, "%s:\n", __func__);
+       struct m88ts2022_dev *dev = i2c_get_clientdata(client);
+       struct dvb_frontend *fe = dev->cfg.fe;
+
+       dev_dbg(&client->dev, "\n");
 
        memset(&fe->ops.tuner_ops, 0, sizeof(struct dvb_tuner_ops));
        fe->tuner_priv = NULL;
-       kfree(priv);
+       kfree(dev);
 
        return 0;
 }
index 0363dd866a2dab01ba9a19c2e7d4a85d59e53a99..feeb5ad6beef879c357612e708cc6c8e265c7f75 100644 (file)
 #define M88TS2022_PRIV_H
 
 #include "m88ts2022.h"
+#include <linux/regmap.h>
 
-struct m88ts2022_priv {
+struct m88ts2022_dev {
        struct m88ts2022_config cfg;
        struct i2c_client *client;
-       struct dvb_frontend *fe;
+       struct regmap *regmap;
        u32 frequency_khz;
 };
 
index ee99e372c943455a9aec8439dc3cab06c848867c..26019e73199314b779e788bfd6a57905c9c68457 100644 (file)
@@ -67,7 +67,8 @@ static int msi001_set_gain(struct msi001 *s, int lna_gain, int mixer_gain,
 {
        int ret;
        u32 reg;
-       dev_dbg(&s->spi->dev, "%s: lna=%d mixer=%d if=%d\n", __func__,
+
+       dev_dbg(&s->spi->dev, "lna=%d mixer=%d if=%d\n",
                        lna_gain, mixer_gain, if_gain);
 
        reg = 1 << 0;
@@ -83,7 +84,7 @@ static int msi001_set_gain(struct msi001 *s, int lna_gain, int mixer_gain,
 
        return 0;
 err:
-       dev_dbg(&s->spi->dev, "%s: failed %d\n", __func__, ret);
+       dev_dbg(&s->spi->dev, "failed %d\n", ret);
        return ret;
 };
 
@@ -94,6 +95,7 @@ static int msi001_set_tuner(struct msi001 *s)
        u32 reg;
        u64 f_vco, tmp64;
        u8 mode, filter_mode, lo_div;
+
        static const struct {
                u32 rf;
                u8 mode;
@@ -145,9 +147,7 @@ static int msi001_set_tuner(struct msi001 *s)
        #define R_REF 4
        #define F_OUT_STEP 1
 
-       dev_dbg(&s->spi->dev,
-                       "%s: f_rf=%d f_if=%d\n",
-                       __func__, f_rf, f_if);
+       dev_dbg(&s->spi->dev, "f_rf=%d f_if=%d\n", f_rf, f_if);
 
        for (i = 0; i < ARRAY_SIZE(band_lut); i++) {
                if (f_rf <= band_lut[i].rf) {
@@ -198,8 +198,7 @@ static int msi001_set_tuner(struct msi001 *s)
 
        s->bandwidth->val = bandwidth_lut[i].freq;
 
-       dev_dbg(&s->spi->dev, "%s: bandwidth selected=%d\n",
-                       __func__, bandwidth_lut[i].freq);
+       dev_dbg(&s->spi->dev, "bandwidth selected=%d\n", bandwidth_lut[i].freq);
 
        f_vco = (u64) (f_rf + f_if + f_if1) * lo_div;
        tmp64 = f_vco;
@@ -225,9 +224,8 @@ static int msi001_set_tuner(struct msi001 *s)
        tmp += 1ul * F_REF * R_REF * frac / thresh;
        tmp /= lo_div;
 
-       dev_dbg(&s->spi->dev,
-                       "%s: rf=%u:%u n=%d thresh=%d frac=%d\n",
-                               __func__, f_rf, tmp, n, thresh, frac);
+       dev_dbg(&s->spi->dev, "rf=%u:%u n=%d thresh=%d frac=%d\n",
+                               f_rf, tmp, n, thresh, frac);
 
        ret = msi001_wreg(s, 0x00000e);
        if (ret)
@@ -276,7 +274,7 @@ static int msi001_set_tuner(struct msi001 *s)
 
        return 0;
 err:
-       dev_dbg(&s->spi->dev, "%s: failed %d\n", __func__, ret);
+       dev_dbg(&s->spi->dev, "failed %d\n", ret);
        return ret;
 };
 
@@ -284,7 +282,8 @@ static int msi001_s_power(struct v4l2_subdev *sd, int on)
 {
        struct msi001 *s = sd_to_msi001(sd);
        int ret;
-       dev_dbg(&s->spi->dev, "%s: on=%d\n", __func__, on);
+
+       dev_dbg(&s->spi->dev, "on=%d\n", on);
 
        if (on)
                ret = 0;
@@ -301,7 +300,8 @@ static const struct v4l2_subdev_core_ops msi001_core_ops = {
 static int msi001_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *v)
 {
        struct msi001 *s = sd_to_msi001(sd);
-       dev_dbg(&s->spi->dev, "%s: index=%d\n", __func__, v->index);
+
+       dev_dbg(&s->spi->dev, "index=%d\n", v->index);
 
        strlcpy(v->name, "Mirics MSi001", sizeof(v->name));
        v->type = V4L2_TUNER_RF;
@@ -315,14 +315,16 @@ static int msi001_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *v)
 static int msi001_s_tuner(struct v4l2_subdev *sd, const struct v4l2_tuner *v)
 {
        struct msi001 *s = sd_to_msi001(sd);
-       dev_dbg(&s->spi->dev, "%s: index=%d\n", __func__, v->index);
+
+       dev_dbg(&s->spi->dev, "index=%d\n", v->index);
        return 0;
 }
 
 static int msi001_g_frequency(struct v4l2_subdev *sd, struct v4l2_frequency *f)
 {
        struct msi001 *s = sd_to_msi001(sd);
-       dev_dbg(&s->spi->dev, "%s: tuner=%d\n", __func__, f->tuner);
+
+       dev_dbg(&s->spi->dev, "tuner=%d\n", f->tuner);
        f->frequency = s->f_tuner;
        return 0;
 }
@@ -332,8 +334,9 @@ static int msi001_s_frequency(struct v4l2_subdev *sd,
 {
        struct msi001 *s = sd_to_msi001(sd);
        unsigned int band;
-       dev_dbg(&s->spi->dev, "%s: tuner=%d type=%d frequency=%u\n",
-                       __func__, f->tuner, f->type, f->frequency);
+
+       dev_dbg(&s->spi->dev, "tuner=%d type=%d frequency=%u\n",
+                       f->tuner, f->type, f->frequency);
 
        if (f->frequency < ((bands[0].rangehigh + bands[1].rangelow) / 2))
                band = 0;
@@ -349,8 +352,9 @@ static int msi001_enum_freq_bands(struct v4l2_subdev *sd,
                struct v4l2_frequency_band *band)
 {
        struct msi001 *s = sd_to_msi001(sd);
-       dev_dbg(&s->spi->dev, "%s: tuner=%d type=%d index=%d\n",
-                       __func__, band->tuner, band->type, band->index);
+
+       dev_dbg(&s->spi->dev, "tuner=%d type=%d index=%d\n",
+                       band->tuner, band->type, band->index);
 
        if (band->index >= ARRAY_SIZE(bands))
                return -EINVAL;
@@ -380,9 +384,10 @@ static int msi001_s_ctrl(struct v4l2_ctrl *ctrl)
        struct msi001 *s = container_of(ctrl->handler, struct msi001, hdl);
 
        int ret;
+
        dev_dbg(&s->spi->dev,
-                       "%s: id=%d name=%s val=%d min=%lld max=%lld step=%lld\n",
-                       __func__, ctrl->id, ctrl->name, ctrl->val,
+                       "id=%d name=%s val=%d min=%lld max=%lld step=%lld\n",
+                       ctrl->id, ctrl->name, ctrl->val,
                        ctrl->minimum, ctrl->maximum, ctrl->step);
 
        switch (ctrl->id) {
@@ -403,8 +408,7 @@ static int msi001_s_ctrl(struct v4l2_ctrl *ctrl)
                                s->mixer_gain->cur.val, s->if_gain->val);
                break;
        default:
-               dev_dbg(&s->spi->dev, "%s: unkown control %d\n",
-                               __func__, ctrl->id);
+               dev_dbg(&s->spi->dev, "unkown control %d\n", ctrl->id);
                ret = -EINVAL;
        }
 
@@ -419,7 +423,8 @@ static int msi001_probe(struct spi_device *spi)
 {
        struct msi001 *s;
        int ret;
-       dev_dbg(&spi->dev, "%s:\n", __func__);
+
+       dev_dbg(&spi->dev, "\n");
 
        s = kzalloc(sizeof(struct msi001), GFP_KERNEL);
        if (s == NULL) {
@@ -466,7 +471,8 @@ static int msi001_remove(struct spi_device *spi)
 {
        struct v4l2_subdev *sd = spi_get_drvdata(spi);
        struct msi001 *s = sd_to_msi001(sd);
-       dev_dbg(&spi->dev, "%s:\n", __func__);
+
+       dev_dbg(&spi->dev, "\n");
 
        /*
         * Registered by v4l2_spi_new_subdev() from master driver, but we must
index 13381de58a843a4b8f4997705bdfc62c40ae34f5..b87b2549d58d6eab5b202dca2abb8645a04a6141 100644 (file)
@@ -157,7 +157,6 @@ static int mt2060_set_params(struct dvb_frontend *fe)
 {
        struct dtv_frontend_properties *c = &fe->dtv_property_cache;
        struct mt2060_priv *priv;
-       int ret=0;
        int i=0;
        u32 freq;
        u8  lnaband;
@@ -240,7 +239,7 @@ static int mt2060_set_params(struct dvb_frontend *fe)
        if (fe->ops.i2c_gate_ctrl)
                fe->ops.i2c_gate_ctrl(fe, 0); /* close i2c_gate */
 
-       return ret;
+       return 0;
 }
 
 static void mt2060_calibrate(struct mt2060_priv *priv)
index f640dcf4a81d8a7e204bba0a015f126b9d8756bc..9e9c5eb4cb66949a7e84a9789a9829f6f1f913d9 100644 (file)
@@ -1216,7 +1216,7 @@ static u32 MT2063_SetReceiverMode(struct mt2063_state *state,
        if (status >= 0) {
                val =
                    (state->
-                    reg[MT2063_REG_PD1_TGT] & (u8) ~0x40) | (RFAGCEN[Mode]
+                    reg[MT2063_REG_PD1_TGT] & ~0x40) | (RFAGCEN[Mode]
                                                                   ? 0x40 :
                                                                   0x00);
                if (state->reg[MT2063_REG_PD1_TGT] != val)
@@ -1225,7 +1225,7 @@ static u32 MT2063_SetReceiverMode(struct mt2063_state *state,
 
        /* LNARin */
        if (status >= 0) {
-               u8 val = (state->reg[MT2063_REG_CTRL_2C] & (u8) ~0x03) |
+               u8 val = (state->reg[MT2063_REG_CTRL_2C] & ~0x03) |
                         (LNARIN[Mode] & 0x03);
                if (state->reg[MT2063_REG_CTRL_2C] != val)
                        status |= mt2063_setreg(state, MT2063_REG_CTRL_2C, val);
@@ -1235,19 +1235,19 @@ static u32 MT2063_SetReceiverMode(struct mt2063_state *state,
        if (status >= 0) {
                val =
                    (state->
-                    reg[MT2063_REG_FIFF_CTRL2] & (u8) ~0xF0) |
+                    reg[MT2063_REG_FIFF_CTRL2] & ~0xF0) |
                    (FIFFQEN[Mode] << 7) | (FIFFQ[Mode] << 4);
                if (state->reg[MT2063_REG_FIFF_CTRL2] != val) {
                        status |=
                            mt2063_setreg(state, MT2063_REG_FIFF_CTRL2, val);
                        /* trigger FIFF calibration, needed after changing FIFFQ */
                        val =
-                           (state->reg[MT2063_REG_FIFF_CTRL] | (u8) 0x01);
+                           (state->reg[MT2063_REG_FIFF_CTRL] | 0x01);
                        status |=
                            mt2063_setreg(state, MT2063_REG_FIFF_CTRL, val);
                        val =
                            (state->
-                            reg[MT2063_REG_FIFF_CTRL] & (u8) ~0x01);
+                            reg[MT2063_REG_FIFF_CTRL] & ~0x01);
                        status |=
                            mt2063_setreg(state, MT2063_REG_FIFF_CTRL, val);
                }
@@ -1259,7 +1259,7 @@ static u32 MT2063_SetReceiverMode(struct mt2063_state *state,
 
        /* acLNAmax */
        if (status >= 0) {
-               u8 val = (state->reg[MT2063_REG_LNA_OV] & (u8) ~0x1F) |
+               u8 val = (state->reg[MT2063_REG_LNA_OV] & ~0x1F) |
                         (ACLNAMAX[Mode] & 0x1F);
                if (state->reg[MT2063_REG_LNA_OV] != val)
                        status |= mt2063_setreg(state, MT2063_REG_LNA_OV, val);
@@ -1267,7 +1267,7 @@ static u32 MT2063_SetReceiverMode(struct mt2063_state *state,
 
        /* LNATGT */
        if (status >= 0) {
-               u8 val = (state->reg[MT2063_REG_LNA_TGT] & (u8) ~0x3F) |
+               u8 val = (state->reg[MT2063_REG_LNA_TGT] & ~0x3F) |
                         (LNATGT[Mode] & 0x3F);
                if (state->reg[MT2063_REG_LNA_TGT] != val)
                        status |= mt2063_setreg(state, MT2063_REG_LNA_TGT, val);
@@ -1275,7 +1275,7 @@ static u32 MT2063_SetReceiverMode(struct mt2063_state *state,
 
        /* ACRF */
        if (status >= 0) {
-               u8 val = (state->reg[MT2063_REG_RF_OV] & (u8) ~0x1F) |
+               u8 val = (state->reg[MT2063_REG_RF_OV] & ~0x1F) |
                         (ACRFMAX[Mode] & 0x1F);
                if (state->reg[MT2063_REG_RF_OV] != val)
                        status |= mt2063_setreg(state, MT2063_REG_RF_OV, val);
@@ -1283,7 +1283,7 @@ static u32 MT2063_SetReceiverMode(struct mt2063_state *state,
 
        /* PD1TGT */
        if (status >= 0) {
-               u8 val = (state->reg[MT2063_REG_PD1_TGT] & (u8) ~0x3F) |
+               u8 val = (state->reg[MT2063_REG_PD1_TGT] & ~0x3F) |
                         (PD1TGT[Mode] & 0x3F);
                if (state->reg[MT2063_REG_PD1_TGT] != val)
                        status |= mt2063_setreg(state, MT2063_REG_PD1_TGT, val);
@@ -1294,7 +1294,7 @@ static u32 MT2063_SetReceiverMode(struct mt2063_state *state,
                u8 val = ACFIFMAX[Mode];
                if (state->reg[MT2063_REG_PART_REV] != MT2063_B3 && val > 5)
                        val = 5;
-               val = (state->reg[MT2063_REG_FIF_OV] & (u8) ~0x1F) |
+               val = (state->reg[MT2063_REG_FIF_OV] & ~0x1F) |
                      (val & 0x1F);
                if (state->reg[MT2063_REG_FIF_OV] != val)
                        status |= mt2063_setreg(state, MT2063_REG_FIF_OV, val);
@@ -1302,7 +1302,7 @@ static u32 MT2063_SetReceiverMode(struct mt2063_state *state,
 
        /* PD2TGT */
        if (status >= 0) {
-               u8 val = (state->reg[MT2063_REG_PD2_TGT] & (u8) ~0x3F) |
+               u8 val = (state->reg[MT2063_REG_PD2_TGT] & ~0x3F) |
                    (PD2TGT[Mode] & 0x3F);
                if (state->reg[MT2063_REG_PD2_TGT] != val)
                        status |= mt2063_setreg(state, MT2063_REG_PD2_TGT, val);
@@ -1310,7 +1310,7 @@ static u32 MT2063_SetReceiverMode(struct mt2063_state *state,
 
        /* Ignore ATN Overload */
        if (status >= 0) {
-               val = (state->reg[MT2063_REG_LNA_TGT] & (u8) ~0x80) |
+               val = (state->reg[MT2063_REG_LNA_TGT] & ~0x80) |
                      (RFOVDIS[Mode] ? 0x80 : 0x00);
                if (state->reg[MT2063_REG_LNA_TGT] != val)
                        status |= mt2063_setreg(state, MT2063_REG_LNA_TGT, val);
@@ -1318,7 +1318,7 @@ static u32 MT2063_SetReceiverMode(struct mt2063_state *state,
 
        /* Ignore FIF Overload */
        if (status >= 0) {
-               val = (state->reg[MT2063_REG_PD1_TGT] & (u8) ~0x80) |
+               val = (state->reg[MT2063_REG_PD1_TGT] & ~0x80) |
                      (FIFOVDIS[Mode] ? 0x80 : 0x00);
                if (state->reg[MT2063_REG_PD1_TGT] != val)
                        status |= mt2063_setreg(state, MT2063_REG_PD1_TGT, val);
diff --git a/drivers/media/tuners/mxl301rf.c b/drivers/media/tuners/mxl301rf.c
new file mode 100644 (file)
index 0000000..1575a5d
--- /dev/null
@@ -0,0 +1,349 @@
+/*
+ * MaxLinear MxL301RF OFDM tuner driver
+ *
+ * Copyright (C) 2014 Akihiro Tsukada <tskd08@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2.
+ *
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+/*
+ * NOTICE:
+ * This driver is incomplete and lacks init/config of the chips,
+ * as the necessary info is not disclosed.
+ * Other features like get_if_frequency() are missing as well.
+ * It assumes that users of this driver (such as a PCI bridge of
+ * DTV receiver cards) properly init and configure the chip
+ * via I2C *before* calling this driver's init() function.
+ *
+ * Currently, PT3 driver is the only one that uses this driver,
+ * and contains init/config code in its firmware.
+ * Thus some part of the code might be dependent on PT3 specific config.
+ */
+
+#include <linux/kernel.h>
+#include "mxl301rf.h"
+
+struct mxl301rf_state {
+       struct mxl301rf_config cfg;
+       struct i2c_client *i2c;
+};
+
+static struct mxl301rf_state *cfg_to_state(struct mxl301rf_config *c)
+{
+       return container_of(c, struct mxl301rf_state, cfg);
+}
+
+static int raw_write(struct mxl301rf_state *state, const u8 *buf, int len)
+{
+       int ret;
+
+       ret = i2c_master_send(state->i2c, buf, len);
+       if (ret >= 0 && ret < len)
+               ret = -EIO;
+       return (ret == len) ? 0 : ret;
+}
+
+static int reg_write(struct mxl301rf_state *state, u8 reg, u8 val)
+{
+       u8 buf[2] = { reg, val };
+
+       return raw_write(state, buf, 2);
+}
+
+static int reg_read(struct mxl301rf_state *state, u8 reg, u8 *val)
+{
+       u8 wbuf[2] = { 0xfb, reg };
+       int ret;
+
+       ret = raw_write(state, wbuf, sizeof(wbuf));
+       if (ret == 0)
+               ret = i2c_master_recv(state->i2c, val, 1);
+       if (ret >= 0 && ret < 1)
+               ret = -EIO;
+       return (ret == 1) ? 0 : ret;
+}
+
+/* tuner_ops */
+
+/* get RSSI and update propery cache, set to *out in % */
+static int mxl301rf_get_rf_strength(struct dvb_frontend *fe, u16 *out)
+{
+       struct mxl301rf_state *state;
+       int ret;
+       u8  rf_in1, rf_in2, rf_off1, rf_off2;
+       u16 rf_in, rf_off;
+       s64 level;
+       struct dtv_fe_stats *rssi;
+
+       rssi = &fe->dtv_property_cache.strength;
+       rssi->len = 1;
+       rssi->stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+       *out = 0;
+
+       state = fe->tuner_priv;
+       ret = reg_write(state, 0x14, 0x01);
+       if (ret < 0)
+               return ret;
+       usleep_range(1000, 2000);
+
+       ret = reg_read(state, 0x18, &rf_in1);
+       if (ret == 0)
+               ret = reg_read(state, 0x19, &rf_in2);
+       if (ret == 0)
+               ret = reg_read(state, 0xd6, &rf_off1);
+       if (ret == 0)
+               ret = reg_read(state, 0xd7, &rf_off2);
+       if (ret != 0)
+               return ret;
+
+       rf_in = (rf_in2 & 0x07) << 8 | rf_in1;
+       rf_off = (rf_off2 & 0x0f) << 5 | (rf_off1 >> 3);
+       level = rf_in - rf_off - (113 << 3); /* x8 dBm */
+       level = level * 1000 / 8;
+       rssi->stat[0].svalue = level;
+       rssi->stat[0].scale = FE_SCALE_DECIBEL;
+       /* *out = (level - min) * 100 / (max - min) */
+       *out = (rf_in - rf_off + (1 << 9) - 1) * 100 / ((5 << 9) - 2);
+       return 0;
+}
+
+/* spur shift parameters */
+struct shf {
+       u32     freq;           /* Channel center frequency */
+       u32     ofst_th;        /* Offset frequency threshold */
+       u8      shf_val;        /* Spur shift value */
+       u8      shf_dir;        /* Spur shift direction */
+};
+
+static const struct shf shf_tab[] = {
+       {  64500, 500, 0x92, 0x07 },
+       { 191500, 300, 0xe2, 0x07 },
+       { 205500, 500, 0x2c, 0x04 },
+       { 212500, 500, 0x1e, 0x04 },
+       { 226500, 500, 0xd4, 0x07 },
+       {  99143, 500, 0x9c, 0x07 },
+       { 173143, 500, 0xd4, 0x07 },
+       { 191143, 300, 0xd4, 0x07 },
+       { 207143, 500, 0xce, 0x07 },
+       { 225143, 500, 0xce, 0x07 },
+       { 243143, 500, 0xd4, 0x07 },
+       { 261143, 500, 0xd4, 0x07 },
+       { 291143, 500, 0xd4, 0x07 },
+       { 339143, 500, 0x2c, 0x04 },
+       { 117143, 500, 0x7a, 0x07 },
+       { 135143, 300, 0x7a, 0x07 },
+       { 153143, 500, 0x01, 0x07 }
+};
+
+struct reg_val {
+       u8 reg;
+       u8 val;
+} __attribute__ ((__packed__));
+
+static const struct reg_val set_idac[] = {
+       { 0x0d, 0x00 },
+       { 0x0c, 0x67 },
+       { 0x6f, 0x89 },
+       { 0x70, 0x0c },
+       { 0x6f, 0x8a },
+       { 0x70, 0x0e },
+       { 0x6f, 0x8b },
+       { 0x70, 0x1c },
+};
+
+static int mxl301rf_set_params(struct dvb_frontend *fe)
+{
+       struct reg_val tune0[] = {
+               { 0x13, 0x00 },         /* abort tuning */
+               { 0x3b, 0xc0 },
+               { 0x3b, 0x80 },
+               { 0x10, 0x95 },         /* BW */
+               { 0x1a, 0x05 },
+               { 0x61, 0x00 },         /* spur shift value (placeholder) */
+               { 0x62, 0xa0 }          /* spur shift direction (placeholder) */
+       };
+
+       struct reg_val tune1[] = {
+               { 0x11, 0x40 },         /* RF frequency L (placeholder) */
+               { 0x12, 0x0e },         /* RF frequency H (placeholder) */
+               { 0x13, 0x01 }          /* start tune */
+       };
+
+       struct mxl301rf_state *state;
+       u32 freq;
+       u16 f;
+       u32 tmp, div;
+       int i, ret;
+
+       state = fe->tuner_priv;
+       freq = fe->dtv_property_cache.frequency;
+
+       /* spur shift function (for analog) */
+       for (i = 0; i < ARRAY_SIZE(shf_tab); i++) {
+               if (freq >= (shf_tab[i].freq - shf_tab[i].ofst_th) * 1000 &&
+                   freq <= (shf_tab[i].freq + shf_tab[i].ofst_th) * 1000) {
+                       tune0[5].val = shf_tab[i].shf_val;
+                       tune0[6].val = 0xa0 | shf_tab[i].shf_dir;
+                       break;
+               }
+       }
+       ret = raw_write(state, (u8 *) tune0, sizeof(tune0));
+       if (ret < 0)
+               goto failed;
+       usleep_range(3000, 4000);
+
+       /* convert freq to 10.6 fixed point float [MHz] */
+       f = freq / 1000000;
+       tmp = freq % 1000000;
+       div = 1000000;
+       for (i = 0; i < 6; i++) {
+               f <<= 1;
+               div >>= 1;
+               if (tmp > div) {
+                       tmp -= div;
+                       f |= 1;
+               }
+       }
+       if (tmp > 7812)
+               f++;
+       tune1[0].val = f & 0xff;
+       tune1[1].val = f >> 8;
+       ret = raw_write(state, (u8 *) tune1, sizeof(tune1));
+       if (ret < 0)
+               goto failed;
+       msleep(31);
+
+       ret = reg_write(state, 0x1a, 0x0d);
+       if (ret < 0)
+               goto failed;
+       ret = raw_write(state, (u8 *) set_idac, sizeof(set_idac));
+       if (ret < 0)
+               goto failed;
+       return 0;
+
+failed:
+       dev_warn(&state->i2c->dev, "(%s) failed. [adap%d-fe%d]\n",
+               __func__, fe->dvb->num, fe->id);
+       return ret;
+}
+
+static const struct reg_val standby_data[] = {
+       { 0x01, 0x00 },
+       { 0x13, 0x00 }
+};
+
+static int mxl301rf_sleep(struct dvb_frontend *fe)
+{
+       struct mxl301rf_state *state;
+       int ret;
+
+       state = fe->tuner_priv;
+       ret = raw_write(state, (u8 *)standby_data, sizeof(standby_data));
+       if (ret < 0)
+               dev_warn(&state->i2c->dev, "(%s) failed. [adap%d-fe%d]\n",
+                       __func__, fe->dvb->num, fe->id);
+       return ret;
+}
+
+
+/* init sequence is not public.
+ * the parent must have init'ed the device.
+ * just wake up here.
+ */
+static int mxl301rf_init(struct dvb_frontend *fe)
+{
+       struct mxl301rf_state *state;
+       int ret;
+
+       state = fe->tuner_priv;
+
+       ret = reg_write(state, 0x01, 0x01);
+       if (ret < 0) {
+               dev_warn(&state->i2c->dev, "(%s) failed. [adap%d-fe%d]\n",
+                        __func__, fe->dvb->num, fe->id);
+               return ret;
+       }
+       return 0;
+}
+
+/* I2C driver functions */
+
+static const struct dvb_tuner_ops mxl301rf_ops = {
+       .info = {
+               .name = "MaxLinear MxL301RF",
+
+               .frequency_min =  93000000,
+               .frequency_max = 803142857,
+       },
+
+       .init = mxl301rf_init,
+       .sleep = mxl301rf_sleep,
+
+       .set_params = mxl301rf_set_params,
+       .get_rf_strength = mxl301rf_get_rf_strength,
+};
+
+
+static int mxl301rf_probe(struct i2c_client *client,
+                         const struct i2c_device_id *id)
+{
+       struct mxl301rf_state *state;
+       struct mxl301rf_config *cfg;
+       struct dvb_frontend *fe;
+
+       state = kzalloc(sizeof(*state), GFP_KERNEL);
+       if (!state)
+               return -ENOMEM;
+
+       state->i2c = client;
+       cfg = client->dev.platform_data;
+
+       memcpy(&state->cfg, cfg, sizeof(state->cfg));
+       fe = cfg->fe;
+       fe->tuner_priv = state;
+       memcpy(&fe->ops.tuner_ops, &mxl301rf_ops, sizeof(mxl301rf_ops));
+
+       i2c_set_clientdata(client, &state->cfg);
+       dev_info(&client->dev, "MaxLinear MxL301RF attached.\n");
+       return 0;
+}
+
+static int mxl301rf_remove(struct i2c_client *client)
+{
+       struct mxl301rf_state *state;
+
+       state = cfg_to_state(i2c_get_clientdata(client));
+       state->cfg.fe->tuner_priv = NULL;
+       kfree(state);
+       return 0;
+}
+
+
+static const struct i2c_device_id mxl301rf_id[] = {
+       {"mxl301rf", 0},
+       {}
+};
+MODULE_DEVICE_TABLE(i2c, mxl301rf_id);
+
+static struct i2c_driver mxl301rf_driver = {
+       .driver = {
+               .name   = "mxl301rf",
+       },
+       .probe          = mxl301rf_probe,
+       .remove         = mxl301rf_remove,
+       .id_table       = mxl301rf_id,
+};
+
+module_i2c_driver(mxl301rf_driver);
+
+MODULE_DESCRIPTION("MaxLinear MXL301RF tuner");
+MODULE_AUTHOR("Akihiro TSUKADA");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/tuners/mxl301rf.h b/drivers/media/tuners/mxl301rf.h
new file mode 100644 (file)
index 0000000..19e6840
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * MaxLinear MxL301RF OFDM tuner driver
+ *
+ * Copyright (C) 2014 Akihiro Tsukada <tskd08@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2.
+ *
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef MXL301RF_H
+#define MXL301RF_H
+
+#include "dvb_frontend.h"
+
+struct mxl301rf_config {
+       struct dvb_frontend *fe;
+};
+
+#endif /* MXL301RF_H */
index b473b76cb278b52f316cdb6249cba5da667e7d41..92a3be4fde870be4707ab5b8b3cecb8c734d635a 100644 (file)
@@ -1692,7 +1692,6 @@ static u16 MXL5005_TunerConfig(struct dvb_frontend *fe,
        )
 {
        struct mxl5005s_state *state = fe->tuner_priv;
-       u16 status = 0;
 
        state->Mode = Mode;
        state->IF_Mode = IF_mode;
@@ -1715,7 +1714,7 @@ static u16 MXL5005_TunerConfig(struct dvb_frontend *fe,
        /* Synthesizer LO frequency calculation */
        MXL_SynthIFLO_Calc(fe);
 
-       return status;
+       return 0;
 }
 
 static void MXL_SynthIFLO_Calc(struct dvb_frontend *fe)
diff --git a/drivers/media/tuners/qm1d1c0042.c b/drivers/media/tuners/qm1d1c0042.c
new file mode 100644 (file)
index 0000000..18bc745
--- /dev/null
@@ -0,0 +1,448 @@
+/*
+ * Sharp QM1D1C0042 8PSK tuner driver
+ *
+ * Copyright (C) 2014 Akihiro Tsukada <tskd08@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2.
+ *
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+/*
+ * NOTICE:
+ * As the disclosed information on the chip is very limited,
+ * this driver lacks some features, including chip config like IF freq.
+ * It assumes that users of this driver (such as a PCI bridge of
+ * DTV receiver cards) know the relevant info and
+ * configure the chip via I2C if necessary.
+ *
+ * Currently, PT3 driver is the only one that uses this driver,
+ * and contains init/config code in its firmware.
+ * Thus some part of the code might be dependent on PT3 specific config.
+ */
+
+#include <linux/kernel.h>
+#include <linux/math64.h>
+#include "qm1d1c0042.h"
+
+#define QM1D1C0042_NUM_REGS 0x20
+
+static const u8 reg_initval[QM1D1C0042_NUM_REGS] = {
+       0x48, 0x1c, 0xa0, 0x10, 0xbc, 0xc5, 0x20, 0x33,
+       0x06, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
+       0x00, 0xff, 0xf3, 0x00, 0x2a, 0x64, 0xa6, 0x86,
+       0x8c, 0xcf, 0xb8, 0xf1, 0xa8, 0xf2, 0x89, 0x00
+};
+
+static const struct qm1d1c0042_config default_cfg = {
+       .xtal_freq = 16000,
+       .lpf = 1,
+       .fast_srch = 0,
+       .lpf_wait = 20,
+       .fast_srch_wait = 4,
+       .normal_srch_wait = 15,
+};
+
+struct qm1d1c0042_state {
+       struct qm1d1c0042_config cfg;
+       struct i2c_client *i2c;
+       u8 regs[QM1D1C0042_NUM_REGS];
+};
+
+static struct qm1d1c0042_state *cfg_to_state(struct qm1d1c0042_config *c)
+{
+       return container_of(c, struct qm1d1c0042_state, cfg);
+}
+
+static int reg_write(struct qm1d1c0042_state *state, u8 reg, u8 val)
+{
+       u8 wbuf[2] = { reg, val };
+       int ret;
+
+       ret = i2c_master_send(state->i2c, wbuf, sizeof(wbuf));
+       if (ret >= 0 && ret < sizeof(wbuf))
+               ret = -EIO;
+       return (ret == sizeof(wbuf)) ? 0 : ret;
+}
+
+static int reg_read(struct qm1d1c0042_state *state, u8 reg, u8 *val)
+{
+       struct i2c_msg msgs[2] = {
+               {
+                       .addr = state->i2c->addr,
+                       .flags = 0,
+                       .buf = &reg,
+                       .len = 1,
+               },
+               {
+                       .addr = state->i2c->addr,
+                       .flags = I2C_M_RD,
+                       .buf = val,
+                       .len = 1,
+               },
+       };
+       int ret;
+
+       ret = i2c_transfer(state->i2c->adapter, msgs, ARRAY_SIZE(msgs));
+       if (ret >= 0 && ret < ARRAY_SIZE(msgs))
+               ret = -EIO;
+       return (ret == ARRAY_SIZE(msgs)) ? 0 : ret;
+}
+
+
+static int qm1d1c0042_set_srch_mode(struct qm1d1c0042_state *state, bool fast)
+{
+       if (fast)
+               state->regs[0x03] |= 0x01; /* set fast search mode */
+       else
+               state->regs[0x03] &= ~0x01 & 0xff;
+
+       return reg_write(state, 0x03, state->regs[0x03]);
+}
+
+static int qm1d1c0042_wakeup(struct qm1d1c0042_state *state)
+{
+       int ret;
+
+       state->regs[0x01] |= 1 << 3;             /* BB_Reg_enable */
+       state->regs[0x01] &= (~(1 << 0)) & 0xff; /* NORMAL (wake-up) */
+       state->regs[0x05] &= (~(1 << 3)) & 0xff; /* pfd_rst NORMAL */
+       ret = reg_write(state, 0x01, state->regs[0x01]);
+       if (ret == 0)
+               ret = reg_write(state, 0x05, state->regs[0x05]);
+
+       if (ret < 0)
+               dev_warn(&state->i2c->dev, "(%s) failed. [adap%d-fe%d]\n",
+                       __func__, state->cfg.fe->dvb->num, state->cfg.fe->id);
+       return ret;
+}
+
+/* tuner_ops */
+
+static int qm1d1c0042_set_config(struct dvb_frontend *fe, void *priv_cfg)
+{
+       struct qm1d1c0042_state *state;
+       struct qm1d1c0042_config *cfg;
+
+       state = fe->tuner_priv;
+       cfg = priv_cfg;
+
+       if (cfg->fe)
+               state->cfg.fe = cfg->fe;
+
+       if (cfg->xtal_freq != QM1D1C0042_CFG_XTAL_DFLT)
+               dev_warn(&state->i2c->dev,
+                       "(%s) changing xtal_freq not supported. ", __func__);
+       state->cfg.xtal_freq = default_cfg.xtal_freq;
+
+       state->cfg.lpf = cfg->lpf;
+       state->cfg.fast_srch = cfg->fast_srch;
+
+       if (cfg->lpf_wait != QM1D1C0042_CFG_WAIT_DFLT)
+               state->cfg.lpf_wait = cfg->lpf_wait;
+       else
+               state->cfg.lpf_wait = default_cfg.lpf_wait;
+
+       if (cfg->fast_srch_wait != QM1D1C0042_CFG_WAIT_DFLT)
+               state->cfg.fast_srch_wait = cfg->fast_srch_wait;
+       else
+               state->cfg.fast_srch_wait = default_cfg.fast_srch_wait;
+
+       if (cfg->normal_srch_wait != QM1D1C0042_CFG_WAIT_DFLT)
+               state->cfg.normal_srch_wait = cfg->normal_srch_wait;
+       else
+               state->cfg.normal_srch_wait = default_cfg.normal_srch_wait;
+       return 0;
+}
+
+/* divisor, vco_band parameters */
+/*  {maxfreq,  param1(band?), param2(div?) */
+static const u32 conv_table[9][3] = {
+       { 2151000, 1, 7 },
+       { 1950000, 1, 6 },
+       { 1800000, 1, 5 },
+       { 1600000, 1, 4 },
+       { 1450000, 1, 3 },
+       { 1250000, 1, 2 },
+       { 1200000, 0, 7 },
+       {  975000, 0, 6 },
+       {  950000, 0, 0 }
+};
+
+static int qm1d1c0042_set_params(struct dvb_frontend *fe)
+{
+       struct qm1d1c0042_state *state;
+       u32 freq;
+       int i, ret;
+       u8 val, mask;
+       u32 a, sd;
+       s32 b;
+
+       state = fe->tuner_priv;
+       freq = fe->dtv_property_cache.frequency;
+
+       state->regs[0x08] &= 0xf0;
+       state->regs[0x08] |= 0x09;
+
+       state->regs[0x13] &= 0x9f;
+       state->regs[0x13] |= 0x20;
+
+       /* div2/vco_band */
+       val = state->regs[0x02] & 0x0f;
+       for (i = 0; i < 8; i++)
+               if (freq < conv_table[i][0] && freq >= conv_table[i + 1][0]) {
+                       val |= conv_table[i][1] << 7;
+                       val |= conv_table[i][2] << 4;
+                       break;
+               }
+       ret = reg_write(state, 0x02, val);
+       if (ret < 0)
+               return ret;
+
+       a = (freq + state->cfg.xtal_freq / 2) / state->cfg.xtal_freq;
+
+       state->regs[0x06] &= 0x40;
+       state->regs[0x06] |= (a - 12) / 4;
+       ret = reg_write(state, 0x06, state->regs[0x06]);
+       if (ret < 0)
+               return ret;
+
+       state->regs[0x07] &= 0xf0;
+       state->regs[0x07] |= (a - 4 * ((a - 12) / 4 + 1) - 5) & 0x0f;
+       ret = reg_write(state, 0x07, state->regs[0x07]);
+       if (ret < 0)
+               return ret;
+
+       /* LPF */
+       val = state->regs[0x08];
+       if (state->cfg.lpf) {
+               /* LPF_CLK, LPF_FC */
+               val &= 0xf0;
+               val |= 0x02;
+       }
+       ret = reg_write(state, 0x08, val);
+       if (ret < 0)
+               return ret;
+
+       /*
+        * b = (freq / state->cfg.xtal_freq - a) << 20;
+        * sd = b          (b >= 0)
+        *      1<<22 + b  (b < 0)
+        */
+       b = (s32)div64_s64(((s64) freq) << 20, state->cfg.xtal_freq)
+                          - (((s64) a) << 20);
+
+       if (b >= 0)
+               sd = b;
+       else
+               sd = (1 << 22) + b;
+
+       state->regs[0x09] &= 0xc0;
+       state->regs[0x09] |= (sd >> 16) & 0x3f;
+       state->regs[0x0a] = (sd >> 8) & 0xff;
+       state->regs[0x0b] = sd & 0xff;
+       ret = reg_write(state, 0x09, state->regs[0x09]);
+       if (ret == 0)
+               ret = reg_write(state, 0x0a, state->regs[0x0a]);
+       if (ret == 0)
+               ret = reg_write(state, 0x0b, state->regs[0x0b]);
+       if (ret != 0)
+               return ret;
+
+       if (!state->cfg.lpf) {
+               /* CSEL_Offset */
+               ret = reg_write(state, 0x13, state->regs[0x13]);
+               if (ret < 0)
+                       return ret;
+       }
+
+       /* VCO_TM, LPF_TM */
+       mask = state->cfg.lpf ? 0x3f : 0x7f;
+       val = state->regs[0x0c] & mask;
+       ret = reg_write(state, 0x0c, val);
+       if (ret < 0)
+               return ret;
+       usleep_range(2000, 3000);
+       val = state->regs[0x0c] | ~mask;
+       ret = reg_write(state, 0x0c, val);
+       if (ret < 0)
+               return ret;
+
+       if (state->cfg.lpf)
+               msleep(state->cfg.lpf_wait);
+       else if (state->regs[0x03] & 0x01)
+               msleep(state->cfg.fast_srch_wait);
+       else
+               msleep(state->cfg.normal_srch_wait);
+
+       if (state->cfg.lpf) {
+               /* LPF_FC */
+               ret = reg_write(state, 0x08, 0x09);
+               if (ret < 0)
+                       return ret;
+
+               /* CSEL_Offset */
+               ret = reg_write(state, 0x13, state->regs[0x13]);
+               if (ret < 0)
+                       return ret;
+       }
+       return 0;
+}
+
+static int qm1d1c0042_sleep(struct dvb_frontend *fe)
+{
+       struct qm1d1c0042_state *state;
+       int ret;
+
+       state = fe->tuner_priv;
+       state->regs[0x01] &= (~(1 << 3)) & 0xff; /* BB_Reg_disable */
+       state->regs[0x01] |= 1 << 0;             /* STDBY */
+       state->regs[0x05] |= 1 << 3;             /* pfd_rst STANDBY */
+       ret = reg_write(state, 0x05, state->regs[0x05]);
+       if (ret == 0)
+               ret = reg_write(state, 0x01, state->regs[0x01]);
+       if (ret < 0)
+               dev_warn(&state->i2c->dev, "(%s) failed. [adap%d-fe%d]\n",
+                       __func__, fe->dvb->num, fe->id);
+       return ret;
+}
+
+static int qm1d1c0042_init(struct dvb_frontend *fe)
+{
+       struct qm1d1c0042_state *state;
+       u8 val;
+       int i, ret;
+
+       state = fe->tuner_priv;
+       memcpy(state->regs, reg_initval, sizeof(reg_initval));
+
+       reg_write(state, 0x01, 0x0c);
+       reg_write(state, 0x01, 0x0c);
+
+       ret = reg_write(state, 0x01, 0x0c); /* soft reset on */
+       if (ret < 0)
+               goto failed;
+       usleep_range(2000, 3000);
+
+       val = state->regs[0x01] | 0x10;
+       ret = reg_write(state, 0x01, val); /* soft reset off */
+       if (ret < 0)
+               goto failed;
+
+       /* check ID */
+       ret = reg_read(state, 0x00, &val);
+       if (ret < 0 || val != 0x48)
+               goto failed;
+       usleep_range(2000, 3000);
+
+       state->regs[0x0c] |= 0x40;
+       ret = reg_write(state, 0x0c, state->regs[0x0c]);
+       if (ret < 0)
+               goto failed;
+       msleep(state->cfg.lpf_wait);
+
+       /* set all writable registers */
+       for (i = 1; i <= 0x0c ; i++) {
+               ret = reg_write(state, i, state->regs[i]);
+               if (ret < 0)
+                       goto failed;
+       }
+       for (i = 0x11; i < QM1D1C0042_NUM_REGS; i++) {
+               ret = reg_write(state, i, state->regs[i]);
+               if (ret < 0)
+                       goto failed;
+       }
+
+       ret = qm1d1c0042_wakeup(state);
+       if (ret < 0)
+               goto failed;
+
+       ret = qm1d1c0042_set_srch_mode(state, state->cfg.fast_srch);
+       if (ret < 0)
+               goto failed;
+
+       return ret;
+
+failed:
+       dev_warn(&state->i2c->dev, "(%s) failed. [adap%d-fe%d]\n",
+               __func__, fe->dvb->num, fe->id);
+       return ret;
+}
+
+/* I2C driver functions */
+
+static const struct dvb_tuner_ops qm1d1c0042_ops = {
+       .info = {
+               .name = "Sharp QM1D1C0042",
+
+               .frequency_min =  950000,
+               .frequency_max = 2150000,
+       },
+
+       .init = qm1d1c0042_init,
+       .sleep = qm1d1c0042_sleep,
+       .set_config = qm1d1c0042_set_config,
+       .set_params = qm1d1c0042_set_params,
+};
+
+
+static int qm1d1c0042_probe(struct i2c_client *client,
+                           const struct i2c_device_id *id)
+{
+       struct qm1d1c0042_state *state;
+       struct qm1d1c0042_config *cfg;
+       struct dvb_frontend *fe;
+
+       state = kzalloc(sizeof(*state), GFP_KERNEL);
+       if (!state)
+               return -ENOMEM;
+       state->i2c = client;
+
+       cfg = client->dev.platform_data;
+       fe = cfg->fe;
+       fe->tuner_priv = state;
+       qm1d1c0042_set_config(fe, cfg);
+       memcpy(&fe->ops.tuner_ops, &qm1d1c0042_ops, sizeof(qm1d1c0042_ops));
+
+       i2c_set_clientdata(client, &state->cfg);
+       dev_info(&client->dev, "Sharp QM1D1C0042 attached.\n");
+       return 0;
+}
+
+static int qm1d1c0042_remove(struct i2c_client *client)
+{
+       struct qm1d1c0042_state *state;
+
+       state = cfg_to_state(i2c_get_clientdata(client));
+       state->cfg.fe->tuner_priv = NULL;
+       kfree(state);
+       return 0;
+}
+
+
+static const struct i2c_device_id qm1d1c0042_id[] = {
+       {"qm1d1c0042", 0},
+       {}
+};
+MODULE_DEVICE_TABLE(i2c, qm1d1c0042_id);
+
+static struct i2c_driver qm1d1c0042_driver = {
+       .driver = {
+               .name   = "qm1d1c0042",
+       },
+       .probe          = qm1d1c0042_probe,
+       .remove         = qm1d1c0042_remove,
+       .id_table       = qm1d1c0042_id,
+};
+
+module_i2c_driver(qm1d1c0042_driver);
+
+MODULE_DESCRIPTION("Sharp QM1D1C0042 tuner");
+MODULE_AUTHOR("Akihiro TSUKADA");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/tuners/qm1d1c0042.h b/drivers/media/tuners/qm1d1c0042.h
new file mode 100644 (file)
index 0000000..4f5c188
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * Sharp QM1D1C0042 8PSK tuner driver
+ *
+ * Copyright (C) 2014 Akihiro Tsukada <tskd08@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2.
+ *
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef QM1D1C0042_H
+#define QM1D1C0042_H
+
+#include "dvb_frontend.h"
+
+
+struct qm1d1c0042_config {
+       struct dvb_frontend *fe;
+
+       u32  xtal_freq;    /* [kHz] */ /* currently ignored */
+       bool lpf;          /* enable LPF */
+       bool fast_srch;    /* enable fast search mode, no LPF */
+       u32  lpf_wait;         /* wait in tuning with LPF enabled. [ms] */
+       u32  fast_srch_wait;   /* with fast-search mode, no LPF. [ms] */
+       u32  normal_srch_wait; /* with no LPF/fast-search mode. [ms] */
+};
+/* special values indicating to use the default in qm1d1c0042_config */
+#define QM1D1C0042_CFG_XTAL_DFLT 0
+#define QM1D1C0042_CFG_WAIT_DFLT 0
+
+#endif /* QM1D1C0042_H */
index 6c53edb73a632ed0c43ade3acf363c9b580bff3d..cf97142e01e6a34c3ebd30cf6e143c5599dab919 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Silicon Labs Si2157/2158 silicon tuner driver
+ * Silicon Labs Si2147/2157/2158 silicon tuner driver
  *
  * Copyright (C) 2014 Antti Palosaari <crope@iki.fi>
  *
@@ -55,8 +55,7 @@ static int si2157_cmd_execute(struct si2157 *s, struct si2157_cmd *cmd)
                                break;
                }
 
-               dev_dbg(&s->client->dev, "%s: cmd execution took %d ms\n",
-                               __func__,
+               dev_dbg(&s->client->dev, "cmd execution took %d ms\n",
                                jiffies_to_msecs(jiffies) -
                                (jiffies_to_msecs(timeout) - TIMEOUT));
 
@@ -75,7 +74,7 @@ err_mutex_unlock:
 
        return 0;
 err:
-       dev_dbg(&s->client->dev, "%s: failed=%d\n", __func__, ret);
+       dev_dbg(&s->client->dev, "failed=%d\n", ret);
        return ret;
 }
 
@@ -88,9 +87,12 @@ static int si2157_init(struct dvb_frontend *fe)
        u8 *fw_file;
        unsigned int chip_id;
 
-       dev_dbg(&s->client->dev, "%s:\n", __func__);
+       dev_dbg(&s->client->dev, "\n");
 
-       /* configure? */
+       if (s->fw_loaded)
+               goto warm;
+
+       /* power up */
        memcpy(cmd.args, "\xc0\x00\x0c\x00\x00\x01\x01\x01\x01\x01\x01\x02\x00\x00\x01", 15);
        cmd.wlen = 15;
        cmd.rlen = 1;
@@ -111,45 +113,47 @@ static int si2157_init(struct dvb_frontend *fe)
 
        #define SI2158_A20 ('A' << 24 | 58 << 16 | '2' << 8 | '0' << 0)
        #define SI2157_A30 ('A' << 24 | 57 << 16 | '3' << 8 | '0' << 0)
+       #define SI2147_A30 ('A' << 24 | 47 << 16 | '3' << 8 | '0' << 0)
 
        switch (chip_id) {
        case SI2158_A20:
                fw_file = SI2158_A20_FIRMWARE;
                break;
        case SI2157_A30:
+       case SI2147_A30:
                goto skip_fw_download;
                break;
        default:
                dev_err(&s->client->dev,
-                               "%s: unkown chip version Si21%d-%c%c%c\n",
-                               KBUILD_MODNAME, cmd.args[2], cmd.args[1],
+                               "unknown chip version Si21%d-%c%c%c\n",
+                               cmd.args[2], cmd.args[1],
                                cmd.args[3], cmd.args[4]);
                ret = -EINVAL;
                goto err;
        }
 
        /* cold state - try to download firmware */
-       dev_info(&s->client->dev, "%s: found a '%s' in cold state\n",
-                       KBUILD_MODNAME, si2157_ops.info.name);
+       dev_info(&s->client->dev, "found a '%s' in cold state\n",
+                       si2157_ops.info.name);
 
        /* request the firmware, this will block and timeout */
        ret = request_firmware(&fw, fw_file, &s->client->dev);
        if (ret) {
-               dev_err(&s->client->dev, "%s: firmware file '%s' not found\n",
-                               KBUILD_MODNAME, fw_file);
+               dev_err(&s->client->dev, "firmware file '%s' not found\n",
+                               fw_file);
                goto err;
        }
 
        /* firmware should be n chunks of 17 bytes */
        if (fw->size % 17 != 0) {
-               dev_err(&s->client->dev, "%s: firmware file '%s' is invalid\n",
-                               KBUILD_MODNAME, fw_file);
+               dev_err(&s->client->dev, "firmware file '%s' is invalid\n",
+                               fw_file);
                ret = -EINVAL;
                goto err;
        }
 
-       dev_info(&s->client->dev, "%s: downloading firmware from file '%s'\n",
-                       KBUILD_MODNAME, fw_file);
+       dev_info(&s->client->dev, "downloading firmware from file '%s'\n",
+                       fw_file);
 
        for (remaining = fw->size; remaining > 0; remaining -= 17) {
                len = fw->data[fw->size - remaining];
@@ -159,8 +163,8 @@ static int si2157_init(struct dvb_frontend *fe)
                ret = si2157_cmd_execute(s, &cmd);
                if (ret) {
                        dev_err(&s->client->dev,
-                                       "%s: firmware download failed=%d\n",
-                                       KBUILD_MODNAME, ret);
+                                       "firmware download failed=%d\n",
+                                       ret);
                        goto err;
                }
        }
@@ -177,14 +181,17 @@ skip_fw_download:
        if (ret)
                goto err;
 
-       s->active = true;
+       s->fw_loaded = true;
 
+warm:
+       s->active = true;
        return 0;
+
 err:
        if (fw)
                release_firmware(fw);
 
-       dev_dbg(&s->client->dev, "%s: failed=%d\n", __func__, ret);
+       dev_dbg(&s->client->dev, "failed=%d\n", ret);
        return ret;
 }
 
@@ -194,20 +201,21 @@ static int si2157_sleep(struct dvb_frontend *fe)
        int ret;
        struct si2157_cmd cmd;
 
-       dev_dbg(&s->client->dev, "%s:\n", __func__);
+       dev_dbg(&s->client->dev, "\n");
 
        s->active = false;
 
-       memcpy(cmd.args, "\x13", 1);
-       cmd.wlen = 1;
-       cmd.rlen = 0;
+       /* standby */
+       memcpy(cmd.args, "\x16\x00", 2);
+       cmd.wlen = 2;
+       cmd.rlen = 1;
        ret = si2157_cmd_execute(s, &cmd);
        if (ret)
                goto err;
 
        return 0;
 err:
-       dev_dbg(&s->client->dev, "%s: failed=%d\n", __func__, ret);
+       dev_dbg(&s->client->dev, "failed=%d\n", ret);
        return ret;
 }
 
@@ -220,8 +228,8 @@ static int si2157_set_params(struct dvb_frontend *fe)
        u8 bandwidth, delivery_system;
 
        dev_dbg(&s->client->dev,
-                       "%s: delivery_system=%d frequency=%u bandwidth_hz=%u\n",
-                       __func__, c->delivery_system, c->frequency,
+                       "delivery_system=%d frequency=%u bandwidth_hz=%u\n",
+                       c->delivery_system, c->frequency,
                        c->bandwidth_hz);
 
        if (!s->active) {
@@ -239,6 +247,9 @@ static int si2157_set_params(struct dvb_frontend *fe)
                bandwidth = 0x0f;
 
        switch (c->delivery_system) {
+       case SYS_ATSC:
+                       delivery_system = 0x00;
+                       break;
        case SYS_DVBT:
        case SYS_DVBT2: /* it seems DVB-T and DVB-T2 both are 0x20 here */
                        delivery_system = 0x20;
@@ -256,7 +267,14 @@ static int si2157_set_params(struct dvb_frontend *fe)
        if (s->inversion)
                cmd.args[5] = 0x01;
        cmd.wlen = 6;
-       cmd.rlen = 1;
+       cmd.rlen = 4;
+       ret = si2157_cmd_execute(s, &cmd);
+       if (ret)
+               goto err;
+
+       memcpy(cmd.args, "\x14\x00\x02\x07\x01\x00", 6);
+       cmd.wlen = 6;
+       cmd.rlen = 4;
        ret = si2157_cmd_execute(s, &cmd);
        if (ret)
                goto err;
@@ -275,7 +293,7 @@ static int si2157_set_params(struct dvb_frontend *fe)
 
        return 0;
 err:
-       dev_dbg(&s->client->dev, "%s: failed=%d\n", __func__, ret);
+       dev_dbg(&s->client->dev, "failed=%d\n", ret);
        return ret;
 }
 
@@ -310,13 +328,14 @@ static int si2157_probe(struct i2c_client *client,
        s = kzalloc(sizeof(struct si2157), GFP_KERNEL);
        if (!s) {
                ret = -ENOMEM;
-               dev_err(&client->dev, "%s: kzalloc() failed\n", KBUILD_MODNAME);
+               dev_err(&client->dev, "kzalloc() failed\n");
                goto err;
        }
 
        s->client = client;
        s->fe = cfg->fe;
        s->inversion = cfg->inversion;
+       s->fw_loaded = false;
        mutex_init(&s->i2c_mutex);
 
        /* check if the tuner is there */
@@ -333,11 +352,10 @@ static int si2157_probe(struct i2c_client *client,
        i2c_set_clientdata(client, s);
 
        dev_info(&s->client->dev,
-                       "%s: Silicon Labs Si2157/Si2158 successfully attached\n",
-                       KBUILD_MODNAME);
+                       "Silicon Labs Si2157/Si2158 successfully attached\n");
        return 0;
 err:
-       dev_dbg(&client->dev, "%s: failed=%d\n", __func__, ret);
+       dev_dbg(&client->dev, "failed=%d\n", ret);
        kfree(s);
 
        return ret;
@@ -348,7 +366,7 @@ static int si2157_remove(struct i2c_client *client)
        struct si2157 *s = i2c_get_clientdata(client);
        struct dvb_frontend *fe = s->fe;
 
-       dev_dbg(&client->dev, "%s:\n", __func__);
+       dev_dbg(&client->dev, "\n");
 
        memset(&fe->ops.tuner_ops, 0, sizeof(struct dvb_tuner_ops));
        fe->tuner_priv = NULL;
index 6da4d5d1c8178b25ad5e3965e5a90b06dbd2865f..d3b19cadb4a16d04fa83fbafd7e483514bfc6e1e 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Silicon Labs Si2157/2158 silicon tuner driver
+ * Silicon Labs Si2147/2157/2158 silicon tuner driver
  *
  * Copyright (C) 2014 Antti Palosaari <crope@iki.fi>
  *
index 3ddab5e6b50038cbb9034f556fb6f77edec5308f..e71ffafed951b804f7a272a5ecc12795e86f30d5 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Silicon Labs Si2157/2158 silicon tuner driver
+ * Silicon Labs Si2147/2157/2158 silicon tuner driver
  *
  * Copyright (C) 2014 Antti Palosaari <crope@iki.fi>
  *
@@ -26,6 +26,7 @@ struct si2157 {
        struct i2c_client *client;
        struct dvb_frontend *fe;
        bool active;
+       bool fw_loaded;
        bool inversion;
 };
 
index 05a4ac9edb6b0559eedde3f39273bb958df9cfd8..d93e0667b46b65b78d67105f8acd7ffe929863d5 100644 (file)
  */
 
 #include "tda18212.h"
+#include <linux/regmap.h>
 
-/* Max transfer size done by I2C transfer functions */
-#define MAX_XFER_SIZE  64
-
-struct tda18212_priv {
-       struct tda18212_config *cfg;
-       struct i2c_adapter *i2c;
+struct tda18212_dev {
+       struct tda18212_config cfg;
+       struct i2c_client *client;
+       struct regmap *regmap;
 
        u32 if_frequency;
 };
 
-/* write multiple registers */
-static int tda18212_wr_regs(struct tda18212_priv *priv, u8 reg, u8 *val,
-       int len)
-{
-       int ret;
-       u8 buf[MAX_XFER_SIZE];
-       struct i2c_msg msg[1] = {
-               {
-                       .addr = priv->cfg->i2c_address,
-                       .flags = 0,
-                       .len = 1 + len,
-                       .buf = buf,
-               }
-       };
-
-       if (1 + len > sizeof(buf)) {
-               dev_warn(&priv->i2c->dev,
-                        "%s: i2c wr reg=%04x: len=%d is too big!\n",
-                        KBUILD_MODNAME, reg, len);
-               return -EINVAL;
-       }
-
-       buf[0] = reg;
-       memcpy(&buf[1], val, len);
-
-       ret = i2c_transfer(priv->i2c, msg, 1);
-       if (ret == 1) {
-               ret = 0;
-       } else {
-               dev_warn(&priv->i2c->dev, "%s: i2c wr failed=%d reg=%02x " \
-                               "len=%d\n", KBUILD_MODNAME, ret, reg, len);
-               ret = -EREMOTEIO;
-       }
-       return ret;
-}
-
-/* read multiple registers */
-static int tda18212_rd_regs(struct tda18212_priv *priv, u8 reg, u8 *val,
-       int len)
-{
-       int ret;
-       u8 buf[MAX_XFER_SIZE];
-       struct i2c_msg msg[2] = {
-               {
-                       .addr = priv->cfg->i2c_address,
-                       .flags = 0,
-                       .len = 1,
-                       .buf = &reg,
-               }, {
-                       .addr = priv->cfg->i2c_address,
-                       .flags = I2C_M_RD,
-                       .len = len,
-                       .buf = buf,
-               }
-       };
-
-       if (len > sizeof(buf)) {
-               dev_warn(&priv->i2c->dev,
-                        "%s: i2c rd reg=%04x: len=%d is too big!\n",
-                        KBUILD_MODNAME, reg, len);
-               return -EINVAL;
-       }
-
-       ret = i2c_transfer(priv->i2c, msg, 2);
-       if (ret == 2) {
-               memcpy(val, buf, len);
-               ret = 0;
-       } else {
-               dev_warn(&priv->i2c->dev, "%s: i2c rd failed=%d reg=%02x " \
-                               "len=%d\n", KBUILD_MODNAME, ret, reg, len);
-               ret = -EREMOTEIO;
-       }
-
-       return ret;
-}
-
-/* write single register */
-static int tda18212_wr_reg(struct tda18212_priv *priv, u8 reg, u8 val)
-{
-       return tda18212_wr_regs(priv, reg, &val, 1);
-}
-
-/* read single register */
-static int tda18212_rd_reg(struct tda18212_priv *priv, u8 reg, u8 *val)
-{
-       return tda18212_rd_regs(priv, reg, val, 1);
-}
-
-#if 0 /* keep, useful when developing driver */
-static void tda18212_dump_regs(struct tda18212_priv *priv)
-{
-       int i;
-       u8 buf[256];
-
-       #define TDA18212_RD_LEN 32
-       for (i = 0; i < sizeof(buf); i += TDA18212_RD_LEN)
-               tda18212_rd_regs(priv, i, &buf[i], TDA18212_RD_LEN);
-
-       print_hex_dump(KERN_INFO, "", DUMP_PREFIX_OFFSET, 32, 1, buf,
-               sizeof(buf), true);
-
-       return;
-}
-#endif
-
 static int tda18212_set_params(struct dvb_frontend *fe)
 {
-       struct tda18212_priv *priv = fe->tuner_priv;
+       struct tda18212_dev *dev = fe->tuner_priv;
        struct dtv_frontend_properties *c = &fe->dtv_property_cache;
        int ret, i;
        u32 if_khz;
@@ -166,9 +60,9 @@ static int tda18212_set_params(struct dvb_frontend *fe)
                [ATSC_QAM] = { 0x7d, 0x20, 0x63 },
        };
 
-       dev_dbg(&priv->i2c->dev,
-                       "%s: delivery_system=%d frequency=%d bandwidth_hz=%d\n",
-                       __func__, c->delivery_system, c->frequency,
+       dev_dbg(&dev->client->dev,
+                       "delivery_system=%d frequency=%d bandwidth_hz=%d\n",
+                       c->delivery_system, c->frequency,
                        c->bandwidth_hz);
 
        if (fe->ops.i2c_gate_ctrl)
@@ -176,25 +70,25 @@ static int tda18212_set_params(struct dvb_frontend *fe)
 
        switch (c->delivery_system) {
        case SYS_ATSC:
-               if_khz = priv->cfg->if_atsc_vsb;
+               if_khz = dev->cfg.if_atsc_vsb;
                i = ATSC_VSB;
                break;
        case SYS_DVBC_ANNEX_B:
-               if_khz = priv->cfg->if_atsc_qam;
+               if_khz = dev->cfg.if_atsc_qam;
                i = ATSC_QAM;
                break;
        case SYS_DVBT:
                switch (c->bandwidth_hz) {
                case 6000000:
-                       if_khz = priv->cfg->if_dvbt_6;
+                       if_khz = dev->cfg.if_dvbt_6;
                        i = DVBT_6;
                        break;
                case 7000000:
-                       if_khz = priv->cfg->if_dvbt_7;
+                       if_khz = dev->cfg.if_dvbt_7;
                        i = DVBT_7;
                        break;
                case 8000000:
-                       if_khz = priv->cfg->if_dvbt_8;
+                       if_khz = dev->cfg.if_dvbt_8;
                        i = DVBT_8;
                        break;
                default:
@@ -205,15 +99,15 @@ static int tda18212_set_params(struct dvb_frontend *fe)
        case SYS_DVBT2:
                switch (c->bandwidth_hz) {
                case 6000000:
-                       if_khz = priv->cfg->if_dvbt2_6;
+                       if_khz = dev->cfg.if_dvbt2_6;
                        i = DVBT2_6;
                        break;
                case 7000000:
-                       if_khz = priv->cfg->if_dvbt2_7;
+                       if_khz = dev->cfg.if_dvbt2_7;
                        i = DVBT2_7;
                        break;
                case 8000000:
-                       if_khz = priv->cfg->if_dvbt2_8;
+                       if_khz = dev->cfg.if_dvbt2_8;
                        i = DVBT2_8;
                        break;
                default:
@@ -223,7 +117,7 @@ static int tda18212_set_params(struct dvb_frontend *fe)
                break;
        case SYS_DVBC_ANNEX_A:
        case SYS_DVBC_ANNEX_C:
-               if_khz = priv->cfg->if_dvbc;
+               if_khz = dev->cfg.if_dvbc;
                i = DVBC_8;
                break;
        default:
@@ -231,15 +125,15 @@ static int tda18212_set_params(struct dvb_frontend *fe)
                goto error;
        }
 
-       ret = tda18212_wr_reg(priv, 0x23, bw_params[i][2]);
+       ret = regmap_write(dev->regmap, 0x23, bw_params[i][2]);
        if (ret)
                goto error;
 
-       ret = tda18212_wr_reg(priv, 0x06, 0x00);
+       ret = regmap_write(dev->regmap, 0x06, 0x00);
        if (ret)
                goto error;
 
-       ret = tda18212_wr_reg(priv, 0x0f, bw_params[i][0]);
+       ret = regmap_write(dev->regmap, 0x0f, bw_params[i][0]);
        if (ret)
                goto error;
 
@@ -252,12 +146,12 @@ static int tda18212_set_params(struct dvb_frontend *fe)
        buf[6] = ((c->frequency / 1000) >>  0) & 0xff;
        buf[7] = 0xc1;
        buf[8] = 0x01;
-       ret = tda18212_wr_regs(priv, 0x12, buf, sizeof(buf));
+       ret = regmap_bulk_write(dev->regmap, 0x12, buf, sizeof(buf));
        if (ret)
                goto error;
 
        /* actual IF rounded as it is on register */
-       priv->if_frequency = buf[3] * 50 * 1000;
+       dev->if_frequency = buf[3] * 50 * 1000;
 
 exit:
        if (fe->ops.i2c_gate_ctrl)
@@ -266,26 +160,19 @@ exit:
        return ret;
 
 error:
-       dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret);
+       dev_dbg(&dev->client->dev, "failed=%d\n", ret);
        goto exit;
 }
 
 static int tda18212_get_if_frequency(struct dvb_frontend *fe, u32 *frequency)
 {
-       struct tda18212_priv *priv = fe->tuner_priv;
+       struct tda18212_dev *dev = fe->tuner_priv;
 
-       *frequency = priv->if_frequency;
+       *frequency = dev->if_frequency;
 
        return 0;
 }
 
-static int tda18212_release(struct dvb_frontend *fe)
-{
-       kfree(fe->tuner_priv);
-       fe->tuner_priv = NULL;
-       return 0;
-}
-
 static const struct dvb_tuner_ops tda18212_tuner_ops = {
        .info = {
                .name           = "NXP TDA18212",
@@ -295,53 +182,110 @@ static const struct dvb_tuner_ops tda18212_tuner_ops = {
                .frequency_step =      1000,
        },
 
-       .release       = tda18212_release,
-
        .set_params    = tda18212_set_params,
        .get_if_frequency = tda18212_get_if_frequency,
 };
 
-struct dvb_frontend *tda18212_attach(struct dvb_frontend *fe,
-       struct i2c_adapter *i2c, struct tda18212_config *cfg)
+static int tda18212_probe(struct i2c_client *client,
+               const struct i2c_device_id *id)
 {
-       struct tda18212_priv *priv = NULL;
+       struct tda18212_config *cfg = client->dev.platform_data;
+       struct dvb_frontend *fe = cfg->fe;
+       struct tda18212_dev *dev;
        int ret;
-       u8 val;
+       unsigned int chip_id;
+       char *version;
+       static const struct regmap_config regmap_config = {
+               .reg_bits = 8,
+               .val_bits = 8,
+       };
 
-       priv = kzalloc(sizeof(struct tda18212_priv), GFP_KERNEL);
-       if (priv == NULL)
-               return NULL;
+       dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+       if (dev == NULL) {
+               ret = -ENOMEM;
+               dev_err(&client->dev, "kzalloc() failed\n");
+               goto err;
+       }
 
-       priv->cfg = cfg;
-       priv->i2c = i2c;
-       fe->tuner_priv = priv;
+       memcpy(&dev->cfg, cfg, sizeof(struct tda18212_config));
+       dev->client = client;
+       dev->regmap = devm_regmap_init_i2c(client, &regmap_config);
+       if (IS_ERR(dev->regmap)) {
+               ret = PTR_ERR(dev->regmap);
+               goto err;
+       }
 
+       /* check if the tuner is there */
        if (fe->ops.i2c_gate_ctrl)
                fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */
 
-       /* check if the tuner is there */
-       ret = tda18212_rd_reg(priv, 0x00, &val);
+       ret = regmap_read(dev->regmap, 0x00, &chip_id);
+       dev_dbg(&dev->client->dev, "chip_id=%02x\n", chip_id);
 
        if (fe->ops.i2c_gate_ctrl)
                fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */
 
-       if (!ret)
-               dev_dbg(&priv->i2c->dev, "%s: chip id=%02x\n", __func__, val);
-       if (ret || val != 0xc7) {
-               kfree(priv);
-               return NULL;
+       if (ret)
+               goto err;
+
+       switch (chip_id) {
+       case 0xc7:
+               version = "M"; /* master */
+               break;
+       case 0x47:
+               version = "S"; /* slave */
+               break;
+       default:
+               ret = -ENODEV;
+               goto err;
        }
 
-       dev_info(&priv->i2c->dev,
-                       "%s: NXP TDA18212HN successfully identified\n",
-                       KBUILD_MODNAME);
+       dev_info(&dev->client->dev,
+                       "NXP TDA18212HN/%s successfully identified\n", version);
 
+       fe->tuner_priv = dev;
        memcpy(&fe->ops.tuner_ops, &tda18212_tuner_ops,
-               sizeof(struct dvb_tuner_ops));
+                       sizeof(struct dvb_tuner_ops));
+       i2c_set_clientdata(client, dev);
 
-       return fe;
+       return 0;
+err:
+       dev_dbg(&client->dev, "failed=%d\n", ret);
+       kfree(dev);
+       return ret;
 }
-EXPORT_SYMBOL(tda18212_attach);
+
+static int tda18212_remove(struct i2c_client *client)
+{
+       struct tda18212_dev *dev = i2c_get_clientdata(client);
+       struct dvb_frontend *fe = dev->cfg.fe;
+
+       dev_dbg(&client->dev, "\n");
+
+       memset(&fe->ops.tuner_ops, 0, sizeof(struct dvb_tuner_ops));
+       fe->tuner_priv = NULL;
+       kfree(dev);
+
+       return 0;
+}
+
+static const struct i2c_device_id tda18212_id[] = {
+       {"tda18212", 0},
+       {}
+};
+MODULE_DEVICE_TABLE(i2c, tda18212_id);
+
+static struct i2c_driver tda18212_driver = {
+       .driver = {
+               .owner  = THIS_MODULE,
+               .name   = "tda18212",
+       },
+       .probe          = tda18212_probe,
+       .remove         = tda18212_remove,
+       .id_table       = tda18212_id,
+};
+
+module_i2c_driver(tda18212_driver);
 
 MODULE_DESCRIPTION("NXP TDA18212HN silicon tuner driver");
 MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
index c36b49e4b2742a8f8cf12f1dd99e253c69d89ac6..e58c9096d79c5e5a08a6bcdb5a644fa19490edbf 100644 (file)
@@ -25,8 +25,6 @@
 #include "dvb_frontend.h"
 
 struct tda18212_config {
-       u8 i2c_address;
-
        u16 if_dvbt_6;
        u16 if_dvbt_7;
        u16 if_dvbt_8;
@@ -37,18 +35,11 @@ struct tda18212_config {
        u16 if_dvbc;
        u16 if_atsc_vsb;
        u16 if_atsc_qam;
-};
 
-#if IS_ENABLED(CONFIG_MEDIA_TUNER_TDA18212)
-extern struct dvb_frontend *tda18212_attach(struct dvb_frontend *fe,
-       struct i2c_adapter *i2c, struct tda18212_config *cfg);
-#else
-static inline struct dvb_frontend *tda18212_attach(struct dvb_frontend *fe,
-       struct i2c_adapter *i2c, struct tda18212_config *cfg)
-{
-       printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-       return NULL;
-}
-#endif
+       /*
+        * pointer to DVB frontend
+        */
+       struct dvb_frontend *fe;
+};
 
 #endif
index 18c77afe2e4ff8f32345a56d6aae199de1062c74..86e5e31101186ef37b30055b9f43e0725fc7ba01 100644 (file)
@@ -714,12 +714,11 @@ fail:
        return ret;
 }
 
-int _tda_printk(struct tda18271_priv *state, const char *level,
-               const char *func, const char *fmt, ...)
+void _tda_printk(struct tda18271_priv *state, const char *level,
+                const char *func, const char *fmt, ...)
 {
        struct va_format vaf;
        va_list args;
-       int rtn;
 
        va_start(args, fmt);
 
@@ -727,15 +726,13 @@ int _tda_printk(struct tda18271_priv *state, const char *level,
        vaf.va = &args;
 
        if (state)
-               rtn = printk("%s%s: [%d-%04x|%c] %pV",
-                            level, func, i2c_adapter_id(state->i2c_props.adap),
-                            state->i2c_props.addr,
-                            (state->role == TDA18271_MASTER) ? 'M' : 'S',
-                            &vaf);
+               printk("%s%s: [%d-%04x|%c] %pV",
+                      level, func, i2c_adapter_id(state->i2c_props.adap),
+                      state->i2c_props.addr,
+                      (state->role == TDA18271_MASTER) ? 'M' : 'S',
+                      &vaf);
        else
-               rtn = printk("%s%s: %pV", level, func, &vaf);
+               printk("%s%s: %pV", level, func, &vaf);
 
        va_end(args);
-
-       return rtn;
 }
index 454c152ccaa023d66423591108ca16616c058660..b36a7b75477253ad6cc1e678579833d8476354fb 100644 (file)
@@ -139,8 +139,8 @@ extern int tda18271_debug;
 #define DBG_CAL  16
 
 __attribute__((format(printf, 4, 5)))
-int _tda_printk(struct tda18271_priv *state, const char *level,
-               const char *func, const char *fmt, ...);
+void _tda_printk(struct tda18271_priv *state, const char *level,
+                const char *func, const char *fmt, ...);
 
 #define tda_printk(st, lvl, fmt, arg...)                       \
        _tda_printk(st, lvl, __func__, fmt, ##arg)
index 565eeebb3aebc990fc89b7e4fafc98c0e876e487..d12f5e4ad8bf42e0138de60316f1a16ae419a2b8 100644 (file)
@@ -178,67 +178,67 @@ static int xc2028_get_reg(struct xc2028_data *priv, u16 reg, u16 *val)
 #define dump_firm_type(t)      dump_firm_type_and_int_freq(t, 0)
 static void dump_firm_type_and_int_freq(unsigned int type, u16 int_freq)
 {
-        if (type & BASE)
+       if (type & BASE)
                printk("BASE ");
-        if (type & INIT1)
+       if (type & INIT1)
                printk("INIT1 ");
-        if (type & F8MHZ)
+       if (type & F8MHZ)
                printk("F8MHZ ");
-        if (type & MTS)
+       if (type & MTS)
                printk("MTS ");
-        if (type & D2620)
+       if (type & D2620)
                printk("D2620 ");
-        if (type & D2633)
+       if (type & D2633)
                printk("D2633 ");
-        if (type & DTV6)
+       if (type & DTV6)
                printk("DTV6 ");
-        if (type & QAM)
+       if (type & QAM)
                printk("QAM ");
-        if (type & DTV7)
+       if (type & DTV7)
                printk("DTV7 ");
-        if (type & DTV78)
+       if (type & DTV78)
                printk("DTV78 ");
-        if (type & DTV8)
+       if (type & DTV8)
                printk("DTV8 ");
-        if (type & FM)
+       if (type & FM)
                printk("FM ");
-        if (type & INPUT1)
+       if (type & INPUT1)
                printk("INPUT1 ");
-        if (type & LCD)
+       if (type & LCD)
                printk("LCD ");
-        if (type & NOGD)
+       if (type & NOGD)
                printk("NOGD ");
-        if (type & MONO)
+       if (type & MONO)
                printk("MONO ");
-        if (type & ATSC)
+       if (type & ATSC)
                printk("ATSC ");
-        if (type & IF)
+       if (type & IF)
                printk("IF ");
-        if (type & LG60)
+       if (type & LG60)
                printk("LG60 ");
-        if (type & ATI638)
+       if (type & ATI638)
                printk("ATI638 ");
-        if (type & OREN538)
+       if (type & OREN538)
                printk("OREN538 ");
-        if (type & OREN36)
+       if (type & OREN36)
                printk("OREN36 ");
-        if (type & TOYOTA388)
+       if (type & TOYOTA388)
                printk("TOYOTA388 ");
-        if (type & TOYOTA794)
+       if (type & TOYOTA794)
                printk("TOYOTA794 ");
-        if (type & DIBCOM52)
+       if (type & DIBCOM52)
                printk("DIBCOM52 ");
-        if (type & ZARLINK456)
+       if (type & ZARLINK456)
                printk("ZARLINK456 ");
-        if (type & CHINA)
+       if (type & CHINA)
                printk("CHINA ");
-        if (type & F6MHZ)
+       if (type & F6MHZ)
                printk("F6MHZ ");
-        if (type & INPUT2)
+       if (type & INPUT2)
                printk("INPUT2 ");
-        if (type & SCODE)
+       if (type & SCODE)
                printk("SCODE ");
-        if (type & HAS_IF)
+       if (type & HAS_IF)
                printk("HAS_IF_%d ", int_freq);
 }
 
diff --git a/drivers/media/tuners/tuner_it913x.c b/drivers/media/tuners/tuner_it913x.c
deleted file mode 100644 (file)
index 3d83c42..0000000
+++ /dev/null
@@ -1,453 +0,0 @@
-/*
- * ITE Tech IT9137 silicon tuner driver
- *
- *  Copyright (C) 2011 Malcolm Priestley (tvboxspy@gmail.com)
- *  IT9137 Copyright (C) ITE Tech 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.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.=
- */
-
-#include "tuner_it913x_priv.h"
-
-struct it913x_state {
-       struct i2c_adapter *i2c_adap;
-       u8 i2c_addr;
-       u8 chip_ver;
-       u8 tuner_type;
-       u8 firmware_ver;
-       u16 tun_xtal;
-       u8 tun_fdiv;
-       u8 tun_clk_mode;
-       u32 tun_fn_min;
-};
-
-/* read multiple registers */
-static int it913x_rd_regs(struct it913x_state *state,
-               u32 reg, u8 *data, u8 count)
-{
-       int ret;
-       u8 b[3];
-       struct i2c_msg msg[2] = {
-               { .addr = state->i2c_addr, .flags = 0,
-                       .buf = b, .len = sizeof(b) },
-               { .addr = state->i2c_addr, .flags = I2C_M_RD,
-                       .buf = data, .len = count }
-       };
-       b[0] = (u8)(reg >> 16) & 0xff;
-       b[1] = (u8)(reg >> 8) & 0xff;
-       b[2] = (u8) reg & 0xff;
-       b[0] |= 0x80; /* All reads from demodulator */
-
-       ret = i2c_transfer(state->i2c_adap, msg, 2);
-
-       return ret;
-}
-
-/* read single register */
-static int it913x_rd_reg(struct it913x_state *state, u32 reg)
-{
-       int ret;
-       u8 b[1];
-       ret = it913x_rd_regs(state, reg, &b[0], sizeof(b));
-       return (ret < 0) ? -ENODEV : b[0];
-}
-
-/* write multiple registers */
-static int it913x_wr_regs(struct it913x_state *state,
-               u8 pro, u32 reg, u8 buf[], u8 count)
-{
-       u8 b[256];
-       struct i2c_msg msg[1] = {
-               { .addr = state->i2c_addr, .flags = 0,
-                 .buf = b, .len = 3 + count }
-       };
-       int ret;
-       b[0] = (u8)(reg >> 16) & 0xff;
-       b[1] = (u8)(reg >> 8) & 0xff;
-       b[2] = (u8) reg & 0xff;
-       memcpy(&b[3], buf, count);
-
-       if (pro == PRO_DMOD)
-               b[0] |= 0x80;
-
-       ret = i2c_transfer(state->i2c_adap, msg, 1);
-
-       if (ret < 0)
-               return -EIO;
-
-       return 0;
-}
-
-/* write single register */
-static int it913x_wr_reg(struct it913x_state *state,
-               u8 pro, u32 reg, u32 data)
-{
-       int ret;
-       u8 b[4];
-       u8 s;
-
-       b[0] = data >> 24;
-       b[1] = (data >> 16) & 0xff;
-       b[2] = (data >> 8) & 0xff;
-       b[3] = data & 0xff;
-       /* expand write as needed */
-       if (data < 0x100)
-               s = 3;
-       else if (data < 0x1000)
-               s = 2;
-       else if (data < 0x100000)
-               s = 1;
-       else
-               s = 0;
-
-       ret = it913x_wr_regs(state, pro, reg, &b[s], sizeof(b) - s);
-
-       return ret;
-}
-
-static int it913x_script_loader(struct it913x_state *state,
-               struct it913xset *loadscript)
-{
-       int ret, i;
-       if (loadscript == NULL)
-               return -EINVAL;
-
-       for (i = 0; i < 1000; ++i) {
-               if (loadscript[i].pro == 0xff)
-                       break;
-               ret = it913x_wr_regs(state, loadscript[i].pro,
-                       loadscript[i].address,
-                       loadscript[i].reg, loadscript[i].count);
-               if (ret < 0)
-                       return -ENODEV;
-       }
-       return 0;
-}
-
-static int it913x_init(struct dvb_frontend *fe)
-{
-       struct it913x_state *state = fe->tuner_priv;
-       int ret, i, reg;
-       u8 val, nv_val;
-       u8 nv[] = {48, 32, 24, 16, 12, 8, 6, 4, 2};
-       u8 b[2];
-
-       reg = it913x_rd_reg(state, 0xec86);
-       switch (reg) {
-       case 0:
-               state->tun_clk_mode = reg;
-               state->tun_xtal = 2000;
-               state->tun_fdiv = 3;
-               val = 16;
-               break;
-       case -ENODEV:
-               return -ENODEV;
-       case 1:
-       default:
-               state->tun_clk_mode = reg;
-               state->tun_xtal = 640;
-               state->tun_fdiv = 1;
-               val = 6;
-               break;
-       }
-
-       reg = it913x_rd_reg(state, 0xed03);
-
-       if (reg < 0)
-               return -ENODEV;
-       else if (reg < ARRAY_SIZE(nv))
-               nv_val = nv[reg];
-       else
-               nv_val = 2;
-
-       for (i = 0; i < 50; i++) {
-               ret = it913x_rd_regs(state, 0xed23, &b[0], sizeof(b));
-               reg = (b[1] << 8) + b[0];
-               if (reg > 0)
-                       break;
-               if (ret < 0)
-                       return -ENODEV;
-               udelay(2000);
-       }
-       state->tun_fn_min = state->tun_xtal * reg;
-       state->tun_fn_min /= (state->tun_fdiv * nv_val);
-       dev_dbg(&state->i2c_adap->dev, "%s: Tuner fn_min %d\n", __func__,
-                       state->tun_fn_min);
-
-       if (state->chip_ver > 1)
-               msleep(50);
-       else {
-               for (i = 0; i < 50; i++) {
-                       reg = it913x_rd_reg(state, 0xec82);
-                       if (reg > 0)
-                               break;
-                       if (reg < 0)
-                               return -ENODEV;
-                       udelay(2000);
-               }
-       }
-
-       /* Power Up Tuner - common all versions */
-       ret = it913x_wr_reg(state, PRO_DMOD, 0xec40, 0x1);
-       ret |= it913x_wr_reg(state, PRO_DMOD, 0xfba8, 0x0);
-       ret |= it913x_wr_reg(state, PRO_DMOD, 0xec57, 0x0);
-       ret |= it913x_wr_reg(state, PRO_DMOD, 0xec58, 0x0);
-
-       return it913x_wr_reg(state, PRO_DMOD, 0xed81, val);
-}
-
-static int it9137_set_params(struct dvb_frontend *fe)
-{
-       struct it913x_state *state = fe->tuner_priv;
-       struct it913xset *set_tuner = set_it9137_template;
-       struct dtv_frontend_properties *p = &fe->dtv_property_cache;
-       u32 bandwidth = p->bandwidth_hz;
-       u32 frequency_m = p->frequency;
-       int ret, reg;
-       u32 frequency = frequency_m / 1000;
-       u32 freq, temp_f, tmp;
-       u16 iqik_m_cal;
-       u16 n_div;
-       u8 n;
-       u8 l_band;
-       u8 lna_band;
-       u8 bw;
-
-       if (state->firmware_ver == 1)
-               set_tuner = set_it9135_template;
-       else
-               set_tuner = set_it9137_template;
-
-       dev_dbg(&state->i2c_adap->dev, "%s: Tuner Frequency %d Bandwidth %d\n",
-                       __func__, frequency, bandwidth);
-
-       if (frequency >= 51000 && frequency <= 440000) {
-               l_band = 0;
-               lna_band = 0;
-       } else if (frequency > 440000 && frequency <= 484000) {
-               l_band = 1;
-               lna_band = 1;
-       } else if (frequency > 484000 && frequency <= 533000) {
-               l_band = 1;
-               lna_band = 2;
-       } else if (frequency > 533000 && frequency <= 587000) {
-               l_band = 1;
-               lna_band = 3;
-       } else if (frequency > 587000 && frequency <= 645000) {
-               l_band = 1;
-               lna_band = 4;
-       } else if (frequency > 645000 && frequency <= 710000) {
-               l_band = 1;
-               lna_band = 5;
-       } else if (frequency > 710000 && frequency <= 782000) {
-               l_band = 1;
-               lna_band = 6;
-       } else if (frequency > 782000 && frequency <= 860000) {
-               l_band = 1;
-               lna_band = 7;
-       } else if (frequency > 1450000 && frequency <= 1492000) {
-               l_band = 1;
-               lna_band = 0;
-       } else if (frequency > 1660000 && frequency <= 1685000) {
-               l_band = 1;
-               lna_band = 1;
-       } else
-               return -EINVAL;
-       set_tuner[0].reg[0] = lna_band;
-
-       switch (bandwidth) {
-       case 5000000:
-               bw = 0;
-               break;
-       case 6000000:
-               bw = 2;
-               break;
-       case 7000000:
-               bw = 4;
-               break;
-       default:
-       case 8000000:
-               bw = 6;
-               break;
-       }
-
-       set_tuner[1].reg[0] = bw;
-       set_tuner[2].reg[0] = 0xa0 | (l_band << 3);
-
-       if (frequency > 53000 && frequency <= 74000) {
-               n_div = 48;
-               n = 0;
-       } else if (frequency > 74000 && frequency <= 111000) {
-               n_div = 32;
-               n = 1;
-       } else if (frequency > 111000 && frequency <= 148000) {
-               n_div = 24;
-               n = 2;
-       } else if (frequency > 148000 && frequency <= 222000) {
-               n_div = 16;
-               n = 3;
-       } else if (frequency > 222000 && frequency <= 296000) {
-               n_div = 12;
-               n = 4;
-       } else if (frequency > 296000 && frequency <= 445000) {
-               n_div = 8;
-               n = 5;
-       } else if (frequency > 445000 && frequency <= state->tun_fn_min) {
-               n_div = 6;
-               n = 6;
-       } else if (frequency > state->tun_fn_min && frequency <= 950000) {
-               n_div = 4;
-               n = 7;
-       } else if (frequency > 1450000 && frequency <= 1680000) {
-               n_div = 2;
-               n = 0;
-       } else
-               return -EINVAL;
-
-       reg = it913x_rd_reg(state, 0xed81);
-       iqik_m_cal = (u16)reg * n_div;
-
-       if (reg < 0x20) {
-               if (state->tun_clk_mode == 0)
-                       iqik_m_cal = (iqik_m_cal * 9) >> 5;
-               else
-                       iqik_m_cal >>= 1;
-       } else {
-               iqik_m_cal = 0x40 - iqik_m_cal;
-               if (state->tun_clk_mode == 0)
-                       iqik_m_cal = ~((iqik_m_cal * 9) >> 5);
-               else
-                       iqik_m_cal = ~(iqik_m_cal >> 1);
-       }
-
-       temp_f = frequency * (u32)n_div * (u32)state->tun_fdiv;
-       freq = temp_f / state->tun_xtal;
-       tmp = freq * state->tun_xtal;
-
-       if ((temp_f - tmp) >= (state->tun_xtal >> 1))
-               freq++;
-
-       freq += (u32) n << 13;
-       /* Frequency OMEGA_IQIK_M_CAL_MID*/
-       temp_f = freq + (u32)iqik_m_cal;
-
-       set_tuner[3].reg[0] =  temp_f & 0xff;
-       set_tuner[4].reg[0] =  (temp_f >> 8) & 0xff;
-
-       dev_dbg(&state->i2c_adap->dev, "%s: High Frequency = %04x\n",
-                       __func__, temp_f);
-
-       /* Lower frequency */
-       set_tuner[5].reg[0] =  freq & 0xff;
-       set_tuner[6].reg[0] =  (freq >> 8) & 0xff;
-
-       dev_dbg(&state->i2c_adap->dev, "%s: low Frequency = %04x\n",
-                       __func__, freq);
-
-       ret = it913x_script_loader(state, set_tuner);
-
-       return (ret < 0) ? -ENODEV : 0;
-}
-
-/* Power sequence */
-/* Power Up    Tuner on -> Frontend suspend off -> Tuner clk on */
-/* Power Down  Frontend suspend on -> Tuner clk off -> Tuner off */
-
-static int it913x_sleep(struct dvb_frontend *fe)
-{
-       struct it913x_state *state = fe->tuner_priv;
-       return it913x_script_loader(state, it9137_tuner_off);
-}
-
-static int it913x_release(struct dvb_frontend *fe)
-{
-       kfree(fe->tuner_priv);
-       return 0;
-}
-
-static const struct dvb_tuner_ops it913x_tuner_ops = {
-       .info = {
-               .name           = "ITE Tech IT913X",
-               .frequency_min  = 174000000,
-               .frequency_max  = 862000000,
-       },
-
-       .release = it913x_release,
-
-       .init = it913x_init,
-       .sleep = it913x_sleep,
-       .set_params = it9137_set_params,
-};
-
-struct dvb_frontend *it913x_attach(struct dvb_frontend *fe,
-               struct i2c_adapter *i2c_adap, u8 i2c_addr, u8 config)
-{
-       struct it913x_state *state = NULL;
-       int ret;
-
-       /* allocate memory for the internal state */
-       state = kzalloc(sizeof(struct it913x_state), GFP_KERNEL);
-       if (state == NULL)
-               return NULL;
-
-       state->i2c_adap = i2c_adap;
-       state->i2c_addr = i2c_addr;
-
-       switch (config) {
-       case AF9033_TUNER_IT9135_38:
-       case AF9033_TUNER_IT9135_51:
-       case AF9033_TUNER_IT9135_52:
-               state->chip_ver = 0x01;
-               break;
-       case AF9033_TUNER_IT9135_60:
-       case AF9033_TUNER_IT9135_61:
-       case AF9033_TUNER_IT9135_62:
-               state->chip_ver = 0x02;
-               break;
-       default:
-               dev_dbg(&i2c_adap->dev,
-                               "%s: invalid config=%02x\n", __func__, config);
-               goto error;
-       }
-
-       state->tuner_type = config;
-       state->firmware_ver = 1;
-
-       /* tuner RF initial */
-       ret = it913x_wr_reg(state, PRO_DMOD, 0xec4c, 0x68);
-       if (ret < 0)
-               goto error;
-
-       fe->tuner_priv = state;
-       memcpy(&fe->ops.tuner_ops, &it913x_tuner_ops,
-                       sizeof(struct dvb_tuner_ops));
-
-       dev_info(&i2c_adap->dev,
-                       "%s: ITE Tech IT913X successfully attached\n",
-                       KBUILD_MODNAME);
-       dev_dbg(&i2c_adap->dev, "%s: config=%02x chip_ver=%02x\n",
-                       __func__, config, state->chip_ver);
-
-       return fe;
-error:
-       kfree(state);
-       return NULL;
-}
-EXPORT_SYMBOL(it913x_attach);
-
-MODULE_DESCRIPTION("ITE Tech IT913X silicon tuner driver");
-MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/tuners/tuner_it913x.h b/drivers/media/tuners/tuner_it913x.h
deleted file mode 100644 (file)
index 12dd36b..0000000
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * ITE Tech IT9137 silicon tuner driver
- *
- *  Copyright (C) 2011 Malcolm Priestley (tvboxspy@gmail.com)
- *  IT9137 Copyright (C) ITE Tech 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.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.=
- */
-
-#ifndef IT913X_H
-#define IT913X_H
-
-#include "dvb_frontend.h"
-
-#if defined(CONFIG_MEDIA_TUNER_IT913X) || \
-       (defined(CONFIG_MEDIA_TUNER_IT913X_MODULE) && defined(MODULE))
-extern struct dvb_frontend *it913x_attach(struct dvb_frontend *fe,
-       struct i2c_adapter *i2c_adap,
-       u8 i2c_addr,
-       u8 config);
-#else
-static inline struct dvb_frontend *it913x_attach(struct dvb_frontend *fe,
-       struct i2c_adapter *i2c_adap,
-       u8 i2c_addr,
-       u8 config)
-{
-       pr_warn("%s: driver disabled by Kconfig\n", __func__);
-       return NULL;
-}
-#endif
-
-#endif
diff --git a/drivers/media/tuners/tuner_it913x_priv.h b/drivers/media/tuners/tuner_it913x_priv.h
deleted file mode 100644 (file)
index ce65210..0000000
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * ITE Tech IT9137 silicon tuner driver
- *
- *  Copyright (C) 2011 Malcolm Priestley (tvboxspy@gmail.com)
- *  IT9137 Copyright (C) ITE Tech 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.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.=
- */
-
-#ifndef IT913X_PRIV_H
-#define IT913X_PRIV_H
-
-#include "tuner_it913x.h"
-#include "af9033.h"
-
-#define PRO_LINK               0x0
-#define PRO_DMOD               0x1
-#define TRIGGER_OFSM           0x0000
-
-struct it913xset {     u32 pro;
-                       u32 address;
-                       u8 reg[15];
-                       u8 count;
-};
-
-/* Tuner setting scripts (still keeping it9137) */
-static struct it913xset it9137_tuner_off[] = {
-       {PRO_DMOD, 0xfba8, {0x01}, 0x01}, /* Tuner Clock Off  */
-       {PRO_DMOD, 0xec40, {0x00}, 0x01}, /* Power Down Tuner */
-       {PRO_DMOD, 0xec02, {0x3f, 0x1f, 0x3f, 0x3f}, 0x04},
-       {PRO_DMOD, 0xec06, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-                               0x00, 0x00, 0x00, 0x00}, 0x0c},
-       {PRO_DMOD, 0xec12, {0x00, 0x00, 0x00, 0x00}, 0x04},
-       {PRO_DMOD, 0xec17, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-                               0x00}, 0x09},
-       {PRO_DMOD, 0xec22, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-                               0x00, 0x00}, 0x0a},
-       {PRO_DMOD, 0xec20, {0x00}, 0x01},
-       {PRO_DMOD, 0xec3f, {0x01}, 0x01},
-       {0xff, 0x0000, {0x00}, 0x00}, /* Terminating Entry */
-};
-
-static struct it913xset set_it9135_template[] = {
-       {PRO_DMOD, 0xee06, {0x00}, 0x01},
-       {PRO_DMOD, 0xec56, {0x00}, 0x01},
-       {PRO_DMOD, 0xec4c, {0x00}, 0x01},
-       {PRO_DMOD, 0xec4d, {0x00}, 0x01},
-       {PRO_DMOD, 0xec4e, {0x00}, 0x01},
-       {PRO_DMOD, 0x011e, {0x00}, 0x01}, /* Older Devices */
-       {PRO_DMOD, 0x011f, {0x00}, 0x01},
-       {0xff, 0x0000, {0x00}, 0x00}, /* Terminating Entry */
-};
-
-static struct it913xset set_it9137_template[] = {
-       {PRO_DMOD, 0xee06, {0x00}, 0x01},
-       {PRO_DMOD, 0xec56, {0x00}, 0x01},
-       {PRO_DMOD, 0xec4c, {0x00}, 0x01},
-       {PRO_DMOD, 0xec4d, {0x00}, 0x01},
-       {PRO_DMOD, 0xec4e, {0x00}, 0x01},
-       {PRO_DMOD, 0xec4f, {0x00}, 0x01},
-       {PRO_DMOD, 0xec50, {0x00}, 0x01},
-       {0xff, 0x0000, {0x00}, 0x00}, /* Terminating Entry */
-};
-
-#endif
index f9ab79e3432d9cb4018fcd017548a9f457724b9c..219ebafae70fd3f9b8d1f5541d43100e7a73aa64 100644 (file)
@@ -569,67 +569,67 @@ static int xc4000_readreg(struct xc4000_priv *priv, u16 reg, u16 *val)
 #define dump_firm_type(t)      dump_firm_type_and_int_freq(t, 0)
 static void dump_firm_type_and_int_freq(unsigned int type, u16 int_freq)
 {
-        if (type & BASE)
+       if (type & BASE)
                printk(KERN_CONT "BASE ");
-        if (type & INIT1)
+       if (type & INIT1)
                printk(KERN_CONT "INIT1 ");
-        if (type & F8MHZ)
+       if (type & F8MHZ)
                printk(KERN_CONT "F8MHZ ");
-        if (type & MTS)
+       if (type & MTS)
                printk(KERN_CONT "MTS ");
-        if (type & D2620)
+       if (type & D2620)
                printk(KERN_CONT "D2620 ");
-        if (type & D2633)
+       if (type & D2633)
                printk(KERN_CONT "D2633 ");
-        if (type & DTV6)
+       if (type & DTV6)
                printk(KERN_CONT "DTV6 ");
-        if (type & QAM)
+       if (type & QAM)
                printk(KERN_CONT "QAM ");
-        if (type & DTV7)
+       if (type & DTV7)
                printk(KERN_CONT "DTV7 ");
-        if (type & DTV78)
+       if (type & DTV78)
                printk(KERN_CONT "DTV78 ");
-        if (type & DTV8)
+       if (type & DTV8)
                printk(KERN_CONT "DTV8 ");
-        if (type & FM)
+       if (type & FM)
                printk(KERN_CONT "FM ");
-        if (type & INPUT1)
+       if (type & INPUT1)
                printk(KERN_CONT "INPUT1 ");
-        if (type & LCD)
+       if (type & LCD)
                printk(KERN_CONT "LCD ");
-        if (type & NOGD)
+       if (type & NOGD)
                printk(KERN_CONT "NOGD ");
-        if (type & MONO)
+       if (type & MONO)
                printk(KERN_CONT "MONO ");
-        if (type & ATSC)
+       if (type & ATSC)
                printk(KERN_CONT "ATSC ");
-        if (type & IF)
+       if (type & IF)
                printk(KERN_CONT "IF ");
-        if (type & LG60)
+       if (type & LG60)
                printk(KERN_CONT "LG60 ");
-        if (type & ATI638)
+       if (type & ATI638)
                printk(KERN_CONT "ATI638 ");
-        if (type & OREN538)
+       if (type & OREN538)
                printk(KERN_CONT "OREN538 ");
-        if (type & OREN36)
+       if (type & OREN36)
                printk(KERN_CONT "OREN36 ");
-        if (type & TOYOTA388)
+       if (type & TOYOTA388)
                printk(KERN_CONT "TOYOTA388 ");
-        if (type & TOYOTA794)
+       if (type & TOYOTA794)
                printk(KERN_CONT "TOYOTA794 ");
-        if (type & DIBCOM52)
+       if (type & DIBCOM52)
                printk(KERN_CONT "DIBCOM52 ");
-        if (type & ZARLINK456)
+       if (type & ZARLINK456)
                printk(KERN_CONT "ZARLINK456 ");
-        if (type & CHINA)
+       if (type & CHINA)
                printk(KERN_CONT "CHINA ");
-        if (type & F6MHZ)
+       if (type & F6MHZ)
                printk(KERN_CONT "F6MHZ ");
-        if (type & INPUT2)
+       if (type & INPUT2)
                printk(KERN_CONT "INPUT2 ");
-        if (type & SCODE)
+       if (type & SCODE)
                printk(KERN_CONT "SCODE ");
-        if (type & HAS_IF)
+       if (type & HAS_IF)
                printk(KERN_CONT "HAS_IF_%d ", int_freq);
 }
 
index e135760f7d486d5bb6061fb0452bbbb5f87545af..e44c8aba6074c0667181d9e7a7daab2f7db4d1bc 100644 (file)
@@ -59,6 +59,7 @@ struct xc5000_priv {
        u32 freq_hz, freq_offset;
        u32 bandwidth;
        u8  video_standard;
+       unsigned int mode;
        u8  rf_mode;
        u8  radio_input;
 
@@ -69,6 +70,8 @@ struct xc5000_priv {
 
        struct dvb_frontend *fe;
        struct delayed_work timer_sleep;
+
+       const struct firmware   *firmware;
 };
 
 /* Misc Defines */
@@ -712,9 +715,50 @@ static void xc_debug_dump(struct xc5000_priv *priv)
        }
 }
 
-static int xc5000_set_params(struct dvb_frontend *fe)
+static int xc5000_tune_digital(struct dvb_frontend *fe)
+{
+       struct xc5000_priv *priv = fe->tuner_priv;
+       int ret;
+       u32 bw = fe->dtv_property_cache.bandwidth_hz;
+
+       ret = xc_set_signal_source(priv, priv->rf_mode);
+       if (ret != 0) {
+               printk(KERN_ERR
+                       "xc5000: xc_set_signal_source(%d) failed\n",
+                       priv->rf_mode);
+               return -EREMOTEIO;
+       }
+
+       ret = xc_set_tv_standard(priv,
+               xc5000_standard[priv->video_standard].video_mode,
+               xc5000_standard[priv->video_standard].audio_mode, 0);
+       if (ret != 0) {
+               printk(KERN_ERR "xc5000: xc_set_tv_standard failed\n");
+               return -EREMOTEIO;
+       }
+
+       ret = xc_set_IF_frequency(priv, priv->if_khz);
+       if (ret != 0) {
+               printk(KERN_ERR "xc5000: xc_Set_IF_frequency(%d) failed\n",
+                      priv->if_khz);
+               return -EIO;
+       }
+
+       xc_write_reg(priv, XREG_OUTPUT_AMP, 0x8a);
+
+       xc_tune_channel(priv, priv->freq_hz, XC_TUNE_DIGITAL);
+
+       if (debug)
+               xc_debug_dump(priv);
+
+       priv->bandwidth = bw;
+
+       return 0;
+}
+
+static int xc5000_set_digital_params(struct dvb_frontend *fe)
 {
-       int ret, b;
+       int b;
        struct xc5000_priv *priv = fe->tuner_priv;
        u32 bw = fe->dtv_property_cache.bandwidth_hz;
        u32 freq = fe->dtv_property_cache.frequency;
@@ -794,43 +838,12 @@ static int xc5000_set_params(struct dvb_frontend *fe)
        }
 
        priv->freq_hz = freq - priv->freq_offset;
+       priv->mode = V4L2_TUNER_DIGITAL_TV;
 
        dprintk(1, "%s() frequency=%d (compensated to %d)\n",
                __func__, freq, priv->freq_hz);
 
-       ret = xc_set_signal_source(priv, priv->rf_mode);
-       if (ret != 0) {
-               printk(KERN_ERR
-                       "xc5000: xc_set_signal_source(%d) failed\n",
-                       priv->rf_mode);
-               return -EREMOTEIO;
-       }
-
-       ret = xc_set_tv_standard(priv,
-               xc5000_standard[priv->video_standard].video_mode,
-               xc5000_standard[priv->video_standard].audio_mode, 0);
-       if (ret != 0) {
-               printk(KERN_ERR "xc5000: xc_set_tv_standard failed\n");
-               return -EREMOTEIO;
-       }
-
-       ret = xc_set_IF_frequency(priv, priv->if_khz);
-       if (ret != 0) {
-               printk(KERN_ERR "xc5000: xc_Set_IF_frequency(%d) failed\n",
-                      priv->if_khz);
-               return -EIO;
-       }
-
-       xc_write_reg(priv, XREG_OUTPUT_AMP, 0x8a);
-
-       xc_tune_channel(priv, priv->freq_hz, XC_TUNE_DIGITAL);
-
-       if (debug)
-               xc_debug_dump(priv);
-
-       priv->bandwidth = bw;
-
-       return 0;
+       return xc5000_tune_digital(fe);
 }
 
 static int xc5000_is_firmware_loaded(struct dvb_frontend *fe)
@@ -852,12 +865,10 @@ static int xc5000_is_firmware_loaded(struct dvb_frontend *fe)
        return ret;
 }
 
-static int xc5000_set_tv_freq(struct dvb_frontend *fe,
-       struct analog_parameters *params)
+static void xc5000_config_tv(struct dvb_frontend *fe,
+                            struct analog_parameters *params)
 {
        struct xc5000_priv *priv = fe->tuner_priv;
-       u16 pll_lock_status;
-       int ret;
 
        dprintk(1, "%s() frequency=%d (in units of 62.5khz)\n",
                __func__, params->frequency);
@@ -876,42 +887,49 @@ static int xc5000_set_tv_freq(struct dvb_frontend *fe,
        if (params->std & V4L2_STD_MN) {
                /* default to BTSC audio standard */
                priv->video_standard = MN_NTSC_PAL_BTSC;
-               goto tune_channel;
+               return;
        }
 
        if (params->std & V4L2_STD_PAL_BG) {
                /* default to NICAM audio standard */
                priv->video_standard = BG_PAL_NICAM;
-               goto tune_channel;
+               return;
        }
 
        if (params->std & V4L2_STD_PAL_I) {
                /* default to NICAM audio standard */
                priv->video_standard = I_PAL_NICAM;
-               goto tune_channel;
+               return;
        }
 
        if (params->std & V4L2_STD_PAL_DK) {
                /* default to NICAM audio standard */
                priv->video_standard = DK_PAL_NICAM;
-               goto tune_channel;
+               return;
        }
 
        if (params->std & V4L2_STD_SECAM_DK) {
                /* default to A2 DK1 audio standard */
                priv->video_standard = DK_SECAM_A2DK1;
-               goto tune_channel;
+               return;
        }
 
        if (params->std & V4L2_STD_SECAM_L) {
                priv->video_standard = L_SECAM_NICAM;
-               goto tune_channel;
+               return;
        }
 
        if (params->std & V4L2_STD_SECAM_LC) {
                priv->video_standard = LC_SECAM_NICAM;
-               goto tune_channel;
+               return;
        }
+}
+
+static int xc5000_set_tv_freq(struct dvb_frontend *fe)
+{
+       struct xc5000_priv *priv = fe->tuner_priv;
+       u16 pll_lock_status;
+       int ret;
 
 tune_channel:
        ret = xc_set_signal_source(priv, priv->rf_mode);
@@ -955,12 +973,11 @@ tune_channel:
        return 0;
 }
 
-static int xc5000_set_radio_freq(struct dvb_frontend *fe,
-       struct analog_parameters *params)
+static int xc5000_config_radio(struct dvb_frontend *fe,
+                              struct analog_parameters *params)
+
 {
        struct xc5000_priv *priv = fe->tuner_priv;
-       int ret = -EINVAL;
-       u8 radio_input;
 
        dprintk(1, "%s() frequency=%d (in units of khz)\n",
                __func__, params->frequency);
@@ -970,6 +987,18 @@ static int xc5000_set_radio_freq(struct dvb_frontend *fe,
                return -EINVAL;
        }
 
+       priv->freq_hz = params->frequency * 125 / 2;
+       priv->rf_mode = XC_RF_MODE_AIR;
+
+       return 0;
+}
+
+static int xc5000_set_radio_freq(struct dvb_frontend *fe)
+{
+       struct xc5000_priv *priv = fe->tuner_priv;
+       int ret;
+       u8 radio_input;
+
        if (priv->radio_input == XC5000_RADIO_FM1)
                radio_input = FM_RADIO_INPUT1;
        else if  (priv->radio_input == XC5000_RADIO_FM2)
@@ -982,10 +1011,6 @@ static int xc5000_set_radio_freq(struct dvb_frontend *fe,
                return -EINVAL;
        }
 
-       priv->freq_hz = params->frequency * 125 / 2;
-
-       priv->rf_mode = XC_RF_MODE_AIR;
-
        ret = xc_set_tv_standard(priv, xc5000_standard[radio_input].video_mode,
                               xc5000_standard[radio_input].audio_mode, radio_input);
 
@@ -1013,34 +1038,53 @@ static int xc5000_set_radio_freq(struct dvb_frontend *fe,
        return 0;
 }
 
-static int xc5000_set_analog_params(struct dvb_frontend *fe,
-                            struct analog_parameters *params)
+static int xc5000_set_params(struct dvb_frontend *fe)
 {
        struct xc5000_priv *priv = fe->tuner_priv;
-       int ret = -EINVAL;
-
-       if (priv->i2c_props.adap == NULL)
-               return -EINVAL;
 
        if (xc_load_fw_and_init_tuner(fe, 0) != 0) {
                dprintk(1, "Unable to load firmware and init tuner\n");
                return -EINVAL;
        }
 
+       switch (priv->mode) {
+       case V4L2_TUNER_RADIO:
+               return xc5000_set_radio_freq(fe);
+       case V4L2_TUNER_ANALOG_TV:
+               return xc5000_set_tv_freq(fe);
+       case V4L2_TUNER_DIGITAL_TV:
+               return xc5000_tune_digital(fe);
+       }
+
+       return 0;
+}
+
+static int xc5000_set_analog_params(struct dvb_frontend *fe,
+                            struct analog_parameters *params)
+{
+       struct xc5000_priv *priv = fe->tuner_priv;
+       int ret;
+
+       if (priv->i2c_props.adap == NULL)
+               return -EINVAL;
+
        switch (params->mode) {
        case V4L2_TUNER_RADIO:
-               ret = xc5000_set_radio_freq(fe, params);
+               ret = xc5000_config_radio(fe, params);
+               if (ret)
+                       return ret;
                break;
        case V4L2_TUNER_ANALOG_TV:
-       case V4L2_TUNER_DIGITAL_TV:
-               ret = xc5000_set_tv_freq(fe, params);
+               xc5000_config_tv(fe, params);
+               break;
+       default:
                break;
        }
+       priv->mode = params->mode;
 
-       return ret;
+       return xc5000_set_params(fe);
 }
 
-
 static int xc5000_get_frequency(struct dvb_frontend *fe, u32 *freq)
 {
        struct xc5000_priv *priv = fe->tuner_priv;
@@ -1094,20 +1138,23 @@ static int xc_load_fw_and_init_tuner(struct dvb_frontend *fe, int force)
        if (!force && xc5000_is_firmware_loaded(fe) == 0)
                return 0;
 
-       ret = request_firmware(&fw, desired_fw->name,
-                              priv->i2c_props.adap->dev.parent);
-       if (ret) {
-               printk(KERN_ERR "xc5000: Upload failed. (file not found?)\n");
-               return ret;
-       }
-
-       dprintk(1, "firmware read %Zu bytes.\n", fw->size);
+       if (!priv->firmware) {
+               ret = request_firmware(&fw, desired_fw->name,
+                                       priv->i2c_props.adap->dev.parent);
+               if (ret) {
+                       pr_err("xc5000: Upload failed. rc %d\n", ret);
+                       return ret;
+               }
+               dprintk(1, "firmware read %Zu bytes.\n", fw->size);
 
-       if (fw->size != desired_fw->size) {
-               printk(KERN_ERR "xc5000: Firmware file with incorrect size\n");
-               ret = -EINVAL;
-               goto err;
-       }
+               if (fw->size != desired_fw->size) {
+                       pr_err("xc5000: Firmware file with incorrect size\n");
+                       release_firmware(fw);
+                       return -EINVAL;
+               }
+               priv->firmware = fw;
+       } else
+               fw = priv->firmware;
 
        /* Try up to 5 times to load firmware */
        for (i = 0; i < 5; i++) {
@@ -1190,7 +1237,6 @@ err:
        else
                printk(KERN_CONT " - too many retries. Giving up\n");
 
-       release_firmware(fw);
        return ret;
 }
 
@@ -1229,6 +1275,38 @@ static int xc5000_sleep(struct dvb_frontend *fe)
        return 0;
 }
 
+static int xc5000_suspend(struct dvb_frontend *fe)
+{
+       struct xc5000_priv *priv = fe->tuner_priv;
+       int ret;
+
+       dprintk(1, "%s()\n", __func__);
+
+       cancel_delayed_work(&priv->timer_sleep);
+
+       ret = xc5000_tuner_reset(fe);
+       if (ret != 0)
+               printk(KERN_ERR
+                       "xc5000: %s() unable to shutdown tuner\n",
+                       __func__);
+
+       return 0;
+}
+
+static int xc5000_resume(struct dvb_frontend *fe)
+{
+       struct xc5000_priv *priv = fe->tuner_priv;
+
+       dprintk(1, "%s()\n", __func__);
+
+       /* suspended before firmware is loaded.
+          Avoid firmware load in resume path. */
+       if (!priv->firmware)
+               return 0;
+
+       return xc5000_set_params(fe);
+}
+
 static int xc5000_init(struct dvb_frontend *fe)
 {
        struct xc5000_priv *priv = fe->tuner_priv;
@@ -1256,6 +1334,8 @@ static int xc5000_release(struct dvb_frontend *fe)
        if (priv) {
                cancel_delayed_work(&priv->timer_sleep);
                hybrid_tuner_release_state(priv);
+               if (priv->firmware)
+                       release_firmware(priv->firmware);
        }
 
        mutex_unlock(&xc5000_list_mutex);
@@ -1293,9 +1373,11 @@ static const struct dvb_tuner_ops xc5000_tuner_ops = {
        .release           = xc5000_release,
        .init              = xc5000_init,
        .sleep             = xc5000_sleep,
+       .suspend           = xc5000_suspend,
+       .resume            = xc5000_resume,
 
        .set_config        = xc5000_set_config,
-       .set_params        = xc5000_set_params,
+       .set_params        = xc5000_set_digital_params,
        .set_analog_params = xc5000_set_analog_params,
        .get_frequency     = xc5000_get_frequency,
        .get_if_frequency  = xc5000_get_if_frequency,
index 94d51e092db34a4df56fb49570dd5e2de3af0895..056181f2f5694864be2740c05f95069e8aa923d1 100644 (file)
@@ -46,6 +46,7 @@ source "drivers/media/usb/ttusb-budget/Kconfig"
 source "drivers/media/usb/ttusb-dec/Kconfig"
 source "drivers/media/usb/siano/Kconfig"
 source "drivers/media/usb/b2c2/Kconfig"
+source "drivers/media/usb/as102/Kconfig"
 endif
 
 if (MEDIA_CAMERA_SUPPORT || MEDIA_ANALOG_TV_SUPPORT || MEDIA_DIGITAL_TV_SUPPORT)
@@ -55,8 +56,9 @@ endif
 
 if MEDIA_SDR_SUPPORT
        comment "Software defined radio USB devices"
-source "drivers/media/usb/msi2500/Kconfig"
 source "drivers/media/usb/airspy/Kconfig"
+source "drivers/media/usb/hackrf/Kconfig"
+source "drivers/media/usb/msi2500/Kconfig"
 endif
 
 endif #MEDIA_USB_SUPPORT
index f438efffefc59e027a1241fc7a30b42774b416c8..6f2eb7c8416c47844eeb2977122f554b0513668c 100644 (file)
@@ -9,8 +9,9 @@ obj-y += zr364xx/ stkwebcam/ s2255/
 obj-$(CONFIG_USB_VIDEO_CLASS)  += uvc/
 obj-$(CONFIG_USB_GSPCA)         += gspca/
 obj-$(CONFIG_USB_PWC)           += pwc/
-obj-$(CONFIG_USB_MSI2500)       += msi2500/
 obj-$(CONFIG_USB_AIRSPY)        += airspy/
+obj-$(CONFIG_USB_HACKRF)        += hackrf/
+obj-$(CONFIG_USB_MSI2500)       += msi2500/
 obj-$(CONFIG_VIDEO_CPIA2) += cpia2/
 obj-$(CONFIG_VIDEO_AU0828) += au0828/
 obj-$(CONFIG_VIDEO_HDPVR)      += hdpvr/
@@ -23,3 +24,4 @@ obj-$(CONFIG_VIDEO_TM6000) += tm6000/
 obj-$(CONFIG_VIDEO_EM28XX) += em28xx/
 obj-$(CONFIG_VIDEO_USBTV) += usbtv/
 obj-$(CONFIG_VIDEO_GO7007) += go7007/
+obj-$(CONFIG_DVB_AS102) += as102/
index cb0e515d80ae378e7e26edecfa196c4024d7dd4b..4069234abed5432c7fbf2f867da9c0235d4eba37 100644 (file)
@@ -107,6 +107,7 @@ struct airspy {
 #define USB_STATE_URB_BUF  (1 << 3)
        unsigned long flags;
 
+       struct device *dev;
        struct usb_device *udev;
        struct video_device vdev;
        struct v4l2_device v4l2_dev;
@@ -154,16 +155,15 @@ struct airspy {
        unsigned int sample_measured;
 };
 
-#define airspy_dbg_usb_control_msg(_udev, _r, _t, _v, _i, _b, _l) { \
+#define airspy_dbg_usb_control_msg(_dev, _r, _t, _v, _i, _b, _l) { \
        char *_direction; \
        if (_t & USB_DIR_IN) \
                _direction = "<<<"; \
        else \
                _direction = ">>>"; \
-       dev_dbg(&_udev->dev, "%s: %02x %02x %02x %02x %02x %02x %02x %02x " \
-                       "%s %*ph\n",  __func__, _t, _r, _v & 0xff, _v >> 8, \
-                       _i & 0xff, _i >> 8, _l & 0xff, _l >> 8, _direction, \
-                       _l, _b); \
+       dev_dbg(_dev, "%02x %02x %02x %02x %02x %02x %02x %02x %s %*ph\n", \
+                       _t, _r, _v & 0xff, _v >> 8, _i & 0xff, _i >> 8, \
+                       _l & 0xff, _l >> 8, _direction, _l, _b); \
 }
 
 /* execute firmware command */
@@ -192,7 +192,7 @@ static int airspy_ctrl_msg(struct airspy *s, u8 request, u16 value, u16 index,
                requesttype = (USB_TYPE_VENDOR | USB_DIR_IN);
                break;
        default:
-               dev_err(&s->udev->dev, "Unknown command %02x\n", request);
+               dev_err(s->dev, "Unknown command %02x\n", request);
                ret = -EINVAL;
                goto err;
        }
@@ -203,11 +203,10 @@ static int airspy_ctrl_msg(struct airspy *s, u8 request, u16 value, u16 index,
 
        ret = usb_control_msg(s->udev, pipe, request, requesttype, value,
                        index, s->buf, size, 1000);
-       airspy_dbg_usb_control_msg(s->udev, request, requesttype, value,
+       airspy_dbg_usb_control_msg(s->dev, request, requesttype, value,
                        index, s->buf, size);
        if (ret < 0) {
-               dev_err(&s->udev->dev,
-                               "usb_control_msg() failed %d request %02x\n",
+               dev_err(s->dev, "usb_control_msg() failed %d request %02x\n",
                                ret, request);
                goto err;
        }
@@ -224,7 +223,7 @@ err:
 /* Private functions */
 static struct airspy_frame_buf *airspy_get_next_fill_buf(struct airspy *s)
 {
-       unsigned long flags = 0;
+       unsigned long flags;
        struct airspy_frame_buf *buf = NULL;
 
        spin_lock_irqsave(&s->queued_bufs_lock, flags);
@@ -251,16 +250,18 @@ static unsigned int airspy_convert_stream(struct airspy *s,
                dst_len = 0;
        }
 
-       /* calculate samping rate and output it in 10 seconds intervals */
+       /* calculate sample rate and output it in 10 seconds intervals */
        if (unlikely(time_is_before_jiffies(s->jiffies_next))) {
                #define MSECS 10000UL
+               unsigned int msecs = jiffies_to_msecs(jiffies -
+                               s->jiffies_next + msecs_to_jiffies(MSECS));
                unsigned int samples = s->sample - s->sample_measured;
+
                s->jiffies_next = jiffies + msecs_to_jiffies(MSECS);
                s->sample_measured = s->sample;
-               dev_dbg(&s->udev->dev,
-                               "slen=%d samples=%u msecs=%lu sample rate=%lu\n",
-                               src_len, samples, MSECS,
-                               samples * 1000UL / MSECS);
+               dev_dbg(s->dev, "slen=%u samples=%u msecs=%u sample rate=%lu\n",
+                               src_len, samples, msecs,
+                               samples * 1000UL / msecs);
        }
 
        /* total number of samples */
@@ -278,9 +279,8 @@ static void airspy_urb_complete(struct urb *urb)
        struct airspy *s = urb->context;
        struct airspy_frame_buf *fbuf;
 
-       dev_dbg_ratelimited(&s->udev->dev,
-                       "%s: status=%d length=%d/%d errors=%d\n",
-                       __func__, urb->status, urb->actual_length,
+       dev_dbg_ratelimited(s->dev, "status=%d length=%d/%d errors=%d\n",
+                       urb->status, urb->actual_length,
                        urb->transfer_buffer_length, urb->error_count);
 
        switch (urb->status) {
@@ -292,8 +292,7 @@ static void airspy_urb_complete(struct urb *urb)
        case -ESHUTDOWN:
                return;
        default:            /* error */
-               dev_err_ratelimited(&s->udev->dev, "URB failed %d\n",
-                               urb->status);
+               dev_err_ratelimited(s->dev, "URB failed %d\n", urb->status);
                break;
        }
 
@@ -304,7 +303,7 @@ static void airspy_urb_complete(struct urb *urb)
                fbuf = airspy_get_next_fill_buf(s);
                if (unlikely(fbuf == NULL)) {
                        s->vb_full++;
-                       dev_notice_ratelimited(&s->udev->dev,
+                       dev_notice_ratelimited(s->dev,
                                        "videobuf is full, %d packets dropped\n",
                                        s->vb_full);
                        goto skip;
@@ -328,7 +327,7 @@ static int airspy_kill_urbs(struct airspy *s)
        int i;
 
        for (i = s->urbs_submitted - 1; i >= 0; i--) {
-               dev_dbg(&s->udev->dev, "%s: kill urb=%d\n", __func__, i);
+               dev_dbg(s->dev, "kill urb=%d\n", i);
                /* stop the URB */
                usb_kill_urb(s->urb_list[i]);
        }
@@ -342,11 +341,10 @@ static int airspy_submit_urbs(struct airspy *s)
        int i, ret;
 
        for (i = 0; i < s->urbs_initialized; i++) {
-               dev_dbg(&s->udev->dev, "%s: submit urb=%d\n", __func__, i);
+               dev_dbg(s->dev, "submit urb=%d\n", i);
                ret = usb_submit_urb(s->urb_list[i], GFP_ATOMIC);
                if (ret) {
-                       dev_err(&s->udev->dev,
-                                       "Could not submit URB no. %d - get them all back\n",
+                       dev_err(s->dev, "Could not submit URB no. %d - get them all back\n",
                                        i);
                        airspy_kill_urbs(s);
                        return ret;
@@ -362,8 +360,7 @@ static int airspy_free_stream_bufs(struct airspy *s)
        if (s->flags & USB_STATE_URB_BUF) {
                while (s->buf_num) {
                        s->buf_num--;
-                       dev_dbg(&s->udev->dev, "%s: free buf=%d\n",
-                                       __func__, s->buf_num);
+                       dev_dbg(s->dev, "free buf=%d\n", s->buf_num);
                        usb_free_coherent(s->udev, s->buf_size,
                                          s->buf_list[s->buf_num],
                                          s->dma_addr[s->buf_num]);
@@ -379,23 +376,20 @@ static int airspy_alloc_stream_bufs(struct airspy *s)
        s->buf_num = 0;
        s->buf_size = BULK_BUFFER_SIZE;
 
-       dev_dbg(&s->udev->dev,
-                       "%s: all in all I will use %u bytes for streaming\n",
-                       __func__,  MAX_BULK_BUFS * BULK_BUFFER_SIZE);
+       dev_dbg(s->dev, "all in all I will use %u bytes for streaming\n",
+                       MAX_BULK_BUFS * BULK_BUFFER_SIZE);
 
        for (s->buf_num = 0; s->buf_num < MAX_BULK_BUFS; s->buf_num++) {
                s->buf_list[s->buf_num] = usb_alloc_coherent(s->udev,
                                BULK_BUFFER_SIZE, GFP_ATOMIC,
                                &s->dma_addr[s->buf_num]);
                if (!s->buf_list[s->buf_num]) {
-                       dev_dbg(&s->udev->dev, "%s: alloc buf=%d failed\n",
-                                       __func__, s->buf_num);
+                       dev_dbg(s->dev, "alloc buf=%d failed\n", s->buf_num);
                        airspy_free_stream_bufs(s);
                        return -ENOMEM;
                }
 
-               dev_dbg(&s->udev->dev, "%s: alloc buf=%d %p (dma %llu)\n",
-                               __func__, s->buf_num,
+               dev_dbg(s->dev, "alloc buf=%d %p (dma %llu)\n", s->buf_num,
                                s->buf_list[s->buf_num],
                                (long long)s->dma_addr[s->buf_num]);
                s->flags |= USB_STATE_URB_BUF;
@@ -412,8 +406,7 @@ static int airspy_free_urbs(struct airspy *s)
 
        for (i = s->urbs_initialized - 1; i >= 0; i--) {
                if (s->urb_list[i]) {
-                       dev_dbg(&s->udev->dev, "%s: free urb=%d\n",
-                                       __func__, i);
+                       dev_dbg(s->dev, "free urb=%d\n", i);
                        /* free the URBs */
                        usb_free_urb(s->urb_list[i]);
                }
@@ -429,10 +422,10 @@ static int airspy_alloc_urbs(struct airspy *s)
 
        /* allocate the URBs */
        for (i = 0; i < MAX_BULK_BUFS; i++) {
-               dev_dbg(&s->udev->dev, "%s: alloc urb=%d\n", __func__, i);
+               dev_dbg(s->dev, "alloc urb=%d\n", i);
                s->urb_list[i] = usb_alloc_urb(0, GFP_ATOMIC);
                if (!s->urb_list[i]) {
-                       dev_dbg(&s->udev->dev, "%s: failed\n", __func__);
+                       dev_dbg(s->dev, "failed\n");
                        for (j = 0; j < i; j++)
                                usb_free_urb(s->urb_list[j]);
                        return -ENOMEM;
@@ -455,13 +448,14 @@ static int airspy_alloc_urbs(struct airspy *s)
 /* Must be called with vb_queue_lock hold */
 static void airspy_cleanup_queued_bufs(struct airspy *s)
 {
-       unsigned long flags = 0;
+       unsigned long flags;
 
-       dev_dbg(&s->udev->dev, "%s:\n", __func__);
+       dev_dbg(s->dev, "\n");
 
        spin_lock_irqsave(&s->queued_bufs_lock, flags);
        while (!list_empty(&s->queued_bufs)) {
                struct airspy_frame_buf *buf;
+
                buf = list_entry(s->queued_bufs.next,
                                struct airspy_frame_buf, list);
                list_del(&buf->list);
@@ -476,7 +470,7 @@ static void airspy_disconnect(struct usb_interface *intf)
        struct v4l2_device *v = usb_get_intfdata(intf);
        struct airspy *s = container_of(v, struct airspy, v4l2_dev);
 
-       dev_dbg(&s->udev->dev, "%s:\n", __func__);
+       dev_dbg(s->dev, "\n");
 
        mutex_lock(&s->vb_queue_lock);
        mutex_lock(&s->v4l2_lock);
@@ -497,7 +491,7 @@ static int airspy_queue_setup(struct vb2_queue *vq,
 {
        struct airspy *s = vb2_get_drv_priv(vq);
 
-       dev_dbg(&s->udev->dev, "%s: *nbuffers=%d\n", __func__, *nbuffers);
+       dev_dbg(s->dev, "nbuffers=%d\n", *nbuffers);
 
        /* Need at least 8 buffers */
        if (vq->num_buffers + *nbuffers < 8)
@@ -505,8 +499,7 @@ static int airspy_queue_setup(struct vb2_queue *vq,
        *nplanes = 1;
        sizes[0] = PAGE_ALIGN(s->buffersize);
 
-       dev_dbg(&s->udev->dev, "%s: nbuffers=%d sizes[0]=%d\n",
-                       __func__, *nbuffers, sizes[0]);
+       dev_dbg(s->dev, "nbuffers=%d sizes[0]=%d\n", *nbuffers, sizes[0]);
        return 0;
 }
 
@@ -515,7 +508,7 @@ static void airspy_buf_queue(struct vb2_buffer *vb)
        struct airspy *s = vb2_get_drv_priv(vb->vb2_queue);
        struct airspy_frame_buf *buf =
                        container_of(vb, struct airspy_frame_buf, vb);
-       unsigned long flags = 0;
+       unsigned long flags;
 
        /* Check the device has not disconnected between prep and queuing */
        if (unlikely(!s->udev)) {
@@ -533,34 +526,56 @@ static int airspy_start_streaming(struct vb2_queue *vq, unsigned int count)
        struct airspy *s = vb2_get_drv_priv(vq);
        int ret;
 
-       dev_dbg(&s->udev->dev, "%s:\n", __func__);
+       dev_dbg(s->dev, "\n");
 
        if (!s->udev)
                return -ENODEV;
 
        mutex_lock(&s->v4l2_lock);
 
-       set_bit(POWER_ON, &s->flags);
-
        s->sequence = 0;
 
+       set_bit(POWER_ON, &s->flags);
+
        ret = airspy_alloc_stream_bufs(s);
        if (ret)
-               goto err;
+               goto err_clear_bit;
 
        ret = airspy_alloc_urbs(s);
        if (ret)
-               goto err;
+               goto err_free_stream_bufs;
 
        ret = airspy_submit_urbs(s);
        if (ret)
-               goto err;
+               goto err_free_urbs;
 
        /* start hardware streaming */
        ret = airspy_ctrl_msg(s, CMD_RECEIVER_MODE, 1, 0, NULL, 0);
        if (ret)
-               goto err;
-err:
+               goto err_kill_urbs;
+
+       goto exit_mutex_unlock;
+
+err_kill_urbs:
+       airspy_kill_urbs(s);
+err_free_urbs:
+       airspy_free_urbs(s);
+err_free_stream_bufs:
+       airspy_free_stream_bufs(s);
+err_clear_bit:
+       clear_bit(POWER_ON, &s->flags);
+
+       /* return all queued buffers to vb2 */
+       {
+               struct airspy_frame_buf *buf, *tmp;
+
+               list_for_each_entry_safe(buf, tmp, &s->queued_bufs, list) {
+                       list_del(&buf->list);
+                       vb2_buffer_done(&buf->vb, VB2_BUF_STATE_QUEUED);
+               }
+       }
+
+exit_mutex_unlock:
        mutex_unlock(&s->v4l2_lock);
 
        return ret;
@@ -570,7 +585,7 @@ static void airspy_stop_streaming(struct vb2_queue *vq)
 {
        struct airspy *s = vb2_get_drv_priv(vq);
 
-       dev_dbg(&s->udev->dev, "%s:\n", __func__);
+       dev_dbg(s->dev, "\n");
 
        mutex_lock(&s->v4l2_lock);
 
@@ -602,8 +617,6 @@ static int airspy_querycap(struct file *file, void *fh,
 {
        struct airspy *s = video_drvdata(file);
 
-       dev_dbg(&s->udev->dev, "%s:\n", __func__);
-
        strlcpy(cap->driver, KBUILD_MODNAME, sizeof(cap->driver));
        strlcpy(cap->card, s->vdev.name, sizeof(cap->card));
        usb_make_path(s->udev, cap->bus_info, sizeof(cap->bus_info));
@@ -617,10 +630,6 @@ static int airspy_querycap(struct file *file, void *fh,
 static int airspy_enum_fmt_sdr_cap(struct file *file, void *priv,
                struct v4l2_fmtdesc *f)
 {
-       struct airspy *s = video_drvdata(file);
-
-       dev_dbg(&s->udev->dev, "%s: index=%d\n", __func__, f->index);
-
        if (f->index >= NUM_FORMATS)
                return -EINVAL;
 
@@ -635,9 +644,6 @@ static int airspy_g_fmt_sdr_cap(struct file *file, void *priv,
 {
        struct airspy *s = video_drvdata(file);
 
-       dev_dbg(&s->udev->dev, "%s: pixelformat fourcc %4.4s\n", __func__,
-                       (char *)&s->pixelformat);
-
        f->fmt.sdr.pixelformat = s->pixelformat;
        f->fmt.sdr.buffersize = s->buffersize;
        memset(f->fmt.sdr.reserved, 0, sizeof(f->fmt.sdr.reserved));
@@ -652,9 +658,6 @@ static int airspy_s_fmt_sdr_cap(struct file *file, void *priv,
        struct vb2_queue *q = &s->vb_queue;
        int i;
 
-       dev_dbg(&s->udev->dev, "%s: pixelformat fourcc %4.4s\n", __func__,
-                       (char *)&f->fmt.sdr.pixelformat);
-
        if (vb2_is_busy(q))
                return -EBUSY;
 
@@ -679,12 +682,8 @@ static int airspy_s_fmt_sdr_cap(struct file *file, void *priv,
 static int airspy_try_fmt_sdr_cap(struct file *file, void *priv,
                struct v4l2_format *f)
 {
-       struct airspy *s = video_drvdata(file);
        int i;
 
-       dev_dbg(&s->udev->dev, "%s: pixelformat fourcc %4.4s\n", __func__,
-                       (char *)&f->fmt.sdr.pixelformat);
-
        memset(f->fmt.sdr.reserved, 0, sizeof(f->fmt.sdr.reserved));
        for (i = 0; i < NUM_FORMATS; i++) {
                if (formats[i].pixelformat == f->fmt.sdr.pixelformat) {
@@ -702,11 +701,8 @@ static int airspy_try_fmt_sdr_cap(struct file *file, void *priv,
 static int airspy_s_tuner(struct file *file, void *priv,
                const struct v4l2_tuner *v)
 {
-       struct airspy *s = video_drvdata(file);
        int ret;
 
-       dev_dbg(&s->udev->dev, "%s: index=%d\n", __func__, v->index);
-
        if (v->index == 0)
                ret = 0;
        else if (v->index == 1)
@@ -719,11 +715,8 @@ static int airspy_s_tuner(struct file *file, void *priv,
 
 static int airspy_g_tuner(struct file *file, void *priv, struct v4l2_tuner *v)
 {
-       struct airspy *s = video_drvdata(file);
        int ret;
 
-       dev_dbg(&s->udev->dev, "%s: index=%d\n", __func__, v->index);
-
        if (v->index == 0) {
                strlcpy(v->name, "AirSpy ADC", sizeof(v->name));
                v->type = V4L2_TUNER_ADC;
@@ -749,17 +742,18 @@ static int airspy_g_frequency(struct file *file, void *priv,
                struct v4l2_frequency *f)
 {
        struct airspy *s = video_drvdata(file);
-       int ret  = 0;
-       dev_dbg(&s->udev->dev, "%s: tuner=%d type=%d\n",
-                       __func__, f->tuner, f->type);
+       int ret;
 
        if (f->tuner == 0) {
                f->type = V4L2_TUNER_ADC;
                f->frequency = s->f_adc;
+               dev_dbg(s->dev, "ADC frequency=%u Hz\n", s->f_adc);
                ret = 0;
        } else if (f->tuner == 1) {
                f->type = V4L2_TUNER_RF;
                f->frequency = s->f_rf;
+               dev_dbg(s->dev, "RF frequency=%u Hz\n", s->f_rf);
+               ret = 0;
        } else {
                ret = -EINVAL;
        }
@@ -774,22 +768,17 @@ static int airspy_s_frequency(struct file *file, void *priv,
        int ret;
        u8 buf[4];
 
-       dev_dbg(&s->udev->dev, "%s: tuner=%d type=%d frequency=%u\n",
-                       __func__, f->tuner, f->type, f->frequency);
-
        if (f->tuner == 0) {
                s->f_adc = clamp_t(unsigned int, f->frequency,
                                bands[0].rangelow,
                                bands[0].rangehigh);
-               dev_dbg(&s->udev->dev, "%s: ADC frequency=%u Hz\n",
-                               __func__, s->f_adc);
+               dev_dbg(s->dev, "ADC frequency=%u Hz\n", s->f_adc);
                ret = 0;
        } else if (f->tuner == 1) {
                s->f_rf = clamp_t(unsigned int, f->frequency,
                                bands_rf[0].rangelow,
                                bands_rf[0].rangehigh);
-               dev_dbg(&s->udev->dev, "%s: RF frequency=%u Hz\n",
-                               __func__, s->f_rf);
+               dev_dbg(s->dev, "RF frequency=%u Hz\n", s->f_rf);
                buf[0] = (s->f_rf >>  0) & 0xff;
                buf[1] = (s->f_rf >>  8) & 0xff;
                buf[2] = (s->f_rf >> 16) & 0xff;
@@ -805,10 +794,7 @@ static int airspy_s_frequency(struct file *file, void *priv,
 static int airspy_enum_freq_bands(struct file *file, void *priv,
                struct v4l2_frequency_band *band)
 {
-       struct airspy *s = video_drvdata(file);
        int ret;
-       dev_dbg(&s->udev->dev, "%s: tuner=%d type=%d index=%d\n",
-                       __func__, band->tuner, band->type, band->index);
 
        if (band->tuner == 0) {
                if (band->index >= ARRAY_SIZE(bands)) {
@@ -892,10 +878,9 @@ static int airspy_set_lna_gain(struct airspy *s)
        int ret;
        u8 u8tmp;
 
-       dev_dbg(&s->udev->dev, "%s: lna auto=%d->%d val=%d->%d\n",
-                       __func__, s->lna_gain_auto->cur.val,
-                       s->lna_gain_auto->val, s->lna_gain->cur.val,
-                       s->lna_gain->val);
+       dev_dbg(s->dev, "lna auto=%d->%d val=%d->%d\n",
+                       s->lna_gain_auto->cur.val, s->lna_gain_auto->val,
+                       s->lna_gain->cur.val, s->lna_gain->val);
 
        ret = airspy_ctrl_msg(s, CMD_SET_LNA_AGC, 0, s->lna_gain_auto->val,
                        &u8tmp, 1);
@@ -910,7 +895,7 @@ static int airspy_set_lna_gain(struct airspy *s)
        }
 err:
        if (ret)
-               dev_dbg(&s->udev->dev, "%s: failed=%d\n", __func__, ret);
+               dev_dbg(s->dev, "failed=%d\n", ret);
 
        return ret;
 }
@@ -920,10 +905,9 @@ static int airspy_set_mixer_gain(struct airspy *s)
        int ret;
        u8 u8tmp;
 
-       dev_dbg(&s->udev->dev, "%s: mixer auto=%d->%d val=%d->%d\n",
-                       __func__, s->mixer_gain_auto->cur.val,
-                       s->mixer_gain_auto->val, s->mixer_gain->cur.val,
-                       s->mixer_gain->val);
+       dev_dbg(s->dev, "mixer auto=%d->%d val=%d->%d\n",
+                       s->mixer_gain_auto->cur.val, s->mixer_gain_auto->val,
+                       s->mixer_gain->cur.val, s->mixer_gain->val);
 
        ret = airspy_ctrl_msg(s, CMD_SET_MIXER_AGC, 0, s->mixer_gain_auto->val,
                        &u8tmp, 1);
@@ -938,7 +922,7 @@ static int airspy_set_mixer_gain(struct airspy *s)
        }
 err:
        if (ret)
-               dev_dbg(&s->udev->dev, "%s: failed=%d\n", __func__, ret);
+               dev_dbg(s->dev, "failed=%d\n", ret);
 
        return ret;
 }
@@ -948,8 +932,7 @@ static int airspy_set_if_gain(struct airspy *s)
        int ret;
        u8 u8tmp;
 
-       dev_dbg(&s->udev->dev, "%s: val=%d->%d\n",
-                       __func__, s->if_gain->cur.val, s->if_gain->val);
+       dev_dbg(s->dev, "val=%d->%d\n", s->if_gain->cur.val, s->if_gain->val);
 
        ret = airspy_ctrl_msg(s, CMD_SET_VGA_GAIN, 0, s->if_gain->val,
                        &u8tmp, 1);
@@ -957,7 +940,7 @@ static int airspy_set_if_gain(struct airspy *s)
                goto err;
 err:
        if (ret)
-               dev_dbg(&s->udev->dev, "%s: failed=%d\n", __func__, ret);
+               dev_dbg(s->dev, "failed=%d\n", ret);
 
        return ret;
 }
@@ -980,8 +963,8 @@ static int airspy_s_ctrl(struct v4l2_ctrl *ctrl)
                ret = airspy_set_if_gain(s);
                break;
        default:
-               dev_dbg(&s->udev->dev, "%s: unknown ctrl: id=%d name=%s\n",
-                               __func__, ctrl->id, ctrl->name);
+               dev_dbg(s->dev, "unknown ctrl: id=%d name=%s\n",
+                               ctrl->id, ctrl->name);
                ret = -EINVAL;
        }
 
@@ -995,15 +978,13 @@ static const struct v4l2_ctrl_ops airspy_ctrl_ops = {
 static int airspy_probe(struct usb_interface *intf,
                const struct usb_device_id *id)
 {
-       struct usb_device *udev = interface_to_usbdev(intf);
-       struct airspy *s = NULL;
+       struct airspy *s;
        int ret;
        u8 u8tmp, buf[BUF_SIZE];
 
        s = kzalloc(sizeof(struct airspy), GFP_KERNEL);
        if (s == NULL) {
-               dev_err(&udev->dev,
-                               "Could not allocate memory for airspy state\n");
+               dev_err(&intf->dev, "Could not allocate memory for state\n");
                return -ENOMEM;
        }
 
@@ -1011,7 +992,8 @@ static int airspy_probe(struct usb_interface *intf,
        mutex_init(&s->vb_queue_lock);
        spin_lock_init(&s->queued_bufs_lock);
        INIT_LIST_HEAD(&s->queued_bufs);
-       s->udev = udev;
+       s->dev = &intf->dev;
+       s->udev = interface_to_usbdev(intf);
        s->f_adc = bands[0].rangelow;
        s->f_rf = bands_rf[0].rangelow;
        s->pixelformat = formats[0].pixelformat;
@@ -1023,14 +1005,14 @@ static int airspy_probe(struct usb_interface *intf,
                ret = airspy_ctrl_msg(s, CMD_VERSION_STRING_READ, 0, 0,
                                buf, BUF_SIZE);
        if (ret) {
-               dev_err(&s->udev->dev, "Could not detect board\n");
+               dev_err(s->dev, "Could not detect board\n");
                goto err_free_mem;
        }
 
        buf[BUF_SIZE - 1] = '\0';
 
-       dev_info(&s->udev->dev, "Board ID: %02x\n", u8tmp);
-       dev_info(&s->udev->dev, "Firmware version: %s\n", buf);
+       dev_info(s->dev, "Board ID: %02x\n", u8tmp);
+       dev_info(s->dev, "Firmware version: %s\n", buf);
 
        /* Init videobuf2 queue structure */
        s->vb_queue.type = V4L2_BUF_TYPE_SDR_CAPTURE;
@@ -1042,7 +1024,7 @@ static int airspy_probe(struct usb_interface *intf,
        s->vb_queue.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
        ret = vb2_queue_init(&s->vb_queue);
        if (ret) {
-               dev_err(&s->udev->dev, "Could not initialize vb2 queue\n");
+               dev_err(s->dev, "Could not initialize vb2 queue\n");
                goto err_free_mem;
        }
 
@@ -1056,8 +1038,7 @@ static int airspy_probe(struct usb_interface *intf,
        s->v4l2_dev.release = airspy_video_release;
        ret = v4l2_device_register(&intf->dev, &s->v4l2_dev);
        if (ret) {
-               dev_err(&s->udev->dev,
-                               "Failed to register v4l2-device (%d)\n", ret);
+               dev_err(s->dev, "Failed to register v4l2-device (%d)\n", ret);
                goto err_free_mem;
        }
 
@@ -1077,7 +1058,7 @@ static int airspy_probe(struct usb_interface *intf,
                        V4L2_CID_RF_TUNER_IF_GAIN, 0, 15, 1, 0);
        if (s->hdl.error) {
                ret = s->hdl.error;
-               dev_err(&s->udev->dev, "Could not initialize controls\n");
+               dev_err(s->dev, "Could not initialize controls\n");
                goto err_free_controls;
        }
 
@@ -1089,16 +1070,13 @@ static int airspy_probe(struct usb_interface *intf,
 
        ret = video_register_device(&s->vdev, VFL_TYPE_SDR, -1);
        if (ret) {
-               dev_err(&s->udev->dev,
-                               "Failed to register as video device (%d)\n",
+               dev_err(s->dev, "Failed to register as video device (%d)\n",
                                ret);
                goto err_unregister_v4l2_dev;
        }
-       dev_info(&s->udev->dev, "Registered as %s\n",
+       dev_info(s->dev, "Registered as %s\n",
                        video_device_node_name(&s->vdev));
-       dev_notice(&s->udev->dev,
-                       "%s: SDR API is still slightly experimental and functionality changes may follow\n",
-                       KBUILD_MODNAME);
+       dev_notice(s->dev, "SDR API is still slightly experimental and functionality changes may follow\n");
        return 0;
 
 err_free_controls:
diff --git a/drivers/media/usb/as102/Kconfig b/drivers/media/usb/as102/Kconfig
new file mode 100644 (file)
index 0000000..28aba00
--- /dev/null
@@ -0,0 +1,8 @@
+config DVB_AS102
+       tristate "Abilis AS102 DVB receiver"
+       depends on DVB_CORE && USB && I2C && INPUT
+       select FW_LOADER
+       help
+         Choose Y or M here if you have a device containing an AS102
+
+         To compile this driver as a module, choose M here
diff --git a/drivers/media/usb/as102/Makefile b/drivers/media/usb/as102/Makefile
new file mode 100644 (file)
index 0000000..22f43ee
--- /dev/null
@@ -0,0 +1,7 @@
+dvb-as102-objs := as102_drv.o as102_fw.o as10x_cmd.o as10x_cmd_stream.o \
+                 as102_usb_drv.o as10x_cmd_cfg.o
+
+obj-$(CONFIG_DVB_AS102) += dvb-as102.o
+
+ccflags-y += -Idrivers/media/dvb-core
+ccflags-y += -Idrivers/media/dvb-frontends
diff --git a/drivers/media/usb/as102/as102_drv.c b/drivers/media/usb/as102/as102_drv.c
new file mode 100644 (file)
index 0000000..8be1474
--- /dev/null
@@ -0,0 +1,401 @@
+/*
+ * Abilis Systems Single DVB-T Receiver
+ * Copyright (C) 2008 Pierrick Hascoet <pierrick.hascoet@abilis.com>
+ * Copyright (C) 2010 Devin Heitmueller <dheitmueller@kernellabs.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, 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/kernel.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/mm.h>
+#include <linux/kref.h>
+#include <linux/uaccess.h>
+#include <linux/usb.h>
+
+/* header file for usb device driver*/
+#include "as102_drv.h"
+#include "as10x_cmd.h"
+#include "as102_fe.h"
+#include "as102_fw.h"
+#include "dvbdev.h"
+
+int dual_tuner;
+module_param_named(dual_tuner, dual_tuner, int, 0644);
+MODULE_PARM_DESC(dual_tuner, "Activate Dual-Tuner config (default: off)");
+
+static int fw_upload = 1;
+module_param_named(fw_upload, fw_upload, int, 0644);
+MODULE_PARM_DESC(fw_upload, "Turn on/off default FW upload (default: on)");
+
+static int pid_filtering;
+module_param_named(pid_filtering, pid_filtering, int, 0644);
+MODULE_PARM_DESC(pid_filtering, "Activate HW PID filtering (default: off)");
+
+static int ts_auto_disable;
+module_param_named(ts_auto_disable, ts_auto_disable, int, 0644);
+MODULE_PARM_DESC(ts_auto_disable, "Stream Auto Enable on FW (default: off)");
+
+int elna_enable = 1;
+module_param_named(elna_enable, elna_enable, int, 0644);
+MODULE_PARM_DESC(elna_enable, "Activate eLNA (default: on)");
+
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
+static void as102_stop_stream(struct as102_dev_t *dev)
+{
+       struct as10x_bus_adapter_t *bus_adap;
+
+       if (dev != NULL)
+               bus_adap = &dev->bus_adap;
+       else
+               return;
+
+       if (bus_adap->ops->stop_stream != NULL)
+               bus_adap->ops->stop_stream(dev);
+
+       if (ts_auto_disable) {
+               if (mutex_lock_interruptible(&dev->bus_adap.lock))
+                       return;
+
+               if (as10x_cmd_stop_streaming(bus_adap) < 0)
+                       dev_dbg(&dev->bus_adap.usb_dev->dev,
+                               "as10x_cmd_stop_streaming failed\n");
+
+               mutex_unlock(&dev->bus_adap.lock);
+       }
+}
+
+static int as102_start_stream(struct as102_dev_t *dev)
+{
+       struct as10x_bus_adapter_t *bus_adap;
+       int ret = -EFAULT;
+
+       if (dev != NULL)
+               bus_adap = &dev->bus_adap;
+       else
+               return ret;
+
+       if (bus_adap->ops->start_stream != NULL)
+               ret = bus_adap->ops->start_stream(dev);
+
+       if (ts_auto_disable) {
+               if (mutex_lock_interruptible(&dev->bus_adap.lock))
+                       return -EFAULT;
+
+               ret = as10x_cmd_start_streaming(bus_adap);
+
+               mutex_unlock(&dev->bus_adap.lock);
+       }
+
+       return ret;
+}
+
+static int as10x_pid_filter(struct as102_dev_t *dev,
+                           int index, u16 pid, int onoff) {
+
+       struct as10x_bus_adapter_t *bus_adap = &dev->bus_adap;
+       int ret = -EFAULT;
+
+       if (mutex_lock_interruptible(&dev->bus_adap.lock)) {
+               dev_dbg(&dev->bus_adap.usb_dev->dev,
+                       "amutex_lock_interruptible(lock) failed !\n");
+               return -EBUSY;
+       }
+
+       switch (onoff) {
+       case 0:
+               ret = as10x_cmd_del_PID_filter(bus_adap, (uint16_t) pid);
+               dev_dbg(&dev->bus_adap.usb_dev->dev,
+                       "DEL_PID_FILTER([%02d] 0x%04x) ret = %d\n",
+                       index, pid, ret);
+               break;
+       case 1:
+       {
+               struct as10x_ts_filter filter;
+
+               filter.type = TS_PID_TYPE_TS;
+               filter.idx = 0xFF;
+               filter.pid = pid;
+
+               ret = as10x_cmd_add_PID_filter(bus_adap, &filter);
+               dev_dbg(&dev->bus_adap.usb_dev->dev,
+                       "ADD_PID_FILTER([%02d -> %02d], 0x%04x) ret = %d\n",
+                       index, filter.idx, filter.pid, ret);
+               break;
+       }
+       }
+
+       mutex_unlock(&dev->bus_adap.lock);
+       return ret;
+}
+
+static int as102_dvb_dmx_start_feed(struct dvb_demux_feed *dvbdmxfeed)
+{
+       int ret = 0;
+       struct dvb_demux *demux = dvbdmxfeed->demux;
+       struct as102_dev_t *as102_dev = demux->priv;
+
+       if (mutex_lock_interruptible(&as102_dev->sem))
+               return -ERESTARTSYS;
+
+       if (pid_filtering)
+               as10x_pid_filter(as102_dev, dvbdmxfeed->index,
+                                dvbdmxfeed->pid, 1);
+
+       if (as102_dev->streaming++ == 0)
+               ret = as102_start_stream(as102_dev);
+
+       mutex_unlock(&as102_dev->sem);
+       return ret;
+}
+
+static int as102_dvb_dmx_stop_feed(struct dvb_demux_feed *dvbdmxfeed)
+{
+       struct dvb_demux *demux = dvbdmxfeed->demux;
+       struct as102_dev_t *as102_dev = demux->priv;
+
+       if (mutex_lock_interruptible(&as102_dev->sem))
+               return -ERESTARTSYS;
+
+       if (--as102_dev->streaming == 0)
+               as102_stop_stream(as102_dev);
+
+       if (pid_filtering)
+               as10x_pid_filter(as102_dev, dvbdmxfeed->index,
+                                dvbdmxfeed->pid, 0);
+
+       mutex_unlock(&as102_dev->sem);
+       return 0;
+}
+
+static int as102_set_tune(void *priv, struct as10x_tune_args *tune_args)
+{
+       struct as10x_bus_adapter_t *bus_adap = priv;
+       int ret;
+
+       /* Set frontend arguments */
+       if (mutex_lock_interruptible(&bus_adap->lock))
+               return -EBUSY;
+
+       ret =  as10x_cmd_set_tune(bus_adap, tune_args);
+       if (ret != 0)
+               dev_dbg(&bus_adap->usb_dev->dev,
+                       "as10x_cmd_set_tune failed. (err = %d)\n", ret);
+
+       mutex_unlock(&bus_adap->lock);
+
+       return ret;
+}
+
+static int as102_get_tps(void *priv, struct as10x_tps *tps)
+{
+       struct as10x_bus_adapter_t *bus_adap = priv;
+       int ret;
+
+       if (mutex_lock_interruptible(&bus_adap->lock))
+               return -EBUSY;
+
+       /* send abilis command: GET_TPS */
+       ret = as10x_cmd_get_tps(bus_adap, tps);
+
+       mutex_unlock(&bus_adap->lock);
+
+       return ret;
+}
+
+static int as102_get_status(void *priv, struct as10x_tune_status *tstate)
+{
+       struct as10x_bus_adapter_t *bus_adap = priv;
+       int ret;
+
+       if (mutex_lock_interruptible(&bus_adap->lock))
+               return -EBUSY;
+
+       /* send abilis command: GET_TUNE_STATUS */
+       ret = as10x_cmd_get_tune_status(bus_adap, tstate);
+       if (ret < 0) {
+               dev_dbg(&bus_adap->usb_dev->dev,
+                       "as10x_cmd_get_tune_status failed (err = %d)\n",
+                       ret);
+       }
+
+       mutex_unlock(&bus_adap->lock);
+
+       return ret;
+}
+
+static int as102_get_stats(void *priv, struct as10x_demod_stats *demod_stats)
+{
+       struct as10x_bus_adapter_t *bus_adap = priv;
+       int ret;
+
+       if (mutex_lock_interruptible(&bus_adap->lock))
+               return -EBUSY;
+
+       /* send abilis command: GET_TUNE_STATUS */
+       ret = as10x_cmd_get_demod_stats(bus_adap, demod_stats);
+       if (ret < 0) {
+               dev_dbg(&bus_adap->usb_dev->dev,
+                       "as10x_cmd_get_demod_stats failed (probably not tuned)\n");
+       } else {
+               dev_dbg(&bus_adap->usb_dev->dev,
+                       "demod status: fc: 0x%08x, bad fc: 0x%08x, bytes corrected: 0x%08x , MER: 0x%04x\n",
+                       demod_stats->frame_count,
+                       demod_stats->bad_frame_count,
+                       demod_stats->bytes_fixed_by_rs,
+                       demod_stats->mer);
+       }
+       mutex_unlock(&bus_adap->lock);
+
+       return ret;
+}
+
+static int as102_stream_ctrl(void *priv, int acquire, uint32_t elna_cfg)
+{
+       struct as10x_bus_adapter_t *bus_adap = priv;
+       int ret;
+
+       if (mutex_lock_interruptible(&bus_adap->lock))
+               return -EBUSY;
+
+       if (acquire) {
+               if (elna_enable)
+                       as10x_cmd_set_context(bus_adap,
+                                             CONTEXT_LNA, elna_cfg);
+
+               ret = as10x_cmd_turn_on(bus_adap);
+       } else {
+               ret = as10x_cmd_turn_off(bus_adap);
+       }
+
+       mutex_unlock(&bus_adap->lock);
+
+       return ret;
+}
+
+static const struct as102_fe_ops as102_fe_ops = {
+       .set_tune = as102_set_tune,
+       .get_tps  = as102_get_tps,
+       .get_status = as102_get_status,
+       .get_stats = as102_get_stats,
+       .stream_ctrl = as102_stream_ctrl,
+};
+
+int as102_dvb_register(struct as102_dev_t *as102_dev)
+{
+       struct device *dev = &as102_dev->bus_adap.usb_dev->dev;
+       int ret;
+
+       ret = dvb_register_adapter(&as102_dev->dvb_adap,
+                          as102_dev->name, THIS_MODULE,
+                          dev, adapter_nr);
+       if (ret < 0) {
+               dev_err(dev, "%s: dvb_register_adapter() failed: %d\n",
+                       __func__, ret);
+               return ret;
+       }
+
+       as102_dev->dvb_dmx.priv = as102_dev;
+       as102_dev->dvb_dmx.filternum = pid_filtering ? 16 : 256;
+       as102_dev->dvb_dmx.feednum = 256;
+       as102_dev->dvb_dmx.start_feed = as102_dvb_dmx_start_feed;
+       as102_dev->dvb_dmx.stop_feed = as102_dvb_dmx_stop_feed;
+
+       as102_dev->dvb_dmx.dmx.capabilities = DMX_TS_FILTERING |
+                                             DMX_SECTION_FILTERING;
+
+       as102_dev->dvb_dmxdev.filternum = as102_dev->dvb_dmx.filternum;
+       as102_dev->dvb_dmxdev.demux = &as102_dev->dvb_dmx.dmx;
+       as102_dev->dvb_dmxdev.capabilities = 0;
+
+       ret = dvb_dmx_init(&as102_dev->dvb_dmx);
+       if (ret < 0) {
+               dev_err(dev, "%s: dvb_dmx_init() failed: %d\n", __func__, ret);
+               goto edmxinit;
+       }
+
+       ret = dvb_dmxdev_init(&as102_dev->dvb_dmxdev, &as102_dev->dvb_adap);
+       if (ret < 0) {
+               dev_err(dev, "%s: dvb_dmxdev_init() failed: %d\n",
+                       __func__, ret);
+               goto edmxdinit;
+       }
+
+       /* Attach the frontend */
+       as102_dev->dvb_fe = dvb_attach(as102_attach, as102_dev->name,
+                                      &as102_fe_ops,
+                                      &as102_dev->bus_adap,
+                                      as102_dev->elna_cfg);
+       if (!as102_dev->dvb_fe) {
+               dev_err(dev, "%s: as102_attach() failed: %d",
+                   __func__, ret);
+               goto efereg;
+       }
+
+       ret =  dvb_register_frontend(&as102_dev->dvb_adap, as102_dev->dvb_fe);
+       if (ret < 0) {
+               dev_err(dev, "%s: as102_dvb_register_frontend() failed: %d",
+                   __func__, ret);
+               goto efereg;
+       }
+
+       /* init bus mutex for token locking */
+       mutex_init(&as102_dev->bus_adap.lock);
+
+       /* init start / stop stream mutex */
+       mutex_init(&as102_dev->sem);
+
+       /*
+        * try to load as102 firmware. If firmware upload failed, we'll be
+        * able to upload it later.
+        */
+       if (fw_upload)
+               try_then_request_module(as102_fw_upload(&as102_dev->bus_adap),
+                               "firmware_class");
+
+       pr_info("Registered device %s", as102_dev->name);
+       return 0;
+
+efereg:
+       dvb_dmxdev_release(&as102_dev->dvb_dmxdev);
+edmxdinit:
+       dvb_dmx_release(&as102_dev->dvb_dmx);
+edmxinit:
+       dvb_unregister_adapter(&as102_dev->dvb_adap);
+       return ret;
+}
+
+void as102_dvb_unregister(struct as102_dev_t *as102_dev)
+{
+       /* unregister as102 frontend */
+       dvb_unregister_frontend(as102_dev->dvb_fe);
+
+       /* detach frontend */
+       dvb_frontend_detach(as102_dev->dvb_fe);
+
+       /* unregister demux device */
+       dvb_dmxdev_release(&as102_dev->dvb_dmxdev);
+       dvb_dmx_release(&as102_dev->dvb_dmx);
+
+       /* unregister dvb adapter */
+       dvb_unregister_adapter(&as102_dev->dvb_adap);
+
+       pr_info("Unregistered device %s", as102_dev->name);
+}
+
+module_usb_driver(as102_usb_driver);
+
+/* modinfo details */
+MODULE_DESCRIPTION(DRIVER_FULL_NAME);
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Pierrick Hascoet <pierrick.hascoet@abilis.com>");
diff --git a/drivers/media/usb/as102/as102_drv.h b/drivers/media/usb/as102/as102_drv.h
new file mode 100644 (file)
index 0000000..aee2d76
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+ * Abilis Systems Single DVB-T Receiver
+ * Copyright (C) 2008 Pierrick Hascoet <pierrick.hascoet@abilis.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, 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 _AS102_DRV_H
+#define _AS102_DRV_H
+#include <linux/usb.h>
+#include <dvb_demux.h>
+#include <dvb_frontend.h>
+#include <dmxdev.h>
+#include "as10x_handle.h"
+#include "as10x_cmd.h"
+#include "as102_usb_drv.h"
+
+#define DRIVER_FULL_NAME "Abilis Systems as10x usb driver"
+#define DRIVER_NAME "as10x_usb"
+
+#define debug  as102_debug
+extern struct usb_driver as102_usb_driver;
+extern int elna_enable;
+
+#define AS102_DEVICE_MAJOR     192
+
+#define AS102_USB_BUF_SIZE     512
+#define MAX_STREAM_URB         32
+
+struct as10x_bus_adapter_t {
+       struct usb_device *usb_dev;
+       /* bus token lock */
+       struct mutex lock;
+       /* low level interface for bus adapter */
+       union as10x_bus_token_t {
+               /* usb token */
+               struct as10x_usb_token_cmd_t usb;
+       } token;
+
+       /* token cmd xfer id */
+       uint16_t cmd_xid;
+
+       /* as10x command and response for dvb interface*/
+       struct as10x_cmd_t *cmd, *rsp;
+
+       /* bus adapter private ops callback */
+       struct as102_priv_ops_t *ops;
+};
+
+struct as102_dev_t {
+       const char *name;
+       struct as10x_bus_adapter_t bus_adap;
+       struct list_head device_entry;
+       struct kref kref;
+       uint8_t elna_cfg;
+
+       struct dvb_adapter dvb_adap;
+       struct dvb_frontend *dvb_fe;
+       struct dvb_demux dvb_dmx;
+       struct dmxdev dvb_dmxdev;
+
+       /* timer handle to trig ts stream download */
+       struct timer_list timer_handle;
+
+       struct mutex sem;
+       dma_addr_t dma_addr;
+       void *stream;
+       int streaming;
+       struct urb *stream_urb[MAX_STREAM_URB];
+};
+
+int as102_dvb_register(struct as102_dev_t *dev);
+void as102_dvb_unregister(struct as102_dev_t *dev);
+
+#endif
diff --git a/drivers/media/usb/as102/as102_fw.c b/drivers/media/usb/as102/as102_fw.c
new file mode 100644 (file)
index 0000000..07d08c4
--- /dev/null
@@ -0,0 +1,228 @@
+/*
+ * Abilis Systems Single DVB-T Receiver
+ * Copyright (C) 2008 Pierrick Hascoet <pierrick.hascoet@abilis.com>
+ * Copyright (C) 2010 Devin Heitmueller <dheitmueller@kernellabs.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, 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/kernel.h>
+#include <linux/errno.h>
+#include <linux/ctype.h>
+#include <linux/delay.h>
+#include <linux/firmware.h>
+
+#include "as102_drv.h"
+#include "as102_fw.h"
+
+static const char as102_st_fw1[] = "as102_data1_st.hex";
+static const char as102_st_fw2[] = "as102_data2_st.hex";
+static const char as102_dt_fw1[] = "as102_data1_dt.hex";
+static const char as102_dt_fw2[] = "as102_data2_dt.hex";
+
+static unsigned char atohx(unsigned char *dst, char *src)
+{
+       unsigned char value = 0;
+
+       char msb = tolower(*src) - '0';
+       char lsb = tolower(*(src + 1)) - '0';
+
+       if (msb > 9)
+               msb -= 7;
+       if (lsb > 9)
+               lsb -= 7;
+
+       *dst = value = ((msb & 0xF) << 4) | (lsb & 0xF);
+       return value;
+}
+
+/*
+ * Parse INTEL HEX firmware file to extract address and data.
+ */
+static int parse_hex_line(unsigned char *fw_data, unsigned char *addr,
+                         unsigned char *data, int *dataLength,
+                         unsigned char *addr_has_changed) {
+
+       int count = 0;
+       unsigned char *src, dst;
+
+       if (*fw_data++ != ':') {
+               pr_err("invalid firmware file\n");
+               return -EFAULT;
+       }
+
+       /* locate end of line */
+       for (src = fw_data; *src != '\n'; src += 2) {
+               atohx(&dst, src);
+               /* parse line to split addr / data */
+               switch (count) {
+               case 0:
+                       *dataLength = dst;
+                       break;
+               case 1:
+                       addr[2] = dst;
+                       break;
+               case 2:
+                       addr[3] = dst;
+                       break;
+               case 3:
+                       /* check if data is an address */
+                       if (dst == 0x04)
+                               *addr_has_changed = 1;
+                       else
+                               *addr_has_changed = 0;
+                       break;
+               case  4:
+               case  5:
+                       if (*addr_has_changed)
+                               addr[(count - 4)] = dst;
+                       else
+                               data[(count - 4)] = dst;
+                       break;
+               default:
+                       data[(count - 4)] = dst;
+                       break;
+               }
+               count++;
+       }
+
+       /* return read value + ':' + '\n' */
+       return (count * 2) + 2;
+}
+
+static int as102_firmware_upload(struct as10x_bus_adapter_t *bus_adap,
+                                unsigned char *cmd,
+                                const struct firmware *firmware) {
+
+       struct as10x_fw_pkt_t fw_pkt;
+       int total_read_bytes = 0, errno = 0;
+       unsigned char addr_has_changed = 0;
+
+       for (total_read_bytes = 0; total_read_bytes < firmware->size; ) {
+               int read_bytes = 0, data_len = 0;
+
+               /* parse intel hex line */
+               read_bytes = parse_hex_line(
+                               (u8 *) (firmware->data + total_read_bytes),
+                               fw_pkt.raw.address,
+                               fw_pkt.raw.data,
+                               &data_len,
+                               &addr_has_changed);
+
+               if (read_bytes <= 0)
+                       goto error;
+
+               /* detect the end of file */
+               total_read_bytes += read_bytes;
+               if (total_read_bytes == firmware->size) {
+                       fw_pkt.u.request[0] = 0x00;
+                       fw_pkt.u.request[1] = 0x03;
+
+                       /* send EOF command */
+                       errno = bus_adap->ops->upload_fw_pkt(bus_adap,
+                                                            (uint8_t *)
+                                                            &fw_pkt, 2, 0);
+                       if (errno < 0)
+                               goto error;
+               } else {
+                       if (!addr_has_changed) {
+                               /* prepare command to send */
+                               fw_pkt.u.request[0] = 0x00;
+                               fw_pkt.u.request[1] = 0x01;
+
+                               data_len += sizeof(fw_pkt.u.request);
+                               data_len += sizeof(fw_pkt.raw.address);
+
+                               /* send cmd to device */
+                               errno = bus_adap->ops->upload_fw_pkt(bus_adap,
+                                                                    (uint8_t *)
+                                                                    &fw_pkt,
+                                                                    data_len,
+                                                                    0);
+                               if (errno < 0)
+                                       goto error;
+                       }
+               }
+       }
+error:
+       return (errno == 0) ? total_read_bytes : errno;
+}
+
+int as102_fw_upload(struct as10x_bus_adapter_t *bus_adap)
+{
+       int errno = -EFAULT;
+       const struct firmware *firmware = NULL;
+       unsigned char *cmd_buf = NULL;
+       const char *fw1, *fw2;
+       struct usb_device *dev = bus_adap->usb_dev;
+
+       /* select fw file to upload */
+       if (dual_tuner) {
+               fw1 = as102_dt_fw1;
+               fw2 = as102_dt_fw2;
+       } else {
+               fw1 = as102_st_fw1;
+               fw2 = as102_st_fw2;
+       }
+
+       /* allocate buffer to store firmware upload command and data */
+       cmd_buf = kzalloc(MAX_FW_PKT_SIZE, GFP_KERNEL);
+       if (cmd_buf == NULL) {
+               errno = -ENOMEM;
+               goto error;
+       }
+
+       /* request kernel to locate firmware file: part1 */
+       errno = request_firmware(&firmware, fw1, &dev->dev);
+       if (errno < 0) {
+               pr_err("%s: unable to locate firmware file: %s\n",
+                      DRIVER_NAME, fw1);
+               goto error;
+       }
+
+       /* initiate firmware upload */
+       errno = as102_firmware_upload(bus_adap, cmd_buf, firmware);
+       if (errno < 0) {
+               pr_err("%s: error during firmware upload part1\n",
+                      DRIVER_NAME);
+               goto error;
+       }
+
+       pr_info("%s: firmware: %s loaded with success\n",
+               DRIVER_NAME, fw1);
+       release_firmware(firmware);
+
+       /* wait for boot to complete */
+       mdelay(100);
+
+       /* request kernel to locate firmware file: part2 */
+       errno = request_firmware(&firmware, fw2, &dev->dev);
+       if (errno < 0) {
+               pr_err("%s: unable to locate firmware file: %s\n",
+                      DRIVER_NAME, fw2);
+               goto error;
+       }
+
+       /* initiate firmware upload */
+       errno = as102_firmware_upload(bus_adap, cmd_buf, firmware);
+       if (errno < 0) {
+               pr_err("%s: error during firmware upload part2\n",
+                      DRIVER_NAME);
+               goto error;
+       }
+
+       pr_info("%s: firmware: %s loaded with success\n",
+               DRIVER_NAME, fw2);
+error:
+       kfree(cmd_buf);
+       release_firmware(firmware);
+
+       return errno;
+}
diff --git a/drivers/media/usb/as102/as102_fw.h b/drivers/media/usb/as102/as102_fw.h
new file mode 100644 (file)
index 0000000..2732b78
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * Abilis Systems Single DVB-T Receiver
+ * Copyright (C) 2008 Pierrick Hascoet <pierrick.hascoet@abilis.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, 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 MAX_FW_PKT_SIZE        64
+
+extern int dual_tuner;
+
+struct as10x_raw_fw_pkt {
+       unsigned char address[4];
+       unsigned char data[MAX_FW_PKT_SIZE - 6];
+} __packed;
+
+struct as10x_fw_pkt_t {
+       union {
+               unsigned char request[2];
+               unsigned char length[2];
+       } __packed u;
+       struct as10x_raw_fw_pkt raw;
+} __packed;
+
+#ifdef __KERNEL__
+int as102_fw_upload(struct as10x_bus_adapter_t *bus_adap);
+#endif
diff --git a/drivers/media/usb/as102/as102_usb_drv.c b/drivers/media/usb/as102/as102_usb_drv.c
new file mode 100644 (file)
index 0000000..3f66906
--- /dev/null
@@ -0,0 +1,475 @@
+/*
+ * Abilis Systems Single DVB-T Receiver
+ * Copyright (C) 2008 Pierrick Hascoet <pierrick.hascoet@abilis.com>
+ * Copyright (C) 2010 Devin Heitmueller <dheitmueller@kernellabs.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, 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/kernel.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/mm.h>
+#include <linux/usb.h>
+
+#include "as102_drv.h"
+#include "as102_usb_drv.h"
+#include "as102_fw.h"
+
+static void as102_usb_disconnect(struct usb_interface *interface);
+static int as102_usb_probe(struct usb_interface *interface,
+                          const struct usb_device_id *id);
+
+static int as102_usb_start_stream(struct as102_dev_t *dev);
+static void as102_usb_stop_stream(struct as102_dev_t *dev);
+
+static int as102_open(struct inode *inode, struct file *file);
+static int as102_release(struct inode *inode, struct file *file);
+
+static struct usb_device_id as102_usb_id_table[] = {
+       { USB_DEVICE(AS102_USB_DEVICE_VENDOR_ID, AS102_USB_DEVICE_PID_0001) },
+       { USB_DEVICE(PCTV_74E_USB_VID, PCTV_74E_USB_PID) },
+       { USB_DEVICE(ELGATO_EYETV_DTT_USB_VID, ELGATO_EYETV_DTT_USB_PID) },
+       { USB_DEVICE(NBOX_DVBT_DONGLE_USB_VID, NBOX_DVBT_DONGLE_USB_PID) },
+       { USB_DEVICE(SKY_IT_DIGITAL_KEY_USB_VID, SKY_IT_DIGITAL_KEY_USB_PID) },
+       { } /* Terminating entry */
+};
+
+/* Note that this table must always have the same number of entries as the
+   as102_usb_id_table struct */
+static const char * const as102_device_names[] = {
+       AS102_REFERENCE_DESIGN,
+       AS102_PCTV_74E,
+       AS102_ELGATO_EYETV_DTT_NAME,
+       AS102_NBOX_DVBT_DONGLE_NAME,
+       AS102_SKY_IT_DIGITAL_KEY_NAME,
+       NULL /* Terminating entry */
+};
+
+/* eLNA configuration: devices built on the reference design work best
+   with 0xA0, while custom designs seem to require 0xC0 */
+static uint8_t const as102_elna_cfg[] = {
+       0xA0,
+       0xC0,
+       0xC0,
+       0xA0,
+       0xA0,
+       0x00 /* Terminating entry */
+};
+
+struct usb_driver as102_usb_driver = {
+       .name           = DRIVER_FULL_NAME,
+       .probe          = as102_usb_probe,
+       .disconnect     = as102_usb_disconnect,
+       .id_table       = as102_usb_id_table
+};
+
+static const struct file_operations as102_dev_fops = {
+       .owner          = THIS_MODULE,
+       .open           = as102_open,
+       .release        = as102_release,
+};
+
+static struct usb_class_driver as102_usb_class_driver = {
+       .name           = "aton2-%d",
+       .fops           = &as102_dev_fops,
+       .minor_base     = AS102_DEVICE_MAJOR,
+};
+
+static int as102_usb_xfer_cmd(struct as10x_bus_adapter_t *bus_adap,
+                             unsigned char *send_buf, int send_buf_len,
+                             unsigned char *recv_buf, int recv_buf_len)
+{
+       int ret = 0;
+
+       if (send_buf != NULL) {
+               ret = usb_control_msg(bus_adap->usb_dev,
+                                     usb_sndctrlpipe(bus_adap->usb_dev, 0),
+                                     AS102_USB_DEVICE_TX_CTRL_CMD,
+                                     USB_DIR_OUT | USB_TYPE_VENDOR |
+                                     USB_RECIP_DEVICE,
+                                     bus_adap->cmd_xid, /* value */
+                                     0, /* index */
+                                     send_buf, send_buf_len,
+                                     USB_CTRL_SET_TIMEOUT /* 200 */);
+               if (ret < 0) {
+                       dev_dbg(&bus_adap->usb_dev->dev,
+                               "usb_control_msg(send) failed, err %i\n", ret);
+                       return ret;
+               }
+
+               if (ret != send_buf_len) {
+                       dev_dbg(&bus_adap->usb_dev->dev,
+                       "only wrote %d of %d bytes\n", ret, send_buf_len);
+                       return -1;
+               }
+       }
+
+       if (recv_buf != NULL) {
+#ifdef TRACE
+               dev_dbg(bus_adap->usb_dev->dev,
+                       "want to read: %d bytes\n", recv_buf_len);
+#endif
+               ret = usb_control_msg(bus_adap->usb_dev,
+                                     usb_rcvctrlpipe(bus_adap->usb_dev, 0),
+                                     AS102_USB_DEVICE_RX_CTRL_CMD,
+                                     USB_DIR_IN | USB_TYPE_VENDOR |
+                                     USB_RECIP_DEVICE,
+                                     bus_adap->cmd_xid, /* value */
+                                     0, /* index */
+                                     recv_buf, recv_buf_len,
+                                     USB_CTRL_GET_TIMEOUT /* 200 */);
+               if (ret < 0) {
+                       dev_dbg(&bus_adap->usb_dev->dev,
+                               "usb_control_msg(recv) failed, err %i\n", ret);
+                       return ret;
+               }
+#ifdef TRACE
+               dev_dbg(bus_adap->usb_dev->dev,
+                       "read %d bytes\n", recv_buf_len);
+#endif
+       }
+
+       return ret;
+}
+
+static int as102_send_ep1(struct as10x_bus_adapter_t *bus_adap,
+                         unsigned char *send_buf,
+                         int send_buf_len,
+                         int swap32)
+{
+       int ret, actual_len;
+
+       ret = usb_bulk_msg(bus_adap->usb_dev,
+                          usb_sndbulkpipe(bus_adap->usb_dev, 1),
+                          send_buf, send_buf_len, &actual_len, 200);
+       if (ret) {
+               dev_dbg(&bus_adap->usb_dev->dev,
+                       "usb_bulk_msg(send) failed, err %i\n", ret);
+               return ret;
+       }
+
+       if (actual_len != send_buf_len) {
+               dev_dbg(&bus_adap->usb_dev->dev, "only wrote %d of %d bytes\n",
+                       actual_len, send_buf_len);
+               return -1;
+       }
+       return actual_len;
+}
+
+static int as102_read_ep2(struct as10x_bus_adapter_t *bus_adap,
+                  unsigned char *recv_buf, int recv_buf_len)
+{
+       int ret, actual_len;
+
+       if (recv_buf == NULL)
+               return -EINVAL;
+
+       ret = usb_bulk_msg(bus_adap->usb_dev,
+                          usb_rcvbulkpipe(bus_adap->usb_dev, 2),
+                          recv_buf, recv_buf_len, &actual_len, 200);
+       if (ret) {
+               dev_dbg(&bus_adap->usb_dev->dev,
+                       "usb_bulk_msg(recv) failed, err %i\n", ret);
+               return ret;
+       }
+
+       if (actual_len != recv_buf_len) {
+               dev_dbg(&bus_adap->usb_dev->dev, "only read %d of %d bytes\n",
+                       actual_len, recv_buf_len);
+               return -1;
+       }
+       return actual_len;
+}
+
+static struct as102_priv_ops_t as102_priv_ops = {
+       .upload_fw_pkt  = as102_send_ep1,
+       .xfer_cmd       = as102_usb_xfer_cmd,
+       .as102_read_ep2 = as102_read_ep2,
+       .start_stream   = as102_usb_start_stream,
+       .stop_stream    = as102_usb_stop_stream,
+};
+
+static int as102_submit_urb_stream(struct as102_dev_t *dev, struct urb *urb)
+{
+       int err;
+
+       usb_fill_bulk_urb(urb,
+                         dev->bus_adap.usb_dev,
+                         usb_rcvbulkpipe(dev->bus_adap.usb_dev, 0x2),
+                         urb->transfer_buffer,
+                         AS102_USB_BUF_SIZE,
+                         as102_urb_stream_irq,
+                         dev);
+
+       err = usb_submit_urb(urb, GFP_ATOMIC);
+       if (err)
+               dev_dbg(&urb->dev->dev,
+                       "%s: usb_submit_urb failed\n", __func__);
+
+       return err;
+}
+
+void as102_urb_stream_irq(struct urb *urb)
+{
+       struct as102_dev_t *as102_dev = urb->context;
+
+       if (urb->actual_length > 0) {
+               dvb_dmx_swfilter(&as102_dev->dvb_dmx,
+                                urb->transfer_buffer,
+                                urb->actual_length);
+       } else {
+               if (urb->actual_length == 0)
+                       memset(urb->transfer_buffer, 0, AS102_USB_BUF_SIZE);
+       }
+
+       /* is not stopped, re-submit urb */
+       if (as102_dev->streaming)
+               as102_submit_urb_stream(as102_dev, urb);
+}
+
+static void as102_free_usb_stream_buffer(struct as102_dev_t *dev)
+{
+       int i;
+
+       for (i = 0; i < MAX_STREAM_URB; i++)
+               usb_free_urb(dev->stream_urb[i]);
+
+       usb_free_coherent(dev->bus_adap.usb_dev,
+                       MAX_STREAM_URB * AS102_USB_BUF_SIZE,
+                       dev->stream,
+                       dev->dma_addr);
+}
+
+static int as102_alloc_usb_stream_buffer(struct as102_dev_t *dev)
+{
+       int i;
+
+       dev->stream = usb_alloc_coherent(dev->bus_adap.usb_dev,
+                                      MAX_STREAM_URB * AS102_USB_BUF_SIZE,
+                                      GFP_KERNEL,
+                                      &dev->dma_addr);
+       if (!dev->stream) {
+               dev_dbg(&dev->bus_adap.usb_dev->dev,
+                       "%s: usb_buffer_alloc failed\n", __func__);
+               return -ENOMEM;
+       }
+
+       memset(dev->stream, 0, MAX_STREAM_URB * AS102_USB_BUF_SIZE);
+
+       /* init urb buffers */
+       for (i = 0; i < MAX_STREAM_URB; i++) {
+               struct urb *urb;
+
+               urb = usb_alloc_urb(0, GFP_ATOMIC);
+               if (urb == NULL) {
+                       dev_dbg(&dev->bus_adap.usb_dev->dev,
+                               "%s: usb_alloc_urb failed\n", __func__);
+                       as102_free_usb_stream_buffer(dev);
+                       return -ENOMEM;
+               }
+
+               urb->transfer_buffer = dev->stream + (i * AS102_USB_BUF_SIZE);
+               urb->transfer_dma = dev->dma_addr + (i * AS102_USB_BUF_SIZE);
+               urb->transfer_flags = URB_NO_TRANSFER_DMA_MAP;
+               urb->transfer_buffer_length = AS102_USB_BUF_SIZE;
+
+               dev->stream_urb[i] = urb;
+       }
+       return 0;
+}
+
+static void as102_usb_stop_stream(struct as102_dev_t *dev)
+{
+       int i;
+
+       for (i = 0; i < MAX_STREAM_URB; i++)
+               usb_kill_urb(dev->stream_urb[i]);
+}
+
+static int as102_usb_start_stream(struct as102_dev_t *dev)
+{
+       int i, ret = 0;
+
+       for (i = 0; i < MAX_STREAM_URB; i++) {
+               ret = as102_submit_urb_stream(dev, dev->stream_urb[i]);
+               if (ret) {
+                       as102_usb_stop_stream(dev);
+                       return ret;
+               }
+       }
+
+       return 0;
+}
+
+static void as102_usb_release(struct kref *kref)
+{
+       struct as102_dev_t *as102_dev;
+
+       as102_dev = container_of(kref, struct as102_dev_t, kref);
+       if (as102_dev != NULL) {
+               usb_put_dev(as102_dev->bus_adap.usb_dev);
+               kfree(as102_dev);
+       }
+}
+
+static void as102_usb_disconnect(struct usb_interface *intf)
+{
+       struct as102_dev_t *as102_dev;
+
+       /* extract as102_dev_t from usb_device private data */
+       as102_dev = usb_get_intfdata(intf);
+
+       /* unregister dvb layer */
+       as102_dvb_unregister(as102_dev);
+
+       /* free usb buffers */
+       as102_free_usb_stream_buffer(as102_dev);
+
+       usb_set_intfdata(intf, NULL);
+
+       /* usb unregister device */
+       usb_deregister_dev(intf, &as102_usb_class_driver);
+
+       /* decrement usage counter */
+       kref_put(&as102_dev->kref, as102_usb_release);
+
+       pr_info("%s: device has been disconnected\n", DRIVER_NAME);
+}
+
+static int as102_usb_probe(struct usb_interface *intf,
+                          const struct usb_device_id *id)
+{
+       int ret;
+       struct as102_dev_t *as102_dev;
+       int i;
+
+       /* This should never actually happen */
+       if (ARRAY_SIZE(as102_usb_id_table) !=
+           (sizeof(as102_device_names) / sizeof(const char *))) {
+               pr_err("Device names table invalid size");
+               return -EINVAL;
+       }
+
+       as102_dev = kzalloc(sizeof(struct as102_dev_t), GFP_KERNEL);
+       if (as102_dev == NULL)
+               return -ENOMEM;
+
+       /* Assign the user-friendly device name */
+       for (i = 0; i < ARRAY_SIZE(as102_usb_id_table); i++) {
+               if (id == &as102_usb_id_table[i]) {
+                       as102_dev->name = as102_device_names[i];
+                       as102_dev->elna_cfg = as102_elna_cfg[i];
+               }
+       }
+
+       if (as102_dev->name == NULL)
+               as102_dev->name = "Unknown AS102 device";
+
+       /* set private callback functions */
+       as102_dev->bus_adap.ops = &as102_priv_ops;
+
+       /* init cmd token for usb bus */
+       as102_dev->bus_adap.cmd = &as102_dev->bus_adap.token.usb.c;
+       as102_dev->bus_adap.rsp = &as102_dev->bus_adap.token.usb.r;
+
+       /* init kernel device reference */
+       kref_init(&as102_dev->kref);
+
+       /* store as102 device to usb_device private data */
+       usb_set_intfdata(intf, (void *) as102_dev);
+
+       /* store in as102 device the usb_device pointer */
+       as102_dev->bus_adap.usb_dev = usb_get_dev(interface_to_usbdev(intf));
+
+       /* we can register the device now, as it is ready */
+       ret = usb_register_dev(intf, &as102_usb_class_driver);
+       if (ret < 0) {
+               /* something prevented us from registering this driver */
+               dev_err(&intf->dev,
+                       "%s: usb_register_dev() failed (errno = %d)\n",
+                       __func__, ret);
+               goto failed;
+       }
+
+       pr_info("%s: device has been detected\n", DRIVER_NAME);
+
+       /* request buffer allocation for streaming */
+       ret = as102_alloc_usb_stream_buffer(as102_dev);
+       if (ret != 0)
+               goto failed_stream;
+
+       /* register dvb layer */
+       ret = as102_dvb_register(as102_dev);
+       if (ret != 0)
+               goto failed_dvb;
+
+       return ret;
+
+failed_dvb:
+       as102_free_usb_stream_buffer(as102_dev);
+failed_stream:
+       usb_deregister_dev(intf, &as102_usb_class_driver);
+failed:
+       usb_put_dev(as102_dev->bus_adap.usb_dev);
+       usb_set_intfdata(intf, NULL);
+       kfree(as102_dev);
+       return ret;
+}
+
+static int as102_open(struct inode *inode, struct file *file)
+{
+       int ret = 0, minor = 0;
+       struct usb_interface *intf = NULL;
+       struct as102_dev_t *dev = NULL;
+
+       /* read minor from inode */
+       minor = iminor(inode);
+
+       /* fetch device from usb interface */
+       intf = usb_find_interface(&as102_usb_driver, minor);
+       if (intf == NULL) {
+               pr_err("%s: can't find device for minor %d\n",
+                      __func__, minor);
+               ret = -ENODEV;
+               goto exit;
+       }
+
+       /* get our device */
+       dev = usb_get_intfdata(intf);
+       if (dev == NULL) {
+               ret = -EFAULT;
+               goto exit;
+       }
+
+       /* save our device object in the file's private structure */
+       file->private_data = dev;
+
+       /* increment our usage count for the device */
+       kref_get(&dev->kref);
+
+exit:
+       return ret;
+}
+
+static int as102_release(struct inode *inode, struct file *file)
+{
+       struct as102_dev_t *dev = NULL;
+
+       dev = file->private_data;
+       if (dev != NULL) {
+               /* decrement the count on our device */
+               kref_put(&dev->kref, as102_usb_release);
+       }
+
+       return 0;
+}
+
+MODULE_DEVICE_TABLE(usb, as102_usb_id_table);
diff --git a/drivers/media/usb/as102/as102_usb_drv.h b/drivers/media/usb/as102/as102_usb_drv.h
new file mode 100644 (file)
index 0000000..4fb1baa
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * Abilis Systems Single DVB-T Receiver
+ * Copyright (C) 2008 Pierrick Hascoet <pierrick.hascoet@abilis.com>
+ * Copyright (C) 2010 Devin Heitmueller <dheitmueller@kernellabs.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, 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 _AS102_USB_DRV_H_
+#define _AS102_USB_DRV_H_
+
+#define AS102_USB_DEVICE_TX_CTRL_CMD   0xF1
+#define AS102_USB_DEVICE_RX_CTRL_CMD   0xF2
+
+/* define these values to match the supported devices */
+
+/* Abilis system: "TITAN" */
+#define AS102_REFERENCE_DESIGN         "Abilis Systems DVB-Titan"
+#define AS102_USB_DEVICE_VENDOR_ID     0x1BA6
+#define AS102_USB_DEVICE_PID_0001      0x0001
+
+/* PCTV Systems: PCTV picoStick (74e) */
+#define AS102_PCTV_74E                 "PCTV Systems picoStick (74e)"
+#define PCTV_74E_USB_VID               0x2013
+#define PCTV_74E_USB_PID               0x0246
+
+/* Elgato: EyeTV DTT Deluxe */
+#define AS102_ELGATO_EYETV_DTT_NAME    "Elgato EyeTV DTT Deluxe"
+#define ELGATO_EYETV_DTT_USB_VID       0x0fd9
+#define ELGATO_EYETV_DTT_USB_PID       0x002c
+
+/* nBox: nBox DVB-T Dongle */
+#define AS102_NBOX_DVBT_DONGLE_NAME    "nBox DVB-T Dongle"
+#define NBOX_DVBT_DONGLE_USB_VID       0x0b89
+#define NBOX_DVBT_DONGLE_USB_PID       0x0007
+
+/* Sky Italia: Digital Key (green led) */
+#define AS102_SKY_IT_DIGITAL_KEY_NAME  "Sky IT Digital Key (green led)"
+#define SKY_IT_DIGITAL_KEY_USB_VID     0x2137
+#define SKY_IT_DIGITAL_KEY_USB_PID     0x0001
+
+void as102_urb_stream_irq(struct urb *urb);
+
+struct as10x_usb_token_cmd_t {
+       /* token cmd */
+       struct as10x_cmd_t c;
+       /* token response */
+       struct as10x_cmd_t r;
+};
+#endif
diff --git a/drivers/media/usb/as102/as10x_cmd.c b/drivers/media/usb/as102/as10x_cmd.c
new file mode 100644 (file)
index 0000000..8706179
--- /dev/null
@@ -0,0 +1,413 @@
+/*
+ * Abilis Systems Single DVB-T Receiver
+ * Copyright (C) 2008 Pierrick Hascoet <pierrick.hascoet@abilis.com>
+ * Copyright (C) 2010 Devin Heitmueller <dheitmueller@kernellabs.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, 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/kernel.h>
+#include "as102_drv.h"
+#include "as10x_cmd.h"
+
+/**
+ * as10x_cmd_turn_on - send turn on command to AS10x
+ * @adap:   pointer to AS10x bus adapter
+ *
+ * Return 0 when no error, < 0 in case of error.
+ */
+int as10x_cmd_turn_on(struct as10x_bus_adapter_t *adap)
+{
+       int error = AS10X_CMD_ERROR;
+       struct as10x_cmd_t *pcmd, *prsp;
+
+       pcmd = adap->cmd;
+       prsp = adap->rsp;
+
+       /* prepare command */
+       as10x_cmd_build(pcmd, (++adap->cmd_xid),
+                       sizeof(pcmd->body.turn_on.req));
+
+       /* fill command */
+       pcmd->body.turn_on.req.proc_id = cpu_to_le16(CONTROL_PROC_TURNON);
+
+       /* send command */
+       if (adap->ops->xfer_cmd) {
+               error = adap->ops->xfer_cmd(adap, (uint8_t *) pcmd,
+                                           sizeof(pcmd->body.turn_on.req) +
+                                           HEADER_SIZE,
+                                           (uint8_t *) prsp,
+                                           sizeof(prsp->body.turn_on.rsp) +
+                                           HEADER_SIZE);
+       }
+
+       if (error < 0)
+               goto out;
+
+       /* parse response */
+       error = as10x_rsp_parse(prsp, CONTROL_PROC_TURNON_RSP);
+
+out:
+       return error;
+}
+
+/**
+ * as10x_cmd_turn_off - send turn off command to AS10x
+ * @adap:   pointer to AS10x bus adapter
+ *
+ * Return 0 on success or negative value in case of error.
+ */
+int as10x_cmd_turn_off(struct as10x_bus_adapter_t *adap)
+{
+       int error = AS10X_CMD_ERROR;
+       struct as10x_cmd_t *pcmd, *prsp;
+
+       pcmd = adap->cmd;
+       prsp = adap->rsp;
+
+       /* prepare command */
+       as10x_cmd_build(pcmd, (++adap->cmd_xid),
+                       sizeof(pcmd->body.turn_off.req));
+
+       /* fill command */
+       pcmd->body.turn_off.req.proc_id = cpu_to_le16(CONTROL_PROC_TURNOFF);
+
+       /* send command */
+       if (adap->ops->xfer_cmd) {
+               error = adap->ops->xfer_cmd(
+                       adap, (uint8_t *) pcmd,
+                       sizeof(pcmd->body.turn_off.req) + HEADER_SIZE,
+                       (uint8_t *) prsp,
+                       sizeof(prsp->body.turn_off.rsp) + HEADER_SIZE);
+       }
+
+       if (error < 0)
+               goto out;
+
+       /* parse response */
+       error = as10x_rsp_parse(prsp, CONTROL_PROC_TURNOFF_RSP);
+
+out:
+       return error;
+}
+
+/**
+ * as10x_cmd_set_tune - send set tune command to AS10x
+ * @adap:    pointer to AS10x bus adapter
+ * @ptune:   tune parameters
+ *
+ * Return 0 on success or negative value in case of error.
+ */
+int as10x_cmd_set_tune(struct as10x_bus_adapter_t *adap,
+                      struct as10x_tune_args *ptune)
+{
+       int error = AS10X_CMD_ERROR;
+       struct as10x_cmd_t *preq, *prsp;
+
+       preq = adap->cmd;
+       prsp = adap->rsp;
+
+       /* prepare command */
+       as10x_cmd_build(preq, (++adap->cmd_xid),
+                       sizeof(preq->body.set_tune.req));
+
+       /* fill command */
+       preq->body.set_tune.req.proc_id = cpu_to_le16(CONTROL_PROC_SETTUNE);
+       preq->body.set_tune.req.args.freq = (__force __u32)cpu_to_le32(ptune->freq);
+       preq->body.set_tune.req.args.bandwidth = ptune->bandwidth;
+       preq->body.set_tune.req.args.hier_select = ptune->hier_select;
+       preq->body.set_tune.req.args.modulation = ptune->modulation;
+       preq->body.set_tune.req.args.hierarchy = ptune->hierarchy;
+       preq->body.set_tune.req.args.interleaving_mode  =
+               ptune->interleaving_mode;
+       preq->body.set_tune.req.args.code_rate  = ptune->code_rate;
+       preq->body.set_tune.req.args.guard_interval = ptune->guard_interval;
+       preq->body.set_tune.req.args.transmission_mode  =
+               ptune->transmission_mode;
+
+       /* send command */
+       if (adap->ops->xfer_cmd) {
+               error = adap->ops->xfer_cmd(adap,
+                                           (uint8_t *) preq,
+                                           sizeof(preq->body.set_tune.req)
+                                           + HEADER_SIZE,
+                                           (uint8_t *) prsp,
+                                           sizeof(prsp->body.set_tune.rsp)
+                                           + HEADER_SIZE);
+       }
+
+       if (error < 0)
+               goto out;
+
+       /* parse response */
+       error = as10x_rsp_parse(prsp, CONTROL_PROC_SETTUNE_RSP);
+
+out:
+       return error;
+}
+
+/**
+ * as10x_cmd_get_tune_status - send get tune status command to AS10x
+ * @adap: pointer to AS10x bus adapter
+ * @pstatus: pointer to updated status structure of the current tune
+ *
+ * Return 0 on success or negative value in case of error.
+ */
+int as10x_cmd_get_tune_status(struct as10x_bus_adapter_t *adap,
+                             struct as10x_tune_status *pstatus)
+{
+       int error = AS10X_CMD_ERROR;
+       struct as10x_cmd_t  *preq, *prsp;
+
+       preq = adap->cmd;
+       prsp = adap->rsp;
+
+       /* prepare command */
+       as10x_cmd_build(preq, (++adap->cmd_xid),
+                       sizeof(preq->body.get_tune_status.req));
+
+       /* fill command */
+       preq->body.get_tune_status.req.proc_id =
+               cpu_to_le16(CONTROL_PROC_GETTUNESTAT);
+
+       /* send command */
+       if (adap->ops->xfer_cmd) {
+               error = adap->ops->xfer_cmd(
+                       adap,
+                       (uint8_t *) preq,
+                       sizeof(preq->body.get_tune_status.req) + HEADER_SIZE,
+                       (uint8_t *) prsp,
+                       sizeof(prsp->body.get_tune_status.rsp) + HEADER_SIZE);
+       }
+
+       if (error < 0)
+               goto out;
+
+       /* parse response */
+       error = as10x_rsp_parse(prsp, CONTROL_PROC_GETTUNESTAT_RSP);
+       if (error < 0)
+               goto out;
+
+       /* Response OK -> get response data */
+       pstatus->tune_state = prsp->body.get_tune_status.rsp.sts.tune_state;
+       pstatus->signal_strength  =
+               le16_to_cpu((__force __le16)prsp->body.get_tune_status.rsp.sts.signal_strength);
+       pstatus->PER = le16_to_cpu((__force __le16)prsp->body.get_tune_status.rsp.sts.PER);
+       pstatus->BER = le16_to_cpu((__force __le16)prsp->body.get_tune_status.rsp.sts.BER);
+
+out:
+       return error;
+}
+
+/**
+ * as10x_cmd_get_tps - send get TPS command to AS10x
+ * @adap:      pointer to AS10x handle
+ * @ptps:      pointer to TPS parameters structure
+ *
+ * Return 0 on success or negative value in case of error.
+ */
+int as10x_cmd_get_tps(struct as10x_bus_adapter_t *adap, struct as10x_tps *ptps)
+{
+       int error = AS10X_CMD_ERROR;
+       struct as10x_cmd_t *pcmd, *prsp;
+
+       pcmd = adap->cmd;
+       prsp = adap->rsp;
+
+       /* prepare command */
+       as10x_cmd_build(pcmd, (++adap->cmd_xid),
+                       sizeof(pcmd->body.get_tps.req));
+
+       /* fill command */
+       pcmd->body.get_tune_status.req.proc_id =
+               cpu_to_le16(CONTROL_PROC_GETTPS);
+
+       /* send command */
+       if (adap->ops->xfer_cmd) {
+               error = adap->ops->xfer_cmd(adap,
+                                           (uint8_t *) pcmd,
+                                           sizeof(pcmd->body.get_tps.req) +
+                                           HEADER_SIZE,
+                                           (uint8_t *) prsp,
+                                           sizeof(prsp->body.get_tps.rsp) +
+                                           HEADER_SIZE);
+       }
+
+       if (error < 0)
+               goto out;
+
+       /* parse response */
+       error = as10x_rsp_parse(prsp, CONTROL_PROC_GETTPS_RSP);
+       if (error < 0)
+               goto out;
+
+       /* Response OK -> get response data */
+       ptps->modulation = prsp->body.get_tps.rsp.tps.modulation;
+       ptps->hierarchy = prsp->body.get_tps.rsp.tps.hierarchy;
+       ptps->interleaving_mode = prsp->body.get_tps.rsp.tps.interleaving_mode;
+       ptps->code_rate_HP = prsp->body.get_tps.rsp.tps.code_rate_HP;
+       ptps->code_rate_LP = prsp->body.get_tps.rsp.tps.code_rate_LP;
+       ptps->guard_interval = prsp->body.get_tps.rsp.tps.guard_interval;
+       ptps->transmission_mode  = prsp->body.get_tps.rsp.tps.transmission_mode;
+       ptps->DVBH_mask_HP = prsp->body.get_tps.rsp.tps.DVBH_mask_HP;
+       ptps->DVBH_mask_LP = prsp->body.get_tps.rsp.tps.DVBH_mask_LP;
+       ptps->cell_ID = le16_to_cpu((__force __le16)prsp->body.get_tps.rsp.tps.cell_ID);
+
+out:
+       return error;
+}
+
+/**
+ * as10x_cmd_get_demod_stats - send get demod stats command to AS10x
+ * @adap:          pointer to AS10x bus adapter
+ * @pdemod_stats:  pointer to demod stats parameters structure
+ *
+ * Return 0 on success or negative value in case of error.
+ */
+int as10x_cmd_get_demod_stats(struct as10x_bus_adapter_t *adap,
+                             struct as10x_demod_stats *pdemod_stats)
+{
+       int error = AS10X_CMD_ERROR;
+       struct as10x_cmd_t *pcmd, *prsp;
+
+       pcmd = adap->cmd;
+       prsp = adap->rsp;
+
+       /* prepare command */
+       as10x_cmd_build(pcmd, (++adap->cmd_xid),
+                       sizeof(pcmd->body.get_demod_stats.req));
+
+       /* fill command */
+       pcmd->body.get_demod_stats.req.proc_id =
+               cpu_to_le16(CONTROL_PROC_GET_DEMOD_STATS);
+
+       /* send command */
+       if (adap->ops->xfer_cmd) {
+               error = adap->ops->xfer_cmd(adap,
+                               (uint8_t *) pcmd,
+                               sizeof(pcmd->body.get_demod_stats.req)
+                               + HEADER_SIZE,
+                               (uint8_t *) prsp,
+                               sizeof(prsp->body.get_demod_stats.rsp)
+                               + HEADER_SIZE);
+       }
+
+       if (error < 0)
+               goto out;
+
+       /* parse response */
+       error = as10x_rsp_parse(prsp, CONTROL_PROC_GET_DEMOD_STATS_RSP);
+       if (error < 0)
+               goto out;
+
+       /* Response OK -> get response data */
+       pdemod_stats->frame_count =
+               le32_to_cpu((__force __le32)prsp->body.get_demod_stats.rsp.stats.frame_count);
+       pdemod_stats->bad_frame_count =
+               le32_to_cpu((__force __le32)prsp->body.get_demod_stats.rsp.stats.bad_frame_count);
+       pdemod_stats->bytes_fixed_by_rs =
+               le32_to_cpu((__force __le32)prsp->body.get_demod_stats.rsp.stats.bytes_fixed_by_rs);
+       pdemod_stats->mer =
+               le16_to_cpu((__force __le16)prsp->body.get_demod_stats.rsp.stats.mer);
+       pdemod_stats->has_started =
+               prsp->body.get_demod_stats.rsp.stats.has_started;
+
+out:
+       return error;
+}
+
+/**
+ * as10x_cmd_get_impulse_resp - send get impulse response command to AS10x
+ * @adap:     pointer to AS10x bus adapter
+ * @is_ready: pointer to value indicating when impulse
+ *           response data is ready
+ *
+ * Return 0 on success or negative value in case of error.
+ */
+int as10x_cmd_get_impulse_resp(struct as10x_bus_adapter_t *adap,
+                              uint8_t *is_ready)
+{
+       int error = AS10X_CMD_ERROR;
+       struct as10x_cmd_t *pcmd, *prsp;
+
+       pcmd = adap->cmd;
+       prsp = adap->rsp;
+
+       /* prepare command */
+       as10x_cmd_build(pcmd, (++adap->cmd_xid),
+                       sizeof(pcmd->body.get_impulse_rsp.req));
+
+       /* fill command */
+       pcmd->body.get_impulse_rsp.req.proc_id =
+               cpu_to_le16(CONTROL_PROC_GET_IMPULSE_RESP);
+
+       /* send command */
+       if (adap->ops->xfer_cmd) {
+               error = adap->ops->xfer_cmd(adap,
+                                       (uint8_t *) pcmd,
+                                       sizeof(pcmd->body.get_impulse_rsp.req)
+                                       + HEADER_SIZE,
+                                       (uint8_t *) prsp,
+                                       sizeof(prsp->body.get_impulse_rsp.rsp)
+                                       + HEADER_SIZE);
+       }
+
+       if (error < 0)
+               goto out;
+
+       /* parse response */
+       error = as10x_rsp_parse(prsp, CONTROL_PROC_GET_IMPULSE_RESP_RSP);
+       if (error < 0)
+               goto out;
+
+       /* Response OK -> get response data */
+       *is_ready = prsp->body.get_impulse_rsp.rsp.is_ready;
+
+out:
+       return error;
+}
+
+/**
+ * as10x_cmd_build - build AS10x command header
+ * @pcmd:     pointer to AS10x command buffer
+ * @xid:      sequence id of the command
+ * @cmd_len:  length of the command
+ */
+void as10x_cmd_build(struct as10x_cmd_t *pcmd,
+                    uint16_t xid, uint16_t cmd_len)
+{
+       pcmd->header.req_id = cpu_to_le16(xid);
+       pcmd->header.prog = cpu_to_le16(SERVICE_PROG_ID);
+       pcmd->header.version = cpu_to_le16(SERVICE_PROG_VERSION);
+       pcmd->header.data_len = cpu_to_le16(cmd_len);
+}
+
+/**
+ * as10x_rsp_parse - Parse command response
+ * @prsp:       pointer to AS10x command buffer
+ * @proc_id:    id of the command
+ *
+ * Return 0 on success or negative value in case of error.
+ */
+int as10x_rsp_parse(struct as10x_cmd_t *prsp, uint16_t proc_id)
+{
+       int error;
+
+       /* extract command error code */
+       error = prsp->body.common.rsp.error;
+
+       if ((error == 0) &&
+           (le16_to_cpu(prsp->body.common.rsp.proc_id) == proc_id)) {
+               return 0;
+       }
+
+       return AS10X_CMD_ERROR;
+}
diff --git a/drivers/media/usb/as102/as10x_cmd.h b/drivers/media/usb/as102/as10x_cmd.h
new file mode 100644 (file)
index 0000000..e06b84e
--- /dev/null
@@ -0,0 +1,523 @@
+/*
+ * Abilis Systems Single DVB-T Receiver
+ * Copyright (C) 2008 Pierrick Hascoet <pierrick.hascoet@abilis.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, 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 _AS10X_CMD_H_
+#define _AS10X_CMD_H_
+
+#include <linux/kernel.h>
+
+#include "as102_fe_types.h"
+
+/*********************************/
+/*       MACRO DEFINITIONS       */
+/*********************************/
+#define AS10X_CMD_ERROR                -1
+
+#define SERVICE_PROG_ID                0x0002
+#define SERVICE_PROG_VERSION   0x0001
+
+#define HIER_NONE              0x00
+#define HIER_LOW_PRIORITY      0x01
+
+#define HEADER_SIZE (sizeof(struct as10x_cmd_header_t))
+
+/* context request types */
+#define GET_CONTEXT_DATA       1
+#define SET_CONTEXT_DATA       2
+
+/* ODSP suspend modes */
+#define CFG_MODE_ODSP_RESUME   0
+#define CFG_MODE_ODSP_SUSPEND  1
+
+/* Dump memory size */
+#define DUMP_BLOCK_SIZE_MAX    0x20
+
+/*********************************/
+/*     TYPE DEFINITION           */
+/*********************************/
+enum control_proc {
+       CONTROL_PROC_TURNON                     = 0x0001,
+       CONTROL_PROC_TURNON_RSP                 = 0x0100,
+       CONTROL_PROC_SET_REGISTER               = 0x0002,
+       CONTROL_PROC_SET_REGISTER_RSP           = 0x0200,
+       CONTROL_PROC_GET_REGISTER               = 0x0003,
+       CONTROL_PROC_GET_REGISTER_RSP           = 0x0300,
+       CONTROL_PROC_SETTUNE                    = 0x000A,
+       CONTROL_PROC_SETTUNE_RSP                = 0x0A00,
+       CONTROL_PROC_GETTUNESTAT                = 0x000B,
+       CONTROL_PROC_GETTUNESTAT_RSP            = 0x0B00,
+       CONTROL_PROC_GETTPS                     = 0x000D,
+       CONTROL_PROC_GETTPS_RSP                 = 0x0D00,
+       CONTROL_PROC_SETFILTER                  = 0x000E,
+       CONTROL_PROC_SETFILTER_RSP              = 0x0E00,
+       CONTROL_PROC_REMOVEFILTER               = 0x000F,
+       CONTROL_PROC_REMOVEFILTER_RSP           = 0x0F00,
+       CONTROL_PROC_GET_IMPULSE_RESP           = 0x0012,
+       CONTROL_PROC_GET_IMPULSE_RESP_RSP       = 0x1200,
+       CONTROL_PROC_START_STREAMING            = 0x0013,
+       CONTROL_PROC_START_STREAMING_RSP        = 0x1300,
+       CONTROL_PROC_STOP_STREAMING             = 0x0014,
+       CONTROL_PROC_STOP_STREAMING_RSP         = 0x1400,
+       CONTROL_PROC_GET_DEMOD_STATS            = 0x0015,
+       CONTROL_PROC_GET_DEMOD_STATS_RSP        = 0x1500,
+       CONTROL_PROC_ELNA_CHANGE_MODE           = 0x0016,
+       CONTROL_PROC_ELNA_CHANGE_MODE_RSP       = 0x1600,
+       CONTROL_PROC_ODSP_CHANGE_MODE           = 0x0017,
+       CONTROL_PROC_ODSP_CHANGE_MODE_RSP       = 0x1700,
+       CONTROL_PROC_AGC_CHANGE_MODE            = 0x0018,
+       CONTROL_PROC_AGC_CHANGE_MODE_RSP        = 0x1800,
+
+       CONTROL_PROC_CONTEXT                    = 0x00FC,
+       CONTROL_PROC_CONTEXT_RSP                = 0xFC00,
+       CONTROL_PROC_DUMP_MEMORY                = 0x00FD,
+       CONTROL_PROC_DUMP_MEMORY_RSP            = 0xFD00,
+       CONTROL_PROC_DUMPLOG_MEMORY             = 0x00FE,
+       CONTROL_PROC_DUMPLOG_MEMORY_RSP         = 0xFE00,
+       CONTROL_PROC_TURNOFF                    = 0x00FF,
+       CONTROL_PROC_TURNOFF_RSP                = 0xFF00
+};
+
+union as10x_turn_on {
+       /* request */
+       struct {
+               /* request identifier */
+               __le16 proc_id;
+       } __packed req;
+       /* response */
+       struct {
+               /* response identifier */
+               __le16 proc_id;
+               /* error */
+               uint8_t error;
+       } __packed rsp;
+} __packed;
+
+union as10x_turn_off {
+       /* request */
+       struct {
+               /* request identifier */
+               __le16 proc_id;
+       } __packed req;
+       /* response */
+       struct {
+               /* response identifier */
+               __le16 proc_id;
+               /* error */
+               uint8_t err;
+       } __packed rsp;
+} __packed;
+
+union as10x_set_tune {
+       /* request */
+       struct {
+               /* request identifier */
+               __le16 proc_id;
+               /* tune params */
+               struct as10x_tune_args args;
+       } __packed req;
+       /* response */
+       struct {
+               /* response identifier */
+               __le16 proc_id;
+               /* response error */
+               uint8_t error;
+       } __packed rsp;
+} __packed;
+
+union as10x_get_tune_status {
+       /* request */
+       struct {
+               /* request identifier */
+               __le16 proc_id;
+       } __packed req;
+       /* response */
+       struct {
+               /* response identifier */
+               __le16 proc_id;
+               /* response error */
+               uint8_t error;
+               /* tune status */
+               struct as10x_tune_status sts;
+       } __packed rsp;
+} __packed;
+
+union as10x_get_tps {
+       /* request */
+       struct {
+               /* request identifier */
+               __le16 proc_id;
+       } __packed req;
+       /* response */
+       struct {
+               /* response identifier */
+               __le16 proc_id;
+               /* response error */
+               uint8_t error;
+               /* tps details */
+               struct as10x_tps tps;
+       } __packed rsp;
+} __packed;
+
+union as10x_common {
+       /* request */
+       struct {
+               /* request identifier */
+               __le16  proc_id;
+       } __packed req;
+       /* response */
+       struct {
+               /* response identifier */
+               __le16 proc_id;
+               /* response error */
+               uint8_t error;
+       } __packed rsp;
+} __packed;
+
+union as10x_add_pid_filter {
+       /* request */
+       struct {
+               /* request identifier */
+               __le16  proc_id;
+               /* PID to filter */
+               __le16  pid;
+               /* stream type (MPE, PSI/SI or PES )*/
+               uint8_t stream_type;
+               /* PID index in filter table */
+               uint8_t idx;
+       } __packed req;
+       /* response */
+       struct {
+               /* response identifier */
+               __le16 proc_id;
+               /* response error */
+               uint8_t error;
+               /* Filter id */
+               uint8_t filter_id;
+       } __packed rsp;
+} __packed;
+
+union as10x_del_pid_filter {
+       /* request */
+       struct {
+               /* request identifier */
+               __le16  proc_id;
+               /* PID to remove */
+               __le16  pid;
+       } __packed req;
+       /* response */
+       struct {
+               /* response identifier */
+               __le16 proc_id;
+               /* response error */
+               uint8_t error;
+       } __packed rsp;
+} __packed;
+
+union as10x_start_streaming {
+       /* request */
+       struct {
+               /* request identifier */
+               __le16 proc_id;
+       } __packed req;
+       /* response */
+       struct {
+               /* response identifier */
+               __le16 proc_id;
+               /* error */
+               uint8_t error;
+       } __packed rsp;
+} __packed;
+
+union as10x_stop_streaming {
+       /* request */
+       struct {
+               /* request identifier */
+               __le16 proc_id;
+       } __packed req;
+       /* response */
+       struct {
+               /* response identifier */
+               __le16 proc_id;
+               /* error */
+               uint8_t error;
+       } __packed rsp;
+} __packed;
+
+union as10x_get_demod_stats {
+       /* request */
+       struct {
+               /* request identifier */
+               __le16 proc_id;
+       } __packed req;
+       /* response */
+       struct {
+               /* response identifier */
+               __le16 proc_id;
+               /* error */
+               uint8_t error;
+               /* demod stats */
+               struct as10x_demod_stats stats;
+       } __packed rsp;
+} __packed;
+
+union as10x_get_impulse_resp {
+       /* request */
+       struct {
+               /* request identifier */
+               __le16 proc_id;
+       } __packed req;
+       /* response */
+       struct {
+               /* response identifier */
+               __le16 proc_id;
+               /* error */
+               uint8_t error;
+               /* impulse response ready */
+               uint8_t is_ready;
+       } __packed rsp;
+} __packed;
+
+union as10x_fw_context {
+       /* request */
+       struct {
+               /* request identifier */
+               __le16 proc_id;
+               /* value to write (for set context)*/
+               struct as10x_register_value reg_val;
+               /* context tag */
+               __le16 tag;
+               /* context request type */
+               __le16 type;
+       } __packed req;
+       /* response */
+       struct {
+               /* response identifier */
+               __le16 proc_id;
+               /* value read (for get context) */
+               struct as10x_register_value reg_val;
+               /* context request type */
+               __le16 type;
+               /* error */
+               uint8_t error;
+       } __packed rsp;
+} __packed;
+
+union as10x_set_register {
+       /* request */
+       struct {
+               /* response identifier */
+               __le16 proc_id;
+               /* register description */
+               struct as10x_register_addr reg_addr;
+               /* register content */
+               struct as10x_register_value reg_val;
+       } __packed req;
+       /* response */
+       struct {
+               /* response identifier */
+               __le16 proc_id;
+               /* error */
+               uint8_t error;
+       } __packed rsp;
+} __packed;
+
+union as10x_get_register {
+       /* request */
+       struct {
+               /* response identifier */
+               __le16 proc_id;
+               /* register description */
+               struct as10x_register_addr reg_addr;
+       } __packed req;
+       /* response */
+       struct {
+               /* response identifier */
+               __le16 proc_id;
+               /* error */
+               uint8_t error;
+               /* register content */
+               struct as10x_register_value reg_val;
+       } __packed rsp;
+} __packed;
+
+union as10x_cfg_change_mode {
+       /* request */
+       struct {
+               /* request identifier */
+               __le16 proc_id;
+               /* mode */
+               uint8_t mode;
+       } __packed req;
+       /* response */
+       struct {
+               /* response identifier */
+               __le16 proc_id;
+               /* error */
+               uint8_t error;
+       } __packed rsp;
+} __packed;
+
+struct as10x_cmd_header_t {
+       __le16 req_id;
+       __le16 prog;
+       __le16 version;
+       __le16 data_len;
+} __packed;
+
+#define DUMP_BLOCK_SIZE 16
+
+union as10x_dump_memory {
+       /* request */
+       struct {
+               /* request identifier */
+               __le16 proc_id;
+               /* dump memory type request */
+               uint8_t dump_req;
+               /* register description */
+               struct as10x_register_addr reg_addr;
+               /* nb blocks to read */
+               __le16 num_blocks;
+       } __packed req;
+       /* response */
+       struct {
+               /* response identifier */
+               __le16 proc_id;
+               /* error */
+               uint8_t error;
+               /* dump response */
+               uint8_t dump_rsp;
+               /* data */
+               union {
+                       uint8_t  data8[DUMP_BLOCK_SIZE];
+                       __le16 data16[DUMP_BLOCK_SIZE / sizeof(__le16)];
+                       __le32 data32[DUMP_BLOCK_SIZE / sizeof(__le32)];
+               } __packed u;
+       } __packed rsp;
+} __packed;
+
+union as10x_dumplog_memory {
+       struct {
+               /* request identifier */
+               __le16 proc_id;
+               /* dump memory type request */
+               uint8_t dump_req;
+       } __packed req;
+       struct {
+               /* request identifier */
+               __le16 proc_id;
+               /* error */
+               uint8_t error;
+               /* dump response */
+               uint8_t dump_rsp;
+               /* dump data */
+               uint8_t data[DUMP_BLOCK_SIZE];
+       } __packed rsp;
+} __packed;
+
+union as10x_raw_data {
+       /* request */
+       struct {
+               __le16 proc_id;
+               uint8_t data[64 - sizeof(struct as10x_cmd_header_t)
+                            - 2 /* proc_id */];
+       } __packed req;
+       /* response */
+       struct {
+               __le16 proc_id;
+               uint8_t error;
+               uint8_t data[64 - sizeof(struct as10x_cmd_header_t)
+                            - 2 /* proc_id */ - 1 /* rc */];
+       } __packed rsp;
+} __packed;
+
+struct as10x_cmd_t {
+       struct as10x_cmd_header_t header;
+       union {
+               union as10x_turn_on             turn_on;
+               union as10x_turn_off            turn_off;
+               union as10x_set_tune            set_tune;
+               union as10x_get_tune_status     get_tune_status;
+               union as10x_get_tps             get_tps;
+               union as10x_common              common;
+               union as10x_add_pid_filter      add_pid_filter;
+               union as10x_del_pid_filter      del_pid_filter;
+               union as10x_start_streaming     start_streaming;
+               union as10x_stop_streaming      stop_streaming;
+               union as10x_get_demod_stats     get_demod_stats;
+               union as10x_get_impulse_resp    get_impulse_rsp;
+               union as10x_fw_context          context;
+               union as10x_set_register        set_register;
+               union as10x_get_register        get_register;
+               union as10x_cfg_change_mode     cfg_change_mode;
+               union as10x_dump_memory         dump_memory;
+               union as10x_dumplog_memory      dumplog_memory;
+               union as10x_raw_data            raw_data;
+       } __packed body;
+} __packed;
+
+struct as10x_token_cmd_t {
+       /* token cmd */
+       struct as10x_cmd_t c;
+       /* token response */
+       struct as10x_cmd_t r;
+} __packed;
+
+
+/**************************/
+/* FUNCTION DECLARATION   */
+/**************************/
+
+void as10x_cmd_build(struct as10x_cmd_t *pcmd, uint16_t proc_id,
+                     uint16_t cmd_len);
+int as10x_rsp_parse(struct as10x_cmd_t *r, uint16_t proc_id);
+
+/* as10x cmd */
+int as10x_cmd_turn_on(struct as10x_bus_adapter_t *adap);
+int as10x_cmd_turn_off(struct as10x_bus_adapter_t *adap);
+
+int as10x_cmd_set_tune(struct as10x_bus_adapter_t *adap,
+                      struct as10x_tune_args *ptune);
+
+int as10x_cmd_get_tune_status(struct as10x_bus_adapter_t *adap,
+                             struct as10x_tune_status *pstatus);
+
+int as10x_cmd_get_tps(struct as10x_bus_adapter_t *adap,
+                     struct as10x_tps *ptps);
+
+int as10x_cmd_get_demod_stats(struct as10x_bus_adapter_t  *adap,
+                             struct as10x_demod_stats *pdemod_stats);
+
+int as10x_cmd_get_impulse_resp(struct as10x_bus_adapter_t *adap,
+                              uint8_t *is_ready);
+
+/* as10x cmd stream */
+int as10x_cmd_add_PID_filter(struct as10x_bus_adapter_t *adap,
+                            struct as10x_ts_filter *filter);
+int as10x_cmd_del_PID_filter(struct as10x_bus_adapter_t *adap,
+                            uint16_t pid_value);
+
+int as10x_cmd_start_streaming(struct as10x_bus_adapter_t *adap);
+int as10x_cmd_stop_streaming(struct as10x_bus_adapter_t *adap);
+
+/* as10x cmd cfg */
+int as10x_cmd_set_context(struct as10x_bus_adapter_t *adap,
+                         uint16_t tag,
+                         uint32_t value);
+int as10x_cmd_get_context(struct as10x_bus_adapter_t *adap,
+                         uint16_t tag,
+                         uint32_t *pvalue);
+
+int as10x_cmd_eLNA_change_mode(struct as10x_bus_adapter_t *adap, uint8_t mode);
+int as10x_context_rsp_parse(struct as10x_cmd_t *prsp, uint16_t proc_id);
+#endif
diff --git a/drivers/media/usb/as102/as10x_cmd_cfg.c b/drivers/media/usb/as102/as10x_cmd_cfg.c
new file mode 100644 (file)
index 0000000..c87f2ca
--- /dev/null
@@ -0,0 +1,201 @@
+/*
+ * Abilis Systems Single DVB-T Receiver
+ * Copyright (C) 2008 Pierrick Hascoet <pierrick.hascoet@abilis.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, 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/kernel.h>
+#include "as102_drv.h"
+#include "as10x_cmd.h"
+
+/***************************/
+/* FUNCTION DEFINITION     */
+/***************************/
+
+/**
+ * as10x_cmd_get_context - Send get context command to AS10x
+ * @adap:      pointer to AS10x bus adapter
+ * @tag:       context tag
+ * @pvalue:    pointer where to store context value read
+ *
+ * Return 0 on success or negative value in case of error.
+ */
+int as10x_cmd_get_context(struct as10x_bus_adapter_t *adap, uint16_t tag,
+                         uint32_t *pvalue)
+{
+       int  error;
+       struct as10x_cmd_t *pcmd, *prsp;
+
+       pcmd = adap->cmd;
+       prsp = adap->rsp;
+
+       /* prepare command */
+       as10x_cmd_build(pcmd, (++adap->cmd_xid),
+                       sizeof(pcmd->body.context.req));
+
+       /* fill command */
+       pcmd->body.context.req.proc_id = cpu_to_le16(CONTROL_PROC_CONTEXT);
+       pcmd->body.context.req.tag = cpu_to_le16(tag);
+       pcmd->body.context.req.type = cpu_to_le16(GET_CONTEXT_DATA);
+
+       /* send command */
+       if (adap->ops->xfer_cmd) {
+               error  = adap->ops->xfer_cmd(adap,
+                                            (uint8_t *) pcmd,
+                                            sizeof(pcmd->body.context.req)
+                                            + HEADER_SIZE,
+                                            (uint8_t *) prsp,
+                                            sizeof(prsp->body.context.rsp)
+                                            + HEADER_SIZE);
+       } else {
+               error = AS10X_CMD_ERROR;
+       }
+
+       if (error < 0)
+               goto out;
+
+       /* parse response: context command do not follow the common response */
+       /* structure -> specific handling response parse required            */
+       error = as10x_context_rsp_parse(prsp, CONTROL_PROC_CONTEXT_RSP);
+
+       if (error == 0) {
+               /* Response OK -> get response data */
+               *pvalue = le32_to_cpu((__force __le32)prsp->body.context.rsp.reg_val.u.value32);
+               /* value returned is always a 32-bit value */
+       }
+
+out:
+       return error;
+}
+
+/**
+ * as10x_cmd_set_context - send set context command to AS10x
+ * @adap:      pointer to AS10x bus adapter
+ * @tag:       context tag
+ * @value:     value to set in context
+ *
+ * Return 0 on success or negative value in case of error.
+ */
+int as10x_cmd_set_context(struct as10x_bus_adapter_t *adap, uint16_t tag,
+                         uint32_t value)
+{
+       int error;
+       struct as10x_cmd_t *pcmd, *prsp;
+
+       pcmd = adap->cmd;
+       prsp = adap->rsp;
+
+       /* prepare command */
+       as10x_cmd_build(pcmd, (++adap->cmd_xid),
+                       sizeof(pcmd->body.context.req));
+
+       /* fill command */
+       pcmd->body.context.req.proc_id = cpu_to_le16(CONTROL_PROC_CONTEXT);
+       /* pcmd->body.context.req.reg_val.mode initialization is not required */
+       pcmd->body.context.req.reg_val.u.value32 = (__force u32)cpu_to_le32(value);
+       pcmd->body.context.req.tag = cpu_to_le16(tag);
+       pcmd->body.context.req.type = cpu_to_le16(SET_CONTEXT_DATA);
+
+       /* send command */
+       if (adap->ops->xfer_cmd) {
+               error  = adap->ops->xfer_cmd(adap,
+                                            (uint8_t *) pcmd,
+                                            sizeof(pcmd->body.context.req)
+                                            + HEADER_SIZE,
+                                            (uint8_t *) prsp,
+                                            sizeof(prsp->body.context.rsp)
+                                            + HEADER_SIZE);
+       } else {
+               error = AS10X_CMD_ERROR;
+       }
+
+       if (error < 0)
+               goto out;
+
+       /* parse response: context command do not follow the common response */
+       /* structure -> specific handling response parse required            */
+       error = as10x_context_rsp_parse(prsp, CONTROL_PROC_CONTEXT_RSP);
+
+out:
+       return error;
+}
+
+/**
+ * as10x_cmd_eLNA_change_mode - send eLNA change mode command to AS10x
+ * @adap:      pointer to AS10x bus adapter
+ * @mode:      mode selected:
+ *             - ON    : 0x0 => eLNA always ON
+ *             - OFF   : 0x1 => eLNA always OFF
+ *             - AUTO  : 0x2 => eLNA follow hysteresis parameters
+ *                              to be ON or OFF
+ *
+ * Return 0 on success or negative value in case of error.
+ */
+int as10x_cmd_eLNA_change_mode(struct as10x_bus_adapter_t *adap, uint8_t mode)
+{
+       int error;
+       struct as10x_cmd_t *pcmd, *prsp;
+
+       pcmd = adap->cmd;
+       prsp = adap->rsp;
+
+       /* prepare command */
+       as10x_cmd_build(pcmd, (++adap->cmd_xid),
+                       sizeof(pcmd->body.cfg_change_mode.req));
+
+       /* fill command */
+       pcmd->body.cfg_change_mode.req.proc_id =
+               cpu_to_le16(CONTROL_PROC_ELNA_CHANGE_MODE);
+       pcmd->body.cfg_change_mode.req.mode = mode;
+
+       /* send command */
+       if (adap->ops->xfer_cmd) {
+               error  = adap->ops->xfer_cmd(adap, (uint8_t *) pcmd,
+                               sizeof(pcmd->body.cfg_change_mode.req)
+                               + HEADER_SIZE, (uint8_t *) prsp,
+                               sizeof(prsp->body.cfg_change_mode.rsp)
+                               + HEADER_SIZE);
+       } else {
+               error = AS10X_CMD_ERROR;
+       }
+
+       if (error < 0)
+               goto out;
+
+       /* parse response */
+       error = as10x_rsp_parse(prsp, CONTROL_PROC_ELNA_CHANGE_MODE_RSP);
+
+out:
+       return error;
+}
+
+/**
+ * as10x_context_rsp_parse - Parse context command response
+ * @prsp:       pointer to AS10x command response buffer
+ * @proc_id:    id of the command
+ *
+ * Since the contex command response does not follow the common
+ * response, a specific parse function is required.
+ * Return 0 on success or negative value in case of error.
+ */
+int as10x_context_rsp_parse(struct as10x_cmd_t *prsp, uint16_t proc_id)
+{
+       int err;
+
+       err = prsp->body.context.rsp.error;
+
+       if ((err == 0) &&
+           (le16_to_cpu(prsp->body.context.rsp.proc_id) == proc_id)) {
+               return 0;
+       }
+       return AS10X_CMD_ERROR;
+}
diff --git a/drivers/media/usb/as102/as10x_cmd_stream.c b/drivers/media/usb/as102/as10x_cmd_stream.c
new file mode 100644 (file)
index 0000000..126aea9
--- /dev/null
@@ -0,0 +1,207 @@
+/*
+ * Abilis Systems Single DVB-T Receiver
+ * Copyright (C) 2008 Pierrick Hascoet <pierrick.hascoet@abilis.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, 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/kernel.h>
+#include "as102_drv.h"
+#include "as10x_cmd.h"
+
+/**
+ * as10x_cmd_add_PID_filter - send add filter command to AS10x
+ * @adap:      pointer to AS10x bus adapter
+ * @filter:    TSFilter filter for DVB-T
+ *
+ * Return 0 on success or negative value in case of error.
+ */
+int as10x_cmd_add_PID_filter(struct as10x_bus_adapter_t *adap,
+                            struct as10x_ts_filter *filter)
+{
+       int error;
+       struct as10x_cmd_t *pcmd, *prsp;
+
+       pcmd = adap->cmd;
+       prsp = adap->rsp;
+
+       /* prepare command */
+       as10x_cmd_build(pcmd, (++adap->cmd_xid),
+                       sizeof(pcmd->body.add_pid_filter.req));
+
+       /* fill command */
+       pcmd->body.add_pid_filter.req.proc_id =
+               cpu_to_le16(CONTROL_PROC_SETFILTER);
+       pcmd->body.add_pid_filter.req.pid = cpu_to_le16(filter->pid);
+       pcmd->body.add_pid_filter.req.stream_type = filter->type;
+
+       if (filter->idx < 16)
+               pcmd->body.add_pid_filter.req.idx = filter->idx;
+       else
+               pcmd->body.add_pid_filter.req.idx = 0xFF;
+
+       /* send command */
+       if (adap->ops->xfer_cmd) {
+               error = adap->ops->xfer_cmd(adap, (uint8_t *) pcmd,
+                               sizeof(pcmd->body.add_pid_filter.req)
+                               + HEADER_SIZE, (uint8_t *) prsp,
+                               sizeof(prsp->body.add_pid_filter.rsp)
+                               + HEADER_SIZE);
+       } else {
+               error = AS10X_CMD_ERROR;
+       }
+
+       if (error < 0)
+               goto out;
+
+       /* parse response */
+       error = as10x_rsp_parse(prsp, CONTROL_PROC_SETFILTER_RSP);
+
+       if (error == 0) {
+               /* Response OK -> get response data */
+               filter->idx = prsp->body.add_pid_filter.rsp.filter_id;
+       }
+
+out:
+       return error;
+}
+
+/**
+ * as10x_cmd_del_PID_filter - Send delete filter command to AS10x
+ * @adap:         pointer to AS10x bus adapte
+ * @pid_value:    PID to delete
+ *
+ * Return 0 on success or negative value in case of error.
+ */
+int as10x_cmd_del_PID_filter(struct as10x_bus_adapter_t *adap,
+                            uint16_t pid_value)
+{
+       int error;
+       struct as10x_cmd_t *pcmd, *prsp;
+
+       pcmd = adap->cmd;
+       prsp = adap->rsp;
+
+       /* prepare command */
+       as10x_cmd_build(pcmd, (++adap->cmd_xid),
+                       sizeof(pcmd->body.del_pid_filter.req));
+
+       /* fill command */
+       pcmd->body.del_pid_filter.req.proc_id =
+               cpu_to_le16(CONTROL_PROC_REMOVEFILTER);
+       pcmd->body.del_pid_filter.req.pid = cpu_to_le16(pid_value);
+
+       /* send command */
+       if (adap->ops->xfer_cmd) {
+               error = adap->ops->xfer_cmd(adap, (uint8_t *) pcmd,
+                               sizeof(pcmd->body.del_pid_filter.req)
+                               + HEADER_SIZE, (uint8_t *) prsp,
+                               sizeof(prsp->body.del_pid_filter.rsp)
+                               + HEADER_SIZE);
+       } else {
+               error = AS10X_CMD_ERROR;
+       }
+
+       if (error < 0)
+               goto out;
+
+       /* parse response */
+       error = as10x_rsp_parse(prsp, CONTROL_PROC_REMOVEFILTER_RSP);
+
+out:
+       return error;
+}
+
+/**
+ * as10x_cmd_start_streaming - Send start streaming command to AS10x
+ * @adap:   pointer to AS10x bus adapter
+ *
+ * Return 0 on success or negative value in case of error.
+ */
+int as10x_cmd_start_streaming(struct as10x_bus_adapter_t *adap)
+{
+       int error;
+       struct as10x_cmd_t *pcmd, *prsp;
+
+       pcmd = adap->cmd;
+       prsp = adap->rsp;
+
+       /* prepare command */
+       as10x_cmd_build(pcmd, (++adap->cmd_xid),
+                       sizeof(pcmd->body.start_streaming.req));
+
+       /* fill command */
+       pcmd->body.start_streaming.req.proc_id =
+               cpu_to_le16(CONTROL_PROC_START_STREAMING);
+
+       /* send command */
+       if (adap->ops->xfer_cmd) {
+               error = adap->ops->xfer_cmd(adap, (uint8_t *) pcmd,
+                               sizeof(pcmd->body.start_streaming.req)
+                               + HEADER_SIZE, (uint8_t *) prsp,
+                               sizeof(prsp->body.start_streaming.rsp)
+                               + HEADER_SIZE);
+       } else {
+               error = AS10X_CMD_ERROR;
+       }
+
+       if (error < 0)
+               goto out;
+
+       /* parse response */
+       error = as10x_rsp_parse(prsp, CONTROL_PROC_START_STREAMING_RSP);
+
+out:
+       return error;
+}
+
+/**
+ * as10x_cmd_stop_streaming - Send stop streaming command to AS10x
+ * @adap:   pointer to AS10x bus adapter
+ *
+ * Return 0 on success or negative value in case of error.
+ */
+int as10x_cmd_stop_streaming(struct as10x_bus_adapter_t *adap)
+{
+       int8_t error;
+       struct as10x_cmd_t *pcmd, *prsp;
+
+       pcmd = adap->cmd;
+       prsp = adap->rsp;
+
+       /* prepare command */
+       as10x_cmd_build(pcmd, (++adap->cmd_xid),
+                       sizeof(pcmd->body.stop_streaming.req));
+
+       /* fill command */
+       pcmd->body.stop_streaming.req.proc_id =
+               cpu_to_le16(CONTROL_PROC_STOP_STREAMING);
+
+       /* send command */
+       if (adap->ops->xfer_cmd) {
+               error = adap->ops->xfer_cmd(adap, (uint8_t *) pcmd,
+                               sizeof(pcmd->body.stop_streaming.req)
+                               + HEADER_SIZE, (uint8_t *) prsp,
+                               sizeof(prsp->body.stop_streaming.rsp)
+                               + HEADER_SIZE);
+       } else {
+               error = AS10X_CMD_ERROR;
+       }
+
+       if (error < 0)
+               goto out;
+
+       /* parse response */
+       error = as10x_rsp_parse(prsp, CONTROL_PROC_STOP_STREAMING_RSP);
+
+out:
+       return error;
+}
diff --git a/drivers/media/usb/as102/as10x_handle.h b/drivers/media/usb/as102/as10x_handle.h
new file mode 100644 (file)
index 0000000..d6b58c7
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * Abilis Systems Single DVB-T Receiver
+ * Copyright (C) 2008 Pierrick Hascoet <pierrick.hascoet@abilis.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, 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 _AS10X_HANDLE_H
+#define _AS10X_HANDLE_H
+struct as10x_bus_adapter_t;
+struct as102_dev_t;
+
+#include "as10x_cmd.h"
+
+/* values for "mode" field */
+#define REGMODE8       8
+#define REGMODE16      16
+#define REGMODE32      32
+
+struct as102_priv_ops_t {
+       int (*upload_fw_pkt)(struct as10x_bus_adapter_t *bus_adap,
+                             unsigned char *buf, int buflen, int swap32);
+
+       int (*send_cmd)(struct as10x_bus_adapter_t *bus_adap,
+                        unsigned char *buf, int buflen);
+
+       int (*xfer_cmd)(struct as10x_bus_adapter_t *bus_adap,
+                        unsigned char *send_buf, int send_buf_len,
+                        unsigned char *recv_buf, int recv_buf_len);
+
+       int (*start_stream)(struct as102_dev_t *dev);
+       void (*stop_stream)(struct as102_dev_t *dev);
+
+       int (*reset_target)(struct as10x_bus_adapter_t *bus_adap);
+
+       int (*read_write)(struct as10x_bus_adapter_t *bus_adap, uint8_t mode,
+                         uint32_t rd_addr, uint16_t rd_len,
+                         uint32_t wr_addr, uint16_t wr_len);
+
+       int (*as102_read_ep2)(struct as10x_bus_adapter_t *bus_adap,
+                              unsigned char *recv_buf,
+                              int recv_buf_len);
+};
+#endif
index 2c6b7da137ed1bc2b20236c1336b1acec097d190..9eb77ac2153b06a60e65c781994901ba12208d6d 100644 (file)
@@ -46,6 +46,8 @@ struct au0828_board au0828_boards[] = {
                .name   = "Hauppauge HVR850",
                .tuner_type = TUNER_XC5000,
                .tuner_addr = 0x61,
+               .has_ir_i2c = 1,
+               .has_analog = 1,
                .i2c_clk_divider = AU0828_I2C_CLK_250KHZ,
                .input = {
                        {
@@ -72,12 +74,7 @@ struct au0828_board au0828_boards[] = {
                .tuner_type = TUNER_XC5000,
                .tuner_addr = 0x61,
                .has_ir_i2c = 1,
-               /* The au0828 hardware i2c implementation does not properly
-                  support the xc5000's i2c clock stretching.  So we need to
-                  lower the clock frequency enough where the 15us clock
-                  stretch fits inside of a normal clock cycle, or else the
-                  au0828 fails to set the STOP bit.  A 30 KHz clock puts the
-                  clock pulse width at 18us */
+               .has_analog = 1,
                .i2c_clk_divider = AU0828_I2C_CLK_250KHZ,
                .input = {
                        {
@@ -101,20 +98,20 @@ struct au0828_board au0828_boards[] = {
        },
        [AU0828_BOARD_HAUPPAUGE_HVR950Q_MXL] = {
                .name   = "Hauppauge HVR950Q rev xxF8",
-               .tuner_type = UNSET,
-               .tuner_addr = ADDR_UNSET,
+               .tuner_type = TUNER_XC5000,
+               .tuner_addr = 0x61,
                .i2c_clk_divider = AU0828_I2C_CLK_250KHZ,
        },
        [AU0828_BOARD_DVICO_FUSIONHDTV7] = {
                .name   = "DViCO FusionHDTV USB",
-               .tuner_type = UNSET,
-               .tuner_addr = ADDR_UNSET,
+               .tuner_type = TUNER_XC5000,
+               .tuner_addr = 0x61,
                .i2c_clk_divider = AU0828_I2C_CLK_250KHZ,
        },
        [AU0828_BOARD_HAUPPAUGE_WOODBURY] = {
                .name = "Hauppauge Woodbury",
-               .tuner_type = UNSET,
-               .tuner_addr = ADDR_UNSET,
+               .tuner_type = TUNER_NXP_TDA18271,
+               .tuner_addr = 0x60,
                .i2c_clk_divider = AU0828_I2C_CLK_250KHZ,
        },
 };
@@ -142,8 +139,7 @@ int au0828_tuner_callback(void *priv, int component, int command, int arg)
                        mdelay(10);
                        return 0;
                } else {
-                       printk(KERN_ERR
-                               "%s(): Unknown command.\n", __func__);
+                       pr_err("%s(): Unknown command.\n", __func__);
                        return -EINVAL;
                }
                break;
@@ -177,12 +173,12 @@ static void hauppauge_eeprom(struct au0828_dev *dev, u8 *eeprom_data)
        case 72500: /* WinTV-HVR950q (OEM, No IR, ATSC/QAM */
                break;
        default:
-               printk(KERN_WARNING "%s: warning: "
-                      "unknown hauppauge model #%d\n", __func__, tv.model);
+               pr_warn("%s: warning: unknown hauppauge model #%d\n",
+                       __func__, tv.model);
                break;
        }
 
-       printk(KERN_INFO "%s: hauppauge eeprom: model=%d\n",
+       pr_info("%s: hauppauge eeprom: model=%d\n",
               __func__, tv.model);
 }
 
@@ -228,16 +224,16 @@ void au0828_card_analog_fe_setup(struct au0828_dev *dev)
                sd = v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap,
                                "au8522", 0x8e >> 1, NULL);
                if (sd == NULL)
-                       printk(KERN_ERR "analog subdev registration failed\n");
+                       pr_err("analog subdev registration failed\n");
        }
 
        /* Setup tuners */
-       if (dev->board.tuner_type != TUNER_ABSENT) {
+       if (dev->board.tuner_type != TUNER_ABSENT && dev->board.has_analog) {
                /* Load the tuner module, which does the attach */
                sd = v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap,
                                "tuner", dev->board.tuner_addr, NULL);
                if (sd == NULL)
-                       printk(KERN_ERR "tuner subdev registration fail\n");
+                       pr_err("tuner subdev registration fail\n");
 
                tun_setup.mode_mask      = mode_mask;
                tun_setup.type           = dev->board.tuner_type;
index 56025e6894421e59db3dd2acf8a72b015b12c0ef..bc064803b6c7f6c2c6fb05b93c8fba7efb5cda22 100644 (file)
  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
+#include "au0828.h"
+
 #include <linux/module.h>
 #include <linux/slab.h>
 #include <linux/videodev2.h>
 #include <media/v4l2-common.h>
 #include <linux/mutex.h>
 
-#include "au0828.h"
-
 /*
  * 1 = General debug messages
  * 2 = USB handling
@@ -90,7 +90,7 @@ static int send_control_msg(struct au0828_dev *dev, u16 request, u32 value,
                status = min(status, 0);
 
                if (status < 0) {
-                       printk(KERN_ERR "%s() Failed sending control message, error %d.\n",
+                       pr_err("%s() Failed sending control message, error %d.\n",
                                __func__, status);
                }
 
@@ -115,7 +115,7 @@ static int recv_control_msg(struct au0828_dev *dev, u16 request, u32 value,
                status = min(status, 0);
 
                if (status < 0) {
-                       printk(KERN_ERR "%s() Failed receiving control message, error %d.\n",
+                       pr_err("%s() Failed receiving control message, error %d.\n",
                                __func__, status);
                }
 
@@ -153,9 +153,7 @@ static void au0828_usb_disconnect(struct usb_interface *interface)
 
        dprintk(1, "%s()\n", __func__);
 
-#ifdef CONFIG_VIDEO_AU0828_RC
        au0828_rc_unregister(dev);
-#endif
        /* Digital TV */
        au0828_dvb_unregister(dev);
 
@@ -199,15 +197,14 @@ static int au0828_usb_probe(struct usb_interface *interface,
         * not enough even for most Digital TV streams.
         */
        if (usbdev->speed != USB_SPEED_HIGH && disable_usb_speed_check == 0) {
-               printk(KERN_ERR "au0828: Device initialization failed.\n");
-               printk(KERN_ERR "au0828: Device must be connected to a "
-                      "high-speed USB 2.0 port.\n");
+               pr_err("au0828: Device initialization failed.\n");
+               pr_err("au0828: Device must be connected to a high-speed USB 2.0 port.\n");
                return -ENODEV;
        }
 
        dev = kzalloc(sizeof(*dev), GFP_KERNEL);
        if (dev == NULL) {
-               printk(KERN_ERR "%s() Unable to allocate memory\n", __func__);
+               pr_err("%s() Unable to allocate memory\n", __func__);
                return -ENOMEM;
        }
 
@@ -266,10 +263,8 @@ static int au0828_usb_probe(struct usb_interface *interface,
                pr_err("%s() au0282_dev_register failed\n",
                       __func__);
 
-#ifdef CONFIG_VIDEO_AU0828_RC
        /* Remote controller */
        au0828_rc_register(dev);
-#endif
 
        /*
         * Store the pointer to the au0828_dev so it can be accessed in
@@ -277,7 +272,7 @@ static int au0828_usb_probe(struct usb_interface *interface,
         */
        usb_set_intfdata(interface, dev);
 
-       printk(KERN_INFO "Registered device AU0828 [%s]\n",
+       pr_info("Registered device AU0828 [%s]\n",
                dev->board.name == NULL ? "Unset" : dev->board.name);
 
        mutex_unlock(&dev->lock);
@@ -285,13 +280,56 @@ static int au0828_usb_probe(struct usb_interface *interface,
        return retval;
 }
 
+static int au0828_suspend(struct usb_interface *interface,
+                               pm_message_t message)
+{
+       struct au0828_dev *dev = usb_get_intfdata(interface);
+
+       if (!dev)
+               return 0;
+
+       pr_info("Suspend\n");
+
+       au0828_rc_suspend(dev);
+       au0828_v4l2_suspend(dev);
+       au0828_dvb_suspend(dev);
+
+       /* FIXME: should suspend also ATV/DTV */
+
+       return 0;
+}
+
+static int au0828_resume(struct usb_interface *interface)
+{
+       struct au0828_dev *dev = usb_get_intfdata(interface);
+       if (!dev)
+               return 0;
+
+       pr_info("Resume\n");
+
+       /* Power Up the bridge */
+       au0828_write(dev, REG_600, 1 << 4);
+
+       /* Bring up the GPIO's and supporting devices */
+       au0828_gpio_setup(dev);
+
+       au0828_rc_resume(dev);
+       au0828_v4l2_resume(dev);
+       au0828_dvb_resume(dev);
+
+       /* FIXME: should resume also ATV/DTV */
+
+       return 0;
+}
+
 static struct usb_driver au0828_usb_driver = {
-       .name           = DRIVER_NAME,
+       .name           = KBUILD_MODNAME,
        .probe          = au0828_usb_probe,
        .disconnect     = au0828_usb_disconnect,
        .id_table       = au0828_usb_id_table,
-
-       /* FIXME: Add suspend and resume functions */
+       .suspend        = au0828_suspend,
+       .resume         = au0828_resume,
+       .reset_resume   = au0828_resume,
 };
 
 static int __init au0828_init(void)
@@ -299,27 +337,27 @@ static int __init au0828_init(void)
        int ret;
 
        if (au0828_debug & 1)
-               printk(KERN_INFO "%s() Debugging is enabled\n", __func__);
+               pr_info("%s() Debugging is enabled\n", __func__);
 
        if (au0828_debug & 2)
-               printk(KERN_INFO "%s() USB Debugging is enabled\n", __func__);
+               pr_info("%s() USB Debugging is enabled\n", __func__);
 
        if (au0828_debug & 4)
-               printk(KERN_INFO "%s() I2C Debugging is enabled\n", __func__);
+               pr_info("%s() I2C Debugging is enabled\n", __func__);
 
        if (au0828_debug & 8)
-               printk(KERN_INFO "%s() Bridge Debugging is enabled\n",
+               pr_info("%s() Bridge Debugging is enabled\n",
                       __func__);
 
        if (au0828_debug & 16)
-               printk(KERN_INFO "%s() IR Debugging is enabled\n",
+               pr_info("%s() IR Debugging is enabled\n",
                       __func__);
 
-       printk(KERN_INFO "au0828 driver loaded\n");
+       pr_info("au0828 driver loaded\n");
 
        ret = usb_register(&au0828_usb_driver);
        if (ret)
-               printk(KERN_ERR "usb_register failed, error = %d\n", ret);
+               pr_err("usb_register failed, error = %d\n", ret);
 
        return ret;
 }
index d8b5d9480279a29441f0cadb47a4e36c59936855..00ab1563d142ed682dc91e76a80db44112504595 100644 (file)
  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
+#include "au0828.h"
+
 #include <linux/module.h>
 #include <linux/slab.h>
 #include <linux/init.h>
 #include <linux/device.h>
-#include <linux/suspend.h>
 #include <media/v4l2-common.h>
 #include <media/tuner.h>
 
-#include "au0828.h"
 #include "au8522.h"
 #include "xc5000.h"
 #include "mxl5007t.h"
@@ -121,13 +121,13 @@ static void urb_completion(struct urb *purb)
                return;
        }
 
-       if (dev->urb_streaming == 0) {
+       if (!dev->urb_streaming) {
                dprintk(2, "%s: not streaming!\n", __func__);
                return;
        }
 
        if (ptype != PIPE_BULK) {
-               printk(KERN_ERR "%s: Unsupported URB type %d\n",
+               pr_err("%s: Unsupported URB type %d\n",
                       __func__, ptype);
                return;
        }
@@ -159,7 +159,10 @@ static int stop_urb_transfer(struct au0828_dev *dev)
 
        dprintk(2, "%s()\n", __func__);
 
-       dev->urb_streaming = 0;
+       if (!dev->urb_streaming)
+               return 0;
+
+       dev->urb_streaming = false;
        for (i = 0; i < URB_COUNT; i++) {
                if (dev->urbs[i]) {
                        usb_kill_urb(dev->urbs[i]);
@@ -202,8 +205,7 @@ static int start_urb_transfer(struct au0828_dev *dev)
                if (!purb->transfer_buffer) {
                        usb_free_urb(purb);
                        dev->urbs[i] = NULL;
-                       printk(KERN_ERR
-                              "%s: failed big buffer allocation, err = %d\n",
+                       pr_err("%s: failed big buffer allocation, err = %d\n",
                               __func__, ret);
                        goto err;
                }
@@ -224,13 +226,13 @@ static int start_urb_transfer(struct au0828_dev *dev)
                ret = usb_submit_urb(dev->urbs[i], GFP_ATOMIC);
                if (ret != 0) {
                        stop_urb_transfer(dev);
-                       printk(KERN_ERR "%s: failed urb submission, "
-                              "err = %d\n", __func__, ret);
+                       pr_err("%s: failed urb submission, err = %d\n",
+                              __func__, ret);
                        return ret;
                }
        }
 
-       dev->urb_streaming = 1;
+       dev->urb_streaming = true;
        ret = 0;
 
 err:
@@ -268,7 +270,7 @@ static int au0828_dvb_start_feed(struct dvb_demux_feed *feed)
        if (!demux->dmx.frontend)
                return -EINVAL;
 
-       if (dvb) {
+       if (dvb->frontend) {
                mutex_lock(&dvb->lock);
                dvb->start_count++;
                dprintk(1, "%s(), start_count: %d, stop_count: %d\n", __func__,
@@ -297,7 +299,7 @@ static int au0828_dvb_stop_feed(struct dvb_demux_feed *feed)
 
        dprintk(1, "%s()\n", __func__);
 
-       if (dvb) {
+       if (dvb->frontend) {
                cancel_work_sync(&dev->restart_streaming);
 
                mutex_lock(&dvb->lock);
@@ -324,7 +326,7 @@ static void au0828_restart_dvb_streaming(struct work_struct *work)
                                              restart_streaming);
        struct au0828_dvb *dvb = &dev->dvb;
 
-       if (dev->urb_streaming == 0)
+       if (!dev->urb_streaming)
                return;
 
        dprintk(1, "Restarting streaming...!\n");
@@ -393,9 +395,8 @@ static int dvb_register(struct au0828_dev *dev)
                        if (!dev->dig_transfer_buffer[i]) {
                                result = -ENOMEM;
 
-                               printk(KERN_ERR
-                                      "%s: failed buffer allocation (errno = %d)\n",
-                                      DRIVER_NAME, result);
+                               pr_err("failed buffer allocation (errno = %d)\n",
+                                      result);
                                goto fail_adapter;
                        }
                }
@@ -404,11 +405,12 @@ static int dvb_register(struct au0828_dev *dev)
        INIT_WORK(&dev->restart_streaming, au0828_restart_dvb_streaming);
 
        /* register adapter */
-       result = dvb_register_adapter(&dvb->adapter, DRIVER_NAME, THIS_MODULE,
+       result = dvb_register_adapter(&dvb->adapter,
+                                     KBUILD_MODNAME, THIS_MODULE,
                                      &dev->usbdev->dev, adapter_nr);
        if (result < 0) {
-               printk(KERN_ERR "%s: dvb_register_adapter failed "
-                      "(errno = %d)\n", DRIVER_NAME, result);
+               pr_err("dvb_register_adapter failed (errno = %d)\n",
+                      result);
                goto fail_adapter;
        }
        dvb->adapter.priv = dev;
@@ -416,8 +418,8 @@ static int dvb_register(struct au0828_dev *dev)
        /* register frontend */
        result = dvb_register_frontend(&dvb->adapter, dvb->frontend);
        if (result < 0) {
-               printk(KERN_ERR "%s: dvb_register_frontend failed "
-                      "(errno = %d)\n", DRIVER_NAME, result);
+               pr_err("dvb_register_frontend failed (errno = %d)\n",
+                      result);
                goto fail_frontend;
        }
 
@@ -436,8 +438,7 @@ static int dvb_register(struct au0828_dev *dev)
        dvb->demux.stop_feed  = au0828_dvb_stop_feed;
        result = dvb_dmx_init(&dvb->demux);
        if (result < 0) {
-               printk(KERN_ERR "%s: dvb_dmx_init failed (errno = %d)\n",
-                      DRIVER_NAME, result);
+               pr_err("dvb_dmx_init failed (errno = %d)\n", result);
                goto fail_dmx;
        }
 
@@ -446,31 +447,29 @@ static int dvb_register(struct au0828_dev *dev)
        dvb->dmxdev.capabilities = 0;
        result = dvb_dmxdev_init(&dvb->dmxdev, &dvb->adapter);
        if (result < 0) {
-               printk(KERN_ERR "%s: dvb_dmxdev_init failed (errno = %d)\n",
-                      DRIVER_NAME, result);
+               pr_err("dvb_dmxdev_init failed (errno = %d)\n", result);
                goto fail_dmxdev;
        }
 
        dvb->fe_hw.source = DMX_FRONTEND_0;
        result = dvb->demux.dmx.add_frontend(&dvb->demux.dmx, &dvb->fe_hw);
        if (result < 0) {
-               printk(KERN_ERR "%s: add_frontend failed "
-                      "(DMX_FRONTEND_0, errno = %d)\n", DRIVER_NAME, result);
+               pr_err("add_frontend failed (DMX_FRONTEND_0, errno = %d)\n",
+                      result);
                goto fail_fe_hw;
        }
 
        dvb->fe_mem.source = DMX_MEMORY_FE;
        result = dvb->demux.dmx.add_frontend(&dvb->demux.dmx, &dvb->fe_mem);
        if (result < 0) {
-               printk(KERN_ERR "%s: add_frontend failed "
-                      "(DMX_MEMORY_FE, errno = %d)\n", DRIVER_NAME, result);
+               pr_err("add_frontend failed (DMX_MEMORY_FE, errno = %d)\n",
+                      result);
                goto fail_fe_mem;
        }
 
        result = dvb->demux.dmx.connect_frontend(&dvb->demux.dmx, &dvb->fe_hw);
        if (result < 0) {
-               printk(KERN_ERR "%s: connect_frontend failed (errno = %d)\n",
-                      DRIVER_NAME, result);
+               pr_err("connect_frontend failed (errno = %d)\n", result);
                goto fail_fe_conn;
        }
 
@@ -530,8 +529,7 @@ void au0828_dvb_unregister(struct au0828_dev *dev)
                for (i = 0; i < URB_COUNT; i++)
                        kfree(dev->dig_transfer_buffer[i]);
        }
-
-
+       dvb->frontend = NULL;
 }
 
 /* All the DVB attach calls go here, this function get's modified
@@ -596,12 +594,11 @@ int au0828_dvb_register(struct au0828_dev *dev)
                }
                break;
        default:
-               printk(KERN_WARNING "The frontend of your DVB/ATSC card "
-                      "isn't supported yet\n");
+               pr_warn("The frontend of your DVB/ATSC card isn't supported yet\n");
                break;
        }
        if (NULL == dvb->frontend) {
-               printk(KERN_ERR "%s() Frontend initialization failed\n",
+               pr_err("%s() Frontend initialization failed\n",
                       __func__);
                return -1;
        }
@@ -613,8 +610,49 @@ int au0828_dvb_register(struct au0828_dev *dev)
        if (ret < 0) {
                if (dvb->frontend->ops.release)
                        dvb->frontend->ops.release(dvb->frontend);
+               dvb->frontend = NULL;
                return ret;
        }
 
        return 0;
 }
+
+void au0828_dvb_suspend(struct au0828_dev *dev)
+{
+       struct au0828_dvb *dvb = &dev->dvb;
+       int rc;
+
+       if (dvb->frontend) {
+               if (dev->urb_streaming) {
+                       cancel_work_sync(&dev->restart_streaming);
+                       /* Stop transport */
+                       mutex_lock(&dvb->lock);
+                       stop_urb_transfer(dev);
+                       au0828_stop_transport(dev, 1);
+                       mutex_unlock(&dvb->lock);
+                       dev->need_urb_start = true;
+               }
+               /* suspend frontend - does tuner and fe to sleep */
+               rc = dvb_frontend_suspend(dvb->frontend);
+               pr_info("au0828_dvb_suspend(): Suspending DVB fe %d\n", rc);
+       }
+}
+
+void au0828_dvb_resume(struct au0828_dev *dev)
+{
+       struct au0828_dvb *dvb = &dev->dvb;
+       int rc;
+
+       if (dvb->frontend) {
+               /* resume frontend - does fe and tuner init */
+               rc = dvb_frontend_resume(dvb->frontend);
+               pr_info("au0828_dvb_resume(): Resuming DVB fe %d\n", rc);
+               if (dev->need_urb_start) {
+                       /* Start transport */
+                       mutex_lock(&dvb->lock);
+                       au0828_start_transport(dev);
+                       start_urb_transfer(dev);
+                       mutex_unlock(&dvb->lock);
+               }
+       }
+}
index daaeaf1b089cf1976c6204dacd53551af2b6ebb9..ae7ac6669769f3cdcc2d2ba01db5cc0c73ce5039 100644 (file)
  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
+#include "au0828.h"
+
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/init.h>
 #include <linux/delay.h>
 #include <linux/io.h>
 
-#include "au0828.h"
 #include "media/tuner.h"
 #include <media/v4l2-common.h>
 
@@ -340,7 +341,7 @@ static struct i2c_algorithm au0828_i2c_algo_template = {
 /* ----------------------------------------------------------------------- */
 
 static struct i2c_adapter au0828_i2c_adap_template = {
-       .name              = DRIVER_NAME,
+       .name              = KBUILD_MODNAME,
        .owner             = THIS_MODULE,
        .algo              = &au0828_i2c_algo_template,
 };
@@ -365,7 +366,7 @@ static void do_i2c_scan(char *name, struct i2c_client *c)
                rc = i2c_master_recv(c, &buf, 0);
                if (rc < 0)
                        continue;
-               printk(KERN_INFO "%s: i2c scan: found device @ 0x%x  [%s]\n",
+               pr_info("%s: i2c scan: found device @ 0x%x  [%s]\n",
                       name, i << 1, i2c_devs[i] ? i2c_devs[i] : "???");
        }
 }
@@ -381,7 +382,7 @@ int au0828_i2c_register(struct au0828_dev *dev)
 
        dev->i2c_adap.dev.parent = &dev->usbdev->dev;
 
-       strlcpy(dev->i2c_adap.name, DRIVER_NAME,
+       strlcpy(dev->i2c_adap.name, KBUILD_MODNAME,
                sizeof(dev->i2c_adap.name));
 
        dev->i2c_adap.algo = &dev->i2c_algo;
@@ -396,11 +397,11 @@ int au0828_i2c_register(struct au0828_dev *dev)
        dev->i2c_client.adapter = &dev->i2c_adap;
 
        if (0 == dev->i2c_rc) {
-               printk(KERN_INFO "%s: i2c bus registered\n", DRIVER_NAME);
+               pr_info("i2c bus registered\n");
                if (i2c_scan)
-                       do_i2c_scan(DRIVER_NAME, &dev->i2c_client);
+                       do_i2c_scan(KBUILD_MODNAME, &dev->i2c_client);
        } else
-               printk(KERN_INFO "%s: i2c bus register FAILED\n", DRIVER_NAME);
+               pr_info("i2c bus register FAILED\n");
 
        return dev->i2c_rc;
 }
index fd0d3a90ce7d0294cd2f2bc3d0bdc3cdf7d25e21..63995f97dc653276abd5aaaab44e08c3dde0ba69 100644 (file)
@@ -17,6 +17,8 @@
   GNU General Public License for more details.
  */
 
+#include "au0828.h"
+
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/delay.h>
@@ -25,7 +27,9 @@
 #include <linux/slab.h>
 #include <media/rc-core.h>
 
-#include "au0828.h"
+static int disable_ir;
+module_param(disable_ir,        int, 0444);
+MODULE_PARM_DESC(disable_ir, "disable infrared remote support");
 
 struct au0828_rc {
        struct au0828_dev *dev;
@@ -90,14 +94,19 @@ static int au8522_rc_read(struct au0828_rc *ir, u16 reg, int val,
 static int au8522_rc_andor(struct au0828_rc *ir, u16 reg, u8 mask, u8 value)
 {
        int rc;
-       char buf;
+       char buf, oldbuf;
 
        rc = au8522_rc_read(ir, reg, -1, &buf, 1);
        if (rc < 0)
                return rc;
 
+       oldbuf = buf;
        buf = (buf & ~mask) | (value & mask);
 
+       /* Nothing to do, just return */
+       if (buf == oldbuf)
+               return 0;
+
        return au8522_rc_write(ir, reg, buf);
 }
 
@@ -122,8 +131,11 @@ static int au0828_get_key_au8522(struct au0828_rc *ir)
 
        /* Check IR int */
        rc = au8522_rc_read(ir, 0xe1, -1, buf, 1);
-       if (rc < 0 || !(buf[0] & (1 << 4)))
+       if (rc < 0 || !(buf[0] & (1 << 4))) {
+               /* Be sure that IR is enabled */
+               au8522_rc_set(ir, 0xe0, 1 << 4);
                return 0;
+       }
 
        /* Something arrived. Get the data */
        rc = au8522_rc_read(ir, 0xe3, 0x11, buf, sizeof(buf));
@@ -135,8 +147,6 @@ static int au0828_get_key_au8522(struct au0828_rc *ir)
        /* Disable IR */
        au8522_rc_clear(ir, 0xe0, 1 << 4);
 
-       usleep_range(45000, 46000);
-
        /* Enable IR */
        au8522_rc_set(ir, 0xe0, 1 << 4);
 
@@ -243,10 +253,10 @@ static void au0828_rc_stop(struct rc_dev *rc)
 {
        struct au0828_rc *ir = rc->priv;
 
+       cancel_delayed_work_sync(&ir->work);
+
        /* Disable IR */
        au8522_rc_clear(ir, 0xe0, 1 << 4);
-
-       cancel_delayed_work_sync(&ir->work);
 }
 
 static int au0828_probe_i2c_ir(struct au0828_dev *dev)
@@ -273,7 +283,7 @@ int au0828_rc_register(struct au0828_dev *dev)
        int err = -ENOMEM;
        u16 i2c_rc_dev_addr = 0;
 
-       if (!dev->board.has_ir_i2c)
+       if (!dev->board.has_ir_i2c || disable_ir)
                return 0;
 
        i2c_rc_dev_addr = au0828_probe_i2c_ir(dev);
@@ -368,8 +378,13 @@ int au0828_rc_suspend(struct au0828_dev *dev)
        if (!ir)
                return 0;
 
+       pr_info("Stopping RC\n");
+
        cancel_delayed_work_sync(&ir->work);
 
+       /* Disable IR */
+       au8522_rc_clear(ir, 0xe0, 1 << 4);
+
        return 0;
 }
 
@@ -380,6 +395,11 @@ int au0828_rc_resume(struct au0828_dev *dev)
        if (!ir)
                return 0;
 
+       pr_info("Restarting RC\n");
+
+       /* Enable IR */
+       au8522_rc_set(ir, 0xe0, 1 << 4);
+
        schedule_delayed_work(&ir->work, msecs_to_jiffies(ir->polling));
 
        return 0;
index 63f593070ee8b14be8f98e70dc1ab8e8c28c644e..932d24f42b247d7f13ee83534961fcf281aaf1cc 100644 (file)
    02110-1301, USA.
  */
 
+#include "au0828.h"
+
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/slab.h>
 
-#include "au0828.h"
-
 static unsigned int vbibufs = 5;
 module_param(vbibufs, int, 0644);
 MODULE_PARM_DESC(vbibufs, "number of vbi buffers, range 2-32");
index 98f7ea1d6d6382109cfb119ffb62c6789693597b..5f337b118bffe36e9969c3a8963e9871034ffce1 100644 (file)
  *
  */
 
+#include "au0828.h"
+
 #include <linux/module.h>
 #include <linux/slab.h>
 #include <linux/init.h>
 #include <linux/device.h>
-#include <linux/suspend.h>
 #include <media/v4l2-common.h>
 #include <media/v4l2-ioctl.h>
 #include <media/v4l2-event.h>
 #include <media/tuner.h>
-#include "au0828.h"
 #include "au0828-reg.h"
 
 static DEFINE_MUTEX(au0828_sysfs_lock);
@@ -53,7 +53,7 @@ MODULE_PARM_DESC(isoc_debug, "enable debug messages [isoc transfers]");
 #define au0828_isocdbg(fmt, arg...) \
 do {\
        if (isoc_debug) { \
-               printk(KERN_INFO "au0828 %s :"fmt, \
+               pr_info("au0828 %s :"fmt, \
                       __func__ , ##arg);          \
        } \
   } while (0)
@@ -106,12 +106,12 @@ static inline void print_err_status(struct au0828_dev *dev,
 static int check_dev(struct au0828_dev *dev)
 {
        if (dev->dev_state & DEV_DISCONNECTED) {
-               printk(KERN_INFO "v4l2 ioctl: device not present\n");
+               pr_info("v4l2 ioctl: device not present\n");
                return -ENODEV;
        }
 
        if (dev->dev_state & DEV_MISCONFIGURED) {
-               printk(KERN_INFO "v4l2 ioctl: device is misconfigured; "
+               pr_info("v4l2 ioctl: device is misconfigured; "
                       "close and open it again\n");
                return -EIO;
        }
@@ -159,6 +159,7 @@ static void au0828_irq_callback(struct urb *urb)
                au0828_isocdbg("urb resubmit failed (error=%i)\n",
                               urb->status);
        }
+       dev->stream_state = STREAM_ON;
 }
 
 /*
@@ -198,6 +199,8 @@ static void au0828_uninit_isoc(struct au0828_dev *dev)
        dev->isoc_ctl.urb = NULL;
        dev->isoc_ctl.transfer_buffer = NULL;
        dev->isoc_ctl.num_bufs = 0;
+
+       dev->stream_state = STREAM_OFF;
 }
 
 /*
@@ -717,7 +720,7 @@ buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb,
        if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
                rc = videobuf_iolock(vq, &buf->vb, NULL);
                if (rc < 0) {
-                       printk(KERN_INFO "videobuf_iolock failed\n");
+                       pr_info("videobuf_iolock failed\n");
                        goto fail;
                }
        }
@@ -730,7 +733,7 @@ buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb,
                                      AU0828_MAX_ISO_BUFS, dev->max_pkt_size,
                                      au0828_isoc_copy);
                if (rc < 0) {
-                       printk(KERN_INFO "au0828_init_isoc failed\n");
+                       pr_info("au0828_init_isoc failed\n");
                        goto fail;
                }
        }
@@ -801,7 +804,7 @@ static int au0828_analog_stream_enable(struct au0828_dev *d)
                /* set au0828 interface0 to AS5 here again */
                ret = usb_set_interface(d->usbdev, 0, 5);
                if (ret < 0) {
-                       printk(KERN_INFO "Au0828 can't set alt setting to 5!\n");
+                       pr_info("Au0828 can't set alt setting to 5!\n");
                        return -EBUSY;
                }
        }
@@ -1090,7 +1093,7 @@ static int au0828_v4l2_close(struct file *filp)
                   USB bandwidth */
                ret = usb_set_interface(dev->usbdev, 0, 0);
                if (ret < 0)
-                       printk(KERN_INFO "Au0828 can't set alternate to 0!\n");
+                       pr_info("Au0828 can't set alternate to 0!\n");
        }
        mutex_unlock(&dev->lock);
 
@@ -1344,7 +1347,7 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
                return rc;
 
        if (videobuf_queue_is_busy(&fh->vb_vidq)) {
-               printk(KERN_INFO "%s queue busy\n", __func__);
+               pr_info("%s queue busy\n", __func__);
                rc = -EBUSY;
                goto out;
        }
@@ -1868,6 +1871,69 @@ static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b)
        return rc;
 }
 
+void au0828_v4l2_suspend(struct au0828_dev *dev)
+{
+       struct urb *urb;
+       int i;
+
+       pr_info("stopping V4L2\n");
+
+       if (dev->stream_state == STREAM_ON) {
+               pr_info("stopping V4L2 active URBs\n");
+               au0828_analog_stream_disable(dev);
+               /* stop urbs */
+               for (i = 0; i < dev->isoc_ctl.num_bufs; i++) {
+                       urb = dev->isoc_ctl.urb[i];
+                       if (urb) {
+                               if (!irqs_disabled())
+                                       usb_kill_urb(urb);
+                               else
+                                       usb_unlink_urb(urb);
+                       }
+               }
+       }
+
+       if (dev->vid_timeout_running)
+               del_timer_sync(&dev->vid_timeout);
+       if (dev->vbi_timeout_running)
+               del_timer_sync(&dev->vbi_timeout);
+}
+
+void au0828_v4l2_resume(struct au0828_dev *dev)
+{
+       int i, rc;
+
+       pr_info("restarting V4L2\n");
+
+       if (dev->stream_state == STREAM_ON) {
+               au0828_stream_interrupt(dev);
+               au0828_init_tuner(dev);
+       }
+
+       if (dev->vid_timeout_running)
+               mod_timer(&dev->vid_timeout, jiffies + (HZ / 10));
+       if (dev->vbi_timeout_running)
+               mod_timer(&dev->vbi_timeout, jiffies + (HZ / 10));
+
+       /* If we were doing ac97 instead of i2s, it would go here...*/
+       au0828_i2s_init(dev);
+
+       au0828_analog_stream_enable(dev);
+
+       if (!(dev->stream_state == STREAM_ON)) {
+               au0828_analog_stream_reset(dev);
+               /* submit urbs */
+               for (i = 0; i < dev->isoc_ctl.num_bufs; i++) {
+                       rc = usb_submit_urb(dev->isoc_ctl.urb[i], GFP_ATOMIC);
+                       if (rc) {
+                               au0828_isocdbg("submit of urb %i failed (error=%i)\n",
+                                              i, rc);
+                               au0828_uninit_isoc(dev);
+                       }
+               }
+       }
+}
+
 static struct v4l2_file_operations au0828_v4l_fops = {
        .owner      = THIS_MODULE,
        .open       = au0828_v4l2_open,
@@ -1939,7 +2005,7 @@ int au0828_analog_register(struct au0828_dev *dev,
        retval = usb_set_interface(dev->usbdev,
                        interface->cur_altsetting->desc.bInterfaceNumber, 5);
        if (retval != 0) {
-               printk(KERN_INFO "Failure setting usb interface0 to as5\n");
+               pr_info("Failure setting usb interface0 to as5\n");
                return retval;
        }
 
@@ -1963,7 +2029,7 @@ int au0828_analog_register(struct au0828_dev *dev,
                }
        }
        if (!(dev->isoc_in_endpointaddr)) {
-               printk(KERN_INFO "Could not locate isoc endpoint\n");
+               pr_info("Could not locate isoc endpoint\n");
                kfree(dev);
                return -ENODEV;
        }
index 96bec05d7dac1abd153baa53cfa84b25c1d7a27b..36815a369c68f860fc910b9e49e79e3247acfcba 100644 (file)
@@ -19,6 +19,8 @@
  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/usb.h>
 #include <linux/i2c.h>
 #include <linux/i2c-algo-bit.h>
@@ -42,7 +44,6 @@
 #include "au0828-reg.h"
 #include "au0828-cards.h"
 
-#define DRIVER_NAME "au0828"
 #define URB_COUNT   16
 #define URB_BUFSIZE (0xe522)
 
@@ -89,6 +90,7 @@ struct au0828_board {
        unsigned char tuner_addr;
        unsigned char i2c_clk_divider;
        unsigned char has_ir_i2c:1;
+       unsigned char has_analog:1;
        struct au0828_input input[AU0828_MAX_INPUT];
 
 };
@@ -266,8 +268,8 @@ struct au0828_dev {
        char *transfer_buffer[AU0828_MAX_ISO_BUFS];/* transfer buffers for isoc
                                                   transfer */
 
-       /* USB / URB Related */
-       int             urb_streaming;
+       /* DVB USB / URB Related */
+       bool            urb_streaming, need_urb_start;
        struct urb      *urbs[URB_COUNT];
 
        /* Preallocated transfer digital transfer buffers */
@@ -311,22 +313,38 @@ int au0828_analog_register(struct au0828_dev *dev,
                           struct usb_interface *interface);
 int au0828_analog_stream_disable(struct au0828_dev *d);
 void au0828_analog_unregister(struct au0828_dev *dev);
+#ifdef CONFIG_VIDEO_AU0828_V4L2
+void au0828_v4l2_suspend(struct au0828_dev *dev);
+void au0828_v4l2_resume(struct au0828_dev *dev);
+#else
+static inline void au0828_v4l2_suspend(struct au0828_dev *dev) { };
+static inline void au0828_v4l2_resume(struct au0828_dev *dev) { };
+#endif
 
 /* ----------------------------------------------------------- */
 /* au0828-dvb.c */
 extern int au0828_dvb_register(struct au0828_dev *dev);
 extern void au0828_dvb_unregister(struct au0828_dev *dev);
+void au0828_dvb_suspend(struct au0828_dev *dev);
+void au0828_dvb_resume(struct au0828_dev *dev);
 
 /* au0828-vbi.c */
 extern struct videobuf_queue_ops au0828_vbi_qops;
 
 #define dprintk(level, fmt, arg...)\
        do { if (au0828_debug & level)\
-               printk(KERN_DEBUG DRIVER_NAME "/0: " fmt, ## arg);\
+               printk(KERN_DEBUG pr_fmt(fmt), ## arg);\
        } while (0)
 
 /* au0828-input.c */
-int au0828_rc_register(struct au0828_dev *dev);
-void au0828_rc_unregister(struct au0828_dev *dev);
-int au0828_rc_suspend(struct au0828_dev *dev);
-int au0828_rc_resume(struct au0828_dev *dev);
+#ifdef CONFIG_VIDEO_AU0828_RC
+extern int au0828_rc_register(struct au0828_dev *dev);
+extern void au0828_rc_unregister(struct au0828_dev *dev);
+extern int au0828_rc_suspend(struct au0828_dev *dev);
+extern int au0828_rc_resume(struct au0828_dev *dev);
+#else
+static inline int au0828_rc_register(struct au0828_dev *dev) { return 0; }
+static inline void au0828_rc_unregister(struct au0828_dev *dev) { }
+static inline int au0828_rc_suspend(struct au0828_dev *dev) { return 0; }
+static inline int au0828_rc_resume(struct au0828_dev *dev) { return 0; }
+#endif
index a428c10e1a1657dbcb1f767c90993f66fcba1ea4..40a69879fc0ad91993e375637b2e41a6b32e0156 100644 (file)
@@ -1595,7 +1595,7 @@ void cx231xx_set_DIF_bandpass(struct cx231xx *dev, u32 if_freq,
                if_freq = 16000000;
        }
 
-       cx231xx_info("Enter IF=%zd\n",
+       cx231xx_info("Enter IF=%zu\n",
                        ARRAY_SIZE(Dif_set_array));
        for (i = 0; i < ARRAY_SIZE(Dif_set_array); i++) {
                if (Dif_set_array[i].if_freq == if_freq) {
@@ -2223,7 +2223,7 @@ int cx231xx_set_power_mode(struct cx231xx *dev, enum AV_MODE mode)
        if (status < 0)
                return status;
 
-       tmp = le32_to_cpu(*((u32 *) value));
+       tmp = le32_to_cpu(*((__le32 *) value));
 
        switch (mode) {
        case POLARIS_AVMODE_ENXTERNAL_AV:
@@ -2444,7 +2444,7 @@ int cx231xx_power_suspend(struct cx231xx *dev)
        if (status > 0)
                return status;
 
-       tmp = le32_to_cpu(*((u32 *) value));
+       tmp = le32_to_cpu(*((__le32 *) value));
        tmp &= (~PWR_MODE_MASK);
 
        value[0] = (u8) tmp;
@@ -2472,7 +2472,7 @@ int cx231xx_start_stream(struct cx231xx *dev, u32 ep_mask)
        if (status < 0)
                return status;
 
-       tmp = le32_to_cpu(*((u32 *) value));
+       tmp = le32_to_cpu(*((__le32 *) value));
        tmp |= ep_mask;
        value[0] = (u8) tmp;
        value[1] = (u8) (tmp >> 8);
@@ -2497,7 +2497,7 @@ int cx231xx_stop_stream(struct cx231xx *dev, u32 ep_mask)
        if (status < 0)
                return status;
 
-       tmp = le32_to_cpu(*((u32 *) value));
+       tmp = le32_to_cpu(*((__le32 *) value));
        tmp &= (~ep_mask);
        value[0] = (u8) tmp;
        value[1] = (u8) (tmp >> 8);
@@ -2644,7 +2644,7 @@ static int cx231xx_set_gpio_bit(struct cx231xx *dev, u32 gpio_bit, u32 gpio_val)
 {
        int status = 0;
 
-       gpio_val = cpu_to_le32(gpio_val);
+       gpio_val = (__force u32)cpu_to_le32(gpio_val);
        status = cx231xx_send_gpio_cmd(dev, gpio_bit, (u8 *)&gpio_val, 4, 0, 0);
 
        return status;
@@ -2652,7 +2652,7 @@ static int cx231xx_set_gpio_bit(struct cx231xx *dev, u32 gpio_bit, u32 gpio_val)
 
 static int cx231xx_get_gpio_bit(struct cx231xx *dev, u32 gpio_bit, u32 *gpio_val)
 {
-       u32 tmp;
+       __le32 tmp;
        int status = 0;
 
        status = cx231xx_send_gpio_cmd(dev, gpio_bit, (u8 *)&tmp, 4, 0, 1);
index 8039b769f2580fd7409d56b0a4e7cd1078a75ee4..791f00c6276b1e489e38f019d4e7bbe40362a0e2 100644 (file)
@@ -705,7 +705,7 @@ struct cx231xx_board cx231xx_boards[] = {
                },
        },
        [CX231XX_BOARD_HAUPPAUGE_930C_HD_1113xx] = {
-               .name = "Hauppauge WinTV 930C-HD (1113xx) / PCTV QuatroStick 521e",
+               .name = "Hauppauge WinTV 930C-HD (1113xx) / HVR-900H (111xxx) / PCTV QuatroStick 521e",
                .tuner_type = TUNER_NXP_TDA18271,
                .tuner_addr = 0x60,
                .tuner_gpio = RDE250_XCV_TUNER,
@@ -744,7 +744,7 @@ struct cx231xx_board cx231xx_boards[] = {
                } },
        },
        [CX231XX_BOARD_HAUPPAUGE_930C_HD_1114xx] = {
-               .name = "Hauppauge WinTV 930C-HD (1114xx) / PCTV QuatroStick 522e",
+               .name = "Hauppauge WinTV 930C-HD (1114xx) / HVR-901H (1114xx) / PCTV QuatroStick 522e",
                .tuner_type = TUNER_ABSENT,
                .tuner_addr = 0x60,
                .tuner_gpio = RDE250_XCV_TUNER,
@@ -815,6 +815,12 @@ struct usb_device_id cx231xx_id_table[] = {
         .driver_info = CX231XX_BOARD_HAUPPAUGE_930C_HD_1113xx},
        {USB_DEVICE(0x2040, 0xb131),
         .driver_info = CX231XX_BOARD_HAUPPAUGE_930C_HD_1114xx},
+       /* Hauppauge WinTV-HVR-900-H */
+       {USB_DEVICE(0x2040, 0xb138),
+        .driver_info = CX231XX_BOARD_HAUPPAUGE_930C_HD_1113xx},
+       /* Hauppauge WinTV-HVR-901-H */
+       {USB_DEVICE(0x2040, 0xb139),
+        .driver_info = CX231XX_BOARD_HAUPPAUGE_930C_HD_1114xx},
        {USB_DEVICE(0x2040, 0xb140),
         .driver_info = CX231XX_BOARD_HAUPPAUGE_EXETER},
        {USB_DEVICE(0x2040, 0xc200),
index 513194aa6561c76d70f45a7286a6456c52153325..180103e48036727e322399c53437599ced61b8c5 100644 (file)
@@ -1491,7 +1491,7 @@ int cx231xx_mode_register(struct cx231xx *dev, u16 address, u32 mode)
        if (status < 0)
                return status;
 
-       tmp = le32_to_cpu(*((u32 *) value));
+       tmp = le32_to_cpu(*((__le32 *) value));
        tmp |= mode;
 
        value[0] = (u8) tmp;
index 1fa79741d1991f0709cfebfb961d5f11d54fb166..6c7b5e250eed7fc2903eae3f56039ed195fd4d33 100644 (file)
@@ -403,8 +403,6 @@ static int attach_xc5000(u8 addr, struct cx231xx *dev)
 
 int cx231xx_set_analog_freq(struct cx231xx *dev, u32 freq)
 {
-       int status = 0;
-
        if ((dev->dvb != NULL) && (dev->dvb->frontend != NULL)) {
 
                struct dvb_tuner_ops *dops = &dev->dvb->frontend->ops.tuner_ops;
@@ -423,7 +421,7 @@ int cx231xx_set_analog_freq(struct cx231xx *dev, u32 freq)
 
        }
 
-       return status;
+       return 0;
 }
 
 int cx231xx_reset_analog_tuner(struct cx231xx *dev)
@@ -740,7 +738,7 @@ static int dvb_init(struct cx231xx *dev)
                        goto out_free;
                }
 
-               dev->dvb->frontend->ops.i2c_gate_ctrl = 0;
+               dev->dvb->frontend->ops.i2c_gate_ctrl = NULL;
 
                /* define general-purpose callback pointer */
                dvb->frontend->callback = cx231xx_tuner_callback;
@@ -773,7 +771,7 @@ static int dvb_init(struct cx231xx *dev)
                        goto out_free;
                }
 
-               dev->dvb->frontend->ops.i2c_gate_ctrl = 0;
+               dev->dvb->frontend->ops.i2c_gate_ctrl = NULL;
 
                /* define general-purpose callback pointer */
                dvb->frontend->callback = cx231xx_tuner_callback;
index 66645b02c854dd66435f9bfcb2e5f2f8e390506e..5b34323ad207950e3025ee9226b7456f358ddecc 100644 (file)
@@ -141,3 +141,10 @@ config DVB_USB_RTL28XXU
        help
          Say Y here to support the Realtek RTL28xxU DVB USB receiver.
 
+config DVB_USB_DVBSKY
+       tristate "DVBSky USB support"
+       depends on DVB_USB_V2
+       select DVB_M88DS3103 if MEDIA_SUBDRV_AUTOSELECT
+       select MEDIA_TUNER_M88TS2022 if MEDIA_SUBDRV_AUTOSELECT
+       help
+         Say Y here to support the USB receivers from DVBSky.
index bc38f03394cda0e1a397b390f354b620fe486a73..f10d4df0eae5c2962e4a20de60de3145a082ea83 100644 (file)
@@ -37,6 +37,9 @@ obj-$(CONFIG_DVB_USB_MXL111SF) += mxl111sf-tuner.o
 dvb-usb-rtl28xxu-objs := rtl28xxu.o
 obj-$(CONFIG_DVB_USB_RTL28XXU) += dvb-usb-rtl28xxu.o
 
+dvb-usb-dvbsky-objs := dvbsky.o
+obj-$(CONFIG_DVB_USB_DVBSKY) += dvb-usb-dvbsky.o
+
 ccflags-y += -I$(srctree)/drivers/media/dvb-core
 ccflags-y += -I$(srctree)/drivers/media/dvb-frontends
 ccflags-y += -I$(srctree)/drivers/media/tuners
index 5ca738ab44e000911dec36cecdc1f6818ec6a7c2..16c0b7d4f8e701e58bb23191d66ca74951a0fa1e 100644 (file)
@@ -419,7 +419,7 @@ static int af9015_eeprom_hash(struct dvb_usb_device *d)
        /* calculate checksum */
        for (i = 0; i < AF9015_EEPROM_SIZE / sizeof(u32); i++) {
                state->eeprom_sum *= GOLDEN_RATIO_PRIME_32;
-               state->eeprom_sum += le32_to_cpu(((u32 *)buf)[i]);
+               state->eeprom_sum += le32_to_cpu(((__le32 *)buf)[i]);
        }
 
        for (i = 0; i < AF9015_EEPROM_SIZE; i += 16)
index c82beac0e0cbfd1fa9f3225bf044e55eab7de410..00758c83eec733475be5596818a5347868cde089 100644 (file)
@@ -193,6 +193,92 @@ static int af9035_wr_reg_mask(struct dvb_usb_device *d, u32 reg, u8 val,
        return af9035_wr_regs(d, reg, &val, 1);
 }
 
+static int af9035_add_i2c_dev(struct dvb_usb_device *d, char *type, u8 addr,
+               void *platform_data, struct i2c_adapter *adapter)
+{
+       int ret, num;
+       struct state *state = d_to_priv(d);
+       struct i2c_client *client;
+       struct i2c_board_info board_info = {
+               .addr = addr,
+               .platform_data = platform_data,
+       };
+
+       strlcpy(board_info.type, type, I2C_NAME_SIZE);
+
+       /* find first free client */
+       for (num = 0; num < AF9035_I2C_CLIENT_MAX; num++) {
+               if (state->i2c_client[num] == NULL)
+                       break;
+       }
+
+       dev_dbg(&d->udev->dev, "%s: num=%d\n", __func__, num);
+
+       if (num == AF9035_I2C_CLIENT_MAX) {
+               dev_err(&d->udev->dev, "%s: I2C client out of index\n",
+                               KBUILD_MODNAME);
+               ret = -ENODEV;
+               goto err;
+       }
+
+       request_module(board_info.type);
+
+       /* register I2C device */
+       client = i2c_new_device(adapter, &board_info);
+       if (client == NULL || client->dev.driver == NULL) {
+               ret = -ENODEV;
+               goto err;
+       }
+
+       /* increase I2C driver usage count */
+       if (!try_module_get(client->dev.driver->owner)) {
+               i2c_unregister_device(client);
+               ret = -ENODEV;
+               goto err;
+       }
+
+       state->i2c_client[num] = client;
+       return 0;
+err:
+       dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret);
+       return ret;
+}
+
+static void af9035_del_i2c_dev(struct dvb_usb_device *d)
+{
+       int num;
+       struct state *state = d_to_priv(d);
+       struct i2c_client *client;
+
+       /* find last used client */
+       num = AF9035_I2C_CLIENT_MAX;
+       while (num--) {
+               if (state->i2c_client[num] != NULL)
+                       break;
+       }
+
+       dev_dbg(&d->udev->dev, "%s: num=%d\n", __func__, num);
+
+       if (num == -1) {
+               dev_err(&d->udev->dev, "%s: I2C client out of index\n",
+                               KBUILD_MODNAME);
+               goto err;
+       }
+
+       client = state->i2c_client[num];
+
+       /* decrease I2C driver usage count */
+       module_put(client->dev.driver->owner);
+
+       /* unregister I2C device */
+       i2c_unregister_device(client);
+
+       state->i2c_client[num] = NULL;
+       return;
+err:
+       dev_dbg(&d->udev->dev, "%s: failed\n", __func__);
+}
+
 static int af9035_i2c_master_xfer(struct i2c_adapter *adap,
                struct i2c_msg msg[], int num)
 {
@@ -204,7 +290,7 @@ static int af9035_i2c_master_xfer(struct i2c_adapter *adap,
                return -EAGAIN;
 
        /*
-        * I2C sub header is 5 bytes long. Meaning of those bytes are:
+        * AF9035 I2C sub header is 5 bytes long. Meaning of those bytes are:
         * 0: data len
         * 1: I2C addr << 1
         * 2: reg addr len
@@ -218,110 +304,156 @@ static int af9035_i2c_master_xfer(struct i2c_adapter *adap,
         * NOTE: As a firmware knows tuner type there is very small possibility
         * there could be some tuner I2C hacks done by firmware and this may
         * lead problems if firmware expects those bytes are used.
+        *
+        * TODO: Here is few hacks. AF9035 chip integrates AF9033 demodulator.
+        * IT9135 chip integrates AF9033 demodulator and RF tuner. For dual
+        * tuner devices, there is also external AF9033 demodulator connected
+        * via external I2C bus. All AF9033 demod I2C traffic, both single and
+        * dual tuner configuration, is covered by firmware - actual USB IO
+        * looks just like a memory access.
+        * In case of IT913x chip, there is own tuner driver. It is implemented
+        * currently as a I2C driver, even tuner IP block is likely build
+        * directly into the demodulator memory space and there is no own I2C
+        * bus. I2C subsystem does not allow register multiple devices to same
+        * bus, having same slave address. Due to that we reuse demod address,
+        * shifted by one bit, on that case.
+        *
+        * For IT930x we use a different command and the sub header is
+        * different as well:
+        * 0: data len
+        * 1: I2C bus (0x03 seems to be only value used)
+        * 2: I2C addr << 1
         */
-       if (num == 2 && !(msg[0].flags & I2C_M_RD) &&
-                       (msg[1].flags & I2C_M_RD)) {
+#define AF9035_IS_I2C_XFER_WRITE_READ(_msg, _num) \
+       (_num == 2 && !(_msg[0].flags & I2C_M_RD) && (_msg[1].flags & I2C_M_RD))
+#define AF9035_IS_I2C_XFER_WRITE(_msg, _num) \
+       (_num == 1 && !(_msg[0].flags & I2C_M_RD))
+#define AF9035_IS_I2C_XFER_READ(_msg, _num) \
+       (_num == 1 && (_msg[0].flags & I2C_M_RD))
+
+       if (AF9035_IS_I2C_XFER_WRITE_READ(msg, num)) {
                if (msg[0].len > 40 || msg[1].len > 40) {
                        /* TODO: correct limits > 40 */
                        ret = -EOPNOTSUPP;
-               } else if ((msg[0].addr == state->af9033_config[0].i2c_addr) ||
-                          (msg[0].addr == state->af9033_config[1].i2c_addr)) {
+               } else if ((msg[0].addr == state->af9033_i2c_addr[0]) ||
+                          (msg[0].addr == state->af9033_i2c_addr[1]) ||
+                          (state->chip_type == 0x9135)) {
                        /* demod access via firmware interface */
                        u32 reg = msg[0].buf[0] << 16 | msg[0].buf[1] << 8 |
                                        msg[0].buf[2];
 
-                       if (msg[0].addr == state->af9033_config[1].i2c_addr)
+                       if (msg[0].addr == state->af9033_i2c_addr[1] ||
+                           msg[0].addr == (state->af9033_i2c_addr[1] >> 1))
                                reg |= 0x100000;
 
                        ret = af9035_rd_regs(d, reg, &msg[1].buf[0],
                                        msg[1].len);
                } else {
-                       /* I2C */
+                       /* I2C write + read */
                        u8 buf[MAX_XFER_SIZE];
                        struct usb_req req = { CMD_I2C_RD, 0, 5 + msg[0].len,
                                        buf, msg[1].len, msg[1].buf };
 
-                       if (5 + msg[0].len > sizeof(buf)) {
-                               dev_warn(&d->udev->dev,
-                                        "%s: i2c xfer: len=%d is too big!\n",
-                                        KBUILD_MODNAME, msg[0].len);
-                               ret = -EOPNOTSUPP;
-                               goto unlock;
+                       if (state->chip_type == 0x9306) {
+                               req.cmd = CMD_GENERIC_I2C_RD;
+                               req.wlen = 3 + msg[0].len;
                        }
                        req.mbox |= ((msg[0].addr & 0x80)  >>  3);
+
                        buf[0] = msg[1].len;
-                       buf[1] = msg[0].addr << 1;
-                       buf[2] = 0x00; /* reg addr len */
-                       buf[3] = 0x00; /* reg addr MSB */
-                       buf[4] = 0x00; /* reg addr LSB */
-                       memcpy(&buf[5], msg[0].buf, msg[0].len);
+                       if (state->chip_type == 0x9306) {
+                               buf[1] = 0x03; /* I2C bus */
+                               buf[2] = msg[0].addr << 1;
+                               memcpy(&buf[3], msg[0].buf, msg[0].len);
+                       } else {
+                               buf[1] = msg[0].addr << 1;
+                               buf[2] = 0x00; /* reg addr len */
+                               buf[3] = 0x00; /* reg addr MSB */
+                               buf[4] = 0x00; /* reg addr LSB */
+                               memcpy(&buf[5], msg[0].buf, msg[0].len);
+                       }
                        ret = af9035_ctrl_msg(d, &req);
                }
-       } else if (num == 1 && !(msg[0].flags & I2C_M_RD)) {
+       } else if (AF9035_IS_I2C_XFER_WRITE(msg, num)) {
                if (msg[0].len > 40) {
                        /* TODO: correct limits > 40 */
                        ret = -EOPNOTSUPP;
-               } else if ((msg[0].addr == state->af9033_config[0].i2c_addr) ||
-                          (msg[0].addr == state->af9033_config[1].i2c_addr)) {
+               } else if ((msg[0].addr == state->af9033_i2c_addr[0]) ||
+                          (msg[0].addr == state->af9033_i2c_addr[1]) ||
+                          (state->chip_type == 0x9135)) {
                        /* demod access via firmware interface */
                        u32 reg = msg[0].buf[0] << 16 | msg[0].buf[1] << 8 |
                                        msg[0].buf[2];
 
-                       if (msg[0].addr == state->af9033_config[1].i2c_addr)
+                       if (msg[0].addr == state->af9033_i2c_addr[1] ||
+                           msg[0].addr == (state->af9033_i2c_addr[1] >> 1))
                                reg |= 0x100000;
 
                        ret = af9035_wr_regs(d, reg, &msg[0].buf[3],
                                        msg[0].len - 3);
                } else {
-                       /* I2C */
+                       /* I2C write */
                        u8 buf[MAX_XFER_SIZE];
                        struct usb_req req = { CMD_I2C_WR, 0, 5 + msg[0].len,
                                        buf, 0, NULL };
 
-                       if (5 + msg[0].len > sizeof(buf)) {
-                               dev_warn(&d->udev->dev,
-                                        "%s: i2c xfer: len=%d is too big!\n",
-                                        KBUILD_MODNAME, msg[0].len);
-                               ret = -EOPNOTSUPP;
-                               goto unlock;
+                       if (state->chip_type == 0x9306) {
+                               req.cmd = CMD_GENERIC_I2C_WR;
+                               req.wlen = 3 + msg[0].len;
                        }
+
                        req.mbox |= ((msg[0].addr & 0x80)  >>  3);
                        buf[0] = msg[0].len;
-                       buf[1] = msg[0].addr << 1;
-                       buf[2] = 0x00; /* reg addr len */
-                       buf[3] = 0x00; /* reg addr MSB */
-                       buf[4] = 0x00; /* reg addr LSB */
-                       memcpy(&buf[5], msg[0].buf, msg[0].len);
+                       if (state->chip_type == 0x9306) {
+                               buf[1] = 0x03; /* I2C bus */
+                               buf[2] = msg[0].addr << 1;
+                               memcpy(&buf[3], msg[0].buf, msg[0].len);
+                       } else {
+                               buf[1] = msg[0].addr << 1;
+                               buf[2] = 0x00; /* reg addr len */
+                               buf[3] = 0x00; /* reg addr MSB */
+                               buf[4] = 0x00; /* reg addr LSB */
+                               memcpy(&buf[5], msg[0].buf, msg[0].len);
+                       }
                        ret = af9035_ctrl_msg(d, &req);
                }
-       } else if (num == 1 && (msg[0].flags & I2C_M_RD)) {
+       } else if (AF9035_IS_I2C_XFER_READ(msg, num)) {
                if (msg[0].len > 40) {
                        /* TODO: correct limits > 40 */
                        ret = -EOPNOTSUPP;
                } else {
-                       /* I2C */
+                       /* I2C read */
                        u8 buf[5];
                        struct usb_req req = { CMD_I2C_RD, 0, sizeof(buf),
-                                       buf, msg[0].len, msg[0].buf };
+                                               buf, msg[0].len, msg[0].buf };
+
+                       if (state->chip_type == 0x9306) {
+                               req.cmd = CMD_GENERIC_I2C_RD;
+                               req.wlen = 3;
+                       }
                        req.mbox |= ((msg[0].addr & 0x80)  >>  3);
                        buf[0] = msg[0].len;
-                       buf[1] = msg[0].addr << 1;
-                       buf[2] = 0x00; /* reg addr len */
-                       buf[3] = 0x00; /* reg addr MSB */
-                       buf[4] = 0x00; /* reg addr LSB */
+                       if (state->chip_type == 0x9306) {
+                               buf[1] = 0x03; /* I2C bus */
+                               buf[2] = msg[0].addr << 1;
+                       } else {
+                               buf[1] = msg[0].addr << 1;
+                               buf[2] = 0x00; /* reg addr len */
+                               buf[3] = 0x00; /* reg addr MSB */
+                               buf[4] = 0x00; /* reg addr LSB */
+                       }
                        ret = af9035_ctrl_msg(d, &req);
                }
        } else {
                /*
                 * We support only three kind of I2C transactions:
-                * 1) 1 x read + 1 x write (repeated start)
+                * 1) 1 x write + 1 x read (repeated start)
                 * 2) 1 x write
                 * 3) 1 x read
                 */
                ret = -EOPNOTSUPP;
        }
 
-unlock:
        mutex_unlock(&d->i2c_mutex);
 
        if (ret < 0)
@@ -371,6 +503,9 @@ static int af9035_identify_state(struct dvb_usb_device *d, const char **name)
                else
                        *name = AF9035_FIRMWARE_IT9135_V1;
                state->eeprom_addr = EEPROM_BASE_IT9135;
+       } else if (state->chip_type == 0x9306) {
+               *name = AF9035_FIRMWARE_IT9303;
+               state->eeprom_addr = EEPROM_BASE_IT9135;
        } else {
                *name = AF9035_FIRMWARE_AF9035;
                state->eeprom_addr = EEPROM_BASE_AF9035;
@@ -536,6 +671,7 @@ static int af9035_download_firmware(struct dvb_usb_device *d,
        u8 tmp;
        struct usb_req req = { 0, 0, 0, NULL, 0, NULL };
        struct usb_req req_fw_ver = { CMD_FW_QUERYINFO, 0, 1, wbuf, 4, rbuf };
+
        dev_dbg(&d->udev->dev, "%s:\n", __func__);
 
        /*
@@ -579,7 +715,8 @@ static int af9035_download_firmware(struct dvb_usb_device *d,
                if (!tmp)
                        tmp = 0x3a;
 
-               if (state->chip_type == 0x9135) {
+               if ((state->chip_type == 0x9135) ||
+                               (state->chip_type == 0x9306)) {
                        ret = af9035_wr_reg(d, 0x004bfb, tmp);
                        if (ret < 0)
                                goto err;
@@ -640,23 +777,26 @@ static int af9035_read_config(struct dvb_usb_device *d)
        u16 tmp16, addr;
 
        /* demod I2C "address" */
-       state->af9033_config[0].i2c_addr = 0x38;
-       state->af9033_config[1].i2c_addr = 0x3a;
+       state->af9033_i2c_addr[0] = 0x38;
+       state->af9033_i2c_addr[1] = 0x3a;
        state->af9033_config[0].adc_multiplier = AF9033_ADC_MULTIPLIER_2X;
        state->af9033_config[1].adc_multiplier = AF9033_ADC_MULTIPLIER_2X;
        state->af9033_config[0].ts_mode = AF9033_TS_MODE_USB;
        state->af9033_config[1].ts_mode = AF9033_TS_MODE_SERIAL;
 
-       /* eeprom memory mapped location */
        if (state->chip_type == 0x9135) {
+               /* feed clock for integrated RF tuner */
+               state->af9033_config[0].dyn0_clk = true;
+               state->af9033_config[1].dyn0_clk = true;
+
                if (state->chip_version == 0x02) {
                        state->af9033_config[0].tuner = AF9033_TUNER_IT9135_60;
                        state->af9033_config[1].tuner = AF9033_TUNER_IT9135_60;
-                       tmp16 = 0x00461d;
+                       tmp16 = 0x00461d; /* eeprom memory mapped location */
                } else {
                        state->af9033_config[0].tuner = AF9033_TUNER_IT9135_38;
                        state->af9033_config[1].tuner = AF9033_TUNER_IT9135_38;
-                       tmp16 = 0x00461b;
+                       tmp16 = 0x00461b; /* eeprom memory mapped location */
                }
 
                /* check if eeprom exists */
@@ -668,8 +808,16 @@ static int af9035_read_config(struct dvb_usb_device *d)
                        dev_dbg(&d->udev->dev, "%s: no eeprom\n", __func__);
                        goto skip_eeprom;
                }
+       } else if (state->chip_type == 0x9306) {
+               /*
+                * IT930x is an USB bridge, only single demod-single tuner
+                * configurations seen so far.
+                */
+               return 0;
        }
 
+
+
        /* check if there is dual tuners */
        ret = af9035_rd_reg(d, state->eeprom_addr + EEPROM_TS_MODE, &tmp);
        if (ret < 0)
@@ -690,7 +838,7 @@ static int af9035_read_config(struct dvb_usb_device *d)
                        goto err;
 
                if (tmp)
-                       state->af9033_config[1].i2c_addr = tmp;
+                       state->af9033_i2c_addr[1] = tmp;
 
                dev_dbg(&d->udev->dev, "%s: 2nd demod I2C addr=%02x\n",
                                __func__, tmp);
@@ -799,25 +947,6 @@ static int af9035_read_config(struct dvb_usb_device *d)
                addr += 0x10; /* shift for the 2nd tuner params */
        }
 
-       /*
-        * These AVerMedia devices has a bad EEPROM content :-(
-        * Override some wrong values here.
-        */
-       if (le16_to_cpu(d->udev->descriptor.idVendor) == USB_VID_AVERMEDIA) {
-               switch (le16_to_cpu(d->udev->descriptor.idProduct)) {
-               case USB_PID_AVERMEDIA_A835B_1835:
-               case USB_PID_AVERMEDIA_A835B_2835:
-               case USB_PID_AVERMEDIA_A835B_3835:
-                       dev_info(&d->udev->dev,
-                                "%s: overriding tuner from %02x to %02x\n",
-                                KBUILD_MODNAME, state->af9033_config[0].tuner,
-                                AF9033_TUNER_IT9135_60);
-
-                       state->af9033_config[0].tuner = AF9033_TUNER_IT9135_60;
-                       break;
-               }
-       }
-
 skip_eeprom:
        /* get demod clock */
        ret = af9035_rd_reg(d, 0x00d800, &tmp);
@@ -990,6 +1119,7 @@ static int af9035_frontend_callback(void *adapter_priv, int component,
 static int af9035_get_adapter_count(struct dvb_usb_device *d)
 {
        struct state *state = d_to_priv(d);
+
        return state->dual_mode + 1;
 }
 
@@ -998,7 +1128,8 @@ static int af9035_frontend_attach(struct dvb_usb_adapter *adap)
        struct state *state = adap_to_priv(adap);
        struct dvb_usb_device *d = adap_to_d(adap);
        int ret;
-       dev_dbg(&d->udev->dev, "%s:\n", __func__);
+
+       dev_dbg(&d->udev->dev, "%s: adap->id=%d\n", __func__, adap->id);
 
        if (!state->af9033_config[adap->id].tuner) {
                /* unsupported tuner */
@@ -1006,9 +1137,13 @@ static int af9035_frontend_attach(struct dvb_usb_adapter *adap)
                goto err;
        }
 
-       /* attach demodulator */
-       adap->fe[0] = dvb_attach(af9033_attach, &state->af9033_config[adap->id],
-                       &d->i2c_adap, &state->ops);
+       state->af9033_config[adap->id].fe = &adap->fe[0];
+       state->af9033_config[adap->id].ops = &state->ops;
+       ret = af9035_add_i2c_dev(d, "af9033", state->af9033_i2c_addr[adap->id],
+                       &state->af9033_config[adap->id], &d->i2c_adap);
+       if (ret)
+               goto err;
+
        if (adap->fe[0] == NULL) {
                ret = -ENODEV;
                goto err;
@@ -1026,6 +1161,78 @@ err:
        return ret;
 }
 
+static int it930x_frontend_attach(struct dvb_usb_adapter *adap)
+{
+       struct state *state = adap_to_priv(adap);
+       struct dvb_usb_device *d = adap_to_d(adap);
+       int ret;
+       struct si2168_config si2168_config;
+       struct i2c_adapter *adapter;
+
+       dev_dbg(&d->udev->dev, "adap->id=%d\n", adap->id);
+
+       si2168_config.i2c_adapter = &adapter;
+       si2168_config.fe = &adap->fe[0];
+       si2168_config.ts_mode = SI2168_TS_SERIAL;
+
+       state->af9033_config[adap->id].fe = &adap->fe[0];
+       state->af9033_config[adap->id].ops = &state->ops;
+       ret = af9035_add_i2c_dev(d, "si2168", 0x67, &si2168_config,
+                               &d->i2c_adap);
+       if (ret)
+               goto err;
+
+       if (adap->fe[0] == NULL) {
+               ret = -ENODEV;
+               goto err;
+       }
+       state->i2c_adapter_demod = adapter;
+
+       return 0;
+
+err:
+       dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret);
+
+       return ret;
+}
+
+static int af9035_frontend_detach(struct dvb_usb_adapter *adap)
+{
+       struct state *state = adap_to_priv(adap);
+       struct dvb_usb_device *d = adap_to_d(adap);
+       int demod2;
+
+       dev_dbg(&d->udev->dev, "%s: adap->id=%d\n", __func__, adap->id);
+
+       /*
+        * For dual tuner devices we have to resolve 2nd demod client, as there
+        * is two different kind of tuner drivers; one is using I2C binding
+        * and the other is using DVB attach/detach binding.
+        */
+       switch (state->af9033_config[adap->id].tuner) {
+       case AF9033_TUNER_IT9135_38:
+       case AF9033_TUNER_IT9135_51:
+       case AF9033_TUNER_IT9135_52:
+       case AF9033_TUNER_IT9135_60:
+       case AF9033_TUNER_IT9135_61:
+       case AF9033_TUNER_IT9135_62:
+               demod2 = 2;
+               break;
+       default:
+               demod2 = 1;
+       }
+
+       if (adap->id == 1) {
+               if (state->i2c_client[demod2])
+                       af9035_del_i2c_dev(d);
+       } else if (adap->id == 0) {
+               if (state->i2c_client[0])
+                       af9035_del_i2c_dev(d);
+       }
+
+       return 0;
+}
+
 static struct tua9001_config af9035_tua9001_config = {
        .i2c_addr = 0x60,
 };
@@ -1084,7 +1291,8 @@ static int af9035_tuner_attach(struct dvb_usb_adapter *adap)
        struct dvb_frontend *fe;
        struct i2c_msg msg[1];
        u8 tuner_addr;
-       dev_dbg(&d->udev->dev, "%s:\n", __func__);
+
+       dev_dbg(&d->udev->dev, "%s: adap->id=%d\n", __func__, adap->id);
 
        /*
         * XXX: Hack used in that function: we abuse unused I2C address bit [7]
@@ -1243,14 +1451,53 @@ static int af9035_tuner_attach(struct dvb_usb_adapter *adap)
        case AF9033_TUNER_IT9135_38:
        case AF9033_TUNER_IT9135_51:
        case AF9033_TUNER_IT9135_52:
+       {
+               struct it913x_config it913x_config = {
+                       .fe = adap->fe[0],
+                       .chip_ver = 1,
+               };
+
+               if (state->dual_mode) {
+                       if (adap->id == 0)
+                               it913x_config.role = IT913X_ROLE_DUAL_MASTER;
+                       else
+                               it913x_config.role = IT913X_ROLE_DUAL_SLAVE;
+               }
+
+               ret = af9035_add_i2c_dev(d, "it913x",
+                               state->af9033_i2c_addr[adap->id] >> 1,
+                               &it913x_config, &d->i2c_adap);
+               if (ret)
+                       goto err;
+
+               fe = adap->fe[0];
+               break;
+       }
        case AF9033_TUNER_IT9135_60:
        case AF9033_TUNER_IT9135_61:
        case AF9033_TUNER_IT9135_62:
-               /* attach tuner */
-               fe = dvb_attach(it913x_attach, adap->fe[0], &d->i2c_adap,
-                               state->af9033_config[adap->id].i2c_addr,
-                               state->af9033_config[0].tuner);
+       {
+               struct it913x_config it913x_config = {
+                       .fe = adap->fe[0],
+                       .chip_ver = 2,
+               };
+
+               if (state->dual_mode) {
+                       if (adap->id == 0)
+                               it913x_config.role = IT913X_ROLE_DUAL_MASTER;
+                       else
+                               it913x_config.role = IT913X_ROLE_DUAL_SLAVE;
+               }
+
+               ret = af9035_add_i2c_dev(d, "it913x",
+                               state->af9033_i2c_addr[adap->id] >> 1,
+                               &it913x_config, &d->i2c_adap);
+               if (ret)
+                       goto err;
+
+               fe = adap->fe[0];
                break;
+       }
        default:
                fe = NULL;
        }
@@ -1268,6 +1515,119 @@ err:
        return ret;
 }
 
+static int it930x_tuner_attach(struct dvb_usb_adapter *adap)
+{
+       struct state *state = adap_to_priv(adap);
+       struct dvb_usb_device *d = adap_to_d(adap);
+       int ret;
+       struct si2157_config si2157_config;
+
+       dev_dbg(&d->udev->dev, "%s: adap->id=%d\n", __func__, adap->id);
+
+       /* I2C master bus 2 clock speed 300k */
+       ret = af9035_wr_reg(d, 0x00f6a7, 0x07);
+       if (ret < 0)
+               goto err;
+
+       /* I2C master bus 1,3 clock speed 300k */
+       ret = af9035_wr_reg(d, 0x00f103, 0x07);
+       if (ret < 0)
+               goto err;
+
+       /* set gpio11 low */
+       ret = af9035_wr_reg_mask(d, 0xd8d4, 0x01, 0x01);
+       if (ret < 0)
+               goto err;
+
+       ret = af9035_wr_reg_mask(d, 0xd8d5, 0x01, 0x01);
+       if (ret < 0)
+               goto err;
+
+       ret = af9035_wr_reg_mask(d, 0xd8d3, 0x01, 0x01);
+       if (ret < 0)
+               goto err;
+
+       /* Tuner enable using gpiot2_en, gpiot2_on and gpiot2_o (reset) */
+       ret = af9035_wr_reg_mask(d, 0xd8b8, 0x01, 0x01);
+       if (ret < 0)
+               goto err;
+
+       ret = af9035_wr_reg_mask(d, 0xd8b9, 0x01, 0x01);
+       if (ret < 0)
+               goto err;
+
+       ret = af9035_wr_reg_mask(d, 0xd8b7, 0x00, 0x01);
+       if (ret < 0)
+               goto err;
+
+       msleep(200);
+
+       ret = af9035_wr_reg_mask(d, 0xd8b7, 0x01, 0x01);
+       if (ret < 0)
+               goto err;
+
+       memset(&si2157_config, 0, sizeof(si2157_config));
+       si2157_config.fe = adap->fe[0];
+       ret = af9035_add_i2c_dev(d, "si2157", 0x63,
+                       &si2157_config, state->i2c_adapter_demod);
+
+       if (ret)
+               goto err;
+
+       return 0;
+
+err:
+       dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret);
+
+       return ret;
+}
+
+
+static int it930x_tuner_detach(struct dvb_usb_adapter *adap)
+{
+       struct state *state = adap_to_priv(adap);
+       struct dvb_usb_device *d = adap_to_d(adap);
+
+       dev_dbg(&d->udev->dev, "adap->id=%d\n", adap->id);
+
+       if (adap->id == 1) {
+               if (state->i2c_client[3])
+                       af9035_del_i2c_dev(d);
+       } else if (adap->id == 0) {
+               if (state->i2c_client[1])
+                       af9035_del_i2c_dev(d);
+       }
+
+       return 0;
+}
+
+
+static int af9035_tuner_detach(struct dvb_usb_adapter *adap)
+{
+       struct state *state = adap_to_priv(adap);
+       struct dvb_usb_device *d = adap_to_d(adap);
+
+       dev_dbg(&d->udev->dev, "%s: adap->id=%d\n", __func__, adap->id);
+
+       switch (state->af9033_config[adap->id].tuner) {
+       case AF9033_TUNER_IT9135_38:
+       case AF9033_TUNER_IT9135_51:
+       case AF9033_TUNER_IT9135_52:
+       case AF9033_TUNER_IT9135_60:
+       case AF9033_TUNER_IT9135_61:
+       case AF9033_TUNER_IT9135_62:
+               if (adap->id == 1) {
+                       if (state->i2c_client[3])
+                               af9035_del_i2c_dev(d);
+               } else if (adap->id == 0) {
+                       if (state->i2c_client[1])
+                               af9035_del_i2c_dev(d);
+               }
+       }
+
+       return 0;
+}
+
 static int af9035_init(struct dvb_usb_device *d)
 {
        struct state *state = d_to_priv(d);
@@ -1315,6 +1675,89 @@ err:
        return ret;
 }
 
+static int it930x_init(struct dvb_usb_device *d)
+{
+       struct state *state = d_to_priv(d);
+       int ret, i;
+       u16 frame_size = (d->udev->speed == USB_SPEED_FULL ? 5 : 816) * 188 / 4;
+       u8 packet_size = (d->udev->speed == USB_SPEED_FULL ? 64 : 512) / 4;
+       struct reg_val_mask tab[] = {
+               { 0x00da1a, 0x00, 0x01 }, /* ignore_sync_byte */
+               { 0x00f41f, 0x04, 0x04 }, /* dvbt_inten */
+               { 0x00da10, 0x00, 0x01 }, /* mpeg_full_speed */
+               { 0x00f41a, 0x01, 0x01 }, /* dvbt_en */
+               { 0x00da1d, 0x01, 0x01 }, /* mp2_sw_rst, reset EP4 */
+               { 0x00dd11, 0x00, 0x20 }, /* ep4_tx_en, disable EP4 */
+               { 0x00dd13, 0x00, 0x20 }, /* ep4_tx_nak, disable EP4 NAK */
+               { 0x00dd11, 0x20, 0x20 }, /* ep4_tx_en, enable EP4 */
+               { 0x00dd11, 0x00, 0x40 }, /* ep5_tx_en, disable EP5 */
+               { 0x00dd13, 0x00, 0x40 }, /* ep5_tx_nak, disable EP5 NAK */
+               { 0x00dd11, state->dual_mode << 6, 0x40 }, /* enable EP5 */
+               { 0x00dd88, (frame_size >> 0) & 0xff, 0xff},
+               { 0x00dd89, (frame_size >> 8) & 0xff, 0xff},
+               { 0x00dd0c, packet_size, 0xff},
+               { 0x00dd8a, (frame_size >> 0) & 0xff, 0xff},
+               { 0x00dd8b, (frame_size >> 8) & 0xff, 0xff},
+               { 0x00dd0d, packet_size, 0xff },
+               { 0x00da1d, 0x00, 0x01 }, /* mp2_sw_rst, disable */
+               { 0x00d833, 0x01, 0xff }, /* slew rate ctrl: slew rate boosts */
+               { 0x00d830, 0x00, 0xff }, /* Bit 0 of output driving control */
+               { 0x00d831, 0x01, 0xff }, /* Bit 1 of output driving control */
+               { 0x00d832, 0x00, 0xff }, /* Bit 2 of output driving control */
+
+               /* suspend gpio1 for TS-C */
+               { 0x00d8b0, 0x01, 0xff }, /* gpio1 */
+               { 0x00d8b1, 0x01, 0xff }, /* gpio1 */
+               { 0x00d8af, 0x00, 0xff }, /* gpio1 */
+
+               /* suspend gpio7 for TS-D */
+               { 0x00d8c4, 0x01, 0xff }, /* gpio7 */
+               { 0x00d8c5, 0x01, 0xff }, /* gpio7 */
+               { 0x00d8c3, 0x00, 0xff }, /* gpio7 */
+
+               /* suspend gpio13 for TS-B */
+               { 0x00d8dc, 0x01, 0xff }, /* gpio13 */
+               { 0x00d8dd, 0x01, 0xff }, /* gpio13 */
+               { 0x00d8db, 0x00, 0xff }, /* gpio13 */
+
+               /* suspend gpio14 for TS-E */
+               { 0x00d8e4, 0x01, 0xff }, /* gpio14 */
+               { 0x00d8e5, 0x01, 0xff }, /* gpio14 */
+               { 0x00d8e3, 0x00, 0xff }, /* gpio14 */
+
+               /* suspend gpio15 for TS-A */
+               { 0x00d8e8, 0x01, 0xff }, /* gpio15 */
+               { 0x00d8e9, 0x01, 0xff }, /* gpio15 */
+               { 0x00d8e7, 0x00, 0xff }, /* gpio15 */
+
+               { 0x00da58, 0x00, 0x01 }, /* ts_in_src, serial */
+               { 0x00da73, 0x01, 0xff }, /* ts0_aggre_mode */
+               { 0x00da78, 0x47, 0xff }, /* ts0_sync_byte */
+               { 0x00da4c, 0x01, 0xff }, /* ts0_en */
+               { 0x00da5a, 0x1f, 0xff }, /* ts_fail_ignore */
+       };
+
+       dev_dbg(&d->udev->dev,
+                       "%s: USB speed=%d frame_size=%04x packet_size=%02x\n",
+                       __func__, d->udev->speed, frame_size, packet_size);
+
+       /* init endpoints */
+       for (i = 0; i < ARRAY_SIZE(tab); i++) {
+               ret = af9035_wr_reg_mask(d, tab[i].reg,
+                               tab[i].val, tab[i].mask);
+
+               if (ret < 0)
+                       goto err;
+       }
+
+       return 0;
+err:
+       dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret);
+
+       return ret;
+}
+
+
 #if IS_ENABLED(CONFIG_RC_CORE)
 static int af9035_rc_query(struct dvb_usb_device *d)
 {
@@ -1409,6 +1852,7 @@ static int af9035_get_stream_config(struct dvb_frontend *fe, u8 *ts_type,
                struct usb_data_stream_properties *stream)
 {
        struct dvb_usb_device *d = fe_to_d(fe);
+
        dev_dbg(&d->udev->dev, "%s: adap=%d\n", __func__, fe_to_adap(fe)->id);
 
        if (d->udev->speed == USB_SPEED_FULL)
@@ -1486,7 +1930,9 @@ static const struct dvb_usb_device_properties af9035_props = {
        .i2c_algo = &af9035_i2c_algo,
        .read_config = af9035_read_config,
        .frontend_attach = af9035_frontend_attach,
+       .frontend_detach = af9035_frontend_detach,
        .tuner_attach = af9035_tuner_attach,
+       .tuner_detach = af9035_tuner_detach,
        .init = af9035_init,
        .get_rc_config = af9035_get_rc_config,
        .get_stream_config = af9035_get_stream_config,
@@ -1515,6 +1961,37 @@ static const struct dvb_usb_device_properties af9035_props = {
        },
 };
 
+static const struct dvb_usb_device_properties it930x_props = {
+       .driver_name = KBUILD_MODNAME,
+       .owner = THIS_MODULE,
+       .adapter_nr = adapter_nr,
+       .size_of_priv = sizeof(struct state),
+
+       .generic_bulk_ctrl_endpoint = 0x02,
+       .generic_bulk_ctrl_endpoint_response = 0x81,
+
+       .identify_state = af9035_identify_state,
+       .download_firmware = af9035_download_firmware,
+
+       .i2c_algo = &af9035_i2c_algo,
+       .read_config = af9035_read_config,
+       .frontend_attach = it930x_frontend_attach,
+       .frontend_detach = af9035_frontend_detach,
+       .tuner_attach = it930x_tuner_attach,
+       .tuner_detach = it930x_tuner_detach,
+       .init = it930x_init,
+       .get_stream_config = af9035_get_stream_config,
+
+       .get_adapter_count = af9035_get_adapter_count,
+       .adapter = {
+               {
+                       .stream = DVB_USB_STREAM_BULK(0x84, 4, 816 * 188),
+               }, {
+                       .stream = DVB_USB_STREAM_BULK(0x85, 4, 816 * 188),
+               },
+       },
+};
+
 static const struct usb_device_id af9035_id_table[] = {
        /* AF9035 devices */
        { DVB_USB_DEVICE(USB_VID_AFATECH, USB_PID_AFATECH_AF9035_9035,
@@ -1568,17 +2045,21 @@ static const struct usb_device_id af9035_id_table[] = {
        { DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_CTVDIGDUAL_V2,
                &af9035_props, "Digital Dual TV Receiver CTVDIGDUAL_V2",
                                                        RC_MAP_IT913X_V1) },
+       /* IT930x devices */
+       { DVB_USB_DEVICE(USB_VID_ITETECH, USB_PID_ITETECH_IT9303,
+               &it930x_props, "ITE 9303 Generic", NULL) },
        /* XXX: that same ID [0ccd:0099] is used by af9015 driver too */
        { DVB_USB_DEVICE(USB_VID_TERRATEC, 0x0099,
-               &af9035_props, "TerraTec Cinergy T Stick Dual RC (rev. 2)", NULL) },
+               &af9035_props, "TerraTec Cinergy T Stick Dual RC (rev. 2)",
+               NULL) },
        { DVB_USB_DEVICE(USB_VID_LEADTEK, 0x6a05,
                &af9035_props, "Leadtek WinFast DTV Dongle Dual", NULL) },
        { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xf900,
                &af9035_props, "Hauppauge WinTV-MiniStick 2", NULL) },
        { DVB_USB_DEVICE(USB_VID_PCTV, USB_PID_PCTV_78E,
-               &af9035_props, "PCTV 78e", RC_MAP_IT913X_V1) },
+               &af9035_props, "PCTV AndroiDTV (78e)", RC_MAP_IT913X_V1) },
        { DVB_USB_DEVICE(USB_VID_PCTV, USB_PID_PCTV_79E,
-               &af9035_props, "PCTV 79e", RC_MAP_IT913X_V2) },
+               &af9035_props, "PCTV microStick (79e)", RC_MAP_IT913X_V2) },
        { }
 };
 MODULE_DEVICE_TABLE(usb, af9035_id_table);
@@ -1603,3 +2084,4 @@ MODULE_LICENSE("GPL");
 MODULE_FIRMWARE(AF9035_FIRMWARE_AF9035);
 MODULE_FIRMWARE(AF9035_FIRMWARE_IT9135_V1);
 MODULE_FIRMWARE(AF9035_FIRMWARE_IT9135_V2);
+MODULE_FIRMWARE(AF9035_FIRMWARE_IT9303);
index c21902fdd4c44e8d04ecce5962487921f4a92c16..416a97f05ec8539fbc2c11dad23e1261a819650c 100644 (file)
@@ -30,7 +30,9 @@
 #include "mxl5007t.h"
 #include "tda18218.h"
 #include "fc2580.h"
-#include "tuner_it913x.h"
+#include "it913x.h"
+#include "si2168.h"
+#include "si2157.h"
 
 struct reg_val {
        u32 reg;
@@ -61,9 +63,12 @@ struct state {
        u16 chip_type;
        u8 dual_mode:1;
        u16 eeprom_addr;
+       u8 af9033_i2c_addr[2];
        struct af9033_config af9033_config[2];
-
        struct af9033_ops ops;
+       #define AF9035_I2C_CLIENT_MAX 4
+       struct i2c_client *i2c_client[AF9035_I2C_CLIENT_MAX];
+       struct i2c_adapter *i2c_adapter_demod;
 };
 
 static const u32 clock_lut_af9035[] = {
@@ -97,6 +102,7 @@ static const u32 clock_lut_it9135[] = {
 #define AF9035_FIRMWARE_AF9035 "dvb-usb-af9035-02.fw"
 #define AF9035_FIRMWARE_IT9135_V1 "dvb-usb-it9135-01.fw"
 #define AF9035_FIRMWARE_IT9135_V2 "dvb-usb-it9135-02.fw"
+#define AF9035_FIRMWARE_IT9303 "dvb-usb-it9303-01.fw"
 
 /*
  * eeprom is memory mapped as read only. Writing that memory mapped address
@@ -138,5 +144,7 @@ static const u32 clock_lut_it9135[] = {
 #define CMD_FW_DL_BEGIN             0x24
 #define CMD_FW_DL_END               0x25
 #define CMD_FW_SCATTER_WR           0x29
+#define CMD_GENERIC_I2C_RD          0x2a
+#define CMD_GENERIC_I2C_WR          0x2b
 
 #endif
index e4a2382196f0b98dba2cf82cba61879357ad397b..d3c5f230e97a7272f69e7cbba367c3a18c9cbe8b 100644 (file)
@@ -332,7 +332,6 @@ static struct tda10023_config anysee_tda10023_tda18212_config = {
 };
 
 static struct tda18212_config anysee_tda18212_config = {
-       .i2c_address = (0xc0 >> 1),
        .if_dvbt_6 = 4150,
        .if_dvbt_7 = 4150,
        .if_dvbt_8 = 4150,
@@ -340,7 +339,6 @@ static struct tda18212_config anysee_tda18212_config = {
 };
 
 static struct tda18212_config anysee_tda18212_config2 = {
-       .i2c_address = 0x60 /* (0xc0 >> 1) */,
        .if_dvbt_6 = 3550,
        .if_dvbt_7 = 3700,
        .if_dvbt_8 = 4150,
@@ -632,6 +630,92 @@ error:
        return ret;
 }
 
+static int anysee_add_i2c_dev(struct dvb_usb_device *d, char *type, u8 addr,
+               void *platform_data)
+{
+       int ret, num;
+       struct anysee_state *state = d_to_priv(d);
+       struct i2c_client *client;
+       struct i2c_adapter *adapter = &d->i2c_adap;
+       struct i2c_board_info board_info = {
+               .addr = addr,
+               .platform_data = platform_data,
+       };
+
+       strlcpy(board_info.type, type, I2C_NAME_SIZE);
+
+       /* find first free client */
+       for (num = 0; num < ANYSEE_I2C_CLIENT_MAX; num++) {
+               if (state->i2c_client[num] == NULL)
+                       break;
+       }
+
+       dev_dbg(&d->udev->dev, "%s: num=%d\n", __func__, num);
+
+       if (num == ANYSEE_I2C_CLIENT_MAX) {
+               dev_err(&d->udev->dev, "%s: I2C client out of index\n",
+                               KBUILD_MODNAME);
+               ret = -ENODEV;
+               goto err;
+       }
+
+       request_module(board_info.type);
+
+       /* register I2C device */
+       client = i2c_new_device(adapter, &board_info);
+       if (client == NULL || client->dev.driver == NULL) {
+               ret = -ENODEV;
+               goto err;
+       }
+
+       /* increase I2C driver usage count */
+       if (!try_module_get(client->dev.driver->owner)) {
+               i2c_unregister_device(client);
+               ret = -ENODEV;
+               goto err;
+       }
+
+       state->i2c_client[num] = client;
+       return 0;
+err:
+       dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret);
+       return ret;
+}
+
+static void anysee_del_i2c_dev(struct dvb_usb_device *d)
+{
+       int num;
+       struct anysee_state *state = d_to_priv(d);
+       struct i2c_client *client;
+
+       /* find last used client */
+       num = ANYSEE_I2C_CLIENT_MAX;
+       while (num--) {
+               if (state->i2c_client[num] != NULL)
+                       break;
+       }
+
+       dev_dbg(&d->udev->dev, "%s: num=%d\n", __func__, num);
+
+       if (num == -1) {
+               dev_err(&d->udev->dev, "%s: I2C client out of index\n",
+                               KBUILD_MODNAME);
+               goto err;
+       }
+
+       client = state->i2c_client[num];
+
+       /* decrease I2C driver usage count */
+       module_put(client->dev.driver->owner);
+
+       /* unregister I2C device */
+       i2c_unregister_device(client);
+
+       state->i2c_client[num] = NULL;
+err:
+       dev_dbg(&d->udev->dev, "%s: failed\n", __func__);
+}
+
 static int anysee_frontend_attach(struct dvb_usb_adapter *adap)
 {
        struct anysee_state *state = adap_to_priv(adap);
@@ -640,12 +724,12 @@ static int anysee_frontend_attach(struct dvb_usb_adapter *adap)
        u8 tmp;
        struct i2c_msg msg[2] = {
                {
-                       .addr = anysee_tda18212_config.i2c_address,
+                       .addr = 0x60,
                        .flags = 0,
                        .len = 1,
                        .buf = "\x00",
                }, {
-                       .addr = anysee_tda18212_config.i2c_address,
+                       .addr = 0x60,
                        .flags = I2C_M_RD,
                        .len = 1,
                        .buf = &tmp,
@@ -723,9 +807,11 @@ static int anysee_frontend_attach(struct dvb_usb_adapter *adap)
                /* probe TDA18212 */
                tmp = 0;
                ret = i2c_transfer(&d->i2c_adap, msg, 2);
-               if (ret == 2 && tmp == 0xc7)
+               if (ret == 2 && tmp == 0xc7) {
                        dev_dbg(&d->udev->dev, "%s: TDA18212 found\n",
                                        __func__);
+                       state->has_tda18212 = true;
+               }
                else
                        tmp = 0;
 
@@ -939,46 +1025,63 @@ static int anysee_tuner_attach(struct dvb_usb_adapter *adap)
                 * fails attach old simple PLL. */
 
                /* attach tuner */
-               fe = dvb_attach(tda18212_attach, adap->fe[0], &d->i2c_adap,
-                               &anysee_tda18212_config);
+               if (state->has_tda18212) {
+                       struct tda18212_config tda18212_config =
+                                       anysee_tda18212_config;
 
-               if (fe && adap->fe[1]) {
-                       /* attach tuner for 2nd FE */
-                       fe = dvb_attach(tda18212_attach, adap->fe[1],
-                                       &d->i2c_adap, &anysee_tda18212_config);
-                       break;
-               } else if (fe) {
-                       break;
-               }
-
-               /* attach tuner */
-               fe = dvb_attach(dvb_pll_attach, adap->fe[0], (0xc0 >> 1),
-                               &d->i2c_adap, DVB_PLL_SAMSUNG_DTOS403IH102A);
+                       tda18212_config.fe = adap->fe[0];
+                       ret = anysee_add_i2c_dev(d, "tda18212", 0x60,
+                                       &tda18212_config);
+                       if (ret)
+                               goto err;
+
+                       /* copy tuner ops for 2nd FE as tuner is shared */
+                       if (adap->fe[1]) {
+                               adap->fe[1]->tuner_priv =
+                                               adap->fe[0]->tuner_priv;
+                               memcpy(&adap->fe[1]->ops.tuner_ops,
+                                               &adap->fe[0]->ops.tuner_ops,
+                                               sizeof(struct dvb_tuner_ops));
+                       }
 
-               if (fe && adap->fe[1]) {
-                       /* attach tuner for 2nd FE */
-                       fe = dvb_attach(dvb_pll_attach, adap->fe[1],
+                       return 0;
+               } else {
+                       /* attach tuner */
+                       fe = dvb_attach(dvb_pll_attach, adap->fe[0],
                                        (0xc0 >> 1), &d->i2c_adap,
                                        DVB_PLL_SAMSUNG_DTOS403IH102A);
+
+                       if (fe && adap->fe[1]) {
+                               /* attach tuner for 2nd FE */
+                               fe = dvb_attach(dvb_pll_attach, adap->fe[1],
+                                               (0xc0 >> 1), &d->i2c_adap,
+                                               DVB_PLL_SAMSUNG_DTOS403IH102A);
+                       }
                }
 
                break;
        case ANYSEE_HW_508TC: /* 18 */
        case ANYSEE_HW_508PTC: /* 21 */
+       {
                /* E7 TC */
                /* E7 PTC */
+               struct tda18212_config tda18212_config = anysee_tda18212_config;
 
-               /* attach tuner */
-               fe = dvb_attach(tda18212_attach, adap->fe[0], &d->i2c_adap,
-                               &anysee_tda18212_config);
-
-               if (fe) {
-                       /* attach tuner for 2nd FE */
-                       fe = dvb_attach(tda18212_attach, adap->fe[1],
-                                       &d->i2c_adap, &anysee_tda18212_config);
+               tda18212_config.fe = adap->fe[0];
+               ret = anysee_add_i2c_dev(d, "tda18212", 0x60, &tda18212_config);
+               if (ret)
+                       goto err;
+
+               /* copy tuner ops for 2nd FE as tuner is shared */
+               if (adap->fe[1]) {
+                       adap->fe[1]->tuner_priv = adap->fe[0]->tuner_priv;
+                       memcpy(&adap->fe[1]->ops.tuner_ops,
+                                       &adap->fe[0]->ops.tuner_ops,
+                                       sizeof(struct dvb_tuner_ops));
                }
 
-               break;
+               return 0;
+       }
        case ANYSEE_HW_508S2: /* 19 */
        case ANYSEE_HW_508PS2: /* 22 */
                /* E7 S2 */
@@ -997,13 +1100,18 @@ static int anysee_tuner_attach(struct dvb_usb_adapter *adap)
                break;
 
        case ANYSEE_HW_508T2C: /* 20 */
+       {
                /* E7 T2C */
+               struct tda18212_config tda18212_config =
+                               anysee_tda18212_config2;
 
-               /* attach tuner */
-               fe = dvb_attach(tda18212_attach, adap->fe[0], &d->i2c_adap,
-                               &anysee_tda18212_config2);
+               tda18212_config.fe = adap->fe[0];
+               ret = anysee_add_i2c_dev(d, "tda18212", 0x60, &tda18212_config);
+               if (ret)
+                       goto err;
 
-               break;
+               return 0;
+       }
        default:
                fe = NULL;
        }
@@ -1012,7 +1120,7 @@ static int anysee_tuner_attach(struct dvb_usb_adapter *adap)
                ret = 0;
        else
                ret = -ENODEV;
-
+err:
        return ret;
 }
 
@@ -1270,6 +1378,11 @@ static int anysee_init(struct dvb_usb_device *d)
 
 static void anysee_exit(struct dvb_usb_device *d)
 {
+       struct anysee_state *state = d_to_priv(d);
+
+       if (state->i2c_client[0])
+               anysee_del_i2c_dev(d);
+
        return anysee_ci_release(d);
 }
 
index 8f426d9fc6e1110b14c521deb770e35bbc837843..3ca2bca4ebafacc581bfd3cc3aa17c3d087c209b 100644 (file)
@@ -55,8 +55,11 @@ struct anysee_state {
        u8 buf[64];
        u8 seq;
        u8 hw; /* PCB ID */
+       #define ANYSEE_I2C_CLIENT_MAX 1
+       struct i2c_client *i2c_client[ANYSEE_I2C_CLIENT_MAX];
        u8 fe_id:1; /* frondend ID */
        u8 has_ci:1;
+       u8 has_tda18212:1;
        u8 ci_attached:1;
        struct dvb_ca_en50221 ci;
        unsigned long ci_cam_ready; /* jiffies */
index 124b4baa7e975d9ec63ac8c243d3e2741fd8d4c7..14e111e13e54c31eae02814b9602e1cf06564e4d 100644 (file)
@@ -214,6 +214,7 @@ struct dvb_usb_adapter_properties {
  * @read_config: called to resolve device configuration
  * @read_mac_address: called to resolve adapter mac-address
  * @frontend_attach: called to attach the possible frontends
+ * @frontend_detach: called to detach the possible frontends
  * @tuner_attach: called to attach the possible tuners
  * @frontend_ctrl: called to power on/off active frontend
  * @streaming_ctrl: called to start/stop the usb streaming of adapter
@@ -254,7 +255,9 @@ struct dvb_usb_device_properties {
        int (*read_config) (struct dvb_usb_device *d);
        int (*read_mac_address) (struct dvb_usb_adapter *, u8 []);
        int (*frontend_attach) (struct dvb_usb_adapter *);
+       int (*frontend_detach)(struct dvb_usb_adapter *);
        int (*tuner_attach) (struct dvb_usb_adapter *);
+       int (*tuner_detach)(struct dvb_usb_adapter *);
        int (*frontend_ctrl) (struct dvb_frontend *, int);
        int (*streaming_ctrl) (struct dvb_frontend *, int);
        int (*init) (struct dvb_usb_device *);
index 2e90310be2afd7d9ae954b63c55301ae5d25bac0..1950f37df835187c0ac0e153231b316adcaea106 100644 (file)
@@ -21,7 +21,7 @@
 
 #include "dvb_usb_common.h"
 
-int dvb_usbv2_disable_rc_polling;
+static int dvb_usbv2_disable_rc_polling;
 module_param_named(disable_rc_polling, dvb_usbv2_disable_rc_polling, int, 0644);
 MODULE_PARM_DESC(disable_rc_polling,
                "disable remote control polling (default: 0)");
@@ -664,9 +664,10 @@ err:
 
 static int dvb_usbv2_adapter_frontend_exit(struct dvb_usb_adapter *adap)
 {
-       int i;
-       dev_dbg(&adap_to_d(adap)->udev->dev, "%s: adap=%d\n", __func__,
-                       adap->id);
+       int ret, i;
+       struct dvb_usb_device *d = adap_to_d(adap);
+
+       dev_dbg(&d->udev->dev, "%s: adap=%d\n", __func__, adap->id);
 
        for (i = MAX_NO_OF_FE_PER_ADAP - 1; i >= 0; i--) {
                if (adap->fe[i]) {
@@ -675,6 +676,23 @@ static int dvb_usbv2_adapter_frontend_exit(struct dvb_usb_adapter *adap)
                }
        }
 
+       if (d->props->tuner_detach) {
+               ret = d->props->tuner_detach(adap);
+               if (ret < 0) {
+                       dev_dbg(&d->udev->dev, "%s: tuner_detach() failed=%d\n",
+                                       __func__, ret);
+               }
+       }
+
+       if (d->props->frontend_detach) {
+               ret = d->props->frontend_detach(adap);
+               if (ret < 0) {
+                       dev_dbg(&d->udev->dev,
+                                       "%s: frontend_detach() failed=%d\n",
+                                       __func__, ret);
+               }
+       }
+
        return 0;
 }
 
@@ -762,9 +780,9 @@ static int dvb_usbv2_adapter_exit(struct dvb_usb_device *d)
 
        for (i = MAX_NO_OF_ADAPTER_PER_DEVICE - 1; i >= 0; i--) {
                if (d->adapter[i].props) {
-                       dvb_usbv2_adapter_frontend_exit(&d->adapter[i]);
                        dvb_usbv2_adapter_dvb_exit(&d->adapter[i]);
                        dvb_usbv2_adapter_stream_exit(&d->adapter[i]);
+                       dvb_usbv2_adapter_frontend_exit(&d->adapter[i]);
                }
        }
 
index 33ff97e708e3a8c2defa22491ab56cd1619fac8a..22bdce15ecf31fcd351309ca7fa5794cb228869d 100644 (file)
@@ -26,7 +26,7 @@ static int dvb_usb_v2_generic_io(struct dvb_usb_device *d,
 {
        int ret, actual_length;
 
-       if (!d || !wbuf || !wlen || !d->props->generic_bulk_ctrl_endpoint ||
+       if (!wbuf || !wlen || !d->props->generic_bulk_ctrl_endpoint ||
                        !d->props->generic_bulk_ctrl_endpoint_response) {
                dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, -EINVAL);
                return -EINVAL;
diff --git a/drivers/media/usb/dvb-usb-v2/dvbsky.c b/drivers/media/usb/dvb-usb-v2/dvbsky.c
new file mode 100644 (file)
index 0000000..34688c8
--- /dev/null
@@ -0,0 +1,460 @@
+/*
+ * Driver for DVBSky USB2.0 receiver
+ *
+ * Copyright (C) 2013 Max nibble <nibble.max@gmail.com>
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "dvb_usb.h"
+#include "m88ds3103.h"
+#include "m88ts2022.h"
+
+#define DVBSKY_MSG_DELAY       0/*2000*/
+#define DVBSKY_BUF_LEN 64
+
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
+struct dvbsky_state {
+       struct mutex stream_mutex;
+       u8 ibuf[DVBSKY_BUF_LEN];
+       u8 obuf[DVBSKY_BUF_LEN];
+       u8 last_lock;
+       struct i2c_client *i2c_client_tuner;
+
+       /* fe hook functions*/
+       int (*fe_set_voltage)(struct dvb_frontend *fe,
+               fe_sec_voltage_t voltage);
+       int (*fe_read_status)(struct dvb_frontend *fe,
+               fe_status_t *status);
+};
+
+static int dvbsky_usb_generic_rw(struct dvb_usb_device *d,
+               u8 *wbuf, u16 wlen, u8 *rbuf, u16 rlen)
+{
+       int ret;
+       struct dvbsky_state *state = d_to_priv(d);
+
+       mutex_lock(&d->usb_mutex);
+       if (wlen != 0)
+               memcpy(state->obuf, wbuf, wlen);
+
+       ret = dvb_usbv2_generic_rw_locked(d, state->obuf, wlen,
+                       state->ibuf, rlen);
+
+       if (!ret && (rlen != 0))
+               memcpy(rbuf, state->ibuf, rlen);
+
+       mutex_unlock(&d->usb_mutex);
+       return ret;
+}
+
+static int dvbsky_stream_ctrl(struct dvb_usb_device *d, u8 onoff)
+{
+       struct dvbsky_state *state = d_to_priv(d);
+       int ret;
+       u8 obuf_pre[3] = { 0x37, 0, 0 };
+       u8 obuf_post[3] = { 0x36, 3, 0 };
+
+       mutex_lock(&state->stream_mutex);
+       ret = dvbsky_usb_generic_rw(d, obuf_pre, 3, NULL, 0);
+       if (!ret && onoff) {
+               msleep(20);
+               ret = dvbsky_usb_generic_rw(d, obuf_post, 3, NULL, 0);
+       }
+       mutex_unlock(&state->stream_mutex);
+       return ret;
+}
+
+static int dvbsky_streaming_ctrl(struct dvb_frontend *fe, int onoff)
+{
+       struct dvb_usb_device *d = fe_to_d(fe);
+
+       return dvbsky_stream_ctrl(d, (onoff == 0) ? 0 : 1);
+}
+
+/* GPIO */
+static int dvbsky_gpio_ctrl(struct dvb_usb_device *d, u8 gport, u8 value)
+{
+       int ret;
+       u8 obuf[3], ibuf[2];
+
+       obuf[0] = 0x0e;
+       obuf[1] = gport;
+       obuf[2] = value;
+       ret = dvbsky_usb_generic_rw(d, obuf, 3, ibuf, 1);
+       if (ret)
+               dev_err(&d->udev->dev, "%s: %s() failed=%d\n",
+                       KBUILD_MODNAME, __func__, ret);
+       return ret;
+}
+
+/* I2C */
+static int dvbsky_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
+       int num)
+{
+       struct dvb_usb_device *d = i2c_get_adapdata(adap);
+       int ret = 0;
+       u8 ibuf[64], obuf[64];
+
+       if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
+               return -EAGAIN;
+
+       if (num > 2) {
+               dev_err(&d->udev->dev,
+               "dvbsky_usb: too many i2c messages[%d] than 2.", num);
+               ret = -EOPNOTSUPP;
+               goto i2c_error;
+       }
+
+       if (num == 1) {
+               if (msg[0].len > 60) {
+                       dev_err(&d->udev->dev,
+                       "dvbsky_usb: too many i2c bytes[%d] than 60.",
+                       msg[0].len);
+                       ret = -EOPNOTSUPP;
+                       goto i2c_error;
+               }
+               if (msg[0].flags & I2C_M_RD) {
+                       /* single read */
+                       obuf[0] = 0x09;
+                       obuf[1] = 0;
+                       obuf[2] = msg[0].len;
+                       obuf[3] = msg[0].addr;
+                       ret = dvbsky_usb_generic_rw(d, obuf, 4,
+                                       ibuf, msg[0].len + 1);
+                       if (ret)
+                               dev_err(&d->udev->dev, "%s: %s() failed=%d\n",
+                                       KBUILD_MODNAME, __func__, ret);
+                       if (!ret)
+                               memcpy(msg[0].buf, &ibuf[1], msg[0].len);
+               } else {
+                       /* write */
+                       obuf[0] = 0x08;
+                       obuf[1] = msg[0].addr;
+                       obuf[2] = msg[0].len;
+                       memcpy(&obuf[3], msg[0].buf, msg[0].len);
+                       ret = dvbsky_usb_generic_rw(d, obuf,
+                                       msg[0].len + 3, ibuf, 1);
+                       if (ret)
+                               dev_err(&d->udev->dev, "%s: %s() failed=%d\n",
+                                       KBUILD_MODNAME, __func__, ret);
+               }
+       } else {
+               if ((msg[0].len > 60) || (msg[1].len > 60)) {
+                       dev_err(&d->udev->dev,
+                       "dvbsky_usb: too many i2c bytes[w-%d][r-%d] than 60.",
+                       msg[0].len, msg[1].len);
+                       ret = -EOPNOTSUPP;
+                       goto i2c_error;
+               }
+               /* write then read */
+               obuf[0] = 0x09;
+               obuf[1] = msg[0].len;
+               obuf[2] = msg[1].len;
+               obuf[3] = msg[0].addr;
+               memcpy(&obuf[4], msg[0].buf, msg[0].len);
+               ret = dvbsky_usb_generic_rw(d, obuf,
+                       msg[0].len + 4, ibuf, msg[1].len + 1);
+               if (ret)
+                       dev_err(&d->udev->dev, "%s: %s() failed=%d\n",
+                               KBUILD_MODNAME, __func__, ret);
+
+               if (!ret)
+                       memcpy(msg[1].buf, &ibuf[1], msg[1].len);
+       }
+i2c_error:
+       mutex_unlock(&d->i2c_mutex);
+       return (ret) ? ret : num;
+}
+
+static u32 dvbsky_i2c_func(struct i2c_adapter *adapter)
+{
+       return I2C_FUNC_I2C;
+}
+
+static struct i2c_algorithm dvbsky_i2c_algo = {
+       .master_xfer   = dvbsky_i2c_xfer,
+       .functionality = dvbsky_i2c_func,
+};
+
+#if IS_ENABLED(CONFIG_RC_CORE)
+static int dvbsky_rc_query(struct dvb_usb_device *d)
+{
+       u32 code = 0xffff, scancode;
+       u8 rc5_command, rc5_system;
+       u8 obuf[2], ibuf[2], toggle;
+       int ret;
+
+       obuf[0] = 0x10;
+       ret = dvbsky_usb_generic_rw(d, obuf, 1, ibuf, 2);
+       if (ret)
+               dev_err(&d->udev->dev, "%s: %s() failed=%d\n",
+                       KBUILD_MODNAME, __func__, ret);
+       if (ret == 0)
+               code = (ibuf[0] << 8) | ibuf[1];
+       if (code != 0xffff) {
+               dev_dbg(&d->udev->dev, "rc code: %x\n", code);
+               rc5_command = code & 0x3F;
+               rc5_system = (code & 0x7C0) >> 6;
+               toggle = (code & 0x800) ? 1 : 0;
+               scancode = rc5_system << 8 | rc5_command;
+               rc_keydown(d->rc_dev, RC_TYPE_RC5, scancode, toggle);
+       }
+       return 0;
+}
+
+static int dvbsky_get_rc_config(struct dvb_usb_device *d, struct dvb_usb_rc *rc)
+{
+       rc->allowed_protos = RC_BIT_RC5;
+       rc->query          = dvbsky_rc_query;
+       rc->interval       = 300;
+       return 0;
+}
+#else
+       #define dvbsky_get_rc_config NULL
+#endif
+
+static int dvbsky_usb_set_voltage(struct dvb_frontend *fe,
+       fe_sec_voltage_t voltage)
+{
+       struct dvb_usb_device *d = fe_to_d(fe);
+       struct dvbsky_state *state = d_to_priv(d);
+       u8 value;
+
+       if (voltage == SEC_VOLTAGE_OFF)
+               value = 0;
+       else
+               value = 1;
+       dvbsky_gpio_ctrl(d, 0x80, value);
+
+       return state->fe_set_voltage(fe, voltage);
+}
+
+static int dvbsky_read_mac_addr(struct dvb_usb_adapter *adap, u8 mac[6])
+{
+       struct dvb_usb_device *d = adap_to_d(adap);
+       u8 obuf[] = { 0x1e, 0x00 };
+       u8 ibuf[6] = { 0 };
+       struct i2c_msg msg[] = {
+               {
+                       .addr = 0x51,
+                       .flags = 0,
+                       .buf = obuf,
+                       .len = 2,
+               }, {
+                       .addr = 0x51,
+                       .flags = I2C_M_RD,
+                       .buf = ibuf,
+                       .len = 6,
+               }
+       };
+
+       if (i2c_transfer(&d->i2c_adap, msg, 2) == 2)
+               memcpy(mac, ibuf, 6);
+
+       dev_info(&d->udev->dev, "dvbsky_usb MAC address=%pM\n", mac);
+
+       return 0;
+}
+
+static int dvbsky_usb_read_status(struct dvb_frontend *fe, fe_status_t *status)
+{
+       struct dvb_usb_device *d = fe_to_d(fe);
+       struct dvbsky_state *state = d_to_priv(d);
+       int ret;
+
+       ret = state->fe_read_status(fe, status);
+
+       /* it need resync slave fifo when signal change from unlock to lock.*/
+       if ((*status & FE_HAS_LOCK) && (!state->last_lock))
+               dvbsky_stream_ctrl(d, 1);
+
+       state->last_lock = (*status & FE_HAS_LOCK) ? 1 : 0;
+       return ret;
+}
+
+static const struct m88ds3103_config dvbsky_s960_m88ds3103_config = {
+       .i2c_addr = 0x68,
+       .clock = 27000000,
+       .i2c_wr_max = 33,
+       .clock_out = 0,
+       .ts_mode = M88DS3103_TS_CI,
+       .ts_clk = 16000,
+       .ts_clk_pol = 0,
+       .agc = 0x99,
+       .lnb_hv_pol = 1,
+       .lnb_en_pol = 1,
+};
+
+static int dvbsky_s960_attach(struct dvb_usb_adapter *adap)
+{
+       struct dvbsky_state *state = adap_to_priv(adap);
+       struct dvb_usb_device *d = adap_to_d(adap);
+       int ret = 0;
+       /* demod I2C adapter */
+       struct i2c_adapter *i2c_adapter;
+       struct i2c_client *client;
+       struct i2c_board_info info;
+       struct m88ts2022_config m88ts2022_config = {
+                       .clock = 27000000,
+               };
+       memset(&info, 0, sizeof(struct i2c_board_info));
+
+       /* attach demod */
+       adap->fe[0] = dvb_attach(m88ds3103_attach,
+                       &dvbsky_s960_m88ds3103_config,
+                       &d->i2c_adap,
+                       &i2c_adapter);
+       if (!adap->fe[0]) {
+               dev_err(&d->udev->dev, "dvbsky_s960_attach fail.\n");
+               ret = -ENODEV;
+               goto fail_attach;
+       }
+
+       /* attach tuner */
+       m88ts2022_config.fe = adap->fe[0];
+       strlcpy(info.type, "m88ts2022", I2C_NAME_SIZE);
+       info.addr = 0x60;
+       info.platform_data = &m88ts2022_config;
+       request_module("m88ts2022");
+       client = i2c_new_device(i2c_adapter, &info);
+       if (client == NULL || client->dev.driver == NULL) {
+               dvb_frontend_detach(adap->fe[0]);
+               ret = -ENODEV;
+               goto fail_attach;
+       }
+
+       if (!try_module_get(client->dev.driver->owner)) {
+               i2c_unregister_device(client);
+               dvb_frontend_detach(adap->fe[0]);
+               ret = -ENODEV;
+               goto fail_attach;
+       }
+
+       /* delegate signal strength measurement to tuner */
+       adap->fe[0]->ops.read_signal_strength =
+                       adap->fe[0]->ops.tuner_ops.get_rf_strength;
+
+       /* hook fe: need to resync the slave fifo when signal locks. */
+       state->fe_read_status = adap->fe[0]->ops.read_status;
+       adap->fe[0]->ops.read_status = dvbsky_usb_read_status;
+
+       /* hook fe: LNB off/on is control by Cypress usb chip. */
+       state->fe_set_voltage = adap->fe[0]->ops.set_voltage;
+       adap->fe[0]->ops.set_voltage = dvbsky_usb_set_voltage;
+
+       state->i2c_client_tuner = client;
+
+fail_attach:
+       return ret;
+}
+
+static int dvbsky_identify_state(struct dvb_usb_device *d, const char **name)
+{
+       dvbsky_gpio_ctrl(d, 0x04, 1);
+       msleep(20);
+       dvbsky_gpio_ctrl(d, 0x83, 0);
+       dvbsky_gpio_ctrl(d, 0xc0, 1);
+       msleep(100);
+       dvbsky_gpio_ctrl(d, 0x83, 1);
+       dvbsky_gpio_ctrl(d, 0xc0, 0);
+       msleep(50);
+
+       return WARM;
+}
+
+static int dvbsky_init(struct dvb_usb_device *d)
+{
+       struct dvbsky_state *state = d_to_priv(d);
+
+       /* use default interface */
+       /*
+       ret = usb_set_interface(d->udev, 0, 0);
+       if (ret)
+               return ret;
+       */
+       mutex_init(&state->stream_mutex);
+
+       state->last_lock = 0;
+
+       return 0;
+}
+
+static void dvbsky_exit(struct dvb_usb_device *d)
+{
+       struct dvbsky_state *state = d_to_priv(d);
+       struct i2c_client *client;
+
+       client = state->i2c_client_tuner;
+       /* remove I2C tuner */
+       if (client) {
+               module_put(client->dev.driver->owner);
+               i2c_unregister_device(client);
+       }
+}
+
+/* DVB USB Driver stuff */
+static struct dvb_usb_device_properties dvbsky_s960_props = {
+       .driver_name = KBUILD_MODNAME,
+       .owner = THIS_MODULE,
+       .adapter_nr = adapter_nr,
+       .size_of_priv = sizeof(struct dvbsky_state),
+
+       .generic_bulk_ctrl_endpoint = 0x01,
+       .generic_bulk_ctrl_endpoint_response = 0x81,
+       .generic_bulk_ctrl_delay = DVBSKY_MSG_DELAY,
+
+       .i2c_algo         = &dvbsky_i2c_algo,
+       .frontend_attach  = dvbsky_s960_attach,
+       .init             = dvbsky_init,
+       .get_rc_config    = dvbsky_get_rc_config,
+       .streaming_ctrl   = dvbsky_streaming_ctrl,
+       .identify_state   = dvbsky_identify_state,
+       .exit             = dvbsky_exit,
+       .read_mac_address = dvbsky_read_mac_addr,
+
+       .num_adapters = 1,
+       .adapter = {
+               {
+                       .stream = DVB_USB_STREAM_BULK(0x82, 8, 4096),
+               }
+       }
+};
+
+static const struct usb_device_id dvbsky_id_table[] = {
+       { DVB_USB_DEVICE(0x0572, 0x6831,
+               &dvbsky_s960_props, "DVBSky S960/S860", RC_MAP_DVBSKY) },
+       { }
+};
+MODULE_DEVICE_TABLE(usb, dvbsky_id_table);
+
+static struct usb_driver dvbsky_usb_driver = {
+       .name = KBUILD_MODNAME,
+       .id_table = dvbsky_id_table,
+       .probe = dvb_usbv2_probe,
+       .disconnect = dvb_usbv2_disconnect,
+       .suspend = dvb_usbv2_suspend,
+       .resume = dvb_usbv2_resume,
+       .reset_resume = dvb_usbv2_reset_resume,
+       .no_dynamic_id = 1,
+       .soft_unbind = 1,
+};
+
+module_usb_driver(dvbsky_usb_driver);
+
+MODULE_AUTHOR("Max nibble <nibble.max@gmail.com>");
+MODULE_DESCRIPTION("Driver for DVBSky USB");
+MODULE_LICENSE("GPL");
index e332af7311872c162333a386021cd89be3e2b1ca..9f2c5459b73a672485e118e4e17df4f671c6b776 100644 (file)
@@ -1252,7 +1252,7 @@ static int lme2510_get_stream_config(struct dvb_frontend *fe, u8 *ts_type,
 
        /* Turn PID filter on the fly by module option */
        if (pid_filter == 2) {
-               adap->pid_filtering  = 1;
+               adap->pid_filtering  = true;
                adap->max_feed_count = 15;
        }
 
index b8a707e57b994c6d7863941402d91350b990ea0e..c3447eaf11047339eafc14edc8ce2d573b7d96be 100644 (file)
@@ -31,11 +31,11 @@ module_param_named(debug, dvb_usb_mxl111sf_debug, int, 0644);
 MODULE_PARM_DESC(debug, "set debugging level "
                 "(1=info, 2=xfer, 4=i2c, 8=reg, 16=adv (or-able)).");
 
-int dvb_usb_mxl111sf_isoc;
+static int dvb_usb_mxl111sf_isoc;
 module_param_named(isoc, dvb_usb_mxl111sf_isoc, int, 0644);
 MODULE_PARM_DESC(isoc, "enable usb isoc xfer (0=bulk, 1=isoc).");
 
-int dvb_usb_mxl111sf_spi;
+static int dvb_usb_mxl111sf_spi;
 module_param_named(spi, dvb_usb_mxl111sf_spi, int, 0644);
 MODULE_PARM_DESC(spi, "use spi rather than tp for data xfer (0=tp, 1=spi).");
 
@@ -43,7 +43,7 @@ MODULE_PARM_DESC(spi, "use spi rather than tp for data xfer (0=tp, 1=spi).");
 #define ANT_PATH_EXTERNAL 1
 #define ANT_PATH_INTERNAL 2
 
-int dvb_usb_mxl111sf_rfswitch =
+static int dvb_usb_mxl111sf_rfswitch =
 #if 0
                ANT_PATH_AUTO;
 #else
@@ -887,7 +887,7 @@ static u32 mxl111sf_i2c_func(struct i2c_adapter *adapter)
        return I2C_FUNC_I2C;
 }
 
-struct i2c_algorithm mxl111sf_i2c_algo = {
+static struct i2c_algorithm mxl111sf_i2c_algo = {
        .master_xfer   = mxl111sf_i2c_xfer,
        .functionality = mxl111sf_i2c_func,
 #ifdef NEED_ALGO_CONTROL
index 10aef2188fbe764deb206320d1db71beb386f2aa..41d3eb922a006d5f4649adb34b64707eaac02759 100644 (file)
@@ -130,7 +130,7 @@ config DVB_USB_CXUSB
 
          Medion MD95700 hybrid USB2.0 device.
          DViCO FusionHDTV (Bluebird) USB2.0 devices
-         TechnoTrend TVStick CT2-4400
+         TechnoTrend TVStick CT2-4400 and CT2-4650 CI devices
 
 config DVB_USB_M920X
        tristate "Uli m920x DVB-T USB2.0 support"
index af176b6ce738e78d4dc366ae0d56597f833f4e59..3f4361e48a32ef98dd3faf6970a32127df549d4e 100644 (file)
@@ -30,7 +30,7 @@ MODULE_PARM_DESC(debug,
                 "set debugging level (1=info,xfer=2,rc=4,reg=8,i2c=16,fw=32 (or-able))."
                 DVB_USB_DEBUG_STATUS);
 /* enable obnoxious led */
-bool dvb_usb_af9005_led = 1;
+bool dvb_usb_af9005_led = true;
 module_param_named(led, dvb_usb_af9005_led, bool, 0644);
 MODULE_PARM_DESC(led, "enable led (default: 1).");
 
index 16bc579d1404e836e7bb287a1744c1e52fec48d7..356abb369c20b6cd07649fd1f75252f939d0a6e0 100644 (file)
@@ -44,6 +44,7 @@
 #include "atbm8830.h"
 #include "si2168.h"
 #include "si2157.h"
+#include "sp2.h"
 
 /* Max transfer size done by I2C transfer functions */
 #define MAX_XFER_SIZE  80
@@ -175,7 +176,7 @@ static int cxusb_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
 
        for (i = 0; i < num; i++) {
 
-               if (d->udev->descriptor.idVendor == USB_VID_MEDION)
+               if (le16_to_cpu(d->udev->descriptor.idVendor) == USB_VID_MEDION)
                        switch (msg[i].addr) {
                        case 0x63:
                                cxusb_gpio_tuner(d, 0);
@@ -672,6 +673,70 @@ static struct rc_map_table rc_map_d680_dmb_table[] = {
        { 0x0025, KEY_POWER },
 };
 
+static int cxusb_tt_ct2_4400_read_mac_address(struct dvb_usb_device *d, u8 mac[6])
+{
+       u8 wbuf[2];
+       u8 rbuf[6];
+       int ret;
+       struct i2c_msg msg[] = {
+               {
+                       .addr = 0x51,
+                       .flags = 0,
+                       .buf = wbuf,
+                       .len = 2,
+               }, {
+                       .addr = 0x51,
+                       .flags = I2C_M_RD,
+                       .buf = rbuf,
+                       .len = 6,
+               }
+       };
+
+       wbuf[0] = 0x1e;
+       wbuf[1] = 0x00;
+       ret = cxusb_i2c_xfer(&d->i2c_adap, msg, 2);
+
+       if (ret == 2) {
+               memcpy(mac, rbuf, 6);
+               return 0;
+       } else {
+               if (ret < 0)
+                       return ret;
+               return -EIO;
+       }
+}
+
+static int cxusb_tt_ct2_4650_ci_ctrl(void *priv, u8 read, int addr,
+                                       u8 data, int *mem)
+{
+       struct dvb_usb_device *d = priv;
+       u8 wbuf[3];
+       u8 rbuf[2];
+       int ret;
+
+       wbuf[0] = (addr >> 8) & 0xff;
+       wbuf[1] = addr & 0xff;
+
+       if (read) {
+               ret = cxusb_ctrl_msg(d, CMD_SP2_CI_READ, wbuf, 2, rbuf, 2);
+       } else {
+               wbuf[2] = data;
+               ret = cxusb_ctrl_msg(d, CMD_SP2_CI_WRITE, wbuf, 3, rbuf, 1);
+       }
+
+       if (ret)
+               goto err;
+
+       if (read)
+               *mem = rbuf[1];
+
+       return 0;
+err:
+       deb_info("%s: ci usb write returned %d\n", __func__, ret);
+       return ret;
+
+}
+
 static int cxusb_dee1601_demod_init(struct dvb_frontend* fe)
 {
        static u8 clock_config []  = { CLOCK_CTL,  0x38, 0x28 };
@@ -1350,9 +1415,12 @@ static int cxusb_tt_ct2_4400_attach(struct dvb_usb_adapter *adap)
        struct i2c_adapter *adapter;
        struct i2c_client *client_demod;
        struct i2c_client *client_tuner;
+       struct i2c_client *client_ci;
        struct i2c_board_info info;
        struct si2168_config si2168_config;
        struct si2157_config si2157_config;
+       struct sp2_config sp2_config;
+       u8 o[2], i;
 
        /* reset the tuner */
        if (cxusb_tt_ct2_4400_gpio_tuner(d, 0) < 0) {
@@ -1369,6 +1437,7 @@ static int cxusb_tt_ct2_4400_attach(struct dvb_usb_adapter *adap)
        /* attach frontend */
        si2168_config.i2c_adapter = &adapter;
        si2168_config.fe = &adap->fe_adap[0].fe;
+       si2168_config.ts_mode = SI2168_TS_PARALLEL;
        memset(&info, 0, sizeof(struct i2c_board_info));
        strlcpy(info.type, "si2168", I2C_NAME_SIZE);
        info.addr = 0x64;
@@ -1408,6 +1477,48 @@ static int cxusb_tt_ct2_4400_attach(struct dvb_usb_adapter *adap)
 
        st->i2c_client_tuner = client_tuner;
 
+       /* initialize CI */
+       if (d->udev->descriptor.idProduct ==
+               USB_PID_TECHNOTREND_CONNECT_CT2_4650_CI) {
+
+               memcpy(o, "\xc0\x01", 2);
+               cxusb_ctrl_msg(d, CMD_GPIO_WRITE, o, 2, &i, 1);
+               msleep(100);
+
+               memcpy(o, "\xc0\x00", 2);
+               cxusb_ctrl_msg(d, CMD_GPIO_WRITE, o, 2, &i, 1);
+               msleep(100);
+
+               memset(&sp2_config, 0, sizeof(sp2_config));
+               sp2_config.dvb_adap = &adap->dvb_adap;
+               sp2_config.priv = d;
+               sp2_config.ci_control = cxusb_tt_ct2_4650_ci_ctrl;
+               memset(&info, 0, sizeof(struct i2c_board_info));
+               strlcpy(info.type, "sp2", I2C_NAME_SIZE);
+               info.addr = 0x40;
+               info.platform_data = &sp2_config;
+               request_module(info.type);
+               client_ci = i2c_new_device(&d->i2c_adap, &info);
+               if (client_ci == NULL || client_ci->dev.driver == NULL) {
+                       module_put(client_tuner->dev.driver->owner);
+                       i2c_unregister_device(client_tuner);
+                       module_put(client_demod->dev.driver->owner);
+                       i2c_unregister_device(client_demod);
+                       return -ENODEV;
+               }
+               if (!try_module_get(client_ci->dev.driver->owner)) {
+                       i2c_unregister_device(client_ci);
+                       module_put(client_tuner->dev.driver->owner);
+                       i2c_unregister_device(client_tuner);
+                       module_put(client_demod->dev.driver->owner);
+                       i2c_unregister_device(client_demod);
+                       return -ENODEV;
+               }
+
+               st->i2c_client_ci = client_ci;
+
+       }
+
        return 0;
 }
 
@@ -1537,6 +1648,13 @@ static void cxusb_disconnect(struct usb_interface *intf)
        struct cxusb_state *st = d->priv;
        struct i2c_client *client;
 
+       /* remove I2C client for CI */
+       client = st->i2c_client_ci;
+       if (client) {
+               module_put(client->dev.driver->owner);
+               i2c_unregister_device(client);
+       }
+
        /* remove I2C client for tuner */
        client = st->i2c_client_tuner;
        if (client) {
@@ -1576,6 +1694,7 @@ static struct usb_device_id cxusb_table [] = {
        { USB_DEVICE(USB_VID_CONEXANT, USB_PID_CONEXANT_D680_DMB) },
        { USB_DEVICE(USB_VID_CONEXANT, USB_PID_MYGICA_D689) },
        { USB_DEVICE(USB_VID_TECHNOTREND, USB_PID_TECHNOTREND_TVSTICK_CT2_4400) },
+       { USB_DEVICE(USB_VID_TECHNOTREND, USB_PID_TECHNOTREND_CONNECT_CT2_4650_CI) },
        {}              /* Terminating entry */
 };
 MODULE_DEVICE_TABLE (usb, cxusb_table);
@@ -2230,6 +2349,8 @@ static struct dvb_usb_device_properties cxusb_tt_ct2_4400_properties = {
        .size_of_priv     = sizeof(struct cxusb_state),
 
        .num_adapters = 1,
+       .read_mac_address = cxusb_tt_ct2_4400_read_mac_address,
+
        .adapter = {
                {
                .num_frontends = 1,
@@ -2265,13 +2386,18 @@ static struct dvb_usb_device_properties cxusb_tt_ct2_4400_properties = {
                .rc_interval    = 150,
        },
 
-       .num_device_descs = 1,
+       .num_device_descs = 2,
        .devices = {
                {
                        "TechnoTrend TVStick CT2-4400",
                        { NULL },
                        { &cxusb_table[20], NULL },
                },
+               {
+                       "TechnoTrend TT-connect CT2-4650 CI",
+                       { NULL },
+                       { &cxusb_table[21], NULL },
+               },
        }
 };
 
index 527ff7905e1590961b64b8edd3b62b859a9f903a..29f3e2ea2476a21394dcc60e7ba2cc70b9d2cdad 100644 (file)
 #define CMD_ANALOG        0x50
 #define CMD_DIGITAL       0x51
 
+#define CMD_SP2_CI_WRITE  0x70
+#define CMD_SP2_CI_READ   0x71
+
 struct cxusb_state {
        u8 gpio_write_state[3];
        struct i2c_client *i2c_client_demod;
        struct i2c_client *i2c_client_tuner;
+       struct i2c_client *i2c_client_ci;
 };
 
 #endif
index ce47d3f1c8502a1774a3eee1b518d0cd5821247d..e1757b8f5f5d0e7775abbc91c40bba817fec9d3d 100644 (file)
@@ -220,12 +220,21 @@ static struct dibx000_agc_config stk7700d_7000p_mt2266_agc_config[2] = {
 };
 
 static struct dibx000_bandwidth_config stk7700d_mt2266_pll_config = {
-       60000, 30000,
-       1, 8, 3, 1, 0,
-       0, 0, 1, 1, 2,
-       (3 << 14) | (1 << 12) | (524 << 0),
-       0,
-       20452225,
+       .internal = 60000,
+       .sampling = 30000,
+       .pll_prediv = 1,
+       .pll_ratio = 8,
+       .pll_range = 3,
+       .pll_reset = 1,
+       .pll_bypass = 0,
+       .enable_refdiv = 0,
+       .bypclk_div = 0,
+       .IO_CLK_en_core = 1,
+       .ADClkSrc = 1,
+       .modulo = 2,
+       .sad_cfg = (3 << 14) | (1 << 12) | (524 << 0),
+       .ifreq = 0,
+       .timf = 20452225,
 };
 
 static struct dib7000p_config stk7700d_dib7000p_mt2266_config[] = {
@@ -342,57 +351,57 @@ static int stk7700d_tuner_attach(struct dvb_usb_adapter *adap)
 
 /* STK7700-PH: Digital/Analog Hybrid Tuner, e.h. Cinergy HT USB HE */
 static struct dibx000_agc_config xc3028_agc_config = {
-       BAND_VHF | BAND_UHF,       /* band_caps */
-
+       .band_caps = BAND_VHF | BAND_UHF,
        /* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, P_agc_freq_pwm_div=0,
         * P_agc_inv_pwm1=0, P_agc_inv_pwm2=0, P_agc_inh_dc_rv_est=0,
         * P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=2, P_agc_write=0 */
-       (0 << 15) | (0 << 14) | (0 << 11) | (0 << 10) | (0 << 9) | (0 << 8) |
-       (3 << 5) | (0 << 4) | (2 << 1) | (0 << 0), /* setup */
-
-       712,    /* inv_gain */
-       21,     /* time_stabiliz */
-
-       0,      /* alpha_level */
-       118,    /* thlock */
-
-       0,      /* wbd_inv */
-       2867,   /* wbd_ref */
-       0,      /* wbd_sel */
-       2,      /* wbd_alpha */
-
-       0,      /* agc1_max */
-       0,      /* agc1_min */
-       39718,  /* agc2_max */
-       9930,   /* agc2_min */
-       0,      /* agc1_pt1 */
-       0,      /* agc1_pt2 */
-       0,      /* agc1_pt3 */
-       0,      /* agc1_slope1 */
-       0,      /* agc1_slope2 */
-       0,      /* agc2_pt1 */
-       128,    /* agc2_pt2 */
-       29,     /* agc2_slope1 */
-       29,     /* agc2_slope2 */
-
-       17,     /* alpha_mant */
-       27,     /* alpha_exp */
-       23,     /* beta_mant */
-       51,     /* beta_exp */
-
-       1,      /* perform_agc_softsplit */
+       .setup = (0 << 15) | (0 << 14) | (0 << 11) | (0 << 10) | (0 << 9) | (0 << 8) | (3 << 5) | (0 << 4) | (2 << 1) | (0 << 0),
+       .inv_gain = 712,
+       .time_stabiliz = 21,
+       .alpha_level = 0,
+       .thlock = 118,
+       .wbd_inv = 0,
+       .wbd_ref = 2867,
+       .wbd_sel = 0,
+       .wbd_alpha = 2,
+       .agc1_max = 0,
+       .agc1_min = 0,
+       .agc2_max = 39718,
+       .agc2_min = 9930,
+       .agc1_pt1 = 0,
+       .agc1_pt2 = 0,
+       .agc1_pt3 = 0,
+       .agc1_slope1 = 0,
+       .agc1_slope2 = 0,
+       .agc2_pt1 = 0,
+       .agc2_pt2 = 128,
+       .agc2_slope1 = 29,
+       .agc2_slope2 = 29,
+       .alpha_mant = 17,
+       .alpha_exp = 27,
+       .beta_mant = 23,
+       .beta_exp = 51,
+       .perform_agc_softsplit = 1,
 };
 
 /* PLL Configuration for COFDM BW_MHz = 8.00 with external clock = 30.00 */
 static struct dibx000_bandwidth_config xc3028_bw_config = {
-       60000, 30000, /* internal, sampling */
-       1, 8, 3, 1, 0, /* pll_cfg: prediv, ratio, range, reset, bypass */
-       0, 0, 1, 1, 0, /* misc: refdiv, bypclk_div, IO_CLK_en_core, ADClkSrc,
-                         modulo */
-       (3 << 14) | (1 << 12) | (524 << 0), /* sad_cfg: refsel, sel, freq_15k */
-       (1 << 25) | 5816102, /* ifreq = 5.200000 MHz */
-       20452225, /* timf */
-       30000000, /* xtal_hz */
+       .internal = 60000,
+       .sampling = 30000,
+       .pll_prediv = 1,
+       .pll_ratio = 8,
+       .pll_range = 3,
+       .pll_reset = 1,
+       .pll_bypass = 0,
+       .enable_refdiv = 0,
+       .bypclk_div = 0,
+       .IO_CLK_en_core = 1,
+       .ADClkSrc = 1,
+       .modulo = 0,
+       .sad_cfg = (3 << 14) | (1 << 12) | (524 << 0), /* sad_cfg: refsel, sel, freq_15k */
+       .ifreq = (1 << 25) | 5816102,  /* ifreq = 5.200000 MHz */
+       .timf = 20452225,
+       .xtal_hz = 30000000,
 };
 
 static struct dib7000p_config stk7700ph_dib7700_xc3028_config = {
@@ -614,59 +623,55 @@ static struct dibx000_agc_config stk7700p_7000m_mt2060_agc_config = {
 };
 
 static struct dibx000_agc_config stk7700p_7000p_mt2060_agc_config = {
-       BAND_UHF | BAND_VHF,
-
+       .band_caps = BAND_UHF | BAND_VHF,
        /* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, P_agc_freq_pwm_div=5, P_agc_inv_pwm1=0, P_agc_inv_pwm2=0,
         * P_agc_inh_dc_rv_est=0, P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=2, P_agc_write=0 */
-       (0 << 15) | (0 << 14) | (5 << 11) | (0 << 10) | (0 << 9) | (0 << 8)
-       | (3 << 5) | (0 << 4) | (2 << 1) | (0 << 0),
-
-       712,
-       41,
-
-       0,
-       118,
-
-       0,
-       4095,
-       0,
-       0,
-
-       42598,
-       16384,
-       42598,
-           0,
-
-         0,
-       137,
-       255,
-
-         0,
-       255,
-
-       0,
-       0,
-
-        0,
-       41,
-
-       15,
-       25,
-
-       28,
-       48,
-
-       0,
+       .setup = (0 << 15) | (0 << 14) | (5 << 11) | (0 << 10) | (0 << 9) | (0 << 8) | (3 << 5) | (0 << 4) | (2 << 1) | (0 << 0),
+       .inv_gain = 712,
+       .time_stabiliz = 41,
+       .alpha_level = 0,
+       .thlock = 118,
+       .wbd_inv = 0,
+       .wbd_ref = 4095,
+       .wbd_sel = 0,
+       .wbd_alpha = 0,
+       .agc1_max = 42598,
+       .agc1_min = 16384,
+       .agc2_max = 42598,
+       .agc2_min = 0,
+       .agc1_pt1 = 0,
+       .agc1_pt2 = 137,
+       .agc1_pt3 = 255,
+       .agc1_slope1 = 0,
+       .agc1_slope2 = 255,
+       .agc2_pt1 = 0,
+       .agc2_pt2 = 0,
+       .agc2_slope1 = 0,
+       .agc2_slope2 = 41,
+       .alpha_mant = 15,
+       .alpha_exp = 25,
+       .beta_mant = 28,
+       .beta_exp = 48,
+       .perform_agc_softsplit = 0,
 };
 
 static struct dibx000_bandwidth_config stk7700p_pll_config = {
-       60000, 30000,
-       1, 8, 3, 1, 0,
-       0, 0, 1, 1, 0,
-       (3 << 14) | (1 << 12) | (524 << 0),
-       60258167,
-       20452225,
-       30000000,
+       .internal = 60000,
+       .sampling = 30000,
+       .pll_prediv = 1,
+       .pll_ratio = 8,
+       .pll_range = 3,
+       .pll_reset = 1,
+       .pll_bypass = 0,
+       .enable_refdiv = 0,
+       .bypclk_div = 0,
+       .IO_CLK_en_core = 1,
+       .ADClkSrc = 1,
+       .modulo = 0,
+       .sad_cfg = (3 << 14) | (1 << 12) | (524 << 0),
+       .ifreq = 60258167,
+       .timf = 20452225,
+       .xtal_hz = 30000000,
 };
 
 static struct dib7000m_config stk7700p_dib7000m_config = {
@@ -758,45 +763,36 @@ static int stk7700p_tuner_attach(struct dvb_usb_adapter *adap)
 
 /* DIB7070 generic */
 static struct dibx000_agc_config dib7070_agc_config = {
-       BAND_UHF | BAND_VHF | BAND_LBAND | BAND_SBAND,
+       .band_caps = BAND_UHF | BAND_VHF | BAND_LBAND | BAND_SBAND,
        /* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, P_agc_freq_pwm_div=5, P_agc_inv_pwm1=0, P_agc_inv_pwm2=0,
         * P_agc_inh_dc_rv_est=0, P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=5, P_agc_write=0 */
-       (0 << 15) | (0 << 14) | (5 << 11) | (0 << 10) | (0 << 9) | (0 << 8)
-       | (3 << 5) | (0 << 4) | (5 << 1) | (0 << 0),
-
-       600,
-       10,
-
-       0,
-       118,
-
-       0,
-       3530,
-       1,
-       5,
-
-       65535,
-               0,
-
-       65535,
-       0,
-
-       0,
-       40,
-       183,
-       206,
-       255,
-       72,
-       152,
-       88,
-       90,
-
-       17,
-       27,
-       23,
-       51,
-
-       0,
+       .setup = (0 << 15) | (0 << 14) | (5 << 11) | (0 << 10) | (0 << 9) | (0 << 8) | (3 << 5) | (0 << 4) | (5 << 1) | (0 << 0),
+       .inv_gain = 600,
+       .time_stabiliz = 10,
+       .alpha_level = 0,
+       .thlock = 118,
+       .wbd_inv = 0,
+       .wbd_ref = 3530,
+       .wbd_sel = 1,
+       .wbd_alpha = 5,
+       .agc1_max = 65535,
+       .agc1_min = 0,
+       .agc2_max = 65535,
+       .agc2_min = 0,
+       .agc1_pt1 = 0,
+       .agc1_pt2 = 40,
+       .agc1_pt3 = 183,
+       .agc1_slope1 = 206,
+       .agc1_slope2 = 255,
+       .agc2_pt1 = 72,
+       .agc2_pt2 = 152,
+       .agc2_slope1 = 88,
+       .agc2_slope2 = 90,
+       .alpha_mant = 17,
+       .alpha_exp = 27,
+       .beta_mant = 23,
+       .beta_exp = 51,
+       .perform_agc_softsplit = 0,
 };
 
 static int dib7070_tuner_reset(struct dvb_frontend *fe, int onoff)
@@ -952,13 +948,22 @@ static int stk70x0p_pid_filter_ctrl(struct dvb_usb_adapter *adapter, int onoff)
 }
 
 static struct dibx000_bandwidth_config dib7070_bw_config_12_mhz = {
-       60000, 15000,
-       1, 20, 3, 1, 0,
-       0, 0, 1, 1, 2,
-       (3 << 14) | (1 << 12) | (524 << 0),
-       (0 << 25) | 0,
-       20452225,
-       12000000,
+       .internal = 60000,
+       .sampling = 15000,
+       .pll_prediv = 1,
+       .pll_ratio = 20,
+       .pll_range = 3,
+       .pll_reset = 1,
+       .pll_bypass = 0,
+       .enable_refdiv = 0,
+       .bypclk_div = 0,
+       .IO_CLK_en_core = 1,
+       .ADClkSrc = 1,
+       .modulo = 2,
+       .sad_cfg = (3 << 14) | (1 << 12) | (524 << 0),
+       .ifreq = (0 << 25) | 0,
+       .timf = 20452225,
+       .xtal_hz = 12000000,
 };
 
 static struct dib7000p_config dib7070p_dib7000p_config = {
@@ -1169,14 +1174,22 @@ static struct dibx000_agc_config dib807x_agc_config[2] = {
 };
 
 static struct dibx000_bandwidth_config dib807x_bw_config_12_mhz = {
-       60000, 15000, /* internal, sampling*/
-       1, 20, 3, 1, 0, /* pll_cfg: prediv, ratio, range, reset, bypass*/
-       0, 0, 1, 1, 2, /* misc: refdiv, bypclk_div, IO_CLK_en_core,
-                         ADClkSrc, modulo */
-       (3 << 14) | (1 << 12) | (599 << 0), /* sad_cfg: refsel, sel, freq_15k*/
-       (0 << 25) | 0, /* ifreq = 0.000000 MHz*/
-       18179755, /* timf*/
-       12000000, /* xtal_hz*/
+       .internal = 60000,
+       .sampling = 15000,
+       .pll_prediv = 1,
+       .pll_ratio = 20,
+       .pll_range = 3,
+       .pll_reset = 1,
+       .pll_bypass = 0,
+       .enable_refdiv = 0,
+       .bypclk_div = 0,
+       .IO_CLK_en_core = 1,
+       .ADClkSrc = 1,
+       .modulo = 2,
+       .sad_cfg = (3 << 14) | (1 << 12) | (599 << 0),  /* sad_cfg: refsel, sel, freq_15k*/
+       .ifreq = (0 << 25) | 0,                         /* ifreq = 0.000000 MHz*/
+       .timf = 18179755,
+       .xtal_hz = 12000000,
 };
 
 static struct dib8000_config dib807x_dib8000_config[2] = {
@@ -1921,13 +1934,22 @@ static struct dibx000_agc_config dib8096p_agc_config[2] = {
 };
 
 static struct dibx000_bandwidth_config dib8096p_clock_config_12_mhz = {
-       108000, 13500,
-       1, 9, 1, 0, 0,
-       0, 0, 0, 0, 2,
-       (3 << 14) | (1 << 12) | (524 << 0),
-       (0 << 25) | 0,
-       20199729,
-       12000000,
+       .internal = 108000,
+       .sampling = 13500,
+       .pll_prediv = 1,
+       .pll_ratio = 9,
+       .pll_range = 1,
+       .pll_reset = 0,
+       .pll_bypass = 0,
+       .enable_refdiv = 0,
+       .bypclk_div = 0,
+       .IO_CLK_en_core = 0,
+       .ADClkSrc = 0,
+       .modulo = 2,
+       .sad_cfg = (3 << 14) | (1 << 12) | (524 << 0),
+       .ifreq = (0 << 25) | 0,
+       .timf = 20199729,
+       .xtal_hz = 12000000,
 };
 
 static struct dib8000_config tfe8096p_dib8000_config = {
@@ -2724,13 +2746,22 @@ static struct dibx000_agc_config dib7090_agc_config[2] = {
 };
 
 static struct dibx000_bandwidth_config dib7090_clock_config_12_mhz = {
-       60000, 15000,
-       1, 5, 0, 0, 0,
-       0, 0, 1, 1, 2,
-       (3 << 14) | (1 << 12) | (524 << 0),
-       (0 << 25) | 0,
-       20452225,
-       15000000,
+       .internal = 60000,
+       .sampling = 15000,
+       .pll_prediv = 1,
+       .pll_ratio = 5,
+       .pll_range = 0,
+       .pll_reset = 0,
+       .pll_bypass = 0,
+       .enable_refdiv = 0,
+       .bypclk_div = 0,
+       .IO_CLK_en_core = 1,
+       .ADClkSrc = 1,
+       .modulo = 2,
+       .sad_cfg = (3 << 14) | (1 << 12) | (524 << 0),
+       .ifreq = (0 << 25) | 0,
+       .timf = 20452225,
+       .xtal_hz = 15000000,
 };
 
 static struct dib7000p_config nim7090_dib7000p_config = {
@@ -3498,14 +3529,22 @@ static struct dibx000_agc_config stk7700p_7000p_xc4000_agc_config = {
 };
 
 static struct dibx000_bandwidth_config stk7700p_xc4000_pll_config = {
-       60000, 30000,   /* internal, sampling */
-       1, 8, 3, 1, 0,  /* pll_cfg: prediv, ratio, range, reset, bypass */
-       0, 0, 1, 1, 0,  /* misc: refdiv, bypclk_div, IO_CLK_en_core, */
-                       /* ADClkSrc, modulo */
-       (3 << 14) | (1 << 12) | 524,    /* sad_cfg: refsel, sel, freq_15k */
-       39370534,       /* ifreq */
-       20452225,       /* timf */
-       30000000        /* xtal */
+       .internal = 60000,
+       .sampling = 30000,
+       .pll_prediv = 1,
+       .pll_ratio = 8,
+       .pll_range = 3,
+       .pll_reset = 1,
+       .pll_bypass = 0,
+       .enable_refdiv = 0,
+       .bypclk_div = 0,
+       .IO_CLK_en_core = 1,
+       .ADClkSrc = 1,
+       .modulo = 0,
+       .sad_cfg = (3 << 14) | (1 << 12) | 524, /* sad_cfg: refsel, sel, freq_15k */
+       .ifreq = 39370534,
+       .timf = 20452225,
+       .xtal_hz = 30000000
 };
 
 /* FIXME: none of these inputs are validated yet */
index 6d68af0c49c83ecab8d542eb0a3942902e70e7e8..ef3a8f75f82ebe21b4ee5b7963aed9bbf8449c32 100644 (file)
@@ -258,8 +258,8 @@ static struct dib3000mc_config mod3000p_dib3000p_config = {
 
 int dibusb_dib3000mc_frontend_attach(struct dvb_usb_adapter *adap)
 {
-       if (adap->dev->udev->descriptor.idVendor  == USB_VID_LITEON &&
-                       adap->dev->udev->descriptor.idProduct ==
+       if (le16_to_cpu(adap->dev->udev->descriptor.idVendor) == USB_VID_LITEON &&
+           le16_to_cpu(adap->dev->udev->descriptor.idProduct) ==
                        USB_PID_LITEON_DVB_T_WARM) {
                msleep(1000);
        }
@@ -297,8 +297,8 @@ int dibusb_dib3000mc_tuner_attach(struct dvb_usb_adapter *adap)
        struct i2c_adapter *tun_i2c;
 
        // First IF calibration for Liteon Sticks
-       if (adap->dev->udev->descriptor.idVendor  == USB_VID_LITEON &&
-               adap->dev->udev->descriptor.idProduct == USB_PID_LITEON_DVB_T_WARM) {
+       if (le16_to_cpu(adap->dev->udev->descriptor.idVendor) == USB_VID_LITEON &&
+           le16_to_cpu(adap->dev->udev->descriptor.idProduct) == USB_PID_LITEON_DVB_T_WARM) {
 
                dibusb_read_eeprom_byte(adap->dev,0x7E,&a);
                dibusb_read_eeprom_byte(adap->dev,0x7F,&b);
@@ -310,8 +310,8 @@ int dibusb_dib3000mc_tuner_attach(struct dvb_usb_adapter *adap)
                else
                        warn("LITE-ON DVB-T: Strange IF1 calibration :%2X %2X\n", a, b);
 
-       } else if (adap->dev->udev->descriptor.idVendor  == USB_VID_DIBCOM &&
-                  adap->dev->udev->descriptor.idProduct == USB_PID_DIBCOM_MOD3001_WARM) {
+       } else if (le16_to_cpu(adap->dev->udev->descriptor.idVendor) == USB_VID_DIBCOM &&
+                  le16_to_cpu(adap->dev->udev->descriptor.idProduct) == USB_PID_DIBCOM_MOD3001_WARM) {
                u8 desc;
                dibusb_read_eeprom_byte(adap->dev, 7, &desc);
                if (desc == 2) {
index 2add8c507ec9ecd6cf2d27b7097a9c7e98fe9d2d..1a3df10d6bad5e1c1354874c8d715a7f6e5629c0 100644 (file)
@@ -667,7 +667,7 @@ static int s6x0_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[],
                                obuf[1] = (msg[j].addr << 1);
                                memcpy(obuf + 2, msg[j].buf, msg[j].len);
                                dw210x_op_rw(d->udev,
-                                               udev->descriptor.idProduct ==
+                                               le16_to_cpu(udev->descriptor.idProduct) ==
                                                0x7500 ? 0x92 : 0x90, 0, 0,
                                                obuf, msg[j].len + 2,
                                                DW210X_WRITE_MSG);
@@ -1598,7 +1598,7 @@ static int dw2102_load_firmware(struct usb_device *dev,
        u8 reset16[] = {0, 0, 0, 0, 0, 0, 0};
        const struct firmware *fw;
 
-       switch (dev->descriptor.idProduct) {
+       switch (le16_to_cpu(dev->descriptor.idProduct)) {
        case 0x2101:
                ret = request_firmware(&fw, DW2101_FIRMWARE, &dev->dev);
                if (ret != 0) {
@@ -1641,7 +1641,7 @@ static int dw2102_load_firmware(struct usb_device *dev,
                        ret = -EINVAL;
                }
                /* init registers */
-               switch (dev->descriptor.idProduct) {
+               switch (le16_to_cpu(dev->descriptor.idProduct)) {
                case USB_PID_TEVII_S650:
                        dw2104_properties.rc.core.rc_codes = RC_MAP_TEVII_NEC;
                case USB_PID_DW2104:
@@ -1901,14 +1901,14 @@ static struct dvb_usb_device_properties s6x0_properties = {
        }
 };
 
-struct dvb_usb_device_properties *p1100;
+static struct dvb_usb_device_properties *p1100;
 static struct dvb_usb_device_description d1100 = {
        "Prof 1100 USB ",
        {&dw2102_table[PROF_1100], NULL},
        {NULL},
 };
 
-struct dvb_usb_device_properties *s660;
+static struct dvb_usb_device_properties *s660;
 static struct dvb_usb_device_description d660 = {
        "TeVii S660 USB",
        {&dw2102_table[TEVII_S660], NULL},
@@ -1927,14 +1927,14 @@ static struct dvb_usb_device_description d480_2 = {
        {NULL},
 };
 
-struct dvb_usb_device_properties *p7500;
+static struct dvb_usb_device_properties *p7500;
 static struct dvb_usb_device_description d7500 = {
        "Prof 7500 USB DVB-S2",
        {&dw2102_table[PROF_7500], NULL},
        {NULL},
 };
 
-struct dvb_usb_device_properties *s421;
+static struct dvb_usb_device_properties *s421;
 static struct dvb_usb_device_description d421 = {
        "TeVii S421 PCI",
        {&dw2102_table[TEVII_S421], NULL},
index 16ba90acf5396ff54395497e9180b5f883adfc37..14a2119912ba5246474c6b249a855f5815c34331 100644 (file)
@@ -554,8 +554,8 @@ static int opera1_probe(struct usb_interface *intf,
 {
        struct usb_device *udev = interface_to_usbdev(intf);
 
-       if (udev->descriptor.idProduct == USB_PID_OPERA1_WARM &&
-               udev->descriptor.idVendor == USB_VID_OPERA1 &&
+       if (le16_to_cpu(udev->descriptor.idProduct) == USB_PID_OPERA1_WARM &&
+           le16_to_cpu(udev->descriptor.idVendor) == USB_VID_OPERA1 &&
                opera1_xilinx_load_firmware(udev, "dvb-usb-opera1-fpga-01.fw") != 0
            ) {
                return -EINVAL;
index bdfe8963591cbac6dfe69028ead20993421b118e..d17618fe8f5c80528bb8f6febc202449b5ad2999 100644 (file)
@@ -883,7 +883,7 @@ static int pctv452e_frontend_attach(struct dvb_usb_adapter *a)
        if (!a->fe_adap[0].fe)
                return -ENODEV;
        if ((dvb_attach(lnbp22_attach, a->fe_adap[0].fe,
-                                       &a->dev->i2c_adap)) == 0)
+                                       &a->dev->i2c_adap)) == NULL)
                err("Cannot attach lnbp22\n");
 
        id = a->dev->desc->warm_ids[0];
@@ -900,7 +900,7 @@ static int pctv452e_tuner_attach(struct dvb_usb_adapter *a)
        if (!a->fe_adap[0].fe)
                return -ENODEV;
        if (dvb_attach(stb6100_attach, a->fe_adap[0].fe, &stb6100_config,
-                                       &a->dev->i2c_adap) == 0) {
+                                       &a->dev->i2c_adap) == NULL) {
                err("%s failed\n", __func__);
                return -ENODEV;
        }
@@ -965,7 +965,7 @@ static struct dvb_usb_device_properties pctv452e_properties = {
                  .cold_ids = { NULL, NULL }, /* this is a warm only device */
                  .warm_ids = { &pctv452e_usb_table[0], NULL }
                },
-               { 0 },
+               { NULL },
        }
 };
 
@@ -1023,7 +1023,7 @@ static struct dvb_usb_device_properties tt_connect_s2_3600_properties = {
                  .cold_ids = { NULL, NULL },
                  .warm_ids = { &pctv452e_usb_table[2], NULL }
                },
-               { 0 },
+               { NULL },
        }
 };
 
index e881ef7b64451060f39627ece2cb79c0f49330f7..957c7ae30efe5f5d724908f9b231e8a0b780e406 100644 (file)
@@ -268,7 +268,7 @@ static int snd_em28xx_capture_open(struct snd_pcm_substream *substream)
        nonblock = !!(substream->f_flags & O_NONBLOCK);
        if (nonblock) {
                if (!mutex_trylock(&dev->lock))
-               return -EAGAIN;
+                       return -EAGAIN;
        } else
                mutex_lock(&dev->lock);
 
@@ -893,7 +893,7 @@ static int em28xx_audio_init(struct em28xx *dev)
        static int          devnr;
        int                 err;
 
-       if (!dev->has_alsa_audio) {
+       if (dev->usb_audio_type != EM28XX_USB_AUDIO_VENDOR) {
                /* This device does not support the extension (in this case
                   the device is expecting the snd-usb-audio module or
                   doesn't have analog audio support at all) */
@@ -975,7 +975,7 @@ static int em28xx_audio_fini(struct em28xx *dev)
        if (dev == NULL)
                return 0;
 
-       if (!dev->has_alsa_audio) {
+       if (dev->usb_audio_type != EM28XX_USB_AUDIO_VENDOR) {
                /* This device does not support the extension (in this case
                   the device is expecting the snd-usb-audio module or
                   doesn't have analog audio support at all) */
@@ -1003,7 +1003,7 @@ static int em28xx_audio_suspend(struct em28xx *dev)
        if (dev == NULL)
                return 0;
 
-       if (!dev->has_alsa_audio)
+       if (dev->usb_audio_type != EM28XX_USB_AUDIO_VENDOR)
                return 0;
 
        em28xx_info("Suspending audio extension");
@@ -1017,7 +1017,7 @@ static int em28xx_audio_resume(struct em28xx *dev)
        if (dev == NULL)
                return 0;
 
-       if (!dev->has_alsa_audio)
+       if (dev->usb_audio_type != EM28XX_USB_AUDIO_VENDOR)
                return 0;
 
        em28xx_info("Resuming audio extension");
index 9da812b8a7861de75722cf5fcfdbe29e3baf39eb..71fa51e7984e462115d0bb7564ea6871a9c012b9 100644 (file)
@@ -2246,7 +2246,7 @@ struct em28xx_board em28xx_boards[] = {
 };
 EXPORT_SYMBOL_GPL(em28xx_boards);
 
-const unsigned int em28xx_bcount = ARRAY_SIZE(em28xx_boards);
+static const unsigned int em28xx_bcount = ARRAY_SIZE(em28xx_boards);
 
 /* table of devices that work with this driver */
 struct usb_device_id em28xx_id_table[] = {
@@ -2931,9 +2931,9 @@ static void request_module_async(struct work_struct *work)
 #if defined(CONFIG_MODULES) && defined(MODULE)
        if (dev->has_video)
                request_module("em28xx-v4l");
-       if (dev->has_audio_class)
+       if (dev->usb_audio_type == EM28XX_USB_AUDIO_CLASS)
                request_module("snd-usb-audio");
-       else if (dev->has_alsa_audio)
+       else if (dev->usb_audio_type == EM28XX_USB_AUDIO_VENDOR)
                request_module("em28xx-alsa");
        if (dev->board.has_dvb)
                request_module("em28xx-dvb");
@@ -3098,16 +3098,6 @@ static int em28xx_init_dev(struct em28xx *dev, struct usb_device *udev,
                }
        }
 
-       if (dev->chip_id == CHIP_ID_EM2870 ||
-           dev->chip_id == CHIP_ID_EM2874 ||
-           dev->chip_id == CHIP_ID_EM28174 ||
-           dev->chip_id == CHIP_ID_EM28178) {
-               /* Digital only device - don't load any alsa module */
-               dev->audio_mode.has_audio = false;
-               dev->has_audio_class = false;
-               dev->has_alsa_audio = false;
-       }
-
        if (chip_name != default_chip_name)
                printk(KERN_INFO DRIVER_NAME
                       ": chip ID is %s\n", chip_name);
@@ -3190,7 +3180,7 @@ static int em28xx_usb_probe(struct usb_interface *interface,
        struct usb_device *udev;
        struct em28xx *dev = NULL;
        int retval;
-       bool has_audio = false, has_video = false, has_dvb = false;
+       bool has_vendor_audio = false, has_video = false, has_dvb = false;
        int i, nr, try_bulk;
        const int ifnum = interface->altsetting[0].desc.bInterfaceNumber;
        char *speed;
@@ -3272,7 +3262,7 @@ static int em28xx_usb_probe(struct usb_interface *interface,
                                        break;
                                case 0x83:
                                        if (usb_endpoint_xfer_isoc(e)) {
-                                               has_audio = true;
+                                               has_vendor_audio = true;
                                        } else {
                                                printk(KERN_INFO DRIVER_NAME
                                                ": error: skipping audio endpoint 0x83, because it uses bulk transfers !\n");
@@ -3328,7 +3318,7 @@ static int em28xx_usb_probe(struct usb_interface *interface,
                }
        }
 
-       if (!(has_audio || has_video || has_dvb)) {
+       if (!(has_vendor_audio || has_video || has_dvb)) {
                retval = -ENODEV;
                goto err_free;
        }
@@ -3375,26 +3365,27 @@ static int em28xx_usb_probe(struct usb_interface *interface,
        dev->devno = nr;
        dev->model = id->driver_info;
        dev->alt   = -1;
-       dev->is_audio_only = has_audio && !(has_video || has_dvb);
-       dev->has_alsa_audio = has_audio;
-       dev->audio_mode.has_audio = has_audio;
+       dev->is_audio_only = has_vendor_audio && !(has_video || has_dvb);
        dev->has_video = has_video;
        dev->ifnum = ifnum;
 
-       /* Checks if audio is provided by some interface */
+       if (has_vendor_audio) {
+               printk(KERN_INFO DRIVER_NAME ": Audio interface %i found %s\n",
+                      ifnum, "(Vendor Class)");
+               dev->usb_audio_type = EM28XX_USB_AUDIO_VENDOR;
+       }
+       /* Checks if audio is provided by a USB Audio Class interface */
        for (i = 0; i < udev->config->desc.bNumInterfaces; i++) {
                struct usb_interface *uif = udev->config->interface[i];
                if (uif->altsetting[0].desc.bInterfaceClass == USB_CLASS_AUDIO) {
-                       dev->has_audio_class = 1;
+                       if (has_vendor_audio)
+                               em28xx_err("em28xx: device seems to have vendor AND usb audio class interfaces !\n"
+                                          "\t\tThe vendor interface will be ignored. Please contact the developers <linux-media@vger.kernel.org>\n");
+                       dev->usb_audio_type = EM28XX_USB_AUDIO_CLASS;
                        break;
                }
        }
 
-       if (has_audio)
-               printk(KERN_INFO DRIVER_NAME
-                      ": Audio interface %i found %s\n",
-                      ifnum,
-                      dev->has_audio_class ? "(USB Audio Class)" : "(Vendor Class)");
        if (has_video)
                printk(KERN_INFO DRIVER_NAME
                       ": Video interface %i found:%s%s\n",
index 523d7e92bf47b7974515a1d9acd2fc19ab131b51..b5e52fe7957aff0d047abb1f89caab275fcb1afd 100644 (file)
@@ -279,7 +279,7 @@ int em28xx_read_ac97(struct em28xx *dev, u8 reg)
 {
        int ret;
        u8 addr = (reg & 0x7f) | 0x80;
-       u16 val;
+       __le16 val;
 
        ret = em28xx_is_ac97_ready(dev);
        if (ret < 0)
@@ -433,7 +433,7 @@ int em28xx_audio_analog_set(struct em28xx *dev)
        int ret, i;
        u8 xclk;
 
-       if (!dev->audio_mode.has_audio)
+       if (dev->int_audio_type == EM28XX_INT_AUDIO_NONE)
                return 0;
 
        /* It is assumed that all devices use master volume for output.
@@ -505,37 +505,48 @@ int em28xx_audio_setup(struct em28xx *dev)
 {
        int vid1, vid2, feat, cfg;
        u32 vid;
+       u8 i2s_samplerates;
 
-       if (!dev->audio_mode.has_audio)
+       if (dev->chip_id == CHIP_ID_EM2870 ||
+           dev->chip_id == CHIP_ID_EM2874 ||
+           dev->chip_id == CHIP_ID_EM28174 ||
+           dev->chip_id == CHIP_ID_EM28178) {
+               /* Digital only device - don't load any alsa module */
+               dev->int_audio_type = EM28XX_INT_AUDIO_NONE;
+               dev->usb_audio_type = EM28XX_USB_AUDIO_NONE;
                return 0;
+       }
 
        /* See how this device is configured */
        cfg = em28xx_read_reg(dev, EM28XX_R00_CHIPCFG);
        em28xx_info("Config register raw data: 0x%02x\n", cfg);
-       if (cfg < 0) {
-               /* Register read error?  */
-               cfg = EM28XX_CHIPCFG_AC97; /* Be conservative */
+       if (cfg < 0) { /* Register read error */
+               /* Be conservative */
+               dev->int_audio_type = EM28XX_INT_AUDIO_AC97;
        } else if ((cfg & EM28XX_CHIPCFG_AUDIOMASK) == 0x00) {
                /* The device doesn't have vendor audio at all */
-               dev->has_alsa_audio = false;
-               dev->audio_mode.has_audio = false;
+               dev->int_audio_type = EM28XX_INT_AUDIO_NONE;
+               dev->usb_audio_type = EM28XX_USB_AUDIO_NONE;
                return 0;
        } else if ((cfg & EM28XX_CHIPCFG_AUDIOMASK) != EM28XX_CHIPCFG_AC97) {
+               dev->int_audio_type = EM28XX_INT_AUDIO_I2S;
                if (dev->chip_id < CHIP_ID_EM2860 &&
                    (cfg & EM28XX_CHIPCFG_AUDIOMASK) ==
                    EM2820_CHIPCFG_I2S_1_SAMPRATE)
-                       dev->audio_mode.i2s_samplerates = 1;
+                       i2s_samplerates = 1;
                else if (dev->chip_id >= CHIP_ID_EM2860 &&
                         (cfg & EM28XX_CHIPCFG_AUDIOMASK) ==
                         EM2860_CHIPCFG_I2S_5_SAMPRATES)
-                       dev->audio_mode.i2s_samplerates = 5;
+                       i2s_samplerates = 5;
                else
-                       dev->audio_mode.i2s_samplerates = 3;
+                       i2s_samplerates = 3;
                em28xx_info("I2S Audio (%d sample rate(s))\n",
-                                              dev->audio_mode.i2s_samplerates);
+                                              i2s_samplerates);
                /* Skip the code that does AC97 vendor detection */
                dev->audio_mode.ac97 = EM28XX_NO_AC97;
                goto init_audio;
+       } else {
+               dev->int_audio_type = EM28XX_INT_AUDIO_AC97;
        }
 
        dev->audio_mode.ac97 = EM28XX_AC97_OTHER;
@@ -549,8 +560,9 @@ int em28xx_audio_setup(struct em28xx *dev)
                 */
                em28xx_warn("AC97 chip type couldn't be determined\n");
                dev->audio_mode.ac97 = EM28XX_NO_AC97;
-               dev->has_alsa_audio = false;
-               dev->audio_mode.has_audio = false;
+               if (dev->usb_audio_type == EM28XX_USB_AUDIO_VENDOR)
+                       dev->usb_audio_type = EM28XX_USB_AUDIO_NONE;
+               dev->int_audio_type = EM28XX_INT_AUDIO_NONE;
                goto init_audio;
        }
 
@@ -559,15 +571,12 @@ int em28xx_audio_setup(struct em28xx *dev)
                goto init_audio;
 
        vid = vid1 << 16 | vid2;
-
-       dev->audio_mode.ac97_vendor_id = vid;
        em28xx_warn("AC97 vendor ID = 0x%08x\n", vid);
 
        feat = em28xx_read_ac97(dev, AC97_RESET);
        if (feat < 0)
                goto init_audio;
 
-       dev->audio_mode.ac97_feat = feat;
        em28xx_warn("AC97 features = 0x%04x\n", feat);
 
        /* Try to identify what audio processor we have */
@@ -586,8 +595,8 @@ init_audio:
                em28xx_info("Empia 202 AC97 audio processor detected\n");
                break;
        case EM28XX_AC97_SIGMATEL:
-               em28xx_info("Sigmatel audio processor detected(stac 97%02x)\n",
-                           dev->audio_mode.ac97_vendor_id & 0xff);
+               em28xx_info("Sigmatel audio processor detected (stac 97%02x)\n",
+                           vid & 0xff);
                break;
        case EM28XX_AC97_OTHER:
                em28xx_warn("Unknown AC97 audio processor detected!\n");
index 3a3e243edf89df29982f632cb06e0f53af6ad515..9682c52d67d17b3be3d52e9fc9f878f73d2aed9d 100644 (file)
@@ -373,7 +373,6 @@ static struct tda18271_config kworld_ub435q_v2_config = {
 };
 
 static struct tda18212_config kworld_ub435q_v3_config = {
-       .i2c_address    = 0x60,
        .if_atsc_vsb    = 3600,
        .if_atsc_qam    = 3600,
 };
@@ -856,7 +855,9 @@ static const struct m88ds3103_config pctv_461e_m88ds3103_config = {
        .clock = 27000000,
        .i2c_wr_max = 33,
        .clock_out = 0,
-       .ts_mode = M88DS3103_TS_PARALLEL_16,
+       .ts_mode = M88DS3103_TS_PARALLEL,
+       .ts_clk = 16000,
+       .ts_clk_pol = 1,
        .agc = 0x99,
 };
 
@@ -1435,6 +1436,15 @@ static int em28xx_dvb_init(struct em28xx *dev)
                }
                break;
        case EM2874_BOARD_KWORLD_UB435Q_V3:
+       {
+               struct i2c_client *client;
+               struct i2c_adapter *adapter = &dev->i2c_adap[dev->def_i2c_bus];
+               struct i2c_board_info board_info = {
+                       .type = "tda18212",
+                       .addr = 0x60,
+                       .platform_data = &kworld_ub435q_v3_config,
+               };
+
                dvb->fe[0] = dvb_attach(lgdt3305_attach,
                                        &em2874_lgdt3305_nogate_dev,
                                        &dev->i2c_adap[dev->def_i2c_bus]);
@@ -1443,14 +1453,26 @@ static int em28xx_dvb_init(struct em28xx *dev)
                        goto out_free;
                }
 
-               /* Attach the demodulator. */
-               if (!dvb_attach(tda18212_attach, dvb->fe[0],
-                               &dev->i2c_adap[dev->def_i2c_bus],
-                               &kworld_ub435q_v3_config)) {
-                       result = -EINVAL;
+               /* attach tuner */
+               kworld_ub435q_v3_config.fe = dvb->fe[0];
+               request_module("tda18212");
+               client = i2c_new_device(adapter, &board_info);
+               if (client == NULL || client->dev.driver == NULL) {
+                       dvb_frontend_detach(dvb->fe[0]);
+                       result = -ENODEV;
                        goto out_free;
                }
+
+               if (!try_module_get(client->dev.driver->owner)) {
+                       i2c_unregister_device(client);
+                       dvb_frontend_detach(dvb->fe[0]);
+                       result = -ENODEV;
+                       goto out_free;
+               }
+
+               dvb->i2c_client_tuner = client;
                break;
+       }
        case EM2874_BOARD_PCTV_HD_MINI_80E:
                dvb->fe[0] = dvb_attach(drx39xxj_attach, &dev->i2c_adap[dev->def_i2c_bus]);
                if (dvb->fe[0] != NULL) {
@@ -1533,6 +1555,7 @@ static int em28xx_dvb_init(struct em28xx *dev)
                        /* attach demod */
                        si2168_config.i2c_adapter = &adapter;
                        si2168_config.fe = &dvb->fe[0];
+                       si2168_config.ts_mode = SI2168_TS_PARALLEL;
                        memset(&info, 0, sizeof(struct i2c_board_info));
                        strlcpy(info.type, "si2168", I2C_NAME_SIZE);
                        info.addr = 0x64;
index ed843bd221eaec8a9bb3307d965a0b49275e50f1..581f6dad4ca9deef0fa5a0820372238b8a4e3bbd 100644 (file)
@@ -71,8 +71,7 @@ struct em28xx_IR {
        unsigned int last_readcount;
        u64 rc_type;
 
-       /* i2c slave address of external device (if used) */
-       u16 i2c_dev_addr;
+       struct i2c_client *i2c_client;
 
        int  (*get_key_i2c)(struct i2c_client *ir, enum rc_type *protocol, u32 *scancode);
        int  (*get_key)(struct em28xx_IR *, struct em28xx_ir_poll_result *);
@@ -294,16 +293,11 @@ static int em2874_polling_getkey(struct em28xx_IR *ir,
 
 static int em28xx_i2c_ir_handle_key(struct em28xx_IR *ir)
 {
-       struct em28xx *dev = ir->dev;
        static u32 scancode;
        enum rc_type protocol;
        int rc;
-       struct i2c_client client;
-
-       client.adapter = &ir->dev->i2c_adap[dev->def_i2c_bus];
-       client.addr = ir->i2c_dev_addr;
 
-       rc = ir->get_key_i2c(&client, &protocol, &scancode);
+       rc = ir->get_key_i2c(ir->i2c_client, &protocol, &scancode);
        if (rc < 0) {
                dprintk("ir->get_key_i2c() failed: %d\n", rc);
                return rc;
@@ -361,7 +355,7 @@ static void em28xx_ir_work(struct work_struct *work)
 {
        struct em28xx_IR *ir = container_of(work, struct em28xx_IR, work.work);
 
-       if (ir->i2c_dev_addr) /* external i2c device */
+       if (ir->i2c_client) /* external i2c device */
                em28xx_i2c_ir_handle_key(ir);
        else /* internal device */
                em28xx_ir_handle_key(ir);
@@ -609,17 +603,17 @@ static int em28xx_register_snapshot_button(struct em28xx *dev)
 static void em28xx_init_buttons(struct em28xx *dev)
 {
        u8  i = 0, j = 0;
-       bool addr_new = 0;
+       bool addr_new = false;
 
        dev->button_polling_interval = EM28XX_BUTTONS_DEBOUNCED_QUERY_INTERVAL;
        while (dev->board.buttons[i].role >= 0 &&
                         dev->board.buttons[i].role < EM28XX_NUM_BUTTON_ROLES) {
                struct em28xx_button *button = &dev->board.buttons[i];
                /* Check if polling address is already on the list */
-               addr_new = 1;
+               addr_new = true;
                for (j = 0; j < dev->num_button_polling_addresses; j++) {
                        if (button->reg_r == dev->button_polling_addresses[j]) {
-                               addr_new = 0;
+                               addr_new = false;
                                break;
                        }
                }
@@ -756,7 +750,13 @@ static int em28xx_ir_init(struct em28xx *dev)
                        goto error;
                }
 
-               ir->i2c_dev_addr = i2c_rc_dev_addr;
+               ir->i2c_client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
+               if (!ir->i2c_client)
+                       goto error;
+               ir->i2c_client->adapter = &ir->dev->i2c_adap[dev->def_i2c_bus];
+               ir->i2c_client->addr = i2c_rc_dev_addr;
+               ir->i2c_client->flags = 0;
+               /* NOTE: all other fields of i2c_client are unused */
        } else {        /* internal device */
                switch (dev->chip_id) {
                case CHIP_ID_EM2860:
@@ -815,6 +815,7 @@ static int em28xx_ir_init(struct em28xx *dev)
        return 0;
 
 error:
+       kfree(ir->i2c_client);
        dev->ir = NULL;
        rc_free_device(rc);
        kfree(ir);
@@ -841,6 +842,8 @@ static int em28xx_ir_fini(struct em28xx *dev)
        if (ir->rc)
                rc_unregister_device(ir->rc);
 
+       kfree(ir->i2c_client);
+
        /* done */
        kfree(ir);
        dev->ir = NULL;
index 6d7f657f6f55cad6e19a72a1b0ff0477751a909c..34ee1e03a73283b3cc1e4100140ee343984a7b0d 100644 (file)
 #include "em28xx.h"
 #include "em28xx-v4l.h"
 
-static unsigned int vbibufs = 5;
-module_param(vbibufs, int, 0644);
-MODULE_PARM_DESC(vbibufs, "number of vbi buffers, range 2-32");
-
-static unsigned int vbi_debug;
-module_param(vbi_debug, int, 0644);
-MODULE_PARM_DESC(vbi_debug, "enable debug messages [vbi]");
-
-#define dprintk(level, fmt, arg...)    if (vbi_debug >= level) \
-       printk(KERN_DEBUG "%s: " fmt, dev->core->name , ## arg)
-
 /* ------------------------------------------------------------------ */
 
 static int vbi_queue_setup(struct vb2_queue *vq, const struct v4l2_format *fmt,
index 29abc379551e5d6f79483520a892006dca848ed7..03d5ece0319c63e748f669635889769fc64ea210 100644 (file)
@@ -435,7 +435,10 @@ static inline void finish_buffer(struct em28xx *dev,
        em28xx_isocdbg("[%p/%d] wakeup\n", buf, buf->top_field);
 
        buf->vb.v4l2_buf.sequence = dev->v4l2->field_count++;
-       buf->vb.v4l2_buf.field = V4L2_FIELD_INTERLACED;
+       if (dev->v4l2->progressive)
+               buf->vb.v4l2_buf.field = V4L2_FIELD_NONE;
+       else
+               buf->vb.v4l2_buf.field = V4L2_FIELD_INTERLACED;
        v4l2_get_timestamp(&buf->vb.v4l2_buf.timestamp);
 
        vb2_buffer_done(&buf->vb, VB2_BUF_STATE_DONE);
@@ -478,7 +481,7 @@ static void em28xx_copy_video(struct em28xx *dev,
        lencopy = lencopy > remain ? remain : lencopy;
 
        if ((char *)startwrite + lencopy > (char *)buf->vb_buf + buf->length) {
-               em28xx_isocdbg("Overflow of %zi bytes past buffer end (1)\n",
+               em28xx_isocdbg("Overflow of %zu bytes past buffer end (1)\n",
                              ((char *)startwrite + lencopy) -
                              ((char *)buf->vb_buf + buf->length));
                remain = (char *)buf->vb_buf + buf->length -
@@ -504,7 +507,7 @@ static void em28xx_copy_video(struct em28xx *dev,
 
                if ((char *)startwrite + lencopy > (char *)buf->vb_buf +
                    buf->length) {
-                       em28xx_isocdbg("Overflow of %zi bytes past buffer end"
+                       em28xx_isocdbg("Overflow of %zu bytes past buffer end"
                                       "(2)\n",
                                       ((char *)startwrite + lencopy) -
                                       ((char *)buf->vb_buf + buf->length));
@@ -718,7 +721,7 @@ static inline void process_frame_data_em25xx(struct em28xx *dev,
        struct em28xx_buffer    *buf = dev->usb_ctl.vid_buf;
        struct em28xx_dmaqueue  *dmaq = &dev->vidq;
        struct em28xx_v4l2      *v4l2 = dev->v4l2;
-       bool frame_end = 0;
+       bool frame_end = false;
 
        /* Check for header */
        /* NOTE: at least with bulk transfers, only the first packet
@@ -994,13 +997,16 @@ static void em28xx_stop_streaming(struct vb2_queue *vq)
        }
 
        spin_lock_irqsave(&dev->slock, flags);
+       if (dev->usb_ctl.vid_buf != NULL) {
+               vb2_buffer_done(&dev->usb_ctl.vid_buf->vb, VB2_BUF_STATE_ERROR);
+               dev->usb_ctl.vid_buf = NULL;
+       }
        while (!list_empty(&vidq->active)) {
                struct em28xx_buffer *buf;
                buf = list_entry(vidq->active.next, struct em28xx_buffer, list);
                list_del(&buf->list);
                vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR);
        }
-       dev->usb_ctl.vid_buf = NULL;
        spin_unlock_irqrestore(&dev->slock, flags);
 }
 
@@ -1021,13 +1027,16 @@ void em28xx_stop_vbi_streaming(struct vb2_queue *vq)
        }
 
        spin_lock_irqsave(&dev->slock, flags);
+       if (dev->usb_ctl.vbi_buf != NULL) {
+               vb2_buffer_done(&dev->usb_ctl.vbi_buf->vb, VB2_BUF_STATE_ERROR);
+               dev->usb_ctl.vbi_buf = NULL;
+       }
        while (!list_empty(&vbiq->active)) {
                struct em28xx_buffer *buf;
                buf = list_entry(vbiq->active.next, struct em28xx_buffer, list);
                list_del(&buf->list);
                vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR);
        }
-       dev->usb_ctl.vbi_buf = NULL;
        spin_unlock_irqrestore(&dev->slock, flags);
 }
 
@@ -1711,7 +1720,7 @@ static int vidioc_querycap(struct file *file, void  *priv,
        else
                cap->device_caps = V4L2_CAP_READWRITE | V4L2_CAP_VBI_CAPTURE;
 
-       if (dev->audio_mode.has_audio)
+       if (dev->int_audio_type != EM28XX_INT_AUDIO_NONE)
                cap->device_caps |= V4L2_CAP_AUDIO;
 
        if (dev->tuner_type != TUNER_ABSENT)
@@ -2296,7 +2305,7 @@ static int em28xx_v4l2_init(struct em28xx *dev)
        v4l2->v4l2_dev.ctrl_handler = hdl;
 
        if (dev->board.is_webcam)
-               v4l2->progressive = 1;
+               v4l2->progressive = true;
 
        /*
         * Default format, used for tvp5150 or saa711x output formats
@@ -2502,7 +2511,7 @@ static int em28xx_v4l2_init(struct em28xx *dev)
                v4l2_disable_ioctl(v4l2->vdev, VIDIOC_G_FREQUENCY);
                v4l2_disable_ioctl(v4l2->vdev, VIDIOC_S_FREQUENCY);
        }
-       if (!dev->audio_mode.has_audio) {
+       if (dev->int_audio_type == EM28XX_INT_AUDIO_NONE) {
                v4l2_disable_ioctl(v4l2->vdev, VIDIOC_G_AUDIO);
                v4l2_disable_ioctl(v4l2->vdev, VIDIOC_S_AUDIO);
        }
@@ -2532,7 +2541,7 @@ static int em28xx_v4l2_init(struct em28xx *dev)
                        v4l2_disable_ioctl(v4l2->vbi_dev, VIDIOC_G_FREQUENCY);
                        v4l2_disable_ioctl(v4l2->vbi_dev, VIDIOC_S_FREQUENCY);
                }
-               if (!dev->audio_mode.has_audio) {
+               if (dev->int_audio_type == EM28XX_INT_AUDIO_NONE) {
                        v4l2_disable_ioctl(v4l2->vbi_dev, VIDIOC_G_AUDIO);
                        v4l2_disable_ioctl(v4l2->vbi_dev, VIDIOC_S_AUDIO);
                }
index 4360338e7b310a2ab985eca427ef34124ddf15a5..a21a7463b557913ff0c97eb41f203a1f1d95c930 100644 (file)
@@ -309,13 +309,18 @@ enum em28xx_ac97_mode {
 
 struct em28xx_audio_mode {
        enum em28xx_ac97_mode ac97;
+};
 
-       u16 ac97_feat;
-       u32 ac97_vendor_id;
-
-       unsigned int has_audio:1;
+enum em28xx_int_audio_type {
+       EM28XX_INT_AUDIO_NONE = 0,
+       EM28XX_INT_AUDIO_AC97,
+       EM28XX_INT_AUDIO_I2S,
+};
 
-       u8 i2s_samplerates;
+enum em28xx_usb_audio_type {
+       EM28XX_USB_AUDIO_NONE = 0,
+       EM28XX_USB_AUDIO_CLASS,
+       EM28XX_USB_AUDIO_VENDOR,
 };
 
 /* em28xx has two audio inputs: tuner and line in.
@@ -608,9 +613,9 @@ struct em28xx {
        unsigned int is_em25xx:1;       /* em25xx/em276x/7x/8x family bridge */
        unsigned char disconnected:1;   /* device has been diconnected */
        unsigned int has_video:1;
-       unsigned int has_audio_class:1;
-       unsigned int has_alsa_audio:1;
        unsigned int is_audio_only:1;
+       enum em28xx_int_audio_type int_audio_type;
+       enum em28xx_usb_audio_type usb_audio_type;
 
        struct em28xx_board board;
 
index ece27ece81158f0c17b1125f3a8e27616082a45b..3f986e1178ce4fa5f821eadf489b3e5f15ff2e33 100644 (file)
@@ -696,7 +696,7 @@ static int go7007_usb_ezusb_write_interrupt(struct go7007 *go,
                                sizeof(status_reg), timeout);
                if (r < 0)
                        break;
-               status_reg = le16_to_cpu(*((u16 *)go->usb_buf));
+               status_reg = le16_to_cpu(*((__le16 *)go->usb_buf));
                if (!(status_reg & 0x0010))
                        break;
                msleep(10);
@@ -751,7 +751,7 @@ static int go7007_usb_onboard_write_interrupt(struct go7007 *go,
 static void go7007_usb_readinterrupt_complete(struct urb *urb)
 {
        struct go7007 *go = (struct go7007 *)urb->context;
-       u16 *regs = (u16 *)urb->transfer_buffer;
+       __le16 *regs = (__le16 *)urb->transfer_buffer;
        int status = urb->status;
 
        if (status) {
index e8cf23c91cefc0b570391f5146b831733f5d14be..43d65057a5fe657464d5e7709c769e9fa4b93115 100644 (file)
@@ -876,9 +876,8 @@ static int gspca_init_transfer(struct gspca_dev *gspca_dev)
                ep_tb[0].alt = gspca_dev->alt;
                alt_idx = 1;
        } else {
-
-       /* else, compute the minimum bandwidth
-        * and build the endpoint table */
+               /* else, compute the minimum bandwidth
+                * and build the endpoint table */
                alt_idx = build_isoc_ep_tb(gspca_dev, intf, ep_tb);
                if (alt_idx <= 0) {
                        pr_err("no transfer endpoint found\n");
index f06253cd746901bfbeca0521e42c465db4241fa9..d39adf90303b9a4371fd3ed878705ae7754535d8 100644 (file)
@@ -235,6 +235,6 @@ int gspca_resume(struct usb_interface *intf);
 int gspca_expo_autogain(struct gspca_dev *gspca_dev, int avg_lum,
        int desired_avg_lum, int deadzone, int gain_knee, int exposure_knee);
 int gspca_coarse_grained_expo_autogain(struct gspca_dev *gspca_dev,
-        int avg_lum, int desired_avg_lum, int deadzone);
+       int avg_lum, int desired_avg_lum, int deadzone);
 
 #endif /* GSPCAV2_H */
index 45bc1f51c5d8c14ed0fe6d6dd71690d7b990c530..3cb30a37d6ac90818521dc646b48b9f9bfcabb95 100644 (file)
@@ -51,9 +51,9 @@ struct pkt_hdr {
 
 struct cam_hdr {
        uint8_t magic[2];
-       uint16_t len;
-       uint16_t cmd;
-       uint16_t tag;
+       __le16 len;
+       __le16 cmd;
+       __le16 tag;
 };
 
 /* specific webcam descriptor */
@@ -188,9 +188,9 @@ static int send_cmd(struct gspca_dev *gspca_dev, uint16_t cmd, void *cmdbuf,
                       rhdr->tag, chdr->tag);
                return -1;
        }
-       if (cpu_to_le16(rhdr->len) != (actual_len/2)) {
+       if (le16_to_cpu(rhdr->len) != (actual_len/2)) {
                pr_err("send_cmd: Bad len %04x != %04x\n",
-                      cpu_to_le16(rhdr->len), (int)(actual_len/2));
+                      le16_to_cpu(rhdr->len), (int)(actual_len/2));
                return -1;
        }
 
@@ -211,7 +211,7 @@ static int write_register(struct gspca_dev *gspca_dev, uint16_t reg,
                        uint16_t data)
 {
        uint16_t reply[2];
-       uint16_t cmd[2];
+       __le16 cmd[2];
        int res;
 
        cmd[0] = cpu_to_le16(reg);
index 41a9a892f79c546c4a6b54edbee1ac09408897f6..d0ee899584a9f1188d44613ec6f21228a0e94e7a 100644 (file)
@@ -1297,7 +1297,7 @@ static void set_cmatrix(struct gspca_dev *gspca_dev,
        s32 hue_coord, hue_index = 180 + hue;
        u8 cmatrix[21];
 
-       memset(cmatrix, 0, sizeof cmatrix);
+       memset(cmatrix, 0, sizeof(cmatrix));
        cmatrix[2] = (contrast * 0x25 / 0x100) + 0x26;
        cmatrix[0] = 0x13 + (cmatrix[2] - 0x26) * 0x13 / 0x25;
        cmatrix[4] = 0x07 + (cmatrix[2] - 0x26) * 0x07 / 0x25;
@@ -1787,8 +1787,9 @@ static int sd_init(struct gspca_dev *gspca_dev)
        struct sd *sd = (struct sd *) gspca_dev;
        int i;
        u8 value;
-       u8 i2c_init[9] =
-               {0x80, sd->i2c_addr, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03};
+       u8 i2c_init[9] = {
+               0x80, sd->i2c_addr, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03
+       };
 
        for (i = 0; i < ARRAY_SIZE(bridge_init); i++) {
                value = bridge_init[i][1];
@@ -2242,8 +2243,9 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
 {
        struct sd *sd = (struct sd *) gspca_dev;
        int avg_lum, is_jpeg;
-       static const u8 frame_header[] =
-               {0xff, 0xff, 0x00, 0xc4, 0xc4, 0x96};
+       static const u8 frame_header[] = {
+               0xff, 0xff, 0x00, 0xc4, 0xc4, 0x96
+       };
 
        is_jpeg = (sd->fmt & 0x03) == 0;
        if (len >= 64 && memcmp(data, frame_header, 6) == 0) {
diff --git a/drivers/media/usb/hackrf/Kconfig b/drivers/media/usb/hackrf/Kconfig
new file mode 100644 (file)
index 0000000..937e6f5
--- /dev/null
@@ -0,0 +1,10 @@
+config USB_HACKRF
+       tristate "HackRF"
+       depends on VIDEO_V4L2
+       select VIDEOBUF2_VMALLOC
+       ---help---
+         This is a video4linux2 driver for HackRF SDR device.
+
+         To compile this driver as a module, choose M here: the
+         module will be called hackrf
+
diff --git a/drivers/media/usb/hackrf/Makefile b/drivers/media/usb/hackrf/Makefile
new file mode 100644 (file)
index 0000000..73064a2
--- /dev/null
@@ -0,0 +1 @@
+obj-$(CONFIG_USB_HACKRF)              += hackrf.o
diff --git a/drivers/media/usb/hackrf/hackrf.c b/drivers/media/usb/hackrf/hackrf.c
new file mode 100644 (file)
index 0000000..328b5ba
--- /dev/null
@@ -0,0 +1,1142 @@
+/*
+ * HackRF driver
+ *
+ * Copyright (C) 2014 Antti Palosaari <crope@iki.fi>
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (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/slab.h>
+#include <linux/usb.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-event.h>
+#include <media/videobuf2-vmalloc.h>
+
+/* HackRF USB API commands (from HackRF Library) */
+enum {
+       CMD_SET_TRANSCEIVER_MODE           = 0x01,
+       CMD_SAMPLE_RATE_SET                = 0x06,
+       CMD_BASEBAND_FILTER_BANDWIDTH_SET  = 0x07,
+       CMD_BOARD_ID_READ                  = 0x0e,
+       CMD_VERSION_STRING_READ            = 0x0f,
+       CMD_SET_FREQ                       = 0x10,
+       CMD_SET_LNA_GAIN                   = 0x13,
+       CMD_SET_VGA_GAIN                   = 0x14,
+};
+
+/*
+ *       bEndpointAddress     0x81  EP 1 IN
+ *         Transfer Type            Bulk
+ *       wMaxPacketSize     0x0200  1x 512 bytes
+ */
+#define MAX_BULK_BUFS            (6)
+#define BULK_BUFFER_SIZE         (128 * 512)
+
+static const struct v4l2_frequency_band bands_adc[] = {
+       {
+               .tuner = 0,
+               .type = V4L2_TUNER_ADC,
+               .index = 0,
+               .capability = V4L2_TUNER_CAP_1HZ | V4L2_TUNER_CAP_FREQ_BANDS,
+               .rangelow   =   200000,
+               .rangehigh  = 24000000,
+       },
+};
+
+static const struct v4l2_frequency_band bands_rf[] = {
+       {
+               .tuner = 1,
+               .type = V4L2_TUNER_RF,
+               .index = 0,
+               .capability = V4L2_TUNER_CAP_1HZ | V4L2_TUNER_CAP_FREQ_BANDS,
+               .rangelow   =          1,
+               .rangehigh  = 4294967294LL, /* max u32, hw goes over 7GHz */
+       },
+};
+
+/* stream formats */
+struct hackrf_format {
+       char    *name;
+       u32     pixelformat;
+       u32     buffersize;
+};
+
+/* format descriptions for capture and preview */
+static struct hackrf_format formats[] = {
+       {
+               .name           = "Complex S8",
+               .pixelformat    = V4L2_SDR_FMT_CS8,
+               .buffersize     = BULK_BUFFER_SIZE,
+       },
+};
+
+static const unsigned int NUM_FORMATS = ARRAY_SIZE(formats);
+
+/* intermediate buffers with raw data from the USB device */
+struct hackrf_frame_buf {
+       struct vb2_buffer vb;   /* common v4l buffer stuff -- must be first */
+       struct list_head list;
+};
+
+struct hackrf_dev {
+#define POWER_ON           (1 << 1)
+#define URB_BUF            (1 << 2)
+#define USB_STATE_URB_BUF  (1 << 3)
+       unsigned long flags;
+
+       struct device *dev;
+       struct usb_device *udev;
+       struct video_device vdev;
+       struct v4l2_device v4l2_dev;
+
+       /* videobuf2 queue and queued buffers list */
+       struct vb2_queue vb_queue;
+       struct list_head queued_bufs;
+       spinlock_t queued_bufs_lock; /* Protects queued_bufs */
+       unsigned sequence;           /* Buffer sequence counter */
+       unsigned int vb_full;        /* vb is full and packets dropped */
+
+       /* Note if taking both locks v4l2_lock must always be locked first! */
+       struct mutex v4l2_lock;      /* Protects everything else */
+       struct mutex vb_queue_lock;  /* Protects vb_queue */
+
+       struct urb     *urb_list[MAX_BULK_BUFS];
+       int            buf_num;
+       unsigned long  buf_size;
+       u8             *buf_list[MAX_BULK_BUFS];
+       dma_addr_t     dma_addr[MAX_BULK_BUFS];
+       int            urbs_initialized;
+       int            urbs_submitted;
+
+       /* USB control message buffer */
+       #define BUF_SIZE 24
+       u8 buf[BUF_SIZE];
+
+       /* Current configuration */
+       unsigned int f_adc;
+       unsigned int f_rf;
+       u32 pixelformat;
+       u32 buffersize;
+
+       /* Controls */
+       struct v4l2_ctrl_handler hdl;
+       struct v4l2_ctrl *bandwidth_auto;
+       struct v4l2_ctrl *bandwidth;
+       struct v4l2_ctrl *lna_gain;
+       struct v4l2_ctrl *if_gain;
+
+       /* Sample rate calc */
+       unsigned long jiffies_next;
+       unsigned int sample;
+       unsigned int sample_measured;
+};
+
+#define hackrf_dbg_usb_control_msg(_dev, _r, _t, _v, _i, _b, _l) { \
+       char *_direction; \
+       if (_t & USB_DIR_IN) \
+               _direction = "<<<"; \
+       else \
+               _direction = ">>>"; \
+       dev_dbg(_dev, "%02x %02x %02x %02x %02x %02x %02x %02x %s %*ph\n", \
+                       _t, _r, _v & 0xff, _v >> 8, _i & 0xff, \
+                       _i >> 8, _l & 0xff, _l >> 8, _direction, _l, _b); \
+}
+
+/* execute firmware command */
+static int hackrf_ctrl_msg(struct hackrf_dev *dev, u8 request, u16 value,
+               u16 index, u8 *data, u16 size)
+{
+       int ret;
+       unsigned int pipe;
+       u8 requesttype;
+
+       switch (request) {
+       case CMD_SET_TRANSCEIVER_MODE:
+       case CMD_SET_FREQ:
+       case CMD_SAMPLE_RATE_SET:
+       case CMD_BASEBAND_FILTER_BANDWIDTH_SET:
+               pipe = usb_sndctrlpipe(dev->udev, 0);
+               requesttype = (USB_TYPE_VENDOR | USB_DIR_OUT);
+               break;
+       case CMD_BOARD_ID_READ:
+       case CMD_VERSION_STRING_READ:
+       case CMD_SET_LNA_GAIN:
+       case CMD_SET_VGA_GAIN:
+               pipe = usb_rcvctrlpipe(dev->udev, 0);
+               requesttype = (USB_TYPE_VENDOR | USB_DIR_IN);
+               break;
+       default:
+               dev_err(dev->dev, "Unknown command %02x\n", request);
+               ret = -EINVAL;
+               goto err;
+       }
+
+       /* write request */
+       if (!(requesttype & USB_DIR_IN))
+               memcpy(dev->buf, data, size);
+
+       ret = usb_control_msg(dev->udev, pipe, request, requesttype, value,
+                       index, dev->buf, size, 1000);
+       hackrf_dbg_usb_control_msg(dev->dev, request, requesttype, value,
+                       index, dev->buf, size);
+       if (ret < 0) {
+               dev_err(dev->dev, "usb_control_msg() failed %d request %02x\n",
+                               ret, request);
+               goto err;
+       }
+
+       /* read request */
+       if (requesttype & USB_DIR_IN)
+               memcpy(data, dev->buf, size);
+
+       return 0;
+err:
+       return ret;
+}
+
+/* Private functions */
+static struct hackrf_frame_buf *hackrf_get_next_fill_buf(struct hackrf_dev *dev)
+{
+       unsigned long flags;
+       struct hackrf_frame_buf *buf = NULL;
+
+       spin_lock_irqsave(&dev->queued_bufs_lock, flags);
+       if (list_empty(&dev->queued_bufs))
+               goto leave;
+
+       buf = list_entry(dev->queued_bufs.next, struct hackrf_frame_buf, list);
+       list_del(&buf->list);
+leave:
+       spin_unlock_irqrestore(&dev->queued_bufs_lock, flags);
+       return buf;
+}
+
+static unsigned int hackrf_convert_stream(struct hackrf_dev *dev,
+               void *dst, void *src, unsigned int src_len)
+{
+       memcpy(dst, src, src_len);
+
+       /* calculate sample rate and output it in 10 seconds intervals */
+       if (unlikely(time_is_before_jiffies(dev->jiffies_next))) {
+               #define MSECS 10000UL
+               unsigned int msecs = jiffies_to_msecs(jiffies -
+                               dev->jiffies_next + msecs_to_jiffies(MSECS));
+               unsigned int samples = dev->sample - dev->sample_measured;
+
+               dev->jiffies_next = jiffies + msecs_to_jiffies(MSECS);
+               dev->sample_measured = dev->sample;
+               dev_dbg(dev->dev, "slen=%u samples=%u msecs=%u sample rate=%lu\n",
+                               src_len, samples, msecs,
+                               samples * 1000UL / msecs);
+       }
+
+       /* total number of samples */
+       dev->sample += src_len / 2;
+
+       return src_len;
+}
+
+/*
+ * This gets called for the bulk stream pipe. This is done in interrupt
+ * time, so it has to be fast, not crash, and not stall. Neat.
+ */
+static void hackrf_urb_complete(struct urb *urb)
+{
+       struct hackrf_dev *dev = urb->context;
+       struct hackrf_frame_buf *fbuf;
+
+       dev_dbg_ratelimited(dev->dev, "status=%d length=%d/%d errors=%d\n",
+                       urb->status, urb->actual_length,
+                       urb->transfer_buffer_length, urb->error_count);
+
+       switch (urb->status) {
+       case 0:             /* success */
+       case -ETIMEDOUT:    /* NAK */
+               break;
+       case -ECONNRESET:   /* kill */
+       case -ENOENT:
+       case -ESHUTDOWN:
+               return;
+       default:            /* error */
+               dev_err_ratelimited(dev->dev, "URB failed %d\n", urb->status);
+               break;
+       }
+
+       if (likely(urb->actual_length > 0)) {
+               void *ptr;
+               unsigned int len;
+               /* get free framebuffer */
+               fbuf = hackrf_get_next_fill_buf(dev);
+               if (unlikely(fbuf == NULL)) {
+                       dev->vb_full++;
+                       dev_notice_ratelimited(dev->dev,
+                                       "videobuf is full, %d packets dropped\n",
+                                       dev->vb_full);
+                       goto skip;
+               }
+
+               /* fill framebuffer */
+               ptr = vb2_plane_vaddr(&fbuf->vb, 0);
+               len = hackrf_convert_stream(dev, ptr, urb->transfer_buffer,
+                               urb->actual_length);
+               vb2_set_plane_payload(&fbuf->vb, 0, len);
+               v4l2_get_timestamp(&fbuf->vb.v4l2_buf.timestamp);
+               fbuf->vb.v4l2_buf.sequence = dev->sequence++;
+               vb2_buffer_done(&fbuf->vb, VB2_BUF_STATE_DONE);
+       }
+skip:
+       usb_submit_urb(urb, GFP_ATOMIC);
+}
+
+static int hackrf_kill_urbs(struct hackrf_dev *dev)
+{
+       int i;
+
+       for (i = dev->urbs_submitted - 1; i >= 0; i--) {
+               dev_dbg(dev->dev, "kill urb=%d\n", i);
+               /* stop the URB */
+               usb_kill_urb(dev->urb_list[i]);
+       }
+       dev->urbs_submitted = 0;
+
+       return 0;
+}
+
+static int hackrf_submit_urbs(struct hackrf_dev *dev)
+{
+       int i, ret;
+
+       for (i = 0; i < dev->urbs_initialized; i++) {
+               dev_dbg(dev->dev, "submit urb=%d\n", i);
+               ret = usb_submit_urb(dev->urb_list[i], GFP_ATOMIC);
+               if (ret) {
+                       dev_err(dev->dev, "Could not submit URB no. %d - get them all back\n",
+                                       i);
+                       hackrf_kill_urbs(dev);
+                       return ret;
+               }
+               dev->urbs_submitted++;
+       }
+
+       return 0;
+}
+
+static int hackrf_free_stream_bufs(struct hackrf_dev *dev)
+{
+       if (dev->flags & USB_STATE_URB_BUF) {
+               while (dev->buf_num) {
+                       dev->buf_num--;
+                       dev_dbg(dev->dev, "free buf=%d\n", dev->buf_num);
+                       usb_free_coherent(dev->udev, dev->buf_size,
+                                         dev->buf_list[dev->buf_num],
+                                         dev->dma_addr[dev->buf_num]);
+               }
+       }
+       dev->flags &= ~USB_STATE_URB_BUF;
+
+       return 0;
+}
+
+static int hackrf_alloc_stream_bufs(struct hackrf_dev *dev)
+{
+       dev->buf_num = 0;
+       dev->buf_size = BULK_BUFFER_SIZE;
+
+       dev_dbg(dev->dev, "all in all I will use %u bytes for streaming\n",
+                       MAX_BULK_BUFS * BULK_BUFFER_SIZE);
+
+       for (dev->buf_num = 0; dev->buf_num < MAX_BULK_BUFS; dev->buf_num++) {
+               dev->buf_list[dev->buf_num] = usb_alloc_coherent(dev->udev,
+                               BULK_BUFFER_SIZE, GFP_ATOMIC,
+                               &dev->dma_addr[dev->buf_num]);
+               if (!dev->buf_list[dev->buf_num]) {
+                       dev_dbg(dev->dev, "alloc buf=%d failed\n",
+                                       dev->buf_num);
+                       hackrf_free_stream_bufs(dev);
+                       return -ENOMEM;
+               }
+
+               dev_dbg(dev->dev, "alloc buf=%d %p (dma %llu)\n", dev->buf_num,
+                               dev->buf_list[dev->buf_num],
+                               (long long)dev->dma_addr[dev->buf_num]);
+               dev->flags |= USB_STATE_URB_BUF;
+       }
+
+       return 0;
+}
+
+static int hackrf_free_urbs(struct hackrf_dev *dev)
+{
+       int i;
+
+       hackrf_kill_urbs(dev);
+
+       for (i = dev->urbs_initialized - 1; i >= 0; i--) {
+               if (dev->urb_list[i]) {
+                       dev_dbg(dev->dev, "free urb=%d\n", i);
+                       /* free the URBs */
+                       usb_free_urb(dev->urb_list[i]);
+               }
+       }
+       dev->urbs_initialized = 0;
+
+       return 0;
+}
+
+static int hackrf_alloc_urbs(struct hackrf_dev *dev)
+{
+       int i, j;
+
+       /* allocate the URBs */
+       for (i = 0; i < MAX_BULK_BUFS; i++) {
+               dev_dbg(dev->dev, "alloc urb=%d\n", i);
+               dev->urb_list[i] = usb_alloc_urb(0, GFP_ATOMIC);
+               if (!dev->urb_list[i]) {
+                       dev_dbg(dev->dev, "failed\n");
+                       for (j = 0; j < i; j++)
+                               usb_free_urb(dev->urb_list[j]);
+                       return -ENOMEM;
+               }
+               usb_fill_bulk_urb(dev->urb_list[i],
+                               dev->udev,
+                               usb_rcvbulkpipe(dev->udev, 0x81),
+                               dev->buf_list[i],
+                               BULK_BUFFER_SIZE,
+                               hackrf_urb_complete, dev);
+
+               dev->urb_list[i]->transfer_flags = URB_NO_TRANSFER_DMA_MAP;
+               dev->urb_list[i]->transfer_dma = dev->dma_addr[i];
+               dev->urbs_initialized++;
+       }
+
+       return 0;
+}
+
+/* Must be called with vb_queue_lock hold */
+static void hackrf_cleanup_queued_bufs(struct hackrf_dev *dev)
+{
+       unsigned long flags;
+
+       dev_dbg(dev->dev, "\n");
+
+       spin_lock_irqsave(&dev->queued_bufs_lock, flags);
+       while (!list_empty(&dev->queued_bufs)) {
+               struct hackrf_frame_buf *buf;
+
+               buf = list_entry(dev->queued_bufs.next,
+                               struct hackrf_frame_buf, list);
+               list_del(&buf->list);
+               vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR);
+       }
+       spin_unlock_irqrestore(&dev->queued_bufs_lock, flags);
+}
+
+/* The user yanked out the cable... */
+static void hackrf_disconnect(struct usb_interface *intf)
+{
+       struct v4l2_device *v = usb_get_intfdata(intf);
+       struct hackrf_dev *dev = container_of(v, struct hackrf_dev, v4l2_dev);
+
+       dev_dbg(dev->dev, "\n");
+
+       mutex_lock(&dev->vb_queue_lock);
+       mutex_lock(&dev->v4l2_lock);
+       /* No need to keep the urbs around after disconnection */
+       dev->udev = NULL;
+       v4l2_device_disconnect(&dev->v4l2_dev);
+       video_unregister_device(&dev->vdev);
+       mutex_unlock(&dev->v4l2_lock);
+       mutex_unlock(&dev->vb_queue_lock);
+
+       v4l2_device_put(&dev->v4l2_dev);
+}
+
+/* Videobuf2 operations */
+static int hackrf_queue_setup(struct vb2_queue *vq,
+               const struct v4l2_format *fmt, unsigned int *nbuffers,
+               unsigned int *nplanes, unsigned int sizes[], void *alloc_ctxs[])
+{
+       struct hackrf_dev *dev = vb2_get_drv_priv(vq);
+
+       dev_dbg(dev->dev, "nbuffers=%d\n", *nbuffers);
+
+       /* Need at least 8 buffers */
+       if (vq->num_buffers + *nbuffers < 8)
+               *nbuffers = 8 - vq->num_buffers;
+       *nplanes = 1;
+       sizes[0] = PAGE_ALIGN(dev->buffersize);
+
+       dev_dbg(dev->dev, "nbuffers=%d sizes[0]=%d\n", *nbuffers, sizes[0]);
+       return 0;
+}
+
+static void hackrf_buf_queue(struct vb2_buffer *vb)
+{
+       struct hackrf_dev *dev = vb2_get_drv_priv(vb->vb2_queue);
+       struct hackrf_frame_buf *buf =
+                       container_of(vb, struct hackrf_frame_buf, vb);
+       unsigned long flags;
+
+       spin_lock_irqsave(&dev->queued_bufs_lock, flags);
+       list_add_tail(&buf->list, &dev->queued_bufs);
+       spin_unlock_irqrestore(&dev->queued_bufs_lock, flags);
+}
+
+static int hackrf_start_streaming(struct vb2_queue *vq, unsigned int count)
+{
+       struct hackrf_dev *dev = vb2_get_drv_priv(vq);
+       int ret;
+
+       dev_dbg(dev->dev, "\n");
+
+       if (!dev->udev)
+               return -ENODEV;
+
+       mutex_lock(&dev->v4l2_lock);
+
+       dev->sequence = 0;
+
+       set_bit(POWER_ON, &dev->flags);
+
+       ret = hackrf_alloc_stream_bufs(dev);
+       if (ret)
+               goto err;
+
+       ret = hackrf_alloc_urbs(dev);
+       if (ret)
+               goto err;
+
+       ret = hackrf_submit_urbs(dev);
+       if (ret)
+               goto err;
+
+       /* start hardware streaming */
+       ret = hackrf_ctrl_msg(dev, CMD_SET_TRANSCEIVER_MODE, 1, 0, NULL, 0);
+       if (ret)
+               goto err;
+
+       goto exit_mutex_unlock;
+err:
+       hackrf_kill_urbs(dev);
+       hackrf_free_urbs(dev);
+       hackrf_free_stream_bufs(dev);
+       clear_bit(POWER_ON, &dev->flags);
+
+       /* return all queued buffers to vb2 */
+       {
+               struct hackrf_frame_buf *buf, *tmp;
+
+               list_for_each_entry_safe(buf, tmp, &dev->queued_bufs, list) {
+                       list_del(&buf->list);
+                       vb2_buffer_done(&buf->vb, VB2_BUF_STATE_QUEUED);
+               }
+       }
+
+exit_mutex_unlock:
+       mutex_unlock(&dev->v4l2_lock);
+
+       return ret;
+}
+
+static void hackrf_stop_streaming(struct vb2_queue *vq)
+{
+       struct hackrf_dev *dev = vb2_get_drv_priv(vq);
+
+       dev_dbg(dev->dev, "\n");
+
+       mutex_lock(&dev->v4l2_lock);
+
+       /* stop hardware streaming */
+       hackrf_ctrl_msg(dev, CMD_SET_TRANSCEIVER_MODE, 0, 0, NULL, 0);
+
+       hackrf_kill_urbs(dev);
+       hackrf_free_urbs(dev);
+       hackrf_free_stream_bufs(dev);
+
+       hackrf_cleanup_queued_bufs(dev);
+
+       clear_bit(POWER_ON, &dev->flags);
+
+       mutex_unlock(&dev->v4l2_lock);
+}
+
+static struct vb2_ops hackrf_vb2_ops = {
+       .queue_setup            = hackrf_queue_setup,
+       .buf_queue              = hackrf_buf_queue,
+       .start_streaming        = hackrf_start_streaming,
+       .stop_streaming         = hackrf_stop_streaming,
+       .wait_prepare           = vb2_ops_wait_prepare,
+       .wait_finish            = vb2_ops_wait_finish,
+};
+
+static int hackrf_querycap(struct file *file, void *fh,
+               struct v4l2_capability *cap)
+{
+       struct hackrf_dev *dev = video_drvdata(file);
+
+       dev_dbg(dev->dev, "\n");
+
+       strlcpy(cap->driver, KBUILD_MODNAME, sizeof(cap->driver));
+       strlcpy(cap->card, dev->vdev.name, sizeof(cap->card));
+       usb_make_path(dev->udev, cap->bus_info, sizeof(cap->bus_info));
+       cap->device_caps = V4L2_CAP_SDR_CAPTURE | V4L2_CAP_STREAMING |
+                       V4L2_CAP_READWRITE | V4L2_CAP_TUNER;
+       cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
+
+       return 0;
+}
+
+static int hackrf_s_fmt_sdr_cap(struct file *file, void *priv,
+               struct v4l2_format *f)
+{
+       struct hackrf_dev *dev = video_drvdata(file);
+       struct vb2_queue *q = &dev->vb_queue;
+       int i;
+
+       dev_dbg(dev->dev, "pixelformat fourcc %4.4s\n",
+                       (char *)&f->fmt.sdr.pixelformat);
+
+       if (vb2_is_busy(q))
+               return -EBUSY;
+
+       memset(f->fmt.sdr.reserved, 0, sizeof(f->fmt.sdr.reserved));
+       for (i = 0; i < NUM_FORMATS; i++) {
+               if (f->fmt.sdr.pixelformat == formats[i].pixelformat) {
+                       dev->pixelformat = formats[i].pixelformat;
+                       dev->buffersize = formats[i].buffersize;
+                       f->fmt.sdr.buffersize = formats[i].buffersize;
+                       return 0;
+               }
+       }
+
+       dev->pixelformat = formats[0].pixelformat;
+       dev->buffersize = formats[0].buffersize;
+       f->fmt.sdr.pixelformat = formats[0].pixelformat;
+       f->fmt.sdr.buffersize = formats[0].buffersize;
+
+       return 0;
+}
+
+static int hackrf_g_fmt_sdr_cap(struct file *file, void *priv,
+               struct v4l2_format *f)
+{
+       struct hackrf_dev *dev = video_drvdata(file);
+
+       dev_dbg(dev->dev, "pixelformat fourcc %4.4s\n",
+                       (char *)&dev->pixelformat);
+
+       memset(f->fmt.sdr.reserved, 0, sizeof(f->fmt.sdr.reserved));
+       f->fmt.sdr.pixelformat = dev->pixelformat;
+       f->fmt.sdr.buffersize = dev->buffersize;
+
+       return 0;
+}
+
+static int hackrf_try_fmt_sdr_cap(struct file *file, void *priv,
+               struct v4l2_format *f)
+{
+       struct hackrf_dev *dev = video_drvdata(file);
+       int i;
+
+       dev_dbg(dev->dev, "pixelformat fourcc %4.4s\n",
+                       (char *)&f->fmt.sdr.pixelformat);
+
+       memset(f->fmt.sdr.reserved, 0, sizeof(f->fmt.sdr.reserved));
+       for (i = 0; i < NUM_FORMATS; i++) {
+               if (formats[i].pixelformat == f->fmt.sdr.pixelformat) {
+                       f->fmt.sdr.buffersize = formats[i].buffersize;
+                       return 0;
+               }
+       }
+
+       f->fmt.sdr.pixelformat = formats[0].pixelformat;
+       f->fmt.sdr.buffersize = formats[0].buffersize;
+
+       return 0;
+}
+
+static int hackrf_enum_fmt_sdr_cap(struct file *file, void *priv,
+               struct v4l2_fmtdesc *f)
+{
+       struct hackrf_dev *dev = video_drvdata(file);
+
+       dev_dbg(dev->dev, "index=%d\n", f->index);
+
+       if (f->index >= NUM_FORMATS)
+               return -EINVAL;
+
+       strlcpy(f->description, formats[f->index].name, sizeof(f->description));
+       f->pixelformat = formats[f->index].pixelformat;
+
+       return 0;
+}
+
+static int hackrf_s_tuner(struct file *file, void *priv,
+               const struct v4l2_tuner *v)
+{
+       struct hackrf_dev *dev = video_drvdata(file);
+       int ret;
+
+       dev_dbg(dev->dev, "index=%d\n", v->index);
+
+       if (v->index == 0)
+               ret = 0;
+       else if (v->index == 1)
+               ret = 0;
+       else
+               ret = -EINVAL;
+
+       return ret;
+}
+
+static int hackrf_g_tuner(struct file *file, void *priv, struct v4l2_tuner *v)
+{
+       struct hackrf_dev *dev = video_drvdata(file);
+       int ret;
+
+       dev_dbg(dev->dev, "index=%d\n", v->index);
+
+       if (v->index == 0) {
+               strlcpy(v->name, "HackRF ADC", sizeof(v->name));
+               v->type = V4L2_TUNER_ADC;
+               v->capability = V4L2_TUNER_CAP_1HZ | V4L2_TUNER_CAP_FREQ_BANDS;
+               v->rangelow  = bands_adc[0].rangelow;
+               v->rangehigh = bands_adc[0].rangehigh;
+               ret = 0;
+       } else if (v->index == 1) {
+               strlcpy(v->name, "HackRF RF", sizeof(v->name));
+               v->type = V4L2_TUNER_RF;
+               v->capability = V4L2_TUNER_CAP_1HZ | V4L2_TUNER_CAP_FREQ_BANDS;
+               v->rangelow  = bands_rf[0].rangelow;
+               v->rangehigh = bands_rf[0].rangehigh;
+               ret = 0;
+       } else {
+               ret = -EINVAL;
+       }
+
+       return ret;
+}
+
+static int hackrf_s_frequency(struct file *file, void *priv,
+               const struct v4l2_frequency *f)
+{
+       struct hackrf_dev *dev = video_drvdata(file);
+       int ret;
+       unsigned int upper, lower;
+       u8 buf[8];
+
+       dev_dbg(dev->dev, "tuner=%d type=%d frequency=%u\n",
+                       f->tuner, f->type, f->frequency);
+
+       if (f->tuner == 0) {
+               dev->f_adc = clamp_t(unsigned int, f->frequency,
+                               bands_adc[0].rangelow, bands_adc[0].rangehigh);
+               dev_dbg(dev->dev, "ADC frequency=%u Hz\n", dev->f_adc);
+               upper = dev->f_adc;
+               lower = 1;
+               buf[0] = (upper >>  0) & 0xff;
+               buf[1] = (upper >>  8) & 0xff;
+               buf[2] = (upper >> 16) & 0xff;
+               buf[3] = (upper >> 24) & 0xff;
+               buf[4] = (lower >>  0) & 0xff;
+               buf[5] = (lower >>  8) & 0xff;
+               buf[6] = (lower >> 16) & 0xff;
+               buf[7] = (lower >> 24) & 0xff;
+               ret = hackrf_ctrl_msg(dev, CMD_SAMPLE_RATE_SET, 0, 0, buf, 8);
+       } else if (f->tuner == 1) {
+               dev->f_rf = clamp_t(unsigned int, f->frequency,
+                               bands_rf[0].rangelow, bands_rf[0].rangehigh);
+               dev_dbg(dev->dev, "RF frequency=%u Hz\n", dev->f_rf);
+               upper = dev->f_rf / 1000000;
+               lower = dev->f_rf % 1000000;
+               buf[0] = (upper >>  0) & 0xff;
+               buf[1] = (upper >>  8) & 0xff;
+               buf[2] = (upper >> 16) & 0xff;
+               buf[3] = (upper >> 24) & 0xff;
+               buf[4] = (lower >>  0) & 0xff;
+               buf[5] = (lower >>  8) & 0xff;
+               buf[6] = (lower >> 16) & 0xff;
+               buf[7] = (lower >> 24) & 0xff;
+               ret = hackrf_ctrl_msg(dev, CMD_SET_FREQ, 0, 0, buf, 8);
+       } else {
+               ret = -EINVAL;
+       }
+
+       return ret;
+}
+
+static int hackrf_g_frequency(struct file *file, void *priv,
+               struct v4l2_frequency *f)
+{
+       struct hackrf_dev *dev = video_drvdata(file);
+       int ret;
+
+       dev_dbg(dev->dev, "tuner=%d type=%d\n", f->tuner, f->type);
+
+       if (f->tuner == 0) {
+               f->type = V4L2_TUNER_ADC;
+               f->frequency = dev->f_adc;
+               ret = 0;
+       } else if (f->tuner == 1) {
+               f->type = V4L2_TUNER_RF;
+               f->frequency = dev->f_rf;
+               ret = 0;
+       } else {
+               ret = -EINVAL;
+       }
+
+       return ret;
+}
+
+static int hackrf_enum_freq_bands(struct file *file, void *priv,
+               struct v4l2_frequency_band *band)
+{
+       struct hackrf_dev *dev = video_drvdata(file);
+       int ret;
+
+       dev_dbg(dev->dev, "tuner=%d type=%d index=%d\n",
+                       band->tuner, band->type, band->index);
+
+       if (band->tuner == 0) {
+               if (band->index >= ARRAY_SIZE(bands_adc)) {
+                       ret = -EINVAL;
+               } else {
+                       *band = bands_adc[band->index];
+                       ret = 0;
+               }
+       } else if (band->tuner == 1) {
+               if (band->index >= ARRAY_SIZE(bands_rf)) {
+                       ret = -EINVAL;
+               } else {
+                       *band = bands_rf[band->index];
+                       ret = 0;
+               }
+       } else {
+               ret = -EINVAL;
+       }
+
+       return ret;
+}
+
+static const struct v4l2_ioctl_ops hackrf_ioctl_ops = {
+       .vidioc_querycap          = hackrf_querycap,
+
+       .vidioc_s_fmt_sdr_cap     = hackrf_s_fmt_sdr_cap,
+       .vidioc_g_fmt_sdr_cap     = hackrf_g_fmt_sdr_cap,
+       .vidioc_enum_fmt_sdr_cap  = hackrf_enum_fmt_sdr_cap,
+       .vidioc_try_fmt_sdr_cap   = hackrf_try_fmt_sdr_cap,
+
+       .vidioc_reqbufs           = vb2_ioctl_reqbufs,
+       .vidioc_create_bufs       = vb2_ioctl_create_bufs,
+       .vidioc_prepare_buf       = vb2_ioctl_prepare_buf,
+       .vidioc_querybuf          = vb2_ioctl_querybuf,
+       .vidioc_qbuf              = vb2_ioctl_qbuf,
+       .vidioc_dqbuf             = vb2_ioctl_dqbuf,
+
+       .vidioc_streamon          = vb2_ioctl_streamon,
+       .vidioc_streamoff         = vb2_ioctl_streamoff,
+
+       .vidioc_s_tuner           = hackrf_s_tuner,
+       .vidioc_g_tuner           = hackrf_g_tuner,
+
+       .vidioc_s_frequency       = hackrf_s_frequency,
+       .vidioc_g_frequency       = hackrf_g_frequency,
+       .vidioc_enum_freq_bands   = hackrf_enum_freq_bands,
+
+       .vidioc_subscribe_event   = v4l2_ctrl_subscribe_event,
+       .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
+       .vidioc_log_status        = v4l2_ctrl_log_status,
+};
+
+static const struct v4l2_file_operations hackrf_fops = {
+       .owner                    = THIS_MODULE,
+       .open                     = v4l2_fh_open,
+       .release                  = vb2_fop_release,
+       .read                     = vb2_fop_read,
+       .poll                     = vb2_fop_poll,
+       .mmap                     = vb2_fop_mmap,
+       .unlocked_ioctl           = video_ioctl2,
+};
+
+static struct video_device hackrf_template = {
+       .name                     = "HackRF One",
+       .release                  = video_device_release_empty,
+       .fops                     = &hackrf_fops,
+       .ioctl_ops                = &hackrf_ioctl_ops,
+};
+
+static void hackrf_video_release(struct v4l2_device *v)
+{
+       struct hackrf_dev *dev = container_of(v, struct hackrf_dev, v4l2_dev);
+
+       v4l2_ctrl_handler_free(&dev->hdl);
+       v4l2_device_unregister(&dev->v4l2_dev);
+       kfree(dev);
+}
+
+static int hackrf_set_bandwidth(struct hackrf_dev *dev)
+{
+       int ret, i;
+       u16 u16tmp, u16tmp2;
+       unsigned int bandwidth;
+
+       static const struct {
+               u32 freq;
+       } bandwidth_lut[] = {
+               { 1750000}, /*  1.75 MHz */
+               { 2500000}, /*  2.5  MHz */
+               { 3500000}, /*  3.5  MHz */
+               { 5000000}, /*  5    MHz */
+               { 5500000}, /*  5.5  MHz */
+               { 6000000}, /*  6    MHz */
+               { 7000000}, /*  7    MHz */
+               { 8000000}, /*  8    MHz */
+               { 9000000}, /*  9    MHz */
+               {10000000}, /* 10    MHz */
+               {12000000}, /* 12    MHz */
+               {14000000}, /* 14    MHz */
+               {15000000}, /* 15    MHz */
+               {20000000}, /* 20    MHz */
+               {24000000}, /* 24    MHz */
+               {28000000}, /* 28    MHz */
+       };
+
+       dev_dbg(dev->dev, "bandwidth auto=%d->%d val=%d->%d f_adc=%u\n",
+                       dev->bandwidth_auto->cur.val,
+                       dev->bandwidth_auto->val, dev->bandwidth->cur.val,
+                       dev->bandwidth->val, dev->f_adc);
+
+       if (dev->bandwidth_auto->val == true)
+               bandwidth = dev->f_adc;
+       else
+               bandwidth = dev->bandwidth->val;
+
+       for (i = 0; i < ARRAY_SIZE(bandwidth_lut); i++) {
+               if (bandwidth <= bandwidth_lut[i].freq) {
+                       bandwidth = bandwidth_lut[i].freq;
+                       break;
+               }
+       }
+
+       dev->bandwidth->val = bandwidth;
+       dev->bandwidth->cur.val = bandwidth;
+
+       dev_dbg(dev->dev, "bandwidth selected=%d\n", bandwidth_lut[i].freq);
+
+       u16tmp = 0;
+       u16tmp |= ((bandwidth >> 0) & 0xff) << 0;
+       u16tmp |= ((bandwidth >> 8) & 0xff) << 8;
+       u16tmp2 = 0;
+       u16tmp2 |= ((bandwidth >> 16) & 0xff) << 0;
+       u16tmp2 |= ((bandwidth >> 24) & 0xff) << 8;
+
+       ret = hackrf_ctrl_msg(dev, CMD_BASEBAND_FILTER_BANDWIDTH_SET,
+                               u16tmp, u16tmp2, NULL, 0);
+       if (ret)
+               dev_dbg(dev->dev, "failed=%d\n", ret);
+
+       return ret;
+}
+
+static int hackrf_set_lna_gain(struct hackrf_dev *dev)
+{
+       int ret;
+       u8 u8tmp;
+
+       dev_dbg(dev->dev, "lna val=%d->%d\n",
+                       dev->lna_gain->cur.val, dev->lna_gain->val);
+
+       ret = hackrf_ctrl_msg(dev, CMD_SET_LNA_GAIN, 0, dev->lna_gain->val,
+                       &u8tmp, 1);
+       if (ret)
+               dev_dbg(dev->dev, "failed=%d\n", ret);
+
+       return ret;
+}
+
+static int hackrf_set_if_gain(struct hackrf_dev *dev)
+{
+       int ret;
+       u8 u8tmp;
+
+       dev_dbg(dev->dev, "val=%d->%d\n",
+                       dev->if_gain->cur.val, dev->if_gain->val);
+
+       ret = hackrf_ctrl_msg(dev, CMD_SET_VGA_GAIN, 0, dev->if_gain->val,
+                       &u8tmp, 1);
+       if (ret)
+               dev_dbg(dev->dev, "failed=%d\n", ret);
+
+       return ret;
+}
+
+static int hackrf_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+       struct hackrf_dev *dev = container_of(ctrl->handler,
+                       struct hackrf_dev, hdl);
+       int ret;
+
+       switch (ctrl->id) {
+       case V4L2_CID_RF_TUNER_BANDWIDTH_AUTO:
+       case V4L2_CID_RF_TUNER_BANDWIDTH:
+               ret = hackrf_set_bandwidth(dev);
+               break;
+       case  V4L2_CID_RF_TUNER_LNA_GAIN:
+               ret = hackrf_set_lna_gain(dev);
+               break;
+       case  V4L2_CID_RF_TUNER_IF_GAIN:
+               ret = hackrf_set_if_gain(dev);
+               break;
+       default:
+               dev_dbg(dev->dev, "unknown ctrl: id=%d name=%s\n",
+                               ctrl->id, ctrl->name);
+               ret = -EINVAL;
+       }
+
+       return ret;
+}
+
+static const struct v4l2_ctrl_ops hackrf_ctrl_ops = {
+       .s_ctrl = hackrf_s_ctrl,
+};
+
+static int hackrf_probe(struct usb_interface *intf,
+               const struct usb_device_id *id)
+{
+       struct hackrf_dev *dev;
+       int ret;
+       u8 u8tmp, buf[BUF_SIZE];
+
+       dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+       if (dev == NULL)
+               return -ENOMEM;
+
+       mutex_init(&dev->v4l2_lock);
+       mutex_init(&dev->vb_queue_lock);
+       spin_lock_init(&dev->queued_bufs_lock);
+       INIT_LIST_HEAD(&dev->queued_bufs);
+       dev->dev = &intf->dev;
+       dev->udev = interface_to_usbdev(intf);
+       dev->f_adc = bands_adc[0].rangelow;
+       dev->f_rf = bands_rf[0].rangelow;
+       dev->pixelformat = formats[0].pixelformat;
+       dev->buffersize = formats[0].buffersize;
+
+       /* Detect device */
+       ret = hackrf_ctrl_msg(dev, CMD_BOARD_ID_READ, 0, 0, &u8tmp, 1);
+       if (ret == 0)
+               ret = hackrf_ctrl_msg(dev, CMD_VERSION_STRING_READ, 0, 0,
+                               buf, BUF_SIZE);
+       if (ret) {
+               dev_err(dev->dev, "Could not detect board\n");
+               goto err_free_mem;
+       }
+
+       buf[BUF_SIZE - 1] = '\0';
+
+       dev_info(dev->dev, "Board ID: %02x\n", u8tmp);
+       dev_info(dev->dev, "Firmware version: %s\n", buf);
+
+       /* Init videobuf2 queue structure */
+       dev->vb_queue.type = V4L2_BUF_TYPE_SDR_CAPTURE;
+       dev->vb_queue.io_modes = VB2_MMAP | VB2_USERPTR | VB2_READ;
+       dev->vb_queue.drv_priv = dev;
+       dev->vb_queue.buf_struct_size = sizeof(struct hackrf_frame_buf);
+       dev->vb_queue.ops = &hackrf_vb2_ops;
+       dev->vb_queue.mem_ops = &vb2_vmalloc_memops;
+       dev->vb_queue.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
+       ret = vb2_queue_init(&dev->vb_queue);
+       if (ret) {
+               dev_err(dev->dev, "Could not initialize vb2 queue\n");
+               goto err_free_mem;
+       }
+
+       /* Init video_device structure */
+       dev->vdev = hackrf_template;
+       dev->vdev.queue = &dev->vb_queue;
+       dev->vdev.queue->lock = &dev->vb_queue_lock;
+       video_set_drvdata(&dev->vdev, dev);
+
+       /* Register the v4l2_device structure */
+       dev->v4l2_dev.release = hackrf_video_release;
+       ret = v4l2_device_register(&intf->dev, &dev->v4l2_dev);
+       if (ret) {
+               dev_err(dev->dev, "Failed to register v4l2-device (%d)\n", ret);
+               goto err_free_mem;
+       }
+
+       /* Register controls */
+       v4l2_ctrl_handler_init(&dev->hdl, 4);
+       dev->bandwidth_auto = v4l2_ctrl_new_std(&dev->hdl, &hackrf_ctrl_ops,
+                       V4L2_CID_RF_TUNER_BANDWIDTH_AUTO, 0, 1, 1, 1);
+       dev->bandwidth = v4l2_ctrl_new_std(&dev->hdl, &hackrf_ctrl_ops,
+                       V4L2_CID_RF_TUNER_BANDWIDTH,
+                       1750000, 28000000, 50000, 1750000);
+       v4l2_ctrl_auto_cluster(2, &dev->bandwidth_auto, 0, false);
+       dev->lna_gain = v4l2_ctrl_new_std(&dev->hdl, &hackrf_ctrl_ops,
+                       V4L2_CID_RF_TUNER_LNA_GAIN, 0, 40, 8, 0);
+       dev->if_gain = v4l2_ctrl_new_std(&dev->hdl, &hackrf_ctrl_ops,
+                       V4L2_CID_RF_TUNER_IF_GAIN, 0, 62, 2, 0);
+       if (dev->hdl.error) {
+               ret = dev->hdl.error;
+               dev_err(dev->dev, "Could not initialize controls\n");
+               goto err_free_controls;
+       }
+
+       v4l2_ctrl_handler_setup(&dev->hdl);
+
+       dev->v4l2_dev.ctrl_handler = &dev->hdl;
+       dev->vdev.v4l2_dev = &dev->v4l2_dev;
+       dev->vdev.lock = &dev->v4l2_lock;
+
+       ret = video_register_device(&dev->vdev, VFL_TYPE_SDR, -1);
+       if (ret) {
+               dev_err(dev->dev, "Failed to register as video device (%d)\n",
+                               ret);
+               goto err_unregister_v4l2_dev;
+       }
+       dev_info(dev->dev, "Registered as %s\n",
+                       video_device_node_name(&dev->vdev));
+       dev_notice(dev->dev, "SDR API is still slightly experimental and functionality changes may follow\n");
+       return 0;
+
+err_free_controls:
+       v4l2_ctrl_handler_free(&dev->hdl);
+err_unregister_v4l2_dev:
+       v4l2_device_unregister(&dev->v4l2_dev);
+err_free_mem:
+       kfree(dev);
+       return ret;
+}
+
+/* USB device ID list */
+static struct usb_device_id hackrf_id_table[] = {
+       { USB_DEVICE(0x1d50, 0x6089) }, /* HackRF One */
+       { }
+};
+MODULE_DEVICE_TABLE(usb, hackrf_id_table);
+
+/* USB subsystem interface */
+static struct usb_driver hackrf_driver = {
+       .name                     = KBUILD_MODNAME,
+       .probe                    = hackrf_probe,
+       .disconnect               = hackrf_disconnect,
+       .id_table                 = hackrf_id_table,
+};
+
+module_usb_driver(hackrf_driver);
+
+MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
+MODULE_DESCRIPTION("HackRF");
+MODULE_LICENSE("GPL");
index 6053661dc04bd39727021c311f7d80f1d37ca60a..6e86032ea5dba481e41fa1713852ce05cb120f67 100644 (file)
@@ -59,13 +59,10 @@ int get_video_info(struct hdpvr_device *dev, struct hdpvr_video_info *vidinf)
                              1000);
 
 #ifdef HDPVR_DEBUG
-       if (hdpvr_debug & MSG_INFO) {
-               char print_buf[15];
-               hex_dump_to_buffer(dev->usbc_buf, 5, 16, 1, print_buf,
-                                  sizeof(print_buf), 0);
+       if (hdpvr_debug & MSG_INFO)
                v4l2_dbg(MSG_INFO, hdpvr_debug, &dev->v4l2_dev,
-                        "get video info returned: %d, %s\n", ret, print_buf);
-       }
+                        "get video info returned: %d, %5ph\n", ret,
+                        dev->usbc_buf);
 #endif
        mutex_unlock(&dev->usbc_mutex);
 
@@ -82,9 +79,6 @@ int get_video_info(struct hdpvr_device *dev, struct hdpvr_video_info *vidinf)
 
 int get_input_lines_info(struct hdpvr_device *dev)
 {
-#ifdef HDPVR_DEBUG
-       char print_buf[9];
-#endif
        int ret, lines;
 
        mutex_lock(&dev->usbc_mutex);
@@ -96,13 +90,10 @@ int get_input_lines_info(struct hdpvr_device *dev)
                              1000);
 
 #ifdef HDPVR_DEBUG
-       if (hdpvr_debug & MSG_INFO) {
-               hex_dump_to_buffer(dev->usbc_buf, 3, 16, 1, print_buf,
-                                  sizeof(print_buf), 0);
+       if (hdpvr_debug & MSG_INFO)
                v4l2_dbg(MSG_INFO, hdpvr_debug, &dev->v4l2_dev,
-                        "get input lines info returned: %d, %s\n", ret,
-                        print_buf);
-       }
+                        "get input lines info returned: %d, %3ph\n", ret,
+                        dev->usbc_buf);
 #else
        (void)ret;      /* suppress compiler warning */
 #endif
index c5638964c3f286665e0cd57ae1e713be0506e881..42b4cdf28cfd9d24e89e38a7ca3eb84a0354b57e 100644 (file)
@@ -124,14 +124,6 @@ static int device_authorization(struct hdpvr_device *dev)
        int ret, retval = -ENOMEM;
        char request_type = 0x38, rcv_request = 0x81;
        char *response;
-#ifdef HDPVR_DEBUG
-       size_t buf_size = 46;
-       char *print_buf = kzalloc(5*buf_size+1, GFP_KERNEL);
-       if (!print_buf) {
-               v4l2_err(&dev->v4l2_dev, "Out of memory\n");
-               return retval;
-       }
-#endif
 
        mutex_lock(&dev->usbc_mutex);
        ret = usb_control_msg(dev->udev,
@@ -147,11 +139,9 @@ static int device_authorization(struct hdpvr_device *dev)
        }
 #ifdef HDPVR_DEBUG
        else {
-               hex_dump_to_buffer(dev->usbc_buf, 46, 16, 1, print_buf,
-                                  5*buf_size+1, 0);
                v4l2_dbg(MSG_INFO, hdpvr_debug, &dev->v4l2_dev,
-                        "Status request returned, len %d: %s\n",
-                        ret, print_buf);
+                        "Status request returned, len %d: %46ph\n",
+                        ret, dev->usbc_buf);
        }
 #endif
 
@@ -189,15 +179,13 @@ static int device_authorization(struct hdpvr_device *dev)
 
        response = dev->usbc_buf+38;
 #ifdef HDPVR_DEBUG
-       hex_dump_to_buffer(response, 8, 16, 1, print_buf, 5*buf_size+1, 0);
-       v4l2_dbg(MSG_INFO, hdpvr_debug, &dev->v4l2_dev, "challenge: %s\n",
-                print_buf);
+       v4l2_dbg(MSG_INFO, hdpvr_debug, &dev->v4l2_dev, "challenge: %8ph\n",
+                response);
 #endif
        challenge(response);
 #ifdef HDPVR_DEBUG
-       hex_dump_to_buffer(response, 8, 16, 1, print_buf, 5*buf_size+1, 0);
-       v4l2_dbg(MSG_INFO, hdpvr_debug, &dev->v4l2_dev, " response: %s\n",
-                print_buf);
+       v4l2_dbg(MSG_INFO, hdpvr_debug, &dev->v4l2_dev, " response: %8ph\n",
+                response);
 #endif
 
        msleep(100);
@@ -213,9 +201,6 @@ static int device_authorization(struct hdpvr_device *dev)
        retval = ret != 8;
 unlock:
        mutex_unlock(&dev->usbc_mutex);
-#ifdef HDPVR_DEBUG
-       kfree(print_buf);
-#endif
        return retval;
 }
 
index 26b133414032bcaf3f6b48a4da78f1809f9d4872..efc761c78f7250e5b27a93b0fcb18bbc3fb142a5 100644 (file)
@@ -120,6 +120,7 @@ struct msi2500_frame_buf {
 };
 
 struct msi2500_state {
+       struct device *dev;
        struct video_device vdev;
        struct v4l2_device v4l2_dev;
        struct v4l2_subdev *v4l2_subdev;
@@ -153,14 +154,13 @@ struct msi2500_state {
        u32 next_sample; /* for track lost packets */
        u32 sample; /* for sample rate calc */
        unsigned long jiffies_next;
-       unsigned int sample_ctrl_bit[4];
 };
 
 /* Private functions */
 static struct msi2500_frame_buf *msi2500_get_next_fill_buf(
                struct msi2500_state *s)
 {
-       unsigned long flags = 0;
+       unsigned long flags;
        struct msi2500_frame_buf *buf = NULL;
 
        spin_lock_irqsave(&s->queued_bufs_lock, flags);
@@ -269,7 +269,7 @@ static int msi2500_convert_stream(struct msi2500_state *s, u8 *dst, u8 *src,
                sample[i] = src[3] << 24 | src[2] << 16 | src[1] << 8 |
                                src[0] << 0;
                if (i == 0 && s->next_sample != sample[0]) {
-                       dev_dbg_ratelimited(&s->udev->dev,
+                       dev_dbg_ratelimited(s->dev,
                                        "%d samples lost, %d %08x:%08x\n",
                                        sample[0] - s->next_sample,
                                        src_len, s->next_sample, sample[0]);
@@ -279,7 +279,7 @@ static int msi2500_convert_stream(struct msi2500_state *s, u8 *dst, u8 *src,
                 * Dump all unknown 'garbage' data - maybe we will discover
                 * someday if there is something rational...
                 */
-               dev_dbg_ratelimited(&s->udev->dev, "%*ph\n", 12, &src[4]);
+               dev_dbg_ratelimited(s->dev, "%*ph\n", 12, &src[4]);
 
                src += 16; /* skip header */
 
@@ -322,8 +322,7 @@ static int msi2500_convert_stream(struct msi2500_state *s, u8 *dst, u8 *src,
                }
                case MSI2500_PIX_FMT_SDR_MSI2500_384: /* 384 x IQ samples */
                        /* Dump unknown 'garbage' data */
-                       dev_dbg_ratelimited(&s->udev->dev,
-                                       "%*ph\n", 24, &src[1000]);
+                       dev_dbg_ratelimited(s->dev, "%*ph\n", 24, &src[1000]);
                        memcpy(dst, src, 984);
                        src += 984 + 24;
                        dst += 984;
@@ -365,8 +364,7 @@ static int msi2500_convert_stream(struct msi2500_state *s, u8 *dst, u8 *src,
 
                s->jiffies_next = jiffies + msecs_to_jiffies(MSECS);
                s->sample = s->next_sample;
-               dev_dbg(&s->udev->dev,
-                               "size=%u samples=%u msecs=%u sample rate=%lu\n",
+               dev_dbg(s->dev, "size=%u samples=%u msecs=%u sample rate=%lu\n",
                                src_len, samples, msecs,
                                samples * 1000UL / msecs);
        }
@@ -387,19 +385,16 @@ static void msi2500_isoc_handler(struct urb *urb)
 
        if (unlikely(urb->status == -ENOENT || urb->status == -ECONNRESET ||
                        urb->status == -ESHUTDOWN)) {
-               dev_dbg(&s->udev->dev, "URB (%p) unlinked %ssynchronuously\n",
+               dev_dbg(s->dev, "URB (%p) unlinked %ssynchronuously\n",
                                urb, urb->status == -ENOENT ? "" : "a");
                return;
        }
 
        if (unlikely(urb->status != 0)) {
-               dev_dbg(&s->udev->dev,
-                               "msi2500_isoc_handler() called with status %d\n",
-                               urb->status);
+               dev_dbg(s->dev, "called with status %d\n", urb->status);
                /* Give up after a number of contiguous errors */
                if (++s->isoc_errors > MAX_ISOC_ERRORS)
-                       dev_dbg(&s->udev->dev,
-                                       "Too many ISOC errors, bailing out\n");
+                       dev_dbg(s->dev, "Too many ISOC errors, bailing out\n");
                goto handler_end;
        } else {
                /* Reset ISOC error counter. We did get here, after all. */
@@ -413,7 +408,7 @@ static void msi2500_isoc_handler(struct urb *urb)
                /* Check frame error */
                fstatus = urb->iso_frame_desc[i].status;
                if (unlikely(fstatus)) {
-                       dev_dbg_ratelimited(&s->udev->dev,
+                       dev_dbg_ratelimited(s->dev,
                                        "frame=%d/%d has error %d skipping\n",
                                        i, urb->number_of_packets, fstatus);
                        continue;
@@ -430,7 +425,7 @@ static void msi2500_isoc_handler(struct urb *urb)
                fbuf = msi2500_get_next_fill_buf(s);
                if (unlikely(fbuf == NULL)) {
                        s->vb_full++;
-                       dev_dbg_ratelimited(&s->udev->dev,
+                       dev_dbg_ratelimited(s->dev,
                                        "videobuf is full, %d packets dropped\n",
                                        s->vb_full);
                        continue;
@@ -446,22 +441,19 @@ static void msi2500_isoc_handler(struct urb *urb)
 handler_end:
        i = usb_submit_urb(urb, GFP_ATOMIC);
        if (unlikely(i != 0))
-               dev_dbg(&s->udev->dev,
-                               "Error (%d) re-submitting urb in msi2500_isoc_handler\n",
-                               i);
+               dev_dbg(s->dev, "Error (%d) re-submitting urb\n", i);
 }
 
 static void msi2500_iso_stop(struct msi2500_state *s)
 {
        int i;
 
-       dev_dbg(&s->udev->dev, "%s:\n", __func__);
+       dev_dbg(s->dev, "\n");
 
        /* Unlinking ISOC buffers one by one */
        for (i = 0; i < MAX_ISO_BUFS; i++) {
                if (s->urbs[i]) {
-                       dev_dbg(&s->udev->dev, "Unlinking URB %p\n",
-                                       s->urbs[i]);
+                       dev_dbg(s->dev, "Unlinking URB %p\n", s->urbs[i]);
                        usb_kill_urb(s->urbs[i]);
                }
        }
@@ -471,12 +463,12 @@ static void msi2500_iso_free(struct msi2500_state *s)
 {
        int i;
 
-       dev_dbg(&s->udev->dev, "%s:\n", __func__);
+       dev_dbg(s->dev, "\n");
 
        /* Freeing ISOC buffers one by one */
        for (i = 0; i < MAX_ISO_BUFS; i++) {
                if (s->urbs[i]) {
-                       dev_dbg(&s->udev->dev, "Freeing URB\n");
+                       dev_dbg(s->dev, "Freeing URB\n");
                        if (s->urbs[i]->transfer_buffer) {
                                usb_free_coherent(s->udev,
                                        s->urbs[i]->transfer_buffer_length,
@@ -492,7 +484,7 @@ static void msi2500_iso_free(struct msi2500_state *s)
 /* Both v4l2_lock and vb_queue_lock should be locked when calling this */
 static void msi2500_isoc_cleanup(struct msi2500_state *s)
 {
-       dev_dbg(&s->udev->dev, "%s:\n", __func__);
+       dev_dbg(s->dev, "\n");
 
        msi2500_iso_stop(s);
        msi2500_iso_free(s);
@@ -501,14 +493,12 @@ static void msi2500_isoc_cleanup(struct msi2500_state *s)
 /* Both v4l2_lock and vb_queue_lock should be locked when calling this */
 static int msi2500_isoc_init(struct msi2500_state *s)
 {
-       struct usb_device *udev;
        struct urb *urb;
        int i, j, ret;
 
-       dev_dbg(&s->udev->dev, "%s:\n", __func__);
+       dev_dbg(s->dev, "\n");
 
        s->isoc_errors = 0;
-       udev = s->udev;
 
        ret = usb_set_interface(s->udev, 0, 1);
        if (ret)
@@ -518,23 +508,22 @@ static int msi2500_isoc_init(struct msi2500_state *s)
        for (i = 0; i < MAX_ISO_BUFS; i++) {
                urb = usb_alloc_urb(ISO_FRAMES_PER_DESC, GFP_KERNEL);
                if (urb == NULL) {
-                       dev_err(&s->udev->dev,
-                                       "Failed to allocate urb %d\n", i);
+                       dev_err(s->dev, "Failed to allocate urb %d\n", i);
                        msi2500_isoc_cleanup(s);
                        return -ENOMEM;
                }
                s->urbs[i] = urb;
-               dev_dbg(&s->udev->dev, "Allocated URB at 0x%p\n", urb);
+               dev_dbg(s->dev, "Allocated URB at 0x%p\n", urb);
 
                urb->interval = 1;
-               urb->dev = udev;
-               urb->pipe = usb_rcvisocpipe(udev, 0x81);
+               urb->dev = s->udev;
+               urb->pipe = usb_rcvisocpipe(s->udev, 0x81);
                urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP;
-               urb->transfer_buffer = usb_alloc_coherent(udev, ISO_BUFFER_SIZE,
+               urb->transfer_buffer = usb_alloc_coherent(s->udev,
+                               ISO_BUFFER_SIZE,
                                GFP_KERNEL, &urb->transfer_dma);
                if (urb->transfer_buffer == NULL) {
-                       dev_err(&s->udev->dev,
-                                       "Failed to allocate urb buffer %d\n",
+                       dev_err(s->dev, "Failed to allocate urb buffer %d\n",
                                        i);
                        msi2500_isoc_cleanup(s);
                        return -ENOMEM;
@@ -554,13 +543,12 @@ static int msi2500_isoc_init(struct msi2500_state *s)
        for (i = 0; i < MAX_ISO_BUFS; i++) {
                ret = usb_submit_urb(s->urbs[i], GFP_KERNEL);
                if (ret) {
-                       dev_err(&s->udev->dev,
-                                       "isoc_init() submit_urb %d failed with error %d\n",
+                       dev_err(s->dev, "usb_submit_urb %d failed with error %d\n",
                                        i, ret);
                        msi2500_isoc_cleanup(s);
                        return ret;
                }
-               dev_dbg(&s->udev->dev, "URB 0x%p submitted.\n", s->urbs[i]);
+               dev_dbg(s->dev, "URB 0x%p submitted.\n", s->urbs[i]);
        }
 
        /* All is done... */
@@ -570,9 +558,9 @@ static int msi2500_isoc_init(struct msi2500_state *s)
 /* Must be called with vb_queue_lock hold */
 static void msi2500_cleanup_queued_bufs(struct msi2500_state *s)
 {
-       unsigned long flags = 0;
+       unsigned long flags;
 
-       dev_dbg(&s->udev->dev, "%s:\n", __func__);
+       dev_dbg(s->dev, "\n");
 
        spin_lock_irqsave(&s->queued_bufs_lock, flags);
        while (!list_empty(&s->queued_bufs)) {
@@ -593,7 +581,7 @@ static void msi2500_disconnect(struct usb_interface *intf)
        struct msi2500_state *s =
                        container_of(v, struct msi2500_state, v4l2_dev);
 
-       dev_dbg(&s->udev->dev, "%s:\n", __func__);
+       dev_dbg(s->dev, "\n");
 
        mutex_lock(&s->vb_queue_lock);
        mutex_lock(&s->v4l2_lock);
@@ -613,7 +601,7 @@ static int msi2500_querycap(struct file *file, void *fh,
 {
        struct msi2500_state *s = video_drvdata(file);
 
-       dev_dbg(&s->udev->dev, "%s:\n", __func__);
+       dev_dbg(s->dev, "\n");
 
        strlcpy(cap->driver, KBUILD_MODNAME, sizeof(cap->driver));
        strlcpy(cap->card, s->vdev.name, sizeof(cap->card));
@@ -631,14 +619,13 @@ static int msi2500_queue_setup(struct vb2_queue *vq,
 {
        struct msi2500_state *s = vb2_get_drv_priv(vq);
 
-       dev_dbg(&s->udev->dev, "%s: *nbuffers=%d\n", __func__, *nbuffers);
+       dev_dbg(s->dev, "nbuffers=%d\n", *nbuffers);
 
        /* Absolute min and max number of buffers available for mmap() */
        *nbuffers = clamp_t(unsigned int, *nbuffers, 8, 32);
        *nplanes = 1;
        sizes[0] = PAGE_ALIGN(s->buffersize);
-       dev_dbg(&s->udev->dev, "%s: nbuffers=%d sizes[0]=%d\n",
-                       __func__, *nbuffers, sizes[0]);
+       dev_dbg(s->dev, "nbuffers=%d sizes[0]=%d\n", *nbuffers, sizes[0]);
        return 0;
 }
 
@@ -647,7 +634,7 @@ static void msi2500_buf_queue(struct vb2_buffer *vb)
        struct msi2500_state *s = vb2_get_drv_priv(vb->vb2_queue);
        struct msi2500_frame_buf *buf =
                        container_of(vb, struct msi2500_frame_buf, vb);
-       unsigned long flags = 0;
+       unsigned long flags;
 
        /* Check the device has not disconnected between prep and queuing */
        if (unlikely(!s->udev)) {
@@ -665,16 +652,15 @@ static void msi2500_buf_queue(struct vb2_buffer *vb)
 #define CMD_STOP_STREAMING     0x45
 #define CMD_READ_UNKNOW        0x48
 
-#define msi2500_dbg_usb_control_msg(_udev, _r, _t, _v, _i, _b, _l) { \
+#define msi2500_dbg_usb_control_msg(_dev, _r, _t, _v, _i, _b, _l) { \
        char *_direction; \
        if (_t & USB_DIR_IN) \
                _direction = "<<<"; \
        else \
                _direction = ">>>"; \
-       dev_dbg(&_udev->dev, "%s: %02x %02x %02x %02x %02x %02x %02x %02x " \
-                       "%s %*ph\n",  __func__, _t, _r, _v & 0xff, _v >> 8, \
-                       _i & 0xff, _i >> 8, _l & 0xff, _l >> 8, _direction, \
-                       _l, _b); \
+       dev_dbg(_dev, "%02x %02x %02x %02x %02x %02x %02x %02x %s %*ph\n", \
+                       _t, _r, _v & 0xff, _v >> 8, _i & 0xff, _i >> 8, \
+                       _l & 0xff, _l >> 8, _direction, _l, _b); \
 }
 
 static int msi2500_ctrl_msg(struct msi2500_state *s, u8 cmd, u32 data)
@@ -685,18 +671,16 @@ static int msi2500_ctrl_msg(struct msi2500_state *s, u8 cmd, u32 data)
        u16 value = (data >> 0) & 0xffff;
        u16 index = (data >> 16) & 0xffff;
 
-       msi2500_dbg_usb_control_msg(s->udev,
+       msi2500_dbg_usb_control_msg(s->dev,
                        request, requesttype, value, index, NULL, 0);
-
        ret = usb_control_msg(s->udev, usb_sndctrlpipe(s->udev, 0),
                        request, requesttype, value, index, NULL, 0, 2000);
-
        if (ret)
-               dev_err(&s->udev->dev, "%s: failed %d, cmd %02x, data %04x\n",
-                               __func__, ret, cmd, data);
+               dev_err(s->dev, "failed %d, cmd %02x, data %04x\n",
+                               ret, cmd, data);
 
        return ret;
-};
+}
 
 #define F_REF 24000000
 #define DIV_R_IN 2
@@ -785,8 +769,7 @@ static int msi2500_set_usb_adc(struct msi2500_state *s)
 
        for (div_r_out = 4; div_r_out < 16; div_r_out += 2) {
                f_vco = f_sr * div_r_out * 12;
-               dev_dbg(&s->udev->dev, "%s: div_r_out=%d f_vco=%d\n",
-                               __func__, div_r_out, f_vco);
+               dev_dbg(s->dev, "div_r_out=%d f_vco=%d\n", div_r_out, f_vco);
                if (f_vco >= 202000000)
                        break;
        }
@@ -800,10 +783,8 @@ static int msi2500_set_usb_adc(struct msi2500_state *s)
        reg3 |= ((fract >> 20) & 0x000001) << 15; /* [20] */
        reg4 |= ((fract >>  0) & 0x0fffff) <<  8; /* [19:0] */
 
-       dev_dbg(&s->udev->dev,
-                       "%s: f_sr=%d f_vco=%d div_n=%d div_m=%d div_r_out=%d reg3=%08x reg4=%08x\n",
-                       __func__, f_sr, f_vco, div_n, div_m, div_r_out, reg3,
-                       reg4);
+       dev_dbg(s->dev, "f_sr=%d f_vco=%d div_n=%d div_m=%d div_r_out=%d reg3=%08x reg4=%08x\n",
+                       f_sr, f_vco, div_n, div_m, div_r_out, reg3, reg4);
 
        ret = msi2500_ctrl_msg(s, CMD_WREG, 0x00608008);
        if (ret)
@@ -838,14 +819,14 @@ static int msi2500_set_usb_adc(struct msi2500_state *s)
                goto err;
 err:
        return ret;
-};
+}
 
 static int msi2500_start_streaming(struct vb2_queue *vq, unsigned int count)
 {
        struct msi2500_state *s = vb2_get_drv_priv(vq);
        int ret;
 
-       dev_dbg(&s->udev->dev, "%s:\n", __func__);
+       dev_dbg(s->dev, "\n");
 
        if (!s->udev)
                return -ENODEV;
@@ -873,7 +854,7 @@ static void msi2500_stop_streaming(struct vb2_queue *vq)
 {
        struct msi2500_state *s = vb2_get_drv_priv(vq);
 
-       dev_dbg(&s->udev->dev, "%s:\n", __func__);
+       dev_dbg(s->dev, "\n");
 
        mutex_lock(&s->v4l2_lock);
 
@@ -909,7 +890,7 @@ static int msi2500_enum_fmt_sdr_cap(struct file *file, void *priv,
 {
        struct msi2500_state *s = video_drvdata(file);
 
-       dev_dbg(&s->udev->dev, "%s: index=%d\n", __func__, f->index);
+       dev_dbg(s->dev, "index=%d\n", f->index);
 
        if (f->index >= s->num_formats)
                return -EINVAL;
@@ -925,7 +906,7 @@ static int msi2500_g_fmt_sdr_cap(struct file *file, void *priv,
 {
        struct msi2500_state *s = video_drvdata(file);
 
-       dev_dbg(&s->udev->dev, "%s: pixelformat fourcc %4.4s\n", __func__,
+       dev_dbg(s->dev, "pixelformat fourcc %4.4s\n",
                        (char *)&s->pixelformat);
 
        f->fmt.sdr.pixelformat = s->pixelformat;
@@ -942,7 +923,7 @@ static int msi2500_s_fmt_sdr_cap(struct file *file, void *priv,
        struct vb2_queue *q = &s->vb_queue;
        int i;
 
-       dev_dbg(&s->udev->dev, "%s: pixelformat fourcc %4.4s\n", __func__,
+       dev_dbg(s->dev, "pixelformat fourcc %4.4s\n",
                        (char *)&f->fmt.sdr.pixelformat);
 
        if (vb2_is_busy(q))
@@ -972,7 +953,7 @@ static int msi2500_try_fmt_sdr_cap(struct file *file, void *priv,
        struct msi2500_state *s = video_drvdata(file);
        int i;
 
-       dev_dbg(&s->udev->dev, "%s: pixelformat fourcc %4.4s\n", __func__,
+       dev_dbg(s->dev, "pixelformat fourcc %4.4s\n",
                        (char *)&f->fmt.sdr.pixelformat);
 
        memset(f->fmt.sdr.reserved, 0, sizeof(f->fmt.sdr.reserved));
@@ -995,7 +976,7 @@ static int msi2500_s_tuner(struct file *file, void *priv,
        struct msi2500_state *s = video_drvdata(file);
        int ret;
 
-       dev_dbg(&s->udev->dev, "%s: index=%d\n", __func__, v->index);
+       dev_dbg(s->dev, "index=%d\n", v->index);
 
        if (v->index == 0)
                ret = 0;
@@ -1012,7 +993,7 @@ static int msi2500_g_tuner(struct file *file, void *priv, struct v4l2_tuner *v)
        struct msi2500_state *s = video_drvdata(file);
        int ret;
 
-       dev_dbg(&s->udev->dev, "%s: index=%d\n", __func__, v->index);
+       dev_dbg(s->dev, "index=%d\n", v->index);
 
        if (v->index == 0) {
                strlcpy(v->name, "Mirics MSi2500", sizeof(v->name));
@@ -1036,8 +1017,7 @@ static int msi2500_g_frequency(struct file *file, void *priv,
        struct msi2500_state *s = video_drvdata(file);
        int ret  = 0;
 
-       dev_dbg(&s->udev->dev, "%s: tuner=%d type=%d\n",
-                       __func__, f->tuner, f->type);
+       dev_dbg(s->dev, "tuner=%d type=%d\n", f->tuner, f->type);
 
        if (f->tuner == 0) {
                f->frequency = s->f_adc;
@@ -1058,15 +1038,14 @@ static int msi2500_s_frequency(struct file *file, void *priv,
        struct msi2500_state *s = video_drvdata(file);
        int ret;
 
-       dev_dbg(&s->udev->dev, "%s: tuner=%d type=%d frequency=%u\n",
-                       __func__, f->tuner, f->type, f->frequency);
+       dev_dbg(s->dev, "tuner=%d type=%d frequency=%u\n",
+                       f->tuner, f->type, f->frequency);
 
        if (f->tuner == 0) {
                s->f_adc = clamp_t(unsigned int, f->frequency,
                                bands[0].rangelow,
                                bands[0].rangehigh);
-               dev_dbg(&s->udev->dev, "%s: ADC frequency=%u Hz\n",
-                               __func__, s->f_adc);
+               dev_dbg(s->dev, "ADC frequency=%u Hz\n", s->f_adc);
                ret = msi2500_set_usb_adc(s);
        } else if (f->tuner == 1) {
                ret = v4l2_subdev_call(s->v4l2_subdev, tuner, s_frequency, f);
@@ -1083,8 +1062,8 @@ static int msi2500_enum_freq_bands(struct file *file, void *priv,
        struct msi2500_state *s = video_drvdata(file);
        int ret;
 
-       dev_dbg(&s->udev->dev, "%s: tuner=%d type=%d index=%d\n",
-                       __func__, band->tuner, band->type, band->index);
+       dev_dbg(s->dev, "tuner=%d type=%d index=%d\n",
+                       band->tuner, band->type, band->index);
 
        if (band->tuner == 0) {
                if (band->index >= ARRAY_SIZE(bands)) {
@@ -1169,8 +1148,7 @@ static int msi2500_transfer_one_message(struct spi_master *master,
        u32 data;
 
        list_for_each_entry(t, &m->transfers, transfer_list) {
-               dev_dbg(&s->udev->dev, "%s: msg=%*ph\n",
-                               __func__, t->len, t->tx_buf);
+               dev_dbg(s->dev, "msg=%*ph\n", t->len, t->tx_buf);
                data = 0x09; /* reg 9 is SPI adapter */
                data |= ((u8 *)t->tx_buf)[0] << 8;
                data |= ((u8 *)t->tx_buf)[1] << 16;
@@ -1186,8 +1164,7 @@ static int msi2500_transfer_one_message(struct spi_master *master,
 static int msi2500_probe(struct usb_interface *intf,
                const struct usb_device_id *id)
 {
-       struct usb_device *udev = interface_to_usbdev(intf);
-       struct msi2500_state *s = NULL;
+       struct msi2500_state *s;
        struct v4l2_subdev *sd;
        struct spi_master *master;
        int ret;
@@ -1200,7 +1177,7 @@ static int msi2500_probe(struct usb_interface *intf,
 
        s = kzalloc(sizeof(struct msi2500_state), GFP_KERNEL);
        if (s == NULL) {
-               pr_err("Could not allocate memory for msi2500_state\n");
+               dev_err(&intf->dev, "Could not allocate memory for state\n");
                return -ENOMEM;
        }
 
@@ -1208,12 +1185,13 @@ static int msi2500_probe(struct usb_interface *intf,
        mutex_init(&s->vb_queue_lock);
        spin_lock_init(&s->queued_bufs_lock);
        INIT_LIST_HEAD(&s->queued_bufs);
-       s->udev = udev;
+       s->dev = &intf->dev;
+       s->udev = interface_to_usbdev(intf);
        s->f_adc = bands[0].rangelow;
        s->pixelformat = formats[0].pixelformat;
        s->buffersize = formats[0].buffersize;
        s->num_formats = NUM_FORMATS;
-       if (msi2500_emulated_fmt == false)
+       if (!msi2500_emulated_fmt)
                s->num_formats -= 2;
 
        /* Init videobuf2 queue structure */
@@ -1226,7 +1204,7 @@ static int msi2500_probe(struct usb_interface *intf,
        s->vb_queue.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
        ret = vb2_queue_init(&s->vb_queue);
        if (ret) {
-               dev_err(&s->udev->dev, "Could not initialize vb2 queue\n");
+               dev_err(s->dev, "Could not initialize vb2 queue\n");
                goto err_free_mem;
        }
 
@@ -1240,13 +1218,12 @@ static int msi2500_probe(struct usb_interface *intf,
        s->v4l2_dev.release = msi2500_video_release;
        ret = v4l2_device_register(&intf->dev, &s->v4l2_dev);
        if (ret) {
-               dev_err(&s->udev->dev,
-                               "Failed to register v4l2-device (%d)\n", ret);
+               dev_err(s->dev, "Failed to register v4l2-device (%d)\n", ret);
                goto err_free_mem;
        }
 
        /* SPI master adapter */
-       master = spi_alloc_master(&s->udev->dev, 0);
+       master = spi_alloc_master(s->dev, 0);
        if (master == NULL) {
                ret = -ENOMEM;
                goto err_unregister_v4l2_dev;
@@ -1267,7 +1244,7 @@ static int msi2500_probe(struct usb_interface *intf,
        sd = v4l2_spi_new_subdev(&s->v4l2_dev, master, &board_info);
        s->v4l2_subdev = sd;
        if (sd == NULL) {
-               dev_err(&s->udev->dev, "cannot get v4l2 subdevice\n");
+               dev_err(s->dev, "cannot get v4l2 subdevice\n");
                ret = -ENODEV;
                goto err_unregister_master;
        }
@@ -1276,7 +1253,7 @@ static int msi2500_probe(struct usb_interface *intf,
        v4l2_ctrl_handler_init(&s->hdl, 0);
        if (s->hdl.error) {
                ret = s->hdl.error;
-               dev_err(&s->udev->dev, "Could not initialize controls\n");
+               dev_err(s->dev, "Could not initialize controls\n");
                goto err_free_controls;
        }
 
@@ -1289,16 +1266,13 @@ static int msi2500_probe(struct usb_interface *intf,
 
        ret = video_register_device(&s->vdev, VFL_TYPE_SDR, -1);
        if (ret) {
-               dev_err(&s->udev->dev,
-                               "Failed to register as video device (%d)\n",
+               dev_err(s->dev, "Failed to register as video device (%d)\n",
                                ret);
                goto err_unregister_v4l2_dev;
        }
-       dev_info(&s->udev->dev, "Registered as %s\n",
+       dev_info(s->dev, "Registered as %s\n",
                        video_device_node_name(&s->vdev));
-       dev_notice(&s->udev->dev,
-                       "%s: SDR API is still slightly experimental and functionality changes may follow\n",
-                       KBUILD_MODNAME);
+       dev_notice(s->dev, "SDR API is still slightly experimental and functionality changes may follow\n");
 
        return 0;
 
index aa7449eaca08d027ba752aeddffa9ea883ad7e86..3d987984602f1bad2042a778aeef9b79c39dab32 100644 (file)
@@ -52,7 +52,7 @@ enum { custom_autocontour, custom_contour, custom_noise_reduction,
        custom_awb_speed, custom_awb_delay,
        custom_save_user, custom_restore_user, custom_restore_factory };
 
-const char * const pwc_auto_whitebal_qmenu[] = {
+static const char * const pwc_auto_whitebal_qmenu[] = {
        "Indoor (Incandescant Lighting) Mode",
        "Outdoor (Sunlight) Mode",
        "Indoor (Fluorescent Lighting) Mode",
index 2c901861034afd746a6fec9540e1ebf47f2c0156..ccc00099b26144e4bd1c5b99cbfccbf266a50ad7 100644 (file)
@@ -2245,7 +2245,7 @@ static int s2255_probe(struct usb_interface *interface,
        }
 
        atomic_set(&dev->num_channels, 0);
-       dev->pid = le16_to_cpu(id->idProduct);
+       dev->pid = id->idProduct;
        dev->fw_data = kzalloc(sizeof(struct s2255_fw), GFP_KERNEL);
        if (!dev->fw_data)
                goto errorFWDATA1;
index 1836a416d80646151e80c67d8896f96fa6fd1fe2..94e10b10b66e8c41c95672a702bcb84c91f5b05b 100644 (file)
@@ -277,14 +277,14 @@ static int smsusb1_load_firmware(struct usb_device *udev, int id, int board_id)
                rc = usb_bulk_msg(udev, usb_sndbulkpipe(udev, 2),
                                  fw_buffer, fw->size, &dummy, 1000);
 
-               sms_info("sent %zd(%d) bytes, rc %d", fw->size, dummy, rc);
+               sms_info("sent %zu(%d) bytes, rc %d", fw->size, dummy, rc);
 
                kfree(fw_buffer);
        } else {
                sms_err("failed to allocate firmware buffer");
                rc = -ENOMEM;
        }
-       sms_info("read FW %s, size=%zd", fw_filename, fw->size);
+       sms_info("read FW %s, size=%zu", fw_filename, fw->size);
 
        release_firmware(fw);
 
@@ -655,6 +655,8 @@ static const struct usb_device_id smsusb_id_table[] = {
                .driver_info = SMS1XXX_BOARD_ONDA_MDTV_DATA_CARD },
        { USB_DEVICE(0x3275, 0x0080),
                .driver_info = SMS1XXX_BOARD_SIANO_RIO },
+       { USB_DEVICE(0x2013, 0x0257),
+               .driver_info = SMS1XXX_BOARD_PCTV_77E },
        { } /* Terminating entry */
        };
 
index 5c45c9d0712ddf949f0ac571b5649111585046ae..9c29552aedec2e7b1a08447619671cd65c170b77 100644 (file)
@@ -156,6 +156,9 @@ static int ttusbdecfe_dvbs_diseqc_send_master_cmd(struct dvb_frontend* fe, struc
                   0x00, 0x00, 0x00, 0x00,
                   0x00, 0x00 };
 
+       if (cmd->msg_len > sizeof(b) - 4)
+               return -EINVAL;
+
        memcpy(&b[4], cmd->msg, cmd->msg_len);
 
        state->config->send_command(fe, 0x72,
index 7c5b86006ee627c43a52003fb816c7fceb10b6f4..b833c5b9094edb33fbac7fd167a09710b065fbd2 100644 (file)
@@ -1,6 +1,7 @@
 config VIDEO_USBTV
         tristate "USBTV007 video capture support"
-        depends on VIDEO_V4L2
+        depends on VIDEO_V4L2 && SND
+        select SND_PCM
         select VIDEOBUF2_VMALLOC
 
         ---help---
index 775316a88ea6953210befcabf71e4a005c67bc15..f555cf8a3dd2ea886ad9ad3f2b41b69d61444922 100644 (file)
@@ -1,4 +1,5 @@
 usbtv-y := usbtv-core.o \
-       usbtv-video.o
+       usbtv-video.o \
+       usbtv-audio.o
 
 obj-$(CONFIG_VIDEO_USBTV) += usbtv.o
diff --git a/drivers/media/usb/usbtv/usbtv-audio.c b/drivers/media/usb/usbtv/usbtv-audio.c
new file mode 100644 (file)
index 0000000..78c12d2
--- /dev/null
@@ -0,0 +1,385 @@
+/*
+ * Fushicai USBTV007 Audio-Video Grabber Driver
+ *
+ * Product web site:
+ * http://www.fushicai.com/products_detail/&productId=d05449ee-b690-42f9-a661-aa7353894bed.html
+ *
+ * Copyright (c) 2013 Federico Simoncelli
+ * All rights reserved.
+ * No physical hardware was harmed running Windows during the
+ * reverse-engineering activity
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification.
+ * 2. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL").
+ */
+
+#include <sound/core.h>
+#include <sound/initval.h>
+#include <sound/ac97_codec.h>
+#include <sound/pcm_params.h>
+
+#include "usbtv.h"
+
+static struct snd_pcm_hardware snd_usbtv_digital_hw = {
+       .info = SNDRV_PCM_INFO_BATCH |
+               SNDRV_PCM_INFO_MMAP |
+               SNDRV_PCM_INFO_INTERLEAVED |
+               SNDRV_PCM_INFO_BLOCK_TRANSFER |
+               SNDRV_PCM_INFO_MMAP_VALID,
+       .formats = SNDRV_PCM_FMTBIT_S16_LE,
+       .rates = SNDRV_PCM_RATE_48000,
+       .rate_min = 48000,
+       .rate_max = 48000,
+       .channels_min = 2,
+       .channels_max = 2,
+       .period_bytes_min = 11059,
+       .period_bytes_max = 13516,
+       .periods_min = 2,
+       .periods_max = 98,
+       .buffer_bytes_max = 62720 * 8, /* value in usbaudio.c */
+};
+
+static int snd_usbtv_pcm_open(struct snd_pcm_substream *substream)
+{
+       struct usbtv *chip = snd_pcm_substream_chip(substream);
+       struct snd_pcm_runtime *runtime = substream->runtime;
+
+       chip->snd_substream = substream;
+       runtime->hw = snd_usbtv_digital_hw;
+
+       return 0;
+}
+
+static int snd_usbtv_pcm_close(struct snd_pcm_substream *substream)
+{
+       struct usbtv *chip = snd_pcm_substream_chip(substream);
+
+       if (atomic_read(&chip->snd_stream)) {
+               atomic_set(&chip->snd_stream, 0);
+               schedule_work(&chip->snd_trigger);
+       }
+
+       return 0;
+}
+
+static int snd_usbtv_hw_params(struct snd_pcm_substream *substream,
+               struct snd_pcm_hw_params *hw_params)
+{
+       int rv;
+       struct usbtv *chip = snd_pcm_substream_chip(substream);
+
+       rv = snd_pcm_lib_malloc_pages(substream,
+               params_buffer_bytes(hw_params));
+
+       if (rv < 0) {
+               dev_warn(chip->dev, "pcm audio buffer allocation failure %i\n",
+                       rv);
+               return rv;
+       }
+
+       return 0;
+}
+
+static int snd_usbtv_hw_free(struct snd_pcm_substream *substream)
+{
+       snd_pcm_lib_free_pages(substream);
+       return 0;
+}
+
+static int snd_usbtv_prepare(struct snd_pcm_substream *substream)
+{
+       struct usbtv *chip = snd_pcm_substream_chip(substream);
+
+       chip->snd_buffer_pos = 0;
+       chip->snd_period_pos = 0;
+
+       return 0;
+}
+
+static void usbtv_audio_urb_received(struct urb *urb)
+{
+       struct usbtv *chip = urb->context;
+       struct snd_pcm_substream *substream = chip->snd_substream;
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       size_t i, frame_bytes, chunk_length, buffer_pos, period_pos;
+       int period_elapsed;
+       void *urb_current;
+
+       switch (urb->status) {
+       case 0:
+       case -ETIMEDOUT:
+               break;
+       case -ENOENT:
+       case -EPROTO:
+       case -ECONNRESET:
+       case -ESHUTDOWN:
+               return;
+       default:
+               dev_warn(chip->dev, "unknown audio urb status %i\n",
+                       urb->status);
+       }
+
+       if (!atomic_read(&chip->snd_stream))
+               return;
+
+       frame_bytes = runtime->frame_bits >> 3;
+       chunk_length = USBTV_CHUNK / frame_bytes;
+
+       buffer_pos = chip->snd_buffer_pos;
+       period_pos = chip->snd_period_pos;
+       period_elapsed = 0;
+
+       for (i = 0; i < urb->actual_length; i += USBTV_CHUNK_SIZE) {
+               urb_current = urb->transfer_buffer + i + USBTV_AUDIO_HDRSIZE;
+
+               if (buffer_pos + chunk_length >= runtime->buffer_size) {
+                       size_t cnt = (runtime->buffer_size - buffer_pos) *
+                               frame_bytes;
+                       memcpy(runtime->dma_area + buffer_pos * frame_bytes,
+                               urb_current, cnt);
+                       memcpy(runtime->dma_area, urb_current + cnt,
+                               chunk_length * frame_bytes - cnt);
+               } else {
+                       memcpy(runtime->dma_area + buffer_pos * frame_bytes,
+                               urb_current, chunk_length * frame_bytes);
+               }
+
+               buffer_pos += chunk_length;
+               period_pos += chunk_length;
+
+               if (buffer_pos >= runtime->buffer_size)
+                       buffer_pos -= runtime->buffer_size;
+
+               if (period_pos >= runtime->period_size) {
+                       period_pos -= runtime->period_size;
+                       period_elapsed = 1;
+               }
+       }
+
+       snd_pcm_stream_lock(substream);
+
+       chip->snd_buffer_pos = buffer_pos;
+       chip->snd_period_pos = period_pos;
+
+       snd_pcm_stream_unlock(substream);
+
+       if (period_elapsed)
+               snd_pcm_period_elapsed(substream);
+
+       usb_submit_urb(urb, GFP_ATOMIC);
+}
+
+static int usbtv_audio_start(struct usbtv *chip)
+{
+       unsigned int pipe;
+       static const u16 setup[][2] = {
+               /* These seem to enable the device. */
+               { USBTV_BASE + 0x0008, 0x0001 },
+               { USBTV_BASE + 0x01d0, 0x00ff },
+               { USBTV_BASE + 0x01d9, 0x0002 },
+
+               { USBTV_BASE + 0x01da, 0x0013 },
+               { USBTV_BASE + 0x01db, 0x0012 },
+               { USBTV_BASE + 0x01e9, 0x0002 },
+               { USBTV_BASE + 0x01ec, 0x006c },
+               { USBTV_BASE + 0x0294, 0x0020 },
+               { USBTV_BASE + 0x0255, 0x00cf },
+               { USBTV_BASE + 0x0256, 0x0020 },
+               { USBTV_BASE + 0x01eb, 0x0030 },
+               { USBTV_BASE + 0x027d, 0x00a6 },
+               { USBTV_BASE + 0x0280, 0x0011 },
+               { USBTV_BASE + 0x0281, 0x0040 },
+               { USBTV_BASE + 0x0282, 0x0011 },
+               { USBTV_BASE + 0x0283, 0x0040 },
+               { 0xf891, 0x0010 },
+
+               /* this sets the input from composite */
+               { USBTV_BASE + 0x0284, 0x00aa },
+       };
+
+       chip->snd_bulk_urb = usb_alloc_urb(0, GFP_KERNEL);
+       if (chip->snd_bulk_urb == NULL)
+               goto err_alloc_urb;
+
+       pipe = usb_rcvbulkpipe(chip->udev, USBTV_AUDIO_ENDP);
+
+       chip->snd_bulk_urb->transfer_buffer = kzalloc(
+               USBTV_AUDIO_URBSIZE, GFP_KERNEL);
+       if (chip->snd_bulk_urb->transfer_buffer == NULL)
+               goto err_transfer_buffer;
+
+       usb_fill_bulk_urb(chip->snd_bulk_urb, chip->udev, pipe,
+               chip->snd_bulk_urb->transfer_buffer, USBTV_AUDIO_URBSIZE,
+               usbtv_audio_urb_received, chip);
+
+       /* starting the stream */
+       usbtv_set_regs(chip, setup, ARRAY_SIZE(setup));
+
+       usb_clear_halt(chip->udev, pipe);
+       usb_submit_urb(chip->snd_bulk_urb, GFP_ATOMIC);
+
+       return 0;
+
+err_transfer_buffer:
+       usb_free_urb(chip->snd_bulk_urb);
+       chip->snd_bulk_urb = NULL;
+
+err_alloc_urb:
+       return -ENOMEM;
+}
+
+static int usbtv_audio_stop(struct usbtv *chip)
+{
+       static const u16 setup[][2] = {
+       /* The original windows driver sometimes sends also:
+        *   { USBTV_BASE + 0x00a2, 0x0013 }
+        * but it seems useless and its real effects are untested at
+        * the moment.
+        */
+               { USBTV_BASE + 0x027d, 0x0000 },
+               { USBTV_BASE + 0x0280, 0x0010 },
+               { USBTV_BASE + 0x0282, 0x0010 },
+       };
+
+       if (chip->snd_bulk_urb) {
+               usb_kill_urb(chip->snd_bulk_urb);
+               kfree(chip->snd_bulk_urb->transfer_buffer);
+               usb_free_urb(chip->snd_bulk_urb);
+               chip->snd_bulk_urb = NULL;
+       }
+
+       usbtv_set_regs(chip, setup, ARRAY_SIZE(setup));
+
+       return 0;
+}
+
+void usbtv_audio_suspend(struct usbtv *usbtv)
+{
+       if (atomic_read(&usbtv->snd_stream) && usbtv->snd_bulk_urb)
+               usb_kill_urb(usbtv->snd_bulk_urb);
+}
+
+void usbtv_audio_resume(struct usbtv *usbtv)
+{
+       if (atomic_read(&usbtv->snd_stream) && usbtv->snd_bulk_urb)
+               usb_submit_urb(usbtv->snd_bulk_urb, GFP_ATOMIC);
+}
+
+static void snd_usbtv_trigger(struct work_struct *work)
+{
+       struct usbtv *chip = container_of(work, struct usbtv, snd_trigger);
+
+       if (atomic_read(&chip->snd_stream))
+               usbtv_audio_start(chip);
+       else
+               usbtv_audio_stop(chip);
+}
+
+static int snd_usbtv_card_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+       struct usbtv *chip = snd_pcm_substream_chip(substream);
+
+       switch (cmd) {
+       case SNDRV_PCM_TRIGGER_START:
+       case SNDRV_PCM_TRIGGER_RESUME:
+       case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+               atomic_set(&chip->snd_stream, 1);
+               break;
+       case SNDRV_PCM_TRIGGER_STOP:
+       case SNDRV_PCM_TRIGGER_SUSPEND:
+       case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+               atomic_set(&chip->snd_stream, 0);
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       schedule_work(&chip->snd_trigger);
+
+       return 0;
+}
+
+static snd_pcm_uframes_t snd_usbtv_pointer(struct snd_pcm_substream *substream)
+{
+       struct usbtv *chip = snd_pcm_substream_chip(substream);
+
+       return chip->snd_buffer_pos;
+}
+
+static struct snd_pcm_ops snd_usbtv_pcm_ops = {
+       .open = snd_usbtv_pcm_open,
+       .close = snd_usbtv_pcm_close,
+       .ioctl = snd_pcm_lib_ioctl,
+       .hw_params = snd_usbtv_hw_params,
+       .hw_free = snd_usbtv_hw_free,
+       .prepare = snd_usbtv_prepare,
+       .trigger = snd_usbtv_card_trigger,
+       .pointer = snd_usbtv_pointer,
+};
+
+int usbtv_audio_init(struct usbtv *usbtv)
+{
+       int rv;
+       struct snd_card *card;
+       struct snd_pcm *pcm;
+
+       INIT_WORK(&usbtv->snd_trigger, snd_usbtv_trigger);
+       atomic_set(&usbtv->snd_stream, 0);
+
+       rv = snd_card_new(&usbtv->udev->dev, SNDRV_DEFAULT_IDX1, "usbtv",
+               THIS_MODULE, 0, &card);
+       if (rv < 0)
+               return rv;
+
+       strlcpy(card->driver, usbtv->dev->driver->name, sizeof(card->driver));
+       strlcpy(card->shortname, "usbtv", sizeof(card->shortname));
+       snprintf(card->longname, sizeof(card->longname),
+               "USBTV Audio at bus %d device %d", usbtv->udev->bus->busnum,
+               usbtv->udev->devnum);
+
+       snd_card_set_dev(card, usbtv->dev);
+
+       usbtv->snd = card;
+
+       rv = snd_pcm_new(card, "USBTV Audio", 0, 0, 1, &pcm);
+       if (rv < 0)
+               goto err;
+
+       strlcpy(pcm->name, "USBTV Audio Input", sizeof(pcm->name));
+       pcm->info_flags = 0;
+       pcm->private_data = usbtv;
+
+       snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_usbtv_pcm_ops);
+       snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_CONTINUOUS,
+               snd_dma_continuous_data(GFP_KERNEL), USBTV_AUDIO_BUFFER,
+               USBTV_AUDIO_BUFFER);
+
+       rv = snd_card_register(card);
+       if (rv)
+               goto err;
+
+       return 0;
+
+err:
+       usbtv->snd = NULL;
+       snd_card_free(card);
+
+       return rv;
+}
+
+void usbtv_audio_free(struct usbtv *usbtv)
+{
+       if (usbtv->snd && usbtv->udev) {
+               snd_card_free(usbtv->snd);
+               usbtv->snd = NULL;
+       }
+}
index 473fab81b602276b85cc2320eb76854611fe16ee..29428bef272c657346f2850f6372f55cb33208d2 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Fushicai USBTV007 Video Grabber Driver
+ * Fushicai USBTV007 Audio-Video Grabber Driver
  *
  * Product web site:
  * http://www.fushicai.com/products_detail/&productId=d05449ee-b690-42f9-a661-aa7353894bed.html
@@ -84,12 +84,19 @@ static int usbtv_probe(struct usb_interface *intf,
        if (ret < 0)
                goto usbtv_video_fail;
 
+       ret = usbtv_audio_init(usbtv);
+       if (ret < 0)
+               goto usbtv_audio_fail;
+
        /* for simplicity we exploit the v4l2_device reference counting */
        v4l2_device_get(&usbtv->v4l2_dev);
 
-       dev_info(dev, "Fushicai USBTV007 Video Grabber\n");
+       dev_info(dev, "Fushicai USBTV007 Audio-Video Grabber\n");
        return 0;
 
+usbtv_audio_fail:
+       usbtv_video_free(usbtv);
+
 usbtv_video_fail:
        usb_set_intfdata(intf, NULL);
        usb_put_dev(usbtv->udev);
@@ -101,11 +108,13 @@ usbtv_video_fail:
 static void usbtv_disconnect(struct usb_interface *intf)
 {
        struct usbtv *usbtv = usb_get_intfdata(intf);
+
        usb_set_intfdata(intf, NULL);
 
        if (!usbtv)
                return;
 
+       usbtv_audio_free(usbtv);
        usbtv_video_free(usbtv);
 
        usb_put_dev(usbtv->udev);
@@ -122,8 +131,8 @@ static struct usb_device_id usbtv_id_table[] = {
 };
 MODULE_DEVICE_TABLE(usb, usbtv_id_table);
 
-MODULE_AUTHOR("Lubomir Rintel");
-MODULE_DESCRIPTION("Fushicai USBTV007 Video Grabber Driver");
+MODULE_AUTHOR("Lubomir Rintel, Federico Simoncelli");
+MODULE_DESCRIPTION("Fushicai USBTV007 Audio-Video Grabber Driver");
 MODULE_LICENSE("Dual BSD/GPL");
 
 static struct usb_driver usbtv_usb_driver = {
index 030c5854b4b3e45913a6a5d70bb03cb3a5bcf51c..9d3525f659f066d3c013105052e9fc31a76874aa 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Fushicai USBTV007 Video Grabber Driver
+ * Fushicai USBTV007 Audio-Video Grabber Driver
  *
  * Product web site:
  * http://www.fushicai.com/products_detail/&productId=d05449ee-b690-42f9-a661-aa7353894bed.html
@@ -79,7 +79,6 @@ static int usbtv_select_input(struct usbtv *usbtv, int input)
                { USBTV_BASE + 0x011f, 0x00f2 },
                { USBTV_BASE + 0x0127, 0x0060 },
                { USBTV_BASE + 0x00ae, 0x0010 },
-               { USBTV_BASE + 0x0284, 0x00aa },
                { USBTV_BASE + 0x0239, 0x0060 },
        };
 
@@ -88,7 +87,6 @@ static int usbtv_select_input(struct usbtv *usbtv, int input)
                { USBTV_BASE + 0x011f, 0x00ff },
                { USBTV_BASE + 0x0127, 0x0060 },
                { USBTV_BASE + 0x00ae, 0x0030 },
-               { USBTV_BASE + 0x0284, 0x0088 },
                { USBTV_BASE + 0x0239, 0x0060 },
        };
 
@@ -225,7 +223,6 @@ static int usbtv_setup_capture(struct usbtv *usbtv)
                { USBTV_BASE + 0x0159, 0x0006 },
                { USBTV_BASE + 0x015d, 0x0000 },
 
-               { USBTV_BASE + 0x0284, 0x0088 },
                { USBTV_BASE + 0x0003, 0x0004 },
                { USBTV_BASE + 0x0100, 0x00d3 },
                { USBTV_BASE + 0x0115, 0x0015 },
@@ -256,7 +253,7 @@ static int usbtv_setup_capture(struct usbtv *usbtv)
  * 720 pixel lines, as the chunk is 240 words long, which is 480 pixels.
  * Therefore, we break down the chunk into two halves before copyting,
  * so that we can interleave a line if needed. */
-static void usbtv_chunk_to_vbuf(u32 *frame, u32 *src, int chunk_no, int odd)
+static void usbtv_chunk_to_vbuf(u32 *frame, __be32 *src, int chunk_no, int odd)
 {
        int half;
 
@@ -266,6 +263,7 @@ static void usbtv_chunk_to_vbuf(u32 *frame, u32 *src, int chunk_no, int odd)
                int part_index = (line * 2 + !odd) * 3 + (part_no % 3);
 
                u32 *dst = &frame[part_index * USBTV_CHUNK/2];
+
                memcpy(dst, src, USBTV_CHUNK/2 * sizeof(*src));
                src += USBTV_CHUNK/2;
        }
@@ -274,7 +272,7 @@ static void usbtv_chunk_to_vbuf(u32 *frame, u32 *src, int chunk_no, int odd)
 /* Called for each 256-byte image chunk.
  * First word identifies the chunk, followed by 240 words of image
  * data and padding. */
-static void usbtv_image_chunk(struct usbtv *usbtv, u32 *chunk)
+static void usbtv_image_chunk(struct usbtv *usbtv, __be32 *chunk)
 {
        int frame_id, odd, chunk_no;
        u32 *frame;
@@ -365,7 +363,7 @@ static void usbtv_iso_cb(struct urb *ip)
 
                for (offset = 0; USBTV_CHUNK_SIZE * offset < size; offset++)
                        usbtv_image_chunk(usbtv,
-                               (u32 *)&data[USBTV_CHUNK_SIZE * offset]);
+                               (__be32 *)&data[USBTV_CHUNK_SIZE * offset]);
        }
 
 resubmit:
@@ -410,6 +408,7 @@ static void usbtv_stop(struct usbtv *usbtv)
        /* Cancel running transfers. */
        for (i = 0; i < USBTV_ISOC_TRANSFERS; i++) {
                struct urb *ip = usbtv->isoc_urbs[i];
+
                if (ip == NULL)
                        continue;
                usb_kill_urb(ip);
@@ -434,6 +433,8 @@ static int usbtv_start(struct usbtv *usbtv)
        int i;
        int ret;
 
+       usbtv_audio_suspend(usbtv);
+
        ret = usb_set_interface(usbtv->udev, 0, 0);
        if (ret < 0)
                return ret;
@@ -446,6 +447,8 @@ static int usbtv_start(struct usbtv *usbtv)
        if (ret < 0)
                return ret;
 
+       usbtv_audio_resume(usbtv);
+
        for (i = 0; i < USBTV_ISOC_TRANSFERS; i++) {
                struct urb *ip;
 
@@ -559,6 +562,7 @@ static int usbtv_g_input(struct file *file, void *priv, unsigned int *i)
 static int usbtv_s_input(struct file *file, void *priv, unsigned int i)
 {
        struct usbtv *usbtv = video_drvdata(file);
+
        return usbtv_select_input(usbtv, i);
 }
 
index cb1d388cc647703d12736c4d37c5b98b67a1457b..968119581fab3e95adad4771576c3249ff56b0d5 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Fushicai USBTV007 Video Grabber Driver
+ * Fushicai USBTV007 Audio-Video Grabber Driver
  *
  * Copyright (c) 2013 Lubomir Rintel
  * All rights reserved.
@@ -28,6 +28,7 @@
 
 /* Hardware. */
 #define USBTV_VIDEO_ENDP       0x81
+#define USBTV_AUDIO_ENDP       0x83
 #define USBTV_BASE             0xc000
 #define USBTV_REQUEST_REG      12
 
 #define USBTV_CHUNK_SIZE       256
 #define USBTV_CHUNK            240
 
+#define USBTV_AUDIO_URBSIZE    20480
+#define USBTV_AUDIO_HDRSIZE    4
+#define USBTV_AUDIO_BUFFER     65536
+
 /* Chunk header. */
 #define USBTV_MAGIC_OK(chunk)  ((be32_to_cpu(chunk[0]) & 0xff000000) \
                                                        == 0x88000000)
@@ -91,9 +96,23 @@ struct usbtv {
        int iso_size;
        unsigned int sequence;
        struct urb *isoc_urbs[USBTV_ISOC_TRANSFERS];
+
+       /* audio */
+       struct snd_card *snd;
+       struct snd_pcm_substream *snd_substream;
+       atomic_t snd_stream;
+       struct work_struct snd_trigger;
+       struct urb *snd_bulk_urb;
+       size_t snd_buffer_pos;
+       size_t snd_period_pos;
 };
 
 int usbtv_set_regs(struct usbtv *usbtv, const u16 regs[][2], int size);
 
 int usbtv_video_init(struct usbtv *usbtv);
 void usbtv_video_free(struct usbtv *usbtv);
+
+int usbtv_audio_init(struct usbtv *usbtv);
+void usbtv_audio_free(struct usbtv *usbtv);
+void usbtv_audio_suspend(struct usbtv *usbtv);
+void usbtv_audio_resume(struct usbtv *usbtv);
index 0eb82106d2ff4015bc8cee2e0159626b8ba4ad8e..3e59b288b8a89cc70d9b4c086c5784e922ff1e65 100644 (file)
@@ -309,9 +309,8 @@ static struct uvc_control_info uvc_ctrls[] = {
                .selector       = UVC_CT_PANTILT_RELATIVE_CONTROL,
                .index          = 12,
                .size           = 4,
-               .flags          = UVC_CTRL_FLAG_SET_CUR | UVC_CTRL_FLAG_GET_MIN
-                               | UVC_CTRL_FLAG_GET_MAX | UVC_CTRL_FLAG_GET_RES
-                               | UVC_CTRL_FLAG_GET_DEF
+               .flags          = UVC_CTRL_FLAG_SET_CUR
+                               | UVC_CTRL_FLAG_GET_RANGE
                                | UVC_CTRL_FLAG_AUTO_UPDATE,
        },
        {
@@ -391,6 +390,35 @@ static void uvc_ctrl_set_zoom(struct uvc_control_mapping *mapping,
        data[2] = min((int)abs(value), 0xff);
 }
 
+static __s32 uvc_ctrl_get_rel_speed(struct uvc_control_mapping *mapping,
+       __u8 query, const __u8 *data)
+{
+       unsigned int first = mapping->offset / 8;
+       __s8 rel = (__s8)data[first];
+
+       switch (query) {
+       case UVC_GET_CUR:
+               return (rel == 0) ? 0 : (rel > 0 ? data[first+1]
+                                                : -data[first+1]);
+       case UVC_GET_MIN:
+               return -data[first+1];
+       case UVC_GET_MAX:
+       case UVC_GET_RES:
+       case UVC_GET_DEF:
+       default:
+               return data[first+1];
+       }
+}
+
+static void uvc_ctrl_set_rel_speed(struct uvc_control_mapping *mapping,
+       __s32 value, __u8 *data)
+{
+       unsigned int first = mapping->offset / 8;
+
+       data[first] = value == 0 ? 0 : (value > 0) ? 1 : 0xff;
+       data[first+1] = min_t(int, abs(value), 0xff);
+}
+
 static struct uvc_control_mapping uvc_ctrl_mappings[] = {
        {
                .id             = V4L2_CID_BRIGHTNESS,
@@ -676,6 +704,30 @@ static struct uvc_control_mapping uvc_ctrl_mappings[] = {
                .v4l2_type      = V4L2_CTRL_TYPE_INTEGER,
                .data_type      = UVC_CTRL_DATA_TYPE_SIGNED,
        },
+       {
+               .id             = V4L2_CID_PAN_SPEED,
+               .name           = "Pan (Speed)",
+               .entity         = UVC_GUID_UVC_CAMERA,
+               .selector       = UVC_CT_PANTILT_RELATIVE_CONTROL,
+               .size           = 16,
+               .offset         = 0,
+               .v4l2_type      = V4L2_CTRL_TYPE_INTEGER,
+               .data_type      = UVC_CTRL_DATA_TYPE_SIGNED,
+               .get            = uvc_ctrl_get_rel_speed,
+               .set            = uvc_ctrl_set_rel_speed,
+       },
+       {
+               .id             = V4L2_CID_TILT_SPEED,
+               .name           = "Tilt (Speed)",
+               .entity         = UVC_GUID_UVC_CAMERA,
+               .selector       = UVC_CT_PANTILT_RELATIVE_CONTROL,
+               .size           = 16,
+               .offset         = 16,
+               .v4l2_type      = V4L2_CTRL_TYPE_INTEGER,
+               .data_type      = UVC_CTRL_DATA_TYPE_SIGNED,
+               .get            = uvc_ctrl_get_rel_speed,
+               .set            = uvc_ctrl_set_rel_speed,
+       },
        {
                .id             = V4L2_CID_PRIVACY,
                .name           = "Privacy",
@@ -1795,7 +1847,7 @@ done:
  * - Handle restore order (Auto-Exposure Mode should be restored before
  *   Exposure Time).
  */
-int uvc_ctrl_resume_device(struct uvc_device *dev)
+int uvc_ctrl_restore_values(struct uvc_device *dev)
 {
        struct uvc_control *ctrl;
        struct uvc_entity *entity;
index f8135f4e3b5262793e511193033d9b9bb9ad5abb..7c8322d4fc63fae2e2e65f24f080d1db7fd604a4 100644 (file)
@@ -2000,7 +2000,7 @@ static int __uvc_resume(struct usb_interface *intf, int reset)
                int ret = 0;
 
                if (reset) {
-                       ret = uvc_ctrl_resume_device(dev);
+                       ret = uvc_ctrl_restore_values(dev);
                        if (ret < 0)
                                return ret;
                }
@@ -2175,6 +2175,15 @@ static struct usb_device_id uvc_ids[] = {
          .bInterfaceClass      = USB_CLASS_VENDOR_SPEC,
          .bInterfaceSubClass   = 1,
          .bInterfaceProtocol   = 0 },
+       /* Logitech HD Pro Webcam C920 */
+       { .match_flags          = USB_DEVICE_ID_MATCH_DEVICE
+                               | USB_DEVICE_ID_MATCH_INT_INFO,
+         .idVendor             = 0x046d,
+         .idProduct            = 0x082d,
+         .bInterfaceClass      = USB_CLASS_VIDEO,
+         .bInterfaceSubClass   = 1,
+         .bInterfaceProtocol   = 0,
+         .driver_info          = UVC_QUIRK_RESTORE_CTRLS_ON_INIT },
        /* Chicony CNF7129 (Asus EEE 100HE) */
        { .match_flags          = USB_DEVICE_ID_MATCH_DEVICE
                                | USB_DEVICE_ID_MATCH_INT_INFO,
@@ -2229,6 +2238,15 @@ static struct usb_device_id uvc_ids[] = {
          .bInterfaceSubClass   = 1,
          .bInterfaceProtocol   = 0,
          .driver_info          = UVC_QUIRK_PROBE_DEF },
+       /* Dell XPS M1330 (OmniVision OV7670 webcam) */
+       { .match_flags          = USB_DEVICE_ID_MATCH_DEVICE
+                               | USB_DEVICE_ID_MATCH_INT_INFO,
+         .idVendor             = 0x05a9,
+         .idProduct            = 0x7670,
+         .bInterfaceClass      = USB_CLASS_VIDEO,
+         .bInterfaceSubClass   = 1,
+         .bInterfaceProtocol   = 0,
+         .driver_info          = UVC_QUIRK_PROBE_DEF },
        /* Apple Built-In iSight */
        { .match_flags          = USB_DEVICE_ID_MATCH_DEVICE
                                | USB_DEVICE_ID_MATCH_INT_INFO,
index 378ae02e593b93a19bb9010a23f62175029bbefd..60a8e2c3631e0b155b241e624092ccef271ae030 100644 (file)
@@ -318,6 +318,7 @@ static int uvc_v4l2_set_format(struct uvc_streaming *stream,
        stream->ctrl = probe;
        stream->cur_format = format;
        stream->cur_frame = frame;
+       stream->frame_size = fmt->fmt.pix.sizeimage;
 
 done:
        mutex_unlock(&stream->mutex);
index 9144a2f3ed826c541ef9d5d1b3286e00ce7c1d6d..9ace520bb079792b840d8aff38b68945fef0eeb0 100644 (file)
@@ -1143,7 +1143,7 @@ static int uvc_video_encode_data(struct uvc_streaming *stream,
 static void uvc_video_validate_buffer(const struct uvc_streaming *stream,
                                      struct uvc_buffer *buf)
 {
-       if (buf->length != buf->bytesused &&
+       if (stream->frame_size != buf->bytesused &&
            !(stream->cur_format->flags & UVC_FMT_FLAG_COMPRESSED))
                buf->error = 1;
 }
@@ -1463,7 +1463,7 @@ static unsigned int uvc_endpoint_max_bpi(struct usb_device *dev,
 
        switch (dev->speed) {
        case USB_SPEED_SUPER:
-               return ep->ss_ep_comp.wBytesPerInterval;
+               return le16_to_cpu(ep->ss_ep_comp.wBytesPerInterval);
        case USB_SPEED_HIGH:
                psize = usb_endpoint_maxp(&ep->desc);
                return (psize & 0x07ff) * (1 + ((psize >> 11) & 3));
@@ -1678,6 +1678,12 @@ static int uvc_init_video(struct uvc_streaming *stream, gfp_t gfp_flags)
                }
        }
 
+       /* The Logitech C920 temporarily forgets that it should not be adjusting
+        * Exposure Absolute during init so restore controls to stored values.
+        */
+       if (stream->dev->quirks & UVC_QUIRK_RESTORE_CTRLS_ON_INIT)
+               uvc_ctrl_restore_values(stream->dev);
+
        return 0;
 }
 
index b1f69a6d4068f1c64aec057142efcf02b9b6f82e..6f676c29ec09fd997b8833d78df1b8b72fdf0d91 100644 (file)
 #define UVC_QUIRK_FIX_BANDWIDTH                0x00000080
 #define UVC_QUIRK_PROBE_DEF            0x00000100
 #define UVC_QUIRK_RESTRICT_FRAME_RATE  0x00000200
+#define UVC_QUIRK_RESTORE_CTRLS_ON_INIT        0x00000400
 
 /* Format flags */
 #define UVC_FMT_FLAG_COMPRESSED                0x00000001
@@ -456,6 +457,8 @@ struct uvc_streaming {
        struct uvc_format *def_format;
        struct uvc_format *cur_format;
        struct uvc_frame *cur_frame;
+       size_t frame_size;
+
        /* Protect access to ctrl, cur_format, cur_frame and hardware video
         * probe control.
         */
@@ -688,7 +691,7 @@ extern int uvc_ctrl_add_mapping(struct uvc_video_chain *chain,
                const struct uvc_control_mapping *mapping);
 extern int uvc_ctrl_init_device(struct uvc_device *dev);
 extern void uvc_ctrl_cleanup_device(struct uvc_device *dev);
-extern int uvc_ctrl_resume_device(struct uvc_device *dev);
+extern int uvc_ctrl_restore_values(struct uvc_device *dev);
 
 extern int uvc_ctrl_begin(struct uvc_video_chain *chain);
 extern int __uvc_ctrl_commit(struct uvc_fh *handle, int rollback,
index 06c18ba16fa0427cc71fff76f08c140f55b05384..559f8372e2eb3d9bfc021da1196582d3f438ba21 100644 (file)
@@ -601,7 +601,7 @@ static int tuner_probe(struct i2c_client *client,
        t->name = "(tuner unset)";
        t->type = UNSET;
        t->audmode = V4L2_TUNER_MODE_STEREO;
-       t->standby = 1;
+       t->standby = true;
        t->radio_freq = 87.5 * 16000;   /* Initial freq range */
        t->tv_freq = 400 * 16; /* Sets freq to VHF High - needed for some PLL's to properly start */
 
@@ -1260,7 +1260,9 @@ static int tuner_suspend(struct device *dev)
 
        tuner_dbg("suspend\n");
 
-       if (!t->standby && analog_ops->standby)
+       if (t->fe.ops.tuner_ops.suspend)
+               t->fe.ops.tuner_ops.suspend(&t->fe);
+       else if (!t->standby && analog_ops->standby)
                analog_ops->standby(&t->fe);
 
        return 0;
@@ -1273,7 +1275,9 @@ static int tuner_resume(struct device *dev)
 
        tuner_dbg("resume\n");
 
-       if (!t->standby)
+       if (t->fe.ops.tuner_ops.resume)
+               t->fe.ops.tuner_ops.resume(&t->fe);
+       else if (!t->standby)
                if (set_mode(t, t->mode) == 0)
                        set_freq(t, 0);
 
index ccaa38f65cf189cf1874e9ed514ea62aa603d50f..2e9d81f4c1a57e9f51cd728b991c887558d11c72 100644 (file)
@@ -435,16 +435,13 @@ static unsigned int clamp_align(unsigned int x, unsigned int min,
        /* Bits that must be zero to be aligned */
        unsigned int mask = ~((1 << align) - 1);
 
+       /* Clamp to aligned min and max */
+       x = clamp(x, (min + ~mask) & mask, max & mask);
+
        /* Round to nearest aligned value */
        if (align)
                x = (x + (1 << (align - 1))) & mask;
 
-       /* Clamp to aligned value of min and max */
-       if (x < min)
-               x = (min + ~mask) & mask;
-       else if (x > max)
-               x = max & mask;
-
        return x;
 }
 
index cca6c2f76b3a3ed75c4398a2f67d302be41ee384..e502a5fb299471b2912bf15f25b5aada4aede3dd 100644 (file)
@@ -328,7 +328,7 @@ struct v4l2_buffer32 {
        __u32                   reserved;
 };
 
-static int get_v4l2_plane32(struct v4l2_plane *up, struct v4l2_plane32 *up32,
+static int get_v4l2_plane32(struct v4l2_plane __user *up, struct v4l2_plane32 __user *up32,
                                enum v4l2_memory memory)
 {
        void __user *up_pln;
@@ -357,7 +357,7 @@ static int get_v4l2_plane32(struct v4l2_plane *up, struct v4l2_plane32 *up32,
        return 0;
 }
 
-static int put_v4l2_plane32(struct v4l2_plane *up, struct v4l2_plane32 *up32,
+static int put_v4l2_plane32(struct v4l2_plane __user *up, struct v4l2_plane32 __user *up32,
                                enum v4l2_memory memory)
 {
        if (copy_in_user(up32, up, 2 * sizeof(__u32)) ||
@@ -427,7 +427,7 @@ static int get_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user
                 * by passing a very big num_planes value */
                uplane = compat_alloc_user_space(num_planes *
                                                sizeof(struct v4l2_plane));
-               kp->m.planes = uplane;
+               kp->m.planes = (__force struct v4l2_plane *)uplane;
 
                while (--num_planes >= 0) {
                        ret = get_v4l2_plane32(uplane, uplane32, kp->memory);
@@ -498,7 +498,7 @@ static int put_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user
                if (num_planes == 0)
                        return 0;
 
-               uplane = kp->m.planes;
+               uplane = (__force struct v4l2_plane __user *)kp->m.planes;
                if (get_user(p, &up->m.planes))
                        return -EFAULT;
                uplane32 = compat_ptr(p);
@@ -562,7 +562,7 @@ static int get_v4l2_framebuffer32(struct v4l2_framebuffer *kp, struct v4l2_frame
                get_user(kp->flags, &up->flags) ||
                copy_from_user(&kp->fmt, &up->fmt, sizeof(up->fmt)))
                        return -EFAULT;
-       kp->base = compat_ptr(tmp);
+       kp->base = (__force void *)compat_ptr(tmp);
        return 0;
 }
 
@@ -667,11 +667,15 @@ static int get_v4l2_ext_controls32(struct v4l2_ext_controls *kp, struct v4l2_ext
                        n * sizeof(struct v4l2_ext_control32)))
                return -EFAULT;
        kcontrols = compat_alloc_user_space(n * sizeof(struct v4l2_ext_control));
-       kp->controls = kcontrols;
+       kp->controls = (__force struct v4l2_ext_control *)kcontrols;
        while (--n >= 0) {
+               u32 id;
+
                if (copy_in_user(kcontrols, ucontrols, sizeof(*ucontrols)))
                        return -EFAULT;
-               if (ctrl_is_pointer(kcontrols->id)) {
+               if (get_user(id, &kcontrols->id))
+                       return -EFAULT;
+               if (ctrl_is_pointer(id)) {
                        void __user *s;
 
                        if (get_user(p, &ucontrols->string))
@@ -689,7 +693,8 @@ static int get_v4l2_ext_controls32(struct v4l2_ext_controls *kp, struct v4l2_ext
 static int put_v4l2_ext_controls32(struct v4l2_ext_controls *kp, struct v4l2_ext_controls32 __user *up)
 {
        struct v4l2_ext_control32 __user *ucontrols;
-       struct v4l2_ext_control __user *kcontrols = kp->controls;
+       struct v4l2_ext_control __user *kcontrols =
+               (__force struct v4l2_ext_control __user *)kp->controls;
        int n = kp->count;
        compat_caddr_t p;
 
@@ -711,11 +716,14 @@ static int put_v4l2_ext_controls32(struct v4l2_ext_controls *kp, struct v4l2_ext
 
        while (--n >= 0) {
                unsigned size = sizeof(*ucontrols);
+               u32 id;
 
+               if (get_user(id, &kcontrols->id))
+                       return -EFAULT;
                /* Do not modify the pointer when copying a pointer control.
                   The contents of the pointer was changed, not the pointer
                   itself. */
-               if (ctrl_is_pointer(kcontrols->id))
+               if (ctrl_is_pointer(id))
                        size -= sizeof(ucontrols->value64);
                if (copy_in_user(ucontrols, kcontrols, size))
                        return -EFAULT;
@@ -770,7 +778,7 @@ static int get_v4l2_edid32(struct v4l2_edid *kp, struct v4l2_edid32 __user *up)
                get_user(tmp, &up->edid) ||
                copy_from_user(kp->reserved, up->reserved, sizeof(kp->reserved)))
                        return -EFAULT;
-       kp->edid = compat_ptr(tmp);
+       kp->edid = (__force u8 *)compat_ptr(tmp);
        return 0;
 }
 
@@ -783,7 +791,7 @@ static int put_v4l2_edid32(struct v4l2_edid *kp, struct v4l2_edid32 __user *up)
                put_user(kp->start_block, &up->start_block) ||
                put_user(kp->blocks, &up->blocks) ||
                put_user(tmp, &up->edid) ||
-               copy_to_user(kp->reserved, up->reserved, sizeof(kp->reserved)))
+               copy_to_user(up->reserved, kp->reserved, sizeof(up->reserved)))
                        return -EFAULT;
        return 0;
 }
index f030d6a9e04421f2fcd63c9fce6fc713cdc897f1..86012140923fcf57526952c975a9516084f174f1 100644 (file)
@@ -796,6 +796,8 @@ const char *v4l2_ctrl_get_name(u32 id)
        case V4L2_CID_AUTO_FOCUS_STOP:          return "Auto Focus, Stop";
        case V4L2_CID_AUTO_FOCUS_STATUS:        return "Auto Focus, Status";
        case V4L2_CID_AUTO_FOCUS_RANGE:         return "Auto Focus, Range";
+       case V4L2_CID_PAN_SPEED:                return "Pan, Speed";
+       case V4L2_CID_TILT_SPEED:               return "Tilt, Speed";
 
        /* FM Radio Modulator controls */
        /* Keep the order of the 'case's the same as in v4l2-controls.h! */
@@ -859,6 +861,10 @@ const char *v4l2_ctrl_get_name(u32 id)
        case V4L2_CID_VBLANK:                   return "Vertical Blanking";
        case V4L2_CID_HBLANK:                   return "Horizontal Blanking";
        case V4L2_CID_ANALOGUE_GAIN:            return "Analogue Gain";
+       case V4L2_CID_TEST_PATTERN_RED:         return "Red Pixel Value";
+       case V4L2_CID_TEST_PATTERN_GREENR:      return "Green (Red) Pixel Value";
+       case V4L2_CID_TEST_PATTERN_BLUE:        return "Blue Pixel Value";
+       case V4L2_CID_TEST_PATTERN_GREENB:      return "Green (Blue) Pixel Value";
 
        /* Image processing controls */
        /* Keep the order of the 'case's the same as in v4l2-controls.h! */
index ce1c9f5d9dee1040c43f798b5163c4821feabbfd..b1d8dbb39665eab512f8dd59abdfac63fbed43e2 100644 (file)
@@ -164,7 +164,8 @@ bool v4l2_valid_dv_timings(const struct v4l2_dv_timings *t,
            bt->width > cap->max_width ||
            bt->pixelclock < cap->min_pixelclock ||
            bt->pixelclock > cap->max_pixelclock ||
-           (cap->standards && !(bt->standards & cap->standards)) ||
+           (cap->standards && bt->standards &&
+            !(bt->standards & cap->standards)) ||
            (bt->interlaced && !(caps & V4L2_DV_BT_CAP_INTERLACED)) ||
            (!bt->interlaced && !(caps & V4L2_DV_BT_CAP_PROGRESSIVE)))
                return false;
index d15e16737eef4e0fd6d58d9babcba00ddcd2df77..9ccb19a435ef7a04a7d125af5a5b86c3b130a79d 100644 (file)
@@ -562,7 +562,7 @@ static void v4l_print_ext_controls(const void *arg, bool write_only)
        pr_cont("class=0x%x, count=%d, error_idx=%d",
                        p->ctrl_class, p->count, p->error_idx);
        for (i = 0; i < p->count; i++) {
-               if (p->controls[i].size)
+               if (!p->controls[i].size)
                        pr_cont(", id/val=0x%x/0x%x",
                                p->controls[i].id, p->controls[i].value);
                else
@@ -1153,9 +1153,9 @@ static int v4l_g_fmt(const struct v4l2_ioctl_ops *ops,
        switch (p->type) {
        case V4L2_BUF_TYPE_VIDEO_OVERLAY:
        case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY: {
-               struct v4l2_clip *clips = p->fmt.win.clips;
+               struct v4l2_clip __user *clips = p->fmt.win.clips;
                u32 clipcount = p->fmt.win.clipcount;
-               void *bitmap = p->fmt.win.bitmap;
+               void __user *bitmap = p->fmt.win.bitmap;
 
                memset(&p->fmt, 0, sizeof(p->fmt));
                p->fmt.win.clips = clips;
index b4d235c13fbfc43d12decce919e9dc367e094ea5..543631c3557ab94ec264164532403d33b0eb5497 100644 (file)
@@ -501,11 +501,20 @@ int v4l2_subdev_link_validate_default(struct v4l2_subdev *sd,
                                      struct v4l2_subdev_format *source_fmt,
                                      struct v4l2_subdev_format *sink_fmt)
 {
+       /* The width, height and code must match. */
        if (source_fmt->format.width != sink_fmt->format.width
            || source_fmt->format.height != sink_fmt->format.height
            || source_fmt->format.code != sink_fmt->format.code)
                return -EINVAL;
 
+       /* The field order must match, or the sink field order must be NONE
+        * to support interlaced hardware connected to bridges that support
+        * progressive formats only.
+        */
+       if (source_fmt->format.field != sink_fmt->format.field &&
+           sink_fmt->format.field != V4L2_FIELD_NONE)
+               return -EINVAL;
+
        return 0;
 }
 EXPORT_SYMBOL_GPL(v4l2_subdev_link_validate_default);
index fb5ee5dd8fe933cbdd371aeecf41a3047d2e0e39..b91a266d0b7efcced9ad3bbca2b08cb398377505 100644 (file)
@@ -441,11 +441,6 @@ int videobuf_reqbufs(struct videobuf_queue *q,
        unsigned int size, count;
        int retval;
 
-       if (req->count < 1) {
-               dprintk(1, "reqbufs: count invalid (%d)\n", req->count);
-               return -EINVAL;
-       }
-
        if (req->memory != V4L2_MEMORY_MMAP     &&
            req->memory != V4L2_MEMORY_USERPTR  &&
            req->memory != V4L2_MEMORY_OVERLAY) {
@@ -471,6 +466,12 @@ int videobuf_reqbufs(struct videobuf_queue *q,
                goto done;
        }
 
+       if (req->count == 0) {
+               dprintk(1, "reqbufs: count invalid (%d)\n", req->count);
+               retval = __videobuf_free(q);
+               goto done;
+       }
+
        count = req->count;
        if (count > VIDEO_MAX_FRAME)
                count = VIDEO_MAX_FRAME;
index 3c8cc023a5a5e3c2718545b8814664fbf02be291..3ff15f1c9d702219b33a43e3df0e9eb07fab93e6 100644 (file)
@@ -253,9 +253,11 @@ int videobuf_dma_init_kernel(struct videobuf_dmabuf *dma, int direction,
        return 0;
 out_free_pages:
        while (i > 0) {
-               void *addr = page_address(dma->vaddr_pages[i]);
-               dma_free_coherent(dma->dev, PAGE_SIZE, addr, dma->dma_addr[i]);
+               void *addr;
+
                i--;
+               addr = page_address(dma->vaddr_pages[i]);
+               dma_free_coherent(dma->dev, PAGE_SIZE, addr, dma->dma_addr[i]);
        }
        kfree(dma->dma_addr);
        dma->dma_addr = NULL;
index 25d3ae2188cb29fc2338e0dc976d21db17829447..f2e43de3dd879330fbc6a230d6d267f5c6efdf0d 100644 (file)
@@ -36,7 +36,7 @@ module_param(debug, int, 0644);
 #define dprintk(level, fmt, arg...)                                          \
        do {                                                                  \
                if (debug >= level)                                           \
-                       pr_debug("vb2: %s: " fmt, __func__, ## arg); \
+                       pr_info("vb2: %s: " fmt, __func__, ## arg); \
        } while (0)
 
 #ifdef CONFIG_VIDEO_ADV_DEBUG
@@ -882,7 +882,9 @@ static int __reqbufs(struct vb2_queue *q, struct v4l2_requestbuffers *req)
                 * We already have buffers allocated, so first check if they
                 * are not in use and can be freed.
                 */
+               mutex_lock(&q->mmap_lock);
                if (q->memory == V4L2_MEMORY_MMAP && __buffers_in_use(q)) {
+                       mutex_unlock(&q->mmap_lock);
                        dprintk(1, "memory in use, cannot free\n");
                        return -EBUSY;
                }
@@ -894,6 +896,7 @@ static int __reqbufs(struct vb2_queue *q, struct v4l2_requestbuffers *req)
                 */
                __vb2_queue_cancel(q);
                ret = __vb2_queue_free(q, q->num_buffers);
+               mutex_unlock(&q->mmap_lock);
                if (ret)
                        return ret;
 
@@ -955,6 +958,7 @@ static int __reqbufs(struct vb2_queue *q, struct v4l2_requestbuffers *req)
                 */
        }
 
+       mutex_lock(&q->mmap_lock);
        q->num_buffers = allocated_buffers;
 
        if (ret < 0) {
@@ -963,8 +967,10 @@ static int __reqbufs(struct vb2_queue *q, struct v4l2_requestbuffers *req)
                 * from q->num_buffers.
                 */
                __vb2_queue_free(q, allocated_buffers);
+               mutex_unlock(&q->mmap_lock);
                return ret;
        }
+       mutex_unlock(&q->mmap_lock);
 
        /*
         * Return the number of successfully allocated buffers
@@ -1063,6 +1069,7 @@ static int __create_bufs(struct vb2_queue *q, struct v4l2_create_buffers *create
                 */
        }
 
+       mutex_lock(&q->mmap_lock);
        q->num_buffers += allocated_buffers;
 
        if (ret < 0) {
@@ -1071,8 +1078,10 @@ static int __create_bufs(struct vb2_queue *q, struct v4l2_create_buffers *create
                 * from q->num_buffers.
                 */
                __vb2_queue_free(q, allocated_buffers);
+               mutex_unlock(&q->mmap_lock);
                return -ENOMEM;
        }
+       mutex_unlock(&q->mmap_lock);
 
        /*
         * Return the number of successfully allocated buffers
@@ -1581,7 +1590,6 @@ static void __enqueue_in_driver(struct vb2_buffer *vb)
 static int __buf_prepare(struct vb2_buffer *vb, const struct v4l2_buffer *b)
 {
        struct vb2_queue *q = vb->vb2_queue;
-       struct rw_semaphore *mmap_sem;
        int ret;
 
        ret = __verify_length(vb, b);
@@ -1618,26 +1626,9 @@ static int __buf_prepare(struct vb2_buffer *vb, const struct v4l2_buffer *b)
                ret = __qbuf_mmap(vb, b);
                break;
        case V4L2_MEMORY_USERPTR:
-               /*
-                * In case of user pointer buffers vb2 allocators need to get
-                * direct access to userspace pages. This requires getting
-                * the mmap semaphore for read access in the current process
-                * structure. The same semaphore is taken before calling mmap
-                * operation, while both qbuf/prepare_buf and mmap are called
-                * by the driver or v4l2 core with the driver's lock held.
-                * To avoid an AB-BA deadlock (mmap_sem then driver's lock in
-                * mmap and driver's lock then mmap_sem in qbuf/prepare_buf),
-                * the videobuf2 core releases the driver's lock, takes
-                * mmap_sem and then takes the driver's lock again.
-                */
-               mmap_sem = &current->mm->mmap_sem;
-               call_void_qop(q, wait_prepare, q);
-               down_read(mmap_sem);
-               call_void_qop(q, wait_finish, q);
-
+               down_read(&current->mm->mmap_sem);
                ret = __qbuf_userptr(vb, b);
-
-               up_read(mmap_sem);
+               up_read(&current->mm->mmap_sem);
                break;
        case V4L2_MEMORY_DMABUF:
                ret = __qbuf_dmabuf(vb, b);
@@ -2504,7 +2495,9 @@ int vb2_mmap(struct vb2_queue *q, struct vm_area_struct *vma)
                return -EINVAL;
        }
 
+       mutex_lock(&q->mmap_lock);
        ret = call_memop(vb, mmap, vb->planes[plane].mem_priv, vma);
+       mutex_unlock(&q->mmap_lock);
        if (ret)
                return ret;
 
@@ -2523,6 +2516,7 @@ unsigned long vb2_get_unmapped_area(struct vb2_queue *q,
        unsigned long off = pgoff << PAGE_SHIFT;
        struct vb2_buffer *vb;
        unsigned int buffer, plane;
+       void *vaddr;
        int ret;
 
        if (q->memory != V4L2_MEMORY_MMAP) {
@@ -2539,7 +2533,8 @@ unsigned long vb2_get_unmapped_area(struct vb2_queue *q,
 
        vb = q->bufs[buffer];
 
-       return (unsigned long)vb2_plane_vaddr(vb, plane);
+       vaddr = vb2_plane_vaddr(vb, plane);
+       return vaddr ? (unsigned long)vaddr : -EINVAL;
 }
 EXPORT_SYMBOL_GPL(vb2_get_unmapped_area);
 #endif
@@ -2686,6 +2681,7 @@ int vb2_queue_init(struct vb2_queue *q)
        INIT_LIST_HEAD(&q->queued_list);
        INIT_LIST_HEAD(&q->done_list);
        spin_lock_init(&q->done_lock);
+       mutex_init(&q->mmap_lock);
        init_waitqueue_head(&q->done_wq);
 
        if (q->buf_struct_size == 0)
@@ -2707,7 +2703,9 @@ void vb2_queue_release(struct vb2_queue *q)
 {
        __vb2_cleanup_fileio(q);
        __vb2_queue_cancel(q);
+       mutex_lock(&q->mmap_lock);
        __vb2_queue_free(q, q->num_buffers);
+       mutex_unlock(&q->mmap_lock);
 }
 EXPORT_SYMBOL_GPL(vb2_queue_release);
 
@@ -2985,6 +2983,12 @@ static size_t __vb2_perform_fileio(struct vb2_queue *q, char __user *data, size_
                buf->queued = 0;
                buf->size = read ? vb2_get_plane_payload(q->bufs[index], 0)
                                 : vb2_plane_size(q->bufs[index], 0);
+               /* Compensate for data_offset on read in the multiplanar case. */
+               if (is_multiplanar && read &&
+                   fileio->b.m.planes[0].data_offset < buf->size) {
+                       buf->pos = fileio->b.m.planes[0].data_offset;
+                       buf->size -= buf->pos;
+               }
        } else {
                buf = &fileio->bufs[index];
        }
@@ -3372,15 +3376,8 @@ EXPORT_SYMBOL_GPL(vb2_ioctl_expbuf);
 int vb2_fop_mmap(struct file *file, struct vm_area_struct *vma)
 {
        struct video_device *vdev = video_devdata(file);
-       struct mutex *lock = vdev->queue->lock ? vdev->queue->lock : vdev->lock;
-       int err;
 
-       if (lock && mutex_lock_interruptible(lock))
-               return -ERESTARTSYS;
-       err = vb2_mmap(vdev->queue, vma);
-       if (lock)
-               mutex_unlock(lock);
-       return err;
+       return vb2_mmap(vdev->queue, vma);
 }
 EXPORT_SYMBOL_GPL(vb2_fop_mmap);
 
@@ -3499,15 +3496,8 @@ unsigned long vb2_fop_get_unmapped_area(struct file *file, unsigned long addr,
                unsigned long len, unsigned long pgoff, unsigned long flags)
 {
        struct video_device *vdev = video_devdata(file);
-       struct mutex *lock = vdev->queue->lock ? vdev->queue->lock : vdev->lock;
-       int ret;
 
-       if (lock && mutex_lock_interruptible(lock))
-               return -ERESTARTSYS;
-       ret = vb2_get_unmapped_area(vdev->queue, addr, len, pgoff, flags);
-       if (lock)
-               mutex_unlock(lock);
-       return ret;
+       return vb2_get_unmapped_area(vdev->queue, addr, len, pgoff, flags);
 }
 EXPORT_SYMBOL_GPL(vb2_fop_get_unmapped_area);
 #endif
index 31727bf285d0de164d00024a5c34fe539403c94d..e2a4f5f415b2be30d0b223d7fac1e423dec411cf 100644 (file)
@@ -188,6 +188,7 @@ static void r592_host_reset(struct r592_device *dev)
        r592_set_mode(dev, dev->parallel_mode);
 }
 
+#ifdef CONFIG_PM_SLEEP
 /* Disable all hardware interrupts */
 static void r592_clear_interrupts(struct r592_device *dev)
 {
@@ -195,6 +196,7 @@ static void r592_clear_interrupts(struct r592_device *dev)
        r592_clear_reg_mask(dev, R592_REG_MSC, IRQ_ALL_ACK_MASK);
        r592_clear_reg_mask(dev, R592_REG_MSC, IRQ_ALL_EN_MASK);
 }
+#endif
 
 /* Tests if there is an CRC error */
 static int r592_test_io_error(struct r592_device *dev)
index de5abf244746ac7dc32e99d02b61d131e4877a77..cf66ef1ffaf32d59b60ed2ff30873988ec2bd3e4 100644 (file)
@@ -454,6 +454,21 @@ config MFD_MAX8998
          additional drivers must be enabled in order to use the functionality
          of the device.
 
+config MFD_MENF21BMC
+       tristate "MEN 14F021P00 Board Management Controller Support"
+       depends on I2C
+       select MFD_CORE
+       help
+         Say yes here to add support for the MEN 14F021P00 BMC
+         which is a Board Management Controller connected to the I2C bus.
+         The device supports multiple sub-devices like LED, HWMON and WDT.
+         This driver provides common support for accessing the devices;
+         additional drivers must be enabled in order to use the
+         functionality of the BMC device.
+
+         This driver can also be built as a module. If so the module
+         will be called menf21bmc.
+
 config EZX_PCAP
        bool "Motorola EZXPCAP Support"
        depends on SPI_MASTER
index f00148782d9b3c234609ad10827430ec84c2a56b..d58068aa8aa9492fbbdd432123e4b5749d819bbf 100644 (file)
@@ -169,6 +169,7 @@ obj-$(CONFIG_MFD_AS3711)    += as3711.o
 obj-$(CONFIG_MFD_AS3722)       += as3722.o
 obj-$(CONFIG_MFD_STW481X)      += stw481x.o
 obj-$(CONFIG_MFD_IPAQ_MICRO)   += ipaq-micro.o
+obj-$(CONFIG_MFD_MENF21BMC)    += menf21bmc.o
 
 intel-soc-pmic-objs            := intel_soc_pmic_core.o intel_soc_pmic_crc.o
 obj-$(CONFIG_INTEL_SOC_PMIC)   += intel-soc-pmic.o
diff --git a/drivers/mfd/menf21bmc.c b/drivers/mfd/menf21bmc.c
new file mode 100644 (file)
index 0000000..1c27434
--- /dev/null
@@ -0,0 +1,132 @@
+/*
+ *  MEN 14F021P00 Board Management Controller (BMC) MFD Core Driver.
+ *
+ *  Copyright (C) 2014 MEN Mikro Elektronik Nuernberg GmbH
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ */
+
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/mfd/core.h>
+
+#define BMC_CMD_WDT_EXIT_PROD  0x18
+#define BMC_CMD_WDT_PROD_STAT  0x19
+#define BMC_CMD_REV_MAJOR      0x80
+#define BMC_CMD_REV_MINOR      0x81
+#define BMC_CMD_REV_MAIN       0x82
+
+static struct mfd_cell menf21bmc_cell[] = {
+       { .name = "menf21bmc_wdt", },
+       { .name = "menf21bmc_led", },
+       { .name = "menf21bmc_hwmon", }
+};
+
+static int menf21bmc_wdt_exit_prod_mode(struct i2c_client *client)
+{
+       int val, ret;
+
+       val = i2c_smbus_read_byte_data(client, BMC_CMD_WDT_PROD_STAT);
+       if (val < 0)
+               return val;
+
+       /*
+        * Production mode should be not active after delivery of the Board.
+        * To be sure we check it, inform the user and exit the mode
+        * if active.
+        */
+       if (val == 0x00) {
+               dev_info(&client->dev,
+                       "BMC in production mode. Exit production mode\n");
+
+               ret = i2c_smbus_write_byte(client, BMC_CMD_WDT_EXIT_PROD);
+               if (ret < 0)
+                       return ret;
+       }
+
+       return 0;
+}
+
+static int
+menf21bmc_probe(struct i2c_client *client, const struct i2c_device_id *ids)
+{
+       int rev_major, rev_minor, rev_main;
+       int ret;
+
+       ret = i2c_check_functionality(client->adapter,
+                                     I2C_FUNC_SMBUS_BYTE_DATA |
+                                     I2C_FUNC_SMBUS_WORD_DATA |
+                                     I2C_FUNC_SMBUS_BYTE);
+       if (!ret)
+               return -ENODEV;
+
+       rev_major = i2c_smbus_read_word_data(client, BMC_CMD_REV_MAJOR);
+       if (rev_major < 0) {
+               dev_err(&client->dev, "failed to get BMC major revision\n");
+               return rev_major;
+       }
+
+       rev_minor = i2c_smbus_read_word_data(client, BMC_CMD_REV_MINOR);
+       if (rev_minor < 0) {
+               dev_err(&client->dev, "failed to get BMC minor revision\n");
+               return rev_minor;
+       }
+
+       rev_main = i2c_smbus_read_word_data(client, BMC_CMD_REV_MAIN);
+       if (rev_main < 0) {
+               dev_err(&client->dev, "failed to get BMC main revision\n");
+               return rev_main;
+       }
+
+       dev_info(&client->dev, "FW Revision: %02d.%02d.%02d\n",
+                rev_major, rev_minor, rev_main);
+
+       /*
+        * We have to exit the Production Mode of the BMC to activate the
+        * Watchdog functionality and the BIOS life sign monitoring.
+        */
+       ret = menf21bmc_wdt_exit_prod_mode(client);
+       if (ret < 0) {
+               dev_err(&client->dev, "failed to leave production mode\n");
+               return ret;
+       }
+
+       ret = mfd_add_devices(&client->dev, 0, menf21bmc_cell,
+                             ARRAY_SIZE(menf21bmc_cell), NULL, 0, NULL);
+       if (ret < 0) {
+               dev_err(&client->dev, "failed to add BMC sub-devices\n");
+               return ret;
+       }
+
+       return 0;
+}
+
+static int menf21bmc_remove(struct i2c_client *client)
+{
+       mfd_remove_devices(&client->dev);
+       return 0;
+}
+
+static const struct i2c_device_id menf21bmc_id_table[] = {
+       { "menf21bmc" },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, menf21bmc_id_table);
+
+static struct i2c_driver menf21bmc_driver = {
+       .driver.name    = "menf21bmc",
+       .id_table       = menf21bmc_id_table,
+       .probe          = menf21bmc_probe,
+       .remove         = menf21bmc_remove,
+};
+
+module_i2c_driver(menf21bmc_driver);
+
+MODULE_DESCRIPTION("MEN 14F021P00 BMC mfd core driver");
+MODULE_AUTHOR("Andreas Werner <andreas.werner@men.de>");
+MODULE_LICENSE("GPL v2");
index b841180c7c742f57f63f1345453720b4bb9725a3..bbeb4516facf239b7bce979f6993ae38f1e4e459 100644 (file)
@@ -527,4 +527,5 @@ source "drivers/misc/vmw_vmci/Kconfig"
 source "drivers/misc/mic/Kconfig"
 source "drivers/misc/genwqe/Kconfig"
 source "drivers/misc/echo/Kconfig"
+source "drivers/misc/cxl/Kconfig"
 endmenu
index 5497d026e651f47ffdaaf8bcac9a67cd30c4b2a9..7d5c4cd118c44fbf052425d2d61e3ec3cc1ae455 100644 (file)
@@ -55,3 +55,4 @@ obj-y                         += mic/
 obj-$(CONFIG_GENWQE)           += genwqe/
 obj-$(CONFIG_ECHO)             += echo/
 obj-$(CONFIG_VEXPRESS_SYSCFG)  += vexpress-syscfg.o
+obj-$(CONFIG_CXL_BASE)         += cxl/
index 24272e022bec926f729d6cf26fd5953e63316ad7..bca2630d006f4d088b4873e08a399983bc845615 100644 (file)
@@ -454,7 +454,7 @@ exit_done:
 
                                name = &p[str_table + name_id];
 
-                               if (strnicmp(aconf->action, name, strlen(name)) == 0) {
+                               if (strncasecmp(aconf->action, name, strlen(name)) == 0) {
                                        action_found = 1;
                                        current_proc =
                                                get_unaligned_be32(&p[action_table +
@@ -2176,7 +2176,7 @@ static int altera_get_note(u8 *p, s32 program_size,
                        key_ptr = &p[note_strings +
                                        get_unaligned_be32(
                                        &p[note_table + (8 * i)])];
-                       if ((strnicmp(key, key_ptr, strlen(key_ptr)) == 0) &&
+                       if ((strncasecmp(key, key_ptr, strlen(key_ptr)) == 0) &&
                                                (key != NULL)) {
                                status = 0;
 
index 7be89832db19f90ca2e1182fe91b77fa08efcea1..7e97e53f9ff2474fd1741b911c43a277d8408ea2 100644 (file)
@@ -749,13 +749,8 @@ static ssize_t fpga_read(struct file *filp, char __user *buf, size_t count,
                         loff_t *f_pos)
 {
        struct fpga_dev *priv = filp->private_data;
-
-       count = min_t(size_t, priv->bytes - *f_pos, count);
-       if (copy_to_user(buf, priv->vb.vaddr + *f_pos, count))
-               return -EFAULT;
-
-       *f_pos += count;
-       return count;
+       return simple_read_from_buffer(buf, count, ppos,
+                                      priv->vb.vaddr, priv->bytes);
 }
 
 static loff_t fpga_llseek(struct file *filp, loff_t offset, int origin)
@@ -767,26 +762,7 @@ static loff_t fpga_llseek(struct file *filp, loff_t offset, int origin)
        if ((filp->f_flags & O_ACCMODE) != O_RDONLY)
                return -EINVAL;
 
-       switch (origin) {
-       case SEEK_SET: /* seek relative to the beginning of the file */
-               newpos = offset;
-               break;
-       case SEEK_CUR: /* seek relative to current position in the file */
-               newpos = filp->f_pos + offset;
-               break;
-       case SEEK_END: /* seek relative to the end of the file */
-               newpos = priv->fw_size - offset;
-               break;
-       default:
-               return -EINVAL;
-       }
-
-       /* check for sanity */
-       if (newpos > priv->fw_size)
-               return -EINVAL;
-
-       filp->f_pos = newpos;
-       return newpos;
+       return fixed_size_llseek(file, offset, origin, priv->fw_size);
 }
 
 static const struct file_operations fpga_fops = {
diff --git a/drivers/misc/cxl/Kconfig b/drivers/misc/cxl/Kconfig
new file mode 100644 (file)
index 0000000..a990b39
--- /dev/null
@@ -0,0 +1,25 @@
+#
+# IBM Coherent Accelerator (CXL) compatible devices
+#
+
+config CXL_BASE
+       bool
+       default n
+       select PPC_COPRO_BASE
+
+config CXL
+       tristate "Support for IBM Coherent Accelerators (CXL)"
+       depends on PPC_POWERNV && PCI_MSI
+       select CXL_BASE
+       default m
+       help
+         Select this option to enable driver support for IBM Coherent
+         Accelerators (CXL).  CXL is otherwise known as Coherent Accelerator
+         Processor Interface (CAPI).  CAPI allows accelerators in FPGAs to be
+         coherently attached to a CPU via an MMU.  This driver enables
+         userspace programs to access these accelerators via /dev/cxl/afuM.N
+         devices.
+
+         CAPI adapters are found in POWER8 based systems.
+
+         If unsure, say N.
diff --git a/drivers/misc/cxl/Makefile b/drivers/misc/cxl/Makefile
new file mode 100644 (file)
index 0000000..165e98f
--- /dev/null
@@ -0,0 +1,3 @@
+cxl-y                          += main.o file.o irq.o fault.o native.o context.o sysfs.o debugfs.o pci.o
+obj-$(CONFIG_CXL)              += cxl.o
+obj-$(CONFIG_CXL_BASE)         += base.o
diff --git a/drivers/misc/cxl/base.c b/drivers/misc/cxl/base.c
new file mode 100644 (file)
index 0000000..0654ad8
--- /dev/null
@@ -0,0 +1,86 @@
+/*
+ * Copyright 2014 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.
+ */
+
+#include <linux/module.h>
+#include <linux/rcupdate.h>
+#include <asm/errno.h>
+#include <misc/cxl.h>
+#include "cxl.h"
+
+/* protected by rcu */
+static struct cxl_calls *cxl_calls;
+
+atomic_t cxl_use_count = ATOMIC_INIT(0);
+EXPORT_SYMBOL(cxl_use_count);
+
+#ifdef CONFIG_CXL_MODULE
+
+static inline struct cxl_calls *cxl_calls_get(void)
+{
+       struct cxl_calls *calls = NULL;
+
+       rcu_read_lock();
+       calls = rcu_dereference(cxl_calls);
+       if (calls && !try_module_get(calls->owner))
+               calls = NULL;
+       rcu_read_unlock();
+
+       return calls;
+}
+
+static inline void cxl_calls_put(struct cxl_calls *calls)
+{
+       BUG_ON(calls != cxl_calls);
+
+       /* we don't need to rcu this, as we hold a reference to the module */
+       module_put(cxl_calls->owner);
+}
+
+#else /* !defined CONFIG_CXL_MODULE */
+
+static inline struct cxl_calls *cxl_calls_get(void)
+{
+       return cxl_calls;
+}
+
+static inline void cxl_calls_put(struct cxl_calls *calls) { }
+
+#endif /* CONFIG_CXL_MODULE */
+
+void cxl_slbia(struct mm_struct *mm)
+{
+       struct cxl_calls *calls;
+
+       calls = cxl_calls_get();
+       if (!calls)
+               return;
+
+       if (cxl_ctx_in_use())
+           calls->cxl_slbia(mm);
+
+       cxl_calls_put(calls);
+}
+
+int register_cxl_calls(struct cxl_calls *calls)
+{
+       if (cxl_calls)
+               return -EBUSY;
+
+       rcu_assign_pointer(cxl_calls, calls);
+       return 0;
+}
+EXPORT_SYMBOL_GPL(register_cxl_calls);
+
+void unregister_cxl_calls(struct cxl_calls *calls)
+{
+       BUG_ON(cxl_calls->owner != calls->owner);
+       RCU_INIT_POINTER(cxl_calls, NULL);
+       synchronize_rcu();
+}
+EXPORT_SYMBOL_GPL(unregister_cxl_calls);
diff --git a/drivers/misc/cxl/context.c b/drivers/misc/cxl/context.c
new file mode 100644 (file)
index 0000000..cca4721
--- /dev/null
@@ -0,0 +1,193 @@
+/*
+ * Copyright 2014 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.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/bitmap.h>
+#include <linux/sched.h>
+#include <linux/pid.h>
+#include <linux/fs.h>
+#include <linux/mm.h>
+#include <linux/debugfs.h>
+#include <linux/slab.h>
+#include <linux/idr.h>
+#include <asm/cputable.h>
+#include <asm/current.h>
+#include <asm/copro.h>
+
+#include "cxl.h"
+
+/*
+ * Allocates space for a CXL context.
+ */
+struct cxl_context *cxl_context_alloc(void)
+{
+       return kzalloc(sizeof(struct cxl_context), GFP_KERNEL);
+}
+
+/*
+ * Initialises a CXL context.
+ */
+int cxl_context_init(struct cxl_context *ctx, struct cxl_afu *afu, bool master)
+{
+       int i;
+
+       spin_lock_init(&ctx->sste_lock);
+       ctx->afu = afu;
+       ctx->master = master;
+       ctx->pid = NULL; /* Set in start work ioctl */
+
+       /*
+        * Allocate the segment table before we put it in the IDR so that we
+        * can always access it when dereferenced from IDR. For the same
+        * reason, the segment table is only destroyed after the context is
+        * removed from the IDR.  Access to this in the IOCTL is protected by
+        * Linux filesytem symantics (can't IOCTL until open is complete).
+        */
+       i = cxl_alloc_sst(ctx);
+       if (i)
+               return i;
+
+       INIT_WORK(&ctx->fault_work, cxl_handle_fault);
+
+       init_waitqueue_head(&ctx->wq);
+       spin_lock_init(&ctx->lock);
+
+       ctx->irq_bitmap = NULL;
+       ctx->pending_irq = false;
+       ctx->pending_fault = false;
+       ctx->pending_afu_err = false;
+
+       /*
+        * When we have to destroy all contexts in cxl_context_detach_all() we
+        * end up with afu_release_irqs() called from inside a
+        * idr_for_each_entry(). Hence we need to make sure that anything
+        * dereferenced from this IDR is ok before we allocate the IDR here.
+        * This clears out the IRQ ranges to ensure this.
+        */
+       for (i = 0; i < CXL_IRQ_RANGES; i++)
+               ctx->irqs.range[i] = 0;
+
+       mutex_init(&ctx->status_mutex);
+
+       ctx->status = OPENED;
+
+       /*
+        * Allocating IDR! We better make sure everything's setup that
+        * dereferences from it.
+        */
+       idr_preload(GFP_KERNEL);
+       spin_lock(&afu->contexts_lock);
+       i = idr_alloc(&ctx->afu->contexts_idr, ctx, 0,
+                     ctx->afu->num_procs, GFP_NOWAIT);
+       spin_unlock(&afu->contexts_lock);
+       idr_preload_end();
+       if (i < 0)
+               return i;
+
+       ctx->pe = i;
+       ctx->elem = &ctx->afu->spa[i];
+       ctx->pe_inserted = false;
+       return 0;
+}
+
+/*
+ * Map a per-context mmio space into the given vma.
+ */
+int cxl_context_iomap(struct cxl_context *ctx, struct vm_area_struct *vma)
+{
+       u64 len = vma->vm_end - vma->vm_start;
+       len = min(len, ctx->psn_size);
+
+       if (ctx->afu->current_mode == CXL_MODE_DEDICATED) {
+               vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+               return vm_iomap_memory(vma, ctx->afu->psn_phys, ctx->afu->adapter->ps_size);
+       }
+
+       /* make sure there is a valid per process space for this AFU */
+       if ((ctx->master && !ctx->afu->psa) || (!ctx->afu->pp_psa)) {
+               pr_devel("AFU doesn't support mmio space\n");
+               return -EINVAL;
+       }
+
+       /* Can't mmap until the AFU is enabled */
+       if (!ctx->afu->enabled)
+               return -EBUSY;
+
+       pr_devel("%s: mmio physical: %llx pe: %i master:%i\n", __func__,
+                ctx->psn_phys, ctx->pe , ctx->master);
+
+       vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+       return vm_iomap_memory(vma, ctx->psn_phys, len);
+}
+
+/*
+ * Detach a context from the hardware. This disables interrupts and doesn't
+ * return until all outstanding interrupts for this context have completed. The
+ * hardware should no longer access *ctx after this has returned.
+ */
+static void __detach_context(struct cxl_context *ctx)
+{
+       enum cxl_context_status status;
+
+       mutex_lock(&ctx->status_mutex);
+       status = ctx->status;
+       ctx->status = CLOSED;
+       mutex_unlock(&ctx->status_mutex);
+       if (status != STARTED)
+               return;
+
+       WARN_ON(cxl_detach_process(ctx));
+       afu_release_irqs(ctx);
+       flush_work(&ctx->fault_work); /* Only needed for dedicated process */
+       wake_up_all(&ctx->wq);
+}
+
+/*
+ * Detach the given context from the AFU. This doesn't actually
+ * free the context but it should stop the context running in hardware
+ * (ie. prevent this context from generating any further interrupts
+ * so that it can be freed).
+ */
+void cxl_context_detach(struct cxl_context *ctx)
+{
+       __detach_context(ctx);
+}
+
+/*
+ * Detach all contexts on the given AFU.
+ */
+void cxl_context_detach_all(struct cxl_afu *afu)
+{
+       struct cxl_context *ctx;
+       int tmp;
+
+       rcu_read_lock();
+       idr_for_each_entry(&afu->contexts_idr, ctx, tmp)
+               /*
+                * Anything done in here needs to be setup before the IDR is
+                * created and torn down after the IDR removed
+                */
+               __detach_context(ctx);
+       rcu_read_unlock();
+}
+
+void cxl_context_free(struct cxl_context *ctx)
+{
+       spin_lock(&ctx->afu->contexts_lock);
+       idr_remove(&ctx->afu->contexts_idr, ctx->pe);
+       spin_unlock(&ctx->afu->contexts_lock);
+       synchronize_rcu();
+
+       free_page((u64)ctx->sstp);
+       ctx->sstp = NULL;
+
+       put_pid(ctx->pid);
+       kfree(ctx);
+}
diff --git a/drivers/misc/cxl/cxl.h b/drivers/misc/cxl/cxl.h
new file mode 100644 (file)
index 0000000..3d2b867
--- /dev/null
@@ -0,0 +1,629 @@
+/*
+ * Copyright 2014 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.
+ */
+
+#ifndef _CXL_H_
+#define _CXL_H_
+
+#include <linux/interrupt.h>
+#include <linux/semaphore.h>
+#include <linux/device.h>
+#include <linux/types.h>
+#include <linux/cdev.h>
+#include <linux/pid.h>
+#include <linux/io.h>
+#include <linux/pci.h>
+#include <asm/cputable.h>
+#include <asm/mmu.h>
+#include <asm/reg.h>
+#include <misc/cxl.h>
+
+#include <uapi/misc/cxl.h>
+
+extern uint cxl_verbose;
+
+#define CXL_TIMEOUT 5
+
+/*
+ * Bump version each time a user API change is made, whether it is
+ * backwards compatible ot not.
+ */
+#define CXL_API_VERSION 1
+#define CXL_API_VERSION_COMPATIBLE 1
+
+/*
+ * Opaque types to avoid accidentally passing registers for the wrong MMIO
+ *
+ * At the end of the day, I'm not married to using typedef here, but it might
+ * (and has!) help avoid bugs like mixing up CXL_PSL_CtxTime and
+ * CXL_PSL_CtxTime_An, or calling cxl_p1n_write instead of cxl_p1_write.
+ *
+ * I'm quite happy if these are changed back to #defines before upstreaming, it
+ * should be little more than a regexp search+replace operation in this file.
+ */
+typedef struct {
+       const int x;
+} cxl_p1_reg_t;
+typedef struct {
+       const int x;
+} cxl_p1n_reg_t;
+typedef struct {
+       const int x;
+} cxl_p2n_reg_t;
+#define cxl_reg_off(reg) \
+       (reg.x)
+
+/* Memory maps. Ref CXL Appendix A */
+
+/* PSL Privilege 1 Memory Map */
+/* Configuration and Control area */
+static const cxl_p1_reg_t CXL_PSL_CtxTime = {0x0000};
+static const cxl_p1_reg_t CXL_PSL_ErrIVTE = {0x0008};
+static const cxl_p1_reg_t CXL_PSL_KEY1    = {0x0010};
+static const cxl_p1_reg_t CXL_PSL_KEY2    = {0x0018};
+static const cxl_p1_reg_t CXL_PSL_Control = {0x0020};
+/* Downloading */
+static const cxl_p1_reg_t CXL_PSL_DLCNTL  = {0x0060};
+static const cxl_p1_reg_t CXL_PSL_DLADDR  = {0x0068};
+
+/* PSL Lookaside Buffer Management Area */
+static const cxl_p1_reg_t CXL_PSL_LBISEL  = {0x0080};
+static const cxl_p1_reg_t CXL_PSL_SLBIE   = {0x0088};
+static const cxl_p1_reg_t CXL_PSL_SLBIA   = {0x0090};
+static const cxl_p1_reg_t CXL_PSL_TLBIE   = {0x00A0};
+static const cxl_p1_reg_t CXL_PSL_TLBIA   = {0x00A8};
+static const cxl_p1_reg_t CXL_PSL_AFUSEL  = {0x00B0};
+
+/* 0x00C0:7EFF Implementation dependent area */
+static const cxl_p1_reg_t CXL_PSL_FIR1      = {0x0100};
+static const cxl_p1_reg_t CXL_PSL_FIR2      = {0x0108};
+static const cxl_p1_reg_t CXL_PSL_VERSION   = {0x0118};
+static const cxl_p1_reg_t CXL_PSL_RESLCKTO  = {0x0128};
+static const cxl_p1_reg_t CXL_PSL_FIR_CNTL  = {0x0148};
+static const cxl_p1_reg_t CXL_PSL_DSNDCTL   = {0x0150};
+static const cxl_p1_reg_t CXL_PSL_SNWRALLOC = {0x0158};
+static const cxl_p1_reg_t CXL_PSL_TRACE     = {0x0170};
+/* 0x7F00:7FFF Reserved PCIe MSI-X Pending Bit Array area */
+/* 0x8000:FFFF Reserved PCIe MSI-X Table Area */
+
+/* PSL Slice Privilege 1 Memory Map */
+/* Configuration Area */
+static const cxl_p1n_reg_t CXL_PSL_SR_An          = {0x00};
+static const cxl_p1n_reg_t CXL_PSL_LPID_An        = {0x08};
+static const cxl_p1n_reg_t CXL_PSL_AMBAR_An       = {0x10};
+static const cxl_p1n_reg_t CXL_PSL_SPOffset_An    = {0x18};
+static const cxl_p1n_reg_t CXL_PSL_ID_An          = {0x20};
+static const cxl_p1n_reg_t CXL_PSL_SERR_An        = {0x28};
+/* Memory Management and Lookaside Buffer Management */
+static const cxl_p1n_reg_t CXL_PSL_SDR_An         = {0x30};
+static const cxl_p1n_reg_t CXL_PSL_AMOR_An        = {0x38};
+/* Pointer Area */
+static const cxl_p1n_reg_t CXL_HAURP_An           = {0x80};
+static const cxl_p1n_reg_t CXL_PSL_SPAP_An        = {0x88};
+static const cxl_p1n_reg_t CXL_PSL_LLCMD_An       = {0x90};
+/* Control Area */
+static const cxl_p1n_reg_t CXL_PSL_SCNTL_An       = {0xA0};
+static const cxl_p1n_reg_t CXL_PSL_CtxTime_An     = {0xA8};
+static const cxl_p1n_reg_t CXL_PSL_IVTE_Offset_An = {0xB0};
+static const cxl_p1n_reg_t CXL_PSL_IVTE_Limit_An  = {0xB8};
+/* 0xC0:FF Implementation Dependent Area */
+static const cxl_p1n_reg_t CXL_PSL_FIR_SLICE_An   = {0xC0};
+static const cxl_p1n_reg_t CXL_AFU_DEBUG_An       = {0xC8};
+static const cxl_p1n_reg_t CXL_PSL_APCALLOC_A     = {0xD0};
+static const cxl_p1n_reg_t CXL_PSL_COALLOC_A      = {0xD8};
+static const cxl_p1n_reg_t CXL_PSL_RXCTL_A        = {0xE0};
+static const cxl_p1n_reg_t CXL_PSL_SLICE_TRACE    = {0xE8};
+
+/* PSL Slice Privilege 2 Memory Map */
+/* Configuration and Control Area */
+static const cxl_p2n_reg_t CXL_PSL_PID_TID_An = {0x000};
+static const cxl_p2n_reg_t CXL_CSRP_An        = {0x008};
+static const cxl_p2n_reg_t CXL_AURP0_An       = {0x010};
+static const cxl_p2n_reg_t CXL_AURP1_An       = {0x018};
+static const cxl_p2n_reg_t CXL_SSTP0_An       = {0x020};
+static const cxl_p2n_reg_t CXL_SSTP1_An       = {0x028};
+static const cxl_p2n_reg_t CXL_PSL_AMR_An     = {0x030};
+/* Segment Lookaside Buffer Management */
+static const cxl_p2n_reg_t CXL_SLBIE_An       = {0x040};
+static const cxl_p2n_reg_t CXL_SLBIA_An       = {0x048};
+static const cxl_p2n_reg_t CXL_SLBI_Select_An = {0x050};
+/* Interrupt Registers */
+static const cxl_p2n_reg_t CXL_PSL_DSISR_An   = {0x060};
+static const cxl_p2n_reg_t CXL_PSL_DAR_An     = {0x068};
+static const cxl_p2n_reg_t CXL_PSL_DSR_An     = {0x070};
+static const cxl_p2n_reg_t CXL_PSL_TFC_An     = {0x078};
+static const cxl_p2n_reg_t CXL_PSL_PEHandle_An = {0x080};
+static const cxl_p2n_reg_t CXL_PSL_ErrStat_An = {0x088};
+/* AFU Registers */
+static const cxl_p2n_reg_t CXL_AFU_Cntl_An    = {0x090};
+static const cxl_p2n_reg_t CXL_AFU_ERR_An     = {0x098};
+/* Work Element Descriptor */
+static const cxl_p2n_reg_t CXL_PSL_WED_An     = {0x0A0};
+/* 0x0C0:FFF Implementation Dependent Area */
+
+#define CXL_PSL_SPAP_Addr 0x0ffffffffffff000ULL
+#define CXL_PSL_SPAP_Size 0x0000000000000ff0ULL
+#define CXL_PSL_SPAP_Size_Shift 4
+#define CXL_PSL_SPAP_V    0x0000000000000001ULL
+
+/****** CXL_PSL_DLCNTL *****************************************************/
+#define CXL_PSL_DLCNTL_D (0x1ull << (63-28))
+#define CXL_PSL_DLCNTL_C (0x1ull << (63-29))
+#define CXL_PSL_DLCNTL_E (0x1ull << (63-30))
+#define CXL_PSL_DLCNTL_S (0x1ull << (63-31))
+#define CXL_PSL_DLCNTL_CE (CXL_PSL_DLCNTL_C | CXL_PSL_DLCNTL_E)
+#define CXL_PSL_DLCNTL_DCES (CXL_PSL_DLCNTL_D | CXL_PSL_DLCNTL_CE | CXL_PSL_DLCNTL_S)
+
+/****** CXL_PSL_SR_An ******************************************************/
+#define CXL_PSL_SR_An_SF  MSR_SF            /* 64bit */
+#define CXL_PSL_SR_An_TA  (1ull << (63-1))  /* Tags active,   GA1: 0 */
+#define CXL_PSL_SR_An_HV  MSR_HV            /* Hypervisor,    GA1: 0 */
+#define CXL_PSL_SR_An_PR  MSR_PR            /* Problem state, GA1: 1 */
+#define CXL_PSL_SR_An_ISL (1ull << (63-53)) /* Ignore Segment Large Page */
+#define CXL_PSL_SR_An_TC  (1ull << (63-54)) /* Page Table secondary hash */
+#define CXL_PSL_SR_An_US  (1ull << (63-56)) /* User state,    GA1: X */
+#define CXL_PSL_SR_An_SC  (1ull << (63-58)) /* Segment Table secondary hash */
+#define CXL_PSL_SR_An_R   MSR_DR            /* Relocate,      GA1: 1 */
+#define CXL_PSL_SR_An_MP  (1ull << (63-62)) /* Master Process */
+#define CXL_PSL_SR_An_LE  (1ull << (63-63)) /* Little Endian */
+
+/****** CXL_PSL_LLCMD_An ****************************************************/
+#define CXL_LLCMD_TERMINATE   0x0001000000000000ULL
+#define CXL_LLCMD_REMOVE      0x0002000000000000ULL
+#define CXL_LLCMD_SUSPEND     0x0003000000000000ULL
+#define CXL_LLCMD_RESUME      0x0004000000000000ULL
+#define CXL_LLCMD_ADD         0x0005000000000000ULL
+#define CXL_LLCMD_UPDATE      0x0006000000000000ULL
+#define CXL_LLCMD_HANDLE_MASK 0x000000000000ffffULL
+
+/****** CXL_PSL_ID_An ****************************************************/
+#define CXL_PSL_ID_An_F        (1ull << (63-31))
+#define CXL_PSL_ID_An_L        (1ull << (63-30))
+
+/****** CXL_PSL_SCNTL_An ****************************************************/
+#define CXL_PSL_SCNTL_An_CR          (0x1ull << (63-15))
+/* Programming Modes: */
+#define CXL_PSL_SCNTL_An_PM_MASK     (0xffffull << (63-31))
+#define CXL_PSL_SCNTL_An_PM_Shared   (0x0000ull << (63-31))
+#define CXL_PSL_SCNTL_An_PM_OS       (0x0001ull << (63-31))
+#define CXL_PSL_SCNTL_An_PM_Process  (0x0002ull << (63-31))
+#define CXL_PSL_SCNTL_An_PM_AFU      (0x0004ull << (63-31))
+#define CXL_PSL_SCNTL_An_PM_AFU_PBT  (0x0104ull << (63-31))
+/* Purge Status (ro) */
+#define CXL_PSL_SCNTL_An_Ps_MASK     (0x3ull << (63-39))
+#define CXL_PSL_SCNTL_An_Ps_Pending  (0x1ull << (63-39))
+#define CXL_PSL_SCNTL_An_Ps_Complete (0x3ull << (63-39))
+/* Purge */
+#define CXL_PSL_SCNTL_An_Pc          (0x1ull << (63-48))
+/* Suspend Status (ro) */
+#define CXL_PSL_SCNTL_An_Ss_MASK     (0x3ull << (63-55))
+#define CXL_PSL_SCNTL_An_Ss_Pending  (0x1ull << (63-55))
+#define CXL_PSL_SCNTL_An_Ss_Complete (0x3ull << (63-55))
+/* Suspend Control */
+#define CXL_PSL_SCNTL_An_Sc          (0x1ull << (63-63))
+
+/* AFU Slice Enable Status (ro) */
+#define CXL_AFU_Cntl_An_ES_MASK     (0x7ull << (63-2))
+#define CXL_AFU_Cntl_An_ES_Disabled (0x0ull << (63-2))
+#define CXL_AFU_Cntl_An_ES_Enabled  (0x4ull << (63-2))
+/* AFU Slice Enable */
+#define CXL_AFU_Cntl_An_E           (0x1ull << (63-3))
+/* AFU Slice Reset status (ro) */
+#define CXL_AFU_Cntl_An_RS_MASK     (0x3ull << (63-5))
+#define CXL_AFU_Cntl_An_RS_Pending  (0x1ull << (63-5))
+#define CXL_AFU_Cntl_An_RS_Complete (0x2ull << (63-5))
+/* AFU Slice Reset */
+#define CXL_AFU_Cntl_An_RA          (0x1ull << (63-7))
+
+/****** CXL_SSTP0/1_An ******************************************************/
+/* These top bits are for the segment that CONTAINS the segment table */
+#define CXL_SSTP0_An_B_SHIFT    SLB_VSID_SSIZE_SHIFT
+#define CXL_SSTP0_An_KS             (1ull << (63-2))
+#define CXL_SSTP0_An_KP             (1ull << (63-3))
+#define CXL_SSTP0_An_N              (1ull << (63-4))
+#define CXL_SSTP0_An_L              (1ull << (63-5))
+#define CXL_SSTP0_An_C              (1ull << (63-6))
+#define CXL_SSTP0_An_TA             (1ull << (63-7))
+#define CXL_SSTP0_An_LP_SHIFT                (63-9)  /* 2 Bits */
+/* And finally, the virtual address & size of the segment table: */
+#define CXL_SSTP0_An_SegTableSize_SHIFT      (63-31) /* 12 Bits */
+#define CXL_SSTP0_An_SegTableSize_MASK \
+       (((1ull << 12) - 1) << CXL_SSTP0_An_SegTableSize_SHIFT)
+#define CXL_SSTP0_An_STVA_U_MASK   ((1ull << (63-49))-1)
+#define CXL_SSTP1_An_STVA_L_MASK (~((1ull << (63-55))-1))
+#define CXL_SSTP1_An_V              (1ull << (63-63))
+
+/****** CXL_PSL_SLBIE_[An] **************************************************/
+/* write: */
+#define CXL_SLBIE_C        PPC_BIT(36)         /* Class */
+#define CXL_SLBIE_SS       PPC_BITMASK(37, 38) /* Segment Size */
+#define CXL_SLBIE_SS_SHIFT PPC_BITLSHIFT(38)
+#define CXL_SLBIE_TA       PPC_BIT(38)         /* Tags Active */
+/* read: */
+#define CXL_SLBIE_MAX      PPC_BITMASK(24, 31)
+#define CXL_SLBIE_PENDING  PPC_BITMASK(56, 63)
+
+/****** Common to all CXL_TLBIA/SLBIA_[An] **********************************/
+#define CXL_TLB_SLB_P          (1ull) /* Pending (read) */
+
+/****** Common to all CXL_TLB/SLB_IA/IE_[An] registers **********************/
+#define CXL_TLB_SLB_IQ_ALL     (0ull) /* Inv qualifier */
+#define CXL_TLB_SLB_IQ_LPID    (1ull) /* Inv qualifier */
+#define CXL_TLB_SLB_IQ_LPIDPID (3ull) /* Inv qualifier */
+
+/****** CXL_PSL_AFUSEL ******************************************************/
+#define CXL_PSL_AFUSEL_A (1ull << (63-55)) /* Adapter wide invalidates affect all AFUs */
+
+/****** CXL_PSL_DSISR_An ****************************************************/
+#define CXL_PSL_DSISR_An_DS (1ull << (63-0))  /* Segment not found */
+#define CXL_PSL_DSISR_An_DM (1ull << (63-1))  /* PTE not found (See also: M) or protection fault */
+#define CXL_PSL_DSISR_An_ST (1ull << (63-2))  /* Segment Table PTE not found */
+#define CXL_PSL_DSISR_An_UR (1ull << (63-3))  /* AURP PTE not found */
+#define CXL_PSL_DSISR_TRANS (CXL_PSL_DSISR_An_DS | CXL_PSL_DSISR_An_DM | CXL_PSL_DSISR_An_ST | CXL_PSL_DSISR_An_UR)
+#define CXL_PSL_DSISR_An_PE (1ull << (63-4))  /* PSL Error (implementation specific) */
+#define CXL_PSL_DSISR_An_AE (1ull << (63-5))  /* AFU Error */
+#define CXL_PSL_DSISR_An_OC (1ull << (63-6))  /* OS Context Warning */
+/* NOTE: Bits 32:63 are undefined if DSISR[DS] = 1 */
+#define CXL_PSL_DSISR_An_M  DSISR_NOHPTE      /* PTE not found */
+#define CXL_PSL_DSISR_An_P  DSISR_PROTFAULT   /* Storage protection violation */
+#define CXL_PSL_DSISR_An_A  (1ull << (63-37)) /* AFU lock access to write through or cache inhibited storage */
+#define CXL_PSL_DSISR_An_S  DSISR_ISSTORE     /* Access was afu_wr or afu_zero */
+#define CXL_PSL_DSISR_An_K  DSISR_KEYFAULT    /* Access not permitted by virtual page class key protection */
+
+/****** CXL_PSL_TFC_An ******************************************************/
+#define CXL_PSL_TFC_An_A  (1ull << (63-28)) /* Acknowledge non-translation fault */
+#define CXL_PSL_TFC_An_C  (1ull << (63-29)) /* Continue (abort transaction) */
+#define CXL_PSL_TFC_An_AE (1ull << (63-30)) /* Restart PSL with address error */
+#define CXL_PSL_TFC_An_R  (1ull << (63-31)) /* Restart PSL transaction */
+
+/* cxl_process_element->software_status */
+#define CXL_PE_SOFTWARE_STATE_V (1ul << (31 -  0)) /* Valid */
+#define CXL_PE_SOFTWARE_STATE_C (1ul << (31 - 29)) /* Complete */
+#define CXL_PE_SOFTWARE_STATE_S (1ul << (31 - 30)) /* Suspend */
+#define CXL_PE_SOFTWARE_STATE_T (1ul << (31 - 31)) /* Terminate */
+
+/* SPA->sw_command_status */
+#define CXL_SPA_SW_CMD_MASK         0xffff000000000000ULL
+#define CXL_SPA_SW_CMD_TERMINATE    0x0001000000000000ULL
+#define CXL_SPA_SW_CMD_REMOVE       0x0002000000000000ULL
+#define CXL_SPA_SW_CMD_SUSPEND      0x0003000000000000ULL
+#define CXL_SPA_SW_CMD_RESUME       0x0004000000000000ULL
+#define CXL_SPA_SW_CMD_ADD          0x0005000000000000ULL
+#define CXL_SPA_SW_CMD_UPDATE       0x0006000000000000ULL
+#define CXL_SPA_SW_STATE_MASK       0x0000ffff00000000ULL
+#define CXL_SPA_SW_STATE_TERMINATED 0x0000000100000000ULL
+#define CXL_SPA_SW_STATE_REMOVED    0x0000000200000000ULL
+#define CXL_SPA_SW_STATE_SUSPENDED  0x0000000300000000ULL
+#define CXL_SPA_SW_STATE_RESUMED    0x0000000400000000ULL
+#define CXL_SPA_SW_STATE_ADDED      0x0000000500000000ULL
+#define CXL_SPA_SW_STATE_UPDATED    0x0000000600000000ULL
+#define CXL_SPA_SW_PSL_ID_MASK      0x00000000ffff0000ULL
+#define CXL_SPA_SW_LINK_MASK        0x000000000000ffffULL
+
+#define CXL_MAX_SLICES 4
+#define MAX_AFU_MMIO_REGS 3
+
+#define CXL_MODE_DEDICATED   0x1
+#define CXL_MODE_DIRECTED    0x2
+#define CXL_MODE_TIME_SLICED 0x4
+#define CXL_SUPPORTED_MODES (CXL_MODE_DEDICATED | CXL_MODE_DIRECTED)
+
+enum cxl_context_status {
+       CLOSED,
+       OPENED,
+       STARTED
+};
+
+enum prefault_modes {
+       CXL_PREFAULT_NONE,
+       CXL_PREFAULT_WED,
+       CXL_PREFAULT_ALL,
+};
+
+struct cxl_sste {
+       __be64 esid_data;
+       __be64 vsid_data;
+};
+
+#define to_cxl_adapter(d) container_of(d, struct cxl, dev)
+#define to_cxl_afu(d) container_of(d, struct cxl_afu, dev)
+
+struct cxl_afu {
+       irq_hw_number_t psl_hwirq;
+       irq_hw_number_t serr_hwirq;
+       unsigned int serr_virq;
+       void __iomem *p1n_mmio;
+       void __iomem *p2n_mmio;
+       phys_addr_t psn_phys;
+       u64 pp_offset;
+       u64 pp_size;
+       void __iomem *afu_desc_mmio;
+       struct cxl *adapter;
+       struct device dev;
+       struct cdev afu_cdev_s, afu_cdev_m, afu_cdev_d;
+       struct device *chardev_s, *chardev_m, *chardev_d;
+       struct idr contexts_idr;
+       struct dentry *debugfs;
+       spinlock_t contexts_lock;
+       struct mutex spa_mutex;
+       spinlock_t afu_cntl_lock;
+
+       /*
+        * Only the first part of the SPA is used for the process element
+        * linked list. The only other part that software needs to worry about
+        * is sw_command_status, which we store a separate pointer to.
+        * Everything else in the SPA is only used by hardware
+        */
+       struct cxl_process_element *spa;
+       __be64 *sw_command_status;
+       unsigned int spa_size;
+       int spa_order;
+       int spa_max_procs;
+       unsigned int psl_virq;
+
+       int pp_irqs;
+       int irqs_max;
+       int num_procs;
+       int max_procs_virtualised;
+       int slice;
+       int modes_supported;
+       int current_mode;
+       enum prefault_modes prefault_mode;
+       bool psa;
+       bool pp_psa;
+       bool enabled;
+};
+
+/*
+ * This is a cxl context.  If the PSL is in dedicated mode, there will be one
+ * of these per AFU.  If in AFU directed there can be lots of these.
+ */
+struct cxl_context {
+       struct cxl_afu *afu;
+
+       /* Problem state MMIO */
+       phys_addr_t psn_phys;
+       u64 psn_size;
+
+       spinlock_t sste_lock; /* Protects segment table entries */
+       struct cxl_sste *sstp;
+       u64 sstp0, sstp1;
+       unsigned int sst_size, sst_lru;
+
+       wait_queue_head_t wq;
+       struct pid *pid;
+       spinlock_t lock; /* Protects pending_irq_mask, pending_fault and fault_addr */
+       /* Only used in PR mode */
+       u64 process_token;
+
+       unsigned long *irq_bitmap; /* Accessed from IRQ context */
+       struct cxl_irq_ranges irqs;
+       u64 fault_addr;
+       u64 fault_dsisr;
+       u64 afu_err;
+
+       /*
+        * This status and it's lock pretects start and detach context
+        * from racing.  It also prevents detach from racing with
+        * itself
+        */
+       enum cxl_context_status status;
+       struct mutex status_mutex;
+
+
+       /* XXX: Is it possible to need multiple work items at once? */
+       struct work_struct fault_work;
+       u64 dsisr;
+       u64 dar;
+
+       struct cxl_process_element *elem;
+
+       int pe; /* process element handle */
+       u32 irq_count;
+       bool pe_inserted;
+       bool master;
+       bool kernel;
+       bool pending_irq;
+       bool pending_fault;
+       bool pending_afu_err;
+};
+
+struct cxl {
+       void __iomem *p1_mmio;
+       void __iomem *p2_mmio;
+       irq_hw_number_t err_hwirq;
+       unsigned int err_virq;
+       spinlock_t afu_list_lock;
+       struct cxl_afu *afu[CXL_MAX_SLICES];
+       struct device dev;
+       struct dentry *trace;
+       struct dentry *psl_err_chk;
+       struct dentry *debugfs;
+       struct bin_attribute cxl_attr;
+       int adapter_num;
+       int user_irqs;
+       u64 afu_desc_off;
+       u64 afu_desc_size;
+       u64 ps_off;
+       u64 ps_size;
+       u16 psl_rev;
+       u16 base_image;
+       u8 vsec_status;
+       u8 caia_major;
+       u8 caia_minor;
+       u8 slices;
+       bool user_image_loaded;
+       bool perst_loads_image;
+       bool perst_select_user;
+};
+
+int cxl_alloc_one_irq(struct cxl *adapter);
+void cxl_release_one_irq(struct cxl *adapter, int hwirq);
+int cxl_alloc_irq_ranges(struct cxl_irq_ranges *irqs, struct cxl *adapter, unsigned int num);
+void cxl_release_irq_ranges(struct cxl_irq_ranges *irqs, struct cxl *adapter);
+int cxl_setup_irq(struct cxl *adapter, unsigned int hwirq, unsigned int virq);
+
+/* common == phyp + powernv */
+struct cxl_process_element_common {
+       __be32 tid;
+       __be32 pid;
+       __be64 csrp;
+       __be64 aurp0;
+       __be64 aurp1;
+       __be64 sstp0;
+       __be64 sstp1;
+       __be64 amr;
+       u8     reserved3[4];
+       __be64 wed;
+} __packed;
+
+/* just powernv */
+struct cxl_process_element {
+       __be64 sr;
+       __be64 SPOffset;
+       __be64 sdr;
+       __be64 haurp;
+       __be32 ctxtime;
+       __be16 ivte_offsets[4];
+       __be16 ivte_ranges[4];
+       __be32 lpid;
+       struct cxl_process_element_common common;
+       __be32 software_state;
+} __packed;
+
+static inline void __iomem *_cxl_p1_addr(struct cxl *cxl, cxl_p1_reg_t reg)
+{
+       WARN_ON(!cpu_has_feature(CPU_FTR_HVMODE));
+       return cxl->p1_mmio + cxl_reg_off(reg);
+}
+
+#define cxl_p1_write(cxl, reg, val) \
+       out_be64(_cxl_p1_addr(cxl, reg), val)
+#define cxl_p1_read(cxl, reg) \
+       in_be64(_cxl_p1_addr(cxl, reg))
+
+static inline void __iomem *_cxl_p1n_addr(struct cxl_afu *afu, cxl_p1n_reg_t reg)
+{
+       WARN_ON(!cpu_has_feature(CPU_FTR_HVMODE));
+       return afu->p1n_mmio + cxl_reg_off(reg);
+}
+
+#define cxl_p1n_write(afu, reg, val) \
+       out_be64(_cxl_p1n_addr(afu, reg), val)
+#define cxl_p1n_read(afu, reg) \
+       in_be64(_cxl_p1n_addr(afu, reg))
+
+static inline void __iomem *_cxl_p2n_addr(struct cxl_afu *afu, cxl_p2n_reg_t reg)
+{
+       return afu->p2n_mmio + cxl_reg_off(reg);
+}
+
+#define cxl_p2n_write(afu, reg, val) \
+       out_be64(_cxl_p2n_addr(afu, reg), val)
+#define cxl_p2n_read(afu, reg) \
+       in_be64(_cxl_p2n_addr(afu, reg))
+
+struct cxl_calls {
+       void (*cxl_slbia)(struct mm_struct *mm);
+       struct module *owner;
+};
+int register_cxl_calls(struct cxl_calls *calls);
+void unregister_cxl_calls(struct cxl_calls *calls);
+
+int cxl_alloc_adapter_nr(struct cxl *adapter);
+void cxl_remove_adapter_nr(struct cxl *adapter);
+
+int cxl_file_init(void);
+void cxl_file_exit(void);
+int cxl_register_adapter(struct cxl *adapter);
+int cxl_register_afu(struct cxl_afu *afu);
+int cxl_chardev_d_afu_add(struct cxl_afu *afu);
+int cxl_chardev_m_afu_add(struct cxl_afu *afu);
+int cxl_chardev_s_afu_add(struct cxl_afu *afu);
+void cxl_chardev_afu_remove(struct cxl_afu *afu);
+
+void cxl_context_detach_all(struct cxl_afu *afu);
+void cxl_context_free(struct cxl_context *ctx);
+void cxl_context_detach(struct cxl_context *ctx);
+
+int cxl_sysfs_adapter_add(struct cxl *adapter);
+void cxl_sysfs_adapter_remove(struct cxl *adapter);
+int cxl_sysfs_afu_add(struct cxl_afu *afu);
+void cxl_sysfs_afu_remove(struct cxl_afu *afu);
+int cxl_sysfs_afu_m_add(struct cxl_afu *afu);
+void cxl_sysfs_afu_m_remove(struct cxl_afu *afu);
+
+int cxl_afu_activate_mode(struct cxl_afu *afu, int mode);
+int _cxl_afu_deactivate_mode(struct cxl_afu *afu, int mode);
+int cxl_afu_deactivate_mode(struct cxl_afu *afu);
+int cxl_afu_select_best_mode(struct cxl_afu *afu);
+
+unsigned int cxl_map_irq(struct cxl *adapter, irq_hw_number_t hwirq,
+                        irq_handler_t handler, void *cookie);
+void cxl_unmap_irq(unsigned int virq, void *cookie);
+int cxl_register_psl_irq(struct cxl_afu *afu);
+void cxl_release_psl_irq(struct cxl_afu *afu);
+int cxl_register_psl_err_irq(struct cxl *adapter);
+void cxl_release_psl_err_irq(struct cxl *adapter);
+int cxl_register_serr_irq(struct cxl_afu *afu);
+void cxl_release_serr_irq(struct cxl_afu *afu);
+int afu_register_irqs(struct cxl_context *ctx, u32 count);
+void afu_release_irqs(struct cxl_context *ctx);
+irqreturn_t cxl_slice_irq_err(int irq, void *data);
+
+int cxl_debugfs_init(void);
+void cxl_debugfs_exit(void);
+int cxl_debugfs_adapter_add(struct cxl *adapter);
+void cxl_debugfs_adapter_remove(struct cxl *adapter);
+int cxl_debugfs_afu_add(struct cxl_afu *afu);
+void cxl_debugfs_afu_remove(struct cxl_afu *afu);
+
+void cxl_handle_fault(struct work_struct *work);
+void cxl_prefault(struct cxl_context *ctx, u64 wed);
+
+struct cxl *get_cxl_adapter(int num);
+int cxl_alloc_sst(struct cxl_context *ctx);
+
+void init_cxl_native(void);
+
+struct cxl_context *cxl_context_alloc(void);
+int cxl_context_init(struct cxl_context *ctx, struct cxl_afu *afu, bool master);
+void cxl_context_free(struct cxl_context *ctx);
+int cxl_context_iomap(struct cxl_context *ctx, struct vm_area_struct *vma);
+
+/* This matches the layout of the H_COLLECT_CA_INT_INFO retbuf */
+struct cxl_irq_info {
+       u64 dsisr;
+       u64 dar;
+       u64 dsr;
+       u32 pid;
+       u32 tid;
+       u64 afu_err;
+       u64 errstat;
+       u64 padding[3]; /* to match the expected retbuf size for plpar_hcall9 */
+};
+
+int cxl_attach_process(struct cxl_context *ctx, bool kernel, u64 wed,
+                           u64 amr);
+int cxl_detach_process(struct cxl_context *ctx);
+
+int cxl_get_irq(struct cxl_context *ctx, struct cxl_irq_info *info);
+int cxl_ack_irq(struct cxl_context *ctx, u64 tfc, u64 psl_reset_mask);
+
+int cxl_check_error(struct cxl_afu *afu);
+int cxl_afu_slbia(struct cxl_afu *afu);
+int cxl_tlb_slb_invalidate(struct cxl *adapter);
+int cxl_afu_disable(struct cxl_afu *afu);
+int cxl_afu_reset(struct cxl_afu *afu);
+int cxl_psl_purge(struct cxl_afu *afu);
+
+void cxl_stop_trace(struct cxl *cxl);
+
+extern struct pci_driver cxl_pci_driver;
+
+#endif
diff --git a/drivers/misc/cxl/debugfs.c b/drivers/misc/cxl/debugfs.c
new file mode 100644 (file)
index 0000000..825c412
--- /dev/null
@@ -0,0 +1,132 @@
+/*
+ * Copyright 2014 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.
+ */
+
+#include <linux/debugfs.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+
+#include "cxl.h"
+
+static struct dentry *cxl_debugfs;
+
+void cxl_stop_trace(struct cxl *adapter)
+{
+       int slice;
+
+       /* Stop the trace */
+       cxl_p1_write(adapter, CXL_PSL_TRACE, 0x8000000000000017LL);
+
+       /* Stop the slice traces */
+       spin_lock(&adapter->afu_list_lock);
+       for (slice = 0; slice < adapter->slices; slice++) {
+               if (adapter->afu[slice])
+                       cxl_p1n_write(adapter->afu[slice], CXL_PSL_SLICE_TRACE, 0x8000000000000000LL);
+       }
+       spin_unlock(&adapter->afu_list_lock);
+}
+
+/* Helpers to export CXL mmaped IO registers via debugfs */
+static int debugfs_io_u64_get(void *data, u64 *val)
+{
+       *val = in_be64((u64 __iomem *)data);
+       return 0;
+}
+
+static int debugfs_io_u64_set(void *data, u64 val)
+{
+       out_be64((u64 __iomem *)data, val);
+       return 0;
+}
+DEFINE_SIMPLE_ATTRIBUTE(fops_io_x64, debugfs_io_u64_get, debugfs_io_u64_set, "0x%016llx\n");
+
+static struct dentry *debugfs_create_io_x64(const char *name, umode_t mode,
+                                           struct dentry *parent, u64 __iomem *value)
+{
+       return debugfs_create_file(name, mode, parent, (void *)value, &fops_io_x64);
+}
+
+int cxl_debugfs_adapter_add(struct cxl *adapter)
+{
+       struct dentry *dir;
+       char buf[32];
+
+       if (!cxl_debugfs)
+               return -ENODEV;
+
+       snprintf(buf, 32, "card%i", adapter->adapter_num);
+       dir = debugfs_create_dir(buf, cxl_debugfs);
+       if (IS_ERR(dir))
+               return PTR_ERR(dir);
+       adapter->debugfs = dir;
+
+       debugfs_create_io_x64("fir1",     S_IRUSR, dir, _cxl_p1_addr(adapter, CXL_PSL_FIR1));
+       debugfs_create_io_x64("fir2",     S_IRUSR, dir, _cxl_p1_addr(adapter, CXL_PSL_FIR2));
+       debugfs_create_io_x64("fir_cntl", S_IRUSR, dir, _cxl_p1_addr(adapter, CXL_PSL_FIR_CNTL));
+       debugfs_create_io_x64("err_ivte", S_IRUSR, dir, _cxl_p1_addr(adapter, CXL_PSL_ErrIVTE));
+
+       debugfs_create_io_x64("trace", S_IRUSR | S_IWUSR, dir, _cxl_p1_addr(adapter, CXL_PSL_TRACE));
+
+       return 0;
+}
+
+void cxl_debugfs_adapter_remove(struct cxl *adapter)
+{
+       debugfs_remove_recursive(adapter->debugfs);
+}
+
+int cxl_debugfs_afu_add(struct cxl_afu *afu)
+{
+       struct dentry *dir;
+       char buf[32];
+
+       if (!afu->adapter->debugfs)
+               return -ENODEV;
+
+       snprintf(buf, 32, "psl%i.%i", afu->adapter->adapter_num, afu->slice);
+       dir = debugfs_create_dir(buf, afu->adapter->debugfs);
+       if (IS_ERR(dir))
+               return PTR_ERR(dir);
+       afu->debugfs = dir;
+
+       debugfs_create_io_x64("fir",        S_IRUSR, dir, _cxl_p1n_addr(afu, CXL_PSL_FIR_SLICE_An));
+       debugfs_create_io_x64("serr",       S_IRUSR, dir, _cxl_p1n_addr(afu, CXL_PSL_SERR_An));
+       debugfs_create_io_x64("afu_debug",  S_IRUSR, dir, _cxl_p1n_addr(afu, CXL_AFU_DEBUG_An));
+       debugfs_create_io_x64("sr",         S_IRUSR, dir, _cxl_p1n_addr(afu, CXL_PSL_SR_An));
+
+       debugfs_create_io_x64("dsisr",      S_IRUSR, dir, _cxl_p2n_addr(afu, CXL_PSL_DSISR_An));
+       debugfs_create_io_x64("dar",        S_IRUSR, dir, _cxl_p2n_addr(afu, CXL_PSL_DAR_An));
+       debugfs_create_io_x64("sstp0",      S_IRUSR, dir, _cxl_p2n_addr(afu, CXL_SSTP0_An));
+       debugfs_create_io_x64("sstp1",      S_IRUSR, dir, _cxl_p2n_addr(afu, CXL_SSTP1_An));
+       debugfs_create_io_x64("err_status", S_IRUSR, dir, _cxl_p2n_addr(afu, CXL_PSL_ErrStat_An));
+
+       debugfs_create_io_x64("trace", S_IRUSR | S_IWUSR, dir, _cxl_p1n_addr(afu, CXL_PSL_SLICE_TRACE));
+
+       return 0;
+}
+
+void cxl_debugfs_afu_remove(struct cxl_afu *afu)
+{
+       debugfs_remove_recursive(afu->debugfs);
+}
+
+int __init cxl_debugfs_init(void)
+{
+       struct dentry *ent;
+       ent = debugfs_create_dir("cxl", NULL);
+       if (IS_ERR(ent))
+               return PTR_ERR(ent);
+       cxl_debugfs = ent;
+
+       return 0;
+}
+
+void cxl_debugfs_exit(void)
+{
+       debugfs_remove_recursive(cxl_debugfs);
+}
diff --git a/drivers/misc/cxl/fault.c b/drivers/misc/cxl/fault.c
new file mode 100644 (file)
index 0000000..69506eb
--- /dev/null
@@ -0,0 +1,291 @@
+/*
+ * Copyright 2014 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.
+ */
+
+#include <linux/workqueue.h>
+#include <linux/sched.h>
+#include <linux/pid.h>
+#include <linux/mm.h>
+#include <linux/moduleparam.h>
+
+#undef MODULE_PARAM_PREFIX
+#define MODULE_PARAM_PREFIX "cxl" "."
+#include <asm/current.h>
+#include <asm/copro.h>
+#include <asm/mmu.h>
+
+#include "cxl.h"
+
+static struct cxl_sste* find_free_sste(struct cxl_sste *primary_group,
+                                      bool sec_hash,
+                                      struct cxl_sste *secondary_group,
+                                      unsigned int *lru)
+{
+       unsigned int i, entry;
+       struct cxl_sste *sste, *group = primary_group;
+
+       for (i = 0; i < 2; i++) {
+               for (entry = 0; entry < 8; entry++) {
+                       sste = group + entry;
+                       if (!(be64_to_cpu(sste->esid_data) & SLB_ESID_V))
+                               return sste;
+               }
+               if (!sec_hash)
+                       break;
+               group = secondary_group;
+       }
+       /* Nothing free, select an entry to cast out */
+       if (sec_hash && (*lru & 0x8))
+               sste = secondary_group + (*lru & 0x7);
+       else
+               sste = primary_group + (*lru & 0x7);
+       *lru = (*lru + 1) & 0xf;
+
+       return sste;
+}
+
+static void cxl_load_segment(struct cxl_context *ctx, struct copro_slb *slb)
+{
+       /* mask is the group index, we search primary and secondary here. */
+       unsigned int mask = (ctx->sst_size >> 7)-1; /* SSTP0[SegTableSize] */
+       bool sec_hash = 1;
+       struct cxl_sste *sste;
+       unsigned int hash;
+       unsigned long flags;
+
+
+       sec_hash = !!(cxl_p1n_read(ctx->afu, CXL_PSL_SR_An) & CXL_PSL_SR_An_SC);
+
+       if (slb->vsid & SLB_VSID_B_1T)
+               hash = (slb->esid >> SID_SHIFT_1T) & mask;
+       else /* 256M */
+               hash = (slb->esid >> SID_SHIFT) & mask;
+
+       spin_lock_irqsave(&ctx->sste_lock, flags);
+       sste = find_free_sste(ctx->sstp + (hash << 3), sec_hash,
+                             ctx->sstp + ((~hash & mask) << 3), &ctx->sst_lru);
+
+       pr_devel("CXL Populating SST[%li]: %#llx %#llx\n",
+                       sste - ctx->sstp, slb->vsid, slb->esid);
+
+       sste->vsid_data = cpu_to_be64(slb->vsid);
+       sste->esid_data = cpu_to_be64(slb->esid);
+       spin_unlock_irqrestore(&ctx->sste_lock, flags);
+}
+
+static int cxl_fault_segment(struct cxl_context *ctx, struct mm_struct *mm,
+                            u64 ea)
+{
+       struct copro_slb slb = {0,0};
+       int rc;
+
+       if (!(rc = copro_calculate_slb(mm, ea, &slb))) {
+               cxl_load_segment(ctx, &slb);
+       }
+
+       return rc;
+}
+
+static void cxl_ack_ae(struct cxl_context *ctx)
+{
+       unsigned long flags;
+
+       cxl_ack_irq(ctx, CXL_PSL_TFC_An_AE, 0);
+
+       spin_lock_irqsave(&ctx->lock, flags);
+       ctx->pending_fault = true;
+       ctx->fault_addr = ctx->dar;
+       ctx->fault_dsisr = ctx->dsisr;
+       spin_unlock_irqrestore(&ctx->lock, flags);
+
+       wake_up_all(&ctx->wq);
+}
+
+static int cxl_handle_segment_miss(struct cxl_context *ctx,
+                                  struct mm_struct *mm, u64 ea)
+{
+       int rc;
+
+       pr_devel("CXL interrupt: Segment fault pe: %i ea: %#llx\n", ctx->pe, ea);
+
+       if ((rc = cxl_fault_segment(ctx, mm, ea)))
+               cxl_ack_ae(ctx);
+       else {
+
+               mb(); /* Order seg table write to TFC MMIO write */
+               cxl_ack_irq(ctx, CXL_PSL_TFC_An_R, 0);
+       }
+
+       return IRQ_HANDLED;
+}
+
+static void cxl_handle_page_fault(struct cxl_context *ctx,
+                                 struct mm_struct *mm, u64 dsisr, u64 dar)
+{
+       unsigned flt = 0;
+       int result;
+       unsigned long access, flags;
+
+       if ((result = copro_handle_mm_fault(mm, dar, dsisr, &flt))) {
+               pr_devel("copro_handle_mm_fault failed: %#x\n", result);
+               return cxl_ack_ae(ctx);
+       }
+
+       /*
+        * update_mmu_cache() will not have loaded the hash since current->trap
+        * is not a 0x400 or 0x300, so just call hash_page_mm() here.
+        */
+       access = _PAGE_PRESENT;
+       if (dsisr & CXL_PSL_DSISR_An_S)
+               access |= _PAGE_RW;
+       if ((!ctx->kernel) || ~(dar & (1ULL << 63)))
+               access |= _PAGE_USER;
+       local_irq_save(flags);
+       hash_page_mm(mm, dar, access, 0x300);
+       local_irq_restore(flags);
+
+       pr_devel("Page fault successfully handled for pe: %i!\n", ctx->pe);
+       cxl_ack_irq(ctx, CXL_PSL_TFC_An_R, 0);
+}
+
+void cxl_handle_fault(struct work_struct *fault_work)
+{
+       struct cxl_context *ctx =
+               container_of(fault_work, struct cxl_context, fault_work);
+       u64 dsisr = ctx->dsisr;
+       u64 dar = ctx->dar;
+       struct task_struct *task;
+       struct mm_struct *mm;
+
+       if (cxl_p2n_read(ctx->afu, CXL_PSL_DSISR_An) != dsisr ||
+           cxl_p2n_read(ctx->afu, CXL_PSL_DAR_An) != dar ||
+           cxl_p2n_read(ctx->afu, CXL_PSL_PEHandle_An) != ctx->pe) {
+               /* Most likely explanation is harmless - a dedicated process
+                * has detached and these were cleared by the PSL purge, but
+                * warn about it just in case */
+               dev_notice(&ctx->afu->dev, "cxl_handle_fault: Translation fault regs changed\n");
+               return;
+       }
+
+       pr_devel("CXL BOTTOM HALF handling fault for afu pe: %i. "
+               "DSISR: %#llx DAR: %#llx\n", ctx->pe, dsisr, dar);
+
+       if (!(task = get_pid_task(ctx->pid, PIDTYPE_PID))) {
+               pr_devel("cxl_handle_fault unable to get task %i\n",
+                        pid_nr(ctx->pid));
+               cxl_ack_ae(ctx);
+               return;
+       }
+       if (!(mm = get_task_mm(task))) {
+               pr_devel("cxl_handle_fault unable to get mm %i\n",
+                        pid_nr(ctx->pid));
+               cxl_ack_ae(ctx);
+               goto out;
+       }
+
+       if (dsisr & CXL_PSL_DSISR_An_DS)
+               cxl_handle_segment_miss(ctx, mm, dar);
+       else if (dsisr & CXL_PSL_DSISR_An_DM)
+               cxl_handle_page_fault(ctx, mm, dsisr, dar);
+       else
+               WARN(1, "cxl_handle_fault has nothing to handle\n");
+
+       mmput(mm);
+out:
+       put_task_struct(task);
+}
+
+static void cxl_prefault_one(struct cxl_context *ctx, u64 ea)
+{
+       int rc;
+       struct task_struct *task;
+       struct mm_struct *mm;
+
+       if (!(task = get_pid_task(ctx->pid, PIDTYPE_PID))) {
+               pr_devel("cxl_prefault_one unable to get task %i\n",
+                        pid_nr(ctx->pid));
+               return;
+       }
+       if (!(mm = get_task_mm(task))) {
+               pr_devel("cxl_prefault_one unable to get mm %i\n",
+                        pid_nr(ctx->pid));
+               put_task_struct(task);
+               return;
+       }
+
+       rc = cxl_fault_segment(ctx, mm, ea);
+
+       mmput(mm);
+       put_task_struct(task);
+}
+
+static u64 next_segment(u64 ea, u64 vsid)
+{
+       if (vsid & SLB_VSID_B_1T)
+               ea |= (1ULL << 40) - 1;
+       else
+               ea |= (1ULL << 28) - 1;
+
+       return ea + 1;
+}
+
+static void cxl_prefault_vma(struct cxl_context *ctx)
+{
+       u64 ea, last_esid = 0;
+       struct copro_slb slb;
+       struct vm_area_struct *vma;
+       int rc;
+       struct task_struct *task;
+       struct mm_struct *mm;
+
+       if (!(task = get_pid_task(ctx->pid, PIDTYPE_PID))) {
+               pr_devel("cxl_prefault_vma unable to get task %i\n",
+                        pid_nr(ctx->pid));
+               return;
+       }
+       if (!(mm = get_task_mm(task))) {
+               pr_devel("cxl_prefault_vm unable to get mm %i\n",
+                        pid_nr(ctx->pid));
+               goto out1;
+       }
+
+       down_read(&mm->mmap_sem);
+       for (vma = mm->mmap; vma; vma = vma->vm_next) {
+               for (ea = vma->vm_start; ea < vma->vm_end;
+                               ea = next_segment(ea, slb.vsid)) {
+                       rc = copro_calculate_slb(mm, ea, &slb);
+                       if (rc)
+                               continue;
+
+                       if (last_esid == slb.esid)
+                               continue;
+
+                       cxl_load_segment(ctx, &slb);
+                       last_esid = slb.esid;
+               }
+       }
+       up_read(&mm->mmap_sem);
+
+       mmput(mm);
+out1:
+       put_task_struct(task);
+}
+
+void cxl_prefault(struct cxl_context *ctx, u64 wed)
+{
+       switch (ctx->afu->prefault_mode) {
+       case CXL_PREFAULT_WED:
+               cxl_prefault_one(ctx, wed);
+               break;
+       case CXL_PREFAULT_ALL:
+               cxl_prefault_vma(ctx);
+               break;
+       default:
+               break;
+       }
+}
diff --git a/drivers/misc/cxl/file.c b/drivers/misc/cxl/file.c
new file mode 100644 (file)
index 0000000..378b099
--- /dev/null
@@ -0,0 +1,518 @@
+/*
+ * Copyright 2014 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.
+ */
+
+#include <linux/spinlock.h>
+#include <linux/module.h>
+#include <linux/export.h>
+#include <linux/kernel.h>
+#include <linux/bitmap.h>
+#include <linux/sched.h>
+#include <linux/poll.h>
+#include <linux/pid.h>
+#include <linux/fs.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <asm/cputable.h>
+#include <asm/current.h>
+#include <asm/copro.h>
+
+#include "cxl.h"
+
+#define CXL_NUM_MINORS 256 /* Total to reserve */
+#define CXL_DEV_MINORS 13   /* 1 control + 4 AFUs * 3 (dedicated/master/shared) */
+
+#define CXL_CARD_MINOR(adapter) (adapter->adapter_num * CXL_DEV_MINORS)
+#define CXL_AFU_MINOR_D(afu) (CXL_CARD_MINOR(afu->adapter) + 1 + (3 * afu->slice))
+#define CXL_AFU_MINOR_M(afu) (CXL_AFU_MINOR_D(afu) + 1)
+#define CXL_AFU_MINOR_S(afu) (CXL_AFU_MINOR_D(afu) + 2)
+#define CXL_AFU_MKDEV_D(afu) MKDEV(MAJOR(cxl_dev), CXL_AFU_MINOR_D(afu))
+#define CXL_AFU_MKDEV_M(afu) MKDEV(MAJOR(cxl_dev), CXL_AFU_MINOR_M(afu))
+#define CXL_AFU_MKDEV_S(afu) MKDEV(MAJOR(cxl_dev), CXL_AFU_MINOR_S(afu))
+
+#define CXL_DEVT_ADAPTER(dev) (MINOR(dev) / CXL_DEV_MINORS)
+#define CXL_DEVT_AFU(dev) ((MINOR(dev) % CXL_DEV_MINORS - 1) / 3)
+
+#define CXL_DEVT_IS_CARD(dev) (MINOR(dev) % CXL_DEV_MINORS == 0)
+
+static dev_t cxl_dev;
+
+static struct class *cxl_class;
+
+static int __afu_open(struct inode *inode, struct file *file, bool master)
+{
+       struct cxl *adapter;
+       struct cxl_afu *afu;
+       struct cxl_context *ctx;
+       int adapter_num = CXL_DEVT_ADAPTER(inode->i_rdev);
+       int slice = CXL_DEVT_AFU(inode->i_rdev);
+       int rc = -ENODEV;
+
+       pr_devel("afu_open afu%i.%i\n", slice, adapter_num);
+
+       if (!(adapter = get_cxl_adapter(adapter_num)))
+               return -ENODEV;
+
+       if (slice > adapter->slices)
+               goto err_put_adapter;
+
+       spin_lock(&adapter->afu_list_lock);
+       if (!(afu = adapter->afu[slice])) {
+               spin_unlock(&adapter->afu_list_lock);
+               goto err_put_adapter;
+       }
+       get_device(&afu->dev);
+       spin_unlock(&adapter->afu_list_lock);
+
+       if (!afu->current_mode)
+               goto err_put_afu;
+
+       if (!(ctx = cxl_context_alloc())) {
+               rc = -ENOMEM;
+               goto err_put_afu;
+       }
+
+       if ((rc = cxl_context_init(ctx, afu, master)))
+               goto err_put_afu;
+
+       pr_devel("afu_open pe: %i\n", ctx->pe);
+       file->private_data = ctx;
+       cxl_ctx_get();
+
+       /* Our ref on the AFU will now hold the adapter */
+       put_device(&adapter->dev);
+
+       return 0;
+
+err_put_afu:
+       put_device(&afu->dev);
+err_put_adapter:
+       put_device(&adapter->dev);
+       return rc;
+}
+static int afu_open(struct inode *inode, struct file *file)
+{
+       return __afu_open(inode, file, false);
+}
+
+static int afu_master_open(struct inode *inode, struct file *file)
+{
+       return __afu_open(inode, file, true);
+}
+
+static int afu_release(struct inode *inode, struct file *file)
+{
+       struct cxl_context *ctx = file->private_data;
+
+       pr_devel("%s: closing cxl file descriptor. pe: %i\n",
+                __func__, ctx->pe);
+       cxl_context_detach(ctx);
+
+       put_device(&ctx->afu->dev);
+
+       /*
+        * At this this point all bottom halfs have finished and we should be
+        * getting no more IRQs from the hardware for this context.  Once it's
+        * removed from the IDR (and RCU synchronised) it's safe to free the
+        * sstp and context.
+        */
+       cxl_context_free(ctx);
+
+       cxl_ctx_put();
+       return 0;
+}
+
+static long afu_ioctl_start_work(struct cxl_context *ctx,
+                                struct cxl_ioctl_start_work __user *uwork)
+{
+       struct cxl_ioctl_start_work work;
+       u64 amr = 0;
+       int rc;
+
+       pr_devel("%s: pe: %i\n", __func__, ctx->pe);
+
+       mutex_lock(&ctx->status_mutex);
+       if (ctx->status != OPENED) {
+               rc = -EIO;
+               goto out;
+       }
+
+       if (copy_from_user(&work, uwork,
+                          sizeof(struct cxl_ioctl_start_work))) {
+               rc = -EFAULT;
+               goto out;
+       }
+
+       /*
+        * if any of the reserved fields are set or any of the unused
+        * flags are set it's invalid
+        */
+       if (work.reserved1 || work.reserved2 || work.reserved3 ||
+           work.reserved4 || work.reserved5 || work.reserved6 ||
+           (work.flags & ~CXL_START_WORK_ALL)) {
+               rc = -EINVAL;
+               goto out;
+       }
+
+       if (!(work.flags & CXL_START_WORK_NUM_IRQS))
+               work.num_interrupts = ctx->afu->pp_irqs;
+       else if ((work.num_interrupts < ctx->afu->pp_irqs) ||
+                (work.num_interrupts > ctx->afu->irqs_max)) {
+               rc =  -EINVAL;
+               goto out;
+       }
+       if ((rc = afu_register_irqs(ctx, work.num_interrupts)))
+               goto out;
+
+       if (work.flags & CXL_START_WORK_AMR)
+               amr = work.amr & mfspr(SPRN_UAMOR);
+
+       /*
+        * We grab the PID here and not in the file open to allow for the case
+        * where a process (master, some daemon, etc) has opened the chardev on
+        * behalf of another process, so the AFU's mm gets bound to the process
+        * that performs this ioctl and not the process that opened the file.
+        */
+       ctx->pid = get_pid(get_task_pid(current, PIDTYPE_PID));
+
+       if ((rc = cxl_attach_process(ctx, false, work.work_element_descriptor,
+                                    amr)))
+               goto out;
+
+       ctx->status = STARTED;
+       rc = 0;
+out:
+       mutex_unlock(&ctx->status_mutex);
+       return rc;
+}
+static long afu_ioctl_process_element(struct cxl_context *ctx,
+                                     int __user *upe)
+{
+       pr_devel("%s: pe: %i\n", __func__, ctx->pe);
+
+       if (copy_to_user(upe, &ctx->pe, sizeof(__u32)))
+               return -EFAULT;
+
+       return 0;
+}
+
+static long afu_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+       struct cxl_context *ctx = file->private_data;
+
+       if (ctx->status == CLOSED)
+               return -EIO;
+
+       pr_devel("afu_ioctl\n");
+       switch (cmd) {
+       case CXL_IOCTL_START_WORK:
+               return afu_ioctl_start_work(ctx, (struct cxl_ioctl_start_work __user *)arg);
+       case CXL_IOCTL_GET_PROCESS_ELEMENT:
+               return afu_ioctl_process_element(ctx, (__u32 __user *)arg);
+       }
+       return -EINVAL;
+}
+
+static long afu_compat_ioctl(struct file *file, unsigned int cmd,
+                            unsigned long arg)
+{
+       return afu_ioctl(file, cmd, arg);
+}
+
+static int afu_mmap(struct file *file, struct vm_area_struct *vm)
+{
+       struct cxl_context *ctx = file->private_data;
+
+       /* AFU must be started before we can MMIO */
+       if (ctx->status != STARTED)
+               return -EIO;
+
+       return cxl_context_iomap(ctx, vm);
+}
+
+static unsigned int afu_poll(struct file *file, struct poll_table_struct *poll)
+{
+       struct cxl_context *ctx = file->private_data;
+       int mask = 0;
+       unsigned long flags;
+
+
+       poll_wait(file, &ctx->wq, poll);
+
+       pr_devel("afu_poll wait done pe: %i\n", ctx->pe);
+
+       spin_lock_irqsave(&ctx->lock, flags);
+       if (ctx->pending_irq || ctx->pending_fault ||
+           ctx->pending_afu_err)
+               mask |= POLLIN | POLLRDNORM;
+       else if (ctx->status == CLOSED)
+               /* Only error on closed when there are no futher events pending
+                */
+               mask |= POLLERR;
+       spin_unlock_irqrestore(&ctx->lock, flags);
+
+       pr_devel("afu_poll pe: %i returning %#x\n", ctx->pe, mask);
+
+       return mask;
+}
+
+static inline int ctx_event_pending(struct cxl_context *ctx)
+{
+       return (ctx->pending_irq || ctx->pending_fault ||
+           ctx->pending_afu_err || (ctx->status == CLOSED));
+}
+
+static ssize_t afu_read(struct file *file, char __user *buf, size_t count,
+                       loff_t *off)
+{
+       struct cxl_context *ctx = file->private_data;
+       struct cxl_event event;
+       unsigned long flags;
+       int rc;
+       DEFINE_WAIT(wait);
+
+       if (count < CXL_READ_MIN_SIZE)
+               return -EINVAL;
+
+       spin_lock_irqsave(&ctx->lock, flags);
+
+       for (;;) {
+               prepare_to_wait(&ctx->wq, &wait, TASK_INTERRUPTIBLE);
+               if (ctx_event_pending(ctx))
+                       break;
+
+               if (file->f_flags & O_NONBLOCK) {
+                       rc = -EAGAIN;
+                       goto out;
+               }
+
+               if (signal_pending(current)) {
+                       rc = -ERESTARTSYS;
+                       goto out;
+               }
+
+               spin_unlock_irqrestore(&ctx->lock, flags);
+               pr_devel("afu_read going to sleep...\n");
+               schedule();
+               pr_devel("afu_read woken up\n");
+               spin_lock_irqsave(&ctx->lock, flags);
+       }
+
+       finish_wait(&ctx->wq, &wait);
+
+       memset(&event, 0, sizeof(event));
+       event.header.process_element = ctx->pe;
+       event.header.size = sizeof(struct cxl_event_header);
+       if (ctx->pending_irq) {
+               pr_devel("afu_read delivering AFU interrupt\n");
+               event.header.size += sizeof(struct cxl_event_afu_interrupt);
+               event.header.type = CXL_EVENT_AFU_INTERRUPT;
+               event.irq.irq = find_first_bit(ctx->irq_bitmap, ctx->irq_count) + 1;
+               clear_bit(event.irq.irq - 1, ctx->irq_bitmap);
+               if (bitmap_empty(ctx->irq_bitmap, ctx->irq_count))
+                       ctx->pending_irq = false;
+       } else if (ctx->pending_fault) {
+               pr_devel("afu_read delivering data storage fault\n");
+               event.header.size += sizeof(struct cxl_event_data_storage);
+               event.header.type = CXL_EVENT_DATA_STORAGE;
+               event.fault.addr = ctx->fault_addr;
+               event.fault.dsisr = ctx->fault_dsisr;
+               ctx->pending_fault = false;
+       } else if (ctx->pending_afu_err) {
+               pr_devel("afu_read delivering afu error\n");
+               event.header.size += sizeof(struct cxl_event_afu_error);
+               event.header.type = CXL_EVENT_AFU_ERROR;
+               event.afu_error.error = ctx->afu_err;
+               ctx->pending_afu_err = false;
+       } else if (ctx->status == CLOSED) {
+               pr_devel("afu_read fatal error\n");
+               spin_unlock_irqrestore(&ctx->lock, flags);
+               return -EIO;
+       } else
+               WARN(1, "afu_read must be buggy\n");
+
+       spin_unlock_irqrestore(&ctx->lock, flags);
+
+       if (copy_to_user(buf, &event, event.header.size))
+               return -EFAULT;
+       return event.header.size;
+
+out:
+       finish_wait(&ctx->wq, &wait);
+       spin_unlock_irqrestore(&ctx->lock, flags);
+       return rc;
+}
+
+static const struct file_operations afu_fops = {
+       .owner          = THIS_MODULE,
+       .open           = afu_open,
+       .poll           = afu_poll,
+       .read           = afu_read,
+       .release        = afu_release,
+       .unlocked_ioctl = afu_ioctl,
+       .compat_ioctl   = afu_compat_ioctl,
+       .mmap           = afu_mmap,
+};
+
+static const struct file_operations afu_master_fops = {
+       .owner          = THIS_MODULE,
+       .open           = afu_master_open,
+       .poll           = afu_poll,
+       .read           = afu_read,
+       .release        = afu_release,
+       .unlocked_ioctl = afu_ioctl,
+       .compat_ioctl   = afu_compat_ioctl,
+       .mmap           = afu_mmap,
+};
+
+
+static char *cxl_devnode(struct device *dev, umode_t *mode)
+{
+       if (CXL_DEVT_IS_CARD(dev->devt)) {
+               /*
+                * These minor numbers will eventually be used to program the
+                * PSL and AFUs once we have dynamic reprogramming support
+                */
+               return NULL;
+       }
+       return kasprintf(GFP_KERNEL, "cxl/%s", dev_name(dev));
+}
+
+extern struct class *cxl_class;
+
+static int cxl_add_chardev(struct cxl_afu *afu, dev_t devt, struct cdev *cdev,
+                          struct device **chardev, char *postfix, char *desc,
+                          const struct file_operations *fops)
+{
+       struct device *dev;
+       int rc;
+
+       cdev_init(cdev, fops);
+       if ((rc = cdev_add(cdev, devt, 1))) {
+               dev_err(&afu->dev, "Unable to add %s chardev: %i\n", desc, rc);
+               return rc;
+       }
+
+       dev = device_create(cxl_class, &afu->dev, devt, afu,
+                       "afu%i.%i%s", afu->adapter->adapter_num, afu->slice, postfix);
+       if (IS_ERR(dev)) {
+               dev_err(&afu->dev, "Unable to create %s chardev in sysfs: %i\n", desc, rc);
+               rc = PTR_ERR(dev);
+               goto err;
+       }
+
+       *chardev = dev;
+
+       return 0;
+err:
+       cdev_del(cdev);
+       return rc;
+}
+
+int cxl_chardev_d_afu_add(struct cxl_afu *afu)
+{
+       return cxl_add_chardev(afu, CXL_AFU_MKDEV_D(afu), &afu->afu_cdev_d,
+                              &afu->chardev_d, "d", "dedicated",
+                              &afu_master_fops); /* Uses master fops */
+}
+
+int cxl_chardev_m_afu_add(struct cxl_afu *afu)
+{
+       return cxl_add_chardev(afu, CXL_AFU_MKDEV_M(afu), &afu->afu_cdev_m,
+                              &afu->chardev_m, "m", "master",
+                              &afu_master_fops);
+}
+
+int cxl_chardev_s_afu_add(struct cxl_afu *afu)
+{
+       return cxl_add_chardev(afu, CXL_AFU_MKDEV_S(afu), &afu->afu_cdev_s,
+                              &afu->chardev_s, "s", "shared",
+                              &afu_fops);
+}
+
+void cxl_chardev_afu_remove(struct cxl_afu *afu)
+{
+       if (afu->chardev_d) {
+               cdev_del(&afu->afu_cdev_d);
+               device_unregister(afu->chardev_d);
+               afu->chardev_d = NULL;
+       }
+       if (afu->chardev_m) {
+               cdev_del(&afu->afu_cdev_m);
+               device_unregister(afu->chardev_m);
+               afu->chardev_m = NULL;
+       }
+       if (afu->chardev_s) {
+               cdev_del(&afu->afu_cdev_s);
+               device_unregister(afu->chardev_s);
+               afu->chardev_s = NULL;
+       }
+}
+
+int cxl_register_afu(struct cxl_afu *afu)
+{
+       afu->dev.class = cxl_class;
+
+       return device_register(&afu->dev);
+}
+
+int cxl_register_adapter(struct cxl *adapter)
+{
+       adapter->dev.class = cxl_class;
+
+       /*
+        * Future: When we support dynamically reprogramming the PSL & AFU we
+        * will expose the interface to do that via a chardev:
+        * adapter->dev.devt = CXL_CARD_MKDEV(adapter);
+        */
+
+       return device_register(&adapter->dev);
+}
+
+int __init cxl_file_init(void)
+{
+       int rc;
+
+       /*
+        * If these change we really need to update API.  Either change some
+        * flags or update API version number CXL_API_VERSION.
+        */
+       BUILD_BUG_ON(CXL_API_VERSION != 1);
+       BUILD_BUG_ON(sizeof(struct cxl_ioctl_start_work) != 64);
+       BUILD_BUG_ON(sizeof(struct cxl_event_header) != 8);
+       BUILD_BUG_ON(sizeof(struct cxl_event_afu_interrupt) != 8);
+       BUILD_BUG_ON(sizeof(struct cxl_event_data_storage) != 32);
+       BUILD_BUG_ON(sizeof(struct cxl_event_afu_error) != 16);
+
+       if ((rc = alloc_chrdev_region(&cxl_dev, 0, CXL_NUM_MINORS, "cxl"))) {
+               pr_err("Unable to allocate CXL major number: %i\n", rc);
+               return rc;
+       }
+
+       pr_devel("CXL device allocated, MAJOR %i\n", MAJOR(cxl_dev));
+
+       cxl_class = class_create(THIS_MODULE, "cxl");
+       if (IS_ERR(cxl_class)) {
+               pr_err("Unable to create CXL class\n");
+               rc = PTR_ERR(cxl_class);
+               goto err;
+       }
+       cxl_class->devnode = cxl_devnode;
+
+       return 0;
+
+err:
+       unregister_chrdev_region(cxl_dev, CXL_NUM_MINORS);
+       return rc;
+}
+
+void cxl_file_exit(void)
+{
+       unregister_chrdev_region(cxl_dev, CXL_NUM_MINORS);
+       class_destroy(cxl_class);
+}
diff --git a/drivers/misc/cxl/irq.c b/drivers/misc/cxl/irq.c
new file mode 100644 (file)
index 0000000..336020c
--- /dev/null
@@ -0,0 +1,402 @@
+/*
+ * Copyright 2014 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.
+ */
+
+#include <linux/interrupt.h>
+#include <linux/workqueue.h>
+#include <linux/sched.h>
+#include <linux/wait.h>
+#include <linux/slab.h>
+#include <linux/pid.h>
+#include <asm/cputable.h>
+#include <misc/cxl.h>
+
+#include "cxl.h"
+
+/* XXX: This is implementation specific */
+static irqreturn_t handle_psl_slice_error(struct cxl_context *ctx, u64 dsisr, u64 errstat)
+{
+       u64 fir1, fir2, fir_slice, serr, afu_debug;
+
+       fir1 = cxl_p1_read(ctx->afu->adapter, CXL_PSL_FIR1);
+       fir2 = cxl_p1_read(ctx->afu->adapter, CXL_PSL_FIR2);
+       fir_slice = cxl_p1n_read(ctx->afu, CXL_PSL_FIR_SLICE_An);
+       serr = cxl_p1n_read(ctx->afu, CXL_PSL_SERR_An);
+       afu_debug = cxl_p1n_read(ctx->afu, CXL_AFU_DEBUG_An);
+
+       dev_crit(&ctx->afu->dev, "PSL ERROR STATUS: 0x%.16llx\n", errstat);
+       dev_crit(&ctx->afu->dev, "PSL_FIR1: 0x%.16llx\n", fir1);
+       dev_crit(&ctx->afu->dev, "PSL_FIR2: 0x%.16llx\n", fir2);
+       dev_crit(&ctx->afu->dev, "PSL_SERR_An: 0x%.16llx\n", serr);
+       dev_crit(&ctx->afu->dev, "PSL_FIR_SLICE_An: 0x%.16llx\n", fir_slice);
+       dev_crit(&ctx->afu->dev, "CXL_PSL_AFU_DEBUG_An: 0x%.16llx\n", afu_debug);
+
+       dev_crit(&ctx->afu->dev, "STOPPING CXL TRACE\n");
+       cxl_stop_trace(ctx->afu->adapter);
+
+       return cxl_ack_irq(ctx, 0, errstat);
+}
+
+irqreturn_t cxl_slice_irq_err(int irq, void *data)
+{
+       struct cxl_afu *afu = data;
+       u64 fir_slice, errstat, serr, afu_debug;
+
+       WARN(irq, "CXL SLICE ERROR interrupt %i\n", irq);
+
+       serr = cxl_p1n_read(afu, CXL_PSL_SERR_An);
+       fir_slice = cxl_p1n_read(afu, CXL_PSL_FIR_SLICE_An);
+       errstat = cxl_p2n_read(afu, CXL_PSL_ErrStat_An);
+       afu_debug = cxl_p1n_read(afu, CXL_AFU_DEBUG_An);
+       dev_crit(&afu->dev, "PSL_SERR_An: 0x%.16llx\n", serr);
+       dev_crit(&afu->dev, "PSL_FIR_SLICE_An: 0x%.16llx\n", fir_slice);
+       dev_crit(&afu->dev, "CXL_PSL_ErrStat_An: 0x%.16llx\n", errstat);
+       dev_crit(&afu->dev, "CXL_PSL_AFU_DEBUG_An: 0x%.16llx\n", afu_debug);
+
+       cxl_p1n_write(afu, CXL_PSL_SERR_An, serr);
+
+       return IRQ_HANDLED;
+}
+
+static irqreturn_t cxl_irq_err(int irq, void *data)
+{
+       struct cxl *adapter = data;
+       u64 fir1, fir2, err_ivte;
+
+       WARN(1, "CXL ERROR interrupt %i\n", irq);
+
+       err_ivte = cxl_p1_read(adapter, CXL_PSL_ErrIVTE);
+       dev_crit(&adapter->dev, "PSL_ErrIVTE: 0x%.16llx\n", err_ivte);
+
+       dev_crit(&adapter->dev, "STOPPING CXL TRACE\n");
+       cxl_stop_trace(adapter);
+
+       fir1 = cxl_p1_read(adapter, CXL_PSL_FIR1);
+       fir2 = cxl_p1_read(adapter, CXL_PSL_FIR2);
+
+       dev_crit(&adapter->dev, "PSL_FIR1: 0x%.16llx\nPSL_FIR2: 0x%.16llx\n", fir1, fir2);
+
+       return IRQ_HANDLED;
+}
+
+static irqreturn_t schedule_cxl_fault(struct cxl_context *ctx, u64 dsisr, u64 dar)
+{
+       ctx->dsisr = dsisr;
+       ctx->dar = dar;
+       schedule_work(&ctx->fault_work);
+       return IRQ_HANDLED;
+}
+
+static irqreturn_t cxl_irq(int irq, void *data)
+{
+       struct cxl_context *ctx = data;
+       struct cxl_irq_info irq_info;
+       u64 dsisr, dar;
+       int result;
+
+       if ((result = cxl_get_irq(ctx, &irq_info))) {
+               WARN(1, "Unable to get CXL IRQ Info: %i\n", result);
+               return IRQ_HANDLED;
+       }
+
+       dsisr = irq_info.dsisr;
+       dar = irq_info.dar;
+
+       pr_devel("CXL interrupt %i for afu pe: %i DSISR: %#llx DAR: %#llx\n", irq, ctx->pe, dsisr, dar);
+
+       if (dsisr & CXL_PSL_DSISR_An_DS) {
+               /*
+                * We don't inherently need to sleep to handle this, but we do
+                * need to get a ref to the task's mm, which we can't do from
+                * irq context without the potential for a deadlock since it
+                * takes the task_lock. An alternate option would be to keep a
+                * reference to the task's mm the entire time it has cxl open,
+                * but to do that we need to solve the issue where we hold a
+                * ref to the mm, but the mm can hold a ref to the fd after an
+                * mmap preventing anything from being cleaned up.
+                */
+               pr_devel("Scheduling segment miss handling for later pe: %i\n", ctx->pe);
+               return schedule_cxl_fault(ctx, dsisr, dar);
+       }
+
+       if (dsisr & CXL_PSL_DSISR_An_M)
+               pr_devel("CXL interrupt: PTE not found\n");
+       if (dsisr & CXL_PSL_DSISR_An_P)
+               pr_devel("CXL interrupt: Storage protection violation\n");
+       if (dsisr & CXL_PSL_DSISR_An_A)
+               pr_devel("CXL interrupt: AFU lock access to write through or cache inhibited storage\n");
+       if (dsisr & CXL_PSL_DSISR_An_S)
+               pr_devel("CXL interrupt: Access was afu_wr or afu_zero\n");
+       if (dsisr & CXL_PSL_DSISR_An_K)
+               pr_devel("CXL interrupt: Access not permitted by virtual page class key protection\n");
+
+       if (dsisr & CXL_PSL_DSISR_An_DM) {
+               /*
+                * In some cases we might be able to handle the fault
+                * immediately if hash_page would succeed, but we still need
+                * the task's mm, which as above we can't get without a lock
+                */
+               pr_devel("Scheduling page fault handling for later pe: %i\n", ctx->pe);
+               return schedule_cxl_fault(ctx, dsisr, dar);
+       }
+       if (dsisr & CXL_PSL_DSISR_An_ST)
+               WARN(1, "CXL interrupt: Segment Table PTE not found\n");
+       if (dsisr & CXL_PSL_DSISR_An_UR)
+               pr_devel("CXL interrupt: AURP PTE not found\n");
+       if (dsisr & CXL_PSL_DSISR_An_PE)
+               return handle_psl_slice_error(ctx, dsisr, irq_info.errstat);
+       if (dsisr & CXL_PSL_DSISR_An_AE) {
+               pr_devel("CXL interrupt: AFU Error %.llx\n", irq_info.afu_err);
+
+               if (ctx->pending_afu_err) {
+                       /*
+                        * This shouldn't happen - the PSL treats these errors
+                        * as fatal and will have reset the AFU, so there's not
+                        * much point buffering multiple AFU errors.
+                        * OTOH if we DO ever see a storm of these come in it's
+                        * probably best that we log them somewhere:
+                        */
+                       dev_err_ratelimited(&ctx->afu->dev, "CXL AFU Error "
+                                           "undelivered to pe %i: %.llx\n",
+                                           ctx->pe, irq_info.afu_err);
+               } else {
+                       spin_lock(&ctx->lock);
+                       ctx->afu_err = irq_info.afu_err;
+                       ctx->pending_afu_err = 1;
+                       spin_unlock(&ctx->lock);
+
+                       wake_up_all(&ctx->wq);
+               }
+
+               cxl_ack_irq(ctx, CXL_PSL_TFC_An_A, 0);
+       }
+       if (dsisr & CXL_PSL_DSISR_An_OC)
+               pr_devel("CXL interrupt: OS Context Warning\n");
+
+       WARN(1, "Unhandled CXL PSL IRQ\n");
+       return IRQ_HANDLED;
+}
+
+static irqreturn_t cxl_irq_multiplexed(int irq, void *data)
+{
+       struct cxl_afu *afu = data;
+       struct cxl_context *ctx;
+       int ph = cxl_p2n_read(afu, CXL_PSL_PEHandle_An) & 0xffff;
+       int ret;
+
+       rcu_read_lock();
+       ctx = idr_find(&afu->contexts_idr, ph);
+       if (ctx) {
+               ret = cxl_irq(irq, ctx);
+               rcu_read_unlock();
+               return ret;
+       }
+       rcu_read_unlock();
+
+       WARN(1, "Unable to demultiplex CXL PSL IRQ\n");
+       return IRQ_HANDLED;
+}
+
+static irqreturn_t cxl_irq_afu(int irq, void *data)
+{
+       struct cxl_context *ctx = data;
+       irq_hw_number_t hwirq = irqd_to_hwirq(irq_get_irq_data(irq));
+       int irq_off, afu_irq = 1;
+       __u16 range;
+       int r;
+
+       for (r = 1; r < CXL_IRQ_RANGES; r++) {
+               irq_off = hwirq - ctx->irqs.offset[r];
+               range = ctx->irqs.range[r];
+               if (irq_off >= 0 && irq_off < range) {
+                       afu_irq += irq_off;
+                       break;
+               }
+               afu_irq += range;
+       }
+       if (unlikely(r >= CXL_IRQ_RANGES)) {
+               WARN(1, "Recieved AFU IRQ out of range for pe %i (virq %i hwirq %lx)\n",
+                    ctx->pe, irq, hwirq);
+               return IRQ_HANDLED;
+       }
+
+       pr_devel("Received AFU interrupt %i for pe: %i (virq %i hwirq %lx)\n",
+              afu_irq, ctx->pe, irq, hwirq);
+
+       if (unlikely(!ctx->irq_bitmap)) {
+               WARN(1, "Recieved AFU IRQ for context with no IRQ bitmap\n");
+               return IRQ_HANDLED;
+       }
+       spin_lock(&ctx->lock);
+       set_bit(afu_irq - 1, ctx->irq_bitmap);
+       ctx->pending_irq = true;
+       spin_unlock(&ctx->lock);
+
+       wake_up_all(&ctx->wq);
+
+       return IRQ_HANDLED;
+}
+
+unsigned int cxl_map_irq(struct cxl *adapter, irq_hw_number_t hwirq,
+                        irq_handler_t handler, void *cookie)
+{
+       unsigned int virq;
+       int result;
+
+       /* IRQ Domain? */
+       virq = irq_create_mapping(NULL, hwirq);
+       if (!virq) {
+               dev_warn(&adapter->dev, "cxl_map_irq: irq_create_mapping failed\n");
+               return 0;
+       }
+
+       cxl_setup_irq(adapter, hwirq, virq);
+
+       pr_devel("hwirq %#lx mapped to virq %u\n", hwirq, virq);
+
+       result = request_irq(virq, handler, 0, "cxl", cookie);
+       if (result) {
+               dev_warn(&adapter->dev, "cxl_map_irq: request_irq failed: %i\n", result);
+               return 0;
+       }
+
+       return virq;
+}
+
+void cxl_unmap_irq(unsigned int virq, void *cookie)
+{
+       free_irq(virq, cookie);
+       irq_dispose_mapping(virq);
+}
+
+static int cxl_register_one_irq(struct cxl *adapter,
+                               irq_handler_t handler,
+                               void *cookie,
+                               irq_hw_number_t *dest_hwirq,
+                               unsigned int *dest_virq)
+{
+       int hwirq, virq;
+
+       if ((hwirq = cxl_alloc_one_irq(adapter)) < 0)
+               return hwirq;
+
+       if (!(virq = cxl_map_irq(adapter, hwirq, handler, cookie)))
+               goto err;
+
+       *dest_hwirq = hwirq;
+       *dest_virq = virq;
+
+       return 0;
+
+err:
+       cxl_release_one_irq(adapter, hwirq);
+       return -ENOMEM;
+}
+
+int cxl_register_psl_err_irq(struct cxl *adapter)
+{
+       int rc;
+
+       if ((rc = cxl_register_one_irq(adapter, cxl_irq_err, adapter,
+                                      &adapter->err_hwirq,
+                                      &adapter->err_virq)))
+               return rc;
+
+       cxl_p1_write(adapter, CXL_PSL_ErrIVTE, adapter->err_hwirq & 0xffff);
+
+       return 0;
+}
+
+void cxl_release_psl_err_irq(struct cxl *adapter)
+{
+       cxl_p1_write(adapter, CXL_PSL_ErrIVTE, 0x0000000000000000);
+       cxl_unmap_irq(adapter->err_virq, adapter);
+       cxl_release_one_irq(adapter, adapter->err_hwirq);
+}
+
+int cxl_register_serr_irq(struct cxl_afu *afu)
+{
+       u64 serr;
+       int rc;
+
+       if ((rc = cxl_register_one_irq(afu->adapter, cxl_slice_irq_err, afu,
+                                      &afu->serr_hwirq,
+                                      &afu->serr_virq)))
+               return rc;
+
+       serr = cxl_p1n_read(afu, CXL_PSL_SERR_An);
+       serr = (serr & 0x00ffffffffff0000ULL) | (afu->serr_hwirq & 0xffff);
+       cxl_p1n_write(afu, CXL_PSL_SERR_An, serr);
+
+       return 0;
+}
+
+void cxl_release_serr_irq(struct cxl_afu *afu)
+{
+       cxl_p1n_write(afu, CXL_PSL_SERR_An, 0x0000000000000000);
+       cxl_unmap_irq(afu->serr_virq, afu);
+       cxl_release_one_irq(afu->adapter, afu->serr_hwirq);
+}
+
+int cxl_register_psl_irq(struct cxl_afu *afu)
+{
+       return cxl_register_one_irq(afu->adapter, cxl_irq_multiplexed, afu,
+                       &afu->psl_hwirq, &afu->psl_virq);
+}
+
+void cxl_release_psl_irq(struct cxl_afu *afu)
+{
+       cxl_unmap_irq(afu->psl_virq, afu);
+       cxl_release_one_irq(afu->adapter, afu->psl_hwirq);
+}
+
+int afu_register_irqs(struct cxl_context *ctx, u32 count)
+{
+       irq_hw_number_t hwirq;
+       int rc, r, i;
+
+       if ((rc = cxl_alloc_irq_ranges(&ctx->irqs, ctx->afu->adapter, count)))
+               return rc;
+
+       /* Multiplexed PSL Interrupt */
+       ctx->irqs.offset[0] = ctx->afu->psl_hwirq;
+       ctx->irqs.range[0] = 1;
+
+       ctx->irq_count = count;
+       ctx->irq_bitmap = kcalloc(BITS_TO_LONGS(count),
+                                 sizeof(*ctx->irq_bitmap), GFP_KERNEL);
+       if (!ctx->irq_bitmap)
+               return -ENOMEM;
+       for (r = 1; r < CXL_IRQ_RANGES; r++) {
+               hwirq = ctx->irqs.offset[r];
+               for (i = 0; i < ctx->irqs.range[r]; hwirq++, i++) {
+                       cxl_map_irq(ctx->afu->adapter, hwirq,
+                                    cxl_irq_afu, ctx);
+               }
+       }
+
+       return 0;
+}
+
+void afu_release_irqs(struct cxl_context *ctx)
+{
+       irq_hw_number_t hwirq;
+       unsigned int virq;
+       int r, i;
+
+       for (r = 1; r < CXL_IRQ_RANGES; r++) {
+               hwirq = ctx->irqs.offset[r];
+               for (i = 0; i < ctx->irqs.range[r]; hwirq++, i++) {
+                       virq = irq_find_mapping(NULL, hwirq);
+                       if (virq)
+                               cxl_unmap_irq(virq, ctx);
+               }
+       }
+
+       cxl_release_irq_ranges(&ctx->irqs, ctx->afu->adapter);
+}
diff --git a/drivers/misc/cxl/main.c b/drivers/misc/cxl/main.c
new file mode 100644 (file)
index 0000000..4cde9b6
--- /dev/null
@@ -0,0 +1,230 @@
+/*
+ * Copyright 2014 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.
+ */
+
+#include <linux/spinlock.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/mutex.h>
+#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/mm.h>
+#include <linux/of.h>
+#include <linux/slab.h>
+#include <linux/idr.h>
+#include <linux/pci.h>
+#include <asm/cputable.h>
+#include <misc/cxl.h>
+
+#include "cxl.h"
+
+static DEFINE_SPINLOCK(adapter_idr_lock);
+static DEFINE_IDR(cxl_adapter_idr);
+
+uint cxl_verbose;
+module_param_named(verbose, cxl_verbose, uint, 0600);
+MODULE_PARM_DESC(verbose, "Enable verbose dmesg output");
+
+static inline void _cxl_slbia(struct cxl_context *ctx, struct mm_struct *mm)
+{
+       struct task_struct *task;
+       unsigned long flags;
+       if (!(task = get_pid_task(ctx->pid, PIDTYPE_PID))) {
+               pr_devel("%s unable to get task %i\n",
+                        __func__, pid_nr(ctx->pid));
+               return;
+       }
+
+       if (task->mm != mm)
+               goto out_put;
+
+       pr_devel("%s matched mm - card: %i afu: %i pe: %i\n", __func__,
+                ctx->afu->adapter->adapter_num, ctx->afu->slice, ctx->pe);
+
+       spin_lock_irqsave(&ctx->sste_lock, flags);
+       memset(ctx->sstp, 0, ctx->sst_size);
+       spin_unlock_irqrestore(&ctx->sste_lock, flags);
+       mb();
+       cxl_afu_slbia(ctx->afu);
+out_put:
+       put_task_struct(task);
+}
+
+static inline void cxl_slbia_core(struct mm_struct *mm)
+{
+       struct cxl *adapter;
+       struct cxl_afu *afu;
+       struct cxl_context *ctx;
+       int card, slice, id;
+
+       pr_devel("%s called\n", __func__);
+
+       spin_lock(&adapter_idr_lock);
+       idr_for_each_entry(&cxl_adapter_idr, adapter, card) {
+               /* XXX: Make this lookup faster with link from mm to ctx */
+               spin_lock(&adapter->afu_list_lock);
+               for (slice = 0; slice < adapter->slices; slice++) {
+                       afu = adapter->afu[slice];
+                       if (!afu->enabled)
+                               continue;
+                       rcu_read_lock();
+                       idr_for_each_entry(&afu->contexts_idr, ctx, id)
+                               _cxl_slbia(ctx, mm);
+                       rcu_read_unlock();
+               }
+               spin_unlock(&adapter->afu_list_lock);
+       }
+       spin_unlock(&adapter_idr_lock);
+}
+
+static struct cxl_calls cxl_calls = {
+       .cxl_slbia = cxl_slbia_core,
+       .owner = THIS_MODULE,
+};
+
+int cxl_alloc_sst(struct cxl_context *ctx)
+{
+       unsigned long vsid;
+       u64 ea_mask, size, sstp0, sstp1;
+
+       sstp0 = 0;
+       sstp1 = 0;
+
+       ctx->sst_size = PAGE_SIZE;
+       ctx->sst_lru = 0;
+       ctx->sstp = (struct cxl_sste *)get_zeroed_page(GFP_KERNEL);
+       if (!ctx->sstp) {
+               pr_err("cxl_alloc_sst: Unable to allocate segment table\n");
+               return -ENOMEM;
+       }
+       pr_devel("SSTP allocated at 0x%p\n", ctx->sstp);
+
+       vsid  = get_kernel_vsid((u64)ctx->sstp, mmu_kernel_ssize) << 12;
+
+       sstp0 |= (u64)mmu_kernel_ssize << CXL_SSTP0_An_B_SHIFT;
+       sstp0 |= (SLB_VSID_KERNEL | mmu_psize_defs[mmu_linear_psize].sllp) << 50;
+
+       size = (((u64)ctx->sst_size >> 8) - 1) << CXL_SSTP0_An_SegTableSize_SHIFT;
+       if (unlikely(size & ~CXL_SSTP0_An_SegTableSize_MASK)) {
+               WARN(1, "Impossible segment table size\n");
+               return -EINVAL;
+       }
+       sstp0 |= size;
+
+       if (mmu_kernel_ssize == MMU_SEGSIZE_256M)
+               ea_mask = 0xfffff00ULL;
+       else
+               ea_mask = 0xffffffff00ULL;
+
+       sstp0 |=  vsid >>     (50-14);  /*   Top 14 bits of VSID */
+       sstp1 |= (vsid << (64-(50-14))) & ~ea_mask;
+       sstp1 |= (u64)ctx->sstp & ea_mask;
+       sstp1 |= CXL_SSTP1_An_V;
+
+       pr_devel("Looked up %#llx: slbfee. %#llx (ssize: %x, vsid: %#lx), copied to SSTP0: %#llx, SSTP1: %#llx\n",
+                       (u64)ctx->sstp, (u64)ctx->sstp & ESID_MASK, mmu_kernel_ssize, vsid, sstp0, sstp1);
+
+       /* Store calculated sstp hardware points for use later */
+       ctx->sstp0 = sstp0;
+       ctx->sstp1 = sstp1;
+
+       return 0;
+}
+
+/* Find a CXL adapter by it's number and increase it's refcount */
+struct cxl *get_cxl_adapter(int num)
+{
+       struct cxl *adapter;
+
+       spin_lock(&adapter_idr_lock);
+       if ((adapter = idr_find(&cxl_adapter_idr, num)))
+               get_device(&adapter->dev);
+       spin_unlock(&adapter_idr_lock);
+
+       return adapter;
+}
+
+int cxl_alloc_adapter_nr(struct cxl *adapter)
+{
+       int i;
+
+       idr_preload(GFP_KERNEL);
+       spin_lock(&adapter_idr_lock);
+       i = idr_alloc(&cxl_adapter_idr, adapter, 0, 0, GFP_NOWAIT);
+       spin_unlock(&adapter_idr_lock);
+       idr_preload_end();
+       if (i < 0)
+               return i;
+
+       adapter->adapter_num = i;
+
+       return 0;
+}
+
+void cxl_remove_adapter_nr(struct cxl *adapter)
+{
+       idr_remove(&cxl_adapter_idr, adapter->adapter_num);
+}
+
+int cxl_afu_select_best_mode(struct cxl_afu *afu)
+{
+       if (afu->modes_supported & CXL_MODE_DIRECTED)
+               return cxl_afu_activate_mode(afu, CXL_MODE_DIRECTED);
+
+       if (afu->modes_supported & CXL_MODE_DEDICATED)
+               return cxl_afu_activate_mode(afu, CXL_MODE_DEDICATED);
+
+       dev_warn(&afu->dev, "No supported programming modes available\n");
+       /* We don't fail this so the user can inspect sysfs */
+       return 0;
+}
+
+static int __init init_cxl(void)
+{
+       int rc = 0;
+
+       if (!cpu_has_feature(CPU_FTR_HVMODE))
+               return -EPERM;
+
+       if ((rc = cxl_file_init()))
+               return rc;
+
+       cxl_debugfs_init();
+
+       if ((rc = register_cxl_calls(&cxl_calls)))
+               goto err;
+
+       if ((rc = pci_register_driver(&cxl_pci_driver)))
+               goto err1;
+
+       return 0;
+err1:
+       unregister_cxl_calls(&cxl_calls);
+err:
+       cxl_debugfs_exit();
+       cxl_file_exit();
+
+       return rc;
+}
+
+static void exit_cxl(void)
+{
+       pci_unregister_driver(&cxl_pci_driver);
+
+       cxl_debugfs_exit();
+       cxl_file_exit();
+       unregister_cxl_calls(&cxl_calls);
+}
+
+module_init(init_cxl);
+module_exit(exit_cxl);
+
+MODULE_DESCRIPTION("IBM Coherent Accelerator");
+MODULE_AUTHOR("Ian Munsie <imunsie@au1.ibm.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/misc/cxl/native.c b/drivers/misc/cxl/native.c
new file mode 100644 (file)
index 0000000..623286a
--- /dev/null
@@ -0,0 +1,683 @@
+/*
+ * Copyright 2014 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.
+ */
+
+#include <linux/spinlock.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/sched.h>
+#include <linux/mutex.h>
+#include <linux/mm.h>
+#include <linux/uaccess.h>
+#include <asm/synch.h>
+#include <misc/cxl.h>
+
+#include "cxl.h"
+
+static int afu_control(struct cxl_afu *afu, u64 command,
+                      u64 result, u64 mask, bool enabled)
+{
+       u64 AFU_Cntl = cxl_p2n_read(afu, CXL_AFU_Cntl_An);
+       unsigned long timeout = jiffies + (HZ * CXL_TIMEOUT);
+
+       spin_lock(&afu->afu_cntl_lock);
+       pr_devel("AFU command starting: %llx\n", command);
+
+       cxl_p2n_write(afu, CXL_AFU_Cntl_An, AFU_Cntl | command);
+
+       AFU_Cntl = cxl_p2n_read(afu, CXL_AFU_Cntl_An);
+       while ((AFU_Cntl & mask) != result) {
+               if (time_after_eq(jiffies, timeout)) {
+                       dev_warn(&afu->dev, "WARNING: AFU control timed out!\n");
+                       spin_unlock(&afu->afu_cntl_lock);
+                       return -EBUSY;
+               }
+               pr_devel_ratelimited("AFU control... (0x%.16llx)\n",
+                                    AFU_Cntl | command);
+               cpu_relax();
+               AFU_Cntl = cxl_p2n_read(afu, CXL_AFU_Cntl_An);
+       };
+       pr_devel("AFU command complete: %llx\n", command);
+       afu->enabled = enabled;
+       spin_unlock(&afu->afu_cntl_lock);
+
+       return 0;
+}
+
+static int afu_enable(struct cxl_afu *afu)
+{
+       pr_devel("AFU enable request\n");
+
+       return afu_control(afu, CXL_AFU_Cntl_An_E,
+                          CXL_AFU_Cntl_An_ES_Enabled,
+                          CXL_AFU_Cntl_An_ES_MASK, true);
+}
+
+int cxl_afu_disable(struct cxl_afu *afu)
+{
+       pr_devel("AFU disable request\n");
+
+       return afu_control(afu, 0, CXL_AFU_Cntl_An_ES_Disabled,
+                          CXL_AFU_Cntl_An_ES_MASK, false);
+}
+
+/* This will disable as well as reset */
+int cxl_afu_reset(struct cxl_afu *afu)
+{
+       pr_devel("AFU reset request\n");
+
+       return afu_control(afu, CXL_AFU_Cntl_An_RA,
+                          CXL_AFU_Cntl_An_RS_Complete | CXL_AFU_Cntl_An_ES_Disabled,
+                          CXL_AFU_Cntl_An_RS_MASK | CXL_AFU_Cntl_An_ES_MASK,
+                          false);
+}
+
+static int afu_check_and_enable(struct cxl_afu *afu)
+{
+       if (afu->enabled)
+               return 0;
+       return afu_enable(afu);
+}
+
+int cxl_psl_purge(struct cxl_afu *afu)
+{
+       u64 PSL_CNTL = cxl_p1n_read(afu, CXL_PSL_SCNTL_An);
+       u64 AFU_Cntl = cxl_p2n_read(afu, CXL_AFU_Cntl_An);
+       u64 dsisr, dar;
+       u64 start, end;
+       unsigned long timeout = jiffies + (HZ * CXL_TIMEOUT);
+
+       pr_devel("PSL purge request\n");
+
+       if ((AFU_Cntl & CXL_AFU_Cntl_An_ES_MASK) != CXL_AFU_Cntl_An_ES_Disabled) {
+               WARN(1, "psl_purge request while AFU not disabled!\n");
+               cxl_afu_disable(afu);
+       }
+
+       cxl_p1n_write(afu, CXL_PSL_SCNTL_An,
+                      PSL_CNTL | CXL_PSL_SCNTL_An_Pc);
+       start = local_clock();
+       PSL_CNTL = cxl_p1n_read(afu, CXL_PSL_SCNTL_An);
+       while ((PSL_CNTL &  CXL_PSL_SCNTL_An_Ps_MASK)
+                       == CXL_PSL_SCNTL_An_Ps_Pending) {
+               if (time_after_eq(jiffies, timeout)) {
+                       dev_warn(&afu->dev, "WARNING: PSL Purge timed out!\n");
+                       return -EBUSY;
+               }
+               dsisr = cxl_p2n_read(afu, CXL_PSL_DSISR_An);
+               pr_devel_ratelimited("PSL purging... PSL_CNTL: 0x%.16llx  PSL_DSISR: 0x%.16llx\n", PSL_CNTL, dsisr);
+               if (dsisr & CXL_PSL_DSISR_TRANS) {
+                       dar = cxl_p2n_read(afu, CXL_PSL_DAR_An);
+                       dev_notice(&afu->dev, "PSL purge terminating pending translation, DSISR: 0x%.16llx, DAR: 0x%.16llx\n", dsisr, dar);
+                       cxl_p2n_write(afu, CXL_PSL_TFC_An, CXL_PSL_TFC_An_AE);
+               } else if (dsisr) {
+                       dev_notice(&afu->dev, "PSL purge acknowledging pending non-translation fault, DSISR: 0x%.16llx\n", dsisr);
+                       cxl_p2n_write(afu, CXL_PSL_TFC_An, CXL_PSL_TFC_An_A);
+               } else {
+                       cpu_relax();
+               }
+               PSL_CNTL = cxl_p1n_read(afu, CXL_PSL_SCNTL_An);
+       };
+       end = local_clock();
+       pr_devel("PSL purged in %lld ns\n", end - start);
+
+       cxl_p1n_write(afu, CXL_PSL_SCNTL_An,
+                      PSL_CNTL & ~CXL_PSL_SCNTL_An_Pc);
+       return 0;
+}
+
+static int spa_max_procs(int spa_size)
+{
+       /*
+        * From the CAIA:
+        *    end_of_SPA_area = SPA_Base + ((n+4) * 128) + (( ((n*8) + 127) >> 7) * 128) + 255
+        * Most of that junk is really just an overly-complicated way of saying
+        * the last 256 bytes are __aligned(128), so it's really:
+        *    end_of_SPA_area = end_of_PSL_queue_area + __aligned(128) 255
+        * and
+        *    end_of_PSL_queue_area = SPA_Base + ((n+4) * 128) + (n*8) - 1
+        * so
+        *    sizeof(SPA) = ((n+4) * 128) + (n*8) + __aligned(128) 256
+        * Ignore the alignment (which is safe in this case as long as we are
+        * careful with our rounding) and solve for n:
+        */
+       return ((spa_size / 8) - 96) / 17;
+}
+
+static int alloc_spa(struct cxl_afu *afu)
+{
+       u64 spap;
+
+       /* Work out how many pages to allocate */
+       afu->spa_order = 0;
+       do {
+               afu->spa_order++;
+               afu->spa_size = (1 << afu->spa_order) * PAGE_SIZE;
+               afu->spa_max_procs = spa_max_procs(afu->spa_size);
+       } while (afu->spa_max_procs < afu->num_procs);
+
+       WARN_ON(afu->spa_size > 0x100000); /* Max size supported by the hardware */
+
+       if (!(afu->spa = (struct cxl_process_element *)
+             __get_free_pages(GFP_KERNEL | __GFP_ZERO, afu->spa_order))) {
+               pr_err("cxl_alloc_spa: Unable to allocate scheduled process area\n");
+               return -ENOMEM;
+       }
+       pr_devel("spa pages: %i afu->spa_max_procs: %i   afu->num_procs: %i\n",
+                1<<afu->spa_order, afu->spa_max_procs, afu->num_procs);
+
+       afu->sw_command_status = (__be64 *)((char *)afu->spa +
+                                           ((afu->spa_max_procs + 3) * 128));
+
+       spap = virt_to_phys(afu->spa) & CXL_PSL_SPAP_Addr;
+       spap |= ((afu->spa_size >> (12 - CXL_PSL_SPAP_Size_Shift)) - 1) & CXL_PSL_SPAP_Size;
+       spap |= CXL_PSL_SPAP_V;
+       pr_devel("cxl: SPA allocated at 0x%p. Max processes: %i, sw_command_status: 0x%p CXL_PSL_SPAP_An=0x%016llx\n", afu->spa, afu->spa_max_procs, afu->sw_command_status, spap);
+       cxl_p1n_write(afu, CXL_PSL_SPAP_An, spap);
+
+       return 0;
+}
+
+static void release_spa(struct cxl_afu *afu)
+{
+       free_pages((unsigned long) afu->spa, afu->spa_order);
+}
+
+int cxl_tlb_slb_invalidate(struct cxl *adapter)
+{
+       unsigned long timeout = jiffies + (HZ * CXL_TIMEOUT);
+
+       pr_devel("CXL adapter wide TLBIA & SLBIA\n");
+
+       cxl_p1_write(adapter, CXL_PSL_AFUSEL, CXL_PSL_AFUSEL_A);
+
+       cxl_p1_write(adapter, CXL_PSL_TLBIA, CXL_TLB_SLB_IQ_ALL);
+       while (cxl_p1_read(adapter, CXL_PSL_TLBIA) & CXL_TLB_SLB_P) {
+               if (time_after_eq(jiffies, timeout)) {
+                       dev_warn(&adapter->dev, "WARNING: CXL adapter wide TLBIA timed out!\n");
+                       return -EBUSY;
+               }
+               cpu_relax();
+       }
+
+       cxl_p1_write(adapter, CXL_PSL_SLBIA, CXL_TLB_SLB_IQ_ALL);
+       while (cxl_p1_read(adapter, CXL_PSL_SLBIA) & CXL_TLB_SLB_P) {
+               if (time_after_eq(jiffies, timeout)) {
+                       dev_warn(&adapter->dev, "WARNING: CXL adapter wide SLBIA timed out!\n");
+                       return -EBUSY;
+               }
+               cpu_relax();
+       }
+       return 0;
+}
+
+int cxl_afu_slbia(struct cxl_afu *afu)
+{
+       unsigned long timeout = jiffies + (HZ * CXL_TIMEOUT);
+
+       pr_devel("cxl_afu_slbia issuing SLBIA command\n");
+       cxl_p2n_write(afu, CXL_SLBIA_An, CXL_TLB_SLB_IQ_ALL);
+       while (cxl_p2n_read(afu, CXL_SLBIA_An) & CXL_TLB_SLB_P) {
+               if (time_after_eq(jiffies, timeout)) {
+                       dev_warn(&afu->dev, "WARNING: CXL AFU SLBIA timed out!\n");
+                       return -EBUSY;
+               }
+               cpu_relax();
+       }
+       return 0;
+}
+
+static int cxl_write_sstp(struct cxl_afu *afu, u64 sstp0, u64 sstp1)
+{
+       int rc;
+
+       /* 1. Disable SSTP by writing 0 to SSTP1[V] */
+       cxl_p2n_write(afu, CXL_SSTP1_An, 0);
+
+       /* 2. Invalidate all SLB entries */
+       if ((rc = cxl_afu_slbia(afu)))
+               return rc;
+
+       /* 3. Set SSTP0_An */
+       cxl_p2n_write(afu, CXL_SSTP0_An, sstp0);
+
+       /* 4. Set SSTP1_An */
+       cxl_p2n_write(afu, CXL_SSTP1_An, sstp1);
+
+       return 0;
+}
+
+/* Using per slice version may improve performance here. (ie. SLBIA_An) */
+static void slb_invalid(struct cxl_context *ctx)
+{
+       struct cxl *adapter = ctx->afu->adapter;
+       u64 slbia;
+
+       WARN_ON(!mutex_is_locked(&ctx->afu->spa_mutex));
+
+       cxl_p1_write(adapter, CXL_PSL_LBISEL,
+                       ((u64)be32_to_cpu(ctx->elem->common.pid) << 32) |
+                       be32_to_cpu(ctx->elem->lpid));
+       cxl_p1_write(adapter, CXL_PSL_SLBIA, CXL_TLB_SLB_IQ_LPIDPID);
+
+       while (1) {
+               slbia = cxl_p1_read(adapter, CXL_PSL_SLBIA);
+               if (!(slbia & CXL_TLB_SLB_P))
+                       break;
+               cpu_relax();
+       }
+}
+
+static int do_process_element_cmd(struct cxl_context *ctx,
+                                 u64 cmd, u64 pe_state)
+{
+       u64 state;
+
+       WARN_ON(!ctx->afu->enabled);
+
+       ctx->elem->software_state = cpu_to_be32(pe_state);
+       smp_wmb();
+       *(ctx->afu->sw_command_status) = cpu_to_be64(cmd | 0 | ctx->pe);
+       smp_mb();
+       cxl_p1n_write(ctx->afu, CXL_PSL_LLCMD_An, cmd | ctx->pe);
+       while (1) {
+               state = be64_to_cpup(ctx->afu->sw_command_status);
+               if (state == ~0ULL) {
+                       pr_err("cxl: Error adding process element to AFU\n");
+                       return -1;
+               }
+               if ((state & (CXL_SPA_SW_CMD_MASK | CXL_SPA_SW_STATE_MASK  | CXL_SPA_SW_LINK_MASK)) ==
+                   (cmd | (cmd >> 16) | ctx->pe))
+                       break;
+               /*
+                * The command won't finish in the PSL if there are
+                * outstanding DSIs.  Hence we need to yield here in
+                * case there are outstanding DSIs that we need to
+                * service.  Tuning possiblity: we could wait for a
+                * while before sched
+                */
+               schedule();
+
+       }
+       return 0;
+}
+
+static int add_process_element(struct cxl_context *ctx)
+{
+       int rc = 0;
+
+       mutex_lock(&ctx->afu->spa_mutex);
+       pr_devel("%s Adding pe: %i started\n", __func__, ctx->pe);
+       if (!(rc = do_process_element_cmd(ctx, CXL_SPA_SW_CMD_ADD, CXL_PE_SOFTWARE_STATE_V)))
+               ctx->pe_inserted = true;
+       pr_devel("%s Adding pe: %i finished\n", __func__, ctx->pe);
+       mutex_unlock(&ctx->afu->spa_mutex);
+       return rc;
+}
+
+static int terminate_process_element(struct cxl_context *ctx)
+{
+       int rc = 0;
+
+       /* fast path terminate if it's already invalid */
+       if (!(ctx->elem->software_state & cpu_to_be32(CXL_PE_SOFTWARE_STATE_V)))
+               return rc;
+
+       mutex_lock(&ctx->afu->spa_mutex);
+       pr_devel("%s Terminate pe: %i started\n", __func__, ctx->pe);
+       rc = do_process_element_cmd(ctx, CXL_SPA_SW_CMD_TERMINATE,
+                                   CXL_PE_SOFTWARE_STATE_V | CXL_PE_SOFTWARE_STATE_T);
+       ctx->elem->software_state = 0;  /* Remove Valid bit */
+       pr_devel("%s Terminate pe: %i finished\n", __func__, ctx->pe);
+       mutex_unlock(&ctx->afu->spa_mutex);
+       return rc;
+}
+
+static int remove_process_element(struct cxl_context *ctx)
+{
+       int rc = 0;
+
+       mutex_lock(&ctx->afu->spa_mutex);
+       pr_devel("%s Remove pe: %i started\n", __func__, ctx->pe);
+       if (!(rc = do_process_element_cmd(ctx, CXL_SPA_SW_CMD_REMOVE, 0)))
+               ctx->pe_inserted = false;
+       slb_invalid(ctx);
+       pr_devel("%s Remove pe: %i finished\n", __func__, ctx->pe);
+       mutex_unlock(&ctx->afu->spa_mutex);
+
+       return rc;
+}
+
+
+static void assign_psn_space(struct cxl_context *ctx)
+{
+       if (!ctx->afu->pp_size || ctx->master) {
+               ctx->psn_phys = ctx->afu->psn_phys;
+               ctx->psn_size = ctx->afu->adapter->ps_size;
+       } else {
+               ctx->psn_phys = ctx->afu->psn_phys +
+                       (ctx->afu->pp_offset + ctx->afu->pp_size * ctx->pe);
+               ctx->psn_size = ctx->afu->pp_size;
+       }
+}
+
+static int activate_afu_directed(struct cxl_afu *afu)
+{
+       int rc;
+
+       dev_info(&afu->dev, "Activating AFU directed mode\n");
+
+       if (alloc_spa(afu))
+               return -ENOMEM;
+
+       cxl_p1n_write(afu, CXL_PSL_SCNTL_An, CXL_PSL_SCNTL_An_PM_AFU);
+       cxl_p1n_write(afu, CXL_PSL_AMOR_An, 0xFFFFFFFFFFFFFFFFULL);
+       cxl_p1n_write(afu, CXL_PSL_ID_An, CXL_PSL_ID_An_F | CXL_PSL_ID_An_L);
+
+       afu->current_mode = CXL_MODE_DIRECTED;
+       afu->num_procs = afu->max_procs_virtualised;
+
+       if ((rc = cxl_chardev_m_afu_add(afu)))
+               return rc;
+
+       if ((rc = cxl_sysfs_afu_m_add(afu)))
+               goto err;
+
+       if ((rc = cxl_chardev_s_afu_add(afu)))
+               goto err1;
+
+       return 0;
+err1:
+       cxl_sysfs_afu_m_remove(afu);
+err:
+       cxl_chardev_afu_remove(afu);
+       return rc;
+}
+
+#ifdef CONFIG_CPU_LITTLE_ENDIAN
+#define set_endian(sr) ((sr) |= CXL_PSL_SR_An_LE)
+#else
+#define set_endian(sr) ((sr) &= ~(CXL_PSL_SR_An_LE))
+#endif
+
+static int attach_afu_directed(struct cxl_context *ctx, u64 wed, u64 amr)
+{
+       u64 sr;
+       int r, result;
+
+       assign_psn_space(ctx);
+
+       ctx->elem->ctxtime = 0; /* disable */
+       ctx->elem->lpid = cpu_to_be32(mfspr(SPRN_LPID));
+       ctx->elem->haurp = 0; /* disable */
+       ctx->elem->sdr = cpu_to_be64(mfspr(SPRN_SDR1));
+
+       sr = CXL_PSL_SR_An_SC;
+       if (ctx->master)
+               sr |= CXL_PSL_SR_An_MP;
+       if (mfspr(SPRN_LPCR) & LPCR_TC)
+               sr |= CXL_PSL_SR_An_TC;
+       /* HV=0, PR=1, R=1 for userspace
+        * For kernel contexts: this would need to change
+        */
+       sr |= CXL_PSL_SR_An_PR | CXL_PSL_SR_An_R;
+       set_endian(sr);
+       sr &= ~(CXL_PSL_SR_An_HV);
+       if (!test_tsk_thread_flag(current, TIF_32BIT))
+               sr |= CXL_PSL_SR_An_SF;
+       ctx->elem->common.pid = cpu_to_be32(current->pid);
+       ctx->elem->common.tid = 0;
+       ctx->elem->sr = cpu_to_be64(sr);
+
+       ctx->elem->common.csrp = 0; /* disable */
+       ctx->elem->common.aurp0 = 0; /* disable */
+       ctx->elem->common.aurp1 = 0; /* disable */
+
+       cxl_prefault(ctx, wed);
+
+       ctx->elem->common.sstp0 = cpu_to_be64(ctx->sstp0);
+       ctx->elem->common.sstp1 = cpu_to_be64(ctx->sstp1);
+
+       for (r = 0; r < CXL_IRQ_RANGES; r++) {
+               ctx->elem->ivte_offsets[r] = cpu_to_be16(ctx->irqs.offset[r]);
+               ctx->elem->ivte_ranges[r] = cpu_to_be16(ctx->irqs.range[r]);
+       }
+
+       ctx->elem->common.amr = cpu_to_be64(amr);
+       ctx->elem->common.wed = cpu_to_be64(wed);
+
+       /* first guy needs to enable */
+       if ((result = afu_check_and_enable(ctx->afu)))
+               return result;
+
+       add_process_element(ctx);
+
+       return 0;
+}
+
+static int deactivate_afu_directed(struct cxl_afu *afu)
+{
+       dev_info(&afu->dev, "Deactivating AFU directed mode\n");
+
+       afu->current_mode = 0;
+       afu->num_procs = 0;
+
+       cxl_sysfs_afu_m_remove(afu);
+       cxl_chardev_afu_remove(afu);
+
+       cxl_afu_reset(afu);
+       cxl_afu_disable(afu);
+       cxl_psl_purge(afu);
+
+       release_spa(afu);
+
+       return 0;
+}
+
+static int activate_dedicated_process(struct cxl_afu *afu)
+{
+       dev_info(&afu->dev, "Activating dedicated process mode\n");
+
+       cxl_p1n_write(afu, CXL_PSL_SCNTL_An, CXL_PSL_SCNTL_An_PM_Process);
+
+       cxl_p1n_write(afu, CXL_PSL_CtxTime_An, 0); /* disable */
+       cxl_p1n_write(afu, CXL_PSL_SPAP_An, 0);    /* disable */
+       cxl_p1n_write(afu, CXL_PSL_AMOR_An, 0xFFFFFFFFFFFFFFFFULL);
+       cxl_p1n_write(afu, CXL_PSL_LPID_An, mfspr(SPRN_LPID));
+       cxl_p1n_write(afu, CXL_HAURP_An, 0);       /* disable */
+       cxl_p1n_write(afu, CXL_PSL_SDR_An, mfspr(SPRN_SDR1));
+
+       cxl_p2n_write(afu, CXL_CSRP_An, 0);        /* disable */
+       cxl_p2n_write(afu, CXL_AURP0_An, 0);       /* disable */
+       cxl_p2n_write(afu, CXL_AURP1_An, 0);       /* disable */
+
+       afu->current_mode = CXL_MODE_DEDICATED;
+       afu->num_procs = 1;
+
+       return cxl_chardev_d_afu_add(afu);
+}
+
+static int attach_dedicated(struct cxl_context *ctx, u64 wed, u64 amr)
+{
+       struct cxl_afu *afu = ctx->afu;
+       u64 sr;
+       int rc;
+
+       sr = CXL_PSL_SR_An_SC;
+       set_endian(sr);
+       if (ctx->master)
+               sr |= CXL_PSL_SR_An_MP;
+       if (mfspr(SPRN_LPCR) & LPCR_TC)
+               sr |= CXL_PSL_SR_An_TC;
+       sr |= CXL_PSL_SR_An_PR | CXL_PSL_SR_An_R;
+       if (!test_tsk_thread_flag(current, TIF_32BIT))
+               sr |= CXL_PSL_SR_An_SF;
+       cxl_p2n_write(afu, CXL_PSL_PID_TID_An, (u64)current->pid << 32);
+       cxl_p1n_write(afu, CXL_PSL_SR_An, sr);
+
+       if ((rc = cxl_write_sstp(afu, ctx->sstp0, ctx->sstp1)))
+               return rc;
+
+       cxl_prefault(ctx, wed);
+
+       cxl_p1n_write(afu, CXL_PSL_IVTE_Offset_An,
+                      (((u64)ctx->irqs.offset[0] & 0xffff) << 48) |
+                      (((u64)ctx->irqs.offset[1] & 0xffff) << 32) |
+                      (((u64)ctx->irqs.offset[2] & 0xffff) << 16) |
+                       ((u64)ctx->irqs.offset[3] & 0xffff));
+       cxl_p1n_write(afu, CXL_PSL_IVTE_Limit_An, (u64)
+                      (((u64)ctx->irqs.range[0] & 0xffff) << 48) |
+                      (((u64)ctx->irqs.range[1] & 0xffff) << 32) |
+                      (((u64)ctx->irqs.range[2] & 0xffff) << 16) |
+                       ((u64)ctx->irqs.range[3] & 0xffff));
+
+       cxl_p2n_write(afu, CXL_PSL_AMR_An, amr);
+
+       /* master only context for dedicated */
+       assign_psn_space(ctx);
+
+       if ((rc = cxl_afu_reset(afu)))
+               return rc;
+
+       cxl_p2n_write(afu, CXL_PSL_WED_An, wed);
+
+       return afu_enable(afu);
+}
+
+static int deactivate_dedicated_process(struct cxl_afu *afu)
+{
+       dev_info(&afu->dev, "Deactivating dedicated process mode\n");
+
+       afu->current_mode = 0;
+       afu->num_procs = 0;
+
+       cxl_chardev_afu_remove(afu);
+
+       return 0;
+}
+
+int _cxl_afu_deactivate_mode(struct cxl_afu *afu, int mode)
+{
+       if (mode == CXL_MODE_DIRECTED)
+               return deactivate_afu_directed(afu);
+       if (mode == CXL_MODE_DEDICATED)
+               return deactivate_dedicated_process(afu);
+       return 0;
+}
+
+int cxl_afu_deactivate_mode(struct cxl_afu *afu)
+{
+       return _cxl_afu_deactivate_mode(afu, afu->current_mode);
+}
+
+int cxl_afu_activate_mode(struct cxl_afu *afu, int mode)
+{
+       if (!mode)
+               return 0;
+       if (!(mode & afu->modes_supported))
+               return -EINVAL;
+
+       if (mode == CXL_MODE_DIRECTED)
+               return activate_afu_directed(afu);
+       if (mode == CXL_MODE_DEDICATED)
+               return activate_dedicated_process(afu);
+
+       return -EINVAL;
+}
+
+int cxl_attach_process(struct cxl_context *ctx, bool kernel, u64 wed, u64 amr)
+{
+       ctx->kernel = kernel;
+       if (ctx->afu->current_mode == CXL_MODE_DIRECTED)
+               return attach_afu_directed(ctx, wed, amr);
+
+       if (ctx->afu->current_mode == CXL_MODE_DEDICATED)
+               return attach_dedicated(ctx, wed, amr);
+
+       return -EINVAL;
+}
+
+static inline int detach_process_native_dedicated(struct cxl_context *ctx)
+{
+       cxl_afu_reset(ctx->afu);
+       cxl_afu_disable(ctx->afu);
+       cxl_psl_purge(ctx->afu);
+       return 0;
+}
+
+/*
+ * TODO: handle case when this is called inside a rcu_read_lock() which may
+ * happen when we unbind the driver (ie. cxl_context_detach_all()) .  Terminate
+ * & remove use a mutex lock and schedule which will not good with lock held.
+ * May need to write do_process_element_cmd() that handles outstanding page
+ * faults synchronously.
+ */
+static inline int detach_process_native_afu_directed(struct cxl_context *ctx)
+{
+       if (!ctx->pe_inserted)
+               return 0;
+       if (terminate_process_element(ctx))
+               return -1;
+       if (remove_process_element(ctx))
+               return -1;
+
+       return 0;
+}
+
+int cxl_detach_process(struct cxl_context *ctx)
+{
+       if (ctx->afu->current_mode == CXL_MODE_DEDICATED)
+               return detach_process_native_dedicated(ctx);
+
+       return detach_process_native_afu_directed(ctx);
+}
+
+int cxl_get_irq(struct cxl_context *ctx, struct cxl_irq_info *info)
+{
+       u64 pidtid;
+
+       info->dsisr = cxl_p2n_read(ctx->afu, CXL_PSL_DSISR_An);
+       info->dar = cxl_p2n_read(ctx->afu, CXL_PSL_DAR_An);
+       info->dsr = cxl_p2n_read(ctx->afu, CXL_PSL_DSR_An);
+       pidtid = cxl_p2n_read(ctx->afu, CXL_PSL_PID_TID_An);
+       info->pid = pidtid >> 32;
+       info->tid = pidtid & 0xffffffff;
+       info->afu_err = cxl_p2n_read(ctx->afu, CXL_AFU_ERR_An);
+       info->errstat = cxl_p2n_read(ctx->afu, CXL_PSL_ErrStat_An);
+
+       return 0;
+}
+
+static void recover_psl_err(struct cxl_afu *afu, u64 errstat)
+{
+       u64 dsisr;
+
+       pr_devel("RECOVERING FROM PSL ERROR... (0x%.16llx)\n", errstat);
+
+       /* Clear PSL_DSISR[PE] */
+       dsisr = cxl_p2n_read(afu, CXL_PSL_DSISR_An);
+       cxl_p2n_write(afu, CXL_PSL_DSISR_An, dsisr & ~CXL_PSL_DSISR_An_PE);
+
+       /* Write 1s to clear error status bits */
+       cxl_p2n_write(afu, CXL_PSL_ErrStat_An, errstat);
+}
+
+int cxl_ack_irq(struct cxl_context *ctx, u64 tfc, u64 psl_reset_mask)
+{
+       if (tfc)
+               cxl_p2n_write(ctx->afu, CXL_PSL_TFC_An, tfc);
+       if (psl_reset_mask)
+               recover_psl_err(ctx->afu, psl_reset_mask);
+
+       return 0;
+}
+
+int cxl_check_error(struct cxl_afu *afu)
+{
+       return (cxl_p1n_read(afu, CXL_PSL_SCNTL_An) == ~0ULL);
+}
diff --git a/drivers/misc/cxl/pci.c b/drivers/misc/cxl/pci.c
new file mode 100644 (file)
index 0000000..10c98ab
--- /dev/null
@@ -0,0 +1,1000 @@
+/*
+ * Copyright 2014 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.
+ */
+
+#include <linux/pci_regs.h>
+#include <linux/pci_ids.h>
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/sort.h>
+#include <linux/pci.h>
+#include <linux/of.h>
+#include <linux/delay.h>
+#include <asm/opal.h>
+#include <asm/msi_bitmap.h>
+#include <asm/pci-bridge.h> /* for struct pci_controller */
+#include <asm/pnv-pci.h>
+
+#include "cxl.h"
+
+
+#define CXL_PCI_VSEC_ID        0x1280
+#define CXL_VSEC_MIN_SIZE 0x80
+
+#define CXL_READ_VSEC_LENGTH(dev, vsec, dest)                  \
+       {                                                       \
+               pci_read_config_word(dev, vsec + 0x6, dest);    \
+               *dest >>= 4;                                    \
+       }
+#define CXL_READ_VSEC_NAFUS(dev, vsec, dest) \
+       pci_read_config_byte(dev, vsec + 0x8, dest)
+
+#define CXL_READ_VSEC_STATUS(dev, vsec, dest) \
+       pci_read_config_byte(dev, vsec + 0x9, dest)
+#define CXL_STATUS_SECOND_PORT  0x80
+#define CXL_STATUS_MSI_X_FULL   0x40
+#define CXL_STATUS_MSI_X_SINGLE 0x20
+#define CXL_STATUS_FLASH_RW     0x08
+#define CXL_STATUS_FLASH_RO     0x04
+#define CXL_STATUS_LOADABLE_AFU 0x02
+#define CXL_STATUS_LOADABLE_PSL 0x01
+/* If we see these features we won't try to use the card */
+#define CXL_UNSUPPORTED_FEATURES \
+       (CXL_STATUS_MSI_X_FULL | CXL_STATUS_MSI_X_SINGLE)
+
+#define CXL_READ_VSEC_MODE_CONTROL(dev, vsec, dest) \
+       pci_read_config_byte(dev, vsec + 0xa, dest)
+#define CXL_WRITE_VSEC_MODE_CONTROL(dev, vsec, val) \
+       pci_write_config_byte(dev, vsec + 0xa, val)
+#define CXL_VSEC_PROTOCOL_MASK   0xe0
+#define CXL_VSEC_PROTOCOL_1024TB 0x80
+#define CXL_VSEC_PROTOCOL_512TB  0x40
+#define CXL_VSEC_PROTOCOL_256TB  0x20 /* Power 8 uses this */
+#define CXL_VSEC_PROTOCOL_ENABLE 0x01
+
+#define CXL_READ_VSEC_PSL_REVISION(dev, vsec, dest) \
+       pci_read_config_word(dev, vsec + 0xc, dest)
+#define CXL_READ_VSEC_CAIA_MINOR(dev, vsec, dest) \
+       pci_read_config_byte(dev, vsec + 0xe, dest)
+#define CXL_READ_VSEC_CAIA_MAJOR(dev, vsec, dest) \
+       pci_read_config_byte(dev, vsec + 0xf, dest)
+#define CXL_READ_VSEC_BASE_IMAGE(dev, vsec, dest) \
+       pci_read_config_word(dev, vsec + 0x10, dest)
+
+#define CXL_READ_VSEC_IMAGE_STATE(dev, vsec, dest) \
+       pci_read_config_byte(dev, vsec + 0x13, dest)
+#define CXL_WRITE_VSEC_IMAGE_STATE(dev, vsec, val) \
+       pci_write_config_byte(dev, vsec + 0x13, val)
+#define CXL_VSEC_USER_IMAGE_LOADED 0x80 /* RO */
+#define CXL_VSEC_PERST_LOADS_IMAGE 0x20 /* RW */
+#define CXL_VSEC_PERST_SELECT_USER 0x10 /* RW */
+
+#define CXL_READ_VSEC_AFU_DESC_OFF(dev, vsec, dest) \
+       pci_read_config_dword(dev, vsec + 0x20, dest)
+#define CXL_READ_VSEC_AFU_DESC_SIZE(dev, vsec, dest) \
+       pci_read_config_dword(dev, vsec + 0x24, dest)
+#define CXL_READ_VSEC_PS_OFF(dev, vsec, dest) \
+       pci_read_config_dword(dev, vsec + 0x28, dest)
+#define CXL_READ_VSEC_PS_SIZE(dev, vsec, dest) \
+       pci_read_config_dword(dev, vsec + 0x2c, dest)
+
+
+/* This works a little different than the p1/p2 register accesses to make it
+ * easier to pull out individual fields */
+#define AFUD_READ(afu, off)            in_be64(afu->afu_desc_mmio + off)
+#define EXTRACT_PPC_BIT(val, bit)      (!!(val & PPC_BIT(bit)))
+#define EXTRACT_PPC_BITS(val, bs, be)  ((val & PPC_BITMASK(bs, be)) >> PPC_BITLSHIFT(be))
+
+#define AFUD_READ_INFO(afu)            AFUD_READ(afu, 0x0)
+#define   AFUD_NUM_INTS_PER_PROC(val)  EXTRACT_PPC_BITS(val,  0, 15)
+#define   AFUD_NUM_PROCS(val)          EXTRACT_PPC_BITS(val, 16, 31)
+#define   AFUD_NUM_CRS(val)            EXTRACT_PPC_BITS(val, 32, 47)
+#define   AFUD_MULTIMODE(val)          EXTRACT_PPC_BIT(val, 48)
+#define   AFUD_PUSH_BLOCK_TRANSFER(val)        EXTRACT_PPC_BIT(val, 55)
+#define   AFUD_DEDICATED_PROCESS(val)  EXTRACT_PPC_BIT(val, 59)
+#define   AFUD_AFU_DIRECTED(val)       EXTRACT_PPC_BIT(val, 61)
+#define   AFUD_TIME_SLICED(val)                EXTRACT_PPC_BIT(val, 63)
+#define AFUD_READ_CR(afu)              AFUD_READ(afu, 0x20)
+#define   AFUD_CR_LEN(val)             EXTRACT_PPC_BITS(val, 8, 63)
+#define AFUD_READ_CR_OFF(afu)          AFUD_READ(afu, 0x28)
+#define AFUD_READ_PPPSA(afu)           AFUD_READ(afu, 0x30)
+#define   AFUD_PPPSA_PP(val)           EXTRACT_PPC_BIT(val, 6)
+#define   AFUD_PPPSA_PSA(val)          EXTRACT_PPC_BIT(val, 7)
+#define   AFUD_PPPSA_LEN(val)          EXTRACT_PPC_BITS(val, 8, 63)
+#define AFUD_READ_PPPSA_OFF(afu)       AFUD_READ(afu, 0x38)
+#define AFUD_READ_EB(afu)              AFUD_READ(afu, 0x40)
+#define   AFUD_EB_LEN(val)             EXTRACT_PPC_BITS(val, 8, 63)
+#define AFUD_READ_EB_OFF(afu)          AFUD_READ(afu, 0x48)
+
+static DEFINE_PCI_DEVICE_TABLE(cxl_pci_tbl) = {
+       { PCI_DEVICE(PCI_VENDOR_ID_IBM, 0x0477), },
+       { PCI_DEVICE(PCI_VENDOR_ID_IBM, 0x044b), },
+       { PCI_DEVICE(PCI_VENDOR_ID_IBM, 0x04cf), },
+       { PCI_DEVICE_CLASS(0x120000, ~0), },
+
+       { }
+};
+MODULE_DEVICE_TABLE(pci, cxl_pci_tbl);
+
+
+/*
+ * Mostly using these wrappers to avoid confusion:
+ * priv 1 is BAR2, while priv 2 is BAR0
+ */
+static inline resource_size_t p1_base(struct pci_dev *dev)
+{
+       return pci_resource_start(dev, 2);
+}
+
+static inline resource_size_t p1_size(struct pci_dev *dev)
+{
+       return pci_resource_len(dev, 2);
+}
+
+static inline resource_size_t p2_base(struct pci_dev *dev)
+{
+       return pci_resource_start(dev, 0);
+}
+
+static inline resource_size_t p2_size(struct pci_dev *dev)
+{
+       return pci_resource_len(dev, 0);
+}
+
+static int find_cxl_vsec(struct pci_dev *dev)
+{
+       int vsec = 0;
+       u16 val;
+
+       while ((vsec = pci_find_next_ext_capability(dev, vsec, PCI_EXT_CAP_ID_VNDR))) {
+               pci_read_config_word(dev, vsec + 0x4, &val);
+               if (val == CXL_PCI_VSEC_ID)
+                       return vsec;
+       }
+       return 0;
+
+}
+
+static void dump_cxl_config_space(struct pci_dev *dev)
+{
+       int vsec;
+       u32 val;
+
+       dev_info(&dev->dev, "dump_cxl_config_space\n");
+
+       pci_read_config_dword(dev, PCI_BASE_ADDRESS_0, &val);
+       dev_info(&dev->dev, "BAR0: %#.8x\n", val);
+       pci_read_config_dword(dev, PCI_BASE_ADDRESS_1, &val);
+       dev_info(&dev->dev, "BAR1: %#.8x\n", val);
+       pci_read_config_dword(dev, PCI_BASE_ADDRESS_2, &val);
+       dev_info(&dev->dev, "BAR2: %#.8x\n", val);
+       pci_read_config_dword(dev, PCI_BASE_ADDRESS_3, &val);
+       dev_info(&dev->dev, "BAR3: %#.8x\n", val);
+       pci_read_config_dword(dev, PCI_BASE_ADDRESS_4, &val);
+       dev_info(&dev->dev, "BAR4: %#.8x\n", val);
+       pci_read_config_dword(dev, PCI_BASE_ADDRESS_5, &val);
+       dev_info(&dev->dev, "BAR5: %#.8x\n", val);
+
+       dev_info(&dev->dev, "p1 regs: %#llx, len: %#llx\n",
+               p1_base(dev), p1_size(dev));
+       dev_info(&dev->dev, "p2 regs: %#llx, len: %#llx\n",
+               p1_base(dev), p2_size(dev));
+       dev_info(&dev->dev, "BAR 4/5: %#llx, len: %#llx\n",
+               pci_resource_start(dev, 4), pci_resource_len(dev, 4));
+
+       if (!(vsec = find_cxl_vsec(dev)))
+               return;
+
+#define show_reg(name, what) \
+       dev_info(&dev->dev, "cxl vsec: %30s: %#x\n", name, what)
+
+       pci_read_config_dword(dev, vsec + 0x0, &val);
+       show_reg("Cap ID", (val >> 0) & 0xffff);
+       show_reg("Cap Ver", (val >> 16) & 0xf);
+       show_reg("Next Cap Ptr", (val >> 20) & 0xfff);
+       pci_read_config_dword(dev, vsec + 0x4, &val);
+       show_reg("VSEC ID", (val >> 0) & 0xffff);
+       show_reg("VSEC Rev", (val >> 16) & 0xf);
+       show_reg("VSEC Length", (val >> 20) & 0xfff);
+       pci_read_config_dword(dev, vsec + 0x8, &val);
+       show_reg("Num AFUs", (val >> 0) & 0xff);
+       show_reg("Status", (val >> 8) & 0xff);
+       show_reg("Mode Control", (val >> 16) & 0xff);
+       show_reg("Reserved", (val >> 24) & 0xff);
+       pci_read_config_dword(dev, vsec + 0xc, &val);
+       show_reg("PSL Rev", (val >> 0) & 0xffff);
+       show_reg("CAIA Ver", (val >> 16) & 0xffff);
+       pci_read_config_dword(dev, vsec + 0x10, &val);
+       show_reg("Base Image Rev", (val >> 0) & 0xffff);
+       show_reg("Reserved", (val >> 16) & 0x0fff);
+       show_reg("Image Control", (val >> 28) & 0x3);
+       show_reg("Reserved", (val >> 30) & 0x1);
+       show_reg("Image Loaded", (val >> 31) & 0x1);
+
+       pci_read_config_dword(dev, vsec + 0x14, &val);
+       show_reg("Reserved", val);
+       pci_read_config_dword(dev, vsec + 0x18, &val);
+       show_reg("Reserved", val);
+       pci_read_config_dword(dev, vsec + 0x1c, &val);
+       show_reg("Reserved", val);
+
+       pci_read_config_dword(dev, vsec + 0x20, &val);
+       show_reg("AFU Descriptor Offset", val);
+       pci_read_config_dword(dev, vsec + 0x24, &val);
+       show_reg("AFU Descriptor Size", val);
+       pci_read_config_dword(dev, vsec + 0x28, &val);
+       show_reg("Problem State Offset", val);
+       pci_read_config_dword(dev, vsec + 0x2c, &val);
+       show_reg("Problem State Size", val);
+
+       pci_read_config_dword(dev, vsec + 0x30, &val);
+       show_reg("Reserved", val);
+       pci_read_config_dword(dev, vsec + 0x34, &val);
+       show_reg("Reserved", val);
+       pci_read_config_dword(dev, vsec + 0x38, &val);
+       show_reg("Reserved", val);
+       pci_read_config_dword(dev, vsec + 0x3c, &val);
+       show_reg("Reserved", val);
+
+       pci_read_config_dword(dev, vsec + 0x40, &val);
+       show_reg("PSL Programming Port", val);
+       pci_read_config_dword(dev, vsec + 0x44, &val);
+       show_reg("PSL Programming Control", val);
+
+       pci_read_config_dword(dev, vsec + 0x48, &val);
+       show_reg("Reserved", val);
+       pci_read_config_dword(dev, vsec + 0x4c, &val);
+       show_reg("Reserved", val);
+
+       pci_read_config_dword(dev, vsec + 0x50, &val);
+       show_reg("Flash Address Register", val);
+       pci_read_config_dword(dev, vsec + 0x54, &val);
+       show_reg("Flash Size Register", val);
+       pci_read_config_dword(dev, vsec + 0x58, &val);
+       show_reg("Flash Status/Control Register", val);
+       pci_read_config_dword(dev, vsec + 0x58, &val);
+       show_reg("Flash Data Port", val);
+
+#undef show_reg
+}
+
+static void dump_afu_descriptor(struct cxl_afu *afu)
+{
+       u64 val;
+
+#define show_reg(name, what) \
+       dev_info(&afu->dev, "afu desc: %30s: %#llx\n", name, what)
+
+       val = AFUD_READ_INFO(afu);
+       show_reg("num_ints_per_process", AFUD_NUM_INTS_PER_PROC(val));
+       show_reg("num_of_processes", AFUD_NUM_PROCS(val));
+       show_reg("num_of_afu_CRs", AFUD_NUM_CRS(val));
+       show_reg("req_prog_mode", val & 0xffffULL);
+
+       val = AFUD_READ(afu, 0x8);
+       show_reg("Reserved", val);
+       val = AFUD_READ(afu, 0x10);
+       show_reg("Reserved", val);
+       val = AFUD_READ(afu, 0x18);
+       show_reg("Reserved", val);
+
+       val = AFUD_READ_CR(afu);
+       show_reg("Reserved", (val >> (63-7)) & 0xff);
+       show_reg("AFU_CR_len", AFUD_CR_LEN(val));
+
+       val = AFUD_READ_CR_OFF(afu);
+       show_reg("AFU_CR_offset", val);
+
+       val = AFUD_READ_PPPSA(afu);
+       show_reg("PerProcessPSA_control", (val >> (63-7)) & 0xff);
+       show_reg("PerProcessPSA Length", AFUD_PPPSA_LEN(val));
+
+       val = AFUD_READ_PPPSA_OFF(afu);
+       show_reg("PerProcessPSA_offset", val);
+
+       val = AFUD_READ_EB(afu);
+       show_reg("Reserved", (val >> (63-7)) & 0xff);
+       show_reg("AFU_EB_len", AFUD_EB_LEN(val));
+
+       val = AFUD_READ_EB_OFF(afu);
+       show_reg("AFU_EB_offset", val);
+
+#undef show_reg
+}
+
+static int init_implementation_adapter_regs(struct cxl *adapter, struct pci_dev *dev)
+{
+       struct device_node *np;
+       const __be32 *prop;
+       u64 psl_dsnctl;
+       u64 chipid;
+
+       if (!(np = pnv_pci_to_phb_node(dev)))
+               return -ENODEV;
+
+       while (np && !(prop = of_get_property(np, "ibm,chip-id", NULL)))
+               np = of_get_next_parent(np);
+       if (!np)
+               return -ENODEV;
+       chipid = be32_to_cpup(prop);
+       of_node_put(np);
+
+       /* Tell PSL where to route data to */
+       psl_dsnctl = 0x02E8900002000000ULL | (chipid << (63-5));
+       cxl_p1_write(adapter, CXL_PSL_DSNDCTL, psl_dsnctl);
+       cxl_p1_write(adapter, CXL_PSL_RESLCKTO, 0x20000000200ULL);
+       /* snoop write mask */
+       cxl_p1_write(adapter, CXL_PSL_SNWRALLOC, 0x00000000FFFFFFFFULL);
+       /* set fir_accum */
+       cxl_p1_write(adapter, CXL_PSL_FIR_CNTL, 0x0800000000000000ULL);
+       /* for debugging with trace arrays */
+       cxl_p1_write(adapter, CXL_PSL_TRACE, 0x0000FF7C00000000ULL);
+
+       return 0;
+}
+
+static int init_implementation_afu_regs(struct cxl_afu *afu)
+{
+       /* read/write masks for this slice */
+       cxl_p1n_write(afu, CXL_PSL_APCALLOC_A, 0xFFFFFFFEFEFEFEFEULL);
+       /* APC read/write masks for this slice */
+       cxl_p1n_write(afu, CXL_PSL_COALLOC_A, 0xFF000000FEFEFEFEULL);
+       /* for debugging with trace arrays */
+       cxl_p1n_write(afu, CXL_PSL_SLICE_TRACE, 0x0000FFFF00000000ULL);
+       cxl_p1n_write(afu, CXL_PSL_RXCTL_A, 0xF000000000000000ULL);
+
+       return 0;
+}
+
+int cxl_setup_irq(struct cxl *adapter, unsigned int hwirq,
+                        unsigned int virq)
+{
+       struct pci_dev *dev = to_pci_dev(adapter->dev.parent);
+
+       return pnv_cxl_ioda_msi_setup(dev, hwirq, virq);
+}
+
+int cxl_alloc_one_irq(struct cxl *adapter)
+{
+       struct pci_dev *dev = to_pci_dev(adapter->dev.parent);
+
+       return pnv_cxl_alloc_hwirqs(dev, 1);
+}
+
+void cxl_release_one_irq(struct cxl *adapter, int hwirq)
+{
+       struct pci_dev *dev = to_pci_dev(adapter->dev.parent);
+
+       return pnv_cxl_release_hwirqs(dev, hwirq, 1);
+}
+
+int cxl_alloc_irq_ranges(struct cxl_irq_ranges *irqs, struct cxl *adapter, unsigned int num)
+{
+       struct pci_dev *dev = to_pci_dev(adapter->dev.parent);
+
+       return pnv_cxl_alloc_hwirq_ranges(irqs, dev, num);
+}
+
+void cxl_release_irq_ranges(struct cxl_irq_ranges *irqs, struct cxl *adapter)
+{
+       struct pci_dev *dev = to_pci_dev(adapter->dev.parent);
+
+       pnv_cxl_release_hwirq_ranges(irqs, dev);
+}
+
+static int setup_cxl_bars(struct pci_dev *dev)
+{
+       /* Safety check in case we get backported to < 3.17 without M64 */
+       if ((p1_base(dev) < 0x100000000ULL) ||
+           (p2_base(dev) < 0x100000000ULL)) {
+               dev_err(&dev->dev, "ABORTING: M32 BAR assignment incompatible with CXL\n");
+               return -ENODEV;
+       }
+
+       /*
+        * BAR 4/5 has a special meaning for CXL and must be programmed with a
+        * special value corresponding to the CXL protocol address range.
+        * For POWER 8 that means bits 48:49 must be set to 10
+        */
+       pci_write_config_dword(dev, PCI_BASE_ADDRESS_4, 0x00000000);
+       pci_write_config_dword(dev, PCI_BASE_ADDRESS_5, 0x00020000);
+
+       return 0;
+}
+
+/* pciex node: ibm,opal-m64-window = <0x3d058 0x0 0x3d058 0x0 0x8 0x0>; */
+static int switch_card_to_cxl(struct pci_dev *dev)
+{
+       int vsec;
+       u8 val;
+       int rc;
+
+       dev_info(&dev->dev, "switch card to CXL\n");
+
+       if (!(vsec = find_cxl_vsec(dev))) {
+               dev_err(&dev->dev, "ABORTING: CXL VSEC not found!\n");
+               return -ENODEV;
+       }
+
+       if ((rc = CXL_READ_VSEC_MODE_CONTROL(dev, vsec, &val))) {
+               dev_err(&dev->dev, "failed to read current mode control: %i", rc);
+               return rc;
+       }
+       val &= ~CXL_VSEC_PROTOCOL_MASK;
+       val |= CXL_VSEC_PROTOCOL_256TB | CXL_VSEC_PROTOCOL_ENABLE;
+       if ((rc = CXL_WRITE_VSEC_MODE_CONTROL(dev, vsec, val))) {
+               dev_err(&dev->dev, "failed to enable CXL protocol: %i", rc);
+               return rc;
+       }
+       /*
+        * The CAIA spec (v0.12 11.6 Bi-modal Device Support) states
+        * we must wait 100ms after this mode switch before touching
+        * PCIe config space.
+        */
+       msleep(100);
+
+       return 0;
+}
+
+static int cxl_map_slice_regs(struct cxl_afu *afu, struct cxl *adapter, struct pci_dev *dev)
+{
+       u64 p1n_base, p2n_base, afu_desc;
+       const u64 p1n_size = 0x100;
+       const u64 p2n_size = 0x1000;
+
+       p1n_base = p1_base(dev) + 0x10000 + (afu->slice * p1n_size);
+       p2n_base = p2_base(dev) + (afu->slice * p2n_size);
+       afu->psn_phys = p2_base(dev) + (adapter->ps_off + (afu->slice * adapter->ps_size));
+       afu_desc = p2_base(dev) + adapter->afu_desc_off + (afu->slice * adapter->afu_desc_size);
+
+       if (!(afu->p1n_mmio = ioremap(p1n_base, p1n_size)))
+               goto err;
+       if (!(afu->p2n_mmio = ioremap(p2n_base, p2n_size)))
+               goto err1;
+       if (afu_desc) {
+               if (!(afu->afu_desc_mmio = ioremap(afu_desc, adapter->afu_desc_size)))
+                       goto err2;
+       }
+
+       return 0;
+err2:
+       iounmap(afu->p2n_mmio);
+err1:
+       iounmap(afu->p1n_mmio);
+err:
+       dev_err(&afu->dev, "Error mapping AFU MMIO regions\n");
+       return -ENOMEM;
+}
+
+static void cxl_unmap_slice_regs(struct cxl_afu *afu)
+{
+       if (afu->p1n_mmio)
+               iounmap(afu->p2n_mmio);
+       if (afu->p1n_mmio)
+               iounmap(afu->p1n_mmio);
+}
+
+static void cxl_release_afu(struct device *dev)
+{
+       struct cxl_afu *afu = to_cxl_afu(dev);
+
+       pr_devel("cxl_release_afu\n");
+
+       kfree(afu);
+}
+
+static struct cxl_afu *cxl_alloc_afu(struct cxl *adapter, int slice)
+{
+       struct cxl_afu *afu;
+
+       if (!(afu = kzalloc(sizeof(struct cxl_afu), GFP_KERNEL)))
+               return NULL;
+
+       afu->adapter = adapter;
+       afu->dev.parent = &adapter->dev;
+       afu->dev.release = cxl_release_afu;
+       afu->slice = slice;
+       idr_init(&afu->contexts_idr);
+       spin_lock_init(&afu->contexts_lock);
+       spin_lock_init(&afu->afu_cntl_lock);
+       mutex_init(&afu->spa_mutex);
+
+       afu->prefault_mode = CXL_PREFAULT_NONE;
+       afu->irqs_max = afu->adapter->user_irqs;
+
+       return afu;
+}
+
+/* Expects AFU struct to have recently been zeroed out */
+static int cxl_read_afu_descriptor(struct cxl_afu *afu)
+{
+       u64 val;
+
+       val = AFUD_READ_INFO(afu);
+       afu->pp_irqs = AFUD_NUM_INTS_PER_PROC(val);
+       afu->max_procs_virtualised = AFUD_NUM_PROCS(val);
+
+       if (AFUD_AFU_DIRECTED(val))
+               afu->modes_supported |= CXL_MODE_DIRECTED;
+       if (AFUD_DEDICATED_PROCESS(val))
+               afu->modes_supported |= CXL_MODE_DEDICATED;
+       if (AFUD_TIME_SLICED(val))
+               afu->modes_supported |= CXL_MODE_TIME_SLICED;
+
+       val = AFUD_READ_PPPSA(afu);
+       afu->pp_size = AFUD_PPPSA_LEN(val) * 4096;
+       afu->psa = AFUD_PPPSA_PSA(val);
+       if ((afu->pp_psa = AFUD_PPPSA_PP(val)))
+               afu->pp_offset = AFUD_READ_PPPSA_OFF(afu);
+
+       return 0;
+}
+
+static int cxl_afu_descriptor_looks_ok(struct cxl_afu *afu)
+{
+       if (afu->psa && afu->adapter->ps_size <
+                       (afu->pp_offset + afu->pp_size*afu->max_procs_virtualised)) {
+               dev_err(&afu->dev, "per-process PSA can't fit inside the PSA!\n");
+               return -ENODEV;
+       }
+
+       if (afu->pp_psa && (afu->pp_size < PAGE_SIZE))
+               dev_warn(&afu->dev, "AFU uses < PAGE_SIZE per-process PSA!");
+
+       return 0;
+}
+
+static int sanitise_afu_regs(struct cxl_afu *afu)
+{
+       u64 reg;
+
+       /*
+        * Clear out any regs that contain either an IVTE or address or may be
+        * waiting on an acknowledgement to try to be a bit safer as we bring
+        * it online
+        */
+       reg = cxl_p2n_read(afu, CXL_AFU_Cntl_An);
+       if ((reg & CXL_AFU_Cntl_An_ES_MASK) != CXL_AFU_Cntl_An_ES_Disabled) {
+               dev_warn(&afu->dev, "WARNING: AFU was not disabled: %#.16llx\n", reg);
+               if (cxl_afu_reset(afu))
+                       return -EIO;
+               if (cxl_afu_disable(afu))
+                       return -EIO;
+               if (cxl_psl_purge(afu))
+                       return -EIO;
+       }
+       cxl_p1n_write(afu, CXL_PSL_SPAP_An, 0x0000000000000000);
+       cxl_p1n_write(afu, CXL_PSL_IVTE_Limit_An, 0x0000000000000000);
+       cxl_p1n_write(afu, CXL_PSL_IVTE_Offset_An, 0x0000000000000000);
+       cxl_p1n_write(afu, CXL_PSL_AMBAR_An, 0x0000000000000000);
+       cxl_p1n_write(afu, CXL_PSL_SPOffset_An, 0x0000000000000000);
+       cxl_p1n_write(afu, CXL_HAURP_An, 0x0000000000000000);
+       cxl_p2n_write(afu, CXL_CSRP_An, 0x0000000000000000);
+       cxl_p2n_write(afu, CXL_AURP1_An, 0x0000000000000000);
+       cxl_p2n_write(afu, CXL_AURP0_An, 0x0000000000000000);
+       cxl_p2n_write(afu, CXL_SSTP1_An, 0x0000000000000000);
+       cxl_p2n_write(afu, CXL_SSTP0_An, 0x0000000000000000);
+       reg = cxl_p2n_read(afu, CXL_PSL_DSISR_An);
+       if (reg) {
+               dev_warn(&afu->dev, "AFU had pending DSISR: %#.16llx\n", reg);
+               if (reg & CXL_PSL_DSISR_TRANS)
+                       cxl_p2n_write(afu, CXL_PSL_TFC_An, CXL_PSL_TFC_An_AE);
+               else
+                       cxl_p2n_write(afu, CXL_PSL_TFC_An, CXL_PSL_TFC_An_A);
+       }
+       reg = cxl_p1n_read(afu, CXL_PSL_SERR_An);
+       if (reg) {
+               if (reg & ~0xffff)
+                       dev_warn(&afu->dev, "AFU had pending SERR: %#.16llx\n", reg);
+               cxl_p1n_write(afu, CXL_PSL_SERR_An, reg & ~0xffff);
+       }
+       reg = cxl_p2n_read(afu, CXL_PSL_ErrStat_An);
+       if (reg) {
+               dev_warn(&afu->dev, "AFU had pending error status: %#.16llx\n", reg);
+               cxl_p2n_write(afu, CXL_PSL_ErrStat_An, reg);
+       }
+
+       return 0;
+}
+
+static int cxl_init_afu(struct cxl *adapter, int slice, struct pci_dev *dev)
+{
+       struct cxl_afu *afu;
+       bool free = true;
+       int rc;
+
+       if (!(afu = cxl_alloc_afu(adapter, slice)))
+               return -ENOMEM;
+
+       if ((rc = dev_set_name(&afu->dev, "afu%i.%i", adapter->adapter_num, slice)))
+               goto err1;
+
+       if ((rc = cxl_map_slice_regs(afu, adapter, dev)))
+               goto err1;
+
+       if ((rc = sanitise_afu_regs(afu)))
+               goto err2;
+
+       /* We need to reset the AFU before we can read the AFU descriptor */
+       if ((rc = cxl_afu_reset(afu)))
+               goto err2;
+
+       if (cxl_verbose)
+               dump_afu_descriptor(afu);
+
+       if ((rc = cxl_read_afu_descriptor(afu)))
+               goto err2;
+
+       if ((rc = cxl_afu_descriptor_looks_ok(afu)))
+               goto err2;
+
+       if ((rc = init_implementation_afu_regs(afu)))
+               goto err2;
+
+       if ((rc = cxl_register_serr_irq(afu)))
+               goto err2;
+
+       if ((rc = cxl_register_psl_irq(afu)))
+               goto err3;
+
+       /* Don't care if this fails */
+       cxl_debugfs_afu_add(afu);
+
+       /*
+        * After we call this function we must not free the afu directly, even
+        * if it returns an error!
+        */
+       if ((rc = cxl_register_afu(afu)))
+               goto err_put1;
+
+       if ((rc = cxl_sysfs_afu_add(afu)))
+               goto err_put1;
+
+
+       if ((rc = cxl_afu_select_best_mode(afu)))
+               goto err_put2;
+
+       adapter->afu[afu->slice] = afu;
+
+       return 0;
+
+err_put2:
+       cxl_sysfs_afu_remove(afu);
+err_put1:
+       device_unregister(&afu->dev);
+       free = false;
+       cxl_debugfs_afu_remove(afu);
+       cxl_release_psl_irq(afu);
+err3:
+       cxl_release_serr_irq(afu);
+err2:
+       cxl_unmap_slice_regs(afu);
+err1:
+       if (free)
+               kfree(afu);
+       return rc;
+}
+
+static void cxl_remove_afu(struct cxl_afu *afu)
+{
+       pr_devel("cxl_remove_afu\n");
+
+       if (!afu)
+               return;
+
+       cxl_sysfs_afu_remove(afu);
+       cxl_debugfs_afu_remove(afu);
+
+       spin_lock(&afu->adapter->afu_list_lock);
+       afu->adapter->afu[afu->slice] = NULL;
+       spin_unlock(&afu->adapter->afu_list_lock);
+
+       cxl_context_detach_all(afu);
+       cxl_afu_deactivate_mode(afu);
+
+       cxl_release_psl_irq(afu);
+       cxl_release_serr_irq(afu);
+       cxl_unmap_slice_regs(afu);
+
+       device_unregister(&afu->dev);
+}
+
+
+static int cxl_map_adapter_regs(struct cxl *adapter, struct pci_dev *dev)
+{
+       if (pci_request_region(dev, 2, "priv 2 regs"))
+               goto err1;
+       if (pci_request_region(dev, 0, "priv 1 regs"))
+               goto err2;
+
+       pr_devel("cxl_map_adapter_regs: p1: %#.16llx %#llx, p2: %#.16llx %#llx",
+                       p1_base(dev), p1_size(dev), p2_base(dev), p2_size(dev));
+
+       if (!(adapter->p1_mmio = ioremap(p1_base(dev), p1_size(dev))))
+               goto err3;
+
+       if (!(adapter->p2_mmio = ioremap(p2_base(dev), p2_size(dev))))
+               goto err4;
+
+       return 0;
+
+err4:
+       iounmap(adapter->p1_mmio);
+       adapter->p1_mmio = NULL;
+err3:
+       pci_release_region(dev, 0);
+err2:
+       pci_release_region(dev, 2);
+err1:
+       return -ENOMEM;
+}
+
+static void cxl_unmap_adapter_regs(struct cxl *adapter)
+{
+       if (adapter->p1_mmio)
+               iounmap(adapter->p1_mmio);
+       if (adapter->p2_mmio)
+               iounmap(adapter->p2_mmio);
+}
+
+static int cxl_read_vsec(struct cxl *adapter, struct pci_dev *dev)
+{
+       int vsec;
+       u32 afu_desc_off, afu_desc_size;
+       u32 ps_off, ps_size;
+       u16 vseclen;
+       u8 image_state;
+
+       if (!(vsec = find_cxl_vsec(dev))) {
+               dev_err(&adapter->dev, "ABORTING: CXL VSEC not found!\n");
+               return -ENODEV;
+       }
+
+       CXL_READ_VSEC_LENGTH(dev, vsec, &vseclen);
+       if (vseclen < CXL_VSEC_MIN_SIZE) {
+               pr_err("ABORTING: CXL VSEC too short\n");
+               return -EINVAL;
+       }
+
+       CXL_READ_VSEC_STATUS(dev, vsec, &adapter->vsec_status);
+       CXL_READ_VSEC_PSL_REVISION(dev, vsec, &adapter->psl_rev);
+       CXL_READ_VSEC_CAIA_MAJOR(dev, vsec, &adapter->caia_major);
+       CXL_READ_VSEC_CAIA_MINOR(dev, vsec, &adapter->caia_minor);
+       CXL_READ_VSEC_BASE_IMAGE(dev, vsec, &adapter->base_image);
+       CXL_READ_VSEC_IMAGE_STATE(dev, vsec, &image_state);
+       adapter->user_image_loaded = !!(image_state & CXL_VSEC_USER_IMAGE_LOADED);
+       adapter->perst_loads_image = !!(image_state & CXL_VSEC_PERST_LOADS_IMAGE);
+       adapter->perst_select_user = !!(image_state & CXL_VSEC_PERST_SELECT_USER);
+
+       CXL_READ_VSEC_NAFUS(dev, vsec, &adapter->slices);
+       CXL_READ_VSEC_AFU_DESC_OFF(dev, vsec, &afu_desc_off);
+       CXL_READ_VSEC_AFU_DESC_SIZE(dev, vsec, &afu_desc_size);
+       CXL_READ_VSEC_PS_OFF(dev, vsec, &ps_off);
+       CXL_READ_VSEC_PS_SIZE(dev, vsec, &ps_size);
+
+       /* Convert everything to bytes, because there is NO WAY I'd look at the
+        * code a month later and forget what units these are in ;-) */
+       adapter->ps_off = ps_off * 64 * 1024;
+       adapter->ps_size = ps_size * 64 * 1024;
+       adapter->afu_desc_off = afu_desc_off * 64 * 1024;
+       adapter->afu_desc_size = afu_desc_size *64 * 1024;
+
+       /* Total IRQs - 1 PSL ERROR - #AFU*(1 slice error + 1 DSI) */
+       adapter->user_irqs = pnv_cxl_get_irq_count(dev) - 1 - 2*adapter->slices;
+
+       return 0;
+}
+
+static int cxl_vsec_looks_ok(struct cxl *adapter, struct pci_dev *dev)
+{
+       if (adapter->vsec_status & CXL_STATUS_SECOND_PORT)
+               return -EBUSY;
+
+       if (adapter->vsec_status & CXL_UNSUPPORTED_FEATURES) {
+               dev_err(&adapter->dev, "ABORTING: CXL requires unsupported features\n");
+               return -EINVAL;
+       }
+
+       if (!adapter->slices) {
+               /* Once we support dynamic reprogramming we can use the card if
+                * it supports loadable AFUs */
+               dev_err(&adapter->dev, "ABORTING: Device has no AFUs\n");
+               return -EINVAL;
+       }
+
+       if (!adapter->afu_desc_off || !adapter->afu_desc_size) {
+               dev_err(&adapter->dev, "ABORTING: VSEC shows no AFU descriptors\n");
+               return -EINVAL;
+       }
+
+       if (adapter->ps_size > p2_size(dev) - adapter->ps_off) {
+               dev_err(&adapter->dev, "ABORTING: Problem state size larger than "
+                                  "available in BAR2: 0x%llx > 0x%llx\n",
+                        adapter->ps_size, p2_size(dev) - adapter->ps_off);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static void cxl_release_adapter(struct device *dev)
+{
+       struct cxl *adapter = to_cxl_adapter(dev);
+
+       pr_devel("cxl_release_adapter\n");
+
+       kfree(adapter);
+}
+
+static struct cxl *cxl_alloc_adapter(struct pci_dev *dev)
+{
+       struct cxl *adapter;
+
+       if (!(adapter = kzalloc(sizeof(struct cxl), GFP_KERNEL)))
+               return NULL;
+
+       adapter->dev.parent = &dev->dev;
+       adapter->dev.release = cxl_release_adapter;
+       pci_set_drvdata(dev, adapter);
+       spin_lock_init(&adapter->afu_list_lock);
+
+       return adapter;
+}
+
+static int sanitise_adapter_regs(struct cxl *adapter)
+{
+       cxl_p1_write(adapter, CXL_PSL_ErrIVTE, 0x0000000000000000);
+       return cxl_tlb_slb_invalidate(adapter);
+}
+
+static struct cxl *cxl_init_adapter(struct pci_dev *dev)
+{
+       struct cxl *adapter;
+       bool free = true;
+       int rc;
+
+
+       if (!(adapter = cxl_alloc_adapter(dev)))
+               return ERR_PTR(-ENOMEM);
+
+       if ((rc = switch_card_to_cxl(dev)))
+               goto err1;
+
+       if ((rc = cxl_alloc_adapter_nr(adapter)))
+               goto err1;
+
+       if ((rc = dev_set_name(&adapter->dev, "card%i", adapter->adapter_num)))
+               goto err2;
+
+       if ((rc = cxl_read_vsec(adapter, dev)))
+               goto err2;
+
+       if ((rc = cxl_vsec_looks_ok(adapter, dev)))
+               goto err2;
+
+       if ((rc = cxl_map_adapter_regs(adapter, dev)))
+               goto err2;
+
+       if ((rc = sanitise_adapter_regs(adapter)))
+               goto err2;
+
+       if ((rc = init_implementation_adapter_regs(adapter, dev)))
+               goto err3;
+
+       if ((rc = pnv_phb_to_cxl(dev)))
+               goto err3;
+
+       if ((rc = cxl_register_psl_err_irq(adapter)))
+               goto err3;
+
+       /* Don't care if this one fails: */
+       cxl_debugfs_adapter_add(adapter);
+
+       /*
+        * After we call this function we must not free the adapter directly,
+        * even if it returns an error!
+        */
+       if ((rc = cxl_register_adapter(adapter)))
+               goto err_put1;
+
+       if ((rc = cxl_sysfs_adapter_add(adapter)))
+               goto err_put1;
+
+       return adapter;
+
+err_put1:
+       device_unregister(&adapter->dev);
+       free = false;
+       cxl_debugfs_adapter_remove(adapter);
+       cxl_release_psl_err_irq(adapter);
+err3:
+       cxl_unmap_adapter_regs(adapter);
+err2:
+       cxl_remove_adapter_nr(adapter);
+err1:
+       if (free)
+               kfree(adapter);
+       return ERR_PTR(rc);
+}
+
+static void cxl_remove_adapter(struct cxl *adapter)
+{
+       struct pci_dev *pdev = to_pci_dev(adapter->dev.parent);
+
+       pr_devel("cxl_release_adapter\n");
+
+       cxl_sysfs_adapter_remove(adapter);
+       cxl_debugfs_adapter_remove(adapter);
+       cxl_release_psl_err_irq(adapter);
+       cxl_unmap_adapter_regs(adapter);
+       cxl_remove_adapter_nr(adapter);
+
+       device_unregister(&adapter->dev);
+
+       pci_release_region(pdev, 0);
+       pci_release_region(pdev, 2);
+       pci_disable_device(pdev);
+}
+
+static int cxl_probe(struct pci_dev *dev, const struct pci_device_id *id)
+{
+       struct cxl *adapter;
+       int slice;
+       int rc;
+
+       pci_dev_get(dev);
+
+       if (cxl_verbose)
+               dump_cxl_config_space(dev);
+
+       if ((rc = setup_cxl_bars(dev)))
+               return rc;
+
+       if ((rc = pci_enable_device(dev))) {
+               dev_err(&dev->dev, "pci_enable_device failed: %i\n", rc);
+               return rc;
+       }
+
+       adapter = cxl_init_adapter(dev);
+       if (IS_ERR(adapter)) {
+               dev_err(&dev->dev, "cxl_init_adapter failed: %li\n", PTR_ERR(adapter));
+               return PTR_ERR(adapter);
+       }
+
+       for (slice = 0; slice < adapter->slices; slice++) {
+               if ((rc = cxl_init_afu(adapter, slice, dev)))
+                       dev_err(&dev->dev, "AFU %i failed to initialise: %i\n", slice, rc);
+       }
+
+       return 0;
+}
+
+static void cxl_remove(struct pci_dev *dev)
+{
+       struct cxl *adapter = pci_get_drvdata(dev);
+       int afu;
+
+       dev_warn(&dev->dev, "pci remove\n");
+
+       /*
+        * Lock to prevent someone grabbing a ref through the adapter list as
+        * we are removing it
+        */
+       for (afu = 0; afu < adapter->slices; afu++)
+               cxl_remove_afu(adapter->afu[afu]);
+       cxl_remove_adapter(adapter);
+}
+
+struct pci_driver cxl_pci_driver = {
+       .name = "cxl-pci",
+       .id_table = cxl_pci_tbl,
+       .probe = cxl_probe,
+       .remove = cxl_remove,
+};
diff --git a/drivers/misc/cxl/sysfs.c b/drivers/misc/cxl/sysfs.c
new file mode 100644 (file)
index 0000000..ce7ec06
--- /dev/null
@@ -0,0 +1,385 @@
+/*
+ * Copyright 2014 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.
+ */
+
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/sysfs.h>
+
+#include "cxl.h"
+
+#define to_afu_chardev_m(d) dev_get_drvdata(d)
+
+/*********  Adapter attributes  **********************************************/
+
+static ssize_t caia_version_show(struct device *device,
+                                struct device_attribute *attr,
+                                char *buf)
+{
+       struct cxl *adapter = to_cxl_adapter(device);
+
+       return scnprintf(buf, PAGE_SIZE, "%i.%i\n", adapter->caia_major,
+                        adapter->caia_minor);
+}
+
+static ssize_t psl_revision_show(struct device *device,
+                                struct device_attribute *attr,
+                                char *buf)
+{
+       struct cxl *adapter = to_cxl_adapter(device);
+
+       return scnprintf(buf, PAGE_SIZE, "%i\n", adapter->psl_rev);
+}
+
+static ssize_t base_image_show(struct device *device,
+                              struct device_attribute *attr,
+                              char *buf)
+{
+       struct cxl *adapter = to_cxl_adapter(device);
+
+       return scnprintf(buf, PAGE_SIZE, "%i\n", adapter->base_image);
+}
+
+static ssize_t image_loaded_show(struct device *device,
+                                struct device_attribute *attr,
+                                char *buf)
+{
+       struct cxl *adapter = to_cxl_adapter(device);
+
+       if (adapter->user_image_loaded)
+               return scnprintf(buf, PAGE_SIZE, "user\n");
+       return scnprintf(buf, PAGE_SIZE, "factory\n");
+}
+
+static struct device_attribute adapter_attrs[] = {
+       __ATTR_RO(caia_version),
+       __ATTR_RO(psl_revision),
+       __ATTR_RO(base_image),
+       __ATTR_RO(image_loaded),
+};
+
+
+/*********  AFU master specific attributes  **********************************/
+
+static ssize_t mmio_size_show_master(struct device *device,
+                                    struct device_attribute *attr,
+                                    char *buf)
+{
+       struct cxl_afu *afu = to_afu_chardev_m(device);
+
+       return scnprintf(buf, PAGE_SIZE, "%llu\n", afu->adapter->ps_size);
+}
+
+static ssize_t pp_mmio_off_show(struct device *device,
+                               struct device_attribute *attr,
+                               char *buf)
+{
+       struct cxl_afu *afu = to_afu_chardev_m(device);
+
+       return scnprintf(buf, PAGE_SIZE, "%llu\n", afu->pp_offset);
+}
+
+static ssize_t pp_mmio_len_show(struct device *device,
+                               struct device_attribute *attr,
+                               char *buf)
+{
+       struct cxl_afu *afu = to_afu_chardev_m(device);
+
+       return scnprintf(buf, PAGE_SIZE, "%llu\n", afu->pp_size);
+}
+
+static struct device_attribute afu_master_attrs[] = {
+       __ATTR(mmio_size, S_IRUGO, mmio_size_show_master, NULL),
+       __ATTR_RO(pp_mmio_off),
+       __ATTR_RO(pp_mmio_len),
+};
+
+
+/*********  AFU attributes  **************************************************/
+
+static ssize_t mmio_size_show(struct device *device,
+                             struct device_attribute *attr,
+                             char *buf)
+{
+       struct cxl_afu *afu = to_cxl_afu(device);
+
+       if (afu->pp_size)
+               return scnprintf(buf, PAGE_SIZE, "%llu\n", afu->pp_size);
+       return scnprintf(buf, PAGE_SIZE, "%llu\n", afu->adapter->ps_size);
+}
+
+static ssize_t reset_store_afu(struct device *device,
+                              struct device_attribute *attr,
+                              const char *buf, size_t count)
+{
+       struct cxl_afu *afu = to_cxl_afu(device);
+       int rc;
+
+       /* Not safe to reset if it is currently in use */
+       spin_lock(&afu->contexts_lock);
+       if (!idr_is_empty(&afu->contexts_idr)) {
+               rc = -EBUSY;
+               goto err;
+       }
+
+       if ((rc = cxl_afu_reset(afu)))
+               goto err;
+
+       rc = count;
+err:
+       spin_unlock(&afu->contexts_lock);
+       return rc;
+}
+
+static ssize_t irqs_min_show(struct device *device,
+                            struct device_attribute *attr,
+                            char *buf)
+{
+       struct cxl_afu *afu = to_cxl_afu(device);
+
+       return scnprintf(buf, PAGE_SIZE, "%i\n", afu->pp_irqs);
+}
+
+static ssize_t irqs_max_show(struct device *device,
+                                 struct device_attribute *attr,
+                                 char *buf)
+{
+       struct cxl_afu *afu = to_cxl_afu(device);
+
+       return scnprintf(buf, PAGE_SIZE, "%i\n", afu->irqs_max);
+}
+
+static ssize_t irqs_max_store(struct device *device,
+                                 struct device_attribute *attr,
+                                 const char *buf, size_t count)
+{
+       struct cxl_afu *afu = to_cxl_afu(device);
+       ssize_t ret;
+       int irqs_max;
+
+       ret = sscanf(buf, "%i", &irqs_max);
+       if (ret != 1)
+               return -EINVAL;
+
+       if (irqs_max < afu->pp_irqs)
+               return -EINVAL;
+
+       if (irqs_max > afu->adapter->user_irqs)
+               return -EINVAL;
+
+       afu->irqs_max = irqs_max;
+       return count;
+}
+
+static ssize_t modes_supported_show(struct device *device,
+                                   struct device_attribute *attr, char *buf)
+{
+       struct cxl_afu *afu = to_cxl_afu(device);
+       char *p = buf, *end = buf + PAGE_SIZE;
+
+       if (afu->modes_supported & CXL_MODE_DEDICATED)
+               p += scnprintf(p, end - p, "dedicated_process\n");
+       if (afu->modes_supported & CXL_MODE_DIRECTED)
+               p += scnprintf(p, end - p, "afu_directed\n");
+       return (p - buf);
+}
+
+static ssize_t prefault_mode_show(struct device *device,
+                                 struct device_attribute *attr,
+                                 char *buf)
+{
+       struct cxl_afu *afu = to_cxl_afu(device);
+
+       switch (afu->prefault_mode) {
+       case CXL_PREFAULT_WED:
+               return scnprintf(buf, PAGE_SIZE, "work_element_descriptor\n");
+       case CXL_PREFAULT_ALL:
+               return scnprintf(buf, PAGE_SIZE, "all\n");
+       default:
+               return scnprintf(buf, PAGE_SIZE, "none\n");
+       }
+}
+
+static ssize_t prefault_mode_store(struct device *device,
+                         struct device_attribute *attr,
+                         const char *buf, size_t count)
+{
+       struct cxl_afu *afu = to_cxl_afu(device);
+       enum prefault_modes mode = -1;
+
+       if (!strncmp(buf, "work_element_descriptor", 23))
+               mode = CXL_PREFAULT_WED;
+       if (!strncmp(buf, "all", 3))
+               mode = CXL_PREFAULT_ALL;
+       if (!strncmp(buf, "none", 4))
+               mode = CXL_PREFAULT_NONE;
+
+       if (mode == -1)
+               return -EINVAL;
+
+       afu->prefault_mode = mode;
+       return count;
+}
+
+static ssize_t mode_show(struct device *device,
+                        struct device_attribute *attr,
+                        char *buf)
+{
+       struct cxl_afu *afu = to_cxl_afu(device);
+
+       if (afu->current_mode == CXL_MODE_DEDICATED)
+               return scnprintf(buf, PAGE_SIZE, "dedicated_process\n");
+       if (afu->current_mode == CXL_MODE_DIRECTED)
+               return scnprintf(buf, PAGE_SIZE, "afu_directed\n");
+       return scnprintf(buf, PAGE_SIZE, "none\n");
+}
+
+static ssize_t mode_store(struct device *device, struct device_attribute *attr,
+                         const char *buf, size_t count)
+{
+       struct cxl_afu *afu = to_cxl_afu(device);
+       int old_mode, mode = -1;
+       int rc = -EBUSY;
+
+       /* can't change this if we have a user */
+       spin_lock(&afu->contexts_lock);
+       if (!idr_is_empty(&afu->contexts_idr))
+               goto err;
+
+       if (!strncmp(buf, "dedicated_process", 17))
+               mode = CXL_MODE_DEDICATED;
+       if (!strncmp(buf, "afu_directed", 12))
+               mode = CXL_MODE_DIRECTED;
+       if (!strncmp(buf, "none", 4))
+               mode = 0;
+
+       if (mode == -1) {
+               rc = -EINVAL;
+               goto err;
+       }
+
+       /*
+        * cxl_afu_deactivate_mode needs to be done outside the lock, prevent
+        * other contexts coming in before we are ready:
+        */
+       old_mode = afu->current_mode;
+       afu->current_mode = 0;
+       afu->num_procs = 0;
+
+       spin_unlock(&afu->contexts_lock);
+
+       if ((rc = _cxl_afu_deactivate_mode(afu, old_mode)))
+               return rc;
+       if ((rc = cxl_afu_activate_mode(afu, mode)))
+               return rc;
+
+       return count;
+err:
+       spin_unlock(&afu->contexts_lock);
+       return rc;
+}
+
+static ssize_t api_version_show(struct device *device,
+                               struct device_attribute *attr,
+                               char *buf)
+{
+       return scnprintf(buf, PAGE_SIZE, "%i\n", CXL_API_VERSION);
+}
+
+static ssize_t api_version_compatible_show(struct device *device,
+                                          struct device_attribute *attr,
+                                          char *buf)
+{
+       return scnprintf(buf, PAGE_SIZE, "%i\n", CXL_API_VERSION_COMPATIBLE);
+}
+
+static struct device_attribute afu_attrs[] = {
+       __ATTR_RO(mmio_size),
+       __ATTR_RO(irqs_min),
+       __ATTR_RW(irqs_max),
+       __ATTR_RO(modes_supported),
+       __ATTR_RW(mode),
+       __ATTR_RW(prefault_mode),
+       __ATTR_RO(api_version),
+       __ATTR_RO(api_version_compatible),
+       __ATTR(reset, S_IWUSR, NULL, reset_store_afu),
+};
+
+
+
+int cxl_sysfs_adapter_add(struct cxl *adapter)
+{
+       int i, rc;
+
+       for (i = 0; i < ARRAY_SIZE(adapter_attrs); i++) {
+               if ((rc = device_create_file(&adapter->dev, &adapter_attrs[i])))
+                       goto err;
+       }
+       return 0;
+err:
+       for (i--; i >= 0; i--)
+               device_remove_file(&adapter->dev, &adapter_attrs[i]);
+       return rc;
+}
+void cxl_sysfs_adapter_remove(struct cxl *adapter)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(adapter_attrs); i++)
+               device_remove_file(&adapter->dev, &adapter_attrs[i]);
+}
+
+int cxl_sysfs_afu_add(struct cxl_afu *afu)
+{
+       int i, rc;
+
+       for (i = 0; i < ARRAY_SIZE(afu_attrs); i++) {
+               if ((rc = device_create_file(&afu->dev, &afu_attrs[i])))
+                       goto err;
+       }
+
+       return 0;
+
+err:
+       for (i--; i >= 0; i--)
+               device_remove_file(&afu->dev, &afu_attrs[i]);
+       return rc;
+}
+
+void cxl_sysfs_afu_remove(struct cxl_afu *afu)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(afu_attrs); i++)
+               device_remove_file(&afu->dev, &afu_attrs[i]);
+}
+
+int cxl_sysfs_afu_m_add(struct cxl_afu *afu)
+{
+       int i, rc;
+
+       for (i = 0; i < ARRAY_SIZE(afu_master_attrs); i++) {
+               if ((rc = device_create_file(afu->chardev_m, &afu_master_attrs[i])))
+                       goto err;
+       }
+
+       return 0;
+
+err:
+       for (i--; i >= 0; i--)
+               device_remove_file(afu->chardev_m, &afu_master_attrs[i]);
+       return rc;
+}
+
+void cxl_sysfs_afu_m_remove(struct cxl_afu *afu)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(afu_master_attrs); i++)
+               device_remove_file(afu->chardev_m, &afu_master_attrs[i]);
+}
index ede41f05c392d499542dac45f9228f37364ecf30..1fa4c80ff88639e894ba8276387cb73cfbd3b93b 100644 (file)
@@ -977,7 +977,7 @@ static int mmc_blk_cmd_recovery(struct mmc_card *card, struct request *req,
                return ERR_CONTINUE;
 
        /* Now for stop errors.  These aren't fatal to the transfer. */
-       pr_err("%s: error %d sending stop command, original cmd response %#x, card status %#x\n",
+       pr_info("%s: error %d sending stop command, original cmd response %#x, card status %#x\n",
               req->rq_disk->disk_name, brq->stop.error,
               brq->cmd.resp[0], status);
 
@@ -1398,10 +1398,15 @@ static void mmc_blk_rw_rq_prep(struct mmc_queue_req *mqrq,
                if (disable_multi)
                        brq->data.blocks = 1;
 
-               /* Some controllers can't do multiblock reads due to hw bugs */
-               if (card->host->caps2 & MMC_CAP2_NO_MULTI_READ &&
-                   rq_data_dir(req) == READ)
-                       brq->data.blocks = 1;
+               /*
+                * Some controllers have HW issues while operating
+                * in multiple I/O mode
+                */
+               if (card->host->ops->multi_io_quirk)
+                       brq->data.blocks = card->host->ops->multi_io_quirk(card,
+                                               (rq_data_dir(req) == READ) ?
+                                               MMC_DATA_READ : MMC_DATA_WRITE,
+                                               brq->data.blocks);
        }
 
        if (brq->data.blocks > 1 || do_rel_wr) {
@@ -1923,8 +1928,8 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *rqc)
                case MMC_BLK_ECC_ERR:
                        if (brq->data.blocks > 1) {
                                /* Redo read one sector at a time */
-                               pr_warning("%s: retrying using single block read\n",
-                                          req->rq_disk->disk_name);
+                               pr_warn("%s: retrying using single block read\n",
+                                       req->rq_disk->disk_name);
                                disable_multi = 1;
                                break;
                        }
@@ -2131,7 +2136,7 @@ static struct mmc_blk_data *mmc_blk_alloc_req(struct mmc_card *card,
        md->disk->queue = md->queue.queue;
        md->disk->driverfs_dev = parent;
        set_disk_ro(md->disk, md->read_only || default_ro);
-       if (area_type & MMC_BLK_DATA_AREA_RPMB)
+       if (area_type & (MMC_BLK_DATA_AREA_RPMB | MMC_BLK_DATA_AREA_BOOT))
                md->disk->flags |= GENHD_FL_NO_PART_SCAN;
 
        /*
index 3e049c13429cfbe730179724053796cc65ba62de..feea926e32f87b7d47610c41a85732dfcf3cc832 100644 (file)
@@ -229,14 +229,12 @@ int mmc_init_queue(struct mmc_queue *mq, struct mmc_card *card,
                if (bouncesz > 512) {
                        mqrq_cur->bounce_buf = kmalloc(bouncesz, GFP_KERNEL);
                        if (!mqrq_cur->bounce_buf) {
-                               pr_warning("%s: unable to "
-                                       "allocate bounce cur buffer\n",
+                               pr_warn("%s: unable to allocate bounce cur buffer\n",
                                        mmc_card_name(card));
                        }
                        mqrq_prev->bounce_buf = kmalloc(bouncesz, GFP_KERNEL);
                        if (!mqrq_prev->bounce_buf) {
-                               pr_warning("%s: unable to "
-                                       "allocate bounce prev buffer\n",
+                               pr_warn("%s: unable to allocate bounce prev buffer\n",
                                        mmc_card_name(card));
                                kfree(mqrq_cur->bounce_buf);
                                mqrq_cur->bounce_buf = NULL;
index f093cea0d0600797cc1574c6f85a25dac5c128fc..d2de5925b73e6d7cb730b6b687e26d04cc0f92bf 100644 (file)
@@ -1063,8 +1063,8 @@ static int sdio_uart_probe(struct sdio_func *func,
                return -ENOMEM;
 
        if (func->class == SDIO_CLASS_UART) {
-               pr_warning("%s: need info on UART class basic setup\n",
-                      sdio_func_id(func));
+               pr_warn("%s: need info on UART class basic setup\n",
+                       sdio_func_id(func));
                kfree(port);
                return -ENOSYS;
        } else if (func->class == SDIO_CLASS_GPS) {
@@ -1082,9 +1082,8 @@ static int sdio_uart_probe(struct sdio_func *func,
                                break;
                }
                if (!tpl) {
-                       pr_warning(
-       "%s: can't find tuple 0x91 subtuple 0 (SUBTPL_SIOREG) for GPS class\n",
-                              sdio_func_id(func));
+                       pr_warn("%s: can't find tuple 0x91 subtuple 0 (SUBTPL_SIOREG) for GPS class\n",
+                               sdio_func_id(func));
                        kfree(port);
                        return -EINVAL;
                }
index d03a080fb9cd35ff0b29bf50380f08fdd8818c23..f26a5f1d926dd7e6a79ec1b9f87f7be4fd691994 100644 (file)
@@ -433,8 +433,8 @@ static void mmc_wait_for_req_done(struct mmc_host *host,
                 */
                if (cmd->sanitize_busy && cmd->error == -ETIMEDOUT) {
                        if (!mmc_interrupt_hpi(host->card)) {
-                               pr_warning("%s: %s: Interrupted sanitize\n",
-                                          mmc_hostname(host), __func__);
+                               pr_warn("%s: %s: Interrupted sanitize\n",
+                                       mmc_hostname(host), __func__);
                                cmd->error = 0;
                                break;
                        } else {
@@ -995,7 +995,7 @@ void mmc_set_chip_select(struct mmc_host *host, int mode)
  */
 static void __mmc_set_clock(struct mmc_host *host, unsigned int hz)
 {
-       WARN_ON(hz < host->f_min);
+       WARN_ON(hz && hz < host->f_min);
 
        if (hz > host->f_max)
                hz = host->f_max;
@@ -1221,15 +1221,14 @@ int mmc_regulator_get_ocrmask(struct regulator *supply)
        int                     result = 0;
        int                     count;
        int                     i;
+       int                     vdd_uV;
+       int                     vdd_mV;
 
        count = regulator_count_voltages(supply);
        if (count < 0)
                return count;
 
        for (i = 0; i < count; i++) {
-               int             vdd_uV;
-               int             vdd_mV;
-
                vdd_uV = regulator_list_voltage(supply, i);
                if (vdd_uV <= 0)
                        continue;
@@ -1238,6 +1237,15 @@ int mmc_regulator_get_ocrmask(struct regulator *supply)
                result |= mmc_vddrange_to_ocrmask(vdd_mV, vdd_mV);
        }
 
+       if (!result) {
+               vdd_uV = regulator_get_voltage(supply);
+               if (vdd_uV <= 0)
+                       return vdd_uV;
+
+               vdd_mV = vdd_uV / 1000;
+               result = mmc_vddrange_to_ocrmask(vdd_mV, vdd_mV);
+       }
+
        return result;
 }
 EXPORT_SYMBOL_GPL(mmc_regulator_get_ocrmask);
@@ -1263,7 +1271,6 @@ int mmc_regulator_set_ocr(struct mmc_host *mmc,
 
        if (vdd_bit) {
                int             tmp;
-               int             voltage;
 
                /*
                 * REVISIT mmc_vddrange_to_ocrmask() may have set some
@@ -1280,22 +1287,7 @@ int mmc_regulator_set_ocr(struct mmc_host *mmc,
                        max_uV = min_uV + 100 * 1000;
                }
 
-               /*
-                * If we're using a fixed/static regulator, don't call
-                * regulator_set_voltage; it would fail.
-                */
-               voltage = regulator_get_voltage(supply);
-
-               if (!regulator_can_change_voltage(supply))
-                       min_uV = max_uV = voltage;
-
-               if (voltage < 0)
-                       result = voltage;
-               else if (voltage < min_uV || voltage > max_uV)
-                       result = regulator_set_voltage(supply, min_uV, max_uV);
-               else
-                       result = 0;
-
+               result = regulator_set_voltage(supply, min_uV, max_uV);
                if (result == 0 && !mmc->regulator_enabled) {
                        result = regulator_enable(supply);
                        if (!result)
@@ -1425,8 +1417,8 @@ int mmc_set_signal_voltage(struct mmc_host *host, int signal_voltage, u32 ocr)
        if (!host->ops->start_signal_voltage_switch)
                return -EPERM;
        if (!host->ops->card_busy)
-               pr_warning("%s: cannot verify signal voltage switch\n",
-                               mmc_hostname(host));
+               pr_warn("%s: cannot verify signal voltage switch\n",
+                       mmc_hostname(host));
 
        cmd.opcode = SD_SWITCH_VOLTAGE;
        cmd.arg = 0;
@@ -1761,7 +1753,7 @@ void mmc_init_erase(struct mmc_card *card)
                card->erase_shift = ffs(card->ssr.au) - 1;
        } else if (card->ext_csd.hc_erase_size) {
                card->pref_erase = card->ext_csd.hc_erase_size;
-       } else {
+       } else if (card->erase_size) {
                sz = (card->csd.capacity << (card->csd.read_blkbits - 9)) >> 11;
                if (sz < 128)
                        card->pref_erase = 512 * 1024 / 512;
@@ -1778,7 +1770,8 @@ void mmc_init_erase(struct mmc_card *card)
                        if (sz)
                                card->pref_erase += card->erase_size - sz;
                }
-       }
+       } else
+               card->pref_erase = 0;
 }
 
 static unsigned int mmc_mmc_erase_timeout(struct mmc_card *card,
@@ -2489,6 +2482,7 @@ void mmc_start_host(struct mmc_host *host)
 {
        host->f_init = max(freqs[0], host->f_min);
        host->rescan_disable = 0;
+       host->ios.power_mode = MMC_POWER_UNDEFINED;
        if (host->caps2 & MMC_CAP2_NO_PRESCAN_POWERUP)
                mmc_power_off(host);
        else
index 95cceae96944c17c19dbb4e9916119a72fb2bce6..03c53b72a2d6a34bafbea7e1a1bda90299772fa8 100644 (file)
@@ -310,9 +310,8 @@ int mmc_of_parse(struct mmc_host *host)
 {
        struct device_node *np;
        u32 bus_width;
-       bool explicit_inv_wp, gpio_inv_wp = false;
-       enum of_gpio_flags flags;
-       int len, ret, gpio;
+       int len, ret;
+       bool cap_invert, gpio_invert;
 
        if (!host->parent || !host->parent->of_node)
                return 0;
@@ -360,59 +359,62 @@ int mmc_of_parse(struct mmc_host *host)
        if (of_find_property(np, "non-removable", &len)) {
                host->caps |= MMC_CAP_NONREMOVABLE;
        } else {
-               bool explicit_inv_cd, gpio_inv_cd = false;
-
-               explicit_inv_cd = of_property_read_bool(np, "cd-inverted");
+               if (of_property_read_bool(np, "cd-inverted"))
+                       cap_invert = true;
+               else
+                       cap_invert = false;
 
                if (of_find_property(np, "broken-cd", &len))
                        host->caps |= MMC_CAP_NEEDS_POLL;
 
-               gpio = of_get_named_gpio_flags(np, "cd-gpios", 0, &flags);
-               if (gpio == -EPROBE_DEFER)
-                       return gpio;
-               if (gpio_is_valid(gpio)) {
-                       if (!(flags & OF_GPIO_ACTIVE_LOW))
-                               gpio_inv_cd = true;
-
-                       ret = mmc_gpio_request_cd(host, gpio, 0);
-                       if (ret < 0) {
-                               dev_err(host->parent,
-                                       "Failed to request CD GPIO #%d: %d!\n",
-                                       gpio, ret);
+               ret = mmc_gpiod_request_cd(host, "cd", 0, true,
+                                          0, &gpio_invert);
+               if (ret) {
+                       if (ret == -EPROBE_DEFER)
                                return ret;
-                       } else {
-                               dev_info(host->parent, "Got CD GPIO #%d.\n",
-                                        gpio);
+                       if (ret != -ENOENT) {
+                               dev_err(host->parent,
+                                       "Failed to request CD GPIO: %d\n",
+                                       ret);
                        }
-               }
-
-               if (explicit_inv_cd ^ gpio_inv_cd)
+               } else
+                       dev_info(host->parent, "Got CD GPIO\n");
+
+               /*
+                * There are two ways to flag that the CD line is inverted:
+                * through the cd-inverted flag and by the GPIO line itself
+                * being inverted from the GPIO subsystem. This is a leftover
+                * from the times when the GPIO subsystem did not make it
+                * possible to flag a line as inverted.
+                *
+                * If the capability on the host AND the GPIO line are
+                * both inverted, the end result is that the CD line is
+                * not inverted.
+                */
+               if (cap_invert ^ gpio_invert)
                        host->caps2 |= MMC_CAP2_CD_ACTIVE_HIGH;
        }
 
        /* Parse Write Protection */
-       explicit_inv_wp = of_property_read_bool(np, "wp-inverted");
-
-       gpio = of_get_named_gpio_flags(np, "wp-gpios", 0, &flags);
-       if (gpio == -EPROBE_DEFER) {
-               ret = -EPROBE_DEFER;
-               goto out;
-       }
-       if (gpio_is_valid(gpio)) {
-               if (!(flags & OF_GPIO_ACTIVE_LOW))
-                       gpio_inv_wp = true;
+       if (of_property_read_bool(np, "wp-inverted"))
+               cap_invert = true;
+       else
+               cap_invert = false;
 
-               ret = mmc_gpio_request_ro(host, gpio);
-               if (ret < 0) {
-                       dev_err(host->parent,
-                               "Failed to request WP GPIO: %d!\n", ret);
+       ret = mmc_gpiod_request_ro(host, "wp", 0, false, 0, &gpio_invert);
+       if (ret) {
+               if (ret == -EPROBE_DEFER)
                        goto out;
-               } else {
-                               dev_info(host->parent, "Got WP GPIO #%d.\n",
-                                        gpio);
+               if (ret != -ENOENT) {
+                       dev_err(host->parent,
+                               "Failed to request WP GPIO: %d\n",
+                               ret);
                }
-       }
-       if (explicit_inv_wp ^ gpio_inv_wp)
+       } else
+               dev_info(host->parent, "Got WP GPIO\n");
+
+       /* See the comment on CD inversion above */
+       if (cap_invert ^ gpio_invert)
                host->caps2 |= MMC_CAP2_RO_ACTIVE_HIGH;
 
        if (of_find_property(np, "cap-sd-highspeed", &len))
@@ -452,6 +454,14 @@ int mmc_of_parse(struct mmc_host *host)
        if (of_find_property(np, "mmc-hs400-1_2v", &len))
                host->caps2 |= MMC_CAP2_HS400_1_2V | MMC_CAP2_HS200_1_2V_SDR;
 
+       host->dsr_req = !of_property_read_u32(np, "dsr", &host->dsr);
+       if (host->dsr_req && (host->dsr & ~0xffff)) {
+               dev_err(host->parent,
+                       "device tree specified broken value for DSR: 0x%x, ignoring\n",
+                       host->dsr);
+               host->dsr_req = 0;
+       }
+
        return 0;
 
 out:
index 1eda8dd8c867228b5643e40f7655b513643eb26f..a301a78a2bd1cdc11eb5f674ab563ac74700ea76 100644 (file)
@@ -162,6 +162,7 @@ static int mmc_decode_csd(struct mmc_card *card)
        csd->read_partial = UNSTUFF_BITS(resp, 79, 1);
        csd->write_misalign = UNSTUFF_BITS(resp, 78, 1);
        csd->read_misalign = UNSTUFF_BITS(resp, 77, 1);
+       csd->dsr_imp = UNSTUFF_BITS(resp, 76, 1);
        csd->r2w_factor = UNSTUFF_BITS(resp, 26, 3);
        csd->write_blkbits = UNSTUFF_BITS(resp, 22, 4);
        csd->write_partial = UNSTUFF_BITS(resp, 21, 1);
@@ -225,9 +226,7 @@ static int mmc_get_ext_csd(struct mmc_card *card, u8 **new_ext_csd)
                                "Card will be ignored.\n",
                                mmc_hostname(card->host));
                } else {
-                       pr_warning("%s: unable to read "
-                               "EXT_CSD, performance might "
-                               "suffer.\n",
+                       pr_warn("%s: unable to read EXT_CSD, performance might suffer\n",
                                mmc_hostname(card->host));
                        err = 0;
                }
@@ -298,6 +297,97 @@ static void mmc_select_card_type(struct mmc_card *card)
        card->mmc_avail_type = avail_type;
 }
 
+static void mmc_manage_enhanced_area(struct mmc_card *card, u8 *ext_csd)
+{
+       u8 hc_erase_grp_sz, hc_wp_grp_sz;
+
+       /*
+        * Disable these attributes by default
+        */
+       card->ext_csd.enhanced_area_offset = -EINVAL;
+       card->ext_csd.enhanced_area_size = -EINVAL;
+
+       /*
+        * Enhanced area feature support -- check whether the eMMC
+        * card has the Enhanced area enabled.  If so, export enhanced
+        * area offset and size to user by adding sysfs interface.
+        */
+       if ((ext_csd[EXT_CSD_PARTITION_SUPPORT] & 0x2) &&
+           (ext_csd[EXT_CSD_PARTITION_ATTRIBUTE] & 0x1)) {
+               if (card->ext_csd.partition_setting_completed) {
+                       hc_erase_grp_sz =
+                               ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE];
+                       hc_wp_grp_sz =
+                               ext_csd[EXT_CSD_HC_WP_GRP_SIZE];
+
+                       /*
+                        * calculate the enhanced data area offset, in bytes
+                        */
+                       card->ext_csd.enhanced_area_offset =
+                               (ext_csd[139] << 24) + (ext_csd[138] << 16) +
+                               (ext_csd[137] << 8) + ext_csd[136];
+                       if (mmc_card_blockaddr(card))
+                               card->ext_csd.enhanced_area_offset <<= 9;
+                       /*
+                        * calculate the enhanced data area size, in kilobytes
+                        */
+                       card->ext_csd.enhanced_area_size =
+                               (ext_csd[142] << 16) + (ext_csd[141] << 8) +
+                               ext_csd[140];
+                       card->ext_csd.enhanced_area_size *=
+                               (size_t)(hc_erase_grp_sz * hc_wp_grp_sz);
+                       card->ext_csd.enhanced_area_size <<= 9;
+               } else {
+                       pr_warn("%s: defines enhanced area without partition setting complete\n",
+                               mmc_hostname(card->host));
+               }
+       }
+}
+
+static void mmc_manage_gp_partitions(struct mmc_card *card, u8 *ext_csd)
+{
+       int idx;
+       u8 hc_erase_grp_sz, hc_wp_grp_sz;
+       unsigned int part_size;
+
+       /*
+        * General purpose partition feature support --
+        * If ext_csd has the size of general purpose partitions,
+        * set size, part_cfg, partition name in mmc_part.
+        */
+       if (ext_csd[EXT_CSD_PARTITION_SUPPORT] &
+           EXT_CSD_PART_SUPPORT_PART_EN) {
+               hc_erase_grp_sz =
+                       ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE];
+               hc_wp_grp_sz =
+                       ext_csd[EXT_CSD_HC_WP_GRP_SIZE];
+
+               for (idx = 0; idx < MMC_NUM_GP_PARTITION; idx++) {
+                       if (!ext_csd[EXT_CSD_GP_SIZE_MULT + idx * 3] &&
+                           !ext_csd[EXT_CSD_GP_SIZE_MULT + idx * 3 + 1] &&
+                           !ext_csd[EXT_CSD_GP_SIZE_MULT + idx * 3 + 2])
+                               continue;
+                       if (card->ext_csd.partition_setting_completed == 0) {
+                               pr_warn("%s: has partition size defined without partition complete\n",
+                                       mmc_hostname(card->host));
+                               break;
+                       }
+                       part_size =
+                               (ext_csd[EXT_CSD_GP_SIZE_MULT + idx * 3 + 2]
+                               << 16) +
+                               (ext_csd[EXT_CSD_GP_SIZE_MULT + idx * 3 + 1]
+                               << 8) +
+                               ext_csd[EXT_CSD_GP_SIZE_MULT + idx * 3];
+                       part_size *= (size_t)(hc_erase_grp_sz *
+                               hc_wp_grp_sz);
+                       mmc_part_add(card, part_size << 19,
+                               EXT_CSD_PART_CONFIG_ACC_GP0 + idx,
+                               "gp%d", idx, false,
+                               MMC_BLK_DATA_AREA_GP);
+               }
+       }
+}
+
 /*
  * Decode extended CSD.
  */
@@ -305,7 +395,6 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd)
 {
        int err = 0, idx;
        unsigned int part_size;
-       u8 hc_erase_grp_sz = 0, hc_wp_grp_sz = 0;
 
        BUG_ON(!card);
 
@@ -402,80 +491,16 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd)
                ext_csd[EXT_CSD_TRIM_MULT];
        card->ext_csd.raw_partition_support = ext_csd[EXT_CSD_PARTITION_SUPPORT];
        if (card->ext_csd.rev >= 4) {
-               /*
-                * Enhanced area feature support -- check whether the eMMC
-                * card has the Enhanced area enabled.  If so, export enhanced
-                * area offset and size to user by adding sysfs interface.
-                */
-               if ((ext_csd[EXT_CSD_PARTITION_SUPPORT] & 0x2) &&
-                   (ext_csd[EXT_CSD_PARTITION_ATTRIBUTE] & 0x1)) {
-                       hc_erase_grp_sz =
-                               ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE];
-                       hc_wp_grp_sz =
-                               ext_csd[EXT_CSD_HC_WP_GRP_SIZE];
+               if (ext_csd[EXT_CSD_PARTITION_SETTING_COMPLETED] &
+                   EXT_CSD_PART_SETTING_COMPLETED)
+                       card->ext_csd.partition_setting_completed = 1;
+               else
+                       card->ext_csd.partition_setting_completed = 0;
 
-                       card->ext_csd.enhanced_area_en = 1;
-                       /*
-                        * calculate the enhanced data area offset, in bytes
-                        */
-                       card->ext_csd.enhanced_area_offset =
-                               (ext_csd[139] << 24) + (ext_csd[138] << 16) +
-                               (ext_csd[137] << 8) + ext_csd[136];
-                       if (mmc_card_blockaddr(card))
-                               card->ext_csd.enhanced_area_offset <<= 9;
-                       /*
-                        * calculate the enhanced data area size, in kilobytes
-                        */
-                       card->ext_csd.enhanced_area_size =
-                               (ext_csd[142] << 16) + (ext_csd[141] << 8) +
-                               ext_csd[140];
-                       card->ext_csd.enhanced_area_size *=
-                               (size_t)(hc_erase_grp_sz * hc_wp_grp_sz);
-                       card->ext_csd.enhanced_area_size <<= 9;
-               } else {
-                       /*
-                        * If the enhanced area is not enabled, disable these
-                        * device attributes.
-                        */
-                       card->ext_csd.enhanced_area_offset = -EINVAL;
-                       card->ext_csd.enhanced_area_size = -EINVAL;
-               }
+               mmc_manage_enhanced_area(card, ext_csd);
 
-               /*
-                * General purpose partition feature support --
-                * If ext_csd has the size of general purpose partitions,
-                * set size, part_cfg, partition name in mmc_part.
-                */
-               if (ext_csd[EXT_CSD_PARTITION_SUPPORT] &
-                       EXT_CSD_PART_SUPPORT_PART_EN) {
-                       if (card->ext_csd.enhanced_area_en != 1) {
-                               hc_erase_grp_sz =
-                                       ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE];
-                               hc_wp_grp_sz =
-                                       ext_csd[EXT_CSD_HC_WP_GRP_SIZE];
-
-                               card->ext_csd.enhanced_area_en = 1;
-                       }
+               mmc_manage_gp_partitions(card, ext_csd);
 
-                       for (idx = 0; idx < MMC_NUM_GP_PARTITION; idx++) {
-                               if (!ext_csd[EXT_CSD_GP_SIZE_MULT + idx * 3] &&
-                               !ext_csd[EXT_CSD_GP_SIZE_MULT + idx * 3 + 1] &&
-                               !ext_csd[EXT_CSD_GP_SIZE_MULT + idx * 3 + 2])
-                                       continue;
-                               part_size =
-                               (ext_csd[EXT_CSD_GP_SIZE_MULT + idx * 3 + 2]
-                                       << 16) +
-                               (ext_csd[EXT_CSD_GP_SIZE_MULT + idx * 3 + 1]
-                                       << 8) +
-                               ext_csd[EXT_CSD_GP_SIZE_MULT + idx * 3];
-                               part_size *= (size_t)(hc_erase_grp_sz *
-                                       hc_wp_grp_sz);
-                               mmc_part_add(card, part_size << 19,
-                                       EXT_CSD_PART_CONFIG_ACC_GP0 + idx,
-                                       "gp%d", idx, false,
-                                       MMC_BLK_DATA_AREA_GP);
-                       }
-               }
                card->ext_csd.sec_trim_mult =
                        ext_csd[EXT_CSD_SEC_TRIM_MULT];
                card->ext_csd.sec_erase_mult =
@@ -789,8 +814,8 @@ static int __mmc_select_powerclass(struct mmc_card *card,
                                ext_csd->raw_pwr_cl_200_360;
                break;
        default:
-               pr_warning("%s: Voltage range not supported "
-                          "for power class.\n", mmc_hostname(host));
+               pr_warn("%s: Voltage range not supported for power class\n",
+                       mmc_hostname(host));
                return -EINVAL;
        }
 
@@ -987,19 +1012,35 @@ static int mmc_select_hs_ddr(struct mmc_card *card)
         * 1.8V vccq at 3.3V core voltage (vcc) is not required
         * in the JEDEC spec for DDR.
         *
-        * Do not force change in vccq since we are obviously
-        * working and no change to vccq is needed.
+        * Even (e)MMC card can support 3.3v to 1.2v vccq, but not all
+        * host controller can support this, like some of the SDHCI
+        * controller which connect to an eMMC device. Some of these
+        * host controller still needs to use 1.8v vccq for supporting
+        * DDR mode.
+        *
+        * So the sequence will be:
+        * if (host and device can both support 1.2v IO)
+        *      use 1.2v IO;
+        * else if (host and device can both support 1.8v IO)
+        *      use 1.8v IO;
+        * so if host and device can only support 3.3v IO, this is the
+        * last choice.
         *
         * WARNING: eMMC rules are NOT the same as SD DDR
         */
-       if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_DDR_1_2V) {
-               err = __mmc_set_signal_voltage(host,
-                               MMC_SIGNAL_VOLTAGE_120);
-               if (err)
-                       return err;
-       }
+       err = -EINVAL;
+       if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_DDR_1_2V)
+               err = __mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_120);
+
+       if (err && (card->mmc_avail_type & EXT_CSD_CARD_TYPE_DDR_1_8V))
+               err = __mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180);
 
-       mmc_set_timing(host, MMC_TIMING_MMC_DDR52);
+       /* make sure vccq is 3.3v after switching disaster */
+       if (err)
+               err = __mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_330);
+
+       if (!err)
+               mmc_set_timing(host, MMC_TIMING_MMC_DDR52);
 
        return err;
 }
@@ -1134,6 +1175,38 @@ bus_speed:
        return err;
 }
 
+const u8 tuning_blk_pattern_4bit[MMC_TUNING_BLK_PATTERN_4BIT_SIZE] = {
+       0xff, 0x0f, 0xff, 0x00, 0xff, 0xcc, 0xc3, 0xcc,
+       0xc3, 0x3c, 0xcc, 0xff, 0xfe, 0xff, 0xfe, 0xef,
+       0xff, 0xdf, 0xff, 0xdd, 0xff, 0xfb, 0xff, 0xfb,
+       0xbf, 0xff, 0x7f, 0xff, 0x77, 0xf7, 0xbd, 0xef,
+       0xff, 0xf0, 0xff, 0xf0, 0x0f, 0xfc, 0xcc, 0x3c,
+       0xcc, 0x33, 0xcc, 0xcf, 0xff, 0xef, 0xff, 0xee,
+       0xff, 0xfd, 0xff, 0xfd, 0xdf, 0xff, 0xbf, 0xff,
+       0xbb, 0xff, 0xf7, 0xff, 0xf7, 0x7f, 0x7b, 0xde,
+};
+EXPORT_SYMBOL(tuning_blk_pattern_4bit);
+
+const u8 tuning_blk_pattern_8bit[MMC_TUNING_BLK_PATTERN_8BIT_SIZE] = {
+       0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00,
+       0xff, 0xff, 0xcc, 0xcc, 0xcc, 0x33, 0xcc, 0xcc,
+       0xcc, 0x33, 0x33, 0xcc, 0xcc, 0xcc, 0xff, 0xff,
+       0xff, 0xee, 0xff, 0xff, 0xff, 0xee, 0xee, 0xff,
+       0xff, 0xff, 0xdd, 0xff, 0xff, 0xff, 0xdd, 0xdd,
+       0xff, 0xff, 0xff, 0xbb, 0xff, 0xff, 0xff, 0xbb,
+       0xbb, 0xff, 0xff, 0xff, 0x77, 0xff, 0xff, 0xff,
+       0x77, 0x77, 0xff, 0x77, 0xbb, 0xdd, 0xee, 0xff,
+       0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
+       0x00, 0xff, 0xff, 0xcc, 0xcc, 0xcc, 0x33, 0xcc,
+       0xcc, 0xcc, 0x33, 0x33, 0xcc, 0xcc, 0xcc, 0xff,
+       0xff, 0xff, 0xee, 0xff, 0xff, 0xff, 0xee, 0xee,
+       0xff, 0xff, 0xff, 0xdd, 0xff, 0xff, 0xff, 0xdd,
+       0xdd, 0xff, 0xff, 0xff, 0xbb, 0xff, 0xff, 0xff,
+       0xbb, 0xbb, 0xff, 0xff, 0xff, 0x77, 0xff, 0xff,
+       0xff, 0x77, 0x77, 0xff, 0x77, 0xbb, 0xdd, 0xee,
+};
+EXPORT_SYMBOL(tuning_blk_pattern_8bit);
+
 /*
  * Execute tuning sequence to seek the proper bus operating
  * conditions for HS200 and HS400, which sends CMD21 to the device.
@@ -1271,6 +1344,13 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
                        goto free_card;
        }
 
+       /*
+        * handling only for cards supporting DSR and hosts requesting
+        * DSR configuration
+        */
+       if (card->csd.dsr_imp && host->dsr_req)
+               mmc_set_dsr(host);
+
        /*
         * Select card, as all following commands rely on that.
         */
@@ -1308,7 +1388,7 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
         * If enhanced_area_en is TRUE, host needs to enable ERASE_GRP_DEF
         * bit.  This bit will be lost every time after a reset or power off.
         */
-       if (card->ext_csd.enhanced_area_en ||
+       if (card->ext_csd.partition_setting_completed ||
            (card->ext_csd.rev >= 3 && (host->caps2 & MMC_CAP2_HC_ERASE_SZ))) {
                err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
                                 EXT_CSD_ERASE_GROUP_DEF, 1,
@@ -1408,8 +1488,8 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
                if (err && err != -EBADMSG)
                        goto free_card;
                if (err) {
-                       pr_warning("%s: Enabling HPI failed\n",
-                                  mmc_hostname(card->host));
+                       pr_warn("%s: Enabling HPI failed\n",
+                               mmc_hostname(card->host));
                        err = 0;
                } else
                        card->ext_csd.hpi_en = 1;
@@ -1430,9 +1510,8 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
                 * Only if no error, cache is turned on successfully.
                 */
                if (err) {
-                       pr_warning("%s: Cache is supported, "
-                                       "but failed to turn on (%d)\n",
-                                       mmc_hostname(card->host), err);
+                       pr_warn("%s: Cache is supported, but failed to turn on (%d)\n",
+                               mmc_hostname(card->host), err);
                        card->ext_csd.cache_ctrl = 0;
                        err = 0;
                } else {
index f51b5ba3bbea99ce1f2b74e5b3c80a4b882b972c..7911e0510a1d6c2ed131e0fb74c913b2a9cc0162 100644 (file)
@@ -93,6 +93,26 @@ int mmc_deselect_cards(struct mmc_host *host)
        return _mmc_select_card(host, NULL);
 }
 
+/*
+ * Write the value specified in the device tree or board code into the optional
+ * 16 bit Driver Stage Register. This can be used to tune raise/fall times and
+ * drive strength of the DAT and CMD outputs. The actual meaning of a given
+ * value is hardware dependant.
+ * The presence of the DSR register can be determined from the CSD register,
+ * bit 76.
+ */
+int mmc_set_dsr(struct mmc_host *host)
+{
+       struct mmc_command cmd = {0};
+
+       cmd.opcode = MMC_SET_DSR;
+
+       cmd.arg = (host->dsr << 16) | 0xffff;
+       cmd.flags = MMC_RSP_NONE | MMC_CMD_AC;
+
+       return mmc_wait_for_cmd(host, &cmd, MMC_CMD_RETRIES);
+}
+
 int mmc_go_idle(struct mmc_host *host)
 {
        int err;
@@ -629,8 +649,8 @@ int mmc_send_hpi_cmd(struct mmc_card *card, u32 *status)
        int err;
 
        if (!card->ext_csd.hpi) {
-               pr_warning("%s: Card didn't support HPI command\n",
-                          mmc_hostname(card->host));
+               pr_warn("%s: Card didn't support HPI command\n",
+                       mmc_hostname(card->host));
                return -EINVAL;
        }
 
index 80ae9f4e0293a045ca8e4ebb89023e3c64e062da..390dac665b2a6246309415ca019840bee4661b07 100644 (file)
@@ -14,6 +14,7 @@
 
 int mmc_select_card(struct mmc_card *card);
 int mmc_deselect_cards(struct mmc_host *host);
+int mmc_set_dsr(struct mmc_host *host);
 int mmc_go_idle(struct mmc_host *host);
 int mmc_send_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr);
 int mmc_all_send_cid(struct mmc_host *host, u32 *cid);
index 0c44510bf717874808a0e1d20de68aa3cf2afda5..d90a6de7901d7514550b3c9ed64d383e528244ad 100644 (file)
@@ -127,6 +127,7 @@ static int mmc_decode_csd(struct mmc_card *card)
                csd->read_partial = UNSTUFF_BITS(resp, 79, 1);
                csd->write_misalign = UNSTUFF_BITS(resp, 78, 1);
                csd->read_misalign = UNSTUFF_BITS(resp, 77, 1);
+               csd->dsr_imp = UNSTUFF_BITS(resp, 76, 1);
                csd->r2w_factor = UNSTUFF_BITS(resp, 26, 3);
                csd->write_blkbits = UNSTUFF_BITS(resp, 22, 4);
                csd->write_partial = UNSTUFF_BITS(resp, 21, 1);
@@ -228,8 +229,8 @@ static int mmc_read_ssr(struct mmc_card *card)
        u32 *ssr;
 
        if (!(card->csd.cmdclass & CCC_APP_SPEC)) {
-               pr_warning("%s: card lacks mandatory SD Status "
-                       "function.\n", mmc_hostname(card->host));
+               pr_warn("%s: card lacks mandatory SD Status function\n",
+                       mmc_hostname(card->host));
                return 0;
        }
 
@@ -239,8 +240,8 @@ static int mmc_read_ssr(struct mmc_card *card)
 
        err = mmc_app_sd_status(card, ssr);
        if (err) {
-               pr_warning("%s: problem reading SD Status "
-                       "register.\n", mmc_hostname(card->host));
+               pr_warn("%s: problem reading SD Status register\n",
+                       mmc_hostname(card->host));
                err = 0;
                goto out;
        }
@@ -264,8 +265,8 @@ static int mmc_read_ssr(struct mmc_card *card)
                                card->ssr.erase_offset = eo * 1000;
                        }
                } else {
-                       pr_warning("%s: SD Status: Invalid Allocation Unit size.\n",
-                                  mmc_hostname(card->host));
+                       pr_warn("%s: SD Status: Invalid Allocation Unit size\n",
+                               mmc_hostname(card->host));
                }
        }
 out:
@@ -285,8 +286,7 @@ static int mmc_read_switch(struct mmc_card *card)
                return 0;
 
        if (!(card->csd.cmdclass & CCC_SWITCH)) {
-               pr_warning("%s: card lacks mandatory switch "
-                       "function, performance might suffer.\n",
+               pr_warn("%s: card lacks mandatory switch function, performance might suffer\n",
                        mmc_hostname(card->host));
                return 0;
        }
@@ -315,7 +315,7 @@ static int mmc_read_switch(struct mmc_card *card)
                if (err != -EINVAL && err != -ENOSYS && err != -EFAULT)
                        goto out;
 
-               pr_warning("%s: problem reading Bus Speed modes.\n",
+               pr_warn("%s: problem reading Bus Speed modes\n",
                        mmc_hostname(card->host));
                err = 0;
 
@@ -371,8 +371,7 @@ int mmc_sd_switch_hs(struct mmc_card *card)
                goto out;
 
        if ((status[16] & 0xF) != 1) {
-               pr_warning("%s: Problem switching card "
-                       "into high-speed mode!\n",
+               pr_warn("%s: Problem switching card into high-speed mode!\n",
                        mmc_hostname(card->host));
                err = 0;
        } else {
@@ -439,7 +438,7 @@ static int sd_select_driver_type(struct mmc_card *card, u8 *status)
                return err;
 
        if ((status[15] & 0xF) != drive_strength) {
-               pr_warning("%s: Problem setting drive strength!\n",
+               pr_warn("%s: Problem setting drive strength!\n",
                        mmc_hostname(card->host));
                return 0;
        }
@@ -517,7 +516,7 @@ static int sd_set_bus_speed_mode(struct mmc_card *card, u8 *status)
                return err;
 
        if ((status[16] & 0xF) != card->sd_bus_speed)
-               pr_warning("%s: Problem setting bus speed mode!\n",
+               pr_warn("%s: Problem setting bus speed mode!\n",
                        mmc_hostname(card->host));
        else {
                mmc_set_timing(card->host, timing);
@@ -597,7 +596,7 @@ static int sd_set_current_limit(struct mmc_card *card, u8 *status)
                        return err;
 
                if (((status[15] >> 4) & 0x0F) != current_limit)
-                       pr_warning("%s: Problem setting current limit!\n",
+                       pr_warn("%s: Problem setting current limit!\n",
                                mmc_hostname(card->host));
 
        }
@@ -726,8 +725,7 @@ int mmc_sd_get_cid(struct mmc_host *host, u32 ocr, u32 *cid, u32 *rocr)
 try_again:
        if (!retries) {
                ocr &= ~SD_OCR_S18R;
-               pr_warning("%s: Skipping voltage switch\n",
-                       mmc_hostname(host));
+               pr_warn("%s: Skipping voltage switch\n", mmc_hostname(host));
        }
 
        /*
@@ -871,9 +869,7 @@ int mmc_sd_setup_card(struct mmc_host *host, struct mmc_card *card,
                }
 
                if (ro < 0) {
-                       pr_warning("%s: host does not "
-                               "support reading read-only "
-                               "switch. assuming write-enable.\n",
+                       pr_warn("%s: host does not support reading read-only switch, assuming write-enable\n",
                                mmc_hostname(host));
                } else if (ro > 0) {
                        mmc_card_set_readonly(card);
@@ -953,6 +949,13 @@ static int mmc_sd_init_card(struct mmc_host *host, u32 ocr,
                mmc_decode_cid(card);
        }
 
+       /*
+        * handling only for cards supporting DSR and hosts requesting
+        * DSR configuration
+        */
+       if (card->csd.dsr_imp && host->dsr_req)
+               mmc_set_dsr(host);
+
        /*
         * Select card, as all following commands rely on that.
         */
index e636d9e99e4ae7faa698bb77a33285b301a33523..2439e717655b132654fb67e9509af8d834940ee1 100644 (file)
@@ -216,8 +216,8 @@ static int sdio_enable_wide(struct mmc_card *card)
                return ret;
 
        if ((ctrl & SDIO_BUS_WIDTH_MASK) == SDIO_BUS_WIDTH_RESERVED)
-               pr_warning("%s: SDIO_CCCR_IF is invalid: 0x%02x\n",
-                          mmc_hostname(card->host), ctrl);
+               pr_warn("%s: SDIO_CCCR_IF is invalid: 0x%02x\n",
+                       mmc_hostname(card->host), ctrl);
 
        /* set as 4-bit bus width */
        ctrl &= ~SDIO_BUS_WIDTH_MASK;
@@ -605,8 +605,7 @@ static int mmc_sdio_init_card(struct mmc_host *host, u32 ocr,
 
 try_again:
        if (!retries) {
-               pr_warning("%s: Skipping voltage switch\n",
-                               mmc_hostname(host));
+               pr_warn("%s: Skipping voltage switch\n", mmc_hostname(host));
                ocr &= ~R4_18V_PRESENT;
        }
 
@@ -992,8 +991,16 @@ static int mmc_sdio_resume(struct mmc_host *host)
                }
        }
 
-       if (!err && host->sdio_irqs)
-               wake_up_process(host->sdio_irq_thread);
+       if (!err && host->sdio_irqs) {
+               if (!(host->caps2 & MMC_CAP2_SDIO_IRQ_NOTHREAD)) {
+                       wake_up_process(host->sdio_irq_thread);
+               } else if (host->caps & MMC_CAP_SDIO_IRQ) {
+                       mmc_host_clk_hold(host);
+                       host->ops->enable_sdio_irq(host, 1);
+                       mmc_host_clk_release(host);
+               }
+       }
+
        mmc_release_host(host);
 
        host->pm_flags &= ~MMC_PM_KEEP_POWER;
index 65cf7a7e05eaf23ef73bf7ea8889b35c0f367597..6da97b170563a8f6bebfba78779d8cb20ffa78bb 100644 (file)
@@ -178,8 +178,8 @@ static int sdio_bus_remove(struct device *dev)
        drv->remove(func);
 
        if (func->irq_handler) {
-               pr_warning("WARNING: driver %s did not remove "
-                       "its interrupt handler!\n", drv->name);
+               pr_warn("WARNING: driver %s did not remove its interrupt handler!\n",
+                       drv->name);
                sdio_claim_host(func);
                sdio_release_irq(func);
                sdio_release_host(func);
index 5cc13c8d35bbf3b2c60c8bc68054e05bec0e62fc..09cc67d028f07b76165414625829bdd22f56b7f0 100644 (file)
@@ -69,16 +69,15 @@ static int process_sdio_pending_irqs(struct mmc_host *host)
                if (pending & (1 << i)) {
                        func = card->sdio_func[i - 1];
                        if (!func) {
-                               pr_warning("%s: pending IRQ for "
-                                       "non-existent function\n",
+                               pr_warn("%s: pending IRQ for non-existent function\n",
                                        mmc_card_id(card));
                                ret = -EINVAL;
                        } else if (func->irq_handler) {
                                func->irq_handler(func);
                                count++;
                        } else {
-                               pr_warning("%s: pending IRQ with no handler\n",
-                                      sdio_func_id(func));
+                               pr_warn("%s: pending IRQ with no handler\n",
+                                       sdio_func_id(func));
                                ret = -EINVAL;
                        }
                }
@@ -208,7 +207,7 @@ static int sdio_card_irq_get(struct mmc_card *card)
                                host->sdio_irqs--;
                                return err;
                        }
-               } else {
+               } else if (host->caps & MMC_CAP_SDIO_IRQ) {
                        mmc_host_clk_hold(host);
                        host->ops->enable_sdio_irq(host, 1);
                        mmc_host_clk_release(host);
@@ -229,7 +228,7 @@ static int sdio_card_irq_put(struct mmc_card *card)
                if (!(host->caps2 & MMC_CAP2_SDIO_IRQ_NOTHREAD)) {
                        atomic_set(&host->sdio_irq_thread_abort, 1);
                        kthread_stop(host->sdio_irq_thread);
-               } else {
+               } else if (host->caps & MMC_CAP_SDIO_IRQ) {
                        mmc_host_clk_hold(host);
                        host->ops->enable_sdio_irq(host, 0);
                        mmc_host_clk_release(host);
index 5f89cb83d5f00008aa3c98f550f9ff962c0306c0..69bbf2adb329db5570b0c0b698152110fb2ccee4 100644 (file)
@@ -221,8 +221,6 @@ int mmc_gpio_request_cd(struct mmc_host *host, unsigned int gpio,
        ctx->override_cd_active_level = true;
        ctx->cd_gpio = gpio_to_desc(gpio);
 
-       mmc_gpiod_request_cd_irq(host);
-
        return 0;
 }
 EXPORT_SYMBOL(mmc_gpio_request_cd);
@@ -283,6 +281,8 @@ EXPORT_SYMBOL(mmc_gpio_free_cd);
  * @idx: index of the GPIO to obtain in the consumer
  * @override_active_level: ignore %GPIO_ACTIVE_LOW flag
  * @debounce: debounce time in microseconds
+ * @gpio_invert: will return whether the GPIO line is inverted or not, set
+ * to NULL to ignore
  *
  * Use this function in place of mmc_gpio_request_cd() to use the GPIO
  * descriptor API.  Note that it is paired with mmc_gpiod_free_cd() not
@@ -293,7 +293,7 @@ EXPORT_SYMBOL(mmc_gpio_free_cd);
  */
 int mmc_gpiod_request_cd(struct mmc_host *host, const char *con_id,
                         unsigned int idx, bool override_active_level,
-                        unsigned int debounce)
+                        unsigned int debounce, bool *gpio_invert)
 {
        struct mmc_gpio *ctx;
        struct gpio_desc *desc;
@@ -308,20 +308,19 @@ int mmc_gpiod_request_cd(struct mmc_host *host, const char *con_id,
        if (!con_id)
                con_id = ctx->cd_label;
 
-       desc = devm_gpiod_get_index(host->parent, con_id, idx);
+       desc = devm_gpiod_get_index(host->parent, con_id, idx, GPIOD_IN);
        if (IS_ERR(desc))
                return PTR_ERR(desc);
 
-       ret = gpiod_direction_input(desc);
-       if (ret < 0)
-               return ret;
-
        if (debounce) {
                ret = gpiod_set_debounce(desc, debounce);
                if (ret < 0)
                        return ret;
        }
 
+       if (gpio_invert)
+               *gpio_invert = !gpiod_is_active_low(desc);
+
        ctx->override_cd_active_level = override_active_level;
        ctx->cd_gpio = desc;
 
@@ -329,6 +328,59 @@ int mmc_gpiod_request_cd(struct mmc_host *host, const char *con_id,
 }
 EXPORT_SYMBOL(mmc_gpiod_request_cd);
 
+/**
+ * mmc_gpiod_request_ro - request a gpio descriptor for write protection
+ * @host: mmc host
+ * @con_id: function within the GPIO consumer
+ * @idx: index of the GPIO to obtain in the consumer
+ * @override_active_level: ignore %GPIO_ACTIVE_LOW flag
+ * @debounce: debounce time in microseconds
+ * @gpio_invert: will return whether the GPIO line is inverted or not,
+ * set to NULL to ignore
+ *
+ * Use this function in place of mmc_gpio_request_ro() to use the GPIO
+ * descriptor API.  Note that it is paired with mmc_gpiod_free_ro() not
+ * mmc_gpio_free_ro().
+ *
+ * Returns zero on success, else an error.
+ */
+int mmc_gpiod_request_ro(struct mmc_host *host, const char *con_id,
+                        unsigned int idx, bool override_active_level,
+                        unsigned int debounce, bool *gpio_invert)
+{
+       struct mmc_gpio *ctx;
+       struct gpio_desc *desc;
+       int ret;
+
+       ret = mmc_gpio_alloc(host);
+       if (ret < 0)
+               return ret;
+
+       ctx = host->slot.handler_priv;
+
+       if (!con_id)
+               con_id = ctx->ro_label;
+
+       desc = devm_gpiod_get_index(host->parent, con_id, idx, GPIOD_IN);
+       if (IS_ERR(desc))
+               return PTR_ERR(desc);
+
+       if (debounce) {
+               ret = gpiod_set_debounce(desc, debounce);
+               if (ret < 0)
+                       return ret;
+       }
+
+       if (gpio_invert)
+               *gpio_invert = !gpiod_is_active_low(desc);
+
+       ctx->override_ro_active_level = override_active_level;
+       ctx->ro_gpio = desc;
+
+       return 0;
+}
+EXPORT_SYMBOL(mmc_gpiod_request_ro);
+
 /**
  * mmc_gpiod_free_cd - free the card-detection gpio descriptor
  * @host: mmc host
@@ -348,7 +400,7 @@ void mmc_gpiod_free_cd(struct mmc_host *host)
                host->slot.cd_irq = -EINVAL;
        }
 
-       devm_gpiod_put(&host->class_dev, ctx->cd_gpio);
+       devm_gpiod_put(host->parent, ctx->cd_gpio);
 
        ctx->cd_gpio = NULL;
 }
index 45113582246427eae3f9c6d893cdd6e305a1631b..13860656104b5f58df865ee74501750a3d045c7c 100644 (file)
@@ -14,6 +14,17 @@ config MMC_ARMMMCI
 
          If unsure, say N.
 
+config MMC_QCOM_DML
+       tristate "Qualcomm Data Mover for SD Card Controller"
+       depends on MMC_ARMMMCI && QCOM_BAM_DMA
+       default y
+       help
+         This selects the Qualcomm Data Mover lite/local on SD Card controller.
+         This option will enable the dma to work correctly, if you are using
+         Qcom SOCs and MMC, you would probably need this option to get DMA working.
+
+         if unsure, say N.
+
 config MMC_PXA
        tristate "Intel PXA25x/26x/27x Multimedia Card Interface support"
        depends on ARCH_PXA
@@ -568,7 +579,8 @@ config SDH_BFIN_MISSING_CMD_PULLUP_WORKAROUND
 
 config MMC_DW
        tristate "Synopsys DesignWare Memory Card Interface"
-       depends on ARC || ARM
+       depends on HAS_DMA
+       depends on ARC || ARM || MIPS || COMPILE_TEST
        help
          This selects support for the Synopsys DesignWare Mobile Storage IP
          block, this provides host support for SD and MMC interfaces, in both
@@ -626,6 +638,15 @@ config MMC_DW_PCI
 
          If unsure, say N.
 
+config MMC_DW_ROCKCHIP
+       tristate "Rockchip specific extensions for Synopsys DW Memory Card Interface"
+       depends on MMC_DW && ARCH_ROCKCHIP
+       select MMC_DW_PLTFM
+       help
+         This selects support for Rockchip SoC specific extensions to the
+         Synopsys DesignWare Memory Card Interface driver. Select this option
+         for platforms based on RK3066, RK3188 and RK3288 SoC's.
+
 config MMC_SH_MMCIF
        tristate "SuperH Internal MMCIF support"
        depends on MMC_BLOCK && HAS_DMA
index f211eede8db58d48887d5619d96c4cca6bdbdbab..b09ecfb88269da9f3d1b5796a2b84137e3e10dd5 100644 (file)
@@ -3,6 +3,7 @@
 #
 
 obj-$(CONFIG_MMC_ARMMMCI)      += mmci.o
+obj-$(CONFIG_MMC_QCOM_DML)     += mmci_qcom_dml.o
 obj-$(CONFIG_MMC_PXA)          += pxamci.o
 obj-$(CONFIG_MMC_MXC)          += mxcmmc.o
 obj-$(CONFIG_MMC_MXS)          += mxs-mmc.o
@@ -45,6 +46,7 @@ obj-$(CONFIG_MMC_DW_PLTFM)    += dw_mmc-pltfm.o
 obj-$(CONFIG_MMC_DW_EXYNOS)    += dw_mmc-exynos.o
 obj-$(CONFIG_MMC_DW_K3)                += dw_mmc-k3.o
 obj-$(CONFIG_MMC_DW_PCI)       += dw_mmc-pci.o
+obj-$(CONFIG_MMC_DW_ROCKCHIP)  += dw_mmc-rockchip.o
 obj-$(CONFIG_MMC_SH_MMCIF)     += sh_mmcif.o
 obj-$(CONFIG_MMC_JZ4740)       += jz4740_mmc.o
 obj-$(CONFIG_MMC_VUB300)       += vub300.o
index bb585d9409014e8bead8879acf5f7145e9e5790c..77250d4b197923124f9389b811623ea3a6359c28 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/gpio.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
+#include <linux/io.h>
 #include <linux/ioport.h>
 #include <linux/module.h>
 #include <linux/of.h>
@@ -2195,7 +2196,8 @@ static int __init atmci_init_slot(struct atmel_mci *host,
        /* Assume card is present initially */
        set_bit(ATMCI_CARD_PRESENT, &slot->flags);
        if (gpio_is_valid(slot->detect_pin)) {
-               if (gpio_request(slot->detect_pin, "mmc_detect")) {
+               if (devm_gpio_request(&host->pdev->dev, slot->detect_pin,
+                                     "mmc_detect")) {
                        dev_dbg(&mmc->class_dev, "no detect pin available\n");
                        slot->detect_pin = -EBUSY;
                } else if (gpio_get_value(slot->detect_pin) ^
@@ -2208,7 +2210,8 @@ static int __init atmci_init_slot(struct atmel_mci *host,
                mmc->caps |= MMC_CAP_NEEDS_POLL;
 
        if (gpio_is_valid(slot->wp_pin)) {
-               if (gpio_request(slot->wp_pin, "mmc_wp")) {
+               if (devm_gpio_request(&host->pdev->dev, slot->wp_pin,
+                                     "mmc_wp")) {
                        dev_dbg(&mmc->class_dev, "no WP pin available\n");
                        slot->wp_pin = -EBUSY;
                }
@@ -2232,7 +2235,6 @@ static int __init atmci_init_slot(struct atmel_mci *host,
                        dev_dbg(&mmc->class_dev,
                                "could not request IRQ %d for detect pin\n",
                                gpio_to_irq(slot->detect_pin));
-                       gpio_free(slot->detect_pin);
                        slot->detect_pin = -EBUSY;
                }
        }
@@ -2242,7 +2244,7 @@ static int __init atmci_init_slot(struct atmel_mci *host,
        return 0;
 }
 
-static void __exit atmci_cleanup_slot(struct atmel_mci_slot *slot,
+static void atmci_cleanup_slot(struct atmel_mci_slot *slot,
                unsigned int id)
 {
        /* Debugfs stuff is cleaned up by mmc core */
@@ -2257,10 +2259,7 @@ static void __exit atmci_cleanup_slot(struct atmel_mci_slot *slot,
 
                free_irq(gpio_to_irq(pin), slot);
                del_timer_sync(&slot->detect_timer);
-               gpio_free(pin);
        }
-       if (gpio_is_valid(slot->wp_pin))
-               gpio_free(slot->wp_pin);
 
        slot->host->slot[id] = NULL;
        mmc_free_host(slot->mmc);
@@ -2344,6 +2343,7 @@ static void __init atmci_get_cap(struct atmel_mci *host)
 
        /* keep only major version number */
        switch (version & 0xf00) {
+       case 0x600:
        case 0x500:
                host->caps.has_odd_clk_div = 1;
        case 0x400:
@@ -2377,7 +2377,7 @@ static int __init atmci_probe(struct platform_device *pdev)
        struct resource                 *regs;
        unsigned int                    nr_slots;
        int                             irq;
-       int                             ret;
+       int                             ret, i;
 
        regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        if (!regs)
@@ -2395,7 +2395,7 @@ static int __init atmci_probe(struct platform_device *pdev)
        if (irq < 0)
                return irq;
 
-       host = kzalloc(sizeof(struct atmel_mci), GFP_KERNEL);
+       host = devm_kzalloc(&pdev->dev, sizeof(*host), GFP_KERNEL);
        if (!host)
                return -ENOMEM;
 
@@ -2403,20 +2403,18 @@ static int __init atmci_probe(struct platform_device *pdev)
        spin_lock_init(&host->lock);
        INIT_LIST_HEAD(&host->queue);
 
-       host->mck = clk_get(&pdev->dev, "mci_clk");
-       if (IS_ERR(host->mck)) {
-               ret = PTR_ERR(host->mck);
-               goto err_clk_get;
-       }
+       host->mck = devm_clk_get(&pdev->dev, "mci_clk");
+       if (IS_ERR(host->mck))
+               return PTR_ERR(host->mck);
 
-       ret = -ENOMEM;
-       host->regs = ioremap(regs->start, resource_size(regs));
+       host->regs = devm_ioremap(&pdev->dev, regs->start, resource_size(regs));
        if (!host->regs)
-               goto err_ioremap;
+               return -ENOMEM;
 
        ret = clk_prepare_enable(host->mck);
        if (ret)
-               goto err_request_irq;
+               return ret;
+
        atmci_writel(host, ATMCI_CR, ATMCI_CR_SWRST);
        host->bus_hz = clk_get_rate(host->mck);
        clk_disable_unprepare(host->mck);
@@ -2427,7 +2425,7 @@ static int __init atmci_probe(struct platform_device *pdev)
 
        ret = request_irq(irq, atmci_interrupt, 0, dev_name(&pdev->dev), host);
        if (ret)
-               goto err_request_irq;
+               return ret;
 
        /* Get MCI capabilities and set operations according to it */
        atmci_get_cap(host);
@@ -2485,7 +2483,7 @@ static int __init atmci_probe(struct platform_device *pdev)
                if (!host->buffer) {
                        ret = -ENOMEM;
                        dev_err(&pdev->dev, "buffer allocation failed\n");
-                       goto err_init_slot;
+                       goto err_dma_alloc;
                }
        }
 
@@ -2495,16 +2493,16 @@ static int __init atmci_probe(struct platform_device *pdev)
 
        return 0;
 
+err_dma_alloc:
+       for (i = 0; i < ATMCI_MAX_NR_SLOTS; i++) {
+               if (host->slot[i])
+                       atmci_cleanup_slot(host->slot[i], i);
+       }
 err_init_slot:
+       del_timer_sync(&host->timer);
        if (host->dma.chan)
                dma_release_channel(host->dma.chan);
        free_irq(irq, host);
-err_request_irq:
-       iounmap(host->regs);
-err_ioremap:
-       clk_put(host->mck);
-err_clk_get:
-       kfree(host);
        return ret;
 }
 
@@ -2528,14 +2526,11 @@ static int __exit atmci_remove(struct platform_device *pdev)
        atmci_readl(host, ATMCI_SR);
        clk_disable_unprepare(host->mck);
 
+       del_timer_sync(&host->timer);
        if (host->dma.chan)
                dma_release_channel(host->dma.chan);
 
        free_irq(platform_get_irq(pdev, 0), host);
-       iounmap(host->regs);
-
-       clk_put(host->mck);
-       kfree(host);
 
        return 0;
 }
index 9c9f6af29251c6f6be68b533f22b29584104c889..725f6a6fd89b425b83cffb9e093d55d819a5078f 100644 (file)
@@ -1028,9 +1028,12 @@ static int au1xmmc_probe(struct platform_device *pdev)
        host->clk = clk_get(&pdev->dev, ALCHEMY_PERIPH_CLK);
        if (IS_ERR(host->clk)) {
                dev_err(&pdev->dev, "cannot find clock\n");
+               ret = PTR_ERR(host->clk);
                goto out_irq;
        }
-       if (clk_prepare_enable(host->clk)) {
+
+       ret = clk_prepare_enable(host->clk);
+       if (ret) {
                dev_err(&pdev->dev, "cannot enable clock\n");
                goto out_clk;
        }
index 6ada1b36685b0b20f471cfdd1318590046464c4d..4c69fbd2981190734d4ef1ff9861df73c1ab5806 100644 (file)
@@ -95,9 +95,6 @@ static int dw_mci_pci_resume(struct device *dev)
 
        return dw_mci_resume(host);
 }
-#else
-#define dw_mci_pci_suspend     NULL
-#define dw_mci_pci_resume      NULL
 #endif /* CONFIG_PM_SLEEP */
 
 static SIMPLE_DEV_PM_OPS(dw_mci_pci_pmops, dw_mci_pci_suspend, dw_mci_pci_resume);
index d4a47a9f55848cbc40f383c3378a9c20304667d6..8b6572162ed960ed9d8c0ead021dda6a574c664e 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/mmc/mmc.h>
 #include <linux/mmc/dw_mmc.h>
 #include <linux/of.h>
+#include <linux/clk.h>
 
 #include "dw_mmc.h"
 #include "dw_mmc-pltfm.h"
@@ -30,10 +31,6 @@ static void dw_mci_pltfm_prepare_command(struct dw_mci *host, u32 *cmdr)
        *cmdr |= SDMMC_CMD_USE_HOLD_REG;
 }
 
-static const struct dw_mci_drv_data rockchip_drv_data = {
-       .prepare_command        = dw_mci_pltfm_prepare_command,
-};
-
 static const struct dw_mci_drv_data socfpga_drv_data = {
        .prepare_command        = dw_mci_pltfm_prepare_command,
 };
@@ -84,9 +81,6 @@ static int dw_mci_pltfm_resume(struct device *dev)
 
        return dw_mci_resume(host);
 }
-#else
-#define dw_mci_pltfm_suspend   NULL
-#define dw_mci_pltfm_resume    NULL
 #endif /* CONFIG_PM_SLEEP */
 
 SIMPLE_DEV_PM_OPS(dw_mci_pltfm_pmops, dw_mci_pltfm_suspend, dw_mci_pltfm_resume);
@@ -94,8 +88,6 @@ EXPORT_SYMBOL_GPL(dw_mci_pltfm_pmops);
 
 static const struct of_device_id dw_mci_pltfm_match[] = {
        { .compatible = "snps,dw-mshc", },
-       { .compatible = "rockchip,rk2928-dw-mshc",
-               .data = &rockchip_drv_data },
        { .compatible = "altr,socfpga-dw-mshc",
                .data = &socfpga_drv_data },
        {},
diff --git a/drivers/mmc/host/dw_mmc-rockchip.c b/drivers/mmc/host/dw_mmc-rockchip.c
new file mode 100644 (file)
index 0000000..f0c2cb1
--- /dev/null
@@ -0,0 +1,136 @@
+/*
+ * Copyright (c) 2014, Fuzhou Rockchip Electronics Co., Ltd
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/mmc/host.h>
+#include <linux/mmc/dw_mmc.h>
+#include <linux/of_address.h>
+
+#include "dw_mmc.h"
+#include "dw_mmc-pltfm.h"
+
+#define RK3288_CLKGEN_DIV       2
+
+static void dw_mci_rockchip_prepare_command(struct dw_mci *host, u32 *cmdr)
+{
+       *cmdr |= SDMMC_CMD_USE_HOLD_REG;
+}
+
+static int dw_mci_rk3288_setup_clock(struct dw_mci *host)
+{
+       host->bus_hz /= RK3288_CLKGEN_DIV;
+
+       return 0;
+}
+
+static void dw_mci_rk3288_set_ios(struct dw_mci *host, struct mmc_ios *ios)
+{
+       int ret;
+       unsigned int cclkin;
+       u32 bus_hz;
+
+       /*
+        * cclkin: source clock of mmc controller
+        * bus_hz: card interface clock generated by CLKGEN
+        * bus_hz = cclkin / RK3288_CLKGEN_DIV
+        * ios->clock = (div == 0) ? bus_hz : (bus_hz / (2 * div))
+        *
+        * Note: div can only be 0 or 1
+        *       if DDR50 8bit mode(only emmc work in 8bit mode),
+        *       div must be set 1
+        */
+       if (ios->bus_width == MMC_BUS_WIDTH_8 &&
+           ios->timing == MMC_TIMING_MMC_DDR52)
+               cclkin = 2 * ios->clock * RK3288_CLKGEN_DIV;
+       else
+               cclkin = ios->clock * RK3288_CLKGEN_DIV;
+
+       ret = clk_set_rate(host->ciu_clk, cclkin);
+       if (ret)
+               dev_warn(host->dev, "failed to set rate %uHz\n", ios->clock);
+
+       bus_hz = clk_get_rate(host->ciu_clk) / RK3288_CLKGEN_DIV;
+       if (bus_hz != host->bus_hz) {
+               host->bus_hz = bus_hz;
+               /* force dw_mci_setup_bus() */
+               host->current_speed = 0;
+       }
+}
+
+static const struct dw_mci_drv_data rk2928_drv_data = {
+       .prepare_command        = dw_mci_rockchip_prepare_command,
+};
+
+static const struct dw_mci_drv_data rk3288_drv_data = {
+       .prepare_command        = dw_mci_rockchip_prepare_command,
+       .set_ios                = dw_mci_rk3288_set_ios,
+       .setup_clock    = dw_mci_rk3288_setup_clock,
+};
+
+static const struct of_device_id dw_mci_rockchip_match[] = {
+       { .compatible = "rockchip,rk2928-dw-mshc",
+               .data = &rk2928_drv_data },
+       { .compatible = "rockchip,rk3288-dw-mshc",
+               .data = &rk3288_drv_data },
+       {},
+};
+MODULE_DEVICE_TABLE(of, dw_mci_rockchip_match);
+
+static int dw_mci_rockchip_probe(struct platform_device *pdev)
+{
+       const struct dw_mci_drv_data *drv_data;
+       const struct of_device_id *match;
+
+       if (!pdev->dev.of_node)
+               return -ENODEV;
+
+       match = of_match_node(dw_mci_rockchip_match, pdev->dev.of_node);
+       drv_data = match->data;
+
+       return dw_mci_pltfm_register(pdev, drv_data);
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int dw_mci_rockchip_suspend(struct device *dev)
+{
+       struct dw_mci *host = dev_get_drvdata(dev);
+
+       return dw_mci_suspend(host);
+}
+
+static int dw_mci_rockchip_resume(struct device *dev)
+{
+       struct dw_mci *host = dev_get_drvdata(dev);
+
+       return dw_mci_resume(host);
+}
+#endif /* CONFIG_PM_SLEEP */
+
+static SIMPLE_DEV_PM_OPS(dw_mci_rockchip_pmops,
+                        dw_mci_rockchip_suspend,
+                        dw_mci_rockchip_resume);
+
+static struct platform_driver dw_mci_rockchip_pltfm_driver = {
+       .probe          = dw_mci_rockchip_probe,
+       .remove         = __exit_p(dw_mci_pltfm_remove),
+       .driver         = {
+               .name           = "dwmmc_rockchip",
+               .of_match_table = dw_mci_rockchip_match,
+               .pm             = &dw_mci_rockchip_pmops,
+       },
+};
+
+module_platform_driver(dw_mci_rockchip_pltfm_driver);
+
+MODULE_AUTHOR("Addy Ke <addy.ke@rock-chips.com>");
+MODULE_DESCRIPTION("Rockchip Specific DW-MSHC Driver Extension");
+MODULE_ALIAS("platform:dwmmc-rockchip");
+MODULE_LICENSE("GPL v2");
index 8f216edbdf080d0c51e3eedcf83a75a1886fc9e3..69f0cc68d5b2727412c3b430d0f5eaee99072941 100644 (file)
@@ -29,6 +29,7 @@
 #include <linux/irq.h>
 #include <linux/mmc/host.h>
 #include <linux/mmc/mmc.h>
+#include <linux/mmc/sd.h>
 #include <linux/mmc/sdio.h>
 #include <linux/mmc/dw_mmc.h>
 #include <linux/bitops.h>
@@ -81,36 +82,6 @@ struct idmac_desc {
 };
 #endif /* CONFIG_MMC_DW_IDMAC */
 
-static const u8 tuning_blk_pattern_4bit[] = {
-       0xff, 0x0f, 0xff, 0x00, 0xff, 0xcc, 0xc3, 0xcc,
-       0xc3, 0x3c, 0xcc, 0xff, 0xfe, 0xff, 0xfe, 0xef,
-       0xff, 0xdf, 0xff, 0xdd, 0xff, 0xfb, 0xff, 0xfb,
-       0xbf, 0xff, 0x7f, 0xff, 0x77, 0xf7, 0xbd, 0xef,
-       0xff, 0xf0, 0xff, 0xf0, 0x0f, 0xfc, 0xcc, 0x3c,
-       0xcc, 0x33, 0xcc, 0xcf, 0xff, 0xef, 0xff, 0xee,
-       0xff, 0xfd, 0xff, 0xfd, 0xdf, 0xff, 0xbf, 0xff,
-       0xbb, 0xff, 0xf7, 0xff, 0xf7, 0x7f, 0x7b, 0xde,
-};
-
-static const u8 tuning_blk_pattern_8bit[] = {
-       0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00,
-       0xff, 0xff, 0xcc, 0xcc, 0xcc, 0x33, 0xcc, 0xcc,
-       0xcc, 0x33, 0x33, 0xcc, 0xcc, 0xcc, 0xff, 0xff,
-       0xff, 0xee, 0xff, 0xff, 0xff, 0xee, 0xee, 0xff,
-       0xff, 0xff, 0xdd, 0xff, 0xff, 0xff, 0xdd, 0xdd,
-       0xff, 0xff, 0xff, 0xbb, 0xff, 0xff, 0xff, 0xbb,
-       0xbb, 0xff, 0xff, 0xff, 0x77, 0xff, 0xff, 0xff,
-       0x77, 0x77, 0xff, 0x77, 0xbb, 0xdd, 0xee, 0xff,
-       0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
-       0x00, 0xff, 0xff, 0xcc, 0xcc, 0xcc, 0x33, 0xcc,
-       0xcc, 0xcc, 0x33, 0x33, 0xcc, 0xcc, 0xcc, 0xff,
-       0xff, 0xff, 0xee, 0xff, 0xff, 0xff, 0xee, 0xee,
-       0xff, 0xff, 0xff, 0xdd, 0xff, 0xff, 0xff, 0xdd,
-       0xdd, 0xff, 0xff, 0xff, 0xbb, 0xff, 0xff, 0xff,
-       0xbb, 0xbb, 0xff, 0xff, 0xff, 0x77, 0xff, 0xff,
-       0xff, 0x77, 0x77, 0xff, 0x77, 0xbb, 0xdd, 0xee,
-};
-
 static bool dw_mci_reset(struct dw_mci *host);
 
 #if defined(CONFIG_DEBUG_FS)
@@ -234,10 +205,13 @@ err:
 }
 #endif /* defined(CONFIG_DEBUG_FS) */
 
+static void mci_send_cmd(struct dw_mci_slot *slot, u32 cmd, u32 arg);
+
 static u32 dw_mci_prepare_command(struct mmc_host *mmc, struct mmc_command *cmd)
 {
        struct mmc_data *data;
        struct dw_mci_slot *slot = mmc_priv(mmc);
+       struct dw_mci *host = slot->host;
        const struct dw_mci_drv_data *drv_data = slot->host->drv_data;
        u32 cmdr;
        cmd->error = -EINPROGRESS;
@@ -253,6 +227,34 @@ static u32 dw_mci_prepare_command(struct mmc_host *mmc, struct mmc_command *cmd)
        else if (cmd->opcode != MMC_SEND_STATUS && cmd->data)
                cmdr |= SDMMC_CMD_PRV_DAT_WAIT;
 
+       if (cmd->opcode == SD_SWITCH_VOLTAGE) {
+               u32 clk_en_a;
+
+               /* Special bit makes CMD11 not die */
+               cmdr |= SDMMC_CMD_VOLT_SWITCH;
+
+               /* Change state to continue to handle CMD11 weirdness */
+               WARN_ON(slot->host->state != STATE_SENDING_CMD);
+               slot->host->state = STATE_SENDING_CMD11;
+
+               /*
+                * We need to disable low power mode (automatic clock stop)
+                * while doing voltage switch so we don't confuse the card,
+                * since stopping the clock is a specific part of the UHS
+                * voltage change dance.
+                *
+                * Note that low power mode (SDMMC_CLKEN_LOW_PWR) will be
+                * unconditionally turned back on in dw_mci_setup_bus() if it's
+                * ever called with a non-zero clock.  That shouldn't happen
+                * until the voltage change is all done.
+                */
+               clk_en_a = mci_readl(host, CLKENA);
+               clk_en_a &= ~(SDMMC_CLKEN_LOW_PWR << slot->id);
+               mci_writel(host, CLKENA, clk_en_a);
+               mci_send_cmd(slot, SDMMC_CMD_UPD_CLK |
+                            SDMMC_CMD_PRV_DAT_WAIT, 0);
+       }
+
        if (cmd->flags & MMC_RSP_PRESENT) {
                /* We expect a response, so set this bit */
                cmdr |= SDMMC_CMD_RESP_EXP;
@@ -775,11 +777,15 @@ static void dw_mci_setup_bus(struct dw_mci_slot *slot, bool force_clkinit)
        unsigned int clock = slot->clock;
        u32 div;
        u32 clk_en_a;
+       u32 sdmmc_cmd_bits = SDMMC_CMD_UPD_CLK | SDMMC_CMD_PRV_DAT_WAIT;
+
+       /* We must continue to set bit 28 in CMD until the change is complete */
+       if (host->state == STATE_WAITING_CMD11_DONE)
+               sdmmc_cmd_bits |= SDMMC_CMD_VOLT_SWITCH;
 
        if (!clock) {
                mci_writel(host, CLKENA, 0);
-               mci_send_cmd(slot,
-                            SDMMC_CMD_UPD_CLK | SDMMC_CMD_PRV_DAT_WAIT, 0);
+               mci_send_cmd(slot, sdmmc_cmd_bits, 0);
        } else if (clock != host->current_speed || force_clkinit) {
                div = host->bus_hz / clock;
                if (host->bus_hz % clock && host->bus_hz > clock)
@@ -803,15 +809,13 @@ static void dw_mci_setup_bus(struct dw_mci_slot *slot, bool force_clkinit)
                mci_writel(host, CLKSRC, 0);
 
                /* inform CIU */
-               mci_send_cmd(slot,
-                            SDMMC_CMD_UPD_CLK | SDMMC_CMD_PRV_DAT_WAIT, 0);
+               mci_send_cmd(slot, sdmmc_cmd_bits, 0);
 
                /* set clock to desired speed */
                mci_writel(host, CLKDIV, div);
 
                /* inform CIU */
-               mci_send_cmd(slot,
-                            SDMMC_CMD_UPD_CLK | SDMMC_CMD_PRV_DAT_WAIT, 0);
+               mci_send_cmd(slot, sdmmc_cmd_bits, 0);
 
                /* enable clock; only low power if no SDIO */
                clk_en_a = SDMMC_CLKEN_ENABLE << slot->id;
@@ -820,8 +824,7 @@ static void dw_mci_setup_bus(struct dw_mci_slot *slot, bool force_clkinit)
                mci_writel(host, CLKENA, clk_en_a);
 
                /* inform CIU */
-               mci_send_cmd(slot,
-                            SDMMC_CMD_UPD_CLK | SDMMC_CMD_PRV_DAT_WAIT, 0);
+               mci_send_cmd(slot, sdmmc_cmd_bits, 0);
 
                /* keep the clock with reflecting clock dividor */
                slot->__clk_old = clock << div;
@@ -897,6 +900,17 @@ static void dw_mci_queue_request(struct dw_mci *host, struct dw_mci_slot *slot,
 
        slot->mrq = mrq;
 
+       if (host->state == STATE_WAITING_CMD11_DONE) {
+               dev_warn(&slot->mmc->class_dev,
+                        "Voltage change didn't complete\n");
+               /*
+                * this case isn't expected to happen, so we can
+                * either crash here or just try to continue on
+                * in the closest possible state
+                */
+               host->state = STATE_IDLE;
+       }
+
        if (host->state == STATE_IDLE) {
                host->state = STATE_SENDING_CMD;
                dw_mci_start_request(host, slot);
@@ -936,6 +950,7 @@ static void dw_mci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
        struct dw_mci_slot *slot = mmc_priv(mmc);
        const struct dw_mci_drv_data *drv_data = slot->host->drv_data;
        u32 regs;
+       int ret;
 
        switch (ios->bus_width) {
        case MMC_BUS_WIDTH_4:
@@ -972,14 +987,43 @@ static void dw_mci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
        /* Slot specific timing and width adjustment */
        dw_mci_setup_bus(slot, false);
 
+       if (slot->host->state == STATE_WAITING_CMD11_DONE && ios->clock != 0)
+               slot->host->state = STATE_IDLE;
+
        switch (ios->power_mode) {
        case MMC_POWER_UP:
+               if (!IS_ERR(mmc->supply.vmmc)) {
+                       ret = mmc_regulator_set_ocr(mmc, mmc->supply.vmmc,
+                                       ios->vdd);
+                       if (ret) {
+                               dev_err(slot->host->dev,
+                                       "failed to enable vmmc regulator\n");
+                               /*return, if failed turn on vmmc*/
+                               return;
+                       }
+               }
+               if (!IS_ERR(mmc->supply.vqmmc) && !slot->host->vqmmc_enabled) {
+                       ret = regulator_enable(mmc->supply.vqmmc);
+                       if (ret < 0)
+                               dev_err(slot->host->dev,
+                                       "failed to enable vqmmc regulator\n");
+                       else
+                               slot->host->vqmmc_enabled = true;
+               }
                set_bit(DW_MMC_CARD_NEED_INIT, &slot->flags);
                regs = mci_readl(slot->host, PWREN);
                regs |= (1 << slot->id);
                mci_writel(slot->host, PWREN, regs);
                break;
        case MMC_POWER_OFF:
+               if (!IS_ERR(mmc->supply.vmmc))
+                       mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, 0);
+
+               if (!IS_ERR(mmc->supply.vqmmc) && slot->host->vqmmc_enabled) {
+                       regulator_disable(mmc->supply.vqmmc);
+                       slot->host->vqmmc_enabled = false;
+               }
+
                regs = mci_readl(slot->host, PWREN);
                regs &= ~(1 << slot->id);
                mci_writel(slot->host, PWREN, regs);
@@ -989,6 +1033,59 @@ static void dw_mci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
        }
 }
 
+static int dw_mci_card_busy(struct mmc_host *mmc)
+{
+       struct dw_mci_slot *slot = mmc_priv(mmc);
+       u32 status;
+
+       /*
+        * Check the busy bit which is low when DAT[3:0]
+        * (the data lines) are 0000
+        */
+       status = mci_readl(slot->host, STATUS);
+
+       return !!(status & SDMMC_STATUS_BUSY);
+}
+
+static int dw_mci_switch_voltage(struct mmc_host *mmc, struct mmc_ios *ios)
+{
+       struct dw_mci_slot *slot = mmc_priv(mmc);
+       struct dw_mci *host = slot->host;
+       u32 uhs;
+       u32 v18 = SDMMC_UHS_18V << slot->id;
+       int min_uv, max_uv;
+       int ret;
+
+       /*
+        * Program the voltage.  Note that some instances of dw_mmc may use
+        * the UHS_REG for this.  For other instances (like exynos) the UHS_REG
+        * does no harm but you need to set the regulator directly.  Try both.
+        */
+       uhs = mci_readl(host, UHS_REG);
+       if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_330) {
+               min_uv = 2700000;
+               max_uv = 3600000;
+               uhs &= ~v18;
+       } else {
+               min_uv = 1700000;
+               max_uv = 1950000;
+               uhs |= v18;
+       }
+       if (!IS_ERR(mmc->supply.vqmmc)) {
+               ret = regulator_set_voltage(mmc->supply.vqmmc, min_uv, max_uv);
+
+               if (ret) {
+                       dev_err(&mmc->class_dev,
+                                        "Regulator set error %d: %d - %d\n",
+                                        ret, min_uv, max_uv);
+                       return ret;
+               }
+       }
+       mci_writel(host, UHS_REG, uhs);
+
+       return 0;
+}
+
 static int dw_mci_get_ro(struct mmc_host *mmc)
 {
        int read_only;
@@ -1131,6 +1228,9 @@ static const struct mmc_host_ops dw_mci_ops = {
        .get_cd                 = dw_mci_get_cd,
        .enable_sdio_irq        = dw_mci_enable_sdio_irq,
        .execute_tuning         = dw_mci_execute_tuning,
+       .card_busy              = dw_mci_card_busy,
+       .start_signal_voltage_switch = dw_mci_switch_voltage,
+
 };
 
 static void dw_mci_request_end(struct dw_mci *host, struct mmc_request *mrq)
@@ -1154,7 +1254,11 @@ static void dw_mci_request_end(struct dw_mci *host, struct mmc_request *mrq)
                dw_mci_start_request(host, slot);
        } else {
                dev_vdbg(host->dev, "list empty\n");
-               host->state = STATE_IDLE;
+
+               if (host->state == STATE_SENDING_CMD11)
+                       host->state = STATE_WAITING_CMD11_DONE;
+               else
+                       host->state = STATE_IDLE;
        }
 
        spin_unlock(&host->lock);
@@ -1265,8 +1369,10 @@ static void dw_mci_tasklet_func(unsigned long priv)
 
                switch (state) {
                case STATE_IDLE:
+               case STATE_WAITING_CMD11_DONE:
                        break;
 
+               case STATE_SENDING_CMD11:
                case STATE_SENDING_CMD:
                        if (!test_and_clear_bit(EVENT_CMD_COMPLETE,
                                                &host->pending_events))
@@ -1299,6 +1405,14 @@ static void dw_mci_tasklet_func(unsigned long priv)
                        /* fall through */
 
                case STATE_SENDING_DATA:
+                       /*
+                        * We could get a data error and never a transfer
+                        * complete so we'd better check for it here.
+                        *
+                        * Note that we don't really care if we also got a
+                        * transfer complete; stopping the DMA and sending an
+                        * abort won't hurt.
+                        */
                        if (test_and_clear_bit(EVENT_DATA_ERROR,
                                               &host->pending_events)) {
                                dw_mci_stop_dma(host);
@@ -1312,7 +1426,29 @@ static void dw_mci_tasklet_func(unsigned long priv)
                                break;
 
                        set_bit(EVENT_XFER_COMPLETE, &host->completed_events);
+
+                       /*
+                        * Handle an EVENT_DATA_ERROR that might have shown up
+                        * before the transfer completed.  This might not have
+                        * been caught by the check above because the interrupt
+                        * could have gone off between the previous check and
+                        * the check for transfer complete.
+                        *
+                        * Technically this ought not be needed assuming we
+                        * get a DATA_COMPLETE eventually (we'll notice the
+                        * error and end the request), but it shouldn't hurt.
+                        *
+                        * This has the advantage of sending the stop command.
+                        */
+                       if (test_and_clear_bit(EVENT_DATA_ERROR,
+                                              &host->pending_events)) {
+                               dw_mci_stop_dma(host);
+                               send_stop_abort(host, data);
+                               state = STATE_DATA_ERROR;
+                               break;
+                       }
                        prev_state = state = STATE_DATA_BUSY;
+
                        /* fall through */
 
                case STATE_DATA_BUSY:
@@ -1335,6 +1471,22 @@ static void dw_mci_tasklet_func(unsigned long priv)
                                /* stop command for open-ended transfer*/
                                if (data->stop)
                                        send_stop_abort(host, data);
+                       } else {
+                               /*
+                                * If we don't have a command complete now we'll
+                                * never get one since we just reset everything;
+                                * better end the request.
+                                *
+                                * If we do have a command complete we'll fall
+                                * through to the SENDING_STOP command and
+                                * everything will be peachy keen.
+                                */
+                               if (!test_bit(EVENT_CMD_COMPLETE,
+                                             &host->pending_events)) {
+                                       host->cmd = NULL;
+                                       dw_mci_request_end(host, mrq);
+                                       goto unlock;
+                               }
                        }
 
                        /*
@@ -1821,6 +1973,14 @@ static irqreturn_t dw_mci_interrupt(int irq, void *dev_id)
        }
 
        if (pending) {
+               /* Check volt switch first, since it can look like an error */
+               if ((host->state == STATE_SENDING_CMD11) &&
+                   (pending & SDMMC_INT_VOLT_SWITCH)) {
+                       mci_writel(host, RINTSTS, SDMMC_INT_VOLT_SWITCH);
+                       pending &= ~SDMMC_INT_VOLT_SWITCH;
+                       dw_mci_cmd_interrupt(host, pending);
+               }
+
                if (pending & DW_MCI_CMD_ERROR_FLAGS) {
                        mci_writel(host, RINTSTS, DW_MCI_CMD_ERROR_FLAGS);
                        host->cmd_status = pending;
@@ -1926,7 +2086,9 @@ static void dw_mci_work_routine_card(struct work_struct *work)
 
                                        switch (host->state) {
                                        case STATE_IDLE:
+                                       case STATE_WAITING_CMD11_DONE:
                                                break;
+                                       case STATE_SENDING_CMD11:
                                        case STATE_SENDING_CMD:
                                                mrq->cmd->error = -ENOMEDIUM;
                                                if (!mrq->data)
@@ -2028,10 +2190,6 @@ static int dw_mci_of_get_slot_quirks(struct device *dev, u8 slot)
 {
        return 0;
 }
-static struct device_node *dw_mci_of_find_slot_node(struct device *dev, u8 slot)
-{
-       return NULL;
-}
 #endif /* CONFIG_OF */
 
 static int dw_mci_init_slot(struct dw_mci *host, unsigned int id)
@@ -2064,7 +2222,13 @@ static int dw_mci_init_slot(struct dw_mci *host, unsigned int id)
                mmc->f_max = freq[1];
        }
 
-       mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34;
+       /*if there are external regulators, get them*/
+       ret = mmc_regulator_get_supply(mmc);
+       if (ret == -EPROBE_DEFER)
+               goto err_host_allocated;
+
+       if (!mmc->ocr_avail)
+               mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34;
 
        if (host->pdata->caps)
                mmc->caps = host->pdata->caps;
@@ -2085,7 +2249,9 @@ static int dw_mci_init_slot(struct dw_mci *host, unsigned int id)
        if (host->pdata->caps2)
                mmc->caps2 = host->pdata->caps2;
 
-       mmc_of_parse(mmc);
+       ret = mmc_of_parse(mmc);
+       if (ret)
+               goto err_host_allocated;
 
        if (host->pdata->blk_settings) {
                mmc->max_segs = host->pdata->blk_settings->max_segs;
@@ -2117,7 +2283,7 @@ static int dw_mci_init_slot(struct dw_mci *host, unsigned int id)
 
        ret = mmc_add_host(mmc);
        if (ret)
-               goto err_setup_bus;
+               goto err_host_allocated;
 
 #if defined(CONFIG_DEBUG_FS)
        dw_mci_init_debugfs(slot);
@@ -2128,9 +2294,9 @@ static int dw_mci_init_slot(struct dw_mci *host, unsigned int id)
 
        return 0;
 
-err_setup_bus:
+err_host_allocated:
        mmc_free_host(mmc);
-       return -EINVAL;
+       return ret;
 }
 
 static void dw_mci_cleanup_slot(struct dw_mci_slot *slot, unsigned int id)
@@ -2423,24 +2589,6 @@ int dw_mci_probe(struct dw_mci *host)
                }
        }
 
-       host->vmmc = devm_regulator_get_optional(host->dev, "vmmc");
-       if (IS_ERR(host->vmmc)) {
-               ret = PTR_ERR(host->vmmc);
-               if (ret == -EPROBE_DEFER)
-                       goto err_clk_ciu;
-
-               dev_info(host->dev, "no vmmc regulator found: %d\n", ret);
-               host->vmmc = NULL;
-       } else {
-               ret = regulator_enable(host->vmmc);
-               if (ret) {
-                       if (ret != -EPROBE_DEFER)
-                               dev_err(host->dev,
-                                       "regulator_enable fail: %d\n", ret);
-                       goto err_clk_ciu;
-               }
-       }
-
        host->quirks = host->pdata->quirks;
 
        spin_lock_init(&host->lock);
@@ -2584,8 +2732,6 @@ err_workqueue:
 err_dmaunmap:
        if (host->use_dma && host->dma_ops->exit)
                host->dma_ops->exit(host);
-       if (host->vmmc)
-               regulator_disable(host->vmmc);
 
 err_clk_ciu:
        if (!IS_ERR(host->ciu_clk))
@@ -2621,9 +2767,6 @@ void dw_mci_remove(struct dw_mci *host)
        if (host->use_dma && host->dma_ops->exit)
                host->dma_ops->exit(host);
 
-       if (host->vmmc)
-               regulator_disable(host->vmmc);
-
        if (!IS_ERR(host->ciu_clk))
                clk_disable_unprepare(host->ciu_clk);
 
@@ -2640,9 +2783,6 @@ EXPORT_SYMBOL(dw_mci_remove);
  */
 int dw_mci_suspend(struct dw_mci *host)
 {
-       if (host->vmmc)
-               regulator_disable(host->vmmc);
-
        return 0;
 }
 EXPORT_SYMBOL(dw_mci_suspend);
@@ -2651,15 +2791,6 @@ int dw_mci_resume(struct dw_mci *host)
 {
        int i, ret;
 
-       if (host->vmmc) {
-               ret = regulator_enable(host->vmmc);
-               if (ret) {
-                       dev_err(host->dev,
-                               "failed to enable regulator: %d\n", ret);
-                       return ret;
-               }
-       }
-
        if (!dw_mci_ctrl_reset(host, SDMMC_CTRL_ALL_RESET_FLAGS)) {
                ret = -ENODEV;
                return ret;
index 08fd956d81f3bc687162e333cb612c37f06ad025..01b99e8a919073b10dace3daea7b8444f70b0e9b 100644 (file)
@@ -99,6 +99,7 @@
 #define SDMMC_INT_HLE                  BIT(12)
 #define SDMMC_INT_FRUN                 BIT(11)
 #define SDMMC_INT_HTO                  BIT(10)
+#define SDMMC_INT_VOLT_SWITCH          BIT(10) /* overloads bit 10! */
 #define SDMMC_INT_DRTO                 BIT(9)
 #define SDMMC_INT_RTO                  BIT(8)
 #define SDMMC_INT_DCRC                 BIT(7)
 /* Command register defines */
 #define SDMMC_CMD_START                        BIT(31)
 #define SDMMC_CMD_USE_HOLD_REG BIT(29)
+#define SDMMC_CMD_VOLT_SWITCH          BIT(28)
 #define SDMMC_CMD_CCS_EXP              BIT(23)
 #define SDMMC_CMD_CEATA_RD             BIT(22)
 #define SDMMC_CMD_UPD_CLK              BIT(21)
 /* Status register defines */
 #define SDMMC_GET_FCNT(x)              (((x)>>17) & 0x1FFF)
 #define SDMMC_STATUS_DMA_REQ           BIT(31)
+#define SDMMC_STATUS_BUSY              BIT(9)
 /* FIFOTH register defines */
 #define SDMMC_SET_FIFOTH(m, r, t)      (((m) & 0x7) << 28 | \
                                         ((r) & 0xFFF) << 16 | \
 #define SDMMC_GET_VERID(x)             ((x) & 0xFFFF)
 /* Card read threshold */
 #define SDMMC_SET_RD_THLD(v, x)                (((v) & 0x1FFF) << 16 | (x))
-
+#define SDMMC_UHS_18V                  BIT(0)
 /* All ctrl reset bits */
 #define SDMMC_CTRL_ALL_RESET_FLAGS \
        (SDMMC_CTRL_RESET | SDMMC_CTRL_FIFO_RESET | SDMMC_CTRL_DMA_RESET)
index 537d6c7a5ae48a9458dd3674cf56a975a8331996..76e8bce6f46e7015bb6ae9e3dfe082d2cf58db35 100644 (file)
@@ -30,7 +30,9 @@
 #include <asm/mach-jz4740/gpio.h>
 #include <asm/cacheflush.h>
 #include <linux/dma-mapping.h>
+#include <linux/dmaengine.h>
 
+#include <asm/mach-jz4740/dma.h>
 #include <asm/mach-jz4740/jz4740_mmc.h>
 
 #define JZ_REG_MMC_STRPCL      0x00
@@ -112,6 +114,11 @@ enum jz4740_mmc_state {
        JZ4740_MMC_STATE_DONE,
 };
 
+struct jz4740_mmc_host_next {
+       int sg_len;
+       s32 cookie;
+};
+
 struct jz4740_mmc_host {
        struct mmc_host *mmc;
        struct platform_device *pdev;
@@ -122,6 +129,7 @@ struct jz4740_mmc_host {
        int card_detect_irq;
 
        void __iomem *base;
+       struct resource *mem_res;
        struct mmc_request *req;
        struct mmc_command *cmd;
 
@@ -136,8 +144,220 @@ struct jz4740_mmc_host {
        struct timer_list timeout_timer;
        struct sg_mapping_iter miter;
        enum jz4740_mmc_state state;
+
+       /* DMA support */
+       struct dma_chan *dma_rx;
+       struct dma_chan *dma_tx;
+       struct jz4740_mmc_host_next next_data;
+       bool use_dma;
+       int sg_len;
+
+/* The DMA trigger level is 8 words, that is to say, the DMA read
+ * trigger is when data words in MSC_RXFIFO is >= 8 and the DMA write
+ * trigger is when data words in MSC_TXFIFO is < 8.
+ */
+#define JZ4740_MMC_FIFO_HALF_SIZE 8
 };
 
+/*----------------------------------------------------------------------------*/
+/* DMA infrastructure */
+
+static void jz4740_mmc_release_dma_channels(struct jz4740_mmc_host *host)
+{
+       if (!host->use_dma)
+               return;
+
+       dma_release_channel(host->dma_tx);
+       dma_release_channel(host->dma_rx);
+}
+
+static int jz4740_mmc_acquire_dma_channels(struct jz4740_mmc_host *host)
+{
+       dma_cap_mask_t mask;
+
+       dma_cap_zero(mask);
+       dma_cap_set(DMA_SLAVE, mask);
+
+       host->dma_tx = dma_request_channel(mask, NULL, host);
+       if (!host->dma_tx) {
+               dev_err(mmc_dev(host->mmc), "Failed to get dma_tx channel\n");
+               return -ENODEV;
+       }
+
+       host->dma_rx = dma_request_channel(mask, NULL, host);
+       if (!host->dma_rx) {
+               dev_err(mmc_dev(host->mmc), "Failed to get dma_rx channel\n");
+               goto free_master_write;
+       }
+
+       /* Initialize DMA pre request cookie */
+       host->next_data.cookie = 1;
+
+       return 0;
+
+free_master_write:
+       dma_release_channel(host->dma_tx);
+       return -ENODEV;
+}
+
+static inline int jz4740_mmc_get_dma_dir(struct mmc_data *data)
+{
+       return (data->flags & MMC_DATA_READ) ? DMA_FROM_DEVICE : DMA_TO_DEVICE;
+}
+
+static inline struct dma_chan *jz4740_mmc_get_dma_chan(struct jz4740_mmc_host *host,
+                                                      struct mmc_data *data)
+{
+       return (data->flags & MMC_DATA_READ) ? host->dma_rx : host->dma_tx;
+}
+
+static void jz4740_mmc_dma_unmap(struct jz4740_mmc_host *host,
+                                struct mmc_data *data)
+{
+       struct dma_chan *chan = jz4740_mmc_get_dma_chan(host, data);
+       enum dma_data_direction dir = jz4740_mmc_get_dma_dir(data);
+
+       dma_unmap_sg(chan->device->dev, data->sg, data->sg_len, dir);
+}
+
+/* Prepares DMA data for current/next transfer, returns non-zero on failure */
+static int jz4740_mmc_prepare_dma_data(struct jz4740_mmc_host *host,
+                                      struct mmc_data *data,
+                                      struct jz4740_mmc_host_next *next,
+                                      struct dma_chan *chan)
+{
+       struct jz4740_mmc_host_next *next_data = &host->next_data;
+       enum dma_data_direction dir = jz4740_mmc_get_dma_dir(data);
+       int sg_len;
+
+       if (!next && data->host_cookie &&
+           data->host_cookie != host->next_data.cookie) {
+               dev_warn(mmc_dev(host->mmc),
+                        "[%s] invalid cookie: data->host_cookie %d host->next_data.cookie %d\n",
+                        __func__,
+                        data->host_cookie,
+                        host->next_data.cookie);
+               data->host_cookie = 0;
+       }
+
+       /* Check if next job is already prepared */
+       if (next || data->host_cookie != host->next_data.cookie) {
+               sg_len = dma_map_sg(chan->device->dev,
+                                   data->sg,
+                                   data->sg_len,
+                                   dir);
+
+       } else {
+               sg_len = next_data->sg_len;
+               next_data->sg_len = 0;
+       }
+
+       if (sg_len <= 0) {
+               dev_err(mmc_dev(host->mmc),
+                       "Failed to map scatterlist for DMA operation\n");
+               return -EINVAL;
+       }
+
+       if (next) {
+               next->sg_len = sg_len;
+               data->host_cookie = ++next->cookie < 0 ? 1 : next->cookie;
+       } else
+               host->sg_len = sg_len;
+
+       return 0;
+}
+
+static int jz4740_mmc_start_dma_transfer(struct jz4740_mmc_host *host,
+                                        struct mmc_data *data)
+{
+       int ret;
+       struct dma_chan *chan;
+       struct dma_async_tx_descriptor *desc;
+       struct dma_slave_config conf = {
+               .src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES,
+               .dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES,
+               .src_maxburst = JZ4740_MMC_FIFO_HALF_SIZE,
+               .dst_maxburst = JZ4740_MMC_FIFO_HALF_SIZE,
+       };
+
+       if (data->flags & MMC_DATA_WRITE) {
+               conf.direction = DMA_MEM_TO_DEV;
+               conf.dst_addr = host->mem_res->start + JZ_REG_MMC_TXFIFO;
+               conf.slave_id = JZ4740_DMA_TYPE_MMC_TRANSMIT;
+               chan = host->dma_tx;
+       } else {
+               conf.direction = DMA_DEV_TO_MEM;
+               conf.src_addr = host->mem_res->start + JZ_REG_MMC_RXFIFO;
+               conf.slave_id = JZ4740_DMA_TYPE_MMC_RECEIVE;
+               chan = host->dma_rx;
+       }
+
+       ret = jz4740_mmc_prepare_dma_data(host, data, NULL, chan);
+       if (ret)
+               return ret;
+
+       dmaengine_slave_config(chan, &conf);
+       desc = dmaengine_prep_slave_sg(chan,
+                                      data->sg,
+                                      host->sg_len,
+                                      conf.direction,
+                                      DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+       if (!desc) {
+               dev_err(mmc_dev(host->mmc),
+                       "Failed to allocate DMA %s descriptor",
+                        conf.direction == DMA_MEM_TO_DEV ? "TX" : "RX");
+               goto dma_unmap;
+       }
+
+       dmaengine_submit(desc);
+       dma_async_issue_pending(chan);
+
+       return 0;
+
+dma_unmap:
+       jz4740_mmc_dma_unmap(host, data);
+       return -ENOMEM;
+}
+
+static void jz4740_mmc_pre_request(struct mmc_host *mmc,
+                                  struct mmc_request *mrq,
+                                  bool is_first_req)
+{
+       struct jz4740_mmc_host *host = mmc_priv(mmc);
+       struct mmc_data *data = mrq->data;
+       struct jz4740_mmc_host_next *next_data = &host->next_data;
+
+       BUG_ON(data->host_cookie);
+
+       if (host->use_dma) {
+               struct dma_chan *chan = jz4740_mmc_get_dma_chan(host, data);
+
+               if (jz4740_mmc_prepare_dma_data(host, data, next_data, chan))
+                       data->host_cookie = 0;
+       }
+}
+
+static void jz4740_mmc_post_request(struct mmc_host *mmc,
+                                   struct mmc_request *mrq,
+                                   int err)
+{
+       struct jz4740_mmc_host *host = mmc_priv(mmc);
+       struct mmc_data *data = mrq->data;
+
+       if (host->use_dma && data->host_cookie) {
+               jz4740_mmc_dma_unmap(host, data);
+               data->host_cookie = 0;
+       }
+
+       if (err) {
+               struct dma_chan *chan = jz4740_mmc_get_dma_chan(host, data);
+
+               dmaengine_terminate_all(chan);
+       }
+}
+
+/*----------------------------------------------------------------------------*/
+
 static void jz4740_mmc_set_irq_enabled(struct jz4740_mmc_host *host,
        unsigned int irq, bool enabled)
 {
@@ -442,6 +662,8 @@ static void jz4740_mmc_send_command(struct jz4740_mmc_host *host,
                        cmdat |= JZ_MMC_CMDAT_WRITE;
                if (cmd->data->flags & MMC_DATA_STREAM)
                        cmdat |= JZ_MMC_CMDAT_STREAM;
+               if (host->use_dma)
+                       cmdat |= JZ_MMC_CMDAT_DMA_EN;
 
                writew(cmd->data->blksz, host->base + JZ_REG_MMC_BLKLEN);
                writew(cmd->data->blocks, host->base + JZ_REG_MMC_NOB);
@@ -474,6 +696,7 @@ static irqreturn_t jz_mmc_irq_worker(int irq, void *devid)
        struct jz4740_mmc_host *host = (struct jz4740_mmc_host *)devid;
        struct mmc_command *cmd = host->req->cmd;
        struct mmc_request *req = host->req;
+       struct mmc_data *data = cmd->data;
        bool timeout = false;
 
        if (cmd->error)
@@ -484,23 +707,37 @@ static irqreturn_t jz_mmc_irq_worker(int irq, void *devid)
                if (cmd->flags & MMC_RSP_PRESENT)
                        jz4740_mmc_read_response(host, cmd);
 
-               if (!cmd->data)
+               if (!data)
                        break;
 
                jz_mmc_prepare_data_transfer(host);
 
        case JZ4740_MMC_STATE_TRANSFER_DATA:
-               if (cmd->data->flags & MMC_DATA_READ)
-                       timeout = jz4740_mmc_read_data(host, cmd->data);
+               if (host->use_dma) {
+                       /* Use DMA if enabled.
+                        * Data transfer direction is defined later by
+                        * relying on data flags in
+                        * jz4740_mmc_prepare_dma_data() and
+                        * jz4740_mmc_start_dma_transfer().
+                        */
+                       timeout = jz4740_mmc_start_dma_transfer(host, data);
+                       data->bytes_xfered = data->blocks * data->blksz;
+               } else if (data->flags & MMC_DATA_READ)
+                       /* Use PIO if DMA is not enabled.
+                        * Data transfer direction was defined before
+                        * by relying on data flags in
+                        * jz_mmc_prepare_data_transfer().
+                        */
+                       timeout = jz4740_mmc_read_data(host, data);
                else
-                       timeout = jz4740_mmc_write_data(host, cmd->data);
+                       timeout = jz4740_mmc_write_data(host, data);
 
                if (unlikely(timeout)) {
                        host->state = JZ4740_MMC_STATE_TRANSFER_DATA;
                        break;
                }
 
-               jz4740_mmc_transfer_check_state(host, cmd->data);
+               jz4740_mmc_transfer_check_state(host, data);
 
                timeout = jz4740_mmc_poll_irq(host, JZ_MMC_IRQ_DATA_TRAN_DONE);
                if (unlikely(timeout)) {
@@ -664,6 +901,8 @@ static void jz4740_mmc_enable_sdio_irq(struct mmc_host *mmc, int enable)
 
 static const struct mmc_host_ops jz4740_mmc_ops = {
        .request        = jz4740_mmc_request,
+       .pre_req        = jz4740_mmc_pre_request,
+       .post_req       = jz4740_mmc_post_request,
        .set_ios        = jz4740_mmc_set_ios,
        .get_ro         = mmc_gpio_get_ro,
        .get_cd         = mmc_gpio_get_cd,
@@ -757,7 +996,6 @@ static int jz4740_mmc_probe(struct platform_device* pdev)
        struct mmc_host *mmc;
        struct jz4740_mmc_host *host;
        struct jz4740_mmc_platform_data *pdata;
-       struct resource *res;
 
        pdata = pdev->dev.platform_data;
 
@@ -784,10 +1022,11 @@ static int jz4740_mmc_probe(struct platform_device* pdev)
                goto err_free_host;
        }
 
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       host->base = devm_ioremap_resource(&pdev->dev, res);
+       host->mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       host->base = devm_ioremap_resource(&pdev->dev, host->mem_res);
        if (IS_ERR(host->base)) {
                ret = PTR_ERR(host->base);
+               dev_err(&pdev->dev, "Failed to ioremap base memory\n");
                goto err_free_host;
        }
 
@@ -834,6 +1073,10 @@ static int jz4740_mmc_probe(struct platform_device* pdev)
        /* It is not important when it times out, it just needs to timeout. */
        set_timer_slack(&host->timeout_timer, HZ);
 
+       host->use_dma = true;
+       if (host->use_dma && jz4740_mmc_acquire_dma_channels(host) != 0)
+               host->use_dma = false;
+
        platform_set_drvdata(pdev, host);
        ret = mmc_add_host(mmc);
 
@@ -843,6 +1086,10 @@ static int jz4740_mmc_probe(struct platform_device* pdev)
        }
        dev_info(&pdev->dev, "JZ SD/MMC card driver registered\n");
 
+       dev_info(&pdev->dev, "Using %s, %d-bit mode\n",
+                host->use_dma ? "DMA" : "PIO",
+                (mmc->caps & MMC_CAP_4_BIT_DATA) ? 4 : 1);
+
        return 0;
 
 err_free_irq:
@@ -850,6 +1097,8 @@ err_free_irq:
 err_free_gpios:
        jz4740_mmc_free_gpios(pdev);
 err_gpio_bulk_free:
+       if (host->use_dma)
+               jz4740_mmc_release_dma_channels(host);
        jz_gpio_bulk_free(jz4740_mmc_pins, jz4740_mmc_num_pins(host));
 err_free_host:
        mmc_free_host(mmc);
@@ -872,6 +1121,9 @@ static int jz4740_mmc_remove(struct platform_device *pdev)
        jz4740_mmc_free_gpios(pdev);
        jz_gpio_bulk_free(jz4740_mmc_pins, jz4740_mmc_num_pins(host));
 
+       if (host->use_dma)
+               jz4740_mmc_release_dma_channels(host);
+
        mmc_free_host(host->mmc);
 
        return 0;
@@ -909,7 +1161,6 @@ static struct platform_driver jz4740_mmc_driver = {
        .remove = jz4740_mmc_remove,
        .driver = {
                .name = "jz4740-mmc",
-               .owner = THIS_MODULE,
                .pm = JZ4740_MMC_PM_OPS,
        },
 };
index cc8d4a6099cdc602071af7616e1451896e7f6959..e4a07546f8b631d4c905dbe483449bf381960279 100644 (file)
@@ -1436,6 +1436,7 @@ static int mmc_spi_probe(struct spi_device *spi)
                                             host->pdata->cd_debounce);
                if (status != 0)
                        goto fail_add_host;
+               mmc_gpiod_request_cd_irq(mmc);
        }
 
        if (host->pdata && host->pdata->flags & MMC_SPI_USE_RO_GPIO) {
index e4d470704150c257bdf0e535cefa05f4bc41a059..43af791e2e45e1b29a94fc364978c99a315f2ffa 100644 (file)
@@ -43,6 +43,7 @@
 #include <asm/sizes.h>
 
 #include "mmci.h"
+#include "mmci_qcom_dml.h"
 
 #define DRIVER_NAME "mmci-pl18x"
 
@@ -60,12 +61,13 @@ static unsigned int fmax = 515633;
  * @fifohalfsize: number of bytes that can be written when MCI_TXFIFOHALFEMPTY
  *               is asserted (likewise for RX)
  * @data_cmd_enable: enable value for data commands.
- * @sdio: variant supports SDIO
+ * @st_sdio: enable ST specific SDIO logic
  * @st_clkdiv: true if using a ST-specific clock divider algorithm
  * @datactrl_mask_ddrmode: ddr mode mask in datactrl register.
  * @blksz_datactrl16: true if Block size is at b16..b30 position in datactrl register
  * @blksz_datactrl4: true if Block size is at b4..b16 position in datactrl
  *                  register
+ * @datactrl_mask_sdio: SDIO enable mask in datactrl register
  * @pwrreg_powerup: power up value for MMCIPOWER register
  * @f_max: maximum clk frequency supported by the controller.
  * @signal_direction: input/out direction of bus signals can be indicated
@@ -74,6 +76,7 @@ static unsigned int fmax = 515633;
  * @pwrreg_nopower: bits in MMCIPOWER don't controls ext. power supply
  * @explicit_mclk_control: enable explicit mclk control in driver.
  * @qcom_fifo: enables qcom specific fifo pio read logic.
+ * @qcom_dml: enables qcom specific dma glue for dma transfers.
  * @reversed_irq_handling: handle data irq before cmd irq.
  */
 struct variant_data {
@@ -86,7 +89,8 @@ struct variant_data {
        unsigned int            fifohalfsize;
        unsigned int            data_cmd_enable;
        unsigned int            datactrl_mask_ddrmode;
-       bool                    sdio;
+       unsigned int            datactrl_mask_sdio;
+       bool                    st_sdio;
        bool                    st_clkdiv;
        bool                    blksz_datactrl16;
        bool                    blksz_datactrl4;
@@ -98,6 +102,7 @@ struct variant_data {
        bool                    pwrreg_nopower;
        bool                    explicit_mclk_control;
        bool                    qcom_fifo;
+       bool                    qcom_dml;
        bool                    reversed_irq_handling;
 };
 
@@ -133,7 +138,8 @@ static struct variant_data variant_u300 = {
        .clkreg_enable          = MCI_ST_U300_HWFCEN,
        .clkreg_8bit_bus_enable = MCI_ST_8BIT_BUS,
        .datalength_bits        = 16,
-       .sdio                   = true,
+       .datactrl_mask_sdio     = MCI_ST_DPSM_SDIOEN,
+       .st_sdio                        = true,
        .pwrreg_powerup         = MCI_PWR_ON,
        .f_max                  = 100000000,
        .signal_direction       = true,
@@ -146,7 +152,8 @@ static struct variant_data variant_nomadik = {
        .fifohalfsize           = 8 * 4,
        .clkreg                 = MCI_CLK_ENABLE,
        .datalength_bits        = 24,
-       .sdio                   = true,
+       .datactrl_mask_sdio     = MCI_ST_DPSM_SDIOEN,
+       .st_sdio                = true,
        .st_clkdiv              = true,
        .pwrreg_powerup         = MCI_PWR_ON,
        .f_max                  = 100000000,
@@ -163,7 +170,8 @@ static struct variant_data variant_ux500 = {
        .clkreg_8bit_bus_enable = MCI_ST_8BIT_BUS,
        .clkreg_neg_edge_enable = MCI_ST_UX500_NEG_EDGE,
        .datalength_bits        = 24,
-       .sdio                   = true,
+       .datactrl_mask_sdio     = MCI_ST_DPSM_SDIOEN,
+       .st_sdio                = true,
        .st_clkdiv              = true,
        .pwrreg_powerup         = MCI_PWR_ON,
        .f_max                  = 100000000,
@@ -182,7 +190,8 @@ static struct variant_data variant_ux500v2 = {
        .clkreg_neg_edge_enable = MCI_ST_UX500_NEG_EDGE,
        .datactrl_mask_ddrmode  = MCI_ST_DPSM_DDRMODE,
        .datalength_bits        = 24,
-       .sdio                   = true,
+       .datactrl_mask_sdio     = MCI_ST_DPSM_SDIOEN,
+       .st_sdio                = true,
        .st_clkdiv              = true,
        .blksz_datactrl16       = true,
        .pwrreg_powerup         = MCI_PWR_ON,
@@ -208,6 +217,7 @@ static struct variant_data variant_qcom = {
        .f_max                  = 208000000,
        .explicit_mclk_control  = true,
        .qcom_fifo              = true,
+       .qcom_dml               = true,
 };
 
 static int mmci_card_busy(struct mmc_host *mmc)
@@ -421,6 +431,7 @@ static void mmci_dma_setup(struct mmci_host *host)
 {
        const char *rxname, *txname;
        dma_cap_mask_t mask;
+       struct variant_data *variant = host->variant;
 
        host->dma_rx_channel = dma_request_slave_channel(mmc_dev(host->mmc), "rx");
        host->dma_tx_channel = dma_request_slave_channel(mmc_dev(host->mmc), "tx");
@@ -471,6 +482,10 @@ static void mmci_dma_setup(struct mmci_host *host)
                if (max_seg_size < host->mmc->max_seg_size)
                        host->mmc->max_seg_size = max_seg_size;
        }
+
+       if (variant->qcom_dml && host->dma_rx_channel && host->dma_tx_channel)
+               if (dml_hw_init(host, host->mmc->parent->of_node))
+                       variant->qcom_dml = false;
 }
 
 /*
@@ -572,6 +587,7 @@ static int __mmci_dma_prep_data(struct mmci_host *host, struct mmc_data *data,
        struct dma_async_tx_descriptor *desc;
        enum dma_data_direction buffer_dirn;
        int nr_sg;
+       unsigned long flags = DMA_CTRL_ACK;
 
        if (data->flags & MMC_DATA_READ) {
                conf.direction = DMA_DEV_TO_MEM;
@@ -596,9 +612,12 @@ static int __mmci_dma_prep_data(struct mmci_host *host, struct mmc_data *data,
        if (nr_sg == 0)
                return -EINVAL;
 
+       if (host->variant->qcom_dml)
+               flags |= DMA_PREP_INTERRUPT;
+
        dmaengine_slave_config(chan, &conf);
        desc = dmaengine_prep_slave_sg(chan, data->sg, nr_sg,
-                                           conf.direction, DMA_CTRL_ACK);
+                                           conf.direction, flags);
        if (!desc)
                goto unmap_exit;
 
@@ -647,6 +666,9 @@ static int mmci_dma_start_data(struct mmci_host *host, unsigned int datactrl)
        dmaengine_submit(host->dma_desc_current);
        dma_async_issue_pending(host->dma_current);
 
+       if (host->variant->qcom_dml)
+               dml_start_xfer(host, data);
+
        datactrl |= MCI_DPSM_DMAENABLE;
 
        /* Trigger the DMA transfer */
@@ -792,32 +814,26 @@ static void mmci_start_data(struct mmci_host *host, struct mmc_data *data)
        if (data->flags & MMC_DATA_READ)
                datactrl |= MCI_DPSM_DIRECTION;
 
-       /* The ST Micro variants has a special bit to enable SDIO */
-       if (variant->sdio && host->mmc->card)
-               if (mmc_card_sdio(host->mmc->card)) {
-                       /*
-                        * The ST Micro variants has a special bit
-                        * to enable SDIO.
-                        */
-                       u32 clk;
+       if (host->mmc->card && mmc_card_sdio(host->mmc->card)) {
+               u32 clk;
 
-                       datactrl |= MCI_ST_DPSM_SDIOEN;
+               datactrl |= variant->datactrl_mask_sdio;
 
-                       /*
-                        * The ST Micro variant for SDIO small write transfers
-                        * needs to have clock H/W flow control disabled,
-                        * otherwise the transfer will not start. The threshold
-                        * depends on the rate of MCLK.
-                        */
-                       if (data->flags & MMC_DATA_WRITE &&
-                           (host->size < 8 ||
-                            (host->size <= 8 && host->mclk > 50000000)))
-                               clk = host->clk_reg & ~variant->clkreg_enable;
-                       else
-                               clk = host->clk_reg | variant->clkreg_enable;
+               /*
+                * The ST Micro variant for SDIO small write transfers
+                * needs to have clock H/W flow control disabled,
+                * otherwise the transfer will not start. The threshold
+                * depends on the rate of MCLK.
+                */
+               if (variant->st_sdio && data->flags & MMC_DATA_WRITE &&
+                   (host->size < 8 ||
+                    (host->size <= 8 && host->mclk > 50000000)))
+                       clk = host->clk_reg & ~variant->clkreg_enable;
+               else
+                       clk = host->clk_reg | variant->clkreg_enable;
 
-                       mmci_write_clkreg(host, clk);
-               }
+               mmci_write_clkreg(host, clk);
+       }
 
        if (host->mmc->ios.timing == MMC_TIMING_UHS_DDR50 ||
            host->mmc->ios.timing == MMC_TIMING_MMC_DDR52)
@@ -1658,16 +1674,35 @@ static int mmci_probe(struct amba_device *dev,
        writel(0, host->base + MMCIMASK1);
        writel(0xfff, host->base + MMCICLEAR);
 
-       /* If DT, cd/wp gpios must be supplied through it. */
-       if (!np && gpio_is_valid(plat->gpio_cd)) {
-               ret = mmc_gpio_request_cd(mmc, plat->gpio_cd, 0);
-               if (ret)
-                       goto clk_disable;
-       }
-       if (!np && gpio_is_valid(plat->gpio_wp)) {
-               ret = mmc_gpio_request_ro(mmc, plat->gpio_wp);
-               if (ret)
-                       goto clk_disable;
+       /*
+        * If:
+        * - not using DT but using a descriptor table, or
+        * - using a table of descriptors ALONGSIDE DT, or
+        * look up these descriptors named "cd" and "wp" right here, fail
+        * silently of these do not exist and proceed to try platform data
+        */
+       if (!np) {
+               ret = mmc_gpiod_request_cd(mmc, "cd", 0, false, 0, NULL);
+               if (ret < 0) {
+                       if (ret == -EPROBE_DEFER)
+                               goto clk_disable;
+                       else if (gpio_is_valid(plat->gpio_cd)) {
+                               ret = mmc_gpio_request_cd(mmc, plat->gpio_cd, 0);
+                               if (ret)
+                                       goto clk_disable;
+                       }
+               }
+
+               ret = mmc_gpiod_request_ro(mmc, "wp", 0, false, 0, NULL);
+               if (ret < 0) {
+                       if (ret == -EPROBE_DEFER)
+                               goto clk_disable;
+                       else if (gpio_is_valid(plat->gpio_wp)) {
+                               ret = mmc_gpio_request_ro(mmc, plat->gpio_wp);
+                               if (ret)
+                                       goto clk_disable;
+                       }
+               }
        }
 
        ret = devm_request_irq(&dev->dev, dev->irq[0], mmci_irq, IRQF_SHARED,
diff --git a/drivers/mmc/host/mmci_qcom_dml.c b/drivers/mmc/host/mmci_qcom_dml.c
new file mode 100644 (file)
index 0000000..2b7fc37
--- /dev/null
@@ -0,0 +1,177 @@
+/*
+ *
+ * Copyright (c) 2011, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+#include <linux/of.h>
+#include <linux/of_dma.h>
+#include <linux/bitops.h>
+#include <linux/mmc/host.h>
+#include <linux/mmc/card.h>
+#include "mmci.h"
+
+/* Registers */
+#define DML_CONFIG                     0x00
+#define PRODUCER_CRCI_MSK              GENMASK(1, 0)
+#define PRODUCER_CRCI_DISABLE          0
+#define PRODUCER_CRCI_X_SEL            BIT(0)
+#define PRODUCER_CRCI_Y_SEL            BIT(1)
+#define CONSUMER_CRCI_MSK              GENMASK(3, 2)
+#define CONSUMER_CRCI_DISABLE          0
+#define CONSUMER_CRCI_X_SEL            BIT(2)
+#define CONSUMER_CRCI_Y_SEL            BIT(3)
+#define PRODUCER_TRANS_END_EN          BIT(4)
+#define BYPASS                         BIT(16)
+#define DIRECT_MODE                    BIT(17)
+#define INFINITE_CONS_TRANS            BIT(18)
+
+#define DML_SW_RESET                   0x08
+#define DML_PRODUCER_START             0x0c
+#define DML_CONSUMER_START             0x10
+#define DML_PRODUCER_PIPE_LOGICAL_SIZE 0x14
+#define DML_CONSUMER_PIPE_LOGICAL_SIZE 0x18
+#define DML_PIPE_ID                    0x1c
+#define PRODUCER_PIPE_ID_SHFT          0
+#define PRODUCER_PIPE_ID_MSK           GENMASK(4, 0)
+#define CONSUMER_PIPE_ID_SHFT          16
+#define CONSUMER_PIPE_ID_MSK           GENMASK(20, 16)
+
+#define DML_PRODUCER_BAM_BLOCK_SIZE    0x24
+#define DML_PRODUCER_BAM_TRANS_SIZE    0x28
+
+/* other definitions */
+#define PRODUCER_PIPE_LOGICAL_SIZE     4096
+#define CONSUMER_PIPE_LOGICAL_SIZE     4096
+
+#define DML_OFFSET                     0x800
+
+void dml_start_xfer(struct mmci_host *host, struct mmc_data *data)
+{
+       u32 config;
+       void __iomem *base = host->base + DML_OFFSET;
+
+       if (data->flags & MMC_DATA_READ) {
+               /* Read operation: configure DML for producer operation */
+               /* Set producer CRCI-x and disable consumer CRCI */
+               config = readl_relaxed(base + DML_CONFIG);
+               config = (config & ~PRODUCER_CRCI_MSK) | PRODUCER_CRCI_X_SEL;
+               config = (config & ~CONSUMER_CRCI_MSK) | CONSUMER_CRCI_DISABLE;
+               writel_relaxed(config, base + DML_CONFIG);
+
+               /* Set the Producer BAM block size */
+               writel_relaxed(data->blksz, base + DML_PRODUCER_BAM_BLOCK_SIZE);
+
+               /* Set Producer BAM Transaction size */
+               writel_relaxed(data->blocks * data->blksz,
+                              base + DML_PRODUCER_BAM_TRANS_SIZE);
+               /* Set Producer Transaction End bit */
+               config = readl_relaxed(base + DML_CONFIG);
+               config |= PRODUCER_TRANS_END_EN;
+               writel_relaxed(config, base + DML_CONFIG);
+               /* Trigger producer */
+               writel_relaxed(1, base + DML_PRODUCER_START);
+       } else {
+               /* Write operation: configure DML for consumer operation */
+               /* Set consumer CRCI-x and disable producer CRCI*/
+               config = readl_relaxed(base + DML_CONFIG);
+               config = (config & ~CONSUMER_CRCI_MSK) | CONSUMER_CRCI_X_SEL;
+               config = (config & ~PRODUCER_CRCI_MSK) | PRODUCER_CRCI_DISABLE;
+               writel_relaxed(config, base + DML_CONFIG);
+               /* Clear Producer Transaction End bit */
+               config = readl_relaxed(base + DML_CONFIG);
+               config &= ~PRODUCER_TRANS_END_EN;
+               writel_relaxed(config, base + DML_CONFIG);
+               /* Trigger consumer */
+               writel_relaxed(1, base + DML_CONSUMER_START);
+       }
+
+       /* make sure the dml is configured before dma is triggered */
+       wmb();
+}
+
+static int of_get_dml_pipe_index(struct device_node *np, const char *name)
+{
+       int index;
+       struct of_phandle_args  dma_spec;
+
+       index = of_property_match_string(np, "dma-names", name);
+
+       if (index < 0)
+               return -ENODEV;
+
+       if (of_parse_phandle_with_args(np, "dmas", "#dma-cells", index,
+                                      &dma_spec))
+               return -ENODEV;
+
+       if (dma_spec.args_count)
+               return dma_spec.args[0];
+
+       return -ENODEV;
+}
+
+/* Initialize the dml hardware connected to SD Card controller */
+int dml_hw_init(struct mmci_host *host, struct device_node *np)
+{
+       u32 config;
+       void __iomem *base;
+       int consumer_id, producer_id;
+
+       consumer_id = of_get_dml_pipe_index(np, "tx");
+       producer_id = of_get_dml_pipe_index(np, "rx");
+
+       if (producer_id < 0 || consumer_id < 0)
+               return -ENODEV;
+
+       base = host->base + DML_OFFSET;
+
+       /* Reset the DML block */
+       writel_relaxed(1, base + DML_SW_RESET);
+
+       /* Disable the producer and consumer CRCI */
+       config = (PRODUCER_CRCI_DISABLE | CONSUMER_CRCI_DISABLE);
+       /*
+        * Disable the bypass mode. Bypass mode will only be used
+        * if data transfer is to happen in PIO mode and don't
+        * want the BAM interface to connect with SDCC-DML.
+        */
+       config &= ~BYPASS;
+       /*
+        * Disable direct mode as we don't DML to MASTER the AHB bus.
+        * BAM connected with DML should MASTER the AHB bus.
+        */
+       config &= ~DIRECT_MODE;
+       /*
+        * Disable infinite mode transfer as we won't be doing any
+        * infinite size data transfers. All data transfer will be
+        * of finite data size.
+        */
+       config &= ~INFINITE_CONS_TRANS;
+       writel_relaxed(config, base + DML_CONFIG);
+
+       /*
+        * Initialize the logical BAM pipe size for producer
+        * and consumer.
+        */
+       writel_relaxed(PRODUCER_PIPE_LOGICAL_SIZE,
+                      base + DML_PRODUCER_PIPE_LOGICAL_SIZE);
+       writel_relaxed(CONSUMER_PIPE_LOGICAL_SIZE,
+                      base + DML_CONSUMER_PIPE_LOGICAL_SIZE);
+
+       /* Initialize Producer/consumer pipe id */
+       writel_relaxed(producer_id | (consumer_id << CONSUMER_PIPE_ID_SHFT),
+                      base + DML_PIPE_ID);
+
+       /* Make sure dml intialization is finished */
+       mb();
+
+       return 0;
+}
diff --git a/drivers/mmc/host/mmci_qcom_dml.h b/drivers/mmc/host/mmci_qcom_dml.h
new file mode 100644 (file)
index 0000000..6e405d0
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ *
+ * Copyright (c) 2011, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+#ifndef __MMC_QCOM_DML_H__
+#define __MMC_QCOM_DML_H__
+
+#ifdef CONFIG_MMC_QCOM_DML
+int dml_hw_init(struct mmci_host *host, struct device_node *np);
+void dml_start_xfer(struct mmci_host *host, struct mmc_data *data);
+#else
+static inline int dml_hw_init(struct mmci_host *host, struct device_node *np)
+{
+       return -ENOSYS;
+}
+static inline void dml_start_xfer(struct mmci_host *host, struct mmc_data *data)
+{
+}
+#endif /* CONFIG_MMC_QCOM_DML */
+
+#endif /* __MMC_QCOM_DML_H__ */
index b4b1efbf6c165c21aa1d8f1fe13e6bc9efb57f09..f3e18d08e8529e05e443395bfbf3cc73b1c3496a 100644 (file)
@@ -717,7 +717,6 @@ static struct platform_driver moxart_mmc_driver = {
        .remove     = moxart_remove,
        .driver     = {
                .name           = "mmc-moxart",
-               .owner          = THIS_MODULE,
                .of_match_table = moxart_mmc_match,
        },
 };
index ed1cb93c3784b54a62916e9aeb0540db2bf303e6..ad111422ad55b9dbbf3b83dacd0aaf33c286a204 100644 (file)
@@ -1238,7 +1238,6 @@ static struct platform_driver mxcmci_driver = {
        .id_table       = mxcmci_devtype,
        .driver         = {
                .name           = DRIVER_NAME,
-               .owner          = THIS_MODULE,
                .pm     = &mxcmci_pm_ops,
                .of_match_table = mxcmci_of_match,
        }
index 140885a5a4e734bbcb3806e39e7601503e1cf599..cd74e5143c36a2d2c90641e45723920364ca08b1 100644 (file)
@@ -735,7 +735,6 @@ static struct platform_driver mxs_mmc_driver = {
        .id_table       = mxs_ssp_ids,
        .driver         = {
                .name   = DRIVER_NAME,
-               .owner  = THIS_MODULE,
 #ifdef CONFIG_PM
                .pm     = &mxs_mmc_pm_ops,
 #endif
index 81974ecdfcbcb7a1649eee6eeab7a14dd8f49600..68dd6c79c378c8a355a36e23300eb996bfcbc720 100644 (file)
@@ -1494,7 +1494,6 @@ static struct platform_driver mmc_omap_driver = {
        .remove         = mmc_omap_remove,
        .driver         = {
                .name   = DRIVER_NAME,
-               .owner  = THIS_MODULE,
                .of_match_table = of_match_ptr(mmc_omap_match),
        },
 };
index 965672663ef066a3b2e58c5f1a2478c5becdfdda..df27bb4fc098b218a298e70493aa5c22131c7b52 100644 (file)
@@ -1829,7 +1829,17 @@ static int omap_hsmmc_disable_fclk(struct mmc_host *mmc)
        return 0;
 }
 
-static const struct mmc_host_ops omap_hsmmc_ops = {
+static int omap_hsmmc_multi_io_quirk(struct mmc_card *card,
+                                    unsigned int direction, int blk_size)
+{
+       /* This controller can't do multiblock reads due to hw bugs */
+       if (direction == MMC_DATA_READ)
+               return 1;
+
+       return blk_size;
+}
+
+static struct mmc_host_ops omap_hsmmc_ops = {
        .enable = omap_hsmmc_enable_fclk,
        .disable = omap_hsmmc_disable_fclk,
        .post_req = omap_hsmmc_post_req,
@@ -2101,7 +2111,7 @@ static int omap_hsmmc_probe(struct platform_device *pdev)
 
        if (host->pdata->controller_flags & OMAP_HSMMC_BROKEN_MULTIBLOCK_READ) {
                dev_info(&pdev->dev, "multiblock reads disabled due to 35xx erratum 2.1.1.128; MMC read performance may suffer\n");
-               mmc->caps2 |= MMC_CAP2_NO_MULTI_READ;
+               omap_hsmmc_ops.multi_io_quirk = omap_hsmmc_multi_io_quirk;
        }
 
        pm_runtime_enable(host->dev);
@@ -2489,7 +2499,6 @@ static struct platform_driver omap_hsmmc_driver = {
        .remove         = omap_hsmmc_remove,
        .driver         = {
                .name = DRIVER_NAME,
-               .owner = THIS_MODULE,
                .pm = &omap_hsmmc_dev_pm_ops,
                .of_match_table = of_match_ptr(omap_mmc_of_match),
        },
index 32fe11323f39e10bee30cac93daa0ba94e771939..1b6d0bfe35f53c2d474d884feda7c7b1271911c7 100644 (file)
@@ -474,7 +474,7 @@ static void pxamci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
                unsigned int clk = rate / ios->clock;
 
                if (host->clkrt == CLKRT_OFF)
-                       clk_enable(host->clk);
+                       clk_prepare_enable(host->clk);
 
                if (ios->clock == 26000000) {
                        /* to support 26MHz */
@@ -501,7 +501,7 @@ static void pxamci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
                pxamci_stop_clock(host);
                if (host->clkrt != CLKRT_OFF) {
                        host->clkrt = CLKRT_OFF;
-                       clk_disable(host->clk);
+                       clk_disable_unprepare(host->clk);
                }
        }
 
@@ -885,7 +885,6 @@ static struct platform_driver pxamci_driver = {
        .remove         = pxamci_remove,
        .driver         = {
                .name   = DRIVER_NAME,
-               .owner  = THIS_MODULE,
                .of_match_table = of_match_ptr(pxa_mmc_dt_ids),
        },
 };
index dfde4a21023864ae26aa68336001772d51e41209..c70b602f8f1ef435c9d7dcf1e31c9f3f570dc997 100644 (file)
@@ -412,6 +412,13 @@ static void sd_send_cmd_get_rsp(struct realtek_pci_sdmmc *host,
        }
 
        if (rsp_type == SD_RSP_TYPE_R2) {
+               /*
+                * The controller offloads the last byte {CRC-7, end bit 1'b1}
+                * of response type R2. Assign dummy CRC, 0, and end bit to the
+                * byte(ptr[16], goes into the LSB of resp[3] later).
+                */
+               ptr[16] = 1;
+
                for (i = 0; i < 4; i++) {
                        cmd->resp[i] = get_unaligned_be32(ptr + 1 + i * 4);
                        dev_dbg(sdmmc_dev(host), "cmd->resp[%d] = 0x%08x\n",
@@ -1292,6 +1299,7 @@ static void realtek_init_host(struct realtek_pci_sdmmc *host)
        mmc->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_SD_HIGHSPEED |
                MMC_CAP_MMC_HIGHSPEED | MMC_CAP_BUS_WIDTH_TEST |
                MMC_CAP_UHS_SDR12 | MMC_CAP_UHS_SDR25;
+       mmc->caps2 = MMC_CAP2_NO_PRESCAN_POWERUP | MMC_CAP2_FULL_PWR_CYCLE;
        mmc->max_current_330 = 400;
        mmc->max_current_180 = 800;
        mmc->ops = &realtek_pci_sdmmc_ops;
@@ -1416,7 +1424,6 @@ static struct platform_driver rtsx_pci_sdmmc_driver = {
        .remove         = rtsx_pci_sdmmc_drv_remove,
        .id_table       = rtsx_pci_sdmmc_ids,
        .driver         = {
-               .owner  = THIS_MODULE,
                .name   = DRV_NAME_RTSX_PCI_SDMMC,
        },
 };
index 5d3766e792f0855cd117b42fab7068e3c90a7726..88af827e086b9f66b5acbfe663cb8837b1d62d24 100644 (file)
@@ -435,6 +435,13 @@ static void sd_send_cmd_get_rsp(struct rtsx_usb_sdmmc *host,
        }
 
        if (rsp_type == SD_RSP_TYPE_R2) {
+               /*
+                * The controller offloads the last byte {CRC-7, end bit 1'b1}
+                * of response type R2. Assign dummy CRC, 0, and end bit to the
+                * byte(ptr[16], goes into the LSB of resp[3] later).
+                */
+               ptr[16] = 1;
+
                for (i = 0; i < 4; i++) {
                        cmd->resp[i] = get_unaligned_be32(ptr + 1 + i * 4);
                        dev_dbg(sdmmc_dev(host), "cmd->resp[%d] = 0x%08x\n",
@@ -1329,6 +1336,7 @@ static void rtsx_usb_init_host(struct rtsx_usb_sdmmc *host)
                MMC_CAP_MMC_HIGHSPEED | MMC_CAP_BUS_WIDTH_TEST |
                MMC_CAP_UHS_SDR12 | MMC_CAP_UHS_SDR25 | MMC_CAP_UHS_SDR50 |
                MMC_CAP_NEEDS_POLL;
+       mmc->caps2 = MMC_CAP2_NO_PRESCAN_POWERUP | MMC_CAP2_FULL_PWR_CYCLE;
 
        mmc->max_current_330 = 400;
        mmc->max_current_180 = 800;
@@ -1445,7 +1453,6 @@ static struct platform_driver rtsx_usb_sdmmc_driver = {
        .remove         = rtsx_usb_sdmmc_drv_remove,
        .id_table       = rtsx_usb_sdmmc_ids,
        .driver         = {
-               .owner  = THIS_MODULE,
                .name   = "rtsx_usb_sdmmc",
        },
 };
index e5516a226362dc0c4e98c39215bfe2c55f87b992..94cddf381ba3d72d1e9359afffb694f06dce6118 100644 (file)
@@ -985,7 +985,8 @@ static int s3cmci_setup_data(struct s3cmci_host *host, struct mmc_data *data)
                 * one block being transferred. */
 
                if (data->blocks > 1) {
-                       pr_warning("%s: can't do non-word sized block transfers (blksz %d)\n", __func__, data->blksz);
+                       pr_warn("%s: can't do non-word sized block transfers (blksz %d)\n",
+                               __func__, data->blksz);
                        return -EINVAL;
                }
        }
@@ -1874,7 +1875,6 @@ MODULE_DEVICE_TABLE(platform, s3cmci_driver_ids);
 static struct platform_driver s3cmci_driver = {
        .driver = {
                .name   = "s3c-sdi",
-               .owner  = THIS_MODULE,
        },
        .id_table       = s3cmci_driver_ids,
        .probe          = s3cmci_probe,
index 8c5337002c5137ec5658cc79f929c25f378ab0f8..9cccc0e89b0435928ca375d8b1640c5008cc6551 100644 (file)
@@ -67,6 +67,8 @@ struct sdhci_acpi_slot {
        unsigned int    caps2;
        mmc_pm_flag_t   pm_caps;
        unsigned int    flags;
+       int (*probe_slot)(struct platform_device *, const char *, const char *);
+       int (*remove_slot)(struct platform_device *);
 };
 
 struct sdhci_acpi_host {
@@ -122,13 +124,67 @@ static const struct sdhci_acpi_chip sdhci_acpi_chip_int = {
        .ops = &sdhci_acpi_ops_int,
 };
 
+static int sdhci_acpi_emmc_probe_slot(struct platform_device *pdev,
+                                     const char *hid, const char *uid)
+{
+       struct sdhci_acpi_host *c = platform_get_drvdata(pdev);
+       struct sdhci_host *host;
+
+       if (!c || !c->host)
+               return 0;
+
+       host = c->host;
+
+       /* Platform specific code during emmc proble slot goes here */
+
+       if (hid && uid && !strcmp(hid, "80860F14") && !strcmp(uid, "1") &&
+           sdhci_readl(host, SDHCI_CAPABILITIES) == 0x446cc8b2 &&
+           sdhci_readl(host, SDHCI_CAPABILITIES_1) == 0x00000807)
+               host->timeout_clk = 1000; /* 1000 kHz i.e. 1 MHz */
+
+       return 0;
+}
+
+static int sdhci_acpi_sdio_probe_slot(struct platform_device *pdev,
+                                     const char *hid, const char *uid)
+{
+       struct sdhci_acpi_host *c = platform_get_drvdata(pdev);
+       struct sdhci_host *host;
+
+       if (!c || !c->host)
+               return 0;
+
+       host = c->host;
+
+       /* Platform specific code during emmc proble slot goes here */
+
+       return 0;
+}
+
+static int sdhci_acpi_sd_probe_slot(struct platform_device *pdev,
+                                   const char *hid, const char *uid)
+{
+       struct sdhci_acpi_host *c = platform_get_drvdata(pdev);
+       struct sdhci_host *host;
+
+       if (!c || !c->host || !c->slot)
+               return 0;
+
+       host = c->host;
+
+       /* Platform specific code during emmc proble slot goes here */
+
+       return 0;
+}
+
 static const struct sdhci_acpi_slot sdhci_acpi_slot_int_emmc = {
        .chip    = &sdhci_acpi_chip_int,
        .caps    = MMC_CAP_8_BIT_DATA | MMC_CAP_NONREMOVABLE |
                   MMC_CAP_HW_RESET | MMC_CAP_1_8V_DDR,
        .caps2   = MMC_CAP2_HC_ERASE_SZ,
        .flags   = SDHCI_ACPI_RUNTIME_PM,
-       .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN,
+       .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN | SDHCI_QUIRK2_STOP_WITH_TC,
+       .probe_slot     = sdhci_acpi_emmc_probe_slot,
 };
 
 static const struct sdhci_acpi_slot sdhci_acpi_slot_int_sdio = {
@@ -137,12 +193,15 @@ static const struct sdhci_acpi_slot sdhci_acpi_slot_int_sdio = {
        .caps    = MMC_CAP_NONREMOVABLE | MMC_CAP_POWER_OFF_CARD,
        .flags   = SDHCI_ACPI_RUNTIME_PM,
        .pm_caps = MMC_PM_KEEP_POWER,
+       .probe_slot     = sdhci_acpi_sdio_probe_slot,
 };
 
 static const struct sdhci_acpi_slot sdhci_acpi_slot_int_sd = {
        .flags   = SDHCI_ACPI_SD_CD | SDHCI_ACPI_SD_CD_OVERRIDE_LEVEL |
                   SDHCI_ACPI_RUNTIME_PM,
-       .quirks2 = SDHCI_QUIRK2_CARD_ON_NEEDS_BUS_ON,
+       .quirks2 = SDHCI_QUIRK2_CARD_ON_NEEDS_BUS_ON |
+                  SDHCI_QUIRK2_STOP_WITH_TC,
+       .probe_slot     = sdhci_acpi_sd_probe_slot,
 };
 
 struct sdhci_acpi_uid_slot {
@@ -156,6 +215,7 @@ static const struct sdhci_acpi_uid_slot sdhci_acpi_uids[] = {
        { "80860F14" , "3" , &sdhci_acpi_slot_int_sd   },
        { "80860F16" , NULL, &sdhci_acpi_slot_int_sd   },
        { "INT33BB"  , "2" , &sdhci_acpi_slot_int_sdio },
+       { "INT33BB"  , "3" , &sdhci_acpi_slot_int_sd },
        { "INT33C6"  , NULL, &sdhci_acpi_slot_int_sdio },
        { "INT3436"  , NULL, &sdhci_acpi_slot_int_sdio },
        { "PNP0D40"  },
@@ -173,8 +233,8 @@ static const struct acpi_device_id sdhci_acpi_ids[] = {
 };
 MODULE_DEVICE_TABLE(acpi, sdhci_acpi_ids);
 
-static const struct sdhci_acpi_slot *sdhci_acpi_get_slot_by_ids(const char *hid,
-                                                               const char *uid)
+static const struct sdhci_acpi_slot *sdhci_acpi_get_slot(const char *hid,
+                                                        const char *uid)
 {
        const struct sdhci_acpi_uid_slot *u;
 
@@ -189,24 +249,6 @@ static const struct sdhci_acpi_slot *sdhci_acpi_get_slot_by_ids(const char *hid,
        return NULL;
 }
 
-static const struct sdhci_acpi_slot *sdhci_acpi_get_slot(acpi_handle handle,
-                                                        const char *hid)
-{
-       const struct sdhci_acpi_slot *slot;
-       struct acpi_device_info *info;
-       const char *uid = NULL;
-       acpi_status status;
-
-       status = acpi_get_object_info(handle, &info);
-       if (!ACPI_FAILURE(status) && (info->valid & ACPI_VALID_UID))
-               uid = info->unique_id.string;
-
-       slot = sdhci_acpi_get_slot_by_ids(hid, uid);
-
-       kfree(info);
-       return slot;
-}
-
 static int sdhci_acpi_probe(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
@@ -217,6 +259,7 @@ static int sdhci_acpi_probe(struct platform_device *pdev)
        struct resource *iomem;
        resource_size_t len;
        const char *hid;
+       const char *uid;
        int err;
 
        if (acpi_bus_get_device(handle, &device))
@@ -226,6 +269,7 @@ static int sdhci_acpi_probe(struct platform_device *pdev)
                return -ENODEV;
 
        hid = acpi_device_hid(device);
+       uid = device->pnp.unique_id;
 
        iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        if (!iomem)
@@ -244,7 +288,7 @@ static int sdhci_acpi_probe(struct platform_device *pdev)
 
        c = sdhci_priv(host);
        c->host = host;
-       c->slot = sdhci_acpi_get_slot(handle, hid);
+       c->slot = sdhci_acpi_get_slot(hid, uid);
        c->pdev = pdev;
        c->use_runtime_pm = sdhci_acpi_flag(c, SDHCI_ACPI_RUNTIME_PM);
 
@@ -277,6 +321,11 @@ static int sdhci_acpi_probe(struct platform_device *pdev)
        }
 
        if (c->slot) {
+               if (c->slot->probe_slot) {
+                       err = c->slot->probe_slot(pdev, hid, uid);
+                       if (err)
+                               goto err_free;
+               }
                if (c->slot->chip) {
                        host->ops            = c->slot->chip->ops;
                        host->quirks        |= c->slot->chip->quirks;
@@ -297,7 +346,7 @@ static int sdhci_acpi_probe(struct platform_device *pdev)
        if (sdhci_acpi_flag(c, SDHCI_ACPI_SD_CD)) {
                bool v = sdhci_acpi_flag(c, SDHCI_ACPI_SD_CD_OVERRIDE_LEVEL);
 
-               if (mmc_gpiod_request_cd(host->mmc, NULL, 0, v, 0)) {
+               if (mmc_gpiod_request_cd(host->mmc, NULL, 0, v, 0, NULL)) {
                        dev_warn(dev, "failed to setup card detect gpio\n");
                        c->use_runtime_pm = false;
                }
@@ -334,6 +383,9 @@ static int sdhci_acpi_remove(struct platform_device *pdev)
                pm_runtime_put_noidle(dev);
        }
 
+       if (c->slot && c->slot->remove_slot)
+               c->slot->remove_slot(pdev);
+
        dead = (sdhci_readl(c->host, SDHCI_INT_STATUS) == ~0);
        sdhci_remove_host(c->host, dead);
        sdhci_free_host(c->host);
@@ -385,20 +437,13 @@ static int sdhci_acpi_runtime_idle(struct device *dev)
        return 0;
 }
 
-#else
-
-#define sdhci_acpi_runtime_suspend     NULL
-#define sdhci_acpi_runtime_resume      NULL
-#define sdhci_acpi_runtime_idle                NULL
-
 #endif
 
 static const struct dev_pm_ops sdhci_acpi_pm_ops = {
        .suspend                = sdhci_acpi_suspend,
        .resume                 = sdhci_acpi_resume,
-       .runtime_suspend        = sdhci_acpi_runtime_suspend,
-       .runtime_resume         = sdhci_acpi_runtime_resume,
-       .runtime_idle           = sdhci_acpi_runtime_idle,
+       SET_RUNTIME_PM_OPS(sdhci_acpi_runtime_suspend,
+                       sdhci_acpi_runtime_resume, sdhci_acpi_runtime_idle)
 };
 
 static struct platform_driver sdhci_acpi_driver = {
index dd780c315a638edbfb90dbdae818472f927a0c5e..e7e4fbdcbfe021e248e91b25fce4eb0a3cf2a1ed 100644 (file)
@@ -225,7 +225,7 @@ static struct sdhci_pltfm_data sdhci_pltfm_data_kona = {
                SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN,
 };
 
-static struct __initconst of_device_id sdhci_bcm_kona_of_match[] = {
+static const struct of_device_id sdhci_bcm_kona_of_match[] = {
        { .compatible = "brcm,kona-sdhci"},
        { .compatible = "bcm,kona-sdhci"}, /* deprecated name */
        {}
@@ -359,7 +359,6 @@ static int sdhci_bcm_kona_remove(struct platform_device *pdev)
 static struct platform_driver sdhci_bcm_kona_driver = {
        .driver         = {
                .name   = "sdhci-kona",
-               .owner  = THIS_MODULE,
                .pm     = SDHCI_PLTFM_PMOPS,
                .of_match_table = sdhci_bcm_kona_of_match,
        },
index 46af9a439d7b48c772f68352253ba23641d756ea..439d259fdf1d571336fe86a3b3de483143430517 100644 (file)
@@ -194,7 +194,6 @@ MODULE_DEVICE_TABLE(of, bcm2835_sdhci_of_match);
 static struct platform_driver bcm2835_sdhci_driver = {
        .driver = {
                .name = "sdhci-bcm2835",
-               .owner = THIS_MODULE,
                .of_match_table = bcm2835_sdhci_of_match,
                .pm = SDHCI_PLTFM_PMOPS,
        },
index 14b74075589afd5b24ce594bb0b42adf7f5ae1cc..a7935a8d0922218f0874deea4e7f303a35dbb685 100644 (file)
@@ -106,7 +106,6 @@ static int sdhci_cns3xxx_remove(struct platform_device *pdev)
 static struct platform_driver sdhci_cns3xxx_driver = {
        .driver         = {
                .name   = "sdhci-cns3xxx",
-               .owner  = THIS_MODULE,
                .pm     = SDHCI_PLTFM_PMOPS,
        },
        .probe          = sdhci_cns3xxx_probe,
index e6278ec007d775c576346102e358426e08c3edbe..ca969d271a270bfb0bcb6e56fc3626f7398218a5 100644 (file)
@@ -146,7 +146,6 @@ MODULE_DEVICE_TABLE(of, sdhci_dove_of_match_table);
 static struct platform_driver sdhci_dove_driver = {
        .driver         = {
                .name   = "sdhci-dove",
-               .owner  = THIS_MODULE,
                .pm     = SDHCI_PLTFM_PMOPS,
                .of_match_table = sdhci_dove_of_match_table,
        },
index ccec0e32590f6b5f9336f0fc77df279e429756a2..587ee0edeb576b8ad2a25c0762d059afff8a1f2c 100644 (file)
@@ -880,6 +880,24 @@ static void esdhc_reset(struct sdhci_host *host, u8 mask)
        sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE);
 }
 
+static unsigned int esdhc_get_max_timeout_count(struct sdhci_host *host)
+{
+       struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+       struct pltfm_imx_data *imx_data = pltfm_host->priv;
+
+       return esdhc_is_usdhc(imx_data) ? 1 << 28 : 1 << 27;
+}
+
+static void esdhc_set_timeout(struct sdhci_host *host, struct mmc_command *cmd)
+{
+       struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+       struct pltfm_imx_data *imx_data = pltfm_host->priv;
+
+       /* use maximum timeout counter */
+       sdhci_writeb(host, esdhc_is_usdhc(imx_data) ? 0xF : 0xE,
+                       SDHCI_TIMEOUT_CONTROL);
+}
+
 static struct sdhci_ops sdhci_esdhc_ops = {
        .read_l = esdhc_readl_le,
        .read_w = esdhc_readw_le,
@@ -889,7 +907,9 @@ static struct sdhci_ops sdhci_esdhc_ops = {
        .set_clock = esdhc_pltfm_set_clock,
        .get_max_clock = esdhc_pltfm_get_max_clock,
        .get_min_clock = esdhc_pltfm_get_min_clock,
+       .get_max_timeout_count = esdhc_get_max_timeout_count,
        .get_ro = esdhc_pltfm_get_ro,
+       .set_timeout = esdhc_set_timeout,
        .set_bus_width = esdhc_pltfm_set_bus_width,
        .set_uhs_signaling = esdhc_set_uhs_signaling,
        .reset = esdhc_reset,
@@ -1207,7 +1227,6 @@ static const struct dev_pm_ops sdhci_esdhc_pmops = {
 static struct platform_driver sdhci_esdhc_imx_driver = {
        .driver         = {
                .name   = "sdhci-esdhc-imx",
-               .owner  = THIS_MODULE,
                .of_match_table = imx_esdhc_dt_ids,
                .pm     = &sdhci_esdhc_pmops,
        },
index 1a6661ed62050fda39cea0a57428abd2bb09e9e0..30804385af6dd02106045d7ef0109319ec5318a1 100644 (file)
 #define CMUX_SHIFT_PHASE_SHIFT 24
 #define CMUX_SHIFT_PHASE_MASK  (7 << CMUX_SHIFT_PHASE_SHIFT)
 
-static const u32 tuning_block_64[] = {
-       0x00ff0fff, 0xccc3ccff, 0xffcc3cc3, 0xeffefffe,
-       0xddffdfff, 0xfbfffbff, 0xff7fffbf, 0xefbdf777,
-       0xf0fff0ff, 0x3cccfc0f, 0xcfcc33cc, 0xeeffefff,
-       0xfdfffdff, 0xffbfffdf, 0xfff7ffbb, 0xde7b7ff7
-};
-
-static const u32 tuning_block_128[] = {
-       0xff00ffff, 0x0000ffff, 0xccccffff, 0xcccc33cc,
-       0xcc3333cc, 0xffffcccc, 0xffffeeff, 0xffeeeeff,
-       0xffddffff, 0xddddffff, 0xbbffffff, 0xbbffffff,
-       0xffffffbb, 0xffffff77, 0x77ff7777, 0xffeeddbb,
-       0x00ffffff, 0x00ffffff, 0xccffff00, 0xcc33cccc,
-       0x3333cccc, 0xffcccccc, 0xffeeffff, 0xeeeeffff,
-       0xddffffff, 0xddffffff, 0xffffffdd, 0xffffffbb,
-       0xffffbbbb, 0xffff77ff, 0xff7777ff, 0xeeddbb77
-};
-
 struct sdhci_msm_host {
        struct platform_device *pdev;
        void __iomem *core_mem; /* MSM SDCC mapped address */
@@ -358,8 +340,8 @@ static int sdhci_msm_execute_tuning(struct sdhci_host *host, u32 opcode)
 {
        int tuning_seq_cnt = 3;
        u8 phase, *data_buf, tuned_phases[16], tuned_phase_cnt = 0;
-       const u32 *tuning_block_pattern = tuning_block_64;
-       int size = sizeof(tuning_block_64);     /* Pattern size in bytes */
+       const u8 *tuning_block_pattern = tuning_blk_pattern_4bit;
+       int size = sizeof(tuning_blk_pattern_4bit);
        int rc;
        struct mmc_host *mmc = host->mmc;
        struct mmc_ios ios = host->mmc->ios;
@@ -375,8 +357,8 @@ static int sdhci_msm_execute_tuning(struct sdhci_host *host, u32 opcode)
 
        if ((opcode == MMC_SEND_TUNING_BLOCK_HS200) &&
            (mmc->ios.bus_width == MMC_BUS_WIDTH_8)) {
-               tuning_block_pattern = tuning_block_128;
-               size = sizeof(tuning_block_128);
+               tuning_block_pattern = tuning_blk_pattern_8bit;
+               size = sizeof(tuning_blk_pattern_8bit);
        }
 
        data_buf = kmalloc(size, GFP_KERNEL);
@@ -610,7 +592,6 @@ static struct platform_driver sdhci_msm_driver = {
        .remove = sdhci_msm_remove,
        .driver = {
                   .name = "sdhci_msm",
-                  .owner = THIS_MODULE,
                   .of_match_table = sdhci_msm_dt_match,
        },
 };
index 5bd1092310f2e6c1b742ce11e3b590119be66435..981d66e5c023147d99ae35a6e9e985e453800058 100644 (file)
@@ -213,7 +213,6 @@ MODULE_DEVICE_TABLE(of, sdhci_arasan_of_match);
 static struct platform_driver sdhci_arasan_driver = {
        .driver = {
                .name = "sdhci-arasan",
-               .owner = THIS_MODULE,
                .of_match_table = sdhci_arasan_of_match,
                .pm = &sdhci_arasan_dev_pm_ops,
        },
index 8be4dcfb49a05f12c2f2711323e321af8f529625..8872c85c63d4a9dc7e9bfddaefe28f7ab8e55fb2 100644 (file)
@@ -388,7 +388,6 @@ MODULE_DEVICE_TABLE(of, sdhci_esdhc_of_match);
 static struct platform_driver sdhci_esdhc_driver = {
        .driver = {
                .name = "sdhci-esdhc",
-               .owner = THIS_MODULE,
                .of_match_table = sdhci_esdhc_of_match,
                .pm = ESDHC_PMOPS,
        },
index b341661369a20a645ea3356e2d8a71cfb42a9ee0..be479279a1d55479bad67654e855fa71781678ea 100644 (file)
@@ -89,7 +89,6 @@ MODULE_DEVICE_TABLE(of, sdhci_hlwd_of_match);
 static struct platform_driver sdhci_hlwd_driver = {
        .driver = {
                .name = "sdhci-hlwd",
-               .owner = THIS_MODULE,
                .of_match_table = sdhci_hlwd_of_match,
                .pm = SDHCI_PLTFM_PMOPS,
        },
index c3a1debc9289860755a207cf1315ef544bdda21c..61192973e7cbaad1305c2ebea324f43e2506665a 100644 (file)
@@ -24,6 +24,7 @@
 #include <linux/io.h>
 #include <linux/gpio.h>
 #include <linux/pm_runtime.h>
+#include <linux/mmc/slot-gpio.h>
 #include <linux/mmc/sdhci-pci-data.h>
 
 #include "sdhci.h"
@@ -271,6 +272,8 @@ static int byt_emmc_probe_slot(struct sdhci_pci_slot *slot)
                                 MMC_CAP_HW_RESET | MMC_CAP_1_8V_DDR;
        slot->host->mmc->caps2 |= MMC_CAP2_HC_ERASE_SZ;
        slot->hw_reset = sdhci_pci_int_hw_reset;
+       if (slot->chip->pdev->device == PCI_DEVICE_ID_INTEL_BSW_EMMC)
+               slot->host->timeout_clk = 1000; /* 1000 kHz i.e. 1 MHz */
        return 0;
 }
 
@@ -280,22 +283,35 @@ static int byt_sdio_probe_slot(struct sdhci_pci_slot *slot)
        return 0;
 }
 
+static int byt_sd_probe_slot(struct sdhci_pci_slot *slot)
+{
+       slot->cd_con_id = NULL;
+       slot->cd_idx = 0;
+       slot->cd_override_level = true;
+       return 0;
+}
+
 static const struct sdhci_pci_fixes sdhci_intel_byt_emmc = {
        .allow_runtime_pm = true,
        .probe_slot     = byt_emmc_probe_slot,
-       .quirks2        = SDHCI_QUIRK2_PRESET_VALUE_BROKEN,
+       .quirks2        = SDHCI_QUIRK2_PRESET_VALUE_BROKEN |
+                         SDHCI_QUIRK2_STOP_WITH_TC,
 };
 
 static const struct sdhci_pci_fixes sdhci_intel_byt_sdio = {
-       .quirks2        = SDHCI_QUIRK2_HOST_OFF_CARD_ON,
+       .quirks2        = SDHCI_QUIRK2_HOST_OFF_CARD_ON |
+                       SDHCI_QUIRK2_PRESET_VALUE_BROKEN,
        .allow_runtime_pm = true,
        .probe_slot     = byt_sdio_probe_slot,
 };
 
 static const struct sdhci_pci_fixes sdhci_intel_byt_sd = {
-       .quirks2        = SDHCI_QUIRK2_CARD_ON_NEEDS_BUS_ON,
+       .quirks2        = SDHCI_QUIRK2_CARD_ON_NEEDS_BUS_ON |
+                         SDHCI_QUIRK2_PRESET_VALUE_BROKEN |
+                         SDHCI_QUIRK2_STOP_WITH_TC,
        .allow_runtime_pm = true,
        .own_cd_for_runtime_pm = true,
+       .probe_slot     = byt_sd_probe_slot,
 };
 
 /* Define Host controllers for Intel Merrifield platform */
@@ -317,7 +333,9 @@ static int intel_mrfl_mmc_probe_slot(struct sdhci_pci_slot *slot)
 
 static const struct sdhci_pci_fixes sdhci_intel_mrfl_mmc = {
        .quirks         = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC,
-       .quirks2        = SDHCI_QUIRK2_BROKEN_HS200,
+       .quirks2        = SDHCI_QUIRK2_BROKEN_HS200 |
+                       SDHCI_QUIRK2_PRESET_VALUE_BROKEN,
+       .allow_runtime_pm = true,
        .probe_slot     = intel_mrfl_mmc_probe_slot,
 };
 
@@ -876,6 +894,29 @@ static const struct pci_device_id pci_ids[] = {
                .driver_data    = (kernel_ulong_t)&sdhci_intel_byt_emmc,
        },
 
+       {
+               .vendor         = PCI_VENDOR_ID_INTEL,
+               .device         = PCI_DEVICE_ID_INTEL_BSW_EMMC,
+               .subvendor      = PCI_ANY_ID,
+               .subdevice      = PCI_ANY_ID,
+               .driver_data    = (kernel_ulong_t)&sdhci_intel_byt_emmc,
+       },
+
+       {
+               .vendor         = PCI_VENDOR_ID_INTEL,
+               .device         = PCI_DEVICE_ID_INTEL_BSW_SDIO,
+               .subvendor      = PCI_ANY_ID,
+               .subdevice      = PCI_ANY_ID,
+               .driver_data    = (kernel_ulong_t)&sdhci_intel_byt_sdio,
+       },
+
+       {
+               .vendor         = PCI_VENDOR_ID_INTEL,
+               .device         = PCI_DEVICE_ID_INTEL_BSW_SD,
+               .subvendor      = PCI_ANY_ID,
+               .subdevice      = PCI_ANY_ID,
+               .driver_data    = (kernel_ulong_t)&sdhci_intel_byt_sd,
+       },
 
        {
                .vendor         = PCI_VENDOR_ID_INTEL,
@@ -1269,20 +1310,13 @@ static int sdhci_pci_runtime_idle(struct device *dev)
        return 0;
 }
 
-#else
-
-#define sdhci_pci_runtime_suspend      NULL
-#define sdhci_pci_runtime_resume       NULL
-#define sdhci_pci_runtime_idle         NULL
-
 #endif
 
 static const struct dev_pm_ops sdhci_pci_pm_ops = {
        .suspend = sdhci_pci_suspend,
        .resume = sdhci_pci_resume,
-       .runtime_suspend = sdhci_pci_runtime_suspend,
-       .runtime_resume = sdhci_pci_runtime_resume,
-       .runtime_idle = sdhci_pci_runtime_idle,
+       SET_RUNTIME_PM_OPS(sdhci_pci_runtime_suspend,
+                       sdhci_pci_runtime_resume, sdhci_pci_runtime_idle)
 };
 
 /*****************************************************************************\
@@ -1332,6 +1366,7 @@ static struct sdhci_pci_slot *sdhci_pci_probe_slot(
        slot->pci_bar = bar;
        slot->rst_n_gpio = -EINVAL;
        slot->cd_gpio = -EINVAL;
+       slot->cd_idx = -1;
 
        /* Retrieve platform data if there is any */
        if (*sdhci_pci_get_data)
@@ -1390,6 +1425,13 @@ static struct sdhci_pci_slot *sdhci_pci_probe_slot(
        host->mmc->slotno = slotno;
        host->mmc->caps2 |= MMC_CAP2_NO_PRESCAN_POWERUP;
 
+       if (slot->cd_idx >= 0 &&
+           mmc_gpiod_request_cd(host->mmc, slot->cd_con_id, slot->cd_idx,
+                                slot->cd_override_level, 0, NULL)) {
+               dev_warn(&pdev->dev, "failed to setup card detect gpio\n");
+               slot->cd_idx = -1;
+       }
+
        ret = sdhci_add_host(host);
        if (ret)
                goto remove;
@@ -1402,7 +1444,7 @@ static struct sdhci_pci_slot *sdhci_pci_probe_slot(
         * Note sdhci_pci_add_own_cd() sets slot->cd_gpio to -EINVAL on failure.
         */
        if (chip->fixes && chip->fixes->own_cd_for_runtime_pm &&
-           !gpio_is_valid(slot->cd_gpio))
+           !gpio_is_valid(slot->cd_gpio) && slot->cd_idx < 0)
                chip->allow_runtime_pm = false;
 
        return slot;
index c101477ef3be28364b31b50c92c88dd72909e3d6..d57c3d169914e94e716b64b90e8b8da2b86afa87 100644 (file)
@@ -11,6 +11,9 @@
 #define PCI_DEVICE_ID_INTEL_BYT_SDIO   0x0f15
 #define PCI_DEVICE_ID_INTEL_BYT_SD     0x0f16
 #define PCI_DEVICE_ID_INTEL_BYT_EMMC2  0x0f50
+#define PCI_DEVICE_ID_INTEL_BSW_EMMC   0x2294
+#define PCI_DEVICE_ID_INTEL_BSW_SDIO   0x2295
+#define PCI_DEVICE_ID_INTEL_BSW_SD     0x2296
 #define PCI_DEVICE_ID_INTEL_MRFL_MMC   0x1190
 #define PCI_DEVICE_ID_INTEL_CLV_SDIO0  0x08f9
 #define PCI_DEVICE_ID_INTEL_CLV_SDIO1  0x08fa
@@ -61,6 +64,10 @@ struct sdhci_pci_slot {
        int                     cd_gpio;
        int                     cd_irq;
 
+       char                    *cd_con_id;
+       int                     cd_idx;
+       bool                    cd_override_level;
+
        void (*hw_reset)(struct sdhci_host *host);
 };
 
index 7e834fb78f427d2c085dce62956337d126e7e4f3..c5b01d6bb85d41fdf236473b4f2b25cae9ee68f5 100644 (file)
@@ -123,7 +123,6 @@ struct sdhci_host *sdhci_pltfm_init(struct platform_device *pdev,
                                    size_t priv_size)
 {
        struct sdhci_host *host;
-       struct device_node *np = pdev->dev.of_node;
        struct resource *iomem;
        int ret;
 
@@ -136,13 +135,8 @@ struct sdhci_host *sdhci_pltfm_init(struct platform_device *pdev,
        if (resource_size(iomem) < 0x100)
                dev_err(&pdev->dev, "Invalid iomem size!\n");
 
-       /* Some PCI-based MFD need the parent here */
-       if (pdev->dev.parent != &platform_bus && !np)
-               host = sdhci_alloc_host(pdev->dev.parent,
-                       sizeof(struct sdhci_pltfm_host) + priv_size);
-       else
-               host = sdhci_alloc_host(&pdev->dev,
-                       sizeof(struct sdhci_pltfm_host) + priv_size);
+       host = sdhci_alloc_host(&pdev->dev,
+               sizeof(struct sdhci_pltfm_host) + priv_size);
 
        if (IS_ERR(host)) {
                ret = PTR_ERR(host);
index 3c0f3c0a1cc86969f5f72dfaa27d6fdc2f083b58..b4c23e983baf221c62d81ba0f957d2674e3296a4 100644 (file)
@@ -261,7 +261,6 @@ static int sdhci_pxav2_remove(struct platform_device *pdev)
 static struct platform_driver sdhci_pxav2_driver = {
        .driver         = {
                .name   = "sdhci-pxav2",
-               .owner  = THIS_MODULE,
 #ifdef CONFIG_OF
                .of_match_table = sdhci_pxav2_of_match,
 #endif
index 6f842fb8e6b81834de13f0ffef3e19af2b9cb3a0..5036d7d39529a949d982e5814a9f4d010683a9a3 100644 (file)
@@ -224,12 +224,11 @@ static void pxav3_set_uhs_signaling(struct sdhci_host *host, unsigned int uhs)
 
 static const struct sdhci_ops pxav3_sdhci_ops = {
        .set_clock = sdhci_set_clock,
-       .set_uhs_signaling = pxav3_set_uhs_signaling,
        .platform_send_init_74_clocks = pxav3_gen_init_74_clocks,
        .get_max_clock = sdhci_pltfm_clk_get_max_clock,
        .set_bus_width = sdhci_set_bus_width,
        .reset = pxav3_reset,
-       .set_uhs_signaling = sdhci_set_uhs_signaling,
+       .set_uhs_signaling = pxav3_set_uhs_signaling,
 };
 
 static struct sdhci_pltfm_data sdhci_pxav3_pdata = {
@@ -381,11 +380,11 @@ static int sdhci_pxav3_probe(struct platform_device *pdev)
 
        return 0;
 
-err_of_parse:
-err_cd_req:
 err_add_host:
        pm_runtime_put_sync(&pdev->dev);
        pm_runtime_disable(&pdev->dev);
+err_of_parse:
+err_cd_req:
        clk_disable_unprepare(clk);
 err_clk_get:
 err_mbus_win:
@@ -492,7 +491,6 @@ static struct platform_driver sdhci_pxav3_driver = {
 #ifdef CONFIG_OF
                .of_match_table = sdhci_pxav3_of_match,
 #endif
-               .owner  = THIS_MODULE,
                .pm     = SDHCI_PXAV3_PMOPS,
        },
        .probe          = sdhci_pxav3_probe,
index fa5954a05449f9ae0116c1db1d486458674e8d0b..0ce6eb17deaf5b6361199ed2e8583f7bd72c5b56 100644 (file)
@@ -606,8 +606,6 @@ static int sdhci_s3c_probe(struct platform_device *pdev)
        ret = sdhci_add_host(host);
        if (ret) {
                dev_err(dev, "sdhci_add_host() failed\n");
-               pm_runtime_forbid(&pdev->dev);
-               pm_runtime_get_noresume(&pdev->dev);
                goto err_req_regs;
        }
 
@@ -618,6 +616,8 @@ static int sdhci_s3c_probe(struct platform_device *pdev)
        return 0;
 
  err_req_regs:
+       pm_runtime_disable(&pdev->dev);
+
  err_no_busclks:
        clk_disable_unprepare(sc->clk_io);
 
@@ -747,7 +747,6 @@ static struct platform_driver sdhci_s3c_driver = {
        .remove         = sdhci_s3c_remove,
        .id_table       = sdhci_s3c_driver_ids,
        .driver         = {
-               .owner  = THIS_MODULE,
                .name   = "s3c-sdhci",
                .of_match_table = of_match_ptr(sdhci_s3c_dt_match),
                .pm     = SDHCI_S3C_PMOPS,
index 17004531d089e6c2bce4fc33d319f6fdf3cb377f..dd29d47c07aa8168dec853de07bdc599508112ab 100644 (file)
@@ -15,6 +15,8 @@
 #include <linux/mmc/slot-gpio.h>
 #include "sdhci-pltfm.h"
 
+#define SDHCI_SIRF_8BITBUS BIT(3)
+
 struct sdhci_sirf_priv {
        struct clk *clk;
        int gpio_cd;
@@ -27,10 +29,30 @@ static unsigned int sdhci_sirf_get_max_clk(struct sdhci_host *host)
        return clk_get_rate(priv->clk);
 }
 
+static void sdhci_sirf_set_bus_width(struct sdhci_host *host, int width)
+{
+       u8 ctrl;
+
+       ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL);
+       ctrl &= ~(SDHCI_CTRL_4BITBUS | SDHCI_SIRF_8BITBUS);
+
+       /*
+        * CSR atlas7 and prima2 SD host version is not 3.0
+        * 8bit-width enable bit of CSR SD hosts is 3,
+        * while stardard hosts use bit 5
+        */
+       if (width == MMC_BUS_WIDTH_8)
+               ctrl |= SDHCI_SIRF_8BITBUS;
+       else if (width == MMC_BUS_WIDTH_4)
+               ctrl |= SDHCI_CTRL_4BITBUS;
+
+       sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
+}
+
 static struct sdhci_ops sdhci_sirf_ops = {
        .set_clock = sdhci_set_clock,
        .get_max_clock  = sdhci_sirf_get_max_clk,
-       .set_bus_width = sdhci_set_bus_width,
+       .set_bus_width = sdhci_sirf_set_bus_width,
        .reset = sdhci_reset,
        .set_uhs_signaling = sdhci_set_uhs_signaling,
 };
@@ -94,6 +116,7 @@ static int sdhci_sirf_probe(struct platform_device *pdev)
                                ret);
                        goto err_request_cd;
                }
+               mmc_gpiod_request_cd_irq(host->mmc);
        }
 
        return 0;
@@ -167,7 +190,6 @@ MODULE_DEVICE_TABLE(of, sdhci_sirf_of_match);
 static struct platform_driver sdhci_sirf_driver = {
        .driver         = {
                .name   = "sdhci-sirf",
-               .owner  = THIS_MODULE,
                .of_match_table = sdhci_sirf_of_match,
 #ifdef CONFIG_PM_SLEEP
                .pm     = &sdhci_sirf_pm_ops,
index 9d535c7336ef8425ab40bc6d6abea91553f17294..22e58268545f0b028ee3cd82d4fa7e50a49a4558 100644 (file)
@@ -230,7 +230,6 @@ MODULE_DEVICE_TABLE(of, sdhci_spear_id_table);
 static struct platform_driver sdhci_driver = {
        .driver = {
                .name   = "sdhci",
-               .owner  = THIS_MODULE,
                .pm     = &sdhci_pm_ops,
                .of_match_table = of_match_ptr(sdhci_spear_id_table),
        },
index 33100d10d17685b732279dc5c2d42b3f8950ee97..59797106af930c874eb0558ea368a5225ba2a461 100644 (file)
@@ -318,7 +318,6 @@ static int sdhci_tegra_remove(struct platform_device *pdev)
 static struct platform_driver sdhci_tegra_driver = {
        .driver         = {
                .name   = "sdhci-tegra",
-               .owner  = THIS_MODULE,
                .of_match_table = sdhci_tegra_dt_match,
                .pm     = SDHCI_PLTFM_PMOPS,
        },
index 37b2a9ae52eff16cd44649f42fb4822ff05c89db..ada1a3ea3a87122b7b6ca52c7397e338bc81128f 100644 (file)
@@ -707,19 +707,28 @@ static void sdhci_set_transfer_irqs(struct sdhci_host *host)
        sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE);
 }
 
-static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_command *cmd)
+static void sdhci_set_timeout(struct sdhci_host *host, struct mmc_command *cmd)
 {
        u8 count;
+
+       if (host->ops->set_timeout) {
+               host->ops->set_timeout(host, cmd);
+       } else {
+               count = sdhci_calc_timeout(host, cmd);
+               sdhci_writeb(host, count, SDHCI_TIMEOUT_CONTROL);
+       }
+}
+
+static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_command *cmd)
+{
        u8 ctrl;
        struct mmc_data *data = cmd->data;
        int ret;
 
        WARN_ON(host->data);
 
-       if (data || (cmd->flags & MMC_RSP_BUSY)) {
-               count = sdhci_calc_timeout(host, cmd);
-               sdhci_writeb(host, count, SDHCI_TIMEOUT_CONTROL);
-       }
+       if (data || (cmd->flags & MMC_RSP_BUSY))
+               sdhci_set_timeout(host, cmd);
 
        if (!data)
                return;
@@ -1007,6 +1016,7 @@ void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd)
        mod_timer(&host->timer, timeout);
 
        host->cmd = cmd;
+       host->busy_handle = 0;
 
        sdhci_prepare_data(host, cmd);
 
@@ -1194,7 +1204,6 @@ void sdhci_set_clock(struct sdhci_host *host, unsigned int clock)
 clock_set:
        if (real_div)
                host->mmc->actual_clock = (host->max_clk * clk_mul) / real_div;
-
        clk |= (div & SDHCI_DIV_MASK) << SDHCI_DIVIDER_SHIFT;
        clk |= ((div & SDHCI_DIV_HI_MASK) >> SDHCI_DIV_MASK_LEN)
                << SDHCI_DIVIDER_HI_SHIFT;
@@ -1357,11 +1366,12 @@ static void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq)
                present_state = sdhci_readl(host, SDHCI_PRESENT_STATE);
                /*
                 * Check if the re-tuning timer has already expired and there
-                * is no on-going data transfer. If so, we need to execute
-                * tuning procedure before sending command.
+                * is no on-going data transfer and DAT0 is not busy. If so,
+                * we need to execute tuning procedure before sending command.
                 */
                if ((host->flags & SDHCI_NEEDS_RETUNING) &&
-                   !(present_state & (SDHCI_DOING_WRITE | SDHCI_DOING_READ))) {
+                   !(present_state & (SDHCI_DOING_WRITE | SDHCI_DOING_READ)) &&
+                   (present_state & SDHCI_DATA_0_LVL_MASK)) {
                        if (mmc->card) {
                                /* eMMC uses cmd21 but sd and sdio use cmd19 */
                                tuning_opcode =
@@ -1471,6 +1481,18 @@ static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios)
        if (!ios->clock || ios->clock != host->clock) {
                host->ops->set_clock(host, ios->clock);
                host->clock = ios->clock;
+
+               if (host->quirks & SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK &&
+                   host->clock) {
+                       host->timeout_clk = host->mmc->actual_clock ?
+                                               host->mmc->actual_clock / 1000 :
+                                               host->clock / 1000;
+                       host->mmc->max_busy_timeout =
+                               host->ops->get_max_timeout_count ?
+                               host->ops->get_max_timeout_count(host) :
+                               1 << 27;
+                       host->mmc->max_busy_timeout /= host->timeout_clk;
+               }
        }
 
        sdhci_set_power(host, ios->power_mode, ios->vdd);
@@ -1733,8 +1755,8 @@ static int sdhci_do_start_signal_voltage_switch(struct sdhci_host *host,
                        ret = regulator_set_voltage(mmc->supply.vqmmc, 2700000,
                                                    3600000);
                        if (ret) {
-                               pr_warning("%s: Switching to 3.3V signalling voltage "
-                                               " failed\n", mmc_hostname(mmc));
+                               pr_warn("%s: Switching to 3.3V signalling voltage failed\n",
+                                       mmc_hostname(mmc));
                                return -EIO;
                        }
                }
@@ -1746,8 +1768,8 @@ static int sdhci_do_start_signal_voltage_switch(struct sdhci_host *host,
                if (!(ctrl & SDHCI_CTRL_VDD_180))
                        return 0;
 
-               pr_warning("%s: 3.3V regulator output did not became stable\n",
-                               mmc_hostname(mmc));
+               pr_warn("%s: 3.3V regulator output did not became stable\n",
+                       mmc_hostname(mmc));
 
                return -EAGAIN;
        case MMC_SIGNAL_VOLTAGE_180:
@@ -1755,8 +1777,8 @@ static int sdhci_do_start_signal_voltage_switch(struct sdhci_host *host,
                        ret = regulator_set_voltage(mmc->supply.vqmmc,
                                        1700000, 1950000);
                        if (ret) {
-                               pr_warning("%s: Switching to 1.8V signalling voltage "
-                                               " failed\n", mmc_hostname(mmc));
+                               pr_warn("%s: Switching to 1.8V signalling voltage failed\n",
+                                       mmc_hostname(mmc));
                                return -EIO;
                        }
                }
@@ -1773,8 +1795,8 @@ static int sdhci_do_start_signal_voltage_switch(struct sdhci_host *host,
                if (ctrl & SDHCI_CTRL_VDD_180)
                        return 0;
 
-               pr_warning("%s: 1.8V regulator output did not became stable\n",
-                               mmc_hostname(mmc));
+               pr_warn("%s: 1.8V regulator output did not became stable\n",
+                       mmc_hostname(mmc));
 
                return -EAGAIN;
        case MMC_SIGNAL_VOLTAGE_120:
@@ -1782,8 +1804,8 @@ static int sdhci_do_start_signal_voltage_switch(struct sdhci_host *host,
                        ret = regulator_set_voltage(mmc->supply.vqmmc, 1100000,
                                                    1300000);
                        if (ret) {
-                               pr_warning("%s: Switching to 1.2V signalling voltage "
-                                               " failed\n", mmc_hostname(mmc));
+                               pr_warn("%s: Switching to 1.2V signalling voltage failed\n",
+                                       mmc_hostname(mmc));
                                return -EIO;
                        }
                }
@@ -2203,7 +2225,7 @@ static void sdhci_tuning_timer(unsigned long data)
  *                                                                           *
 \*****************************************************************************/
 
-static void sdhci_cmd_irq(struct sdhci_host *host, u32 intmask)
+static void sdhci_cmd_irq(struct sdhci_host *host, u32 intmask, u32 *mask)
 {
        BUG_ON(intmask == 0);
 
@@ -2241,11 +2263,18 @@ static void sdhci_cmd_irq(struct sdhci_host *host, u32 intmask)
                if (host->cmd->data)
                        DBG("Cannot wait for busy signal when also "
                                "doing a data transfer");
-               else if (!(host->quirks & SDHCI_QUIRK_NO_BUSY_IRQ))
+               else if (!(host->quirks & SDHCI_QUIRK_NO_BUSY_IRQ)
+                               && !host->busy_handle) {
+                       /* Mark that command complete before busy is ended */
+                       host->busy_handle = 1;
                        return;
+               }
 
                /* The controller does not support the end-of-busy IRQ,
                 * fall through and take the SDHCI_INT_RESPONSE */
+       } else if ((host->quirks2 & SDHCI_QUIRK2_STOP_WITH_TC) &&
+                  host->cmd->opcode == MMC_STOP_TRANSMISSION && !host->data) {
+               *mask &= ~SDHCI_INT_DATA_END;
        }
 
        if (intmask & SDHCI_INT_RESPONSE)
@@ -2304,8 +2333,21 @@ static void sdhci_data_irq(struct sdhci_host *host, u32 intmask)
                 * above in sdhci_cmd_irq().
                 */
                if (host->cmd && (host->cmd->flags & MMC_RSP_BUSY)) {
+                       if (intmask & SDHCI_INT_DATA_TIMEOUT) {
+                               host->cmd->error = -ETIMEDOUT;
+                               tasklet_schedule(&host->finish_tasklet);
+                               return;
+                       }
                        if (intmask & SDHCI_INT_DATA_END) {
-                               sdhci_finish_command(host);
+                               /*
+                                * Some cards handle busy-end interrupt
+                                * before the command completed, so make
+                                * sure we do things in the proper order.
+                                */
+                               if (host->busy_handle)
+                                       sdhci_finish_command(host);
+                               else
+                                       host->busy_handle = 1;
                                return;
                        }
                }
@@ -2442,7 +2484,8 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id)
                }
 
                if (intmask & SDHCI_INT_CMD_MASK)
-                       sdhci_cmd_irq(host, intmask & SDHCI_INT_CMD_MASK);
+                       sdhci_cmd_irq(host, intmask & SDHCI_INT_CMD_MASK,
+                                     &intmask);
 
                if (intmask & SDHCI_INT_DATA_MASK)
                        sdhci_data_irq(host, intmask & SDHCI_INT_DATA_MASK);
@@ -2534,7 +2577,7 @@ void sdhci_enable_irq_wakeups(struct sdhci_host *host)
 }
 EXPORT_SYMBOL_GPL(sdhci_enable_irq_wakeups);
 
-void sdhci_disable_irq_wakeups(struct sdhci_host *host)
+static void sdhci_disable_irq_wakeups(struct sdhci_host *host)
 {
        u8 val;
        u8 mask = SDHCI_WAKE_ON_INSERT | SDHCI_WAKE_ON_REMOVE
@@ -2544,7 +2587,6 @@ void sdhci_disable_irq_wakeups(struct sdhci_host *host)
        val &= ~mask;
        sdhci_writeb(host, val, SDHCI_WAKE_UP_CONTROL);
 }
-EXPORT_SYMBOL_GPL(sdhci_disable_irq_wakeups);
 
 int sdhci_suspend_host(struct sdhci_host *host)
 {
@@ -2749,6 +2791,7 @@ int sdhci_add_host(struct sdhci_host *host)
        u32 caps[2] = {0, 0};
        u32 max_current_caps;
        unsigned int ocr_avail;
+       unsigned int override_timeout_clk;
        int ret;
 
        WARN_ON(host == NULL);
@@ -2762,6 +2805,8 @@ int sdhci_add_host(struct sdhci_host *host)
        if (debug_quirks2)
                host->quirks2 = debug_quirks2;
 
+       override_timeout_clk = host->timeout_clk;
+
        sdhci_do_reset(host, SDHCI_RESET_ALL);
 
        host->version = sdhci_readw(host, SDHCI_HOST_VERSION);
@@ -2807,8 +2852,7 @@ int sdhci_add_host(struct sdhci_host *host)
        if (host->flags & (SDHCI_USE_SDMA | SDHCI_USE_ADMA)) {
                if (host->ops->enable_dma) {
                        if (host->ops->enable_dma(host)) {
-                               pr_warning("%s: No suitable DMA "
-                                       "available. Falling back to PIO.\n",
+                               pr_warn("%s: No suitable DMA available - falling back to PIO\n",
                                        mmc_hostname(mmc));
                                host->flags &=
                                        ~(SDHCI_USE_SDMA | SDHCI_USE_ADMA);
@@ -2830,15 +2874,14 @@ int sdhci_add_host(struct sdhci_host *host)
                        dma_free_coherent(mmc_dev(mmc), ADMA_SIZE,
                                          host->adma_desc, host->adma_addr);
                        kfree(host->align_buffer);
-                       pr_warning("%s: Unable to allocate ADMA "
-                               "buffers. Falling back to standard DMA.\n",
+                       pr_warn("%s: Unable to allocate ADMA buffers - falling back to standard DMA\n",
                                mmc_hostname(mmc));
                        host->flags &= ~SDHCI_USE_ADMA;
                        host->adma_desc = NULL;
                        host->align_buffer = NULL;
                } else if (host->adma_addr & 3) {
-                       pr_warning("%s: unable to allocate aligned ADMA descriptor\n",
-                                  mmc_hostname(mmc));
+                       pr_warn("%s: unable to allocate aligned ADMA descriptor\n",
+                               mmc_hostname(mmc));
                        host->flags &= ~SDHCI_USE_ADMA;
                        dma_free_coherent(mmc_dev(mmc), ADMA_SIZE,
                                          host->adma_desc, host->adma_addr);
@@ -2908,25 +2951,30 @@ int sdhci_add_host(struct sdhci_host *host)
        } else
                mmc->f_min = host->max_clk / SDHCI_MAX_DIV_SPEC_200;
 
-       host->timeout_clk =
-               (caps[0] & SDHCI_TIMEOUT_CLK_MASK) >> SDHCI_TIMEOUT_CLK_SHIFT;
-       if (host->timeout_clk == 0) {
-               if (host->ops->get_timeout_clock) {
-                       host->timeout_clk = host->ops->get_timeout_clock(host);
-               } else if (!(host->quirks &
-                               SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK)) {
-                       pr_err("%s: Hardware doesn't specify timeout clock "
-                              "frequency.\n", mmc_hostname(mmc));
-                       return -ENODEV;
+       if (!(host->quirks & SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK)) {
+               host->timeout_clk = (caps[0] & SDHCI_TIMEOUT_CLK_MASK) >>
+                                       SDHCI_TIMEOUT_CLK_SHIFT;
+               if (host->timeout_clk == 0) {
+                       if (host->ops->get_timeout_clock) {
+                               host->timeout_clk =
+                                       host->ops->get_timeout_clock(host);
+                       } else {
+                               pr_err("%s: Hardware doesn't specify timeout clock frequency.\n",
+                                       mmc_hostname(mmc));
+                               return -ENODEV;
+                       }
                }
-       }
-       if (caps[0] & SDHCI_TIMEOUT_CLK_UNIT)
-               host->timeout_clk *= 1000;
 
-       if (host->quirks & SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK)
-               host->timeout_clk = mmc->f_max / 1000;
+               if (caps[0] & SDHCI_TIMEOUT_CLK_UNIT)
+                       host->timeout_clk *= 1000;
 
-       mmc->max_busy_timeout = (1 << 27) / host->timeout_clk;
+               mmc->max_busy_timeout = host->ops->get_max_timeout_count ?
+                       host->ops->get_max_timeout_count(host) : 1 << 27;
+               mmc->max_busy_timeout /= host->timeout_clk;
+       }
+
+       if (override_timeout_clk)
+               host->timeout_clk = override_timeout_clk;
 
        mmc->caps |= MMC_CAP_SDIO_IRQ | MMC_CAP_ERASE | MMC_CAP_CMD23;
        mmc->caps2 |= MMC_CAP2_SDIO_IRQ_NOTHREAD;
@@ -2998,8 +3046,13 @@ int sdhci_add_host(struct sdhci_host *host)
                /* SD3.0: SDR104 is supported so (for eMMC) the caps2
                 * field can be promoted to support HS200.
                 */
-               if (!(host->quirks2 & SDHCI_QUIRK2_BROKEN_HS200))
+               if (!(host->quirks2 & SDHCI_QUIRK2_BROKEN_HS200)) {
                        mmc->caps2 |= MMC_CAP2_HS200;
+                       if (IS_ERR(mmc->supply.vqmmc) ||
+                                       !regulator_is_supported_voltage
+                                       (mmc->supply.vqmmc, 1100000, 1300000))
+                               mmc->caps2 &= ~MMC_CAP2_HS200_1_2V_SDR;
+               }
        } else if (caps[1] & SDHCI_SUPPORT_SDR50)
                mmc->caps |= MMC_CAP_UHS_SDR50;
 
@@ -3049,7 +3102,7 @@ int sdhci_add_host(struct sdhci_host *host)
         */
        max_current_caps = sdhci_readl(host, SDHCI_MAX_CURRENT);
        if (!max_current_caps && !IS_ERR(mmc->supply.vmmc)) {
-               u32 curr = regulator_get_current_limit(mmc->supply.vmmc);
+               int curr = regulator_get_current_limit(mmc->supply.vmmc);
                if (curr > 0) {
 
                        /* convert to SDHCI_MAX_CURRENT format */
@@ -3158,8 +3211,8 @@ int sdhci_add_host(struct sdhci_host *host)
                mmc->max_blk_size = (caps[0] & SDHCI_MAX_BLOCK_MASK) >>
                                SDHCI_MAX_BLOCK_SHIFT;
                if (mmc->max_blk_size >= 3) {
-                       pr_warning("%s: Invalid maximum block size, "
-                               "assuming 512 bytes\n", mmc_hostname(mmc));
+                       pr_warn("%s: Invalid maximum block size, assuming 512 bytes\n",
+                               mmc_hostname(mmc));
                        mmc->max_blk_size = 0;
                }
        }
index 4a5cd5e3fa3eeb7a0992976c902b99bb29316584..31896a779d4ed07834026743ac9d87ad917bebb8 100644 (file)
@@ -72,6 +72,7 @@
 #define  SDHCI_WRITE_PROTECT   0x00080000
 #define  SDHCI_DATA_LVL_MASK   0x00F00000
 #define   SDHCI_DATA_LVL_SHIFT 20
+#define   SDHCI_DATA_0_LVL_MASK        0x00100000
 
 #define SDHCI_HOST_CONTROL     0x28
 #define  SDHCI_CTRL_LED                0x01
@@ -281,6 +282,9 @@ struct sdhci_ops {
        unsigned int    (*get_max_clock)(struct sdhci_host *host);
        unsigned int    (*get_min_clock)(struct sdhci_host *host);
        unsigned int    (*get_timeout_clock)(struct sdhci_host *host);
+       unsigned int    (*get_max_timeout_count)(struct sdhci_host *host);
+       void            (*set_timeout)(struct sdhci_host *host,
+                                      struct mmc_command *cmd);
        void            (*set_bus_width)(struct sdhci_host *host, int width);
        void (*platform_send_init_74_clocks)(struct sdhci_host *host,
                                             u8 power_mode);
index d11708c815d721ba7dd9626ff21a523331ac4392..7d9d6a3215210f537b1b6e46070b610320f80ff5 100644 (file)
@@ -1553,7 +1553,6 @@ static struct platform_driver sh_mmcif_driver = {
        .driver         = {
                .name   = DRIVER_NAME,
                .pm     = &sh_mmcif_dev_pm_ops,
-               .owner  = THIS_MODULE,
                .of_match_table = mmcif_of_match,
        },
 };
index 91058dabd11afdbe443633140f2732462709d024..a2e81a1ea6af19ddae959327d9503189ff228659 100644 (file)
@@ -39,6 +39,7 @@ struct sh_mobile_sdhi_of_data {
        unsigned long tmio_flags;
        unsigned long capabilities;
        unsigned long capabilities2;
+       dma_addr_t dma_rx_offset;
 };
 
 static const struct sh_mobile_sdhi_of_data sh_mobile_sdhi_of_cfg[] = {
@@ -48,14 +49,16 @@ static const struct sh_mobile_sdhi_of_data sh_mobile_sdhi_of_cfg[] = {
 };
 
 static const struct sh_mobile_sdhi_of_data of_rcar_gen1_compatible = {
-       .tmio_flags     = TMIO_MMC_HAS_IDLE_WAIT | TMIO_MMC_WRPROTECT_DISABLE,
+       .tmio_flags     = TMIO_MMC_HAS_IDLE_WAIT | TMIO_MMC_WRPROTECT_DISABLE |
+                         TMIO_MMC_CLK_ACTUAL,
        .capabilities   = MMC_CAP_SD_HIGHSPEED | MMC_CAP_SDIO_IRQ,
 };
 
 static const struct sh_mobile_sdhi_of_data of_rcar_gen2_compatible = {
-       .tmio_flags     = TMIO_MMC_HAS_IDLE_WAIT | TMIO_MMC_WRPROTECT_DISABLE,
+       .tmio_flags     = TMIO_MMC_HAS_IDLE_WAIT | TMIO_MMC_WRPROTECT_DISABLE |
+                         TMIO_MMC_CLK_ACTUAL,
        .capabilities   = MMC_CAP_SD_HIGHSPEED | MMC_CAP_SDIO_IRQ,
-       .capabilities2  = MMC_CAP2_NO_MULTI_READ,
+       .dma_rx_offset  = 0x2000,
 };
 
 static const struct of_device_id sh_mobile_sdhi_of_match[] = {
@@ -68,6 +71,9 @@ static const struct of_device_id sh_mobile_sdhi_of_match[] = {
        { .compatible = "renesas,sdhi-r8a7779", .data = &of_rcar_gen1_compatible, },
        { .compatible = "renesas,sdhi-r8a7790", .data = &of_rcar_gen2_compatible, },
        { .compatible = "renesas,sdhi-r8a7791", .data = &of_rcar_gen2_compatible, },
+       { .compatible = "renesas,sdhi-r8a7792", .data = &of_rcar_gen2_compatible, },
+       { .compatible = "renesas,sdhi-r8a7793", .data = &of_rcar_gen2_compatible, },
+       { .compatible = "renesas,sdhi-r8a7794", .data = &of_rcar_gen2_compatible, },
        {},
 };
 MODULE_DEVICE_TABLE(of, sh_mobile_sdhi_of_match);
@@ -132,6 +138,24 @@ static int sh_mobile_sdhi_write16_hook(struct tmio_mmc_host *host, int addr)
        return 0;
 }
 
+static int sh_mobile_sdhi_multi_io_quirk(struct mmc_card *card,
+                                        unsigned int direction, int blk_size)
+{
+       /*
+        * In Renesas controllers, when performing a
+        * multiple block read of one or two blocks,
+        * depending on the timing with which the
+        * response register is read, the response
+        * value may not be read properly.
+        * Use single block read for this HW bug
+        */
+       if ((direction == MMC_DATA_READ) &&
+           blk_size == 2)
+               return 1;
+
+       return blk_size;
+}
+
 static void sh_mobile_sdhi_cd_wakeup(const struct platform_device *pdev)
 {
        mmc_detect_change(platform_get_drvdata(pdev), msecs_to_jiffies(100));
@@ -187,6 +211,7 @@ static int sh_mobile_sdhi_probe(struct platform_device *pdev)
        mmc_data->clk_disable = sh_mobile_sdhi_clk_disable;
        mmc_data->capabilities = MMC_CAP_MMC_HIGHSPEED;
        mmc_data->write16_hook = sh_mobile_sdhi_write16_hook;
+       mmc_data->multi_io_quirk = sh_mobile_sdhi_multi_io_quirk;
        if (p) {
                mmc_data->flags = p->tmio_flags;
                mmc_data->ocr_mask = p->tmio_ocr_mask;
@@ -223,11 +248,27 @@ static int sh_mobile_sdhi_probe(struct platform_device *pdev)
         */
        mmc_data->flags |= TMIO_MMC_SDIO_IRQ;
 
+       /*
+        * All SDHI have CMD12 controll bit
+        */
+       mmc_data->flags |= TMIO_MMC_HAVE_CMD12_CTRL;
+
+       /*
+        * All SDHI need SDIO_INFO1 reserved bit
+        */
+       mmc_data->flags |= TMIO_MMC_SDIO_STATUS_QUIRK;
+
+       /*
+        * All SDHI have DMA control register
+        */
+       mmc_data->flags |= TMIO_MMC_HAVE_CTL_DMA_REG;
+
        if (of_id && of_id->data) {
                const struct sh_mobile_sdhi_of_data *of_data = of_id->data;
                mmc_data->flags |= of_data->tmio_flags;
                mmc_data->capabilities |= of_data->capabilities;
                mmc_data->capabilities2 |= of_data->capabilities2;
+               dma_priv->dma_rx_offset = of_data->dma_rx_offset;
        }
 
        /* SD control register space size is 0x100, 0x200 for bus_shift=1 */
@@ -332,8 +373,9 @@ static int sh_mobile_sdhi_remove(struct platform_device *pdev)
 }
 
 static const struct dev_pm_ops tmio_mmc_dev_pm_ops = {
-       SET_SYSTEM_SLEEP_PM_OPS(tmio_mmc_host_suspend, tmio_mmc_host_resume)
-       SET_RUNTIME_PM_OPS(tmio_mmc_host_runtime_suspend,
+       SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
+                       pm_runtime_force_resume)
+       SET_PM_RUNTIME_PM_OPS(tmio_mmc_host_runtime_suspend,
                        tmio_mmc_host_runtime_resume,
                        NULL)
 };
@@ -341,7 +383,6 @@ static const struct dev_pm_ops tmio_mmc_dev_pm_ops = {
 static struct platform_driver sh_mobile_sdhi_driver = {
        .driver         = {
                .name   = "sh_mobile_sdhi",
-               .owner  = THIS_MODULE,
                .pm     = &tmio_mmc_dev_pm_ops,
                .of_match_table = sh_mobile_sdhi_of_match,
        },
index 024f67c98cdcad3b741e3b5ec39ad8b17a670d8c..d1663b3c41436fc4cb4a7f172364644c08cbaad5 100644 (file)
@@ -990,7 +990,8 @@ static int sunxi_mmc_probe(struct platform_device *pdev)
        /* 400kHz ~ 50MHz */
        mmc->f_min              =   400000;
        mmc->f_max              = 50000000;
-       mmc->caps              |= MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED;
+       mmc->caps              |= MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED |
+                                 MMC_CAP_ERASE;
 
        ret = mmc_of_parse(mmc);
        if (ret)
@@ -1035,7 +1036,6 @@ static int sunxi_mmc_remove(struct platform_device *pdev)
 static struct platform_driver sunxi_mmc_driver = {
        .driver = {
                .name   = "sunxi-mmc",
-               .owner  = THIS_MODULE,
                .of_match_table = of_match_ptr(sunxi_mmc_of_match),
        },
        .probe          = sunxi_mmc_probe,
index d1760ebcac0359e6e25273ac849f4c89f60f6b2b..93c4b40df90a78bfcb16375d3669436112fa77a7 100644 (file)
@@ -952,8 +952,8 @@ static int tifm_sd_probe(struct tifm_dev *sock)
 
        if (!(TIFM_SOCK_STATE_OCCUPIED
              & readl(sock->addr + SOCK_PRESENT_STATE))) {
-               pr_warning("%s : card gone, unexpectedly\n",
-                      dev_name(&sock->dev));
+               pr_warn("%s : card gone, unexpectedly\n",
+                       dev_name(&sock->dev));
                return rc;
        }
 
index cfad844730d80195ff63172c3f69aed3e3fe1155..659028ddb8b17e052721b0c8e9791ffbf598cd19 100644 (file)
@@ -30,7 +30,7 @@ static int tmio_mmc_suspend(struct device *dev)
        const struct mfd_cell *cell = mfd_get_cell(pdev);
        int ret;
 
-       ret = tmio_mmc_host_suspend(dev);
+       ret = pm_runtime_force_suspend(dev);
 
        /* Tell MFD core it can disable us now.*/
        if (!ret && cell->disable)
@@ -50,7 +50,7 @@ static int tmio_mmc_resume(struct device *dev)
                ret = cell->resume(pdev);
 
        if (!ret)
-               ret = tmio_mmc_host_resume(dev);
+               ret = pm_runtime_force_resume(dev);
 
        return ret;
 }
@@ -135,6 +135,9 @@ static int tmio_mmc_remove(struct platform_device *pdev)
 
 static const struct dev_pm_ops tmio_mmc_dev_pm_ops = {
        SET_SYSTEM_SLEEP_PM_OPS(tmio_mmc_suspend, tmio_mmc_resume)
+       SET_PM_RUNTIME_PM_OPS(tmio_mmc_host_runtime_suspend,
+                       tmio_mmc_host_runtime_resume,
+                       NULL)
 };
 
 static struct platform_driver tmio_mmc_driver = {
index 100ffe0b2faf932399f3e47af4e61167b7a706ad..a34ecbe1c1ad62c0d8c4b3d5ed7010a3df770020 100644 (file)
 
 struct tmio_mmc_data;
 
-/*
- * We differentiate between the following 3 power states:
- * 1. card slot powered off, controller stopped. This is used, when either there
- *    is no card in the slot, or the card really has to be powered down.
- * 2. card slot powered on, controller stopped. This is used, when a card is in
- *    the slot, but no activity is currently taking place. This is a power-
- *    saving mode with card-state preserved. This state can be entered, e.g.
- *    when MMC clock-gating is used.
- * 3. card slot powered on, controller running. This is the actual active state.
- */
-enum tmio_mmc_power {
-       TMIO_MMC_OFF_STOP,      /* card power off, controller stopped */
-       TMIO_MMC_ON_STOP,       /* card power on, controller stopped */
-       TMIO_MMC_ON_RUN,        /* card power on, controller running */
-};
-
 struct tmio_mmc_host {
        void __iomem *ctl;
        struct mmc_command      *cmd;
@@ -63,9 +47,6 @@ struct tmio_mmc_host {
        struct mmc_data         *data;
        struct mmc_host         *mmc;
 
-       /* Controller and card power state */
-       enum tmio_mmc_power     power;
-
        /* Callbacks for clock / power control */
        void (*set_pwr)(struct platform_device *host, int state);
        void (*set_clk_div)(struct platform_device *host, int state);
@@ -92,15 +73,16 @@ struct tmio_mmc_host {
        struct delayed_work     delayed_reset_work;
        struct work_struct      done;
 
-       /* Cache IRQ mask */
+       /* Cache */
        u32                     sdcard_irq_mask;
        u32                     sdio_irq_mask;
+       unsigned int            clk_cache;
 
        spinlock_t              lock;           /* protect host private data */
        unsigned long           last_req_ts;
        struct mutex            ios_lock;       /* protect set_ios() context */
        bool                    native_hotplug;
-       bool                    resuming;
+       bool                    sdio_irq_enabled;
 };
 
 int tmio_mmc_host_probe(struct tmio_mmc_host **host,
@@ -162,12 +144,7 @@ static inline void tmio_mmc_abort_dma(struct tmio_mmc_host *host)
 }
 #endif
 
-#ifdef CONFIG_PM_SLEEP
-int tmio_mmc_host_suspend(struct device *dev);
-int tmio_mmc_host_resume(struct device *dev);
-#endif
-
-#ifdef CONFIG_PM_RUNTIME
+#ifdef CONFIG_PM
 int tmio_mmc_host_runtime_suspend(struct device *dev);
 int tmio_mmc_host_runtime_resume(struct device *dev);
 #endif
index eb8f1d5c34b157f51c01210a273bf2c81257ac2d..7d077388b9eb48010bafd28a171addc461f163b6 100644 (file)
@@ -28,10 +28,8 @@ void tmio_mmc_enable_dma(struct tmio_mmc_host *host, bool enable)
        if (!host->chan_tx || !host->chan_rx)
                return;
 
-#if defined(CONFIG_SUPERH) || defined(CONFIG_ARCH_SHMOBILE)
-       /* Switch DMA mode on or off - SuperH specific? */
-       sd_ctrl_write16(host, CTL_DMA_ENABLE, enable ? 2 : 0);
-#endif
+       if (host->pdata->flags & TMIO_MMC_HAVE_CTL_DMA_REG)
+               sd_ctrl_write16(host, CTL_DMA_ENABLE, enable ? 2 : 0);
 }
 
 void tmio_mmc_abort_dma(struct tmio_mmc_host *host)
@@ -312,7 +310,7 @@ void tmio_mmc_request_dma(struct tmio_mmc_host *host, struct tmio_mmc_data *pdat
                if (pdata->dma->chan_priv_rx)
                        cfg.slave_id = pdata->dma->slave_id_rx;
                cfg.direction = DMA_DEV_TO_MEM;
-               cfg.src_addr = cfg.dst_addr;
+               cfg.src_addr = cfg.dst_addr + pdata->dma->dma_rx_offset;
                cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
                cfg.dst_addr = 0;
                ret = dmaengine_slave_config(host->chan_rx, &cfg);
index faf0924e71cb1d08a1fbe10645f713f8524a2bf8..250bf8c9f9986e47f498f6e127e32b02c9835f21 100644 (file)
@@ -44,6 +44,7 @@
 #include <linux/pm_qos.h>
 #include <linux/pm_runtime.h>
 #include <linux/regulator/consumer.h>
+#include <linux/mmc/sdio.h>
 #include <linux/scatterlist.h>
 #include <linux/spinlock.h>
 #include <linux/workqueue.h>
@@ -129,19 +130,28 @@ static void tmio_mmc_enable_sdio_irq(struct mmc_host *mmc, int enable)
 {
        struct tmio_mmc_host *host = mmc_priv(mmc);
 
-       if (enable) {
+       if (enable && !host->sdio_irq_enabled) {
+               /* Keep device active while SDIO irq is enabled */
+               pm_runtime_get_sync(mmc_dev(mmc));
+               host->sdio_irq_enabled = true;
+
                host->sdio_irq_mask = TMIO_SDIO_MASK_ALL &
                                        ~TMIO_SDIO_STAT_IOIRQ;
                sd_ctrl_write16(host, CTL_TRANSACTION_CTL, 0x0001);
                sd_ctrl_write16(host, CTL_SDIO_IRQ_MASK, host->sdio_irq_mask);
-       } else {
+       } else if (!enable && host->sdio_irq_enabled) {
                host->sdio_irq_mask = TMIO_SDIO_MASK_ALL;
                sd_ctrl_write16(host, CTL_SDIO_IRQ_MASK, host->sdio_irq_mask);
                sd_ctrl_write16(host, CTL_TRANSACTION_CTL, 0x0000);
+
+               host->sdio_irq_enabled = false;
+               pm_runtime_mark_last_busy(mmc_dev(mmc));
+               pm_runtime_put_autosuspend(mmc_dev(mmc));
        }
 }
 
-static void tmio_mmc_set_clock(struct tmio_mmc_host *host, int new_clock)
+static void tmio_mmc_set_clock(struct tmio_mmc_host *host,
+                               unsigned int new_clock)
 {
        u32 clk = 0, clock;
 
@@ -149,7 +159,11 @@ static void tmio_mmc_set_clock(struct tmio_mmc_host *host, int new_clock)
                for (clock = host->mmc->f_min, clk = 0x80000080;
                        new_clock >= (clock<<1); clk >>= 1)
                        clock <<= 1;
-               clk |= 0x100;
+
+               /* 1/1 clock is option */
+               if ((host->pdata->flags & TMIO_MMC_CLK_ACTUAL) &&
+                   ((clk >> 22) & 0x1))
+                       clk |= 0xff;
        }
 
        if (host->set_clk_div)
@@ -245,6 +259,9 @@ static void tmio_mmc_reset_work(struct work_struct *work)
 
        tmio_mmc_abort_dma(host);
        mmc_request_done(host->mmc, mrq);
+
+       pm_runtime_mark_last_busy(mmc_dev(host->mmc));
+       pm_runtime_put_autosuspend(mmc_dev(host->mmc));
 }
 
 /* called with host->lock held, interrupts disabled */
@@ -274,6 +291,9 @@ static void tmio_mmc_finish_request(struct tmio_mmc_host *host)
                tmio_mmc_abort_dma(host);
 
        mmc_request_done(host->mmc, mrq);
+
+       pm_runtime_mark_last_busy(mmc_dev(host->mmc));
+       pm_runtime_put_autosuspend(mmc_dev(host->mmc));
 }
 
 static void tmio_mmc_done_work(struct work_struct *work)
@@ -295,6 +315,7 @@ static void tmio_mmc_done_work(struct work_struct *work)
 #define TRANSFER_READ  0x1000
 #define TRANSFER_MULTI 0x2000
 #define SECURITY_CMD   0x4000
+#define NO_CMD12_ISSUE 0x4000 /* TMIO_MMC_HAVE_CMD12_CTRL */
 
 static int tmio_mmc_start_command(struct tmio_mmc_host *host, struct mmc_command *cmd)
 {
@@ -331,6 +352,14 @@ static int tmio_mmc_start_command(struct tmio_mmc_host *host, struct mmc_command
                if (data->blocks > 1) {
                        sd_ctrl_write16(host, CTL_STOP_INTERNAL_ACTION, 0x100);
                        c |= TRANSFER_MULTI;
+
+                       /*
+                        * Disable auto CMD12 at IO_RW_EXTENDED when
+                        * multiple block transfer
+                        */
+                       if ((host->pdata->flags & TMIO_MMC_HAVE_CMD12_CTRL) &&
+                           (cmd->opcode == SD_IO_RW_EXTENDED))
+                               c |= NO_CMD12_ISSUE;
                }
                if (data->flags & MMC_DATA_READ)
                        c |= TRANSFER_READ;
@@ -347,6 +376,40 @@ static int tmio_mmc_start_command(struct tmio_mmc_host *host, struct mmc_command
        return 0;
 }
 
+static void tmio_mmc_transfer_data(struct tmio_mmc_host *host,
+                                  unsigned short *buf,
+                                  unsigned int count)
+{
+       int is_read = host->data->flags & MMC_DATA_READ;
+       u8  *buf8;
+
+       /*
+        * Transfer the data
+        */
+       if (is_read)
+               sd_ctrl_read16_rep(host, CTL_SD_DATA_PORT, buf, count >> 1);
+       else
+               sd_ctrl_write16_rep(host, CTL_SD_DATA_PORT, buf, count >> 1);
+
+       /* if count was even number */
+       if (!(count & 0x1))
+               return;
+
+       /* if count was odd number */
+       buf8 = (u8 *)(buf + (count >> 1));
+
+       /*
+        * FIXME
+        *
+        * driver and this function are assuming that
+        * it is used as little endian
+        */
+       if (is_read)
+               *buf8 = sd_ctrl_read16(host, CTL_SD_DATA_PORT) & 0xff;
+       else
+               sd_ctrl_write16(host, CTL_SD_DATA_PORT, *buf8);
+}
+
 /*
  * This chip always returns (at least?) as much data as you ask for.
  * I'm unsure what happens if you ask for less than a block. This should be
@@ -379,10 +442,7 @@ static void tmio_mmc_pio_irq(struct tmio_mmc_host *host)
                 count, host->sg_off, data->flags);
 
        /* Transfer the data */
-       if (data->flags & MMC_DATA_READ)
-               sd_ctrl_read16_rep(host, CTL_SD_DATA_PORT, buf, count >> 1);
-       else
-               sd_ctrl_write16_rep(host, CTL_SD_DATA_PORT, buf, count >> 1);
+       tmio_mmc_transfer_data(host, buf, count);
 
        host->sg_off += count;
 
@@ -465,6 +525,9 @@ static void tmio_mmc_data_irq(struct tmio_mmc_host *host)
                goto out;
 
        if (host->chan_tx && (data->flags & MMC_DATA_WRITE) && !host->force_pio) {
+               u32 status = sd_ctrl_read32(host, CTL_STATUS);
+               bool done = false;
+
                /*
                 * Has all data been written out yet? Testing on SuperH showed,
                 * that in most cases the first interrupt comes already with the
@@ -473,7 +536,15 @@ static void tmio_mmc_data_irq(struct tmio_mmc_host *host)
                 * DATAEND interrupt with the BUSY bit set, in this cases
                 * waiting for one more interrupt fixes the problem.
                 */
-               if (!(sd_ctrl_read32(host, CTL_STATUS) & TMIO_STAT_CMD_BUSY)) {
+               if (host->pdata->flags & TMIO_MMC_HAS_IDLE_WAIT) {
+                       if (status & TMIO_STAT_ILL_FUNC)
+                               done = true;
+               } else {
+                       if (!(status & TMIO_STAT_CMD_BUSY))
+                               done = true;
+               }
+
+               if (done) {
                        tmio_mmc_disable_mmc_irqs(host, TMIO_STAT_DATAEND);
                        tasklet_schedule(&host->dma_complete);
                }
@@ -557,6 +628,9 @@ static void tmio_mmc_card_irq_status(struct tmio_mmc_host *host,
 
        pr_debug_status(*status);
        pr_debug_status(*ireg);
+
+       /* Clear the status except the interrupt status */
+       sd_ctrl_write32(host, CTL_STATUS, TMIO_MASK_IRQ);
 }
 
 static bool __tmio_mmc_card_detect_irq(struct tmio_mmc_host *host,
@@ -637,6 +711,7 @@ irqreturn_t tmio_mmc_sdio_irq(int irq, void *devid)
        struct mmc_host *mmc = host->mmc;
        struct tmio_mmc_data *pdata = host->pdata;
        unsigned int ireg, status;
+       unsigned int sdio_status;
 
        if (!(pdata->flags & TMIO_MMC_SDIO_IRQ))
                return IRQ_HANDLED;
@@ -644,7 +719,11 @@ irqreturn_t tmio_mmc_sdio_irq(int irq, void *devid)
        status = sd_ctrl_read16(host, CTL_SDIO_STATUS);
        ireg = status & TMIO_SDIO_MASK_ALL & ~host->sdcard_irq_mask;
 
-       sd_ctrl_write16(host, CTL_SDIO_STATUS, status & ~TMIO_SDIO_MASK_ALL);
+       sdio_status = status & ~TMIO_SDIO_MASK_ALL;
+       if (pdata->flags & TMIO_MMC_SDIO_STATUS_QUIRK)
+               sdio_status |= 6;
+
+       sd_ctrl_write16(host, CTL_SDIO_STATUS, sdio_status);
 
        if (mmc->caps & MMC_CAP_SDIO_IRQ && ireg & TMIO_SDIO_STAT_IOIRQ)
                mmc_signal_sdio_irq(mmc);
@@ -728,6 +807,8 @@ static void tmio_mmc_request(struct mmc_host *mmc, struct mmc_request *mrq)
 
        spin_unlock_irqrestore(&host->lock, flags);
 
+       pm_runtime_get_sync(mmc_dev(mmc));
+
        if (mrq->data) {
                ret = tmio_mmc_start_data(host, mrq->data);
                if (ret)
@@ -746,11 +827,14 @@ fail:
        host->mrq = NULL;
        mrq->cmd->error = ret;
        mmc_request_done(mmc, mrq);
+
+       pm_runtime_mark_last_busy(mmc_dev(mmc));
+       pm_runtime_put_autosuspend(mmc_dev(mmc));
 }
 
-static int tmio_mmc_clk_update(struct mmc_host *mmc)
+static int tmio_mmc_clk_update(struct tmio_mmc_host *host)
 {
-       struct tmio_mmc_host *host = mmc_priv(mmc);
+       struct mmc_host *mmc = host->mmc;
        struct tmio_mmc_data *pdata = host->pdata;
        int ret;
 
@@ -812,6 +896,19 @@ static void tmio_mmc_power_off(struct tmio_mmc_host *host)
                host->set_pwr(host->pdev, 0);
 }
 
+static void tmio_mmc_set_bus_width(struct tmio_mmc_host *host,
+                               unsigned char bus_width)
+{
+       switch (bus_width) {
+       case MMC_BUS_WIDTH_1:
+               sd_ctrl_write16(host, CTL_SD_MEM_CARD_OPT, 0x80e0);
+               break;
+       case MMC_BUS_WIDTH_4:
+               sd_ctrl_write16(host, CTL_SD_MEM_CARD_OPT, 0x00e0);
+               break;
+       }
+}
+
 /* Set MMC clock / power.
  * Note: This controller uses a simple divider scheme therefore it cannot
  * run a MMC card at full speed (20MHz). The max clock is 24MHz on SD, but as
@@ -824,6 +921,8 @@ static void tmio_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
        struct device *dev = &host->pdev->dev;
        unsigned long flags;
 
+       pm_runtime_get_sync(mmc_dev(mmc));
+
        mutex_lock(&host->ios_lock);
 
        spin_lock_irqsave(&host->lock, flags);
@@ -850,60 +949,22 @@ static void tmio_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
 
        spin_unlock_irqrestore(&host->lock, flags);
 
-       /*
-        * host->power toggles between false and true in both cases - either
-        * or not the controller can be runtime-suspended during inactivity.
-        * But if the controller has to be kept on, the runtime-pm usage_count
-        * is kept positive, so no suspending actually takes place.
-        */
-       if (ios->power_mode == MMC_POWER_ON && ios->clock) {
-               if (host->power != TMIO_MMC_ON_RUN) {
-                       tmio_mmc_clk_update(mmc);
-                       pm_runtime_get_sync(dev);
-                       if (host->resuming) {
-                               tmio_mmc_reset(host);
-                               host->resuming = false;
-                       }
-               }
-               if (host->power == TMIO_MMC_OFF_STOP)
-                       tmio_mmc_reset(host);
+       switch (ios->power_mode) {
+       case MMC_POWER_OFF:
+               tmio_mmc_power_off(host);
+               tmio_mmc_clk_stop(host);
+               break;
+       case MMC_POWER_UP:
                tmio_mmc_set_clock(host, ios->clock);
-               if (host->power == TMIO_MMC_OFF_STOP)
-                       /* power up SD card and the bus */
-                       tmio_mmc_power_on(host, ios->vdd);
-               host->power = TMIO_MMC_ON_RUN;
-               /* start bus clock */
+               tmio_mmc_power_on(host, ios->vdd);
                tmio_mmc_clk_start(host);
-       } else if (ios->power_mode != MMC_POWER_UP) {
-               struct tmio_mmc_data *pdata = host->pdata;
-               unsigned int old_power = host->power;
-
-               if (old_power != TMIO_MMC_OFF_STOP) {
-                       if (ios->power_mode == MMC_POWER_OFF) {
-                               tmio_mmc_power_off(host);
-                               host->power = TMIO_MMC_OFF_STOP;
-                       } else {
-                               host->power = TMIO_MMC_ON_STOP;
-                       }
-               }
-
-               if (old_power == TMIO_MMC_ON_RUN) {
-                       tmio_mmc_clk_stop(host);
-                       pm_runtime_put(dev);
-                       if (pdata->clk_disable)
-                               pdata->clk_disable(host->pdev);
-               }
-       }
-
-       if (host->power != TMIO_MMC_OFF_STOP) {
-               switch (ios->bus_width) {
-               case MMC_BUS_WIDTH_1:
-                       sd_ctrl_write16(host, CTL_SD_MEM_CARD_OPT, 0x80e0);
+               tmio_mmc_set_bus_width(host, ios->bus_width);
                break;
-               case MMC_BUS_WIDTH_4:
-                       sd_ctrl_write16(host, CTL_SD_MEM_CARD_OPT, 0x00e0);
+       case MMC_POWER_ON:
+               tmio_mmc_set_clock(host, ios->clock);
+               tmio_mmc_clk_start(host);
+               tmio_mmc_set_bus_width(host, ios->bus_width);
                break;
-               }
        }
 
        /* Let things settle. delay taken from winCE driver */
@@ -915,7 +976,12 @@ static void tmio_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
                        ios->clock, ios->power_mode);
        host->mrq = NULL;
 
+       host->clk_cache = ios->clock;
+
        mutex_unlock(&host->ios_lock);
+
+       pm_runtime_mark_last_busy(mmc_dev(mmc));
+       pm_runtime_put_autosuspend(mmc_dev(mmc));
 }
 
 static int tmio_mmc_get_ro(struct mmc_host *mmc)
@@ -926,8 +992,25 @@ static int tmio_mmc_get_ro(struct mmc_host *mmc)
        if (ret >= 0)
                return ret;
 
-       return !((pdata->flags & TMIO_MMC_WRPROTECT_DISABLE) ||
-                (sd_ctrl_read32(host, CTL_STATUS) & TMIO_STAT_WRPROTECT));
+       pm_runtime_get_sync(mmc_dev(mmc));
+       ret = !((pdata->flags & TMIO_MMC_WRPROTECT_DISABLE) ||
+               (sd_ctrl_read32(host, CTL_STATUS) & TMIO_STAT_WRPROTECT));
+       pm_runtime_mark_last_busy(mmc_dev(mmc));
+       pm_runtime_put_autosuspend(mmc_dev(mmc));
+
+       return ret;
+}
+
+static int tmio_multi_io_quirk(struct mmc_card *card,
+                              unsigned int direction, int blk_size)
+{
+       struct tmio_mmc_host *host = mmc_priv(card->host);
+       struct tmio_mmc_data *pdata = host->pdata;
+
+       if (pdata->multi_io_quirk)
+               return pdata->multi_io_quirk(card, direction, blk_size);
+
+       return blk_size;
 }
 
 static const struct mmc_host_ops tmio_mmc_ops = {
@@ -936,6 +1019,7 @@ static const struct mmc_host_ops tmio_mmc_ops = {
        .get_ro         = tmio_mmc_get_ro,
        .get_cd         = mmc_gpio_get_cd,
        .enable_sdio_irq = tmio_mmc_enable_sdio_irq,
+       .multi_io_quirk = tmio_multi_io_quirk,
 };
 
 static int tmio_mmc_init_ocr(struct tmio_mmc_host *host)
@@ -1032,28 +1116,23 @@ int tmio_mmc_host_probe(struct tmio_mmc_host **host,
                                  mmc->caps & MMC_CAP_NONREMOVABLE ||
                                  mmc->slot.cd_irq >= 0);
 
-       _host->power = TMIO_MMC_OFF_STOP;
-       pm_runtime_enable(&pdev->dev);
-       ret = pm_runtime_resume(&pdev->dev);
-       if (ret < 0)
-               goto pm_disable;
-
-       if (tmio_mmc_clk_update(mmc) < 0) {
+       if (tmio_mmc_clk_update(_host) < 0) {
                mmc->f_max = pdata->hclk;
                mmc->f_min = mmc->f_max / 512;
        }
 
        /*
-        * There are 4 different scenarios for the card detection:
-        *  1) an external gpio irq handles the cd (best for power savings)
-        *  2) internal sdhi irq handles the cd
-        *  3) a worker thread polls the sdhi - indicated by MMC_CAP_NEEDS_POLL
-        *  4) the medium is non-removable - indicated by MMC_CAP_NONREMOVABLE
-        *
-        *  While we increment the runtime PM counter for all scenarios when
-        *  the mmc core activates us by calling an appropriate set_ios(), we
-        *  must additionally ensure that in case 2) the tmio mmc hardware stays
-        *  powered on during runtime for the card detection to work.
+        * Check the sanity of mmc->f_min to prevent tmio_mmc_set_clock() from
+        * looping forever...
+        */
+       if (mmc->f_min == 0) {
+               ret = -EINVAL;
+               goto host_free;
+       }
+
+       /*
+        * While using internal tmio hardware logic for card detection, we need
+        * to ensure it stays powered for it to work.
         */
        if (_host->native_hotplug)
                pm_runtime_get_noresume(&pdev->dev);
@@ -1074,8 +1153,12 @@ int tmio_mmc_host_probe(struct tmio_mmc_host **host,
 
        _host->sdcard_irq_mask &= ~irq_mask;
 
-       if (pdata->flags & TMIO_MMC_SDIO_IRQ)
-               tmio_mmc_enable_sdio_irq(mmc, 0);
+       _host->sdio_irq_enabled = false;
+       if (pdata->flags & TMIO_MMC_SDIO_IRQ) {
+               _host->sdio_irq_mask = TMIO_SDIO_MASK_ALL;
+               sd_ctrl_write16(_host, CTL_SDIO_IRQ_MASK, _host->sdio_irq_mask);
+               sd_ctrl_write16(_host, CTL_TRANSACTION_CTL, 0x0000);
+       }
 
        spin_lock_init(&_host->lock);
        mutex_init(&_host->ios_lock);
@@ -1087,9 +1170,12 @@ int tmio_mmc_host_probe(struct tmio_mmc_host **host,
        /* See if we also get DMA */
        tmio_mmc_request_dma(_host, pdata);
 
+       pm_runtime_set_active(&pdev->dev);
+       pm_runtime_set_autosuspend_delay(&pdev->dev, 50);
+       pm_runtime_use_autosuspend(&pdev->dev);
+       pm_runtime_enable(&pdev->dev);
+
        ret = mmc_add_host(mmc);
-       if (pdata->clk_disable)
-               pdata->clk_disable(pdev);
        if (ret < 0) {
                tmio_mmc_host_remove(_host);
                return ret;
@@ -1103,15 +1189,13 @@ int tmio_mmc_host_probe(struct tmio_mmc_host **host,
                        tmio_mmc_host_remove(_host);
                        return ret;
                }
+               mmc_gpiod_request_cd_irq(mmc);
        }
 
        *host = _host;
 
        return 0;
 
-pm_disable:
-       pm_runtime_disable(&pdev->dev);
-       iounmap(_host->ctl);
 host_free:
        mmc_free_host(mmc);
 
@@ -1142,34 +1226,20 @@ void tmio_mmc_host_remove(struct tmio_mmc_host *host)
 }
 EXPORT_SYMBOL(tmio_mmc_host_remove);
 
-#ifdef CONFIG_PM_SLEEP
-int tmio_mmc_host_suspend(struct device *dev)
+#ifdef CONFIG_PM
+int tmio_mmc_host_runtime_suspend(struct device *dev)
 {
        struct mmc_host *mmc = dev_get_drvdata(dev);
        struct tmio_mmc_host *host = mmc_priv(mmc);
 
        tmio_mmc_disable_mmc_irqs(host, TMIO_MASK_ALL);
-       return 0;
-}
-EXPORT_SYMBOL(tmio_mmc_host_suspend);
-
-int tmio_mmc_host_resume(struct device *dev)
-{
-       struct mmc_host *mmc = dev_get_drvdata(dev);
-       struct tmio_mmc_host *host = mmc_priv(mmc);
 
-       tmio_mmc_enable_dma(host, true);
+       if (host->clk_cache)
+               tmio_mmc_clk_stop(host);
 
-       /* The MMC core will perform the complete set up */
-       host->resuming = true;
-       return 0;
-}
-EXPORT_SYMBOL(tmio_mmc_host_resume);
-#endif
+       if (host->pdata->clk_disable)
+               host->pdata->clk_disable(host->pdev);
 
-#ifdef CONFIG_PM_RUNTIME
-int tmio_mmc_host_runtime_suspend(struct device *dev)
-{
        return 0;
 }
 EXPORT_SYMBOL(tmio_mmc_host_runtime_suspend);
@@ -1179,6 +1249,14 @@ int tmio_mmc_host_runtime_resume(struct device *dev)
        struct mmc_host *mmc = dev_get_drvdata(dev);
        struct tmio_mmc_host *host = mmc_priv(mmc);
 
+       tmio_mmc_reset(host);
+       tmio_mmc_clk_update(host);
+
+       if (host->clk_cache) {
+               tmio_mmc_set_clock(host, host->clk_cache);
+               tmio_mmc_clk_start(host);
+       }
+
        tmio_mmc_enable_dma(host, true);
 
        return 0;
index 1defd5ed323668780846c6fe85041dec6205c20a..9a6dfb0c4eccb54f2afa8514f6e5ded1dab9f202 100644 (file)
@@ -803,8 +803,7 @@ static void wbsd_request(struct mmc_host *mmc, struct mmc_request *mrq)
 
                default:
 #ifdef CONFIG_MMC_DEBUG
-                       pr_warning("%s: Data command %d is not "
-                               "supported by this controller.\n",
+                       pr_warn("%s: Data command %d is not supported by this controller\n",
                                mmc_hostname(host->mmc), cmd->opcode);
 #endif
                        cmd->error = -EINVAL;
@@ -1429,8 +1428,8 @@ free:
        free_dma(dma);
 
 err:
-       pr_warning(DRIVER_NAME ": Unable to allocate DMA %d. "
-               "Falling back on FIFO.\n", dma);
+       pr_warn(DRIVER_NAME ": Unable to allocate DMA %d - falling back on FIFO\n",
+               dma);
 }
 
 static void wbsd_release_dma(struct wbsd_host *host)
@@ -1664,9 +1663,7 @@ static int wbsd_init(struct device *dev, int base, int irq, int dma,
        ret = wbsd_scan(host);
        if (ret) {
                if (pnp && (ret == -ENODEV)) {
-                       pr_warning(DRIVER_NAME
-                               ": Unable to confirm device presence. You may "
-                               "experience lock-ups.\n");
+                       pr_warn(DRIVER_NAME ": Unable to confirm device presence - you may experience lock-ups\n");
                } else {
                        wbsd_free_mmc(dev);
                        return ret;
@@ -1688,10 +1685,7 @@ static int wbsd_init(struct device *dev, int base, int irq, int dma,
         */
        if (pnp) {
                if ((host->config != 0) && !wbsd_chip_validate(host)) {
-                       pr_warning(DRIVER_NAME
-                               ": PnP active but chip not configured! "
-                               "You probably have a buggy BIOS. "
-                               "Configuring chip manually.\n");
+                       pr_warn(DRIVER_NAME ": PnP active but chip not configured! You probably have a buggy BIOS. Configuring chip manually.\n");
                        wbsd_chip_config(host);
                }
        } else
@@ -1884,10 +1878,7 @@ static int wbsd_pnp_resume(struct pnp_dev *pnp_dev)
         */
        if (host->config != 0) {
                if (!wbsd_chip_validate(host)) {
-                       pr_warning(DRIVER_NAME
-                               ": PnP active but chip not configured! "
-                               "You probably have a buggy BIOS. "
-                               "Configuring chip manually.\n");
+                       pr_warn(DRIVER_NAME ": PnP active but chip not configured! You probably have a buggy BIOS. Configuring chip manually.\n");
                        wbsd_chip_config(host);
                }
        }
index 33c64955d4d7b3e4bd1d9fc09b08b42b1113db34..8876c7d3d712fe267cbd96239cfd0cbc12e20056 100644 (file)
@@ -188,8 +188,9 @@ static int ubiblock_read_to_buf(struct ubiblock *dev, char *buffer,
 
        ret = ubi_read(dev->desc, leb, buffer, offset, len);
        if (ret) {
-               ubi_err("%s ubi_read error %d",
-                       dev->gd->disk_name, ret);
+               ubi_err("%s: error %d while reading from LEB %d (offset %d, "
+                       "length %d)", dev->gd->disk_name, ret, leb, offset,
+                       len);
                return ret;
        }
        return 0;
@@ -378,7 +379,7 @@ int ubiblock_create(struct ubi_volume_info *vi)
 {
        struct ubiblock *dev;
        struct gendisk *gd;
-       u64 disk_capacity = ((u64)vi->size * vi->usable_leb_size) >> 9;
+       u64 disk_capacity = vi->used_bytes >> 9;
        int ret;
 
        if ((sector_t)disk_capacity != disk_capacity)
@@ -502,13 +503,8 @@ int ubiblock_remove(struct ubi_volume_info *vi)
 static int ubiblock_resize(struct ubi_volume_info *vi)
 {
        struct ubiblock *dev;
-       u64 disk_capacity = ((u64)vi->size * vi->usable_leb_size) >> 9;
+       u64 disk_capacity = vi->used_bytes >> 9;
 
-       if ((sector_t)disk_capacity != disk_capacity) {
-               ubi_warn("%s: the volume is too big, cannot resize (%d LEBs)",
-                        dev->gd->disk_name, vi->size);
-               return -EFBIG;
-       }
        /*
         * Need to lock the device list until we stop using the device,
         * otherwise the device struct might get released in
@@ -520,10 +516,20 @@ static int ubiblock_resize(struct ubi_volume_info *vi)
                mutex_unlock(&devices_mutex);
                return -ENODEV;
        }
+       if ((sector_t)disk_capacity != disk_capacity) {
+               mutex_unlock(&devices_mutex);
+               ubi_warn("%s: the volume is too big (%d LEBs), cannot resize",
+                        dev->gd->disk_name, vi->size);
+               return -EFBIG;
+       }
 
        mutex_lock(&dev->dev_mutex);
-       set_capacity(dev->gd, disk_capacity);
-       ubi_msg("%s resized to %d LEBs", dev->gd->disk_name, vi->size);
+
+       if (get_capacity(dev->gd) != disk_capacity) {
+               set_capacity(dev->gd, disk_capacity);
+               ubi_msg("%s resized to %lld bytes", dev->gd->disk_name,
+                       vi->used_bytes);
+       }
        mutex_unlock(&dev->dev_mutex);
        mutex_unlock(&devices_mutex);
        return 0;
@@ -547,6 +553,14 @@ static int ubiblock_notify(struct notifier_block *nb,
        case UBI_VOLUME_RESIZED:
                ubiblock_resize(&nt->vi);
                break;
+       case UBI_VOLUME_UPDATED:
+               /*
+                * If the volume is static, a content update might mean the
+                * size (i.e. used_bytes) was also changed.
+                */
+               if (nt->vi.vol_type == UBI_STATIC_VOLUME)
+                       ubiblock_resize(&nt->vi);
+               break;
        default:
                break;
        }
index 7646220ca6e26dd4d687d6cca32de24d7d526977..59de69a24e406ca2c0fbc0fd34c2561e8696279c 100644 (file)
@@ -425,8 +425,10 @@ static long vol_cdev_ioctl(struct file *file, unsigned int cmd,
                        break;
 
                err = ubi_start_update(ubi, vol, bytes);
-               if (bytes == 0)
+               if (bytes == 0) {
+                       ubi_volume_notify(ubi, vol, UBI_VOLUME_UPDATED);
                        revoke_exclusive(desc, UBI_READWRITE);
+               }
                break;
        }
 
@@ -699,7 +701,7 @@ static int rename_volumes(struct ubi_device *ubi,
                req->ents[i].name[req->ents[i].name_len] = '\0';
                n = strlen(req->ents[i].name);
                if (n != req->ents[i].name_len)
-                       err = -EINVAL;
+                       return -EINVAL;
        }
 
        /* Make sure volume IDs and names are unique */
index 0e11671dadc48c129c3f9cd669c8cf7c9ec5bf70..2402d3b50171de184233e9719a74c90028201296 100644 (file)
@@ -441,10 +441,9 @@ retry:
 
        err = ubi_io_read_data(ubi, buf, pnum, offset, len);
        if (err) {
-               if (err == UBI_IO_BITFLIPS) {
+               if (err == UBI_IO_BITFLIPS)
                        scrub = 1;
-                       err = 0;
-               } else if (mtd_is_eccerr(err)) {
+               else if (mtd_is_eccerr(err)) {
                        if (vol->vol_type == UBI_DYNAMIC_VOLUME)
                                goto out_unlock;
                        scrub = 1;
index 0431b46d9fd9e0211a8c7f5e865721a6b32895b5..cfd5b5e90156e536ca9cd479286248bb7dadc8e6 100644 (file)
@@ -24,7 +24,8 @@ size_t ubi_calc_fm_size(struct ubi_device *ubi)
 {
        size_t size;
 
-       size = sizeof(struct ubi_fm_hdr) + \
+       size = sizeof(struct ubi_fm_sb) + \
+               sizeof(struct ubi_fm_hdr) + \
                sizeof(struct ubi_fm_scan_pool) + \
                sizeof(struct ubi_fm_scan_pool) + \
                (ubi->peb_count * sizeof(struct ubi_fm_ec)) + \
@@ -330,6 +331,7 @@ static int process_pool_aeb(struct ubi_device *ubi, struct ubi_attach_info *ai,
                av = tmp_av;
        else {
                ubi_err("orphaned volume in fastmap pool!");
+               kmem_cache_free(ai->aeb_slab_cache, new_aeb);
                return UBI_BAD_FASTMAP;
        }
 
index 7bf416329c1973ee58b6c3511f90c8aecc5a997a..320fc38fa2a1508cd0a0db2e5c9da19ed7291789 100644 (file)
@@ -439,7 +439,8 @@ struct ubi_debug_info {
  *          @move_to, @move_to_put @erase_pending, @wl_scheduled, @works,
  *          @erroneous, and @erroneous_peb_count fields
  * @move_mutex: serializes eraseblock moves
- * @work_sem: synchronizes the WL worker with use tasks
+ * @work_sem: used to wait for all the scheduled works to finish and prevent
+ * new works from being submitted
  * @wl_scheduled: non-zero if the wear-leveling was scheduled
  * @lookuptbl: a table to quickly find a &struct ubi_wl_entry object for any
  *             physical eraseblock
@@ -713,14 +714,15 @@ struct ubi_attach_info {
  * @torture: if the physical eraseblock has to be tortured
  * @anchor: produce a anchor PEB to by used by fastmap
  *
- * The @func pointer points to the worker function. If the @cancel argument is
- * not zero, the worker has to free the resources and exit immediately. The
- * worker has to return zero in case of success and a negative error code in
+ * The @func pointer points to the worker function. If the @shutdown argument is
+ * not zero, the worker has to free the resources and exit immediately as the
+ * WL sub-system is shutting down.
+ * The worker has to return zero in case of success and a negative error code in
  * case of failure.
  */
 struct ubi_work {
        struct list_head list;
-       int (*func)(struct ubi_device *ubi, struct ubi_work *wrk, int cancel);
+       int (*func)(struct ubi_device *ubi, struct ubi_work *wrk, int shutdown);
        /* The below fields are only relevant to erasure works */
        struct ubi_wl_entry *e;
        int vol_id;
index 20f4917131450f844332183756a25bce6f28d9a9..6654f191868e59e264270c89942cffad41fba982 100644 (file)
@@ -272,7 +272,7 @@ static int produce_free_peb(struct ubi_device *ubi)
 {
        int err;
 
-       while (!ubi->free.rb_node) {
+       while (!ubi->free.rb_node && ubi->works_count) {
                spin_unlock(&ubi->wl_lock);
 
                dbg_wl("do one work synchronously");
@@ -835,7 +835,7 @@ repeat:
  * @wrk: the work to schedule
  *
  * This function adds a work defined by @wrk to the tail of the pending works
- * list. Can only be used of ubi->work_sem is already held in read mode!
+ * list. Can only be used if ubi->work_sem is already held in read mode!
  */
 static void __schedule_ubi_work(struct ubi_device *ubi, struct ubi_work *wrk)
 {
@@ -864,7 +864,7 @@ static void schedule_ubi_work(struct ubi_device *ubi, struct ubi_work *wrk)
 }
 
 static int erase_worker(struct ubi_device *ubi, struct ubi_work *wl_wrk,
-                       int cancel);
+                       int shutdown);
 
 #ifdef CONFIG_MTD_UBI_FASTMAP
 /**
@@ -990,14 +990,15 @@ int ubi_wl_put_fm_peb(struct ubi_device *ubi, struct ubi_wl_entry *fm_e,
  * wear_leveling_worker - wear-leveling worker function.
  * @ubi: UBI device description object
  * @wrk: the work object
- * @cancel: non-zero if the worker has to free memory and exit
+ * @shutdown: non-zero if the worker has to free memory and exit
+ * because the WL-subsystem is shutting down
  *
  * This function copies a more worn out physical eraseblock to a less worn out
  * one. Returns zero in case of success and a negative error code in case of
  * failure.
  */
 static int wear_leveling_worker(struct ubi_device *ubi, struct ubi_work *wrk,
-                               int cancel)
+                               int shutdown)
 {
        int err, scrubbing = 0, torture = 0, protect = 0, erroneous = 0;
        int vol_id = -1, uninitialized_var(lnum);
@@ -1008,7 +1009,7 @@ static int wear_leveling_worker(struct ubi_device *ubi, struct ubi_work *wrk,
        struct ubi_vid_hdr *vid_hdr;
 
        kfree(wrk);
-       if (cancel)
+       if (shutdown)
                return 0;
 
        vid_hdr = ubi_zalloc_vid_hdr(ubi, GFP_NOFS);
@@ -1407,7 +1408,8 @@ int ubi_ensure_anchor_pebs(struct ubi_device *ubi)
  * erase_worker - physical eraseblock erase worker function.
  * @ubi: UBI device description object
  * @wl_wrk: the work object
- * @cancel: non-zero if the worker has to free memory and exit
+ * @shutdown: non-zero if the worker has to free memory and exit
+ * because the WL sub-system is shutting down
  *
  * This function erases a physical eraseblock and perform torture testing if
  * needed. It also takes care about marking the physical eraseblock bad if
@@ -1415,7 +1417,7 @@ int ubi_ensure_anchor_pebs(struct ubi_device *ubi)
  * failure.
  */
 static int erase_worker(struct ubi_device *ubi, struct ubi_work *wl_wrk,
-                       int cancel)
+                       int shutdown)
 {
        struct ubi_wl_entry *e = wl_wrk->e;
        int pnum = e->pnum;
@@ -1423,7 +1425,7 @@ static int erase_worker(struct ubi_device *ubi, struct ubi_work *wl_wrk,
        int lnum = wl_wrk->lnum;
        int err, available_consumed = 0;
 
-       if (cancel) {
+       if (shutdown) {
                dbg_wl("cancel erasure of PEB %d EC %d", pnum, e->ec);
                kfree(wl_wrk);
                kmem_cache_free(ubi_wl_entry_slab, e);
@@ -1845,10 +1847,10 @@ int ubi_thread(void *u)
 }
 
 /**
- * cancel_pending - cancel all pending works.
+ * shutdown_work - shutdown all pending works.
  * @ubi: UBI device description object
  */
-static void cancel_pending(struct ubi_device *ubi)
+static void shutdown_work(struct ubi_device *ubi)
 {
        while (!list_empty(&ubi->works)) {
                struct ubi_work *wrk;
@@ -1997,7 +1999,7 @@ int ubi_wl_init(struct ubi_device *ubi, struct ubi_attach_info *ai)
        return 0;
 
 out_free:
-       cancel_pending(ubi);
+       shutdown_work(ubi);
        tree_destroy(&ubi->used);
        tree_destroy(&ubi->free);
        tree_destroy(&ubi->scrub);
@@ -2029,7 +2031,7 @@ static void protection_queue_destroy(struct ubi_device *ubi)
 void ubi_wl_close(struct ubi_device *ubi)
 {
        dbg_wl("close the WL sub-system");
-       cancel_pending(ubi);
+       shutdown_work(ubi);
        protection_queue_destroy(ubi);
        tree_destroy(&ubi->used);
        tree_destroy(&ubi->erroneous);
index c643e8a0a0dc4354f92011d0c2f480a48ef6ff1c..589b3524771385c1a1cdb76091f26f6582a1805a 100644 (file)
@@ -2,5 +2,6 @@
 # Makefile for APM X-Gene Ethernet Driver.
 #
 
-xgene-enet-objs := xgene_enet_hw.o xgene_enet_main.o xgene_enet_ethtool.o
+xgene-enet-objs := xgene_enet_hw.o xgene_enet_xgmac.o \
+                  xgene_enet_main.o xgene_enet_ethtool.o
 obj-$(CONFIG_NET_XGENE) += xgene-enet.o
index 63f2aa54a594085ffc2b2194c4b46868817cc889..c1c997b923426229696ad473e846a7bfd5ff409f 100644 (file)
@@ -59,10 +59,22 @@ static int xgene_get_settings(struct net_device *ndev, struct ethtool_cmd *cmd)
        struct xgene_enet_pdata *pdata = netdev_priv(ndev);
        struct phy_device *phydev = pdata->phy_dev;
 
-       if (phydev == NULL)
-               return -ENODEV;
+       if (pdata->phy_mode == PHY_INTERFACE_MODE_RGMII) {
+               if (phydev == NULL)
+                       return -ENODEV;
 
-       return phy_ethtool_gset(phydev, cmd);
+               return phy_ethtool_gset(phydev, cmd);
+       }
+
+       cmd->supported = SUPPORTED_10000baseT_Full | SUPPORTED_FIBRE;
+       cmd->advertising = cmd->supported;
+       ethtool_cmd_speed_set(cmd, SPEED_10000);
+       cmd->duplex = DUPLEX_FULL;
+       cmd->port = PORT_FIBRE;
+       cmd->transceiver = XCVR_EXTERNAL;
+       cmd->autoneg = AUTONEG_DISABLE;
+
+       return 0;
 }
 
 static int xgene_set_settings(struct net_device *ndev, struct ethtool_cmd *cmd)
@@ -70,10 +82,14 @@ static int xgene_set_settings(struct net_device *ndev, struct ethtool_cmd *cmd)
        struct xgene_enet_pdata *pdata = netdev_priv(ndev);
        struct phy_device *phydev = pdata->phy_dev;
 
-       if (phydev == NULL)
-               return -ENODEV;
+       if (pdata->phy_mode == PHY_INTERFACE_MODE_RGMII) {
+               if (phydev == NULL)
+                       return -ENODEV;
+
+               return phy_ethtool_sset(phydev, cmd);
+       }
 
-       return phy_ethtool_sset(phydev, cmd);
+       return -EINVAL;
 }
 
 static void xgene_get_strings(struct net_device *ndev, u32 stringset, u8 *data)
index 812d8d65159be7b4f66de25fbc998013000e11f9..c8f3824f7606fdaf01a42f9c3ad0527393498dcb 100644 (file)
@@ -402,7 +402,7 @@ static int xgene_mii_phy_read(struct xgene_enet_pdata *pdata,
        return data;
 }
 
-void xgene_gmac_set_mac_addr(struct xgene_enet_pdata *pdata)
+static void xgene_gmac_set_mac_addr(struct xgene_enet_pdata *pdata)
 {
        u32 addr0, addr1;
        u8 *dev_addr = pdata->ndev->dev_addr;
@@ -436,13 +436,13 @@ static int xgene_enet_ecc_init(struct xgene_enet_pdata *pdata)
        return 0;
 }
 
-void xgene_gmac_reset(struct xgene_enet_pdata *pdata)
+static void xgene_gmac_reset(struct xgene_enet_pdata *pdata)
 {
        xgene_enet_wr_mcx_mac(pdata, MAC_CONFIG_1_ADDR, SOFT_RESET1);
        xgene_enet_wr_mcx_mac(pdata, MAC_CONFIG_1_ADDR, 0);
 }
 
-void xgene_gmac_init(struct xgene_enet_pdata *pdata, int speed)
+static void xgene_gmac_init(struct xgene_enet_pdata *pdata)
 {
        u32 value, mc2;
        u32 intf_ctl, rgmii;
@@ -456,7 +456,7 @@ void xgene_gmac_init(struct xgene_enet_pdata *pdata, int speed)
        xgene_enet_rd_mcx_mac(pdata, INTERFACE_CONTROL_ADDR, &intf_ctl);
        xgene_enet_rd_csr(pdata, RGMII_REG_0_ADDR, &rgmii);
 
-       switch (speed) {
+       switch (pdata->phy_speed) {
        case SPEED_10:
                ENET_INTERFACE_MODE2_SET(&mc2, 1);
                CFG_MACMODE_SET(&icm0, 0);
@@ -525,8 +525,8 @@ static void xgene_enet_config_ring_if_assoc(struct xgene_enet_pdata *pdata)
        xgene_enet_wr_ring_if(pdata, ENET_CFGSSQMIQMLITEFPQASSOC_ADDR, val);
 }
 
-void xgene_enet_cle_bypass(struct xgene_enet_pdata *pdata,
-                          u32 dst_ring_num, u16 bufpool_id)
+static void xgene_enet_cle_bypass(struct xgene_enet_pdata *pdata,
+                                 u32 dst_ring_num, u16 bufpool_id)
 {
        u32 cb;
        u32 fpsel;
@@ -544,7 +544,7 @@ void xgene_enet_cle_bypass(struct xgene_enet_pdata *pdata,
        xgene_enet_wr_csr(pdata, CLE_BYPASS_REG1_0_ADDR, cb);
 }
 
-void xgene_gmac_rx_enable(struct xgene_enet_pdata *pdata)
+static void xgene_gmac_rx_enable(struct xgene_enet_pdata *pdata)
 {
        u32 data;
 
@@ -552,7 +552,7 @@ void xgene_gmac_rx_enable(struct xgene_enet_pdata *pdata)
        xgene_enet_wr_mcx_mac(pdata, MAC_CONFIG_1_ADDR, data | RX_EN);
 }
 
-void xgene_gmac_tx_enable(struct xgene_enet_pdata *pdata)
+static void xgene_gmac_tx_enable(struct xgene_enet_pdata *pdata)
 {
        u32 data;
 
@@ -560,7 +560,7 @@ void xgene_gmac_tx_enable(struct xgene_enet_pdata *pdata)
        xgene_enet_wr_mcx_mac(pdata, MAC_CONFIG_1_ADDR, data | TX_EN);
 }
 
-void xgene_gmac_rx_disable(struct xgene_enet_pdata *pdata)
+static void xgene_gmac_rx_disable(struct xgene_enet_pdata *pdata)
 {
        u32 data;
 
@@ -568,7 +568,7 @@ void xgene_gmac_rx_disable(struct xgene_enet_pdata *pdata)
        xgene_enet_wr_mcx_mac(pdata, MAC_CONFIG_1_ADDR, data & ~RX_EN);
 }
 
-void xgene_gmac_tx_disable(struct xgene_enet_pdata *pdata)
+static void xgene_gmac_tx_disable(struct xgene_enet_pdata *pdata)
 {
        u32 data;
 
@@ -576,7 +576,7 @@ void xgene_gmac_tx_disable(struct xgene_enet_pdata *pdata)
        xgene_enet_wr_mcx_mac(pdata, MAC_CONFIG_1_ADDR, data & ~TX_EN);
 }
 
-void xgene_enet_reset(struct xgene_enet_pdata *pdata)
+static void xgene_enet_reset(struct xgene_enet_pdata *pdata)
 {
        u32 val;
 
@@ -593,7 +593,7 @@ void xgene_enet_reset(struct xgene_enet_pdata *pdata)
        xgene_enet_wr_mcx_mac(pdata, MII_MGMT_CONFIG_ADDR, val);
 }
 
-void xgene_gport_shutdown(struct xgene_enet_pdata *pdata)
+static void xgene_gport_shutdown(struct xgene_enet_pdata *pdata)
 {
        clk_disable_unprepare(pdata->clk);
 }
@@ -627,10 +627,10 @@ static void xgene_enet_adjust_link(struct net_device *ndev)
 
        if (phydev->link) {
                if (pdata->phy_speed != phydev->speed) {
-                       xgene_gmac_init(pdata, phydev->speed);
+                       pdata->phy_speed = phydev->speed;
+                       xgene_gmac_init(pdata);
                        xgene_gmac_rx_enable(pdata);
                        xgene_gmac_tx_enable(pdata);
-                       pdata->phy_speed = phydev->speed;
                        phy_print_status(phydev);
                }
        } else {
@@ -726,3 +726,19 @@ void xgene_enet_mdio_remove(struct xgene_enet_pdata *pdata)
        mdiobus_free(pdata->mdio_bus);
        pdata->mdio_bus = NULL;
 }
+
+struct xgene_mac_ops xgene_gmac_ops = {
+       .init = xgene_gmac_init,
+       .reset = xgene_gmac_reset,
+       .rx_enable = xgene_gmac_rx_enable,
+       .tx_enable = xgene_gmac_tx_enable,
+       .rx_disable = xgene_gmac_rx_disable,
+       .tx_disable = xgene_gmac_tx_disable,
+       .set_mac_addr = xgene_gmac_set_mac_addr,
+};
+
+struct xgene_port_ops xgene_gport_ops = {
+       .reset = xgene_enet_reset,
+       .cle_bypass = xgene_enet_cle_bypass,
+       .shutdown = xgene_gport_shutdown,
+};
index 371e7a5b250790fbb5418bddd99fd2cf1bfc7272..15ec4267779c4459d932ddcb9e5e6f2564d795ca 100644 (file)
@@ -42,6 +42,11 @@ static inline u32 xgene_get_bits(u32 val, u32 start, u32 end)
        return (val & GENMASK(end, start)) >> start;
 }
 
+enum xgene_enet_rm {
+       RM0,
+       RM3 = 3
+};
+
 #define CSR_RING_ID            0x0008
 #define OVERWRITE              BIT(31)
 #define IS_BUFFER_POOL         BIT(20)
@@ -52,7 +57,6 @@ static inline u32 xgene_get_bits(u32 val, u32 start, u32 end)
 #define CSR_RING_WR_BASE       0x0070
 #define NUM_RING_CONFIG                5
 #define BUFPOOL_MODE           3
-#define RM3                    3
 #define INC_DEC_CMD_ADDR       0x002c
 #define UDP_HDR_SIZE           2
 #define BUF_LEN_CODE_2K                0x5000
@@ -94,11 +98,9 @@ static inline u32 xgene_get_bits(u32 val, u32 start, u32 end)
 
 #define BLOCK_ETH_CSR_OFFSET           0x2000
 #define BLOCK_ETH_RING_IF_OFFSET       0x9000
-#define BLOCK_ETH_CLKRST_CSR_OFFSET    0xC000
 #define BLOCK_ETH_DIAG_CSR_OFFSET      0xD000
 
 #define BLOCK_ETH_MAC_OFFSET           0x0000
-#define BLOCK_ETH_STATS_OFFSET         0x0014
 #define BLOCK_ETH_MAC_CSR_OFFSET       0x2800
 
 #define MAC_ADDR_REG_OFFSET            0x00
@@ -107,12 +109,6 @@ static inline u32 xgene_get_bits(u32 val, u32 start, u32 end)
 #define MAC_READ_REG_OFFSET            0x0c
 #define MAC_COMMAND_DONE_REG_OFFSET    0x10
 
-#define STAT_ADDR_REG_OFFSET           0x00
-#define STAT_COMMAND_REG_OFFSET                0x04
-#define STAT_WRITE_REG_OFFSET          0x08
-#define STAT_READ_REG_OFFSET           0x0c
-#define STAT_COMMAND_DONE_REG_OFFSET   0x10
-
 #define MII_MGMT_CONFIG_ADDR           0x20
 #define MII_MGMT_COMMAND_ADDR          0x24
 #define MII_MGMT_ADDRESS_ADDR          0x28
@@ -318,20 +314,10 @@ void xgene_enet_parse_error(struct xgene_enet_desc_ring *ring,
                            struct xgene_enet_pdata *pdata,
                            enum xgene_enet_err_code status);
 
-void xgene_enet_reset(struct xgene_enet_pdata *priv);
-void xgene_gmac_reset(struct xgene_enet_pdata *priv);
-void xgene_gmac_init(struct xgene_enet_pdata *priv, int speed);
-void xgene_gmac_tx_enable(struct xgene_enet_pdata *priv);
-void xgene_gmac_rx_enable(struct xgene_enet_pdata *priv);
-void xgene_gmac_tx_disable(struct xgene_enet_pdata *priv);
-void xgene_gmac_rx_disable(struct xgene_enet_pdata *priv);
-void xgene_gmac_set_mac_addr(struct xgene_enet_pdata *pdata);
-void xgene_enet_cle_bypass(struct xgene_enet_pdata *pdata,
-                          u32 dst_ring_num, u16 bufpool_id);
-void xgene_gport_shutdown(struct xgene_enet_pdata *priv);
-void xgene_gmac_get_tx_stats(struct xgene_enet_pdata *pdata);
-
 int xgene_enet_mdio_config(struct xgene_enet_pdata *pdata);
 void xgene_enet_mdio_remove(struct xgene_enet_pdata *pdata);
 
+extern struct xgene_mac_ops xgene_gmac_ops;
+extern struct xgene_port_ops xgene_gport_ops;
+
 #endif /* __XGENE_ENET_HW_H__ */
index e4222af2baa66838d27d136c8e4c3d9be369679b..9b85239ceedfef2e2d877d0510082e7f49f4e010 100644 (file)
@@ -21,6 +21,7 @@
 
 #include "xgene_enet_main.h"
 #include "xgene_enet_hw.h"
+#include "xgene_enet_xgmac.h"
 
 static void xgene_enet_init_bufpool(struct xgene_enet_desc_ring *buf_pool)
 {
@@ -390,7 +391,7 @@ static int xgene_enet_process_ring(struct xgene_enet_desc_ring *ring,
                }
        }
 
-       return budget;
+       return count;
 }
 
 static int xgene_enet_napi(struct napi_struct *napi, const int budget)
@@ -413,7 +414,7 @@ static void xgene_enet_timeout(struct net_device *ndev)
 {
        struct xgene_enet_pdata *pdata = netdev_priv(ndev);
 
-       xgene_gmac_reset(pdata);
+       pdata->mac_ops->reset(pdata);
 }
 
 static int xgene_enet_register_irq(struct net_device *ndev)
@@ -445,18 +446,21 @@ static void xgene_enet_free_irq(struct net_device *ndev)
 static int xgene_enet_open(struct net_device *ndev)
 {
        struct xgene_enet_pdata *pdata = netdev_priv(ndev);
+       struct xgene_mac_ops *mac_ops = pdata->mac_ops;
        int ret;
 
-       xgene_gmac_tx_enable(pdata);
-       xgene_gmac_rx_enable(pdata);
+       mac_ops->tx_enable(pdata);
+       mac_ops->rx_enable(pdata);
 
        ret = xgene_enet_register_irq(ndev);
        if (ret)
                return ret;
        napi_enable(&pdata->rx_ring->napi);
 
-       if (pdata->phy_dev)
+       if (pdata->phy_mode == PHY_INTERFACE_MODE_RGMII)
                phy_start(pdata->phy_dev);
+       else
+               schedule_delayed_work(&pdata->link_work, PHY_POLL_LINK_OFF);
 
        netif_start_queue(ndev);
 
@@ -466,18 +470,21 @@ static int xgene_enet_open(struct net_device *ndev)
 static int xgene_enet_close(struct net_device *ndev)
 {
        struct xgene_enet_pdata *pdata = netdev_priv(ndev);
+       struct xgene_mac_ops *mac_ops = pdata->mac_ops;
 
        netif_stop_queue(ndev);
 
-       if (pdata->phy_dev)
+       if (pdata->phy_mode == PHY_INTERFACE_MODE_RGMII)
                phy_stop(pdata->phy_dev);
+       else
+               cancel_delayed_work_sync(&pdata->link_work);
 
        napi_disable(&pdata->rx_ring->napi);
        xgene_enet_free_irq(ndev);
        xgene_enet_process_ring(pdata->rx_ring, -1);
 
-       xgene_gmac_tx_disable(pdata);
-       xgene_gmac_rx_disable(pdata);
+       mac_ops->tx_disable(pdata);
+       mac_ops->rx_disable(pdata);
 
        return 0;
 }
@@ -613,7 +620,6 @@ static struct xgene_enet_desc_ring *xgene_enet_create_desc_ring(
 
        ring->cmd_base = pdata->ring_cmd_addr + (ring->num << 6);
        ring->cmd = ring->cmd_base + INC_DEC_CMD_ADDR;
-       pdata->rm = RM3;
        ring = xgene_enet_setup_ring(ring);
        netdev_dbg(ndev, "ring info: num=%d  size=%d  id=%d  slots=%d\n",
                   ring->num, ring->size, ring->id, ring->slots);
@@ -724,7 +730,7 @@ static int xgene_enet_set_mac_address(struct net_device *ndev, void *addr)
        ret = eth_mac_addr(ndev, addr);
        if (ret)
                return ret;
-       xgene_gmac_set_mac_addr(pdata);
+       pdata->mac_ops->set_mac_addr(pdata);
 
        return ret;
 }
@@ -803,8 +809,13 @@ static int xgene_enet_get_resources(struct xgene_enet_pdata *pdata)
 
        pdata->phy_mode = of_get_phy_mode(pdev->dev.of_node);
        if (pdata->phy_mode < 0) {
-               dev_err(dev, "Incorrect phy-connection-type in DTS\n");
-               return -EINVAL;
+               dev_err(dev, "Unable to get phy-connection-type\n");
+               return pdata->phy_mode;
+       }
+       if (pdata->phy_mode != PHY_INTERFACE_MODE_RGMII &&
+           pdata->phy_mode != PHY_INTERFACE_MODE_XGMII) {
+               dev_err(dev, "Incorrect phy-connection-type specified\n");
+               return -ENODEV;
        }
 
        pdata->clk = devm_clk_get(&pdev->dev, NULL);
@@ -819,12 +830,18 @@ static int xgene_enet_get_resources(struct xgene_enet_pdata *pdata)
        pdata->eth_csr_addr = base_addr + BLOCK_ETH_CSR_OFFSET;
        pdata->eth_ring_if_addr = base_addr + BLOCK_ETH_RING_IF_OFFSET;
        pdata->eth_diag_csr_addr = base_addr + BLOCK_ETH_DIAG_CSR_OFFSET;
-       pdata->mcx_mac_addr = base_addr + BLOCK_ETH_MAC_OFFSET;
-       pdata->mcx_stats_addr = base_addr + BLOCK_ETH_STATS_OFFSET;
-       pdata->mcx_mac_csr_addr = base_addr + BLOCK_ETH_MAC_CSR_OFFSET;
+       if (pdata->phy_mode == PHY_INTERFACE_MODE_RGMII) {
+               pdata->mcx_mac_addr = base_addr + BLOCK_ETH_MAC_OFFSET;
+               pdata->mcx_mac_csr_addr = base_addr + BLOCK_ETH_MAC_CSR_OFFSET;
+               pdata->rm = RM3;
+       } else {
+               pdata->mcx_mac_addr = base_addr + BLOCK_AXG_MAC_OFFSET;
+               pdata->mcx_mac_csr_addr = base_addr + BLOCK_AXG_MAC_CSR_OFFSET;
+               pdata->rm = RM0;
+       }
        pdata->rx_buff_cnt = NUM_PKT_BUF;
 
-       return ret;
+       return 0;
 }
 
 static int xgene_enet_init_hw(struct xgene_enet_pdata *pdata)
@@ -834,8 +851,7 @@ static int xgene_enet_init_hw(struct xgene_enet_pdata *pdata)
        u16 dst_ring_num;
        int ret;
 
-       xgene_gmac_tx_disable(pdata);
-       xgene_gmac_rx_disable(pdata);
+       pdata->port_ops->reset(pdata);
 
        ret = xgene_enet_create_desc_rings(ndev);
        if (ret) {
@@ -853,11 +869,26 @@ static int xgene_enet_init_hw(struct xgene_enet_pdata *pdata)
        }
 
        dst_ring_num = xgene_enet_dst_ring_num(pdata->rx_ring);
-       xgene_enet_cle_bypass(pdata, dst_ring_num, buf_pool->id);
+       pdata->port_ops->cle_bypass(pdata, dst_ring_num, buf_pool->id);
+       pdata->mac_ops->init(pdata);
 
        return ret;
 }
 
+static void xgene_enet_setup_ops(struct xgene_enet_pdata *pdata)
+{
+       switch (pdata->phy_mode) {
+       case PHY_INTERFACE_MODE_RGMII:
+               pdata->mac_ops = &xgene_gmac_ops;
+               pdata->port_ops = &xgene_gport_ops;
+               break;
+       default:
+               pdata->mac_ops = &xgene_xgmac_ops;
+               pdata->port_ops = &xgene_xgport_ops;
+               break;
+       }
+}
+
 static int xgene_enet_probe(struct platform_device *pdev)
 {
        struct net_device *ndev;
@@ -886,8 +917,7 @@ static int xgene_enet_probe(struct platform_device *pdev)
        if (ret)
                goto err;
 
-       xgene_enet_reset(pdata);
-       xgene_gmac_init(pdata, SPEED_1000);
+       xgene_enet_setup_ops(pdata);
 
        ret = register_netdev(ndev);
        if (ret) {
@@ -907,7 +937,10 @@ static int xgene_enet_probe(struct platform_device *pdev)
 
        napi = &pdata->rx_ring->napi;
        netif_napi_add(ndev, napi, xgene_enet_napi, NAPI_POLL_WEIGHT);
-       ret = xgene_enet_mdio_config(pdata);
+       if (pdata->phy_mode == PHY_INTERFACE_MODE_RGMII)
+               ret = xgene_enet_mdio_config(pdata);
+       else
+               INIT_DELAYED_WORK(&pdata->link_work, xgene_enet_link_state);
 
        return ret;
 err:
@@ -918,19 +951,21 @@ err:
 static int xgene_enet_remove(struct platform_device *pdev)
 {
        struct xgene_enet_pdata *pdata;
+       struct xgene_mac_ops *mac_ops;
        struct net_device *ndev;
 
        pdata = platform_get_drvdata(pdev);
+       mac_ops = pdata->mac_ops;
        ndev = pdata->ndev;
 
-       xgene_gmac_rx_disable(pdata);
-       xgene_gmac_tx_disable(pdata);
+       mac_ops->rx_disable(pdata);
+       mac_ops->tx_disable(pdata);
 
        netif_napi_del(&pdata->rx_ring->napi);
        xgene_enet_mdio_remove(pdata);
        xgene_enet_delete_desc_rings(pdata);
        unregister_netdev(ndev);
-       xgene_gport_shutdown(pdata);
+       pdata->port_ops->shutdown(pdata);
        free_netdev(ndev);
 
        return 0;
@@ -956,5 +991,6 @@ module_platform_driver(xgene_enet_driver);
 
 MODULE_DESCRIPTION("APM X-Gene SoC Ethernet driver");
 MODULE_VERSION(XGENE_DRV_VERSION);
+MODULE_AUTHOR("Iyappan Subramanian <isubramanian@apm.com>");
 MODULE_AUTHOR("Keyur Chudgar <kchudgar@apm.com>");
 MODULE_LICENSE("GPL");
index 0815866986b00406927ed94a39768cf20c23b4fd..86cf68b65584974ed60af95647fcf60260c64baa 100644 (file)
@@ -68,6 +68,23 @@ struct xgene_enet_desc_ring {
        };
 };
 
+struct xgene_mac_ops {
+       void (*init)(struct xgene_enet_pdata *pdata);
+       void (*reset)(struct xgene_enet_pdata *pdata);
+       void (*tx_enable)(struct xgene_enet_pdata *pdata);
+       void (*rx_enable)(struct xgene_enet_pdata *pdata);
+       void (*tx_disable)(struct xgene_enet_pdata *pdata);
+       void (*rx_disable)(struct xgene_enet_pdata *pdata);
+       void (*set_mac_addr)(struct xgene_enet_pdata *pdata);
+};
+
+struct xgene_port_ops {
+       void (*reset)(struct xgene_enet_pdata *pdata);
+       void (*cle_bypass)(struct xgene_enet_pdata *pdata,
+                          u32 dst_ring_num, u16 bufpool_id);
+       void (*shutdown)(struct xgene_enet_pdata *pdata);
+};
+
 /* ethernet private data */
 struct xgene_enet_pdata {
        struct net_device *ndev;
@@ -88,16 +105,17 @@ struct xgene_enet_pdata {
        void __iomem *eth_ring_if_addr;
        void __iomem *eth_diag_csr_addr;
        void __iomem *mcx_mac_addr;
-       void __iomem *mcx_stats_addr;
        void __iomem *mcx_mac_csr_addr;
        void __iomem *base_addr;
        void __iomem *ring_csr_addr;
        void __iomem *ring_cmd_addr;
        u32 phy_addr;
        int phy_mode;
-       u32 speed;
-       u16 rm;
+       enum xgene_enet_rm rm;
        struct rtnl_link_stats64 stats;
+       struct xgene_mac_ops *mac_ops;
+       struct xgene_port_ops *port_ops;
+       struct delayed_work link_work;
 };
 
 /* Set the specified value into a bit-field defined by its starting position
diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_xgmac.c b/drivers/net/ethernet/apm/xgene/xgene_enet_xgmac.c
new file mode 100644 (file)
index 0000000..cd64b9f
--- /dev/null
@@ -0,0 +1,331 @@
+/* Applied Micro X-Gene SoC Ethernet Driver
+ *
+ * Copyright (c) 2014, Applied Micro Circuits Corporation
+ * Authors: Iyappan Subramanian <isubramanian@apm.com>
+ *         Keyur Chudgar <kchudgar@apm.com>
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "xgene_enet_main.h"
+#include "xgene_enet_hw.h"
+#include "xgene_enet_xgmac.h"
+
+static void xgene_enet_wr_csr(struct xgene_enet_pdata *pdata,
+                             u32 offset, u32 val)
+{
+       void __iomem *addr = pdata->eth_csr_addr + offset;
+
+       iowrite32(val, addr);
+}
+
+static void xgene_enet_wr_ring_if(struct xgene_enet_pdata *pdata,
+                                 u32 offset, u32 val)
+{
+       void __iomem *addr = pdata->eth_ring_if_addr + offset;
+
+       iowrite32(val, addr);
+}
+
+static void xgene_enet_wr_diag_csr(struct xgene_enet_pdata *pdata,
+                                  u32 offset, u32 val)
+{
+       void __iomem *addr = pdata->eth_diag_csr_addr + offset;
+
+       iowrite32(val, addr);
+}
+
+static bool xgene_enet_wr_indirect(void __iomem *addr, void __iomem *wr,
+                                  void __iomem *cmd, void __iomem *cmd_done,
+                                  u32 wr_addr, u32 wr_data)
+{
+       u32 done;
+       u8 wait = 10;
+
+       iowrite32(wr_addr, addr);
+       iowrite32(wr_data, wr);
+       iowrite32(XGENE_ENET_WR_CMD, cmd);
+
+       /* wait for write command to complete */
+       while (!(done = ioread32(cmd_done)) && wait--)
+               udelay(1);
+
+       if (!done)
+               return false;
+
+       iowrite32(0, cmd);
+
+       return true;
+}
+
+static void xgene_enet_wr_mac(struct xgene_enet_pdata *pdata,
+                             u32 wr_addr, u32 wr_data)
+{
+       void __iomem *addr, *wr, *cmd, *cmd_done;
+
+       addr = pdata->mcx_mac_addr + MAC_ADDR_REG_OFFSET;
+       wr = pdata->mcx_mac_addr + MAC_WRITE_REG_OFFSET;
+       cmd = pdata->mcx_mac_addr + MAC_COMMAND_REG_OFFSET;
+       cmd_done = pdata->mcx_mac_addr + MAC_COMMAND_DONE_REG_OFFSET;
+
+       if (!xgene_enet_wr_indirect(addr, wr, cmd, cmd_done, wr_addr, wr_data))
+               netdev_err(pdata->ndev, "MCX mac write failed, addr: %04x\n",
+                          wr_addr);
+}
+
+static void xgene_enet_rd_csr(struct xgene_enet_pdata *pdata,
+                             u32 offset, u32 *val)
+{
+       void __iomem *addr = pdata->eth_csr_addr + offset;
+
+       *val = ioread32(addr);
+}
+
+static void xgene_enet_rd_diag_csr(struct xgene_enet_pdata *pdata,
+                                  u32 offset, u32 *val)
+{
+       void __iomem *addr = pdata->eth_diag_csr_addr + offset;
+
+       *val = ioread32(addr);
+}
+
+static bool xgene_enet_rd_indirect(void __iomem *addr, void __iomem *rd,
+                                  void __iomem *cmd, void __iomem *cmd_done,
+                                  u32 rd_addr, u32 *rd_data)
+{
+       u32 done;
+       u8 wait = 10;
+
+       iowrite32(rd_addr, addr);
+       iowrite32(XGENE_ENET_RD_CMD, cmd);
+
+       /* wait for read command to complete */
+       while (!(done = ioread32(cmd_done)) && wait--)
+               udelay(1);
+
+       if (!done)
+               return false;
+
+       *rd_data = ioread32(rd);
+       iowrite32(0, cmd);
+
+       return true;
+}
+
+static void xgene_enet_rd_mac(struct xgene_enet_pdata *pdata,
+                             u32 rd_addr, u32 *rd_data)
+{
+       void __iomem *addr, *rd, *cmd, *cmd_done;
+
+       addr = pdata->mcx_mac_addr + MAC_ADDR_REG_OFFSET;
+       rd = pdata->mcx_mac_addr + MAC_READ_REG_OFFSET;
+       cmd = pdata->mcx_mac_addr + MAC_COMMAND_REG_OFFSET;
+       cmd_done = pdata->mcx_mac_addr + MAC_COMMAND_DONE_REG_OFFSET;
+
+       if (!xgene_enet_rd_indirect(addr, rd, cmd, cmd_done, rd_addr, rd_data))
+               netdev_err(pdata->ndev, "MCX mac read failed, addr: %04x\n",
+                          rd_addr);
+}
+
+static int xgene_enet_ecc_init(struct xgene_enet_pdata *pdata)
+{
+       struct net_device *ndev = pdata->ndev;
+       u32 data;
+       u8 wait = 10;
+
+       xgene_enet_wr_diag_csr(pdata, ENET_CFG_MEM_RAM_SHUTDOWN_ADDR, 0x0);
+       do {
+               usleep_range(100, 110);
+               xgene_enet_rd_diag_csr(pdata, ENET_BLOCK_MEM_RDY_ADDR, &data);
+       } while ((data != 0xffffffff) && wait--);
+
+       if (data != 0xffffffff) {
+               netdev_err(ndev, "Failed to release memory from shutdown\n");
+               return -ENODEV;
+       }
+
+       return 0;
+}
+
+static void xgene_enet_config_ring_if_assoc(struct xgene_enet_pdata *pdata)
+{
+       xgene_enet_wr_ring_if(pdata, ENET_CFGSSQMIWQASSOC_ADDR, 0);
+       xgene_enet_wr_ring_if(pdata, ENET_CFGSSQMIFPQASSOC_ADDR, 0);
+       xgene_enet_wr_ring_if(pdata, ENET_CFGSSQMIQMLITEWQASSOC_ADDR, 0);
+       xgene_enet_wr_ring_if(pdata, ENET_CFGSSQMIQMLITEFPQASSOC_ADDR, 0);
+}
+
+static void xgene_xgmac_reset(struct xgene_enet_pdata *pdata)
+{
+       xgene_enet_wr_mac(pdata, AXGMAC_CONFIG_0, HSTMACRST);
+       xgene_enet_wr_mac(pdata, AXGMAC_CONFIG_0, 0);
+}
+
+static void xgene_xgmac_set_mac_addr(struct xgene_enet_pdata *pdata)
+{
+       u32 addr0, addr1;
+       u8 *dev_addr = pdata->ndev->dev_addr;
+
+       addr0 = (dev_addr[3] << 24) | (dev_addr[2] << 16) |
+               (dev_addr[1] << 8) | dev_addr[0];
+       addr1 = (dev_addr[5] << 24) | (dev_addr[4] << 16);
+
+       xgene_enet_wr_mac(pdata, HSTMACADR_LSW_ADDR, addr0);
+       xgene_enet_wr_mac(pdata, HSTMACADR_MSW_ADDR, addr1);
+}
+
+static u32 xgene_enet_link_status(struct xgene_enet_pdata *pdata)
+{
+       u32 data;
+
+       xgene_enet_rd_csr(pdata, XG_LINK_STATUS_ADDR, &data);
+
+       return data;
+}
+
+static void xgene_xgmac_init(struct xgene_enet_pdata *pdata)
+{
+       u32 data;
+
+       xgene_xgmac_reset(pdata);
+
+       xgene_enet_rd_mac(pdata, AXGMAC_CONFIG_1, &data);
+       data |= HSTPPEN;
+       data &= ~HSTLENCHK;
+       xgene_enet_wr_mac(pdata, AXGMAC_CONFIG_1, data);
+
+       xgene_enet_wr_mac(pdata, HSTMAXFRAME_LENGTH_ADDR, 0x06000600);
+       xgene_xgmac_set_mac_addr(pdata);
+
+       xgene_enet_rd_csr(pdata, XG_RSIF_CONFIG_REG_ADDR, &data);
+       data |= CFG_RSIF_FPBUFF_TIMEOUT_EN;
+       xgene_enet_wr_csr(pdata, XG_RSIF_CONFIG_REG_ADDR, data);
+
+       xgene_enet_wr_csr(pdata, XG_CFG_BYPASS_ADDR, RESUME_TX);
+       xgene_enet_wr_csr(pdata, XGENET_RX_DV_GATE_REG_0_ADDR, 0);
+       xgene_enet_rd_csr(pdata, XG_ENET_SPARE_CFG_REG_ADDR, &data);
+       data |= BIT(12);
+       xgene_enet_wr_csr(pdata, XG_ENET_SPARE_CFG_REG_ADDR, data);
+       xgene_enet_wr_csr(pdata, XG_ENET_SPARE_CFG_REG_1_ADDR, 0x82);
+}
+
+static void xgene_xgmac_rx_enable(struct xgene_enet_pdata *pdata)
+{
+       u32 data;
+
+       xgene_enet_rd_mac(pdata, AXGMAC_CONFIG_1, &data);
+       xgene_enet_wr_mac(pdata, AXGMAC_CONFIG_1, data | HSTRFEN);
+}
+
+static void xgene_xgmac_tx_enable(struct xgene_enet_pdata *pdata)
+{
+       u32 data;
+
+       xgene_enet_rd_mac(pdata, AXGMAC_CONFIG_1, &data);
+       xgene_enet_wr_mac(pdata, AXGMAC_CONFIG_1, data | HSTTFEN);
+}
+
+static void xgene_xgmac_rx_disable(struct xgene_enet_pdata *pdata)
+{
+       u32 data;
+
+       xgene_enet_rd_mac(pdata, AXGMAC_CONFIG_1, &data);
+       xgene_enet_wr_mac(pdata, AXGMAC_CONFIG_1, data & ~HSTRFEN);
+}
+
+static void xgene_xgmac_tx_disable(struct xgene_enet_pdata *pdata)
+{
+       u32 data;
+
+       xgene_enet_rd_mac(pdata, AXGMAC_CONFIG_1, &data);
+       xgene_enet_wr_mac(pdata, AXGMAC_CONFIG_1, data & ~HSTTFEN);
+}
+
+static void xgene_enet_reset(struct xgene_enet_pdata *pdata)
+{
+       clk_prepare_enable(pdata->clk);
+       clk_disable_unprepare(pdata->clk);
+       clk_prepare_enable(pdata->clk);
+
+       xgene_enet_ecc_init(pdata);
+       xgene_enet_config_ring_if_assoc(pdata);
+}
+
+static void xgene_enet_xgcle_bypass(struct xgene_enet_pdata *pdata,
+                                   u32 dst_ring_num, u16 bufpool_id)
+{
+       u32 cb, fpsel;
+
+       xgene_enet_rd_csr(pdata, XCLE_BYPASS_REG0_ADDR, &cb);
+       cb |= CFG_CLE_BYPASS_EN0;
+       CFG_CLE_IP_PROTOCOL0_SET(&cb, 3);
+       xgene_enet_wr_csr(pdata, XCLE_BYPASS_REG0_ADDR, cb);
+
+       fpsel = xgene_enet_ring_bufnum(bufpool_id) - 0x20;
+       xgene_enet_rd_csr(pdata, XCLE_BYPASS_REG1_ADDR, &cb);
+       CFG_CLE_DSTQID0_SET(&cb, dst_ring_num);
+       CFG_CLE_FPSEL0_SET(&cb, fpsel);
+       xgene_enet_wr_csr(pdata, XCLE_BYPASS_REG1_ADDR, cb);
+}
+
+static void xgene_enet_shutdown(struct xgene_enet_pdata *pdata)
+{
+       clk_disable_unprepare(pdata->clk);
+}
+
+void xgene_enet_link_state(struct work_struct *work)
+{
+       struct xgene_enet_pdata *pdata = container_of(to_delayed_work(work),
+                                        struct xgene_enet_pdata, link_work);
+       struct net_device *ndev = pdata->ndev;
+       u32 link_status, poll_interval;
+
+       link_status = xgene_enet_link_status(pdata);
+       if (link_status) {
+               if (!netif_carrier_ok(ndev)) {
+                       netif_carrier_on(ndev);
+                       xgene_xgmac_init(pdata);
+                       xgene_xgmac_rx_enable(pdata);
+                       xgene_xgmac_tx_enable(pdata);
+                       netdev_info(ndev, "Link is Up - 10Gbps\n");
+               }
+               poll_interval = PHY_POLL_LINK_ON;
+       } else {
+               if (netif_carrier_ok(ndev)) {
+                       xgene_xgmac_rx_disable(pdata);
+                       xgene_xgmac_tx_disable(pdata);
+                       netif_carrier_off(ndev);
+                       netdev_info(ndev, "Link is Down\n");
+               }
+               poll_interval = PHY_POLL_LINK_OFF;
+       }
+
+       schedule_delayed_work(&pdata->link_work, poll_interval);
+}
+
+struct xgene_mac_ops xgene_xgmac_ops = {
+       .init = xgene_xgmac_init,
+       .reset = xgene_xgmac_reset,
+       .rx_enable = xgene_xgmac_rx_enable,
+       .tx_enable = xgene_xgmac_tx_enable,
+       .rx_disable = xgene_xgmac_rx_disable,
+       .tx_disable = xgene_xgmac_tx_disable,
+       .set_mac_addr = xgene_xgmac_set_mac_addr,
+};
+
+struct xgene_port_ops xgene_xgport_ops = {
+       .reset = xgene_enet_reset,
+       .cle_bypass = xgene_enet_xgcle_bypass,
+       .shutdown = xgene_enet_shutdown,
+};
diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_xgmac.h b/drivers/net/ethernet/apm/xgene/xgene_enet_xgmac.h
new file mode 100644 (file)
index 0000000..d2d59e7
--- /dev/null
@@ -0,0 +1,57 @@
+/* Applied Micro X-Gene SoC Ethernet Driver
+ *
+ * Copyright (c) 2014, Applied Micro Circuits Corporation
+ * Authors: Iyappan Subramanian <isubramanian@apm.com>
+ *         Keyur Chudgar <kchudgar@apm.com>
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __XGENE_ENET_XGMAC_H__
+#define __XGENE_ENET_XGMAC_H__
+
+#define BLOCK_AXG_MAC_OFFSET           0x0800
+#define BLOCK_AXG_MAC_CSR_OFFSET       0x2000
+
+#define AXGMAC_CONFIG_0                        0x0000
+#define AXGMAC_CONFIG_1                        0x0004
+#define HSTMACRST                      BIT(31)
+#define HSTTCTLEN                      BIT(31)
+#define HSTTFEN                                BIT(30)
+#define HSTRCTLEN                      BIT(29)
+#define HSTRFEN                                BIT(28)
+#define HSTPPEN                                BIT(7)
+#define HSTDRPLT64                     BIT(5)
+#define HSTLENCHK                      BIT(3)
+#define HSTMACADR_LSW_ADDR             0x0010
+#define HSTMACADR_MSW_ADDR             0x0014
+#define HSTMAXFRAME_LENGTH_ADDR                0x0020
+
+#define XG_RSIF_CONFIG_REG_ADDR                0x00a0
+#define XCLE_BYPASS_REG0_ADDR           0x0160
+#define XCLE_BYPASS_REG1_ADDR           0x0164
+#define XG_CFG_BYPASS_ADDR             0x0204
+#define XG_LINK_STATUS_ADDR            0x0228
+#define XG_ENET_SPARE_CFG_REG_ADDR     0x040c
+#define XG_ENET_SPARE_CFG_REG_1_ADDR   0x0410
+#define XGENET_RX_DV_GATE_REG_0_ADDR   0x0804
+
+#define PHY_POLL_LINK_ON       (10 * HZ)
+#define PHY_POLL_LINK_OFF      (PHY_POLL_LINK_ON / 5)
+
+void xgene_enet_link_state(struct work_struct *work);
+extern struct xgene_mac_ops xgene_xgmac_ops;
+extern struct xgene_port_ops xgene_xgport_ops;
+
+#endif /* __XGENE_ENET_XGMAC_H__ */
index 07568818864440190918e314425f697a26d93ff6..9ae36979bdee010aa2e8a276dc17611593e3383c 100644 (file)
@@ -436,7 +436,8 @@ static int bcm_sysport_set_wol(struct net_device *dev,
        /* Flag the device and relevant IRQ as wakeup capable */
        if (wol->wolopts) {
                device_set_wakeup_enable(kdev, 1);
-               enable_irq_wake(priv->wol_irq);
+               if (priv->wol_irq_disabled)
+                       enable_irq_wake(priv->wol_irq);
                priv->wol_irq_disabled = 0;
        } else {
                device_set_wakeup_enable(kdev, 0);
index fff2634b6f3414258655d2174e7988a1be3f843d..fdc9ec09e453510636460780226e0349cc51b9a5 100644 (file)
@@ -1285,11 +1285,6 @@ static unsigned int bcmgenet_desc_rx(struct bcmgenet_priv *priv,
                cb = &priv->rx_cbs[priv->rx_read_ptr];
                skb = cb->skb;
 
-               rxpktprocessed++;
-
-               priv->rx_read_ptr++;
-               priv->rx_read_ptr &= (priv->num_rx_bds - 1);
-
                /* We do not have a backing SKB, so we do not have a
                 * corresponding DMA mapping for this incoming packet since
                 * bcmgenet_rx_refill always either has both skb and mapping or
@@ -1404,6 +1399,10 @@ refill:
                err = bcmgenet_rx_refill(priv, cb);
                if (err)
                        netif_err(priv, rx_err, dev, "Rx refill failed\n");
+
+               rxpktprocessed++;
+               priv->rx_read_ptr++;
+               priv->rx_read_ptr &= (priv->num_rx_bds - 1);
        }
 
        return rxpktprocessed;
index b82b7e4e06b27222af1613799af7354790210294..149a0d70c10883f3f769904ef6ae2ca6b2f66f8e 100644 (file)
@@ -86,7 +86,9 @@ int bcmgenet_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
        /* Flag the device and relevant IRQ as wakeup capable */
        if (wol->wolopts) {
                device_set_wakeup_enable(kdev, 1);
-               enable_irq_wake(priv->wol_irq);
+               /* Avoid unbalanced enable_irq_wake calls */
+               if (priv->wol_irq_disabled)
+                       enable_irq_wake(priv->wol_irq);
                priv->wol_irq_disabled = false;
        } else {
                device_set_wakeup_enable(kdev, 0);
index 9b2c669b6522234abedd23db142ad5493a008ade..410ed5805a9a8c46ff23cc0df05a20e3729b3c39 100644 (file)
@@ -968,7 +968,7 @@ void t4_intr_enable(struct adapter *adapter);
 void t4_intr_disable(struct adapter *adapter);
 int t4_slow_intr_handler(struct adapter *adapter);
 
-int t4_wait_dev_ready(struct adapter *adap);
+int t4_wait_dev_ready(void __iomem *regs);
 int t4_link_start(struct adapter *adap, unsigned int mbox, unsigned int port,
                  struct link_config *lc);
 int t4_restart_aneg(struct adapter *adap, unsigned int mbox, unsigned int port);
index 321f3d9385c9b0f6ec90c04c3fe91b63dc131c32..5b38e955af6ec39b804b333cbbfd9bdf3817db4f 100644 (file)
@@ -6137,7 +6137,7 @@ static pci_ers_result_t eeh_slot_reset(struct pci_dev *pdev)
        pci_save_state(pdev);
        pci_cleanup_aer_uncorrect_error_status(pdev);
 
-       if (t4_wait_dev_ready(adap) < 0)
+       if (t4_wait_dev_ready(adap->regs) < 0)
                return PCI_ERS_RESULT_DISCONNECT;
        if (t4_fw_hello(adap, adap->fn, adap->fn, MASTER_MUST, NULL) < 0)
                return PCI_ERS_RESULT_DISCONNECT;
@@ -6530,6 +6530,10 @@ static int init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
                goto out_disable_device;
        }
 
+       err = t4_wait_dev_ready(regs);
+       if (err < 0)
+               goto out_unmap_bar0;
+
        /* We control everything through one PF */
        func = SOURCEPF_GET(readl(regs + PL_WHOAMI));
        if (func != ent->driver_data) {
index fab4c84a1da4c5fa8313f6c133613c245b7846be..5e1b314e11af674f8d0f7f1ebf3bed60835dda08 100644 (file)
@@ -1123,7 +1123,10 @@ out_free:        dev_kfree_skb_any(skb);
                lso->c.ipid_ofst = htons(0);
                lso->c.mss = htons(ssi->gso_size);
                lso->c.seqno_offset = htonl(0);
-               lso->c.len = htonl(skb->len);
+               if (is_t4(adap->params.chip))
+                       lso->c.len = htonl(skb->len);
+               else
+                       lso->c.len = htonl(LSO_T5_XFER_SIZE(skb->len));
                cpl = (void *)(lso + 1);
                cntrl = TXPKT_CSUM_TYPE(v6 ? TX_CSUM_TCPIP6 : TX_CSUM_TCPIP) |
                        TXPKT_IPHDR_LEN(l3hdr_len) |
index 22d7581341a912a3fb1329fdf7445677aa27f2cd..1fff1495fe31561187e325dedc741a9367cf8c81 100644 (file)
@@ -3845,12 +3845,19 @@ static void init_link_config(struct link_config *lc, unsigned int caps)
        }
 }
 
-int t4_wait_dev_ready(struct adapter *adap)
+#define CIM_PF_NOACCESS 0xeeeeeeee
+
+int t4_wait_dev_ready(void __iomem *regs)
 {
-       if (t4_read_reg(adap, PL_WHOAMI) != 0xffffffff)
+       u32 whoami;
+
+       whoami = readl(regs + PL_WHOAMI);
+       if (whoami != 0xffffffff && whoami != CIM_PF_NOACCESS)
                return 0;
+
        msleep(500);
-       return t4_read_reg(adap, PL_WHOAMI) != 0xffffffff ? 0 : -EIO;
+       whoami = readl(regs + PL_WHOAMI);
+       return (whoami != 0xffffffff && whoami != CIM_PF_NOACCESS ? 0 : -EIO);
 }
 
 struct flash_desc {
@@ -3919,10 +3926,6 @@ int t4_prep_adapter(struct adapter *adapter)
        uint16_t device_id;
        u32 pl_rev;
 
-       ret = t4_wait_dev_ready(adapter);
-       if (ret < 0)
-               return ret;
-
        get_pci_mode(adapter, &adapter->params.pci);
        pl_rev = G_REV(t4_read_reg(adapter, PL_REV));
 
index 52e08103f221f8647355f61882be1601d0a428c1..5f4db2398c71a97885727e9e97f58529a6fe08da 100644 (file)
@@ -527,6 +527,7 @@ struct cpl_tx_pkt_lso_core {
 #define LSO_LAST_SLICE    (1 << 22)
 #define LSO_FIRST_SLICE   (1 << 23)
 #define LSO_OPCODE(x)     ((x) << 24)
+#define LSO_T5_XFER_SIZE(x) ((x) << 0)
        __be16 ipid_ofst;
        __be16 mss;
        __be32 seqno_offset;
index eee2728830271e7cbf98252f3713fe5eec28f7f3..a1024db5dc136bb2a64fe5d3d696580ae3e38434 100644 (file)
@@ -72,9 +72,8 @@
 #define  PIDX_MASK   0x00003fffU
 #define  PIDX_SHIFT  0
 #define  PIDX(x)     ((x) << PIDX_SHIFT)
-#define  S_PIDX_T5   0
-#define  M_PIDX_T5   0x1fffU
-#define  PIDX_T5(x)  (((x) >> S_PIDX_T5) & M_PIDX_T5)
+#define  PIDX_SHIFT_T5   0
+#define  PIDX_T5(x)  ((x) << PIDX_SHIFT_T5)
 
 
 #define SGE_TIMERREGS  6
index 8498a641b2e32c9c17169b2dfe9c4122a584a3d9..bfa398d9182681c92203f5a7687010e5fdcad7d8 100644 (file)
@@ -163,15 +163,19 @@ void t4vf_os_link_changed(struct adapter *adapter, int pidx, int link_ok)
                netif_carrier_on(dev);
 
                switch (pi->link_cfg.speed) {
-               case SPEED_10000:
+               case 40000:
+                       s = "40Gbps";
+                       break;
+
+               case 10000:
                        s = "10Gbps";
                        break;
 
-               case SPEED_1000:
+               case 1000:
                        s = "1000Mbps";
                        break;
 
-               case SPEED_100:
+               case 100:
                        s = "100Mbps";
                        break;
 
@@ -2351,7 +2355,7 @@ static void cfg_queues(struct adapter *adapter)
                struct port_info *pi = adap2pinfo(adapter, pidx);
 
                pi->first_qset = qidx;
-               pi->nqsets = is_10g_port(&pi->link_cfg) ? q10g : 1;
+               pi->nqsets = is_x_10g_port(&pi->link_cfg) ? q10g : 1;
                qidx += pi->nqsets;
        }
        s->ethqsets = qidx;
index a5fb9493dee826563561072185d85ccc46513337..85036e6b42c4cd4f7663ef2487948448d2d04be8 100644 (file)
@@ -1208,7 +1208,10 @@ int t4vf_eth_xmit(struct sk_buff *skb, struct net_device *dev)
                lso->ipid_ofst = cpu_to_be16(0);
                lso->mss = cpu_to_be16(ssi->gso_size);
                lso->seqno_offset = cpu_to_be32(0);
-               lso->len = cpu_to_be32(skb->len);
+               if (is_t4(adapter->params.chip))
+                       lso->len = cpu_to_be32(skb->len);
+               else
+                       lso->len = cpu_to_be32(LSO_T5_XFER_SIZE(skb->len));
 
                /*
                 * Set up TX Packet CPL pointer, control word and perform
index f412d0fa0850c720849301b46584a208bfd79b26..95df61dcb4ce57021237a15013bfdc8e88c0fa5d 100644 (file)
@@ -228,6 +228,12 @@ static inline bool is_10g_port(const struct link_config *lc)
        return (lc->supported & SUPPORTED_10000baseT_Full) != 0;
 }
 
+static inline bool is_x_10g_port(const struct link_config *lc)
+{
+       return (lc->supported & FW_PORT_CAP_SPEED_10G) != 0 ||
+               (lc->supported & FW_PORT_CAP_SPEED_40G) != 0;
+}
+
 static inline unsigned int core_ticks_per_usec(const struct adapter *adapter)
 {
        return adapter->params.vpd.cclk / 1000;
index 25dfeb8f28ed015c6c49f12e163809daa8e1976a..e984fdc48ba2e326a738e6f5bfa14e1bfda73f02 100644 (file)
@@ -327,6 +327,8 @@ int t4vf_port_init(struct adapter *adapter, int pidx)
                v |= SUPPORTED_1000baseT_Full;
        if (word & FW_PORT_CAP_SPEED_10G)
                v |= SUPPORTED_10000baseT_Full;
+       if (word & FW_PORT_CAP_SPEED_40G)
+               v |= SUPPORTED_40000baseSR4_Full;
        if (word & FW_PORT_CAP_ANEG)
                v |= SUPPORTED_Autoneg;
        init_link_config(&pi->link_cfg, v);
@@ -1352,11 +1354,13 @@ int t4vf_handle_fw_rpl(struct adapter *adapter, const __be64 *rpl)
                if (word & FW_PORT_CMD_TXPAUSE)
                        fc |= PAUSE_TX;
                if (word & FW_PORT_CMD_LSPEED(FW_PORT_CAP_SPEED_100M))
-                       speed = SPEED_100;
+                       speed = 100;
                else if (word & FW_PORT_CMD_LSPEED(FW_PORT_CAP_SPEED_1G))
-                       speed = SPEED_1000;
+                       speed = 1000;
                else if (word & FW_PORT_CMD_LSPEED(FW_PORT_CAP_SPEED_10G))
-                       speed = SPEED_10000;
+                       speed = 10000;
+               else if (word & FW_PORT_CMD_LSPEED(FW_PORT_CAP_SPEED_40G))
+                       speed = 40000;
 
                /*
                 * Scan all of our "ports" (Virtual Interfaces) looking for
index 2c578db401e89dd978e27ce3f9b575c0fd9b4cad..08f5b911d96be1b01f99484ee748c24aaed7f483 100644 (file)
@@ -125,7 +125,7 @@ out:
 }
 
 #define FCC_NAPI_RX_EVENT_MSK  (FCC_ENET_RXF | FCC_ENET_RXB)
-#define FCC_NAPI_TX_EVENT_MSK  (FCC_ENET_TXF | FCC_ENET_TXB)
+#define FCC_NAPI_TX_EVENT_MSK  (FCC_ENET_TXB)
 #define FCC_RX_EVENT           (FCC_ENET_RXF)
 #define FCC_TX_EVENT           (FCC_ENET_TXB)
 #define FCC_ERR_EVENT_MSK      (FCC_ENET_TXE)
index 41aa0b475ca0af009f8edfcfdd9a9cd02a19ecb1..f30411f0701f694175392198941b0d69d3798682 100644 (file)
@@ -116,7 +116,7 @@ static int do_pd_setup(struct fs_enet_private *fep)
 }
 
 #define SCC_NAPI_RX_EVENT_MSK  (SCCE_ENET_RXF | SCCE_ENET_RXB)
-#define SCC_NAPI_TX_EVENT_MSK  (SCCE_ENET_TXF | SCCE_ENET_TXB)
+#define SCC_NAPI_TX_EVENT_MSK  (SCCE_ENET_TXB)
 #define SCC_RX_EVENT           (SCCE_ENET_RXF)
 #define SCC_TX_EVENT           (SCCE_ENET_TXB)
 #define SCC_ERR_EVENT_MSK      (SCCE_ENET_TXE | SCCE_ENET_BSY)
index 583e71ab7f51b7f9edb307814d1310d1beebb2ff..964c6bf377104df3eafd6043299d04051b51db5c 100644 (file)
@@ -28,7 +28,9 @@
 #include <linux/of_device.h>
 
 #include <asm/io.h>
+#if IS_ENABLED(CONFIG_UCC_GETH)
 #include <asm/ucc.h>   /* for ucc_set_qe_mux_mii_mng() */
+#endif
 
 #include "gianfar.h"
 
@@ -102,19 +104,22 @@ static int fsl_pq_mdio_write(struct mii_bus *bus, int mii_id, int regnum,
 {
        struct fsl_pq_mdio_priv *priv = bus->priv;
        struct fsl_pq_mii __iomem *regs = priv->regs;
-       u32 status;
+       unsigned int timeout;
 
        /* Set the PHY address and the register address we want to write */
-       out_be32(&regs->miimadd, (mii_id << 8) | regnum);
+       iowrite32be((mii_id << 8) | regnum, &regs->miimadd);
 
        /* Write out the value we want */
-       out_be32(&regs->miimcon, value);
+       iowrite32be(value, &regs->miimcon);
 
        /* Wait for the transaction to finish */
-       status = spin_event_timeout(!(in_be32(&regs->miimind) & MIIMIND_BUSY),
-                                   MII_TIMEOUT, 0);
+       timeout = MII_TIMEOUT;
+       while ((ioread32be(&regs->miimind) & MIIMIND_BUSY) && timeout) {
+               cpu_relax();
+               timeout--;
+       }
 
-       return status ? 0 : -ETIMEDOUT;
+       return timeout ? 0 : -ETIMEDOUT;
 }
 
 /*
@@ -131,25 +136,29 @@ static int fsl_pq_mdio_read(struct mii_bus *bus, int mii_id, int regnum)
 {
        struct fsl_pq_mdio_priv *priv = bus->priv;
        struct fsl_pq_mii __iomem *regs = priv->regs;
-       u32 status;
+       unsigned int timeout;
        u16 value;
 
        /* Set the PHY address and the register address we want to read */
-       out_be32(&regs->miimadd, (mii_id << 8) | regnum);
+       iowrite32be((mii_id << 8) | regnum, &regs->miimadd);
 
        /* Clear miimcom, and then initiate a read */
-       out_be32(&regs->miimcom, 0);
-       out_be32(&regs->miimcom, MII_READ_COMMAND);
+       iowrite32be(0, &regs->miimcom);
+       iowrite32be(MII_READ_COMMAND, &regs->miimcom);
 
        /* Wait for the transaction to finish, normally less than 100us */
-       status = spin_event_timeout(!(in_be32(&regs->miimind) &
-                                   (MIIMIND_NOTVALID | MIIMIND_BUSY)),
-                                   MII_TIMEOUT, 0);
-       if (!status)
+       timeout = MII_TIMEOUT;
+       while ((ioread32be(&regs->miimind) &
+              (MIIMIND_NOTVALID | MIIMIND_BUSY)) && timeout) {
+               cpu_relax();
+               timeout--;
+       }
+
+       if (!timeout)
                return -ETIMEDOUT;
 
        /* Grab the value of the register from miimstat */
-       value = in_be32(&regs->miimstat);
+       value = ioread32be(&regs->miimstat);
 
        dev_dbg(&bus->dev, "read %04x from address %x/%x\n", value, mii_id, regnum);
        return value;
@@ -160,23 +169,26 @@ static int fsl_pq_mdio_reset(struct mii_bus *bus)
 {
        struct fsl_pq_mdio_priv *priv = bus->priv;
        struct fsl_pq_mii __iomem *regs = priv->regs;
-       u32 status;
+       unsigned int timeout;
 
        mutex_lock(&bus->mdio_lock);
 
        /* Reset the management interface */
-       out_be32(&regs->miimcfg, MIIMCFG_RESET);
+       iowrite32be(MIIMCFG_RESET, &regs->miimcfg);
 
        /* Setup the MII Mgmt clock speed */
-       out_be32(&regs->miimcfg, MIIMCFG_INIT_VALUE);
+       iowrite32be(MIIMCFG_INIT_VALUE, &regs->miimcfg);
 
        /* Wait until the bus is free */
-       status = spin_event_timeout(!(in_be32(&regs->miimind) & MIIMIND_BUSY),
-                                   MII_TIMEOUT, 0);
+       timeout = MII_TIMEOUT;
+       while ((ioread32be(&regs->miimind) & MIIMIND_BUSY) && timeout) {
+               cpu_relax();
+               timeout--;
+       }
 
        mutex_unlock(&bus->mdio_lock);
 
-       if (!status) {
+       if (!timeout) {
                dev_err(&bus->dev, "timeout waiting for MII bus\n");
                return -EBUSY;
        }
@@ -433,7 +445,7 @@ static int fsl_pq_mdio_probe(struct platform_device *pdev)
 
                        tbipa = data->get_tbipa(priv->map);
 
-                       out_be32(tbipa, be32_to_cpup(prop));
+                       iowrite32be(be32_to_cpup(prop), tbipa);
                }
        }
 
index fb29d049f4e12b8df13bbe21ad44c8e73de1ea01..379b1a578d3da37deb4e23114a72631085231252 100644 (file)
 #include <linux/net_tstamp.h>
 
 #include <asm/io.h>
+#ifdef CONFIG_PPC
 #include <asm/reg.h>
 #include <asm/mpc85xx.h>
+#endif
 #include <asm/irq.h>
 #include <asm/uaccess.h>
 #include <linux/module.h>
 #include <linux/phy_fixed.h>
 #include <linux/of.h>
 #include <linux/of_net.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
 
 #include "gianfar.h"
 
@@ -161,7 +165,7 @@ static void gfar_init_rxbdp(struct gfar_priv_rx_q *rx_queue, struct rxbd8 *bdp,
        if (bdp == rx_queue->rx_bd_base + rx_queue->rx_ring_size - 1)
                lstatus |= BD_LFLAG(RXBD_WRAP);
 
-       eieio();
+       gfar_wmb();
 
        bdp->lstatus = lstatus;
 }
@@ -1061,6 +1065,7 @@ static void gfar_init_filer_table(struct gfar_private *priv)
        }
 }
 
+#ifdef CONFIG_PPC
 static void __gfar_detect_errata_83xx(struct gfar_private *priv)
 {
        unsigned int pvr = mfspr(SPRN_PVR);
@@ -1093,6 +1098,7 @@ static void __gfar_detect_errata_85xx(struct gfar_private *priv)
            ((SVR_SOC_VER(svr) == SVR_P2010) && (SVR_REV(svr) < 0x20)))
                priv->errata |= GFAR_ERRATA_76; /* aka eTSEC 20 */
 }
+#endif
 
 static void gfar_detect_errata(struct gfar_private *priv)
 {
@@ -1101,10 +1107,12 @@ static void gfar_detect_errata(struct gfar_private *priv)
        /* no plans to fix */
        priv->errata |= GFAR_ERRATA_A002;
 
+#ifdef CONFIG_PPC
        if (pvr_version_is(PVR_VER_E500V1) || pvr_version_is(PVR_VER_E500V2))
                __gfar_detect_errata_85xx(priv);
        else /* non-mpc85xx parts, i.e. e300 core based */
                __gfar_detect_errata_83xx(priv);
+#endif
 
        if (priv->errata)
                dev_info(dev, "enabled errata workarounds, flags: 0x%x\n",
@@ -1754,26 +1762,32 @@ static void gfar_halt_nodisable(struct gfar_private *priv)
 {
        struct gfar __iomem *regs = priv->gfargrp[0].regs;
        u32 tempval;
+       unsigned int timeout;
+       int stopped;
 
        gfar_ints_disable(priv);
 
+       if (gfar_is_dma_stopped(priv))
+               return;
+
        /* Stop the DMA, and wait for it to stop */
        tempval = gfar_read(&regs->dmactrl);
-       if ((tempval & (DMACTRL_GRS | DMACTRL_GTS)) !=
-           (DMACTRL_GRS | DMACTRL_GTS)) {
-               int ret;
-
-               tempval |= (DMACTRL_GRS | DMACTRL_GTS);
-               gfar_write(&regs->dmactrl, tempval);
+       tempval |= (DMACTRL_GRS | DMACTRL_GTS);
+       gfar_write(&regs->dmactrl, tempval);
 
-               do {
-                       ret = spin_event_timeout(((gfar_read(&regs->ievent) &
-                                (IEVENT_GRSC | IEVENT_GTSC)) ==
-                                (IEVENT_GRSC | IEVENT_GTSC)), 1000000, 0);
-                       if (!ret && !(gfar_read(&regs->ievent) & IEVENT_GRSC))
-                               ret = __gfar_is_rx_idle(priv);
-               } while (!ret);
+retry:
+       timeout = 1000;
+       while (!(stopped = gfar_is_dma_stopped(priv)) && timeout) {
+               cpu_relax();
+               timeout--;
        }
+
+       if (!timeout)
+               stopped = gfar_is_dma_stopped(priv);
+
+       if (!stopped && !gfar_is_rx_dma_stopped(priv) &&
+           !__gfar_is_rx_idle(priv))
+               goto retry;
 }
 
 /* Halt the receive and transmit queues */
@@ -2357,18 +2371,11 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev)
         */
        spin_lock_irqsave(&tx_queue->txlock, flags);
 
-       /* The powerpc-specific eieio() is used, as wmb() has too strong
-        * semantics (it requires synchronization between cacheable and
-        * uncacheable mappings, which eieio doesn't provide and which we
-        * don't need), thus requiring a more expensive sync instruction.  At
-        * some point, the set of architecture-independent barrier functions
-        * should be expanded to include weaker barriers.
-        */
-       eieio();
+       gfar_wmb();
 
        txbdp_start->lstatus = lstatus;
 
-       eieio(); /* force lstatus write before tx_skbuff */
+       gfar_wmb(); /* force lstatus write before tx_skbuff */
 
        tx_queue->tx_skbuff[tx_queue->skb_curtx] = skb;
 
@@ -3240,22 +3247,21 @@ static void gfar_set_mac_for_addr(struct net_device *dev, int num,
 {
        struct gfar_private *priv = netdev_priv(dev);
        struct gfar __iomem *regs = priv->gfargrp[0].regs;
-       int idx;
-       char tmpbuf[ETH_ALEN];
        u32 tempval;
        u32 __iomem *macptr = &regs->macstnaddr1;
 
        macptr += num*2;
 
-       /* Now copy it into the mac registers backwards, cuz
-        * little endian is silly
+       /* For a station address of 0x12345678ABCD in transmission
+        * order (BE), MACnADDR1 is set to 0xCDAB7856 and
+        * MACnADDR2 is set to 0x34120000.
         */
-       for (idx = 0; idx < ETH_ALEN; idx++)
-               tmpbuf[ETH_ALEN - 1 - idx] = addr[idx];
+       tempval = (addr[5] << 24) | (addr[4] << 16) |
+                 (addr[3] << 8)  |  addr[2];
 
-       gfar_write(macptr, *((u32 *) (tmpbuf)));
+       gfar_write(macptr, tempval);
 
-       tempval = *((u32 *) (tmpbuf + 4));
+       tempval = (addr[1] << 24) | (addr[0] << 16);
 
        gfar_write(macptr+1, tempval);
 }
index 84632c569f2c3ba43225c2a9a4f773dd24ea1580..2805cfbf1765147487c2f3da6390858803c5cd33 100644 (file)
@@ -1226,6 +1226,37 @@ static inline void gfar_write_isrg(struct gfar_private *priv)
        }
 }
 
+static inline int gfar_is_dma_stopped(struct gfar_private *priv)
+{
+       struct gfar __iomem *regs = priv->gfargrp[0].regs;
+
+       return ((gfar_read(&regs->ievent) & (IEVENT_GRSC | IEVENT_GTSC)) ==
+              (IEVENT_GRSC | IEVENT_GTSC));
+}
+
+static inline int gfar_is_rx_dma_stopped(struct gfar_private *priv)
+{
+       struct gfar __iomem *regs = priv->gfargrp[0].regs;
+
+       return gfar_read(&regs->ievent) & IEVENT_GRSC;
+}
+
+static inline void gfar_wmb(void)
+{
+#if defined(CONFIG_PPC)
+       /* The powerpc-specific eieio() is used, as wmb() has too strong
+        * semantics (it requires synchronization between cacheable and
+        * uncacheable mappings, which eieio() doesn't provide and which we
+        * don't need), thus requiring a more expensive sync instruction.  At
+        * some point, the set of architecture-independent barrier functions
+        * should be expanded to include weaker barriers.
+        */
+       eieio();
+#else
+       wmb(); /* order write acesses for BD (or FCB) fields */
+#endif
+}
+
 irqreturn_t gfar_receive(int irq, void *dev_id);
 int startup_gfar(struct net_device *dev);
 void stop_gfar(struct net_device *dev);
index 6a6d5ee51e6a04bd077882b717742ee9a6e39522..6919adb66f53a5305a1d6db538b9d7fff61a0e96 100644 (file)
@@ -304,6 +304,7 @@ config FM10K
        tristate "Intel(R) FM10000 Ethernet Switch Host Interface Support"
        default n
        depends on PCI_MSI
+       select PTP_1588_CLOCK
        ---help---
          This driver supports Intel(R) FM10000 Ethernet Switch Host
          Interface.  For more information on how to identify your adapter,
index 6c800a330d66306f1fb2a83435e9373f19ecd857..9d7118a0d67a7a9ec7350a00f52bab104cfb6d01 100644 (file)
@@ -219,11 +219,10 @@ static bool fm10k_can_reuse_rx_page(struct fm10k_rx_buffer *rx_buffer,
        /* flip page offset to other buffer */
        rx_buffer->page_offset ^= FM10K_RX_BUFSZ;
 
-       /* since we are the only owner of the page and we need to
-        * increment it, just set the value to 2 in order to avoid
-        * an unnecessary locked operation
+       /* Even if we own the page, we are not allowed to use atomic_set()
+        * This would break get_page_unless_zero() users.
         */
-       atomic_set(&page->_count, 2);
+       atomic_inc(&page->_count);
 #else
        /* move offset up to the next cache line */
        rx_buffer->page_offset += truesize;
index ae59c0b108c55bf2d802a9e14ed6c92b19758635..a21b14495ebd0d7b953a1d8e4b2319d23452b95e 100644 (file)
@@ -6545,11 +6545,10 @@ static bool igb_can_reuse_rx_page(struct igb_rx_buffer *rx_buffer,
        /* flip page offset to other buffer */
        rx_buffer->page_offset ^= IGB_RX_BUFSZ;
 
-       /* since we are the only owner of the page and we need to
-        * increment it, just set the value to 2 in order to avoid
-        * an unnecessary locked operation
+       /* Even if we own the page, we are not allowed to use atomic_set()
+        * This would break get_page_unless_zero() users.
         */
-       atomic_set(&page->_count, 2);
+       atomic_inc(&page->_count);
 #else
        /* move offset up to the next cache line */
        rx_buffer->page_offset += truesize;
index d677b5a23b5869a71a8d9f04fa7f7d1e6762ea05..fec5212d43374835156049f8b7c5f0bc828dcdde 100644 (file)
@@ -1865,12 +1865,10 @@ static bool ixgbe_add_rx_frag(struct ixgbe_ring *rx_ring,
        /* flip page offset to other buffer */
        rx_buffer->page_offset ^= truesize;
 
-       /*
-        * since we are the only owner of the page and we need to
-        * increment it, just set the value to 2 in order to avoid
-        * an unecessary locked operation
+       /* Even if we own the page, we are not allowed to use atomic_set()
+        * This would break get_page_unless_zero() users.
         */
-       atomic_set(&page->_count, 2);
+       atomic_inc(&page->_count);
 #else
        /* move offset up to the next cache line */
        rx_buffer->page_offset += truesize;
index b3b72ad92d4a9de406e327d93d10cc1e1ef7d8cd..d323a695dfbcb4e3c6f23dfacf75cc45fb7908ee 100644 (file)
@@ -64,7 +64,8 @@ config MVPP2
 
 config PXA168_ETH
        tristate "Marvell pxa168 ethernet support"
-       depends on (CPU_PXA168 || ARCH_BERLIN || COMPILE_TEST) && HAS_IOMEM
+       depends on HAS_IOMEM && HAS_DMA
+       depends on CPU_PXA168 || ARCH_BERLIN || COMPILE_TEST
        select PHYLIB
        ---help---
          This driver supports the pxa168 Ethernet ports.
index a33048ee9621a360060fed128d6f048faf53ea42..01660c595f5c3e7e4a8470228fbf04699b690e9c 100644 (file)
@@ -76,10 +76,10 @@ static int mlx4_alloc_pages(struct mlx4_en_priv *priv,
        page_alloc->dma = dma;
        page_alloc->page_offset = frag_info->frag_align;
        /* Not doing get_page() for each frag is a big win
-        * on asymetric workloads.
+        * on asymetric workloads. Note we can not use atomic_set().
         */
-       atomic_set(&page->_count,
-                  page_alloc->page_size / frag_info->frag_stride);
+       atomic_add(page_alloc->page_size / frag_info->frag_stride - 1,
+                  &page->_count);
        return 0;
 }
 
index 5efe60ea6526b3d06305530b75240b9de719f1f3..0adcf73cf722400c6e1a25dff3bab57bd5b8cb71 100644 (file)
@@ -134,7 +134,7 @@ static void dwmac1000_set_filter(struct mac_device_info *hw,
        void __iomem *ioaddr = (void __iomem *)dev->base_addr;
        unsigned int value = 0;
        unsigned int perfect_addr_number = hw->unicast_filter_entries;
-       u32 mc_filter[2];
+       u32 mc_filter[8];
        int mcbitslog2 = hw->mcast_bits_log2;
 
        pr_debug("%s: # mcasts %d, # unicast %d\n", __func__,
@@ -182,7 +182,7 @@ static void dwmac1000_set_filter(struct mac_device_info *hw,
                struct netdev_hw_addr *ha;
 
                netdev_for_each_uc_addr(ha, dev) {
-                       stmmac_get_mac_addr(ioaddr, ha->addr,
+                       stmmac_set_mac_addr(ioaddr, ha->addr,
                                            GMAC_ADDR_HIGH(reg),
                                            GMAC_ADDR_LOW(reg));
                        reg++;
index 15396720f489a802338eda997b26dbff2de66103..3652afd3ec78d9e395a7902d9fe3cc6da570b43a 100644 (file)
@@ -954,7 +954,7 @@ static int vnet_start_xmit(struct sk_buff *skb, struct net_device *dev)
        spin_lock_irqsave(&port->vio.lock, flags);
 
        dr = &port->vio.drings[VIO_DRIVER_TX_RING];
-       if (unlikely(vnet_tx_dring_avail(dr) < 2)) {
+       if (unlikely(vnet_tx_dring_avail(dr) < 1)) {
                if (!netif_queue_stopped(dev)) {
                        netif_stop_queue(dev);
 
@@ -1049,7 +1049,7 @@ ldc_start_done:
        dev->stats.tx_bytes += port->tx_bufs[txi].skb->len;
 
        dr->prod = (dr->prod + 1) & (VNET_TX_RING_SIZE - 1);
-       if (unlikely(vnet_tx_dring_avail(dr) < 2)) {
+       if (unlikely(vnet_tx_dring_avail(dr) < 1)) {
                netif_stop_queue(dev);
                if (vnet_tx_dring_avail(dr) > VNET_TX_WAKEUP_THRESH(dr))
                        netif_wake_queue(dev);
index 38b4fae61f04ab32a2a0020ed50f0e12aef24a2c..29b3bb410781c2530a41ae689b8a91d51e1de3ef 100644 (file)
@@ -260,7 +260,7 @@ static void macvlan_broadcast(struct sk_buff *skb,
                                        mode == MACVLAN_MODE_BRIDGE) ?:
                                      netif_rx_ni(nskb);
                        macvlan_count_rx(vlan, skb->len + ETH_HLEN,
-                                        err == NET_RX_SUCCESS, 1);
+                                        err == NET_RX_SUCCESS, true);
                }
        }
 }
@@ -379,7 +379,7 @@ static void macvlan_forward_source_one(struct sk_buff *skb,
        nskb->pkt_type = PACKET_HOST;
 
        ret = netif_rx(nskb);
-       macvlan_count_rx(vlan, len, ret == NET_RX_SUCCESS, 0);
+       macvlan_count_rx(vlan, len, ret == NET_RX_SUCCESS, false);
 }
 
 static void macvlan_forward_source(struct sk_buff *skb,
@@ -407,7 +407,8 @@ static rx_handler_result_t macvlan_handle_frame(struct sk_buff **pskb)
        const struct macvlan_dev *src;
        struct net_device *dev;
        unsigned int len = 0;
-       int ret = NET_RX_DROP;
+       int ret;
+       rx_handler_result_t handle_res;
 
        port = macvlan_port_get_rcu(skb->dev);
        if (is_multicast_ether_addr(eth->h_dest)) {
@@ -423,6 +424,7 @@ static rx_handler_result_t macvlan_handle_frame(struct sk_buff **pskb)
                        vlan = src;
                        ret = macvlan_broadcast_one(skb, vlan, eth, 0) ?:
                              netif_rx(skb);
+                       handle_res = RX_HANDLER_CONSUMED;
                        goto out;
                }
 
@@ -448,17 +450,20 @@ static rx_handler_result_t macvlan_handle_frame(struct sk_buff **pskb)
        }
        len = skb->len + ETH_HLEN;
        skb = skb_share_check(skb, GFP_ATOMIC);
-       if (!skb)
+       if (!skb) {
+               ret = NET_RX_DROP;
+               handle_res = RX_HANDLER_CONSUMED;
                goto out;
+       }
 
        skb->dev = dev;
        skb->pkt_type = PACKET_HOST;
 
-       ret = netif_rx(skb);
-
+       ret = NET_RX_SUCCESS;
+       handle_res = RX_HANDLER_ANOTHER;
 out:
-       macvlan_count_rx(vlan, len, ret == NET_RX_SUCCESS, 0);
-       return RX_HANDLER_CONSUMED;
+       macvlan_count_rx(vlan, len, ret == NET_RX_SUCCESS, false);
+       return handle_res;
 }
 
 static int macvlan_queue_xmit(struct sk_buff *skb, struct net_device *dev)
index 011dbda2b2f1571e0e8241eb38ce3fc96f81a986..492435fce1d48d420872fef643141b1f0ddd848a 100644 (file)
@@ -26,6 +26,7 @@
 #include <linux/phy.h>
 #include <linux/micrel_phy.h>
 #include <linux/of.h>
+#include <linux/clk.h>
 
 /* Operation Mode Strap Override */
 #define MII_KSZPHY_OMSO                                0x16
@@ -72,9 +73,12 @@ static int ksz_config_flags(struct phy_device *phydev)
 {
        int regval;
 
-       if (phydev->dev_flags & MICREL_PHY_50MHZ_CLK) {
+       if (phydev->dev_flags & (MICREL_PHY_50MHZ_CLK | MICREL_PHY_25MHZ_CLK)) {
                regval = phy_read(phydev, MII_KSZPHY_CTRL);
-               regval |= KSZ8051_RMII_50MHZ_CLK;
+               if (phydev->dev_flags & MICREL_PHY_50MHZ_CLK)
+                       regval |= KSZ8051_RMII_50MHZ_CLK;
+               else
+                       regval &= ~KSZ8051_RMII_50MHZ_CLK;
                return phy_write(phydev, MII_KSZPHY_CTRL, regval);
        }
        return 0;
@@ -440,6 +444,27 @@ ksz9021_wr_mmd_phyreg(struct phy_device *phydev, int ptrad, int devnum,
 {
 }
 
+static int ksz8021_probe(struct phy_device *phydev)
+{
+       struct clk *clk;
+
+       clk = devm_clk_get(&phydev->dev, "rmii-ref");
+       if (!IS_ERR(clk)) {
+               unsigned long rate = clk_get_rate(clk);
+
+               if (rate > 24500000 && rate < 25500000) {
+                       phydev->dev_flags |= MICREL_PHY_25MHZ_CLK;
+               } else if (rate > 49500000 && rate < 50500000) {
+                       phydev->dev_flags |= MICREL_PHY_50MHZ_CLK;
+               } else {
+                       dev_err(&phydev->dev, "Clock rate out of range: %ld\n", rate);
+                       return -EINVAL;
+               }
+       }
+
+       return 0;
+}
+
 static struct phy_driver ksphy_driver[] = {
 {
        .phy_id         = PHY_ID_KS8737,
@@ -462,6 +487,7 @@ static struct phy_driver ksphy_driver[] = {
        .features       = (PHY_BASIC_FEATURES | SUPPORTED_Pause |
                           SUPPORTED_Asym_Pause),
        .flags          = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
+       .probe          = ksz8021_probe,
        .config_init    = ksz8021_config_init,
        .config_aneg    = genphy_config_aneg,
        .read_status    = genphy_read_status,
@@ -477,6 +503,7 @@ static struct phy_driver ksphy_driver[] = {
        .features       = (PHY_BASIC_FEATURES | SUPPORTED_Pause |
                           SUPPORTED_Asym_Pause),
        .flags          = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
+       .probe          = ksz8021_probe,
        .config_init    = ksz8021_config_init,
        .config_aneg    = genphy_config_aneg,
        .read_status    = genphy_read_status,
index 80e6f3430f65e96dfe3e3b8b13d694f727f330cc..68c3a3f4e0abe54910923aca8aa64286366e131a 100644 (file)
@@ -594,7 +594,7 @@ static long ppp_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
                        if (file == ppp->owner)
                                ppp_shutdown_interface(ppp);
                }
-               if (atomic_long_read(&file->f_count) <= 2) {
+               if (atomic_long_read(&file->f_count) < 2) {
                        ppp_release(NULL, file);
                        err = 0;
                } else
index acaaf6784179b04bf227de6fefb770f3e744a231..186ce541c65762f8ee1720aae7f573f145982406 100644 (file)
@@ -2152,9 +2152,7 @@ static int tun_chr_fasync(int fd, struct file *file, int on)
                goto out;
 
        if (on) {
-               ret = __f_setown(file, task_pid(current), PIDTYPE_PID, 0);
-               if (ret)
-                       goto out;
+               __f_setown(file, task_pid(current), PIDTYPE_PID, 0);
                tfile->flags |= TUN_FASYNC;
        } else
                tfile->flags &= ~TUN_FASYNC;
index 5cfd414b9a3ea5cc59224cffe0dd675bef490930..864159eb744eb3ac0127070f10aaed82a610a0e6 100644 (file)
@@ -26,7 +26,7 @@
 #include <linux/mdio.h>
 
 /* Version Information */
-#define DRIVER_VERSION "v1.06.1 (2014/10/01)"
+#define DRIVER_VERSION "v1.07.0 (2014/10/09)"
 #define DRIVER_AUTHOR "Realtek linux nic maintainers <nic_swsd@realtek.com>"
 #define DRIVER_DESC "Realtek RTL8152/RTL8153 Based USB Ethernet Adapters"
 #define MODULENAME "r8152"
@@ -566,6 +566,7 @@ struct r8152 {
        spinlock_t rx_lock, tx_lock;
        struct delayed_work schedule;
        struct mii_if_info mii;
+       struct mutex control;   /* use for hw setting */
 
        struct rtl_ops {
                void (*init)(struct r8152 *);
@@ -942,15 +943,8 @@ static int read_mii_word(struct net_device *netdev, int phy_id, int reg)
        if (phy_id != R8152_PHY_ID)
                return -EINVAL;
 
-       ret = usb_autopm_get_interface(tp->intf);
-       if (ret < 0)
-               goto out;
-
        ret = r8152_mdio_read(tp, reg);
 
-       usb_autopm_put_interface(tp->intf);
-
-out:
        return ret;
 }
 
@@ -965,12 +959,7 @@ void write_mii_word(struct net_device *netdev, int phy_id, int reg, int val)
        if (phy_id != R8152_PHY_ID)
                return;
 
-       if (usb_autopm_get_interface(tp->intf) < 0)
-               return;
-
        r8152_mdio_write(tp, reg, val);
-
-       usb_autopm_put_interface(tp->intf);
 }
 
 static int
@@ -989,12 +978,16 @@ static int rtl8152_set_mac_address(struct net_device *netdev, void *p)
        if (ret < 0)
                goto out1;
 
+       mutex_lock(&tp->control);
+
        memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len);
 
        ocp_write_byte(tp, MCU_TYPE_PLA, PLA_CRWECR, CRWECR_CONFIG);
        pla_ocp_write(tp, PLA_IDR, BYTE_EN_SIX_BYTES, 8, addr->sa_data);
        ocp_write_byte(tp, MCU_TYPE_PLA, PLA_CRWECR, CRWECR_NORAML);
 
+       mutex_unlock(&tp->control);
+
        usb_autopm_put_interface(tp->intf);
 out1:
        return ret;
@@ -2145,6 +2138,13 @@ static int rtl8152_set_features(struct net_device *dev,
 {
        netdev_features_t changed = features ^ dev->features;
        struct r8152 *tp = netdev_priv(dev);
+       int ret;
+
+       ret = usb_autopm_get_interface(tp->intf);
+       if (ret < 0)
+               goto out;
+
+       mutex_lock(&tp->control);
 
        if (changed & NETIF_F_HW_VLAN_CTAG_RX) {
                if (features & NETIF_F_HW_VLAN_CTAG_RX)
@@ -2153,7 +2153,12 @@ static int rtl8152_set_features(struct net_device *dev,
                        rtl_rx_vlan_en(tp, false);
        }
 
-       return 0;
+       mutex_unlock(&tp->control);
+
+       usb_autopm_put_interface(tp->intf);
+
+out:
+       return ret;
 }
 
 #define WAKE_ANY (WAKE_PHY | WAKE_MAGIC | WAKE_UCAST | WAKE_BCAST | WAKE_MCAST)
@@ -2851,6 +2856,11 @@ static void rtl_work_func_t(struct work_struct *work)
        if (test_bit(RTL8152_UNPLUG, &tp->flags))
                goto out1;
 
+       if (!mutex_trylock(&tp->control)) {
+               schedule_delayed_work(&tp->schedule, 0);
+               goto out1;
+       }
+
        if (test_bit(RTL8152_LINK_CHG, &tp->flags))
                set_carrier(tp);
 
@@ -2866,6 +2876,8 @@ static void rtl_work_func_t(struct work_struct *work)
        if (test_bit(PHY_RESET, &tp->flags))
                rtl_phy_reset(tp);
 
+       mutex_unlock(&tp->control);
+
 out1:
        usb_autopm_put_interface(tp->intf);
 }
@@ -2885,6 +2897,8 @@ static int rtl8152_open(struct net_device *netdev)
                goto out;
        }
 
+       mutex_lock(&tp->control);
+
        /* The WORK_ENABLE may be set when autoresume occurs */
        if (test_bit(WORK_ENABLE, &tp->flags)) {
                clear_bit(WORK_ENABLE, &tp->flags);
@@ -2913,6 +2927,8 @@ static int rtl8152_open(struct net_device *netdev)
                free_all_mem(tp);
        }
 
+       mutex_unlock(&tp->control);
+
        usb_autopm_put_interface(tp->intf);
 
 out:
@@ -2933,6 +2949,8 @@ static int rtl8152_close(struct net_device *netdev)
        if (res < 0) {
                rtl_drop_queued_tx(tp);
        } else {
+               mutex_lock(&tp->control);
+
                /* The autosuspend may have been enabled and wouldn't
                 * be disable when autoresume occurs, because the
                 * netif_running() would be false.
@@ -2945,6 +2963,9 @@ static int rtl8152_close(struct net_device *netdev)
                tasklet_disable(&tp->tl);
                tp->rtl_ops.down(tp);
                tasklet_enable(&tp->tl);
+
+               mutex_unlock(&tp->control);
+
                usb_autopm_put_interface(tp->intf);
        }
 
@@ -3169,6 +3190,8 @@ static int rtl8152_suspend(struct usb_interface *intf, pm_message_t message)
 {
        struct r8152 *tp = usb_get_intfdata(intf);
 
+       mutex_lock(&tp->control);
+
        if (PMSG_IS_AUTO(message))
                set_bit(SELECTIVE_SUSPEND, &tp->flags);
        else
@@ -3188,6 +3211,8 @@ static int rtl8152_suspend(struct usb_interface *intf, pm_message_t message)
                tasklet_enable(&tp->tl);
        }
 
+       mutex_unlock(&tp->control);
+
        return 0;
 }
 
@@ -3195,6 +3220,8 @@ static int rtl8152_resume(struct usb_interface *intf)
 {
        struct r8152 *tp = usb_get_intfdata(intf);
 
+       mutex_lock(&tp->control);
+
        if (!test_bit(SELECTIVE_SUSPEND, &tp->flags)) {
                tp->rtl_ops.init(tp);
                netif_device_attach(tp->netdev);
@@ -3220,6 +3247,8 @@ static int rtl8152_resume(struct usb_interface *intf)
                usb_submit_urb(tp->intr_urb, GFP_KERNEL);
        }
 
+       mutex_unlock(&tp->control);
+
        return 0;
 }
 
@@ -3230,9 +3259,13 @@ static void rtl8152_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
        if (usb_autopm_get_interface(tp->intf) < 0)
                return;
 
+       mutex_lock(&tp->control);
+
        wol->supported = WAKE_ANY;
        wol->wolopts = __rtl_get_wol(tp);
 
+       mutex_unlock(&tp->control);
+
        usb_autopm_put_interface(tp->intf);
 }
 
@@ -3245,9 +3278,13 @@ static int rtl8152_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
        if (ret < 0)
                goto out_set_wol;
 
+       mutex_lock(&tp->control);
+
        __rtl_set_wol(tp, wol->wolopts);
        tp->saved_wolopts = wol->wolopts & WAKE_ANY;
 
+       mutex_unlock(&tp->control);
+
        usb_autopm_put_interface(tp->intf);
 
 out_set_wol:
@@ -3282,11 +3319,25 @@ static
 int rtl8152_get_settings(struct net_device *netdev, struct ethtool_cmd *cmd)
 {
        struct r8152 *tp = netdev_priv(netdev);
+       int ret;
 
        if (!tp->mii.mdio_read)
                return -EOPNOTSUPP;
 
-       return mii_ethtool_gset(&tp->mii, cmd);
+       ret = usb_autopm_get_interface(tp->intf);
+       if (ret < 0)
+               goto out;
+
+       mutex_lock(&tp->control);
+
+       ret = mii_ethtool_gset(&tp->mii, cmd);
+
+       mutex_unlock(&tp->control);
+
+       usb_autopm_put_interface(tp->intf);
+
+out:
+       return ret;
 }
 
 static int rtl8152_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
@@ -3298,8 +3349,12 @@ static int rtl8152_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
        if (ret < 0)
                goto out;
 
+       mutex_lock(&tp->control);
+
        ret = rtl8152_set_speed(tp, cmd->autoneg, cmd->speed, cmd->duplex);
 
+       mutex_unlock(&tp->control);
+
        usb_autopm_put_interface(tp->intf);
 
 out:
@@ -3459,8 +3514,12 @@ rtl_ethtool_get_eee(struct net_device *net, struct ethtool_eee *edata)
        if (ret < 0)
                goto out;
 
+       mutex_lock(&tp->control);
+
        ret = tp->rtl_ops.eee_get(tp, edata);
 
+       mutex_unlock(&tp->control);
+
        usb_autopm_put_interface(tp->intf);
 
 out:
@@ -3477,10 +3536,14 @@ rtl_ethtool_set_eee(struct net_device *net, struct ethtool_eee *edata)
        if (ret < 0)
                goto out;
 
+       mutex_lock(&tp->control);
+
        ret = tp->rtl_ops.eee_set(tp, edata);
        if (!ret)
                ret = mii_nway_restart(&tp->mii);
 
+       mutex_unlock(&tp->control);
+
        usb_autopm_put_interface(tp->intf);
 
 out:
@@ -3522,7 +3585,9 @@ static int rtl8152_ioctl(struct net_device *netdev, struct ifreq *rq, int cmd)
                break;
 
        case SIOCGMIIREG:
+               mutex_lock(&tp->control);
                data->val_out = r8152_mdio_read(tp, data->reg_num);
+               mutex_unlock(&tp->control);
                break;
 
        case SIOCSMIIREG:
@@ -3530,7 +3595,9 @@ static int rtl8152_ioctl(struct net_device *netdev, struct ifreq *rq, int cmd)
                        res = -EPERM;
                        break;
                }
+               mutex_lock(&tp->control);
                r8152_mdio_write(tp, data->reg_num, data->val_in);
+               mutex_unlock(&tp->control);
                break;
 
        default:
@@ -3723,6 +3790,7 @@ static int rtl8152_probe(struct usb_interface *intf,
                goto out;
 
        tasklet_init(&tp->tl, bottom_half, (unsigned long)tp);
+       mutex_init(&tp->control);
        INIT_DELAYED_WORK(&tp->schedule, rtl_work_func_t);
 
        netdev->netdev_ops = &rtl8152_netdev_ops;
index 992bc02bc016f55e3106b7f4e426998b908cd4d0..692184dd674a378aba293ca6be398eccd0aa8b87 100644 (file)
@@ -1,5 +1 @@
-
 obj-$(CONFIG_WIMAX_I2400M)     += i2400m/
-
-# (from Sam Ravnborg) force kbuild to create built-in.o
-obj- := dummy.o
index bfa0b1518da1b5b7d95ce69170f5f7934ee375a1..01a7db061c6a2b8df0a8cac77a747c506d971705 100644 (file)
@@ -294,7 +294,6 @@ struct ath_tx_control {
  *  (axq_qnum).
  */
 struct ath_tx {
-       u16 seq_no;
        u32 txqsetup;
        spinlock_t txbuflock;
        struct list_head txbuf;
@@ -563,6 +562,7 @@ int ath_tx_init(struct ath_softc *sc, int nbufs);
 int ath_txq_update(struct ath_softc *sc, int qnum,
                   struct ath9k_tx_queue_info *q);
 void ath_update_max_aggr_framelen(struct ath_softc *sc, int queue, int txop);
+void ath_assign_seq(struct ath_common *common, struct sk_buff *skb);
 int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb,
                 struct ath_tx_control *txctl);
 void ath_tx_cabq(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
@@ -592,6 +592,8 @@ void ath9k_release_buffered_frames(struct ieee80211_hw *hw,
 struct ath_vif {
        struct list_head list;
 
+       u16 seq_no;
+
        /* BSS info */
        u8 bssid[ETH_ALEN];
        u16 aid;
index a6af855ef6ed9adb41e5a2c5d4ca90d197036c46..ecb783beeec2a1257ccc3abafa8bced7818246b2 100644 (file)
@@ -144,16 +144,8 @@ static struct ath_buf *ath9k_beacon_generate(struct ieee80211_hw *hw,
        mgmt_hdr->u.beacon.timestamp = avp->tsf_adjust;
 
        info = IEEE80211_SKB_CB(skb);
-       if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) {
-               /*
-                * TODO: make sure the seq# gets assigned properly (vs. other
-                * TX frames)
-                */
-               struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
-               sc->tx.seq_no += 0x10;
-               hdr->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG);
-               hdr->seq_ctrl |= cpu_to_le16(sc->tx.seq_no);
-       }
+
+       ath_assign_seq(common, skb);
 
        if (vif->p2p)
                ath9k_beacon_add_noa(sc, avp, skb);
index d779f4fa50e3a8392c697aaf0612bdea7ad99ad1..4014c4be6e79d86c72f68a2d57ace42fd4963907 100644 (file)
@@ -464,6 +464,7 @@ static int ath9k_init_priv(struct ath9k_htc_priv *priv,
                return -ENOMEM;
 
        ah->dev = priv->dev;
+       ah->hw = priv->hw;
        ah->hw_version.devid = devid;
        ah->hw_version.usbdev = drv_info;
        ah->ah_flags |= AH_USE_EEPROM;
index 205162449b726a135fa7d4b27ab90274e7758ca8..6f6a974f7fdb265960db2098f2c45b9684ffca2b 100644 (file)
@@ -2332,7 +2332,7 @@ static void ath9k_remove_chanctx(struct ieee80211_hw *hw,
                conf->def.chan->center_freq);
 
        ctx->assigned = false;
-       ctx->hw_queue_base = -1;
+       ctx->hw_queue_base = 0;
        ath_chanctx_event(sc, NULL, ATH_CHANCTX_EVENT_UNASSIGN);
 
        mutex_unlock(&sc->mutex);
index 8a69d08ec55c574349dda86348c04e709c4debfe..40ab65e6882f10cf0c4fa4707fb0b90065ea135a 100644 (file)
@@ -54,6 +54,12 @@ static struct sk_buff *ath9k_build_tx99_skb(struct ath_softc *sc)
        struct ieee80211_hdr *hdr;
        struct ieee80211_tx_info *tx_info;
        struct sk_buff *skb;
+       struct ath_vif *avp;
+
+       if (!sc->tx99_vif)
+               return NULL;
+
+       avp = (struct ath_vif *)sc->tx99_vif->drv_priv;
 
        skb = alloc_skb(len, GFP_KERNEL);
        if (!skb)
@@ -71,7 +77,7 @@ static struct sk_buff *ath9k_build_tx99_skb(struct ath_softc *sc)
        memcpy(hdr->addr2, hw->wiphy->perm_addr, ETH_ALEN);
        memcpy(hdr->addr3, hw->wiphy->perm_addr, ETH_ALEN);
 
-       hdr->seq_ctrl |= cpu_to_le16(sc->tx.seq_no);
+       hdr->seq_ctrl |= cpu_to_le16(avp->seq_no);
 
        tx_info = IEEE80211_SKB_CB(skb);
        memset(tx_info, 0, sizeof(*tx_info));
index 151ae49fa57e54c415d81a0c07bba000471af910..493a183d0aaf7d04c77103a8c4ea2b2c477089ad 100644 (file)
@@ -2139,6 +2139,28 @@ static struct ath_buf *ath_tx_setup_buffer(struct ath_softc *sc,
        return bf;
 }
 
+void ath_assign_seq(struct ath_common *common, struct sk_buff *skb)
+{
+       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
+       struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+       struct ieee80211_vif *vif = info->control.vif;
+       struct ath_vif *avp;
+
+       if (!(info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ))
+               return;
+
+       if (!vif)
+               return;
+
+       avp = (struct ath_vif *)vif->drv_priv;
+
+       if (info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT)
+               avp->seq_no += 0x10;
+
+       hdr->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG);
+       hdr->seq_ctrl |= cpu_to_le16(avp->seq_no);
+}
+
 static int ath_tx_prepare(struct ieee80211_hw *hw, struct sk_buff *skb,
                          struct ath_tx_control *txctl)
 {
@@ -2162,17 +2184,7 @@ static int ath_tx_prepare(struct ieee80211_hw *hw, struct sk_buff *skb,
        if (info->control.hw_key)
                frmlen += info->control.hw_key->icv_len;
 
-       /*
-        * As a temporary workaround, assign seq# here; this will likely need
-        * to be cleaned up to work better with Beacon transmission and virtual
-        * BSSes.
-        */
-       if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) {
-               if (info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT)
-                       sc->tx.seq_no += 0x10;
-               hdr->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG);
-               hdr->seq_ctrl |= cpu_to_le16(sc->tx.seq_no);
-       }
+       ath_assign_seq(ath9k_hw_common(sc->sc_ah), skb);
 
        if ((vif && vif->type != NL80211_IFTYPE_AP &&
                    vif->type != NL80211_IFTYPE_AP_VLAN) ||
index 83f47af19280de4c3cd0cdf528c997b3d149187d..338d723376043e78d813b1423f3c93e14cec820b 100644 (file)
@@ -79,13 +79,13 @@ void ath_printk(const char *level, const struct ath_common* common,
        vaf.fmt = fmt;
        vaf.va = &args;
 
-       if (common && common->hw && common->hw->wiphy)
+       if (common && common->hw && common->hw->wiphy) {
                printk("%sath: %s: %pV",
                       level, wiphy_name(common->hw->wiphy), &vaf);
-       else
+               trace_ath_log(common->hw->wiphy, &vaf);
+       } else {
                printk("%sath: %pV", level, &vaf);
-
-       trace_ath_log(common->hw->wiphy, &vaf);
+       }
 
        va_end(args);
 }
index 8efd17c52f65c5307b6136f14fcd94e2def45b2b..dd84557cf957e37d5a07ebce0b985f5e27d0d3a8 100644 (file)
@@ -168,7 +168,6 @@ static int prism2_bss_list_proc_show(struct seq_file *m, void *v)
        local_info_t *local = m->private;
        struct list_head *ptr = v;
        struct hostap_bss_info *bss;
-       int i;
 
        if (ptr == &local->bss_list) {
                seq_printf(m, "#BSSID\tlast_update\tcount\tcapab_info\tSSID(txt)\t"
@@ -181,9 +180,7 @@ static int prism2_bss_list_proc_show(struct seq_file *m, void *v)
                   bss->bssid, bss->last_update,
                   bss->count, bss->capab_info);
 
-       for (i = 0; i < bss->ssid_len; i++)
-               seq_putc(m,bss->ssid[i] >= 32 && bss->ssid[i] < 127 ?
-                          bss->ssid[i] : '_');
+       seq_printf(m, "%*pE", (int)bss->ssid_len, bss->ssid);
 
        seq_putc(m, '\t');
        seq_printf(m, "%*phN", (int)bss->ssid_len, bss->ssid);
index c3d726f334e33c27c7a14f9a4266ba4f4a1aa783..6fabea0309dd9a208d82be0451e07d24af45ab16 100644 (file)
@@ -2005,7 +2005,6 @@ static void isr_indicate_associated(struct ipw2100_priv *priv, u32 status)
        u32 chan;
        char *txratename;
        u8 bssid[ETH_ALEN];
-       DECLARE_SSID_BUF(ssid);
 
        /*
         * TBD: BSSID is usually 00:00:00:00:00:00 here and not
@@ -2067,8 +2066,8 @@ static void isr_indicate_associated(struct ipw2100_priv *priv, u32 status)
                break;
        }
 
-       IPW_DEBUG_INFO("%s: Associated with '%s' at %s, channel %d (BSSID=%pM)\n",
-                      priv->net_dev->name, print_ssid(ssid, essid, essid_len),
+       IPW_DEBUG_INFO("%s: Associated with '%*pE' at %s, channel %d (BSSID=%pM)\n",
+                      priv->net_dev->name, essid_len, essid,
                       txratename, chan, bssid);
 
        /* now we copy read ssid into dev */
@@ -2095,9 +2094,8 @@ static int ipw2100_set_essid(struct ipw2100_priv *priv, char *essid,
                .host_command_length = ssid_len
        };
        int err;
-       DECLARE_SSID_BUF(ssid);
 
-       IPW_DEBUG_HC("SSID: '%s'\n", print_ssid(ssid, essid, ssid_len));
+       IPW_DEBUG_HC("SSID: '%*pE'\n", ssid_len, essid);
 
        if (ssid_len)
                memcpy(cmd.host_command_parameters, essid, ssid_len);
@@ -2138,11 +2136,8 @@ static int ipw2100_set_essid(struct ipw2100_priv *priv, char *essid,
 
 static void isr_indicate_association_lost(struct ipw2100_priv *priv, u32 status)
 {
-       DECLARE_SSID_BUF(ssid);
-
        IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE | IPW_DL_ASSOC,
-                 "disassociated: '%s' %pM\n",
-                 print_ssid(ssid, priv->essid, priv->essid_len),
+                 "disassociated: '%*pE' %pM\n", priv->essid_len, priv->essid,
                  priv->bssid);
 
        priv->status &= ~(STATUS_ASSOCIATED | STATUS_ASSOCIATING);
@@ -6975,7 +6970,6 @@ static int ipw2100_wx_set_essid(struct net_device *dev,
        char *essid = "";       /* ANY */
        int length = 0;
        int err = 0;
-       DECLARE_SSID_BUF(ssid);
 
        mutex_lock(&priv->action_mutex);
        if (!(priv->status & STATUS_INITIALIZED)) {
@@ -7005,8 +6999,7 @@ static int ipw2100_wx_set_essid(struct net_device *dev,
                goto done;
        }
 
-       IPW_DEBUG_WX("Setting ESSID: '%s' (%d)\n",
-                    print_ssid(ssid, essid, length), length);
+       IPW_DEBUG_WX("Setting ESSID: '%*pE' (%d)\n", length, essid, length);
 
        priv->essid_len = length;
        memcpy(priv->essid, essid, priv->essid_len);
@@ -7027,13 +7020,12 @@ static int ipw2100_wx_get_essid(struct net_device *dev,
         */
 
        struct ipw2100_priv *priv = libipw_priv(dev);
-       DECLARE_SSID_BUF(ssid);
 
        /* If we are associated, trying to associate, or have a statically
         * configured ESSID then return that; otherwise return ANY */
        if (priv->config & CFG_STATIC_ESSID || priv->status & STATUS_ASSOCIATED) {
-               IPW_DEBUG_WX("Getting essid: '%s'\n",
-                            print_ssid(ssid, priv->essid, priv->essid_len));
+               IPW_DEBUG_WX("Getting essid: '%*pE'\n",
+                            priv->essid_len, priv->essid);
                memcpy(extra, priv->essid, priv->essid_len);
                wrqu->essid.length = priv->essid_len;
                wrqu->essid.flags = 1;  /* active */
index f0c3c77a48d38eb7e2318280ab9492582091c39f..edc344334a7547006901de8e3b5dcd79db66c0a9 100644 (file)
@@ -4496,7 +4496,6 @@ static void handle_scan_event(struct ipw_priv *priv)
 static void ipw_rx_notification(struct ipw_priv *priv,
                                       struct ipw_rx_notification *notif)
 {
-       DECLARE_SSID_BUF(ssid);
        u16 size = le16_to_cpu(notif->size);
 
        IPW_DEBUG_NOTIF("type = %i (%d bytes)\n", notif->subtype, size);
@@ -4509,9 +4508,8 @@ static void ipw_rx_notification(struct ipw_priv *priv,
                        case CMAS_ASSOCIATED:{
                                        IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE |
                                                  IPW_DL_ASSOC,
-                                                 "associated: '%s' %pM\n",
-                                                 print_ssid(ssid, priv->essid,
-                                                            priv->essid_len),
+                                                 "associated: '%*pE' %pM\n",
+                                                 priv->essid_len, priv->essid,
                                                  priv->bssid);
 
                                        switch (priv->ieee->iw_mode) {
@@ -4585,14 +4583,9 @@ static void ipw_rx_notification(struct ipw_priv *priv,
                                                IPW_DEBUG(IPW_DL_NOTIF |
                                                          IPW_DL_STATE |
                                                          IPW_DL_ASSOC,
-                                                         "deauthenticated: '%s' "
-                                                         "%pM"
-                                                         ": (0x%04X) - %s\n",
-                                                         print_ssid(ssid,
-                                                                    priv->
-                                                                    essid,
-                                                                    priv->
-                                                                    essid_len),
+                                                         "deauthenticated: '%*pE' %pM: (0x%04X) - %s\n",
+                                                         priv->essid_len,
+                                                         priv->essid,
                                                          priv->bssid,
                                                          le16_to_cpu(auth->status),
                                                          ipw_get_status_code
@@ -4610,9 +4603,8 @@ static void ipw_rx_notification(struct ipw_priv *priv,
 
                                        IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE |
                                                  IPW_DL_ASSOC,
-                                                 "authenticated: '%s' %pM\n",
-                                                 print_ssid(ssid, priv->essid,
-                                                            priv->essid_len),
+                                                 "authenticated: '%*pE' %pM\n",
+                                                 priv->essid_len, priv->essid,
                                                  priv->bssid);
                                        break;
                                }
@@ -4638,9 +4630,8 @@ static void ipw_rx_notification(struct ipw_priv *priv,
 
                                        IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE |
                                                  IPW_DL_ASSOC,
-                                                 "disassociated: '%s' %pM\n",
-                                                 print_ssid(ssid, priv->essid,
-                                                            priv->essid_len),
+                                                 "disassociated: '%*pE' %pM\n",
+                                                 priv->essid_len, priv->essid,
                                                  priv->bssid);
 
                                        priv->status &=
@@ -4676,9 +4667,8 @@ static void ipw_rx_notification(struct ipw_priv *priv,
                        switch (auth->state) {
                        case CMAS_AUTHENTICATED:
                                IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE,
-                                         "authenticated: '%s' %pM\n",
-                                         print_ssid(ssid, priv->essid,
-                                                    priv->essid_len),
+                                         "authenticated: '%*pE' %pM\n",
+                                         priv->essid_len, priv->essid,
                                          priv->bssid);
                                priv->status |= STATUS_AUTH;
                                break;
@@ -4695,9 +4685,8 @@ static void ipw_rx_notification(struct ipw_priv *priv,
                                }
                                IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE |
                                          IPW_DL_ASSOC,
-                                         "deauthenticated: '%s' %pM\n",
-                                         print_ssid(ssid, priv->essid,
-                                                    priv->essid_len),
+                                         "deauthenticated: '%*pE' %pM\n",
+                                         priv->essid_len, priv->essid,
                                          priv->bssid);
 
                                priv->status &= ~(STATUS_ASSOCIATING |
@@ -5516,16 +5505,13 @@ static int ipw_find_adhoc_network(struct ipw_priv *priv,
                                  int roaming)
 {
        struct ipw_supported_rates rates;
-       DECLARE_SSID_BUF(ssid);
 
        /* Verify that this network's capability is compatible with the
         * current mode (AdHoc or Infrastructure) */
        if ((priv->ieee->iw_mode == IW_MODE_ADHOC &&
             !(network->capability & WLAN_CAPABILITY_IBSS))) {
-               IPW_DEBUG_MERGE("Network '%s (%pM)' excluded due to "
-                               "capability mismatch.\n",
-                               print_ssid(ssid, network->ssid,
-                                          network->ssid_len),
+               IPW_DEBUG_MERGE("Network '%*pE (%pM)' excluded due to capability mismatch.\n",
+                               network->ssid_len, network->ssid,
                                network->bssid);
                return 0;
        }
@@ -5536,10 +5522,8 @@ static int ipw_find_adhoc_network(struct ipw_priv *priv,
                if ((network->ssid_len != match->network->ssid_len) ||
                    memcmp(network->ssid, match->network->ssid,
                           network->ssid_len)) {
-                       IPW_DEBUG_MERGE("Network '%s (%pM)' excluded "
-                                       "because of non-network ESSID.\n",
-                                       print_ssid(ssid, network->ssid,
-                                                  network->ssid_len),
+                       IPW_DEBUG_MERGE("Network '%*pE (%pM)' excluded because of non-network ESSID.\n",
+                                       network->ssid_len, network->ssid,
                                        network->bssid);
                        return 0;
                }
@@ -5550,17 +5534,10 @@ static int ipw_find_adhoc_network(struct ipw_priv *priv,
                    ((network->ssid_len != priv->essid_len) ||
                     memcmp(network->ssid, priv->essid,
                            min(network->ssid_len, priv->essid_len)))) {
-                       char escaped[IW_ESSID_MAX_SIZE * 2 + 1];
-
-                       strlcpy(escaped,
-                               print_ssid(ssid, network->ssid,
-                                          network->ssid_len),
-                               sizeof(escaped));
-                       IPW_DEBUG_MERGE("Network '%s (%pM)' excluded "
-                                       "because of ESSID mismatch: '%s'.\n",
-                                       escaped, network->bssid,
-                                       print_ssid(ssid, priv->essid,
-                                                  priv->essid_len));
+                       IPW_DEBUG_MERGE("Network '%*pE (%pM)' excluded because of ESSID mismatch: '%*pE'.\n",
+                                       network->ssid_len, network->ssid,
+                                       network->bssid, priv->essid_len,
+                                       priv->essid);
                        return 0;
                }
        }
@@ -5569,26 +5546,20 @@ static int ipw_find_adhoc_network(struct ipw_priv *priv,
         * testing everything else. */
 
        if (network->time_stamp[0] < match->network->time_stamp[0]) {
-               IPW_DEBUG_MERGE("Network '%s excluded because newer than "
-                               "current network.\n",
-                               print_ssid(ssid, match->network->ssid,
-                                          match->network->ssid_len));
+               IPW_DEBUG_MERGE("Network '%*pE excluded because newer than current network.\n",
+                               match->network->ssid_len, match->network->ssid);
                return 0;
        } else if (network->time_stamp[1] < match->network->time_stamp[1]) {
-               IPW_DEBUG_MERGE("Network '%s excluded because newer than "
-                               "current network.\n",
-                               print_ssid(ssid, match->network->ssid,
-                                          match->network->ssid_len));
+               IPW_DEBUG_MERGE("Network '%*pE excluded because newer than current network.\n",
+                               match->network->ssid_len, match->network->ssid);
                return 0;
        }
 
        /* Now go through and see if the requested network is valid... */
        if (priv->ieee->scan_age != 0 &&
            time_after(jiffies, network->last_scanned + priv->ieee->scan_age)) {
-               IPW_DEBUG_MERGE("Network '%s (%pM)' excluded "
-                               "because of age: %ums.\n",
-                               print_ssid(ssid, network->ssid,
-                                          network->ssid_len),
+               IPW_DEBUG_MERGE("Network '%*pE (%pM)' excluded because of age: %ums.\n",
+                               network->ssid_len, network->ssid,
                                network->bssid,
                                jiffies_to_msecs(jiffies -
                                                 network->last_scanned));
@@ -5597,10 +5568,8 @@ static int ipw_find_adhoc_network(struct ipw_priv *priv,
 
        if ((priv->config & CFG_STATIC_CHANNEL) &&
            (network->channel != priv->channel)) {
-               IPW_DEBUG_MERGE("Network '%s (%pM)' excluded "
-                               "because of channel mismatch: %d != %d.\n",
-                               print_ssid(ssid, network->ssid,
-                                          network->ssid_len),
+               IPW_DEBUG_MERGE("Network '%*pE (%pM)' excluded because of channel mismatch: %d != %d.\n",
+                               network->ssid_len, network->ssid,
                                network->bssid,
                                network->channel, priv->channel);
                return 0;
@@ -5609,10 +5578,8 @@ static int ipw_find_adhoc_network(struct ipw_priv *priv,
        /* Verify privacy compatibility */
        if (((priv->capability & CAP_PRIVACY_ON) ? 1 : 0) !=
            ((network->capability & WLAN_CAPABILITY_PRIVACY) ? 1 : 0)) {
-               IPW_DEBUG_MERGE("Network '%s (%pM)' excluded "
-                               "because of privacy mismatch: %s != %s.\n",
-                               print_ssid(ssid, network->ssid,
-                                          network->ssid_len),
+               IPW_DEBUG_MERGE("Network '%*pE (%pM)' excluded because of privacy mismatch: %s != %s.\n",
+                               network->ssid_len, network->ssid,
                                network->bssid,
                                priv->
                                capability & CAP_PRIVACY_ON ? "on" : "off",
@@ -5623,22 +5590,16 @@ static int ipw_find_adhoc_network(struct ipw_priv *priv,
        }
 
        if (ether_addr_equal(network->bssid, priv->bssid)) {
-               IPW_DEBUG_MERGE("Network '%s (%pM)' excluded "
-                               "because of the same BSSID match: %pM"
-                               ".\n", print_ssid(ssid, network->ssid,
-                                                 network->ssid_len),
-                               network->bssid,
-                               priv->bssid);
+               IPW_DEBUG_MERGE("Network '%*pE (%pM)' excluded because of the same BSSID match: %pM.\n",
+                               network->ssid_len, network->ssid,
+                               network->bssid, priv->bssid);
                return 0;
        }
 
        /* Filter out any incompatible freq / mode combinations */
        if (!libipw_is_valid_mode(priv->ieee, network->mode)) {
-               IPW_DEBUG_MERGE("Network '%s (%pM)' excluded "
-                               "because of invalid frequency/mode "
-                               "combination.\n",
-                               print_ssid(ssid, network->ssid,
-                                          network->ssid_len),
+               IPW_DEBUG_MERGE("Network '%*pE (%pM)' excluded because of invalid frequency/mode combination.\n",
+                               network->ssid_len, network->ssid,
                                network->bssid);
                return 0;
        }
@@ -5646,20 +5607,15 @@ static int ipw_find_adhoc_network(struct ipw_priv *priv,
        /* Ensure that the rates supported by the driver are compatible with
         * this AP, including verification of basic rates (mandatory) */
        if (!ipw_compatible_rates(priv, network, &rates)) {
-               IPW_DEBUG_MERGE("Network '%s (%pM)' excluded "
-                               "because configured rate mask excludes "
-                               "AP mandatory rate.\n",
-                               print_ssid(ssid, network->ssid,
-                                          network->ssid_len),
+               IPW_DEBUG_MERGE("Network '%*pE (%pM)' excluded because configured rate mask excludes AP mandatory rate.\n",
+                               network->ssid_len, network->ssid,
                                network->bssid);
                return 0;
        }
 
        if (rates.num_rates == 0) {
-               IPW_DEBUG_MERGE("Network '%s (%pM)' excluded "
-                               "because of no compatible rates.\n",
-                               print_ssid(ssid, network->ssid,
-                                          network->ssid_len),
+               IPW_DEBUG_MERGE("Network '%*pE (%pM)' excluded because of no compatible rates.\n",
+                               network->ssid_len, network->ssid,
                                network->bssid);
                return 0;
        }
@@ -5671,16 +5627,14 @@ static int ipw_find_adhoc_network(struct ipw_priv *priv,
        /* Set up 'new' AP to this network */
        ipw_copy_rates(&match->rates, &rates);
        match->network = network;
-       IPW_DEBUG_MERGE("Network '%s (%pM)' is a viable match.\n",
-                       print_ssid(ssid, network->ssid, network->ssid_len),
-                       network->bssid);
+       IPW_DEBUG_MERGE("Network '%*pE (%pM)' is a viable match.\n",
+                       network->ssid_len, network->ssid, network->bssid);
 
        return 1;
 }
 
 static void ipw_merge_adhoc_network(struct work_struct *work)
 {
-       DECLARE_SSID_BUF(ssid);
        struct ipw_priv *priv =
                container_of(work, struct ipw_priv, merge_networks);
        struct libipw_network *network = NULL;
@@ -5710,9 +5664,8 @@ static void ipw_merge_adhoc_network(struct work_struct *work)
 
                mutex_lock(&priv->mutex);
                if ((priv->ieee->iw_mode == IW_MODE_ADHOC)) {
-                       IPW_DEBUG_MERGE("remove network %s\n",
-                                       print_ssid(ssid, priv->essid,
-                                                  priv->essid_len));
+                       IPW_DEBUG_MERGE("remove network %*pE\n",
+                                       priv->essid_len, priv->essid);
                        ipw_remove_current_network(priv);
                }
 
@@ -5728,7 +5681,6 @@ static int ipw_best_network(struct ipw_priv *priv,
                            struct libipw_network *network, int roaming)
 {
        struct ipw_supported_rates rates;
-       DECLARE_SSID_BUF(ssid);
 
        /* Verify that this network's capability is compatible with the
         * current mode (AdHoc or Infrastructure) */
@@ -5736,10 +5688,8 @@ static int ipw_best_network(struct ipw_priv *priv,
             !(network->capability & WLAN_CAPABILITY_ESS)) ||
            (priv->ieee->iw_mode == IW_MODE_ADHOC &&
             !(network->capability & WLAN_CAPABILITY_IBSS))) {
-               IPW_DEBUG_ASSOC("Network '%s (%pM)' excluded due to "
-                               "capability mismatch.\n",
-                               print_ssid(ssid, network->ssid,
-                                          network->ssid_len),
+               IPW_DEBUG_ASSOC("Network '%*pE (%pM)' excluded due to capability mismatch.\n",
+                               network->ssid_len, network->ssid,
                                network->bssid);
                return 0;
        }
@@ -5750,10 +5700,8 @@ static int ipw_best_network(struct ipw_priv *priv,
                if ((network->ssid_len != match->network->ssid_len) ||
                    memcmp(network->ssid, match->network->ssid,
                           network->ssid_len)) {
-                       IPW_DEBUG_ASSOC("Network '%s (%pM)' excluded "
-                                       "because of non-network ESSID.\n",
-                                       print_ssid(ssid, network->ssid,
-                                                  network->ssid_len),
+                       IPW_DEBUG_ASSOC("Network '%*pE (%pM)' excluded because of non-network ESSID.\n",
+                                       network->ssid_len, network->ssid,
                                        network->bssid);
                        return 0;
                }
@@ -5764,16 +5712,10 @@ static int ipw_best_network(struct ipw_priv *priv,
                    ((network->ssid_len != priv->essid_len) ||
                     memcmp(network->ssid, priv->essid,
                            min(network->ssid_len, priv->essid_len)))) {
-                       char escaped[IW_ESSID_MAX_SIZE * 2 + 1];
-                       strlcpy(escaped,
-                               print_ssid(ssid, network->ssid,
-                                          network->ssid_len),
-                               sizeof(escaped));
-                       IPW_DEBUG_ASSOC("Network '%s (%pM)' excluded "
-                                       "because of ESSID mismatch: '%s'.\n",
-                                       escaped, network->bssid,
-                                       print_ssid(ssid, priv->essid,
-                                                  priv->essid_len));
+                       IPW_DEBUG_ASSOC("Network '%*pE (%pM)' excluded because of ESSID mismatch: '%*pE'.\n",
+                                       network->ssid_len, network->ssid,
+                                       network->bssid, priv->essid_len,
+                                       priv->essid);
                        return 0;
                }
        }
@@ -5781,16 +5723,10 @@ static int ipw_best_network(struct ipw_priv *priv,
        /* If the old network rate is better than this one, don't bother
         * testing everything else. */
        if (match->network && match->network->stats.rssi > network->stats.rssi) {
-               char escaped[IW_ESSID_MAX_SIZE * 2 + 1];
-               strlcpy(escaped,
-                       print_ssid(ssid, network->ssid, network->ssid_len),
-                       sizeof(escaped));
-               IPW_DEBUG_ASSOC("Network '%s (%pM)' excluded because "
-                               "'%s (%pM)' has a stronger signal.\n",
-                               escaped, network->bssid,
-                               print_ssid(ssid, match->network->ssid,
-                                          match->network->ssid_len),
-                               match->network->bssid);
+               IPW_DEBUG_ASSOC("Network '%*pE (%pM)' excluded because '%*pE (%pM)' has a stronger signal.\n",
+                               network->ssid_len, network->ssid,
+                               network->bssid, match->network->ssid_len,
+                               match->network->ssid, match->network->bssid);
                return 0;
        }
 
@@ -5798,11 +5734,8 @@ static int ipw_best_network(struct ipw_priv *priv,
         * last 3 seconds, do not try and associate again... */
        if (network->last_associate &&
            time_after(network->last_associate + (HZ * 3UL), jiffies)) {
-               IPW_DEBUG_ASSOC("Network '%s (%pM)' excluded "
-                               "because of storming (%ums since last "
-                               "assoc attempt).\n",
-                               print_ssid(ssid, network->ssid,
-                                          network->ssid_len),
+               IPW_DEBUG_ASSOC("Network '%*pE (%pM)' excluded because of storming (%ums since last assoc attempt).\n",
+                               network->ssid_len, network->ssid,
                                network->bssid,
                                jiffies_to_msecs(jiffies -
                                                 network->last_associate));
@@ -5812,10 +5745,8 @@ static int ipw_best_network(struct ipw_priv *priv,
        /* Now go through and see if the requested network is valid... */
        if (priv->ieee->scan_age != 0 &&
            time_after(jiffies, network->last_scanned + priv->ieee->scan_age)) {
-               IPW_DEBUG_ASSOC("Network '%s (%pM)' excluded "
-                               "because of age: %ums.\n",
-                               print_ssid(ssid, network->ssid,
-                                          network->ssid_len),
+               IPW_DEBUG_ASSOC("Network '%*pE (%pM)' excluded because of age: %ums.\n",
+                               network->ssid_len, network->ssid,
                                network->bssid,
                                jiffies_to_msecs(jiffies -
                                                 network->last_scanned));
@@ -5824,10 +5755,8 @@ static int ipw_best_network(struct ipw_priv *priv,
 
        if ((priv->config & CFG_STATIC_CHANNEL) &&
            (network->channel != priv->channel)) {
-               IPW_DEBUG_ASSOC("Network '%s (%pM)' excluded "
-                               "because of channel mismatch: %d != %d.\n",
-                               print_ssid(ssid, network->ssid,
-                                          network->ssid_len),
+               IPW_DEBUG_ASSOC("Network '%*pE (%pM)' excluded because of channel mismatch: %d != %d.\n",
+                               network->ssid_len, network->ssid,
                                network->bssid,
                                network->channel, priv->channel);
                return 0;
@@ -5836,10 +5765,8 @@ static int ipw_best_network(struct ipw_priv *priv,
        /* Verify privacy compatibility */
        if (((priv->capability & CAP_PRIVACY_ON) ? 1 : 0) !=
            ((network->capability & WLAN_CAPABILITY_PRIVACY) ? 1 : 0)) {
-               IPW_DEBUG_ASSOC("Network '%s (%pM)' excluded "
-                               "because of privacy mismatch: %s != %s.\n",
-                               print_ssid(ssid, network->ssid,
-                                          network->ssid_len),
+               IPW_DEBUG_ASSOC("Network '%*pE (%pM)' excluded because of privacy mismatch: %s != %s.\n",
+                               network->ssid_len, network->ssid,
                                network->bssid,
                                priv->capability & CAP_PRIVACY_ON ? "on" :
                                "off",
@@ -5850,31 +5777,24 @@ static int ipw_best_network(struct ipw_priv *priv,
 
        if ((priv->config & CFG_STATIC_BSSID) &&
            !ether_addr_equal(network->bssid, priv->bssid)) {
-               IPW_DEBUG_ASSOC("Network '%s (%pM)' excluded "
-                               "because of BSSID mismatch: %pM.\n",
-                               print_ssid(ssid, network->ssid,
-                                          network->ssid_len),
+               IPW_DEBUG_ASSOC("Network '%*pE (%pM)' excluded because of BSSID mismatch: %pM.\n",
+                               network->ssid_len, network->ssid,
                                network->bssid, priv->bssid);
                return 0;
        }
 
        /* Filter out any incompatible freq / mode combinations */
        if (!libipw_is_valid_mode(priv->ieee, network->mode)) {
-               IPW_DEBUG_ASSOC("Network '%s (%pM)' excluded "
-                               "because of invalid frequency/mode "
-                               "combination.\n",
-                               print_ssid(ssid, network->ssid,
-                                          network->ssid_len),
+               IPW_DEBUG_ASSOC("Network '%*pE (%pM)' excluded because of invalid frequency/mode combination.\n",
+                               network->ssid_len, network->ssid,
                                network->bssid);
                return 0;
        }
 
        /* Filter out invalid channel in current GEO */
        if (!libipw_is_valid_channel(priv->ieee, network->channel)) {
-               IPW_DEBUG_ASSOC("Network '%s (%pM)' excluded "
-                               "because of invalid channel in current GEO\n",
-                               print_ssid(ssid, network->ssid,
-                                          network->ssid_len),
+               IPW_DEBUG_ASSOC("Network '%*pE (%pM)' excluded because of invalid channel in current GEO\n",
+                               network->ssid_len, network->ssid,
                                network->bssid);
                return 0;
        }
@@ -5882,20 +5802,15 @@ static int ipw_best_network(struct ipw_priv *priv,
        /* Ensure that the rates supported by the driver are compatible with
         * this AP, including verification of basic rates (mandatory) */
        if (!ipw_compatible_rates(priv, network, &rates)) {
-               IPW_DEBUG_ASSOC("Network '%s (%pM)' excluded "
-                               "because configured rate mask excludes "
-                               "AP mandatory rate.\n",
-                               print_ssid(ssid, network->ssid,
-                                          network->ssid_len),
+               IPW_DEBUG_ASSOC("Network '%*pE (%pM)' excluded because configured rate mask excludes AP mandatory rate.\n",
+                               network->ssid_len, network->ssid,
                                network->bssid);
                return 0;
        }
 
        if (rates.num_rates == 0) {
-               IPW_DEBUG_ASSOC("Network '%s (%pM)' excluded "
-                               "because of no compatible rates.\n",
-                               print_ssid(ssid, network->ssid,
-                                          network->ssid_len),
+               IPW_DEBUG_ASSOC("Network '%*pE (%pM)' excluded because of no compatible rates.\n",
+                               network->ssid_len, network->ssid,
                                network->bssid);
                return 0;
        }
@@ -5908,9 +5823,8 @@ static int ipw_best_network(struct ipw_priv *priv,
        ipw_copy_rates(&match->rates, &rates);
        match->network = network;
 
-       IPW_DEBUG_ASSOC("Network '%s (%pM)' is a viable match.\n",
-                       print_ssid(ssid, network->ssid, network->ssid_len),
-                       network->bssid);
+       IPW_DEBUG_ASSOC("Network '%*pE (%pM)' is a viable match.\n",
+                       network->ssid_len, network->ssid, network->bssid);
 
        return 1;
 }
@@ -6152,7 +6066,6 @@ static void ipw_bg_adhoc_check(struct work_struct *work)
 
 static void ipw_debug_config(struct ipw_priv *priv)
 {
-       DECLARE_SSID_BUF(ssid);
        IPW_DEBUG_INFO("Scan completed, no valid APs matched "
                       "[CFG 0x%08X]\n", priv->config);
        if (priv->config & CFG_STATIC_CHANNEL)
@@ -6160,8 +6073,8 @@ static void ipw_debug_config(struct ipw_priv *priv)
        else
                IPW_DEBUG_INFO("Channel unlocked.\n");
        if (priv->config & CFG_STATIC_ESSID)
-               IPW_DEBUG_INFO("ESSID locked to '%s'\n",
-                              print_ssid(ssid, priv->essid, priv->essid_len));
+               IPW_DEBUG_INFO("ESSID locked to '%*pE'\n",
+                              priv->essid_len, priv->essid);
        else
                IPW_DEBUG_INFO("ESSID unlocked.\n");
        if (priv->config & CFG_STATIC_BSSID)
@@ -7385,7 +7298,6 @@ static int ipw_associate_network(struct ipw_priv *priv,
                                 struct ipw_supported_rates *rates, int roaming)
 {
        int err;
-       DECLARE_SSID_BUF(ssid);
 
        if (priv->config & CFG_FIXED_RATE)
                ipw_set_fixed_rate(priv, network->mode);
@@ -7451,10 +7363,9 @@ static int ipw_associate_network(struct ipw_priv *priv,
                priv->assoc_request.capability &=
                    ~cpu_to_le16(WLAN_CAPABILITY_SHORT_SLOT_TIME);
 
-       IPW_DEBUG_ASSOC("%ssociation attempt: '%s', channel %d, "
-                       "802.11%c [%d], %s[:%s], enc=%s%s%s%c%c\n",
+       IPW_DEBUG_ASSOC("%ssociation attempt: '%*pE', channel %d, 802.11%c [%d], %s[:%s], enc=%s%s%s%c%c\n",
                        roaming ? "Rea" : "A",
-                       print_ssid(ssid, priv->essid, priv->essid_len),
+                       priv->essid_len, priv->essid,
                        network->channel,
                        ipw_modes[priv->assoc_request.ieee_mode],
                        rates->num_rates,
@@ -7553,9 +7464,8 @@ static int ipw_associate_network(struct ipw_priv *priv,
                return err;
        }
 
-       IPW_DEBUG(IPW_DL_STATE, "associating: '%s' %pM\n",
-                 print_ssid(ssid, priv->essid, priv->essid_len),
-                 priv->bssid);
+       IPW_DEBUG(IPW_DL_STATE, "associating: '%*pE' %pM\n",
+                 priv->essid_len, priv->essid, priv->bssid);
 
        return 0;
 }
@@ -7645,7 +7555,6 @@ static int ipw_associate(void *data)
        struct ipw_supported_rates *rates;
        struct list_head *element;
        unsigned long flags;
-       DECLARE_SSID_BUF(ssid);
 
        if (priv->ieee->iw_mode == IW_MODE_MONITOR) {
                IPW_DEBUG_ASSOC("Not attempting association (monitor mode)\n");
@@ -7704,10 +7613,8 @@ static int ipw_associate(void *data)
                        /* If there are no more slots, expire the oldest */
                        list_del(&oldest->list);
                        target = oldest;
-                       IPW_DEBUG_ASSOC("Expired '%s' (%pM) from "
-                                       "network list.\n",
-                                       print_ssid(ssid, target->ssid,
-                                                  target->ssid_len),
+                       IPW_DEBUG_ASSOC("Expired '%*pE' (%pM) from network list.\n",
+                                       target->ssid_len, target->ssid,
                                        target->bssid);
                        list_add_tail(&target->list,
                                      &priv->ieee->network_free_list);
@@ -9093,7 +9000,6 @@ static int ipw_wx_set_essid(struct net_device *dev,
 {
        struct ipw_priv *priv = libipw_priv(dev);
         int length;
-       DECLARE_SSID_BUF(ssid);
 
         mutex_lock(&priv->mutex);
 
@@ -9118,8 +9024,7 @@ static int ipw_wx_set_essid(struct net_device *dev,
                return 0;
        }
 
-       IPW_DEBUG_WX("Setting ESSID: '%s' (%d)\n",
-                    print_ssid(ssid, extra, length), length);
+       IPW_DEBUG_WX("Setting ESSID: '%*pE' (%d)\n", length, extra, length);
 
        priv->essid_len = length;
        memcpy(priv->essid, extra, priv->essid_len);
@@ -9138,15 +9043,14 @@ static int ipw_wx_get_essid(struct net_device *dev,
                            union iwreq_data *wrqu, char *extra)
 {
        struct ipw_priv *priv = libipw_priv(dev);
-       DECLARE_SSID_BUF(ssid);
 
        /* If we are associated, trying to associate, or have a statically
         * configured ESSID then return that; otherwise return ANY */
        mutex_lock(&priv->mutex);
        if (priv->config & CFG_STATIC_ESSID ||
            priv->status & (STATUS_ASSOCIATED | STATUS_ASSOCIATING)) {
-               IPW_DEBUG_WX("Getting essid: '%s'\n",
-                            print_ssid(ssid, priv->essid, priv->essid_len));
+               IPW_DEBUG_WX("Getting essid: '%*pE'\n",
+                            priv->essid_len, priv->essid);
                memcpy(extra, priv->essid, priv->essid_len);
                wrqu->essid.length = priv->essid_len;
                wrqu->essid.flags = 1;  /* active */
index a586a85bfcfe88ccd6378ad476caca6b9aa10a15..2d66984079bb1f1bc928c1aed037851285a22ea6 100644 (file)
@@ -1120,7 +1120,6 @@ static int libipw_parse_info_param(struct libipw_info_element
                                      *info_element, u16 length,
                                      struct libipw_network *network)
 {
-       DECLARE_SSID_BUF(ssid);
        u8 i;
 #ifdef CONFIG_LIBIPW_DEBUG
        char rates_str[64];
@@ -1151,10 +1150,9 @@ static int libipw_parse_info_param(struct libipw_info_element
                                memset(network->ssid + network->ssid_len, 0,
                                       IW_ESSID_MAX_SIZE - network->ssid_len);
 
-                       LIBIPW_DEBUG_MGMT("WLAN_EID_SSID: '%s' len=%d.\n",
-                                            print_ssid(ssid, network->ssid,
-                                                       network->ssid_len),
-                                            network->ssid_len);
+                       LIBIPW_DEBUG_MGMT("WLAN_EID_SSID: '%*pE' len=%d.\n",
+                                         network->ssid_len, network->ssid,
+                                         network->ssid_len);
                        break;
 
                case WLAN_EID_SUPP_RATES:
@@ -1399,8 +1397,6 @@ static int libipw_network_init(struct libipw_device *ieee, struct libipw_probe_r
                                         struct libipw_network *network,
                                         struct libipw_rx_stats *stats)
 {
-       DECLARE_SSID_BUF(ssid);
-
        network->qos_data.active = 0;
        network->qos_data.supported = 0;
        network->qos_data.param_count = 0;
@@ -1447,11 +1443,9 @@ static int libipw_network_init(struct libipw_device *ieee, struct libipw_probe_r
        }
 
        if (network->mode == 0) {
-               LIBIPW_DEBUG_SCAN("Filtered out '%s (%pM)' "
-                                    "network.\n",
-                                    print_ssid(ssid, network->ssid,
-                                                network->ssid_len),
-                                    network->bssid);
+               LIBIPW_DEBUG_SCAN("Filtered out '%*pE (%pM)' network.\n",
+                                 network->ssid_len, network->ssid,
+                                 network->bssid);
                return 1;
        }
 
@@ -1563,11 +1557,9 @@ static void libipw_process_probe_response(struct libipw_device
        struct libipw_info_element *info_element = beacon->info_element;
 #endif
        unsigned long flags;
-       DECLARE_SSID_BUF(ssid);
 
-       LIBIPW_DEBUG_SCAN("'%s' (%pM"
-                    "): %c%c%c%c %c%c%c%c-%c%c%c%c %c%c%c%c\n",
-                    print_ssid(ssid, info_element->data, info_element->len),
+       LIBIPW_DEBUG_SCAN("'%*pE' (%pM): %c%c%c%c %c%c%c%c-%c%c%c%c %c%c%c%c\n",
+                    info_element->len, info_element->data,
                     beacon->header.addr3,
                     (beacon->capability & cpu_to_le16(1 << 0xf)) ? '1' : '0',
                     (beacon->capability & cpu_to_le16(1 << 0xe)) ? '1' : '0',
@@ -1587,12 +1579,11 @@ static void libipw_process_probe_response(struct libipw_device
                     (beacon->capability & cpu_to_le16(1 << 0x0)) ? '1' : '0');
 
        if (libipw_network_init(ieee, beacon, &network, stats)) {
-               LIBIPW_DEBUG_SCAN("Dropped '%s' (%pM) via %s.\n",
-                                    print_ssid(ssid, info_element->data,
-                                                info_element->len),
-                                    beacon->header.addr3,
-                                    is_beacon(beacon->header.frame_ctl) ?
-                                    "BEACON" : "PROBE RESPONSE");
+               LIBIPW_DEBUG_SCAN("Dropped '%*pE' (%pM) via %s.\n",
+                                 info_element->len, info_element->data,
+                                 beacon->header.addr3,
+                                 is_beacon(beacon->header.frame_ctl) ?
+                                 "BEACON" : "PROBE RESPONSE");
                return;
        }
 
@@ -1624,11 +1615,9 @@ static void libipw_process_probe_response(struct libipw_device
                        /* If there are no more slots, expire the oldest */
                        list_del(&oldest->list);
                        target = oldest;
-                       LIBIPW_DEBUG_SCAN("Expired '%s' (%pM) from "
-                                            "network list.\n",
-                                            print_ssid(ssid, target->ssid,
-                                                        target->ssid_len),
-                                            target->bssid);
+                       LIBIPW_DEBUG_SCAN("Expired '%*pE' (%pM) from network list.\n",
+                                         target->ssid_len, target->ssid,
+                                         target->bssid);
                        libipw_network_reset(target);
                } else {
                        /* Otherwise just pull from the free list */
@@ -1638,23 +1627,21 @@ static void libipw_process_probe_response(struct libipw_device
                }
 
 #ifdef CONFIG_LIBIPW_DEBUG
-               LIBIPW_DEBUG_SCAN("Adding '%s' (%pM) via %s.\n",
-                                    print_ssid(ssid, network.ssid,
-                                                network.ssid_len),
-                                    network.bssid,
-                                    is_beacon(beacon->header.frame_ctl) ?
-                                    "BEACON" : "PROBE RESPONSE");
+               LIBIPW_DEBUG_SCAN("Adding '%*pE' (%pM) via %s.\n",
+                                 network.ssid_len, network.ssid,
+                                 network.bssid,
+                                 is_beacon(beacon->header.frame_ctl) ?
+                                 "BEACON" : "PROBE RESPONSE");
 #endif
                memcpy(target, &network, sizeof(*target));
                network.ibss_dfs = NULL;
                list_add_tail(&target->list, &ieee->network_list);
        } else {
-               LIBIPW_DEBUG_SCAN("Updating '%s' (%pM) via %s.\n",
-                                    print_ssid(ssid, target->ssid,
-                                                target->ssid_len),
-                                    target->bssid,
-                                    is_beacon(beacon->header.frame_ctl) ?
-                                    "BEACON" : "PROBE RESPONSE");
+               LIBIPW_DEBUG_SCAN("Updating '%*pE' (%pM) via %s.\n",
+                                 target->ssid_len, target->ssid,
+                                 target->bssid,
+                                 is_beacon(beacon->header.frame_ctl) ?
+                                 "BEACON" : "PROBE RESPONSE");
                update_network(target, &network);
                network.ibss_dfs = NULL;
        }
index 54aba474443867f463714e117f14a605ba251803..dd29f46d086b2bf2f60586655fb59ff9647c0b0c 100644 (file)
@@ -272,7 +272,6 @@ int libipw_wx_get_scan(struct libipw_device *ieee,
        char *ev = extra;
        char *stop = ev + wrqu->data.length;
        int i = 0;
-       DECLARE_SSID_BUF(ssid);
 
        LIBIPW_DEBUG_WX("Getting scan\n");
 
@@ -290,12 +289,10 @@ int libipw_wx_get_scan(struct libipw_device *ieee,
                        ev = libipw_translate_scan(ieee, ev, stop, network,
                                                      info);
                else {
-                       LIBIPW_DEBUG_SCAN("Not showing network '%s ("
-                                            "%pM)' due to age (%ums).\n",
-                                            print_ssid(ssid, network->ssid,
-                                                        network->ssid_len),
-                                            network->bssid,
-                                            elapsed_jiffies_msecs(
+                       LIBIPW_DEBUG_SCAN("Not showing network '%*pE (%pM)' due to age (%ums).\n",
+                                         network->ssid_len, network->ssid,
+                                         network->bssid,
+                                         elapsed_jiffies_msecs(
                                                       network->last_scanned));
                }
        }
@@ -322,7 +319,6 @@ int libipw_wx_set_encode(struct libipw_device *ieee,
        int i, key, key_provided, len;
        struct lib80211_crypt_data **crypt;
        int host_crypto = ieee->host_encrypt || ieee->host_decrypt;
-       DECLARE_SSID_BUF(ssid);
 
        LIBIPW_DEBUG_WX("SET_ENCODE\n");
 
@@ -417,8 +413,8 @@ int libipw_wx_set_encode(struct libipw_device *ieee,
                if (len > erq->length)
                        memset(sec.keys[key] + erq->length, 0,
                               len - erq->length);
-               LIBIPW_DEBUG_WX("Setting key %d to '%s' (%d:%d bytes)\n",
-                                  key, print_ssid(ssid, sec.keys[key], len),
+               LIBIPW_DEBUG_WX("Setting key %d to '%*pE' (%d:%d bytes)\n",
+                                  key, len, sec.keys[key],
                                   erq->length, len);
                sec.key_sizes[key] = len;
                if (*crypt)
index 818b1edaaa9aa5d38f3176828ca2ed3802fb3fde..34f09ef90bb31bbc02f0fda014c27ed3dfa52e72 100644 (file)
@@ -590,7 +590,6 @@ static int lbs_ret_scan(struct lbs_private *priv, unsigned long dummy,
                int chan_no = -1;
                const u8 *ssid = NULL;
                u8 ssid_len = 0;
-               DECLARE_SSID_BUF(ssid_buf);
 
                int len = get_unaligned_le16(pos);
                pos += 2;
@@ -644,10 +643,8 @@ static int lbs_ret_scan(struct lbs_private *priv, unsigned long dummy,
                        struct ieee80211_channel *channel =
                                ieee80211_get_channel(wiphy, freq);
 
-                       lbs_deb_scan("scan: %pM, capa %04x, chan %2d, %s, "
-                                    "%d dBm\n",
-                                    bssid, capa, chan_no,
-                                    print_ssid(ssid_buf, ssid, ssid_len),
+                       lbs_deb_scan("scan: %pM, capa %04x, chan %2d, %*pE, %d dBm\n",
+                                    bssid, capa, chan_no, ssid_len, ssid,
                                     LBS_SCAN_RSSI_TO_MBM(rssi)/100);
 
                        if (channel &&
@@ -1984,7 +1981,6 @@ static int lbs_join_ibss(struct wiphy *wiphy, struct net_device *dev,
        struct lbs_private *priv = wiphy_priv(wiphy);
        int ret = 0;
        struct cfg80211_bss *bss;
-       DECLARE_SSID_BUF(ssid_buf);
 
        if (dev == priv->mesh_dev)
                return -EOPNOTSUPP;
index 01a67f62696f74788e6e4b01eb717f1f6d7fb75c..d0c881dd584677f18c551657d351b6bee435da5f 100644 (file)
@@ -93,7 +93,6 @@ static int lbs_mesh_config(struct lbs_private *priv, uint16_t action,
 {
        struct cmd_ds_mesh_config cmd;
        struct mrvl_meshie *ie;
-       DECLARE_SSID_BUF(ssid);
 
        memset(&cmd, 0, sizeof(cmd));
        cmd.channel = cpu_to_le16(chan);
@@ -122,9 +121,9 @@ static int lbs_mesh_config(struct lbs_private *priv, uint16_t action,
        default:
                return -1;
        }
-       lbs_deb_cmd("mesh config action %d type %x channel %d SSID %s\n",
-                   action, priv->mesh_tlv, chan,
-                   print_ssid(ssid, priv->mesh_ssid, priv->mesh_ssid_len));
+       lbs_deb_cmd("mesh config action %d type %x channel %d SSID %*pE\n",
+                   action, priv->mesh_tlv, chan, priv->mesh_ssid_len,
+                   priv->mesh_ssid);
 
        return __lbs_mesh_config_send(priv, &cmd, action, priv->mesh_tlv);
 }
index ded967aa6ecb6f69fbad672485052b6f55e66423..706b844bce00f4299c9b245c311afd1c0edc43f9 100644 (file)
@@ -742,35 +742,49 @@ static void rtl8180_int_disable(struct ieee80211_hw *dev)
 }
 
 static void rtl8180_conf_basic_rates(struct ieee80211_hw *dev,
-                           u32 rates_mask)
+                           u32 basic_mask)
 {
        struct rtl8180_priv *priv = dev->priv;
-
-       u8 max, min;
        u16 reg;
-
-       max = fls(rates_mask) - 1;
-       min = ffs(rates_mask) - 1;
+       u32 resp_mask;
+       u8 basic_max;
+       u8 resp_max, resp_min;
+
+       resp_mask = basic_mask;
+       /* IEEE80211 says the response rate should be equal to the highest basic
+        * rate that is not faster than received frame. But it says also that if
+        * the basic rate set does not contains any rate for the current
+        * modulation class then mandatory rate set must be used for that
+        * modulation class. Eventually add OFDM mandatory rates..
+        */
+       if ((resp_mask & 0xf) == resp_mask)
+               resp_mask |= 0x150; /* 6, 12, 24Mbps */
 
        switch (priv->chip_family) {
 
        case RTL818X_CHIP_FAMILY_RTL8180:
                /* in 8180 this is NOT a BITMAP */
+               basic_max = fls(basic_mask) - 1;
                reg = rtl818x_ioread16(priv, &priv->map->BRSR);
                reg &= ~3;
-               reg |= max;
+               reg |= basic_max;
                rtl818x_iowrite16(priv, &priv->map->BRSR, reg);
                break;
 
        case RTL818X_CHIP_FAMILY_RTL8185:
+               resp_max = fls(resp_mask) - 1;
+               resp_min = ffs(resp_mask) - 1;
                /* in 8185 this is a BITMAP */
-               rtl818x_iowrite16(priv, &priv->map->BRSR, rates_mask);
-               rtl818x_iowrite8(priv, &priv->map->RESP_RATE, (max << 4) | min);
+               rtl818x_iowrite16(priv, &priv->map->BRSR, basic_mask);
+               rtl818x_iowrite8(priv, &priv->map->RESP_RATE, (resp_max << 4) |
+                               resp_min);
                break;
 
        case RTL818X_CHIP_FAMILY_RTL8187SE:
-               /* in 8187se this is a BITMAP */
-               rtl818x_iowrite16(priv, &priv->map->BRSR_8187SE, rates_mask);
+               /* in 8187se this is a BITMAP. BRSR reg actually sets
+                * response rates.
+                */
+               rtl818x_iowrite16(priv, &priv->map->BRSR_8187SE, resp_mask);
                break;
        }
 }
index 976667ae85498feeb7abb06b505a254706dcefee..6866dcf24340959c78483e6e098d9e3c0dcfd889 100644 (file)
@@ -1370,7 +1370,7 @@ struct rtl_mac {
        bool rdg_en;
 
        /*AP*/
-       u8 bssid[6];
+       u8 bssid[ETH_ALEN] __aligned(2);
        u32 vendor;
        u8 mcs[16];     /* 16 bytes mcs for HT rates. */
        u32 basic_rates; /* b/g rates */
index 9c47b897b6d212c3de827ddde941acb325111546..8079c31ac5e64372fe978405c8faa72981998320 100644 (file)
@@ -937,22 +937,18 @@ static int read_xenbus_vif_flags(struct backend_info *be)
        return 0;
 }
 
-
-/* ** Driver Registration ** */
-
-
 static const struct xenbus_device_id netback_ids[] = {
        { "vif" },
        { "" }
 };
 
-
-static DEFINE_XENBUS_DRIVER(netback, ,
+static struct xenbus_driver netback_driver = {
+       .ids = netback_ids,
        .probe = netback_probe,
        .remove = netback_remove,
        .uevent = netback_uevent,
        .otherend_changed = frontend_changed,
-);
+};
 
 int xenvif_xenbus_init(void)
 {
index ca82f545ec2ca12678ca4f4ce6669c0b564f8bb2..fa671442f420806224bc85ee5f6b5200f7b5478c 100644 (file)
@@ -2300,12 +2300,6 @@ static void xennet_sysfs_delif(struct net_device *netdev)
 
 #endif /* CONFIG_SYSFS */
 
-static const struct xenbus_device_id netfront_ids[] = {
-       { "vif" },
-       { "" }
-};
-
-
 static int xennet_remove(struct xenbus_device *dev)
 {
        struct netfront_info *info = dev_get_drvdata(&dev->dev);
@@ -2338,12 +2332,18 @@ static int xennet_remove(struct xenbus_device *dev)
        return 0;
 }
 
-static DEFINE_XENBUS_DRIVER(netfront, ,
+static const struct xenbus_device_id netfront_ids[] = {
+       { "vif" },
+       { "" }
+};
+
+static struct xenbus_driver netfront_driver = {
+       .ids = netfront_ids,
        .probe = netfront_probe,
        .remove = xennet_remove,
        .resume = netfront_resume,
        .otherend_changed = netback_changed,
-);
+};
 
 static int __init netif_init(void)
 {
index 5160c4eb73c2e3788cd310693be3969b88642ea9..1a13f5b722c57e4d2d523c6be9b289084dba115a 100644 (file)
@@ -11,6 +11,7 @@ config OF_SELFTEST
        bool "Device Tree Runtime self tests"
        depends on OF_IRQ && OF_EARLY_FLATTREE
        select OF_DYNAMIC
+       select OF_RESOLVE
        help
          This option builds in test cases for the device tree infrastructure
          that are executed once at boot time, and the results dumped to the
@@ -79,4 +80,7 @@ config OF_RESERVED_MEM
        help
          Helpers to allow for reservation of memory regions
 
+config OF_RESOLVE
+       bool
+
 endmenu # OF
index 2b6a7b129d10b2092cb9e891158908c86c82fcfa..ca9209ce50cd74b85c599e16482c0e38078e03e0 100644 (file)
@@ -13,6 +13,7 @@ obj-$(CONFIG_OF_PCI)  += of_pci.o
 obj-$(CONFIG_OF_PCI_IRQ)  += of_pci_irq.o
 obj-$(CONFIG_OF_MTD)   += of_mtd.o
 obj-$(CONFIG_OF_RESERVED_MEM) += of_reserved_mem.o
+obj-$(CONFIG_OF_RESOLVE)  += resolver.o
 
 CFLAGS_fdt.o = -I$(src)/../../scripts/dtc/libfdt
 CFLAGS_fdt_address.o = -I$(src)/../../scripts/dtc/libfdt
index 293ed4b687ba7265889002edcb4f01b7d7edfe21..2305dc0382bca0a5c86bc89f5335253de46ff109 100644 (file)
@@ -1021,6 +1021,9 @@ struct device_node *of_find_node_by_phandle(phandle handle)
        struct device_node *np;
        unsigned long flags;
 
+       if (!handle)
+               return NULL;
+
        raw_spin_lock_irqsave(&devtree_lock, flags);
        for (np = of_allnodes; np; np = np->allnext)
                if (np->phandle == handle)
diff --git a/drivers/of/resolver.c b/drivers/of/resolver.c
new file mode 100644 (file)
index 0000000..aed7959
--- /dev/null
@@ -0,0 +1,336 @@
+/*
+ * Functions for dealing with DT resolution
+ *
+ * Copyright (C) 2012 Pantelis Antoniou <panto@antoniou-consulting.com>
+ * Copyright (C) 2012 Texas Instruments 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.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/string.h>
+#include <linux/ctype.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+
+/* illegal phandle value (set when unresolved) */
+#define OF_PHANDLE_ILLEGAL     0xdeadbeef
+
+/**
+ * Find a node with the give full name by recursively following any of
+ * the child node links.
+ */
+static struct device_node *__of_find_node_by_full_name(struct device_node *node,
+               const char *full_name)
+{
+       struct device_node *child, *found;
+
+       if (node == NULL)
+               return NULL;
+
+       /* check */
+       if (of_node_cmp(node->full_name, full_name) == 0)
+               return node;
+
+       for_each_child_of_node(node, child) {
+               found = __of_find_node_by_full_name(child, full_name);
+               if (found != NULL)
+                       return found;
+       }
+
+       return NULL;
+}
+
+/*
+ * Find live tree's maximum phandle value.
+ */
+static phandle of_get_tree_max_phandle(void)
+{
+       struct device_node *node;
+       phandle phandle;
+       unsigned long flags;
+
+       /* now search recursively */
+       raw_spin_lock_irqsave(&devtree_lock, flags);
+       phandle = 0;
+       for_each_of_allnodes(node) {
+               if (node->phandle != OF_PHANDLE_ILLEGAL &&
+                               node->phandle > phandle)
+                       phandle = node->phandle;
+       }
+       raw_spin_unlock_irqrestore(&devtree_lock, flags);
+
+       return phandle;
+}
+
+/*
+ * Adjust a subtree's phandle values by a given delta.
+ * Makes sure not to just adjust the device node's phandle value,
+ * but modify the phandle properties values as well.
+ */
+static void __of_adjust_tree_phandles(struct device_node *node,
+               int phandle_delta)
+{
+       struct device_node *child;
+       struct property *prop;
+       phandle phandle;
+
+       /* first adjust the node's phandle direct value */
+       if (node->phandle != 0 && node->phandle != OF_PHANDLE_ILLEGAL)
+               node->phandle += phandle_delta;
+
+       /* now adjust phandle & linux,phandle values */
+       for_each_property_of_node(node, prop) {
+
+               /* only look for these two */
+               if (of_prop_cmp(prop->name, "phandle") != 0 &&
+                   of_prop_cmp(prop->name, "linux,phandle") != 0)
+                       continue;
+
+               /* must be big enough */
+               if (prop->length < 4)
+                       continue;
+
+               /* read phandle value */
+               phandle = be32_to_cpup(prop->value);
+               if (phandle == OF_PHANDLE_ILLEGAL)      /* unresolved */
+                       continue;
+
+               /* adjust */
+               *(uint32_t *)prop->value = cpu_to_be32(node->phandle);
+       }
+
+       /* now do the children recursively */
+       for_each_child_of_node(node, child)
+               __of_adjust_tree_phandles(child, phandle_delta);
+}
+
+static int __of_adjust_phandle_ref(struct device_node *node, struct property *rprop, int value, bool is_delta)
+{
+       phandle phandle;
+       struct device_node *refnode;
+       struct property *sprop;
+       char *propval, *propcur, *propend, *nodestr, *propstr, *s;
+       int offset, propcurlen;
+       int err = 0;
+
+       /* make a copy */
+       propval = kmalloc(rprop->length, GFP_KERNEL);
+       if (!propval) {
+               pr_err("%s: Could not copy value of '%s'\n",
+                               __func__, rprop->name);
+               return -ENOMEM;
+       }
+       memcpy(propval, rprop->value, rprop->length);
+
+       propend = propval + rprop->length;
+       for (propcur = propval; propcur < propend; propcur += propcurlen + 1) {
+               propcurlen = strlen(propcur);
+
+               nodestr = propcur;
+               s = strchr(propcur, ':');
+               if (!s) {
+                       pr_err("%s: Illegal symbol entry '%s' (1)\n",
+                               __func__, propcur);
+                       err = -EINVAL;
+                       goto err_fail;
+               }
+               *s++ = '\0';
+
+               propstr = s;
+               s = strchr(s, ':');
+               if (!s) {
+                       pr_err("%s: Illegal symbol entry '%s' (2)\n",
+                               __func__, (char *)rprop->value);
+                       err = -EINVAL;
+                       goto err_fail;
+               }
+
+               *s++ = '\0';
+               err = kstrtoint(s, 10, &offset);
+               if (err != 0) {
+                       pr_err("%s: Could get offset '%s'\n",
+                               __func__, (char *)rprop->value);
+                       goto err_fail;
+               }
+
+               /* look into the resolve node for the full path */
+               refnode = __of_find_node_by_full_name(node, nodestr);
+               if (!refnode) {
+                       pr_warn("%s: Could not find refnode '%s'\n",
+                               __func__, (char *)rprop->value);
+                       continue;
+               }
+
+               /* now find the property */
+               for_each_property_of_node(refnode, sprop) {
+                       if (of_prop_cmp(sprop->name, propstr) == 0)
+                               break;
+               }
+
+               if (!sprop) {
+                       pr_err("%s: Could not find property '%s'\n",
+                               __func__, (char *)rprop->value);
+                       err = -ENOENT;
+                       goto err_fail;
+               }
+
+               phandle = is_delta ? be32_to_cpup(sprop->value + offset) + value : value;
+               *(__be32 *)(sprop->value + offset) = cpu_to_be32(phandle);
+       }
+
+err_fail:
+       kfree(propval);
+       return err;
+}
+
+/*
+ * Adjust the local phandle references by the given phandle delta.
+ * Assumes the existances of a __local_fixups__ node at the root
+ * of the tree. Does not take any devtree locks so make sure you
+ * call this on a tree which is at the detached state.
+ */
+static int __of_adjust_tree_phandle_references(struct device_node *node,
+               int phandle_delta)
+{
+       struct device_node *child;
+       struct property *rprop;
+       int err;
+
+       /* locate the symbols & fixups nodes on resolve */
+       for_each_child_of_node(node, child)
+               if (of_node_cmp(child->name, "__local_fixups__") == 0)
+                       break;
+
+       /* no local fixups */
+       if (!child)
+               return 0;
+
+       /* find the local fixups property */
+       for_each_property_of_node(child, rprop) {
+               /* skip properties added automatically */
+               if (of_prop_cmp(rprop->name, "name") == 0)
+                       continue;
+
+               err = __of_adjust_phandle_ref(node, rprop, phandle_delta, true);
+               if (err)
+                       return err;
+       }
+
+       return 0;
+}
+
+/**
+ * of_resolve  - Resolve the given node against the live tree.
+ *
+ * @resolve:   Node to resolve
+ *
+ * Perform dynamic Device Tree resolution against the live tree
+ * to the given node to resolve. This depends on the live tree
+ * having a __symbols__ node, and the resolve node the __fixups__ &
+ * __local_fixups__ nodes (if needed).
+ * The result of the operation is a resolve node that it's contents
+ * are fit to be inserted or operate upon the live tree.
+ * Returns 0 on success or a negative error value on error.
+ */
+int of_resolve_phandles(struct device_node *resolve)
+{
+       struct device_node *child, *refnode;
+       struct device_node *root_sym, *resolve_sym, *resolve_fix;
+       struct property *rprop;
+       const char *refpath;
+       phandle phandle, phandle_delta;
+       int err;
+
+       /* the resolve node must exist, and be detached */
+       if (!resolve || !of_node_check_flag(resolve, OF_DETACHED))
+               return -EINVAL;
+
+       /* first we need to adjust the phandles */
+       phandle_delta = of_get_tree_max_phandle() + 1;
+       __of_adjust_tree_phandles(resolve, phandle_delta);
+       err = __of_adjust_tree_phandle_references(resolve, phandle_delta);
+       if (err != 0)
+               return err;
+
+       root_sym = NULL;
+       resolve_sym = NULL;
+       resolve_fix = NULL;
+
+       /* this may fail (if no fixups are required) */
+       root_sym = of_find_node_by_path("/__symbols__");
+
+       /* locate the symbols & fixups nodes on resolve */
+       for_each_child_of_node(resolve, child) {
+
+               if (!resolve_sym &&
+                               of_node_cmp(child->name, "__symbols__") == 0)
+                       resolve_sym = child;
+
+               if (!resolve_fix &&
+                               of_node_cmp(child->name, "__fixups__") == 0)
+                       resolve_fix = child;
+
+               /* both found, don't bother anymore */
+               if (resolve_sym && resolve_fix)
+                       break;
+       }
+
+       /* we do allow for the case where no fixups are needed */
+       if (!resolve_fix) {
+               err = 0;        /* no error */
+               goto out;
+       }
+
+       /* we need to fixup, but no root symbols... */
+       if (!root_sym) {
+               err = -EINVAL;
+               goto out;
+       }
+
+       for_each_property_of_node(resolve_fix, rprop) {
+
+               /* skip properties added automatically */
+               if (of_prop_cmp(rprop->name, "name") == 0)
+                       continue;
+
+               err = of_property_read_string(root_sym,
+                               rprop->name, &refpath);
+               if (err != 0) {
+                       pr_err("%s: Could not find symbol '%s'\n",
+                                       __func__, rprop->name);
+                       goto out;
+               }
+
+               refnode = of_find_node_by_path(refpath);
+               if (!refnode) {
+                       pr_err("%s: Could not find node by path '%s'\n",
+                                       __func__, refpath);
+                       err = -ENOENT;
+                       goto out;
+               }
+
+               phandle = refnode->phandle;
+               of_node_put(refnode);
+
+               pr_debug("%s: %s phandle is 0x%08x\n",
+                               __func__, rprop->name, phandle);
+
+               err = __of_adjust_phandle_ref(resolve, rprop, phandle, false);
+               if (err)
+                       break;
+       }
+
+out:
+       /* NULL is handled by of_node_put as NOP */
+       of_node_put(root_sym);
+
+       return err;
+}
+EXPORT_SYMBOL_GPL(of_resolve_phandles);
index a737cb5974deae12aed1987d5250326ffa350445..78001270a5980bc7342a5241c8930297cf92f883 100644 (file)
@@ -7,6 +7,7 @@
 #include <linux/clk.h>
 #include <linux/err.h>
 #include <linux/errno.h>
+#include <linux/hashtable.h>
 #include <linux/module.h>
 #include <linux/of.h>
 #include <linux/of_fdt.h>
@@ -24,7 +25,7 @@ static struct selftest_results {
        int failed;
 } selftest_results;
 
-#define NO_OF_NODES 2
+#define NO_OF_NODES 3
 static struct device_node *nodes[NO_OF_NODES];
 static int last_node_index;
 static bool selftest_live_tree;
@@ -145,6 +146,97 @@ static void __init of_selftest_dynamic(void)
                         "Adding a large property should have passed\n");
 }
 
+static int __init of_selftest_check_node_linkage(struct device_node *np)
+{
+       struct device_node *child, *allnext_index = np;
+       int count = 0, rc;
+
+       for_each_child_of_node(np, child) {
+               if (child->parent != np) {
+                       pr_err("Child node %s links to wrong parent %s\n",
+                                child->name, np->name);
+                       return -EINVAL;
+               }
+
+               while (allnext_index && allnext_index != child)
+                       allnext_index = allnext_index->allnext;
+               if (allnext_index != child) {
+                       pr_err("Node %s is ordered differently in sibling and allnode lists\n",
+                                child->name);
+                       return -EINVAL;
+               }
+
+               rc = of_selftest_check_node_linkage(child);
+               if (rc < 0)
+                       return rc;
+               count += rc;
+       }
+
+       return count + 1;
+}
+
+static void __init of_selftest_check_tree_linkage(void)
+{
+       struct device_node *np;
+       int allnode_count = 0, child_count;
+
+       if (!of_allnodes)
+               return;
+
+       for_each_of_allnodes(np)
+               allnode_count++;
+       child_count = of_selftest_check_node_linkage(of_allnodes);
+
+       selftest(child_count > 0, "Device node data structure is corrupted\n");
+       selftest(child_count == allnode_count, "allnodes list size (%i) doesn't match"
+                "sibling lists size (%i)\n", allnode_count, child_count);
+       pr_debug("allnodes list size (%i); sibling lists size (%i)\n", allnode_count, child_count);
+}
+
+struct node_hash {
+       struct hlist_node node;
+       struct device_node *np;
+};
+
+static DEFINE_HASHTABLE(phandle_ht, 8);
+static void __init of_selftest_check_phandles(void)
+{
+       struct device_node *np;
+       struct node_hash *nh;
+       struct hlist_node *tmp;
+       int i, dup_count = 0, phandle_count = 0;
+
+       for_each_of_allnodes(np) {
+               if (!np->phandle)
+                       continue;
+
+               hash_for_each_possible(phandle_ht, nh, node, np->phandle) {
+                       if (nh->np->phandle == np->phandle) {
+                               pr_info("Duplicate phandle! %i used by %s and %s\n",
+                                       np->phandle, nh->np->full_name, np->full_name);
+                               dup_count++;
+                               break;
+                       }
+               }
+
+               nh = kzalloc(sizeof(*nh), GFP_KERNEL);
+               if (WARN_ON(!nh))
+                       return;
+
+               nh->np = np;
+               hash_add(phandle_ht, &nh->node, np->phandle);
+               phandle_count++;
+       }
+       selftest(dup_count == 0, "Found %i duplicates in %i phandles\n",
+                dup_count, phandle_count);
+
+       /* Clean up */
+       hash_for_each_safe(phandle_ht, i, tmp, nh, node) {
+               hash_del(&nh->node);
+               kfree(nh);
+       }
+}
+
 static void __init of_selftest_parse_phandle_with_args(void)
 {
        struct device_node *np;
@@ -637,6 +729,8 @@ static int attach_node_and_children(struct device_node *np)
        dup = np;
 
        while (dup) {
+               if (WARN_ON(last_node_index >= NO_OF_NODES))
+                       return -EINVAL;
                nodes[last_node_index++] = dup;
                dup = dup->sibling;
        }
@@ -670,6 +764,7 @@ static int __init selftest_data_add(void)
        extern uint8_t __dtb_testcases_begin[];
        extern uint8_t __dtb_testcases_end[];
        const int size = __dtb_testcases_end - __dtb_testcases_begin;
+       int rc;
 
        if (!size) {
                pr_warn("%s: No testcase data to attach; not running tests\n",
@@ -690,6 +785,12 @@ static int __init selftest_data_add(void)
                pr_warn("%s: No tree to attach; not running tests\n", __func__);
                return -ENODATA;
        }
+       of_node_set_flag(selftest_data_node, OF_DETACHED);
+       rc = of_resolve_phandles(selftest_data_node);
+       if (rc) {
+               pr_err("%s: Failed to resolve phandles (rc=%i)\n", __func__, rc);
+               return -EINVAL;
+       }
 
        if (!of_allnodes) {
                /* enabling flag for removing nodes */
@@ -717,10 +818,6 @@ static void detach_node_and_children(struct device_node *np)
 {
        while (np->child)
                detach_node_and_children(np->child);
-
-       while (np->sibling)
-               detach_node_and_children(np->sibling);
-
        of_detach_node(np);
 }
 
@@ -749,8 +846,7 @@ static void selftest_data_remove(void)
                if (nodes[last_node_index]) {
                        np = of_find_node_by_path(nodes[last_node_index]->full_name);
                        if (strcmp(np->full_name, "/aliases") != 0) {
-                               detach_node_and_children(np->child);
-                               of_detach_node(np);
+                               detach_node_and_children(np);
                        } else {
                                for_each_property_of_node(np, prop) {
                                        if (strcmp(prop->name, "testcase-alias") == 0)
@@ -780,6 +876,8 @@ static int __init of_selftest(void)
        of_node_put(np);
 
        pr_info("start of selftest - you will see error messages\n");
+       of_selftest_check_tree_linkage();
+       of_selftest_check_phandles();
        of_selftest_find_node_by_name();
        of_selftest_dynamic();
        of_selftest_parse_phandle_with_args();
@@ -790,12 +888,16 @@ static int __init of_selftest(void)
        of_selftest_parse_interrupts_extended();
        of_selftest_match_node();
        of_selftest_platform_populate();
-       pr_info("end of selftest - %i passed, %i failed\n",
-               selftest_results.passed, selftest_results.failed);
 
        /* removing selftest data from live tree */
        selftest_data_remove();
 
+       /* Double check linkage after removing testcase data */
+       of_selftest_check_tree_linkage();
+
+       pr_info("end of selftest - %i passed, %i failed\n",
+               selftest_results.passed, selftest_results.failed);
+
        return 0;
 }
 late_initcall(of_selftest);
index 219ef9324e9c6b8e270f064b97a1d34f11e6c884..6994e15c24bfe25d322ec9fe499daef23084a3bb 100644 (file)
 #include "tests-interrupts.dtsi"
 #include "tests-match.dtsi"
 #include "tests-platform.dtsi"
+
+/*
+ * phandle fixup data - generated by dtc patches that aren't upstream.
+ * This data must be regenerated whenever phandle references are modified in
+ * the testdata tree.
+ *
+ * The format of this data may be subject to change. For the time being consider
+ * this a kernel-internal data format.
+ */
+/ { __local_fixups__ {
+       fixup = "/testcase-data/testcase-device2:interrupt-parent:0",
+               "/testcase-data/testcase-device1:interrupt-parent:0",
+               "/testcase-data/interrupts/interrupts-extended0:interrupts-extended:60",
+               "/testcase-data/interrupts/interrupts-extended0:interrupts-extended:52",
+               "/testcase-data/interrupts/interrupts-extended0:interrupts-extended:44",
+               "/testcase-data/interrupts/interrupts-extended0:interrupts-extended:36",
+               "/testcase-data/interrupts/interrupts-extended0:interrupts-extended:24",
+               "/testcase-data/interrupts/interrupts-extended0:interrupts-extended:8",
+               "/testcase-data/interrupts/interrupts-extended0:interrupts-extended:0",
+               "/testcase-data/interrupts/interrupts1:interrupt-parent:0",
+               "/testcase-data/interrupts/interrupts0:interrupt-parent:0",
+               "/testcase-data/interrupts/intmap1:interrupt-map:12",
+               "/testcase-data/interrupts/intmap0:interrupt-map:52",
+               "/testcase-data/interrupts/intmap0:interrupt-map:36",
+               "/testcase-data/interrupts/intmap0:interrupt-map:16",
+               "/testcase-data/interrupts/intmap0:interrupt-map:4",
+               "/testcase-data/phandle-tests/consumer-a:phandle-list-bad-args:12",
+               "/testcase-data/phandle-tests/consumer-a:phandle-list-bad-args:0",
+               "/testcase-data/phandle-tests/consumer-a:phandle-list:56",
+               "/testcase-data/phandle-tests/consumer-a:phandle-list:52",
+               "/testcase-data/phandle-tests/consumer-a:phandle-list:40",
+               "/testcase-data/phandle-tests/consumer-a:phandle-list:24",
+               "/testcase-data/phandle-tests/consumer-a:phandle-list:8",
+               "/testcase-data/phandle-tests/consumer-a:phandle-list:0";
+}; };
index 90cca5e3805f584cbf3a571098e64f684aca3797..ef31b77404ef8e1113010805cbcbe46b71f1ff0f 100644 (file)
@@ -121,7 +121,6 @@ static int kpowerswd(void *param)
                unsigned long soft_power_reg = (unsigned long) param;
 
                schedule_timeout_interruptible(pwrsw_enabled ? HZ : HZ/POWERSWITCH_POLL_PER_SEC);
-               __set_current_state(TASK_RUNNING);
 
                if (unlikely(!pwrsw_enabled))
                        continue;
index 2f7c92c4757a33371025679e0468e21ffdaeacde..9fab30af0e75abdcec135707363951d7e9e26f8c 100644 (file)
@@ -302,6 +302,7 @@ void get_cached_msi_msg(unsigned int irq, struct msi_msg *msg)
 
        __get_cached_msi_msg(entry, msg);
 }
+EXPORT_SYMBOL_GPL(get_cached_msi_msg);
 
 void __write_msi_msg(struct msi_desc *entry, struct msi_msg *msg)
 {
@@ -346,6 +347,7 @@ void write_msi_msg(unsigned int irq, struct msi_msg *msg)
 
        __write_msi_msg(entry, msg);
 }
+EXPORT_SYMBOL_GPL(write_msi_msg);
 
 static void free_msi_irqs(struct pci_dev *dev)
 {
index 53df39a22c8acb20f6dda5dff8aa4050516dbfb2..116ca3746adb47cd5887bad8b8014ccdb5641b9c 100644 (file)
@@ -1136,11 +1136,13 @@ static const struct xenbus_device_id xenpci_ids[] = {
        {""},
 };
 
-static DEFINE_XENBUS_DRIVER(xenpci, "pcifront",
+static struct xenbus_driver xenpci_driver = {
+       .name                   = "pcifront",
+       .ids                    = xenpci_ids,
        .probe                  = pcifront_xenbus_probe,
        .remove                 = pcifront_xenbus_remove,
        .otherend_changed       = pcifront_backend_changed,
-);
+};
 
 static int __init pcifront_init(void)
 {
index 390e8e33d5e31b77d67c7d7a1a8c659ead20e791..25721bf20092dc47865e08a6b21c3011c0c0f05a 100644 (file)
@@ -163,18 +163,24 @@ static void dell_wmi_notify(u32 value, void *context)
                const struct key_entry *key;
                int reported_key;
                u16 *buffer_entry = (u16 *)obj->buffer.pointer;
+               int buffer_size = obj->buffer.length/2;
 
-               if (dell_new_hk_type && (buffer_entry[1] != 0x10)) {
+               if (buffer_size >= 2 && dell_new_hk_type && buffer_entry[1] != 0x10) {
                        pr_info("Received unknown WMI event (0x%x)\n",
                                buffer_entry[1]);
                        kfree(obj);
                        return;
                }
 
-               if (dell_new_hk_type || buffer_entry[1] == 0x0)
+               if (buffer_size >= 3 && (dell_new_hk_type || buffer_entry[1] == 0x0))
                        reported_key = (int)buffer_entry[2];
-               else
+               else if (buffer_size >= 2)
                        reported_key = (int)buffer_entry[1] & 0xffff;
+               else {
+                       pr_info("Received unknown WMI event\n");
+                       kfree(obj);
+                       return;
+               }
 
                key = sparse_keymap_entry_from_scancode(dell_wmi_input_dev,
                                                        reported_key);
index bd533c22be570a736795b2a35a83a7439a1d76d5..db79902c4a8ee86ee17c8c27039fd0d868d0792b 100644 (file)
@@ -263,13 +263,11 @@ static int acpi_setter_handle(struct eeepc_laptop *eeepc, int cm,
 /*
  * Sys helpers
  */
-static int parse_arg(const char *buf, unsigned long count, int *val)
+static int parse_arg(const char *buf, int *val)
 {
-       if (!count)
-               return 0;
        if (sscanf(buf, "%i", val) != 1)
                return -EINVAL;
-       return count;
+       return 0;
 }
 
 static ssize_t store_sys_acpi(struct device *dev, int cm,
@@ -278,12 +276,13 @@ static ssize_t store_sys_acpi(struct device *dev, int cm,
        struct eeepc_laptop *eeepc = dev_get_drvdata(dev);
        int rv, value;
 
-       rv = parse_arg(buf, count, &value);
-       if (rv > 0)
-               value = set_acpi(eeepc, cm, value);
-       if (value < 0)
+       rv = parse_arg(buf, &value);
+       if (rv < 0)
+               return rv;
+       rv = set_acpi(eeepc, cm, value);
+       if (rv < 0)
                return -EIO;
-       return rv;
+       return count;
 }
 
 static ssize_t show_sys_acpi(struct device *dev, int cm, char *buf)
@@ -296,30 +295,34 @@ static ssize_t show_sys_acpi(struct device *dev, int cm, char *buf)
        return sprintf(buf, "%d\n", value);
 }
 
-#define EEEPC_CREATE_DEVICE_ATTR(_name, _mode, _cm)                    \
-       static ssize_t show_##_name(struct device *dev,                 \
+#define EEEPC_ACPI_SHOW_FUNC(_name, _cm)                               \
+       static ssize_t _name##_show(struct device *dev,                 \
                                    struct device_attribute *attr,      \
                                    char *buf)                          \
        {                                                               \
                return show_sys_acpi(dev, _cm, buf);                    \
-       }                                                               \
-       static ssize_t store_##_name(struct device *dev,                \
+       }
+
+#define EEEPC_ACPI_STORE_FUNC(_name, _cm)                              \
+       static ssize_t _name##_store(struct device *dev,                \
                                     struct device_attribute *attr,     \
                                     const char *buf, size_t count)     \
        {                                                               \
                return store_sys_acpi(dev, _cm, buf, count);            \
-       }                                                               \
-       static struct device_attribute dev_attr_##_name = {             \
-               .attr = {                                               \
-                       .name = __stringify(_name),                     \
-                       .mode = _mode },                                \
-               .show   = show_##_name,                                 \
-               .store  = store_##_name,                                \
        }
 
-EEEPC_CREATE_DEVICE_ATTR(camera, 0644, CM_ASL_CAMERA);
-EEEPC_CREATE_DEVICE_ATTR(cardr, 0644, CM_ASL_CARDREADER);
-EEEPC_CREATE_DEVICE_ATTR(disp, 0200, CM_ASL_DISPLAYSWITCH);
+#define EEEPC_CREATE_DEVICE_ATTR_RW(_name, _cm)                                \
+       EEEPC_ACPI_SHOW_FUNC(_name, _cm)                                \
+       EEEPC_ACPI_STORE_FUNC(_name, _cm)                               \
+       static DEVICE_ATTR_RW(_name)
+
+#define EEEPC_CREATE_DEVICE_ATTR_WO(_name, _cm)                                \
+       EEEPC_ACPI_STORE_FUNC(_name, _cm)                               \
+       static DEVICE_ATTR_WO(_name)
+
+EEEPC_CREATE_DEVICE_ATTR_RW(camera, CM_ASL_CAMERA);
+EEEPC_CREATE_DEVICE_ATTR_RW(cardr, CM_ASL_CARDREADER);
+EEEPC_CREATE_DEVICE_ATTR_WO(disp, CM_ASL_DISPLAYSWITCH);
 
 struct eeepc_cpufv {
        int num;
@@ -329,14 +332,17 @@ struct eeepc_cpufv {
 static int get_cpufv(struct eeepc_laptop *eeepc, struct eeepc_cpufv *c)
 {
        c->cur = get_acpi(eeepc, CM_ASL_CPUFV);
+       if (c->cur < 0)
+               return -ENODEV;
+
        c->num = (c->cur >> 8) & 0xff;
        c->cur &= 0xff;
-       if (c->cur < 0 || c->num <= 0 || c->num > 12)
+       if (c->num == 0 || c->num > 12)
                return -ENODEV;
        return 0;
 }
 
-static ssize_t show_available_cpufv(struct device *dev,
+static ssize_t available_cpufv_show(struct device *dev,
                                    struct device_attribute *attr,
                                    char *buf)
 {
@@ -353,7 +359,7 @@ static ssize_t show_available_cpufv(struct device *dev,
        return len;
 }
 
-static ssize_t show_cpufv(struct device *dev,
+static ssize_t cpufv_show(struct device *dev,
                          struct device_attribute *attr,
                          char *buf)
 {
@@ -365,7 +371,7 @@ static ssize_t show_cpufv(struct device *dev,
        return sprintf(buf, "%#x\n", (c.num << 8) | c.cur);
 }
 
-static ssize_t store_cpufv(struct device *dev,
+static ssize_t cpufv_store(struct device *dev,
                           struct device_attribute *attr,
                           const char *buf, size_t count)
 {
@@ -377,16 +383,18 @@ static ssize_t store_cpufv(struct device *dev,
                return -EPERM;
        if (get_cpufv(eeepc, &c))
                return -ENODEV;
-       rv = parse_arg(buf, count, &value);
+       rv = parse_arg(buf, &value);
        if (rv < 0)
                return rv;
-       if (!rv || value < 0 || value >= c.num)
+       if (value < 0 || value >= c.num)
                return -EINVAL;
-       set_acpi(eeepc, CM_ASL_CPUFV, value);
-       return rv;
+       rv = set_acpi(eeepc, CM_ASL_CPUFV, value);
+       if (rv)
+               return rv;
+       return count;
 }
 
-static ssize_t show_cpufv_disabled(struct device *dev,
+static ssize_t cpufv_disabled_show(struct device *dev,
                          struct device_attribute *attr,
                          char *buf)
 {
@@ -395,14 +403,14 @@ static ssize_t show_cpufv_disabled(struct device *dev,
        return sprintf(buf, "%d\n", eeepc->cpufv_disabled);
 }
 
-static ssize_t store_cpufv_disabled(struct device *dev,
+static ssize_t cpufv_disabled_store(struct device *dev,
                           struct device_attribute *attr,
                           const char *buf, size_t count)
 {
        struct eeepc_laptop *eeepc = dev_get_drvdata(dev);
        int rv, value;
 
-       rv = parse_arg(buf, count, &value);
+       rv = parse_arg(buf, &value);
        if (rv < 0)
                return rv;
 
@@ -412,7 +420,7 @@ static ssize_t store_cpufv_disabled(struct device *dev,
                        pr_warn("cpufv enabled (not officially supported "
                                "on this model)\n");
                eeepc->cpufv_disabled = false;
-               return rv;
+               return count;
        case 1:
                return -EPERM;
        default:
@@ -421,29 +429,9 @@ static ssize_t store_cpufv_disabled(struct device *dev,
 }
 
 
-static struct device_attribute dev_attr_cpufv = {
-       .attr = {
-               .name = "cpufv",
-               .mode = 0644 },
-       .show   = show_cpufv,
-       .store  = store_cpufv
-};
-
-static struct device_attribute dev_attr_available_cpufv = {
-       .attr = {
-               .name = "available_cpufv",
-               .mode = 0444 },
-       .show   = show_available_cpufv
-};
-
-static struct device_attribute dev_attr_cpufv_disabled = {
-       .attr = {
-               .name = "cpufv_disabled",
-               .mode = 0644 },
-       .show   = show_cpufv_disabled,
-       .store  = store_cpufv_disabled
-};
-
+static DEVICE_ATTR_RW(cpufv);
+static DEVICE_ATTR_RO(available_cpufv);
+static DEVICE_ATTR_RW(cpufv_disabled);
 
 static struct attribute *platform_attributes[] = {
        &dev_attr_camera.attr,
@@ -545,7 +533,7 @@ static int eeepc_led_init(struct eeepc_laptop *eeepc)
        eeepc->tpd_led.name = "eeepc::touchpad";
        eeepc->tpd_led.brightness_set = tpd_led_set;
        if (get_acpi(eeepc, CM_ASL_TPD) >= 0) /* if method is available */
-         eeepc->tpd_led.brightness_get = tpd_led_get;
+               eeepc->tpd_led.brightness_get = tpd_led_get;
        eeepc->tpd_led.max_brightness = 1;
 
        rv = led_classdev_register(&eeepc->platform_device->dev,
@@ -680,22 +668,21 @@ static int eeepc_register_rfkill_notifier(struct eeepc_laptop *eeepc,
 
        status = acpi_get_handle(NULL, node, &handle);
 
-       if (ACPI_SUCCESS(status)) {
-               status = acpi_install_notify_handler(handle,
-                                                    ACPI_SYSTEM_NOTIFY,
-                                                    eeepc_rfkill_notify,
-                                                    eeepc);
-               if (ACPI_FAILURE(status))
-                       pr_warn("Failed to register notify on %s\n", node);
-
-               /*
-                * Refresh pci hotplug in case the rfkill state was
-                * changed during setup.
-                */
-               eeepc_rfkill_hotplug(eeepc, handle);
-       } else
+       if (ACPI_FAILURE(status))
                return -ENODEV;
 
+       status = acpi_install_notify_handler(handle,
+                                            ACPI_SYSTEM_NOTIFY,
+                                            eeepc_rfkill_notify,
+                                            eeepc);
+       if (ACPI_FAILURE(status))
+               pr_warn("Failed to register notify on %s\n", node);
+
+       /*
+        * Refresh pci hotplug in case the rfkill state was
+        * changed during setup.
+        */
+       eeepc_rfkill_hotplug(eeepc, handle);
        return 0;
 }
 
@@ -707,20 +694,21 @@ static void eeepc_unregister_rfkill_notifier(struct eeepc_laptop *eeepc,
 
        status = acpi_get_handle(NULL, node, &handle);
 
-       if (ACPI_SUCCESS(status)) {
-               status = acpi_remove_notify_handler(handle,
-                                                    ACPI_SYSTEM_NOTIFY,
-                                                    eeepc_rfkill_notify);
-               if (ACPI_FAILURE(status))
-                       pr_err("Error removing rfkill notify handler %s\n",
-                               node);
-                       /*
-                        * Refresh pci hotplug in case the rfkill
-                        * state was changed after
-                        * eeepc_unregister_rfkill_notifier()
-                        */
-               eeepc_rfkill_hotplug(eeepc, handle);
-       }
+       if (ACPI_FAILURE(status))
+               return;
+
+       status = acpi_remove_notify_handler(handle,
+                                            ACPI_SYSTEM_NOTIFY,
+                                            eeepc_rfkill_notify);
+       if (ACPI_FAILURE(status))
+               pr_err("Error removing rfkill notify handler %s\n",
+                       node);
+               /*
+                * Refresh pci hotplug in case the rfkill
+                * state was changed after
+                * eeepc_unregister_rfkill_notifier()
+                */
+       eeepc_rfkill_hotplug(eeepc, handle);
 }
 
 static int eeepc_get_adapter_status(struct hotplug_slot *hotplug_slot,
@@ -1042,10 +1030,11 @@ static ssize_t store_sys_hwmon(void (*set)(int), const char *buf, size_t count)
 {
        int rv, value;
 
-       rv = parse_arg(buf, count, &value);
-       if (rv > 0)
-               set(value);
-       return rv;
+       rv = parse_arg(buf, &value);
+       if (rv < 0)
+               return rv;
+       set(value);
+       return count;
 }
 
 static ssize_t show_sys_hwmon(int (*get)(void), char *buf)
@@ -1053,26 +1042,36 @@ static ssize_t show_sys_hwmon(int (*get)(void), char *buf)
        return sprintf(buf, "%d\n", get());
 }
 
-#define EEEPC_CREATE_SENSOR_ATTR(_name, _mode, _get, _set)             \
-       static ssize_t show_##_name(struct device *dev,                 \
+#define EEEPC_SENSOR_SHOW_FUNC(_name, _get)                            \
+       static ssize_t _name##_show(struct device *dev,                 \
                                    struct device_attribute *attr,      \
                                    char *buf)                          \
        {                                                               \
                return show_sys_hwmon(_get, buf);                       \
-       }                                                               \
-       static ssize_t store_##_name(struct device *dev,                \
+       }
+
+#define EEEPC_SENSOR_STORE_FUNC(_name, _set)                           \
+       static ssize_t _name##_store(struct device *dev,                \
                                     struct device_attribute *attr,     \
                                     const char *buf, size_t count)     \
        {                                                               \
                return store_sys_hwmon(_set, buf, count);               \
-       }                                                               \
-       static DEVICE_ATTR(_name, _mode, show_##_name, store_##_name)
+       }
+
+#define EEEPC_CREATE_SENSOR_ATTR_RW(_name, _get, _set)                 \
+       EEEPC_SENSOR_SHOW_FUNC(_name, _get)                             \
+       EEEPC_SENSOR_STORE_FUNC(_name, _set)                            \
+       static DEVICE_ATTR_RW(_name)
 
-EEEPC_CREATE_SENSOR_ATTR(fan1_input, S_IRUGO, eeepc_get_fan_rpm, NULL);
-EEEPC_CREATE_SENSOR_ATTR(pwm1, S_IRUGO | S_IWUSR,
-                        eeepc_get_fan_pwm, eeepc_set_fan_pwm);
-EEEPC_CREATE_SENSOR_ATTR(pwm1_enable, S_IRUGO | S_IWUSR,
-                        eeepc_get_fan_ctrl, eeepc_set_fan_ctrl);
+#define EEEPC_CREATE_SENSOR_ATTR_RO(_name, _get)                       \
+       EEEPC_SENSOR_SHOW_FUNC(_name, _get)                             \
+       static DEVICE_ATTR_RO(_name)
+
+EEEPC_CREATE_SENSOR_ATTR_RO(fan1_input, eeepc_get_fan_rpm);
+EEEPC_CREATE_SENSOR_ATTR_RW(pwm1, eeepc_get_fan_pwm,
+                           eeepc_set_fan_pwm);
+EEEPC_CREATE_SENSOR_ATTR_RW(pwm1_enable, eeepc_get_fan_ctrl,
+                           eeepc_set_fan_ctrl);
 
 static struct attribute *hwmon_attrs[] = {
        &dev_attr_pwm1.attr,
@@ -1424,8 +1423,9 @@ static int eeepc_acpi_add(struct acpi_device *device)
                result = eeepc_backlight_init(eeepc);
                if (result)
                        goto fail_backlight;
-       } else
+       } else {
                pr_info("Backlight controlled by ACPI video driver\n");
+       }
 
        result = eeepc_input_init(eeepc);
        if (result)
index d45bca34bf1b3bc935f5dc9b729fd87219cf4825..7344d841f4d98d17810b5f6bdbee8965415af6e5 100644 (file)
@@ -35,7 +35,7 @@ static ssize_t irst_show_wakeup_events(struct device *dev,
        acpi = to_acpi_device(dev);
 
        status = acpi_evaluate_integer(acpi->handle, "GFFS", NULL, &value);
-       if (!ACPI_SUCCESS(status))
+       if (ACPI_FAILURE(status))
                return -EINVAL;
 
        return sprintf(buf, "%lld\n", value);
@@ -59,7 +59,7 @@ static ssize_t irst_store_wakeup_events(struct device *dev,
 
        status = acpi_execute_simple_method(acpi->handle, "SFFS", value);
 
-       if (!ACPI_SUCCESS(status))
+       if (ACPI_FAILURE(status))
                return -EINVAL;
 
        return count;
@@ -81,7 +81,7 @@ static ssize_t irst_show_wakeup_time(struct device *dev,
        acpi = to_acpi_device(dev);
 
        status = acpi_evaluate_integer(acpi->handle, "GFTV", NULL, &value);
-       if (!ACPI_SUCCESS(status))
+       if (ACPI_FAILURE(status))
                return -EINVAL;
 
        return sprintf(buf, "%lld\n", value);
@@ -105,7 +105,7 @@ static ssize_t irst_store_wakeup_time(struct device *dev,
 
        status = acpi_execute_simple_method(acpi->handle, "SFTV", value);
 
-       if (!ACPI_SUCCESS(status))
+       if (ACPI_FAILURE(status))
                return -EINVAL;
 
        return count;
@@ -119,21 +119,16 @@ static struct device_attribute irst_timeout_attr = {
 
 static int irst_add(struct acpi_device *acpi)
 {
-       int error = 0;
+       int error;
 
        error = device_create_file(&acpi->dev, &irst_timeout_attr);
-       if (error)
-               goto out;
+       if (unlikely(error))
+               return error;
 
        error = device_create_file(&acpi->dev, &irst_wakeup_attr);
-       if (error)
-               goto out_timeout;
+       if (unlikely(error))
+               device_remove_file(&acpi->dev, &irst_timeout_attr);
 
-       return 0;
-
-out_timeout:
-       device_remove_file(&acpi->dev, &irst_timeout_attr);
-out:
        return error;
 }
 
index 3bbc6eb60de56d5ebb55daa80b183f8296520325..cf0f89364d4411f8321bdf69bff7b64725b5612f 100644 (file)
@@ -3440,7 +3440,7 @@ err_exit:
        delete_attr_set(hotkey_dev_attributes, &tpacpi_pdev->dev.kobj);
        hotkey_dev_attributes = NULL;
 
-       return (res < 0)? res : 1;
+       return (res < 0) ? res : 1;
 }
 
 /* Thinkpad X1 Carbon support 5 modes including Home mode, Web browser
@@ -4576,7 +4576,7 @@ static int __init video_init(struct ibm_init_struct *iibm)
                str_supported(video_supported != TPACPI_VIDEO_NONE),
                video_supported);
 
-       return (video_supported != TPACPI_VIDEO_NONE)? 0 : 1;
+       return (video_supported != TPACPI_VIDEO_NONE) ? 0 : 1;
 }
 
 static void video_exit(void)
@@ -4669,7 +4669,7 @@ static int video_outputsw_set(int status)
                return -ENOSYS;
        }
 
-       return (res)? 0 : -EIO;
+       return (res) ? 0 : -EIO;
 }
 
 static int video_autosw_get(void)
@@ -4695,7 +4695,7 @@ static int video_autosw_get(void)
 
 static int video_autosw_set(int enable)
 {
-       if (!acpi_evalf(vid_handle, NULL, "_DOS", "vd", (enable)? 1 : 0))
+       if (!acpi_evalf(vid_handle, NULL, "_DOS", "vd", (enable) ? 1 : 0))
                return -EIO;
        return 0;
 }
@@ -4730,20 +4730,20 @@ static int video_outputsw_cycle(void)
                return -EIO;
        }
 
-       return (res)? 0 : -EIO;
+       return (res) ? 0 : -EIO;
 }
 
 static int video_expand_toggle(void)
 {
        switch (video_supported) {
        case TPACPI_VIDEO_570:
-               return acpi_evalf(ec_handle, NULL, "_Q17", "v")?
+               return acpi_evalf(ec_handle, NULL, "_Q17", "v") ?
                        0 : -EIO;
        case TPACPI_VIDEO_770:
-               return acpi_evalf(vid_handle, NULL, "VEXP", "v")?
+               return acpi_evalf(vid_handle, NULL, "VEXP", "v") ?
                        0 : -EIO;
        case TPACPI_VIDEO_NEW:
-               return acpi_evalf(NULL, NULL, "\\VEXP", "v")?
+               return acpi_evalf(NULL, NULL, "\\VEXP", "v") ?
                        0 : -EIO;
        default:
                return -ENOSYS;
@@ -4887,14 +4887,14 @@ static int light_set_status(int status)
        if (tp_features.light) {
                if (cmos_handle) {
                        rc = acpi_evalf(cmos_handle, NULL, NULL, "vd",
-                                       (status)?
+                                       (status) ?
                                                TP_CMOS_THINKLIGHT_ON :
                                                TP_CMOS_THINKLIGHT_OFF);
                } else {
                        rc = acpi_evalf(lght_handle, NULL, NULL, "vd",
-                                       (status)? 1 : 0);
+                                       (status) ? 1 : 0);
                }
-               return (rc)? 0 : -EIO;
+               return (rc) ? 0 : -EIO;
        }
 
        return -ENXIO;
@@ -4923,7 +4923,7 @@ static void light_sysfs_set(struct led_classdev *led_cdev,
 
 static enum led_brightness light_sysfs_get(struct led_classdev *led_cdev)
 {
-       return (light_get_status() == 1)? LED_FULL : LED_OFF;
+       return (light_get_status() == 1) ? LED_FULL : LED_OFF;
 }
 
 static struct tpacpi_led_classdev tpacpi_led_thinklight = {
@@ -5045,7 +5045,7 @@ static ssize_t cmos_command_store(struct device *dev,
                return -EINVAL;
 
        res = issue_thinkpad_cmos_command(cmos_cmd);
-       return (res)? res : count;
+       return (res) ? res : count;
 }
 
 static struct device_attribute dev_attr_cmos_command =
@@ -5069,7 +5069,7 @@ static int __init cmos_init(struct ibm_init_struct *iibm)
        if (res)
                return res;
 
-       return (cmos_handle)? 0 : 1;
+       return (cmos_handle) ? 0 : 1;
 }
 
 static void cmos_exit(void)
@@ -5179,9 +5179,9 @@ static int led_get_status(const unsigned int led)
                if (!acpi_evalf(ec_handle,
                                &status, "GLED", "dd", 1 << led))
                        return -EIO;
-               led_s = (status == 0)?
+               led_s = (status == 0) ?
                                TPACPI_LED_OFF :
-                               ((status == 1)?
+                               ((status == 1) ?
                                        TPACPI_LED_ON :
                                        TPACPI_LED_BLINK);
                tpacpi_led_state_cache[led] = led_s;
@@ -5578,7 +5578,7 @@ static int __init beep_init(struct ibm_init_struct *iibm)
 
        tp_features.beep_needs_two_args = !!(quirks & TPACPI_BEEP_Q1);
 
-       return (beep_handle)? 0 : 1;
+       return (beep_handle) ? 0 : 1;
 }
 
 static int beep_read(struct seq_file *m)
@@ -6527,7 +6527,7 @@ static int brightness_write(char *buf)
        if (!rc && ibm_backlight_device)
                backlight_force_update(ibm_backlight_device,
                                        BACKLIGHT_UPDATE_SYSFS);
-       return (rc == -EINTR)? -ERESTARTSYS : rc;
+       return (rc == -EINTR) ? -ERESTARTSYS : rc;
 }
 
 static struct ibm_struct brightness_driver_data = {
@@ -7984,7 +7984,7 @@ static ssize_t fan_pwm1_store(struct device *dev,
        }
 
        mutex_unlock(&fan_mutex);
-       return (rc)? rc : count;
+       return (rc) ? rc : count;
 }
 
 static struct device_attribute dev_attr_fan_pwm1 =
@@ -8662,7 +8662,7 @@ static const char * __init str_supported(int is_supported)
 {
        static char text_unsupported[] __initdata = "not supported";
 
-       return (is_supported)? &text_unsupported[4] : &text_unsupported[0];
+       return (is_supported) ? &text_unsupported[4] : &text_unsupported[0];
 }
 #endif /* CONFIG_THINKPAD_ACPI_DEBUG */
 
@@ -8783,7 +8783,7 @@ err_out:
                ibm->name, ret);
 
        ibm_exit(ibm);
-       return (ret < 0)? ret : 0;
+       return (ret < 0) ? ret : 0;
 }
 
 /* Probing */
@@ -8794,7 +8794,7 @@ static bool __pure __init tpacpi_is_fw_digit(const char c)
 }
 
 /* Most models: xxyTkkWW (#.##c); Ancient 570/600 and -SL lacks (#.##c) */
-static bool __pure __init tpacpi_is_valid_fw_id(const char* const s,
+static bool __pure __init tpacpi_is_valid_fw_id(const char * const s,
                                                const char t)
 {
        return s && strlen(s) >= 8 &&
@@ -8878,13 +8878,13 @@ static int __must_check __init get_thinkpad_model_data(
        }
 
        s = dmi_get_system_info(DMI_PRODUCT_VERSION);
-       if (s && !(strnicmp(s, "ThinkPad", 8) && strnicmp(s, "Lenovo", 6))) {
+       if (s && !(strncasecmp(s, "ThinkPad", 8) && strncasecmp(s, "Lenovo", 6))) {
                tp->model_str = kstrdup(s, GFP_KERNEL);
                if (!tp->model_str)
                        return -ENOMEM;
        } else {
                s = dmi_get_system_info(DMI_BIOS_VENDOR);
-               if (s && !(strnicmp(s, "Lenovo", 6))) {
+               if (s && !(strncasecmp(s, "Lenovo", 6))) {
                        tp->model_str = kstrdup(s, GFP_KERNEL);
                        if (!tp->model_str)
                                return -ENOMEM;
index d0dce734b2edb37e055d6f30f6901a234645708f..ef3a1904e92fe0827de83d79540bc1b569801554 100644 (file)
@@ -71,7 +71,8 @@ MODULE_LICENSE("GPL");
 /* Toshiba ACPI method paths */
 #define METHOD_VIDEO_OUT       "\\_SB_.VALX.DSSX"
 
-/* Toshiba HCI interface definitions
+/* The Toshiba configuration interface is composed of the HCI and the SCI,
+ * which are defined as follows:
  *
  * HCI is Toshiba's "Hardware Control Interface" which is supposed to
  * be uniform across all their models.  Ideally we would just call
@@ -84,7 +85,7 @@ MODULE_LICENSE("GPL");
  * conceal differences in hardware between different models.
  */
 
-#define HCI_WORDS                      6
+#define TCI_WORDS                      6
 
 /* operations */
 #define HCI_SET                                0xff00
@@ -95,17 +96,18 @@ MODULE_LICENSE("GPL");
 #define SCI_SET                                0xf400
 
 /* return codes */
-#define HCI_SUCCESS                    0x0000
-#define HCI_FAILURE                    0x1000
-#define HCI_NOT_SUPPORTED              0x8000
-#define HCI_EMPTY                      0x8c00
-#define HCI_DATA_NOT_AVAILABLE         0x8d20
-#define HCI_NOT_INITIALIZED            0x8d50
-#define SCI_OPEN_CLOSE_OK              0x0044
-#define SCI_ALREADY_OPEN               0x8100
-#define SCI_NOT_OPENED                 0x8200
-#define SCI_INPUT_DATA_ERROR           0x8300
-#define SCI_NOT_PRESENT                        0x8600
+#define TOS_SUCCESS                    0x0000
+#define TOS_OPEN_CLOSE_OK              0x0044
+#define TOS_FAILURE                    0x1000
+#define TOS_NOT_SUPPORTED              0x8000
+#define TOS_ALREADY_OPEN               0x8100
+#define TOS_NOT_OPENED                 0x8200
+#define TOS_INPUT_DATA_ERROR           0x8300
+#define TOS_WRITE_PROTECTED            0x8400
+#define TOS_NOT_PRESENT                        0x8600
+#define TOS_FIFO_EMPTY                 0x8c00
+#define TOS_DATA_NOT_AVAILABLE         0x8d20
+#define TOS_NOT_INITIALIZED            0x8d50
 
 /* registers */
 #define HCI_FAN                                0x0004
@@ -138,8 +140,12 @@ MODULE_LICENSE("GPL");
 #define HCI_WIRELESS_BT_PRESENT                0x0f
 #define HCI_WIRELESS_BT_ATTACH         0x40
 #define HCI_WIRELESS_BT_POWER          0x80
+#define SCI_KBD_MODE_MASK              0x1f
 #define SCI_KBD_MODE_FNZ               0x1
 #define SCI_KBD_MODE_AUTO              0x2
+#define SCI_KBD_MODE_ON                        0x8
+#define SCI_KBD_MODE_OFF               0x10
+#define SCI_KBD_TIME_MAX               0x3c001a
 
 struct toshiba_acpi_dev {
        struct acpi_device *acpi_dev;
@@ -155,6 +161,7 @@ struct toshiba_acpi_dev {
        int force_fan;
        int last_key_event;
        int key_event_valid;
+       int kbd_type;
        int kbd_mode;
        int kbd_time;
 
@@ -190,6 +197,7 @@ static const struct key_entry toshiba_acpi_keymap[] = {
        { KE_KEY, 0x101, { KEY_MUTE } },
        { KE_KEY, 0x102, { KEY_ZOOMOUT } },
        { KE_KEY, 0x103, { KEY_ZOOMIN } },
+       { KE_KEY, 0x10f, { KEY_TAB } },
        { KE_KEY, 0x12c, { KEY_KBDILLUMTOGGLE } },
        { KE_KEY, 0x139, { KEY_ZOOMRESET } },
        { KE_KEY, 0x13b, { KEY_COFFEE } },
@@ -210,7 +218,11 @@ static const struct key_entry toshiba_acpi_keymap[] = {
        { KE_KEY, 0xb32, { KEY_NEXTSONG } },
        { KE_KEY, 0xb33, { KEY_PLAYPAUSE } },
        { KE_KEY, 0xb5a, { KEY_MEDIA } },
-       { KE_IGNORE, 0x1430, { KEY_RESERVED } },
+       { KE_IGNORE, 0x1430, { KEY_RESERVED } }, /* Wake from sleep */
+       { KE_IGNORE, 0x1501, { KEY_RESERVED } }, /* Output changed */
+       { KE_IGNORE, 0x1502, { KEY_RESERVED } }, /* HDMI plugged/unplugged */
+       { KE_IGNORE, 0x1ABE, { KEY_RESERVED } }, /* Protection level set */
+       { KE_IGNORE, 0x1ABF, { KEY_RESERVED } }, /* Protection level off */
        { KE_END, 0 },
 };
 
@@ -264,22 +276,22 @@ static int write_acpi_int(const char *methodName, int val)
        return (status == AE_OK) ? 0 : -EIO;
 }
 
-/* Perform a raw HCI call.  Here we don't care about input or output buffer
- * format.
+/* Perform a raw configuration call.  Here we don't care about input or output
+ * buffer format.
  */
-static acpi_status hci_raw(struct toshiba_acpi_dev *dev,
-                          const u32 in[HCI_WORDS], u32 out[HCI_WORDS])
+static acpi_status tci_raw(struct toshiba_acpi_dev *dev,
+                          const u32 in[TCI_WORDS], u32 out[TCI_WORDS])
 {
        struct acpi_object_list params;
-       union acpi_object in_objs[HCI_WORDS];
+       union acpi_object in_objs[TCI_WORDS];
        struct acpi_buffer results;
-       union acpi_object out_objs[HCI_WORDS + 1];
+       union acpi_object out_objs[TCI_WORDS + 1];
        acpi_status status;
        int i;
 
-       params.count = HCI_WORDS;
+       params.count = TCI_WORDS;
        params.pointer = in_objs;
-       for (i = 0; i < HCI_WORDS; ++i) {
+       for (i = 0; i < TCI_WORDS; ++i) {
                in_objs[i].type = ACPI_TYPE_INTEGER;
                in_objs[i].integer.value = in[i];
        }
@@ -290,7 +302,7 @@ static acpi_status hci_raw(struct toshiba_acpi_dev *dev,
        status = acpi_evaluate_object(dev->acpi_dev->handle,
                                      (char *)dev->method_hci, &params,
                                      &results);
-       if ((status == AE_OK) && (out_objs->package.count <= HCI_WORDS)) {
+       if ((status == AE_OK) && (out_objs->package.count <= TCI_WORDS)) {
                for (i = 0; i < out_objs->package.count; ++i) {
                        out[i] = out_objs->package.elements[i].integer.value;
                }
@@ -305,47 +317,49 @@ static acpi_status hci_raw(struct toshiba_acpi_dev *dev,
  * may be useful (such as "not supported").
  */
 
-static acpi_status hci_write1(struct toshiba_acpi_dev *dev, u32 reg,
-                             u32 in1, u32 *result)
+static u32 hci_write1(struct toshiba_acpi_dev *dev, u32 reg, u32 in1)
 {
-       u32 in[HCI_WORDS] = { HCI_SET, reg, in1, 0, 0, 0 };
-       u32 out[HCI_WORDS];
-       acpi_status status = hci_raw(dev, in, out);
-       *result = (status == AE_OK) ? out[0] : HCI_FAILURE;
-       return status;
+       u32 in[TCI_WORDS] = { HCI_SET, reg, in1, 0, 0, 0 };
+       u32 out[TCI_WORDS];
+       acpi_status status = tci_raw(dev, in, out);
+
+       return ACPI_SUCCESS(status) ? out[0] : TOS_FAILURE;
 }
 
-static acpi_status hci_read1(struct toshiba_acpi_dev *dev, u32 reg,
-                            u32 *out1, u32 *result)
+static u32 hci_read1(struct toshiba_acpi_dev *dev, u32 reg, u32 *out1)
 {
-       u32 in[HCI_WORDS] = { HCI_GET, reg, 0, 0, 0, 0 };
-       u32 out[HCI_WORDS];
-       acpi_status status = hci_raw(dev, in, out);
+       u32 in[TCI_WORDS] = { HCI_GET, reg, 0, 0, 0, 0 };
+       u32 out[TCI_WORDS];
+       acpi_status status = tci_raw(dev, in, out);
+       if (ACPI_FAILURE(status))
+               return TOS_FAILURE;
+
        *out1 = out[2];
-       *result = (status == AE_OK) ? out[0] : HCI_FAILURE;
-       return status;
+
+       return out[0];
 }
 
-static acpi_status hci_write2(struct toshiba_acpi_dev *dev, u32 reg,
-                             u32 in1, u32 in2, u32 *result)
+static u32 hci_write2(struct toshiba_acpi_dev *dev, u32 reg, u32 in1, u32 in2)
 {
-       u32 in[HCI_WORDS] = { HCI_SET, reg, in1, in2, 0, 0 };
-       u32 out[HCI_WORDS];
-       acpi_status status = hci_raw(dev, in, out);
-       *result = (status == AE_OK) ? out[0] : HCI_FAILURE;
-       return status;
+       u32 in[TCI_WORDS] = { HCI_SET, reg, in1, in2, 0, 0 };
+       u32 out[TCI_WORDS];
+       acpi_status status = tci_raw(dev, in, out);
+
+       return ACPI_SUCCESS(status) ? out[0] : TOS_FAILURE;
 }
 
-static acpi_status hci_read2(struct toshiba_acpi_dev *dev, u32 reg,
-                            u32 *out1, u32 *out2, u32 *result)
+static u32 hci_read2(struct toshiba_acpi_dev *dev, u32 reg, u32 *out1, u32 *out2)
 {
-       u32 in[HCI_WORDS] = { HCI_GET, reg, *out1, *out2, 0, 0 };
-       u32 out[HCI_WORDS];
-       acpi_status status = hci_raw(dev, in, out);
+       u32 in[TCI_WORDS] = { HCI_GET, reg, *out1, *out2, 0, 0 };
+       u32 out[TCI_WORDS];
+       acpi_status status = tci_raw(dev, in, out);
+       if (ACPI_FAILURE(status))
+               return TOS_FAILURE;
+
        *out1 = out[2];
        *out2 = out[3];
-       *result = (status == AE_OK) ? out[0] : HCI_FAILURE;
-       return status;
+
+       return out[0];
 }
 
 /* common sci tasks
@@ -353,22 +367,22 @@ static acpi_status hci_read2(struct toshiba_acpi_dev *dev, u32 reg,
 
 static int sci_open(struct toshiba_acpi_dev *dev)
 {
-       u32 in[HCI_WORDS] = { SCI_OPEN, 0, 0, 0, 0, 0 };
-       u32 out[HCI_WORDS];
+       u32 in[TCI_WORDS] = { SCI_OPEN, 0, 0, 0, 0, 0 };
+       u32 out[TCI_WORDS];
        acpi_status status;
 
-       status = hci_raw(dev, in, out);
-       if  (ACPI_FAILURE(status) || out[0] == HCI_FAILURE) {
+       status = tci_raw(dev, in, out);
+       if  (ACPI_FAILURE(status) || out[0] == TOS_FAILURE) {
                pr_err("ACPI call to open SCI failed\n");
                return 0;
        }
 
-       if (out[0] == SCI_OPEN_CLOSE_OK) {
+       if (out[0] == TOS_OPEN_CLOSE_OK) {
                return 1;
-       } else if (out[0] == SCI_ALREADY_OPEN) {
+       } else if (out[0] == TOS_ALREADY_OPEN) {
                pr_info("Toshiba SCI already opened\n");
                return 1;
-       } else if (out[0] == SCI_NOT_PRESENT) {
+       } else if (out[0] == TOS_NOT_PRESENT) {
                pr_info("Toshiba SCI is not present\n");
        }
 
@@ -377,61 +391,62 @@ static int sci_open(struct toshiba_acpi_dev *dev)
 
 static void sci_close(struct toshiba_acpi_dev *dev)
 {
-       u32 in[HCI_WORDS] = { SCI_CLOSE, 0, 0, 0, 0, 0 };
-       u32 out[HCI_WORDS];
+       u32 in[TCI_WORDS] = { SCI_CLOSE, 0, 0, 0, 0, 0 };
+       u32 out[TCI_WORDS];
        acpi_status status;
 
-       status = hci_raw(dev, in, out);
-       if (ACPI_FAILURE(status) || out[0] == HCI_FAILURE) {
+       status = tci_raw(dev, in, out);
+       if (ACPI_FAILURE(status) || out[0] == TOS_FAILURE) {
                pr_err("ACPI call to close SCI failed\n");
                return;
        }
 
-       if (out[0] == SCI_OPEN_CLOSE_OK)
+       if (out[0] == TOS_OPEN_CLOSE_OK)
                return;
-       else if (out[0] == SCI_NOT_OPENED)
+       else if (out[0] == TOS_NOT_OPENED)
                pr_info("Toshiba SCI not opened\n");
-       else if (out[0] == SCI_NOT_PRESENT)
+       else if (out[0] == TOS_NOT_PRESENT)
                pr_info("Toshiba SCI is not present\n");
 }
 
-static acpi_status sci_read(struct toshiba_acpi_dev *dev, u32 reg,
-                           u32 *out1, u32 *result)
+static u32 sci_read(struct toshiba_acpi_dev *dev, u32 reg, u32 *out1)
 {
-       u32 in[HCI_WORDS] = { SCI_GET, reg, 0, 0, 0, 0 };
-       u32 out[HCI_WORDS];
-       acpi_status status = hci_raw(dev, in, out);
+       u32 in[TCI_WORDS] = { SCI_GET, reg, 0, 0, 0, 0 };
+       u32 out[TCI_WORDS];
+       acpi_status status = tci_raw(dev, in, out);
+       if (ACPI_FAILURE(status))
+               return TOS_FAILURE;
+
        *out1 = out[2];
-       *result = (ACPI_SUCCESS(status)) ? out[0] : HCI_FAILURE;
-       return status;
+
+       return out[0];
 }
 
-static acpi_status sci_write(struct toshiba_acpi_dev *dev, u32 reg,
-                            u32 in1, u32 *result)
+static u32 sci_write(struct toshiba_acpi_dev *dev, u32 reg, u32 in1)
 {
-       u32 in[HCI_WORDS] = { SCI_SET, reg, in1, 0, 0, 0 };
-       u32 out[HCI_WORDS];
-       acpi_status status = hci_raw(dev, in, out);
-       *result = (ACPI_SUCCESS(status)) ? out[0] : HCI_FAILURE;
-       return status;
+       u32 in[TCI_WORDS] = { SCI_SET, reg, in1, 0, 0, 0 };
+       u32 out[TCI_WORDS];
+       acpi_status status = tci_raw(dev, in, out);
+
+       return ACPI_SUCCESS(status) ? out[0] : TOS_FAILURE;
 }
 
 /* Illumination support */
 static int toshiba_illumination_available(struct toshiba_acpi_dev *dev)
 {
-       u32 in[HCI_WORDS] = { SCI_GET, SCI_ILLUMINATION, 0, 0, 0, 0 };
-       u32 out[HCI_WORDS];
+       u32 in[TCI_WORDS] = { SCI_GET, SCI_ILLUMINATION, 0, 0, 0, 0 };
+       u32 out[TCI_WORDS];
        acpi_status status;
 
        if (!sci_open(dev))
                return 0;
 
-       status = hci_raw(dev, in, out);
+       status = tci_raw(dev, in, out);
        sci_close(dev);
-       if (ACPI_FAILURE(status) || out[0] == HCI_FAILURE) {
+       if (ACPI_FAILURE(status) || out[0] == TOS_FAILURE) {
                pr_err("ACPI call to query Illumination support failed\n");
                return 0;
-       } else if (out[0] == HCI_NOT_SUPPORTED || out[1] != 1) {
+       } else if (out[0] == TOS_NOT_SUPPORTED) {
                pr_info("Illumination device not available\n");
                return 0;
        }
@@ -445,7 +460,6 @@ static void toshiba_illumination_set(struct led_classdev *cdev,
        struct toshiba_acpi_dev *dev = container_of(cdev,
                        struct toshiba_acpi_dev, led_dev);
        u32 state, result;
-       acpi_status status;
 
        /* First request : initialize communication. */
        if (!sci_open(dev))
@@ -453,12 +467,12 @@ static void toshiba_illumination_set(struct led_classdev *cdev,
 
        /* Switch the illumination on/off */
        state = brightness ? 1 : 0;
-       status = sci_write(dev, SCI_ILLUMINATION, state, &result);
+       result = sci_write(dev, SCI_ILLUMINATION, state);
        sci_close(dev);
-       if (ACPI_FAILURE(status)) {
+       if (result == TOS_FAILURE) {
                pr_err("ACPI call for illumination failed\n");
                return;
-       } else if (result == HCI_NOT_SUPPORTED) {
+       } else if (result == TOS_NOT_SUPPORTED) {
                pr_info("Illumination not supported\n");
                return;
        }
@@ -469,19 +483,18 @@ static enum led_brightness toshiba_illumination_get(struct led_classdev *cdev)
        struct toshiba_acpi_dev *dev = container_of(cdev,
                        struct toshiba_acpi_dev, led_dev);
        u32 state, result;
-       acpi_status status;
 
        /* First request : initialize communication. */
        if (!sci_open(dev))
                return LED_OFF;
 
        /* Check the illumination */
-       status = sci_read(dev, SCI_ILLUMINATION, &state, &result);
+       result = sci_read(dev, SCI_ILLUMINATION, &state);
        sci_close(dev);
-       if (ACPI_FAILURE(status) || result == SCI_INPUT_DATA_ERROR) {
+       if (result == TOS_FAILURE || result == TOS_INPUT_DATA_ERROR) {
                pr_err("ACPI call for illumination failed\n");
                return LED_OFF;
-       } else if (result == HCI_NOT_SUPPORTED) {
+       } else if (result == TOS_NOT_SUPPORTED) {
                pr_info("Illumination not supported\n");
                return LED_OFF;
        }
@@ -490,20 +503,55 @@ static enum led_brightness toshiba_illumination_get(struct led_classdev *cdev)
 }
 
 /* KBD Illumination */
+static int toshiba_kbd_illum_available(struct toshiba_acpi_dev *dev)
+{
+       u32 in[TCI_WORDS] = { SCI_GET, SCI_KBD_ILLUM_STATUS, 0, 0, 0, 0 };
+       u32 out[TCI_WORDS];
+       acpi_status status;
+
+       if (!sci_open(dev))
+               return 0;
+
+       status = tci_raw(dev, in, out);
+       sci_close(dev);
+       if (ACPI_FAILURE(status) || out[0] == TOS_INPUT_DATA_ERROR) {
+               pr_err("ACPI call to query kbd illumination support failed\n");
+               return 0;
+       } else if (out[0] == TOS_NOT_SUPPORTED) {
+               pr_info("Keyboard illumination not available\n");
+               return 0;
+       }
+
+       /* Check for keyboard backlight timeout max value,
+        * previous kbd backlight implementation set this to
+        * 0x3c0003, and now the new implementation set this
+        * to 0x3c001a, use this to distinguish between them
+        */
+       if (out[3] == SCI_KBD_TIME_MAX)
+               dev->kbd_type = 2;
+       else
+               dev->kbd_type = 1;
+       /* Get the current keyboard backlight mode */
+       dev->kbd_mode = out[2] & SCI_KBD_MODE_MASK;
+       /* Get the current time (1-60 seconds) */
+       dev->kbd_time = out[2] >> HCI_MISC_SHIFT;
+
+       return 1;
+}
+
 static int toshiba_kbd_illum_status_set(struct toshiba_acpi_dev *dev, u32 time)
 {
        u32 result;
-       acpi_status status;
 
        if (!sci_open(dev))
                return -EIO;
 
-       status = sci_write(dev, SCI_KBD_ILLUM_STATUS, time, &result);
+       result = sci_write(dev, SCI_KBD_ILLUM_STATUS, time);
        sci_close(dev);
-       if (ACPI_FAILURE(status) || result == SCI_INPUT_DATA_ERROR) {
+       if (result == TOS_FAILURE || result == TOS_INPUT_DATA_ERROR) {
                pr_err("ACPI call to set KBD backlight status failed\n");
                return -EIO;
-       } else if (result == HCI_NOT_SUPPORTED) {
+       } else if (result == TOS_NOT_SUPPORTED) {
                pr_info("Keyboard backlight status not supported\n");
                return -ENODEV;
        }
@@ -514,17 +562,16 @@ static int toshiba_kbd_illum_status_set(struct toshiba_acpi_dev *dev, u32 time)
 static int toshiba_kbd_illum_status_get(struct toshiba_acpi_dev *dev, u32 *time)
 {
        u32 result;
-       acpi_status status;
 
        if (!sci_open(dev))
                return -EIO;
 
-       status = sci_read(dev, SCI_KBD_ILLUM_STATUS, time, &result);
+       result = sci_read(dev, SCI_KBD_ILLUM_STATUS, time);
        sci_close(dev);
-       if (ACPI_FAILURE(status) || result == SCI_INPUT_DATA_ERROR) {
+       if (result == TOS_FAILURE || result == TOS_INPUT_DATA_ERROR) {
                pr_err("ACPI call to get KBD backlight status failed\n");
                return -EIO;
-       } else if (result == HCI_NOT_SUPPORTED) {
+       } else if (result == TOS_NOT_SUPPORTED) {
                pr_info("Keyboard backlight status not supported\n");
                return -ENODEV;
        }
@@ -537,14 +584,13 @@ static enum led_brightness toshiba_kbd_backlight_get(struct led_classdev *cdev)
        struct toshiba_acpi_dev *dev = container_of(cdev,
                        struct toshiba_acpi_dev, kbd_led);
        u32 state, result;
-       acpi_status status;
 
        /* Check the keyboard backlight state */
-       status = hci_read1(dev, HCI_KBD_ILLUMINATION, &state, &result);
-       if (ACPI_FAILURE(status) || result == SCI_INPUT_DATA_ERROR) {
+       result = hci_read1(dev, HCI_KBD_ILLUMINATION, &state);
+       if (result == TOS_FAILURE || result == TOS_INPUT_DATA_ERROR) {
                pr_err("ACPI call to get the keyboard backlight failed\n");
                return LED_OFF;
-       } else if (result == HCI_NOT_SUPPORTED) {
+       } else if (result == TOS_NOT_SUPPORTED) {
                pr_info("Keyboard backlight not supported\n");
                return LED_OFF;
        }
@@ -558,15 +604,14 @@ static void toshiba_kbd_backlight_set(struct led_classdev *cdev,
        struct toshiba_acpi_dev *dev = container_of(cdev,
                        struct toshiba_acpi_dev, kbd_led);
        u32 state, result;
-       acpi_status status;
 
        /* Set the keyboard backlight state */
        state = brightness ? 1 : 0;
-       status = hci_write1(dev, HCI_KBD_ILLUMINATION, state, &result);
-       if (ACPI_FAILURE(status) || result == SCI_INPUT_DATA_ERROR) {
+       result = hci_write1(dev, HCI_KBD_ILLUMINATION, state);
+       if (result == TOS_FAILURE || result == TOS_INPUT_DATA_ERROR) {
                pr_err("ACPI call to set KBD Illumination mode failed\n");
                return;
-       } else if (result == HCI_NOT_SUPPORTED) {
+       } else if (result == TOS_NOT_SUPPORTED) {
                pr_info("Keyboard backlight not supported\n");
                return;
        }
@@ -576,17 +621,16 @@ static void toshiba_kbd_backlight_set(struct led_classdev *cdev,
 static int toshiba_touchpad_set(struct toshiba_acpi_dev *dev, u32 state)
 {
        u32 result;
-       acpi_status status;
 
        if (!sci_open(dev))
                return -EIO;
 
-       status = sci_write(dev, SCI_TOUCHPAD, state, &result);
+       result = sci_write(dev, SCI_TOUCHPAD, state);
        sci_close(dev);
-       if (ACPI_FAILURE(status)) {
+       if (result == TOS_FAILURE) {
                pr_err("ACPI call to set the touchpad failed\n");
                return -EIO;
-       } else if (result == HCI_NOT_SUPPORTED) {
+       } else if (result == TOS_NOT_SUPPORTED) {
                return -ENODEV;
        }
 
@@ -596,17 +640,16 @@ static int toshiba_touchpad_set(struct toshiba_acpi_dev *dev, u32 state)
 static int toshiba_touchpad_get(struct toshiba_acpi_dev *dev, u32 *state)
 {
        u32 result;
-       acpi_status status;
 
        if (!sci_open(dev))
                return -EIO;
 
-       status = sci_read(dev, SCI_TOUCHPAD, state, &result);
+       result = sci_read(dev, SCI_TOUCHPAD, state);
        sci_close(dev);
-       if (ACPI_FAILURE(status)) {
+       if (result == TOS_FAILURE) {
                pr_err("ACPI call to query the touchpad failed\n");
                return -EIO;
-       } else if (result == HCI_NOT_SUPPORTED) {
+       } else if (result == TOS_NOT_SUPPORTED) {
                return -ENODEV;
        }
 
@@ -617,11 +660,11 @@ static int toshiba_touchpad_get(struct toshiba_acpi_dev *dev, u32 *state)
 static int toshiba_eco_mode_available(struct toshiba_acpi_dev *dev)
 {
        acpi_status status;
-       u32 in[HCI_WORDS] = { HCI_GET, HCI_ECO_MODE, 0, 1, 0, 0 };
-       u32 out[HCI_WORDS];
+       u32 in[TCI_WORDS] = { HCI_GET, HCI_ECO_MODE, 0, 1, 0, 0 };
+       u32 out[TCI_WORDS];
 
-       status = hci_raw(dev, in, out);
-       if (ACPI_FAILURE(status) || out[0] == SCI_INPUT_DATA_ERROR) {
+       status = tci_raw(dev, in, out);
+       if (ACPI_FAILURE(status) || out[0] == TOS_INPUT_DATA_ERROR) {
                pr_info("ACPI call to get ECO led failed\n");
                return 0;
        }
@@ -633,12 +676,12 @@ static enum led_brightness toshiba_eco_mode_get_status(struct led_classdev *cdev
 {
        struct toshiba_acpi_dev *dev = container_of(cdev,
                        struct toshiba_acpi_dev, eco_led);
-       u32 in[HCI_WORDS] = { HCI_GET, HCI_ECO_MODE, 0, 1, 0, 0 };
-       u32 out[HCI_WORDS];
+       u32 in[TCI_WORDS] = { HCI_GET, HCI_ECO_MODE, 0, 1, 0, 0 };
+       u32 out[TCI_WORDS];
        acpi_status status;
 
-       status = hci_raw(dev, in, out);
-       if (ACPI_FAILURE(status) || out[0] == SCI_INPUT_DATA_ERROR) {
+       status = tci_raw(dev, in, out);
+       if (ACPI_FAILURE(status) || out[0] == TOS_INPUT_DATA_ERROR) {
                pr_err("ACPI call to get ECO led failed\n");
                return LED_OFF;
        }
@@ -651,14 +694,14 @@ static void toshiba_eco_mode_set_status(struct led_classdev *cdev,
 {
        struct toshiba_acpi_dev *dev = container_of(cdev,
                        struct toshiba_acpi_dev, eco_led);
-       u32 in[HCI_WORDS] = { HCI_SET, HCI_ECO_MODE, 0, 1, 0, 0 };
-       u32 out[HCI_WORDS];
+       u32 in[TCI_WORDS] = { HCI_SET, HCI_ECO_MODE, 0, 1, 0, 0 };
+       u32 out[TCI_WORDS];
        acpi_status status;
 
        /* Switch the Eco Mode led on/off */
        in[2] = (brightness) ? 1 : 0;
-       status = hci_raw(dev, in, out);
-       if (ACPI_FAILURE(status) || out[0] == SCI_INPUT_DATA_ERROR) {
+       status = tci_raw(dev, in, out);
+       if (ACPI_FAILURE(status) || out[0] == TOS_INPUT_DATA_ERROR) {
                pr_err("ACPI call to set ECO led failed\n");
                return;
        }
@@ -667,22 +710,22 @@ static void toshiba_eco_mode_set_status(struct led_classdev *cdev,
 /* Accelerometer support */
 static int toshiba_accelerometer_supported(struct toshiba_acpi_dev *dev)
 {
-       u32 in[HCI_WORDS] = { HCI_GET, HCI_ACCELEROMETER2, 0, 0, 0, 0 };
-       u32 out[HCI_WORDS];
+       u32 in[TCI_WORDS] = { HCI_GET, HCI_ACCELEROMETER2, 0, 0, 0, 0 };
+       u32 out[TCI_WORDS];
        acpi_status status;
 
        /* Check if the accelerometer call exists,
         * this call also serves as initialization
         */
-       status = hci_raw(dev, in, out);
-       if (ACPI_FAILURE(status) || out[0] == SCI_INPUT_DATA_ERROR) {
+       status = tci_raw(dev, in, out);
+       if (ACPI_FAILURE(status) || out[0] == TOS_INPUT_DATA_ERROR) {
                pr_err("ACPI call to query the accelerometer failed\n");
                return -EIO;
-       } else if (out[0] == HCI_DATA_NOT_AVAILABLE ||
-                  out[0] == HCI_NOT_INITIALIZED) {
+       } else if (out[0] == TOS_DATA_NOT_AVAILABLE ||
+                  out[0] == TOS_NOT_INITIALIZED) {
                pr_err("Accelerometer not initialized\n");
                return -EIO;
-       } else if (out[0] == HCI_NOT_SUPPORTED) {
+       } else if (out[0] == TOS_NOT_SUPPORTED) {
                pr_info("Accelerometer not supported\n");
                return -ENODEV;
        }
@@ -693,13 +736,13 @@ static int toshiba_accelerometer_supported(struct toshiba_acpi_dev *dev)
 static int toshiba_accelerometer_get(struct toshiba_acpi_dev *dev,
                                      u32 *xy, u32 *z)
 {
-       u32 in[HCI_WORDS] = { HCI_GET, HCI_ACCELEROMETER, 0, 1, 0, 0 };
-       u32 out[HCI_WORDS];
+       u32 in[TCI_WORDS] = { HCI_GET, HCI_ACCELEROMETER, 0, 1, 0, 0 };
+       u32 out[TCI_WORDS];
        acpi_status status;
 
        /* Check the Accelerometer status */
-       status = hci_raw(dev, in, out);
-       if (ACPI_FAILURE(status) || out[0] == SCI_INPUT_DATA_ERROR) {
+       status = tci_raw(dev, in, out);
+       if (ACPI_FAILURE(status) || out[0] == TOS_INPUT_DATA_ERROR) {
                pr_err("ACPI call to query the accelerometer failed\n");
                return -EIO;
        }
@@ -719,8 +762,8 @@ static u32 hci_get_bt_present(struct toshiba_acpi_dev *dev, bool *present)
 
        value = 0;
        value2 = 0;
-       hci_read2(dev, HCI_WIRELESS, &value, &value2, &hci_result);
-       if (hci_result == HCI_SUCCESS)
+       hci_result = hci_read2(dev, HCI_WIRELESS, &value, &value2);
+       if (hci_result == TOS_SUCCESS)
                *present = (value & HCI_WIRELESS_BT_PRESENT) ? true : false;
 
        return hci_result;
@@ -733,7 +776,7 @@ static u32 hci_get_radio_state(struct toshiba_acpi_dev *dev, bool *radio_state)
 
        value = 0;
        value2 = 0x0001;
-       hci_read2(dev, HCI_WIRELESS, &value, &value2, &hci_result);
+       hci_result = hci_read2(dev, HCI_WIRELESS, &value, &value2);
 
        *radio_state = value & HCI_WIRELESS_KILL_SWITCH;
        return hci_result;
@@ -750,7 +793,7 @@ static int bt_rfkill_set_block(void *data, bool blocked)
        value = (blocked == false);
 
        mutex_lock(&dev->mutex);
-       if (hci_get_radio_state(dev, &radio_state) != HCI_SUCCESS) {
+       if (hci_get_radio_state(dev, &radio_state) != TOS_SUCCESS) {
                err = -EIO;
                goto out;
        }
@@ -760,10 +803,10 @@ static int bt_rfkill_set_block(void *data, bool blocked)
                goto out;
        }
 
-       hci_write2(dev, HCI_WIRELESS, value, HCI_WIRELESS_BT_POWER, &result1);
-       hci_write2(dev, HCI_WIRELESS, value, HCI_WIRELESS_BT_ATTACH, &result2);
+       result1 = hci_write2(dev, HCI_WIRELESS, value, HCI_WIRELESS_BT_POWER);
+       result2 = hci_write2(dev, HCI_WIRELESS, value, HCI_WIRELESS_BT_ATTACH);
 
-       if (result1 != HCI_SUCCESS || result2 != HCI_SUCCESS)
+       if (result1 != TOS_SUCCESS || result2 != TOS_SUCCESS)
                err = -EIO;
        else
                err = 0;
@@ -782,7 +825,7 @@ static void bt_rfkill_poll(struct rfkill *rfkill, void *data)
        mutex_lock(&dev->mutex);
 
        hci_result = hci_get_radio_state(dev, &value);
-       if (hci_result != HCI_SUCCESS) {
+       if (hci_result != TOS_SUCCESS) {
                /* Can't do anything useful */
                mutex_unlock(&dev->mutex);
                return;
@@ -806,9 +849,9 @@ static int get_tr_backlight_status(struct toshiba_acpi_dev *dev, bool *enabled)
        u32 hci_result;
        u32 status;
 
-       hci_read1(dev, HCI_TR_BACKLIGHT, &status, &hci_result);
+       hci_result = hci_read1(dev, HCI_TR_BACKLIGHT, &status);
        *enabled = !status;
-       return hci_result == HCI_SUCCESS ? 0 : -EIO;
+       return hci_result == TOS_SUCCESS ? 0 : -EIO;
 }
 
 static int set_tr_backlight_status(struct toshiba_acpi_dev *dev, bool enable)
@@ -816,8 +859,8 @@ static int set_tr_backlight_status(struct toshiba_acpi_dev *dev, bool enable)
        u32 hci_result;
        u32 value = !enable;
 
-       hci_write1(dev, HCI_TR_BACKLIGHT, value, &hci_result);
-       return hci_result == HCI_SUCCESS ? 0 : -EIO;
+       hci_result = hci_write1(dev, HCI_TR_BACKLIGHT, value);
+       return hci_result == TOS_SUCCESS ? 0 : -EIO;
 }
 
 static struct proc_dir_entry *toshiba_proc_dir /*= 0*/ ;
@@ -838,8 +881,8 @@ static int __get_lcd_brightness(struct toshiba_acpi_dev *dev)
                brightness++;
        }
 
-       hci_read1(dev, HCI_LCD_BRIGHTNESS, &value, &hci_result);
-       if (hci_result == HCI_SUCCESS)
+       hci_result = hci_read1(dev, HCI_LCD_BRIGHTNESS, &value);
+       if (hci_result == TOS_SUCCESS)
                return brightness + (value >> HCI_LCD_BRIGHTNESS_SHIFT);
 
        return -EIO;
@@ -879,8 +922,8 @@ static int lcd_proc_open(struct inode *inode, struct file *file)
 
 static int set_lcd_brightness(struct toshiba_acpi_dev *dev, int value)
 {
-       u32 in[HCI_WORDS] = { HCI_SET, HCI_LCD_BRIGHTNESS, 0, 0, 0, 0 };
-       u32 out[HCI_WORDS];
+       u32 in[TCI_WORDS] = { HCI_SET, HCI_LCD_BRIGHTNESS, 0, 0, 0, 0 };
+       u32 out[TCI_WORDS];
        acpi_status status;
 
        if (dev->tr_backlight_supported) {
@@ -893,19 +936,19 @@ static int set_lcd_brightness(struct toshiba_acpi_dev *dev, int value)
        }
 
        in[2] = value << HCI_LCD_BRIGHTNESS_SHIFT;
-       status = hci_raw(dev, in, out);
-       if (ACPI_FAILURE(status) || out[0] == HCI_FAILURE) {
+       status = tci_raw(dev, in, out);
+       if (ACPI_FAILURE(status) || out[0] == TOS_FAILURE) {
                pr_err("ACPI call to set brightness failed");
                return -EIO;
        }
        /* Extra check for "incomplete" backlight method, where the AML code
-        * doesn't check for HCI_SET or HCI_GET and returns HCI_SUCCESS,
+        * doesn't check for HCI_SET or HCI_GET and returns TOS_SUCCESS,
         * the actual brightness, and in some cases the max brightness.
         */
        if (out[2] > 0  || out[3] == 0xE000)
                return -ENODEV;
 
-       return out[0] == HCI_SUCCESS ? 0 : -EIO;
+       return out[0] == TOS_SUCCESS ? 0 : -EIO;
 }
 
 static int set_lcd_status(struct backlight_device *bd)
@@ -953,8 +996,8 @@ static int get_video_status(struct toshiba_acpi_dev *dev, u32 *status)
 {
        u32 hci_result;
 
-       hci_read1(dev, HCI_VIDEO_OUT, status, &hci_result);
-       return hci_result == HCI_SUCCESS ? 0 : -EIO;
+       hci_result = hci_read1(dev, HCI_VIDEO_OUT, status);
+       return hci_result == TOS_SUCCESS ? 0 : -EIO;
 }
 
 static int video_proc_show(struct seq_file *m, void *v)
@@ -1057,8 +1100,8 @@ static int get_fan_status(struct toshiba_acpi_dev *dev, u32 *status)
 {
        u32 hci_result;
 
-       hci_read1(dev, HCI_FAN, status, &hci_result);
-       return hci_result == HCI_SUCCESS ? 0 : -EIO;
+       hci_result = hci_read1(dev, HCI_FAN, status);
+       return hci_result == TOS_SUCCESS ? 0 : -EIO;
 }
 
 static int fan_proc_show(struct seq_file *m, void *v)
@@ -1097,8 +1140,8 @@ static ssize_t fan_proc_write(struct file *file, const char __user *buf,
 
        if (sscanf(cmd, " force_on : %i", &value) == 1 &&
            value >= 0 && value <= 1) {
-               hci_write1(dev, HCI_FAN, value, &hci_result);
-               if (hci_result != HCI_SUCCESS)
+               hci_result = hci_write1(dev, HCI_FAN, value);
+               if (hci_result != TOS_SUCCESS)
                        return -EIO;
                else
                        dev->force_fan = value;
@@ -1125,17 +1168,17 @@ static int keys_proc_show(struct seq_file *m, void *v)
        u32 value;
 
        if (!dev->key_event_valid && dev->system_event_supported) {
-               hci_read1(dev, HCI_SYSTEM_EVENT, &value, &hci_result);
-               if (hci_result == HCI_SUCCESS) {
+               hci_result = hci_read1(dev, HCI_SYSTEM_EVENT, &value);
+               if (hci_result == TOS_SUCCESS) {
                        dev->key_event_valid = 1;
                        dev->last_key_event = value;
-               } else if (hci_result == HCI_EMPTY) {
+               } else if (hci_result == TOS_FIFO_EMPTY) {
                        /* better luck next time */
-               } else if (hci_result == HCI_NOT_SUPPORTED) {
+               } else if (hci_result == TOS_NOT_SUPPORTED) {
                        /* This is a workaround for an unresolved issue on
                         * some machines where system events sporadically
                         * become disabled. */
-                       hci_write1(dev, HCI_SYSTEM_EVENT, 1, &hci_result);
+                       hci_result = hci_write1(dev, HCI_SYSTEM_EVENT, 1);
                        pr_notice("Re-enabled hotkeys\n");
                } else {
                        pr_err("Error reading hotkey status\n");
@@ -1249,6 +1292,62 @@ static const struct backlight_ops toshiba_backlight_data = {
 /*
  * Sysfs files
  */
+static ssize_t toshiba_kbd_bl_mode_store(struct device *dev,
+                                        struct device_attribute *attr,
+                                        const char *buf, size_t count);
+static ssize_t toshiba_kbd_bl_mode_show(struct device *dev,
+                                       struct device_attribute *attr,
+                                       char *buf);
+static ssize_t toshiba_kbd_type_show(struct device *dev,
+                                    struct device_attribute *attr,
+                                    char *buf);
+static ssize_t toshiba_available_kbd_modes_show(struct device *dev,
+                                       struct device_attribute *attr,
+                                       char *buf);
+static ssize_t toshiba_kbd_bl_timeout_store(struct device *dev,
+                                           struct device_attribute *attr,
+                                           const char *buf, size_t count);
+static ssize_t toshiba_kbd_bl_timeout_show(struct device *dev,
+                                          struct device_attribute *attr,
+                                          char *buf);
+static ssize_t toshiba_touchpad_store(struct device *dev,
+                                     struct device_attribute *attr,
+                                     const char *buf, size_t count);
+static ssize_t toshiba_touchpad_show(struct device *dev,
+                                    struct device_attribute *attr,
+                                    char *buf);
+static ssize_t toshiba_position_show(struct device *dev,
+                                    struct device_attribute *attr,
+                                    char *buf);
+
+static DEVICE_ATTR(kbd_backlight_mode, S_IRUGO | S_IWUSR,
+                  toshiba_kbd_bl_mode_show, toshiba_kbd_bl_mode_store);
+static DEVICE_ATTR(kbd_type, S_IRUGO, toshiba_kbd_type_show, NULL);
+static DEVICE_ATTR(available_kbd_modes, S_IRUGO,
+                  toshiba_available_kbd_modes_show, NULL);
+static DEVICE_ATTR(kbd_backlight_timeout, S_IRUGO | S_IWUSR,
+                  toshiba_kbd_bl_timeout_show, toshiba_kbd_bl_timeout_store);
+static DEVICE_ATTR(touchpad, S_IRUGO | S_IWUSR,
+                  toshiba_touchpad_show, toshiba_touchpad_store);
+static DEVICE_ATTR(position, S_IRUGO, toshiba_position_show, NULL);
+
+static struct attribute *toshiba_attributes[] = {
+       &dev_attr_kbd_backlight_mode.attr,
+       &dev_attr_kbd_type.attr,
+       &dev_attr_available_kbd_modes.attr,
+       &dev_attr_kbd_backlight_timeout.attr,
+       &dev_attr_touchpad.attr,
+       &dev_attr_position.attr,
+       NULL,
+};
+
+static umode_t toshiba_sysfs_is_visible(struct kobject *,
+                                       struct attribute *, int);
+
+static struct attribute_group toshiba_attr_group = {
+       .is_visible = toshiba_sysfs_is_visible,
+       .attrs = toshiba_attributes,
+};
 
 static ssize_t toshiba_kbd_bl_mode_store(struct device *dev,
                                         struct device_attribute *attr,
@@ -1263,20 +1362,50 @@ static ssize_t toshiba_kbd_bl_mode_store(struct device *dev,
        ret = kstrtoint(buf, 0, &mode);
        if (ret)
                return ret;
-       if (mode != SCI_KBD_MODE_FNZ && mode != SCI_KBD_MODE_AUTO)
-               return -EINVAL;
+
+       /* Check for supported modes depending on keyboard backlight type */
+       if (toshiba->kbd_type == 1) {
+               /* Type 1 supports SCI_KBD_MODE_FNZ and SCI_KBD_MODE_AUTO */
+               if (mode != SCI_KBD_MODE_FNZ && mode != SCI_KBD_MODE_AUTO)
+                       return -EINVAL;
+       } else if (toshiba->kbd_type == 2) {
+               /* Type 2 doesn't support SCI_KBD_MODE_FNZ */
+               if (mode != SCI_KBD_MODE_AUTO && mode != SCI_KBD_MODE_ON &&
+                   mode != SCI_KBD_MODE_OFF)
+                       return -EINVAL;
+       }
 
        /* Set the Keyboard Backlight Mode where:
-        * Mode - Auto (2) | FN-Z (1)
         *      Auto - KBD backlight turns off automatically in given time
         *      FN-Z - KBD backlight "toggles" when hotkey pressed
+        *      ON   - KBD backlight is always on
+        *      OFF  - KBD backlight is always off
         */
+
+       /* Only make a change if the actual mode has changed */
        if (toshiba->kbd_mode != mode) {
+               /* Shift the time to "base time" (0x3c0000 == 60 seconds) */
                time = toshiba->kbd_time << HCI_MISC_SHIFT;
-               time = time + toshiba->kbd_mode;
+
+               /* OR the "base time" to the actual method format */
+               if (toshiba->kbd_type == 1) {
+                       /* Type 1 requires the current mode */
+                       time |= toshiba->kbd_mode;
+               } else if (toshiba->kbd_type == 2) {
+                       /* Type 2 requires the desired mode */
+                       time |= mode;
+               }
+
                ret = toshiba_kbd_illum_status_set(toshiba, time);
                if (ret)
                        return ret;
+
+               /* Update sysfs entries on successful mode change*/
+               ret = sysfs_update_group(&toshiba->acpi_dev->dev.kobj,
+                                        &toshiba_attr_group);
+               if (ret)
+                       return ret;
+
                toshiba->kbd_mode = mode;
        }
 
@@ -1293,7 +1422,30 @@ static ssize_t toshiba_kbd_bl_mode_show(struct device *dev,
        if (toshiba_kbd_illum_status_get(toshiba, &time) < 0)
                return -EIO;
 
-       return sprintf(buf, "%i\n", time & 0x07);
+       return sprintf(buf, "%i\n", time & SCI_KBD_MODE_MASK);
+}
+
+static ssize_t toshiba_kbd_type_show(struct device *dev,
+                                    struct device_attribute *attr,
+                                    char *buf)
+{
+       struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
+
+       return sprintf(buf, "%d\n", toshiba->kbd_type);
+}
+
+static ssize_t toshiba_available_kbd_modes_show(struct device *dev,
+                                               struct device_attribute *attr,
+                                               char *buf)
+{
+       struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
+
+       if (toshiba->kbd_type == 1)
+               return sprintf(buf, "%x %x\n",
+                              SCI_KBD_MODE_FNZ, SCI_KBD_MODE_AUTO);
+
+       return sprintf(buf, "%x %x %x\n",
+                      SCI_KBD_MODE_AUTO, SCI_KBD_MODE_ON, SCI_KBD_MODE_OFF);
 }
 
 static ssize_t toshiba_kbd_bl_timeout_store(struct device *dev,
@@ -1301,18 +1453,38 @@ static ssize_t toshiba_kbd_bl_timeout_store(struct device *dev,
                                            const char *buf, size_t count)
 {
        struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
-       int time = -1;
+       int time;
+       int ret;
 
-       if (sscanf(buf, "%i", &time) != 1 && (time < 0 || time > 60))
-               return -EINVAL;
+       ret = kstrtoint(buf, 0, &time);
+       if (ret)
+               return ret;
 
-       /* Set the Keyboard Backlight Timeout: 0-60 seconds */
-       if (time != -1 && toshiba->kbd_time != time) {
+       /* Check for supported values depending on kbd_type */
+       if (toshiba->kbd_type == 1) {
+               if (time < 0 || time > 60)
+                       return -EINVAL;
+       } else if (toshiba->kbd_type == 2) {
+               if (time < 1 || time > 60)
+                       return -EINVAL;
+       }
+
+       /* Set the Keyboard Backlight Timeout */
+
+       /* Only make a change if the actual timeout has changed */
+       if (toshiba->kbd_time != time) {
+               /* Shift the time to "base time" (0x3c0000 == 60 seconds) */
                time = time << HCI_MISC_SHIFT;
-               time = (toshiba->kbd_mode == SCI_KBD_MODE_AUTO) ?
-                                                       time + 1 : time + 2;
-               if (toshiba_kbd_illum_status_set(toshiba, time) < 0)
-                       return -EIO;
+               /* OR the "base time" to the actual method format */
+               if (toshiba->kbd_type == 1)
+                       time |= SCI_KBD_MODE_FNZ;
+               else if (toshiba->kbd_type == 2)
+                       time |= SCI_KBD_MODE_AUTO;
+
+               ret = toshiba_kbd_illum_status_set(toshiba, time);
+               if (ret)
+                       return ret;
+
                toshiba->kbd_time = time >> HCI_MISC_SHIFT;
        }
 
@@ -1338,12 +1510,18 @@ static ssize_t toshiba_touchpad_store(struct device *dev,
 {
        struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
        int state;
+       int ret;
 
        /* Set the TouchPad on/off, 0 - Disable | 1 - Enable */
-       if (sscanf(buf, "%i", &state) == 1 && (state == 0 || state == 1)) {
-               if (toshiba_touchpad_set(toshiba, state) < 0)
-                       return -EIO;
-       }
+       ret = kstrtoint(buf, 0, &state);
+       if (ret)
+               return ret;
+       if (state != 0 && state != 1)
+               return -EINVAL;
+
+       ret = toshiba_touchpad_set(toshiba, state);
+       if (ret)
+               return ret;
 
        return count;
 }
@@ -1383,22 +1561,6 @@ static ssize_t toshiba_position_show(struct device *dev,
        return sprintf(buf, "%d %d %d\n", x, y, z);
 }
 
-static DEVICE_ATTR(kbd_backlight_mode, S_IRUGO | S_IWUSR,
-                  toshiba_kbd_bl_mode_show, toshiba_kbd_bl_mode_store);
-static DEVICE_ATTR(kbd_backlight_timeout, S_IRUGO | S_IWUSR,
-                  toshiba_kbd_bl_timeout_show, toshiba_kbd_bl_timeout_store);
-static DEVICE_ATTR(touchpad, S_IRUGO | S_IWUSR,
-                  toshiba_touchpad_show, toshiba_touchpad_store);
-static DEVICE_ATTR(position, S_IRUGO, toshiba_position_show, NULL);
-
-static struct attribute *toshiba_attributes[] = {
-       &dev_attr_kbd_backlight_mode.attr,
-       &dev_attr_kbd_backlight_timeout.attr,
-       &dev_attr_touchpad.attr,
-       &dev_attr_position.attr,
-       NULL,
-};
-
 static umode_t toshiba_sysfs_is_visible(struct kobject *kobj,
                                        struct attribute *attr, int idx)
 {
@@ -1418,11 +1580,6 @@ static umode_t toshiba_sysfs_is_visible(struct kobject *kobj,
        return exists ? attr->mode : 0;
 }
 
-static struct attribute_group toshiba_attr_group = {
-       .is_visible = toshiba_sysfs_is_visible,
-       .attrs = toshiba_attributes,
-};
-
 static bool toshiba_acpi_i8042_filter(unsigned char data, unsigned char str,
                                      struct serio *port)
 {
@@ -1535,8 +1692,8 @@ static int toshiba_acpi_setup_keyboard(struct toshiba_acpi_dev *dev)
        if (acpi_has_method(dev->acpi_dev->handle, "INFO"))
                dev->info_supported = 1;
        else {
-               hci_write1(dev, HCI_SYSTEM_EVENT, 1, &hci_result);
-               if (hci_result == HCI_SUCCESS)
+               hci_result = hci_write1(dev, HCI_SYSTEM_EVENT, 1);
+               if (hci_result == TOS_SUCCESS)
                        dev->system_event_supported = 1;
        }
 
@@ -1558,7 +1715,7 @@ static int toshiba_acpi_setup_keyboard(struct toshiba_acpi_dev *dev)
                goto err_remove_filter;
        }
 
-       hci_write1(dev, HCI_HOTKEY_EVENT, HCI_HOTKEY_ENABLE, &hci_result);
+       hci_result = hci_write1(dev, HCI_HOTKEY_EVENT, HCI_HOTKEY_ENABLE);
        return 0;
 
  err_remove_filter:
@@ -1716,7 +1873,7 @@ static int toshiba_acpi_add(struct acpi_device *acpi_dev)
                goto error;
 
        /* Register rfkill switch for Bluetooth */
-       if (hci_get_bt_present(dev, &bt_present) == HCI_SUCCESS && bt_present) {
+       if (hci_get_bt_present(dev, &bt_present) == TOS_SUCCESS && bt_present) {
                dev->bt_rfk = rfkill_alloc("Toshiba Bluetooth",
                                           &acpi_dev->dev,
                                           RFKILL_TYPE_BLUETOOTH,
@@ -1754,12 +1911,7 @@ static int toshiba_acpi_add(struct acpi_device *acpi_dev)
                        dev->eco_supported = 1;
        }
 
-       ret = toshiba_kbd_illum_status_get(dev, &dummy);
-       if (!ret) {
-               dev->kbd_time = dummy >> HCI_MISC_SHIFT;
-               dev->kbd_mode = dummy & 0x07;
-       }
-       dev->kbd_illum_supported = !ret;
+       dev->kbd_illum_supported = toshiba_kbd_illum_available(dev);
        /*
         * Only register the LED if KBD illumination is supported
         * and the keyboard backlight operation mode is set to FN-Z
@@ -1824,26 +1976,26 @@ static void toshiba_acpi_notify(struct acpi_device *acpi_dev, u32 event)
                        toshiba_acpi_report_hotkey(dev, scancode);
        } else if (dev->system_event_supported) {
                do {
-                       hci_read1(dev, HCI_SYSTEM_EVENT, &value, &hci_result);
+                       hci_result = hci_read1(dev, HCI_SYSTEM_EVENT, &value);
                        switch (hci_result) {
-                       case HCI_SUCCESS:
+                       case TOS_SUCCESS:
                                toshiba_acpi_report_hotkey(dev, (int)value);
                                break;
-                       case HCI_NOT_SUPPORTED:
+                       case TOS_NOT_SUPPORTED:
                                /*
                                 * This is a workaround for an unresolved
                                 * issue on some machines where system events
                                 * sporadically become disabled.
                                 */
-                               hci_write1(dev, HCI_SYSTEM_EVENT, 1,
-                                          &hci_result);
+                               hci_result =
+                                       hci_write1(dev, HCI_SYSTEM_EVENT, 1);
                                pr_notice("Re-enabled hotkeys\n");
                                /* fall through */
                        default:
                                retries--;
                                break;
                        }
-               } while (retries && hci_result != HCI_EMPTY);
+               } while (retries && hci_result != TOS_FIFO_EMPTY);
        }
 }
 
@@ -1854,7 +2006,7 @@ static int toshiba_acpi_suspend(struct device *device)
        u32 result;
 
        if (dev->hotkey_dev)
-               hci_write1(dev, HCI_HOTKEY_EVENT, HCI_HOTKEY_DISABLE, &result);
+               result = hci_write1(dev, HCI_HOTKEY_EVENT, HCI_HOTKEY_DISABLE);
 
        return 0;
 }
@@ -1871,7 +2023,7 @@ static int toshiba_acpi_resume(struct device *device)
                if (ACPI_FAILURE(status))
                        pr_info("Unable to re-enable hotkeys\n");
 
-               hci_write1(dev, HCI_HOTKEY_EVENT, HCI_HOTKEY_ENABLE, &result);
+               result = hci_write1(dev, HCI_HOTKEY_EVENT, HCI_HOTKEY_ENABLE);
        }
 
        return 0;
index e6c403be09a924b7fe795e973dafb227a089affe..4b6808ff0e5df3517f5e72a9fdd71ed6f05d0a9e 100644 (file)
@@ -346,41 +346,41 @@ static ssize_t resources_store(struct device *dmdev,
        }
 
        buf = skip_spaces(buf);
-       if (!strnicmp(buf, "disable", 7)) {
+       if (!strncasecmp(buf, "disable", 7)) {
                retval = pnp_disable_dev(dev);
                goto done;
        }
-       if (!strnicmp(buf, "activate", 8)) {
+       if (!strncasecmp(buf, "activate", 8)) {
                retval = pnp_activate_dev(dev);
                goto done;
        }
-       if (!strnicmp(buf, "fill", 4)) {
+       if (!strncasecmp(buf, "fill", 4)) {
                if (dev->active)
                        goto done;
                retval = pnp_auto_config_dev(dev);
                goto done;
        }
-       if (!strnicmp(buf, "auto", 4)) {
+       if (!strncasecmp(buf, "auto", 4)) {
                if (dev->active)
                        goto done;
                pnp_init_resources(dev);
                retval = pnp_auto_config_dev(dev);
                goto done;
        }
-       if (!strnicmp(buf, "clear", 5)) {
+       if (!strncasecmp(buf, "clear", 5)) {
                if (dev->active)
                        goto done;
                pnp_init_resources(dev);
                goto done;
        }
-       if (!strnicmp(buf, "get", 3)) {
+       if (!strncasecmp(buf, "get", 3)) {
                mutex_lock(&pnp_res_mutex);
                if (pnp_can_read(dev))
                        dev->protocol->get(dev);
                mutex_unlock(&pnp_res_mutex);
                goto done;
        }
-       if (!strnicmp(buf, "set", 3)) {
+       if (!strncasecmp(buf, "set", 3)) {
                resource_size_t start;
                resource_size_t end;
                unsigned long flags;
@@ -392,31 +392,31 @@ static ssize_t resources_store(struct device *dmdev,
                mutex_lock(&pnp_res_mutex);
                while (1) {
                        buf = skip_spaces(buf);
-                       if (!strnicmp(buf, "io", 2)) {
+                       if (!strncasecmp(buf, "io", 2)) {
                                buf = pnp_get_resource_value(buf + 2,
                                                             IORESOURCE_IO,
                                                             &start, &end,
                                                             &flags);
                                pnp_add_io_resource(dev, start, end, flags);
-                       } else if (!strnicmp(buf, "mem", 3)) {
+                       } else if (!strncasecmp(buf, "mem", 3)) {
                                buf = pnp_get_resource_value(buf + 3,
                                                             IORESOURCE_MEM,
                                                             &start, &end,
                                                             &flags);
                                pnp_add_mem_resource(dev, start, end, flags);
-                       } else if (!strnicmp(buf, "irq", 3)) {
+                       } else if (!strncasecmp(buf, "irq", 3)) {
                                buf = pnp_get_resource_value(buf + 3,
                                                             IORESOURCE_IRQ,
                                                             &start, NULL,
                                                             &flags);
                                pnp_add_irq_resource(dev, start, flags);
-                       } else if (!strnicmp(buf, "dma", 3)) {
+                       } else if (!strncasecmp(buf, "dma", 3)) {
                                buf = pnp_get_resource_value(buf + 3,
                                                             IORESOURCE_DMA,
                                                             &start, NULL,
                                                             &flags);
                                pnp_add_dma_resource(dev, start, flags);
-                       } else if (!strnicmp(buf, "bus", 3)) {
+                       } else if (!strncasecmp(buf, "bus", 3)) {
                                buf = pnp_get_resource_value(buf + 3,
                                                             IORESOURCE_BUS,
                                                             &start, &end,
index 3e51f8d29bfefe34a47224fa967b0dde1e20b2c1..edd707ee7281154ae11995fcfc196c63120a927f 100644 (file)
@@ -20,7 +20,8 @@
 
 static void restart_poweroff_do_poweroff(void)
 {
-       arm_pm_restart(REBOOT_HARD, NULL);
+       reboot_mode = REBOOT_HARD;
+       machine_restart(NULL);
 }
 
 static int restart_poweroff_probe(struct platform_device *pdev)
index 1bea0fc43464f9dcc2ce3f94a87d3628590d6de5..8cd0beebdc3f0464670893eec27222b5d11c8b69 100644 (file)
@@ -288,6 +288,26 @@ config RTC_DRV_MAX77686
          This driver can also be built as a module. If so, the module
          will be called rtc-max77686.
 
+config RTC_DRV_RK808
+       tristate "Rockchip RK808 RTC"
+       depends on MFD_RK808
+       help
+         If you say yes here you will get support for the
+         RTC of RK808 PMIC.
+
+         This driver can also be built as a module. If so, the module
+         will be called rk808-rtc.
+
+config RTC_DRV_MAX77802
+       tristate "Maxim 77802 RTC"
+       depends on MFD_MAX77686
+       help
+         If you say yes here you will get support for the
+         RTC of Maxim MAX77802 PMIC.
+
+         This driver can also be built as a module. If so, the module
+         will be called rtc-max77802.
+
 config RTC_DRV_RS5C372
        tristate "Ricoh R2025S/D, RS5C372A/B, RV5C386, RV5C387A"
        help
@@ -732,6 +752,7 @@ config RTC_DRV_DS1216
 
 config RTC_DRV_DS1286
        tristate "Dallas DS1286"
+       depends on HAS_IOMEM
        help
          If you say yes here you get support for the Dallas DS1286 RTC chips.
 
@@ -743,6 +764,7 @@ config RTC_DRV_DS1302
 
 config RTC_DRV_DS1511
        tristate "Dallas DS1511"
+       depends on HAS_IOMEM
        help
          If you say yes here you get support for the
          Dallas DS1511 timekeeping/watchdog chip.
@@ -752,6 +774,7 @@ config RTC_DRV_DS1511
 
 config RTC_DRV_DS1553
        tristate "Maxim/Dallas DS1553"
+       depends on HAS_IOMEM
        help
          If you say yes here you get support for the
          Maxim/Dallas DS1553 timekeeping chip.
@@ -761,6 +784,7 @@ config RTC_DRV_DS1553
 
 config RTC_DRV_DS1742
        tristate "Maxim/Dallas DS1742/1743"
+       depends on HAS_IOMEM
        help
          If you say yes here you get support for the
          Maxim/Dallas DS1742/1743 timekeeping chip.
@@ -816,6 +840,7 @@ config RTC_DRV_EFI
 
 config RTC_DRV_STK17TA8
        tristate "Simtek STK17TA8"
+       depends on HAS_IOMEM
        help
          If you say yes here you get support for the
          Simtek STK17TA8 timekeeping chip.
@@ -834,6 +859,7 @@ config RTC_DRV_M48T86
 
 config RTC_DRV_M48T35
        tristate "ST M48T35"
+       depends on HAS_IOMEM
        help
          If you say Y here you will get support for the
          ST M48T35 RTC chip.
@@ -843,6 +869,7 @@ config RTC_DRV_M48T35
 
 config RTC_DRV_M48T59
        tristate "ST M48T59/M48T08/M48T02"
+       depends on HAS_IOMEM
        help
          If you say Y here you will get support for the
          ST M48T59 RTC chip and compatible ST M48T08 and M48T02.
@@ -855,6 +882,7 @@ config RTC_DRV_M48T59
 
 config RTC_DRV_MSM6242
        tristate "Oki MSM6242"
+       depends on HAS_IOMEM
        help
          If you say yes here you get support for the Oki MSM6242
          timekeeping chip. It is used in some Amiga models (e.g. A2000).
@@ -864,6 +892,7 @@ config RTC_DRV_MSM6242
 
 config RTC_DRV_BQ4802
        tristate "TI BQ4802"
+       depends on HAS_IOMEM
        help
          If you say Y here you will get support for the TI
          BQ4802 RTC chip.
@@ -873,6 +902,7 @@ config RTC_DRV_BQ4802
 
 config RTC_DRV_RP5C01
        tristate "Ricoh RP5C01"
+       depends on HAS_IOMEM
        help
          If you say yes here you get support for the Ricoh RP5C01
          timekeeping chip. It is used in some Amiga models (e.g. A3000
@@ -1374,6 +1404,7 @@ config RTC_DRV_MOXART
 
 config RTC_DRV_XGENE
        tristate "APM X-Gene RTC"
+       depends on HAS_IOMEM
        help
          If you say yes here you get support for the APM X-Gene SoC real time
          clock.
index 9055b7dd3dc5b93655088bd83f7911ca678e9d50..b188323c096a62421696fbe394a74d061939ddcb 100644 (file)
@@ -85,6 +85,7 @@ obj-$(CONFIG_RTC_DRV_MAX8998) += rtc-max8998.o
 obj-$(CONFIG_RTC_DRV_MAX8997)  += rtc-max8997.o
 obj-$(CONFIG_RTC_DRV_MAX6902)  += rtc-max6902.o
 obj-$(CONFIG_RTC_DRV_MAX77686) += rtc-max77686.o
+obj-$(CONFIG_RTC_DRV_MAX77802)  += rtc-max77802.o
 obj-$(CONFIG_RTC_DRV_MC13XXX)  += rtc-mc13xxx.o
 obj-$(CONFIG_RTC_DRV_MCP795)   += rtc-mcp795.o
 obj-$(CONFIG_RTC_DRV_MSM6242)  += rtc-msm6242.o
@@ -109,6 +110,7 @@ obj-$(CONFIG_RTC_DRV_PUV3)  += rtc-puv3.o
 obj-$(CONFIG_RTC_DRV_PXA)      += rtc-pxa.o
 obj-$(CONFIG_RTC_DRV_R9701)    += rtc-r9701.o
 obj-$(CONFIG_RTC_DRV_RC5T583)  += rtc-rc5t583.o
+obj-$(CONFIG_RTC_DRV_RK808)    += rtc-rk808.o
 obj-$(CONFIG_RTC_DRV_RP5C01)   += rtc-rp5c01.o
 obj-$(CONFIG_RTC_DRV_RS5C313)  += rtc-rs5c313.o
 obj-$(CONFIG_RTC_DRV_RS5C348)  += rtc-rs5c348.o
index c74bf0dc52cc83baa3a66de3f030f27c7a089335..314129e66d6e8fd47280202cacf19f0793848e58 100644 (file)
@@ -2,10 +2,14 @@
  * Driver for TI BQ32000 RTC.
  *
  * Copyright (C) 2009 Semihalf.
+ * Copyright (C) 2014 Pavel Machek <pavel@denx.de>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
+ *
+ * You can get hardware description at
+ * http://www.ti.com/lit/ds/symlink/bq32000.pdf
  */
 
 #include <linux/module.h>
 #define BQ32K_CENT             0x40    /* Century flag */
 #define BQ32K_CENT_EN          0x80    /* Century flag enable bit */
 
+#define BQ32K_CALIBRATION      0x07    /* CAL_CFG1, calibration and control */
+#define BQ32K_TCH2             0x08    /* Trickle charge enable */
+#define BQ32K_CFG2             0x09    /* Trickle charger control */
+
 struct bq32k_regs {
        uint8_t         seconds;
        uint8_t         minutes;
@@ -122,6 +130,57 @@ static const struct rtc_class_ops bq32k_rtc_ops = {
        .set_time       = bq32k_rtc_set_time,
 };
 
+static int trickle_charger_of_init(struct device *dev, struct device_node *node)
+{
+       unsigned char reg;
+       int error;
+       u32 ohms = 0;
+
+       if (of_property_read_u32(node, "trickle-resistor-ohms" , &ohms))
+               return 0;
+
+       switch (ohms) {
+       case 180+940:
+               /*
+                * TCHE[3:0] == 0x05, TCH2 == 1, TCFE == 0 (charging
+                * over diode and 940ohm resistor)
+                */
+
+               if (of_property_read_bool(node, "trickle-diode-disable")) {
+                       dev_err(dev, "diode and resistor mismatch\n");
+                       return -EINVAL;
+               }
+               reg = 0x05;
+               break;
+
+       case 180+20000:
+               /* diode disabled */
+
+               if (!of_property_read_bool(node, "trickle-diode-disable")) {
+                       dev_err(dev, "bq32k: diode and resistor mismatch\n");
+                       return -EINVAL;
+               }
+               reg = 0x25;
+               break;
+
+       default:
+               dev_err(dev, "invalid resistor value (%d)\n", ohms);
+               return -EINVAL;
+       }
+
+       error = bq32k_write(dev, &reg, BQ32K_CFG2, 1);
+       if (error)
+               return error;
+
+       reg = 0x20;
+       error = bq32k_write(dev, &reg, BQ32K_TCH2, 1);
+       if (error)
+               return error;
+
+       dev_info(dev, "Enabled trickle RTC battery charge.\n");
+       return 0;
+}
+
 static int bq32k_probe(struct i2c_client *client,
                                const struct i2c_device_id *id)
 {
@@ -153,6 +212,9 @@ static int bq32k_probe(struct i2c_client *client,
        if (error)
                return error;
 
+       if (client && client->dev.of_node)
+               trickle_charger_of_init(dev, client->dev.of_node);
+
        rtc = devm_rtc_device_register(&client->dev, bq32k_driver.driver.name,
                                                &bq32k_rtc_ops, THIS_MODULE);
        if (IS_ERR(rtc))
index b0e4a3eb33c7dc55d7632fd167cff27e0549b1fb..5b2e76159b419854ca8f69b8c3f99919fbab319f 100644 (file)
@@ -856,7 +856,7 @@ static void __exit cmos_do_remove(struct device *dev)
        cmos->dev = NULL;
 }
 
-#ifdef CONFIG_PM_SLEEP
+#ifdef CONFIG_PM
 
 static int cmos_suspend(struct device *dev)
 {
@@ -907,6 +907,8 @@ static inline int cmos_poweroff(struct device *dev)
        return cmos_suspend(dev);
 }
 
+#ifdef CONFIG_PM_SLEEP
+
 static int cmos_resume(struct device *dev)
 {
        struct cmos_rtc *cmos = dev_get_drvdata(dev);
@@ -954,6 +956,7 @@ static int cmos_resume(struct device *dev)
        return 0;
 }
 
+#endif
 #else
 
 static inline int cmos_poweroff(struct device *dev)
index f03d5ba96db1fe3f5e063e15957056604896570b..bb43cf703efc590bf40ba62a3de52aeea64d71b4 100644 (file)
@@ -126,9 +126,14 @@ struct chip_desc {
        u16                     nvram_offset;
        u16                     nvram_size;
        u16                     trickle_charger_reg;
+       u8                      trickle_charger_setup;
+       u8                      (*do_trickle_setup)(struct i2c_client *, uint32_t, bool);
 };
 
-static const struct chip_desc chips[last_ds_type] = {
+static u8 do_trickle_setup_ds1339(struct i2c_client *,
+                                 uint32_t ohms, bool diode);
+
+static struct chip_desc chips[last_ds_type] = {
        [ds_1307] = {
                .nvram_offset   = 8,
                .nvram_size     = 56,
@@ -143,6 +148,7 @@ static const struct chip_desc chips[last_ds_type] = {
        [ds_1339] = {
                .alarm          = 1,
                .trickle_charger_reg = 0x10,
+               .do_trickle_setup = &do_trickle_setup_ds1339,
        },
        [ds_1340] = {
                .trickle_charger_reg = 0x08,
@@ -833,15 +839,58 @@ ds1307_nvram_write(struct file *filp, struct kobject *kobj,
        return count;
 }
 
+
 /*----------------------------------------------------------------------*/
 
+static u8 do_trickle_setup_ds1339(struct i2c_client *client,
+                                 uint32_t ohms, bool diode)
+{
+       u8 setup = (diode) ? DS1307_TRICKLE_CHARGER_DIODE :
+               DS1307_TRICKLE_CHARGER_NO_DIODE;
+
+       switch (ohms) {
+       case 250:
+               setup |= DS1307_TRICKLE_CHARGER_250_OHM;
+               break;
+       case 2000:
+               setup |= DS1307_TRICKLE_CHARGER_2K_OHM;
+               break;
+       case 4000:
+               setup |= DS1307_TRICKLE_CHARGER_4K_OHM;
+               break;
+       default:
+               dev_warn(&client->dev,
+                        "Unsupported ohm value %u in dt\n", ohms);
+               return 0;
+       }
+       return setup;
+}
+
+static void ds1307_trickle_of_init(struct i2c_client *client,
+                                  struct chip_desc *chip)
+{
+       uint32_t ohms = 0;
+       bool diode = true;
+
+       if (!chip->do_trickle_setup)
+               goto out;
+       if (of_property_read_u32(client->dev.of_node, "trickle-resistor-ohms" , &ohms))
+               goto out;
+       if (of_property_read_bool(client->dev.of_node, "trickle-diode-disable"))
+               diode = false;
+       chip->trickle_charger_setup = chip->do_trickle_setup(client,
+                                                            ohms, diode);
+out:
+       return;
+}
+
 static int ds1307_probe(struct i2c_client *client,
                        const struct i2c_device_id *id)
 {
        struct ds1307           *ds1307;
        int                     err = -ENODEV;
        int                     tmp;
-       const struct chip_desc  *chip = &chips[id->driver_data];
+       struct chip_desc        *chip = &chips[id->driver_data];
        struct i2c_adapter      *adapter = to_i2c_adapter(client->dev.parent);
        bool                    want_irq = false;
        unsigned char           *buf;
@@ -866,9 +915,19 @@ static int ds1307_probe(struct i2c_client *client,
        ds1307->client  = client;
        ds1307->type    = id->driver_data;
 
-       if (pdata && pdata->trickle_charger_setup && chip->trickle_charger_reg)
+       if (!pdata && client->dev.of_node)
+               ds1307_trickle_of_init(client, chip);
+       else if (pdata && pdata->trickle_charger_setup)
+               chip->trickle_charger_setup = pdata->trickle_charger_setup;
+
+       if (chip->trickle_charger_setup && chip->trickle_charger_reg) {
+               dev_dbg(&client->dev, "writing trickle charger info 0x%x to 0x%x\n",
+                   DS13XX_TRICKLE_CHARGER_MAGIC | chip->trickle_charger_setup,
+                   chip->trickle_charger_reg);
                i2c_smbus_write_byte_data(client, chip->trickle_charger_reg,
-                       DS13XX_TRICKLE_CHARGER_MAGIC | pdata->trickle_charger_setup);
+                   DS13XX_TRICKLE_CHARGER_MAGIC |
+                   chip->trickle_charger_setup);
+       }
 
        buf = ds1307->regs;
        if (i2c_check_functionality(adapter, I2C_FUNC_SMBUS_I2C_BLOCK)) {
index aa55f081c505c81bee8bf71ccfe49d85dc27fef7..ee3ba7e6b45e148d3f03c9d671ddefbcbc02f282 100644 (file)
@@ -274,7 +274,7 @@ static int isl12022_probe(struct i2c_client *client,
 }
 
 #ifdef CONFIG_OF
-static struct of_device_id isl12022_dt_match[] = {
+static const struct of_device_id isl12022_dt_match[] = {
        { .compatible = "isl,isl12022" },
        { },
 };
index d20a7f0786ebd9540625caa57c7609412569354f..cf73e969c8cc9a1ac38add953e79f6f9f6892094 100644 (file)
 #define RTC_UDR_MASK                   (1 << RTC_UDR_SHIFT)
 #define RTC_RBUDR_SHIFT                        4
 #define RTC_RBUDR_MASK                 (1 << RTC_RBUDR_SHIFT)
-/* WTSR and SMPL Register */
-#define WTSRT_SHIFT                    0
-#define SMPLT_SHIFT                    2
-#define WTSR_EN_SHIFT                  6
-#define SMPL_EN_SHIFT                  7
-#define WTSRT_MASK                     (3 << WTSRT_SHIFT)
-#define SMPLT_MASK                     (3 << SMPLT_SHIFT)
-#define WTSR_EN_MASK                   (1 << WTSR_EN_SHIFT)
-#define SMPL_EN_MASK                   (1 << SMPL_EN_SHIFT)
 /* RTC Hour register */
 #define HOUR_PM_SHIFT                  6
 #define HOUR_PM_MASK                   (1 << HOUR_PM_SHIFT)
@@ -49,7 +40,6 @@
 #define ALARM_ENABLE_MASK              (1 << ALARM_ENABLE_SHIFT)
 
 #define MAX77686_RTC_UPDATE_DELAY      16
-#undef MAX77686_RTC_WTSR_SMPL
 
 enum {
        RTC_SEC = 0,
@@ -80,16 +70,6 @@ enum MAX77686_RTC_OP {
        MAX77686_RTC_READ,
 };
 
-static inline int max77686_rtc_calculate_wday(u8 shifted)
-{
-       int counter = -1;
-       while (shifted) {
-               shifted >>= 1;
-               counter++;
-       }
-       return counter;
-}
-
 static void max77686_rtc_data_to_tm(u8 *data, struct rtc_time *tm,
                                   int rtc_24hr_mode)
 {
@@ -103,7 +83,8 @@ static void max77686_rtc_data_to_tm(u8 *data, struct rtc_time *tm,
                        tm->tm_hour += 12;
        }
 
-       tm->tm_wday = max77686_rtc_calculate_wday(data[RTC_WEEKDAY] & 0x7f);
+       /* Only a single bit is set in data[], so fls() would be equivalent */
+       tm->tm_wday = ffs(data[RTC_WEEKDAY] & 0x7f) - 1;
        tm->tm_mday = data[RTC_DATE] & 0x1f;
        tm->tm_mon = (data[RTC_MONTH] & 0x0f) - 1;
        tm->tm_year = (data[RTC_YEAR] & 0x7f) + 100;
@@ -412,64 +393,6 @@ static const struct rtc_class_ops max77686_rtc_ops = {
        .alarm_irq_enable = max77686_rtc_alarm_irq_enable,
 };
 
-#ifdef MAX77686_RTC_WTSR_SMPL
-static void max77686_rtc_enable_wtsr(struct max77686_rtc_info *info, bool enable)
-{
-       int ret;
-       unsigned int val, mask;
-
-       if (enable)
-               val = (1 << WTSR_EN_SHIFT) | (3 << WTSRT_SHIFT);
-       else
-               val = 0;
-
-       mask = WTSR_EN_MASK | WTSRT_MASK;
-
-       dev_info(info->dev, "%s: %s WTSR\n", __func__,
-                       enable ? "enable" : "disable");
-
-       ret = regmap_update_bits(info->max77686->rtc_regmap,
-                                MAX77686_WTSR_SMPL_CNTL, mask, val);
-       if (ret < 0) {
-               dev_err(info->dev, "%s: fail to update WTSR reg(%d)\n",
-                               __func__, ret);
-               return;
-       }
-
-       max77686_rtc_update(info, MAX77686_RTC_WRITE);
-}
-
-static void max77686_rtc_enable_smpl(struct max77686_rtc_info *info, bool enable)
-{
-       int ret;
-       unsigned int val, mask;
-
-       if (enable)
-               val = (1 << SMPL_EN_SHIFT) | (0 << SMPLT_SHIFT);
-       else
-               val = 0;
-
-       mask = SMPL_EN_MASK | SMPLT_MASK;
-
-       dev_info(info->dev, "%s: %s SMPL\n", __func__,
-                       enable ? "enable" : "disable");
-
-       ret = regmap_update_bits(info->max77686->rtc_regmap,
-                                MAX77686_WTSR_SMPL_CNTL, mask, val);
-       if (ret < 0) {
-               dev_err(info->dev, "%s: fail to update SMPL reg(%d)\n",
-                               __func__, ret);
-               return;
-       }
-
-       max77686_rtc_update(info, MAX77686_RTC_WRITE);
-
-       val = 0;
-       regmap_read(info->max77686->rtc_regmap, MAX77686_WTSR_SMPL_CNTL, &val);
-       dev_info(info->dev, "%s: WTSR_SMPL(0x%02x)\n", __func__, val);
-}
-#endif /* MAX77686_RTC_WTSR_SMPL */
-
 static int max77686_rtc_init_reg(struct max77686_rtc_info *info)
 {
        u8 data[2];
@@ -519,19 +442,12 @@ static int max77686_rtc_probe(struct platform_device *pdev)
                goto err_rtc;
        }
 
-#ifdef MAX77686_RTC_WTSR_SMPL
-       max77686_rtc_enable_wtsr(info, true);
-       max77686_rtc_enable_smpl(info, true);
-#endif
-
        device_init_wakeup(&pdev->dev, 1);
 
        info->rtc_dev = devm_rtc_device_register(&pdev->dev, "max77686-rtc",
                                        &max77686_rtc_ops, THIS_MODULE);
 
        if (IS_ERR(info->rtc_dev)) {
-               dev_info(&pdev->dev, "%s: fail\n", __func__);
-
                ret = PTR_ERR(info->rtc_dev);
                dev_err(&pdev->dev, "Failed to register RTC device: %d\n", ret);
                if (ret == 0)
@@ -539,6 +455,12 @@ static int max77686_rtc_probe(struct platform_device *pdev)
                goto err_rtc;
        }
 
+       if (!max77686->rtc_irq_data) {
+               ret = -EINVAL;
+               dev_err(&pdev->dev, "%s: no RTC regmap IRQ chip\n", __func__);
+               goto err_rtc;
+       }
+
        info->virq = regmap_irq_get_virq(max77686->rtc_irq_data,
                                         MAX77686_RTCIRQ_RTCA1);
        if (!info->virq) {
@@ -556,33 +478,33 @@ err_rtc:
        return ret;
 }
 
-static void max77686_rtc_shutdown(struct platform_device *pdev)
+#ifdef CONFIG_PM_SLEEP
+static int max77686_rtc_suspend(struct device *dev)
 {
-#ifdef MAX77686_RTC_WTSR_SMPL
-       struct max77686_rtc_info *info = platform_get_drvdata(pdev);
-       int i;
-       u8 val = 0;
-
-       for (i = 0; i < 3; i++) {
-               max77686_rtc_enable_wtsr(info, false);
-               regmap_read(info->max77686->rtc_regmap, MAX77686_WTSR_SMPL_CNTL, &val);
-               dev_info(info->dev, "%s: WTSR_SMPL reg(0x%02x)\n", __func__,
-                               val);
-               if (val & WTSR_EN_MASK) {
-                       dev_emerg(info->dev, "%s: fail to disable WTSR\n",
-                                       __func__);
-               } else {
-                       dev_info(info->dev, "%s: success to disable WTSR\n",
-                                       __func__);
-                       break;
-               }
+       if (device_may_wakeup(dev)) {
+               struct max77686_rtc_info *info = dev_get_drvdata(dev);
+
+               return enable_irq_wake(info->virq);
        }
 
-       /* Disable SMPL when power off */
-       max77686_rtc_enable_smpl(info, false);
-#endif /* MAX77686_RTC_WTSR_SMPL */
+       return 0;
 }
 
+static int max77686_rtc_resume(struct device *dev)
+{
+       if (device_may_wakeup(dev)) {
+               struct max77686_rtc_info *info = dev_get_drvdata(dev);
+
+               return disable_irq_wake(info->virq);
+       }
+
+       return 0;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(max77686_rtc_pm_ops,
+                        max77686_rtc_suspend, max77686_rtc_resume);
+
 static const struct platform_device_id rtc_id[] = {
        { "max77686-rtc", 0 },
        {},
@@ -592,9 +514,9 @@ static struct platform_driver max77686_rtc_driver = {
        .driver         = {
                .name   = "max77686-rtc",
                .owner  = THIS_MODULE,
+               .pm     = &max77686_rtc_pm_ops,
        },
        .probe          = max77686_rtc_probe,
-       .shutdown       = max77686_rtc_shutdown,
        .id_table       = rtc_id,
 };
 
diff --git a/drivers/rtc/rtc-max77802.c b/drivers/rtc/rtc-max77802.c
new file mode 100644 (file)
index 0000000..5664713
--- /dev/null
@@ -0,0 +1,502 @@
+/*
+ * RTC driver for Maxim MAX77802
+ *
+ * Copyright (C) 2013 Google, Inc
+ *
+ * Copyright (C) 2012 Samsung Electronics Co.Ltd
+ *
+ *  based on rtc-max8997.c
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ *
+ */
+
+#include <linux/slab.h>
+#include <linux/rtc.h>
+#include <linux/delay.h>
+#include <linux/mutex.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/mfd/max77686-private.h>
+#include <linux/irqdomain.h>
+#include <linux/regmap.h>
+
+/* RTC Control Register */
+#define BCD_EN_SHIFT                   0
+#define BCD_EN_MASK                    (1 << BCD_EN_SHIFT)
+#define MODEL24_SHIFT                  1
+#define MODEL24_MASK                   (1 << MODEL24_SHIFT)
+/* RTC Update Register1 */
+#define RTC_UDR_SHIFT                  0
+#define RTC_UDR_MASK                   (1 << RTC_UDR_SHIFT)
+#define RTC_RBUDR_SHIFT                        4
+#define RTC_RBUDR_MASK                 (1 << RTC_RBUDR_SHIFT)
+/* RTC Hour register */
+#define HOUR_PM_SHIFT                  6
+#define HOUR_PM_MASK                   (1 << HOUR_PM_SHIFT)
+/* RTC Alarm Enable */
+#define ALARM_ENABLE_SHIFT             7
+#define ALARM_ENABLE_MASK              (1 << ALARM_ENABLE_SHIFT)
+
+/* For the RTCAE1 register, we write this value to enable the alarm */
+#define ALARM_ENABLE_VALUE             0x77
+
+#define MAX77802_RTC_UPDATE_DELAY_US   200
+
+enum {
+       RTC_SEC = 0,
+       RTC_MIN,
+       RTC_HOUR,
+       RTC_WEEKDAY,
+       RTC_MONTH,
+       RTC_YEAR,
+       RTC_DATE,
+       RTC_NR_TIME
+};
+
+struct max77802_rtc_info {
+       struct device           *dev;
+       struct max77686_dev     *max77802;
+       struct i2c_client       *rtc;
+       struct rtc_device       *rtc_dev;
+       struct mutex            lock;
+
+       struct regmap           *regmap;
+
+       int virq;
+       int rtc_24hr_mode;
+};
+
+enum MAX77802_RTC_OP {
+       MAX77802_RTC_WRITE,
+       MAX77802_RTC_READ,
+};
+
+static void max77802_rtc_data_to_tm(u8 *data, struct rtc_time *tm,
+                                  int rtc_24hr_mode)
+{
+       tm->tm_sec = data[RTC_SEC] & 0xff;
+       tm->tm_min = data[RTC_MIN] & 0xff;
+       if (rtc_24hr_mode)
+               tm->tm_hour = data[RTC_HOUR] & 0x1f;
+       else {
+               tm->tm_hour = data[RTC_HOUR] & 0x0f;
+               if (data[RTC_HOUR] & HOUR_PM_MASK)
+                       tm->tm_hour += 12;
+       }
+
+       /* Only a single bit is set in data[], so fls() would be equivalent */
+       tm->tm_wday = ffs(data[RTC_WEEKDAY] & 0xff) - 1;
+       tm->tm_mday = data[RTC_DATE] & 0x1f;
+       tm->tm_mon = (data[RTC_MONTH] & 0x0f) - 1;
+
+       tm->tm_year = data[RTC_YEAR] & 0xff;
+       tm->tm_yday = 0;
+       tm->tm_isdst = 0;
+}
+
+static int max77802_rtc_tm_to_data(struct rtc_time *tm, u8 *data)
+{
+       data[RTC_SEC] = tm->tm_sec;
+       data[RTC_MIN] = tm->tm_min;
+       data[RTC_HOUR] = tm->tm_hour;
+       data[RTC_WEEKDAY] = 1 << tm->tm_wday;
+       data[RTC_DATE] = tm->tm_mday;
+       data[RTC_MONTH] = tm->tm_mon + 1;
+       data[RTC_YEAR] = tm->tm_year;
+
+       return 0;
+}
+
+static int max77802_rtc_update(struct max77802_rtc_info *info,
+       enum MAX77802_RTC_OP op)
+{
+       int ret;
+       unsigned int data;
+
+       if (op == MAX77802_RTC_WRITE)
+               data = 1 << RTC_UDR_SHIFT;
+       else
+               data = 1 << RTC_RBUDR_SHIFT;
+
+       ret = regmap_update_bits(info->max77802->regmap,
+                                MAX77802_RTC_UPDATE0, data, data);
+       if (ret < 0)
+               dev_err(info->dev, "%s: fail to write update reg(ret=%d, data=0x%x)\n",
+                               __func__, ret, data);
+       else {
+               /* Minimum delay required before RTC update. */
+               usleep_range(MAX77802_RTC_UPDATE_DELAY_US,
+                            MAX77802_RTC_UPDATE_DELAY_US * 2);
+       }
+
+       return ret;
+}
+
+static int max77802_rtc_read_time(struct device *dev, struct rtc_time *tm)
+{
+       struct max77802_rtc_info *info = dev_get_drvdata(dev);
+       u8 data[RTC_NR_TIME];
+       int ret;
+
+       mutex_lock(&info->lock);
+
+       ret = max77802_rtc_update(info, MAX77802_RTC_READ);
+       if (ret < 0)
+               goto out;
+
+       ret = regmap_bulk_read(info->max77802->regmap,
+                               MAX77802_RTC_SEC, data, RTC_NR_TIME);
+       if (ret < 0) {
+               dev_err(info->dev, "%s: fail to read time reg(%d)\n", __func__,
+                       ret);
+               goto out;
+       }
+
+       max77802_rtc_data_to_tm(data, tm, info->rtc_24hr_mode);
+
+       ret = rtc_valid_tm(tm);
+
+out:
+       mutex_unlock(&info->lock);
+       return ret;
+}
+
+static int max77802_rtc_set_time(struct device *dev, struct rtc_time *tm)
+{
+       struct max77802_rtc_info *info = dev_get_drvdata(dev);
+       u8 data[RTC_NR_TIME];
+       int ret;
+
+       ret = max77802_rtc_tm_to_data(tm, data);
+       if (ret < 0)
+               return ret;
+
+       mutex_lock(&info->lock);
+
+       ret = regmap_bulk_write(info->max77802->regmap,
+                                MAX77802_RTC_SEC, data, RTC_NR_TIME);
+       if (ret < 0) {
+               dev_err(info->dev, "%s: fail to write time reg(%d)\n", __func__,
+                       ret);
+               goto out;
+       }
+
+       ret = max77802_rtc_update(info, MAX77802_RTC_WRITE);
+
+out:
+       mutex_unlock(&info->lock);
+       return ret;
+}
+
+static int max77802_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+       struct max77802_rtc_info *info = dev_get_drvdata(dev);
+       u8 data[RTC_NR_TIME];
+       unsigned int val;
+       int ret;
+
+       mutex_lock(&info->lock);
+
+       ret = max77802_rtc_update(info, MAX77802_RTC_READ);
+       if (ret < 0)
+               goto out;
+
+       ret = regmap_bulk_read(info->max77802->regmap,
+                                MAX77802_ALARM1_SEC, data, RTC_NR_TIME);
+       if (ret < 0) {
+               dev_err(info->dev, "%s:%d fail to read alarm reg(%d)\n",
+                               __func__, __LINE__, ret);
+               goto out;
+       }
+
+       max77802_rtc_data_to_tm(data, &alrm->time, info->rtc_24hr_mode);
+
+       alrm->enabled = 0;
+       ret = regmap_read(info->max77802->regmap,
+                         MAX77802_RTC_AE1, &val);
+       if (ret < 0) {
+               dev_err(info->dev, "%s:%d fail to read alarm enable(%d)\n",
+                       __func__, __LINE__, ret);
+               goto out;
+       }
+       if (val)
+               alrm->enabled = 1;
+
+       alrm->pending = 0;
+       ret = regmap_read(info->max77802->regmap, MAX77802_REG_STATUS2, &val);
+       if (ret < 0) {
+               dev_err(info->dev, "%s:%d fail to read status2 reg(%d)\n",
+                               __func__, __LINE__, ret);
+               goto out;
+       }
+
+       if (val & (1 << 2)) /* RTCA1 */
+               alrm->pending = 1;
+
+out:
+       mutex_unlock(&info->lock);
+       return 0;
+}
+
+static int max77802_rtc_stop_alarm(struct max77802_rtc_info *info)
+{
+       int ret;
+
+       if (!mutex_is_locked(&info->lock))
+               dev_warn(info->dev, "%s: should have mutex locked\n", __func__);
+
+       ret = max77802_rtc_update(info, MAX77802_RTC_READ);
+       if (ret < 0)
+               goto out;
+
+       ret = regmap_write(info->max77802->regmap,
+                          MAX77802_RTC_AE1, 0);
+       if (ret < 0) {
+               dev_err(info->dev, "%s: fail to write alarm reg(%d)\n",
+                       __func__, ret);
+               goto out;
+       }
+
+       ret = max77802_rtc_update(info, MAX77802_RTC_WRITE);
+out:
+       return ret;
+}
+
+static int max77802_rtc_start_alarm(struct max77802_rtc_info *info)
+{
+       int ret;
+
+       if (!mutex_is_locked(&info->lock))
+               dev_warn(info->dev, "%s: should have mutex locked\n",
+                        __func__);
+
+       ret = max77802_rtc_update(info, MAX77802_RTC_READ);
+       if (ret < 0)
+               goto out;
+
+       ret = regmap_write(info->max77802->regmap,
+                                  MAX77802_RTC_AE1,
+                                  ALARM_ENABLE_VALUE);
+
+       if (ret < 0) {
+               dev_err(info->dev, "%s: fail to read alarm reg(%d)\n",
+                               __func__, ret);
+               goto out;
+       }
+
+       ret = max77802_rtc_update(info, MAX77802_RTC_WRITE);
+out:
+       return ret;
+}
+
+static int max77802_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+       struct max77802_rtc_info *info = dev_get_drvdata(dev);
+       u8 data[RTC_NR_TIME];
+       int ret;
+
+       ret = max77802_rtc_tm_to_data(&alrm->time, data);
+       if (ret < 0)
+               return ret;
+
+       mutex_lock(&info->lock);
+
+       ret = max77802_rtc_stop_alarm(info);
+       if (ret < 0)
+               goto out;
+
+       ret = regmap_bulk_write(info->max77802->regmap,
+                                MAX77802_ALARM1_SEC, data, RTC_NR_TIME);
+
+       if (ret < 0) {
+               dev_err(info->dev, "%s: fail to write alarm reg(%d)\n",
+                               __func__, ret);
+               goto out;
+       }
+
+       ret = max77802_rtc_update(info, MAX77802_RTC_WRITE);
+       if (ret < 0)
+               goto out;
+
+       if (alrm->enabled)
+               ret = max77802_rtc_start_alarm(info);
+out:
+       mutex_unlock(&info->lock);
+       return ret;
+}
+
+static int max77802_rtc_alarm_irq_enable(struct device *dev,
+                                        unsigned int enabled)
+{
+       struct max77802_rtc_info *info = dev_get_drvdata(dev);
+       int ret;
+
+       mutex_lock(&info->lock);
+       if (enabled)
+               ret = max77802_rtc_start_alarm(info);
+       else
+               ret = max77802_rtc_stop_alarm(info);
+       mutex_unlock(&info->lock);
+
+       return ret;
+}
+
+static irqreturn_t max77802_rtc_alarm_irq(int irq, void *data)
+{
+       struct max77802_rtc_info *info = data;
+
+       dev_dbg(info->dev, "%s:irq(%d)\n", __func__, irq);
+
+       rtc_update_irq(info->rtc_dev, 1, RTC_IRQF | RTC_AF);
+
+       return IRQ_HANDLED;
+}
+
+static const struct rtc_class_ops max77802_rtc_ops = {
+       .read_time = max77802_rtc_read_time,
+       .set_time = max77802_rtc_set_time,
+       .read_alarm = max77802_rtc_read_alarm,
+       .set_alarm = max77802_rtc_set_alarm,
+       .alarm_irq_enable = max77802_rtc_alarm_irq_enable,
+};
+
+static int max77802_rtc_init_reg(struct max77802_rtc_info *info)
+{
+       u8 data[2];
+       int ret;
+
+       max77802_rtc_update(info, MAX77802_RTC_READ);
+
+       /* Set RTC control register : Binary mode, 24hour mdoe */
+       data[0] = (1 << BCD_EN_SHIFT) | (1 << MODEL24_SHIFT);
+       data[1] = (0 << BCD_EN_SHIFT) | (1 << MODEL24_SHIFT);
+
+       info->rtc_24hr_mode = 1;
+
+       ret = regmap_bulk_write(info->max77802->regmap,
+                               MAX77802_RTC_CONTROLM, data, ARRAY_SIZE(data));
+       if (ret < 0) {
+               dev_err(info->dev, "%s: fail to write controlm reg(%d)\n",
+                               __func__, ret);
+               return ret;
+       }
+
+       ret = max77802_rtc_update(info, MAX77802_RTC_WRITE);
+       return ret;
+}
+
+static int max77802_rtc_probe(struct platform_device *pdev)
+{
+       struct max77686_dev *max77802 = dev_get_drvdata(pdev->dev.parent);
+       struct max77802_rtc_info *info;
+       int ret;
+
+       dev_dbg(&pdev->dev, "%s\n", __func__);
+
+       info = devm_kzalloc(&pdev->dev, sizeof(struct max77802_rtc_info),
+                           GFP_KERNEL);
+       if (!info)
+               return -ENOMEM;
+
+       mutex_init(&info->lock);
+       info->dev = &pdev->dev;
+       info->max77802 = max77802;
+       info->rtc = max77802->i2c;
+
+       platform_set_drvdata(pdev, info);
+
+       ret = max77802_rtc_init_reg(info);
+
+       if (ret < 0) {
+               dev_err(&pdev->dev, "Failed to initialize RTC reg:%d\n", ret);
+               return ret;
+       }
+
+       device_init_wakeup(&pdev->dev, 1);
+
+       info->rtc_dev = devm_rtc_device_register(&pdev->dev, "max77802-rtc",
+                                                &max77802_rtc_ops, THIS_MODULE);
+
+       if (IS_ERR(info->rtc_dev)) {
+               ret = PTR_ERR(info->rtc_dev);
+               dev_err(&pdev->dev, "Failed to register RTC device: %d\n", ret);
+               if (ret == 0)
+                       ret = -EINVAL;
+               return ret;
+       }
+
+       if (!max77802->rtc_irq_data) {
+               dev_err(&pdev->dev, "No RTC regmap IRQ chip\n");
+               return -EINVAL;
+       }
+
+       info->virq = regmap_irq_get_virq(max77802->rtc_irq_data,
+                                        MAX77686_RTCIRQ_RTCA1);
+
+       if (info->virq <= 0) {
+               dev_err(&pdev->dev, "Failed to get virtual IRQ %d\n",
+                       MAX77686_RTCIRQ_RTCA1);
+               return -EINVAL;
+       }
+
+       ret = devm_request_threaded_irq(&pdev->dev, info->virq, NULL,
+                                       max77802_rtc_alarm_irq, 0, "rtc-alarm1",
+                                       info);
+       if (ret < 0)
+               dev_err(&pdev->dev, "Failed to request alarm IRQ: %d: %d\n",
+                       info->virq, ret);
+
+       return ret;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int max77802_rtc_suspend(struct device *dev)
+{
+       if (device_may_wakeup(dev)) {
+               struct max77802_rtc_info *info = dev_get_drvdata(dev);
+
+               return enable_irq_wake(info->virq);
+       }
+
+       return 0;
+}
+
+static int max77802_rtc_resume(struct device *dev)
+{
+       if (device_may_wakeup(dev)) {
+               struct max77802_rtc_info *info = dev_get_drvdata(dev);
+
+               return disable_irq_wake(info->virq);
+       }
+
+       return 0;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(max77802_rtc_pm_ops,
+                        max77802_rtc_suspend, max77802_rtc_resume);
+
+static const struct platform_device_id rtc_id[] = {
+       { "max77802-rtc", 0 },
+       {},
+};
+
+static struct platform_driver max77802_rtc_driver = {
+       .driver         = {
+               .name   = "max77802-rtc",
+               .owner  = THIS_MODULE,
+               .pm     = &max77802_rtc_pm_ops,
+       },
+       .probe          = max77802_rtc_probe,
+       .id_table       = rtc_id,
+};
+
+module_platform_driver(max77802_rtc_driver);
+
+MODULE_DESCRIPTION("Maxim MAX77802 RTC driver");
+MODULE_AUTHOR("Simon Glass <sjg@chromium.org>");
+MODULE_LICENSE("GPL");
index dc4f14255cc36c755ca90658cdad4c501fda4f71..3b965ad6f4d5ad959f84c920e52767443cb899d4 100644 (file)
@@ -401,7 +401,7 @@ static int mpc5121_rtc_remove(struct platform_device *op)
 }
 
 #ifdef CONFIG_OF
-static struct of_device_id mpc5121_rtc_match[] = {
+static const struct of_device_id mpc5121_rtc_match[] = {
        { .compatible = "fsl,mpc5121-rtc", },
        { .compatible = "fsl,mpc5200-rtc", },
        {},
index 5a197d9dc7e727b881740b5715e80aa31155ce7e..c2ef0a22ee94639a0db6d3f1e0334d26947059cb 100644 (file)
@@ -167,8 +167,8 @@ static irqreturn_t pcf8563_irq(int irq, void *dev_id)
        char pending;
 
        err = pcf8563_get_alarm_mode(pcf8563->client, NULL, &pending);
-       if (err < 0)
-               return err;
+       if (err)
+               return IRQ_NONE;
 
        if (pending) {
                rtc_update_irq(pcf8563->rtc, 1, RTC_IRQF | RTC_AF);
index c2639845186b3f8433551116074ae19197ee1866..5911a6dca29199d976fd71b72e818eda1480431c 100644 (file)
@@ -176,7 +176,11 @@ static int pcf8583_rtc_read_time(struct device *dev, struct rtc_time *tm)
 {
        struct i2c_client *client = to_i2c_client(dev);
        unsigned char ctrl, year[2];
-       struct rtc_mem mem = { CMOS_YEAR, sizeof(year), year };
+       struct rtc_mem mem = {
+               .loc = CMOS_YEAR,
+               .nr = sizeof(year),
+               .data = year
+       };
        int real_year, year_offset, err;
 
        /*
@@ -222,8 +226,16 @@ static int pcf8583_rtc_set_time(struct device *dev, struct rtc_time *tm)
 {
        struct i2c_client *client = to_i2c_client(dev);
        unsigned char year[2], chk;
-       struct rtc_mem cmos_year  = { CMOS_YEAR, sizeof(year), year };
-       struct rtc_mem cmos_check = { CMOS_CHECKSUM, 1, &chk };
+       struct rtc_mem cmos_year  = {
+               .loc = CMOS_YEAR,
+               .nr = sizeof(year),
+               .data = year
+       };
+       struct rtc_mem cmos_check = {
+               .loc = CMOS_CHECKSUM,
+               .nr = 1,
+               .data = &chk
+       };
        unsigned int proper_year = tm->tm_year + 1900;
        int ret;
 
diff --git a/drivers/rtc/rtc-rk808.c b/drivers/rtc/rtc-rk808.c
new file mode 100644 (file)
index 0000000..df42257
--- /dev/null
@@ -0,0 +1,414 @@
+/*
+ * RTC driver for Rockchip RK808
+ *
+ * Copyright (c) 2014, Fuzhou Rockchip Electronics Co., Ltd
+ *
+ * Author: Chris Zhong <zyw@rock-chips.com>
+ * Author: Zhang Qing <zhangqing@rock-chips.com>
+ *
+ * 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.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/rtc.h>
+#include <linux/bcd.h>
+#include <linux/mfd/rk808.h>
+#include <linux/platform_device.h>
+#include <linux/i2c.h>
+
+/* RTC_CTRL_REG bitfields */
+#define BIT_RTC_CTRL_REG_STOP_RTC_M            BIT(0)
+
+/* RK808 has a shadowed register for saving a "frozen" RTC time.
+ * When user setting "GET_TIME" to 1, the time will save in this shadowed
+ * register. If set "READSEL" to 1, user read rtc time register, actually
+ * get the time of that moment. If we need the real time, clr this bit.
+ */
+#define BIT_RTC_CTRL_REG_RTC_GET_TIME          BIT(6)
+#define BIT_RTC_CTRL_REG_RTC_READSEL_M         BIT(7)
+#define BIT_RTC_INTERRUPTS_REG_IT_ALARM_M      BIT(3)
+#define RTC_STATUS_MASK                0xFE
+
+#define SECONDS_REG_MSK                0x7F
+#define MINUTES_REG_MAK                0x7F
+#define HOURS_REG_MSK          0x3F
+#define DAYS_REG_MSK           0x3F
+#define MONTHS_REG_MSK         0x1F
+#define YEARS_REG_MSK          0xFF
+#define WEEKS_REG_MSK          0x7
+
+/* REG_SECONDS_REG through REG_YEARS_REG is how many registers? */
+
+#define NUM_TIME_REGS  (RK808_WEEKS_REG - RK808_SECONDS_REG + 1)
+#define NUM_ALARM_REGS (RK808_ALARM_YEARS_REG - RK808_ALARM_SECONDS_REG + 1)
+
+struct rk808_rtc {
+       struct rk808 *rk808;
+       struct rtc_device *rtc;
+       int irq;
+};
+
+/* Read current time and date in RTC */
+static int rk808_rtc_readtime(struct device *dev, struct rtc_time *tm)
+{
+       struct rk808_rtc *rk808_rtc = dev_get_drvdata(dev);
+       struct rk808 *rk808 = rk808_rtc->rk808;
+       u8 rtc_data[NUM_TIME_REGS];
+       int ret;
+
+       /* Force an update of the shadowed registers right now */
+       ret = regmap_update_bits(rk808->regmap, RK808_RTC_CTRL_REG,
+                                BIT_RTC_CTRL_REG_RTC_GET_TIME,
+                                0);
+       if (ret) {
+               dev_err(dev, "Failed to update bits rtc_ctrl: %d\n", ret);
+               return ret;
+       }
+
+       ret = regmap_update_bits(rk808->regmap, RK808_RTC_CTRL_REG,
+                                BIT_RTC_CTRL_REG_RTC_GET_TIME,
+                                BIT_RTC_CTRL_REG_RTC_GET_TIME);
+       if (ret) {
+               dev_err(dev, "Failed to update bits rtc_ctrl: %d\n", ret);
+               return ret;
+       }
+
+       ret = regmap_bulk_read(rk808->regmap, RK808_SECONDS_REG,
+                              rtc_data, NUM_TIME_REGS);
+       if (ret) {
+               dev_err(dev, "Failed to bulk read rtc_data: %d\n", ret);
+               return ret;
+       }
+
+       tm->tm_sec = bcd2bin(rtc_data[0] & SECONDS_REG_MSK);
+       tm->tm_min = bcd2bin(rtc_data[1] & MINUTES_REG_MAK);
+       tm->tm_hour = bcd2bin(rtc_data[2] & HOURS_REG_MSK);
+       tm->tm_mday = bcd2bin(rtc_data[3] & DAYS_REG_MSK);
+       tm->tm_mon = (bcd2bin(rtc_data[4] & MONTHS_REG_MSK)) - 1;
+       tm->tm_year = (bcd2bin(rtc_data[5] & YEARS_REG_MSK)) + 100;
+       tm->tm_wday = bcd2bin(rtc_data[6] & WEEKS_REG_MSK);
+       dev_dbg(dev, "RTC date/time %4d-%02d-%02d(%d) %02d:%02d:%02d\n",
+               1900 + tm->tm_year, tm->tm_mon + 1, tm->tm_mday,
+               tm->tm_wday, tm->tm_hour , tm->tm_min, tm->tm_sec);
+
+       return ret;
+}
+
+/* Set current time and date in RTC */
+static int rk808_rtc_set_time(struct device *dev, struct rtc_time *tm)
+{
+       struct rk808_rtc *rk808_rtc = dev_get_drvdata(dev);
+       struct rk808 *rk808 = rk808_rtc->rk808;
+       u8 rtc_data[NUM_TIME_REGS];
+       int ret;
+
+       rtc_data[0] = bin2bcd(tm->tm_sec);
+       rtc_data[1] = bin2bcd(tm->tm_min);
+       rtc_data[2] = bin2bcd(tm->tm_hour);
+       rtc_data[3] = bin2bcd(tm->tm_mday);
+       rtc_data[4] = bin2bcd(tm->tm_mon + 1);
+       rtc_data[5] = bin2bcd(tm->tm_year - 100);
+       rtc_data[6] = bin2bcd(tm->tm_wday);
+       dev_dbg(dev, "set RTC date/time %4d-%02d-%02d(%d) %02d:%02d:%02d\n",
+               1900 + tm->tm_year, tm->tm_mon + 1, tm->tm_mday,
+               tm->tm_wday, tm->tm_hour , tm->tm_min, tm->tm_sec);
+
+       /* Stop RTC while updating the RTC registers */
+       ret = regmap_update_bits(rk808->regmap, RK808_RTC_CTRL_REG,
+                                BIT_RTC_CTRL_REG_STOP_RTC_M,
+                                BIT_RTC_CTRL_REG_STOP_RTC_M);
+       if (ret) {
+               dev_err(dev, "Failed to update RTC control: %d\n", ret);
+               return ret;
+       }
+
+       ret = regmap_bulk_write(rk808->regmap, RK808_SECONDS_REG,
+                               rtc_data, NUM_TIME_REGS);
+       if (ret) {
+               dev_err(dev, "Failed to bull write rtc_data: %d\n", ret);
+               return ret;
+       }
+       /* Start RTC again */
+       ret = regmap_update_bits(rk808->regmap, RK808_RTC_CTRL_REG,
+                                BIT_RTC_CTRL_REG_STOP_RTC_M, 0);
+       if (ret) {
+               dev_err(dev, "Failed to update RTC control: %d\n", ret);
+               return ret;
+       }
+       return 0;
+}
+
+/* Read alarm time and date in RTC */
+static int rk808_rtc_readalarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+       struct rk808_rtc *rk808_rtc = dev_get_drvdata(dev);
+       struct rk808 *rk808 = rk808_rtc->rk808;
+       u8 alrm_data[NUM_ALARM_REGS];
+       uint32_t int_reg;
+       int ret;
+
+       ret = regmap_bulk_read(rk808->regmap, RK808_ALARM_SECONDS_REG,
+                              alrm_data, NUM_ALARM_REGS);
+
+       alrm->time.tm_sec = bcd2bin(alrm_data[0] & SECONDS_REG_MSK);
+       alrm->time.tm_min = bcd2bin(alrm_data[1] & MINUTES_REG_MAK);
+       alrm->time.tm_hour = bcd2bin(alrm_data[2] & HOURS_REG_MSK);
+       alrm->time.tm_mday = bcd2bin(alrm_data[3] & DAYS_REG_MSK);
+       alrm->time.tm_mon = (bcd2bin(alrm_data[4] & MONTHS_REG_MSK)) - 1;
+       alrm->time.tm_year = (bcd2bin(alrm_data[5] & YEARS_REG_MSK)) + 100;
+
+       ret = regmap_read(rk808->regmap, RK808_RTC_INT_REG, &int_reg);
+       if (ret) {
+               dev_err(dev, "Failed to read RTC INT REG: %d\n", ret);
+               return ret;
+       }
+
+       dev_dbg(dev, "alrm read RTC date/time %4d-%02d-%02d(%d) %02d:%02d:%02d\n",
+               1900 + alrm->time.tm_year, alrm->time.tm_mon + 1,
+               alrm->time.tm_mday, alrm->time.tm_wday, alrm->time.tm_hour,
+               alrm->time.tm_min, alrm->time.tm_sec);
+
+       alrm->enabled = (int_reg & BIT_RTC_INTERRUPTS_REG_IT_ALARM_M) ? 1 : 0;
+
+       return 0;
+}
+
+static int rk808_rtc_stop_alarm(struct rk808_rtc *rk808_rtc)
+{
+       struct rk808 *rk808 = rk808_rtc->rk808;
+       int ret;
+
+       ret = regmap_update_bits(rk808->regmap, RK808_RTC_INT_REG,
+                                BIT_RTC_INTERRUPTS_REG_IT_ALARM_M, 0);
+
+       return ret;
+}
+
+static int rk808_rtc_start_alarm(struct rk808_rtc *rk808_rtc)
+{
+       struct rk808 *rk808 = rk808_rtc->rk808;
+       int ret;
+
+       ret = regmap_update_bits(rk808->regmap, RK808_RTC_INT_REG,
+                                BIT_RTC_INTERRUPTS_REG_IT_ALARM_M,
+                                BIT_RTC_INTERRUPTS_REG_IT_ALARM_M);
+
+       return ret;
+}
+
+static int rk808_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+       struct rk808_rtc *rk808_rtc = dev_get_drvdata(dev);
+       struct rk808 *rk808 = rk808_rtc->rk808;
+       u8 alrm_data[NUM_ALARM_REGS];
+       int ret;
+
+       ret = rk808_rtc_stop_alarm(rk808_rtc);
+       if (ret) {
+               dev_err(dev, "Failed to stop alarm: %d\n", ret);
+               return ret;
+       }
+       dev_dbg(dev, "alrm set RTC date/time %4d-%02d-%02d(%d) %02d:%02d:%02d\n",
+               1900 + alrm->time.tm_year, alrm->time.tm_mon + 1,
+               alrm->time.tm_mday, alrm->time.tm_wday, alrm->time.tm_hour,
+               alrm->time.tm_min, alrm->time.tm_sec);
+
+       alrm_data[0] = bin2bcd(alrm->time.tm_sec);
+       alrm_data[1] = bin2bcd(alrm->time.tm_min);
+       alrm_data[2] = bin2bcd(alrm->time.tm_hour);
+       alrm_data[3] = bin2bcd(alrm->time.tm_mday);
+       alrm_data[4] = bin2bcd(alrm->time.tm_mon + 1);
+       alrm_data[5] = bin2bcd(alrm->time.tm_year - 100);
+
+       ret = regmap_bulk_write(rk808->regmap, RK808_ALARM_SECONDS_REG,
+                               alrm_data, NUM_ALARM_REGS);
+       if (ret) {
+               dev_err(dev, "Failed to bulk write: %d\n", ret);
+               return ret;
+       }
+       if (alrm->enabled) {
+               ret = rk808_rtc_start_alarm(rk808_rtc);
+               if (ret) {
+                       dev_err(dev, "Failed to start alarm: %d\n", ret);
+                       return ret;
+               }
+       }
+       return 0;
+}
+
+static int rk808_rtc_alarm_irq_enable(struct device *dev,
+                                     unsigned int enabled)
+{
+       struct rk808_rtc *rk808_rtc = dev_get_drvdata(dev);
+
+       if (enabled)
+               return rk808_rtc_start_alarm(rk808_rtc);
+
+       return rk808_rtc_stop_alarm(rk808_rtc);
+}
+
+/*
+ * We will just handle setting the frequency and make use the framework for
+ * reading the periodic interupts.
+ *
+ * @freq: Current periodic IRQ freq:
+ * bit 0: every second
+ * bit 1: every minute
+ * bit 2: every hour
+ * bit 3: every day
+ */
+static irqreturn_t rk808_alarm_irq(int irq, void *data)
+{
+       struct rk808_rtc *rk808_rtc = data;
+       struct rk808 *rk808 = rk808_rtc->rk808;
+       struct i2c_client *client = rk808->i2c;
+       int ret;
+
+       ret = regmap_write(rk808->regmap, RK808_RTC_STATUS_REG,
+                          RTC_STATUS_MASK);
+       if (ret) {
+               dev_err(&client->dev,
+                       "%s:Failed to update RTC status: %d\n", __func__, ret);
+               return ret;
+       }
+
+       rtc_update_irq(rk808_rtc->rtc, 1, RTC_IRQF | RTC_AF);
+       dev_dbg(&client->dev,
+                "%s:irq=%d\n", __func__, irq);
+       return IRQ_HANDLED;
+}
+
+static const struct rtc_class_ops rk808_rtc_ops = {
+       .read_time = rk808_rtc_readtime,
+       .set_time = rk808_rtc_set_time,
+       .read_alarm = rk808_rtc_readalarm,
+       .set_alarm = rk808_rtc_setalarm,
+       .alarm_irq_enable = rk808_rtc_alarm_irq_enable,
+};
+
+#ifdef CONFIG_PM_SLEEP
+/* Turn off the alarm if it should not be a wake source. */
+static int rk808_rtc_suspend(struct device *dev)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       struct rk808_rtc *rk808_rtc = dev_get_drvdata(&pdev->dev);
+
+       if (device_may_wakeup(dev))
+               enable_irq_wake(rk808_rtc->irq);
+
+       return 0;
+}
+
+/* Enable the alarm if it should be enabled (in case it was disabled to
+ * prevent use as a wake source).
+ */
+static int rk808_rtc_resume(struct device *dev)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       struct rk808_rtc *rk808_rtc = dev_get_drvdata(&pdev->dev);
+
+       if (device_may_wakeup(dev))
+               disable_irq_wake(rk808_rtc->irq);
+
+       return 0;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(rk808_rtc_pm_ops,
+       rk808_rtc_suspend, rk808_rtc_resume);
+
+static int rk808_rtc_probe(struct platform_device *pdev)
+{
+       struct rk808 *rk808 = dev_get_drvdata(pdev->dev.parent);
+       struct rk808_rtc *rk808_rtc;
+       struct rtc_time tm;
+       int ret;
+
+       rk808_rtc = devm_kzalloc(&pdev->dev, sizeof(*rk808_rtc), GFP_KERNEL);
+       if (rk808_rtc == NULL)
+               return -ENOMEM;
+
+       platform_set_drvdata(pdev, rk808_rtc);
+       rk808_rtc->rk808 = rk808;
+
+       /* start rtc running by default, and use shadowed timer. */
+       ret = regmap_update_bits(rk808->regmap, RK808_RTC_CTRL_REG,
+                                BIT_RTC_CTRL_REG_STOP_RTC_M |
+                                BIT_RTC_CTRL_REG_RTC_READSEL_M,
+                                BIT_RTC_CTRL_REG_RTC_READSEL_M);
+       if (ret) {
+               dev_err(&pdev->dev,
+                       "Failed to update RTC control: %d\n", ret);
+               return ret;
+       }
+
+       ret = regmap_write(rk808->regmap, RK808_RTC_STATUS_REG,
+                          RTC_STATUS_MASK);
+       if (ret) {
+               dev_err(&pdev->dev,
+                       "Failed to write RTC status: %d\n", ret);
+                       return ret;
+       }
+
+       /* set init time */
+       ret = rk808_rtc_readtime(&pdev->dev, &tm);
+       if (ret) {
+               dev_err(&pdev->dev, "Failed to read RTC time\n");
+               return ret;
+       }
+       ret = rtc_valid_tm(&tm);
+       if (ret)
+               dev_warn(&pdev->dev, "invalid date/time\n");
+
+       device_init_wakeup(&pdev->dev, 1);
+
+       rk808_rtc->rtc = devm_rtc_device_register(&pdev->dev, "rk808-rtc",
+                                                 &rk808_rtc_ops, THIS_MODULE);
+       if (IS_ERR(rk808_rtc->rtc)) {
+               ret = PTR_ERR(rk808_rtc->rtc);
+               return ret;
+       }
+
+       rk808_rtc->irq = platform_get_irq(pdev, 0);
+       if (rk808_rtc->irq < 0) {
+               if (rk808_rtc->irq != -EPROBE_DEFER)
+                       dev_err(&pdev->dev, "Wake up is not possible as irq = %d\n",
+                               rk808_rtc->irq);
+               return rk808_rtc->irq;
+       }
+
+       /* request alarm irq of rk808 */
+       ret = devm_request_threaded_irq(&pdev->dev, rk808_rtc->irq, NULL,
+                                       rk808_alarm_irq, 0,
+                                       "RTC alarm", rk808_rtc);
+       if (ret) {
+               dev_err(&pdev->dev, "Failed to request alarm IRQ %d: %d\n",
+                       rk808_rtc->irq, ret);
+       }
+
+       return ret;
+}
+
+static struct platform_driver rk808_rtc_driver = {
+       .probe = rk808_rtc_probe,
+       .driver = {
+               .name = "rk808-rtc",
+               .pm = &rk808_rtc_pm_ops,
+       },
+};
+
+module_platform_driver(rk808_rtc_driver);
+
+MODULE_DESCRIPTION("RTC driver for the rk808 series PMICs");
+MODULE_AUTHOR("Chris Zhong <zyw@rock-chips.com>");
+MODULE_AUTHOR("Zhang Qing <zhangqing@rock-chips.com>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:rk808-rtc");
index ccf54f06396bf251bf42be6007c40db21b84a5c6..28871cd7e3b592681d0839b2830b710e4bce0d60 100644 (file)
@@ -142,12 +142,11 @@ static int rs5c_get_regs(struct rs5c372 *rs5c)
        }
 
        dev_dbg(&client->dev,
-               "%02x %02x %02x (%02x) %02x %02x %02x (%02x), "
-               "%02x %02x %02x, %02x %02x %02x; %02x %02x\n",
-               rs5c->regs[0],  rs5c->regs[1],  rs5c->regs[2],  rs5c->regs[3],
-               rs5c->regs[4],  rs5c->regs[5],  rs5c->regs[6],  rs5c->regs[7],
-               rs5c->regs[8],  rs5c->regs[9],  rs5c->regs[10], rs5c->regs[11],
-               rs5c->regs[12], rs5c->regs[13], rs5c->regs[14], rs5c->regs[15]);
+               "%3ph (%02x) %3ph (%02x), %3ph, %3ph; %02x %02x\n",
+               rs5c->regs + 0, rs5c->regs[3],
+               rs5c->regs + 4, rs5c->regs[7],
+               rs5c->regs + 8, rs5c->regs + 11,
+               rs5c->regs[14], rs5c->regs[15]);
 
        return 0;
 }
index 4958a363b2c76a29b38c476177bca94fe378ca01..a6b1252c9941884a93dac49ed4c10c828ad0964d 100644 (file)
 #include <asm/irq.h>
 #include "rtc-s3c.h"
 
-enum s3c_cpu_type {
-       TYPE_S3C2410,
-       TYPE_S3C2416,
-       TYPE_S3C2443,
-       TYPE_S3C64XX,
-};
+struct s3c_rtc {
+       struct device *dev;
+       struct rtc_device *rtc;
 
-struct s3c_rtc_drv_data {
-       int cpu_type;
-};
+       void __iomem *base;
+       struct clk *rtc_clk;
+       struct clk *rtc_src_clk;
+       bool enabled;
+
+       struct s3c_rtc_data *data;
 
-/* I have yet to find an S3C implementation with more than one
- * of these rtc blocks in */
+       int irq_alarm;
+       int irq_tick;
 
-static struct clk *rtc_clk;
-static void __iomem *s3c_rtc_base;
-static int s3c_rtc_alarmno;
-static int s3c_rtc_tickno;
-static enum s3c_cpu_type s3c_rtc_cpu_type;
+       spinlock_t pie_lock;
+       spinlock_t alarm_clk_lock;
 
-static DEFINE_SPINLOCK(s3c_rtc_pie_lock);
+       int ticnt_save, ticnt_en_save;
+       bool wake_en;
+};
+
+struct s3c_rtc_data {
+       int max_user_freq;
+       bool needs_src_clk;
+
+       void (*irq_handler) (struct s3c_rtc *info, int mask);
+       void (*set_freq) (struct s3c_rtc *info, int freq);
+       void (*enable_tick) (struct s3c_rtc *info, struct seq_file *seq);
+       void (*select_tick_clk) (struct s3c_rtc *info);
+       void (*save_tick_cnt) (struct s3c_rtc *info);
+       void (*restore_tick_cnt) (struct s3c_rtc *info);
+       void (*enable) (struct s3c_rtc *info);
+       void (*disable) (struct s3c_rtc *info);
+};
 
-static void s3c_rtc_alarm_clk_enable(bool enable)
+static void s3c_rtc_alarm_clk_enable(struct s3c_rtc *info, bool enable)
 {
-       static DEFINE_SPINLOCK(s3c_rtc_alarm_clk_lock);
-       static bool alarm_clk_enabled;
        unsigned long irq_flags;
 
-       spin_lock_irqsave(&s3c_rtc_alarm_clk_lock, irq_flags);
+       spin_lock_irqsave(&info->alarm_clk_lock, irq_flags);
        if (enable) {
-               if (!alarm_clk_enabled) {
-                       clk_enable(rtc_clk);
-                       alarm_clk_enabled = true;
+               if (!info->enabled) {
+                       clk_enable(info->rtc_clk);
+                       if (info->data->needs_src_clk)
+                               clk_enable(info->rtc_src_clk);
+                       info->enabled = true;
                }
        } else {
-               if (alarm_clk_enabled) {
-                       clk_disable(rtc_clk);
-                       alarm_clk_enabled = false;
+               if (info->enabled) {
+                       if (info->data->needs_src_clk)
+                               clk_disable(info->rtc_src_clk);
+                       clk_disable(info->rtc_clk);
+                       info->enabled = false;
                }
        }
-       spin_unlock_irqrestore(&s3c_rtc_alarm_clk_lock, irq_flags);
+       spin_unlock_irqrestore(&info->alarm_clk_lock, irq_flags);
 }
 
 /* IRQ Handlers */
-
-static irqreturn_t s3c_rtc_alarmirq(int irq, void *id)
+static irqreturn_t s3c_rtc_tickirq(int irq, void *id)
 {
-       struct rtc_device *rdev = id;
-
-       clk_enable(rtc_clk);
-       rtc_update_irq(rdev, 1, RTC_AF | RTC_IRQF);
-
-       if (s3c_rtc_cpu_type == TYPE_S3C64XX)
-               writeb(S3C2410_INTP_ALM, s3c_rtc_base + S3C2410_INTP);
-
-       clk_disable(rtc_clk);
+       struct s3c_rtc *info = (struct s3c_rtc *)id;
 
-       s3c_rtc_alarm_clk_enable(false);
+       if (info->data->irq_handler)
+               info->data->irq_handler(info, S3C2410_INTP_TIC);
 
        return IRQ_HANDLED;
 }
 
-static irqreturn_t s3c_rtc_tickirq(int irq, void *id)
+static irqreturn_t s3c_rtc_alarmirq(int irq, void *id)
 {
-       struct rtc_device *rdev = id;
+       struct s3c_rtc *info = (struct s3c_rtc *)id;
 
-       clk_enable(rtc_clk);
-       rtc_update_irq(rdev, 1, RTC_PF | RTC_IRQF);
+       if (info->data->irq_handler)
+               info->data->irq_handler(info, S3C2410_INTP_ALM);
 
-       if (s3c_rtc_cpu_type == TYPE_S3C64XX)
-               writeb(S3C2410_INTP_TIC, s3c_rtc_base + S3C2410_INTP);
-
-       clk_disable(rtc_clk);
        return IRQ_HANDLED;
 }
 
 /* Update control registers */
 static int s3c_rtc_setaie(struct device *dev, unsigned int enabled)
 {
+       struct s3c_rtc *info = dev_get_drvdata(dev);
        unsigned int tmp;
 
-       dev_dbg(dev, "%s: aie=%d\n", __func__, enabled);
+       dev_dbg(info->dev, "%s: aie=%d\n", __func__, enabled);
 
-       clk_enable(rtc_clk);
-       tmp = readb(s3c_rtc_base + S3C2410_RTCALM) & ~S3C2410_RTCALM_ALMEN;
+       clk_enable(info->rtc_clk);
+       if (info->data->needs_src_clk)
+               clk_enable(info->rtc_src_clk);
+       tmp = readb(info->base + S3C2410_RTCALM) & ~S3C2410_RTCALM_ALMEN;
 
        if (enabled)
                tmp |= S3C2410_RTCALM_ALMEN;
 
-       writeb(tmp, s3c_rtc_base + S3C2410_RTCALM);
-       clk_disable(rtc_clk);
+       writeb(tmp, info->base + S3C2410_RTCALM);
+       if (info->data->needs_src_clk)
+               clk_disable(info->rtc_src_clk);
+       clk_disable(info->rtc_clk);
 
-       s3c_rtc_alarm_clk_enable(enabled);
+       s3c_rtc_alarm_clk_enable(info, enabled);
 
        return 0;
 }
 
-static int s3c_rtc_setfreq(struct device *dev, int freq)
+/* Set RTC frequency */
+static int s3c_rtc_setfreq(struct s3c_rtc *info, int freq)
 {
-       struct platform_device *pdev = to_platform_device(dev);
-       struct rtc_device *rtc_dev = platform_get_drvdata(pdev);
-       unsigned int tmp = 0;
-       int val;
-
        if (!is_power_of_2(freq))
                return -EINVAL;
 
-       clk_enable(rtc_clk);
-       spin_lock_irq(&s3c_rtc_pie_lock);
+       clk_enable(info->rtc_clk);
+       if (info->data->needs_src_clk)
+               clk_enable(info->rtc_src_clk);
+       spin_lock_irq(&info->pie_lock);
 
-       if (s3c_rtc_cpu_type != TYPE_S3C64XX) {
-               tmp = readb(s3c_rtc_base + S3C2410_TICNT);
-               tmp &= S3C2410_TICNT_ENABLE;
-       }
+       if (info->data->set_freq)
+               info->data->set_freq(info, freq);
 
-       val = (rtc_dev->max_user_freq / freq) - 1;
-
-       if (s3c_rtc_cpu_type == TYPE_S3C2416 || s3c_rtc_cpu_type == TYPE_S3C2443) {
-               tmp |= S3C2443_TICNT_PART(val);
-               writel(S3C2443_TICNT1_PART(val), s3c_rtc_base + S3C2443_TICNT1);
-
-               if (s3c_rtc_cpu_type == TYPE_S3C2416)
-                       writel(S3C2416_TICNT2_PART(val), s3c_rtc_base + S3C2416_TICNT2);
-       } else {
-               tmp |= val;
-       }
-
-       writel(tmp, s3c_rtc_base + S3C2410_TICNT);
-       spin_unlock_irq(&s3c_rtc_pie_lock);
-       clk_disable(rtc_clk);
+       spin_unlock_irq(&info->pie_lock);
+       if (info->data->needs_src_clk)
+               clk_disable(info->rtc_src_clk);
+       clk_disable(info->rtc_clk);
 
        return 0;
 }
 
 /* Time read/write */
-
 static int s3c_rtc_gettime(struct device *dev, struct rtc_time *rtc_tm)
 {
+       struct s3c_rtc *info = dev_get_drvdata(dev);
        unsigned int have_retried = 0;
-       void __iomem *base = s3c_rtc_base;
 
-       clk_enable(rtc_clk);
+       clk_enable(info->rtc_clk);
+       if (info->data->needs_src_clk)
+               clk_enable(info->rtc_src_clk);
+
  retry_get_time:
-       rtc_tm->tm_min  = readb(base + S3C2410_RTCMIN);
-       rtc_tm->tm_hour = readb(base + S3C2410_RTCHOUR);
-       rtc_tm->tm_mday = readb(base + S3C2410_RTCDATE);
-       rtc_tm->tm_mon  = readb(base + S3C2410_RTCMON);
-       rtc_tm->tm_year = readb(base + S3C2410_RTCYEAR);
-       rtc_tm->tm_sec  = readb(base + S3C2410_RTCSEC);
+       rtc_tm->tm_min  = readb(info->base + S3C2410_RTCMIN);
+       rtc_tm->tm_hour = readb(info->base + S3C2410_RTCHOUR);
+       rtc_tm->tm_mday = readb(info->base + S3C2410_RTCDATE);
+       rtc_tm->tm_mon  = readb(info->base + S3C2410_RTCMON);
+       rtc_tm->tm_year = readb(info->base + S3C2410_RTCYEAR);
+       rtc_tm->tm_sec  = readb(info->base + S3C2410_RTCSEC);
 
        /* the only way to work out whether the system was mid-update
         * when we read it is to check the second counter, and if it
@@ -207,13 +202,16 @@ static int s3c_rtc_gettime(struct device *dev, struct rtc_time *rtc_tm)
 
        rtc_tm->tm_mon -= 1;
 
-       clk_disable(rtc_clk);
+       if (info->data->needs_src_clk)
+               clk_disable(info->rtc_src_clk);
+       clk_disable(info->rtc_clk);
+
        return rtc_valid_tm(rtc_tm);
 }
 
 static int s3c_rtc_settime(struct device *dev, struct rtc_time *tm)
 {
-       void __iomem *base = s3c_rtc_base;
+       struct s3c_rtc *info = dev_get_drvdata(dev);
        int year = tm->tm_year - 100;
 
        dev_dbg(dev, "set time %04d.%02d.%02d %02d:%02d:%02d\n",
@@ -227,33 +225,42 @@ static int s3c_rtc_settime(struct device *dev, struct rtc_time *tm)
                return -EINVAL;
        }
 
-       clk_enable(rtc_clk);
-       writeb(bin2bcd(tm->tm_sec),  base + S3C2410_RTCSEC);
-       writeb(bin2bcd(tm->tm_min),  base + S3C2410_RTCMIN);
-       writeb(bin2bcd(tm->tm_hour), base + S3C2410_RTCHOUR);
-       writeb(bin2bcd(tm->tm_mday), base + S3C2410_RTCDATE);
-       writeb(bin2bcd(tm->tm_mon + 1), base + S3C2410_RTCMON);
-       writeb(bin2bcd(year), base + S3C2410_RTCYEAR);
-       clk_disable(rtc_clk);
+       clk_enable(info->rtc_clk);
+       if (info->data->needs_src_clk)
+               clk_enable(info->rtc_src_clk);
+
+       writeb(bin2bcd(tm->tm_sec),  info->base + S3C2410_RTCSEC);
+       writeb(bin2bcd(tm->tm_min),  info->base + S3C2410_RTCMIN);
+       writeb(bin2bcd(tm->tm_hour), info->base + S3C2410_RTCHOUR);
+       writeb(bin2bcd(tm->tm_mday), info->base + S3C2410_RTCDATE);
+       writeb(bin2bcd(tm->tm_mon + 1), info->base + S3C2410_RTCMON);
+       writeb(bin2bcd(year), info->base + S3C2410_RTCYEAR);
+
+       if (info->data->needs_src_clk)
+               clk_disable(info->rtc_src_clk);
+       clk_disable(info->rtc_clk);
 
        return 0;
 }
 
 static int s3c_rtc_getalarm(struct device *dev, struct rtc_wkalrm *alrm)
 {
+       struct s3c_rtc *info = dev_get_drvdata(dev);
        struct rtc_time *alm_tm = &alrm->time;
-       void __iomem *base = s3c_rtc_base;
        unsigned int alm_en;
 
-       clk_enable(rtc_clk);
-       alm_tm->tm_sec  = readb(base + S3C2410_ALMSEC);
-       alm_tm->tm_min  = readb(base + S3C2410_ALMMIN);
-       alm_tm->tm_hour = readb(base + S3C2410_ALMHOUR);
-       alm_tm->tm_mon  = readb(base + S3C2410_ALMMON);
-       alm_tm->tm_mday = readb(base + S3C2410_ALMDATE);
-       alm_tm->tm_year = readb(base + S3C2410_ALMYEAR);
+       clk_enable(info->rtc_clk);
+       if (info->data->needs_src_clk)
+               clk_enable(info->rtc_src_clk);
 
-       alm_en = readb(base + S3C2410_RTCALM);
+       alm_tm->tm_sec  = readb(info->base + S3C2410_ALMSEC);
+       alm_tm->tm_min  = readb(info->base + S3C2410_ALMMIN);
+       alm_tm->tm_hour = readb(info->base + S3C2410_ALMHOUR);
+       alm_tm->tm_mon  = readb(info->base + S3C2410_ALMMON);
+       alm_tm->tm_mday = readb(info->base + S3C2410_ALMDATE);
+       alm_tm->tm_year = readb(info->base + S3C2410_ALMYEAR);
+
+       alm_en = readb(info->base + S3C2410_RTCALM);
 
        alrm->enabled = (alm_en & S3C2410_RTCALM_ALMEN) ? 1 : 0;
 
@@ -297,65 +304,74 @@ static int s3c_rtc_getalarm(struct device *dev, struct rtc_wkalrm *alrm)
        else
                alm_tm->tm_year = -1;
 
-       clk_disable(rtc_clk);
+       if (info->data->needs_src_clk)
+               clk_disable(info->rtc_src_clk);
+       clk_disable(info->rtc_clk);
+
        return 0;
 }
 
 static int s3c_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm)
 {
+       struct s3c_rtc *info = dev_get_drvdata(dev);
        struct rtc_time *tm = &alrm->time;
-       void __iomem *base = s3c_rtc_base;
        unsigned int alrm_en;
 
-       clk_enable(rtc_clk);
+       clk_enable(info->rtc_clk);
+       if (info->data->needs_src_clk)
+               clk_enable(info->rtc_src_clk);
+
        dev_dbg(dev, "s3c_rtc_setalarm: %d, %04d.%02d.%02d %02d:%02d:%02d\n",
                 alrm->enabled,
                 1900 + tm->tm_year, tm->tm_mon + 1, tm->tm_mday,
                 tm->tm_hour, tm->tm_min, tm->tm_sec);
 
-       alrm_en = readb(base + S3C2410_RTCALM) & S3C2410_RTCALM_ALMEN;
-       writeb(0x00, base + S3C2410_RTCALM);
+       alrm_en = readb(info->base + S3C2410_RTCALM) & S3C2410_RTCALM_ALMEN;
+       writeb(0x00, info->base + S3C2410_RTCALM);
 
        if (tm->tm_sec < 60 && tm->tm_sec >= 0) {
                alrm_en |= S3C2410_RTCALM_SECEN;
-               writeb(bin2bcd(tm->tm_sec), base + S3C2410_ALMSEC);
+               writeb(bin2bcd(tm->tm_sec), info->base + S3C2410_ALMSEC);
        }
 
        if (tm->tm_min < 60 && tm->tm_min >= 0) {
                alrm_en |= S3C2410_RTCALM_MINEN;
-               writeb(bin2bcd(tm->tm_min), base + S3C2410_ALMMIN);
+               writeb(bin2bcd(tm->tm_min), info->base + S3C2410_ALMMIN);
        }
 
        if (tm->tm_hour < 24 && tm->tm_hour >= 0) {
                alrm_en |= S3C2410_RTCALM_HOUREN;
-               writeb(bin2bcd(tm->tm_hour), base + S3C2410_ALMHOUR);
+               writeb(bin2bcd(tm->tm_hour), info->base + S3C2410_ALMHOUR);
        }
 
        dev_dbg(dev, "setting S3C2410_RTCALM to %08x\n", alrm_en);
 
-       writeb(alrm_en, base + S3C2410_RTCALM);
+       writeb(alrm_en, info->base + S3C2410_RTCALM);
 
        s3c_rtc_setaie(dev, alrm->enabled);
 
-       clk_disable(rtc_clk);
+       if (info->data->needs_src_clk)
+               clk_disable(info->rtc_src_clk);
+       clk_disable(info->rtc_clk);
+
        return 0;
 }
 
 static int s3c_rtc_proc(struct device *dev, struct seq_file *seq)
 {
-       unsigned int ticnt;
+       struct s3c_rtc *info = dev_get_drvdata(dev);
 
-       clk_enable(rtc_clk);
-       if (s3c_rtc_cpu_type == TYPE_S3C64XX) {
-               ticnt = readw(s3c_rtc_base + S3C2410_RTCCON);
-               ticnt &= S3C64XX_RTCCON_TICEN;
-       } else {
-               ticnt = readb(s3c_rtc_base + S3C2410_TICNT);
-               ticnt &= S3C2410_TICNT_ENABLE;
-       }
+       clk_enable(info->rtc_clk);
+       if (info->data->needs_src_clk)
+               clk_enable(info->rtc_src_clk);
+
+       if (info->data->enable_tick)
+               info->data->enable_tick(info, seq);
+
+       if (info->data->needs_src_clk)
+               clk_disable(info->rtc_src_clk);
+       clk_disable(info->rtc_clk);
 
-       seq_printf(seq, "periodic_IRQ\t: %s\n", ticnt  ? "yes" : "no");
-       clk_disable(rtc_clk);
        return 0;
 }
 
@@ -368,152 +384,199 @@ static const struct rtc_class_ops s3c_rtcops = {
        .alarm_irq_enable = s3c_rtc_setaie,
 };
 
-static void s3c_rtc_enable(struct platform_device *pdev, int en)
+static void s3c24xx_rtc_enable(struct s3c_rtc *info)
 {
-       void __iomem *base = s3c_rtc_base;
-       unsigned int tmp;
+       unsigned int con, tmp;
 
-       if (s3c_rtc_base == NULL)
-               return;
-
-       clk_enable(rtc_clk);
-       if (!en) {
-               tmp = readw(base + S3C2410_RTCCON);
-               if (s3c_rtc_cpu_type == TYPE_S3C64XX)
-                       tmp &= ~S3C64XX_RTCCON_TICEN;
-               tmp &= ~S3C2410_RTCCON_RTCEN;
-               writew(tmp, base + S3C2410_RTCCON);
-
-               if (s3c_rtc_cpu_type != TYPE_S3C64XX) {
-                       tmp = readb(base + S3C2410_TICNT);
-                       tmp &= ~S3C2410_TICNT_ENABLE;
-                       writeb(tmp, base + S3C2410_TICNT);
-               }
-       } else {
-               /* re-enable the device, and check it is ok */
+       clk_enable(info->rtc_clk);
+       if (info->data->needs_src_clk)
+               clk_enable(info->rtc_src_clk);
 
-               if ((readw(base+S3C2410_RTCCON) & S3C2410_RTCCON_RTCEN) == 0) {
-                       dev_info(&pdev->dev, "rtc disabled, re-enabling\n");
+       con = readw(info->base + S3C2410_RTCCON);
+       /* re-enable the device, and check it is ok */
+       if ((con & S3C2410_RTCCON_RTCEN) == 0) {
+               dev_info(info->dev, "rtc disabled, re-enabling\n");
 
-                       tmp = readw(base + S3C2410_RTCCON);
-                       writew(tmp | S3C2410_RTCCON_RTCEN,
-                               base + S3C2410_RTCCON);
-               }
+               tmp = readw(info->base + S3C2410_RTCCON);
+               writew(tmp | S3C2410_RTCCON_RTCEN,
+                       info->base + S3C2410_RTCCON);
+       }
 
-               if ((readw(base + S3C2410_RTCCON) & S3C2410_RTCCON_CNTSEL)) {
-                       dev_info(&pdev->dev, "removing RTCCON_CNTSEL\n");
+       if (con & S3C2410_RTCCON_CNTSEL) {
+               dev_info(info->dev, "removing RTCCON_CNTSEL\n");
 
-                       tmp = readw(base + S3C2410_RTCCON);
-                       writew(tmp & ~S3C2410_RTCCON_CNTSEL,
-                               base + S3C2410_RTCCON);
-               }
+               tmp = readw(info->base + S3C2410_RTCCON);
+               writew(tmp & ~S3C2410_RTCCON_CNTSEL,
+                       info->base + S3C2410_RTCCON);
+       }
 
-               if ((readw(base + S3C2410_RTCCON) & S3C2410_RTCCON_CLKRST)) {
-                       dev_info(&pdev->dev, "removing RTCCON_CLKRST\n");
+       if (con & S3C2410_RTCCON_CLKRST) {
+               dev_info(info->dev, "removing RTCCON_CLKRST\n");
 
-                       tmp = readw(base + S3C2410_RTCCON);
-                       writew(tmp & ~S3C2410_RTCCON_CLKRST,
-                               base + S3C2410_RTCCON);
-               }
+               tmp = readw(info->base + S3C2410_RTCCON);
+               writew(tmp & ~S3C2410_RTCCON_CLKRST,
+                       info->base + S3C2410_RTCCON);
        }
-       clk_disable(rtc_clk);
+
+       if (info->data->needs_src_clk)
+               clk_disable(info->rtc_src_clk);
+       clk_disable(info->rtc_clk);
 }
 
-static int s3c_rtc_remove(struct platform_device *dev)
+static void s3c24xx_rtc_disable(struct s3c_rtc *info)
 {
-       s3c_rtc_setaie(&dev->dev, 0);
+       unsigned int con;
+
+       clk_enable(info->rtc_clk);
+       if (info->data->needs_src_clk)
+               clk_enable(info->rtc_src_clk);
+
+       con = readw(info->base + S3C2410_RTCCON);
+       con &= ~S3C2410_RTCCON_RTCEN;
+       writew(con, info->base + S3C2410_RTCCON);
 
-       clk_unprepare(rtc_clk);
-       rtc_clk = NULL;
+       con = readb(info->base + S3C2410_TICNT);
+       con &= ~S3C2410_TICNT_ENABLE;
+       writeb(con, info->base + S3C2410_TICNT);
+
+       if (info->data->needs_src_clk)
+               clk_disable(info->rtc_src_clk);
+       clk_disable(info->rtc_clk);
+}
+
+static void s3c6410_rtc_disable(struct s3c_rtc *info)
+{
+       unsigned int con;
+
+       clk_enable(info->rtc_clk);
+       if (info->data->needs_src_clk)
+               clk_enable(info->rtc_src_clk);
+
+       con = readw(info->base + S3C2410_RTCCON);
+       con &= ~S3C64XX_RTCCON_TICEN;
+       con &= ~S3C2410_RTCCON_RTCEN;
+       writew(con, info->base + S3C2410_RTCCON);
+
+       if (info->data->needs_src_clk)
+               clk_disable(info->rtc_src_clk);
+       clk_disable(info->rtc_clk);
+}
+
+static int s3c_rtc_remove(struct platform_device *pdev)
+{
+       struct s3c_rtc *info = platform_get_drvdata(pdev);
+
+       s3c_rtc_setaie(info->dev, 0);
+
+       clk_unprepare(info->rtc_clk);
+       info->rtc_clk = NULL;
 
        return 0;
 }
 
 static const struct of_device_id s3c_rtc_dt_match[];
 
-static inline int s3c_rtc_get_driver_data(struct platform_device *pdev)
+static struct s3c_rtc_data *s3c_rtc_get_data(struct platform_device *pdev)
 {
-#ifdef CONFIG_OF
-       struct s3c_rtc_drv_data *data;
-       if (pdev->dev.of_node) {
-               const struct of_device_id *match;
-               match = of_match_node(s3c_rtc_dt_match, pdev->dev.of_node);
-               data = (struct s3c_rtc_drv_data *) match->data;
-               return data->cpu_type;
-       }
-#endif
-       return platform_get_device_id(pdev)->driver_data;
+       const struct of_device_id *match;
+
+       match = of_match_node(s3c_rtc_dt_match, pdev->dev.of_node);
+       return (struct s3c_rtc_data *)match->data;
 }
 
 static int s3c_rtc_probe(struct platform_device *pdev)
 {
-       struct rtc_device *rtc;
+       struct s3c_rtc *info = NULL;
        struct rtc_time rtc_tm;
        struct resource *res;
        int ret;
-       int tmp;
 
-       dev_dbg(&pdev->dev, "%s: probe=%p\n", __func__, pdev);
+       info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
+       if (!info)
+               return -ENOMEM;
 
        /* find the IRQs */
-
-       s3c_rtc_tickno = platform_get_irq(pdev, 1);
-       if (s3c_rtc_tickno < 0) {
+       info->irq_tick = platform_get_irq(pdev, 1);
+       if (info->irq_tick < 0) {
                dev_err(&pdev->dev, "no irq for rtc tick\n");
-               return s3c_rtc_tickno;
+               return info->irq_tick;
+       }
+
+       info->dev = &pdev->dev;
+       info->data = s3c_rtc_get_data(pdev);
+       if (!info->data) {
+               dev_err(&pdev->dev, "failed getting s3c_rtc_data\n");
+               return -EINVAL;
        }
+       spin_lock_init(&info->pie_lock);
+       spin_lock_init(&info->alarm_clk_lock);
+
+       platform_set_drvdata(pdev, info);
 
-       s3c_rtc_alarmno = platform_get_irq(pdev, 0);
-       if (s3c_rtc_alarmno < 0) {
+       info->irq_alarm = platform_get_irq(pdev, 0);
+       if (info->irq_alarm < 0) {
                dev_err(&pdev->dev, "no irq for alarm\n");
-               return s3c_rtc_alarmno;
+               return info->irq_alarm;
        }
 
        dev_dbg(&pdev->dev, "s3c2410_rtc: tick irq %d, alarm irq %d\n",
-                s3c_rtc_tickno, s3c_rtc_alarmno);
+                info->irq_tick, info->irq_alarm);
 
        /* get the memory region */
-
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       s3c_rtc_base = devm_ioremap_resource(&pdev->dev, res);
-       if (IS_ERR(s3c_rtc_base))
-               return PTR_ERR(s3c_rtc_base);
-
-       rtc_clk = devm_clk_get(&pdev->dev, "rtc");
-       if (IS_ERR(rtc_clk)) {
-               dev_err(&pdev->dev, "failed to find rtc clock source\n");
-               ret = PTR_ERR(rtc_clk);
-               rtc_clk = NULL;
-               return ret;
+       info->base = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(info->base))
+               return PTR_ERR(info->base);
+
+       info->rtc_clk = devm_clk_get(&pdev->dev, "rtc");
+       if (IS_ERR(info->rtc_clk)) {
+               dev_err(&pdev->dev, "failed to find rtc clock\n");
+               return PTR_ERR(info->rtc_clk);
        }
+       clk_prepare_enable(info->rtc_clk);
 
-       clk_prepare_enable(rtc_clk);
+       info->rtc_src_clk = devm_clk_get(&pdev->dev, "rtc_src");
+       if (IS_ERR(info->rtc_src_clk)) {
+               dev_err(&pdev->dev, "failed to find rtc source clock\n");
+               return PTR_ERR(info->rtc_src_clk);
+       }
+       clk_prepare_enable(info->rtc_src_clk);
 
-       /* check to see if everything is setup correctly */
 
-       s3c_rtc_enable(pdev, 1);
+       /* check to see if everything is setup correctly */
+       if (info->data->enable)
+               info->data->enable(info);
 
        dev_dbg(&pdev->dev, "s3c2410_rtc: RTCCON=%02x\n",
-                readw(s3c_rtc_base + S3C2410_RTCCON));
+                readw(info->base + S3C2410_RTCCON));
 
        device_init_wakeup(&pdev->dev, 1);
 
        /* register RTC and exit */
-
-       rtc = devm_rtc_device_register(&pdev->dev, "s3c", &s3c_rtcops,
+       info->rtc = devm_rtc_device_register(&pdev->dev, "s3c", &s3c_rtcops,
                                  THIS_MODULE);
-
-       if (IS_ERR(rtc)) {
+       if (IS_ERR(info->rtc)) {
                dev_err(&pdev->dev, "cannot attach rtc\n");
-               ret = PTR_ERR(rtc);
+               ret = PTR_ERR(info->rtc);
                goto err_nortc;
        }
 
-       s3c_rtc_cpu_type = s3c_rtc_get_driver_data(pdev);
+       ret = devm_request_irq(&pdev->dev, info->irq_alarm, s3c_rtc_alarmirq,
+                         0,  "s3c2410-rtc alarm", info);
+       if (ret) {
+               dev_err(&pdev->dev, "IRQ%d error %d\n", info->irq_alarm, ret);
+               goto err_nortc;
+       }
 
-       /* Check RTC Time */
+       ret = devm_request_irq(&pdev->dev, info->irq_tick, s3c_rtc_tickirq,
+                         0,  "s3c2410-rtc tick", info);
+       if (ret) {
+               dev_err(&pdev->dev, "IRQ%d error %d\n", info->irq_tick, ret);
+               goto err_nortc;
+       }
 
-       s3c_rtc_gettime(NULL, &rtc_tm);
+       /* Check RTC Time */
+       s3c_rtc_gettime(&pdev->dev, &rtc_tm);
 
        if (rtc_valid_tm(&rtc_tm)) {
                rtc_tm.tm_year  = 100;
@@ -523,163 +586,312 @@ static int s3c_rtc_probe(struct platform_device *pdev)
                rtc_tm.tm_min   = 0;
                rtc_tm.tm_sec   = 0;
 
-               s3c_rtc_settime(NULL, &rtc_tm);
+               s3c_rtc_settime(&pdev->dev, &rtc_tm);
 
                dev_warn(&pdev->dev, "warning: invalid RTC value so initializing it\n");
        }
 
-       if (s3c_rtc_cpu_type != TYPE_S3C2410)
-               rtc->max_user_freq = 32768;
-       else
-               rtc->max_user_freq = 128;
-
-       if (s3c_rtc_cpu_type == TYPE_S3C2416 || s3c_rtc_cpu_type == TYPE_S3C2443) {
-               tmp = readw(s3c_rtc_base + S3C2410_RTCCON);
-               tmp |= S3C2443_RTCCON_TICSEL;
-               writew(tmp, s3c_rtc_base + S3C2410_RTCCON);
-       }
+       if (info->data->select_tick_clk)
+               info->data->select_tick_clk(info);
 
-       platform_set_drvdata(pdev, rtc);
+       s3c_rtc_setfreq(info, 1);
 
-       s3c_rtc_setfreq(&pdev->dev, 1);
-
-       ret = devm_request_irq(&pdev->dev, s3c_rtc_alarmno, s3c_rtc_alarmirq,
-                         0,  "s3c2410-rtc alarm", rtc);
-       if (ret) {
-               dev_err(&pdev->dev, "IRQ%d error %d\n", s3c_rtc_alarmno, ret);
-               goto err_nortc;
-       }
-
-       ret = devm_request_irq(&pdev->dev, s3c_rtc_tickno, s3c_rtc_tickirq,
-                         0,  "s3c2410-rtc tick", rtc);
-       if (ret) {
-               dev_err(&pdev->dev, "IRQ%d error %d\n", s3c_rtc_tickno, ret);
-               goto err_nortc;
-       }
-
-       clk_disable(rtc_clk);
+       if (info->data->needs_src_clk)
+               clk_disable(info->rtc_src_clk);
+       clk_disable(info->rtc_clk);
 
        return 0;
 
  err_nortc:
-       s3c_rtc_enable(pdev, 0);
-       clk_disable_unprepare(rtc_clk);
+       if (info->data->disable)
+               info->data->disable(info);
+       clk_disable_unprepare(info->rtc_clk);
 
        return ret;
 }
 
 #ifdef CONFIG_PM_SLEEP
-/* RTC Power management control */
-
-static int ticnt_save, ticnt_en_save;
-static bool wake_en;
 
 static int s3c_rtc_suspend(struct device *dev)
 {
-       struct platform_device *pdev = to_platform_device(dev);
+       struct s3c_rtc *info = dev_get_drvdata(dev);
+
+       clk_enable(info->rtc_clk);
+       if (info->data->needs_src_clk)
+               clk_enable(info->rtc_src_clk);
 
-       clk_enable(rtc_clk);
        /* save TICNT for anyone using periodic interrupts */
-       if (s3c_rtc_cpu_type == TYPE_S3C64XX) {
-               ticnt_en_save = readw(s3c_rtc_base + S3C2410_RTCCON);
-               ticnt_en_save &= S3C64XX_RTCCON_TICEN;
-               ticnt_save = readl(s3c_rtc_base + S3C2410_TICNT);
-       } else {
-               ticnt_save = readb(s3c_rtc_base + S3C2410_TICNT);
-       }
-       s3c_rtc_enable(pdev, 0);
+       if (info->data->save_tick_cnt)
+               info->data->save_tick_cnt(info);
+
+       if (info->data->disable)
+               info->data->disable(info);
 
-       if (device_may_wakeup(dev) && !wake_en) {
-               if (enable_irq_wake(s3c_rtc_alarmno) == 0)
-                       wake_en = true;
+       if (device_may_wakeup(dev) && !info->wake_en) {
+               if (enable_irq_wake(info->irq_alarm) == 0)
+                       info->wake_en = true;
                else
                        dev_err(dev, "enable_irq_wake failed\n");
        }
-       clk_disable(rtc_clk);
+
+       if (info->data->needs_src_clk)
+               clk_disable(info->rtc_src_clk);
+       clk_disable(info->rtc_clk);
 
        return 0;
 }
 
 static int s3c_rtc_resume(struct device *dev)
 {
-       struct platform_device *pdev = to_platform_device(dev);
-       unsigned int tmp;
+       struct s3c_rtc *info = dev_get_drvdata(dev);
 
-       clk_enable(rtc_clk);
-       s3c_rtc_enable(pdev, 1);
-       if (s3c_rtc_cpu_type == TYPE_S3C64XX) {
-               writel(ticnt_save, s3c_rtc_base + S3C2410_TICNT);
-               if (ticnt_en_save) {
-                       tmp = readw(s3c_rtc_base + S3C2410_RTCCON);
-                       writew(tmp | ticnt_en_save,
-                                       s3c_rtc_base + S3C2410_RTCCON);
-               }
-       } else {
-               writeb(ticnt_save, s3c_rtc_base + S3C2410_TICNT);
-       }
+       clk_enable(info->rtc_clk);
+       if (info->data->needs_src_clk)
+               clk_enable(info->rtc_src_clk);
 
-       if (device_may_wakeup(dev) && wake_en) {
-               disable_irq_wake(s3c_rtc_alarmno);
-               wake_en = false;
+       if (info->data->enable)
+               info->data->enable(info);
+
+       if (info->data->restore_tick_cnt)
+               info->data->restore_tick_cnt(info);
+
+       if (device_may_wakeup(dev) && info->wake_en) {
+               disable_irq_wake(info->irq_alarm);
+               info->wake_en = false;
        }
-       clk_disable(rtc_clk);
+
+       if (info->data->needs_src_clk)
+               clk_disable(info->rtc_src_clk);
+       clk_disable(info->rtc_clk);
 
        return 0;
 }
 #endif
-
 static SIMPLE_DEV_PM_OPS(s3c_rtc_pm_ops, s3c_rtc_suspend, s3c_rtc_resume);
 
-#ifdef CONFIG_OF
-static struct s3c_rtc_drv_data s3c_rtc_drv_data_array[] = {
-       [TYPE_S3C2410] = { TYPE_S3C2410 },
-       [TYPE_S3C2416] = { TYPE_S3C2416 },
-       [TYPE_S3C2443] = { TYPE_S3C2443 },
-       [TYPE_S3C64XX] = { TYPE_S3C64XX },
+static void s3c24xx_rtc_irq(struct s3c_rtc *info, int mask)
+{
+       clk_enable(info->rtc_clk);
+       if (info->data->needs_src_clk)
+               clk_enable(info->rtc_src_clk);
+       rtc_update_irq(info->rtc, 1, RTC_AF | RTC_IRQF);
+       if (info->data->needs_src_clk)
+               clk_disable(info->rtc_src_clk);
+       clk_disable(info->rtc_clk);
+
+       s3c_rtc_alarm_clk_enable(info, false);
+}
+
+static void s3c6410_rtc_irq(struct s3c_rtc *info, int mask)
+{
+       clk_enable(info->rtc_clk);
+       if (info->data->needs_src_clk)
+               clk_enable(info->rtc_src_clk);
+       rtc_update_irq(info->rtc, 1, RTC_AF | RTC_IRQF);
+       writeb(mask, info->base + S3C2410_INTP);
+       if (info->data->needs_src_clk)
+               clk_disable(info->rtc_src_clk);
+       clk_disable(info->rtc_clk);
+
+       s3c_rtc_alarm_clk_enable(info, false);
+}
+
+static void s3c2410_rtc_setfreq(struct s3c_rtc *info, int freq)
+{
+       unsigned int tmp = 0;
+       int val;
+
+       tmp = readb(info->base + S3C2410_TICNT);
+       tmp &= S3C2410_TICNT_ENABLE;
+
+       val = (info->rtc->max_user_freq / freq) - 1;
+       tmp |= val;
+
+       writel(tmp, info->base + S3C2410_TICNT);
+}
+
+static void s3c2416_rtc_setfreq(struct s3c_rtc *info, int freq)
+{
+       unsigned int tmp = 0;
+       int val;
+
+       tmp = readb(info->base + S3C2410_TICNT);
+       tmp &= S3C2410_TICNT_ENABLE;
+
+       val = (info->rtc->max_user_freq / freq) - 1;
+
+       tmp |= S3C2443_TICNT_PART(val);
+       writel(S3C2443_TICNT1_PART(val), info->base + S3C2443_TICNT1);
+
+       writel(S3C2416_TICNT2_PART(val), info->base + S3C2416_TICNT2);
+
+       writel(tmp, info->base + S3C2410_TICNT);
+}
+
+static void s3c2443_rtc_setfreq(struct s3c_rtc *info, int freq)
+{
+       unsigned int tmp = 0;
+       int val;
+
+       tmp = readb(info->base + S3C2410_TICNT);
+       tmp &= S3C2410_TICNT_ENABLE;
+
+       val = (info->rtc->max_user_freq / freq) - 1;
+
+       tmp |= S3C2443_TICNT_PART(val);
+       writel(S3C2443_TICNT1_PART(val), info->base + S3C2443_TICNT1);
+
+       writel(tmp, info->base + S3C2410_TICNT);
+}
+
+static void s3c6410_rtc_setfreq(struct s3c_rtc *info, int freq)
+{
+       int val;
+
+       val = (info->rtc->max_user_freq / freq) - 1;
+       writel(val, info->base + S3C2410_TICNT);
+}
+
+static void s3c24xx_rtc_enable_tick(struct s3c_rtc *info, struct seq_file *seq)
+{
+       unsigned int ticnt;
+
+       ticnt = readb(info->base + S3C2410_TICNT);
+       ticnt &= S3C2410_TICNT_ENABLE;
+
+       seq_printf(seq, "periodic_IRQ\t: %s\n", ticnt  ? "yes" : "no");
+}
+
+static void s3c2416_rtc_select_tick_clk(struct s3c_rtc *info)
+{
+       unsigned int con;
+
+       con = readw(info->base + S3C2410_RTCCON);
+       con |= S3C2443_RTCCON_TICSEL;
+       writew(con, info->base + S3C2410_RTCCON);
+}
+
+static void s3c6410_rtc_enable_tick(struct s3c_rtc *info, struct seq_file *seq)
+{
+       unsigned int ticnt;
+
+       ticnt = readw(info->base + S3C2410_RTCCON);
+       ticnt &= S3C64XX_RTCCON_TICEN;
+
+       seq_printf(seq, "periodic_IRQ\t: %s\n", ticnt  ? "yes" : "no");
+}
+
+static void s3c24xx_rtc_save_tick_cnt(struct s3c_rtc *info)
+{
+       info->ticnt_save = readb(info->base + S3C2410_TICNT);
+}
+
+static void s3c24xx_rtc_restore_tick_cnt(struct s3c_rtc *info)
+{
+       writeb(info->ticnt_save, info->base + S3C2410_TICNT);
+}
+
+static void s3c6410_rtc_save_tick_cnt(struct s3c_rtc *info)
+{
+       info->ticnt_en_save = readw(info->base + S3C2410_RTCCON);
+       info->ticnt_en_save &= S3C64XX_RTCCON_TICEN;
+       info->ticnt_save = readl(info->base + S3C2410_TICNT);
+}
+
+static void s3c6410_rtc_restore_tick_cnt(struct s3c_rtc *info)
+{
+       unsigned int con;
+
+       writel(info->ticnt_save, info->base + S3C2410_TICNT);
+       if (info->ticnt_en_save) {
+               con = readw(info->base + S3C2410_RTCCON);
+               writew(con | info->ticnt_en_save,
+                               info->base + S3C2410_RTCCON);
+       }
+}
+
+static struct s3c_rtc_data const s3c2410_rtc_data = {
+       .max_user_freq          = 128,
+       .irq_handler            = s3c24xx_rtc_irq,
+       .set_freq               = s3c2410_rtc_setfreq,
+       .enable_tick            = s3c24xx_rtc_enable_tick,
+       .save_tick_cnt          = s3c24xx_rtc_save_tick_cnt,
+       .restore_tick_cnt       = s3c24xx_rtc_restore_tick_cnt,
+       .enable                 = s3c24xx_rtc_enable,
+       .disable                = s3c24xx_rtc_disable,
+};
+
+static struct s3c_rtc_data const s3c2416_rtc_data = {
+       .max_user_freq          = 32768,
+       .irq_handler            = s3c24xx_rtc_irq,
+       .set_freq               = s3c2416_rtc_setfreq,
+       .enable_tick            = s3c24xx_rtc_enable_tick,
+       .select_tick_clk        = s3c2416_rtc_select_tick_clk,
+       .save_tick_cnt          = s3c24xx_rtc_save_tick_cnt,
+       .restore_tick_cnt       = s3c24xx_rtc_restore_tick_cnt,
+       .enable                 = s3c24xx_rtc_enable,
+       .disable                = s3c24xx_rtc_disable,
+};
+
+static struct s3c_rtc_data const s3c2443_rtc_data = {
+       .max_user_freq          = 32768,
+       .irq_handler            = s3c24xx_rtc_irq,
+       .set_freq               = s3c2443_rtc_setfreq,
+       .enable_tick            = s3c24xx_rtc_enable_tick,
+       .select_tick_clk        = s3c2416_rtc_select_tick_clk,
+       .save_tick_cnt          = s3c24xx_rtc_save_tick_cnt,
+       .restore_tick_cnt       = s3c24xx_rtc_restore_tick_cnt,
+       .enable                 = s3c24xx_rtc_enable,
+       .disable                = s3c24xx_rtc_disable,
+};
+
+static struct s3c_rtc_data const s3c6410_rtc_data = {
+       .max_user_freq          = 32768,
+       .irq_handler            = s3c6410_rtc_irq,
+       .set_freq               = s3c6410_rtc_setfreq,
+       .enable_tick            = s3c6410_rtc_enable_tick,
+       .save_tick_cnt          = s3c6410_rtc_save_tick_cnt,
+       .restore_tick_cnt       = s3c6410_rtc_restore_tick_cnt,
+       .enable                 = s3c24xx_rtc_enable,
+       .disable                = s3c6410_rtc_disable,
+};
+
+static struct s3c_rtc_data const exynos3250_rtc_data = {
+       .max_user_freq          = 32768,
+       .needs_src_clk          = true,
+       .irq_handler            = s3c6410_rtc_irq,
+       .set_freq               = s3c6410_rtc_setfreq,
+       .enable_tick            = s3c6410_rtc_enable_tick,
+       .save_tick_cnt          = s3c6410_rtc_save_tick_cnt,
+       .restore_tick_cnt       = s3c6410_rtc_restore_tick_cnt,
+       .enable                 = s3c24xx_rtc_enable,
+       .disable                = s3c6410_rtc_disable,
 };
 
 static const struct of_device_id s3c_rtc_dt_match[] = {
        {
                .compatible = "samsung,s3c2410-rtc",
-               .data = &s3c_rtc_drv_data_array[TYPE_S3C2410],
+               .data = (void *)&s3c2410_rtc_data,
        }, {
                .compatible = "samsung,s3c2416-rtc",
-               .data = &s3c_rtc_drv_data_array[TYPE_S3C2416],
+               .data = (void *)&s3c2416_rtc_data,
        }, {
                .compatible = "samsung,s3c2443-rtc",
-               .data = &s3c_rtc_drv_data_array[TYPE_S3C2443],
+               .data = (void *)&s3c2443_rtc_data,
        }, {
                .compatible = "samsung,s3c6410-rtc",
-               .data = &s3c_rtc_drv_data_array[TYPE_S3C64XX],
-       },
-       {},
-};
-MODULE_DEVICE_TABLE(of, s3c_rtc_dt_match);
-#endif
-
-static struct platform_device_id s3c_rtc_driver_ids[] = {
-       {
-               .name           = "s3c2410-rtc",
-               .driver_data    = TYPE_S3C2410,
-       }, {
-               .name           = "s3c2416-rtc",
-               .driver_data    = TYPE_S3C2416,
-       }, {
-               .name           = "s3c2443-rtc",
-               .driver_data    = TYPE_S3C2443,
+               .data = (void *)&s3c6410_rtc_data,
        }, {
-               .name           = "s3c64xx-rtc",
-               .driver_data    = TYPE_S3C64XX,
+               .compatible = "samsung,exynos3250-rtc",
+               .data = (void *)&exynos3250_rtc_data,
        },
-       { }
+       { /* sentinel */ },
 };
-
-MODULE_DEVICE_TABLE(platform, s3c_rtc_driver_ids);
+MODULE_DEVICE_TABLE(of, s3c_rtc_dt_match);
 
 static struct platform_driver s3c_rtc_driver = {
        .probe          = s3c_rtc_probe,
        .remove         = s3c_rtc_remove,
-       .id_table       = s3c_rtc_driver_ids,
        .driver         = {
                .name   = "s3c-rtc",
                .owner  = THIS_MODULE,
@@ -687,7 +899,6 @@ static struct platform_driver s3c_rtc_driver = {
                .of_match_table = of_match_ptr(s3c_rtc_dt_match),
        },
 };
-
 module_platform_driver(s3c_rtc_driver);
 
 MODULE_DESCRIPTION("Samsung S3C RTC Driver");
index 5df05f26b7d9d966fc35a3fab397afbc33b53f7b..329db997ee6680fc931897b04a01495209df66d2 100644 (file)
@@ -1660,6 +1660,14 @@ void dasd_int_handler(struct ccw_device *cdev, unsigned long intparm,
                device->discipline->check_for_device_change(device, cqr, irb);
                dasd_put_device(device);
        }
+
+       /* check for for attention message */
+       if (scsw_dstat(&irb->scsw) & DEV_STAT_ATTENTION) {
+               device = dasd_device_from_cdev_locked(cdev);
+               device->discipline->check_attention(device, irb->esw.esw1.lpum);
+               dasd_put_device(device);
+       }
+
        if (!cqr)
                return;
 
@@ -2261,8 +2269,8 @@ static inline int _wait_for_wakeup_queue(struct list_head *ccw_queue)
 static int _dasd_sleep_on_queue(struct list_head *ccw_queue, int interruptible)
 {
        struct dasd_device *device;
-       int rc;
        struct dasd_ccw_req *cqr, *n;
+       int rc;
 
 retry:
        list_for_each_entry_safe(cqr, n, ccw_queue, blocklist) {
@@ -2310,21 +2318,26 @@ retry:
                /*
                 * for alias devices simplify error recovery and
                 * return to upper layer
+                * do not skip ERP requests
                 */
-               if (cqr->startdev != cqr->basedev &&
+               if (cqr->startdev != cqr->basedev && !cqr->refers &&
                    (cqr->status == DASD_CQR_TERMINATED ||
                     cqr->status == DASD_CQR_NEED_ERP))
                        return -EAGAIN;
-               else {
-                       /* normal recovery for basedev IO */
-                       if (__dasd_sleep_on_erp(cqr)) {
-                               if (!cqr->status == DASD_CQR_TERMINATED &&
-                                   !cqr->status == DASD_CQR_NEED_ERP)
-                                       break;
-                               rc = 1;
-                       }
+
+               /* normal recovery for basedev IO */
+               if (__dasd_sleep_on_erp(cqr)) {
+                       goto retry;
+                       /* remember that ERP was needed */
+                       rc = 1;
+                       /* skip processing for active cqr */
+                       if (cqr->status != DASD_CQR_TERMINATED &&
+                           cqr->status != DASD_CQR_NEED_ERP)
+                               break;
                }
        }
+
+       /* start ERP requests in upper loop */
        if (rc)
                goto retry;
 
index 14ba80bfa571bc4b34eb795c85f6725b96f6ad7b..8286f742436b7b75f40638c77f9414b76b0d45a9 100644 (file)
@@ -1432,6 +1432,29 @@ static ssize_t dasd_reservation_state_store(struct device *dev,
 static DEVICE_ATTR(last_known_reservation_state, 0644,
                   dasd_reservation_state_show, dasd_reservation_state_store);
 
+static ssize_t dasd_pm_show(struct device *dev,
+                             struct device_attribute *attr, char *buf)
+{
+       struct dasd_device *device;
+       u8 opm, nppm, cablepm, cuirpm, hpfpm;
+
+       device = dasd_device_from_cdev(to_ccwdev(dev));
+       if (IS_ERR(device))
+               return sprintf(buf, "0\n");
+
+       opm = device->path_data.opm;
+       nppm = device->path_data.npm;
+       cablepm = device->path_data.cablepm;
+       cuirpm = device->path_data.cuirpm;
+       hpfpm = device->path_data.hpfpm;
+       dasd_put_device(device);
+
+       return sprintf(buf, "%02x %02x %02x %02x %02x\n", opm, nppm,
+                      cablepm, cuirpm, hpfpm);
+}
+
+static DEVICE_ATTR(path_masks, 0444, dasd_pm_show, NULL);
+
 static struct attribute * dasd_attrs[] = {
        &dev_attr_readonly.attr,
        &dev_attr_discipline.attr,
@@ -1450,6 +1473,7 @@ static struct attribute * dasd_attrs[] = {
        &dev_attr_reservation_policy.attr,
        &dev_attr_last_known_reservation_state.attr,
        &dev_attr_safe_offline.attr,
+       &dev_attr_path_masks.attr,
        NULL,
 };
 
index 51dea7baf02c01b9ce38463491b3b9ba101de2d2..d47f5b99623a1e4913f6a8d1b9571e18cf5968f1 100644 (file)
@@ -29,6 +29,8 @@
 #include <asm/cio.h>
 #include <asm/ccwdev.h>
 #include <asm/itcw.h>
+#include <asm/schid.h>
+#include <asm/chpid.h>
 
 #include "dasd_int.h"
 #include "dasd_eckd.h"
@@ -112,6 +114,12 @@ struct path_verification_work_data {
 static struct path_verification_work_data *path_verification_worker;
 static DEFINE_MUTEX(dasd_path_verification_mutex);
 
+struct check_attention_work_data {
+       struct work_struct worker;
+       struct dasd_device *device;
+       __u8 lpum;
+};
+
 /* initial attempt at a probe function. this can be simplified once
  * the other detection code is gone */
 static int
@@ -1126,6 +1134,7 @@ static int dasd_eckd_read_conf(struct dasd_device *device)
                                        "device %s instead of %s\n", lpm,
                                        print_path_uid, print_device_uid);
                                path_err = -EINVAL;
+                               path_data->cablepm |= lpm;
                                continue;
                        }
 
@@ -1141,6 +1150,13 @@ static int dasd_eckd_read_conf(struct dasd_device *device)
                        break;
                }
                path_data->opm |= lpm;
+               /*
+                * if the path is used
+                * it should not be in one of the negative lists
+                */
+               path_data->cablepm &= ~lpm;
+               path_data->hpfpm &= ~lpm;
+               path_data->cuirpm &= ~lpm;
 
                if (conf_data != private->conf_data)
                        kfree(conf_data);
@@ -1230,7 +1246,7 @@ static void do_path_verification_work(struct work_struct *work)
        struct dasd_eckd_private path_private;
        struct dasd_uid *uid;
        __u8 path_rcd_buf[DASD_ECKD_RCD_DATA_SIZE];
-       __u8 lpm, opm, npm, ppm, epm;
+       __u8 lpm, opm, npm, ppm, epm, hpfpm, cablepm;
        unsigned long flags;
        char print_uid[60];
        int rc;
@@ -1248,6 +1264,9 @@ static void do_path_verification_work(struct work_struct *work)
        npm = 0;
        ppm = 0;
        epm = 0;
+       hpfpm = 0;
+       cablepm = 0;
+
        for (lpm = 0x80; lpm; lpm >>= 1) {
                if (!(lpm & data->tbvpm))
                        continue;
@@ -1289,6 +1308,7 @@ static void do_path_verification_work(struct work_struct *work)
                        opm &= ~lpm;
                        npm &= ~lpm;
                        ppm &= ~lpm;
+                       hpfpm |= lpm;
                        continue;
                }
 
@@ -1350,6 +1370,7 @@ static void do_path_verification_work(struct work_struct *work)
                                opm &= ~lpm;
                                npm &= ~lpm;
                                ppm &= ~lpm;
+                               cablepm |= lpm;
                                continue;
                        }
                }
@@ -1364,12 +1385,21 @@ static void do_path_verification_work(struct work_struct *work)
                spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags);
                if (!device->path_data.opm && opm) {
                        device->path_data.opm = opm;
+                       device->path_data.cablepm &= ~opm;
+                       device->path_data.cuirpm &= ~opm;
+                       device->path_data.hpfpm &= ~opm;
                        dasd_generic_path_operational(device);
-               } else
+               } else {
                        device->path_data.opm |= opm;
+                       device->path_data.cablepm &= ~opm;
+                       device->path_data.cuirpm &= ~opm;
+                       device->path_data.hpfpm &= ~opm;
+               }
                device->path_data.npm |= npm;
                device->path_data.ppm |= ppm;
                device->path_data.tbvpm |= epm;
+               device->path_data.cablepm |= cablepm;
+               device->path_data.hpfpm |= hpfpm;
                spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags);
        }
 
@@ -4475,6 +4505,343 @@ out_err:
        return -1;
 }
 
+static int dasd_eckd_read_message_buffer(struct dasd_device *device,
+                                        struct dasd_rssd_messages *messages,
+                                        __u8 lpum)
+{
+       struct dasd_rssd_messages *message_buf;
+       struct dasd_psf_prssd_data *prssdp;
+       struct dasd_eckd_private *private;
+       struct dasd_ccw_req *cqr;
+       struct ccw1 *ccw;
+       int rc;
+
+       private = (struct dasd_eckd_private *) device->private;
+       cqr = dasd_smalloc_request(DASD_ECKD_MAGIC, 1 /* PSF */ + 1 /* RSSD */,
+                                  (sizeof(struct dasd_psf_prssd_data) +
+                                   sizeof(struct dasd_rssd_messages)),
+                                  device);
+       if (IS_ERR(cqr)) {
+               DBF_EVENT_DEVID(DBF_WARNING, device->cdev, "%s",
+                               "Could not allocate read message buffer request");
+               return PTR_ERR(cqr);
+       }
+
+       cqr->startdev = device;
+       cqr->memdev = device;
+       cqr->block = NULL;
+       cqr->retries = 256;
+       cqr->expires = 10 * HZ;
+
+       /* we need to check for messages on exactly this path */
+       set_bit(DASD_CQR_VERIFY_PATH, &cqr->flags);
+       cqr->lpm = lpum;
+
+       /* Prepare for Read Subsystem Data */
+       prssdp = (struct dasd_psf_prssd_data *) cqr->data;
+       memset(prssdp, 0, sizeof(struct dasd_psf_prssd_data));
+       prssdp->order = PSF_ORDER_PRSSD;
+       prssdp->suborder = 0x03;        /* Message Buffer */
+       /* all other bytes of prssdp must be zero */
+
+       ccw = cqr->cpaddr;
+       ccw->cmd_code = DASD_ECKD_CCW_PSF;
+       ccw->count = sizeof(struct dasd_psf_prssd_data);
+       ccw->flags |= CCW_FLAG_CC;
+       ccw->flags |= CCW_FLAG_SLI;
+       ccw->cda = (__u32)(addr_t) prssdp;
+
+       /* Read Subsystem Data - message buffer */
+       message_buf = (struct dasd_rssd_messages *) (prssdp + 1);
+       memset(message_buf, 0, sizeof(struct dasd_rssd_messages));
+
+       ccw++;
+       ccw->cmd_code = DASD_ECKD_CCW_RSSD;
+       ccw->count = sizeof(struct dasd_rssd_messages);
+       ccw->flags |= CCW_FLAG_SLI;
+       ccw->cda = (__u32)(addr_t) message_buf;
+
+       cqr->buildclk = get_tod_clock();
+       cqr->status = DASD_CQR_FILLED;
+       rc = dasd_sleep_on_immediatly(cqr);
+       if (rc == 0) {
+               prssdp = (struct dasd_psf_prssd_data *) cqr->data;
+               message_buf = (struct dasd_rssd_messages *)
+                       (prssdp + 1);
+               memcpy(messages, message_buf,
+                      sizeof(struct dasd_rssd_messages));
+       } else
+               DBF_EVENT_DEVID(DBF_WARNING, device->cdev,
+                               "Reading messages failed with rc=%d\n"
+                               , rc);
+       dasd_sfree_request(cqr, cqr->memdev);
+       return rc;
+}
+
+/*
+ * Perform Subsystem Function - CUIR response
+ */
+static int
+dasd_eckd_psf_cuir_response(struct dasd_device *device, int response,
+                           __u32 message_id,
+                           struct channel_path_desc *desc,
+                           struct subchannel_id sch_id)
+{
+       struct dasd_psf_cuir_response *psf_cuir;
+       struct dasd_ccw_req *cqr;
+       struct ccw1 *ccw;
+       int rc;
+
+       cqr = dasd_smalloc_request(DASD_ECKD_MAGIC, 1 /* PSF */ ,
+                                 sizeof(struct dasd_psf_cuir_response),
+                                 device);
+
+       if (IS_ERR(cqr)) {
+               DBF_DEV_EVENT(DBF_WARNING, device, "%s",
+                          "Could not allocate PSF-CUIR request");
+               return PTR_ERR(cqr);
+       }
+
+       psf_cuir = (struct dasd_psf_cuir_response *)cqr->data;
+       psf_cuir->order = PSF_ORDER_CUIR_RESPONSE;
+       psf_cuir->cc = response;
+       if (desc)
+               psf_cuir->chpid = desc->chpid;
+       psf_cuir->message_id = message_id;
+       psf_cuir->cssid = sch_id.cssid;
+       psf_cuir->ssid = sch_id.ssid;
+
+       ccw = cqr->cpaddr;
+       ccw->cmd_code = DASD_ECKD_CCW_PSF;
+       ccw->cda = (__u32)(addr_t)psf_cuir;
+       ccw->count = sizeof(struct dasd_psf_cuir_response);
+
+       cqr->startdev = device;
+       cqr->memdev = device;
+       cqr->block = NULL;
+       cqr->retries = 256;
+       cqr->expires = 10*HZ;
+       cqr->buildclk = get_tod_clock();
+       cqr->status = DASD_CQR_FILLED;
+
+       rc = dasd_sleep_on(cqr);
+
+       dasd_sfree_request(cqr, cqr->memdev);
+       return rc;
+}
+
+static int dasd_eckd_cuir_change_state(struct dasd_device *device, __u8 lpum)
+{
+       unsigned long flags;
+       __u8 tbcpm;
+
+       spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags);
+       tbcpm = device->path_data.opm & ~lpum;
+       if (tbcpm) {
+               device->path_data.opm = tbcpm;
+               device->path_data.cuirpm |= lpum;
+       }
+       spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags);
+       return tbcpm ? 0 : PSF_CUIR_LAST_PATH;
+}
+
+/*
+ * walk through all devices and quiesce them
+ * if it is the last path return error
+ *
+ * if only part of the devices are quiesced and an error
+ * occurs no onlining necessary, the storage server will
+ * notify the already set offline devices again
+ */
+static int dasd_eckd_cuir_quiesce(struct dasd_device *device, __u8 lpum,
+                                struct channel_path_desc *desc,
+                                struct subchannel_id sch_id)
+{
+       struct alias_pav_group *pavgroup, *tempgroup;
+       struct dasd_eckd_private *private;
+       struct dasd_device *dev, *n;
+       int rc;
+
+       private = (struct dasd_eckd_private *) device->private;
+       rc = 0;
+
+       /* active devices */
+       list_for_each_entry_safe(dev, n,
+                                &private->lcu->active_devices,
+                                alias_list) {
+               rc = dasd_eckd_cuir_change_state(dev, lpum);
+               if (rc)
+                       goto out;
+       }
+
+       /* inactive devices */
+       list_for_each_entry_safe(dev, n,
+                                &private->lcu->inactive_devices,
+                                alias_list) {
+               rc = dasd_eckd_cuir_change_state(dev, lpum);
+               if (rc)
+                       goto out;
+       }
+
+       /* devices in PAV groups */
+       list_for_each_entry_safe(pavgroup, tempgroup,
+                                &private->lcu->grouplist, group) {
+               list_for_each_entry_safe(dev, n, &pavgroup->baselist,
+                                        alias_list) {
+                       rc = dasd_eckd_cuir_change_state(dev, lpum);
+                       if (rc)
+                               goto out;
+               }
+               list_for_each_entry_safe(dev, n, &pavgroup->aliaslist,
+                                        alias_list) {
+                       rc = dasd_eckd_cuir_change_state(dev, lpum);
+                       if (rc)
+                               goto out;
+               }
+       }
+
+       pr_warn("Service on the storage server caused path %x.%02x to go offline",
+               sch_id.cssid, desc ? desc->chpid : 0);
+       rc = PSF_CUIR_COMPLETED;
+out:
+       return rc;
+}
+
+static int dasd_eckd_cuir_resume(struct dasd_device *device, __u8 lpum,
+                                struct channel_path_desc *desc,
+                                struct subchannel_id sch_id)
+{
+       struct alias_pav_group *pavgroup, *tempgroup;
+       struct dasd_eckd_private *private;
+       struct dasd_device *dev, *n;
+
+       pr_info("Path %x.%02x is back online after service on the storage server",
+               sch_id.cssid, desc ? desc->chpid : 0);
+       private = (struct dasd_eckd_private *) device->private;
+
+       /*
+        * the path may have been added through a generic path event before
+        * only trigger path verification if the path is not already in use
+        */
+
+       list_for_each_entry_safe(dev, n,
+                                &private->lcu->active_devices,
+                                alias_list) {
+               if (!(dev->path_data.opm & lpum)) {
+                       dev->path_data.tbvpm |= lpum;
+                       dasd_schedule_device_bh(dev);
+               }
+       }
+
+       list_for_each_entry_safe(dev, n,
+                                &private->lcu->inactive_devices,
+                                alias_list) {
+               if (!(dev->path_data.opm & lpum)) {
+                       dev->path_data.tbvpm |= lpum;
+                       dasd_schedule_device_bh(dev);
+               }
+       }
+
+       /* devices in PAV groups */
+       list_for_each_entry_safe(pavgroup, tempgroup,
+                                &private->lcu->grouplist,
+                                group) {
+               list_for_each_entry_safe(dev, n,
+                                        &pavgroup->baselist,
+                                        alias_list) {
+                       if (!(dev->path_data.opm & lpum)) {
+                               dev->path_data.tbvpm |= lpum;
+                               dasd_schedule_device_bh(dev);
+                       }
+               }
+               list_for_each_entry_safe(dev, n,
+                                        &pavgroup->aliaslist,
+                                        alias_list) {
+                       if (!(dev->path_data.opm & lpum)) {
+                               dev->path_data.tbvpm |= lpum;
+                               dasd_schedule_device_bh(dev);
+                       }
+               }
+       }
+       return PSF_CUIR_COMPLETED;
+}
+
+static void dasd_eckd_handle_cuir(struct dasd_device *device, void *messages,
+                                __u8 lpum)
+{
+       struct dasd_cuir_message *cuir = messages;
+       struct channel_path_desc *desc;
+       struct subchannel_id sch_id;
+       int pos, response;
+       ccw_device_get_schid(device->cdev, &sch_id);
+
+       /* get position of path in mask */
+       pos = 8 - ffs(lpum);
+       /* get channel path descriptor from this position */
+       desc = ccw_device_get_chp_desc(device->cdev, pos);
+
+       if (cuir->code == CUIR_QUIESCE) {
+               /* quiesce */
+               response = dasd_eckd_cuir_quiesce(device, lpum, desc, sch_id);
+       } else if (cuir->code == CUIR_RESUME) {
+               /* resume */
+               response = dasd_eckd_cuir_resume(device, lpum, desc, sch_id);
+       } else
+               response = PSF_CUIR_NOT_SUPPORTED;
+
+       dasd_eckd_psf_cuir_response(device, response, cuir->message_id,
+                                   desc, sch_id);
+
+       /* free descriptor copy */
+       kfree(desc);
+}
+
+static void dasd_eckd_check_attention_work(struct work_struct *work)
+{
+       struct check_attention_work_data *data;
+       struct dasd_rssd_messages *messages;
+       struct dasd_device *device;
+       int rc;
+
+       data = container_of(work, struct check_attention_work_data, worker);
+       device = data->device;
+
+       messages = kzalloc(sizeof(*messages), GFP_KERNEL);
+       if (!messages) {
+               DBF_DEV_EVENT(DBF_WARNING, device, "%s",
+                             "Could not allocate attention message buffer");
+               goto out;
+       }
+
+       rc = dasd_eckd_read_message_buffer(device, messages, data->lpum);
+       if (rc)
+               goto out;
+
+       if (messages->length == ATTENTION_LENGTH_CUIR &&
+           messages->format == ATTENTION_FORMAT_CUIR)
+               dasd_eckd_handle_cuir(device, messages, data->lpum);
+
+out:
+       dasd_put_device(device);
+       kfree(messages);
+       kfree(data);
+}
+
+static int dasd_eckd_check_attention(struct dasd_device *device, __u8 lpum)
+{
+       struct check_attention_work_data *data;
+
+       data = kzalloc(sizeof(*data), GFP_ATOMIC);
+       if (!data)
+               return -ENOMEM;
+       INIT_WORK(&data->worker, dasd_eckd_check_attention_work);
+       dasd_get_device(device);
+       data->device = device;
+       data->lpum = lpum;
+       schedule_work(&data->worker);
+       return 0;
+}
+
 static struct ccw_driver dasd_eckd_driver = {
        .driver = {
                .name   = "dasd-eckd",
@@ -4539,6 +4906,7 @@ static struct dasd_discipline dasd_eckd_discipline = {
        .reload = dasd_eckd_reload_device,
        .get_uid = dasd_eckd_get_uid,
        .kick_validate = dasd_eckd_kick_validate_server,
+       .check_attention = dasd_eckd_check_attention,
 };
 
 static int __init
index 2555e494591ff57f6e75202f46ae8b4ea61ee9e8..ddab7df36e25dddd0b471f1a71525a7282e975e5 100644 (file)
 /*
  * Perform Subsystem Function / Sub-Orders
  */
-#define PSF_ORDER_PRSSD 0x18
-#define PSF_ORDER_SSC  0x1D
+#define PSF_ORDER_PRSSD                         0x18
+#define PSF_ORDER_CUIR_RESPONSE                 0x1A
+#define PSF_ORDER_SSC                   0x1D
+
+/*
+ * CUIR response condition codes
+ */
+#define PSF_CUIR_INVALID                0x00
+#define PSF_CUIR_COMPLETED              0x01
+#define PSF_CUIR_NOT_SUPPORTED          0x02
+#define PSF_CUIR_ERROR_IN_REQ           0x03
+#define PSF_CUIR_DENIED                         0x04
+#define PSF_CUIR_LAST_PATH              0x05
+#define PSF_CUIR_DEVICE_ONLINE          0x06
+#define PSF_CUIR_VARY_FAILURE           0x07
+#define PSF_CUIR_SOFTWARE_FAILURE       0x08
+#define PSF_CUIR_NOT_RECOGNIZED                 0x09
+
+/*
+ * CUIR codes
+ */
+#define CUIR_QUIESCE                    0x01
+#define CUIR_RESUME                     0x02
+
+/*
+ * attention message definitions
+ */
+#define ATTENTION_LENGTH_CUIR           0x0e
+#define ATTENTION_FORMAT_CUIR           0x01
 
 /*
  * Size that is reportet for large volumes in the old 16-bit no_cyl field
@@ -342,6 +369,38 @@ struct dasd_rssd_features {
        char feature[256];
 } __attribute__((packed));
 
+struct dasd_rssd_messages {
+       __u16 length;
+       __u8 format;
+       __u8 code;
+       __u32 message_id;
+       __u8 flags;
+       char messages[4087];
+} __packed;
+
+struct dasd_cuir_message {
+       __u16 length;
+       __u8 format;
+       __u8 code;
+       __u32 message_id;
+       __u8 flags;
+       __u8 neq_map[3];
+       __u8 ned_map;
+       __u8 record_selector;
+} __packed;
+
+struct dasd_psf_cuir_response {
+       __u8 order;
+       __u8 flags;
+       __u8 cc;
+       __u8 chpid;
+       __u16 device_nr;
+       __u16 reserved;
+       __u32 message_id;
+       __u64 system_id;
+       __u8 cssid;
+       __u8 ssid;
+} __packed;
 
 /*
  * Perform Subsystem Function - Prepare for Read Subsystem Data
index c20170166909fbf55fc9abefc1140245c14ad3ed..8b5d4100abf7c75107b61ce02ed7e7d10c252f81 100644 (file)
@@ -357,6 +357,7 @@ struct dasd_discipline {
 
        int (*get_uid) (struct dasd_device *, struct dasd_uid *);
        void (*kick_validate) (struct dasd_device *);
+       int (*check_attention)(struct dasd_device *, __u8);
 };
 
 extern struct dasd_discipline *dasd_diag_discipline_pointer;
@@ -382,6 +383,10 @@ struct dasd_path {
        __u8 tbvpm;
        __u8 ppm;
        __u8 npm;
+       /* paths that are not used because of a special condition */
+       __u8 cablepm; /* miss-cabled */
+       __u8 hpfpm;   /* the HPF requirements of the other paths are not met */
+       __u8 cuirpm;  /* CUIR varied offline */
 };
 
 struct dasd_profile_info {
@@ -501,7 +506,10 @@ struct dasd_block {
        struct dasd_profile profile;
 };
 
-
+struct dasd_attention_data {
+       struct dasd_device *device;
+       __u8 lpum;
+};
 
 /* reasons why device (ccw_device_start) was stopped */
 #define DASD_STOPPED_NOT_ACC 1         /* not accessible */
index 71bf959732fe0112823ca12fc9ed4ee388274ce8..dc24ecfac2d1600cb5cc4364a7e883c6d6368812 100644 (file)
@@ -102,6 +102,19 @@ config SCLP_ASYNC
          want for inform other people about your kernel panics,
          need this feature and intend to run your kernel in LPAR.
 
+config HMC_DRV
+       def_tristate m
+       prompt "Support for file transfers from HMC drive CD/DVD-ROM"
+       depends on 64BIT
+       select CRC16
+       help
+         This option enables support for file transfers from a Hardware
+         Management Console (HMC) drive CD/DVD-ROM. It is available as a
+         module, called 'hmcdrv', and also as kernel built-in. There is one
+         optional parameter for this module: cachesize=N, which modifies the
+         transfer cache size from it's default value 0.5MB to N bytes. If N
+         is zero, then no caching is performed.
+
 config S390_TAPE
        def_tristate m
        prompt "S/390 tape device support"
index 78b6ace7edcbae024467e251e8900f7617626b8e..6fa9364d1c079050fc82062ec14d45bf78e476b5 100644 (file)
@@ -33,3 +33,6 @@ obj-$(CONFIG_S390_VMUR) += vmur.o
 
 zcore_mod-objs := sclp_sdias.o zcore.o
 obj-$(CONFIG_CRASH_DUMP) += zcore_mod.o
+
+hmcdrv-objs := hmcdrv_mod.o hmcdrv_dev.o hmcdrv_ftp.o hmcdrv_cache.o diag_ftp.o sclp_ftp.o
+obj-$(CONFIG_HMC_DRV) += hmcdrv.o
diff --git a/drivers/s390/char/diag_ftp.c b/drivers/s390/char/diag_ftp.c
new file mode 100644 (file)
index 0000000..9388963
--- /dev/null
@@ -0,0 +1,237 @@
+/*
+ *    DIAGNOSE X'2C4' instruction based HMC FTP services, useable on z/VM
+ *
+ *    Copyright IBM Corp. 2013
+ *    Author(s): Ralf Hoppe (rhoppe@de.ibm.com)
+ *
+ */
+
+#define KMSG_COMPONENT "hmcdrv"
+#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
+
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/irq.h>
+#include <linux/wait.h>
+#include <linux/string.h>
+#include <asm/ctl_reg.h>
+
+#include "hmcdrv_ftp.h"
+#include "diag_ftp.h"
+
+/* DIAGNOSE X'2C4' return codes in Ry */
+#define DIAG_FTP_RET_OK        0 /* HMC FTP started successfully */
+#define DIAG_FTP_RET_EBUSY     4 /* HMC FTP service currently busy */
+#define DIAG_FTP_RET_EIO       8 /* HMC FTP service I/O error */
+/* and an artificial extension */
+#define DIAG_FTP_RET_EPERM     2 /* HMC FTP service privilege error */
+
+/* FTP service status codes (after INTR at guest real location 133) */
+#define DIAG_FTP_STAT_OK       0U /* request completed successfully */
+#define DIAG_FTP_STAT_PGCC     4U /* program check condition */
+#define DIAG_FTP_STAT_PGIOE    8U /* paging I/O error */
+#define DIAG_FTP_STAT_TIMEOUT  12U /* timeout */
+#define DIAG_FTP_STAT_EBASE    16U /* base of error codes from SCLP */
+#define DIAG_FTP_STAT_LDFAIL   (DIAG_FTP_STAT_EBASE + 1U) /* failed */
+#define DIAG_FTP_STAT_LDNPERM  (DIAG_FTP_STAT_EBASE + 2U) /* not allowed */
+#define DIAG_FTP_STAT_LDRUNS   (DIAG_FTP_STAT_EBASE + 3U) /* runs */
+#define DIAG_FTP_STAT_LDNRUNS  (DIAG_FTP_STAT_EBASE + 4U) /* not runs */
+
+/**
+ * struct diag_ftp_ldfpl - load file FTP parameter list (LDFPL)
+ * @bufaddr: real buffer address (at 4k boundary)
+ * @buflen: length of buffer
+ * @offset: dir/file offset
+ * @intparm: interruption parameter (unused)
+ * @transferred: bytes transferred
+ * @fsize: file size, filled on GET
+ * @failaddr: failing address
+ * @spare: padding
+ * @fident: file name - ASCII
+ */
+struct diag_ftp_ldfpl {
+       u64 bufaddr;
+       u64 buflen;
+       u64 offset;
+       u64 intparm;
+       u64 transferred;
+       u64 fsize;
+       u64 failaddr;
+       u64 spare;
+       u8 fident[HMCDRV_FTP_FIDENT_MAX];
+} __packed;
+
+static DECLARE_COMPLETION(diag_ftp_rx_complete);
+static int diag_ftp_subcode;
+
+/**
+ * diag_ftp_handler() - FTP services IRQ handler
+ * @extirq: external interrupt (sub-) code
+ * @param32: 32-bit interruption parameter from &struct diag_ftp_ldfpl
+ * @param64: unused (for 64-bit interrupt parameters)
+ */
+static void diag_ftp_handler(struct ext_code extirq,
+                            unsigned int param32,
+                            unsigned long param64)
+{
+       if ((extirq.subcode >> 8) != 8)
+               return; /* not a FTP services sub-code */
+
+       inc_irq_stat(IRQEXT_FTP);
+       diag_ftp_subcode = extirq.subcode & 0xffU;
+       complete(&diag_ftp_rx_complete);
+}
+
+/**
+ * diag_ftp_2c4() - DIAGNOSE X'2C4' service call
+ * @fpl: pointer to prepared LDFPL
+ * @cmd: FTP command to be executed
+ *
+ * Performs a DIAGNOSE X'2C4' call with (input/output) FTP parameter list
+ * @fpl and FTP function code @cmd. In case of an error the function does
+ * nothing and returns an (negative) error code.
+ *
+ * Notes:
+ * 1. This function only initiates a transfer, so the caller must wait
+ *    for completion (asynchronous execution).
+ * 2. The FTP parameter list @fpl must be aligned to a double-word boundary.
+ * 3. fpl->bufaddr must be a real address, 4k aligned
+ */
+static int diag_ftp_2c4(struct diag_ftp_ldfpl *fpl,
+                       enum hmcdrv_ftp_cmdid cmd)
+{
+       int rc;
+
+       asm volatile(
+               "       diag    %[addr],%[cmd],0x2c4\n"
+               "0:     j       2f\n"
+               "1:     la      %[rc],%[err]\n"
+               "2:\n"
+               EX_TABLE(0b, 1b)
+               : [rc] "=d" (rc), "+m" (*fpl)
+               : [cmd] "0" (cmd), [addr] "d" (virt_to_phys(fpl)),
+                 [err] "i" (DIAG_FTP_RET_EPERM)
+               : "cc");
+
+       switch (rc) {
+       case DIAG_FTP_RET_OK:
+               return 0;
+       case DIAG_FTP_RET_EBUSY:
+               return -EBUSY;
+       case DIAG_FTP_RET_EPERM:
+               return -EPERM;
+       case DIAG_FTP_RET_EIO:
+       default:
+               return -EIO;
+       }
+}
+
+/**
+ * diag_ftp_cmd() - executes a DIAG X'2C4' FTP command, targeting a HMC
+ * @ftp: pointer to FTP command specification
+ * @fsize: return of file size (or NULL if undesirable)
+ *
+ * Attention: Notice that this function is not reentrant - so the caller
+ * must ensure locking.
+ *
+ * Return: number of bytes read/written or a (negative) error code
+ */
+ssize_t diag_ftp_cmd(const struct hmcdrv_ftp_cmdspec *ftp, size_t *fsize)
+{
+       struct diag_ftp_ldfpl *ldfpl;
+       ssize_t len;
+#ifdef DEBUG
+       unsigned long start_jiffies;
+
+       pr_debug("starting DIAG X'2C4' on '%s', requesting %zd bytes\n",
+                ftp->fname, ftp->len);
+       start_jiffies = jiffies;
+#endif
+       init_completion(&diag_ftp_rx_complete);
+
+       ldfpl = (void *) get_zeroed_page(GFP_KERNEL | GFP_DMA);
+       if (!ldfpl) {
+               len = -ENOMEM;
+               goto out;
+       }
+
+       len = strlcpy(ldfpl->fident, ftp->fname, sizeof(ldfpl->fident));
+       if (len >= HMCDRV_FTP_FIDENT_MAX) {
+               len = -EINVAL;
+               goto out_free;
+       }
+
+       ldfpl->transferred = 0;
+       ldfpl->fsize = 0;
+       ldfpl->offset = ftp->ofs;
+       ldfpl->buflen = ftp->len;
+       ldfpl->bufaddr = virt_to_phys(ftp->buf);
+
+       len = diag_ftp_2c4(ldfpl, ftp->id);
+       if (len)
+               goto out_free;
+
+       /*
+        * There is no way to cancel the running diag X'2C4', the code
+        * needs to wait unconditionally until the transfer is complete.
+        */
+       wait_for_completion(&diag_ftp_rx_complete);
+
+#ifdef DEBUG
+       pr_debug("completed DIAG X'2C4' after %lu ms\n",
+                (jiffies - start_jiffies) * 1000 / HZ);
+       pr_debug("status of DIAG X'2C4' is %u, with %lld/%lld bytes\n",
+                diag_ftp_subcode, ldfpl->transferred, ldfpl->fsize);
+#endif
+
+       switch (diag_ftp_subcode) {
+       case DIAG_FTP_STAT_OK: /* success */
+               len = ldfpl->transferred;
+               if (fsize)
+                       *fsize = ldfpl->fsize;
+               break;
+       case DIAG_FTP_STAT_LDNPERM:
+               len = -EPERM;
+               break;
+       case DIAG_FTP_STAT_LDRUNS:
+               len = -EBUSY;
+               break;
+       case DIAG_FTP_STAT_LDFAIL:
+               len = -ENOENT; /* no such file or media */
+               break;
+       default:
+               len = -EIO;
+               break;
+       }
+
+out_free:
+       free_page((unsigned long) ldfpl);
+out:
+       return len;
+}
+
+/**
+ * diag_ftp_startup() - startup of FTP services, when running on z/VM
+ *
+ * Return: 0 on success, else an (negative) error code
+ */
+int diag_ftp_startup(void)
+{
+       int rc;
+
+       rc = register_external_irq(EXT_IRQ_CP_SERVICE, diag_ftp_handler);
+       if (rc)
+               return rc;
+
+       ctl_set_bit(0, 63 - 22);
+       return 0;
+}
+
+/**
+ * diag_ftp_shutdown() - shutdown of FTP services, when running on z/VM
+ */
+void diag_ftp_shutdown(void)
+{
+       ctl_clear_bit(0, 63 - 22);
+       unregister_external_irq(EXT_IRQ_CP_SERVICE, diag_ftp_handler);
+}
diff --git a/drivers/s390/char/diag_ftp.h b/drivers/s390/char/diag_ftp.h
new file mode 100644 (file)
index 0000000..3abd261
--- /dev/null
@@ -0,0 +1,21 @@
+/*
+ *    DIAGNOSE X'2C4' instruction based SE/HMC FTP Services, useable on z/VM
+ *
+ *    Notice that all functions exported here are not reentrant.
+ *    So usage should be exclusive, ensured by the caller (e.g. using a
+ *    mutex).
+ *
+ *    Copyright IBM Corp. 2013
+ *    Author(s): Ralf Hoppe (rhoppe@de.ibm.com)
+ */
+
+#ifndef __DIAG_FTP_H__
+#define __DIAG_FTP_H__
+
+#include "hmcdrv_ftp.h"
+
+int diag_ftp_startup(void);
+void diag_ftp_shutdown(void);
+ssize_t diag_ftp_cmd(const struct hmcdrv_ftp_cmdspec *ftp, size_t *fsize);
+
+#endif  /* __DIAG_FTP_H__ */
diff --git a/drivers/s390/char/hmcdrv_cache.c b/drivers/s390/char/hmcdrv_cache.c
new file mode 100644 (file)
index 0000000..4cda5ad
--- /dev/null
@@ -0,0 +1,252 @@
+/*
+ *    SE/HMC Drive (Read) Cache Functions
+ *
+ *    Copyright IBM Corp. 2013
+ *    Author(s): Ralf Hoppe (rhoppe@de.ibm.com)
+ *
+ */
+
+#define KMSG_COMPONENT "hmcdrv"
+#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
+
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/jiffies.h>
+
+#include "hmcdrv_ftp.h"
+#include "hmcdrv_cache.h"
+
+#define HMCDRV_CACHE_TIMEOUT           30 /* aging timeout in seconds */
+
+/**
+ * struct hmcdrv_cache_entry - file cache (only used on read/dir)
+ * @id: FTP command ID
+ * @content: kernel-space buffer, 4k aligned
+ * @len: size of @content cache (0 if caching disabled)
+ * @ofs: start of content within file (-1 if no cached content)
+ * @fname: file name
+ * @fsize: file size
+ * @timeout: cache timeout in jiffies
+ *
+ * Notice that the first three members (id, fname, fsize) are cached on all
+ * read/dir requests. But content is cached only under some preconditions.
+ * Uncached content is signalled by a negative value of @ofs.
+ */
+struct hmcdrv_cache_entry {
+       enum hmcdrv_ftp_cmdid id;
+       char fname[HMCDRV_FTP_FIDENT_MAX];
+       size_t fsize;
+       loff_t ofs;
+       unsigned long timeout;
+       void *content;
+       size_t len;
+};
+
+static int hmcdrv_cache_order; /* cache allocated page order */
+
+static struct hmcdrv_cache_entry hmcdrv_cache_file = {
+       .fsize = SIZE_MAX,
+       .ofs = -1,
+       .len = 0,
+       .fname = {'\0'}
+};
+
+/**
+ * hmcdrv_cache_get() - looks for file data/content in read cache
+ * @ftp: pointer to FTP command specification
+ *
+ * Return: number of bytes read from cache or a negative number if nothing
+ * in content cache (for the file/cmd specified in @ftp)
+ */
+static ssize_t hmcdrv_cache_get(const struct hmcdrv_ftp_cmdspec *ftp)
+{
+       loff_t pos; /* position in cache (signed) */
+       ssize_t len;
+
+       if ((ftp->id != hmcdrv_cache_file.id) ||
+           strcmp(hmcdrv_cache_file.fname, ftp->fname))
+               return -1;
+
+       if (ftp->ofs >= hmcdrv_cache_file.fsize) /* EOF ? */
+               return 0;
+
+       if ((hmcdrv_cache_file.ofs < 0) || /* has content? */
+           time_after(jiffies, hmcdrv_cache_file.timeout))
+               return -1;
+
+       /* there seems to be cached content - calculate the maximum number
+        * of bytes that can be returned (regarding file size and offset)
+        */
+       len = hmcdrv_cache_file.fsize - ftp->ofs;
+
+       if (len > ftp->len)
+               len = ftp->len;
+
+       /* check if the requested chunk falls into our cache (which starts
+        * at offset 'hmcdrv_cache_file.ofs' in the file of interest)
+        */
+       pos = ftp->ofs - hmcdrv_cache_file.ofs;
+
+       if ((pos >= 0) &&
+           ((pos + len) <= hmcdrv_cache_file.len)) {
+
+               memcpy(ftp->buf,
+                      hmcdrv_cache_file.content + pos,
+                      len);
+               pr_debug("using cached content of '%s', returning %zd/%zd bytes\n",
+                        hmcdrv_cache_file.fname, len,
+                        hmcdrv_cache_file.fsize);
+
+               return len;
+       }
+
+       return -1;
+}
+
+/**
+ * hmcdrv_cache_do() - do a HMC drive CD/DVD transfer with cache update
+ * @ftp: pointer to FTP command specification
+ * @func: FTP transfer function to be used
+ *
+ * Return: number of bytes read/written or a (negative) error code
+ */
+static ssize_t hmcdrv_cache_do(const struct hmcdrv_ftp_cmdspec *ftp,
+                              hmcdrv_cache_ftpfunc func)
+{
+       ssize_t len;
+
+       /* only cache content if the read/dir cache really exists
+        * (hmcdrv_cache_file.len > 0), is large enough to handle the
+        * request (hmcdrv_cache_file.len >= ftp->len) and there is a need
+        * to do so (ftp->len > 0)
+        */
+       if ((ftp->len > 0) && (hmcdrv_cache_file.len >= ftp->len)) {
+
+               /* because the cache is not located at ftp->buf, we have to
+                * assemble a new HMC drive FTP cmd specification (pointing
+                * to our cache, and using the increased size)
+                */
+               struct hmcdrv_ftp_cmdspec cftp = *ftp; /* make a copy */
+               cftp.buf = hmcdrv_cache_file.content;  /* and update */
+               cftp.len = hmcdrv_cache_file.len;      /* buffer data */
+
+               len = func(&cftp, &hmcdrv_cache_file.fsize); /* now do */
+
+               if (len > 0) {
+                       pr_debug("caching %zd bytes content for '%s'\n",
+                                len, ftp->fname);
+
+                       if (len > ftp->len)
+                               len = ftp->len;
+
+                       hmcdrv_cache_file.ofs = ftp->ofs;
+                       hmcdrv_cache_file.timeout = jiffies +
+                               HMCDRV_CACHE_TIMEOUT * HZ;
+                       memcpy(ftp->buf, hmcdrv_cache_file.content, len);
+               }
+       } else {
+               len = func(ftp, &hmcdrv_cache_file.fsize);
+               hmcdrv_cache_file.ofs = -1; /* invalidate content */
+       }
+
+       if (len > 0) {
+               /* cache some file info (FTP command, file name and file
+                * size) unconditionally
+                */
+               strlcpy(hmcdrv_cache_file.fname, ftp->fname,
+                       HMCDRV_FTP_FIDENT_MAX);
+               hmcdrv_cache_file.id = ftp->id;
+               pr_debug("caching cmd %d, file size %zu for '%s'\n",
+                        ftp->id, hmcdrv_cache_file.fsize, ftp->fname);
+       }
+
+       return len;
+}
+
+/**
+ * hmcdrv_cache_cmd() - perform a cached HMC drive CD/DVD transfer
+ * @ftp: pointer to FTP command specification
+ * @func: FTP transfer function to be used
+ *
+ * Attention: Notice that this function is not reentrant - so the caller
+ * must ensure exclusive execution.
+ *
+ * Return: number of bytes read/written or a (negative) error code
+ */
+ssize_t hmcdrv_cache_cmd(const struct hmcdrv_ftp_cmdspec *ftp,
+                        hmcdrv_cache_ftpfunc func)
+{
+       ssize_t len;
+
+       if ((ftp->id == HMCDRV_FTP_DIR) || /* read cache */
+           (ftp->id == HMCDRV_FTP_NLIST) ||
+           (ftp->id == HMCDRV_FTP_GET)) {
+
+               len = hmcdrv_cache_get(ftp);
+
+               if (len >= 0) /* got it from cache ? */
+                       return len; /* yes */
+
+               len = hmcdrv_cache_do(ftp, func);
+
+               if (len >= 0)
+                       return len;
+
+       } else {
+               len = func(ftp, NULL); /* simply do original command */
+       }
+
+       /* invalidate the (read) cache in case there was a write operation
+        * or an error on read/dir
+        */
+       hmcdrv_cache_file.id = HMCDRV_FTP_NOOP;
+       hmcdrv_cache_file.fsize = LLONG_MAX;
+       hmcdrv_cache_file.ofs = -1;
+
+       return len;
+}
+
+/**
+ * hmcdrv_cache_startup() - startup of HMC drive cache
+ * @cachesize: cache size
+ *
+ * Return: 0 on success, else a (negative) error code
+ */
+int hmcdrv_cache_startup(size_t cachesize)
+{
+       if (cachesize > 0) { /* perform caching ? */
+               hmcdrv_cache_order = get_order(cachesize);
+               hmcdrv_cache_file.content =
+                       (void *) __get_free_pages(GFP_KERNEL | GFP_DMA,
+                                                 hmcdrv_cache_order);
+
+               if (!hmcdrv_cache_file.content) {
+                       pr_err("Allocating the requested cache size of %zu bytes failed\n",
+                              cachesize);
+                       return -ENOMEM;
+               }
+
+               pr_debug("content cache enabled, size is %zu bytes\n",
+                        cachesize);
+       }
+
+       hmcdrv_cache_file.len = cachesize;
+       return 0;
+}
+
+/**
+ * hmcdrv_cache_shutdown() - shutdown of HMC drive cache
+ */
+void hmcdrv_cache_shutdown(void)
+{
+       if (hmcdrv_cache_file.content) {
+               free_pages((unsigned long) hmcdrv_cache_file.content,
+                          hmcdrv_cache_order);
+               hmcdrv_cache_file.content = NULL;
+       }
+
+       hmcdrv_cache_file.id = HMCDRV_FTP_NOOP;
+       hmcdrv_cache_file.fsize = LLONG_MAX;
+       hmcdrv_cache_file.ofs = -1;
+       hmcdrv_cache_file.len = 0; /* no cache */
+}
diff --git a/drivers/s390/char/hmcdrv_cache.h b/drivers/s390/char/hmcdrv_cache.h
new file mode 100644 (file)
index 0000000..a14b575
--- /dev/null
@@ -0,0 +1,24 @@
+/*
+ *    SE/HMC Drive (Read) Cache Functions
+ *
+ *    Copyright IBM Corp. 2013
+ *    Author(s): Ralf Hoppe (rhoppe@de.ibm.com)
+ */
+
+#ifndef __HMCDRV_CACHE_H__
+#define __HMCDRV_CACHE_H__
+
+#include <linux/mmzone.h>
+#include "hmcdrv_ftp.h"
+
+#define HMCDRV_CACHE_SIZE_DFLT (MAX_ORDER_NR_PAGES * PAGE_SIZE / 2UL)
+
+typedef ssize_t (*hmcdrv_cache_ftpfunc)(const struct hmcdrv_ftp_cmdspec *ftp,
+                                       size_t *fsize);
+
+ssize_t hmcdrv_cache_cmd(const struct hmcdrv_ftp_cmdspec *ftp,
+                        hmcdrv_cache_ftpfunc func);
+int hmcdrv_cache_startup(size_t cachesize);
+void hmcdrv_cache_shutdown(void);
+
+#endif  /* __HMCDRV_CACHE_H__ */
diff --git a/drivers/s390/char/hmcdrv_dev.c b/drivers/s390/char/hmcdrv_dev.c
new file mode 100644 (file)
index 0000000..0c51761
--- /dev/null
@@ -0,0 +1,370 @@
+/*
+ *    HMC Drive CD/DVD Device
+ *
+ *    Copyright IBM Corp. 2013
+ *    Author(s): Ralf Hoppe (rhoppe@de.ibm.com)
+ *
+ *    This file provides a Linux "misc" character device for access to an
+ *    assigned HMC drive CD/DVD-ROM. It works as follows: First create the
+ *    device by calling hmcdrv_dev_init(). After open() a lseek(fd, 0,
+ *    SEEK_END) indicates that a new FTP command follows (not needed on the
+ *    first command after open). Then write() the FTP command ASCII string
+ *    to it, e.g. "dir /" or "nls <directory>" or "get <filename>". At the
+ *    end read() the response.
+ */
+
+#define KMSG_COMPONENT "hmcdrv"
+#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/fs.h>
+#include <linux/cdev.h>
+#include <linux/miscdevice.h>
+#include <linux/device.h>
+#include <linux/capability.h>
+#include <linux/delay.h>
+#include <linux/uaccess.h>
+
+#include "hmcdrv_dev.h"
+#include "hmcdrv_ftp.h"
+
+/* If the following macro is defined, then the HMC device creates it's own
+ * separated device class (and dynamically assigns a major number). If not
+ * defined then the HMC device is assigned to the "misc" class devices.
+ *
+#define HMCDRV_DEV_CLASS "hmcftp"
+ */
+
+#define HMCDRV_DEV_NAME  "hmcdrv"
+#define HMCDRV_DEV_BUSY_DELAY   500 /* delay between -EBUSY trials in ms */
+#define HMCDRV_DEV_BUSY_RETRIES  3   /* number of retries on -EBUSY */
+
+struct hmcdrv_dev_node {
+
+#ifdef HMCDRV_DEV_CLASS
+       struct cdev dev; /* character device structure */
+       umode_t mode;    /* mode of device node (unused, zero) */
+#else
+       struct miscdevice dev; /* "misc" device structure */
+#endif
+
+};
+
+static int hmcdrv_dev_open(struct inode *inode, struct file *fp);
+static int hmcdrv_dev_release(struct inode *inode, struct file *fp);
+static loff_t hmcdrv_dev_seek(struct file *fp, loff_t pos, int whence);
+static ssize_t hmcdrv_dev_read(struct file *fp, char __user *ubuf,
+                              size_t len, loff_t *pos);
+static ssize_t hmcdrv_dev_write(struct file *fp, const char __user *ubuf,
+                               size_t len, loff_t *pos);
+static ssize_t hmcdrv_dev_transfer(char __kernel *cmd, loff_t offset,
+                                  char __user *buf, size_t len);
+
+/*
+ * device operations
+ */
+static const struct file_operations hmcdrv_dev_fops = {
+       .open = hmcdrv_dev_open,
+       .llseek = hmcdrv_dev_seek,
+       .release = hmcdrv_dev_release,
+       .read = hmcdrv_dev_read,
+       .write = hmcdrv_dev_write,
+};
+
+static struct hmcdrv_dev_node hmcdrv_dev; /* HMC device struct (static) */
+
+#ifdef HMCDRV_DEV_CLASS
+
+static struct class *hmcdrv_dev_class; /* device class pointer */
+static dev_t hmcdrv_dev_no; /* device number (major/minor) */
+
+/**
+ * hmcdrv_dev_name() - provides a naming hint for a device node in /dev
+ * @dev: device for which the naming/mode hint is
+ * @mode: file mode for device node created in /dev
+ *
+ * See: devtmpfs.c, function devtmpfs_create_node()
+ *
+ * Return: recommended device file name in /dev
+ */
+static char *hmcdrv_dev_name(struct device *dev, umode_t *mode)
+{
+       char *nodename = NULL;
+       const char *devname = dev_name(dev); /* kernel device name */
+
+       if (devname)
+               nodename = kasprintf(GFP_KERNEL, "%s", devname);
+
+       /* on device destroy (rmmod) the mode pointer may be NULL
+        */
+       if (mode)
+               *mode = hmcdrv_dev.mode;
+
+       return nodename;
+}
+
+#endif /* HMCDRV_DEV_CLASS */
+
+/*
+ * open()
+ */
+static int hmcdrv_dev_open(struct inode *inode, struct file *fp)
+{
+       int rc;
+
+       /* check for non-blocking access, which is really unsupported
+        */
+       if (fp->f_flags & O_NONBLOCK)
+               return -EINVAL;
+
+       /* Because it makes no sense to open this device read-only (then a
+        * FTP command cannot be emitted), we respond with an error.
+        */
+       if ((fp->f_flags & O_ACCMODE) == O_RDONLY)
+               return -EINVAL;
+
+       /* prevent unloading this module as long as anyone holds the
+        * device file open - so increment the reference count here
+        */
+       if (!try_module_get(THIS_MODULE))
+               return -ENODEV;
+
+       fp->private_data = NULL; /* no command yet */
+       rc = hmcdrv_ftp_startup();
+       if (rc)
+               module_put(THIS_MODULE);
+
+       pr_debug("open file '/dev/%s' with return code %d\n",
+                fp->f_dentry->d_name.name, rc);
+       return rc;
+}
+
+/*
+ * release()
+ */
+static int hmcdrv_dev_release(struct inode *inode, struct file *fp)
+{
+       pr_debug("closing file '/dev/%s'\n", fp->f_dentry->d_name.name);
+       kfree(fp->private_data);
+       fp->private_data = NULL;
+       hmcdrv_ftp_shutdown();
+       module_put(THIS_MODULE);
+       return 0;
+}
+
+/*
+ * lseek()
+ */
+static loff_t hmcdrv_dev_seek(struct file *fp, loff_t pos, int whence)
+{
+       switch (whence) {
+       case SEEK_CUR: /* relative to current file position */
+               pos += fp->f_pos; /* new position stored in 'pos' */
+               break;
+
+       case SEEK_SET: /* absolute (relative to beginning of file) */
+               break; /* SEEK_SET */
+
+               /* We use SEEK_END as a special indicator for a SEEK_SET
+                * (set absolute position), combined with a FTP command
+                * clear.
+                */
+       case SEEK_END:
+               if (fp->private_data) {
+                       kfree(fp->private_data);
+                       fp->private_data = NULL;
+               }
+
+               break; /* SEEK_END */
+
+       default: /* SEEK_DATA, SEEK_HOLE: unsupported */
+               return -EINVAL;
+       }
+
+       if (pos < 0)
+               return -EINVAL;
+
+       if (fp->f_pos != pos)
+               ++fp->f_version;
+
+       fp->f_pos = pos;
+       return pos;
+}
+
+/*
+ * transfer (helper function)
+ */
+static ssize_t hmcdrv_dev_transfer(char __kernel *cmd, loff_t offset,
+                                  char __user *buf, size_t len)
+{
+       ssize_t retlen;
+       unsigned trials = HMCDRV_DEV_BUSY_RETRIES;
+
+       do {
+               retlen = hmcdrv_ftp_cmd(cmd, offset, buf, len);
+
+               if (retlen != -EBUSY)
+                       break;
+
+               msleep(HMCDRV_DEV_BUSY_DELAY);
+
+       } while (--trials > 0);
+
+       return retlen;
+}
+
+/*
+ * read()
+ */
+static ssize_t hmcdrv_dev_read(struct file *fp, char __user *ubuf,
+                              size_t len, loff_t *pos)
+{
+       ssize_t retlen;
+
+       if (((fp->f_flags & O_ACCMODE) == O_WRONLY) ||
+           (fp->private_data == NULL)) { /* no FTP cmd defined ? */
+               return -EBADF;
+       }
+
+       retlen = hmcdrv_dev_transfer((char *) fp->private_data,
+                                    *pos, ubuf, len);
+
+       pr_debug("read from file '/dev/%s' at %lld returns %zd/%zu\n",
+                fp->f_dentry->d_name.name, (long long) *pos, retlen, len);
+
+       if (retlen > 0)
+               *pos += retlen;
+
+       return retlen;
+}
+
+/*
+ * write()
+ */
+static ssize_t hmcdrv_dev_write(struct file *fp, const char __user *ubuf,
+                               size_t len, loff_t *pos)
+{
+       ssize_t retlen;
+
+       pr_debug("writing file '/dev/%s' at pos. %lld with length %zd\n",
+                fp->f_dentry->d_name.name, (long long) *pos, len);
+
+       if (!fp->private_data) { /* first expect a cmd write */
+               fp->private_data = kmalloc(len + 1, GFP_KERNEL);
+
+               if (!fp->private_data)
+                       return -ENOMEM;
+
+               if (!copy_from_user(fp->private_data, ubuf, len)) {
+                       ((char *)fp->private_data)[len] = '\0';
+                       return len;
+               }
+
+               kfree(fp->private_data);
+               fp->private_data = NULL;
+               return -EFAULT;
+       }
+
+       retlen = hmcdrv_dev_transfer((char *) fp->private_data,
+                                    *pos, (char __user *) ubuf, len);
+       if (retlen > 0)
+               *pos += retlen;
+
+       pr_debug("write to file '/dev/%s' returned %zd\n",
+                fp->f_dentry->d_name.name, retlen);
+
+       return retlen;
+}
+
+/**
+ * hmcdrv_dev_init() - creates a HMC drive CD/DVD device
+ *
+ * This function creates a HMC drive CD/DVD kernel device and an associated
+ * device under /dev, using a dynamically allocated major number.
+ *
+ * Return: 0 on success, else an error code.
+ */
+int hmcdrv_dev_init(void)
+{
+       int rc;
+
+#ifdef HMCDRV_DEV_CLASS
+       struct device *dev;
+
+       rc = alloc_chrdev_region(&hmcdrv_dev_no, 0, 1, HMCDRV_DEV_NAME);
+
+       if (rc)
+               goto out_err;
+
+       cdev_init(&hmcdrv_dev.dev, &hmcdrv_dev_fops);
+       hmcdrv_dev.dev.owner = THIS_MODULE;
+       rc = cdev_add(&hmcdrv_dev.dev, hmcdrv_dev_no, 1);
+
+       if (rc)
+               goto out_unreg;
+
+       /* At this point the character device exists in the kernel (see
+        * /proc/devices), but not under /dev nor /sys/devices/virtual. So
+        * we have to create an associated class (see /sys/class).
+        */
+       hmcdrv_dev_class = class_create(THIS_MODULE, HMCDRV_DEV_CLASS);
+
+       if (IS_ERR(hmcdrv_dev_class)) {
+               rc = PTR_ERR(hmcdrv_dev_class);
+               goto out_devdel;
+       }
+
+       /* Finally a device node in /dev has to be established (as 'mkdev'
+        * does from the command line). Notice that assignment of a device
+        * node name/mode function is optional (only for mode != 0600).
+        */
+       hmcdrv_dev.mode = 0; /* "unset" */
+       hmcdrv_dev_class->devnode = hmcdrv_dev_name;
+
+       dev = device_create(hmcdrv_dev_class, NULL, hmcdrv_dev_no, NULL,
+                           "%s", HMCDRV_DEV_NAME);
+       if (!IS_ERR(dev))
+               return 0;
+
+       rc = PTR_ERR(dev);
+       class_destroy(hmcdrv_dev_class);
+       hmcdrv_dev_class = NULL;
+
+out_devdel:
+       cdev_del(&hmcdrv_dev.dev);
+
+out_unreg:
+       unregister_chrdev_region(hmcdrv_dev_no, 1);
+
+out_err:
+
+#else  /* !HMCDRV_DEV_CLASS */
+       hmcdrv_dev.dev.minor = MISC_DYNAMIC_MINOR;
+       hmcdrv_dev.dev.name = HMCDRV_DEV_NAME;
+       hmcdrv_dev.dev.fops = &hmcdrv_dev_fops;
+       hmcdrv_dev.dev.mode = 0; /* finally produces 0600 */
+       rc = misc_register(&hmcdrv_dev.dev);
+#endif /* HMCDRV_DEV_CLASS */
+
+       return rc;
+}
+
+/**
+ * hmcdrv_dev_exit() - destroys a HMC drive CD/DVD device
+ */
+void hmcdrv_dev_exit(void)
+{
+#ifdef HMCDRV_DEV_CLASS
+       if (!IS_ERR_OR_NULL(hmcdrv_dev_class)) {
+               device_destroy(hmcdrv_dev_class, hmcdrv_dev_no);
+               class_destroy(hmcdrv_dev_class);
+       }
+
+       cdev_del(&hmcdrv_dev.dev);
+       unregister_chrdev_region(hmcdrv_dev_no, 1);
+#else  /* !HMCDRV_DEV_CLASS */
+       misc_deregister(&hmcdrv_dev.dev);
+#endif /* HMCDRV_DEV_CLASS */
+}
diff --git a/drivers/s390/char/hmcdrv_dev.h b/drivers/s390/char/hmcdrv_dev.h
new file mode 100644 (file)
index 0000000..cb17f07
--- /dev/null
@@ -0,0 +1,14 @@
+/*
+ *    SE/HMC Drive FTP Device
+ *
+ *    Copyright IBM Corp. 2013
+ *    Author(s): Ralf Hoppe (rhoppe@de.ibm.com)
+ */
+
+#ifndef __HMCDRV_DEV_H__
+#define __HMCDRV_DEV_H__
+
+int hmcdrv_dev_init(void);
+void hmcdrv_dev_exit(void);
+
+#endif  /* __HMCDRV_DEV_H__ */
diff --git a/drivers/s390/char/hmcdrv_ftp.c b/drivers/s390/char/hmcdrv_ftp.c
new file mode 100644 (file)
index 0000000..4bd6332
--- /dev/null
@@ -0,0 +1,343 @@
+/*
+ *    HMC Drive FTP Services
+ *
+ *    Copyright IBM Corp. 2013
+ *    Author(s): Ralf Hoppe (rhoppe@de.ibm.com)
+ */
+
+#define KMSG_COMPONENT "hmcdrv"
+#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/uaccess.h>
+#include <linux/export.h>
+
+#include <linux/ctype.h>
+#include <linux/crc16.h>
+
+#include "hmcdrv_ftp.h"
+#include "hmcdrv_cache.h"
+#include "sclp_ftp.h"
+#include "diag_ftp.h"
+
+/**
+ * struct hmcdrv_ftp_ops - HMC drive FTP operations
+ * @startup: startup function
+ * @shutdown: shutdown function
+ * @cmd: FTP transfer function
+ */
+struct hmcdrv_ftp_ops {
+       int (*startup)(void);
+       void (*shutdown)(void);
+       ssize_t (*transfer)(const struct hmcdrv_ftp_cmdspec *ftp,
+                           size_t *fsize);
+};
+
+static enum hmcdrv_ftp_cmdid hmcdrv_ftp_cmd_getid(const char *cmd, int len);
+static int hmcdrv_ftp_parse(char *cmd, struct hmcdrv_ftp_cmdspec *ftp);
+
+static struct hmcdrv_ftp_ops *hmcdrv_ftp_funcs; /* current operations */
+static DEFINE_MUTEX(hmcdrv_ftp_mutex); /* mutex for hmcdrv_ftp_funcs */
+static unsigned hmcdrv_ftp_refcnt; /* start/shutdown reference counter */
+
+/**
+ * hmcdrv_ftp_cmd_getid() - determine FTP command ID from a command string
+ * @cmd: FTP command string (NOT zero-terminated)
+ * @len: length of FTP command string in @cmd
+ */
+static enum hmcdrv_ftp_cmdid hmcdrv_ftp_cmd_getid(const char *cmd, int len)
+{
+       /* HMC FTP command descriptor */
+       struct hmcdrv_ftp_cmd_desc {
+               const char *str;           /* command string */
+               enum hmcdrv_ftp_cmdid cmd; /* associated command as enum */
+       };
+
+       /* Description of all HMC drive FTP commands
+        *
+        * Notes:
+        * 1. Array size should be a prime number.
+        * 2. Do not change the order of commands in table (because the
+        *    index is determined by CRC % ARRAY_SIZE).
+        * 3. Original command 'nlist' was renamed, else the CRC would
+        *    collide with 'append' (see point 2).
+        */
+       static const struct hmcdrv_ftp_cmd_desc ftpcmds[7] = {
+
+               {.str = "get", /* [0] get (CRC = 0x68eb) */
+                .cmd = HMCDRV_FTP_GET},
+               {.str = "dir", /* [1] dir (CRC = 0x6a9e) */
+                .cmd = HMCDRV_FTP_DIR},
+               {.str = "delete", /* [2] delete (CRC = 0x53ae) */
+                .cmd = HMCDRV_FTP_DELETE},
+               {.str = "nls", /* [3] nls (CRC = 0xf87c) */
+                .cmd = HMCDRV_FTP_NLIST},
+               {.str = "put", /* [4] put (CRC = 0xac56) */
+                .cmd = HMCDRV_FTP_PUT},
+               {.str = "append", /* [5] append (CRC = 0xf56e) */
+                .cmd = HMCDRV_FTP_APPEND},
+               {.str = NULL} /* [6] unused */
+       };
+
+       const struct hmcdrv_ftp_cmd_desc *pdesc;
+
+       u16 crc = 0xffffU;
+
+       if (len == 0)
+               return HMCDRV_FTP_NOOP; /* error indiactor */
+
+       crc = crc16(crc, cmd, len);
+       pdesc = ftpcmds + (crc % ARRAY_SIZE(ftpcmds));
+       pr_debug("FTP command '%s' has CRC 0x%04x, at table pos. %lu\n",
+                cmd, crc, (crc % ARRAY_SIZE(ftpcmds)));
+
+       if (!pdesc->str || strncmp(pdesc->str, cmd, len))
+               return HMCDRV_FTP_NOOP;
+
+       pr_debug("FTP command '%s' found, with ID %d\n",
+                pdesc->str, pdesc->cmd);
+
+       return pdesc->cmd;
+}
+
+/**
+ * hmcdrv_ftp_parse() - HMC drive FTP command parser
+ * @cmd: FTP command string "<cmd> <filename>"
+ * @ftp: Pointer to FTP command specification buffer (output)
+ *
+ * Return: 0 on success, else a (negative) error code
+ */
+static int hmcdrv_ftp_parse(char *cmd, struct hmcdrv_ftp_cmdspec *ftp)
+{
+       char *start;
+       int argc = 0;
+
+       ftp->id = HMCDRV_FTP_NOOP;
+       ftp->fname = NULL;
+
+       while (*cmd != '\0') {
+
+               while (isspace(*cmd))
+                       ++cmd;
+
+               if (*cmd == '\0')
+                       break;
+
+               start = cmd;
+
+               switch (argc) {
+               case 0: /* 1st argument (FTP command) */
+                       while ((*cmd != '\0') && !isspace(*cmd))
+                               ++cmd;
+                       ftp->id = hmcdrv_ftp_cmd_getid(start, cmd - start);
+                       break;
+               case 1: /* 2nd / last argument (rest of line) */
+                       while ((*cmd != '\0') && !iscntrl(*cmd))
+                               ++cmd;
+                       ftp->fname = start;
+                       /* fall through */
+               default:
+                       *cmd = '\0';
+                       break;
+               } /* switch */
+
+               ++argc;
+       } /* while */
+
+       if (!ftp->fname || (ftp->id == HMCDRV_FTP_NOOP))
+               return -EINVAL;
+
+       return 0;
+}
+
+/**
+ * hmcdrv_ftp_do() - perform a HMC drive FTP, with data from kernel-space
+ * @ftp: pointer to FTP command specification
+ *
+ * Return: number of bytes read/written or a negative error code
+ */
+ssize_t hmcdrv_ftp_do(const struct hmcdrv_ftp_cmdspec *ftp)
+{
+       ssize_t len;
+
+       mutex_lock(&hmcdrv_ftp_mutex);
+
+       if (hmcdrv_ftp_funcs && hmcdrv_ftp_refcnt) {
+               pr_debug("starting transfer, cmd %d for '%s' at %lld with %zd bytes\n",
+                        ftp->id, ftp->fname, (long long) ftp->ofs, ftp->len);
+               len = hmcdrv_cache_cmd(ftp, hmcdrv_ftp_funcs->transfer);
+       } else {
+               len = -ENXIO;
+       }
+
+       mutex_unlock(&hmcdrv_ftp_mutex);
+       return len;
+}
+EXPORT_SYMBOL(hmcdrv_ftp_do);
+
+/**
+ * hmcdrv_ftp_probe() - probe for the HMC drive FTP service
+ *
+ * Return: 0 if service is available, else an (negative) error code
+ */
+int hmcdrv_ftp_probe(void)
+{
+       int rc;
+
+       struct hmcdrv_ftp_cmdspec ftp = {
+               .id = HMCDRV_FTP_NOOP,
+               .ofs = 0,
+               .fname = "",
+               .len = PAGE_SIZE
+       };
+
+       ftp.buf = (void *) get_zeroed_page(GFP_KERNEL | GFP_DMA);
+
+       if (!ftp.buf)
+               return -ENOMEM;
+
+       rc = hmcdrv_ftp_startup();
+
+       if (rc)
+               return rc;
+
+       rc = hmcdrv_ftp_do(&ftp);
+       free_page((unsigned long) ftp.buf);
+       hmcdrv_ftp_shutdown();
+
+       switch (rc) {
+       case -ENOENT: /* no such file/media or currently busy, */
+       case -EBUSY:  /* but service seems to be available */
+               rc = 0;
+               break;
+       default: /* leave 'rc' as it is for [0, -EPERM, -E...] */
+               if (rc > 0)
+                       rc = 0; /* clear length (success) */
+               break;
+       } /* switch */
+
+       return rc;
+}
+EXPORT_SYMBOL(hmcdrv_ftp_probe);
+
+/**
+ * hmcdrv_ftp_cmd() - Perform a HMC drive FTP, with data from user-space
+ *
+ * @cmd: FTP command string "<cmd> <filename>"
+ * @offset: file position to read/write
+ * @buf: user-space buffer for read/written directory/file
+ * @len: size of @buf (read/dir) or number of bytes to write
+ *
+ * This function must not be called before hmcdrv_ftp_startup() was called.
+ *
+ * Return: number of bytes read/written or a negative error code
+ */
+ssize_t hmcdrv_ftp_cmd(char __kernel *cmd, loff_t offset,
+                      char __user *buf, size_t len)
+{
+       int order;
+
+       struct hmcdrv_ftp_cmdspec ftp = {.len = len, .ofs = offset};
+       ssize_t retlen = hmcdrv_ftp_parse(cmd, &ftp);
+
+       if (retlen)
+               return retlen;
+
+       order = get_order(ftp.len);
+       ftp.buf = (void *) __get_free_pages(GFP_KERNEL | GFP_DMA, order);
+
+       if (!ftp.buf)
+               return -ENOMEM;
+
+       switch (ftp.id) {
+       case HMCDRV_FTP_DIR:
+       case HMCDRV_FTP_NLIST:
+       case HMCDRV_FTP_GET:
+               retlen = hmcdrv_ftp_do(&ftp);
+
+               if ((retlen >= 0) &&
+                   copy_to_user(buf, ftp.buf, retlen))
+                       retlen = -EFAULT;
+               break;
+
+       case HMCDRV_FTP_PUT:
+       case HMCDRV_FTP_APPEND:
+               if (!copy_from_user(ftp.buf, buf, ftp.len))
+                       retlen = hmcdrv_ftp_do(&ftp);
+               else
+                       retlen = -EFAULT;
+               break;
+
+       case HMCDRV_FTP_DELETE:
+               retlen = hmcdrv_ftp_do(&ftp);
+               break;
+
+       default:
+               retlen = -EOPNOTSUPP;
+               break;
+       }
+
+       free_pages((unsigned long) ftp.buf, order);
+       return retlen;
+}
+
+/**
+ * hmcdrv_ftp_startup() - startup of HMC drive FTP functionality for a
+ * dedicated (owner) instance
+ *
+ * Return: 0 on success, else an (negative) error code
+ */
+int hmcdrv_ftp_startup(void)
+{
+       static struct hmcdrv_ftp_ops hmcdrv_ftp_zvm = {
+               .startup = diag_ftp_startup,
+               .shutdown = diag_ftp_shutdown,
+               .transfer = diag_ftp_cmd
+       };
+
+       static struct hmcdrv_ftp_ops hmcdrv_ftp_lpar = {
+               .startup = sclp_ftp_startup,
+               .shutdown = sclp_ftp_shutdown,
+               .transfer = sclp_ftp_cmd
+       };
+
+       int rc = 0;
+
+       mutex_lock(&hmcdrv_ftp_mutex); /* block transfers while start-up */
+
+       if (hmcdrv_ftp_refcnt == 0) {
+               if (MACHINE_IS_VM)
+                       hmcdrv_ftp_funcs = &hmcdrv_ftp_zvm;
+               else if (MACHINE_IS_LPAR || MACHINE_IS_KVM)
+                       hmcdrv_ftp_funcs = &hmcdrv_ftp_lpar;
+               else
+                       rc = -EOPNOTSUPP;
+
+               if (hmcdrv_ftp_funcs)
+                       rc = hmcdrv_ftp_funcs->startup();
+       }
+
+       if (!rc)
+               ++hmcdrv_ftp_refcnt;
+
+       mutex_unlock(&hmcdrv_ftp_mutex);
+       return rc;
+}
+EXPORT_SYMBOL(hmcdrv_ftp_startup);
+
+/**
+ * hmcdrv_ftp_shutdown() - shutdown of HMC drive FTP functionality for a
+ * dedicated (owner) instance
+ */
+void hmcdrv_ftp_shutdown(void)
+{
+       mutex_lock(&hmcdrv_ftp_mutex);
+       --hmcdrv_ftp_refcnt;
+
+       if ((hmcdrv_ftp_refcnt == 0) && hmcdrv_ftp_funcs)
+               hmcdrv_ftp_funcs->shutdown();
+
+       mutex_unlock(&hmcdrv_ftp_mutex);
+}
+EXPORT_SYMBOL(hmcdrv_ftp_shutdown);
diff --git a/drivers/s390/char/hmcdrv_ftp.h b/drivers/s390/char/hmcdrv_ftp.h
new file mode 100644 (file)
index 0000000..f3643a7
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ *    SE/HMC Drive FTP Services
+ *
+ *    Copyright IBM Corp. 2013
+ *    Author(s): Ralf Hoppe (rhoppe@de.ibm.com)
+ */
+
+#ifndef __HMCDRV_FTP_H__
+#define __HMCDRV_FTP_H__
+
+#include <linux/types.h> /* size_t, loff_t */
+
+/*
+ * HMC drive FTP Service max. length of path (w/ EOS)
+ */
+#define HMCDRV_FTP_FIDENT_MAX 192
+
+/**
+ * enum hmcdrv_ftp_cmdid - HMC drive FTP commands
+ * @HMCDRV_FTP_NOOP: do nothing (only for probing)
+ * @HMCDRV_FTP_GET: read a file
+ * @HMCDRV_FTP_PUT: (over-) write a file
+ * @HMCDRV_FTP_APPEND: append to a file
+ * @HMCDRV_FTP_DIR: list directory long (ls -l)
+ * @HMCDRV_FTP_NLIST: list files, no directories (name list)
+ * @HMCDRV_FTP_DELETE: delete a file
+ * @HMCDRV_FTP_CANCEL: cancel operation (SCLP/LPAR only)
+ */
+enum hmcdrv_ftp_cmdid {
+       HMCDRV_FTP_NOOP = 0,
+       HMCDRV_FTP_GET = 1,
+       HMCDRV_FTP_PUT = 2,
+       HMCDRV_FTP_APPEND = 3,
+       HMCDRV_FTP_DIR = 4,
+       HMCDRV_FTP_NLIST = 5,
+       HMCDRV_FTP_DELETE = 6,
+       HMCDRV_FTP_CANCEL = 7
+};
+
+/**
+ * struct hmcdrv_ftp_cmdspec - FTP command specification
+ * @id: FTP command ID
+ * @ofs: offset in file
+ * @fname: filename (ASCII), null-terminated
+ * @buf: kernel-space transfer data buffer, 4k aligned
+ * @len: (max) number of bytes to transfer from/to @buf
+ */
+struct hmcdrv_ftp_cmdspec {
+       enum hmcdrv_ftp_cmdid id;
+       loff_t ofs;
+       const char *fname;
+       void __kernel *buf;
+       size_t len;
+};
+
+int hmcdrv_ftp_startup(void);
+void hmcdrv_ftp_shutdown(void);
+int hmcdrv_ftp_probe(void);
+ssize_t hmcdrv_ftp_do(const struct hmcdrv_ftp_cmdspec *ftp);
+ssize_t hmcdrv_ftp_cmd(char __kernel *cmd, loff_t offset,
+                      char __user *buf, size_t len);
+
+#endif  /* __HMCDRV_FTP_H__ */
diff --git a/drivers/s390/char/hmcdrv_mod.c b/drivers/s390/char/hmcdrv_mod.c
new file mode 100644 (file)
index 0000000..505c6a7
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ *    HMC Drive DVD Module
+ *
+ *    Copyright IBM Corp. 2013
+ *    Author(s): Ralf Hoppe (rhoppe@de.ibm.com)
+ */
+
+#define KMSG_COMPONENT "hmcdrv"
+#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/version.h>
+#include <linux/stat.h>
+
+#include "hmcdrv_ftp.h"
+#include "hmcdrv_dev.h"
+#include "hmcdrv_cache.h"
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Copyright 2013 IBM Corporation");
+MODULE_DESCRIPTION("HMC drive DVD access");
+
+/*
+ * module parameter 'cachesize'
+ */
+static size_t hmcdrv_mod_cachesize = HMCDRV_CACHE_SIZE_DFLT;
+module_param_named(cachesize, hmcdrv_mod_cachesize, ulong, S_IRUGO);
+
+/**
+ * hmcdrv_mod_init() - module init function
+ */
+static int __init hmcdrv_mod_init(void)
+{
+       int rc = hmcdrv_ftp_probe(); /* perform w/o cache */
+
+       if (rc)
+               return rc;
+
+       rc = hmcdrv_cache_startup(hmcdrv_mod_cachesize);
+
+       if (rc)
+               return rc;
+
+       rc = hmcdrv_dev_init();
+
+       if (rc)
+               hmcdrv_cache_shutdown();
+
+       return rc;
+}
+
+/**
+ * hmcdrv_mod_exit() - module exit function
+ */
+static void __exit hmcdrv_mod_exit(void)
+{
+       hmcdrv_dev_exit();
+       hmcdrv_cache_shutdown();
+}
+
+module_init(hmcdrv_mod_init);
+module_exit(hmcdrv_mod_exit);
index a68b5ec7d042b369d4a68bc1c78e35b7793e1c1a..a88069f8c677e437d4248a757ee33b659aac295a 100644 (file)
@@ -19,6 +19,7 @@
 
 #define EVTYP_OPCMD            0x01
 #define EVTYP_MSG              0x02
+#define EVTYP_DIAG_TEST                0x07
 #define EVTYP_STATECHANGE      0x08
 #define EVTYP_PMSGCMD          0x09
 #define EVTYP_CNTLPROGOPCMD    0x20
@@ -32,6 +33,7 @@
 
 #define EVTYP_OPCMD_MASK       0x80000000
 #define EVTYP_MSG_MASK         0x40000000
+#define EVTYP_DIAG_TEST_MASK   0x02000000
 #define EVTYP_STATECHANGE_MASK 0x01000000
 #define EVTYP_PMSGCMD_MASK     0x00800000
 #define EVTYP_CTLPROGOPCMD_MASK        0x00000001
diff --git a/drivers/s390/char/sclp_diag.h b/drivers/s390/char/sclp_diag.h
new file mode 100644 (file)
index 0000000..59c4afa
--- /dev/null
@@ -0,0 +1,89 @@
+/*
+ *    Copyright IBM Corp. 2013
+ *    Author(s): Ralf Hoppe (rhoppe@de.ibm.com)
+ */
+
+#ifndef _SCLP_DIAG_H
+#define _SCLP_DIAG_H
+
+#include <linux/types.h>
+
+/* return codes for Diagnostic Test FTP Service, as indicated in member
+ * sclp_diag_ftp::ldflg
+ */
+#define SCLP_DIAG_FTP_OK       0x80U /* success */
+#define SCLP_DIAG_FTP_LDFAIL   0x01U /* load failed */
+#define SCLP_DIAG_FTP_LDNPERM  0x02U /* not allowed */
+#define SCLP_DIAG_FTP_LDRUNS   0x03U /* LD runs */
+#define SCLP_DIAG_FTP_LDNRUNS  0x04U /* LD does not run */
+
+#define SCLP_DIAG_FTP_XPCX     0x80 /* PCX communication code */
+#define SCLP_DIAG_FTP_ROUTE    4 /* routing code for new FTP service */
+
+/*
+ * length of Diagnostic Test FTP Service event buffer
+ */
+#define SCLP_DIAG_FTP_EVBUF_LEN                                \
+       (offsetof(struct sclp_diag_evbuf, mdd) +        \
+        sizeof(struct sclp_diag_ftp))
+
+/**
+ * struct sclp_diag_ftp - Diagnostic Test FTP Service model-dependent data
+ * @pcx: code for PCX communication (should be 0x80)
+ * @ldflg: load flag (see defines above)
+ * @cmd: FTP command
+ * @pgsize: page size (0 = 4kB, 1 = large page size)
+ * @srcflg: source flag
+ * @spare: reserved (zeroes)
+ * @offset: file offset
+ * @fsize: file size
+ * @length: buffer size resp. bytes transferred
+ * @failaddr: failing address
+ * @bufaddr: buffer address, virtual
+ * @asce: region or segment table designation
+ * @fident: file name (ASCII, zero-terminated)
+ */
+struct sclp_diag_ftp {
+       u8 pcx;
+       u8 ldflg;
+       u8 cmd;
+       u8 pgsize;
+       u8 srcflg;
+       u8 spare;
+       u64 offset;
+       u64 fsize;
+       u64 length;
+       u64 failaddr;
+       u64 bufaddr;
+       u64 asce;
+
+       u8 fident[256];
+} __packed;
+
+/**
+ * struct sclp_diag_evbuf - Diagnostic Test (ET7) Event Buffer
+ * @hdr: event buffer header
+ * @route: diagnostic route
+ * @mdd: model-dependent data (@route dependent)
+ */
+struct sclp_diag_evbuf {
+       struct evbuf_header hdr;
+       u16 route;
+
+       union {
+               struct sclp_diag_ftp ftp;
+       } mdd;
+} __packed;
+
+/**
+ * struct sclp_diag_sccb - Diagnostic Test (ET7) SCCB
+ * @hdr: SCCB header
+ * @evbuf: event buffer
+ */
+struct sclp_diag_sccb {
+
+       struct sccb_header hdr;
+       struct sclp_diag_evbuf evbuf;
+} __packed;
+
+#endif /* _SCLP_DIAG_H */
index 1918d9dff45d0dfcca43cafe4bd762008c4448f6..5bd6cb145a87d4bfd4e11f7ca139bac1f7ec51e3 100644 (file)
@@ -281,7 +281,7 @@ out:
 
 static unsigned int __init sclp_con_check_linemode(struct init_sccb *sccb)
 {
-       if (!(sccb->sclp_send_mask & (EVTYP_OPCMD_MASK | EVTYP_PMSGCMD_MASK)))
+       if (!(sccb->sclp_send_mask & EVTYP_OPCMD_MASK))
                return 0;
        if (!(sccb->sclp_receive_mask & (EVTYP_MSG_MASK | EVTYP_PMSGCMD_MASK)))
                return 0;
diff --git a/drivers/s390/char/sclp_ftp.c b/drivers/s390/char/sclp_ftp.c
new file mode 100644 (file)
index 0000000..6561cc5
--- /dev/null
@@ -0,0 +1,275 @@
+/*
+ *    SCLP Event Type (ET) 7 - Diagnostic Test FTP Services, useable on LPAR
+ *
+ *    Copyright IBM Corp. 2013
+ *    Author(s): Ralf Hoppe (rhoppe@de.ibm.com)
+ *
+ */
+
+#define KMSG_COMPONENT "hmcdrv"
+#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
+
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+#include <linux/wait.h>
+#include <linux/string.h>
+#include <linux/jiffies.h>
+#include <asm/sysinfo.h>
+#include <asm/ebcdic.h>
+
+#include "sclp.h"
+#include "sclp_diag.h"
+#include "sclp_ftp.h"
+
+static DECLARE_COMPLETION(sclp_ftp_rx_complete);
+static u8 sclp_ftp_ldflg;
+static u64 sclp_ftp_fsize;
+static u64 sclp_ftp_length;
+
+/**
+ * sclp_ftp_txcb() - Diagnostic Test FTP services SCLP command callback
+ */
+static void sclp_ftp_txcb(struct sclp_req *req, void *data)
+{
+       struct completion *completion = data;
+
+#ifdef DEBUG
+       pr_debug("SCLP (ET7) TX-IRQ, SCCB @ 0x%p: %*phN\n",
+                req->sccb, 24, req->sccb);
+#endif
+       complete(completion);
+}
+
+/**
+ * sclp_ftp_rxcb() - Diagnostic Test FTP services receiver event callback
+ */
+static void sclp_ftp_rxcb(struct evbuf_header *evbuf)
+{
+       struct sclp_diag_evbuf *diag = (struct sclp_diag_evbuf *) evbuf;
+
+       /*
+        * Check for Diagnostic Test FTP Service
+        */
+       if (evbuf->type != EVTYP_DIAG_TEST ||
+           diag->route != SCLP_DIAG_FTP_ROUTE ||
+           diag->mdd.ftp.pcx != SCLP_DIAG_FTP_XPCX ||
+           evbuf->length < SCLP_DIAG_FTP_EVBUF_LEN)
+               return;
+
+#ifdef DEBUG
+       pr_debug("SCLP (ET7) RX-IRQ, Event @ 0x%p: %*phN\n",
+                evbuf, 24, evbuf);
+#endif
+
+       /*
+        * Because the event buffer is located in a page which is owned
+        * by the SCLP core, all data of interest must be copied. The
+        * error indication is in 'sclp_ftp_ldflg'
+        */
+       sclp_ftp_ldflg = diag->mdd.ftp.ldflg;
+       sclp_ftp_fsize = diag->mdd.ftp.fsize;
+       sclp_ftp_length = diag->mdd.ftp.length;
+
+       complete(&sclp_ftp_rx_complete);
+}
+
+/**
+ * sclp_ftp_et7() - start a Diagnostic Test FTP Service SCLP request
+ * @ftp: pointer to FTP descriptor
+ *
+ * Return: 0 on success, else a (negative) error code
+ */
+static int sclp_ftp_et7(const struct hmcdrv_ftp_cmdspec *ftp)
+{
+       struct completion completion;
+       struct sclp_diag_sccb *sccb;
+       struct sclp_req *req;
+       size_t len;
+       int rc;
+
+       req = kzalloc(sizeof(*req), GFP_KERNEL);
+       sccb = (void *) get_zeroed_page(GFP_KERNEL | GFP_DMA);
+       if (!req || !sccb) {
+               rc = -ENOMEM;
+               goto out_free;
+       }
+
+       sccb->hdr.length = SCLP_DIAG_FTP_EVBUF_LEN +
+               sizeof(struct sccb_header);
+       sccb->evbuf.hdr.type = EVTYP_DIAG_TEST;
+       sccb->evbuf.hdr.length = SCLP_DIAG_FTP_EVBUF_LEN;
+       sccb->evbuf.hdr.flags = 0; /* clear processed-buffer */
+       sccb->evbuf.route = SCLP_DIAG_FTP_ROUTE;
+       sccb->evbuf.mdd.ftp.pcx = SCLP_DIAG_FTP_XPCX;
+       sccb->evbuf.mdd.ftp.srcflg = 0;
+       sccb->evbuf.mdd.ftp.pgsize = 0;
+       sccb->evbuf.mdd.ftp.asce = _ASCE_REAL_SPACE;
+       sccb->evbuf.mdd.ftp.ldflg = SCLP_DIAG_FTP_LDFAIL;
+       sccb->evbuf.mdd.ftp.fsize = 0;
+       sccb->evbuf.mdd.ftp.cmd = ftp->id;
+       sccb->evbuf.mdd.ftp.offset = ftp->ofs;
+       sccb->evbuf.mdd.ftp.length = ftp->len;
+       sccb->evbuf.mdd.ftp.bufaddr = virt_to_phys(ftp->buf);
+
+       len = strlcpy(sccb->evbuf.mdd.ftp.fident, ftp->fname,
+                     HMCDRV_FTP_FIDENT_MAX);
+       if (len >= HMCDRV_FTP_FIDENT_MAX) {
+               rc = -EINVAL;
+               goto out_free;
+       }
+
+       req->command = SCLP_CMDW_WRITE_EVENT_DATA;
+       req->sccb = sccb;
+       req->status = SCLP_REQ_FILLED;
+       req->callback = sclp_ftp_txcb;
+       req->callback_data = &completion;
+
+       init_completion(&completion);
+
+       rc = sclp_add_request(req);
+       if (rc)
+               goto out_free;
+
+       /* Wait for end of ftp sclp command. */
+       wait_for_completion(&completion);
+
+#ifdef DEBUG
+       pr_debug("status of SCLP (ET7) request is 0x%04x (0x%02x)\n",
+                sccb->hdr.response_code, sccb->evbuf.hdr.flags);
+#endif
+
+       /*
+        * Check if sclp accepted the request. The data transfer runs
+        * asynchronously and the completion is indicated with an
+        * sclp ET7 event.
+        */
+       if (req->status != SCLP_REQ_DONE ||
+           (sccb->evbuf.hdr.flags & 0x80) == 0 || /* processed-buffer */
+           (sccb->hdr.response_code & 0xffU) != 0x20U) {
+               rc = -EIO;
+       }
+
+out_free:
+       free_page((unsigned long) sccb);
+       kfree(req);
+       return rc;
+}
+
+/**
+ * sclp_ftp_cmd() - executes a HMC related SCLP Diagnose (ET7) FTP command
+ * @ftp: pointer to FTP command specification
+ * @fsize: return of file size (or NULL if undesirable)
+ *
+ * Attention: Notice that this function is not reentrant - so the caller
+ * must ensure locking.
+ *
+ * Return: number of bytes read/written or a (negative) error code
+ */
+ssize_t sclp_ftp_cmd(const struct hmcdrv_ftp_cmdspec *ftp, size_t *fsize)
+{
+       ssize_t len;
+#ifdef DEBUG
+       unsigned long start_jiffies;
+
+       pr_debug("starting SCLP (ET7), cmd %d for '%s' at %lld with %zd bytes\n",
+                ftp->id, ftp->fname, (long long) ftp->ofs, ftp->len);
+       start_jiffies = jiffies;
+#endif
+
+       init_completion(&sclp_ftp_rx_complete);
+
+       /* Start ftp sclp command. */
+       len = sclp_ftp_et7(ftp);
+       if (len)
+               goto out_unlock;
+
+       /*
+        * There is no way to cancel the sclp ET7 request, the code
+        * needs to wait unconditionally until the transfer is complete.
+        */
+       wait_for_completion(&sclp_ftp_rx_complete);
+
+#ifdef DEBUG
+       pr_debug("completed SCLP (ET7) request after %lu ms (all)\n",
+                (jiffies - start_jiffies) * 1000 / HZ);
+       pr_debug("return code of SCLP (ET7) FTP Service is 0x%02x, with %lld/%lld bytes\n",
+                sclp_ftp_ldflg, sclp_ftp_length, sclp_ftp_fsize);
+#endif
+
+       switch (sclp_ftp_ldflg) {
+       case SCLP_DIAG_FTP_OK:
+               len = sclp_ftp_length;
+               if (fsize)
+                       *fsize = sclp_ftp_fsize;
+               break;
+       case SCLP_DIAG_FTP_LDNPERM:
+               len = -EPERM;
+               break;
+       case SCLP_DIAG_FTP_LDRUNS:
+               len = -EBUSY;
+               break;
+       case SCLP_DIAG_FTP_LDFAIL:
+               len = -ENOENT;
+               break;
+       default:
+               len = -EIO;
+               break;
+       }
+
+out_unlock:
+       return len;
+}
+
+/*
+ * ET7 event listener
+ */
+static struct sclp_register sclp_ftp_event = {
+       .send_mask = EVTYP_DIAG_TEST_MASK,    /* want tx events */
+       .receive_mask = EVTYP_DIAG_TEST_MASK, /* want rx events */
+       .receiver_fn = sclp_ftp_rxcb,         /* async callback (rx) */
+       .state_change_fn = NULL,
+       .pm_event_fn = NULL,
+};
+
+/**
+ * sclp_ftp_startup() - startup of FTP services, when running on LPAR
+ */
+int sclp_ftp_startup(void)
+{
+#ifdef DEBUG
+       unsigned long info;
+#endif
+       int rc;
+
+       rc = sclp_register(&sclp_ftp_event);
+       if (rc)
+               return rc;
+
+#ifdef DEBUG
+       info = get_zeroed_page(GFP_KERNEL);
+
+       if (info != 0) {
+               struct sysinfo_2_2_2 *info222 = (struct sysinfo_2_2_2 *)info;
+
+               if (!stsi(info222, 2, 2, 2)) { /* get SYSIB 2.2.2 */
+                       info222->name[sizeof(info222->name) - 1] = '\0';
+                       EBCASC_500(info222->name, sizeof(info222->name) - 1);
+                       pr_debug("SCLP (ET7) FTP Service working on LPAR %u (%s)\n",
+                                info222->lpar_number, info222->name);
+               }
+
+               free_page(info);
+       }
+#endif /* DEBUG */
+       return 0;
+}
+
+/**
+ * sclp_ftp_shutdown() - shutdown of FTP services, when running on LPAR
+ */
+void sclp_ftp_shutdown(void)
+{
+       sclp_unregister(&sclp_ftp_event);
+}
diff --git a/drivers/s390/char/sclp_ftp.h b/drivers/s390/char/sclp_ftp.h
new file mode 100644 (file)
index 0000000..98ba318
--- /dev/null
@@ -0,0 +1,21 @@
+/*
+ *    SCLP Event Type (ET) 7 - Diagnostic Test FTP Services, useable on LPAR
+ *
+ *    Notice that all functions exported here are not reentrant.
+ *    So usage should be exclusive, ensured by the caller (e.g. using a
+ *    mutex).
+ *
+ *    Copyright IBM Corp. 2013
+ *    Author(s): Ralf Hoppe (rhoppe@de.ibm.com)
+ */
+
+#ifndef __SCLP_FTP_H__
+#define __SCLP_FTP_H__
+
+#include "hmcdrv_ftp.h"
+
+int sclp_ftp_startup(void);
+void sclp_ftp_shutdown(void);
+ssize_t sclp_ftp_cmd(const struct hmcdrv_ftp_cmdspec *ftp, size_t *fsize);
+
+#endif  /* __SCLP_FTP_H__ */
index 3b13d58fe87bb7cf431a912052862c3be0d6ce7f..35a84af875ee97c046c8f9e9e2b3ddacae16eddc 100644 (file)
@@ -33,7 +33,7 @@ static void sclp_rw_pm_event(struct sclp_register *reg,
 
 /* Event type structure for write message and write priority message */
 static struct sclp_register sclp_rw_event = {
-       .send_mask = EVTYP_MSG_MASK | EVTYP_PMSGCMD_MASK,
+       .send_mask = EVTYP_MSG_MASK,
        .pm_event_fn = sclp_rw_pm_event,
 };
 
@@ -456,14 +456,9 @@ sclp_emit_buffer(struct sclp_buffer *buffer,
                return -EIO;
 
        sccb = buffer->sccb;
-       if (sclp_rw_event.sclp_receive_mask & EVTYP_MSG_MASK)
-               /* Use normal write message */
-               sccb->msg_buf.header.type = EVTYP_MSG;
-       else if (sclp_rw_event.sclp_receive_mask & EVTYP_PMSGCMD_MASK)
-               /* Use write priority message */
-               sccb->msg_buf.header.type = EVTYP_PMSGCMD;
-       else
-               return -EOPNOTSUPP;
+       /* Use normal write message */
+       sccb->msg_buf.header.type = EVTYP_MSG;
+
        buffer->request.command = SCLP_CMDW_WRITE_EVENT_DATA;
        buffer->request.status = SCLP_REQ_FILLED;
        buffer->request.callback = sclp_writedata_callback;
index b9a9f721716d478559cdc169ee0d1c201a186665..ae67386c03d3b8301a581c58a68a028d70f22fbf 100644 (file)
@@ -206,10 +206,6 @@ sclp_vt220_callback(struct sclp_req *request, void *data)
 static int
 __sclp_vt220_emit(struct sclp_vt220_request *request)
 {
-       if (!(sclp_vt220_register.sclp_receive_mask & EVTYP_VT220MSG_MASK)) {
-               request->sclp_req.status = SCLP_REQ_FAILED;
-               return -EIO;
-       }
        request->sclp_req.command = SCLP_CMDW_WRITE_EVENT_DATA;
        request->sclp_req.status = SCLP_REQ_FILLED;
        request->sclp_req.callback = sclp_vt220_callback;
index 6dc60725de92f704a15dd5c877410832221ec5b8..77f9b9c2f7019d822a5bb9b96459af51f169d67f 100644 (file)
@@ -402,7 +402,9 @@ __tapechar_ioctl(struct tape_device *device,
                memset(&get, 0, sizeof(get));
                get.mt_type = MT_ISUNKNOWN;
                get.mt_resid = 0 /* device->devstat.rescnt */;
-               get.mt_dsreg = device->tape_state;
+               get.mt_dsreg =
+                       ((device->char_data.block_size << MT_ST_BLKSIZE_SHIFT)
+                        & MT_ST_BLKSIZE_MASK);
                /* FIXME: mt_gstat, mt_erreg, mt_fileno */
                get.mt_gstat = 0;
                get.mt_erreg = 0;
index a8848db7b09dd25f5d7dadb6a743dcb28f0262b0..9bb48d70957cb254d6858e08d3db09c796df6c98 100644 (file)
@@ -338,7 +338,6 @@ static int vmlogrdr_open (struct inode *inode, struct file *filp)
 
        /* set the file options */
        filp->private_data = logptr;
-       filp->f_op = &vmlogrdr_fops;
 
        /* start recording for this service*/
        if (logptr->autorecording) {
index 1884653e4472423bbb9e95fc7aa1dfdffa085495..efcf48481c5fa0fd1f6eea4e81d2469cccffe3df 100644 (file)
@@ -28,6 +28,7 @@
 #include <asm/processor.h>
 #include <asm/irqflags.h>
 #include <asm/checksum.h>
+#include <asm/switch_to.h>
 #include "sclp.h"
 
 #define TRACE(x...) debug_sprintf_event(zcore_dbf, 1, x)
@@ -149,18 +150,21 @@ static int memcpy_hsa_kernel(void *dest, unsigned long src, size_t count)
 
 static int __init init_cpu_info(enum arch_id arch)
 {
-       struct save_area *sa;
+       struct save_area_ext *sa_ext;
 
        /* get info for boot cpu from lowcore, stored in the HSA */
 
-       sa = dump_save_area_create(0);
-       if (!sa)
+       sa_ext = dump_save_area_create(0);
+       if (!sa_ext)
                return -ENOMEM;
-       if (memcpy_hsa_kernel(sa, sys_info.sa_base, sys_info.sa_size) < 0) {
+       if (memcpy_hsa_kernel(&sa_ext->sa, sys_info.sa_base,
+                             sys_info.sa_size) < 0) {
                TRACE("could not copy from HSA\n");
-               kfree(sa);
+               kfree(sa_ext);
                return -EIO;
        }
+       if (MACHINE_HAS_VX)
+               save_vx_regs_safe(sa_ext->vx_regs);
        return 0;
 }
 
@@ -258,7 +262,7 @@ static int zcore_add_lc(char __user *buf, unsigned long start, size_t count)
                unsigned long sa_start, sa_end; /* save area range */
                unsigned long prefix;
                unsigned long sa_off, len, buf_off;
-               struct save_area *save_area = dump_save_areas.areas[i];
+               struct save_area *save_area = &dump_save_areas.areas[i]->sa;
 
                prefix = save_area->pref_reg;
                sa_start = prefix + sys_info.sa_base;
@@ -612,7 +616,7 @@ static void __init zcore_header_init(int arch, struct zcore_header *hdr,
        hdr->tod = get_tod_clock();
        get_cpu_id(&hdr->cpu_id);
        for (i = 0; i < dump_save_areas.count; i++) {
-               prefix = dump_save_areas.areas[i]->pref_reg;
+               prefix = dump_save_areas.areas[i]->sa.pref_reg;
                hdr->real_cpu_cnt++;
                if (!prefix)
                        continue;
index 00bfbee0af9e0ebf54defb9759801337ec3dc8e7..56eb4ee4deba05e4a5d1bd59d50ab6408d219000 100644 (file)
@@ -87,7 +87,7 @@ static irqreturn_t do_airq_interrupt(int irq, void *dummy)
        struct airq_struct *airq;
        struct hlist_head *head;
 
-       __this_cpu_write(s390_idle.nohz_delay, 1);
+       set_cpu_flag(CIF_NOHZ_DELAY);
        tpi_info = (struct tpi_info *) &get_irq_regs()->int_code;
        head = &airq_lists[tpi_info->isc];
        rcu_read_lock();
index d497aa05a72f1da5f2e4b56091c06329696d0130..c692dfebd0bab1c808f460349dff194b028f5c5c 100644 (file)
@@ -257,11 +257,11 @@ static ssize_t chp_status_write(struct device *dev,
        if (!num_args)
                return count;
 
-       if (!strnicmp(cmd, "on", 2) || !strcmp(cmd, "1")) {
+       if (!strncasecmp(cmd, "on", 2) || !strcmp(cmd, "1")) {
                mutex_lock(&cp->lock);
                error = s390_vary_chpid(cp->chpid, 1);
                mutex_unlock(&cp->lock);
-       } else if (!strnicmp(cmd, "off", 3) || !strcmp(cmd, "0")) {
+       } else if (!strncasecmp(cmd, "off", 3) || !strcmp(cmd, "0")) {
                mutex_lock(&cp->lock);
                error = s390_vary_chpid(cp->chpid, 0);
                mutex_unlock(&cp->lock);
index 2905d8b0ec95b7db0e14b7e2e129af202b5c12ab..d5a6f287d2fed8ef18c3702c0ec1ab1684cbe79f 100644 (file)
@@ -561,7 +561,7 @@ static irqreturn_t do_cio_interrupt(int irq, void *dummy)
        struct subchannel *sch;
        struct irb *irb;
 
-       __this_cpu_write(s390_idle.nohz_delay, 1);
+       set_cpu_flag(CIF_NOHZ_DELAY);
        tpi_info = (struct tpi_info *) &get_irq_regs()->int_code;
        irb = &__get_cpu_var(cio_irb);
        sch = (struct subchannel *)(unsigned long) tpi_info->intparm;
index 4038437ff033f892d30c746056bbb16d12e40c5a..99485415dcc2502f540490df5d443d3f92183563 100644 (file)
@@ -664,6 +664,17 @@ static ssize_t ap_hwtype_show(struct device *dev,
 }
 
 static DEVICE_ATTR(hwtype, 0444, ap_hwtype_show, NULL);
+
+static ssize_t ap_raw_hwtype_show(struct device *dev,
+                             struct device_attribute *attr, char *buf)
+{
+       struct ap_device *ap_dev = to_ap_dev(dev);
+
+       return snprintf(buf, PAGE_SIZE, "%d\n", ap_dev->raw_hwtype);
+}
+
+static DEVICE_ATTR(raw_hwtype, 0444, ap_raw_hwtype_show, NULL);
+
 static ssize_t ap_depth_show(struct device *dev, struct device_attribute *attr,
                             char *buf)
 {
@@ -734,6 +745,7 @@ static DEVICE_ATTR(ap_functions, 0444, ap_functions_show, NULL);
 
 static struct attribute *ap_dev_attrs[] = {
        &dev_attr_hwtype.attr,
+       &dev_attr_raw_hwtype.attr,
        &dev_attr_depth.attr,
        &dev_attr_request_count.attr,
        &dev_attr_requestq_count.attr,
@@ -1188,6 +1200,10 @@ static int ap_select_domain(void)
        ap_qid_t qid;
        int rc, i, j;
 
+       /* IF APXA isn't installed, only 16 domains could be defined */
+       if (!ap_configuration->ap_extended && (ap_domain_index > 15))
+               return -EINVAL;
+
        /*
         * We want to use a single domain. Either the one specified with
         * the "domain=" parameter or the domain with the maximum number
@@ -1413,9 +1429,13 @@ static void ap_scan_bus(struct work_struct *unused)
                                continue;
                        }
                        break;
+               case 11:
+                       ap_dev->device_type = 10;
+                       break;
                default:
                        ap_dev->device_type = device_type;
                }
+               ap_dev->raw_hwtype = device_type;
 
                rc = ap_query_functions(qid, &device_functions);
                if (!rc)
@@ -1900,9 +1920,15 @@ static void ap_reset_all(void)
 {
        int i, j;
 
-       for (i = 0; i < AP_DOMAINS; i++)
-               for (j = 0; j < AP_DEVICES; j++)
+       for (i = 0; i < AP_DOMAINS; i++) {
+               if (!ap_test_config_domain(i))
+                       continue;
+               for (j = 0; j < AP_DEVICES; j++) {
+                       if (!ap_test_config_card_id(j))
+                               continue;
                        ap_reset_queue(AP_MKQID(j, i));
+               }
+       }
 }
 
 static struct reset_call ap_reset_call = {
index 6405ae24a7a69674ddc602d5bbef2a9ccd29d7bf..055a0f956d171865c2e2c01b121c7ccd4e5198aa 100644 (file)
@@ -31,7 +31,7 @@
 #include <linux/types.h>
 
 #define AP_DEVICES 64          /* Number of AP devices. */
-#define AP_DOMAINS 16          /* Number of AP domains. */
+#define AP_DOMAINS 256         /* Number of AP domains. */
 #define AP_MAX_RESET 90                /* Maximum number of resets. */
 #define AP_RESET_TIMEOUT (HZ*0.7)      /* Time in ticks for reset timeouts. */
 #define AP_CONFIG_TIME 30      /* Time in seconds between AP bus rescans. */
@@ -45,9 +45,9 @@ extern int ap_domain_index;
  */
 typedef unsigned int ap_qid_t;
 
-#define AP_MKQID(_device,_queue) (((_device) & 63) << 8 | ((_queue) & 15))
+#define AP_MKQID(_device, _queue) (((_device) & 63) << 8 | ((_queue) & 255))
 #define AP_QID_DEVICE(_qid) (((_qid) >> 8) & 63)
-#define AP_QID_QUEUE(_qid) ((_qid) & 15)
+#define AP_QID_QUEUE(_qid) ((_qid) & 255)
 
 /**
  * structy ap_queue_status - Holds the AP queue status.
@@ -161,6 +161,7 @@ struct ap_device {
        ap_qid_t qid;                   /* AP queue id. */
        int queue_depth;                /* AP queue depth.*/
        int device_type;                /* AP device type. */
+       int raw_hwtype;                 /* AP raw hardware type. */
        unsigned int functions;         /* AP device function bitfield. */
        int unregistered;               /* marks AP device as unregistered */
        struct timer_list timeout;      /* Timer for request timeouts. */
index 0e18c5dcd91f3bfe28954dbd49cc626517ee6238..08f1830cbfc4020e5901b9ae1f12fae518f29ac5 100644 (file)
@@ -343,10 +343,11 @@ struct zcrypt_ops *__ops_lookup(unsigned char *name, int variant)
                        break;
                }
        }
+       if (!found || !try_module_get(zops->owner))
+               zops = NULL;
+
        spin_unlock_bh(&zcrypt_ops_list_lock);
 
-       if (!found)
-               return NULL;
        return zops;
 }
 
@@ -359,8 +360,6 @@ struct zcrypt_ops *zcrypt_msgtype_request(unsigned char *name, int variant)
                request_module("%s", name);
                zops = __ops_lookup(name, variant);
        }
-       if ((!zops) || (!try_module_get(zops->owner)))
-               return NULL;
        return zops;
 }
 EXPORT_SYMBOL(zcrypt_msgtype_request);
index fbc6701bef30811c7359861fcf6b81da39f6476d..213e54ee8a6660de47b05825f4ba5265bccd3463 100644 (file)
@@ -481,7 +481,6 @@ claw_open(struct net_device *dev)
                 spin_unlock_irqrestore(
                        get_ccwdev_lock(privptr->channel[i].cdev), saveflags);
                 schedule();
-               set_current_state(TASK_RUNNING);
                 remove_wait_queue(&privptr->channel[i].wait, &wait);
                 if(rc != 0)
                         ccw_check_return_code(privptr->channel[i].cdev, rc);
@@ -828,7 +827,6 @@ claw_release(struct net_device *dev)
                spin_unlock_irqrestore(
                        get_ccwdev_lock(privptr->channel[i].cdev), saveflags);
                schedule();
-               set_current_state(TASK_RUNNING);
                remove_wait_queue(&privptr->channel[i].wait, &wait);
                if (rc != 0) {
                         ccw_check_return_code(privptr->channel[i].cdev, rc);
index e85e64a07d02f1852df460c1d8dc613821dfef91..296619b7426c5cb1de04a4556e9531a919106fff 100644 (file)
@@ -587,6 +587,16 @@ config VMWARE_PVSCSI
          To compile this driver as a module, choose M here: the
          module will be called vmw_pvscsi.
 
+config XEN_SCSI_FRONTEND
+       tristate "XEN SCSI frontend driver"
+       depends on SCSI && XEN
+       select XEN_XENBUS_FRONTEND
+       help
+         The XEN SCSI frontend driver allows the kernel to access SCSI Devices
+         within another guest OS (usually Dom0).
+         Only needed if the kernel is running in a XEN guest and generic
+         SCSI access to a device is needed.
+
 config HYPERV_STORAGE
        tristate "Microsoft Hyper-V virtual storage driver"
        depends on SCSI && HYPERV
index 5f0d299b009384446a07ff99587e346fbdfdb4fb..59f1ce6df2d6461af2136a784252f44d0dc351c1 100644 (file)
@@ -141,6 +141,7 @@ obj-$(CONFIG_SCSI_ESAS2R)   += esas2r/
 obj-$(CONFIG_SCSI_PMCRAID)     += pmcraid.o
 obj-$(CONFIG_SCSI_VIRTIO)      += virtio_scsi.o
 obj-$(CONFIG_VMWARE_PVSCSI)    += vmw_pvscsi.o
+obj-$(CONFIG_XEN_SCSI_FRONTEND)        += xen-scsifront.o
 obj-$(CONFIG_HYPERV_STORAGE)   += hv_storvsc.o
 
 obj-$(CONFIG_ARM)              += arm/
index 00ee0ed642aac717fd8c0b1e2976c860ccb664ff..4a8ac7d8c76b25467e5f51087f3f2ff6d6e2f5dd 100644 (file)
@@ -1884,7 +1884,6 @@ retry:
                        set_current_state(TASK_INTERRUPTIBLE);
                        spin_unlock_bh(&p->fcoe_rx_list.lock);
                        schedule();
-                       set_current_state(TASK_RUNNING);
                        goto retry;
                }
 
index 52a216f21ae579644b97c093e89e12306a265595..e5afc3884d74a68a3f180188edb3fb75c5fba762 100644 (file)
@@ -528,7 +528,7 @@ ips_setup(char *ips_str)
                 * Update the variables
                 */
                for (i = 0; i < ARRAY_SIZE(options); i++) {
-                       if (strnicmp
+                       if (strncasecmp
                            (key, options[i].option_name,
                             strlen(options[i].option_name)) == 0) {
                                if (value)
index dabd25429c58fc1e281cb6321335dc1a59ff75ce..db3dbd999cb6b1aec722c7ead94769d8eebb91a4 100644 (file)
@@ -4875,7 +4875,6 @@ qla2x00_do_dpc(void *data)
                    "DPC handler sleeping.\n");
 
                schedule();
-               __set_current_state(TASK_RUNNING);
 
                if (!base_vha->flags.init_done || ha->flags.mbox_busy)
                        goto end_loop;
index 2b6d447ad6d641723169cb45af42efdab5cb16be..238e06f13b8a1c977146699d95f1783bbef571e7 100644 (file)
@@ -3371,7 +3371,7 @@ static ssize_t opts_store(struct device_driver *ddp, const char *buf,
        char work[20];
 
         if (1 == sscanf(buf, "%10s", work)) {
-               if (0 == strnicmp(work,"0x", 2)) {
+               if (0 == strncasecmp(work,"0x", 2)) {
                        if (1 == sscanf(&work[2], "%x", &opts))
                                goto opts_done;
                } else {
diff --git a/drivers/scsi/xen-scsifront.c b/drivers/scsi/xen-scsifront.c
new file mode 100644 (file)
index 0000000..34199d2
--- /dev/null
@@ -0,0 +1,1026 @@
+/*
+ * Xen SCSI frontend driver
+ *
+ * Copyright (c) 2008, FUJITSU Limited
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation; or, when distributed
+ * separately from the Linux kernel or incorporated into other
+ * software packages, subject to the following license:
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this source file (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy, modify,
+ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/wait.h>
+#include <linux/interrupt.h>
+#include <linux/mutex.h>
+#include <linux/spinlock.h>
+#include <linux/sched.h>
+#include <linux/blkdev.h>
+#include <linux/pfn.h>
+#include <linux/slab.h>
+#include <linux/bitops.h>
+
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi.h>
+#include <scsi/scsi_host.h>
+
+#include <xen/xen.h>
+#include <xen/xenbus.h>
+#include <xen/grant_table.h>
+#include <xen/events.h>
+#include <xen/page.h>
+
+#include <xen/interface/grant_table.h>
+#include <xen/interface/io/vscsiif.h>
+#include <xen/interface/io/protocols.h>
+
+#include <asm/xen/hypervisor.h>
+
+
+#define GRANT_INVALID_REF      0
+
+#define VSCSIFRONT_OP_ADD_LUN  1
+#define VSCSIFRONT_OP_DEL_LUN  2
+
+/* Tuning point. */
+#define VSCSIIF_DEFAULT_CMD_PER_LUN 10
+#define VSCSIIF_MAX_TARGET          64
+#define VSCSIIF_MAX_LUN             255
+
+#define VSCSIIF_RING_SIZE      __CONST_RING_SIZE(vscsiif, PAGE_SIZE)
+#define VSCSIIF_MAX_REQS       VSCSIIF_RING_SIZE
+
+#define vscsiif_grants_sg(_sg) (PFN_UP((_sg) *         \
+                               sizeof(struct scsiif_request_segment)))
+
+struct vscsifrnt_shadow {
+       /* command between backend and frontend */
+       unsigned char act;
+       uint16_t rqid;
+
+       unsigned int nr_grants;         /* number of grants in gref[] */
+       struct scsiif_request_segment *sg;      /* scatter/gather elements */
+
+       /* Do reset or abort function. */
+       wait_queue_head_t wq_reset;     /* reset work queue           */
+       int wait_reset;                 /* reset work queue condition */
+       int32_t rslt_reset;             /* reset response status:     */
+                                       /* SUCCESS or FAILED or:      */
+#define RSLT_RESET_WAITING     0
+#define RSLT_RESET_ERR         -1
+
+       /* Requested struct scsi_cmnd is stored from kernel. */
+       struct scsi_cmnd *sc;
+       int gref[vscsiif_grants_sg(SG_ALL) + SG_ALL];
+};
+
+struct vscsifrnt_info {
+       struct xenbus_device *dev;
+
+       struct Scsi_Host *host;
+       int host_active;
+
+       unsigned int evtchn;
+       unsigned int irq;
+
+       grant_ref_t ring_ref;
+       struct vscsiif_front_ring ring;
+       struct vscsiif_response ring_rsp;
+
+       spinlock_t shadow_lock;
+       DECLARE_BITMAP(shadow_free_bitmap, VSCSIIF_MAX_REQS);
+       struct vscsifrnt_shadow *shadow[VSCSIIF_MAX_REQS];
+
+       wait_queue_head_t wq_sync;
+       unsigned int wait_ring_available:1;
+
+       char dev_state_path[64];
+       struct task_struct *curr;
+};
+
+static DEFINE_MUTEX(scsifront_mutex);
+
+static void scsifront_wake_up(struct vscsifrnt_info *info)
+{
+       info->wait_ring_available = 0;
+       wake_up(&info->wq_sync);
+}
+
+static int scsifront_get_rqid(struct vscsifrnt_info *info)
+{
+       unsigned long flags;
+       int free;
+
+       spin_lock_irqsave(&info->shadow_lock, flags);
+
+       free = find_first_bit(info->shadow_free_bitmap, VSCSIIF_MAX_REQS);
+       __clear_bit(free, info->shadow_free_bitmap);
+
+       spin_unlock_irqrestore(&info->shadow_lock, flags);
+
+       return free;
+}
+
+static int _scsifront_put_rqid(struct vscsifrnt_info *info, uint32_t id)
+{
+       int empty = bitmap_empty(info->shadow_free_bitmap, VSCSIIF_MAX_REQS);
+
+       __set_bit(id, info->shadow_free_bitmap);
+       info->shadow[id] = NULL;
+
+       return empty || info->wait_ring_available;
+}
+
+static void scsifront_put_rqid(struct vscsifrnt_info *info, uint32_t id)
+{
+       unsigned long flags;
+       int kick;
+
+       spin_lock_irqsave(&info->shadow_lock, flags);
+       kick = _scsifront_put_rqid(info, id);
+       spin_unlock_irqrestore(&info->shadow_lock, flags);
+
+       if (kick)
+               scsifront_wake_up(info);
+}
+
+static struct vscsiif_request *scsifront_pre_req(struct vscsifrnt_info *info)
+{
+       struct vscsiif_front_ring *ring = &(info->ring);
+       struct vscsiif_request *ring_req;
+       uint32_t id;
+
+       id = scsifront_get_rqid(info);  /* use id in response */
+       if (id >= VSCSIIF_MAX_REQS)
+               return NULL;
+
+       ring_req = RING_GET_REQUEST(&(info->ring), ring->req_prod_pvt);
+
+       ring->req_prod_pvt++;
+
+       ring_req->rqid = (uint16_t)id;
+
+       return ring_req;
+}
+
+static void scsifront_do_request(struct vscsifrnt_info *info)
+{
+       struct vscsiif_front_ring *ring = &(info->ring);
+       int notify;
+
+       RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(ring, notify);
+       if (notify)
+               notify_remote_via_irq(info->irq);
+}
+
+static void scsifront_gnttab_done(struct vscsifrnt_info *info, uint32_t id)
+{
+       struct vscsifrnt_shadow *s = info->shadow[id];
+       int i;
+
+       if (s->sc->sc_data_direction == DMA_NONE)
+               return;
+
+       for (i = 0; i < s->nr_grants; i++) {
+               if (unlikely(gnttab_query_foreign_access(s->gref[i]) != 0)) {
+                       shost_printk(KERN_ALERT, info->host, KBUILD_MODNAME
+                                    "grant still in use by backend\n");
+                       BUG();
+               }
+               gnttab_end_foreign_access(s->gref[i], 0, 0UL);
+       }
+
+       kfree(s->sg);
+}
+
+static void scsifront_cdb_cmd_done(struct vscsifrnt_info *info,
+                                  struct vscsiif_response *ring_rsp)
+{
+       struct scsi_cmnd *sc;
+       uint32_t id;
+       uint8_t sense_len;
+
+       id = ring_rsp->rqid;
+       sc = info->shadow[id]->sc;
+
+       BUG_ON(sc == NULL);
+
+       scsifront_gnttab_done(info, id);
+       scsifront_put_rqid(info, id);
+
+       sc->result = ring_rsp->rslt;
+       scsi_set_resid(sc, ring_rsp->residual_len);
+
+       sense_len = min_t(uint8_t, VSCSIIF_SENSE_BUFFERSIZE,
+                         ring_rsp->sense_len);
+
+       if (sense_len)
+               memcpy(sc->sense_buffer, ring_rsp->sense_buffer, sense_len);
+
+       sc->scsi_done(sc);
+}
+
+static void scsifront_sync_cmd_done(struct vscsifrnt_info *info,
+                                   struct vscsiif_response *ring_rsp)
+{
+       uint16_t id = ring_rsp->rqid;
+       unsigned long flags;
+       struct vscsifrnt_shadow *shadow = info->shadow[id];
+       int kick;
+
+       spin_lock_irqsave(&info->shadow_lock, flags);
+       shadow->wait_reset = 1;
+       switch (shadow->rslt_reset) {
+       case RSLT_RESET_WAITING:
+               shadow->rslt_reset = ring_rsp->rslt;
+               break;
+       case RSLT_RESET_ERR:
+               kick = _scsifront_put_rqid(info, id);
+               spin_unlock_irqrestore(&info->shadow_lock, flags);
+               kfree(shadow);
+               if (kick)
+                       scsifront_wake_up(info);
+               return;
+       default:
+               shost_printk(KERN_ERR, info->host, KBUILD_MODNAME
+                            "bad reset state %d, possibly leaking %u\n",
+                            shadow->rslt_reset, id);
+               break;
+       }
+       spin_unlock_irqrestore(&info->shadow_lock, flags);
+
+       wake_up(&shadow->wq_reset);
+}
+
+static int scsifront_cmd_done(struct vscsifrnt_info *info)
+{
+       struct vscsiif_response *ring_rsp;
+       RING_IDX i, rp;
+       int more_to_do = 0;
+       unsigned long flags;
+
+       spin_lock_irqsave(info->host->host_lock, flags);
+
+       rp = info->ring.sring->rsp_prod;
+       rmb();  /* ordering required respective to dom0 */
+       for (i = info->ring.rsp_cons; i != rp; i++) {
+
+               ring_rsp = RING_GET_RESPONSE(&info->ring, i);
+
+               if (WARN(ring_rsp->rqid >= VSCSIIF_MAX_REQS ||
+                        test_bit(ring_rsp->rqid, info->shadow_free_bitmap),
+                        "illegal rqid %u returned by backend!\n",
+                        ring_rsp->rqid))
+                       continue;
+
+               if (info->shadow[ring_rsp->rqid]->act == VSCSIIF_ACT_SCSI_CDB)
+                       scsifront_cdb_cmd_done(info, ring_rsp);
+               else
+                       scsifront_sync_cmd_done(info, ring_rsp);
+       }
+
+       info->ring.rsp_cons = i;
+
+       if (i != info->ring.req_prod_pvt)
+               RING_FINAL_CHECK_FOR_RESPONSES(&info->ring, more_to_do);
+       else
+               info->ring.sring->rsp_event = i + 1;
+
+       info->wait_ring_available = 0;
+
+       spin_unlock_irqrestore(info->host->host_lock, flags);
+
+       wake_up(&info->wq_sync);
+
+       return more_to_do;
+}
+
+static irqreturn_t scsifront_irq_fn(int irq, void *dev_id)
+{
+       struct vscsifrnt_info *info = dev_id;
+
+       while (scsifront_cmd_done(info))
+               /* Yield point for this unbounded loop. */
+               cond_resched();
+
+       return IRQ_HANDLED;
+}
+
+static int map_data_for_request(struct vscsifrnt_info *info,
+                               struct scsi_cmnd *sc,
+                               struct vscsiif_request *ring_req,
+                               struct vscsifrnt_shadow *shadow)
+{
+       grant_ref_t gref_head;
+       struct page *page;
+       int err, ref, ref_cnt = 0;
+       int grant_ro = (sc->sc_data_direction == DMA_TO_DEVICE);
+       unsigned int i, off, len, bytes;
+       unsigned int data_len = scsi_bufflen(sc);
+       unsigned int data_grants = 0, seg_grants = 0;
+       struct scatterlist *sg;
+       unsigned long mfn;
+       struct scsiif_request_segment *seg;
+
+       ring_req->nr_segments = 0;
+       if (sc->sc_data_direction == DMA_NONE || !data_len)
+               return 0;
+
+       scsi_for_each_sg(sc, sg, scsi_sg_count(sc), i)
+               data_grants += PFN_UP(sg->offset + sg->length);
+
+       if (data_grants > VSCSIIF_SG_TABLESIZE) {
+               if (data_grants > info->host->sg_tablesize) {
+                       shost_printk(KERN_ERR, info->host, KBUILD_MODNAME
+                            "Unable to map request_buffer for command!\n");
+                       return -E2BIG;
+               }
+               seg_grants = vscsiif_grants_sg(data_grants);
+               shadow->sg = kcalloc(data_grants,
+                       sizeof(struct scsiif_request_segment), GFP_ATOMIC);
+               if (!shadow->sg)
+                       return -ENOMEM;
+       }
+       seg = shadow->sg ? : ring_req->seg;
+
+       err = gnttab_alloc_grant_references(seg_grants + data_grants,
+                                           &gref_head);
+       if (err) {
+               kfree(shadow->sg);
+               shost_printk(KERN_ERR, info->host, KBUILD_MODNAME
+                            "gnttab_alloc_grant_references() error\n");
+               return -ENOMEM;
+       }
+
+       if (seg_grants) {
+               page = virt_to_page(seg);
+               off = (unsigned long)seg & ~PAGE_MASK;
+               len = sizeof(struct scsiif_request_segment) * data_grants;
+               while (len > 0) {
+                       bytes = min_t(unsigned int, len, PAGE_SIZE - off);
+
+                       ref = gnttab_claim_grant_reference(&gref_head);
+                       BUG_ON(ref == -ENOSPC);
+
+                       mfn = pfn_to_mfn(page_to_pfn(page));
+                       gnttab_grant_foreign_access_ref(ref,
+                               info->dev->otherend_id, mfn, 1);
+                       shadow->gref[ref_cnt] = ref;
+                       ring_req->seg[ref_cnt].gref   = ref;
+                       ring_req->seg[ref_cnt].offset = (uint16_t)off;
+                       ring_req->seg[ref_cnt].length = (uint16_t)bytes;
+
+                       page++;
+                       len -= bytes;
+                       off = 0;
+                       ref_cnt++;
+               }
+               BUG_ON(seg_grants < ref_cnt);
+               seg_grants = ref_cnt;
+       }
+
+       scsi_for_each_sg(sc, sg, scsi_sg_count(sc), i) {
+               page = sg_page(sg);
+               off = sg->offset;
+               len = sg->length;
+
+               while (len > 0 && data_len > 0) {
+                       /*
+                        * sg sends a scatterlist that is larger than
+                        * the data_len it wants transferred for certain
+                        * IO sizes.
+                        */
+                       bytes = min_t(unsigned int, len, PAGE_SIZE - off);
+                       bytes = min(bytes, data_len);
+
+                       ref = gnttab_claim_grant_reference(&gref_head);
+                       BUG_ON(ref == -ENOSPC);
+
+                       mfn = pfn_to_mfn(page_to_pfn(page));
+                       gnttab_grant_foreign_access_ref(ref,
+                               info->dev->otherend_id, mfn, grant_ro);
+
+                       shadow->gref[ref_cnt] = ref;
+                       seg->gref   = ref;
+                       seg->offset = (uint16_t)off;
+                       seg->length = (uint16_t)bytes;
+
+                       page++;
+                       seg++;
+                       len -= bytes;
+                       data_len -= bytes;
+                       off = 0;
+                       ref_cnt++;
+               }
+       }
+
+       if (seg_grants)
+               ring_req->nr_segments = VSCSIIF_SG_GRANT | seg_grants;
+       else
+               ring_req->nr_segments = (uint8_t)ref_cnt;
+       shadow->nr_grants = ref_cnt;
+
+       return 0;
+}
+
+static struct vscsiif_request *scsifront_command2ring(
+               struct vscsifrnt_info *info, struct scsi_cmnd *sc,
+               struct vscsifrnt_shadow *shadow)
+{
+       struct vscsiif_request *ring_req;
+
+       memset(shadow, 0, sizeof(*shadow));
+
+       ring_req = scsifront_pre_req(info);
+       if (!ring_req)
+               return NULL;
+
+       info->shadow[ring_req->rqid] = shadow;
+       shadow->rqid = ring_req->rqid;
+
+       ring_req->id      = sc->device->id;
+       ring_req->lun     = sc->device->lun;
+       ring_req->channel = sc->device->channel;
+       ring_req->cmd_len = sc->cmd_len;
+
+       BUG_ON(sc->cmd_len > VSCSIIF_MAX_COMMAND_SIZE);
+
+       memcpy(ring_req->cmnd, sc->cmnd, sc->cmd_len);
+
+       ring_req->sc_data_direction   = (uint8_t)sc->sc_data_direction;
+       ring_req->timeout_per_command = sc->request->timeout / HZ;
+
+       return ring_req;
+}
+
+static int scsifront_queuecommand(struct Scsi_Host *shost,
+                                 struct scsi_cmnd *sc)
+{
+       struct vscsifrnt_info *info = shost_priv(shost);
+       struct vscsiif_request *ring_req;
+       struct vscsifrnt_shadow *shadow = scsi_cmd_priv(sc);
+       unsigned long flags;
+       int err;
+       uint16_t rqid;
+
+       spin_lock_irqsave(shost->host_lock, flags);
+       if (RING_FULL(&info->ring))
+               goto busy;
+
+       ring_req = scsifront_command2ring(info, sc, shadow);
+       if (!ring_req)
+               goto busy;
+
+       sc->result = 0;
+
+       rqid = ring_req->rqid;
+       ring_req->act = VSCSIIF_ACT_SCSI_CDB;
+
+       shadow->sc  = sc;
+       shadow->act = VSCSIIF_ACT_SCSI_CDB;
+
+       err = map_data_for_request(info, sc, ring_req, shadow);
+       if (err < 0) {
+               pr_debug("%s: err %d\n", __func__, err);
+               scsifront_put_rqid(info, rqid);
+               spin_unlock_irqrestore(shost->host_lock, flags);
+               if (err == -ENOMEM)
+                       return SCSI_MLQUEUE_HOST_BUSY;
+               sc->result = DID_ERROR << 16;
+               sc->scsi_done(sc);
+               return 0;
+       }
+
+       scsifront_do_request(info);
+       spin_unlock_irqrestore(shost->host_lock, flags);
+
+       return 0;
+
+busy:
+       spin_unlock_irqrestore(shost->host_lock, flags);
+       pr_debug("%s: busy\n", __func__);
+       return SCSI_MLQUEUE_HOST_BUSY;
+}
+
+/*
+ * Any exception handling (reset or abort) must be forwarded to the backend.
+ * We have to wait until an answer is returned. This answer contains the
+ * result to be returned to the requestor.
+ */
+static int scsifront_action_handler(struct scsi_cmnd *sc, uint8_t act)
+{
+       struct Scsi_Host *host = sc->device->host;
+       struct vscsifrnt_info *info = shost_priv(host);
+       struct vscsifrnt_shadow *shadow, *s = scsi_cmd_priv(sc);
+       struct vscsiif_request *ring_req;
+       int err = 0;
+
+       shadow = kmalloc(sizeof(*shadow), GFP_NOIO);
+       if (!shadow)
+               return FAILED;
+
+       spin_lock_irq(host->host_lock);
+
+       for (;;) {
+               if (!RING_FULL(&info->ring)) {
+                       ring_req = scsifront_command2ring(info, sc, shadow);
+                       if (ring_req)
+                               break;
+               }
+               if (err) {
+                       spin_unlock_irq(host->host_lock);
+                       kfree(shadow);
+                       return FAILED;
+               }
+               info->wait_ring_available = 1;
+               spin_unlock_irq(host->host_lock);
+               err = wait_event_interruptible(info->wq_sync,
+                                              !info->wait_ring_available);
+               spin_lock_irq(host->host_lock);
+       }
+
+       ring_req->act = act;
+       ring_req->ref_rqid = s->rqid;
+
+       shadow->act = act;
+       shadow->rslt_reset = RSLT_RESET_WAITING;
+       init_waitqueue_head(&shadow->wq_reset);
+
+       ring_req->nr_segments = 0;
+
+       scsifront_do_request(info);
+
+       spin_unlock_irq(host->host_lock);
+       err = wait_event_interruptible(shadow->wq_reset, shadow->wait_reset);
+       spin_lock_irq(host->host_lock);
+
+       if (!err) {
+               err = shadow->rslt_reset;
+               scsifront_put_rqid(info, shadow->rqid);
+               kfree(shadow);
+       } else {
+               spin_lock(&info->shadow_lock);
+               shadow->rslt_reset = RSLT_RESET_ERR;
+               spin_unlock(&info->shadow_lock);
+               err = FAILED;
+       }
+
+       spin_unlock_irq(host->host_lock);
+       return err;
+}
+
+static int scsifront_eh_abort_handler(struct scsi_cmnd *sc)
+{
+       pr_debug("%s\n", __func__);
+       return scsifront_action_handler(sc, VSCSIIF_ACT_SCSI_ABORT);
+}
+
+static int scsifront_dev_reset_handler(struct scsi_cmnd *sc)
+{
+       pr_debug("%s\n", __func__);
+       return scsifront_action_handler(sc, VSCSIIF_ACT_SCSI_RESET);
+}
+
+static int scsifront_sdev_configure(struct scsi_device *sdev)
+{
+       struct vscsifrnt_info *info = shost_priv(sdev->host);
+
+       if (info && current == info->curr)
+               xenbus_printf(XBT_NIL, info->dev->nodename,
+                             info->dev_state_path, "%d", XenbusStateConnected);
+
+       return 0;
+}
+
+static void scsifront_sdev_destroy(struct scsi_device *sdev)
+{
+       struct vscsifrnt_info *info = shost_priv(sdev->host);
+
+       if (info && current == info->curr)
+               xenbus_printf(XBT_NIL, info->dev->nodename,
+                             info->dev_state_path, "%d", XenbusStateClosed);
+}
+
+static struct scsi_host_template scsifront_sht = {
+       .module                 = THIS_MODULE,
+       .name                   = "Xen SCSI frontend driver",
+       .queuecommand           = scsifront_queuecommand,
+       .eh_abort_handler       = scsifront_eh_abort_handler,
+       .eh_device_reset_handler = scsifront_dev_reset_handler,
+       .slave_configure        = scsifront_sdev_configure,
+       .slave_destroy          = scsifront_sdev_destroy,
+       .cmd_per_lun            = VSCSIIF_DEFAULT_CMD_PER_LUN,
+       .can_queue              = VSCSIIF_MAX_REQS,
+       .this_id                = -1,
+       .cmd_size               = sizeof(struct vscsifrnt_shadow),
+       .sg_tablesize           = VSCSIIF_SG_TABLESIZE,
+       .use_clustering         = DISABLE_CLUSTERING,
+       .proc_name              = "scsifront",
+};
+
+static int scsifront_alloc_ring(struct vscsifrnt_info *info)
+{
+       struct xenbus_device *dev = info->dev;
+       struct vscsiif_sring *sring;
+       int err = -ENOMEM;
+
+       /***** Frontend to Backend ring start *****/
+       sring = (struct vscsiif_sring *)__get_free_page(GFP_KERNEL);
+       if (!sring) {
+               xenbus_dev_fatal(dev, err,
+                       "fail to allocate shared ring (Front to Back)");
+               return err;
+       }
+       SHARED_RING_INIT(sring);
+       FRONT_RING_INIT(&info->ring, sring, PAGE_SIZE);
+
+       err = xenbus_grant_ring(dev, virt_to_mfn(sring));
+       if (err < 0) {
+               free_page((unsigned long)sring);
+               xenbus_dev_fatal(dev, err,
+                       "fail to grant shared ring (Front to Back)");
+               return err;
+       }
+       info->ring_ref = err;
+
+       err = xenbus_alloc_evtchn(dev, &info->evtchn);
+       if (err) {
+               xenbus_dev_fatal(dev, err, "xenbus_alloc_evtchn");
+               goto free_gnttab;
+       }
+
+       err = bind_evtchn_to_irq(info->evtchn);
+       if (err <= 0) {
+               xenbus_dev_fatal(dev, err, "bind_evtchn_to_irq");
+               goto free_gnttab;
+       }
+
+       info->irq = err;
+
+       err = request_threaded_irq(info->irq, NULL, scsifront_irq_fn,
+                                  IRQF_ONESHOT, "scsifront", info);
+       if (err) {
+               xenbus_dev_fatal(dev, err, "request_threaded_irq");
+               goto free_irq;
+       }
+
+       return 0;
+
+/* free resource */
+free_irq:
+       unbind_from_irqhandler(info->irq, info);
+free_gnttab:
+       gnttab_end_foreign_access(info->ring_ref, 0,
+                                 (unsigned long)info->ring.sring);
+
+       return err;
+}
+
+static int scsifront_init_ring(struct vscsifrnt_info *info)
+{
+       struct xenbus_device *dev = info->dev;
+       struct xenbus_transaction xbt;
+       int err;
+
+       pr_debug("%s\n", __func__);
+
+       err = scsifront_alloc_ring(info);
+       if (err)
+               return err;
+       pr_debug("%s: %u %u\n", __func__, info->ring_ref, info->evtchn);
+
+again:
+       err = xenbus_transaction_start(&xbt);
+       if (err)
+               xenbus_dev_fatal(dev, err, "starting transaction");
+
+       err = xenbus_printf(xbt, dev->nodename, "ring-ref", "%u",
+                           info->ring_ref);
+       if (err) {
+               xenbus_dev_fatal(dev, err, "%s", "writing ring-ref");
+               goto fail;
+       }
+
+       err = xenbus_printf(xbt, dev->nodename, "event-channel", "%u",
+                           info->evtchn);
+
+       if (err) {
+               xenbus_dev_fatal(dev, err, "%s", "writing event-channel");
+               goto fail;
+       }
+
+       err = xenbus_transaction_end(xbt, 0);
+       if (err) {
+               if (err == -EAGAIN)
+                       goto again;
+               xenbus_dev_fatal(dev, err, "completing transaction");
+               goto free_sring;
+       }
+
+       return 0;
+
+fail:
+       xenbus_transaction_end(xbt, 1);
+free_sring:
+       unbind_from_irqhandler(info->irq, info);
+       gnttab_end_foreign_access(info->ring_ref, 0,
+                                 (unsigned long)info->ring.sring);
+
+       return err;
+}
+
+
+static int scsifront_probe(struct xenbus_device *dev,
+                          const struct xenbus_device_id *id)
+{
+       struct vscsifrnt_info *info;
+       struct Scsi_Host *host;
+       int err = -ENOMEM;
+       char name[TASK_COMM_LEN];
+
+       host = scsi_host_alloc(&scsifront_sht, sizeof(*info));
+       if (!host) {
+               xenbus_dev_fatal(dev, err, "fail to allocate scsi host");
+               return err;
+       }
+       info = (struct vscsifrnt_info *)host->hostdata;
+
+       dev_set_drvdata(&dev->dev, info);
+       info->dev = dev;
+
+       bitmap_fill(info->shadow_free_bitmap, VSCSIIF_MAX_REQS);
+
+       err = scsifront_init_ring(info);
+       if (err) {
+               scsi_host_put(host);
+               return err;
+       }
+
+       init_waitqueue_head(&info->wq_sync);
+       spin_lock_init(&info->shadow_lock);
+
+       snprintf(name, TASK_COMM_LEN, "vscsiif.%d", host->host_no);
+
+       host->max_id      = VSCSIIF_MAX_TARGET;
+       host->max_channel = 0;
+       host->max_lun     = VSCSIIF_MAX_LUN;
+       host->max_sectors = (host->sg_tablesize - 1) * PAGE_SIZE / 512;
+       host->max_cmd_len = VSCSIIF_MAX_COMMAND_SIZE;
+
+       err = scsi_add_host(host, &dev->dev);
+       if (err) {
+               dev_err(&dev->dev, "fail to add scsi host %d\n", err);
+               goto free_sring;
+       }
+       info->host = host;
+       info->host_active = 1;
+
+       xenbus_switch_state(dev, XenbusStateInitialised);
+
+       return 0;
+
+free_sring:
+       unbind_from_irqhandler(info->irq, info);
+       gnttab_end_foreign_access(info->ring_ref, 0,
+                                 (unsigned long)info->ring.sring);
+       scsi_host_put(host);
+       return err;
+}
+
+static int scsifront_remove(struct xenbus_device *dev)
+{
+       struct vscsifrnt_info *info = dev_get_drvdata(&dev->dev);
+
+       pr_debug("%s: %s removed\n", __func__, dev->nodename);
+
+       mutex_lock(&scsifront_mutex);
+       if (info->host_active) {
+               /* Scsi_host not yet removed */
+               scsi_remove_host(info->host);
+               info->host_active = 0;
+       }
+       mutex_unlock(&scsifront_mutex);
+
+       gnttab_end_foreign_access(info->ring_ref, 0,
+                                 (unsigned long)info->ring.sring);
+       unbind_from_irqhandler(info->irq, info);
+
+       scsi_host_put(info->host);
+
+       return 0;
+}
+
+static void scsifront_disconnect(struct vscsifrnt_info *info)
+{
+       struct xenbus_device *dev = info->dev;
+       struct Scsi_Host *host = info->host;
+
+       pr_debug("%s: %s disconnect\n", __func__, dev->nodename);
+
+       /*
+        * When this function is executed, all devices of
+        * Frontend have been deleted.
+        * Therefore, it need not block I/O before remove_host.
+        */
+
+       mutex_lock(&scsifront_mutex);
+       if (info->host_active) {
+               scsi_remove_host(host);
+               info->host_active = 0;
+       }
+       mutex_unlock(&scsifront_mutex);
+
+       xenbus_frontend_closed(dev);
+}
+
+static void scsifront_do_lun_hotplug(struct vscsifrnt_info *info, int op)
+{
+       struct xenbus_device *dev = info->dev;
+       int i, err = 0;
+       char str[64];
+       char **dir;
+       unsigned int dir_n = 0;
+       unsigned int device_state;
+       unsigned int hst, chn, tgt, lun;
+       struct scsi_device *sdev;
+
+       dir = xenbus_directory(XBT_NIL, dev->otherend, "vscsi-devs", &dir_n);
+       if (IS_ERR(dir))
+               return;
+
+       /* mark current task as the one allowed to modify device states */
+       BUG_ON(info->curr);
+       info->curr = current;
+
+       for (i = 0; i < dir_n; i++) {
+               /* read status */
+               snprintf(str, sizeof(str), "vscsi-devs/%s/state", dir[i]);
+               err = xenbus_scanf(XBT_NIL, dev->otherend, str, "%u",
+                                  &device_state);
+               if (XENBUS_EXIST_ERR(err))
+                       continue;
+
+               /* virtual SCSI device */
+               snprintf(str, sizeof(str), "vscsi-devs/%s/v-dev", dir[i]);
+               err = xenbus_scanf(XBT_NIL, dev->otherend, str,
+                                  "%u:%u:%u:%u", &hst, &chn, &tgt, &lun);
+               if (XENBUS_EXIST_ERR(err))
+                       continue;
+
+               /*
+                * Front device state path, used in slave_configure called
+                * on successfull scsi_add_device, and in slave_destroy called
+                * on remove of a device.
+                */
+               snprintf(info->dev_state_path, sizeof(info->dev_state_path),
+                        "vscsi-devs/%s/state", dir[i]);
+
+               switch (op) {
+               case VSCSIFRONT_OP_ADD_LUN:
+                       if (device_state != XenbusStateInitialised)
+                               break;
+
+                       if (scsi_add_device(info->host, chn, tgt, lun)) {
+                               dev_err(&dev->dev, "scsi_add_device\n");
+                               xenbus_printf(XBT_NIL, dev->nodename,
+                                             info->dev_state_path,
+                                             "%d", XenbusStateClosed);
+                       }
+                       break;
+               case VSCSIFRONT_OP_DEL_LUN:
+                       if (device_state != XenbusStateClosing)
+                               break;
+
+                       sdev = scsi_device_lookup(info->host, chn, tgt, lun);
+                       if (sdev) {
+                               scsi_remove_device(sdev);
+                               scsi_device_put(sdev);
+                       }
+                       break;
+               default:
+                       break;
+               }
+       }
+
+       info->curr = NULL;
+
+       kfree(dir);
+}
+
+static void scsifront_read_backend_params(struct xenbus_device *dev,
+                                         struct vscsifrnt_info *info)
+{
+       unsigned int sg_grant;
+       int ret;
+       struct Scsi_Host *host = info->host;
+
+       ret = xenbus_scanf(XBT_NIL, dev->otherend, "feature-sg-grant", "%u",
+                          &sg_grant);
+       if (ret == 1 && sg_grant) {
+               sg_grant = min_t(unsigned int, sg_grant, SG_ALL);
+               sg_grant = max_t(unsigned int, sg_grant, VSCSIIF_SG_TABLESIZE);
+               host->sg_tablesize = min_t(unsigned int, sg_grant,
+                       VSCSIIF_SG_TABLESIZE * PAGE_SIZE /
+                       sizeof(struct scsiif_request_segment));
+               host->max_sectors = (host->sg_tablesize - 1) * PAGE_SIZE / 512;
+       }
+       dev_info(&dev->dev, "using up to %d SG entries\n", host->sg_tablesize);
+}
+
+static void scsifront_backend_changed(struct xenbus_device *dev,
+                                     enum xenbus_state backend_state)
+{
+       struct vscsifrnt_info *info = dev_get_drvdata(&dev->dev);
+
+       pr_debug("%s: %p %u %u\n", __func__, dev, dev->state, backend_state);
+
+       switch (backend_state) {
+       case XenbusStateUnknown:
+       case XenbusStateInitialising:
+       case XenbusStateInitWait:
+       case XenbusStateInitialised:
+               break;
+
+       case XenbusStateConnected:
+               scsifront_read_backend_params(dev, info);
+               if (xenbus_read_driver_state(dev->nodename) ==
+                   XenbusStateInitialised)
+                       scsifront_do_lun_hotplug(info, VSCSIFRONT_OP_ADD_LUN);
+
+               if (dev->state != XenbusStateConnected)
+                       xenbus_switch_state(dev, XenbusStateConnected);
+               break;
+
+       case XenbusStateClosed:
+               if (dev->state == XenbusStateClosed)
+                       break;
+               /* Missed the backend's Closing state -- fallthrough */
+       case XenbusStateClosing:
+               scsifront_disconnect(info);
+               break;
+
+       case XenbusStateReconfiguring:
+               scsifront_do_lun_hotplug(info, VSCSIFRONT_OP_DEL_LUN);
+               xenbus_switch_state(dev, XenbusStateReconfiguring);
+               break;
+
+       case XenbusStateReconfigured:
+               scsifront_do_lun_hotplug(info, VSCSIFRONT_OP_ADD_LUN);
+               xenbus_switch_state(dev, XenbusStateConnected);
+               break;
+       }
+}
+
+static const struct xenbus_device_id scsifront_ids[] = {
+       { "vscsi" },
+       { "" }
+};
+
+static struct xenbus_driver scsifront_driver = {
+       .ids                    = scsifront_ids,
+       .probe                  = scsifront_probe,
+       .remove                 = scsifront_remove,
+       .otherend_changed       = scsifront_backend_changed,
+};
+
+static int __init scsifront_init(void)
+{
+       if (!xen_domain())
+               return -ENODEV;
+
+       return xenbus_register_frontend(&scsifront_driver);
+}
+module_init(scsifront_init);
+
+static void __exit scsifront_exit(void)
+{
+       xenbus_unregister_driver(&scsifront_driver);
+}
+module_exit(scsifront_exit);
+
+MODULE_DESCRIPTION("Xen SCSI frontend driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("xen:vscsi");
+MODULE_AUTHOR("Juergen Gross <jgross@suse.com>");
index 713a9722678746f24363e3b9f3f4a0f89cc145ad..ad4f5790a76f5005fbb9d55fcf67cb85bf887770 100644 (file)
@@ -339,7 +339,7 @@ static loff_t ashmem_llseek(struct file *file, loff_t offset, int origin)
                goto out;
        }
 
-       ret = asma->file->f_op->llseek(asma->file, offset, origin);
+       ret = vfs_llseek(asma->file, offset, origin);
        if (ret < 0)
                goto out;
 
index ee3a7380e53b129ed04320940d6cae57cbbd4226..a402fdaf54ca37417e5282d1bb89008190b9a73a 100644 (file)
@@ -125,7 +125,7 @@ long compat_ion_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
 {
        long ret;
 
-       if (!filp->f_op || !filp->f_op->unlocked_ioctl)
+       if (!filp->f_op->unlocked_ioctl)
                return -ENOTTY;
 
        switch (cmd) {
index 0bf0d24d12d5b8be9f077ba3422a07832ad5e7cb..28b93d39a94eb6b76b72d1db051b2f52b48175e7 100644 (file)
@@ -411,69 +411,18 @@ static void fix_up_readers(struct logger_log *log, size_t len)
 }
 
 /*
- * do_write_log - writes 'len' bytes from 'buf' to 'log'
- *
- * The caller needs to hold log->mutex.
- */
-static void do_write_log(struct logger_log *log, const void *buf, size_t count)
-{
-       size_t len;
-
-       len = min(count, log->size - log->w_off);
-       memcpy(log->buffer + log->w_off, buf, len);
-
-       if (count != len)
-               memcpy(log->buffer, buf + len, count - len);
-
-       log->w_off = logger_offset(log, log->w_off + count);
-
-}
-
-/*
- * do_write_log_user - writes 'len' bytes from the user-space buffer 'buf' to
- * the log 'log'
- *
- * The caller needs to hold log->mutex.
- *
- * Returns 'count' on success, negative error code on failure.
- */
-static ssize_t do_write_log_from_user(struct logger_log *log,
-                                     const void __user *buf, size_t count)
-{
-       size_t len;
-
-       len = min(count, log->size - log->w_off);
-       if (len && copy_from_user(log->buffer + log->w_off, buf, len))
-               return -EFAULT;
-
-       if (count != len)
-               if (copy_from_user(log->buffer, buf + len, count - len))
-                       /*
-                        * Note that by not updating w_off, this abandons the
-                        * portion of the new entry that *was* successfully
-                        * copied, just above.  This is intentional to avoid
-                        * message corruption from missing fragments.
-                        */
-                       return -EFAULT;
-
-       log->w_off = logger_offset(log, log->w_off + count);
-
-       return count;
-}
-
-/*
- * logger_aio_write - our write method, implementing support for write(),
+ * logger_write_iter - our write method, implementing support for write(),
  * writev(), and aio_write(). Writes are our fast path, and we try to optimize
  * them above all else.
  */
-static ssize_t logger_aio_write(struct kiocb *iocb, const struct iovec *iov,
-                        unsigned long nr_segs, loff_t ppos)
+static ssize_t logger_write_iter(struct kiocb *iocb, struct iov_iter *from)
 {
        struct logger_log *log = file_get_log(iocb->ki_filp);
-       size_t orig;
        struct logger_entry header;
        struct timespec now;
-       ssize_t ret = 0;
+       size_t len, count;
+
+       count = min_t(size_t, iocb->ki_nbytes, LOGGER_ENTRY_MAX_PAYLOAD);
 
        now = current_kernel_time();
 
@@ -482,7 +431,7 @@ static ssize_t logger_aio_write(struct kiocb *iocb, const struct iovec *iov,
        header.sec = now.tv_sec;
        header.nsec = now.tv_nsec;
        header.euid = current_euid();
-       header.len = min_t(size_t, iocb->ki_nbytes, LOGGER_ENTRY_MAX_PAYLOAD);
+       header.len = count;
        header.hdr_size = sizeof(struct logger_entry);
 
        /* null writes succeed, return zero */
@@ -491,8 +440,6 @@ static ssize_t logger_aio_write(struct kiocb *iocb, const struct iovec *iov,
 
        mutex_lock(&log->mutex);
 
-       orig = log->w_off;
-
        /*
         * Fix up any readers, pulling them forward to the first readable
         * entry after (what will be) the new write offset. We do this now
@@ -501,33 +448,35 @@ static ssize_t logger_aio_write(struct kiocb *iocb, const struct iovec *iov,
         */
        fix_up_readers(log, sizeof(struct logger_entry) + header.len);
 
-       do_write_log(log, &header, sizeof(struct logger_entry));
-
-       while (nr_segs-- > 0) {
-               size_t len;
-               ssize_t nr;
+       len = min(sizeof(header), log->size - log->w_off);
+       memcpy(log->buffer + log->w_off, &header, len);
+       memcpy(log->buffer, (char *)&header + len, sizeof(header) - len);
 
-               /* figure out how much of this vector we can keep */
-               len = min_t(size_t, iov->iov_len, header.len - ret);
+       len = min(count, log->size - log->w_off);
 
-               /* write out this segment's payload */
-               nr = do_write_log_from_user(log, iov->iov_base, len);
-               if (unlikely(nr < 0)) {
-                       log->w_off = orig;
-                       mutex_unlock(&log->mutex);
-                       return nr;
-               }
+       if (copy_from_iter(log->buffer + log->w_off, len, from) != len) {
+               /*
+                * Note that by not updating w_off, this abandons the
+                * portion of the new entry that *was* successfully
+                * copied, just above.  This is intentional to avoid
+                * message corruption from missing fragments.
+                */
+               mutex_unlock(&log->mutex);
+               return -EFAULT;
+       }
 
-               iov++;
-               ret += nr;
+       if (copy_from_iter(log->buffer, count - len, from) != count - len) {
+               mutex_unlock(&log->mutex);
+               return -EFAULT;
        }
 
+       log->w_off = logger_offset(log, log->w_off + count);
        mutex_unlock(&log->mutex);
 
        /* wake up any blocked readers */
        wake_up_interruptible(&log->wq);
 
-       return ret;
+       return len;
 }
 
 static struct logger_log *get_log_from_minor(int minor)
@@ -736,7 +685,7 @@ static long logger_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 static const struct file_operations logger_fops = {
        .owner = THIS_MODULE,
        .read = logger_read,
-       .aio_write = logger_aio_write,
+       .write_iter = logger_write_iter,
        .poll = logger_poll,
        .unlocked_ioctl = logger_ioctl,
        .compat_ioctl = logger_ioctl,
index b188478277598e8c9079e3731f3168c14f04de97..9cb222e2996f5e5391f7832ce9649bff580fd0ce 100644 (file)
@@ -531,6 +531,7 @@ static struct drm_driver imx_drm_driver = {
        .unload                 = imx_drm_driver_unload,
        .lastclose              = imx_drm_driver_lastclose,
        .preclose               = imx_drm_driver_preclose,
+       .set_busid              = drm_platform_set_busid,
        .gem_free_object        = drm_gem_cma_free_object,
        .gem_vm_ops             = &drm_gem_cma_vm_ops,
        .dumb_create            = drm_gem_cma_dumb_create,
index 86f1a91e896fe4bd35e80adec70bf4ba66faa6af..14c9c8d18d02a5dfb933d844768c07f8c3cb320a 100644 (file)
@@ -3215,7 +3215,6 @@ kiblnd_connd (void *arg)
 
                schedule_timeout(timeout);
 
-               set_current_state(TASK_RUNNING);
                remove_wait_queue(&kiblnd_data.kib_connd_waitq, &wait);
                spin_lock_irqsave(&kiblnd_data.kib_connd_lock, flags);
        }
@@ -3432,7 +3431,6 @@ kiblnd_scheduler(void *arg)
                busy_loops = 0;
 
                remove_wait_queue(&sched->ibs_waitq, &wait);
-               set_current_state(TASK_RUNNING);
                spin_lock_irqsave(&sched->ibs_lock, flags);
        }
 
@@ -3507,7 +3505,6 @@ kiblnd_failover_thread(void *arg)
 
                rc = schedule_timeout(long_sleep ? cfs_time_seconds(10) :
                                                   cfs_time_seconds(1));
-               set_current_state(TASK_RUNNING);
                remove_wait_queue(&kiblnd_data.kib_failover_waitq, &wait);
                write_lock_irqsave(glock, flags);
 
index bcfee7c219429a39051e25d1bfcc326afdfd152b..d29f5f134b896019bd95e95103d3f478052c0d09 100644 (file)
@@ -2232,7 +2232,6 @@ ksocknal_connd (void *arg)
                nloops = 0;
                schedule_timeout(timeout);
 
-               set_current_state(TASK_RUNNING);
                remove_wait_queue(&ksocknal_data.ksnd_connd_waitq, &wait);
                spin_lock_bh(connd_lock);
        }
index 1bf9c90b4789237990f1fedf232c6a5b48726368..e73ca3df97340625cdeb8c0f2a9a4ee2d41d1d21 100644 (file)
@@ -131,7 +131,6 @@ int __cfs_fail_timeout_set(__u32 id, __u32 value, int ms, int set)
                       id, ms);
                set_current_state(TASK_UNINTERRUPTIBLE);
                schedule_timeout(cfs_time_seconds(ms) / 1000);
-               set_current_state(TASK_RUNNING);
                CERROR("cfs_fail_timeout id %x awake\n", id);
        }
        return ret;
index 3323eb5e77b07ea1e56367c21ff9497e2143f661..655cf5037b0b9f2d5e2e88f4dc37ee399bf21d95 100644 (file)
@@ -19,8 +19,6 @@ menuconfig STAGING_MEDIA
 if STAGING_MEDIA
 
 # Please keep them in alphabetic order
-source "drivers/staging/media/as102/Kconfig"
-
 source "drivers/staging/media/bcm2048/Kconfig"
 
 source "drivers/staging/media/cxd2099/Kconfig"
index 7db83f373f63010c8618255415146c9a1d9dd03e..6dbe578178cdcdbb4d988809c40c3241a36816a2 100644 (file)
@@ -1,4 +1,3 @@
-obj-$(CONFIG_DVB_AS102)                += as102/
 obj-$(CONFIG_I2C_BCM2048)      += bcm2048/
 obj-$(CONFIG_DVB_CXD2099)      += cxd2099/
 obj-$(CONFIG_LIRC_STAGING)     += lirc/
diff --git a/drivers/staging/media/as102/Kconfig b/drivers/staging/media/as102/Kconfig
deleted file mode 100644 (file)
index 28aba00..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-config DVB_AS102
-       tristate "Abilis AS102 DVB receiver"
-       depends on DVB_CORE && USB && I2C && INPUT
-       select FW_LOADER
-       help
-         Choose Y or M here if you have a device containing an AS102
-
-         To compile this driver as a module, choose M here
diff --git a/drivers/staging/media/as102/Makefile b/drivers/staging/media/as102/Makefile
deleted file mode 100644 (file)
index 8916d8a..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-dvb-as102-objs := as102_drv.o as102_fw.o as10x_cmd.o as10x_cmd_stream.o \
-               as102_fe.o as102_usb_drv.o as10x_cmd_cfg.o
-
-obj-$(CONFIG_DVB_AS102) += dvb-as102.o
-
-ccflags-y += -Idrivers/media/dvb-core
diff --git a/drivers/staging/media/as102/as102_drv.c b/drivers/staging/media/as102/as102_drv.c
deleted file mode 100644 (file)
index 09d64cd..0000000
+++ /dev/null
@@ -1,277 +0,0 @@
-/*
- * Abilis Systems Single DVB-T Receiver
- * Copyright (C) 2008 Pierrick Hascoet <pierrick.hascoet@abilis.com>
- * Copyright (C) 2010 Devin Heitmueller <dheitmueller@kernellabs.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, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/slab.h>
-#include <linux/module.h>
-#include <linux/mm.h>
-#include <linux/kref.h>
-#include <linux/uaccess.h>
-#include <linux/usb.h>
-
-/* header file for usb device driver*/
-#include "as102_drv.h"
-#include "as102_fw.h"
-#include "dvbdev.h"
-
-int as102_debug;
-module_param_named(debug, as102_debug, int, 0644);
-MODULE_PARM_DESC(debug, "Turn on/off debugging (default: off)");
-
-int dual_tuner;
-module_param_named(dual_tuner, dual_tuner, int, 0644);
-MODULE_PARM_DESC(dual_tuner, "Activate Dual-Tuner config (default: off)");
-
-static int fw_upload = 1;
-module_param_named(fw_upload, fw_upload, int, 0644);
-MODULE_PARM_DESC(fw_upload, "Turn on/off default FW upload (default: on)");
-
-static int pid_filtering;
-module_param_named(pid_filtering, pid_filtering, int, 0644);
-MODULE_PARM_DESC(pid_filtering, "Activate HW PID filtering (default: off)");
-
-static int ts_auto_disable;
-module_param_named(ts_auto_disable, ts_auto_disable, int, 0644);
-MODULE_PARM_DESC(ts_auto_disable, "Stream Auto Enable on FW (default: off)");
-
-int elna_enable = 1;
-module_param_named(elna_enable, elna_enable, int, 0644);
-MODULE_PARM_DESC(elna_enable, "Activate eLNA (default: on)");
-
-DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
-
-static void as102_stop_stream(struct as102_dev_t *dev)
-{
-       struct as10x_bus_adapter_t *bus_adap;
-
-       if (dev != NULL)
-               bus_adap = &dev->bus_adap;
-       else
-               return;
-
-       if (bus_adap->ops->stop_stream != NULL)
-               bus_adap->ops->stop_stream(dev);
-
-       if (ts_auto_disable) {
-               if (mutex_lock_interruptible(&dev->bus_adap.lock))
-                       return;
-
-               if (as10x_cmd_stop_streaming(bus_adap) < 0)
-                       dprintk(debug, "as10x_cmd_stop_streaming failed\n");
-
-               mutex_unlock(&dev->bus_adap.lock);
-       }
-}
-
-static int as102_start_stream(struct as102_dev_t *dev)
-{
-       struct as10x_bus_adapter_t *bus_adap;
-       int ret = -EFAULT;
-
-       if (dev != NULL)
-               bus_adap = &dev->bus_adap;
-       else
-               return ret;
-
-       if (bus_adap->ops->start_stream != NULL)
-               ret = bus_adap->ops->start_stream(dev);
-
-       if (ts_auto_disable) {
-               if (mutex_lock_interruptible(&dev->bus_adap.lock))
-                       return -EFAULT;
-
-               ret = as10x_cmd_start_streaming(bus_adap);
-
-               mutex_unlock(&dev->bus_adap.lock);
-       }
-
-       return ret;
-}
-
-static int as10x_pid_filter(struct as102_dev_t *dev,
-                           int index, u16 pid, int onoff) {
-
-       struct as10x_bus_adapter_t *bus_adap = &dev->bus_adap;
-       int ret = -EFAULT;
-
-       if (mutex_lock_interruptible(&dev->bus_adap.lock)) {
-               dprintk(debug, "mutex_lock_interruptible(lock) failed !\n");
-               return -EBUSY;
-       }
-
-       switch (onoff) {
-       case 0:
-               ret = as10x_cmd_del_PID_filter(bus_adap, (uint16_t) pid);
-               dprintk(debug, "DEL_PID_FILTER([%02d] 0x%04x) ret = %d\n",
-                       index, pid, ret);
-               break;
-       case 1:
-       {
-               struct as10x_ts_filter filter;
-
-               filter.type = TS_PID_TYPE_TS;
-               filter.idx = 0xFF;
-               filter.pid = pid;
-
-               ret = as10x_cmd_add_PID_filter(bus_adap, &filter);
-               dprintk(debug,
-                       "ADD_PID_FILTER([%02d -> %02d], 0x%04x) ret = %d\n",
-                       index, filter.idx, filter.pid, ret);
-               break;
-       }
-       }
-
-       mutex_unlock(&dev->bus_adap.lock);
-       return ret;
-}
-
-static int as102_dvb_dmx_start_feed(struct dvb_demux_feed *dvbdmxfeed)
-{
-       int ret = 0;
-       struct dvb_demux *demux = dvbdmxfeed->demux;
-       struct as102_dev_t *as102_dev = demux->priv;
-
-       if (mutex_lock_interruptible(&as102_dev->sem))
-               return -ERESTARTSYS;
-
-       if (pid_filtering)
-               as10x_pid_filter(as102_dev, dvbdmxfeed->index,
-                                dvbdmxfeed->pid, 1);
-
-       if (as102_dev->streaming++ == 0)
-               ret = as102_start_stream(as102_dev);
-
-       mutex_unlock(&as102_dev->sem);
-       return ret;
-}
-
-static int as102_dvb_dmx_stop_feed(struct dvb_demux_feed *dvbdmxfeed)
-{
-       struct dvb_demux *demux = dvbdmxfeed->demux;
-       struct as102_dev_t *as102_dev = demux->priv;
-
-       if (mutex_lock_interruptible(&as102_dev->sem))
-               return -ERESTARTSYS;
-
-       if (--as102_dev->streaming == 0)
-               as102_stop_stream(as102_dev);
-
-       if (pid_filtering)
-               as10x_pid_filter(as102_dev, dvbdmxfeed->index,
-                                dvbdmxfeed->pid, 0);
-
-       mutex_unlock(&as102_dev->sem);
-       return 0;
-}
-
-int as102_dvb_register(struct as102_dev_t *as102_dev)
-{
-       struct device *dev = &as102_dev->bus_adap.usb_dev->dev;
-       int ret;
-
-       ret = dvb_register_adapter(&as102_dev->dvb_adap,
-                          as102_dev->name, THIS_MODULE,
-                          dev, adapter_nr);
-       if (ret < 0) {
-               dev_err(dev, "%s: dvb_register_adapter() failed: %d\n",
-                       __func__, ret);
-               return ret;
-       }
-
-       as102_dev->dvb_dmx.priv = as102_dev;
-       as102_dev->dvb_dmx.filternum = pid_filtering ? 16 : 256;
-       as102_dev->dvb_dmx.feednum = 256;
-       as102_dev->dvb_dmx.start_feed = as102_dvb_dmx_start_feed;
-       as102_dev->dvb_dmx.stop_feed = as102_dvb_dmx_stop_feed;
-
-       as102_dev->dvb_dmx.dmx.capabilities = DMX_TS_FILTERING |
-                                             DMX_SECTION_FILTERING;
-
-       as102_dev->dvb_dmxdev.filternum = as102_dev->dvb_dmx.filternum;
-       as102_dev->dvb_dmxdev.demux = &as102_dev->dvb_dmx.dmx;
-       as102_dev->dvb_dmxdev.capabilities = 0;
-
-       ret = dvb_dmx_init(&as102_dev->dvb_dmx);
-       if (ret < 0) {
-               dev_err(dev, "%s: dvb_dmx_init() failed: %d\n", __func__, ret);
-               goto edmxinit;
-       }
-
-       ret = dvb_dmxdev_init(&as102_dev->dvb_dmxdev, &as102_dev->dvb_adap);
-       if (ret < 0) {
-               dev_err(dev, "%s: dvb_dmxdev_init() failed: %d\n",
-                       __func__, ret);
-               goto edmxdinit;
-       }
-
-       ret = as102_dvb_register_fe(as102_dev, &as102_dev->dvb_fe);
-       if (ret < 0) {
-               dev_err(dev, "%s: as102_dvb_register_frontend() failed: %d",
-                   __func__, ret);
-               goto efereg;
-       }
-
-       /* init bus mutex for token locking */
-       mutex_init(&as102_dev->bus_adap.lock);
-
-       /* init start / stop stream mutex */
-       mutex_init(&as102_dev->sem);
-
-       /*
-        * try to load as102 firmware. If firmware upload failed, we'll be
-        * able to upload it later.
-        */
-       if (fw_upload)
-               try_then_request_module(as102_fw_upload(&as102_dev->bus_adap),
-                               "firmware_class");
-
-       pr_info("Registered device %s", as102_dev->name);
-       return 0;
-
-efereg:
-       dvb_dmxdev_release(&as102_dev->dvb_dmxdev);
-edmxdinit:
-       dvb_dmx_release(&as102_dev->dvb_dmx);
-edmxinit:
-       dvb_unregister_adapter(&as102_dev->dvb_adap);
-       return ret;
-}
-
-void as102_dvb_unregister(struct as102_dev_t *as102_dev)
-{
-       /* unregister as102 frontend */
-       as102_dvb_unregister_fe(&as102_dev->dvb_fe);
-
-       /* unregister demux device */
-       dvb_dmxdev_release(&as102_dev->dvb_dmxdev);
-       dvb_dmx_release(&as102_dev->dvb_dmx);
-
-       /* unregister dvb adapter */
-       dvb_unregister_adapter(&as102_dev->dvb_adap);
-
-       pr_info("Unregistered device %s", as102_dev->name);
-}
-
-module_usb_driver(as102_usb_driver);
-
-/* modinfo details */
-MODULE_DESCRIPTION(DRIVER_FULL_NAME);
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Pierrick Hascoet <pierrick.hascoet@abilis.com>");
diff --git a/drivers/staging/media/as102/as102_drv.h b/drivers/staging/media/as102/as102_drv.h
deleted file mode 100644 (file)
index a06837d..0000000
+++ /dev/null
@@ -1,99 +0,0 @@
-/*
- * Abilis Systems Single DVB-T Receiver
- * Copyright (C) 2008 Pierrick Hascoet <pierrick.hascoet@abilis.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, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#include <linux/usb.h>
-#include <dvb_demux.h>
-#include <dvb_frontend.h>
-#include <dmxdev.h>
-#include "as10x_cmd.h"
-#include "as102_usb_drv.h"
-
-#define DRIVER_FULL_NAME "Abilis Systems as10x usb driver"
-#define DRIVER_NAME "as10x_usb"
-
-extern int as102_debug;
-#define debug  as102_debug
-extern struct usb_driver as102_usb_driver;
-extern int elna_enable;
-
-#define dprintk(debug, args...) \
-       do { if (debug) {       \
-               pr_debug("%s: ", __func__);     \
-               printk(args);   \
-       } } while (0)
-
-#define AS102_DEVICE_MAJOR     192
-
-#define AS102_USB_BUF_SIZE     512
-#define MAX_STREAM_URB         32
-
-struct as10x_bus_adapter_t {
-       struct usb_device *usb_dev;
-       /* bus token lock */
-       struct mutex lock;
-       /* low level interface for bus adapter */
-       union as10x_bus_token_t {
-               /* usb token */
-               struct as10x_usb_token_cmd_t usb;
-       } token;
-
-       /* token cmd xfer id */
-       uint16_t cmd_xid;
-
-       /* as10x command and response for dvb interface*/
-       struct as10x_cmd_t *cmd, *rsp;
-
-       /* bus adapter private ops callback */
-       struct as102_priv_ops_t *ops;
-};
-
-struct as102_dev_t {
-       const char *name;
-       struct as10x_bus_adapter_t bus_adap;
-       struct list_head device_entry;
-       struct kref kref;
-       uint8_t elna_cfg;
-
-       struct dvb_adapter dvb_adap;
-       struct dvb_frontend dvb_fe;
-       struct dvb_demux dvb_dmx;
-       struct dmxdev dvb_dmxdev;
-
-       /* demodulator stats */
-       struct as10x_demod_stats demod_stats;
-       /* signal strength */
-       uint16_t signal_strength;
-       /* bit error rate */
-       uint32_t ber;
-
-       /* timer handle to trig ts stream download */
-       struct timer_list timer_handle;
-
-       struct mutex sem;
-       dma_addr_t dma_addr;
-       void *stream;
-       int streaming;
-       struct urb *stream_urb[MAX_STREAM_URB];
-};
-
-int as102_dvb_register(struct as102_dev_t *dev);
-void as102_dvb_unregister(struct as102_dev_t *dev);
-
-int as102_dvb_register_fe(struct as102_dev_t *dev, struct dvb_frontend *fe);
-int as102_dvb_unregister_fe(struct dvb_frontend *dev);
diff --git a/drivers/staging/media/as102/as102_fe.c b/drivers/staging/media/as102/as102_fe.c
deleted file mode 100644 (file)
index b686b76..0000000
+++ /dev/null
@@ -1,571 +0,0 @@
-/*
- * Abilis Systems Single DVB-T Receiver
- * Copyright (C) 2008 Pierrick Hascoet <pierrick.hascoet@abilis.com>
- * Copyright (C) 2010 Devin Heitmueller <dheitmueller@kernellabs.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, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-#include "as102_drv.h"
-#include "as10x_types.h"
-#include "as10x_cmd.h"
-
-static void as10x_fe_copy_tps_parameters(struct dtv_frontend_properties *dst,
-                                        struct as10x_tps *src);
-
-static void as102_fe_copy_tune_parameters(struct as10x_tune_args *dst,
-                                         struct dtv_frontend_properties *src);
-
-static int as102_fe_set_frontend(struct dvb_frontend *fe)
-{
-       struct dtv_frontend_properties *p = &fe->dtv_property_cache;
-       int ret = 0;
-       struct as102_dev_t *dev;
-       struct as10x_tune_args tune_args = { 0 };
-
-       dev = (struct as102_dev_t *) fe->tuner_priv;
-       if (dev == NULL)
-               return -ENODEV;
-
-       if (mutex_lock_interruptible(&dev->bus_adap.lock))
-               return -EBUSY;
-
-       as102_fe_copy_tune_parameters(&tune_args, p);
-
-       /* send abilis command: SET_TUNE */
-       ret =  as10x_cmd_set_tune(&dev->bus_adap, &tune_args);
-       if (ret != 0)
-               dprintk(debug, "as10x_cmd_set_tune failed. (err = %d)\n", ret);
-
-       mutex_unlock(&dev->bus_adap.lock);
-
-       return (ret < 0) ? -EINVAL : 0;
-}
-
-static int as102_fe_get_frontend(struct dvb_frontend *fe)
-{
-       struct dtv_frontend_properties *p = &fe->dtv_property_cache;
-       int ret = 0;
-       struct as102_dev_t *dev;
-       struct as10x_tps tps = { 0 };
-
-       dev = (struct as102_dev_t *) fe->tuner_priv;
-       if (dev == NULL)
-               return -EINVAL;
-
-       if (mutex_lock_interruptible(&dev->bus_adap.lock))
-               return -EBUSY;
-
-       /* send abilis command: GET_TPS */
-       ret = as10x_cmd_get_tps(&dev->bus_adap, &tps);
-
-       if (ret == 0)
-               as10x_fe_copy_tps_parameters(p, &tps);
-
-       mutex_unlock(&dev->bus_adap.lock);
-
-       return (ret < 0) ? -EINVAL : 0;
-}
-
-static int as102_fe_get_tune_settings(struct dvb_frontend *fe,
-                       struct dvb_frontend_tune_settings *settings) {
-
-#if 0
-       dprintk(debug, "step_size    = %d\n", settings->step_size);
-       dprintk(debug, "max_drift    = %d\n", settings->max_drift);
-       dprintk(debug, "min_delay_ms = %d -> %d\n", settings->min_delay_ms,
-               1000);
-#endif
-
-       settings->min_delay_ms = 1000;
-
-       return 0;
-}
-
-
-static int as102_fe_read_status(struct dvb_frontend *fe, fe_status_t *status)
-{
-       int ret = 0;
-       struct as102_dev_t *dev;
-       struct as10x_tune_status tstate = { 0 };
-
-       dev = (struct as102_dev_t *) fe->tuner_priv;
-       if (dev == NULL)
-               return -ENODEV;
-
-       if (mutex_lock_interruptible(&dev->bus_adap.lock))
-               return -EBUSY;
-
-       /* send abilis command: GET_TUNE_STATUS */
-       ret = as10x_cmd_get_tune_status(&dev->bus_adap, &tstate);
-       if (ret < 0) {
-               dprintk(debug, "as10x_cmd_get_tune_status failed (err = %d)\n",
-                       ret);
-               goto out;
-       }
-
-       dev->signal_strength  = tstate.signal_strength;
-       dev->ber  = tstate.BER;
-
-       switch (tstate.tune_state) {
-       case TUNE_STATUS_SIGNAL_DVB_OK:
-               *status = FE_HAS_SIGNAL | FE_HAS_CARRIER;
-               break;
-       case TUNE_STATUS_STREAM_DETECTED:
-               *status = FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_SYNC;
-               break;
-       case TUNE_STATUS_STREAM_TUNED:
-               *status = FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_SYNC |
-                       FE_HAS_LOCK;
-               break;
-       default:
-               *status = TUNE_STATUS_NOT_TUNED;
-       }
-
-       dprintk(debug, "tuner status: 0x%02x, strength %d, per: %d, ber: %d\n",
-                       tstate.tune_state, tstate.signal_strength,
-                       tstate.PER, tstate.BER);
-
-       if (*status & FE_HAS_LOCK) {
-               if (as10x_cmd_get_demod_stats(&dev->bus_adap,
-                       (struct as10x_demod_stats *) &dev->demod_stats) < 0) {
-                       memset(&dev->demod_stats, 0, sizeof(dev->demod_stats));
-                       dprintk(debug,
-                               "as10x_cmd_get_demod_stats failed (probably not tuned)\n");
-               } else {
-                       dprintk(debug,
-                               "demod status: fc: 0x%08x, bad fc: 0x%08x, "
-                               "bytes corrected: 0x%08x , MER: 0x%04x\n",
-                               dev->demod_stats.frame_count,
-                               dev->demod_stats.bad_frame_count,
-                               dev->demod_stats.bytes_fixed_by_rs,
-                               dev->demod_stats.mer);
-               }
-       } else {
-               memset(&dev->demod_stats, 0, sizeof(dev->demod_stats));
-       }
-
-out:
-       mutex_unlock(&dev->bus_adap.lock);
-       return ret;
-}
-
-/*
- * Note:
- * - in AS102 SNR=MER
- *   - the SNR will be returned in linear terms, i.e. not in dB
- *   - the accuracy equals Â±2dB for a SNR range from 4dB to 30dB
- *   - the accuracy is >2dB for SNR values outside this range
- */
-static int as102_fe_read_snr(struct dvb_frontend *fe, u16 *snr)
-{
-       struct as102_dev_t *dev;
-
-       dev = (struct as102_dev_t *) fe->tuner_priv;
-       if (dev == NULL)
-               return -ENODEV;
-
-       *snr = dev->demod_stats.mer;
-
-       return 0;
-}
-
-static int as102_fe_read_ber(struct dvb_frontend *fe, u32 *ber)
-{
-       struct as102_dev_t *dev;
-
-       dev = (struct as102_dev_t *) fe->tuner_priv;
-       if (dev == NULL)
-               return -ENODEV;
-
-       *ber = dev->ber;
-
-       return 0;
-}
-
-static int as102_fe_read_signal_strength(struct dvb_frontend *fe,
-                                        u16 *strength)
-{
-       struct as102_dev_t *dev;
-
-       dev = (struct as102_dev_t *) fe->tuner_priv;
-       if (dev == NULL)
-               return -ENODEV;
-
-       *strength = (((0xffff * 400) * dev->signal_strength + 41000) * 2);
-
-       return 0;
-}
-
-static int as102_fe_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
-{
-       struct as102_dev_t *dev;
-
-       dev = (struct as102_dev_t *) fe->tuner_priv;
-       if (dev == NULL)
-               return -ENODEV;
-
-       if (dev->demod_stats.has_started)
-               *ucblocks = dev->demod_stats.bad_frame_count;
-       else
-               *ucblocks = 0;
-
-       return 0;
-}
-
-static int as102_fe_ts_bus_ctrl(struct dvb_frontend *fe, int acquire)
-{
-       struct as102_dev_t *dev;
-       int ret;
-
-       dev = (struct as102_dev_t *) fe->tuner_priv;
-       if (dev == NULL)
-               return -ENODEV;
-
-       if (mutex_lock_interruptible(&dev->bus_adap.lock))
-               return -EBUSY;
-
-       if (acquire) {
-               if (elna_enable)
-                       as10x_cmd_set_context(&dev->bus_adap,
-                                             CONTEXT_LNA, dev->elna_cfg);
-
-               ret = as10x_cmd_turn_on(&dev->bus_adap);
-       } else {
-               ret = as10x_cmd_turn_off(&dev->bus_adap);
-       }
-
-       mutex_unlock(&dev->bus_adap.lock);
-
-       return ret;
-}
-
-static struct dvb_frontend_ops as102_fe_ops = {
-       .delsys = { SYS_DVBT },
-       .info = {
-               .name                   = "Unknown AS102 device",
-               .frequency_min          = 174000000,
-               .frequency_max          = 862000000,
-               .frequency_stepsize     = 166667,
-               .caps = FE_CAN_INVERSION_AUTO
-                       | FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4
-                       | FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO
-                       | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QPSK
-                       | FE_CAN_QAM_AUTO
-                       | FE_CAN_TRANSMISSION_MODE_AUTO
-                       | FE_CAN_GUARD_INTERVAL_AUTO
-                       | FE_CAN_HIERARCHY_AUTO
-                       | FE_CAN_RECOVER
-                       | FE_CAN_MUTE_TS
-       },
-
-       .set_frontend           = as102_fe_set_frontend,
-       .get_frontend           = as102_fe_get_frontend,
-       .get_tune_settings      = as102_fe_get_tune_settings,
-
-       .read_status            = as102_fe_read_status,
-       .read_snr               = as102_fe_read_snr,
-       .read_ber               = as102_fe_read_ber,
-       .read_signal_strength   = as102_fe_read_signal_strength,
-       .read_ucblocks          = as102_fe_read_ucblocks,
-       .ts_bus_ctrl            = as102_fe_ts_bus_ctrl,
-};
-
-int as102_dvb_unregister_fe(struct dvb_frontend *fe)
-{
-       /* unregister frontend */
-       dvb_unregister_frontend(fe);
-
-       /* detach frontend */
-       dvb_frontend_detach(fe);
-
-       return 0;
-}
-
-int as102_dvb_register_fe(struct as102_dev_t *as102_dev,
-                         struct dvb_frontend *dvb_fe)
-{
-       int errno;
-       struct dvb_adapter *dvb_adap;
-
-       if (as102_dev == NULL)
-               return -EINVAL;
-
-       /* extract dvb_adapter */
-       dvb_adap = &as102_dev->dvb_adap;
-
-       /* init frontend callback ops */
-       memcpy(&dvb_fe->ops, &as102_fe_ops, sizeof(struct dvb_frontend_ops));
-       strncpy(dvb_fe->ops.info.name, as102_dev->name,
-               sizeof(dvb_fe->ops.info.name));
-
-       /* register dvb frontend */
-       errno = dvb_register_frontend(dvb_adap, dvb_fe);
-       if (errno == 0)
-               dvb_fe->tuner_priv = as102_dev;
-
-       return errno;
-}
-
-static void as10x_fe_copy_tps_parameters(struct dtv_frontend_properties *fe_tps,
-                                        struct as10x_tps *as10x_tps)
-{
-
-       /* extract constellation */
-       switch (as10x_tps->modulation) {
-       case CONST_QPSK:
-               fe_tps->modulation = QPSK;
-               break;
-       case CONST_QAM16:
-               fe_tps->modulation = QAM_16;
-               break;
-       case CONST_QAM64:
-               fe_tps->modulation = QAM_64;
-               break;
-       }
-
-       /* extract hierarchy */
-       switch (as10x_tps->hierarchy) {
-       case HIER_NONE:
-               fe_tps->hierarchy = HIERARCHY_NONE;
-               break;
-       case HIER_ALPHA_1:
-               fe_tps->hierarchy = HIERARCHY_1;
-               break;
-       case HIER_ALPHA_2:
-               fe_tps->hierarchy = HIERARCHY_2;
-               break;
-       case HIER_ALPHA_4:
-               fe_tps->hierarchy = HIERARCHY_4;
-               break;
-       }
-
-       /* extract code rate HP */
-       switch (as10x_tps->code_rate_HP) {
-       case CODE_RATE_1_2:
-               fe_tps->code_rate_HP = FEC_1_2;
-               break;
-       case CODE_RATE_2_3:
-               fe_tps->code_rate_HP = FEC_2_3;
-               break;
-       case CODE_RATE_3_4:
-               fe_tps->code_rate_HP = FEC_3_4;
-               break;
-       case CODE_RATE_5_6:
-               fe_tps->code_rate_HP = FEC_5_6;
-               break;
-       case CODE_RATE_7_8:
-               fe_tps->code_rate_HP = FEC_7_8;
-               break;
-       }
-
-       /* extract code rate LP */
-       switch (as10x_tps->code_rate_LP) {
-       case CODE_RATE_1_2:
-               fe_tps->code_rate_LP = FEC_1_2;
-               break;
-       case CODE_RATE_2_3:
-               fe_tps->code_rate_LP = FEC_2_3;
-               break;
-       case CODE_RATE_3_4:
-               fe_tps->code_rate_LP = FEC_3_4;
-               break;
-       case CODE_RATE_5_6:
-               fe_tps->code_rate_LP = FEC_5_6;
-               break;
-       case CODE_RATE_7_8:
-               fe_tps->code_rate_LP = FEC_7_8;
-               break;
-       }
-
-       /* extract guard interval */
-       switch (as10x_tps->guard_interval) {
-       case GUARD_INT_1_32:
-               fe_tps->guard_interval = GUARD_INTERVAL_1_32;
-               break;
-       case GUARD_INT_1_16:
-               fe_tps->guard_interval = GUARD_INTERVAL_1_16;
-               break;
-       case GUARD_INT_1_8:
-               fe_tps->guard_interval = GUARD_INTERVAL_1_8;
-               break;
-       case GUARD_INT_1_4:
-               fe_tps->guard_interval = GUARD_INTERVAL_1_4;
-               break;
-       }
-
-       /* extract transmission mode */
-       switch (as10x_tps->transmission_mode) {
-       case TRANS_MODE_2K:
-               fe_tps->transmission_mode = TRANSMISSION_MODE_2K;
-               break;
-       case TRANS_MODE_8K:
-               fe_tps->transmission_mode = TRANSMISSION_MODE_8K;
-               break;
-       }
-}
-
-static uint8_t as102_fe_get_code_rate(fe_code_rate_t arg)
-{
-       uint8_t c;
-
-       switch (arg) {
-       case FEC_1_2:
-               c = CODE_RATE_1_2;
-               break;
-       case FEC_2_3:
-               c = CODE_RATE_2_3;
-               break;
-       case FEC_3_4:
-               c = CODE_RATE_3_4;
-               break;
-       case FEC_5_6:
-               c = CODE_RATE_5_6;
-               break;
-       case FEC_7_8:
-               c = CODE_RATE_7_8;
-               break;
-       default:
-               c = CODE_RATE_UNKNOWN;
-               break;
-       }
-
-       return c;
-}
-
-static void as102_fe_copy_tune_parameters(struct as10x_tune_args *tune_args,
-                         struct dtv_frontend_properties *params)
-{
-
-       /* set frequency */
-       tune_args->freq = params->frequency / 1000;
-
-       /* fix interleaving_mode */
-       tune_args->interleaving_mode = INTLV_NATIVE;
-
-       switch (params->bandwidth_hz) {
-       case 8000000:
-               tune_args->bandwidth = BW_8_MHZ;
-               break;
-       case 7000000:
-               tune_args->bandwidth = BW_7_MHZ;
-               break;
-       case 6000000:
-               tune_args->bandwidth = BW_6_MHZ;
-               break;
-       default:
-               tune_args->bandwidth = BW_8_MHZ;
-       }
-
-       switch (params->guard_interval) {
-       case GUARD_INTERVAL_1_32:
-               tune_args->guard_interval = GUARD_INT_1_32;
-               break;
-       case GUARD_INTERVAL_1_16:
-               tune_args->guard_interval = GUARD_INT_1_16;
-               break;
-       case GUARD_INTERVAL_1_8:
-               tune_args->guard_interval = GUARD_INT_1_8;
-               break;
-       case GUARD_INTERVAL_1_4:
-               tune_args->guard_interval = GUARD_INT_1_4;
-               break;
-       case GUARD_INTERVAL_AUTO:
-       default:
-               tune_args->guard_interval = GUARD_UNKNOWN;
-               break;
-       }
-
-       switch (params->modulation) {
-       case QPSK:
-               tune_args->modulation = CONST_QPSK;
-               break;
-       case QAM_16:
-               tune_args->modulation = CONST_QAM16;
-               break;
-       case QAM_64:
-               tune_args->modulation = CONST_QAM64;
-               break;
-       default:
-               tune_args->modulation = CONST_UNKNOWN;
-               break;
-       }
-
-       switch (params->transmission_mode) {
-       case TRANSMISSION_MODE_2K:
-               tune_args->transmission_mode = TRANS_MODE_2K;
-               break;
-       case TRANSMISSION_MODE_8K:
-               tune_args->transmission_mode = TRANS_MODE_8K;
-               break;
-       default:
-               tune_args->transmission_mode = TRANS_MODE_UNKNOWN;
-       }
-
-       switch (params->hierarchy) {
-       case HIERARCHY_NONE:
-               tune_args->hierarchy = HIER_NONE;
-               break;
-       case HIERARCHY_1:
-               tune_args->hierarchy = HIER_ALPHA_1;
-               break;
-       case HIERARCHY_2:
-               tune_args->hierarchy = HIER_ALPHA_2;
-               break;
-       case HIERARCHY_4:
-               tune_args->hierarchy = HIER_ALPHA_4;
-               break;
-       case HIERARCHY_AUTO:
-               tune_args->hierarchy = HIER_UNKNOWN;
-               break;
-       }
-
-       dprintk(debug, "tuner parameters: freq: %d  bw: 0x%02x  gi: 0x%02x\n",
-                       params->frequency,
-                       tune_args->bandwidth,
-                       tune_args->guard_interval);
-
-       /*
-        * Detect a hierarchy selection
-        * if HP/LP are both set to FEC_NONE, HP will be selected.
-        */
-       if ((tune_args->hierarchy != HIER_NONE) &&
-                      ((params->code_rate_LP == FEC_NONE) ||
-                       (params->code_rate_HP == FEC_NONE))) {
-
-               if (params->code_rate_LP == FEC_NONE) {
-                       tune_args->hier_select = HIER_HIGH_PRIORITY;
-                       tune_args->code_rate =
-                          as102_fe_get_code_rate(params->code_rate_HP);
-               }
-
-               if (params->code_rate_HP == FEC_NONE) {
-                       tune_args->hier_select = HIER_LOW_PRIORITY;
-                       tune_args->code_rate =
-                          as102_fe_get_code_rate(params->code_rate_LP);
-               }
-
-               dprintk(debug,
-                       "\thierarchy: 0x%02x  selected: %s  code_rate_%s: 0x%02x\n",
-                       tune_args->hierarchy,
-                       tune_args->hier_select == HIER_HIGH_PRIORITY ?
-                       "HP" : "LP",
-                       tune_args->hier_select == HIER_HIGH_PRIORITY ?
-                       "HP" : "LP",
-                       tune_args->code_rate);
-       } else {
-               tune_args->code_rate =
-                       as102_fe_get_code_rate(params->code_rate_HP);
-       }
-}
diff --git a/drivers/staging/media/as102/as102_fw.c b/drivers/staging/media/as102/as102_fw.c
deleted file mode 100644 (file)
index f33f752..0000000
+++ /dev/null
@@ -1,232 +0,0 @@
-/*
- * Abilis Systems Single DVB-T Receiver
- * Copyright (C) 2008 Pierrick Hascoet <pierrick.hascoet@abilis.com>
- * Copyright (C) 2010 Devin Heitmueller <dheitmueller@kernellabs.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, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/ctype.h>
-#include <linux/delay.h>
-#include <linux/firmware.h>
-
-#include "as102_drv.h"
-#include "as102_fw.h"
-
-static const char as102_st_fw1[] = "as102_data1_st.hex";
-static const char as102_st_fw2[] = "as102_data2_st.hex";
-static const char as102_dt_fw1[] = "as102_data1_dt.hex";
-static const char as102_dt_fw2[] = "as102_data2_dt.hex";
-
-static unsigned char atohx(unsigned char *dst, char *src)
-{
-       unsigned char value = 0;
-
-       char msb = tolower(*src) - '0';
-       char lsb = tolower(*(src + 1)) - '0';
-
-       if (msb > 9)
-               msb -= 7;
-       if (lsb > 9)
-               lsb -= 7;
-
-       *dst = value = ((msb & 0xF) << 4) | (lsb & 0xF);
-       return value;
-}
-
-/*
- * Parse INTEL HEX firmware file to extract address and data.
- */
-static int parse_hex_line(unsigned char *fw_data, unsigned char *addr,
-                         unsigned char *data, int *dataLength,
-                         unsigned char *addr_has_changed) {
-
-       int count = 0;
-       unsigned char *src, dst;
-
-       if (*fw_data++ != ':') {
-               pr_err("invalid firmware file\n");
-               return -EFAULT;
-       }
-
-       /* locate end of line */
-       for (src = fw_data; *src != '\n'; src += 2) {
-               atohx(&dst, src);
-               /* parse line to split addr / data */
-               switch (count) {
-               case 0:
-                       *dataLength = dst;
-                       break;
-               case 1:
-                       addr[2] = dst;
-                       break;
-               case 2:
-                       addr[3] = dst;
-                       break;
-               case 3:
-                       /* check if data is an address */
-                       if (dst == 0x04)
-                               *addr_has_changed = 1;
-                       else
-                               *addr_has_changed = 0;
-                       break;
-               case  4:
-               case  5:
-                       if (*addr_has_changed)
-                               addr[(count - 4)] = dst;
-                       else
-                               data[(count - 4)] = dst;
-                       break;
-               default:
-                       data[(count - 4)] = dst;
-                       break;
-               }
-               count++;
-       }
-
-       /* return read value + ':' + '\n' */
-       return (count * 2) + 2;
-}
-
-static int as102_firmware_upload(struct as10x_bus_adapter_t *bus_adap,
-                                unsigned char *cmd,
-                                const struct firmware *firmware) {
-
-       struct as10x_fw_pkt_t fw_pkt;
-       int total_read_bytes = 0, errno = 0;
-       unsigned char addr_has_changed = 0;
-
-       for (total_read_bytes = 0; total_read_bytes < firmware->size; ) {
-               int read_bytes = 0, data_len = 0;
-
-               /* parse intel hex line */
-               read_bytes = parse_hex_line(
-                               (u8 *) (firmware->data + total_read_bytes),
-                               fw_pkt.raw.address,
-                               fw_pkt.raw.data,
-                               &data_len,
-                               &addr_has_changed);
-
-               if (read_bytes <= 0)
-                       goto error;
-
-               /* detect the end of file */
-               total_read_bytes += read_bytes;
-               if (total_read_bytes == firmware->size) {
-                       fw_pkt.u.request[0] = 0x00;
-                       fw_pkt.u.request[1] = 0x03;
-
-                       /* send EOF command */
-                       errno = bus_adap->ops->upload_fw_pkt(bus_adap,
-                                                            (uint8_t *)
-                                                            &fw_pkt, 2, 0);
-                       if (errno < 0)
-                               goto error;
-               } else {
-                       if (!addr_has_changed) {
-                               /* prepare command to send */
-                               fw_pkt.u.request[0] = 0x00;
-                               fw_pkt.u.request[1] = 0x01;
-
-                               data_len += sizeof(fw_pkt.u.request);
-                               data_len += sizeof(fw_pkt.raw.address);
-
-                               /* send cmd to device */
-                               errno = bus_adap->ops->upload_fw_pkt(bus_adap,
-                                                                    (uint8_t *)
-                                                                    &fw_pkt,
-                                                                    data_len,
-                                                                    0);
-                               if (errno < 0)
-                                       goto error;
-                       }
-               }
-       }
-error:
-       return (errno == 0) ? total_read_bytes : errno;
-}
-
-int as102_fw_upload(struct as10x_bus_adapter_t *bus_adap)
-{
-       int errno = -EFAULT;
-       const struct firmware *firmware = NULL;
-       unsigned char *cmd_buf = NULL;
-       const char *fw1, *fw2;
-       struct usb_device *dev = bus_adap->usb_dev;
-
-       /* select fw file to upload */
-       if (dual_tuner) {
-               fw1 = as102_dt_fw1;
-               fw2 = as102_dt_fw2;
-       } else {
-               fw1 = as102_st_fw1;
-               fw2 = as102_st_fw2;
-       }
-
-       /* allocate buffer to store firmware upload command and data */
-       cmd_buf = kzalloc(MAX_FW_PKT_SIZE, GFP_KERNEL);
-       if (cmd_buf == NULL) {
-               errno = -ENOMEM;
-               goto error;
-       }
-
-       /* request kernel to locate firmware file: part1 */
-       errno = request_firmware(&firmware, fw1, &dev->dev);
-       if (errno < 0) {
-               pr_err("%s: unable to locate firmware file: %s\n",
-                      DRIVER_NAME, fw1);
-               goto error;
-       }
-
-       /* initiate firmware upload */
-       errno = as102_firmware_upload(bus_adap, cmd_buf, firmware);
-       if (errno < 0) {
-               pr_err("%s: error during firmware upload part1\n",
-                      DRIVER_NAME);
-               goto error;
-       }
-
-       pr_info("%s: firmware: %s loaded with success\n",
-               DRIVER_NAME, fw1);
-       release_firmware(firmware);
-
-       /* wait for boot to complete */
-       mdelay(100);
-
-       /* request kernel to locate firmware file: part2 */
-       errno = request_firmware(&firmware, fw2, &dev->dev);
-       if (errno < 0) {
-               pr_err("%s: unable to locate firmware file: %s\n",
-                      DRIVER_NAME, fw2);
-               goto error;
-       }
-
-       /* initiate firmware upload */
-       errno = as102_firmware_upload(bus_adap, cmd_buf, firmware);
-       if (errno < 0) {
-               pr_err("%s: error during firmware upload part2\n",
-                      DRIVER_NAME);
-               goto error;
-       }
-
-       pr_info("%s: firmware: %s loaded with success\n",
-               DRIVER_NAME, fw2);
-error:
-       kfree(cmd_buf);
-       release_firmware(firmware);
-
-       return errno;
-}
diff --git a/drivers/staging/media/as102/as102_fw.h b/drivers/staging/media/as102/as102_fw.h
deleted file mode 100644 (file)
index 4bfc684..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * Abilis Systems Single DVB-T Receiver
- * Copyright (C) 2008 Pierrick Hascoet <pierrick.hascoet@abilis.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, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-#define MAX_FW_PKT_SIZE        64
-
-extern int dual_tuner;
-
-struct as10x_raw_fw_pkt {
-       unsigned char address[4];
-       unsigned char data[MAX_FW_PKT_SIZE - 6];
-} __packed;
-
-struct as10x_fw_pkt_t {
-       union {
-               unsigned char request[2];
-               unsigned char length[2];
-       } __packed u;
-       struct as10x_raw_fw_pkt raw;
-} __packed;
-
-#ifdef __KERNEL__
-int as102_fw_upload(struct as10x_bus_adapter_t *bus_adap);
-#endif
diff --git a/drivers/staging/media/as102/as102_usb_drv.c b/drivers/staging/media/as102/as102_usb_drv.c
deleted file mode 100644 (file)
index e6f6278..0000000
+++ /dev/null
@@ -1,472 +0,0 @@
-/*
- * Abilis Systems Single DVB-T Receiver
- * Copyright (C) 2008 Pierrick Hascoet <pierrick.hascoet@abilis.com>
- * Copyright (C) 2010 Devin Heitmueller <dheitmueller@kernellabs.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, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/slab.h>
-#include <linux/mm.h>
-#include <linux/usb.h>
-
-#include "as102_drv.h"
-#include "as102_usb_drv.h"
-#include "as102_fw.h"
-
-static void as102_usb_disconnect(struct usb_interface *interface);
-static int as102_usb_probe(struct usb_interface *interface,
-                          const struct usb_device_id *id);
-
-static int as102_usb_start_stream(struct as102_dev_t *dev);
-static void as102_usb_stop_stream(struct as102_dev_t *dev);
-
-static int as102_open(struct inode *inode, struct file *file);
-static int as102_release(struct inode *inode, struct file *file);
-
-static struct usb_device_id as102_usb_id_table[] = {
-       { USB_DEVICE(AS102_USB_DEVICE_VENDOR_ID, AS102_USB_DEVICE_PID_0001) },
-       { USB_DEVICE(PCTV_74E_USB_VID, PCTV_74E_USB_PID) },
-       { USB_DEVICE(ELGATO_EYETV_DTT_USB_VID, ELGATO_EYETV_DTT_USB_PID) },
-       { USB_DEVICE(NBOX_DVBT_DONGLE_USB_VID, NBOX_DVBT_DONGLE_USB_PID) },
-       { USB_DEVICE(SKY_IT_DIGITAL_KEY_USB_VID, SKY_IT_DIGITAL_KEY_USB_PID) },
-       { } /* Terminating entry */
-};
-
-/* Note that this table must always have the same number of entries as the
-   as102_usb_id_table struct */
-static const char * const as102_device_names[] = {
-       AS102_REFERENCE_DESIGN,
-       AS102_PCTV_74E,
-       AS102_ELGATO_EYETV_DTT_NAME,
-       AS102_NBOX_DVBT_DONGLE_NAME,
-       AS102_SKY_IT_DIGITAL_KEY_NAME,
-       NULL /* Terminating entry */
-};
-
-/* eLNA configuration: devices built on the reference design work best
-   with 0xA0, while custom designs seem to require 0xC0 */
-static uint8_t const as102_elna_cfg[] = {
-       0xA0,
-       0xC0,
-       0xC0,
-       0xA0,
-       0xA0,
-       0x00 /* Terminating entry */
-};
-
-struct usb_driver as102_usb_driver = {
-       .name           = DRIVER_FULL_NAME,
-       .probe          = as102_usb_probe,
-       .disconnect     = as102_usb_disconnect,
-       .id_table       = as102_usb_id_table
-};
-
-static const struct file_operations as102_dev_fops = {
-       .owner          = THIS_MODULE,
-       .open           = as102_open,
-       .release        = as102_release,
-};
-
-static struct usb_class_driver as102_usb_class_driver = {
-       .name           = "aton2-%d",
-       .fops           = &as102_dev_fops,
-       .minor_base     = AS102_DEVICE_MAJOR,
-};
-
-static int as102_usb_xfer_cmd(struct as10x_bus_adapter_t *bus_adap,
-                             unsigned char *send_buf, int send_buf_len,
-                             unsigned char *recv_buf, int recv_buf_len)
-{
-       int ret = 0;
-
-       if (send_buf != NULL) {
-               ret = usb_control_msg(bus_adap->usb_dev,
-                                     usb_sndctrlpipe(bus_adap->usb_dev, 0),
-                                     AS102_USB_DEVICE_TX_CTRL_CMD,
-                                     USB_DIR_OUT | USB_TYPE_VENDOR |
-                                     USB_RECIP_DEVICE,
-                                     bus_adap->cmd_xid, /* value */
-                                     0, /* index */
-                                     send_buf, send_buf_len,
-                                     USB_CTRL_SET_TIMEOUT /* 200 */);
-               if (ret < 0) {
-                       dprintk(debug, "usb_control_msg(send) failed, err %i\n",
-                                       ret);
-                       return ret;
-               }
-
-               if (ret != send_buf_len) {
-                       dprintk(debug, "only wrote %d of %d bytes\n",
-                                       ret, send_buf_len);
-                       return -1;
-               }
-       }
-
-       if (recv_buf != NULL) {
-#ifdef TRACE
-               dprintk(debug, "want to read: %d bytes\n", recv_buf_len);
-#endif
-               ret = usb_control_msg(bus_adap->usb_dev,
-                                     usb_rcvctrlpipe(bus_adap->usb_dev, 0),
-                                     AS102_USB_DEVICE_RX_CTRL_CMD,
-                                     USB_DIR_IN | USB_TYPE_VENDOR |
-                                     USB_RECIP_DEVICE,
-                                     bus_adap->cmd_xid, /* value */
-                                     0, /* index */
-                                     recv_buf, recv_buf_len,
-                                     USB_CTRL_GET_TIMEOUT /* 200 */);
-               if (ret < 0) {
-                       dprintk(debug, "usb_control_msg(recv) failed, err %i\n",
-                                       ret);
-                       return ret;
-               }
-#ifdef TRACE
-               dprintk(debug, "read %d bytes\n", recv_buf_len);
-#endif
-       }
-
-       return ret;
-}
-
-static int as102_send_ep1(struct as10x_bus_adapter_t *bus_adap,
-                         unsigned char *send_buf,
-                         int send_buf_len,
-                         int swap32)
-{
-       int ret = 0, actual_len;
-
-       ret = usb_bulk_msg(bus_adap->usb_dev,
-                          usb_sndbulkpipe(bus_adap->usb_dev, 1),
-                          send_buf, send_buf_len, &actual_len, 200);
-       if (ret) {
-               dprintk(debug, "usb_bulk_msg(send) failed, err %i\n", ret);
-               return ret;
-       }
-
-       if (actual_len != send_buf_len) {
-               dprintk(debug, "only wrote %d of %d bytes\n",
-                               actual_len, send_buf_len);
-               return -1;
-       }
-       return ret ? ret : actual_len;
-}
-
-static int as102_read_ep2(struct as10x_bus_adapter_t *bus_adap,
-                  unsigned char *recv_buf, int recv_buf_len)
-{
-       int ret = 0, actual_len;
-
-       if (recv_buf == NULL)
-               return -EINVAL;
-
-       ret = usb_bulk_msg(bus_adap->usb_dev,
-                          usb_rcvbulkpipe(bus_adap->usb_dev, 2),
-                          recv_buf, recv_buf_len, &actual_len, 200);
-       if (ret) {
-               dprintk(debug, "usb_bulk_msg(recv) failed, err %i\n", ret);
-               return ret;
-       }
-
-       if (actual_len != recv_buf_len) {
-               dprintk(debug, "only read %d of %d bytes\n",
-                               actual_len, recv_buf_len);
-               return -1;
-       }
-       return ret ? ret : actual_len;
-}
-
-static struct as102_priv_ops_t as102_priv_ops = {
-       .upload_fw_pkt  = as102_send_ep1,
-       .xfer_cmd       = as102_usb_xfer_cmd,
-       .as102_read_ep2 = as102_read_ep2,
-       .start_stream   = as102_usb_start_stream,
-       .stop_stream    = as102_usb_stop_stream,
-};
-
-static int as102_submit_urb_stream(struct as102_dev_t *dev, struct urb *urb)
-{
-       int err;
-
-       usb_fill_bulk_urb(urb,
-                         dev->bus_adap.usb_dev,
-                         usb_rcvbulkpipe(dev->bus_adap.usb_dev, 0x2),
-                         urb->transfer_buffer,
-                         AS102_USB_BUF_SIZE,
-                         as102_urb_stream_irq,
-                         dev);
-
-       err = usb_submit_urb(urb, GFP_ATOMIC);
-       if (err)
-               dprintk(debug, "%s: usb_submit_urb failed\n", __func__);
-
-       return err;
-}
-
-void as102_urb_stream_irq(struct urb *urb)
-{
-       struct as102_dev_t *as102_dev = urb->context;
-
-       if (urb->actual_length > 0) {
-               dvb_dmx_swfilter(&as102_dev->dvb_dmx,
-                                urb->transfer_buffer,
-                                urb->actual_length);
-       } else {
-               if (urb->actual_length == 0)
-                       memset(urb->transfer_buffer, 0, AS102_USB_BUF_SIZE);
-       }
-
-       /* is not stopped, re-submit urb */
-       if (as102_dev->streaming)
-               as102_submit_urb_stream(as102_dev, urb);
-}
-
-static void as102_free_usb_stream_buffer(struct as102_dev_t *dev)
-{
-       int i;
-
-       for (i = 0; i < MAX_STREAM_URB; i++)
-               usb_free_urb(dev->stream_urb[i]);
-
-       usb_free_coherent(dev->bus_adap.usb_dev,
-                       MAX_STREAM_URB * AS102_USB_BUF_SIZE,
-                       dev->stream,
-                       dev->dma_addr);
-}
-
-static int as102_alloc_usb_stream_buffer(struct as102_dev_t *dev)
-{
-       int i;
-
-       dev->stream = usb_alloc_coherent(dev->bus_adap.usb_dev,
-                                      MAX_STREAM_URB * AS102_USB_BUF_SIZE,
-                                      GFP_KERNEL,
-                                      &dev->dma_addr);
-       if (!dev->stream) {
-               dprintk(debug, "%s: usb_buffer_alloc failed\n", __func__);
-               return -ENOMEM;
-       }
-
-       memset(dev->stream, 0, MAX_STREAM_URB * AS102_USB_BUF_SIZE);
-
-       /* init urb buffers */
-       for (i = 0; i < MAX_STREAM_URB; i++) {
-               struct urb *urb;
-
-               urb = usb_alloc_urb(0, GFP_ATOMIC);
-               if (urb == NULL) {
-                       dprintk(debug, "%s: usb_alloc_urb failed\n", __func__);
-                       as102_free_usb_stream_buffer(dev);
-                       return -ENOMEM;
-               }
-
-               urb->transfer_buffer = dev->stream + (i * AS102_USB_BUF_SIZE);
-               urb->transfer_dma = dev->dma_addr + (i * AS102_USB_BUF_SIZE);
-               urb->transfer_flags = URB_NO_TRANSFER_DMA_MAP;
-               urb->transfer_buffer_length = AS102_USB_BUF_SIZE;
-
-               dev->stream_urb[i] = urb;
-       }
-       return 0;
-}
-
-static void as102_usb_stop_stream(struct as102_dev_t *dev)
-{
-       int i;
-
-       for (i = 0; i < MAX_STREAM_URB; i++)
-               usb_kill_urb(dev->stream_urb[i]);
-}
-
-static int as102_usb_start_stream(struct as102_dev_t *dev)
-{
-       int i, ret = 0;
-
-       for (i = 0; i < MAX_STREAM_URB; i++) {
-               ret = as102_submit_urb_stream(dev, dev->stream_urb[i]);
-               if (ret) {
-                       as102_usb_stop_stream(dev);
-                       return ret;
-               }
-       }
-
-       return 0;
-}
-
-static void as102_usb_release(struct kref *kref)
-{
-       struct as102_dev_t *as102_dev;
-
-       as102_dev = container_of(kref, struct as102_dev_t, kref);
-       if (as102_dev != NULL) {
-               usb_put_dev(as102_dev->bus_adap.usb_dev);
-               kfree(as102_dev);
-       }
-}
-
-static void as102_usb_disconnect(struct usb_interface *intf)
-{
-       struct as102_dev_t *as102_dev;
-
-       /* extract as102_dev_t from usb_device private data */
-       as102_dev = usb_get_intfdata(intf);
-
-       /* unregister dvb layer */
-       as102_dvb_unregister(as102_dev);
-
-       /* free usb buffers */
-       as102_free_usb_stream_buffer(as102_dev);
-
-       usb_set_intfdata(intf, NULL);
-
-       /* usb unregister device */
-       usb_deregister_dev(intf, &as102_usb_class_driver);
-
-       /* decrement usage counter */
-       kref_put(&as102_dev->kref, as102_usb_release);
-
-       pr_info("%s: device has been disconnected\n", DRIVER_NAME);
-}
-
-static int as102_usb_probe(struct usb_interface *intf,
-                          const struct usb_device_id *id)
-{
-       int ret;
-       struct as102_dev_t *as102_dev;
-       int i;
-
-       /* This should never actually happen */
-       if (ARRAY_SIZE(as102_usb_id_table) !=
-           (sizeof(as102_device_names) / sizeof(const char *))) {
-               pr_err("Device names table invalid size");
-               return -EINVAL;
-       }
-
-       as102_dev = kzalloc(sizeof(struct as102_dev_t), GFP_KERNEL);
-       if (as102_dev == NULL)
-               return -ENOMEM;
-
-       /* Assign the user-friendly device name */
-       for (i = 0; i < ARRAY_SIZE(as102_usb_id_table); i++) {
-               if (id == &as102_usb_id_table[i]) {
-                       as102_dev->name = as102_device_names[i];
-                       as102_dev->elna_cfg = as102_elna_cfg[i];
-               }
-       }
-
-       if (as102_dev->name == NULL)
-               as102_dev->name = "Unknown AS102 device";
-
-       /* set private callback functions */
-       as102_dev->bus_adap.ops = &as102_priv_ops;
-
-       /* init cmd token for usb bus */
-       as102_dev->bus_adap.cmd = &as102_dev->bus_adap.token.usb.c;
-       as102_dev->bus_adap.rsp = &as102_dev->bus_adap.token.usb.r;
-
-       /* init kernel device reference */
-       kref_init(&as102_dev->kref);
-
-       /* store as102 device to usb_device private data */
-       usb_set_intfdata(intf, (void *) as102_dev);
-
-       /* store in as102 device the usb_device pointer */
-       as102_dev->bus_adap.usb_dev = usb_get_dev(interface_to_usbdev(intf));
-
-       /* we can register the device now, as it is ready */
-       ret = usb_register_dev(intf, &as102_usb_class_driver);
-       if (ret < 0) {
-               /* something prevented us from registering this driver */
-               dev_err(&intf->dev,
-                       "%s: usb_register_dev() failed (errno = %d)\n",
-                       __func__, ret);
-               goto failed;
-       }
-
-       pr_info("%s: device has been detected\n", DRIVER_NAME);
-
-       /* request buffer allocation for streaming */
-       ret = as102_alloc_usb_stream_buffer(as102_dev);
-       if (ret != 0)
-               goto failed_stream;
-
-       /* register dvb layer */
-       ret = as102_dvb_register(as102_dev);
-       if (ret != 0)
-               goto failed_dvb;
-
-       return ret;
-
-failed_dvb:
-       as102_free_usb_stream_buffer(as102_dev);
-failed_stream:
-       usb_deregister_dev(intf, &as102_usb_class_driver);
-failed:
-       usb_put_dev(as102_dev->bus_adap.usb_dev);
-       usb_set_intfdata(intf, NULL);
-       kfree(as102_dev);
-       return ret;
-}
-
-static int as102_open(struct inode *inode, struct file *file)
-{
-       int ret = 0, minor = 0;
-       struct usb_interface *intf = NULL;
-       struct as102_dev_t *dev = NULL;
-
-       /* read minor from inode */
-       minor = iminor(inode);
-
-       /* fetch device from usb interface */
-       intf = usb_find_interface(&as102_usb_driver, minor);
-       if (intf == NULL) {
-               pr_err("%s: can't find device for minor %d\n",
-                      __func__, minor);
-               ret = -ENODEV;
-               goto exit;
-       }
-
-       /* get our device */
-       dev = usb_get_intfdata(intf);
-       if (dev == NULL) {
-               ret = -EFAULT;
-               goto exit;
-       }
-
-       /* save our device object in the file's private structure */
-       file->private_data = dev;
-
-       /* increment our usage count for the device */
-       kref_get(&dev->kref);
-
-exit:
-       return ret;
-}
-
-static int as102_release(struct inode *inode, struct file *file)
-{
-       struct as102_dev_t *dev = NULL;
-
-       dev = file->private_data;
-       if (dev != NULL) {
-               /* decrement the count on our device */
-               kref_put(&dev->kref, as102_usb_release);
-       }
-
-       return 0;
-}
-
-MODULE_DEVICE_TABLE(usb, as102_usb_id_table);
diff --git a/drivers/staging/media/as102/as102_usb_drv.h b/drivers/staging/media/as102/as102_usb_drv.h
deleted file mode 100644 (file)
index 1ad1ec5..0000000
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * Abilis Systems Single DVB-T Receiver
- * Copyright (C) 2008 Pierrick Hascoet <pierrick.hascoet@abilis.com>
- * Copyright (C) 2010 Devin Heitmueller <dheitmueller@kernellabs.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, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-#ifndef _AS102_USB_DRV_H_
-#define _AS102_USB_DRV_H_
-
-#define AS102_USB_DEVICE_TX_CTRL_CMD   0xF1
-#define AS102_USB_DEVICE_RX_CTRL_CMD   0xF2
-
-/* define these values to match the supported devices */
-
-/* Abilis system: "TITAN" */
-#define AS102_REFERENCE_DESIGN         "Abilis Systems DVB-Titan"
-#define AS102_USB_DEVICE_VENDOR_ID     0x1BA6
-#define AS102_USB_DEVICE_PID_0001      0x0001
-
-/* PCTV Systems: PCTV picoStick (74e) */
-#define AS102_PCTV_74E                 "PCTV Systems picoStick (74e)"
-#define PCTV_74E_USB_VID               0x2013
-#define PCTV_74E_USB_PID               0x0246
-
-/* Elgato: EyeTV DTT Deluxe */
-#define AS102_ELGATO_EYETV_DTT_NAME    "Elgato EyeTV DTT Deluxe"
-#define ELGATO_EYETV_DTT_USB_VID       0x0fd9
-#define ELGATO_EYETV_DTT_USB_PID       0x002c
-
-/* nBox: nBox DVB-T Dongle */
-#define AS102_NBOX_DVBT_DONGLE_NAME    "nBox DVB-T Dongle"
-#define NBOX_DVBT_DONGLE_USB_VID       0x0b89
-#define NBOX_DVBT_DONGLE_USB_PID       0x0007
-
-/* Sky Italia: Digital Key (green led) */
-#define AS102_SKY_IT_DIGITAL_KEY_NAME  "Sky IT Digital Key (green led)"
-#define SKY_IT_DIGITAL_KEY_USB_VID     0x2137
-#define SKY_IT_DIGITAL_KEY_USB_PID     0x0001
-
-void as102_urb_stream_irq(struct urb *urb);
-
-struct as10x_usb_token_cmd_t {
-       /* token cmd */
-       struct as10x_cmd_t c;
-       /* token response */
-       struct as10x_cmd_t r;
-};
-#endif
diff --git a/drivers/staging/media/as102/as10x_cmd.c b/drivers/staging/media/as102/as10x_cmd.c
deleted file mode 100644 (file)
index 9e49f15..0000000
+++ /dev/null
@@ -1,418 +0,0 @@
-/*
- * Abilis Systems Single DVB-T Receiver
- * Copyright (C) 2008 Pierrick Hascoet <pierrick.hascoet@abilis.com>
- * Copyright (C) 2010 Devin Heitmueller <dheitmueller@kernellabs.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, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#include <linux/kernel.h>
-#include "as102_drv.h"
-#include "as10x_types.h"
-#include "as10x_cmd.h"
-
-/**
- * as10x_cmd_turn_on - send turn on command to AS10x
- * @adap:   pointer to AS10x bus adapter
- *
- * Return 0 when no error, < 0 in case of error.
- */
-int as10x_cmd_turn_on(struct as10x_bus_adapter_t *adap)
-{
-       int error = AS10X_CMD_ERROR;
-       struct as10x_cmd_t *pcmd, *prsp;
-
-       pcmd = adap->cmd;
-       prsp = adap->rsp;
-
-       /* prepare command */
-       as10x_cmd_build(pcmd, (++adap->cmd_xid),
-                       sizeof(pcmd->body.turn_on.req));
-
-       /* fill command */
-       pcmd->body.turn_on.req.proc_id = cpu_to_le16(CONTROL_PROC_TURNON);
-
-       /* send command */
-       if (adap->ops->xfer_cmd) {
-               error = adap->ops->xfer_cmd(adap, (uint8_t *) pcmd,
-                                           sizeof(pcmd->body.turn_on.req) +
-                                           HEADER_SIZE,
-                                           (uint8_t *) prsp,
-                                           sizeof(prsp->body.turn_on.rsp) +
-                                           HEADER_SIZE);
-       }
-
-       if (error < 0)
-               goto out;
-
-       /* parse response */
-       error = as10x_rsp_parse(prsp, CONTROL_PROC_TURNON_RSP);
-
-out:
-       return error;
-}
-
-/**
- * as10x_cmd_turn_off - send turn off command to AS10x
- * @adap:   pointer to AS10x bus adapter
- *
- * Return 0 on success or negative value in case of error.
- */
-int as10x_cmd_turn_off(struct as10x_bus_adapter_t *adap)
-{
-       int error = AS10X_CMD_ERROR;
-       struct as10x_cmd_t *pcmd, *prsp;
-
-       pcmd = adap->cmd;
-       prsp = adap->rsp;
-
-       /* prepare command */
-       as10x_cmd_build(pcmd, (++adap->cmd_xid),
-                       sizeof(pcmd->body.turn_off.req));
-
-       /* fill command */
-       pcmd->body.turn_off.req.proc_id = cpu_to_le16(CONTROL_PROC_TURNOFF);
-
-       /* send command */
-       if (adap->ops->xfer_cmd) {
-               error = adap->ops->xfer_cmd(
-                       adap, (uint8_t *) pcmd,
-                       sizeof(pcmd->body.turn_off.req) + HEADER_SIZE,
-                       (uint8_t *) prsp,
-                       sizeof(prsp->body.turn_off.rsp) + HEADER_SIZE);
-       }
-
-       if (error < 0)
-               goto out;
-
-       /* parse response */
-       error = as10x_rsp_parse(prsp, CONTROL_PROC_TURNOFF_RSP);
-
-out:
-       return error;
-}
-
-/**
- * as10x_cmd_set_tune - send set tune command to AS10x
- * @adap:    pointer to AS10x bus adapter
- * @ptune:   tune parameters
- *
- * Return 0 on success or negative value in case of error.
- */
-int as10x_cmd_set_tune(struct as10x_bus_adapter_t *adap,
-                      struct as10x_tune_args *ptune)
-{
-       int error = AS10X_CMD_ERROR;
-       struct as10x_cmd_t *preq, *prsp;
-
-       preq = adap->cmd;
-       prsp = adap->rsp;
-
-       /* prepare command */
-       as10x_cmd_build(preq, (++adap->cmd_xid),
-                       sizeof(preq->body.set_tune.req));
-
-       /* fill command */
-       preq->body.set_tune.req.proc_id = cpu_to_le16(CONTROL_PROC_SETTUNE);
-       preq->body.set_tune.req.args.freq = cpu_to_le32(ptune->freq);
-       preq->body.set_tune.req.args.bandwidth = ptune->bandwidth;
-       preq->body.set_tune.req.args.hier_select = ptune->hier_select;
-       preq->body.set_tune.req.args.modulation = ptune->modulation;
-       preq->body.set_tune.req.args.hierarchy = ptune->hierarchy;
-       preq->body.set_tune.req.args.interleaving_mode  =
-               ptune->interleaving_mode;
-       preq->body.set_tune.req.args.code_rate  = ptune->code_rate;
-       preq->body.set_tune.req.args.guard_interval = ptune->guard_interval;
-       preq->body.set_tune.req.args.transmission_mode  =
-               ptune->transmission_mode;
-
-       /* send command */
-       if (adap->ops->xfer_cmd) {
-               error = adap->ops->xfer_cmd(adap,
-                                           (uint8_t *) preq,
-                                           sizeof(preq->body.set_tune.req)
-                                           + HEADER_SIZE,
-                                           (uint8_t *) prsp,
-                                           sizeof(prsp->body.set_tune.rsp)
-                                           + HEADER_SIZE);
-       }
-
-       if (error < 0)
-               goto out;
-
-       /* parse response */
-       error = as10x_rsp_parse(prsp, CONTROL_PROC_SETTUNE_RSP);
-
-out:
-       return error;
-}
-
-/**
- * as10x_cmd_get_tune_status - send get tune status command to AS10x
- * @adap: pointer to AS10x bus adapter
- * @pstatus: pointer to updated status structure of the current tune
- *
- * Return 0 on success or negative value in case of error.
- */
-int as10x_cmd_get_tune_status(struct as10x_bus_adapter_t *adap,
-                             struct as10x_tune_status *pstatus)
-{
-       int error = AS10X_CMD_ERROR;
-       struct as10x_cmd_t  *preq, *prsp;
-
-       preq = adap->cmd;
-       prsp = adap->rsp;
-
-       /* prepare command */
-       as10x_cmd_build(preq, (++adap->cmd_xid),
-                       sizeof(preq->body.get_tune_status.req));
-
-       /* fill command */
-       preq->body.get_tune_status.req.proc_id =
-               cpu_to_le16(CONTROL_PROC_GETTUNESTAT);
-
-       /* send command */
-       if (adap->ops->xfer_cmd) {
-               error = adap->ops->xfer_cmd(
-                       adap,
-                       (uint8_t *) preq,
-                       sizeof(preq->body.get_tune_status.req) + HEADER_SIZE,
-                       (uint8_t *) prsp,
-                       sizeof(prsp->body.get_tune_status.rsp) + HEADER_SIZE);
-       }
-
-       if (error < 0)
-               goto out;
-
-       /* parse response */
-       error = as10x_rsp_parse(prsp, CONTROL_PROC_GETTUNESTAT_RSP);
-       if (error < 0)
-               goto out;
-
-       /* Response OK -> get response data */
-       pstatus->tune_state = prsp->body.get_tune_status.rsp.sts.tune_state;
-       pstatus->signal_strength  =
-               le16_to_cpu(prsp->body.get_tune_status.rsp.sts.signal_strength);
-       pstatus->PER = le16_to_cpu(prsp->body.get_tune_status.rsp.sts.PER);
-       pstatus->BER = le16_to_cpu(prsp->body.get_tune_status.rsp.sts.BER);
-
-out:
-       return error;
-}
-
-/**
- * as10x_cmd_get_tps - send get TPS command to AS10x
- * @adap:      pointer to AS10x handle
- * @ptps:      pointer to TPS parameters structure
- *
- * Return 0 on success or negative value in case of error.
- */
-int as10x_cmd_get_tps(struct as10x_bus_adapter_t *adap, struct as10x_tps *ptps)
-{
-       int error = AS10X_CMD_ERROR;
-       struct as10x_cmd_t *pcmd, *prsp;
-
-       pcmd = adap->cmd;
-       prsp = adap->rsp;
-
-       /* prepare command */
-       as10x_cmd_build(pcmd, (++adap->cmd_xid),
-                       sizeof(pcmd->body.get_tps.req));
-
-       /* fill command */
-       pcmd->body.get_tune_status.req.proc_id =
-               cpu_to_le16(CONTROL_PROC_GETTPS);
-
-       /* send command */
-       if (adap->ops->xfer_cmd) {
-               error = adap->ops->xfer_cmd(adap,
-                                           (uint8_t *) pcmd,
-                                           sizeof(pcmd->body.get_tps.req) +
-                                           HEADER_SIZE,
-                                           (uint8_t *) prsp,
-                                           sizeof(prsp->body.get_tps.rsp) +
-                                           HEADER_SIZE);
-       }
-
-       if (error < 0)
-               goto out;
-
-       /* parse response */
-       error = as10x_rsp_parse(prsp, CONTROL_PROC_GETTPS_RSP);
-       if (error < 0)
-               goto out;
-
-       /* Response OK -> get response data */
-       ptps->modulation = prsp->body.get_tps.rsp.tps.modulation;
-       ptps->hierarchy = prsp->body.get_tps.rsp.tps.hierarchy;
-       ptps->interleaving_mode = prsp->body.get_tps.rsp.tps.interleaving_mode;
-       ptps->code_rate_HP = prsp->body.get_tps.rsp.tps.code_rate_HP;
-       ptps->code_rate_LP = prsp->body.get_tps.rsp.tps.code_rate_LP;
-       ptps->guard_interval = prsp->body.get_tps.rsp.tps.guard_interval;
-       ptps->transmission_mode  = prsp->body.get_tps.rsp.tps.transmission_mode;
-       ptps->DVBH_mask_HP = prsp->body.get_tps.rsp.tps.DVBH_mask_HP;
-       ptps->DVBH_mask_LP = prsp->body.get_tps.rsp.tps.DVBH_mask_LP;
-       ptps->cell_ID = le16_to_cpu(prsp->body.get_tps.rsp.tps.cell_ID);
-
-out:
-       return error;
-}
-
-/**
- * as10x_cmd_get_demod_stats - send get demod stats command to AS10x
- * @adap:          pointer to AS10x bus adapter
- * @pdemod_stats:  pointer to demod stats parameters structure
- *
- * Return 0 on success or negative value in case of error.
- */
-int as10x_cmd_get_demod_stats(struct as10x_bus_adapter_t *adap,
-                             struct as10x_demod_stats *pdemod_stats)
-{
-       int error = AS10X_CMD_ERROR;
-       struct as10x_cmd_t *pcmd, *prsp;
-
-       pcmd = adap->cmd;
-       prsp = adap->rsp;
-
-       /* prepare command */
-       as10x_cmd_build(pcmd, (++adap->cmd_xid),
-                       sizeof(pcmd->body.get_demod_stats.req));
-
-       /* fill command */
-       pcmd->body.get_demod_stats.req.proc_id =
-               cpu_to_le16(CONTROL_PROC_GET_DEMOD_STATS);
-
-       /* send command */
-       if (adap->ops->xfer_cmd) {
-               error = adap->ops->xfer_cmd(adap,
-                               (uint8_t *) pcmd,
-                               sizeof(pcmd->body.get_demod_stats.req)
-                               + HEADER_SIZE,
-                               (uint8_t *) prsp,
-                               sizeof(prsp->body.get_demod_stats.rsp)
-                               + HEADER_SIZE);
-       }
-
-       if (error < 0)
-               goto out;
-
-       /* parse response */
-       error = as10x_rsp_parse(prsp, CONTROL_PROC_GET_DEMOD_STATS_RSP);
-       if (error < 0)
-               goto out;
-
-       /* Response OK -> get response data */
-       pdemod_stats->frame_count =
-               le32_to_cpu(prsp->body.get_demod_stats.rsp.stats.frame_count);
-       pdemod_stats->bad_frame_count =
-               le32_to_cpu(prsp->body.get_demod_stats.rsp.stats.bad_frame_count);
-       pdemod_stats->bytes_fixed_by_rs =
-               le32_to_cpu(prsp->body.get_demod_stats.rsp.stats.bytes_fixed_by_rs);
-       pdemod_stats->mer =
-               le16_to_cpu(prsp->body.get_demod_stats.rsp.stats.mer);
-       pdemod_stats->has_started =
-               prsp->body.get_demod_stats.rsp.stats.has_started;
-
-out:
-       return error;
-}
-
-/**
- * as10x_cmd_get_impulse_resp - send get impulse response command to AS10x
- * @adap:     pointer to AS10x bus adapter
- * @is_ready: pointer to value indicating when impulse
- *           response data is ready
- *
- * Return 0 on success or negative value in case of error.
- */
-int as10x_cmd_get_impulse_resp(struct as10x_bus_adapter_t *adap,
-                              uint8_t *is_ready)
-{
-       int error = AS10X_CMD_ERROR;
-       struct as10x_cmd_t *pcmd, *prsp;
-
-       pcmd = adap->cmd;
-       prsp = adap->rsp;
-
-       /* prepare command */
-       as10x_cmd_build(pcmd, (++adap->cmd_xid),
-                       sizeof(pcmd->body.get_impulse_rsp.req));
-
-       /* fill command */
-       pcmd->body.get_impulse_rsp.req.proc_id =
-               cpu_to_le16(CONTROL_PROC_GET_IMPULSE_RESP);
-
-       /* send command */
-       if (adap->ops->xfer_cmd) {
-               error = adap->ops->xfer_cmd(adap,
-                                       (uint8_t *) pcmd,
-                                       sizeof(pcmd->body.get_impulse_rsp.req)
-                                       + HEADER_SIZE,
-                                       (uint8_t *) prsp,
-                                       sizeof(prsp->body.get_impulse_rsp.rsp)
-                                       + HEADER_SIZE);
-       }
-
-       if (error < 0)
-               goto out;
-
-       /* parse response */
-       error = as10x_rsp_parse(prsp, CONTROL_PROC_GET_IMPULSE_RESP_RSP);
-       if (error < 0)
-               goto out;
-
-       /* Response OK -> get response data */
-       *is_ready = prsp->body.get_impulse_rsp.rsp.is_ready;
-
-out:
-       return error;
-}
-
-/**
- * as10x_cmd_build - build AS10x command header
- * @pcmd:     pointer to AS10x command buffer
- * @xid:      sequence id of the command
- * @cmd_len:  length of the command
- */
-void as10x_cmd_build(struct as10x_cmd_t *pcmd,
-                    uint16_t xid, uint16_t cmd_len)
-{
-       pcmd->header.req_id = cpu_to_le16(xid);
-       pcmd->header.prog = cpu_to_le16(SERVICE_PROG_ID);
-       pcmd->header.version = cpu_to_le16(SERVICE_PROG_VERSION);
-       pcmd->header.data_len = cpu_to_le16(cmd_len);
-}
-
-/**
- * as10x_rsp_parse - Parse command response
- * @prsp:       pointer to AS10x command buffer
- * @proc_id:    id of the command
- *
- * Return 0 on success or negative value in case of error.
- */
-int as10x_rsp_parse(struct as10x_cmd_t *prsp, uint16_t proc_id)
-{
-       int error;
-
-       /* extract command error code */
-       error = prsp->body.common.rsp.error;
-
-       if ((error == 0) &&
-           (le16_to_cpu(prsp->body.common.rsp.proc_id) == proc_id)) {
-               return 0;
-       }
-
-       return AS10X_CMD_ERROR;
-}
diff --git a/drivers/staging/media/as102/as10x_cmd.h b/drivers/staging/media/as102/as10x_cmd.h
deleted file mode 100644 (file)
index e21ec6c..0000000
+++ /dev/null
@@ -1,529 +0,0 @@
-/*
- * Abilis Systems Single DVB-T Receiver
- * Copyright (C) 2008 Pierrick Hascoet <pierrick.hascoet@abilis.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, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-#ifndef _AS10X_CMD_H_
-#define _AS10X_CMD_H_
-
-#ifdef __KERNEL__
-#include <linux/kernel.h>
-#endif
-
-#include "as10x_types.h"
-
-/*********************************/
-/*       MACRO DEFINITIONS       */
-/*********************************/
-#define AS10X_CMD_ERROR                -1
-
-#define SERVICE_PROG_ID                0x0002
-#define SERVICE_PROG_VERSION   0x0001
-
-#define HIER_NONE              0x00
-#define HIER_LOW_PRIORITY      0x01
-
-#define HEADER_SIZE (sizeof(struct as10x_cmd_header_t))
-
-/* context request types */
-#define GET_CONTEXT_DATA       1
-#define SET_CONTEXT_DATA       2
-
-/* ODSP suspend modes */
-#define CFG_MODE_ODSP_RESUME   0
-#define CFG_MODE_ODSP_SUSPEND  1
-
-/* Dump memory size */
-#define DUMP_BLOCK_SIZE_MAX    0x20
-
-/*********************************/
-/*     TYPE DEFINITION           */
-/*********************************/
-enum control_proc {
-       CONTROL_PROC_TURNON                     = 0x0001,
-       CONTROL_PROC_TURNON_RSP                 = 0x0100,
-       CONTROL_PROC_SET_REGISTER               = 0x0002,
-       CONTROL_PROC_SET_REGISTER_RSP           = 0x0200,
-       CONTROL_PROC_GET_REGISTER               = 0x0003,
-       CONTROL_PROC_GET_REGISTER_RSP           = 0x0300,
-       CONTROL_PROC_SETTUNE                    = 0x000A,
-       CONTROL_PROC_SETTUNE_RSP                = 0x0A00,
-       CONTROL_PROC_GETTUNESTAT                = 0x000B,
-       CONTROL_PROC_GETTUNESTAT_RSP            = 0x0B00,
-       CONTROL_PROC_GETTPS                     = 0x000D,
-       CONTROL_PROC_GETTPS_RSP                 = 0x0D00,
-       CONTROL_PROC_SETFILTER                  = 0x000E,
-       CONTROL_PROC_SETFILTER_RSP              = 0x0E00,
-       CONTROL_PROC_REMOVEFILTER               = 0x000F,
-       CONTROL_PROC_REMOVEFILTER_RSP           = 0x0F00,
-       CONTROL_PROC_GET_IMPULSE_RESP           = 0x0012,
-       CONTROL_PROC_GET_IMPULSE_RESP_RSP       = 0x1200,
-       CONTROL_PROC_START_STREAMING            = 0x0013,
-       CONTROL_PROC_START_STREAMING_RSP        = 0x1300,
-       CONTROL_PROC_STOP_STREAMING             = 0x0014,
-       CONTROL_PROC_STOP_STREAMING_RSP         = 0x1400,
-       CONTROL_PROC_GET_DEMOD_STATS            = 0x0015,
-       CONTROL_PROC_GET_DEMOD_STATS_RSP        = 0x1500,
-       CONTROL_PROC_ELNA_CHANGE_MODE           = 0x0016,
-       CONTROL_PROC_ELNA_CHANGE_MODE_RSP       = 0x1600,
-       CONTROL_PROC_ODSP_CHANGE_MODE           = 0x0017,
-       CONTROL_PROC_ODSP_CHANGE_MODE_RSP       = 0x1700,
-       CONTROL_PROC_AGC_CHANGE_MODE            = 0x0018,
-       CONTROL_PROC_AGC_CHANGE_MODE_RSP        = 0x1800,
-
-       CONTROL_PROC_CONTEXT                    = 0x00FC,
-       CONTROL_PROC_CONTEXT_RSP                = 0xFC00,
-       CONTROL_PROC_DUMP_MEMORY                = 0x00FD,
-       CONTROL_PROC_DUMP_MEMORY_RSP            = 0xFD00,
-       CONTROL_PROC_DUMPLOG_MEMORY             = 0x00FE,
-       CONTROL_PROC_DUMPLOG_MEMORY_RSP         = 0xFE00,
-       CONTROL_PROC_TURNOFF                    = 0x00FF,
-       CONTROL_PROC_TURNOFF_RSP                = 0xFF00
-};
-
-union as10x_turn_on {
-       /* request */
-       struct {
-               /* request identifier */
-               uint16_t proc_id;
-       } __packed req;
-       /* response */
-       struct {
-               /* response identifier */
-               uint16_t proc_id;
-               /* error */
-               uint8_t error;
-       } __packed rsp;
-} __packed;
-
-union as10x_turn_off {
-       /* request */
-       struct {
-               /* request identifier */
-               uint16_t proc_id;
-       } __packed req;
-       /* response */
-       struct {
-               /* response identifier */
-               uint16_t proc_id;
-               /* error */
-               uint8_t err;
-       } __packed rsp;
-} __packed;
-
-union as10x_set_tune {
-       /* request */
-       struct {
-               /* request identifier */
-               uint16_t proc_id;
-               /* tune params */
-               struct as10x_tune_args args;
-       } __packed req;
-       /* response */
-       struct {
-               /* response identifier */
-               uint16_t proc_id;
-               /* response error */
-               uint8_t error;
-       } __packed rsp;
-} __packed;
-
-union as10x_get_tune_status {
-       /* request */
-       struct {
-               /* request identifier */
-               uint16_t proc_id;
-       } __packed req;
-       /* response */
-       struct {
-               /* response identifier */
-               uint16_t proc_id;
-               /* response error */
-               uint8_t error;
-               /* tune status */
-               struct as10x_tune_status sts;
-       } __packed rsp;
-} __packed;
-
-union as10x_get_tps {
-       /* request */
-       struct {
-               /* request identifier */
-               uint16_t proc_id;
-       } __packed req;
-       /* response */
-       struct {
-               /* response identifier */
-               uint16_t proc_id;
-               /* response error */
-               uint8_t error;
-               /* tps details */
-               struct as10x_tps tps;
-       } __packed rsp;
-} __packed;
-
-union as10x_common {
-       /* request */
-       struct {
-               /* request identifier */
-               uint16_t  proc_id;
-       } __packed req;
-       /* response */
-       struct {
-               /* response identifier */
-               uint16_t proc_id;
-               /* response error */
-               uint8_t error;
-       } __packed rsp;
-} __packed;
-
-union as10x_add_pid_filter {
-       /* request */
-       struct {
-               /* request identifier */
-               uint16_t  proc_id;
-               /* PID to filter */
-               uint16_t  pid;
-               /* stream type (MPE, PSI/SI or PES )*/
-               uint8_t stream_type;
-               /* PID index in filter table */
-               uint8_t idx;
-       } __packed req;
-       /* response */
-       struct {
-               /* response identifier */
-               uint16_t proc_id;
-               /* response error */
-               uint8_t error;
-               /* Filter id */
-               uint8_t filter_id;
-       } __packed rsp;
-} __packed;
-
-union as10x_del_pid_filter {
-       /* request */
-       struct {
-               /* request identifier */
-               uint16_t  proc_id;
-               /* PID to remove */
-               uint16_t  pid;
-       } __packed req;
-       /* response */
-       struct {
-               /* response identifier */
-               uint16_t proc_id;
-               /* response error */
-               uint8_t error;
-       } __packed rsp;
-} __packed;
-
-union as10x_start_streaming {
-       /* request */
-       struct {
-               /* request identifier */
-               uint16_t proc_id;
-       } __packed req;
-       /* response */
-       struct {
-               /* response identifier */
-               uint16_t proc_id;
-               /* error */
-               uint8_t error;
-       } __packed rsp;
-} __packed;
-
-union as10x_stop_streaming {
-       /* request */
-       struct {
-               /* request identifier */
-               uint16_t proc_id;
-       } __packed req;
-       /* response */
-       struct {
-               /* response identifier */
-               uint16_t proc_id;
-               /* error */
-               uint8_t error;
-       } __packed rsp;
-} __packed;
-
-union as10x_get_demod_stats {
-       /* request */
-       struct {
-               /* request identifier */
-               uint16_t proc_id;
-       } __packed req;
-       /* response */
-       struct {
-               /* response identifier */
-               uint16_t proc_id;
-               /* error */
-               uint8_t error;
-               /* demod stats */
-               struct as10x_demod_stats stats;
-       } __packed rsp;
-} __packed;
-
-union as10x_get_impulse_resp {
-       /* request */
-       struct {
-               /* request identifier */
-               uint16_t proc_id;
-       } __packed req;
-       /* response */
-       struct {
-               /* response identifier */
-               uint16_t proc_id;
-               /* error */
-               uint8_t error;
-               /* impulse response ready */
-               uint8_t is_ready;
-       } __packed rsp;
-} __packed;
-
-union as10x_fw_context {
-       /* request */
-       struct {
-               /* request identifier */
-               uint16_t proc_id;
-               /* value to write (for set context)*/
-               struct as10x_register_value reg_val;
-               /* context tag */
-               uint16_t tag;
-               /* context request type */
-               uint16_t type;
-       } __packed req;
-       /* response */
-       struct {
-               /* response identifier */
-               uint16_t proc_id;
-               /* value read (for get context) */
-               struct as10x_register_value reg_val;
-               /* context request type */
-               uint16_t type;
-               /* error */
-               uint8_t error;
-       } __packed rsp;
-} __packed;
-
-union as10x_set_register {
-       /* request */
-       struct {
-               /* response identifier */
-               uint16_t proc_id;
-               /* register description */
-               struct as10x_register_addr reg_addr;
-               /* register content */
-               struct as10x_register_value reg_val;
-       } __packed req;
-       /* response */
-       struct {
-               /* response identifier */
-               uint16_t proc_id;
-               /* error */
-               uint8_t error;
-       } __packed rsp;
-} __packed;
-
-union as10x_get_register {
-       /* request */
-       struct {
-               /* response identifier */
-               uint16_t proc_id;
-               /* register description */
-               struct as10x_register_addr reg_addr;
-       } __packed req;
-       /* response */
-       struct {
-               /* response identifier */
-               uint16_t proc_id;
-               /* error */
-               uint8_t error;
-               /* register content */
-               struct as10x_register_value reg_val;
-       } __packed rsp;
-} __packed;
-
-union as10x_cfg_change_mode {
-       /* request */
-       struct {
-               /* request identifier */
-               uint16_t proc_id;
-               /* mode */
-               uint8_t mode;
-       } __packed req;
-       /* response */
-       struct {
-               /* response identifier */
-               uint16_t proc_id;
-               /* error */
-               uint8_t error;
-       } __packed rsp;
-} __packed;
-
-struct as10x_cmd_header_t {
-       uint16_t req_id;
-       uint16_t prog;
-       uint16_t version;
-       uint16_t data_len;
-} __packed;
-
-#define DUMP_BLOCK_SIZE 16
-
-union as10x_dump_memory {
-       /* request */
-       struct {
-               /* request identifier */
-               uint16_t proc_id;
-               /* dump memory type request */
-               uint8_t dump_req;
-               /* register description */
-               struct as10x_register_addr reg_addr;
-               /* nb blocks to read */
-               uint16_t num_blocks;
-       } __packed req;
-       /* response */
-       struct {
-               /* response identifier */
-               uint16_t proc_id;
-               /* error */
-               uint8_t error;
-               /* dump response */
-               uint8_t dump_rsp;
-               /* data */
-               union {
-                       uint8_t  data8[DUMP_BLOCK_SIZE];
-                       uint16_t data16[DUMP_BLOCK_SIZE / sizeof(uint16_t)];
-                       uint32_t data32[DUMP_BLOCK_SIZE / sizeof(uint32_t)];
-               } __packed u;
-       } __packed rsp;
-} __packed;
-
-union as10x_dumplog_memory {
-       struct {
-               /* request identifier */
-               uint16_t proc_id;
-               /* dump memory type request */
-               uint8_t dump_req;
-       } __packed req;
-       struct {
-               /* request identifier */
-               uint16_t proc_id;
-               /* error */
-               uint8_t error;
-               /* dump response */
-               uint8_t dump_rsp;
-               /* dump data */
-               uint8_t data[DUMP_BLOCK_SIZE];
-       } __packed rsp;
-} __packed;
-
-union as10x_raw_data {
-       /* request */
-       struct {
-               uint16_t proc_id;
-               uint8_t data[64 - sizeof(struct as10x_cmd_header_t)
-                            - 2 /* proc_id */];
-       } __packed req;
-       /* response */
-       struct {
-               uint16_t proc_id;
-               uint8_t error;
-               uint8_t data[64 - sizeof(struct as10x_cmd_header_t)
-                            - 2 /* proc_id */ - 1 /* rc */];
-       } __packed rsp;
-} __packed;
-
-struct as10x_cmd_t {
-       struct as10x_cmd_header_t header;
-       union {
-               union as10x_turn_on             turn_on;
-               union as10x_turn_off            turn_off;
-               union as10x_set_tune            set_tune;
-               union as10x_get_tune_status     get_tune_status;
-               union as10x_get_tps             get_tps;
-               union as10x_common              common;
-               union as10x_add_pid_filter      add_pid_filter;
-               union as10x_del_pid_filter      del_pid_filter;
-               union as10x_start_streaming     start_streaming;
-               union as10x_stop_streaming      stop_streaming;
-               union as10x_get_demod_stats     get_demod_stats;
-               union as10x_get_impulse_resp    get_impulse_rsp;
-               union as10x_fw_context          context;
-               union as10x_set_register        set_register;
-               union as10x_get_register        get_register;
-               union as10x_cfg_change_mode     cfg_change_mode;
-               union as10x_dump_memory         dump_memory;
-               union as10x_dumplog_memory      dumplog_memory;
-               union as10x_raw_data            raw_data;
-       } __packed body;
-} __packed;
-
-struct as10x_token_cmd_t {
-       /* token cmd */
-       struct as10x_cmd_t c;
-       /* token response */
-       struct as10x_cmd_t r;
-} __packed;
-
-
-/**************************/
-/* FUNCTION DECLARATION   */
-/**************************/
-
-void as10x_cmd_build(struct as10x_cmd_t *pcmd, uint16_t proc_id,
-                     uint16_t cmd_len);
-int as10x_rsp_parse(struct as10x_cmd_t *r, uint16_t proc_id);
-
-/* as10x cmd */
-int as10x_cmd_turn_on(struct as10x_bus_adapter_t *adap);
-int as10x_cmd_turn_off(struct as10x_bus_adapter_t *adap);
-
-int as10x_cmd_set_tune(struct as10x_bus_adapter_t *adap,
-                      struct as10x_tune_args *ptune);
-
-int as10x_cmd_get_tune_status(struct as10x_bus_adapter_t *adap,
-                             struct as10x_tune_status *pstatus);
-
-int as10x_cmd_get_tps(struct as10x_bus_adapter_t *adap,
-                     struct as10x_tps *ptps);
-
-int as10x_cmd_get_demod_stats(struct as10x_bus_adapter_t  *adap,
-                             struct as10x_demod_stats *pdemod_stats);
-
-int as10x_cmd_get_impulse_resp(struct as10x_bus_adapter_t *adap,
-                              uint8_t *is_ready);
-
-/* as10x cmd stream */
-int as10x_cmd_add_PID_filter(struct as10x_bus_adapter_t *adap,
-                            struct as10x_ts_filter *filter);
-int as10x_cmd_del_PID_filter(struct as10x_bus_adapter_t *adap,
-                            uint16_t pid_value);
-
-int as10x_cmd_start_streaming(struct as10x_bus_adapter_t *adap);
-int as10x_cmd_stop_streaming(struct as10x_bus_adapter_t *adap);
-
-/* as10x cmd cfg */
-int as10x_cmd_set_context(struct as10x_bus_adapter_t *adap,
-                         uint16_t tag,
-                         uint32_t value);
-int as10x_cmd_get_context(struct as10x_bus_adapter_t *adap,
-                         uint16_t tag,
-                         uint32_t *pvalue);
-
-int as10x_cmd_eLNA_change_mode(struct as10x_bus_adapter_t *adap, uint8_t mode);
-int as10x_context_rsp_parse(struct as10x_cmd_t *prsp, uint16_t proc_id);
-#endif
diff --git a/drivers/staging/media/as102/as10x_cmd_cfg.c b/drivers/staging/media/as102/as10x_cmd_cfg.c
deleted file mode 100644 (file)
index b1e300d..0000000
+++ /dev/null
@@ -1,206 +0,0 @@
-/*
- * Abilis Systems Single DVB-T Receiver
- * Copyright (C) 2008 Pierrick Hascoet <pierrick.hascoet@abilis.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, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#include <linux/kernel.h>
-#include "as102_drv.h"
-#include "as10x_types.h"
-#include "as10x_cmd.h"
-
-/***************************/
-/* FUNCTION DEFINITION     */
-/***************************/
-
-/**
- * as10x_cmd_get_context - Send get context command to AS10x
- * @adap:      pointer to AS10x bus adapter
- * @tag:       context tag
- * @pvalue:    pointer where to store context value read
- *
- * Return 0 on success or negative value in case of error.
- */
-int as10x_cmd_get_context(struct as10x_bus_adapter_t *adap, uint16_t tag,
-                         uint32_t *pvalue)
-{
-       int  error;
-       struct as10x_cmd_t *pcmd, *prsp;
-
-       pcmd = adap->cmd;
-       prsp = adap->rsp;
-
-       /* prepare command */
-       as10x_cmd_build(pcmd, (++adap->cmd_xid),
-                       sizeof(pcmd->body.context.req));
-
-       /* fill command */
-       pcmd->body.context.req.proc_id = cpu_to_le16(CONTROL_PROC_CONTEXT);
-       pcmd->body.context.req.tag = cpu_to_le16(tag);
-       pcmd->body.context.req.type = cpu_to_le16(GET_CONTEXT_DATA);
-
-       /* send command */
-       if (adap->ops->xfer_cmd) {
-               error  = adap->ops->xfer_cmd(adap,
-                                            (uint8_t *) pcmd,
-                                            sizeof(pcmd->body.context.req)
-                                            + HEADER_SIZE,
-                                            (uint8_t *) prsp,
-                                            sizeof(prsp->body.context.rsp)
-                                            + HEADER_SIZE);
-       } else {
-               error = AS10X_CMD_ERROR;
-       }
-
-       if (error < 0)
-               goto out;
-
-       /* parse response: context command do not follow the common response */
-       /* structure -> specific handling response parse required            */
-       error = as10x_context_rsp_parse(prsp, CONTROL_PROC_CONTEXT_RSP);
-
-       if (error == 0) {
-               /* Response OK -> get response data */
-               *pvalue = le32_to_cpu(prsp->body.context.rsp.reg_val.u.value32);
-               /* value returned is always a 32-bit value */
-       }
-
-out:
-       return error;
-}
-
-/**
- * as10x_cmd_set_context - send set context command to AS10x
- * @adap:      pointer to AS10x bus adapter
- * @tag:       context tag
- * @value:     value to set in context
- *
- * Return 0 on success or negative value in case of error.
- */
-int as10x_cmd_set_context(struct as10x_bus_adapter_t *adap, uint16_t tag,
-                         uint32_t value)
-{
-       int error;
-       struct as10x_cmd_t *pcmd, *prsp;
-
-       pcmd = adap->cmd;
-       prsp = adap->rsp;
-
-       /* prepare command */
-       as10x_cmd_build(pcmd, (++adap->cmd_xid),
-                       sizeof(pcmd->body.context.req));
-
-       /* fill command */
-       pcmd->body.context.req.proc_id = cpu_to_le16(CONTROL_PROC_CONTEXT);
-       /* pcmd->body.context.req.reg_val.mode initialization is not required */
-       pcmd->body.context.req.reg_val.u.value32 = cpu_to_le32(value);
-       pcmd->body.context.req.tag = cpu_to_le16(tag);
-       pcmd->body.context.req.type = cpu_to_le16(SET_CONTEXT_DATA);
-
-       /* send command */
-       if (adap->ops->xfer_cmd) {
-               error  = adap->ops->xfer_cmd(adap,
-                                            (uint8_t *) pcmd,
-                                            sizeof(pcmd->body.context.req)
-                                            + HEADER_SIZE,
-                                            (uint8_t *) prsp,
-                                            sizeof(prsp->body.context.rsp)
-                                            + HEADER_SIZE);
-       } else {
-               error = AS10X_CMD_ERROR;
-       }
-
-       if (error < 0)
-               goto out;
-
-       /* parse response: context command do not follow the common response */
-       /* structure -> specific handling response parse required            */
-       error = as10x_context_rsp_parse(prsp, CONTROL_PROC_CONTEXT_RSP);
-
-out:
-       return error;
-}
-
-/**
- * as10x_cmd_eLNA_change_mode - send eLNA change mode command to AS10x
- * @adap:      pointer to AS10x bus adapter
- * @mode:      mode selected:
- *             - ON    : 0x0 => eLNA always ON
- *             - OFF   : 0x1 => eLNA always OFF
- *             - AUTO  : 0x2 => eLNA follow hysteresis parameters
- *                              to be ON or OFF
- *
- * Return 0 on success or negative value in case of error.
- */
-int as10x_cmd_eLNA_change_mode(struct as10x_bus_adapter_t *adap, uint8_t mode)
-{
-       int error;
-       struct as10x_cmd_t *pcmd, *prsp;
-
-       pcmd = adap->cmd;
-       prsp = adap->rsp;
-
-       /* prepare command */
-       as10x_cmd_build(pcmd, (++adap->cmd_xid),
-                       sizeof(pcmd->body.cfg_change_mode.req));
-
-       /* fill command */
-       pcmd->body.cfg_change_mode.req.proc_id =
-               cpu_to_le16(CONTROL_PROC_ELNA_CHANGE_MODE);
-       pcmd->body.cfg_change_mode.req.mode = mode;
-
-       /* send command */
-       if (adap->ops->xfer_cmd) {
-               error  = adap->ops->xfer_cmd(adap, (uint8_t *) pcmd,
-                               sizeof(pcmd->body.cfg_change_mode.req)
-                               + HEADER_SIZE, (uint8_t *) prsp,
-                               sizeof(prsp->body.cfg_change_mode.rsp)
-                               + HEADER_SIZE);
-       } else {
-               error = AS10X_CMD_ERROR;
-       }
-
-       if (error < 0)
-               goto out;
-
-       /* parse response */
-       error = as10x_rsp_parse(prsp, CONTROL_PROC_ELNA_CHANGE_MODE_RSP);
-
-out:
-       return error;
-}
-
-/**
- * as10x_context_rsp_parse - Parse context command response
- * @prsp:       pointer to AS10x command response buffer
- * @proc_id:    id of the command
- *
- * Since the contex command response does not follow the common
- * response, a specific parse function is required.
- * Return 0 on success or negative value in case of error.
- */
-int as10x_context_rsp_parse(struct as10x_cmd_t *prsp, uint16_t proc_id)
-{
-       int err;
-
-       err = prsp->body.context.rsp.error;
-
-       if ((err == 0) &&
-           (le16_to_cpu(prsp->body.context.rsp.proc_id) == proc_id)) {
-               return 0;
-       }
-       return AS10X_CMD_ERROR;
-}
diff --git a/drivers/staging/media/as102/as10x_cmd_stream.c b/drivers/staging/media/as102/as10x_cmd_stream.c
deleted file mode 100644 (file)
index 1088ca1..0000000
+++ /dev/null
@@ -1,211 +0,0 @@
-/*
- * Abilis Systems Single DVB-T Receiver
- * Copyright (C) 2008 Pierrick Hascoet <pierrick.hascoet@abilis.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, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#include <linux/kernel.h>
-#include "as102_drv.h"
-#include "as10x_cmd.h"
-
-/**
- * as10x_cmd_add_PID_filter - send add filter command to AS10x
- * @adap:      pointer to AS10x bus adapter
- * @filter:    TSFilter filter for DVB-T
- *
- * Return 0 on success or negative value in case of error.
- */
-int as10x_cmd_add_PID_filter(struct as10x_bus_adapter_t *adap,
-                            struct as10x_ts_filter *filter)
-{
-       int error;
-       struct as10x_cmd_t *pcmd, *prsp;
-
-       pcmd = adap->cmd;
-       prsp = adap->rsp;
-
-       /* prepare command */
-       as10x_cmd_build(pcmd, (++adap->cmd_xid),
-                       sizeof(pcmd->body.add_pid_filter.req));
-
-       /* fill command */
-       pcmd->body.add_pid_filter.req.proc_id =
-               cpu_to_le16(CONTROL_PROC_SETFILTER);
-       pcmd->body.add_pid_filter.req.pid = cpu_to_le16(filter->pid);
-       pcmd->body.add_pid_filter.req.stream_type = filter->type;
-
-       if (filter->idx < 16)
-               pcmd->body.add_pid_filter.req.idx = filter->idx;
-       else
-               pcmd->body.add_pid_filter.req.idx = 0xFF;
-
-       /* send command */
-       if (adap->ops->xfer_cmd) {
-               error = adap->ops->xfer_cmd(adap, (uint8_t *) pcmd,
-                               sizeof(pcmd->body.add_pid_filter.req)
-                               + HEADER_SIZE, (uint8_t *) prsp,
-                               sizeof(prsp->body.add_pid_filter.rsp)
-                               + HEADER_SIZE);
-       } else {
-               error = AS10X_CMD_ERROR;
-       }
-
-       if (error < 0)
-               goto out;
-
-       /* parse response */
-       error = as10x_rsp_parse(prsp, CONTROL_PROC_SETFILTER_RSP);
-
-       if (error == 0) {
-               /* Response OK -> get response data */
-               filter->idx = prsp->body.add_pid_filter.rsp.filter_id;
-       }
-
-out:
-       return error;
-}
-
-/**
- * as10x_cmd_del_PID_filter - Send delete filter command to AS10x
- * @adap:         pointer to AS10x bus adapte
- * @pid_value:    PID to delete
- *
- * Return 0 on success or negative value in case of error.
- */
-int as10x_cmd_del_PID_filter(struct as10x_bus_adapter_t *adap,
-                            uint16_t pid_value)
-{
-       int error;
-       struct as10x_cmd_t *pcmd, *prsp;
-
-       pcmd = adap->cmd;
-       prsp = adap->rsp;
-
-       /* prepare command */
-       as10x_cmd_build(pcmd, (++adap->cmd_xid),
-                       sizeof(pcmd->body.del_pid_filter.req));
-
-       /* fill command */
-       pcmd->body.del_pid_filter.req.proc_id =
-               cpu_to_le16(CONTROL_PROC_REMOVEFILTER);
-       pcmd->body.del_pid_filter.req.pid = cpu_to_le16(pid_value);
-
-       /* send command */
-       if (adap->ops->xfer_cmd) {
-               error = adap->ops->xfer_cmd(adap, (uint8_t *) pcmd,
-                               sizeof(pcmd->body.del_pid_filter.req)
-                               + HEADER_SIZE, (uint8_t *) prsp,
-                               sizeof(prsp->body.del_pid_filter.rsp)
-                               + HEADER_SIZE);
-       } else {
-               error = AS10X_CMD_ERROR;
-       }
-
-       if (error < 0)
-               goto out;
-
-       /* parse response */
-       error = as10x_rsp_parse(prsp, CONTROL_PROC_REMOVEFILTER_RSP);
-
-out:
-       return error;
-}
-
-/**
- * as10x_cmd_start_streaming - Send start streaming command to AS10x
- * @adap:   pointer to AS10x bus adapter
- *
- * Return 0 on success or negative value in case of error.
- */
-int as10x_cmd_start_streaming(struct as10x_bus_adapter_t *adap)
-{
-       int error;
-       struct as10x_cmd_t *pcmd, *prsp;
-
-       pcmd = adap->cmd;
-       prsp = adap->rsp;
-
-       /* prepare command */
-       as10x_cmd_build(pcmd, (++adap->cmd_xid),
-                       sizeof(pcmd->body.start_streaming.req));
-
-       /* fill command */
-       pcmd->body.start_streaming.req.proc_id =
-               cpu_to_le16(CONTROL_PROC_START_STREAMING);
-
-       /* send command */
-       if (adap->ops->xfer_cmd) {
-               error = adap->ops->xfer_cmd(adap, (uint8_t *) pcmd,
-                               sizeof(pcmd->body.start_streaming.req)
-                               + HEADER_SIZE, (uint8_t *) prsp,
-                               sizeof(prsp->body.start_streaming.rsp)
-                               + HEADER_SIZE);
-       } else {
-               error = AS10X_CMD_ERROR;
-       }
-
-       if (error < 0)
-               goto out;
-
-       /* parse response */
-       error = as10x_rsp_parse(prsp, CONTROL_PROC_START_STREAMING_RSP);
-
-out:
-       return error;
-}
-
-/**
- * as10x_cmd_stop_streaming - Send stop streaming command to AS10x
- * @adap:   pointer to AS10x bus adapter
- *
- * Return 0 on success or negative value in case of error.
- */
-int as10x_cmd_stop_streaming(struct as10x_bus_adapter_t *adap)
-{
-       int8_t error;
-       struct as10x_cmd_t *pcmd, *prsp;
-
-       pcmd = adap->cmd;
-       prsp = adap->rsp;
-
-       /* prepare command */
-       as10x_cmd_build(pcmd, (++adap->cmd_xid),
-                       sizeof(pcmd->body.stop_streaming.req));
-
-       /* fill command */
-       pcmd->body.stop_streaming.req.proc_id =
-               cpu_to_le16(CONTROL_PROC_STOP_STREAMING);
-
-       /* send command */
-       if (adap->ops->xfer_cmd) {
-               error = adap->ops->xfer_cmd(adap, (uint8_t *) pcmd,
-                               sizeof(pcmd->body.stop_streaming.req)
-                               + HEADER_SIZE, (uint8_t *) prsp,
-                               sizeof(prsp->body.stop_streaming.rsp)
-                               + HEADER_SIZE);
-       } else {
-               error = AS10X_CMD_ERROR;
-       }
-
-       if (error < 0)
-               goto out;
-
-       /* parse response */
-       error = as10x_rsp_parse(prsp, CONTROL_PROC_STOP_STREAMING_RSP);
-
-out:
-       return error;
-}
diff --git a/drivers/staging/media/as102/as10x_handle.h b/drivers/staging/media/as102/as10x_handle.h
deleted file mode 100644 (file)
index 5638b19..0000000
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Abilis Systems Single DVB-T Receiver
- * Copyright (C) 2008 Pierrick Hascoet <pierrick.hascoet@abilis.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, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-#ifdef __KERNEL__
-struct as10x_bus_adapter_t;
-struct as102_dev_t;
-
-#include "as10x_cmd.h"
-
-/* values for "mode" field */
-#define REGMODE8       8
-#define REGMODE16      16
-#define REGMODE32      32
-
-struct as102_priv_ops_t {
-       int (*upload_fw_pkt)(struct as10x_bus_adapter_t *bus_adap,
-                             unsigned char *buf, int buflen, int swap32);
-
-       int (*send_cmd)(struct as10x_bus_adapter_t *bus_adap,
-                        unsigned char *buf, int buflen);
-
-       int (*xfer_cmd)(struct as10x_bus_adapter_t *bus_adap,
-                        unsigned char *send_buf, int send_buf_len,
-                        unsigned char *recv_buf, int recv_buf_len);
-
-       int (*start_stream)(struct as102_dev_t *dev);
-       void (*stop_stream)(struct as102_dev_t *dev);
-
-       int (*reset_target)(struct as10x_bus_adapter_t *bus_adap);
-
-       int (*read_write)(struct as10x_bus_adapter_t *bus_adap, uint8_t mode,
-                         uint32_t rd_addr, uint16_t rd_len,
-                         uint32_t wr_addr, uint16_t wr_len);
-
-       int (*as102_read_ep2)(struct as10x_bus_adapter_t *bus_adap,
-                              unsigned char *recv_buf,
-                              int recv_buf_len);
-};
-#endif
diff --git a/drivers/staging/media/as102/as10x_types.h b/drivers/staging/media/as102/as10x_types.h
deleted file mode 100644 (file)
index af26e05..0000000
+++ /dev/null
@@ -1,194 +0,0 @@
-/*
- * Abilis Systems Single DVB-T Receiver
- * Copyright (C) 2008 Pierrick Hascoet <pierrick.hascoet@abilis.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, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-#ifndef _AS10X_TYPES_H_
-#define _AS10X_TYPES_H_
-
-#include "as10x_handle.h"
-
-/*********************************/
-/*       MACRO DEFINITIONS       */
-/*********************************/
-
-/* bandwidth constant values */
-#define BW_5_MHZ               0x00
-#define BW_6_MHZ               0x01
-#define BW_7_MHZ               0x02
-#define BW_8_MHZ               0x03
-
-/* hierarchy priority selection values */
-#define HIER_NO_PRIORITY       0x00
-#define HIER_LOW_PRIORITY      0x01
-#define HIER_HIGH_PRIORITY     0x02
-
-/* constellation available values */
-#define CONST_QPSK             0x00
-#define CONST_QAM16            0x01
-#define CONST_QAM64            0x02
-#define CONST_UNKNOWN          0xFF
-
-/* hierarchy available values */
-#define HIER_NONE              0x00
-#define HIER_ALPHA_1           0x01
-#define HIER_ALPHA_2           0x02
-#define HIER_ALPHA_4           0x03
-#define HIER_UNKNOWN           0xFF
-
-/* interleaving available values */
-#define INTLV_NATIVE           0x00
-#define INTLV_IN_DEPTH         0x01
-#define INTLV_UNKNOWN          0xFF
-
-/* code rate available values */
-#define CODE_RATE_1_2          0x00
-#define CODE_RATE_2_3          0x01
-#define CODE_RATE_3_4          0x02
-#define CODE_RATE_5_6          0x03
-#define CODE_RATE_7_8          0x04
-#define CODE_RATE_UNKNOWN      0xFF
-
-/* guard interval available values */
-#define GUARD_INT_1_32         0x00
-#define GUARD_INT_1_16         0x01
-#define GUARD_INT_1_8          0x02
-#define GUARD_INT_1_4          0x03
-#define GUARD_UNKNOWN          0xFF
-
-/* transmission mode available values */
-#define TRANS_MODE_2K          0x00
-#define TRANS_MODE_8K          0x01
-#define TRANS_MODE_4K          0x02
-#define TRANS_MODE_UNKNOWN     0xFF
-
-/* DVBH signalling available values */
-#define TIMESLICING_PRESENT    0x01
-#define MPE_FEC_PRESENT                0x02
-
-/* tune state available */
-#define TUNE_STATUS_NOT_TUNED          0x00
-#define TUNE_STATUS_IDLE               0x01
-#define TUNE_STATUS_LOCKING            0x02
-#define TUNE_STATUS_SIGNAL_DVB_OK      0x03
-#define TUNE_STATUS_STREAM_DETECTED    0x04
-#define TUNE_STATUS_STREAM_TUNED       0x05
-#define TUNE_STATUS_ERROR              0xFF
-
-/* available TS FID filter types */
-#define TS_PID_TYPE_TS         0
-#define TS_PID_TYPE_PSI_SI     1
-#define TS_PID_TYPE_MPE                2
-
-/* number of echos available */
-#define MAX_ECHOS      15
-
-/* Context types */
-#define CONTEXT_LNA                    1010
-#define CONTEXT_ELNA_HYSTERESIS                4003
-#define CONTEXT_ELNA_GAIN              4004
-#define CONTEXT_MER_THRESHOLD          5005
-#define CONTEXT_MER_OFFSET             5006
-#define CONTEXT_IR_STATE               7000
-#define CONTEXT_TSOUT_MSB_FIRST                7004
-#define CONTEXT_TSOUT_FALLING_EDGE     7005
-
-/* Configuration modes */
-#define CFG_MODE_ON    0
-#define CFG_MODE_OFF   1
-#define CFG_MODE_AUTO  2
-
-struct as10x_tps {
-       uint8_t modulation;
-       uint8_t hierarchy;
-       uint8_t interleaving_mode;
-       uint8_t code_rate_HP;
-       uint8_t code_rate_LP;
-       uint8_t guard_interval;
-       uint8_t transmission_mode;
-       uint8_t DVBH_mask_HP;
-       uint8_t DVBH_mask_LP;
-       uint16_t cell_ID;
-} __packed;
-
-struct as10x_tune_args {
-       /* frequency */
-       uint32_t freq;
-       /* bandwidth */
-       uint8_t bandwidth;
-       /* hierarchy selection */
-       uint8_t hier_select;
-       /* constellation */
-       uint8_t modulation;
-       /* hierarchy */
-       uint8_t hierarchy;
-       /* interleaving mode */
-       uint8_t interleaving_mode;
-       /* code rate */
-       uint8_t code_rate;
-       /* guard interval */
-       uint8_t guard_interval;
-       /* transmission mode */
-       uint8_t transmission_mode;
-} __packed;
-
-struct as10x_tune_status {
-       /* tune status */
-       uint8_t tune_state;
-       /* signal strength */
-       int16_t signal_strength;
-       /* packet error rate 10^-4 */
-       uint16_t PER;
-       /* bit error rate 10^-4 */
-       uint16_t BER;
-} __packed;
-
-struct as10x_demod_stats {
-       /* frame counter */
-       uint32_t frame_count;
-       /* Bad frame counter */
-       uint32_t bad_frame_count;
-       /* Number of wrong bytes fixed by Reed-Solomon */
-       uint32_t bytes_fixed_by_rs;
-       /* Averaged MER */
-       uint16_t mer;
-       /* statistics calculation state indicator (started or not) */
-       uint8_t has_started;
-} __packed;
-
-struct as10x_ts_filter {
-       uint16_t pid;  /* valid PID value 0x00 : 0x2000 */
-       uint8_t  type; /* Red TS_PID_TYPE_<N> values */
-       uint8_t  idx;  /* index in filtering table */
-} __packed;
-
-struct as10x_register_value {
-       uint8_t mode;
-       union {
-               uint8_t  value8;   /* 8 bit value */
-               uint16_t value16;  /* 16 bit value */
-               uint32_t value32;  /* 32 bit value */
-       } __packed u;
-} __packed;
-
-struct as10x_register_addr {
-       /* register addr */
-       uint32_t addr;
-       /* register mode access */
-       uint8_t mode;
-};
-
-#endif
index 12f321dd23993ea8a1d35c54e6d14b733470484c..4de2f082491d8a007cac94b17f2fb55096b9c371 100644 (file)
@@ -1,6 +1,7 @@
 config VIDEO_DM365_VPFE
        tristate "DM365 VPFE Media Controller Capture Driver"
        depends on VIDEO_V4L2 && ARCH_DAVINCI_DM365 && !VIDEO_DM365_ISIF
+       depends on HAS_DMA
        select VIDEOBUF2_DMA_CONTIG
        help
          Support for DM365 VPFE based Media Controller Capture driver.
index 226a1ca90b3c6a11098dd9846559db986c5506e0..2d496001b6e84d5d04e44b64274d4431f2c56ff2 100644 (file)
@@ -1,6 +1,7 @@
 config VIDEO_DT3155
        tristate "DT3155 frame grabber, Video4Linux interface"
        depends on PCI && VIDEO_DEV && VIDEO_V4L2
+       depends on HAS_DMA
        select VIDEOBUF2_DMA_CONTIG
        default n
        ---help---
index 726cc3a31856673952525e0343fa0be95d7f41ec..7aca44f28c5ad54087b9a6fdd2dbe0fc6ff1bb20 100644 (file)
@@ -414,6 +414,7 @@ static ssize_t vfd_write(struct file *file, const char __user *buf,
        data_buf = memdup_user(buf, n_bytes);
        if (IS_ERR(data_buf)) {
                retval = PTR_ERR(data_buf);
+               data_buf = NULL;
                goto exit;
        }
 
index 86ad811fda24c1723e91ad816e97d4ca761c3f32..c20ef56202bf05ab9c8c72860c01f08ef813beeb 100644 (file)
@@ -392,6 +392,7 @@ static ssize_t vfd_write(struct file *file, const char __user *buf,
        data_buf = memdup_user((void const __user *)buf, n_bytes);
        if (IS_ERR(data_buf)) {
                retval = PTR_ERR(data_buf);
+               data_buf = NULL;
                goto exit;
        }
 
index 8afc6fee40c547ccca5f5c106e651c3fbfce9942..b78643f907e7a4e7cd4974a877c3ddd98a19a77e 100644 (file)
@@ -1,6 +1,7 @@
 config VIDEO_OMAP4
        bool "OMAP 4 Camera support"
        depends on VIDEO_V4L2=y && VIDEO_V4L2_SUBDEV_API && I2C=y && ARCH_OMAP4
+       depends on HAS_DMA
        select VIDEOBUF2_DMA_CONTIG
        ---help---
          Driver for an OMAP 4 ISS controller.
index 1718229f627861993cf15223075367cdbb8e63e9..d9d55d12fd5fdef16e3632f3832c7111bb46044d 100644 (file)
@@ -79,7 +79,7 @@ int rtw_android_cmdstr_to_num(char *cmdstr)
 {
        int cmd_num;
        for (cmd_num = 0; cmd_num < ANDROID_WIFI_CMD_MAX; cmd_num++)
-               if (0 == strnicmp(cmdstr , android_wifi_cmd_str[cmd_num],
+               if (0 == strncasecmp(cmdstr , android_wifi_cmd_str[cmd_num],
                                  strlen(android_wifi_cmd_str[cmd_num])))
                        break;
        return cmd_num;
index 91d35df286c345cf0d71a10eee78da76dd437ed6..2d82f8993ea1422111fcfa18f90381b5862024cf 100644 (file)
@@ -2957,25 +2957,13 @@ extern inline int rtllib_get_scans(struct rtllib_device *ieee)
 static inline const char *escape_essid(const char *essid, u8 essid_len)
 {
        static char escaped[IW_ESSID_MAX_SIZE * 2 + 1];
-       const char *s = essid;
-       char *d = escaped;
 
        if (rtllib_is_empty_essid(essid, essid_len)) {
                memcpy(escaped, "<hidden>", sizeof("<hidden>"));
                return escaped;
        }
 
-       essid_len = min(essid_len, (u8)IW_ESSID_MAX_SIZE);
-       while (essid_len--) {
-               if (*s == '\0') {
-                       *d++ = '\\';
-                       *d++ = '0';
-                       s++;
-               } else {
-                       *d++ = *s++;
-               }
-       }
-       *d = '\0';
+       snprintf(escaped, sizeof(escaped), "%*pEn", essid_len, essid);
        return escaped;
 }
 
index 9ecfa4a2421d7b5b815d114e0d551615ce9de0e5..b44aa17d30a764f429fad303d9c562d97975b8d4 100644 (file)
@@ -2593,25 +2593,13 @@ static inline int ieee80211_get_scans(struct ieee80211_device *ieee)
 
 static inline const char *escape_essid(const char *essid, u8 essid_len) {
        static char escaped[IW_ESSID_MAX_SIZE * 2 + 1];
-       const char *s = essid;
-       char *d = escaped;
 
        if (ieee80211_is_empty_essid(essid, essid_len)) {
                memcpy(escaped, "<hidden>", sizeof("<hidden>"));
                return escaped;
        }
 
-       essid_len = min(essid_len, (u8)IW_ESSID_MAX_SIZE);
-       while (essid_len--) {
-               if (*s == '\0') {
-                       *d++ = '\\';
-                       *d++ = '0';
-                       s++;
-               } else {
-                       *d++ = *s++;
-               }
-       }
-       *d = '\0';
+       snprintf(escaped, sizeof(escaped), "%*pEn", essid_len, essid);
        return escaped;
 }
 
index 73cec14cbf566c89436f4b92b8c6ed435513881b..8b1f533314331e5d9882316259954ef42254d355 100644 (file)
@@ -410,41 +410,19 @@ static ssize_t vme_user_write(struct file *file, const char __user *buf,
 
 static loff_t vme_user_llseek(struct file *file, loff_t off, int whence)
 {
-       loff_t absolute = -1;
        unsigned int minor = MINOR(file_inode(file)->i_rdev);
        size_t image_size;
+       loff_t res;
 
        if (minor == CONTROL_MINOR)
                return -EINVAL;
 
        mutex_lock(&image[minor].mutex);
        image_size = vme_get_size(image[minor].resource);
-
-       switch (whence) {
-       case SEEK_SET:
-               absolute = off;
-               break;
-       case SEEK_CUR:
-               absolute = file->f_pos + off;
-               break;
-       case SEEK_END:
-               absolute = image_size + off;
-               break;
-       default:
-               mutex_unlock(&image[minor].mutex);
-               return -EINVAL;
-       }
-
-       if ((absolute < 0) || (absolute >= image_size)) {
-               mutex_unlock(&image[minor].mutex);
-               return -EINVAL;
-       }
-
-       file->f_pos = absolute;
-
+       res = fixed_size_llseek(file, off, whence, image_size);
        mutex_unlock(&image[minor].mutex);
 
-       return absolute;
+       return res;
 }
 
 /*
index 799ce8aa70efb2ba30018668d2aebbb6b8d4b107..df577dfe7ffbe18ea45a0f2a91804a1a22f7062e 100644 (file)
@@ -60,7 +60,6 @@
 #include <linux/netdevice.h>
 #include <linux/workqueue.h>
 #include <linux/byteorder/generic.h>
-#include <linux/ctype.h>
 
 #include <linux/io.h>
 #include <linux/delay.h>
 #include "hfa384x.h"
 #include "prism2mgmt.h"
 
-/* Create a string of printable chars from something that might not be */
-/* It's recommended that the str be 4*len + 1 bytes long */
-#define wlan_mkprintstr(buf, buflen, str, strlen) \
-{ \
-       int i = 0; \
-       int j = 0; \
-       memset(str, 0, (strlen)); \
-       for (i = 0; i < (buflen); i++) { \
-               if (isprint((buf)[i])) { \
-                       (str)[j] = (buf)[i]; \
-                       j++; \
-               } else { \
-                       (str)[j] = '\\'; \
-                       (str)[j+1] = 'x'; \
-                       (str)[j+2] = hex_asc_hi((buf)[i]); \
-                       (str)[j+3] = hex_asc_lo((buf)[i]); \
-                       j += 4; \
-               } \
-       } \
-}
-
 static char *dev_info = "prism2_usb";
 static wlandevice_t *create_wlan(void);
 
@@ -607,7 +585,6 @@ static int prism2sta_getcardinfo(wlandevice_t *wlandev)
        hfa384x_t *hw = (hfa384x_t *) wlandev->priv;
        u16 temp;
        u8 snum[HFA384x_RID_NICSERIALNUMBER_LEN];
-       char pstr[(HFA384x_RID_NICSERIALNUMBER_LEN * 4) + 1];
 
        /* Collect version and compatibility info */
        /*  Some are critical, some are not */
@@ -862,9 +839,8 @@ static int prism2sta_getcardinfo(wlandevice_t *wlandev)
        result = hfa384x_drvr_getconfig(hw, HFA384x_RID_NICSERIALNUMBER,
                                        snum, HFA384x_RID_NICSERIALNUMBER_LEN);
        if (!result) {
-               wlan_mkprintstr(snum, HFA384x_RID_NICSERIALNUMBER_LEN,
-                               pstr, sizeof(pstr));
-               netdev_info(wlandev->netdev, "Prism2 card SN: %s\n", pstr);
+               netdev_info(wlandev->netdev, "Prism2 card SN: %*pEhp\n",
+                           HFA384x_RID_NICSERIALNUMBER_LEN, snum);
        } else {
                netdev_err(wlandev->netdev, "Failed to retrieve Prism2 Card SN\n");
                goto failed;
index 71b0ec0c370d73aad18d685118c197735c5b2833..1e23f4f8d2c2099cc2f634010e4ff8ff2c2db11c 100644 (file)
@@ -66,7 +66,7 @@ static struct thermal_governor *__find_governor(const char *name)
                return def_governor;
 
        list_for_each_entry(pos, &thermal_governor_list, governor_list)
-               if (!strnicmp(name, pos->name, THERMAL_NAME_LENGTH))
+               if (!strncasecmp(name, pos->name, THERMAL_NAME_LENGTH))
                        return pos;
 
        return NULL;
@@ -104,7 +104,7 @@ int thermal_register_governor(struct thermal_governor *governor)
 
                name = pos->tzp->governor_name;
 
-               if (!strnicmp(name, governor->name, THERMAL_NAME_LENGTH))
+               if (!strncasecmp(name, governor->name, THERMAL_NAME_LENGTH))
                        pos->governor = governor;
        }
 
@@ -129,7 +129,7 @@ void thermal_unregister_governor(struct thermal_governor *governor)
        mutex_lock(&thermal_list_lock);
 
        list_for_each_entry(pos, &thermal_tz_list, node) {
-               if (!strnicmp(pos->governor->name, governor->name,
+               if (!strncasecmp(pos->governor->name, governor->name,
                                                THERMAL_NAME_LENGTH))
                        pos->governor = NULL;
        }
@@ -1665,7 +1665,7 @@ struct thermal_zone_device *thermal_zone_get_zone_by_name(const char *name)
 
        mutex_lock(&thermal_list_lock);
        list_for_each_entry(pos, &thermal_tz_list, node)
-               if (!strnicmp(name, pos->type, THERMAL_NAME_LENGTH)) {
+               if (!strncasecmp(name, pos->type, THERMAL_NAME_LENGTH)) {
                        found++;
                        ref = pos;
                }
index 8096fcbe2dc171d4742b561fdcaa0f60e1894547..d7b198c400c755487309cf6e6d9b615c9cfe4a69 100644 (file)
@@ -77,7 +77,6 @@ bfin_jc_emudat_manager(void *arg)
                        pr_debug("waiting for readers\n");
                        __set_current_state(TASK_UNINTERRUPTIBLE);
                        schedule();
-                       __set_current_state(TASK_RUNNING);
                        continue;
                }
 
index 5618b5fc7500e149dfd79ac2515309749f905834..f575a9b5ede7b05bd24c87ecf58425e89ec20fdc 100644 (file)
@@ -452,7 +452,7 @@ void __init hvc_vio_init_early(void)
                return;
 #endif
        /* Check whether the user has requested a different console. */
-       if (!strstr(cmd_line, "console="))
+       if (!strstr(boot_command_line, "console="))
                add_preferred_console("hvc", 0, NULL);
        hvc_instantiate(0, 0, ops);
 }
index 2967f0388d2c0153a09471a9b5e059ed033d66f9..f1e57425e39ff00b1a929500f4ea297aba5ae095 100644 (file)
@@ -347,8 +347,6 @@ static int xen_console_remove(struct xencons_info *info)
 }
 
 #ifdef CONFIG_HVC_XEN_FRONTEND
-static struct xenbus_driver xencons_driver;
-
 static int xencons_remove(struct xenbus_device *dev)
 {
        return xen_console_remove(dev_get_drvdata(&dev->dev));
@@ -499,13 +497,14 @@ static const struct xenbus_device_id xencons_ids[] = {
        { "" }
 };
 
-
-static DEFINE_XENBUS_DRIVER(xencons, "xenconsole",
+static struct xenbus_driver xencons_driver = {
+       .name = "xenconsole",
+       .ids = xencons_ids,
        .probe = xencons_probe,
        .remove = xencons_remove,
        .resume = xencons_resume,
        .otherend_changed = xencons_backend_changed,
-);
+};
 #endif /* CONFIG_HVC_XEN_FRONTEND */
 
 static int __init xen_hvc_init(void)
index 2f6f9b5e4891d1fb92cec7687d9066c22993566c..16a2c0237dd60a06513e2ad1f616e13a7bd71c0b 100644 (file)
@@ -2186,8 +2186,9 @@ static int __tty_fasync(int fd, struct file *filp, int on)
                }
                get_pid(pid);
                spin_unlock_irqrestore(&tty->ctrl_lock, flags);
-               retval = __f_setown(filp, pid, type, 0);
+               __f_setown(filp, pid, type, 0);
                put_pid(pid);
+               retval = 0;
        }
 out:
        return retval;
index 4ad11e03cf540d69be8427e4e0547edcf83a4207..7c6771d027a222f33dc472a71ff400995749e0b7 100644 (file)
@@ -164,10 +164,9 @@ struct ffs_desc_helper {
 static int  __must_check ffs_epfiles_create(struct ffs_data *ffs);
 static void ffs_epfiles_destroy(struct ffs_epfile *epfiles, unsigned count);
 
-static struct inode *__must_check
+static struct dentry *
 ffs_sb_create_file(struct super_block *sb, const char *name, void *data,
-                  const struct file_operations *fops,
-                  struct dentry **dentry_p);
+                  const struct file_operations *fops);
 
 /* Devices management *******************************************************/
 
@@ -1119,10 +1118,9 @@ ffs_sb_make_inode(struct super_block *sb, void *data,
 }
 
 /* Create "regular" file */
-static struct inode *ffs_sb_create_file(struct super_block *sb,
+static struct dentry *ffs_sb_create_file(struct super_block *sb,
                                        const char *name, void *data,
-                                       const struct file_operations *fops,
-                                       struct dentry **dentry_p)
+                                       const struct file_operations *fops)
 {
        struct ffs_data *ffs = sb->s_fs_info;
        struct dentry   *dentry;
@@ -1141,10 +1139,7 @@ static struct inode *ffs_sb_create_file(struct super_block *sb,
        }
 
        d_add(dentry, inode);
-       if (dentry_p)
-               *dentry_p = dentry;
-
-       return inode;
+       return dentry;
 }
 
 /* Super block */
@@ -1189,7 +1184,7 @@ static int ffs_sb_fill(struct super_block *sb, void *_data, int silent)
 
        /* EP0 file */
        if (unlikely(!ffs_sb_create_file(sb, "ep0", ffs,
-                                        &ffs_ep0_operations, NULL)))
+                                        &ffs_ep0_operations)))
                return -ENOMEM;
 
        return 0;
@@ -1561,9 +1556,10 @@ static int ffs_epfiles_create(struct ffs_data *ffs)
                        sprintf(epfiles->name, "ep%02x", ffs->eps_addrmap[i]);
                else
                        sprintf(epfiles->name, "ep%u", i);
-               if (!unlikely(ffs_sb_create_file(ffs->sb, epfiles->name, epfile,
-                                                &ffs_epfile_operations,
-                                                &epfile->dentry))) {
+               epfile->dentry = ffs_sb_create_file(ffs->sb, epfiles->name,
+                                                epfile,
+                                                &ffs_epfile_operations);
+               if (unlikely(!epfile->dentry)) {
                        ffs_epfiles_destroy(epfiles, i - 1);
                        return -ENOMEM;
                }
index edefec2cc584444c53a6c4840e8f5143d1bdebe5..c744e4975d744c4fb710a429ec055616fffd4833 100644 (file)
@@ -198,7 +198,6 @@ struct ep_data {
        struct list_head                epfiles;
        wait_queue_head_t               wait;
        struct dentry                   *dentry;
-       struct inode                    *inode;
 };
 
 static inline void get_ep (struct ep_data *data)
@@ -1618,10 +1617,9 @@ static void destroy_ep_files (struct dev_data *dev)
 }
 
 
-static struct inode *
+static struct dentry *
 gadgetfs_create_file (struct super_block *sb, char const *name,
-               void *data, const struct file_operations *fops,
-               struct dentry **dentry_p);
+               void *data, const struct file_operations *fops);
 
 static int activate_ep_files (struct dev_data *dev)
 {
@@ -1649,10 +1647,9 @@ static int activate_ep_files (struct dev_data *dev)
                if (!data->req)
                        goto enomem1;
 
-               data->inode = gadgetfs_create_file (dev->sb, data->name,
-                               data, &ep_config_operations,
-                               &data->dentry);
-               if (!data->inode)
+               data->dentry = gadgetfs_create_file (dev->sb, data->name,
+                               data, &ep_config_operations);
+               if (!data->dentry)
                        goto enomem2;
                list_add_tail (&data->epfiles, &dev->epfiles);
        }
@@ -2012,10 +2009,9 @@ gadgetfs_make_inode (struct super_block *sb,
 /* creates in fs root directory, so non-renamable and non-linkable.
  * so inode and dentry are paired, until device reconfig.
  */
-static struct inode *
+static struct dentry *
 gadgetfs_create_file (struct super_block *sb, char const *name,
-               void *data, const struct file_operations *fops,
-               struct dentry **dentry_p)
+               void *data, const struct file_operations *fops)
 {
        struct dentry   *dentry;
        struct inode    *inode;
@@ -2031,8 +2027,7 @@ gadgetfs_create_file (struct super_block *sb, char const *name,
                return NULL;
        }
        d_add (dentry, inode);
-       *dentry_p = dentry;
-       return inode;
+       return dentry;
 }
 
 static const struct super_operations gadget_fs_operations = {
@@ -2080,9 +2075,8 @@ gadgetfs_fill_super (struct super_block *sb, void *opts, int silent)
                goto Enomem;
 
        dev->sb = sb;
-       if (!gadgetfs_create_file (sb, CHIP,
-                               dev, &dev_init_operations,
-                               &dev->dentry)) {
+       dev->dentry = gadgetfs_create_file(sb, CHIP, dev, &dev_init_operations);
+       if (!dev->dentry) {
                put_dev(dev);
                goto Enomem;
        }
index f7825332a3251b2001645b581eec09524562fbec..9558da3f06a05ac11706a3294c98efc0b2823502 100644 (file)
@@ -876,15 +876,11 @@ static void vfio_pci_remove(struct pci_dev *pdev)
 {
        struct vfio_pci_device *vdev;
 
-       mutex_lock(&driver_lock);
-
        vdev = vfio_del_group_dev(&pdev->dev);
        if (vdev) {
                iommu_group_put(pdev->dev.iommu_group);
                kfree(vdev);
        }
-
-       mutex_unlock(&driver_lock);
 }
 
 static pci_ers_result_t vfio_pci_aer_err_detected(struct pci_dev *pdev,
@@ -927,108 +923,90 @@ static struct pci_driver vfio_pci_driver = {
        .err_handler    = &vfio_err_handlers,
 };
 
-/*
- * Test whether a reset is necessary and possible.  We mark devices as
- * needs_reset when they are released, but don't have a function-local reset
- * available.  If any of these exist in the affected devices, we want to do
- * a bus/slot reset.  We also need all of the affected devices to be unused,
- * so we abort if any device has a non-zero refcnt.  driver_lock prevents a
- * device from being opened during the scan or unbound from vfio-pci.
- */
-static int vfio_pci_test_bus_reset(struct pci_dev *pdev, void *data)
-{
-       bool *needs_reset = data;
-       struct pci_driver *pci_drv = ACCESS_ONCE(pdev->driver);
-       int ret = -EBUSY;
-
-       if (pci_drv == &vfio_pci_driver) {
-               struct vfio_device *device;
-               struct vfio_pci_device *vdev;
-
-               device = vfio_device_get_from_dev(&pdev->dev);
-               if (!device)
-                       return ret;
-
-               vdev = vfio_device_data(device);
-               if (vdev) {
-                       if (vdev->needs_reset)
-                               *needs_reset = true;
-
-                       if (!vdev->refcnt)
-                               ret = 0;
-               }
-
-               vfio_device_put(device);
-       }
-
-       /*
-        * TODO: vfio-core considers groups to be viable even if some devices
-        * are attached to known drivers, like pci-stub or pcieport.  We can't
-        * freeze devices from being unbound to those drivers like we can
-        * here though, so it would be racy to test for them.  We also can't
-        * use device_lock() to prevent changes as that would interfere with
-        * PCI-core taking device_lock during bus reset.  For now, we require
-        * devices to be bound to vfio-pci to get a bus/slot reset on release.
-        */
-
-       return ret;
-}
+struct vfio_devices {
+       struct vfio_device **devices;
+       int cur_index;
+       int max_index;
+};
 
-/* Clear needs_reset on all affected devices after successful bus/slot reset */
-static int vfio_pci_clear_needs_reset(struct pci_dev *pdev, void *data)
+static int vfio_pci_get_devs(struct pci_dev *pdev, void *data)
 {
+       struct vfio_devices *devs = data;
        struct pci_driver *pci_drv = ACCESS_ONCE(pdev->driver);
 
-       if (pci_drv == &vfio_pci_driver) {
-               struct vfio_device *device;
-               struct vfio_pci_device *vdev;
+       if (pci_drv != &vfio_pci_driver)
+               return -EBUSY;
 
-               device = vfio_device_get_from_dev(&pdev->dev);
-               if (!device)
-                       return 0;
+       if (devs->cur_index == devs->max_index)
+               return -ENOSPC;
 
-               vdev = vfio_device_data(device);
-               if (vdev)
-                       vdev->needs_reset = false;
-
-               vfio_device_put(device);
-       }
+       devs->devices[devs->cur_index] = vfio_device_get_from_dev(&pdev->dev);
+       if (!devs->devices[devs->cur_index])
+               return -EINVAL;
 
+       devs->cur_index++;
        return 0;
 }
 
 /*
  * Attempt to do a bus/slot reset if there are devices affected by a reset for
  * this device that are needs_reset and all of the affected devices are unused
- * (!refcnt).  Callers of this function are required to hold driver_lock such
- * that devices can not be unbound from vfio-pci or opened by a user while we
- * test for and perform a bus/slot reset.
+ * (!refcnt).  Callers are required to hold driver_lock when calling this to
+ * prevent device opens and concurrent bus reset attempts.  We prevent device
+ * unbinds by acquiring and holding a reference to the vfio_device.
+ *
+ * NB: vfio-core considers a group to be viable even if some devices are
+ * bound to drivers like pci-stub or pcieport.  Here we require all devices
+ * to be bound to vfio_pci since that's the only way we can be sure they
+ * stay put.
  */
 static void vfio_pci_try_bus_reset(struct vfio_pci_device *vdev)
 {
+       struct vfio_devices devs = { .cur_index = 0 };
+       int i = 0, ret = -EINVAL;
        bool needs_reset = false, slot = false;
-       int ret;
+       struct vfio_pci_device *tmp;
 
        if (!pci_probe_reset_slot(vdev->pdev->slot))
                slot = true;
        else if (pci_probe_reset_bus(vdev->pdev->bus))
                return;
 
-       if (vfio_pci_for_each_slot_or_bus(vdev->pdev,
-                                         vfio_pci_test_bus_reset,
-                                         &needs_reset, slot) || !needs_reset)
+       if (vfio_pci_for_each_slot_or_bus(vdev->pdev, vfio_pci_count_devs,
+                                         &i, slot) || !i)
                return;
 
-       if (slot)
-               ret = pci_try_reset_slot(vdev->pdev->slot);
-       else
-               ret = pci_try_reset_bus(vdev->pdev->bus);
-
-       if (ret)
+       devs.max_index = i;
+       devs.devices = kcalloc(i, sizeof(struct vfio_device *), GFP_KERNEL);
+       if (!devs.devices)
                return;
 
-       vfio_pci_for_each_slot_or_bus(vdev->pdev,
-                                     vfio_pci_clear_needs_reset, NULL, slot);
+       if (vfio_pci_for_each_slot_or_bus(vdev->pdev,
+                                         vfio_pci_get_devs, &devs, slot))
+               goto put_devs;
+
+       for (i = 0; i < devs.cur_index; i++) {
+               tmp = vfio_device_data(devs.devices[i]);
+               if (tmp->needs_reset)
+                       needs_reset = true;
+               if (tmp->refcnt)
+                       goto put_devs;
+       }
+
+       if (needs_reset)
+               ret = slot ? pci_try_reset_slot(vdev->pdev->slot) :
+                            pci_try_reset_bus(vdev->pdev->bus);
+
+put_devs:
+       for (i = 0; i < devs.cur_index; i++) {
+               if (!ret) {
+                       tmp = vfio_device_data(devs.devices[i]);
+                       tmp->needs_reset = false;
+               }
+               vfio_device_put(devs.devices[i]);
+       }
+
+       kfree(devs.devices);
 }
 
 static void __exit vfio_pci_cleanup(void)
index 9dd49c9839ac6de24496d37e0f4020e424415a1d..553212f037c37304b0a07d6741b9b68d97ed2c54 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/device.h>
 #include <linux/interrupt.h>
 #include <linux/eventfd.h>
+#include <linux/msi.h>
 #include <linux/pci.h>
 #include <linux/file.h>
 #include <linux/poll.h>
@@ -548,6 +549,20 @@ static int vfio_msi_set_vector_signal(struct vfio_pci_device *vdev,
                return PTR_ERR(trigger);
        }
 
+       /*
+        * The MSIx vector table resides in device memory which may be cleared
+        * via backdoor resets. We don't allow direct access to the vector
+        * table so even if a userspace driver attempts to save/restore around
+        * such a reset it would be unsuccessful. To avoid this, restore the
+        * cached value of the message prior to enabling.
+        */
+       if (msix) {
+               struct msi_msg msg;
+
+               get_cached_msi_msg(irq, &msg);
+               write_msi_msg(irq, &msg);
+       }
+
        ret = request_irq(irq, vfio_msihandler, 0,
                          vdev->ctx[vector].name, trigger);
        if (ret) {
index 0734fbe5b651ef68ca464e9a667ded19a8df5f0b..583ccdb2c58f110fc45e7a7abdc56f81af8d3b4a 100644 (file)
@@ -57,7 +57,8 @@ struct vfio_iommu {
        struct list_head        domain_list;
        struct mutex            lock;
        struct rb_root          dma_list;
-       bool v2;
+       bool                    v2;
+       bool                    nesting;
 };
 
 struct vfio_domain {
@@ -705,6 +706,15 @@ static int vfio_iommu_type1_attach_group(void *iommu_data,
                goto out_free;
        }
 
+       if (iommu->nesting) {
+               int attr = 1;
+
+               ret = iommu_domain_set_attr(domain->domain, DOMAIN_ATTR_NESTING,
+                                           &attr);
+               if (ret)
+                       goto out_domain;
+       }
+
        ret = iommu_attach_group(domain->domain, iommu_group);
        if (ret)
                goto out_domain;
@@ -819,17 +829,26 @@ static void *vfio_iommu_type1_open(unsigned long arg)
 {
        struct vfio_iommu *iommu;
 
-       if (arg != VFIO_TYPE1_IOMMU && arg != VFIO_TYPE1v2_IOMMU)
-               return ERR_PTR(-EINVAL);
-
        iommu = kzalloc(sizeof(*iommu), GFP_KERNEL);
        if (!iommu)
                return ERR_PTR(-ENOMEM);
 
+       switch (arg) {
+       case VFIO_TYPE1_IOMMU:
+               break;
+       case VFIO_TYPE1_NESTING_IOMMU:
+               iommu->nesting = true;
+       case VFIO_TYPE1v2_IOMMU:
+               iommu->v2 = true;
+               break;
+       default:
+               kfree(iommu);
+               return ERR_PTR(-EINVAL);
+       }
+
        INIT_LIST_HEAD(&iommu->domain_list);
        iommu->dma_list = RB_ROOT;
        mutex_init(&iommu->lock);
-       iommu->v2 = (arg == VFIO_TYPE1v2_IOMMU);
 
        return iommu;
 }
@@ -885,6 +904,7 @@ static long vfio_iommu_type1_ioctl(void *iommu_data,
                switch (arg) {
                case VFIO_TYPE1_IOMMU:
                case VFIO_TYPE1v2_IOMMU:
+               case VFIO_TYPE1_NESTING_IOMMU:
                        return 1;
                case VFIO_DMA_CC_IOMMU:
                        if (!iommu)
index 86dfceb9201f2503e2050dc71c8906fcd8abf281..5fa42db769ee8e5d9d88edd8dbccc71102290ad1 100644 (file)
@@ -92,7 +92,7 @@ long vfio_spapr_iommu_eeh_ioctl(struct iommu_group *group,
 
        return ret;
 }
-EXPORT_SYMBOL(vfio_spapr_iommu_eeh_ioctl);
+EXPORT_SYMBOL_GPL(vfio_spapr_iommu_eeh_ioctl);
 
 MODULE_VERSION(DRIVER_VERSION);
 MODULE_LICENSE("GPL v2");
index a6f7cc0a088352c9695196b442a2153e57abb662..9a23698b6fe8398c1025ea3a234db11a4779ba09 100644 (file)
@@ -265,7 +265,6 @@ static int pm860x_backlight_probe(struct platform_device *pdev)
 static struct platform_driver pm860x_backlight_driver = {
        .driver         = {
                .name   = "88pm860x-backlight",
-               .owner  = THIS_MODULE,
        },
        .probe          = pm860x_backlight_probe,
 };
index 86234c31d79c0a1afb3ae05660f3472342ed1d50..50774e6577003d6fa8f7bb6f03d079fae1191530 100644 (file)
@@ -211,7 +211,6 @@ static int aat2870_bl_remove(struct platform_device *pdev)
 static struct platform_driver aat2870_bl_driver = {
        .driver = {
                .name   = "aat2870-backlight",
-               .owner  = THIS_MODULE,
        },
        .probe          = aat2870_bl_probe,
        .remove         = aat2870_bl_remove,
index f37097a261a210f1c168def54c2ef22e6fa6e965..dd88ba1d71ceb64849535542a8cb3289d89df4c1 100644 (file)
@@ -67,6 +67,7 @@ static int adp5520_bl_set(struct backlight_device *bl, int brightness)
 static int adp5520_bl_update_status(struct backlight_device *bl)
 {
        int brightness = bl->props.brightness;
+
        if (bl->props.power != FB_BLANK_UNBLANK)
                brightness = 0;
 
@@ -374,7 +375,6 @@ static SIMPLE_DEV_PM_OPS(adp5520_bl_pm_ops, adp5520_bl_suspend,
 static struct platform_driver adp5520_bl_driver = {
        .driver         = {
                .name   = "adp5520-backlight",
-               .owner  = THIS_MODULE,
                .pm     = &adp5520_bl_pm_ops,
        },
        .probe          = adp5520_bl_probe,
index be8d83deca7d5a2a7ca563873a7008d33599541b..71147f4461b8cb57fc3a0b62b502bc97bdac843b 100644 (file)
@@ -181,6 +181,7 @@ static int adp8860_clr_bits(struct i2c_client *client, int reg, uint8_t bit_mask
 static void adp8860_led_work(struct work_struct *work)
 {
        struct adp8860_led *led = container_of(work, struct adp8860_led, work);
+
        adp8860_write(led->client, ADP8860_ISC1 - led->id + 1,
                         led->new_brightness >> 1);
 }
@@ -362,6 +363,7 @@ static int adp8860_bl_set(struct backlight_device *bl, int brightness)
 static int adp8860_bl_update_status(struct backlight_device *bl)
 {
        int brightness = bl->props.brightness;
+
        if (bl->props.power != FB_BLANK_UNBLANK)
                brightness = 0;
 
@@ -499,6 +501,7 @@ static ssize_t adp8860_bl_l1_daylight_max_store(struct device *dev,
 {
        struct adp8860_bl *data = dev_get_drvdata(dev);
        int ret = kstrtoul(buf, 10, &data->cached_daylight_max);
+
        if (ret)
                return ret;
 
index 251af4d38d8648add6c2323c34fe24a7e048a772..037e430833435457381f2c282b3839e2a8964dc5 100644 (file)
@@ -144,6 +144,7 @@ static int adp8870_read(struct i2c_client *client, int reg, uint8_t *val)
 static int adp8870_write(struct i2c_client *client, u8 reg, u8 val)
 {
        int ret = i2c_smbus_write_byte_data(client, reg, val);
+
        if (ret)
                dev_err(&client->dev, "failed to write\n");
 
@@ -195,6 +196,7 @@ static int adp8870_clr_bits(struct i2c_client *client, int reg, uint8_t bit_mask
 static void adp8870_led_work(struct work_struct *work)
 {
        struct adp8870_led *led = container_of(work, struct adp8870_led, work);
+
        adp8870_write(led->client, ADP8870_ISC1 + led->id - 1,
                         led->new_brightness >> 1);
 }
@@ -399,6 +401,7 @@ static int adp8870_bl_set(struct backlight_device *bl, int brightness)
 static int adp8870_bl_update_status(struct backlight_device *bl)
 {
        int brightness = bl->props.brightness;
+
        if (bl->props.power != FB_BLANK_UNBLANK)
                brightness = 0;
 
@@ -649,6 +652,7 @@ static ssize_t adp8870_bl_l1_daylight_max_store(struct device *dev,
 {
        struct adp8870_bl *data = dev_get_drvdata(dev);
        int ret = kstrtoul(buf, 10, &data->cached_daylight_max);
+
        if (ret)
                return ret;
 
index 4726c8be626f3dc794dfb137da1353a0d69ed887..5f897f99cc9b68c154207bfaad4461137977ea97 100644 (file)
@@ -325,11 +325,11 @@ static int ams369fg06_power_on(struct ams369fg06 *lcd)
        if (!pd->reset) {
                dev_err(lcd->dev, "reset is NULL.\n");
                return -EINVAL;
-       } else {
-               pd->reset(lcd->ld);
-               msleep(pd->reset_delay);
        }
 
+       pd->reset(lcd->ld);
+       msleep(pd->reset_delay);
+
        ret = ams369fg06_ldi_init(lcd);
        if (ret) {
                dev_err(lcd->dev, "failed to initialize ldi.\n");
index bb1fc45b7549e7b0ffd4b49fc1cbce8512e4b0a5..734a9158946b1f805a3738d9e9c31f25cf8b3314 100644 (file)
@@ -467,7 +467,6 @@ static int as3711_backlight_probe(struct platform_device *pdev)
 static struct platform_driver as3711_backlight_driver = {
        .driver         = {
                .name   = "as3711-backlight",
-               .owner  = THIS_MODULE,
        },
        .probe          = as3711_backlight_probe,
 };
index 51d18d637e2b88f02a9ff6ff1ff9702645d07d73..d7c37a8ccd1fbabe00063ded2bb0337e184e73db 100644 (file)
@@ -143,6 +143,7 @@ static void lcdtg_i2c_send_byte(struct corgi_lcd *lcd,
                                uint8_t base, uint8_t data)
 {
        int i;
+
        for (i = 0; i < 8; i++) {
                if (data & 0x80)
                        lcdtg_i2c_send_bit(lcd, base | POWER0_COM_DOUT);
index f3fed9ef745f5aca7290677a2f6ae8d866be151e..3e3880fc8c8e3926cde346259d463aa0703dc469 100644 (file)
@@ -235,6 +235,7 @@ static int cr_backlight_probe(struct platform_device *pdev)
 static int cr_backlight_remove(struct platform_device *pdev)
 {
        struct cr_panel *crp = platform_get_drvdata(pdev);
+
        crp->cr_backlight_device->props.power = FB_BLANK_POWERDOWN;
        crp->cr_backlight_device->props.brightness = 0;
        crp->cr_backlight_device->props.max_brightness = 0;
index 12c5d840c5909e173fcf34492487b6409f479f67..f793738f06fbe142b454c7cf677ead073aef5f09 100644 (file)
@@ -162,7 +162,6 @@ static int da903x_backlight_probe(struct platform_device *pdev)
 static struct platform_driver da903x_backlight_driver = {
        .driver         = {
                .name   = "da903x-backlight",
-               .owner  = THIS_MODULE,
        },
        .probe          = da903x_backlight_probe,
 };
index 20d55becaa7434e76704a7a59771ab413014b09f..d4bd74bd5070709215c6ec4db409af67c841c4e8 100644 (file)
@@ -173,7 +173,6 @@ static struct platform_driver da9052_wled_driver = {
        .id_table       = da9052_wled_ids,
        .driver = {
                .name   = "da9052-wled",
-               .owner  = THIS_MODULE,
        },
 };
 
index 0d1f633c6480190d8dc90d0d122832b4e4c98174..0067931821c677b0bcb542d3aa3004633f2479ac 100644 (file)
@@ -128,7 +128,6 @@ static SIMPLE_DEV_PM_OPS(ep93xxbl_pm_ops, ep93xxbl_suspend, ep93xxbl_resume);
 static struct platform_driver ep93xxbl_driver = {
        .driver         = {
                .name   = "ep93xx-bl",
-               .owner  = THIS_MODULE,
                .pm     = &ep93xxbl_pm_ops,
        },
        .probe          = ep93xxbl_probe,
index 5d8d65200db77b739154c44e394138bc8b332641..67dfb939a51428f1fb1a54381bfde0b56d53fe8e 100644 (file)
@@ -52,24 +52,6 @@ static int genericbl_get_intensity(struct backlight_device *bd)
        return genericbl_intensity;
 }
 
-/*
- * Called when the battery is low to limit the backlight intensity.
- * If limit==0 clear any limit, otherwise limit the intensity
- */
-void genericbl_limit_intensity(int limit)
-{
-       struct backlight_device *bd = generic_backlight_device;
-
-       mutex_lock(&bd->ops_lock);
-       if (limit)
-               bd->props.state |= GENERICBL_BATTLOW;
-       else
-               bd->props.state &= ~GENERICBL_BATTLOW;
-       backlight_update_status(generic_backlight_device);
-       mutex_unlock(&bd->ops_lock);
-}
-EXPORT_SYMBOL(genericbl_limit_intensity);
-
 static const struct backlight_ops genericbl_ops = {
        .options = BL_CORE_SUSPENDRESUME,
        .get_brightness = genericbl_get_intensity,
index aaead04a2d541c838e02d7611f42d0c29a1a1084..439feb2389a8cc3d70a45d7a2a3eac431d4f8db9 100644 (file)
@@ -151,7 +151,6 @@ static struct of_device_id gpio_backlight_of_match[] = {
 static struct platform_driver gpio_backlight_driver = {
        .driver         = {
                .name           = "gpio-backlight",
-               .owner          = THIS_MODULE,
                .of_match_table = of_match_ptr(gpio_backlight_of_match),
        },
        .probe          = gpio_backlight_probe,
index ea67fe199e34ed880c305fa1b0ca26f330eccccd..e7f0890cc21142f947eaf41e6975e5007ecf96ce 100644 (file)
@@ -495,17 +495,18 @@ static int ili922x_probe(struct spi_device *spi)
                        "no LCD found: Chip ID 0x%x, ret %d\n",
                        reg, ret);
                return -ENODEV;
-       } else {
-               dev_info(&spi->dev, "ILI%x found, SPI freq %d, mode %d\n",
-                        reg, spi->max_speed_hz, spi->mode);
        }
 
+       dev_info(&spi->dev, "ILI%x found, SPI freq %d, mode %d\n",
+                reg, spi->max_speed_hz, spi->mode);
+
        ret = ili922x_read_status(spi, &reg);
        if (ret) {
                dev_err(&spi->dev, "reading RS failed...\n");
                return ret;
-       } else
-               dev_dbg(&spi->dev, "status: 0x%x\n", reg);
+       }
+
+       dev_dbg(&spi->dev, "status: 0x%x\n", reg);
 
        ili922x_display_init(spi);
 
index 6ce96b4a879696bc04457b329f2f39e16bb5e7ed..7e6ff53468924bcb246a81ad018dcbb397e54ea4 100644 (file)
@@ -41,11 +41,11 @@ static int jornada_bl_get_brightness(struct backlight_device *bd)
                dev_err(&bd->dev, "get brightness timeout\n");
                jornada_ssp_end();
                return -ETIMEDOUT;
-       } else {
-               /* exchange txdummy for value */
-               ret = jornada_ssp_byte(TXDUMMY);
        }
 
+       /* exchange txdummy for value */
+       ret = jornada_ssp_byte(TXDUMMY);
+
        jornada_ssp_end();
 
        return BL_MAX_BRIGHT - ret;
index 228bc319de1922251d3c4cffb5adf190c375393b..dfa0fa0d5c782c082efcd04fe9a5f1ed964787a4 100644 (file)
 
 static int jornada_lcd_get_power(struct lcd_device *ld)
 {
-       /* LDD2 in PPC = LCD POWER */
-       if (PPSR & PPC_LDD2)
-               return FB_BLANK_UNBLANK;        /* PW ON */
-       else
-               return FB_BLANK_POWERDOWN;      /* PW OFF */
+       return PPSR & PPC_LDD2 ? FB_BLANK_UNBLANK : FB_BLANK_POWERDOWN;
 }
 
 static int jornada_lcd_get_contrast(struct lcd_device *ld)
index ccb44e8e492721e981bc09dd98e58338020f6c48..f71eaf10c4ebddac11a32b5ec5baf03519743dc0 100644 (file)
@@ -566,11 +566,11 @@ static int ld9040_power_on(struct ld9040 *lcd)
        if (!pd->reset) {
                dev_err(lcd->dev, "reset is NULL.\n");
                return -EINVAL;
-       } else {
-               pd->reset(lcd->ld);
-               msleep(pd->reset_delay);
        }
 
+       pd->reset(lcd->ld);
+       msleep(pd->reset_delay);
+
        ret = ld9040_ldi_init(lcd);
        if (ret) {
                dev_err(lcd->dev, "failed to initialize ldi.\n");
index cff1fbe89a1bf547ed206e7979352dfaa4b0692b..0e2337f367b61bfa0639ef62a4e3c40f01b510cd 100644 (file)
@@ -397,7 +397,6 @@ static void lm3533_bl_shutdown(struct platform_device *pdev)
 static struct platform_driver lm3533_bl_driver = {
        .driver = {
                .name   = "lm3533-backlight",
-               .owner  = THIS_MODULE,
                .pm     = &lm3533_bl_pm_ops,
        },
        .probe          = lm3533_bl_probe,
index 5f36808d214f0d27665ced0baaf87e4f9a95b6ff..cd50df5807eadb2b4bf18b6fa8efc906beda0dee 100644 (file)
@@ -254,7 +254,6 @@ static void lm3639_torch_brightness_set(struct led_classdev *cdev,
        return;
 out:
        dev_err(pchip->dev, "i2c failed to access register\n");
-       return;
 }
 
 /* flash */
@@ -293,7 +292,6 @@ static void lm3639_flash_brightness_set(struct led_classdev *cdev,
        return;
 out:
        dev_err(pchip->dev, "i2c failed to access register\n");
-       return;
 }
 
 static const struct regmap_config lm3639_regmap = {
index 77258b7b04be288214cba7ee141bf87402c514cf..7e3810308c3e456e56d5f5e6512fbef0bbc2d7dd 100644 (file)
@@ -232,19 +232,19 @@ static int lms501kf03_power_on(struct lms501kf03 *lcd)
        if (!pd->power_on) {
                dev_err(lcd->dev, "power_on is NULL.\n");
                return -EINVAL;
-       } else {
-               pd->power_on(lcd->ld, 1);
-               msleep(pd->power_on_delay);
        }
 
+       pd->power_on(lcd->ld, 1);
+       msleep(pd->power_on_delay);
+
        if (!pd->reset) {
                dev_err(lcd->dev, "reset is NULL.\n");
                return -EINVAL;
-       } else {
-               pd->reset(lcd->ld);
-               msleep(pd->reset_delay);
        }
 
+       pd->reset(lcd->ld);
+       msleep(pd->reset_delay);
+
        ret = lms501kf03_ldi_init(lcd);
        if (ret) {
                dev_err(lcd->dev, "failed to initialize ldi.\n");
index dcdd5443efcf42237b0821963933c9b87a65c900..25fb8e3d75b16765e74198cacdf9e816ca84b3ea 100644 (file)
@@ -268,6 +268,7 @@ static int lp855x_bl_update_status(struct backlight_device *bl)
 
        } else if (lp->mode == REGISTER_BASED) {
                u8 val = bl->props.brightness;
+
                lp855x_write_byte(lp, lp->cfg->reg_brightness, val);
        }
 
@@ -308,6 +309,7 @@ static ssize_t lp855x_get_chip_id(struct device *dev,
                                struct device_attribute *attr, char *buf)
 {
        struct lp855x *lp = dev_get_drvdata(dev);
+
        return scnprintf(buf, PAGE_SIZE, "%s\n", lp->chipname);
 }
 
index d6c4f6a2d43e2a1c2ec872b061ddd408217a3537..e418d5b1aa55a6973ae1dfee8968f8d7baa778ca 100644 (file)
@@ -315,7 +315,6 @@ static struct platform_driver lp8788_bl_driver = {
        .remove = lp8788_backlight_remove,
        .driver = {
                .name = LP8788_DEV_BACKLIGHT,
-               .owner = THIS_MODULE,
        },
 };
 module_platform_driver(lp8788_bl_driver);
index 66fa08c920d25c61e492e8e639f5eea722835a36..7b738d60ecc22e27560e42c9cef0669628e4aa28 100644 (file)
@@ -197,7 +197,6 @@ static int max8925_backlight_probe(struct platform_device *pdev)
 static struct platform_driver max8925_backlight_driver = {
        .driver         = {
                .name   = "max8925-backlight",
-               .owner  = THIS_MODULE,
        },
        .probe          = max8925_backlight_probe,
 };
index a0dcd88ac74fce38d77531df242a690c4bc1eb12..546d94df21d53ac436891273828058043acb2c2d 100644 (file)
@@ -120,6 +120,7 @@ static int omapbl_update_status(struct backlight_device *dev)
 static int omapbl_get_intensity(struct backlight_device *dev)
 {
        struct omap_backlight *bl = bl_get_data(dev);
+
        return bl->current_intensity;
 }
 
index f5a5202dd79d4c1cbba5b11631f323fa5bf59ee3..3acdb9f646ed05792fa047eb5272d03a23e8eef6 100644 (file)
@@ -152,7 +152,6 @@ static int ot200_backlight_remove(struct platform_device *pdev)
 static struct platform_driver ot200_backlight_driver = {
        .driver         = {
                .name   = "ot200-backlight",
-               .owner  = THIS_MODULE,
        },
        .probe          = ot200_backlight_probe,
        .remove         = ot200_backlight_remove,
index 2e3f82063c03b7243eed9b077c14e0b081297724..5d8bb8b201835ddf96ed1a5465ed25f682a2a9e8 100644 (file)
@@ -142,7 +142,6 @@ static int pandora_backlight_probe(struct platform_device *pdev)
 static struct platform_driver pandora_backlight_driver = {
        .driver         = {
                .name   = "pandora-backlight",
-               .owner  = THIS_MODULE,
        },
        .probe          = pandora_backlight_probe,
 };
index b95d3b0aaffee03dc5f5f0380d91b456ea5293cb..85bd573b6d15c1b248fefb9addc5fd755772b635 100644 (file)
@@ -90,6 +90,7 @@ static int pcf50633_bl_update_status(struct backlight_device *bl)
 static int pcf50633_bl_get_brightness(struct backlight_device *bl)
 {
        struct pcf50633_bl *pcf_bl = bl_get_data(bl);
+
        return pcf_bl->brightness;
 }
 
index c3d2e209fc8f5b2ed148c30deeb5bffe970756a2..872a3bf21fafc014a5ee0453d9001485543b95ff 100644 (file)
@@ -148,7 +148,6 @@ MODULE_DEVICE_TABLE(of, platform_lcd_of_match);
 static struct platform_driver platform_lcd_driver = {
        .driver         = {
                .name   = "platform-lcd",
-               .owner  = THIS_MODULE,
                .pm     = &platform_lcd_pm_ops,
                .of_match_table = of_match_ptr(platform_lcd_of_match),
        },
index b85983e97f0afbc70665d1aa134d5b182e25976e..cb5ae4c08469c57304f337ae862bf46a11b58ac3 100644 (file)
@@ -390,7 +390,6 @@ static const struct dev_pm_ops pwm_backlight_pm_ops = {
 static struct platform_driver pwm_backlight_driver = {
        .driver         = {
                .name           = "pwm-backlight",
-               .owner          = THIS_MODULE,
                .pm             = &pwm_backlight_pm_ops,
                .of_match_table = of_match_ptr(pwm_backlight_of_match),
        },
index f3a65c8940ed9dae8c03fb115b23f09d3df87e39..28bfa127fee45aca7a0bd4c193efa47cb8d80e58 100644 (file)
@@ -507,19 +507,19 @@ static int s6e63m0_power_on(struct s6e63m0 *lcd)
        if (!pd->power_on) {
                dev_err(lcd->dev, "power_on is NULL.\n");
                return -EINVAL;
-       } else {
-               pd->power_on(lcd->ld, 1);
-               msleep(pd->power_on_delay);
        }
 
+       pd->power_on(lcd->ld, 1);
+       msleep(pd->power_on_delay);
+
        if (!pd->reset) {
                dev_err(lcd->dev, "reset is NULL.\n");
                return -EINVAL;
-       } else {
-               pd->reset(lcd->ld);
-               msleep(pd->reset_delay);
        }
 
+       pd->reset(lcd->ld);
+       msleep(pd->reset_delay);
+
        ret = s6e63m0_ldi_init(lcd);
        if (ret) {
                dev_err(lcd->dev, "failed to initialize ldi.\n");
index 908016fc5829ff3ef0667f5be62c51999d30106e..30afce33ef2afcfa364e3aa622d09a48b152d94e 100644 (file)
@@ -300,12 +300,14 @@ static int tdo24m_power(struct tdo24m *lcd, int power)
 static int tdo24m_set_power(struct lcd_device *ld, int power)
 {
        struct tdo24m *lcd = lcd_get_data(ld);
+
        return tdo24m_power(lcd, power);
 }
 
 static int tdo24m_get_power(struct lcd_device *ld)
 {
        struct tdo24m *lcd = lcd_get_data(ld);
+
        return lcd->power;
 }
 
index 2e04d93aa0efe0a8e687279d81e58c1f2d257d7a..61d72bffd402f25c2abc10266c4241c32ce006e5 100644 (file)
@@ -323,7 +323,6 @@ static int tps65217_bl_probe(struct platform_device *pdev)
 static struct platform_driver tps65217_bl_driver = {
        .probe          = tps65217_bl_probe,
        .driver         = {
-               .owner  = THIS_MODULE,
                .name   = "tps65217-bl",
        },
 };
index 8b9455e9306930027b4fa20454b2ac837d8b4ff9..6eab0d6c262aab5d11fa8d4da17f3c5d0e7d8e6c 100644 (file)
@@ -111,6 +111,7 @@ static int wm831x_backlight_update_status(struct backlight_device *bl)
 static int wm831x_backlight_get_brightness(struct backlight_device *bl)
 {
        struct wm831x_backlight_data *data = bl_get_data(bl);
+
        return data->current_brightness;
 }
 
@@ -217,7 +218,6 @@ static int wm831x_backlight_probe(struct platform_device *pdev)
 static struct platform_driver wm831x_backlight_driver = {
        .driver         = {
                .name   = "wm831x-backlight",
-               .owner  = THIS_MODULE,
        },
        .probe          = wm831x_backlight_probe,
 };
index e911b9c96e19ba644226b5ef5bb96338915c0995..ccbe2ae22ac5318b2bf3e5bfa227f1295c5d7982 100644 (file)
@@ -4,6 +4,7 @@
 
 menuconfig FB
        tristate "Support for frame buffer devices"
+       select FB_CMDLINE
        ---help---
          The frame buffer device provides an abstraction for the graphics
          hardware. It represents the frame buffer of some video hardware and
@@ -52,6 +53,9 @@ config FIRMWARE_EDID
         combination with certain motherboards and monitors are known to
         suffer from this problem.
 
+config FB_CMDLINE
+       bool
+
 config FB_DDC
        tristate
        depends on FB
index fa306538dac29ae6bfab136546949377e968782b..67f28e20a89256c0b11a23d9a81bf8defa98c1e5 100644 (file)
@@ -1,4 +1,5 @@
 obj-y                             += fb_notify.o
+obj-$(CONFIG_FB_CMDLINE)          += fb_cmdline.o
 obj-$(CONFIG_FB)                  += fb.o
 fb-y                              := fbmem.o fbmon.o fbcmap.o fbsysfs.o \
                                      modedb.o fbcvt.o
diff --git a/drivers/video/fbdev/core/fb_cmdline.c b/drivers/video/fbdev/core/fb_cmdline.c
new file mode 100644 (file)
index 0000000..39509cc
--- /dev/null
@@ -0,0 +1,110 @@
+/*
+ *  linux/drivers/video/fb_cmdline.c
+ *
+ *  Copyright (C) 2014 Intel Corp
+ *  Copyright (C) 1994 Martin Schaller
+ *
+ *     2001 - Documented with DocBook
+ *     - Brad Douglas <brad@neruo.com>
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file COPYING in the main directory of this archive
+ * for more details.
+ *
+ * Authors:
+ *    Vetter <danie.vetter@ffwll.ch>
+ */
+#include <linux/init.h>
+#include <linux/fb.h>
+
+static char *video_options[FB_MAX] __read_mostly;
+static int ofonly __read_mostly;
+
+const char *fb_mode_option;
+EXPORT_SYMBOL_GPL(fb_mode_option);
+
+/**
+ * fb_get_options - get kernel boot parameters
+ * @name:   framebuffer name as it would appear in
+ *          the boot parameter line
+ *          (video=<name>:<options>)
+ * @option: the option will be stored here
+ *
+ * NOTE: Needed to maintain backwards compatibility
+ */
+int fb_get_options(const char *name, char **option)
+{
+       char *opt, *options = NULL;
+       int retval = 0;
+       int name_len = strlen(name), i;
+
+       if (name_len && ofonly && strncmp(name, "offb", 4))
+               retval = 1;
+
+       if (name_len && !retval) {
+               for (i = 0; i < FB_MAX; i++) {
+                       if (video_options[i] == NULL)
+                               continue;
+                       if (!video_options[i][0])
+                               continue;
+                       opt = video_options[i];
+                       if (!strncmp(name, opt, name_len) &&
+                           opt[name_len] == ':')
+                               options = opt + name_len + 1;
+               }
+       }
+       /* No match, pass global option */
+       if (!options && option && fb_mode_option)
+               options = kstrdup(fb_mode_option, GFP_KERNEL);
+       if (options && !strncmp(options, "off", 3))
+               retval = 1;
+
+       if (option)
+               *option = options;
+
+       return retval;
+}
+EXPORT_SYMBOL(fb_get_options);
+
+/**
+ *     video_setup - process command line options
+ *     @options: string of options
+ *
+ *     Process command line options for frame buffer subsystem.
+ *
+ *     NOTE: This function is a __setup and __init function.
+ *            It only stores the options.  Drivers have to call
+ *            fb_get_options() as necessary.
+ *
+ *     Returns zero.
+ *
+ */
+static int __init video_setup(char *options)
+{
+       int i, global = 0;
+
+       if (!options || !*options)
+               global = 1;
+
+       if (!global && !strncmp(options, "ofonly", 6)) {
+               ofonly = 1;
+               global = 1;
+       }
+
+       if (!global && !strchr(options, ':')) {
+               fb_mode_option = options;
+               global = 1;
+       }
+
+       if (!global) {
+               for (i = 0; i < FB_MAX; i++) {
+                       if (video_options[i] == NULL) {
+                               video_options[i] = options;
+                               break;
+                       }
+               }
+       }
+
+       return 1;
+}
+__setup("video=", video_setup);
index b5e85f6c1c26a8576a74a6205a3857ebbeffe9bf..0705d8883edecc785a72f4ef256b9894e4d0e950 100644 (file)
@@ -1908,96 +1908,4 @@ int fb_new_modelist(struct fb_info *info)
        return err;
 }
 
-static char *video_options[FB_MAX] __read_mostly;
-static int ofonly __read_mostly;
-
-/**
- * fb_get_options - get kernel boot parameters
- * @name:   framebuffer name as it would appear in
- *          the boot parameter line
- *          (video=<name>:<options>)
- * @option: the option will be stored here
- *
- * NOTE: Needed to maintain backwards compatibility
- */
-int fb_get_options(const char *name, char **option)
-{
-       char *opt, *options = NULL;
-       int retval = 0;
-       int name_len = strlen(name), i;
-
-       if (name_len && ofonly && strncmp(name, "offb", 4))
-               retval = 1;
-
-       if (name_len && !retval) {
-               for (i = 0; i < FB_MAX; i++) {
-                       if (video_options[i] == NULL)
-                               continue;
-                       if (!video_options[i][0])
-                               continue;
-                       opt = video_options[i];
-                       if (!strncmp(name, opt, name_len) &&
-                           opt[name_len] == ':')
-                               options = opt + name_len + 1;
-               }
-       }
-       /* No match, pass global option */
-       if (!options && option && fb_mode_option)
-               options = kstrdup(fb_mode_option, GFP_KERNEL);
-       if (options && !strncmp(options, "off", 3))
-               retval = 1;
-
-       if (option)
-               *option = options;
-
-       return retval;
-}
-EXPORT_SYMBOL(fb_get_options);
-
-#ifndef MODULE
-/**
- *     video_setup - process command line options
- *     @options: string of options
- *
- *     Process command line options for frame buffer subsystem.
- *
- *     NOTE: This function is a __setup and __init function.
- *            It only stores the options.  Drivers have to call
- *            fb_get_options() as necessary.
- *
- *     Returns zero.
- *
- */
-static int __init video_setup(char *options)
-{
-       int i, global = 0;
-
-       if (!options || !*options)
-               global = 1;
-
-       if (!global && !strncmp(options, "ofonly", 6)) {
-               ofonly = 1;
-               global = 1;
-       }
-
-       if (!global && !strchr(options, ':')) {
-               fb_mode_option = options;
-               global = 1;
-       }
-
-       if (!global) {
-               for (i = 0; i < FB_MAX; i++) {
-                       if (video_options[i] == NULL) {
-                               video_options[i] = options;
-                               break;
-                       }
-
-               }
-       }
-
-       return 1;
-}
-__setup("video=", video_setup);
-#endif
-
 MODULE_LICENSE("GPL");
index a9a907c440d73ee89f2acc8fd20d7aa905230b43..388f7971494b1bea4b0fe1e6ab0e6a607f0baa66 100644 (file)
@@ -29,9 +29,6 @@
 #define DPRINTK(fmt, args...)
 #endif
 
-const char *fb_mode_option;
-EXPORT_SYMBOL_GPL(fb_mode_option);
-
 /*
  *  Standard video mode definitions (taken from XFree86)
  */
index 167cffff3d4e3436fc60856a43cef5efe3685763..7c74f58fc10194515ffb831ac31ba765315a2c44 100644 (file)
@@ -1001,7 +1001,7 @@ static int pvr2_get_param(const struct pvr2_params *p, const char *s, int val,
 
        for (i = 0 ; i < size ; i++ ) {
                if (s != NULL) {
-                       if (!strnicmp(p[i].name, s, strlen(s)))
+                       if (!strncasecmp(p[i].name, s, strlen(s)))
                                return p[i].val;
                } else {
                        if (p[i].val == val)
index 43c63a4f31784adf4ddaf9021fc2dead0098d309..e350eb57f11d6d7f5e989e1d0a5187fb2944fec8 100644 (file)
@@ -601,12 +601,12 @@ static int s3c2410fb_debug_store(struct device *dev,
        if (len < 1)
                return -EINVAL;
 
-       if (strnicmp(buf, "on", 2) == 0 ||
-           strnicmp(buf, "1", 1) == 0) {
+       if (strncasecmp(buf, "on", 2) == 0 ||
+           strncasecmp(buf, "1", 1) == 0) {
                debug = 1;
                dev_dbg(dev, "s3c2410fb: Debug On");
-       } else if (strnicmp(buf, "off", 3) == 0 ||
-                  strnicmp(buf, "0", 1) == 0) {
+       } else if (strncasecmp(buf, "off", 3) == 0 ||
+                  strncasecmp(buf, "0", 1) == 0) {
                debug = 0;
                dev_dbg(dev, "s3c2410fb: Debug Off");
        } else {
index 3f12a2dd959a0ade49737a9938654acd14a4233f..4f5cf035ac3c9aa524686b67a7d6c57eb62a7456 100644 (file)
@@ -162,7 +162,7 @@ static void sisfb_search_mode(char *name, bool quiet)
                return;
        }
 
-       if(!strnicmp(name, sisbios_mode[MODE_INDEX_NONE].name, strlen(name))) {
+       if(!strncasecmp(name, sisbios_mode[MODE_INDEX_NONE].name, strlen(name))) {
                if(!quiet)
                        printk(KERN_ERR "sisfb: Mode 'none' not supported anymore. Using default.\n");
 
@@ -201,7 +201,7 @@ static void sisfb_search_mode(char *name, bool quiet)
 
        i = 0; j = 0;
        while(sisbios_mode[i].mode_no[0] != 0) {
-               if(!strnicmp(nameptr, sisbios_mode[i++].name, strlen(nameptr))) {
+               if(!strncasecmp(nameptr, sisbios_mode[i++].name, strlen(nameptr))) {
                        if(sisfb_fstn) {
                                if(sisbios_mode[i-1].mode_no[1] == 0x50 ||
                                   sisbios_mode[i-1].mode_no[1] == 0x56 ||
@@ -262,7 +262,7 @@ sisfb_search_crt2type(const char *name)
        if(name == NULL) return;
 
        while(sis_crt2type[i].type_no != -1) {
-               if(!strnicmp(name, sis_crt2type[i].name, strlen(sis_crt2type[i].name))) {
+               if(!strncasecmp(name, sis_crt2type[i].name, strlen(sis_crt2type[i].name))) {
                        sisfb_crt2type = sis_crt2type[i].type_no;
                        sisfb_tvplug = sis_crt2type[i].tvplug_no;
                        sisfb_crt2flags = sis_crt2type[i].flags;
@@ -289,7 +289,7 @@ sisfb_search_tvstd(const char *name)
                return;
 
        while(sis_tvtype[i].type_no != -1) {
-               if(!strnicmp(name, sis_tvtype[i].name, strlen(sis_tvtype[i].name))) {
+               if(!strncasecmp(name, sis_tvtype[i].name, strlen(sis_tvtype[i].name))) {
                        sisfb_tvstd = sis_tvtype[i].type_no;
                        break;
                }
@@ -308,12 +308,12 @@ sisfb_search_specialtiming(const char *name)
        if(name == NULL)
                return;
 
-       if(!strnicmp(name, "none", 4)) {
+       if(!strncasecmp(name, "none", 4)) {
                sisfb_specialtiming = CUT_FORCENONE;
                printk(KERN_DEBUG "sisfb: Special timing disabled\n");
        } else {
                while(mycustomttable[i].chipID != 0) {
-                       if(!strnicmp(name,mycustomttable[i].optionName,
+                       if(!strncasecmp(name,mycustomttable[i].optionName,
                           strlen(mycustomttable[i].optionName))) {
                                sisfb_specialtiming = mycustomttable[i].SpecialID;
                                found = true;
@@ -3952,68 +3952,68 @@ static int __init sisfb_setup(char *options)
 
                if(!(*this_opt)) continue;
 
-               if(!strnicmp(this_opt, "off", 3)) {
+               if(!strncasecmp(this_opt, "off", 3)) {
                        sisfb_off = 1;
-               } else if(!strnicmp(this_opt, "forcecrt2type:", 14)) {
+               } else if(!strncasecmp(this_opt, "forcecrt2type:", 14)) {
                        /* Need to check crt2 type first for fstn/dstn */
                        sisfb_search_crt2type(this_opt + 14);
-               } else if(!strnicmp(this_opt, "tvmode:",7)) {
+               } else if(!strncasecmp(this_opt, "tvmode:",7)) {
                        sisfb_search_tvstd(this_opt + 7);
-               } else if(!strnicmp(this_opt, "tvstandard:",11)) {
+               } else if(!strncasecmp(this_opt, "tvstandard:",11)) {
                        sisfb_search_tvstd(this_opt + 11);
-               } else if(!strnicmp(this_opt, "mode:", 5)) {
+               } else if(!strncasecmp(this_opt, "mode:", 5)) {
                        sisfb_search_mode(this_opt + 5, false);
-               } else if(!strnicmp(this_opt, "vesa:", 5)) {
+               } else if(!strncasecmp(this_opt, "vesa:", 5)) {
                        sisfb_search_vesamode(simple_strtoul(this_opt + 5, NULL, 0), false);
-               } else if(!strnicmp(this_opt, "rate:", 5)) {
+               } else if(!strncasecmp(this_opt, "rate:", 5)) {
                        sisfb_parm_rate = simple_strtoul(this_opt + 5, NULL, 0);
-               } else if(!strnicmp(this_opt, "forcecrt1:", 10)) {
+               } else if(!strncasecmp(this_opt, "forcecrt1:", 10)) {
                        sisfb_forcecrt1 = (int)simple_strtoul(this_opt + 10, NULL, 0);
-               } else if(!strnicmp(this_opt, "mem:",4)) {
+               } else if(!strncasecmp(this_opt, "mem:",4)) {
                        sisfb_parm_mem = simple_strtoul(this_opt + 4, NULL, 0);
-               } else if(!strnicmp(this_opt, "pdc:", 4)) {
+               } else if(!strncasecmp(this_opt, "pdc:", 4)) {
                        sisfb_pdc = simple_strtoul(this_opt + 4, NULL, 0);
-               } else if(!strnicmp(this_opt, "pdc1:", 5)) {
+               } else if(!strncasecmp(this_opt, "pdc1:", 5)) {
                        sisfb_pdca = simple_strtoul(this_opt + 5, NULL, 0);
-               } else if(!strnicmp(this_opt, "noaccel", 7)) {
+               } else if(!strncasecmp(this_opt, "noaccel", 7)) {
                        sisfb_accel = 0;
-               } else if(!strnicmp(this_opt, "accel", 5)) {
+               } else if(!strncasecmp(this_opt, "accel", 5)) {
                        sisfb_accel = -1;
-               } else if(!strnicmp(this_opt, "noypan", 6)) {
+               } else if(!strncasecmp(this_opt, "noypan", 6)) {
                        sisfb_ypan = 0;
-               } else if(!strnicmp(this_opt, "ypan", 4)) {
+               } else if(!strncasecmp(this_opt, "ypan", 4)) {
                        sisfb_ypan = -1;
-               } else if(!strnicmp(this_opt, "nomax", 5)) {
+               } else if(!strncasecmp(this_opt, "nomax", 5)) {
                        sisfb_max = 0;
-               } else if(!strnicmp(this_opt, "max", 3)) {
+               } else if(!strncasecmp(this_opt, "max", 3)) {
                        sisfb_max = -1;
-               } else if(!strnicmp(this_opt, "userom:", 7)) {
+               } else if(!strncasecmp(this_opt, "userom:", 7)) {
                        sisfb_userom = (int)simple_strtoul(this_opt + 7, NULL, 0);
-               } else if(!strnicmp(this_opt, "useoem:", 7)) {
+               } else if(!strncasecmp(this_opt, "useoem:", 7)) {
                        sisfb_useoem = (int)simple_strtoul(this_opt + 7, NULL, 0);
-               } else if(!strnicmp(this_opt, "nocrt2rate", 10)) {
+               } else if(!strncasecmp(this_opt, "nocrt2rate", 10)) {
                        sisfb_nocrt2rate = 1;
-               } else if(!strnicmp(this_opt, "scalelcd:", 9)) {
+               } else if(!strncasecmp(this_opt, "scalelcd:", 9)) {
                        unsigned long temp = 2;
                        temp = simple_strtoul(this_opt + 9, NULL, 0);
                        if((temp == 0) || (temp == 1)) {
                           sisfb_scalelcd = temp ^ 1;
                        }
-               } else if(!strnicmp(this_opt, "tvxposoffset:", 13)) {
+               } else if(!strncasecmp(this_opt, "tvxposoffset:", 13)) {
                        int temp = 0;
                        temp = (int)simple_strtol(this_opt + 13, NULL, 0);
                        if((temp >= -32) && (temp <= 32)) {
                           sisfb_tvxposoffset = temp;
                        }
-               } else if(!strnicmp(this_opt, "tvyposoffset:", 13)) {
+               } else if(!strncasecmp(this_opt, "tvyposoffset:", 13)) {
                        int temp = 0;
                        temp = (int)simple_strtol(this_opt + 13, NULL, 0);
                        if((temp >= -32) && (temp <= 32)) {
                           sisfb_tvyposoffset = temp;
                        }
-               } else if(!strnicmp(this_opt, "specialtiming:", 14)) {
+               } else if(!strncasecmp(this_opt, "specialtiming:", 14)) {
                        sisfb_search_specialtiming(this_opt + 14);
-               } else if(!strnicmp(this_opt, "lvdshl:", 7)) {
+               } else if(!strncasecmp(this_opt, "lvdshl:", 7)) {
                        int temp = 4;
                        temp = simple_strtoul(this_opt + 7, NULL, 0);
                        if((temp >= 0) && (temp <= 3)) {
@@ -4022,9 +4022,9 @@ static int __init sisfb_setup(char *options)
                } else if(this_opt[0] >= '0' && this_opt[0] <= '9') {
                        sisfb_search_mode(this_opt, true);
 #if !defined(__i386__) && !defined(__x86_64__)
-               } else if(!strnicmp(this_opt, "resetcard", 9)) {
+               } else if(!strncasecmp(this_opt, "resetcard", 9)) {
                        sisfb_resetcard = 1;
-               } else if(!strnicmp(this_opt, "videoram:", 9)) {
+               } else if(!strncasecmp(this_opt, "videoram:", 9)) {
                        sisfb_videoram = simple_strtoul(this_opt + 9, NULL, 0);
 #endif
                } else {
index c2c8eb668784f08766444b1cabb159c37c92f455..9e74e8fbe074015c7ee149104edf6826424a87a3 100644 (file)
@@ -1187,9 +1187,9 @@ static ssize_t sm501fb_crtsrc_store(struct device *dev,
        if (len < 1)
                return -EINVAL;
 
-       if (strnicmp(buf, "crt", 3) == 0)
+       if (strncasecmp(buf, "crt", 3) == 0)
                head = HEAD_CRT;
-       else if (strnicmp(buf, "panel", 5) == 0)
+       else if (strncasecmp(buf, "panel", 5) == 0)
                head = HEAD_PANEL;
        else
                return -EINVAL;
index 901014bbc8210b4ac876df7db9c8a0a4493256eb..09dc44736c1ac72160f5d9aa4d13ab1912151be9 100644 (file)
@@ -684,12 +684,13 @@ static const struct xenbus_device_id xenfb_ids[] = {
        { "" }
 };
 
-static DEFINE_XENBUS_DRIVER(xenfb, ,
+static struct xenbus_driver xenfb_driver = {
+       .ids = xenfb_ids,
        .probe = xenfb_probe,
        .remove = xenfb_remove,
        .resume = xenfb_resume,
        .otherend_changed = xenfb_backend_changed,
-);
+};
 
 static int __init xenfb_init(void)
 {
index 1d1330a78af35686ca179e7f4a9b6b848e4c842a..e3d5bf0a50218e0f3c8db39973a90e2cdeabefeb 100644 (file)
@@ -95,6 +95,16 @@ config GPIO_WATCHDOG
          If you say yes here you get support for watchdog device
          controlled through GPIO-line.
 
+config MENF21BMC_WATCHDOG
+       tristate "MEN 14F021P00 BMC Watchdog"
+       depends on MFD_MENF21BMC
+       select WATCHDOG_CORE
+       help
+         Say Y here to include support for the MEN 14F021P00 BMC Watchdog.
+
+         This driver can also be built as a module. If so the module
+         will be called menf21bmc_wdt.
+
 config WM831X_WATCHDOG
        tristate "WM831x watchdog"
        depends on MFD_WM831X
index 468c3204c3b190b7be20616d02d25ba947408581..de1701470c14fd12f2bfcc08b74fd56cedbe3a6a 100644 (file)
@@ -178,3 +178,4 @@ obj-$(CONFIG_WM831X_WATCHDOG) += wm831x_wdt.o
 obj-$(CONFIG_WM8350_WATCHDOG) += wm8350_wdt.o
 obj-$(CONFIG_MAX63XX_WATCHDOG) += max63xx_wdt.o
 obj-$(CONFIG_SOFT_WATCHDOG) += softdog.o
+obj-$(CONFIG_MENF21BMC_WATCHDOG) += menf21bmc_wdt.o
index 996b2f7d330e94ec3143e6bebe0c86f74e162943..665e0e7dfe1e2e2e03eb371bc377f58b6f9f5236 100644 (file)
@@ -301,6 +301,28 @@ static struct miscdevice wdt_miscdev = {
        .fops   =       &wdt_fops,
 };
 
+static int wdt_restart_handle(struct notifier_block *this, unsigned long mode,
+                             void *cmd)
+{
+       /*
+        * Cobalt devices have no way of rebooting themselves other
+        * than getting the watchdog to pull reset, so we restart the
+        * watchdog on reboot with no heartbeat.
+        */
+       wdt_change(WDT_ENABLE);
+
+       /* loop until the watchdog fires */
+       while (true)
+               ;
+
+       return NOTIFY_DONE;
+}
+
+static struct notifier_block wdt_restart_handler = {
+       .notifier_call = wdt_restart_handle,
+       .priority = 128,
+};
+
 /*
  *     Notifier for system down
  */
@@ -311,15 +333,6 @@ static int wdt_notify_sys(struct notifier_block *this,
        if (code == SYS_DOWN || code == SYS_HALT)
                wdt_turnoff();
 
-       if (code == SYS_RESTART) {
-               /*
-                * Cobalt devices have no way of rebooting themselves other
-                * than getting the watchdog to pull reset, so we restart the
-                * watchdog on reboot with no heartbeat
-                */
-               wdt_change(WDT_ENABLE);
-               pr_info("Watchdog timer is now enabled with no heartbeat - should reboot in ~1 second\n");
-       }
        return NOTIFY_DONE;
 }
 
@@ -338,6 +351,7 @@ static void __exit alim7101_wdt_unload(void)
        /* Deregister */
        misc_deregister(&wdt_miscdev);
        unregister_reboot_notifier(&wdt_notifier);
+       unregister_restart_handler(&wdt_restart_handler);
        pci_dev_put(alim7101_pmu);
 }
 
@@ -390,11 +404,17 @@ static int __init alim7101_wdt_init(void)
                goto err_out;
        }
 
+       rc = register_restart_handler(&wdt_restart_handler);
+       if (rc) {
+               pr_err("cannot register restart handler (err=%d)\n", rc);
+               goto err_out_reboot;
+       }
+
        rc = misc_register(&wdt_miscdev);
        if (rc) {
                pr_err("cannot register miscdev on minor=%d (err=%d)\n",
                       wdt_miscdev.minor, rc);
-               goto err_out_reboot;
+               goto err_out_restart;
        }
 
        if (nowayout)
@@ -404,6 +424,8 @@ static int __init alim7101_wdt_init(void)
                timeout, nowayout);
        return 0;
 
+err_out_restart:
+       unregister_restart_handler(&wdt_restart_handler);
 err_out_reboot:
        unregister_reboot_notifier(&wdt_notifier);
 err_out:
diff --git a/drivers/watchdog/menf21bmc_wdt.c b/drivers/watchdog/menf21bmc_wdt.c
new file mode 100644 (file)
index 0000000..2042874
--- /dev/null
@@ -0,0 +1,203 @@
+/*
+ *  MEN 14F021P00 Board Management Controller (BMC) Watchdog Driver.
+ *
+ *  Copyright (C) 2014 MEN Mikro Elektronik Nuernberg GmbH
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ */
+
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/watchdog.h>
+#include <linux/platform_device.h>
+#include <linux/i2c.h>
+
+#define DEVNAME "menf21bmc_wdt"
+
+#define BMC_CMD_WD_ON          0x11
+#define BMC_CMD_WD_OFF         0x12
+#define BMC_CMD_WD_TRIG                0x13
+#define BMC_CMD_WD_TIME                0x14
+#define BMC_CMD_WD_STATE       0x17
+#define BMC_WD_OFF_VAL         0x69
+#define BMC_CMD_RST_RSN                0x92
+
+#define BMC_WD_TIMEOUT_MIN     1       /* in sec */
+#define BMC_WD_TIMEOUT_MAX     6553    /* in sec */
+
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default="
+                               __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
+
+struct menf21bmc_wdt {
+       struct watchdog_device wdt;
+       struct i2c_client *i2c_client;
+};
+
+static int menf21bmc_wdt_set_bootstatus(struct menf21bmc_wdt *data)
+{
+       int rst_rsn;
+
+       rst_rsn = i2c_smbus_read_byte_data(data->i2c_client, BMC_CMD_RST_RSN);
+       if (rst_rsn < 0)
+               return rst_rsn;
+
+       if (rst_rsn == 0x02)
+               data->wdt.bootstatus |= WDIOF_CARDRESET;
+       else if (rst_rsn == 0x05)
+               data->wdt.bootstatus |= WDIOF_EXTERN1;
+       else if (rst_rsn == 0x06)
+               data->wdt.bootstatus |= WDIOF_EXTERN2;
+       else if (rst_rsn == 0x0A)
+               data->wdt.bootstatus |= WDIOF_POWERUNDER;
+
+       return 0;
+}
+
+static int menf21bmc_wdt_start(struct watchdog_device *wdt)
+{
+       struct menf21bmc_wdt *drv_data = watchdog_get_drvdata(wdt);
+
+       return i2c_smbus_write_byte(drv_data->i2c_client, BMC_CMD_WD_ON);
+}
+
+static int menf21bmc_wdt_stop(struct watchdog_device *wdt)
+{
+       struct menf21bmc_wdt *drv_data = watchdog_get_drvdata(wdt);
+
+       return i2c_smbus_write_byte_data(drv_data->i2c_client,
+                                        BMC_CMD_WD_OFF, BMC_WD_OFF_VAL);
+}
+
+static int
+menf21bmc_wdt_settimeout(struct watchdog_device *wdt, unsigned int timeout)
+{
+       int ret;
+       struct menf21bmc_wdt *drv_data = watchdog_get_drvdata(wdt);
+
+       /*
+        *  BMC Watchdog does have a resolution of 100ms.
+        *  Watchdog API defines the timeout in seconds, so we have to
+        *  multiply the value.
+        */
+       ret = i2c_smbus_write_word_data(drv_data->i2c_client,
+                                       BMC_CMD_WD_TIME, timeout * 10);
+       if (ret < 0)
+               return ret;
+
+       wdt->timeout = timeout;
+
+       return 0;
+}
+
+static int menf21bmc_wdt_ping(struct watchdog_device *wdt)
+{
+       struct menf21bmc_wdt *drv_data = watchdog_get_drvdata(wdt);
+
+       return i2c_smbus_write_byte(drv_data->i2c_client, BMC_CMD_WD_TRIG);
+}
+
+static const struct watchdog_info menf21bmc_wdt_info = {
+       .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING,
+       .identity = DEVNAME,
+};
+
+static const struct watchdog_ops menf21bmc_wdt_ops = {
+       .owner          = THIS_MODULE,
+       .start          = menf21bmc_wdt_start,
+       .stop           = menf21bmc_wdt_stop,
+       .ping           = menf21bmc_wdt_ping,
+       .set_timeout    = menf21bmc_wdt_settimeout,
+};
+
+static int menf21bmc_wdt_probe(struct platform_device *pdev)
+{
+       int ret, bmc_timeout;
+       struct menf21bmc_wdt *drv_data;
+       struct i2c_client *i2c_client = to_i2c_client(pdev->dev.parent);
+
+       drv_data = devm_kzalloc(&pdev->dev,
+                               sizeof(struct menf21bmc_wdt), GFP_KERNEL);
+       if (!drv_data)
+               return -ENOMEM;
+
+       drv_data->wdt.ops = &menf21bmc_wdt_ops;
+       drv_data->wdt.info = &menf21bmc_wdt_info;
+       drv_data->wdt.min_timeout = BMC_WD_TIMEOUT_MIN;
+       drv_data->wdt.max_timeout = BMC_WD_TIMEOUT_MAX;
+       drv_data->i2c_client = i2c_client;
+
+       /*
+        * Get the current wdt timeout value from the BMC because
+        * the BMC will save the value set before if the system restarts.
+        */
+       bmc_timeout = i2c_smbus_read_word_data(drv_data->i2c_client,
+                                              BMC_CMD_WD_TIME);
+       if (bmc_timeout < 0) {
+               dev_err(&pdev->dev, "failed to get current WDT timeout\n");
+               return bmc_timeout;
+       }
+
+       watchdog_init_timeout(&drv_data->wdt, bmc_timeout / 10, &pdev->dev);
+       watchdog_set_nowayout(&drv_data->wdt, nowayout);
+       watchdog_set_drvdata(&drv_data->wdt, drv_data);
+       platform_set_drvdata(pdev, drv_data);
+
+       ret = menf21bmc_wdt_set_bootstatus(drv_data);
+       if (ret < 0) {
+               dev_err(&pdev->dev, "failed to set Watchdog bootstatus\n");
+               return ret;
+       }
+
+       ret = watchdog_register_device(&drv_data->wdt);
+       if (ret) {
+               dev_err(&pdev->dev, "failed to register Watchdog device\n");
+               return ret;
+       }
+
+       dev_info(&pdev->dev, "MEN 14F021P00 BMC Watchdog device enabled\n");
+
+       return 0;
+}
+
+static int menf21bmc_wdt_remove(struct platform_device *pdev)
+{
+       struct menf21bmc_wdt *drv_data = platform_get_drvdata(pdev);
+
+       dev_warn(&pdev->dev,
+                "Unregister MEN 14F021P00 BMC Watchdog device, board may reset\n");
+
+       watchdog_unregister_device(&drv_data->wdt);
+
+       return 0;
+}
+
+static void menf21bmc_wdt_shutdown(struct platform_device *pdev)
+{
+       struct menf21bmc_wdt *drv_data = platform_get_drvdata(pdev);
+
+       i2c_smbus_write_word_data(drv_data->i2c_client,
+                                 BMC_CMD_WD_OFF, BMC_WD_OFF_VAL);
+}
+
+static struct  platform_driver menf21bmc_wdt = {
+       .driver         = {
+               .owner = THIS_MODULE,
+               .name   = DEVNAME,
+       },
+       .probe          = menf21bmc_wdt_probe,
+       .remove         = menf21bmc_wdt_remove,
+       .shutdown       = menf21bmc_wdt_shutdown,
+};
+
+module_platform_driver(menf21bmc_wdt);
+
+MODULE_DESCRIPTION("MEN 14F021P00 BMC Watchdog driver");
+MODULE_AUTHOR("Andreas Werner <andreas.werner@men.de>");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:menf21bmc_wdt");
index 4aa3a8a876fe84f109a211b560e453ccf879172b..a64405b825969c341f00f02ca752853fa8a0de13 100644 (file)
 #include <linux/module.h>
 #include <linux/err.h>
 #include <linux/kernel.h>
+#include <linux/notifier.h>
 #include <linux/platform_device.h>
+#include <linux/reboot.h>
 #include <linux/watchdog.h>
 #include <linux/moduleparam.h>
 
-#include <asm/system_misc.h>
-
 #define REG_COUNT                      0x4
 #define REG_MODE                       0x8
 #define REG_ENABLE                     0xC
@@ -29,17 +29,22 @@ struct moxart_wdt_dev {
        struct watchdog_device dev;
        void __iomem *base;
        unsigned int clock_frequency;
+       struct notifier_block restart_handler;
 };
 
-static struct moxart_wdt_dev *moxart_restart_ctx;
-
 static int heartbeat;
 
-static void moxart_wdt_restart(enum reboot_mode reboot_mode, const char *cmd)
+static int moxart_restart_handle(struct notifier_block *this,
+                                unsigned long mode, void *cmd)
 {
-       writel(1, moxart_restart_ctx->base + REG_COUNT);
-       writel(0x5ab9, moxart_restart_ctx->base + REG_MODE);
-       writel(0x03, moxart_restart_ctx->base + REG_ENABLE);
+       struct moxart_wdt_dev *moxart_wdt = container_of(this,
+                                                        struct moxart_wdt_dev,
+                                                        restart_handler);
+       writel(1, moxart_wdt->base + REG_COUNT);
+       writel(0x5ab9, moxart_wdt->base + REG_MODE);
+       writel(0x03, moxart_wdt->base + REG_ENABLE);
+
+       return NOTIFY_DONE;
 }
 
 static int moxart_wdt_stop(struct watchdog_device *wdt_dev)
@@ -136,8 +141,12 @@ static int moxart_wdt_probe(struct platform_device *pdev)
        if (err)
                return err;
 
-       moxart_restart_ctx = moxart_wdt;
-       arm_pm_restart = moxart_wdt_restart;
+       moxart_wdt->restart_handler.notifier_call = moxart_restart_handle;
+       moxart_wdt->restart_handler.priority = 128;
+       err = register_restart_handler(&moxart_wdt->restart_handler);
+       if (err)
+               dev_err(dev, "cannot register restart notifier (err=%d)\n",
+                       err);
 
        dev_dbg(dev, "Watchdog enabled (heartbeat=%d sec, nowayout=%d)\n",
                moxart_wdt->dev.timeout, nowayout);
@@ -149,9 +158,8 @@ static int moxart_wdt_remove(struct platform_device *pdev)
 {
        struct moxart_wdt_dev *moxart_wdt = platform_get_drvdata(pdev);
 
-       arm_pm_restart = NULL;
+       unregister_restart_handler(&moxart_wdt->restart_handler);
        moxart_wdt_stop(&moxart_wdt->dev);
-       watchdog_unregister_device(&moxart_wdt->dev);
 
        return 0;
 }
index 60deb9d304c0dfcea5bb8b5b8111d164cffcf791..480bb557f353cbdfc1923769b5ee0441750e8ca8 100644 (file)
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/moduleparam.h>
+#include <linux/notifier.h>
 #include <linux/of.h>
 #include <linux/platform_device.h>
 #include <linux/reboot.h>
 #include <linux/types.h>
 #include <linux/watchdog.h>
 
-#include <asm/system_misc.h>
-
 #define WDT_MAX_TIMEOUT         16
 #define WDT_MIN_TIMEOUT         1
 #define WDT_MODE_TIMEOUT(n)     ((n) << 3)
@@ -50,6 +49,7 @@ static unsigned int timeout = WDT_MAX_TIMEOUT;
 struct sunxi_wdt_dev {
        struct watchdog_device wdt_dev;
        void __iomem *wdt_base;
+       struct notifier_block restart_handler;
 };
 
 /*
@@ -74,24 +74,29 @@ static const int wdt_timeout_map[] = {
        [16] = 0xB, /* 16s */
 };
 
-static void __iomem *reboot_wdt_base;
 
-static void sun4i_wdt_restart(enum reboot_mode mode, const char *cmd)
+static int sunxi_restart_handle(struct notifier_block *this, unsigned long mode,
+                               void *cmd)
 {
+       struct sunxi_wdt_dev *sunxi_wdt = container_of(this,
+                                                      struct sunxi_wdt_dev,
+                                                      restart_handler);
+       void __iomem *wdt_base = sunxi_wdt->wdt_base;
+
        /* Enable timer and set reset bit in the watchdog */
-       writel(WDT_MODE_EN | WDT_MODE_RST_EN, reboot_wdt_base + WDT_MODE);
+       writel(WDT_MODE_EN | WDT_MODE_RST_EN, wdt_base + WDT_MODE);
 
        /*
         * Restart the watchdog. The default (and lowest) interval
         * value for the watchdog is 0.5s.
         */
-       writel(WDT_CTRL_RELOAD, reboot_wdt_base + WDT_CTRL);
+       writel(WDT_CTRL_RELOAD, wdt_base + WDT_CTRL);
 
        while (1) {
                mdelay(5);
-               writel(WDT_MODE_EN | WDT_MODE_RST_EN,
-                      reboot_wdt_base + WDT_MODE);
+               writel(WDT_MODE_EN | WDT_MODE_RST_EN, wdt_base + WDT_MODE);
        }
+       return NOTIFY_DONE;
 }
 
 static int sunxi_wdt_ping(struct watchdog_device *wdt_dev)
@@ -205,8 +210,12 @@ static int sunxi_wdt_probe(struct platform_device *pdev)
        if (unlikely(err))
                return err;
 
-       reboot_wdt_base = sunxi_wdt->wdt_base;
-       arm_pm_restart = sun4i_wdt_restart;
+       sunxi_wdt->restart_handler.notifier_call = sunxi_restart_handle;
+       sunxi_wdt->restart_handler.priority = 128;
+       err = register_restart_handler(&sunxi_wdt->restart_handler);
+       if (err)
+               dev_err(&pdev->dev,
+                       "cannot register restart handler (err=%d)\n", err);
 
        dev_info(&pdev->dev, "Watchdog enabled (timeout=%d sec, nowayout=%d)",
                        sunxi_wdt->wdt_dev.timeout, nowayout);
@@ -218,7 +227,7 @@ static int sunxi_wdt_remove(struct platform_device *pdev)
 {
        struct sunxi_wdt_dev *sunxi_wdt = platform_get_drvdata(pdev);
 
-       arm_pm_restart = NULL;
+       unregister_restart_handler(&sunxi_wdt->restart_handler);
 
        watchdog_unregister_device(&sunxi_wdt->wdt_dev);
        watchdog_set_drvdata(&sunxi_wdt->wdt_dev, NULL);
index 8bc01838daf9dd8ac7fa53524e13c2a252cec6fe..b812462083fcaf8d32c215327d28b7c4b7e6e4da 100644 (file)
@@ -172,6 +172,15 @@ config XEN_PCIDEV_BACKEND
 
          If in doubt, say m.
 
+config XEN_SCSI_BACKEND
+       tristate "XEN SCSI backend driver"
+       depends on XEN && XEN_BACKEND && TARGET_CORE
+       help
+         The SCSI backend driver allows the kernel to export its SCSI Devices
+         to other guests via a high-performance shared-memory interface.
+         Only needed for systems running as XEN driver domains (e.g. Dom0) and
+         if guests need generic access to SCSI devices.
+
 config XEN_PRIVCMD
        tristate
        depends on XEN
index 84044b554e33bd614c59ca6ce75d92684a9b2313..2140398a2a8c6b5f521c6250bb56a56ad41c9df7 100644 (file)
@@ -36,6 +36,7 @@ obj-$(CONFIG_XEN_ACPI_HOTPLUG_MEMORY) += xen-acpi-memhotplug.o
 obj-$(CONFIG_XEN_ACPI_HOTPLUG_CPU)     += xen-acpi-cpuhotplug.o
 obj-$(CONFIG_XEN_ACPI_PROCESSOR)       += xen-acpi-processor.o
 obj-$(CONFIG_XEN_EFI)                  += efi.o
+obj-$(CONFIG_XEN_SCSI_BACKEND)         += xen-scsiback.o
 xen-evtchn-y                           := evtchn.o
 xen-gntdev-y                           := gntdev.o
 xen-gntalloc-y                         := gntalloc.o
index 31f618a49661cac0a02e5d384c784c05dbb1bf31..1f850c97482f23e8b51a67e2d36a37f39fd21546 100644 (file)
@@ -27,6 +27,8 @@
 #include <xen/interface/platform.h>
 #include <xen/xen.h>
 
+#include <asm/page.h>
+
 #include <asm/xen/hypercall.h>
 
 #define INIT_EFI_OP(name) \
index 5b5c5ff273fdb7b09def11dcee21e4043640ce77..b4bca2d4a7e53c7675b25d632b560e1369b19020 100644 (file)
@@ -900,8 +900,8 @@ static int bind_ipi_to_irq(unsigned int ipi, unsigned int cpu)
        return irq;
 }
 
-static int bind_interdomain_evtchn_to_irq(unsigned int remote_domain,
-                                         unsigned int remote_port)
+int bind_interdomain_evtchn_to_irq(unsigned int remote_domain,
+                                  unsigned int remote_port)
 {
        struct evtchn_bind_interdomain bind_interdomain;
        int err;
@@ -914,6 +914,7 @@ static int bind_interdomain_evtchn_to_irq(unsigned int remote_domain,
 
        return err ? : bind_evtchn_to_irq(bind_interdomain.local_port);
 }
+EXPORT_SYMBOL_GPL(bind_interdomain_evtchn_to_irq);
 
 static int find_virq(unsigned int virq, unsigned int cpu)
 {
index c254ae036f18fe5f7ceaee5589de7f3501d80f7e..7786291ba229d93190516013863a933cc9eeeb86 100644 (file)
@@ -592,7 +592,7 @@ static int grow_gnttab_list(unsigned int more_frames)
        return 0;
 
 grow_nomem:
-       for ( ; i >= nr_glist_frames; i--)
+       while (i-- > nr_glist_frames)
                free_page((unsigned long) gnttab_list[i]);
        return -ENOMEM;
 }
index c214daab482910b203b436520d876a618ffcca9b..ad8d30c088fe4b37d4c62b5f863e2561e4724509 100644 (file)
@@ -719,11 +719,13 @@ static const struct xenbus_device_id xen_pcibk_ids[] = {
        {""},
 };
 
-static DEFINE_XENBUS_DRIVER(xen_pcibk, DRV_NAME,
+static struct xenbus_driver xen_pcibk_driver = {
+       .name                   = DRV_NAME,
+       .ids                    = xen_pcibk_ids,
        .probe                  = xen_pcibk_xenbus_probe,
        .remove                 = xen_pcibk_xenbus_remove,
        .otherend_changed       = xen_pcibk_frontend_changed,
-);
+};
 
 const struct xen_pcibk_backend *__read_mostly xen_pcibk_backend;
 
diff --git a/drivers/xen/xen-scsiback.c b/drivers/xen/xen-scsiback.c
new file mode 100644 (file)
index 0000000..3e32146
--- /dev/null
@@ -0,0 +1,2126 @@
+/*
+ * Xen SCSI backend driver
+ *
+ * Copyright (c) 2008, FUJITSU Limited
+ *
+ * Based on the blkback driver code.
+ * Adaption to kernel taget core infrastructure taken from vhost/scsi.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; or, when distributed
+ * separately from the Linux kernel or incorporated into other
+ * software packages, subject to the following license:
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this source file (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy, modify,
+ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <stdarg.h>
+
+#include <linux/module.h>
+#include <linux/utsname.h>
+#include <linux/interrupt.h>
+#include <linux/slab.h>
+#include <linux/wait.h>
+#include <linux/sched.h>
+#include <linux/list.h>
+#include <linux/gfp.h>
+#include <linux/delay.h>
+#include <linux/spinlock.h>
+#include <linux/configfs.h>
+
+#include <generated/utsrelease.h>
+
+#include <scsi/scsi_dbg.h>
+#include <scsi/scsi_eh.h>
+#include <scsi/scsi_tcq.h>
+
+#include <target/target_core_base.h>
+#include <target/target_core_fabric.h>
+#include <target/target_core_configfs.h>
+#include <target/target_core_fabric_configfs.h>
+
+#include <asm/hypervisor.h>
+
+#include <xen/xen.h>
+#include <xen/balloon.h>
+#include <xen/events.h>
+#include <xen/xenbus.h>
+#include <xen/grant_table.h>
+#include <xen/page.h>
+
+#include <xen/interface/grant_table.h>
+#include <xen/interface/io/vscsiif.h>
+
+#define DPRINTK(_f, _a...)                     \
+       pr_debug("(file=%s, line=%d) " _f, __FILE__ , __LINE__ , ## _a)
+
+#define VSCSI_VERSION  "v0.1"
+#define VSCSI_NAMELEN  32
+
+struct ids_tuple {
+       unsigned int hst;               /* host    */
+       unsigned int chn;               /* channel */
+       unsigned int tgt;               /* target  */
+       unsigned int lun;               /* LUN     */
+};
+
+struct v2p_entry {
+       struct ids_tuple v;             /* translate from */
+       struct scsiback_tpg *tpg;       /* translate to   */
+       unsigned int lun;
+       struct kref kref;
+       struct list_head l;
+};
+
+struct vscsibk_info {
+       struct xenbus_device *dev;
+
+       domid_t domid;
+       unsigned int irq;
+
+       struct vscsiif_back_ring ring;
+       int ring_error;
+
+       spinlock_t ring_lock;
+       atomic_t nr_unreplied_reqs;
+
+       spinlock_t v2p_lock;
+       struct list_head v2p_entry_lists;
+
+       wait_queue_head_t waiting_to_free;
+};
+
+/* theoretical maximum of grants for one request */
+#define VSCSI_MAX_GRANTS       (SG_ALL + VSCSIIF_SG_TABLESIZE)
+
+/*
+ * VSCSI_GRANT_BATCH is the maximum number of grants to be processed in one
+ * call to map/unmap grants. Don't choose it too large, as there are arrays
+ * with VSCSI_GRANT_BATCH elements allocated on the stack.
+ */
+#define VSCSI_GRANT_BATCH      16
+
+struct vscsibk_pend {
+       uint16_t rqid;
+
+       uint8_t cmnd[VSCSIIF_MAX_COMMAND_SIZE];
+       uint8_t cmd_len;
+
+       uint8_t sc_data_direction;
+       uint16_t n_sg;          /* real length of SG list */
+       uint16_t n_grants;      /* SG pages and potentially SG list */
+       uint32_t data_len;
+       uint32_t result;
+
+       struct vscsibk_info *info;
+       struct v2p_entry *v2p;
+       struct scatterlist *sgl;
+
+       uint8_t sense_buffer[VSCSIIF_SENSE_BUFFERSIZE];
+
+       grant_handle_t grant_handles[VSCSI_MAX_GRANTS];
+       struct page *pages[VSCSI_MAX_GRANTS];
+
+       struct se_cmd se_cmd;
+};
+
+struct scsiback_tmr {
+       atomic_t tmr_complete;
+       wait_queue_head_t tmr_wait;
+};
+
+struct scsiback_nexus {
+       /* Pointer to TCM session for I_T Nexus */
+       struct se_session *tvn_se_sess;
+};
+
+struct scsiback_tport {
+       /* SCSI protocol the tport is providing */
+       u8 tport_proto_id;
+       /* Binary World Wide unique Port Name for pvscsi Target port */
+       u64 tport_wwpn;
+       /* ASCII formatted WWPN for pvscsi Target port */
+       char tport_name[VSCSI_NAMELEN];
+       /* Returned by scsiback_make_tport() */
+       struct se_wwn tport_wwn;
+};
+
+struct scsiback_tpg {
+       /* scsiback port target portal group tag for TCM */
+       u16 tport_tpgt;
+       /* track number of TPG Port/Lun Links wrt explicit I_T Nexus shutdown */
+       int tv_tpg_port_count;
+       /* xen-pvscsi references to tpg_nexus, protected by tv_tpg_mutex */
+       int tv_tpg_fe_count;
+       /* list for scsiback_list */
+       struct list_head tv_tpg_list;
+       /* Used to protect access for tpg_nexus */
+       struct mutex tv_tpg_mutex;
+       /* Pointer to the TCM pvscsi I_T Nexus for this TPG endpoint */
+       struct scsiback_nexus *tpg_nexus;
+       /* Pointer back to scsiback_tport */
+       struct scsiback_tport *tport;
+       /* Returned by scsiback_make_tpg() */
+       struct se_portal_group se_tpg;
+       /* alias used in xenstore */
+       char param_alias[VSCSI_NAMELEN];
+       /* list of info structures related to this target portal group */
+       struct list_head info_list;
+};
+
+#define SCSIBACK_INVALID_HANDLE (~0)
+
+static bool log_print_stat;
+module_param(log_print_stat, bool, 0644);
+
+static int scsiback_max_buffer_pages = 1024;
+module_param_named(max_buffer_pages, scsiback_max_buffer_pages, int, 0644);
+MODULE_PARM_DESC(max_buffer_pages,
+"Maximum number of free pages to keep in backend buffer");
+
+static struct kmem_cache *scsiback_cachep;
+static DEFINE_SPINLOCK(free_pages_lock);
+static int free_pages_num;
+static LIST_HEAD(scsiback_free_pages);
+
+/* Global spinlock to protect scsiback TPG list */
+static DEFINE_MUTEX(scsiback_mutex);
+static LIST_HEAD(scsiback_list);
+
+/* Local pointer to allocated TCM configfs fabric module */
+static struct target_fabric_configfs *scsiback_fabric_configfs;
+
+static void scsiback_get(struct vscsibk_info *info)
+{
+       atomic_inc(&info->nr_unreplied_reqs);
+}
+
+static void scsiback_put(struct vscsibk_info *info)
+{
+       if (atomic_dec_and_test(&info->nr_unreplied_reqs))
+               wake_up(&info->waiting_to_free);
+}
+
+static void put_free_pages(struct page **page, int num)
+{
+       unsigned long flags;
+       int i = free_pages_num + num, n = num;
+
+       if (num == 0)
+               return;
+       if (i > scsiback_max_buffer_pages) {
+               n = min(num, i - scsiback_max_buffer_pages);
+               free_xenballooned_pages(n, page + num - n);
+               n = num - n;
+       }
+       spin_lock_irqsave(&free_pages_lock, flags);
+       for (i = 0; i < n; i++)
+               list_add(&page[i]->lru, &scsiback_free_pages);
+       free_pages_num += n;
+       spin_unlock_irqrestore(&free_pages_lock, flags);
+}
+
+static int get_free_page(struct page **page)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&free_pages_lock, flags);
+       if (list_empty(&scsiback_free_pages)) {
+               spin_unlock_irqrestore(&free_pages_lock, flags);
+               return alloc_xenballooned_pages(1, page, false);
+       }
+       page[0] = list_first_entry(&scsiback_free_pages, struct page, lru);
+       list_del(&page[0]->lru);
+       free_pages_num--;
+       spin_unlock_irqrestore(&free_pages_lock, flags);
+       return 0;
+}
+
+static unsigned long vaddr_page(struct page *page)
+{
+       unsigned long pfn = page_to_pfn(page);
+
+       return (unsigned long)pfn_to_kaddr(pfn);
+}
+
+static unsigned long vaddr(struct vscsibk_pend *req, int seg)
+{
+       return vaddr_page(req->pages[seg]);
+}
+
+static void scsiback_print_status(char *sense_buffer, int errors,
+                                       struct vscsibk_pend *pending_req)
+{
+       struct scsiback_tpg *tpg = pending_req->v2p->tpg;
+
+       pr_err("xen-pvscsi[%s:%d] cmnd[0]=%02x -> st=%02x msg=%02x host=%02x drv=%02x\n",
+              tpg->tport->tport_name, pending_req->v2p->lun,
+              pending_req->cmnd[0], status_byte(errors), msg_byte(errors),
+              host_byte(errors), driver_byte(errors));
+
+       if (CHECK_CONDITION & status_byte(errors))
+               __scsi_print_sense("xen-pvscsi", sense_buffer,
+                                  SCSI_SENSE_BUFFERSIZE);
+}
+
+static void scsiback_fast_flush_area(struct vscsibk_pend *req)
+{
+       struct gnttab_unmap_grant_ref unmap[VSCSI_GRANT_BATCH];
+       struct page *pages[VSCSI_GRANT_BATCH];
+       unsigned int i, invcount = 0;
+       grant_handle_t handle;
+       int err;
+
+       kfree(req->sgl);
+       req->sgl = NULL;
+       req->n_sg = 0;
+
+       if (!req->n_grants)
+               return;
+
+       for (i = 0; i < req->n_grants; i++) {
+               handle = req->grant_handles[i];
+               if (handle == SCSIBACK_INVALID_HANDLE)
+                       continue;
+               gnttab_set_unmap_op(&unmap[invcount], vaddr(req, i),
+                                   GNTMAP_host_map, handle);
+               req->grant_handles[i] = SCSIBACK_INVALID_HANDLE;
+               pages[invcount] = req->pages[i];
+               put_page(pages[invcount]);
+               invcount++;
+               if (invcount < VSCSI_GRANT_BATCH)
+                       continue;
+               err = gnttab_unmap_refs(unmap, NULL, pages, invcount);
+               BUG_ON(err);
+               invcount = 0;
+       }
+
+       if (invcount) {
+               err = gnttab_unmap_refs(unmap, NULL, pages, invcount);
+               BUG_ON(err);
+       }
+
+       put_free_pages(req->pages, req->n_grants);
+       req->n_grants = 0;
+}
+
+static void scsiback_free_translation_entry(struct kref *kref)
+{
+       struct v2p_entry *entry = container_of(kref, struct v2p_entry, kref);
+       struct scsiback_tpg *tpg = entry->tpg;
+
+       mutex_lock(&tpg->tv_tpg_mutex);
+       tpg->tv_tpg_fe_count--;
+       mutex_unlock(&tpg->tv_tpg_mutex);
+
+       kfree(entry);
+}
+
+static void scsiback_do_resp_with_sense(char *sense_buffer, int32_t result,
+                       uint32_t resid, struct vscsibk_pend *pending_req)
+{
+       struct vscsiif_response *ring_res;
+       struct vscsibk_info *info = pending_req->info;
+       int notify;
+       struct scsi_sense_hdr sshdr;
+       unsigned long flags;
+       unsigned len;
+
+       spin_lock_irqsave(&info->ring_lock, flags);
+
+       ring_res = RING_GET_RESPONSE(&info->ring, info->ring.rsp_prod_pvt);
+       info->ring.rsp_prod_pvt++;
+
+       ring_res->rslt   = result;
+       ring_res->rqid   = pending_req->rqid;
+
+       if (sense_buffer != NULL &&
+           scsi_normalize_sense(sense_buffer, VSCSIIF_SENSE_BUFFERSIZE,
+                                &sshdr)) {
+               len = min_t(unsigned, 8 + sense_buffer[7],
+                           VSCSIIF_SENSE_BUFFERSIZE);
+               memcpy(ring_res->sense_buffer, sense_buffer, len);
+               ring_res->sense_len = len;
+       } else {
+               ring_res->sense_len = 0;
+       }
+
+       ring_res->residual_len = resid;
+
+       RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(&info->ring, notify);
+       spin_unlock_irqrestore(&info->ring_lock, flags);
+
+       if (notify)
+               notify_remote_via_irq(info->irq);
+
+       if (pending_req->v2p)
+               kref_put(&pending_req->v2p->kref,
+                        scsiback_free_translation_entry);
+}
+
+static void scsiback_cmd_done(struct vscsibk_pend *pending_req)
+{
+       struct vscsibk_info *info = pending_req->info;
+       unsigned char *sense_buffer;
+       unsigned int resid;
+       int errors;
+
+       sense_buffer = pending_req->sense_buffer;
+       resid        = pending_req->se_cmd.residual_count;
+       errors       = pending_req->result;
+
+       if (errors && log_print_stat)
+               scsiback_print_status(sense_buffer, errors, pending_req);
+
+       scsiback_fast_flush_area(pending_req);
+       scsiback_do_resp_with_sense(sense_buffer, errors, resid, pending_req);
+       scsiback_put(info);
+}
+
+static void scsiback_cmd_exec(struct vscsibk_pend *pending_req)
+{
+       struct se_cmd *se_cmd = &pending_req->se_cmd;
+       struct se_session *sess = pending_req->v2p->tpg->tpg_nexus->tvn_se_sess;
+       int rc;
+
+       memset(pending_req->sense_buffer, 0, VSCSIIF_SENSE_BUFFERSIZE);
+
+       memset(se_cmd, 0, sizeof(*se_cmd));
+
+       scsiback_get(pending_req->info);
+       rc = target_submit_cmd_map_sgls(se_cmd, sess, pending_req->cmnd,
+                       pending_req->sense_buffer, pending_req->v2p->lun,
+                       pending_req->data_len, 0,
+                       pending_req->sc_data_direction, 0,
+                       pending_req->sgl, pending_req->n_sg,
+                       NULL, 0, NULL, 0);
+       if (rc < 0) {
+               transport_send_check_condition_and_sense(se_cmd,
+                               TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE, 0);
+               transport_generic_free_cmd(se_cmd, 0);
+       }
+}
+
+static int scsiback_gnttab_data_map_batch(struct gnttab_map_grant_ref *map,
+       struct page **pg, grant_handle_t *grant, int cnt)
+{
+       int err, i;
+
+       if (!cnt)
+               return 0;
+
+       err = gnttab_map_refs(map, NULL, pg, cnt);
+       BUG_ON(err);
+       for (i = 0; i < cnt; i++) {
+               if (unlikely(map[i].status != GNTST_okay)) {
+                       pr_err("xen-pvscsi: invalid buffer -- could not remap it\n");
+                       map[i].handle = SCSIBACK_INVALID_HANDLE;
+                       err = -ENOMEM;
+               } else {
+                       get_page(pg[i]);
+               }
+               grant[i] = map[i].handle;
+       }
+       return err;
+}
+
+static int scsiback_gnttab_data_map_list(struct vscsibk_pend *pending_req,
+                       struct scsiif_request_segment *seg, struct page **pg,
+                       grant_handle_t *grant, int cnt, u32 flags)
+{
+       int mapcount = 0, i, err = 0;
+       struct gnttab_map_grant_ref map[VSCSI_GRANT_BATCH];
+       struct vscsibk_info *info = pending_req->info;
+
+       for (i = 0; i < cnt; i++) {
+               if (get_free_page(pg + mapcount)) {
+                       put_free_pages(pg, mapcount);
+                       pr_err("xen-pvscsi: no grant page\n");
+                       return -ENOMEM;
+               }
+               gnttab_set_map_op(&map[mapcount], vaddr_page(pg[mapcount]),
+                                 flags, seg[i].gref, info->domid);
+               mapcount++;
+               if (mapcount < VSCSI_GRANT_BATCH)
+                       continue;
+               err = scsiback_gnttab_data_map_batch(map, pg, grant, mapcount);
+               pg += mapcount;
+               grant += mapcount;
+               pending_req->n_grants += mapcount;
+               if (err)
+                       return err;
+               mapcount = 0;
+       }
+       err = scsiback_gnttab_data_map_batch(map, pg, grant, mapcount);
+       pending_req->n_grants += mapcount;
+       return err;
+}
+
+static int scsiback_gnttab_data_map(struct vscsiif_request *ring_req,
+                                       struct vscsibk_pend *pending_req)
+{
+       u32 flags;
+       int i, err, n_segs, i_seg = 0;
+       struct page **pg;
+       struct scsiif_request_segment *seg;
+       unsigned long end_seg = 0;
+       unsigned int nr_segments = (unsigned int)ring_req->nr_segments;
+       unsigned int nr_sgl = 0;
+       struct scatterlist *sg;
+       grant_handle_t *grant;
+
+       pending_req->n_sg = 0;
+       pending_req->n_grants = 0;
+       pending_req->data_len = 0;
+
+       nr_segments &= ~VSCSIIF_SG_GRANT;
+       if (!nr_segments)
+               return 0;
+
+       if (nr_segments > VSCSIIF_SG_TABLESIZE) {
+               DPRINTK("xen-pvscsi: invalid parameter nr_seg = %d\n",
+                       ring_req->nr_segments);
+               return -EINVAL;
+       }
+
+       if (ring_req->nr_segments & VSCSIIF_SG_GRANT) {
+               err = scsiback_gnttab_data_map_list(pending_req, ring_req->seg,
+                       pending_req->pages, pending_req->grant_handles,
+                       nr_segments, GNTMAP_host_map | GNTMAP_readonly);
+               if (err)
+                       return err;
+               nr_sgl = nr_segments;
+               nr_segments = 0;
+               for (i = 0; i < nr_sgl; i++) {
+                       n_segs = ring_req->seg[i].length /
+                                sizeof(struct scsiif_request_segment);
+                       if ((unsigned)ring_req->seg[i].offset +
+                           (unsigned)ring_req->seg[i].length > PAGE_SIZE ||
+                           n_segs * sizeof(struct scsiif_request_segment) !=
+                           ring_req->seg[i].length)
+                               return -EINVAL;
+                       nr_segments += n_segs;
+               }
+               if (nr_segments > SG_ALL) {
+                       DPRINTK("xen-pvscsi: invalid nr_seg = %d\n",
+                               nr_segments);
+                       return -EINVAL;
+               }
+       }
+
+       /* free of (sgl) in fast_flush_area()*/
+       pending_req->sgl = kmalloc_array(nr_segments,
+                                       sizeof(struct scatterlist), GFP_KERNEL);
+       if (!pending_req->sgl)
+               return -ENOMEM;
+
+       sg_init_table(pending_req->sgl, nr_segments);
+       pending_req->n_sg = nr_segments;
+
+       flags = GNTMAP_host_map;
+       if (pending_req->sc_data_direction == DMA_TO_DEVICE)
+               flags |= GNTMAP_readonly;
+
+       pg = pending_req->pages + nr_sgl;
+       grant = pending_req->grant_handles + nr_sgl;
+       if (!nr_sgl) {
+               seg = ring_req->seg;
+               err = scsiback_gnttab_data_map_list(pending_req, seg,
+                       pg, grant, nr_segments, flags);
+               if (err)
+                       return err;
+       } else {
+               for (i = 0; i < nr_sgl; i++) {
+                       seg = (struct scsiif_request_segment *)(
+                             vaddr(pending_req, i) + ring_req->seg[i].offset);
+                       n_segs = ring_req->seg[i].length /
+                                sizeof(struct scsiif_request_segment);
+                       err = scsiback_gnttab_data_map_list(pending_req, seg,
+                               pg, grant, n_segs, flags);
+                       if (err)
+                               return err;
+                       pg += n_segs;
+                       grant += n_segs;
+               }
+               end_seg = vaddr(pending_req, 0) + ring_req->seg[0].offset;
+               seg = (struct scsiif_request_segment *)end_seg;
+               end_seg += ring_req->seg[0].length;
+               pg = pending_req->pages + nr_sgl;
+       }
+
+       for_each_sg(pending_req->sgl, sg, nr_segments, i) {
+               sg_set_page(sg, pg[i], seg->length, seg->offset);
+               pending_req->data_len += seg->length;
+               seg++;
+               if (nr_sgl && (unsigned long)seg >= end_seg) {
+                       i_seg++;
+                       end_seg = vaddr(pending_req, i_seg) +
+                                 ring_req->seg[i_seg].offset;
+                       seg = (struct scsiif_request_segment *)end_seg;
+                       end_seg += ring_req->seg[i_seg].length;
+               }
+               if (sg->offset >= PAGE_SIZE ||
+                   sg->length > PAGE_SIZE ||
+                   sg->offset + sg->length > PAGE_SIZE)
+                       return -EINVAL;
+       }
+
+       return 0;
+}
+
+static void scsiback_disconnect(struct vscsibk_info *info)
+{
+       wait_event(info->waiting_to_free,
+               atomic_read(&info->nr_unreplied_reqs) == 0);
+
+       unbind_from_irqhandler(info->irq, info);
+       info->irq = 0;
+       xenbus_unmap_ring_vfree(info->dev, info->ring.sring);
+}
+
+static void scsiback_device_action(struct vscsibk_pend *pending_req,
+       enum tcm_tmreq_table act, int tag)
+{
+       int rc, err = FAILED;
+       struct scsiback_tpg *tpg = pending_req->v2p->tpg;
+       struct se_cmd *se_cmd = &pending_req->se_cmd;
+       struct scsiback_tmr *tmr;
+
+       tmr = kzalloc(sizeof(struct scsiback_tmr), GFP_KERNEL);
+       if (!tmr)
+               goto out;
+
+       init_waitqueue_head(&tmr->tmr_wait);
+
+       transport_init_se_cmd(se_cmd, tpg->se_tpg.se_tpg_tfo,
+               tpg->tpg_nexus->tvn_se_sess, 0, DMA_NONE, MSG_SIMPLE_TAG,
+               &pending_req->sense_buffer[0]);
+
+       rc = core_tmr_alloc_req(se_cmd, tmr, act, GFP_KERNEL);
+       if (rc < 0)
+               goto out;
+
+       se_cmd->se_tmr_req->ref_task_tag = tag;
+
+       if (transport_lookup_tmr_lun(se_cmd, pending_req->v2p->lun) < 0)
+               goto out;
+
+       transport_generic_handle_tmr(se_cmd);
+       wait_event(tmr->tmr_wait, atomic_read(&tmr->tmr_complete));
+
+       err = (se_cmd->se_tmr_req->response == TMR_FUNCTION_COMPLETE) ?
+               SUCCESS : FAILED;
+
+out:
+       if (tmr) {
+               transport_generic_free_cmd(&pending_req->se_cmd, 1);
+               kfree(tmr);
+       }
+
+       scsiback_do_resp_with_sense(NULL, err, 0, pending_req);
+
+       kmem_cache_free(scsiback_cachep, pending_req);
+}
+
+/*
+  Perform virtual to physical translation
+*/
+static struct v2p_entry *scsiback_do_translation(struct vscsibk_info *info,
+                       struct ids_tuple *v)
+{
+       struct v2p_entry *entry;
+       struct list_head *head = &(info->v2p_entry_lists);
+       unsigned long flags;
+
+       spin_lock_irqsave(&info->v2p_lock, flags);
+       list_for_each_entry(entry, head, l) {
+               if ((entry->v.chn == v->chn) &&
+                   (entry->v.tgt == v->tgt) &&
+                   (entry->v.lun == v->lun)) {
+                       kref_get(&entry->kref);
+                       goto out;
+               }
+       }
+       entry = NULL;
+
+out:
+       spin_unlock_irqrestore(&info->v2p_lock, flags);
+       return entry;
+}
+
+static int prepare_pending_reqs(struct vscsibk_info *info,
+                               struct vscsiif_request *ring_req,
+                               struct vscsibk_pend *pending_req)
+{
+       struct v2p_entry *v2p;
+       struct ids_tuple vir;
+
+       pending_req->rqid       = ring_req->rqid;
+       pending_req->info       = info;
+
+       vir.chn = ring_req->channel;
+       vir.tgt = ring_req->id;
+       vir.lun = ring_req->lun;
+
+       v2p = scsiback_do_translation(info, &vir);
+       if (!v2p) {
+               pending_req->v2p = NULL;
+               DPRINTK("xen-pvscsi: doesn't exist.\n");
+               return -ENODEV;
+       }
+       pending_req->v2p = v2p;
+
+       /* request range check from frontend */
+       pending_req->sc_data_direction = ring_req->sc_data_direction;
+       if ((pending_req->sc_data_direction != DMA_BIDIRECTIONAL) &&
+               (pending_req->sc_data_direction != DMA_TO_DEVICE) &&
+               (pending_req->sc_data_direction != DMA_FROM_DEVICE) &&
+               (pending_req->sc_data_direction != DMA_NONE)) {
+               DPRINTK("xen-pvscsi: invalid parameter data_dir = %d\n",
+                       pending_req->sc_data_direction);
+               return -EINVAL;
+       }
+
+       pending_req->cmd_len = ring_req->cmd_len;
+       if (pending_req->cmd_len > VSCSIIF_MAX_COMMAND_SIZE) {
+               DPRINTK("xen-pvscsi: invalid parameter cmd_len = %d\n",
+                       pending_req->cmd_len);
+               return -EINVAL;
+       }
+       memcpy(pending_req->cmnd, ring_req->cmnd, pending_req->cmd_len);
+
+       return 0;
+}
+
+static int scsiback_do_cmd_fn(struct vscsibk_info *info)
+{
+       struct vscsiif_back_ring *ring = &info->ring;
+       struct vscsiif_request *ring_req;
+       struct vscsibk_pend *pending_req;
+       RING_IDX rc, rp;
+       int err, more_to_do;
+       uint32_t result;
+       uint8_t act;
+
+       rc = ring->req_cons;
+       rp = ring->sring->req_prod;
+       rmb();  /* guest system is accessing ring, too */
+
+       if (RING_REQUEST_PROD_OVERFLOW(ring, rp)) {
+               rc = ring->rsp_prod_pvt;
+               pr_warn("xen-pvscsi: Dom%d provided bogus ring requests (%#x - %#x = %u). Halting ring processing\n",
+                          info->domid, rp, rc, rp - rc);
+               info->ring_error = 1;
+               return 0;
+       }
+
+       while ((rc != rp)) {
+               if (RING_REQUEST_CONS_OVERFLOW(ring, rc))
+                       break;
+               pending_req = kmem_cache_alloc(scsiback_cachep, GFP_KERNEL);
+               if (!pending_req)
+                       return 1;
+
+               ring_req = RING_GET_REQUEST(ring, rc);
+               ring->req_cons = ++rc;
+
+               act = ring_req->act;
+               err = prepare_pending_reqs(info, ring_req, pending_req);
+               if (err) {
+                       switch (err) {
+                       case -ENODEV:
+                               result = DID_NO_CONNECT;
+                               break;
+                       default:
+                               result = DRIVER_ERROR;
+                               break;
+                       }
+                       scsiback_do_resp_with_sense(NULL, result << 24, 0,
+                                                   pending_req);
+                       kmem_cache_free(scsiback_cachep, pending_req);
+                       return 1;
+               }
+
+               switch (act) {
+               case VSCSIIF_ACT_SCSI_CDB:
+                       if (scsiback_gnttab_data_map(ring_req, pending_req)) {
+                               scsiback_fast_flush_area(pending_req);
+                               scsiback_do_resp_with_sense(NULL,
+                                       DRIVER_ERROR << 24, 0, pending_req);
+                               kmem_cache_free(scsiback_cachep, pending_req);
+                       } else {
+                               scsiback_cmd_exec(pending_req);
+                       }
+                       break;
+               case VSCSIIF_ACT_SCSI_ABORT:
+                       scsiback_device_action(pending_req, TMR_ABORT_TASK,
+                               ring_req->ref_rqid);
+                       break;
+               case VSCSIIF_ACT_SCSI_RESET:
+                       scsiback_device_action(pending_req, TMR_LUN_RESET, 0);
+                       break;
+               default:
+                       pr_err_ratelimited("xen-pvscsi: invalid request\n");
+                       scsiback_do_resp_with_sense(NULL, DRIVER_ERROR << 24,
+                                                   0, pending_req);
+                       kmem_cache_free(scsiback_cachep, pending_req);
+                       break;
+               }
+
+               /* Yield point for this unbounded loop. */
+               cond_resched();
+       }
+
+       RING_FINAL_CHECK_FOR_REQUESTS(&info->ring, more_to_do);
+       return more_to_do;
+}
+
+static irqreturn_t scsiback_irq_fn(int irq, void *dev_id)
+{
+       struct vscsibk_info *info = dev_id;
+
+       if (info->ring_error)
+               return IRQ_HANDLED;
+
+       while (scsiback_do_cmd_fn(info))
+               cond_resched();
+
+       return IRQ_HANDLED;
+}
+
+static int scsiback_init_sring(struct vscsibk_info *info, grant_ref_t ring_ref,
+                       evtchn_port_t evtchn)
+{
+       void *area;
+       struct vscsiif_sring *sring;
+       int err;
+
+       if (info->irq)
+               return -1;
+
+       err = xenbus_map_ring_valloc(info->dev, ring_ref, &area);
+       if (err)
+               return err;
+
+       sring = (struct vscsiif_sring *)area;
+       BACK_RING_INIT(&info->ring, sring, PAGE_SIZE);
+
+       err = bind_interdomain_evtchn_to_irq(info->domid, evtchn);
+       if (err < 0)
+               goto unmap_page;
+
+       info->irq = err;
+
+       err = request_threaded_irq(info->irq, NULL, scsiback_irq_fn,
+                                  IRQF_ONESHOT, "vscsiif-backend", info);
+       if (err)
+               goto free_irq;
+
+       return 0;
+
+free_irq:
+       unbind_from_irqhandler(info->irq, info);
+       info->irq = 0;
+unmap_page:
+       xenbus_unmap_ring_vfree(info->dev, area);
+
+       return err;
+}
+
+static int scsiback_map(struct vscsibk_info *info)
+{
+       struct xenbus_device *dev = info->dev;
+       unsigned int ring_ref, evtchn;
+       int err;
+
+       err = xenbus_gather(XBT_NIL, dev->otherend,
+                       "ring-ref", "%u", &ring_ref,
+                       "event-channel", "%u", &evtchn, NULL);
+       if (err) {
+               xenbus_dev_fatal(dev, err, "reading %s ring", dev->otherend);
+               return err;
+       }
+
+       return scsiback_init_sring(info, ring_ref, evtchn);
+}
+
+/*
+  Add a new translation entry
+*/
+static int scsiback_add_translation_entry(struct vscsibk_info *info,
+                                         char *phy, struct ids_tuple *v)
+{
+       int err = 0;
+       struct v2p_entry *entry;
+       struct v2p_entry *new;
+       struct list_head *head = &(info->v2p_entry_lists);
+       unsigned long flags;
+       char *lunp;
+       unsigned int lun;
+       struct scsiback_tpg *tpg_entry, *tpg = NULL;
+       char *error = "doesn't exist";
+
+       lunp = strrchr(phy, ':');
+       if (!lunp) {
+               pr_err("xen-pvscsi: illegal format of physical device %s\n",
+                       phy);
+               return -EINVAL;
+       }
+       *lunp = 0;
+       lunp++;
+       if (kstrtouint(lunp, 10, &lun) || lun >= TRANSPORT_MAX_LUNS_PER_TPG) {
+               pr_err("xen-pvscsi: lun number not valid: %s\n", lunp);
+               return -EINVAL;
+       }
+
+       mutex_lock(&scsiback_mutex);
+       list_for_each_entry(tpg_entry, &scsiback_list, tv_tpg_list) {
+               if (!strcmp(phy, tpg_entry->tport->tport_name) ||
+                   !strcmp(phy, tpg_entry->param_alias)) {
+                       spin_lock(&tpg_entry->se_tpg.tpg_lun_lock);
+                       if (tpg_entry->se_tpg.tpg_lun_list[lun]->lun_status ==
+                           TRANSPORT_LUN_STATUS_ACTIVE) {
+                               if (!tpg_entry->tpg_nexus)
+                                       error = "nexus undefined";
+                               else
+                                       tpg = tpg_entry;
+                       }
+                       spin_unlock(&tpg_entry->se_tpg.tpg_lun_lock);
+                       break;
+               }
+       }
+       if (tpg) {
+               mutex_lock(&tpg->tv_tpg_mutex);
+               tpg->tv_tpg_fe_count++;
+               mutex_unlock(&tpg->tv_tpg_mutex);
+       }
+       mutex_unlock(&scsiback_mutex);
+
+       if (!tpg) {
+               pr_err("xen-pvscsi: %s:%d %s\n", phy, lun, error);
+               return -ENODEV;
+       }
+
+       new = kmalloc(sizeof(struct v2p_entry), GFP_KERNEL);
+       if (new == NULL) {
+               err = -ENOMEM;
+               goto out_free;
+       }
+
+       spin_lock_irqsave(&info->v2p_lock, flags);
+
+       /* Check double assignment to identical virtual ID */
+       list_for_each_entry(entry, head, l) {
+               if ((entry->v.chn == v->chn) &&
+                   (entry->v.tgt == v->tgt) &&
+                   (entry->v.lun == v->lun)) {
+                       pr_warn("xen-pvscsi: Virtual ID is already used. Assignment was not performed.\n");
+                       err = -EEXIST;
+                       goto out;
+               }
+
+       }
+
+       /* Create a new translation entry and add to the list */
+       kref_init(&new->kref);
+       new->v = *v;
+       new->tpg = tpg;
+       new->lun = lun;
+       list_add_tail(&new->l, head);
+
+out:
+       spin_unlock_irqrestore(&info->v2p_lock, flags);
+
+out_free:
+       mutex_lock(&tpg->tv_tpg_mutex);
+       tpg->tv_tpg_fe_count--;
+       mutex_unlock(&tpg->tv_tpg_mutex);
+
+       if (err)
+               kfree(new);
+
+       return err;
+}
+
+static void __scsiback_del_translation_entry(struct v2p_entry *entry)
+{
+       list_del(&entry->l);
+       kref_put(&entry->kref, scsiback_free_translation_entry);
+}
+
+/*
+  Delete the translation entry specfied
+*/
+static int scsiback_del_translation_entry(struct vscsibk_info *info,
+                                         struct ids_tuple *v)
+{
+       struct v2p_entry *entry;
+       struct list_head *head = &(info->v2p_entry_lists);
+       unsigned long flags;
+
+       spin_lock_irqsave(&info->v2p_lock, flags);
+       /* Find out the translation entry specified */
+       list_for_each_entry(entry, head, l) {
+               if ((entry->v.chn == v->chn) &&
+                   (entry->v.tgt == v->tgt) &&
+                   (entry->v.lun == v->lun)) {
+                       goto found;
+               }
+       }
+
+       spin_unlock_irqrestore(&info->v2p_lock, flags);
+       return 1;
+
+found:
+       /* Delete the translation entry specfied */
+       __scsiback_del_translation_entry(entry);
+
+       spin_unlock_irqrestore(&info->v2p_lock, flags);
+       return 0;
+}
+
+static void scsiback_do_add_lun(struct vscsibk_info *info, const char *state,
+                               char *phy, struct ids_tuple *vir)
+{
+       if (!scsiback_add_translation_entry(info, phy, vir)) {
+               if (xenbus_printf(XBT_NIL, info->dev->nodename, state,
+                                 "%d", XenbusStateInitialised)) {
+                       pr_err("xen-pvscsi: xenbus_printf error %s\n", state);
+                       scsiback_del_translation_entry(info, vir);
+               }
+       } else {
+               xenbus_printf(XBT_NIL, info->dev->nodename, state,
+                             "%d", XenbusStateClosed);
+       }
+}
+
+static void scsiback_do_del_lun(struct vscsibk_info *info, const char *state,
+                               struct ids_tuple *vir)
+{
+       if (!scsiback_del_translation_entry(info, vir)) {
+               if (xenbus_printf(XBT_NIL, info->dev->nodename, state,
+                                 "%d", XenbusStateClosed))
+                       pr_err("xen-pvscsi: xenbus_printf error %s\n", state);
+       }
+}
+
+#define VSCSIBACK_OP_ADD_OR_DEL_LUN    1
+#define VSCSIBACK_OP_UPDATEDEV_STATE   2
+
+static void scsiback_do_1lun_hotplug(struct vscsibk_info *info, int op,
+                                    char *ent)
+{
+       int err;
+       struct ids_tuple vir;
+       char *val;
+       int device_state;
+       char phy[VSCSI_NAMELEN];
+       char str[64];
+       char state[64];
+       struct xenbus_device *dev = info->dev;
+
+       /* read status */
+       snprintf(state, sizeof(state), "vscsi-devs/%s/state", ent);
+       err = xenbus_scanf(XBT_NIL, dev->nodename, state, "%u", &device_state);
+       if (XENBUS_EXIST_ERR(err))
+               return;
+
+       /* physical SCSI device */
+       snprintf(str, sizeof(str), "vscsi-devs/%s/p-dev", ent);
+       val = xenbus_read(XBT_NIL, dev->nodename, str, NULL);
+       if (IS_ERR(val)) {
+               xenbus_printf(XBT_NIL, dev->nodename, state,
+                             "%d", XenbusStateClosed);
+               return;
+       }
+       strlcpy(phy, val, VSCSI_NAMELEN);
+       kfree(val);
+
+       /* virtual SCSI device */
+       snprintf(str, sizeof(str), "vscsi-devs/%s/v-dev", ent);
+       err = xenbus_scanf(XBT_NIL, dev->nodename, str, "%u:%u:%u:%u",
+                          &vir.hst, &vir.chn, &vir.tgt, &vir.lun);
+       if (XENBUS_EXIST_ERR(err)) {
+               xenbus_printf(XBT_NIL, dev->nodename, state,
+                             "%d", XenbusStateClosed);
+               return;
+       }
+
+       switch (op) {
+       case VSCSIBACK_OP_ADD_OR_DEL_LUN:
+               if (device_state == XenbusStateInitialising)
+                       scsiback_do_add_lun(info, state, phy, &vir);
+               if (device_state == XenbusStateClosing)
+                       scsiback_do_del_lun(info, state, &vir);
+               break;
+
+       case VSCSIBACK_OP_UPDATEDEV_STATE:
+               if (device_state == XenbusStateInitialised) {
+                       /* modify vscsi-devs/dev-x/state */
+                       if (xenbus_printf(XBT_NIL, dev->nodename, state,
+                                         "%d", XenbusStateConnected)) {
+                               pr_err("xen-pvscsi: xenbus_printf error %s\n",
+                                      str);
+                               scsiback_del_translation_entry(info, &vir);
+                               xenbus_printf(XBT_NIL, dev->nodename, state,
+                                             "%d", XenbusStateClosed);
+                       }
+               }
+               break;
+       /*When it is necessary, processing is added here.*/
+       default:
+               break;
+       }
+}
+
+static void scsiback_do_lun_hotplug(struct vscsibk_info *info, int op)
+{
+       int i;
+       char **dir;
+       unsigned int ndir = 0;
+
+       dir = xenbus_directory(XBT_NIL, info->dev->nodename, "vscsi-devs",
+                              &ndir);
+       if (IS_ERR(dir))
+               return;
+
+       for (i = 0; i < ndir; i++)
+               scsiback_do_1lun_hotplug(info, op, dir[i]);
+
+       kfree(dir);
+}
+
+static void scsiback_frontend_changed(struct xenbus_device *dev,
+                                       enum xenbus_state frontend_state)
+{
+       struct vscsibk_info *info = dev_get_drvdata(&dev->dev);
+
+       switch (frontend_state) {
+       case XenbusStateInitialising:
+               break;
+
+       case XenbusStateInitialised:
+               if (scsiback_map(info))
+                       break;
+
+               scsiback_do_lun_hotplug(info, VSCSIBACK_OP_ADD_OR_DEL_LUN);
+               xenbus_switch_state(dev, XenbusStateConnected);
+               break;
+
+       case XenbusStateConnected:
+               scsiback_do_lun_hotplug(info, VSCSIBACK_OP_UPDATEDEV_STATE);
+
+               if (dev->state == XenbusStateConnected)
+                       break;
+
+               xenbus_switch_state(dev, XenbusStateConnected);
+               break;
+
+       case XenbusStateClosing:
+               if (info->irq)
+                       scsiback_disconnect(info);
+
+               xenbus_switch_state(dev, XenbusStateClosing);
+               break;
+
+       case XenbusStateClosed:
+               xenbus_switch_state(dev, XenbusStateClosed);
+               if (xenbus_dev_is_online(dev))
+                       break;
+               /* fall through if not online */
+       case XenbusStateUnknown:
+               device_unregister(&dev->dev);
+               break;
+
+       case XenbusStateReconfiguring:
+               scsiback_do_lun_hotplug(info, VSCSIBACK_OP_ADD_OR_DEL_LUN);
+               xenbus_switch_state(dev, XenbusStateReconfigured);
+
+               break;
+
+       default:
+               xenbus_dev_fatal(dev, -EINVAL, "saw state %d at frontend",
+                                       frontend_state);
+               break;
+       }
+}
+
+/*
+  Release the translation entry specfied
+*/
+static void scsiback_release_translation_entry(struct vscsibk_info *info)
+{
+       struct v2p_entry *entry, *tmp;
+       struct list_head *head = &(info->v2p_entry_lists);
+       unsigned long flags;
+
+       spin_lock_irqsave(&info->v2p_lock, flags);
+
+       list_for_each_entry_safe(entry, tmp, head, l)
+               __scsiback_del_translation_entry(entry);
+
+       spin_unlock_irqrestore(&info->v2p_lock, flags);
+}
+
+static int scsiback_remove(struct xenbus_device *dev)
+{
+       struct vscsibk_info *info = dev_get_drvdata(&dev->dev);
+
+       if (info->irq)
+               scsiback_disconnect(info);
+
+       scsiback_release_translation_entry(info);
+
+       dev_set_drvdata(&dev->dev, NULL);
+
+       return 0;
+}
+
+static int scsiback_probe(struct xenbus_device *dev,
+                          const struct xenbus_device_id *id)
+{
+       int err;
+
+       struct vscsibk_info *info = kzalloc(sizeof(struct vscsibk_info),
+                                           GFP_KERNEL);
+
+       DPRINTK("%p %d\n", dev, dev->otherend_id);
+
+       if (!info) {
+               xenbus_dev_fatal(dev, -ENOMEM, "allocating backend structure");
+               return -ENOMEM;
+       }
+       info->dev = dev;
+       dev_set_drvdata(&dev->dev, info);
+
+       info->domid = dev->otherend_id;
+       spin_lock_init(&info->ring_lock);
+       info->ring_error = 0;
+       atomic_set(&info->nr_unreplied_reqs, 0);
+       init_waitqueue_head(&info->waiting_to_free);
+       info->dev = dev;
+       info->irq = 0;
+       INIT_LIST_HEAD(&info->v2p_entry_lists);
+       spin_lock_init(&info->v2p_lock);
+
+       err = xenbus_printf(XBT_NIL, dev->nodename, "feature-sg-grant", "%u",
+                           SG_ALL);
+       if (err)
+               xenbus_dev_error(dev, err, "writing feature-sg-grant");
+
+       err = xenbus_switch_state(dev, XenbusStateInitWait);
+       if (err)
+               goto fail;
+
+       return 0;
+
+fail:
+       pr_warn("xen-pvscsi: %s failed\n", __func__);
+       scsiback_remove(dev);
+
+       return err;
+}
+
+static char *scsiback_dump_proto_id(struct scsiback_tport *tport)
+{
+       switch (tport->tport_proto_id) {
+       case SCSI_PROTOCOL_SAS:
+               return "SAS";
+       case SCSI_PROTOCOL_FCP:
+               return "FCP";
+       case SCSI_PROTOCOL_ISCSI:
+               return "iSCSI";
+       default:
+               break;
+       }
+
+       return "Unknown";
+}
+
+static u8 scsiback_get_fabric_proto_ident(struct se_portal_group *se_tpg)
+{
+       struct scsiback_tpg *tpg = container_of(se_tpg,
+                               struct scsiback_tpg, se_tpg);
+       struct scsiback_tport *tport = tpg->tport;
+
+       switch (tport->tport_proto_id) {
+       case SCSI_PROTOCOL_SAS:
+               return sas_get_fabric_proto_ident(se_tpg);
+       case SCSI_PROTOCOL_FCP:
+               return fc_get_fabric_proto_ident(se_tpg);
+       case SCSI_PROTOCOL_ISCSI:
+               return iscsi_get_fabric_proto_ident(se_tpg);
+       default:
+               pr_err("Unknown tport_proto_id: 0x%02x, using SAS emulation\n",
+                       tport->tport_proto_id);
+               break;
+       }
+
+       return sas_get_fabric_proto_ident(se_tpg);
+}
+
+static char *scsiback_get_fabric_wwn(struct se_portal_group *se_tpg)
+{
+       struct scsiback_tpg *tpg = container_of(se_tpg,
+                               struct scsiback_tpg, se_tpg);
+       struct scsiback_tport *tport = tpg->tport;
+
+       return &tport->tport_name[0];
+}
+
+static u16 scsiback_get_tag(struct se_portal_group *se_tpg)
+{
+       struct scsiback_tpg *tpg = container_of(se_tpg,
+                               struct scsiback_tpg, se_tpg);
+       return tpg->tport_tpgt;
+}
+
+static u32 scsiback_get_default_depth(struct se_portal_group *se_tpg)
+{
+       return 1;
+}
+
+static u32
+scsiback_get_pr_transport_id(struct se_portal_group *se_tpg,
+                             struct se_node_acl *se_nacl,
+                             struct t10_pr_registration *pr_reg,
+                             int *format_code,
+                             unsigned char *buf)
+{
+       struct scsiback_tpg *tpg = container_of(se_tpg,
+                               struct scsiback_tpg, se_tpg);
+       struct scsiback_tport *tport = tpg->tport;
+
+       switch (tport->tport_proto_id) {
+       case SCSI_PROTOCOL_SAS:
+               return sas_get_pr_transport_id(se_tpg, se_nacl, pr_reg,
+                                       format_code, buf);
+       case SCSI_PROTOCOL_FCP:
+               return fc_get_pr_transport_id(se_tpg, se_nacl, pr_reg,
+                                       format_code, buf);
+       case SCSI_PROTOCOL_ISCSI:
+               return iscsi_get_pr_transport_id(se_tpg, se_nacl, pr_reg,
+                                       format_code, buf);
+       default:
+               pr_err("Unknown tport_proto_id: 0x%02x, using SAS emulation\n",
+                       tport->tport_proto_id);
+               break;
+       }
+
+       return sas_get_pr_transport_id(se_tpg, se_nacl, pr_reg,
+                       format_code, buf);
+}
+
+static u32
+scsiback_get_pr_transport_id_len(struct se_portal_group *se_tpg,
+                                 struct se_node_acl *se_nacl,
+                                 struct t10_pr_registration *pr_reg,
+                                 int *format_code)
+{
+       struct scsiback_tpg *tpg = container_of(se_tpg,
+                               struct scsiback_tpg, se_tpg);
+       struct scsiback_tport *tport = tpg->tport;
+
+       switch (tport->tport_proto_id) {
+       case SCSI_PROTOCOL_SAS:
+               return sas_get_pr_transport_id_len(se_tpg, se_nacl, pr_reg,
+                                       format_code);
+       case SCSI_PROTOCOL_FCP:
+               return fc_get_pr_transport_id_len(se_tpg, se_nacl, pr_reg,
+                                       format_code);
+       case SCSI_PROTOCOL_ISCSI:
+               return iscsi_get_pr_transport_id_len(se_tpg, se_nacl, pr_reg,
+                                       format_code);
+       default:
+               pr_err("Unknown tport_proto_id: 0x%02x, using SAS emulation\n",
+                       tport->tport_proto_id);
+               break;
+       }
+
+       return sas_get_pr_transport_id_len(se_tpg, se_nacl, pr_reg,
+                       format_code);
+}
+
+static char *
+scsiback_parse_pr_out_transport_id(struct se_portal_group *se_tpg,
+                                   const char *buf,
+                                   u32 *out_tid_len,
+                                   char **port_nexus_ptr)
+{
+       struct scsiback_tpg *tpg = container_of(se_tpg,
+                               struct scsiback_tpg, se_tpg);
+       struct scsiback_tport *tport = tpg->tport;
+
+       switch (tport->tport_proto_id) {
+       case SCSI_PROTOCOL_SAS:
+               return sas_parse_pr_out_transport_id(se_tpg, buf, out_tid_len,
+                                       port_nexus_ptr);
+       case SCSI_PROTOCOL_FCP:
+               return fc_parse_pr_out_transport_id(se_tpg, buf, out_tid_len,
+                                       port_nexus_ptr);
+       case SCSI_PROTOCOL_ISCSI:
+               return iscsi_parse_pr_out_transport_id(se_tpg, buf, out_tid_len,
+                                       port_nexus_ptr);
+       default:
+               pr_err("Unknown tport_proto_id: 0x%02x, using SAS emulation\n",
+                       tport->tport_proto_id);
+               break;
+       }
+
+       return sas_parse_pr_out_transport_id(se_tpg, buf, out_tid_len,
+                       port_nexus_ptr);
+}
+
+static struct se_wwn *
+scsiback_make_tport(struct target_fabric_configfs *tf,
+                    struct config_group *group,
+                    const char *name)
+{
+       struct scsiback_tport *tport;
+       char *ptr;
+       u64 wwpn = 0;
+       int off = 0;
+
+       tport = kzalloc(sizeof(struct scsiback_tport), GFP_KERNEL);
+       if (!tport)
+               return ERR_PTR(-ENOMEM);
+
+       tport->tport_wwpn = wwpn;
+       /*
+        * Determine the emulated Protocol Identifier and Target Port Name
+        * based on the incoming configfs directory name.
+        */
+       ptr = strstr(name, "naa.");
+       if (ptr) {
+               tport->tport_proto_id = SCSI_PROTOCOL_SAS;
+               goto check_len;
+       }
+       ptr = strstr(name, "fc.");
+       if (ptr) {
+               tport->tport_proto_id = SCSI_PROTOCOL_FCP;
+               off = 3; /* Skip over "fc." */
+               goto check_len;
+       }
+       ptr = strstr(name, "iqn.");
+       if (ptr) {
+               tport->tport_proto_id = SCSI_PROTOCOL_ISCSI;
+               goto check_len;
+       }
+
+       pr_err("Unable to locate prefix for emulated Target Port: %s\n", name);
+       kfree(tport);
+       return ERR_PTR(-EINVAL);
+
+check_len:
+       if (strlen(name) >= VSCSI_NAMELEN) {
+               pr_err("Emulated %s Address: %s, exceeds max: %d\n", name,
+                       scsiback_dump_proto_id(tport), VSCSI_NAMELEN);
+               kfree(tport);
+               return ERR_PTR(-EINVAL);
+       }
+       snprintf(&tport->tport_name[0], VSCSI_NAMELEN, "%s", &name[off]);
+
+       pr_debug("xen-pvscsi: Allocated emulated Target %s Address: %s\n",
+                scsiback_dump_proto_id(tport), name);
+
+       return &tport->tport_wwn;
+}
+
+static void scsiback_drop_tport(struct se_wwn *wwn)
+{
+       struct scsiback_tport *tport = container_of(wwn,
+                               struct scsiback_tport, tport_wwn);
+
+       pr_debug("xen-pvscsi: Deallocating emulated Target %s Address: %s\n",
+                scsiback_dump_proto_id(tport), tport->tport_name);
+
+       kfree(tport);
+}
+
+static struct se_node_acl *
+scsiback_alloc_fabric_acl(struct se_portal_group *se_tpg)
+{
+       return kzalloc(sizeof(struct se_node_acl), GFP_KERNEL);
+}
+
+static void
+scsiback_release_fabric_acl(struct se_portal_group *se_tpg,
+                            struct se_node_acl *se_nacl)
+{
+       kfree(se_nacl);
+}
+
+static u32 scsiback_tpg_get_inst_index(struct se_portal_group *se_tpg)
+{
+       return 1;
+}
+
+static int scsiback_check_stop_free(struct se_cmd *se_cmd)
+{
+       /*
+        * Do not release struct se_cmd's containing a valid TMR
+        * pointer.  These will be released directly in scsiback_device_action()
+        * with transport_generic_free_cmd().
+        */
+       if (se_cmd->se_cmd_flags & SCF_SCSI_TMR_CDB)
+               return 0;
+
+       transport_generic_free_cmd(se_cmd, 0);
+       return 1;
+}
+
+static void scsiback_release_cmd(struct se_cmd *se_cmd)
+{
+       struct vscsibk_pend *pending_req = container_of(se_cmd,
+                               struct vscsibk_pend, se_cmd);
+
+       kmem_cache_free(scsiback_cachep, pending_req);
+}
+
+static int scsiback_shutdown_session(struct se_session *se_sess)
+{
+       return 0;
+}
+
+static void scsiback_close_session(struct se_session *se_sess)
+{
+}
+
+static u32 scsiback_sess_get_index(struct se_session *se_sess)
+{
+       return 0;
+}
+
+static int scsiback_write_pending(struct se_cmd *se_cmd)
+{
+       /* Go ahead and process the write immediately */
+       target_execute_cmd(se_cmd);
+
+       return 0;
+}
+
+static int scsiback_write_pending_status(struct se_cmd *se_cmd)
+{
+       return 0;
+}
+
+static void scsiback_set_default_node_attrs(struct se_node_acl *nacl)
+{
+}
+
+static u32 scsiback_get_task_tag(struct se_cmd *se_cmd)
+{
+       struct vscsibk_pend *pending_req = container_of(se_cmd,
+                               struct vscsibk_pend, se_cmd);
+
+       return pending_req->rqid;
+}
+
+static int scsiback_get_cmd_state(struct se_cmd *se_cmd)
+{
+       return 0;
+}
+
+static int scsiback_queue_data_in(struct se_cmd *se_cmd)
+{
+       struct vscsibk_pend *pending_req = container_of(se_cmd,
+                               struct vscsibk_pend, se_cmd);
+
+       pending_req->result = SAM_STAT_GOOD;
+       scsiback_cmd_done(pending_req);
+       return 0;
+}
+
+static int scsiback_queue_status(struct se_cmd *se_cmd)
+{
+       struct vscsibk_pend *pending_req = container_of(se_cmd,
+                               struct vscsibk_pend, se_cmd);
+
+       if (se_cmd->sense_buffer &&
+           ((se_cmd->se_cmd_flags & SCF_TRANSPORT_TASK_SENSE) ||
+            (se_cmd->se_cmd_flags & SCF_EMULATED_TASK_SENSE)))
+               pending_req->result = (DRIVER_SENSE << 24) |
+                                     SAM_STAT_CHECK_CONDITION;
+       else
+               pending_req->result = se_cmd->scsi_status;
+
+       scsiback_cmd_done(pending_req);
+       return 0;
+}
+
+static void scsiback_queue_tm_rsp(struct se_cmd *se_cmd)
+{
+       struct se_tmr_req *se_tmr = se_cmd->se_tmr_req;
+       struct scsiback_tmr *tmr = se_tmr->fabric_tmr_ptr;
+
+       atomic_set(&tmr->tmr_complete, 1);
+       wake_up(&tmr->tmr_wait);
+}
+
+static void scsiback_aborted_task(struct se_cmd *se_cmd)
+{
+}
+
+static ssize_t scsiback_tpg_param_show_alias(struct se_portal_group *se_tpg,
+                                            char *page)
+{
+       struct scsiback_tpg *tpg = container_of(se_tpg, struct scsiback_tpg,
+                                               se_tpg);
+       ssize_t rb;
+
+       mutex_lock(&tpg->tv_tpg_mutex);
+       rb = snprintf(page, PAGE_SIZE, "%s\n", tpg->param_alias);
+       mutex_unlock(&tpg->tv_tpg_mutex);
+
+       return rb;
+}
+
+static ssize_t scsiback_tpg_param_store_alias(struct se_portal_group *se_tpg,
+                                             const char *page, size_t count)
+{
+       struct scsiback_tpg *tpg = container_of(se_tpg, struct scsiback_tpg,
+                                               se_tpg);
+       int len;
+
+       if (strlen(page) >= VSCSI_NAMELEN) {
+               pr_err("param alias: %s, exceeds max: %d\n", page,
+                       VSCSI_NAMELEN);
+               return -EINVAL;
+       }
+
+       mutex_lock(&tpg->tv_tpg_mutex);
+       len = snprintf(tpg->param_alias, VSCSI_NAMELEN, "%s", page);
+       if (tpg->param_alias[len - 1] == '\n')
+               tpg->param_alias[len - 1] = '\0';
+       mutex_unlock(&tpg->tv_tpg_mutex);
+
+       return count;
+}
+
+TF_TPG_PARAM_ATTR(scsiback, alias, S_IRUGO | S_IWUSR);
+
+static struct configfs_attribute *scsiback_param_attrs[] = {
+       &scsiback_tpg_param_alias.attr,
+       NULL,
+};
+
+static int scsiback_make_nexus(struct scsiback_tpg *tpg,
+                               const char *name)
+{
+       struct se_portal_group *se_tpg;
+       struct se_session *se_sess;
+       struct scsiback_nexus *tv_nexus;
+
+       mutex_lock(&tpg->tv_tpg_mutex);
+       if (tpg->tpg_nexus) {
+               mutex_unlock(&tpg->tv_tpg_mutex);
+               pr_debug("tpg->tpg_nexus already exists\n");
+               return -EEXIST;
+       }
+       se_tpg = &tpg->se_tpg;
+
+       tv_nexus = kzalloc(sizeof(struct scsiback_nexus), GFP_KERNEL);
+       if (!tv_nexus) {
+               mutex_unlock(&tpg->tv_tpg_mutex);
+               return -ENOMEM;
+       }
+       /*
+        *  Initialize the struct se_session pointer
+        */
+       tv_nexus->tvn_se_sess = transport_init_session(TARGET_PROT_NORMAL);
+       if (IS_ERR(tv_nexus->tvn_se_sess)) {
+               mutex_unlock(&tpg->tv_tpg_mutex);
+               kfree(tv_nexus);
+               return -ENOMEM;
+       }
+       se_sess = tv_nexus->tvn_se_sess;
+       /*
+        * Since we are running in 'demo mode' this call with generate a
+        * struct se_node_acl for the scsiback struct se_portal_group with
+        * the SCSI Initiator port name of the passed configfs group 'name'.
+        */
+       tv_nexus->tvn_se_sess->se_node_acl = core_tpg_check_initiator_node_acl(
+                               se_tpg, (unsigned char *)name);
+       if (!tv_nexus->tvn_se_sess->se_node_acl) {
+               mutex_unlock(&tpg->tv_tpg_mutex);
+               pr_debug("core_tpg_check_initiator_node_acl() failed for %s\n",
+                        name);
+               goto out;
+       }
+       /*
+        * Now register the TCM pvscsi virtual I_T Nexus as active with the
+        * call to __transport_register_session()
+        */
+       __transport_register_session(se_tpg, tv_nexus->tvn_se_sess->se_node_acl,
+                       tv_nexus->tvn_se_sess, tv_nexus);
+       tpg->tpg_nexus = tv_nexus;
+
+       mutex_unlock(&tpg->tv_tpg_mutex);
+       return 0;
+
+out:
+       transport_free_session(se_sess);
+       kfree(tv_nexus);
+       return -ENOMEM;
+}
+
+static int scsiback_drop_nexus(struct scsiback_tpg *tpg)
+{
+       struct se_session *se_sess;
+       struct scsiback_nexus *tv_nexus;
+
+       mutex_lock(&tpg->tv_tpg_mutex);
+       tv_nexus = tpg->tpg_nexus;
+       if (!tv_nexus) {
+               mutex_unlock(&tpg->tv_tpg_mutex);
+               return -ENODEV;
+       }
+
+       se_sess = tv_nexus->tvn_se_sess;
+       if (!se_sess) {
+               mutex_unlock(&tpg->tv_tpg_mutex);
+               return -ENODEV;
+       }
+
+       if (tpg->tv_tpg_port_count != 0) {
+               mutex_unlock(&tpg->tv_tpg_mutex);
+               pr_err("Unable to remove xen-pvscsi I_T Nexus with active TPG port count: %d\n",
+                       tpg->tv_tpg_port_count);
+               return -EBUSY;
+       }
+
+       if (tpg->tv_tpg_fe_count != 0) {
+               mutex_unlock(&tpg->tv_tpg_mutex);
+               pr_err("Unable to remove xen-pvscsi I_T Nexus with active TPG frontend count: %d\n",
+                       tpg->tv_tpg_fe_count);
+               return -EBUSY;
+       }
+
+       pr_debug("xen-pvscsi: Removing I_T Nexus to emulated %s Initiator Port: %s\n",
+               scsiback_dump_proto_id(tpg->tport),
+               tv_nexus->tvn_se_sess->se_node_acl->initiatorname);
+
+       /*
+        * Release the SCSI I_T Nexus to the emulated xen-pvscsi Target Port
+        */
+       transport_deregister_session(tv_nexus->tvn_se_sess);
+       tpg->tpg_nexus = NULL;
+       mutex_unlock(&tpg->tv_tpg_mutex);
+
+       kfree(tv_nexus);
+       return 0;
+}
+
+static ssize_t scsiback_tpg_show_nexus(struct se_portal_group *se_tpg,
+                                       char *page)
+{
+       struct scsiback_tpg *tpg = container_of(se_tpg,
+                               struct scsiback_tpg, se_tpg);
+       struct scsiback_nexus *tv_nexus;
+       ssize_t ret;
+
+       mutex_lock(&tpg->tv_tpg_mutex);
+       tv_nexus = tpg->tpg_nexus;
+       if (!tv_nexus) {
+               mutex_unlock(&tpg->tv_tpg_mutex);
+               return -ENODEV;
+       }
+       ret = snprintf(page, PAGE_SIZE, "%s\n",
+                       tv_nexus->tvn_se_sess->se_node_acl->initiatorname);
+       mutex_unlock(&tpg->tv_tpg_mutex);
+
+       return ret;
+}
+
+static ssize_t scsiback_tpg_store_nexus(struct se_portal_group *se_tpg,
+                                        const char *page,
+                                        size_t count)
+{
+       struct scsiback_tpg *tpg = container_of(se_tpg,
+                               struct scsiback_tpg, se_tpg);
+       struct scsiback_tport *tport_wwn = tpg->tport;
+       unsigned char i_port[VSCSI_NAMELEN], *ptr, *port_ptr;
+       int ret;
+       /*
+        * Shutdown the active I_T nexus if 'NULL' is passed..
+        */
+       if (!strncmp(page, "NULL", 4)) {
+               ret = scsiback_drop_nexus(tpg);
+               return (!ret) ? count : ret;
+       }
+       /*
+        * Otherwise make sure the passed virtual Initiator port WWN matches
+        * the fabric protocol_id set in scsiback_make_tport(), and call
+        * scsiback_make_nexus().
+        */
+       if (strlen(page) >= VSCSI_NAMELEN) {
+               pr_err("Emulated NAA Sas Address: %s, exceeds max: %d\n",
+                       page, VSCSI_NAMELEN);
+               return -EINVAL;
+       }
+       snprintf(&i_port[0], VSCSI_NAMELEN, "%s", page);
+
+       ptr = strstr(i_port, "naa.");
+       if (ptr) {
+               if (tport_wwn->tport_proto_id != SCSI_PROTOCOL_SAS) {
+                       pr_err("Passed SAS Initiator Port %s does not match target port protoid: %s\n",
+                               i_port, scsiback_dump_proto_id(tport_wwn));
+                       return -EINVAL;
+               }
+               port_ptr = &i_port[0];
+               goto check_newline;
+       }
+       ptr = strstr(i_port, "fc.");
+       if (ptr) {
+               if (tport_wwn->tport_proto_id != SCSI_PROTOCOL_FCP) {
+                       pr_err("Passed FCP Initiator Port %s does not match target port protoid: %s\n",
+                               i_port, scsiback_dump_proto_id(tport_wwn));
+                       return -EINVAL;
+               }
+               port_ptr = &i_port[3]; /* Skip over "fc." */
+               goto check_newline;
+       }
+       ptr = strstr(i_port, "iqn.");
+       if (ptr) {
+               if (tport_wwn->tport_proto_id != SCSI_PROTOCOL_ISCSI) {
+                       pr_err("Passed iSCSI Initiator Port %s does not match target port protoid: %s\n",
+                               i_port, scsiback_dump_proto_id(tport_wwn));
+                       return -EINVAL;
+               }
+               port_ptr = &i_port[0];
+               goto check_newline;
+       }
+       pr_err("Unable to locate prefix for emulated Initiator Port: %s\n",
+               i_port);
+       return -EINVAL;
+       /*
+        * Clear any trailing newline for the NAA WWN
+        */
+check_newline:
+       if (i_port[strlen(i_port) - 1] == '\n')
+               i_port[strlen(i_port) - 1] = '\0';
+
+       ret = scsiback_make_nexus(tpg, port_ptr);
+       if (ret < 0)
+               return ret;
+
+       return count;
+}
+
+TF_TPG_BASE_ATTR(scsiback, nexus, S_IRUGO | S_IWUSR);
+
+static struct configfs_attribute *scsiback_tpg_attrs[] = {
+       &scsiback_tpg_nexus.attr,
+       NULL,
+};
+
+static ssize_t
+scsiback_wwn_show_attr_version(struct target_fabric_configfs *tf,
+                               char *page)
+{
+       return sprintf(page, "xen-pvscsi fabric module %s on %s/%s on "
+               UTS_RELEASE"\n",
+               VSCSI_VERSION, utsname()->sysname, utsname()->machine);
+}
+
+TF_WWN_ATTR_RO(scsiback, version);
+
+static struct configfs_attribute *scsiback_wwn_attrs[] = {
+       &scsiback_wwn_version.attr,
+       NULL,
+};
+
+static char *scsiback_get_fabric_name(void)
+{
+       return "xen-pvscsi";
+}
+
+static int scsiback_port_link(struct se_portal_group *se_tpg,
+                              struct se_lun *lun)
+{
+       struct scsiback_tpg *tpg = container_of(se_tpg,
+                               struct scsiback_tpg, se_tpg);
+
+       mutex_lock(&tpg->tv_tpg_mutex);
+       tpg->tv_tpg_port_count++;
+       mutex_unlock(&tpg->tv_tpg_mutex);
+
+       return 0;
+}
+
+static void scsiback_port_unlink(struct se_portal_group *se_tpg,
+                                 struct se_lun *lun)
+{
+       struct scsiback_tpg *tpg = container_of(se_tpg,
+                               struct scsiback_tpg, se_tpg);
+
+       mutex_lock(&tpg->tv_tpg_mutex);
+       tpg->tv_tpg_port_count--;
+       mutex_unlock(&tpg->tv_tpg_mutex);
+}
+
+static struct se_portal_group *
+scsiback_make_tpg(struct se_wwn *wwn,
+                  struct config_group *group,
+                  const char *name)
+{
+       struct scsiback_tport *tport = container_of(wwn,
+                       struct scsiback_tport, tport_wwn);
+
+       struct scsiback_tpg *tpg;
+       u16 tpgt;
+       int ret;
+
+       if (strstr(name, "tpgt_") != name)
+               return ERR_PTR(-EINVAL);
+       ret = kstrtou16(name + 5, 10, &tpgt);
+       if (ret)
+               return ERR_PTR(ret);
+
+       tpg = kzalloc(sizeof(struct scsiback_tpg), GFP_KERNEL);
+       if (!tpg)
+               return ERR_PTR(-ENOMEM);
+
+       mutex_init(&tpg->tv_tpg_mutex);
+       INIT_LIST_HEAD(&tpg->tv_tpg_list);
+       INIT_LIST_HEAD(&tpg->info_list);
+       tpg->tport = tport;
+       tpg->tport_tpgt = tpgt;
+
+       ret = core_tpg_register(&scsiback_fabric_configfs->tf_ops, wwn,
+                               &tpg->se_tpg, tpg, TRANSPORT_TPG_TYPE_NORMAL);
+       if (ret < 0) {
+               kfree(tpg);
+               return NULL;
+       }
+       mutex_lock(&scsiback_mutex);
+       list_add_tail(&tpg->tv_tpg_list, &scsiback_list);
+       mutex_unlock(&scsiback_mutex);
+
+       return &tpg->se_tpg;
+}
+
+static void scsiback_drop_tpg(struct se_portal_group *se_tpg)
+{
+       struct scsiback_tpg *tpg = container_of(se_tpg,
+                               struct scsiback_tpg, se_tpg);
+
+       mutex_lock(&scsiback_mutex);
+       list_del(&tpg->tv_tpg_list);
+       mutex_unlock(&scsiback_mutex);
+       /*
+        * Release the virtual I_T Nexus for this xen-pvscsi TPG
+        */
+       scsiback_drop_nexus(tpg);
+       /*
+        * Deregister the se_tpg from TCM..
+        */
+       core_tpg_deregister(se_tpg);
+       kfree(tpg);
+}
+
+static int scsiback_check_true(struct se_portal_group *se_tpg)
+{
+       return 1;
+}
+
+static int scsiback_check_false(struct se_portal_group *se_tpg)
+{
+       return 0;
+}
+
+static struct target_core_fabric_ops scsiback_ops = {
+       .get_fabric_name                = scsiback_get_fabric_name,
+       .get_fabric_proto_ident         = scsiback_get_fabric_proto_ident,
+       .tpg_get_wwn                    = scsiback_get_fabric_wwn,
+       .tpg_get_tag                    = scsiback_get_tag,
+       .tpg_get_default_depth          = scsiback_get_default_depth,
+       .tpg_get_pr_transport_id        = scsiback_get_pr_transport_id,
+       .tpg_get_pr_transport_id_len    = scsiback_get_pr_transport_id_len,
+       .tpg_parse_pr_out_transport_id  = scsiback_parse_pr_out_transport_id,
+       .tpg_check_demo_mode            = scsiback_check_true,
+       .tpg_check_demo_mode_cache      = scsiback_check_true,
+       .tpg_check_demo_mode_write_protect = scsiback_check_false,
+       .tpg_check_prod_mode_write_protect = scsiback_check_false,
+       .tpg_alloc_fabric_acl           = scsiback_alloc_fabric_acl,
+       .tpg_release_fabric_acl         = scsiback_release_fabric_acl,
+       .tpg_get_inst_index             = scsiback_tpg_get_inst_index,
+       .check_stop_free                = scsiback_check_stop_free,
+       .release_cmd                    = scsiback_release_cmd,
+       .put_session                    = NULL,
+       .shutdown_session               = scsiback_shutdown_session,
+       .close_session                  = scsiback_close_session,
+       .sess_get_index                 = scsiback_sess_get_index,
+       .sess_get_initiator_sid         = NULL,
+       .write_pending                  = scsiback_write_pending,
+       .write_pending_status           = scsiback_write_pending_status,
+       .set_default_node_attributes    = scsiback_set_default_node_attrs,
+       .get_task_tag                   = scsiback_get_task_tag,
+       .get_cmd_state                  = scsiback_get_cmd_state,
+       .queue_data_in                  = scsiback_queue_data_in,
+       .queue_status                   = scsiback_queue_status,
+       .queue_tm_rsp                   = scsiback_queue_tm_rsp,
+       .aborted_task                   = scsiback_aborted_task,
+       /*
+        * Setup callers for generic logic in target_core_fabric_configfs.c
+        */
+       .fabric_make_wwn                = scsiback_make_tport,
+       .fabric_drop_wwn                = scsiback_drop_tport,
+       .fabric_make_tpg                = scsiback_make_tpg,
+       .fabric_drop_tpg                = scsiback_drop_tpg,
+       .fabric_post_link               = scsiback_port_link,
+       .fabric_pre_unlink              = scsiback_port_unlink,
+       .fabric_make_np                 = NULL,
+       .fabric_drop_np                 = NULL,
+#if 0
+       .fabric_make_nodeacl            = scsiback_make_nodeacl,
+       .fabric_drop_nodeacl            = scsiback_drop_nodeacl,
+#endif
+};
+
+static int scsiback_register_configfs(void)
+{
+       struct target_fabric_configfs *fabric;
+       int ret;
+
+       pr_debug("xen-pvscsi: fabric module %s on %s/%s on "UTS_RELEASE"\n",
+                VSCSI_VERSION, utsname()->sysname, utsname()->machine);
+       /*
+        * Register the top level struct config_item_type with TCM core
+        */
+       fabric = target_fabric_configfs_init(THIS_MODULE, "xen-pvscsi");
+       if (IS_ERR(fabric))
+               return PTR_ERR(fabric);
+
+       /*
+        * Setup fabric->tf_ops from our local scsiback_ops
+        */
+       fabric->tf_ops = scsiback_ops;
+       /*
+        * Setup default attribute lists for various fabric->tf_cit_tmpl
+        */
+       fabric->tf_cit_tmpl.tfc_wwn_cit.ct_attrs = scsiback_wwn_attrs;
+       fabric->tf_cit_tmpl.tfc_tpg_base_cit.ct_attrs = scsiback_tpg_attrs;
+       fabric->tf_cit_tmpl.tfc_tpg_attrib_cit.ct_attrs = NULL;
+       fabric->tf_cit_tmpl.tfc_tpg_param_cit.ct_attrs = scsiback_param_attrs;
+       fabric->tf_cit_tmpl.tfc_tpg_np_base_cit.ct_attrs = NULL;
+       fabric->tf_cit_tmpl.tfc_tpg_nacl_base_cit.ct_attrs = NULL;
+       fabric->tf_cit_tmpl.tfc_tpg_nacl_attrib_cit.ct_attrs = NULL;
+       fabric->tf_cit_tmpl.tfc_tpg_nacl_auth_cit.ct_attrs = NULL;
+       fabric->tf_cit_tmpl.tfc_tpg_nacl_param_cit.ct_attrs = NULL;
+       /*
+        * Register the fabric for use within TCM
+        */
+       ret = target_fabric_configfs_register(fabric);
+       if (ret < 0) {
+               target_fabric_configfs_free(fabric);
+               return ret;
+       }
+       /*
+        * Setup our local pointer to *fabric
+        */
+       scsiback_fabric_configfs = fabric;
+       pr_debug("xen-pvscsi: Set fabric -> scsiback_fabric_configfs\n");
+       return 0;
+};
+
+static void scsiback_deregister_configfs(void)
+{
+       if (!scsiback_fabric_configfs)
+               return;
+
+       target_fabric_configfs_deregister(scsiback_fabric_configfs);
+       scsiback_fabric_configfs = NULL;
+       pr_debug("xen-pvscsi: Cleared scsiback_fabric_configfs\n");
+};
+
+static const struct xenbus_device_id scsiback_ids[] = {
+       { "vscsi" },
+       { "" }
+};
+
+static struct xenbus_driver scsiback_driver = {
+       .ids                    = scsiback_ids,
+       .probe                  = scsiback_probe,
+       .remove                 = scsiback_remove,
+       .otherend_changed       = scsiback_frontend_changed
+};
+
+static void scsiback_init_pend(void *p)
+{
+       struct vscsibk_pend *pend = p;
+       int i;
+
+       memset(pend, 0, sizeof(*pend));
+       for (i = 0; i < VSCSI_MAX_GRANTS; i++)
+               pend->grant_handles[i] = SCSIBACK_INVALID_HANDLE;
+}
+
+static int __init scsiback_init(void)
+{
+       int ret;
+
+       if (!xen_domain())
+               return -ENODEV;
+
+       scsiback_cachep = kmem_cache_create("vscsiif_cache",
+               sizeof(struct vscsibk_pend), 0, 0, scsiback_init_pend);
+       if (!scsiback_cachep)
+               return -ENOMEM;
+
+       ret = xenbus_register_backend(&scsiback_driver);
+       if (ret)
+               goto out_cache_destroy;
+
+       ret = scsiback_register_configfs();
+       if (ret)
+               goto out_unregister_xenbus;
+
+       return 0;
+
+out_unregister_xenbus:
+       xenbus_unregister_driver(&scsiback_driver);
+out_cache_destroy:
+       kmem_cache_destroy(scsiback_cachep);
+       pr_err("xen-pvscsi: %s: error %d\n", __func__, ret);
+       return ret;
+}
+
+static void __exit scsiback_exit(void)
+{
+       struct page *page;
+
+       while (free_pages_num) {
+               if (get_free_page(&page))
+                       BUG();
+               free_xenballooned_pages(1, &page);
+       }
+       scsiback_deregister_configfs();
+       xenbus_unregister_driver(&scsiback_driver);
+       kmem_cache_destroy(scsiback_cachep);
+}
+
+module_init(scsiback_init);
+module_exit(scsiback_exit);
+
+MODULE_DESCRIPTION("Xen SCSI backend driver");
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_ALIAS("xen-backend:vscsi");
+MODULE_AUTHOR("Juergen Gross <jgross@suse.com>");
index 439c9dca9eeedea8c490a9e57174c6745cae8637..ca744102b6663fb92f37da6f9bc4974fac393d53 100644 (file)
@@ -259,7 +259,6 @@ static char *error_path(struct xenbus_device *dev)
 static void xenbus_va_dev_error(struct xenbus_device *dev, int err,
                                const char *fmt, va_list ap)
 {
-       int ret;
        unsigned int len;
        char *printf_buffer = NULL;
        char *path_buffer = NULL;
@@ -270,9 +269,7 @@ static void xenbus_va_dev_error(struct xenbus_device *dev, int err,
                goto fail;
 
        len = sprintf(printf_buffer, "%i ", -err);
-       ret = vsnprintf(printf_buffer+len, PRINTF_BUFFER_SIZE-len, fmt, ap);
-
-       BUG_ON(len + ret > PRINTF_BUFFER_SIZE-1);
+       vsnprintf(printf_buffer+len, PRINTF_BUFFER_SIZE-len, fmt, ap);
 
        dev_err(&dev->dev, "%s\n", printf_buffer);
 
@@ -361,8 +358,8 @@ static void xenbus_switch_fatal(struct xenbus_device *dev, int depth, int err,
  * @ring_mfn: mfn of ring to grant
 
  * Grant access to the given @ring_mfn to the peer of the given device.  Return
- * 0 on success, or -errno on error.  On error, the device will switch to
- * XenbusStateClosing, and the error will be saved in the store.
+ * a grant reference on success, or -errno on error. On error, the device will
+ * switch to XenbusStateClosing, and the error will be saved in the store.
  */
 int xenbus_grant_ring(struct xenbus_device *dev, unsigned long ring_mfn)
 {
index 3c0a74b3e9b15af5355c8619294805f59030f75d..564b31584860432634a898a8fce9c7dc155a6662 100644 (file)
@@ -297,9 +297,13 @@ void xenbus_dev_shutdown(struct device *_dev)
 EXPORT_SYMBOL_GPL(xenbus_dev_shutdown);
 
 int xenbus_register_driver_common(struct xenbus_driver *drv,
-                                 struct xen_bus_type *bus)
+                                 struct xen_bus_type *bus,
+                                 struct module *owner, const char *mod_name)
 {
+       drv->driver.name = drv->name ? drv->name : drv->ids[0].devicetype;
        drv->driver.bus = &bus->bus;
+       drv->driver.owner = owner;
+       drv->driver.mod_name = mod_name;
 
        return driver_register(&drv->driver);
 }
index 1085ec294a1987a5620b24c4a2e120528d13cac0..c9ec7ca1f7ab6f4e3f78099c434d2533f0881b2f 100644 (file)
@@ -60,7 +60,9 @@ extern int xenbus_match(struct device *_dev, struct device_driver *_drv);
 extern int xenbus_dev_probe(struct device *_dev);
 extern int xenbus_dev_remove(struct device *_dev);
 extern int xenbus_register_driver_common(struct xenbus_driver *drv,
-                                        struct xen_bus_type *bus);
+                                        struct xen_bus_type *bus,
+                                        struct module *owner,
+                                        const char *mod_name);
 extern int xenbus_probe_node(struct xen_bus_type *bus,
                             const char *type,
                             const char *nodename);
index 5125dce11a6083da92fc5942a09c2aa786f181d8..04f7f85a5edf88ae21a01c6acae092b3a17c5a83 100644 (file)
@@ -234,13 +234,15 @@ int xenbus_dev_is_online(struct xenbus_device *dev)
 }
 EXPORT_SYMBOL_GPL(xenbus_dev_is_online);
 
-int xenbus_register_backend(struct xenbus_driver *drv)
+int __xenbus_register_backend(struct xenbus_driver *drv, struct module *owner,
+                             const char *mod_name)
 {
        drv->read_otherend_details = read_frontend_details;
 
-       return xenbus_register_driver_common(drv, &xenbus_backend);
+       return xenbus_register_driver_common(drv, &xenbus_backend,
+                                            owner, mod_name);
 }
-EXPORT_SYMBOL_GPL(xenbus_register_backend);
+EXPORT_SYMBOL_GPL(__xenbus_register_backend);
 
 static int backend_probe_and_watch(struct notifier_block *notifier,
                                   unsigned long event,
index cb385c10d2b15679729810dd24e5c9bb3cd9117c..bcb53bdc469c43a66914eec1f63acc05936d482f 100644 (file)
@@ -317,13 +317,15 @@ static void wait_for_devices(struct xenbus_driver *xendrv)
                         print_device_status);
 }
 
-int xenbus_register_frontend(struct xenbus_driver *drv)
+int __xenbus_register_frontend(struct xenbus_driver *drv, struct module *owner,
+                              const char *mod_name)
 {
        int ret;
 
        drv->read_otherend_details = read_backend_details;
 
-       ret = xenbus_register_driver_common(drv, &xenbus_frontend);
+       ret = xenbus_register_driver_common(drv, &xenbus_frontend,
+                                           owner, mod_name);
        if (ret)
                return ret;
 
@@ -332,7 +334,7 @@ int xenbus_register_frontend(struct xenbus_driver *drv)
 
        return 0;
 }
-EXPORT_SYMBOL_GPL(xenbus_register_frontend);
+EXPORT_SYMBOL_GPL(__xenbus_register_frontend);
 
 static DECLARE_WAIT_QUEUE_HEAD(backend_state_wq);
 static int backend_state;
index 0862d34cf7d1068db9e0d926646b431bf7c2fd4b..e297e1b52636dadb9bf3f3acb2102c079e73e0e6 100644 (file)
@@ -232,6 +232,6 @@ targets := $(fw-shipped-) $(patsubst $(obj)/%,%, \
 
 # Without this, built-in.o won't be created when it's empty, and the
 # final vmlinux link will fail.
-obj-n := dummy
+obj- := dummy
 
 hostprogs-y := ihex2fw
index d51ec9fafcc81d097924a7c3472a406f1b75048c..47db55aee7f2d1ad233c209a7be54ea1f1e58466 100644 (file)
@@ -65,8 +65,8 @@ static struct p9_fid *v9fs_fid_find(struct dentry *dentry, kuid_t uid, int any)
 {
        struct p9_fid *fid, *ret;
 
-       p9_debug(P9_DEBUG_VFS, " dentry: %s (%p) uid %d any %d\n",
-                dentry->d_name.name, dentry, from_kuid(&init_user_ns, uid),
+       p9_debug(P9_DEBUG_VFS, " dentry: %pd (%p) uid %d any %d\n",
+                dentry, dentry, from_kuid(&init_user_ns, uid),
                 any);
        ret = NULL;
        /* we'll recheck under lock if there's anything to look in */
index cc1cfae726b38fdc645fc7af79b4879371727b0a..eb14e055ea83e8509e7ea6ae569e3c1966d3b896 100644 (file)
@@ -266,8 +266,8 @@ v9fs_direct_IO(int rw, struct kiocb *iocb, struct iov_iter *iter, loff_t pos)
         * Now that we do caching with cache mode enabled, We need
         * to support direct IO
         */
-       p9_debug(P9_DEBUG_VFS, "v9fs_direct_IO: v9fs_direct_IO (%s) off/no(%lld/%lu) EINVAL\n",
-                iocb->ki_filp->f_path.dentry->d_name.name,
+       p9_debug(P9_DEBUG_VFS, "v9fs_direct_IO: v9fs_direct_IO (%pD) off/no(%lld/%lu) EINVAL\n",
+                iocb->ki_filp,
                 (long long)pos, iter->nr_segs);
 
        return -EINVAL;
index b03dd23feda8104d70536b514ec996fa612c5b89..a345b2d659cc8ac638ddb8dbd2d39535e442ec4b 100644 (file)
@@ -49,8 +49,8 @@
  */
 static int v9fs_cached_dentry_delete(const struct dentry *dentry)
 {
-       p9_debug(P9_DEBUG_VFS, " dentry: %s (%p)\n",
-                dentry->d_name.name, dentry);
+       p9_debug(P9_DEBUG_VFS, " dentry: %pd (%p)\n",
+                dentry, dentry);
 
        /* Don't cache negative dentries */
        if (!dentry->d_inode)
@@ -67,8 +67,8 @@ static int v9fs_cached_dentry_delete(const struct dentry *dentry)
 static void v9fs_dentry_release(struct dentry *dentry)
 {
        struct hlist_node *p, *n;
-       p9_debug(P9_DEBUG_VFS, " dentry: %s (%p)\n",
-                dentry->d_name.name, dentry);
+       p9_debug(P9_DEBUG_VFS, " dentry: %pd (%p)\n",
+                dentry, dentry);
        hlist_for_each_safe(p, n, (struct hlist_head *)&dentry->d_fsdata)
                p9_client_clunk(hlist_entry(p, struct p9_fid, dlist));
        dentry->d_fsdata = NULL;
index 0b3bfa303ddaddb0ae5cd8be8fe7ac6bc65257f1..4f1151088ebe8779da1af2173818c0088afb2cd0 100644 (file)
@@ -116,7 +116,7 @@ static int v9fs_dir_readdir(struct file *file, struct dir_context *ctx)
        int reclen = 0;
        struct p9_rdir *rdir;
 
-       p9_debug(P9_DEBUG_VFS, "name %s\n", file->f_path.dentry->d_name.name);
+       p9_debug(P9_DEBUG_VFS, "name %pD\n", file);
        fid = file->private_data;
 
        buflen = fid->clnt->msize - P9_IOHDRSZ;
@@ -172,7 +172,7 @@ static int v9fs_dir_readdir_dotl(struct file *file, struct dir_context *ctx)
        struct p9_rdir *rdir;
        struct p9_dirent curdirent;
 
-       p9_debug(P9_DEBUG_VFS, "name %s\n", file->f_path.dentry->d_name.name);
+       p9_debug(P9_DEBUG_VFS, "name %pD\n", file);
        fid = file->private_data;
 
        buflen = fid->clnt->msize - P9_READDIRHDRSZ;
index 520c11c2dcca4c9ff31a591600ca0c8ced52481c..5594505e6e730eac98c5b2a2f786d00b946a987b 100644 (file)
@@ -301,8 +301,8 @@ static int v9fs_file_lock_dotl(struct file *filp, int cmd, struct file_lock *fl)
        struct inode *inode = file_inode(filp);
        int ret = -ENOLCK;
 
-       p9_debug(P9_DEBUG_VFS, "filp: %p cmd:%d lock: %p name: %s\n",
-                filp, cmd, fl, filp->f_path.dentry->d_name.name);
+       p9_debug(P9_DEBUG_VFS, "filp: %p cmd:%d lock: %p name: %pD\n",
+                filp, cmd, fl, filp);
 
        /* No mandatory locks */
        if (__mandatory_lock(inode) && fl->fl_type != F_UNLCK)
@@ -337,8 +337,8 @@ static int v9fs_file_flock_dotl(struct file *filp, int cmd,
        struct inode *inode = file_inode(filp);
        int ret = -ENOLCK;
 
-       p9_debug(P9_DEBUG_VFS, "filp: %p cmd:%d lock: %p name: %s\n",
-                filp, cmd, fl, filp->f_path.dentry->d_name.name);
+       p9_debug(P9_DEBUG_VFS, "filp: %p cmd:%d lock: %p name: %pD\n",
+                filp, cmd, fl, filp);
 
        /* No mandatory locks */
        if (__mandatory_lock(inode) && fl->fl_type != F_UNLCK)
index 7fa4f7a7653d3f73765de06c58bba9c24eedbe9a..296482fc77a9dcdcc8f1a4b829863c73daff2d16 100644 (file)
@@ -648,7 +648,7 @@ v9fs_create(struct v9fs_session_info *v9ses, struct inode *dir,
        struct p9_fid *dfid, *ofid, *fid;
        struct inode *inode;
 
-       p9_debug(P9_DEBUG_VFS, "name %s\n", dentry->d_name.name);
+       p9_debug(P9_DEBUG_VFS, "name %pd\n", dentry);
 
        err = 0;
        ofid = NULL;
@@ -755,7 +755,7 @@ static int v9fs_vfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode
        struct p9_fid *fid;
        struct v9fs_session_info *v9ses;
 
-       p9_debug(P9_DEBUG_VFS, "name %s\n", dentry->d_name.name);
+       p9_debug(P9_DEBUG_VFS, "name %pd\n", dentry);
        err = 0;
        v9ses = v9fs_inode2v9ses(dir);
        perm = unixmode2p9mode(v9ses, mode | S_IFDIR);
@@ -791,8 +791,8 @@ struct dentry *v9fs_vfs_lookup(struct inode *dir, struct dentry *dentry,
        struct inode *inode;
        char *name;
 
-       p9_debug(P9_DEBUG_VFS, "dir: %p dentry: (%s) %p flags: %x\n",
-                dir, dentry->d_name.name, dentry, flags);
+       p9_debug(P9_DEBUG_VFS, "dir: %p dentry: (%pd) %p flags: %x\n",
+                dir, dentry, dentry, flags);
 
        if (dentry->d_name.len > NAME_MAX)
                return ERR_PTR(-ENAMETOOLONG);
@@ -1239,7 +1239,7 @@ static int v9fs_readlink(struct dentry *dentry, char *buffer, int buflen)
        struct p9_fid *fid;
        struct p9_wstat *st;
 
-       p9_debug(P9_DEBUG_VFS, " %s\n", dentry->d_name.name);
+       p9_debug(P9_DEBUG_VFS, " %pd\n", dentry);
        retval = -EPERM;
        v9ses = v9fs_dentry2v9ses(dentry);
        fid = v9fs_fid_lookup(dentry);
@@ -1262,8 +1262,8 @@ static int v9fs_readlink(struct dentry *dentry, char *buffer, int buflen)
        retval = min(strlen(st->extension)+1, (size_t)buflen);
        memcpy(buffer, st->extension, retval);
 
-       p9_debug(P9_DEBUG_VFS, "%s -> %s (%.*s)\n",
-                dentry->d_name.name, st->extension, buflen, buffer);
+       p9_debug(P9_DEBUG_VFS, "%pd -> %s (%.*s)\n",
+                dentry, st->extension, buflen, buffer);
 
 done:
        p9stat_free(st);
@@ -1283,7 +1283,7 @@ static void *v9fs_vfs_follow_link(struct dentry *dentry, struct nameidata *nd)
        int len = 0;
        char *link = __getname();
 
-       p9_debug(P9_DEBUG_VFS, "%s\n", dentry->d_name.name);
+       p9_debug(P9_DEBUG_VFS, "%pd\n", dentry);
 
        if (!link)
                link = ERR_PTR(-ENOMEM);
@@ -1314,8 +1314,8 @@ v9fs_vfs_put_link(struct dentry *dentry, struct nameidata *nd, void *p)
 {
        char *s = nd_get_link(nd);
 
-       p9_debug(P9_DEBUG_VFS, " %s %s\n",
-                dentry->d_name.name, IS_ERR(s) ? "<error>" : s);
+       p9_debug(P9_DEBUG_VFS, " %pd %s\n",
+                dentry, IS_ERR(s) ? "<error>" : s);
        if (!IS_ERR(s))
                __putname(s);
 }
@@ -1364,8 +1364,8 @@ static int v9fs_vfs_mkspecial(struct inode *dir, struct dentry *dentry,
 static int
 v9fs_vfs_symlink(struct inode *dir, struct dentry *dentry, const char *symname)
 {
-       p9_debug(P9_DEBUG_VFS, " %lu,%s,%s\n",
-                dir->i_ino, dentry->d_name.name, symname);
+       p9_debug(P9_DEBUG_VFS, " %lu,%pd,%s\n",
+                dir->i_ino, dentry, symname);
 
        return v9fs_vfs_mkspecial(dir, dentry, P9_DMSYMLINK, symname);
 }
@@ -1386,8 +1386,8 @@ v9fs_vfs_link(struct dentry *old_dentry, struct inode *dir,
        char *name;
        struct p9_fid *oldfid;
 
-       p9_debug(P9_DEBUG_VFS, " %lu,%s,%s\n",
-                dir->i_ino, dentry->d_name.name, old_dentry->d_name.name);
+       p9_debug(P9_DEBUG_VFS, " %lu,%pd,%pd\n",
+                dir->i_ino, dentry, old_dentry);
 
        oldfid = v9fs_fid_clone(old_dentry);
        if (IS_ERR(oldfid))
@@ -1428,8 +1428,8 @@ v9fs_vfs_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, dev_t rde
        char *name;
        u32 perm;
 
-       p9_debug(P9_DEBUG_VFS, " %lu,%s mode: %hx MAJOR: %u MINOR: %u\n",
-                dir->i_ino, dentry->d_name.name, mode,
+       p9_debug(P9_DEBUG_VFS, " %lu,%pd mode: %hx MAJOR: %u MINOR: %u\n",
+                dir->i_ino, dentry, mode,
                 MAJOR(rdev), MINOR(rdev));
 
        if (!new_valid_dev(rdev))
index 1fa85aae24df0c0255934a2016feea8aba1d4fc1..02b64f4e576ac48aa2f3310be3634e65c28a6079 100644 (file)
@@ -393,7 +393,7 @@ static int v9fs_vfs_mkdir_dotl(struct inode *dir,
        struct dentry *dir_dentry;
        struct posix_acl *dacl = NULL, *pacl = NULL;
 
-       p9_debug(P9_DEBUG_VFS, "name %s\n", dentry->d_name.name);
+       p9_debug(P9_DEBUG_VFS, "name %pd\n", dentry);
        err = 0;
        v9ses = v9fs_inode2v9ses(dir);
 
@@ -767,8 +767,8 @@ v9fs_vfs_link_dotl(struct dentry *old_dentry, struct inode *dir,
        struct p9_fid *dfid, *oldfid;
        struct v9fs_session_info *v9ses;
 
-       p9_debug(P9_DEBUG_VFS, "dir ino: %lu, old_name: %s, new_name: %s\n",
-                dir->i_ino, old_dentry->d_name.name, dentry->d_name.name);
+       p9_debug(P9_DEBUG_VFS, "dir ino: %lu, old_name: %pd, new_name: %pd\n",
+                dir->i_ino, old_dentry, dentry);
 
        v9ses = v9fs_inode2v9ses(dir);
        dir_dentry = dentry->d_parent;
@@ -917,7 +917,7 @@ v9fs_vfs_follow_link_dotl(struct dentry *dentry, struct nameidata *nd)
        char *link = __getname();
        char *target;
 
-       p9_debug(P9_DEBUG_VFS, "%s\n", dentry->d_name.name);
+       p9_debug(P9_DEBUG_VFS, "%pd\n", dentry);
 
        if (!link) {
                link = ERR_PTR(-ENOMEM);
index 406b29836b19ebe3b8d3196dc51109c6491eb684..abc853968fed7307691aa7593f94b3b310cb80ab 100644 (file)
@@ -10,8 +10,6 @@
 
 #include "affs.h"
 
-extern struct timezone sys_tz;
-
 static char ErrorBuffer[256];
 
 /*
index a7fe57d2cd9a0aa6a59df2cd90778127ebc2bbc3..1ed590aafecf744884c3e55af7cd9627d1c729f8 100644 (file)
@@ -584,11 +584,14 @@ affs_extent_file_ofs(struct inode *inode, u32 newsize)
                bh->b_state &= ~(1UL << BH_New);
                mark_buffer_dirty_inode(bh, inode);
                if (prev_bh) {
-                       u32 tmp = be32_to_cpu(AFFS_DATA_HEAD(prev_bh)->next);
-                       if (tmp)
-                               affs_warning(sb, "extent_file_ofs", "next block already set for %d (%d)", bidx, tmp);
+                       u32 tmp_next = be32_to_cpu(AFFS_DATA_HEAD(prev_bh)->next);
+
+                       if (tmp_next)
+                               affs_warning(sb, "extent_file_ofs",
+                                            "next block already set for %d (%d)",
+                                            bidx, tmp_next);
                        AFFS_DATA_HEAD(prev_bh)->next = cpu_to_be32(bh->b_blocknr);
-                       affs_adjust_checksum(prev_bh, bh->b_blocknr - tmp);
+                       affs_adjust_checksum(prev_bh, bh->b_blocknr - tmp_next);
                        mark_buffer_dirty_inode(prev_bh, inode);
                        affs_brelse(prev_bh);
                }
@@ -727,11 +730,14 @@ static int affs_write_end_ofs(struct file *file, struct address_space *mapping,
                        AFFS_DATA_HEAD(bh)->next = 0;
                        bh->b_state &= ~(1UL << BH_New);
                        if (prev_bh) {
-                               u32 tmp = be32_to_cpu(AFFS_DATA_HEAD(prev_bh)->next);
-                               if (tmp)
-                                       affs_warning(sb, "commit_write_ofs", "next block already set for %d (%d)", bidx, tmp);
+                               u32 tmp_next = be32_to_cpu(AFFS_DATA_HEAD(prev_bh)->next);
+
+                               if (tmp_next)
+                                       affs_warning(sb, "commit_write_ofs",
+                                                    "next block already set for %d (%d)",
+                                                    bidx, tmp_next);
                                AFFS_DATA_HEAD(prev_bh)->next = cpu_to_be32(bh->b_blocknr);
-                               affs_adjust_checksum(prev_bh, bh->b_blocknr - tmp);
+                               affs_adjust_checksum(prev_bh, bh->b_blocknr - tmp_next);
                                mark_buffer_dirty_inode(prev_bh, inode);
                        }
                }
@@ -758,11 +764,14 @@ static int affs_write_end_ofs(struct file *file, struct address_space *mapping,
                        AFFS_DATA_HEAD(bh)->next = 0;
                        bh->b_state &= ~(1UL << BH_New);
                        if (prev_bh) {
-                               u32 tmp = be32_to_cpu(AFFS_DATA_HEAD(prev_bh)->next);
-                               if (tmp)
-                                       affs_warning(sb, "commit_write_ofs", "next block already set for %d (%d)", bidx, tmp);
+                               u32 tmp_next = be32_to_cpu(AFFS_DATA_HEAD(prev_bh)->next);
+
+                               if (tmp_next)
+                                       affs_warning(sb, "commit_write_ofs",
+                                                    "next block already set for %d (%d)",
+                                                    bidx, tmp_next);
                                AFFS_DATA_HEAD(prev_bh)->next = cpu_to_be32(bh->b_blocknr);
-                               affs_adjust_checksum(prev_bh, bh->b_blocknr - tmp);
+                               affs_adjust_checksum(prev_bh, bh->b_blocknr - tmp_next);
                                mark_buffer_dirty_inode(prev_bh, inode);
                        }
                } else if (be32_to_cpu(AFFS_DATA_HEAD(bh)->size) < tmp)
@@ -842,12 +851,12 @@ affs_truncate(struct inode *inode)
                struct address_space *mapping = inode->i_mapping;
                struct page *page;
                void *fsdata;
-               loff_t size = inode->i_size;
+               loff_t isize = inode->i_size;
                int res;
 
-               res = mapping->a_ops->write_begin(NULL, mapping, size, 0, 0, &page, &fsdata);
+               res = mapping->a_ops->write_begin(NULL, mapping, isize, 0, 0, &page, &fsdata);
                if (!res)
-                       res = mapping->a_ops->write_end(NULL, mapping, size, 0, 0, page, fsdata);
+                       res = mapping->a_ops->write_end(NULL, mapping, isize, 0, 0, page, fsdata);
                else
                        inode->i_size = AFFS_I(inode)->mmu_private;
                mark_inode_dirty(inode);
index bec2d1a0c91c3e8ac62eb40a706a3bb704fd404e..e217c511459bbfdd0fe36e745cf2a0c7fe6d2bd2 100644 (file)
 #include "affs.h"
 
 extern const struct inode_operations affs_symlink_inode_operations;
-extern struct timezone sys_tz;
 
 struct inode *affs_iget(struct super_block *sb, unsigned long ino)
 {
        struct affs_sb_info     *sbi = AFFS_SB(sb);
        struct buffer_head      *bh;
-       struct affs_head        *head;
        struct affs_tail        *tail;
        struct inode            *inode;
        u32                      block;
@@ -49,7 +47,6 @@ struct inode *affs_iget(struct super_block *sb, unsigned long ino)
                goto bad_inode;
        }
 
-       head = AFFS_HEAD(bh);
        tail = AFFS_TAIL(sb, bh);
        prot = be32_to_cpu(tail->protect);
 
index 51f1a95bff738e61f7b2600ee6584228f309c76c..f754ab68a840a22d1d9eae18f78706a8537f07ea 100644 (file)
@@ -20,8 +20,6 @@
 #include <linux/writeback.h>
 #include "affs.h"
 
-extern struct timezone sys_tz;
-
 static int affs_statfs(struct dentry *dentry, struct kstatfs *buf);
 static int affs_remount (struct super_block *sb, int *flags, char *data);
 
@@ -308,7 +306,6 @@ static int affs_fill_super(struct super_block *sb, void *data, int silent)
        u32                      chksum;
        int                      num_bm;
        int                      i, j;
-       s32                      key;
        kuid_t                   uid;
        kgid_t                   gid;
        int                      reserved;
@@ -367,7 +364,7 @@ static int affs_fill_super(struct super_block *sb, void *data, int silent)
                i = j = blocksize;
                size = size / (blocksize / 512);
        }
-       for (blocksize = i, key = 0; blocksize <= j; blocksize <<= 1, size >>= 1) {
+       for (blocksize = i; blocksize <= j; blocksize <<= 1, size >>= 1) {
                sbi->s_root_block = root_block;
                if (root_block < 0)
                        sbi->s_root_block = (reserved + size - 1) / 2;
@@ -399,7 +396,6 @@ static int affs_fill_super(struct super_block *sb, void *data, int silent)
                            be32_to_cpu(AFFS_ROOT_TAIL(sb, root_bh)->stype) == ST_ROOT) {
                                sbi->s_hashsize    = blocksize / 4 - 56;
                                sbi->s_root_block += num_bm;
-                               key                        = 1;
                                goto got_root;
                        }
                        affs_brelse(root_bh);
index 529300327f4574d2dc36345be3c7398442548e08..a1645b88fe8a47d9a54fde42f1e5084932c96b94 100644 (file)
@@ -669,7 +669,6 @@ static int afs_d_revalidate(struct dentry *dentry, unsigned int flags)
 
 out_valid:
        dentry->d_fsdata = dir_version;
-out_skip:
        dput(parent);
        key_put(key);
        _leave(" = 1 [valid]");
@@ -682,10 +681,6 @@ not_found:
        spin_unlock(&dentry->d_lock);
 
 out_bad:
-       /* don't unhash if we have submounts */
-       if (check_submounts_and_drop(dentry) != 0)
-               goto out_skip;
-
        _debug("dropping dentry %s/%s",
               parent->d_name.name, dentry->d_name.name);
        dput(parent);
index b6df2e83809f4ac81ed5b3d02f944ac7f32d9de8..52976785a32caed097d9bb10f9990557189bbe77 100644 (file)
@@ -130,7 +130,6 @@ static int afs_vlocation_access_vl_by_id(struct afs_vlocation *vl,
                                        /* second+ BUSY - sleep a little bit */
                                        set_current_state(TASK_UNINTERRUPTIBLE);
                                        schedule_timeout(1);
-                                       __set_current_state(TASK_RUNNING);
                                }
                                continue;
                        }
index 9e359fb20c0a5cec2b344fff4ef0b64844f0850d..8e98cf954babb8944a32fdc58fd3c38760933a5a 100644 (file)
@@ -79,6 +79,10 @@ struct autofs_info {
 };
 
 #define AUTOFS_INF_EXPIRING    (1<<0) /* dentry is in the process of expiring */
+#define AUTOFS_INF_NO_RCU      (1<<1) /* the dentry is being considered
+                                       * for expiry, so RCU_walk is
+                                       * not permitted
+                                       */
 #define AUTOFS_INF_PENDING     (1<<2) /* dentry pending mount */
 
 struct autofs_wait_queue {
@@ -148,7 +152,7 @@ void autofs4_free_ino(struct autofs_info *);
 
 /* Expiration */
 int is_autofs4_dentry(struct dentry *);
-int autofs4_expire_wait(struct dentry *dentry);
+int autofs4_expire_wait(struct dentry *dentry, int rcu_walk);
 int autofs4_expire_run(struct super_block *, struct vfsmount *,
                        struct autofs_sb_info *,
                        struct autofs_packet_expire __user *);
index 5b570b6efa280bfdb4b4e9dc930fb6ba6041e3ad..aaf96cb25452cf04a5d7a47f2b506486e67cd502 100644 (file)
@@ -450,7 +450,7 @@ static int autofs_dev_ioctl_requester(struct file *fp,
        ino = autofs4_dentry_ino(path.dentry);
        if (ino) {
                err = 0;
-               autofs4_expire_wait(path.dentry);
+               autofs4_expire_wait(path.dentry, 0);
                spin_lock(&sbi->fs_lock);
                param->requester.uid = from_kuid_munged(current_user_ns(), ino->uid);
                param->requester.gid = from_kgid_munged(current_user_ns(), ino->gid);
index a7be57e39be78791930c2dc362507d53e9ec6174..683a5b9ce22a372d023bcf998f614afc3d284257 100644 (file)
@@ -30,12 +30,6 @@ static inline int autofs4_can_expire(struct dentry *dentry,
                /* Too young to die */
                if (!timeout || time_after(ino->last_used + timeout, now))
                        return 0;
-
-               /* update last_used here :-
-                  - obviously makes sense if it is in use now
-                  - less obviously, prevents rapid-fire expire
-                    attempts if expire fails the first time */
-               ino->last_used = now;
        }
        return 1;
 }
@@ -255,12 +249,6 @@ static int autofs4_tree_busy(struct vfsmount *mnt,
                        struct autofs_info *ino = autofs4_dentry_ino(p);
                        unsigned int ino_count = atomic_read(&ino->count);
 
-                       /*
-                        * Clean stale dentries below that have not been
-                        * invalidated after a mount fail during lookup
-                        */
-                       d_invalidate(p);
-
                        /* allow for dget above and top is already dgot */
                        if (p == top)
                                ino_count += 2;
@@ -333,10 +321,19 @@ struct dentry *autofs4_expire_direct(struct super_block *sb,
        if (ino->flags & AUTOFS_INF_PENDING)
                goto out;
        if (!autofs4_direct_busy(mnt, root, timeout, do_now)) {
-               ino->flags |= AUTOFS_INF_EXPIRING;
-               init_completion(&ino->expire_complete);
+               ino->flags |= AUTOFS_INF_NO_RCU;
                spin_unlock(&sbi->fs_lock);
-               return root;
+               synchronize_rcu();
+               spin_lock(&sbi->fs_lock);
+               if (!autofs4_direct_busy(mnt, root, timeout, do_now)) {
+                       ino->flags |= AUTOFS_INF_EXPIRING;
+                       smp_mb();
+                       ino->flags &= ~AUTOFS_INF_NO_RCU;
+                       init_completion(&ino->expire_complete);
+                       spin_unlock(&sbi->fs_lock);
+                       return root;
+               }
+               ino->flags &= ~AUTOFS_INF_NO_RCU;
        }
 out:
        spin_unlock(&sbi->fs_lock);
@@ -345,6 +342,89 @@ out:
        return NULL;
 }
 
+/* Check if 'dentry' should expire, or return a nearby
+ * dentry that is suitable.
+ * If returned dentry is different from arg dentry,
+ * then a dget() reference was taken, else not.
+ */
+static struct dentry *should_expire(struct dentry *dentry,
+                                   struct vfsmount *mnt,
+                                   unsigned long timeout,
+                                   int how)
+{
+       int do_now = how & AUTOFS_EXP_IMMEDIATE;
+       int exp_leaves = how & AUTOFS_EXP_LEAVES;
+       struct autofs_info *ino = autofs4_dentry_ino(dentry);
+       unsigned int ino_count;
+
+       /* No point expiring a pending mount */
+       if (ino->flags & AUTOFS_INF_PENDING)
+               return NULL;
+
+       /*
+        * Case 1: (i) indirect mount or top level pseudo direct mount
+        *         (autofs-4.1).
+        *         (ii) indirect mount with offset mount, check the "/"
+        *         offset (autofs-5.0+).
+        */
+       if (d_mountpoint(dentry)) {
+               DPRINTK("checking mountpoint %p %.*s",
+                       dentry, (int)dentry->d_name.len, dentry->d_name.name);
+
+               /* Can we umount this guy */
+               if (autofs4_mount_busy(mnt, dentry))
+                       return NULL;
+
+               /* Can we expire this guy */
+               if (autofs4_can_expire(dentry, timeout, do_now))
+                       return dentry;
+               return NULL;
+       }
+
+       if (dentry->d_inode && S_ISLNK(dentry->d_inode->i_mode)) {
+               DPRINTK("checking symlink %p %.*s",
+                       dentry, (int)dentry->d_name.len, dentry->d_name.name);
+               /*
+                * A symlink can't be "busy" in the usual sense so
+                * just check last used for expire timeout.
+                */
+               if (autofs4_can_expire(dentry, timeout, do_now))
+                       return dentry;
+               return NULL;
+       }
+
+       if (simple_empty(dentry))
+               return NULL;
+
+       /* Case 2: tree mount, expire iff entire tree is not busy */
+       if (!exp_leaves) {
+               /* Path walk currently on this dentry? */
+               ino_count = atomic_read(&ino->count) + 1;
+               if (d_count(dentry) > ino_count)
+                       return NULL;
+
+               if (!autofs4_tree_busy(mnt, dentry, timeout, do_now))
+                       return dentry;
+       /*
+        * Case 3: pseudo direct mount, expire individual leaves
+        *         (autofs-4.1).
+        */
+       } else {
+               /* Path walk currently on this dentry? */
+               struct dentry *expired;
+               ino_count = atomic_read(&ino->count) + 1;
+               if (d_count(dentry) > ino_count)
+                       return NULL;
+
+               expired = autofs4_check_leaves(mnt, dentry, timeout, do_now);
+               if (expired) {
+                       if (expired == dentry)
+                               dput(dentry);
+                       return expired;
+               }
+       }
+       return NULL;
+}
 /*
  * Find an eligible tree to time-out
  * A tree is eligible if :-
@@ -359,11 +439,8 @@ struct dentry *autofs4_expire_indirect(struct super_block *sb,
        unsigned long timeout;
        struct dentry *root = sb->s_root;
        struct dentry *dentry;
-       struct dentry *expired = NULL;
-       int do_now = how & AUTOFS_EXP_IMMEDIATE;
-       int exp_leaves = how & AUTOFS_EXP_LEAVES;
+       struct dentry *expired;
        struct autofs_info *ino;
-       unsigned int ino_count;
 
        if (!root)
                return NULL;
@@ -375,77 +452,28 @@ struct dentry *autofs4_expire_indirect(struct super_block *sb,
        while ((dentry = get_next_positive_subdir(dentry, root))) {
                spin_lock(&sbi->fs_lock);
                ino = autofs4_dentry_ino(dentry);
-               /* No point expiring a pending mount */
-               if (ino->flags & AUTOFS_INF_PENDING)
-                       goto next;
-
-               /*
-                * Case 1: (i) indirect mount or top level pseudo direct mount
-                *         (autofs-4.1).
-                *         (ii) indirect mount with offset mount, check the "/"
-                *         offset (autofs-5.0+).
-                */
-               if (d_mountpoint(dentry)) {
-                       DPRINTK("checking mountpoint %p %.*s",
-                               dentry, (int)dentry->d_name.len, dentry->d_name.name);
-
-                       /* Can we umount this guy */
-                       if (autofs4_mount_busy(mnt, dentry))
-                               goto next;
-
-                       /* Can we expire this guy */
-                       if (autofs4_can_expire(dentry, timeout, do_now)) {
-                               expired = dentry;
-                               goto found;
-                       }
-                       goto next;
-               }
-
-               if (dentry->d_inode && S_ISLNK(dentry->d_inode->i_mode)) {
-                       DPRINTK("checking symlink %p %.*s",
-                               dentry, (int)dentry->d_name.len, dentry->d_name.name);
-                       /*
-                        * A symlink can't be "busy" in the usual sense so
-                        * just check last used for expire timeout.
-                        */
-                       if (autofs4_can_expire(dentry, timeout, do_now)) {
-                               expired = dentry;
-                               goto found;
-                       }
-                       goto next;
+               if (ino->flags & AUTOFS_INF_NO_RCU)
+                       expired = NULL;
+               else
+                       expired = should_expire(dentry, mnt, timeout, how);
+               if (!expired) {
+                       spin_unlock(&sbi->fs_lock);
+                       continue;
                }
-
-               if (simple_empty(dentry))
-                       goto next;
-
-               /* Case 2: tree mount, expire iff entire tree is not busy */
-               if (!exp_leaves) {
-                       /* Path walk currently on this dentry? */
-                       ino_count = atomic_read(&ino->count) + 1;
-                       if (d_count(dentry) > ino_count)
-                               goto next;
-
-                       if (!autofs4_tree_busy(mnt, dentry, timeout, do_now)) {
-                               expired = dentry;
-                               goto found;
-                       }
-               /*
-                * Case 3: pseudo direct mount, expire individual leaves
-                *         (autofs-4.1).
-                */
-               } else {
-                       /* Path walk currently on this dentry? */
-                       ino_count = atomic_read(&ino->count) + 1;
-                       if (d_count(dentry) > ino_count)
-                               goto next;
-
-                       expired = autofs4_check_leaves(mnt, dentry, timeout, do_now);
-                       if (expired) {
+               ino = autofs4_dentry_ino(expired);
+               ino->flags |= AUTOFS_INF_NO_RCU;
+               spin_unlock(&sbi->fs_lock);
+               synchronize_rcu();
+               spin_lock(&sbi->fs_lock);
+               if (should_expire(expired, mnt, timeout, how)) {
+                       if (expired != dentry)
                                dput(dentry);
-                               goto found;
-                       }
+                       goto found;
                }
-next:
+
+               ino->flags &= ~AUTOFS_INF_NO_RCU;
+               if (expired != dentry)
+                       dput(expired);
                spin_unlock(&sbi->fs_lock);
        }
        return NULL;
@@ -453,8 +481,9 @@ next:
 found:
        DPRINTK("returning %p %.*s",
                expired, (int)expired->d_name.len, expired->d_name.name);
-       ino = autofs4_dentry_ino(expired);
        ino->flags |= AUTOFS_INF_EXPIRING;
+       smp_mb();
+       ino->flags &= ~AUTOFS_INF_NO_RCU;
        init_completion(&ino->expire_complete);
        spin_unlock(&sbi->fs_lock);
        spin_lock(&sbi->lookup_lock);
@@ -467,13 +496,18 @@ found:
        return expired;
 }
 
-int autofs4_expire_wait(struct dentry *dentry)
+int autofs4_expire_wait(struct dentry *dentry, int rcu_walk)
 {
        struct autofs_sb_info *sbi = autofs4_sbi(dentry->d_sb);
        struct autofs_info *ino = autofs4_dentry_ino(dentry);
        int status;
 
        /* Block on any pending expire */
+       if (!(ino->flags & (AUTOFS_INF_EXPIRING | AUTOFS_INF_NO_RCU)))
+               return 0;
+       if (rcu_walk)
+               return -ECHILD;
+
        spin_lock(&sbi->fs_lock);
        if (ino->flags & AUTOFS_INF_EXPIRING) {
                spin_unlock(&sbi->fs_lock);
@@ -525,6 +559,8 @@ int autofs4_expire_run(struct super_block *sb,
 
        spin_lock(&sbi->fs_lock);
        ino = autofs4_dentry_ino(dentry);
+       /* avoid rapid-fire expire attempts if expiry fails */
+       ino->last_used = now;
        ino->flags &= ~AUTOFS_INF_EXPIRING;
        complete_all(&ino->expire_complete);
        spin_unlock(&sbi->fs_lock);
@@ -551,6 +587,8 @@ int autofs4_do_expire_multi(struct super_block *sb, struct vfsmount *mnt,
                ret = autofs4_wait(sbi, dentry, NFY_EXPIRE);
 
                spin_lock(&sbi->fs_lock);
+               /* avoid rapid-fire expire attempts if expiry fails */
+               ino->last_used = now;
                ino->flags &= ~AUTOFS_INF_EXPIRING;
                complete_all(&ino->expire_complete);
                spin_unlock(&sbi->fs_lock);
index cdb25ebccc4c49c2ac2f4a4c17d998ae99f14941..d76d083f2f0687ccc1e3cea255f041154ae2f662 100644 (file)
@@ -210,7 +210,8 @@ next:
        return NULL;
 }
 
-static struct dentry *autofs4_lookup_expiring(struct dentry *dentry)
+static struct dentry *autofs4_lookup_expiring(struct dentry *dentry,
+                                             bool rcu_walk)
 {
        struct autofs_sb_info *sbi = autofs4_sbi(dentry->d_sb);
        struct dentry *parent = dentry->d_parent;
@@ -229,6 +230,11 @@ static struct dentry *autofs4_lookup_expiring(struct dentry *dentry)
                struct dentry *expiring;
                struct qstr *qstr;
 
+               if (rcu_walk) {
+                       spin_unlock(&sbi->lookup_lock);
+                       return ERR_PTR(-ECHILD);
+               }
+
                ino = list_entry(p, struct autofs_info, expiring);
                expiring = ino->dentry;
 
@@ -264,13 +270,15 @@ next:
        return NULL;
 }
 
-static int autofs4_mount_wait(struct dentry *dentry)
+static int autofs4_mount_wait(struct dentry *dentry, bool rcu_walk)
 {
        struct autofs_sb_info *sbi = autofs4_sbi(dentry->d_sb);
        struct autofs_info *ino = autofs4_dentry_ino(dentry);
        int status = 0;
 
        if (ino->flags & AUTOFS_INF_PENDING) {
+               if (rcu_walk)
+                       return -ECHILD;
                DPRINTK("waiting for mount name=%.*s",
                        dentry->d_name.len, dentry->d_name.name);
                status = autofs4_wait(sbi, dentry, NFY_MOUNT);
@@ -280,20 +288,22 @@ static int autofs4_mount_wait(struct dentry *dentry)
        return status;
 }
 
-static int do_expire_wait(struct dentry *dentry)
+static int do_expire_wait(struct dentry *dentry, bool rcu_walk)
 {
        struct dentry *expiring;
 
-       expiring = autofs4_lookup_expiring(dentry);
+       expiring = autofs4_lookup_expiring(dentry, rcu_walk);
+       if (IS_ERR(expiring))
+               return PTR_ERR(expiring);
        if (!expiring)
-               return autofs4_expire_wait(dentry);
+               return autofs4_expire_wait(dentry, rcu_walk);
        else {
                /*
                 * If we are racing with expire the request might not
                 * be quite complete, but the directory has been removed
                 * so it must have been successful, just wait for it.
                 */
-               autofs4_expire_wait(expiring);
+               autofs4_expire_wait(expiring, 0);
                autofs4_del_expiring(expiring);
                dput(expiring);
        }
@@ -345,7 +355,7 @@ static struct vfsmount *autofs4_d_automount(struct path *path)
         * and the directory was removed, so just go ahead and try
         * the mount.
         */
-       status = do_expire_wait(dentry);
+       status = do_expire_wait(dentry, 0);
        if (status && status != -EAGAIN)
                return NULL;
 
@@ -353,7 +363,7 @@ static struct vfsmount *autofs4_d_automount(struct path *path)
        spin_lock(&sbi->fs_lock);
        if (ino->flags & AUTOFS_INF_PENDING) {
                spin_unlock(&sbi->fs_lock);
-               status = autofs4_mount_wait(dentry);
+               status = autofs4_mount_wait(dentry, 0);
                if (status)
                        return ERR_PTR(status);
                goto done;
@@ -394,7 +404,7 @@ static struct vfsmount *autofs4_d_automount(struct path *path)
                }
                ino->flags |= AUTOFS_INF_PENDING;
                spin_unlock(&sbi->fs_lock);
-               status = autofs4_mount_wait(dentry);
+               status = autofs4_mount_wait(dentry, 0);
                spin_lock(&sbi->fs_lock);
                ino->flags &= ~AUTOFS_INF_PENDING;
                if (status) {
@@ -423,28 +433,46 @@ static int autofs4_d_manage(struct dentry *dentry, bool rcu_walk)
 
        /* The daemon never waits. */
        if (autofs4_oz_mode(sbi)) {
-               if (rcu_walk)
-                       return 0;
                if (!d_mountpoint(dentry))
                        return -EISDIR;
                return 0;
        }
 
-       /* We need to sleep, so we need pathwalk to be in ref-mode */
-       if (rcu_walk)
-               return -ECHILD;
-
        /* Wait for pending expires */
-       do_expire_wait(dentry);
+       if (do_expire_wait(dentry, rcu_walk) == -ECHILD)
+               return -ECHILD;
 
        /*
         * This dentry may be under construction so wait on mount
         * completion.
         */
-       status = autofs4_mount_wait(dentry);
+       status = autofs4_mount_wait(dentry, rcu_walk);
        if (status)
                return status;
 
+       if (rcu_walk) {
+               /* We don't need fs_lock in rcu_walk mode,
+                * just testing 'AUTOFS_INFO_NO_RCU' is enough.
+                * simple_empty() takes a spinlock, so leave it
+                * to last.
+                * We only return -EISDIR when certain this isn't
+                * a mount-trap.
+                */
+               struct inode *inode;
+               if (ino->flags & (AUTOFS_INF_EXPIRING | AUTOFS_INF_NO_RCU))
+                       return 0;
+               if (d_mountpoint(dentry))
+                       return 0;
+               inode = ACCESS_ONCE(dentry->d_inode);
+               if (inode && S_ISLNK(inode->i_mode))
+                       return -EISDIR;
+               if (list_empty(&dentry->d_subdirs))
+                       return 0;
+               if (!simple_empty(dentry))
+                       return -EISDIR;
+               return 0;
+       }
+
        spin_lock(&sbi->fs_lock);
        /*
         * If the dentry has been selected for expire while we slept
index 9c7faa8a9288ca3a015857ca885094eceb989e56..0826e91dacda31129e3d62faf3dd67350dfa30d1 100644 (file)
 /*
  * In memory structure of each btree node
  */
-typedef struct {
+struct befs_btree_node {
        befs_host_btree_nodehead head;  /* head of node converted to cpu byteorder */
        struct buffer_head *bh;
        befs_btree_nodehead *od_node;   /* on disk node */
-} befs_btree_node;
+};
 
 /* local constants */
 static const befs_off_t befs_bt_inval = 0xffffffffffffffffULL;
@@ -90,27 +90,30 @@ static const befs_off_t befs_bt_inval = 0xffffffffffffffffULL;
 /* local functions */
 static int befs_btree_seekleaf(struct super_block *sb, befs_data_stream * ds,
                               befs_btree_super * bt_super,
-                              befs_btree_node * this_node,
+                              struct befs_btree_node *this_node,
                               befs_off_t * node_off);
 
 static int befs_bt_read_super(struct super_block *sb, befs_data_stream * ds,
                              befs_btree_super * sup);
 
 static int befs_bt_read_node(struct super_block *sb, befs_data_stream * ds,
-                            befs_btree_node * node, befs_off_t node_off);
+                            struct befs_btree_node *node,
+                            befs_off_t node_off);
 
-static int befs_leafnode(befs_btree_node * node);
+static int befs_leafnode(struct befs_btree_node *node);
 
-static fs16 *befs_bt_keylen_index(befs_btree_node * node);
+static fs16 *befs_bt_keylen_index(struct befs_btree_node *node);
 
-static fs64 *befs_bt_valarray(befs_btree_node * node);
+static fs64 *befs_bt_valarray(struct befs_btree_node *node);
 
-static char *befs_bt_keydata(befs_btree_node * node);
+static char *befs_bt_keydata(struct befs_btree_node *node);
 
-static int befs_find_key(struct super_block *sb, befs_btree_node * node,
+static int befs_find_key(struct super_block *sb,
+                        struct befs_btree_node *node,
                         const char *findkey, befs_off_t * value);
 
-static char *befs_bt_get_key(struct super_block *sb, befs_btree_node * node,
+static char *befs_bt_get_key(struct super_block *sb,
+                            struct befs_btree_node *node,
                             int index, u16 * keylen);
 
 static int befs_compare_strings(const void *key1, int keylen1,
@@ -191,7 +194,7 @@ befs_bt_read_super(struct super_block *sb, befs_data_stream * ds,
 
 static int
 befs_bt_read_node(struct super_block *sb, befs_data_stream * ds,
-                 befs_btree_node * node, befs_off_t node_off)
+                 struct befs_btree_node *node, befs_off_t node_off)
 {
        uint off = 0;
 
@@ -247,7 +250,7 @@ int
 befs_btree_find(struct super_block *sb, befs_data_stream * ds,
                const char *key, befs_off_t * value)
 {
-       befs_btree_node *this_node = NULL;
+       struct befs_btree_node *this_node = NULL;
        befs_btree_super bt_super;
        befs_off_t node_off;
        int res;
@@ -260,11 +263,11 @@ befs_btree_find(struct super_block *sb, befs_data_stream * ds,
                goto error;
        }
 
-       this_node = kmalloc(sizeof (befs_btree_node),
+       this_node = kmalloc(sizeof(struct befs_btree_node),
                                                GFP_NOFS);
        if (!this_node) {
                befs_error(sb, "befs_btree_find() failed to allocate %zu "
-                          "bytes of memory", sizeof (befs_btree_node));
+                          "bytes of memory", sizeof(struct befs_btree_node));
                goto error;
        }
 
@@ -333,7 +336,7 @@ befs_btree_find(struct super_block *sb, befs_data_stream * ds,
  * Use binary search instead of a linear.
  */
 static int
-befs_find_key(struct super_block *sb, befs_btree_node * node,
+befs_find_key(struct super_block *sb, struct befs_btree_node *node,
              const char *findkey, befs_off_t * value)
 {
        int first, last, mid;
@@ -417,7 +420,7 @@ befs_btree_read(struct super_block *sb, befs_data_stream * ds,
                loff_t key_no, size_t bufsize, char *keybuf, size_t * keysize,
                befs_off_t * value)
 {
-       befs_btree_node *this_node;
+       struct befs_btree_node *this_node;
        befs_btree_super bt_super;
        befs_off_t node_off = 0;
        int cur_key;
@@ -436,9 +439,10 @@ befs_btree_read(struct super_block *sb, befs_data_stream * ds,
                goto error;
        }
 
-       if ((this_node = kmalloc(sizeof (befs_btree_node), GFP_NOFS)) == NULL) {
+       this_node = kmalloc(sizeof(struct befs_btree_node), GFP_NOFS);
+       if (this_node == NULL) {
                befs_error(sb, "befs_btree_read() failed to allocate %zu "
-                          "bytes of memory", sizeof (befs_btree_node));
+                          "bytes of memory", sizeof(struct befs_btree_node));
                goto error;
        }
 
@@ -545,7 +549,8 @@ befs_btree_read(struct super_block *sb, befs_data_stream * ds,
  */
 static int
 befs_btree_seekleaf(struct super_block *sb, befs_data_stream * ds,
-                   befs_btree_super * bt_super, befs_btree_node * this_node,
+                   befs_btree_super *bt_super,
+                   struct befs_btree_node *this_node,
                    befs_off_t * node_off)
 {
 
@@ -600,7 +605,7 @@ befs_btree_seekleaf(struct super_block *sb, befs_data_stream * ds,
  * Return 1 if leaf, 0 if interior
  */
 static int
-befs_leafnode(befs_btree_node * node)
+befs_leafnode(struct befs_btree_node *node)
 {
        /* all interior nodes (and only interior nodes) have an overflow node */
        if (node->head.overflow == befs_bt_inval)
@@ -623,7 +628,7 @@ befs_leafnode(befs_btree_node * node)
  * Except that rounding up to 8 works, and rounding up to 4 doesn't.
  */
 static fs16 *
-befs_bt_keylen_index(befs_btree_node * node)
+befs_bt_keylen_index(struct befs_btree_node *node)
 {
        const int keylen_align = 8;
        unsigned long int off =
@@ -644,7 +649,7 @@ befs_bt_keylen_index(befs_btree_node * node)
  * of the node pointed to by the node header
  */
 static fs64 *
-befs_bt_valarray(befs_btree_node * node)
+befs_bt_valarray(struct befs_btree_node *node)
 {
        void *keylen_index_start = (void *) befs_bt_keylen_index(node);
        size_t keylen_index_size = node->head.all_key_count * sizeof (fs16);
@@ -660,7 +665,7 @@ befs_bt_valarray(befs_btree_node * node)
  * of the node pointed to by the node header 
  */
 static char *
-befs_bt_keydata(befs_btree_node * node)
+befs_bt_keydata(struct befs_btree_node *node)
 {
        return (char *) ((void *) node->od_node + sizeof (befs_btree_nodehead));
 }
@@ -676,7 +681,7 @@ befs_bt_keydata(befs_btree_node * node)
  * Returns NULL on failure (bad input) and sets *@keylen = 0
  */
 static char *
-befs_bt_get_key(struct super_block *sb, befs_btree_node * node,
+befs_bt_get_key(struct super_block *sb, struct befs_btree_node *node,
                int index, u16 * keylen)
 {
        int prev_key_end;
index ca0ba15a73061fb61aaee9c4951ba6097d10544b..929dec08c348ec01ada445e218f8a1bde05d58f9 100644 (file)
@@ -256,11 +256,8 @@ static int load_aout_binary(struct linux_binprm * bprm)
                (current->mm->start_brk = N_BSSADDR(ex));
 
        retval = setup_arg_pages(bprm, STACK_TOP, EXSTACK_DEFAULT);
-       if (retval < 0) {
-               /* Someone check-me: is this error path enough? */
-               send_sig(SIGKILL, current, 0);
+       if (retval < 0)
                return retval;
-       }
 
        install_exec_creds(bprm);
 
@@ -278,17 +275,13 @@ static int load_aout_binary(struct linux_binprm * bprm)
                map_size = ex.a_text+ex.a_data;
 #endif
                error = vm_brk(text_addr & PAGE_MASK, map_size);
-               if (error != (text_addr & PAGE_MASK)) {
-                       send_sig(SIGKILL, current, 0);
+               if (error != (text_addr & PAGE_MASK))
                        return error;
-               }
 
                error = read_code(bprm->file, text_addr, pos,
                                  ex.a_text+ex.a_data);
-               if ((signed long)error < 0) {
-                       send_sig(SIGKILL, current, 0);
+               if ((signed long)error < 0)
                        return error;
-               }
        } else {
                if ((ex.a_text & 0xfff || ex.a_data & 0xfff) &&
                    (N_MAGIC(ex) != NMAGIC) && printk_ratelimit())
@@ -315,28 +308,22 @@ static int load_aout_binary(struct linux_binprm * bprm)
                        MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE | MAP_EXECUTABLE,
                        fd_offset);
 
-               if (error != N_TXTADDR(ex)) {
-                       send_sig(SIGKILL, current, 0);
+               if (error != N_TXTADDR(ex))
                        return error;
-               }
 
                error = vm_mmap(bprm->file, N_DATADDR(ex), ex.a_data,
                                PROT_READ | PROT_WRITE | PROT_EXEC,
                                MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE | MAP_EXECUTABLE,
                                fd_offset + ex.a_text);
-               if (error != N_DATADDR(ex)) {
-                       send_sig(SIGKILL, current, 0);
+               if (error != N_DATADDR(ex))
                        return error;
-               }
        }
 beyond_if:
        set_binfmt(&aout_format);
 
        retval = set_brk(current->mm->start_brk, current->mm->brk);
-       if (retval < 0) {
-               send_sig(SIGKILL, current, 0);
+       if (retval < 0)
                return retval;
-       }
 
        current->mm->start_stack =
                (unsigned long) create_aout_tables((char __user *) bprm->p, bprm);
index 3892c1a2324143498f3e62fc171a0f5cdc6c44c9..d8fc0605b9d23039b558cc4d1327a40c246caa09 100644 (file)
@@ -738,10 +738,8 @@ static int load_elf_binary(struct linux_binprm *bprm)
           change some of these later */
        retval = setup_arg_pages(bprm, randomize_stack_top(STACK_TOP),
                                 executable_stack);
-       if (retval < 0) {
-               send_sig(SIGKILL, current, 0);
+       if (retval < 0)
                goto out_free_dentry;
-       }
        
        current->mm->start_stack = bprm->p;
 
@@ -763,10 +761,8 @@ static int load_elf_binary(struct linux_binprm *bprm)
                           and clear the area.  */
                        retval = set_brk(elf_bss + load_bias,
                                         elf_brk + load_bias);
-                       if (retval) {
-                               send_sig(SIGKILL, current, 0);
+                       if (retval)
                                goto out_free_dentry;
-                       }
                        nbyte = ELF_PAGEOFFSET(elf_bss);
                        if (nbyte) {
                                nbyte = ELF_MIN_ALIGN - nbyte;
@@ -820,7 +816,6 @@ static int load_elf_binary(struct linux_binprm *bprm)
                error = elf_map(bprm->file, load_bias + vaddr, elf_ppnt,
                                elf_prot, elf_flags, 0);
                if (BAD_ADDR(error)) {
-                       send_sig(SIGKILL, current, 0);
                        retval = IS_ERR((void *)error) ?
                                PTR_ERR((void*)error) : -EINVAL;
                        goto out_free_dentry;
@@ -851,7 +846,6 @@ static int load_elf_binary(struct linux_binprm *bprm)
                    elf_ppnt->p_memsz > TASK_SIZE ||
                    TASK_SIZE - elf_ppnt->p_memsz < k) {
                        /* set_brk can never work. Avoid overflows. */
-                       send_sig(SIGKILL, current, 0);
                        retval = -EINVAL;
                        goto out_free_dentry;
                }
@@ -883,12 +877,9 @@ static int load_elf_binary(struct linux_binprm *bprm)
         * up getting placed where the bss needs to go.
         */
        retval = set_brk(elf_bss, elf_brk);
-       if (retval) {
-               send_sig(SIGKILL, current, 0);
+       if (retval)
                goto out_free_dentry;
-       }
        if (likely(elf_bss != elf_brk) && unlikely(padzero(elf_bss))) {
-               send_sig(SIGSEGV, current, 0);
                retval = -EFAULT; /* Nobody gets to see this, but.. */
                goto out_free_dentry;
        }
@@ -909,7 +900,6 @@ static int load_elf_binary(struct linux_binprm *bprm)
                        elf_entry += loc->interp_elf_ex.e_entry;
                }
                if (BAD_ADDR(elf_entry)) {
-                       force_sig(SIGSEGV, current);
                        retval = IS_ERR((void *)elf_entry) ?
                                        (int)elf_entry : -EINVAL;
                        goto out_free_dentry;
@@ -922,7 +912,6 @@ static int load_elf_binary(struct linux_binprm *bprm)
        } else {
                elf_entry = loc->elf_ex.e_entry;
                if (BAD_ADDR(elf_entry)) {
-                       force_sig(SIGSEGV, current);
                        retval = -EINVAL;
                        goto out_free_dentry;
                }
@@ -934,19 +923,15 @@ static int load_elf_binary(struct linux_binprm *bprm)
 
 #ifdef ARCH_HAS_SETUP_ADDITIONAL_PAGES
        retval = arch_setup_additional_pages(bprm, !!elf_interpreter);
-       if (retval < 0) {
-               send_sig(SIGKILL, current, 0);
+       if (retval < 0)
                goto out;
-       }
 #endif /* ARCH_HAS_SETUP_ADDITIONAL_PAGES */
 
        install_exec_creds(bprm);
        retval = create_elf_tables(bprm, &loc->elf_ex,
                          load_addr, interp_load_addr);
-       if (retval < 0) {
-               send_sig(SIGKILL, current, 0);
+       if (retval < 0)
                goto out;
-       }
        /* N.B. passed_fileno might not be initialized? */
        current->mm->end_code = end_code;
        current->mm->start_code = start_code;
index fe2a643ee005387719766b6bc4f3041cd410c4b2..d3634bfb7fe187b4de899e809188319c08b6ac23 100644 (file)
@@ -317,8 +317,8 @@ static int load_elf_fdpic_binary(struct linux_binprm *bprm)
                goto error;
 
        /* there's now no turning back... the old userspace image is dead,
-        * defunct, deceased, etc. after this point we have to exit via
-        * error_kill */
+        * defunct, deceased, etc.
+        */
        set_personality(PER_LINUX_FDPIC);
        if (elf_read_implies_exec(&exec_params.hdr, executable_stack))
                current->personality |= READ_IMPLIES_EXEC;
@@ -343,24 +343,22 @@ static int load_elf_fdpic_binary(struct linux_binprm *bprm)
 
        retval = setup_arg_pages(bprm, current->mm->start_stack,
                                 executable_stack);
-       if (retval < 0) {
-               send_sig(SIGKILL, current, 0);
-               goto error_kill;
-       }
+       if (retval < 0)
+               goto error;
 #endif
 
        /* load the executable and interpreter into memory */
        retval = elf_fdpic_map_file(&exec_params, bprm->file, current->mm,
                                    "executable");
        if (retval < 0)
-               goto error_kill;
+               goto error;
 
        if (interpreter_name) {
                retval = elf_fdpic_map_file(&interp_params, interpreter,
                                            current->mm, "interpreter");
                if (retval < 0) {
                        printk(KERN_ERR "Unable to load interpreter\n");
-                       goto error_kill;
+                       goto error;
                }
 
                allow_write_access(interpreter);
@@ -397,7 +395,7 @@ static int load_elf_fdpic_binary(struct linux_binprm *bprm)
        if (IS_ERR_VALUE(current->mm->start_brk)) {
                retval = current->mm->start_brk;
                current->mm->start_brk = 0;
-               goto error_kill;
+               goto error;
        }
 
        current->mm->brk = current->mm->start_brk;
@@ -410,7 +408,7 @@ static int load_elf_fdpic_binary(struct linux_binprm *bprm)
        install_exec_creds(bprm);
        if (create_elf_fdpic_tables(bprm, current->mm,
                                    &exec_params, &interp_params) < 0)
-               goto error_kill;
+               goto error;
 
        kdebug("- start_code  %lx", current->mm->start_code);
        kdebug("- end_code    %lx", current->mm->end_code);
@@ -449,12 +447,6 @@ error:
        kfree(interp_params.phdrs);
        kfree(interp_params.loadmap);
        return retval;
-
-       /* unrecoverable error - kill the process */
-error_kill:
-       send_sig(SIGSEGV, current, 0);
-       goto error;
-
 }
 
 /*****************************************************************************/
index b60500300dd7803e20655d50437aec7dfefeedec..fd8beb9657a2c66f406d3eacadae5ca95e65d805 100644 (file)
@@ -62,7 +62,22 @@ static struct file_system_type bm_fs_type;
 static struct vfsmount *bm_mnt;
 static int entry_count;
 
-/* 
+/*
+ * Max length of the register string.  Determined by:
+ *  - 7 delimiters
+ *  - name:   ~50 bytes
+ *  - type:   1 byte
+ *  - offset: 3 bytes (has to be smaller than BINPRM_BUF_SIZE)
+ *  - magic:  128 bytes (512 in escaped form)
+ *  - mask:   128 bytes (512 in escaped form)
+ *  - interp: ~50 bytes
+ *  - flags:  5 bytes
+ * Round that up a bit, and then back off to hold the internal data
+ * (like struct Node).
+ */
+#define MAX_REGISTER_LENGTH 1920
+
+/*
  * Check if we support the binfmt
  * if we do, return the node, else NULL
  * locking is done in load_misc_binary
@@ -279,7 +294,7 @@ static Node *create_entry(const char __user *buffer, size_t count)
 
        /* some sanity checks */
        err = -EINVAL;
-       if ((count < 11) || (count > 256))
+       if ((count < 11) || (count > MAX_REGISTER_LENGTH))
                goto out;
 
        err = -ENOMEM;
@@ -396,12 +411,12 @@ static int parse_command(const char __user *buffer, size_t count)
 {
        char s[4];
 
-       if (!count)
-               return 0;
        if (count > 3)
                return -EINVAL;
        if (copy_from_user(s, buffer, count))
                return -EFAULT;
+       if (!count)
+               return 0;
        if (s[count-1] == '\n')
                count--;
        if (count == 1 && s[0] == '0')
index fbd76ded9a34b3260a5e794115fff0312b3c6e08..4dabeb893b7c18cced67230fd8fbcc36c677983b 100644 (file)
@@ -74,6 +74,7 @@ BTRFS_WORK_HELPER(endio_helper);
 BTRFS_WORK_HELPER(endio_meta_helper);
 BTRFS_WORK_HELPER(endio_meta_write_helper);
 BTRFS_WORK_HELPER(endio_raid56_helper);
+BTRFS_WORK_HELPER(endio_repair_helper);
 BTRFS_WORK_HELPER(rmw_helper);
 BTRFS_WORK_HELPER(endio_write_helper);
 BTRFS_WORK_HELPER(freespace_write_helper);
@@ -91,7 +92,7 @@ __btrfs_alloc_workqueue(const char *name, int flags, int max_active,
 {
        struct __btrfs_workqueue *ret = kzalloc(sizeof(*ret), GFP_NOFS);
 
-       if (unlikely(!ret))
+       if (!ret)
                return NULL;
 
        ret->max_active = max_active;
@@ -115,7 +116,7 @@ __btrfs_alloc_workqueue(const char *name, int flags, int max_active,
                ret->normal_wq = alloc_workqueue("%s-%s", flags,
                                                 ret->max_active, "btrfs",
                                                 name);
-       if (unlikely(!ret->normal_wq)) {
+       if (!ret->normal_wq) {
                kfree(ret);
                return NULL;
        }
@@ -137,12 +138,12 @@ struct btrfs_workqueue *btrfs_alloc_workqueue(const char *name,
 {
        struct btrfs_workqueue *ret = kzalloc(sizeof(*ret), GFP_NOFS);
 
-       if (unlikely(!ret))
+       if (!ret)
                return NULL;
 
        ret->normal = __btrfs_alloc_workqueue(name, flags & ~WQ_HIGHPRI,
                                              max_active, thresh);
-       if (unlikely(!ret->normal)) {
+       if (!ret->normal) {
                kfree(ret);
                return NULL;
        }
@@ -150,7 +151,7 @@ struct btrfs_workqueue *btrfs_alloc_workqueue(const char *name,
        if (flags & WQ_HIGHPRI) {
                ret->high = __btrfs_alloc_workqueue(name, flags, max_active,
                                                    thresh);
-               if (unlikely(!ret->high)) {
+               if (!ret->high) {
                        __btrfs_destroy_workqueue(ret->normal);
                        kfree(ret);
                        return NULL;
index e9e31c94758fd6ddea5cbd458d5aca04a27e9a73..e386c29ef1f62c559a184e4ae31884c2bcc425ba 100644 (file)
@@ -53,6 +53,7 @@ BTRFS_WORK_HELPER_PROTO(endio_helper);
 BTRFS_WORK_HELPER_PROTO(endio_meta_helper);
 BTRFS_WORK_HELPER_PROTO(endio_meta_write_helper);
 BTRFS_WORK_HELPER_PROTO(endio_raid56_helper);
+BTRFS_WORK_HELPER_PROTO(endio_repair_helper);
 BTRFS_WORK_HELPER_PROTO(rmw_helper);
 BTRFS_WORK_HELPER_PROTO(endio_write_helper);
 BTRFS_WORK_HELPER_PROTO(freespace_write_helper);
index 54a201dac7f9455bd1e294c2731d5b47226b7bef..2d3e32ebfd15510b8e97519a006486c83755121b 100644 (file)
@@ -25,6 +25,9 @@
 #include "delayed-ref.h"
 #include "locking.h"
 
+/* Just an arbitrary number so we can be sure this happened */
+#define BACKREF_FOUND_SHARED 6
+
 struct extent_inode_elem {
        u64 inum;
        u64 offset;
@@ -377,7 +380,8 @@ out:
 static int __resolve_indirect_refs(struct btrfs_fs_info *fs_info,
                                   struct btrfs_path *path, u64 time_seq,
                                   struct list_head *head,
-                                  const u64 *extent_item_pos, u64 total_refs)
+                                  const u64 *extent_item_pos, u64 total_refs,
+                                  u64 root_objectid)
 {
        int err;
        int ret = 0;
@@ -402,6 +406,10 @@ static int __resolve_indirect_refs(struct btrfs_fs_info *fs_info,
                        continue;
                if (ref->count == 0)
                        continue;
+               if (root_objectid && ref->root_id != root_objectid) {
+                       ret = BACKREF_FOUND_SHARED;
+                       goto out;
+               }
                err = __resolve_indirect_ref(fs_info, path, time_seq, ref,
                                             parents, extent_item_pos,
                                             total_refs);
@@ -482,7 +490,7 @@ static int __add_missing_keys(struct btrfs_fs_info *fs_info,
                        continue;
                BUG_ON(!ref->wanted_disk_byte);
                eb = read_tree_block(fs_info->tree_root, ref->wanted_disk_byte,
-                                    fs_info->tree_root->leafsize, 0);
+                                    0);
                if (!eb || !extent_buffer_uptodate(eb)) {
                        free_extent_buffer(eb);
                        return -EIO;
@@ -561,7 +569,8 @@ static void __merge_refs(struct list_head *head, int mode)
  * smaller or equal that seq to the list
  */
 static int __add_delayed_refs(struct btrfs_delayed_ref_head *head, u64 seq,
-                             struct list_head *prefs, u64 *total_refs)
+                             struct list_head *prefs, u64 *total_refs,
+                             u64 inum)
 {
        struct btrfs_delayed_extent_op *extent_op = head->extent_op;
        struct rb_node *n = &head->node.rb_node;
@@ -625,6 +634,16 @@ static int __add_delayed_refs(struct btrfs_delayed_ref_head *head, u64 seq,
                        key.objectid = ref->objectid;
                        key.type = BTRFS_EXTENT_DATA_KEY;
                        key.offset = ref->offset;
+
+                       /*
+                        * Found a inum that doesn't match our known inum, we
+                        * know it's shared.
+                        */
+                       if (inum && ref->objectid != inum) {
+                               ret = BACKREF_FOUND_SHARED;
+                               break;
+                       }
+
                        ret = __add_prelim_ref(prefs, ref->root, &key, 0, 0,
                                               node->bytenr,
                                               node->ref_mod * sgn, GFP_ATOMIC);
@@ -659,7 +678,7 @@ static int __add_delayed_refs(struct btrfs_delayed_ref_head *head, u64 seq,
 static int __add_inline_refs(struct btrfs_fs_info *fs_info,
                             struct btrfs_path *path, u64 bytenr,
                             int *info_level, struct list_head *prefs,
-                            u64 *total_refs)
+                            u64 *total_refs, u64 inum)
 {
        int ret = 0;
        int slot;
@@ -744,6 +763,12 @@ static int __add_inline_refs(struct btrfs_fs_info *fs_info,
                                                                      dref);
                        key.type = BTRFS_EXTENT_DATA_KEY;
                        key.offset = btrfs_extent_data_ref_offset(leaf, dref);
+
+                       if (inum && key.objectid != inum) {
+                               ret = BACKREF_FOUND_SHARED;
+                               break;
+                       }
+
                        root = btrfs_extent_data_ref_root(leaf, dref);
                        ret = __add_prelim_ref(prefs, root, &key, 0, 0,
                                               bytenr, count, GFP_NOFS);
@@ -765,7 +790,7 @@ static int __add_inline_refs(struct btrfs_fs_info *fs_info,
  */
 static int __add_keyed_refs(struct btrfs_fs_info *fs_info,
                            struct btrfs_path *path, u64 bytenr,
-                           int info_level, struct list_head *prefs)
+                           int info_level, struct list_head *prefs, u64 inum)
 {
        struct btrfs_root *extent_root = fs_info->extent_root;
        int ret;
@@ -827,6 +852,12 @@ static int __add_keyed_refs(struct btrfs_fs_info *fs_info,
                                                                      dref);
                        key.type = BTRFS_EXTENT_DATA_KEY;
                        key.offset = btrfs_extent_data_ref_offset(leaf, dref);
+
+                       if (inum && key.objectid != inum) {
+                               ret = BACKREF_FOUND_SHARED;
+                               break;
+                       }
+
                        root = btrfs_extent_data_ref_root(leaf, dref);
                        ret = __add_prelim_ref(prefs, root, &key, 0, 0,
                                               bytenr, count, GFP_NOFS);
@@ -854,7 +885,8 @@ static int __add_keyed_refs(struct btrfs_fs_info *fs_info,
 static int find_parent_nodes(struct btrfs_trans_handle *trans,
                             struct btrfs_fs_info *fs_info, u64 bytenr,
                             u64 time_seq, struct ulist *refs,
-                            struct ulist *roots, const u64 *extent_item_pos)
+                            struct ulist *roots, const u64 *extent_item_pos,
+                            u64 root_objectid, u64 inum)
 {
        struct btrfs_key key;
        struct btrfs_path *path;
@@ -929,7 +961,8 @@ again:
                        }
                        spin_unlock(&delayed_refs->lock);
                        ret = __add_delayed_refs(head, time_seq,
-                                                &prefs_delayed, &total_refs);
+                                                &prefs_delayed, &total_refs,
+                                                inum);
                        mutex_unlock(&head->mutex);
                        if (ret)
                                goto out;
@@ -951,11 +984,11 @@ again:
                     key.type == BTRFS_METADATA_ITEM_KEY)) {
                        ret = __add_inline_refs(fs_info, path, bytenr,
                                                &info_level, &prefs,
-                                               &total_refs);
+                                               &total_refs, inum);
                        if (ret)
                                goto out;
                        ret = __add_keyed_refs(fs_info, path, bytenr,
-                                              info_level, &prefs);
+                                              info_level, &prefs, inum);
                        if (ret)
                                goto out;
                }
@@ -971,7 +1004,8 @@ again:
        __merge_refs(&prefs, 1);
 
        ret = __resolve_indirect_refs(fs_info, path, time_seq, &prefs,
-                                     extent_item_pos, total_refs);
+                                     extent_item_pos, total_refs,
+                                     root_objectid);
        if (ret)
                goto out;
 
@@ -981,6 +1015,11 @@ again:
                ref = list_first_entry(&prefs, struct __prelim_ref, list);
                WARN_ON(ref->count < 0);
                if (roots && ref->count && ref->root_id && ref->parent == 0) {
+                       if (root_objectid && ref->root_id != root_objectid) {
+                               ret = BACKREF_FOUND_SHARED;
+                               goto out;
+                       }
+
                        /* no parent == root of tree */
                        ret = ulist_add(roots, ref->root_id, 0, GFP_NOFS);
                        if (ret < 0)
@@ -989,12 +1028,10 @@ again:
                if (ref->count && ref->parent) {
                        if (extent_item_pos && !ref->inode_list &&
                            ref->level == 0) {
-                               u32 bsz;
                                struct extent_buffer *eb;
-                               bsz = btrfs_level_size(fs_info->extent_root,
-                                                       ref->level);
+
                                eb = read_tree_block(fs_info->extent_root,
-                                                          ref->parent, bsz, 0);
+                                                          ref->parent, 0);
                                if (!eb || !extent_buffer_uptodate(eb)) {
                                        free_extent_buffer(eb);
                                        ret = -EIO;
@@ -1087,7 +1124,7 @@ static int btrfs_find_all_leafs(struct btrfs_trans_handle *trans,
                return -ENOMEM;
 
        ret = find_parent_nodes(trans, fs_info, bytenr,
-                               time_seq, *leafs, NULL, extent_item_pos);
+                               time_seq, *leafs, NULL, extent_item_pos, 0, 0);
        if (ret < 0 && ret != -ENOENT) {
                free_leaf_list(*leafs);
                return ret;
@@ -1130,7 +1167,7 @@ static int __btrfs_find_all_roots(struct btrfs_trans_handle *trans,
        ULIST_ITER_INIT(&uiter);
        while (1) {
                ret = find_parent_nodes(trans, fs_info, bytenr,
-                                       time_seq, tmp, *roots, NULL);
+                                       time_seq, tmp, *roots, NULL, 0, 0);
                if (ret < 0 && ret != -ENOENT) {
                        ulist_free(tmp);
                        ulist_free(*roots);
@@ -1161,6 +1198,54 @@ int btrfs_find_all_roots(struct btrfs_trans_handle *trans,
        return ret;
 }
 
+int btrfs_check_shared(struct btrfs_trans_handle *trans,
+                      struct btrfs_fs_info *fs_info, u64 root_objectid,
+                      u64 inum, u64 bytenr)
+{
+       struct ulist *tmp = NULL;
+       struct ulist *roots = NULL;
+       struct ulist_iterator uiter;
+       struct ulist_node *node;
+       struct seq_list elem = {};
+       int ret = 0;
+
+       tmp = ulist_alloc(GFP_NOFS);
+       roots = ulist_alloc(GFP_NOFS);
+       if (!tmp || !roots) {
+               ulist_free(tmp);
+               ulist_free(roots);
+               return -ENOMEM;
+       }
+
+       if (trans)
+               btrfs_get_tree_mod_seq(fs_info, &elem);
+       else
+               down_read(&fs_info->commit_root_sem);
+       ULIST_ITER_INIT(&uiter);
+       while (1) {
+               ret = find_parent_nodes(trans, fs_info, bytenr, elem.seq, tmp,
+                                       roots, NULL, root_objectid, inum);
+               if (ret == BACKREF_FOUND_SHARED) {
+                       ret = 1;
+                       break;
+               }
+               if (ret < 0 && ret != -ENOENT)
+                       break;
+               node = ulist_next(tmp, &uiter);
+               if (!node)
+                       break;
+               bytenr = node->val;
+               cond_resched();
+       }
+       if (trans)
+               btrfs_put_tree_mod_seq(fs_info, &elem);
+       else
+               up_read(&fs_info->commit_root_sem);
+       ulist_free(tmp);
+       ulist_free(roots);
+       return ret;
+}
+
 /*
  * this makes the path point to (inum INODE_ITEM ioff)
  */
@@ -1193,7 +1278,7 @@ int btrfs_find_one_extref(struct btrfs_root *root, u64 inode_objectid,
        unsigned long ptr;
 
        key.objectid = inode_objectid;
-       btrfs_set_key_type(&key, BTRFS_INODE_EXTREF_KEY);
+       key.type = BTRFS_INODE_EXTREF_KEY;
        key.offset = start_off;
 
        ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
@@ -1233,7 +1318,7 @@ int btrfs_find_one_extref(struct btrfs_root *root, u64 inode_objectid,
                ret = -ENOENT;
                if (found_key.objectid != inode_objectid)
                        break;
-               if (btrfs_key_type(&found_key) != BTRFS_INODE_EXTREF_KEY)
+               if (found_key.type != BTRFS_INODE_EXTREF_KEY)
                        break;
 
                ret = 0;
@@ -1366,7 +1451,7 @@ int extent_from_logical(struct btrfs_fs_info *fs_info, u64 logical,
        }
        btrfs_item_key_to_cpu(path->nodes[0], found_key, path->slots[0]);
        if (found_key->type == BTRFS_METADATA_ITEM_KEY)
-               size = fs_info->extent_root->leafsize;
+               size = fs_info->extent_root->nodesize;
        else if (found_key->type == BTRFS_EXTENT_ITEM_KEY)
                size = found_key->offset;
 
index 86fc20fec28243f0f594a40a17da64a5d79da30f..2a1ac6bfc724637f3a80ac15c6ce6237dc7998f0 100644 (file)
@@ -71,6 +71,9 @@ int btrfs_find_one_extref(struct btrfs_root *root, u64 inode_objectid,
                          u64 start_off, struct btrfs_path *path,
                          struct btrfs_inode_extref **ret_extref,
                          u64 *found_off);
+int btrfs_check_shared(struct btrfs_trans_handle *trans,
+                      struct btrfs_fs_info *fs_info, u64 root_objectid,
+                      u64 inum, u64 bytenr);
 
 int __init btrfs_prelim_ref_init(void);
 void btrfs_prelim_ref_exit(void);
index 56b8522d5767b5858928d4152c0ab64ca43886ca..4aadadcfab20178d734ad395c1448676603a01b8 100644 (file)
 #define BTRFS_INODE_IN_DELALLOC_LIST           9
 #define BTRFS_INODE_READDIO_NEED_LOCK          10
 #define BTRFS_INODE_HAS_PROPS                  11
+/*
+ * The following 3 bits are meant only for the btree inode.
+ * When any of them is set, it means an error happened while writing an
+ * extent buffer belonging to:
+ * 1) a non-log btree
+ * 2) a log btree and first log sub-transaction
+ * 3) a log btree and second log sub-transaction
+ */
+#define BTRFS_INODE_BTREE_ERR                  12
+#define BTRFS_INODE_BTREE_LOG1_ERR             13
+#define BTRFS_INODE_BTREE_LOG2_ERR             14
 
 /* in memory btrfs inode */
 struct btrfs_inode {
@@ -120,6 +131,12 @@ struct btrfs_inode {
         */
        u64 delalloc_bytes;
 
+       /*
+        * total number of bytes pending defrag, used by stat to check whether
+        * it needs COW.
+        */
+       u64 defrag_bytes;
+
        /*
         * the size of the file stored in the metadata on disk.  data=ordered
         * means the in-memory i_size might be larger than the size on disk
@@ -248,8 +265,11 @@ static inline int btrfs_inode_in_log(struct inode *inode, u64 generation)
        return 0;
 }
 
+#define BTRFS_DIO_ORIG_BIO_SUBMITTED   0x1
+
 struct btrfs_dio_private {
        struct inode *inode;
+       unsigned long flags;
        u64 logical_offset;
        u64 disk_bytenr;
        u64 bytes;
@@ -266,7 +286,12 @@ struct btrfs_dio_private {
 
        /* dio_bio came from fs/direct-io.c */
        struct bio *dio_bio;
-       u8 csum[0];
+
+       /*
+        * The original bio may be splited to several sub-bios, this is
+        * done during endio of sub-bios
+        */
+       int (*subio_endio)(struct inode *, struct btrfs_io_bio *, int);
 };
 
 /*
index ce92ae30250fb256fbbbdb9158315c757a24adc1..cb7f3fe9c9f6ff21bacffd3ab5a4a2bc7eccf1f0 100644 (file)
@@ -807,7 +807,7 @@ static int btrfsic_process_superblock_dev_mirror(
 
        /* super block bytenr is always the unmapped device bytenr */
        dev_bytenr = btrfs_sb_offset(superblock_mirror_num);
-       if (dev_bytenr + BTRFS_SUPER_INFO_SIZE > device->total_bytes)
+       if (dev_bytenr + BTRFS_SUPER_INFO_SIZE > device->commit_total_bytes)
                return -1;
        bh = __bread(superblock_bdev, dev_bytenr / 4096,
                     BTRFS_SUPER_INFO_SIZE);
@@ -820,7 +820,6 @@ static int btrfsic_process_superblock_dev_mirror(
            btrfs_super_magic(super_tmp) != BTRFS_MAGIC ||
            memcmp(device->uuid, super_tmp->dev_item.uuid, BTRFS_UUID_SIZE) ||
            btrfs_super_nodesize(super_tmp) != state->metablock_size ||
-           btrfs_super_leafsize(super_tmp) != state->metablock_size ||
            btrfs_super_sectorsize(super_tmp) != state->datablock_size) {
                brelse(bh);
                return 0;
@@ -1252,8 +1251,7 @@ static void btrfsic_read_from_block_data(
 
        while (len > 0) {
                cur = min(len, ((size_t)PAGE_CACHE_SIZE - offset_in_page));
-               BUG_ON(i >= (block_ctx->len + PAGE_CACHE_SIZE - 1) >>
-                           PAGE_CACHE_SHIFT);
+               BUG_ON(i >= DIV_ROUND_UP(block_ctx->len, PAGE_CACHE_SIZE));
                kaddr = block_ctx->datav[i];
                memcpy(dst, kaddr + offset_in_page, cur);
 
@@ -3120,24 +3118,12 @@ int btrfsic_mount(struct btrfs_root *root,
        struct list_head *dev_head = &fs_devices->devices;
        struct btrfs_device *device;
 
-       if (root->nodesize != root->leafsize) {
-               printk(KERN_INFO
-                      "btrfsic: cannot handle nodesize %d != leafsize %d!\n",
-                      root->nodesize, root->leafsize);
-               return -1;
-       }
        if (root->nodesize & ((u64)PAGE_CACHE_SIZE - 1)) {
                printk(KERN_INFO
                       "btrfsic: cannot handle nodesize %d not being a multiple of PAGE_CACHE_SIZE %ld!\n",
                       root->nodesize, PAGE_CACHE_SIZE);
                return -1;
        }
-       if (root->leafsize & ((u64)PAGE_CACHE_SIZE - 1)) {
-               printk(KERN_INFO
-                      "btrfsic: cannot handle leafsize %d not being a multiple of PAGE_CACHE_SIZE %ld!\n",
-                      root->leafsize, PAGE_CACHE_SIZE);
-               return -1;
-       }
        if (root->sectorsize & ((u64)PAGE_CACHE_SIZE - 1)) {
                printk(KERN_INFO
                       "btrfsic: cannot handle sectorsize %d not being a multiple of PAGE_CACHE_SIZE %ld!\n",
index 1daea0b47187b58db65dde86411e88578473fcf4..d3220d31d3cbf0e653898d15816f5895045c06d5 100644 (file)
@@ -91,8 +91,7 @@ static inline int compressed_bio_size(struct btrfs_root *root,
        u16 csum_size = btrfs_super_csum_size(root->fs_info->super_copy);
 
        return sizeof(struct compressed_bio) +
-               ((disk_size + root->sectorsize - 1) / root->sectorsize) *
-               csum_size;
+               (DIV_ROUND_UP(disk_size, root->sectorsize)) * csum_size;
 }
 
 static struct bio *compressed_bio_alloc(struct block_device *bdev,
@@ -389,7 +388,8 @@ int btrfs_submit_compressed_write(struct inode *inode, u64 start,
                         * freed before we're done setting it up
                         */
                        atomic_inc(&cb->pending_bios);
-                       ret = btrfs_bio_wq_end_io(root->fs_info, bio, 0);
+                       ret = btrfs_bio_wq_end_io(root->fs_info, bio,
+                                       BTRFS_WQ_ENDIO_DATA);
                        BUG_ON(ret); /* -ENOMEM */
 
                        if (!skip_sum) {
@@ -420,7 +420,7 @@ int btrfs_submit_compressed_write(struct inode *inode, u64 start,
        }
        bio_get(bio);
 
-       ret = btrfs_bio_wq_end_io(root->fs_info, bio, 0);
+       ret = btrfs_bio_wq_end_io(root->fs_info, bio, BTRFS_WQ_ENDIO_DATA);
        BUG_ON(ret); /* -ENOMEM */
 
        if (!skip_sum) {
@@ -615,8 +615,7 @@ int btrfs_submit_compressed_read(struct inode *inode, struct bio *bio,
        cb->compress_type = extent_compress_type(bio_flags);
        cb->orig_bio = bio;
 
-       nr_pages = (compressed_len + PAGE_CACHE_SIZE - 1) /
-                                PAGE_CACHE_SIZE;
+       nr_pages = DIV_ROUND_UP(compressed_len, PAGE_CACHE_SIZE);
        cb->compressed_pages = kzalloc(sizeof(struct page *) * nr_pages,
                                       GFP_NOFS);
        if (!cb->compressed_pages)
@@ -670,7 +669,8 @@ int btrfs_submit_compressed_read(struct inode *inode, struct bio *bio,
                    PAGE_CACHE_SIZE) {
                        bio_get(comp_bio);
 
-                       ret = btrfs_bio_wq_end_io(root->fs_info, comp_bio, 0);
+                       ret = btrfs_bio_wq_end_io(root->fs_info, comp_bio,
+                                       BTRFS_WQ_ENDIO_DATA);
                        BUG_ON(ret); /* -ENOMEM */
 
                        /*
@@ -686,8 +686,8 @@ int btrfs_submit_compressed_read(struct inode *inode, struct bio *bio,
                                                        comp_bio, sums);
                                BUG_ON(ret); /* -ENOMEM */
                        }
-                       sums += (comp_bio->bi_iter.bi_size +
-                                root->sectorsize - 1) / root->sectorsize;
+                       sums += DIV_ROUND_UP(comp_bio->bi_iter.bi_size,
+                                            root->sectorsize);
 
                        ret = btrfs_map_bio(root, READ, comp_bio,
                                            mirror_num, 0);
@@ -708,7 +708,8 @@ int btrfs_submit_compressed_read(struct inode *inode, struct bio *bio,
        }
        bio_get(comp_bio);
 
-       ret = btrfs_bio_wq_end_io(root->fs_info, comp_bio, 0);
+       ret = btrfs_bio_wq_end_io(root->fs_info, comp_bio,
+                       BTRFS_WQ_ENDIO_DATA);
        BUG_ON(ret); /* -ENOMEM */
 
        if (!(BTRFS_I(inode)->flags & BTRFS_INODE_NODATASUM)) {
index 44ee5d2e52a41935828ac954ebeefe8ce17568e6..19bc6162fb8e899cc51bd3d777fcbddf91589aa6 100644 (file)
@@ -258,9 +258,8 @@ int btrfs_copy_root(struct btrfs_trans_handle *trans,
        else
                btrfs_node_key(buf, &disk_key, 0);
 
-       cow = btrfs_alloc_free_block(trans, root, buf->len, 0,
-                                    new_root_objectid, &disk_key, level,
-                                    buf->start, 0);
+       cow = btrfs_alloc_tree_block(trans, root, 0, new_root_objectid,
+                       &disk_key, level, buf->start, 0);
        if (IS_ERR(cow))
                return PTR_ERR(cow);
 
@@ -1133,9 +1132,9 @@ static noinline int __btrfs_cow_block(struct btrfs_trans_handle *trans,
        } else
                parent_start = 0;
 
-       cow = btrfs_alloc_free_block(trans, root, buf->len, parent_start,
-                                    root->root_key.objectid, &disk_key,
-                                    level, search_start, empty_size);
+       cow = btrfs_alloc_tree_block(trans, root, parent_start,
+                       root->root_key.objectid, &disk_key, level,
+                       search_start, empty_size);
        if (IS_ERR(cow))
                return PTR_ERR(cow);
 
@@ -1425,7 +1424,6 @@ get_old_root(struct btrfs_root *root, u64 time_seq)
        struct tree_mod_root *old_root = NULL;
        u64 old_generation = 0;
        u64 logical;
-       u32 blocksize;
 
        eb_root = btrfs_read_lock_root_node(root);
        tm = __tree_mod_log_oldest_root(root->fs_info, eb_root, time_seq);
@@ -1444,8 +1442,7 @@ get_old_root(struct btrfs_root *root, u64 time_seq)
        if (old_root && tm && tm->op != MOD_LOG_KEY_REMOVE_WHILE_FREEING) {
                btrfs_tree_read_unlock(eb_root);
                free_extent_buffer(eb_root);
-               blocksize = btrfs_level_size(root, old_root->level);
-               old = read_tree_block(root, logical, blocksize, 0);
+               old = read_tree_block(root, logical, 0);
                if (WARN_ON(!old || !extent_buffer_uptodate(old))) {
                        free_extent_buffer(old);
                        btrfs_warn(root->fs_info,
@@ -1506,10 +1503,9 @@ static inline int should_cow_block(struct btrfs_trans_handle *trans,
                                   struct btrfs_root *root,
                                   struct extent_buffer *buf)
 {
-#ifdef CONFIG_BTRFS_FS_RUN_SANITY_TESTS
-       if (unlikely(test_bit(BTRFS_ROOT_DUMMY_ROOT, &root->state)))
+       if (btrfs_test_is_dummy_root(root))
                return 0;
-#endif
+
        /* ensure we can see the force_cow */
        smp_rmb();
 
@@ -1651,7 +1647,7 @@ int btrfs_realloc_node(struct btrfs_trans_handle *trans,
        WARN_ON(trans->transid != root->fs_info->generation);
 
        parent_nritems = btrfs_header_nritems(parent);
-       blocksize = btrfs_level_size(root, parent_level - 1);
+       blocksize = root->nodesize;
        end_slot = parent_nritems;
 
        if (parent_nritems == 1)
@@ -1685,15 +1681,14 @@ int btrfs_realloc_node(struct btrfs_trans_handle *trans,
                        continue;
                }
 
-               cur = btrfs_find_tree_block(root, blocknr, blocksize);
+               cur = btrfs_find_tree_block(root, blocknr);
                if (cur)
                        uptodate = btrfs_buffer_uptodate(cur, gen, 0);
                else
                        uptodate = 0;
                if (!cur || !uptodate) {
                        if (!cur) {
-                               cur = read_tree_block(root, blocknr,
-                                                        blocksize, gen);
+                               cur = read_tree_block(root, blocknr, gen);
                                if (!cur || !extent_buffer_uptodate(cur)) {
                                        free_extent_buffer(cur);
                                        return -EIO;
@@ -1872,7 +1867,6 @@ static noinline struct extent_buffer *read_node_slot(struct btrfs_root *root,
        BUG_ON(level == 0);
 
        eb = read_tree_block(root, btrfs_node_blockptr(parent, slot),
-                            btrfs_level_size(root, level - 1),
                             btrfs_node_ptr_generation(parent, slot));
        if (eb && !extent_buffer_uptodate(eb)) {
                free_extent_buffer(eb);
@@ -2267,8 +2261,8 @@ static void reada_for_search(struct btrfs_root *root,
        node = path->nodes[level];
 
        search = btrfs_node_blockptr(node, slot);
-       blocksize = btrfs_level_size(root, level - 1);
-       eb = btrfs_find_tree_block(root, search, blocksize);
+       blocksize = root->nodesize;
+       eb = btrfs_find_tree_block(root, search);
        if (eb) {
                free_extent_buffer(eb);
                return;
@@ -2298,7 +2292,7 @@ static void reada_for_search(struct btrfs_root *root,
                if ((search <= target && target - search <= 65536) ||
                    (search > target && search - target <= 65536)) {
                        gen = btrfs_node_ptr_generation(node, nr);
-                       readahead_tree_block(root, search, blocksize, gen);
+                       readahead_tree_block(root, search, blocksize);
                        nread += blocksize;
                }
                nscan++;
@@ -2325,12 +2319,12 @@ static noinline void reada_for_balance(struct btrfs_root *root,
 
        nritems = btrfs_header_nritems(parent);
        slot = path->slots[level + 1];
-       blocksize = btrfs_level_size(root, level);
+       blocksize = root->nodesize;
 
        if (slot > 0) {
                block1 = btrfs_node_blockptr(parent, slot - 1);
                gen = btrfs_node_ptr_generation(parent, slot - 1);
-               eb = btrfs_find_tree_block(root, block1, blocksize);
+               eb = btrfs_find_tree_block(root, block1);
                /*
                 * if we get -eagain from btrfs_buffer_uptodate, we
                 * don't want to return eagain here.  That will loop
@@ -2343,16 +2337,16 @@ static noinline void reada_for_balance(struct btrfs_root *root,
        if (slot + 1 < nritems) {
                block2 = btrfs_node_blockptr(parent, slot + 1);
                gen = btrfs_node_ptr_generation(parent, slot + 1);
-               eb = btrfs_find_tree_block(root, block2, blocksize);
+               eb = btrfs_find_tree_block(root, block2);
                if (eb && btrfs_buffer_uptodate(eb, gen, 1) != 0)
                        block2 = 0;
                free_extent_buffer(eb);
        }
 
        if (block1)
-               readahead_tree_block(root, block1, blocksize, 0);
+               readahead_tree_block(root, block1, blocksize);
        if (block2)
-               readahead_tree_block(root, block2, blocksize, 0);
+               readahead_tree_block(root, block2, blocksize);
 }
 
 
@@ -2454,16 +2448,14 @@ read_block_for_search(struct btrfs_trans_handle *trans,
 {
        u64 blocknr;
        u64 gen;
-       u32 blocksize;
        struct extent_buffer *b = *eb_ret;
        struct extent_buffer *tmp;
        int ret;
 
        blocknr = btrfs_node_blockptr(b, slot);
        gen = btrfs_node_ptr_generation(b, slot);
-       blocksize = btrfs_level_size(root, level - 1);
 
-       tmp = btrfs_find_tree_block(root, blocknr, blocksize);
+       tmp = btrfs_find_tree_block(root, blocknr);
        if (tmp) {
                /* first we do an atomic uptodate check */
                if (btrfs_buffer_uptodate(tmp, gen, 1) > 0) {
@@ -2507,7 +2499,7 @@ read_block_for_search(struct btrfs_trans_handle *trans,
        btrfs_release_path(p);
 
        ret = -EAGAIN;
-       tmp = read_tree_block(root, blocknr, blocksize, 0);
+       tmp = read_tree_block(root, blocknr, 0);
        if (tmp) {
                /*
                 * If the read above didn't mark this buffer up to date,
@@ -2792,8 +2784,6 @@ again:
                        if (!should_cow_block(trans, root, b))
                                goto cow_done;
 
-                       btrfs_set_path_blocking(p);
-
                        /*
                         * must have write locks on this node and the
                         * parent
@@ -2807,6 +2797,7 @@ again:
                                goto again;
                        }
 
+                       btrfs_set_path_blocking(p);
                        err = btrfs_cow_block(trans, root, b,
                                              p->nodes[level + 1],
                                              p->slots[level + 1], &b);
@@ -3362,9 +3353,8 @@ static noinline int insert_new_root(struct btrfs_trans_handle *trans,
        else
                btrfs_node_key(lower, &lower_key, 0);
 
-       c = btrfs_alloc_free_block(trans, root, root->nodesize, 0,
-                                  root->root_key.objectid, &lower_key,
-                                  level, root->node->start, 0);
+       c = btrfs_alloc_tree_block(trans, root, 0, root->root_key.objectid,
+                                  &lower_key, level, root->node->start, 0);
        if (IS_ERR(c))
                return PTR_ERR(c);
 
@@ -3502,9 +3492,8 @@ static noinline int split_node(struct btrfs_trans_handle *trans,
        mid = (c_nritems + 1) / 2;
        btrfs_node_key(c, &disk_key, mid);
 
-       split = btrfs_alloc_free_block(trans, root, root->nodesize, 0,
-                                       root->root_key.objectid,
-                                       &disk_key, level, c->start, 0);
+       split = btrfs_alloc_tree_block(trans, root, 0, root->root_key.objectid,
+                       &disk_key, level, c->start, 0);
        if (IS_ERR(split))
                return PTR_ERR(split);
 
@@ -4282,13 +4271,12 @@ again:
        else
                btrfs_item_key(l, &disk_key, mid);
 
-       right = btrfs_alloc_free_block(trans, root, root->leafsize, 0,
-                                       root->root_key.objectid,
-                                       &disk_key, 0, l->start, 0);
+       right = btrfs_alloc_tree_block(trans, root, 0, root->root_key.objectid,
+                       &disk_key, 0, l->start, 0);
        if (IS_ERR(right))
                return PTR_ERR(right);
 
-       root_add_used(root, root->leafsize);
+       root_add_used(root, root->nodesize);
 
        memset_extent_buffer(right, 0, 0, sizeof(struct btrfs_header));
        btrfs_set_header_bytenr(right, right->start);
@@ -4626,8 +4614,7 @@ void btrfs_truncate_item(struct btrfs_root *root, struct btrfs_path *path,
                                ptr = btrfs_item_ptr_offset(leaf, slot);
                                memmove_extent_buffer(leaf, ptr,
                                      (unsigned long)fi,
-                                     offsetof(struct btrfs_file_extent_item,
-                                                disk_bytenr));
+                                     BTRFS_FILE_EXTENT_INLINE_DATA_START);
                        }
                }
 
@@ -4738,6 +4725,12 @@ void setup_items_for_insert(struct btrfs_root *root, struct btrfs_path *path,
        int slot;
        struct btrfs_map_token token;
 
+       if (path->slots[0] == 0) {
+               btrfs_cpu_key_to_disk(&disk_key, cpu_key);
+               fixup_low_keys(root, path, &disk_key, 1);
+       }
+       btrfs_unlock_up_safe(path, 1);
+
        btrfs_init_map_token(&token);
 
        leaf = path->nodes[0];
@@ -4798,12 +4791,6 @@ void setup_items_for_insert(struct btrfs_root *root, struct btrfs_path *path,
        }
 
        btrfs_set_header_nritems(leaf, nritems + nr);
-
-       if (slot == 0) {
-               btrfs_cpu_key_to_disk(&disk_key, cpu_key);
-               fixup_low_keys(root, path, &disk_key, 1);
-       }
-       btrfs_unlock_up_safe(path, 1);
        btrfs_mark_buffer_dirty(leaf);
 
        if (btrfs_leaf_free_space(root, leaf) < 0) {
@@ -5145,8 +5132,9 @@ int btrfs_search_forward(struct btrfs_root *root, struct btrfs_key *min_key,
        u32 nritems;
        int level;
        int ret = 1;
+       int keep_locks = path->keep_locks;
 
-       WARN_ON(!path->keep_locks);
+       path->keep_locks = 1;
 again:
        cur = btrfs_read_lock_root_node(root);
        level = btrfs_header_level(cur);
@@ -5210,7 +5198,6 @@ find_next_key:
                path->slots[level] = slot;
                if (level == path->lowest_level) {
                        ret = 0;
-                       unlock_up(path, level, 1, 0, NULL);
                        goto out;
                }
                btrfs_set_path_blocking(path);
@@ -5225,9 +5212,12 @@ find_next_key:
                btrfs_clear_path_blocking(path, NULL, 0);
        }
 out:
-       if (ret == 0)
+       path->keep_locks = keep_locks;
+       if (ret == 0) {
+               btrfs_unlock_up_safe(path, path->lowest_level + 1);
+               btrfs_set_path_blocking(path);
                memcpy(min_key, &found_key, sizeof(found_key));
-       btrfs_set_path_blocking(path);
+       }
        return ret;
 }
 
@@ -5375,7 +5365,7 @@ int btrfs_compare_trees(struct btrfs_root *left_root,
                goto out;
        }
 
-       tmp_buf = kmalloc(left_root->leafsize, GFP_NOFS);
+       tmp_buf = kmalloc(left_root->nodesize, GFP_NOFS);
        if (!tmp_buf) {
                ret = -ENOMEM;
                goto out;
@@ -5520,18 +5510,18 @@ int btrfs_compare_trees(struct btrfs_root *left_root,
                                        goto out;
                                advance_right = ADVANCE;
                        } else {
-                               enum btrfs_compare_tree_result cmp;
+                               enum btrfs_compare_tree_result result;
 
                                WARN_ON(!extent_buffer_uptodate(left_path->nodes[0]));
                                ret = tree_compare_item(left_root, left_path,
                                                right_path, tmp_buf);
                                if (ret)
-                                       cmp = BTRFS_COMPARE_TREE_CHANGED;
+                                       result = BTRFS_COMPARE_TREE_CHANGED;
                                else
-                                       cmp = BTRFS_COMPARE_TREE_SAME;
+                                       result = BTRFS_COMPARE_TREE_SAME;
                                ret = changed_cb(left_root, right_root,
                                                 left_path, right_path,
-                                                &left_key, cmp, ctx);
+                                                &left_key, result, ctx);
                                if (ret < 0)
                                        goto out;
                                advance_left = ADVANCE;
index 8e29b614fe93d9b8cc22c9eb5d54377d617bb9e7..d557264ee974deab61c33736d93af24ffb2a93d2 100644 (file)
@@ -34,6 +34,7 @@
 #include <linux/pagemap.h>
 #include <linux/btrfs.h>
 #include <linux/workqueue.h>
+#include <linux/security.h>
 #include "extent_io.h"
 #include "extent_map.h"
 #include "async-thread.h"
@@ -62,13 +63,6 @@ struct btrfs_ordered_sum;
 
 #define BTRFS_COMPAT_EXTENT_TREE_V0
 
-/*
- * files bigger than this get some pre-flushing when they are added
- * to the ordered operations list.  That way we limit the total
- * work done by the commit
- */
-#define BTRFS_ORDERED_OPERATIONS_FLUSH_LIMIT (8 * 1024 * 1024)
-
 /* holds pointers to all of the tree roots */
 #define BTRFS_ROOT_TREE_OBJECTID 1ULL
 
@@ -391,10 +385,12 @@ struct btrfs_header {
                                      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->leafsize))
+#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) - \
-                                       sizeof(struct btrfs_file_extent_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))
@@ -474,7 +470,7 @@ struct btrfs_super_block {
        __le64 num_devices;
        __le32 sectorsize;
        __le32 nodesize;
-       __le32 leafsize;
+       __le32 __unused_leafsize;
        __le32 stripesize;
        __le32 sys_chunk_array_size;
        __le64 chunk_root_generation;
@@ -903,6 +899,8 @@ struct btrfs_file_extent_item {
        /*
         * disk space consumed by the extent, checksum blocks are included
         * in these numbers
+        *
+        * At this offset in the structure, the inline extent data start.
         */
        __le64 disk_bytenr;
        __le64 disk_num_bytes;
@@ -1305,8 +1303,8 @@ struct btrfs_block_group_cache {
         */
        struct list_head cluster_list;
 
-       /* For delayed block group creation */
-       struct list_head new_bg_list;
+       /* For delayed block group creation or deletion of empty block groups */
+       struct list_head bg_list;
 };
 
 /* delayed seq elem */
@@ -1545,6 +1543,7 @@ struct btrfs_fs_info {
        struct btrfs_workqueue *endio_workers;
        struct btrfs_workqueue *endio_meta_workers;
        struct btrfs_workqueue *endio_raid56_workers;
+       struct btrfs_workqueue *endio_repair_workers;
        struct btrfs_workqueue *rmw_workers;
        struct btrfs_workqueue *endio_meta_write_workers;
        struct btrfs_workqueue *endio_write_workers;
@@ -1574,6 +1573,7 @@ struct btrfs_fs_info {
        int do_barriers;
        int closing;
        int log_root_recovering;
+       int open;
 
        u64 total_pinned;
 
@@ -1723,6 +1723,12 @@ struct btrfs_fs_info {
 
        /* Used to reclaim the metadata space in the background. */
        struct work_struct async_reclaim_work;
+
+       spinlock_t unused_bgs_lock;
+       struct list_head unused_bgs;
+
+       /* For btrfs to record security options */
+       struct security_mnt_opts security_opts;
 };
 
 struct btrfs_subvolume_writers {
@@ -1776,12 +1782,12 @@ struct btrfs_root {
 
        /* free ino cache stuff */
        struct btrfs_free_space_ctl *free_ino_ctl;
-       enum btrfs_caching_type cached;
-       spinlock_t cache_lock;
-       wait_queue_head_t cache_wait;
+       enum btrfs_caching_type ino_cache_state;
+       spinlock_t ino_cache_lock;
+       wait_queue_head_t ino_cache_wait;
        struct btrfs_free_space_ctl *free_ino_pinned;
-       u64 cache_progress;
-       struct inode *cache_inode;
+       u64 ino_cache_progress;
+       struct inode *ino_cache_inode;
 
        struct mutex log_mutex;
        wait_queue_head_t log_writer_wait;
@@ -1806,18 +1812,14 @@ struct btrfs_root {
        /* node allocations are done in nodesize units */
        u32 nodesize;
 
-       /* leaf allocations are done in leafsize units */
-       u32 leafsize;
-
        u32 stripesize;
 
        u32 type;
 
        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;
@@ -2094,6 +2096,7 @@ struct btrfs_ioctl_defrag_range_args {
 #define        BTRFS_MOUNT_CHANGE_INODE_CACHE  (1 << 24)
 
 #define BTRFS_DEFAULT_COMMIT_INTERVAL  (30)
+#define BTRFS_DEFAULT_MAX_INLINE       (8192)
 
 #define btrfs_clear_opt(o, opt)                ((o) &= ~BTRFS_MOUNT_##opt)
 #define btrfs_set_opt(o, opt)          ((o) |= BTRFS_MOUNT_##opt)
@@ -2995,8 +2998,6 @@ BTRFS_SETGET_STACK_FUNCS(super_sectorsize, struct btrfs_super_block,
                         sectorsize, 32);
 BTRFS_SETGET_STACK_FUNCS(super_nodesize, struct btrfs_super_block,
                         nodesize, 32);
-BTRFS_SETGET_STACK_FUNCS(super_leafsize, struct btrfs_super_block,
-                        leafsize, 32);
 BTRFS_SETGET_STACK_FUNCS(super_stripesize, struct btrfs_super_block,
                         stripesize, 32);
 BTRFS_SETGET_STACK_FUNCS(super_root_dir, struct btrfs_super_block,
@@ -3049,14 +3050,12 @@ BTRFS_SETGET_STACK_FUNCS(stack_file_extent_compression,
 static inline unsigned long
 btrfs_file_extent_inline_start(struct btrfs_file_extent_item *e)
 {
-       unsigned long offset = (unsigned long)e;
-       offset += offsetof(struct btrfs_file_extent_item, disk_bytenr);
-       return offset;
+       return (unsigned long)e + BTRFS_FILE_EXTENT_INLINE_DATA_START;
 }
 
 static inline u32 btrfs_file_extent_calc_inline_size(u32 datasize)
 {
-       return offsetof(struct btrfs_file_extent_item, disk_bytenr) + datasize;
+       return BTRFS_FILE_EXTENT_INLINE_DATA_START + datasize;
 }
 
 BTRFS_SETGET_FUNCS(file_extent_disk_bytenr, struct btrfs_file_extent_item,
@@ -3086,9 +3085,7 @@ BTRFS_SETGET_FUNCS(file_extent_other_encoding, struct btrfs_file_extent_item,
 static inline u32 btrfs_file_extent_inline_item_len(struct extent_buffer *eb,
                                                    struct btrfs_item *e)
 {
-       unsigned long offset;
-       offset = offsetof(struct btrfs_file_extent_item, disk_bytenr);
-       return btrfs_item_size(eb, e) - offset;
+       return btrfs_item_size(eb, e) - BTRFS_FILE_EXTENT_INLINE_DATA_START;
 }
 
 /* this returns the number of file bytes represented by the inline item.
@@ -3232,13 +3229,6 @@ static inline struct btrfs_fs_info *btrfs_sb(struct super_block *sb)
        return sb->s_fs_info;
 }
 
-static inline u32 btrfs_level_size(struct btrfs_root *root, int level)
-{
-       if (level == 0)
-               return root->leafsize;
-       return root->nodesize;
-}
-
 /* helper function to cast into the data area of the leaf. */
 #define btrfs_item_ptr(leaf, slot, type) \
        ((type *)(btrfs_leaf_data(leaf) + \
@@ -3263,7 +3253,7 @@ static inline gfp_t btrfs_alloc_write_mask(struct address_space *mapping)
 static inline u64 btrfs_calc_trans_metadata_size(struct btrfs_root *root,
                                                 unsigned num_items)
 {
-       return (root->leafsize + root->nodesize * (BTRFS_MAX_LEVEL - 1)) *
+       return (root->nodesize + root->nodesize * (BTRFS_MAX_LEVEL - 1)) *
                2 * num_items;
 }
 
@@ -3274,8 +3264,7 @@ static inline u64 btrfs_calc_trans_metadata_size(struct btrfs_root *root,
 static inline u64 btrfs_calc_trunc_metadata_size(struct btrfs_root *root,
                                                 unsigned num_items)
 {
-       return (root->leafsize + root->nodesize * (BTRFS_MAX_LEVEL - 1)) *
-               num_items;
+       return root->nodesize * BTRFS_MAX_LEVEL * num_items;
 }
 
 int btrfs_should_throttle_delayed_refs(struct btrfs_trans_handle *trans,
@@ -3305,9 +3294,9 @@ struct btrfs_block_group_cache *btrfs_lookup_block_group(
                                                 u64 bytenr);
 void btrfs_put_block_group(struct btrfs_block_group_cache *cache);
 int get_block_group_index(struct btrfs_block_group_cache *cache);
-struct extent_buffer *btrfs_alloc_free_block(struct btrfs_trans_handle *trans,
-                                       struct btrfs_root *root, u32 blocksize,
-                                       u64 parent, u64 root_objectid,
+struct extent_buffer *btrfs_alloc_tree_block(struct btrfs_trans_handle *trans,
+                                       struct btrfs_root *root, u64 parent,
+                                       u64 root_objectid,
                                        struct btrfs_disk_key *key, int level,
                                        u64 hint, u64 empty_size);
 void btrfs_free_tree_block(struct btrfs_trans_handle *trans,
@@ -3363,6 +3352,7 @@ int btrfs_make_block_group(struct btrfs_trans_handle *trans,
                           u64 size);
 int btrfs_remove_block_group(struct btrfs_trans_handle *trans,
                             struct btrfs_root *root, u64 group_start);
+void btrfs_delete_unused_bgs(struct btrfs_fs_info *fs_info);
 void btrfs_create_pending_block_groups(struct btrfs_trans_handle *trans,
                                       struct btrfs_root *root);
 u64 btrfs_get_alloc_profile(struct btrfs_root *root, int data);
@@ -3604,6 +3594,7 @@ static inline void free_fs_info(struct btrfs_fs_info *fs_info)
        kfree(fs_info->uuid_root);
        kfree(fs_info->super_copy);
        kfree(fs_info->super_for_commit);
+       security_free_mnt_opts(&fs_info->security_opts);
        kfree(fs_info);
 }
 
@@ -3739,8 +3730,7 @@ int btrfs_del_csums(struct btrfs_trans_handle *trans,
 int btrfs_lookup_bio_sums(struct btrfs_root *root, struct inode *inode,
                          struct bio *bio, u32 *dst);
 int btrfs_lookup_bio_sums_dio(struct btrfs_root *root, struct inode *inode,
-                             struct btrfs_dio_private *dip, struct bio *bio,
-                             u64 logical_offset);
+                             struct bio *bio, u64 logical_offset);
 int btrfs_insert_file_extent(struct btrfs_trans_handle *trans,
                             struct btrfs_root *root,
                             u64 objectid, u64 pos,
@@ -4141,8 +4131,15 @@ static inline int btrfs_defrag_cancelled(struct btrfs_fs_info *fs_info)
 /* Sanity test specific functions */
 #ifdef CONFIG_BTRFS_FS_RUN_SANITY_TESTS
 void btrfs_test_destroy_inode(struct inode *inode);
-int btrfs_verify_qgroup_counts(struct btrfs_fs_info *fs_info, u64 qgroupid,
-                              u64 rfer, u64 excl);
 #endif
 
+static inline int btrfs_test_is_dummy_root(struct btrfs_root *root)
+{
+#ifdef CONFIG_BTRFS_FS_RUN_SANITY_TESTS
+       if (unlikely(test_bit(BTRFS_ROOT_DUMMY_ROOT, &root->state)))
+               return 1;
+#endif
+       return 0;
+}
+
 #endif
index a2e90f855d7d1e3cad650fc1d9691fd2de01cf65..054577bddaf27869d9a524a73d4df5a76072e4e1 100644 (file)
@@ -1042,7 +1042,7 @@ static int __btrfs_update_delayed_inode(struct btrfs_trans_handle *trans,
        int ret;
 
        key.objectid = node->inode_id;
-       btrfs_set_key_type(&key, BTRFS_INODE_ITEM_KEY);
+       key.type = BTRFS_INODE_ITEM_KEY;
        key.offset = 0;
 
        if (test_bit(BTRFS_DELAYED_NODE_DEL_IREF, &node->flags))
@@ -1099,7 +1099,7 @@ err_out:
 search:
        btrfs_release_path(path);
 
-       btrfs_set_key_type(&key, BTRFS_INODE_EXTREF_KEY);
+       key.type = BTRFS_INODE_EXTREF_KEY;
        key.offset = -1;
        ret = btrfs_search_slot(trans, root, &key, path, -1, 1);
        if (ret < 0)
@@ -1473,7 +1473,7 @@ int btrfs_insert_delayed_dir_index(struct btrfs_trans_handle *trans,
        }
 
        delayed_item->key.objectid = btrfs_ino(dir);
-       btrfs_set_key_type(&delayed_item->key, BTRFS_DIR_INDEX_KEY);
+       delayed_item->key.type = BTRFS_DIR_INDEX_KEY;
        delayed_item->key.offset = index;
 
        dir_item = (struct btrfs_dir_item *)delayed_item->data;
@@ -1542,7 +1542,7 @@ int btrfs_delete_delayed_dir_index(struct btrfs_trans_handle *trans,
                return PTR_ERR(node);
 
        item_key.objectid = btrfs_ino(dir);
-       btrfs_set_key_type(&item_key, BTRFS_DIR_INDEX_KEY);
+       item_key.type = BTRFS_DIR_INDEX_KEY;
        item_key.offset = index;
 
        ret = btrfs_delete_delayed_insertion_item(root, node, &item_key);
index eea26e1b2fda1d21230dd5f1e01e25f8fb23a3e8..6f662b34ba0e8392c58d7d481092f9e461631af4 100644 (file)
@@ -168,8 +168,12 @@ no_valid_dev_replace_entry_found:
                                        dev_replace->srcdev->total_bytes;
                                dev_replace->tgtdev->disk_total_bytes =
                                        dev_replace->srcdev->disk_total_bytes;
+                               dev_replace->tgtdev->commit_total_bytes =
+                                       dev_replace->srcdev->commit_total_bytes;
                                dev_replace->tgtdev->bytes_used =
                                        dev_replace->srcdev->bytes_used;
+                               dev_replace->tgtdev->commit_bytes_used =
+                                       dev_replace->srcdev->commit_bytes_used;
                        }
                        dev_replace->tgtdev->is_tgtdev_for_dev_replace = 1;
                        btrfs_init_dev_replace_tgtdev_for_resume(fs_info,
@@ -329,30 +333,34 @@ int btrfs_dev_replace_start(struct btrfs_root *root,
            args->start.tgtdev_name[0] == '\0')
                return -EINVAL;
 
-       mutex_lock(&fs_info->volume_mutex);
-       ret = btrfs_init_dev_replace_tgtdev(root, args->start.tgtdev_name,
-                                           &tgt_device);
-       if (ret) {
-               btrfs_err(fs_info, "target device %s is invalid!",
-                      args->start.tgtdev_name);
-               mutex_unlock(&fs_info->volume_mutex);
-               return -EINVAL;
+       /*
+        * Here we commit the transaction to make sure commit_total_bytes
+        * of all the devices are updated.
+        */
+       trans = btrfs_attach_transaction(root);
+       if (!IS_ERR(trans)) {
+               ret = btrfs_commit_transaction(trans, root);
+               if (ret)
+                       return ret;
+       } else if (PTR_ERR(trans) != -ENOENT) {
+               return PTR_ERR(trans);
        }
 
+       /* the disk copy procedure reuses the scrub code */
+       mutex_lock(&fs_info->volume_mutex);
        ret = btrfs_dev_replace_find_srcdev(root, args->start.srcdevid,
                                            args->start.srcdev_name,
                                            &src_device);
-       mutex_unlock(&fs_info->volume_mutex);
        if (ret) {
-               ret = -EINVAL;
-               goto leave_no_lock;
+               mutex_unlock(&fs_info->volume_mutex);
+               return ret;
        }
 
-       if (tgt_device->total_bytes < src_device->total_bytes) {
-               btrfs_err(fs_info, "target device is smaller than source device!");
-               ret = -EINVAL;
-               goto leave_no_lock;
-       }
+       ret = btrfs_init_dev_replace_tgtdev(root, args->start.tgtdev_name,
+                                           src_device, &tgt_device);
+       mutex_unlock(&fs_info->volume_mutex);
+       if (ret)
+               return ret;
 
        btrfs_dev_replace_lock(dev_replace);
        switch (dev_replace->replace_state) {
@@ -380,10 +388,6 @@ int btrfs_dev_replace_start(struct btrfs_root *root,
                      src_device->devid,
                      rcu_str_deref(tgt_device->name));
 
-       tgt_device->total_bytes = src_device->total_bytes;
-       tgt_device->disk_total_bytes = src_device->disk_total_bytes;
-       tgt_device->bytes_used = src_device->bytes_used;
-
        /*
         * from now on, the writes to the srcdev are all duplicated to
         * go to the tgtdev as well (refer to btrfs_map_block()).
@@ -414,7 +418,7 @@ int btrfs_dev_replace_start(struct btrfs_root *root,
 
        /* the disk copy procedure reuses the scrub code */
        ret = btrfs_scrub_dev(fs_info, src_device->devid, 0,
-                             src_device->total_bytes,
+                             btrfs_device_get_total_bytes(src_device),
                              &dev_replace->scrub_progress, 0, 1);
 
        ret = btrfs_dev_replace_finishing(root->fs_info, ret);
@@ -426,9 +430,7 @@ leave:
        dev_replace->srcdev = NULL;
        dev_replace->tgtdev = NULL;
        btrfs_dev_replace_unlock(dev_replace);
-leave_no_lock:
-       if (tgt_device)
-               btrfs_destroy_dev_replace_tgtdev(fs_info, tgt_device);
+       btrfs_destroy_dev_replace_tgtdev(fs_info, tgt_device);
        return ret;
 }
 
@@ -507,9 +509,10 @@ static int btrfs_dev_replace_finishing(struct btrfs_fs_info *fs_info,
        ret = btrfs_commit_transaction(trans, root);
        WARN_ON(ret);
 
+       mutex_lock(&uuid_mutex);
        /* keep away write_all_supers() during the finishing procedure */
-       mutex_lock(&root->fs_info->chunk_mutex);
        mutex_lock(&root->fs_info->fs_devices->device_list_mutex);
+       mutex_lock(&root->fs_info->chunk_mutex);
        btrfs_dev_replace_lock(dev_replace);
        dev_replace->replace_state =
                scrub_ret ? BTRFS_IOCTL_DEV_REPLACE_STATE_CANCELED
@@ -532,8 +535,9 @@ static int btrfs_dev_replace_finishing(struct btrfs_fs_info *fs_info,
                              src_device->devid,
                              rcu_str_deref(tgt_device->name), scrub_ret);
                btrfs_dev_replace_unlock(dev_replace);
-               mutex_unlock(&root->fs_info->fs_devices->device_list_mutex);
                mutex_unlock(&root->fs_info->chunk_mutex);
+               mutex_unlock(&root->fs_info->fs_devices->device_list_mutex);
+               mutex_unlock(&uuid_mutex);
                if (tgt_device)
                        btrfs_destroy_dev_replace_tgtdev(fs_info, tgt_device);
                mutex_unlock(&dev_replace->lock_finishing_cancel_unmount);
@@ -542,7 +546,7 @@ static int btrfs_dev_replace_finishing(struct btrfs_fs_info *fs_info,
        }
 
        printk_in_rcu(KERN_INFO
-                     "BTRFS: dev_replace from %s (devid %llu) to %s) finished\n",
+                     "BTRFS: dev_replace from %s (devid %llu) to %s finished\n",
                      src_device->missing ? "<missing disk>" :
                        rcu_str_deref(src_device->name),
                      src_device->devid,
@@ -550,23 +554,29 @@ static int btrfs_dev_replace_finishing(struct btrfs_fs_info *fs_info,
        tgt_device->is_tgtdev_for_dev_replace = 0;
        tgt_device->devid = src_device->devid;
        src_device->devid = BTRFS_DEV_REPLACE_DEVID;
-       tgt_device->bytes_used = src_device->bytes_used;
        memcpy(uuid_tmp, tgt_device->uuid, sizeof(uuid_tmp));
        memcpy(tgt_device->uuid, src_device->uuid, sizeof(tgt_device->uuid));
        memcpy(src_device->uuid, uuid_tmp, sizeof(src_device->uuid));
-       tgt_device->total_bytes = src_device->total_bytes;
-       tgt_device->disk_total_bytes = src_device->disk_total_bytes;
-       tgt_device->bytes_used = src_device->bytes_used;
+       btrfs_device_set_total_bytes(tgt_device, src_device->total_bytes);
+       btrfs_device_set_disk_total_bytes(tgt_device,
+                                         src_device->disk_total_bytes);
+       btrfs_device_set_bytes_used(tgt_device, src_device->bytes_used);
+       ASSERT(list_empty(&src_device->resized_list));
+       tgt_device->commit_total_bytes = src_device->commit_total_bytes;
+       tgt_device->commit_bytes_used = src_device->bytes_used;
        if (fs_info->sb->s_bdev == src_device->bdev)
                fs_info->sb->s_bdev = tgt_device->bdev;
        if (fs_info->fs_devices->latest_bdev == src_device->bdev)
                fs_info->fs_devices->latest_bdev = tgt_device->bdev;
        list_add(&tgt_device->dev_alloc_list, &fs_info->fs_devices->alloc_list);
+       fs_info->fs_devices->rw_devices++;
 
        /* replace the sysfs entry */
        btrfs_kobj_rm_device(fs_info, src_device);
        btrfs_kobj_add_device(fs_info, tgt_device);
 
+       btrfs_dev_replace_unlock(dev_replace);
+
        btrfs_rm_dev_replace_blocked(fs_info);
 
        btrfs_rm_dev_replace_srcdev(fs_info, src_device);
@@ -580,9 +590,9 @@ static int btrfs_dev_replace_finishing(struct btrfs_fs_info *fs_info,
         * superblock is scratched out so that it is no longer marked to
         * belong to this filesystem.
         */
-       btrfs_dev_replace_unlock(dev_replace);
-       mutex_unlock(&root->fs_info->fs_devices->device_list_mutex);
        mutex_unlock(&root->fs_info->chunk_mutex);
+       mutex_unlock(&root->fs_info->fs_devices->device_list_mutex);
+       mutex_unlock(&uuid_mutex);
 
        /* write back the superblocks */
        trans = btrfs_start_transaction(root, 0);
@@ -643,6 +653,7 @@ void btrfs_dev_replace_status(struct btrfs_fs_info *fs_info,
                              struct btrfs_ioctl_dev_replace_args *args)
 {
        struct btrfs_dev_replace *dev_replace = &fs_info->dev_replace;
+       struct btrfs_device *srcdev;
 
        btrfs_dev_replace_lock(dev_replace);
        /* even if !dev_replace_is_valid, the values are good enough for
@@ -665,8 +676,9 @@ void btrfs_dev_replace_status(struct btrfs_fs_info *fs_info,
                break;
        case BTRFS_IOCTL_DEV_REPLACE_STATE_STARTED:
        case BTRFS_IOCTL_DEV_REPLACE_STATE_SUSPENDED:
+               srcdev = dev_replace->srcdev;
                args->status.progress_1000 = div64_u64(dev_replace->cursor_left,
-                       div64_u64(dev_replace->srcdev->total_bytes, 1000));
+                       div64_u64(btrfs_device_get_total_bytes(srcdev), 1000));
                break;
        }
        btrfs_dev_replace_unlock(dev_replace);
@@ -825,7 +837,7 @@ static int btrfs_dev_replace_continue_on_mount(struct btrfs_fs_info *fs_info)
 
        ret = btrfs_scrub_dev(fs_info, dev_replace->srcdev->devid,
                              dev_replace->committed_cursor_left,
-                             dev_replace->srcdev->total_bytes,
+                             btrfs_device_get_total_bytes(dev_replace->srcdev),
                              &dev_replace->scrub_progress, 0, 1);
        ret = btrfs_dev_replace_finishing(fs_info, ret);
        WARN_ON(ret);
index a0691df5dceaa9dfdb3100732bf82ee81793f32c..fc8df866e91988bdbcbee0d9e50f770ebd0de905 100644 (file)
@@ -86,7 +86,7 @@ int btrfs_insert_xattr_item(struct btrfs_trans_handle *trans,
        BUG_ON(name_len + data_len > BTRFS_MAX_XATTR_SIZE(root));
 
        key.objectid = objectid;
-       btrfs_set_key_type(&key, BTRFS_XATTR_ITEM_KEY);
+       key.type = BTRFS_XATTR_ITEM_KEY;
        key.offset = btrfs_name_hash(name, name_len);
 
        data_size = sizeof(*dir_item) + name_len + data_len;
@@ -137,7 +137,7 @@ int btrfs_insert_dir_item(struct btrfs_trans_handle *trans, struct btrfs_root
        u32 data_size;
 
        key.objectid = btrfs_ino(dir);
-       btrfs_set_key_type(&key, BTRFS_DIR_ITEM_KEY);
+       key.type = BTRFS_DIR_ITEM_KEY;
        key.offset = btrfs_name_hash(name, name_len);
 
        path = btrfs_alloc_path();
@@ -204,7 +204,7 @@ struct btrfs_dir_item *btrfs_lookup_dir_item(struct btrfs_trans_handle *trans,
        int cow = mod != 0;
 
        key.objectid = dir;
-       btrfs_set_key_type(&key, BTRFS_DIR_ITEM_KEY);
+       key.type = BTRFS_DIR_ITEM_KEY;
 
        key.offset = btrfs_name_hash(name, name_len);
 
@@ -234,7 +234,7 @@ int btrfs_check_dir_item_collision(struct btrfs_root *root, u64 dir,
                return -ENOMEM;
 
        key.objectid = dir;
-       btrfs_set_key_type(&key, BTRFS_DIR_ITEM_KEY);
+       key.type = BTRFS_DIR_ITEM_KEY;
        key.offset = btrfs_name_hash(name, name_len);
 
        ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
@@ -297,7 +297,7 @@ btrfs_lookup_dir_index_item(struct btrfs_trans_handle *trans,
        int cow = mod != 0;
 
        key.objectid = dir;
-       btrfs_set_key_type(&key, BTRFS_DIR_INDEX_KEY);
+       key.type = BTRFS_DIR_INDEX_KEY;
        key.offset = objectid;
 
        ret = btrfs_search_slot(trans, root, &key, path, ins_len, cow);
@@ -367,7 +367,7 @@ struct btrfs_dir_item *btrfs_lookup_xattr(struct btrfs_trans_handle *trans,
        int cow = mod != 0;
 
        key.objectid = dir;
-       btrfs_set_key_type(&key, BTRFS_XATTR_ITEM_KEY);
+       key.type = BTRFS_XATTR_ITEM_KEY;
        key.offset = btrfs_name_hash(name, name_len);
        ret = btrfs_search_slot(trans, root, &key, path, ins_len, cow);
        if (ret < 0)
index d0d78dc07792dd822682198bb72c4a2a758e02ba..fa45e3cae40db660c6170811cfc54c66d81556c1 100644 (file)
@@ -72,21 +72,41 @@ static int btrfs_cleanup_transaction(struct btrfs_root *root);
 static void btrfs_error_commit_super(struct btrfs_root *root);
 
 /*
- * end_io_wq structs are used to do processing in task context when an IO is
- * complete.  This is used during reads to verify checksums, and it is used
+ * btrfs_end_io_wq structs are used to do processing in task context when an IO
+ * is complete.  This is used during reads to verify checksums, and it is used
  * by writes to insert metadata for new file extents after IO is complete.
  */
-struct end_io_wq {
+struct btrfs_end_io_wq {
        struct bio *bio;
        bio_end_io_t *end_io;
        void *private;
        struct btrfs_fs_info *info;
        int error;
-       int metadata;
+       enum btrfs_wq_endio_type metadata;
        struct list_head list;
        struct btrfs_work work;
 };
 
+static struct kmem_cache *btrfs_end_io_wq_cache;
+
+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,
+                                       NULL);
+       if (!btrfs_end_io_wq_cache)
+               return -ENOMEM;
+       return 0;
+}
+
+void btrfs_end_io_wq_exit(void)
+{
+       if (btrfs_end_io_wq_cache)
+               kmem_cache_destroy(btrfs_end_io_wq_cache);
+}
+
 /*
  * async submit bios are used to offload expensive checksumming
  * onto the worker threads.  They checksum file and metadata bios
@@ -327,8 +347,7 @@ static int verify_parent_transid(struct extent_io_tree *io_tree,
 {
        struct extent_state *cached_state = NULL;
        int ret;
-       bool need_lock = (current->journal_info ==
-                         (void *)BTRFS_SEND_TRANS_STUB);
+       bool need_lock = (current->journal_info == BTRFS_SEND_TRANS_STUB);
 
        if (!parent_transid || btrfs_header_generation(eb) == parent_transid)
                return 0;
@@ -348,9 +367,9 @@ static int verify_parent_transid(struct extent_io_tree *io_tree,
                ret = 0;
                goto out;
        }
-       printk_ratelimited("parent transid verify failed on %llu wanted %llu "
-                      "found %llu\n",
-                      eb->start, parent_transid, btrfs_header_generation(eb));
+       printk_ratelimited(KERN_INFO "BTRFS (device %s): parent transid verify failed on %llu wanted %llu found %llu\n",
+                       eb->fs_info->sb->s_id, eb->start,
+                       parent_transid, btrfs_header_generation(eb));
        ret = 1;
 
        /*
@@ -607,22 +626,22 @@ static int btree_readpage_end_io_hook(struct btrfs_io_bio *io_bio,
                goto err;
 
        eb->read_mirror = mirror;
-       if (test_bit(EXTENT_BUFFER_IOERR, &eb->bflags)) {
+       if (test_bit(EXTENT_BUFFER_READ_ERR, &eb->bflags)) {
                ret = -EIO;
                goto err;
        }
 
        found_start = btrfs_header_bytenr(eb);
        if (found_start != eb->start) {
-               printk_ratelimited(KERN_INFO "BTRFS: bad tree block start "
+               printk_ratelimited(KERN_INFO "BTRFS (device %s): bad tree block start "
                               "%llu %llu\n",
-                              found_start, eb->start);
+                              eb->fs_info->sb->s_id, found_start, eb->start);
                ret = -EIO;
                goto err;
        }
        if (check_tree_block_fsid(root, eb)) {
-               printk_ratelimited(KERN_INFO "BTRFS: bad fsid on block %llu\n",
-                              eb->start);
+               printk_ratelimited(KERN_INFO "BTRFS (device %s): bad fsid on block %llu\n",
+                              eb->fs_info->sb->s_id, eb->start);
                ret = -EIO;
                goto err;
        }
@@ -680,7 +699,7 @@ static int btree_io_failed_hook(struct page *page, int failed_mirror)
        struct btrfs_root *root = BTRFS_I(page->mapping->host)->root;
 
        eb = (struct extent_buffer *)page->private;
-       set_bit(EXTENT_BUFFER_IOERR, &eb->bflags);
+       set_bit(EXTENT_BUFFER_READ_ERR, &eb->bflags);
        eb->read_mirror = failed_mirror;
        atomic_dec(&eb->io_pages);
        if (test_and_clear_bit(EXTENT_BUFFER_READAHEAD, &eb->bflags))
@@ -690,7 +709,7 @@ static int btree_io_failed_hook(struct page *page, int failed_mirror)
 
 static void end_workqueue_bio(struct bio *bio, int err)
 {
-       struct end_io_wq *end_io_wq = bio->bi_private;
+       struct btrfs_end_io_wq *end_io_wq = bio->bi_private;
        struct btrfs_fs_info *fs_info;
        struct btrfs_workqueue *wq;
        btrfs_work_func_t func;
@@ -713,7 +732,11 @@ static void end_workqueue_bio(struct bio *bio, int err)
                        func = btrfs_endio_write_helper;
                }
        } else {
-               if (end_io_wq->metadata == BTRFS_WQ_ENDIO_RAID56) {
+               if (unlikely(end_io_wq->metadata ==
+                            BTRFS_WQ_ENDIO_DIO_REPAIR)) {
+                       wq = fs_info->endio_repair_workers;
+                       func = btrfs_endio_repair_helper;
+               } else if (end_io_wq->metadata == BTRFS_WQ_ENDIO_RAID56) {
                        wq = fs_info->endio_raid56_workers;
                        func = btrfs_endio_raid56_helper;
                } else if (end_io_wq->metadata) {
@@ -729,19 +752,12 @@ static void end_workqueue_bio(struct bio *bio, int err)
        btrfs_queue_work(wq, &end_io_wq->work);
 }
 
-/*
- * For the metadata arg you want
- *
- * 0 - if data
- * 1 - if normal metadta
- * 2 - if writing to the free space cache area
- * 3 - raid parity work
- */
 int btrfs_bio_wq_end_io(struct btrfs_fs_info *info, struct bio *bio,
-                       int metadata)
+                       enum btrfs_wq_endio_type metadata)
 {
-       struct end_io_wq *end_io_wq;
-       end_io_wq = kmalloc(sizeof(*end_io_wq), GFP_NOFS);
+       struct btrfs_end_io_wq *end_io_wq;
+
+       end_io_wq = kmem_cache_alloc(btrfs_end_io_wq_cache, GFP_NOFS);
        if (!end_io_wq)
                return -ENOMEM;
 
@@ -925,7 +941,7 @@ static int btree_submit_bio_hook(struct inode *inode, int rw, struct bio *bio,
                 * can happen in the async kernel threads
                 */
                ret = btrfs_bio_wq_end_io(BTRFS_I(inode)->root->fs_info,
-                                         bio, 1);
+                                         bio, BTRFS_WQ_ENDIO_METADATA);
                if (ret)
                        goto out_w_error;
                ret = btrfs_map_bio(BTRFS_I(inode)->root, rw, bio,
@@ -1057,20 +1073,17 @@ static const struct address_space_operations btree_aops = {
        .set_page_dirty = btree_set_page_dirty,
 };
 
-int readahead_tree_block(struct btrfs_root *root, u64 bytenr, u32 blocksize,
-                        u64 parent_transid)
+void readahead_tree_block(struct btrfs_root *root, u64 bytenr, u32 blocksize)
 {
        struct extent_buffer *buf = NULL;
        struct inode *btree_inode = root->fs_info->btree_inode;
-       int ret = 0;
 
        buf = btrfs_find_create_tree_block(root, bytenr, blocksize);
        if (!buf)
-               return 0;
+               return;
        read_extent_buffer_pages(&BTRFS_I(btree_inode)->io_tree,
                                 buf, 0, WAIT_NONE, btree_get_extent, 0);
        free_extent_buffer(buf);
-       return ret;
 }
 
 int reada_tree_block_flagged(struct btrfs_root *root, u64 bytenr, u32 blocksize,
@@ -1106,7 +1119,7 @@ int reada_tree_block_flagged(struct btrfs_root *root, u64 bytenr, u32 blocksize,
 }
 
 struct extent_buffer *btrfs_find_tree_block(struct btrfs_root *root,
-                                           u64 bytenr, u32 blocksize)
+                                           u64 bytenr)
 {
        return find_extent_buffer(root->fs_info, bytenr);
 }
@@ -1114,11 +1127,9 @@ struct extent_buffer *btrfs_find_tree_block(struct btrfs_root *root,
 struct extent_buffer *btrfs_find_create_tree_block(struct btrfs_root *root,
                                                 u64 bytenr, u32 blocksize)
 {
-#ifdef CONFIG_BTRFS_FS_RUN_SANITY_TESTS
-       if (unlikely(test_bit(BTRFS_ROOT_DUMMY_ROOT, &root->state)))
+       if (btrfs_test_is_dummy_root(root))
                return alloc_test_extent_buffer(root->fs_info, bytenr,
                                                blocksize);
-#endif
        return alloc_extent_buffer(root->fs_info, bytenr, blocksize);
 }
 
@@ -1136,12 +1147,12 @@ int btrfs_wait_tree_block_writeback(struct extent_buffer *buf)
 }
 
 struct extent_buffer *read_tree_block(struct btrfs_root *root, u64 bytenr,
-                                     u32 blocksize, u64 parent_transid)
+                                     u64 parent_transid)
 {
        struct extent_buffer *buf = NULL;
        int ret;
 
-       buf = btrfs_find_create_tree_block(root, bytenr, blocksize);
+       buf = btrfs_find_create_tree_block(root, bytenr, root->nodesize);
        if (!buf)
                return NULL;
 
@@ -1200,16 +1211,14 @@ btrfs_free_subvolume_writers(struct btrfs_subvolume_writers *writers)
        kfree(writers);
 }
 
-static void __setup_root(u32 nodesize, u32 leafsize, u32 sectorsize,
-                        u32 stripesize, struct btrfs_root *root,
-                        struct btrfs_fs_info *fs_info,
+static void __setup_root(u32 nodesize, u32 sectorsize, u32 stripesize,
+                        struct btrfs_root *root, struct btrfs_fs_info *fs_info,
                         u64 objectid)
 {
        root->node = NULL;
        root->commit_root = NULL;
        root->sectorsize = sectorsize;
        root->nodesize = nodesize;
-       root->leafsize = leafsize;
        root->stripesize = stripesize;
        root->state = 0;
        root->orphan_cleanup_state = 0;
@@ -1295,7 +1304,7 @@ struct btrfs_root *btrfs_alloc_dummy_root(void)
        root = btrfs_alloc_root(NULL);
        if (!root)
                return ERR_PTR(-ENOMEM);
-       __setup_root(4096, 4096, 4096, 4096, root, NULL, 1);
+       __setup_root(4096, 4096, 4096, root, NULL, 1);
        set_bit(BTRFS_ROOT_DUMMY_ROOT, &root->state);
        root->alloc_bytenr = 0;
 
@@ -1318,15 +1327,13 @@ struct btrfs_root *btrfs_create_tree(struct btrfs_trans_handle *trans,
        if (!root)
                return ERR_PTR(-ENOMEM);
 
-       __setup_root(tree_root->nodesize, tree_root->leafsize,
-                    tree_root->sectorsize, tree_root->stripesize,
-                    root, fs_info, objectid);
+       __setup_root(tree_root->nodesize, tree_root->sectorsize,
+               tree_root->stripesize, root, fs_info, objectid);
        root->root_key.objectid = objectid;
        root->root_key.type = BTRFS_ROOT_ITEM_KEY;
        root->root_key.offset = 0;
 
-       leaf = btrfs_alloc_free_block(trans, root, root->leafsize,
-                                     0, objectid, NULL, 0, 0, 0);
+       leaf = btrfs_alloc_tree_block(trans, root, 0, objectid, NULL, 0, 0, 0);
        if (IS_ERR(leaf)) {
                ret = PTR_ERR(leaf);
                leaf = NULL;
@@ -1396,9 +1403,9 @@ static struct btrfs_root *alloc_log_tree(struct btrfs_trans_handle *trans,
        if (!root)
                return ERR_PTR(-ENOMEM);
 
-       __setup_root(tree_root->nodesize, tree_root->leafsize,
-                    tree_root->sectorsize, tree_root->stripesize,
-                    root, fs_info, BTRFS_TREE_LOG_OBJECTID);
+       __setup_root(tree_root->nodesize, tree_root->sectorsize,
+                    tree_root->stripesize, root, fs_info,
+                    BTRFS_TREE_LOG_OBJECTID);
 
        root->root_key.objectid = BTRFS_TREE_LOG_OBJECTID;
        root->root_key.type = BTRFS_ROOT_ITEM_KEY;
@@ -1413,9 +1420,8 @@ static struct btrfs_root *alloc_log_tree(struct btrfs_trans_handle *trans,
         * updated (along with back refs to the log tree).
         */
 
-       leaf = btrfs_alloc_free_block(trans, root, root->leafsize, 0,
-                                     BTRFS_TREE_LOG_OBJECTID, NULL,
-                                     0, 0, 0);
+       leaf = btrfs_alloc_tree_block(trans, root, 0, BTRFS_TREE_LOG_OBJECTID,
+                       NULL, 0, 0, 0);
        if (IS_ERR(leaf)) {
                kfree(root);
                return ERR_CAST(leaf);
@@ -1465,7 +1471,7 @@ int btrfs_add_log_tree(struct btrfs_trans_handle *trans,
        btrfs_set_stack_inode_generation(inode_item, 1);
        btrfs_set_stack_inode_size(inode_item, 3);
        btrfs_set_stack_inode_nlink(inode_item, 1);
-       btrfs_set_stack_inode_nbytes(inode_item, root->leafsize);
+       btrfs_set_stack_inode_nbytes(inode_item, root->nodesize);
        btrfs_set_stack_inode_mode(inode_item, S_IFDIR | 0755);
 
        btrfs_set_root_node(&log_root->root_item, log_root->node);
@@ -1485,7 +1491,6 @@ static struct btrfs_root *btrfs_read_tree_root(struct btrfs_root *tree_root,
        struct btrfs_fs_info *fs_info = tree_root->fs_info;
        struct btrfs_path *path;
        u64 generation;
-       u32 blocksize;
        int ret;
 
        path = btrfs_alloc_path();
@@ -1498,9 +1503,8 @@ static struct btrfs_root *btrfs_read_tree_root(struct btrfs_root *tree_root,
                goto alloc_fail;
        }
 
-       __setup_root(tree_root->nodesize, tree_root->leafsize,
-                    tree_root->sectorsize, tree_root->stripesize,
-                    root, fs_info, key->objectid);
+       __setup_root(tree_root->nodesize, tree_root->sectorsize,
+               tree_root->stripesize, root, fs_info, key->objectid);
 
        ret = btrfs_find_root(tree_root, key, path,
                              &root->root_item, &root->root_key);
@@ -1511,9 +1515,8 @@ static struct btrfs_root *btrfs_read_tree_root(struct btrfs_root *tree_root,
        }
 
        generation = btrfs_root_generation(&root->root_item);
-       blocksize = btrfs_level_size(root, btrfs_root_level(&root->root_item));
        root->node = read_tree_block(root, btrfs_root_bytenr(&root->root_item),
-                                    blocksize, generation);
+                                    generation);
        if (!root->node) {
                ret = -ENOMEM;
                goto find_fail;
@@ -1573,8 +1576,8 @@ int btrfs_init_fs_root(struct btrfs_root *root)
        root->subv_writers = writers;
 
        btrfs_init_free_ino_ctl(root);
-       spin_lock_init(&root->cache_lock);
-       init_waitqueue_head(&root->cache_wait);
+       spin_lock_init(&root->ino_cache_lock);
+       init_waitqueue_head(&root->ino_cache_wait);
 
        ret = get_anon_bdev(&root->anon_dev);
        if (ret)
@@ -1708,10 +1711,6 @@ static int btrfs_congested_fn(void *congested_data, int bdi_bits)
        return ret;
 }
 
-/*
- * If this fails, caller must call bdi_destroy() to get rid of the
- * bdi again.
- */
 static int setup_bdi(struct btrfs_fs_info *info, struct backing_dev_info *bdi)
 {
        int err;
@@ -1734,16 +1733,16 @@ static int setup_bdi(struct btrfs_fs_info *info, struct backing_dev_info *bdi)
 static void end_workqueue_fn(struct btrfs_work *work)
 {
        struct bio *bio;
-       struct end_io_wq *end_io_wq;
+       struct btrfs_end_io_wq *end_io_wq;
        int error;
 
-       end_io_wq = container_of(work, struct end_io_wq, work);
+       end_io_wq = container_of(work, struct btrfs_end_io_wq, work);
        bio = end_io_wq->bio;
 
        error = end_io_wq->error;
        bio->bi_private = end_io_wq->private;
        bio->bi_end_io = end_io_wq->end_io;
-       kfree(end_io_wq);
+       kmem_cache_free(btrfs_end_io_wq_cache, end_io_wq);
        bio_endio_nodec(bio, error);
 }
 
@@ -1772,6 +1771,7 @@ static int cleaner_kthread(void *arg)
                }
 
                btrfs_run_delayed_iputs(root);
+               btrfs_delete_unused_bgs(root->fs_info);
                again = btrfs_clean_one_deleted_snapshot(root);
                mutex_unlock(&root->fs_info->cleaner_mutex);
 
@@ -2063,6 +2063,7 @@ static void btrfs_stop_all_workers(struct btrfs_fs_info *fs_info)
        btrfs_destroy_workqueue(fs_info->endio_workers);
        btrfs_destroy_workqueue(fs_info->endio_meta_workers);
        btrfs_destroy_workqueue(fs_info->endio_raid56_workers);
+       btrfs_destroy_workqueue(fs_info->endio_repair_workers);
        btrfs_destroy_workqueue(fs_info->rmw_workers);
        btrfs_destroy_workqueue(fs_info->endio_meta_write_workers);
        btrfs_destroy_workqueue(fs_info->endio_write_workers);
@@ -2143,8 +2144,6 @@ int open_ctree(struct super_block *sb,
 {
        u32 sectorsize;
        u32 nodesize;
-       u32 leafsize;
-       u32 blocksize;
        u32 stripesize;
        u64 generation;
        u64 features;
@@ -2233,6 +2232,7 @@ int open_ctree(struct super_block *sb,
        spin_lock_init(&fs_info->super_lock);
        spin_lock_init(&fs_info->qgroup_op_lock);
        spin_lock_init(&fs_info->buffer_lock);
+       spin_lock_init(&fs_info->unused_bgs_lock);
        rwlock_init(&fs_info->tree_mod_log_lock);
        mutex_init(&fs_info->reloc_mutex);
        mutex_init(&fs_info->delalloc_root_mutex);
@@ -2242,6 +2242,7 @@ int open_ctree(struct super_block *sb,
        INIT_LIST_HEAD(&fs_info->dirty_cowonly_roots);
        INIT_LIST_HEAD(&fs_info->space_info);
        INIT_LIST_HEAD(&fs_info->tree_mod_seq_list);
+       INIT_LIST_HEAD(&fs_info->unused_bgs);
        btrfs_mapping_init(&fs_info->mapping_tree);
        btrfs_init_block_rsv(&fs_info->global_block_rsv,
                             BTRFS_BLOCK_RSV_GLOBAL);
@@ -2260,7 +2261,7 @@ int open_ctree(struct super_block *sb,
        atomic_set(&fs_info->qgroup_op_seq, 0);
        atomic64_set(&fs_info->tree_mod_seq, 0);
        fs_info->sb = sb;
-       fs_info->max_inline = 8192 * 1024;
+       fs_info->max_inline = BTRFS_DEFAULT_MAX_INLINE;
        fs_info->metadata_ratio = 0;
        fs_info->defrag_inodes = RB_ROOT;
        fs_info->free_chunk_space = 0;
@@ -2389,7 +2390,7 @@ int open_ctree(struct super_block *sb,
                goto fail_alloc;
        }
 
-       __setup_root(4096, 4096, 4096, 4096, tree_root,
+       __setup_root(4096, 4096, 4096, tree_root,
                     fs_info, BTRFS_ROOT_TREE_OBJECTID);
 
        invalidate_bdev(fs_devices->latest_bdev);
@@ -2469,19 +2470,22 @@ int open_ctree(struct super_block *sb,
                goto fail_alloc;
        }
 
-       if (btrfs_super_leafsize(disk_super) !=
+       /*
+        * Leafsize and nodesize were always equal, this is only a sanity check.
+        */
+       if (le32_to_cpu(disk_super->__unused_leafsize) !=
            btrfs_super_nodesize(disk_super)) {
                printk(KERN_ERR "BTRFS: couldn't mount because metadata "
                       "blocksizes don't match.  node %d leaf %d\n",
                       btrfs_super_nodesize(disk_super),
-                      btrfs_super_leafsize(disk_super));
+                      le32_to_cpu(disk_super->__unused_leafsize));
                err = -EINVAL;
                goto fail_alloc;
        }
-       if (btrfs_super_leafsize(disk_super) > BTRFS_MAX_METADATA_BLOCKSIZE) {
+       if (btrfs_super_nodesize(disk_super) > BTRFS_MAX_METADATA_BLOCKSIZE) {
                printk(KERN_ERR "BTRFS: couldn't mount because metadata "
                       "blocksize (%d) was too large\n",
-                      btrfs_super_leafsize(disk_super));
+                      btrfs_super_nodesize(disk_super));
                err = -EINVAL;
                goto fail_alloc;
        }
@@ -2498,17 +2502,16 @@ int open_ctree(struct super_block *sb,
         * flag our filesystem as having big metadata blocks if
         * they are bigger than the page size
         */
-       if (btrfs_super_leafsize(disk_super) > PAGE_CACHE_SIZE) {
+       if (btrfs_super_nodesize(disk_super) > PAGE_CACHE_SIZE) {
                if (!(features & BTRFS_FEATURE_INCOMPAT_BIG_METADATA))
                        printk(KERN_INFO "BTRFS: flagging fs with big metadata feature\n");
                features |= BTRFS_FEATURE_INCOMPAT_BIG_METADATA;
        }
 
        nodesize = btrfs_super_nodesize(disk_super);
-       leafsize = btrfs_super_leafsize(disk_super);
        sectorsize = btrfs_super_sectorsize(disk_super);
        stripesize = btrfs_super_stripesize(disk_super);
-       fs_info->dirty_metadata_batch = leafsize * (1 + ilog2(nr_cpu_ids));
+       fs_info->dirty_metadata_batch = nodesize * (1 + ilog2(nr_cpu_ids));
        fs_info->delalloc_batch = sectorsize * 512 * (1 + ilog2(nr_cpu_ids));
 
        /*
@@ -2516,7 +2519,7 @@ int open_ctree(struct super_block *sb,
         * extent buffers for the same range.  It leads to corruptions
         */
        if ((features & BTRFS_FEATURE_INCOMPAT_MIXED_GROUPS) &&
-           (sectorsize != leafsize)) {
+           (sectorsize != nodesize)) {
                printk(KERN_WARNING "BTRFS: unequal leaf/node/sector sizes "
                                "are not allowed for mixed block groups on %s\n",
                                sb->s_id);
@@ -2579,6 +2582,8 @@ int open_ctree(struct super_block *sb,
                btrfs_alloc_workqueue("endio-meta-write", flags, max_active, 2);
        fs_info->endio_raid56_workers =
                btrfs_alloc_workqueue("endio-raid56", flags, max_active, 4);
+       fs_info->endio_repair_workers =
+               btrfs_alloc_workqueue("endio-repair", flags, 1, 0);
        fs_info->rmw_workers =
                btrfs_alloc_workqueue("rmw", flags, max_active, 2);
        fs_info->endio_write_workers =
@@ -2600,11 +2605,12 @@ int open_ctree(struct super_block *sb,
              fs_info->submit_workers && fs_info->flush_workers &&
              fs_info->endio_workers && fs_info->endio_meta_workers &&
              fs_info->endio_meta_write_workers &&
+             fs_info->endio_repair_workers &&
              fs_info->endio_write_workers && fs_info->endio_raid56_workers &&
              fs_info->endio_freespace_worker && fs_info->rmw_workers &&
              fs_info->caching_workers && fs_info->readahead_workers &&
              fs_info->fixup_workers && fs_info->delayed_workers &&
-             fs_info->fixup_workers && fs_info->extent_workers &&
+             fs_info->extent_workers &&
              fs_info->qgroup_rescan_workers)) {
                err = -ENOMEM;
                goto fail_sb_buffer;
@@ -2615,7 +2621,6 @@ int open_ctree(struct super_block *sb,
                                    4 * 1024 * 1024 / PAGE_CACHE_SIZE);
 
        tree_root->nodesize = nodesize;
-       tree_root->leafsize = leafsize;
        tree_root->sectorsize = sectorsize;
        tree_root->stripesize = stripesize;
 
@@ -2642,16 +2647,14 @@ int open_ctree(struct super_block *sb,
                goto fail_sb_buffer;
        }
 
-       blocksize = btrfs_level_size(tree_root,
-                                    btrfs_super_chunk_root_level(disk_super));
        generation = btrfs_super_chunk_root_generation(disk_super);
 
-       __setup_root(nodesize, leafsize, sectorsize, stripesize,
-                    chunk_root, fs_info, BTRFS_CHUNK_TREE_OBJECTID);
+       __setup_root(nodesize, sectorsize, stripesize, chunk_root,
+                    fs_info, BTRFS_CHUNK_TREE_OBJECTID);
 
        chunk_root->node = read_tree_block(chunk_root,
                                           btrfs_super_chunk_root(disk_super),
-                                          blocksize, generation);
+                                          generation);
        if (!chunk_root->node ||
            !test_bit(EXTENT_BUFFER_UPTODATE, &chunk_root->node->bflags)) {
                printk(KERN_WARNING "BTRFS: failed to read chunk root on %s\n",
@@ -2684,13 +2687,11 @@ int open_ctree(struct super_block *sb,
        }
 
 retry_root_backup:
-       blocksize = btrfs_level_size(tree_root,
-                                    btrfs_super_root_level(disk_super));
        generation = btrfs_super_generation(disk_super);
 
        tree_root->node = read_tree_block(tree_root,
                                          btrfs_super_root(disk_super),
-                                         blocksize, generation);
+                                         generation);
        if (!tree_root->node ||
            !test_bit(EXTENT_BUFFER_UPTODATE, &tree_root->node->bflags)) {
                printk(KERN_WARNING "BTRFS: failed to read tree root on %s\n",
@@ -2859,9 +2860,6 @@ retry_root_backup:
                        err = -EIO;
                        goto fail_qgroup;
                }
-               blocksize =
-                    btrfs_level_size(tree_root,
-                                     btrfs_super_log_root_level(disk_super));
 
                log_tree_root = btrfs_alloc_root(fs_info);
                if (!log_tree_root) {
@@ -2869,11 +2867,10 @@ retry_root_backup:
                        goto fail_qgroup;
                }
 
-               __setup_root(nodesize, leafsize, sectorsize, stripesize,
+               __setup_root(nodesize, sectorsize, stripesize,
                             log_tree_root, fs_info, BTRFS_TREE_LOG_OBJECTID);
 
                log_tree_root->node = read_tree_block(tree_root, bytenr,
-                                                     blocksize,
                                                      generation + 1);
                if (!log_tree_root->node ||
                    !extent_buffer_uptodate(log_tree_root->node)) {
@@ -2980,6 +2977,8 @@ retry_root_backup:
                fs_info->update_uuid_tree_gen = 1;
        }
 
+       fs_info->open = 1;
+
        return 0;
 
 fail_qgroup:
@@ -3139,7 +3138,8 @@ static int write_dev_supers(struct btrfs_device *device,
 
        for (i = 0; i < max_mirrors; i++) {
                bytenr = btrfs_sb_offset(i);
-               if (bytenr + BTRFS_SUPER_INFO_SIZE >= device->total_bytes)
+               if (bytenr + BTRFS_SUPER_INFO_SIZE >=
+                   device->commit_total_bytes)
                        break;
 
                if (wait) {
@@ -3456,8 +3456,9 @@ static int write_all_supers(struct btrfs_root *root, int max_mirrors)
                btrfs_set_stack_device_type(dev_item, dev->type);
                btrfs_set_stack_device_id(dev_item, dev->devid);
                btrfs_set_stack_device_total_bytes(dev_item,
-                                                  dev->disk_total_bytes);
-               btrfs_set_stack_device_bytes_used(dev_item, dev->bytes_used);
+                                                  dev->commit_total_bytes);
+               btrfs_set_stack_device_bytes_used(dev_item,
+                                                 dev->commit_bytes_used);
                btrfs_set_stack_device_io_align(dev_item, dev->io_align);
                btrfs_set_stack_device_io_width(dev_item, dev->io_width);
                btrfs_set_stack_device_sector_size(dev_item, dev->sector_size);
@@ -3532,7 +3533,7 @@ void btrfs_drop_and_free_fs_root(struct btrfs_fs_info *fs_info,
 
 static void free_fs_root(struct btrfs_root *root)
 {
-       iput(root->cache_inode);
+       iput(root->ino_cache_inode);
        WARN_ON(!RB_EMPTY_ROOT(&root->inode_tree));
        btrfs_free_block_rsv(root, root->orphan_block_rsv);
        root->orphan_block_rsv = NULL;
@@ -3623,7 +3624,7 @@ int btrfs_commit_super(struct btrfs_root *root)
        return btrfs_commit_transaction(trans, root);
 }
 
-int close_ctree(struct btrfs_root *root)
+void close_ctree(struct btrfs_root *root)
 {
        struct btrfs_fs_info *fs_info = root->fs_info;
        int ret;
@@ -3689,6 +3690,7 @@ int close_ctree(struct btrfs_root *root)
        invalidate_inode_pages2(fs_info->btree_inode->i_mapping);
        btrfs_stop_all_workers(fs_info);
 
+       fs_info->open = 0;
        free_root_pointers(fs_info, 1);
 
        iput(fs_info->btree_inode);
@@ -3711,8 +3713,6 @@ int close_ctree(struct btrfs_root *root)
 
        btrfs_free_block_rsv(root, root->orphan_block_rsv);
        root->orphan_block_rsv = NULL;
-
-       return 0;
 }
 
 int btrfs_buffer_uptodate(struct extent_buffer *buf, u64 parent_transid,
@@ -3814,10 +3814,73 @@ int btrfs_read_buffer(struct extent_buffer *buf, u64 parent_transid)
 static int btrfs_check_super_valid(struct btrfs_fs_info *fs_info,
                              int read_only)
 {
+       struct btrfs_super_block *sb = fs_info->super_copy;
+       int ret = 0;
+
+       if (sb->root_level > BTRFS_MAX_LEVEL) {
+               printk(KERN_ERR "BTRFS: tree_root level too big: %d > %d\n",
+                               sb->root_level, BTRFS_MAX_LEVEL);
+               ret = -EINVAL;
+       }
+       if (sb->chunk_root_level > BTRFS_MAX_LEVEL) {
+               printk(KERN_ERR "BTRFS: chunk_root level too big: %d > %d\n",
+                               sb->chunk_root_level, BTRFS_MAX_LEVEL);
+               ret = -EINVAL;
+       }
+       if (sb->log_root_level > BTRFS_MAX_LEVEL) {
+               printk(KERN_ERR "BTRFS: log_root level too big: %d > %d\n",
+                               sb->log_root_level, BTRFS_MAX_LEVEL);
+               ret = -EINVAL;
+       }
+
        /*
-        * Placeholder for checks
+        * The common minimum, we don't know if we can trust the nodesize/sectorsize
+        * items yet, they'll be verified later. Issue just a warning.
         */
-       return 0;
+       if (!IS_ALIGNED(sb->root, 4096))
+               printk(KERN_WARNING "BTRFS: tree_root block unaligned: %llu\n",
+                               sb->root);
+       if (!IS_ALIGNED(sb->chunk_root, 4096))
+               printk(KERN_WARNING "BTRFS: tree_root block unaligned: %llu\n",
+                               sb->chunk_root);
+       if (!IS_ALIGNED(sb->log_root, 4096))
+               printk(KERN_WARNING "BTRFS: tree_root block unaligned: %llu\n",
+                               sb->log_root);
+
+       if (memcmp(fs_info->fsid, sb->dev_item.fsid, BTRFS_UUID_SIZE) != 0) {
+               printk(KERN_ERR "BTRFS: dev_item UUID does not match fsid: %pU != %pU\n",
+                               fs_info->fsid, sb->dev_item.fsid);
+               ret = -EINVAL;
+       }
+
+       /*
+        * Hint to catch really bogus numbers, bitflips or so, more exact checks are
+        * done later
+        */
+       if (sb->num_devices > (1UL << 31))
+               printk(KERN_WARNING "BTRFS: suspicious number of devices: %llu\n",
+                               sb->num_devices);
+
+       if (sb->bytenr != BTRFS_SUPER_INFO_OFFSET) {
+               printk(KERN_ERR "BTRFS: super offset mismatch %llu != %u\n",
+                               sb->bytenr, BTRFS_SUPER_INFO_OFFSET);
+               ret = -EINVAL;
+       }
+
+       /*
+        * The generation is a global counter, we'll trust it more than the others
+        * but it's still possible that it's the one that's wrong.
+        */
+       if (sb->generation < sb->chunk_root_generation)
+               printk(KERN_WARNING
+                       "BTRFS: suspicious: generation < chunk_root_generation: %llu < %llu\n",
+                       sb->generation, sb->chunk_root_generation);
+       if (sb->generation < sb->cache_generation && sb->cache_generation != (u64)-1)
+               printk(KERN_WARNING
+                       "BTRFS: suspicious: generation < cache_generation: %llu < %llu\n",
+                       sb->generation, sb->cache_generation);
+
+       return ret;
 }
 
 static void btrfs_error_commit_super(struct btrfs_root *root)
@@ -4009,9 +4072,8 @@ static int btrfs_destroy_marked_extents(struct btrfs_root *root,
 
                clear_extent_bits(dirty_pages, start, end, mark, GFP_NOFS);
                while (start <= end) {
-                       eb = btrfs_find_tree_block(root, start,
-                                                  root->leafsize);
-                       start += root->leafsize;
+                       eb = btrfs_find_tree_block(root, start);
+                       start += root->nodesize;
                        if (!eb)
                                continue;
                        wait_on_extent_buffer_writeback(eb);
index 23ce3ceba0a975d5544eb35f0dfd306aff87ad0c..414651821fb3b38a62df3a72fa44877f66b2e602 100644 (file)
 #define BTRFS_SUPER_MIRROR_MAX  3
 #define BTRFS_SUPER_MIRROR_SHIFT 12
 
-enum {
+enum btrfs_wq_endio_type {
        BTRFS_WQ_ENDIO_DATA = 0,
        BTRFS_WQ_ENDIO_METADATA = 1,
        BTRFS_WQ_ENDIO_FREE_SPACE = 2,
        BTRFS_WQ_ENDIO_RAID56 = 3,
+       BTRFS_WQ_ENDIO_DIO_REPAIR = 4,
 };
 
 static inline u64 btrfs_sb_offset(int mirror)
@@ -44,9 +45,8 @@ struct btrfs_device;
 struct btrfs_fs_devices;
 
 struct extent_buffer *read_tree_block(struct btrfs_root *root, u64 bytenr,
-                                     u32 blocksize, u64 parent_transid);
-int readahead_tree_block(struct btrfs_root *root, u64 bytenr, u32 blocksize,
-                        u64 parent_transid);
+                                     u64 parent_transid);
+void readahead_tree_block(struct btrfs_root *root, u64 bytenr, u32 blocksize);
 int reada_tree_block_flagged(struct btrfs_root *root, u64 bytenr, u32 blocksize,
                         int mirror_num, struct extent_buffer **eb);
 struct extent_buffer *btrfs_find_create_tree_block(struct btrfs_root *root,
@@ -56,13 +56,13 @@ void clean_tree_block(struct btrfs_trans_handle *trans,
 int open_ctree(struct super_block *sb,
               struct btrfs_fs_devices *fs_devices,
               char *options);
-int close_ctree(struct btrfs_root *root);
+void close_ctree(struct btrfs_root *root);
 int write_ctree_super(struct btrfs_trans_handle *trans,
                      struct btrfs_root *root, int max_mirrors);
 struct buffer_head *btrfs_read_dev_super(struct block_device *bdev);
 int btrfs_commit_super(struct btrfs_root *root);
 struct extent_buffer *btrfs_find_tree_block(struct btrfs_root *root,
-                                           u64 bytenr, u32 blocksize);
+                                           u64 bytenr);
 struct btrfs_root *btrfs_read_fs_root(struct btrfs_root *tree_root,
                                      struct btrfs_key *location);
 int btrfs_init_fs_root(struct btrfs_root *root);
@@ -119,7 +119,7 @@ int btrfs_read_buffer(struct extent_buffer *buf, u64 parent_transid);
 u32 btrfs_csum_data(char *data, u32 seed, size_t len);
 void btrfs_csum_final(u32 crc, char *result);
 int btrfs_bio_wq_end_io(struct btrfs_fs_info *info, struct bio *bio,
-                       int metadata);
+                       enum btrfs_wq_endio_type metadata);
 int btrfs_wq_submit_bio(struct btrfs_fs_info *fs_info, struct inode *inode,
                        int rw, struct bio *bio, int mirror_num,
                        unsigned long bio_flags, u64 bio_offset,
@@ -141,6 +141,8 @@ int btree_lock_page_hook(struct page *page, void *data,
                                void (*flush_fn)(void *));
 int btrfs_calc_num_tolerated_disk_barrier_failures(
        struct btrfs_fs_info *fs_info);
+int __init btrfs_end_io_wq_init(void);
+void btrfs_end_io_wq_exit(void);
 
 #ifdef CONFIG_DEBUG_LOCK_ALLOC
 void btrfs_init_lockdep(void);
index 41422a3de8ed03f66c7341d8289c1626097a4ff7..37d164540c3a25c469d831899e05f9cc5eccb9d1 100644 (file)
@@ -70,7 +70,7 @@ static struct dentry *btrfs_get_dentry(struct super_block *sb, u64 objectid,
                return ERR_PTR(-ESTALE);
 
        key.objectid = root_objectid;
-       btrfs_set_key_type(&key, BTRFS_ROOT_ITEM_KEY);
+       key.type = BTRFS_ROOT_ITEM_KEY;
        key.offset = (u64)-1;
 
        index = srcu_read_lock(&fs_info->subvol_srcu);
@@ -82,7 +82,7 @@ static struct dentry *btrfs_get_dentry(struct super_block *sb, u64 objectid,
        }
 
        key.objectid = objectid;
-       btrfs_set_key_type(&key, BTRFS_INODE_ITEM_KEY);
+       key.type = BTRFS_INODE_ITEM_KEY;
        key.offset = 0;
 
        inode = btrfs_iget(sb, &key, root, NULL);
index caaf015d6e4b740d091e0f46f60c06aa612ff111..d565895710126f813fd8a6c88c520ffe0fcffd3c 100644 (file)
@@ -491,7 +491,7 @@ next:
                                                          key.objectid);
                        if (key.type == BTRFS_METADATA_ITEM_KEY)
                                last = key.objectid +
-                                       fs_info->tree_root->leafsize;
+                                       fs_info->tree_root->nodesize;
                        else
                                last = key.objectid + key.offset;
 
@@ -765,7 +765,7 @@ int btrfs_lookup_extent_info(struct btrfs_trans_handle *trans,
         * different
         */
        if (metadata && !btrfs_fs_incompat(root->fs_info, SKINNY_METADATA)) {
-               offset = root->leafsize;
+               offset = root->nodesize;
                metadata = 0;
        }
 
@@ -799,13 +799,13 @@ again:
                                              path->slots[0]);
                        if (key.objectid == bytenr &&
                            key.type == BTRFS_EXTENT_ITEM_KEY &&
-                           key.offset == root->leafsize)
+                           key.offset == root->nodesize)
                                ret = 0;
                }
                if (ret) {
                        key.objectid = bytenr;
                        key.type = BTRFS_EXTENT_ITEM_KEY;
-                       key.offset = root->leafsize;
+                       key.offset = root->nodesize;
                        btrfs_release_path(path);
                        goto again;
                }
@@ -2651,7 +2651,7 @@ int btrfs_check_space_for_delayed_refs(struct btrfs_trans_handle *trans,
        num_bytes = btrfs_calc_trans_metadata_size(root, 1);
        num_heads = heads_to_leaves(root, num_heads);
        if (num_heads > 1)
-               num_bytes += (num_heads - 1) * root->leafsize;
+               num_bytes += (num_heads - 1) * root->nodesize;
        num_bytes <<= 1;
        global_rsv = &root->fs_info->global_block_rsv;
 
@@ -3073,10 +3073,10 @@ static int __btrfs_mod_ref(struct btrfs_trans_handle *trans,
        int (*process_func)(struct btrfs_trans_handle *, struct btrfs_root *,
                            u64, u64, u64, u64, u64, u64, int);
 
-#ifdef CONFIG_BTRFS_FS_RUN_SANITY_TESTS
-       if (unlikely(test_bit(BTRFS_ROOT_DUMMY_ROOT, &root->state)))
+
+       if (btrfs_test_is_dummy_root(root))
                return 0;
-#endif
+
        ref_root = btrfs_header_owner(buf);
        nritems = btrfs_header_nritems(buf);
        level = btrfs_header_level(buf);
@@ -3097,7 +3097,7 @@ static int __btrfs_mod_ref(struct btrfs_trans_handle *trans,
        for (i = 0; i < nritems; i++) {
                if (level == 0) {
                        btrfs_item_key_to_cpu(buf, &key, i);
-                       if (btrfs_key_type(&key) != BTRFS_EXTENT_DATA_KEY)
+                       if (key.type != BTRFS_EXTENT_DATA_KEY)
                                continue;
                        fi = btrfs_item_ptr(buf, i,
                                            struct btrfs_file_extent_item);
@@ -3117,7 +3117,7 @@ static int __btrfs_mod_ref(struct btrfs_trans_handle *trans,
                                goto fail;
                } else {
                        bytenr = btrfs_node_blockptr(buf, i);
-                       num_bytes = btrfs_level_size(root, level - 1);
+                       num_bytes = root->nodesize;
                        ret = process_func(trans, root, bytenr, num_bytes,
                                           parent, ref_root, level - 1, 0,
                                           1);
@@ -4343,11 +4343,21 @@ static inline int need_do_async_reclaim(struct btrfs_space_info *space_info,
 }
 
 static int btrfs_need_do_async_reclaim(struct btrfs_space_info *space_info,
-                                      struct btrfs_fs_info *fs_info)
+                                      struct btrfs_fs_info *fs_info,
+                                      int flush_state)
 {
        u64 used;
 
        spin_lock(&space_info->lock);
+       /*
+        * We run out of space and have not got any free space via flush_space,
+        * so don't bother doing async reclaim.
+        */
+       if (flush_state > COMMIT_TRANS && space_info->full) {
+               spin_unlock(&space_info->lock);
+               return 0;
+       }
+
        used = space_info->bytes_used + space_info->bytes_reserved +
               space_info->bytes_pinned + space_info->bytes_readonly +
               space_info->bytes_may_use;
@@ -4380,11 +4390,12 @@ static void btrfs_async_reclaim_metadata_space(struct work_struct *work)
                flush_space(fs_info->fs_root, space_info, to_reclaim,
                            to_reclaim, flush_state);
                flush_state++;
-               if (!btrfs_need_do_async_reclaim(space_info, fs_info))
+               if (!btrfs_need_do_async_reclaim(space_info, fs_info,
+                                                flush_state))
                        return;
        } while (flush_state <= COMMIT_TRANS);
 
-       if (btrfs_need_do_async_reclaim(space_info, fs_info))
+       if (btrfs_need_do_async_reclaim(space_info, fs_info, flush_state))
                queue_work(system_unbound_wq, work);
 }
 
@@ -4502,7 +4513,13 @@ again:
                space_info->flush = 1;
        } else if (!ret && space_info->flags & BTRFS_BLOCK_GROUP_METADATA) {
                used += orig_bytes;
-               if (need_do_async_reclaim(space_info, root->fs_info, used) &&
+               /*
+                * We will do the space reservation dance during log replay,
+                * which means we won't have fs_info->fs_root set, so don't do
+                * the async reclaim as we will panic.
+                */
+               if (!root->fs_info->log_root_recovering &&
+                   need_do_async_reclaim(space_info, root->fs_info, used) &&
                    !work_busy(&root->fs_info->async_reclaim_work))
                        queue_work(system_unbound_wq,
                                   &root->fs_info->async_reclaim_work);
@@ -4839,7 +4856,7 @@ static u64 calc_global_metadata_size(struct btrfs_fs_info *fs_info)
        if (num_bytes * 3 > meta_used)
                num_bytes = div64_u64(meta_used, 3);
 
-       return ALIGN(num_bytes, fs_info->extent_root->leafsize << 10);
+       return ALIGN(num_bytes, fs_info->extent_root->nodesize << 10);
 }
 
 static void update_global_block_rsv(struct btrfs_fs_info *fs_info)
@@ -4988,7 +5005,7 @@ int btrfs_subvolume_reserve_metadata(struct btrfs_root *root,
 
        if (root->fs_info->quota_enabled) {
                /* One for parent inode, two for dir entries */
-               num_bytes = 3 * root->leafsize;
+               num_bytes = 3 * root->nodesize;
                ret = btrfs_qgroup_reserve(root, num_bytes);
                if (ret)
                        return ret;
@@ -5176,7 +5193,7 @@ int btrfs_delalloc_reserve_metadata(struct inode *inode, u64 num_bytes)
 
        if (root->fs_info->quota_enabled) {
                ret = btrfs_qgroup_reserve(root, num_bytes +
-                                          nr_extents * root->leafsize);
+                                          nr_extents * root->nodesize);
                if (ret)
                        goto out_fail;
        }
@@ -5185,7 +5202,7 @@ int btrfs_delalloc_reserve_metadata(struct inode *inode, u64 num_bytes)
        if (unlikely(ret)) {
                if (root->fs_info->quota_enabled)
                        btrfs_qgroup_free(root, num_bytes +
-                                               nr_extents * root->leafsize);
+                                               nr_extents * root->nodesize);
                goto out_fail;
        }
 
@@ -5301,7 +5318,7 @@ void btrfs_delalloc_release_metadata(struct inode *inode, u64 num_bytes)
                                      btrfs_ino(inode), to_free, 0);
        if (root->fs_info->quota_enabled) {
                btrfs_qgroup_free(root, num_bytes +
-                                       dropped * root->leafsize);
+                                       dropped * root->nodesize);
        }
 
        btrfs_block_rsv_release(root, &root->fs_info->delalloc_block_rsv,
@@ -5422,6 +5439,20 @@ static int update_block_group(struct btrfs_root *root,
                        spin_unlock(&cache->space_info->lock);
                } else {
                        old_val -= num_bytes;
+
+                       /*
+                        * No longer have used bytes in this block group, queue
+                        * it for deletion.
+                        */
+                       if (old_val == 0) {
+                               spin_lock(&info->unused_bgs_lock);
+                               if (list_empty(&cache->bg_list)) {
+                                       btrfs_get_block_group(cache);
+                                       list_add_tail(&cache->bg_list,
+                                                     &info->unused_bgs);
+                               }
+                               spin_unlock(&info->unused_bgs_lock);
+                       }
                        btrfs_set_block_group_used(&cache->item, old_val);
                        cache->pinned += num_bytes;
                        cache->space_info->bytes_pinned += num_bytes;
@@ -6233,10 +6264,9 @@ int btrfs_free_extent(struct btrfs_trans_handle *trans, struct btrfs_root *root,
        int ret;
        struct btrfs_fs_info *fs_info = root->fs_info;
 
-#ifdef CONFIG_BTRFS_FS_RUN_SANITY_TESTS
-       if (unlikely(test_bit(BTRFS_ROOT_DUMMY_ROOT, &root->state)))
+       if (btrfs_test_is_dummy_root(root))
                return 0;
-#endif
+
        add_pinned_bytes(root->fs_info, num_bytes, owner, root_objectid);
 
        /*
@@ -6263,14 +6293,6 @@ int btrfs_free_extent(struct btrfs_trans_handle *trans, struct btrfs_root *root,
        return ret;
 }
 
-static u64 stripe_align(struct btrfs_root *root,
-                       struct btrfs_block_group_cache *cache,
-                       u64 val, u64 num_bytes)
-{
-       u64 ret = ALIGN(val, root->stripesize);
-       return ret;
-}
-
 /*
  * when we wait for progress in the block group caching, its because
  * our allocation attempt failed at least once.  So, we must sleep
@@ -6464,7 +6486,7 @@ static noinline int find_free_extent(struct btrfs_root *orig_root,
        bool have_caching_bg = false;
 
        WARN_ON(num_bytes < root->sectorsize);
-       btrfs_set_key_type(ins, BTRFS_EXTENT_ITEM_KEY);
+       ins->type = BTRFS_EXTENT_ITEM_KEY;
        ins->objectid = 0;
        ins->offset = 0;
 
@@ -6751,8 +6773,7 @@ unclustered_alloc:
                        goto loop;
                }
 checks:
-               search_start = stripe_align(root, block_group,
-                                           offset, num_bytes);
+               search_start = ALIGN(offset, root->stripesize);
 
                /* move on to the next group */
                if (search_start + num_bytes >
@@ -7077,7 +7098,7 @@ static int alloc_reserved_tree_block(struct btrfs_trans_handle *trans,
        path = btrfs_alloc_path();
        if (!path) {
                btrfs_free_and_pin_reserved_extent(root, ins->objectid,
-                                                  root->leafsize);
+                                                  root->nodesize);
                return -ENOMEM;
        }
 
@@ -7086,7 +7107,7 @@ static int alloc_reserved_tree_block(struct btrfs_trans_handle *trans,
                                      ins, size);
        if (ret) {
                btrfs_free_and_pin_reserved_extent(root, ins->objectid,
-                                                  root->leafsize);
+                                                  root->nodesize);
                btrfs_free_path(path);
                return ret;
        }
@@ -7101,7 +7122,7 @@ static int alloc_reserved_tree_block(struct btrfs_trans_handle *trans,
 
        if (skinny_metadata) {
                iref = (struct btrfs_extent_inline_ref *)(extent_item + 1);
-               num_bytes = root->leafsize;
+               num_bytes = root->nodesize;
        } else {
                block_info = (struct btrfs_tree_block_info *)(extent_item + 1);
                btrfs_set_tree_block_key(leaf, block_info, key);
@@ -7131,14 +7152,14 @@ static int alloc_reserved_tree_block(struct btrfs_trans_handle *trans,
                        return ret;
        }
 
-       ret = update_block_group(root, ins->objectid, root->leafsize, 1);
+       ret = update_block_group(root, ins->objectid, root->nodesize, 1);
        if (ret) { /* -ENOENT, logic error */
                btrfs_err(fs_info, "update block group failed for %llu %llu",
                        ins->objectid, ins->offset);
                BUG();
        }
 
-       trace_btrfs_reserved_extent_alloc(root, ins->objectid, root->leafsize);
+       trace_btrfs_reserved_extent_alloc(root, ins->objectid, root->nodesize);
        return ret;
 }
 
@@ -7213,17 +7234,19 @@ btrfs_init_new_buffer(struct btrfs_trans_handle *trans, struct btrfs_root *root,
        btrfs_set_buffer_uptodate(buf);
 
        if (root->root_key.objectid == BTRFS_TREE_LOG_OBJECTID) {
+               buf->log_index = root->log_transid % 2;
                /*
                 * we allow two log transactions at a time, use different
                 * EXENT bit to differentiate dirty pages.
                 */
-               if (root->log_transid % 2 == 0)
+               if (buf->log_index == 0)
                        set_extent_dirty(&root->dirty_log_pages, buf->start,
                                        buf->start + buf->len - 1, GFP_NOFS);
                else
                        set_extent_new(&root->dirty_log_pages, buf->start,
                                        buf->start + buf->len - 1, GFP_NOFS);
        } else {
+               buf->log_index = -1;
                set_extent_dirty(&trans->transaction->dirty_pages, buf->start,
                         buf->start + buf->len - 1, GFP_NOFS);
        }
@@ -7300,8 +7323,8 @@ static void unuse_block_rsv(struct btrfs_fs_info *fs_info,
  *
  * returns the tree buffer or NULL.
  */
-struct extent_buffer *btrfs_alloc_free_block(struct btrfs_trans_handle *trans,
-                                       struct btrfs_root *root, u32 blocksize,
+struct extent_buffer *btrfs_alloc_tree_block(struct btrfs_trans_handle *trans,
+                                       struct btrfs_root *root,
                                        u64 parent, u64 root_objectid,
                                        struct btrfs_disk_key *key, int level,
                                        u64 hint, u64 empty_size)
@@ -7311,18 +7334,18 @@ struct extent_buffer *btrfs_alloc_free_block(struct btrfs_trans_handle *trans,
        struct extent_buffer *buf;
        u64 flags = 0;
        int ret;
+       u32 blocksize = root->nodesize;
        bool skinny_metadata = btrfs_fs_incompat(root->fs_info,
                                                 SKINNY_METADATA);
 
-#ifdef CONFIG_BTRFS_FS_RUN_SANITY_TESTS
-       if (unlikely(test_bit(BTRFS_ROOT_DUMMY_ROOT, &root->state))) {
+       if (btrfs_test_is_dummy_root(root)) {
                buf = btrfs_init_new_buffer(trans, root, root->alloc_bytenr,
                                            blocksize, 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))
                return ERR_CAST(block_rsv);
@@ -7417,7 +7440,7 @@ static noinline void reada_walk_down(struct btrfs_trans_handle *trans,
 
        eb = path->nodes[wc->level];
        nritems = btrfs_header_nritems(eb);
-       blocksize = btrfs_level_size(root, wc->level - 1);
+       blocksize = root->nodesize;
 
        for (slot = path->slots[wc->level]; slot < nritems; slot++) {
                if (nread >= wc->reada_count)
@@ -7464,10 +7487,7 @@ static noinline void reada_walk_down(struct btrfs_trans_handle *trans,
                                continue;
                }
 reada:
-               ret = readahead_tree_block(root, bytenr, blocksize,
-                                          generation);
-               if (ret)
-                       break;
+               readahead_tree_block(root, bytenr, blocksize);
                nread++;
        }
        wc->reada_slot = slot;
@@ -7626,7 +7646,6 @@ walk_down:
        level = root_level;
        while (level >= 0) {
                if (path->nodes[level] == NULL) {
-                       int child_bsize = root->nodesize;
                        int parent_slot;
                        u64 child_gen;
                        u64 child_bytenr;
@@ -7638,8 +7657,7 @@ walk_down:
                        child_bytenr = btrfs_node_blockptr(eb, parent_slot);
                        child_gen = btrfs_node_ptr_generation(eb, parent_slot);
 
-                       eb = read_tree_block(root, child_bytenr, child_bsize,
-                                            child_gen);
+                       eb = read_tree_block(root, child_bytenr, child_gen);
                        if (!eb || !extent_buffer_uptodate(eb)) {
                                ret = -EIO;
                                goto out;
@@ -7655,7 +7673,7 @@ walk_down:
                        ret = btrfs_qgroup_record_ref(trans, root->fs_info,
                                                root->objectid,
                                                child_bytenr,
-                                               child_bsize,
+                                               root->nodesize,
                                                BTRFS_QGROUP_OPER_SUB_SUBTREE,
                                                0);
                        if (ret)
@@ -7806,9 +7824,9 @@ static noinline int do_walk_down(struct btrfs_trans_handle *trans,
        }
 
        bytenr = btrfs_node_blockptr(path->nodes[level], path->slots[level]);
-       blocksize = btrfs_level_size(root, level - 1);
+       blocksize = root->nodesize;
 
-       next = btrfs_find_tree_block(root, bytenr, blocksize);
+       next = btrfs_find_tree_block(root, bytenr);
        if (!next) {
                next = btrfs_find_create_tree_block(root, bytenr, blocksize);
                if (!next)
@@ -7870,7 +7888,7 @@ static noinline int do_walk_down(struct btrfs_trans_handle *trans,
        if (!next) {
                if (reada && level == 1)
                        reada_walk_down(trans, root, wc, path);
-               next = read_tree_block(root, bytenr, blocksize, generation);
+               next = read_tree_block(root, bytenr, generation);
                if (!next || !extent_buffer_uptodate(next)) {
                        free_extent_buffer(next);
                        return -EIO;
@@ -8853,6 +8871,16 @@ int btrfs_free_block_groups(struct btrfs_fs_info *info)
        }
        up_write(&info->commit_root_sem);
 
+       spin_lock(&info->unused_bgs_lock);
+       while (!list_empty(&info->unused_bgs)) {
+               block_group = list_first_entry(&info->unused_bgs,
+                                              struct btrfs_block_group_cache,
+                                              bg_list);
+               list_del_init(&block_group->bg_list);
+               btrfs_put_block_group(block_group);
+       }
+       spin_unlock(&info->unused_bgs_lock);
+
        spin_lock(&info->block_group_cache_lock);
        while ((n = rb_last(&info->block_group_cache_tree)) != NULL) {
                block_group = rb_entry(n, struct btrfs_block_group_cache,
@@ -8987,7 +9015,7 @@ btrfs_create_block_group_cache(struct btrfs_root *root, u64 start, u64 size)
        init_rwsem(&cache->data_rwsem);
        INIT_LIST_HEAD(&cache->list);
        INIT_LIST_HEAD(&cache->cluster_list);
-       INIT_LIST_HEAD(&cache->new_bg_list);
+       INIT_LIST_HEAD(&cache->bg_list);
        btrfs_init_free_space_ctl(cache);
 
        return cache;
@@ -9009,7 +9037,7 @@ int btrfs_read_block_groups(struct btrfs_root *root)
        root = info->extent_root;
        key.objectid = 0;
        key.offset = 0;
-       btrfs_set_key_type(&key, BTRFS_BLOCK_GROUP_ITEM_KEY);
+       key.type = BTRFS_BLOCK_GROUP_ITEM_KEY;
        path = btrfs_alloc_path();
        if (!path)
                return -ENOMEM;
@@ -9128,8 +9156,18 @@ int btrfs_read_block_groups(struct btrfs_root *root)
                __link_block_group(space_info, cache);
 
                set_avail_alloc_bits(root->fs_info, cache->flags);
-               if (btrfs_chunk_readonly(root, cache->key.objectid))
+               if (btrfs_chunk_readonly(root, cache->key.objectid)) {
                        set_block_group_ro(cache, 1);
+               } else if (btrfs_block_group_used(&cache->item) == 0) {
+                       spin_lock(&info->unused_bgs_lock);
+                       /* Should always be true but just in case. */
+                       if (list_empty(&cache->bg_list)) {
+                               btrfs_get_block_group(cache);
+                               list_add_tail(&cache->bg_list,
+                                             &info->unused_bgs);
+                       }
+                       spin_unlock(&info->unused_bgs_lock);
+               }
        }
 
        list_for_each_entry_rcu(space_info, &root->fs_info->space_info, list) {
@@ -9170,10 +9208,8 @@ void btrfs_create_pending_block_groups(struct btrfs_trans_handle *trans,
        struct btrfs_key key;
        int ret = 0;
 
-       list_for_each_entry_safe(block_group, tmp, &trans->new_bgs,
-                                new_bg_list) {
-               list_del_init(&block_group->new_bg_list);
-
+       list_for_each_entry_safe(block_group, tmp, &trans->new_bgs, bg_list) {
+               list_del_init(&block_group->bg_list);
                if (ret)
                        continue;
 
@@ -9259,7 +9295,7 @@ int btrfs_make_block_group(struct btrfs_trans_handle *trans,
 
        __link_block_group(cache->space_info, cache);
 
-       list_add_tail(&cache->new_bg_list, &trans->new_bgs);
+       list_add_tail(&cache->bg_list, &trans->new_bgs);
 
        set_avail_alloc_bits(extent_root->fs_info, type);
 
@@ -9413,8 +9449,6 @@ int btrfs_remove_block_group(struct btrfs_trans_handle *trans,
 
        memcpy(&key, &block_group->key, sizeof(key));
 
-       btrfs_clear_space_info_full(root->fs_info);
-
        btrfs_put_block_group(block_group);
        btrfs_put_block_group(block_group);
 
@@ -9430,6 +9464,101 @@ out:
        return ret;
 }
 
+/*
+ * Process the unused_bgs list and remove any that don't have any allocated
+ * space inside of them.
+ */
+void btrfs_delete_unused_bgs(struct btrfs_fs_info *fs_info)
+{
+       struct btrfs_block_group_cache *block_group;
+       struct btrfs_space_info *space_info;
+       struct btrfs_root *root = fs_info->extent_root;
+       struct btrfs_trans_handle *trans;
+       int ret = 0;
+
+       if (!fs_info->open)
+               return;
+
+       spin_lock(&fs_info->unused_bgs_lock);
+       while (!list_empty(&fs_info->unused_bgs)) {
+               u64 start, end;
+
+               block_group = list_first_entry(&fs_info->unused_bgs,
+                                              struct btrfs_block_group_cache,
+                                              bg_list);
+               space_info = block_group->space_info;
+               list_del_init(&block_group->bg_list);
+               if (ret || btrfs_mixed_space_info(space_info)) {
+                       btrfs_put_block_group(block_group);
+                       continue;
+               }
+               spin_unlock(&fs_info->unused_bgs_lock);
+
+               /* Don't want to race with allocators so take the groups_sem */
+               down_write(&space_info->groups_sem);
+               spin_lock(&block_group->lock);
+               if (block_group->reserved ||
+                   btrfs_block_group_used(&block_group->item) ||
+                   block_group->ro) {
+                       /*
+                        * We want to bail if we made new allocations or have
+                        * outstanding allocations in this block group.  We do
+                        * the ro check in case balance is currently acting on
+                        * this block group.
+                        */
+                       spin_unlock(&block_group->lock);
+                       up_write(&space_info->groups_sem);
+                       goto next;
+               }
+               spin_unlock(&block_group->lock);
+
+               /* We don't want to force the issue, only flip if it's ok. */
+               ret = set_block_group_ro(block_group, 0);
+               up_write(&space_info->groups_sem);
+               if (ret < 0) {
+                       ret = 0;
+                       goto next;
+               }
+
+               /*
+                * Want to do this before we do anything else so we can recover
+                * properly if we fail to join the transaction.
+                */
+               trans = btrfs_join_transaction(root);
+               if (IS_ERR(trans)) {
+                       btrfs_set_block_group_rw(root, block_group);
+                       ret = PTR_ERR(trans);
+                       goto next;
+               }
+
+               /*
+                * We could have pending pinned extents for this block group,
+                * just delete them, we don't care about them anymore.
+                */
+               start = block_group->key.objectid;
+               end = start + block_group->key.offset - 1;
+               clear_extent_bits(&fs_info->freed_extents[0], start, end,
+                                 EXTENT_DIRTY, GFP_NOFS);
+               clear_extent_bits(&fs_info->freed_extents[1], start, end,
+                                 EXTENT_DIRTY, GFP_NOFS);
+
+               /* Reset pinned so btrfs_put_block_group doesn't complain */
+               block_group->pinned = 0;
+
+               /*
+                * Btrfs_remove_chunk will abort the transaction if things go
+                * horribly wrong.
+                */
+               ret = btrfs_remove_chunk(trans, root,
+                                        block_group->key.objectid);
+               btrfs_end_transaction(trans, root);
+next:
+               btrfs_put_block_group(block_group);
+               spin_lock(&fs_info->unused_bgs_lock);
+       }
+       spin_unlock(&fs_info->unused_bgs_lock);
+}
+
 int btrfs_init_space_info(struct btrfs_fs_info *fs_info)
 {
        struct btrfs_space_info *space_info;
@@ -9561,7 +9690,7 @@ void btrfs_end_nocow_write(struct btrfs_root *root)
 
 int btrfs_start_nocow_write(struct btrfs_root *root)
 {
-       if (unlikely(atomic_read(&root->will_be_snapshoted)))
+       if (atomic_read(&root->will_be_snapshoted))
                return 0;
 
        percpu_counter_inc(&root->subv_writers->counter);
@@ -9569,7 +9698,7 @@ int btrfs_start_nocow_write(struct btrfs_root *root)
         * Make sure counter is updated before we check for snapshot creation.
         */
        smp_mb();
-       if (unlikely(atomic_read(&root->will_be_snapshoted))) {
+       if (atomic_read(&root->will_be_snapshoted)) {
                btrfs_end_nocow_write(root);
                return 0;
        }
index af0359dcf337dbfec421b49fedbb8b5d0ecbf8b8..bf3f424e0013c17d3a47047e5c7301abba93bfac 100644 (file)
@@ -25,6 +25,11 @@ static struct kmem_cache *extent_state_cache;
 static struct kmem_cache *extent_buffer_cache;
 static struct bio_set *btrfs_bioset;
 
+static inline bool extent_state_in_tree(const struct extent_state *state)
+{
+       return !RB_EMPTY_NODE(&state->rb_node);
+}
+
 #ifdef CONFIG_BTRFS_DEBUG
 static LIST_HEAD(buffers);
 static LIST_HEAD(states);
@@ -59,9 +64,9 @@ void btrfs_leak_debug_check(void)
 
        while (!list_empty(&states)) {
                state = list_entry(states.next, struct extent_state, leak_list);
-               printk(KERN_ERR "BTRFS: state leak: start %llu end %llu "
-                      "state %lu in tree %p refs %d\n",
-                      state->start, state->end, state->state, state->tree,
+               pr_err("BTRFS: state leak: start %llu end %llu state %lu in tree %d refs %d\n",
+                      state->start, state->end, state->state,
+                      extent_state_in_tree(state),
                       atomic_read(&state->refs));
                list_del(&state->leak_list);
                kmem_cache_free(extent_state_cache, state);
@@ -209,7 +214,7 @@ static struct extent_state *alloc_extent_state(gfp_t mask)
                return state;
        state->state = 0;
        state->private = 0;
-       state->tree = NULL;
+       RB_CLEAR_NODE(&state->rb_node);
        btrfs_leak_debug_add(&state->leak_list, &states);
        atomic_set(&state->refs, 1);
        init_waitqueue_head(&state->wq);
@@ -222,7 +227,7 @@ void free_extent_state(struct extent_state *state)
        if (!state)
                return;
        if (atomic_dec_and_test(&state->refs)) {
-               WARN_ON(state->tree);
+               WARN_ON(extent_state_in_tree(state));
                btrfs_leak_debug_del(&state->leak_list);
                trace_free_extent_state(state, _RET_IP_);
                kmem_cache_free(extent_state_cache, state);
@@ -371,8 +376,8 @@ static void merge_state(struct extent_io_tree *tree,
                    other->state == state->state) {
                        merge_cb(tree, state, other);
                        state->start = other->start;
-                       other->tree = NULL;
                        rb_erase(&other->rb_node, &tree->state);
+                       RB_CLEAR_NODE(&other->rb_node);
                        free_extent_state(other);
                }
        }
@@ -383,8 +388,8 @@ static void merge_state(struct extent_io_tree *tree,
                    other->state == state->state) {
                        merge_cb(tree, state, other);
                        state->end = other->end;
-                       other->tree = NULL;
                        rb_erase(&other->rb_node, &tree->state);
+                       RB_CLEAR_NODE(&other->rb_node);
                        free_extent_state(other);
                }
        }
@@ -442,7 +447,6 @@ static int insert_state(struct extent_io_tree *tree,
                       found->start, found->end, start, end);
                return -EEXIST;
        }
-       state->tree = tree;
        merge_state(tree, state);
        return 0;
 }
@@ -486,7 +490,6 @@ static int split_state(struct extent_io_tree *tree, struct extent_state *orig,
                free_extent_state(prealloc);
                return -EEXIST;
        }
-       prealloc->tree = tree;
        return 0;
 }
 
@@ -524,9 +527,9 @@ static struct extent_state *clear_state_bit(struct extent_io_tree *tree,
                wake_up(&state->wq);
        if (state->state == 0) {
                next = next_state(state);
-               if (state->tree) {
+               if (extent_state_in_tree(state)) {
                        rb_erase(&state->rb_node, &tree->state);
-                       state->tree = NULL;
+                       RB_CLEAR_NODE(&state->rb_node);
                        free_extent_state(state);
                } else {
                        WARN_ON(1);
@@ -606,8 +609,8 @@ again:
                        cached_state = NULL;
                }
 
-               if (cached && cached->tree && cached->start <= start &&
-                   cached->end > start) {
+               if (cached && extent_state_in_tree(cached) &&
+                   cached->start <= start && cached->end > start) {
                        if (clear)
                                atomic_dec(&cached->refs);
                        state = cached;
@@ -843,7 +846,7 @@ again:
        if (cached_state && *cached_state) {
                state = *cached_state;
                if (state->start <= start && state->end > start &&
-                   state->tree) {
+                   extent_state_in_tree(state)) {
                        node = &state->rb_node;
                        goto hit_next;
                }
@@ -1069,7 +1072,7 @@ again:
        if (cached_state && *cached_state) {
                state = *cached_state;
                if (state->start <= start && state->end > start &&
-                   state->tree) {
+                   extent_state_in_tree(state)) {
                        node = &state->rb_node;
                        goto hit_next;
                }
@@ -1459,7 +1462,7 @@ int find_first_extent_bit(struct extent_io_tree *tree, u64 start,
        spin_lock(&tree->lock);
        if (cached_state && *cached_state) {
                state = *cached_state;
-               if (state->end == start - 1 && state->tree) {
+               if (state->end == start - 1 && extent_state_in_tree(state)) {
                        n = rb_next(&state->rb_node);
                        while (n) {
                                state = rb_entry(n, struct extent_state,
@@ -1905,7 +1908,7 @@ int test_range_bit(struct extent_io_tree *tree, u64 start, u64 end,
        int bitset = 0;
 
        spin_lock(&tree->lock);
-       if (cached && cached->tree && cached->start <= start &&
+       if (cached && extent_state_in_tree(cached) && cached->start <= start &&
            cached->end > start)
                node = &cached->rb_node;
        else
@@ -1959,27 +1962,7 @@ static void check_page_uptodate(struct extent_io_tree *tree, struct page *page)
                SetPageUptodate(page);
 }
 
-/*
- * When IO fails, either with EIO or csum verification fails, we
- * try other mirrors that might have a good copy of the data.  This
- * io_failure_record is used to record state as we go through all the
- * mirrors.  If another mirror has good data, the page is set up to date
- * and things continue.  If a good mirror can't be found, the original
- * bio end_io callback is called to indicate things have failed.
- */
-struct io_failure_record {
-       struct page *page;
-       u64 start;
-       u64 len;
-       u64 logical;
-       unsigned long bio_flags;
-       int this_mirror;
-       int failed_mirror;
-       int in_validation;
-};
-
-static int free_io_failure(struct inode *inode, struct io_failure_record *rec,
-                               int did_repair)
+int free_io_failure(struct inode *inode, struct io_failure_record *rec)
 {
        int ret;
        int err = 0;
@@ -2012,10 +1995,10 @@ static int free_io_failure(struct inode *inode, struct io_failure_record *rec,
  * currently, there can be no more than two copies of every data bit. thus,
  * exactly one rewrite is required.
  */
-int repair_io_failure(struct btrfs_fs_info *fs_info, u64 start,
-                       u64 length, u64 logical, struct page *page,
-                       int mirror_num)
+int repair_io_failure(struct inode *inode, u64 start, u64 length, u64 logical,
+                     struct page *page, unsigned int pg_offset, int mirror_num)
 {
+       struct btrfs_fs_info *fs_info = BTRFS_I(inode)->root->fs_info;
        struct bio *bio;
        struct btrfs_device *dev;
        u64 map_length = 0;
@@ -2053,7 +2036,7 @@ int repair_io_failure(struct btrfs_fs_info *fs_info, u64 start,
                return -EIO;
        }
        bio->bi_bdev = dev->bdev;
-       bio_add_page(bio, page, length, start - page_offset(page));
+       bio_add_page(bio, page, length, pg_offset);
 
        if (btrfsic_submit_bio_wait(WRITE_SYNC, bio)) {
                /* try to remap that extent elsewhere? */
@@ -2063,10 +2046,9 @@ int repair_io_failure(struct btrfs_fs_info *fs_info, u64 start,
        }
 
        printk_ratelimited_in_rcu(KERN_INFO
-                       "BTRFS: read error corrected: ino %lu off %llu "
-                   "(dev %s sector %llu)\n", page->mapping->host->i_ino,
-                   start, rcu_str_deref(dev->name), sector);
-
+                                 "BTRFS: read error corrected: ino %llu off %llu (dev %s sector %llu)\n",
+                                 btrfs_ino(inode), start,
+                                 rcu_str_deref(dev->name), sector);
        bio_put(bio);
        return 0;
 }
@@ -2082,9 +2064,11 @@ int repair_eb_io_failure(struct btrfs_root *root, struct extent_buffer *eb,
                return -EROFS;
 
        for (i = 0; i < num_pages; i++) {
-               struct page *p = extent_buffer_page(eb, i);
-               ret = repair_io_failure(root->fs_info, start, PAGE_CACHE_SIZE,
-                                       start, p, mirror_num);
+               struct page *p = eb->pages[i];
+
+               ret = repair_io_failure(root->fs_info->btree_inode, start,
+                                       PAGE_CACHE_SIZE, start, p,
+                                       start - page_offset(p), mirror_num);
                if (ret)
                        break;
                start += PAGE_CACHE_SIZE;
@@ -2097,16 +2081,15 @@ int repair_eb_io_failure(struct btrfs_root *root, struct extent_buffer *eb,
  * each time an IO finishes, we do a fast check in the IO failure tree
  * to see if we need to process or clean up an io_failure_record
  */
-static int clean_io_failure(u64 start, struct page *page)
+int clean_io_failure(struct inode *inode, u64 start, struct page *page,
+                    unsigned int pg_offset)
 {
        u64 private;
        u64 private_failure;
        struct io_failure_record *failrec;
-       struct inode *inode = page->mapping->host;
        struct btrfs_fs_info *fs_info = BTRFS_I(inode)->root->fs_info;
        struct extent_state *state;
        int num_copies;
-       int did_repair = 0;
        int ret;
 
        private = 0;
@@ -2127,7 +2110,6 @@ static int clean_io_failure(u64 start, struct page *page)
                /* there was no real error, just free the record */
                pr_debug("clean_io_failure: freeing dummy error at %llu\n",
                         failrec->start);
-               did_repair = 1;
                goto out;
        }
        if (fs_info->sb->s_flags & MS_RDONLY)
@@ -2144,55 +2126,70 @@ static int clean_io_failure(u64 start, struct page *page)
                num_copies = btrfs_num_copies(fs_info, failrec->logical,
                                              failrec->len);
                if (num_copies > 1)  {
-                       ret = repair_io_failure(fs_info, start, failrec->len,
-                                               failrec->logical, page,
-                                               failrec->failed_mirror);
-                       did_repair = !ret;
+                       repair_io_failure(inode, start, failrec->len,
+                                         failrec->logical, page,
+                                         pg_offset, failrec->failed_mirror);
                }
-               ret = 0;
        }
 
 out:
-       if (!ret)
-               ret = free_io_failure(inode, failrec, did_repair);
+       free_io_failure(inode, failrec);
 
-       return ret;
+       return 0;
 }
 
 /*
- * this is a generic handler for readpage errors (default
- * readpage_io_failed_hook). if other copies exist, read those and write back
- * good data to the failed position. does not investigate in remapping the
- * failed extent elsewhere, hoping the device will be smart enough to do this as
- * needed
+ * Can be called when
+ * - hold extent lock
+ * - under ordered extent
+ * - the inode is freeing
  */
+void btrfs_free_io_failure_record(struct inode *inode, u64 start, u64 end)
+{
+       struct extent_io_tree *failure_tree = &BTRFS_I(inode)->io_failure_tree;
+       struct io_failure_record *failrec;
+       struct extent_state *state, *next;
 
-static int bio_readpage_error(struct bio *failed_bio, u64 phy_offset,
-                             struct page *page, u64 start, u64 end,
-                             int failed_mirror)
+       if (RB_EMPTY_ROOT(&failure_tree->state))
+               return;
+
+       spin_lock(&failure_tree->lock);
+       state = find_first_extent_bit_state(failure_tree, start, EXTENT_DIRTY);
+       while (state) {
+               if (state->start > end)
+                       break;
+
+               ASSERT(state->end <= end);
+
+               next = next_state(state);
+
+               failrec = (struct io_failure_record *)state->private;
+               free_extent_state(state);
+               kfree(failrec);
+
+               state = next;
+       }
+       spin_unlock(&failure_tree->lock);
+}
+
+int btrfs_get_io_failure_record(struct inode *inode, u64 start, u64 end,
+                               struct io_failure_record **failrec_ret)
 {
-       struct io_failure_record *failrec = NULL;
+       struct io_failure_record *failrec;
        u64 private;
        struct extent_map *em;
-       struct inode *inode = page->mapping->host;
        struct extent_io_tree *failure_tree = &BTRFS_I(inode)->io_failure_tree;
        struct extent_io_tree *tree = &BTRFS_I(inode)->io_tree;
        struct extent_map_tree *em_tree = &BTRFS_I(inode)->extent_tree;
-       struct bio *bio;
-       struct btrfs_io_bio *btrfs_failed_bio;
-       struct btrfs_io_bio *btrfs_bio;
-       int num_copies;
        int ret;
-       int read_mode;
        u64 logical;
 
-       BUG_ON(failed_bio->bi_rw & REQ_WRITE);
-
        ret = get_state_private(failure_tree, start, &private);
        if (ret) {
                failrec = kzalloc(sizeof(*failrec), GFP_NOFS);
                if (!failrec)
                        return -ENOMEM;
+
                failrec->start = start;
                failrec->len = end - start + 1;
                failrec->this_mirror = 0;
@@ -2212,11 +2209,11 @@ static int bio_readpage_error(struct bio *failed_bio, u64 phy_offset,
                        em = NULL;
                }
                read_unlock(&em_tree->lock);
-
                if (!em) {
                        kfree(failrec);
                        return -EIO;
                }
+
                logical = start - em->start;
                logical = em->block_start + logical;
                if (test_bit(EXTENT_FLAG_COMPRESSED, &em->flags)) {
@@ -2225,8 +2222,10 @@ static int bio_readpage_error(struct bio *failed_bio, u64 phy_offset,
                        extent_set_compress_type(&failrec->bio_flags,
                                                 em->compress_type);
                }
-               pr_debug("bio_readpage_error: (new) logical=%llu, start=%llu, "
-                        "len=%llu\n", logical, start, failrec->len);
+
+               pr_debug("Get IO Failure Record: (new) logical=%llu, start=%llu, len=%llu\n",
+                        logical, start, failrec->len);
+
                failrec->logical = logical;
                free_extent_map(em);
 
@@ -2246,8 +2245,7 @@ static int bio_readpage_error(struct bio *failed_bio, u64 phy_offset,
                }
        } else {
                failrec = (struct io_failure_record *)(unsigned long)private;
-               pr_debug("bio_readpage_error: (found) logical=%llu, "
-                        "start=%llu, len=%llu, validation=%d\n",
+               pr_debug("Get IO Failure Record: (found) logical=%llu, start=%llu, len=%llu, validation=%d\n",
                         failrec->logical, failrec->start, failrec->len,
                         failrec->in_validation);
                /*
@@ -2256,6 +2254,17 @@ static int bio_readpage_error(struct bio *failed_bio, u64 phy_offset,
                 * clean_io_failure() clean all those errors at once.
                 */
        }
+
+       *failrec_ret = failrec;
+
+       return 0;
+}
+
+int btrfs_check_repairable(struct inode *inode, struct bio *failed_bio,
+                          struct io_failure_record *failrec, int failed_mirror)
+{
+       int num_copies;
+
        num_copies = btrfs_num_copies(BTRFS_I(inode)->root->fs_info,
                                      failrec->logical, failrec->len);
        if (num_copies == 1) {
@@ -2264,10 +2273,9 @@ static int bio_readpage_error(struct bio *failed_bio, u64 phy_offset,
                 * all the retry and error correction code that follows. no
                 * matter what the error is, it is very likely to persist.
                 */
-               pr_debug("bio_readpage_error: cannot repair, num_copies=%d, next_mirror %d, failed_mirror %d\n",
+               pr_debug("Check Repairable: cannot repair, num_copies=%d, next_mirror %d, failed_mirror %d\n",
                         num_copies, failrec->this_mirror, failed_mirror);
-               free_io_failure(inode, failrec, 0);
-               return -EIO;
+               return 0;
        }
 
        /*
@@ -2287,7 +2295,6 @@ static int bio_readpage_error(struct bio *failed_bio, u64 phy_offset,
                BUG_ON(failrec->in_validation);
                failrec->in_validation = 1;
                failrec->this_mirror = failed_mirror;
-               read_mode = READ_SYNC | REQ_FAILFAST_DEV;
        } else {
                /*
                 * we're ready to fulfill a) and b) alongside. get a good copy
@@ -2303,25 +2310,36 @@ static int bio_readpage_error(struct bio *failed_bio, u64 phy_offset,
                failrec->this_mirror++;
                if (failrec->this_mirror == failed_mirror)
                        failrec->this_mirror++;
-               read_mode = READ_SYNC;
        }
 
        if (failrec->this_mirror > num_copies) {
-               pr_debug("bio_readpage_error: (fail) num_copies=%d, next_mirror %d, failed_mirror %d\n",
+               pr_debug("Check Repairable: (fail) num_copies=%d, next_mirror %d, failed_mirror %d\n",
                         num_copies, failrec->this_mirror, failed_mirror);
-               free_io_failure(inode, failrec, 0);
-               return -EIO;
+               return 0;
        }
 
+       return 1;
+}
+
+
+struct bio *btrfs_create_repair_bio(struct inode *inode, struct bio *failed_bio,
+                                   struct io_failure_record *failrec,
+                                   struct page *page, int pg_offset, int icsum,
+                                   bio_end_io_t *endio_func, void *data)
+{
+       struct bio *bio;
+       struct btrfs_io_bio *btrfs_failed_bio;
+       struct btrfs_io_bio *btrfs_bio;
+
        bio = btrfs_io_bio_alloc(GFP_NOFS, 1);
-       if (!bio) {
-               free_io_failure(inode, failrec, 0);
-               return -EIO;
-       }
-       bio->bi_end_io = failed_bio->bi_end_io;
+       if (!bio)
+               return NULL;
+
+       bio->bi_end_io = endio_func;
        bio->bi_iter.bi_sector = failrec->logical >> 9;
        bio->bi_bdev = BTRFS_I(inode)->root->fs_info->fs_devices->latest_bdev;
        bio->bi_iter.bi_size = 0;
+       bio->bi_private = data;
 
        btrfs_failed_bio = btrfs_io_bio(failed_bio);
        if (btrfs_failed_bio->csum) {
@@ -2330,21 +2348,73 @@ static int bio_readpage_error(struct bio *failed_bio, u64 phy_offset,
 
                btrfs_bio = btrfs_io_bio(bio);
                btrfs_bio->csum = btrfs_bio->csum_inline;
-               phy_offset >>= inode->i_sb->s_blocksize_bits;
-               phy_offset *= csum_size;
-               memcpy(btrfs_bio->csum, btrfs_failed_bio->csum + phy_offset,
+               icsum *= csum_size;
+               memcpy(btrfs_bio->csum, btrfs_failed_bio->csum + icsum,
                       csum_size);
        }
 
-       bio_add_page(bio, page, failrec->len, start - page_offset(page));
+       bio_add_page(bio, page, failrec->len, pg_offset);
+
+       return bio;
+}
+
+/*
+ * this is a generic handler for readpage errors (default
+ * readpage_io_failed_hook). if other copies exist, read those and write back
+ * good data to the failed position. does not investigate in remapping the
+ * failed extent elsewhere, hoping the device will be smart enough to do this as
+ * needed
+ */
+
+static int bio_readpage_error(struct bio *failed_bio, u64 phy_offset,
+                             struct page *page, u64 start, u64 end,
+                             int failed_mirror)
+{
+       struct io_failure_record *failrec;
+       struct inode *inode = page->mapping->host;
+       struct extent_io_tree *tree = &BTRFS_I(inode)->io_tree;
+       struct bio *bio;
+       int read_mode;
+       int ret;
+
+       BUG_ON(failed_bio->bi_rw & REQ_WRITE);
+
+       ret = btrfs_get_io_failure_record(inode, start, end, &failrec);
+       if (ret)
+               return ret;
+
+       ret = btrfs_check_repairable(inode, failed_bio, failrec, failed_mirror);
+       if (!ret) {
+               free_io_failure(inode, failrec);
+               return -EIO;
+       }
+
+       if (failed_bio->bi_vcnt > 1)
+               read_mode = READ_SYNC | REQ_FAILFAST_DEV;
+       else
+               read_mode = READ_SYNC;
+
+       phy_offset >>= inode->i_sb->s_blocksize_bits;
+       bio = btrfs_create_repair_bio(inode, failed_bio, failrec, page,
+                                     start - page_offset(page),
+                                     (int)phy_offset, failed_bio->bi_end_io,
+                                     NULL);
+       if (!bio) {
+               free_io_failure(inode, failrec);
+               return -EIO;
+       }
 
-       pr_debug("bio_readpage_error: submitting new read[%#x] to "
-                "this_mirror=%d, num_copies=%d, in_validation=%d\n", read_mode,
-                failrec->this_mirror, num_copies, failrec->in_validation);
+       pr_debug("Repair Read Error: submitting new read[%#x] to this_mirror=%d, in_validation=%d\n",
+                read_mode, failrec->this_mirror, failrec->in_validation);
 
        ret = tree->ops->submit_bio_hook(inode, read_mode, bio,
                                         failrec->this_mirror,
                                         failrec->bio_flags, 0);
+       if (ret) {
+               free_io_failure(inode, failrec);
+               bio_put(bio);
+       }
+
        return ret;
 }
 
@@ -2469,7 +2539,7 @@ static void end_bio_extent_readpage(struct bio *bio, int err)
                struct inode *inode = page->mapping->host;
 
                pr_debug("end_bio_extent_readpage: bi_sector=%llu, err=%d, "
-                        "mirror=%lu\n", (u64)bio->bi_iter.bi_sector, err,
+                        "mirror=%u\n", (u64)bio->bi_iter.bi_sector, err,
                         io_bio->mirror_num);
                tree = &BTRFS_I(inode)->io_tree;
 
@@ -2503,7 +2573,7 @@ static void end_bio_extent_readpage(struct bio *bio, int err)
                        if (ret)
                                uptodate = 0;
                        else
-                               clean_io_failure(start, page);
+                               clean_io_failure(inode, start, page, 0);
                }
 
                if (likely(uptodate))
@@ -2540,12 +2610,12 @@ readpage_ok:
                if (likely(uptodate)) {
                        loff_t i_size = i_size_read(inode);
                        pgoff_t end_index = i_size >> PAGE_CACHE_SHIFT;
-                       unsigned offset;
+                       unsigned off;
 
                        /* Zero out the end if this page straddles i_size */
-                       offset = i_size & (PAGE_CACHE_SIZE-1);
-                       if (page->index == end_index && offset)
-                               zero_user_segment(page, offset, PAGE_CACHE_SIZE);
+                       off = i_size & (PAGE_CACHE_SIZE-1);
+                       if (page->index == end_index && off)
+                               zero_user_segment(page, off, PAGE_CACHE_SIZE);
                        SetPageUptodate(page);
                } else {
                        ClearPageUptodate(page);
@@ -2618,9 +2688,18 @@ btrfs_bio_alloc(struct block_device *bdev, u64 first_sector, int nr_vecs,
 
 struct bio *btrfs_bio_clone(struct bio *bio, gfp_t gfp_mask)
 {
-       return bio_clone_bioset(bio, gfp_mask, btrfs_bioset);
-}
+       struct btrfs_io_bio *btrfs_bio;
+       struct bio *new;
 
+       new = bio_clone_bioset(bio, gfp_mask, btrfs_bioset);
+       if (new) {
+               btrfs_bio = btrfs_io_bio(new);
+               btrfs_bio->csum = NULL;
+               btrfs_bio->csum_allocated = NULL;
+               btrfs_bio->end_io = NULL;
+       }
+       return new;
+}
 
 /* this also allocates from the btrfs_bioset */
 struct bio *btrfs_io_bio_alloc(gfp_t gfp_mask, unsigned int nr_iovecs)
@@ -3501,7 +3580,7 @@ lock_extent_buffer_for_io(struct extent_buffer *eb,
 
        num_pages = num_extent_pages(eb->start, eb->len);
        for (i = 0; i < num_pages; i++) {
-               struct page *p = extent_buffer_page(eb, i);
+               struct page *p = eb->pages[i];
 
                if (!trylock_page(p)) {
                        if (!flush) {
@@ -3522,6 +3601,68 @@ static void end_extent_buffer_writeback(struct extent_buffer *eb)
        wake_up_bit(&eb->bflags, EXTENT_BUFFER_WRITEBACK);
 }
 
+static void set_btree_ioerr(struct page *page)
+{
+       struct extent_buffer *eb = (struct extent_buffer *)page->private;
+       struct btrfs_inode *btree_ino = BTRFS_I(eb->fs_info->btree_inode);
+
+       SetPageError(page);
+       if (test_and_set_bit(EXTENT_BUFFER_WRITE_ERR, &eb->bflags))
+               return;
+
+       /*
+        * If writeback for a btree extent that doesn't belong to a log tree
+        * failed, increment the counter transaction->eb_write_errors.
+        * We do this because while the transaction is running and before it's
+        * committing (when we call filemap_fdata[write|wait]_range against
+        * the btree inode), we might have
+        * btree_inode->i_mapping->a_ops->writepages() called by the VM - if it
+        * returns an error or an error happens during writeback, when we're
+        * committing the transaction we wouldn't know about it, since the pages
+        * can be no longer dirty nor marked anymore for writeback (if a
+        * subsequent modification to the extent buffer didn't happen before the
+        * transaction commit), which makes filemap_fdata[write|wait]_range not
+        * able to find the pages tagged with SetPageError at transaction
+        * commit time. So if this happens we must abort the transaction,
+        * otherwise we commit a super block with btree roots that point to
+        * btree nodes/leafs whose content on disk is invalid - either garbage
+        * or the content of some node/leaf from a past generation that got
+        * cowed or deleted and is no longer valid.
+        *
+        * Note: setting AS_EIO/AS_ENOSPC in the btree inode's i_mapping would
+        * not be enough - we need to distinguish between log tree extents vs
+        * non-log tree extents, and the next filemap_fdatawait_range() call
+        * will catch and clear such errors in the mapping - and that call might
+        * be from a log sync and not from a transaction commit. Also, checking
+        * for the eb flag EXTENT_BUFFER_WRITE_ERR at transaction commit time is
+        * not done and would not be reliable - the eb might have been released
+        * from memory and reading it back again means that flag would not be
+        * set (since it's a runtime flag, not persisted on disk).
+        *
+        * Using the flags below in the btree inode also makes us achieve the
+        * goal of AS_EIO/AS_ENOSPC when writepages() returns success, started
+        * writeback for all dirty pages and before filemap_fdatawait_range()
+        * is called, the writeback for all dirty pages had already finished
+        * with errors - because we were not using AS_EIO/AS_ENOSPC,
+        * filemap_fdatawait_range() would return success, as it could not know
+        * that writeback errors happened (the pages were no longer tagged for
+        * writeback).
+        */
+       switch (eb->log_index) {
+       case -1:
+               set_bit(BTRFS_INODE_BTREE_ERR, &btree_ino->runtime_flags);
+               break;
+       case 0:
+               set_bit(BTRFS_INODE_BTREE_LOG1_ERR, &btree_ino->runtime_flags);
+               break;
+       case 1:
+               set_bit(BTRFS_INODE_BTREE_LOG2_ERR, &btree_ino->runtime_flags);
+               break;
+       default:
+               BUG(); /* unexpected, logic error */
+       }
+}
+
 static void end_bio_extent_buffer_writepage(struct bio *bio, int err)
 {
        struct bio_vec *bvec;
@@ -3535,10 +3676,9 @@ static void end_bio_extent_buffer_writepage(struct bio *bio, int err)
                BUG_ON(!eb);
                done = atomic_dec_and_test(&eb->io_pages);
 
-               if (err || test_bit(EXTENT_BUFFER_IOERR, &eb->bflags)) {
-                       set_bit(EXTENT_BUFFER_IOERR, &eb->bflags);
+               if (err || test_bit(EXTENT_BUFFER_WRITE_ERR, &eb->bflags)) {
                        ClearPageUptodate(page);
-                       SetPageError(page);
+                       set_btree_ioerr(page);
                }
 
                end_page_writeback(page);
@@ -3565,14 +3705,14 @@ static noinline_for_stack int write_one_eb(struct extent_buffer *eb,
        int rw = (epd->sync_io ? WRITE_SYNC : WRITE) | REQ_META;
        int ret = 0;
 
-       clear_bit(EXTENT_BUFFER_IOERR, &eb->bflags);
+       clear_bit(EXTENT_BUFFER_WRITE_ERR, &eb->bflags);
        num_pages = num_extent_pages(eb->start, eb->len);
        atomic_set(&eb->io_pages, num_pages);
        if (btrfs_header_owner(eb) == BTRFS_TREE_LOG_OBJECTID)
                bio_flags = EXTENT_BIO_TREE_LOG;
 
        for (i = 0; i < num_pages; i++) {
-               struct page *p = extent_buffer_page(eb, i);
+               struct page *p = eb->pages[i];
 
                clear_page_dirty_for_io(p);
                set_page_writeback(p);
@@ -3582,8 +3722,8 @@ static noinline_for_stack int write_one_eb(struct extent_buffer *eb,
                                         0, epd->bio_flags, bio_flags);
                epd->bio_flags = bio_flags;
                if (ret) {
-                       set_bit(EXTENT_BUFFER_IOERR, &eb->bflags);
-                       SetPageError(p);
+                       set_btree_ioerr(p);
+                       end_page_writeback(p);
                        if (atomic_sub_and_test(num_pages - i, &eb->io_pages))
                                end_extent_buffer_writeback(eb);
                        ret = -EIO;
@@ -3596,7 +3736,8 @@ static noinline_for_stack int write_one_eb(struct extent_buffer *eb,
 
        if (unlikely(ret)) {
                for (; i < num_pages; i++) {
-                       struct page *p = extent_buffer_page(eb, i);
+                       struct page *p = eb->pages[i];
+                       clear_page_dirty_for_io(p);
                        unlock_page(p);
                }
        }
@@ -4166,19 +4307,6 @@ static struct extent_map *get_extent_skip_holes(struct inode *inode,
        return NULL;
 }
 
-static noinline int count_ext_ref(u64 inum, u64 offset, u64 root_id, void *ctx)
-{
-       unsigned long cnt = *((unsigned long *)ctx);
-
-       cnt++;
-       *((unsigned long *)ctx) = cnt;
-
-       /* Now we're sure that the extent is shared. */
-       if (cnt > 1)
-               return 1;
-       return 0;
-}
-
 int extent_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
                __u64 start, __u64 len, get_extent_t *get_extent)
 {
@@ -4195,6 +4323,7 @@ int extent_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
        struct extent_map *em = NULL;
        struct extent_state *cached_state = NULL;
        struct btrfs_path *path;
+       struct btrfs_root *root = BTRFS_I(inode)->root;
        int end = 0;
        u64 em_start = 0;
        u64 em_len = 0;
@@ -4215,8 +4344,8 @@ int extent_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
         * lookup the last file extent.  We're not using i_size here
         * because there might be preallocation past i_size
         */
-       ret = btrfs_lookup_file_extent(NULL, BTRFS_I(inode)->root,
-                                      path, btrfs_ino(inode), -1, 0);
+       ret = btrfs_lookup_file_extent(NULL, root, path, btrfs_ino(inode), -1,
+                                      0);
        if (ret < 0) {
                btrfs_free_path(path);
                return ret;
@@ -4224,7 +4353,7 @@ int extent_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
        WARN_ON(!ret);
        path->slots[0]--;
        btrfs_item_key_to_cpu(path->nodes[0], &found_key, path->slots[0]);
-       found_type = btrfs_key_type(&found_key);
+       found_type = found_key.type;
 
        /* No extents, but there might be delalloc bits */
        if (found_key.objectid != btrfs_ino(inode) ||
@@ -4309,25 +4438,27 @@ int extent_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
                } else if (em->block_start == EXTENT_MAP_DELALLOC) {
                        flags |= (FIEMAP_EXTENT_DELALLOC |
                                  FIEMAP_EXTENT_UNKNOWN);
-               } else {
-                       unsigned long ref_cnt = 0;
+               } else if (fieinfo->fi_extents_max) {
+                       u64 bytenr = em->block_start -
+                               (em->start - em->orig_start);
 
                        disko = em->block_start + offset_in_extent;
 
                        /*
                         * As btrfs supports shared space, this information
                         * can be exported to userspace tools via
-                        * flag FIEMAP_EXTENT_SHARED.
+                        * flag FIEMAP_EXTENT_SHARED.  If fi_extents_max == 0
+                        * then we're just getting a count and we can skip the
+                        * lookup stuff.
                         */
-                       ret = iterate_inodes_from_logical(
-                                       em->block_start,
-                                       BTRFS_I(inode)->root->fs_info,
-                                       path, count_ext_ref, &ref_cnt);
-                       if (ret < 0 && ret != -ENOENT)
+                       ret = btrfs_check_shared(NULL, root->fs_info,
+                                                root->objectid,
+                                                btrfs_ino(inode), bytenr);
+                       if (ret < 0)
                                goto out_free;
-
-                       if (ref_cnt > 1)
+                       if (ret)
                                flags |= FIEMAP_EXTENT_SHARED;
+                       ret = 0;
                }
                if (test_bit(EXTENT_FLAG_COMPRESSED, &em->flags))
                        flags |= FIEMAP_EXTENT_ENCODED;
@@ -4381,24 +4512,21 @@ int extent_buffer_under_io(struct extent_buffer *eb)
 /*
  * Helper for releasing extent buffer page.
  */
-static void btrfs_release_extent_buffer_page(struct extent_buffer *eb,
-                                               unsigned long start_idx)
+static void btrfs_release_extent_buffer_page(struct extent_buffer *eb)
 {
        unsigned long index;
-       unsigned long num_pages;
        struct page *page;
        int mapped = !test_bit(EXTENT_BUFFER_DUMMY, &eb->bflags);
 
        BUG_ON(extent_buffer_under_io(eb));
 
-       num_pages = num_extent_pages(eb->start, eb->len);
-       index = start_idx + num_pages;
-       if (start_idx >= index)
+       index = num_extent_pages(eb->start, eb->len);
+       if (index == 0)
                return;
 
        do {
                index--;
-               page = extent_buffer_page(eb, index);
+               page = eb->pages[index];
                if (page && mapped) {
                        spin_lock(&page->mapping->private_lock);
                        /*
@@ -4429,7 +4557,7 @@ static void btrfs_release_extent_buffer_page(struct extent_buffer *eb,
                        /* One for when we alloced the page */
                        page_cache_release(page);
                }
-       } while (index != start_idx);
+       } while (index != 0);
 }
 
 /*
@@ -4437,7 +4565,7 @@ static void btrfs_release_extent_buffer_page(struct extent_buffer *eb,
  */
 static inline void btrfs_release_extent_buffer(struct extent_buffer *eb)
 {
-       btrfs_release_extent_buffer_page(eb, 0);
+       btrfs_release_extent_buffer_page(eb);
        __free_extent_buffer(eb);
 }
 
@@ -4580,7 +4708,8 @@ static void mark_extent_buffer_accessed(struct extent_buffer *eb,
 
        num_pages = num_extent_pages(eb->start, eb->len);
        for (i = 0; i < num_pages; i++) {
-               struct page *p = extent_buffer_page(eb, i);
+               struct page *p = eb->pages[i];
+
                if (p != accessed)
                        mark_page_accessed(p);
        }
@@ -4749,7 +4878,7 @@ again:
         */
        SetPageChecked(eb->pages[0]);
        for (i = 1; i < num_pages; i++) {
-               p = extent_buffer_page(eb, i);
+               p = eb->pages[i];
                ClearPageChecked(p);
                unlock_page(p);
        }
@@ -4794,7 +4923,7 @@ static int release_extent_buffer(struct extent_buffer *eb)
                }
 
                /* Should be safe to release our pages at this point */
-               btrfs_release_extent_buffer_page(eb, 0);
+               btrfs_release_extent_buffer_page(eb);
                call_rcu(&eb->rcu_head, btrfs_release_extent_buffer_rcu);
                return 1;
        }
@@ -4860,7 +4989,7 @@ void clear_extent_buffer_dirty(struct extent_buffer *eb)
        num_pages = num_extent_pages(eb->start, eb->len);
 
        for (i = 0; i < num_pages; i++) {
-               page = extent_buffer_page(eb, i);
+               page = eb->pages[i];
                if (!PageDirty(page))
                        continue;
 
@@ -4896,7 +5025,7 @@ int set_extent_buffer_dirty(struct extent_buffer *eb)
        WARN_ON(!test_bit(EXTENT_BUFFER_TREE_REF, &eb->bflags));
 
        for (i = 0; i < num_pages; i++)
-               set_page_dirty(extent_buffer_page(eb, i));
+               set_page_dirty(eb->pages[i]);
        return was_dirty;
 }
 
@@ -4909,7 +5038,7 @@ int clear_extent_buffer_uptodate(struct extent_buffer *eb)
        clear_bit(EXTENT_BUFFER_UPTODATE, &eb->bflags);
        num_pages = num_extent_pages(eb->start, eb->len);
        for (i = 0; i < num_pages; i++) {
-               page = extent_buffer_page(eb, i);
+               page = eb->pages[i];
                if (page)
                        ClearPageUptodate(page);
        }
@@ -4925,7 +5054,7 @@ int set_extent_buffer_uptodate(struct extent_buffer *eb)
        set_bit(EXTENT_BUFFER_UPTODATE, &eb->bflags);
        num_pages = num_extent_pages(eb->start, eb->len);
        for (i = 0; i < num_pages; i++) {
-               page = extent_buffer_page(eb, i);
+               page = eb->pages[i];
                SetPageUptodate(page);
        }
        return 0;
@@ -4965,7 +5094,7 @@ int read_extent_buffer_pages(struct extent_io_tree *tree,
 
        num_pages = num_extent_pages(eb->start, eb->len);
        for (i = start_i; i < num_pages; i++) {
-               page = extent_buffer_page(eb, i);
+               page = eb->pages[i];
                if (wait == WAIT_NONE) {
                        if (!trylock_page(page))
                                goto unlock_exit;
@@ -4984,11 +5113,11 @@ int read_extent_buffer_pages(struct extent_io_tree *tree,
                goto unlock_exit;
        }
 
-       clear_bit(EXTENT_BUFFER_IOERR, &eb->bflags);
+       clear_bit(EXTENT_BUFFER_READ_ERR, &eb->bflags);
        eb->read_mirror = 0;
        atomic_set(&eb->io_pages, num_reads);
        for (i = start_i; i < num_pages; i++) {
-               page = extent_buffer_page(eb, i);
+               page = eb->pages[i];
                if (!PageUptodate(page)) {
                        ClearPageError(page);
                        err = __extent_read_full_page(tree, page,
@@ -5013,7 +5142,7 @@ int read_extent_buffer_pages(struct extent_io_tree *tree,
                return ret;
 
        for (i = start_i; i < num_pages; i++) {
-               page = extent_buffer_page(eb, i);
+               page = eb->pages[i];
                wait_on_page_locked(page);
                if (!PageUptodate(page))
                        ret = -EIO;
@@ -5024,7 +5153,7 @@ int read_extent_buffer_pages(struct extent_io_tree *tree,
 unlock_exit:
        i = start_i;
        while (locked_pages > 0) {
-               page = extent_buffer_page(eb, i);
+               page = eb->pages[i];
                i++;
                unlock_page(page);
                locked_pages--;
@@ -5050,7 +5179,7 @@ void read_extent_buffer(struct extent_buffer *eb, void *dstv,
        offset = (start_offset + start) & (PAGE_CACHE_SIZE - 1);
 
        while (len > 0) {
-               page = extent_buffer_page(eb, i);
+               page = eb->pages[i];
 
                cur = min(len, (PAGE_CACHE_SIZE - offset));
                kaddr = page_address(page);
@@ -5082,7 +5211,7 @@ int read_extent_buffer_to_user(struct extent_buffer *eb, void __user *dstv,
        offset = (start_offset + start) & (PAGE_CACHE_SIZE - 1);
 
        while (len > 0) {
-               page = extent_buffer_page(eb, i);
+               page = eb->pages[i];
 
                cur = min(len, (PAGE_CACHE_SIZE - offset));
                kaddr = page_address(page);
@@ -5131,7 +5260,7 @@ int map_private_extent_buffer(struct extent_buffer *eb, unsigned long start,
                return -EINVAL;
        }
 
-       p = extent_buffer_page(eb, i);
+       p = eb->pages[i];
        kaddr = page_address(p);
        *map = kaddr + offset;
        *map_len = PAGE_CACHE_SIZE - offset;
@@ -5157,7 +5286,7 @@ int memcmp_extent_buffer(struct extent_buffer *eb, const void *ptrv,
        offset = (start_offset + start) & (PAGE_CACHE_SIZE - 1);
 
        while (len > 0) {
-               page = extent_buffer_page(eb, i);
+               page = eb->pages[i];
 
                cur = min(len, (PAGE_CACHE_SIZE - offset));
 
@@ -5191,7 +5320,7 @@ void write_extent_buffer(struct extent_buffer *eb, const void *srcv,
        offset = (start_offset + start) & (PAGE_CACHE_SIZE - 1);
 
        while (len > 0) {
-               page = extent_buffer_page(eb, i);
+               page = eb->pages[i];
                WARN_ON(!PageUptodate(page));
 
                cur = min(len, PAGE_CACHE_SIZE - offset);
@@ -5221,7 +5350,7 @@ void memset_extent_buffer(struct extent_buffer *eb, char c,
        offset = (start_offset + start) & (PAGE_CACHE_SIZE - 1);
 
        while (len > 0) {
-               page = extent_buffer_page(eb, i);
+               page = eb->pages[i];
                WARN_ON(!PageUptodate(page));
 
                cur = min(len, PAGE_CACHE_SIZE - offset);
@@ -5252,7 +5381,7 @@ void copy_extent_buffer(struct extent_buffer *dst, struct extent_buffer *src,
                (PAGE_CACHE_SIZE - 1);
 
        while (len > 0) {
-               page = extent_buffer_page(dst, i);
+               page = dst->pages[i];
                WARN_ON(!PageUptodate(page));
 
                cur = min(len, (unsigned long)(PAGE_CACHE_SIZE - offset));
@@ -5330,8 +5459,7 @@ void memcpy_extent_buffer(struct extent_buffer *dst, unsigned long dst_offset,
                cur = min_t(unsigned long, cur,
                        (unsigned long)(PAGE_CACHE_SIZE - dst_off_in_page));
 
-               copy_pages(extent_buffer_page(dst, dst_i),
-                          extent_buffer_page(dst, src_i),
+               copy_pages(dst->pages[dst_i], dst->pages[src_i],
                           dst_off_in_page, src_off_in_page, cur);
 
                src_offset += cur;
@@ -5377,8 +5505,7 @@ void memmove_extent_buffer(struct extent_buffer *dst, unsigned long dst_offset,
 
                cur = min_t(unsigned long, len, src_off_in_page + 1);
                cur = min(cur, dst_off_in_page + 1);
-               copy_pages(extent_buffer_page(dst, dst_i),
-                          extent_buffer_page(dst, src_i),
+               copy_pages(dst->pages[dst_i], dst->pages[src_i],
                           dst_off_in_page - cur + 1,
                           src_off_in_page - cur + 1, cur);
 
index ccc264e7bde12760035dacfd40cafb25b663de4e..6d4b938be98678660cc51fb55bd51a5688279ed8 100644 (file)
@@ -11,8 +11,6 @@
 #define EXTENT_NEW (1 << 4)
 #define EXTENT_DELALLOC (1 << 5)
 #define EXTENT_DEFRAG (1 << 6)
-#define EXTENT_DEFRAG_DONE (1 << 7)
-#define EXTENT_BUFFER_FILLED (1 << 8)
 #define EXTENT_BOUNDARY (1 << 9)
 #define EXTENT_NODATASUM (1 << 10)
 #define EXTENT_DO_ACCOUNTING (1 << 11)
 
 /* these are bit numbers for test/set bit */
 #define EXTENT_BUFFER_UPTODATE 0
-#define EXTENT_BUFFER_BLOCKING 1
 #define EXTENT_BUFFER_DIRTY 2
 #define EXTENT_BUFFER_CORRUPT 3
 #define EXTENT_BUFFER_READAHEAD 4      /* this got triggered by readahead */
 #define EXTENT_BUFFER_TREE_REF 5
 #define EXTENT_BUFFER_STALE 6
 #define EXTENT_BUFFER_WRITEBACK 7
-#define EXTENT_BUFFER_IOERR 8
+#define EXTENT_BUFFER_READ_ERR 8        /* read IO error */
 #define EXTENT_BUFFER_DUMMY 9
 #define EXTENT_BUFFER_IN_TREE 10
+#define EXTENT_BUFFER_WRITE_ERR 11    /* write IO error */
 
 /* these are flags for extent_clear_unlock_delalloc */
 #define PAGE_UNLOCK            (1 << 0)
@@ -57,7 +55,6 @@
  * map has page->private set to one.
  */
 #define EXTENT_PAGE_PRIVATE 1
-#define EXTENT_PAGE_PRIVATE_FIRST_PAGE 3
 
 struct extent_state;
 struct btrfs_root;
@@ -108,7 +105,6 @@ struct extent_state {
        struct rb_node rb_node;
 
        /* ADD NEW ELEMENTS AFTER THIS */
-       struct extent_io_tree *tree;
        wait_queue_head_t wq;
        atomic_t refs;
        unsigned long state;
@@ -126,8 +122,6 @@ struct extent_state {
 struct extent_buffer {
        u64 start;
        unsigned long len;
-       unsigned long map_start;
-       unsigned long map_len;
        unsigned long bflags;
        struct btrfs_fs_info *fs_info;
        spinlock_t refs_lock;
@@ -144,7 +138,9 @@ struct extent_buffer {
        atomic_t blocking_readers;
        atomic_t spinning_readers;
        atomic_t spinning_writers;
-       int lock_nested;
+       short lock_nested;
+       /* >= 0 if eb belongs to a log tree, -1 otherwise */
+       short log_index;
 
        /* protects write locks */
        rwlock_t lock;
@@ -286,12 +282,6 @@ static inline unsigned long num_extent_pages(u64 start, u64 len)
                (start >> PAGE_CACHE_SHIFT);
 }
 
-static inline struct page *extent_buffer_page(struct extent_buffer *eb,
-                                             unsigned long i)
-{
-       return eb->pages[i];
-}
-
 static inline void extent_buffer_get(struct extent_buffer *eb)
 {
        atomic_inc(&eb->refs);
@@ -341,18 +331,50 @@ struct bio *btrfs_bio_clone(struct bio *bio, gfp_t gfp_mask);
 
 struct btrfs_fs_info;
 
-int repair_io_failure(struct btrfs_fs_info *fs_info, u64 start,
-                       u64 length, u64 logical, struct page *page,
-                       int mirror_num);
+int repair_io_failure(struct inode *inode, u64 start, u64 length, u64 logical,
+                     struct page *page, unsigned int pg_offset,
+                     int mirror_num);
+int clean_io_failure(struct inode *inode, u64 start, struct page *page,
+                    unsigned int pg_offset);
 int end_extent_writepage(struct page *page, int err, u64 start, u64 end);
 int repair_eb_io_failure(struct btrfs_root *root, struct extent_buffer *eb,
                         int mirror_num);
+
+/*
+ * When IO fails, either with EIO or csum verification fails, we
+ * try other mirrors that might have a good copy of the data.  This
+ * io_failure_record is used to record state as we go through all the
+ * mirrors.  If another mirror has good data, the page is set up to date
+ * and things continue.  If a good mirror can't be found, the original
+ * bio end_io callback is called to indicate things have failed.
+ */
+struct io_failure_record {
+       struct page *page;
+       u64 start;
+       u64 len;
+       u64 logical;
+       unsigned long bio_flags;
+       int this_mirror;
+       int failed_mirror;
+       int in_validation;
+};
+
+void btrfs_free_io_failure_record(struct inode *inode, u64 start, u64 end);
+int btrfs_get_io_failure_record(struct inode *inode, u64 start, u64 end,
+                               struct io_failure_record **failrec_ret);
+int btrfs_check_repairable(struct inode *inode, struct bio *failed_bio,
+                          struct io_failure_record *failrec, int fail_mirror);
+struct bio *btrfs_create_repair_bio(struct inode *inode, struct bio *failed_bio,
+                                   struct io_failure_record *failrec,
+                                   struct page *page, int pg_offset, int icsum,
+                                   bio_end_io_t *endio_func, void *data);
+int free_io_failure(struct inode *inode, struct io_failure_record *rec);
 #ifdef CONFIG_BTRFS_FS_RUN_SANITY_TESTS
 noinline u64 find_lock_delalloc_range(struct inode *inode,
                                      struct extent_io_tree *tree,
                                      struct page *locked_page, u64 *start,
                                      u64 *end, u64 max_bytes);
+#endif
 struct extent_buffer *alloc_test_extent_buffer(struct btrfs_fs_info *fs_info,
                                               u64 start, unsigned long len);
 #endif
-#endif
index 54c84daec9b515f73f8f1178a1e4ea9485d20e3f..783a94355efd0be2acd75d1a84b3860ec7a28740 100644 (file)
@@ -55,7 +55,7 @@ int btrfs_insert_file_extent(struct btrfs_trans_handle *trans,
                return -ENOMEM;
        file_key.objectid = objectid;
        file_key.offset = pos;
-       btrfs_set_key_type(&file_key, BTRFS_EXTENT_DATA_KEY);
+       file_key.type = BTRFS_EXTENT_DATA_KEY;
 
        path->leave_spinning = 1;
        ret = btrfs_insert_empty_item(trans, root, path, &file_key,
@@ -100,7 +100,7 @@ btrfs_lookup_csum(struct btrfs_trans_handle *trans,
 
        file_key.objectid = BTRFS_EXTENT_CSUM_OBJECTID;
        file_key.offset = bytenr;
-       btrfs_set_key_type(&file_key, BTRFS_EXTENT_CSUM_KEY);
+       file_key.type = BTRFS_EXTENT_CSUM_KEY;
        ret = btrfs_search_slot(trans, root, &file_key, path, 0, cow);
        if (ret < 0)
                goto fail;
@@ -111,7 +111,7 @@ btrfs_lookup_csum(struct btrfs_trans_handle *trans,
                        goto fail;
                path->slots[0]--;
                btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]);
-               if (btrfs_key_type(&found_key) != BTRFS_EXTENT_CSUM_KEY)
+               if (found_key.type != BTRFS_EXTENT_CSUM_KEY)
                        goto fail;
 
                csum_offset = (bytenr - found_key.offset) >>
@@ -148,7 +148,7 @@ int btrfs_lookup_file_extent(struct btrfs_trans_handle *trans,
 
        file_key.objectid = objectid;
        file_key.offset = offset;
-       btrfs_set_key_type(&file_key, BTRFS_EXTENT_DATA_KEY);
+       file_key.type = BTRFS_EXTENT_DATA_KEY;
        ret = btrfs_search_slot(trans, root, &file_key, path, ins_len, cow);
        return ret;
 }
@@ -299,19 +299,9 @@ int btrfs_lookup_bio_sums(struct btrfs_root *root, struct inode *inode,
 }
 
 int btrfs_lookup_bio_sums_dio(struct btrfs_root *root, struct inode *inode,
-                             struct btrfs_dio_private *dip, struct bio *bio,
-                             u64 offset)
+                             struct bio *bio, u64 offset)
 {
-       int len = (bio->bi_iter.bi_sector << 9) - dip->disk_bytenr;
-       u16 csum_size = btrfs_super_csum_size(root->fs_info->super_copy);
-       int ret;
-
-       len >>= inode->i_sb->s_blocksize_bits;
-       len *= csum_size;
-
-       ret = __btrfs_lookup_bio_sums(root, inode, bio, offset,
-                                     (u32 *)(dip->csum + len), 1);
-       return ret;
+       return __btrfs_lookup_bio_sums(root, inode, bio, offset, NULL, 1);
 }
 
 int btrfs_lookup_csums_range(struct btrfs_root *root, u64 start, u64 end,
@@ -329,8 +319,8 @@ int btrfs_lookup_csums_range(struct btrfs_root *root, u64 start, u64 end,
        u64 csum_end;
        u16 csum_size = btrfs_super_csum_size(root->fs_info->super_copy);
 
-       ASSERT(start == ALIGN(start, root->sectorsize) &&
-              (end + 1) == ALIGN(end + 1, root->sectorsize));
+       ASSERT(IS_ALIGNED(start, root->sectorsize) &&
+              IS_ALIGNED(end + 1, root->sectorsize));
 
        path = btrfs_alloc_path();
        if (!path)
@@ -720,7 +710,7 @@ again:
        bytenr = sums->bytenr + total_bytes;
        file_key.objectid = BTRFS_EXTENT_CSUM_OBJECTID;
        file_key.offset = bytenr;
-       btrfs_set_key_type(&file_key, BTRFS_EXTENT_CSUM_KEY);
+       file_key.type = BTRFS_EXTENT_CSUM_KEY;
 
        item = btrfs_lookup_csum(trans, root, path, bytenr, 1);
        if (!IS_ERR(item)) {
@@ -790,7 +780,7 @@ again:
        csum_offset = (bytenr - found_key.offset) >>
                        root->fs_info->sb->s_blocksize_bits;
 
-       if (btrfs_key_type(&found_key) != BTRFS_EXTENT_CSUM_KEY ||
+       if (found_key.type != BTRFS_EXTENT_CSUM_KEY ||
            found_key.objectid != BTRFS_EXTENT_CSUM_OBJECTID ||
            csum_offset >= MAX_CSUM_ITEMS(root, csum_size)) {
                goto insert;
index ff1cc0399b9a206c127b4707b6dcd69d455d8231..a18ceabd99a87978f785e2ef0b6318eab3b80ab9 100644 (file)
@@ -299,7 +299,7 @@ static int __btrfs_run_defrag_inode(struct btrfs_fs_info *fs_info,
 
        /* get the inode */
        key.objectid = defrag->root;
-       btrfs_set_key_type(&key, BTRFS_ROOT_ITEM_KEY);
+       key.type = BTRFS_ROOT_ITEM_KEY;
        key.offset = (u64)-1;
 
        index = srcu_read_lock(&fs_info->subvol_srcu);
@@ -311,7 +311,7 @@ static int __btrfs_run_defrag_inode(struct btrfs_fs_info *fs_info,
        }
 
        key.objectid = defrag->ino;
-       btrfs_set_key_type(&key, BTRFS_INODE_ITEM_KEY);
+       key.type = BTRFS_INODE_ITEM_KEY;
        key.offset = 0;
        inode = btrfs_iget(fs_info->sb, &key, inode_root, NULL);
        if (IS_ERR(inode)) {
@@ -452,7 +452,7 @@ static noinline int btrfs_copy_from_user(loff_t pos, int num_pages,
                if (unlikely(copied == 0))
                        break;
 
-               if (unlikely(copied < PAGE_CACHE_SIZE - offset)) {
+               if (copied < PAGE_CACHE_SIZE - offset) {
                        offset += copied;
                } else {
                        pg++;
@@ -1481,9 +1481,8 @@ static noinline ssize_t __btrfs_buffered_write(struct file *file,
        bool force_page_uptodate = false;
        bool need_unlock;
 
-       nrptrs = min((iov_iter_count(i) + PAGE_CACHE_SIZE - 1) /
-                    PAGE_CACHE_SIZE, PAGE_CACHE_SIZE /
-                    (sizeof(struct page *)));
+       nrptrs = min(DIV_ROUND_UP(iov_iter_count(i), PAGE_CACHE_SIZE),
+                       PAGE_CACHE_SIZE / (sizeof(struct page *)));
        nrptrs = min(nrptrs, current->nr_dirtied_pause - current->nr_dirtied);
        nrptrs = max(nrptrs, 8);
        pages = kmalloc(nrptrs * sizeof(struct page *), GFP_KERNEL);
@@ -1497,8 +1496,8 @@ static noinline ssize_t __btrfs_buffered_write(struct file *file,
                size_t write_bytes = min(iov_iter_count(i),
                                         nrptrs * (size_t)PAGE_CACHE_SIZE -
                                         offset);
-               size_t num_pages = (write_bytes + offset +
-                                   PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
+               size_t num_pages = DIV_ROUND_UP(write_bytes + offset,
+                                               PAGE_CACHE_SIZE);
                size_t reserve_bytes;
                size_t dirty_pages;
                size_t copied;
@@ -1526,9 +1525,8 @@ static noinline ssize_t __btrfs_buffered_write(struct file *file,
                                 * our prealloc extent may be smaller than
                                 * write_bytes, so scale down.
                                 */
-                               num_pages = (write_bytes + offset +
-                                            PAGE_CACHE_SIZE - 1) >>
-                                       PAGE_CACHE_SHIFT;
+                               num_pages = DIV_ROUND_UP(write_bytes + offset,
+                                                        PAGE_CACHE_SIZE);
                                reserve_bytes = num_pages << PAGE_CACHE_SHIFT;
                                ret = 0;
                        } else {
@@ -1590,9 +1588,8 @@ again:
                        dirty_pages = 0;
                } else {
                        force_page_uptodate = false;
-                       dirty_pages = (copied + offset +
-                                      PAGE_CACHE_SIZE - 1) >>
-                                      PAGE_CACHE_SHIFT;
+                       dirty_pages = DIV_ROUND_UP(copied + offset,
+                                                  PAGE_CACHE_SIZE);
                }
 
                /*
@@ -1653,7 +1650,7 @@ again:
                cond_resched();
 
                balance_dirty_pages_ratelimited(inode->i_mapping);
-               if (dirty_pages < (root->leafsize >> PAGE_CACHE_SHIFT) + 1)
+               if (dirty_pages < (root->nodesize >> PAGE_CACHE_SHIFT) + 1)
                        btrfs_btree_balance_dirty(root);
 
                pos += copied;
@@ -1795,7 +1792,7 @@ static ssize_t btrfs_file_write_iter(struct kiocb *iocb,
        if (sync)
                atomic_inc(&BTRFS_I(inode)->sync_writers);
 
-       if (unlikely(file->f_flags & O_DIRECT)) {
+       if (file->f_flags & O_DIRECT) {
                num_written = __btrfs_direct_write(iocb, from, pos);
        } else {
                num_written = __btrfs_buffered_write(file, from, pos);
@@ -1852,6 +1849,20 @@ int btrfs_release_file(struct inode *inode, struct file *filp)
        return 0;
 }
 
+static int start_ordered_ops(struct inode *inode, loff_t start, loff_t end)
+{
+       int ret;
+
+       atomic_inc(&BTRFS_I(inode)->sync_writers);
+       ret = filemap_fdatawrite_range(inode->i_mapping, start, end);
+       if (!ret && test_bit(BTRFS_INODE_HAS_ASYNC_EXTENT,
+                            &BTRFS_I(inode)->runtime_flags))
+               ret = filemap_fdatawrite_range(inode->i_mapping, start, end);
+       atomic_dec(&BTRFS_I(inode)->sync_writers);
+
+       return ret;
+}
+
 /*
  * fsync call for both files and directories.  This logs the inode into
  * the tree log instead of forcing full commits whenever possible.
@@ -1881,30 +1892,64 @@ int btrfs_sync_file(struct file *file, loff_t start, loff_t end, int datasync)
         * multi-task, and make the performance up.  See
         * btrfs_wait_ordered_range for an explanation of the ASYNC check.
         */
-       atomic_inc(&BTRFS_I(inode)->sync_writers);
-       ret = filemap_fdatawrite_range(inode->i_mapping, start, end);
-       if (!ret && test_bit(BTRFS_INODE_HAS_ASYNC_EXTENT,
-                            &BTRFS_I(inode)->runtime_flags))
-               ret = filemap_fdatawrite_range(inode->i_mapping, start, end);
-       atomic_dec(&BTRFS_I(inode)->sync_writers);
+       ret = start_ordered_ops(inode, start, end);
        if (ret)
                return ret;
 
        mutex_lock(&inode->i_mutex);
-
-       /*
-        * We flush the dirty pages again to avoid some dirty pages in the
-        * range being left.
-        */
        atomic_inc(&root->log_batch);
        full_sync = test_bit(BTRFS_INODE_NEEDS_FULL_SYNC,
                             &BTRFS_I(inode)->runtime_flags);
+       /*
+        * We might have have had more pages made dirty after calling
+        * start_ordered_ops and before acquiring the inode's i_mutex.
+        */
        if (full_sync) {
+               /*
+                * For a full sync, we need to make sure any ordered operations
+                * start and finish before we start logging the inode, so that
+                * all extents are persisted and the respective file extent
+                * items are in the fs/subvol btree.
+                */
                ret = btrfs_wait_ordered_range(inode, start, end - start + 1);
-               if (ret) {
-                       mutex_unlock(&inode->i_mutex);
-                       goto out;
-               }
+       } else {
+               /*
+                * Start any new ordered operations before starting to log the
+                * inode. We will wait for them to finish in btrfs_sync_log().
+                *
+                * Right before acquiring the inode's mutex, we might have new
+                * writes dirtying pages, which won't immediately start the
+                * respective ordered operations - that is done through the
+                * fill_delalloc callbacks invoked from the writepage and
+                * writepages address space operations. So make sure we start
+                * all ordered operations before starting to log our inode. Not
+                * doing this means that while logging the inode, writeback
+                * could start and invoke writepage/writepages, which would call
+                * the fill_delalloc callbacks (cow_file_range,
+                * submit_compressed_extents). These callbacks add first an
+                * extent map to the modified list of extents and then create
+                * the respective ordered operation, which means in
+                * tree-log.c:btrfs_log_inode() we might capture all existing
+                * ordered operations (with btrfs_get_logged_extents()) before
+                * the fill_delalloc callback adds its ordered operation, and by
+                * the time we visit the modified list of extent maps (with
+                * btrfs_log_changed_extents()), we see and process the extent
+                * map they created. We then use the extent map to construct a
+                * file extent item for logging without waiting for the
+                * respective ordered operation to finish - this file extent
+                * item points to a disk location that might not have yet been
+                * written to, containing random data - so after a crash a log
+                * replay will make our inode have file extent items that point
+                * to disk locations containing invalid data, as we returned
+                * success to userspace without waiting for the respective
+                * ordered operation to finish, because it wasn't captured by
+                * btrfs_get_logged_extents().
+                */
+               ret = start_ordered_ops(inode, start, end);
+       }
+       if (ret) {
+               mutex_unlock(&inode->i_mutex);
+               goto out;
        }
        atomic_inc(&root->log_batch);
 
@@ -1984,6 +2029,25 @@ int btrfs_sync_file(struct file *file, loff_t start, loff_t end, int datasync)
         */
        mutex_unlock(&inode->i_mutex);
 
+       /*
+        * If any of the ordered extents had an error, just return it to user
+        * space, so that the application knows some writes didn't succeed and
+        * can take proper action (retry for e.g.). Blindly committing the
+        * transaction in this case, would fool userspace that everything was
+        * successful. And we also want to make sure our log doesn't contain
+        * file extent items pointing to extents that weren't fully written to -
+        * just like in the non fast fsync path, where we check for the ordered
+        * operation's error flag before writing to the log tree and return -EIO
+        * if any of them had this flag set (btrfs_wait_ordered_range) -
+        * therefore we need to check for errors in the ordered operations,
+        * which are indicated by ctx.io_err.
+        */
+       if (ctx.io_err) {
+               btrfs_end_transaction(trans, root);
+               ret = ctx.io_err;
+               goto out;
+       }
+
        if (ret != BTRFS_NO_LOG_SYNC) {
                if (!ret) {
                        ret = btrfs_sync_log(trans, root, &ctx);
@@ -2621,23 +2685,28 @@ static int find_desired_extent(struct inode *inode, loff_t *offset, int whence)
        struct btrfs_root *root = BTRFS_I(inode)->root;
        struct extent_map *em = NULL;
        struct extent_state *cached_state = NULL;
-       u64 lockstart = *offset;
-       u64 lockend = i_size_read(inode);
-       u64 start = *offset;
-       u64 len = i_size_read(inode);
+       u64 lockstart;
+       u64 lockend;
+       u64 start;
+       u64 len;
        int ret = 0;
 
-       lockend = max_t(u64, root->sectorsize, lockend);
+       if (inode->i_size == 0)
+               return -ENXIO;
+
+       /*
+        * *offset can be negative, in this case we start finding DATA/HOLE from
+        * the very start of the file.
+        */
+       start = max_t(loff_t, 0, *offset);
+
+       lockstart = round_down(start, root->sectorsize);
+       lockend = round_up(i_size_read(inode), root->sectorsize);
        if (lockend <= lockstart)
                lockend = lockstart + root->sectorsize;
-
        lockend--;
        len = lockend - lockstart + 1;
 
-       len = max_t(u64, len, root->sectorsize);
-       if (inode->i_size == 0)
-               return -ENXIO;
-
        lock_extent_bits(&BTRFS_I(inode)->io_tree, lockstart, lockend, 0,
                         &cached_state);
 
index 2b0a627cb5f94e414d3c9751f5e8e384e39c42f9..33848196550e4984eff6a577242e7710f70b0c82 100644 (file)
@@ -279,8 +279,7 @@ static int io_ctl_init(struct io_ctl *io_ctl, struct inode *inode,
        int num_pages;
        int check_crcs = 0;
 
-       num_pages = (i_size_read(inode) + PAGE_CACHE_SIZE - 1) >>
-                   PAGE_CACHE_SHIFT;
+       num_pages = DIV_ROUND_UP(i_size_read(inode), PAGE_CACHE_SIZE);
 
        if (btrfs_ino(inode) != BTRFS_FREE_INO_OBJECTID)
                check_crcs = 1;
@@ -1998,6 +1997,128 @@ static bool try_merge_free_space(struct btrfs_free_space_ctl *ctl,
        return merged;
 }
 
+static bool steal_from_bitmap_to_end(struct btrfs_free_space_ctl *ctl,
+                                    struct btrfs_free_space *info,
+                                    bool update_stat)
+{
+       struct btrfs_free_space *bitmap;
+       unsigned long i;
+       unsigned long j;
+       const u64 end = info->offset + info->bytes;
+       const u64 bitmap_offset = offset_to_bitmap(ctl, end);
+       u64 bytes;
+
+       bitmap = tree_search_offset(ctl, bitmap_offset, 1, 0);
+       if (!bitmap)
+               return false;
+
+       i = offset_to_bit(bitmap->offset, ctl->unit, end);
+       j = find_next_zero_bit(bitmap->bitmap, BITS_PER_BITMAP, i);
+       if (j == i)
+               return false;
+       bytes = (j - i) * ctl->unit;
+       info->bytes += bytes;
+
+       if (update_stat)
+               bitmap_clear_bits(ctl, bitmap, end, bytes);
+       else
+               __bitmap_clear_bits(ctl, bitmap, end, bytes);
+
+       if (!bitmap->bytes)
+               free_bitmap(ctl, bitmap);
+
+       return true;
+}
+
+static bool steal_from_bitmap_to_front(struct btrfs_free_space_ctl *ctl,
+                                      struct btrfs_free_space *info,
+                                      bool update_stat)
+{
+       struct btrfs_free_space *bitmap;
+       u64 bitmap_offset;
+       unsigned long i;
+       unsigned long j;
+       unsigned long prev_j;
+       u64 bytes;
+
+       bitmap_offset = offset_to_bitmap(ctl, info->offset);
+       /* If we're on a boundary, try the previous logical bitmap. */
+       if (bitmap_offset == info->offset) {
+               if (info->offset == 0)
+                       return false;
+               bitmap_offset = offset_to_bitmap(ctl, info->offset - 1);
+       }
+
+       bitmap = tree_search_offset(ctl, bitmap_offset, 1, 0);
+       if (!bitmap)
+               return false;
+
+       i = offset_to_bit(bitmap->offset, ctl->unit, info->offset) - 1;
+       j = 0;
+       prev_j = (unsigned long)-1;
+       for_each_clear_bit_from(j, bitmap->bitmap, BITS_PER_BITMAP) {
+               if (j > i)
+                       break;
+               prev_j = j;
+       }
+       if (prev_j == i)
+               return false;
+
+       if (prev_j == (unsigned long)-1)
+               bytes = (i + 1) * ctl->unit;
+       else
+               bytes = (i - prev_j) * ctl->unit;
+
+       info->offset -= bytes;
+       info->bytes += bytes;
+
+       if (update_stat)
+               bitmap_clear_bits(ctl, bitmap, info->offset, bytes);
+       else
+               __bitmap_clear_bits(ctl, bitmap, info->offset, bytes);
+
+       if (!bitmap->bytes)
+               free_bitmap(ctl, bitmap);
+
+       return true;
+}
+
+/*
+ * We prefer always to allocate from extent entries, both for clustered and
+ * non-clustered allocation requests. So when attempting to add a new extent
+ * entry, try to see if there's adjacent free space in bitmap entries, and if
+ * there is, migrate that space from the bitmaps to the extent.
+ * Like this we get better chances of satisfying space allocation requests
+ * because we attempt to satisfy them based on a single cache entry, and never
+ * on 2 or more entries - even if the entries represent a contiguous free space
+ * region (e.g. 1 extent entry + 1 bitmap entry starting where the extent entry
+ * ends).
+ */
+static void steal_from_bitmap(struct btrfs_free_space_ctl *ctl,
+                             struct btrfs_free_space *info,
+                             bool update_stat)
+{
+       /*
+        * Only work with disconnected entries, as we can change their offset,
+        * and must be extent entries.
+        */
+       ASSERT(!info->bitmap);
+       ASSERT(RB_EMPTY_NODE(&info->offset_index));
+
+       if (ctl->total_bitmaps > 0) {
+               bool stole_end;
+               bool stole_front = false;
+
+               stole_end = steal_from_bitmap_to_end(ctl, info, update_stat);
+               if (ctl->total_bitmaps > 0)
+                       stole_front = steal_from_bitmap_to_front(ctl, info,
+                                                                update_stat);
+
+               if (stole_end || stole_front)
+                       try_merge_free_space(ctl, info, update_stat);
+       }
+}
+
 int __btrfs_add_free_space(struct btrfs_free_space_ctl *ctl,
                           u64 offset, u64 bytes)
 {
@@ -2010,6 +2131,7 @@ int __btrfs_add_free_space(struct btrfs_free_space_ctl *ctl,
 
        info->offset = offset;
        info->bytes = bytes;
+       RB_CLEAR_NODE(&info->offset_index);
 
        spin_lock(&ctl->tree_lock);
 
@@ -2029,6 +2151,14 @@ int __btrfs_add_free_space(struct btrfs_free_space_ctl *ctl,
                goto out;
        }
 link:
+       /*
+        * Only steal free space from adjacent bitmaps if we're sure we're not
+        * going to add the new free space to existing bitmap entries - because
+        * that would mean unnecessary work that would be reverted. Therefore
+        * attempt to steal space from bitmaps if we're adding an extent entry.
+        */
+       steal_from_bitmap(ctl, info, true);
+
        ret = link_free_space(ctl, info);
        if (ret)
                kmem_cache_free(btrfs_free_space_cachep, info);
@@ -2205,10 +2335,13 @@ __btrfs_return_cluster_to_free_space(
                entry = rb_entry(node, struct btrfs_free_space, offset_index);
                node = rb_next(&entry->offset_index);
                rb_erase(&entry->offset_index, &cluster->root);
+               RB_CLEAR_NODE(&entry->offset_index);
 
                bitmap = (entry->bitmap != NULL);
-               if (!bitmap)
+               if (!bitmap) {
                        try_merge_free_space(ctl, entry, false);
+                       steal_from_bitmap(ctl, entry, false);
+               }
                tree_insert_offset(&ctl->free_space_offset,
                                   entry->offset, &entry->offset_index, bitmap);
        }
@@ -3033,10 +3166,10 @@ struct inode *lookup_free_ino_inode(struct btrfs_root *root,
 {
        struct inode *inode = NULL;
 
-       spin_lock(&root->cache_lock);
-       if (root->cache_inode)
-               inode = igrab(root->cache_inode);
-       spin_unlock(&root->cache_lock);
+       spin_lock(&root->ino_cache_lock);
+       if (root->ino_cache_inode)
+               inode = igrab(root->ino_cache_inode);
+       spin_unlock(&root->ino_cache_lock);
        if (inode)
                return inode;
 
@@ -3044,10 +3177,10 @@ struct inode *lookup_free_ino_inode(struct btrfs_root *root,
        if (IS_ERR(inode))
                return inode;
 
-       spin_lock(&root->cache_lock);
+       spin_lock(&root->ino_cache_lock);
        if (!btrfs_fs_closing(root->fs_info))
-               root->cache_inode = igrab(inode);
-       spin_unlock(&root->cache_lock);
+               root->ino_cache_inode = igrab(inode);
+       spin_unlock(&root->ino_cache_lock);
 
        return inode;
 }
@@ -3176,6 +3309,7 @@ again:
                map = NULL;
                add_new_bitmap(ctl, info, offset);
                bitmap_info = info;
+               info = NULL;
        }
 
        bytes_added = add_bytes_to_bitmap(ctl, bitmap_info, offset, bytes);
@@ -3186,6 +3320,8 @@ again:
        if (bytes)
                goto again;
 
+       if (info)
+               kmem_cache_free(btrfs_free_space_cachep, info);
        if (map)
                kfree(map);
        return 0;
@@ -3260,6 +3396,7 @@ have_info:
                        goto have_info;
                }
 
+               ret = 0;
                goto out;
        }
 
index 85889aa82c62dd8d05d9c8a01cff08f86afc4d05..64f15bb30a81dbf9ada217d4e0c09cd74fddb197 100644 (file)
@@ -20,10 +20,8 @@ static struct crypto_shash *tfm;
 int __init btrfs_hash_init(void)
 {
        tfm = crypto_alloc_shash("crc32c", 0, 0);
-       if (IS_ERR(tfm))
-               return PTR_ERR(tfm);
 
-       return 0;
+       return PTR_ERR_OR_ZERO(tfm);
 }
 
 void btrfs_hash_exit(void)
index 2be38df703c9b095f35ed5e887fa2c37c7fb0e7c..8ffa4783cbf438ed182e6f94e39711ded5207558 100644 (file)
@@ -135,7 +135,7 @@ static int btrfs_del_inode_extref(struct btrfs_trans_handle *trans,
        u32 item_size;
 
        key.objectid = inode_objectid;
-       btrfs_set_key_type(&key, BTRFS_INODE_EXTREF_KEY);
+       key.type = BTRFS_INODE_EXTREF_KEY;
        key.offset = btrfs_extref_hash(ref_objectid, name, name_len);
 
        path = btrfs_alloc_path();
@@ -209,7 +209,7 @@ int btrfs_del_inode_ref(struct btrfs_trans_handle *trans,
 
        key.objectid = inode_objectid;
        key.offset = ref_objectid;
-       btrfs_set_key_type(&key, BTRFS_INODE_REF_KEY);
+       key.type = BTRFS_INODE_REF_KEY;
 
        path = btrfs_alloc_path();
        if (!path)
@@ -337,7 +337,7 @@ int btrfs_insert_inode_ref(struct btrfs_trans_handle *trans,
 
        key.objectid = inode_objectid;
        key.offset = ref_objectid;
-       btrfs_set_key_type(&key, BTRFS_INODE_REF_KEY);
+       key.type = BTRFS_INODE_REF_KEY;
 
        path = btrfs_alloc_path();
        if (!path)
@@ -400,7 +400,7 @@ int btrfs_insert_empty_inode(struct btrfs_trans_handle *trans,
        struct btrfs_key key;
        int ret;
        key.objectid = objectid;
-       btrfs_set_key_type(&key, BTRFS_INODE_ITEM_KEY);
+       key.type = BTRFS_INODE_ITEM_KEY;
        key.offset = 0;
 
        ret = btrfs_insert_empty_item(trans, root, path, &key,
@@ -420,13 +420,13 @@ int btrfs_lookup_inode(struct btrfs_trans_handle *trans, struct btrfs_root
        struct btrfs_key found_key;
 
        ret = btrfs_search_slot(trans, root, location, path, ins_len, cow);
-       if (ret > 0 && btrfs_key_type(location) == BTRFS_ROOT_ITEM_KEY &&
+       if (ret > 0 && location->type == BTRFS_ROOT_ITEM_KEY &&
            location->offset == (u64)-1 && path->slots[0] != 0) {
                slot = path->slots[0] - 1;
                leaf = path->nodes[0];
                btrfs_item_key_to_cpu(leaf, &found_key, slot);
                if (found_key.objectid == location->objectid &&
-                   btrfs_key_type(&found_key) == btrfs_key_type(location)) {
+                   found_key.type == location->type) {
                        path->slots[0]--;
                        return 0;
                }
index 888fbe19079fd7589484feb089cfa88dcafa6a89..83d646bd2e4b90f34bd597b8ba6f6244071e48f1 100644 (file)
@@ -87,7 +87,7 @@ again:
                                 */
                                btrfs_item_key_to_cpu(leaf, &key, 0);
                                btrfs_release_path(path);
-                               root->cache_progress = last;
+                               root->ino_cache_progress = last;
                                up_read(&fs_info->commit_root_sem);
                                schedule_timeout(1);
                                goto again;
@@ -106,7 +106,7 @@ again:
                if (last != (u64)-1 && last + 1 != key.objectid) {
                        __btrfs_add_free_space(ctl, last + 1,
                                               key.objectid - last - 1);
-                       wake_up(&root->cache_wait);
+                       wake_up(&root->ino_cache_wait);
                }
 
                last = key.objectid;
@@ -119,14 +119,14 @@ next:
                                       root->highest_objectid - last - 1);
        }
 
-       spin_lock(&root->cache_lock);
-       root->cached = BTRFS_CACHE_FINISHED;
-       spin_unlock(&root->cache_lock);
+       spin_lock(&root->ino_cache_lock);
+       root->ino_cache_state = BTRFS_CACHE_FINISHED;
+       spin_unlock(&root->ino_cache_lock);
 
-       root->cache_progress = (u64)-1;
+       root->ino_cache_progress = (u64)-1;
        btrfs_unpin_free_ino(root);
 out:
-       wake_up(&root->cache_wait);
+       wake_up(&root->ino_cache_wait);
        up_read(&fs_info->commit_root_sem);
 
        btrfs_free_path(path);
@@ -144,20 +144,20 @@ static void start_caching(struct btrfs_root *root)
        if (!btrfs_test_opt(root, INODE_MAP_CACHE))
                return;
 
-       spin_lock(&root->cache_lock);
-       if (root->cached != BTRFS_CACHE_NO) {
-               spin_unlock(&root->cache_lock);
+       spin_lock(&root->ino_cache_lock);
+       if (root->ino_cache_state != BTRFS_CACHE_NO) {
+               spin_unlock(&root->ino_cache_lock);
                return;
        }
 
-       root->cached = BTRFS_CACHE_STARTED;
-       spin_unlock(&root->cache_lock);
+       root->ino_cache_state = BTRFS_CACHE_STARTED;
+       spin_unlock(&root->ino_cache_lock);
 
        ret = load_free_ino_cache(root->fs_info, root);
        if (ret == 1) {
-               spin_lock(&root->cache_lock);
-               root->cached = BTRFS_CACHE_FINISHED;
-               spin_unlock(&root->cache_lock);
+               spin_lock(&root->ino_cache_lock);
+               root->ino_cache_state = BTRFS_CACHE_FINISHED;
+               spin_unlock(&root->ino_cache_lock);
                return;
        }
 
@@ -196,11 +196,11 @@ again:
 
        start_caching(root);
 
-       wait_event(root->cache_wait,
-                  root->cached == BTRFS_CACHE_FINISHED ||
+       wait_event(root->ino_cache_wait,
+                  root->ino_cache_state == BTRFS_CACHE_FINISHED ||
                   root->free_ino_ctl->free_space > 0);
 
-       if (root->cached == BTRFS_CACHE_FINISHED &&
+       if (root->ino_cache_state == BTRFS_CACHE_FINISHED &&
            root->free_ino_ctl->free_space == 0)
                return -ENOSPC;
        else
@@ -214,17 +214,17 @@ void btrfs_return_ino(struct btrfs_root *root, u64 objectid)
        if (!btrfs_test_opt(root, INODE_MAP_CACHE))
                return;
 again:
-       if (root->cached == BTRFS_CACHE_FINISHED) {
+       if (root->ino_cache_state == BTRFS_CACHE_FINISHED) {
                __btrfs_add_free_space(pinned, objectid, 1);
        } else {
                down_write(&root->fs_info->commit_root_sem);
-               spin_lock(&root->cache_lock);
-               if (root->cached == BTRFS_CACHE_FINISHED) {
-                       spin_unlock(&root->cache_lock);
+               spin_lock(&root->ino_cache_lock);
+               if (root->ino_cache_state == BTRFS_CACHE_FINISHED) {
+                       spin_unlock(&root->ino_cache_lock);
                        up_write(&root->fs_info->commit_root_sem);
                        goto again;
                }
-               spin_unlock(&root->cache_lock);
+               spin_unlock(&root->ino_cache_lock);
 
                start_caching(root);
 
@@ -235,10 +235,10 @@ again:
 }
 
 /*
- * When a transaction is committed, we'll move those inode numbers which
- * are smaller than root->cache_progress from pinned tree to free_ino tree,
- * and others will just be dropped, because the commit root we were
- * searching has changed.
+ * When a transaction is committed, we'll move those inode numbers which are
+ * smaller than root->ino_cache_progress from pinned tree to free_ino tree, and
+ * others will just be dropped, because the commit root we were searching has
+ * changed.
  *
  * Must be called with root->fs_info->commit_root_sem held
  */
@@ -261,10 +261,10 @@ void btrfs_unpin_free_ino(struct btrfs_root *root)
                info = rb_entry(n, struct btrfs_free_space, offset_index);
                BUG_ON(info->bitmap); /* Logic error */
 
-               if (info->offset > root->cache_progress)
+               if (info->offset > root->ino_cache_progress)
                        goto free;
-               else if (info->offset + info->bytes > root->cache_progress)
-                       count = root->cache_progress - info->offset + 1;
+               else if (info->offset + info->bytes > root->ino_cache_progress)
+                       count = root->ino_cache_progress - info->offset + 1;
                else
                        count = info->bytes;
 
@@ -462,13 +462,13 @@ again:
                }
        }
 
-       spin_lock(&root->cache_lock);
-       if (root->cached != BTRFS_CACHE_FINISHED) {
+       spin_lock(&root->ino_cache_lock);
+       if (root->ino_cache_state != BTRFS_CACHE_FINISHED) {
                ret = -1;
-               spin_unlock(&root->cache_lock);
+               spin_unlock(&root->ino_cache_lock);
                goto out_put;
        }
-       spin_unlock(&root->cache_lock);
+       spin_unlock(&root->ino_cache_lock);
 
        spin_lock(&ctl->tree_lock);
        prealloc = sizeof(struct btrfs_free_space) * ctl->free_extents;
index 016c403bfe7e4241b33c6b6c3e4101ba5ea993b2..fc9c0439caa314e131e1c23c384884b71bf84fb1 100644 (file)
@@ -153,7 +153,7 @@ static int insert_inline_extent(struct btrfs_trans_handle *trans,
 
                key.objectid = btrfs_ino(inode);
                key.offset = start;
-               btrfs_set_key_type(&key, BTRFS_EXTENT_DATA_KEY);
+               key.type = BTRFS_EXTENT_DATA_KEY;
 
                datasize = btrfs_file_extent_calc_inline_size(cur_size);
                path->leave_spinning = 1;
@@ -249,8 +249,8 @@ static noinline int cow_file_range_inline(struct btrfs_root *root,
                data_len = compressed_size;
 
        if (start > 0 ||
-           actual_end >= PAGE_CACHE_SIZE ||
-           data_len >= BTRFS_MAX_INLINE_DATA_SIZE(root) ||
+           actual_end > PAGE_CACHE_SIZE ||
+           data_len > BTRFS_MAX_INLINE_DATA_SIZE(root) ||
            (!compressed_size &&
            (actual_end & (root->sectorsize - 1)) == 0) ||
            end + 1 < isize ||
@@ -348,6 +348,23 @@ static noinline int add_async_extent(struct async_cow *cow,
        return 0;
 }
 
+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))
+               return 1;
+       /* bad compression ratios */
+       if (BTRFS_I(inode)->flags & BTRFS_INODE_NOCOMPRESS)
+               return 0;
+       if (btrfs_test_opt(root, COMPRESS) ||
+           BTRFS_I(inode)->flags & BTRFS_INODE_COMPRESS ||
+           BTRFS_I(inode)->force_compress)
+               return 1;
+       return 0;
+}
+
 /*
  * we create compressed extents in two phases.  The first
  * phase compresses a range of pages that have already been
@@ -444,10 +461,7 @@ again:
         * inode has not been flagged as nocompress.  This flag can
         * change at any time if we discover bad compression ratios.
         */
-       if (!(BTRFS_I(inode)->flags & BTRFS_INODE_NOCOMPRESS) &&
-           (btrfs_test_opt(root, COMPRESS) ||
-            (BTRFS_I(inode)->force_compress) ||
-            (BTRFS_I(inode)->flags & BTRFS_INODE_COMPRESS))) {
+       if (inode_need_compress(inode)) {
                WARN_ON(pages);
                pages = kzalloc(sizeof(struct page *) * nr_pages, GFP_NOFS);
                if (!pages) {
@@ -1094,7 +1108,8 @@ static int cow_file_range_async(struct inode *inode, struct page *locked_page,
                async_cow->locked_page = locked_page;
                async_cow->start = start;
 
-               if (BTRFS_I(inode)->flags & BTRFS_INODE_NOCOMPRESS)
+               if (BTRFS_I(inode)->flags & BTRFS_INODE_NOCOMPRESS &&
+                   !btrfs_test_opt(root, FORCE_COMPRESS))
                        cur_end = end;
                else
                        cur_end = min(end, start + 512 * 1024 - 1);
@@ -1445,6 +1460,26 @@ error:
        return ret;
 }
 
+static inline int need_force_cow(struct inode *inode, u64 start, u64 end)
+{
+
+       if (!(BTRFS_I(inode)->flags & BTRFS_INODE_NODATACOW) &&
+           !(BTRFS_I(inode)->flags & BTRFS_INODE_PREALLOC))
+               return 0;
+
+       /*
+        * @defrag_bytes is a hint value, no spinlock held here,
+        * if is not zero, it means the file is defragging.
+        * Force cow if given extent needs to be defragged.
+        */
+       if (BTRFS_I(inode)->defrag_bytes &&
+           test_range_bit(&BTRFS_I(inode)->io_tree, start, end,
+                          EXTENT_DEFRAG, 0, NULL))
+               return 1;
+
+       return 0;
+}
+
 /*
  * extent_io.c call back to do delayed allocation processing
  */
@@ -1453,17 +1488,15 @@ static int run_delalloc_range(struct inode *inode, struct page *locked_page,
                              unsigned long *nr_written)
 {
        int ret;
-       struct btrfs_root *root = BTRFS_I(inode)->root;
+       int force_cow = need_force_cow(inode, start, end);
 
-       if (BTRFS_I(inode)->flags & BTRFS_INODE_NODATACOW) {
+       if (BTRFS_I(inode)->flags & BTRFS_INODE_NODATACOW && !force_cow) {
                ret = run_delalloc_nocow(inode, locked_page, start, end,
                                         page_started, 1, nr_written);
-       } else if (BTRFS_I(inode)->flags & BTRFS_INODE_PREALLOC) {
+       } else if (BTRFS_I(inode)->flags & BTRFS_INODE_PREALLOC && !force_cow) {
                ret = run_delalloc_nocow(inode, locked_page, start, end,
                                         page_started, 0, nr_written);
-       } else if (!btrfs_test_opt(root, COMPRESS) &&
-                  !(BTRFS_I(inode)->force_compress) &&
-                  !(BTRFS_I(inode)->flags & BTRFS_INODE_COMPRESS)) {
+       } else if (!inode_need_compress(inode)) {
                ret = cow_file_range(inode, locked_page, start, end,
                                      page_started, nr_written, 1);
        } else {
@@ -1555,6 +1588,8 @@ static void btrfs_set_bit_hook(struct inode *inode,
                               struct extent_state *state, unsigned long *bits)
 {
 
+       if ((*bits & EXTENT_DEFRAG) && !(*bits & EXTENT_DELALLOC))
+               WARN_ON(1);
        /*
         * set_bit and clear bit hooks normally require _irqsave/restore
         * but in this case, we are only testing for the DELALLOC
@@ -1577,6 +1612,8 @@ static void btrfs_set_bit_hook(struct inode *inode,
                                     root->fs_info->delalloc_batch);
                spin_lock(&BTRFS_I(inode)->lock);
                BTRFS_I(inode)->delalloc_bytes += len;
+               if (*bits & EXTENT_DEFRAG)
+                       BTRFS_I(inode)->defrag_bytes += len;
                if (do_list && !test_bit(BTRFS_INODE_IN_DELALLOC_LIST,
                                         &BTRFS_I(inode)->runtime_flags))
                        btrfs_add_delalloc_inodes(root, inode);
@@ -1591,6 +1628,13 @@ static void btrfs_clear_bit_hook(struct inode *inode,
                                 struct extent_state *state,
                                 unsigned long *bits)
 {
+       u64 len = state->end + 1 - state->start;
+
+       spin_lock(&BTRFS_I(inode)->lock);
+       if ((state->state & EXTENT_DEFRAG) && (*bits & EXTENT_DEFRAG))
+               BTRFS_I(inode)->defrag_bytes -= len;
+       spin_unlock(&BTRFS_I(inode)->lock);
+
        /*
         * set_bit and clear bit hooks normally require _irqsave/restore
         * but in this case, we are only testing for the DELALLOC
@@ -1598,7 +1642,6 @@ static void btrfs_clear_bit_hook(struct inode *inode,
         */
        if ((state->state & EXTENT_DELALLOC) && (*bits & EXTENT_DELALLOC)) {
                struct btrfs_root *root = BTRFS_I(inode)->root;
-               u64 len = state->end + 1 - state->start;
                bool do_list = !btrfs_is_free_space_inode(inode);
 
                if (*bits & EXTENT_FIRST_DELALLOC) {
@@ -2660,6 +2703,10 @@ static int btrfs_finish_ordered_io(struct btrfs_ordered_extent *ordered_extent)
                goto out;
        }
 
+       btrfs_free_io_failure_record(inode, ordered_extent->file_offset,
+                                    ordered_extent->file_offset +
+                                    ordered_extent->len - 1);
+
        if (test_bit(BTRFS_ORDERED_TRUNCATED, &ordered_extent->flags)) {
                truncated = true;
                logical_len = ordered_extent->truncated_len;
@@ -2856,6 +2903,40 @@ static int btrfs_writepage_end_io_hook(struct page *page, u64 start, u64 end,
        return 0;
 }
 
+static int __readpage_endio_check(struct inode *inode,
+                                 struct btrfs_io_bio *io_bio,
+                                 int icsum, struct page *page,
+                                 int pgoff, u64 start, size_t len)
+{
+       char *kaddr;
+       u32 csum_expected;
+       u32 csum = ~(u32)0;
+       static DEFINE_RATELIMIT_STATE(_rs, DEFAULT_RATELIMIT_INTERVAL,
+                                     DEFAULT_RATELIMIT_BURST);
+
+       csum_expected = *(((u32 *)io_bio->csum) + icsum);
+
+       kaddr = kmap_atomic(page);
+       csum = btrfs_csum_data(kaddr + pgoff, csum,  len);
+       btrfs_csum_final(csum, (char *)&csum);
+       if (csum != csum_expected)
+               goto zeroit;
+
+       kunmap_atomic(kaddr);
+       return 0;
+zeroit:
+       if (__ratelimit(&_rs))
+               btrfs_info(BTRFS_I(inode)->root->fs_info,
+                          "csum failed ino %llu off %llu csum %u expected csum %u",
+                          btrfs_ino(inode), start, csum, csum_expected);
+       memset(kaddr + pgoff, 1, len);
+       flush_dcache_page(page);
+       kunmap_atomic(kaddr);
+       if (csum_expected == 0)
+               return 0;
+       return -EIO;
+}
+
 /*
  * when reads are done, we need to check csums to verify the data is correct
  * if there's a match, we allow the bio to finish.  If not, the code in
@@ -2868,20 +2949,15 @@ static int btrfs_readpage_end_io_hook(struct btrfs_io_bio *io_bio,
        size_t offset = start - page_offset(page);
        struct inode *inode = page->mapping->host;
        struct extent_io_tree *io_tree = &BTRFS_I(inode)->io_tree;
-       char *kaddr;
        struct btrfs_root *root = BTRFS_I(inode)->root;
-       u32 csum_expected;
-       u32 csum = ~(u32)0;
-       static DEFINE_RATELIMIT_STATE(_rs, DEFAULT_RATELIMIT_INTERVAL,
-                                     DEFAULT_RATELIMIT_BURST);
 
        if (PageChecked(page)) {
                ClearPageChecked(page);
-               goto good;
+               return 0;
        }
 
        if (BTRFS_I(inode)->flags & BTRFS_INODE_NODATASUM)
-               goto good;
+               return 0;
 
        if (root->root_key.objectid == BTRFS_DATA_RELOC_TREE_OBJECTID &&
            test_range_bit(io_tree, start, end, EXTENT_NODATASUM, 1, NULL)) {
@@ -2891,28 +2967,8 @@ static int btrfs_readpage_end_io_hook(struct btrfs_io_bio *io_bio,
        }
 
        phy_offset >>= inode->i_sb->s_blocksize_bits;
-       csum_expected = *(((u32 *)io_bio->csum) + phy_offset);
-
-       kaddr = kmap_atomic(page);
-       csum = btrfs_csum_data(kaddr + offset, csum,  end - start + 1);
-       btrfs_csum_final(csum, (char *)&csum);
-       if (csum != csum_expected)
-               goto zeroit;
-
-       kunmap_atomic(kaddr);
-good:
-       return 0;
-
-zeroit:
-       if (__ratelimit(&_rs))
-               btrfs_info(root->fs_info, "csum failed ino %llu off %llu csum %u expected csum %u",
-                       btrfs_ino(page->mapping->host), start, csum, csum_expected);
-       memset(kaddr + offset, 1, end - start + 1);
-       flush_dcache_page(page);
-       kunmap_atomic(kaddr);
-       if (csum_expected == 0)
-               return 0;
-       return -EIO;
+       return __readpage_endio_check(inode, io_bio, phy_offset, page, offset,
+                                     start, (size_t)(end - start + 1));
 }
 
 struct delayed_iput {
@@ -3159,7 +3215,7 @@ int btrfs_orphan_cleanup(struct btrfs_root *root)
        path->reada = -1;
 
        key.objectid = BTRFS_ORPHAN_OBJECTID;
-       btrfs_set_key_type(&key, BTRFS_ORPHAN_ITEM_KEY);
+       key.type = BTRFS_ORPHAN_ITEM_KEY;
        key.offset = (u64)-1;
 
        while (1) {
@@ -3186,7 +3242,7 @@ int btrfs_orphan_cleanup(struct btrfs_root *root)
                /* make sure the item matches what we want */
                if (found_key.objectid != BTRFS_ORPHAN_OBJECTID)
                        break;
-               if (btrfs_key_type(&found_key) != BTRFS_ORPHAN_ITEM_KEY)
+               if (found_key.type != BTRFS_ORPHAN_ITEM_KEY)
                        break;
 
                /* release the path since we're done with it */
@@ -3662,7 +3718,8 @@ noinline int btrfs_update_inode(struct btrfs_trans_handle *trans,
         * without delay
         */
        if (!btrfs_is_free_space_inode(inode)
-           && root->root_key.objectid != BTRFS_DATA_RELOC_TREE_OBJECTID) {
+           && root->root_key.objectid != BTRFS_DATA_RELOC_TREE_OBJECTID
+           && !root->fs_info->log_root_recovering) {
                btrfs_update_root_times(trans, root);
 
                ret = btrfs_delayed_update_inode(trans, root, inode);
@@ -4085,7 +4142,7 @@ search_again:
                fi = NULL;
                leaf = path->nodes[0];
                btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]);
-               found_type = btrfs_key_type(&found_key);
+               found_type = found_key.type;
 
                if (found_key.objectid != ino)
                        break;
@@ -4747,6 +4804,8 @@ void btrfs_evict_inode(struct inode *inode)
        /* do we really want it for ->i_nlink > 0 and zero btrfs_root_refs? */
        btrfs_wait_ordered_range(inode, 0, (u64)-1);
 
+       btrfs_free_io_failure_record(inode, 0, (u64)-1);
+
        if (root->fs_info->log_root_recovering) {
                BUG_ON(test_bit(BTRFS_INODE_HAS_ORPHAN_ITEM,
                                 &BTRFS_I(inode)->runtime_flags));
@@ -5331,7 +5390,7 @@ static int btrfs_real_readdir(struct file *file, struct dir_context *ctx)
                btrfs_get_delayed_items(inode, &ins_list, &del_list);
        }
 
-       btrfs_set_key_type(&key, key_type);
+       key.type = key_type;
        key.offset = ctx->pos;
        key.objectid = btrfs_ino(inode);
 
@@ -5356,7 +5415,7 @@ static int btrfs_real_readdir(struct file *file, struct dir_context *ctx)
 
                if (found_key.objectid != key.objectid)
                        break;
-               if (btrfs_key_type(&found_key) != key_type)
+               if (found_key.type != key_type)
                        break;
                if (found_key.offset < ctx->pos)
                        goto next;
@@ -5568,7 +5627,7 @@ static int btrfs_set_inode_index_count(struct inode *inode)
        int ret;
 
        key.objectid = btrfs_ino(inode);
-       btrfs_set_key_type(&key, BTRFS_DIR_INDEX_KEY);
+       key.type = BTRFS_DIR_INDEX_KEY;
        key.offset = (u64)-1;
 
        path = btrfs_alloc_path();
@@ -5600,7 +5659,7 @@ static int btrfs_set_inode_index_count(struct inode *inode)
        btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]);
 
        if (found_key.objectid != btrfs_ino(inode) ||
-           btrfs_key_type(&found_key) != BTRFS_DIR_INDEX_KEY) {
+           found_key.type != BTRFS_DIR_INDEX_KEY) {
                BTRFS_I(inode)->index_cnt = 2;
                goto out;
        }
@@ -5718,7 +5777,7 @@ static struct inode *btrfs_new_inode(struct btrfs_trans_handle *trans,
        set_bit(BTRFS_INODE_NEEDS_FULL_SYNC, &BTRFS_I(inode)->runtime_flags);
 
        key[0].objectid = objectid;
-       btrfs_set_key_type(&key[0], BTRFS_INODE_ITEM_KEY);
+       key[0].type = BTRFS_INODE_ITEM_KEY;
        key[0].offset = 0;
 
        sizes[0] = sizeof(struct btrfs_inode_item);
@@ -5731,7 +5790,7 @@ static struct inode *btrfs_new_inode(struct btrfs_trans_handle *trans,
                 * add more hard links than can fit in the ref item.
                 */
                key[1].objectid = objectid;
-               btrfs_set_key_type(&key[1], BTRFS_INODE_REF_KEY);
+               key[1].type = BTRFS_INODE_REF_KEY;
                key[1].offset = ref_objectid;
 
                sizes[1] = name_len + sizeof(*ref);
@@ -5740,7 +5799,7 @@ static struct inode *btrfs_new_inode(struct btrfs_trans_handle *trans,
        location = &BTRFS_I(inode)->location;
        location->objectid = objectid;
        location->offset = 0;
-       btrfs_set_key_type(location, BTRFS_INODE_ITEM_KEY);
+       location->type = BTRFS_INODE_ITEM_KEY;
 
        ret = btrfs_insert_inode_locked(inode);
        if (ret < 0)
@@ -5832,7 +5891,7 @@ int btrfs_add_link(struct btrfs_trans_handle *trans,
                memcpy(&key, &BTRFS_I(inode)->root->root_key, sizeof(key));
        } else {
                key.objectid = ino;
-               btrfs_set_key_type(&key, BTRFS_INODE_ITEM_KEY);
+               key.type = BTRFS_INODE_ITEM_KEY;
                key.offset = 0;
        }
 
@@ -6191,21 +6250,60 @@ out_fail_inode:
        goto out_fail;
 }
 
+/* Find next extent map of a given extent map, caller needs to ensure locks */
+static struct extent_map *next_extent_map(struct extent_map *em)
+{
+       struct rb_node *next;
+
+       next = rb_next(&em->rb_node);
+       if (!next)
+               return NULL;
+       return container_of(next, struct extent_map, rb_node);
+}
+
+static struct extent_map *prev_extent_map(struct extent_map *em)
+{
+       struct rb_node *prev;
+
+       prev = rb_prev(&em->rb_node);
+       if (!prev)
+               return NULL;
+       return container_of(prev, struct extent_map, rb_node);
+}
+
 /* helper for btfs_get_extent.  Given an existing extent in the tree,
+ * the existing extent is the nearest extent to map_start,
  * and an extent that you want to insert, deal with overlap and insert
- * the new extent into the tree.
+ * the best fitted new extent into the tree.
  */
 static int merge_extent_mapping(struct extent_map_tree *em_tree,
                                struct extent_map *existing,
                                struct extent_map *em,
                                u64 map_start)
 {
+       struct extent_map *prev;
+       struct extent_map *next;
+       u64 start;
+       u64 end;
        u64 start_diff;
 
        BUG_ON(map_start < em->start || map_start >= extent_map_end(em));
-       start_diff = map_start - em->start;
-       em->start = map_start;
-       em->len = existing->start - em->start;
+
+       if (existing->start > map_start) {
+               next = existing;
+               prev = prev_extent_map(next);
+       } else {
+               prev = existing;
+               next = next_extent_map(prev);
+       }
+
+       start = prev ? extent_map_end(prev) : em->start;
+       start = max_t(u64, start, em->start);
+       end = next ? next->start : extent_map_end(em);
+       end = min_t(u64, end, extent_map_end(em));
+       start_diff = start - em->start;
+       em->start = start;
+       em->len = end - start;
        if (em->block_start < EXTENT_MAP_LAST_BYTE &&
            !test_bit(EXTENT_FLAG_COMPRESSED, &em->flags)) {
                em->block_start += start_diff;
@@ -6333,7 +6431,7 @@ again:
                              struct btrfs_file_extent_item);
        /* are we inside the extent that was found? */
        btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]);
-       found_type = btrfs_key_type(&found_key);
+       found_type = found_key.type;
        if (found_key.objectid != objectid ||
            found_type != BTRFS_EXTENT_DATA_KEY) {
                /*
@@ -6482,25 +6580,21 @@ insert:
 
                ret = 0;
 
-               existing = lookup_extent_mapping(em_tree, start, len);
-               if (existing && (existing->start > start ||
-                   existing->start + existing->len <= start)) {
+               existing = search_extent_mapping(em_tree, start, len);
+               /*
+                * existing will always be non-NULL, since there must be
+                * extent causing the -EEXIST.
+                */
+               if (start >= extent_map_end(existing) ||
+                   start <= existing->start) {
+                       /*
+                        * The existing extent map is the one nearest to
+                        * the [start, start + len) range which overlaps
+                        */
+                       err = merge_extent_mapping(em_tree, existing,
+                                                  em, start);
                        free_extent_map(existing);
-                       existing = NULL;
-               }
-               if (!existing) {
-                       existing = lookup_extent_mapping(em_tree, em->start,
-                                                        em->len);
-                       if (existing) {
-                               err = merge_extent_mapping(em_tree, existing,
-                                                          em, start);
-                               free_extent_map(existing);
-                               if (err) {
-                                       free_extent_map(em);
-                                       em = NULL;
-                               }
-                       } else {
-                               err = -EIO;
+                       if (err) {
                                free_extent_map(em);
                                em = NULL;
                        }
@@ -7112,8 +7206,10 @@ static int btrfs_get_blocks_direct(struct inode *inode, sector_t iblock,
                                                       block_start, len,
                                                       orig_block_len,
                                                       ram_bytes, type);
-                               if (IS_ERR(em))
+                               if (IS_ERR(em)) {
+                                       ret = PTR_ERR(em);
                                        goto unlock_err;
+                               }
                        }
 
                        ret = btrfs_add_ordered_extent_dio(inode, start,
@@ -7188,45 +7284,277 @@ unlock_err:
        return ret;
 }
 
-static void btrfs_endio_direct_read(struct bio *bio, int err)
+static inline int submit_dio_repair_bio(struct inode *inode, struct bio *bio,
+                                       int rw, int mirror_num)
 {
-       struct btrfs_dio_private *dip = bio->bi_private;
-       struct bio_vec *bvec;
-       struct inode *inode = dip->inode;
        struct btrfs_root *root = BTRFS_I(inode)->root;
-       struct bio *dio_bio;
-       u32 *csums = (u32 *)dip->csum;
+       int ret;
+
+       BUG_ON(rw & REQ_WRITE);
+
+       bio_get(bio);
+
+       ret = btrfs_bio_wq_end_io(root->fs_info, bio,
+                                 BTRFS_WQ_ENDIO_DIO_REPAIR);
+       if (ret)
+               goto err;
+
+       ret = btrfs_map_bio(root, rw, bio, mirror_num, 0);
+err:
+       bio_put(bio);
+       return ret;
+}
+
+static int btrfs_check_dio_repairable(struct inode *inode,
+                                     struct bio *failed_bio,
+                                     struct io_failure_record *failrec,
+                                     int failed_mirror)
+{
+       int num_copies;
+
+       num_copies = btrfs_num_copies(BTRFS_I(inode)->root->fs_info,
+                                     failrec->logical, failrec->len);
+       if (num_copies == 1) {
+               /*
+                * we only have a single copy of the data, so don't bother with
+                * all the retry and error correction code that follows. no
+                * matter what the error is, it is very likely to persist.
+                */
+               pr_debug("Check DIO Repairable: cannot repair, num_copies=%d, next_mirror %d, failed_mirror %d\n",
+                        num_copies, failrec->this_mirror, failed_mirror);
+               return 0;
+       }
+
+       failrec->failed_mirror = failed_mirror;
+       failrec->this_mirror++;
+       if (failrec->this_mirror == failed_mirror)
+               failrec->this_mirror++;
+
+       if (failrec->this_mirror > num_copies) {
+               pr_debug("Check DIO Repairable: (fail) num_copies=%d, next_mirror %d, failed_mirror %d\n",
+                        num_copies, failrec->this_mirror, failed_mirror);
+               return 0;
+       }
+
+       return 1;
+}
+
+static int dio_read_error(struct inode *inode, struct bio *failed_bio,
+                         struct page *page, u64 start, u64 end,
+                         int failed_mirror, bio_end_io_t *repair_endio,
+                         void *repair_arg)
+{
+       struct io_failure_record *failrec;
+       struct bio *bio;
+       int isector;
+       int read_mode;
+       int ret;
+
+       BUG_ON(failed_bio->bi_rw & REQ_WRITE);
+
+       ret = btrfs_get_io_failure_record(inode, start, end, &failrec);
+       if (ret)
+               return ret;
+
+       ret = btrfs_check_dio_repairable(inode, failed_bio, failrec,
+                                        failed_mirror);
+       if (!ret) {
+               free_io_failure(inode, failrec);
+               return -EIO;
+       }
+
+       if (failed_bio->bi_vcnt > 1)
+               read_mode = READ_SYNC | REQ_FAILFAST_DEV;
+       else
+               read_mode = READ_SYNC;
+
+       isector = start - btrfs_io_bio(failed_bio)->logical;
+       isector >>= inode->i_sb->s_blocksize_bits;
+       bio = btrfs_create_repair_bio(inode, failed_bio, failrec, page,
+                                     0, isector, repair_endio, repair_arg);
+       if (!bio) {
+               free_io_failure(inode, failrec);
+               return -EIO;
+       }
+
+       btrfs_debug(BTRFS_I(inode)->root->fs_info,
+                   "Repair DIO Read Error: submitting new dio read[%#x] to this_mirror=%d, in_validation=%d\n",
+                   read_mode, failrec->this_mirror, failrec->in_validation);
+
+       ret = submit_dio_repair_bio(inode, bio, read_mode,
+                                   failrec->this_mirror);
+       if (ret) {
+               free_io_failure(inode, failrec);
+               bio_put(bio);
+       }
+
+       return ret;
+}
+
+struct btrfs_retry_complete {
+       struct completion done;
+       struct inode *inode;
+       u64 start;
+       int uptodate;
+};
+
+static void btrfs_retry_endio_nocsum(struct bio *bio, int err)
+{
+       struct btrfs_retry_complete *done = bio->bi_private;
+       struct bio_vec *bvec;
+       int i;
+
+       if (err)
+               goto end;
+
+       done->uptodate = 1;
+       bio_for_each_segment_all(bvec, bio, i)
+               clean_io_failure(done->inode, done->start, bvec->bv_page, 0);
+end:
+       complete(&done->done);
+       bio_put(bio);
+}
+
+static int __btrfs_correct_data_nocsum(struct inode *inode,
+                                      struct btrfs_io_bio *io_bio)
+{
+       struct bio_vec *bvec;
+       struct btrfs_retry_complete done;
        u64 start;
        int i;
+       int ret;
+
+       start = io_bio->logical;
+       done.inode = inode;
+
+       bio_for_each_segment_all(bvec, &io_bio->bio, i) {
+try_again:
+               done.uptodate = 0;
+               done.start = start;
+               init_completion(&done.done);
+
+               ret = dio_read_error(inode, &io_bio->bio, bvec->bv_page, start,
+                                    start + bvec->bv_len - 1,
+                                    io_bio->mirror_num,
+                                    btrfs_retry_endio_nocsum, &done);
+               if (ret)
+                       return ret;
+
+               wait_for_completion(&done.done);
+
+               if (!done.uptodate) {
+                       /* We might have another mirror, so try again */
+                       goto try_again;
+               }
+
+               start += bvec->bv_len;
+       }
+
+       return 0;
+}
+
+static void btrfs_retry_endio(struct bio *bio, int err)
+{
+       struct btrfs_retry_complete *done = bio->bi_private;
+       struct btrfs_io_bio *io_bio = btrfs_io_bio(bio);
+       struct bio_vec *bvec;
+       int uptodate;
+       int ret;
+       int i;
+
+       if (err)
+               goto end;
 
-       start = dip->logical_offset;
+       uptodate = 1;
        bio_for_each_segment_all(bvec, bio, i) {
-               if (!(BTRFS_I(inode)->flags & BTRFS_INODE_NODATASUM)) {
-                       struct page *page = bvec->bv_page;
-                       char *kaddr;
-                       u32 csum = ~(u32)0;
-                       unsigned long flags;
-
-                       local_irq_save(flags);
-                       kaddr = kmap_atomic(page);
-                       csum = btrfs_csum_data(kaddr + bvec->bv_offset,
-                                              csum, bvec->bv_len);
-                       btrfs_csum_final(csum, (char *)&csum);
-                       kunmap_atomic(kaddr);
-                       local_irq_restore(flags);
-
-                       flush_dcache_page(bvec->bv_page);
-                       if (csum != csums[i]) {
-                               btrfs_err(root->fs_info, "csum failed ino %llu off %llu csum %u expected csum %u",
-                                         btrfs_ino(inode), start, csum,
-                                         csums[i]);
-                               err = -EIO;
-                       }
+               ret = __readpage_endio_check(done->inode, io_bio, i,
+                                            bvec->bv_page, 0,
+                                            done->start, bvec->bv_len);
+               if (!ret)
+                       clean_io_failure(done->inode, done->start,
+                                        bvec->bv_page, 0);
+               else
+                       uptodate = 0;
+       }
+
+       done->uptodate = uptodate;
+end:
+       complete(&done->done);
+       bio_put(bio);
+}
+
+static int __btrfs_subio_endio_read(struct inode *inode,
+                                   struct btrfs_io_bio *io_bio, int err)
+{
+       struct bio_vec *bvec;
+       struct btrfs_retry_complete done;
+       u64 start;
+       u64 offset = 0;
+       int i;
+       int ret;
+
+       err = 0;
+       start = io_bio->logical;
+       done.inode = inode;
+
+       bio_for_each_segment_all(bvec, &io_bio->bio, i) {
+               ret = __readpage_endio_check(inode, io_bio, i, bvec->bv_page,
+                                            0, start, bvec->bv_len);
+               if (likely(!ret))
+                       goto next;
+try_again:
+               done.uptodate = 0;
+               done.start = start;
+               init_completion(&done.done);
+
+               ret = dio_read_error(inode, &io_bio->bio, bvec->bv_page, start,
+                                    start + bvec->bv_len - 1,
+                                    io_bio->mirror_num,
+                                    btrfs_retry_endio, &done);
+               if (ret) {
+                       err = ret;
+                       goto next;
                }
 
+               wait_for_completion(&done.done);
+
+               if (!done.uptodate) {
+                       /* We might have another mirror, so try again */
+                       goto try_again;
+               }
+next:
+               offset += bvec->bv_len;
                start += bvec->bv_len;
        }
 
+       return err;
+}
+
+static int btrfs_subio_endio_read(struct inode *inode,
+                                 struct btrfs_io_bio *io_bio, int err)
+{
+       bool skip_csum = BTRFS_I(inode)->flags & BTRFS_INODE_NODATASUM;
+
+       if (skip_csum) {
+               if (unlikely(err))
+                       return __btrfs_correct_data_nocsum(inode, io_bio);
+               else
+                       return 0;
+       } else {
+               return __btrfs_subio_endio_read(inode, io_bio, err);
+       }
+}
+
+static void btrfs_endio_direct_read(struct bio *bio, int err)
+{
+       struct btrfs_dio_private *dip = bio->bi_private;
+       struct inode *inode = dip->inode;
+       struct bio *dio_bio;
+       struct btrfs_io_bio *io_bio = btrfs_io_bio(bio);
+
+       if (dip->flags & BTRFS_DIO_ORIG_BIO_SUBMITTED)
+               err = btrfs_subio_endio_read(inode, io_bio, err);
+
        unlock_extent(&BTRFS_I(inode)->io_tree, dip->logical_offset,
                      dip->logical_offset + dip->bytes - 1);
        dio_bio = dip->dio_bio;
@@ -7237,6 +7565,9 @@ static void btrfs_endio_direct_read(struct bio *bio, int err)
        if (err)
                clear_bit(BIO_UPTODATE, &dio_bio->bi_flags);
        dio_end_io(dio_bio, err);
+
+       if (io_bio->end_io)
+               io_bio->end_io(io_bio, err);
        bio_put(bio);
 }
 
@@ -7302,12 +7633,17 @@ static void btrfs_end_dio_bio(struct bio *bio, int err)
 {
        struct btrfs_dio_private *dip = bio->bi_private;
 
+       if (err)
+               btrfs_warn(BTRFS_I(dip->inode)->root->fs_info,
+                          "direct IO failed ino %llu rw %lu sector %#Lx len %u err no %d",
+                          btrfs_ino(dip->inode), bio->bi_rw,
+                          (unsigned long long)bio->bi_iter.bi_sector,
+                          bio->bi_iter.bi_size, err);
+
+       if (dip->subio_endio)
+               err = dip->subio_endio(dip->inode, btrfs_io_bio(bio), err);
+
        if (err) {
-               btrfs_err(BTRFS_I(dip->inode)->root->fs_info,
-                         "direct IO failed ino %llu rw %lu sector %#Lx len %u err no %d",
-                     btrfs_ino(dip->inode), bio->bi_rw,
-                     (unsigned long long)bio->bi_iter.bi_sector,
-                     bio->bi_iter.bi_size, err);
                dip->errors = 1;
 
                /*
@@ -7338,6 +7674,38 @@ static struct bio *btrfs_dio_bio_alloc(struct block_device *bdev,
        return btrfs_bio_alloc(bdev, first_sector, nr_vecs, gfp_flags);
 }
 
+static inline int btrfs_lookup_and_bind_dio_csum(struct btrfs_root *root,
+                                                struct inode *inode,
+                                                struct btrfs_dio_private *dip,
+                                                struct bio *bio,
+                                                u64 file_offset)
+{
+       struct btrfs_io_bio *io_bio = btrfs_io_bio(bio);
+       struct btrfs_io_bio *orig_io_bio = btrfs_io_bio(dip->orig_bio);
+       int ret;
+
+       /*
+        * We load all the csum data we need when we submit
+        * the first bio to reduce the csum tree search and
+        * contention.
+        */
+       if (dip->logical_offset == file_offset) {
+               ret = btrfs_lookup_bio_sums_dio(root, inode, dip->orig_bio,
+                                               file_offset);
+               if (ret)
+                       return ret;
+       }
+
+       if (bio == dip->orig_bio)
+               return 0;
+
+       file_offset -= dip->logical_offset;
+       file_offset >>= inode->i_sb->s_blocksize_bits;
+       io_bio->csum = (u8 *)(((u32 *)orig_io_bio->csum) + file_offset);
+
+       return 0;
+}
+
 static inline int __btrfs_submit_dio_bio(struct bio *bio, struct inode *inode,
                                         int rw, u64 file_offset, int skip_sum,
                                         int async_submit)
@@ -7353,7 +7721,8 @@ static inline int __btrfs_submit_dio_bio(struct bio *bio, struct inode *inode,
        bio_get(bio);
 
        if (!write) {
-               ret = btrfs_bio_wq_end_io(root->fs_info, bio, 0);
+               ret = btrfs_bio_wq_end_io(root->fs_info, bio,
+                               BTRFS_WQ_ENDIO_DATA);
                if (ret)
                        goto err;
        }
@@ -7376,13 +7745,12 @@ static inline int __btrfs_submit_dio_bio(struct bio *bio, struct inode *inode,
                ret = btrfs_csum_one_bio(root, inode, bio, file_offset, 1);
                if (ret)
                        goto err;
-       } else if (!skip_sum) {
-               ret = btrfs_lookup_bio_sums_dio(root, inode, dip, bio,
-                                               file_offset);
+       } else {
+               ret = btrfs_lookup_and_bind_dio_csum(root, inode, dip, bio,
+                                                    file_offset);
                if (ret)
                        goto err;
        }
-
 map:
        ret = btrfs_map_bio(root, rw, bio, 0, async_submit);
 err:
@@ -7403,7 +7771,7 @@ static int btrfs_submit_direct_hook(int rw, struct btrfs_dio_private *dip,
        u64 submit_len = 0;
        u64 map_length;
        int nr_pages = 0;
-       int ret = 0;
+       int ret;
        int async_submit = 0;
 
        map_length = orig_bio->bi_iter.bi_size;
@@ -7414,6 +7782,7 @@ static int btrfs_submit_direct_hook(int rw, struct btrfs_dio_private *dip,
 
        if (map_length >= orig_bio->bi_iter.bi_size) {
                bio = orig_bio;
+               dip->flags |= BTRFS_DIO_ORIG_BIO_SUBMITTED;
                goto submit;
        }
 
@@ -7430,12 +7799,13 @@ static int btrfs_submit_direct_hook(int rw, struct btrfs_dio_private *dip,
 
        bio->bi_private = dip;
        bio->bi_end_io = btrfs_end_dio_bio;
+       btrfs_io_bio(bio)->logical = file_offset;
        atomic_inc(&dip->pending_bios);
 
        while (bvec <= (orig_bio->bi_io_vec + orig_bio->bi_vcnt - 1)) {
-               if (unlikely(map_length < submit_len + bvec->bv_len ||
+               if (map_length < submit_len + bvec->bv_len ||
                    bio_add_page(bio, bvec->bv_page, bvec->bv_len,
-                                bvec->bv_offset) < bvec->bv_len)) {
+                                bvec->bv_offset) < bvec->bv_len) {
                        /*
                         * inc the count before we submit the bio so
                         * we know the end IO handler won't happen before
@@ -7464,6 +7834,7 @@ static int btrfs_submit_direct_hook(int rw, struct btrfs_dio_private *dip,
                                goto out_err;
                        bio->bi_private = dip;
                        bio->bi_end_io = btrfs_end_dio_bio;
+                       btrfs_io_bio(bio)->logical = file_offset;
 
                        map_length = orig_bio->bi_iter.bi_size;
                        ret = btrfs_map_block(root->fs_info, rw,
@@ -7507,11 +7878,10 @@ static void btrfs_submit_direct(int rw, struct bio *dio_bio,
        struct btrfs_root *root = BTRFS_I(inode)->root;
        struct btrfs_dio_private *dip;
        struct bio *io_bio;
+       struct btrfs_io_bio *btrfs_bio;
        int skip_sum;
-       int sum_len;
        int write = rw & REQ_WRITE;
        int ret = 0;
-       u16 csum_size;
 
        skip_sum = BTRFS_I(inode)->flags & BTRFS_INODE_NODATASUM;
 
@@ -7521,16 +7891,7 @@ static void btrfs_submit_direct(int rw, struct bio *dio_bio,
                goto free_ordered;
        }
 
-       if (!skip_sum && !write) {
-               csum_size = btrfs_super_csum_size(root->fs_info->super_copy);
-               sum_len = dio_bio->bi_iter.bi_size >>
-                       inode->i_sb->s_blocksize_bits;
-               sum_len *= csum_size;
-       } else {
-               sum_len = 0;
-       }
-
-       dip = kmalloc(sizeof(*dip) + sum_len, GFP_NOFS);
+       dip = kzalloc(sizeof(*dip), GFP_NOFS);
        if (!dip) {
                ret = -ENOMEM;
                goto free_io_bio;
@@ -7542,20 +7903,25 @@ static void btrfs_submit_direct(int rw, struct bio *dio_bio,
        dip->bytes = dio_bio->bi_iter.bi_size;
        dip->disk_bytenr = (u64)dio_bio->bi_iter.bi_sector << 9;
        io_bio->bi_private = dip;
-       dip->errors = 0;
        dip->orig_bio = io_bio;
        dip->dio_bio = dio_bio;
        atomic_set(&dip->pending_bios, 0);
+       btrfs_bio = btrfs_io_bio(io_bio);
+       btrfs_bio->logical = file_offset;
 
-       if (write)
+       if (write) {
                io_bio->bi_end_io = btrfs_endio_direct_write;
-       else
+       } else {
                io_bio->bi_end_io = btrfs_endio_direct_read;
+               dip->subio_endio = btrfs_subio_endio_read;
+       }
 
        ret = btrfs_submit_direct_hook(rw, dip, skip_sum);
        if (!ret)
                return;
 
+       if (btrfs_bio->end_io)
+               btrfs_bio->end_io(btrfs_bio, ret);
 free_io_bio:
        bio_put(io_bio);
 
@@ -7652,8 +8018,8 @@ static ssize_t btrfs_direct_IO(int rw, struct kiocb *iocb,
                ret = btrfs_delalloc_reserve_space(inode, count);
                if (ret)
                        goto out;
-       } else if (unlikely(test_bit(BTRFS_INODE_READDIO_NEED_LOCK,
-                                    &BTRFS_I(inode)->runtime_flags))) {
+       } else if (test_bit(BTRFS_INODE_READDIO_NEED_LOCK,
+                                    &BTRFS_I(inode)->runtime_flags)) {
                inode_dio_done(inode);
                flags = DIO_LOCKING | DIO_SKIP_HOLES;
                wakeup = false;
@@ -8173,6 +8539,7 @@ struct inode *btrfs_alloc_inode(struct super_block *sb)
        ei->last_sub_trans = 0;
        ei->logged_trans = 0;
        ei->delalloc_bytes = 0;
+       ei->defrag_bytes = 0;
        ei->disk_i_size = 0;
        ei->flags = 0;
        ei->csum_bytes = 0;
@@ -8231,6 +8598,7 @@ void btrfs_destroy_inode(struct inode *inode)
        WARN_ON(BTRFS_I(inode)->reserved_extents);
        WARN_ON(BTRFS_I(inode)->delalloc_bytes);
        WARN_ON(BTRFS_I(inode)->csum_bytes);
+       WARN_ON(BTRFS_I(inode)->defrag_bytes);
 
        /*
         * This can happen where we create an inode, but somebody else also
@@ -8646,7 +9014,7 @@ static int __start_delalloc_inodes(struct btrfs_root *root, int delay_iput,
                spin_unlock(&root->delalloc_lock);
 
                work = btrfs_alloc_delalloc_work(inode, 0, delay_iput);
-               if (unlikely(!work)) {
+               if (!work) {
                        if (delay_iput)
                                btrfs_add_delayed_iput(inode);
                        else
@@ -8832,7 +9200,7 @@ static int btrfs_symlink(struct inode *dir, struct dentry *dentry,
        }
        key.objectid = btrfs_ino(inode);
        key.offset = 0;
-       btrfs_set_key_type(&key, BTRFS_EXTENT_DATA_KEY);
+       key.type = BTRFS_EXTENT_DATA_KEY;
        datasize = btrfs_file_extent_calc_inline_size(name_len);
        err = btrfs_insert_empty_item(trans, root, path, &key,
                                      datasize);
index 8a8e29878c34283812f8d990c2432cff94bbab2a..0fe1aa047f15e46aa323316a4a9c31e841c5b664 100644 (file)
@@ -332,6 +332,9 @@ static int btrfs_ioctl_setflags(struct file *file, void __user *arg)
                        goto out_drop;
 
        } else {
+               ret = btrfs_set_prop(inode, "btrfs.compression", NULL, 0, 0);
+               if (ret && ret != -ENODATA)
+                       goto out_drop;
                ip->flags &= ~(BTRFS_INODE_COMPRESS | BTRFS_INODE_NOCOMPRESS);
        }
 
@@ -477,8 +480,7 @@ static noinline int create_subvol(struct inode *dir,
        if (ret)
                goto fail;
 
-       leaf = btrfs_alloc_free_block(trans, root, root->leafsize,
-                                     0, objectid, NULL, 0, 0, 0);
+       leaf = btrfs_alloc_tree_block(trans, root, 0, objectid, NULL, 0, 0, 0);
        if (IS_ERR(leaf)) {
                ret = PTR_ERR(leaf);
                goto fail;
@@ -503,7 +505,7 @@ static noinline int create_subvol(struct inode *dir,
        btrfs_set_stack_inode_generation(inode_item, 1);
        btrfs_set_stack_inode_size(inode_item, 3);
        btrfs_set_stack_inode_nlink(inode_item, 1);
-       btrfs_set_stack_inode_nbytes(inode_item, root->leafsize);
+       btrfs_set_stack_inode_nbytes(inode_item, root->nodesize);
        btrfs_set_stack_inode_mode(inode_item, S_IFDIR | 0755);
 
        btrfs_set_root_flags(&root_item, 0);
@@ -535,7 +537,7 @@ static noinline int create_subvol(struct inode *dir,
 
        key.objectid = objectid;
        key.offset = 0;
-       btrfs_set_key_type(&key, BTRFS_ROOT_ITEM_KEY);
+       key.type = BTRFS_ROOT_ITEM_KEY;
        ret = btrfs_insert_root(trans, root->fs_info->tree_root, &key,
                                &root_item);
        if (ret)
@@ -882,7 +884,7 @@ out_unlock:
  * file you want to defrag, we return 0 to let you know to skip this
  * part of the file
  */
-static int check_defrag_in_cache(struct inode *inode, u64 offset, int thresh)
+static int check_defrag_in_cache(struct inode *inode, u64 offset, u32 thresh)
 {
        struct extent_io_tree *io_tree = &BTRFS_I(inode)->io_tree;
        struct extent_map *em = NULL;
@@ -917,7 +919,7 @@ static int check_defrag_in_cache(struct inode *inode, u64 offset, int thresh)
  */
 static int find_new_extents(struct btrfs_root *root,
                            struct inode *inode, u64 newer_than,
-                           u64 *off, int thresh)
+                           u64 *off, u32 thresh)
 {
        struct btrfs_path *path;
        struct btrfs_key min_key;
@@ -936,12 +938,9 @@ static int find_new_extents(struct btrfs_root *root,
        min_key.offset = *off;
 
        while (1) {
-               path->keep_locks = 1;
                ret = btrfs_search_forward(root, &min_key, path, newer_than);
                if (ret != 0)
                        goto none;
-               path->keep_locks = 0;
-               btrfs_unlock_up_safe(path, 1);
 process_slot:
                if (min_key.objectid != ino)
                        goto none;
@@ -1029,7 +1028,7 @@ static bool defrag_check_next_extent(struct inode *inode, struct extent_map *em)
        return ret;
 }
 
-static int should_defrag_range(struct inode *inode, u64 start, int thresh,
+static int should_defrag_range(struct inode *inode, u64 start, u32 thresh,
                               u64 *last_len, u64 *skip, u64 *defrag_end,
                               int compress)
 {
@@ -1259,7 +1258,7 @@ int btrfs_defrag_file(struct inode *inode, struct file *file,
        int ret;
        int defrag_count = 0;
        int compress_type = BTRFS_COMPRESS_ZLIB;
-       int extent_thresh = range->extent_thresh;
+       u32 extent_thresh = range->extent_thresh;
        unsigned long max_cluster = (256 * 1024) >> PAGE_CACHE_SHIFT;
        unsigned long cluster = max_cluster;
        u64 new_align = ~((u64)128 * 1024 - 1);
@@ -1335,8 +1334,7 @@ int btrfs_defrag_file(struct inode *inode, struct file *file,
                inode->i_mapping->writeback_index = i;
 
        while (i <= last_index && defrag_count < max_to_defrag &&
-              (i < (i_size_read(inode) + PAGE_CACHE_SIZE - 1) >>
-               PAGE_CACHE_SHIFT)) {
+              (i < DIV_ROUND_UP(i_size_read(inode), PAGE_CACHE_SIZE))) {
                /*
                 * make sure we stop running if someone unmounts
                 * the FS
@@ -1359,7 +1357,7 @@ int btrfs_defrag_file(struct inode *inode, struct file *file,
                         * the should_defrag function tells us how much to skip
                         * bump our counter by the suggested amount
                         */
-                       next = (skip + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
+                       next = DIV_ROUND_UP(skip, PAGE_CACHE_SIZE);
                        i = max(i + 1, next);
                        continue;
                }
@@ -1554,7 +1552,7 @@ static noinline int btrfs_ioctl_resize(struct file *file,
                goto out_free;
        }
 
-       old_size = device->total_bytes;
+       old_size = btrfs_device_get_total_bytes(device);
 
        if (mod < 0) {
                if (new_size > old_size) {
@@ -2089,8 +2087,6 @@ static noinline int search_ioctl(struct inode *inode,
        key.type = sk->min_type;
        key.offset = sk->min_offset;
 
-       path->keep_locks = 1;
-
        while (1) {
                ret = btrfs_search_forward(root, &key, path, sk->min_transid);
                if (ret != 0) {
@@ -2423,9 +2419,7 @@ static noinline int btrfs_ioctl_snap_destroy(struct file *file,
                goto out_dput;
        }
 
-       err = d_invalidate(dentry);
-       if (err)
-               goto out_unlock;
+       d_invalidate(dentry);
 
        down_write(&root->fs_info->subvol_sem);
 
@@ -2510,7 +2504,6 @@ out_release:
        btrfs_subvolume_release_metadata(root, &block_rsv, qgroup_reserved);
 out_up_write:
        up_write(&root->fs_info->subvol_sem);
-out_unlock:
        if (err) {
                spin_lock(&dest->root_item_lock);
                root_flags = btrfs_root_flags(&dest->root_item);
@@ -2526,9 +2519,9 @@ out_unlock:
                ASSERT(dest->send_in_progress == 0);
 
                /* the last ref */
-               if (dest->cache_inode) {
-                       iput(dest->cache_inode);
-                       dest->cache_inode = NULL;
+               if (dest->ino_cache_inode) {
+                       iput(dest->ino_cache_inode);
+                       dest->ino_cache_inode = NULL;
                }
        }
 out_dput:
@@ -2634,6 +2627,9 @@ static long btrfs_ioctl_add_dev(struct btrfs_root *root, void __user *arg)
        vol_args->name[BTRFS_PATH_NAME_MAX] = '\0';
        ret = btrfs_init_new_device(root, vol_args->name);
 
+       if (!ret)
+               btrfs_info(root->fs_info, "disk added %s",vol_args->name);
+
        kfree(vol_args);
 out:
        mutex_unlock(&root->fs_info->volume_mutex);
@@ -2673,6 +2669,9 @@ static long btrfs_ioctl_rm_dev(struct file *file, void __user *arg)
        mutex_unlock(&root->fs_info->volume_mutex);
        atomic_set(&root->fs_info->mutually_exclusive_operation_running, 0);
 
+       if (!ret)
+               btrfs_info(root->fs_info, "disk deleted %s",vol_args->name);
+
 out:
        kfree(vol_args);
 err_drop:
@@ -2737,8 +2736,8 @@ static long btrfs_ioctl_dev_info(struct btrfs_root *root, void __user *arg)
        }
 
        di_args->devid = dev->devid;
-       di_args->bytes_used = dev->bytes_used;
-       di_args->total_bytes = dev->total_bytes;
+       di_args->bytes_used = btrfs_device_get_bytes_used(dev);
+       di_args->total_bytes = btrfs_device_get_total_bytes(dev);
        memcpy(di_args->uuid, dev->uuid, sizeof(di_args->uuid));
        if (dev->name) {
                struct rcu_string *name;
@@ -3164,7 +3163,7 @@ static void clone_update_extent_map(struct inode *inode,
                                        em->start + em->len - 1, 0);
        }
 
-       if (unlikely(ret))
+       if (ret)
                set_bit(BTRFS_INODE_NEEDS_FULL_SYNC,
                        &BTRFS_I(inode)->runtime_flags);
 }
@@ -3199,7 +3198,7 @@ static int btrfs_clone(struct inode *src, struct inode *inode,
        u64 last_dest_end = destoff;
 
        ret = -ENOMEM;
-       buf = vmalloc(btrfs_level_size(root, 0));
+       buf = vmalloc(root->nodesize);
        if (!buf)
                return ret;
 
@@ -3252,11 +3251,11 @@ process_slot:
                slot = path->slots[0];
 
                btrfs_item_key_to_cpu(leaf, &key, slot);
-               if (btrfs_key_type(&key) > BTRFS_EXTENT_DATA_KEY ||
+               if (key.type > BTRFS_EXTENT_DATA_KEY ||
                    key.objectid != btrfs_ino(src))
                        break;
 
-               if (btrfs_key_type(&key) == BTRFS_EXTENT_DATA_KEY) {
+               if (key.type == BTRFS_EXTENT_DATA_KEY) {
                        struct btrfs_file_extent_item *extent;
                        int type;
                        u32 size;
@@ -5283,6 +5282,12 @@ long btrfs_ioctl(struct file *file, unsigned int
                if (ret)
                        return ret;
                ret = btrfs_sync_fs(file->f_dentry->d_sb, 1);
+               /*
+                * The transaction thread may want to do more work,
+                * namely it pokes the cleaner ktread that will start
+                * processing uncleaned subvols.
+                */
+               wake_up_process(root->fs_info->transaction_kthread);
                return ret;
        }
        case BTRFS_IOC_START_SYNC:
index dfad8514f0daa5054378ebae0d739c9a89dd3963..78285f30909edd09f19cc6eb48985d47eed3c565 100644 (file)
@@ -266,8 +266,7 @@ static int lzo_decompress_biovec(struct list_head *ws,
        char *data_in;
        unsigned long page_in_index = 0;
        unsigned long page_out_index = 0;
-       unsigned long total_pages_in = (srclen + PAGE_CACHE_SIZE - 1) /
-                                       PAGE_CACHE_SIZE;
+       unsigned long total_pages_in = DIV_ROUND_UP(srclen, PAGE_CACHE_SIZE);
        unsigned long buf_start;
        unsigned long buf_offset = 0;
        unsigned long bytes;
index 65793edb38ca881a3f82f49101bc4b079574ed4c..47767d5b8f0bacb10613941dcd90259d097ee075 100644 (file)
@@ -27,7 +27,7 @@ int btrfs_insert_orphan_item(struct btrfs_trans_handle *trans,
        int ret = 0;
 
        key.objectid = BTRFS_ORPHAN_OBJECTID;
-       btrfs_set_key_type(&key, BTRFS_ORPHAN_ITEM_KEY);
+       key.type = BTRFS_ORPHAN_ITEM_KEY;
        key.offset = offset;
 
        path = btrfs_alloc_path();
@@ -48,7 +48,7 @@ int btrfs_del_orphan_item(struct btrfs_trans_handle *trans,
        int ret = 0;
 
        key.objectid = BTRFS_ORPHAN_OBJECTID;
-       btrfs_set_key_type(&key, BTRFS_ORPHAN_ITEM_KEY);
+       key.type = BTRFS_ORPHAN_ITEM_KEY;
        key.offset = offset;
 
        path = btrfs_alloc_path();
index 9626b4ad3b9a5a82812c7ced61ed9ce47fd995fb..647ab12fdf5dbcb397e93ee8a958968b2d83ab1e 100644 (file)
@@ -195,7 +195,7 @@ void btrfs_print_leaf(struct btrfs_root *root, struct extent_buffer *l)
        for (i = 0 ; i < nr ; i++) {
                item = btrfs_item_nr(i);
                btrfs_item_key_to_cpu(l, &key, i);
-               type = btrfs_key_type(&key);
+               type = key.type;
                printk(KERN_INFO "\titem %d key (%llu %u %llu) itemoff %d "
                       "itemsize %d\n",
                        i, key.objectid, type, key.offset,
@@ -336,7 +336,6 @@ void btrfs_print_tree(struct btrfs_root *root, struct extent_buffer *c)
        for (i = 0; i < nr; i++) {
                struct extent_buffer *next = read_tree_block(root,
                                        btrfs_node_blockptr(c, i),
-                                       btrfs_level_size(root, level - 1),
                                        btrfs_node_ptr_generation(c, i));
                if (btrfs_is_leaf(next) &&
                   level != 1)
index ded5c601d9162a7699a3fa4802a8c9df9bd37722..48b60dbf807fd170593b2e0c7d0a3d1a36f26f58 100644 (file)
@@ -539,10 +539,9 @@ static int add_qgroup_item(struct btrfs_trans_handle *trans,
        struct extent_buffer *leaf;
        struct btrfs_key key;
 
-#ifdef CONFIG_BTRFS_FS_RUN_SANITY_TESTS
-       if (unlikely(test_bit(BTRFS_ROOT_DUMMY_ROOT, &quota_root->state)))
+       if (btrfs_test_is_dummy_root(quota_root))
                return 0;
-#endif
+
        path = btrfs_alloc_path();
        if (!path)
                return -ENOMEM;
@@ -551,9 +550,15 @@ static int add_qgroup_item(struct btrfs_trans_handle *trans,
        key.type = BTRFS_QGROUP_INFO_KEY;
        key.offset = qgroupid;
 
+       /*
+        * Avoid a transaction abort by catching -EEXIST here. In that
+        * case, we proceed by re-initializing the existing structure
+        * on disk.
+        */
+
        ret = btrfs_insert_empty_item(trans, quota_root, path, &key,
                                      sizeof(*qgroup_info));
-       if (ret)
+       if (ret && ret != -EEXIST)
                goto out;
 
        leaf = path->nodes[0];
@@ -572,7 +577,7 @@ static int add_qgroup_item(struct btrfs_trans_handle *trans,
        key.type = BTRFS_QGROUP_LIMIT_KEY;
        ret = btrfs_insert_empty_item(trans, quota_root, path, &key,
                                      sizeof(*qgroup_limit));
-       if (ret)
+       if (ret && ret != -EEXIST)
                goto out;
 
        leaf = path->nodes[0];
@@ -692,10 +697,9 @@ static int update_qgroup_info_item(struct btrfs_trans_handle *trans,
        int ret;
        int slot;
 
-#ifdef CONFIG_BTRFS_FS_RUN_SANITY_TESTS
-       if (unlikely(test_bit(BTRFS_ROOT_DUMMY_ROOT, &root->state)))
+       if (btrfs_test_is_dummy_root(root))
                return 0;
-#endif
+
        key.objectid = 0;
        key.type = BTRFS_QGROUP_INFO_KEY;
        key.offset = qgroup->qgroupid;
@@ -1335,6 +1339,8 @@ int btrfs_qgroup_record_ref(struct btrfs_trans_handle *trans,
        INIT_LIST_HEAD(&oper->elem.list);
        oper->elem.seq = 0;
 
+       trace_btrfs_qgroup_record_ref(oper);
+
        if (type == BTRFS_QGROUP_OPER_SUB_SUBTREE) {
                /*
                 * If any operation for this bytenr/ref_root combo
@@ -2077,6 +2083,8 @@ static int btrfs_qgroup_account(struct btrfs_trans_handle *trans,
 
        ASSERT(is_fstree(oper->ref_root));
 
+       trace_btrfs_qgroup_account(oper);
+
        switch (oper->type) {
        case BTRFS_QGROUP_OPER_ADD_EXCL:
        case BTRFS_QGROUP_OPER_SUB_EXCL:
@@ -2237,7 +2245,6 @@ int btrfs_qgroup_inherit(struct btrfs_trans_handle *trans,
        if (srcid) {
                struct btrfs_root *srcroot;
                struct btrfs_key srckey;
-               int srcroot_level;
 
                srckey.objectid = srcid;
                srckey.type = BTRFS_ROOT_ITEM_KEY;
@@ -2249,8 +2256,7 @@ int btrfs_qgroup_inherit(struct btrfs_trans_handle *trans,
                }
 
                rcu_read_lock();
-               srcroot_level = btrfs_header_level(srcroot->node);
-               level_size = btrfs_level_size(srcroot, srcroot_level);
+               level_size = srcroot->nodesize;
                rcu_read_unlock();
        }
 
@@ -2566,7 +2572,7 @@ qgroup_rescan_leaf(struct btrfs_fs_info *fs_info, struct btrfs_path *path,
                    found.type != BTRFS_METADATA_ITEM_KEY)
                        continue;
                if (found.type == BTRFS_METADATA_ITEM_KEY)
-                       num_bytes = fs_info->extent_root->leafsize;
+                       num_bytes = fs_info->extent_root->nodesize;
                else
                        num_bytes = found.offset;
 
index 0a6b6e4bcbb97a8af56ad6a58aef9f514c3b1132..6a41631cb95988c89e23ffdcb6bdc2466c065b2d 100644 (file)
@@ -912,7 +912,7 @@ static struct page *page_in_rbio(struct btrfs_raid_bio *rbio,
 static unsigned long rbio_nr_pages(unsigned long stripe_len, int nr_stripes)
 {
        unsigned long nr = stripe_len * nr_stripes;
-       return (nr + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
+       return DIV_ROUND_UP(nr, PAGE_CACHE_SIZE);
 }
 
 /*
@@ -1442,7 +1442,7 @@ static int raid56_rmw_stripe(struct btrfs_raid_bio *rbio)
        struct btrfs_bio *bbio = rbio->bbio;
        struct bio_list bio_list;
        int ret;
-       int nr_pages = (rbio->stripe_len + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
+       int nr_pages = DIV_ROUND_UP(rbio->stripe_len, PAGE_CACHE_SIZE);
        int pagenr;
        int stripe;
        struct bio *bio;
@@ -1725,7 +1725,7 @@ static void __raid_recover_end_io(struct btrfs_raid_bio *rbio)
        int pagenr, stripe;
        void **pointers;
        int faila = -1, failb = -1;
-       int nr_pages = (rbio->stripe_len + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
+       int nr_pages = DIV_ROUND_UP(rbio->stripe_len, PAGE_CACHE_SIZE);
        struct page *page;
        int err;
        int i;
@@ -1940,7 +1940,7 @@ static int __raid56_parity_recover(struct btrfs_raid_bio *rbio)
        struct btrfs_bio *bbio = rbio->bbio;
        struct bio_list bio_list;
        int ret;
-       int nr_pages = (rbio->stripe_len + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
+       int nr_pages = DIV_ROUND_UP(rbio->stripe_len, PAGE_CACHE_SIZE);
        int pagenr;
        int stripe;
        struct bio *bio;
index 20408c6b665ae94e03a152c94bb822bb87fdc63e..b63ae20618fb3f573d7917b088fa58a11f887293 100644 (file)
@@ -347,7 +347,7 @@ static struct reada_extent *reada_find_extent(struct btrfs_root *root,
        if (!re)
                return NULL;
 
-       blocksize = btrfs_level_size(root, level);
+       blocksize = root->nodesize;
        re->logical = logical;
        re->blocksize = blocksize;
        re->top = *top;
index 65245a07275baa37e8089e5e0901c924193d12da..74257d6436adda1b772d8658be41202093ef577a 100644 (file)
@@ -736,7 +736,8 @@ again:
                err = ret;
                goto out;
        }
-       BUG_ON(!ret || !path1->slots[0]);
+       ASSERT(ret);
+       ASSERT(path1->slots[0]);
 
        path1->slots[0]--;
 
@@ -746,10 +747,10 @@ again:
                 * the backref was added previously when processing
                 * backref of type BTRFS_TREE_BLOCK_REF_KEY
                 */
-               BUG_ON(!list_is_singular(&cur->upper));
+               ASSERT(list_is_singular(&cur->upper));
                edge = list_entry(cur->upper.next, struct backref_edge,
                                  list[LOWER]);
-               BUG_ON(!list_empty(&edge->list[UPPER]));
+               ASSERT(list_empty(&edge->list[UPPER]));
                exist = edge->node[UPPER];
                /*
                 * add the upper level block to pending list if we need
@@ -831,7 +832,7 @@ again:
                                        cur->cowonly = 1;
                        }
 #else
-               BUG_ON(key.type == BTRFS_EXTENT_REF_V0_KEY);
+               ASSERT(key.type != BTRFS_EXTENT_REF_V0_KEY);
                if (key.type == BTRFS_SHARED_BLOCK_REF_KEY) {
 #endif
                        if (key.objectid == key.offset) {
@@ -840,7 +841,7 @@ again:
                                 * backref of this type.
                                 */
                                root = find_reloc_root(rc, cur->bytenr);
-                               BUG_ON(!root);
+                               ASSERT(root);
                                cur->root = root;
                                break;
                        }
@@ -868,7 +869,7 @@ again:
                        } else {
                                upper = rb_entry(rb_node, struct backref_node,
                                                 rb_node);
-                               BUG_ON(!upper->checked);
+                               ASSERT(upper->checked);
                                INIT_LIST_HEAD(&edge->list[UPPER]);
                        }
                        list_add_tail(&edge->list[LOWER], &cur->upper);
@@ -892,7 +893,7 @@ again:
 
                if (btrfs_root_level(&root->root_item) == cur->level) {
                        /* tree root */
-                       BUG_ON(btrfs_root_bytenr(&root->root_item) !=
+                       ASSERT(btrfs_root_bytenr(&root->root_item) ==
                               cur->bytenr);
                        if (should_ignore_root(root))
                                list_add(&cur->list, &useless);
@@ -927,7 +928,7 @@ again:
                need_check = true;
                for (; level < BTRFS_MAX_LEVEL; level++) {
                        if (!path2->nodes[level]) {
-                               BUG_ON(btrfs_root_bytenr(&root->root_item) !=
+                               ASSERT(btrfs_root_bytenr(&root->root_item) ==
                                       lower->bytenr);
                                if (should_ignore_root(root))
                                        list_add(&lower->list, &useless);
@@ -977,12 +978,15 @@ again:
                                        need_check = false;
                                        list_add_tail(&edge->list[UPPER],
                                                      &list);
-                               } else
+                               } else {
+                                       if (upper->checked)
+                                               need_check = true;
                                        INIT_LIST_HEAD(&edge->list[UPPER]);
+                               }
                        } else {
                                upper = rb_entry(rb_node, struct backref_node,
                                                 rb_node);
-                               BUG_ON(!upper->checked);
+                               ASSERT(upper->checked);
                                INIT_LIST_HEAD(&edge->list[UPPER]);
                                if (!upper->owner)
                                        upper->owner = btrfs_header_owner(eb);
@@ -1026,7 +1030,7 @@ next:
         * everything goes well, connect backref nodes and insert backref nodes
         * into the cache.
         */
-       BUG_ON(!node->checked);
+       ASSERT(node->checked);
        cowonly = node->cowonly;
        if (!cowonly) {
                rb_node = tree_insert(&cache->rb_root, node->bytenr,
@@ -1062,8 +1066,21 @@ next:
                        continue;
                }
 
-               BUG_ON(!upper->checked);
-               BUG_ON(cowonly != upper->cowonly);
+               if (!upper->checked) {
+                       /*
+                        * Still want to blow up for developers since this is a
+                        * logic bug.
+                        */
+                       ASSERT(0);
+                       err = -EINVAL;
+                       goto out;
+               }
+               if (cowonly != upper->cowonly) {
+                       ASSERT(0);
+                       err = -EINVAL;
+                       goto out;
+               }
+
                if (!cowonly) {
                        rb_node = tree_insert(&cache->rb_root, upper->bytenr,
                                              &upper->rb_node);
@@ -1086,7 +1103,7 @@ next:
        while (!list_empty(&useless)) {
                upper = list_entry(useless.next, struct backref_node, list);
                list_del_init(&upper->list);
-               BUG_ON(!list_empty(&upper->upper));
+               ASSERT(list_empty(&upper->upper));
                if (upper == node)
                        node = NULL;
                if (upper->lowest) {
@@ -1119,29 +1136,45 @@ out:
        if (err) {
                while (!list_empty(&useless)) {
                        lower = list_entry(useless.next,
-                                          struct backref_node, upper);
-                       list_del_init(&lower->upper);
+                                          struct backref_node, list);
+                       list_del_init(&lower->list);
                }
-               upper = node;
-               INIT_LIST_HEAD(&list);
-               while (upper) {
-                       if (RB_EMPTY_NODE(&upper->rb_node)) {
-                               list_splice_tail(&upper->upper, &list);
-                               free_backref_node(cache, upper);
-                       }
-
-                       if (list_empty(&list))
-                               break;
-
-                       edge = list_entry(list.next, struct backref_edge,
-                                         list[LOWER]);
+               while (!list_empty(&list)) {
+                       edge = list_first_entry(&list, struct backref_edge,
+                                               list[UPPER]);
+                       list_del(&edge->list[UPPER]);
                        list_del(&edge->list[LOWER]);
+                       lower = edge->node[LOWER];
                        upper = edge->node[UPPER];
                        free_backref_edge(cache, edge);
+
+                       /*
+                        * Lower is no longer linked to any upper backref nodes
+                        * and isn't in the cache, we can free it ourselves.
+                        */
+                       if (list_empty(&lower->upper) &&
+                           RB_EMPTY_NODE(&lower->rb_node))
+                               list_add(&lower->list, &useless);
+
+                       if (!RB_EMPTY_NODE(&upper->rb_node))
+                               continue;
+
+                       /* Add this guy's upper edges to the list to proces */
+                       list_for_each_entry(edge, &upper->upper, list[LOWER])
+                               list_add_tail(&edge->list[UPPER], &list);
+                       if (list_empty(&upper->upper))
+                               list_add(&upper->list, &useless);
+               }
+
+               while (!list_empty(&useless)) {
+                       lower = list_entry(useless.next,
+                                          struct backref_node, list);
+                       list_del_init(&lower->list);
+                       free_backref_node(cache, lower);
                }
                return ERR_PTR(err);
        }
-       BUG_ON(node && node->detached);
+       ASSERT(!node || !node->detached);
        return node;
 }
 
@@ -1787,7 +1820,7 @@ again:
                        btrfs_node_key_to_cpu(parent, next_key, slot + 1);
 
                old_bytenr = btrfs_node_blockptr(parent, slot);
-               blocksize = btrfs_level_size(dest, level - 1);
+               blocksize = dest->nodesize;
                old_ptr_gen = btrfs_node_ptr_generation(parent, slot);
 
                if (level <= max_level) {
@@ -1813,8 +1846,7 @@ again:
                                break;
                        }
 
-                       eb = read_tree_block(dest, old_bytenr, blocksize,
-                                            old_ptr_gen);
+                       eb = read_tree_block(dest, old_bytenr, old_ptr_gen);
                        if (!eb || !extent_buffer_uptodate(eb)) {
                                ret = (!eb) ? -ENOMEM : -EIO;
                                free_extent_buffer(eb);
@@ -1944,7 +1976,6 @@ int walk_down_reloc_tree(struct btrfs_root *root, struct btrfs_path *path,
        u64 bytenr;
        u64 ptr_gen = 0;
        u64 last_snapshot;
-       u32 blocksize;
        u32 nritems;
 
        last_snapshot = btrfs_root_last_snapshot(&root->root_item);
@@ -1970,8 +2001,7 @@ int walk_down_reloc_tree(struct btrfs_root *root, struct btrfs_path *path,
                }
 
                bytenr = btrfs_node_blockptr(eb, path->slots[i]);
-               blocksize = btrfs_level_size(root, i - 1);
-               eb = read_tree_block(root, bytenr, blocksize, ptr_gen);
+               eb = read_tree_block(root, bytenr, ptr_gen);
                if (!eb || !extent_buffer_uptodate(eb)) {
                        free_extent_buffer(eb);
                        return -EIO;
@@ -2316,7 +2346,7 @@ void free_reloc_roots(struct list_head *list)
 }
 
 static noinline_for_stack
-int merge_reloc_roots(struct reloc_control *rc)
+void merge_reloc_roots(struct reloc_control *rc)
 {
        struct btrfs_root *root;
        struct btrfs_root *reloc_root;
@@ -2397,7 +2427,6 @@ out:
        }
 
        BUG_ON(!RB_EMPTY_ROOT(&rc->reloc_root_tree.rb_root));
-       return ret;
 }
 
 static void free_block_list(struct rb_root *blocks)
@@ -2544,8 +2573,7 @@ u64 calcu_metadata_size(struct reloc_control *rc,
                        if (next->processed && (reserve || next != node))
                                break;
 
-                       num_bytes += btrfs_level_size(rc->extent_root,
-                                                     next->level);
+                       num_bytes += rc->extent_root->nodesize;
 
                        if (list_empty(&next->upper))
                                break;
@@ -2679,9 +2707,9 @@ static int do_relocation(struct btrfs_trans_handle *trans,
                                goto next;
                }
 
-               blocksize = btrfs_level_size(root, node->level);
+               blocksize = root->nodesize;
                generation = btrfs_node_ptr_generation(upper->eb, slot);
-               eb = read_tree_block(root, bytenr, blocksize, generation);
+               eb = read_tree_block(root, bytenr, generation);
                if (!eb || !extent_buffer_uptodate(eb)) {
                        free_extent_buffer(eb);
                        err = -EIO;
@@ -2789,7 +2817,7 @@ static void __mark_block_processed(struct reloc_control *rc,
        u32 blocksize;
        if (node->level == 0 ||
            in_block_group(node->bytenr, rc->block_group)) {
-               blocksize = btrfs_level_size(rc->extent_root, node->level);
+               blocksize = rc->extent_root->nodesize;
                mark_block_processed(rc, node->bytenr, blocksize);
        }
        node->processed = 1;
@@ -2843,7 +2871,7 @@ static int get_tree_block_key(struct reloc_control *rc,
 
        BUG_ON(block->key_ready);
        eb = read_tree_block(rc->extent_root, block->bytenr,
-                            block->key.objectid, block->key.offset);
+                            block->key.offset);
        if (!eb || !extent_buffer_uptodate(eb)) {
                free_extent_buffer(eb);
                return -EIO;
@@ -2858,20 +2886,6 @@ static int get_tree_block_key(struct reloc_control *rc,
        return 0;
 }
 
-static int reada_tree_block(struct reloc_control *rc,
-                           struct tree_block *block)
-{
-       BUG_ON(block->key_ready);
-       if (block->key.type == BTRFS_METADATA_ITEM_KEY)
-               readahead_tree_block(rc->extent_root, block->bytenr,
-                                    block->key.objectid,
-                                    rc->extent_root->leafsize);
-       else
-               readahead_tree_block(rc->extent_root, block->bytenr,
-                                    block->key.objectid, block->key.offset);
-       return 0;
-}
-
 /*
  * helper function to relocate a tree block
  */
@@ -2951,7 +2965,8 @@ int relocate_tree_blocks(struct btrfs_trans_handle *trans,
        while (rb_node) {
                block = rb_entry(rb_node, struct tree_block, rb_node);
                if (!block->key_ready)
-                       reada_tree_block(rc, block);
+                       readahead_tree_block(rc->extent_root, block->bytenr,
+                                       block->key.objectid);
                rb_node = rb_next(rb_node);
        }
 
@@ -3313,7 +3328,7 @@ static int add_tree_block(struct reloc_control *rc,
                return -ENOMEM;
 
        block->bytenr = extent_key->objectid;
-       block->key.objectid = rc->extent_root->leafsize;
+       block->key.objectid = rc->extent_root->nodesize;
        block->key.offset = generation;
        block->level = level;
        block->key_ready = 0;
@@ -3640,7 +3655,7 @@ int add_data_references(struct reloc_control *rc,
        struct btrfs_extent_inline_ref *iref;
        unsigned long ptr;
        unsigned long end;
-       u32 blocksize = btrfs_level_size(rc->extent_root, 0);
+       u32 blocksize = rc->extent_root->nodesize;
        int ret = 0;
        int err = 0;
 
@@ -3783,7 +3798,7 @@ next:
                }
 
                if (key.type == BTRFS_METADATA_ITEM_KEY &&
-                   key.objectid + rc->extent_root->leafsize <=
+                   key.objectid + rc->extent_root->nodesize <=
                    rc->search_start) {
                        path->slots[0]++;
                        goto next;
@@ -3801,7 +3816,7 @@ next:
                                rc->search_start = key.objectid + key.offset;
                        else
                                rc->search_start = key.objectid +
-                                       rc->extent_root->leafsize;
+                                       rc->extent_root->nodesize;
                        memcpy(extent_key, &key, sizeof(key));
                        return 0;
                }
@@ -4096,7 +4111,6 @@ static int __insert_orphan_inode(struct btrfs_trans_handle *trans,
        btrfs_set_inode_flags(leaf, item, BTRFS_INODE_NOCOMPRESS |
                                          BTRFS_INODE_PREALLOC);
        btrfs_mark_buffer_dirty(leaf);
-       btrfs_release_path(path);
 out:
        btrfs_free_path(path);
        return ret;
index f4a41f37be229b555fb2e26993aff7055ee7fff1..efa08311382725c6770f3899033778ba8e3129ac 100644 (file)
@@ -137,7 +137,6 @@ struct scrub_ctx {
        int                     pages_per_rd_bio;
        u32                     sectorsize;
        u32                     nodesize;
-       u32                     leafsize;
 
        int                     is_dev_replace;
        struct scrub_wr_ctx     wr_ctx;
@@ -178,17 +177,12 @@ struct scrub_copy_nocow_ctx {
 struct scrub_warning {
        struct btrfs_path       *path;
        u64                     extent_item_size;
-       char                    *scratch_buf;
-       char                    *msg_buf;
        const char              *errstr;
        sector_t                sector;
        u64                     logical;
        struct btrfs_device     *dev;
-       int                     msg_bufsize;
-       int                     scratch_bufsize;
 };
 
-
 static void scrub_pending_bio_inc(struct scrub_ctx *sctx);
 static void scrub_pending_bio_dec(struct scrub_ctx *sctx);
 static void scrub_pending_trans_workers_inc(struct scrub_ctx *sctx);
@@ -438,7 +432,6 @@ struct scrub_ctx *scrub_setup_ctx(struct btrfs_device *dev, int is_dev_replace)
        }
        sctx->first_free = 0;
        sctx->nodesize = dev->dev_root->nodesize;
-       sctx->leafsize = dev->dev_root->leafsize;
        sctx->sectorsize = dev->dev_root->sectorsize;
        atomic_set(&sctx->bios_in_flight, 0);
        atomic_set(&sctx->workers_pending, 0);
@@ -553,7 +546,6 @@ static void scrub_print_warning(const char *errstr, struct scrub_block *sblock)
        u64 ref_root;
        u32 item_size;
        u8 ref_level;
-       const int bufsize = 4096;
        int ret;
 
        WARN_ON(sblock->page_count < 1);
@@ -561,18 +553,13 @@ static void scrub_print_warning(const char *errstr, struct scrub_block *sblock)
        fs_info = sblock->sctx->dev_root->fs_info;
 
        path = btrfs_alloc_path();
+       if (!path)
+               return;
 
-       swarn.scratch_buf = kmalloc(bufsize, GFP_NOFS);
-       swarn.msg_buf = kmalloc(bufsize, GFP_NOFS);
        swarn.sector = (sblock->pagev[0]->physical) >> 9;
        swarn.logical = sblock->pagev[0]->logical;
        swarn.errstr = errstr;
        swarn.dev = NULL;
-       swarn.msg_bufsize = bufsize;
-       swarn.scratch_bufsize = bufsize;
-
-       if (!path || !swarn.scratch_buf || !swarn.msg_buf)
-               goto out;
 
        ret = extent_from_logical(fs_info, swarn.logical, path, &found_key,
                                  &flags);
@@ -613,8 +600,6 @@ static void scrub_print_warning(const char *errstr, struct scrub_block *sblock)
 
 out:
        btrfs_free_path(path);
-       kfree(swarn.scratch_buf);
-       kfree(swarn.msg_buf);
 }
 
 static int scrub_fixup_readpage(u64 inum, u64 offset, u64 root, void *fixup_ctx)
@@ -681,9 +666,9 @@ static int scrub_fixup_readpage(u64 inum, u64 offset, u64 root, void *fixup_ctx)
                        ret = -EIO;
                        goto out;
                }
-               fs_info = BTRFS_I(inode)->root->fs_info;
-               ret = repair_io_failure(fs_info, offset, PAGE_SIZE,
+               ret = repair_io_failure(inode, offset, PAGE_SIZE,
                                        fixup->logical, page,
+                                       offset - page_offset(page),
                                        fixup->mirror_num);
                unlock_page(page);
                corrected = !ret;
@@ -1361,6 +1346,16 @@ static void scrub_recheck_block(struct btrfs_fs_info *fs_info,
        return;
 }
 
+static inline int scrub_check_fsid(u8 fsid[],
+                                  struct scrub_page *spage)
+{
+       struct btrfs_fs_devices *fs_devices = spage->dev->fs_devices;
+       int ret;
+
+       ret = memcmp(fsid, fs_devices->fsid, BTRFS_UUID_SIZE);
+       return !ret;
+}
+
 static void scrub_recheck_block_checksum(struct btrfs_fs_info *fs_info,
                                         struct scrub_block *sblock,
                                         int is_metadata, int have_csum,
@@ -1380,7 +1375,7 @@ static void scrub_recheck_block_checksum(struct btrfs_fs_info *fs_info,
                h = (struct btrfs_header *)mapped_buffer;
 
                if (sblock->pagev[0]->logical != btrfs_stack_header_bytenr(h) ||
-                   memcmp(h->fsid, fs_info->fsid, BTRFS_UUID_SIZE) ||
+                   !scrub_check_fsid(h->fsid, sblock->pagev[0]) ||
                    memcmp(h->chunk_tree_uuid, fs_info->chunk_tree_uuid,
                           BTRFS_UUID_SIZE)) {
                        sblock->header_error = 1;
@@ -1751,14 +1746,13 @@ static int scrub_checksum_tree_block(struct scrub_block *sblock)
        if (sblock->pagev[0]->generation != btrfs_stack_header_generation(h))
                ++fail;
 
-       if (memcmp(h->fsid, fs_info->fsid, BTRFS_UUID_SIZE))
+       if (!scrub_check_fsid(h->fsid, sblock->pagev[0]))
                ++fail;
 
        if (memcmp(h->chunk_tree_uuid, fs_info->chunk_tree_uuid,
                   BTRFS_UUID_SIZE))
                ++fail;
 
-       WARN_ON(sctx->nodesize != sctx->leafsize);
        len = sctx->nodesize - BTRFS_CSUM_SIZE;
        mapped_size = PAGE_SIZE - BTRFS_CSUM_SIZE;
        p = ((u8 *)mapped_buffer) + BTRFS_CSUM_SIZE;
@@ -1791,8 +1785,6 @@ static int scrub_checksum_super(struct scrub_block *sblock)
 {
        struct btrfs_super_block *s;
        struct scrub_ctx *sctx = sblock->sctx;
-       struct btrfs_root *root = sctx->dev_root;
-       struct btrfs_fs_info *fs_info = root->fs_info;
        u8 calculated_csum[BTRFS_CSUM_SIZE];
        u8 on_disk_csum[BTRFS_CSUM_SIZE];
        struct page *page;
@@ -1817,7 +1809,7 @@ static int scrub_checksum_super(struct scrub_block *sblock)
        if (sblock->pagev[0]->generation != btrfs_super_generation(s))
                ++fail_gen;
 
-       if (memcmp(s->fsid, fs_info->fsid, BTRFS_UUID_SIZE))
+       if (!scrub_check_fsid(s->fsid, sblock->pagev[0]))
                ++fail_cor;
 
        len = BTRFS_SUPER_INFO_SIZE - BTRFS_CSUM_SIZE;
@@ -2196,7 +2188,6 @@ static int scrub_extent(struct scrub_ctx *sctx, u64 logical, u64 len,
                sctx->stat.data_bytes_scrubbed += len;
                spin_unlock(&sctx->stat_lock);
        } else if (flags & BTRFS_EXTENT_FLAG_TREE_BLOCK) {
-               WARN_ON(sctx->nodesize != sctx->leafsize);
                blocksize = sctx->nodesize;
                spin_lock(&sctx->stat_lock);
                sctx->stat.tree_extents_scrubbed++;
@@ -2487,7 +2478,7 @@ static noinline_for_stack int scrub_stripe(struct scrub_ctx *sctx,
                        btrfs_item_key_to_cpu(l, &key, slot);
 
                        if (key.type == BTRFS_METADATA_ITEM_KEY)
-                               bytes = root->leafsize;
+                               bytes = root->nodesize;
                        else
                                bytes = key.offset;
 
@@ -2714,7 +2705,7 @@ int scrub_enumerate_chunks(struct scrub_ctx *sctx,
                if (found_key.objectid != scrub_dev->devid)
                        break;
 
-               if (btrfs_key_type(&found_key) != BTRFS_DEV_EXTENT_KEY)
+               if (found_key.type != BTRFS_DEV_EXTENT_KEY)
                        break;
 
                if (found_key.offset >= end)
@@ -2828,11 +2819,16 @@ static noinline_for_stack int scrub_supers(struct scrub_ctx *sctx,
        if (test_bit(BTRFS_FS_STATE_ERROR, &root->fs_info->fs_state))
                return -EIO;
 
-       gen = root->fs_info->last_trans_committed;
+       /* Seed devices of a new filesystem has their own generation. */
+       if (scrub_dev->fs_devices != root->fs_info->fs_devices)
+               gen = scrub_dev->generation;
+       else
+               gen = root->fs_info->last_trans_committed;
 
        for (i = 0; i < BTRFS_SUPER_MIRROR_MAX; i++) {
                bytenr = btrfs_sb_offset(i);
-               if (bytenr + BTRFS_SUPER_INFO_SIZE > scrub_dev->total_bytes)
+               if (bytenr + BTRFS_SUPER_INFO_SIZE >
+                   scrub_dev->commit_total_bytes)
                        break;
 
                ret = scrub_pages(sctx, bytenr, BTRFS_SUPER_INFO_SIZE, bytenr,
@@ -2910,17 +2906,6 @@ int btrfs_scrub_dev(struct btrfs_fs_info *fs_info, u64 devid, u64 start,
        if (btrfs_fs_closing(fs_info))
                return -EINVAL;
 
-       /*
-        * check some assumptions
-        */
-       if (fs_info->chunk_root->nodesize != fs_info->chunk_root->leafsize) {
-               btrfs_err(fs_info,
-                          "scrub: size assumption nodesize == leafsize (%d == %d) fails",
-                      fs_info->chunk_root->nodesize,
-                      fs_info->chunk_root->leafsize);
-               return -EINVAL;
-       }
-
        if (fs_info->chunk_root->nodesize > BTRFS_STRIPE_LEN) {
                /*
                 * in this case scrub is unable to calculate the checksum
index 6528aa6621819f31fae18eb9d337b1cfd624ba3a..874828dd0a8627d8c57097d17303f6db68f76775 100644 (file)
@@ -515,7 +515,8 @@ static int write_buf(struct file *filp, const void *buf, u32 len, loff_t *off)
        set_fs(KERNEL_DS);
 
        while (pos < len) {
-               ret = vfs_write(filp, (char *)buf + pos, len - pos, off);
+               ret = vfs_write(filp, (__force const char __user *)buf + pos,
+                               len - pos, off);
                /* TODO handle that correctly */
                /*if (ret == -ERESTARTSYS) {
                        continue;
@@ -985,11 +986,13 @@ static int iterate_dir_item(struct btrfs_root *root, struct btrfs_path *path,
        int num;
        u8 type;
 
-       if (found_key->type == BTRFS_XATTR_ITEM_KEY)
-               buf_len = BTRFS_MAX_XATTR_SIZE(root);
-       else
-               buf_len = PATH_MAX;
-
+       /*
+        * Start with a small buffer (1 page). If later we end up needing more
+        * space, which can happen for xattrs on a fs with a leaf size greater
+        * then the page size, attempt to increase the buffer. Typically xattr
+        * values are small.
+        */
+       buf_len = PATH_MAX;
        buf = kmalloc(buf_len, GFP_NOFS);
        if (!buf) {
                ret = -ENOMEM;
@@ -1016,7 +1019,7 @@ static int iterate_dir_item(struct btrfs_root *root, struct btrfs_path *path,
                                ret = -ENAMETOOLONG;
                                goto out;
                        }
-                       if (name_len + data_len > buf_len) {
+                       if (name_len + data_len > BTRFS_MAX_XATTR_SIZE(root)) {
                                ret = -E2BIG;
                                goto out;
                        }
@@ -1024,12 +1027,34 @@ static int iterate_dir_item(struct btrfs_root *root, struct btrfs_path *path,
                        /*
                         * Path too long
                         */
-                       if (name_len + data_len > buf_len) {
+                       if (name_len + data_len > PATH_MAX) {
                                ret = -ENAMETOOLONG;
                                goto out;
                        }
                }
 
+               if (name_len + data_len > buf_len) {
+                       buf_len = name_len + data_len;
+                       if (is_vmalloc_addr(buf)) {
+                               vfree(buf);
+                               buf = NULL;
+                       } else {
+                               char *tmp = krealloc(buf, buf_len,
+                                                    GFP_NOFS | __GFP_NOWARN);
+
+                               if (!tmp)
+                                       kfree(buf);
+                               buf = tmp;
+                       }
+                       if (!buf) {
+                               buf = vmalloc(buf_len);
+                               if (!buf) {
+                                       ret = -ENOMEM;
+                                       goto out;
+                               }
+                       }
+               }
+
                read_extent_buffer(eb, buf, (unsigned long)(di + 1),
                                name_len + data_len);
 
@@ -1050,7 +1075,7 @@ static int iterate_dir_item(struct btrfs_root *root, struct btrfs_path *path,
        }
 
 out:
-       kfree(buf);
+       kvfree(buf);
        return ret;
 }
 
@@ -3302,7 +3327,7 @@ static int wait_for_parent_move(struct send_ctx *sctx,
                if (ret < 0 && ret != -ENOENT) {
                        goto out;
                } else if (ret == -ENOENT) {
-                       ret = 1;
+                       ret = 0;
                        break;
                }
 
@@ -5703,7 +5728,7 @@ long btrfs_ioctl_send(struct file *mnt_file, void __user *arg_)
                        NULL);
        sort_clone_roots = 1;
 
-       current->journal_info = (void *)BTRFS_SEND_TRANS_STUB;
+       current->journal_info = BTRFS_SEND_TRANS_STUB;
        ret = send_subvol(sctx);
        current->journal_info = NULL;
        if (ret < 0)
index c4124de4435bffed06afc3a76ea6aba49a7c5317..a2b97ef10317081aebaa09aedeaddf4dec71a492 100644 (file)
@@ -60,6 +60,7 @@
 #include "backref.h"
 #include "tests/btrfs-tests.h"
 
+#include "qgroup.h"
 #define CREATE_TRACE_POINTS
 #include <trace/events/btrfs.h>
 
@@ -307,13 +308,7 @@ void __btrfs_panic(struct btrfs_fs_info *fs_info, const char *function,
 
 static void btrfs_put_super(struct super_block *sb)
 {
-       (void)close_ctree(btrfs_sb(sb)->tree_root);
-       /* FIXME: need to fix VFS to return error? */
-       /* AV: return it _where_?  ->put_super() can be triggered by any number
-        * of async events, up to and including delivery of SIGKILL to the
-        * last process that kept it busy.  Or segfault in the aforementioned
-        * process...  Whom would you report that to?
-        */
+       close_ctree(btrfs_sb(sb)->tree_root);
 }
 
 enum {
@@ -400,7 +395,6 @@ int btrfs_parse_options(struct btrfs_root *root, char *options)
        int ret = 0;
        char *compress_type;
        bool compress_force = false;
-       bool compress = false;
 
        cache_gen = btrfs_super_cache_generation(root->fs_info->super_copy);
        if (cache_gen)
@@ -478,7 +472,6 @@ int btrfs_parse_options(struct btrfs_root *root, char *options)
                        /* Fallthrough */
                case Opt_compress:
                case Opt_compress_type:
-                       compress = true;
                        if (token == Opt_compress ||
                            token == Opt_compress_force ||
                            strcmp(args[0].from, "zlib") == 0) {
@@ -508,11 +501,18 @@ int btrfs_parse_options(struct btrfs_root *root, char *options)
                                btrfs_set_and_info(root, FORCE_COMPRESS,
                                                   "force %s compression",
                                                   compress_type);
-                       } else if (compress) {
+                       } else {
                                if (!btrfs_test_opt(root, COMPRESS))
                                        btrfs_info(root->fs_info,
                                                   "btrfs: use %s compression",
                                                   compress_type);
+                               /*
+                                * If we remount from compress-force=xxx to
+                                * compress=xxx, we need clear FORCE_COMPRESS
+                                * flag, otherwise, there is no way for users
+                                * to disable forcible compression separately.
+                                */
+                               btrfs_clear_opt(info->mount_opt, FORCE_COMPRESS);
                        }
                        break;
                case Opt_ssd:
@@ -1014,7 +1014,7 @@ static int btrfs_show_options(struct seq_file *seq, struct dentry *dentry)
                seq_puts(seq, ",nodatacow");
        if (btrfs_test_opt(root, NOBARRIER))
                seq_puts(seq, ",nobarrier");
-       if (info->max_inline != 8192 * 1024)
+       if (info->max_inline != BTRFS_DEFAULT_MAX_INLINE)
                seq_printf(seq, ",max_inline=%llu", info->max_inline);
        if (info->alloc_start != 0)
                seq_printf(seq, ",alloc_start=%llu", info->alloc_start);
@@ -1215,6 +1215,56 @@ static struct dentry *mount_subvol(const char *subvol_name, int flags,
        return root;
 }
 
+static int parse_security_options(char *orig_opts,
+                                 struct security_mnt_opts *sec_opts)
+{
+       char *secdata = NULL;
+       int ret = 0;
+
+       secdata = alloc_secdata();
+       if (!secdata)
+               return -ENOMEM;
+       ret = security_sb_copy_data(orig_opts, secdata);
+       if (ret) {
+               free_secdata(secdata);
+               return ret;
+       }
+       ret = security_sb_parse_opts_str(secdata, sec_opts);
+       free_secdata(secdata);
+       return ret;
+}
+
+static int setup_security_options(struct btrfs_fs_info *fs_info,
+                                 struct super_block *sb,
+                                 struct security_mnt_opts *sec_opts)
+{
+       int ret = 0;
+
+       /*
+        * Call security_sb_set_mnt_opts() to check whether new sec_opts
+        * is valid.
+        */
+       ret = security_sb_set_mnt_opts(sb, sec_opts, 0, NULL);
+       if (ret)
+               return ret;
+
+#ifdef CONFIG_SECURITY
+       if (!fs_info->security_opts.num_mnt_opts) {
+               /* first time security setup, copy sec_opts to fs_info */
+               memcpy(&fs_info->security_opts, sec_opts, sizeof(*sec_opts));
+       } else {
+               /*
+                * Since SELinux(the only one supports security_mnt_opts) does
+                * NOT support changing context during remount/mount same sb,
+                * This must be the same or part of the same security options,
+                * just free it.
+                */
+               security_free_mnt_opts(sec_opts);
+       }
+#endif
+       return ret;
+}
+
 /*
  * Find a superblock for the given device / mount point.
  *
@@ -1229,6 +1279,7 @@ static struct dentry *btrfs_mount(struct file_system_type *fs_type, int flags,
        struct dentry *root;
        struct btrfs_fs_devices *fs_devices = NULL;
        struct btrfs_fs_info *fs_info = NULL;
+       struct security_mnt_opts new_sec_opts;
        fmode_t mode = FMODE_READ;
        char *subvol_name = NULL;
        u64 subvol_objectid = 0;
@@ -1251,9 +1302,16 @@ static struct dentry *btrfs_mount(struct file_system_type *fs_type, int flags,
                return root;
        }
 
+       security_init_mnt_opts(&new_sec_opts);
+       if (data) {
+               error = parse_security_options(data, &new_sec_opts);
+               if (error)
+                       return ERR_PTR(error);
+       }
+
        error = btrfs_scan_one_device(device_name, mode, fs_type, &fs_devices);
        if (error)
-               return ERR_PTR(error);
+               goto error_sec_opts;
 
        /*
         * Setup a dummy root and fs_info for test/set super.  This is because
@@ -1262,13 +1320,16 @@ static struct dentry *btrfs_mount(struct file_system_type *fs_type, int flags,
         * then open_ctree will properly initialize everything later.
         */
        fs_info = kzalloc(sizeof(struct btrfs_fs_info), GFP_NOFS);
-       if (!fs_info)
-               return ERR_PTR(-ENOMEM);
+       if (!fs_info) {
+               error = -ENOMEM;
+               goto error_sec_opts;
+       }
 
        fs_info->fs_devices = fs_devices;
 
        fs_info->super_copy = kzalloc(BTRFS_SUPER_INFO_SIZE, GFP_NOFS);
        fs_info->super_for_commit = kzalloc(BTRFS_SUPER_INFO_SIZE, GFP_NOFS);
+       security_init_mnt_opts(&fs_info->security_opts);
        if (!fs_info->super_copy || !fs_info->super_for_commit) {
                error = -ENOMEM;
                goto error_fs_info;
@@ -1306,8 +1367,19 @@ static struct dentry *btrfs_mount(struct file_system_type *fs_type, int flags,
        }
 
        root = !error ? get_default_root(s, subvol_objectid) : ERR_PTR(error);
-       if (IS_ERR(root))
+       if (IS_ERR(root)) {
+               deactivate_locked_super(s);
+               error = PTR_ERR(root);
+               goto error_sec_opts;
+       }
+
+       fs_info = btrfs_sb(s);
+       error = setup_security_options(fs_info, s, &new_sec_opts);
+       if (error) {
+               dput(root);
                deactivate_locked_super(s);
+               goto error_sec_opts;
+       }
 
        return root;
 
@@ -1315,6 +1387,8 @@ error_close_devices:
        btrfs_close_devices(fs_devices);
 error_fs_info:
        free_fs_info(fs_info);
+error_sec_opts:
+       security_free_mnt_opts(&new_sec_opts);
        return ERR_PTR(error);
 }
 
@@ -1396,6 +1470,21 @@ static int btrfs_remount(struct super_block *sb, int *flags, char *data)
        sync_filesystem(sb);
        btrfs_remount_prepare(fs_info);
 
+       if (data) {
+               struct security_mnt_opts new_sec_opts;
+
+               security_init_mnt_opts(&new_sec_opts);
+               ret = parse_security_options(data, &new_sec_opts);
+               if (ret)
+                       goto restore;
+               ret = setup_security_options(fs_info, sb,
+                                            &new_sec_opts);
+               if (ret) {
+                       security_free_mnt_opts(&new_sec_opts);
+                       goto restore;
+               }
+       }
+
        ret = btrfs_parse_options(root, data);
        if (ret) {
                ret = -EINVAL;
@@ -1694,7 +1783,11 @@ static int btrfs_statfs(struct dentry *dentry, struct kstatfs *buf)
        struct btrfs_block_rsv *block_rsv = &fs_info->global_block_rsv;
        int ret;
 
-       /* holding chunk_muext to avoid allocating new chunks */
+       /*
+        * holding chunk_muext to avoid allocating new chunks, holding
+        * device_list_mutex to avoid the device being removed
+        */
+       mutex_lock(&fs_info->fs_devices->device_list_mutex);
        mutex_lock(&fs_info->chunk_mutex);
        rcu_read_lock();
        list_for_each_entry_rcu(found, head, list) {
@@ -1735,11 +1828,13 @@ static int btrfs_statfs(struct dentry *dentry, struct kstatfs *buf)
        ret = btrfs_calc_avail_data_space(fs_info->tree_root, &total_free_data);
        if (ret) {
                mutex_unlock(&fs_info->chunk_mutex);
+               mutex_unlock(&fs_info->fs_devices->device_list_mutex);
                return ret;
        }
        buf->f_bavail += div_u64(total_free_data, factor);
        buf->f_bavail = buf->f_bavail >> bits;
        mutex_unlock(&fs_info->chunk_mutex);
+       mutex_unlock(&fs_info->fs_devices->device_list_mutex);
 
        buf->f_type = BTRFS_SUPER_MAGIC;
        buf->f_bsize = dentry->d_sb->s_blocksize;
@@ -1769,7 +1864,7 @@ static struct file_system_type btrfs_fs_type = {
        .name           = "btrfs",
        .mount          = btrfs_mount,
        .kill_sb        = btrfs_kill_super,
-       .fs_flags       = FS_REQUIRES_DEV,
+       .fs_flags       = FS_REQUIRES_DEV | FS_BINARY_MOUNTDATA,
 };
 MODULE_ALIAS_FS("btrfs");
 
@@ -1992,12 +2087,16 @@ static int __init init_btrfs_fs(void)
                goto free_auto_defrag;
 
        err = btrfs_prelim_ref_init();
+       if (err)
+               goto free_delayed_ref;
+
+       err = btrfs_end_io_wq_init();
        if (err)
                goto free_prelim_ref;
 
        err = btrfs_interface_init();
        if (err)
-               goto free_delayed_ref;
+               goto free_end_io_wq;
 
        btrfs_init_lockdep();
 
@@ -2015,6 +2114,8 @@ static int __init init_btrfs_fs(void)
 
 unregister_ioctl:
        btrfs_interface_exit();
+free_end_io_wq:
+       btrfs_end_io_wq_exit();
 free_prelim_ref:
        btrfs_prelim_ref_exit();
 free_delayed_ref:
index 12e53556e214c2c26f0a67aadf63b53637178822..b2e7bb4393f65cf17575dadc2686a693d83bd253 100644 (file)
@@ -242,7 +242,7 @@ static ssize_t global_rsv_size_show(struct kobject *kobj,
        struct btrfs_block_rsv *block_rsv = &fs_info->global_block_rsv;
        return btrfs_show_u64(&block_rsv->size, &block_rsv->lock, buf);
 }
-BTRFS_ATTR(global_rsv_size, 0444, global_rsv_size_show);
+BTRFS_ATTR(global_rsv_size, global_rsv_size_show);
 
 static ssize_t global_rsv_reserved_show(struct kobject *kobj,
                                        struct kobj_attribute *a, char *buf)
@@ -251,7 +251,7 @@ static ssize_t global_rsv_reserved_show(struct kobject *kobj,
        struct btrfs_block_rsv *block_rsv = &fs_info->global_block_rsv;
        return btrfs_show_u64(&block_rsv->reserved, &block_rsv->lock, buf);
 }
-BTRFS_ATTR(global_rsv_reserved, 0444, global_rsv_reserved_show);
+BTRFS_ATTR(global_rsv_reserved, global_rsv_reserved_show);
 
 #define to_space_info(_kobj) container_of(_kobj, struct btrfs_space_info, kobj)
 #define to_raid_kobj(_kobj) container_of(_kobj, struct raid_kobject, kobj)
@@ -306,7 +306,7 @@ static ssize_t btrfs_space_info_show_##field(struct kobject *kobj,  \
        struct btrfs_space_info *sinfo = to_space_info(kobj);           \
        return btrfs_show_u64(&sinfo->field, &sinfo->lock, buf);        \
 }                                                                      \
-BTRFS_ATTR(field, 0444, btrfs_space_info_show_##field)
+BTRFS_ATTR(field, btrfs_space_info_show_##field)
 
 static ssize_t btrfs_space_info_show_total_bytes_pinned(struct kobject *kobj,
                                                       struct kobj_attribute *a,
@@ -325,7 +325,7 @@ SPACE_INFO_ATTR(bytes_reserved);
 SPACE_INFO_ATTR(bytes_may_use);
 SPACE_INFO_ATTR(disk_used);
 SPACE_INFO_ATTR(disk_total);
-BTRFS_ATTR(total_bytes_pinned, 0444, btrfs_space_info_show_total_bytes_pinned);
+BTRFS_ATTR(total_bytes_pinned, btrfs_space_info_show_total_bytes_pinned);
 
 static struct attribute *space_info_attrs[] = {
        BTRFS_ATTR_PTR(flags),
@@ -363,7 +363,8 @@ static ssize_t btrfs_label_show(struct kobject *kobj,
                                struct kobj_attribute *a, char *buf)
 {
        struct btrfs_fs_info *fs_info = to_fs_info(kobj);
-       return snprintf(buf, PAGE_SIZE, "%s\n", fs_info->super_copy->label);
+       char *label = fs_info->super_copy->label;
+       return snprintf(buf, PAGE_SIZE, label[0] ? "%s\n" : "%s", label);
 }
 
 static ssize_t btrfs_label_store(struct kobject *kobj,
@@ -374,8 +375,18 @@ static ssize_t btrfs_label_store(struct kobject *kobj,
        struct btrfs_trans_handle *trans;
        struct btrfs_root *root = fs_info->fs_root;
        int ret;
+       size_t p_len;
 
-       if (len >= BTRFS_LABEL_SIZE)
+       if (fs_info->sb->s_flags & MS_RDONLY)
+               return -EROFS;
+
+       /*
+        * p_len is the len until the first occurrence of either
+        * '\n' or '\0'
+        */
+       p_len = strcspn(buf, "\n");
+
+       if (p_len >= BTRFS_LABEL_SIZE)
                return -EINVAL;
 
        trans = btrfs_start_transaction(root, 0);
@@ -383,7 +394,8 @@ static ssize_t btrfs_label_store(struct kobject *kobj,
                return PTR_ERR(trans);
 
        spin_lock(&root->fs_info->super_lock);
-       strcpy(fs_info->super_copy->label, buf);
+       memset(fs_info->super_copy->label, 0, BTRFS_LABEL_SIZE);
+       memcpy(fs_info->super_copy->label, buf, p_len);
        spin_unlock(&root->fs_info->super_lock);
        ret = btrfs_commit_transaction(trans, root);
 
@@ -392,14 +404,7 @@ static ssize_t btrfs_label_store(struct kobject *kobj,
 
        return ret;
 }
-BTRFS_ATTR_RW(label, 0644, btrfs_label_show, btrfs_label_store);
-
-static ssize_t btrfs_no_store(struct kobject *kobj,
-                                struct kobj_attribute *a,
-                                const char *buf, size_t len)
-{
-       return -EPERM;
-}
+BTRFS_ATTR_RW(label, btrfs_label_show, btrfs_label_store);
 
 static ssize_t btrfs_nodesize_show(struct kobject *kobj,
                                struct kobj_attribute *a, char *buf)
@@ -409,7 +414,7 @@ static ssize_t btrfs_nodesize_show(struct kobject *kobj,
        return snprintf(buf, PAGE_SIZE, "%u\n", fs_info->super_copy->nodesize);
 }
 
-BTRFS_ATTR_RW(nodesize, 0444, btrfs_nodesize_show, btrfs_no_store);
+BTRFS_ATTR(nodesize, btrfs_nodesize_show);
 
 static ssize_t btrfs_sectorsize_show(struct kobject *kobj,
                                struct kobj_attribute *a, char *buf)
@@ -419,7 +424,7 @@ static ssize_t btrfs_sectorsize_show(struct kobject *kobj,
        return snprintf(buf, PAGE_SIZE, "%u\n", fs_info->super_copy->sectorsize);
 }
 
-BTRFS_ATTR_RW(sectorsize, 0444, btrfs_sectorsize_show, btrfs_no_store);
+BTRFS_ATTR(sectorsize, btrfs_sectorsize_show);
 
 static ssize_t btrfs_clone_alignment_show(struct kobject *kobj,
                                struct kobj_attribute *a, char *buf)
@@ -429,7 +434,7 @@ static ssize_t btrfs_clone_alignment_show(struct kobject *kobj,
        return snprintf(buf, PAGE_SIZE, "%u\n", fs_info->super_copy->sectorsize);
 }
 
-BTRFS_ATTR_RW(clone_alignment, 0444, btrfs_clone_alignment_show, btrfs_no_store);
+BTRFS_ATTR(clone_alignment, btrfs_clone_alignment_show);
 
 static struct attribute *btrfs_attrs[] = {
        BTRFS_ATTR_PTR(label),
index ac46df37504c45c0bac5196ea02d979677b225f6..f7dd298b3cf6ecbb080924ffd083af7bb68a4e1f 100644 (file)
@@ -20,16 +20,20 @@ enum btrfs_feature_set {
        .store  = _store,                                               \
 }
 
-#define BTRFS_ATTR_RW(_name, _mode, _show, _store)                     \
-static struct kobj_attribute btrfs_attr_##_name =                      \
-                       __INIT_KOBJ_ATTR(_name, _mode, _show, _store)
-#define BTRFS_ATTR(_name, _mode, _show)                                        \
-       BTRFS_ATTR_RW(_name, _mode, _show, NULL)
+#define BTRFS_ATTR_RW(_name, _show, _store)                    \
+       static struct kobj_attribute btrfs_attr_##_name =               \
+                       __INIT_KOBJ_ATTR(_name, 0644, _show, _store)
+
+#define BTRFS_ATTR(_name, _show)                                       \
+       static struct kobj_attribute btrfs_attr_##_name =               \
+                       __INIT_KOBJ_ATTR(_name, 0444, _show, NULL)
+
 #define BTRFS_ATTR_PTR(_name)    (&btrfs_attr_##_name.attr)
 
 #define BTRFS_RAID_ATTR(_name, _show)                                  \
-static struct kobj_attribute btrfs_raid_attr_##_name =                 \
+       static struct kobj_attribute btrfs_raid_attr_##_name =          \
                        __INIT_KOBJ_ATTR(_name, 0444, _show, NULL)
+
 #define BTRFS_RAID_ATTR_PTR(_name)    (&btrfs_raid_attr_##_name.attr)
 
 
index c8d9ddf84c6946d166b4e8dc67fa0ffd24a99b46..2299bfde39eec666fe1b0876733746a76673f5a5 100644 (file)
@@ -40,11 +40,12 @@ static struct btrfs_block_group_cache *init_test_block_group(void)
        cache->key.offset = 1024 * 1024 * 1024;
        cache->key.type = BTRFS_BLOCK_GROUP_ITEM_KEY;
        cache->sectorsize = 4096;
+       cache->full_stripe_len = 4096;
 
        spin_lock_init(&cache->lock);
        INIT_LIST_HEAD(&cache->list);
        INIT_LIST_HEAD(&cache->cluster_list);
-       INIT_LIST_HEAD(&cache->new_bg_list);
+       INIT_LIST_HEAD(&cache->bg_list);
 
        btrfs_init_free_space_ctl(cache);
 
@@ -364,6 +365,517 @@ static int test_bitmaps_and_extents(struct btrfs_block_group_cache *cache)
        return 0;
 }
 
+/* Used by test_steal_space_from_bitmap_to_extent(). */
+static bool test_use_bitmap(struct btrfs_free_space_ctl *ctl,
+                           struct btrfs_free_space *info)
+{
+       return ctl->free_extents > 0;
+}
+
+/* Used by test_steal_space_from_bitmap_to_extent(). */
+static int
+check_num_extents_and_bitmaps(const struct btrfs_block_group_cache *cache,
+                             const int num_extents,
+                             const int num_bitmaps)
+{
+       if (cache->free_space_ctl->free_extents != num_extents) {
+               test_msg("Incorrect # of extent entries in the cache: %d, expected %d\n",
+                        cache->free_space_ctl->free_extents, num_extents);
+               return -EINVAL;
+       }
+       if (cache->free_space_ctl->total_bitmaps != num_bitmaps) {
+               test_msg("Incorrect # of extent entries in the cache: %d, expected %d\n",
+                        cache->free_space_ctl->total_bitmaps, num_bitmaps);
+               return -EINVAL;
+       }
+       return 0;
+}
+
+/* Used by test_steal_space_from_bitmap_to_extent(). */
+static int check_cache_empty(struct btrfs_block_group_cache *cache)
+{
+       u64 offset;
+       u64 max_extent_size;
+
+       /*
+        * Now lets confirm that there's absolutely no free space left to
+        * allocate.
+        */
+       if (cache->free_space_ctl->free_space != 0) {
+               test_msg("Cache free space is not 0\n");
+               return -EINVAL;
+       }
+
+       /* And any allocation request, no matter how small, should fail now. */
+       offset = btrfs_find_space_for_alloc(cache, 0, 4096, 0,
+                                           &max_extent_size);
+       if (offset != 0) {
+               test_msg("Space allocation did not fail, returned offset: %llu",
+                        offset);
+               return -EINVAL;
+       }
+
+       /* And no extent nor bitmap entries in the cache anymore. */
+       return check_num_extents_and_bitmaps(cache, 0, 0);
+}
+
+/*
+ * Before we were able to steal free space from a bitmap entry to an extent
+ * entry, we could end up with 2 entries representing a contiguous free space.
+ * One would be an extent entry and the other a bitmap entry. Since in order
+ * to allocate space to a caller we use only 1 entry, we couldn't return that
+ * whole range to the caller if it was requested. This forced the caller to
+ * either assume ENOSPC or perform several smaller space allocations, which
+ * wasn't optimal as they could be spread all over the block group while under
+ * concurrency (extra overhead and fragmentation).
+ *
+ * This stealing approach is benefical, since we always prefer to allocate from
+ * extent entries, both for clustered and non-clustered allocation requests.
+ */
+static int
+test_steal_space_from_bitmap_to_extent(struct btrfs_block_group_cache *cache)
+{
+       int ret;
+       u64 offset;
+       u64 max_extent_size;
+
+       bool (*use_bitmap_op)(struct btrfs_free_space_ctl *,
+                             struct btrfs_free_space *);
+
+       test_msg("Running space stealing from bitmap to extent\n");
+
+       /*
+        * For this test, we want to ensure we end up with an extent entry
+        * immediately adjacent to a bitmap entry, where the bitmap starts
+        * at an offset where the extent entry ends. We keep adding and
+        * removing free space to reach into this state, but to get there
+        * we need to reach a point where marking new free space doesn't
+        * result in adding new extent entries or merging the new space
+        * with existing extent entries - the space ends up being marked
+        * in an existing bitmap that covers the new free space range.
+        *
+        * To get there, we need to reach the threshold defined set at
+        * cache->free_space_ctl->extents_thresh, which currently is
+        * 256 extents on a x86_64 system at least, and a few other
+        * conditions (check free_space_cache.c). Instead of making the
+        * test much longer and complicated, use a "use_bitmap" operation
+        * that forces use of bitmaps as soon as we have at least 1
+        * extent entry.
+        */
+       use_bitmap_op = cache->free_space_ctl->op->use_bitmap;
+       cache->free_space_ctl->op->use_bitmap = test_use_bitmap;
+
+       /*
+        * Extent entry covering free space range [128Mb - 256Kb, 128Mb - 128Kb[
+        */
+       ret = test_add_free_space_entry(cache, 128 * 1024 * 1024 - 256 * 1024,
+                                       128 * 1024, 0);
+       if (ret) {
+               test_msg("Couldn't add extent entry %d\n", ret);
+               return ret;
+       }
+
+       /* Bitmap entry covering free space range [128Mb + 512Kb, 256Mb[ */
+       ret = test_add_free_space_entry(cache, 128 * 1024 * 1024 + 512 * 1024,
+                                       128 * 1024 * 1024 - 512 * 1024, 1);
+       if (ret) {
+               test_msg("Couldn't add bitmap entry %d\n", ret);
+               return ret;
+       }
+
+       ret = check_num_extents_and_bitmaps(cache, 2, 1);
+       if (ret)
+               return ret;
+
+       /*
+        * Now make only the first 256Kb of the bitmap marked as free, so that
+        * we end up with only the following ranges marked as free space:
+        *
+        * [128Mb - 256Kb, 128Mb - 128Kb[
+        * [128Mb + 512Kb, 128Mb + 768Kb[
+        */
+       ret = btrfs_remove_free_space(cache,
+                                     128 * 1024 * 1024 + 768 * 1024,
+                                     128 * 1024 * 1024 - 768 * 1024);
+       if (ret) {
+               test_msg("Failed to free part of bitmap space %d\n", ret);
+               return ret;
+       }
+
+       /* Confirm that only those 2 ranges are marked as free. */
+       if (!test_check_exists(cache, 128 * 1024 * 1024 - 256 * 1024,
+                              128 * 1024)) {
+               test_msg("Free space range missing\n");
+               return -ENOENT;
+       }
+       if (!test_check_exists(cache, 128 * 1024 * 1024 + 512 * 1024,
+                              256 * 1024)) {
+               test_msg("Free space range missing\n");
+               return -ENOENT;
+       }
+
+       /*
+        * Confirm that the bitmap range [128Mb + 768Kb, 256Mb[ isn't marked
+        * as free anymore.
+        */
+       if (test_check_exists(cache, 128 * 1024 * 1024 + 768 * 1024,
+                             128 * 1024 * 1024 - 768 * 1024)) {
+               test_msg("Bitmap region not removed from space cache\n");
+               return -EINVAL;
+       }
+
+       /*
+        * Confirm that the region [128Mb + 256Kb, 128Mb + 512Kb[, which is
+        * covered by the bitmap, isn't marked as free.
+        */
+       if (test_check_exists(cache, 128 * 1024 * 1024 + 256 * 1024,
+                             256 * 1024)) {
+               test_msg("Invalid bitmap region marked as free\n");
+               return -EINVAL;
+       }
+
+       /*
+        * Confirm that the region [128Mb, 128Mb + 256Kb[, which is covered
+        * by the bitmap too, isn't marked as free either.
+        */
+       if (test_check_exists(cache, 128 * 1024 * 1024,
+                             256 * 1024)) {
+               test_msg("Invalid bitmap region marked as free\n");
+               return -EINVAL;
+       }
+
+       /*
+        * Now lets mark the region [128Mb, 128Mb + 512Kb[ as free too. But,
+        * lets make sure the free space cache marks it as free in the bitmap,
+        * and doesn't insert a new extent entry to represent this region.
+        */
+       ret = btrfs_add_free_space(cache, 128 * 1024 * 1024, 512 * 1024);
+       if (ret) {
+               test_msg("Error adding free space: %d\n", ret);
+               return ret;
+       }
+       /* Confirm the region is marked as free. */
+       if (!test_check_exists(cache, 128 * 1024 * 1024, 512 * 1024)) {
+               test_msg("Bitmap region not marked as free\n");
+               return -ENOENT;
+       }
+
+       /*
+        * Confirm that no new extent entries or bitmap entries were added to
+        * the cache after adding that free space region.
+        */
+       ret = check_num_extents_and_bitmaps(cache, 2, 1);
+       if (ret)
+               return ret;
+
+       /*
+        * Now lets add a small free space region to the right of the previous
+        * one, which is not contiguous with it and is part of the bitmap too.
+        * The goal is to test that the bitmap entry space stealing doesn't
+        * steal this space region.
+        */
+       ret = btrfs_add_free_space(cache, 128 * 1024 * 1024 + 16 * 1024 * 1024,
+                                  4096);
+       if (ret) {
+               test_msg("Error adding free space: %d\n", ret);
+               return ret;
+       }
+
+       /*
+        * Confirm that no new extent entries or bitmap entries were added to
+        * the cache after adding that free space region.
+        */
+       ret = check_num_extents_and_bitmaps(cache, 2, 1);
+       if (ret)
+               return ret;
+
+       /*
+        * Now mark the region [128Mb - 128Kb, 128Mb[ as free too. This will
+        * expand the range covered by the existing extent entry that represents
+        * the free space [128Mb - 256Kb, 128Mb - 128Kb[.
+        */
+       ret = btrfs_add_free_space(cache, 128 * 1024 * 1024 - 128 * 1024,
+                                  128 * 1024);
+       if (ret) {
+               test_msg("Error adding free space: %d\n", ret);
+               return ret;
+       }
+       /* Confirm the region is marked as free. */
+       if (!test_check_exists(cache, 128 * 1024 * 1024 - 128 * 1024,
+                              128 * 1024)) {
+               test_msg("Extent region not marked as free\n");
+               return -ENOENT;
+       }
+
+       /*
+        * Confirm that our extent entry didn't stole all free space from the
+        * bitmap, because of the small 4Kb free space region.
+        */
+       ret = check_num_extents_and_bitmaps(cache, 2, 1);
+       if (ret)
+               return ret;
+
+       /*
+        * So now we have the range [128Mb - 256Kb, 128Mb + 768Kb[ as free
+        * space. Without stealing bitmap free space into extent entry space,
+        * we would have all this free space represented by 2 entries in the
+        * cache:
+        *
+        * extent entry covering range: [128Mb - 256Kb, 128Mb[
+        * bitmap entry covering range: [128Mb, 128Mb + 768Kb[
+        *
+        * Attempting to allocate the whole free space (1Mb) would fail, because
+        * we can't allocate from multiple entries.
+        * With the bitmap free space stealing, we get a single extent entry
+        * that represents the 1Mb free space, and therefore we're able to
+        * allocate the whole free space at once.
+        */
+       if (!test_check_exists(cache, 128 * 1024 * 1024 - 256 * 1024,
+                              1 * 1024 * 1024)) {
+               test_msg("Expected region not marked as free\n");
+               return -ENOENT;
+       }
+
+       if (cache->free_space_ctl->free_space != (1 * 1024 * 1024 + 4096)) {
+               test_msg("Cache free space is not 1Mb + 4Kb\n");
+               return -EINVAL;
+       }
+
+       offset = btrfs_find_space_for_alloc(cache,
+                                           0, 1 * 1024 * 1024, 0,
+                                           &max_extent_size);
+       if (offset != (128 * 1024 * 1024 - 256 * 1024)) {
+               test_msg("Failed to allocate 1Mb from space cache, returned offset is: %llu\n",
+                        offset);
+               return -EINVAL;
+       }
+
+       /* All that remains is a 4Kb free space region in a bitmap. Confirm. */
+       ret = check_num_extents_and_bitmaps(cache, 1, 1);
+       if (ret)
+               return ret;
+
+       if (cache->free_space_ctl->free_space != 4096) {
+               test_msg("Cache free space is not 4Kb\n");
+               return -EINVAL;
+       }
+
+       offset = btrfs_find_space_for_alloc(cache,
+                                           0, 4096, 0,
+                                           &max_extent_size);
+       if (offset != (128 * 1024 * 1024 + 16 * 1024 * 1024)) {
+               test_msg("Failed to allocate 4Kb from space cache, returned offset is: %llu\n",
+                        offset);
+               return -EINVAL;
+       }
+
+       ret = check_cache_empty(cache);
+       if (ret)
+               return ret;
+
+       __btrfs_remove_free_space_cache(cache->free_space_ctl);
+
+       /*
+        * Now test a similar scenario, but where our extent entry is located
+        * to the right of the bitmap entry, so that we can check that stealing
+        * space from a bitmap to the front of an extent entry works.
+        */
+
+       /*
+        * Extent entry covering free space range [128Mb + 128Kb, 128Mb + 256Kb[
+        */
+       ret = test_add_free_space_entry(cache, 128 * 1024 * 1024 + 128 * 1024,
+                                       128 * 1024, 0);
+       if (ret) {
+               test_msg("Couldn't add extent entry %d\n", ret);
+               return ret;
+       }
+
+       /* Bitmap entry covering free space range [0, 128Mb - 512Kb[ */
+       ret = test_add_free_space_entry(cache, 0,
+                                       128 * 1024 * 1024 - 512 * 1024, 1);
+       if (ret) {
+               test_msg("Couldn't add bitmap entry %d\n", ret);
+               return ret;
+       }
+
+       ret = check_num_extents_and_bitmaps(cache, 2, 1);
+       if (ret)
+               return ret;
+
+       /*
+        * Now make only the last 256Kb of the bitmap marked as free, so that
+        * we end up with only the following ranges marked as free space:
+        *
+        * [128Mb + 128b, 128Mb + 256Kb[
+        * [128Mb - 768Kb, 128Mb - 512Kb[
+        */
+       ret = btrfs_remove_free_space(cache,
+                                     0,
+                                     128 * 1024 * 1024 - 768 * 1024);
+       if (ret) {
+               test_msg("Failed to free part of bitmap space %d\n", ret);
+               return ret;
+       }
+
+       /* Confirm that only those 2 ranges are marked as free. */
+       if (!test_check_exists(cache, 128 * 1024 * 1024 + 128 * 1024,
+                              128 * 1024)) {
+               test_msg("Free space range missing\n");
+               return -ENOENT;
+       }
+       if (!test_check_exists(cache, 128 * 1024 * 1024 - 768 * 1024,
+                              256 * 1024)) {
+               test_msg("Free space range missing\n");
+               return -ENOENT;
+       }
+
+       /*
+        * Confirm that the bitmap range [0, 128Mb - 768Kb[ isn't marked
+        * as free anymore.
+        */
+       if (test_check_exists(cache, 0,
+                             128 * 1024 * 1024 - 768 * 1024)) {
+               test_msg("Bitmap region not removed from space cache\n");
+               return -EINVAL;
+       }
+
+       /*
+        * Confirm that the region [128Mb - 512Kb, 128Mb[, which is
+        * covered by the bitmap, isn't marked as free.
+        */
+       if (test_check_exists(cache, 128 * 1024 * 1024 - 512 * 1024,
+                             512 * 1024)) {
+               test_msg("Invalid bitmap region marked as free\n");
+               return -EINVAL;
+       }
+
+       /*
+        * Now lets mark the region [128Mb - 512Kb, 128Mb[ as free too. But,
+        * lets make sure the free space cache marks it as free in the bitmap,
+        * and doesn't insert a new extent entry to represent this region.
+        */
+       ret = btrfs_add_free_space(cache, 128 * 1024 * 1024 - 512 * 1024,
+                                  512 * 1024);
+       if (ret) {
+               test_msg("Error adding free space: %d\n", ret);
+               return ret;
+       }
+       /* Confirm the region is marked as free. */
+       if (!test_check_exists(cache, 128 * 1024 * 1024 - 512 * 1024,
+                              512 * 1024)) {
+               test_msg("Bitmap region not marked as free\n");
+               return -ENOENT;
+       }
+
+       /*
+        * Confirm that no new extent entries or bitmap entries were added to
+        * the cache after adding that free space region.
+        */
+       ret = check_num_extents_and_bitmaps(cache, 2, 1);
+       if (ret)
+               return ret;
+
+       /*
+        * Now lets add a small free space region to the left of the previous
+        * one, which is not contiguous with it and is part of the bitmap too.
+        * The goal is to test that the bitmap entry space stealing doesn't
+        * steal this space region.
+        */
+       ret = btrfs_add_free_space(cache, 32 * 1024 * 1024, 8192);
+       if (ret) {
+               test_msg("Error adding free space: %d\n", ret);
+               return ret;
+       }
+
+       /*
+        * Now mark the region [128Mb, 128Mb + 128Kb[ as free too. This will
+        * expand the range covered by the existing extent entry that represents
+        * the free space [128Mb + 128Kb, 128Mb + 256Kb[.
+        */
+       ret = btrfs_add_free_space(cache, 128 * 1024 * 1024, 128 * 1024);
+       if (ret) {
+               test_msg("Error adding free space: %d\n", ret);
+               return ret;
+       }
+       /* Confirm the region is marked as free. */
+       if (!test_check_exists(cache, 128 * 1024 * 1024, 128 * 1024)) {
+               test_msg("Extent region not marked as free\n");
+               return -ENOENT;
+       }
+
+       /*
+        * Confirm that our extent entry didn't stole all free space from the
+        * bitmap, because of the small 8Kb free space region.
+        */
+       ret = check_num_extents_and_bitmaps(cache, 2, 1);
+       if (ret)
+               return ret;
+
+       /*
+        * So now we have the range [128Mb - 768Kb, 128Mb + 256Kb[ as free
+        * space. Without stealing bitmap free space into extent entry space,
+        * we would have all this free space represented by 2 entries in the
+        * cache:
+        *
+        * extent entry covering range: [128Mb, 128Mb + 256Kb[
+        * bitmap entry covering range: [128Mb - 768Kb, 128Mb[
+        *
+        * Attempting to allocate the whole free space (1Mb) would fail, because
+        * we can't allocate from multiple entries.
+        * With the bitmap free space stealing, we get a single extent entry
+        * that represents the 1Mb free space, and therefore we're able to
+        * allocate the whole free space at once.
+        */
+       if (!test_check_exists(cache, 128 * 1024 * 1024 - 768 * 1024,
+                              1 * 1024 * 1024)) {
+               test_msg("Expected region not marked as free\n");
+               return -ENOENT;
+       }
+
+       if (cache->free_space_ctl->free_space != (1 * 1024 * 1024 + 8192)) {
+               test_msg("Cache free space is not 1Mb + 8Kb\n");
+               return -EINVAL;
+       }
+
+       offset = btrfs_find_space_for_alloc(cache,
+                                           0, 1 * 1024 * 1024, 0,
+                                           &max_extent_size);
+       if (offset != (128 * 1024 * 1024 - 768 * 1024)) {
+               test_msg("Failed to allocate 1Mb from space cache, returned offset is: %llu\n",
+                        offset);
+               return -EINVAL;
+       }
+
+       /* All that remains is a 8Kb free space region in a bitmap. Confirm. */
+       ret = check_num_extents_and_bitmaps(cache, 1, 1);
+       if (ret)
+               return ret;
+
+       if (cache->free_space_ctl->free_space != 8192) {
+               test_msg("Cache free space is not 8Kb\n");
+               return -EINVAL;
+       }
+
+       offset = btrfs_find_space_for_alloc(cache,
+                                           0, 8192, 0,
+                                           &max_extent_size);
+       if (offset != (32 * 1024 * 1024)) {
+               test_msg("Failed to allocate 8Kb from space cache, returned offset is: %llu\n",
+                        offset);
+               return -EINVAL;
+       }
+
+       ret = check_cache_empty(cache);
+       if (ret)
+               return ret;
+
+       cache->free_space_ctl->op->use_bitmap = use_bitmap_op;
+       __btrfs_remove_free_space_cache(cache->free_space_ctl);
+
+       return 0;
+}
+
 int btrfs_test_free_space_cache(void)
 {
        struct btrfs_block_group_cache *cache;
@@ -386,6 +898,8 @@ int btrfs_test_free_space_cache(void)
        ret = test_bitmaps_and_extents(cache);
        if (ret)
                goto out;
+
+       ret = test_steal_space_from_bitmap_to_extent(cache);
 out:
        __btrfs_remove_free_space_cache(cache->free_space_ctl);
        kfree(cache->free_space_ctl);
index d89c6d3542cab4c55372954ae97e9e32ec1ba443..dcaae36167288aff33fe679c99b18fc14130188f 100644 (file)
@@ -386,7 +386,7 @@ start_transaction(struct btrfs_root *root, u64 num_items, unsigned int type,
        int ret;
 
        /* Send isn't supposed to start transactions. */
-       ASSERT(current->journal_info != (void *)BTRFS_SEND_TRANS_STUB);
+       ASSERT(current->journal_info != BTRFS_SEND_TRANS_STUB);
 
        if (test_bit(BTRFS_FS_STATE_ERROR, &root->fs_info->fs_state))
                return ERR_PTR(-EROFS);
@@ -408,7 +408,7 @@ start_transaction(struct btrfs_root *root, u64 num_items, unsigned int type,
        if (num_items > 0 && root != root->fs_info->chunk_root) {
                if (root->fs_info->quota_enabled &&
                    is_fstree(root->root_key.objectid)) {
-                       qgroup_reserved = num_items * root->leafsize;
+                       qgroup_reserved = num_items * root->nodesize;
                        ret = btrfs_qgroup_reserve(root, qgroup_reserved);
                        if (ret)
                                return ERR_PTR(ret);
@@ -418,7 +418,7 @@ start_transaction(struct btrfs_root *root, u64 num_items, unsigned int type,
                /*
                 * Do the reservation for the relocation root creation
                 */
-               if (unlikely(need_reserve_reloc_root(root))) {
+               if (need_reserve_reloc_root(root)) {
                        num_bytes += root->nodesize;
                        reloc_reserved = true;
                }
@@ -609,7 +609,6 @@ int btrfs_wait_for_commit(struct btrfs_root *root, u64 transid)
                if (transid <= root->fs_info->last_trans_committed)
                        goto out;
 
-               ret = -EINVAL;
                /* find specified transaction */
                spin_lock(&root->fs_info->trans_lock);
                list_for_each_entry(t, &root->fs_info->trans_list, list) {
@@ -625,9 +624,16 @@ int btrfs_wait_for_commit(struct btrfs_root *root, u64 transid)
                        }
                }
                spin_unlock(&root->fs_info->trans_lock);
-               /* The specified transaction doesn't exist */
-               if (!cur_trans)
+
+               /*
+                * The specified transaction doesn't exist, or we
+                * raced with btrfs_commit_transaction
+                */
+               if (!cur_trans) {
+                       if (transid > root->fs_info->last_trans_committed)
+                               ret = -EINVAL;
                        goto out;
+               }
        } else {
                /* find newest transaction that is committing | committed */
                spin_lock(&root->fs_info->trans_lock);
@@ -851,6 +857,8 @@ int btrfs_wait_marked_extents(struct btrfs_root *root,
        struct extent_state *cached_state = NULL;
        u64 start = 0;
        u64 end;
+       struct btrfs_inode *btree_ino = BTRFS_I(root->fs_info->btree_inode);
+       bool errors = false;
 
        while (!find_first_extent_bit(dirty_pages, start, &start, &end,
                                      EXTENT_NEED_WAIT, &cached_state)) {
@@ -864,6 +872,26 @@ int btrfs_wait_marked_extents(struct btrfs_root *root,
        }
        if (err)
                werr = err;
+
+       if (root->root_key.objectid == BTRFS_TREE_LOG_OBJECTID) {
+               if ((mark & EXTENT_DIRTY) &&
+                   test_and_clear_bit(BTRFS_INODE_BTREE_LOG1_ERR,
+                                      &btree_ino->runtime_flags))
+                       errors = true;
+
+               if ((mark & EXTENT_NEW) &&
+                   test_and_clear_bit(BTRFS_INODE_BTREE_LOG2_ERR,
+                                      &btree_ino->runtime_flags))
+                       errors = true;
+       } else {
+               if (test_and_clear_bit(BTRFS_INODE_BTREE_ERR,
+                                      &btree_ino->runtime_flags))
+                       errors = true;
+       }
+
+       if (errors && !werr)
+               werr = -EIO;
+
        return werr;
 }
 
@@ -1629,6 +1657,7 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans,
 {
        struct btrfs_transaction *cur_trans = trans->transaction;
        struct btrfs_transaction *prev_trans = NULL;
+       struct btrfs_inode *btree_ino = BTRFS_I(root->fs_info->btree_inode);
        int ret;
 
        /* Stop the commit early if ->aborted is set */
@@ -1868,6 +1897,12 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans,
        memcpy(root->fs_info->super_for_commit, root->fs_info->super_copy,
               sizeof(*root->fs_info->super_copy));
 
+       btrfs_update_commit_device_size(root->fs_info);
+       btrfs_update_commit_device_bytes_used(root, cur_trans);
+
+       clear_bit(BTRFS_INODE_BTREE_LOG1_ERR, &btree_ino->runtime_flags);
+       clear_bit(BTRFS_INODE_BTREE_LOG2_ERR, &btree_ino->runtime_flags);
+
        spin_lock(&root->fs_info->trans_lock);
        cur_trans->state = TRANS_STATE_UNBLOCKED;
        root->fs_info->running_transaction = NULL;
@@ -1981,9 +2016,6 @@ int btrfs_clean_one_deleted_snapshot(struct btrfs_root *root)
                ret = btrfs_drop_snapshot(root, NULL, 0, 0);
        else
                ret = btrfs_drop_snapshot(root, NULL, 1, 0);
-       /*
-        * If we encounter a transaction abort during snapshot cleaning, we
-        * don't want to crash here
-        */
+
        return (ret < 0) ? 0 : 1;
 }
index 579be51b27e5ee0970feb4fb21ddf54a1d621a12..d8f40e1a5d2dc1b6dfd9ca24526eb7de2bd189f0 100644 (file)
@@ -79,7 +79,7 @@ struct btrfs_transaction {
 #define TRANS_EXTWRITERS       (__TRANS_USERSPACE | __TRANS_START |    \
                                 __TRANS_ATTACH)
 
-#define BTRFS_SEND_TRANS_STUB  1
+#define BTRFS_SEND_TRANS_STUB  ((void *)1)
 
 struct btrfs_trans_handle {
        u64 transid;
index d0262ceb85e10f2fe57237a9e3b52751c4012074..1475979e5718ab8727ad47f8c52898257c76b0ed 100644 (file)
@@ -97,7 +97,8 @@ static int btrfs_log_inode(struct btrfs_trans_handle *trans,
                           struct btrfs_root *root, struct inode *inode,
                           int inode_only,
                           const loff_t start,
-                          const loff_t end);
+                          const loff_t end,
+                          struct btrfs_log_ctx *ctx);
 static int link_to_fixup_dir(struct btrfs_trans_handle *trans,
                             struct btrfs_root *root,
                             struct btrfs_path *path, u64 objectid);
@@ -1498,7 +1499,7 @@ static noinline int link_to_fixup_dir(struct btrfs_trans_handle *trans,
                return -EIO;
 
        key.objectid = BTRFS_TREE_LOG_FIXUP_OBJECTID;
-       btrfs_set_key_type(&key, BTRFS_ORPHAN_ITEM_KEY);
+       key.type = BTRFS_ORPHAN_ITEM_KEY;
        key.offset = objectid;
 
        ret = btrfs_insert_empty_item(trans, root, path, &key, 0);
@@ -1637,6 +1638,7 @@ static noinline int replay_one_name(struct btrfs_trans_handle *trans,
            found_key.type == log_key.type &&
            found_key.offset == log_key.offset &&
            btrfs_dir_type(path->nodes[0], dst_di) == log_type) {
+               update_size = false;
                goto out;
        }
 
@@ -2157,7 +2159,7 @@ static noinline int walk_down_log_tree(struct btrfs_trans_handle *trans,
 
                bytenr = btrfs_node_blockptr(cur, path->slots[*level]);
                ptr_gen = btrfs_node_ptr_generation(cur, path->slots[*level]);
-               blocksize = btrfs_level_size(root, *level - 1);
+               blocksize = root->nodesize;
 
                parent = path->nodes[*level];
                root_owner = btrfs_header_owner(parent);
@@ -2983,8 +2985,6 @@ static noinline int log_dir_items(struct btrfs_trans_handle *trans,
        min_key.type = key_type;
        min_key.offset = min_offset;
 
-       path->keep_locks = 1;
-
        ret = btrfs_search_forward(root, &min_key, path, trans->transid);
 
        /*
@@ -3364,7 +3364,7 @@ static noinline int copy_items(struct btrfs_trans_handle *trans,
                 * or deletes of this inode don't have to relog the inode
                 * again
                 */
-               if (btrfs_key_type(ins_keys + i) == BTRFS_EXTENT_DATA_KEY &&
+               if (ins_keys[i].type == BTRFS_EXTENT_DATA_KEY &&
                    !skip_csum) {
                        int found_type;
                        extent = btrfs_item_ptr(src, start_slot + i,
@@ -3573,107 +3573,33 @@ static int extent_cmp(void *priv, struct list_head *a, struct list_head *b)
        return 0;
 }
 
-static int log_one_extent(struct btrfs_trans_handle *trans,
-                         struct inode *inode, struct btrfs_root *root,
-                         struct extent_map *em, struct btrfs_path *path,
-                         struct list_head *logged_list)
+static int wait_ordered_extents(struct btrfs_trans_handle *trans,
+                               struct inode *inode,
+                               struct btrfs_root *root,
+                               const struct extent_map *em,
+                               const struct list_head *logged_list,
+                               bool *ordered_io_error)
 {
-       struct btrfs_root *log = root->log_root;
-       struct btrfs_file_extent_item *fi;
-       struct extent_buffer *leaf;
        struct btrfs_ordered_extent *ordered;
-       struct list_head ordered_sums;
-       struct btrfs_map_token token;
-       struct btrfs_key key;
+       struct btrfs_root *log = root->log_root;
        u64 mod_start = em->mod_start;
        u64 mod_len = em->mod_len;
+       const bool skip_csum = BTRFS_I(inode)->flags & BTRFS_INODE_NODATASUM;
        u64 csum_offset;
        u64 csum_len;
-       u64 extent_offset = em->start - em->orig_start;
-       u64 block_len;
-       int ret;
-       bool skip_csum = BTRFS_I(inode)->flags & BTRFS_INODE_NODATASUM;
-       int extent_inserted = 0;
-
-       INIT_LIST_HEAD(&ordered_sums);
-       btrfs_init_map_token(&token);
-
-       ret = __btrfs_drop_extents(trans, log, inode, path, em->start,
-                                  em->start + em->len, NULL, 0, 1,
-                                  sizeof(*fi), &extent_inserted);
-       if (ret)
-               return ret;
-
-       if (!extent_inserted) {
-               key.objectid = btrfs_ino(inode);
-               key.type = BTRFS_EXTENT_DATA_KEY;
-               key.offset = em->start;
-
-               ret = btrfs_insert_empty_item(trans, log, path, &key,
-                                             sizeof(*fi));
-               if (ret)
-                       return ret;
-       }
-       leaf = path->nodes[0];
-       fi = btrfs_item_ptr(leaf, path->slots[0],
-                           struct btrfs_file_extent_item);
-
-       btrfs_set_token_file_extent_generation(leaf, fi, em->generation,
-                                              &token);
-       if (test_bit(EXTENT_FLAG_PREALLOC, &em->flags)) {
-               skip_csum = true;
-               btrfs_set_token_file_extent_type(leaf, fi,
-                                                BTRFS_FILE_EXTENT_PREALLOC,
-                                                &token);
-       } else {
-               btrfs_set_token_file_extent_type(leaf, fi,
-                                                BTRFS_FILE_EXTENT_REG,
-                                                &token);
-               if (em->block_start == EXTENT_MAP_HOLE)
-                       skip_csum = true;
-       }
-
-       block_len = max(em->block_len, em->orig_block_len);
-       if (em->compress_type != BTRFS_COMPRESS_NONE) {
-               btrfs_set_token_file_extent_disk_bytenr(leaf, fi,
-                                                       em->block_start,
-                                                       &token);
-               btrfs_set_token_file_extent_disk_num_bytes(leaf, fi, block_len,
-                                                          &token);
-       } else if (em->block_start < EXTENT_MAP_LAST_BYTE) {
-               btrfs_set_token_file_extent_disk_bytenr(leaf, fi,
-                                                       em->block_start -
-                                                       extent_offset, &token);
-               btrfs_set_token_file_extent_disk_num_bytes(leaf, fi, block_len,
-                                                          &token);
-       } else {
-               btrfs_set_token_file_extent_disk_bytenr(leaf, fi, 0, &token);
-               btrfs_set_token_file_extent_disk_num_bytes(leaf, fi, 0,
-                                                          &token);
-       }
-
-       btrfs_set_token_file_extent_offset(leaf, fi,
-                                          em->start - em->orig_start,
-                                          &token);
-       btrfs_set_token_file_extent_num_bytes(leaf, fi, em->len, &token);
-       btrfs_set_token_file_extent_ram_bytes(leaf, fi, em->ram_bytes, &token);
-       btrfs_set_token_file_extent_compression(leaf, fi, em->compress_type,
-                                               &token);
-       btrfs_set_token_file_extent_encryption(leaf, fi, 0, &token);
-       btrfs_set_token_file_extent_other_encoding(leaf, fi, 0, &token);
-       btrfs_mark_buffer_dirty(leaf);
+       LIST_HEAD(ordered_sums);
+       int ret = 0;
 
-       btrfs_release_path(path);
-       if (ret) {
-               return ret;
-       }
+       *ordered_io_error = false;
 
-       if (skip_csum)
+       if (test_bit(EXTENT_FLAG_PREALLOC, &em->flags) ||
+           em->block_start == EXTENT_MAP_HOLE)
                return 0;
 
        /*
-        * First check and see if our csums are on our outstanding ordered
-        * extents.
+        * Wait far any ordered extent that covers our extent map. If it
+        * finishes without an error, first check and see if our csums are on
+        * our outstanding ordered extents.
         */
        list_for_each_entry(ordered, logged_list, log_list) {
                struct btrfs_ordered_sum *sum;
@@ -3685,6 +3611,24 @@ static int log_one_extent(struct btrfs_trans_handle *trans,
                    mod_start + mod_len <= ordered->file_offset)
                        continue;
 
+               if (!test_bit(BTRFS_ORDERED_IO_DONE, &ordered->flags) &&
+                   !test_bit(BTRFS_ORDERED_IOERR, &ordered->flags) &&
+                   !test_bit(BTRFS_ORDERED_DIRECT, &ordered->flags)) {
+                       const u64 start = ordered->file_offset;
+                       const u64 end = ordered->file_offset + ordered->len - 1;
+
+                       WARN_ON(ordered->inode != inode);
+                       filemap_fdatawrite_range(inode->i_mapping, start, end);
+               }
+
+               wait_event(ordered->wait,
+                          (test_bit(BTRFS_ORDERED_IO_DONE, &ordered->flags) ||
+                           test_bit(BTRFS_ORDERED_IOERR, &ordered->flags)));
+
+               if (test_bit(BTRFS_ORDERED_IOERR, &ordered->flags)) {
+                       *ordered_io_error = true;
+                       break;
+               }
                /*
                 * We are going to copy all the csums on this ordered extent, so
                 * go ahead and adjust mod_start and mod_len in case this
@@ -3716,6 +3660,9 @@ static int log_one_extent(struct btrfs_trans_handle *trans,
                        }
                }
 
+               if (skip_csum)
+                       continue;
+
                /*
                 * To keep us from looping for the above case of an ordered
                 * extent that falls inside of the logged extent.
@@ -3733,18 +3680,16 @@ static int log_one_extent(struct btrfs_trans_handle *trans,
                list_for_each_entry(sum, &ordered->list, list) {
                        ret = btrfs_csum_file_blocks(trans, log, sum);
                        if (ret)
-                               goto unlocked;
+                               break;
                }
-
        }
-unlocked:
 
-       if (!mod_len || ret)
+       if (*ordered_io_error || !mod_len || ret || skip_csum)
                return ret;
 
        if (em->compress_type) {
                csum_offset = 0;
-               csum_len = block_len;
+               csum_len = max(em->block_len, em->orig_block_len);
        } else {
                csum_offset = mod_start - em->start;
                csum_len = mod_len;
@@ -3771,11 +3716,106 @@ unlocked:
        return ret;
 }
 
+static int log_one_extent(struct btrfs_trans_handle *trans,
+                         struct inode *inode, struct btrfs_root *root,
+                         const struct extent_map *em,
+                         struct btrfs_path *path,
+                         const struct list_head *logged_list,
+                         struct btrfs_log_ctx *ctx)
+{
+       struct btrfs_root *log = root->log_root;
+       struct btrfs_file_extent_item *fi;
+       struct extent_buffer *leaf;
+       struct btrfs_map_token token;
+       struct btrfs_key key;
+       u64 extent_offset = em->start - em->orig_start;
+       u64 block_len;
+       int ret;
+       int extent_inserted = 0;
+       bool ordered_io_err = false;
+
+       ret = wait_ordered_extents(trans, inode, root, em, logged_list,
+                                  &ordered_io_err);
+       if (ret)
+               return ret;
+
+       if (ordered_io_err) {
+               ctx->io_err = -EIO;
+               return 0;
+       }
+
+       btrfs_init_map_token(&token);
+
+       ret = __btrfs_drop_extents(trans, log, inode, path, em->start,
+                                  em->start + em->len, NULL, 0, 1,
+                                  sizeof(*fi), &extent_inserted);
+       if (ret)
+               return ret;
+
+       if (!extent_inserted) {
+               key.objectid = btrfs_ino(inode);
+               key.type = BTRFS_EXTENT_DATA_KEY;
+               key.offset = em->start;
+
+               ret = btrfs_insert_empty_item(trans, log, path, &key,
+                                             sizeof(*fi));
+               if (ret)
+                       return ret;
+       }
+       leaf = path->nodes[0];
+       fi = btrfs_item_ptr(leaf, path->slots[0],
+                           struct btrfs_file_extent_item);
+
+       btrfs_set_token_file_extent_generation(leaf, fi, em->generation,
+                                              &token);
+       if (test_bit(EXTENT_FLAG_PREALLOC, &em->flags))
+               btrfs_set_token_file_extent_type(leaf, fi,
+                                                BTRFS_FILE_EXTENT_PREALLOC,
+                                                &token);
+       else
+               btrfs_set_token_file_extent_type(leaf, fi,
+                                                BTRFS_FILE_EXTENT_REG,
+                                                &token);
+
+       block_len = max(em->block_len, em->orig_block_len);
+       if (em->compress_type != BTRFS_COMPRESS_NONE) {
+               btrfs_set_token_file_extent_disk_bytenr(leaf, fi,
+                                                       em->block_start,
+                                                       &token);
+               btrfs_set_token_file_extent_disk_num_bytes(leaf, fi, block_len,
+                                                          &token);
+       } else if (em->block_start < EXTENT_MAP_LAST_BYTE) {
+               btrfs_set_token_file_extent_disk_bytenr(leaf, fi,
+                                                       em->block_start -
+                                                       extent_offset, &token);
+               btrfs_set_token_file_extent_disk_num_bytes(leaf, fi, block_len,
+                                                          &token);
+       } else {
+               btrfs_set_token_file_extent_disk_bytenr(leaf, fi, 0, &token);
+               btrfs_set_token_file_extent_disk_num_bytes(leaf, fi, 0,
+                                                          &token);
+       }
+
+       btrfs_set_token_file_extent_offset(leaf, fi, extent_offset, &token);
+       btrfs_set_token_file_extent_num_bytes(leaf, fi, em->len, &token);
+       btrfs_set_token_file_extent_ram_bytes(leaf, fi, em->ram_bytes, &token);
+       btrfs_set_token_file_extent_compression(leaf, fi, em->compress_type,
+                                               &token);
+       btrfs_set_token_file_extent_encryption(leaf, fi, 0, &token);
+       btrfs_set_token_file_extent_other_encoding(leaf, fi, 0, &token);
+       btrfs_mark_buffer_dirty(leaf);
+
+       btrfs_release_path(path);
+
+       return ret;
+}
+
 static int btrfs_log_changed_extents(struct btrfs_trans_handle *trans,
                                     struct btrfs_root *root,
                                     struct inode *inode,
                                     struct btrfs_path *path,
-                                    struct list_head *logged_list)
+                                    struct list_head *logged_list,
+                                    struct btrfs_log_ctx *ctx)
 {
        struct extent_map *em, *n;
        struct list_head extents;
@@ -3833,7 +3873,8 @@ process:
 
                write_unlock(&tree->lock);
 
-               ret = log_one_extent(trans, inode, root, em, path, logged_list);
+               ret = log_one_extent(trans, inode, root, em, path, logged_list,
+                                    ctx);
                write_lock(&tree->lock);
                clear_em_logging(tree, em);
                free_extent_map(em);
@@ -3863,7 +3904,8 @@ static int btrfs_log_inode(struct btrfs_trans_handle *trans,
                           struct btrfs_root *root, struct inode *inode,
                           int inode_only,
                           const loff_t start,
-                          const loff_t end)
+                          const loff_t end,
+                          struct btrfs_log_ctx *ctx)
 {
        struct btrfs_path *path;
        struct btrfs_path *dst_path;
@@ -3964,7 +4006,6 @@ static int btrfs_log_inode(struct btrfs_trans_handle *trans,
                err = ret;
                goto out_unlock;
        }
-       path->keep_locks = 1;
 
        while (1) {
                ins_nr = 0;
@@ -4049,7 +4090,7 @@ log_extents:
        btrfs_release_path(dst_path);
        if (fast_search) {
                ret = btrfs_log_changed_extents(trans, root, inode, dst_path,
-                                               &logged_list);
+                                               &logged_list, ctx);
                if (ret) {
                        err = ret;
                        goto out_unlock;
@@ -4239,7 +4280,7 @@ static int btrfs_log_inode_parent(struct btrfs_trans_handle *trans,
        if (ret)
                goto end_no_trans;
 
-       ret = btrfs_log_inode(trans, root, inode, inode_only, start, end);
+       ret = btrfs_log_inode(trans, root, inode, inode_only, start, end, ctx);
        if (ret)
                goto end_trans;
 
@@ -4268,7 +4309,7 @@ static int btrfs_log_inode_parent(struct btrfs_trans_handle *trans,
                if (BTRFS_I(inode)->generation >
                    root->fs_info->last_trans_committed) {
                        ret = btrfs_log_inode(trans, root, inode, inode_only,
-                                             0, LLONG_MAX);
+                                             0, LLONG_MAX, ctx);
                        if (ret)
                                goto end_trans;
                }
@@ -4360,7 +4401,7 @@ int btrfs_recover_log_trees(struct btrfs_root *log_root_tree)
 again:
        key.objectid = BTRFS_TREE_LOG_OBJECTID;
        key.offset = (u64)-1;
-       btrfs_set_key_type(&key, BTRFS_ROOT_ITEM_KEY);
+       key.type = BTRFS_ROOT_ITEM_KEY;
 
        while (1) {
                ret = btrfs_search_slot(NULL, log_root_tree, &key, path, 0, 0);
index e2e798ae7cd7c6c989a6633fe7dae682ab4a5148..154990c26dcbc9d63508228b9125182b7168b80e 100644 (file)
@@ -28,6 +28,7 @@
 struct btrfs_log_ctx {
        int log_ret;
        int log_transid;
+       int io_err;
        struct list_head list;
 };
 
@@ -35,6 +36,7 @@ static inline void btrfs_init_log_ctx(struct btrfs_log_ctx *ctx)
 {
        ctx->log_ret = 0;
        ctx->log_transid = 0;
+       ctx->io_err = 0;
        INIT_LIST_HEAD(&ctx->list);
 }
 
index f6a4c03ee7d8fc1cf3aedc3f2b8edf0007992ff7..778282944530f6baba8a27037e191d28922421a1 100644 (file)
@@ -279,7 +279,6 @@ int btrfs_uuid_tree_iterate(struct btrfs_fs_info *fs_info,
        key.offset = 0;
 
 again_search_slot:
-       path->keep_locks = 1;
        ret = btrfs_search_forward(root, &key, path, 0);
        if (ret) {
                if (ret > 0)
index 2c2d6d1d8eee929fc910a82cd17fbec79803cbb2..d47289c715c814f47c7842349afc942640310238 100644 (file)
@@ -50,7 +50,7 @@ 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 DEFINE_MUTEX(uuid_mutex);
+DEFINE_MUTEX(uuid_mutex);
 static LIST_HEAD(fs_uuids);
 
 static void lock_chunks(struct btrfs_root *root)
@@ -74,6 +74,7 @@ static struct btrfs_fs_devices *__alloc_fs_devices(void)
        mutex_init(&fs_devs->device_list_mutex);
 
        INIT_LIST_HEAD(&fs_devs->devices);
+       INIT_LIST_HEAD(&fs_devs->resized_devices);
        INIT_LIST_HEAD(&fs_devs->alloc_list);
        INIT_LIST_HEAD(&fs_devs->list);
 
@@ -154,11 +155,13 @@ static struct btrfs_device *__alloc_device(void)
 
        INIT_LIST_HEAD(&dev->dev_list);
        INIT_LIST_HEAD(&dev->dev_alloc_list);
+       INIT_LIST_HEAD(&dev->resized_list);
 
        spin_lock_init(&dev->io_lock);
 
        spin_lock_init(&dev->reada_lock);
        atomic_set(&dev->reada_in_flight, 0);
+       atomic_set(&dev->dev_stats_ccnt, 0);
        INIT_RADIX_TREE(&dev->reada_zones, GFP_NOFS & ~__GFP_WAIT);
        INIT_RADIX_TREE(&dev->reada_extents, GFP_NOFS & ~__GFP_WAIT);
 
@@ -474,14 +477,13 @@ static noinline int device_list_add(const char *path,
                        return PTR_ERR(fs_devices);
 
                list_add(&fs_devices->list, &fs_uuids);
-               fs_devices->latest_devid = devid;
-               fs_devices->latest_trans = found_transid;
 
                device = NULL;
        } else {
                device = __find_device(&fs_devices->devices, devid,
                                       disk_super->dev_item.uuid);
        }
+
        if (!device) {
                if (fs_devices->opened)
                        return -EBUSY;
@@ -565,10 +567,6 @@ static noinline int device_list_add(const char *path,
        if (!fs_devices->opened)
                device->generation = found_transid;
 
-       if (found_transid > fs_devices->latest_trans) {
-               fs_devices->latest_devid = devid;
-               fs_devices->latest_trans = found_transid;
-       }
        *fs_devices_ret = fs_devices;
 
        return ret;
@@ -584,8 +582,7 @@ static struct btrfs_fs_devices *clone_fs_devices(struct btrfs_fs_devices *orig)
        if (IS_ERR(fs_devices))
                return fs_devices;
 
-       fs_devices->latest_devid = orig->latest_devid;
-       fs_devices->latest_trans = orig->latest_trans;
+       mutex_lock(&orig->device_list_mutex);
        fs_devices->total_devices = orig->total_devices;
 
        /* We have held the volume lock, it is safe to get the devices. */
@@ -614,8 +611,10 @@ static struct btrfs_fs_devices *clone_fs_devices(struct btrfs_fs_devices *orig)
                device->fs_devices = fs_devices;
                fs_devices->num_devices++;
        }
+       mutex_unlock(&orig->device_list_mutex);
        return fs_devices;
 error:
+       mutex_unlock(&orig->device_list_mutex);
        free_fs_devices(fs_devices);
        return ERR_PTR(-ENOMEM);
 }
@@ -624,10 +623,7 @@ void btrfs_close_extra_devices(struct btrfs_fs_info *fs_info,
                               struct btrfs_fs_devices *fs_devices, int step)
 {
        struct btrfs_device *device, *next;
-
-       struct block_device *latest_bdev = NULL;
-       u64 latest_devid = 0;
-       u64 latest_transid = 0;
+       struct btrfs_device *latest_dev = NULL;
 
        mutex_lock(&uuid_mutex);
 again:
@@ -635,11 +631,9 @@ again:
        list_for_each_entry_safe(device, next, &fs_devices->devices, dev_list) {
                if (device->in_fs_metadata) {
                        if (!device->is_tgtdev_for_dev_replace &&
-                           (!latest_transid ||
-                            device->generation > latest_transid)) {
-                               latest_devid = device->devid;
-                               latest_transid = device->generation;
-                               latest_bdev = device->bdev;
+                           (!latest_dev ||
+                            device->generation > latest_dev->generation)) {
+                               latest_dev = device;
                        }
                        continue;
                }
@@ -681,9 +675,7 @@ again:
                goto again;
        }
 
-       fs_devices->latest_bdev = latest_bdev;
-       fs_devices->latest_devid = latest_devid;
-       fs_devices->latest_trans = latest_transid;
+       fs_devices->latest_bdev = latest_dev->bdev;
 
        mutex_unlock(&uuid_mutex);
 }
@@ -732,8 +724,6 @@ static int __btrfs_close_devices(struct btrfs_fs_devices *fs_devices)
                        fs_devices->rw_devices--;
                }
 
-               if (device->can_discard)
-                       fs_devices->num_can_discard--;
                if (device->missing)
                        fs_devices->missing_devices--;
 
@@ -798,11 +788,9 @@ static int __btrfs_open_devices(struct btrfs_fs_devices *fs_devices,
        struct block_device *bdev;
        struct list_head *head = &fs_devices->devices;
        struct btrfs_device *device;
-       struct block_device *latest_bdev = NULL;
+       struct btrfs_device *latest_dev = NULL;
        struct buffer_head *bh;
        struct btrfs_super_block *disk_super;
-       u64 latest_devid = 0;
-       u64 latest_transid = 0;
        u64 devid;
        int seeding = 1;
        int ret = 0;
@@ -830,11 +818,9 @@ static int __btrfs_open_devices(struct btrfs_fs_devices *fs_devices,
                        goto error_brelse;
 
                device->generation = btrfs_super_generation(disk_super);
-               if (!latest_transid || device->generation > latest_transid) {
-                       latest_devid = devid;
-                       latest_transid = device->generation;
-                       latest_bdev = bdev;
-               }
+               if (!latest_dev ||
+                   device->generation > latest_dev->generation)
+                       latest_dev = device;
 
                if (btrfs_super_flags(disk_super) & BTRFS_SUPER_FLAG_SEEDING) {
                        device->writeable = 0;
@@ -844,10 +830,8 @@ static int __btrfs_open_devices(struct btrfs_fs_devices *fs_devices,
                }
 
                q = bdev_get_queue(bdev);
-               if (blk_queue_discard(q)) {
+               if (blk_queue_discard(q))
                        device->can_discard = 1;
-                       fs_devices->num_can_discard++;
-               }
 
                device->bdev = bdev;
                device->in_fs_metadata = 0;
@@ -877,9 +861,7 @@ error_brelse:
        }
        fs_devices->seeding = seeding;
        fs_devices->opened = 1;
-       fs_devices->latest_bdev = latest_bdev;
-       fs_devices->latest_devid = latest_devid;
-       fs_devices->latest_trans = latest_transid;
+       fs_devices->latest_bdev = latest_dev->bdev;
        fs_devices->total_rw_bytes = 0;
 out:
        return ret;
@@ -1053,7 +1035,7 @@ int btrfs_account_dev_extents_size(struct btrfs_device *device, u64 start,
                if (key.objectid > device->devid)
                        break;
 
-               if (btrfs_key_type(&key) != BTRFS_DEV_EXTENT_KEY)
+               if (key.type != BTRFS_DEV_EXTENT_KEY)
                        goto next;
 
                dev_extent = btrfs_item_ptr(l, slot, struct btrfs_dev_extent);
@@ -1205,7 +1187,7 @@ again:
                if (key.objectid > device->devid)
                        break;
 
-               if (btrfs_key_type(&key) != BTRFS_DEV_EXTENT_KEY)
+               if (key.type != BTRFS_DEV_EXTENT_KEY)
                        goto next;
 
                if (key.offset > search_start) {
@@ -1284,7 +1266,7 @@ out:
 
 static int btrfs_free_dev_extent(struct btrfs_trans_handle *trans,
                          struct btrfs_device *device,
-                         u64 start)
+                         u64 start, u64 *dev_extent_len)
 {
        int ret;
        struct btrfs_path *path;
@@ -1326,13 +1308,8 @@ again:
                goto out;
        }
 
-       if (device->bytes_used > 0) {
-               u64 len = btrfs_dev_extent_length(leaf, extent);
-               device->bytes_used -= len;
-               spin_lock(&root->fs_info->free_chunk_lock);
-               root->fs_info->free_chunk_space += len;
-               spin_unlock(&root->fs_info->free_chunk_lock);
-       }
+       *dev_extent_len = btrfs_dev_extent_length(leaf, extent);
+
        ret = btrfs_del_item(trans, root, path);
        if (ret) {
                btrfs_error(root->fs_info, ret,
@@ -1482,8 +1459,10 @@ static int btrfs_add_device(struct btrfs_trans_handle *trans,
        btrfs_set_device_io_align(leaf, dev_item, device->io_align);
        btrfs_set_device_io_width(leaf, dev_item, device->io_width);
        btrfs_set_device_sector_size(leaf, dev_item, device->sector_size);
-       btrfs_set_device_total_bytes(leaf, dev_item, device->disk_total_bytes);
-       btrfs_set_device_bytes_used(leaf, dev_item, device->bytes_used);
+       btrfs_set_device_total_bytes(leaf, dev_item,
+                                    btrfs_device_get_disk_total_bytes(device));
+       btrfs_set_device_bytes_used(leaf, dev_item,
+                                   btrfs_device_get_bytes_used(device));
        btrfs_set_device_group(leaf, dev_item, 0);
        btrfs_set_device_seek_speed(leaf, dev_item, 0);
        btrfs_set_device_bandwidth(leaf, dev_item, 0);
@@ -1539,7 +1518,6 @@ static int btrfs_rm_dev_item(struct btrfs_root *root,
        key.objectid = BTRFS_DEV_ITEMS_OBJECTID;
        key.type = BTRFS_DEV_ITEM_KEY;
        key.offset = device->devid;
-       lock_chunks(root);
 
        ret = btrfs_search_slot(trans, root, &key, path, -1, 1);
        if (ret < 0)
@@ -1555,7 +1533,6 @@ static int btrfs_rm_dev_item(struct btrfs_root *root,
                goto out;
 out:
        btrfs_free_path(path);
-       unlock_chunks(root);
        btrfs_commit_transaction(trans, root);
        return ret;
 }
@@ -1671,8 +1648,8 @@ int btrfs_rm_device(struct btrfs_root *root, char *device_path)
        if (device->writeable) {
                lock_chunks(root);
                list_del_init(&device->dev_alloc_list);
+               device->fs_devices->rw_devices--;
                unlock_chunks(root);
-               root->fs_info->fs_devices->rw_devices--;
                clear_super = true;
        }
 
@@ -1691,11 +1668,6 @@ int btrfs_rm_device(struct btrfs_root *root, char *device_path)
        if (ret)
                goto error_undo;
 
-       spin_lock(&root->fs_info->free_chunk_lock);
-       root->fs_info->free_chunk_space = device->total_bytes -
-               device->bytes_used;
-       spin_unlock(&root->fs_info->free_chunk_lock);
-
        device->in_fs_metadata = 0;
        btrfs_scrub_cancel_dev(root->fs_info, device);
 
@@ -1749,9 +1721,7 @@ int btrfs_rm_device(struct btrfs_root *root, char *device_path)
                        fs_devices = fs_devices->seed;
                }
                cur_devices->seed = NULL;
-               lock_chunks(root);
                __btrfs_close_devices(cur_devices);
-               unlock_chunks(root);
                free_fs_devices(cur_devices);
        }
 
@@ -1824,8 +1794,8 @@ error_undo:
                lock_chunks(root);
                list_add(&device->dev_alloc_list,
                         &root->fs_info->fs_devices->alloc_list);
+               device->fs_devices->rw_devices++;
                unlock_chunks(root);
-               root->fs_info->fs_devices->rw_devices++;
        }
        goto error_brelse;
 }
@@ -1833,29 +1803,57 @@ error_undo:
 void btrfs_rm_dev_replace_srcdev(struct btrfs_fs_info *fs_info,
                                 struct btrfs_device *srcdev)
 {
+       struct btrfs_fs_devices *fs_devices;
+
        WARN_ON(!mutex_is_locked(&fs_info->fs_devices->device_list_mutex));
 
+       /*
+        * in case of fs with no seed, srcdev->fs_devices will point
+        * to fs_devices of fs_info. However when the dev being replaced is
+        * a seed dev it will point to the seed's local fs_devices. In short
+        * srcdev will have its correct fs_devices in both the cases.
+        */
+       fs_devices = srcdev->fs_devices;
+
        list_del_rcu(&srcdev->dev_list);
        list_del_rcu(&srcdev->dev_alloc_list);
-       fs_info->fs_devices->num_devices--;
-       if (srcdev->missing) {
-               fs_info->fs_devices->missing_devices--;
-               fs_info->fs_devices->rw_devices++;
-       }
-       if (srcdev->can_discard)
-               fs_info->fs_devices->num_can_discard--;
-       if (srcdev->bdev) {
-               fs_info->fs_devices->open_devices--;
+       fs_devices->num_devices--;
+       if (srcdev->missing)
+               fs_devices->missing_devices--;
 
-               /*
-                * zero out the old super if it is not writable
-                * (e.g. seed device)
-                */
-               if (srcdev->writeable)
-                       btrfs_scratch_superblock(srcdev);
+       if (srcdev->writeable) {
+               fs_devices->rw_devices--;
+               /* zero out the old super if it is writable */
+               btrfs_scratch_superblock(srcdev);
        }
 
+       if (srcdev->bdev)
+               fs_devices->open_devices--;
+
        call_rcu(&srcdev->rcu, free_device);
+
+       /*
+        * unless fs_devices is seed fs, num_devices shouldn't go
+        * zero
+        */
+       BUG_ON(!fs_devices->num_devices && !fs_devices->seeding);
+
+       /* if this is no devs we rather delete the fs_devices */
+       if (!fs_devices->num_devices) {
+               struct btrfs_fs_devices *tmp_fs_devices;
+
+               tmp_fs_devices = fs_info->fs_devices;
+               while (tmp_fs_devices) {
+                       if (tmp_fs_devices->seed == fs_devices) {
+                               tmp_fs_devices->seed = fs_devices->seed;
+                               break;
+                       }
+                       tmp_fs_devices = tmp_fs_devices->seed;
+               }
+               fs_devices->seed = NULL;
+               __btrfs_close_devices(fs_devices);
+               free_fs_devices(fs_devices);
+       }
 }
 
 void btrfs_destroy_dev_replace_tgtdev(struct btrfs_fs_info *fs_info,
@@ -1863,6 +1861,7 @@ void btrfs_destroy_dev_replace_tgtdev(struct btrfs_fs_info *fs_info,
 {
        struct btrfs_device *next_device;
 
+       mutex_lock(&uuid_mutex);
        WARN_ON(!tgtdev);
        mutex_lock(&fs_info->fs_devices->device_list_mutex);
        if (tgtdev->bdev) {
@@ -1870,8 +1869,6 @@ void btrfs_destroy_dev_replace_tgtdev(struct btrfs_fs_info *fs_info,
                fs_info->fs_devices->open_devices--;
        }
        fs_info->fs_devices->num_devices--;
-       if (tgtdev->can_discard)
-               fs_info->fs_devices->num_can_discard++;
 
        next_device = list_entry(fs_info->fs_devices->devices.next,
                                 struct btrfs_device, dev_list);
@@ -1884,6 +1881,7 @@ void btrfs_destroy_dev_replace_tgtdev(struct btrfs_fs_info *fs_info,
        call_rcu(&tgtdev->rcu, free_device);
 
        mutex_unlock(&fs_info->fs_devices->device_list_mutex);
+       mutex_unlock(&uuid_mutex);
 }
 
 static int btrfs_find_device_by_path(struct btrfs_root *root, char *device_path,
@@ -1982,17 +1980,17 @@ static int btrfs_prepare_sprout(struct btrfs_root *root)
        mutex_lock(&root->fs_info->fs_devices->device_list_mutex);
        list_splice_init_rcu(&fs_devices->devices, &seed_devices->devices,
                              synchronize_rcu);
+       list_for_each_entry(device, &seed_devices->devices, dev_list)
+               device->fs_devices = seed_devices;
 
+       lock_chunks(root);
        list_splice_init(&fs_devices->alloc_list, &seed_devices->alloc_list);
-       list_for_each_entry(device, &seed_devices->devices, dev_list) {
-               device->fs_devices = seed_devices;
-       }
+       unlock_chunks(root);
 
        fs_devices->seeding = 0;
        fs_devices->num_devices = 0;
        fs_devices->open_devices = 0;
        fs_devices->missing_devices = 0;
-       fs_devices->num_can_discard = 0;
        fs_devices->rotating = 0;
        fs_devices->seed = seed_devices;
 
@@ -2092,7 +2090,7 @@ int btrfs_init_new_device(struct btrfs_root *root, char *device_path)
        struct list_head *devices;
        struct super_block *sb = root->fs_info->sb;
        struct rcu_string *name;
-       u64 total_bytes;
+       u64 tmp;
        int seeding_dev = 0;
        int ret = 0;
 
@@ -2148,8 +2146,6 @@ int btrfs_init_new_device(struct btrfs_root *root, char *device_path)
                goto error;
        }
 
-       lock_chunks(root);
-
        q = bdev_get_queue(bdev);
        if (blk_queue_discard(q))
                device->can_discard = 1;
@@ -2160,6 +2156,7 @@ int btrfs_init_new_device(struct btrfs_root *root, char *device_path)
        device->sector_size = root->sectorsize;
        device->total_bytes = i_size_read(bdev->bd_inode);
        device->disk_total_bytes = device->total_bytes;
+       device->commit_total_bytes = device->total_bytes;
        device->dev_root = root->fs_info->dev_root;
        device->bdev = bdev;
        device->in_fs_metadata = 1;
@@ -2177,6 +2174,7 @@ int btrfs_init_new_device(struct btrfs_root *root, char *device_path)
        device->fs_devices = root->fs_info->fs_devices;
 
        mutex_lock(&root->fs_info->fs_devices->device_list_mutex);
+       lock_chunks(root);
        list_add_rcu(&device->dev_list, &root->fs_info->fs_devices->devices);
        list_add(&device->dev_alloc_list,
                 &root->fs_info->fs_devices->alloc_list);
@@ -2184,8 +2182,6 @@ int btrfs_init_new_device(struct btrfs_root *root, char *device_path)
        root->fs_info->fs_devices->open_devices++;
        root->fs_info->fs_devices->rw_devices++;
        root->fs_info->fs_devices->total_devices++;
-       if (device->can_discard)
-               root->fs_info->fs_devices->num_can_discard++;
        root->fs_info->fs_devices->total_rw_bytes += device->total_bytes;
 
        spin_lock(&root->fs_info->free_chunk_lock);
@@ -2195,26 +2191,45 @@ int btrfs_init_new_device(struct btrfs_root *root, char *device_path)
        if (!blk_queue_nonrot(bdev_get_queue(bdev)))
                root->fs_info->fs_devices->rotating = 1;
 
-       total_bytes = btrfs_super_total_bytes(root->fs_info->super_copy);
+       tmp = btrfs_super_total_bytes(root->fs_info->super_copy);
        btrfs_set_super_total_bytes(root->fs_info->super_copy,
-                                   total_bytes + device->total_bytes);
+                                   tmp + device->total_bytes);
 
-       total_bytes = btrfs_super_num_devices(root->fs_info->super_copy);
+       tmp = btrfs_super_num_devices(root->fs_info->super_copy);
        btrfs_set_super_num_devices(root->fs_info->super_copy,
-                                   total_bytes + 1);
+                                   tmp + 1);
 
        /* add sysfs device entry */
        btrfs_kobj_add_device(root->fs_info, device);
 
+       /*
+        * we've got more storage, clear any full flags on the space
+        * infos
+        */
+       btrfs_clear_space_info_full(root->fs_info);
+
+       unlock_chunks(root);
        mutex_unlock(&root->fs_info->fs_devices->device_list_mutex);
 
        if (seeding_dev) {
-               char fsid_buf[BTRFS_UUID_UNPARSED_SIZE];
+               lock_chunks(root);
                ret = init_first_rw_device(trans, root, device);
+               unlock_chunks(root);
                if (ret) {
                        btrfs_abort_transaction(trans, root, ret);
                        goto error_trans;
                }
+       }
+
+       ret = btrfs_add_device(trans, root, device);
+       if (ret) {
+               btrfs_abort_transaction(trans, root, ret);
+               goto error_trans;
+       }
+
+       if (seeding_dev) {
+               char fsid_buf[BTRFS_UUID_UNPARSED_SIZE];
+
                ret = btrfs_finish_sprout(trans, root);
                if (ret) {
                        btrfs_abort_transaction(trans, root, ret);
@@ -2228,21 +2243,8 @@ int btrfs_init_new_device(struct btrfs_root *root, char *device_path)
                                                root->fs_info->fsid);
                if (kobject_rename(&root->fs_info->super_kobj, fsid_buf))
                        goto error_trans;
-       } else {
-               ret = btrfs_add_device(trans, root, device);
-               if (ret) {
-                       btrfs_abort_transaction(trans, root, ret);
-                       goto error_trans;
-               }
        }
 
-       /*
-        * we've got more storage, clear any full flags on the space
-        * infos
-        */
-       btrfs_clear_space_info_full(root->fs_info);
-
-       unlock_chunks(root);
        root->fs_info->num_tolerated_disk_barrier_failures =
                btrfs_calc_num_tolerated_disk_barrier_failures(root->fs_info);
        ret = btrfs_commit_transaction(trans, root);
@@ -2274,7 +2276,6 @@ int btrfs_init_new_device(struct btrfs_root *root, char *device_path)
        return ret;
 
 error_trans:
-       unlock_chunks(root);
        btrfs_end_transaction(trans, root);
        rcu_string_free(device->name);
        btrfs_kobj_rm_device(root->fs_info, device);
@@ -2289,6 +2290,7 @@ error:
 }
 
 int btrfs_init_dev_replace_tgtdev(struct btrfs_root *root, char *device_path,
+                                 struct btrfs_device *srcdev,
                                  struct btrfs_device **device_out)
 {
        struct request_queue *q;
@@ -2301,24 +2303,38 @@ int btrfs_init_dev_replace_tgtdev(struct btrfs_root *root, char *device_path,
        int ret = 0;
 
        *device_out = NULL;
-       if (fs_info->fs_devices->seeding)
+       if (fs_info->fs_devices->seeding) {
+               btrfs_err(fs_info, "the filesystem is a seed filesystem!");
                return -EINVAL;
+       }
 
        bdev = blkdev_get_by_path(device_path, FMODE_WRITE | FMODE_EXCL,
                                  fs_info->bdev_holder);
-       if (IS_ERR(bdev))
+       if (IS_ERR(bdev)) {
+               btrfs_err(fs_info, "target device %s is invalid!", device_path);
                return PTR_ERR(bdev);
+       }
 
        filemap_write_and_wait(bdev->bd_inode->i_mapping);
 
        devices = &fs_info->fs_devices->devices;
        list_for_each_entry(device, devices, dev_list) {
                if (device->bdev == bdev) {
+                       btrfs_err(fs_info, "target device is in the filesystem!");
                        ret = -EEXIST;
                        goto error;
                }
        }
 
+
+       if (i_size_read(bdev->bd_inode) <
+           btrfs_device_get_total_bytes(srcdev)) {
+               btrfs_err(fs_info, "target device is smaller than source device!");
+               ret = -EINVAL;
+               goto error;
+       }
+
+
        device = btrfs_alloc_device(NULL, &devid, NULL);
        if (IS_ERR(device)) {
                ret = PTR_ERR(device);
@@ -2342,8 +2358,12 @@ int btrfs_init_dev_replace_tgtdev(struct btrfs_root *root, char *device_path,
        device->io_width = root->sectorsize;
        device->io_align = root->sectorsize;
        device->sector_size = root->sectorsize;
-       device->total_bytes = i_size_read(bdev->bd_inode);
-       device->disk_total_bytes = device->total_bytes;
+       device->total_bytes = btrfs_device_get_total_bytes(srcdev);
+       device->disk_total_bytes = btrfs_device_get_disk_total_bytes(srcdev);
+       device->bytes_used = btrfs_device_get_bytes_used(srcdev);
+       ASSERT(list_empty(&srcdev->resized_list));
+       device->commit_total_bytes = srcdev->commit_total_bytes;
+       device->commit_bytes_used = device->bytes_used;
        device->dev_root = fs_info->dev_root;
        device->bdev = bdev;
        device->in_fs_metadata = 1;
@@ -2355,8 +2375,6 @@ int btrfs_init_dev_replace_tgtdev(struct btrfs_root *root, char *device_path,
        list_add(&device->dev_list, &fs_info->fs_devices->devices);
        fs_info->fs_devices->num_devices++;
        fs_info->fs_devices->open_devices++;
-       if (device->can_discard)
-               fs_info->fs_devices->num_can_discard++;
        mutex_unlock(&root->fs_info->fs_devices->device_list_mutex);
 
        *device_out = device;
@@ -2415,8 +2433,10 @@ static noinline int btrfs_update_device(struct btrfs_trans_handle *trans,
        btrfs_set_device_io_align(leaf, dev_item, device->io_align);
        btrfs_set_device_io_width(leaf, dev_item, device->io_width);
        btrfs_set_device_sector_size(leaf, dev_item, device->sector_size);
-       btrfs_set_device_total_bytes(leaf, dev_item, device->disk_total_bytes);
-       btrfs_set_device_bytes_used(leaf, dev_item, device->bytes_used);
+       btrfs_set_device_total_bytes(leaf, dev_item,
+                                    btrfs_device_get_disk_total_bytes(device));
+       btrfs_set_device_bytes_used(leaf, dev_item,
+                                   btrfs_device_get_bytes_used(device));
        btrfs_mark_buffer_dirty(leaf);
 
 out:
@@ -2424,40 +2444,44 @@ out:
        return ret;
 }
 
-static int __btrfs_grow_device(struct btrfs_trans_handle *trans,
+int btrfs_grow_device(struct btrfs_trans_handle *trans,
                      struct btrfs_device *device, u64 new_size)
 {
        struct btrfs_super_block *super_copy =
                device->dev_root->fs_info->super_copy;
-       u64 old_total = btrfs_super_total_bytes(super_copy);
-       u64 diff = new_size - device->total_bytes;
+       struct btrfs_fs_devices *fs_devices;
+       u64 old_total;
+       u64 diff;
 
        if (!device->writeable)
                return -EACCES;
+
+       lock_chunks(device->dev_root);
+       old_total = btrfs_super_total_bytes(super_copy);
+       diff = new_size - device->total_bytes;
+
        if (new_size <= device->total_bytes ||
-           device->is_tgtdev_for_dev_replace)
+           device->is_tgtdev_for_dev_replace) {
+               unlock_chunks(device->dev_root);
                return -EINVAL;
+       }
+
+       fs_devices = device->dev_root->fs_info->fs_devices;
 
        btrfs_set_super_total_bytes(super_copy, old_total + diff);
        device->fs_devices->total_rw_bytes += diff;
 
-       device->total_bytes = new_size;
-       device->disk_total_bytes = new_size;
+       btrfs_device_set_total_bytes(device, new_size);
+       btrfs_device_set_disk_total_bytes(device, new_size);
        btrfs_clear_space_info_full(device->dev_root->fs_info);
+       if (list_empty(&device->resized_list))
+               list_add_tail(&device->resized_list,
+                             &fs_devices->resized_devices);
+       unlock_chunks(device->dev_root);
 
        return btrfs_update_device(trans, device);
 }
 
-int btrfs_grow_device(struct btrfs_trans_handle *trans,
-                     struct btrfs_device *device, u64 new_size)
-{
-       int ret;
-       lock_chunks(device->dev_root);
-       ret = __btrfs_grow_device(trans, device, new_size);
-       unlock_chunks(device->dev_root);
-       return ret;
-}
-
 static int btrfs_free_chunk(struct btrfs_trans_handle *trans,
                            struct btrfs_root *root,
                            u64 chunk_tree, u64 chunk_objectid,
@@ -2509,6 +2533,7 @@ static int btrfs_del_sys_chunk(struct btrfs_root *root, u64 chunk_objectid, u64
        u32 cur;
        struct btrfs_key key;
 
+       lock_chunks(root);
        array_size = btrfs_super_sys_array_size(super_copy);
 
        ptr = super_copy->sys_chunk_array;
@@ -2538,79 +2563,95 @@ static int btrfs_del_sys_chunk(struct btrfs_root *root, u64 chunk_objectid, u64
                        cur += len;
                }
        }
+       unlock_chunks(root);
        return ret;
 }
 
-static int btrfs_relocate_chunk(struct btrfs_root *root,
-                        u64 chunk_tree, u64 chunk_objectid,
-                        u64 chunk_offset)
+int btrfs_remove_chunk(struct btrfs_trans_handle *trans,
+                      struct btrfs_root *root, u64 chunk_offset)
 {
        struct extent_map_tree *em_tree;
-       struct btrfs_root *extent_root;
-       struct btrfs_trans_handle *trans;
        struct extent_map *em;
+       struct btrfs_root *extent_root = root->fs_info->extent_root;
        struct map_lookup *map;
-       int ret;
-       int i;
+       u64 dev_extent_len = 0;
+       u64 chunk_objectid = BTRFS_FIRST_CHUNK_TREE_OBJECTID;
+       u64 chunk_tree = root->fs_info->chunk_root->objectid;
+       int i, ret = 0;
 
+       /* Just in case */
        root = root->fs_info->chunk_root;
-       extent_root = root->fs_info->extent_root;
        em_tree = &root->fs_info->mapping_tree.map_tree;
 
-       ret = btrfs_can_relocate(extent_root, chunk_offset);
-       if (ret)
-               return -ENOSPC;
-
-       /* step one, relocate all the extents inside this chunk */
-       ret = btrfs_relocate_block_group(extent_root, chunk_offset);
-       if (ret)
-               return ret;
-
-       trans = btrfs_start_transaction(root, 0);
-       if (IS_ERR(trans)) {
-               ret = PTR_ERR(trans);
-               btrfs_std_error(root->fs_info, ret);
-               return ret;
-       }
-
-       lock_chunks(root);
-
-       /*
-        * step two, delete the device extents and the
-        * chunk tree entries
-        */
        read_lock(&em_tree->lock);
        em = lookup_extent_mapping(em_tree, chunk_offset, 1);
        read_unlock(&em_tree->lock);
 
-       BUG_ON(!em || em->start > chunk_offset ||
-              em->start + em->len < chunk_offset);
+       if (!em || em->start > chunk_offset ||
+           em->start + em->len < chunk_offset) {
+               /*
+                * This is a logic error, but we don't want to just rely on the
+                * user having built with ASSERT enabled, so if ASSERT doens't
+                * do anything we still error out.
+                */
+               ASSERT(0);
+               if (em)
+                       free_extent_map(em);
+               return -EINVAL;
+       }
        map = (struct map_lookup *)em->bdev;
 
        for (i = 0; i < map->num_stripes; i++) {
-               ret = btrfs_free_dev_extent(trans, map->stripes[i].dev,
-                                           map->stripes[i].physical);
-               BUG_ON(ret);
+               struct btrfs_device *device = map->stripes[i].dev;
+               ret = btrfs_free_dev_extent(trans, device,
+                                           map->stripes[i].physical,
+                                           &dev_extent_len);
+               if (ret) {
+                       btrfs_abort_transaction(trans, root, ret);
+                       goto out;
+               }
+
+               if (device->bytes_used > 0) {
+                       lock_chunks(root);
+                       btrfs_device_set_bytes_used(device,
+                                       device->bytes_used - dev_extent_len);
+                       spin_lock(&root->fs_info->free_chunk_lock);
+                       root->fs_info->free_chunk_space += dev_extent_len;
+                       spin_unlock(&root->fs_info->free_chunk_lock);
+                       btrfs_clear_space_info_full(root->fs_info);
+                       unlock_chunks(root);
+               }
 
                if (map->stripes[i].dev) {
                        ret = btrfs_update_device(trans, map->stripes[i].dev);
-                       BUG_ON(ret);
+                       if (ret) {
+                               btrfs_abort_transaction(trans, root, ret);
+                               goto out;
+                       }
                }
        }
        ret = btrfs_free_chunk(trans, root, chunk_tree, chunk_objectid,
                               chunk_offset);
-
-       BUG_ON(ret);
+       if (ret) {
+               btrfs_abort_transaction(trans, root, ret);
+               goto out;
+       }
 
        trace_btrfs_chunk_free(root, map, chunk_offset, em->len);
 
        if (map->type & BTRFS_BLOCK_GROUP_SYSTEM) {
                ret = btrfs_del_sys_chunk(root, chunk_objectid, chunk_offset);
-               BUG_ON(ret);
+               if (ret) {
+                       btrfs_abort_transaction(trans, root, ret);
+                       goto out;
+               }
        }
 
        ret = btrfs_remove_block_group(trans, extent_root, chunk_offset);
-       BUG_ON(ret);
+       if (ret) {
+               btrfs_abort_transaction(trans, extent_root, ret);
+               goto out;
+       }
 
        write_lock(&em_tree->lock);
        remove_extent_mapping(em_tree, em);
@@ -2618,12 +2659,46 @@ static int btrfs_relocate_chunk(struct btrfs_root *root,
 
        /* once for the tree */
        free_extent_map(em);
+out:
        /* once for us */
        free_extent_map(em);
+       return ret;
+}
 
-       unlock_chunks(root);
+static int btrfs_relocate_chunk(struct btrfs_root *root,
+                        u64 chunk_tree, u64 chunk_objectid,
+                        u64 chunk_offset)
+{
+       struct btrfs_root *extent_root;
+       struct btrfs_trans_handle *trans;
+       int ret;
+
+       root = root->fs_info->chunk_root;
+       extent_root = root->fs_info->extent_root;
+
+       ret = btrfs_can_relocate(extent_root, chunk_offset);
+       if (ret)
+               return -ENOSPC;
+
+       /* step one, relocate all the extents inside this chunk */
+       ret = btrfs_relocate_block_group(extent_root, chunk_offset);
+       if (ret)
+               return ret;
+
+       trans = btrfs_start_transaction(root, 0);
+       if (IS_ERR(trans)) {
+               ret = PTR_ERR(trans);
+               btrfs_std_error(root->fs_info, ret);
+               return ret;
+       }
+
+       /*
+        * step two, delete the device extents and the
+        * chunk tree entries
+        */
+       ret = btrfs_remove_chunk(trans, root, chunk_offset);
        btrfs_end_transaction(trans, root);
-       return 0;
+       return ret;
 }
 
 static int btrfs_relocate_sys_chunks(struct btrfs_root *root)
@@ -2676,8 +2751,8 @@ again:
                                                   found_key.offset);
                        if (ret == -ENOSPC)
                                failed++;
-                       else if (ret)
-                               BUG();
+                       else
+                               BUG_ON(ret);
                }
 
                if (found_key.offset == 0)
@@ -3084,11 +3159,12 @@ static int __btrfs_balance(struct btrfs_fs_info *fs_info)
        /* step one make some room on all the devices */
        devices = &fs_info->fs_devices->devices;
        list_for_each_entry(device, devices, dev_list) {
-               old_size = device->total_bytes;
+               old_size = btrfs_device_get_total_bytes(device);
                size_to_free = div_factor(old_size, 1);
                size_to_free = min(size_to_free, (u64)1 * 1024 * 1024);
                if (!device->writeable ||
-                   device->total_bytes - device->bytes_used > size_to_free ||
+                   btrfs_device_get_total_bytes(device) -
+                   btrfs_device_get_bytes_used(device) > size_to_free ||
                    device->is_tgtdev_for_dev_replace)
                        continue;
 
@@ -3643,8 +3719,6 @@ static int btrfs_uuid_scan_kthread(void *data)
        max_key.type = BTRFS_ROOT_ITEM_KEY;
        max_key.offset = (u64)-1;
 
-       path->keep_locks = 1;
-
        while (1) {
                ret = btrfs_search_forward(root, &key, path, 0);
                if (ret) {
@@ -3896,8 +3970,8 @@ int btrfs_shrink_device(struct btrfs_device *device, u64 new_size)
        struct btrfs_key key;
        struct btrfs_super_block *super_copy = root->fs_info->super_copy;
        u64 old_total = btrfs_super_total_bytes(super_copy);
-       u64 old_size = device->total_bytes;
-       u64 diff = device->total_bytes - new_size;
+       u64 old_size = btrfs_device_get_total_bytes(device);
+       u64 diff = old_size - new_size;
 
        if (device->is_tgtdev_for_dev_replace)
                return -EINVAL;
@@ -3910,7 +3984,7 @@ int btrfs_shrink_device(struct btrfs_device *device, u64 new_size)
 
        lock_chunks(root);
 
-       device->total_bytes = new_size;
+       btrfs_device_set_total_bytes(device, new_size);
        if (device->writeable) {
                device->fs_devices->total_rw_bytes -= diff;
                spin_lock(&root->fs_info->free_chunk_lock);
@@ -3976,7 +4050,7 @@ again:
                ret = -ENOSPC;
                lock_chunks(root);
 
-               device->total_bytes = old_size;
+               btrfs_device_set_total_bytes(device, old_size);
                if (device->writeable)
                        device->fs_devices->total_rw_bytes += diff;
                spin_lock(&root->fs_info->free_chunk_lock);
@@ -3994,18 +4068,17 @@ again:
        }
 
        lock_chunks(root);
+       btrfs_device_set_disk_total_bytes(device, new_size);
+       if (list_empty(&device->resized_list))
+               list_add_tail(&device->resized_list,
+                             &root->fs_info->fs_devices->resized_devices);
 
-       device->disk_total_bytes = new_size;
-       /* Now btrfs_update_device() will change the on-disk size. */
-       ret = btrfs_update_device(trans, device);
-       if (ret) {
-               unlock_chunks(root);
-               btrfs_end_transaction(trans, root);
-               goto done;
-       }
        WARN_ON(diff > old_total);
        btrfs_set_super_total_bytes(super_copy, old_total - diff);
        unlock_chunks(root);
+
+       /* Now btrfs_update_device() will change the on-disk size. */
+       ret = btrfs_update_device(trans, device);
        btrfs_end_transaction(trans, root);
 done:
        btrfs_free_path(path);
@@ -4021,10 +4094,13 @@ static int btrfs_add_system_chunk(struct btrfs_root *root,
        u32 array_size;
        u8 *ptr;
 
+       lock_chunks(root);
        array_size = btrfs_super_sys_array_size(super_copy);
        if (array_size + item_size + sizeof(disk_key)
-                       > BTRFS_SYSTEM_CHUNK_ARRAY_SIZE)
+                       > BTRFS_SYSTEM_CHUNK_ARRAY_SIZE) {
+               unlock_chunks(root);
                return -EFBIG;
+       }
 
        ptr = super_copy->sys_chunk_array + array_size;
        btrfs_cpu_key_to_disk(&disk_key, key);
@@ -4033,6 +4109,8 @@ static int btrfs_add_system_chunk(struct btrfs_root *root,
        memcpy(ptr, chunk, item_size);
        item_size += sizeof(disk_key);
        btrfs_set_super_sys_array_size(super_copy, array_size + item_size);
+       unlock_chunks(root);
+
        return 0;
 }
 
@@ -4402,6 +4480,16 @@ static int __btrfs_alloc_chunk(struct btrfs_trans_handle *trans,
        if (ret)
                goto error_del_extent;
 
+       for (i = 0; i < map->num_stripes; i++) {
+               num_bytes = map->stripes[i].dev->bytes_used + stripe_size;
+               btrfs_device_set_bytes_used(map->stripes[i].dev, num_bytes);
+       }
+
+       spin_lock(&extent_root->fs_info->free_chunk_lock);
+       extent_root->fs_info->free_chunk_space -= (stripe_size *
+                                                  map->num_stripes);
+       spin_unlock(&extent_root->fs_info->free_chunk_lock);
+
        free_extent_map(em);
        check_raid56_incompat_flag(extent_root->fs_info, type);
 
@@ -4473,7 +4561,6 @@ int btrfs_finish_chunk_alloc(struct btrfs_trans_handle *trans,
                device = map->stripes[i].dev;
                dev_offset = map->stripes[i].physical;
 
-               device->bytes_used += stripe_size;
                ret = btrfs_update_device(trans, device);
                if (ret)
                        goto out;
@@ -4486,11 +4573,6 @@ int btrfs_finish_chunk_alloc(struct btrfs_trans_handle *trans,
                        goto out;
        }
 
-       spin_lock(&extent_root->fs_info->free_chunk_lock);
-       extent_root->fs_info->free_chunk_space -= (stripe_size *
-                                                  map->num_stripes);
-       spin_unlock(&extent_root->fs_info->free_chunk_lock);
-
        stripe = &chunk->stripe;
        for (i = 0; i < map->num_stripes; i++) {
                device = map->stripes[i].dev;
@@ -4570,16 +4652,25 @@ static noinline int init_first_rw_device(struct btrfs_trans_handle *trans,
        alloc_profile = btrfs_get_alloc_profile(fs_info->chunk_root, 0);
        ret = __btrfs_alloc_chunk(trans, extent_root, sys_chunk_offset,
                                  alloc_profile);
-       if (ret) {
-               btrfs_abort_transaction(trans, root, ret);
-               goto out;
+       return ret;
+}
+
+static inline int btrfs_chunk_max_errors(struct map_lookup *map)
+{
+       int max_errors;
+
+       if (map->type & (BTRFS_BLOCK_GROUP_RAID1 |
+                        BTRFS_BLOCK_GROUP_RAID10 |
+                        BTRFS_BLOCK_GROUP_RAID5 |
+                        BTRFS_BLOCK_GROUP_DUP)) {
+               max_errors = 1;
+       } else if (map->type & BTRFS_BLOCK_GROUP_RAID6) {
+               max_errors = 2;
+       } else {
+               max_errors = 0;
        }
 
-       ret = btrfs_add_device(trans, fs_info->chunk_root, device);
-       if (ret)
-               btrfs_abort_transaction(trans, root, ret);
-out:
-       return ret;
+       return max_errors;
 }
 
 int btrfs_chunk_readonly(struct btrfs_root *root, u64 chunk_offset)
@@ -4588,6 +4679,7 @@ int btrfs_chunk_readonly(struct btrfs_root *root, u64 chunk_offset)
        struct map_lookup *map;
        struct btrfs_mapping_tree *map_tree = &root->fs_info->mapping_tree;
        int readonly = 0;
+       int miss_ndevs = 0;
        int i;
 
        read_lock(&map_tree->map_tree.lock);
@@ -4596,18 +4688,27 @@ int btrfs_chunk_readonly(struct btrfs_root *root, u64 chunk_offset)
        if (!em)
                return 1;
 
-       if (btrfs_test_opt(root, DEGRADED)) {
-               free_extent_map(em);
-               return 0;
-       }
-
        map = (struct map_lookup *)em->bdev;
        for (i = 0; i < map->num_stripes; i++) {
+               if (map->stripes[i].dev->missing) {
+                       miss_ndevs++;
+                       continue;
+               }
+
                if (!map->stripes[i].dev->writeable) {
                        readonly = 1;
-                       break;
+                       goto end;
                }
        }
+
+       /*
+        * If the number of missing devices is larger than max errors,
+        * we can not write the data into that chunk successfully, so
+        * set it readonly.
+        */
+       if (miss_ndevs > btrfs_chunk_max_errors(map))
+               readonly = 1;
+end:
        free_extent_map(em);
        return readonly;
 }
@@ -5008,6 +5109,8 @@ static int __btrfs_map_block(struct btrfs_fs_info *fs_info, int rw,
                        num_stripes = min_t(u64, map->num_stripes,
                                            stripe_nr_end - stripe_nr_orig);
                stripe_index = do_div(stripe_nr, map->num_stripes);
+               if (!(rw & (REQ_WRITE | REQ_DISCARD | REQ_GET_READ_MIRRORS)))
+                       mirror_num = 1;
        } else if (map->type & BTRFS_BLOCK_GROUP_RAID1) {
                if (rw & (REQ_WRITE | REQ_DISCARD | REQ_GET_READ_MIRRORS))
                        num_stripes = map->num_stripes;
@@ -5111,6 +5214,9 @@ static int __btrfs_map_block(struct btrfs_fs_info *fs_info, int rw,
                        /* We distribute the parity blocks across stripes */
                        tmp = stripe_nr + stripe_index;
                        stripe_index = do_div(tmp, map->num_stripes);
+                       if (!(rw & (REQ_WRITE | REQ_DISCARD |
+                                   REQ_GET_READ_MIRRORS)) && mirror_num <= 1)
+                               mirror_num = 1;
                }
        } else {
                /*
@@ -5218,16 +5324,8 @@ static int __btrfs_map_block(struct btrfs_fs_info *fs_info, int rw,
                }
        }
 
-       if (rw & (REQ_WRITE | REQ_GET_READ_MIRRORS)) {
-               if (map->type & (BTRFS_BLOCK_GROUP_RAID1 |
-                                BTRFS_BLOCK_GROUP_RAID10 |
-                                BTRFS_BLOCK_GROUP_RAID5 |
-                                BTRFS_BLOCK_GROUP_DUP)) {
-                       max_errors = 1;
-               } else if (map->type & BTRFS_BLOCK_GROUP_RAID6) {
-                       max_errors = 2;
-               }
-       }
+       if (rw & (REQ_WRITE | REQ_GET_READ_MIRRORS))
+               max_errors = btrfs_chunk_max_errors(map);
 
        if (dev_replace_is_ongoing && (rw & (REQ_WRITE | REQ_DISCARD)) &&
            dev_replace->tgtdev != NULL) {
@@ -5610,8 +5708,8 @@ static void submit_stripe_bio(struct btrfs_root *root, struct btrfs_bio *bbio,
                name = rcu_dereference(dev->name);
                pr_debug("btrfs_map_bio: rw %d, sector=%llu, dev=%lu "
                         "(%s id %llu), size=%u\n", rw,
-                        (u64)bio->bi_sector, (u_long)dev->bdev->bd_dev,
-                        name->str, dev->devid, bio->bi_size);
+                        (u64)bio->bi_iter.bi_sector, (u_long)dev->bdev->bd_dev,
+                        name->str, dev->devid, bio->bi_iter.bi_size);
                rcu_read_unlock();
        }
 #endif
@@ -5789,10 +5887,10 @@ struct btrfs_device *btrfs_find_device(struct btrfs_fs_info *fs_info, u64 devid,
 }
 
 static struct btrfs_device *add_missing_dev(struct btrfs_root *root,
+                                           struct btrfs_fs_devices *fs_devices,
                                            u64 devid, u8 *dev_uuid)
 {
        struct btrfs_device *device;
-       struct btrfs_fs_devices *fs_devices = root->fs_info->fs_devices;
 
        device = btrfs_alloc_device(NULL, &devid, dev_uuid);
        if (IS_ERR(device))
@@ -5929,7 +6027,8 @@ static int read_one_chunk(struct btrfs_root *root, struct btrfs_key *key,
                }
                if (!map->stripes[i].dev) {
                        map->stripes[i].dev =
-                               add_missing_dev(root, devid, uuid);
+                               add_missing_dev(root, root->fs_info->fs_devices,
+                                               devid, uuid);
                        if (!map->stripes[i].dev) {
                                free_extent_map(em);
                                return -EIO;
@@ -5956,7 +6055,9 @@ static void fill_device_from_item(struct extent_buffer *leaf,
        device->devid = btrfs_device_id(leaf, dev_item);
        device->disk_total_bytes = btrfs_device_total_bytes(leaf, dev_item);
        device->total_bytes = device->disk_total_bytes;
+       device->commit_total_bytes = device->disk_total_bytes;
        device->bytes_used = btrfs_device_bytes_used(leaf, dev_item);
+       device->commit_bytes_used = device->bytes_used;
        device->type = btrfs_device_type(leaf, dev_item);
        device->io_align = btrfs_device_io_align(leaf, dev_item);
        device->io_width = btrfs_device_io_width(leaf, dev_item);
@@ -5968,7 +6069,8 @@ static void fill_device_from_item(struct extent_buffer *leaf,
        read_extent_buffer(leaf, device->uuid, ptr, BTRFS_UUID_SIZE);
 }
 
-static int open_seed_devices(struct btrfs_root *root, u8 *fsid)
+static struct btrfs_fs_devices *open_seed_devices(struct btrfs_root *root,
+                                                 u8 *fsid)
 {
        struct btrfs_fs_devices *fs_devices;
        int ret;
@@ -5977,49 +6079,56 @@ static int open_seed_devices(struct btrfs_root *root, u8 *fsid)
 
        fs_devices = root->fs_info->fs_devices->seed;
        while (fs_devices) {
-               if (!memcmp(fs_devices->fsid, fsid, BTRFS_UUID_SIZE)) {
-                       ret = 0;
-                       goto out;
-               }
+               if (!memcmp(fs_devices->fsid, fsid, BTRFS_UUID_SIZE))
+                       return fs_devices;
+
                fs_devices = fs_devices->seed;
        }
 
        fs_devices = find_fsid(fsid);
        if (!fs_devices) {
-               ret = -ENOENT;
-               goto out;
+               if (!btrfs_test_opt(root, DEGRADED))
+                       return ERR_PTR(-ENOENT);
+
+               fs_devices = alloc_fs_devices(fsid);
+               if (IS_ERR(fs_devices))
+                       return fs_devices;
+
+               fs_devices->seeding = 1;
+               fs_devices->opened = 1;
+               return fs_devices;
        }
 
        fs_devices = clone_fs_devices(fs_devices);
-       if (IS_ERR(fs_devices)) {
-               ret = PTR_ERR(fs_devices);
-               goto out;
-       }
+       if (IS_ERR(fs_devices))
+               return fs_devices;
 
        ret = __btrfs_open_devices(fs_devices, FMODE_READ,
                                   root->fs_info->bdev_holder);
        if (ret) {
                free_fs_devices(fs_devices);
+               fs_devices = ERR_PTR(ret);
                goto out;
        }
 
        if (!fs_devices->seeding) {
                __btrfs_close_devices(fs_devices);
                free_fs_devices(fs_devices);
-               ret = -EINVAL;
+               fs_devices = ERR_PTR(-EINVAL);
                goto out;
        }
 
        fs_devices->seed = root->fs_info->fs_devices->seed;
        root->fs_info->fs_devices->seed = fs_devices;
 out:
-       return ret;
+       return fs_devices;
 }
 
 static int read_one_dev(struct btrfs_root *root,
                        struct extent_buffer *leaf,
                        struct btrfs_dev_item *dev_item)
 {
+       struct btrfs_fs_devices *fs_devices = root->fs_info->fs_devices;
        struct btrfs_device *device;
        u64 devid;
        int ret;
@@ -6033,31 +6142,48 @@ static int read_one_dev(struct btrfs_root *root,
                           BTRFS_UUID_SIZE);
 
        if (memcmp(fs_uuid, root->fs_info->fsid, BTRFS_UUID_SIZE)) {
-               ret = open_seed_devices(root, fs_uuid);
-               if (ret && !btrfs_test_opt(root, DEGRADED))
-                       return ret;
+               fs_devices = open_seed_devices(root, fs_uuid);
+               if (IS_ERR(fs_devices))
+                       return PTR_ERR(fs_devices);
        }
 
        device = btrfs_find_device(root->fs_info, devid, dev_uuid, fs_uuid);
-       if (!device || !device->bdev) {
+       if (!device) {
                if (!btrfs_test_opt(root, DEGRADED))
                        return -EIO;
 
-               if (!device) {
-                       btrfs_warn(root->fs_info, "devid %llu missing", devid);
-                       device = add_missing_dev(root, devid, dev_uuid);
-                       if (!device)
-                               return -ENOMEM;
-               } else if (!device->missing) {
+               btrfs_warn(root->fs_info, "devid %llu missing", devid);
+               device = add_missing_dev(root, fs_devices, devid, dev_uuid);
+               if (!device)
+                       return -ENOMEM;
+       } else {
+               if (!device->bdev && !btrfs_test_opt(root, DEGRADED))
+                       return -EIO;
+
+               if(!device->bdev && !device->missing) {
                        /*
                         * this happens when a device that was properly setup
                         * in the device info lists suddenly goes bad.
                         * device->bdev is NULL, and so we have to set
                         * device->missing to one here
                         */
-                       root->fs_info->fs_devices->missing_devices++;
+                       device->fs_devices->missing_devices++;
                        device->missing = 1;
                }
+
+               /* Move the device to its own fs_devices */
+               if (device->fs_devices != fs_devices) {
+                       ASSERT(device->missing);
+
+                       list_move(&device->dev_list, &fs_devices->devices);
+                       device->fs_devices->num_devices--;
+                       fs_devices->num_devices++;
+
+                       device->fs_devices->missing_devices--;
+                       fs_devices->missing_devices++;
+
+                       device->fs_devices = fs_devices;
+               }
        }
 
        if (device->fs_devices != root->fs_info->fs_devices) {
@@ -6373,16 +6499,18 @@ int btrfs_run_dev_stats(struct btrfs_trans_handle *trans,
        struct btrfs_root *dev_root = fs_info->dev_root;
        struct btrfs_fs_devices *fs_devices = fs_info->fs_devices;
        struct btrfs_device *device;
+       int stats_cnt;
        int ret = 0;
 
        mutex_lock(&fs_devices->device_list_mutex);
        list_for_each_entry(device, &fs_devices->devices, dev_list) {
-               if (!device->dev_stats_valid || !device->dev_stats_dirty)
+               if (!device->dev_stats_valid || !btrfs_dev_stats_dirty(device))
                        continue;
 
+               stats_cnt = atomic_read(&device->dev_stats_ccnt);
                ret = update_dev_stat_item(trans, dev_root, device);
                if (!ret)
-                       device->dev_stats_dirty = 0;
+                       atomic_sub(stats_cnt, &device->dev_stats_ccnt);
        }
        mutex_unlock(&fs_devices->device_list_mutex);
 
@@ -6481,3 +6609,51 @@ int btrfs_scratch_superblock(struct btrfs_device *device)
 
        return 0;
 }
+
+/*
+ * Update the size of all devices, which is used for writing out the
+ * super blocks.
+ */
+void btrfs_update_commit_device_size(struct btrfs_fs_info *fs_info)
+{
+       struct btrfs_fs_devices *fs_devices = fs_info->fs_devices;
+       struct btrfs_device *curr, *next;
+
+       if (list_empty(&fs_devices->resized_devices))
+               return;
+
+       mutex_lock(&fs_devices->device_list_mutex);
+       lock_chunks(fs_info->dev_root);
+       list_for_each_entry_safe(curr, next, &fs_devices->resized_devices,
+                                resized_list) {
+               list_del_init(&curr->resized_list);
+               curr->commit_total_bytes = curr->disk_total_bytes;
+       }
+       unlock_chunks(fs_info->dev_root);
+       mutex_unlock(&fs_devices->device_list_mutex);
+}
+
+/* Must be invoked during the transaction commit */
+void btrfs_update_commit_device_bytes_used(struct btrfs_root *root,
+                                       struct btrfs_transaction *transaction)
+{
+       struct extent_map *em;
+       struct map_lookup *map;
+       struct btrfs_device *dev;
+       int i;
+
+       if (list_empty(&transaction->pending_chunks))
+               return;
+
+       /* In order to kick the device replace finish process */
+       lock_chunks(root);
+       list_for_each_entry(em, &transaction->pending_chunks, list) {
+               map = (struct map_lookup *)em->bdev;
+
+               for (i = 0; i < map->num_stripes; i++) {
+                       dev = map->stripes[i].dev;
+                       dev->commit_bytes_used = dev->bytes_used;
+               }
+       }
+       unlock_chunks(root);
+}
index 2aaa00c4781637f508302829ed51e3ae05402c84..08980fa2303916ee08c0f2b6bd30a6b9a6f0a711 100644 (file)
@@ -24,6 +24,8 @@
 #include <linux/btrfs.h>
 #include "async-thread.h"
 
+extern struct mutex uuid_mutex;
+
 #define BTRFS_STRIPE_LEN       (64 * 1024)
 
 struct buffer_head;
@@ -32,41 +34,59 @@ struct btrfs_pending_bios {
        struct bio *tail;
 };
 
+/*
+ * Use sequence counter to get consistent device stat data on
+ * 32-bit processors.
+ */
+#if BITS_PER_LONG==32 && defined(CONFIG_SMP)
+#include <linux/seqlock.h>
+#define __BTRFS_NEED_DEVICE_DATA_ORDERED
+#define btrfs_device_data_ordered_init(device) \
+       seqcount_init(&device->data_seqcount)
+#else
+#define btrfs_device_data_ordered_init(device) do { } while (0)
+#endif
+
 struct btrfs_device {
        struct list_head dev_list;
        struct list_head dev_alloc_list;
        struct btrfs_fs_devices *fs_devices;
+
        struct btrfs_root *dev_root;
 
+       struct rcu_string *name;
+
+       u64 generation;
+
+       spinlock_t io_lock ____cacheline_aligned;
+       int running_pending;
        /* regular prio bios */
        struct btrfs_pending_bios pending_bios;
        /* WRITE_SYNC bios */
        struct btrfs_pending_bios pending_sync_bios;
 
-       u64 generation;
-       int running_pending;
+       struct block_device *bdev;
+
+       /* the mode sent to blkdev_get */
+       fmode_t mode;
+
        int writeable;
        int in_fs_metadata;
        int missing;
        int can_discard;
        int is_tgtdev_for_dev_replace;
 
-       spinlock_t io_lock;
-       /* the mode sent to blkdev_get */
-       fmode_t mode;
-
-       struct block_device *bdev;
-
-
-       struct rcu_string *name;
+#ifdef __BTRFS_NEED_DEVICE_DATA_ORDERED
+       seqcount_t data_seqcount;
+#endif
 
        /* the internal btrfs device id */
        u64 devid;
 
-       /* size of the device */
+       /* size of the device in memory */
        u64 total_bytes;
 
-       /* size of the disk */
+       /* size of the device on disk */
        u64 disk_total_bytes;
 
        /* bytes used */
@@ -83,10 +103,26 @@ struct btrfs_device {
        /* minimal io size for this device */
        u32 sector_size;
 
-
        /* physical drive uuid (or lvm uuid) */
        u8 uuid[BTRFS_UUID_SIZE];
 
+       /*
+        * size of the device on the current transaction
+        *
+        * This variant is update when committing the transaction,
+        * and protected by device_list_mutex
+        */
+       u64 commit_total_bytes;
+
+       /* bytes used on the current transaction */
+       u64 commit_bytes_used;
+       /*
+        * used to manage the device which is resized
+        *
+        * It is protected by chunk_lock.
+        */
+       struct list_head resized_list;
+
        /* for sending down flush barriers */
        int nobarriers;
        struct bio *flush_bio;
@@ -107,26 +143,90 @@ struct btrfs_device {
        struct radix_tree_root reada_zones;
        struct radix_tree_root reada_extents;
 
-
        /* disk I/O failure stats. For detailed description refer to
         * enum btrfs_dev_stat_values in ioctl.h */
        int dev_stats_valid;
-       int dev_stats_dirty; /* counters need to be written to disk */
+
+       /* Counter to record the change of device stats */
+       atomic_t dev_stats_ccnt;
        atomic_t dev_stat_values[BTRFS_DEV_STAT_VALUES_MAX];
 };
 
+/*
+ * If we read those variants at the context of their own lock, we needn't
+ * use the following helpers, reading them directly is safe.
+ */
+#if BITS_PER_LONG==32 && defined(CONFIG_SMP)
+#define BTRFS_DEVICE_GETSET_FUNCS(name)                                        \
+static inline u64                                                      \
+btrfs_device_get_##name(const struct btrfs_device *dev)                        \
+{                                                                      \
+       u64 size;                                                       \
+       unsigned int seq;                                               \
+                                                                       \
+       do {                                                            \
+               seq = read_seqcount_begin(&dev->data_seqcount);         \
+               size = dev->name;                                       \
+       } while (read_seqcount_retry(&dev->data_seqcount, seq));        \
+       return size;                                                    \
+}                                                                      \
+                                                                       \
+static inline void                                                     \
+btrfs_device_set_##name(struct btrfs_device *dev, u64 size)            \
+{                                                                      \
+       preempt_disable();                                              \
+       write_seqcount_begin(&dev->data_seqcount);                      \
+       dev->name = size;                                               \
+       write_seqcount_end(&dev->data_seqcount);                        \
+       preempt_enable();                                               \
+}
+#elif BITS_PER_LONG==32 && defined(CONFIG_PREEMPT)
+#define BTRFS_DEVICE_GETSET_FUNCS(name)                                        \
+static inline u64                                                      \
+btrfs_device_get_##name(const struct btrfs_device *dev)                        \
+{                                                                      \
+       u64 size;                                                       \
+                                                                       \
+       preempt_disable();                                              \
+       size = dev->name;                                               \
+       preempt_enable();                                               \
+       return size;                                                    \
+}                                                                      \
+                                                                       \
+static inline void                                                     \
+btrfs_device_set_##name(struct btrfs_device *dev, u64 size)            \
+{                                                                      \
+       preempt_disable();                                              \
+       dev->name = size;                                               \
+       preempt_enable();                                               \
+}
+#else
+#define BTRFS_DEVICE_GETSET_FUNCS(name)                                        \
+static inline u64                                                      \
+btrfs_device_get_##name(const struct btrfs_device *dev)                        \
+{                                                                      \
+       return dev->name;                                               \
+}                                                                      \
+                                                                       \
+static inline void                                                     \
+btrfs_device_set_##name(struct btrfs_device *dev, u64 size)            \
+{                                                                      \
+       dev->name = size;                                               \
+}
+#endif
+
+BTRFS_DEVICE_GETSET_FUNCS(total_bytes);
+BTRFS_DEVICE_GETSET_FUNCS(disk_total_bytes);
+BTRFS_DEVICE_GETSET_FUNCS(bytes_used);
+
 struct btrfs_fs_devices {
        u8 fsid[BTRFS_FSID_SIZE]; /* FS specific uuid */
 
-       /* the device with this id has the most recent copy of the super */
-       u64 latest_devid;
-       u64 latest_trans;
        u64 num_devices;
        u64 open_devices;
        u64 rw_devices;
        u64 missing_devices;
        u64 total_rw_bytes;
-       u64 num_can_discard;
        u64 total_devices;
        struct block_device *latest_bdev;
 
@@ -139,6 +239,7 @@ struct btrfs_fs_devices {
        struct mutex device_list_mutex;
        struct list_head devices;
 
+       struct list_head resized_devices;
        /* devices not currently being allocated */
        struct list_head alloc_list;
        struct list_head list;
@@ -167,8 +268,9 @@ struct btrfs_fs_devices {
  */
 typedef void (btrfs_io_bio_end_io_t) (struct btrfs_io_bio *bio, int err);
 struct btrfs_io_bio {
-       unsigned long mirror_num;
-       unsigned long stripe_index;
+       unsigned int mirror_num;
+       unsigned int stripe_index;
+       u64 logical;
        u8 *csum;
        u8 csum_inline[BTRFS_BIO_INLINE_CSUM_SIZE];
        u8 *csum_allocated;
@@ -325,6 +427,7 @@ struct btrfs_device *btrfs_find_device(struct btrfs_fs_info *fs_info, u64 devid,
 int btrfs_shrink_device(struct btrfs_device *device, u64 new_size);
 int btrfs_init_new_device(struct btrfs_root *root, char *path);
 int btrfs_init_dev_replace_tgtdev(struct btrfs_root *root, char *device_path,
+                                 struct btrfs_device *srcdev,
                                  struct btrfs_device **device_out);
 int btrfs_balance(struct btrfs_balance_control *bctl,
                  struct btrfs_ioctl_balance_args *bargs);
@@ -360,11 +463,20 @@ unsigned long btrfs_full_stripe_len(struct btrfs_root *root,
 int btrfs_finish_chunk_alloc(struct btrfs_trans_handle *trans,
                                struct btrfs_root *extent_root,
                                u64 chunk_offset, u64 chunk_size);
+int btrfs_remove_chunk(struct btrfs_trans_handle *trans,
+                      struct btrfs_root *root, u64 chunk_offset);
+
+static inline int btrfs_dev_stats_dirty(struct btrfs_device *dev)
+{
+       return atomic_read(&dev->dev_stats_ccnt);
+}
+
 static inline void btrfs_dev_stat_inc(struct btrfs_device *dev,
                                      int index)
 {
        atomic_inc(dev->dev_stat_values + index);
-       dev->dev_stats_dirty = 1;
+       smp_mb__before_atomic();
+       atomic_inc(&dev->dev_stats_ccnt);
 }
 
 static inline int btrfs_dev_stat_read(struct btrfs_device *dev,
@@ -379,7 +491,8 @@ static inline int btrfs_dev_stat_read_and_reset(struct btrfs_device *dev,
        int ret;
 
        ret = atomic_xchg(dev->dev_stat_values + index, 0);
-       dev->dev_stats_dirty = 1;
+       smp_mb__before_atomic();
+       atomic_inc(&dev->dev_stats_ccnt);
        return ret;
 }
 
@@ -387,7 +500,8 @@ static inline void btrfs_dev_stat_set(struct btrfs_device *dev,
                                      int index, unsigned long val)
 {
        atomic_set(dev->dev_stat_values + index, val);
-       dev->dev_stats_dirty = 1;
+       smp_mb__before_atomic();
+       atomic_inc(&dev->dev_stats_ccnt);
 }
 
 static inline void btrfs_dev_stat_reset(struct btrfs_device *dev,
@@ -395,4 +509,8 @@ static inline void btrfs_dev_stat_reset(struct btrfs_device *dev,
 {
        btrfs_dev_stat_set(dev, index, 0);
 }
+
+void btrfs_update_commit_device_size(struct btrfs_fs_info *fs_info);
+void btrfs_update_commit_device_bytes_used(struct btrfs_root *root,
+                                       struct btrfs_transaction *transaction);
 #endif
index ad8328d797ea9910c21f0ecd5db6051d347a4571..dcf20131fbe49c25348463dffedffaeaabf0f607 100644 (file)
@@ -237,7 +237,7 @@ ssize_t btrfs_listxattr(struct dentry *dentry, char *buffer, size_t size)
         * first xattr that we find and walk forward
         */
        key.objectid = btrfs_ino(inode);
-       btrfs_set_key_type(&key, BTRFS_XATTR_ITEM_KEY);
+       key.type = BTRFS_XATTR_ITEM_KEY;
        key.offset = 0;
 
        path = btrfs_alloc_path();
@@ -273,7 +273,7 @@ ssize_t btrfs_listxattr(struct dentry *dentry, char *buffer, size_t size)
                /* check to make sure this item is what we want */
                if (found_key.objectid != key.objectid)
                        break;
-               if (btrfs_key_type(&found_key) != BTRFS_XATTR_ITEM_KEY)
+               if (found_key.type != BTRFS_XATTR_ITEM_KEY)
                        break;
 
                di = btrfs_item_ptr(leaf, slot, struct btrfs_dir_item);
index b67d8fc81277675edb3fdb7beb9b8c4db2c919ad..759fa4e2de8fec28d3f6448456e1e12cec1add17 100644 (file)
@@ -33,8 +33,7 @@
 #include "compression.h"
 
 struct workspace {
-       z_stream inf_strm;
-       z_stream def_strm;
+       z_stream strm;
        char *buf;
        struct list_head list;
 };
@@ -43,8 +42,7 @@ static void zlib_free_workspace(struct list_head *ws)
 {
        struct workspace *workspace = list_entry(ws, struct workspace, list);
 
-       vfree(workspace->def_strm.workspace);
-       vfree(workspace->inf_strm.workspace);
+       vfree(workspace->strm.workspace);
        kfree(workspace->buf);
        kfree(workspace);
 }
@@ -52,17 +50,17 @@ static void zlib_free_workspace(struct list_head *ws)
 static struct list_head *zlib_alloc_workspace(void)
 {
        struct workspace *workspace;
+       int workspacesize;
 
        workspace = kzalloc(sizeof(*workspace), GFP_NOFS);
        if (!workspace)
                return ERR_PTR(-ENOMEM);
 
-       workspace->def_strm.workspace = vmalloc(zlib_deflate_workspacesize(
-                                               MAX_WBITS, MAX_MEM_LEVEL));
-       workspace->inf_strm.workspace = vmalloc(zlib_inflate_workspacesize());
+       workspacesize = max(zlib_deflate_workspacesize(MAX_WBITS, MAX_MEM_LEVEL),
+                       zlib_inflate_workspacesize());
+       workspace->strm.workspace = vmalloc(workspacesize);
        workspace->buf = kmalloc(PAGE_CACHE_SIZE, GFP_NOFS);
-       if (!workspace->def_strm.workspace ||
-           !workspace->inf_strm.workspace || !workspace->buf)
+       if (!workspace->strm.workspace || !workspace->buf)
                goto fail;
 
        INIT_LIST_HEAD(&workspace->list);
@@ -96,14 +94,14 @@ static int zlib_compress_pages(struct list_head *ws,
        *total_out = 0;
        *total_in = 0;
 
-       if (Z_OK != zlib_deflateInit(&workspace->def_strm, 3)) {
+       if (Z_OK != zlib_deflateInit(&workspace->strm, 3)) {
                printk(KERN_WARNING "BTRFS: deflateInit failed\n");
                ret = -EIO;
                goto out;
        }
 
-       workspace->def_strm.total_in = 0;
-       workspace->def_strm.total_out = 0;
+       workspace->strm.total_in = 0;
+       workspace->strm.total_out = 0;
 
        in_page = find_get_page(mapping, start >> PAGE_CACHE_SHIFT);
        data_in = kmap(in_page);
@@ -117,25 +115,25 @@ static int zlib_compress_pages(struct list_head *ws,
        pages[0] = out_page;
        nr_pages = 1;
 
-       workspace->def_strm.next_in = data_in;
-       workspace->def_strm.next_out = cpage_out;
-       workspace->def_strm.avail_out = PAGE_CACHE_SIZE;
-       workspace->def_strm.avail_in = min(len, PAGE_CACHE_SIZE);
+       workspace->strm.next_in = data_in;
+       workspace->strm.next_out = cpage_out;
+       workspace->strm.avail_out = PAGE_CACHE_SIZE;
+       workspace->strm.avail_in = min(len, PAGE_CACHE_SIZE);
 
-       while (workspace->def_strm.total_in < len) {
-               ret = zlib_deflate(&workspace->def_strm, Z_SYNC_FLUSH);
+       while (workspace->strm.total_in < len) {
+               ret = zlib_deflate(&workspace->strm, Z_SYNC_FLUSH);
                if (ret != Z_OK) {
                        printk(KERN_DEBUG "BTRFS: deflate in loop returned %d\n",
                               ret);
-                       zlib_deflateEnd(&workspace->def_strm);
+                       zlib_deflateEnd(&workspace->strm);
                        ret = -EIO;
                        goto out;
                }
 
                /* we're making it bigger, give up */
-               if (workspace->def_strm.total_in > 8192 &&
-                   workspace->def_strm.total_in <
-                   workspace->def_strm.total_out) {
+               if (workspace->strm.total_in > 8192 &&
+                   workspace->strm.total_in <
+                   workspace->strm.total_out) {
                        ret = -E2BIG;
                        goto out;
                }
@@ -143,7 +141,7 @@ static int zlib_compress_pages(struct list_head *ws,
                 * before the total_in so we will pull in a new page for
                 * the stream end if required
                 */
-               if (workspace->def_strm.avail_out == 0) {
+               if (workspace->strm.avail_out == 0) {
                        kunmap(out_page);
                        if (nr_pages == nr_dest_pages) {
                                out_page = NULL;
@@ -158,19 +156,19 @@ static int zlib_compress_pages(struct list_head *ws,
                        cpage_out = kmap(out_page);
                        pages[nr_pages] = out_page;
                        nr_pages++;
-                       workspace->def_strm.avail_out = PAGE_CACHE_SIZE;
-                       workspace->def_strm.next_out = cpage_out;
+                       workspace->strm.avail_out = PAGE_CACHE_SIZE;
+                       workspace->strm.next_out = cpage_out;
                }
                /* we're all done */
-               if (workspace->def_strm.total_in >= len)
+               if (workspace->strm.total_in >= len)
                        break;
 
                /* we've read in a full page, get a new one */
-               if (workspace->def_strm.avail_in == 0) {
-                       if (workspace->def_strm.total_out > max_out)
+               if (workspace->strm.avail_in == 0) {
+                       if (workspace->strm.total_out > max_out)
                                break;
 
-                       bytes_left = len - workspace->def_strm.total_in;
+                       bytes_left = len - workspace->strm.total_in;
                        kunmap(in_page);
                        page_cache_release(in_page);
 
@@ -178,28 +176,28 @@ static int zlib_compress_pages(struct list_head *ws,
                        in_page = find_get_page(mapping,
                                                start >> PAGE_CACHE_SHIFT);
                        data_in = kmap(in_page);
-                       workspace->def_strm.avail_in = min(bytes_left,
+                       workspace->strm.avail_in = min(bytes_left,
                                                           PAGE_CACHE_SIZE);
-                       workspace->def_strm.next_in = data_in;
+                       workspace->strm.next_in = data_in;
                }
        }
-       workspace->def_strm.avail_in = 0;
-       ret = zlib_deflate(&workspace->def_strm, Z_FINISH);
-       zlib_deflateEnd(&workspace->def_strm);
+       workspace->strm.avail_in = 0;
+       ret = zlib_deflate(&workspace->strm, Z_FINISH);
+       zlib_deflateEnd(&workspace->strm);
 
        if (ret != Z_STREAM_END) {
                ret = -EIO;
                goto out;
        }
 
-       if (workspace->def_strm.total_out >= workspace->def_strm.total_in) {
+       if (workspace->strm.total_out >= workspace->strm.total_in) {
                ret = -E2BIG;
                goto out;
        }
 
        ret = 0;
-       *total_out = workspace->def_strm.total_out;
-       *total_in = workspace->def_strm.total_in;
+       *total_out = workspace->strm.total_out;
+       *total_in = workspace->strm.total_in;
 out:
        *out_pages = nr_pages;
        if (out_page)
@@ -225,19 +223,18 @@ static int zlib_decompress_biovec(struct list_head *ws, struct page **pages_in,
        size_t total_out = 0;
        unsigned long page_in_index = 0;
        unsigned long page_out_index = 0;
-       unsigned long total_pages_in = (srclen + PAGE_CACHE_SIZE - 1) /
-                                       PAGE_CACHE_SIZE;
+       unsigned long total_pages_in = DIV_ROUND_UP(srclen, PAGE_CACHE_SIZE);
        unsigned long buf_start;
        unsigned long pg_offset;
 
        data_in = kmap(pages_in[page_in_index]);
-       workspace->inf_strm.next_in = data_in;
-       workspace->inf_strm.avail_in = min_t(size_t, srclen, PAGE_CACHE_SIZE);
-       workspace->inf_strm.total_in = 0;
+       workspace->strm.next_in = data_in;
+       workspace->strm.avail_in = min_t(size_t, srclen, PAGE_CACHE_SIZE);
+       workspace->strm.total_in = 0;
 
-       workspace->inf_strm.total_out = 0;
-       workspace->inf_strm.next_out = workspace->buf;
-       workspace->inf_strm.avail_out = PAGE_CACHE_SIZE;
+       workspace->strm.total_out = 0;
+       workspace->strm.next_out = workspace->buf;
+       workspace->strm.avail_out = PAGE_CACHE_SIZE;
        pg_offset = 0;
 
        /* If it's deflate, and it's got no preset dictionary, then
@@ -247,21 +244,21 @@ static int zlib_decompress_biovec(struct list_head *ws, struct page **pages_in,
            !(((data_in[0]<<8) + data_in[1]) % 31)) {
 
                wbits = -((data_in[0] >> 4) + 8);
-               workspace->inf_strm.next_in += 2;
-               workspace->inf_strm.avail_in -= 2;
+               workspace->strm.next_in += 2;
+               workspace->strm.avail_in -= 2;
        }
 
-       if (Z_OK != zlib_inflateInit2(&workspace->inf_strm, wbits)) {
+       if (Z_OK != zlib_inflateInit2(&workspace->strm, wbits)) {
                printk(KERN_WARNING "BTRFS: inflateInit failed\n");
                return -EIO;
        }
-       while (workspace->inf_strm.total_in < srclen) {
-               ret = zlib_inflate(&workspace->inf_strm, Z_NO_FLUSH);
+       while (workspace->strm.total_in < srclen) {
+               ret = zlib_inflate(&workspace->strm, Z_NO_FLUSH);
                if (ret != Z_OK && ret != Z_STREAM_END)
                        break;
 
                buf_start = total_out;
-               total_out = workspace->inf_strm.total_out;
+               total_out = workspace->strm.total_out;
 
                /* we didn't make progress in this inflate call, we're done */
                if (buf_start == total_out)
@@ -276,10 +273,10 @@ static int zlib_decompress_biovec(struct list_head *ws, struct page **pages_in,
                        goto done;
                }
 
-               workspace->inf_strm.next_out = workspace->buf;
-               workspace->inf_strm.avail_out = PAGE_CACHE_SIZE;
+               workspace->strm.next_out = workspace->buf;
+               workspace->strm.avail_out = PAGE_CACHE_SIZE;
 
-               if (workspace->inf_strm.avail_in == 0) {
+               if (workspace->strm.avail_in == 0) {
                        unsigned long tmp;
                        kunmap(pages_in[page_in_index]);
                        page_in_index++;
@@ -288,9 +285,9 @@ static int zlib_decompress_biovec(struct list_head *ws, struct page **pages_in,
                                break;
                        }
                        data_in = kmap(pages_in[page_in_index]);
-                       workspace->inf_strm.next_in = data_in;
-                       tmp = srclen - workspace->inf_strm.total_in;
-                       workspace->inf_strm.avail_in = min(tmp,
+                       workspace->strm.next_in = data_in;
+                       tmp = srclen - workspace->strm.total_in;
+                       workspace->strm.avail_in = min(tmp,
                                                           PAGE_CACHE_SIZE);
                }
        }
@@ -299,7 +296,7 @@ static int zlib_decompress_biovec(struct list_head *ws, struct page **pages_in,
        else
                ret = 0;
 done:
-       zlib_inflateEnd(&workspace->inf_strm);
+       zlib_inflateEnd(&workspace->strm);
        if (data_in)
                kunmap(pages_in[page_in_index]);
        return ret;
@@ -317,13 +314,13 @@ static int zlib_decompress(struct list_head *ws, unsigned char *data_in,
        unsigned long total_out = 0;
        char *kaddr;
 
-       workspace->inf_strm.next_in = data_in;
-       workspace->inf_strm.avail_in = srclen;
-       workspace->inf_strm.total_in = 0;
+       workspace->strm.next_in = data_in;
+       workspace->strm.avail_in = srclen;
+       workspace->strm.total_in = 0;
 
-       workspace->inf_strm.next_out = workspace->buf;
-       workspace->inf_strm.avail_out = PAGE_CACHE_SIZE;
-       workspace->inf_strm.total_out = 0;
+       workspace->strm.next_out = workspace->buf;
+       workspace->strm.avail_out = PAGE_CACHE_SIZE;
+       workspace->strm.total_out = 0;
        /* If it's deflate, and it's got no preset dictionary, then
           we can tell zlib to skip the adler32 check. */
        if (srclen > 2 && !(data_in[1] & PRESET_DICT) &&
@@ -331,11 +328,11 @@ static int zlib_decompress(struct list_head *ws, unsigned char *data_in,
            !(((data_in[0]<<8) + data_in[1]) % 31)) {
 
                wbits = -((data_in[0] >> 4) + 8);
-               workspace->inf_strm.next_in += 2;
-               workspace->inf_strm.avail_in -= 2;
+               workspace->strm.next_in += 2;
+               workspace->strm.avail_in -= 2;
        }
 
-       if (Z_OK != zlib_inflateInit2(&workspace->inf_strm, wbits)) {
+       if (Z_OK != zlib_inflateInit2(&workspace->strm, wbits)) {
                printk(KERN_WARNING "BTRFS: inflateInit failed\n");
                return -EIO;
        }
@@ -346,12 +343,12 @@ static int zlib_decompress(struct list_head *ws, unsigned char *data_in,
                unsigned long bytes;
                unsigned long pg_offset = 0;
 
-               ret = zlib_inflate(&workspace->inf_strm, Z_NO_FLUSH);
+               ret = zlib_inflate(&workspace->strm, Z_NO_FLUSH);
                if (ret != Z_OK && ret != Z_STREAM_END)
                        break;
 
                buf_start = total_out;
-               total_out = workspace->inf_strm.total_out;
+               total_out = workspace->strm.total_out;
 
                if (total_out == buf_start) {
                        ret = -EIO;
@@ -377,8 +374,8 @@ static int zlib_decompress(struct list_head *ws, unsigned char *data_in,
                pg_offset += bytes;
                bytes_left -= bytes;
 next:
-               workspace->inf_strm.next_out = workspace->buf;
-               workspace->inf_strm.avail_out = PAGE_CACHE_SIZE;
+               workspace->strm.next_out = workspace->buf;
+               workspace->strm.avail_out = PAGE_CACHE_SIZE;
        }
 
        if (ret != Z_STREAM_END && bytes_left != 0)
@@ -386,7 +383,7 @@ next:
        else
                ret = 0;
 
-       zlib_inflateEnd(&workspace->inf_strm);
+       zlib_inflateEnd(&workspace->strm);
        return ret;
 }
 
index 44c14a87750e7780ecb34468e60ed77b61628bf3..9614adc7e7544f3e253260e2d43064a6ad6bd96e 100644 (file)
@@ -1331,8 +1331,8 @@ lookup_bh_lru(struct block_device *bdev, sector_t block, unsigned size)
        for (i = 0; i < BH_LRU_SIZE; i++) {
                struct buffer_head *bh = __this_cpu_read(bh_lrus.bhs[i]);
 
-               if (bh && bh->b_bdev == bdev &&
-                               bh->b_blocknr == block && bh->b_size == size) {
+               if (bh && bh->b_blocknr == block && bh->b_bdev == bdev &&
+                   bh->b_size == size) {
                        if (i) {
                                while (i) {
                                        __this_cpu_write(bh_lrus.bhs[i],
@@ -2318,6 +2318,11 @@ static int cont_expand_zero(struct file *file, struct address_space *mapping,
                err = 0;
 
                balance_dirty_pages_ratelimited(mapping);
+
+               if (unlikely(fatal_signal_pending(current))) {
+                       err = -EINTR;
+                       goto out;
+               }
        }
 
        /* page covers the boundary, find the boundary offset */
index 584743d456c3a7fd241e15c7fffb920a6081442b..1c7293c3a93ae935c5be8cdfc149fcd3f84e0dad 100644 (file)
@@ -268,20 +268,27 @@ static void cachefiles_drop_object(struct fscache_object *_object)
        ASSERT((atomic_read(&object->usage) & 0xffff0000) != 0x6b6b0000);
 #endif
 
-       /* delete retired objects */
-       if (test_bit(FSCACHE_OBJECT_RETIRED, &object->fscache.flags) &&
-           _object != cache->cache.fsdef
-           ) {
-               _debug("- retire object OBJ%x", object->fscache.debug_id);
-               cachefiles_begin_secure(cache, &saved_cred);
-               cachefiles_delete_object(cache, object);
-               cachefiles_end_secure(cache, saved_cred);
-       }
+       /* We need to tidy the object up if we did in fact manage to open it.
+        * It's possible for us to get here before the object is fully
+        * initialised if the parent goes away or the object gets retired
+        * before we set it up.
+        */
+       if (object->dentry) {
+               /* delete retired objects */
+               if (test_bit(FSCACHE_OBJECT_RETIRED, &object->fscache.flags) &&
+                   _object != cache->cache.fsdef
+                   ) {
+                       _debug("- retire object OBJ%x", object->fscache.debug_id);
+                       cachefiles_begin_secure(cache, &saved_cred);
+                       cachefiles_delete_object(cache, object);
+                       cachefiles_end_secure(cache, saved_cred);
+               }
 
-       /* close the filesystem stuff attached to the object */
-       if (object->backer != object->dentry)
-               dput(object->backer);
-       object->backer = NULL;
+               /* close the filesystem stuff attached to the object */
+               if (object->backer != object->dentry)
+                       dput(object->backer);
+               object->backer = NULL;
+       }
 
        /* note that the object is now inactive */
        if (test_bit(CACHEFILES_OBJECT_ACTIVE, &object->flags)) {
index dad7d9542a24bc287e94567fd7e2c1f4c329ae05..e12f189d539b62e5e1bda1c8c28f3a9df0fe44db 100644 (file)
@@ -189,7 +189,7 @@ try_again:
        /* an old object from a previous incarnation is hogging the slot - we
         * need to wait for it to be destroyed */
 wait_for_old_object:
-       if (fscache_object_is_live(&object->fscache)) {
+       if (fscache_object_is_live(&xobject->fscache)) {
                pr_err("\n");
                pr_err("Error: Unexpected object collision\n");
                cachefiles_printk_object(object, xobject);
index 25e745b8eb1b5fe127be7fb20998444432ca9263..616db0e77b44bd8481782047829dfd06605700ae 100644 (file)
@@ -880,7 +880,6 @@ int cachefiles_write_page(struct fscache_storage *op, struct page *page)
 {
        struct cachefiles_object *object;
        struct cachefiles_cache *cache;
-       mm_segment_t old_fs;
        struct file *file;
        struct path path;
        loff_t pos, eof;
@@ -914,36 +913,27 @@ int cachefiles_write_page(struct fscache_storage *op, struct page *page)
        if (IS_ERR(file)) {
                ret = PTR_ERR(file);
        } else {
-               ret = -EIO;
-               if (file->f_op->write) {
-                       pos = (loff_t) page->index << PAGE_SHIFT;
-
-                       /* we mustn't write more data than we have, so we have
-                        * to beware of a partial page at EOF */
-                       eof = object->fscache.store_limit_l;
-                       len = PAGE_SIZE;
-                       if (eof & ~PAGE_MASK) {
-                               ASSERTCMP(pos, <, eof);
-                               if (eof - pos < PAGE_SIZE) {
-                                       _debug("cut short %llx to %llx",
-                                              pos, eof);
-                                       len = eof - pos;
-                                       ASSERTCMP(pos + len, ==, eof);
-                               }
+               pos = (loff_t) page->index << PAGE_SHIFT;
+
+               /* we mustn't write more data than we have, so we have
+                * to beware of a partial page at EOF */
+               eof = object->fscache.store_limit_l;
+               len = PAGE_SIZE;
+               if (eof & ~PAGE_MASK) {
+                       ASSERTCMP(pos, <, eof);
+                       if (eof - pos < PAGE_SIZE) {
+                               _debug("cut short %llx to %llx",
+                                      pos, eof);
+                               len = eof - pos;
+                               ASSERTCMP(pos + len, ==, eof);
                        }
-
-                       data = kmap(page);
-                       file_start_write(file);
-                       old_fs = get_fs();
-                       set_fs(KERNEL_DS);
-                       ret = file->f_op->write(
-                               file, (const void __user *) data, len, &pos);
-                       set_fs(old_fs);
-                       kunmap(page);
-                       file_end_write(file);
-                       if (ret != len)
-                               ret = -EIO;
                }
+
+               data = kmap(page);
+               ret = __kernel_write(file, data, len, &pos);
+               kunmap(page);
+               if (ret != len)
+                       ret = -EIO;
                fput(file);
        }
 
index c29d6ae6887489c29902bec33c4118d4d807e9dc..b6c59eaa4f64356ba069219551c78870035d74d9 100644 (file)
@@ -1069,7 +1069,6 @@ static int ceph_d_revalidate(struct dentry *dentry, unsigned int flags)
                ceph_dentry_lru_touch(dentry);
        } else {
                ceph_dir_clear_complete(dir);
-               d_drop(dentry);
        }
        iput(dir);
        return valid;
index 58df174deb10e5b354a9003ea3ccbfc5240e5cd0..b8602f19981560bc51fe9123689d75eed24f8e0c 100644 (file)
@@ -195,15 +195,15 @@ char *cifs_compose_mount_options(const char *sb_mountdata,
                else
                        noff = tkn_e - (sb_mountdata + off) + 1;
 
-               if (strnicmp(sb_mountdata + off, "unc=", 4) == 0) {
+               if (strncasecmp(sb_mountdata + off, "unc=", 4) == 0) {
                        off += noff;
                        continue;
                }
-               if (strnicmp(sb_mountdata + off, "ip=", 3) == 0) {
+               if (strncasecmp(sb_mountdata + off, "ip=", 3) == 0) {
                        off += noff;
                        continue;
                }
-               if (strnicmp(sb_mountdata + off, "prefixpath=", 11) == 0) {
+               if (strncasecmp(sb_mountdata + off, "prefixpath=", 11) == 0) {
                        off += noff;
                        continue;
                }
index a3e932547617ea016ebb59ff2c9aa738d157153b..f4cf200b3c76714ca5a059b1ecdcca6f2e77b338 100644 (file)
@@ -62,7 +62,6 @@ cifs_spnego_key_destroy(struct key *key)
 struct key_type cifs_spnego_key_type = {
        .name           = "cifs.spnego",
        .instantiate    = cifs_spnego_key_instantiate,
-       .match          = user_match,
        .destroy        = cifs_spnego_key_destroy,
        .describe       = user_describe,
 };
index 7ff866dbb89eb7b31033ce1e99f7b56f664fbdf6..6d00c419cbae0b54016ba997f55baf1ac7c54956 100644 (file)
@@ -84,7 +84,6 @@ static struct key_type cifs_idmap_key_type = {
        .instantiate = cifs_idmap_key_instantiate,
        .destroy     = cifs_idmap_key_destroy,
        .describe    = user_describe,
-       .match       = user_match,
 };
 
 static char *
index 889b9845575079517e92ee387fe5c863751c3848..9d7996e8e7932bc5ad386c894e7955975394490c 100644 (file)
@@ -813,7 +813,8 @@ static loff_t cifs_llseek(struct file *file, loff_t offset, int whence)
        return generic_file_llseek(file, offset, whence);
 }
 
-static int cifs_setlease(struct file *file, long arg, struct file_lock **lease)
+static int
+cifs_setlease(struct file *file, long arg, struct file_lock **lease, void **priv)
 {
        /*
         * Note that this is called by vfs setlease with i_lock held to
@@ -829,7 +830,7 @@ static int cifs_setlease(struct file *file, long arg, struct file_lock **lease)
        if (arg == F_UNLCK ||
            ((arg == F_RDLCK) && CIFS_CACHE_READ(CIFS_I(inode))) ||
            ((arg == F_WRLCK) && CIFS_CACHE_WRITE(CIFS_I(inode))))
-               return generic_setlease(file, arg, lease);
+               return generic_setlease(file, arg, lease, priv);
        else if (tlink_tcon(cfile->tlink)->local_lease &&
                 !CIFS_CACHE_READ(CIFS_I(inode)))
                /*
@@ -840,7 +841,7 @@ static int cifs_setlease(struct file *file, long arg, struct file_lock **lease)
                 * knows that the file won't be changed on the server by anyone
                 * else.
                 */
-               return generic_setlease(file, arg, lease);
+               return generic_setlease(file, arg, lease, priv);
        else
                return -EAGAIN;
 }
index 36ca2045009bf342ef507c132921484c7eaf7ded..239e1fb330002f5153cc2bbb1047506254aa5276 100644 (file)
@@ -1718,7 +1718,7 @@ cifs_parse_mount_options(const char *mountdata, const char *devname,
                                goto cifs_parse_mount_err;
                        }
 
-                        if (strnicmp(string, "default", 7) != 0) {
+                        if (strncasecmp(string, "default", 7) != 0) {
                                vol->iocharset = kstrdup(string,
                                                         GFP_KERNEL);
                                if (!vol->iocharset) {
@@ -1790,7 +1790,7 @@ cifs_parse_mount_options(const char *mountdata, const char *devname,
                        if (string == NULL)
                                goto out_nomem;
 
-                       if (strnicmp(string, "1", 1) == 0) {
+                       if (strncasecmp(string, "1", 1) == 0) {
                                /* This is the default */
                                break;
                        }
index 6cbd9c688cfe818a773a2a7f42c64ce59d693de1..073640675a39684cb698ffc46e445bd7710c22c4 100644 (file)
@@ -461,8 +461,8 @@ cifs_atomic_open(struct inode *inode, struct dentry *direntry,
 
        xid = get_xid();
 
-       cifs_dbg(FYI, "parent inode = 0x%p name is: %s and dentry = 0x%p\n",
-                inode, direntry->d_name.name, direntry);
+       cifs_dbg(FYI, "parent inode = 0x%p name is: %pd and dentry = 0x%p\n",
+                inode, direntry, direntry);
 
        tlink = cifs_sb_tlink(CIFS_SB(inode->i_sb));
        if (IS_ERR(tlink)) {
@@ -540,8 +540,8 @@ int cifs_create(struct inode *inode, struct dentry *direntry, umode_t mode,
        struct cifs_fid fid;
        __u32 oplock;
 
-       cifs_dbg(FYI, "cifs_create parent inode = 0x%p name is: %s and dentry = 0x%p\n",
-                inode, direntry->d_name.name, direntry);
+       cifs_dbg(FYI, "cifs_create parent inode = 0x%p name is: %pd and dentry = 0x%p\n",
+                inode, direntry, direntry);
 
        tlink = cifs_sb_tlink(CIFS_SB(inode->i_sb));
        rc = PTR_ERR(tlink);
@@ -713,8 +713,8 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry,
 
        xid = get_xid();
 
-       cifs_dbg(FYI, "parent inode = 0x%p name is: %s and dentry = 0x%p\n",
-                parent_dir_inode, direntry->d_name.name, direntry);
+       cifs_dbg(FYI, "parent inode = 0x%p name is: %pd and dentry = 0x%p\n",
+                parent_dir_inode, direntry, direntry);
 
        /* check whether path exists */
 
@@ -833,7 +833,7 @@ cifs_d_revalidate(struct dentry *direntry, unsigned int flags)
 {
        int rc = 0;
 
-       cifs_dbg(FYI, "In cifs d_delete, name = %s\n", direntry->d_name.name);
+       cifs_dbg(FYI, "In cifs d_delete, name = %pd\n", direntry);
 
        return rc;
 }     */
index 5f29354b072abfe2a44a4303edc92854c1959082..8f7b40fd8f3ba2947b1fad3821e18ac02c0349ae 100644 (file)
@@ -1650,8 +1650,8 @@ cifs_write(struct cifsFileInfo *open_file, __u32 pid, const char *write_data,
 
        cifs_sb = CIFS_SB(dentry->d_sb);
 
-       cifs_dbg(FYI, "write %zd bytes to offset %lld of %s\n",
-                write_size, *offset, dentry->d_name.name);
+       cifs_dbg(FYI, "write %zd bytes to offset %lld of %pd\n",
+                write_size, *offset, dentry);
 
        tcon = tlink_tcon(open_file->tlink);
        server = tcon->ses->server;
@@ -2273,8 +2273,8 @@ int cifs_strict_fsync(struct file *file, loff_t start, loff_t end,
 
        xid = get_xid();
 
-       cifs_dbg(FYI, "Sync file - name: %s datasync: 0x%x\n",
-                file->f_path.dentry->d_name.name, datasync);
+       cifs_dbg(FYI, "Sync file - name: %pD datasync: 0x%x\n",
+                file, datasync);
 
        if (!CIFS_CACHE_READ(CIFS_I(inode))) {
                rc = cifs_zap_mapping(inode);
@@ -2315,8 +2315,8 @@ int cifs_fsync(struct file *file, loff_t start, loff_t end, int datasync)
 
        xid = get_xid();
 
-       cifs_dbg(FYI, "Sync file - name: %s datasync: 0x%x\n",
-                file->f_path.dentry->d_name.name, datasync);
+       cifs_dbg(FYI, "Sync file - name: %pD datasync: 0x%x\n",
+                file, datasync);
 
        tcon = tlink_tcon(smbfile->tlink);
        if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOSSYNC)) {
index 7899a40465b303db85e1903e9fec1fe57124a261..8fd4ee8e07ff9ea0db8c6e83e26201f4d8134ce2 100644 (file)
@@ -1419,8 +1419,8 @@ cifs_posix_mkdir(struct inode *inode, struct dentry *dentry, umode_t mode,
        d_instantiate(dentry, newinode);
 
 #ifdef CONFIG_CIFS_DEBUG2
-       cifs_dbg(FYI, "instantiated dentry %p %s to inode %p\n",
-                dentry, dentry->d_name.name, newinode);
+       cifs_dbg(FYI, "instantiated dentry %p %pd to inode %p\n",
+                dentry, dentry, newinode);
 
        if (newinode->i_nlink != 2)
                cifs_dbg(FYI, "unexpected number of links %d\n",
@@ -2111,8 +2111,8 @@ cifs_setattr_unix(struct dentry *direntry, struct iattr *attrs)
        struct cifs_unix_set_info_args *args = NULL;
        struct cifsFileInfo *open_file;
 
-       cifs_dbg(FYI, "setattr_unix on file %s attrs->ia_valid=0x%x\n",
-                direntry->d_name.name, attrs->ia_valid);
+       cifs_dbg(FYI, "setattr_unix on file %pd attrs->ia_valid=0x%x\n",
+                direntry, attrs->ia_valid);
 
        xid = get_xid();
 
@@ -2254,8 +2254,8 @@ cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs)
 
        xid = get_xid();
 
-       cifs_dbg(FYI, "setattr on file %s attrs->iavalid 0x%x\n",
-                direntry->d_name.name, attrs->ia_valid);
+       cifs_dbg(FYI, "setattr on file %pd attrs->iavalid 0x%x\n",
+                direntry, attrs->ia_valid);
 
        if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_PERM)
                attrs->ia_valid |= ATTR_FORCE;
index b334a89d6a66eb2151973d6405083db3c254710b..d2141f1013829d028ac1b9df15f2a05b254923d4 100644 (file)
@@ -87,8 +87,6 @@ cifs_prime_dcache(struct dentry *parent, struct qstr *name,
                return;
 
        if (dentry) {
-               int err;
-
                inode = dentry->d_inode;
                if (inode) {
                        /*
@@ -105,10 +103,8 @@ cifs_prime_dcache(struct dentry *parent, struct qstr *name,
                                goto out;
                        }
                }
-               err = d_invalidate(dentry);
+               d_invalidate(dentry);
                dput(dentry);
-               if (err)
-                       return;
        }
 
        /*
index 66d3d3c6b4b248878af6d751178d055310224c3d..b13df99f3534b7e597a3d220949e7f924c1a7c65 100644 (file)
@@ -794,25 +794,21 @@ COMPAT_SYSCALL_DEFINE5(mount, const char __user *, dev_name,
        char *kernel_type;
        unsigned long data_page;
        char *kernel_dev;
-       struct filename *dir;
        int retval;
 
-       retval = copy_mount_string(type, &kernel_type);
-       if (retval < 0)
+       kernel_type = copy_mount_string(type);
+       retval = PTR_ERR(kernel_type);
+       if (IS_ERR(kernel_type))
                goto out;
 
-       dir = getname(dir_name);
-       retval = PTR_ERR(dir);
-       if (IS_ERR(dir))
+       kernel_dev = copy_mount_string(dev_name);
+       retval = PTR_ERR(kernel_dev);
+       if (IS_ERR(kernel_dev))
                goto out1;
 
-       retval = copy_mount_string(dev_name, &kernel_dev);
-       if (retval < 0)
-               goto out2;
-
        retval = copy_mount_options(data, &data_page);
        if (retval < 0)
-               goto out3;
+               goto out2;
 
        retval = -EINVAL;
 
@@ -821,19 +817,17 @@ COMPAT_SYSCALL_DEFINE5(mount, const char __user *, dev_name,
                        do_ncp_super_data_conv((void *)data_page);
                } else if (!strcmp(kernel_type, NFS4_NAME)) {
                        if (do_nfs4_super_data_conv((void *) data_page))
-                               goto out4;
+                               goto out3;
                }
        }
 
-       retval = do_mount(kernel_dev, dir->name, kernel_type,
+       retval = do_mount(kernel_dev, dir_name, kernel_type,
                        flags, (void*)data_page);
 
- out4:
-       free_page(data_page);
  out3:
-       kfree(kernel_dev);
+       free_page(data_page);
  out2:
-       putname(dir);
+       kfree(kernel_dev);
  out1:
        kfree(kernel_type);
  out:
index a93f7e6ea4cf935aea64e8266b221a2c53477628..b5c86ffd5033420523934c7153080d8cdc605bea 100644 (file)
@@ -199,6 +199,14 @@ static int format_corename(struct core_name *cn, struct coredump_params *cprm)
                                err = cn_printf(cn, "%d",
                                              task_tgid_nr(current));
                                break;
+                       case 'i':
+                               err = cn_printf(cn, "%d",
+                                             task_pid_vnr(current));
+                               break;
+                       case 'I':
+                               err = cn_printf(cn, "%d",
+                                             task_pid_nr(current));
+                               break;
                        /* uid */
                        case 'u':
                                err = cn_printf(cn, "%d", cred->uid);
index cb25a1a5e3073748cbef154b6d3575da3f55982d..d5a23fd0da903848682c659085a6c560e48d8a8c 100644 (file)
@@ -235,18 +235,49 @@ static inline int dentry_cmp(const struct dentry *dentry, const unsigned char *c
        return dentry_string_cmp(cs, ct, tcount);
 }
 
+struct external_name {
+       union {
+               atomic_t count;
+               struct rcu_head head;
+       } u;
+       unsigned char name[];
+};
+
+static inline struct external_name *external_name(struct dentry *dentry)
+{
+       return container_of(dentry->d_name.name, struct external_name, name[0]);
+}
+
 static void __d_free(struct rcu_head *head)
 {
        struct dentry *dentry = container_of(head, struct dentry, d_u.d_rcu);
 
        WARN_ON(!hlist_unhashed(&dentry->d_alias));
-       if (dname_external(dentry))
-               kfree(dentry->d_name.name);
        kmem_cache_free(dentry_cache, dentry); 
 }
 
+static void __d_free_external(struct rcu_head *head)
+{
+       struct dentry *dentry = container_of(head, struct dentry, d_u.d_rcu);
+       WARN_ON(!hlist_unhashed(&dentry->d_alias));
+       kfree(external_name(dentry));
+       kmem_cache_free(dentry_cache, dentry); 
+}
+
+static inline int dname_external(const struct dentry *dentry)
+{
+       return dentry->d_name.name != dentry->d_iname;
+}
+
 static void dentry_free(struct dentry *dentry)
 {
+       if (unlikely(dname_external(dentry))) {
+               struct external_name *p = external_name(dentry);
+               if (likely(atomic_dec_and_test(&p->u.count))) {
+                       call_rcu(&dentry->d_u.d_rcu, __d_free_external);
+                       return;
+               }
+       }
        /* if dentry was never visible to RCU, immediate free is OK */
        if (!(dentry->d_flags & DCACHE_RCUACCESS))
                __d_free(&dentry->d_u.d_rcu);
@@ -456,7 +487,7 @@ static void __dentry_kill(struct dentry *dentry)
         * inform the fs via d_prune that this dentry is about to be
         * unhashed and destroyed.
         */
-       if ((dentry->d_flags & DCACHE_OP_PRUNE) && !d_unhashed(dentry))
+       if (dentry->d_flags & DCACHE_OP_PRUNE)
                dentry->d_op->d_prune(dentry);
 
        if (dentry->d_flags & DCACHE_LRU_LIST) {
@@ -619,62 +650,6 @@ kill_it:
 }
 EXPORT_SYMBOL(dput);
 
-/**
- * d_invalidate - invalidate a dentry
- * @dentry: dentry to invalidate
- *
- * Try to invalidate the dentry if it turns out to be
- * possible. If there are other dentries that can be
- * reached through this one we can't delete it and we
- * return -EBUSY. On success we return 0.
- *
- * no dcache lock.
- */
-int d_invalidate(struct dentry * dentry)
-{
-       /*
-        * If it's already been dropped, return OK.
-        */
-       spin_lock(&dentry->d_lock);
-       if (d_unhashed(dentry)) {
-               spin_unlock(&dentry->d_lock);
-               return 0;
-       }
-       /*
-        * Check whether to do a partial shrink_dcache
-        * to get rid of unused child entries.
-        */
-       if (!list_empty(&dentry->d_subdirs)) {
-               spin_unlock(&dentry->d_lock);
-               shrink_dcache_parent(dentry);
-               spin_lock(&dentry->d_lock);
-       }
-
-       /*
-        * Somebody else still using it?
-        *
-        * If it's a directory, we can't drop it
-        * for fear of somebody re-populating it
-        * with children (even though dropping it
-        * would make it unreachable from the root,
-        * we might still populate it if it was a
-        * working directory or similar).
-        * We also need to leave mountpoints alone,
-        * directory or not.
-        */
-       if (dentry->d_lockref.count > 1 && dentry->d_inode) {
-               if (S_ISDIR(dentry->d_inode->i_mode) || d_mountpoint(dentry)) {
-                       spin_unlock(&dentry->d_lock);
-                       return -EBUSY;
-               }
-       }
-
-       __d_drop(dentry);
-       spin_unlock(&dentry->d_lock);
-       return 0;
-}
-EXPORT_SYMBOL(d_invalidate);
 
 /* This must be called with d_lock held */
 static inline void __dget_dlock(struct dentry *dentry)
@@ -735,7 +710,8 @@ EXPORT_SYMBOL(dget_parent);
  * acquire the reference to alias and return it. Otherwise return NULL.
  * Notice that if inode is a directory there can be only one alias and
  * it can be unhashed only if it has no children, or if it is the root
- * of a filesystem.
+ * of a filesystem, or if the directory was renamed and d_revalidate
+ * was the first vfs operation to notice.
  *
  * If the inode has an IS_ROOT, DCACHE_DISCONNECTED alias, then prefer
  * any other hashed alias over that one.
@@ -799,20 +775,13 @@ restart:
        hlist_for_each_entry(dentry, &inode->i_dentry, d_alias) {
                spin_lock(&dentry->d_lock);
                if (!dentry->d_lockref.count) {
-                       /*
-                        * inform the fs via d_prune that this dentry
-                        * is about to be unhashed and destroyed.
-                        */
-                       if ((dentry->d_flags & DCACHE_OP_PRUNE) &&
-                           !d_unhashed(dentry))
-                               dentry->d_op->d_prune(dentry);
-
-                       __dget_dlock(dentry);
-                       __d_drop(dentry);
-                       spin_unlock(&dentry->d_lock);
-                       spin_unlock(&inode->i_lock);
-                       dput(dentry);
-                       goto restart;
+                       struct dentry *parent = lock_parent(dentry);
+                       if (likely(!dentry->d_lockref.count)) {
+                               __dentry_kill(dentry);
+                               goto restart;
+                       }
+                       if (parent)
+                               spin_unlock(&parent->d_lock);
                }
                spin_unlock(&dentry->d_lock);
        }
@@ -1193,7 +1162,7 @@ EXPORT_SYMBOL(have_submounts);
  * reachable (e.g. NFS can unhash a directory dentry and then the complete
  * subtree can become unreachable).
  *
- * Only one of check_submounts_and_drop() and d_set_mounted() must succeed.  For
+ * Only one of d_invalidate() and d_set_mounted() must succeed.  For
  * this reason take rename_lock and d_lock on dentry and ancestors.
  */
 int d_set_mounted(struct dentry *dentry)
@@ -1202,7 +1171,7 @@ int d_set_mounted(struct dentry *dentry)
        int ret = -ENOENT;
        write_seqlock(&rename_lock);
        for (p = dentry->d_parent; !IS_ROOT(p); p = p->d_parent) {
-               /* Need exclusion wrt. check_submounts_and_drop() */
+               /* Need exclusion wrt. d_invalidate() */
                spin_lock(&p->d_lock);
                if (unlikely(d_unhashed(p))) {
                        spin_unlock(&p->d_lock);
@@ -1346,70 +1315,84 @@ void shrink_dcache_for_umount(struct super_block *sb)
        }
 }
 
-static enum d_walk_ret check_and_collect(void *_data, struct dentry *dentry)
+struct detach_data {
+       struct select_data select;
+       struct dentry *mountpoint;
+};
+static enum d_walk_ret detach_and_collect(void *_data, struct dentry *dentry)
 {
-       struct select_data *data = _data;
+       struct detach_data *data = _data;
 
        if (d_mountpoint(dentry)) {
-               data->found = -EBUSY;
+               __dget_dlock(dentry);
+               data->mountpoint = dentry;
                return D_WALK_QUIT;
        }
 
-       return select_collect(_data, dentry);
+       return select_collect(&data->select, dentry);
 }
 
 static void check_and_drop(void *_data)
 {
-       struct select_data *data = _data;
+       struct detach_data *data = _data;
 
-       if (d_mountpoint(data->start))
-               data->found = -EBUSY;
-       if (!data->found)
-               __d_drop(data->start);
+       if (!data->mountpoint && !data->select.found)
+               __d_drop(data->select.start);
 }
 
 /**
- * check_submounts_and_drop - prune dcache, check for submounts and drop
+ * d_invalidate - detach submounts, prune dcache, and drop
+ * @dentry: dentry to invalidate (aka detach, prune and drop)
  *
- * All done as a single atomic operation relative to has_unlinked_ancestor().
- * Returns 0 if successfully unhashed @parent.  If there were submounts then
- * return -EBUSY.
+ * no dcache lock.
  *
- * @dentry: dentry to prune and drop
+ * The final d_drop is done as an atomic operation relative to
+ * rename_lock ensuring there are no races with d_set_mounted.  This
+ * ensures there are no unhashed dentries on the path to a mountpoint.
  */
-int check_submounts_and_drop(struct dentry *dentry)
+void d_invalidate(struct dentry *dentry)
 {
-       int ret = 0;
+       /*
+        * If it's already been dropped, return OK.
+        */
+       spin_lock(&dentry->d_lock);
+       if (d_unhashed(dentry)) {
+               spin_unlock(&dentry->d_lock);
+               return;
+       }
+       spin_unlock(&dentry->d_lock);
 
        /* Negative dentries can be dropped without further checks */
        if (!dentry->d_inode) {
                d_drop(dentry);
-               goto out;
+               return;
        }
 
        for (;;) {
-               struct select_data data;
+               struct detach_data data;
 
-               INIT_LIST_HEAD(&data.dispose);
-               data.start = dentry;
-               data.found = 0;
+               data.mountpoint = NULL;
+               INIT_LIST_HEAD(&data.select.dispose);
+               data.select.start = dentry;
+               data.select.found = 0;
+
+               d_walk(dentry, &data, detach_and_collect, check_and_drop);
 
-               d_walk(dentry, &data, check_and_collect, check_and_drop);
-               ret = data.found;
+               if (data.select.found)
+                       shrink_dentry_list(&data.select.dispose);
 
-               if (!list_empty(&data.dispose))
-                       shrink_dentry_list(&data.dispose);
+               if (data.mountpoint) {
+                       detach_mounts(data.mountpoint);
+                       dput(data.mountpoint);
+               }
 
-               if (ret <= 0)
+               if (!data.mountpoint && !data.select.found)
                        break;
 
                cond_resched();
        }
-
-out:
-       return ret;
 }
-EXPORT_SYMBOL(check_submounts_and_drop);
+EXPORT_SYMBOL(d_invalidate);
 
 /**
  * __d_alloc   -       allocate a dcache entry
@@ -1438,11 +1421,14 @@ struct dentry *__d_alloc(struct super_block *sb, const struct qstr *name)
         */
        dentry->d_iname[DNAME_INLINE_LEN-1] = 0;
        if (name->len > DNAME_INLINE_LEN-1) {
-               dname = kmalloc(name->len + 1, GFP_KERNEL);
-               if (!dname) {
+               size_t size = offsetof(struct external_name, name[1]);
+               struct external_name *p = kmalloc(size + name->len, GFP_KERNEL);
+               if (!p) {
                        kmem_cache_free(dentry_cache, dentry); 
                        return NULL;
                }
+               atomic_set(&p->u.count, 1);
+               dname = p->name;
        } else  {
                dname = dentry->d_iname;
        }       
@@ -2112,10 +2098,10 @@ struct dentry *d_lookup(const struct dentry *parent, const struct qstr *name)
        struct dentry *dentry;
        unsigned seq;
 
-        do {
-                seq = read_seqbegin(&rename_lock);
-                dentry = __d_lookup(parent, name);
-                if (dentry)
+       do {
+               seq = read_seqbegin(&rename_lock);
+               dentry = __d_lookup(parent, name);
+               if (dentry)
                        break;
        } while (read_seqretry(&rename_lock, seq));
        return dentry;
@@ -2372,11 +2358,10 @@ void dentry_update_name_case(struct dentry *dentry, struct qstr *name)
 }
 EXPORT_SYMBOL(dentry_update_name_case);
 
-static void switch_names(struct dentry *dentry, struct dentry *target,
-                        bool exchange)
+static void swap_names(struct dentry *dentry, struct dentry *target)
 {
-       if (dname_external(target)) {
-               if (dname_external(dentry)) {
+       if (unlikely(dname_external(target))) {
+               if (unlikely(dname_external(dentry))) {
                        /*
                         * Both external: swap the pointers
                         */
@@ -2392,7 +2377,7 @@ static void switch_names(struct dentry *dentry, struct dentry *target,
                        target->d_name.name = target->d_iname;
                }
        } else {
-               if (dname_external(dentry)) {
+               if (unlikely(dname_external(dentry))) {
                        /*
                         * dentry:external, target:internal.  Give dentry's
                         * storage to target and make dentry internal
@@ -2407,12 +2392,6 @@ static void switch_names(struct dentry *dentry, struct dentry *target,
                         */
                        unsigned int i;
                        BUILD_BUG_ON(!IS_ALIGNED(DNAME_INLINE_LEN, sizeof(long)));
-                       if (!exchange) {
-                               memcpy(dentry->d_iname, target->d_name.name,
-                                               target->d_name.len + 1);
-                               dentry->d_name.hash_len = target->d_name.hash_len;
-                               return;
-                       }
                        for (i = 0; i < DNAME_INLINE_LEN / sizeof(long); i++) {
                                swap(((long *) &dentry->d_iname)[i],
                                     ((long *) &target->d_iname)[i]);
@@ -2422,6 +2401,24 @@ static void switch_names(struct dentry *dentry, struct dentry *target,
        swap(dentry->d_name.hash_len, target->d_name.hash_len);
 }
 
+static void copy_name(struct dentry *dentry, struct dentry *target)
+{
+       struct external_name *old_name = NULL;
+       if (unlikely(dname_external(dentry)))
+               old_name = external_name(dentry);
+       if (unlikely(dname_external(target))) {
+               atomic_inc(&external_name(target)->u.count);
+               dentry->d_name = target->d_name;
+       } else {
+               memcpy(dentry->d_iname, target->d_name.name,
+                               target->d_name.len + 1);
+               dentry->d_name.name = dentry->d_iname;
+               dentry->d_name.hash_len = target->d_name.hash_len;
+       }
+       if (old_name && likely(atomic_dec_and_test(&old_name->u.count)))
+               kfree_rcu(old_name, u.head);
+}
+
 static void dentry_lock_for_move(struct dentry *dentry, struct dentry *target)
 {
        /*
@@ -2518,7 +2515,10 @@ static void __d_move(struct dentry *dentry, struct dentry *target,
        }
 
        /* Switch the names.. */
-       switch_names(dentry, target, exchange);
+       if (exchange)
+               swap_names(dentry, target);
+       else
+               copy_name(dentry, target);
 
        /* ... and switch them in the tree */
        if (IS_ROOT(dentry)) {
@@ -2625,10 +2625,8 @@ static struct dentry *__d_unalias(struct inode *inode,
                goto out_err;
        m2 = &alias->d_parent->d_inode->i_mutex;
 out_unalias:
-       if (likely(!d_mountpoint(alias))) {
-               __d_move(alias, dentry, false);
-               ret = alias;
-       }
+       __d_move(alias, dentry, false);
+       ret = alias;
 out_err:
        spin_unlock(&inode->i_lock);
        if (m2)
@@ -2810,6 +2808,9 @@ static int prepend(char **buffer, int *buflen, const char *str, int namelen)
  * the beginning of the name. The sequence number check at the caller will
  * retry it again when a d_move() does happen. So any garbage in the buffer
  * due to mismatched pointer and length will be discarded.
+ *
+ * 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)
 {
@@ -2817,6 +2818,8 @@ static int prepend_name(char **buffer, int *buflen, struct qstr *name)
        u32 dlen = ACCESS_ONCE(name->len);
        char *p;
 
+       smp_read_barrier_depends();
+
        *buflen -= dlen + 1;
        if (*buflen < 0)
                return -ENAMETOOLONG;
index f704458ea5f59a78d8b1121508cc9f22acfe6e45..e0ab3a93eeff01b42ec4ffaeb48160bcd0fc9ad6 100644 (file)
@@ -30,7 +30,7 @@ struct plock_op {
 
 struct plock_xop {
        struct plock_op xop;
-       void *callback;
+       int (*callback)(struct file_lock *fl, int result);
        void *fl;
        void *file;
        struct file_lock flc;
@@ -190,7 +190,7 @@ static int dlm_plock_callback(struct plock_op *op)
        struct file *file;
        struct file_lock *fl;
        struct file_lock *flc;
-       int (*notify)(void *, void *, int) = NULL;
+       int (*notify)(struct file_lock *fl, int result) = NULL;
        struct plock_xop *xop = (struct plock_xop *)op;
        int rv = 0;
 
@@ -209,7 +209,7 @@ static int dlm_plock_callback(struct plock_op *op)
        notify = xop->callback;
 
        if (op->info.rv) {
-               notify(fl, NULL, op->info.rv);
+               notify(fl, op->info.rv);
                goto out;
        }
 
@@ -228,7 +228,7 @@ static int dlm_plock_callback(struct plock_op *op)
                          (unsigned long long)op->info.number, file, fl);
        }
 
-       rv = notify(fl, NULL, 0);
+       rv = notify(fl, 0);
        if (rv) {
                /* XXX: We need to cancel the fs lock here: */
                log_print("dlm_plock_callback: lock granted after lock request "
index db0fad3269c0395f230c39cc0fcd6c9975f6d633..f5bce9096555a66be549a2735c783d1e8c18fa9a 100644 (file)
@@ -229,8 +229,8 @@ static int ecryptfs_open(struct inode *inode, struct file *file)
        if (rc) {
                printk(KERN_ERR "%s: Error attempting to initialize "
                        "the lower file for the dentry with name "
-                       "[%s]; rc = [%d]\n", __func__,
-                       ecryptfs_dentry->d_name.name, rc);
+                       "[%pd]; rc = [%d]\n", __func__,
+                       ecryptfs_dentry, rc);
                goto out_free;
        }
        if ((ecryptfs_inode_to_private(inode)->lower_file->f_flags & O_ACCMODE)
@@ -327,7 +327,7 @@ ecryptfs_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
        struct file *lower_file = ecryptfs_file_to_lower(file);
        long rc = -ENOIOCTLCMD;
 
-       if (lower_file->f_op && lower_file->f_op->compat_ioctl)
+       if (lower_file->f_op->compat_ioctl)
                rc = lower_file->f_op->compat_ioctl(lower_file, cmd, arg);
        return rc;
 }
index d4a9431ec73ce0cb215fc3b6e52727b4059f9528..1686dc2da9fd7627df7fea9035262ca900b5676e 100644 (file)
@@ -53,9 +53,7 @@ static void unlock_dir(struct dentry *dir)
 
 static int ecryptfs_inode_test(struct inode *inode, void *lower_inode)
 {
-       if (ecryptfs_inode_to_lower(inode) == (struct inode *)lower_inode)
-               return 1;
-       return 0;
+       return ecryptfs_inode_to_lower(inode) == lower_inode;
 }
 
 static int ecryptfs_inode_set(struct inode *inode, void *opaque)
@@ -192,12 +190,6 @@ ecryptfs_do_create(struct inode *directory_inode,
 
        lower_dentry = ecryptfs_dentry_to_lower(ecryptfs_dentry);
        lower_dir_dentry = lock_parent(lower_dentry);
-       if (IS_ERR(lower_dir_dentry)) {
-               ecryptfs_printk(KERN_ERR, "Error locking directory of "
-                               "dentry\n");
-               inode = ERR_CAST(lower_dir_dentry);
-               goto out;
-       }
        rc = vfs_create(lower_dir_dentry->d_inode, lower_dentry, mode, true);
        if (rc) {
                printk(KERN_ERR "%s: Failure to create dentry in lower fs; "
@@ -215,7 +207,6 @@ ecryptfs_do_create(struct inode *directory_inode,
        fsstack_copy_inode_size(directory_inode, lower_dir_dentry->d_inode);
 out_lock:
        unlock_dir(lower_dir_dentry);
-out:
        return inode;
 }
 
@@ -250,8 +241,8 @@ int ecryptfs_initialize_file(struct dentry *ecryptfs_dentry,
        if (rc) {
                printk(KERN_ERR "%s: Error attempting to initialize "
                        "the lower file for the dentry with name "
-                       "[%s]; rc = [%d]\n", __func__,
-                       ecryptfs_dentry->d_name.name, rc);
+                       "[%pd]; rc = [%d]\n", __func__,
+                       ecryptfs_dentry, rc);
                goto out;
        }
        rc = ecryptfs_write_metadata(ecryptfs_dentry, ecryptfs_inode);
@@ -313,8 +304,8 @@ static int ecryptfs_i_size_read(struct dentry *dentry, struct inode *inode)
        if (rc) {
                printk(KERN_ERR "%s: Error attempting to initialize "
                        "the lower file for the dentry with name "
-                       "[%s]; rc = [%d]\n", __func__,
-                       dentry->d_name.name, rc);
+                       "[%pd]; rc = [%d]\n", __func__,
+                       dentry, rc);
                return rc;
        }
 
@@ -418,8 +409,8 @@ static struct dentry *ecryptfs_lookup(struct inode *ecryptfs_dir_inode,
        if (IS_ERR(lower_dentry)) {
                rc = PTR_ERR(lower_dentry);
                ecryptfs_printk(KERN_DEBUG, "%s: lookup_one_len() returned "
-                               "[%d] on lower_dentry = [%s]\n", __func__, rc,
-                               ecryptfs_dentry->d_name.name);
+                               "[%d] on lower_dentry = [%pd]\n", __func__, rc,
+                               ecryptfs_dentry);
                goto out;
        }
        if (lower_dentry->d_inode)
@@ -1039,7 +1030,7 @@ ecryptfs_setxattr(struct dentry *dentry, const char *name, const void *value,
        }
 
        rc = vfs_setxattr(lower_dentry, name, value, size, flags);
-       if (!rc)
+       if (!rc && dentry->d_inode)
                fsstack_copy_attr_all(dentry->d_inode, lower_dentry->d_inode);
 out:
        return rc;
index 4725a07f003cf3279fa81813748442afc24a053c..635e8e16a5b7692b1d45b7629d404beeafdb8567 100644 (file)
@@ -26,7 +26,6 @@
  */
 
 #include <linux/string.h>
-#include <linux/syscalls.h>
 #include <linux/pagemap.h>
 #include <linux/key.h>
 #include <linux/random.h>
@@ -1846,7 +1845,6 @@ int ecryptfs_parse_packet_set(struct ecryptfs_crypt_stat *crypt_stat,
                                        "(Tag 11 not allowed by itself)\n");
                        rc = -EIO;
                        goto out_wipe_list;
-                       break;
                default:
                        ecryptfs_printk(KERN_DEBUG, "No packet at offset [%zd] "
                                        "of the file header; hex value of "
index e57380e5f6bd78fb983b10e292919d29eba19abc..286f10b0363b15f05a561565f27caa45a46ee9fd 100644 (file)
@@ -434,8 +434,7 @@ void ecryptfs_release_messaging(void)
                mutex_lock(&ecryptfs_msg_ctx_lists_mux);
                for (i = 0; i < ecryptfs_message_buf_len; i++) {
                        mutex_lock(&ecryptfs_msg_ctx_arr[i].mux);
-                       if (ecryptfs_msg_ctx_arr[i].msg)
-                               kfree(ecryptfs_msg_ctx_arr[i].msg);
+                       kfree(ecryptfs_msg_ctx_arr[i].msg);
                        mutex_unlock(&ecryptfs_msg_ctx_arr[i].mux);
                }
                kfree(ecryptfs_msg_ctx_arr);
index a2b42a98c743b80941d7ae1f6caf9ca7158ca1ea..7302b75a9820fa5c6342e098bb8757c31d884a4e 100644 (file)
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -1372,18 +1372,23 @@ int search_binary_handler(struct linux_binprm *bprm)
                read_unlock(&binfmt_lock);
                bprm->recursion_depth++;
                retval = fmt->load_binary(bprm);
+               read_lock(&binfmt_lock);
+               put_binfmt(fmt);
                bprm->recursion_depth--;
-               if (retval >= 0 || retval != -ENOEXEC ||
-                   bprm->mm == NULL || bprm->file == NULL) {
-                       put_binfmt(fmt);
+               if (retval < 0 && !bprm->mm) {
+                       /* we got to flush_old_exec() and failed after it */
+                       read_unlock(&binfmt_lock);
+                       force_sigsegv(SIGSEGV, current);
+                       return retval;
+               }
+               if (retval != -ENOEXEC || !bprm->file) {
+                       read_unlock(&binfmt_lock);
                        return retval;
                }
-               read_lock(&binfmt_lock);
-               put_binfmt(fmt);
        }
        read_unlock(&binfmt_lock);
 
-       if (need_retry && retval == -ENOEXEC) {
+       if (need_retry) {
                if (printable(bprm->buf[0]) && printable(bprm->buf[1]) &&
                    printable(bprm->buf[2]) && printable(bprm->buf[3]))
                        return retval;
index e85ff15a060e7dcb220c4170f8455f7d1c96cba2..fc3cdcf24aedab36e7d31b01bbdc251d8b064e75 100644 (file)
@@ -237,6 +237,8 @@ struct ext3_new_group_data {
 #define EXT3_IOC32_GETVERSION_OLD      FS_IOC32_GETVERSION
 #define EXT3_IOC32_SETVERSION_OLD      FS_IOC32_SETVERSION
 
+/* Number of supported quota types */
+#define EXT3_MAXQUOTAS 2
 
 /*
  *  Mount options
@@ -248,7 +250,7 @@ struct ext3_mount_options {
        unsigned long s_commit_interval;
 #ifdef CONFIG_QUOTA
        int s_jquota_fmt;
-       char *s_qf_names[MAXQUOTAS];
+       char *s_qf_names[EXT3_MAXQUOTAS];
 #endif
 };
 
@@ -669,7 +671,7 @@ struct ext3_sb_info {
        unsigned long s_commit_interval;
        struct block_device *journal_bdev;
 #ifdef CONFIG_QUOTA
-       char *s_qf_names[MAXQUOTAS];            /* Names of quota files with journalled quota */
+       char *s_qf_names[EXT3_MAXQUOTAS];       /* Names of quota files with journalled quota */
        int s_jquota_fmt;                       /* Format of quota to use */
 #endif
 };
@@ -1183,9 +1185,9 @@ extern const struct inode_operations ext3_fast_symlink_inode_operations;
 #define EXT3_QUOTA_INIT_BLOCKS(sb) 0
 #define EXT3_QUOTA_DEL_BLOCKS(sb) 0
 #endif
-#define EXT3_MAXQUOTAS_TRANS_BLOCKS(sb) (MAXQUOTAS*EXT3_QUOTA_TRANS_BLOCKS(sb))
-#define EXT3_MAXQUOTAS_INIT_BLOCKS(sb) (MAXQUOTAS*EXT3_QUOTA_INIT_BLOCKS(sb))
-#define EXT3_MAXQUOTAS_DEL_BLOCKS(sb) (MAXQUOTAS*EXT3_QUOTA_DEL_BLOCKS(sb))
+#define EXT3_MAXQUOTAS_TRANS_BLOCKS(sb) (EXT3_MAXQUOTAS*EXT3_QUOTA_TRANS_BLOCKS(sb))
+#define EXT3_MAXQUOTAS_INIT_BLOCKS(sb) (EXT3_MAXQUOTAS*EXT3_QUOTA_INIT_BLOCKS(sb))
+#define EXT3_MAXQUOTAS_DEL_BLOCKS(sb) (EXT3_MAXQUOTAS*EXT3_QUOTA_DEL_BLOCKS(sb))
 
 int
 ext3_mark_iloc_dirty(handle_t *handle,
index bb0fdacad058a5b1296a0b27e46f567fe1c29be6..7015db0bafd1b0c3179e6a9eb8de8c1e06465751 100644 (file)
@@ -441,7 +441,7 @@ static void ext3_put_super (struct super_block * sb)
        percpu_counter_destroy(&sbi->s_dirs_counter);
        brelse(sbi->s_sbh);
 #ifdef CONFIG_QUOTA
-       for (i = 0; i < MAXQUOTAS; i++)
+       for (i = 0; i < EXT3_MAXQUOTAS; i++)
                kfree(sbi->s_qf_names[i]);
 #endif
 
@@ -1555,7 +1555,7 @@ static void ext3_orphan_cleanup (struct super_block * sb,
        /* Needed for iput() to work correctly and not trash data */
        sb->s_flags |= MS_ACTIVE;
        /* Turn on quotas so that they are updated correctly */
-       for (i = 0; i < MAXQUOTAS; i++) {
+       for (i = 0; i < EXT3_MAXQUOTAS; i++) {
                if (EXT3_SB(sb)->s_qf_names[i]) {
                        int ret = ext3_quota_on_mount(sb, i);
                        if (ret < 0)
@@ -1606,7 +1606,7 @@ static void ext3_orphan_cleanup (struct super_block * sb,
                       PLURAL(nr_truncates));
 #ifdef CONFIG_QUOTA
        /* Turn quotas off */
-       for (i = 0; i < MAXQUOTAS; i++) {
+       for (i = 0; i < EXT3_MAXQUOTAS; i++) {
                if (sb_dqopt(sb)->files[i])
                        dquot_quota_off(sb, i);
        }
@@ -2139,7 +2139,7 @@ failed_mount2:
        kfree(sbi->s_group_desc);
 failed_mount:
 #ifdef CONFIG_QUOTA
-       for (i = 0; i < MAXQUOTAS; i++)
+       for (i = 0; i < EXT3_MAXQUOTAS; i++)
                kfree(sbi->s_qf_names[i]);
 #endif
        ext3_blkdev_remove(sbi);
@@ -2659,7 +2659,7 @@ static int ext3_remount (struct super_block * sb, int * flags, char * data)
        old_opts.s_commit_interval = sbi->s_commit_interval;
 #ifdef CONFIG_QUOTA
        old_opts.s_jquota_fmt = sbi->s_jquota_fmt;
-       for (i = 0; i < MAXQUOTAS; i++)
+       for (i = 0; i < EXT3_MAXQUOTAS; i++)
                if (sbi->s_qf_names[i]) {
                        old_opts.s_qf_names[i] = kstrdup(sbi->s_qf_names[i],
                                                         GFP_KERNEL);
@@ -2763,7 +2763,7 @@ static int ext3_remount (struct super_block * sb, int * flags, char * data)
        }
 #ifdef CONFIG_QUOTA
        /* Release old quota file names */
-       for (i = 0; i < MAXQUOTAS; i++)
+       for (i = 0; i < EXT3_MAXQUOTAS; i++)
                kfree(old_opts.s_qf_names[i]);
 #endif
        if (enable_quota)
@@ -2777,7 +2777,7 @@ restore_opts:
        sbi->s_commit_interval = old_opts.s_commit_interval;
 #ifdef CONFIG_QUOTA
        sbi->s_jquota_fmt = old_opts.s_jquota_fmt;
-       for (i = 0; i < MAXQUOTAS; i++) {
+       for (i = 0; i < EXT3_MAXQUOTAS; i++) {
                kfree(sbi->s_qf_names[i]);
                sbi->s_qf_names[i] = old_opts.s_qf_names[i];
        }
index 628e22a5a5433dae9287bdb94b10c19c6af8a538..d8da2d2e30aedfdd56a2ffc3ac9f80d2325f4ae7 100644 (file)
@@ -164,8 +164,6 @@ int fat_chain_add(struct inode *inode, int new_dclus, int nr_cluster)
        return 0;
 }
 
-extern struct timezone sys_tz;
-
 /*
  * The epoch of FAT timestamp is 1980.
  *     :  bits :     value
index 22d1c3df61acfa61ae957ede4aedfa01a3e9ab7a..99d440a4a6ba259e5bd7ec6b167dbedb2637ac5d 100644 (file)
@@ -98,26 +98,19 @@ static void f_modown(struct file *filp, struct pid *pid, enum pid_type type,
        write_unlock_irq(&filp->f_owner.lock);
 }
 
-int __f_setown(struct file *filp, struct pid *pid, enum pid_type type,
+void __f_setown(struct file *filp, struct pid *pid, enum pid_type type,
                int force)
 {
-       int err;
-
-       err = security_file_set_fowner(filp);
-       if (err)
-               return err;
-
+       security_file_set_fowner(filp);
        f_modown(filp, pid, type, force);
-       return 0;
 }
 EXPORT_SYMBOL(__f_setown);
 
-int f_setown(struct file *filp, unsigned long arg, int force)
+void f_setown(struct file *filp, unsigned long arg, int force)
 {
        enum pid_type type;
        struct pid *pid;
        int who = arg;
-       int result;
        type = PIDTYPE_PID;
        if (who < 0) {
                type = PIDTYPE_PGID;
@@ -125,9 +118,8 @@ int f_setown(struct file *filp, unsigned long arg, int force)
        }
        rcu_read_lock();
        pid = find_vpid(who);
-       result = __f_setown(filp, pid, type, force);
+       __f_setown(filp, pid, type, force);
        rcu_read_unlock();
-       return result;
 }
 EXPORT_SYMBOL(f_setown);
 
@@ -181,7 +173,7 @@ static int f_setown_ex(struct file *filp, unsigned long arg)
        if (owner.pid && !pid)
                ret = -ESRCH;
        else
-               ret = __f_setown(filp, pid, type, 1);
+                __f_setown(filp, pid, type, 1);
        rcu_read_unlock();
 
        return ret;
@@ -302,7 +294,8 @@ static long do_fcntl(int fd, unsigned int cmd, unsigned long arg,
                force_successful_syscall_return();
                break;
        case F_SETOWN:
-               err = f_setown(filp, arg, 1);
+               f_setown(filp, arg, 1);
+               err = 0;
                break;
        case F_GETOWN_EX:
                err = f_getown_ex(filp, arg);
index 66923fe3176e49b03617e2f5477bb8e05fc89dc3..ab3eb6a8823940643ab376782cd9a1e47c583c98 100644 (file)
--- a/fs/file.c
+++ b/fs/file.c
@@ -367,7 +367,7 @@ static struct fdtable *close_files(struct files_struct * files)
                                struct file * file = xchg(&fdt->fd[i], NULL);
                                if (file) {
                                        filp_close(file, files);
-                                       cond_resched();
+                                       cond_resched_rcu_qs();
                                }
                        }
                        i++;
@@ -750,6 +750,7 @@ bool get_close_on_exec(unsigned int fd)
 
 static int do_dup2(struct files_struct *files,
        struct file *file, unsigned fd, unsigned flags)
+__releases(&files->file_lock)
 {
        struct file *tofree;
        struct fdtable *fdt;
index 0bab12b2046009e0dd53fcc1a834c0a153b1f7cd..3f85411b03ce6aac983caa0e0283e8da8848225d 100644 (file)
@@ -150,18 +150,10 @@ over:
 
 /**
  * alloc_file - allocate and initialize a 'struct file'
- * @mnt: the vfsmount on which the file will reside
- * @dentry: the dentry representing the new file
+ *
+ * @path: the (dentry, vfsmount) pair for the new file
  * @mode: the mode with which the new file will be opened
  * @fop: the 'struct file_operations' for the new file
- *
- * Use this instead of get_empty_filp() to get a new
- * 'struct file'.  Do so because of the same initialization
- * pitfalls reasons listed for init_file().  This is a
- * preferred interface to using init_file().
- *
- * If all the callers of init_file() are eliminated, its
- * code should be moved into this function.
  */
 struct file *alloc_file(struct path *path, fmode_t mode,
                const struct file_operations *fop)
index b8179ca6bf9d125aa7862012eb61e5a43b85234e..51dde817e1f24aadc445d17ef19f8256879cf0cf 100644 (file)
@@ -380,26 +380,14 @@ no_config:
 static int fscache_objlist_open(struct inode *inode, struct file *file)
 {
        struct fscache_objlist_data *data;
-       struct seq_file *m;
-       int ret;
 
-       ret = seq_open(file, &fscache_objlist_ops);
-       if (ret < 0)
-               return ret;
-
-       m = file->private_data;
-
-       /* buffer for key extraction */
-       data = kmalloc(sizeof(struct fscache_objlist_data), GFP_KERNEL);
-       if (!data) {
-               seq_release(inode, file);
+       data = __seq_open_private(file, &fscache_objlist_ops, sizeof(*data));
+       if (!data)
                return -ENOMEM;
-       }
 
        /* get the configuration key */
        fscache_objlist_config(data);
 
-       m->private = data;
        return 0;
 }
 
index de1d84af9f7c6baf27b64218fbff43604ab47c04..dbab798f5cafefd8e0ad848298a7baa0f1b70ad4 100644 (file)
@@ -274,9 +274,6 @@ out:
 
 invalid:
        ret = 0;
-
-       if (!(flags & LOOKUP_RCU) && check_submounts_and_drop(entry) != 0)
-               ret = 1;
        goto out;
 }
 
@@ -1289,9 +1286,7 @@ static int fuse_direntplus_link(struct file *file,
                        d_drop(dentry);
                } else if (get_node_id(inode) != o->nodeid ||
                           ((o->attr.mode ^ inode->i_mode) & S_IFMT)) {
-                       err = d_invalidate(dentry);
-                       if (err)
-                               goto out;
+                       d_invalidate(dentry);
                } else if (is_bad_inode(inode)) {
                        err = -EIO;
                        goto out;
index d3a5d4e29ba5f37b10f4f0fd0043c7e9847b9923..589f4ea9381c4518de238d786f56433512c57565 100644 (file)
@@ -93,9 +93,6 @@ invalid_gunlock:
        if (!had_lock)
                gfs2_glock_dq_uninit(&d_gh);
 invalid:
-       if (check_submounts_and_drop(dentry) != 0)
-               goto valid;
-
        dput(parent);
        return 0;
 
index 1a349f9a9685a88c7dc67141ed0cee0c2374fec9..5d4261ff5d23ac98e83498e17fdcd3a7b7fa0d06 100644 (file)
@@ -2100,8 +2100,13 @@ int gfs2_diradd_alloc_required(struct inode *inode, const struct qstr *name,
        }
        if (IS_ERR(dent))
                return PTR_ERR(dent);
-       da->bh = bh;
-       da->dent = dent;
+
+       if (da->save_loc) {
+               da->bh = bh;
+               da->dent = dent;
+       } else {
+               brelse(bh);
+       }
        return 0;
 }
 
index 126c65dda0284080eb71a2eec146782745c8ee63..e1b309c24dab3417c513daf58bab3dd6f73ea884 100644 (file)
@@ -23,6 +23,7 @@ struct gfs2_diradd {
        unsigned nr_blocks;
        struct gfs2_dirent *dent;
        struct buffer_head *bh;
+       int save_loc;
 };
 
 extern struct inode *gfs2_dir_search(struct inode *dir,
index 7f4ed3daa38c4a190132c1c1fa6ce1b1877e0b94..80dd44dca028f97ec343e3c87727be806174094b 100644 (file)
@@ -913,26 +913,6 @@ out_uninit:
 
 #ifdef CONFIG_GFS2_FS_LOCKING_DLM
 
-/**
- * gfs2_setlease - acquire/release a file lease
- * @file: the file pointer
- * @arg: lease type
- * @fl: file lock
- *
- * We don't currently have a way to enforce a lease across the whole
- * cluster; until we do, disable leases (by just returning -EINVAL),
- * unless the administrator has requested purely local locking.
- *
- * Locking: called under i_lock
- *
- * Returns: errno
- */
-
-static int gfs2_setlease(struct file *file, long arg, struct file_lock **fl)
-{
-       return -EINVAL;
-}
-
 /**
  * gfs2_lock - acquire/release a posix lock on a file
  * @file: the file pointer
@@ -1078,7 +1058,7 @@ const struct file_operations gfs2_file_fops = {
        .flock          = gfs2_flock,
        .splice_read    = generic_file_splice_read,
        .splice_write   = iter_file_splice_write,
-       .setlease       = gfs2_setlease,
+       .setlease       = simple_nosetlease,
        .fallocate      = gfs2_fallocate,
 };
 
index 7f513b1ceb2c7adc024b2dee16321a5c4d06b733..8f0c19d1d9439e3827ffd649e7f7d43f096afc89 100644 (file)
@@ -811,7 +811,7 @@ void gfs2_holder_init(struct gfs2_glock *gl, unsigned int state, unsigned flags,
 {
        INIT_LIST_HEAD(&gh->gh_list);
        gh->gh_gl = gl;
-       gh->gh_ip = (unsigned long)__builtin_return_address(0);
+       gh->gh_ip = _RET_IP_;
        gh->gh_owner_pid = get_pid(task_pid(current));
        gh->gh_state = state;
        gh->gh_flags = flags;
@@ -835,7 +835,7 @@ void gfs2_holder_reinit(unsigned int state, unsigned flags, struct gfs2_holder *
        gh->gh_state = state;
        gh->gh_flags = flags;
        gh->gh_iflags = 0;
-       gh->gh_ip = (unsigned long)__builtin_return_address(0);
+       gh->gh_ip = _RET_IP_;
        if (gh->gh_owner_pid)
                put_pid(gh->gh_owner_pid);
        gh->gh_owner_pid = get_pid(task_pid(current));
index 2ffc67dce87f268d0b5824414927c6a1bae90513..1cc0bba6313f21216202d81f8fc1bb283496003a 100644 (file)
@@ -93,7 +93,7 @@ static void gfs2_ail_empty_gl(struct gfs2_glock *gl)
          * tr->alloced is not set since the transaction structure is
          * on the stack */
        tr.tr_reserved = 1 + gfs2_struct2blk(sdp, tr.tr_revokes, sizeof(u64));
-       tr.tr_ip = (unsigned long)__builtin_return_address(0);
+       tr.tr_ip = _RET_IP_;
        sb_start_intwrite(sdp->sd_vfs);
        if (gfs2_log_reserve(sdp, tr.tr_reserved) < 0) {
                sb_end_intwrite(sdp->sd_vfs);
index fc8ac2ee0667c8d66082aa48f05f9acee452a8ac..c4ed823d150e9609529ef1789874801180bcd4d9 100644 (file)
@@ -600,7 +600,7 @@ static int gfs2_create_inode(struct inode *dir, struct dentry *dentry,
        int error, free_vfs_inode = 0;
        u32 aflags = 0;
        unsigned blocks = 1;
-       struct gfs2_diradd da = { .bh = NULL, };
+       struct gfs2_diradd da = { .bh = NULL, .save_loc = 1, };
 
        if (!name->len || name->len > GFS2_FNAMESIZE)
                return -ENAMETOOLONG;
@@ -672,6 +672,7 @@ static int gfs2_create_inode(struct inode *dir, struct dentry *dentry,
        inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
        gfs2_set_inode_blocks(inode, 1);
        munge_mode_uid_gid(dip, inode);
+       check_and_update_goal(dip);
        ip->i_goal = dip->i_goal;
        ip->i_diskflags = 0;
        ip->i_eattr = 0;
@@ -899,7 +900,7 @@ static int gfs2_link(struct dentry *old_dentry, struct inode *dir,
        struct gfs2_inode *ip = GFS2_I(inode);
        struct gfs2_holder ghs[2];
        struct buffer_head *dibh;
-       struct gfs2_diradd da = { .bh = NULL, };
+       struct gfs2_diradd da = { .bh = NULL, .save_loc = 1, };
        int error;
 
        if (S_ISDIR(inode->i_mode))
@@ -1244,6 +1245,9 @@ static int gfs2_atomic_open(struct inode *dir, struct dentry *dentry,
        struct dentry *d;
        bool excl = !!(flags & O_EXCL);
 
+       if (!d_unhashed(dentry))
+               goto skip_lookup;
+
        d = __gfs2_lookup(dir, dentry, file, opened);
        if (IS_ERR(d))
                return PTR_ERR(d);
@@ -1260,6 +1264,8 @@ static int gfs2_atomic_open(struct inode *dir, struct dentry *dentry,
        }
 
        BUG_ON(d != NULL);
+
+skip_lookup:
        if (!(flags & O_CREAT))
                return -ENOENT;
 
@@ -1337,7 +1343,7 @@ static int gfs2_rename(struct inode *odir, struct dentry *odentry,
        struct gfs2_rgrpd *nrgd;
        unsigned int num_gh;
        int dir_rename = 0;
-       struct gfs2_diradd da = { .nr_blocks = 0, };
+       struct gfs2_diradd da = { .nr_blocks = 0, .save_loc = 0, };
        unsigned int x;
        int error;
 
index f4cb9c0d6bbdce4bdfc4a82b20aa7aa2ac119829..7474c413ffd1e2c8da3d4396f3bbc31a0175805d 100644 (file)
@@ -577,6 +577,13 @@ struct gfs2_rgrpd *gfs2_rgrpd_get_next(struct gfs2_rgrpd *rgd)
        return rgd;
 }
 
+void check_and_update_goal(struct gfs2_inode *ip)
+{
+       struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
+       if (!ip->i_goal || gfs2_blk2rgrpd(sdp, ip->i_goal, 1) == NULL)
+               ip->i_goal = ip->i_no_addr;
+}
+
 void gfs2_free_clones(struct gfs2_rgrpd *rgd)
 {
        int x;
@@ -1910,6 +1917,7 @@ int gfs2_inplace_reserve(struct gfs2_inode *ip, const struct gfs2_alloc_parms *a
        } else if (ip->i_rgd && rgrp_contains_block(ip->i_rgd, ip->i_goal)) {
                rs->rs_rbm.rgd = begin = ip->i_rgd;
        } else {
+               check_and_update_goal(ip);
                rs->rs_rbm.rgd = begin = gfs2_blk2rgrpd(sdp, ip->i_goal, 1);
        }
        if (S_ISDIR(ip->i_inode.i_mode) && (ap->aflags & GFS2_AF_ORLOV))
@@ -2089,7 +2097,7 @@ static struct gfs2_rgrpd *rgblk_free(struct gfs2_sbd *sdp, u64 bstart,
                                     u32 blen, unsigned char new_state)
 {
        struct gfs2_rbm rbm;
-       struct gfs2_bitmap *bi;
+       struct gfs2_bitmap *bi, *bi_prev = NULL;
 
        rbm.rgd = gfs2_blk2rgrpd(sdp, bstart, 1);
        if (!rbm.rgd) {
@@ -2098,18 +2106,22 @@ static struct gfs2_rgrpd *rgblk_free(struct gfs2_sbd *sdp, u64 bstart,
                return NULL;
        }
 
+       gfs2_rbm_from_block(&rbm, bstart);
        while (blen--) {
-               gfs2_rbm_from_block(&rbm, bstart);
                bi = rbm_bi(&rbm);
-               bstart++;
-               if (!bi->bi_clone) {
-                       bi->bi_clone = kmalloc(bi->bi_bh->b_size,
-                                              GFP_NOFS | __GFP_NOFAIL);
-                       memcpy(bi->bi_clone + bi->bi_offset,
-                              bi->bi_bh->b_data + bi->bi_offset, bi->bi_len);
+               if (bi != bi_prev) {
+                       if (!bi->bi_clone) {
+                               bi->bi_clone = kmalloc(bi->bi_bh->b_size,
+                                                     GFP_NOFS | __GFP_NOFAIL);
+                               memcpy(bi->bi_clone + bi->bi_offset,
+                                      bi->bi_bh->b_data + bi->bi_offset,
+                                      bi->bi_len);
+                       }
+                       gfs2_trans_add_meta(rbm.rgd->rd_gl, bi->bi_bh);
+                       bi_prev = bi;
                }
-               gfs2_trans_add_meta(rbm.rgd->rd_gl, bi->bi_bh);
                gfs2_setbit(&rbm, false, new_state);
+               gfs2_rbm_incr(&rbm);
        }
 
        return rbm.rgd;
index 463ab2e95d1cb94cafd6e31118ae77000754bd71..5d8f085f7adea18f9acce4ea5ed7f9e15527a7d0 100644 (file)
@@ -80,4 +80,5 @@ static inline bool gfs2_rs_active(struct gfs2_blkreserv *rs)
        return rs && !RB_EMPTY_NODE(&rs->rs_node);
 }
 
+extern void check_and_update_goal(struct gfs2_inode *ip);
 #endif /* __RGRP_DOT_H__ */
index 0546ab4e28e8a3dcbcef555f8574e068b531531c..42bfd33619793fb5bdda021ba9a7b9a027585e86 100644 (file)
@@ -44,7 +44,7 @@ int gfs2_trans_begin(struct gfs2_sbd *sdp, unsigned int blocks,
        if (!tr)
                return -ENOMEM;
 
-       tr->tr_ip = (unsigned long)__builtin_return_address(0);
+       tr->tr_ip = _RET_IP_;
        tr->tr_blocks = blocks;
        tr->tr_revokes = revokes;
        tr->tr_reserved = 1;
index 0524cda47a6e72db892c53c7da294aa212a4c17c..95d255219b1eb89c68db91d85037a19af20cf1a6 100644 (file)
@@ -242,8 +242,6 @@ extern int hfs_mac2asc(struct super_block *, char *, const struct hfs_name *);
 /* super.c */
 extern void hfs_mark_mdb_dirty(struct super_block *sb);
 
-extern struct timezone sys_tz;
-
 /*
  * There are two time systems.  Both are based on seconds since
  * a particular time/date.
index b2623200107b3d0065a5492cfa8b8929734caa3b..9477f8f6aefca491ec50be5c2fda03cf64997a65 100644 (file)
@@ -56,7 +56,7 @@ extern int vfs_path_lookup(struct dentry *, struct vfsmount *,
  * namespace.c
  */
 extern int copy_mount_options(const void __user *, unsigned long *);
-extern int copy_mount_string(const void __user *, char **);
+extern char *copy_mount_string(const void __user *);
 
 extern struct vfsmount *lookup_mnt(struct path *);
 extern int finish_automount(struct vfsmount *, struct path *);
index 5ddaf8625d3b7a1ab3d0128a91dbd3b84b8b9b0b..881b3bd0143faf9e1b492f64d752f16846fea66d 100644 (file)
@@ -247,7 +247,7 @@ static int isofs_dentry_cmp_common(
        }
        if (alen == blen) {
                if (ci) {
-                       if (strnicmp(name->name, str, alen) == 0)
+                       if (strncasecmp(name->name, str, alen) == 0)
                                return 0;
                } else {
                        if (strncmp(name->name, str, alen) == 0)
index 413ef89c2d1ba32fe8507f29355d11c5873bc7d0..046fee8b6e9b3ee95d1d5f0c7a9ad7f94ef7c0c9 100644 (file)
@@ -134,8 +134,6 @@ struct jffs2_sb_info {
        struct rw_semaphore wbuf_sem;   /* Protects the write buffer */
 
        struct delayed_work wbuf_dwork; /* write-buffer write-out work */
-       int wbuf_queued;                /* non-zero delayed work is queued */
-       spinlock_t wbuf_dwork_lock;     /* protects wbuf_dwork and and wbuf_queued */
 
        unsigned char *oobbuf;
        int oobavail; /* How many bytes are available for JFFS2 in OOB */
index a6597d60d76de751224243ddfe6d990cd6de7e87..09ed55190ee2c077524e38a11b4fe41c00f51ac9 100644 (file)
@@ -1162,10 +1162,6 @@ static void delayed_wbuf_sync(struct work_struct *work)
        struct jffs2_sb_info *c = work_to_sb(work);
        struct super_block *sb = OFNI_BS_2SFFJ(c);
 
-       spin_lock(&c->wbuf_dwork_lock);
-       c->wbuf_queued = 0;
-       spin_unlock(&c->wbuf_dwork_lock);
-
        if (!(sb->s_flags & MS_RDONLY)) {
                jffs2_dbg(1, "%s()\n", __func__);
                jffs2_flush_wbuf_gc(c, 0);
@@ -1180,14 +1176,9 @@ void jffs2_dirty_trigger(struct jffs2_sb_info *c)
        if (sb->s_flags & MS_RDONLY)
                return;
 
-       spin_lock(&c->wbuf_dwork_lock);
-       if (!c->wbuf_queued) {
+       delay = msecs_to_jiffies(dirty_writeback_interval * 10);
+       if (queue_delayed_work(system_long_wq, &c->wbuf_dwork, delay))
                jffs2_dbg(1, "%s()\n", __func__);
-               delay = msecs_to_jiffies(dirty_writeback_interval * 10);
-               queue_delayed_work(system_long_wq, &c->wbuf_dwork, delay);
-               c->wbuf_queued = 1;
-       }
-       spin_unlock(&c->wbuf_dwork_lock);
 }
 
 int jffs2_nand_flash_setup(struct jffs2_sb_info *c)
@@ -1211,7 +1202,6 @@ int jffs2_nand_flash_setup(struct jffs2_sb_info *c)
 
        /* Initialise write buffer */
        init_rwsem(&c->wbuf_sem);
-       spin_lock_init(&c->wbuf_dwork_lock);
        INIT_DELAYED_WORK(&c->wbuf_dwork, delayed_wbuf_sync);
        c->wbuf_pagesize = c->mtd->writesize;
        c->wbuf_ofs = 0xFFFFFFFF;
@@ -1251,7 +1241,6 @@ int jffs2_dataflash_setup(struct jffs2_sb_info *c) {
 
        /* Initialize write buffer */
        init_rwsem(&c->wbuf_sem);
-       spin_lock_init(&c->wbuf_dwork_lock);
        INIT_DELAYED_WORK(&c->wbuf_dwork, delayed_wbuf_sync);
        c->wbuf_pagesize =  c->mtd->erasesize;
 
@@ -1311,7 +1300,6 @@ int jffs2_nor_wbuf_flash_setup(struct jffs2_sb_info *c) {
 
        /* Initialize write buffer */
        init_rwsem(&c->wbuf_sem);
-       spin_lock_init(&c->wbuf_dwork_lock);
        INIT_DELAYED_WORK(&c->wbuf_dwork, delayed_wbuf_sync);
 
        c->wbuf_pagesize = c->mtd->writesize;
@@ -1346,7 +1334,6 @@ int jffs2_ubivol_setup(struct jffs2_sb_info *c) {
                return 0;
 
        init_rwsem(&c->wbuf_sem);
-       spin_lock_init(&c->wbuf_dwork_lock);
        INIT_DELAYED_WORK(&c->wbuf_dwork, delayed_wbuf_sync);
 
        c->wbuf_pagesize =  c->mtd->writesize;
index 0acddf60af55a3c39147603121bbdeb237d64112..bc462dcd7a4054dc158f4fb4636c38c6c1575bde 100644 (file)
@@ -1585,7 +1585,6 @@ void jfs_flush_journal(struct jfs_log *log, int wait)
                set_current_state(TASK_UNINTERRUPTIBLE);
                LOGGC_UNLOCK(log);
                schedule();
-               __set_current_state(TASK_RUNNING);
                LOGGC_LOCK(log);
                remove_wait_queue(&target->gcwait, &__wait);
        }
@@ -2359,7 +2358,6 @@ int jfsIOWait(void *arg)
                        set_current_state(TASK_INTERRUPTIBLE);
                        spin_unlock_irq(&log_redrive_lock);
                        schedule();
-                       __set_current_state(TASK_RUNNING);
                }
        } while (!kthread_should_stop());
 
index 564c4f279ac630e8458cd74029284c65f44a7796..d595856453b24ec36234687373aec6576afa3b90 100644 (file)
@@ -136,7 +136,6 @@ static inline void TXN_SLEEP_DROP_LOCK(wait_queue_head_t * event)
        set_current_state(TASK_UNINTERRUPTIBLE);
        TXN_UNLOCK();
        io_schedule();
-       __set_current_state(TASK_RUNNING);
        remove_wait_queue(event, &wait);
 }
 
@@ -2808,7 +2807,6 @@ int jfs_lazycommit(void *arg)
                        set_current_state(TASK_INTERRUPTIBLE);
                        LAZY_UNLOCK(flags);
                        schedule();
-                       __set_current_state(TASK_RUNNING);
                        remove_wait_queue(&jfs_commit_thread_wait, &wq);
                }
        } while (!kthread_should_stop());
@@ -2996,7 +2994,6 @@ int jfs_sync(void *arg)
                        set_current_state(TASK_INTERRUPTIBLE);
                        TXN_UNLOCK();
                        schedule();
-                       __set_current_state(TASK_RUNNING);
                }
        } while (!kthread_should_stop());
 
index adf8cb045b9efb7a038b87f9f98d75c84cf1b0ad..93e897e588a88d0b9e8c3cb589451eaed3a4874b 100644 (file)
@@ -550,7 +550,7 @@ static int jfs_fill_super(struct super_block *sb, void *data, int silent)
        inode->i_ino = 0;
        inode->i_size = sb->s_bdev->bd_inode->i_size;
        inode->i_mapping->a_ops = &jfs_metapage_aops;
-       insert_inode_hash(inode);
+       hlist_add_fake(&inode->i_hash);
        mapping_set_gfp_mask(inode->i_mapping, GFP_NOFS);
 
        sbi->direct_inode = inode;
index a693f5b01ae6ebdda49911cab77f8d75deb97306..1c771931bb602426ddb697e88ec1fc8bb6ebf233 100644 (file)
@@ -463,21 +463,10 @@ static int kernfs_dop_revalidate(struct dentry *dentry, unsigned int flags)
                goto out_bad;
 
        mutex_unlock(&kernfs_mutex);
-out_valid:
        return 1;
 out_bad:
        mutex_unlock(&kernfs_mutex);
 out_bad_unlocked:
-       /*
-        * @dentry doesn't match the underlying kernfs node, drop the
-        * dentry and force lookup.  If we have submounts we must allow the
-        * vfs caches to lie about the state of the filesystem to prevent
-        * leaks and other nasty things, so use check_submounts_and_drop()
-        * instead of d_drop().
-        */
-       if (check_submounts_and_drop(dentry) != 0)
-               goto out_valid;
-
        return 0;
 }
 
index 88e3e00e2eca0d72aa2bc2af350682d26ca7c7ca..171d2846f2a319088f6e43fff1dc0030d3ce6550 100644 (file)
@@ -1075,3 +1075,21 @@ struct inode *alloc_anon_inode(struct super_block *s)
        return inode;
 }
 EXPORT_SYMBOL(alloc_anon_inode);
+
+/**
+ * simple_nosetlease - generic helper for prohibiting leases
+ * @filp: file pointer
+ * @arg: type of lease to obtain
+ * @flp: new lease supplied for insertion
+ * @priv: private data for lm_setup operation
+ *
+ * Generic helper for filesystems that do not wish to allow leases to be set.
+ * All arguments are ignored and it just returns -EINVAL.
+ */
+int
+simple_nosetlease(struct file *filp, long arg, struct file_lock **flp,
+                 void **priv)
+{
+       return -EINVAL;
+}
+EXPORT_SYMBOL(simple_nosetlease);
index ab798a88ec1d52347afe05d4b8ed2eff13151de1..13db95f54176ec0864732177392889c389df2b57 100644 (file)
@@ -245,7 +245,6 @@ nlmsvc_create_block(struct svc_rqst *rqstp, struct nlm_host *host,
        block->b_daemon = rqstp->rq_server;
        block->b_host   = host;
        block->b_file   = file;
-       block->b_fl = NULL;
        file->f_count++;
 
        /* Add to file's list of blocks */
@@ -295,7 +294,6 @@ static void nlmsvc_free_block(struct kref *kref)
        nlmsvc_freegrantargs(block->b_call);
        nlmsvc_release_call(block->b_call);
        nlm_release_file(block->b_file);
-       kfree(block->b_fl);
        kfree(block);
 }
 
@@ -508,7 +506,6 @@ nlmsvc_testlock(struct svc_rqst *rqstp, struct nlm_file *file,
                struct nlm_host *host, struct nlm_lock *lock,
                struct nlm_lock *conflock, struct nlm_cookie *cookie)
 {
-       struct nlm_block        *block = NULL;
        int                     error;
        __be32                  ret;
 
@@ -519,63 +516,26 @@ nlmsvc_testlock(struct svc_rqst *rqstp, struct nlm_file *file,
                                (long long)lock->fl.fl_start,
                                (long long)lock->fl.fl_end);
 
-       /* Get existing block (in case client is busy-waiting) */
-       block = nlmsvc_lookup_block(file, lock);
-
-       if (block == NULL) {
-               struct file_lock *conf = kzalloc(sizeof(*conf), GFP_KERNEL);
-
-               if (conf == NULL)
-                       return nlm_granted;
-               block = nlmsvc_create_block(rqstp, host, file, lock, cookie);
-               if (block == NULL) {
-                       kfree(conf);
-                       return nlm_granted;
-               }
-               block->b_fl = conf;
-       }
-       if (block->b_flags & B_QUEUED) {
-               dprintk("lockd: nlmsvc_testlock deferred block %p flags %d fl %p\n",
-                       block, block->b_flags, block->b_fl);
-               if (block->b_flags & B_TIMED_OUT) {
-                       nlmsvc_unlink_block(block);
-                       ret = nlm_lck_denied;
-                       goto out;
-               }
-               if (block->b_flags & B_GOT_CALLBACK) {
-                       nlmsvc_unlink_block(block);
-                       if (block->b_fl != NULL
-                                       && block->b_fl->fl_type != F_UNLCK) {
-                               lock->fl = *block->b_fl;
-                               goto conf_lock;
-                       } else {
-                               ret = nlm_granted;
-                               goto out;
-                       }
-               }
-               ret = nlm_drop_reply;
-               goto out;
-       }
-
        if (locks_in_grace(SVC_NET(rqstp))) {
                ret = nlm_lck_denied_grace_period;
                goto out;
        }
+
        error = vfs_test_lock(file->f_file, &lock->fl);
-       if (error == FILE_LOCK_DEFERRED) {
-               ret = nlmsvc_defer_lock_rqst(rqstp, block);
-               goto out;
-       }
        if (error) {
+               /* We can't currently deal with deferred test requests */
+               if (error == FILE_LOCK_DEFERRED)
+                       WARN_ON_ONCE(1);
+
                ret = nlm_lck_denied_nolocks;
                goto out;
        }
+
        if (lock->fl.fl_type == F_UNLCK) {
                ret = nlm_granted;
                goto out;
        }
 
-conf_lock:
        dprintk("lockd: conflicting lock(ty=%d, %Ld-%Ld)\n",
                lock->fl.fl_type, (long long)lock->fl.fl_start,
                (long long)lock->fl.fl_end);
@@ -586,10 +546,9 @@ conf_lock:
        conflock->fl.fl_type = lock->fl.fl_type;
        conflock->fl.fl_start = lock->fl.fl_start;
        conflock->fl.fl_end = lock->fl.fl_end;
+       locks_release_private(&lock->fl);
        ret = nlm_lck_denied;
 out:
-       if (block)
-               nlmsvc_release_block(block);
        return ret;
 }
 
@@ -660,29 +619,22 @@ nlmsvc_cancel_blocked(struct net *net, struct nlm_file *file, struct nlm_lock *l
  * This is a callback from the filesystem for VFS file lock requests.
  * It will be used if lm_grant is defined and the filesystem can not
  * respond to the request immediately.
- * For GETLK request it will copy the reply to the nlm_block.
  * For SETLK or SETLKW request it will get the local posix lock.
  * In all cases it will move the block to the head of nlm_blocked q where
  * nlmsvc_retry_blocked() can send back a reply for SETLKW or revisit the
  * deferred rpc for GETLK and SETLK.
  */
 static void
-nlmsvc_update_deferred_block(struct nlm_block *block, struct file_lock *conf,
-                            int result)
+nlmsvc_update_deferred_block(struct nlm_block *block, int result)
 {
        block->b_flags |= B_GOT_CALLBACK;
        if (result == 0)
                block->b_granted = 1;
        else
                block->b_flags |= B_TIMED_OUT;
-       if (conf) {
-               if (block->b_fl)
-                       __locks_copy_lock(block->b_fl, conf);
-       }
 }
 
-static int nlmsvc_grant_deferred(struct file_lock *fl, struct file_lock *conf,
-                                       int result)
+static int nlmsvc_grant_deferred(struct file_lock *fl, int result)
 {
        struct nlm_block *block;
        int rc = -ENOENT;
@@ -697,7 +649,7 @@ static int nlmsvc_grant_deferred(struct file_lock *fl, struct file_lock *conf,
                                        rc = -ENOLCK;
                                        break;
                                }
-                               nlmsvc_update_deferred_block(block, conf, result);
+                               nlmsvc_update_deferred_block(block, result);
                        } else if (result == 0)
                                block->b_granted = 1;
 
index bb08857f90b56cb2b51a77b3f69acfef33a8fd9c..735b8d3fa78c92bf746aff05475be1fa2a82abd6 100644 (file)
@@ -230,8 +230,12 @@ void locks_release_private(struct file_lock *fl)
                        fl->fl_ops->fl_release_private(fl);
                fl->fl_ops = NULL;
        }
-       fl->fl_lmops = NULL;
 
+       if (fl->fl_lmops) {
+               if (fl->fl_lmops->lm_put_owner)
+                       fl->fl_lmops->lm_put_owner(fl);
+               fl->fl_lmops = NULL;
+       }
 }
 EXPORT_SYMBOL_GPL(locks_release_private);
 
@@ -267,21 +271,10 @@ void locks_init_lock(struct file_lock *fl)
 
 EXPORT_SYMBOL(locks_init_lock);
 
-static void locks_copy_private(struct file_lock *new, struct file_lock *fl)
-{
-       if (fl->fl_ops) {
-               if (fl->fl_ops->fl_copy_lock)
-                       fl->fl_ops->fl_copy_lock(new, fl);
-               new->fl_ops = fl->fl_ops;
-       }
-       if (fl->fl_lmops)
-               new->fl_lmops = fl->fl_lmops;
-}
-
 /*
  * Initialize a new lock from an existing file_lock structure.
  */
-void __locks_copy_lock(struct file_lock *new, const struct file_lock *fl)
+void locks_copy_conflock(struct file_lock *new, struct file_lock *fl)
 {
        new->fl_owner = fl->fl_owner;
        new->fl_pid = fl->fl_pid;
@@ -290,22 +283,30 @@ void __locks_copy_lock(struct file_lock *new, const struct file_lock *fl)
        new->fl_type = fl->fl_type;
        new->fl_start = fl->fl_start;
        new->fl_end = fl->fl_end;
+       new->fl_lmops = fl->fl_lmops;
        new->fl_ops = NULL;
-       new->fl_lmops = NULL;
+
+       if (fl->fl_lmops) {
+               if (fl->fl_lmops->lm_get_owner)
+                       fl->fl_lmops->lm_get_owner(new, fl);
+       }
 }
-EXPORT_SYMBOL(__locks_copy_lock);
+EXPORT_SYMBOL(locks_copy_conflock);
 
 void locks_copy_lock(struct file_lock *new, struct file_lock *fl)
 {
        /* "new" must be a freshly-initialized lock */
        WARN_ON_ONCE(new->fl_ops);
 
-       __locks_copy_lock(new, fl);
+       locks_copy_conflock(new, fl);
+
        new->fl_file = fl->fl_file;
        new->fl_ops = fl->fl_ops;
-       new->fl_lmops = fl->fl_lmops;
 
-       locks_copy_private(new, fl);
+       if (fl->fl_ops) {
+               if (fl->fl_ops->fl_copy_lock)
+                       fl->fl_ops->fl_copy_lock(new, fl);
+       }
 }
 
 EXPORT_SYMBOL(locks_copy_lock);
@@ -325,17 +326,18 @@ static inline int flock_translate_cmd(int cmd) {
 }
 
 /* Fill in a file_lock structure with an appropriate FLOCK lock. */
-static int flock_make_lock(struct file *filp, struct file_lock **lock,
-               unsigned int cmd)
+static struct file_lock *
+flock_make_lock(struct file *filp, unsigned int cmd)
 {
        struct file_lock *fl;
        int type = flock_translate_cmd(cmd);
+
        if (type < 0)
-               return type;
+               return ERR_PTR(type);
        
        fl = locks_alloc_lock();
        if (fl == NULL)
-               return -ENOMEM;
+               return ERR_PTR(-ENOMEM);
 
        fl->fl_file = filp;
        fl->fl_owner = filp;
@@ -344,8 +346,7 @@ static int flock_make_lock(struct file *filp, struct file_lock **lock,
        fl->fl_type = type;
        fl->fl_end = OFFSET_MAX;
        
-       *lock = fl;
-       return 0;
+       return fl;
 }
 
 static int assign_type(struct file_lock *fl, long type)
@@ -426,14 +427,34 @@ static int flock_to_posix_lock(struct file *filp, struct file_lock *fl,
 }
 
 /* default lease lock manager operations */
-static void lease_break_callback(struct file_lock *fl)
+static bool
+lease_break_callback(struct file_lock *fl)
 {
        kill_fasync(&fl->fl_fasync, SIGIO, POLL_MSG);
+       return false;
+}
+
+static void
+lease_setup(struct file_lock *fl, void **priv)
+{
+       struct file *filp = fl->fl_file;
+       struct fasync_struct *fa = *priv;
+
+       /*
+        * fasync_insert_entry() returns the old entry if any. If there was no
+        * old entry, then it used "priv" and inserted it into the fasync list.
+        * Clear the pointer to indicate that it shouldn't be freed.
+        */
+       if (!fasync_insert_entry(fa->fa_fd, filp, &fl->fl_fasync, fa))
+               *priv = NULL;
+
+       __f_setown(filp, task_pid(current), PIDTYPE_PID, 0);
 }
 
 static const struct lock_manager_operations lease_manager_ops = {
        .lm_break = lease_break_callback,
        .lm_change = lease_modify,
+       .lm_setup = lease_setup,
 };
 
 /*
@@ -444,7 +465,7 @@ static int lease_init(struct file *filp, long type, struct file_lock *fl)
        if (assign_type(fl, type) != 0)
                return -EINVAL;
 
-       fl->fl_owner = current->files;
+       fl->fl_owner = filp;
        fl->fl_pid = current->tgid;
 
        fl->fl_file = filp;
@@ -735,7 +756,7 @@ posix_test_lock(struct file *filp, struct file_lock *fl)
                        break;
        }
        if (cfl) {
-               __locks_copy_lock(fl, cfl);
+               locks_copy_conflock(fl, cfl);
                if (cfl->fl_nspid)
                        fl->fl_pid = pid_vnr(cfl->fl_nspid);
        } else
@@ -941,7 +962,7 @@ static int __posix_lock_file(struct inode *inode, struct file_lock *request, str
                        if (!posix_locks_conflict(request, fl))
                                continue;
                        if (conflock)
-                               __locks_copy_lock(conflock, fl);
+                               locks_copy_conflock(conflock, fl);
                        error = -EAGAIN;
                        if (!(request->fl_flags & FL_SLEEP))
                                goto out;
@@ -1273,7 +1294,7 @@ static void lease_clear_pending(struct file_lock *fl, int arg)
 }
 
 /* We already had a lease on this file; just change its type */
-int lease_modify(struct file_lock **before, int arg)
+int lease_modify(struct file_lock **before, int arg, struct list_head *dispose)
 {
        struct file_lock *fl = *before;
        int error = assign_type(fl, arg);
@@ -1292,11 +1313,10 @@ int lease_modify(struct file_lock **before, int arg)
                        printk(KERN_ERR "locks_delete_lock: fasync == %p\n", fl->fl_fasync);
                        fl->fl_fasync = NULL;
                }
-               locks_delete_lock(before, NULL);
+               locks_delete_lock(before, dispose);
        }
        return 0;
 }
-
 EXPORT_SYMBOL(lease_modify);
 
 static bool past_time(unsigned long then)
@@ -1307,18 +1327,20 @@ static bool past_time(unsigned long then)
        return time_after(jiffies, then);
 }
 
-static void time_out_leases(struct inode *inode)
+static void time_out_leases(struct inode *inode, struct list_head *dispose)
 {
        struct file_lock **before;
        struct file_lock *fl;
 
+       lockdep_assert_held(&inode->i_lock);
+
        before = &inode->i_flock;
        while ((fl = *before) && IS_LEASE(fl) && lease_breaking(fl)) {
                trace_time_out_leases(inode, fl);
                if (past_time(fl->fl_downgrade_time))
-                       lease_modify(before, F_RDLCK);
+                       lease_modify(before, F_RDLCK, dispose);
                if (past_time(fl->fl_break_time))
-                       lease_modify(before, F_UNLCK);
+                       lease_modify(before, F_UNLCK, dispose);
                if (fl == *before)      /* lease_modify may have freed fl */
                        before = &fl->fl_next;
        }
@@ -1331,6 +1353,20 @@ static bool leases_conflict(struct file_lock *lease, struct file_lock *breaker)
        return locks_conflict(breaker, lease);
 }
 
+static bool
+any_leases_conflict(struct inode *inode, struct file_lock *breaker)
+{
+       struct file_lock *fl;
+
+       lockdep_assert_held(&inode->i_lock);
+
+       for (fl = inode->i_flock ; fl && IS_LEASE(fl); fl = fl->fl_next) {
+               if (leases_conflict(fl, breaker))
+                       return true;
+       }
+       return false;
+}
+
 /**
  *     __break_lease   -       revoke all outstanding leases on file
  *     @inode: the inode of the file to return
@@ -1347,12 +1383,11 @@ static bool leases_conflict(struct file_lock *lease, struct file_lock *breaker)
 int __break_lease(struct inode *inode, unsigned int mode, unsigned int type)
 {
        int error = 0;
-       struct file_lock *new_fl, *flock;
-       struct file_lock *fl;
+       struct file_lock *new_fl;
+       struct file_lock *fl, **before;
        unsigned long break_time;
-       int i_have_this_lease = 0;
-       bool lease_conflict = false;
        int want_write = (mode & O_ACCMODE) != O_RDONLY;
+       LIST_HEAD(dispose);
 
        new_fl = lease_alloc(NULL, want_write ? F_WRLCK : F_RDLCK);
        if (IS_ERR(new_fl))
@@ -1361,20 +1396,9 @@ int __break_lease(struct inode *inode, unsigned int mode, unsigned int type)
 
        spin_lock(&inode->i_lock);
 
-       time_out_leases(inode);
-
-       flock = inode->i_flock;
-       if ((flock == NULL) || !IS_LEASE(flock))
-               goto out;
+       time_out_leases(inode, &dispose);
 
-       for (fl = flock; fl && IS_LEASE(fl); fl = fl->fl_next) {
-               if (leases_conflict(fl, new_fl)) {
-                       lease_conflict = true;
-                       if (fl->fl_owner == current->files)
-                               i_have_this_lease = 1;
-               }
-       }
-       if (!lease_conflict)
+       if (!any_leases_conflict(inode, new_fl))
                goto out;
 
        break_time = 0;
@@ -1384,7 +1408,9 @@ int __break_lease(struct inode *inode, unsigned int mode, unsigned int type)
                        break_time++;   /* so that 0 means no break time */
        }
 
-       for (fl = flock; fl && IS_LEASE(fl); fl = fl->fl_next) {
+       for (before = &inode->i_flock;
+                       ((fl = *before) != NULL) && IS_LEASE(fl);
+                       before = &fl->fl_next) {
                if (!leases_conflict(fl, new_fl))
                        continue;
                if (want_write) {
@@ -1393,51 +1419,56 @@ int __break_lease(struct inode *inode, unsigned int mode, unsigned int type)
                        fl->fl_flags |= FL_UNLOCK_PENDING;
                        fl->fl_break_time = break_time;
                } else {
-                       if (lease_breaking(flock))
+                       if (lease_breaking(inode->i_flock))
                                continue;
                        fl->fl_flags |= FL_DOWNGRADE_PENDING;
                        fl->fl_downgrade_time = break_time;
                }
-               fl->fl_lmops->lm_break(fl);
+               if (fl->fl_lmops->lm_break(fl))
+                       locks_delete_lock(before, &dispose);
        }
 
-       if (i_have_this_lease || (mode & O_NONBLOCK)) {
+       fl = inode->i_flock;
+       if (!fl || !IS_LEASE(fl))
+               goto out;
+
+       if (mode & O_NONBLOCK) {
                trace_break_lease_noblock(inode, new_fl);
                error = -EWOULDBLOCK;
                goto out;
        }
 
 restart:
-       break_time = flock->fl_break_time;
+       break_time = inode->i_flock->fl_break_time;
        if (break_time != 0)
                break_time -= jiffies;
        if (break_time == 0)
                break_time++;
-       locks_insert_block(flock, new_fl);
+       locks_insert_block(inode->i_flock, new_fl);
        trace_break_lease_block(inode, new_fl);
        spin_unlock(&inode->i_lock);
+       locks_dispose_list(&dispose);
        error = wait_event_interruptible_timeout(new_fl->fl_wait,
                                                !new_fl->fl_next, break_time);
        spin_lock(&inode->i_lock);
        trace_break_lease_unblock(inode, new_fl);
        locks_delete_block(new_fl);
        if (error >= 0) {
-               if (error == 0)
-                       time_out_leases(inode);
                /*
                 * Wait for the next conflicting lease that has not been
                 * broken yet
                 */
-               for (flock = inode->i_flock; flock && IS_LEASE(flock);
-                               flock = flock->fl_next) {
-                       if (leases_conflict(new_fl, flock))
-                               goto restart;
-               }
+               if (error == 0)
+                       time_out_leases(inode, &dispose);
+               if (any_leases_conflict(inode, new_fl))
+                       goto restart;
+
                error = 0;
        }
 
 out:
        spin_unlock(&inode->i_lock);
+       locks_dispose_list(&dispose);
        locks_free_lock(new_fl);
        return error;
 }
@@ -1455,8 +1486,18 @@ EXPORT_SYMBOL(__break_lease);
  */
 void lease_get_mtime(struct inode *inode, struct timespec *time)
 {
-       struct file_lock *flock = inode->i_flock;
-       if (flock && IS_LEASE(flock) && (flock->fl_type == F_WRLCK))
+       bool has_lease = false;
+       struct file_lock *flock;
+
+       if (inode->i_flock) {
+               spin_lock(&inode->i_lock);
+               flock = inode->i_flock;
+               if (flock && IS_LEASE(flock) && (flock->fl_type == F_WRLCK))
+                       has_lease = true;
+               spin_unlock(&inode->i_lock);
+       }
+
+       if (has_lease)
                *time = current_fs_time(inode->i_sb);
        else
                *time = inode->i_mtime;
@@ -1492,9 +1533,10 @@ int fcntl_getlease(struct file *filp)
        struct file_lock *fl;
        struct inode *inode = file_inode(filp);
        int type = F_UNLCK;
+       LIST_HEAD(dispose);
 
        spin_lock(&inode->i_lock);
-       time_out_leases(file_inode(filp));
+       time_out_leases(file_inode(filp), &dispose);
        for (fl = file_inode(filp)->i_flock; fl && IS_LEASE(fl);
                        fl = fl->fl_next) {
                if (fl->fl_file == filp) {
@@ -1503,6 +1545,7 @@ int fcntl_getlease(struct file *filp)
                }
        }
        spin_unlock(&inode->i_lock);
+       locks_dispose_list(&dispose);
        return type;
 }
 
@@ -1532,13 +1575,15 @@ check_conflicting_open(const struct dentry *dentry, const long arg)
        return ret;
 }
 
-static int generic_add_lease(struct file *filp, long arg, struct file_lock **flp)
+static int
+generic_add_lease(struct file *filp, long arg, struct file_lock **flp, void **priv)
 {
        struct file_lock *fl, **before, **my_before = NULL, *lease;
        struct dentry *dentry = filp->f_path.dentry;
        struct inode *inode = dentry->d_inode;
        bool is_deleg = (*flp)->fl_flags & FL_DELEG;
        int error;
+       LIST_HEAD(dispose);
 
        lease = *flp;
        trace_generic_add_lease(inode, lease);
@@ -1561,6 +1606,8 @@ static int generic_add_lease(struct file *filp, long arg, struct file_lock **flp
                return -EINVAL;
        }
 
+       spin_lock(&inode->i_lock);
+       time_out_leases(inode, &dispose);
        error = check_conflicting_open(dentry, arg);
        if (error)
                goto out;
@@ -1596,10 +1643,11 @@ static int generic_add_lease(struct file *filp, long arg, struct file_lock **flp
        }
 
        if (my_before != NULL) {
-               error = lease->fl_lmops->lm_change(my_before, arg);
-               if (!error)
-                       *flp = *my_before;
-               goto out;
+               lease = *my_before;
+               error = lease->fl_lmops->lm_change(my_before, arg, &dispose);
+               if (error)
+                       goto out;
+               goto out_setup;
        }
 
        error = -EINVAL;
@@ -1619,43 +1667,61 @@ static int generic_add_lease(struct file *filp, long arg, struct file_lock **flp
        smp_mb();
        error = check_conflicting_open(dentry, arg);
        if (error)
-               locks_unlink_lock(before);
+               goto out_unlink;
+
+out_setup:
+       if (lease->fl_lmops->lm_setup)
+               lease->fl_lmops->lm_setup(lease, priv);
 out:
+       spin_unlock(&inode->i_lock);
+       locks_dispose_list(&dispose);
        if (is_deleg)
                mutex_unlock(&inode->i_mutex);
+       if (!error && !my_before)
+               *flp = NULL;
        return error;
+out_unlink:
+       locks_unlink_lock(before);
+       goto out;
 }
 
-static int generic_delete_lease(struct file *filp, struct file_lock **flp)
+static int generic_delete_lease(struct file *filp)
 {
+       int error = -EAGAIN;
        struct file_lock *fl, **before;
        struct dentry *dentry = filp->f_path.dentry;
        struct inode *inode = dentry->d_inode;
+       LIST_HEAD(dispose);
 
-       trace_generic_delete_lease(inode, *flp);
-
+       spin_lock(&inode->i_lock);
+       time_out_leases(inode, &dispose);
        for (before = &inode->i_flock;
                        ((fl = *before) != NULL) && IS_LEASE(fl);
                        before = &fl->fl_next) {
-               if (fl->fl_file != filp)
-                       continue;
-               return (*flp)->fl_lmops->lm_change(before, F_UNLCK);
+               if (fl->fl_file == filp)
+                       break;
        }
-       return -EAGAIN;
+       trace_generic_delete_lease(inode, fl);
+       if (fl)
+               error = fl->fl_lmops->lm_change(before, F_UNLCK, &dispose);
+       spin_unlock(&inode->i_lock);
+       locks_dispose_list(&dispose);
+       return error;
 }
 
 /**
  *     generic_setlease        -       sets a lease on an open file
- *     @filp: file pointer
- *     @arg: type of lease to obtain
- *     @flp: input - file_lock to use, output - file_lock inserted
+ *     @filp:  file pointer
+ *     @arg:   type of lease to obtain
+ *     @flp:   input - file_lock to use, output - file_lock inserted
+ *     @priv:  private data for lm_setup (may be NULL if lm_setup
+ *             doesn't require it)
  *
  *     The (input) flp->fl_lmops->lm_break function is required
  *     by break_lease().
- *
- *     Called with inode->i_lock held.
  */
-int generic_setlease(struct file *filp, long arg, struct file_lock **flp)
+int generic_setlease(struct file *filp, long arg, struct file_lock **flp,
+                       void **priv)
 {
        struct dentry *dentry = filp->f_path.dentry;
        struct inode *inode = dentry->d_inode;
@@ -1669,83 +1735,52 @@ int generic_setlease(struct file *filp, long arg, struct file_lock **flp)
        if (error)
                return error;
 
-       time_out_leases(inode);
-
-       BUG_ON(!(*flp)->fl_lmops->lm_break);
-
        switch (arg) {
        case F_UNLCK:
-               return generic_delete_lease(filp, flp);
+               return generic_delete_lease(filp);
        case F_RDLCK:
        case F_WRLCK:
-               return generic_add_lease(filp, arg, flp);
+               if (!(*flp)->fl_lmops->lm_break) {
+                       WARN_ON_ONCE(1);
+                       return -ENOLCK;
+               }
+               return generic_add_lease(filp, arg, flp, priv);
        default:
                return -EINVAL;
        }
 }
 EXPORT_SYMBOL(generic_setlease);
 
-static int __vfs_setlease(struct file *filp, long arg, struct file_lock **lease)
-{
-       if (filp->f_op->setlease)
-               return filp->f_op->setlease(filp, arg, lease);
-       else
-               return generic_setlease(filp, arg, lease);
-}
-
 /**
- *     vfs_setlease        -       sets a lease on an open file
- *     @filp: file pointer
- *     @arg: type of lease to obtain
- *     @lease: file_lock to use
- *
- *     Call this to establish a lease on the file.
- *     The (*lease)->fl_lmops->lm_break operation must be set; if not,
- *     break_lease will oops!
- *
- *     This will call the filesystem's setlease file method, if
- *     defined.  Note that there is no getlease method; instead, the
- *     filesystem setlease method should call back to setlease() to
- *     add a lease to the inode's lease list, where fcntl_getlease() can
- *     find it.  Since fcntl_getlease() only reports whether the current
- *     task holds a lease, a cluster filesystem need only do this for
- *     leases held by processes on this node.
- *
- *     There is also no break_lease method; filesystems that
- *     handle their own leases should break leases themselves from the
- *     filesystem's open, create, and (on truncate) setattr methods.
- *
- *     Warning: the only current setlease methods exist only to disable
- *     leases in certain cases.  More vfs changes may be required to
- *     allow a full filesystem lease implementation.
+ * vfs_setlease        -       sets a lease on an open file
+ * @filp:      file pointer
+ * @arg:       type of lease to obtain
+ * @lease:     file_lock to use when adding a lease
+ * @priv:      private info for lm_setup when adding a lease (may be
+ *             NULL if lm_setup doesn't require it)
+ *
+ * Call this to establish a lease on the file. The "lease" argument is not
+ * used for F_UNLCK requests and may be NULL. For commands that set or alter
+ * an existing lease, the (*lease)->fl_lmops->lm_break operation must be set;
+ * if not, this function will return -ENOLCK (and generate a scary-looking
+ * stack trace).
+ *
+ * The "priv" pointer is passed directly to the lm_setup function as-is. It
+ * may be NULL if the lm_setup operation doesn't require it.
  */
-
-int vfs_setlease(struct file *filp, long arg, struct file_lock **lease)
+int
+vfs_setlease(struct file *filp, long arg, struct file_lock **lease, void **priv)
 {
-       struct inode *inode = file_inode(filp);
-       int error;
-
-       spin_lock(&inode->i_lock);
-       error = __vfs_setlease(filp, arg, lease);
-       spin_unlock(&inode->i_lock);
-
-       return error;
+       if (filp->f_op->setlease)
+               return filp->f_op->setlease(filp, arg, lease, priv);
+       else
+               return generic_setlease(filp, arg, lease, priv);
 }
 EXPORT_SYMBOL_GPL(vfs_setlease);
 
-static int do_fcntl_delete_lease(struct file *filp)
-{
-       struct file_lock fl, *flp = &fl;
-
-       lease_init(filp, F_UNLCK, flp);
-
-       return vfs_setlease(filp, F_UNLCK, &flp);
-}
-
 static int do_fcntl_add_lease(unsigned int fd, struct file *filp, long arg)
 {
-       struct file_lock *fl, *ret;
-       struct inode *inode = file_inode(filp);
+       struct file_lock *fl;
        struct fasync_struct *new;
        int error;
 
@@ -1758,26 +1793,9 @@ static int do_fcntl_add_lease(unsigned int fd, struct file *filp, long arg)
                locks_free_lock(fl);
                return -ENOMEM;
        }
-       ret = fl;
-       spin_lock(&inode->i_lock);
-       error = __vfs_setlease(filp, arg, &ret);
-       if (error)
-               goto out_unlock;
-       if (ret == fl)
-               fl = NULL;
-
-       /*
-        * fasync_insert_entry() returns the old entry if any.
-        * If there was no old entry, then it used 'new' and
-        * inserted it into the fasync list. Clear new so that
-        * we don't release it here.
-        */
-       if (!fasync_insert_entry(fd, filp, &ret->fl_fasync, new))
-               new = NULL;
+       new->fa_fd = fd;
 
-       error = __f_setown(filp, task_pid(current), PIDTYPE_PID, 0);
-out_unlock:
-       spin_unlock(&inode->i_lock);
+       error = vfs_setlease(filp, arg, &fl, (void **)&new);
        if (fl)
                locks_free_lock(fl);
        if (new)
@@ -1798,7 +1816,7 @@ out_unlock:
 int fcntl_setlease(unsigned int fd, struct file *filp, long arg)
 {
        if (arg == F_UNLCK)
-               return do_fcntl_delete_lease(filp);
+               return vfs_setlease(filp, F_UNLCK, NULL, NULL);
        return do_fcntl_add_lease(fd, filp, arg);
 }
 
@@ -1867,9 +1885,12 @@ SYSCALL_DEFINE2(flock, unsigned int, fd, unsigned int, cmd)
            !(f.file->f_mode & (FMODE_READ|FMODE_WRITE)))
                goto out_putf;
 
-       error = flock_make_lock(f.file, &lock, cmd);
-       if (error)
+       lock = flock_make_lock(f.file, cmd);
+       if (IS_ERR(lock)) {
+               error = PTR_ERR(lock);
                goto out_putf;
+       }
+
        if (can_sleep)
                lock->fl_flags |= FL_SLEEP;
 
@@ -1981,11 +2002,13 @@ int fcntl_getlk(struct file *filp, unsigned int cmd, struct flock __user *l)
        if (file_lock.fl_type != F_UNLCK) {
                error = posix_lock_to_flock(&flock, &file_lock);
                if (error)
-                       goto out;
+                       goto rel_priv;
        }
        error = -EFAULT;
        if (!copy_to_user(l, &flock, sizeof(flock)))
                error = 0;
+rel_priv:
+       locks_release_private(&file_lock);
 out:
        return error;
 }
@@ -2206,7 +2229,8 @@ int fcntl_getlk64(struct file *filp, unsigned int cmd, struct flock64 __user *l)
        error = -EFAULT;
        if (!copy_to_user(l, &flock, sizeof(flock)))
                error = 0;
-  
+
+       locks_release_private(&file_lock);
 out:
        return error;
 }
@@ -2369,7 +2393,7 @@ void locks_remove_file(struct file *filp)
        while ((fl = *before) != NULL) {
                if (fl->fl_file == filp) {
                        if (IS_LEASE(fl)) {
-                               lease_modify(before, F_UNLCK);
+                               lease_modify(before, F_UNLCK, &dispose);
                                continue;
                        }
 
@@ -2593,86 +2617,6 @@ static int __init proc_locks_init(void)
 module_init(proc_locks_init);
 #endif
 
-/**
- *     lock_may_read - checks that the region is free of locks
- *     @inode: the inode that is being read
- *     @start: the first byte to read
- *     @len: the number of bytes to read
- *
- *     Emulates Windows locking requirements.  Whole-file
- *     mandatory locks (share modes) can prohibit a read and
- *     byte-range POSIX locks can prohibit a read if they overlap.
- *
- *     N.B. this function is only ever called
- *     from knfsd and ownership of locks is never checked.
- */
-int lock_may_read(struct inode *inode, loff_t start, unsigned long len)
-{
-       struct file_lock *fl;
-       int result = 1;
-
-       spin_lock(&inode->i_lock);
-       for (fl = inode->i_flock; fl != NULL; fl = fl->fl_next) {
-               if (IS_POSIX(fl)) {
-                       if (fl->fl_type == F_RDLCK)
-                               continue;
-                       if ((fl->fl_end < start) || (fl->fl_start > (start + len)))
-                               continue;
-               } else if (IS_FLOCK(fl)) {
-                       if (!(fl->fl_type & LOCK_MAND))
-                               continue;
-                       if (fl->fl_type & LOCK_READ)
-                               continue;
-               } else
-                       continue;
-               result = 0;
-               break;
-       }
-       spin_unlock(&inode->i_lock);
-       return result;
-}
-
-EXPORT_SYMBOL(lock_may_read);
-
-/**
- *     lock_may_write - checks that the region is free of locks
- *     @inode: the inode that is being written
- *     @start: the first byte to write
- *     @len: the number of bytes to write
- *
- *     Emulates Windows locking requirements.  Whole-file
- *     mandatory locks (share modes) can prohibit a write and
- *     byte-range POSIX locks can prohibit a write if they overlap.
- *
- *     N.B. this function is only ever called
- *     from knfsd and ownership of locks is never checked.
- */
-int lock_may_write(struct inode *inode, loff_t start, unsigned long len)
-{
-       struct file_lock *fl;
-       int result = 1;
-
-       spin_lock(&inode->i_lock);
-       for (fl = inode->i_flock; fl != NULL; fl = fl->fl_next) {
-               if (IS_POSIX(fl)) {
-                       if ((fl->fl_end < start) || (fl->fl_start > (start + len)))
-                               continue;
-               } else if (IS_FLOCK(fl)) {
-                       if (!(fl->fl_type & LOCK_MAND))
-                               continue;
-                       if (fl->fl_type & LOCK_WRITE)
-                               continue;
-               } else
-                       continue;
-               result = 0;
-               break;
-       }
-       spin_unlock(&inode->i_lock);
-       return result;
-}
-
-EXPORT_SYMBOL(lock_may_write);
-
 static int __init filelock_init(void)
 {
        int i;
index 6740a621552950e7a795b249f635b5eeea7065d1..f82c62840905f8be7df888a6dd87bfb2e2c30af5 100644 (file)
@@ -21,6 +21,7 @@ struct mnt_pcp {
 struct mountpoint {
        struct hlist_node m_hash;
        struct dentry *m_dentry;
+       struct hlist_head m_list;
        int m_count;
 };
 
@@ -29,7 +30,10 @@ struct mount {
        struct mount *mnt_parent;
        struct dentry *mnt_mountpoint;
        struct vfsmount mnt;
-       struct rcu_head mnt_rcu;
+       union {
+               struct rcu_head mnt_rcu;
+               struct llist_node mnt_llist;
+       };
 #ifdef CONFIG_SMP
        struct mnt_pcp __percpu *mnt_pcp;
 #else
@@ -48,6 +52,7 @@ struct mount {
        struct mount *mnt_master;       /* slave is on master->mnt_slave_list */
        struct mnt_namespace *mnt_ns;   /* containing namespace */
        struct mountpoint *mnt_mp;      /* where is it mounted */
+       struct hlist_node mnt_mp_list;  /* list mounts with the same mountpoint */
 #ifdef CONFIG_FSNOTIFY
        struct hlist_head mnt_fsnotify_marks;
        __u32 mnt_fsnotify_mask;
@@ -82,6 +87,15 @@ extern struct mount *__lookup_mnt_last(struct vfsmount *, struct dentry *);
 
 extern bool legitimize_mnt(struct vfsmount *, unsigned);
 
+extern void __detach_mounts(struct dentry *dentry);
+
+static inline void detach_mounts(struct dentry *dentry)
+{
+       if (!d_mountpoint(dentry))
+               return;
+       __detach_mounts(dentry);
+}
+
 static inline void get_mnt_ns(struct mnt_namespace *ns)
 {
        atomic_inc(&ns->count);
@@ -112,3 +126,12 @@ struct proc_mounts {
 #define proc_mounts(p) (container_of((p), struct proc_mounts, m))
 
 extern const struct seq_operations mounts_op;
+
+extern bool __is_local_mountpoint(struct dentry *dentry);
+static inline bool is_local_mountpoint(struct dentry *dentry)
+{
+       if (!d_mountpoint(dentry))
+               return false;
+
+       return __is_local_mountpoint(dentry);
+}
index a7b05bf82d31ad2e8eacbac999a049cab1f8d446..43927d14db67c68706ef8dd208c714ec2ec6addb 100644 (file)
@@ -1306,7 +1306,8 @@ static struct dentry *lookup_dcache(struct qstr *name, struct dentry *dir,
                                if (error < 0) {
                                        dput(dentry);
                                        return ERR_PTR(error);
-                               } else if (!d_invalidate(dentry)) {
+                               } else {
+                                       d_invalidate(dentry);
                                        dput(dentry);
                                        dentry = NULL;
                                }
@@ -1435,10 +1436,9 @@ unlazy:
                        dput(dentry);
                        return status;
                }
-               if (!d_invalidate(dentry)) {
-                       dput(dentry);
-                       goto need_lookup;
-               }
+               d_invalidate(dentry);
+               dput(dentry);
+               goto need_lookup;
        }
 
        path->mnt = mnt;
@@ -1950,7 +1950,7 @@ static int path_lookupat(int dfd, const char *name,
        err = path_init(dfd, name, flags | LOOKUP_PARENT, nd, &base);
 
        if (unlikely(err))
-               return err;
+               goto out;
 
        current->total_link_count = 0;
        err = link_path_walk(name, nd);
@@ -1982,6 +1982,7 @@ static int path_lookupat(int dfd, const char *name,
                }
        }
 
+out:
        if (base)
                fput(base);
 
@@ -2301,7 +2302,7 @@ path_mountpoint(int dfd, const char *name, struct path *path, unsigned int flags
 
        err = path_init(dfd, name, flags | LOOKUP_PARENT, &nd, &base);
        if (unlikely(err))
-               return err;
+               goto out;
 
        current->total_link_count = 0;
        err = link_path_walk(name, &nd);
@@ -3074,7 +3075,7 @@ opened:
        error = open_check_o_direct(file);
        if (error)
                goto exit_fput;
-       error = ima_file_check(file, op->acc_mode);
+       error = ima_file_check(file, op->acc_mode, *opened);
        if (error)
                goto exit_fput;
 
@@ -3565,7 +3566,7 @@ int vfs_rmdir(struct inode *dir, struct dentry *dentry)
        mutex_lock(&dentry->d_inode->i_mutex);
 
        error = -EBUSY;
-       if (d_mountpoint(dentry))
+       if (is_local_mountpoint(dentry))
                goto out;
 
        error = security_inode_rmdir(dir, dentry);
@@ -3579,6 +3580,7 @@ int vfs_rmdir(struct inode *dir, struct dentry *dentry)
 
        dentry->d_inode->i_flags |= S_DEAD;
        dont_mount(dentry);
+       detach_mounts(dentry);
 
 out:
        mutex_unlock(&dentry->d_inode->i_mutex);
@@ -3681,7 +3683,7 @@ int vfs_unlink(struct inode *dir, struct dentry *dentry, struct inode **delegate
                return -EPERM;
 
        mutex_lock(&target->i_mutex);
-       if (d_mountpoint(dentry))
+       if (is_local_mountpoint(dentry))
                error = -EBUSY;
        else {
                error = security_inode_unlink(dir, dentry);
@@ -3690,8 +3692,10 @@ int vfs_unlink(struct inode *dir, struct dentry *dentry, struct inode **delegate
                        if (error)
                                goto out;
                        error = dir->i_op->unlink(dir, dentry);
-                       if (!error)
+                       if (!error) {
                                dont_mount(dentry);
+                               detach_mounts(dentry);
+                       }
                }
        }
 out:
@@ -4126,7 +4130,7 @@ int vfs_rename(struct inode *old_dir, struct dentry *old_dentry,
                mutex_lock(&target->i_mutex);
 
        error = -EBUSY;
-       if (d_mountpoint(old_dentry) || d_mountpoint(new_dentry))
+       if (is_local_mountpoint(old_dentry) || is_local_mountpoint(new_dentry))
                goto out;
 
        if (max_links && new_dir != old_dir) {
@@ -4164,6 +4168,7 @@ int vfs_rename(struct inode *old_dir, struct dentry *old_dentry,
                if (is_dir)
                        target->i_flags |= S_DEAD;
                dont_mount(new_dentry);
+               detach_mounts(new_dentry);
        }
        if (!(old_dir->i_sb->s_type->fs_flags & FS_RENAME_DOES_D_MOVE)) {
                if (!(flags & RENAME_EXCHANGE))
index 74647c2fe69ca3703c2c1492555f5c85eb73ce72..fbba8b17330d40d4daff7cf61763853cfd414395 100644 (file)
@@ -23,6 +23,7 @@
 #include <linux/proc_ns.h>
 #include <linux/magic.h>
 #include <linux/bootmem.h>
+#include <linux/task_work.h>
 #include "pnode.h"
 #include "internal.h"
 
@@ -224,6 +225,7 @@ static struct mount *alloc_vfsmnt(const char *name)
                INIT_LIST_HEAD(&mnt->mnt_share);
                INIT_LIST_HEAD(&mnt->mnt_slave_list);
                INIT_LIST_HEAD(&mnt->mnt_slave);
+               INIT_HLIST_NODE(&mnt->mnt_mp_list);
 #ifdef CONFIG_FSNOTIFY
                INIT_HLIST_HEAD(&mnt->mnt_fsnotify_marks);
 #endif
@@ -666,11 +668,45 @@ struct vfsmount *lookup_mnt(struct path *path)
        return m;
 }
 
-static struct mountpoint *new_mountpoint(struct dentry *dentry)
+/*
+ * __is_local_mountpoint - Test to see if dentry is a mountpoint in the
+ *                         current mount namespace.
+ *
+ * The common case is dentries are not mountpoints at all and that
+ * test is handled inline.  For the slow case when we are actually
+ * dealing with a mountpoint of some kind, walk through all of the
+ * mounts in the current mount namespace and test to see if the dentry
+ * is a mountpoint.
+ *
+ * The mount_hashtable is not usable in the context because we
+ * need to identify all mounts that may be in the current mount
+ * namespace not just a mount that happens to have some specified
+ * parent mount.
+ */
+bool __is_local_mountpoint(struct dentry *dentry)
+{
+       struct mnt_namespace *ns = current->nsproxy->mnt_ns;
+       struct mount *mnt;
+       bool is_covered = false;
+
+       if (!d_mountpoint(dentry))
+               goto out;
+
+       down_read(&namespace_sem);
+       list_for_each_entry(mnt, &ns->list, mnt_list) {
+               is_covered = (mnt->mnt_mountpoint == dentry);
+               if (is_covered)
+                       break;
+       }
+       up_read(&namespace_sem);
+out:
+       return is_covered;
+}
+
+static struct mountpoint *lookup_mountpoint(struct dentry *dentry)
 {
        struct hlist_head *chain = mp_hash(dentry);
        struct mountpoint *mp;
-       int ret;
 
        hlist_for_each_entry(mp, chain, m_hash) {
                if (mp->m_dentry == dentry) {
@@ -681,6 +717,14 @@ static struct mountpoint *new_mountpoint(struct dentry *dentry)
                        return mp;
                }
        }
+       return NULL;
+}
+
+static struct mountpoint *new_mountpoint(struct dentry *dentry)
+{
+       struct hlist_head *chain = mp_hash(dentry);
+       struct mountpoint *mp;
+       int ret;
 
        mp = kmalloc(sizeof(struct mountpoint), GFP_KERNEL);
        if (!mp)
@@ -695,6 +739,7 @@ static struct mountpoint *new_mountpoint(struct dentry *dentry)
        mp->m_dentry = dentry;
        mp->m_count = 1;
        hlist_add_head(&mp->m_hash, chain);
+       INIT_HLIST_HEAD(&mp->m_list);
        return mp;
 }
 
@@ -702,6 +747,7 @@ static void put_mountpoint(struct mountpoint *mp)
 {
        if (!--mp->m_count) {
                struct dentry *dentry = mp->m_dentry;
+               BUG_ON(!hlist_empty(&mp->m_list));
                spin_lock(&dentry->d_lock);
                dentry->d_flags &= ~DCACHE_MOUNTED;
                spin_unlock(&dentry->d_lock);
@@ -748,6 +794,7 @@ static void detach_mnt(struct mount *mnt, struct path *old_path)
        mnt->mnt_mountpoint = mnt->mnt.mnt_root;
        list_del_init(&mnt->mnt_child);
        hlist_del_init_rcu(&mnt->mnt_hash);
+       hlist_del_init(&mnt->mnt_mp_list);
        put_mountpoint(mnt->mnt_mp);
        mnt->mnt_mp = NULL;
 }
@@ -764,6 +811,7 @@ void mnt_set_mountpoint(struct mount *mnt,
        child_mnt->mnt_mountpoint = dget(mp->m_dentry);
        child_mnt->mnt_parent = mnt;
        child_mnt->mnt_mp = mp;
+       hlist_add_head(&child_mnt->mnt_mp_list, &mp->m_list);
 }
 
 /*
@@ -957,6 +1005,46 @@ static struct mount *clone_mnt(struct mount *old, struct dentry *root,
        return ERR_PTR(err);
 }
 
+static void cleanup_mnt(struct mount *mnt)
+{
+       /*
+        * This probably indicates that somebody messed
+        * up a mnt_want/drop_write() pair.  If this
+        * happens, the filesystem was probably unable
+        * to make r/w->r/o transitions.
+        */
+       /*
+        * The locking used to deal with mnt_count decrement provides barriers,
+        * so mnt_get_writers() below is safe.
+        */
+       WARN_ON(mnt_get_writers(mnt));
+       if (unlikely(mnt->mnt_pins.first))
+               mnt_pin_kill(mnt);
+       fsnotify_vfsmount_delete(&mnt->mnt);
+       dput(mnt->mnt.mnt_root);
+       deactivate_super(mnt->mnt.mnt_sb);
+       mnt_free_id(mnt);
+       call_rcu(&mnt->mnt_rcu, delayed_free_vfsmnt);
+}
+
+static void __cleanup_mnt(struct rcu_head *head)
+{
+       cleanup_mnt(container_of(head, struct mount, mnt_rcu));
+}
+
+static LLIST_HEAD(delayed_mntput_list);
+static void delayed_mntput(struct work_struct *unused)
+{
+       struct llist_node *node = llist_del_all(&delayed_mntput_list);
+       struct llist_node *next;
+
+       for (; node; node = next) {
+               next = llist_next(node);
+               cleanup_mnt(llist_entry(node, struct mount, mnt_llist));
+       }
+}
+static DECLARE_DELAYED_WORK(delayed_mntput_work, delayed_mntput);
+
 static void mntput_no_expire(struct mount *mnt)
 {
        rcu_read_lock();
@@ -982,24 +1070,18 @@ static void mntput_no_expire(struct mount *mnt)
        list_del(&mnt->mnt_instance);
        unlock_mount_hash();
 
-       /*
-        * This probably indicates that somebody messed
-        * up a mnt_want/drop_write() pair.  If this
-        * happens, the filesystem was probably unable
-        * to make r/w->r/o transitions.
-        */
-       /*
-        * The locking used to deal with mnt_count decrement provides barriers,
-        * so mnt_get_writers() below is safe.
-        */
-       WARN_ON(mnt_get_writers(mnt));
-       if (unlikely(mnt->mnt_pins.first))
-               mnt_pin_kill(mnt);
-       fsnotify_vfsmount_delete(&mnt->mnt);
-       dput(mnt->mnt.mnt_root);
-       deactivate_super(mnt->mnt.mnt_sb);
-       mnt_free_id(mnt);
-       call_rcu(&mnt->mnt_rcu, delayed_free_vfsmnt);
+       if (likely(!(mnt->mnt.mnt_flags & MNT_INTERNAL))) {
+               struct task_struct *task = current;
+               if (likely(!(task->flags & PF_KTHREAD))) {
+                       init_task_work(&mnt->mnt_rcu, __cleanup_mnt);
+                       if (!task_work_add(task, &mnt->mnt_rcu, true))
+                               return;
+               }
+               if (llist_add(&mnt->mnt_llist, &delayed_mntput_list))
+                       schedule_delayed_work(&delayed_mntput_work, 1);
+               return;
+       }
+       cleanup_mnt(mnt);
 }
 
 void mntput(struct vfsmount *mnt)
@@ -1272,6 +1354,7 @@ void umount_tree(struct mount *mnt, int how)
                if (how < 2)
                        p->mnt.mnt_flags |= MNT_SYNC_UMOUNT;
                if (mnt_has_parent(p)) {
+                       hlist_del_init(&p->mnt_mp_list);
                        put_mountpoint(p->mnt_mp);
                        mnt_add_count(p->mnt_parent, -1);
                        /* move the reference to mountpoint into ->mnt_ex_mountpoint */
@@ -1356,6 +1439,8 @@ static int do_umount(struct mount *mnt, int flags)
                 * Special case for "unmounting" root ...
                 * we just try to remount it readonly.
                 */
+               if (!capable(CAP_SYS_ADMIN))
+                       return -EPERM;
                down_write(&sb->s_umount);
                if (!(sb->s_flags & MS_RDONLY))
                        retval = do_remount_sb(sb, MS_RDONLY, NULL, 0);
@@ -1385,6 +1470,37 @@ static int do_umount(struct mount *mnt, int flags)
        return retval;
 }
 
+/*
+ * __detach_mounts - lazily unmount all mounts on the specified dentry
+ *
+ * During unlink, rmdir, and d_drop it is possible to loose the path
+ * to an existing mountpoint, and wind up leaking the mount.
+ * detach_mounts allows lazily unmounting those mounts instead of
+ * leaking them.
+ *
+ * The caller may hold dentry->d_inode->i_mutex.
+ */
+void __detach_mounts(struct dentry *dentry)
+{
+       struct mountpoint *mp;
+       struct mount *mnt;
+
+       namespace_lock();
+       mp = lookup_mountpoint(dentry);
+       if (!mp)
+               goto out_unlock;
+
+       lock_mount_hash();
+       while (!hlist_empty(&mp->m_list)) {
+               mnt = hlist_entry(mp->m_list.first, struct mount, mnt_mp_list);
+               umount_tree(mnt, 2);
+       }
+       unlock_mount_hash();
+       put_mountpoint(mp);
+out_unlock:
+       namespace_unlock();
+}
+
 /* 
  * Is the caller allowed to modify his namespace?
  */
@@ -1742,7 +1858,9 @@ retry:
        namespace_lock();
        mnt = lookup_mnt(path);
        if (likely(!mnt)) {
-               struct mountpoint *mp = new_mountpoint(dentry);
+               struct mountpoint *mp = lookup_mountpoint(dentry);
+               if (!mp)
+                       mp = new_mountpoint(dentry);
                if (IS_ERR(mp)) {
                        namespace_unlock();
                        mutex_unlock(&dentry->d_inode->i_mutex);
@@ -2398,21 +2516,9 @@ int copy_mount_options(const void __user * data, unsigned long *where)
        return 0;
 }
 
-int copy_mount_string(const void __user *data, char **where)
+char *copy_mount_string(const void __user *data)
 {
-       char *tmp;
-
-       if (!data) {
-               *where = NULL;
-               return 0;
-       }
-
-       tmp = strndup_user(data, PAGE_SIZE);
-       if (IS_ERR(tmp))
-               return PTR_ERR(tmp);
-
-       *where = tmp;
-       return 0;
+       return data ? strndup_user(data, PAGE_SIZE) : NULL;
 }
 
 /*
@@ -2429,7 +2535,7 @@ int copy_mount_string(const void __user *data, char **where)
  * Therefore, if this magic number is present, it carries no information
  * and must be discarded.
  */
-long do_mount(const char *dev_name, const char *dir_name,
+long do_mount(const char *dev_name, const char __user *dir_name,
                const char *type_page, unsigned long flags, void *data_page)
 {
        struct path path;
@@ -2441,15 +2547,11 @@ long do_mount(const char *dev_name, const char *dir_name,
                flags &= ~MS_MGC_MSK;
 
        /* Basic sanity checks */
-
-       if (!dir_name || !*dir_name || !memchr(dir_name, 0, PAGE_SIZE))
-               return -EINVAL;
-
        if (data_page)
                ((char *)data_page)[PAGE_SIZE - 1] = 0;
 
        /* ... and get the mountpoint */
-       retval = kern_path(dir_name, LOOKUP_FOLLOW, &path);
+       retval = user_path(dir_name, &path);
        if (retval)
                return retval;
 
@@ -2674,37 +2776,30 @@ SYSCALL_DEFINE5(mount, char __user *, dev_name, char __user *, dir_name,
 {
        int ret;
        char *kernel_type;
-       struct filename *kernel_dir;
        char *kernel_dev;
        unsigned long data_page;
 
-       ret = copy_mount_string(type, &kernel_type);
-       if (ret < 0)
+       kernel_type = copy_mount_string(type);
+       ret = PTR_ERR(kernel_type);
+       if (IS_ERR(kernel_type))
                goto out_type;
 
-       kernel_dir = getname(dir_name);
-       if (IS_ERR(kernel_dir)) {
-               ret = PTR_ERR(kernel_dir);
-               goto out_dir;
-       }
-
-       ret = copy_mount_string(dev_name, &kernel_dev);
-       if (ret < 0)
+       kernel_dev = copy_mount_string(dev_name);
+       ret = PTR_ERR(kernel_dev);
+       if (IS_ERR(kernel_dev))
                goto out_dev;
 
        ret = copy_mount_options(data, &data_page);
        if (ret < 0)
                goto out_data;
 
-       ret = do_mount(kernel_dev, kernel_dir->name, kernel_type, flags,
+       ret = do_mount(kernel_dev, dir_name, kernel_type, flags,
                (void *) data_page);
 
        free_page(data_page);
 out_data:
        kfree(kernel_dev);
 out_dev:
-       putname(kernel_dir);
-out_dir:
        kfree(kernel_type);
 out_type:
        return ret;
index 08b8ea8c353edaf4966fe0f385e1cc22691851dd..7cb751dfbeef0a86d94237292d09e591e249f4e7 100644 (file)
@@ -388,7 +388,6 @@ static struct dentry *
 ncp_dget_fpos(struct dentry *dentry, struct dentry *parent, unsigned long fpos)
 {
        struct dentry *dent = dentry;
-       struct list_head *next;
 
        if (d_validate(dent, parent)) {
                if (dent->d_name.len <= NCP_MAXPATHLEN &&
@@ -404,9 +403,7 @@ ncp_dget_fpos(struct dentry *dentry, struct dentry *parent, unsigned long fpos)
 
        /* If a pointer is invalid, we search the dentry. */
        spin_lock(&parent->d_lock);
-       next = parent->d_subdirs.next;
-       while (next != &parent->d_subdirs) {
-               dent = list_entry(next, struct dentry, d_u.d_child);
+       list_for_each_entry(dent, &parent->d_subdirs, d_u.d_child) {
                if ((unsigned long)dent->d_fsdata == fpos) {
                        if (dent->d_inode)
                                dget(dent);
@@ -415,7 +412,6 @@ ncp_dget_fpos(struct dentry *dentry, struct dentry *parent, unsigned long fpos)
                        spin_unlock(&parent->d_lock);
                        goto out;
                }
-               next = next->next;
        }
        spin_unlock(&parent->d_lock);
        return NULL;
@@ -1182,9 +1178,6 @@ static int day_n[] =
 {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 0, 0, 0, 0};
 /* Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec */
 
-
-extern struct timezone sys_tz;
-
 static int utc2local(int time)
 {
        return time - sys_tz.tz_minuteswest * 60;
index 32c06587351a138f34b09955802ad397c5b6a5f3..52cb19d66ecbbb328867134c3639383e1a7ac146 100644 (file)
@@ -188,20 +188,14 @@ static inline void
 ncp_renew_dentries(struct dentry *parent)
 {
        struct ncp_server *server = NCP_SERVER(parent->d_inode);
-       struct list_head *next;
        struct dentry *dentry;
 
        spin_lock(&parent->d_lock);
-       next = parent->d_subdirs.next;
-       while (next != &parent->d_subdirs) {
-               dentry = list_entry(next, struct dentry, d_u.d_child);
-
+       list_for_each_entry(dentry, &parent->d_subdirs, d_u.d_child) {
                if (dentry->d_fsdata == NULL)
                        ncp_age_dentry(server, dentry);
                else
                        ncp_new_dentry(dentry);
-
-               next = next->next;
        }
        spin_unlock(&parent->d_lock);
 }
@@ -210,16 +204,12 @@ static inline void
 ncp_invalidate_dircache_entries(struct dentry *parent)
 {
        struct ncp_server *server = NCP_SERVER(parent->d_inode);
-       struct list_head *next;
        struct dentry *dentry;
 
        spin_lock(&parent->d_lock);
-       next = parent->d_subdirs.next;
-       while (next != &parent->d_subdirs) {
-               dentry = list_entry(next, struct dentry, d_u.d_child);
+       list_for_each_entry(dentry, &parent->d_subdirs, d_u.d_child) {
                dentry->d_fsdata = NULL;
                ncp_age_dentry(server, dentry);
-               next = next->next;
        }
        spin_unlock(&parent->d_lock);
 }
index 8d04bda2bd2e62c8609e8b9f59a2c1ea1666d968..e966c023b1b74df4161461a7cad843e6b9bcfbda 100644 (file)
@@ -92,7 +92,6 @@ bl_resolve_deviceid(struct nfs_server *server, struct pnfs_block_volume *b,
 
        set_current_state(TASK_UNINTERRUPTIBLE);
        schedule();
-       __set_current_state(TASK_RUNNING);
        remove_wait_queue(&nn->bl_wq, &wq);
 
        if (reply->status != BL_DEVICE_REQUEST_PROC) {
index 36d921f0c6026c27170b565f46eb4e26999ea812..06e8cfcbb67053759d9b2b17e4c68a4547b257da 100644 (file)
@@ -486,8 +486,7 @@ void nfs_prime_dcache(struct dentry *parent, struct nfs_entry *entry)
                                nfs_setsecurity(dentry->d_inode, entry->fattr, entry->label);
                        goto out;
                } else {
-                       if (d_invalidate(dentry) != 0)
-                               goto out;
+                       d_invalidate(dentry);
                        dput(dentry);
                }
        }
@@ -1211,10 +1210,6 @@ out_zap_parent:
                if (IS_ROOT(dentry))
                        goto out_valid;
        }
-       /* If we have submounts, don't unhash ! */
-       if (check_submounts_and_drop(dentry) != 0)
-               goto out_valid;
-
        dput(parent);
        dfprintk(LOOKUPCACHE, "NFS: %s(%pd2) is invalid\n",
                        __func__, dentry);
index 6920127c5eb7eebce51958422dfbfaf38cbd4b29..4ea92ce0537fdc9710ab4385200ed5e7f724ce76 100644 (file)
@@ -919,17 +919,6 @@ int nfs_flock(struct file *filp, int cmd, struct file_lock *fl)
 }
 EXPORT_SYMBOL_GPL(nfs_flock);
 
-/*
- * There is no protocol support for leases, so we have no way to implement
- * them correctly in the face of opens by other clients.
- */
-int nfs_setlease(struct file *file, long arg, struct file_lock **fl)
-{
-       dprintk("NFS: setlease(%pD2, arg=%ld)\n", file, arg);
-       return -EINVAL;
-}
-EXPORT_SYMBOL_GPL(nfs_setlease);
-
 const struct file_operations nfs_file_operations = {
        .llseek         = nfs_file_llseek,
        .read           = new_sync_read,
@@ -946,6 +935,6 @@ const struct file_operations nfs_file_operations = {
        .splice_read    = nfs_file_splice_read,
        .splice_write   = iter_file_splice_write,
        .check_flags    = nfs_check_flags,
-       .setlease       = nfs_setlease,
+       .setlease       = simple_nosetlease,
 };
 EXPORT_SYMBOL_GPL(nfs_file_operations);
index 7dd55b745c4d96cf07de07fc1a925a3590fbd802..2f5db844c172534a229d86b011be1f6ec2c29aff 100644 (file)
@@ -177,7 +177,6 @@ static struct key_type key_type_id_resolver = {
        .preparse       = user_preparse,
        .free_preparse  = user_free_preparse,
        .instantiate    = generic_key_instantiate,
-       .match          = user_match,
        .revoke         = user_revoke,
        .destroy        = user_destroy,
        .describe       = user_describe,
@@ -401,7 +400,6 @@ static struct key_type key_type_id_resolver_legacy = {
        .preparse       = user_preparse,
        .free_preparse  = user_free_preparse,
        .instantiate    = generic_key_instantiate,
-       .match          = user_match,
        .revoke         = user_revoke,
        .destroy        = user_destroy,
        .describe       = user_describe,
index 14ae6f20a1724aa4d81aed3fee294d643a6aafe1..efaa31c70fbe1c43d265c51bc542a8270348c339 100644 (file)
@@ -339,7 +339,6 @@ int nfs_file_release(struct inode *, struct file *);
 int nfs_lock(struct file *, int, struct file_lock *);
 int nfs_flock(struct file *, int, struct file_lock *);
 int nfs_check_flags(int);
-int nfs_setlease(struct file *, long, struct file_lock **);
 
 /* inode.c */
 extern struct workqueue_struct *nfsiod_workqueue;
index a816f0627a6ce03cda2502c42c780c5ab6a2742c..3e987ad9ae2547488f6a24d9ac0a411c122028ac 100644 (file)
@@ -131,5 +131,5 @@ const struct file_operations nfs4_file_operations = {
        .splice_read    = nfs_file_splice_read,
        .splice_write   = iter_file_splice_write,
        .check_flags    = nfs_check_flags,
-       .setlease       = nfs_setlease,
+       .setlease       = simple_nosetlease,
 };
index ea95a2bc21b59542a517b70e2086f63430b252e9..a25490ae6c62dea32e5b5cff447e1f7e027a9778 100644 (file)
@@ -675,7 +675,6 @@ __cld_pipe_upcall(struct rpc_pipe *pipe, struct cld_msg *cmsg)
        }
 
        schedule();
-       set_current_state(TASK_RUNNING);
 
        if (msg.errno < 0)
                ret = msg.errno;
index 5c0cac1730682178679f7fe7ae00c95b87da9642..e9c3afe4b5d3c306a5dd61692ed34805ca661f7a 100644 (file)
@@ -218,6 +218,13 @@ static void nfsd4_put_session(struct nfsd4_session *ses)
        spin_unlock(&nn->client_lock);
 }
 
+static inline struct nfs4_stateowner *
+nfs4_get_stateowner(struct nfs4_stateowner *sop)
+{
+       atomic_inc(&sop->so_count);
+       return sop;
+}
+
 static int
 same_owner_str(struct nfs4_stateowner *sop, struct xdr_netobj *owner)
 {
@@ -237,10 +244,8 @@ find_openstateowner_str_locked(unsigned int hashval, struct nfsd4_open *open,
                            so_strhash) {
                if (!so->so_is_open_owner)
                        continue;
-               if (same_owner_str(so, &open->op_owner)) {
-                       atomic_inc(&so->so_count);
-                       return openowner(so);
-               }
+               if (same_owner_str(so, &open->op_owner))
+                       return openowner(nfs4_get_stateowner(so));
        }
        return NULL;
 }
@@ -678,18 +683,14 @@ nfs4_put_stid(struct nfs4_stid *s)
 static void nfs4_put_deleg_lease(struct nfs4_file *fp)
 {
        struct file *filp = NULL;
-       struct file_lock *fl;
 
        spin_lock(&fp->fi_lock);
-       if (fp->fi_lease && atomic_dec_and_test(&fp->fi_delegees)) {
+       if (fp->fi_deleg_file && atomic_dec_and_test(&fp->fi_delegees))
                swap(filp, fp->fi_deleg_file);
-               fl = fp->fi_lease;
-               fp->fi_lease = NULL;
-       }
        spin_unlock(&fp->fi_lock);
 
        if (filp) {
-               vfs_setlease(filp, F_UNLCK, &fl);
+               vfs_setlease(filp, F_UNLCK, NULL, NULL);
                fput(filp);
        }
 }
@@ -1655,7 +1656,7 @@ __destroy_client(struct nfs4_client *clp)
        }
        while (!list_empty(&clp->cl_openowners)) {
                oo = list_entry(clp->cl_openowners.next, struct nfs4_openowner, oo_perclient);
-               atomic_inc(&oo->oo_owner.so_count);
+               nfs4_get_stateowner(&oo->oo_owner);
                release_openowner(oo);
        }
        nfsd4_shutdown_callback(clp);
@@ -3067,8 +3068,8 @@ static void nfsd4_init_file(struct nfs4_file *fp, struct knfsd_fh *fh)
        INIT_LIST_HEAD(&fp->fi_stateids);
        INIT_LIST_HEAD(&fp->fi_delegations);
        fh_copy_shallow(&fp->fi_fhandle, fh);
+       fp->fi_deleg_file = NULL;
        fp->fi_had_conflict = false;
-       fp->fi_lease = NULL;
        fp->fi_share_deny = 0;
        memset(fp->fi_fds, 0, sizeof(fp->fi_fds));
        memset(fp->fi_access, 0, sizeof(fp->fi_access));
@@ -3136,8 +3137,7 @@ static void nfsd4_cstate_assign_replay(struct nfsd4_compound_state *cstate,
 {
        if (!nfsd4_has_session(cstate)) {
                mutex_lock(&so->so_replay.rp_mutex);
-               cstate->replay_owner = so;
-               atomic_inc(&so->so_count);
+               cstate->replay_owner = nfs4_get_stateowner(so);
        }
 }
 
@@ -3236,8 +3236,7 @@ static void init_open_stateid(struct nfs4_ol_stateid *stp, struct nfs4_file *fp,
        atomic_inc(&stp->st_stid.sc_count);
        stp->st_stid.sc_type = NFS4_OPEN_STID;
        INIT_LIST_HEAD(&stp->st_locks);
-       stp->st_stateowner = &oo->oo_owner;
-       atomic_inc(&stp->st_stateowner->so_count);
+       stp->st_stateowner = nfs4_get_stateowner(&oo->oo_owner);
        get_nfs4_file(fp);
        stp->st_stid.sc_file = fp;
        stp->st_access_bmap = 0;
@@ -3434,18 +3433,20 @@ static void nfsd_break_one_deleg(struct nfs4_delegation *dp)
 }
 
 /* Called from break_lease() with i_lock held. */
-static void nfsd_break_deleg_cb(struct file_lock *fl)
+static bool
+nfsd_break_deleg_cb(struct file_lock *fl)
 {
+       bool ret = false;
        struct nfs4_file *fp = (struct nfs4_file *)fl->fl_owner;
        struct nfs4_delegation *dp;
 
        if (!fp) {
                WARN(1, "(%p)->fl_owner NULL\n", fl);
-               return;
+               return ret;
        }
        if (fp->fi_had_conflict) {
                WARN(1, "duplicate break on %p\n", fp);
-               return;
+               return ret;
        }
        /*
         * We don't want the locks code to timeout the lease for us;
@@ -3457,24 +3458,23 @@ static void nfsd_break_deleg_cb(struct file_lock *fl)
        spin_lock(&fp->fi_lock);
        fp->fi_had_conflict = true;
        /*
-        * If there are no delegations on the list, then we can't count on this
-        * lease ever being cleaned up. Set the fl_break_time to jiffies so that
-        * time_out_leases will do it ASAP. The fact that fi_had_conflict is now
-        * true should keep any new delegations from being hashed.
+        * If there are no delegations on the list, then return true
+        * so that the lease code will go ahead and delete it.
         */
        if (list_empty(&fp->fi_delegations))
-               fl->fl_break_time = jiffies;
+               ret = true;
        else
                list_for_each_entry(dp, &fp->fi_delegations, dl_perfile)
                        nfsd_break_one_deleg(dp);
        spin_unlock(&fp->fi_lock);
+       return ret;
 }
 
-static
-int nfsd_change_deleg_cb(struct file_lock **onlist, int arg)
+static int
+nfsd_change_deleg_cb(struct file_lock **onlist, int arg, struct list_head *dispose)
 {
        if (arg & F_UNLCK)
-               return lease_modify(onlist, arg);
+               return lease_modify(onlist, arg, dispose);
        else
                return -EAGAIN;
 }
@@ -3820,7 +3820,7 @@ static struct file_lock *nfs4_alloc_init_lease(struct nfs4_file *fp, int flag)
 static int nfs4_setlease(struct nfs4_delegation *dp)
 {
        struct nfs4_file *fp = dp->dl_stid.sc_file;
-       struct file_lock *fl;
+       struct file_lock *fl, *ret;
        struct file *filp;
        int status = 0;
 
@@ -3834,11 +3834,12 @@ static int nfs4_setlease(struct nfs4_delegation *dp)
                return -EBADF;
        }
        fl->fl_file = filp;
-       status = vfs_setlease(filp, fl->fl_type, &fl);
-       if (status) {
+       ret = fl;
+       status = vfs_setlease(filp, fl->fl_type, &fl, NULL);
+       if (fl)
                locks_free_lock(fl);
+       if (status)
                goto out_fput;
-       }
        spin_lock(&state_lock);
        spin_lock(&fp->fi_lock);
        /* Did the lease get broken before we took the lock? */
@@ -3846,13 +3847,12 @@ static int nfs4_setlease(struct nfs4_delegation *dp)
        if (fp->fi_had_conflict)
                goto out_unlock;
        /* Race breaker */
-       if (fp->fi_lease) {
+       if (fp->fi_deleg_file) {
                status = 0;
                atomic_inc(&fp->fi_delegees);
                hash_delegation_locked(dp, fp);
                goto out_unlock;
        }
-       fp->fi_lease = fl;
        fp->fi_deleg_file = filp;
        atomic_set(&fp->fi_delegees, 1);
        hash_delegation_locked(dp, fp);
@@ -3885,7 +3885,7 @@ nfs4_set_delegation(struct nfs4_client *clp, struct svc_fh *fh,
        spin_lock(&state_lock);
        spin_lock(&fp->fi_lock);
        dp->dl_stid.sc_file = fp;
-       if (!fp->fi_lease) {
+       if (!fp->fi_deleg_file) {
                spin_unlock(&fp->fi_lock);
                spin_unlock(&state_lock);
                status = nfs4_setlease(dp);
@@ -4929,9 +4929,25 @@ nfs4_transform_lock_offset(struct file_lock *lock)
                lock->fl_end = OFFSET_MAX;
 }
 
-/* Hack!: For now, we're defining this just so we can use a pointer to it
- * as a unique cookie to identify our (NFSv4's) posix locks. */
+static void nfsd4_fl_get_owner(struct file_lock *dst, struct file_lock *src)
+{
+       struct nfs4_lockowner *lo = (struct nfs4_lockowner *)src->fl_owner;
+       dst->fl_owner = (fl_owner_t)lockowner(nfs4_get_stateowner(&lo->lo_owner));
+}
+
+static void nfsd4_fl_put_owner(struct file_lock *fl)
+{
+       struct nfs4_lockowner *lo = (struct nfs4_lockowner *)fl->fl_owner;
+
+       if (lo) {
+               nfs4_put_stateowner(&lo->lo_owner);
+               fl->fl_owner = NULL;
+       }
+}
+
 static const struct lock_manager_operations nfsd_posix_mng_ops  = {
+       .lm_get_owner = nfsd4_fl_get_owner,
+       .lm_put_owner = nfsd4_fl_put_owner,
 };
 
 static inline void
@@ -4977,10 +4993,8 @@ find_lockowner_str_locked(clientid_t *clid, struct xdr_netobj *owner,
                            so_strhash) {
                if (so->so_is_open_owner)
                        continue;
-               if (!same_owner_str(so, owner))
-                       continue;
-               atomic_inc(&so->so_count);
-               return lockowner(so);
+               if (same_owner_str(so, owner))
+                       return lockowner(nfs4_get_stateowner(so));
        }
        return NULL;
 }
@@ -5059,8 +5073,7 @@ init_lock_stateid(struct nfs4_ol_stateid *stp, struct nfs4_lockowner *lo,
 
        atomic_inc(&stp->st_stid.sc_count);
        stp->st_stid.sc_type = NFS4_LOCK_STID;
-       stp->st_stateowner = &lo->lo_owner;
-       atomic_inc(&lo->lo_owner.so_count);
+       stp->st_stateowner = nfs4_get_stateowner(&lo->lo_owner);
        get_nfs4_file(fp);
        stp->st_stid.sc_file = fp;
        stp->st_stid.sc_free = nfs4_free_lock_stateid;
@@ -5299,7 +5312,8 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
                status = nfserr_openmode;
                goto out;
        }
-       file_lock->fl_owner = (fl_owner_t)lock_sop;
+
+       file_lock->fl_owner = (fl_owner_t)lockowner(nfs4_get_stateowner(&lock_sop->lo_owner));
        file_lock->fl_pid = current->tgid;
        file_lock->fl_file = filp;
        file_lock->fl_flags = FL_POSIX;
@@ -5495,7 +5509,7 @@ nfsd4_locku(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
        }
 
        file_lock->fl_type = F_UNLCK;
-       file_lock->fl_owner = (fl_owner_t)lockowner(stp->st_stateowner);
+       file_lock->fl_owner = (fl_owner_t)lockowner(nfs4_get_stateowner(stp->st_stateowner));
        file_lock->fl_pid = current->tgid;
        file_lock->fl_file = filp;
        file_lock->fl_flags = FL_POSIX;
@@ -5602,7 +5616,7 @@ nfsd4_release_lockowner(struct svc_rqst *rqstp,
                        }
                }
 
-               atomic_inc(&sop->so_count);
+               nfs4_get_stateowner(sop);
                break;
        }
        spin_unlock(&clp->cl_lock);
index 0a47c6a6b3015f7e4253fda96cef67c870ba9860..2712042a66b197937936811057bac63fa7a3f382 100644 (file)
@@ -486,7 +486,6 @@ struct nfs4_file {
        atomic_t                fi_access[2];
        u32                     fi_share_deny;
        struct file             *fi_deleg_file;
-       struct file_lock        *fi_lease;
        atomic_t                fi_delegees;
        struct knfsd_fh         fi_fhandle;
        bool                    fi_had_conflict;
index 965cffd17a0c9fb91f7162e619782b95f25575b8..989129e2d6eac69951abf3a6c1f4f9cae9fbb826 100644 (file)
@@ -721,7 +721,7 @@ nfsd_open(struct svc_rqst *rqstp, struct svc_fh *fhp, umode_t type,
                goto out_nfserr;
        }
 
-       host_err = ima_file_check(file, may_flags);
+       host_err = ima_file_check(file, may_flags, 0);
        if (host_err) {
                nfsd_close(file);
                goto out_nfserr;
index 24978153c0c4daefd04f2853576db34aa3e8e0fe..e9e3325f29f30cbe0c01c4433441803ff097df58 100644 (file)
@@ -56,11 +56,9 @@ int nilfs_sync_file(struct file *file, loff_t start, loff_t end, int datasync)
        mutex_unlock(&inode->i_mutex);
 
        nilfs = inode->i_sb->s_fs_info;
-       if (!err && nilfs_test_opt(nilfs, BARRIER)) {
-               err = blkdev_issue_flush(inode->i_sb->s_bdev, GFP_KERNEL, NULL);
-               if (err != -EIO)
-                       err = 0;
-       }
+       if (!err)
+               err = nilfs_flush_device(nilfs);
+
        return err;
 }
 
index d071e7f23de2a767929338309a5e5c73b5942f97..e1fa69b341b95e5ad970e92664b6a15dd8216e6d 100644 (file)
@@ -126,7 +126,7 @@ int nilfs_get_block(struct inode *inode, sector_t blkoff,
                        nilfs_transaction_abort(inode->i_sb);
                        goto out;
                }
-               nilfs_mark_inode_dirty(inode);
+               nilfs_mark_inode_dirty_sync(inode);
                nilfs_transaction_commit(inode->i_sb); /* never fails */
                /* Error handling should be detailed */
                set_buffer_new(bh_result);
@@ -672,7 +672,7 @@ void nilfs_write_inode_common(struct inode *inode,
           for substitutions of appended fields */
 }
 
-void nilfs_update_inode(struct inode *inode, struct buffer_head *ibh)
+void nilfs_update_inode(struct inode *inode, struct buffer_head *ibh, int flags)
 {
        ino_t ino = inode->i_ino;
        struct nilfs_inode_info *ii = NILFS_I(inode);
@@ -683,7 +683,8 @@ void nilfs_update_inode(struct inode *inode, struct buffer_head *ibh)
 
        if (test_and_clear_bit(NILFS_I_NEW, &ii->i_state))
                memset(raw_inode, 0, NILFS_MDT(ifile)->mi_entry_size);
-       set_bit(NILFS_I_INODE_DIRTY, &ii->i_state);
+       if (flags & I_DIRTY_DATASYNC)
+               set_bit(NILFS_I_INODE_SYNC, &ii->i_state);
 
        nilfs_write_inode_common(inode, raw_inode, 0);
                /* XXX: call with has_bmap = 0 is a workaround to avoid
@@ -939,7 +940,7 @@ int nilfs_set_file_dirty(struct inode *inode, unsigned nr_dirty)
        return 0;
 }
 
-int nilfs_mark_inode_dirty(struct inode *inode)
+int __nilfs_mark_inode_dirty(struct inode *inode, int flags)
 {
        struct buffer_head *ibh;
        int err;
@@ -950,7 +951,7 @@ int nilfs_mark_inode_dirty(struct inode *inode)
                              "failed to reget inode block.\n");
                return err;
        }
-       nilfs_update_inode(inode, ibh);
+       nilfs_update_inode(inode, ibh, flags);
        mark_buffer_dirty(ibh);
        nilfs_mdt_mark_dirty(NILFS_I(inode)->i_root->ifile);
        brelse(ibh);
@@ -983,7 +984,7 @@ void nilfs_dirty_inode(struct inode *inode, int flags)
                return;
        }
        nilfs_transaction_begin(inode->i_sb, &ti, 0);
-       nilfs_mark_inode_dirty(inode);
+       __nilfs_mark_inode_dirty(inode, flags);
        nilfs_transaction_commit(inode->i_sb); /* never fails */
 }
 
index 422fb54b73771f04690e16726f9a85a74c4febfd..9a20e513d7eb89ee21228e6af0a723996c4150a5 100644 (file)
@@ -1022,11 +1022,9 @@ static int nilfs_ioctl_sync(struct inode *inode, struct file *filp,
                return ret;
 
        nilfs = inode->i_sb->s_fs_info;
-       if (nilfs_test_opt(nilfs, BARRIER)) {
-               ret = blkdev_issue_flush(inode->i_sb->s_bdev, GFP_KERNEL, NULL);
-               if (ret == -EIO)
-                       return ret;
-       }
+       ret = nilfs_flush_device(nilfs);
+       if (ret < 0)
+               return ret;
 
        if (argp != NULL) {
                down_read(&nilfs->ns_segctor_sem);
index 0696161bf59d24cb8471491c2a38c852e0594934..91093cd74f0da15e7f972d9c695f221e5afb454d 100644 (file)
@@ -104,7 +104,7 @@ enum {
                                           constructor */
        NILFS_I_COLLECTED,              /* All dirty blocks are collected */
        NILFS_I_UPDATED,                /* The file has been written back */
-       NILFS_I_INODE_DIRTY,            /* write_inode is requested */
+       NILFS_I_INODE_SYNC,             /* dsync is not allowed for inode */
        NILFS_I_BMAP,                   /* has bmap and btnode_cache */
        NILFS_I_GCINODE,                /* inode for GC, on memory only */
 };
@@ -273,7 +273,7 @@ struct inode *nilfs_iget(struct super_block *sb, struct nilfs_root *root,
                         unsigned long ino);
 extern struct inode *nilfs_iget_for_gc(struct super_block *sb,
                                       unsigned long ino, __u64 cno);
-extern void nilfs_update_inode(struct inode *, struct buffer_head *);
+extern void nilfs_update_inode(struct inode *, struct buffer_head *, int);
 extern void nilfs_truncate(struct inode *);
 extern void nilfs_evict_inode(struct inode *);
 extern int nilfs_setattr(struct dentry *, struct iattr *);
@@ -282,10 +282,18 @@ int nilfs_permission(struct inode *inode, int mask);
 int nilfs_load_inode_block(struct inode *inode, struct buffer_head **pbh);
 extern int nilfs_inode_dirty(struct inode *);
 int nilfs_set_file_dirty(struct inode *inode, unsigned nr_dirty);
-extern int nilfs_mark_inode_dirty(struct inode *);
+extern int __nilfs_mark_inode_dirty(struct inode *, int);
 extern void nilfs_dirty_inode(struct inode *, int flags);
 int nilfs_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
                 __u64 start, __u64 len);
+static inline int nilfs_mark_inode_dirty(struct inode *inode)
+{
+       return __nilfs_mark_inode_dirty(inode, I_DIRTY);
+}
+static inline int nilfs_mark_inode_dirty_sync(struct inode *inode)
+{
+       return __nilfs_mark_inode_dirty(inode, I_DIRTY_SYNC);
+}
 
 /* super.c */
 extern struct inode *nilfs_alloc_inode(struct super_block *);
index a1a191634abc1729f94a443ab4eac4cdddaaf54c..7ef18fc656c28568047c30c24adb0bc029bada5c 100644 (file)
@@ -930,7 +930,7 @@ static void nilfs_drop_collected_inodes(struct list_head *head)
                if (!test_and_clear_bit(NILFS_I_COLLECTED, &ii->i_state))
                        continue;
 
-               clear_bit(NILFS_I_INODE_DIRTY, &ii->i_state);
+               clear_bit(NILFS_I_INODE_SYNC, &ii->i_state);
                set_bit(NILFS_I_UPDATED, &ii->i_state);
        }
 }
@@ -1833,6 +1833,7 @@ static void nilfs_segctor_complete_write(struct nilfs_sc_info *sci)
        nilfs_set_next_segment(nilfs, segbuf);
 
        if (update_sr) {
+               nilfs->ns_flushed_device = 0;
                nilfs_set_last_segment(nilfs, segbuf->sb_pseg_start,
                                       segbuf->sb_sum.seg_seq, nilfs->ns_cno++);
 
@@ -2194,7 +2195,7 @@ int nilfs_construct_dsync_segment(struct super_block *sb, struct inode *inode,
        nilfs_transaction_lock(sb, &ti, 0);
 
        ii = NILFS_I(inode);
-       if (test_bit(NILFS_I_INODE_DIRTY, &ii->i_state) ||
+       if (test_bit(NILFS_I_INODE_SYNC, &ii->i_state) ||
            nilfs_test_opt(nilfs, STRICT_ORDER) ||
            test_bit(NILFS_SC_UNCLOSED, &sci->sc_flags) ||
            nilfs_discontinued(nilfs)) {
@@ -2216,6 +2217,8 @@ int nilfs_construct_dsync_segment(struct super_block *sb, struct inode *inode,
        sci->sc_dsync_end = end;
 
        err = nilfs_segctor_do_construct(sci, SC_LSEG_DSYNC);
+       if (!err)
+               nilfs->ns_flushed_device = 0;
 
        nilfs_transaction_unlock(sb);
        return err;
index 228f5bdf07721dabae68349461eb1f24f99a2f33..2e5b3ec85b8f62c967e785697449c773fe0e1337 100644 (file)
@@ -310,6 +310,9 @@ int nilfs_commit_super(struct super_block *sb, int flag)
                                            nilfs->ns_sbsize));
        }
        clear_nilfs_sb_dirty(nilfs);
+       nilfs->ns_flushed_device = 1;
+       /* make sure store to ns_flushed_device cannot be reordered */
+       smp_wmb();
        return nilfs_sync_super(sb, flag);
 }
 
@@ -514,6 +517,9 @@ static int nilfs_sync_fs(struct super_block *sb, int wait)
        }
        up_write(&nilfs->ns_sem);
 
+       if (!err)
+               err = nilfs_flush_device(nilfs);
+
        return err;
 }
 
index d01ead1bea9a738a5268908fe321eed19af3cc07..23778d385836f56c9cad3be7aa3cdaca2e7c1e69 100644 (file)
@@ -46,6 +46,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_bdev: block device
  * @ns_sem: semaphore for shared states
  * @ns_snapshot_mount_mutex: mutex to protect snapshot mounts
@@ -103,6 +104,7 @@ enum {
  */
 struct the_nilfs {
        unsigned long           ns_flags;
+       int                     ns_flushed_device;
 
        struct block_device    *ns_bdev;
        struct rw_semaphore     ns_sem;
@@ -371,4 +373,24 @@ static inline int nilfs_segment_is_active(struct the_nilfs *nilfs, __u64 n)
        return n == nilfs->ns_segnum || n == nilfs->ns_nextnum;
 }
 
+static inline int nilfs_flush_device(struct the_nilfs *nilfs)
+{
+       int err;
+
+       if (!nilfs_test_opt(nilfs, BARRIER) || nilfs->ns_flushed_device)
+               return 0;
+
+       nilfs->ns_flushed_device = 1;
+       /*
+        * the store to ns_flushed_device must not be reordered after
+        * blkdev_issue_flush().
+        */
+       smp_wmb();
+
+       err = blkdev_issue_flush(nilfs->ns_bdev, GFP_KERNEL, NULL);
+       if (err != -EIO)
+               err = 0;
+       return err;
+}
+
 #endif /* _THE_NILFS_H */
index abc8cbcfe90e0fca9f67471740c0b41c9055b7c6..caaaf9dfe3534be9e29826e46058151b5536c48e 100644 (file)
@@ -346,13 +346,7 @@ int fcntl_dirnotify(int fd, struct file *filp, unsigned long arg)
                goto out;
        }
 
-       error = __f_setown(filp, task_pid(current), PIDTYPE_PID, 0);
-       if (error) {
-               /* if we added, we must shoot */
-               if (dn_mark == new_dn_mark)
-                       destroy = 1;
-               goto out;
-       }
+       __f_setown(filp, task_pid(current), PIDTYPE_PID, 0);
 
        error = attach_dn(dn, dn_mark, id, fd, filp, mask);
        /* !error means that we attached the dn to the dn_mark, so don't free it */
index d1338544816896dc773fc930b43dc44bcc157266..eb9d48746ab4008acc1a529c37a15ca98a00c882 100644 (file)
@@ -2244,7 +2244,7 @@ ssize_t o2hb_heartbeat_group_mode_store(struct o2hb_heartbeat_group *group,
                return -EINVAL;
 
        for (i = 0; i < O2HB_HEARTBEAT_NUM_MODES; ++i) {
-               if (strnicmp(page, o2hb_heartbeat_mode_desc[i], len))
+               if (strncasecmp(page, o2hb_heartbeat_mode_desc[i], len))
                        continue;
 
                ret = o2hb_global_heartbeat_mode_set(i);
index 07ac24fd92520f604f6d3cfeff4cd4bd2c6ad85c..af7598bff1b51364affd08eba9cfedba8b3acf16 100644 (file)
@@ -49,13 +49,13 @@ static ssize_t mlog_mask_show(u64 mask, char *buf)
 
 static ssize_t mlog_mask_store(u64 mask, const char *buf, size_t count)
 {
-       if (!strnicmp(buf, "allow", 5)) {
+       if (!strncasecmp(buf, "allow", 5)) {
                __mlog_set_u64(mask, mlog_and_bits);
                __mlog_clear_u64(mask, mlog_not_bits);
-       } else if (!strnicmp(buf, "deny", 4)) {
+       } else if (!strncasecmp(buf, "deny", 4)) {
                __mlog_set_u64(mask, mlog_not_bits);
                __mlog_clear_u64(mask, mlog_and_bits);
-       } else if (!strnicmp(buf, "off", 3)) {
+       } else if (!strncasecmp(buf, "off", 3)) {
                __mlog_clear_u64(mask, mlog_not_bits);
                __mlog_clear_u64(mask, mlog_and_bits);
        } else
index 682732f3f0d8fcb4b7fd8a7e96ebbab3d9e706ba..324dc93ac896c073886846e0d883d1d8f5bd30ca 100644 (file)
@@ -1252,7 +1252,7 @@ bail:
        brelse(bh);
 
        /* Release quota pointers in case we acquired them */
-       for (qtype = 0; qtype < MAXQUOTAS; qtype++)
+       for (qtype = 0; qtype < OCFS2_MAXQUOTAS; qtype++)
                dqput(transfer_to[qtype]);
 
        if (!status && attr->ia_valid & ATTR_MODE) {
index f266d67df3c6e07427942b5c2c61780e2e81220b..1eae330193a63f7a212c475f8df4a42701d28dc3 100644 (file)
@@ -17,6 +17,9 @@
 
 #include "ocfs2.h"
 
+/* Number of quota types we support */
+#define OCFS2_MAXQUOTAS 2
+
 /*
  * In-memory structures
  */
@@ -39,7 +42,7 @@ struct ocfs2_recovery_chunk {
 };
 
 struct ocfs2_quota_recovery {
-       struct list_head r_list[MAXQUOTAS];     /* List of chunks to recover */
+       struct list_head r_list[OCFS2_MAXQUOTAS];       /* List of chunks to recover */
 };
 
 /* In-memory structure with quota header information */
index b990a62cff50c4b6d3bd18f6a5ecede3fe14d440..c93d6722088753901c258151de82dc707e6eb71e 100644 (file)
@@ -336,8 +336,8 @@ void ocfs2_unlock_global_qf(struct ocfs2_mem_dqinfo *oinfo, int ex)
 int ocfs2_global_read_info(struct super_block *sb, int type)
 {
        struct inode *gqinode = NULL;
-       unsigned int ino[MAXQUOTAS] = { USER_QUOTA_SYSTEM_INODE,
-                                       GROUP_QUOTA_SYSTEM_INODE };
+       unsigned int ino[OCFS2_MAXQUOTAS] = { USER_QUOTA_SYSTEM_INODE,
+                                             GROUP_QUOTA_SYSTEM_INODE };
        struct ocfs2_global_disk_dqinfo dinfo;
        struct mem_dqinfo *info = sb_dqinfo(sb, type);
        struct ocfs2_mem_dqinfo *oinfo = info->dqi_priv;
index 2001862bf2b1cfbb20ed78bd9febeacbc96b42a4..10b653930ee26aa97320e827d01499e19ffe2b16 100644 (file)
@@ -166,12 +166,12 @@ static int ocfs2_read_quota_block(struct inode *inode, u64 v_block,
 /* Check whether we understand format of quota files */
 static int ocfs2_local_check_quota_file(struct super_block *sb, int type)
 {
-       unsigned int lmagics[MAXQUOTAS] = OCFS2_LOCAL_QMAGICS;
-       unsigned int lversions[MAXQUOTAS] = OCFS2_LOCAL_QVERSIONS;
-       unsigned int gmagics[MAXQUOTAS] = OCFS2_GLOBAL_QMAGICS;
-       unsigned int gversions[MAXQUOTAS] = OCFS2_GLOBAL_QVERSIONS;
-       unsigned int ino[MAXQUOTAS] = { USER_QUOTA_SYSTEM_INODE,
-                                       GROUP_QUOTA_SYSTEM_INODE };
+       unsigned int lmagics[OCFS2_MAXQUOTAS] = OCFS2_LOCAL_QMAGICS;
+       unsigned int lversions[OCFS2_MAXQUOTAS] = OCFS2_LOCAL_QVERSIONS;
+       unsigned int gmagics[OCFS2_MAXQUOTAS] = OCFS2_GLOBAL_QMAGICS;
+       unsigned int gversions[OCFS2_MAXQUOTAS] = OCFS2_GLOBAL_QVERSIONS;
+       unsigned int ino[OCFS2_MAXQUOTAS] = { USER_QUOTA_SYSTEM_INODE,
+                                             GROUP_QUOTA_SYSTEM_INODE };
        struct buffer_head *bh = NULL;
        struct inode *linode = sb_dqopt(sb)->files[type];
        struct inode *ginode = NULL;
@@ -336,7 +336,7 @@ void ocfs2_free_quota_recovery(struct ocfs2_quota_recovery *rec)
 {
        int type;
 
-       for (type = 0; type < MAXQUOTAS; type++)
+       for (type = 0; type < OCFS2_MAXQUOTAS; type++)
                free_recovery_list(&(rec->r_list[type]));
        kfree(rec);
 }
@@ -382,7 +382,7 @@ static struct ocfs2_quota_recovery *ocfs2_alloc_quota_recovery(void)
        rec = kmalloc(sizeof(struct ocfs2_quota_recovery), GFP_NOFS);
        if (!rec)
                return NULL;
-       for (type = 0; type < MAXQUOTAS; type++)
+       for (type = 0; type < OCFS2_MAXQUOTAS; type++)
                INIT_LIST_HEAD(&(rec->r_list[type]));
        return rec;
 }
@@ -392,10 +392,11 @@ struct ocfs2_quota_recovery *ocfs2_begin_quota_recovery(
                                                struct ocfs2_super *osb,
                                                int slot_num)
 {
-       unsigned int feature[MAXQUOTAS] = { OCFS2_FEATURE_RO_COMPAT_USRQUOTA,
-                                           OCFS2_FEATURE_RO_COMPAT_GRPQUOTA};
-       unsigned int ino[MAXQUOTAS] = { LOCAL_USER_QUOTA_SYSTEM_INODE,
-                                       LOCAL_GROUP_QUOTA_SYSTEM_INODE };
+       unsigned int feature[OCFS2_MAXQUOTAS] = {
+                                       OCFS2_FEATURE_RO_COMPAT_USRQUOTA,
+                                       OCFS2_FEATURE_RO_COMPAT_GRPQUOTA};
+       unsigned int ino[OCFS2_MAXQUOTAS] = { LOCAL_USER_QUOTA_SYSTEM_INODE,
+                                             LOCAL_GROUP_QUOTA_SYSTEM_INODE };
        struct super_block *sb = osb->sb;
        struct ocfs2_local_disk_dqinfo *ldinfo;
        struct inode *lqinode;
@@ -412,7 +413,7 @@ struct ocfs2_quota_recovery *ocfs2_begin_quota_recovery(
                return ERR_PTR(-ENOMEM);
        /* First init... */
 
-       for (type = 0; type < MAXQUOTAS; type++) {
+       for (type = 0; type < OCFS2_MAXQUOTAS; type++) {
                if (!OCFS2_HAS_RO_COMPAT_FEATURE(sb, feature[type]))
                        continue;
                /* At this point, journal of the slot is already replayed so
@@ -589,8 +590,8 @@ int ocfs2_finish_quota_recovery(struct ocfs2_super *osb,
                                struct ocfs2_quota_recovery *rec,
                                int slot_num)
 {
-       unsigned int ino[MAXQUOTAS] = { LOCAL_USER_QUOTA_SYSTEM_INODE,
-                                       LOCAL_GROUP_QUOTA_SYSTEM_INODE };
+       unsigned int ino[OCFS2_MAXQUOTAS] = { LOCAL_USER_QUOTA_SYSTEM_INODE,
+                                             LOCAL_GROUP_QUOTA_SYSTEM_INODE };
        struct super_block *sb = osb->sb;
        struct ocfs2_local_disk_dqinfo *ldinfo;
        struct buffer_head *bh;
@@ -604,7 +605,7 @@ int ocfs2_finish_quota_recovery(struct ocfs2_super *osb,
               "slot %u\n", osb->dev_str, slot_num);
 
        mutex_lock(&sb_dqopt(sb)->dqonoff_mutex);
-       for (type = 0; type < MAXQUOTAS; type++) {
+       for (type = 0; type < OCFS2_MAXQUOTAS; type++) {
                if (list_empty(&(rec->r_list[type])))
                        continue;
                trace_ocfs2_finish_quota_recovery(slot_num);
index 4142546aedae95e668487b9ba8069be1ec929227..93c85bc745e199983550b2e181b757e151cec8d5 100644 (file)
@@ -899,11 +899,12 @@ static int ocfs2_susp_quotas(struct ocfs2_super *osb, int unsuspend)
 {
        int type;
        struct super_block *sb = osb->sb;
-       unsigned int feature[MAXQUOTAS] = { OCFS2_FEATURE_RO_COMPAT_USRQUOTA,
-                                            OCFS2_FEATURE_RO_COMPAT_GRPQUOTA};
+       unsigned int feature[OCFS2_MAXQUOTAS] = {
+                                       OCFS2_FEATURE_RO_COMPAT_USRQUOTA,
+                                       OCFS2_FEATURE_RO_COMPAT_GRPQUOTA};
        int status = 0;
 
-       for (type = 0; type < MAXQUOTAS; type++) {
+       for (type = 0; type < OCFS2_MAXQUOTAS; type++) {
                if (!OCFS2_HAS_RO_COMPAT_FEATURE(sb, feature[type]))
                        continue;
                if (unsuspend)
@@ -927,17 +928,19 @@ static int ocfs2_susp_quotas(struct ocfs2_super *osb, int unsuspend)
 
 static int ocfs2_enable_quotas(struct ocfs2_super *osb)
 {
-       struct inode *inode[MAXQUOTAS] = { NULL, NULL };
+       struct inode *inode[OCFS2_MAXQUOTAS] = { NULL, NULL };
        struct super_block *sb = osb->sb;
-       unsigned int feature[MAXQUOTAS] = { OCFS2_FEATURE_RO_COMPAT_USRQUOTA,
-                                            OCFS2_FEATURE_RO_COMPAT_GRPQUOTA};
-       unsigned int ino[MAXQUOTAS] = { LOCAL_USER_QUOTA_SYSTEM_INODE,
+       unsigned int feature[OCFS2_MAXQUOTAS] = {
+                                       OCFS2_FEATURE_RO_COMPAT_USRQUOTA,
+                                       OCFS2_FEATURE_RO_COMPAT_GRPQUOTA};
+       unsigned int ino[OCFS2_MAXQUOTAS] = {
+                                       LOCAL_USER_QUOTA_SYSTEM_INODE,
                                        LOCAL_GROUP_QUOTA_SYSTEM_INODE };
        int status;
        int type;
 
        sb_dqopt(sb)->flags |= DQUOT_QUOTA_SYS_FILE | DQUOT_NEGATIVE_USAGE;
-       for (type = 0; type < MAXQUOTAS; type++) {
+       for (type = 0; type < OCFS2_MAXQUOTAS; type++) {
                if (!OCFS2_HAS_RO_COMPAT_FEATURE(sb, feature[type]))
                        continue;
                inode[type] = ocfs2_get_system_file_inode(osb, ino[type],
@@ -952,12 +955,12 @@ static int ocfs2_enable_quotas(struct ocfs2_super *osb)
                        goto out_quota_off;
        }
 
-       for (type = 0; type < MAXQUOTAS; type++)
+       for (type = 0; type < OCFS2_MAXQUOTAS; type++)
                iput(inode[type]);
        return 0;
 out_quota_off:
        ocfs2_disable_quotas(osb);
-       for (type = 0; type < MAXQUOTAS; type++)
+       for (type = 0; type < OCFS2_MAXQUOTAS; type++)
                iput(inode[type]);
        mlog_errno(status);
        return status;
@@ -972,7 +975,7 @@ static void ocfs2_disable_quotas(struct ocfs2_super *osb)
 
        /* We mostly ignore errors in this function because there's not much
         * we can do when we see them */
-       for (type = 0; type < MAXQUOTAS; type++) {
+       for (type = 0; type < OCFS2_MAXQUOTAS; type++) {
                if (!sb_has_quota_loaded(sb, type))
                        continue;
                /* Cancel periodic syncing before we grab dqonoff_mutex */
@@ -993,8 +996,9 @@ static void ocfs2_disable_quotas(struct ocfs2_super *osb)
 /* Handle quota on quotactl */
 static int ocfs2_quota_on(struct super_block *sb, int type, int format_id)
 {
-       unsigned int feature[MAXQUOTAS] = { OCFS2_FEATURE_RO_COMPAT_USRQUOTA,
-                                            OCFS2_FEATURE_RO_COMPAT_GRPQUOTA};
+       unsigned int feature[OCFS2_MAXQUOTAS] = {
+                                       OCFS2_FEATURE_RO_COMPAT_USRQUOTA,
+                                       OCFS2_FEATURE_RO_COMPAT_GRPQUOTA};
 
        if (!OCFS2_HAS_RO_COMPAT_FEATURE(sb, feature[type]))
                return -EINVAL;
index ba8819702c56719ae8a1a7b4596662a653a6ef0b..138321b0c6c2b95a8efcef1a5b3183f3126acbb9 100644 (file)
@@ -306,9 +306,7 @@ static const struct super_operations omfs_sops = {
  */
 static int omfs_get_imap(struct super_block *sb)
 {
-       int bitmap_size;
-       int array_size;
-       int count;
+       unsigned int bitmap_size, count, array_size;
        struct omfs_sb_info *sbi = OMFS_SB(sb);
        struct buffer_head *bh;
        unsigned long **ptr;
@@ -473,6 +471,12 @@ static int omfs_fill_super(struct super_block *sb, void *data, int silent)
        sbi->s_sys_blocksize = be32_to_cpu(omfs_sb->s_sys_blocksize);
        mutex_init(&sbi->s_bitmap_lock);
 
+       if (sbi->s_num_blocks > OMFS_MAX_BLOCKS) {
+               printk(KERN_ERR "omfs: sysblock number (%llx) is out of range\n",
+                      (unsigned long long)sbi->s_num_blocks);
+               goto out_brelse_bh;
+       }
+
        if (sbi->s_sys_blocksize > PAGE_SIZE) {
                printk(KERN_ERR "omfs: sysblock size (%d) is out of range\n",
                        sbi->s_sys_blocksize);
index ee5e4327de92cc5e487e36dbbc8647f77702155d..83a98330ed6602d7a5ffe03e7f5598a201e6ecf7 100644 (file)
@@ -18,6 +18,7 @@
 #define OMFS_XOR_COUNT 19
 #define OMFS_MAX_BLOCK_SIZE 8192
 #define OMFS_MAX_CLUSTER_SIZE 8
+#define OMFS_MAX_BLOCKS (1ul << 31)
 
 struct omfs_super_block {
        char s_fill1[256];
index 950100e326a10d2d4819e6e031ac0f7cea4c0258..772efa45a452c75a912ec67641d06bee4cfde4bf 100644 (file)
@@ -1565,7 +1565,6 @@ int pid_revalidate(struct dentry *dentry, unsigned int flags)
                put_task_struct(task);
                return 1;
        }
-       d_drop(dentry);
        return 0;
 }
 
@@ -1702,9 +1701,6 @@ out:
        put_task_struct(task);
 
 out_notask:
-       if (status <= 0)
-               d_drop(dentry);
-
        return status;
 }
 
@@ -2618,8 +2614,7 @@ static void proc_flush_task_mnt(struct vfsmount *mnt, pid_t pid, pid_t tgid)
        /* no ->d_hash() rejects on procfs */
        dentry = d_hash_and_lookup(mnt->mnt_root, &name);
        if (dentry) {
-               shrink_dcache_parent(dentry);
-               d_drop(dentry);
+               d_invalidate(dentry);
                dput(dentry);
        }
 
@@ -2639,8 +2634,7 @@ static void proc_flush_task_mnt(struct vfsmount *mnt, pid_t pid, pid_t tgid)
        name.len = snprintf(buf, sizeof(buf), "%d", pid);
        dentry = d_hash_and_lookup(dir, &name);
        if (dentry) {
-               shrink_dcache_parent(dentry);
-               d_drop(dentry);
+               d_invalidate(dentry);
                dput(dentry);
        }
 
index 955bb55fab8cad3fbdfbd8e69f5536e6c2e53593..e11d7c590bb0bdee4004f84f21423a4e6e6693c3 100644 (file)
@@ -129,8 +129,6 @@ static int tid_fd_revalidate(struct dentry *dentry, unsigned int flags)
                }
                put_task_struct(task);
        }
-
-       d_drop(dentry);
        return 0;
 }
 
index b7a7dc963a359229ee7607a8d32b9c28221810bf..4e0388cffe3db3f7ee88b9ab812d89c056d8c60b 100644 (file)
@@ -827,8 +827,21 @@ static ssize_t clear_refs_write(struct file *file, const char __user *buf,
                        .private = &cp,
                };
                down_read(&mm->mmap_sem);
-               if (type == CLEAR_REFS_SOFT_DIRTY)
+               if (type == CLEAR_REFS_SOFT_DIRTY) {
+                       for (vma = mm->mmap; vma; vma = vma->vm_next) {
+                               if (!(vma->vm_flags & VM_SOFTDIRTY))
+                                       continue;
+                               up_read(&mm->mmap_sem);
+                               down_write(&mm->mmap_sem);
+                               for (vma = mm->mmap; vma; vma = vma->vm_next) {
+                                       vma->vm_flags &= ~VM_SOFTDIRTY;
+                                       vma_set_page_prot(vma);
+                               }
+                               downgrade_write(&mm->mmap_sem);
+                               break;
+                       }
                        mmu_notifier_invalidate_range_start(mm, 0, -1);
+               }
                for (vma = mm->mmap; vma; vma = vma->vm_next) {
                        cp.vma = vma;
                        if (is_vm_hugetlb_page(vma))
@@ -848,10 +861,6 @@ static ssize_t clear_refs_write(struct file *file, const char __user *buf,
                                continue;
                        if (type == CLEAR_REFS_MAPPED && !vma->vm_file)
                                continue;
-                       if (type == CLEAR_REFS_SOFT_DIRTY) {
-                               if (vma->vm_flags & VM_SOFTDIRTY)
-                                       vma->vm_flags &= ~VM_SOFTDIRTY;
-                       }
                        walk_page_range(vma->vm_start, vma->vm_end,
                                        &clear_refs_walk);
                }
index 009d8542a889c7d2b4b98334f0c4868d36076739..7d9318c3d43c70bc16f8939b04e7dfd75389971e 100644 (file)
@@ -513,6 +513,8 @@ ssize_t __kernel_write(struct file *file, const char *buf, size_t count, loff_t
        return ret;
 }
 
+EXPORT_SYMBOL(__kernel_write);
+
 ssize_t vfs_write(struct file *file, const char __user *buf, size_t count, loff_t *pos)
 {
        ssize_t ret;
index a88b1b3e7db3e4f4f5c514062586dbf7a62fa21e..d571e173a9909110ae00452e87ae307cbfbc7730 100644 (file)
@@ -699,11 +699,13 @@ static int add_to_chunk(struct buffer_chunk *chunk, struct buffer_head *bh,
        chunk->bh[chunk->nr++] = bh;
        if (chunk->nr >= CHUNK_SIZE) {
                ret = 1;
-               if (lock)
+               if (lock) {
                        spin_unlock(lock);
-               fn(chunk);
-               if (lock)
+                       fn(chunk);
                        spin_lock(lock);
+               } else {
+                       fn(chunk);
+               }
        }
        return ret;
 }
index 735c2c2b4536b0546e728b38cf663e310b3ac45c..1894d96ccb7c936b4cbe753564c01d3589a125a7 100644 (file)
@@ -506,6 +506,9 @@ typedef struct reiserfs_proc_info_data {
 } reiserfs_proc_info_data_t;
 #endif
 
+/* Number of quota types we support */
+#define REISERFS_MAXQUOTAS 2
+
 /* reiserfs union of in-core super block data */
 struct reiserfs_sb_info {
        /* Buffer containing the super block */
@@ -615,7 +618,7 @@ struct reiserfs_sb_info {
        spinlock_t old_work_lock;     /* protects old_work and work_queued */
 
 #ifdef CONFIG_QUOTA
-       char *s_qf_names[MAXQUOTAS];
+       char *s_qf_names[REISERFS_MAXQUOTAS];
        int s_jquota_fmt;
 #endif
        char *s_jdev;           /* Stored jdev for mount option showing */
index d46e88a33b02451d2cffc955a64c6752fab7c2cd..f1376c92cf74c422aeb9331e2290e5fec88635fb 100644 (file)
@@ -206,7 +206,7 @@ static int finish_unfinished(struct super_block *s)
 #ifdef CONFIG_QUOTA
        int i;
        int ms_active_set;
-       int quota_enabled[MAXQUOTAS];
+       int quota_enabled[REISERFS_MAXQUOTAS];
 #endif
 
        /* compose key to look for "save" links */
@@ -227,7 +227,7 @@ static int finish_unfinished(struct super_block *s)
                s->s_flags |= MS_ACTIVE;
        }
        /* Turn on quotas so that they are updated correctly */
-       for (i = 0; i < MAXQUOTAS; i++) {
+       for (i = 0; i < REISERFS_MAXQUOTAS; i++) {
                quota_enabled[i] = 1;
                if (REISERFS_SB(s)->s_qf_names[i]) {
                        int ret;
@@ -370,7 +370,7 @@ static int finish_unfinished(struct super_block *s)
 #ifdef CONFIG_QUOTA
        /* Turn quotas off */
        reiserfs_write_unlock(s);
-       for (i = 0; i < MAXQUOTAS; i++) {
+       for (i = 0; i < REISERFS_MAXQUOTAS; i++) {
                if (sb_dqopt(s)->files[i] && quota_enabled[i])
                        dquot_quota_off(s, i);
        }
@@ -1360,7 +1360,7 @@ static void handle_quota_files(struct super_block *s, char **qf_names,
 {
        int i;
 
-       for (i = 0; i < MAXQUOTAS; i++) {
+       for (i = 0; i < REISERFS_MAXQUOTAS; i++) {
                if (qf_names[i] != REISERFS_SB(s)->s_qf_names[i])
                        kfree(REISERFS_SB(s)->s_qf_names[i]);
                REISERFS_SB(s)->s_qf_names[i] = qf_names[i];
@@ -1381,7 +1381,7 @@ static int reiserfs_remount(struct super_block *s, int *mount_flags, char *arg)
        struct reiserfs_journal *journal = SB_JOURNAL(s);
        char *new_opts = kstrdup(arg, GFP_KERNEL);
        int err;
-       char *qf_names[MAXQUOTAS];
+       char *qf_names[REISERFS_MAXQUOTAS];
        unsigned int qfmt = 0;
 #ifdef CONFIG_QUOTA
        int i;
@@ -1400,7 +1400,7 @@ static int reiserfs_remount(struct super_block *s, int *mount_flags, char *arg)
            (s, arg, &mount_options, &blocks, NULL, &commit_max_age,
            qf_names, &qfmt)) {
 #ifdef CONFIG_QUOTA
-               for (i = 0; i < MAXQUOTAS; i++)
+               for (i = 0; i < REISERFS_MAXQUOTAS; i++)
                        if (qf_names[i] != REISERFS_SB(s)->s_qf_names[i])
                                kfree(qf_names[i]);
 #endif
@@ -1844,7 +1844,7 @@ static int reiserfs_fill_super(struct super_block *s, void *data, int silent)
        char *jdev_name;
        struct reiserfs_sb_info *sbi;
        int errval = -EINVAL;
-       char *qf_names[MAXQUOTAS] = {};
+       char *qf_names[REISERFS_MAXQUOTAS] = {};
        unsigned int qfmt = 0;
 
        save_mount_options(s, data);
@@ -2169,7 +2169,7 @@ error_unlocked:
 #ifdef CONFIG_QUOTA
        {
                int j;
-               for (j = 0; j < MAXQUOTAS; j++)
+               for (j = 0; j < REISERFS_MAXQUOTAS; j++)
                        kfree(qf_names[j]);
        }
 #endif
index 857ec7e3016f55e12267b7a409e240d888757525..f620e9678dd541a3786d031f9774583693f15341 100644 (file)
@@ -7,7 +7,6 @@ struct inode;
 struct dentry;
 struct iattr;
 struct super_block;
-struct nameidata;
 
 int reiserfs_xattr_register_handlers(void) __init;
 void reiserfs_xattr_unregister_handlers(void);
index 1b836107aceee1f01303bb27ba381d8c38c06163..eae088f6aaaeb6e8a3380adad19fb66feebe9905 100644 (file)
@@ -80,6 +80,8 @@ static unsigned long super_cache_scan(struct shrinker *shrink,
        inodes = list_lru_count_node(&sb->s_inode_lru, sc->nid);
        dentries = list_lru_count_node(&sb->s_dentry_lru, sc->nid);
        total_objects = dentries + inodes + fs_objects + 1;
+       if (!total_objects)
+               total_objects = 1;
 
        /* proportion the scan between the caches */
        dentries = mult_frac(sc->nr_to_scan, dentries, total_objects);
index aa13ad053b14075b8b5a9b0b62067ab0b9904c2d..26b69b2d4a452488405f7ccbc2a4f179c1961bbf 100644 (file)
@@ -164,10 +164,6 @@ static int do_commit(struct ubifs_info *c)
        if (err)
                goto out;
        err = ubifs_orphan_end_commit(c);
-       if (err)
-               goto out;
-       old_ltail_lnum = c->ltail_lnum;
-       err = ubifs_log_end_commit(c, new_ltail_lnum);
        if (err)
                goto out;
        err = dbg_check_old_index(c, &zroot);
@@ -202,7 +198,9 @@ static int do_commit(struct ubifs_info *c)
                c->mst_node->flags |= cpu_to_le32(UBIFS_MST_NO_ORPHS);
        else
                c->mst_node->flags &= ~cpu_to_le32(UBIFS_MST_NO_ORPHS);
-       err = ubifs_write_master(c);
+
+       old_ltail_lnum = c->ltail_lnum;
+       err = ubifs_log_end_commit(c, new_ltail_lnum);
        if (err)
                goto out;
 
index 177b0152fef48c2a71975ce41dc811b11c7b45d7..7ed13e1e216a8978e3a9a11be9bad29b50126103 100644 (file)
@@ -334,9 +334,9 @@ void ubifs_dump_node(const struct ubifs_info *c, const void *node)
                pr_err("\tkey_fmt        %d (%s)\n",
                       (int)sup->key_fmt, get_key_fmt(sup->key_fmt));
                pr_err("\tflags          %#x\n", sup_flags);
-               pr_err("\t  big_lpt      %u\n",
+               pr_err("\tbig_lpt        %u\n",
                       !!(sup_flags & UBIFS_FLG_BIGLPT));
-               pr_err("\t  space_fixup  %u\n",
+               pr_err("\tspace_fixup    %u\n",
                       !!(sup_flags & UBIFS_FLG_SPACE_FIXUP));
                pr_err("\tmin_io_size    %u\n", le32_to_cpu(sup->min_io_size));
                pr_err("\tleb_size       %u\n", le32_to_cpu(sup->leb_size));
@@ -2462,7 +2462,7 @@ static int power_cut_emulated(struct ubifs_info *c, int lnum, int write)
 
                        if (chance(1, 2)) {
                                d->pc_delay = 1;
-                               /* Fail withing 1 minute */
+                               /* Fail within 1 minute */
                                delay = prandom_u32() % 60000;
                                d->pc_timeout = jiffies;
                                d->pc_timeout += msecs_to_jiffies(delay);
index 0e045e75abd8ab7ac1a17cd502c9ff0c22d691e3..fb166e204441d880662e213cc07974c6b4380e89 100644 (file)
@@ -546,15 +546,14 @@ int ubifs_jnl_update(struct ubifs_info *c, const struct inode *dir,
        int aligned_dlen, aligned_ilen, sync = IS_DIRSYNC(dir);
        int last_reference = !!(deletion && inode->i_nlink == 0);
        struct ubifs_inode *ui = ubifs_inode(inode);
-       struct ubifs_inode *dir_ui = ubifs_inode(dir);
+       struct ubifs_inode *host_ui = ubifs_inode(dir);
        struct ubifs_dent_node *dent;
        struct ubifs_ino_node *ino;
        union ubifs_key dent_key, ino_key;
 
        dbg_jnl("ino %lu, dent '%.*s', data len %d in dir ino %lu",
                inode->i_ino, nm->len, nm->name, ui->data_len, dir->i_ino);
-       ubifs_assert(dir_ui->data_len == 0);
-       ubifs_assert(mutex_is_locked(&dir_ui->ui_mutex));
+       ubifs_assert(mutex_is_locked(&host_ui->ui_mutex));
 
        dlen = UBIFS_DENT_NODE_SZ + nm->len + 1;
        ilen = UBIFS_INO_NODE_SZ;
@@ -658,7 +657,7 @@ int ubifs_jnl_update(struct ubifs_info *c, const struct inode *dir,
        ui->synced_i_size = ui->ui_size;
        spin_unlock(&ui->ui_lock);
        mark_inode_clean(c, ui);
-       mark_inode_clean(c, dir_ui);
+       mark_inode_clean(c, host_ui);
        return 0;
 
 out_finish:
index a47ddfc9be6b2373c92e2b9eb8e5ab4454be581a..c14628fbeee2de173015bfd49668175c262287ae 100644 (file)
@@ -106,10 +106,14 @@ static inline long long empty_log_bytes(const struct ubifs_info *c)
        h = (long long)c->lhead_lnum * c->leb_size + c->lhead_offs;
        t = (long long)c->ltail_lnum * c->leb_size;
 
-       if (h >= t)
+       if (h > t)
                return c->log_bytes - h + t;
-       else
+       else if (h != t)
                return t - h;
+       else if (c->lhead_lnum != c->ltail_lnum)
+               return 0;
+       else
+               return c->log_bytes;
 }
 
 /**
@@ -447,9 +451,9 @@ out:
  * @ltail_lnum: new log tail LEB number
  *
  * This function is called on when the commit operation was finished. It
- * moves log tail to new position and unmaps LEBs which contain obsolete data.
- * Returns zero in case of success and a negative error code in case of
- * failure.
+ * moves log tail to new position and updates the master node so that it stores
+ * the new log tail LEB number. Returns zero in case of success and a negative
+ * error code in case of failure.
  */
 int ubifs_log_end_commit(struct ubifs_info *c, int ltail_lnum)
 {
@@ -477,7 +481,12 @@ int ubifs_log_end_commit(struct ubifs_info *c, int ltail_lnum)
        spin_unlock(&c->buds_lock);
 
        err = dbg_check_bud_bytes(c);
+       if (err)
+               goto out;
 
+       err = ubifs_write_master(c);
+
+out:
        mutex_unlock(&c->log_mutex);
        return err;
 }
index 86c6743ec1feb7eb99b17d6557c2ed1a1a90c1b8..bb15771b92ae32ae02390179492647a1d87c9dc2 100644 (file)
@@ -223,11 +223,18 @@ out:
 
 static int udf_release_file(struct inode *inode, struct file *filp)
 {
-       if (filp->f_mode & FMODE_WRITE) {
+       if (filp->f_mode & FMODE_WRITE &&
+           atomic_read(&inode->i_writecount) > 1) {
+               /*
+                * Grab i_mutex to avoid races with writes changing i_size
+                * while we are running.
+                */
+               mutex_lock(&inode->i_mutex);
                down_write(&UDF_I(inode)->i_data_sem);
                udf_discard_prealloc(inode);
                udf_truncate_tail_extent(inode);
                up_write(&UDF_I(inode)->i_data_sem);
+               mutex_unlock(&inode->i_mutex);
        }
        return 0;
 }
index 08598843288fe0c2dd206940d6437c606ef41c1f..c9b4df5810d52560b084b9557150faf8cfbe6e29 100644 (file)
@@ -1277,7 +1277,7 @@ update_time:
  */
 #define UDF_MAX_ICB_NESTING 1024
 
-static int udf_read_inode(struct inode *inode)
+static int udf_read_inode(struct inode *inode, bool hidden_inode)
 {
        struct buffer_head *bh = NULL;
        struct fileEntry *fe;
@@ -1436,8 +1436,11 @@ reread:
 
        link_count = le16_to_cpu(fe->fileLinkCount);
        if (!link_count) {
-               ret = -ESTALE;
-               goto out;
+               if (!hidden_inode) {
+                       ret = -ESTALE;
+                       goto out;
+               }
+               link_count = 1;
        }
        set_nlink(inode, link_count);
 
@@ -1826,7 +1829,8 @@ out:
        return err;
 }
 
-struct inode *udf_iget(struct super_block *sb, struct kernel_lb_addr *ino)
+struct inode *__udf_iget(struct super_block *sb, struct kernel_lb_addr *ino,
+                        bool hidden_inode)
 {
        unsigned long block = udf_get_lb_pblock(sb, ino, 0);
        struct inode *inode = iget_locked(sb, block);
@@ -1839,7 +1843,7 @@ struct inode *udf_iget(struct super_block *sb, struct kernel_lb_addr *ino)
                return inode;
 
        memcpy(&UDF_I(inode)->i_location, ino, sizeof(struct kernel_lb_addr));
-       err = udf_read_inode(inode);
+       err = udf_read_inode(inode, hidden_inode);
        if (err < 0) {
                iget_failed(inode);
                return ERR_PTR(err);
index 5401fc33f5cc906b76b846e62f74751cabd50a68..e229315bbf7adab01933827a68b59ccb8831dec7 100644 (file)
@@ -959,7 +959,7 @@ struct inode *udf_find_metadata_inode_efe(struct super_block *sb,
        addr.logicalBlockNum = meta_file_loc;
        addr.partitionReferenceNum = partition_num;
 
-       metadata_fe = udf_iget(sb, &addr);
+       metadata_fe = udf_iget_special(sb, &addr);
 
        if (IS_ERR(metadata_fe)) {
                udf_warn(sb, "metadata inode efe not found\n");
@@ -1020,7 +1020,7 @@ static int udf_load_metadata_files(struct super_block *sb, int partition)
                udf_debug("Bitmap file location: block = %d part = %d\n",
                          addr.logicalBlockNum, addr.partitionReferenceNum);
 
-               fe = udf_iget(sb, &addr);
+               fe = udf_iget_special(sb, &addr);
                if (IS_ERR(fe)) {
                        if (sb->s_flags & MS_RDONLY)
                                udf_warn(sb, "bitmap inode efe not found but it's ok since the disc is mounted read-only\n");
@@ -1119,7 +1119,7 @@ static int udf_fill_partdesc_info(struct super_block *sb,
                };
                struct inode *inode;
 
-               inode = udf_iget(sb, &loc);
+               inode = udf_iget_special(sb, &loc);
                if (IS_ERR(inode)) {
                        udf_debug("cannot load unallocSpaceTable (part %d)\n",
                                  p_index);
@@ -1154,7 +1154,7 @@ static int udf_fill_partdesc_info(struct super_block *sb,
                };
                struct inode *inode;
 
-               inode = udf_iget(sb, &loc);
+               inode = udf_iget_special(sb, &loc);
                if (IS_ERR(inode)) {
                        udf_debug("cannot load freedSpaceTable (part %d)\n",
                                  p_index);
@@ -1198,7 +1198,7 @@ static void udf_find_vat_block(struct super_block *sb, int p_index,
             vat_block >= map->s_partition_root &&
             vat_block >= start_block - 3; vat_block--) {
                ino.logicalBlockNum = vat_block - map->s_partition_root;
-               inode = udf_iget(sb, &ino);
+               inode = udf_iget_special(sb, &ino);
                if (!IS_ERR(inode)) {
                        sbi->s_vat_inode = inode;
                        break;
index 742557be9936399fba764f645c04b969d2a3cfd5..1cc3c993ebd04f4adb7b425f500e40d1185aae9f 100644 (file)
@@ -138,7 +138,18 @@ extern int udf_write_fi(struct inode *inode, struct fileIdentDesc *,
 /* file.c */
 extern long udf_ioctl(struct file *, unsigned int, unsigned long);
 /* inode.c */
-extern struct inode *udf_iget(struct super_block *, struct kernel_lb_addr *);
+extern struct inode *__udf_iget(struct super_block *, struct kernel_lb_addr *,
+                               bool hidden_inode);
+static inline struct inode *udf_iget_special(struct super_block *sb,
+                                            struct kernel_lb_addr *ino)
+{
+       return __udf_iget(sb, ino, true);
+}
+static inline struct inode *udf_iget(struct super_block *sb,
+                                    struct kernel_lb_addr *ino)
+{
+       return __udf_iget(sb, ino, false);
+}
 extern int udf_expand_file_adinicb(struct inode *);
 extern struct buffer_head *udf_expand_dir_adinicb(struct inode *, int *, int *);
 extern struct buffer_head *udf_bread(struct inode *, int, int, int *);
index 1f11483eba6a7b9f62d611e6f0110ec80a0ce643..77c331f1a77048ef43fddab49f098ac7ca9d4f9c 100644 (file)
@@ -81,8 +81,6 @@ static time_t year_seconds[MAX_YEAR_SECONDS] = {
 /*2038*/ SPY(68, 17, 0)
 };
 
-extern struct timezone sys_tz;
-
 #define SECS_PER_HOUR  (60 * 60)
 #define SECS_PER_DAY   (SECS_PER_HOUR * 24)
 
index 7bc20809c99e3936b232c12b7e0a50913a30b76b..2c1036080d5276bcb51314e649e45f0d6f0990a5 100644 (file)
@@ -784,7 +784,6 @@ static u64 ufs_bitmap_search(struct super_block *sb,
                0x0, 0x2, 0x6, 0xe, 0x1e, 0x3e, 0x7e, 0xfe, 0x1fe
        };
        struct ufs_sb_private_info *uspi = UFS_SB(sb)->s_uspi;
-       struct ufs_cylinder_group *ucg;
        unsigned start, length, loc;
        unsigned pos, want, blockmap, mask, end;
        u64 result;
@@ -792,8 +791,6 @@ static u64 ufs_bitmap_search(struct super_block *sb,
        UFSD("ENTER, cg %u, goal %llu, count %u\n", ucpi->c_cgx,
             (unsigned long long)goal, count);
 
-       ucg = ubh_get_ucg(UCPI_UBH(ucpi));
-
        if (goal)
                start = ufs_dtogd(uspi, goal) >> 3;
        else
index c69e6d43a0d2e863c3e2d6680731371e0d7ef284..64e83efb742d432209b448b9d2a5e734a6e1d66f 100644 (file)
@@ -364,13 +364,12 @@ out:
        return error;
 }
 
-SYSCALL_DEFINE5(setxattr, const char __user *, pathname,
-               const char __user *, name, const void __user *, value,
-               size_t, size, int, flags)
+static int path_setxattr(const char __user *pathname,
+                        const char __user *name, const void __user *value,
+                        size_t size, int flags, unsigned int lookup_flags)
 {
        struct path path;
        int error;
-       unsigned int lookup_flags = LOOKUP_FOLLOW;
 retry:
        error = user_path_at(AT_FDCWD, pathname, lookup_flags, &path);
        if (error)
@@ -388,28 +387,18 @@ retry:
        return error;
 }
 
+SYSCALL_DEFINE5(setxattr, const char __user *, pathname,
+               const char __user *, name, const void __user *, value,
+               size_t, size, int, flags)
+{
+       return path_setxattr(pathname, name, value, size, flags, LOOKUP_FOLLOW);
+}
+
 SYSCALL_DEFINE5(lsetxattr, const char __user *, pathname,
                const char __user *, name, const void __user *, value,
                size_t, size, int, flags)
 {
-       struct path path;
-       int error;
-       unsigned int lookup_flags = 0;
-retry:
-       error = user_path_at(AT_FDCWD, pathname, lookup_flags, &path);
-       if (error)
-               return error;
-       error = mnt_want_write(path.mnt);
-       if (!error) {
-               error = setxattr(path.dentry, name, value, size, flags);
-               mnt_drop_write(path.mnt);
-       }
-       path_put(&path);
-       if (retry_estale(error, lookup_flags)) {
-               lookup_flags |= LOOKUP_REVAL;
-               goto retry;
-       }
-       return error;
+       return path_setxattr(pathname, name, value, size, flags, 0);
 }
 
 SYSCALL_DEFINE5(fsetxattr, int, fd, const char __user *, name,
@@ -481,12 +470,12 @@ getxattr(struct dentry *d, const char __user *name, void __user *value,
        return error;
 }
 
-SYSCALL_DEFINE4(getxattr, const char __user *, pathname,
-               const char __user *, name, void __user *, value, size_t, size)
+static ssize_t path_getxattr(const char __user *pathname,
+                            const char __user *name, void __user *value,
+                            size_t size, unsigned int lookup_flags)
 {
        struct path path;
        ssize_t error;
-       unsigned int lookup_flags = LOOKUP_FOLLOW;
 retry:
        error = user_path_at(AT_FDCWD, pathname, lookup_flags, &path);
        if (error)
@@ -500,23 +489,16 @@ retry:
        return error;
 }
 
+SYSCALL_DEFINE4(getxattr, const char __user *, pathname,
+               const char __user *, name, void __user *, value, size_t, size)
+{
+       return path_getxattr(pathname, name, value, size, LOOKUP_FOLLOW);
+}
+
 SYSCALL_DEFINE4(lgetxattr, const char __user *, pathname,
                const char __user *, name, void __user *, value, size_t, size)
 {
-       struct path path;
-       ssize_t error;
-       unsigned int lookup_flags = 0;
-retry:
-       error = user_path_at(AT_FDCWD, pathname, lookup_flags, &path);
-       if (error)
-               return error;
-       error = getxattr(path.dentry, name, value, size);
-       path_put(&path);
-       if (retry_estale(error, lookup_flags)) {
-               lookup_flags |= LOOKUP_REVAL;
-               goto retry;
-       }
-       return error;
+       return path_getxattr(pathname, name, value, size, 0);
 }
 
 SYSCALL_DEFINE4(fgetxattr, int, fd, const char __user *, name,
@@ -571,12 +553,11 @@ listxattr(struct dentry *d, char __user *list, size_t size)
        return error;
 }
 
-SYSCALL_DEFINE3(listxattr, const char __user *, pathname, char __user *, list,
-               size_t, size)
+static ssize_t path_listxattr(const char __user *pathname, char __user *list,
+                             size_t size, unsigned int lookup_flags)
 {
        struct path path;
        ssize_t error;
-       unsigned int lookup_flags = LOOKUP_FOLLOW;
 retry:
        error = user_path_at(AT_FDCWD, pathname, lookup_flags, &path);
        if (error)
@@ -590,23 +571,16 @@ retry:
        return error;
 }
 
+SYSCALL_DEFINE3(listxattr, const char __user *, pathname, char __user *, list,
+               size_t, size)
+{
+       return path_listxattr(pathname, list, size, LOOKUP_FOLLOW);
+}
+
 SYSCALL_DEFINE3(llistxattr, const char __user *, pathname, char __user *, list,
                size_t, size)
 {
-       struct path path;
-       ssize_t error;
-       unsigned int lookup_flags = 0;
-retry:
-       error = user_path_at(AT_FDCWD, pathname, lookup_flags, &path);
-       if (error)
-               return error;
-       error = listxattr(path.dentry, list, size);
-       path_put(&path);
-       if (retry_estale(error, lookup_flags)) {
-               lookup_flags |= LOOKUP_REVAL;
-               goto retry;
-       }
-       return error;
+       return path_listxattr(pathname, list, size, 0);
 }
 
 SYSCALL_DEFINE3(flistxattr, int, fd, char __user *, list, size_t, size)
@@ -640,12 +614,11 @@ removexattr(struct dentry *d, const char __user *name)
        return vfs_removexattr(d, kname);
 }
 
-SYSCALL_DEFINE2(removexattr, const char __user *, pathname,
-               const char __user *, name)
+static int path_removexattr(const char __user *pathname,
+                           const char __user *name, unsigned int lookup_flags)
 {
        struct path path;
        int error;
-       unsigned int lookup_flags = LOOKUP_FOLLOW;
 retry:
        error = user_path_at(AT_FDCWD, pathname, lookup_flags, &path);
        if (error)
@@ -663,27 +636,16 @@ retry:
        return error;
 }
 
+SYSCALL_DEFINE2(removexattr, const char __user *, pathname,
+               const char __user *, name)
+{
+       return path_removexattr(pathname, name, LOOKUP_FOLLOW);
+}
+
 SYSCALL_DEFINE2(lremovexattr, const char __user *, pathname,
                const char __user *, name)
 {
-       struct path path;
-       int error;
-       unsigned int lookup_flags = 0;
-retry:
-       error = user_path_at(AT_FDCWD, pathname, lookup_flags, &path);
-       if (error)
-               return error;
-       error = mnt_want_write(path.mnt);
-       if (!error) {
-               error = removexattr(path.dentry, name);
-               mnt_drop_write(path.mnt);
-       }
-       path_put(&path);
-       if (retry_estale(error, lookup_flags)) {
-               lookup_flags |= LOOKUP_REVAL;
-               goto retry;
-       }
-       return error;
+       return path_removexattr(pathname, name, 0);
 }
 
 SYSCALL_DEFINE2(fremovexattr, int, fd, const char __user *, name)
index 844e288b9576d1202d88e6628ca5731149fb9b92..53e95b2a1369cf0836df38ccc3311095f7ed8e44 100644 (file)
@@ -21,7 +21,6 @@
 #include <linux/swap.h>
 #include <linux/blkdev.h>
 #include <linux/backing-dev.h>
-#include "time.h"
 #include "kmem.h"
 #include "xfs_message.h"
 
index 4bffffe038a1a8ac329b9dc19e5a885878270088..eff34218f405a0d7473ccfa35221b1f9969f168d 100644 (file)
@@ -2209,6 +2209,10 @@ xfs_agf_verify(
              be32_to_cpu(agf->agf_flcount) <= XFS_AGFL_SIZE(mp)))
                return false;
 
+       if (be32_to_cpu(agf->agf_levels[XFS_BTNUM_BNO]) > XFS_BTREE_MAXLEVELS ||
+           be32_to_cpu(agf->agf_levels[XFS_BTNUM_CNT]) > 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
index 86df952d3e24e7054477338f479d325fa212ce0c..79c981984dcad0b60e2405cd2ba718405b8bd7ab 100644 (file)
@@ -5403,23 +5403,224 @@ error0:
        return error;
 }
 
+/*
+ * Determine whether an extent shift can be accomplished by a merge with the
+ * extent that precedes the target hole of the shift.
+ */
+STATIC bool
+xfs_bmse_can_merge(
+       struct xfs_bmbt_irec    *left,  /* preceding extent */
+       struct xfs_bmbt_irec    *got,   /* current extent to shift */
+       xfs_fileoff_t           shift)  /* shift fsb */
+{
+       xfs_fileoff_t           startoff;
+
+       startoff = got->br_startoff - shift;
+
+       /*
+        * The extent, once shifted, must be adjacent in-file and on-disk with
+        * the preceding extent.
+        */
+       if ((left->br_startoff + left->br_blockcount != startoff) ||
+           (left->br_startblock + left->br_blockcount != got->br_startblock) ||
+           (left->br_state != got->br_state) ||
+           (left->br_blockcount + got->br_blockcount > MAXEXTLEN))
+               return false;
+
+       return true;
+}
+
+/*
+ * A bmap extent shift adjusts the file offset of an extent to fill a preceding
+ * hole in the file. If an extent shift would result in the extent being fully
+ * adjacent to the extent that currently precedes the hole, we can merge with
+ * the preceding extent rather than do the shift.
+ *
+ * This function assumes the caller has verified a shift-by-merge is possible
+ * with the provided extents via xfs_bmse_can_merge().
+ */
+STATIC int
+xfs_bmse_merge(
+       struct xfs_inode                *ip,
+       int                             whichfork,
+       xfs_fileoff_t                   shift,          /* shift fsb */
+       int                             current_ext,    /* idx of gotp */
+       struct xfs_bmbt_rec_host        *gotp,          /* extent to shift */
+       struct xfs_bmbt_rec_host        *leftp,         /* preceding extent */
+       struct xfs_btree_cur            *cur,
+       int                             *logflags)      /* output */
+{
+       struct xfs_ifork                *ifp;
+       struct xfs_bmbt_irec            got;
+       struct xfs_bmbt_irec            left;
+       xfs_filblks_t                   blockcount;
+       int                             error, i;
+
+       ifp = XFS_IFORK_PTR(ip, whichfork);
+       xfs_bmbt_get_all(gotp, &got);
+       xfs_bmbt_get_all(leftp, &left);
+       blockcount = left.br_blockcount + got.br_blockcount;
+
+       ASSERT(xfs_isilocked(ip, XFS_IOLOCK_EXCL));
+       ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL));
+       ASSERT(xfs_bmse_can_merge(&left, &got, shift));
+
+       /*
+        * Merge the in-core extents. Note that the host record pointers and
+        * current_ext index are invalid once the extent has been removed via
+        * xfs_iext_remove().
+        */
+       xfs_bmbt_set_blockcount(leftp, blockcount);
+       xfs_iext_remove(ip, current_ext, 1, 0);
+
+       /*
+        * Update the on-disk extent count, the btree if necessary and log the
+        * inode.
+        */
+       XFS_IFORK_NEXT_SET(ip, whichfork,
+                          XFS_IFORK_NEXTENTS(ip, whichfork) - 1);
+       *logflags |= XFS_ILOG_CORE;
+       if (!cur) {
+               *logflags |= XFS_ILOG_DEXT;
+               return 0;
+       }
+
+       /* lookup and remove the extent to merge */
+       error = xfs_bmbt_lookup_eq(cur, got.br_startoff, got.br_startblock,
+                                  got.br_blockcount, &i);
+       if (error)
+               goto out_error;
+       XFS_WANT_CORRUPTED_GOTO(i == 1, out_error);
+
+       error = xfs_btree_delete(cur, &i);
+       if (error)
+               goto out_error;
+       XFS_WANT_CORRUPTED_GOTO(i == 1, out_error);
+
+       /* lookup and update size of the previous extent */
+       error = xfs_bmbt_lookup_eq(cur, left.br_startoff, left.br_startblock,
+                                  left.br_blockcount, &i);
+       if (error)
+               goto out_error;
+       XFS_WANT_CORRUPTED_GOTO(i == 1, out_error);
+
+       left.br_blockcount = blockcount;
+
+       error = xfs_bmbt_update(cur, left.br_startoff, left.br_startblock,
+                               left.br_blockcount, left.br_state);
+       if (error)
+               goto out_error;
+
+       return 0;
+
+out_error:
+       return error;
+}
+
+/*
+ * Shift a single extent.
+ */
+STATIC int
+xfs_bmse_shift_one(
+       struct xfs_inode                *ip,
+       int                             whichfork,
+       xfs_fileoff_t                   offset_shift_fsb,
+       int                             *current_ext,
+       struct xfs_bmbt_rec_host        *gotp,
+       struct xfs_btree_cur            *cur,
+       int                             *logflags)
+{
+       struct xfs_ifork                *ifp;
+       xfs_fileoff_t                   startoff;
+       struct xfs_bmbt_rec_host        *leftp;
+       struct xfs_bmbt_irec            got;
+       struct xfs_bmbt_irec            left;
+       int                             error;
+       int                             i;
+
+       ifp = XFS_IFORK_PTR(ip, whichfork);
+
+       xfs_bmbt_get_all(gotp, &got);
+       startoff = got.br_startoff - offset_shift_fsb;
+
+       /* delalloc extents should be prevented by caller */
+       XFS_WANT_CORRUPTED_GOTO(!isnullstartblock(got.br_startblock),
+                               out_error);
+
+       /*
+        * If this is the first extent in the file, make sure there's enough
+        * room at the start of the file and jump right to the shift as there's
+        * no left extent to merge.
+        */
+       if (*current_ext == 0) {
+               if (got.br_startoff < offset_shift_fsb)
+                       return -EINVAL;
+               goto shift_extent;
+       }
+
+       /* grab the left extent and check for a large enough hole */
+       leftp = xfs_iext_get_ext(ifp, *current_ext - 1);
+       xfs_bmbt_get_all(leftp, &left);
+
+       if (startoff < left.br_startoff + left.br_blockcount)
+               return -EINVAL;
+
+       /* check whether to merge the extent or shift it down */
+       if (!xfs_bmse_can_merge(&left, &got, offset_shift_fsb))
+               goto shift_extent;
+
+       return xfs_bmse_merge(ip, whichfork, offset_shift_fsb, *current_ext,
+                             gotp, leftp, cur, logflags);
+
+shift_extent:
+       /*
+        * Increment the extent index for the next iteration, update the start
+        * offset of the in-core extent and update the btree if applicable.
+        */
+       (*current_ext)++;
+       xfs_bmbt_set_startoff(gotp, startoff);
+       *logflags |= XFS_ILOG_CORE;
+       if (!cur) {
+               *logflags |= XFS_ILOG_DEXT;
+               return 0;
+       }
+
+       error = xfs_bmbt_lookup_eq(cur, got.br_startoff, got.br_startblock,
+                                  got.br_blockcount, &i);
+       if (error)
+               return error;
+       XFS_WANT_CORRUPTED_GOTO(i == 1, out_error);
+
+       got.br_startoff = startoff;
+       error = xfs_bmbt_update(cur, got.br_startoff, got.br_startblock,
+                               got.br_blockcount, got.br_state);
+       if (error)
+               return error;
+
+       return 0;
+
+out_error:
+       return error;
+}
+
 /*
  * Shift extent records to the left to cover a hole.
  *
- * The maximum number of extents to be shifted in a single operation
- * is @num_exts, and @current_ext keeps track of the current extent
- * index we have shifted. @offset_shift_fsb is the length by which each
- * extent is shifted. If there is no hole to shift the extents
- * into, this will be considered invalid operation and we abort immediately.
+ * The maximum number of extents to be shifted in a single operation is
+ * @num_exts. @start_fsb specifies the file offset to start the shift and the
+ * file offset where we've left off is returned in @next_fsb. @offset_shift_fsb
+ * is the length by which each extent is shifted. If there is no hole to shift
+ * the extents into, this will be considered invalid operation and we abort
+ * immediately.
  */
 int
 xfs_bmap_shift_extents(
        struct xfs_trans        *tp,
        struct xfs_inode        *ip,
-       int                     *done,
        xfs_fileoff_t           start_fsb,
        xfs_fileoff_t           offset_shift_fsb,
-       xfs_extnum_t            *current_ext,
+       int                     *done,
+       xfs_fileoff_t           *next_fsb,
        xfs_fsblock_t           *firstblock,
        struct xfs_bmap_free    *flist,
        int                     num_exts)
@@ -5427,16 +5628,13 @@ xfs_bmap_shift_extents(
        struct xfs_btree_cur            *cur = NULL;
        struct xfs_bmbt_rec_host        *gotp;
        struct xfs_bmbt_irec            got;
-       struct xfs_bmbt_irec            left;
        struct xfs_mount                *mp = ip->i_mount;
        struct xfs_ifork                *ifp;
        xfs_extnum_t                    nexts = 0;
-       xfs_fileoff_t                   startoff;
+       xfs_extnum_t                    current_ext;
        int                             error = 0;
-       int                             i;
        int                             whichfork = XFS_DATA_FORK;
        int                             logflags = 0;
-       xfs_filblks_t                   blockcount = 0;
        int                             total_extents;
 
        if (unlikely(XFS_TEST_ERROR(
@@ -5451,7 +5649,8 @@ xfs_bmap_shift_extents(
        if (XFS_FORCED_SHUTDOWN(mp))
                return -EIO;
 
-       ASSERT(current_ext != NULL);
+       ASSERT(xfs_isilocked(ip, XFS_IOLOCK_EXCL));
+       ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL));
 
        ifp = XFS_IFORK_PTR(ip, whichfork);
        if (!(ifp->if_flags & XFS_IFEXTENTS)) {
@@ -5461,23 +5660,6 @@ xfs_bmap_shift_extents(
                        return error;
        }
 
-       /*
-        * If *current_ext is 0, we would need to lookup the extent
-        * from where we would start shifting and store it in gotp.
-        */
-       if (!*current_ext) {
-               gotp = xfs_iext_bno_to_ext(ifp, start_fsb, current_ext);
-               /*
-                * gotp can be null in 2 cases: 1) if there are no extents
-                * or 2) start_fsb lies in a hole beyond which there are
-                * no extents. Either way, we are done.
-                */
-               if (!gotp) {
-                       *done = 1;
-                       return 0;
-               }
-       }
-
        if (ifp->if_flags & XFS_IFBROOT) {
                cur = xfs_bmbt_init_cursor(mp, tp, ip, whichfork);
                cur->bc_private.b.firstblock = *firstblock;
@@ -5485,113 +5667,47 @@ xfs_bmap_shift_extents(
                cur->bc_private.b.flags = 0;
        }
 
+       /*
+        * Look up the extent index for the fsb where we start shifting. We can
+        * henceforth iterate with current_ext as extent list changes are locked
+        * out via ilock.
+        *
+        * gotp can be null in 2 cases: 1) if there are no extents or 2)
+        * start_fsb lies in a hole beyond which there are no extents. Either
+        * way, we are done.
+        */
+       gotp = xfs_iext_bno_to_ext(ifp, start_fsb, &current_ext);
+       if (!gotp) {
+               *done = 1;
+               goto del_cursor;
+       }
+
        /*
         * There may be delalloc extents in the data fork before the range we
-        * are collapsing out, so we cannot
-        * use the count of real extents here. Instead we have to calculate it
-        * from the incore fork.
+        * are collapsing out, so we cannot use the count of real extents here.
+        * Instead we have to calculate it from the incore fork.
         */
        total_extents = ifp->if_bytes / sizeof(xfs_bmbt_rec_t);
-       while (nexts++ < num_exts && *current_ext < total_extents) {
-
-               gotp = xfs_iext_get_ext(ifp, *current_ext);
-               xfs_bmbt_get_all(gotp, &got);
-               startoff = got.br_startoff - offset_shift_fsb;
-
-               /*
-                * Before shifting extent into hole, make sure that the hole
-                * is large enough to accomodate the shift.
-                */
-               if (*current_ext) {
-                       xfs_bmbt_get_all(xfs_iext_get_ext(ifp,
-                                               *current_ext - 1), &left);
-
-                       if (startoff < left.br_startoff + left.br_blockcount)
-                               error = -EINVAL;
-               } else if (offset_shift_fsb > got.br_startoff) {
-                       /*
-                        * When first extent is shifted, offset_shift_fsb
-                        * should be less than the stating offset of
-                        * the first extent.
-                        */
-                       error = -EINVAL;
-               }
-
+       while (nexts++ < num_exts && current_ext < total_extents) {
+               error = xfs_bmse_shift_one(ip, whichfork, offset_shift_fsb,
+                                       &current_ext, gotp, cur, &logflags);
                if (error)
                        goto del_cursor;
 
-               if (cur) {
-                       error = xfs_bmbt_lookup_eq(cur, got.br_startoff,
-                                                  got.br_startblock,
-                                                  got.br_blockcount,
-                                                  &i);
-                       if (error)
-                               goto del_cursor;
-                       XFS_WANT_CORRUPTED_GOTO(i == 1, del_cursor);
-               }
-
-               /* Check if we can merge 2 adjacent extents */
-               if (*current_ext &&
-                   left.br_startoff + left.br_blockcount == startoff &&
-                   left.br_startblock + left.br_blockcount ==
-                               got.br_startblock &&
-                   left.br_state == got.br_state &&
-                   left.br_blockcount + got.br_blockcount <= MAXEXTLEN) {
-                       blockcount = left.br_blockcount +
-                               got.br_blockcount;
-                       xfs_iext_remove(ip, *current_ext, 1, 0);
-                       logflags |= XFS_ILOG_CORE;
-                       if (cur) {
-                               error = xfs_btree_delete(cur, &i);
-                               if (error)
-                                       goto del_cursor;
-                               XFS_WANT_CORRUPTED_GOTO(i == 1, del_cursor);
-                       } else {
-                               logflags |= XFS_ILOG_DEXT;
-                       }
-                       XFS_IFORK_NEXT_SET(ip, whichfork,
-                               XFS_IFORK_NEXTENTS(ip, whichfork) - 1);
-                       gotp = xfs_iext_get_ext(ifp, --*current_ext);
-                       xfs_bmbt_get_all(gotp, &got);
-
-                       /* Make cursor point to the extent we will update */
-                       if (cur) {
-                               error = xfs_bmbt_lookup_eq(cur, got.br_startoff,
-                                                          got.br_startblock,
-                                                          got.br_blockcount,
-                                                          &i);
-                               if (error)
-                                       goto del_cursor;
-                               XFS_WANT_CORRUPTED_GOTO(i == 1, del_cursor);
-                       }
-
-                       xfs_bmbt_set_blockcount(gotp, blockcount);
-                       got.br_blockcount = blockcount;
-               } else {
-                       /* We have to update the startoff */
-                       xfs_bmbt_set_startoff(gotp, startoff);
-                       got.br_startoff = startoff;
-               }
-
-               logflags |= XFS_ILOG_CORE;
-               if (cur) {
-                       error = xfs_bmbt_update(cur, got.br_startoff,
-                                               got.br_startblock,
-                                               got.br_blockcount,
-                                               got.br_state);
-                       if (error)
-                               goto del_cursor;
-               } else {
-                       logflags |= XFS_ILOG_DEXT;
-               }
-
-               (*current_ext)++;
+               /* update total extent count and grab the next record */
                total_extents = ifp->if_bytes / sizeof(xfs_bmbt_rec_t);
+               if (current_ext >= total_extents)
+                       break;
+               gotp = xfs_iext_get_ext(ifp, current_ext);
        }
 
        /* Check if we are done */
-       if (*current_ext == total_extents)
+       if (current_ext == total_extents) {
                *done = 1;
+       } else if (next_fsb) {
+               xfs_bmbt_get_all(gotp, &got);
+               *next_fsb = got.br_startoff;
+       }
 
 del_cursor:
        if (cur)
@@ -5600,5 +5716,6 @@ del_cursor:
 
        if (logflags)
                xfs_trans_log_inode(tp, ip, logflags);
+
        return error;
 }
index b879ca56a64ccfab5b2a42502a5b50f68b85f1df..44db6db8640241c063a88641d5e10d61fe046c54 100644 (file)
@@ -178,9 +178,8 @@ 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,
-               int *done, xfs_fileoff_t start_fsb,
-               xfs_fileoff_t offset_shift_fsb, xfs_extnum_t *current_ext,
-               xfs_fsblock_t *firstblock, struct xfs_bmap_free *flist,
-               int num_exts);
+               xfs_fileoff_t start_fsb, xfs_fileoff_t offset_shift_fsb,
+               int *done, xfs_fileoff_t *next_fsb, xfs_fsblock_t *firstblock,
+               struct xfs_bmap_free *flist, int num_exts);
 
 #endif /* __XFS_BMAP_H__ */
index 2c42ae28d027594aa456e15572094c24f9aac035..fd827530afec27146861a1416c74d4769b2a32de 100644 (file)
@@ -2563,7 +2563,8 @@ xfs_da_get_buf(
                                    mapp, nmap, 0);
        error = bp ? bp->b_error : -EIO;
        if (error) {
-               xfs_trans_brelse(trans, bp);
+               if (bp)
+                       xfs_trans_brelse(trans, bp);
                goto out_free;
        }
 
index c9aee52a37e202987141ddaf1468fe7ee5b03094..7e42fdfd2f1de5f0732689de22aadcdf0c07282f 100644 (file)
@@ -270,7 +270,6 @@ xfs_dir3_data_get_ftype(
 {
        __uint8_t       ftype = dep->name[dep->namelen];
 
-       ASSERT(ftype < XFS_DIR3_FT_MAX);
        if (ftype >= XFS_DIR3_FT_MAX)
                return XFS_DIR3_FT_UNKNOWN;
        return ftype;
index 6cef22152fd6440d46581bc141b4267b34119aea..7075aaf131f4c5511fbc726ea7c10017b5966e54 100644 (file)
@@ -237,7 +237,8 @@ xfs_dir_init(
 }
 
 /*
-  Enter a name in a directory.
+ * Enter a name in a directory, or check for available space.
+ * If inum is 0, only the available space test is performed.
  */
 int
 xfs_dir_createname(
@@ -254,10 +255,12 @@ xfs_dir_createname(
        int                     v;              /* type-checking value */
 
        ASSERT(S_ISDIR(dp->i_d.di_mode));
-       rval = xfs_dir_ino_validate(tp->t_mountp, inum);
-       if (rval)
-               return rval;
-       XFS_STATS_INC(xs_dir_create);
+       if (inum) {
+               rval = xfs_dir_ino_validate(tp->t_mountp, inum);
+               if (rval)
+                       return rval;
+               XFS_STATS_INC(xs_dir_create);
+       }
 
        args = kmem_zalloc(sizeof(*args), KM_SLEEP | KM_NOFS);
        if (!args)
@@ -276,6 +279,8 @@ xfs_dir_createname(
        args->whichfork = XFS_DATA_FORK;
        args->trans = tp;
        args->op_flags = XFS_DA_OP_ADDNAME | XFS_DA_OP_OKNOENT;
+       if (!inum)
+               args->op_flags |= XFS_DA_OP_JUSTCHECK;
 
        if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL) {
                rval = xfs_dir2_sf_addname(args);
@@ -535,62 +540,14 @@ out_free:
 
 /*
  * See if this entry can be added to the directory without allocating space.
- * First checks that the caller couldn't reserve enough space (resblks = 0).
  */
 int
 xfs_dir_canenter(
        xfs_trans_t     *tp,
        xfs_inode_t     *dp,
-       struct xfs_name *name,          /* name of entry to add */
-       uint            resblks)
+       struct xfs_name *name)          /* name of entry to add */
 {
-       struct xfs_da_args *args;
-       int             rval;
-       int             v;              /* type-checking value */
-
-       if (resblks)
-               return 0;
-
-       ASSERT(S_ISDIR(dp->i_d.di_mode));
-
-       args = kmem_zalloc(sizeof(*args), KM_SLEEP | KM_NOFS);
-       if (!args)
-               return -ENOMEM;
-
-       args->geo = dp->i_mount->m_dir_geo;
-       args->name = name->name;
-       args->namelen = name->len;
-       args->filetype = name->type;
-       args->hashval = dp->i_mount->m_dirnameops->hashname(name);
-       args->dp = dp;
-       args->whichfork = XFS_DATA_FORK;
-       args->trans = tp;
-       args->op_flags = XFS_DA_OP_JUSTCHECK | XFS_DA_OP_ADDNAME |
-                                                       XFS_DA_OP_OKNOENT;
-
-       if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL) {
-               rval = xfs_dir2_sf_addname(args);
-               goto out_free;
-       }
-
-       rval = xfs_dir2_isblock(args, &v);
-       if (rval)
-               goto out_free;
-       if (v) {
-               rval = xfs_dir2_block_addname(args);
-               goto out_free;
-       }
-
-       rval = xfs_dir2_isleaf(args, &v);
-       if (rval)
-               goto out_free;
-       if (v)
-               rval = xfs_dir2_leaf_addname(args);
-       else
-               rval = xfs_dir2_node_addname(args);
-out_free:
-       kmem_free(args);
-       return rval;
+       return xfs_dir_createname(tp, dp, name, 0, NULL, NULL, 0);
 }
 
 /*
index c8e86b0b5e9954f64b271b7569a198fa5ab1425f..4dff261e6ed59ee8b9749c189554428115e8c4df 100644 (file)
@@ -136,7 +136,7 @@ extern int xfs_dir_replace(struct xfs_trans *tp, struct xfs_inode *dp,
                                xfs_fsblock_t *first,
                                struct xfs_bmap_free *flist, xfs_extlen_t tot);
 extern int xfs_dir_canenter(struct xfs_trans *tp, struct xfs_inode *dp,
-                               struct xfs_name *name, uint resblks);
+                               struct xfs_name *name);
 
 /*
  * Direct call from the bmap code, bypassing the generic directory layer.
index b62771f1f4b5b7028569b32af3b16bc806005132..23dcb72fc5e688f7d550f4cd79b7f4fbac8ec7b3 100644 (file)
@@ -1076,8 +1076,8 @@ xfs_dialloc_ag_finobt_newino(
        int i;
 
        if (agi->agi_newino != cpu_to_be32(NULLAGINO)) {
-               error = xfs_inobt_lookup(cur, agi->agi_newino, XFS_LOOKUP_EQ,
-                                        &i);
+               error = xfs_inobt_lookup(cur, be32_to_cpu(agi->agi_newino),
+                                        XFS_LOOKUP_EQ, &i);
                if (error)
                        return error;
                if (i == 1) {
@@ -1085,7 +1085,6 @@ xfs_dialloc_ag_finobt_newino(
                        if (error)
                                return error;
                        XFS_WANT_CORRUPTED_RETURN(i == 1);
-
                        return 0;
                }
        }
@@ -2051,6 +2050,8 @@ xfs_agi_verify(
        if (!XFS_AGI_GOOD_VERSION(be32_to_cpu(agi->agi_versionnum)))
                return false;
 
+       if (be32_to_cpu(agi->agi_level) > 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
index f4dd697cac08720f057b58c094bc4bfe3346ca5b..7c818f1e448416da6bcfae580a6aa898e5114bbb 100644 (file)
@@ -424,20 +424,24 @@ xfs_rtfind_forw(
 }
 
 /*
- * Read and modify the summary information for a given extent size,
+ * Read and/or modify the summary information for a given extent size,
  * bitmap block combination.
  * Keeps track of a current summary block, so we don't keep reading
  * it from the buffer cache.
+ *
+ * Summary information is returned in *sum if specified.
+ * If no delta is specified, returns summary only.
  */
 int
-xfs_rtmodify_summary(
-       xfs_mount_t     *mp,            /* file system mount point */
+xfs_rtmodify_summary_int(
+       xfs_mount_t     *mp,            /* file system mount structure */
        xfs_trans_t     *tp,            /* transaction pointer */
        int             log,            /* log2 of extent size */
        xfs_rtblock_t   bbno,           /* bitmap block number */
        int             delta,          /* change to make to summary info */
        xfs_buf_t       **rbpp,         /* in/out: summary block buffer */
-       xfs_fsblock_t   *rsb)           /* in/out: summary block number */
+       xfs_fsblock_t   *rsb,           /* in/out: summary block number */
+       xfs_suminfo_t   *sum)           /* out: summary info for this block */
 {
        xfs_buf_t       *bp;            /* buffer for the summary block */
        int             error;          /* error value */
@@ -456,7 +460,7 @@ xfs_rtmodify_summary(
        /*
         * If we have an old buffer, and the block number matches, use that.
         */
-       if (rbpp && *rbpp && *rsb == sb)
+       if (*rbpp && *rsb == sb)
                bp = *rbpp;
        /*
         * Otherwise we have to get the buffer.
@@ -465,7 +469,7 @@ xfs_rtmodify_summary(
                /*
                 * If there was an old one, get rid of it first.
                 */
-               if (rbpp && *rbpp)
+               if (*rbpp)
                        xfs_trans_brelse(tp, *rbpp);
                error = xfs_rtbuf_get(mp, tp, sb, 1, &bp);
                if (error) {
@@ -474,21 +478,38 @@ xfs_rtmodify_summary(
                /*
                 * Remember this buffer and block for the next call.
                 */
-               if (rbpp) {
-                       *rbpp = bp;
-                       *rsb = sb;
-               }
+               *rbpp = bp;
+               *rsb = sb;
        }
        /*
-        * Point to the summary information, modify and log it.
+        * Point to the summary information, modify/log it, and/or copy it out.
         */
        sp = XFS_SUMPTR(mp, bp, so);
-       *sp += delta;
-       xfs_trans_log_buf(tp, bp, (uint)((char *)sp - (char *)bp->b_addr),
-               (uint)((char *)sp - (char *)bp->b_addr + sizeof(*sp) - 1));
+       if (delta) {
+               uint first = (uint)((char *)sp - (char *)bp->b_addr);
+
+               *sp += delta;
+               xfs_trans_log_buf(tp, bp, first, first + sizeof(*sp) - 1);
+       }
+       if (sum)
+               *sum = *sp;
        return 0;
 }
 
+int
+xfs_rtmodify_summary(
+       xfs_mount_t     *mp,            /* file system mount structure */
+       xfs_trans_t     *tp,            /* transaction pointer */
+       int             log,            /* log2 of extent size */
+       xfs_rtblock_t   bbno,           /* bitmap block number */
+       int             delta,          /* change to make to summary info */
+       xfs_buf_t       **rbpp,         /* in/out: summary block buffer */
+       xfs_fsblock_t   *rsb)           /* in/out: summary block number */
+{
+       return xfs_rtmodify_summary_int(mp, tp, log, bbno,
+                                       delta, rbpp, rsb, NULL);
+}
+
 /*
  * Set the given range of bitmap bits to the given value.
  * Do whatever I/O and logging is required.
index ad525a5623a49557c9554f23aa72d323e9ed8b77..5f902fa7913f67bb16acf07506e654da8ba2f388 100644 (file)
@@ -279,11 +279,13 @@ xfs_mount_validate_sb(
            sbp->sb_blocklog < XFS_MIN_BLOCKSIZE_LOG                    ||
            sbp->sb_blocklog > XFS_MAX_BLOCKSIZE_LOG                    ||
            sbp->sb_blocksize != (1 << sbp->sb_blocklog)                ||
+           sbp->sb_dirblklog > XFS_MAX_BLOCKSIZE_LOG                   ||
            sbp->sb_inodesize < XFS_DINODE_MIN_SIZE                     ||
            sbp->sb_inodesize > XFS_DINODE_MAX_SIZE                     ||
            sbp->sb_inodelog < XFS_DINODE_MIN_LOG                       ||
            sbp->sb_inodelog > XFS_DINODE_MAX_LOG                       ||
            sbp->sb_inodesize != (1 << sbp->sb_inodelog)                ||
+           sbp->sb_logsunit > XLOG_MAX_RECORD_BSIZE                    ||
            sbp->sb_inopblock != howmany(sbp->sb_blocksize,sbp->sb_inodesize) ||
            (sbp->sb_blocklog - sbp->sb_inodelog != sbp->sb_inopblog)   ||
            (sbp->sb_rextsize * sbp->sb_blocksize > XFS_MAX_RTEXTSIZE)  ||
@@ -443,6 +445,8 @@ __xfs_sb_from_disk(
        to->sb_features_incompat = be32_to_cpu(from->sb_features_incompat);
        to->sb_features_log_incompat =
                                be32_to_cpu(from->sb_features_log_incompat);
+       /* crc is only used on disk, not in memory; just init to 0 here. */
+       to->sb_crc = 0;
        to->sb_pad = 0;
        to->sb_pquotino = be64_to_cpu(from->sb_pquotino);
        to->sb_lsn = be64_to_cpu(from->sb_lsn);
@@ -548,6 +552,9 @@ xfs_sb_to_disk(
        if (!fields)
                return;
 
+       /* We should never write the crc here, it's updated in the IO path */
+       fields &= ~XFS_SB_CRC;
+
        xfs_sb_quota_to_disk(to, from, &fields);
        while (fields) {
                f = (xfs_sb_field_t)xfs_lowbit64((__uint64_t)fields);
diff --git a/fs/xfs/time.h b/fs/xfs/time.h
deleted file mode 100644 (file)
index 387e695..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Copyright (c) 2000-2003,2005 Silicon Graphics, 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_SUPPORT_TIME_H__
-#define __XFS_SUPPORT_TIME_H__
-
-#include <linux/sched.h>
-#include <linux/time.h>
-
-typedef struct timespec timespec_t;
-
-static inline void delay(long ticks)
-{
-       schedule_timeout_uninterruptible(ticks);
-}
-
-static inline void nanotime(struct timespec *tvp)
-{
-       *tvp = CURRENT_TIME;
-}
-
-#endif /* __XFS_SUPPORT_TIME_H__ */
index b984647c24db02e98b4e030fd03c7bac75740923..f5b2453a43b2b554cfe9c32f82bbf91d22d22882 100644 (file)
@@ -434,10 +434,22 @@ xfs_start_page_writeback(
 {
        ASSERT(PageLocked(page));
        ASSERT(!PageWriteback(page));
-       if (clear_dirty)
+
+       /*
+        * if the page was not fully cleaned, we need to ensure that the higher
+        * layers come back to it correctly. That means we need to keep the page
+        * dirty, and for WB_SYNC_ALL writeback we need to ensure the
+        * PAGECACHE_TAG_TOWRITE index mark is not removed so another attempt to
+        * write this page in this writeback sweep will be made.
+        */
+       if (clear_dirty) {
                clear_page_dirty_for_io(page);
-       set_page_writeback(page);
+               set_page_writeback(page);
+       } else
+               set_page_writeback_keepwrite(page);
+
        unlock_page(page);
+
        /* If no buffers on the page are to be written, finish it here */
        if (!buffers)
                end_page_writeback(page);
@@ -548,6 +560,13 @@ xfs_cancel_ioend(
                do {
                        next_bh = bh->b_private;
                        clear_buffer_async_write(bh);
+                       /*
+                        * The unwritten flag is cleared when added to the
+                        * ioend. We're not submitting for I/O so mark the
+                        * buffer unwritten again for next time around.
+                        */
+                       if (ioend->io_type == XFS_IO_UNWRITTEN)
+                               set_buffer_unwritten(bh);
                        unlock_buffer(bh);
                } while ((bh = next_bh) != NULL);
 
index 1707980f9a4b564842cd435d9efc70571a5a9b18..92e8f99a58575b0667be026c9bfc6da5eeeae76d 100644 (file)
@@ -1122,14 +1122,6 @@ xfs_zero_remaining_bytes(
        if (endoff > XFS_ISIZE(ip))
                endoff = XFS_ISIZE(ip);
 
-       bp = xfs_buf_get_uncached(XFS_IS_REALTIME_INODE(ip) ?
-                                       mp->m_rtdev_targp : mp->m_ddev_targp,
-                                 BTOBB(mp->m_sb.sb_blocksize), 0);
-       if (!bp)
-               return -ENOMEM;
-
-       xfs_buf_unlock(bp);
-
        for (offset = startoff; offset <= endoff; offset = lastoffset + 1) {
                uint lock_mode;
 
@@ -1152,42 +1144,24 @@ xfs_zero_remaining_bytes(
                ASSERT(imap.br_startblock != DELAYSTARTBLOCK);
                if (imap.br_state == XFS_EXT_UNWRITTEN)
                        continue;
-               XFS_BUF_UNDONE(bp);
-               XFS_BUF_UNWRITE(bp);
-               XFS_BUF_READ(bp);
-               XFS_BUF_SET_ADDR(bp, xfs_fsb_to_db(ip, imap.br_startblock));
 
-               if (XFS_FORCED_SHUTDOWN(mp)) {
-                       error = -EIO;
-                       break;
-               }
-               xfs_buf_iorequest(bp);
-               error = xfs_buf_iowait(bp);
-               if (error) {
-                       xfs_buf_ioerror_alert(bp,
-                                       "xfs_zero_remaining_bytes(read)");
-                       break;
-               }
+               error = xfs_buf_read_uncached(XFS_IS_REALTIME_INODE(ip) ?
+                               mp->m_rtdev_targp : mp->m_ddev_targp,
+                               xfs_fsb_to_db(ip, imap.br_startblock),
+                               BTOBB(mp->m_sb.sb_blocksize),
+                               0, &bp, NULL);
+               if (error)
+                       return error;
+
                memset(bp->b_addr +
-                       (offset - XFS_FSB_TO_B(mp, imap.br_startoff)),
-                     0, lastoffset - offset + 1);
-               XFS_BUF_UNDONE(bp);
-               XFS_BUF_UNREAD(bp);
-               XFS_BUF_WRITE(bp);
-
-               if (XFS_FORCED_SHUTDOWN(mp)) {
-                       error = -EIO;
-                       break;
-               }
-               xfs_buf_iorequest(bp);
-               error = xfs_buf_iowait(bp);
-               if (error) {
-                       xfs_buf_ioerror_alert(bp,
-                                       "xfs_zero_remaining_bytes(write)");
-                       break;
-               }
+                               (offset - XFS_FSB_TO_B(mp, imap.br_startoff)),
+                      0, lastoffset - offset + 1);
+
+               error = xfs_bwrite(bp);
+               xfs_buf_relse(bp);
+               if (error)
+                       return error;
        }
-       xfs_buf_free(bp);
        return error;
 }
 
@@ -1205,6 +1179,7 @@ xfs_free_file_space(
        xfs_bmap_free_t         free_list;
        xfs_bmbt_irec_t         imap;
        xfs_off_t               ioffset;
+       xfs_off_t               iendoffset;
        xfs_extlen_t            mod=0;
        xfs_mount_t             *mp;
        int                     nimap;
@@ -1233,12 +1208,13 @@ xfs_free_file_space(
        inode_dio_wait(VFS_I(ip));
 
        rounding = max_t(xfs_off_t, 1 << mp->m_sb.sb_blocklog, PAGE_CACHE_SIZE);
-       ioffset = offset & ~(rounding - 1);
-       error = filemap_write_and_wait_range(VFS_I(ip)->i_mapping,
-                                             ioffset, -1);
+       ioffset = round_down(offset, rounding);
+       iendoffset = round_up(offset + len, rounding) - 1;
+       error = filemap_write_and_wait_range(VFS_I(ip)->i_mapping, ioffset,
+                                            iendoffset);
        if (error)
                goto out;
-       truncate_pagecache_range(VFS_I(ip), ioffset, -1);
+       truncate_pagecache_range(VFS_I(ip), ioffset, iendoffset);
 
        /*
         * Need to zero the stuff we're not freeing, on disk.
@@ -1392,14 +1368,14 @@ xfs_zero_file_space(
 
        if (start_boundary < end_boundary - 1) {
                /*
-                * punch out delayed allocation blocks and the page cache over
-                * the conversion range
+                * Writeback the range to ensure any inode size updates due to
+                * appending writes make it to disk (otherwise we could just
+                * punch out the delalloc blocks).
                 */
-               xfs_ilock(ip, XFS_ILOCK_EXCL);
-               error = xfs_bmap_punch_delalloc_range(ip,
-                               XFS_B_TO_FSBT(mp, start_boundary),
-                               XFS_B_TO_FSB(mp, end_boundary - start_boundary));
-               xfs_iunlock(ip, XFS_ILOCK_EXCL);
+               error = filemap_write_and_wait_range(VFS_I(ip)->i_mapping,
+                               start_boundary, end_boundary - 1);
+               if (error)
+                       goto out;
                truncate_pagecache_range(VFS_I(ip), start_boundary,
                                         end_boundary - 1);
 
@@ -1456,41 +1432,47 @@ xfs_collapse_file_space(
        struct xfs_mount        *mp = ip->i_mount;
        struct xfs_trans        *tp;
        int                     error;
-       xfs_extnum_t            current_ext = 0;
        struct xfs_bmap_free    free_list;
        xfs_fsblock_t           first_block;
        int                     committed;
        xfs_fileoff_t           start_fsb;
+       xfs_fileoff_t           next_fsb;
        xfs_fileoff_t           shift_fsb;
 
        ASSERT(xfs_isilocked(ip, XFS_IOLOCK_EXCL));
 
        trace_xfs_collapse_file_space(ip);
 
-       start_fsb = XFS_B_TO_FSB(mp, offset + len);
+       next_fsb = XFS_B_TO_FSB(mp, offset + len);
        shift_fsb = XFS_B_TO_FSB(mp, len);
 
-       /*
-        * Writeback the entire file and force remove any post-eof blocks. The
-        * writeback prevents changes to the extent list via concurrent
-        * writeback and the eofblocks trim prevents the extent shift algorithm
-        * from running into a post-eof delalloc extent.
-        *
-        * XXX: This is a temporary fix until the extent shift loop below is
-        * converted to use offsets and lookups within the ILOCK rather than
-        * carrying around the index into the extent list for the next
-        * iteration.
-        */
-       error = filemap_write_and_wait(VFS_I(ip)->i_mapping);
+       error = xfs_free_file_space(ip, offset, len);
        if (error)
                return error;
+
+       /*
+        * Trim eofblocks to avoid shifting uninitialized post-eof preallocation
+        * into the accessible region of the file.
+        */
        if (xfs_can_free_eofblocks(ip, true)) {
                error = xfs_free_eofblocks(mp, ip, false);
                if (error)
                        return error;
        }
 
-       error = xfs_free_file_space(ip, offset, len);
+       /*
+        * Writeback and invalidate cache for the remainder of the file as we're
+        * about to shift down every extent from the collapse range to EOF. The
+        * free of the collapse range above might have already done some of
+        * this, but we shouldn't rely on it to do anything outside of the range
+        * that was freed.
+        */
+       error = filemap_write_and_wait_range(VFS_I(ip)->i_mapping,
+                                            offset + len, -1);
+       if (error)
+               return error;
+       error = invalidate_inode_pages2_range(VFS_I(ip)->i_mapping,
+                                       (offset + len) >> PAGE_CACHE_SHIFT, -1);
        if (error)
                return error;
 
@@ -1525,10 +1507,10 @@ xfs_collapse_file_space(
                 * We are using the write transaction in which max 2 bmbt
                 * updates are allowed
                 */
-               error = xfs_bmap_shift_extents(tp, ip, &done, start_fsb,
-                                              shift_fsb, &current_ext,
-                                              &first_block, &free_list,
-                                              XFS_BMAP_MAX_SHIFT_EXTENTS);
+               start_fsb = next_fsb;
+               error = xfs_bmap_shift_extents(tp, ip, start_fsb, shift_fsb,
+                               &done, &next_fsb, &first_block, &free_list,
+                               XFS_BMAP_MAX_SHIFT_EXTENTS);
                if (error)
                        goto out;
 
@@ -1638,7 +1620,7 @@ xfs_swap_extents_check_format(
        return 0;
 }
 
-int
+static int
 xfs_swap_extent_flush(
        struct xfs_inode        *ip)
 {
index cd7b8ca9b06410c5d34e92161906532a6221ef66..017b6afe340b891db5b487b6c30740f08613ff2b 100644 (file)
@@ -623,10 +623,11 @@ _xfs_buf_read(
        bp->b_flags &= ~(XBF_WRITE | XBF_ASYNC | XBF_READ_AHEAD);
        bp->b_flags |= flags & (XBF_READ | XBF_ASYNC | XBF_READ_AHEAD);
 
-       xfs_buf_iorequest(bp);
-       if (flags & XBF_ASYNC)
+       if (flags & XBF_ASYNC) {
+               xfs_buf_submit(bp);
                return 0;
-       return xfs_buf_iowait(bp);
+       }
+       return xfs_buf_submit_wait(bp);
 }
 
 xfs_buf_t *
@@ -687,34 +688,39 @@ xfs_buf_readahead_map(
  * Read an uncached buffer from disk. Allocates and returns a locked
  * buffer containing the disk contents or nothing.
  */
-struct xfs_buf *
+int
 xfs_buf_read_uncached(
        struct xfs_buftarg      *target,
        xfs_daddr_t             daddr,
        size_t                  numblks,
        int                     flags,
+       struct xfs_buf          **bpp,
        const struct xfs_buf_ops *ops)
 {
        struct xfs_buf          *bp;
 
+       *bpp = NULL;
+
        bp = xfs_buf_get_uncached(target, numblks, flags);
        if (!bp)
-               return NULL;
+               return -ENOMEM;
 
        /* set up the buffer for a read IO */
        ASSERT(bp->b_map_count == 1);
-       bp->b_bn = daddr;
+       bp->b_bn = XFS_BUF_DADDR_NULL;  /* always null for uncached buffers */
        bp->b_maps[0].bm_bn = daddr;
        bp->b_flags |= XBF_READ;
        bp->b_ops = ops;
 
-       if (XFS_FORCED_SHUTDOWN(target->bt_mount)) {
+       xfs_buf_submit_wait(bp);
+       if (bp->b_error) {
+               int     error = bp->b_error;
                xfs_buf_relse(bp);
-               return NULL;
+               return error;
        }
-       xfs_buf_iorequest(bp);
-       xfs_buf_iowait(bp);
-       return bp;
+
+       *bpp = bp;
+       return 0;
 }
 
 /*
@@ -998,53 +1004,56 @@ xfs_buf_wait_unpin(
  *     Buffer Utility Routines
  */
 
-STATIC void
-xfs_buf_iodone_work(
-       struct work_struct      *work)
+void
+xfs_buf_ioend(
+       struct xfs_buf  *bp)
 {
-       struct xfs_buf          *bp =
-               container_of(work, xfs_buf_t, b_iodone_work);
-       bool                    read = !!(bp->b_flags & XBF_READ);
+       bool            read = bp->b_flags & XBF_READ;
+
+       trace_xfs_buf_iodone(bp, _RET_IP_);
 
        bp->b_flags &= ~(XBF_READ | XBF_WRITE | XBF_READ_AHEAD);
 
-       /* only validate buffers that were read without errors */
-       if (read && bp->b_ops && !bp->b_error && (bp->b_flags & XBF_DONE))
+       /*
+        * Pull in IO completion errors now. We are guaranteed to be running
+        * single threaded, so we don't need the lock to read b_io_error.
+        */
+       if (!bp->b_error && bp->b_io_error)
+               xfs_buf_ioerror(bp, bp->b_io_error);
+
+       /* Only validate buffers that were read without errors */
+       if (read && !bp->b_error && bp->b_ops) {
+               ASSERT(!bp->b_iodone);
                bp->b_ops->verify_read(bp);
+       }
+
+       if (!bp->b_error)
+               bp->b_flags |= XBF_DONE;
 
        if (bp->b_iodone)
                (*(bp->b_iodone))(bp);
        else if (bp->b_flags & XBF_ASYNC)
                xfs_buf_relse(bp);
-       else {
-               ASSERT(read && bp->b_ops);
+       else
                complete(&bp->b_iowait);
-       }
 }
 
-void
-xfs_buf_ioend(
-       struct xfs_buf  *bp,
-       int             schedule)
+static void
+xfs_buf_ioend_work(
+       struct work_struct      *work)
 {
-       bool            read = !!(bp->b_flags & XBF_READ);
-
-       trace_xfs_buf_iodone(bp, _RET_IP_);
+       struct xfs_buf          *bp =
+               container_of(work, xfs_buf_t, b_iodone_work);
 
-       if (bp->b_error == 0)
-               bp->b_flags |= XBF_DONE;
+       xfs_buf_ioend(bp);
+}
 
-       if (bp->b_iodone || (read && bp->b_ops) || (bp->b_flags & XBF_ASYNC)) {
-               if (schedule) {
-                       INIT_WORK(&bp->b_iodone_work, xfs_buf_iodone_work);
-                       queue_work(xfslogd_workqueue, &bp->b_iodone_work);
-               } else {
-                       xfs_buf_iodone_work(&bp->b_iodone_work);
-               }
-       } else {
-               bp->b_flags &= ~(XBF_READ | XBF_WRITE | XBF_READ_AHEAD);
-               complete(&bp->b_iowait);
-       }
+void
+xfs_buf_ioend_async(
+       struct xfs_buf  *bp)
+{
+       INIT_WORK(&bp->b_iodone_work, xfs_buf_ioend_work);
+       queue_work(xfslogd_workqueue, &bp->b_iodone_work);
 }
 
 void
@@ -1067,96 +1076,6 @@ xfs_buf_ioerror_alert(
                (__uint64_t)XFS_BUF_ADDR(bp), func, -bp->b_error, bp->b_length);
 }
 
-/*
- * Called when we want to stop a buffer from getting written or read.
- * We attach the EIO error, muck with its flags, and call xfs_buf_ioend
- * so that the proper iodone callbacks get called.
- */
-STATIC int
-xfs_bioerror(
-       xfs_buf_t *bp)
-{
-#ifdef XFSERRORDEBUG
-       ASSERT(XFS_BUF_ISREAD(bp) || bp->b_iodone);
-#endif
-
-       /*
-        * No need to wait until the buffer is unpinned, we aren't flushing it.
-        */
-       xfs_buf_ioerror(bp, -EIO);
-
-       /*
-        * We're calling xfs_buf_ioend, so delete XBF_DONE flag.
-        */
-       XFS_BUF_UNREAD(bp);
-       XFS_BUF_UNDONE(bp);
-       xfs_buf_stale(bp);
-
-       xfs_buf_ioend(bp, 0);
-
-       return -EIO;
-}
-
-/*
- * Same as xfs_bioerror, except that we are releasing the buffer
- * here ourselves, and avoiding the xfs_buf_ioend call.
- * This is meant for userdata errors; metadata bufs come with
- * iodone functions attached, so that we can track down errors.
- */
-int
-xfs_bioerror_relse(
-       struct xfs_buf  *bp)
-{
-       int64_t         fl = bp->b_flags;
-       /*
-        * No need to wait until the buffer is unpinned.
-        * We aren't flushing it.
-        *
-        * chunkhold expects B_DONE to be set, whether
-        * we actually finish the I/O or not. We don't want to
-        * change that interface.
-        */
-       XFS_BUF_UNREAD(bp);
-       XFS_BUF_DONE(bp);
-       xfs_buf_stale(bp);
-       bp->b_iodone = NULL;
-       if (!(fl & XBF_ASYNC)) {
-               /*
-                * Mark b_error and B_ERROR _both_.
-                * Lot's of chunkcache code assumes that.
-                * There's no reason to mark error for
-                * ASYNC buffers.
-                */
-               xfs_buf_ioerror(bp, -EIO);
-               complete(&bp->b_iowait);
-       } else {
-               xfs_buf_relse(bp);
-       }
-
-       return -EIO;
-}
-
-STATIC int
-xfs_bdstrat_cb(
-       struct xfs_buf  *bp)
-{
-       if (XFS_FORCED_SHUTDOWN(bp->b_target->bt_mount)) {
-               trace_xfs_bdstrat_shut(bp, _RET_IP_);
-               /*
-                * Metadata write that didn't get logged but
-                * written delayed anyway. These aren't associated
-                * with a transaction, and can be ignored.
-                */
-               if (!bp->b_iodone && !XFS_BUF_ISREAD(bp))
-                       return xfs_bioerror_relse(bp);
-               else
-                       return xfs_bioerror(bp);
-       }
-
-       xfs_buf_iorequest(bp);
-       return 0;
-}
-
 int
 xfs_bwrite(
        struct xfs_buf          *bp)
@@ -1166,11 +1085,10 @@ xfs_bwrite(
        ASSERT(xfs_buf_islocked(bp));
 
        bp->b_flags |= XBF_WRITE;
-       bp->b_flags &= ~(XBF_ASYNC | XBF_READ | _XBF_DELWRI_Q | XBF_WRITE_FAIL);
+       bp->b_flags &= ~(XBF_ASYNC | XBF_READ | _XBF_DELWRI_Q |
+                        XBF_WRITE_FAIL | XBF_DONE);
 
-       xfs_bdstrat_cb(bp);
-
-       error = xfs_buf_iowait(bp);
+       error = xfs_buf_submit_wait(bp);
        if (error) {
                xfs_force_shutdown(bp->b_target->bt_mount,
                                   SHUTDOWN_META_IO_ERROR);
@@ -1178,15 +1096,6 @@ xfs_bwrite(
        return error;
 }
 
-STATIC void
-_xfs_buf_ioend(
-       xfs_buf_t               *bp,
-       int                     schedule)
-{
-       if (atomic_dec_and_test(&bp->b_io_remaining) == 1)
-               xfs_buf_ioend(bp, schedule);
-}
-
 STATIC void
 xfs_buf_bio_end_io(
        struct bio              *bio,
@@ -1198,13 +1107,18 @@ xfs_buf_bio_end_io(
         * don't overwrite existing errors - otherwise we can lose errors on
         * buffers that require multiple bios to complete.
         */
-       if (!bp->b_error)
-               xfs_buf_ioerror(bp, error);
+       if (error) {
+               spin_lock(&bp->b_lock);
+               if (!bp->b_io_error)
+                       bp->b_io_error = error;
+               spin_unlock(&bp->b_lock);
+       }
 
        if (!bp->b_error && xfs_buf_is_vmapped(bp) && (bp->b_flags & XBF_READ))
                invalidate_kernel_vmap_range(bp->b_addr, xfs_buf_vmap_len(bp));
 
-       _xfs_buf_ioend(bp, 1);
+       if (atomic_dec_and_test(&bp->b_io_remaining) == 1)
+               xfs_buf_ioend_async(bp);
        bio_put(bio);
 }
 
@@ -1283,7 +1197,7 @@ next_chunk:
        } else {
                /*
                 * This is guaranteed not to be the last io reference count
-                * because the caller (xfs_buf_iorequest) holds a count itself.
+                * because the caller (xfs_buf_submit) holds a count itself.
                 */
                atomic_dec(&bp->b_io_remaining);
                xfs_buf_ioerror(bp, -EIO);
@@ -1373,53 +1287,131 @@ _xfs_buf_ioapply(
        blk_finish_plug(&plug);
 }
 
+/*
+ * Asynchronous IO submission path. This transfers the buffer lock ownership and
+ * the current reference to the IO. It is not safe to reference the buffer after
+ * a call to this function unless the caller holds an additional reference
+ * itself.
+ */
 void
-xfs_buf_iorequest(
-       xfs_buf_t               *bp)
+xfs_buf_submit(
+       struct xfs_buf  *bp)
 {
-       trace_xfs_buf_iorequest(bp, _RET_IP_);
+       trace_xfs_buf_submit(bp, _RET_IP_);
 
        ASSERT(!(bp->b_flags & _XBF_DELWRI_Q));
+       ASSERT(bp->b_flags & XBF_ASYNC);
+
+       /* on shutdown we stale and complete the buffer immediately */
+       if (XFS_FORCED_SHUTDOWN(bp->b_target->bt_mount)) {
+               xfs_buf_ioerror(bp, -EIO);
+               bp->b_flags &= ~XBF_DONE;
+               xfs_buf_stale(bp);
+               xfs_buf_ioend(bp);
+               return;
+       }
 
        if (bp->b_flags & XBF_WRITE)
                xfs_buf_wait_unpin(bp);
+
+       /* clear the internal error state to avoid spurious errors */
+       bp->b_io_error = 0;
+
+       /*
+        * The caller's reference is released during I/O completion.
+        * This occurs some time after the last b_io_remaining reference is
+        * released, so after we drop our Io reference we have to have some
+        * other reference to ensure the buffer doesn't go away from underneath
+        * us. Take a direct reference to ensure we have safe access to the
+        * buffer until we are finished with it.
+        */
        xfs_buf_hold(bp);
 
        /*
-        * Set the count to 1 initially, this will stop an I/O
-        * completion callout which happens before we have started
-        * all the I/O from calling xfs_buf_ioend too early.
+        * Set the count to 1 initially, this will stop an I/O completion
+        * callout which happens before we have started all the I/O from calling
+        * xfs_buf_ioend too early.
         */
        atomic_set(&bp->b_io_remaining, 1);
        _xfs_buf_ioapply(bp);
+
        /*
-        * If _xfs_buf_ioapply failed, we'll get back here with
-        * only the reference we took above.  _xfs_buf_ioend will
-        * drop it to zero, so we'd better not queue it for later,
-        * or we'll free it before it's done.
+        * If _xfs_buf_ioapply failed, we can get back here with only the IO
+        * reference we took above. If we drop it to zero, run completion so
+        * that we don't return to the caller with completion still pending.
         */
-       _xfs_buf_ioend(bp, bp->b_error ? 0 : 1);
+       if (atomic_dec_and_test(&bp->b_io_remaining) == 1) {
+               if (bp->b_error)
+                       xfs_buf_ioend(bp);
+               else
+                       xfs_buf_ioend_async(bp);
+       }
 
        xfs_buf_rele(bp);
+       /* Note: it is not safe to reference bp now we've dropped our ref */
 }
 
 /*
- * Waits for I/O to complete on the buffer supplied.  It returns immediately if
- * no I/O is pending or there is already a pending error on the buffer, in which
- * case nothing will ever complete.  It returns the I/O error code, if any, or
- * 0 if there was no error.
+ * Synchronous buffer IO submission path, read or write.
  */
 int
-xfs_buf_iowait(
-       xfs_buf_t               *bp)
+xfs_buf_submit_wait(
+       struct xfs_buf  *bp)
 {
-       trace_xfs_buf_iowait(bp, _RET_IP_);
+       int             error;
 
-       if (!bp->b_error)
-               wait_for_completion(&bp->b_iowait);
+       trace_xfs_buf_submit_wait(bp, _RET_IP_);
+
+       ASSERT(!(bp->b_flags & (_XBF_DELWRI_Q | XBF_ASYNC)));
+
+       if (XFS_FORCED_SHUTDOWN(bp->b_target->bt_mount)) {
+               xfs_buf_ioerror(bp, -EIO);
+               xfs_buf_stale(bp);
+               bp->b_flags &= ~XBF_DONE;
+               return -EIO;
+       }
+
+       if (bp->b_flags & XBF_WRITE)
+               xfs_buf_wait_unpin(bp);
+
+       /* clear the internal error state to avoid spurious errors */
+       bp->b_io_error = 0;
+
+       /*
+        * For synchronous IO, the IO does not inherit the submitters reference
+        * count, nor the buffer lock. Hence we cannot release the reference we
+        * are about to take until we've waited for all IO completion to occur,
+        * including any xfs_buf_ioend_async() work that may be pending.
+        */
+       xfs_buf_hold(bp);
+
+       /*
+        * Set the count to 1 initially, this will stop an I/O completion
+        * callout which happens before we have started all the I/O from calling
+        * xfs_buf_ioend too early.
+        */
+       atomic_set(&bp->b_io_remaining, 1);
+       _xfs_buf_ioapply(bp);
+
+       /*
+        * make sure we run completion synchronously if it raced with us and is
+        * already complete.
+        */
+       if (atomic_dec_and_test(&bp->b_io_remaining) == 1)
+               xfs_buf_ioend(bp);
 
+       /* wait for completion before gathering the error from the buffer */
+       trace_xfs_buf_iowait(bp, _RET_IP_);
+       wait_for_completion(&bp->b_iowait);
        trace_xfs_buf_iowait_done(bp, _RET_IP_);
-       return bp->b_error;
+       error = bp->b_error;
+
+       /*
+        * all done now, we can release the hold that keeps the buffer
+        * referenced for the entire IO.
+        */
+       xfs_buf_rele(bp);
+       return error;
 }
 
 xfs_caddr_t
@@ -1813,13 +1805,19 @@ __xfs_buf_delwri_submit(
        blk_start_plug(&plug);
        list_for_each_entry_safe(bp, n, io_list, b_list) {
                bp->b_flags &= ~(_XBF_DELWRI_Q | XBF_ASYNC | XBF_WRITE_FAIL);
-               bp->b_flags |= XBF_WRITE;
+               bp->b_flags |= XBF_WRITE | XBF_ASYNC;
 
-               if (!wait) {
-                       bp->b_flags |= XBF_ASYNC;
+               /*
+                * we do all Io submission async. This means if we need to wait
+                * for IO completion we need to take an extra reference so the
+                * buffer is still valid on the other side.
+                */
+               if (wait)
+                       xfs_buf_hold(bp);
+               else
                        list_del_init(&bp->b_list);
-               }
-               xfs_bdstrat_cb(bp);
+
+               xfs_buf_submit(bp);
        }
        blk_finish_plug(&plug);
 
@@ -1866,7 +1864,10 @@ xfs_buf_delwri_submit(
                bp = list_first_entry(&io_list, struct xfs_buf, b_list);
 
                list_del_init(&bp->b_list);
-               error2 = xfs_buf_iowait(bp);
+
+               /* locking the buffer will wait for async IO completion. */
+               xfs_buf_lock(bp);
+               error2 = bp->b_error;
                xfs_buf_relse(bp);
                if (!error)
                        error = error2;
@@ -1884,7 +1885,7 @@ xfs_buf_init(void)
                goto out;
 
        xfslogd_workqueue = alloc_workqueue("xfslogd",
-                                       WQ_MEM_RECLAIM | WQ_HIGHPRI, 1);
+                               WQ_MEM_RECLAIM | WQ_HIGHPRI | WQ_FREEZABLE, 1);
        if (!xfslogd_workqueue)
                goto out_free_buf_zone;
 
index c753183900b369b9dbbb377194c3e7b0fc3c9343..82002c00af9083a8c68fd3383c177f46baa40879 100644 (file)
@@ -158,6 +158,7 @@ typedef struct xfs_buf {
        struct list_head        b_lru;          /* lru list */
        spinlock_t              b_lock;         /* internal state lock */
        unsigned int            b_state;        /* internal state flags */
+       int                     b_io_error;     /* internal IO error state */
        wait_queue_head_t       b_waiters;      /* unpin waiters */
        struct list_head        b_list;
        struct xfs_perag        *b_pag;         /* contains rbtree root */
@@ -268,9 +269,9 @@ int xfs_buf_associate_memory(struct xfs_buf *bp, void *mem, size_t length);
 
 struct xfs_buf *xfs_buf_get_uncached(struct xfs_buftarg *target, size_t numblks,
                                int flags);
-struct xfs_buf *xfs_buf_read_uncached(struct xfs_buftarg *target,
-                               xfs_daddr_t daddr, size_t numblks, int flags,
-                               const struct xfs_buf_ops *ops);
+int xfs_buf_read_uncached(struct xfs_buftarg *target, xfs_daddr_t daddr,
+                         size_t numblks, int flags, struct xfs_buf **bpp,
+                         const struct xfs_buf_ops *ops);
 void xfs_buf_hold(struct xfs_buf *bp);
 
 /* Releasing Buffers */
@@ -286,18 +287,16 @@ extern void xfs_buf_unlock(xfs_buf_t *);
 
 /* Buffer Read and Write Routines */
 extern int xfs_bwrite(struct xfs_buf *bp);
-extern void xfs_buf_ioend(xfs_buf_t *, int);
+extern void xfs_buf_ioend(struct xfs_buf *bp);
 extern void xfs_buf_ioerror(xfs_buf_t *, int);
 extern void xfs_buf_ioerror_alert(struct xfs_buf *, const char *func);
-extern void xfs_buf_iorequest(xfs_buf_t *);
-extern int xfs_buf_iowait(xfs_buf_t *);
+extern void xfs_buf_submit(struct xfs_buf *bp);
+extern int xfs_buf_submit_wait(struct xfs_buf *bp);
 extern void xfs_buf_iomove(xfs_buf_t *, size_t, size_t, void *,
                                xfs_buf_rw_t);
 #define xfs_buf_zero(bp, off, len) \
            xfs_buf_iomove((bp), (off), (len), NULL, XBRW_ZERO)
 
-extern int xfs_bioerror_relse(struct xfs_buf *);
-
 /* Buffer Utility Routines */
 extern xfs_caddr_t xfs_buf_offset(xfs_buf_t *, size_t);
 
index 76007deed31fe4455d80956f5debf82faa8baf96..f1596954332616f46ec00031a37c6888b53f1117 100644 (file)
@@ -491,7 +491,7 @@ xfs_buf_item_unpin(
                xfs_buf_ioerror(bp, -EIO);
                XFS_BUF_UNDONE(bp);
                xfs_buf_stale(bp);
-               xfs_buf_ioend(bp, 0);
+               xfs_buf_ioend(bp);
        }
 }
 
@@ -501,7 +501,7 @@ xfs_buf_item_unpin(
  * buffer being bad..
  */
 
-DEFINE_RATELIMIT_STATE(xfs_buf_write_fail_rl_state, 30 * HZ, 10);
+static DEFINE_RATELIMIT_STATE(xfs_buf_write_fail_rl_state, 30 * HZ, 10);
 
 STATIC uint
 xfs_buf_item_push(
@@ -1081,7 +1081,7 @@ xfs_buf_iodone_callbacks(
         * a way to shut the filesystem down if the writes keep failing.
         *
         * In practice we'll shut the filesystem down soon as non-transient
-        * erorrs tend to affect the whole device and a failing log write
+        * errors tend to affect the whole device and a failing log write
         * will make us give up.  But we really ought to do better here.
         */
        if (XFS_BUF_ISASYNC(bp)) {
@@ -1094,7 +1094,7 @@ xfs_buf_iodone_callbacks(
                if (!(bp->b_flags & (XBF_STALE|XBF_WRITE_FAIL))) {
                        bp->b_flags |= XBF_WRITE | XBF_ASYNC |
                                       XBF_DONE | XBF_WRITE_FAIL;
-                       xfs_buf_iorequest(bp);
+                       xfs_buf_submit(bp);
                } else {
                        xfs_buf_relse(bp);
                }
@@ -1115,7 +1115,7 @@ do_callbacks:
        xfs_buf_do_callbacks(bp);
        bp->b_fspriv = NULL;
        bp->b_iodone = NULL;
-       xfs_buf_ioend(bp, 0);
+       xfs_buf_ioend(bp);
 }
 
 /*
index de5368c803f9db192416e21032ade4535a0efcdd..eb596b4199420fa8378dcd49146640c9783037b4 100644 (file)
@@ -983,7 +983,7 @@ xfs_vm_page_mkwrite(
 
 /*
  * This type is designed to indicate the type of offset we would like
- * to search from page cache for either xfs_seek_data() or xfs_seek_hole().
+ * to search from page cache for xfs_seek_hole_data().
  */
 enum {
        HOLE_OFF = 0,
@@ -1040,7 +1040,7 @@ xfs_lookup_buffer_offset(
 /*
  * This routine is called to find out and return a data or hole offset
  * from the page cache for unwritten extents according to the desired
- * type for xfs_seek_data() or xfs_seek_hole().
+ * type for xfs_seek_hole_data().
  *
  * The argument offset is used to tell where we start to search from the
  * page cache.  Map is used to figure out the end points of the range to
@@ -1200,9 +1200,10 @@ out:
 }
 
 STATIC loff_t
-xfs_seek_data(
+xfs_seek_hole_data(
        struct file             *file,
-       loff_t                  start)
+       loff_t                  start,
+       int                     whence)
 {
        struct inode            *inode = file->f_mapping->host;
        struct xfs_inode        *ip = XFS_I(inode);
@@ -1214,6 +1215,9 @@ xfs_seek_data(
        uint                    lock;
        int                     error;
 
+       if (XFS_FORCED_SHUTDOWN(mp))
+               return -EIO;
+
        lock = xfs_ilock_data_map_shared(ip);
 
        isize = i_size_read(inode);
@@ -1228,6 +1232,7 @@ xfs_seek_data(
         */
        fsbno = XFS_B_TO_FSBT(mp, start);
        end = XFS_B_TO_FSB(mp, isize);
+
        for (;;) {
                struct xfs_bmbt_irec    map[2];
                int                     nmap = 2;
@@ -1248,29 +1253,48 @@ xfs_seek_data(
                        offset = max_t(loff_t, start,
                                       XFS_FSB_TO_B(mp, map[i].br_startoff));
 
-                       /* Landed in a data extent */
-                       if (map[i].br_startblock == DELAYSTARTBLOCK ||
-                           (map[i].br_state == XFS_EXT_NORM &&
-                            !isnullstartblock(map[i].br_startblock)))
+                       /* Landed in the hole we wanted? */
+                       if (whence == SEEK_HOLE &&
+                           map[i].br_startblock == HOLESTARTBLOCK)
+                               goto out;
+
+                       /* Landed in the data extent we wanted? */
+                       if (whence == SEEK_DATA &&
+                           (map[i].br_startblock == DELAYSTARTBLOCK ||
+                            (map[i].br_state == XFS_EXT_NORM &&
+                             !isnullstartblock(map[i].br_startblock))))
                                goto out;
 
                        /*
-                        * Landed in an unwritten extent, try to search data
-                        * from page cache.
+                        * Landed in an unwritten extent, try to search
+                        * for hole or data from page cache.
                         */
                        if (map[i].br_state == XFS_EXT_UNWRITTEN) {
                                if (xfs_find_get_desired_pgoff(inode, &map[i],
-                                                       DATA_OFF, &offset))
+                                     whence == SEEK_HOLE ? HOLE_OFF : DATA_OFF,
+                                                       &offset))
                                        goto out;
                        }
                }
 
                /*
-                * map[0] is hole or its an unwritten extent but
-                * without data in page cache.  Probably means that
-                * we are reading after EOF if nothing in map[1].
+                * We only received one extent out of the two requested. This
+                * means we've hit EOF and didn't find what we are looking for.
                 */
                if (nmap == 1) {
+                       /*
+                        * If we were looking for a hole, set offset to
+                        * the end of the file (i.e., there is an implicit
+                        * hole at the end of any file).
+                        */
+                       if (whence == SEEK_HOLE) {
+                               offset = isize;
+                               break;
+                       }
+                       /*
+                        * If we were looking for data, it's nowhere to be found
+                        */
+                       ASSERT(whence == SEEK_DATA);
                        error = -ENXIO;
                        goto out_unlock;
                }
@@ -1279,125 +1303,30 @@ xfs_seek_data(
 
                /*
                 * Nothing was found, proceed to the next round of search
-                * if reading offset not beyond or hit EOF.
+                * if the next reading offset is not at or beyond EOF.
                 */
                fsbno = map[i - 1].br_startoff + map[i - 1].br_blockcount;
                start = XFS_FSB_TO_B(mp, fsbno);
                if (start >= isize) {
+                       if (whence == SEEK_HOLE) {
+                               offset = isize;
+                               break;
+                       }
+                       ASSERT(whence == SEEK_DATA);
                        error = -ENXIO;
                        goto out_unlock;
                }
        }
 
-out:
-       offset = vfs_setpos(file, offset, inode->i_sb->s_maxbytes);
-
-out_unlock:
-       xfs_iunlock(ip, lock);
-
-       if (error)
-               return error;
-       return offset;
-}
-
-STATIC loff_t
-xfs_seek_hole(
-       struct file             *file,
-       loff_t                  start)
-{
-       struct inode            *inode = file->f_mapping->host;
-       struct xfs_inode        *ip = XFS_I(inode);
-       struct xfs_mount        *mp = ip->i_mount;
-       loff_t                  uninitialized_var(offset);
-       xfs_fsize_t             isize;
-       xfs_fileoff_t           fsbno;
-       xfs_filblks_t           end;
-       uint                    lock;
-       int                     error;
-
-       if (XFS_FORCED_SHUTDOWN(mp))
-               return -EIO;
-
-       lock = xfs_ilock_data_map_shared(ip);
-
-       isize = i_size_read(inode);
-       if (start >= isize) {
-               error = -ENXIO;
-               goto out_unlock;
-       }
-
-       fsbno = XFS_B_TO_FSBT(mp, start);
-       end = XFS_B_TO_FSB(mp, isize);
-
-       for (;;) {
-               struct xfs_bmbt_irec    map[2];
-               int                     nmap = 2;
-               unsigned int            i;
-
-               error = xfs_bmapi_read(ip, fsbno, end - fsbno, map, &nmap,
-                                      XFS_BMAPI_ENTIRE);
-               if (error)
-                       goto out_unlock;
-
-               /* No extents at given offset, must be beyond EOF */
-               if (nmap == 0) {
-                       error = -ENXIO;
-                       goto out_unlock;
-               }
-
-               for (i = 0; i < nmap; i++) {
-                       offset = max_t(loff_t, start,
-                                      XFS_FSB_TO_B(mp, map[i].br_startoff));
-
-                       /* Landed in a hole */
-                       if (map[i].br_startblock == HOLESTARTBLOCK)
-                               goto out;
-
-                       /*
-                        * Landed in an unwritten extent, try to search hole
-                        * from page cache.
-                        */
-                       if (map[i].br_state == XFS_EXT_UNWRITTEN) {
-                               if (xfs_find_get_desired_pgoff(inode, &map[i],
-                                                       HOLE_OFF, &offset))
-                                       goto out;
-                       }
-               }
-
-               /*
-                * map[0] contains data or its unwritten but contains
-                * data in page cache, probably means that we are
-                * reading after EOF.  We should fix offset to point
-                * to the end of the file(i.e., there is an implicit
-                * hole at the end of any file).
-                */
-               if (nmap == 1) {
-                       offset = isize;
-                       break;
-               }
-
-               ASSERT(i > 1);
-
-               /*
-                * Both mappings contains data, proceed to the next round of
-                * search if the current reading offset not beyond or hit EOF.
-                */
-               fsbno = map[i - 1].br_startoff + map[i - 1].br_blockcount;
-               start = XFS_FSB_TO_B(mp, fsbno);
-               if (start >= isize) {
-                       offset = isize;
-                       break;
-               }
-       }
-
 out:
        /*
-        * At this point, we must have found a hole.  However, the returned
+        * If at this point we have found the hole we wanted, the returned
         * offset may be bigger than the file size as it may be aligned to
-        * page boundary for unwritten extents, we need to deal with this
+        * page boundary for unwritten extents.  We need to deal with this
         * situation in particular.
         */
-       offset = min_t(loff_t, offset, isize);
+       if (whence == SEEK_HOLE)
+               offset = min_t(loff_t, offset, isize);
        offset = vfs_setpos(file, offset, inode->i_sb->s_maxbytes);
 
 out_unlock:
@@ -1412,17 +1341,16 @@ STATIC loff_t
 xfs_file_llseek(
        struct file     *file,
        loff_t          offset,
-       int             origin)
+       int             whence)
 {
-       switch (origin) {
+       switch (whence) {
        case SEEK_END:
        case SEEK_CUR:
        case SEEK_SET:
-               return generic_file_llseek(file, offset, origin);
-       case SEEK_DATA:
-               return xfs_seek_data(file, offset);
+               return generic_file_llseek(file, offset, whence);
        case SEEK_HOLE:
-               return xfs_seek_hole(file, offset);
+       case SEEK_DATA:
+               return xfs_seek_hole_data(file, offset, whence);
        default:
                return -EINVAL;
        }
index f91de1ef05e1024b24e2f13046f828f3be497d15..c05ac8b70fa9a394232df75bffc50a7808c34e14 100644 (file)
@@ -172,16 +172,11 @@ xfs_growfs_data_private(
        if ((error = xfs_sb_validate_fsb_count(&mp->m_sb, nb)))
                return error;
        dpct = pct - mp->m_sb.sb_imax_pct;
-       bp = xfs_buf_read_uncached(mp->m_ddev_targp,
+       error = xfs_buf_read_uncached(mp->m_ddev_targp,
                                XFS_FSB_TO_BB(mp, nb) - XFS_FSS_TO_BB(mp, 1),
-                               XFS_FSS_TO_BB(mp, 1), 0, NULL);
-       if (!bp)
-               return -EIO;
-       if (bp->b_error) {
-               error = bp->b_error;
-               xfs_buf_relse(bp);
+                               XFS_FSS_TO_BB(mp, 1), 0, &bp, NULL);
+       if (error)
                return error;
-       }
        xfs_buf_relse(bp);
 
        new = nb;       /* use new as a temporary here */
index 5399ef222dd738b85d39096ac7db5a39ebb8c359..4d41b241298fba5031fb93e59e39e209bf36b308 100644 (file)
@@ -43,3 +43,7 @@ xfs_param_t xfs_params = {
        .fstrm_timer    = {     1,              30*100,         3600*100},
        .eofb_timer     = {     1,              300,            3600*24},
 };
+
+struct xfs_globals xfs_globals = {
+       .log_recovery_delay     =       0,      /* no delay by default */
+};
index 981b2cf519853f72c91dff609c90b78eb1626c4e..b45f7b27b5dff8e7b0b3113ea8668edc03f1a805 100644 (file)
@@ -33,7 +33,6 @@
 #include "xfs_trace.h"
 #include "xfs_icache.h"
 #include "xfs_bmap_util.h"
-#include "xfs_quota.h"
 #include "xfs_dquot_item.h"
 #include "xfs_dquot.h"
 
index fea3c92fb3f0603b5ca44bb86a5a18dcaaac6240..8ed049d1e3327fd61b1a6f1c7d1e0fea0bba77cd 100644 (file)
@@ -654,7 +654,7 @@ xfs_ialloc(
        xfs_inode_t     *ip;
        uint            flags;
        int             error;
-       timespec_t      tv;
+       struct timespec tv;
 
        /*
         * Call the space management code to pick
@@ -720,7 +720,7 @@ xfs_ialloc(
        ip->i_d.di_nextents = 0;
        ASSERT(ip->i_d.di_nblocks == 0);
 
-       nanotime(&tv);
+       tv = current_fs_time(mp->m_super);
        ip->i_d.di_mtime.t_sec = (__int32_t)tv.tv_sec;
        ip->i_d.di_mtime.t_nsec = (__int32_t)tv.tv_nsec;
        ip->i_d.di_atime = ip->i_d.di_mtime;
@@ -769,6 +769,8 @@ xfs_ialloc(
                                        di_flags |= XFS_DIFLAG_EXTSZINHERIT;
                                        ip->i_d.di_extsize = pip->i_d.di_extsize;
                                }
+                               if (pip->i_d.di_flags & XFS_DIFLAG_PROJINHERIT)
+                                       di_flags |= XFS_DIFLAG_PROJINHERIT;
                        } else if (S_ISREG(mode)) {
                                if (pip->i_d.di_flags & XFS_DIFLAG_RTINHERIT)
                                        di_flags |= XFS_DIFLAG_REALTIME;
@@ -789,8 +791,6 @@ xfs_ialloc(
                        if ((pip->i_d.di_flags & XFS_DIFLAG_NOSYMLINKS) &&
                            xfs_inherit_nosymlinks)
                                di_flags |= XFS_DIFLAG_NOSYMLINKS;
-                       if (pip->i_d.di_flags & XFS_DIFLAG_PROJINHERIT)
-                               di_flags |= XFS_DIFLAG_PROJINHERIT;
                        if ((pip->i_d.di_flags & XFS_DIFLAG_NODEFRAG) &&
                            xfs_inherit_nodefrag)
                                di_flags |= XFS_DIFLAG_NODEFRAG;
@@ -1153,9 +1153,11 @@ xfs_create(
        if (error)
                goto out_trans_cancel;
 
-       error = xfs_dir_canenter(tp, dp, name, resblks);
-       if (error)
-               goto out_trans_cancel;
+       if (!resblks) {
+               error = xfs_dir_canenter(tp, dp, name);
+               if (error)
+                       goto out_trans_cancel;
+       }
 
        /*
         * A newly created regular or special file just has one directory
@@ -1421,9 +1423,11 @@ xfs_link(
                goto error_return;
        }
 
-       error = xfs_dir_canenter(tp, tdp, target_name, resblks);
-       if (error)
-               goto error_return;
+       if (!resblks) {
+               error = xfs_dir_canenter(tp, tdp, target_name);
+               if (error)
+                       goto error_return;
+       }
 
        xfs_bmap_init(&free_list, &first_block);
 
@@ -2759,9 +2763,11 @@ xfs_rename(
                 * If there's no space reservation, check the entry will
                 * fit before actually inserting it.
                 */
-               error = xfs_dir_canenter(tp, target_dp, target_name, spaceres);
-               if (error)
-                       goto error_return;
+               if (!spaceres) {
+                       error = xfs_dir_canenter(tp, target_dp, target_name);
+                       if (error)
+                               goto error_return;
+               }
                /*
                 * If target does not exist and the rename crosses
                 * directories, adjust the target directory link count
@@ -3056,7 +3062,7 @@ cluster_corrupt_out:
                        XFS_BUF_UNDONE(bp);
                        xfs_buf_stale(bp);
                        xfs_buf_ioerror(bp, -EIO);
-                       xfs_buf_ioend(bp, 0);
+                       xfs_buf_ioend(bp);
                } else {
                        xfs_buf_stale(bp);
                        xfs_buf_relse(bp);
index c10e3fadd9af659f58d3a512e9706d93bcf123ff..9af2882e1f4c10fa8eed52512a341663e2ff33d4 100644 (file)
@@ -102,7 +102,7 @@ xfs_new_eof(struct xfs_inode *ip, xfs_fsize_t new_size)
 {
        xfs_fsize_t i_size = i_size_read(VFS_I(ip));
 
-       if (new_size > i_size)
+       if (new_size > i_size || new_size < 0)
                new_size = i_size;
        return new_size > ip->i_d.di_size ? new_size : 0;
 }
index de5a7be36e603e5525ac5ba3c49264aa7af6d5d1..63de0b0acc32305da104f51bf5d0d4b2f4172091 100644 (file)
@@ -615,7 +615,7 @@ xfs_iflush_done(
        blip = bp->b_fspriv;
        prev = NULL;
        while (blip != NULL) {
-               if (lip->li_cb != xfs_iflush_done) {
+               if (blip->li_cb != xfs_iflush_done) {
                        prev = blip;
                        blip = blip->li_bio_list;
                        continue;
index 3799695b92495a02e7a15722fbe77b842b77efa2..24c926b6fe857adde4dda4f2aceb38b32c457d1d 100644 (file)
@@ -968,8 +968,6 @@ xfs_set_diflags(
                di_flags |= XFS_DIFLAG_NOATIME;
        if (xflags & XFS_XFLAG_NODUMP)
                di_flags |= XFS_DIFLAG_NODUMP;
-       if (xflags & XFS_XFLAG_PROJINHERIT)
-               di_flags |= XFS_DIFLAG_PROJINHERIT;
        if (xflags & XFS_XFLAG_NODEFRAG)
                di_flags |= XFS_DIFLAG_NODEFRAG;
        if (xflags & XFS_XFLAG_FILESTREAM)
@@ -981,6 +979,8 @@ xfs_set_diflags(
                        di_flags |= XFS_DIFLAG_NOSYMLINKS;
                if (xflags & XFS_XFLAG_EXTSZINHERIT)
                        di_flags |= XFS_DIFLAG_EXTSZINHERIT;
+               if (xflags & XFS_XFLAG_PROJINHERIT)
+                       di_flags |= XFS_DIFLAG_PROJINHERIT;
        } else if (S_ISREG(ip->i_d.di_mode)) {
                if (xflags & XFS_XFLAG_REALTIME)
                        di_flags |= XFS_DIFLAG_REALTIME;
@@ -1231,13 +1231,25 @@ xfs_ioctl_setattr(
 
        }
 
-       if (mask & FSX_EXTSIZE)
-               ip->i_d.di_extsize = fa->fsx_extsize >> mp->m_sb.sb_blocklog;
        if (mask & FSX_XFLAGS) {
                xfs_set_diflags(ip, fa->fsx_xflags);
                xfs_diflags_to_linux(ip);
        }
 
+       /*
+        * Only set the extent size hint if we've already determined that the
+        * extent size hint should be set on the inode. If no extent size flags
+        * are set on the inode then unconditionally clear the extent size hint.
+        */
+       if (mask & FSX_EXTSIZE) {
+               int     extsize = 0;
+
+               if (ip->i_d.di_flags &
+                               (XFS_DIFLAG_EXTSIZE | XFS_DIFLAG_EXTSZINHERIT))
+                       extsize = fa->fsx_extsize >> mp->m_sb.sb_blocklog;
+               ip->i_d.di_extsize = extsize;
+       }
+
        xfs_trans_ichgtime(tp, ip, XFS_ICHGTIME_CHG);
        xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
 
@@ -1349,7 +1361,7 @@ xfs_ioc_setxflags(
 STATIC int
 xfs_getbmap_format(void **ap, struct getbmapx *bmv, int *full)
 {
-       struct getbmap __user   *base = *ap;
+       struct getbmap __user   *base = (struct getbmap __user *)*ap;
 
        /* copy only getbmap portion (not getbmapx) */
        if (copy_to_user(base, bmv, sizeof(struct getbmap)))
@@ -1380,7 +1392,7 @@ xfs_ioc_getbmap(
                bmx.bmv_iflags |= BMV_IF_NO_DMAPI_READ;
 
        error = xfs_getbmap(ip, &bmx, xfs_getbmap_format,
-                           (struct getbmap *)arg+1);
+                           (__force struct getbmap *)arg+1);
        if (error)
                return error;
 
@@ -1393,7 +1405,7 @@ xfs_ioc_getbmap(
 STATIC int
 xfs_getbmapx_format(void **ap, struct getbmapx *bmv, int *full)
 {
-       struct getbmapx __user  *base = *ap;
+       struct getbmapx __user  *base = (struct getbmapx __user *)*ap;
 
        if (copy_to_user(base, bmv, sizeof(struct getbmapx)))
                return -EFAULT;
@@ -1420,7 +1432,7 @@ xfs_ioc_getbmapx(
                return -EINVAL;
 
        error = xfs_getbmap(ip, &bmx, xfs_getbmapx_format,
-                           (struct getbmapx *)arg+1);
+                           (__force struct getbmapx *)arg+1);
        if (error)
                return error;
 
index a554646ff141479eeea453ff7899bdd8e91d92b8..94ce027e28e3df8edac1609318604b0d74877266 100644 (file)
@@ -160,6 +160,7 @@ xfs_ioctl32_bstat_copyin(
            get_user(bstat->bs_gen,     &bstat32->bs_gen)       ||
            get_user(bstat->bs_projid_lo, &bstat32->bs_projid_lo) ||
            get_user(bstat->bs_projid_hi, &bstat32->bs_projid_hi) ||
+           get_user(bstat->bs_forkoff, &bstat32->bs_forkoff)   ||
            get_user(bstat->bs_dmevmask, &bstat32->bs_dmevmask) ||
            get_user(bstat->bs_dmstate, &bstat32->bs_dmstate)   ||
            get_user(bstat->bs_aextents, &bstat32->bs_aextents))
@@ -214,6 +215,7 @@ xfs_bulkstat_one_fmt_compat(
            put_user(buffer->bs_gen,      &p32->bs_gen)         ||
            put_user(buffer->bs_projid,   &p32->bs_projid)      ||
            put_user(buffer->bs_projid_hi,      &p32->bs_projid_hi)     ||
+           put_user(buffer->bs_forkoff,  &p32->bs_forkoff)     ||
            put_user(buffer->bs_dmevmask, &p32->bs_dmevmask)    ||
            put_user(buffer->bs_dmstate,  &p32->bs_dmstate)     ||
            put_user(buffer->bs_aextents, &p32->bs_aextents))
index 80f4060e8970c5aa6b3d893edc206f3b340cc7ee..b1bb45444df8ac48008a1f784c248cfdcb663f88 100644 (file)
@@ -67,8 +67,9 @@ typedef struct compat_xfs_bstat {
        __u32           bs_gen;         /* generation count             */
        __u16           bs_projid_lo;   /* lower part of project id     */
 #define        bs_projid       bs_projid_lo    /* (previously just bs_projid)  */
+       __u16           bs_forkoff;     /* inode fork offset in bytes   */
        __u16           bs_projid_hi;   /* high part of project id      */
-       unsigned char   bs_pad[12];     /* pad space, unused            */
+       unsigned char   bs_pad[10];     /* pad space, unused            */
        __u32           bs_dmevmask;    /* DMIG event mask              */
        __u16           bs_dmstate;     /* DMIG state info              */
        __u16           bs_aextents;    /* attribute number of extents  */
index e9c47b6f5e5a97f3b100a4a6262a1c26a1b01de9..afcf3c926565f940e2986093e7e3491296466d9b 100644 (file)
@@ -404,8 +404,8 @@ xfs_quota_calc_throttle(
        int shift = 0;
        struct xfs_dquot *dq = xfs_inode_dquot(ip, type);
 
-       /* over hi wmark, squash the prealloc completely */
-       if (dq->q_res_bcount >= dq->q_prealloc_hi_wmark) {
+       /* no dq, or over hi wmark, squash the prealloc completely */
+       if (!dq || dq->q_res_bcount >= dq->q_prealloc_hi_wmark) {
                *qblocks = 0;
                *qfreesp = 0;
                return;
index 72129493e9d3563687a6606223a123692fe13a5c..ec6dcdc181ee45fc8a74bb6a018f1fbab01dc1e7 100644 (file)
@@ -849,6 +849,36 @@ xfs_setattr_size(
                return error;
        truncate_setsize(inode, newsize);
 
+       /*
+        * The "we can't serialise against page faults" pain gets worse.
+        *
+        * If the file is mapped then we have to clean the page at the old EOF
+        * when extending the file. Extending the file can expose changes the
+        * underlying page mapping (e.g. from beyond EOF to a hole or
+        * unwritten), and so on the next attempt to write to that page we need
+        * to remap it for write. i.e. we need .page_mkwrite() to be called.
+        * Hence we need to clean the page to clean the pte and so a new write
+        * fault will be triggered appropriately.
+        *
+        * If we do it before we change the inode size, then we can race with a
+        * page fault that maps the page with exactly the same problem. If we do
+        * it after we change the file size, then a new page fault can come in
+        * and allocate space before we've run the rest of the truncate
+        * transaction. That's kinda grotesque, but it's better than have data
+        * over a hole, and so that's the lesser evil that has been chosen here.
+        *
+        * The real solution, however, is to have some mechanism for locking out
+        * page faults while a truncate is in progress.
+        */
+       if (newsize > oldsize && mapping_mapped(VFS_I(ip)->i_mapping)) {
+               error = filemap_write_and_wait_range(
+                               VFS_I(ip)->i_mapping,
+                               round_down(oldsize, PAGE_CACHE_SIZE),
+                               round_up(oldsize, PAGE_CACHE_SIZE) - 1);
+               if (error)
+                       return error;
+       }
+
        tp = xfs_trans_alloc(mp, XFS_TRANS_SETATTR_SIZE);
        error = xfs_trans_reserve(tp, &M_RES(mp)->tr_itruncate, 0, 0);
        if (error)
index f71be9c68017ea993808827918201b5eff31a833..f1deb961a296a300add3a6333eebd47619a2100c 100644 (file)
@@ -639,7 +639,8 @@ next_ag:
                xfs_buf_relse(agbp);
                agbp = NULL;
                agino = 0;
-       } while (++agno < mp->m_sb.sb_agcount);
+               agno++;
+       } while (agno < mp->m_sb.sb_agcount);
 
        if (!error) {
                if (bufidx) {
index d10dc8f397c970e7dacc6ec404bf932c36d0434c..6a51619d8690a37a9c5340b85ace1b2ba44ef8fb 100644 (file)
@@ -56,7 +56,6 @@ typedef __uint64_t __psunsigned_t;
 
 #include "kmem.h"
 #include "mrlock.h"
-#include "time.h"
 #include "uuid.h"
 
 #include <linux/semaphore.h>
@@ -179,6 +178,11 @@ typedef __uint64_t __psunsigned_t;
 #define MAX(a,b)       (max(a,b))
 #define howmany(x, y)  (((x)+((y)-1))/(y))
 
+static inline void delay(long ticks)
+{
+       schedule_timeout_uninterruptible(ticks);
+}
+
 /*
  * XFS wrapper structure for sysfs support. It depends on external data
  * structures and is embedded in various internal data structures to implement
index ca4fd5bd8522ced2b17363487a1d0d39d60f4a8f..fe88ef67f93acb9bbcbf4fbee7c06747b3c8155e 100644 (file)
@@ -1678,7 +1678,7 @@ xlog_bdstrat(
        if (iclog->ic_state & XLOG_STATE_IOERROR) {
                xfs_buf_ioerror(bp, -EIO);
                xfs_buf_stale(bp);
-               xfs_buf_ioend(bp, 0);
+               xfs_buf_ioend(bp);
                /*
                 * It would seem logical to return EIO here, but we rely on
                 * the log state machine to propagate I/O errors instead of
@@ -1688,7 +1688,7 @@ xlog_bdstrat(
                return 0;
        }
 
-       xfs_buf_iorequest(bp);
+       xfs_buf_submit(bp);
        return 0;
 }
 
@@ -3867,18 +3867,17 @@ xlog_state_ioerror(
  * This is called from xfs_force_shutdown, when we're forcibly
  * shutting down the filesystem, typically because of an IO error.
  * Our main objectives here are to make sure that:
- *     a. the filesystem gets marked 'SHUTDOWN' for all interested
+ *     a. if !logerror, flush the logs to disk. Anything modified
+ *        after this is ignored.
+ *     b. the filesystem gets marked 'SHUTDOWN' for all interested
  *        parties to find out, 'atomically'.
- *     b. those who're sleeping on log reservations, pinned objects and
+ *     c. those who're sleeping on log reservations, pinned objects and
  *         other resources get woken up, and be told the bad news.
- *     c. nothing new gets queued up after (a) and (b) are done.
- *     d. if !logerror, flush the iclogs to disk, then seal them off
- *        for business.
+ *     d. nothing new gets queued up after (b) and (c) are done.
  *
- * Note: for delayed logging the !logerror case needs to flush the regions
- * held in memory out to the iclogs before flushing them to disk. This needs
- * to be done before the log is marked as shutdown, otherwise the flush to the
- * iclogs will fail.
+ * Note: for the !logerror case we need to flush the regions held in memory out
+ * to disk first. This needs to be done before the log is marked as shutdown,
+ * otherwise the iclog writes will fail.
  */
 int
 xfs_log_force_umount(
@@ -3910,16 +3909,16 @@ xfs_log_force_umount(
                ASSERT(XLOG_FORCED_SHUTDOWN(log));
                return 1;
        }
-       retval = 0;
 
        /*
-        * Flush the in memory commit item list before marking the log as
-        * being shut down. We need to do it in this order to ensure all the
-        * completed transactions are flushed to disk with the xfs_log_force()
-        * call below.
+        * Flush all the completed transactions to disk before marking the log
+        * being shut down. We need to do it in this order to ensure that
+        * completed operations are safely on disk before we shut down, and that
+        * we don't have to issue any buffer IO after the shutdown flags are set
+        * to guarantee this.
         */
        if (!logerror)
-               xlog_cil_force(log);
+               _xfs_log_force(mp, XFS_LOG_SYNC, NULL);
 
        /*
         * mark the filesystem and the as in a shutdown state and wake
@@ -3931,18 +3930,11 @@ xfs_log_force_umount(
                XFS_BUF_DONE(mp->m_sb_bp);
 
        /*
-        * This flag is sort of redundant because of the mount flag, but
-        * it's good to maintain the separation between the log and the rest
-        * of XFS.
+        * Mark the log and the iclogs with IO error flags to prevent any
+        * further log IO from being issued or completed.
         */
        log->l_flags |= XLOG_IO_ERROR;
-
-       /*
-        * If we hit a log error, we want to mark all the iclogs IOERROR
-        * while we're still holding the loglock.
-        */
-       if (logerror)
-               retval = xlog_state_ioerror(log);
+       retval = xlog_state_ioerror(log);
        spin_unlock(&log->l_icloglock);
 
        /*
@@ -3955,19 +3947,6 @@ xfs_log_force_umount(
        xlog_grant_head_wake_all(&log->l_reserve_head);
        xlog_grant_head_wake_all(&log->l_write_head);
 
-       if (!(log->l_iclog->ic_state & XLOG_STATE_IOERROR)) {
-               ASSERT(!logerror);
-               /*
-                * Force the incore logs to disk before shutting the
-                * log down completely.
-                */
-               _xfs_log_force(mp, XFS_LOG_SYNC, NULL);
-
-               spin_lock(&log->l_icloglock);
-               retval = xlog_state_ioerror(log);
-               spin_unlock(&log->l_icloglock);
-       }
-
        /*
         * Wake up everybody waiting on xfs_log_force. Wake the CIL push first
         * as if the log writes were completed. The abort handling in the log
index f6b79e5325dd4426da54b940fd1bea0ca170a6e8..f506c457011eb1970128fa637dce35500d2a4b54 100644 (file)
@@ -463,12 +463,40 @@ xlog_cil_push(
                spin_unlock(&cil->xc_push_lock);
                goto out_skip;
        }
-       spin_unlock(&cil->xc_push_lock);
 
 
        /* check for a previously pushed seqeunce */
-       if (push_seq < cil->xc_ctx->sequence)
+       if (push_seq < cil->xc_ctx->sequence) {
+               spin_unlock(&cil->xc_push_lock);
                goto out_skip;
+       }
+
+       /*
+        * We are now going to push this context, so add it to the committing
+        * list before we do anything else. This ensures that anyone waiting on
+        * this push can easily detect the difference between a "push in
+        * progress" and "CIL is empty, nothing to do".
+        *
+        * IOWs, a wait loop can now check for:
+        *      the current sequence not being found on the committing list;
+        *      an empty CIL; and
+        *      an unchanged sequence number
+        * to detect a push that had nothing to do and therefore does not need
+        * waiting on. If the CIL is not empty, we get put on the committing
+        * list before emptying the CIL and bumping the sequence number. Hence
+        * an empty CIL and an unchanged sequence number means we jumped out
+        * above after doing nothing.
+        *
+        * Hence the waiter will either find the commit sequence on the
+        * committing list or the sequence number will be unchanged and the CIL
+        * still dirty. In that latter case, the push has not yet started, and
+        * so the waiter will have to continue trying to check the CIL
+        * committing list until it is found. In extreme cases of delay, the
+        * sequence may fully commit between the attempts the wait makes to wait
+        * on the commit sequence.
+        */
+       list_add(&ctx->committing, &cil->xc_committing);
+       spin_unlock(&cil->xc_push_lock);
 
        /*
         * pull all the log vectors off the items in the CIL, and
@@ -532,7 +560,6 @@ xlog_cil_push(
         */
        spin_lock(&cil->xc_push_lock);
        cil->xc_current_sequence = new_ctx->sequence;
-       list_add(&ctx->committing, &cil->xc_committing);
        spin_unlock(&cil->xc_push_lock);
        up_write(&cil->xc_ctx_lock);
 
@@ -855,13 +882,15 @@ restart:
         * Hence by the time we have got here it our sequence may not have been
         * pushed yet. This is true if the current sequence still matches the
         * push sequence after the above wait loop and the CIL still contains
-        * dirty objects.
+        * dirty objects. This is guaranteed by the push code first adding the
+        * context to the committing list before emptying the CIL.
         *
-        * When the push occurs, it will empty the CIL and atomically increment
-        * the currect sequence past the push sequence and move it into the
-        * committing list. Of course, if the CIL is clean at the time of the
-        * push, it won't have pushed the CIL at all, so in that case we should
-        * try the push for this sequence again from the start just in case.
+        * Hence if we don't find the context in the committing list and the
+        * current sequence number is unchanged then the CIL contents are
+        * significant.  If the CIL is empty, if means there was nothing to push
+        * and that means there is nothing to wait for. If the CIL is not empty,
+        * it means we haven't yet started the push, because if it had started
+        * we would have found the context on the committing list.
         */
        if (sequence == cil->xc_current_sequence &&
            !list_empty(&cil->xc_cil)) {
index 1fd5787add9924d7ac726329f2ee88c13a90422d..00cd7f3a8f596362bd2ae4ebe19f1211ca5d3d4e 100644 (file)
@@ -193,12 +193,8 @@ xlog_bread_noalign(
        bp->b_io_length = nbblks;
        bp->b_error = 0;
 
-       if (XFS_FORCED_SHUTDOWN(log->l_mp))
-               return -EIO;
-
-       xfs_buf_iorequest(bp);
-       error = xfs_buf_iowait(bp);
-       if (error)
+       error = xfs_buf_submit_wait(bp);
+       if (error && !XFS_FORCED_SHUTDOWN(log->l_mp))
                xfs_buf_ioerror_alert(bp, __func__);
        return error;
 }
@@ -378,12 +374,14 @@ xlog_recover_iodone(
                 * We're not going to bother about retrying
                 * this during recovery. One strike!
                 */
-               xfs_buf_ioerror_alert(bp, __func__);
-               xfs_force_shutdown(bp->b_target->bt_mount,
-                                       SHUTDOWN_META_IO_ERROR);
+               if (!XFS_FORCED_SHUTDOWN(bp->b_target->bt_mount)) {
+                       xfs_buf_ioerror_alert(bp, __func__);
+                       xfs_force_shutdown(bp->b_target->bt_mount,
+                                               SHUTDOWN_META_IO_ERROR);
+               }
        }
        bp->b_iodone = NULL;
-       xfs_buf_ioend(bp, 0);
+       xfs_buf_ioend(bp);
 }
 
 /*
@@ -1445,160 +1443,6 @@ xlog_clear_stale_blocks(
  ******************************************************************************
  */
 
-STATIC xlog_recover_t *
-xlog_recover_find_tid(
-       struct hlist_head       *head,
-       xlog_tid_t              tid)
-{
-       xlog_recover_t          *trans;
-
-       hlist_for_each_entry(trans, head, r_list) {
-               if (trans->r_log_tid == tid)
-                       return trans;
-       }
-       return NULL;
-}
-
-STATIC void
-xlog_recover_new_tid(
-       struct hlist_head       *head,
-       xlog_tid_t              tid,
-       xfs_lsn_t               lsn)
-{
-       xlog_recover_t          *trans;
-
-       trans = kmem_zalloc(sizeof(xlog_recover_t), KM_SLEEP);
-       trans->r_log_tid   = tid;
-       trans->r_lsn       = lsn;
-       INIT_LIST_HEAD(&trans->r_itemq);
-
-       INIT_HLIST_NODE(&trans->r_list);
-       hlist_add_head(&trans->r_list, head);
-}
-
-STATIC void
-xlog_recover_add_item(
-       struct list_head        *head)
-{
-       xlog_recover_item_t     *item;
-
-       item = kmem_zalloc(sizeof(xlog_recover_item_t), KM_SLEEP);
-       INIT_LIST_HEAD(&item->ri_list);
-       list_add_tail(&item->ri_list, head);
-}
-
-STATIC int
-xlog_recover_add_to_cont_trans(
-       struct xlog             *log,
-       struct xlog_recover     *trans,
-       xfs_caddr_t             dp,
-       int                     len)
-{
-       xlog_recover_item_t     *item;
-       xfs_caddr_t             ptr, old_ptr;
-       int                     old_len;
-
-       if (list_empty(&trans->r_itemq)) {
-               /* finish copying rest of trans header */
-               xlog_recover_add_item(&trans->r_itemq);
-               ptr = (xfs_caddr_t) &trans->r_theader +
-                               sizeof(xfs_trans_header_t) - len;
-               memcpy(ptr, dp, len); /* d, s, l */
-               return 0;
-       }
-       /* take the tail entry */
-       item = list_entry(trans->r_itemq.prev, xlog_recover_item_t, ri_list);
-
-       old_ptr = item->ri_buf[item->ri_cnt-1].i_addr;
-       old_len = item->ri_buf[item->ri_cnt-1].i_len;
-
-       ptr = kmem_realloc(old_ptr, len+old_len, old_len, KM_SLEEP);
-       memcpy(&ptr[old_len], dp, len); /* d, s, l */
-       item->ri_buf[item->ri_cnt-1].i_len += len;
-       item->ri_buf[item->ri_cnt-1].i_addr = ptr;
-       trace_xfs_log_recover_item_add_cont(log, trans, item, 0);
-       return 0;
-}
-
-/*
- * The next region to add is the start of a new region.  It could be
- * a whole region or it could be the first part of a new region.  Because
- * of this, the assumption here is that the type and size fields of all
- * format structures fit into the first 32 bits of the structure.
- *
- * This works because all regions must be 32 bit aligned.  Therefore, we
- * either have both fields or we have neither field.  In the case we have
- * neither field, the data part of the region is zero length.  We only have
- * a log_op_header and can throw away the header since a new one will appear
- * later.  If we have at least 4 bytes, then we can determine how many regions
- * will appear in the current log item.
- */
-STATIC int
-xlog_recover_add_to_trans(
-       struct xlog             *log,
-       struct xlog_recover     *trans,
-       xfs_caddr_t             dp,
-       int                     len)
-{
-       xfs_inode_log_format_t  *in_f;                  /* any will do */
-       xlog_recover_item_t     *item;
-       xfs_caddr_t             ptr;
-
-       if (!len)
-               return 0;
-       if (list_empty(&trans->r_itemq)) {
-               /* we need to catch log corruptions here */
-               if (*(uint *)dp != XFS_TRANS_HEADER_MAGIC) {
-                       xfs_warn(log->l_mp, "%s: bad header magic number",
-                               __func__);
-                       ASSERT(0);
-                       return -EIO;
-               }
-               if (len == sizeof(xfs_trans_header_t))
-                       xlog_recover_add_item(&trans->r_itemq);
-               memcpy(&trans->r_theader, dp, len); /* d, s, l */
-               return 0;
-       }
-
-       ptr = kmem_alloc(len, KM_SLEEP);
-       memcpy(ptr, dp, len);
-       in_f = (xfs_inode_log_format_t *)ptr;
-
-       /* take the tail entry */
-       item = list_entry(trans->r_itemq.prev, xlog_recover_item_t, ri_list);
-       if (item->ri_total != 0 &&
-            item->ri_total == item->ri_cnt) {
-               /* tail item is in use, get a new one */
-               xlog_recover_add_item(&trans->r_itemq);
-               item = list_entry(trans->r_itemq.prev,
-                                       xlog_recover_item_t, ri_list);
-       }
-
-       if (item->ri_total == 0) {              /* first region to be added */
-               if (in_f->ilf_size == 0 ||
-                   in_f->ilf_size > XLOG_MAX_REGIONS_IN_ITEM) {
-                       xfs_warn(log->l_mp,
-               "bad number of regions (%d) in inode log format",
-                                 in_f->ilf_size);
-                       ASSERT(0);
-                       kmem_free(ptr);
-                       return -EIO;
-               }
-
-               item->ri_total = in_f->ilf_size;
-               item->ri_buf =
-                       kmem_zalloc(item->ri_total * sizeof(xfs_log_iovec_t),
-                                   KM_SLEEP);
-       }
-       ASSERT(item->ri_total > item->ri_cnt);
-       /* Description region is ri_buf[0] */
-       item->ri_buf[item->ri_cnt].i_addr = ptr;
-       item->ri_buf[item->ri_cnt].i_len  = len;
-       item->ri_cnt++;
-       trace_xfs_log_recover_item_add(log, trans, item, 0);
-       return 0;
-}
-
 /*
  * Sort the log items in the transaction.
  *
@@ -3254,31 +3098,6 @@ xlog_recover_do_icreate_pass2(
        return 0;
 }
 
-/*
- * Free up any resources allocated by the transaction
- *
- * Remember that EFIs, EFDs, and IUNLINKs are handled later.
- */
-STATIC void
-xlog_recover_free_trans(
-       struct xlog_recover     *trans)
-{
-       xlog_recover_item_t     *item, *n;
-       int                     i;
-
-       list_for_each_entry_safe(item, n, &trans->r_itemq, ri_list) {
-               /* Free the regions in the item. */
-               list_del(&item->ri_list);
-               for (i = 0; i < item->ri_cnt; i++)
-                       kmem_free(item->ri_buf[i].i_addr);
-               /* Free the item itself */
-               kmem_free(item->ri_buf);
-               kmem_free(item);
-       }
-       /* Free the transaction recover structure */
-       kmem_free(trans);
-}
-
 STATIC void
 xlog_recover_buffer_ra_pass2(
        struct xlog                     *log,
@@ -3528,21 +3347,308 @@ out:
        if (!list_empty(&done_list))
                list_splice_init(&done_list, &trans->r_itemq);
 
-       xlog_recover_free_trans(trans);
-
        error2 = xfs_buf_delwri_submit(&buffer_list);
        return error ? error : error2;
 }
 
+STATIC void
+xlog_recover_add_item(
+       struct list_head        *head)
+{
+       xlog_recover_item_t     *item;
+
+       item = kmem_zalloc(sizeof(xlog_recover_item_t), KM_SLEEP);
+       INIT_LIST_HEAD(&item->ri_list);
+       list_add_tail(&item->ri_list, head);
+}
+
 STATIC int
-xlog_recover_unmount_trans(
-       struct xlog             *log)
+xlog_recover_add_to_cont_trans(
+       struct xlog             *log,
+       struct xlog_recover     *trans,
+       xfs_caddr_t             dp,
+       int                     len)
 {
-       /* Do nothing now */
-       xfs_warn(log->l_mp, "%s: Unmount LR", __func__);
+       xlog_recover_item_t     *item;
+       xfs_caddr_t             ptr, old_ptr;
+       int                     old_len;
+
+       if (list_empty(&trans->r_itemq)) {
+               /* finish copying rest of trans header */
+               xlog_recover_add_item(&trans->r_itemq);
+               ptr = (xfs_caddr_t) &trans->r_theader +
+                               sizeof(xfs_trans_header_t) - len;
+               memcpy(ptr, dp, len);
+               return 0;
+       }
+       /* take the tail entry */
+       item = list_entry(trans->r_itemq.prev, xlog_recover_item_t, ri_list);
+
+       old_ptr = item->ri_buf[item->ri_cnt-1].i_addr;
+       old_len = item->ri_buf[item->ri_cnt-1].i_len;
+
+       ptr = kmem_realloc(old_ptr, len+old_len, old_len, KM_SLEEP);
+       memcpy(&ptr[old_len], dp, len);
+       item->ri_buf[item->ri_cnt-1].i_len += len;
+       item->ri_buf[item->ri_cnt-1].i_addr = ptr;
+       trace_xfs_log_recover_item_add_cont(log, trans, item, 0);
+       return 0;
+}
+
+/*
+ * The next region to add is the start of a new region.  It could be
+ * a whole region or it could be the first part of a new region.  Because
+ * of this, the assumption here is that the type and size fields of all
+ * format structures fit into the first 32 bits of the structure.
+ *
+ * This works because all regions must be 32 bit aligned.  Therefore, we
+ * either have both fields or we have neither field.  In the case we have
+ * neither field, the data part of the region is zero length.  We only have
+ * a log_op_header and can throw away the header since a new one will appear
+ * later.  If we have at least 4 bytes, then we can determine how many regions
+ * will appear in the current log item.
+ */
+STATIC int
+xlog_recover_add_to_trans(
+       struct xlog             *log,
+       struct xlog_recover     *trans,
+       xfs_caddr_t             dp,
+       int                     len)
+{
+       xfs_inode_log_format_t  *in_f;                  /* any will do */
+       xlog_recover_item_t     *item;
+       xfs_caddr_t             ptr;
+
+       if (!len)
+               return 0;
+       if (list_empty(&trans->r_itemq)) {
+               /* we need to catch log corruptions here */
+               if (*(uint *)dp != XFS_TRANS_HEADER_MAGIC) {
+                       xfs_warn(log->l_mp, "%s: bad header magic number",
+                               __func__);
+                       ASSERT(0);
+                       return -EIO;
+               }
+               if (len == sizeof(xfs_trans_header_t))
+                       xlog_recover_add_item(&trans->r_itemq);
+               memcpy(&trans->r_theader, dp, len);
+               return 0;
+       }
+
+       ptr = kmem_alloc(len, KM_SLEEP);
+       memcpy(ptr, dp, len);
+       in_f = (xfs_inode_log_format_t *)ptr;
+
+       /* take the tail entry */
+       item = list_entry(trans->r_itemq.prev, xlog_recover_item_t, ri_list);
+       if (item->ri_total != 0 &&
+            item->ri_total == item->ri_cnt) {
+               /* tail item is in use, get a new one */
+               xlog_recover_add_item(&trans->r_itemq);
+               item = list_entry(trans->r_itemq.prev,
+                                       xlog_recover_item_t, ri_list);
+       }
+
+       if (item->ri_total == 0) {              /* first region to be added */
+               if (in_f->ilf_size == 0 ||
+                   in_f->ilf_size > XLOG_MAX_REGIONS_IN_ITEM) {
+                       xfs_warn(log->l_mp,
+               "bad number of regions (%d) in inode log format",
+                                 in_f->ilf_size);
+                       ASSERT(0);
+                       kmem_free(ptr);
+                       return -EIO;
+               }
+
+               item->ri_total = in_f->ilf_size;
+               item->ri_buf =
+                       kmem_zalloc(item->ri_total * sizeof(xfs_log_iovec_t),
+                                   KM_SLEEP);
+       }
+       ASSERT(item->ri_total > item->ri_cnt);
+       /* Description region is ri_buf[0] */
+       item->ri_buf[item->ri_cnt].i_addr = ptr;
+       item->ri_buf[item->ri_cnt].i_len  = len;
+       item->ri_cnt++;
+       trace_xfs_log_recover_item_add(log, trans, item, 0);
        return 0;
 }
 
+/*
+ * Free up any resources allocated by the transaction
+ *
+ * Remember that EFIs, EFDs, and IUNLINKs are handled later.
+ */
+STATIC void
+xlog_recover_free_trans(
+       struct xlog_recover     *trans)
+{
+       xlog_recover_item_t     *item, *n;
+       int                     i;
+
+       list_for_each_entry_safe(item, n, &trans->r_itemq, ri_list) {
+               /* Free the regions in the item. */
+               list_del(&item->ri_list);
+               for (i = 0; i < item->ri_cnt; i++)
+                       kmem_free(item->ri_buf[i].i_addr);
+               /* Free the item itself */
+               kmem_free(item->ri_buf);
+               kmem_free(item);
+       }
+       /* Free the transaction recover structure */
+       kmem_free(trans);
+}
+
+/*
+ * On error or completion, trans is freed.
+ */
+STATIC int
+xlog_recovery_process_trans(
+       struct xlog             *log,
+       struct xlog_recover     *trans,
+       xfs_caddr_t             dp,
+       unsigned int            len,
+       unsigned int            flags,
+       int                     pass)
+{
+       int                     error = 0;
+       bool                    freeit = false;
+
+       /* mask off ophdr transaction container flags */
+       flags &= ~XLOG_END_TRANS;
+       if (flags & XLOG_WAS_CONT_TRANS)
+               flags &= ~XLOG_CONTINUE_TRANS;
+
+       /*
+        * Callees must not free the trans structure. We'll decide if we need to
+        * free it or not based on the operation being done and it's result.
+        */
+       switch (flags) {
+       /* expected flag values */
+       case 0:
+       case XLOG_CONTINUE_TRANS:
+               error = xlog_recover_add_to_trans(log, trans, dp, len);
+               break;
+       case XLOG_WAS_CONT_TRANS:
+               error = xlog_recover_add_to_cont_trans(log, trans, dp, len);
+               break;
+       case XLOG_COMMIT_TRANS:
+               error = xlog_recover_commit_trans(log, trans, pass);
+               /* success or fail, we are now done with this transaction. */
+               freeit = true;
+               break;
+
+       /* unexpected flag values */
+       case XLOG_UNMOUNT_TRANS:
+               /* just skip trans */
+               xfs_warn(log->l_mp, "%s: Unmount LR", __func__);
+               freeit = true;
+               break;
+       case XLOG_START_TRANS:
+       default:
+               xfs_warn(log->l_mp, "%s: bad flag 0x%x", __func__, flags);
+               ASSERT(0);
+               error = -EIO;
+               break;
+       }
+       if (error || freeit)
+               xlog_recover_free_trans(trans);
+       return error;
+}
+
+/*
+ * Lookup the transaction recovery structure associated with the ID in the
+ * current ophdr. If the transaction doesn't exist and the start flag is set in
+ * the ophdr, then allocate a new transaction for future ID matches to find.
+ * Either way, return what we found during the lookup - an existing transaction
+ * or nothing.
+ */
+STATIC struct xlog_recover *
+xlog_recover_ophdr_to_trans(
+       struct hlist_head       rhash[],
+       struct xlog_rec_header  *rhead,
+       struct xlog_op_header   *ohead)
+{
+       struct xlog_recover     *trans;
+       xlog_tid_t              tid;
+       struct hlist_head       *rhp;
+
+       tid = be32_to_cpu(ohead->oh_tid);
+       rhp = &rhash[XLOG_RHASH(tid)];
+       hlist_for_each_entry(trans, rhp, r_list) {
+               if (trans->r_log_tid == tid)
+                       return trans;
+       }
+
+       /*
+        * skip over non-start transaction headers - we could be
+        * processing slack space before the next transaction starts
+        */
+       if (!(ohead->oh_flags & XLOG_START_TRANS))
+               return NULL;
+
+       ASSERT(be32_to_cpu(ohead->oh_len) == 0);
+
+       /*
+        * This is a new transaction so allocate a new recovery container to
+        * hold the recovery ops that will follow.
+        */
+       trans = kmem_zalloc(sizeof(struct xlog_recover), KM_SLEEP);
+       trans->r_log_tid = tid;
+       trans->r_lsn = be64_to_cpu(rhead->h_lsn);
+       INIT_LIST_HEAD(&trans->r_itemq);
+       INIT_HLIST_NODE(&trans->r_list);
+       hlist_add_head(&trans->r_list, rhp);
+
+       /*
+        * Nothing more to do for this ophdr. Items to be added to this new
+        * transaction will be in subsequent ophdr containers.
+        */
+       return NULL;
+}
+
+STATIC int
+xlog_recover_process_ophdr(
+       struct xlog             *log,
+       struct hlist_head       rhash[],
+       struct xlog_rec_header  *rhead,
+       struct xlog_op_header   *ohead,
+       xfs_caddr_t             dp,
+       xfs_caddr_t             end,
+       int                     pass)
+{
+       struct xlog_recover     *trans;
+       unsigned int            len;
+
+       /* Do we understand who wrote this op? */
+       if (ohead->oh_clientid != XFS_TRANSACTION &&
+           ohead->oh_clientid != XFS_LOG) {
+               xfs_warn(log->l_mp, "%s: bad clientid 0x%x",
+                       __func__, ohead->oh_clientid);
+               ASSERT(0);
+               return -EIO;
+       }
+
+       /*
+        * Check the ophdr contains all the data it is supposed to contain.
+        */
+       len = be32_to_cpu(ohead->oh_len);
+       if (dp + len > end) {
+               xfs_warn(log->l_mp, "%s: bad length 0x%x", __func__, len);
+               WARN_ON(1);
+               return -EIO;
+       }
+
+       trans = xlog_recover_ophdr_to_trans(rhash, rhead, ohead);
+       if (!trans) {
+               /* nothing to do, so skip over this ophdr */
+               return 0;
+       }
+
+       return xlog_recovery_process_trans(log, trans, dp, len,
+                                          ohead->oh_flags, pass);
+}
+
 /*
  * There are two valid states of the r_state field.  0 indicates that the
  * transaction structure is in a normal state.  We have either seen the
@@ -3560,86 +3666,30 @@ xlog_recover_process_data(
        xfs_caddr_t             dp,
        int                     pass)
 {
-       xfs_caddr_t             lp;
+       struct xlog_op_header   *ohead;
+       xfs_caddr_t             end;
        int                     num_logops;
-       xlog_op_header_t        *ohead;
-       xlog_recover_t          *trans;
-       xlog_tid_t              tid;
        int                     error;
-       unsigned long           hash;
-       uint                    flags;
 
-       lp = dp + be32_to_cpu(rhead->h_len);
+       end = dp + be32_to_cpu(rhead->h_len);
        num_logops = be32_to_cpu(rhead->h_num_logops);
 
        /* check the log format matches our own - else we can't recover */
        if (xlog_header_check_recover(log->l_mp, rhead))
                return -EIO;
 
-       while ((dp < lp) && num_logops) {
-               ASSERT(dp + sizeof(xlog_op_header_t) <= lp);
-               ohead = (xlog_op_header_t *)dp;
-               dp += sizeof(xlog_op_header_t);
-               if (ohead->oh_clientid != XFS_TRANSACTION &&
-                   ohead->oh_clientid != XFS_LOG) {
-                       xfs_warn(log->l_mp, "%s: bad clientid 0x%x",
-                                       __func__, ohead->oh_clientid);
-                       ASSERT(0);
-                       return -EIO;
-               }
-               tid = be32_to_cpu(ohead->oh_tid);
-               hash = XLOG_RHASH(tid);
-               trans = xlog_recover_find_tid(&rhash[hash], tid);
-               if (trans == NULL) {               /* not found; add new tid */
-                       if (ohead->oh_flags & XLOG_START_TRANS)
-                               xlog_recover_new_tid(&rhash[hash], tid,
-                                       be64_to_cpu(rhead->h_lsn));
-               } else {
-                       if (dp + be32_to_cpu(ohead->oh_len) > lp) {
-                               xfs_warn(log->l_mp, "%s: bad length 0x%x",
-                                       __func__, be32_to_cpu(ohead->oh_len));
-                               WARN_ON(1);
-                               return -EIO;
-                       }
-                       flags = ohead->oh_flags & ~XLOG_END_TRANS;
-                       if (flags & XLOG_WAS_CONT_TRANS)
-                               flags &= ~XLOG_CONTINUE_TRANS;
-                       switch (flags) {
-                       case XLOG_COMMIT_TRANS:
-                               error = xlog_recover_commit_trans(log,
-                                                               trans, pass);
-                               break;
-                       case XLOG_UNMOUNT_TRANS:
-                               error = xlog_recover_unmount_trans(log);
-                               break;
-                       case XLOG_WAS_CONT_TRANS:
-                               error = xlog_recover_add_to_cont_trans(log,
-                                               trans, dp,
-                                               be32_to_cpu(ohead->oh_len));
-                               break;
-                       case XLOG_START_TRANS:
-                               xfs_warn(log->l_mp, "%s: bad transaction",
-                                       __func__);
-                               ASSERT(0);
-                               error = -EIO;
-                               break;
-                       case 0:
-                       case XLOG_CONTINUE_TRANS:
-                               error = xlog_recover_add_to_trans(log, trans,
-                                               dp, be32_to_cpu(ohead->oh_len));
-                               break;
-                       default:
-                               xfs_warn(log->l_mp, "%s: bad flag 0x%x",
-                                       __func__, flags);
-                               ASSERT(0);
-                               error = -EIO;
-                               break;
-                       }
-                       if (error) {
-                               xlog_recover_free_trans(trans);
-                               return error;
-                       }
-               }
+       while ((dp < end) && num_logops) {
+
+               ohead = (struct xlog_op_header *)dp;
+               dp += sizeof(*ohead);
+               ASSERT(dp <= end);
+
+               /* errors will abort recovery */
+               error = xlog_recover_process_ophdr(log, rhash, rhead, ohead,
+                                                   dp, end, pass);
+               if (error)
+                       return error;
+
                dp += be32_to_cpu(ohead->oh_len);
                num_logops--;
        }
@@ -4132,41 +4182,13 @@ xlog_do_recovery_pass(
        }
 
        memset(rhash, 0, sizeof(rhash));
-       if (tail_blk <= head_blk) {
-               for (blk_no = tail_blk; blk_no < head_blk; ) {
-                       error = xlog_bread(log, blk_no, hblks, hbp, &offset);
-                       if (error)
-                               goto bread_err2;
-
-                       rhead = (xlog_rec_header_t *)offset;
-                       error = xlog_valid_rec_header(log, rhead, blk_no);
-                       if (error)
-                               goto bread_err2;
-
-                       /* blocks in data section */
-                       bblks = (int)BTOBB(be32_to_cpu(rhead->h_len));
-                       error = xlog_bread(log, blk_no + hblks, bblks, dbp,
-                                          &offset);
-                       if (error)
-                               goto bread_err2;
-
-                       error = xlog_unpack_data(rhead, offset, log);
-                       if (error)
-                               goto bread_err2;
-
-                       error = xlog_recover_process_data(log,
-                                               rhash, rhead, offset, pass);
-                       if (error)
-                               goto bread_err2;
-                       blk_no += bblks + hblks;
-               }
-       } else {
+       blk_no = tail_blk;
+       if (tail_blk > head_blk) {
                /*
                 * Perform recovery around the end of the physical log.
                 * When the head is not on the same cycle number as the tail,
-                * we can't do a sequential recovery as above.
+                * we can't do a sequential recovery.
                 */
-               blk_no = tail_blk;
                while (blk_no < log->l_logBBsize) {
                        /*
                         * Check for header wrapping around physical end-of-log
@@ -4280,34 +4302,35 @@ xlog_do_recovery_pass(
 
                ASSERT(blk_no >= log->l_logBBsize);
                blk_no -= log->l_logBBsize;
+       }
 
-               /* read first part of physical log */
-               while (blk_no < head_blk) {
-                       error = xlog_bread(log, blk_no, hblks, hbp, &offset);
-                       if (error)
-                               goto bread_err2;
+       /* read first part of physical log */
+       while (blk_no < head_blk) {
+               error = xlog_bread(log, blk_no, hblks, hbp, &offset);
+               if (error)
+                       goto bread_err2;
 
-                       rhead = (xlog_rec_header_t *)offset;
-                       error = xlog_valid_rec_header(log, rhead, blk_no);
-                       if (error)
-                               goto bread_err2;
+               rhead = (xlog_rec_header_t *)offset;
+               error = xlog_valid_rec_header(log, rhead, blk_no);
+               if (error)
+                       goto bread_err2;
 
-                       bblks = (int)BTOBB(be32_to_cpu(rhead->h_len));
-                       error = xlog_bread(log, blk_no+hblks, bblks, dbp,
-                                          &offset);
-                       if (error)
-                               goto bread_err2;
+               /* blocks in data section */
+               bblks = (int)BTOBB(be32_to_cpu(rhead->h_len));
+               error = xlog_bread(log, blk_no+hblks, bblks, dbp,
+                                  &offset);
+               if (error)
+                       goto bread_err2;
 
-                       error = xlog_unpack_data(rhead, offset, log);
-                       if (error)
-                               goto bread_err2;
+               error = xlog_unpack_data(rhead, offset, log);
+               if (error)
+                       goto bread_err2;
 
-                       error = xlog_recover_process_data(log, rhash,
-                                                       rhead, offset, pass);
-                       if (error)
-                               goto bread_err2;
-                       blk_no += bblks + hblks;
-               }
+               error = xlog_recover_process_data(log, rhash,
+                                               rhead, offset, pass);
+               if (error)
+                       goto bread_err2;
+               blk_no += bblks + hblks;
        }
 
  bread_err2:
@@ -4427,16 +4450,12 @@ xlog_do_recover(
        XFS_BUF_UNASYNC(bp);
        bp->b_ops = &xfs_sb_buf_ops;
 
-       if (XFS_FORCED_SHUTDOWN(log->l_mp)) {
-               xfs_buf_relse(bp);
-               return -EIO;
-       }
-
-       xfs_buf_iorequest(bp);
-       error = xfs_buf_iowait(bp);
+       error = xfs_buf_submit_wait(bp);
        if (error) {
-               xfs_buf_ioerror_alert(bp, __func__);
-               ASSERT(0);
+               if (!XFS_FORCED_SHUTDOWN(log->l_mp)) {
+                       xfs_buf_ioerror_alert(bp, __func__);
+                       ASSERT(0);
+               }
                xfs_buf_relse(bp);
                return error;
        }
@@ -4509,6 +4528,18 @@ xlog_recover(
                        return -EINVAL;
                }
 
+               /*
+                * Delay log recovery if the debug hook is set. This is debug
+                * instrumention to coordinate simulation of I/O failures with
+                * log recovery.
+                */
+               if (xfs_globals.log_recovery_delay) {
+                       xfs_notice(log->l_mp,
+                               "Delaying log recovery for %d seconds.",
+                               xfs_globals.log_recovery_delay);
+                       msleep(xfs_globals.log_recovery_delay * 1000);
+               }
+
                xfs_notice(log->l_mp, "Starting recovery (logdev: %s)",
                                log->l_mp->m_logname ? log->l_mp->m_logname
                                                     : "internal");
index fbf0384a466fa25fba334862b0c1762be68ab6d4..51435dbce9c4efd2407be2c12ddd58d86324bce8 100644 (file)
@@ -61,8 +61,6 @@ static DEFINE_MUTEX(xfs_uuid_table_mutex);
 static int xfs_uuid_table_size;
 static uuid_t *xfs_uuid_table;
 
-extern struct kset *xfs_kset;
-
 /*
  * See if the UUID is unique among mounted XFS filesystems.
  * Mount fails if UUID is nil or a FS with the same UUID is already mounted.
@@ -302,21 +300,15 @@ xfs_readsb(
         * access to the superblock.
         */
 reread:
-       bp = xfs_buf_read_uncached(mp->m_ddev_targp, XFS_SB_DADDR,
-                                  BTOBB(sector_size), 0, buf_ops);
-       if (!bp) {
-               if (loud)
-                       xfs_warn(mp, "SB buffer read failed");
-               return -EIO;
-       }
-       if (bp->b_error) {
-               error = bp->b_error;
+       error = xfs_buf_read_uncached(mp->m_ddev_targp, XFS_SB_DADDR,
+                                  BTOBB(sector_size), 0, &bp, buf_ops);
+       if (error) {
                if (loud)
                        xfs_warn(mp, "SB validate failed with error %d.", error);
                /* bad CRC means corrupted metadata */
                if (error == -EFSBADCRC)
                        error = -EFSCORRUPTED;
-               goto release_buf;
+               return error;
        }
 
        /*
@@ -546,40 +538,43 @@ xfs_set_inoalignment(xfs_mount_t *mp)
  * Check that the data (and log if separate) is an ok size.
  */
 STATIC int
-xfs_check_sizes(xfs_mount_t *mp)
+xfs_check_sizes(
+       struct xfs_mount *mp)
 {
-       xfs_buf_t       *bp;
+       struct xfs_buf  *bp;
        xfs_daddr_t     d;
+       int             error;
 
        d = (xfs_daddr_t)XFS_FSB_TO_BB(mp, mp->m_sb.sb_dblocks);
        if (XFS_BB_TO_FSB(mp, d) != mp->m_sb.sb_dblocks) {
                xfs_warn(mp, "filesystem size mismatch detected");
                return -EFBIG;
        }
-       bp = xfs_buf_read_uncached(mp->m_ddev_targp,
+       error = xfs_buf_read_uncached(mp->m_ddev_targp,
                                        d - XFS_FSS_TO_BB(mp, 1),
-                                       XFS_FSS_TO_BB(mp, 1), 0, NULL);
-       if (!bp) {
+                                       XFS_FSS_TO_BB(mp, 1), 0, &bp, NULL);
+       if (error) {
                xfs_warn(mp, "last sector read failed");
-               return -EIO;
+               return error;
        }
        xfs_buf_relse(bp);
 
-       if (mp->m_logdev_targp != mp->m_ddev_targp) {
-               d = (xfs_daddr_t)XFS_FSB_TO_BB(mp, mp->m_sb.sb_logblocks);
-               if (XFS_BB_TO_FSB(mp, d) != mp->m_sb.sb_logblocks) {
-                       xfs_warn(mp, "log size mismatch detected");
-                       return -EFBIG;
-               }
-               bp = xfs_buf_read_uncached(mp->m_logdev_targp,
+       if (mp->m_logdev_targp == mp->m_ddev_targp)
+               return 0;
+
+       d = (xfs_daddr_t)XFS_FSB_TO_BB(mp, mp->m_sb.sb_logblocks);
+       if (XFS_BB_TO_FSB(mp, d) != mp->m_sb.sb_logblocks) {
+               xfs_warn(mp, "log size mismatch detected");
+               return -EFBIG;
+       }
+       error = xfs_buf_read_uncached(mp->m_logdev_targp,
                                        d - XFS_FSB_TO_BB(mp, 1),
-                                       XFS_FSB_TO_BB(mp, 1), 0, NULL);
-               if (!bp) {
-                       xfs_warn(mp, "log device read failed");
-                       return -EIO;
-               }
-               xfs_buf_relse(bp);
+                                       XFS_FSB_TO_BB(mp, 1), 0, &bp, NULL);
+       if (error) {
+               xfs_warn(mp, "log device read failed");
+               return error;
        }
+       xfs_buf_relse(bp);
        return 0;
 }
 
@@ -729,7 +724,6 @@ xfs_mountfs(
 
        xfs_set_maxicount(mp);
 
-       mp->m_kobj.kobject.kset = xfs_kset;
        error = xfs_sysfs_init(&mp->m_kobj, &xfs_mp_ktype, NULL, mp->m_fsname);
        if (error)
                goto out;
index 1eb6f3df698c8bb4eac11b5c03aa23790cbc65c4..30ecca3037e37bc5354fb9e37deb4db6e163fa8a 100644 (file)
@@ -304,7 +304,8 @@ _xfs_mru_cache_reap(
 int
 xfs_mru_cache_init(void)
 {
-       xfs_mru_reap_wq = alloc_workqueue("xfs_mru_cache", WQ_MEM_RECLAIM, 1);
+       xfs_mru_reap_wq = alloc_workqueue("xfs_mru_cache",
+                               WQ_MEM_RECLAIM|WQ_FREEZABLE, 1);
        if (!xfs_mru_reap_wq)
                return -ENOMEM;
        return 0;
index 10232102b4a6ffac8a8a92f627ba0cb0caea64ab..d68f23021af3587cbaed9a3ad90d71343bceee7e 100644 (file)
@@ -434,6 +434,7 @@ xfs_qm_dquot_isolate(
        struct list_head        *item,
        spinlock_t              *lru_lock,
        void                    *arg)
+               __releases(lru_lock) __acquires(lru_lock)
 {
        struct xfs_dquot        *dqp = container_of(item,
                                                struct xfs_dquot, q_lru);
index 909e143b87ae66124472c8f8e08fe1a9aaa4737e..e1175ea9b551b74fce1ba38e48181967e553504d 100644 (file)
@@ -46,7 +46,7 @@
  * Keeps track of a current summary block, so we don't keep reading
  * it from the buffer cache.
  */
-STATIC int                             /* error */
+static int
 xfs_rtget_summary(
        xfs_mount_t     *mp,            /* file system mount structure */
        xfs_trans_t     *tp,            /* transaction pointer */
@@ -56,60 +56,9 @@ xfs_rtget_summary(
        xfs_fsblock_t   *rsb,           /* in/out: summary block number */
        xfs_suminfo_t   *sum)           /* out: summary info for this block */
 {
-       xfs_buf_t       *bp;            /* buffer for summary block */
-       int             error;          /* error value */
-       xfs_fsblock_t   sb;             /* summary fsblock */
-       int             so;             /* index into the summary file */
-       xfs_suminfo_t   *sp;            /* pointer to returned data */
-
-       /*
-        * Compute entry number in the summary file.
-        */
-       so = XFS_SUMOFFS(mp, log, bbno);
-       /*
-        * Compute the block number in the summary file.
-        */
-       sb = XFS_SUMOFFSTOBLOCK(mp, so);
-       /*
-        * If we have an old buffer, and the block number matches, use that.
-        */
-       if (rbpp && *rbpp && *rsb == sb)
-               bp = *rbpp;
-       /*
-        * Otherwise we have to get the buffer.
-        */
-       else {
-               /*
-                * If there was an old one, get rid of it first.
-                */
-               if (rbpp && *rbpp)
-                       xfs_trans_brelse(tp, *rbpp);
-               error = xfs_rtbuf_get(mp, tp, sb, 1, &bp);
-               if (error) {
-                       return error;
-               }
-               /*
-                * Remember this buffer and block for the next call.
-                */
-               if (rbpp) {
-                       *rbpp = bp;
-                       *rsb = sb;
-               }
-       }
-       /*
-        * Point to the summary information & copy it out.
-        */
-       sp = XFS_SUMPTR(mp, bp, so);
-       *sum = *sp;
-       /*
-        * Drop the buffer if we're not asked to remember it.
-        */
-       if (!rbpp)
-               xfs_trans_brelse(tp, bp);
-       return 0;
+       return xfs_rtmodify_summary_int(mp, tp, log, bbno, 0, rbpp, rsb, sum);
 }
 
-
 /*
  * Return whether there are any free extents in the size range given
  * by low and high, for the bitmap block bbno.
@@ -972,16 +921,11 @@ xfs_growfs_rt(
        /*
         * Read in the last block of the device, make sure it exists.
         */
-       bp = xfs_buf_read_uncached(mp->m_rtdev_targp,
+       error = xfs_buf_read_uncached(mp->m_rtdev_targp,
                                XFS_FSB_TO_BB(mp, nrblocks - 1),
-                               XFS_FSB_TO_BB(mp, 1), 0, NULL);
-       if (!bp)
-               return -EIO;
-       if (bp->b_error) {
-               error = bp->b_error;
-               xfs_buf_relse(bp);
+                               XFS_FSB_TO_BB(mp, 1), 0, &bp, NULL);
+       if (error)
                return error;
-       }
        xfs_buf_relse(bp);
 
        /*
@@ -1235,11 +1179,12 @@ xfs_rtallocate_extent(
  */
 int                            /* error */
 xfs_rtmount_init(
-       xfs_mount_t     *mp)    /* file system mount structure */
+       struct xfs_mount        *mp)    /* file system mount structure */
 {
-       xfs_buf_t       *bp;    /* buffer for last block of subvolume */
-       xfs_daddr_t     d;      /* address of last block of subvolume */
-       xfs_sb_t        *sbp;   /* filesystem superblock copy in mount */
+       struct xfs_buf          *bp;    /* buffer for last block of subvolume */
+       struct xfs_sb           *sbp;   /* filesystem superblock copy in mount */
+       xfs_daddr_t             d;      /* address of last block of subvolume */
+       int                     error;
 
        sbp = &mp->m_sb;
        if (sbp->sb_rblocks == 0)
@@ -1265,14 +1210,12 @@ xfs_rtmount_init(
                        (unsigned long long) mp->m_sb.sb_rblocks);
                return -EFBIG;
        }
-       bp = xfs_buf_read_uncached(mp->m_rtdev_targp,
+       error = xfs_buf_read_uncached(mp->m_rtdev_targp,
                                        d - XFS_FSB_TO_BB(mp, 1),
-                                       XFS_FSB_TO_BB(mp, 1), 0, NULL);
-       if (!bp || bp->b_error) {
+                                       XFS_FSB_TO_BB(mp, 1), 0, &bp, NULL);
+       if (error) {
                xfs_warn(mp, "realtime device size check failed");
-               if (bp)
-                       xfs_buf_relse(bp);
-               return -EIO;
+               return error;
        }
        xfs_buf_relse(bp);
        return 0;
index c642795324af649c1c80666e5bdc7e0739551e1d..76c0a4a9bb170a327936d1719c8cc9fa736de324 100644 (file)
@@ -111,6 +111,10 @@ int xfs_rtfind_forw(struct xfs_mount *mp, struct xfs_trans *tp,
                    xfs_rtblock_t *rtblock);
 int xfs_rtmodify_range(struct xfs_mount *mp, struct xfs_trans *tp,
                       xfs_rtblock_t start, xfs_extlen_t len, int val);
+int xfs_rtmodify_summary_int(struct xfs_mount *mp, struct xfs_trans *tp,
+                            int log, xfs_rtblock_t bbno, int delta,
+                            xfs_buf_t **rbpp, xfs_fsblock_t *rsb,
+                            xfs_suminfo_t *sum);
 int xfs_rtmodify_summary(struct xfs_mount *mp, struct xfs_trans *tp, int log,
                         xfs_rtblock_t bbno, int delta, xfs_buf_t **rbpp,
                         xfs_fsblock_t *rsb);
index b194652033cd11c8530ae762d01972fa455a23aa..9f622feda6a43bb32ea1983779a48d20b1446391 100644 (file)
@@ -47,6 +47,7 @@
 #include "xfs_dinode.h"
 #include "xfs_filestream.h"
 #include "xfs_quota.h"
+#include "xfs_sysfs.h"
 
 #include <linux/namei.h>
 #include <linux/init.h>
 static const struct super_operations xfs_super_operations;
 static kmem_zone_t *xfs_ioend_zone;
 mempool_t *xfs_ioend_pool;
-struct kset *xfs_kset;
+
+static struct kset *xfs_kset;          /* top-level xfs sysfs dir */
+#ifdef DEBUG
+static struct xfs_kobj xfs_dbg_kobj;   /* global debug sysfs attrs */
+#endif
 
 #define MNTOPT_LOGBUFS "logbufs"       /* number of XFS log buffers */
 #define MNTOPT_LOGBSIZE        "logbsize"      /* size of XFS log buffers */
@@ -838,32 +843,32 @@ xfs_init_mount_workqueues(
        struct xfs_mount        *mp)
 {
        mp->m_data_workqueue = alloc_workqueue("xfs-data/%s",
-                       WQ_MEM_RECLAIM, 0, mp->m_fsname);
+                       WQ_MEM_RECLAIM|WQ_FREEZABLE, 0, mp->m_fsname);
        if (!mp->m_data_workqueue)
                goto out;
 
        mp->m_unwritten_workqueue = alloc_workqueue("xfs-conv/%s",
-                       WQ_MEM_RECLAIM, 0, mp->m_fsname);
+                       WQ_MEM_RECLAIM|WQ_FREEZABLE, 0, mp->m_fsname);
        if (!mp->m_unwritten_workqueue)
                goto out_destroy_data_iodone_queue;
 
        mp->m_cil_workqueue = alloc_workqueue("xfs-cil/%s",
-                       WQ_MEM_RECLAIM, 0, mp->m_fsname);
+                       WQ_MEM_RECLAIM|WQ_FREEZABLE, 0, mp->m_fsname);
        if (!mp->m_cil_workqueue)
                goto out_destroy_unwritten;
 
        mp->m_reclaim_workqueue = alloc_workqueue("xfs-reclaim/%s",
-                       0, 0, mp->m_fsname);
+                       WQ_FREEZABLE, 0, mp->m_fsname);
        if (!mp->m_reclaim_workqueue)
                goto out_destroy_cil;
 
        mp->m_log_workqueue = alloc_workqueue("xfs-log/%s",
-                       0, 0, mp->m_fsname);
+                       WQ_FREEZABLE, 0, mp->m_fsname);
        if (!mp->m_log_workqueue)
                goto out_destroy_reclaim;
 
        mp->m_eofblocks_workqueue = alloc_workqueue("xfs-eofblocks/%s",
-                       0, 0, mp->m_fsname);
+                       WQ_FREEZABLE, 0, mp->m_fsname);
        if (!mp->m_eofblocks_workqueue)
                goto out_destroy_log;
 
@@ -1406,6 +1411,7 @@ xfs_fs_fill_super(
        atomic_set(&mp->m_active_trans, 0);
        INIT_DELAYED_WORK(&mp->m_reclaim_work, xfs_reclaim_worker);
        INIT_DELAYED_WORK(&mp->m_eofblocks_work, xfs_eofblocks_worker);
+       mp->m_kobj.kobject.kset = xfs_kset;
 
        mp->m_super = sb;
        sb->s_fs_info = mp;
@@ -1715,7 +1721,8 @@ xfs_init_workqueues(void)
         * AGs in all the filesystems mounted. Hence use the default large
         * max_active value for this workqueue.
         */
-       xfs_alloc_wq = alloc_workqueue("xfsalloc", WQ_MEM_RECLAIM, 0);
+       xfs_alloc_wq = alloc_workqueue("xfsalloc",
+                       WQ_MEM_RECLAIM|WQ_FREEZABLE, 0);
        if (!xfs_alloc_wq)
                return -ENOMEM;
 
@@ -1768,9 +1775,16 @@ init_xfs_fs(void)
                goto out_sysctl_unregister;;
        }
 
-       error = xfs_qm_init();
+#ifdef DEBUG
+       xfs_dbg_kobj.kobject.kset = xfs_kset;
+       error = xfs_sysfs_init(&xfs_dbg_kobj, &xfs_dbg_ktype, NULL, "debug");
        if (error)
                goto out_kset_unregister;
+#endif
+
+       error = xfs_qm_init();
+       if (error)
+               goto out_remove_kobj;
 
        error = register_filesystem(&xfs_fs_type);
        if (error)
@@ -1779,7 +1793,11 @@ init_xfs_fs(void)
 
  out_qm_exit:
        xfs_qm_exit();
+ out_remove_kobj:
+#ifdef DEBUG
+       xfs_sysfs_del(&xfs_dbg_kobj);
  out_kset_unregister:
+#endif
        kset_unregister(xfs_kset);
  out_sysctl_unregister:
        xfs_sysctl_unregister();
@@ -1802,6 +1820,9 @@ exit_xfs_fs(void)
 {
        xfs_qm_exit();
        unregister_filesystem(&xfs_fs_type);
+#ifdef DEBUG
+       xfs_sysfs_del(&xfs_dbg_kobj);
+#endif
        kset_unregister(xfs_kset);
        xfs_sysctl_unregister();
        xfs_cleanup_procfs();
index 6a944a2cd36fbf97717ea31f56e82c101caef3a9..02ae62a998e082a54fe86b3a9c6f6b7cdf071e57 100644 (file)
@@ -269,9 +269,11 @@ xfs_symlink(
        /*
         * Check for ability to enter directory entry, if no space reserved.
         */
-       error = xfs_dir_canenter(tp, dp, link_name, resblks);
-       if (error)
-               goto error_return;
+       if (!resblks) {
+               error = xfs_dir_canenter(tp, dp, link_name);
+               if (error)
+                       goto error_return;
+       }
        /*
         * Initialize the bmap freelist prior to calling either
         * bmapi or the directory create code.
index bd8e157c20efa254c736952967e6c894dbd706a0..ffef453757543a94d742eb2890e4858e8bcd7716 100644 (file)
@@ -92,6 +92,11 @@ enum {
 
 extern xfs_param_t     xfs_params;
 
+struct xfs_globals {
+       int     log_recovery_delay;     /* log recovery delay (secs) */
+};
+extern struct xfs_globals      xfs_globals;
+
 #ifdef CONFIG_SYSCTL
 extern int xfs_sysctl_register(void);
 extern void xfs_sysctl_unregister(void);
index 9835139ce1ec24cd2e1d5358377bd844d4323ab7..aa03670851d86574cc542a2eccb1b5c4607e4ca5 100644 (file)
@@ -51,6 +51,80 @@ struct kobj_type xfs_mp_ktype = {
        .release = xfs_sysfs_release,
 };
 
+#ifdef DEBUG
+/* debug */
+
+STATIC ssize_t
+log_recovery_delay_store(
+       const char      *buf,
+       size_t          count,
+       void            *data)
+{
+       int             ret;
+       int             val;
+
+       ret = kstrtoint(buf, 0, &val);
+       if (ret)
+               return ret;
+
+       if (val < 0 || val > 60)
+               return -EINVAL;
+
+       xfs_globals.log_recovery_delay = val;
+
+       return count;
+}
+
+STATIC ssize_t
+log_recovery_delay_show(
+       char    *buf,
+       void    *data)
+{
+       return snprintf(buf, PAGE_SIZE, "%d\n", xfs_globals.log_recovery_delay);
+}
+XFS_SYSFS_ATTR_RW(log_recovery_delay);
+
+static struct attribute *xfs_dbg_attrs[] = {
+       ATTR_LIST(log_recovery_delay),
+       NULL,
+};
+
+STATIC ssize_t
+xfs_dbg_show(
+       struct kobject          *kobject,
+       struct attribute        *attr,
+       char                    *buf)
+{
+       struct xfs_sysfs_attr *xfs_attr = to_attr(attr);
+
+       return xfs_attr->show ? xfs_attr->show(buf, NULL) : 0;
+}
+
+STATIC ssize_t
+xfs_dbg_store(
+       struct kobject          *kobject,
+       struct attribute        *attr,
+       const char              *buf,
+       size_t                  count)
+{
+       struct xfs_sysfs_attr *xfs_attr = to_attr(attr);
+
+       return xfs_attr->store ? xfs_attr->store(buf, count, NULL) : 0;
+}
+
+static struct sysfs_ops xfs_dbg_ops = {
+       .show = xfs_dbg_show,
+       .store = xfs_dbg_store,
+};
+
+struct kobj_type xfs_dbg_ktype = {
+       .release = xfs_sysfs_release,
+       .sysfs_ops = &xfs_dbg_ops,
+       .default_attrs = xfs_dbg_attrs,
+};
+
+#endif /* DEBUG */
+
 /* xlog */
 
 STATIC ssize_t
index 54a2091183c08a066b9751cfca37ba63f1e83b01..240eee35f342b8bbae4511f0ef04d38e32e3a0c4 100644 (file)
@@ -20,6 +20,7 @@
 #define __XFS_SYSFS_H__
 
 extern struct kobj_type xfs_mp_ktype;  /* xfs_mount */
+extern struct kobj_type xfs_dbg_ktype; /* debug */
 extern struct kobj_type xfs_log_ktype; /* xlog */
 
 static inline struct xfs_kobj *
index 152f82782630222321bcd234b20c0ffb0a626e34..51372e34d9889b7977fa4821af3d5785766f983c 100644 (file)
@@ -349,7 +349,8 @@ DEFINE_BUF_EVENT(xfs_buf_free);
 DEFINE_BUF_EVENT(xfs_buf_hold);
 DEFINE_BUF_EVENT(xfs_buf_rele);
 DEFINE_BUF_EVENT(xfs_buf_iodone);
-DEFINE_BUF_EVENT(xfs_buf_iorequest);
+DEFINE_BUF_EVENT(xfs_buf_submit);
+DEFINE_BUF_EVENT(xfs_buf_submit_wait);
 DEFINE_BUF_EVENT(xfs_buf_bawrite);
 DEFINE_BUF_EVENT(xfs_buf_lock);
 DEFINE_BUF_EVENT(xfs_buf_lock_done);
index 96c898e7ac9a7af67f0ab5a6147c7ba9f01cf4b9..e2b2216b163589530c23f0d1e4458c167eea057f 100644 (file)
@@ -318,20 +318,10 @@ xfs_trans_read_buf_map(
                        XFS_BUF_READ(bp);
                        bp->b_ops = ops;
 
-                       /*
-                        * XXX(hch): clean up the error handling here to be less
-                        * of a mess..
-                        */
-                       if (XFS_FORCED_SHUTDOWN(mp)) {
-                               trace_xfs_bdstrat_shut(bp, _RET_IP_);
-                               xfs_bioerror_relse(bp);
-                       } else {
-                               xfs_buf_iorequest(bp);
-                       }
-
-                       error = xfs_buf_iowait(bp);
+                       error = xfs_buf_submit_wait(bp);
                        if (error) {
-                               xfs_buf_ioerror_alert(bp, __func__);
+                               if (!XFS_FORCED_SHUTDOWN(mp))
+                                       xfs_buf_ioerror_alert(bp, __func__);
                                xfs_buf_relse(bp);
                                /*
                                 * We can gracefully recover from most read
index 50c3f5614288febe4c85fdb7c231887527e80f79..cdb4d86520e17c98bce53140b49c8e55187bf23c 100644 (file)
@@ -70,7 +70,7 @@ xfs_trans_ichgtime(
        int                     flags)
 {
        struct inode            *inode = VFS_I(ip);
-       timespec_t              tv;
+       struct timespec         tv;
 
        ASSERT(tp);
        ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL));
index 9c79e7603459ede5f3b1a89046d353e6f295771c..1973ad2b13f4dd80c750e4ff5c71d2e1510c4ff8 100644 (file)
 #include <asm/cmpxchg.h>
 #include <asm/barrier.h>
 
+/*
+ * atomic_$op() - $op integer to atomic variable
+ * @i: integer value to $op
+ * @v: pointer to the atomic variable
+ *
+ * Atomically $ops @i to @v. Does not strictly guarantee a memory-barrier, use
+ * smp_mb__{before,after}_atomic().
+ */
+
+/*
+ * atomic_$op_return() - $op interer to atomic variable and returns the result
+ * @i: integer value to $op
+ * @v: pointer to the atomic variable
+ *
+ * Atomically $ops @i to @v. Does imply a full memory barrier.
+ */
+
 #ifdef CONFIG_SMP
-/* Force people to define core atomics */
-# if !defined(atomic_add_return) || !defined(atomic_sub_return) || \
-     !defined(atomic_clear_mask) || !defined(atomic_set_mask)
-#  error "SMP requires a little arch-specific magic"
-# endif
+
+/* we can build all atomic primitives from cmpxchg */
+
+#define ATOMIC_OP(op, c_op)                                            \
+static inline void atomic_##op(int i, atomic_t *v)                     \
+{                                                                      \
+       int c, old;                                                     \
+                                                                       \
+       c = v->counter;                                                 \
+       while ((old = cmpxchg(&v->counter, c, c c_op i)) != c)          \
+               c = old;                                                \
+}
+
+#define ATOMIC_OP_RETURN(op, c_op)                                     \
+static inline int atomic_##op##_return(int i, atomic_t *v)             \
+{                                                                      \
+       int c, old;                                                     \
+                                                                       \
+       c = v->counter;                                                 \
+       while ((old = cmpxchg(&v->counter, c, c c_op i)) != c)          \
+               c = old;                                                \
+                                                                       \
+       return c c_op i;                                                \
+}
+
+#else
+
+#include <linux/irqflags.h>
+
+#define ATOMIC_OP(op, c_op)                                            \
+static inline void atomic_##op(int i, atomic_t *v)                     \
+{                                                                      \
+       unsigned long flags;                                            \
+                                                                       \
+       raw_local_irq_save(flags);                                      \
+       v->counter = v->counter c_op i;                                 \
+       raw_local_irq_restore(flags);                                   \
+}
+
+#define ATOMIC_OP_RETURN(op, c_op)                                     \
+static inline int atomic_##op##_return(int i, atomic_t *v)             \
+{                                                                      \
+       unsigned long flags;                                            \
+       int ret;                                                        \
+                                                                       \
+       raw_local_irq_save(flags);                                      \
+       ret = (v->counter = v->counter c_op i);                         \
+       raw_local_irq_restore(flags);                                   \
+                                                                       \
+       return ret;                                                     \
+}
+
+#endif /* CONFIG_SMP */
+
+#ifndef atomic_add_return
+ATOMIC_OP_RETURN(add, +)
+#endif
+
+#ifndef atomic_sub_return
+ATOMIC_OP_RETURN(sub, -)
+#endif
+
+#ifndef atomic_clear_mask
+ATOMIC_OP(and, &)
+#define atomic_clear_mask(i, v) atomic_and(~(i), (v))
 #endif
 
+#ifndef atomic_set_mask
+#define CONFIG_ARCH_HAS_ATOMIC_OR
+ATOMIC_OP(or, |)
+#define atomic_set_mask(i, v)  atomic_or((i), (v))
+#endif
+
+#undef ATOMIC_OP_RETURN
+#undef ATOMIC_OP
+
 /*
  * Atomic operations that C can't guarantee us.  Useful for
  * resource counting etc..
 
 #define ATOMIC_INIT(i) { (i) }
 
-#ifdef __KERNEL__
-
 /**
  * atomic_read - read atomic variable
  * @v: pointer of type atomic_t
  * Atomically reads the value of @v.
  */
 #ifndef atomic_read
-#define atomic_read(v) (*(volatile int *)&(v)->counter)
+#define atomic_read(v) ACCESS_ONCE((v)->counter)
 #endif
 
 /**
 
 #include <linux/irqflags.h>
 
-/**
- * atomic_add_return - add integer to atomic variable
- * @i: integer value to add
- * @v: pointer of type atomic_t
- *
- * Atomically adds @i to @v and returns the result
- */
-#ifndef atomic_add_return
-static inline int atomic_add_return(int i, atomic_t *v)
-{
-       unsigned long flags;
-       int temp;
-
-       raw_local_irq_save(flags); /* Don't trace it in an irqsoff handler */
-       temp = v->counter;
-       temp += i;
-       v->counter = temp;
-       raw_local_irq_restore(flags);
-
-       return temp;
-}
-#endif
-
-/**
- * atomic_sub_return - subtract integer from atomic variable
- * @i: integer value to subtract
- * @v: pointer of type atomic_t
- *
- * Atomically subtracts @i from @v and returns the result
- */
-#ifndef atomic_sub_return
-static inline int atomic_sub_return(int i, atomic_t *v)
-{
-       unsigned long flags;
-       int temp;
-
-       raw_local_irq_save(flags); /* Don't trace it in an irqsoff handler */
-       temp = v->counter;
-       temp -= i;
-       v->counter = temp;
-       raw_local_irq_restore(flags);
-
-       return temp;
-}
-#endif
-
 static inline int atomic_add_negative(int i, atomic_t *v)
 {
        return atomic_add_return(i, v) < 0;
@@ -139,49 +177,11 @@ static inline void atomic_dec(atomic_t *v)
 
 static inline int __atomic_add_unless(atomic_t *v, int a, int u)
 {
-  int c, old;
-  c = atomic_read(v);
-  while (c != u && (old = atomic_cmpxchg(v, c, c + a)) != c)
-    c = old;
-  return c;
-}
-
-/**
- * atomic_clear_mask - Atomically clear bits in atomic variable
- * @mask: Mask of the bits to be cleared
- * @v: pointer of type atomic_t
- *
- * Atomically clears the bits set in @mask from @v
- */
-#ifndef atomic_clear_mask
-static inline void atomic_clear_mask(unsigned long mask, atomic_t *v)
-{
-       unsigned long flags;
-
-       mask = ~mask;
-       raw_local_irq_save(flags); /* Don't trace it in a irqsoff handler */
-       v->counter &= mask;
-       raw_local_irq_restore(flags);
+       int c, old;
+       c = atomic_read(v);
+       while (c != u && (old = atomic_cmpxchg(v, c, c + a)) != c)
+               c = old;
+       return c;
 }
-#endif
-
-/**
- * atomic_set_mask - Atomically set bits in atomic variable
- * @mask: Mask of the bits to be set
- * @v: pointer of type atomic_t
- *
- * Atomically sets the bits set in @mask in @v
- */
-#ifndef atomic_set_mask
-static inline void atomic_set_mask(unsigned int mask, atomic_t *v)
-{
-       unsigned long flags;
-
-       raw_local_irq_save(flags); /* Don't trace it in a irqsoff handler */
-       v->counter |= mask;
-       raw_local_irq_restore(flags);
-}
-#endif
 
-#endif /* __KERNEL__ */
 #endif /* __ASM_GENERIC_ATOMIC_H */
index b18ce4f9ee3d8330c9bbd884bcd772dcc172d268..30ad9c86cebb62b1c695afb195fcdfb9ad027bee 100644 (file)
@@ -20,10 +20,22 @@ typedef struct {
 
 extern long long atomic64_read(const atomic64_t *v);
 extern void     atomic64_set(atomic64_t *v, long long i);
-extern void     atomic64_add(long long a, atomic64_t *v);
-extern long long atomic64_add_return(long long a, atomic64_t *v);
-extern void     atomic64_sub(long long a, atomic64_t *v);
-extern long long atomic64_sub_return(long long a, atomic64_t *v);
+
+#define ATOMIC64_OP(op)                                                        \
+extern void     atomic64_##op(long long a, atomic64_t *v);
+
+#define ATOMIC64_OP_RETURN(op)                                         \
+extern long long atomic64_##op##_return(long long a, atomic64_t *v);
+
+#define ATOMIC64_OPS(op)       ATOMIC64_OP(op) ATOMIC64_OP_RETURN(op)
+
+ATOMIC64_OPS(add)
+ATOMIC64_OPS(sub)
+
+#undef ATOMIC64_OPS
+#undef ATOMIC64_OP_RETURN
+#undef ATOMIC64_OP
+
 extern long long atomic64_dec_if_positive(atomic64_t *v);
 extern long long atomic64_cmpxchg(atomic64_t *v, long long o, long long n);
 extern long long atomic64_xchg(atomic64_t *v, long long new);
index d5cb78f539861afdc82eae345ee4c8148fb2448e..fe386fc6e85e27f3c4a1b99262fe023db6a31fc3 100644 (file)
@@ -3,6 +3,8 @@
 
 typedef unsigned long __nocast cputime_t;
 
+#define cmpxchg_cputime(ptr, old, new) cmpxchg(ptr, old, new)
+
 #define cputime_one_jiffy              jiffies_to_cputime(1)
 #define cputime_to_jiffies(__ct)       (__force unsigned long)(__ct)
 #define cputime_to_scaled(__ct)                (__ct)
index 4e817606c5494126a31ae50e58a6e76242d89f07..0419485891f2a8eb6125f154f52d7b16c5fb05b4 100644 (file)
@@ -21,6 +21,8 @@
 typedef u64 __nocast cputime_t;
 typedef u64 __nocast cputime64_t;
 
+#define cmpxchg_cputime(ptr, old, new) cmpxchg64(ptr, old, new)
+
 #define cputime_one_jiffy              jiffies_to_cputime(1)
 
 #define cputime_div(__ct, divisor)  div_u64((__force u64)__ct, divisor)
index a9fd248f5d482c15be819abf48ccc5fd7e78788c..3378dcf4c31ea85b7206fe8b5e03be828330c56d 100644 (file)
@@ -214,14 +214,6 @@ dma_mmap_attrs(struct device *dev, struct vm_area_struct *vma, void *cpu_addr,
 
 #define dma_mmap_coherent(d, v, c, h, s) dma_mmap_attrs(d, v, c, h, s, NULL)
 
-static inline int dma_mmap_writecombine(struct device *dev, struct vm_area_struct *vma,
-                     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);
-}
-
 int
 dma_common_get_sgtable(struct device *dev, struct sg_table *sgt,
                       void *cpu_addr, dma_addr_t dma_addr, size_t size);
index 081ff8826bf6855630f1a7d5a3c51302d72b87c7..752e30d639045c2ec970b479c680a08d4381d4e1 100644 (file)
@@ -253,6 +253,20 @@ static inline int pmd_same(pmd_t pmd_a, pmd_t pmd_b)
 #define pgprot_device pgprot_noncached
 #endif
 
+#ifndef pgprot_modify
+#define pgprot_modify pgprot_modify
+static inline pgprot_t pgprot_modify(pgprot_t oldprot, pgprot_t newprot)
+{
+       if (pgprot_val(oldprot) == pgprot_val(pgprot_noncached(oldprot)))
+               newprot = pgprot_noncached(newprot);
+       if (pgprot_val(oldprot) == pgprot_val(pgprot_writecombine(oldprot)))
+               newprot = pgprot_writecombine(newprot);
+       if (pgprot_val(oldprot) == pgprot_val(pgprot_device(oldprot)))
+               newprot = pgprot_device(newprot);
+       return newprot;
+}
+#endif
+
 /*
  * When walking page tables, get the address of the next boundary,
  * or the end address of the range if that comes earlier.  Although no
index 0d164c6af5397f6a87a9c794bf2c4bbc8cd6c5c5..54add206990166ff44aca927d024d4d62b8256a1 100644 (file)
@@ -15,6 +15,7 @@
 #define _LINUX_PUBLIC_KEY_H
 
 #include <linux/mpi.h>
+#include <keys/asymmetric-type.h>
 #include <crypto/hash_info.h>
 
 enum pkey_algo {
@@ -98,8 +99,9 @@ struct key;
 extern int verify_signature(const struct key *key,
                            const struct public_key_signature *sig);
 
+struct asymmetric_key_id;
 extern struct key *x509_request_asymmetric_key(struct key *keyring,
-                                              const char *issuer,
-                                              const char *key_id);
+                                              const struct asymmetric_key_id *kid,
+                                              bool partial);
 
 #endif /* _LINUX_PUBLIC_KEY_H */
diff --git a/include/drm/ati_pcigart.h b/include/drm/ati_pcigart.h
new file mode 100644 (file)
index 0000000..5765648
--- /dev/null
@@ -0,0 +1,30 @@
+#ifndef DRM_ATI_PCIGART_H
+#define DRM_ATI_PCIGART_H
+
+#include <drm/drm_legacy.h>
+
+/* location of GART table */
+#define DRM_ATI_GART_MAIN 1
+#define DRM_ATI_GART_FB   2
+
+#define DRM_ATI_GART_PCI 1
+#define DRM_ATI_GART_PCIE 2
+#define DRM_ATI_GART_IGP 3
+
+struct drm_ati_pcigart_info {
+       int gart_table_location;
+       int gart_reg_if;
+       void *addr;
+       dma_addr_t bus_addr;
+       dma_addr_t table_mask;
+       struct drm_dma_handle *table_handle;
+       struct drm_local_map mapping;
+       int table_size;
+};
+
+extern int drm_ati_pcigart_init(struct drm_device *dev,
+                               struct drm_ati_pcigart_info * gart_info);
+extern int drm_ati_pcigart_cleanup(struct drm_device *dev,
+                                  struct drm_ati_pcigart_info * gart_info);
+
+#endif
index 196890735367daf53a796099ca21b153d55b560c..53ed87698a74e0e4ae121e75607d74645456525a 100644 (file)
@@ -1,17 +1,14 @@
-/**
- * \file drmP.h
- * Private header for Direct Rendering Manager
- *
- * \author Rickard E. (Rik) Faith <faith@valinux.com>
- * \author Gareth Hughes <gareth@valinux.com>
- */
-
 /*
+ * Internal Header for the Direct Rendering Manager
+ *
  * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
  * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
  * Copyright (c) 2009-2010, Code Aurora Forum.
  * All rights reserved.
  *
+ * Author: Rickard E. (Rik) Faith <faith@valinux.com>
+ * Author: Gareth Hughes <gareth@valinux.com>
+ *
  * Permission is hereby granted, free of charge, to any person obtaining a
  * copy of this software and associated documentation files (the "Software"),
  * to deal in the Software without restriction, including without limitation
 #ifndef _DRM_P_H_
 #define _DRM_P_H_
 
-#ifdef __KERNEL__
-#ifdef __alpha__
-/* add include of current.h so that "current" is defined
- * before static inline funcs in wait.h. Doing this so we
- * can build the DRM (part of PI DRI). 4/21/2000 S + B */
-#include <asm/current.h>
-#endif                         /* __alpha__ */
-#include <linux/kernel.h>
-#include <linux/kref.h>
-#include <linux/miscdevice.h>
+#include <linux/agp_backend.h>
+#include <linux/cdev.h>
+#include <linux/dma-mapping.h>
+#include <linux/file.h>
 #include <linux/fs.h>
+#include <linux/highmem.h>
+#include <linux/idr.h>
 #include <linux/init.h>
-#include <linux/file.h>
-#include <linux/platform_device.h>
-#include <linux/pci.h>
+#include <linux/io.h>
 #include <linux/jiffies.h>
-#include <linux/dma-mapping.h>
+#include <linux/kernel.h>
+#include <linux/kref.h>
+#include <linux/miscdevice.h>
 #include <linux/mm.h>
-#include <linux/cdev.h>
 #include <linux/mutex.h>
-#include <linux/io.h>
-#include <linux/slab.h>
+#include <linux/pci.h>
+#include <linux/platform_device.h>
+#include <linux/poll.h>
 #include <linux/ratelimit.h>
-#if defined(__alpha__) || defined(__powerpc__)
-#include <asm/pgtable.h>       /* For pte_wrprotect */
-#endif
-#include <asm/mman.h>
-#include <asm/uaccess.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
 #include <linux/types.h>
-#include <linux/agp_backend.h>
+#include <linux/vmalloc.h>
 #include <linux/workqueue.h>
-#include <linux/poll.h>
+
+#include <asm/mman.h>
 #include <asm/pgalloc.h>
-#include <drm/drm.h>
-#include <drm/drm_sarea.h>
-#include <drm/drm_vma_manager.h>
+#include <asm/uaccess.h>
 
-#include <linux/idr.h>
+#include <uapi/drm/drm.h>
+#include <uapi/drm/drm_mode.h>
 
-#define __OS_HAS_AGP (defined(CONFIG_AGP) || (defined(CONFIG_AGP_MODULE) && defined(MODULE)))
+#include <drm/drm_agpsupport.h>
+#include <drm/drm_crtc.h>
+#include <drm/drm_global.h>
+#include <drm/drm_hashtab.h>
+#include <drm/drm_mem_util.h>
+#include <drm/drm_mm.h>
+#include <drm/drm_os_linux.h>
+#include <drm/drm_sarea.h>
+#include <drm/drm_vma_manager.h>
 
 struct module;
 
 struct drm_file;
 struct drm_device;
+struct drm_agp_head;
+struct drm_local_map;
+struct drm_device_dma;
+struct drm_dma_handle;
+struct drm_gem_object;
 
 struct device_node;
 struct videomode;
 struct reservation_object;
-
-#include <drm/drm_os_linux.h>
-#include <drm/drm_hashtab.h>
-#include <drm/drm_mm.h>
+struct dma_buf_attachment;
 
 /*
  * 4 debug categories are defined:
@@ -126,7 +126,7 @@ extern __printf(2, 3)
 void drm_ut_debug_printk(const char *function_name,
                         const char *format, ...);
 extern __printf(2, 3)
-int drm_err(const char *func, const char *format, ...);
+void drm_err(const char *func, const char *format, ...);
 
 /***********************************************************************/
 /** \name DRM template customization defaults */
@@ -144,19 +144,6 @@ int drm_err(const char *func, const char *format, ...);
 #define DRIVER_PRIME       0x4000
 #define DRIVER_RENDER      0x8000
 
-/***********************************************************************/
-/** \name Begin the DRM... */
-/*@{*/
-
-#define DRM_DEBUG_CODE 2         /**< Include debugging code if > 1, then
-                                    also include looping detection. */
-
-#define DRM_MAGIC_HASH_ORDER  4  /**< Size of key hash table. Must be power of 2. */
-
-#define DRM_MAP_HASH_OFFSET 0x10000000
-
-/*@}*/
-
 /***********************************************************************/
 /** \name Macros to make printk easier */
 /*@{*/
@@ -198,7 +185,6 @@ int drm_err(const char *func, const char *format, ...);
  * \param fmt printf() like format string.
  * \param arg arguments
  */
-#if DRM_DEBUG_CODE
 #define DRM_DEBUG(fmt, args...)                                                \
        do {                                                            \
                if (unlikely(drm_debug & DRM_UT_CORE))                  \
@@ -220,12 +206,6 @@ int drm_err(const char *func, const char *format, ...);
                if (unlikely(drm_debug & DRM_UT_PRIME))                 \
                        drm_ut_debug_printk(__func__, fmt, ##args);     \
        } while (0)
-#else
-#define DRM_DEBUG_DRIVER(fmt, args...) do { } while (0)
-#define DRM_DEBUG_KMS(fmt, args...)    do { } while (0)
-#define DRM_DEBUG_PRIME(fmt, args...)  do { } while (0)
-#define DRM_DEBUG(fmt, arg...)          do { } while (0)
-#endif
 
 /*@}*/
 
@@ -235,23 +215,6 @@ int drm_err(const char *func, const char *format, ...);
 
 #define DRM_IF_VERSION(maj, min) (maj << 16 | min)
 
-/**
- * Test that the hardware lock is held by the caller, returning otherwise.
- *
- * \param dev DRM device.
- * \param filp file pointer of the caller.
- */
-#define LOCK_TEST_WITH_RETURN( dev, _file_priv )                               \
-do {                                                                           \
-       if (!_DRM_LOCK_IS_HELD(_file_priv->master->lock.hw_lock->lock) ||       \
-           _file_priv->master->lock.file_priv != _file_priv)   {               \
-               DRM_ERROR( "%s called without lock held, held  %d owner %p %p\n",\
-                          __func__, _DRM_LOCK_IS_HELD(_file_priv->master->lock.hw_lock->lock),\
-                          _file_priv->master->lock.file_priv, _file_priv);     \
-               return -EINVAL;                                                 \
-       }                                                                       \
-} while (0)
-
 /**
  * Ioctl function type.
  *
@@ -292,80 +255,6 @@ struct drm_ioctl_desc {
 #define DRM_IOCTL_DEF_DRV(ioctl, _func, _flags)                        \
        [DRM_IOCTL_NR(DRM_##ioctl)] = {.cmd = DRM_##ioctl, .func = _func, .flags = _flags, .cmd_drv = DRM_IOCTL_##ioctl, .name = #ioctl}
 
-struct drm_magic_entry {
-       struct list_head head;
-       struct drm_hash_item hash_item;
-       struct drm_file *priv;
-};
-
-struct drm_vma_entry {
-       struct list_head head;
-       struct vm_area_struct *vma;
-       pid_t pid;
-};
-
-/**
- * DMA buffer.
- */
-struct drm_buf {
-       int idx;                       /**< Index into master buflist */
-       int total;                     /**< Buffer size */
-       int order;                     /**< log-base-2(total) */
-       int used;                      /**< Amount of buffer in use (for DMA) */
-       unsigned long offset;          /**< Byte offset (used internally) */
-       void *address;                 /**< Address of buffer */
-       unsigned long bus_address;     /**< Bus address of buffer */
-       struct drm_buf *next;          /**< Kernel-only: used for free list */
-       __volatile__ int waiting;      /**< On kernel DMA queue */
-       __volatile__ int pending;      /**< On hardware DMA queue */
-       struct drm_file *file_priv;    /**< Private of holding file descr */
-       int context;                   /**< Kernel queue for this buffer */
-       int while_locked;              /**< Dispatch this buffer while locked */
-       enum {
-               DRM_LIST_NONE = 0,
-               DRM_LIST_FREE = 1,
-               DRM_LIST_WAIT = 2,
-               DRM_LIST_PEND = 3,
-               DRM_LIST_PRIO = 4,
-               DRM_LIST_RECLAIM = 5
-       } list;                        /**< Which list we're on */
-
-       int dev_priv_size;               /**< Size of buffer private storage */
-       void *dev_private;               /**< Per-buffer private storage */
-};
-
-/** bufs is one longer than it has to be */
-struct drm_waitlist {
-       int count;                      /**< Number of possible buffers */
-       struct drm_buf **bufs;          /**< List of pointers to buffers */
-       struct drm_buf **rp;                    /**< Read pointer */
-       struct drm_buf **wp;                    /**< Write pointer */
-       struct drm_buf **end;           /**< End pointer */
-       spinlock_t read_lock;
-       spinlock_t write_lock;
-};
-
-typedef struct drm_dma_handle {
-       dma_addr_t busaddr;
-       void *vaddr;
-       size_t size;
-} drm_dma_handle_t;
-
-/**
- * Buffer entry.  There is one of this for each buffer size order.
- */
-struct drm_buf_entry {
-       int buf_size;                   /**< size */
-       int buf_count;                  /**< number of buffers */
-       struct drm_buf *buflist;                /**< buffer list */
-       int seg_count;
-       int page_order;
-       struct drm_dma_handle **seglist;
-
-       int low_mark;                   /**< Low water mark */
-       int high_mark;                  /**< High water mark */
-};
-
 /* Event queued up for userspace to read */
 struct drm_pending_event {
        struct drm_event *event;
@@ -443,207 +332,6 @@ struct drm_lock_data {
        int idle_has_lock;
 };
 
-/**
- * DMA data.
- */
-struct drm_device_dma {
-
-       struct drm_buf_entry bufs[DRM_MAX_ORDER + 1];   /**< buffers, grouped by their size order */
-       int buf_count;                  /**< total number of buffers */
-       struct drm_buf **buflist;               /**< Vector of pointers into drm_device_dma::bufs */
-       int seg_count;
-       int page_count;                 /**< number of pages */
-       unsigned long *pagelist;        /**< page list */
-       unsigned long byte_count;
-       enum {
-               _DRM_DMA_USE_AGP = 0x01,
-               _DRM_DMA_USE_SG = 0x02,
-               _DRM_DMA_USE_FB = 0x04,
-               _DRM_DMA_USE_PCI_RO = 0x08
-       } flags;
-
-};
-
-/**
- * AGP memory entry.  Stored as a doubly linked list.
- */
-struct drm_agp_mem {
-       unsigned long handle;           /**< handle */
-       struct agp_memory *memory;
-       unsigned long bound;            /**< address */
-       int pages;
-       struct list_head head;
-};
-
-/**
- * AGP data.
- *
- * \sa drm_agp_init() and drm_device::agp.
- */
-struct drm_agp_head {
-       struct agp_kern_info agp_info;          /**< AGP device information */
-       struct list_head memory;
-       unsigned long mode;             /**< AGP mode */
-       struct agp_bridge_data *bridge;
-       int enabled;                    /**< whether the AGP bus as been enabled */
-       int acquired;                   /**< whether the AGP device has been acquired */
-       unsigned long base;
-       int agp_mtrr;
-       int cant_use_aperture;
-       unsigned long page_mask;
-};
-
-/**
- * Scatter-gather memory.
- */
-struct drm_sg_mem {
-       unsigned long handle;
-       void *virtual;
-       int pages;
-       struct page **pagelist;
-       dma_addr_t *busaddr;
-};
-
-struct drm_sigdata {
-       int context;
-       struct drm_hw_lock *lock;
-};
-
-
-/**
- * Kernel side of a mapping
- */
-struct drm_local_map {
-       resource_size_t offset;  /**< Requested physical address (0 for SAREA)*/
-       unsigned long size;      /**< Requested physical size (bytes) */
-       enum drm_map_type type;  /**< Type of memory to map */
-       enum drm_map_flags flags;        /**< Flags */
-       void *handle;            /**< User-space: "Handle" to pass to mmap() */
-                                /**< Kernel-space: kernel-virtual address */
-       int mtrr;                /**< MTRR slot used */
-};
-
-typedef struct drm_local_map drm_local_map_t;
-
-/**
- * Mappings list
- */
-struct drm_map_list {
-       struct list_head head;          /**< list head */
-       struct drm_hash_item hash;
-       struct drm_local_map *map;      /**< mapping */
-       uint64_t user_token;
-       struct drm_master *master;
-};
-
-/* location of GART table */
-#define DRM_ATI_GART_MAIN 1
-#define DRM_ATI_GART_FB   2
-
-#define DRM_ATI_GART_PCI 1
-#define DRM_ATI_GART_PCIE 2
-#define DRM_ATI_GART_IGP 3
-
-struct drm_ati_pcigart_info {
-       int gart_table_location;
-       int gart_reg_if;
-       void *addr;
-       dma_addr_t bus_addr;
-       dma_addr_t table_mask;
-       struct drm_dma_handle *table_handle;
-       struct drm_local_map mapping;
-       int table_size;
-};
-
-/**
- * This structure defines the drm_mm memory object, which will be used by the
- * DRM for its buffer objects.
- */
-struct drm_gem_object {
-       /** Reference count of this object */
-       struct kref refcount;
-
-       /**
-        * handle_count - gem file_priv handle count of this object
-        *
-        * Each handle also holds a reference. Note that when the handle_count
-        * drops to 0 any global names (e.g. the id in the flink namespace) will
-        * be cleared.
-        *
-        * Protected by dev->object_name_lock.
-        * */
-       unsigned handle_count;
-
-       /** Related drm device */
-       struct drm_device *dev;
-
-       /** File representing the shmem storage */
-       struct file *filp;
-
-       /* Mapping info for this object */
-       struct drm_vma_offset_node vma_node;
-
-       /**
-        * Size of the object, in bytes.  Immutable over the object's
-        * lifetime.
-        */
-       size_t size;
-
-       /**
-        * Global name for this object, starts at 1. 0 means unnamed.
-        * Access is covered by the object_name_lock in the related drm_device
-        */
-       int name;
-
-       /**
-        * Memory domains. These monitor which caches contain read/write data
-        * related to the object. When transitioning from one set of domains
-        * to another, the driver is called to ensure that caches are suitably
-        * flushed and invalidated
-        */
-       uint32_t read_domains;
-       uint32_t write_domain;
-
-       /**
-        * While validating an exec operation, the
-        * new read/write domain values are computed here.
-        * They will be transferred to the above values
-        * at the point that any cache flushing occurs
-        */
-       uint32_t pending_read_domains;
-       uint32_t pending_write_domain;
-
-       /**
-        * dma_buf - dma buf associated with this GEM object
-        *
-        * Pointer to the dma-buf associated with this gem object (either
-        * through importing or exporting). We break the resulting reference
-        * loop when the last gem handle for this object is released.
-        *
-        * Protected by obj->object_name_lock
-        */
-       struct dma_buf *dma_buf;
-
-       /**
-        * import_attach - dma buf attachment backing this object
-        *
-        * Any foreign dma_buf imported as a gem object has this set to the
-        * attachment point for the device. This is invariant over the lifetime
-        * of a gem object.
-        *
-        * The driver's ->gem_free_object callback is responsible for cleaning
-        * up the dma_buf attachment and references acquired at import time.
-        *
-        * Note that the drm gem/prime core does not depend upon drivers setting
-        * this field any more. So for drivers where this doesn't make sense
-        * (e.g. virtual devices or a displaylink behind an usb bus) they can
-        * simply leave it as NULL.
-        */
-       struct dma_buf_attachment *import_attach;
-};
-
-#include <drm/drm_crtc.h>
-
 /**
  * struct drm_master - drm master structure
  *
@@ -651,7 +339,6 @@ struct drm_gem_object {
  * @minor: Link back to minor char device we are master for. Immutable.
  * @unique: Unique identifier: e.g. busid. Protected by drm_global_mutex.
  * @unique_len: Length of unique field. Protected by drm_global_mutex.
- * @unique_size: Amount allocated. Protected by drm_global_mutex.
  * @magiclist: Hash of used authentication tokens. Protected by struct_mutex.
  * @magicfree: List of used authentication tokens. Protected by struct_mutex.
  * @lock: DRI lock information.
@@ -662,7 +349,6 @@ struct drm_master {
        struct drm_minor *minor;
        char *unique;
        int unique_len;
-       int unique_size;
        struct drm_open_hash magiclist;
        struct list_head magicfree;
        struct drm_lock_data lock;
@@ -677,17 +363,13 @@ struct drm_master {
 /* Flags and return codes for get_vblank_timestamp() driver function. */
 #define DRM_CALLED_FROM_VBLIRQ 1
 #define DRM_VBLANKTIME_SCANOUTPOS_METHOD (1 << 0)
-#define DRM_VBLANKTIME_INVBL             (1 << 1)
+#define DRM_VBLANKTIME_IN_VBLANK         (1 << 1)
 
 /* get_scanout_position() return flags */
 #define DRM_SCANOUTPOS_VALID        (1 << 0)
-#define DRM_SCANOUTPOS_INVBL        (1 << 1)
+#define DRM_SCANOUTPOS_IN_VBLANK    (1 << 1)
 #define DRM_SCANOUTPOS_ACCURATE     (1 << 2)
 
-struct drm_bus {
-       int (*set_busid)(struct drm_device *dev, struct drm_master *master);
-};
-
 /**
  * DRM driver structure. This structure represent the common code for
  * a family of cards. There will one drm_device for each card present
@@ -706,6 +388,7 @@ struct drm_driver {
        int (*dma_ioctl) (struct drm_device *dev, void *data, struct drm_file *file_priv);
        int (*dma_quiescent) (struct drm_device *);
        int (*context_dtor) (struct drm_device *dev, int context);
+       int (*set_busid)(struct drm_device *dev, struct drm_master *master);
 
        /**
         * get_vblank_counter - get raw hardware vblank counter
@@ -888,7 +571,8 @@ struct drm_driver {
                                struct drm_gem_object *obj);
        struct sg_table *(*gem_prime_get_sg_table)(struct drm_gem_object *obj);
        struct drm_gem_object *(*gem_prime_import_sg_table)(
-                               struct drm_device *dev, size_t size,
+                               struct drm_device *dev,
+                               struct dma_buf_attachment *attach,
                                struct sg_table *sgt);
        void *(*gem_prime_vmap)(struct drm_gem_object *obj);
        void (*gem_prime_vunmap)(struct drm_gem_object *obj, void *vaddr);
@@ -924,7 +608,6 @@ struct drm_driver {
        const struct drm_ioctl_desc *ioctls;
        int num_ioctls;
        const struct file_operations *fops;
-       struct drm_bus *bus;
 
        /* List of devices hanging off this driver with stealth attach. */
        struct list_head legacy_dev_list;
@@ -1079,6 +762,16 @@ struct drm_device {
         */
        bool vblank_disable_allowed;
 
+       /*
+        * If true, vblank interrupt will be disabled immediately when the
+        * refcount drops to zero, as opposed to via the vblank disable
+        * timer.
+        * This can be set to true it the hardware has a working vblank
+        * counter and the driver uses drm_vblank_on() and drm_vblank_off()
+        * appropriately.
+        */
+       bool vblank_disable_immediate;
+
        /* array of size num_crtcs */
        struct drm_vblank_crtc *vblank;
 
@@ -1103,13 +796,16 @@ struct drm_device {
 #endif
 
        struct platform_device *platformdev; /**< Platform device struture */
-       struct usb_device *usbdev;
 
        struct drm_sg_mem *sg;  /**< Scatter gather memory */
        unsigned int num_crtcs;                  /**< Number of CRTCs on this device */
-       struct drm_sigdata sigdata;        /**< For block_all_signals */
        sigset_t sigmask;
 
+       struct {
+               int context;
+               struct drm_hw_lock *lock;
+       } sigdata;
+
        struct drm_local_map *agp_buffer_map;
        unsigned int agp_buffer_token;
 
@@ -1172,112 +868,32 @@ extern long drm_ioctl(struct file *filp,
                      unsigned int cmd, unsigned long arg);
 extern long drm_compat_ioctl(struct file *filp,
                             unsigned int cmd, unsigned long arg);
-extern int drm_lastclose(struct drm_device *dev);
 extern bool drm_ioctl_flags(unsigned int nr, unsigned int *flags);
 
                                /* Device support (drm_fops.h) */
-extern struct mutex drm_global_mutex;
 extern int drm_open(struct inode *inode, struct file *filp);
 extern ssize_t drm_read(struct file *filp, char __user *buffer,
                        size_t count, loff_t *offset);
 extern int drm_release(struct inode *inode, struct file *filp);
 
                                /* Mapping support (drm_vm.h) */
-extern int drm_mmap(struct file *filp, struct vm_area_struct *vma);
-extern int drm_mmap_locked(struct file *filp, struct vm_area_struct *vma);
-extern void drm_vm_open_locked(struct drm_device *dev, struct vm_area_struct *vma);
-extern void drm_vm_close_locked(struct drm_device *dev, struct vm_area_struct *vma);
 extern unsigned int drm_poll(struct file *filp, struct poll_table_struct *wait);
 
-                               /* Memory management support (drm_memory.h) */
-#include <drm/drm_memory.h>
-
-
-                               /* Misc. IOCTL support (drm_ioctl.h) */
-extern int drm_irq_by_busid(struct drm_device *dev, void *data,
-                           struct drm_file *file_priv);
-extern int drm_getunique(struct drm_device *dev, void *data,
-                        struct drm_file *file_priv);
-extern int drm_setunique(struct drm_device *dev, void *data,
-                        struct drm_file *file_priv);
-extern int drm_getmap(struct drm_device *dev, void *data,
-                     struct drm_file *file_priv);
-extern int drm_getclient(struct drm_device *dev, void *data,
-                        struct drm_file *file_priv);
-extern int drm_getstats(struct drm_device *dev, void *data,
-                       struct drm_file *file_priv);
-extern int drm_getcap(struct drm_device *dev, void *data,
-                     struct drm_file *file_priv);
-extern int drm_setclientcap(struct drm_device *dev, void *data,
-                           struct drm_file *file_priv);
-extern int drm_setversion(struct drm_device *dev, void *data,
-                         struct drm_file *file_priv);
-extern int drm_noop(struct drm_device *dev, void *data,
-                   struct drm_file *file_priv);
-
-                               /* Authentication IOCTL support (drm_auth.h) */
-extern int drm_getmagic(struct drm_device *dev, void *data,
-                       struct drm_file *file_priv);
-extern int drm_authmagic(struct drm_device *dev, void *data,
-                        struct drm_file *file_priv);
-extern int drm_remove_magic(struct drm_master *master, drm_magic_t magic);
+/* Misc. IOCTL support (drm_ioctl.c) */
+int drm_noop(struct drm_device *dev, void *data,
+            struct drm_file *file_priv);
 
 /* Cache management (drm_cache.c) */
 void drm_clflush_pages(struct page *pages[], unsigned long num_pages);
 void drm_clflush_sg(struct sg_table *st);
 void drm_clflush_virt_range(void *addr, unsigned long length);
 
-                               /* Locking IOCTL support (drm_lock.h) */
-extern int drm_lock(struct drm_device *dev, void *data,
-                   struct drm_file *file_priv);
-extern int drm_unlock(struct drm_device *dev, void *data,
-                     struct drm_file *file_priv);
-extern int drm_lock_free(struct drm_lock_data *lock_data, unsigned int context);
-extern void drm_idlelock_take(struct drm_lock_data *lock_data);
-extern void drm_idlelock_release(struct drm_lock_data *lock_data);
-
 /*
  * These are exported to drivers so that they can implement fencing using
  * DMA quiscent + idle. DMA quiescent usually requires the hardware lock.
  */
 
-extern int drm_i_have_hw_lock(struct drm_device *dev, struct drm_file *file_priv);
-
-                               /* Buffer management support (drm_bufs.h) */
-extern int drm_addbufs_agp(struct drm_device *dev, struct drm_buf_desc * request);
-extern int drm_addbufs_pci(struct drm_device *dev, struct drm_buf_desc * request);
-extern int drm_addmap(struct drm_device *dev, resource_size_t offset,
-                     unsigned int size, enum drm_map_type type,
-                     enum drm_map_flags flags, struct drm_local_map **map_ptr);
-extern int drm_addmap_ioctl(struct drm_device *dev, void *data,
-                           struct drm_file *file_priv);
-extern int drm_rmmap(struct drm_device *dev, struct drm_local_map *map);
-extern int drm_rmmap_locked(struct drm_device *dev, struct drm_local_map *map);
-extern int drm_rmmap_ioctl(struct drm_device *dev, void *data,
-                          struct drm_file *file_priv);
-extern int drm_addbufs(struct drm_device *dev, void *data,
-                      struct drm_file *file_priv);
-extern int drm_infobufs(struct drm_device *dev, void *data,
-                       struct drm_file *file_priv);
-extern int drm_markbufs(struct drm_device *dev, void *data,
-                       struct drm_file *file_priv);
-extern int drm_freebufs(struct drm_device *dev, void *data,
-                       struct drm_file *file_priv);
-extern int drm_mapbufs(struct drm_device *dev, void *data,
-                      struct drm_file *file_priv);
-extern int drm_dma_ioctl(struct drm_device *dev, void *data,
-                        struct drm_file *file_priv);
-
-                               /* DMA support (drm_dma.h) */
-extern int drm_legacy_dma_setup(struct drm_device *dev);
-extern void drm_legacy_dma_takedown(struct drm_device *dev);
-extern void drm_free_buffer(struct drm_device *dev, struct drm_buf * buf);
-extern void drm_core_reclaim_buffers(struct drm_device *dev,
-                                    struct drm_file *filp);
-
                                /* IRQ support (drm_irq.h) */
-extern int drm_control(struct drm_device *dev, void *data,
-                      struct drm_file *file_priv);
 extern int drm_irq_install(struct drm_device *dev, int irq);
 extern int drm_irq_uninstall(struct drm_device *dev);
 
@@ -1294,14 +910,14 @@ extern int drm_vblank_get(struct drm_device *dev, int crtc);
 extern void drm_vblank_put(struct drm_device *dev, int crtc);
 extern int drm_crtc_vblank_get(struct drm_crtc *crtc);
 extern void drm_crtc_vblank_put(struct drm_crtc *crtc);
+extern void drm_wait_one_vblank(struct drm_device *dev, int crtc);
+extern void drm_crtc_wait_one_vblank(struct drm_crtc *crtc);
 extern void drm_vblank_off(struct drm_device *dev, int crtc);
 extern void drm_vblank_on(struct drm_device *dev, int crtc);
 extern void drm_crtc_vblank_off(struct drm_crtc *crtc);
 extern void drm_crtc_vblank_on(struct drm_crtc *crtc);
 extern void drm_vblank_cleanup(struct drm_device *dev);
 
-extern u32 drm_get_last_vbltimestamp(struct drm_device *dev, int crtc,
-                                    struct timeval *tvblank, unsigned flags);
 extern int drm_calc_vbltimestamp_from_scanoutpos(struct drm_device *dev,
                                                 int crtc, int *max_error,
                                                 struct timeval *vblank_time,
@@ -1311,23 +927,23 @@ extern int drm_calc_vbltimestamp_from_scanoutpos(struct drm_device *dev,
 extern void drm_calc_timestamping_constants(struct drm_crtc *crtc,
                                            const struct drm_display_mode *mode);
 
+/**
+ * drm_crtc_vblank_waitqueue - get vblank waitqueue for the CRTC
+ * @crtc: which CRTC's vblank waitqueue to retrieve
+ *
+ * This function returns a pointer to the vblank waitqueue for the CRTC.
+ * Drivers can use this to implement vblank waits using wait_event() & co.
+ */
+static inline wait_queue_head_t *drm_crtc_vblank_waitqueue(struct drm_crtc *crtc)
+{
+       return &crtc->dev->vblank[drm_crtc_index(crtc)].queue;
+}
 
 /* Modesetting support */
 extern void drm_vblank_pre_modeset(struct drm_device *dev, int crtc);
 extern void drm_vblank_post_modeset(struct drm_device *dev, int crtc);
-extern int drm_modeset_ctl(struct drm_device *dev, void *data,
-                          struct drm_file *file_priv);
-
-                               /* AGP/GART support (drm_agpsupport.h) */
-
-#include <drm/drm_agpsupport.h>
 
                                /* Stub support (drm_stub.h) */
-extern int drm_setmaster_ioctl(struct drm_device *dev, void *data,
-                              struct drm_file *file_priv);
-extern int drm_dropmaster_ioctl(struct drm_device *dev, void *data,
-                               struct drm_file *file_priv);
-struct drm_master *drm_master_create(struct drm_minor *minor);
 extern struct drm_master *drm_master_get(struct drm_master *master);
 extern void drm_master_put(struct drm_master **master);
 
@@ -1335,33 +951,14 @@ extern void drm_put_dev(struct drm_device *dev);
 extern void drm_unplug_dev(struct drm_device *dev);
 extern unsigned int drm_debug;
 
-extern unsigned int drm_vblank_offdelay;
-extern unsigned int drm_timestamp_precision;
-extern unsigned int drm_timestamp_monotonic;
-
-extern struct class *drm_class;
-
-extern struct drm_local_map *drm_getsarea(struct drm_device *dev);
-
                                /* Debugfs support */
 #if defined(CONFIG_DEBUG_FS)
-extern int drm_debugfs_init(struct drm_minor *minor, int minor_id,
-                           struct dentry *root);
 extern int drm_debugfs_create_files(const struct drm_info_list *files,
                                    int count, struct dentry *root,
                                    struct drm_minor *minor);
 extern int drm_debugfs_remove_files(const struct drm_info_list *files,
                                    int count, struct drm_minor *minor);
-extern int drm_debugfs_cleanup(struct drm_minor *minor);
-extern int drm_debugfs_connector_add(struct drm_connector *connector);
-extern void drm_debugfs_connector_remove(struct drm_connector *connector);
 #else
-static inline int drm_debugfs_init(struct drm_minor *minor, int minor_id,
-                                  struct dentry *root)
-{
-       return 0;
-}
-
 static inline int drm_debugfs_create_files(const struct drm_info_list *files,
                                           int count, struct dentry *root,
                                           struct drm_minor *minor)
@@ -1374,31 +971,8 @@ static inline int drm_debugfs_remove_files(const struct drm_info_list *files,
 {
        return 0;
 }
-
-static inline int drm_debugfs_cleanup(struct drm_minor *minor)
-{
-       return 0;
-}
-
-static inline int drm_debugfs_connector_add(struct drm_connector *connector)
-{
-       return 0;
-}
-static inline void drm_debugfs_connector_remove(struct drm_connector *connector)
-{
-}
-
 #endif
 
-                               /* Info file support */
-extern int drm_name_info(struct seq_file *m, void *data);
-extern int drm_vm_info(struct seq_file *m, void *data);
-extern int drm_bufs_info(struct seq_file *m, void *data);
-extern int drm_vblank_info(struct seq_file *m, void *data);
-extern int drm_clients_info(struct seq_file *m, void* data);
-extern int drm_gem_name_info(struct seq_file *m, void *data);
-
-
 extern struct dma_buf *drm_gem_prime_export(struct drm_device *dev,
                struct drm_gem_object *obj, int flags);
 extern int drm_gem_prime_handle_to_fd(struct drm_device *dev,
@@ -1410,150 +984,20 @@ extern int drm_gem_prime_fd_to_handle(struct drm_device *dev,
                struct drm_file *file_priv, int prime_fd, uint32_t *handle);
 extern void drm_gem_dmabuf_release(struct dma_buf *dma_buf);
 
-extern int drm_prime_handle_to_fd_ioctl(struct drm_device *dev, void *data,
-                                       struct drm_file *file_priv);
-extern int drm_prime_fd_to_handle_ioctl(struct drm_device *dev, void *data,
-                                       struct drm_file *file_priv);
-
 extern int drm_prime_sg_to_page_addr_arrays(struct sg_table *sgt, struct page **pages,
                                            dma_addr_t *addrs, int max_pages);
 extern struct sg_table *drm_prime_pages_to_sg(struct page **pages, int nr_pages);
 extern void drm_prime_gem_destroy(struct drm_gem_object *obj, struct sg_table *sg);
 
-int drm_gem_dumb_destroy(struct drm_file *file,
-                        struct drm_device *dev,
-                        uint32_t handle);
-
-void drm_prime_init_file_private(struct drm_prime_file_private *prime_fpriv);
-void drm_prime_destroy_file_private(struct drm_prime_file_private *prime_fpriv);
-void drm_prime_remove_buf_handle_locked(struct drm_prime_file_private *prime_fpriv, struct dma_buf *dma_buf);
-
-#if DRM_DEBUG_CODE
-extern int drm_vma_info(struct seq_file *m, void *data);
-#endif
 
-                               /* Scatter Gather Support (drm_scatter.h) */
-extern void drm_legacy_sg_cleanup(struct drm_device *dev);
-extern int drm_sg_alloc(struct drm_device *dev, void *data,
-                       struct drm_file *file_priv);
-extern int drm_sg_free(struct drm_device *dev, void *data,
-                      struct drm_file *file_priv);
-
-                              /* ATI PCIGART support (ati_pcigart.h) */
-extern int drm_ati_pcigart_init(struct drm_device *dev,
-                               struct drm_ati_pcigart_info * gart_info);
-extern int drm_ati_pcigart_cleanup(struct drm_device *dev,
-                                  struct drm_ati_pcigart_info * gart_info);
-
-extern drm_dma_handle_t *drm_pci_alloc(struct drm_device *dev, size_t size,
-                                      size_t align);
-extern void __drm_pci_free(struct drm_device *dev, drm_dma_handle_t * dmah);
-extern void drm_pci_free(struct drm_device *dev, drm_dma_handle_t * dmah);
-extern int drm_pci_set_unique(struct drm_device *dev,
-                             struct drm_master *master,
-                             struct drm_unique *u);
+extern struct drm_dma_handle *drm_pci_alloc(struct drm_device *dev, size_t size,
+                                           size_t align);
+extern void drm_pci_free(struct drm_device *dev, struct drm_dma_handle * dmah);
 
                               /* sysfs support (drm_sysfs.c) */
-struct drm_sysfs_class;
-extern struct class *drm_sysfs_create(struct module *owner, char *name);
-extern void drm_sysfs_destroy(void);
-extern struct device *drm_sysfs_minor_alloc(struct drm_minor *minor);
 extern void drm_sysfs_hotplug_event(struct drm_device *dev);
-extern int drm_sysfs_connector_add(struct drm_connector *connector);
-extern void drm_sysfs_connector_remove(struct drm_connector *connector);
-
-/* Graphics Execution Manager library functions (drm_gem.c) */
-int drm_gem_init(struct drm_device *dev);
-void drm_gem_destroy(struct drm_device *dev);
-void drm_gem_object_release(struct drm_gem_object *obj);
-void drm_gem_object_free(struct kref *kref);
-int drm_gem_object_init(struct drm_device *dev,
-                       struct drm_gem_object *obj, size_t size);
-void drm_gem_private_object_init(struct drm_device *dev,
-                                struct drm_gem_object *obj, size_t size);
-void drm_gem_vm_open(struct vm_area_struct *vma);
-void drm_gem_vm_close(struct vm_area_struct *vma);
-int drm_gem_mmap_obj(struct drm_gem_object *obj, unsigned long obj_size,
-                    struct vm_area_struct *vma);
-int drm_gem_mmap(struct file *filp, struct vm_area_struct *vma);
-
-#include <drm/drm_global.h>
-
-static inline void
-drm_gem_object_reference(struct drm_gem_object *obj)
-{
-       kref_get(&obj->refcount);
-}
-
-static inline void
-drm_gem_object_unreference(struct drm_gem_object *obj)
-{
-       if (obj != NULL)
-               kref_put(&obj->refcount, drm_gem_object_free);
-}
-
-static inline void
-drm_gem_object_unreference_unlocked(struct drm_gem_object *obj)
-{
-       if (obj && !atomic_add_unless(&obj->refcount.refcount, -1, 1)) {
-               struct drm_device *dev = obj->dev;
-
-               mutex_lock(&dev->struct_mutex);
-               if (likely(atomic_dec_and_test(&obj->refcount.refcount)))
-                       drm_gem_object_free(&obj->refcount);
-               mutex_unlock(&dev->struct_mutex);
-       }
-}
-
-int drm_gem_handle_create_tail(struct drm_file *file_priv,
-                              struct drm_gem_object *obj,
-                              u32 *handlep);
-int drm_gem_handle_create(struct drm_file *file_priv,
-                         struct drm_gem_object *obj,
-                         u32 *handlep);
-int drm_gem_handle_delete(struct drm_file *filp, u32 handle);
 
 
-void drm_gem_free_mmap_offset(struct drm_gem_object *obj);
-int drm_gem_create_mmap_offset(struct drm_gem_object *obj);
-int drm_gem_create_mmap_offset_size(struct drm_gem_object *obj, size_t size);
-
-struct page **drm_gem_get_pages(struct drm_gem_object *obj);
-void drm_gem_put_pages(struct drm_gem_object *obj, struct page **pages,
-               bool dirty, bool accessed);
-
-struct drm_gem_object *drm_gem_object_lookup(struct drm_device *dev,
-                                            struct drm_file *filp,
-                                            u32 handle);
-int drm_gem_close_ioctl(struct drm_device *dev, void *data,
-                       struct drm_file *file_priv);
-int drm_gem_flink_ioctl(struct drm_device *dev, void *data,
-                       struct drm_file *file_priv);
-int drm_gem_open_ioctl(struct drm_device *dev, void *data,
-                      struct drm_file *file_priv);
-void drm_gem_open(struct drm_device *dev, struct drm_file *file_private);
-void drm_gem_release(struct drm_device *dev, struct drm_file *file_private);
-
-extern void drm_core_ioremap(struct drm_local_map *map, struct drm_device *dev);
-extern void drm_core_ioremap_wc(struct drm_local_map *map, struct drm_device *dev);
-extern void drm_core_ioremapfree(struct drm_local_map *map, struct drm_device *dev);
-
-static __inline__ struct drm_local_map *drm_core_findmap(struct drm_device *dev,
-                                                        unsigned int token)
-{
-       struct drm_map_list *_entry;
-       list_for_each_entry(_entry, &dev->maplist, head)
-           if (_entry->user_token == token)
-               return _entry->map;
-       return NULL;
-}
-
-static __inline__ void drm_core_dropmap(struct drm_local_map *map)
-{
-}
-
-#include <drm/drm_mem_util.h>
-
 struct drm_device *drm_dev_alloc(struct drm_driver *driver,
                                 struct device *parent);
 void drm_dev_ref(struct drm_device *dev);
@@ -1587,6 +1031,7 @@ extern void drm_pci_exit(struct drm_driver *driver, struct pci_driver *pdriver);
 extern int drm_get_pci_dev(struct pci_dev *pdev,
                           const struct pci_device_id *ent,
                           struct drm_driver *driver);
+extern int drm_pci_set_busid(struct drm_device *dev, struct drm_master *master);
 
 #define DRM_PCIE_SPEED_25 1
 #define DRM_PCIE_SPEED_50 2
@@ -1596,6 +1041,7 @@ extern int drm_pcie_get_speed_cap_mask(struct drm_device *dev, u32 *speed_mask);
 
 /* platform section */
 extern int drm_platform_init(struct drm_driver *driver, struct platform_device *platform_device);
+extern int drm_platform_set_busid(struct drm_device *d, struct drm_master *m);
 
 /* returns true if currently okay to sleep */
 static __inline__ bool drm_can_sleep(void)
@@ -1605,5 +1051,4 @@ static __inline__ bool drm_can_sleep(void)
        return true;
 }
 
-#endif                         /* __KERNEL__ */
 #endif
index 86a02188074bcec037714fdb1ea293dfb4ae3ebe..055dc058d147247c4a1652f98db20cc869a731dc 100644 (file)
@@ -1,12 +1,32 @@
 #ifndef _DRM_AGPSUPPORT_H_
 #define _DRM_AGPSUPPORT_H_
 
+#include <linux/agp_backend.h>
 #include <linux/kernel.h>
+#include <linux/list.h>
 #include <linux/mm.h>
 #include <linux/mutex.h>
 #include <linux/types.h>
-#include <linux/agp_backend.h>
-#include <drm/drmP.h>
+#include <uapi/drm/drm.h>
+
+struct drm_device;
+struct drm_file;
+
+#define __OS_HAS_AGP (defined(CONFIG_AGP) || (defined(CONFIG_AGP_MODULE) && \
+                                             defined(MODULE)))
+
+struct drm_agp_head {
+       struct agp_kern_info agp_info;
+       struct list_head memory;
+       unsigned long mode;
+       struct agp_bridge_data *bridge;
+       int enabled;
+       int acquired;
+       unsigned long base;
+       int agp_mtrr;
+       int cant_use_aperture;
+       unsigned long page_mask;
+};
 
 #if __OS_HAS_AGP
 
@@ -45,6 +65,7 @@ int drm_agp_unbind_ioctl(struct drm_device *dev, void *data,
 int drm_agp_bind(struct drm_device *dev, struct drm_agp_binding *request);
 int drm_agp_bind_ioctl(struct drm_device *dev, void *data,
                       struct drm_file *file_priv);
+
 #else /* __OS_HAS_AGP */
 
 static inline void drm_free_agp(struct agp_memory * handle, int pages)
@@ -172,6 +193,7 @@ static inline int drm_agp_bind_ioctl(struct drm_device *dev, void *data,
 {
        return -ENODEV;
 }
+
 #endif /* __OS_HAS_AGP */
 
 #endif /* _DRM_AGPSUPPORT_H_ */
diff --git a/include/drm/drm_buffer.h b/include/drm/drm_buffer.h
deleted file mode 100644 (file)
index c80d3a3..0000000
+++ /dev/null
@@ -1,148 +0,0 @@
-/**************************************************************************
- *
- * Copyright 2010 Pauli Nieminen.
- * All Rights Reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sub license, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice (including the
- * next paragraph) shall be included in all copies or substantial portions
- * of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS 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.
- *
- *
- **************************************************************************/
-/*
- * Multipart buffer for coping data which is larger than the page size.
- *
- * Authors:
- * Pauli Nieminen <suokkos-at-gmail-dot-com>
- */
-
-#ifndef _DRM_BUFFER_H_
-#define _DRM_BUFFER_H_
-
-#include <drm/drmP.h>
-
-struct drm_buffer {
-       int iterator;
-       int size;
-       char *data[];
-};
-
-
-/**
- * Return the index of page that buffer is currently pointing at.
- */
-static inline int drm_buffer_page(struct drm_buffer *buf)
-{
-       return buf->iterator / PAGE_SIZE;
-}
-/**
- * Return the index of the current byte in the page
- */
-static inline int drm_buffer_index(struct drm_buffer *buf)
-{
-       return buf->iterator & (PAGE_SIZE - 1);
-}
-/**
- * Return number of bytes that is left to process
- */
-static inline int drm_buffer_unprocessed(struct drm_buffer *buf)
-{
-       return buf->size - buf->iterator;
-}
-
-/**
- * Advance the buffer iterator number of bytes that is given.
- */
-static inline void drm_buffer_advance(struct drm_buffer *buf, int bytes)
-{
-       buf->iterator += bytes;
-}
-
-/**
- * Allocate the drm buffer object.
- *
- *   buf: A pointer to a pointer where the object is stored.
- *   size: The number of bytes to allocate.
- */
-extern int drm_buffer_alloc(struct drm_buffer **buf, int size);
-
-/**
- * Copy the user data to the begin of the buffer and reset the processing
- * iterator.
- *
- *   user_data: A pointer the data that is copied to the buffer.
- *   size: The Number of bytes to copy.
- */
-extern int drm_buffer_copy_from_user(struct drm_buffer *buf,
-               void __user *user_data, int size);
-
-/**
- * Free the drm buffer object
- */
-extern void drm_buffer_free(struct drm_buffer *buf);
-
-/**
- * Read an object from buffer that may be split to multiple parts. If object
- * is not split function just returns the pointer to object in buffer. But in
- * case of split object data is copied to given stack object that is suplied
- * by caller.
- *
- * The processing location of the buffer is also advanced to the next byte
- * after the object.
- *
- *   objsize: The size of the objet in bytes.
- *   stack_obj: A pointer to a memory location where object can be copied.
- */
-extern void *drm_buffer_read_object(struct drm_buffer *buf,
-               int objsize, void *stack_obj);
-
-/**
- * Returns the pointer to the dword which is offset number of elements from the
- * current processing location.
- *
- * Caller must make sure that dword is not split in the buffer. This
- * requirement is easily met if all the sizes of objects in buffer are
- * multiples of dword and PAGE_SIZE is multiple dword.
- *
- * Call to this function doesn't change the processing location.
- *
- *   offset: The index of the dword relative to the internat iterator.
- */
-static inline void *drm_buffer_pointer_to_dword(struct drm_buffer *buffer,
-               int offset)
-{
-       int iter = buffer->iterator + offset * 4;
-       return &buffer->data[iter / PAGE_SIZE][iter & (PAGE_SIZE - 1)];
-}
-/**
- * Returns the pointer to the dword which is offset number of elements from
- * the current processing location.
- *
- * Call to this function doesn't change the processing location.
- *
- *   offset: The index of the byte relative to the internat iterator.
- */
-static inline void *drm_buffer_pointer_to_byte(struct drm_buffer *buffer,
-               int offset)
-{
-       int iter = buffer->iterator + offset;
-       return &buffer->data[iter / PAGE_SIZE][iter & (PAGE_SIZE - 1)];
-}
-
-#endif
index f1105d0da0598c391a6486531a67188da878c111..c40070a92d6b43f055c77f749ec44afc713e031a 100644 (file)
@@ -31,8 +31,8 @@
 #include <linux/idr.h>
 #include <linux/fb.h>
 #include <linux/hdmi.h>
-#include <drm/drm_mode.h>
-#include <drm/drm_fourcc.h>
+#include <uapi/drm/drm_mode.h>
+#include <uapi/drm/drm_fourcc.h>
 #include <drm/drm_modeset_lock.h>
 
 struct drm_device;
@@ -218,10 +218,6 @@ struct drm_property {
        struct list_head enum_blob_list;
 };
 
-void drm_modeset_lock_all(struct drm_device *dev);
-void drm_modeset_unlock_all(struct drm_device *dev);
-void drm_warn_on_modeset_not_all_locked(struct drm_device *dev);
-
 struct drm_crtc;
 struct drm_connector;
 struct drm_encoder;
@@ -345,10 +341,6 @@ struct drm_crtc {
        int cursor_x;
        int cursor_y;
 
-       /* Temporary tracking of the old fb while a modeset is ongoing. Used
-        * by drm_mode_set_config_internal to implement correct refcounting. */
-       struct drm_framebuffer *old_fb;
-
        bool enabled;
 
        /* Requested mode from modesetting. */
@@ -375,6 +367,12 @@ struct drm_crtc {
        void *helper_private;
 
        struct drm_object_properties properties;
+
+       /*
+        * For legacy crtc ioctls so that atomic drivers can get at the locking
+        * acquire context.
+        */
+       struct drm_modeset_acquire_ctx *acquire_ctx;
 };
 
 
@@ -548,6 +546,7 @@ struct drm_connector {
        void *helper_private;
 
        /* forced on connector */
+       struct drm_cmdline_mode cmdline_mode;
        enum drm_connector_force force;
        bool override_edid;
        uint32_t encoder_ids[DRM_CONNECTOR_MAX_ENCODER];
@@ -582,6 +581,7 @@ struct drm_plane_funcs {
                            uint32_t src_w, uint32_t src_h);
        int (*disable_plane)(struct drm_plane *plane);
        void (*destroy)(struct drm_plane *plane);
+       void (*reset)(struct drm_plane *plane);
 
        int (*set_property)(struct drm_plane *plane,
                            struct drm_property *property, uint64_t val);
@@ -620,6 +620,10 @@ struct drm_plane {
        struct drm_crtc *crtc;
        struct drm_framebuffer *fb;
 
+       /* Temporary tracking of the old fb while a modeset is ongoing. Used
+        * by drm_mode_set_config_internal to implement correct refcounting. */
+       struct drm_framebuffer *old_fb;
+
        const struct drm_plane_funcs *funcs;
 
        struct drm_object_properties properties;
@@ -821,6 +825,7 @@ struct drm_mode_config {
        struct drm_property *dpms_property;
        struct drm_property *path_property;
        struct drm_property *plane_type_property;
+       struct drm_property *rotation_property;
 
        /* DVI-I properties */
        struct drm_property *dvi_i_subconnector_property;
@@ -903,6 +908,7 @@ int drm_connector_register(struct drm_connector *connector);
 void drm_connector_unregister(struct drm_connector *connector);
 
 extern void drm_connector_cleanup(struct drm_connector *connector);
+extern unsigned int drm_connector_index(struct drm_connector *connector);
 /* helper to unplug all connectors from sysfs for device */
 extern void drm_connector_unplug_all(struct drm_device *dev);
 
@@ -942,6 +948,7 @@ extern int drm_plane_init(struct drm_device *dev,
                          const uint32_t *formats, uint32_t format_count,
                          bool is_primary);
 extern void drm_plane_cleanup(struct drm_plane *plane);
+extern unsigned int drm_plane_index(struct drm_plane *plane);
 extern void drm_plane_force_disable(struct drm_plane *plane);
 extern int drm_crtc_check_viewport(const struct drm_crtc *crtc,
                                   int x, int y,
@@ -1120,6 +1127,9 @@ extern int drm_mode_obj_get_properties_ioctl(struct drm_device *dev, void *data,
                                             struct drm_file *file_priv);
 extern int drm_mode_obj_set_property_ioctl(struct drm_device *dev, void *data,
                                           struct drm_file *file_priv);
+extern int drm_mode_plane_set_obj_prop(struct drm_plane *plane,
+                                      struct drm_property *property,
+                                      uint64_t value);
 
 extern void drm_fb_get_bpp_depth(uint32_t format, unsigned int *depth,
                                 int *bpp);
index a21568bf15145940cecdc86623d9c4b79dd1111c..9305c718d789b703c3a073f339c9c9b7e0ea352e 100644 (file)
 # define DP_TRAIN_VOLTAGE_SWING_MASK       0x3
 # define DP_TRAIN_VOLTAGE_SWING_SHIFT      0
 # define DP_TRAIN_MAX_SWING_REACHED        (1 << 2)
-# define DP_TRAIN_VOLTAGE_SWING_400        (0 << 0)
-# define DP_TRAIN_VOLTAGE_SWING_600        (1 << 0)
-# define DP_TRAIN_VOLTAGE_SWING_800        (2 << 0)
-# define DP_TRAIN_VOLTAGE_SWING_1200       (3 << 0)
+# define DP_TRAIN_VOLTAGE_SWING_LEVEL_0 (0 << 0)
+# define DP_TRAIN_VOLTAGE_SWING_LEVEL_1 (1 << 0)
+# define DP_TRAIN_VOLTAGE_SWING_LEVEL_2 (2 << 0)
+# define DP_TRAIN_VOLTAGE_SWING_LEVEL_3 (3 << 0)
 
 # define DP_TRAIN_PRE_EMPHASIS_MASK        (3 << 3)
-# define DP_TRAIN_PRE_EMPHASIS_0           (0 << 3)
-# define DP_TRAIN_PRE_EMPHASIS_3_5         (1 << 3)
-# define DP_TRAIN_PRE_EMPHASIS_6           (2 << 3)
-# define DP_TRAIN_PRE_EMPHASIS_9_5         (3 << 3)
+# define DP_TRAIN_PRE_EMPH_LEVEL_0             (0 << 3)
+# define DP_TRAIN_PRE_EMPH_LEVEL_1             (1 << 3)
+# define DP_TRAIN_PRE_EMPH_LEVEL_2             (2 << 3)
+# define DP_TRAIN_PRE_EMPH_LEVEL_3             (3 << 3)
 
 # define DP_TRAIN_PRE_EMPHASIS_SHIFT       3
 # define DP_TRAIN_MAX_PRE_EMPHASIS_REACHED  (1 << 5)
index 9b446ada253218fa81fe26b2beb2675dc99952c5..338fc1053835e5896a9046741c1599a54a3d24b2 100644 (file)
@@ -388,6 +388,7 @@ struct drm_dp_payload {
        int payload_state;
        int start_slot;
        int num_slots;
+       int vcpi;
 };
 
 /**
@@ -454,6 +455,7 @@ struct drm_dp_mst_topology_mgr {
        struct drm_dp_vcpi **proposed_vcpis;
        struct drm_dp_payload *payloads;
        unsigned long payload_mask;
+       unsigned long vcpi_mask;
 
        wait_queue_head_t tx_waitq;
        struct work_struct work;
index bfd329d613c4541fe1bb311e5e435dbac5c3da1a..f4ad254e3488ea4ebdcf98410757f7e5d01e7cd9 100644 (file)
@@ -77,7 +77,6 @@ struct drm_fb_helper_funcs {
 
 struct drm_fb_helper_connector {
        struct drm_connector *connector;
-       struct drm_cmdline_mode cmdline_mode;
 };
 
 struct drm_fb_helper {
diff --git a/include/drm/drm_gem.h b/include/drm/drm_gem.h
new file mode 100644 (file)
index 0000000..1e6ae14
--- /dev/null
@@ -0,0 +1,183 @@
+#ifndef __DRM_GEM_H__
+#define __DRM_GEM_H__
+
+/*
+ * GEM Graphics Execution Manager Driver Interfaces
+ *
+ * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
+ * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
+ * Copyright (c) 2009-2010, Code Aurora Forum.
+ * All rights reserved.
+ * Copyright Â© 2014 Intel Corporation
+ *   Daniel Vetter <daniel.vetter@ffwll.ch>
+ *
+ * Author: Rickard E. (Rik) Faith <faith@valinux.com>
+ * Author: Gareth Hughes <gareth@valinux.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS 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.
+ */
+
+/**
+ * This structure defines the drm_mm memory object, which will be used by the
+ * DRM for its buffer objects.
+ */
+struct drm_gem_object {
+       /** Reference count of this object */
+       struct kref refcount;
+
+       /**
+        * handle_count - gem file_priv handle count of this object
+        *
+        * Each handle also holds a reference. Note that when the handle_count
+        * drops to 0 any global names (e.g. the id in the flink namespace) will
+        * be cleared.
+        *
+        * Protected by dev->object_name_lock.
+        * */
+       unsigned handle_count;
+
+       /** Related drm device */
+       struct drm_device *dev;
+
+       /** File representing the shmem storage */
+       struct file *filp;
+
+       /* Mapping info for this object */
+       struct drm_vma_offset_node vma_node;
+
+       /**
+        * Size of the object, in bytes.  Immutable over the object's
+        * lifetime.
+        */
+       size_t size;
+
+       /**
+        * Global name for this object, starts at 1. 0 means unnamed.
+        * Access is covered by the object_name_lock in the related drm_device
+        */
+       int name;
+
+       /**
+        * Memory domains. These monitor which caches contain read/write data
+        * related to the object. When transitioning from one set of domains
+        * to another, the driver is called to ensure that caches are suitably
+        * flushed and invalidated
+        */
+       uint32_t read_domains;
+       uint32_t write_domain;
+
+       /**
+        * While validating an exec operation, the
+        * new read/write domain values are computed here.
+        * They will be transferred to the above values
+        * at the point that any cache flushing occurs
+        */
+       uint32_t pending_read_domains;
+       uint32_t pending_write_domain;
+
+       /**
+        * dma_buf - dma buf associated with this GEM object
+        *
+        * Pointer to the dma-buf associated with this gem object (either
+        * through importing or exporting). We break the resulting reference
+        * loop when the last gem handle for this object is released.
+        *
+        * Protected by obj->object_name_lock
+        */
+       struct dma_buf *dma_buf;
+
+       /**
+        * import_attach - dma buf attachment backing this object
+        *
+        * Any foreign dma_buf imported as a gem object has this set to the
+        * attachment point for the device. This is invariant over the lifetime
+        * of a gem object.
+        *
+        * The driver's ->gem_free_object callback is responsible for cleaning
+        * up the dma_buf attachment and references acquired at import time.
+        *
+        * Note that the drm gem/prime core does not depend upon drivers setting
+        * this field any more. So for drivers where this doesn't make sense
+        * (e.g. virtual devices or a displaylink behind an usb bus) they can
+        * simply leave it as NULL.
+        */
+       struct dma_buf_attachment *import_attach;
+};
+
+void drm_gem_object_release(struct drm_gem_object *obj);
+void drm_gem_object_free(struct kref *kref);
+int drm_gem_object_init(struct drm_device *dev,
+                       struct drm_gem_object *obj, size_t size);
+void drm_gem_private_object_init(struct drm_device *dev,
+                                struct drm_gem_object *obj, size_t size);
+void drm_gem_vm_open(struct vm_area_struct *vma);
+void drm_gem_vm_close(struct vm_area_struct *vma);
+int drm_gem_mmap_obj(struct drm_gem_object *obj, unsigned long obj_size,
+                    struct vm_area_struct *vma);
+int drm_gem_mmap(struct file *filp, struct vm_area_struct *vma);
+
+static inline void
+drm_gem_object_reference(struct drm_gem_object *obj)
+{
+       kref_get(&obj->refcount);
+}
+
+static inline void
+drm_gem_object_unreference(struct drm_gem_object *obj)
+{
+       if (obj != NULL)
+               kref_put(&obj->refcount, drm_gem_object_free);
+}
+
+static inline void
+drm_gem_object_unreference_unlocked(struct drm_gem_object *obj)
+{
+       if (obj && !atomic_add_unless(&obj->refcount.refcount, -1, 1)) {
+               struct drm_device *dev = obj->dev;
+
+               mutex_lock(&dev->struct_mutex);
+               if (likely(atomic_dec_and_test(&obj->refcount.refcount)))
+                       drm_gem_object_free(&obj->refcount);
+               mutex_unlock(&dev->struct_mutex);
+       }
+}
+
+int drm_gem_handle_create(struct drm_file *file_priv,
+                         struct drm_gem_object *obj,
+                         u32 *handlep);
+int drm_gem_handle_delete(struct drm_file *filp, u32 handle);
+
+
+void drm_gem_free_mmap_offset(struct drm_gem_object *obj);
+int drm_gem_create_mmap_offset(struct drm_gem_object *obj);
+int drm_gem_create_mmap_offset_size(struct drm_gem_object *obj, size_t size);
+
+struct page **drm_gem_get_pages(struct drm_gem_object *obj);
+void drm_gem_put_pages(struct drm_gem_object *obj, struct page **pages,
+               bool dirty, bool accessed);
+
+struct drm_gem_object *drm_gem_object_lookup(struct drm_device *dev,
+                                            struct drm_file *filp,
+                                            u32 handle);
+int drm_gem_dumb_destroy(struct drm_file *file,
+                        struct drm_device *dev,
+                        uint32_t handle);
+
+#endif /* __DRM_GEM_H__ */
index 2a3cea91606da6f568f249b85f89130f8f7e89d8..2ff35f3de9c5b9520587daca98f2c4d67b17bab4 100644 (file)
@@ -2,6 +2,7 @@
 #define __DRM_GEM_CMA_HELPER_H__
 
 #include <drm/drmP.h>
+#include <drm/drm_gem.h>
 
 struct drm_gem_cma_object {
        struct drm_gem_object base;
@@ -44,7 +45,8 @@ void drm_gem_cma_describe(struct drm_gem_cma_object *obj, struct seq_file *m);
 
 struct sg_table *drm_gem_cma_prime_get_sg_table(struct drm_gem_object *obj);
 struct drm_gem_object *
-drm_gem_cma_prime_import_sg_table(struct drm_device *dev, size_t size,
+drm_gem_cma_prime_import_sg_table(struct drm_device *dev,
+                                 struct dma_buf_attachment *attach,
                                  struct sg_table *sgt);
 int drm_gem_cma_prime_mmap(struct drm_gem_object *obj,
                           struct vm_area_struct *vma);
diff --git a/include/drm/drm_legacy.h b/include/drm/drm_legacy.h
new file mode 100644 (file)
index 0000000..3e69803
--- /dev/null
@@ -0,0 +1,203 @@
+#ifndef __DRM_DRM_LEGACY_H__
+#define __DRM_DRM_LEGACY_H__
+
+/*
+ * Legacy driver interfaces for the Direct Rendering Manager
+ *
+ * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
+ * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
+ * Copyright (c) 2009-2010, Code Aurora Forum.
+ * All rights reserved.
+ * Copyright Â© 2014 Intel Corporation
+ *   Daniel Vetter <daniel.vetter@ffwll.ch>
+ *
+ * Author: Rickard E. (Rik) Faith <faith@valinux.com>
+ * Author: Gareth Hughes <gareth@valinux.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS 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.
+ */
+
+
+/*
+ * Legacy Support for palateontologic DRM drivers
+ *
+ * If you add a new driver and it uses any of these functions or structures,
+ * you're doing it terribly wrong.
+ */
+
+/**
+ * DMA buffer.
+ */
+struct drm_buf {
+       int idx;                       /**< Index into master buflist */
+       int total;                     /**< Buffer size */
+       int order;                     /**< log-base-2(total) */
+       int used;                      /**< Amount of buffer in use (for DMA) */
+       unsigned long offset;          /**< Byte offset (used internally) */
+       void *address;                 /**< Address of buffer */
+       unsigned long bus_address;     /**< Bus address of buffer */
+       struct drm_buf *next;          /**< Kernel-only: used for free list */
+       __volatile__ int waiting;      /**< On kernel DMA queue */
+       __volatile__ int pending;      /**< On hardware DMA queue */
+       struct drm_file *file_priv;    /**< Private of holding file descr */
+       int context;                   /**< Kernel queue for this buffer */
+       int while_locked;              /**< Dispatch this buffer while locked */
+       enum {
+               DRM_LIST_NONE = 0,
+               DRM_LIST_FREE = 1,
+               DRM_LIST_WAIT = 2,
+               DRM_LIST_PEND = 3,
+               DRM_LIST_PRIO = 4,
+               DRM_LIST_RECLAIM = 5
+       } list;                        /**< Which list we're on */
+
+       int dev_priv_size;               /**< Size of buffer private storage */
+       void *dev_private;               /**< Per-buffer private storage */
+};
+
+typedef struct drm_dma_handle {
+       dma_addr_t busaddr;
+       void *vaddr;
+       size_t size;
+} drm_dma_handle_t;
+
+/**
+ * Buffer entry.  There is one of this for each buffer size order.
+ */
+struct drm_buf_entry {
+       int buf_size;                   /**< size */
+       int buf_count;                  /**< number of buffers */
+       struct drm_buf *buflist;                /**< buffer list */
+       int seg_count;
+       int page_order;
+       struct drm_dma_handle **seglist;
+
+       int low_mark;                   /**< Low water mark */
+       int high_mark;                  /**< High water mark */
+};
+
+/**
+ * DMA data.
+ */
+struct drm_device_dma {
+
+       struct drm_buf_entry bufs[DRM_MAX_ORDER + 1];   /**< buffers, grouped by their size order */
+       int buf_count;                  /**< total number of buffers */
+       struct drm_buf **buflist;               /**< Vector of pointers into drm_device_dma::bufs */
+       int seg_count;
+       int page_count;                 /**< number of pages */
+       unsigned long *pagelist;        /**< page list */
+       unsigned long byte_count;
+       enum {
+               _DRM_DMA_USE_AGP = 0x01,
+               _DRM_DMA_USE_SG = 0x02,
+               _DRM_DMA_USE_FB = 0x04,
+               _DRM_DMA_USE_PCI_RO = 0x08
+       } flags;
+
+};
+
+/**
+ * Scatter-gather memory.
+ */
+struct drm_sg_mem {
+       unsigned long handle;
+       void *virtual;
+       int pages;
+       struct page **pagelist;
+       dma_addr_t *busaddr;
+};
+
+/**
+ * Kernel side of a mapping
+ */
+struct drm_local_map {
+       resource_size_t offset;  /**< Requested physical address (0 for SAREA)*/
+       unsigned long size;      /**< Requested physical size (bytes) */
+       enum drm_map_type type;  /**< Type of memory to map */
+       enum drm_map_flags flags;        /**< Flags */
+       void *handle;            /**< User-space: "Handle" to pass to mmap() */
+                                /**< Kernel-space: kernel-virtual address */
+       int mtrr;                /**< MTRR slot used */
+};
+
+typedef struct drm_local_map drm_local_map_t;
+
+/**
+ * Mappings list
+ */
+struct drm_map_list {
+       struct list_head head;          /**< list head */
+       struct drm_hash_item hash;
+       struct drm_local_map *map;      /**< mapping */
+       uint64_t user_token;
+       struct drm_master *master;
+};
+
+int drm_legacy_addmap(struct drm_device *d, resource_size_t offset,
+                     unsigned int size, enum drm_map_type type,
+                     enum drm_map_flags flags, struct drm_local_map **map_p);
+int drm_legacy_rmmap(struct drm_device *d, struct drm_local_map *map);
+int drm_legacy_rmmap_locked(struct drm_device *d, struct drm_local_map *map);
+struct drm_local_map *drm_legacy_getsarea(struct drm_device *dev);
+int drm_legacy_mmap(struct file *filp, struct vm_area_struct *vma);
+
+int drm_legacy_addbufs_agp(struct drm_device *d, struct drm_buf_desc *req);
+int drm_legacy_addbufs_pci(struct drm_device *d, struct drm_buf_desc *req);
+
+/**
+ * Test that the hardware lock is held by the caller, returning otherwise.
+ *
+ * \param dev DRM device.
+ * \param filp file pointer of the caller.
+ */
+#define LOCK_TEST_WITH_RETURN( dev, _file_priv )                               \
+do {                                                                           \
+       if (!_DRM_LOCK_IS_HELD(_file_priv->master->lock.hw_lock->lock) ||       \
+           _file_priv->master->lock.file_priv != _file_priv)   {               \
+               DRM_ERROR( "%s called without lock held, held  %d owner %p %p\n",\
+                          __func__, _DRM_LOCK_IS_HELD(_file_priv->master->lock.hw_lock->lock),\
+                          _file_priv->master->lock.file_priv, _file_priv);     \
+               return -EINVAL;                                                 \
+       }                                                                       \
+} while (0)
+
+void drm_legacy_idlelock_take(struct drm_lock_data *lock);
+void drm_legacy_idlelock_release(struct drm_lock_data *lock);
+
+/* drm_pci.c dma alloc wrappers */
+void __drm_legacy_pci_free(struct drm_device *dev, drm_dma_handle_t * dmah);
+
+/* drm_memory.c */
+void drm_legacy_ioremap(struct drm_local_map *map, struct drm_device *dev);
+void drm_legacy_ioremap_wc(struct drm_local_map *map, struct drm_device *dev);
+void drm_legacy_ioremapfree(struct drm_local_map *map, struct drm_device *dev);
+
+static __inline__ struct drm_local_map *drm_legacy_findmap(struct drm_device *dev,
+                                                          unsigned int token)
+{
+       struct drm_map_list *_entry;
+       list_for_each_entry(_entry, &dev->maplist, head)
+           if (_entry->user_token == token)
+               return _entry->map;
+       return NULL;
+}
+
+#endif /* __DRM_DRM_LEGACY_H__ */
diff --git a/include/drm/drm_memory.h b/include/drm/drm_memory.h
deleted file mode 100644 (file)
index 4baf57a..0000000
+++ /dev/null
@@ -1,59 +0,0 @@
-/**
- * \file drm_memory.h
- * Memory management wrappers for DRM
- *
- * \author Rickard E. (Rik) Faith <faith@valinux.com>
- * \author Gareth Hughes <gareth@valinux.com>
- */
-
-/*
- * Created: Thu Feb  4 14:00:34 1999 by faith@valinux.com
- *
- * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
- * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
- * All Rights Reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice (including the next
- * paragraph) shall be included in all copies or substantial portions of the
- * Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS 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/highmem.h>
-#include <linux/vmalloc.h>
-#include <drm/drmP.h>
-
-/**
- * Cut down version of drm_memory_debug.h, which used to be called
- * drm_memory.h.
- */
-
-#if __OS_HAS_AGP
-
-#ifdef HAVE_PAGE_AGP
-#include <asm/agp.h>
-#else
-# ifdef __powerpc__
-#  define PAGE_AGP     __pgprot(_PAGE_KERNEL | _PAGE_NO_CACHE)
-# else
-#  define PAGE_AGP     PAGE_KERNEL
-# endif
-#endif
-
-#else                          /* __OS_HAS_AGP */
-
-#endif
index 2bb55b8b90318c65eef80e2d511495e5731ae4e4..8569dc5a1026a2a986ca5d15bd7e9575dd19723d 100644 (file)
@@ -96,6 +96,8 @@ void mipi_dsi_host_unregister(struct mipi_dsi_host *host);
 #define MIPI_DSI_MODE_EOT_PACKET       BIT(9)
 /* device supports non-continuous clock behavior (DSI spec 5.6.1) */
 #define MIPI_DSI_CLOCK_NON_CONTINUOUS  BIT(10)
+/* transmit data in low power */
+#define MIPI_DSI_MODE_LPM              BIT(11)
 
 enum mipi_dsi_pixel_format {
        MIPI_DSI_FMT_RGB888,
index 402aa7a6a058dc68e3923d1ee2ad7296800d3d69..75a5c45e21c72f2ca34da9f9ccb4d7e2908bd7e3 100644 (file)
@@ -29,7 +29,7 @@
 struct drm_modeset_lock;
 
 /**
- * drm_modeset_acquire_ctx - locking context (see ww_acquire_ctx)
+ * struct drm_modeset_acquire_ctx - locking context (see ww_acquire_ctx)
  * @ww_ctx: base acquire ctx
  * @contended: used internally for -EDEADLK handling
  * @locked: list of held locks
@@ -53,10 +53,15 @@ struct drm_modeset_acquire_ctx {
         * list of held locks (drm_modeset_lock)
         */
        struct list_head locked;
+
+       /**
+        * Trylock mode, use only for panic handlers!
+        */
+       bool trylock_only;
 };
 
 /**
- * drm_modeset_lock - used for locking modeset resources.
+ * struct drm_modeset_lock - used for locking modeset resources.
  * @mutex: resource locking
  * @head: used to hold it's place on state->locked list when
  *    part of an atomic update
@@ -120,6 +125,17 @@ int drm_modeset_lock_interruptible(struct drm_modeset_lock *lock,
 void drm_modeset_unlock(struct drm_modeset_lock *lock);
 
 struct drm_device;
+struct drm_crtc;
+
+void drm_modeset_lock_all(struct drm_device *dev);
+int __drm_modeset_lock_all(struct drm_device *dev, bool trylock);
+void drm_modeset_unlock_all(struct drm_device *dev);
+void drm_modeset_lock_crtc(struct drm_crtc *crtc);
+void drm_modeset_unlock_crtc(struct drm_crtc *crtc);
+void drm_warn_on_modeset_not_all_locked(struct drm_device *dev);
+struct drm_modeset_acquire_ctx *
+drm_modeset_legacy_acquire_ctx(struct drm_crtc *crtc);
+
 int drm_modeset_lock_all_crtcs(struct drm_device *dev,
                struct drm_modeset_acquire_ctx *ctx);
 
diff --git a/include/drm/drm_usb.h b/include/drm/drm_usb.h
deleted file mode 100644 (file)
index 33506c1..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-#ifndef DRM_USB_H
-#define DRM_USB_H
-
-#include <drmP.h>
-
-#include <linux/usb.h>
-
-extern int drm_usb_init(struct drm_driver *driver, struct usb_driver *udriver);
-extern void drm_usb_exit(struct drm_driver *driver, struct usb_driver *udriver);
-
-int drm_get_usb_dev(struct usb_interface *interface,
-                   const struct usb_device_id *id,
-                   struct drm_driver *driver);
-
-#endif
index 7526c5bf56105e95e6e614f4ea1517f1ac6ee64d..0ccf7f267ff94408387d71da446cc89ab1caf6fa 100644 (file)
@@ -45,12 +45,24 @@ struct ttm_bo_device;
 
 struct drm_mm_node;
 
+/**
+ * struct ttm_place
+ *
+ * @fpfn:      first valid page frame number to put the object
+ * @lpfn:      last valid page frame number to put the object
+ * @flags:     memory domain and caching flags for the object
+ *
+ * Structure indicating a possible place to put an object.
+ */
+struct ttm_place {
+       unsigned        fpfn;
+       unsigned        lpfn;
+       uint32_t        flags;
+};
 
 /**
  * struct ttm_placement
  *
- * @fpfn:              first valid page frame number to put the object
- * @lpfn:              last valid page frame number to put the object
  * @num_placement:     number of preferred placements
  * @placement:         preferred placements
  * @num_busy_placement:        number of preferred placements when need to evict buffer
@@ -59,12 +71,10 @@ struct drm_mm_node;
  * Structure indicating the placement you request for an object.
  */
 struct ttm_placement {
-       unsigned        fpfn;
-       unsigned        lpfn;
-       unsigned        num_placement;
-       const uint32_t  *placement;
-       unsigned        num_busy_placement;
-       const uint32_t  *busy_placement;
+       unsigned                num_placement;
+       const struct ttm_place  *placement;
+       unsigned                num_busy_placement;
+       const struct ttm_place  *busy_placement;
 };
 
 /**
@@ -163,7 +173,6 @@ struct ttm_tt;
  * @lru: List head for the lru list.
  * @ddestroy: List head for the delayed destroy list.
  * @swap: List head for swap LRU list.
- * @sync_obj: Pointer to a synchronization object.
  * @priv_flags: Flags describing buffer object internal state.
  * @vma_node: Address space manager node.
  * @offset: The current GPU offset, which can have different meanings
@@ -227,13 +236,9 @@ struct ttm_buffer_object {
        struct list_head io_reserve_lru;
 
        /**
-        * Members protected by struct buffer_object_device::fence_lock
-        * In addition, setting sync_obj to anything else
-        * than NULL requires bo::reserved to be held. This allows for
-        * checking NULL while reserved but not holding the mentioned lock.
+        * Members protected by a bo reservation.
         */
 
-       void *sync_obj;
        unsigned long priv_flags;
 
        struct drm_vma_offset_node vma_node;
@@ -455,6 +460,7 @@ size_t ttm_bo_dma_acc_size(struct ttm_bo_device *bdev,
  * point to the shmem object backing a GEM object if TTM is used to back a
  * GEM user interface.
  * @acc_size: Accounted size for this object.
+ * @resv: Pointer to a reservation_object, or NULL to let ttm allocate one.
  * @destroy: Destroy function. Use NULL for kfree().
  *
  * This function initializes a pre-allocated struct ttm_buffer_object.
@@ -482,6 +488,7 @@ extern int ttm_bo_init(struct ttm_bo_device *bdev,
                        struct file *persistent_swap_storage,
                        size_t acc_size,
                        struct sg_table *sg,
+                       struct reservation_object *resv,
                        void (*destroy) (struct ttm_buffer_object *));
 
 /**
@@ -518,20 +525,6 @@ extern int ttm_bo_create(struct ttm_bo_device *bdev,
                                struct file *persistent_swap_storage,
                                struct ttm_buffer_object **p_bo);
 
-/**
- * ttm_bo_check_placement
- *
- * @bo:                the buffer object.
- * @placement: placements
- *
- * Performs minimal validity checking on an intended change of
- * placement flags.
- * Returns
- * -EINVAL: Intended change is invalid or not allowed.
- */
-extern int ttm_bo_check_placement(struct ttm_buffer_object *bo,
-                                       struct ttm_placement *placement);
-
 /**
  * ttm_bo_init_mm
  *
index 1d9f0f1ff52d2c01cd4b42cc4113a70a90ffa0a8..142d752fc450b74b60e964dd6a5c3d12ba38b163 100644 (file)
@@ -208,8 +208,7 @@ struct ttm_mem_type_manager_func {
         */
        int  (*get_node)(struct ttm_mem_type_manager *man,
                         struct ttm_buffer_object *bo,
-                        struct ttm_placement *placement,
-                        uint32_t flags,
+                        const struct ttm_place *place,
                         struct ttm_mem_reg *mem);
 
        /**
@@ -313,11 +312,6 @@ struct ttm_mem_type_manager {
  * @move: Callback for a driver to hook in accelerated functions to
  * move a buffer.
  * If set to NULL, a potentially slow memcpy() move is used.
- * @sync_obj_signaled: See ttm_fence_api.h
- * @sync_obj_wait: See ttm_fence_api.h
- * @sync_obj_flush: See ttm_fence_api.h
- * @sync_obj_unref: See ttm_fence_api.h
- * @sync_obj_ref: See ttm_fence_api.h
  */
 
 struct ttm_bo_driver {
@@ -419,23 +413,6 @@ struct ttm_bo_driver {
        int (*verify_access) (struct ttm_buffer_object *bo,
                              struct file *filp);
 
-       /**
-        * In case a driver writer dislikes the TTM fence objects,
-        * the driver writer can replace those with sync objects of
-        * his / her own. If it turns out that no driver writer is
-        * using these. I suggest we remove these hooks and plug in
-        * fences directly. The bo driver needs the following functionality:
-        * See the corresponding functions in the fence object API
-        * documentation.
-        */
-
-       bool (*sync_obj_signaled) (void *sync_obj);
-       int (*sync_obj_wait) (void *sync_obj,
-                             bool lazy, bool interruptible);
-       int (*sync_obj_flush) (void *sync_obj);
-       void (*sync_obj_unref) (void **sync_obj);
-       void *(*sync_obj_ref) (void *sync_obj);
-
        /* hook to notify driver about a driver move so it
         * can do tiling things */
        void (*move_notify)(struct ttm_buffer_object *bo,
@@ -522,8 +499,6 @@ struct ttm_bo_global {
  *
  * @driver: Pointer to a struct ttm_bo_driver struct setup by the driver.
  * @man: An array of mem_type_managers.
- * @fence_lock: Protects the synchronizing members on *all* bos belonging
- * to this device.
  * @vma_manager: Address space manager
  * lru_lock: Spinlock that protects the buffer+device lru lists and
  * ddestroy lists.
@@ -543,7 +518,6 @@ struct ttm_bo_device {
        struct ttm_bo_global *glob;
        struct ttm_bo_driver *driver;
        struct ttm_mem_type_manager man[TTM_NUM_MEM_TYPES];
-       spinlock_t fence_lock;
 
        /*
         * Protected by internal locks.
@@ -1026,7 +1000,7 @@ extern void ttm_bo_free_old_node(struct ttm_buffer_object *bo);
  * ttm_bo_move_accel_cleanup.
  *
  * @bo: A pointer to a struct ttm_buffer_object.
- * @sync_obj: A sync object that signals when moving is complete.
+ * @fence: A fence object that signals when moving is complete.
  * @evict: This is an evict move. Don't return until the buffer is idle.
  * @no_wait_gpu: Return immediately if the GPU is busy.
  * @new_mem: struct ttm_mem_reg indicating where to move.
@@ -1040,7 +1014,7 @@ extern void ttm_bo_free_old_node(struct ttm_buffer_object *bo);
  */
 
 extern int ttm_bo_move_accel_cleanup(struct ttm_buffer_object *bo,
-                                    void *sync_obj,
+                                    struct fence *fence,
                                     bool evict, bool no_wait_gpu,
                                     struct ttm_mem_reg *new_mem);
 /**
index 16db7d01a33668b576d9888fa8335bc7cc3346c9..460441714413c620b8313ca9390778e089257651 100644 (file)
  *
  * @head:           list head for thread-private list.
  * @bo:             refcounted buffer object pointer.
- * @reserved:       Indicates whether @bo has been reserved for validation.
- * @removed:        Indicates whether @bo has been removed from lru lists.
- * @put_count:      Number of outstanding references on bo::list_kref.
- * @old_sync_obj:   Pointer to a sync object about to be unreferenced
+ * @shared:         should the fence be added shared?
  */
 
 struct ttm_validate_buffer {
        struct list_head head;
        struct ttm_buffer_object *bo;
-       bool reserved;
-       bool removed;
-       int put_count;
-       void *old_sync_obj;
+       bool shared;
 };
 
 /**
@@ -73,6 +67,7 @@ extern void ttm_eu_backoff_reservation(struct ww_acquire_ctx *ticket,
  * @ticket:  [out] ww_acquire_ctx filled in by call, or NULL if only
  *           non-blocking reserves should be tried.
  * @list:    thread private list of ttm_validate_buffer structs.
+ * @intr:    should the wait be interruptible
  *
  * Tries to reserve bos pointed to by the list entries for validation.
  * If the function returns 0, all buffers are marked as "unfenced",
@@ -84,9 +79,9 @@ extern void ttm_eu_backoff_reservation(struct ww_acquire_ctx *ticket,
  * CPU write reservations to be cleared, and for other threads to
  * unreserve their buffers.
  *
- * This function may return -ERESTART or -EAGAIN if the calling process
- * receives a signal while waiting. In that case, no buffers on the list
- * will be reserved upon return.
+ * If intr is set to true, this function may return -ERESTARTSYS if the
+ * calling process receives a signal while waiting. In that case, no
+ * buffers on the list will be reserved upon return.
  *
  * Buffers reserved by this function should be unreserved by
  * a call to either ttm_eu_backoff_reservation() or
@@ -95,14 +90,14 @@ extern void ttm_eu_backoff_reservation(struct ww_acquire_ctx *ticket,
  */
 
 extern int ttm_eu_reserve_buffers(struct ww_acquire_ctx *ticket,
-                                 struct list_head *list);
+                                 struct list_head *list, bool intr);
 
 /**
  * function ttm_eu_fence_buffer_objects.
  *
  * @ticket:      ww_acquire_ctx from reserve call
  * @list:        thread private list of ttm_validate_buffer structs.
- * @sync_obj:    The new sync object for the buffers.
+ * @fence:       The new exclusive fence for the buffers.
  *
  * This function should be called when command submission is complete, and
  * it will add a new sync object to bos pointed to by entries on @list.
@@ -111,6 +106,7 @@ extern int ttm_eu_reserve_buffers(struct ww_acquire_ctx *ticket,
  */
 
 extern void ttm_eu_fence_buffer_objects(struct ww_acquire_ctx *ticket,
-                                       struct list_head *list, void *sync_obj);
+                                       struct list_head *list,
+                                       struct fence *fence);
 
 #endif
diff --git a/include/dt-bindings/sound/cs35l32.h b/include/dt-bindings/sound/cs35l32.h
new file mode 100644 (file)
index 0000000..0c6d6a3
--- /dev/null
@@ -0,0 +1,26 @@
+#ifndef __DT_CS35L32_H
+#define __DT_CS35L32_H
+
+#define CS35L32_BOOST_MGR_AUTO         0
+#define CS35L32_BOOST_MGR_AUTO_AUDIO   1
+#define CS35L32_BOOST_MGR_BYPASS       2
+#define CS35L32_BOOST_MGR_FIXED                3
+
+#define CS35L32_DATA_CFG_LR_VP         0
+#define CS35L32_DATA_CFG_LR_STAT       1
+#define CS35L32_DATA_CFG_LR            2
+#define CS35L32_DATA_CFG_LR_VPSTAT     3
+
+#define CS35L32_BATT_THRESH_3_1V       0
+#define CS35L32_BATT_THRESH_3_2V       1
+#define CS35L32_BATT_THRESH_3_3V       2
+#define CS35L32_BATT_THRESH_3_4V       3
+
+#define CS35L32_BATT_RECOV_3_1V                0
+#define CS35L32_BATT_RECOV_3_2V                1
+#define CS35L32_BATT_RECOV_3_3V                2
+#define CS35L32_BATT_RECOV_3_4V                3
+#define CS35L32_BATT_RECOV_3_5V                4
+#define CS35L32_BATT_RECOV_3_6V                5
+
+#endif /* __DT_CS35L32_H */
index 7dd473496180b6637b7c213f900d114d3b7d76cf..c0754abb2f5676b8d8df7c0df4d44efdc3767d48 100644 (file)
 
 extern struct key_type key_type_asymmetric;
 
+/*
+ * Identifiers for an asymmetric key ID.  We have three ways of looking up a
+ * key derived from an X.509 certificate:
+ *
+ * (1) Serial Number & Issuer.  Non-optional.  This is the only valid way to
+ *     map a PKCS#7 signature to an X.509 certificate.
+ *
+ * (2) Issuer & Subject Unique IDs.  Optional.  These were the original way to
+ *     match X.509 certificates, but have fallen into disuse in favour of (3).
+ *
+ * (3) Auth & Subject Key Identifiers.  Optional.  SKIDs are only provided on
+ *     CA keys that are intended to sign other keys, so don't appear in end
+ *     user certificates unless forced.
+ *
+ * We could also support an PGP key identifier, which is just a SHA1 sum of the
+ * public key and certain parameters, but since we don't support PGP keys at
+ * the moment, we shall ignore those.
+ *
+ * What we actually do is provide a place where binary identifiers can be
+ * stashed and then compare against them when checking for an id match.
+ */
+struct asymmetric_key_id {
+       unsigned short  len;
+       unsigned char   data[];
+};
+
+struct asymmetric_key_ids {
+       void            *id[2];
+};
+
+extern bool asymmetric_key_id_same(const struct asymmetric_key_id *kid1,
+                                  const struct asymmetric_key_id *kid2);
+
+extern bool asymmetric_key_id_partial(const struct asymmetric_key_id *kid1,
+                                     const struct asymmetric_key_id *kid2);
+
+extern struct asymmetric_key_id *asymmetric_key_generate_id(const void *val_1,
+                                                           size_t len_1,
+                                                           const void *val_2,
+                                                           size_t len_2);
+
 /*
  * The payload is at the discretion of the subtype.
  */
index 3ab1873a4bfab05571bdbc60a60c8a31df5dfde5..cebefb069c44a51bed96e7fc671f0e839bf94d6a 100644 (file)
@@ -40,7 +40,6 @@ struct key_preparsed_payload;
 extern int user_preparse(struct key_preparsed_payload *prep);
 extern void user_free_preparse(struct key_preparsed_payload *prep);
 extern int user_update(struct key *key, struct key_preparsed_payload *prep);
-extern int user_match(const struct key *key, const void *criterion);
 extern void user_revoke(struct key *key);
 extern void user_destroy(struct key *key);
 extern void user_describe(const struct key *user, struct seq_file *m);
index 4c7a4b2104bfc6b105f5258763fda8f0fa6685df..91b77f8d495da646da8975014e9ce118f405880e 100644 (file)
@@ -1,6 +1,8 @@
 #ifndef __LINUX_ATMEL_MCI_H
 #define __LINUX_ATMEL_MCI_H
 
+#include <linux/types.h>
+
 #define ATMCI_MAX_NR_SLOTS     2
 
 /**
index fef3a809e7cf04e6b7a41d81685782ec029638ce..5b08a8540ecfc3e6bcb5bf8b6fbef4d19df93f55 100644 (file)
@@ -3,42 +3,6 @@
 #define _LINUX_ATOMIC_H
 #include <asm/atomic.h>
 
-/*
- * Provide __deprecated wrappers for the new interface, avoid flag day changes.
- * We need the ugly external functions to break header recursion hell.
- */
-#ifndef smp_mb__before_atomic_inc
-static inline void __deprecated smp_mb__before_atomic_inc(void)
-{
-       extern void __smp_mb__before_atomic(void);
-       __smp_mb__before_atomic();
-}
-#endif
-
-#ifndef smp_mb__after_atomic_inc
-static inline void __deprecated smp_mb__after_atomic_inc(void)
-{
-       extern void __smp_mb__after_atomic(void);
-       __smp_mb__after_atomic();
-}
-#endif
-
-#ifndef smp_mb__before_atomic_dec
-static inline void __deprecated smp_mb__before_atomic_dec(void)
-{
-       extern void __smp_mb__before_atomic(void);
-       __smp_mb__before_atomic();
-}
-#endif
-
-#ifndef smp_mb__after_atomic_dec
-static inline void __deprecated smp_mb__after_atomic_dec(void)
-{
-       extern void __smp_mb__after_atomic(void);
-       __smp_mb__after_atomic();
-}
-#endif
-
 /**
  * atomic_add_unless - add unless the number is already a given value
  * @v: pointer of type atomic_t
index cbc5833fb2216ed1029bcfed5f6875ad0d311492..be5fd38bd5a05d83eaac250055defcccacafe054 100644 (file)
@@ -32,26 +32,6 @@ extern unsigned long __sw_hweight64(__u64 w);
  */
 #include <asm/bitops.h>
 
-/*
- * Provide __deprecated wrappers for the new interface, avoid flag day changes.
- * We need the ugly external functions to break header recursion hell.
- */
-#ifndef smp_mb__before_clear_bit
-static inline void __deprecated smp_mb__before_clear_bit(void)
-{
-       extern void __smp_mb__before_atomic(void);
-       __smp_mb__before_atomic();
-}
-#endif
-
-#ifndef smp_mb__after_clear_bit
-static inline void __deprecated smp_mb__after_clear_bit(void)
-{
-       extern void __smp_mb__after_atomic(void);
-       __smp_mb__after_atomic();
-}
-#endif
-
 #define for_each_set_bit(bit, addr, size) \
        for ((bit) = find_first_bit((addr), (size));            \
             (bit) < (size);                                    \
index 371b93042520526dc297a00964267da39253923a..0430ed05d3b9f0511975fbef5ca89ec14faf3e92 100644 (file)
@@ -22,6 +22,9 @@ extern int __init cma_declare_contiguous(phys_addr_t size,
                        phys_addr_t base, phys_addr_t limit,
                        phys_addr_t alignment, unsigned int order_per_bit,
                        bool fixed, struct cma **res_cma);
+extern int cma_init_reserved_mem(phys_addr_t size,
+                                       phys_addr_t base, int order_per_bit,
+                                       struct cma **res_cma);
 extern struct page *cma_alloc(struct cma *cma, int count, unsigned int align);
 extern bool cma_release(struct cma *cma, struct page *pages, int count);
 #endif
diff --git a/include/linux/compiler-gcc5.h b/include/linux/compiler-gcc5.h
new file mode 100644 (file)
index 0000000..cdd1cc2
--- /dev/null
@@ -0,0 +1,66 @@
+#ifndef __LINUX_COMPILER_H
+#error "Please don't include <linux/compiler-gcc5.h> directly, include <linux/compiler.h> instead."
+#endif
+
+#define __used                         __attribute__((__used__))
+#define __must_check                   __attribute__((warn_unused_result))
+#define __compiler_offsetof(a, b)      __builtin_offsetof(a, b)
+
+/* Mark functions as cold. gcc will assume any path leading to a call
+   to them will be unlikely.  This means a lot of manual unlikely()s
+   are unnecessary now for any paths leading to the usual suspects
+   like BUG(), printk(), panic() etc. [but let's keep them for now for
+   older compilers]
+
+   Early snapshots of gcc 4.3 don't support this and we can't detect this
+   in the preprocessor, but we can live with this because they're unreleased.
+   Maketime probing would be overkill here.
+
+   gcc also has a __attribute__((__hot__)) to move hot functions into
+   a special section, but I don't see any sense in this right now in
+   the kernel context */
+#define __cold                 __attribute__((__cold__))
+
+#define __UNIQUE_ID(prefix) __PASTE(__PASTE(__UNIQUE_ID_, prefix), __COUNTER__)
+
+#ifndef __CHECKER__
+# define __compiletime_warning(message) __attribute__((warning(message)))
+# define __compiletime_error(message) __attribute__((error(message)))
+#endif /* __CHECKER__ */
+
+/*
+ * Mark a position in code as unreachable.  This can be used to
+ * suppress control flow warnings after asm blocks that transfer
+ * control elsewhere.
+ *
+ * Early snapshots of gcc 4.5 don't support this and we can't detect
+ * this in the preprocessor, but we can live with this because they're
+ * unreleased.  Really, we need to have autoconf for the kernel.
+ */
+#define unreachable() __builtin_unreachable()
+
+/* Mark a function definition as prohibited from being cloned. */
+#define __noclone      __attribute__((__noclone__))
+
+/*
+ * Tell the optimizer that something else uses this function or variable.
+ */
+#define __visible __attribute__((externally_visible))
+
+/*
+ * GCC 'asm goto' miscompiles certain code sequences:
+ *
+ *   http://gcc.gnu.org/bugzilla/show_bug.cgi?id=58670
+ *
+ * Work it around via a compiler barrier quirk suggested by Jakub Jelinek.
+ * Fixed in GCC 4.8.2 and later versions.
+ *
+ * (asm goto is automatically volatile - the naming reflects this.)
+ */
+#define asm_volatile_goto(x...)        do { asm goto(x); asm (""); } while (0)
+
+#ifdef CONFIG_ARCH_USE_BUILTIN_BSWAP
+#define __HAVE_BUILTIN_BSWAP32__
+#define __HAVE_BUILTIN_BSWAP64__
+#define __HAVE_BUILTIN_BSWAP16__
+#endif /* CONFIG_ARCH_USE_BUILTIN_BSWAP */
index 95978ad7fcddae86ed517956b08aaa0d0615e221..b2d9a43012b20a18d7382bba29806554138383d7 100644 (file)
@@ -213,6 +213,7 @@ extern struct bus_type cpu_subsys;
 extern void cpu_hotplug_begin(void);
 extern void cpu_hotplug_done(void);
 extern void get_online_cpus(void);
+extern bool try_get_online_cpus(void);
 extern void put_online_cpus(void);
 extern void cpu_hotplug_disable(void);
 extern void cpu_hotplug_enable(void);
@@ -230,6 +231,7 @@ int cpu_down(unsigned int cpu);
 static inline void cpu_hotplug_begin(void) {}
 static inline void cpu_hotplug_done(void) {}
 #define get_online_cpus()      do { } while (0)
+#define try_get_online_cpus()  true
 #define put_online_cpus()      do { } while (0)
 #define cpu_hotplug_disable()  do { } while (0)
 #define cpu_hotplug_enable()   do { } while (0)
index 75a227cc7ce20a70f9a7e066059a5b8317696c82..b2a2a08523bfd0a5b19cec75c80b0e94a369a236 100644 (file)
@@ -11,7 +11,6 @@
 #include <linux/rcupdate.h>
 #include <linux/lockref.h>
 
-struct nameidata;
 struct path;
 struct vfsmount;
 
@@ -226,11 +225,6 @@ struct dentry_operations {
 
 extern seqlock_t rename_lock;
 
-static inline int dname_external(const struct dentry *dentry)
-{
-       return dentry->d_name.name != dentry->d_iname;
-}
-
 /*
  * These are the low-level FS interfaces to the dcache..
  */
@@ -254,7 +248,7 @@ extern struct dentry * d_obtain_root(struct inode *);
 extern void shrink_dcache_sb(struct super_block *);
 extern void shrink_dcache_parent(struct dentry *);
 extern void shrink_dcache_for_umount(struct super_block *);
-extern int d_invalidate(struct dentry *);
+extern void d_invalidate(struct dentry *);
 
 /* only used at mount-time */
 extern struct dentry * d_make_root(struct inode *);
@@ -269,7 +263,6 @@ extern void d_prune_aliases(struct inode *);
 
 /* test whether we have any submounts in a subdir tree */
 extern int have_submounts(struct dentry *);
-extern int check_submounts_and_drop(struct dentry *);
 
 /*
  * This adds the entry to the hash queues.
index 931b709862728d46f161a8bc72790fc5a8d8c2dc..d5d388160f420e86a325e1b44d8ff9f7d28b43c9 100644 (file)
@@ -263,6 +263,32 @@ struct dma_attrs;
 #define dma_unmap_sg_attrs(dev, sgl, nents, dir, attrs) \
        dma_unmap_sg(dev, sgl, nents, dir)
 
+#else
+static inline void *dma_alloc_writecombine(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);
+}
+
+static inline void dma_free_writecombine(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);
+}
+
+static inline int dma_mmap_writecombine(struct device *dev,
+                                       struct vm_area_struct *vma,
+                                       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);
+}
 #endif /* CONFIG_HAVE_DMA_ATTRS */
 
 #ifdef CONFIG_NEED_DMA_MAP_STATE
index 94187721ad412c6c8da4b44e946d24ecd240beb0..ab4f1a10da20c7fd059c50235d32aa33322f64a9 100644 (file)
@@ -851,13 +851,7 @@ static inline struct file *get_file(struct file *f)
  */
 #define FILE_LOCK_DEFERRED 1
 
-/*
- * The POSIX file lock owner is determined by
- * the "struct files_struct" in the thread group
- * (or NULL for no owner - BSD locks).
- *
- * Lockd stuffs a "host" pointer into this.
- */
+/* legacy typedef, should eventually be removed */
 typedef void *fl_owner_t;
 
 struct file_lock_operations {
@@ -868,10 +862,13 @@ struct file_lock_operations {
 struct lock_manager_operations {
        int (*lm_compare_owner)(struct file_lock *, struct file_lock *);
        unsigned long (*lm_owner_key)(struct file_lock *);
+       void (*lm_get_owner)(struct file_lock *, struct file_lock *);
+       void (*lm_put_owner)(struct file_lock *);
        void (*lm_notify)(struct file_lock *);  /* unblock callback */
-       int (*lm_grant)(struct file_lock *, struct file_lock *, int);
-       void (*lm_break)(struct file_lock *);
-       int (*lm_change)(struct file_lock **, int);
+       int (*lm_grant)(struct file_lock *, int);
+       bool (*lm_break)(struct file_lock *);
+       int (*lm_change)(struct file_lock **, int, struct list_head *);
+       void (*lm_setup)(struct file_lock *, void **);
 };
 
 struct lock_manager {
@@ -966,7 +963,7 @@ void locks_free_lock(struct file_lock *fl);
 extern void locks_init_lock(struct file_lock *);
 extern struct file_lock * locks_alloc_lock(void);
 extern void locks_copy_lock(struct file_lock *, struct file_lock *);
-extern void __locks_copy_lock(struct file_lock *, const struct file_lock *);
+extern void locks_copy_conflock(struct file_lock *, struct file_lock *);
 extern void locks_remove_posix(struct file *, fl_owner_t);
 extern void locks_remove_file(struct file *);
 extern void locks_release_private(struct file_lock *);
@@ -980,11 +977,9 @@ extern int vfs_cancel_lock(struct file *filp, struct file_lock *fl);
 extern int flock_lock_file_wait(struct file *filp, struct file_lock *fl);
 extern int __break_lease(struct inode *inode, unsigned int flags, unsigned int type);
 extern void lease_get_mtime(struct inode *, struct timespec *time);
-extern int generic_setlease(struct file *, long, struct file_lock **);
-extern int vfs_setlease(struct file *, long, struct file_lock **);
-extern int lease_modify(struct file_lock **, int);
-extern int lock_may_read(struct inode *, loff_t start, unsigned long count);
-extern int lock_may_write(struct inode *, loff_t start, unsigned long count);
+extern int generic_setlease(struct file *, long, struct file_lock **, void **priv);
+extern int vfs_setlease(struct file *, long, struct file_lock **, void **);
+extern int lease_modify(struct file_lock **, int, struct list_head *);
 #else /* !CONFIG_FILE_LOCKING */
 static inline int fcntl_getlk(struct file *file, unsigned int cmd,
                              struct flock __user *user)
@@ -1013,12 +1008,12 @@ static inline int fcntl_setlk64(unsigned int fd, struct file *file,
 #endif
 static inline int fcntl_setlease(unsigned int fd, struct file *filp, long arg)
 {
-       return 0;
+       return -EINVAL;
 }
 
 static inline int fcntl_getlease(struct file *filp)
 {
-       return 0;
+       return F_UNLCK;
 }
 
 static inline void locks_init_lock(struct file_lock *fl)
@@ -1026,7 +1021,7 @@ static inline void locks_init_lock(struct file_lock *fl)
        return;
 }
 
-static inline void __locks_copy_lock(struct file_lock *new, struct file_lock *fl)
+static inline void locks_copy_conflock(struct file_lock *new, struct file_lock *fl)
 {
        return;
 }
@@ -1100,33 +1095,22 @@ static inline void lease_get_mtime(struct inode *inode, struct timespec *time)
 }
 
 static inline int generic_setlease(struct file *filp, long arg,
-                                   struct file_lock **flp)
+                                   struct file_lock **flp, void **priv)
 {
        return -EINVAL;
 }
 
 static inline int vfs_setlease(struct file *filp, long arg,
-                              struct file_lock **lease)
+                              struct file_lock **lease, void **priv)
 {
        return -EINVAL;
 }
 
-static inline int lease_modify(struct file_lock **before, int arg)
+static inline int lease_modify(struct file_lock **before, int arg,
+                              struct list_head *dispose)
 {
        return -EINVAL;
 }
-
-static inline int lock_may_read(struct inode *inode, loff_t start,
-                               unsigned long len)
-{
-       return 1;
-}
-
-static inline int lock_may_write(struct inode *inode, loff_t start,
-                                unsigned long len)
-{
-       return 1;
-}
 #endif /* !CONFIG_FILE_LOCKING */
 
 
@@ -1151,8 +1135,8 @@ extern void fasync_free(struct fasync_struct *);
 /* can be called from interrupts */
 extern void kill_fasync(struct fasync_struct **, int, int);
 
-extern int __f_setown(struct file *filp, struct pid *, enum pid_type, int force);
-extern int f_setown(struct file *filp, unsigned long arg, int force);
+extern void __f_setown(struct file *filp, struct pid *, enum pid_type, int force);
+extern void f_setown(struct file *filp, unsigned long arg, int force);
 extern void f_delown(struct file *filp);
 extern pid_t f_getown(struct file *filp);
 extern int send_sigurg(struct fown_struct *fown);
@@ -1506,7 +1490,7 @@ struct file_operations {
        int (*flock) (struct file *, int, struct file_lock *);
        ssize_t (*splice_write)(struct pipe_inode_info *, struct file *, loff_t *, size_t, unsigned int);
        ssize_t (*splice_read)(struct file *, loff_t *, struct pipe_inode_info *, size_t, unsigned int);
-       int (*setlease)(struct file *, long, struct file_lock **);
+       int (*setlease)(struct file *, long, struct file_lock **, void **);
        long (*fallocate)(struct file *file, int mode, loff_t offset,
                          loff_t len);
        int (*show_fdinfo)(struct seq_file *m, struct file *f);
@@ -1855,7 +1839,8 @@ extern struct vfsmount *kern_mount_data(struct file_system_type *, void *data);
 extern void kern_unmount(struct vfsmount *mnt);
 extern int may_umount_tree(struct vfsmount *);
 extern int may_umount(struct vfsmount *);
-extern long do_mount(const char *, const char *, const char *, unsigned long, void *);
+extern long do_mount(const char *, const char __user *,
+                    const char *, unsigned long, void *);
 extern struct vfsmount *collect_mounts(struct path *);
 extern void drop_collected_mounts(struct vfsmount *);
 extern int iterate_mounts(int (*)(struct vfsmount *, void *), void *,
@@ -1874,7 +1859,7 @@ extern int current_umask(void);
 extern void ihold(struct inode * inode);
 extern void iput(struct inode *);
 
-static inline struct inode *file_inode(struct file *f)
+static inline struct inode *file_inode(const struct file *f)
 {
        return f->f_inode;
 }
@@ -2611,6 +2596,7 @@ extern int simple_write_end(struct file *file, struct address_space *mapping,
                        struct page *page, void *fsdata);
 extern int always_delete_dentry(const struct dentry *);
 extern struct inode *alloc_anon_inode(struct super_block *);
+extern int simple_nosetlease(struct file *, long, struct file_lock **, void **);
 extern const struct dentry_operations simple_dentry_operations;
 
 extern struct dentry *simple_lookup(struct inode *, struct dentry *, unsigned int flags);
index f49ddb1b2273b0d46e1cbf07ca434287a42e3cca..84d60cb841b100eaa71b39612b3d397b37948ddf 100644 (file)
@@ -781,13 +781,13 @@ struct fsl_ifc_regs {
                __be32 amask;
                u32 res4[0x2];
        } amask_cs[FSL_IFC_BANK_COUNT];
-       u32 res5[0x17];
+       u32 res5[0x18];
        struct {
-               __be32 csor_ext;
                __be32 csor;
+               __be32 csor_ext;
                u32 res6;
        } csor_cs[FSL_IFC_BANK_COUNT];
-       u32 res7[0x19];
+       u32 res7[0x18];
        struct {
                __be32 ftim[4];
                u32 res8[0x8];
index f0b0edbf55a94e4e4594ca65270e80bacd2e8f61..662697babd4800f760d61c4ee7b4b8e6bebffb0f 100644 (file)
@@ -56,6 +56,8 @@ struct ftrace_ops;
 typedef void (*ftrace_func_t)(unsigned long ip, unsigned long parent_ip,
                              struct ftrace_ops *op, struct pt_regs *regs);
 
+ftrace_func_t ftrace_ops_get_func(struct ftrace_ops *ops);
+
 /*
  * FTRACE_OPS_FL_* bits denote the state of ftrace_ops struct and are
  * set in the flags member.
@@ -89,6 +91,9 @@ typedef void (*ftrace_func_t)(unsigned long ip, unsigned long parent_ip,
  * INITIALIZED - The ftrace_ops has already been initialized (first use time
  *            register_ftrace_function() is called, it will initialized the ops)
  * DELETED - The ops are being deleted, do not let them be registered again.
+ * ADDING  - The ops is in the process of being added.
+ * REMOVING - The ops is in the process of being removed.
+ * MODIFYING - The ops is in the process of changing its filter functions.
  */
 enum {
        FTRACE_OPS_FL_ENABLED                   = 1 << 0,
@@ -100,6 +105,9 @@ enum {
        FTRACE_OPS_FL_STUB                      = 1 << 6,
        FTRACE_OPS_FL_INITIALIZED               = 1 << 7,
        FTRACE_OPS_FL_DELETED                   = 1 << 8,
+       FTRACE_OPS_FL_ADDING                    = 1 << 9,
+       FTRACE_OPS_FL_REMOVING                  = 1 << 10,
+       FTRACE_OPS_FL_MODIFYING                 = 1 << 11,
 };
 
 #ifdef CONFIG_DYNAMIC_FTRACE
@@ -132,7 +140,7 @@ struct ftrace_ops {
        int                             nr_trampolines;
        struct ftrace_ops_hash          local_hash;
        struct ftrace_ops_hash          *func_hash;
-       struct ftrace_hash              *tramp_hash;
+       struct ftrace_ops_hash          old_hash;
        unsigned long                   trampoline;
 #endif
 };
index 7cf5e9b3255013deb9b4feac058112f5d7acdc5a..120ccc53fcb7f85d80a3f1f0f94c2241e864fbb2 100644 (file)
@@ -15,7 +15,7 @@ struct linux_binprm;
 
 #ifdef CONFIG_IMA
 extern int ima_bprm_check(struct linux_binprm *bprm);
-extern int ima_file_check(struct file *file, int mask);
+extern int ima_file_check(struct file *file, int mask, int opened);
 extern void ima_file_free(struct file *file);
 extern int ima_file_mmap(struct file *file, unsigned long prot);
 extern int ima_module_check(struct file *file);
@@ -27,7 +27,7 @@ static inline int ima_bprm_check(struct linux_binprm *bprm)
        return 0;
 }
 
-static inline int ima_file_check(struct file *file, int mask)
+static inline int ima_file_check(struct file *file, int mask, int opened)
 {
        return 0;
 }
index 2bb4c4f3531ab4b724a1050bf31df9640386daaa..77fc43f8fb72ce05210badb40d44abc29323d40e 100644 (file)
@@ -111,12 +111,21 @@ extern struct group_info init_groups;
 #ifdef CONFIG_PREEMPT_RCU
 #define INIT_TASK_RCU_PREEMPT(tsk)                                     \
        .rcu_read_lock_nesting = 0,                                     \
-       .rcu_read_unlock_special = 0,                                   \
+       .rcu_read_unlock_special.s = 0,                                 \
        .rcu_node_entry = LIST_HEAD_INIT(tsk.rcu_node_entry),           \
        INIT_TASK_RCU_TREE_PREEMPT()
 #else
 #define INIT_TASK_RCU_PREEMPT(tsk)
 #endif
+#ifdef CONFIG_TASKS_RCU
+#define INIT_TASK_RCU_TASKS(tsk)                                       \
+       .rcu_tasks_holdout = false,                                     \
+       .rcu_tasks_holdout_list =                                       \
+               LIST_HEAD_INIT(tsk.rcu_tasks_holdout_list),             \
+       .rcu_tasks_idle_cpu = -1,
+#else
+#define INIT_TASK_RCU_TASKS(tsk)
+#endif
 
 extern struct cred init_cred;
 
@@ -224,6 +233,7 @@ extern struct task_group root_task_group;
        INIT_FTRACE_GRAPH                                               \
        INIT_TRACE_RECURSION                                            \
        INIT_TASK_RCU_PREEMPT(tsk)                                      \
+       INIT_TASK_RCU_TASKS(tsk)                                        \
        INIT_CPUSET_SEQ(tsk)                                            \
        INIT_RT_MUTEXES(tsk)                                            \
        INIT_VTIME(tsk)                                                 \
index 20f9a527922a6a04f84670e7538e7abbc1ece7d1..7b02bcc85b9ead2ced4308c6ff8a120006c1c793 100644 (file)
@@ -80,6 +80,7 @@ enum iommu_attr {
        DOMAIN_ATTR_FSL_PAMU_STASH,
        DOMAIN_ATTR_FSL_PAMU_ENABLE,
        DOMAIN_ATTR_FSL_PAMUV1,
+       DOMAIN_ATTR_NESTING,    /* two stages of translation */
        DOMAIN_ATTR_MAX,
 };
 
index 784304b222b3e6707332f6b4c46015605ea519ad..98f923b6a0eaa78ee8b4ffdf57c87f146e3c03d6 100644 (file)
@@ -8,28 +8,28 @@
  * Copyright (C) 2011-2012 Peter Zijlstra <pzijlstr@redhat.com>
  *
  * Jump labels provide an interface to generate dynamic branches using
- * self-modifying code. Assuming toolchain and architecture support the result
- * of a "if (static_key_false(&key))" statement is a unconditional branch (which
+ * self-modifying code. Assuming toolchain and architecture support, the result
+ * of a "if (static_key_false(&key))" statement is an unconditional branch (which
  * defaults to false - and the true block is placed out of line).
  *
  * However at runtime we can change the branch target using
  * static_key_slow_{inc,dec}(). These function as a 'reference' count on the key
- * object and for as long as there are references all branches referring to
+ * object, and for as long as there are references all branches referring to
  * that particular key will point to the (out of line) true block.
  *
- * Since this relies on modifying code the static_key_slow_{inc,dec}() functions
+ * Since this relies on modifying code, the static_key_slow_{inc,dec}() functions
  * must be considered absolute slow paths (machine wide synchronization etc.).
- * OTOH, since the affected branches are unconditional their runtime overhead
+ * OTOH, since the affected branches are unconditional, their runtime overhead
  * will be absolutely minimal, esp. in the default (off) case where the total
  * effect is a single NOP of appropriate size. The on case will patch in a jump
  * to the out-of-line block.
  *
- * When the control is directly exposed to userspace it is prudent to delay the
+ * When the control is directly exposed to userspace, it is prudent to delay the
  * decrement to avoid high frequency code modifications which can (and do)
  * cause significant performance degradation. Struct static_key_deferred and
  * static_key_slow_dec_deferred() provide for this.
  *
- * Lacking toolchain and or architecture support, it falls back to a simple
+ * Lacking toolchain and or architecture support, jump labels fall back to a simple
  * conditional branch.
  *
  * struct static_key my_key = STATIC_KEY_INIT_TRUE;
@@ -43,8 +43,7 @@
  *
  * Not initializing the key (static data is initialized to 0s anyway) is the
  * same as using STATIC_KEY_INIT_FALSE.
- *
-*/
+ */
 
 #include <linux/types.h>
 #include <linux/compiler.h>
index e9e420b6d9316fc191babb91ae7a7e64b932b0ea..40728cf1c452a8d5fbf8a7065864ad5f34656ad8 100644 (file)
@@ -376,10 +376,6 @@ extern unsigned long simple_strtoul(const char *,char **,unsigned int);
 extern long simple_strtol(const char *,char **,unsigned int);
 extern unsigned long long simple_strtoull(const char *,char **,unsigned int);
 extern long long simple_strtoll(const char *,char **,unsigned int);
-#define strict_strtoul kstrtoul
-#define strict_strtol  kstrtol
-#define strict_strtoull        kstrtoull
-#define strict_strtoll kstrtoll
 
 extern int num_to_str(char *buf, int size, unsigned long long num);
 
@@ -496,6 +492,7 @@ static inline char *hex_byte_pack_upper(char *buf, u8 byte)
 
 extern int hex_to_bin(char ch);
 extern int __must_check hex2bin(u8 *dst, const char *src, size_t count);
+extern char *bin2hex(char *dst, const void *src, size_t count);
 
 bool mac_pton(const char *s, u8 *mac);
 
index 4b2a0e11cc5be7245f343ded8049f7d3e86f0855..9d957b7ae095ed7f2980db140a9c21a6aae70084 100644 (file)
@@ -178,6 +178,7 @@ struct kexec_buf {
        struct kimage *image;
        char *buffer;
        unsigned long bufsz;
+       unsigned long mem;
        unsigned long memsz;
        unsigned long buf_align;
        unsigned long buf_min;
index 44792ee649de2513b8f5dba53d29758cacef2f24..ff9f1d3942356ffd1f16ab777cb8c7ed201b35e8 100644 (file)
@@ -52,6 +52,24 @@ struct key_preparsed_payload {
 typedef int (*request_key_actor_t)(struct key_construction *key,
                                   const char *op, void *aux);
 
+/*
+ * Preparsed matching criterion.
+ */
+struct key_match_data {
+       /* Comparison function, defaults to exact description match, but can be
+        * overridden by type->match_preparse().  Should return true if a match
+        * is found and false if not.
+        */
+       bool (*cmp)(const struct key *key,
+                   const struct key_match_data *match_data);
+
+       const void      *raw_data;      /* Raw match data */
+       void            *preparsed;     /* For ->match_preparse() to stash stuff */
+       unsigned        lookup_type;    /* Type of lookup for this search. */
+#define KEYRING_SEARCH_LOOKUP_DIRECT   0x0000  /* Direct lookup by description. */
+#define KEYRING_SEARCH_LOOKUP_ITERATE  0x0001  /* Iterative search. */
+};
+
 /*
  * kernel managed key type definition
  */
@@ -65,11 +83,6 @@ struct key_type {
         */
        size_t def_datalen;
 
-       /* Default key search algorithm. */
-       unsigned def_lookup_type;
-#define KEYRING_SEARCH_LOOKUP_DIRECT   0x0000  /* Direct lookup by description. */
-#define KEYRING_SEARCH_LOOKUP_ITERATE  0x0001  /* Iterative search. */
-
        /* vet a description */
        int (*vet_description)(const char *description);
 
@@ -96,8 +109,15 @@ struct key_type {
         */
        int (*update)(struct key *key, struct key_preparsed_payload *prep);
 
-       /* match a key against a description */
-       int (*match)(const struct key *key, const void *desc);
+       /* Preparse the data supplied to ->match() (optional).  The
+        * data to be preparsed can be found in match_data->raw_data.
+        * The lookup type can also be set by this function.
+        */
+       int (*match_preparse)(struct key_match_data *match_data);
+
+       /* Free preparsed match data (optional).  This should be supplied it
+        * ->match_preparse() is supplied. */
+       void (*match_free)(struct key_match_data *match_data);
 
        /* clear some of the data from a key on revokation (optional)
         * - the key's semaphore will be write-locked by the caller
index cbbb96fcead9208da224866d849f3b3dfcf0337e..f33f831eb3c801925eed9f8d3333c65df8c57d08 100644 (file)
@@ -5,6 +5,7 @@
 #include <linux/stddef.h>
 #include <linux/poison.h>
 #include <linux/const.h>
+#include <linux/kernel.h>
 
 /*
  * Simple doubly linked list implementation.
index 219d79627c05afc2b0766085b73697a4b41bc621..ff82a32871b566401eb0a177a4b0bf45450b8f4d 100644 (file)
@@ -178,7 +178,6 @@ struct nlm_block {
        unsigned char           b_granted;      /* VFS granted lock */
        struct nlm_file *       b_file;         /* file in question */
        struct cache_req *      b_cache_req;    /* deferred request handling */
-       struct file_lock *      b_fl;           /* set for GETLK */
        struct cache_deferred_req * b_deferred_req;
        unsigned int            b_flags;        /* block flags */
 #define B_QUEUED               1       /* lock queued */
index 64c7425afbcec6036f25385b15c1e566be3d92bb..74ab23176e9b0a34edef8fcf0749d5107521bc90 100644 (file)
@@ -4,7 +4,7 @@
  *  Copyright (C) 2006,2007 Red Hat, Inc., Ingo Molnar <mingo@redhat.com>
  *  Copyright (C) 2007 Red Hat, Inc., Peter Zijlstra <pzijlstr@redhat.com>
  *
- * see Documentation/lockdep-design.txt for more details.
+ * see Documentation/locking/lockdep-design.txt for more details.
  */
 #ifndef __LINUX_LOCKDEP_H
 #define __LINUX_LOCKDEP_H
@@ -510,6 +510,7 @@ static inline void print_irqtrace_events(struct task_struct *curr)
 
 #define lock_map_acquire(l)                    lock_acquire_exclusive(l, 0, 0, NULL, _THIS_IP_)
 #define lock_map_acquire_read(l)               lock_acquire_shared_recursive(l, 0, 0, NULL, _THIS_IP_)
+#define lock_map_acquire_tryread(l)            lock_acquire_shared_recursive(l, 0, 1, NULL, _THIS_IP_)
 #define lock_map_release(l)                    lock_release(l, 1, _THIS_IP_)
 
 #ifdef CONFIG_PROVE_LOCKING
index 8f6f2e91e7ae639db87613a5426c64effd683996..57388171610d1a088bcaa79f5efaab5a0537a214 100644 (file)
@@ -5,6 +5,7 @@
 #include <linux/fb.h>
 #include <linux/io.h>
 #include <linux/jiffies.h>
+#include <linux/mmc/card.h>
 #include <linux/platform_device.h>
 #include <linux/pm_runtime.h>
 
  */
 #define TMIO_MMC_HAVE_HIGH_REG         (1 << 6)
 
+/*
+ * Some controllers have CMD12 automatically
+ * issue/non-issue register
+ */
+#define TMIO_MMC_HAVE_CMD12_CTRL       (1 << 7)
+
+/*
+ * Some controllers needs to set 1 on SDIO status reserved bits
+ */
+#define TMIO_MMC_SDIO_STATUS_QUIRK     (1 << 8)
+
+/*
+ * Some controllers have DMA enable/disable register
+ */
+#define TMIO_MMC_HAVE_CTL_DMA_REG      (1 << 9)
+
+/*
+ * Some controllers allows to set SDx actual clock
+ */
+#define TMIO_MMC_CLK_ACTUAL            (1 << 10)
+
 int tmio_core_mmc_enable(void __iomem *cnf, int shift, unsigned long base);
 int tmio_core_mmc_resume(void __iomem *cnf, int shift, unsigned long base);
 void tmio_core_mmc_pwr(void __iomem *cnf, int shift, int state);
@@ -96,6 +118,7 @@ struct tmio_mmc_dma {
        int slave_id_tx;
        int slave_id_rx;
        int alignment_shift;
+       dma_addr_t dma_rx_offset;
        bool (*filter)(struct dma_chan *chan, void *arg);
 };
 
@@ -120,6 +143,8 @@ struct tmio_mmc_data {
        /* clock management callbacks */
        int (*clk_enable)(struct platform_device *pdev, unsigned int *f);
        void (*clk_disable)(struct platform_device *pdev);
+       int (*multi_io_quirk)(struct mmc_card *card,
+                             unsigned int direction, int blk_size);
 };
 
 /*
index 2e5b194b9b1900b9d5304cbdb52f14aac576b85e..53d33dee70e19a657571d97e773e35d63afa0153 100644 (file)
@@ -37,6 +37,7 @@
 
 /* struct phy_device dev_flags definitions */
 #define MICREL_PHY_50MHZ_CLK   0x00000001
+#define MICREL_PHY_25MHZ_CLK   0x00000002
 
 #define MICREL_KSZ9021_EXTREG_CTRL     0xB
 #define MICREL_KSZ9021_EXTREG_DATA_WRITE       0xC
index fa0d74e0642812dc21e9c32b8e4fc57514238117..02d11ee7f19d1515ac47178575d653e52fc8e4e8 100644 (file)
@@ -347,6 +347,7 @@ static inline int put_page_unless_one(struct page *page)
 }
 
 extern int page_is_ram(unsigned long pfn);
+extern int region_is_ram(resource_size_t phys_addr, unsigned long size);
 
 /* Support for virtually mapped pages */
 struct page *vmalloc_to_page(const void *addr);
@@ -1973,11 +1974,16 @@ static inline struct vm_area_struct *find_exact_vma(struct mm_struct *mm,
 
 #ifdef CONFIG_MMU
 pgprot_t vm_get_page_prot(unsigned long vm_flags);
+void vma_set_page_prot(struct vm_area_struct *vma);
 #else
 static inline pgprot_t vm_get_page_prot(unsigned long vm_flags)
 {
        return __pgprot(0);
 }
+static inline void vma_set_page_prot(struct vm_area_struct *vma)
+{
+       vma->vm_page_prot = vm_get_page_prot(vma->vm_flags);
+}
 #endif
 
 #ifdef CONFIG_NUMA_BALANCING
index d424b9de3affbbee5476b9973070fc03b1b38422..b0692d28f8e649ec64d5f38db0a18967b547ff29 100644 (file)
@@ -42,7 +42,8 @@ struct mmc_csd {
        unsigned int            read_partial:1,
                                read_misalign:1,
                                write_partial:1,
-                               write_misalign:1;
+                               write_misalign:1,
+                               dsr_imp:1;
 };
 
 struct mmc_ext_csd {
@@ -74,7 +75,7 @@ struct mmc_ext_csd {
        unsigned int            sec_trim_mult;  /* Secure trim multiplier  */
        unsigned int            sec_erase_mult; /* Secure erase multiplier */
        unsigned int            trim_timeout;           /* In milliseconds */
-       bool                    enhanced_area_en;       /* enable bit */
+       bool                    partition_setting_completed;    /* enable bit */
        unsigned long long      enhanced_area_offset;   /* Units: Byte */
        unsigned int            enhanced_area_size;     /* Units: KB */
        unsigned int            cache_size;             /* Units: KB */
@@ -214,11 +215,12 @@ enum mmc_blk_status {
 };
 
 /* The number of MMC physical partitions.  These consist of:
- * boot partitions (2), general purpose partitions (4) in MMC v4.4.
+ * boot partitions (2), general purpose partitions (4) and
+ * RPMB partition (1) in MMC v4.4.
  */
 #define MMC_NUM_BOOT_PARTITION 2
 #define MMC_NUM_GP_PARTITION   4
-#define MMC_NUM_PHY_PARTITION  6
+#define MMC_NUM_PHY_PARTITION  7
 #define MAX_MMC_PART_NAME_LEN  20
 
 /*
index 29ce014ab42139cef63da0c6bc78b3d1ca9dd060..001366927cf443aa4ca46275cf8d0c5c3a601b86 100644 (file)
@@ -26,6 +26,8 @@ enum dw_mci_state {
        STATE_DATA_BUSY,
        STATE_SENDING_STOP,
        STATE_DATA_ERROR,
+       STATE_SENDING_CMD11,
+       STATE_WAITING_CMD11_DONE,
 };
 
 enum {
@@ -188,7 +190,7 @@ struct dw_mci {
        /* Workaround flags */
        u32                     quirks;
 
-       struct regulator        *vmmc;  /* Power regulator */
+       bool                    vqmmc_enabled;
        unsigned long           irq_flags; /* IRQ flags */
        int                     irq;
 };
index 7960424d0bc0cf4f1ad65e93f9df79fa83bf9403..df0c15396bbfcce6c01eabe49778c4584d4b2d69 100644 (file)
@@ -42,6 +42,7 @@ struct mmc_ios {
 #define MMC_POWER_OFF          0
 #define MMC_POWER_UP           1
 #define MMC_POWER_ON           2
+#define MMC_POWER_UNDEFINED    3
 
        unsigned char   bus_width;              /* data bus width */
 
@@ -139,6 +140,13 @@ struct mmc_host_ops {
        int     (*select_drive_strength)(unsigned int max_dtr, int host_drv, int card_drv);
        void    (*hw_reset)(struct mmc_host *host);
        void    (*card_event)(struct mmc_host *host);
+
+       /*
+        * Optional callback to support controllers with HW issues for multiple
+        * I/O. Returns the number of supported blocks for the request.
+        */
+       int     (*multi_io_quirk)(struct mmc_card *card,
+                                 unsigned int direction, int blk_size);
 };
 
 struct mmc_card;
@@ -265,7 +273,6 @@ struct mmc_host {
 
 #define MMC_CAP2_BOOTPART_NOACC        (1 << 0)        /* Boot partition no access */
 #define MMC_CAP2_FULL_PWR_CYCLE        (1 << 2)        /* Can do full power cycle */
-#define MMC_CAP2_NO_MULTI_READ (1 << 3)        /* Multiblock reads don't work */
 #define MMC_CAP2_HS200_1_8V_SDR        (1 << 5)        /* can support */
 #define MMC_CAP2_HS200_1_2V_SDR        (1 << 6)        /* can support */
 #define MMC_CAP2_HS200         (MMC_CAP2_HS200_1_8V_SDR | \
@@ -365,6 +372,9 @@ struct mmc_host {
 
        unsigned int            slotno; /* used for sdio acpi binding */
 
+       int                     dsr_req;        /* DSR value is valid */
+       u32                     dsr;    /* optional driver stage (DSR) value */
+
        unsigned long           private[0] ____cacheline_aligned;
 };
 
index 64ec963ed3478b88babe7c4292c2b2e310ca51c2..1cd00b3a75b9e33ee0d2353f92231440802ae920 100644 (file)
 #define MMC_SEND_TUNING_BLOCK    19   /* adtc                    R1  */
 #define MMC_SEND_TUNING_BLOCK_HS200    21      /* adtc R1  */
 
+#define MMC_TUNING_BLK_PATTERN_4BIT_SIZE        64
+#define MMC_TUNING_BLK_PATTERN_8BIT_SIZE       128
+extern const u8 tuning_blk_pattern_4bit[MMC_TUNING_BLK_PATTERN_4BIT_SIZE];
+extern const u8 tuning_blk_pattern_8bit[MMC_TUNING_BLK_PATTERN_8BIT_SIZE];
+
   /* class 3 */
 #define MMC_WRITE_DAT_UNTIL_STOP 20   /* adtc [31:0] data addr   R1  */
 
@@ -281,6 +286,7 @@ struct _mmc_csd {
 #define EXT_CSD_EXP_EVENTS_CTRL                56      /* R/W, 2 bytes */
 #define EXT_CSD_DATA_SECTOR_SIZE       61      /* R */
 #define EXT_CSD_GP_SIZE_MULT           143     /* R/W */
+#define EXT_CSD_PARTITION_SETTING_COMPLETED 155        /* R/W */
 #define EXT_CSD_PARTITION_ATTRIBUTE    156     /* R/W */
 #define EXT_CSD_PARTITION_SUPPORT      160     /* RO */
 #define EXT_CSD_HPI_MGMT               161     /* R/W */
@@ -349,6 +355,7 @@ struct _mmc_csd {
 #define EXT_CSD_PART_CONFIG_ACC_RPMB   (0x3)
 #define EXT_CSD_PART_CONFIG_ACC_GP0    (0x4)
 
+#define EXT_CSD_PART_SETTING_COMPLETED (0x1)
 #define EXT_CSD_PART_SUPPORT_PART_EN   (0x1)
 
 #define EXT_CSD_CMD_SET_NORMAL         (1<<0)
index 09ebe57d5ce9b4a810d82b7900dea772b99abf02..dba793e3a331f1d3039b7c5e96eb2a5ccba188b3 100644 (file)
@@ -98,6 +98,8 @@ struct sdhci_host {
 #define SDHCI_QUIRK2_BROKEN_HS200                      (1<<6)
 /* Controller does not support DDR50 */
 #define SDHCI_QUIRK2_BROKEN_DDR50                      (1<<7)
+/* Stop command (CMD12) can set Transfer Complete when not using MMC_RSP_BUSY */
+#define SDHCI_QUIRK2_STOP_WITH_TC                      (1<<8)
 
        int irq;                /* Device IRQ */
        void __iomem *ioaddr;   /* Mapped address */
@@ -146,6 +148,7 @@ struct sdhci_host {
        struct mmc_command *cmd;        /* Current command */
        struct mmc_data *data;  /* Current data request */
        unsigned int data_early:1;      /* Data finished before cmd */
+       unsigned int busy_handle:1;     /* Handling the order of Busy-end */
 
        struct sg_mapping_iter sg_miter;        /* SG state for PIO */
        unsigned int blocks;    /* remaining PIO blocks */
index d2433381e8286573cda47c579660562196644c83..e56fa24c9322db23bd541fdb0d15e7e012cfdddb 100644 (file)
@@ -24,7 +24,10 @@ void mmc_gpio_free_cd(struct mmc_host *host);
 
 int mmc_gpiod_request_cd(struct mmc_host *host, const char *con_id,
                         unsigned int idx, bool override_active_level,
-                        unsigned int debounce);
+                        unsigned int debounce, bool *gpio_invert);
+int mmc_gpiod_request_ro(struct mmc_host *host, const char *con_id,
+                        unsigned int idx, bool override_active_level,
+                        unsigned int debounce, bool *gpio_invert);
 void mmc_gpiod_free_cd(struct mmc_host *host);
 void mmc_gpiod_request_cd_irq(struct mmc_host *host);
 
index b43f4752304e26410a0a870a6d8a15edd48058fd..1c9effa25e2632497384e973a28954f7e33aedbc 100644 (file)
@@ -78,6 +78,8 @@ struct kernel_param {
        };
 };
 
+extern const struct kernel_param __start___param[], __stop___param[];
+
 /* Special one for strings we want to copy into */
 struct kparam_string {
        unsigned int maxlen;
index 8d5535c58cc28578714c99eb6a4c16bbdd5726a9..cc31498fc526d42788b6800105ba43d8a9d25c4a 100644 (file)
@@ -52,7 +52,7 @@ struct mutex {
        atomic_t                count;
        spinlock_t              wait_lock;
        struct list_head        wait_list;
-#if defined(CONFIG_DEBUG_MUTEXES) || defined(CONFIG_SMP)
+#if defined(CONFIG_DEBUG_MUTEXES) || defined(CONFIG_MUTEX_SPIN_ON_OWNER)
        struct task_struct      *owner;
 #endif
 #ifdef CONFIG_MUTEX_SPIN_ON_OWNER
@@ -133,7 +133,7 @@ static inline int mutex_is_locked(struct mutex *lock)
 
 /*
  * See kernel/locking/mutex.c for detailed documentation of these APIs.
- * Also see Documentation/mutex-design.txt.
+ * Also see Documentation/locking/mutex-design.txt.
  */
 #ifdef CONFIG_DEBUG_LOCK_ALLOC
 extern void mutex_lock_nested(struct mutex *lock, unsigned int subclass);
index 1d2a6ab6b8bbae61a679df9f46f1d97012831235..9b2022ab4d852744e1a558a3877fa8f676611a46 100644 (file)
@@ -24,6 +24,19 @@ static inline void touch_nmi_watchdog(void)
 }
 #endif
 
+#if defined(CONFIG_HARDLOCKUP_DETECTOR)
+extern void watchdog_enable_hardlockup_detector(bool val);
+extern bool watchdog_hardlockup_detector_is_enabled(void);
+#else
+static inline void watchdog_enable_hardlockup_detector(bool val)
+{
+}
+static inline bool watchdog_hardlockup_detector_is_enabled(void)
+{
+       return true;
+}
+#endif
+
 /*
  * Create trigger_all_cpu_backtrace() out of the arch-provided
  * base function. Return whether such support was available,
index 6c4363b8ddc3ddba1a75d9f2396f453ae92ab5e9..6545e7aec7bb95dc41ad6225050cb19e7038287a 100644 (file)
@@ -863,4 +863,7 @@ static inline int of_changeset_update_property(struct of_changeset *ocs,
 }
 #endif
 
+/* CONFIG_OF_RESOLVE api */
+extern int of_resolve_phandles(struct device_node *tree);
+
 #endif /* _LINUX_OF_H */
index da9e6f75319643e1e68d8da05eb9ee574fcc76af..24f97bf74266f423fd52994e959eb7d9694eecc4 100644 (file)
 #define PCI_DEVICE_ID_INTEL_EESSC      0x0008
 #define PCI_DEVICE_ID_INTEL_SNB_IMC    0x0100
 #define PCI_DEVICE_ID_INTEL_IVB_IMC    0x0154
+#define PCI_DEVICE_ID_INTEL_IVB_E3_IMC 0x0150
 #define PCI_DEVICE_ID_INTEL_HSW_IMC    0x0c00
 #define PCI_DEVICE_ID_INTEL_PXHD_0     0x0320
 #define PCI_DEVICE_ID_INTEL_PXHD_1     0x0321
 #define PCI_DEVICE_ID_INTEL_UNC_R2PCIE 0x3c43
 #define PCI_DEVICE_ID_INTEL_UNC_R3QPI0 0x3c44
 #define PCI_DEVICE_ID_INTEL_UNC_R3QPI1 0x3c45
+#define PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_RAS    0x3c71  /* 15.1 */
+#define PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_ERR0   0x3c72  /* 16.2 */
+#define PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_ERR1   0x3c73  /* 16.3 */
+#define PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_ERR2   0x3c76  /* 16.6 */
+#define PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_ERR3   0x3c77  /* 16.7 */
+#define PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_HA0    0x3ca0  /* 14.0 */
+#define PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_TA     0x3ca8  /* 15.0 */
+#define PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_TAD0   0x3caa  /* 15.2 */
+#define PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_TAD1   0x3cab  /* 15.3 */
+#define PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_TAD2   0x3cac  /* 15.4 */
+#define PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_TAD3   0x3cad  /* 15.5 */
+#define PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_DDRIO  0x3cb8  /* 17.0 */
 #define PCI_DEVICE_ID_INTEL_JAKETOWN_UBOX      0x3ce0
+#define PCI_DEVICE_ID_INTEL_SBRIDGE_SAD0       0x3cf4  /* 12.6 */
+#define PCI_DEVICE_ID_INTEL_SBRIDGE_BR         0x3cf5  /* 13.6 */
+#define PCI_DEVICE_ID_INTEL_SBRIDGE_SAD1       0x3cf6  /* 12.7 */
 #define PCI_DEVICE_ID_INTEL_IOAT_SNB   0x402f
 #define PCI_DEVICE_ID_INTEL_5100_16    0x65f0
 #define PCI_DEVICE_ID_INTEL_5100_19    0x65f3
 #define PCI_DEVICE_ID_INTEL_82372FB_1  0x7601
 #define PCI_DEVICE_ID_INTEL_SCH_LPC    0x8119
 #define PCI_DEVICE_ID_INTEL_SCH_IDE    0x811a
+#define PCI_DEVICE_ID_INTEL_E6XX_CU    0x8183
 #define PCI_DEVICE_ID_INTEL_ITC_LPC    0x8186
 #define PCI_DEVICE_ID_INTEL_82454GX    0x84c4
 #define PCI_DEVICE_ID_INTEL_82450GX    0x84c5
index 707617a8c0f6c647b8f3c9d210b833638c20eb02..893a0d07986f526b1402ef19238f6e2dccd70973 100644 (file)
@@ -52,6 +52,7 @@ struct perf_guest_info_callbacks {
 #include <linux/atomic.h>
 #include <linux/sysfs.h>
 #include <linux/perf_regs.h>
+#include <linux/workqueue.h>
 #include <asm/local.h>
 
 struct perf_callchain_entry {
@@ -268,6 +269,7 @@ struct pmu {
  * enum perf_event_active_state - the states of a event
  */
 enum perf_event_active_state {
+       PERF_EVENT_STATE_EXIT           = -3,
        PERF_EVENT_STATE_ERROR          = -2,
        PERF_EVENT_STATE_OFF            = -1,
        PERF_EVENT_STATE_INACTIVE       =  0,
@@ -507,6 +509,9 @@ struct perf_event_context {
        int                             nr_cgroups;      /* cgroup evts */
        int                             nr_branch_stack; /* branch_stack evt */
        struct rcu_head                 rcu_head;
+
+       struct delayed_work             orphans_remove;
+       bool                            orphans_remove_sched;
 };
 
 /*
@@ -604,6 +609,13 @@ struct perf_sample_data {
        u64                             txn;
 };
 
+/* default value for data source */
+#define PERF_MEM_NA (PERF_MEM_S(OP, NA)   |\
+                   PERF_MEM_S(LVL, NA)   |\
+                   PERF_MEM_S(SNOOP, NA) |\
+                   PERF_MEM_S(LOCK, NA)  |\
+                   PERF_MEM_S(TLB, NA))
+
 static inline void perf_sample_data_init(struct perf_sample_data *data,
                                         u64 addr, u64 period)
 {
@@ -616,7 +628,7 @@ static inline void perf_sample_data_init(struct perf_sample_data *data,
        data->regs_user.regs = NULL;
        data->stack_user_size = 0;
        data->weight = 0;
-       data->data_src.val = 0;
+       data->data_src.val = PERF_MEM_NA;
        data->txn = 0;
 }
 
index 1a2e9901a22eb4d5d14b52b56057b84d4bd19820..a5f045e1d8fe273c7db4a56382594ed07ccd1b93 100644 (file)
@@ -14,7 +14,7 @@
 #ifndef __RCAR_DU_H__
 #define __RCAR_DU_H__
 
-#include <drm/drm_mode.h>
+#include <video/videomode.h>
 
 enum rcar_du_output {
        RCAR_DU_OUTPUT_DPAD0,
@@ -35,7 +35,7 @@ enum rcar_du_encoder_type {
 struct rcar_du_panel_data {
        unsigned int width_mm;          /* Panel width in mm */
        unsigned int height_mm;         /* Panel height in mm */
-       struct drm_mode_modeinfo mode;
+       struct videomode mode;
 };
 
 struct rcar_du_connector_lvds_data {
diff --git a/include/linux/prio_heap.h b/include/linux/prio_heap.h
deleted file mode 100644 (file)
index 0809435..0000000
+++ /dev/null
@@ -1,58 +0,0 @@
-#ifndef _LINUX_PRIO_HEAP_H
-#define _LINUX_PRIO_HEAP_H
-
-/*
- * Simple insertion-only static-sized priority heap containing
- * pointers, based on CLR, chapter 7
- */
-
-#include <linux/gfp.h>
-
-/**
- * struct ptr_heap - simple static-sized priority heap
- * @ptrs - pointer to data area
- * @max - max number of elements that can be stored in @ptrs
- * @size - current number of valid elements in @ptrs (in the range 0..@size-1
- * @gt: comparison operator, which should implement "greater than"
- */
-struct ptr_heap {
-       void **ptrs;
-       int max;
-       int size;
-       int (*gt)(void *, void *);
-};
-
-/**
- * heap_init - initialize an empty heap with a given memory size
- * @heap: the heap structure to be initialized
- * @size: amount of memory to use in bytes
- * @gfp_mask: mask to pass to kmalloc()
- * @gt: comparison operator, which should implement "greater than"
- */
-extern int heap_init(struct ptr_heap *heap, size_t size, gfp_t gfp_mask,
-                    int (*gt)(void *, void *));
-
-/**
- * heap_free - release a heap's storage
- * @heap: the heap structure whose data should be released
- */
-void heap_free(struct ptr_heap *heap);
-
-/**
- * heap_insert - insert a value into the heap and return any overflowed value
- * @heap: the heap to be operated on
- * @p: the pointer to be inserted
- *
- * Attempts to insert the given value into the priority heap. If the
- * heap is full prior to the insertion, then the resulting heap will
- * consist of the smallest @max elements of the original heap and the
- * new element; the greatest element will be removed from the heap and
- * returned. Note that the returned element will be the new element
- * (i.e. no change to the heap) if the new element is greater than all
- * elements currently in the heap.
- */
-extern void *heap_insert(struct ptr_heap *heap, void *p);
-
-
-
-#endif /* _LINUX_PRIO_HEAP_H */
index fea49b5da12a99bfa6c87b865a461a2a28e0495b..378c5ee75f78f5e1a521d87afeaf13fe21999af5 100644 (file)
@@ -43,6 +43,16 @@ struct rb_augment_callbacks {
 
 extern void __rb_insert_augmented(struct rb_node *node, struct rb_root *root,
        void (*augment_rotate)(struct rb_node *old, struct rb_node *new));
+/*
+ * Fixup the rbtree and update the augmented information when rebalancing.
+ *
+ * On insertion, the user must update the augmented information on the path
+ * leading to the inserted node, then call rb_link_node() as usual and
+ * rb_augment_inserted() instead of the usual rb_insert_color() call.
+ * If rb_augment_inserted() rebalances the rbtree, it will callback into
+ * a user provided function to update the augmented information on the
+ * affected subtrees.
+ */
 static inline void
 rb_insert_augmented(struct rb_node *node, struct rb_root *root,
                    const struct rb_augment_callbacks *augment)
index d231aa17b1d7490092b1994facbe21c496bead66..a4a819ffb2d116d1225608393481521ad3cacc88 100644 (file)
 #include <asm/barrier.h>
 
 extern int rcu_expedited; /* for sysctl */
-#ifdef CONFIG_RCU_TORTURE_TEST
-extern int rcutorture_runnable; /* for sysctl */
-#endif /* #ifdef CONFIG_RCU_TORTURE_TEST */
 
 enum rcutorture_type {
        RCU_FLAVOR,
        RCU_BH_FLAVOR,
        RCU_SCHED_FLAVOR,
+       RCU_TASKS_FLAVOR,
        SRCU_FLAVOR,
        INVALID_RCU_FLAVOR
 };
@@ -197,6 +195,28 @@ void call_rcu_sched(struct rcu_head *head,
 
 void synchronize_sched(void);
 
+/**
+ * call_rcu_tasks() - Queue an RCU for invocation task-based grace period
+ * @head: structure to be used for queueing the RCU updates.
+ * @func: actual callback function to be invoked after the grace period
+ *
+ * The callback function will be invoked some time after a full grace
+ * period elapses, in other words after all currently executing RCU
+ * read-side critical sections have completed. call_rcu_tasks() assumes
+ * that the read-side critical sections end at a voluntary context
+ * switch (not a preemption!), entry into idle, or transition to usermode
+ * execution.  As such, there are no read-side primitives analogous to
+ * rcu_read_lock() and rcu_read_unlock() because this primitive is intended
+ * to determine that all tasks have passed through a safe state, not so
+ * much for data-strcuture synchronization.
+ *
+ * See the description of call_rcu() for more detailed information on
+ * memory ordering guarantees.
+ */
+void call_rcu_tasks(struct rcu_head *head, void (*func)(struct rcu_head *head));
+void synchronize_rcu_tasks(void);
+void rcu_barrier_tasks(void);
+
 #ifdef CONFIG_PREEMPT_RCU
 
 void __rcu_read_lock(void);
@@ -238,8 +258,8 @@ static inline int rcu_preempt_depth(void)
 
 /* Internal to kernel */
 void rcu_init(void);
-void rcu_sched_qs(int cpu);
-void rcu_bh_qs(int cpu);
+void rcu_sched_qs(void);
+void rcu_bh_qs(void);
 void rcu_check_callbacks(int cpu, int user);
 struct notifier_block;
 void rcu_idle_enter(void);
@@ -269,6 +289,14 @@ static inline void rcu_user_hooks_switch(struct task_struct *prev,
                                         struct task_struct *next) { }
 #endif /* CONFIG_RCU_USER_QS */
 
+#ifdef CONFIG_RCU_NOCB_CPU
+void rcu_init_nohz(void);
+#else /* #ifdef CONFIG_RCU_NOCB_CPU */
+static inline void rcu_init_nohz(void)
+{
+}
+#endif /* #else #ifdef CONFIG_RCU_NOCB_CPU */
+
 /**
  * RCU_NONIDLE - Indicate idle-loop code that needs RCU readers
  * @a: Code that RCU needs to pay attention to.
@@ -294,6 +322,36 @@ static inline void rcu_user_hooks_switch(struct task_struct *prev,
                rcu_irq_exit(); \
        } while (0)
 
+/*
+ * Note a voluntary context switch for RCU-tasks benefit.  This is a
+ * macro rather than an inline function to avoid #include hell.
+ */
+#ifdef CONFIG_TASKS_RCU
+#define TASKS_RCU(x) x
+extern struct srcu_struct tasks_rcu_exit_srcu;
+#define rcu_note_voluntary_context_switch(t) \
+       do { \
+               if (ACCESS_ONCE((t)->rcu_tasks_holdout)) \
+                       ACCESS_ONCE((t)->rcu_tasks_holdout) = false; \
+       } while (0)
+#else /* #ifdef CONFIG_TASKS_RCU */
+#define TASKS_RCU(x) do { } while (0)
+#define rcu_note_voluntary_context_switch(t)   do { } while (0)
+#endif /* #else #ifdef CONFIG_TASKS_RCU */
+
+/**
+ * cond_resched_rcu_qs - Report potential quiescent states to RCU
+ *
+ * This macro resembles cond_resched(), except that it is defined to
+ * report potential quiescent states to RCU-tasks even if the cond_resched()
+ * machinery were to be shut off, as some advocate for PREEMPT kernels.
+ */
+#define cond_resched_rcu_qs() \
+do { \
+       rcu_note_voluntary_context_switch(current); \
+       cond_resched(); \
+} while (0)
+
 #if defined(CONFIG_DEBUG_LOCK_ALLOC) || defined(CONFIG_RCU_TRACE) || defined(CONFIG_SMP)
 bool __rcu_is_watching(void);
 #endif /* #if defined(CONFIG_DEBUG_LOCK_ALLOC) || defined(CONFIG_RCU_TRACE) || defined(CONFIG_SMP) */
@@ -349,7 +407,7 @@ bool rcu_lockdep_current_cpu_online(void);
 #else /* #if defined(CONFIG_HOTPLUG_CPU) && defined(CONFIG_PROVE_RCU) */
 static inline bool rcu_lockdep_current_cpu_online(void)
 {
-       return 1;
+       return true;
 }
 #endif /* #else #if defined(CONFIG_HOTPLUG_CPU) && defined(CONFIG_PROVE_RCU) */
 
@@ -371,41 +429,7 @@ extern struct lockdep_map rcu_sched_lock_map;
 extern struct lockdep_map rcu_callback_map;
 int debug_lockdep_rcu_enabled(void);
 
-/**
- * rcu_read_lock_held() - might we be in RCU read-side critical section?
- *
- * If CONFIG_DEBUG_LOCK_ALLOC is selected, returns nonzero iff in an RCU
- * read-side critical section.  In absence of CONFIG_DEBUG_LOCK_ALLOC,
- * this assumes we are in an RCU read-side critical section unless it can
- * prove otherwise.  This is useful for debug checks in functions that
- * require that they be called within an RCU read-side critical section.
- *
- * Checks debug_lockdep_rcu_enabled() to prevent false positives during boot
- * and while lockdep is disabled.
- *
- * Note that rcu_read_lock() and the matching rcu_read_unlock() must
- * occur in the same context, for example, it is illegal to invoke
- * rcu_read_unlock() in process context if the matching rcu_read_lock()
- * was invoked from within an irq handler.
- *
- * Note that rcu_read_lock() is disallowed if the CPU is either idle or
- * offline from an RCU perspective, so check for those as well.
- */
-static inline int rcu_read_lock_held(void)
-{
-       if (!debug_lockdep_rcu_enabled())
-               return 1;
-       if (!rcu_is_watching())
-               return 0;
-       if (!rcu_lockdep_current_cpu_online())
-               return 0;
-       return lock_is_held(&rcu_lock_map);
-}
-
-/*
- * rcu_read_lock_bh_held() is defined out of line to avoid #include-file
- * hell.
- */
+int rcu_read_lock_held(void);
 int rcu_read_lock_bh_held(void);
 
 /**
index d40a6a45133040fbbb3eb74b0d879e3f013a70d4..38cc5b1e252d2f2ddcc9b2d9e0e1617321ced6d4 100644 (file)
@@ -80,7 +80,7 @@ static inline void kfree_call_rcu(struct rcu_head *head,
 
 static inline void rcu_note_context_switch(int cpu)
 {
-       rcu_sched_qs(cpu);
+       rcu_sched_qs();
 }
 
 /*
index 48bf152761c7a3f27647609c6f83072989888c4b..67fc8fcdc4b0fdcd080ddef1c907b1c2aed3d445 100644 (file)
@@ -38,6 +38,9 @@ extern int reboot_force;
 extern int register_reboot_notifier(struct notifier_block *);
 extern int unregister_reboot_notifier(struct notifier_block *);
 
+extern int register_restart_handler(struct notifier_block *);
+extern int unregister_restart_handler(struct notifier_block *);
+extern void do_kernel_restart(char *cmd);
 
 /*
  * Architecture-specific implementations of sys_reboot commands.
index 035d3c57fc8a7147207c1d2cf4e532a355c9d8ae..8f498cdde2802e25667e3143eac3a6945554563c 100644 (file)
@@ -149,7 +149,7 @@ extern void downgrade_write(struct rw_semaphore *sem);
  * static then another method for expressing nested locking is
  * the explicit definition of lock class keys and the use of
  * lockdep_set_class() at lock initialization time.
- * See Documentation/lockdep-design.txt for more details.)
+ * See Documentation/locking/lockdep-design.txt for more details.)
  */
 extern void down_read_nested(struct rw_semaphore *sem, int subclass);
 extern void down_write_nested(struct rw_semaphore *sem, int subclass);
index 5e63ba59258c5909588f073c546743ef1f35c6b7..5e344bbe63ec29c16845623603c58a192159b7f9 100644 (file)
@@ -57,6 +57,7 @@ struct sched_param {
 #include <linux/llist.h>
 #include <linux/uidgid.h>
 #include <linux/gfp.h>
+#include <linux/magic.h>
 
 #include <asm/processor.h>
 
@@ -646,6 +647,7 @@ struct signal_struct {
         * Live threads maintain their own counters and add to these
         * in __exit_signal, except for the group leader.
         */
+       seqlock_t stats_lock;
        cputime_t utime, stime, cutime, cstime;
        cputime_t gtime;
        cputime_t cgtime;
@@ -1024,6 +1026,7 @@ struct sched_domain_topology_level {
 extern struct sched_domain_topology_level *sched_domain_topology;
 
 extern void set_sched_topology(struct sched_domain_topology_level *tl);
+extern void wake_up_if_idle(int cpu);
 
 #ifdef CONFIG_SCHED_DEBUG
 # define SD_INIT_NAME(type)            .name = #type
@@ -1213,6 +1216,13 @@ struct sched_dl_entity {
        struct hrtimer dl_timer;
 };
 
+union rcu_special {
+       struct {
+               bool blocked;
+               bool need_qs;
+       } b;
+       short s;
+};
 struct rcu_node;
 
 enum perf_event_task_context {
@@ -1265,12 +1275,18 @@ struct task_struct {
 
 #ifdef CONFIG_PREEMPT_RCU
        int rcu_read_lock_nesting;
-       char rcu_read_unlock_special;
+       union rcu_special rcu_read_unlock_special;
        struct list_head rcu_node_entry;
 #endif /* #ifdef CONFIG_PREEMPT_RCU */
 #ifdef CONFIG_TREE_PREEMPT_RCU
        struct rcu_node *rcu_blocked_node;
 #endif /* #ifdef CONFIG_TREE_PREEMPT_RCU */
+#ifdef CONFIG_TASKS_RCU
+       unsigned long rcu_tasks_nvcsw;
+       bool rcu_tasks_holdout;
+       struct list_head rcu_tasks_holdout_list;
+       int rcu_tasks_idle_cpu;
+#endif /* #ifdef CONFIG_TASKS_RCU */
 
 #if defined(CONFIG_SCHEDSTATS) || defined(CONFIG_TASK_DELAY_ACCT)
        struct sched_info sched_info;
@@ -2014,29 +2030,21 @@ extern void task_clear_jobctl_trapping(struct task_struct *task);
 extern void task_clear_jobctl_pending(struct task_struct *task,
                                      unsigned int mask);
 
-#ifdef CONFIG_PREEMPT_RCU
-
-#define RCU_READ_UNLOCK_BLOCKED (1 << 0) /* blocked while in RCU read-side. */
-#define RCU_READ_UNLOCK_NEED_QS (1 << 1) /* RCU core needs CPU response. */
-
 static inline void rcu_copy_process(struct task_struct *p)
 {
+#ifdef CONFIG_PREEMPT_RCU
        p->rcu_read_lock_nesting = 0;
-       p->rcu_read_unlock_special = 0;
-#ifdef CONFIG_TREE_PREEMPT_RCU
+       p->rcu_read_unlock_special.s = 0;
        p->rcu_blocked_node = NULL;
-#endif /* #ifdef CONFIG_TREE_PREEMPT_RCU */
        INIT_LIST_HEAD(&p->rcu_node_entry);
+#endif /* #ifdef CONFIG_PREEMPT_RCU */
+#ifdef CONFIG_TASKS_RCU
+       p->rcu_tasks_holdout = false;
+       INIT_LIST_HEAD(&p->rcu_tasks_holdout_list);
+       p->rcu_tasks_idle_cpu = -1;
+#endif /* #ifdef CONFIG_TASKS_RCU */
 }
 
-#else
-
-static inline void rcu_copy_process(struct task_struct *p)
-{
-}
-
-#endif
-
 static inline void tsk_restore_flags(struct task_struct *task,
                                unsigned long orig_flags, unsigned long flags)
 {
@@ -2642,6 +2650,8 @@ static inline unsigned long *end_of_stack(struct task_struct *p)
 }
 
 #endif
+#define task_stack_end_corrupted(task) \
+               (*(end_of_stack(task)) != STACK_END_MAGIC)
 
 static inline int object_is_on_stack(void *obj)
 {
@@ -2664,6 +2674,7 @@ static inline unsigned long stack_not_used(struct task_struct *p)
        return (unsigned long)n - (unsigned long)end_of_stack(p);
 }
 #endif
+extern void set_task_stack_end_magic(struct task_struct *tsk);
 
 /* set thread flags in other task's structures
  * - see asm/thread_info.h for TIF_xxxx flags available
index 5d586a45a319f20cc1c91412428e81beb0517e60..a19ddacdac30ae8d180c8b3358b18564bfbff564 100644 (file)
@@ -27,19 +27,23 @@ struct seccomp {
        struct seccomp_filter *filter;
 };
 
-extern int __secure_computing(int);
-static inline int secure_computing(int this_syscall)
+#ifdef CONFIG_HAVE_ARCH_SECCOMP_FILTER
+extern int __secure_computing(void);
+static inline int secure_computing(void)
 {
        if (unlikely(test_thread_flag(TIF_SECCOMP)))
-               return  __secure_computing(this_syscall);
+               return  __secure_computing();
        return 0;
 }
 
-/* A wrapper for architectures supporting only SECCOMP_MODE_STRICT. */
-static inline void secure_computing_strict(int this_syscall)
-{
-       BUG_ON(secure_computing(this_syscall) != 0);
-}
+#define SECCOMP_PHASE1_OK      0
+#define SECCOMP_PHASE1_SKIP    1
+
+extern u32 seccomp_phase1(struct seccomp_data *sd);
+int seccomp_phase2(u32 phase1_result);
+#else
+extern void secure_computing_strict(int this_syscall);
+#endif
 
 extern long prctl_get_seccomp(void);
 extern long prctl_set_seccomp(unsigned long, char __user *);
@@ -56,8 +60,11 @@ static inline int seccomp_mode(struct seccomp *s)
 struct seccomp { };
 struct seccomp_filter { };
 
-static inline int secure_computing(int this_syscall) { return 0; }
+#ifdef CONFIG_HAVE_ARCH_SECCOMP_FILTER
+static inline int secure_computing(void) { return 0; }
+#else
 static inline void secure_computing_strict(int this_syscall) { return; }
+#endif
 
 static inline long prctl_get_seccomp(void)
 {
index 623f90e5f38de3f2fcc0a751a25eb10a97f21cd5..ba96471c11bae88b6673faec4d4a268cf550db1b 100644 (file)
@@ -1559,7 +1559,7 @@ struct security_operations {
        int (*file_lock) (struct file *file, unsigned int cmd);
        int (*file_fcntl) (struct file *file, unsigned int cmd,
                           unsigned long arg);
-       int (*file_set_fowner) (struct file *file);
+       void (*file_set_fowner) (struct file *file);
        int (*file_send_sigiotask) (struct task_struct *tsk,
                                    struct fown_struct *fown, int sig);
        int (*file_receive) (struct file *file);
@@ -1834,7 +1834,7 @@ int security_file_mprotect(struct vm_area_struct *vma, unsigned long reqprot,
                           unsigned long prot);
 int security_file_lock(struct file *file, unsigned int cmd);
 int security_file_fcntl(struct file *file, unsigned int cmd, unsigned long arg);
-int security_file_set_fowner(struct file *file);
+void security_file_set_fowner(struct file *file);
 int security_file_send_sigiotask(struct task_struct *tsk,
                                 struct fown_struct *fown, int sig);
 int security_file_receive(struct file *file);
@@ -2108,7 +2108,7 @@ static inline int security_dentry_init_security(struct dentry *dentry,
 static inline int security_inode_init_security(struct inode *inode,
                                                struct inode *dir,
                                                const struct qstr *qstr,
-                                               const initxattrs initxattrs,
+                                               const initxattrs xattrs,
                                                void *fs_data)
 {
        return 0;
@@ -2312,9 +2312,9 @@ static inline int security_file_fcntl(struct file *file, unsigned int cmd,
        return 0;
 }
 
-static inline int security_file_set_fowner(struct file *file)
+static inline void security_file_set_fowner(struct file *file)
 {
-       return 0;
+       return;
 }
 
 static inline int security_file_send_sigiotask(struct task_struct *tsk,
index cc359636cfa32a84364ca5fc3f4380ec71c9dd1c..f5df8f687b4d097dd7855e3670a2b790cb380d5d 100644 (file)
@@ -456,4 +456,23 @@ read_sequnlock_excl_irqrestore(seqlock_t *sl, unsigned long flags)
        spin_unlock_irqrestore(&sl->lock, flags);
 }
 
+static inline unsigned long
+read_seqbegin_or_lock_irqsave(seqlock_t *lock, int *seq)
+{
+       unsigned long flags = 0;
+
+       if (!(*seq & 1))        /* Even */
+               *seq = read_seqbegin(lock);
+       else                    /* Odd */
+               read_seqlock_excl_irqsave(lock, flags);
+
+       return flags;
+}
+
+static inline void
+done_seqretry_irqrestore(seqlock_t *lock, int seq, unsigned long flags)
+{
+       if (seq & 1)
+               read_sequnlock_excl_irqrestore(lock, flags);
+}
 #endif /* __LINUX_SEQLOCK_H */
index 750196fcc0a5144aebb1df7f67102502c871a990..ab1e0392b5ac1ce89c80dc2bf0e4e4ccc7a736bd 100644 (file)
@@ -2,6 +2,7 @@
 #define _LINUX_SIGNAL_H
 
 #include <linux/list.h>
+#include <linux/bug.h>
 #include <uapi/linux/signal.h>
 
 struct task_struct;
@@ -67,7 +68,6 @@ static inline int sigismember(sigset_t *set, int _sig)
 
 static inline int sigisemptyset(sigset_t *set)
 {
-       extern void _NSIG_WORDS_is_unsupported_size(void);
        switch (_NSIG_WORDS) {
        case 4:
                return (set->sig[3] | set->sig[2] |
@@ -77,7 +77,7 @@ static inline int sigisemptyset(sigset_t *set)
        case 1:
                return set->sig[0] == 0;
        default:
-               _NSIG_WORDS_is_unsupported_size();
+               BUILD_BUG();
                return 0;
        }
 }
@@ -90,24 +90,23 @@ static inline int sigisemptyset(sigset_t *set)
 #define _SIG_SET_BINOP(name, op)                                       \
 static inline void name(sigset_t *r, const sigset_t *a, const sigset_t *b) \
 {                                                                      \
-       extern void _NSIG_WORDS_is_unsupported_size(void);              \
        unsigned long a0, a1, a2, a3, b0, b1, b2, b3;                   \
                                                                        \
        switch (_NSIG_WORDS) {                                          \
-           case 4:                                                     \
+       case 4:                                                         \
                a3 = a->sig[3]; a2 = a->sig[2];                         \
                b3 = b->sig[3]; b2 = b->sig[2];                         \
                r->sig[3] = op(a3, b3);                                 \
                r->sig[2] = op(a2, b2);                                 \
-           case 2:                                                     \
+       case 2:                                                         \
                a1 = a->sig[1]; b1 = b->sig[1];                         \
                r->sig[1] = op(a1, b1);                                 \
-           case 1:                                                     \
+       case 1:                                                         \
                a0 = a->sig[0]; b0 = b->sig[0];                         \
                r->sig[0] = op(a0, b0);                                 \
                break;                                                  \
-           default:                                                    \
-               _NSIG_WORDS_is_unsupported_size();                      \
+       default:                                                        \
+               BUILD_BUG();                                            \
        }                                                               \
 }
 
@@ -128,16 +127,14 @@ _SIG_SET_BINOP(sigandnsets, _sig_andn)
 #define _SIG_SET_OP(name, op)                                          \
 static inline void name(sigset_t *set)                                 \
 {                                                                      \
-       extern void _NSIG_WORDS_is_unsupported_size(void);              \
-                                                                       \
        switch (_NSIG_WORDS) {                                          \
-           case 4: set->sig[3] = op(set->sig[3]);                      \
-                   set->sig[2] = op(set->sig[2]);                      \
-           case 2: set->sig[1] = op(set->sig[1]);                      \
-           case 1: set->sig[0] = op(set->sig[0]);                      \
+       case 4: set->sig[3] = op(set->sig[3]);                          \
+               set->sig[2] = op(set->sig[2]);                          \
+       case 2: set->sig[1] = op(set->sig[1]);                          \
+       case 1: set->sig[0] = op(set->sig[0]);                          \
                    break;                                              \
-           default:                                                    \
-               _NSIG_WORDS_is_unsupported_size();                      \
+       default:                                                        \
+               BUILD_BUG();                                            \
        }                                                               \
 }
 
index 34347f26be9b8ff03567a7345b86a8ee3bf17755..93dff5fff524b720e9af7ff84098bb7760e0cd6d 100644 (file)
@@ -100,6 +100,7 @@ int smp_call_function_any(const struct cpumask *mask,
                          smp_call_func_t func, void *info, int wait);
 
 void kick_all_cpus_sync(void);
+void wake_up_all_idle_cpus(void);
 
 /*
  * Generic and arch helpers
@@ -148,6 +149,7 @@ smp_call_function_any(const struct cpumask *mask, smp_call_func_t func,
 }
 
 static inline void kick_all_cpus_sync(void) {  }
+static inline void wake_up_all_idle_cpus(void) {  }
 
 #endif /* !SMP */
 
index 3f2867ff0ced55086615610aa6807f80af042b08..262ba4ef9a8ebacb24e7f7326a05bbcb2f666c69 100644 (file)
@@ -197,7 +197,13 @@ static inline void do_raw_spin_unlock(raw_spinlock_t *lock) __releases(lock)
                 _raw_spin_lock_nest_lock(lock, &(nest_lock)->dep_map); \
         } while (0)
 #else
-# define raw_spin_lock_nested(lock, subclass)          _raw_spin_lock(lock)
+/*
+ * Always evaluate the 'subclass' argument to avoid that the compiler
+ * warns about set-but-not-used variables when building with
+ * CONFIG_DEBUG_LOCK_ALLOC=n and with W=1.
+ */
+# define raw_spin_lock_nested(lock, subclass)          \
+       _raw_spin_lock(((void)(subclass), (lock)))
 # define raw_spin_lock_nest_lock(lock, nest_lock)      _raw_spin_lock(lock)
 #endif
 
index d36977e029af065a7b104c381891db710050850b..e6edfe51575a6f5a452e937376add0afdb7c5d48 100644 (file)
@@ -41,7 +41,7 @@ extern int strcmp(const char *,const char *);
 extern int strncmp(const char *,const char *,__kernel_size_t);
 #endif
 #ifndef __HAVE_ARCH_STRNICMP
-extern int strnicmp(const char *, const char *, __kernel_size_t);
+#define strnicmp strncasecmp
 #endif
 #ifndef __HAVE_ARCH_STRCASECMP
 extern int strcasecmp(const char *s1, const char *s2);
index 3eeee9672a4ac087fe57a691a1579637f810f5a1..6eb567ac56bc10394eb69793ad30b000545afe17 100644 (file)
@@ -20,40 +20,6 @@ int string_get_size(u64 size, enum string_size_units units,
 #define UNESCAPE_ANY           \
        (UNESCAPE_SPACE | UNESCAPE_OCTAL | UNESCAPE_HEX | UNESCAPE_SPECIAL)
 
-/**
- * string_unescape - unquote characters in the given string
- * @src:       source buffer (escaped)
- * @dst:       destination buffer (unescaped)
- * @size:      size of the destination buffer (0 to unlimit)
- * @flags:     combination of the flags (bitwise OR):
- *     %UNESCAPE_SPACE:
- *             '\f' - form feed
- *             '\n' - new line
- *             '\r' - carriage return
- *             '\t' - horizontal tab
- *             '\v' - vertical tab
- *     %UNESCAPE_OCTAL:
- *             '\NNN' - byte with octal value NNN (1 to 3 digits)
- *     %UNESCAPE_HEX:
- *             '\xHH' - byte with hexadecimal value HH (1 to 2 digits)
- *     %UNESCAPE_SPECIAL:
- *             '\"' - double quote
- *             '\\' - backslash
- *             '\a' - alert (BEL)
- *             '\e' - escape
- *     %UNESCAPE_ANY:
- *             all previous together
- *
- * Returns amount of characters processed to the destination buffer excluding
- * trailing '\0'.
- *
- * Because the size of the output will be the same as or less than the size of
- * the input, the transformation may be performed in place.
- *
- * Caller must provide valid source and destination pointers. Be aware that
- * destination buffer will always be NULL-terminated. Source string must be
- * NULL-terminated as well.
- */
 int string_unescape(char *src, char *dst, size_t size, unsigned int flags);
 
 static inline int string_unescape_inplace(char *buf, unsigned int flags)
@@ -71,4 +37,35 @@ static inline int string_unescape_any_inplace(char *buf)
        return string_unescape_any(buf, buf, 0);
 }
 
+#define ESCAPE_SPACE           0x01
+#define ESCAPE_SPECIAL         0x02
+#define ESCAPE_NULL            0x04
+#define ESCAPE_OCTAL           0x08
+#define ESCAPE_ANY             \
+       (ESCAPE_SPACE | ESCAPE_OCTAL | ESCAPE_SPECIAL | ESCAPE_NULL)
+#define ESCAPE_NP              0x10
+#define ESCAPE_ANY_NP          (ESCAPE_ANY | ESCAPE_NP)
+#define ESCAPE_HEX             0x20
+
+int string_escape_mem(const char *src, size_t isz, char **dst, size_t osz,
+               unsigned int flags, const char *esc);
+
+static inline int string_escape_mem_any_np(const char *src, size_t isz,
+               char **dst, size_t osz, const char *esc)
+{
+       return string_escape_mem(src, isz, dst, osz, ESCAPE_ANY_NP, esc);
+}
+
+static inline int string_escape_str(const char *src, char **dst, size_t sz,
+               unsigned int flags, const char *esc)
+{
+       return string_escape_mem(src, strlen(src), dst, sz, flags, esc);
+}
+
+static inline int string_escape_str_any_np(const char *src, char **dst,
+               size_t sz, const char *esc)
+{
+       return string_escape_str(src, dst, sz, ESCAPE_ANY_NP, esc);
+}
+
 #endif
index 595ee86f5e0dba847e6a0d7199fac8b5739d6d0f..eda850ca757a8998edb64c71295fb4ce05dfc17b 100644 (file)
@@ -108,7 +108,7 @@ extern struct tick_sched *tick_get_tick_sched(int cpu);
 extern void tick_irq_enter(void);
 extern int tick_oneshot_mode_active(void);
 #  ifndef arch_needs_cpu
-#   define arch_needs_cpu(cpu) (0)
+#   define arch_needs_cpu() (0)
 #  endif
 # else
 static inline void tick_clock_notify(void) { }
index 5ca58fcbaf1b3be68c9bca647993be7201974faa..7759fc3c622d4af42753175a89b7dad0bd6898ec 100644 (file)
@@ -51,7 +51,7 @@
 
 /* Definitions for online/offline exerciser. */
 int torture_onoff_init(long ooholdoff, long oointerval);
-char *torture_onoff_stats(char *page);
+void torture_onoff_stats(void);
 bool torture_onoff_failures(void);
 
 /* Low-rider random number generator. */
@@ -77,7 +77,8 @@ int torture_stutter_init(int s);
 /* Initialization and cleanup. */
 bool torture_init_begin(char *ttype, bool v, int *runnable);
 void torture_init_end(void);
-bool torture_cleanup(void);
+bool torture_cleanup_begin(void);
+void torture_cleanup_end(void);
 bool torture_must_stop(void);
 bool torture_must_stop_irq(void);
 void torture_kthread_stopping(char *title);
index b1293f15f5920c80d9ebaaa102f91df15a9ab1b7..e08e21e5f601bcec81ea21131c4e58e69c611850 100644 (file)
@@ -157,6 +157,12 @@ extern void syscall_unregfunc(void);
  * Make sure the alignment of the structure in the __tracepoints section will
  * not add unwanted padding between the beginning of the section and the
  * structure. Force alignment to the same alignment as the section start.
+ *
+ * When lockdep is enabled, we make sure to always do the RCU portions of
+ * the tracepoint code, regardless of whether tracing is on or we match the
+ * condition.  This lets us find RCU issues triggered with tracepoints even
+ * when this tracepoint is off.  This code has no purpose other than poking
+ * RCU a bit.
  */
 #define __DECLARE_TRACE(name, proto, args, cond, data_proto, data_args) \
        extern struct tracepoint __tracepoint_##name;                   \
@@ -167,6 +173,11 @@ extern void syscall_unregfunc(void);
                                TP_PROTO(data_proto),                   \
                                TP_ARGS(data_args),                     \
                                TP_CONDITION(cond),,);                  \
+               if (IS_ENABLED(CONFIG_LOCKDEP)) {                       \
+                       rcu_read_lock_sched_notrace();                  \
+                       rcu_dereference_sched(__tracepoint_##name.funcs);\
+                       rcu_read_unlock_sched_notrace();                \
+               }                                                       \
        }                                                               \
        __DECLARE_TRACE_RCU(name, PARAMS(proto), PARAMS(args),          \
                PARAMS(cond), PARAMS(data_proto), PARAMS(data_args))    \
index 290fbf0b6b8ac71736bfc92eec4d00003db912f5..9b1581414cd4ab1606574b01f617ec6a5583f663 100644 (file)
@@ -80,6 +80,9 @@ size_t copy_page_to_iter(struct page *page, size_t offset, size_t bytes,
                         struct iov_iter *i);
 size_t copy_page_from_iter(struct page *page, size_t offset, size_t bytes,
                         struct iov_iter *i);
+size_t copy_to_iter(void *addr, size_t bytes, struct iov_iter *i);
+size_t copy_from_iter(void *addr, size_t bytes, struct iov_iter *i);
+size_t iov_iter_zero(size_t bytes, struct iov_iter *);
 unsigned long iov_iter_alignment(const struct iov_iter *i);
 void iov_iter_init(struct iov_iter *i, int direction, const struct iovec *iov,
                        unsigned long nr_segs, size_t count);
index 80115bf88671f4524a65482a8df6de1d15bad17d..e4a8eb9312eabb508c045b8e0274ae7dd3809a38 100644 (file)
@@ -281,9 +281,11 @@ do {                                                                       \
  * wake_up() has to be called after changing any variable that could
  * change the result of the wait condition.
  *
- * The function returns 0 if the @timeout elapsed, or the remaining
- * jiffies (at least 1) if the @condition evaluated to %true before
- * the @timeout elapsed.
+ * Returns:
+ * 0 if the @condition evaluated to %false after the @timeout elapsed,
+ * 1 if the @condition evaluated to %true after the @timeout elapsed,
+ * or the remaining jiffies (at least 1) if the @condition evaluated
+ * to %true before the @timeout elapsed.
  */
 #define wait_event_timeout(wq, condition, timeout)                     \
 ({                                                                     \
@@ -364,9 +366,11 @@ do {                                                                       \
  * change the result of the wait condition.
  *
  * Returns:
- * 0 if the @timeout elapsed, -%ERESTARTSYS if it was interrupted by
- * a signal, or the remaining jiffies (at least 1) if the @condition
- * evaluated to %true before the @timeout elapsed.
+ * 0 if the @condition evaluated to %false after the @timeout elapsed,
+ * 1 if the @condition evaluated to %true after the @timeout elapsed,
+ * the remaining jiffies (at least 1) if the @condition evaluated
+ * to %true before the @timeout elapsed, or -%ERESTARTSYS if it was
+ * interrupted by a signal.
  */
 #define wait_event_interruptible_timeout(wq, condition, timeout)       \
 ({                                                                     \
index 852e96c4bb46b56d89ddb76d8b440bee01d20ce7..984fb79031de62274363cde081341daea3688593 100644 (file)
@@ -114,7 +114,7 @@ struct ccdc_fault_pixel {
        /* Number of fault pixel */
        unsigned short fp_num;
        /* Address of fault pixel table */
-       unsigned int fpc_table_addr;
+       unsigned long fpc_table_addr;
 };
 
 /* Structure for CCDC configuration parameters for raw capture mode passed
index c9d06d9f7e6eaa823eb4eb8b286ada0008abc176..398279dd1922b4b41959aa7966b0991d19fbb24b 100644 (file)
@@ -57,6 +57,8 @@ enum {
  *             0 - Active high, 1 - Active low
  * @vs_pol: Vertical synchronization polarity
  *             0 - Active high, 1 - Active low
+ * @fld_pol: Field signal polarity
+ *             0 - Positive, 1 - Negative
  * @data_pol: Data polarity
  *             0 - Normal, 1 - One's complement
  */
@@ -65,6 +67,7 @@ struct isp_parallel_platform_data {
        unsigned int clk_pol:1;
        unsigned int hs_pol:1;
        unsigned int vs_pol:1;
+       unsigned int fld_pol:1;
        unsigned int data_pol:1;
 };
 
index 80f951890b4cd1b8397de08e9f82442b97be5c19..e7a1514075ecfc8a3ac11d85fd5f9eb82a848e49 100644 (file)
@@ -135,6 +135,7 @@ void rc_map_init(void);
 #define RC_MAP_DM1105_NEC                "rc-dm1105-nec"
 #define RC_MAP_DNTV_LIVE_DVBT_PRO        "rc-dntv-live-dvbt-pro"
 #define RC_MAP_DNTV_LIVE_DVB_T           "rc-dntv-live-dvb-t"
+#define RC_MAP_DVBSKY                    "rc-dvbsky"
 #define RC_MAP_EMPTY                     "rc-empty"
 #define RC_MAP_EM_TERRATEC               "rc-em-terratec"
 #define RC_MAP_ENCORE_ENLTV2             "rc-encore-enltv2"
index 2fefcf491aa853f8ed868a92f39e8da594422c9b..6ef2d01197da95db59aea39eddc1d0b80592b0b6 100644 (file)
@@ -356,8 +356,8 @@ struct v4l2_fh;
  * @buf_struct_size: size of the driver-specific buffer structure;
  *             "0" indicates the driver doesn't want to use a custom buffer
  *             structure type, so sizeof(struct vb2_buffer) will is used
- * @timestamp_flags: Timestamp flags; V4L2_BUF_FLAGS_TIMESTAMP_* and
- *             V4L2_BUF_FLAGS_TSTAMP_SRC_*
+ * @timestamp_flags: Timestamp flags; V4L2_BUF_FLAG_TIMESTAMP_* and
+ *             V4L2_BUF_FLAG_TSTAMP_SRC_*
  * @gfp_flags: additional gfp flags used when allocating the buffers.
  *             Typically this is 0, but it may be e.g. GFP_DMA or __GFP_DMA32
  *             to force the buffer allocation to a specific memory zone.
@@ -366,6 +366,7 @@ struct v4l2_fh;
  *             cannot be started unless at least this number of buffers
  *             have been queued into the driver.
  *
+ * @mmap_lock: private mutex used when buffers are allocated/freed/mmapped
  * @memory:    current memory type used
  * @bufs:      videobuf buffer structures
  * @num_buffers: number of allocated/used buffers
@@ -402,6 +403,7 @@ struct vb2_queue {
        u32                             min_buffers_needed;
 
 /* private: internal use only */
+       struct mutex                    mmap_lock;
        enum v4l2_memory                memory;
        struct vb2_buffer               *bufs[VIDEO_MAX_FRAME];
        unsigned int                    num_buffers;
@@ -592,6 +594,15 @@ vb2_plane_size(struct vb2_buffer *vb, unsigned int plane_no)
        return 0;
 }
 
+/**
+ * vb2_start_streaming_called() - return streaming status of driver
+ * @q:         videobuf queue
+ */
+static inline bool vb2_start_streaming_called(struct vb2_queue *q)
+{
+       return q->start_streaming_called;
+}
+
 /*
  * The following functions are not part of the vb2 core API, but are simple
  * helper functions that you can use in your struct v4l2_file_operations,
diff --git a/include/misc/cxl.h b/include/misc/cxl.h
new file mode 100644 (file)
index 0000000..975cc78
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2014 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.
+ */
+
+#ifndef _MISC_CXL_H
+#define _MISC_CXL_H
+
+#ifdef CONFIG_CXL_BASE
+
+#define CXL_IRQ_RANGES 4
+
+struct cxl_irq_ranges {
+       irq_hw_number_t offset[CXL_IRQ_RANGES];
+       irq_hw_number_t range[CXL_IRQ_RANGES];
+};
+
+extern atomic_t cxl_use_count;
+
+static inline bool cxl_ctx_in_use(void)
+{
+       return (atomic_read(&cxl_use_count) != 0);
+}
+
+static inline void cxl_ctx_get(void)
+{
+       atomic_inc(&cxl_use_count);
+}
+
+static inline void cxl_ctx_put(void)
+{
+       atomic_dec(&cxl_use_count);
+}
+
+void cxl_slbia(struct mm_struct *mm);
+
+#else /* CONFIG_CXL_BASE */
+
+static inline bool cxl_ctx_in_use(void) { return false; }
+static inline void cxl_slbia(struct mm_struct *mm) {}
+
+#endif /* CONFIG_CXL_BASE */
+
+#endif
index be95b9262801880f7a835f7954f14c1f0c1e2397..aab0f427edb58d59a868595bf6e5238a2546f43d 100644 (file)
 #include <linux/timer.h>
 #include <linux/seq_file.h>
 
-/* print_ssid() is intended to be used in debug (and possibly error)
- * messages. It should never be used for passing ssid to user space. */
-const char *print_ssid(char *buf, const char *ssid, u8 ssid_len);
-#define DECLARE_SSID_BUF(var) char var[IEEE80211_MAX_SSID_LEN * 4 + 1] __maybe_unused
-
 #define NUM_WEP_KEYS   4
 
 enum {
index 7a10cfcd8e33fd73e47e14877f31b1d5baf65b1f..48e18810a9be6fcc6250f80db0d8febcf4e3cdf4 100644 (file)
@@ -1,11 +1,7 @@
 #ifndef _IPV6_NF_REJECT_H
 #define _IPV6_NF_REJECT_H
 
-#include <net/ipv6.h>
-#include <net/ip6_route.h>
-#include <net/ip6_fib.h>
-#include <net/ip6_checksum.h>
-#include <linux/netfilter_ipv6.h>
+#include <linux/icmpv6.h>
 
 static inline void
 nf_send_unreach6(struct net *net, struct sk_buff *skb_in, unsigned char code,
@@ -17,155 +13,6 @@ nf_send_unreach6(struct net *net, struct sk_buff *skb_in, unsigned char code,
        icmpv6_send(skb_in, ICMPV6_DEST_UNREACH, code, 0);
 }
 
-/* Send RST reply */
-static void nf_send_reset6(struct net *net, struct sk_buff *oldskb, int hook)
-{
-       struct sk_buff *nskb;
-       struct tcphdr otcph, *tcph;
-       unsigned int otcplen, hh_len;
-       int tcphoff, needs_ack;
-       const struct ipv6hdr *oip6h = ipv6_hdr(oldskb);
-       struct ipv6hdr *ip6h;
-#define DEFAULT_TOS_VALUE      0x0U
-       const __u8 tclass = DEFAULT_TOS_VALUE;
-       struct dst_entry *dst = NULL;
-       u8 proto;
-       __be16 frag_off;
-       struct flowi6 fl6;
-
-       if ((!(ipv6_addr_type(&oip6h->saddr) & IPV6_ADDR_UNICAST)) ||
-           (!(ipv6_addr_type(&oip6h->daddr) & IPV6_ADDR_UNICAST))) {
-               pr_debug("addr is not unicast.\n");
-               return;
-       }
-
-       proto = oip6h->nexthdr;
-       tcphoff = ipv6_skip_exthdr(oldskb, ((u8*)(oip6h+1) - oldskb->data), &proto, &frag_off);
-
-       if ((tcphoff < 0) || (tcphoff > oldskb->len)) {
-               pr_debug("Cannot get TCP header.\n");
-               return;
-       }
-
-       otcplen = oldskb->len - tcphoff;
-
-       /* IP header checks: fragment, too short. */
-       if (proto != IPPROTO_TCP || otcplen < sizeof(struct tcphdr)) {
-               pr_debug("proto(%d) != IPPROTO_TCP, "
-                        "or too short. otcplen = %d\n",
-                        proto, otcplen);
-               return;
-       }
-
-       if (skb_copy_bits(oldskb, tcphoff, &otcph, sizeof(struct tcphdr)))
-               BUG();
-
-       /* No RST for RST. */
-       if (otcph.rst) {
-               pr_debug("RST is set\n");
-               return;
-       }
-
-       /* Check checksum. */
-       if (nf_ip6_checksum(oldskb, hook, tcphoff, IPPROTO_TCP)) {
-               pr_debug("TCP checksum is invalid\n");
-               return;
-       }
-
-       memset(&fl6, 0, sizeof(fl6));
-       fl6.flowi6_proto = IPPROTO_TCP;
-       fl6.saddr = oip6h->daddr;
-       fl6.daddr = oip6h->saddr;
-       fl6.fl6_sport = otcph.dest;
-       fl6.fl6_dport = otcph.source;
-       security_skb_classify_flow(oldskb, flowi6_to_flowi(&fl6));
-       dst = ip6_route_output(net, NULL, &fl6);
-       if (dst == NULL || dst->error) {
-               dst_release(dst);
-               return;
-       }
-       dst = xfrm_lookup(net, dst, flowi6_to_flowi(&fl6), NULL, 0);
-       if (IS_ERR(dst))
-               return;
-
-       hh_len = (dst->dev->hard_header_len + 15)&~15;
-       nskb = alloc_skb(hh_len + 15 + dst->header_len + sizeof(struct ipv6hdr)
-                        + sizeof(struct tcphdr) + dst->trailer_len,
-                        GFP_ATOMIC);
-
-       if (!nskb) {
-               net_dbg_ratelimited("cannot alloc skb\n");
-               dst_release(dst);
-               return;
-       }
-
-       skb_dst_set(nskb, dst);
-
-       skb_reserve(nskb, hh_len + dst->header_len);
-
-       skb_put(nskb, sizeof(struct ipv6hdr));
-       skb_reset_network_header(nskb);
-       ip6h = ipv6_hdr(nskb);
-       ip6_flow_hdr(ip6h, tclass, 0);
-       ip6h->hop_limit = ip6_dst_hoplimit(dst);
-       ip6h->nexthdr = IPPROTO_TCP;
-       ip6h->saddr = oip6h->daddr;
-       ip6h->daddr = oip6h->saddr;
-
-       skb_reset_transport_header(nskb);
-       tcph = (struct tcphdr *)skb_put(nskb, sizeof(struct tcphdr));
-       /* Truncate to length (no data) */
-       tcph->doff = sizeof(struct tcphdr)/4;
-       tcph->source = otcph.dest;
-       tcph->dest = otcph.source;
-
-       if (otcph.ack) {
-               needs_ack = 0;
-               tcph->seq = otcph.ack_seq;
-               tcph->ack_seq = 0;
-       } else {
-               needs_ack = 1;
-               tcph->ack_seq = htonl(ntohl(otcph.seq) + otcph.syn + otcph.fin
-                                     + otcplen - (otcph.doff<<2));
-               tcph->seq = 0;
-       }
-
-       /* Reset flags */
-       ((u_int8_t *)tcph)[13] = 0;
-       tcph->rst = 1;
-       tcph->ack = needs_ack;
-       tcph->window = 0;
-       tcph->urg_ptr = 0;
-       tcph->check = 0;
-
-       /* Adjust TCP checksum */
-       tcph->check = csum_ipv6_magic(&ipv6_hdr(nskb)->saddr,
-                                     &ipv6_hdr(nskb)->daddr,
-                                     sizeof(struct tcphdr), IPPROTO_TCP,
-                                     csum_partial(tcph,
-                                                  sizeof(struct tcphdr), 0));
-
-       nf_ct_attach(nskb, oldskb);
-
-#if IS_ENABLED(CONFIG_BRIDGE_NETFILTER)
-       /* If we use ip6_local_out for bridged traffic, the MAC source on
-        * the RST will be ours, instead of the destination's.  This confuses
-        * some routers/firewalls, and they drop the packet.  So we need to
-        * build the eth header using the original destination's MAC as the
-        * source, and send the RST packet directly.
-        */
-       if (oldskb->nf_bridge) {
-               struct ethhdr *oeth = eth_hdr(oldskb);
-               nskb->dev = oldskb->nf_bridge->physindev;
-               nskb->protocol = htons(ETH_P_IPV6);
-               ip6h->payload_len = htons(sizeof(struct tcphdr));
-               if (dev_hard_header(nskb, nskb->dev, ntohs(nskb->protocol),
-                                   oeth->h_source, oeth->h_dest, nskb->len) < 0)
-                       return;
-               dev_queue_xmit(nskb);
-       } else
-#endif
-               ip6_local_out(nskb);
-}
+void nf_send_reset6(struct net *net, struct sk_buff *oldskb, int hook);
 
 #endif /* _IPV6_NF_REJECT_H */
index 6f3e10ca0e323f8ca8422e1a75824bce89d61a62..e862497f75568d11cd4deb4f5f5a06712f63d6de 100644 (file)
@@ -183,6 +183,7 @@ struct snd_pcm_ops {
 #define SNDRV_PCM_FMTBIT_G723_40_1B    _SNDRV_PCM_FMTBIT(G723_40_1B)
 #define SNDRV_PCM_FMTBIT_DSD_U8                _SNDRV_PCM_FMTBIT(DSD_U8)
 #define SNDRV_PCM_FMTBIT_DSD_U16_LE    _SNDRV_PCM_FMTBIT(DSD_U16_LE)
+#define SNDRV_PCM_FMTBIT_DSD_U32_LE    _SNDRV_PCM_FMTBIT(DSD_U32_LE)
 
 #ifdef SNDRV_LITTLE_ENDIAN
 #define SNDRV_PCM_FMTBIT_S16           SNDRV_PCM_FMTBIT_S16_LE
@@ -365,6 +366,7 @@ struct snd_pcm_runtime {
 
 struct snd_pcm_group {         /* keep linked substreams */
        spinlock_t lock;
+       struct mutex mutex;
        struct list_head substreams;
        int count;
 };
@@ -460,6 +462,7 @@ struct snd_pcm {
        void (*private_free) (struct snd_pcm *pcm);
        struct device *dev; /* actual hw device this belongs to */
        bool internal; /* pcm is for internal use only */
+       bool nonatomic; /* whole PCM operations are in non-atomic context */
 #if defined(CONFIG_SND_PCM_OSS) || defined(CONFIG_SND_PCM_OSS_MODULE)
        struct snd_pcm_oss oss;
 #endif
@@ -492,8 +495,6 @@ int snd_pcm_notify(struct snd_pcm_notify *notify, int nfree);
  *  Native I/O
  */
 
-extern rwlock_t snd_pcm_link_rwlock;
-
 int snd_pcm_info(struct snd_pcm_substream *substream, struct snd_pcm_info *info);
 int snd_pcm_info_user(struct snd_pcm_substream *substream,
                      struct snd_pcm_info __user *info);
@@ -537,41 +538,18 @@ static inline int snd_pcm_stream_linked(struct snd_pcm_substream *substream)
        return substream->group != &substream->self_group;
 }
 
-static inline void snd_pcm_stream_lock(struct snd_pcm_substream *substream)
-{
-       read_lock(&snd_pcm_link_rwlock);
-       spin_lock(&substream->self_group.lock);
-}
-
-static inline void snd_pcm_stream_unlock(struct snd_pcm_substream *substream)
-{
-       spin_unlock(&substream->self_group.lock);
-       read_unlock(&snd_pcm_link_rwlock);
-}
-
-static inline void snd_pcm_stream_lock_irq(struct snd_pcm_substream *substream)
-{
-       read_lock_irq(&snd_pcm_link_rwlock);
-       spin_lock(&substream->self_group.lock);
-}
-
-static inline void snd_pcm_stream_unlock_irq(struct snd_pcm_substream *substream)
-{
-       spin_unlock(&substream->self_group.lock);
-       read_unlock_irq(&snd_pcm_link_rwlock);
-}
-
-#define snd_pcm_stream_lock_irqsave(substream, flags) \
-do { \
-       read_lock_irqsave(&snd_pcm_link_rwlock, (flags)); \
-       spin_lock(&substream->self_group.lock); \
-} while (0)
-
-#define snd_pcm_stream_unlock_irqrestore(substream, flags) \
-do { \
-       spin_unlock(&substream->self_group.lock); \
-       read_unlock_irqrestore(&snd_pcm_link_rwlock, (flags)); \
-} while (0)
+void snd_pcm_stream_lock(struct snd_pcm_substream *substream);
+void snd_pcm_stream_unlock(struct snd_pcm_substream *substream);
+void snd_pcm_stream_lock_irq(struct snd_pcm_substream *substream);
+void snd_pcm_stream_unlock_irq(struct snd_pcm_substream *substream);
+unsigned long _snd_pcm_stream_lock_irqsave(struct snd_pcm_substream *substream);
+#define snd_pcm_stream_lock_irqsave(substream, flags)           \
+       do {                                                     \
+               typecheck(unsigned long, flags);                 \
+               flags = _snd_pcm_stream_lock_irqsave(substream); \
+       } while (0)
+void snd_pcm_stream_unlock_irqrestore(struct snd_pcm_substream *substream,
+                                     unsigned long flags);
 
 #define snd_pcm_group_for_each_entry(s, substream) \
        list_for_each_entry(s, &substream->group->substreams, link_list)
index 1de744c242f62f4ff49f68579619a40ddcf957c8..a5352712194be276f68243237c6186495b85a854 100644 (file)
@@ -20,6 +20,9 @@ struct rt5645_platform_data {
        /* 0 = IN2N; 1 = GPIO5; 2 = GPIO11 */
        unsigned int dmic2_data_pin;
        /* 0 = IN2P; 1 = GPIO6; 2 = GPIO10; 3 = GPIO12 */
+
+       unsigned int hp_det_gpio;
+       bool gpio_hp_det_active_high;
 };
 
 #endif
index 3da14313bcfc158214c3f984c7adaa22c4a5be33..082670e3a3536cd87ed4f4268478d02d6b4b120a 100644 (file)
 #ifndef __LINUX_SND_RT5677_H
 #define __LINUX_SND_RT5677_H
 
+enum rt5677_dmic2_clk {
+       RT5677_DMIC_CLK1 = 0,
+       RT5677_DMIC_CLK2 = 1,
+};
+
+
 struct rt5677_platform_data {
-       /* IN1 IN2 can optionally be differential */
+       /* IN1/IN2/LOUT1/LOUT2/LOUT3 can optionally be differential */
        bool in1_diff;
        bool in2_diff;
+       bool lout1_diff;
+       bool lout2_diff;
+       bool lout3_diff;
+       /* DMIC2 clock source selection */
+       enum rt5677_dmic2_clk dmic2_clk_pin;
 };
 
 #endif
index aac04ff84eea5674279fd22984db6ca9b79ba8c7..3a4d7da67b8d895c9bd9b5299a70d698709fcd98 100644 (file)
@@ -432,6 +432,7 @@ int snd_soc_dapm_force_enable_pin_unlocked(struct snd_soc_dapm_context *dapm,
 int snd_soc_dapm_ignore_suspend(struct snd_soc_dapm_context *dapm,
                                const char *pin);
 void snd_soc_dapm_auto_nc_pins(struct snd_soc_card *card);
+unsigned int dapm_kcontrol_get_value(const struct snd_kcontrol *kcontrol);
 
 /* Mostly internal - should not normally be used */
 void dapm_mark_io_dirty(struct snd_soc_dapm_context *dapm);
@@ -587,13 +588,13 @@ struct snd_soc_dapm_context {
        enum snd_soc_bias_level suspend_bias_level;
        struct delayed_work delayed_work;
        unsigned int idle_bias_off:1; /* Use BIAS_OFF instead of STANDBY */
-
+       /* Go to BIAS_OFF in suspend if the DAPM context is idle */
+       unsigned int suspend_bias_off:1;
        void (*seq_notifier)(struct snd_soc_dapm_context *,
                             enum snd_soc_dapm_type, int);
 
        struct device *dev; /* from parent - for debug */
        struct snd_soc_component *component; /* parent component */
-       struct snd_soc_codec *codec; /* parent codec */
        struct snd_soc_card *card; /* parent card */
 
        /* used during DAPM updates */
index c83a334dd00fa9186404917183115fca3124670c..7ba7130037a079f1fb065e9c8fdcf55353aa3c9e 100644 (file)
@@ -690,6 +690,17 @@ struct snd_soc_compr_ops {
 struct snd_soc_component_driver {
        const char *name;
 
+       /* Default control and setup, added after probe() is run */
+       const struct snd_kcontrol_new *controls;
+       unsigned int num_controls;
+       const struct snd_soc_dapm_widget *dapm_widgets;
+       unsigned int num_dapm_widgets;
+       const struct snd_soc_dapm_route *dapm_routes;
+       unsigned int num_dapm_routes;
+
+       int (*probe)(struct snd_soc_component *);
+       void (*remove)(struct snd_soc_component *);
+
        /* DT */
        int (*of_xlate_dai_name)(struct snd_soc_component *component,
                                 struct of_phandle_args *args,
@@ -697,6 +708,10 @@ struct snd_soc_component_driver {
        void (*seq_notifier)(struct snd_soc_component *, enum snd_soc_dapm_type,
                int subseq);
        int (*stream_event)(struct snd_soc_component *, int event);
+
+       /* probe ordering - for components with runtime dependencies */
+       int probe_order;
+       int remove_order;
 };
 
 struct snd_soc_component {
@@ -710,6 +725,7 @@ struct snd_soc_component {
 
        unsigned int ignore_pmdown_time:1; /* pmdown_time is ignored at stop */
        unsigned int registered_as_component:1;
+       unsigned int probed:1;
 
        struct list_head list;
 
@@ -728,9 +744,35 @@ struct snd_soc_component {
 
        struct mutex io_mutex;
 
+#ifdef CONFIG_DEBUG_FS
+       struct dentry *debugfs_root;
+#endif
+
+       /*
+       * DO NOT use any of the fields below in drivers, they are temporary and
+       * are going to be removed again soon. If you use them in driver code the
+       * driver will be marked as BROKEN when these fields are removed.
+       */
+
        /* Don't use these, use snd_soc_component_get_dapm() */
        struct snd_soc_dapm_context dapm;
        struct snd_soc_dapm_context *dapm_ptr;
+
+       const struct snd_kcontrol_new *controls;
+       unsigned int num_controls;
+       const struct snd_soc_dapm_widget *dapm_widgets;
+       unsigned int num_dapm_widgets;
+       const struct snd_soc_dapm_route *dapm_routes;
+       unsigned int num_dapm_routes;
+       struct snd_soc_codec *codec;
+
+       int (*probe)(struct snd_soc_component *);
+       void (*remove)(struct snd_soc_component *);
+
+#ifdef CONFIG_DEBUG_FS
+       void (*init_debugfs)(struct snd_soc_component *component);
+       const char *debugfs_prefix;
+#endif
 };
 
 /* SoC Audio Codec device */
@@ -746,11 +788,9 @@ struct snd_soc_codec {
        struct snd_ac97 *ac97;  /* for ad-hoc ac97 devices */
        unsigned int cache_bypass:1; /* Suppress access to the cache */
        unsigned int suspended:1; /* Codec is in suspend PM state */
-       unsigned int probed:1; /* Codec has been probed */
        unsigned int ac97_registered:1; /* Codec has been AC97 registered */
        unsigned int ac97_created:1; /* Codec has been created by SoC */
        unsigned int cache_init:1; /* codec cache has been initialized */
-       u32 cache_only;  /* Suppress writes to hardware */
        u32 cache_sync; /* Cache needs to be synced to hardware */
 
        /* codec IO */
@@ -766,7 +806,6 @@ struct snd_soc_codec {
        struct snd_soc_dapm_context dapm;
 
 #ifdef CONFIG_DEBUG_FS
-       struct dentry *debugfs_codec_root;
        struct dentry *debugfs_reg;
 #endif
 };
@@ -808,15 +847,12 @@ struct snd_soc_codec_driver {
        int (*set_bias_level)(struct snd_soc_codec *,
                              enum snd_soc_bias_level level);
        bool idle_bias_off;
+       bool suspend_bias_off;
 
        void (*seq_notifier)(struct snd_soc_dapm_context *,
                             enum snd_soc_dapm_type, int);
 
        bool ignore_pmdown_time;  /* Doesn't benefit from pmdown delay */
-
-       /* probe ordering - for components with runtime dependencies */
-       int probe_order;
-       int remove_order;
 };
 
 /* SoC platform interface */
@@ -832,14 +868,6 @@ struct snd_soc_platform_driver {
        int (*pcm_new)(struct snd_soc_pcm_runtime *);
        void (*pcm_free)(struct snd_pcm *);
 
-       /* Default control and setup, added after probe() is run */
-       const struct snd_kcontrol_new *controls;
-       int num_controls;
-       const struct snd_soc_dapm_widget *dapm_widgets;
-       int num_dapm_widgets;
-       const struct snd_soc_dapm_route *dapm_routes;
-       int num_dapm_routes;
-
        /*
         * For platform caused delay reporting.
         * Optional.
@@ -853,13 +881,6 @@ struct snd_soc_platform_driver {
        /* platform stream compress ops */
        const struct snd_compr_ops *compr_ops;
 
-       /* probe ordering - for components with runtime dependencies */
-       int probe_order;
-       int remove_order;
-
-       /* platform IO - used for platform DAPM */
-       unsigned int (*read)(struct snd_soc_platform *, unsigned int);
-       int (*write)(struct snd_soc_platform *, unsigned int, unsigned int);
        int (*bespoke_trigger)(struct snd_pcm_substream *, int);
 };
 
@@ -874,15 +895,10 @@ struct snd_soc_platform {
        const struct snd_soc_platform_driver *driver;
 
        unsigned int suspended:1; /* platform is suspended */
-       unsigned int probed:1;
 
        struct list_head list;
 
        struct snd_soc_component component;
-
-#ifdef CONFIG_DEBUG_FS
-       struct dentry *debugfs_platform_root;
-#endif
 };
 
 struct snd_soc_dai_link {
@@ -897,7 +913,7 @@ struct snd_soc_dai_link {
         * only for codec to codec links, or systems using device tree.
         */
        const char *cpu_name;
-       const struct device_node *cpu_of_node;
+       struct device_node *cpu_of_node;
        /*
         * You MAY specify the DAI name of the CPU DAI. If this information is
         * omitted, the CPU-side DAI is matched using .cpu_name/.cpu_of_node
@@ -909,7 +925,7 @@ struct snd_soc_dai_link {
         * DT/OF node, but not both.
         */
        const char *codec_name;
-       const struct device_node *codec_of_node;
+       struct device_node *codec_of_node;
        /* You MUST specify the DAI name within the codec */
        const char *codec_dai_name;
 
@@ -922,7 +938,7 @@ struct snd_soc_dai_link {
         * do not need a platform.
         */
        const char *platform_name;
-       const struct device_node *platform_of_node;
+       struct device_node *platform_of_node;
        int be_id;      /* optional ID for machine driver BE identification */
 
        const struct snd_soc_pcm_stream *params;
@@ -994,7 +1010,7 @@ struct snd_soc_aux_dev {
        const struct device_node *codec_of_node;
 
        /* codec/machine specific init - e.g. add machine controls */
-       int (*init)(struct snd_soc_dapm_context *dapm);
+       int (*init)(struct snd_soc_component *component);
 };
 
 /* SoC card */
@@ -1112,6 +1128,7 @@ struct snd_soc_pcm_runtime {
        struct snd_soc_platform *platform;
        struct snd_soc_dai *codec_dai;
        struct snd_soc_dai *cpu_dai;
+       struct snd_soc_component *component; /* Only valid for AUX dev rtds */
 
        struct snd_soc_dai **codec_dais;
        unsigned int num_codecs;
@@ -1260,9 +1277,6 @@ void snd_soc_component_async_complete(struct snd_soc_component *component);
 int snd_soc_component_test_bits(struct snd_soc_component *component,
        unsigned int reg, unsigned int mask, unsigned int value);
 
-int snd_soc_component_init_io(struct snd_soc_component *component,
-       struct regmap *regmap);
-
 /* device driver data */
 
 static inline void snd_soc_card_set_drvdata(struct snd_soc_card *card,
@@ -1276,26 +1290,37 @@ static inline void *snd_soc_card_get_drvdata(struct snd_soc_card *card)
        return card->drvdata;
 }
 
+static inline void snd_soc_component_set_drvdata(struct snd_soc_component *c,
+               void *data)
+{
+       dev_set_drvdata(c->dev, data);
+}
+
+static inline void *snd_soc_component_get_drvdata(struct snd_soc_component *c)
+{
+       return dev_get_drvdata(c->dev);
+}
+
 static inline void snd_soc_codec_set_drvdata(struct snd_soc_codec *codec,
                void *data)
 {
-       dev_set_drvdata(codec->dev, data);
+       snd_soc_component_set_drvdata(&codec->component, data);
 }
 
 static inline void *snd_soc_codec_get_drvdata(struct snd_soc_codec *codec)
 {
-       return dev_get_drvdata(codec->dev);
+       return snd_soc_component_get_drvdata(&codec->component);
 }
 
 static inline void snd_soc_platform_set_drvdata(struct snd_soc_platform *platform,
                void *data)
 {
-       dev_set_drvdata(platform->dev, data);
+       snd_soc_component_set_drvdata(&platform->component, data);
 }
 
 static inline void *snd_soc_platform_get_drvdata(struct snd_soc_platform *platform)
 {
-       return dev_get_drvdata(platform->dev);
+       return snd_soc_component_get_drvdata(&platform->component);
 }
 
 static inline void snd_soc_pcm_set_drvdata(struct snd_soc_pcm_runtime *rtd,
index f634f8f85db53addf02c5f9e85d94363aee23de6..cae9c9d4ef2260fcdeff0e74fe8177c176ed6b9b 100644 (file)
@@ -80,8 +80,6 @@ struct vx_pipe {
 
        unsigned int references;     /* an output pipe may be used for monitoring and/or playback */
        struct vx_pipe *monitoring_pipe;  /* pointer to the monitoring pipe (capture pipe only)*/
-
-       struct tasklet_struct start_tq;
 };
 
 struct vx_core;
@@ -165,9 +163,7 @@ struct vx_core {
        struct snd_vx_hardware *hw;
        struct snd_vx_ops *ops;
 
-       spinlock_t lock;
-       spinlock_t irq_lock;
-       struct tasklet_struct tq;
+       struct mutex lock;
 
        unsigned int chip_status;
        unsigned int pcm_running;
@@ -223,6 +219,7 @@ void snd_vx_free_firmware(struct vx_core *chip);
  * interrupt handler; exported for pcmcia
  */
 irqreturn_t snd_vx_irq_handler(int irq, void *dev);
+irqreturn_t snd_vx_threaded_irq_handler(int irq, void *dev);
 
 /*
  * lowlevel functions
index 0194a641e4e2589c71176fabee75c43ad1baec7d..b04ee7e5a466e4419c7c0601e285411c920b7ed3 100644 (file)
@@ -175,7 +175,7 @@ TRACE_EVENT(snd_soc_dapm_output_path,
                __entry->path_sink = (long)path->sink;
        ),
 
-       TP_printk("%c%s -> %s -> %s\n",
+       TP_printk("%c%s -> %s -> %s",
                (int) __entry->path_sink &&
                (int) __entry->path_connect ? '*' : ' ',
                __get_str(wname), __get_str(pname), __get_str(psname))
@@ -204,7 +204,7 @@ TRACE_EVENT(snd_soc_dapm_input_path,
                __entry->path_source = (long)path->source;
        ),
 
-       TP_printk("%c%s <- %s <- %s\n",
+       TP_printk("%c%s <- %s <- %s",
                (int) __entry->path_source &&
                (int) __entry->path_connect ? '*' : ' ',
                __get_str(wname), __get_str(pname), __get_str(psname))
@@ -226,7 +226,7 @@ TRACE_EVENT(snd_soc_dapm_connected,
                __entry->stream = stream;
        ),
 
-       TP_printk("%s: found %d paths\n",
+       TP_printk("%s: found %d paths",
                __entry->stream ? "capture" : "playback", __entry->paths)
 );
 
index 4ee4e30d26d9b3a9d5bccbb51348e0b876365f26..1faecea101f3e85a84c247ec997af8216de2523d 100644 (file)
@@ -23,6 +23,7 @@ struct map_lookup;
 struct extent_buffer;
 struct btrfs_work;
 struct __btrfs_workqueue;
+struct btrfs_qgroup_operation;
 
 #define show_ref_type(type)                                            \
        __print_symbolic(type,                                          \
@@ -157,12 +158,13 @@ DEFINE_EVENT(btrfs__inode, btrfs_inode_evict,
 
 #define show_map_flags(flag)                                           \
        __print_flags(flag, "|",                                        \
-               { EXTENT_FLAG_PINNED,           "PINNED"        },      \
-               { EXTENT_FLAG_COMPRESSED,       "COMPRESSED"    },      \
-               { EXTENT_FLAG_VACANCY,          "VACANCY"       },      \
-               { EXTENT_FLAG_PREALLOC,         "PREALLOC"      },      \
-               { EXTENT_FLAG_LOGGING,          "LOGGING"       },      \
-               { EXTENT_FLAG_FILLING,          "FILLING"       })
+               { (1 << EXTENT_FLAG_PINNED),            "PINNED"        },\
+               { (1 << EXTENT_FLAG_COMPRESSED),        "COMPRESSED"    },\
+               { (1 << EXTENT_FLAG_VACANCY),           "VACANCY"       },\
+               { (1 << EXTENT_FLAG_PREALLOC),          "PREALLOC"      },\
+               { (1 << EXTENT_FLAG_LOGGING),           "LOGGING"       },\
+               { (1 << EXTENT_FLAG_FILLING),           "FILLING"       },\
+               { (1 << EXTENT_FLAG_FS_MAPPING),        "FS_MAPPING"    })
 
 TRACE_EVENT_CONDITION(btrfs_get_extent,
 
@@ -996,6 +998,7 @@ DECLARE_EVENT_CLASS(btrfs__work,
                __field(        void *, func                    )
                __field(        void *, ordered_func            )
                __field(        void *, ordered_free            )
+               __field(        void *, normal_work             )
        ),
 
        TP_fast_assign(
@@ -1004,11 +1007,13 @@ DECLARE_EVENT_CLASS(btrfs__work,
                __entry->func           = work->func;
                __entry->ordered_func   = work->ordered_func;
                __entry->ordered_free   = work->ordered_free;
+               __entry->normal_work    = &work->normal_work;
        ),
 
-       TP_printk("work=%p, wq=%p, func=%p, ordered_func=%p, ordered_free=%p",
-                 __entry->work, __entry->wq, __entry->func,
-                 __entry->ordered_func, __entry->ordered_free)
+       TP_printk("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)
 );
 
 /* For situiations that the work is freed */
@@ -1043,13 +1048,6 @@ DEFINE_EVENT(btrfs__work, btrfs_work_sched,
        TP_ARGS(work)
 );
 
-DEFINE_EVENT(btrfs__work, btrfs_normal_work_done,
-
-       TP_PROTO(struct btrfs_work *work),
-
-       TP_ARGS(work)
-);
-
 DEFINE_EVENT(btrfs__work__done, btrfs_all_work_done,
 
        TP_PROTO(struct btrfs_work *work),
@@ -1119,6 +1117,61 @@ DEFINE_EVENT(btrfs__workqueue_done, btrfs_workqueue_destroy,
        TP_ARGS(wq)
 );
 
+#define show_oper_type(type)                                           \
+       __print_symbolic(type,                                          \
+               { BTRFS_QGROUP_OPER_ADD_EXCL,   "OPER_ADD_EXCL" },      \
+               { BTRFS_QGROUP_OPER_ADD_SHARED, "OPER_ADD_SHARED" },    \
+               { BTRFS_QGROUP_OPER_SUB_EXCL,   "OPER_SUB_EXCL" },      \
+               { BTRFS_QGROUP_OPER_SUB_SHARED, "OPER_SUB_SHARED" })
+
+DECLARE_EVENT_CLASS(btrfs_qgroup_oper,
+
+       TP_PROTO(struct btrfs_qgroup_operation *oper),
+
+       TP_ARGS(oper),
+
+       TP_STRUCT__entry(
+               __field(        u64,  ref_root          )
+               __field(        u64,  bytenr            )
+               __field(        u64,  num_bytes         )
+               __field(        u64,  seq               )
+               __field(        int,  type              )
+               __field(        u64,  elem_seq          )
+       ),
+
+       TP_fast_assign(
+               __entry->ref_root       = oper->ref_root;
+               __entry->bytenr         = oper->bytenr,
+               __entry->num_bytes      = oper->num_bytes;
+               __entry->seq            = oper->seq;
+               __entry->type           = oper->type;
+               __entry->elem_seq       = oper->elem.seq;
+       ),
+
+       TP_printk("ref_root = %llu, bytenr = %llu, num_bytes = %llu, "
+                 "seq = %llu, elem.seq = %llu, type = %s",
+                 (unsigned long long)__entry->ref_root,
+                 (unsigned long long)__entry->bytenr,
+                 (unsigned long long)__entry->num_bytes,
+                 (unsigned long long)__entry->seq,
+                 (unsigned long long)__entry->elem_seq,
+                 show_oper_type(__entry->type))
+);
+
+DEFINE_EVENT(btrfs_qgroup_oper, btrfs_qgroup_account,
+
+       TP_PROTO(struct btrfs_qgroup_operation *oper),
+
+       TP_ARGS(oper)
+);
+
+DEFINE_EVENT(btrfs_qgroup_oper, btrfs_qgroup_record_ref,
+
+       TP_PROTO(struct btrfs_qgroup_operation *oper),
+
+       TP_ARGS(oper)
+);
+
 #endif /* _TRACE_BTRFS_H */
 
 /* This part must be outside protection */
index 59d11c22f07639ca586a46644ef32b6e061b4ce1..a0d008070962b6b153b979e51108e3d23b4a5935 100644 (file)
@@ -53,15 +53,15 @@ DECLARE_EVENT_CLASS(filelock_lease,
        ),
 
        TP_fast_assign(
-               __entry->fl = fl;
+               __entry->fl = fl ? fl : NULL;
                __entry->s_dev = inode->i_sb->s_dev;
                __entry->i_ino = inode->i_ino;
-               __entry->fl_next = fl->fl_next;
-               __entry->fl_owner = fl->fl_owner;
-               __entry->fl_flags = fl->fl_flags;
-               __entry->fl_type = fl->fl_type;
-               __entry->fl_break_time = fl->fl_break_time;
-               __entry->fl_downgrade_time = fl->fl_downgrade_time;
+               __entry->fl_next = fl ? fl->fl_next : NULL;
+               __entry->fl_owner = fl ? fl->fl_owner : NULL;
+               __entry->fl_flags = fl ? fl->fl_flags : 0;
+               __entry->fl_type = fl ? fl->fl_type : 0;
+               __entry->fl_break_time = fl ? fl->fl_break_time : 0;
+               __entry->fl_downgrade_time = fl ? fl->fl_downgrade_time : 0;
        ),
 
        TP_printk("fl=0x%p dev=0x%x:0x%x ino=0x%lx fl_next=0x%p fl_owner=0x%p fl_flags=%s fl_type=%s fl_break_time=%lu fl_downgrade_time=%lu",
index aca382266411620f6bd7b052311cee6d6b04e8e7..9b56f37148cfd91d57b849f88c8b1279220aa41a 100644 (file)
@@ -180,9 +180,12 @@ TRACE_EVENT(rcu_grace_period_init,
  * argument is a string as follows:
  *
  *     "WakeEmpty": Wake rcuo kthread, first CB to empty list.
+ *     "WakeEmptyIsDeferred": Wake rcuo kthread later, first CB to empty list.
  *     "WakeOvf": Wake rcuo kthread, CB list is huge.
+ *     "WakeOvfIsDeferred": Wake rcuo kthread later, CB list is huge.
  *     "WakeNot": Don't wake rcuo kthread.
  *     "WakeNotPoll": Don't wake rcuo kthread because it is polling.
+ *     "DeferredWake": Carried out the "IsDeferred" wakeup.
  *     "Poll": Start of new polling cycle for rcu_nocb_poll.
  *     "Sleep": Sleep waiting for CBs for !rcu_nocb_poll.
  *     "WokeEmpty": rcuo kthread woke to find empty list.
index 81d2106287fef98433387e5a62afe628a9192950..245aa6e05e6adef3f0c0cc4ea2e3a017a2231481 100644 (file)
@@ -12,3 +12,4 @@ header-y += video/
 header-y += drm/
 header-y += xen/
 header-y += scsi/
+header-y += misc/
index d5844122ff329dabf4d5c8431f138f48a86d0ed3..5575ed1598bd8a7c30866582c9527a516bc97430 100644 (file)
@@ -32,38 +32,6 @@ struct drm_exynos_gem_create {
        unsigned int handle;
 };
 
-/**
- * A structure for getting buffer offset.
- *
- * @handle: a pointer to gem object created.
- * @pad: just padding to be 64-bit aligned.
- * @offset: relatived offset value of the memory region allocated.
- *     - this value should be set by user.
- */
-struct drm_exynos_gem_map_off {
-       unsigned int handle;
-       unsigned int pad;
-       uint64_t offset;
-};
-
-/**
- * A structure for mapping buffer.
- *
- * @handle: a handle to gem object created.
- * @pad: just padding to be 64-bit aligned.
- * @size: memory size to be mapped.
- * @mapped: having user virtual address mmaped.
- *     - this variable would be filled by exynos gem module
- *     of kernel side with user virtual address which is allocated
- *     by do_mmap().
- */
-struct drm_exynos_gem_mmap {
-       unsigned int handle;
-       unsigned int pad;
-       uint64_t size;
-       uint64_t mapped;
-};
-
 /**
  * A structure to gem information.
  *
@@ -316,8 +284,6 @@ struct drm_exynos_ipp_cmd_ctrl {
 };
 
 #define DRM_EXYNOS_GEM_CREATE          0x00
-#define DRM_EXYNOS_GEM_MAP_OFFSET      0x01
-#define DRM_EXYNOS_GEM_MMAP            0x02
 /* Reserved 0x03 ~ 0x05 for exynos specific gem ioctl */
 #define DRM_EXYNOS_GEM_GET             0x04
 #define DRM_EXYNOS_VIDI_CONNECTION     0x07
@@ -336,12 +302,6 @@ struct drm_exynos_ipp_cmd_ctrl {
 #define DRM_IOCTL_EXYNOS_GEM_CREATE            DRM_IOWR(DRM_COMMAND_BASE + \
                DRM_EXYNOS_GEM_CREATE, struct drm_exynos_gem_create)
 
-#define DRM_IOCTL_EXYNOS_GEM_MAP_OFFSET        DRM_IOWR(DRM_COMMAND_BASE + \
-               DRM_EXYNOS_GEM_MAP_OFFSET, struct drm_exynos_gem_map_off)
-
-#define DRM_IOCTL_EXYNOS_GEM_MMAP      DRM_IOWR(DRM_COMMAND_BASE + \
-               DRM_EXYNOS_GEM_MMAP, struct drm_exynos_gem_mmap)
-
 #define DRM_IOCTL_EXYNOS_GEM_GET       DRM_IOWR(DRM_COMMAND_BASE + \
                DRM_EXYNOS_GEM_GET,     struct drm_exynos_gem_info)
 
index fea6099608ef2244d2020fbf5dcfac3c7d886d91..50d0fb41a3bf32cb2a796f3738adb10d79e3fb6c 100644 (file)
@@ -511,6 +511,7 @@ typedef struct {
 #define DRM_RADEON_GEM_BUSY            0x2a
 #define DRM_RADEON_GEM_VA              0x2b
 #define DRM_RADEON_GEM_OP              0x2c
+#define DRM_RADEON_GEM_USERPTR         0x2d
 
 #define DRM_IOCTL_RADEON_CP_INIT    DRM_IOW( DRM_COMMAND_BASE + DRM_RADEON_CP_INIT, drm_radeon_init_t)
 #define DRM_IOCTL_RADEON_CP_START   DRM_IO(  DRM_COMMAND_BASE + DRM_RADEON_CP_START)
@@ -554,6 +555,7 @@ typedef struct {
 #define DRM_IOCTL_RADEON_GEM_BUSY      DRM_IOWR(DRM_COMMAND_BASE + DRM_RADEON_GEM_BUSY, struct drm_radeon_gem_busy)
 #define DRM_IOCTL_RADEON_GEM_VA                DRM_IOWR(DRM_COMMAND_BASE + DRM_RADEON_GEM_VA, struct drm_radeon_gem_va)
 #define DRM_IOCTL_RADEON_GEM_OP                DRM_IOWR(DRM_COMMAND_BASE + DRM_RADEON_GEM_OP, struct drm_radeon_gem_op)
+#define DRM_IOCTL_RADEON_GEM_USERPTR   DRM_IOWR(DRM_COMMAND_BASE + DRM_RADEON_GEM_USERPTR, struct drm_radeon_gem_userptr)
 
 typedef struct drm_radeon_init {
        enum {
@@ -799,6 +801,10 @@ struct drm_radeon_gem_info {
 #define RADEON_GEM_NO_BACKING_STORE    (1 << 0)
 #define RADEON_GEM_GTT_UC              (1 << 1)
 #define RADEON_GEM_GTT_WC              (1 << 2)
+/* BO is expected to be accessed by the CPU */
+#define RADEON_GEM_CPU_ACCESS          (1 << 3)
+/* CPU access is not expected to work for this BO */
+#define RADEON_GEM_NO_CPU_ACCESS       (1 << 4)
 
 struct drm_radeon_gem_create {
        uint64_t        size;
@@ -808,6 +814,23 @@ struct drm_radeon_gem_create {
        uint32_t        flags;
 };
 
+/*
+ * This is not a reliable API and you should expect it to fail for any
+ * number of reasons and have fallback path that do not use userptr to
+ * perform any operation.
+ */
+#define RADEON_GEM_USERPTR_READONLY    (1 << 0)
+#define RADEON_GEM_USERPTR_ANONONLY    (1 << 1)
+#define RADEON_GEM_USERPTR_VALIDATE    (1 << 2)
+#define RADEON_GEM_USERPTR_REGISTER    (1 << 3)
+
+struct drm_radeon_gem_userptr {
+       uint64_t                addr;
+       uint64_t                size;
+       uint32_t                flags;
+       uint32_t                handle;
+};
+
 #define RADEON_TILING_MACRO                            0x1
 #define RADEON_TILING_MICRO                            0x2
 #define RADEON_TILING_SWAP_16BIT                       0x4
index 4fc66f6b12ced39a20d5c03fd820d1b513cd507d..c472bedbe38ebab3f49e80456ec106c9d90301d0 100644 (file)
@@ -29,7 +29,7 @@
 #define __VMWGFX_DRM_H__
 
 #ifndef __KERNEL__
-#include <drm.h>
+#include <drm/drm.h>
 #endif
 
 #define DRM_VMW_MAX_SURFACE_FACES 6
index 70e150ebc6c9392f4d49aa3744925a82af2561c5..3cc8e1c2b99602fdfbaf24d34612613fcc073149 100644 (file)
@@ -355,6 +355,7 @@ header-y += serio.h
 header-y += shm.h
 header-y += signal.h
 header-y += signalfd.h
+header-y += smiapp.h
 header-y += snmp.h
 header-y += sock_diag.h
 header-y += socket.h
index ef6103bf1f9bb3ade18268a639cc784dcc695b95..ea9bf2561b9efecb236959de88e57c94f96037fb 100644 (file)
@@ -391,6 +391,8 @@ typedef struct elf64_shdr {
 #define NT_S390_LAST_BREAK     0x306   /* s390 breaking event address */
 #define NT_S390_SYSTEM_CALL    0x307   /* s390 system call restart data */
 #define NT_S390_TDB    0x308           /* s390 transaction diagnostic block */
+#define NT_S390_VXRS_LOW       0x309   /* s390 vector registers 0-15 upper half */
+#define NT_S390_VXRS_HIGH      0x30a   /* s390 vector registers 16-31 */
 #define NT_ARM_VFP     0x400           /* ARM VFP/NEON registers */
 #define NT_ARM_TLS     0x401           /* ARM TLS register */
 #define NT_ARM_HW_BREAK        0x402           /* ARM hardware breakpoint registers */
index c26df6787fb075a4d2317a9d9e8e897813df8e0f..f31fe7b660a555f8d646a415cec7f0b35ea57f9c 100644 (file)
@@ -774,7 +774,7 @@ enum nft_reject_inet_code {
        NFT_REJECT_ICMPX_ADMIN_PROHIBITED,
        __NFT_REJECT_ICMPX_MAX
 };
-#define NFT_REJECT_ICMPX_MAX   (__NFT_REJECT_ICMPX_MAX + 1)
+#define NFT_REJECT_ICMPX_MAX   (__NFT_REJECT_ICMPX_MAX - 1)
 
 /**
  * enum nft_reject_attributes - nf_tables reject expression netlink attributes
diff --git a/include/uapi/linux/smiapp.h b/include/uapi/linux/smiapp.h
new file mode 100644 (file)
index 0000000..53938f4
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ * include/uapi/linux/smiapp.h
+ *
+ * Generic driver for SMIA/SMIA++ compliant camera modules
+ *
+ * Copyright (C) 2014 Intel Corporation
+ * Contact: Sakari Ailus <sakari.ailus@iki.fi>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ */
+
+#ifndef __UAPI_LINUX_SMIAPP_H_
+#define __UAPI_LINUX_SMIAPP_H_
+
+#define V4L2_SMIAPP_TEST_PATTERN_MODE_DISABLED                 0
+#define V4L2_SMIAPP_TEST_PATTERN_MODE_SOLID_COLOUR             1
+#define V4L2_SMIAPP_TEST_PATTERN_MODE_COLOUR_BARS              2
+#define V4L2_SMIAPP_TEST_PATTERN_MODE_COLOUR_BARS_GREY         3
+#define V4L2_SMIAPP_TEST_PATTERN_MODE_PN9                      4
+
+#endif /* __UAPI_LINUX_SMIAPP_H_ */
index e946e43fb8d51a80073b25ca88bf023228e8d39c..661f119a51b858e3bc4f4e5f2029ce3fa5f3f6d4 100644 (file)
@@ -746,6 +746,8 @@ enum v4l2_auto_focus_range {
        V4L2_AUTO_FOCUS_RANGE_INFINITY          = 3,
 };
 
+#define V4L2_CID_PAN_SPEED                     (V4L2_CID_CAMERA_CLASS_BASE+32)
+#define V4L2_CID_TILT_SPEED                    (V4L2_CID_CAMERA_CLASS_BASE+33)
 
 /* FM Modulator class control IDs */
 
@@ -865,6 +867,10 @@ enum v4l2_jpeg_chroma_subsampling {
 #define V4L2_CID_VBLANK                                (V4L2_CID_IMAGE_SOURCE_CLASS_BASE + 1)
 #define V4L2_CID_HBLANK                                (V4L2_CID_IMAGE_SOURCE_CLASS_BASE + 2)
 #define V4L2_CID_ANALOGUE_GAIN                 (V4L2_CID_IMAGE_SOURCE_CLASS_BASE + 3)
+#define V4L2_CID_TEST_PATTERN_RED              (V4L2_CID_IMAGE_SOURCE_CLASS_BASE + 4)
+#define V4L2_CID_TEST_PATTERN_GREENR           (V4L2_CID_IMAGE_SOURCE_CLASS_BASE + 5)
+#define V4L2_CID_TEST_PATTERN_BLUE             (V4L2_CID_IMAGE_SOURCE_CLASS_BASE + 6)
+#define V4L2_CID_TEST_PATTERN_GREENB           (V4L2_CID_IMAGE_SOURCE_CLASS_BASE + 7)
 
 
 /* Image processing controls */
index 6c8f159e416eea1b2781b4e00139b4b3afe2ea9a..6a0764c89fcbeaf29cee9bf5dcba996ed9bc3c98 100644 (file)
 #ifndef _V4L2_DV_TIMINGS_H
 #define _V4L2_DV_TIMINGS_H
 
-#if __GNUC__ < 4 || (__GNUC__ == 4 && (__GNUC_MINOR__ < 6))
-/* Sadly gcc versions older than 4.6 have a bug in how they initialize
-   anonymous unions where they require additional curly brackets.
-   This violates the C1x standard. This workaround adds the curly brackets
-   if needed. */
 #define V4L2_INIT_BT_TIMINGS(_width, args...) \
        { .bt = { _width , ## args } }
-#else
-#define V4L2_INIT_BT_TIMINGS(_width, args...) \
-       .bt = { _width , ## args }
-#endif
 
 /* CEA-861-E timings (i.e. standard HDTV timings) */
 
index 6612974c64bf94c93deb267d904faafab2bd1a54..29715d27548f21b20303861c24f56faeab835cc9 100644 (file)
@@ -33,6 +33,9 @@
 /* Check if EEH is supported */
 #define VFIO_EEH                       5
 
+/* Two-stage IOMMU */
+#define VFIO_TYPE1_NESTING_IOMMU       6       /* Implies v2 */
+
 /*
  * The IOCTL interface is designed for extensibility by embedding the
  * structure length (argsz) and flags into structures passed between
index 778a3298fb3441d4ab001afe7e920c249109bf83..1c2f84fd4d99b08e58d6a3dcf2c25667ad03d7e8 100644 (file)
@@ -79,6 +79,7 @@
 /*  Four-character-code (FOURCC) */
 #define v4l2_fourcc(a, b, c, d)\
        ((__u32)(a) | ((__u32)(b) << 8) | ((__u32)(c) << 16) | ((__u32)(d) << 24))
+#define v4l2_fourcc_be(a, b, c, d)     (v4l2_fourcc(a, b, c, d) | (1 << 31))
 
 /*
  *     E N U M S
@@ -307,6 +308,8 @@ struct v4l2_pix_format {
 #define V4L2_PIX_FMT_XRGB555 v4l2_fourcc('X', 'R', '1', '5') /* 16  XRGB-1-5-5-5  */
 #define V4L2_PIX_FMT_RGB565  v4l2_fourcc('R', 'G', 'B', 'P') /* 16  RGB-5-6-5     */
 #define V4L2_PIX_FMT_RGB555X v4l2_fourcc('R', 'G', 'B', 'Q') /* 16  RGB-5-5-5 BE  */
+#define V4L2_PIX_FMT_ARGB555X v4l2_fourcc_be('A', 'R', '1', '5') /* 16  ARGB-5-5-5 BE */
+#define V4L2_PIX_FMT_XRGB555X v4l2_fourcc_be('X', 'R', '1', '5') /* 16  XRGB-5-5-5 BE */
 #define V4L2_PIX_FMT_RGB565X v4l2_fourcc('R', 'G', 'B', 'R') /* 16  RGB-5-6-5 BE  */
 #define V4L2_PIX_FMT_BGR666  v4l2_fourcc('B', 'G', 'R', 'H') /* 18  BGR-6-6-6    */
 #define V4L2_PIX_FMT_BGR24   v4l2_fourcc('B', 'G', 'R', '3') /* 24  BGR-8-8-8     */
@@ -1285,11 +1288,11 @@ struct v4l2_ext_control {
        union {
                __s32 value;
                __s64 value64;
-               char *string;
-               __u8 *p_u8;
-               __u16 *p_u16;
-               __u32 *p_u32;
-               void *ptr;
+               char __user *string;
+               __u8 __user *p_u8;
+               __u16 __user *p_u16;
+               __u32 __user *p_u32;
+               void __user *ptr;
        };
 } __attribute__ ((packed));
 
diff --git a/include/uapi/misc/Kbuild b/include/uapi/misc/Kbuild
new file mode 100644 (file)
index 0000000..e96cae7
--- /dev/null
@@ -0,0 +1,2 @@
+# misc Header export list
+header-y += cxl.h
diff --git a/include/uapi/misc/cxl.h b/include/uapi/misc/cxl.h
new file mode 100644 (file)
index 0000000..cd6d789
--- /dev/null
@@ -0,0 +1,88 @@
+/*
+ * Copyright 2014 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.
+ */
+
+#ifndef _UAPI_MISC_CXL_H
+#define _UAPI_MISC_CXL_H
+
+#include <linux/types.h>
+#include <linux/ioctl.h>
+
+
+struct cxl_ioctl_start_work {
+       __u64 flags;
+       __u64 work_element_descriptor;
+       __u64 amr;
+       __s16 num_interrupts;
+       __s16 reserved1;
+       __s32 reserved2;
+       __u64 reserved3;
+       __u64 reserved4;
+       __u64 reserved5;
+       __u64 reserved6;
+};
+
+#define CXL_START_WORK_AMR             0x0000000000000001ULL
+#define CXL_START_WORK_NUM_IRQS                0x0000000000000002ULL
+#define CXL_START_WORK_ALL             (CXL_START_WORK_AMR |\
+                                        CXL_START_WORK_NUM_IRQS)
+
+/* ioctl numbers */
+#define CXL_MAGIC 0xCA
+#define CXL_IOCTL_START_WORK           _IOW(CXL_MAGIC, 0x00, struct cxl_ioctl_start_work)
+#define CXL_IOCTL_GET_PROCESS_ELEMENT  _IOR(CXL_MAGIC, 0x01, __u32)
+
+#define CXL_READ_MIN_SIZE 0x1000 /* 4K */
+
+/* Events from read() */
+enum cxl_event_type {
+       CXL_EVENT_RESERVED      = 0,
+       CXL_EVENT_AFU_INTERRUPT = 1,
+       CXL_EVENT_DATA_STORAGE  = 2,
+       CXL_EVENT_AFU_ERROR     = 3,
+};
+
+struct cxl_event_header {
+       __u16 type;
+       __u16 size;
+       __u16 process_element;
+       __u16 reserved1;
+};
+
+struct cxl_event_afu_interrupt {
+       __u16 flags;
+       __u16 irq; /* Raised AFU interrupt number */
+       __u32 reserved1;
+};
+
+struct cxl_event_data_storage {
+       __u16 flags;
+       __u16 reserved1;
+       __u32 reserved2;
+       __u64 addr;
+       __u64 dsisr;
+       __u64 reserved3;
+};
+
+struct cxl_event_afu_error {
+       __u16 flags;
+       __u16 reserved1;
+       __u32 reserved2;
+       __u64 error;
+};
+
+struct cxl_event {
+       struct cxl_event_header header;
+       union {
+               struct cxl_event_afu_interrupt irq;
+               struct cxl_event_data_storage fault;
+               struct cxl_event_afu_error afu_error;
+       };
+};
+
+#endif /* _UAPI_MISC_CXL_H */
index 32168f7ffce3ce03fe19bb8f187cfb6321710976..6ee586728df97a0fc335a3c314e0828ac970023f 100644 (file)
@@ -219,7 +219,8 @@ typedef int __bitwise snd_pcm_format_t;
 #define        SNDRV_PCM_FORMAT_G723_40_1B     ((__force snd_pcm_format_t) 47) /* 1 sample in 1 byte */
 #define        SNDRV_PCM_FORMAT_DSD_U8         ((__force snd_pcm_format_t) 48) /* DSD, 1-byte samples DSD (x8) */
 #define        SNDRV_PCM_FORMAT_DSD_U16_LE     ((__force snd_pcm_format_t) 49) /* DSD, 2-byte samples DSD (x16), little endian */
-#define        SNDRV_PCM_FORMAT_LAST           SNDRV_PCM_FORMAT_DSD_U16_LE
+#define        SNDRV_PCM_FORMAT_DSD_U32_LE     ((__force snd_pcm_format_t) 50) /* DSD, 4-byte samples DSD (x32), little endian */
+#define        SNDRV_PCM_FORMAT_LAST           SNDRV_PCM_FORMAT_DSD_U32_LE
 
 #ifdef SNDRV_LITTLE_ENDIAN
 #define        SNDRV_PCM_FORMAT_S16            SNDRV_PCM_FORMAT_S16_LE
index ef64b66b18dfbaf86809e3ec2eaad6d4f1683c70..c74bf4a0520e5860d4548713794d0985d4eb0150 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/videodev2.h>
 #include <linux/bitmap.h>
 #include <linux/fb.h>
+#include <media/v4l2-mediabus.h>
 
 struct ipu_soc;
 
@@ -61,6 +62,29 @@ struct ipu_di_signal_cfg {
        u8 vsync_pin;
 };
 
+/*
+ * Enumeration of CSI destinations
+ */
+enum ipu_csi_dest {
+       IPU_CSI_DEST_IDMAC, /* to memory via SMFC */
+       IPU_CSI_DEST_IC,        /* to Image Converter */
+       IPU_CSI_DEST_VDIC,  /* to VDIC */
+};
+
+/*
+ * Enumeration of IPU rotation modes
+ */
+enum ipu_rotate_mode {
+       IPU_ROTATE_NONE = 0,
+       IPU_ROTATE_VERT_FLIP,
+       IPU_ROTATE_HORIZ_FLIP,
+       IPU_ROTATE_180,
+       IPU_ROTATE_90_RIGHT,
+       IPU_ROTATE_90_RIGHT_VFLIP,
+       IPU_ROTATE_90_RIGHT_HFLIP,
+       IPU_ROTATE_90_LEFT,
+};
+
 enum ipu_color_space {
        IPUV3_COLORSPACE_RGB,
        IPUV3_COLORSPACE_YUV,
@@ -76,6 +100,36 @@ enum ipu_channel_irq {
        IPU_IRQ_EOS = 192,
 };
 
+/*
+ * Enumeration of IDMAC channels
+ */
+#define IPUV3_CHANNEL_CSI0                      0
+#define IPUV3_CHANNEL_CSI1                      1
+#define IPUV3_CHANNEL_CSI2                      2
+#define IPUV3_CHANNEL_CSI3                      3
+#define IPUV3_CHANNEL_VDI_MEM_IC_VF             5
+#define IPUV3_CHANNEL_MEM_IC_PP                        11
+#define IPUV3_CHANNEL_MEM_IC_PRP_VF            12
+#define IPUV3_CHANNEL_G_MEM_IC_PRP_VF          14
+#define IPUV3_CHANNEL_G_MEM_IC_PP              15
+#define IPUV3_CHANNEL_IC_PRP_ENC_MEM           20
+#define IPUV3_CHANNEL_IC_PRP_VF_MEM            21
+#define IPUV3_CHANNEL_IC_PP_MEM                        22
+#define IPUV3_CHANNEL_MEM_BG_SYNC              23
+#define IPUV3_CHANNEL_MEM_BG_ASYNC             24
+#define IPUV3_CHANNEL_MEM_FG_SYNC              27
+#define IPUV3_CHANNEL_MEM_DC_SYNC              28
+#define IPUV3_CHANNEL_MEM_FG_ASYNC             29
+#define IPUV3_CHANNEL_MEM_FG_SYNC_ALPHA                31
+#define IPUV3_CHANNEL_MEM_DC_ASYNC             41
+#define IPUV3_CHANNEL_MEM_ROT_ENC              45
+#define IPUV3_CHANNEL_MEM_ROT_VF               46
+#define IPUV3_CHANNEL_MEM_ROT_PP               47
+#define IPUV3_CHANNEL_ROT_ENC_MEM              48
+#define IPUV3_CHANNEL_ROT_VF_MEM               49
+#define IPUV3_CHANNEL_ROT_PP_MEM               50
+#define IPUV3_CHANNEL_MEM_BG_SYNC_ALPHA                51
+
 int ipu_map_irq(struct ipu_soc *ipu, int irq);
 int ipu_idmac_channel_irq(struct ipu_soc *ipu, struct ipuv3_channel *channel,
                enum ipu_channel_irq irq);
@@ -92,6 +146,13 @@ int ipu_idmac_channel_irq(struct ipu_soc *ipu, struct ipuv3_channel *channel,
 #define IPU_IRQ_VSYNC_PRE_0            (448 + 14)
 #define IPU_IRQ_VSYNC_PRE_1            (448 + 15)
 
+/*
+ * IPU Common functions
+ */
+void ipu_set_csi_src_mux(struct ipu_soc *ipu, int csi_id, bool mipi_csi2);
+void ipu_set_ic_src_mux(struct ipu_soc *ipu, int csi_id, bool vdi);
+void ipu_dump(struct ipu_soc *ipu);
+
 /*
  * IPU Image DMA Controller (idmac) functions
  */
@@ -100,12 +161,16 @@ void ipu_idmac_put(struct ipuv3_channel *);
 
 int ipu_idmac_enable_channel(struct ipuv3_channel *channel);
 int ipu_idmac_disable_channel(struct ipuv3_channel *channel);
+void ipu_idmac_enable_watermark(struct ipuv3_channel *channel, bool enable);
+int ipu_idmac_lock_enable(struct ipuv3_channel *channel, int num_bursts);
 int ipu_idmac_wait_busy(struct ipuv3_channel *channel, int ms);
 
 void ipu_idmac_set_double_buffer(struct ipuv3_channel *channel,
                bool doublebuffer);
 int ipu_idmac_get_current_buffer(struct ipuv3_channel *channel);
+bool ipu_idmac_buffer_is_ready(struct ipuv3_channel *channel, u32 buf_num);
 void ipu_idmac_select_buffer(struct ipuv3_channel *channel, u32 buf_num);
+void ipu_idmac_clear_buffer(struct ipuv3_channel *channel, u32 buf_num);
 
 /*
  * IPU Channel Parameter Memory (cpmem) functions
@@ -121,7 +186,8 @@ struct ipu_rgb {
 struct ipu_image {
        struct v4l2_pix_format pix;
        struct v4l2_rect rect;
-       dma_addr_t phys;
+       dma_addr_t phys0;
+       dma_addr_t phys1;
 };
 
 void ipu_cpmem_zero(struct ipuv3_channel *ch);
@@ -130,7 +196,11 @@ void ipu_cpmem_set_stride(struct ipuv3_channel *ch, int stride);
 void ipu_cpmem_set_high_priority(struct ipuv3_channel *ch);
 void ipu_cpmem_set_buffer(struct ipuv3_channel *ch, int bufnum, dma_addr_t buf);
 void ipu_cpmem_interlaced_scan(struct ipuv3_channel *ch, int stride);
+void ipu_cpmem_set_axi_id(struct ipuv3_channel *ch, u32 id);
 void ipu_cpmem_set_burstsize(struct ipuv3_channel *ch, int burstsize);
+void ipu_cpmem_set_block_mode(struct ipuv3_channel *ch);
+void ipu_cpmem_set_rotation(struct ipuv3_channel *ch,
+                           enum ipu_rotate_mode rot);
 int ipu_cpmem_set_format_rgb(struct ipuv3_channel *ch,
                             const struct ipu_rgb *rgb);
 int ipu_cpmem_set_format_passthrough(struct ipuv3_channel *ch, int width);
@@ -142,6 +212,7 @@ void ipu_cpmem_set_yuv_planar(struct ipuv3_channel *ch,
                              u32 pixel_format, int stride, int height);
 int ipu_cpmem_set_fmt(struct ipuv3_channel *ch, u32 drm_fourcc);
 int ipu_cpmem_set_image(struct ipuv3_channel *ch, struct ipu_image *image);
+void ipu_cpmem_dump(struct ipuv3_channel *ch);
 
 /*
  * IPU Display Controller (dc) functions
@@ -205,19 +276,78 @@ int ipu_dp_set_global_alpha(struct ipu_dp *dp, bool enable, u8 alpha,
 /*
  * IPU CMOS Sensor Interface (csi) functions
  */
-int ipu_csi_enable(struct ipu_soc *ipu, int csi);
-int ipu_csi_disable(struct ipu_soc *ipu, int csi);
+struct ipu_csi;
+int ipu_csi_init_interface(struct ipu_csi *csi,
+                          struct v4l2_mbus_config *mbus_cfg,
+                          struct v4l2_mbus_framefmt *mbus_fmt);
+bool ipu_csi_is_interlaced(struct ipu_csi *csi);
+void ipu_csi_get_window(struct ipu_csi *csi, struct v4l2_rect *w);
+void ipu_csi_set_window(struct ipu_csi *csi, struct v4l2_rect *w);
+void ipu_csi_set_test_generator(struct ipu_csi *csi, bool active,
+                               u32 r_value, u32 g_value, u32 b_value,
+                               u32 pix_clk);
+int ipu_csi_set_mipi_datatype(struct ipu_csi *csi, u32 vc,
+                             struct v4l2_mbus_framefmt *mbus_fmt);
+int ipu_csi_set_skip_smfc(struct ipu_csi *csi, u32 skip,
+                         u32 max_ratio, u32 id);
+int ipu_csi_set_dest(struct ipu_csi *csi, enum ipu_csi_dest csi_dest);
+int ipu_csi_enable(struct ipu_csi *csi);
+int ipu_csi_disable(struct ipu_csi *csi);
+struct ipu_csi *ipu_csi_get(struct ipu_soc *ipu, int id);
+void ipu_csi_put(struct ipu_csi *csi);
+void ipu_csi_dump(struct ipu_csi *csi);
+
+/*
+ * IPU Image Converter (ic) functions
+ */
+enum ipu_ic_task {
+       IC_TASK_ENCODER,
+       IC_TASK_VIEWFINDER,
+       IC_TASK_POST_PROCESSOR,
+       IC_NUM_TASKS,
+};
+
+struct ipu_ic;
+int ipu_ic_task_init(struct ipu_ic *ic,
+                    int in_width, int in_height,
+                    int out_width, int out_height,
+                    enum ipu_color_space in_cs,
+                    enum ipu_color_space out_cs);
+int ipu_ic_task_graphics_init(struct ipu_ic *ic,
+                             enum ipu_color_space in_g_cs,
+                             bool galpha_en, u32 galpha,
+                             bool colorkey_en, u32 colorkey);
+void ipu_ic_task_enable(struct ipu_ic *ic);
+void ipu_ic_task_disable(struct ipu_ic *ic);
+int ipu_ic_task_idma_init(struct ipu_ic *ic, struct ipuv3_channel *channel,
+                         u32 width, u32 height, int burst_size,
+                         enum ipu_rotate_mode rot);
+int ipu_ic_enable(struct ipu_ic *ic);
+int ipu_ic_disable(struct ipu_ic *ic);
+struct ipu_ic *ipu_ic_get(struct ipu_soc *ipu, enum ipu_ic_task task);
+void ipu_ic_put(struct ipu_ic *ic);
+void ipu_ic_dump(struct ipu_ic *ic);
 
 /*
  * IPU Sensor Multiple FIFO Controller (SMFC) functions
  */
-int ipu_smfc_enable(struct ipu_soc *ipu);
-int ipu_smfc_disable(struct ipu_soc *ipu);
-int ipu_smfc_map_channel(struct ipu_soc *ipu, int channel, int csi_id, int mipi_id);
-int ipu_smfc_set_burstsize(struct ipu_soc *ipu, int channel, int burstsize);
+struct ipu_smfc *ipu_smfc_get(struct ipu_soc *ipu, unsigned int chno);
+void ipu_smfc_put(struct ipu_smfc *smfc);
+int ipu_smfc_enable(struct ipu_smfc *smfc);
+int ipu_smfc_disable(struct ipu_smfc *smfc);
+int ipu_smfc_map_channel(struct ipu_smfc *smfc, int csi_id, int mipi_id);
+int ipu_smfc_set_burstsize(struct ipu_smfc *smfc, int burstsize);
+int ipu_smfc_set_watermark(struct ipu_smfc *smfc, u32 set_level, u32 clr_level);
 
 enum ipu_color_space ipu_drm_fourcc_to_colorspace(u32 drm_fourcc);
 enum ipu_color_space ipu_pixelformat_to_colorspace(u32 pixelformat);
+enum ipu_color_space ipu_mbus_code_to_colorspace(u32 mbus_code);
+int ipu_stride_to_bytes(u32 pixel_stride, u32 pixelformat);
+bool ipu_pixelformat_is_planar(u32 pixelformat);
+int ipu_degrees_to_rot_mode(enum ipu_rotate_mode *mode, int degrees,
+                           bool hflip, bool vflip);
+int ipu_rot_mode_to_degrees(int *degrees, enum ipu_rotate_mode mode,
+                           bool hflip, bool vflip);
 
 struct ipu_client_platformdata {
        int csi;
index 8bee7a75e85055444e7e61c0cb0c4552286dc56a..5321cd9636e6a48e0e4ad0e68fe159e2d015e7c8 100644 (file)
@@ -28,6 +28,8 @@ int bind_ipi_to_irqhandler(enum ipi_vector ipi,
                           unsigned long irqflags,
                           const char *devname,
                           void *dev_id);
+int bind_interdomain_evtchn_to_irq(unsigned int remote_domain,
+                                  unsigned int remote_port);
 int bind_interdomain_evtchn_to_irqhandler(unsigned int remote_domain,
                                          unsigned int remote_port,
                                          irq_handler_t handler,
index 6f4eae328ca74be6469e1f4247290e11f0ad8d43..f90b0345465918b6a833a73a1931d18a4de86757 100644 (file)
@@ -3,6 +3,24 @@
  *
  * Definitions used for the Xen ELF notes.
  *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * 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.
+ *
  * Copyright (c) 2006, Ian Campbell, XenSource Ltd.
  */
 
  *
  * LEGACY indicated the fields in the legacy __xen_guest string which
  * this a note type replaces.
+ *
+ * String values (for non-legacy) are NULL terminated ASCII, also known
+ * as ASCIZ type.
  */
 
 /*
  * NAME=VALUE pair (string).
- *
- * LEGACY: FEATURES and PAE
  */
 #define XEN_ELFNOTE_INFO           0
 
 
 /*
  * Whether or not the guest supports cooperative suspend cancellation.
+ * This is a numeric value.
+ *
+ * Default is 0
  */
 #define XEN_ELFNOTE_SUSPEND_CANCEL 14
 
+/*
+ * The (non-default) location the initial phys-to-machine map should be
+ * placed at by the hypervisor (Dom0) or the tools (DomU).
+ * The kernel must be prepared for this mapping to be established using
+ * large pages, despite such otherwise not being available to guests.
+ * The kernel must also be able to handle the page table pages used for
+ * this mapping not being accessible through the initial mapping.
+ * (Only x86-64 supports this at present.)
+ */
+#define XEN_ELFNOTE_INIT_P2M      15
+
+/*
+ * Whether or not the guest can deal with being passed an initrd not
+ * mapped through its initial page tables.
+ */
+#define XEN_ELFNOTE_MOD_START_PFN 16
+
 /*
  * The features supported by this kernel (numeric).
  *
  */
 #define XEN_ELFNOTE_SUPPORTED_FEATURES 17
 
+/*
+ * The number of the highest elfnote defined.
+ */
+#define XEN_ELFNOTE_MAX XEN_ELFNOTE_SUPPORTED_FEATURES
+
 #endif /* __XEN_PUBLIC_ELFNOTE_H__ */
 
 /*
diff --git a/include/xen/interface/io/vscsiif.h b/include/xen/interface/io/vscsiif.h
new file mode 100644 (file)
index 0000000..d07d7ac
--- /dev/null
@@ -0,0 +1,229 @@
+/******************************************************************************
+ * vscsiif.h
+ *
+ * Based on the blkif.h code.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * 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.
+ *
+ * Copyright(c) FUJITSU Limited 2008.
+ */
+
+#ifndef __XEN__PUBLIC_IO_SCSI_H__
+#define __XEN__PUBLIC_IO_SCSI_H__
+
+#include "ring.h"
+#include "../grant_table.h"
+
+/*
+ * Feature and Parameter Negotiation
+ * =================================
+ * The two halves of a Xen pvSCSI driver utilize nodes within the XenStore to
+ * communicate capabilities and to negotiate operating parameters.  This
+ * section enumerates these nodes which reside in the respective front and
+ * backend portions of the XenStore, following the XenBus convention.
+ *
+ * Any specified default value is in effect if the corresponding XenBus node
+ * is not present in the XenStore.
+ *
+ * XenStore nodes in sections marked "PRIVATE" are solely for use by the
+ * driver side whose XenBus tree contains them.
+ *
+ *****************************************************************************
+ *                            Backend XenBus Nodes
+ *****************************************************************************
+ *
+ *------------------ Backend Device Identification (PRIVATE) ------------------
+ *
+ * p-devname
+ *      Values:         string
+ *
+ *      A free string used to identify the physical device (e.g. a disk name).
+ *
+ * p-dev
+ *      Values:         string
+ *
+ *      A string specifying the backend device: either a 4-tuple "h:c:t:l"
+ *      (host, controller, target, lun, all integers), or a WWN (e.g.
+ *      "naa.60014054ac780582").
+ *
+ * v-dev
+ *      Values:         string
+ *
+ *      A string specifying the frontend device in form of a 4-tuple "h:c:t:l"
+ *      (host, controller, target, lun, all integers).
+ *
+ *--------------------------------- Features ---------------------------------
+ *
+ * feature-sg-grant
+ *      Values:         unsigned [VSCSIIF_SG_TABLESIZE...65535]
+ *      Default Value:  0
+ *
+ *      Specifies the maximum number of scatter/gather elements in grant pages
+ *      supported. If not set, the backend supports up to VSCSIIF_SG_TABLESIZE
+ *      SG elements specified directly in the request.
+ *
+ *****************************************************************************
+ *                            Frontend XenBus Nodes
+ *****************************************************************************
+ *
+ *----------------------- Request Transport Parameters -----------------------
+ *
+ * event-channel
+ *      Values:         unsigned
+ *
+ *      The identifier of the Xen event channel used to signal activity
+ *      in the ring buffer.
+ *
+ * ring-ref
+ *      Values:         unsigned
+ *
+ *      The Xen grant reference granting permission for the backend to map
+ *      the sole page in a single page sized ring buffer.
+ *
+ * protocol
+ *      Values:         string (XEN_IO_PROTO_ABI_*)
+ *      Default Value:  XEN_IO_PROTO_ABI_NATIVE
+ *
+ *      The machine ABI rules governing the format of all ring request and
+ *      response structures.
+ */
+
+/* Requests from the frontend to the backend */
+
+/*
+ * Request a SCSI operation specified via a CDB in vscsiif_request.cmnd.
+ * The target is specified via channel, id and lun.
+ *
+ * The operation to be performed is specified via a CDB in cmnd[], the length
+ * of the CDB is in cmd_len. sc_data_direction specifies the direction of data
+ * (to the device, from the device, or none at all).
+ *
+ * If data is to be transferred to or from the device the buffer(s) in the
+ * guest memory is/are specified via one or multiple scsiif_request_segment
+ * descriptors each specifying a memory page via a grant_ref_t, a offset into
+ * the page and the length of the area in that page. All scsiif_request_segment
+ * areas concatenated form the resulting data buffer used by the operation.
+ * If the number of scsiif_request_segment areas is not too large (less than
+ * or equal VSCSIIF_SG_TABLESIZE) the areas can be specified directly in the
+ * seg[] array and the number of valid scsiif_request_segment elements is to be
+ * set in nr_segments.
+ *
+ * If "feature-sg-grant" in the Xenstore is set it is possible to specify more
+ * than VSCSIIF_SG_TABLESIZE scsiif_request_segment elements via indirection.
+ * The maximum number of allowed scsiif_request_segment elements is the value
+ * of the "feature-sg-grant" entry from Xenstore. When using indirection the
+ * seg[] array doesn't contain specifications of the data buffers, but
+ * references to scsiif_request_segment arrays, which in turn reference the
+ * data buffers. While nr_segments holds the number of populated seg[] entries
+ * (plus the set VSCSIIF_SG_GRANT bit), the number of scsiif_request_segment
+ * elements referencing the target data buffers is calculated from the lengths
+ * of the seg[] elements (the sum of all valid seg[].length divided by the
+ * size of one scsiif_request_segment structure).
+ */
+#define VSCSIIF_ACT_SCSI_CDB           1
+
+/*
+ * Request abort of a running operation for the specified target given by
+ * channel, id, lun and the operation's rqid in ref_rqid.
+ */
+#define VSCSIIF_ACT_SCSI_ABORT         2
+
+/*
+ * Request a device reset of the specified target (channel and id).
+ */
+#define VSCSIIF_ACT_SCSI_RESET         3
+
+/*
+ * Preset scatter/gather elements for a following request. Deprecated.
+ * Keeping the define only to avoid usage of the value "4" for other actions.
+ */
+#define VSCSIIF_ACT_SCSI_SG_PRESET     4
+
+/*
+ * Maximum scatter/gather segments per request.
+ *
+ * Considering balance between allocating at least 16 "vscsiif_request"
+ * structures on one page (4096 bytes) and the number of scatter/gather
+ * elements needed, we decided to use 26 as a magic number.
+ *
+ * If "feature-sg-grant" is set, more scatter/gather elements can be specified
+ * by placing them in one or more (up to VSCSIIF_SG_TABLESIZE) granted pages.
+ * In this case the vscsiif_request seg elements don't contain references to
+ * the user data, but to the SG elements referencing the user data.
+ */
+#define VSCSIIF_SG_TABLESIZE           26
+
+/*
+ * based on Linux kernel 2.6.18, still valid
+ * Changing these values requires support of multiple protocols via the rings
+ * as "old clients" will blindly use these values and the resulting structure
+ * sizes.
+ */
+#define VSCSIIF_MAX_COMMAND_SIZE       16
+#define VSCSIIF_SENSE_BUFFERSIZE       96
+
+struct scsiif_request_segment {
+       grant_ref_t gref;
+       uint16_t offset;
+       uint16_t length;
+};
+
+#define VSCSIIF_SG_PER_PAGE (PAGE_SIZE / sizeof(struct scsiif_request_segment))
+
+/* Size of one request is 252 bytes */
+struct vscsiif_request {
+       uint16_t rqid;          /* private guest value, echoed in resp  */
+       uint8_t act;            /* command between backend and frontend */
+       uint8_t cmd_len;        /* valid CDB bytes */
+
+       uint8_t cmnd[VSCSIIF_MAX_COMMAND_SIZE]; /* the CDB */
+       uint16_t timeout_per_command;   /* deprecated */
+       uint16_t channel, id, lun;      /* (virtual) device specification */
+       uint16_t ref_rqid;              /* command abort reference */
+       uint8_t sc_data_direction;      /* for DMA_TO_DEVICE(1)
+                                          DMA_FROM_DEVICE(2)
+                                          DMA_NONE(3) requests */
+       uint8_t nr_segments;            /* Number of pieces of scatter-gather */
+/*
+ * flag in nr_segments: SG elements via grant page
+ *
+ * If VSCSIIF_SG_GRANT is set, the low 7 bits of nr_segments specify the number
+ * of grant pages containing SG elements. Usable if "feature-sg-grant" set.
+ */
+#define VSCSIIF_SG_GRANT       0x80
+
+       struct scsiif_request_segment seg[VSCSIIF_SG_TABLESIZE];
+       uint32_t reserved[3];
+};
+
+/* Size of one response is 252 bytes */
+struct vscsiif_response {
+       uint16_t rqid;          /* identifies request */
+       uint8_t padding;
+       uint8_t sense_len;
+       uint8_t sense_buffer[VSCSIIF_SENSE_BUFFERSIZE];
+       int32_t rslt;
+       uint32_t residual_len;  /* request bufflen -
+                                  return the value from physical device */
+       uint32_t reserved[36];
+};
+
+DEFINE_RING_TYPES(vscsiif, struct vscsiif_request, struct vscsiif_response);
+
+#endif /*__XEN__PUBLIC_IO_SCSI_H__*/
index de082130ba4b3913b51ff1ddfdf9bbfef153ad6b..f68719f405af6b891ae45bac290650186b0b3e35 100644 (file)
@@ -3,6 +3,24 @@
  *
  * Guest OS interface to Xen.
  *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * 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.
+ *
  * Copyright (c) 2004, K A Fraser
  */
 
  * VIRTUAL INTERRUPTS
  *
  * Virtual interrupts that a guest OS may receive from Xen.
+ * In the side comments, 'V.' denotes a per-VCPU VIRQ while 'G.' denotes a
+ * global VIRQ. The former can be bound once per VCPU and cannot be re-bound.
+ * The latter can be allocated only once per guest: they must initially be
+ * allocated to VCPU0 but can subsequently be re-bound.
  */
-#define VIRQ_TIMER      0  /* Timebase update, and/or requested timeout.  */
-#define VIRQ_DEBUG      1  /* Request guest to dump debug info.           */
-#define VIRQ_CONSOLE    2  /* (DOM0) Bytes received on emergency console. */
-#define VIRQ_DOM_EXC    3  /* (DOM0) Exceptional event for some domain.   */
-#define VIRQ_DEBUGGER   6  /* (DOM0) A domain has paused for debugging.   */
-#define VIRQ_PCPU_STATE 9  /* (DOM0) PCPU state changed                   */
+#define VIRQ_TIMER      0  /* V. Timebase update, and/or requested timeout.  */
+#define VIRQ_DEBUG      1  /* V. Request guest to dump debug info.           */
+#define VIRQ_CONSOLE    2  /* G. (DOM0) Bytes received on emergency console. */
+#define VIRQ_DOM_EXC    3  /* G. (DOM0) Exceptional event for some domain.   */
+#define VIRQ_TBUF       4  /* G. (DOM0) Trace buffer has records available.  */
+#define VIRQ_DEBUGGER   6  /* G. (DOM0) A domain has paused for debugging.   */
+#define VIRQ_XENOPROF   7  /* V. XenOprofile interrupt: new sample available */
+#define VIRQ_CON_RING   8  /* G. (DOM0) Bytes received on console            */
+#define VIRQ_PCPU_STATE 9  /* G. (DOM0) PCPU state changed                   */
+#define VIRQ_MEM_EVENT  10 /* G. (DOM0) A memory event has occured           */
+#define VIRQ_XC_RESERVED 11 /* G. Reserved for XenClient                     */
+#define VIRQ_ENOMEM     12 /* G. (DOM0) Low on heap memory       */
 
 /* Architecture-specific VIRQ definitions. */
 #define VIRQ_ARCH_0    16
 #define VIRQ_ARCH_7    23
 
 #define NR_VIRQS       24
+
 /*
- * MMU-UPDATE REQUESTS
- *
- * HYPERVISOR_mmu_update() accepts a list of (ptr, val) pairs.
- * A foreigndom (FD) can be specified (or DOMID_SELF for none).
- * Where the FD has some effect, it is described below.
- * ptr[1:0] specifies the appropriate MMU_* command.
+ * enum neg_errnoval HYPERVISOR_mmu_update(const struct mmu_update reqs[],
+ *                                         unsigned count, unsigned *done_out,
+ *                                         unsigned foreigndom)
+ * @reqs is an array of mmu_update_t structures ((ptr, val) pairs).
+ * @count is the length of the above array.
+ * @pdone is an output parameter indicating number of completed operations
+ * @foreigndom[15:0]: FD, the expected owner of data pages referenced in this
+ *                    hypercall invocation. Can be DOMID_SELF.
+ * @foreigndom[31:16]: PFD, the expected owner of pagetable pages referenced
+ *                     in this hypercall invocation. The value of this field
+ *                     (x) encodes the PFD as follows:
+ *                     x == 0 => PFD == DOMID_SELF
+ *                     x != 0 => PFD == x - 1
  *
+ * Sub-commands: ptr[1:0] specifies the appropriate MMU_* command.
+ * -------------
  * ptr[1:0] == MMU_NORMAL_PT_UPDATE:
- * Updates an entry in a page table. If updating an L1 table, and the new
- * table entry is valid/present, the mapped frame must belong to the FD, if
- * an FD has been specified. If attempting to map an I/O page then the
- * caller assumes the privilege of the FD.
+ * Updates an entry in a page table belonging to PFD. If updating an L1 table,
+ * and the new table entry is valid/present, the mapped frame must belong to
+ * FD. If attempting to map an I/O page then the caller assumes the privilege
+ * of the FD.
  * FD == DOMID_IO: Permit /only/ I/O mappings, at the priv level of the caller.
  * FD == DOMID_XEN: Map restricted areas of Xen's heap space.
  * ptr[:2]  -- Machine address of the page-table entry to modify.
  * val      -- Value to write.
  *
+ * There also certain implicit requirements when using this hypercall. The
+ * pages that make up a pagetable must be mapped read-only in the guest.
+ * This prevents uncontrolled guest updates to the pagetable. Xen strictly
+ * enforces this, and will disallow any pagetable update which will end up
+ * mapping pagetable page RW, and will disallow using any writable page as a
+ * pagetable. In practice it means that when constructing a page table for a
+ * process, thread, etc, we MUST be very dilligient in following these rules:
+ *  1). Start with top-level page (PGD or in Xen language: L4). Fill out
+ *      the entries.
+ *  2). Keep on going, filling out the upper (PUD or L3), and middle (PMD
+ *      or L2).
+ *  3). Start filling out the PTE table (L1) with the PTE entries. Once
+ *      done, make sure to set each of those entries to RO (so writeable bit
+ *      is unset). Once that has been completed, set the PMD (L2) for this
+ *      PTE table as RO.
+ *  4). When completed with all of the PMD (L2) entries, and all of them have
+ *      been set to RO, make sure to set RO the PUD (L3). Do the same
+ *      operation on PGD (L4) pagetable entries that have a PUD (L3) entry.
+ *  5). Now before you can use those pages (so setting the cr3), you MUST also
+ *      pin them so that the hypervisor can verify the entries. This is done
+ *      via the HYPERVISOR_mmuext_op(MMUEXT_PIN_L4_TABLE, guest physical frame
+ *      number of the PGD (L4)). And this point the HYPERVISOR_mmuext_op(
+ *      MMUEXT_NEW_BASEPTR, guest physical frame number of the PGD (L4)) can be
+ *      issued.
+ * For 32-bit guests, the L4 is not used (as there is less pagetables), so
+ * instead use L3.
+ * At this point the pagetables can be modified using the MMU_NORMAL_PT_UPDATE
+ * hypercall. Also if so desired the OS can also try to write to the PTE
+ * and be trapped by the hypervisor (as the PTE entry is RO).
+ *
+ * To deallocate the pages, the operations are the reverse of the steps
+ * mentioned above. The argument is MMUEXT_UNPIN_TABLE for all levels and the
+ * pagetable MUST not be in use (meaning that the cr3 is not set to it).
+ *
  * ptr[1:0] == MMU_MACHPHYS_UPDATE:
  * Updates an entry in the machine->pseudo-physical mapping table.
  * ptr[:2]  -- Machine address within the frame whose mapping to modify.
  * ptr[1:0] == MMU_PT_UPDATE_PRESERVE_AD:
  * As MMU_NORMAL_PT_UPDATE above, but A/D bits currently in the PTE are ORed
  * with those in @val.
+ *
+ * @val is usually the machine frame number along with some attributes.
+ * The attributes by default follow the architecture defined bits. Meaning that
+ * if this is a X86_64 machine and four page table layout is used, the layout
+ * of val is:
+ *  - 63 if set means No execute (NX)
+ *  - 46-13 the machine frame number
+ *  - 12 available for guest
+ *  - 11 available for guest
+ *  - 10 available for guest
+ *  - 9 available for guest
+ *  - 8 global
+ *  - 7 PAT (PSE is disabled, must use hypercall to make 4MB or 2MB pages)
+ *  - 6 dirty
+ *  - 5 accessed
+ *  - 4 page cached disabled
+ *  - 3 page write through
+ *  - 2 userspace accessible
+ *  - 1 writeable
+ *  - 0 present
+ *
+ *  The one bits that does not fit with the default layout is the PAGE_PSE
+ *  also called PAGE_PAT). The MMUEXT_[UN]MARK_SUPER arguments to the
+ *  HYPERVISOR_mmuext_op serve as mechanism to set a pagetable to be 4MB
+ *  (or 2MB) instead of using the PAGE_PSE bit.
+ *
+ *  The reason that the PAGE_PSE (bit 7) is not being utilized is due to Xen
+ *  using it as the Page Attribute Table (PAT) bit - for details on it please
+ *  refer to Intel SDM 10.12. The PAT allows to set the caching attributes of
+ *  pages instead of using MTRRs.
+ *
+ *  The PAT MSR is as follows (it is a 64-bit value, each entry is 8 bits):
+ *                    PAT4                 PAT0
+ *  +-----+-----+----+----+----+-----+----+----+
+ *  | UC  | UC- | WC | WB | UC | UC- | WC | WB |  <= Linux
+ *  +-----+-----+----+----+----+-----+----+----+
+ *  | UC  | UC- | WT | WB | UC | UC- | WT | WB |  <= BIOS (default when machine boots)
+ *  +-----+-----+----+----+----+-----+----+----+
+ *  | rsv | rsv | WP | WC | UC | UC- | WT | WB |  <= Xen
+ *  +-----+-----+----+----+----+-----+----+----+
+ *
+ *  The lookup of this index table translates to looking up
+ *  Bit 7, Bit 4, and Bit 3 of val entry:
+ *
+ *  PAT/PSE (bit 7) ... PCD (bit 4) .. PWT (bit 3).
+ *
+ *  If all bits are off, then we are using PAT0. If bit 3 turned on,
+ *  then we are using PAT1, if bit 3 and bit 4, then PAT2..
+ *
+ *  As you can see, the Linux PAT1 translates to PAT4 under Xen. Which means
+ *  that if a guest that follows Linux's PAT setup and would like to set Write
+ *  Combined on pages it MUST use PAT4 entry. Meaning that Bit 7 (PAGE_PAT) is
+ *  set. For example, under Linux it only uses PAT0, PAT1, and PAT2 for the
+ *  caching as:
+ *
+ *   WB = none (so PAT0)
+ *   WC = PWT (bit 3 on)
+ *   UC = PWT | PCD (bit 3 and 4 are on).
+ *
+ * To make it work with Xen, it needs to translate the WC bit as so:
+ *
+ *  PWT (so bit 3 on) --> PAT (so bit 7 is on) and clear bit 3
+ *
+ * And to translate back it would:
+ *
+ * PAT (bit 7 on) --> PWT (bit 3 on) and clear bit 7.
  */
 #define MMU_NORMAL_PT_UPDATE      0 /* checked '*ptr = val'. ptr is MA.       */
 #define MMU_MACHPHYS_UPDATE       1 /* ptr = MA of frame to modify entry for  */
 /*
  * MMU EXTENDED OPERATIONS
  *
- * HYPERVISOR_mmuext_op() accepts a list of mmuext_op structures.
+ * enum neg_errnoval HYPERVISOR_mmuext_op(mmuext_op_t uops[],
+ *                                        unsigned int count,
+ *                                        unsigned int *pdone,
+ *                                        unsigned int foreigndom)
+ */
+/* HYPERVISOR_mmuext_op() accepts a list of mmuext_op structures.
  * A foreigndom (FD) can be specified (or DOMID_SELF for none).
  * Where the FD has some effect, it is described below.
  *
  * cmd: MMUEXT_FLUSH_CACHE
  * No additional arguments. Writes back and flushes cache contents.
  *
+ * cmd: MMUEXT_FLUSH_CACHE_GLOBAL
+ * No additional arguments. Writes back and flushes cache contents
+ * on all CPUs in the system.
+ *
  * cmd: MMUEXT_SET_LDT
  * linear_addr: Linear address of LDT base (NB. must be page-aligned).
  * nr_ents: Number of entries in LDT.
+ *
+ * cmd: MMUEXT_CLEAR_PAGE
+ * mfn: Machine frame number to be cleared.
+ *
+ * cmd: MMUEXT_COPY_PAGE
+ * mfn: Machine frame number of the destination page.
+ * src_mfn: Machine frame number of the source page.
+ *
+ * cmd: MMUEXT_[UN]MARK_SUPER
+ * mfn: Machine frame number of head of superpage to be [un]marked.
  */
 #define MMUEXT_PIN_L1_TABLE      0
 #define MMUEXT_PIN_L2_TABLE      1
 #define MMUEXT_FLUSH_CACHE      12
 #define MMUEXT_SET_LDT          13
 #define MMUEXT_NEW_USER_BASEPTR 15
+#define MMUEXT_CLEAR_PAGE       16
+#define MMUEXT_COPY_PAGE        17
+#define MMUEXT_FLUSH_CACHE_GLOBAL 18
+#define MMUEXT_MARK_SUPER       19
+#define MMUEXT_UNMARK_SUPER     20
 
 #ifndef __ASSEMBLY__
 struct mmuext_op {
        unsigned int cmd;
        union {
-               /* [UN]PIN_TABLE, NEW_BASEPTR, NEW_USER_BASEPTR */
+               /* [UN]PIN_TABLE, NEW_BASEPTR, NEW_USER_BASEPTR
+                * CLEAR_PAGE, COPY_PAGE, [UN]MARK_SUPER */
                xen_pfn_t mfn;
                /* INVLPG_LOCAL, INVLPG_ALL, SET_LDT */
                unsigned long linear_addr;
@@ -198,6 +361,8 @@ struct mmuext_op {
                unsigned int nr_ents;
                /* TLB_FLUSH_MULTI, INVLPG_MULTI */
                void *vcpumask;
+               /* COPY_PAGE */
+               xen_pfn_t src_mfn;
        } arg2;
 };
 DEFINE_GUEST_HANDLE_STRUCT(mmuext_op);
@@ -225,10 +390,23 @@ DEFINE_GUEST_HANDLE_STRUCT(mmuext_op);
  */
 #define VMASST_CMD_enable                0
 #define VMASST_CMD_disable               1
+
+/* x86/32 guests: simulate full 4GB segment limits. */
 #define VMASST_TYPE_4gb_segments         0
+
+/* x86/32 guests: trap (vector 15) whenever above vmassist is used. */
 #define VMASST_TYPE_4gb_segments_notify  1
+
+/*
+ * x86 guests: support writes to bottom-level PTEs.
+ * NB1. Page-directory entries cannot be written.
+ * NB2. Guest must continue to remove all writable mappings of PTEs.
+ */
 #define VMASST_TYPE_writable_pagetables  2
+
+/* x86/PAE guests: support PDPTs above 4GB. */
 #define VMASST_TYPE_pae_extended_cr3     3
+
 #define MAX_VMASST_TYPE 3
 
 #ifndef __ASSEMBLY__
@@ -260,6 +438,15 @@ typedef uint16_t domid_t;
  */
 #define DOMID_XEN  (0x7FF2U)
 
+/* DOMID_COW is used as the owner of sharable pages */
+#define DOMID_COW  (0x7FF3U)
+
+/* DOMID_INVALID is used to identify pages with unknown owner. */
+#define DOMID_INVALID (0x7FF4U)
+
+/* Idle domain. */
+#define DOMID_IDLE (0x7FFFU)
+
 /*
  * Send an array of these to HYPERVISOR_mmu_update().
  * NB. The fields are natural pointer/address size for this architecture.
@@ -272,7 +459,9 @@ DEFINE_GUEST_HANDLE_STRUCT(mmu_update);
 
 /*
  * Send an array of these to HYPERVISOR_multicall().
- * NB. The fields are natural register size for this architecture.
+ * NB. The fields are logically the natural register size for this
+ * architecture. In cases where xen_ulong_t is larger than this then
+ * any unused bits in the upper portion must be zero.
  */
 struct multicall_entry {
     xen_ulong_t op;
@@ -442,8 +631,48 @@ struct start_info {
        unsigned long mod_start;    /* VIRTUAL address of pre-loaded module.  */
        unsigned long mod_len;      /* Size (bytes) of pre-loaded module.     */
        int8_t cmd_line[MAX_GUEST_CMDLINE];
+       /* The pfn range here covers both page table and p->m table frames.   */
+       unsigned long first_p2m_pfn;/* 1st pfn forming initial P->M table.    */
+       unsigned long nr_p2m_frames;/* # of pfns forming initial P->M table.  */
 };
 
+/* These flags are passed in the 'flags' field of start_info_t. */
+#define SIF_PRIVILEGED    (1<<0)  /* Is the domain privileged? */
+#define SIF_INITDOMAIN    (1<<1)  /* Is this the initial control domain? */
+#define SIF_MULTIBOOT_MOD (1<<2)  /* Is mod_start a multiboot module? */
+#define SIF_MOD_START_PFN (1<<3)  /* Is mod_start a PFN? */
+#define SIF_PM_MASK       (0xFF<<8) /* reserve 1 byte for xen-pm options */
+
+/*
+ * A multiboot module is a package containing modules very similar to a
+ * multiboot module array. The only differences are:
+ * - the array of module descriptors is by convention simply at the beginning
+ *   of the multiboot module,
+ * - addresses in the module descriptors are based on the beginning of the
+ *   multiboot module,
+ * - the number of modules is determined by a termination descriptor that has
+ *   mod_start == 0.
+ *
+ * This permits to both build it statically and reference it in a configuration
+ * file, and let the PV guest easily rebase the addresses to virtual addresses
+ * and at the same time count the number of modules.
+ */
+struct xen_multiboot_mod_list {
+       /* Address of first byte of the module */
+       uint32_t mod_start;
+       /* Address of last byte of the module (inclusive) */
+       uint32_t mod_end;
+       /* Address of zero-terminated command line */
+       uint32_t cmdline;
+       /* Unused, must be zero */
+       uint32_t pad;
+};
+/*
+ * The console structure in start_info.console.dom0
+ *
+ * This structure includes a variety of information required to
+ * have a working VGA/VESA console.
+ */
 struct dom0_vga_console_info {
        uint8_t video_type;
 #define XEN_VGATYPE_TEXT_MODE_3 0x03
@@ -484,11 +713,6 @@ struct dom0_vga_console_info {
        } u;
 };
 
-/* These flags are passed in the 'flags' field of start_info_t. */
-#define SIF_PRIVILEGED    (1<<0)  /* Is the domain privileged? */
-#define SIF_INITDOMAIN    (1<<1)  /* Is this the initial control domain? */
-#define SIF_PM_MASK       (0xFF<<8) /* reserve 1 byte for xen-pm options */
-
 typedef uint64_t cpumap_t;
 
 typedef uint8_t xen_domain_handle_t[16];
index 0324c6d340c19df3ef67d03b3307ce8ac082730c..b78f21caf55aa074d3f883d0a0269f1c7d268339 100644 (file)
@@ -86,6 +86,7 @@ struct xenbus_device_id
 
 /* A xenbus driver. */
 struct xenbus_driver {
+       const char *name;       /* defaults to ids[0].devicetype */
        const struct xenbus_device_id *ids;
        int (*probe)(struct xenbus_device *dev,
                     const struct xenbus_device_id *id);
@@ -100,20 +101,22 @@ struct xenbus_driver {
        int (*is_ready)(struct xenbus_device *dev);
 };
 
-#define DEFINE_XENBUS_DRIVER(var, drvname, methods...)         \
-struct xenbus_driver var ## _driver = {                                \
-       .driver.name = drvname + 0 ?: var ## _ids->devicetype,  \
-       .driver.owner = THIS_MODULE,                            \
-       .ids = var ## _ids, ## methods                          \
-}
-
 static inline struct xenbus_driver *to_xenbus_driver(struct device_driver *drv)
 {
        return container_of(drv, struct xenbus_driver, driver);
 }
 
-int __must_check xenbus_register_frontend(struct xenbus_driver *);
-int __must_check xenbus_register_backend(struct xenbus_driver *);
+int __must_check __xenbus_register_frontend(struct xenbus_driver *drv,
+                                           struct module *owner,
+                                           const char *mod_name);
+int __must_check __xenbus_register_backend(struct xenbus_driver *drv,
+                                          struct module *owner,
+                                          const char *mod_name);
+
+#define xenbus_register_frontend(drv) \
+       __xenbus_register_frontend(drv, THIS_MODULE, KBUILD_MODNAME);
+#define xenbus_register_backend(drv) \
+       __xenbus_register_backend(drv, THIS_MODULE, KBUILD_MODNAME);
 
 void xenbus_unregister_driver(struct xenbus_driver *drv);
 
index d2355812ba48a7e1f52855ad9c431878ee32f175..3ee28ae02cc89cb0c0d3b2a9ca112c1edfda2e96 100644 (file)
@@ -507,6 +507,16 @@ config PREEMPT_RCU
          This option enables preemptible-RCU code that is common between
          TREE_PREEMPT_RCU and, in the old days, TINY_PREEMPT_RCU.
 
+config TASKS_RCU
+       bool "Task_based RCU implementation using voluntary context switch"
+       default n
+       help
+         This option enables a task-based RCU implementation that uses
+         only voluntary context switch (not preemption!), idle, and
+         user-mode execution as quiescent states.
+
+         If unsure, say N.
+
 config RCU_STALL_COMMON
        def_bool ( TREE_RCU || TREE_PREEMPT_RCU || RCU_TRACE )
        help
@@ -737,7 +747,7 @@ choice
 
 config RCU_NOCB_CPU_NONE
        bool "No build_forced no-CBs CPUs"
-       depends on RCU_NOCB_CPU && !NO_HZ_FULL_ALL
+       depends on RCU_NOCB_CPU
        help
          This option does not force any of the CPUs to be no-CBs CPUs.
          Only CPUs designated by the rcu_nocbs= boot parameter will be
@@ -751,7 +761,7 @@ config RCU_NOCB_CPU_NONE
 
 config RCU_NOCB_CPU_ZERO
        bool "CPU 0 is a build_forced no-CBs CPU"
-       depends on RCU_NOCB_CPU && !NO_HZ_FULL_ALL
+       depends on RCU_NOCB_CPU
        help
          This option forces CPU 0 to be a no-CBs CPU, so that its RCU
          callbacks are invoked by a per-CPU kthread whose name begins
@@ -828,6 +838,7 @@ config LOG_BUF_SHIFT
 
 config LOG_CPU_MAX_BUF_SHIFT
        int "CPU kernel log buffer size contribution (13 => 8 KB, 17 => 128KB)"
+       depends on SMP
        range 0 21
        default 12 if !BASE_SMALL
        default 0 if BASE_SMALL
index bece48c3461edd55ba4a9ea5fc1b8662be6bda0f..ad1bd7787bbb0c3298e2f9790b0edd5322227639 100644 (file)
@@ -197,14 +197,14 @@ static __initdata enum state {
 } state, next_state;
 
 static __initdata char *victim;
-static unsigned long count __initdata;
+static unsigned long byte_count __initdata;
 static __initdata loff_t this_header, next_header;
 
 static inline void __init eat(unsigned n)
 {
        victim += n;
        this_header += n;
-       count -= n;
+       byte_count -= n;
 }
 
 static __initdata char *vcollected;
@@ -214,7 +214,7 @@ static __initdata char *collect;
 
 static void __init read_into(char *buf, unsigned size, enum state next)
 {
-       if (count >= size) {
+       if (byte_count >= size) {
                collected = victim;
                eat(size);
                state = next;
@@ -237,8 +237,8 @@ static int __init do_start(void)
 static int __init do_collect(void)
 {
        unsigned long n = remains;
-       if (count < n)
-               n = count;
+       if (byte_count < n)
+               n = byte_count;
        memcpy(collect, victim, n);
        eat(n);
        collect += n;
@@ -280,8 +280,8 @@ static int __init do_header(void)
 
 static int __init do_skip(void)
 {
-       if (this_header + count < next_header) {
-               eat(count);
+       if (this_header + byte_count < next_header) {
+               eat(byte_count);
                return 1;
        } else {
                eat(next_header - this_header);
@@ -292,9 +292,9 @@ static int __init do_skip(void)
 
 static int __init do_reset(void)
 {
-       while(count && *victim == '\0')
+       while (byte_count && *victim == '\0')
                eat(1);
-       if (count && (this_header & 3))
+       if (byte_count && (this_header & 3))
                error("broken padding");
        return 1;
 }
@@ -309,11 +309,11 @@ static int __init maybe_link(void)
        return 0;
 }
 
-static void __init clean_path(char *path, umode_t mode)
+static void __init clean_path(char *path, umode_t fmode)
 {
        struct stat st;
 
-       if (!sys_newlstat(path, &st) && (st.st_mode^mode) & S_IFMT) {
+       if (!sys_newlstat(path, &st) && (st.st_mode ^ fmode) & S_IFMT) {
                if (S_ISDIR(st.st_mode))
                        sys_rmdir(path);
                else
@@ -368,7 +368,7 @@ static int __init do_name(void)
 
 static int __init do_copy(void)
 {
-       if (count >= body_len) {
+       if (byte_count >= body_len) {
                if (xwrite(wfd, victim, body_len) != body_len)
                        error("write error");
                sys_close(wfd);
@@ -378,10 +378,10 @@ static int __init do_copy(void)
                state = SkipIt;
                return 0;
        } else {
-               if (xwrite(wfd, victim, count) != count)
+               if (xwrite(wfd, victim, byte_count) != byte_count)
                        error("write error");
-               body_len -= count;
-               eat(count);
+               body_len -= byte_count;
+               eat(byte_count);
                return 1;
        }
 }
@@ -411,12 +411,12 @@ static __initdata int (*actions[])(void) = {
 
 static long __init write_buffer(char *buf, unsigned long len)
 {
-       count = len;
+       byte_count = len;
        victim = buf;
 
        while (!actions[state]())
                ;
-       return len - count;
+       return len - byte_count;
 }
 
 static long __init flush_buffer(void *bufv, unsigned long len)
index 8af2f1abfe38d5f36eade88169f4f9cd04d8ec5a..800a0daede7e4d8b8940288bd30dfb43a6e922a8 100644 (file)
@@ -501,13 +501,13 @@ asmlinkage __visible void __init start_kernel(void)
 {
        char *command_line;
        char *after_dashes;
-       extern const struct kernel_param __start___param[], __stop___param[];
 
        /*
         * Need to run as early as possible, to initialize the
         * lockdep hash:
         */
        lockdep_init();
+       set_task_stack_end_magic(&init_task);
        smp_setup_processor_id();
        debug_objects_early_init();
 
@@ -583,6 +583,7 @@ asmlinkage __visible void __init start_kernel(void)
        early_irq_init();
        init_IRQ();
        tick_init();
+       rcu_init_nohz();
        init_timers();
        hrtimers_init();
        softirq_init();
@@ -842,7 +843,6 @@ static char *initcall_level_names[] __initdata = {
 
 static void __init do_initcall_level(int level)
 {
-       extern const struct kernel_param __start___param[], __stop___param[];
        initcall_t *fn;
 
        strcpy(initcall_command_line, saved_command_line);
index b5ef4f7946dca3a155b0788993c66512afc8fc4b..9b3c85f8a53825330b99015e34af9d2117393f06 100644 (file)
@@ -171,32 +171,32 @@ static inline int __put_compat_ipc64_perm(struct ipc64_perm *p64,
 }
 
 static inline int __put_compat_ipc_perm(struct ipc64_perm *p,
-                                       struct compat_ipc_perm __user *up)
+                                       struct compat_ipc_perm __user *uip)
 {
        int err;
        __compat_uid_t u;
        __compat_gid_t g;
 
-       err  = __put_user(p->key, &up->key);
+       err  = __put_user(p->key, &uip->key);
        SET_UID(u, p->uid);
-       err |= __put_user(u, &up->uid);
+       err |= __put_user(u, &uip->uid);
        SET_GID(g, p->gid);
-       err |= __put_user(g, &up->gid);
+       err |= __put_user(g, &uip->gid);
        SET_UID(u, p->cuid);
-       err |= __put_user(u, &up->cuid);
+       err |= __put_user(u, &uip->cuid);
        SET_GID(g, p->cgid);
-       err |= __put_user(g, &up->cgid);
-       err |= __put_user(p->mode, &up->mode);
-       err |= __put_user(p->seq, &up->seq);
+       err |= __put_user(g, &uip->cgid);
+       err |= __put_user(p->mode, &uip->mode);
+       err |= __put_user(p->seq, &uip->seq);
        return err;
 }
 
-static inline int get_compat_semid64_ds(struct semid64_ds *s64,
+static inline int get_compat_semid64_ds(struct semid64_ds *sem64,
                                        struct compat_semid64_ds __user *up64)
 {
        if (!access_ok(VERIFY_READ, up64, sizeof(*up64)))
                return -EFAULT;
-       return __get_compat_ipc64_perm(&s64->sem_perm, &up64->sem_perm);
+       return __get_compat_ipc64_perm(&sem64->sem_perm, &up64->sem_perm);
 }
 
 static inline int get_compat_semid_ds(struct semid64_ds *s,
@@ -207,17 +207,17 @@ static inline int get_compat_semid_ds(struct semid64_ds *s,
        return __get_compat_ipc_perm(&s->sem_perm, &up->sem_perm);
 }
 
-static inline int put_compat_semid64_ds(struct semid64_ds *s64,
+static inline int put_compat_semid64_ds(struct semid64_ds *sem64,
                                        struct compat_semid64_ds __user *up64)
 {
        int err;
 
        if (!access_ok(VERIFY_WRITE, up64, sizeof(*up64)))
                return -EFAULT;
-       err  = __put_compat_ipc64_perm(&s64->sem_perm, &up64->sem_perm);
-       err |= __put_user(s64->sem_otime, &up64->sem_otime);
-       err |= __put_user(s64->sem_ctime, &up64->sem_ctime);
-       err |= __put_user(s64->sem_nsems, &up64->sem_nsems);
+       err  = __put_compat_ipc64_perm(&sem64->sem_perm, &up64->sem_perm);
+       err |= __put_user(sem64->sem_otime, &up64->sem_otime);
+       err |= __put_user(sem64->sem_ctime, &up64->sem_ctime);
+       err |= __put_user(sem64->sem_nsems, &up64->sem_nsems);
        return err;
 }
 
@@ -239,11 +239,11 @@ static long do_compat_semctl(int first, int second, int third, u32 pad)
 {
        unsigned long fourth;
        int err, err2;
-       struct semid64_ds s64;
+       struct semid64_ds sem64;
        struct semid64_ds __user *up64;
        int version = compat_ipc_parse_version(&third);
 
-       memset(&s64, 0, sizeof(s64));
+       memset(&sem64, 0, sizeof(sem64));
 
        if ((third & (~IPC_64)) == SETVAL)
 #ifdef __BIG_ENDIAN
@@ -269,29 +269,29 @@ static long do_compat_semctl(int first, int second, int third, u32 pad)
 
        case IPC_STAT:
        case SEM_STAT:
-               up64 = compat_alloc_user_space(sizeof(s64));
+               up64 = compat_alloc_user_space(sizeof(sem64));
                fourth = (unsigned long)up64;
                err = sys_semctl(first, second, third, fourth);
                if (err < 0)
                        break;
-               if (copy_from_user(&s64, up64, sizeof(s64)))
+               if (copy_from_user(&sem64, up64, sizeof(sem64)))
                        err2 = -EFAULT;
                else if (version == IPC_64)
-                       err2 = put_compat_semid64_ds(&s64, compat_ptr(pad));
+                       err2 = put_compat_semid64_ds(&sem64, compat_ptr(pad));
                else
-                       err2 = put_compat_semid_ds(&s64, compat_ptr(pad));
+                       err2 = put_compat_semid_ds(&sem64, compat_ptr(pad));
                if (err2)
                        err = -EFAULT;
                break;
 
        case IPC_SET:
                if (version == IPC_64)
-                       err = get_compat_semid64_ds(&s64, compat_ptr(pad));
+                       err = get_compat_semid64_ds(&sem64, compat_ptr(pad));
                else
-                       err = get_compat_semid_ds(&s64, compat_ptr(pad));
+                       err = get_compat_semid_ds(&sem64, compat_ptr(pad));
 
-               up64 = compat_alloc_user_space(sizeof(s64));
-               if (copy_to_user(up64, &s64, sizeof(s64)))
+               up64 = compat_alloc_user_space(sizeof(sem64));
+               if (copy_to_user(up64, &sem64, sizeof(sem64)))
                        err = -EFAULT;
                if (err)
                        break;
@@ -561,12 +561,12 @@ COMPAT_SYSCALL_DEFINE3(shmat, int, shmid, compat_uptr_t, shmaddr, int, shmflg)
        return (long)ret;
 }
 
-static inline int get_compat_shmid64_ds(struct shmid64_ds *s64,
+static inline int get_compat_shmid64_ds(struct shmid64_ds *sem64,
                                        struct compat_shmid64_ds __user *up64)
 {
        if (!access_ok(VERIFY_READ, up64, sizeof(*up64)))
                return -EFAULT;
-       return __get_compat_ipc64_perm(&s64->shm_perm, &up64->shm_perm);
+       return __get_compat_ipc64_perm(&sem64->shm_perm, &up64->shm_perm);
 }
 
 static inline int get_compat_shmid_ds(struct shmid64_ds *s,
@@ -577,21 +577,21 @@ static inline int get_compat_shmid_ds(struct shmid64_ds *s,
        return __get_compat_ipc_perm(&s->shm_perm, &up->shm_perm);
 }
 
-static inline int put_compat_shmid64_ds(struct shmid64_ds *s64,
+static inline int put_compat_shmid64_ds(struct shmid64_ds *sem64,
                                        struct compat_shmid64_ds __user *up64)
 {
        int err;
 
        if (!access_ok(VERIFY_WRITE, up64, sizeof(*up64)))
                return -EFAULT;
-       err  = __put_compat_ipc64_perm(&s64->shm_perm, &up64->shm_perm);
-       err |= __put_user(s64->shm_atime, &up64->shm_atime);
-       err |= __put_user(s64->shm_dtime, &up64->shm_dtime);
-       err |= __put_user(s64->shm_ctime, &up64->shm_ctime);
-       err |= __put_user(s64->shm_segsz, &up64->shm_segsz);
-       err |= __put_user(s64->shm_nattch, &up64->shm_nattch);
-       err |= __put_user(s64->shm_cpid, &up64->shm_cpid);
-       err |= __put_user(s64->shm_lpid, &up64->shm_lpid);
+       err  = __put_compat_ipc64_perm(&sem64->shm_perm, &up64->shm_perm);
+       err |= __put_user(sem64->shm_atime, &up64->shm_atime);
+       err |= __put_user(sem64->shm_dtime, &up64->shm_dtime);
+       err |= __put_user(sem64->shm_ctime, &up64->shm_ctime);
+       err |= __put_user(sem64->shm_segsz, &up64->shm_segsz);
+       err |= __put_user(sem64->shm_nattch, &up64->shm_nattch);
+       err |= __put_user(sem64->shm_cpid, &up64->shm_cpid);
+       err |= __put_user(sem64->shm_lpid, &up64->shm_lpid);
        return err;
 }
 
@@ -668,12 +668,12 @@ static inline int put_compat_shm_info(struct shm_info __user *ip,
 COMPAT_SYSCALL_DEFINE3(shmctl, int, first, int, second, void __user *, uptr)
 {
        void __user *p;
-       struct shmid64_ds s64;
+       struct shmid64_ds sem64;
        struct shminfo64 smi;
        int err, err2;
        int version = compat_ipc_parse_version(&second);
 
-       memset(&s64, 0, sizeof(s64));
+       memset(&sem64, 0, sizeof(sem64));
 
        switch (second & (~IPC_64)) {
        case IPC_RMID:
@@ -700,14 +700,14 @@ COMPAT_SYSCALL_DEFINE3(shmctl, int, first, int, second, void __user *, uptr)
 
        case IPC_SET:
                if (version == IPC_64)
-                       err = get_compat_shmid64_ds(&s64, uptr);
+                       err = get_compat_shmid64_ds(&sem64, uptr);
                else
-                       err = get_compat_shmid_ds(&s64, uptr);
+                       err = get_compat_shmid_ds(&sem64, uptr);
 
                if (err)
                        break;
-               p = compat_alloc_user_space(sizeof(s64));
-               if (copy_to_user(p, &s64, sizeof(s64)))
+               p = compat_alloc_user_space(sizeof(sem64));
+               if (copy_to_user(p, &sem64, sizeof(sem64)))
                        err = -EFAULT;
                else
                        err = sys_shmctl(first, second, p);
@@ -715,16 +715,16 @@ COMPAT_SYSCALL_DEFINE3(shmctl, int, first, int, second, void __user *, uptr)
 
        case IPC_STAT:
        case SHM_STAT:
-               p = compat_alloc_user_space(sizeof(s64));
+               p = compat_alloc_user_space(sizeof(sem64));
                err = sys_shmctl(first, second, p);
                if (err < 0)
                        break;
-               if (copy_from_user(&s64, p, sizeof(s64)))
+               if (copy_from_user(&sem64, p, sizeof(sem64)))
                        err2 = -EFAULT;
                else if (version == IPC_64)
-                       err2 = put_compat_shmid64_ds(&s64, uptr);
+                       err2 = put_compat_shmid64_ds(&sem64, uptr);
                else
-                       err2 = put_compat_shmid_ds(&s64, uptr);
+                       err2 = put_compat_shmid_ds(&sem64, uptr);
                if (err2)
                        err = -EFAULT;
                break;
index c3f0326e98db1ca9a4e0afe8e494b857992ca851..e8075b24749775f254c4d821ea1fb2c4a8a4c5f1 100644 (file)
@@ -123,7 +123,6 @@ static int proc_ipcauto_dointvec_minmax(struct ctl_table *table, int write,
        void __user *buffer, size_t *lenp, loff_t *ppos)
 {
        struct ctl_table ipc_table;
-       size_t lenp_bef = *lenp;
        int oldval;
        int rc;
 
@@ -133,7 +132,7 @@ static int proc_ipcauto_dointvec_minmax(struct ctl_table *table, int write,
 
        rc = proc_dointvec_minmax(&ipc_table, write, buffer, lenp, ppos);
 
-       if (write && !rc && lenp_bef == *lenp) {
+       if (write && !rc) {
                int newval = *((int *)(ipc_table.data));
                /*
                 * The file "auto_msgmni" has correctly been set.
index 7fc9f9f3a26b874c7fa558d22618273e9eb357d3..01454796ba3c59e20b4db8e71fdf7a17c74f9ad7 100644 (file)
--- a/ipc/shm.c
+++ b/ipc/shm.c
@@ -1172,13 +1172,6 @@ long do_shmat(int shmid, char __user *shmaddr, int shmflg, ulong *raddr,
 
                if (find_vma_intersection(current->mm, addr, addr + size))
                        goto invalid;
-               /*
-                * If shm segment goes below stack, make sure there is some
-                * space left for the stack to grow (at least 4 pages).
-                */
-               if (addr < current->mm->start_stack &&
-                   addr > current->mm->start_stack - size - PAGE_SIZE * 5)
-                       goto invalid;
        }
 
        addr = do_mmap_pgoff(file, addr, size, prot, flags, 0, &populate);
index d73b7af581e23a87617c8e165d9561b76f8d2c0f..88adc329888c5df2d0e93f23fe306995f498d68b 100644 (file)
@@ -892,28 +892,16 @@ static const struct seq_operations sysvipc_proc_seqops = {
 
 static int sysvipc_proc_open(struct inode *inode, struct file *file)
 {
-       int ret;
-       struct seq_file *seq;
        struct ipc_proc_iter *iter;
 
-       ret = -ENOMEM;
-       iter = kmalloc(sizeof(*iter), GFP_KERNEL);
+       iter = __seq_open_private(file, &sysvipc_proc_seqops, sizeof(*iter));
        if (!iter)
-               goto out;
-
-       ret = seq_open(file, &sysvipc_proc_seqops);
-       if (ret) {
-               kfree(iter);
-               goto out;
-       }
-
-       seq = file->private_data;
-       seq->private = iter;
+               return -ENOMEM;
 
        iter->iface = PDE_DATA(inode);
        iter->ns    = get_ipc_ns(current->nsproxy->ipc_ns);
-out:
-       return ret;
+
+       return 0;
 }
 
 static int sysvipc_proc_release(struct inode *inode, struct file *file)
index 81e2a388a0f687eeb472bf33a4e24dd763ef34cf..356450f09c1f89d1ee35820a59a59e3a68cebe63 100644 (file)
@@ -79,6 +79,8 @@ static struct {
 
 /* Lockdep annotations for get/put_online_cpus() and cpu_hotplug_begin/end() */
 #define cpuhp_lock_acquire_read() lock_map_acquire_read(&cpu_hotplug.dep_map)
+#define cpuhp_lock_acquire_tryread() \
+                                 lock_map_acquire_tryread(&cpu_hotplug.dep_map)
 #define cpuhp_lock_acquire()      lock_map_acquire(&cpu_hotplug.dep_map)
 #define cpuhp_lock_release()      lock_map_release(&cpu_hotplug.dep_map)
 
@@ -91,10 +93,22 @@ void get_online_cpus(void)
        mutex_lock(&cpu_hotplug.lock);
        cpu_hotplug.refcount++;
        mutex_unlock(&cpu_hotplug.lock);
-
 }
 EXPORT_SYMBOL_GPL(get_online_cpus);
 
+bool try_get_online_cpus(void)
+{
+       if (cpu_hotplug.active_writer == current)
+               return true;
+       if (!mutex_trylock(&cpu_hotplug.lock))
+               return false;
+       cpuhp_lock_acquire_tryread();
+       cpu_hotplug.refcount++;
+       mutex_unlock(&cpu_hotplug.lock);
+       return true;
+}
+EXPORT_SYMBOL_GPL(try_get_online_cpus);
+
 void put_online_cpus(void)
 {
        if (cpu_hotplug.active_writer == current)
index 70a504601dc3909c15c424b1d2b1afdf25b9b341..b20d544f20c2a12c24ac492c4dae56961e0b959d 100644 (file)
@@ -52,11 +52,11 @@ static int kdb_parsebp(int argc, const char **argv, int *nextargp, kdb_bp_t *bp)
 
        bp->bph_length = 1;
        if ((argc + 1) != nextarg) {
-               if (strnicmp(argv[nextarg], "datar", sizeof("datar")) == 0)
+               if (strncasecmp(argv[nextarg], "datar", sizeof("datar")) == 0)
                        bp->bp_type = BP_ACCESS_WATCHPOINT;
-               else if (strnicmp(argv[nextarg], "dataw", sizeof("dataw")) == 0)
+               else if (strncasecmp(argv[nextarg], "dataw", sizeof("dataw")) == 0)
                        bp->bp_type = BP_WRITE_WATCHPOINT;
-               else if (strnicmp(argv[nextarg], "inst", sizeof("inst")) == 0)
+               else if (strncasecmp(argv[nextarg], "inst", sizeof("inst")) == 0)
                        bp->bp_type = BP_HARDWARE_BREAKPOINT;
                else
                        return KDB_ARGCOUNT;
index 97b67df8fbfed0fe7d3cdbcec0ed213b5df80e6b..f2a88de87a49b590207a0fc966b54060fd103f49 100644 (file)
@@ -52,7 +52,7 @@ static void release_callchain_buffers(void)
        struct callchain_cpus_entries *entries;
 
        entries = callchain_cpus_entries;
-       rcu_assign_pointer(callchain_cpus_entries, NULL);
+       RCU_INIT_POINTER(callchain_cpus_entries, NULL);
        call_rcu(&entries->rcu_head, release_callchain_buffers_rcu);
 }
 
index b1c663593f5c9f082cb3dd997f94978a723b7599..094df8c0742daccba897abc504dd70b6b9ee253f 100644 (file)
@@ -47,6 +47,8 @@
 
 #include <asm/irq_regs.h>
 
+static struct workqueue_struct *perf_wq;
+
 struct remote_function_call {
        struct task_struct      *p;
        int                     (*func)(void *info);
@@ -120,6 +122,13 @@ static int cpu_function_call(int cpu, int (*func) (void *info), void *info)
        return data.ret;
 }
 
+#define EVENT_OWNER_KERNEL ((void *) -1)
+
+static bool is_kernel_event(struct perf_event *event)
+{
+       return event->owner == EVENT_OWNER_KERNEL;
+}
+
 #define PERF_FLAG_ALL (PERF_FLAG_FD_NO_GROUP |\
                       PERF_FLAG_FD_OUTPUT  |\
                       PERF_FLAG_PID_CGROUP |\
@@ -897,13 +906,23 @@ static void put_ctx(struct perf_event_context *ctx)
        }
 }
 
-static void unclone_ctx(struct perf_event_context *ctx)
+/*
+ * This must be done under the ctx->lock, such as to serialize against
+ * context_equiv(), therefore we cannot call put_ctx() since that might end up
+ * calling scheduler related locks and ctx->lock nests inside those.
+ */
+static __must_check struct perf_event_context *
+unclone_ctx(struct perf_event_context *ctx)
 {
-       if (ctx->parent_ctx) {
-               put_ctx(ctx->parent_ctx);
+       struct perf_event_context *parent_ctx = ctx->parent_ctx;
+
+       lockdep_assert_held(&ctx->lock);
+
+       if (parent_ctx)
                ctx->parent_ctx = NULL;
-       }
        ctx->generation++;
+
+       return parent_ctx;
 }
 
 static u32 perf_event_pid(struct perf_event *event, struct task_struct *p)
@@ -1370,6 +1389,45 @@ out:
                perf_event__header_size(tmp);
 }
 
+/*
+ * User event without the task.
+ */
+static bool is_orphaned_event(struct perf_event *event)
+{
+       return event && !is_kernel_event(event) && !event->owner;
+}
+
+/*
+ * Event has a parent but parent's task finished and it's
+ * alive only because of children holding refference.
+ */
+static bool is_orphaned_child(struct perf_event *event)
+{
+       return is_orphaned_event(event->parent);
+}
+
+static void orphans_remove_work(struct work_struct *work);
+
+static void schedule_orphans_remove(struct perf_event_context *ctx)
+{
+       if (!ctx->task || ctx->orphans_remove_sched || !perf_wq)
+               return;
+
+       if (queue_delayed_work(perf_wq, &ctx->orphans_remove, 1)) {
+               get_ctx(ctx);
+               ctx->orphans_remove_sched = true;
+       }
+}
+
+static int __init perf_workqueue_init(void)
+{
+       perf_wq = create_singlethread_workqueue("perf");
+       WARN(!perf_wq, "failed to create perf workqueue\n");
+       return perf_wq ? 0 : -1;
+}
+
+core_initcall(perf_workqueue_init);
+
 static inline int
 event_filter_match(struct perf_event *event)
 {
@@ -1419,6 +1477,9 @@ event_sched_out(struct perf_event *event,
        if (event->attr.exclusive || !cpuctx->active_oncpu)
                cpuctx->exclusive = 0;
 
+       if (is_orphaned_child(event))
+               schedule_orphans_remove(ctx);
+
        perf_pmu_enable(event->pmu);
 }
 
@@ -1726,6 +1787,9 @@ event_sched_in(struct perf_event *event,
        if (event->attr.exclusive)
                cpuctx->exclusive = 1;
 
+       if (is_orphaned_child(event))
+               schedule_orphans_remove(ctx);
+
 out:
        perf_pmu_enable(event->pmu);
 
@@ -2205,6 +2269,9 @@ static void ctx_sched_out(struct perf_event_context *ctx,
 static int context_equiv(struct perf_event_context *ctx1,
                         struct perf_event_context *ctx2)
 {
+       lockdep_assert_held(&ctx1->lock);
+       lockdep_assert_held(&ctx2->lock);
+
        /* Pinning disables the swap optimization */
        if (ctx1->pin_count || ctx2->pin_count)
                return 0;
@@ -2326,7 +2393,7 @@ static void perf_event_context_sched_out(struct task_struct *task, int ctxn,
        next_parent = rcu_dereference(next_ctx->parent_ctx);
 
        /* If neither context have a parent context; they cannot be clones. */
-       if (!parent || !next_parent)
+       if (!parent && !next_parent)
                goto unlock;
 
        if (next_parent == ctx || next_ctx == parent || next_parent == parent) {
@@ -2938,6 +3005,7 @@ static int event_enable_on_exec(struct perf_event *event,
  */
 static void perf_event_enable_on_exec(struct perf_event_context *ctx)
 {
+       struct perf_event_context *clone_ctx = NULL;
        struct perf_event *event;
        unsigned long flags;
        int enabled = 0;
@@ -2969,7 +3037,7 @@ static void perf_event_enable_on_exec(struct perf_event_context *ctx)
         * Unclone this context if we enabled any event.
         */
        if (enabled)
-               unclone_ctx(ctx);
+               clone_ctx = unclone_ctx(ctx);
 
        raw_spin_unlock(&ctx->lock);
 
@@ -2979,6 +3047,9 @@ static void perf_event_enable_on_exec(struct perf_event_context *ctx)
        perf_event_context_sched_in(ctx, ctx->task);
 out:
        local_irq_restore(flags);
+
+       if (clone_ctx)
+               put_ctx(clone_ctx);
 }
 
 void perf_event_exec(void)
@@ -3073,6 +3144,7 @@ static void __perf_event_init_context(struct perf_event_context *ctx)
        INIT_LIST_HEAD(&ctx->flexible_groups);
        INIT_LIST_HEAD(&ctx->event_list);
        atomic_set(&ctx->refcount, 1);
+       INIT_DELAYED_WORK(&ctx->orphans_remove, orphans_remove_work);
 }
 
 static struct perf_event_context *
@@ -3130,7 +3202,7 @@ errout:
 static struct perf_event_context *
 find_get_context(struct pmu *pmu, struct task_struct *task, int cpu)
 {
-       struct perf_event_context *ctx;
+       struct perf_event_context *ctx, *clone_ctx = NULL;
        struct perf_cpu_context *cpuctx;
        unsigned long flags;
        int ctxn, err;
@@ -3164,9 +3236,12 @@ find_get_context(struct pmu *pmu, struct task_struct *task, int cpu)
 retry:
        ctx = perf_lock_task_context(task, ctxn, &flags);
        if (ctx) {
-               unclone_ctx(ctx);
+               clone_ctx = unclone_ctx(ctx);
                ++ctx->pin_count;
                raw_spin_unlock_irqrestore(&ctx->lock, flags);
+
+               if (clone_ctx)
+                       put_ctx(clone_ctx);
        } else {
                ctx = alloc_perf_context(pmu, task);
                err = -ENOMEM;
@@ -3318,16 +3393,12 @@ static void free_event(struct perf_event *event)
 }
 
 /*
- * Called when the last reference to the file is gone.
+ * Remove user event from the owner task.
  */
-static void put_event(struct perf_event *event)
+static void perf_remove_from_owner(struct perf_event *event)
 {
-       struct perf_event_context *ctx = event->ctx;
        struct task_struct *owner;
 
-       if (!atomic_long_dec_and_test(&event->refcount))
-               return;
-
        rcu_read_lock();
        owner = ACCESS_ONCE(event->owner);
        /*
@@ -3360,6 +3431,20 @@ static void put_event(struct perf_event *event)
                mutex_unlock(&owner->perf_event_mutex);
                put_task_struct(owner);
        }
+}
+
+/*
+ * Called when the last reference to the file is gone.
+ */
+static void put_event(struct perf_event *event)
+{
+       struct perf_event_context *ctx = event->ctx;
+
+       if (!atomic_long_dec_and_test(&event->refcount))
+               return;
+
+       if (!is_kernel_event(event))
+               perf_remove_from_owner(event);
 
        WARN_ON_ONCE(ctx->parent_ctx);
        /*
@@ -3394,6 +3479,42 @@ static int perf_release(struct inode *inode, struct file *file)
        return 0;
 }
 
+/*
+ * Remove all orphanes events from the context.
+ */
+static void orphans_remove_work(struct work_struct *work)
+{
+       struct perf_event_context *ctx;
+       struct perf_event *event, *tmp;
+
+       ctx = container_of(work, struct perf_event_context,
+                          orphans_remove.work);
+
+       mutex_lock(&ctx->mutex);
+       list_for_each_entry_safe(event, tmp, &ctx->event_list, event_entry) {
+               struct perf_event *parent_event = event->parent;
+
+               if (!is_orphaned_child(event))
+                       continue;
+
+               perf_remove_from_context(event, true);
+
+               mutex_lock(&parent_event->child_mutex);
+               list_del_init(&event->child_list);
+               mutex_unlock(&parent_event->child_mutex);
+
+               free_event(event);
+               put_event(parent_event);
+       }
+
+       raw_spin_lock_irq(&ctx->lock);
+       ctx->orphans_remove_sched = false;
+       raw_spin_unlock_irq(&ctx->lock);
+       mutex_unlock(&ctx->mutex);
+
+       put_ctx(ctx);
+}
+
 u64 perf_event_read_value(struct perf_event *event, u64 *enabled, u64 *running)
 {
        struct perf_event *child;
@@ -3491,6 +3612,19 @@ static int perf_event_read_one(struct perf_event *event,
        return n * sizeof(u64);
 }
 
+static bool is_event_hup(struct perf_event *event)
+{
+       bool no_children;
+
+       if (event->state != PERF_EVENT_STATE_EXIT)
+               return false;
+
+       mutex_lock(&event->child_mutex);
+       no_children = list_empty(&event->child_list);
+       mutex_unlock(&event->child_mutex);
+       return no_children;
+}
+
 /*
  * Read the performance event - simple non blocking version for now
  */
@@ -3532,7 +3666,12 @@ static unsigned int perf_poll(struct file *file, poll_table *wait)
 {
        struct perf_event *event = file->private_data;
        struct ring_buffer *rb;
-       unsigned int events = POLL_HUP;
+       unsigned int events = POLLHUP;
+
+       poll_wait(file, &event->waitq, wait);
+
+       if (is_event_hup(event))
+               return events;
 
        /*
         * Pin the event->rb by taking event->mmap_mutex; otherwise
@@ -3543,9 +3682,6 @@ static unsigned int perf_poll(struct file *file, poll_table *wait)
        if (rb)
                events = atomic_xchg(&rb->poll, 0);
        mutex_unlock(&event->mmap_mutex);
-
-       poll_wait(file, &event->waitq, wait);
-
        return events;
 }
 
@@ -5809,7 +5945,7 @@ static void swevent_hlist_release(struct swevent_htable *swhash)
        if (!hlist)
                return;
 
-       rcu_assign_pointer(swhash->swevent_hlist, NULL);
+       RCU_INIT_POINTER(swhash->swevent_hlist, NULL);
        kfree_rcu(hlist, rcu_head);
 }
 
@@ -7392,6 +7528,9 @@ perf_event_create_kernel_counter(struct perf_event_attr *attr, int cpu,
                goto err;
        }
 
+       /* Mark owner so we could distinguish it from user events. */
+       event->owner = EVENT_OWNER_KERNEL;
+
        account_event(event);
 
        ctx = find_get_context(event->pmu, task, cpu);
@@ -7478,6 +7617,12 @@ static void sync_child_event(struct perf_event *child_event,
        list_del_init(&child_event->child_list);
        mutex_unlock(&parent_event->child_mutex);
 
+       /*
+        * Make sure user/parent get notified, that we just
+        * lost one event.
+        */
+       perf_event_wakeup(parent_event);
+
        /*
         * Release the parent event, if this was the last
         * reference to it.
@@ -7512,13 +7657,16 @@ __perf_event_exit_task(struct perf_event *child_event,
        if (child_event->parent) {
                sync_child_event(child_event, child);
                free_event(child_event);
+       } else {
+               child_event->state = PERF_EVENT_STATE_EXIT;
+               perf_event_wakeup(child_event);
        }
 }
 
 static void perf_event_exit_task_context(struct task_struct *child, int ctxn)
 {
        struct perf_event *child_event, *next;
-       struct perf_event_context *child_ctx, *parent_ctx;
+       struct perf_event_context *child_ctx, *clone_ctx = NULL;
        unsigned long flags;
 
        if (likely(!child->perf_event_ctxp[ctxn])) {
@@ -7544,29 +7692,17 @@ static void perf_event_exit_task_context(struct task_struct *child, int ctxn)
        task_ctx_sched_out(child_ctx);
        child->perf_event_ctxp[ctxn] = NULL;
 
-       /*
-        * In order to avoid freeing: child_ctx->parent_ctx->task
-        * under perf_event_context::lock, grab another reference.
-        */
-       parent_ctx = child_ctx->parent_ctx;
-       if (parent_ctx)
-               get_ctx(parent_ctx);
-
        /*
         * If this context is a clone; unclone it so it can't get
         * swapped to another process while we're removing all
         * the events from it.
         */
-       unclone_ctx(child_ctx);
+       clone_ctx = unclone_ctx(child_ctx);
        update_context_time(child_ctx);
        raw_spin_unlock_irqrestore(&child_ctx->lock, flags);
 
-       /*
-        * Now that we no longer hold perf_event_context::lock, drop
-        * our extra child_ctx->parent_ctx reference.
-        */
-       if (parent_ctx)
-               put_ctx(parent_ctx);
+       if (clone_ctx)
+               put_ctx(clone_ctx);
 
        /*
         * Report the task dead after unscheduling the events so that we
@@ -7695,6 +7831,7 @@ inherit_event(struct perf_event *parent_event,
              struct perf_event *group_leader,
              struct perf_event_context *child_ctx)
 {
+       enum perf_event_active_state parent_state = parent_event->state;
        struct perf_event *child_event;
        unsigned long flags;
 
@@ -7715,7 +7852,8 @@ inherit_event(struct perf_event *parent_event,
        if (IS_ERR(child_event))
                return child_event;
 
-       if (!atomic_long_inc_not_zero(&parent_event->refcount)) {
+       if (is_orphaned_event(parent_event) ||
+           !atomic_long_inc_not_zero(&parent_event->refcount)) {
                free_event(child_event);
                return NULL;
        }
@@ -7727,7 +7865,7 @@ inherit_event(struct perf_event *parent_event,
         * not its attr.disabled bit.  We hold the parent's mutex,
         * so we won't race with perf_event_{en, dis}able_family.
         */
-       if (parent_event->state >= PERF_EVENT_STATE_INACTIVE)
+       if (parent_state >= PERF_EVENT_STATE_INACTIVE)
                child_event->state = PERF_EVENT_STATE_INACTIVE;
        else
                child_event->state = PERF_EVENT_STATE_OFF;
index 32c58f7433a3672c636687cf81c108eb0f20761e..5d30019ff953cf9cc421c1a37c850dca16e4c8a7 100644 (file)
@@ -115,32 +115,33 @@ static void __exit_signal(struct task_struct *tsk)
 
                if (tsk == sig->curr_target)
                        sig->curr_target = next_thread(tsk);
-               /*
-                * Accumulate here the counters for all threads but the
-                * group leader as they die, so they can be added into
-                * the process-wide totals when those are taken.
-                * The group leader stays around as a zombie as long
-                * as there are other threads.  When it gets reaped,
-                * the exit.c code will add its counts into these totals.
-                * We won't ever get here for the group leader, since it
-                * will have been the last reference on the signal_struct.
-                */
-               task_cputime(tsk, &utime, &stime);
-               sig->utime += utime;
-               sig->stime += stime;
-               sig->gtime += task_gtime(tsk);
-               sig->min_flt += tsk->min_flt;
-               sig->maj_flt += tsk->maj_flt;
-               sig->nvcsw += tsk->nvcsw;
-               sig->nivcsw += tsk->nivcsw;
-               sig->inblock += task_io_get_inblock(tsk);
-               sig->oublock += task_io_get_oublock(tsk);
-               task_io_accounting_add(&sig->ioac, &tsk->ioac);
-               sig->sum_sched_runtime += tsk->se.sum_exec_runtime;
        }
 
+       /*
+        * Accumulate here the counters for all threads but the group leader
+        * as they die, so they can be added into the process-wide totals
+        * when those are taken.  The group leader stays around as a zombie as
+        * long as there are other threads.  When it gets reaped, the exit.c
+        * code will add its counts into these totals.  We won't ever get here
+        * for the group leader, since it will have been the last reference on
+        * the signal_struct.
+        */
+       task_cputime(tsk, &utime, &stime);
+       write_seqlock(&sig->stats_lock);
+       sig->utime += utime;
+       sig->stime += stime;
+       sig->gtime += task_gtime(tsk);
+       sig->min_flt += tsk->min_flt;
+       sig->maj_flt += tsk->maj_flt;
+       sig->nvcsw += tsk->nvcsw;
+       sig->nivcsw += tsk->nivcsw;
+       sig->inblock += task_io_get_inblock(tsk);
+       sig->oublock += task_io_get_oublock(tsk);
+       task_io_accounting_add(&sig->ioac, &tsk->ioac);
+       sig->sum_sched_runtime += tsk->se.sum_exec_runtime;
        sig->nr_threads--;
        __unhash_process(tsk, group_dead);
+       write_sequnlock(&sig->stats_lock);
 
        /*
         * Do this under ->siglock, we can race with another thread
@@ -667,6 +668,7 @@ void do_exit(long code)
 {
        struct task_struct *tsk = current;
        int group_dead;
+       TASKS_RCU(int tasks_rcu_i);
 
        profile_task_exit(tsk);
 
@@ -775,6 +777,7 @@ void do_exit(long code)
         */
        flush_ptrace_hw_breakpoint(tsk);
 
+       TASKS_RCU(tasks_rcu_i = __srcu_read_lock(&tasks_rcu_exit_srcu));
        exit_notify(tsk, group_dead);
        proc_exit_connector(tsk);
 #ifdef CONFIG_NUMA
@@ -814,6 +817,7 @@ void do_exit(long code)
        if (tsk->nr_dirtied)
                __this_cpu_add(dirty_throttle_leaks, tsk->nr_dirtied);
        exit_rcu();
+       TASKS_RCU(__srcu_read_unlock(&tasks_rcu_exit_srcu, tasks_rcu_i));
 
        /*
         * The setting of TASK_RUNNING by try_to_wake_up() may be delayed
@@ -1043,6 +1047,7 @@ static int wait_task_zombie(struct wait_opts *wo, struct task_struct *p)
                spin_lock_irq(&p->real_parent->sighand->siglock);
                psig = p->real_parent->signal;
                sig = p->signal;
+               write_seqlock(&psig->stats_lock);
                psig->cutime += tgutime + sig->cutime;
                psig->cstime += tgstime + sig->cstime;
                psig->cgtime += task_gtime(p) + sig->gtime + sig->cgtime;
@@ -1065,6 +1070,7 @@ static int wait_task_zombie(struct wait_opts *wo, struct task_struct *p)
                        psig->cmaxrss = maxrss;
                task_io_accounting_add(&psig->ioac, &p->ioac);
                task_io_accounting_add(&psig->ioac, &sig->ioac);
+               write_sequnlock(&psig->stats_lock);
                spin_unlock_irq(&p->real_parent->sighand->siglock);
        }
 
index 8c162d102740a1ab806a5fe37ddf70e045c29832..9b7d746d6d629c3d9d1c937a677271f027a5fe2b 100644 (file)
@@ -294,11 +294,18 @@ int __weak arch_dup_task_struct(struct task_struct *dst,
        return 0;
 }
 
+void set_task_stack_end_magic(struct task_struct *tsk)
+{
+       unsigned long *stackend;
+
+       stackend = end_of_stack(tsk);
+       *stackend = STACK_END_MAGIC;    /* for overflow detection */
+}
+
 static struct task_struct *dup_task_struct(struct task_struct *orig)
 {
        struct task_struct *tsk;
        struct thread_info *ti;
-       unsigned long *stackend;
        int node = tsk_fork_get_node(orig);
        int err;
 
@@ -328,8 +335,7 @@ static struct task_struct *dup_task_struct(struct task_struct *orig)
        setup_thread_stack(tsk, orig);
        clear_user_return_notifier(tsk);
        clear_tsk_need_resched(tsk);
-       stackend = end_of_stack(tsk);
-       *stackend = STACK_END_MAGIC;    /* for overflow detection */
+       set_task_stack_end_magic(tsk);
 
 #ifdef CONFIG_CC_STACKPROTECTOR
        tsk->stack_canary = get_random_int();
@@ -1067,6 +1073,7 @@ static int copy_signal(unsigned long clone_flags, struct task_struct *tsk)
        sig->curr_target = tsk;
        init_sigpending(&sig->shared_pending);
        INIT_LIST_HEAD(&sig->posix_timers);
+       seqlock_init(&sig->stats_lock);
 
        hrtimer_init(&sig->real_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
        sig->real_timer.function = it_real_fn;
index ae51670878457d9b0db2498ee032d5735933e96f..5c5987f1081964109f96cd6cc52b285b948f0a9e 100644 (file)
@@ -565,19 +565,12 @@ static int kallsyms_open(struct inode *inode, struct file *file)
         * using get_symbol_offset for every symbol.
         */
        struct kallsym_iter *iter;
-       int ret;
-
-       iter = kmalloc(sizeof(*iter), GFP_KERNEL);
+       iter = __seq_open_private(file, &kallsyms_op, sizeof(*iter));
        if (!iter)
                return -ENOMEM;
        reset_iter(iter, 0);
 
-       ret = seq_open(file, &kallsyms_op);
-       if (ret == 0)
-               ((struct seq_file *)file->private_data)->private = iter;
-       else
-               kfree(iter);
-       return ret;
+       return 0;
 }
 
 #ifdef CONFIG_KGDB_KDB
index 2bee072268d94da0b7e19e60ee5ee90267ea2b63..2abf9f6e9a61866302c858e408c8dd7b5ec93dd5 100644 (file)
@@ -1759,7 +1759,6 @@ static __initdata char *suffix_tbl[] = {
  */
 static int __init parse_crashkernel_suffix(char *cmdline,
                                           unsigned long long   *crash_size,
-                                          unsigned long long   *crash_base,
                                           const char *suffix)
 {
        char *cur = cmdline;
@@ -1848,7 +1847,7 @@ static int __init __parse_crashkernel(char *cmdline,
 
        if (suffix)
                return parse_crashkernel_suffix(ck_cmdline, crash_size,
-                               crash_base, suffix);
+                               suffix);
        /*
         * if the commandline contains a ':', then that's the extended
         * syntax -- if not, it must be the classic syntax
@@ -2016,22 +2015,6 @@ static int __init crash_save_vmcoreinfo_init(void)
 subsys_initcall(crash_save_vmcoreinfo_init);
 
 #ifdef CONFIG_KEXEC_FILE
-static int __kexec_add_segment(struct kimage *image, char *buf,
-                              unsigned long bufsz, unsigned long mem,
-                              unsigned long memsz)
-{
-       struct kexec_segment *ksegment;
-
-       ksegment = &image->segment[image->nr_segments];
-       ksegment->kbuf = buf;
-       ksegment->bufsz = bufsz;
-       ksegment->mem = mem;
-       ksegment->memsz = memsz;
-       image->nr_segments++;
-
-       return 0;
-}
-
 static int locate_mem_hole_top_down(unsigned long start, unsigned long end,
                                    struct kexec_buf *kbuf)
 {
@@ -2064,8 +2047,7 @@ static int locate_mem_hole_top_down(unsigned long start, unsigned long end,
        } while (1);
 
        /* If we are here, we found a suitable memory range */
-       __kexec_add_segment(image, kbuf->buffer, kbuf->bufsz, temp_start,
-                           kbuf->memsz);
+       kbuf->mem = temp_start;
 
        /* Success, stop navigating through remaining System RAM ranges */
        return 1;
@@ -2099,8 +2081,7 @@ static int locate_mem_hole_bottom_up(unsigned long start, unsigned long end,
        } while (1);
 
        /* If we are here, we found a suitable memory range */
-       __kexec_add_segment(image, kbuf->buffer, kbuf->bufsz, temp_start,
-                           kbuf->memsz);
+       kbuf->mem = temp_start;
 
        /* Success, stop navigating through remaining System RAM ranges */
        return 1;
@@ -2187,7 +2168,12 @@ int kexec_add_buffer(struct kimage *image, char *buffer, unsigned long bufsz,
        }
 
        /* Found a suitable memory range */
-       ksegment = &image->segment[image->nr_segments - 1];
+       ksegment = &image->segment[image->nr_segments];
+       ksegment->kbuf = kbuf->buffer;
+       ksegment->bufsz = kbuf->bufsz;
+       ksegment->mem = kbuf->mem;
+       ksegment->memsz = kbuf->memsz;
+       image->nr_segments++;
        *load_addr = ksegment->mem;
        return 0;
 }
index 0955b885d0dc8eb5fe54aeeebe08c0eee6bd9cb7..ec8cce259779061dd863e6a48ff1dcfa1a7a131c 100644 (file)
  * Author: Paul E. McKenney <paulmck@us.ibm.com>
  *     Based on kernel/rcu/torture.c.
  */
-#include <linux/types.h>
 #include <linux/kernel.h>
-#include <linux/init.h>
 #include <linux/module.h>
 #include <linux/kthread.h>
-#include <linux/err.h>
 #include <linux/spinlock.h>
+#include <linux/rwlock.h>
+#include <linux/mutex.h>
+#include <linux/rwsem.h>
 #include <linux/smp.h>
 #include <linux/interrupt.h>
 #include <linux/sched.h>
 #include <linux/atomic.h>
-#include <linux/bitops.h>
-#include <linux/completion.h>
 #include <linux/moduleparam.h>
-#include <linux/percpu.h>
-#include <linux/notifier.h>
-#include <linux/reboot.h>
-#include <linux/freezer.h>
-#include <linux/cpu.h>
 #include <linux/delay.h>
-#include <linux/stat.h>
 #include <linux/slab.h>
-#include <linux/trace_clock.h>
-#include <asm/byteorder.h>
 #include <linux/torture.h>
 
 MODULE_LICENSE("GPL");
@@ -51,6 +41,8 @@ MODULE_AUTHOR("Paul E. McKenney <paulmck@us.ibm.com>");
 
 torture_param(int, nwriters_stress, -1,
             "Number of write-locking stress-test threads");
+torture_param(int, nreaders_stress, -1,
+            "Number of read-locking stress-test threads");
 torture_param(int, onoff_holdoff, 0, "Time after boot before CPU hotplugs (s)");
 torture_param(int, onoff_interval, 0,
             "Time between CPU hotplugs (s), 0=disable");
@@ -66,30 +58,28 @@ torture_param(bool, verbose, true,
 static char *torture_type = "spin_lock";
 module_param(torture_type, charp, 0444);
 MODULE_PARM_DESC(torture_type,
-                "Type of lock to torture (spin_lock, spin_lock_irq, ...)");
-
-static atomic_t n_lock_torture_errors;
+                "Type of lock to torture (spin_lock, spin_lock_irq, mutex_lock, ...)");
 
 static struct task_struct *stats_task;
 static struct task_struct **writer_tasks;
+static struct task_struct **reader_tasks;
 
-static int nrealwriters_stress;
 static bool lock_is_write_held;
+static bool lock_is_read_held;
 
-struct lock_writer_stress_stats {
-       long n_write_lock_fail;
-       long n_write_lock_acquired;
+struct lock_stress_stats {
+       long n_lock_fail;
+       long n_lock_acquired;
 };
-static struct lock_writer_stress_stats *lwsa;
 
 #if defined(MODULE)
 #define LOCKTORTURE_RUNNABLE_INIT 1
 #else
 #define LOCKTORTURE_RUNNABLE_INIT 0
 #endif
-int locktorture_runnable = LOCKTORTURE_RUNNABLE_INIT;
-module_param(locktorture_runnable, int, 0444);
-MODULE_PARM_DESC(locktorture_runnable, "Start locktorture at module init");
+int torture_runnable = LOCKTORTURE_RUNNABLE_INIT;
+module_param(torture_runnable, int, 0444);
+MODULE_PARM_DESC(torture_runnable, "Start locktorture at module init");
 
 /* Forward reference. */
 static void lock_torture_cleanup(void);
@@ -102,12 +92,25 @@ struct lock_torture_ops {
        int (*writelock)(void);
        void (*write_delay)(struct torture_random_state *trsp);
        void (*writeunlock)(void);
+       int (*readlock)(void);
+       void (*read_delay)(struct torture_random_state *trsp);
+       void (*readunlock)(void);
        unsigned long flags;
        const char *name;
 };
 
-static struct lock_torture_ops *cur_ops;
-
+struct lock_torture_cxt {
+       int nrealwriters_stress;
+       int nrealreaders_stress;
+       bool debug_lock;
+       atomic_t n_lock_torture_errors;
+       struct lock_torture_ops *cur_ops;
+       struct lock_stress_stats *lwsa; /* writer statistics */
+       struct lock_stress_stats *lrsa; /* reader statistics */
+};
+static struct lock_torture_cxt cxt = { 0, 0, false,
+                                      ATOMIC_INIT(0),
+                                      NULL, NULL};
 /*
  * Definitions for lock torture testing.
  */
@@ -123,10 +126,10 @@ static void torture_lock_busted_write_delay(struct torture_random_state *trsp)
 
        /* We want a long delay occasionally to force massive contention.  */
        if (!(torture_random(trsp) %
-             (nrealwriters_stress * 2000 * longdelay_us)))
+             (cxt.nrealwriters_stress * 2000 * longdelay_us)))
                mdelay(longdelay_us);
 #ifdef CONFIG_PREEMPT
-       if (!(torture_random(trsp) % (nrealwriters_stress * 20000)))
+       if (!(torture_random(trsp) % (cxt.nrealwriters_stress * 20000)))
                preempt_schedule();  /* Allow test to be preempted. */
 #endif
 }
@@ -140,6 +143,9 @@ static struct lock_torture_ops lock_busted_ops = {
        .writelock      = torture_lock_busted_write_lock,
        .write_delay    = torture_lock_busted_write_delay,
        .writeunlock    = torture_lock_busted_write_unlock,
+       .readlock       = NULL,
+       .read_delay     = NULL,
+       .readunlock     = NULL,
        .name           = "lock_busted"
 };
 
@@ -160,13 +166,13 @@ static void torture_spin_lock_write_delay(struct torture_random_state *trsp)
         * we want a long delay occasionally to force massive contention.
         */
        if (!(torture_random(trsp) %
-             (nrealwriters_stress * 2000 * longdelay_us)))
+             (cxt.nrealwriters_stress * 2000 * longdelay_us)))
                mdelay(longdelay_us);
        if (!(torture_random(trsp) %
-             (nrealwriters_stress * 2 * shortdelay_us)))
+             (cxt.nrealwriters_stress * 2 * shortdelay_us)))
                udelay(shortdelay_us);
 #ifdef CONFIG_PREEMPT
-       if (!(torture_random(trsp) % (nrealwriters_stress * 20000)))
+       if (!(torture_random(trsp) % (cxt.nrealwriters_stress * 20000)))
                preempt_schedule();  /* Allow test to be preempted. */
 #endif
 }
@@ -180,39 +186,253 @@ static struct lock_torture_ops spin_lock_ops = {
        .writelock      = torture_spin_lock_write_lock,
        .write_delay    = torture_spin_lock_write_delay,
        .writeunlock    = torture_spin_lock_write_unlock,
+       .readlock       = NULL,
+       .read_delay     = NULL,
+       .readunlock     = NULL,
        .name           = "spin_lock"
 };
 
 static int torture_spin_lock_write_lock_irq(void)
-__acquires(torture_spinlock_irq)
+__acquires(torture_spinlock)
 {
        unsigned long flags;
 
        spin_lock_irqsave(&torture_spinlock, flags);
-       cur_ops->flags = flags;
+       cxt.cur_ops->flags = flags;
        return 0;
 }
 
 static void torture_lock_spin_write_unlock_irq(void)
 __releases(torture_spinlock)
 {
-       spin_unlock_irqrestore(&torture_spinlock, cur_ops->flags);
+       spin_unlock_irqrestore(&torture_spinlock, cxt.cur_ops->flags);
 }
 
 static struct lock_torture_ops spin_lock_irq_ops = {
        .writelock      = torture_spin_lock_write_lock_irq,
        .write_delay    = torture_spin_lock_write_delay,
        .writeunlock    = torture_lock_spin_write_unlock_irq,
+       .readlock       = NULL,
+       .read_delay     = NULL,
+       .readunlock     = NULL,
        .name           = "spin_lock_irq"
 };
 
+static DEFINE_RWLOCK(torture_rwlock);
+
+static int torture_rwlock_write_lock(void) __acquires(torture_rwlock)
+{
+       write_lock(&torture_rwlock);
+       return 0;
+}
+
+static void torture_rwlock_write_delay(struct torture_random_state *trsp)
+{
+       const unsigned long shortdelay_us = 2;
+       const unsigned long longdelay_ms = 100;
+
+       /* We want a short delay mostly to emulate likely code, and
+        * we want a long delay occasionally to force massive contention.
+        */
+       if (!(torture_random(trsp) %
+             (cxt.nrealwriters_stress * 2000 * longdelay_ms)))
+               mdelay(longdelay_ms);
+       else
+               udelay(shortdelay_us);
+}
+
+static void torture_rwlock_write_unlock(void) __releases(torture_rwlock)
+{
+       write_unlock(&torture_rwlock);
+}
+
+static int torture_rwlock_read_lock(void) __acquires(torture_rwlock)
+{
+       read_lock(&torture_rwlock);
+       return 0;
+}
+
+static void torture_rwlock_read_delay(struct torture_random_state *trsp)
+{
+       const unsigned long shortdelay_us = 10;
+       const unsigned long longdelay_ms = 100;
+
+       /* We want a short delay mostly to emulate likely code, and
+        * we want a long delay occasionally to force massive contention.
+        */
+       if (!(torture_random(trsp) %
+             (cxt.nrealreaders_stress * 2000 * longdelay_ms)))
+               mdelay(longdelay_ms);
+       else
+               udelay(shortdelay_us);
+}
+
+static void torture_rwlock_read_unlock(void) __releases(torture_rwlock)
+{
+       read_unlock(&torture_rwlock);
+}
+
+static struct lock_torture_ops rw_lock_ops = {
+       .writelock      = torture_rwlock_write_lock,
+       .write_delay    = torture_rwlock_write_delay,
+       .writeunlock    = torture_rwlock_write_unlock,
+       .readlock       = torture_rwlock_read_lock,
+       .read_delay     = torture_rwlock_read_delay,
+       .readunlock     = torture_rwlock_read_unlock,
+       .name           = "rw_lock"
+};
+
+static int torture_rwlock_write_lock_irq(void) __acquires(torture_rwlock)
+{
+       unsigned long flags;
+
+       write_lock_irqsave(&torture_rwlock, flags);
+       cxt.cur_ops->flags = flags;
+       return 0;
+}
+
+static void torture_rwlock_write_unlock_irq(void)
+__releases(torture_rwlock)
+{
+       write_unlock_irqrestore(&torture_rwlock, cxt.cur_ops->flags);
+}
+
+static int torture_rwlock_read_lock_irq(void) __acquires(torture_rwlock)
+{
+       unsigned long flags;
+
+       read_lock_irqsave(&torture_rwlock, flags);
+       cxt.cur_ops->flags = flags;
+       return 0;
+}
+
+static void torture_rwlock_read_unlock_irq(void)
+__releases(torture_rwlock)
+{
+       write_unlock_irqrestore(&torture_rwlock, cxt.cur_ops->flags);
+}
+
+static struct lock_torture_ops rw_lock_irq_ops = {
+       .writelock      = torture_rwlock_write_lock_irq,
+       .write_delay    = torture_rwlock_write_delay,
+       .writeunlock    = torture_rwlock_write_unlock_irq,
+       .readlock       = torture_rwlock_read_lock_irq,
+       .read_delay     = torture_rwlock_read_delay,
+       .readunlock     = torture_rwlock_read_unlock_irq,
+       .name           = "rw_lock_irq"
+};
+
+static DEFINE_MUTEX(torture_mutex);
+
+static int torture_mutex_lock(void) __acquires(torture_mutex)
+{
+       mutex_lock(&torture_mutex);
+       return 0;
+}
+
+static void torture_mutex_delay(struct torture_random_state *trsp)
+{
+       const unsigned long longdelay_ms = 100;
+
+       /* We want a long delay occasionally to force massive contention.  */
+       if (!(torture_random(trsp) %
+             (cxt.nrealwriters_stress * 2000 * longdelay_ms)))
+               mdelay(longdelay_ms * 5);
+       else
+               mdelay(longdelay_ms / 5);
+#ifdef CONFIG_PREEMPT
+       if (!(torture_random(trsp) % (cxt.nrealwriters_stress * 20000)))
+               preempt_schedule();  /* Allow test to be preempted. */
+#endif
+}
+
+static void torture_mutex_unlock(void) __releases(torture_mutex)
+{
+       mutex_unlock(&torture_mutex);
+}
+
+static struct lock_torture_ops mutex_lock_ops = {
+       .writelock      = torture_mutex_lock,
+       .write_delay    = torture_mutex_delay,
+       .writeunlock    = torture_mutex_unlock,
+       .readlock       = NULL,
+       .read_delay     = NULL,
+       .readunlock     = NULL,
+       .name           = "mutex_lock"
+};
+
+static DECLARE_RWSEM(torture_rwsem);
+static int torture_rwsem_down_write(void) __acquires(torture_rwsem)
+{
+       down_write(&torture_rwsem);
+       return 0;
+}
+
+static void torture_rwsem_write_delay(struct torture_random_state *trsp)
+{
+       const unsigned long longdelay_ms = 100;
+
+       /* We want a long delay occasionally to force massive contention.  */
+       if (!(torture_random(trsp) %
+             (cxt.nrealwriters_stress * 2000 * longdelay_ms)))
+               mdelay(longdelay_ms * 10);
+       else
+               mdelay(longdelay_ms / 10);
+#ifdef CONFIG_PREEMPT
+       if (!(torture_random(trsp) % (cxt.nrealwriters_stress * 20000)))
+               preempt_schedule();  /* Allow test to be preempted. */
+#endif
+}
+
+static void torture_rwsem_up_write(void) __releases(torture_rwsem)
+{
+       up_write(&torture_rwsem);
+}
+
+static int torture_rwsem_down_read(void) __acquires(torture_rwsem)
+{
+       down_read(&torture_rwsem);
+       return 0;
+}
+
+static void torture_rwsem_read_delay(struct torture_random_state *trsp)
+{
+       const unsigned long longdelay_ms = 100;
+
+       /* We want a long delay occasionally to force massive contention.  */
+       if (!(torture_random(trsp) %
+             (cxt.nrealwriters_stress * 2000 * longdelay_ms)))
+               mdelay(longdelay_ms * 2);
+       else
+               mdelay(longdelay_ms / 2);
+#ifdef CONFIG_PREEMPT
+       if (!(torture_random(trsp) % (cxt.nrealreaders_stress * 20000)))
+               preempt_schedule();  /* Allow test to be preempted. */
+#endif
+}
+
+static void torture_rwsem_up_read(void) __releases(torture_rwsem)
+{
+       up_read(&torture_rwsem);
+}
+
+static struct lock_torture_ops rwsem_lock_ops = {
+       .writelock      = torture_rwsem_down_write,
+       .write_delay    = torture_rwsem_write_delay,
+       .writeunlock    = torture_rwsem_up_write,
+       .readlock       = torture_rwsem_down_read,
+       .read_delay     = torture_rwsem_read_delay,
+       .readunlock     = torture_rwsem_up_read,
+       .name           = "rwsem_lock"
+};
+
 /*
  * Lock torture writer kthread.  Repeatedly acquires and releases
  * the lock, checking for duplicate acquisitions.
  */
 static int lock_torture_writer(void *arg)
 {
-       struct lock_writer_stress_stats *lwsp = arg;
+       struct lock_stress_stats *lwsp = arg;
        static DEFINE_TORTURE_RANDOM(rand);
 
        VERBOSE_TOROUT_STRING("lock_torture_writer task started");
@@ -221,47 +441,86 @@ static int lock_torture_writer(void *arg)
        do {
                if ((torture_random(&rand) & 0xfffff) == 0)
                        schedule_timeout_uninterruptible(1);
-               cur_ops->writelock();
+
+               cxt.cur_ops->writelock();
                if (WARN_ON_ONCE(lock_is_write_held))
-                       lwsp->n_write_lock_fail++;
+                       lwsp->n_lock_fail++;
                lock_is_write_held = 1;
-               lwsp->n_write_lock_acquired++;
-               cur_ops->write_delay(&rand);
+               if (WARN_ON_ONCE(lock_is_read_held))
+                       lwsp->n_lock_fail++; /* rare, but... */
+
+               lwsp->n_lock_acquired++;
+               cxt.cur_ops->write_delay(&rand);
                lock_is_write_held = 0;
-               cur_ops->writeunlock();
+               cxt.cur_ops->writeunlock();
+
                stutter_wait("lock_torture_writer");
        } while (!torture_must_stop());
        torture_kthread_stopping("lock_torture_writer");
        return 0;
 }
 
+/*
+ * Lock torture reader kthread.  Repeatedly acquires and releases
+ * the reader lock.
+ */
+static int lock_torture_reader(void *arg)
+{
+       struct lock_stress_stats *lrsp = arg;
+       static DEFINE_TORTURE_RANDOM(rand);
+
+       VERBOSE_TOROUT_STRING("lock_torture_reader task started");
+       set_user_nice(current, MAX_NICE);
+
+       do {
+               if ((torture_random(&rand) & 0xfffff) == 0)
+                       schedule_timeout_uninterruptible(1);
+
+               cxt.cur_ops->readlock();
+               lock_is_read_held = 1;
+               if (WARN_ON_ONCE(lock_is_write_held))
+                       lrsp->n_lock_fail++; /* rare, but... */
+
+               lrsp->n_lock_acquired++;
+               cxt.cur_ops->read_delay(&rand);
+               lock_is_read_held = 0;
+               cxt.cur_ops->readunlock();
+
+               stutter_wait("lock_torture_reader");
+       } while (!torture_must_stop());
+       torture_kthread_stopping("lock_torture_reader");
+       return 0;
+}
+
 /*
  * Create an lock-torture-statistics message in the specified buffer.
  */
-static void lock_torture_printk(char *page)
+static void __torture_print_stats(char *page,
+                                 struct lock_stress_stats *statp, bool write)
 {
        bool fail = 0;
-       int i;
+       int i, n_stress;
        long max = 0;
-       long min = lwsa[0].n_write_lock_acquired;
+       long min = statp[0].n_lock_acquired;
        long long sum = 0;
 
-       for (i = 0; i < nrealwriters_stress; i++) {
-               if (lwsa[i].n_write_lock_fail)
+       n_stress = write ? cxt.nrealwriters_stress : cxt.nrealreaders_stress;
+       for (i = 0; i < n_stress; i++) {
+               if (statp[i].n_lock_fail)
                        fail = true;
-               sum += lwsa[i].n_write_lock_acquired;
-               if (max < lwsa[i].n_write_lock_fail)
-                       max = lwsa[i].n_write_lock_fail;
-               if (min > lwsa[i].n_write_lock_fail)
-                       min = lwsa[i].n_write_lock_fail;
+               sum += statp[i].n_lock_acquired;
+               if (max < statp[i].n_lock_fail)
+                       max = statp[i].n_lock_fail;
+               if (min > statp[i].n_lock_fail)
+                       min = statp[i].n_lock_fail;
        }
-       page += sprintf(page, "%s%s ", torture_type, TORTURE_FLAG);
        page += sprintf(page,
-                       "Writes:  Total: %lld  Max/Min: %ld/%ld %s  Fail: %d %s\n",
+                       "%s:  Total: %lld  Max/Min: %ld/%ld %s  Fail: %d %s\n",
+                       write ? "Writes" : "Reads ",
                        sum, max, min, max / 2 > min ? "???" : "",
                        fail, fail ? "!!!" : "");
        if (fail)
-               atomic_inc(&n_lock_torture_errors);
+               atomic_inc(&cxt.n_lock_torture_errors);
 }
 
 /*
@@ -274,18 +533,35 @@ static void lock_torture_printk(char *page)
  */
 static void lock_torture_stats_print(void)
 {
-       int size = nrealwriters_stress * 200 + 8192;
+       int size = cxt.nrealwriters_stress * 200 + 8192;
        char *buf;
 
+       if (cxt.cur_ops->readlock)
+               size += cxt.nrealreaders_stress * 200 + 8192;
+
        buf = kmalloc(size, GFP_KERNEL);
        if (!buf) {
                pr_err("lock_torture_stats_print: Out of memory, need: %d",
                       size);
                return;
        }
-       lock_torture_printk(buf);
+
+       __torture_print_stats(buf, cxt.lwsa, true);
        pr_alert("%s", buf);
        kfree(buf);
+
+       if (cxt.cur_ops->readlock) {
+               buf = kmalloc(size, GFP_KERNEL);
+               if (!buf) {
+                       pr_err("lock_torture_stats_print: Out of memory, need: %d",
+                              size);
+                       return;
+               }
+
+               __torture_print_stats(buf, cxt.lrsa, false);
+               pr_alert("%s", buf);
+               kfree(buf);
+       }
 }
 
 /*
@@ -312,9 +588,10 @@ lock_torture_print_module_parms(struct lock_torture_ops *cur_ops,
                                const char *tag)
 {
        pr_alert("%s" TORTURE_FLAG
-                "--- %s: nwriters_stress=%d stat_interval=%d verbose=%d shuffle_interval=%d stutter=%d shutdown_secs=%d onoff_interval=%d onoff_holdoff=%d\n",
-                torture_type, tag, nrealwriters_stress, stat_interval, verbose,
-                shuffle_interval, stutter, shutdown_secs,
+                "--- %s%s: nwriters_stress=%d nreaders_stress=%d stat_interval=%d verbose=%d shuffle_interval=%d stutter=%d shutdown_secs=%d onoff_interval=%d onoff_holdoff=%d\n",
+                torture_type, tag, cxt.debug_lock ? " [debug]": "",
+                cxt.nrealwriters_stress, cxt.nrealreaders_stress, stat_interval,
+                verbose, shuffle_interval, stutter, shutdown_secs,
                 onoff_interval, onoff_holdoff);
 }
 
@@ -322,46 +599,59 @@ static void lock_torture_cleanup(void)
 {
        int i;
 
-       if (torture_cleanup())
+       if (torture_cleanup_begin())
                return;
 
        if (writer_tasks) {
-               for (i = 0; i < nrealwriters_stress; i++)
+               for (i = 0; i < cxt.nrealwriters_stress; i++)
                        torture_stop_kthread(lock_torture_writer,
                                             writer_tasks[i]);
                kfree(writer_tasks);
                writer_tasks = NULL;
        }
 
+       if (reader_tasks) {
+               for (i = 0; i < cxt.nrealreaders_stress; i++)
+                       torture_stop_kthread(lock_torture_reader,
+                                            reader_tasks[i]);
+               kfree(reader_tasks);
+               reader_tasks = NULL;
+       }
+
        torture_stop_kthread(lock_torture_stats, stats_task);
        lock_torture_stats_print();  /* -After- the stats thread is stopped! */
 
-       if (atomic_read(&n_lock_torture_errors))
-               lock_torture_print_module_parms(cur_ops,
+       if (atomic_read(&cxt.n_lock_torture_errors))
+               lock_torture_print_module_parms(cxt.cur_ops,
                                                "End of test: FAILURE");
        else if (torture_onoff_failures())
-               lock_torture_print_module_parms(cur_ops,
+               lock_torture_print_module_parms(cxt.cur_ops,
                                                "End of test: LOCK_HOTPLUG");
        else
-               lock_torture_print_module_parms(cur_ops,
+               lock_torture_print_module_parms(cxt.cur_ops,
                                                "End of test: SUCCESS");
+       torture_cleanup_end();
 }
 
 static int __init lock_torture_init(void)
 {
-       int i;
+       int i, j;
        int firsterr = 0;
        static struct lock_torture_ops *torture_ops[] = {
-               &lock_busted_ops, &spin_lock_ops, &spin_lock_irq_ops,
+               &lock_busted_ops,
+               &spin_lock_ops, &spin_lock_irq_ops,
+               &rw_lock_ops, &rw_lock_irq_ops,
+               &mutex_lock_ops,
+               &rwsem_lock_ops,
        };
 
-       if (!torture_init_begin(torture_type, verbose, &locktorture_runnable))
+       if (!torture_init_begin(torture_type, verbose, &torture_runnable))
                return -EBUSY;
 
        /* Process args and tell the world that the torturer is on the job. */
        for (i = 0; i < ARRAY_SIZE(torture_ops); i++) {
-               cur_ops = torture_ops[i];
-               if (strcmp(torture_type, cur_ops->name) == 0)
+               cxt.cur_ops = torture_ops[i];
+               if (strcmp(torture_type, cxt.cur_ops->name) == 0)
                        break;
        }
        if (i == ARRAY_SIZE(torture_ops)) {
@@ -374,31 +664,69 @@ static int __init lock_torture_init(void)
                torture_init_end();
                return -EINVAL;
        }
-       if (cur_ops->init)
-               cur_ops->init(); /* no "goto unwind" prior to this point!!! */
+       if (cxt.cur_ops->init)
+               cxt.cur_ops->init(); /* no "goto unwind" prior to this point!!! */
 
        if (nwriters_stress >= 0)
-               nrealwriters_stress = nwriters_stress;
+               cxt.nrealwriters_stress = nwriters_stress;
        else
-               nrealwriters_stress = 2 * num_online_cpus();
-       lock_torture_print_module_parms(cur_ops, "Start of test");
+               cxt.nrealwriters_stress = 2 * num_online_cpus();
+
+#ifdef CONFIG_DEBUG_MUTEXES
+       if (strncmp(torture_type, "mutex", 5) == 0)
+               cxt.debug_lock = true;
+#endif
+#ifdef CONFIG_DEBUG_SPINLOCK
+       if ((strncmp(torture_type, "spin", 4) == 0) ||
+           (strncmp(torture_type, "rw_lock", 7) == 0))
+               cxt.debug_lock = true;
+#endif
 
        /* Initialize the statistics so that each run gets its own numbers. */
 
        lock_is_write_held = 0;
-       lwsa = kmalloc(sizeof(*lwsa) * nrealwriters_stress, GFP_KERNEL);
-       if (lwsa == NULL) {
-               VERBOSE_TOROUT_STRING("lwsa: Out of memory");
+       cxt.lwsa = kmalloc(sizeof(*cxt.lwsa) * cxt.nrealwriters_stress, GFP_KERNEL);
+       if (cxt.lwsa == NULL) {
+               VERBOSE_TOROUT_STRING("cxt.lwsa: Out of memory");
                firsterr = -ENOMEM;
                goto unwind;
        }
-       for (i = 0; i < nrealwriters_stress; i++) {
-               lwsa[i].n_write_lock_fail = 0;
-               lwsa[i].n_write_lock_acquired = 0;
+       for (i = 0; i < cxt.nrealwriters_stress; i++) {
+               cxt.lwsa[i].n_lock_fail = 0;
+               cxt.lwsa[i].n_lock_acquired = 0;
        }
 
-       /* Start up the kthreads. */
+       if (cxt.cur_ops->readlock) {
+               if (nreaders_stress >= 0)
+                       cxt.nrealreaders_stress = nreaders_stress;
+               else {
+                       /*
+                        * By default distribute evenly the number of
+                        * readers and writers. We still run the same number
+                        * of threads as the writer-only locks default.
+                        */
+                       if (nwriters_stress < 0) /* user doesn't care */
+                               cxt.nrealwriters_stress = num_online_cpus();
+                       cxt.nrealreaders_stress = cxt.nrealwriters_stress;
+               }
+
+               lock_is_read_held = 0;
+               cxt.lrsa = kmalloc(sizeof(*cxt.lrsa) * cxt.nrealreaders_stress, GFP_KERNEL);
+               if (cxt.lrsa == NULL) {
+                       VERBOSE_TOROUT_STRING("cxt.lrsa: Out of memory");
+                       firsterr = -ENOMEM;
+                       kfree(cxt.lwsa);
+                       goto unwind;
+               }
+
+               for (i = 0; i < cxt.nrealreaders_stress; i++) {
+                       cxt.lrsa[i].n_lock_fail = 0;
+                       cxt.lrsa[i].n_lock_acquired = 0;
+               }
+       }
+       lock_torture_print_module_parms(cxt.cur_ops, "Start of test");
 
+       /* Prepare torture context. */
        if (onoff_interval > 0) {
                firsterr = torture_onoff_init(onoff_holdoff * HZ,
                                              onoff_interval * HZ);
@@ -422,18 +750,51 @@ static int __init lock_torture_init(void)
                        goto unwind;
        }
 
-       writer_tasks = kzalloc(nrealwriters_stress * sizeof(writer_tasks[0]),
+       writer_tasks = kzalloc(cxt.nrealwriters_stress * sizeof(writer_tasks[0]),
                               GFP_KERNEL);
        if (writer_tasks == NULL) {
                VERBOSE_TOROUT_ERRSTRING("writer_tasks: Out of memory");
                firsterr = -ENOMEM;
                goto unwind;
        }
-       for (i = 0; i < nrealwriters_stress; i++) {
-               firsterr = torture_create_kthread(lock_torture_writer, &lwsa[i],
+
+       if (cxt.cur_ops->readlock) {
+               reader_tasks = kzalloc(cxt.nrealreaders_stress * sizeof(reader_tasks[0]),
+                                      GFP_KERNEL);
+               if (reader_tasks == NULL) {
+                       VERBOSE_TOROUT_ERRSTRING("reader_tasks: Out of memory");
+                       firsterr = -ENOMEM;
+                       goto unwind;
+               }
+       }
+
+       /*
+        * Create the kthreads and start torturing (oh, those poor little locks).
+        *
+        * TODO: Note that we interleave writers with readers, giving writers a
+        * slight advantage, by creating its kthread first. This can be modified
+        * for very specific needs, or even let the user choose the policy, if
+        * ever wanted.
+        */
+       for (i = 0, j = 0; i < cxt.nrealwriters_stress ||
+                   j < cxt.nrealreaders_stress; i++, j++) {
+               if (i >= cxt.nrealwriters_stress)
+                       goto create_reader;
+
+               /* Create writer. */
+               firsterr = torture_create_kthread(lock_torture_writer, &cxt.lwsa[i],
                                                  writer_tasks[i]);
                if (firsterr)
                        goto unwind;
+
+       create_reader:
+               if (cxt.cur_ops->readlock == NULL || (j >= cxt.nrealreaders_stress))
+                       continue;
+               /* Create reader. */
+               firsterr = torture_create_kthread(lock_torture_reader, &cxt.lrsa[j],
+                                                 reader_tasks[j]);
+               if (firsterr)
+                       goto unwind;
        }
        if (stat_interval > 0) {
                firsterr = torture_create_kthread(lock_torture_stats, NULL,
index 23e89c5930e9414553f99dfa30ef4d154106d13b..4d60986fcbee74a4fde3906e0d87fc113c5e8172 100644 (file)
@@ -56,9 +56,6 @@ do {                                                                  \
  * If the lock has already been acquired, then this will proceed to spin
  * on this node->locked until the previous lock holder sets the node->locked
  * in mcs_spin_unlock().
- *
- * We don't inline mcs_spin_lock() so that perf can correctly account for the
- * time spent in this lock function.
  */
 static inline
 void mcs_spin_lock(struct mcs_spinlock **lock, struct mcs_spinlock *node)
index ae712b25e4922517a5fc13949d09f2c36294dadb..dadbf88c22c48cea044aac4e34fda9deec78636a 100644 (file)
@@ -15,7 +15,7 @@
  *    by Steven Rostedt, based on work by Gregory Haskins, Peter Morreale
  *    and Sven Dietrich.
  *
- * Also see Documentation/mutex-design.txt.
+ * Also see Documentation/locking/mutex-design.txt.
  */
 #include <linux/mutex.h>
 #include <linux/ww_mutex.h>
@@ -106,6 +106,92 @@ void __sched mutex_lock(struct mutex *lock)
 EXPORT_SYMBOL(mutex_lock);
 #endif
 
+static __always_inline void ww_mutex_lock_acquired(struct ww_mutex *ww,
+                                                  struct ww_acquire_ctx *ww_ctx)
+{
+#ifdef CONFIG_DEBUG_MUTEXES
+       /*
+        * If this WARN_ON triggers, you used ww_mutex_lock to acquire,
+        * but released with a normal mutex_unlock in this call.
+        *
+        * This should never happen, always use ww_mutex_unlock.
+        */
+       DEBUG_LOCKS_WARN_ON(ww->ctx);
+
+       /*
+        * Not quite done after calling ww_acquire_done() ?
+        */
+       DEBUG_LOCKS_WARN_ON(ww_ctx->done_acquire);
+
+       if (ww_ctx->contending_lock) {
+               /*
+                * After -EDEADLK you tried to
+                * acquire a different ww_mutex? Bad!
+                */
+               DEBUG_LOCKS_WARN_ON(ww_ctx->contending_lock != ww);
+
+               /*
+                * You called ww_mutex_lock after receiving -EDEADLK,
+                * but 'forgot' to unlock everything else first?
+                */
+               DEBUG_LOCKS_WARN_ON(ww_ctx->acquired > 0);
+               ww_ctx->contending_lock = NULL;
+       }
+
+       /*
+        * Naughty, using a different class will lead to undefined behavior!
+        */
+       DEBUG_LOCKS_WARN_ON(ww_ctx->ww_class != ww->ww_class);
+#endif
+       ww_ctx->acquired++;
+}
+
+/*
+ * after acquiring lock with fastpath or when we lost out in contested
+ * slowpath, set ctx and wake up any waiters so they can recheck.
+ *
+ * This function is never called when CONFIG_DEBUG_LOCK_ALLOC is set,
+ * as the fastpath and opportunistic spinning are disabled in that case.
+ */
+static __always_inline void
+ww_mutex_set_context_fastpath(struct ww_mutex *lock,
+                              struct ww_acquire_ctx *ctx)
+{
+       unsigned long flags;
+       struct mutex_waiter *cur;
+
+       ww_mutex_lock_acquired(lock, ctx);
+
+       lock->ctx = ctx;
+
+       /*
+        * The lock->ctx update should be visible on all cores before
+        * the atomic read is done, otherwise contended waiters might be
+        * missed. The contended waiters will either see ww_ctx == NULL
+        * and keep spinning, or it will acquire wait_lock, add itself
+        * to waiter list and sleep.
+        */
+       smp_mb(); /* ^^^ */
+
+       /*
+        * Check if lock is contended, if not there is nobody to wake up
+        */
+       if (likely(atomic_read(&lock->base.count) == 0))
+               return;
+
+       /*
+        * Uh oh, we raced in fastpath, wake up everyone in this case,
+        * so they can see the new lock->ctx.
+        */
+       spin_lock_mutex(&lock->base.wait_lock, flags);
+       list_for_each_entry(cur, &lock->base.wait_list, list) {
+               debug_mutex_wake_waiter(&lock->base, cur);
+               wake_up_process(cur->task);
+       }
+       spin_unlock_mutex(&lock->base.wait_lock, flags);
+}
+
+
 #ifdef CONFIG_MUTEX_SPIN_ON_OWNER
 /*
  * In order to avoid a stampede of mutex spinners from acquiring the mutex
@@ -180,6 +266,129 @@ static inline int mutex_can_spin_on_owner(struct mutex *lock)
         */
        return retval;
 }
+
+/*
+ * Atomically try to take the lock when it is available
+ */
+static inline bool mutex_try_to_acquire(struct mutex *lock)
+{
+       return !mutex_is_locked(lock) &&
+               (atomic_cmpxchg(&lock->count, 1, 0) == 1);
+}
+
+/*
+ * Optimistic spinning.
+ *
+ * We try to spin for acquisition when we find that the lock owner
+ * is currently running on a (different) CPU and while we don't
+ * need to reschedule. The rationale is that if the lock owner is
+ * running, it is likely to release the lock soon.
+ *
+ * Since this needs the lock owner, and this mutex implementation
+ * doesn't track the owner atomically in the lock field, we need to
+ * track it non-atomically.
+ *
+ * We can't do this for DEBUG_MUTEXES because that relies on wait_lock
+ * to serialize everything.
+ *
+ * The mutex spinners are queued up using MCS lock so that only one
+ * spinner can compete for the mutex. However, if mutex spinning isn't
+ * going to happen, there is no point in going through the lock/unlock
+ * overhead.
+ *
+ * Returns true when the lock was taken, otherwise false, indicating
+ * that we need to jump to the slowpath and sleep.
+ */
+static bool mutex_optimistic_spin(struct mutex *lock,
+                                 struct ww_acquire_ctx *ww_ctx, const bool use_ww_ctx)
+{
+       struct task_struct *task = current;
+
+       if (!mutex_can_spin_on_owner(lock))
+               goto done;
+
+       if (!osq_lock(&lock->osq))
+               goto done;
+
+       while (true) {
+               struct task_struct *owner;
+
+               if (use_ww_ctx && ww_ctx->acquired > 0) {
+                       struct ww_mutex *ww;
+
+                       ww = container_of(lock, struct ww_mutex, base);
+                       /*
+                        * If ww->ctx is set the contents are undefined, only
+                        * by acquiring wait_lock there is a guarantee that
+                        * they are not invalid when reading.
+                        *
+                        * As such, when deadlock detection needs to be
+                        * performed the optimistic spinning cannot be done.
+                        */
+                       if (ACCESS_ONCE(ww->ctx))
+                               break;
+               }
+
+               /*
+                * If there's an owner, wait for it to either
+                * release the lock or go to sleep.
+                */
+               owner = ACCESS_ONCE(lock->owner);
+               if (owner && !mutex_spin_on_owner(lock, owner))
+                       break;
+
+               /* Try to acquire the mutex if it is unlocked. */
+               if (mutex_try_to_acquire(lock)) {
+                       lock_acquired(&lock->dep_map, ip);
+
+                       if (use_ww_ctx) {
+                               struct ww_mutex *ww;
+                               ww = container_of(lock, struct ww_mutex, base);
+
+                               ww_mutex_set_context_fastpath(ww, ww_ctx);
+                       }
+
+                       mutex_set_owner(lock);
+                       osq_unlock(&lock->osq);
+                       return true;
+               }
+
+               /*
+                * When there's no owner, we might have preempted between the
+                * owner acquiring the lock and setting the owner field. If
+                * we're an RT task that will live-lock because we won't let
+                * the owner complete.
+                */
+               if (!owner && (need_resched() || rt_task(task)))
+                       break;
+
+               /*
+                * The cpu_relax() call is a compiler barrier which forces
+                * everything in this loop to be re-loaded. We don't need
+                * memory barriers as we'll eventually observe the right
+                * values at the cost of a few extra spins.
+                */
+               cpu_relax_lowlatency();
+       }
+
+       osq_unlock(&lock->osq);
+done:
+       /*
+        * If we fell out of the spin path because of need_resched(),
+        * reschedule now, before we try-lock the mutex. This avoids getting
+        * scheduled out right after we obtained the mutex.
+        */
+       if (need_resched())
+               schedule_preempt_disabled();
+
+       return false;
+}
+#else
+static bool mutex_optimistic_spin(struct mutex *lock,
+                                 struct ww_acquire_ctx *ww_ctx, const bool use_ww_ctx)
+{
+       return false;
+}
 #endif
 
 __visible __used noinline
@@ -277,91 +486,6 @@ __mutex_lock_check_stamp(struct mutex *lock, struct ww_acquire_ctx *ctx)
        return 0;
 }
 
-static __always_inline void ww_mutex_lock_acquired(struct ww_mutex *ww,
-                                                  struct ww_acquire_ctx *ww_ctx)
-{
-#ifdef CONFIG_DEBUG_MUTEXES
-       /*
-        * If this WARN_ON triggers, you used ww_mutex_lock to acquire,
-        * but released with a normal mutex_unlock in this call.
-        *
-        * This should never happen, always use ww_mutex_unlock.
-        */
-       DEBUG_LOCKS_WARN_ON(ww->ctx);
-
-       /*
-        * Not quite done after calling ww_acquire_done() ?
-        */
-       DEBUG_LOCKS_WARN_ON(ww_ctx->done_acquire);
-
-       if (ww_ctx->contending_lock) {
-               /*
-                * After -EDEADLK you tried to
-                * acquire a different ww_mutex? Bad!
-                */
-               DEBUG_LOCKS_WARN_ON(ww_ctx->contending_lock != ww);
-
-               /*
-                * You called ww_mutex_lock after receiving -EDEADLK,
-                * but 'forgot' to unlock everything else first?
-                */
-               DEBUG_LOCKS_WARN_ON(ww_ctx->acquired > 0);
-               ww_ctx->contending_lock = NULL;
-       }
-
-       /*
-        * Naughty, using a different class will lead to undefined behavior!
-        */
-       DEBUG_LOCKS_WARN_ON(ww_ctx->ww_class != ww->ww_class);
-#endif
-       ww_ctx->acquired++;
-}
-
-/*
- * after acquiring lock with fastpath or when we lost out in contested
- * slowpath, set ctx and wake up any waiters so they can recheck.
- *
- * This function is never called when CONFIG_DEBUG_LOCK_ALLOC is set,
- * as the fastpath and opportunistic spinning are disabled in that case.
- */
-static __always_inline void
-ww_mutex_set_context_fastpath(struct ww_mutex *lock,
-                              struct ww_acquire_ctx *ctx)
-{
-       unsigned long flags;
-       struct mutex_waiter *cur;
-
-       ww_mutex_lock_acquired(lock, ctx);
-
-       lock->ctx = ctx;
-
-       /*
-        * The lock->ctx update should be visible on all cores before
-        * the atomic read is done, otherwise contended waiters might be
-        * missed. The contended waiters will either see ww_ctx == NULL
-        * and keep spinning, or it will acquire wait_lock, add itself
-        * to waiter list and sleep.
-        */
-       smp_mb(); /* ^^^ */
-
-       /*
-        * Check if lock is contended, if not there is nobody to wake up
-        */
-       if (likely(atomic_read(&lock->base.count) == 0))
-               return;
-
-       /*
-        * Uh oh, we raced in fastpath, wake up everyone in this case,
-        * so they can see the new lock->ctx.
-        */
-       spin_lock_mutex(&lock->base.wait_lock, flags);
-       list_for_each_entry(cur, &lock->base.wait_list, list) {
-               debug_mutex_wake_waiter(&lock->base, cur);
-               wake_up_process(cur->task);
-       }
-       spin_unlock_mutex(&lock->base.wait_lock, flags);
-}
-
 /*
  * Lock a mutex (possibly interruptible), slowpath:
  */
@@ -378,104 +502,12 @@ __mutex_lock_common(struct mutex *lock, long state, unsigned int subclass,
        preempt_disable();
        mutex_acquire_nest(&lock->dep_map, subclass, 0, nest_lock, ip);
 
-#ifdef CONFIG_MUTEX_SPIN_ON_OWNER
-       /*
-        * Optimistic spinning.
-        *
-        * We try to spin for acquisition when we find that the lock owner
-        * is currently running on a (different) CPU and while we don't
-        * need to reschedule. The rationale is that if the lock owner is
-        * running, it is likely to release the lock soon.
-        *
-        * Since this needs the lock owner, and this mutex implementation
-        * doesn't track the owner atomically in the lock field, we need to
-        * track it non-atomically.
-        *
-        * We can't do this for DEBUG_MUTEXES because that relies on wait_lock
-        * to serialize everything.
-        *
-        * The mutex spinners are queued up using MCS lock so that only one
-        * spinner can compete for the mutex. However, if mutex spinning isn't
-        * going to happen, there is no point in going through the lock/unlock
-        * overhead.
-        */
-       if (!mutex_can_spin_on_owner(lock))
-               goto slowpath;
-
-       if (!osq_lock(&lock->osq))
-               goto slowpath;
-
-       for (;;) {
-               struct task_struct *owner;
-
-               if (use_ww_ctx && ww_ctx->acquired > 0) {
-                       struct ww_mutex *ww;
-
-                       ww = container_of(lock, struct ww_mutex, base);
-                       /*
-                        * If ww->ctx is set the contents are undefined, only
-                        * by acquiring wait_lock there is a guarantee that
-                        * they are not invalid when reading.
-                        *
-                        * As such, when deadlock detection needs to be
-                        * performed the optimistic spinning cannot be done.
-                        */
-                       if (ACCESS_ONCE(ww->ctx))
-                               break;
-               }
-
-               /*
-                * If there's an owner, wait for it to either
-                * release the lock or go to sleep.
-                */
-               owner = ACCESS_ONCE(lock->owner);
-               if (owner && !mutex_spin_on_owner(lock, owner))
-                       break;
-
-               /* Try to acquire the mutex if it is unlocked. */
-               if (!mutex_is_locked(lock) &&
-                   (atomic_cmpxchg(&lock->count, 1, 0) == 1)) {
-                       lock_acquired(&lock->dep_map, ip);
-                       if (use_ww_ctx) {
-                               struct ww_mutex *ww;
-                               ww = container_of(lock, struct ww_mutex, base);
-
-                               ww_mutex_set_context_fastpath(ww, ww_ctx);
-                       }
-
-                       mutex_set_owner(lock);
-                       osq_unlock(&lock->osq);
-                       preempt_enable();
-                       return 0;
-               }
-
-               /*
-                * When there's no owner, we might have preempted between the
-                * owner acquiring the lock and setting the owner field. If
-                * we're an RT task that will live-lock because we won't let
-                * the owner complete.
-                */
-               if (!owner && (need_resched() || rt_task(task)))
-                       break;
-
-               /*
-                * The cpu_relax() call is a compiler barrier which forces
-                * everything in this loop to be re-loaded. We don't need
-                * memory barriers as we'll eventually observe the right
-                * values at the cost of a few extra spins.
-                */
-               cpu_relax_lowlatency();
+       if (mutex_optimistic_spin(lock, ww_ctx, use_ww_ctx)) {
+               /* got the lock, yay! */
+               preempt_enable();
+               return 0;
        }
-       osq_unlock(&lock->osq);
-slowpath:
-       /*
-        * If we fell out of the spin path because of need_resched(),
-        * reschedule now, before we try-lock the mutex. This avoids getting
-        * scheduled out right after we obtained the mutex.
-        */
-       if (need_resched())
-               schedule_preempt_disabled();
-#endif
+
        spin_lock_mutex(&lock->wait_lock, flags);
 
        /*
@@ -679,15 +711,21 @@ EXPORT_SYMBOL_GPL(__ww_mutex_lock_interruptible);
  * Release the lock, slowpath:
  */
 static inline void
-__mutex_unlock_common_slowpath(atomic_t *lock_count, int nested)
+__mutex_unlock_common_slowpath(struct mutex *lock, int nested)
 {
-       struct mutex *lock = container_of(lock_count, struct mutex, count);
        unsigned long flags;
 
        /*
-        * some architectures leave the lock unlocked in the fastpath failure
+        * As a performance measurement, release the lock before doing other
+        * wakeup related duties to follow. This allows other tasks to acquire
+        * the lock sooner, while still handling cleanups in past unlock calls.
+        * This can be done as we do not enforce strict equivalence between the
+        * mutex counter and wait_list.
+        *
+        *
+        * Some architectures leave the lock unlocked in the fastpath failure
         * case, others need to leave it locked. In the later case we have to
-        * unlock it here
+        * unlock it here - as the lock counter is currently 0 or negative.
         */
        if (__mutex_slowpath_needs_to_unlock())
                atomic_set(&lock->count, 1);
@@ -716,7 +754,9 @@ __mutex_unlock_common_slowpath(atomic_t *lock_count, int nested)
 __visible void
 __mutex_unlock_slowpath(atomic_t *lock_count)
 {
-       __mutex_unlock_common_slowpath(lock_count, 1);
+       struct mutex *lock = container_of(lock_count, struct mutex, count);
+
+       __mutex_unlock_common_slowpath(lock, 1);
 }
 
 #ifndef CONFIG_DEBUG_LOCK_ALLOC
index 4115fbf83b12ed11e2b05bc7cccfb5933cb3311d..5cda397607f25011eedcc4cbcab7aeef9d211321 100644 (file)
@@ -16,7 +16,7 @@
 #define mutex_remove_waiter(lock, waiter, ti) \
                __list_del((waiter)->list.prev, (waiter)->list.next)
 
-#ifdef CONFIG_SMP
+#ifdef CONFIG_MUTEX_SPIN_ON_OWNER
 static inline void mutex_set_owner(struct mutex *lock)
 {
        lock->owner = current;
index a0ea2a141b3b0fff9614435559dc9e140f31ea69..7c98873a30777f131541a36889631c1efea79320 100644 (file)
@@ -8,7 +8,7 @@
  *  Copyright (C) 2005 Kihon Technologies Inc., Steven Rostedt
  *  Copyright (C) 2006 Esben Nielsen
  *
- *  See Documentation/rt-mutex-design.txt for details.
+ *  See Documentation/locking/rt-mutex-design.txt for details.
  */
 #include <linux/spinlock.h>
 #include <linux/export.h>
index d6203faf2eb1f15522b720605bab13f6008fab4d..7628c3fc37ca30902a6952fd86ffd4387e70eb57 100644 (file)
@@ -246,19 +246,22 @@ struct rw_semaphore __sched *rwsem_down_read_failed(struct rw_semaphore *sem)
 
        return sem;
 }
+EXPORT_SYMBOL(rwsem_down_read_failed);
 
 static inline bool rwsem_try_write_lock(long count, struct rw_semaphore *sem)
 {
-       if (!(count & RWSEM_ACTIVE_MASK)) {
-               /* try acquiring the write lock */
-               if (sem->count == RWSEM_WAITING_BIAS &&
-                   cmpxchg(&sem->count, RWSEM_WAITING_BIAS,
-                           RWSEM_ACTIVE_WRITE_BIAS) == RWSEM_WAITING_BIAS) {
-                       if (!list_is_singular(&sem->wait_list))
-                               rwsem_atomic_update(RWSEM_WAITING_BIAS, sem);
-                       return true;
-               }
+       /*
+        * Try acquiring the write lock. Check count first in order
+        * to reduce unnecessary expensive cmpxchg() operations.
+        */
+       if (count == RWSEM_WAITING_BIAS &&
+           cmpxchg(&sem->count, RWSEM_WAITING_BIAS,
+                   RWSEM_ACTIVE_WRITE_BIAS) == RWSEM_WAITING_BIAS) {
+               if (!list_is_singular(&sem->wait_list))
+                       rwsem_atomic_update(RWSEM_WAITING_BIAS, sem);
+               return true;
        }
+
        return false;
 }
 
@@ -465,6 +468,7 @@ struct rw_semaphore __sched *rwsem_down_write_failed(struct rw_semaphore *sem)
 
        return sem;
 }
+EXPORT_SYMBOL(rwsem_down_write_failed);
 
 /*
  * handle waking up a waiter on the semaphore
@@ -485,6 +489,7 @@ struct rw_semaphore *rwsem_wake(struct rw_semaphore *sem)
 
        return sem;
 }
+EXPORT_SYMBOL(rwsem_wake);
 
 /*
  * downgrade a write lock into a read lock
@@ -506,8 +511,4 @@ struct rw_semaphore *rwsem_downgrade_wake(struct rw_semaphore *sem)
 
        return sem;
 }
-
-EXPORT_SYMBOL(rwsem_down_read_failed);
-EXPORT_SYMBOL(rwsem_down_write_failed);
-EXPORT_SYMBOL(rwsem_wake);
 EXPORT_SYMBOL(rwsem_downgrade_wake);
index 6815171a4fff4166450ac831729112b75ec64881..b8120abe594b893e164791afb0e4527d6ed3886c 100644 (file)
@@ -36,7 +36,7 @@
 static noinline void __down(struct semaphore *sem);
 static noinline int __down_interruptible(struct semaphore *sem);
 static noinline int __down_killable(struct semaphore *sem);
-static noinline int __down_timeout(struct semaphore *sem, long jiffies);
+static noinline int __down_timeout(struct semaphore *sem, long timeout);
 static noinline void __up(struct semaphore *sem);
 
 /**
@@ -145,14 +145,14 @@ EXPORT_SYMBOL(down_trylock);
 /**
  * down_timeout - acquire the semaphore within a specified time
  * @sem: the semaphore to be acquired
- * @jiffies: how long to wait before failing
+ * @timeout: how long to wait before failing
  *
  * Attempts to acquire the semaphore.  If no more tasks are allowed to
  * acquire the semaphore, calling this function will put the task to sleep.
  * If the semaphore is not released within the specified number of jiffies,
  * this function returns -ETIME.  It returns 0 if the semaphore was acquired.
  */
-int down_timeout(struct semaphore *sem, long jiffies)
+int down_timeout(struct semaphore *sem, long timeout)
 {
        unsigned long flags;
        int result = 0;
@@ -161,7 +161,7 @@ int down_timeout(struct semaphore *sem, long jiffies)
        if (likely(sem->count > 0))
                sem->count--;
        else
-               result = __down_timeout(sem, jiffies);
+               result = __down_timeout(sem, timeout);
        raw_spin_unlock_irqrestore(&sem->lock, flags);
 
        return result;
@@ -248,9 +248,9 @@ static noinline int __sched __down_killable(struct semaphore *sem)
        return __down_common(sem, TASK_KILLABLE, MAX_SCHEDULE_TIMEOUT);
 }
 
-static noinline int __sched __down_timeout(struct semaphore *sem, long jiffies)
+static noinline int __sched __down_timeout(struct semaphore *sem, long timeout)
 {
-       return __down_common(sem, TASK_UNINTERRUPTIBLE, jiffies);
+       return __down_common(sem, TASK_UNINTERRUPTIBLE, timeout);
 }
 
 static noinline void __sched __up(struct semaphore *sem)
index 041b5899d5e2d0c70f791224d4e5697ddff2880b..db97b791390fa0ef3f4aa10d1bd5e53fe6e921b8 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/string.h>
 #include <linux/errno.h>
 #include <linux/module.h>
+#include <linux/moduleparam.h>
 #include <linux/device.h>
 #include <linux/err.h>
 #include <linux/slab.h>
@@ -513,8 +514,6 @@ EXPORT_SYMBOL(param_ops_string);
 #define to_module_attr(n) container_of(n, struct module_attribute, attr)
 #define to_module_kobject(n) container_of(n, struct module_kobject, kobj)
 
-extern struct kernel_param __start___param[], __stop___param[];
-
 struct param_attribute
 {
        struct module_attribute mattr;
@@ -774,7 +773,7 @@ static struct module_kobject * __init locate_module_kobject(const char *name)
 }
 
 static void __init kernel_add_sysfs_param(const char *name,
-                                         struct kernel_param *kparam,
+                                         const struct kernel_param *kparam,
                                          unsigned int name_skip)
 {
        struct module_kobject *mk;
@@ -809,7 +808,7 @@ static void __init kernel_add_sysfs_param(const char *name,
  */
 static void __init param_sysfs_builtin(void)
 {
-       struct kernel_param *kp;
+       const struct kernel_param *kp;
        unsigned int name_len;
        char modname[MODULE_NAME_LEN];
 
index 1ce770687ea83c6a05c562591fe475b5f2cc52d0..e3962d63e3681408f43f90b228b63facc29ba4e7 100644 (file)
@@ -267,7 +267,6 @@ static u32 clear_idx;
 #define LOG_ALIGN __alignof__(struct printk_log)
 #endif
 #define __LOG_BUF_LEN (1 << CONFIG_LOG_BUF_SHIFT)
-#define __LOG_CPU_MAX_BUF_LEN (1 << CONFIG_LOG_CPU_MAX_BUF_SHIFT)
 static char __log_buf[__LOG_BUF_LEN] __aligned(LOG_ALIGN);
 static char *log_buf = __log_buf;
 static u32 log_buf_len = __LOG_BUF_LEN;
@@ -519,14 +518,13 @@ struct devkmsg_user {
        char buf[8192];
 };
 
-static ssize_t devkmsg_writev(struct kiocb *iocb, const struct iovec *iv,
-                             unsigned long count, loff_t pos)
+static ssize_t devkmsg_write(struct kiocb *iocb, struct iov_iter *from)
 {
        char *buf, *line;
        int i;
        int level = default_message_loglevel;
        int facility = 1;       /* LOG_USER */
-       size_t len = iov_length(iv, count);
+       size_t len = iocb->ki_nbytes;
        ssize_t ret = len;
 
        if (len > LOG_LINE_MAX)
@@ -535,13 +533,10 @@ static ssize_t devkmsg_writev(struct kiocb *iocb, const struct iovec *iv,
        if (buf == NULL)
                return -ENOMEM;
 
-       line = buf;
-       for (i = 0; i < count; i++) {
-               if (copy_from_user(line, iv[i].iov_base, iv[i].iov_len)) {
-                       ret = -EFAULT;
-                       goto out;
-               }
-               line += iv[i].iov_len;
+       buf[len] = '\0';
+       if (copy_from_iter(buf, len, from) != len) {
+               kfree(buf);
+               return -EFAULT;
        }
 
        /*
@@ -567,10 +562,8 @@ static ssize_t devkmsg_writev(struct kiocb *iocb, const struct iovec *iv,
                        line = endp;
                }
        }
-       line[len] = '\0';
 
        printk_emit(facility, level, NULL, 0, "%s", line);
-out:
        kfree(buf);
        return ret;
 }
@@ -802,7 +795,7 @@ static int devkmsg_release(struct inode *inode, struct file *file)
 const struct file_operations kmsg_fops = {
        .open = devkmsg_open,
        .read = devkmsg_read,
-       .aio_write = devkmsg_writev,
+       .write_iter = devkmsg_write,
        .llseek = devkmsg_llseek,
        .poll = devkmsg_poll,
        .release = devkmsg_release,
@@ -858,6 +851,9 @@ static int __init log_buf_len_setup(char *str)
 }
 early_param("log_buf_len", log_buf_len_setup);
 
+#ifdef CONFIG_SMP
+#define __LOG_CPU_MAX_BUF_LEN (1 << CONFIG_LOG_CPU_MAX_BUF_SHIFT)
+
 static void __init log_buf_add_cpu(void)
 {
        unsigned int cpu_extra;
@@ -884,6 +880,9 @@ static void __init log_buf_add_cpu(void)
 
        log_buf_len_update(cpu_extra + __LOG_BUF_LEN);
 }
+#else /* !CONFIG_SMP */
+static inline void log_buf_add_cpu(void) {}
+#endif /* CONFIG_SMP */
 
 void __init setup_log_buf(int early)
 {
@@ -1680,12 +1679,7 @@ asmlinkage int vprintk_emit(int facility, int level,
         * The printf needs to come first; we need the syslog
         * prefix which might be passed-in as a parameter.
         */
-       if (in_sched)
-               text_len = scnprintf(text, sizeof(textbuf),
-                                    KERN_WARNING "[sched_delayed] ");
-
-       text_len += vscnprintf(text + text_len,
-                              sizeof(textbuf) - text_len, fmt, args);
+       text_len = vscnprintf(text, sizeof(textbuf), fmt, args);
 
        /* mark and strip a trailing newline */
        if (text_len && text[text_len-1] == '\n') {
index 948a7693748ed3d0be04fb022d5ac6a195903e3c..240fa9094f830cdc56565cb2ceb8233984564ac3 100644 (file)
 #include <linux/trace_clock.h>
 #include <asm/byteorder.h>
 #include <linux/torture.h>
+#include <linux/vmalloc.h>
 
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Paul E. McKenney <paulmck@us.ibm.com> and Josh Triplett <josh@joshtriplett.org>");
 
 
+torture_param(int, cbflood_inter_holdoff, HZ,
+             "Holdoff between floods (jiffies)");
+torture_param(int, cbflood_intra_holdoff, 1,
+             "Holdoff between bursts (jiffies)");
+torture_param(int, cbflood_n_burst, 3, "# bursts in flood, zero to disable");
+torture_param(int, cbflood_n_per_burst, 20000,
+             "# callbacks per burst in flood");
 torture_param(int, fqs_duration, 0,
              "Duration of fqs bursts (us), 0 to disable");
 torture_param(int, fqs_holdoff, 0, "Holdoff time within fqs bursts (us)");
@@ -96,10 +104,12 @@ module_param(torture_type, charp, 0444);
 MODULE_PARM_DESC(torture_type, "Type of RCU to torture (rcu, rcu_bh, ...)");
 
 static int nrealreaders;
+static int ncbflooders;
 static struct task_struct *writer_task;
 static struct task_struct **fakewriter_tasks;
 static struct task_struct **reader_tasks;
 static struct task_struct *stats_task;
+static struct task_struct **cbflood_task;
 static struct task_struct *fqs_task;
 static struct task_struct *boost_tasks[NR_CPUS];
 static struct task_struct *stall_task;
@@ -138,6 +148,7 @@ static long n_rcu_torture_boosts;
 static long n_rcu_torture_timers;
 static long n_barrier_attempts;
 static long n_barrier_successes;
+static atomic_long_t n_cbfloods;
 static struct list_head rcu_torture_removed;
 
 static int rcu_torture_writer_state;
@@ -157,9 +168,9 @@ static int rcu_torture_writer_state;
 #else
 #define RCUTORTURE_RUNNABLE_INIT 0
 #endif
-int rcutorture_runnable = RCUTORTURE_RUNNABLE_INIT;
-module_param(rcutorture_runnable, int, 0444);
-MODULE_PARM_DESC(rcutorture_runnable, "Start rcutorture at boot");
+static int torture_runnable = RCUTORTURE_RUNNABLE_INIT;
+module_param(torture_runnable, int, 0444);
+MODULE_PARM_DESC(torture_runnable, "Start rcutorture at boot");
 
 #if defined(CONFIG_RCU_BOOST) && !defined(CONFIG_HOTPLUG_CPU)
 #define rcu_can_boost() 1
@@ -182,7 +193,7 @@ static u64 notrace rcu_trace_clock_local(void)
 #endif /* #else #ifdef CONFIG_RCU_TRACE */
 
 static unsigned long boost_starttime;  /* jiffies of next boost test start. */
-DEFINE_MUTEX(boost_mutex);             /* protect setting boost_starttime */
+static DEFINE_MUTEX(boost_mutex);      /* protect setting boost_starttime */
                                        /*  and boost task create/destroy. */
 static atomic_t barrier_cbs_count;     /* Barrier callbacks registered. */
 static bool barrier_phase;             /* Test phase. */
@@ -242,7 +253,7 @@ struct rcu_torture_ops {
        void (*call)(struct rcu_head *head, void (*func)(struct rcu_head *rcu));
        void (*cb_barrier)(void);
        void (*fqs)(void);
-       void (*stats)(char *page);
+       void (*stats)(void);
        int irq_capable;
        int can_boost;
        const char *name;
@@ -525,21 +536,21 @@ static void srcu_torture_barrier(void)
        srcu_barrier(&srcu_ctl);
 }
 
-static void srcu_torture_stats(char *page)
+static void srcu_torture_stats(void)
 {
        int cpu;
        int idx = srcu_ctl.completed & 0x1;
 
-       page += sprintf(page, "%s%s per-CPU(idx=%d):",
-                      torture_type, TORTURE_FLAG, idx);
+       pr_alert("%s%s per-CPU(idx=%d):",
+                torture_type, TORTURE_FLAG, idx);
        for_each_possible_cpu(cpu) {
                long c0, c1;
 
                c0 = (long)per_cpu_ptr(srcu_ctl.per_cpu_ref, cpu)->c[!idx];
                c1 = (long)per_cpu_ptr(srcu_ctl.per_cpu_ref, cpu)->c[idx];
-               page += sprintf(page, " %d(%ld,%ld)", cpu, c0, c1);
+               pr_cont(" %d(%ld,%ld)", cpu, c0, c1);
        }
-       sprintf(page, "\n");
+       pr_cont("\n");
 }
 
 static void srcu_torture_synchronize_expedited(void)
@@ -601,6 +612,52 @@ static struct rcu_torture_ops sched_ops = {
        .name           = "sched"
 };
 
+#ifdef CONFIG_TASKS_RCU
+
+/*
+ * Definitions for RCU-tasks torture testing.
+ */
+
+static int tasks_torture_read_lock(void)
+{
+       return 0;
+}
+
+static void tasks_torture_read_unlock(int idx)
+{
+}
+
+static void rcu_tasks_torture_deferred_free(struct rcu_torture *p)
+{
+       call_rcu_tasks(&p->rtort_rcu, rcu_torture_cb);
+}
+
+static struct rcu_torture_ops tasks_ops = {
+       .ttype          = RCU_TASKS_FLAVOR,
+       .init           = rcu_sync_torture_init,
+       .readlock       = tasks_torture_read_lock,
+       .read_delay     = rcu_read_delay,  /* just reuse rcu's version. */
+       .readunlock     = tasks_torture_read_unlock,
+       .completed      = rcu_no_completed,
+       .deferred_free  = rcu_tasks_torture_deferred_free,
+       .sync           = synchronize_rcu_tasks,
+       .exp_sync       = synchronize_rcu_tasks,
+       .call           = call_rcu_tasks,
+       .cb_barrier     = rcu_barrier_tasks,
+       .fqs            = NULL,
+       .stats          = NULL,
+       .irq_capable    = 1,
+       .name           = "tasks"
+};
+
+#define RCUTORTURE_TASKS_OPS &tasks_ops,
+
+#else /* #ifdef CONFIG_TASKS_RCU */
+
+#define RCUTORTURE_TASKS_OPS
+
+#endif /* #else #ifdef CONFIG_TASKS_RCU */
+
 /*
  * RCU torture priority-boost testing.  Runs one real-time thread per
  * CPU for moderate bursts, repeatedly registering RCU callbacks and
@@ -667,7 +724,7 @@ static int rcu_torture_boost(void *arg)
                                }
                                call_rcu_time = jiffies;
                        }
-                       cond_resched();
+                       cond_resched_rcu_qs();
                        stutter_wait("rcu_torture_boost");
                        if (torture_must_stop())
                                goto checkwait;
@@ -707,6 +764,58 @@ checkwait: stutter_wait("rcu_torture_boost");
        return 0;
 }
 
+static void rcu_torture_cbflood_cb(struct rcu_head *rhp)
+{
+}
+
+/*
+ * RCU torture callback-flood kthread.  Repeatedly induces bursts of calls
+ * to call_rcu() or analogous, increasing the probability of occurrence
+ * of callback-overflow corner cases.
+ */
+static int
+rcu_torture_cbflood(void *arg)
+{
+       int err = 1;
+       int i;
+       int j;
+       struct rcu_head *rhp;
+
+       if (cbflood_n_per_burst > 0 &&
+           cbflood_inter_holdoff > 0 &&
+           cbflood_intra_holdoff > 0 &&
+           cur_ops->call &&
+           cur_ops->cb_barrier) {
+               rhp = vmalloc(sizeof(*rhp) *
+                             cbflood_n_burst * cbflood_n_per_burst);
+               err = !rhp;
+       }
+       if (err) {
+               VERBOSE_TOROUT_STRING("rcu_torture_cbflood disabled: Bad args or OOM");
+               while (!torture_must_stop())
+                       schedule_timeout_interruptible(HZ);
+               return 0;
+       }
+       VERBOSE_TOROUT_STRING("rcu_torture_cbflood task started");
+       do {
+               schedule_timeout_interruptible(cbflood_inter_holdoff);
+               atomic_long_inc(&n_cbfloods);
+               WARN_ON(signal_pending(current));
+               for (i = 0; i < cbflood_n_burst; i++) {
+                       for (j = 0; j < cbflood_n_per_burst; j++) {
+                               cur_ops->call(&rhp[i * cbflood_n_per_burst + j],
+                                             rcu_torture_cbflood_cb);
+                       }
+                       schedule_timeout_interruptible(cbflood_intra_holdoff);
+                       WARN_ON(signal_pending(current));
+               }
+               cur_ops->cb_barrier();
+               stutter_wait("rcu_torture_cbflood");
+       } while (!torture_must_stop());
+       torture_kthread_stopping("rcu_torture_cbflood");
+       return 0;
+}
+
 /*
  * RCU torture force-quiescent-state kthread.  Repeatedly induces
  * bursts of calls to force_quiescent_state(), increasing the probability
@@ -1019,7 +1128,7 @@ rcu_torture_reader(void *arg)
                __this_cpu_inc(rcu_torture_batch[completed]);
                preempt_enable();
                cur_ops->readunlock(idx);
-               cond_resched();
+               cond_resched_rcu_qs();
                stutter_wait("rcu_torture_reader");
        } while (!torture_must_stop());
        if (irqreader && cur_ops->irq_capable) {
@@ -1031,10 +1140,15 @@ rcu_torture_reader(void *arg)
 }
 
 /*
- * Create an RCU-torture statistics message in the specified buffer.
+ * Print torture statistics.  Caller must ensure that there is only
+ * one call to this function at a given time!!!  This is normally
+ * accomplished by relying on the module system to only have one copy
+ * of the module loaded, and then by giving the rcu_torture_stats
+ * kthread full control (or the init/cleanup functions when rcu_torture_stats
+ * thread is not running).
  */
 static void
-rcu_torture_printk(char *page)
+rcu_torture_stats_print(void)
 {
        int cpu;
        int i;
@@ -1052,55 +1166,61 @@ rcu_torture_printk(char *page)
                if (pipesummary[i] != 0)
                        break;
        }
-       page += sprintf(page, "%s%s ", torture_type, TORTURE_FLAG);
-       page += sprintf(page,
-                      "rtc: %p ver: %lu tfle: %d rta: %d rtaf: %d rtf: %d ",
-                      rcu_torture_current,
-                      rcu_torture_current_version,
-                      list_empty(&rcu_torture_freelist),
-                      atomic_read(&n_rcu_torture_alloc),
-                      atomic_read(&n_rcu_torture_alloc_fail),
-                      atomic_read(&n_rcu_torture_free));
-       page += sprintf(page, "rtmbe: %d rtbke: %ld rtbre: %ld ",
-                      atomic_read(&n_rcu_torture_mberror),
-                      n_rcu_torture_boost_ktrerror,
-                      n_rcu_torture_boost_rterror);
-       page += sprintf(page, "rtbf: %ld rtb: %ld nt: %ld ",
-                      n_rcu_torture_boost_failure,
-                      n_rcu_torture_boosts,
-                      n_rcu_torture_timers);
-       page = torture_onoff_stats(page);
-       page += sprintf(page, "barrier: %ld/%ld:%ld",
-                      n_barrier_successes,
-                      n_barrier_attempts,
-                      n_rcu_torture_barrier_error);
-       page += sprintf(page, "\n%s%s ", torture_type, TORTURE_FLAG);
+
+       pr_alert("%s%s ", torture_type, TORTURE_FLAG);
+       pr_cont("rtc: %p ver: %lu tfle: %d rta: %d rtaf: %d rtf: %d ",
+               rcu_torture_current,
+               rcu_torture_current_version,
+               list_empty(&rcu_torture_freelist),
+               atomic_read(&n_rcu_torture_alloc),
+               atomic_read(&n_rcu_torture_alloc_fail),
+               atomic_read(&n_rcu_torture_free));
+       pr_cont("rtmbe: %d rtbke: %ld rtbre: %ld ",
+               atomic_read(&n_rcu_torture_mberror),
+               n_rcu_torture_boost_ktrerror,
+               n_rcu_torture_boost_rterror);
+       pr_cont("rtbf: %ld rtb: %ld nt: %ld ",
+               n_rcu_torture_boost_failure,
+               n_rcu_torture_boosts,
+               n_rcu_torture_timers);
+       torture_onoff_stats();
+       pr_cont("barrier: %ld/%ld:%ld ",
+               n_barrier_successes,
+               n_barrier_attempts,
+               n_rcu_torture_barrier_error);
+       pr_cont("cbflood: %ld\n", atomic_long_read(&n_cbfloods));
+
+       pr_alert("%s%s ", torture_type, TORTURE_FLAG);
        if (atomic_read(&n_rcu_torture_mberror) != 0 ||
            n_rcu_torture_barrier_error != 0 ||
            n_rcu_torture_boost_ktrerror != 0 ||
            n_rcu_torture_boost_rterror != 0 ||
            n_rcu_torture_boost_failure != 0 ||
            i > 1) {
-               page += sprintf(page, "!!! ");
+               pr_cont("%s", "!!! ");
                atomic_inc(&n_rcu_torture_error);
                WARN_ON_ONCE(1);
        }
-       page += sprintf(page, "Reader Pipe: ");
+       pr_cont("Reader Pipe: ");
        for (i = 0; i < RCU_TORTURE_PIPE_LEN + 1; i++)
-               page += sprintf(page, " %ld", pipesummary[i]);
-       page += sprintf(page, "\n%s%s ", torture_type, TORTURE_FLAG);
-       page += sprintf(page, "Reader Batch: ");
+               pr_cont(" %ld", pipesummary[i]);
+       pr_cont("\n");
+
+       pr_alert("%s%s ", torture_type, TORTURE_FLAG);
+       pr_cont("Reader Batch: ");
        for (i = 0; i < RCU_TORTURE_PIPE_LEN + 1; i++)
-               page += sprintf(page, " %ld", batchsummary[i]);
-       page += sprintf(page, "\n%s%s ", torture_type, TORTURE_FLAG);
-       page += sprintf(page, "Free-Block Circulation: ");
+               pr_cont(" %ld", batchsummary[i]);
+       pr_cont("\n");
+
+       pr_alert("%s%s ", torture_type, TORTURE_FLAG);
+       pr_cont("Free-Block Circulation: ");
        for (i = 0; i < RCU_TORTURE_PIPE_LEN + 1; i++) {
-               page += sprintf(page, " %d",
-                              atomic_read(&rcu_torture_wcount[i]));
+               pr_cont(" %d", atomic_read(&rcu_torture_wcount[i]));
        }
-       page += sprintf(page, "\n");
+       pr_cont("\n");
+
        if (cur_ops->stats)
-               cur_ops->stats(page);
+               cur_ops->stats();
        if (rtcv_snap == rcu_torture_current_version &&
            rcu_torture_current != NULL) {
                int __maybe_unused flags;
@@ -1109,40 +1229,15 @@ rcu_torture_printk(char *page)
 
                rcutorture_get_gp_data(cur_ops->ttype,
                                       &flags, &gpnum, &completed);
-               page += sprintf(page,
-                               "??? Writer stall state %d g%lu c%lu f%#x\n",
-                               rcu_torture_writer_state,
-                               gpnum, completed, flags);
+               pr_alert("??? Writer stall state %d g%lu c%lu f%#x\n",
+                        rcu_torture_writer_state,
+                        gpnum, completed, flags);
                show_rcu_gp_kthreads();
                rcutorture_trace_dump();
        }
        rtcv_snap = rcu_torture_current_version;
 }
 
-/*
- * Print torture statistics.  Caller must ensure that there is only
- * one call to this function at a given time!!!  This is normally
- * accomplished by relying on the module system to only have one copy
- * of the module loaded, and then by giving the rcu_torture_stats
- * kthread full control (or the init/cleanup functions when rcu_torture_stats
- * thread is not running).
- */
-static void
-rcu_torture_stats_print(void)
-{
-       int size = nr_cpu_ids * 200 + 8192;
-       char *buf;
-
-       buf = kmalloc(size, GFP_KERNEL);
-       if (!buf) {
-               pr_err("rcu-torture: Out of memory, need: %d", size);
-               return;
-       }
-       rcu_torture_printk(buf);
-       pr_alert("%s", buf);
-       kfree(buf);
-}
-
 /*
  * Periodically prints torture statistics, if periodic statistics printing
  * was specified via the stat_interval module parameter.
@@ -1295,7 +1390,8 @@ static int rcu_torture_barrier_cbs(void *arg)
                if (atomic_dec_and_test(&barrier_cbs_count))
                        wake_up(&barrier_wq);
        } while (!torture_must_stop());
-       cur_ops->cb_barrier();
+       if (cur_ops->cb_barrier != NULL)
+               cur_ops->cb_barrier();
        destroy_rcu_head_on_stack(&rcu);
        torture_kthread_stopping("rcu_torture_barrier_cbs");
        return 0;
@@ -1418,7 +1514,7 @@ rcu_torture_cleanup(void)
        int i;
 
        rcutorture_record_test_transition();
-       if (torture_cleanup()) {
+       if (torture_cleanup_begin()) {
                if (cur_ops->cb_barrier != NULL)
                        cur_ops->cb_barrier();
                return;
@@ -1447,6 +1543,8 @@ rcu_torture_cleanup(void)
 
        torture_stop_kthread(rcu_torture_stats, stats_task);
        torture_stop_kthread(rcu_torture_fqs, fqs_task);
+       for (i = 0; i < ncbflooders; i++)
+               torture_stop_kthread(rcu_torture_cbflood, cbflood_task[i]);
        if ((test_boost == 1 && cur_ops->can_boost) ||
            test_boost == 2) {
                unregister_cpu_notifier(&rcutorture_cpu_nb);
@@ -1468,6 +1566,7 @@ rcu_torture_cleanup(void)
                                               "End of test: RCU_HOTPLUG");
        else
                rcu_torture_print_module_parms(cur_ops, "End of test: SUCCESS");
+       torture_cleanup_end();
 }
 
 #ifdef CONFIG_DEBUG_OBJECTS_RCU_HEAD
@@ -1534,9 +1633,10 @@ rcu_torture_init(void)
        int firsterr = 0;
        static struct rcu_torture_ops *torture_ops[] = {
                &rcu_ops, &rcu_bh_ops, &rcu_busted_ops, &srcu_ops, &sched_ops,
+               RCUTORTURE_TASKS_OPS
        };
 
-       if (!torture_init_begin(torture_type, verbose, &rcutorture_runnable))
+       if (!torture_init_begin(torture_type, verbose, &torture_runnable))
                return -EBUSY;
 
        /* Process args and tell the world that the torturer is on the job. */
@@ -1693,6 +1793,24 @@ rcu_torture_init(void)
                goto unwind;
        if (object_debug)
                rcu_test_debug_objects();
+       if (cbflood_n_burst > 0) {
+               /* Create the cbflood threads */
+               ncbflooders = (num_online_cpus() + 3) / 4;
+               cbflood_task = kcalloc(ncbflooders, sizeof(*cbflood_task),
+                                      GFP_KERNEL);
+               if (!cbflood_task) {
+                       VERBOSE_TOROUT_ERRSTRING("out of memory");
+                       firsterr = -ENOMEM;
+                       goto unwind;
+               }
+               for (i = 0; i < ncbflooders; i++) {
+                       firsterr = torture_create_kthread(rcu_torture_cbflood,
+                                                         NULL,
+                                                         cbflood_task[i]);
+                       if (firsterr)
+                               goto unwind;
+               }
+       }
        rcutorture_record_test_transition();
        torture_init_end();
        return 0;
index d9efcc13008c00201c130f87135348c7238118ff..c0623fc471256abb404a5d49e8d4d805b7fb4ba7 100644 (file)
@@ -51,7 +51,7 @@ static long long rcu_dynticks_nesting = DYNTICK_TASK_EXIT_IDLE;
 
 #include "tiny_plugin.h"
 
-/* Common code for rcu_idle_enter() and rcu_irq_exit(), see kernel/rcutree.c. */
+/* Common code for rcu_idle_enter() and rcu_irq_exit(), see kernel/rcu/tree.c. */
 static void rcu_idle_enter_common(long long newval)
 {
        if (newval) {
@@ -62,7 +62,7 @@ static void rcu_idle_enter_common(long long newval)
        }
        RCU_TRACE(trace_rcu_dyntick(TPS("Start"),
                                    rcu_dynticks_nesting, newval));
-       if (!is_idle_task(current)) {
+       if (IS_ENABLED(CONFIG_RCU_TRACE) && !is_idle_task(current)) {
                struct task_struct *idle __maybe_unused = idle_task(smp_processor_id());
 
                RCU_TRACE(trace_rcu_dyntick(TPS("Entry error: not idle task"),
@@ -72,7 +72,7 @@ static void rcu_idle_enter_common(long long newval)
                          current->pid, current->comm,
                          idle->pid, idle->comm); /* must be idle task! */
        }
-       rcu_sched_qs(0); /* implies rcu_bh_qsctr_inc(0) */
+       rcu_sched_qs(); /* implies rcu_bh_inc() */
        barrier();
        rcu_dynticks_nesting = newval;
 }
@@ -114,7 +114,7 @@ void rcu_irq_exit(void)
 }
 EXPORT_SYMBOL_GPL(rcu_irq_exit);
 
-/* Common code for rcu_idle_exit() and rcu_irq_enter(), see kernel/rcutree.c. */
+/* Common code for rcu_idle_exit() and rcu_irq_enter(), see kernel/rcu/tree.c. */
 static void rcu_idle_exit_common(long long oldval)
 {
        if (oldval) {
@@ -123,7 +123,7 @@ static void rcu_idle_exit_common(long long oldval)
                return;
        }
        RCU_TRACE(trace_rcu_dyntick(TPS("End"), oldval, rcu_dynticks_nesting));
-       if (!is_idle_task(current)) {
+       if (IS_ENABLED(CONFIG_RCU_TRACE) && !is_idle_task(current)) {
                struct task_struct *idle __maybe_unused = idle_task(smp_processor_id());
 
                RCU_TRACE(trace_rcu_dyntick(TPS("Exit error: not idle task"),
@@ -217,7 +217,7 @@ static int rcu_qsctr_help(struct rcu_ctrlblk *rcp)
  * are at it, given that any rcu quiescent state is also an rcu_bh
  * quiescent state.  Use "+" instead of "||" to defeat short circuiting.
  */
-void rcu_sched_qs(int cpu)
+void rcu_sched_qs(void)
 {
        unsigned long flags;
 
@@ -231,7 +231,7 @@ void rcu_sched_qs(int cpu)
 /*
  * Record an rcu_bh quiescent state.
  */
-void rcu_bh_qs(int cpu)
+void rcu_bh_qs(void)
 {
        unsigned long flags;
 
@@ -251,9 +251,11 @@ void rcu_check_callbacks(int cpu, int user)
 {
        RCU_TRACE(check_cpu_stalls());
        if (user || rcu_is_cpu_rrupt_from_idle())
-               rcu_sched_qs(cpu);
+               rcu_sched_qs();
        else if (!in_softirq())
-               rcu_bh_qs(cpu);
+               rcu_bh_qs();
+       if (user)
+               rcu_note_voluntary_context_switch(current);
 }
 
 /*
index 1b70cb6fbe3ccda0466f3f0004865d82cdd9399d..133e47223095d76fd1203f949a955009d1075688 100644 (file)
@@ -79,9 +79,18 @@ static struct lock_class_key rcu_fqs_class[RCU_NUM_LVLS];
  * the tracing userspace tools to be able to decipher the string
  * address to the matching string.
  */
-#define RCU_STATE_INITIALIZER(sname, sabbr, cr) \
+#ifdef CONFIG_TRACING
+# define DEFINE_RCU_TPS(sname) \
 static char sname##_varname[] = #sname; \
-static const char *tp_##sname##_varname __used __tracepoint_string = sname##_varname; \
+static const char *tp_##sname##_varname __used __tracepoint_string = sname##_varname;
+# define RCU_STATE_NAME(sname) sname##_varname
+#else
+# define DEFINE_RCU_TPS(sname)
+# define RCU_STATE_NAME(sname) __stringify(sname)
+#endif
+
+#define RCU_STATE_INITIALIZER(sname, sabbr, cr) \
+DEFINE_RCU_TPS(sname) \
 struct rcu_state sname##_state = { \
        .level = { &sname##_state.node[0] }, \
        .call = cr, \
@@ -93,7 +102,7 @@ struct rcu_state sname##_state = { \
        .orphan_donetail = &sname##_state.orphan_donelist, \
        .barrier_mutex = __MUTEX_INITIALIZER(sname##_state.barrier_mutex), \
        .onoff_mutex = __MUTEX_INITIALIZER(sname##_state.onoff_mutex), \
-       .name = sname##_varname, \
+       .name = RCU_STATE_NAME(sname), \
        .abbr = sabbr, \
 }; \
 DEFINE_PER_CPU(struct rcu_data, sname##_data)
@@ -188,22 +197,24 @@ static int rcu_gp_in_progress(struct rcu_state *rsp)
  * one since the start of the grace period, this just sets a flag.
  * The caller must have disabled preemption.
  */
-void rcu_sched_qs(int cpu)
+void rcu_sched_qs(void)
 {
-       struct rcu_data *rdp = &per_cpu(rcu_sched_data, cpu);
-
-       if (rdp->passed_quiesce == 0)
-               trace_rcu_grace_period(TPS("rcu_sched"), rdp->gpnum, TPS("cpuqs"));
-       rdp->passed_quiesce = 1;
+       if (!__this_cpu_read(rcu_sched_data.passed_quiesce)) {
+               trace_rcu_grace_period(TPS("rcu_sched"),
+                                      __this_cpu_read(rcu_sched_data.gpnum),
+                                      TPS("cpuqs"));
+               __this_cpu_write(rcu_sched_data.passed_quiesce, 1);
+       }
 }
 
-void rcu_bh_qs(int cpu)
+void rcu_bh_qs(void)
 {
-       struct rcu_data *rdp = &per_cpu(rcu_bh_data, cpu);
-
-       if (rdp->passed_quiesce == 0)
-               trace_rcu_grace_period(TPS("rcu_bh"), rdp->gpnum, TPS("cpuqs"));
-       rdp->passed_quiesce = 1;
+       if (!__this_cpu_read(rcu_bh_data.passed_quiesce)) {
+               trace_rcu_grace_period(TPS("rcu_bh"),
+                                      __this_cpu_read(rcu_bh_data.gpnum),
+                                      TPS("cpuqs"));
+               __this_cpu_write(rcu_bh_data.passed_quiesce, 1);
+       }
 }
 
 static DEFINE_PER_CPU(int, rcu_sched_qs_mask);
@@ -278,7 +289,7 @@ static void rcu_momentary_dyntick_idle(void)
 void rcu_note_context_switch(int cpu)
 {
        trace_rcu_utilization(TPS("Start context switch"));
-       rcu_sched_qs(cpu);
+       rcu_sched_qs();
        rcu_preempt_note_context_switch(cpu);
        if (unlikely(raw_cpu_read(rcu_sched_qs_mask)))
                rcu_momentary_dyntick_idle();
@@ -526,6 +537,7 @@ static void rcu_eqs_enter_common(struct rcu_dynticks *rdtp, long long oldval,
        atomic_inc(&rdtp->dynticks);
        smp_mb__after_atomic();  /* Force ordering with next sojourn. */
        WARN_ON_ONCE(atomic_read(&rdtp->dynticks) & 0x1);
+       rcu_dynticks_task_enter();
 
        /*
         * It is illegal to enter an extended quiescent state while
@@ -642,6 +654,7 @@ void rcu_irq_exit(void)
 static void rcu_eqs_exit_common(struct rcu_dynticks *rdtp, long long oldval,
                               int user)
 {
+       rcu_dynticks_task_exit();
        smp_mb__before_atomic();  /* Force ordering w/previous sojourn. */
        atomic_inc(&rdtp->dynticks);
        /* CPUs seeing atomic_inc() must see later RCU read-side crit sects */
@@ -819,7 +832,7 @@ bool notrace __rcu_is_watching(void)
  */
 bool notrace rcu_is_watching(void)
 {
-       int ret;
+       bool ret;
 
        preempt_disable();
        ret = __rcu_is_watching();
@@ -1647,7 +1660,7 @@ static int rcu_gp_init(struct rcu_state *rsp)
                                            rnp->level, rnp->grplo,
                                            rnp->grphi, rnp->qsmask);
                raw_spin_unlock_irq(&rnp->lock);
-               cond_resched();
+               cond_resched_rcu_qs();
        }
 
        mutex_unlock(&rsp->onoff_mutex);
@@ -1668,7 +1681,7 @@ static int rcu_gp_fqs(struct rcu_state *rsp, int fqs_state_in)
        if (fqs_state == RCU_SAVE_DYNTICK) {
                /* Collect dyntick-idle snapshots. */
                if (is_sysidle_rcu_state(rsp)) {
-                       isidle = 1;
+                       isidle = true;
                        maxj = jiffies - ULONG_MAX / 4;
                }
                force_qs_rnp(rsp, dyntick_save_progress_counter,
@@ -1677,14 +1690,15 @@ static int rcu_gp_fqs(struct rcu_state *rsp, int fqs_state_in)
                fqs_state = RCU_FORCE_QS;
        } else {
                /* Handle dyntick-idle and offline CPUs. */
-               isidle = 0;
+               isidle = false;
                force_qs_rnp(rsp, rcu_implicit_dynticks_qs, &isidle, &maxj);
        }
        /* Clear flag to prevent immediate re-entry. */
        if (ACCESS_ONCE(rsp->gp_flags) & RCU_GP_FLAG_FQS) {
                raw_spin_lock_irq(&rnp->lock);
                smp_mb__after_unlock_lock();
-               ACCESS_ONCE(rsp->gp_flags) &= ~RCU_GP_FLAG_FQS;
+               ACCESS_ONCE(rsp->gp_flags) =
+                       ACCESS_ONCE(rsp->gp_flags) & ~RCU_GP_FLAG_FQS;
                raw_spin_unlock_irq(&rnp->lock);
        }
        return fqs_state;
@@ -1736,7 +1750,7 @@ static void rcu_gp_cleanup(struct rcu_state *rsp)
                /* smp_mb() provided by prior unlock-lock pair. */
                nocb += rcu_future_gp_cleanup(rsp, rnp);
                raw_spin_unlock_irq(&rnp->lock);
-               cond_resched();
+               cond_resched_rcu_qs();
        }
        rnp = rcu_get_root(rsp);
        raw_spin_lock_irq(&rnp->lock);
@@ -1785,8 +1799,8 @@ static int __noreturn rcu_gp_kthread(void *arg)
                        /* Locking provides needed memory barrier. */
                        if (rcu_gp_init(rsp))
                                break;
-                       cond_resched();
-                       flush_signals(current);
+                       cond_resched_rcu_qs();
+                       WARN_ON(signal_pending(current));
                        trace_rcu_grace_period(rsp->name,
                                               ACCESS_ONCE(rsp->gpnum),
                                               TPS("reqwaitsig"));
@@ -1828,11 +1842,11 @@ static int __noreturn rcu_gp_kthread(void *arg)
                                trace_rcu_grace_period(rsp->name,
                                                       ACCESS_ONCE(rsp->gpnum),
                                                       TPS("fqsend"));
-                               cond_resched();
+                               cond_resched_rcu_qs();
                        } else {
                                /* Deal with stray signal. */
-                               cond_resched();
-                               flush_signals(current);
+                               cond_resched_rcu_qs();
+                               WARN_ON(signal_pending(current));
                                trace_rcu_grace_period(rsp->name,
                                                       ACCESS_ONCE(rsp->gpnum),
                                                       TPS("fqswaitsig"));
@@ -1928,7 +1942,7 @@ static void rcu_report_qs_rsp(struct rcu_state *rsp, unsigned long flags)
 {
        WARN_ON_ONCE(!rcu_gp_in_progress(rsp));
        raw_spin_unlock_irqrestore(&rcu_get_root(rsp)->lock, flags);
-       wake_up(&rsp->gp_wq);  /* Memory barrier implied by wake_up() path. */
+       rcu_gp_kthread_wake(rsp);
 }
 
 /*
@@ -2210,8 +2224,6 @@ static void rcu_cleanup_dead_cpu(int cpu, struct rcu_state *rsp)
        /* Adjust any no-longer-needed kthreads. */
        rcu_boost_kthread_setaffinity(rnp, -1);
 
-       /* Remove the dead CPU from the bitmasks in the rcu_node hierarchy. */
-
        /* Exclude any attempts to start a new grace period. */
        mutex_lock(&rsp->onoff_mutex);
        raw_spin_lock_irqsave(&rsp->orphan_lock, flags);
@@ -2393,8 +2405,8 @@ void rcu_check_callbacks(int cpu, int user)
                 * at least not while the corresponding CPU is online.
                 */
 
-               rcu_sched_qs(cpu);
-               rcu_bh_qs(cpu);
+               rcu_sched_qs();
+               rcu_bh_qs();
 
        } else if (!in_softirq()) {
 
@@ -2405,11 +2417,13 @@ void rcu_check_callbacks(int cpu, int user)
                 * critical section, so note it.
                 */
 
-               rcu_bh_qs(cpu);
+               rcu_bh_qs();
        }
        rcu_preempt_check_callbacks(cpu);
        if (rcu_pending(cpu))
                invoke_rcu_core();
+       if (user)
+               rcu_note_voluntary_context_switch(current);
        trace_rcu_utilization(TPS("End scheduler-tick"));
 }
 
@@ -2432,7 +2446,7 @@ static void force_qs_rnp(struct rcu_state *rsp,
        struct rcu_node *rnp;
 
        rcu_for_each_leaf_node(rsp, rnp) {
-               cond_resched();
+               cond_resched_rcu_qs();
                mask = 0;
                raw_spin_lock_irqsave(&rnp->lock, flags);
                smp_mb__after_unlock_lock();
@@ -2449,7 +2463,7 @@ static void force_qs_rnp(struct rcu_state *rsp,
                for (; cpu <= rnp->grphi; cpu++, bit <<= 1) {
                        if ((rnp->qsmask & bit) != 0) {
                                if ((rnp->qsmaskinit & bit) != 0)
-                                       *isidle = 0;
+                                       *isidle = false;
                                if (f(per_cpu_ptr(rsp->rda, cpu), isidle, maxj))
                                        mask |= bit;
                        }
@@ -2505,9 +2519,10 @@ static void force_quiescent_state(struct rcu_state *rsp)
                raw_spin_unlock_irqrestore(&rnp_old->lock, flags);
                return;  /* Someone beat us to it. */
        }
-       ACCESS_ONCE(rsp->gp_flags) |= RCU_GP_FLAG_FQS;
+       ACCESS_ONCE(rsp->gp_flags) =
+               ACCESS_ONCE(rsp->gp_flags) | RCU_GP_FLAG_FQS;
        raw_spin_unlock_irqrestore(&rnp_old->lock, flags);
-       wake_up(&rsp->gp_wq);  /* Memory barrier implied by wake_up() path. */
+       rcu_gp_kthread_wake(rsp);
 }
 
 /*
@@ -2925,11 +2940,6 @@ static int synchronize_sched_expedited_cpu_stop(void *data)
  * restructure your code to batch your updates, and then use a single
  * synchronize_sched() instead.
  *
- * Note that it is illegal to call this function while holding any lock
- * that is acquired by a CPU-hotplug notifier.  And yes, it is also illegal
- * to call this function from a CPU-hotplug notifier.  Failing to observe
- * these restriction will result in deadlock.
- *
  * This implementation can be thought of as an application of ticket
  * locking to RCU, with sync_sched_expedited_started and
  * sync_sched_expedited_done taking on the roles of the halves
@@ -2979,7 +2989,12 @@ void synchronize_sched_expedited(void)
         */
        snap = atomic_long_inc_return(&rsp->expedited_start);
        firstsnap = snap;
-       get_online_cpus();
+       if (!try_get_online_cpus()) {
+               /* CPU hotplug operation in flight, fall back to normal GP. */
+               wait_rcu_gp(call_rcu_sched);
+               atomic_long_inc(&rsp->expedited_normal);
+               return;
+       }
        WARN_ON_ONCE(cpu_is_offline(raw_smp_processor_id()));
 
        /*
@@ -3026,7 +3041,12 @@ void synchronize_sched_expedited(void)
                 * and they started after our first try, so their grace
                 * period works for us.
                 */
-               get_online_cpus();
+               if (!try_get_online_cpus()) {
+                       /* CPU hotplug operation in flight, use normal GP. */
+                       wait_rcu_gp(call_rcu_sched);
+                       atomic_long_inc(&rsp->expedited_normal);
+                       return;
+               }
                snap = atomic_long_read(&rsp->expedited_start);
                smp_mb(); /* ensure read is before try_stop_cpus(). */
        }
@@ -3442,6 +3462,7 @@ static int rcu_cpu_notify(struct notifier_block *self,
        case CPU_UP_PREPARE_FROZEN:
                rcu_prepare_cpu(cpu);
                rcu_prepare_kthreads(cpu);
+               rcu_spawn_all_nocb_kthreads(cpu);
                break;
        case CPU_ONLINE:
        case CPU_DOWN_FAILED:
@@ -3489,7 +3510,7 @@ static int rcu_pm_notify(struct notifier_block *self,
 }
 
 /*
- * Spawn the kthread that handles this RCU flavor's grace periods.
+ * Spawn the kthreads that handle each RCU flavor's grace periods.
  */
 static int __init rcu_spawn_gp_kthread(void)
 {
@@ -3498,6 +3519,7 @@ static int __init rcu_spawn_gp_kthread(void)
        struct rcu_state *rsp;
        struct task_struct *t;
 
+       rcu_scheduler_fully_active = 1;
        for_each_rcu_flavor(rsp) {
                t = kthread_run(rcu_gp_kthread, rsp, "%s", rsp->name);
                BUG_ON(IS_ERR(t));
@@ -3505,8 +3527,9 @@ static int __init rcu_spawn_gp_kthread(void)
                raw_spin_lock_irqsave(&rnp->lock, flags);
                rsp->gp_kthread = t;
                raw_spin_unlock_irqrestore(&rnp->lock, flags);
-               rcu_spawn_nocb_kthreads(rsp);
        }
+       rcu_spawn_nocb_kthreads();
+       rcu_spawn_boost_kthreads();
        return 0;
 }
 early_initcall(rcu_spawn_gp_kthread);
index 6a86eb7bac45e7b540f1ab9ead7d412cf6ef60fa..d03764652d910cb6b8e7f4039ee184ff549187eb 100644 (file)
@@ -350,7 +350,7 @@ struct rcu_data {
        int nocb_p_count_lazy;          /*  (approximate). */
        wait_queue_head_t nocb_wq;      /* For nocb kthreads to sleep on. */
        struct task_struct *nocb_kthread;
-       bool nocb_defer_wakeup;         /* Defer wakeup of nocb_kthread. */
+       int nocb_defer_wakeup;          /* Defer wakeup of nocb_kthread. */
 
        /* The following fields are used by the leader, hence own cacheline. */
        struct rcu_head *nocb_gp_head ____cacheline_internodealigned_in_smp;
@@ -383,6 +383,11 @@ struct rcu_data {
 #define RCU_FORCE_QS           3       /* Need to force quiescent state. */
 #define RCU_SIGNAL_INIT                RCU_SAVE_DYNTICK
 
+/* Values for nocb_defer_wakeup field in struct rcu_data. */
+#define RCU_NOGP_WAKE_NOT      0
+#define RCU_NOGP_WAKE          1
+#define RCU_NOGP_WAKE_FORCE    2
+
 #define RCU_JIFFIES_TILL_FORCE_QS (1 + (HZ > 250) + (HZ > 500))
                                        /* For jiffies_till_first_fqs and */
                                        /*  and jiffies_till_next_fqs. */
@@ -572,6 +577,7 @@ static void rcu_preempt_do_callbacks(void);
 static int rcu_spawn_one_boost_kthread(struct rcu_state *rsp,
                                                 struct rcu_node *rnp);
 #endif /* #ifdef CONFIG_RCU_BOOST */
+static void __init rcu_spawn_boost_kthreads(void);
 static void rcu_prepare_kthreads(int cpu);
 static void rcu_cleanup_after_idle(int cpu);
 static void rcu_prepare_for_idle(int cpu);
@@ -589,10 +595,14 @@ static bool __call_rcu_nocb(struct rcu_data *rdp, struct rcu_head *rhp,
 static bool rcu_nocb_adopt_orphan_cbs(struct rcu_state *rsp,
                                      struct rcu_data *rdp,
                                      unsigned long flags);
-static bool rcu_nocb_need_deferred_wakeup(struct rcu_data *rdp);
+static int rcu_nocb_need_deferred_wakeup(struct rcu_data *rdp);
 static void do_nocb_deferred_wakeup(struct rcu_data *rdp);
 static void rcu_boot_init_nocb_percpu_data(struct rcu_data *rdp);
-static void rcu_spawn_nocb_kthreads(struct rcu_state *rsp);
+static void rcu_spawn_all_nocb_kthreads(int cpu);
+static void __init rcu_spawn_nocb_kthreads(void);
+#ifdef CONFIG_RCU_NOCB_CPU
+static void __init rcu_organize_nocb_kthreads(struct rcu_state *rsp);
+#endif /* #ifdef CONFIG_RCU_NOCB_CPU */
 static void __maybe_unused rcu_kick_nohz_cpu(int cpu);
 static bool init_nocb_callback_list(struct rcu_data *rdp);
 static void rcu_sysidle_enter(struct rcu_dynticks *rdtp, int irq);
@@ -605,6 +615,8 @@ static void rcu_sysidle_report_gp(struct rcu_state *rsp, int isidle,
 static void rcu_bind_gp_kthread(void);
 static void rcu_sysidle_init_percpu_data(struct rcu_dynticks *rdtp);
 static bool rcu_nohz_full_cpu(struct rcu_state *rsp);
+static void rcu_dynticks_task_enter(void);
+static void rcu_dynticks_task_exit(void);
 
 #endif /* #ifndef RCU_TREE_NONCORE */
 
index a7997e272564916d8ec2232b32867add334b6c77..387dd45993449f7a54310fd936693bbc16611f5b 100644 (file)
@@ -85,33 +85,6 @@ static void __init rcu_bootup_announce_oddness(void)
                pr_info("\tBoot-time adjustment of leaf fanout to %d.\n", rcu_fanout_leaf);
        if (nr_cpu_ids != NR_CPUS)
                pr_info("\tRCU restricting CPUs from NR_CPUS=%d to nr_cpu_ids=%d.\n", NR_CPUS, nr_cpu_ids);
-#ifdef CONFIG_RCU_NOCB_CPU
-#ifndef CONFIG_RCU_NOCB_CPU_NONE
-       if (!have_rcu_nocb_mask) {
-               zalloc_cpumask_var(&rcu_nocb_mask, GFP_KERNEL);
-               have_rcu_nocb_mask = true;
-       }
-#ifdef CONFIG_RCU_NOCB_CPU_ZERO
-       pr_info("\tOffload RCU callbacks from CPU 0\n");
-       cpumask_set_cpu(0, rcu_nocb_mask);
-#endif /* #ifdef CONFIG_RCU_NOCB_CPU_ZERO */
-#ifdef CONFIG_RCU_NOCB_CPU_ALL
-       pr_info("\tOffload RCU callbacks from all CPUs\n");
-       cpumask_copy(rcu_nocb_mask, cpu_possible_mask);
-#endif /* #ifdef CONFIG_RCU_NOCB_CPU_ALL */
-#endif /* #ifndef CONFIG_RCU_NOCB_CPU_NONE */
-       if (have_rcu_nocb_mask) {
-               if (!cpumask_subset(rcu_nocb_mask, cpu_possible_mask)) {
-                       pr_info("\tNote: kernel parameter 'rcu_nocbs=' contains nonexistent CPUs.\n");
-                       cpumask_and(rcu_nocb_mask, cpu_possible_mask,
-                                   rcu_nocb_mask);
-               }
-               cpulist_scnprintf(nocb_buf, sizeof(nocb_buf), rcu_nocb_mask);
-               pr_info("\tOffload RCU callbacks from CPUs: %s.\n", nocb_buf);
-               if (rcu_nocb_poll)
-                       pr_info("\tPoll for callbacks from no-CBs CPUs.\n");
-       }
-#endif /* #ifdef CONFIG_RCU_NOCB_CPU */
 }
 
 #ifdef CONFIG_TREE_PREEMPT_RCU
@@ -134,7 +107,7 @@ static void __init rcu_bootup_announce(void)
  * Return the number of RCU-preempt batches processed thus far
  * for debug and statistics.
  */
-long rcu_batches_completed_preempt(void)
+static long rcu_batches_completed_preempt(void)
 {
        return rcu_preempt_state.completed;
 }
@@ -155,18 +128,19 @@ EXPORT_SYMBOL_GPL(rcu_batches_completed);
  * not in a quiescent state.  There might be any number of tasks blocked
  * while in an RCU read-side critical section.
  *
- * Unlike the other rcu_*_qs() functions, callers to this function
- * must disable irqs in order to protect the assignment to
- * ->rcu_read_unlock_special.
- */
-static void rcu_preempt_qs(int cpu)
-{
-       struct rcu_data *rdp = &per_cpu(rcu_preempt_data, cpu);
-
-       if (rdp->passed_quiesce == 0)
-               trace_rcu_grace_period(TPS("rcu_preempt"), rdp->gpnum, TPS("cpuqs"));
-       rdp->passed_quiesce = 1;
-       current->rcu_read_unlock_special &= ~RCU_READ_UNLOCK_NEED_QS;
+ * As with the other rcu_*_qs() functions, callers to this function
+ * must disable preemption.
+ */
+static void rcu_preempt_qs(void)
+{
+       if (!__this_cpu_read(rcu_preempt_data.passed_quiesce)) {
+               trace_rcu_grace_period(TPS("rcu_preempt"),
+                                      __this_cpu_read(rcu_preempt_data.gpnum),
+                                      TPS("cpuqs"));
+               __this_cpu_write(rcu_preempt_data.passed_quiesce, 1);
+               barrier(); /* Coordinate with rcu_preempt_check_callbacks(). */
+               current->rcu_read_unlock_special.b.need_qs = false;
+       }
 }
 
 /*
@@ -190,14 +164,14 @@ static void rcu_preempt_note_context_switch(int cpu)
        struct rcu_node *rnp;
 
        if (t->rcu_read_lock_nesting > 0 &&
-           (t->rcu_read_unlock_special & RCU_READ_UNLOCK_BLOCKED) == 0) {
+           !t->rcu_read_unlock_special.b.blocked) {
 
                /* Possibly blocking in an RCU read-side critical section. */
                rdp = per_cpu_ptr(rcu_preempt_state.rda, cpu);
                rnp = rdp->mynode;
                raw_spin_lock_irqsave(&rnp->lock, flags);
                smp_mb__after_unlock_lock();
-               t->rcu_read_unlock_special |= RCU_READ_UNLOCK_BLOCKED;
+               t->rcu_read_unlock_special.b.blocked = true;
                t->rcu_blocked_node = rnp;
 
                /*
@@ -239,7 +213,7 @@ static void rcu_preempt_note_context_switch(int cpu)
                                       : rnp->gpnum + 1);
                raw_spin_unlock_irqrestore(&rnp->lock, flags);
        } else if (t->rcu_read_lock_nesting < 0 &&
-                  t->rcu_read_unlock_special) {
+                  t->rcu_read_unlock_special.s) {
 
                /*
                 * Complete exit from RCU read-side critical section on
@@ -257,9 +231,7 @@ static void rcu_preempt_note_context_switch(int cpu)
         * grace period, then the fact that the task has been enqueued
         * means that we continue to block the current grace period.
         */
-       local_irq_save(flags);
-       rcu_preempt_qs(cpu);
-       local_irq_restore(flags);
+       rcu_preempt_qs();
 }
 
 /*
@@ -340,7 +312,7 @@ void rcu_read_unlock_special(struct task_struct *t)
        bool drop_boost_mutex = false;
 #endif /* #ifdef CONFIG_RCU_BOOST */
        struct rcu_node *rnp;
-       int special;
+       union rcu_special special;
 
        /* NMI handlers cannot block and cannot safely manipulate state. */
        if (in_nmi())
@@ -350,12 +322,13 @@ void rcu_read_unlock_special(struct task_struct *t)
 
        /*
         * If RCU core is waiting for this CPU to exit critical section,
-        * let it know that we have done so.
+        * let it know that we have done so.  Because irqs are disabled,
+        * t->rcu_read_unlock_special cannot change.
         */
        special = t->rcu_read_unlock_special;
-       if (special & RCU_READ_UNLOCK_NEED_QS) {
-               rcu_preempt_qs(smp_processor_id());
-               if (!t->rcu_read_unlock_special) {
+       if (special.b.need_qs) {
+               rcu_preempt_qs();
+               if (!t->rcu_read_unlock_special.s) {
                        local_irq_restore(flags);
                        return;
                }
@@ -368,8 +341,8 @@ void rcu_read_unlock_special(struct task_struct *t)
        }
 
        /* Clean up if blocked during RCU read-side critical section. */
-       if (special & RCU_READ_UNLOCK_BLOCKED) {
-               t->rcu_read_unlock_special &= ~RCU_READ_UNLOCK_BLOCKED;
+       if (special.b.blocked) {
+               t->rcu_read_unlock_special.b.blocked = false;
 
                /*
                 * Remove this task from the list it blocked on.  The
@@ -653,12 +626,13 @@ static void rcu_preempt_check_callbacks(int cpu)
        struct task_struct *t = current;
 
        if (t->rcu_read_lock_nesting == 0) {
-               rcu_preempt_qs(cpu);
+               rcu_preempt_qs();
                return;
        }
        if (t->rcu_read_lock_nesting > 0 &&
-           per_cpu(rcu_preempt_data, cpu).qs_pending)
-               t->rcu_read_unlock_special |= RCU_READ_UNLOCK_NEED_QS;
+           per_cpu(rcu_preempt_data, cpu).qs_pending &&
+           !per_cpu(rcu_preempt_data, cpu).passed_quiesce)
+               t->rcu_read_unlock_special.b.need_qs = true;
 }
 
 #ifdef CONFIG_RCU_BOOST
@@ -819,11 +793,6 @@ sync_rcu_preempt_exp_init(struct rcu_state *rsp, struct rcu_node *rnp)
  * In fact, if you are using synchronize_rcu_expedited() in a loop,
  * please restructure your code to batch your updates, and then Use a
  * single synchronize_rcu() instead.
- *
- * Note that it is illegal to call this function while holding any lock
- * that is acquired by a CPU-hotplug notifier.  And yes, it is also illegal
- * to call this function from a CPU-hotplug notifier.  Failing to observe
- * these restriction will result in deadlock.
  */
 void synchronize_rcu_expedited(void)
 {
@@ -845,7 +814,11 @@ void synchronize_rcu_expedited(void)
         * being boosted.  This simplifies the process of moving tasks
         * from leaf to root rcu_node structures.
         */
-       get_online_cpus();
+       if (!try_get_online_cpus()) {
+               /* CPU-hotplug operation in flight, fall back to normal GP. */
+               wait_rcu_gp(call_rcu);
+               return;
+       }
 
        /*
         * Acquire lock, falling back to synchronize_rcu() if too many
@@ -897,7 +870,8 @@ void synchronize_rcu_expedited(void)
 
        /* Clean up and exit. */
        smp_mb(); /* ensure expedited GP seen before counter increment. */
-       ACCESS_ONCE(sync_rcu_preempt_exp_count)++;
+       ACCESS_ONCE(sync_rcu_preempt_exp_count) =
+                                       sync_rcu_preempt_exp_count + 1;
 unlock_mb_ret:
        mutex_unlock(&sync_rcu_preempt_exp_mutex);
 mb_ret:
@@ -941,7 +915,7 @@ void exit_rcu(void)
                return;
        t->rcu_read_lock_nesting = 1;
        barrier();
-       t->rcu_read_unlock_special = RCU_READ_UNLOCK_BLOCKED;
+       t->rcu_read_unlock_special.b.blocked = true;
        __rcu_read_unlock();
 }
 
@@ -1462,14 +1436,13 @@ static struct smp_hotplug_thread rcu_cpu_thread_spec = {
 };
 
 /*
- * Spawn all kthreads -- called as soon as the scheduler is running.
+ * Spawn boost kthreads -- called as soon as the scheduler is running.
  */
-static int __init rcu_spawn_kthreads(void)
+static void __init rcu_spawn_boost_kthreads(void)
 {
        struct rcu_node *rnp;
        int cpu;
 
-       rcu_scheduler_fully_active = 1;
        for_each_possible_cpu(cpu)
                per_cpu(rcu_cpu_has_work, cpu) = 0;
        BUG_ON(smpboot_register_percpu_thread(&rcu_cpu_thread_spec));
@@ -1479,9 +1452,7 @@ static int __init rcu_spawn_kthreads(void)
                rcu_for_each_leaf_node(rcu_state_p, rnp)
                        (void)rcu_spawn_one_boost_kthread(rcu_state_p, rnp);
        }
-       return 0;
 }
-early_initcall(rcu_spawn_kthreads);
 
 static void rcu_prepare_kthreads(int cpu)
 {
@@ -1519,12 +1490,9 @@ static void rcu_boost_kthread_setaffinity(struct rcu_node *rnp, int outgoingcpu)
 {
 }
 
-static int __init rcu_scheduler_really_started(void)
+static void __init rcu_spawn_boost_kthreads(void)
 {
-       rcu_scheduler_fully_active = 1;
-       return 0;
 }
-early_initcall(rcu_scheduler_really_started);
 
 static void rcu_prepare_kthreads(int cpu)
 {
@@ -1625,7 +1593,7 @@ static bool __maybe_unused rcu_try_advance_all_cbs(void)
 
        /* Exit early if we advanced recently. */
        if (jiffies == rdtp->last_advance_all)
-               return 0;
+               return false;
        rdtp->last_advance_all = jiffies;
 
        for_each_rcu_flavor(rsp) {
@@ -1848,7 +1816,7 @@ static int rcu_oom_notify(struct notifier_block *self,
        get_online_cpus();
        for_each_online_cpu(cpu) {
                smp_call_function_single(cpu, rcu_oom_notify_cpu, NULL, 1);
-               cond_resched();
+               cond_resched_rcu_qs();
        }
        put_online_cpus();
 
@@ -2075,7 +2043,7 @@ static void wake_nocb_leader(struct rcu_data *rdp, bool force)
        if (!ACCESS_ONCE(rdp_leader->nocb_kthread))
                return;
        if (ACCESS_ONCE(rdp_leader->nocb_leader_sleep) || force) {
-               /* Prior xchg orders against prior callback enqueue. */
+               /* Prior smp_mb__after_atomic() orders against prior enqueue. */
                ACCESS_ONCE(rdp_leader->nocb_leader_sleep) = false;
                wake_up(&rdp_leader->nocb_wq);
        }
@@ -2104,6 +2072,7 @@ static void __call_rcu_nocb_enqueue(struct rcu_data *rdp,
        ACCESS_ONCE(*old_rhpp) = rhp;
        atomic_long_add(rhcount, &rdp->nocb_q_count);
        atomic_long_add(rhcount_lazy, &rdp->nocb_q_count_lazy);
+       smp_mb__after_atomic(); /* Store *old_rhpp before _wake test. */
 
        /* If we are not being polled and there is a kthread, awaken it ... */
        t = ACCESS_ONCE(rdp->nocb_kthread);
@@ -2120,16 +2089,23 @@ static void __call_rcu_nocb_enqueue(struct rcu_data *rdp,
                        trace_rcu_nocb_wake(rdp->rsp->name, rdp->cpu,
                                            TPS("WakeEmpty"));
                } else {
-                       rdp->nocb_defer_wakeup = true;
+                       rdp->nocb_defer_wakeup = RCU_NOGP_WAKE;
                        trace_rcu_nocb_wake(rdp->rsp->name, rdp->cpu,
                                            TPS("WakeEmptyIsDeferred"));
                }
                rdp->qlen_last_fqs_check = 0;
        } else if (len > rdp->qlen_last_fqs_check + qhimark) {
                /* ... or if many callbacks queued. */
-               wake_nocb_leader(rdp, true);
+               if (!irqs_disabled_flags(flags)) {
+                       wake_nocb_leader(rdp, true);
+                       trace_rcu_nocb_wake(rdp->rsp->name, rdp->cpu,
+                                           TPS("WakeOvf"));
+               } else {
+                       rdp->nocb_defer_wakeup = RCU_NOGP_WAKE_FORCE;
+                       trace_rcu_nocb_wake(rdp->rsp->name, rdp->cpu,
+                                           TPS("WakeOvfIsDeferred"));
+               }
                rdp->qlen_last_fqs_check = LONG_MAX / 2;
-               trace_rcu_nocb_wake(rdp->rsp->name, rdp->cpu, TPS("WakeOvf"));
        } else {
                trace_rcu_nocb_wake(rdp->rsp->name, rdp->cpu, TPS("WakeNot"));
        }
@@ -2150,7 +2126,7 @@ static bool __call_rcu_nocb(struct rcu_data *rdp, struct rcu_head *rhp,
 {
 
        if (!rcu_is_nocb_cpu(rdp->cpu))
-               return 0;
+               return false;
        __call_rcu_nocb_enqueue(rdp, rhp, &rhp->next, 1, lazy, flags);
        if (__is_kfree_rcu_offset((unsigned long)rhp->func))
                trace_rcu_kfree_callback(rdp->rsp->name, rhp,
@@ -2161,7 +2137,18 @@ static bool __call_rcu_nocb(struct rcu_data *rdp, struct rcu_head *rhp,
                trace_rcu_callback(rdp->rsp->name, rhp,
                                   -atomic_long_read(&rdp->nocb_q_count_lazy),
                                   -atomic_long_read(&rdp->nocb_q_count));
-       return 1;
+
+       /*
+        * If called from an extended quiescent state with interrupts
+        * disabled, invoke the RCU core in order to allow the idle-entry
+        * deferred-wakeup check to function.
+        */
+       if (irqs_disabled_flags(flags) &&
+           !rcu_is_watching() &&
+           cpu_online(smp_processor_id()))
+               invoke_rcu_core();
+
+       return true;
 }
 
 /*
@@ -2177,7 +2164,7 @@ static bool __maybe_unused rcu_nocb_adopt_orphan_cbs(struct rcu_state *rsp,
 
        /* If this is not a no-CBs CPU, tell the caller to do it the old way. */
        if (!rcu_is_nocb_cpu(smp_processor_id()))
-               return 0;
+               return false;
        rsp->qlen = 0;
        rsp->qlen_lazy = 0;
 
@@ -2196,7 +2183,7 @@ static bool __maybe_unused rcu_nocb_adopt_orphan_cbs(struct rcu_state *rsp,
                rsp->orphan_nxtlist = NULL;
                rsp->orphan_nxttail = &rsp->orphan_nxtlist;
        }
-       return 1;
+       return true;
 }
 
 /*
@@ -2229,7 +2216,7 @@ static void rcu_nocb_wait_gp(struct rcu_data *rdp)
                        (d = ULONG_CMP_GE(ACCESS_ONCE(rnp->completed), c)));
                if (likely(d))
                        break;
-               flush_signals(current);
+               WARN_ON(signal_pending(current));
                trace_rcu_future_gp(rnp, rdp, c, TPS("ResumeWait"));
        }
        trace_rcu_future_gp(rnp, rdp, c, TPS("EndWait"));
@@ -2288,7 +2275,7 @@ wait_again:
                if (!rcu_nocb_poll)
                        trace_rcu_nocb_wake(my_rdp->rsp->name, my_rdp->cpu,
                                            "WokeEmpty");
-               flush_signals(current);
+               WARN_ON(signal_pending(current));
                schedule_timeout_interruptible(1);
 
                /* Rescan in case we were a victim of memory ordering. */
@@ -2327,6 +2314,7 @@ wait_again:
                atomic_long_add(rdp->nocb_gp_count, &rdp->nocb_follower_count);
                atomic_long_add(rdp->nocb_gp_count_lazy,
                                &rdp->nocb_follower_count_lazy);
+               smp_mb__after_atomic(); /* Store *tail before wakeup. */
                if (rdp != my_rdp && tail == &rdp->nocb_follower_head) {
                        /*
                         * List was empty, wake up the follower.
@@ -2367,7 +2355,7 @@ static void nocb_follower_wait(struct rcu_data *rdp)
                if (!rcu_nocb_poll)
                        trace_rcu_nocb_wake(rdp->rsp->name, rdp->cpu,
                                            "WokeEmpty");
-               flush_signals(current);
+               WARN_ON(signal_pending(current));
                schedule_timeout_interruptible(1);
        }
 }
@@ -2428,15 +2416,16 @@ static int rcu_nocb_kthread(void *arg)
                        list = next;
                }
                trace_rcu_batch_end(rdp->rsp->name, c, !!list, 0, 0, 1);
-               ACCESS_ONCE(rdp->nocb_p_count) -= c;
-               ACCESS_ONCE(rdp->nocb_p_count_lazy) -= cl;
+               ACCESS_ONCE(rdp->nocb_p_count) = rdp->nocb_p_count - c;
+               ACCESS_ONCE(rdp->nocb_p_count_lazy) =
+                                               rdp->nocb_p_count_lazy - cl;
                rdp->n_nocbs_invoked += c;
        }
        return 0;
 }
 
 /* Is a deferred wakeup of rcu_nocb_kthread() required? */
-static bool rcu_nocb_need_deferred_wakeup(struct rcu_data *rdp)
+static int rcu_nocb_need_deferred_wakeup(struct rcu_data *rdp)
 {
        return ACCESS_ONCE(rdp->nocb_defer_wakeup);
 }
@@ -2444,11 +2433,79 @@ static bool rcu_nocb_need_deferred_wakeup(struct rcu_data *rdp)
 /* Do a deferred wakeup of rcu_nocb_kthread(). */
 static void do_nocb_deferred_wakeup(struct rcu_data *rdp)
 {
+       int ndw;
+
        if (!rcu_nocb_need_deferred_wakeup(rdp))
                return;
-       ACCESS_ONCE(rdp->nocb_defer_wakeup) = false;
-       wake_nocb_leader(rdp, false);
-       trace_rcu_nocb_wake(rdp->rsp->name, rdp->cpu, TPS("DeferredWakeEmpty"));
+       ndw = ACCESS_ONCE(rdp->nocb_defer_wakeup);
+       ACCESS_ONCE(rdp->nocb_defer_wakeup) = RCU_NOGP_WAKE_NOT;
+       wake_nocb_leader(rdp, ndw == RCU_NOGP_WAKE_FORCE);
+       trace_rcu_nocb_wake(rdp->rsp->name, rdp->cpu, TPS("DeferredWake"));
+}
+
+void __init rcu_init_nohz(void)
+{
+       int cpu;
+       bool need_rcu_nocb_mask = true;
+       struct rcu_state *rsp;
+
+#ifdef CONFIG_RCU_NOCB_CPU_NONE
+       need_rcu_nocb_mask = false;
+#endif /* #ifndef CONFIG_RCU_NOCB_CPU_NONE */
+
+#if defined(CONFIG_NO_HZ_FULL)
+       if (tick_nohz_full_running && cpumask_weight(tick_nohz_full_mask))
+               need_rcu_nocb_mask = true;
+#endif /* #if defined(CONFIG_NO_HZ_FULL) */
+
+       if (!have_rcu_nocb_mask && need_rcu_nocb_mask) {
+               if (!zalloc_cpumask_var(&rcu_nocb_mask, GFP_KERNEL)) {
+                       pr_info("rcu_nocb_mask allocation failed, callback offloading disabled.\n");
+                       return;
+               }
+               have_rcu_nocb_mask = true;
+       }
+       if (!have_rcu_nocb_mask)
+               return;
+
+#ifdef CONFIG_RCU_NOCB_CPU_ZERO
+       pr_info("\tOffload RCU callbacks from CPU 0\n");
+       cpumask_set_cpu(0, rcu_nocb_mask);
+#endif /* #ifdef CONFIG_RCU_NOCB_CPU_ZERO */
+#ifdef CONFIG_RCU_NOCB_CPU_ALL
+       pr_info("\tOffload RCU callbacks from all CPUs\n");
+       cpumask_copy(rcu_nocb_mask, cpu_possible_mask);
+#endif /* #ifdef CONFIG_RCU_NOCB_CPU_ALL */
+#if defined(CONFIG_NO_HZ_FULL)
+       if (tick_nohz_full_running)
+               cpumask_or(rcu_nocb_mask, rcu_nocb_mask, tick_nohz_full_mask);
+#endif /* #if defined(CONFIG_NO_HZ_FULL) */
+
+       if (!cpumask_subset(rcu_nocb_mask, cpu_possible_mask)) {
+               pr_info("\tNote: kernel parameter 'rcu_nocbs=' contains nonexistent CPUs.\n");
+               cpumask_and(rcu_nocb_mask, cpu_possible_mask,
+                           rcu_nocb_mask);
+       }
+       cpulist_scnprintf(nocb_buf, sizeof(nocb_buf), rcu_nocb_mask);
+       pr_info("\tOffload RCU callbacks from CPUs: %s.\n", nocb_buf);
+       if (rcu_nocb_poll)
+               pr_info("\tPoll for callbacks from no-CBs CPUs.\n");
+
+       for_each_rcu_flavor(rsp) {
+               for_each_cpu(cpu, rcu_nocb_mask) {
+                       struct rcu_data *rdp = per_cpu_ptr(rsp->rda, cpu);
+
+                       /*
+                        * If there are early callbacks, they will need
+                        * to be moved to the nocb lists.
+                        */
+                       WARN_ON_ONCE(rdp->nxttail[RCU_NEXT_TAIL] !=
+                                    &rdp->nxtlist &&
+                                    rdp->nxttail[RCU_NEXT_TAIL] != NULL);
+                       init_nocb_callback_list(rdp);
+               }
+               rcu_organize_nocb_kthreads(rsp);
+       }
 }
 
 /* Initialize per-rcu_data variables for no-CBs CPUs. */
@@ -2459,15 +2516,85 @@ static void __init rcu_boot_init_nocb_percpu_data(struct rcu_data *rdp)
        rdp->nocb_follower_tail = &rdp->nocb_follower_head;
 }
 
+/*
+ * If the specified CPU is a no-CBs CPU that does not already have its
+ * rcuo kthread for the specified RCU flavor, spawn it.  If the CPUs are
+ * brought online out of order, this can require re-organizing the
+ * leader-follower relationships.
+ */
+static void rcu_spawn_one_nocb_kthread(struct rcu_state *rsp, int cpu)
+{
+       struct rcu_data *rdp;
+       struct rcu_data *rdp_last;
+       struct rcu_data *rdp_old_leader;
+       struct rcu_data *rdp_spawn = per_cpu_ptr(rsp->rda, cpu);
+       struct task_struct *t;
+
+       /*
+        * If this isn't a no-CBs CPU or if it already has an rcuo kthread,
+        * then nothing to do.
+        */
+       if (!rcu_is_nocb_cpu(cpu) || rdp_spawn->nocb_kthread)
+               return;
+
+       /* If we didn't spawn the leader first, reorganize! */
+       rdp_old_leader = rdp_spawn->nocb_leader;
+       if (rdp_old_leader != rdp_spawn && !rdp_old_leader->nocb_kthread) {
+               rdp_last = NULL;
+               rdp = rdp_old_leader;
+               do {
+                       rdp->nocb_leader = rdp_spawn;
+                       if (rdp_last && rdp != rdp_spawn)
+                               rdp_last->nocb_next_follower = rdp;
+                       rdp_last = rdp;
+                       rdp = rdp->nocb_next_follower;
+                       rdp_last->nocb_next_follower = NULL;
+               } while (rdp);
+               rdp_spawn->nocb_next_follower = rdp_old_leader;
+       }
+
+       /* Spawn the kthread for this CPU and RCU flavor. */
+       t = kthread_run(rcu_nocb_kthread, rdp_spawn,
+                       "rcuo%c/%d", rsp->abbr, cpu);
+       BUG_ON(IS_ERR(t));
+       ACCESS_ONCE(rdp_spawn->nocb_kthread) = t;
+}
+
+/*
+ * If the specified CPU is a no-CBs CPU that does not already have its
+ * rcuo kthreads, spawn them.
+ */
+static void rcu_spawn_all_nocb_kthreads(int cpu)
+{
+       struct rcu_state *rsp;
+
+       if (rcu_scheduler_fully_active)
+               for_each_rcu_flavor(rsp)
+                       rcu_spawn_one_nocb_kthread(rsp, cpu);
+}
+
+/*
+ * Once the scheduler is running, spawn rcuo kthreads for all online
+ * no-CBs CPUs.  This assumes that the early_initcall()s happen before
+ * non-boot CPUs come online -- if this changes, we will need to add
+ * some mutual exclusion.
+ */
+static void __init rcu_spawn_nocb_kthreads(void)
+{
+       int cpu;
+
+       for_each_online_cpu(cpu)
+               rcu_spawn_all_nocb_kthreads(cpu);
+}
+
 /* How many follower CPU IDs per leader?  Default of -1 for sqrt(nr_cpu_ids). */
 static int rcu_nocb_leader_stride = -1;
 module_param(rcu_nocb_leader_stride, int, 0444);
 
 /*
- * Create a kthread for each RCU flavor for each no-CBs CPU.
- * Also initialize leader-follower relationships.
+ * Initialize leader-follower relationships for all no-CBs CPU.
  */
-static void __init rcu_spawn_nocb_kthreads(struct rcu_state *rsp)
+static void __init rcu_organize_nocb_kthreads(struct rcu_state *rsp)
 {
        int cpu;
        int ls = rcu_nocb_leader_stride;
@@ -2475,14 +2602,9 @@ static void __init rcu_spawn_nocb_kthreads(struct rcu_state *rsp)
        struct rcu_data *rdp;
        struct rcu_data *rdp_leader = NULL;  /* Suppress misguided gcc warn. */
        struct rcu_data *rdp_prev = NULL;
-       struct task_struct *t;
 
-       if (rcu_nocb_mask == NULL)
+       if (!have_rcu_nocb_mask)
                return;
-#if defined(CONFIG_NO_HZ_FULL) && !defined(CONFIG_NO_HZ_FULL_ALL)
-       if (tick_nohz_full_running)
-               cpumask_or(rcu_nocb_mask, rcu_nocb_mask, tick_nohz_full_mask);
-#endif /* #if defined(CONFIG_NO_HZ_FULL) && !defined(CONFIG_NO_HZ_FULL_ALL) */
        if (ls == -1) {
                ls = int_sqrt(nr_cpu_ids);
                rcu_nocb_leader_stride = ls;
@@ -2505,21 +2627,15 @@ static void __init rcu_spawn_nocb_kthreads(struct rcu_state *rsp)
                        rdp_prev->nocb_next_follower = rdp;
                }
                rdp_prev = rdp;
-
-               /* Spawn the kthread for this CPU. */
-               t = kthread_run(rcu_nocb_kthread, rdp,
-                               "rcuo%c/%d", rsp->abbr, cpu);
-               BUG_ON(IS_ERR(t));
-               ACCESS_ONCE(rdp->nocb_kthread) = t;
        }
 }
 
 /* Prevent __call_rcu() from enqueuing callbacks on no-CBs CPUs */
 static bool init_nocb_callback_list(struct rcu_data *rdp)
 {
-       if (rcu_nocb_mask == NULL ||
-           !cpumask_test_cpu(rdp->cpu, rcu_nocb_mask))
+       if (!rcu_is_nocb_cpu(rdp->cpu))
                return false;
+
        rdp->nxttail[RCU_NEXT_TAIL] = NULL;
        return true;
 }
@@ -2541,21 +2657,21 @@ static void rcu_init_one_nocb(struct rcu_node *rnp)
 static bool __call_rcu_nocb(struct rcu_data *rdp, struct rcu_head *rhp,
                            bool lazy, unsigned long flags)
 {
-       return 0;
+       return false;
 }
 
 static bool __maybe_unused rcu_nocb_adopt_orphan_cbs(struct rcu_state *rsp,
                                                     struct rcu_data *rdp,
                                                     unsigned long flags)
 {
-       return 0;
+       return false;
 }
 
 static void __init rcu_boot_init_nocb_percpu_data(struct rcu_data *rdp)
 {
 }
 
-static bool rcu_nocb_need_deferred_wakeup(struct rcu_data *rdp)
+static int rcu_nocb_need_deferred_wakeup(struct rcu_data *rdp)
 {
        return false;
 }
@@ -2564,7 +2680,11 @@ static void do_nocb_deferred_wakeup(struct rcu_data *rdp)
 {
 }
 
-static void __init rcu_spawn_nocb_kthreads(struct rcu_state *rsp)
+static void rcu_spawn_all_nocb_kthreads(int cpu)
+{
+}
+
+static void __init rcu_spawn_nocb_kthreads(void)
 {
 }
 
@@ -2595,16 +2715,6 @@ static void __maybe_unused rcu_kick_nohz_cpu(int cpu)
 
 #ifdef CONFIG_NO_HZ_FULL_SYSIDLE
 
-/*
- * Define RCU flavor that holds sysidle state.  This needs to be the
- * most active flavor of RCU.
- */
-#ifdef CONFIG_PREEMPT_RCU
-static struct rcu_state *rcu_sysidle_state = &rcu_preempt_state;
-#else /* #ifdef CONFIG_PREEMPT_RCU */
-static struct rcu_state *rcu_sysidle_state = &rcu_sched_state;
-#endif /* #else #ifdef CONFIG_PREEMPT_RCU */
-
 static int full_sysidle_state;         /* Current system-idle state. */
 #define RCU_SYSIDLE_NOT                0       /* Some CPU is not idle. */
 #define RCU_SYSIDLE_SHORT      1       /* All CPUs idle for brief period. */
@@ -2622,6 +2732,10 @@ static void rcu_sysidle_enter(struct rcu_dynticks *rdtp, int irq)
 {
        unsigned long j;
 
+       /* If there are no nohz_full= CPUs, no need to track this. */
+       if (!tick_nohz_full_enabled())
+               return;
+
        /* Adjust nesting, check for fully idle. */
        if (irq) {
                rdtp->dynticks_idle_nesting--;
@@ -2687,6 +2801,10 @@ void rcu_sysidle_force_exit(void)
  */
 static void rcu_sysidle_exit(struct rcu_dynticks *rdtp, int irq)
 {
+       /* If there are no nohz_full= CPUs, no need to track this. */
+       if (!tick_nohz_full_enabled())
+               return;
+
        /* Adjust nesting, check for already non-idle. */
        if (irq) {
                rdtp->dynticks_idle_nesting++;
@@ -2741,12 +2859,16 @@ static void rcu_sysidle_check_cpu(struct rcu_data *rdp, bool *isidle,
        unsigned long j;
        struct rcu_dynticks *rdtp = rdp->dynticks;
 
+       /* If there are no nohz_full= CPUs, don't check system-wide idleness. */
+       if (!tick_nohz_full_enabled())
+               return;
+
        /*
         * If some other CPU has already reported non-idle, if this is
         * not the flavor of RCU that tracks sysidle state, or if this
         * is an offline or the timekeeping CPU, nothing to do.
         */
-       if (!*isidle || rdp->rsp != rcu_sysidle_state ||
+       if (!*isidle || rdp->rsp != rcu_state_p ||
            cpu_is_offline(rdp->cpu) || rdp->cpu == tick_do_timer_cpu)
                return;
        if (rcu_gp_in_progress(rdp->rsp))
@@ -2772,7 +2894,7 @@ static void rcu_sysidle_check_cpu(struct rcu_data *rdp, bool *isidle,
  */
 static bool is_sysidle_rcu_state(struct rcu_state *rsp)
 {
-       return rsp == rcu_sysidle_state;
+       return rsp == rcu_state_p;
 }
 
 /*
@@ -2850,7 +2972,7 @@ static void rcu_sysidle_cancel(void)
 static void rcu_sysidle_report(struct rcu_state *rsp, int isidle,
                               unsigned long maxj, bool gpkt)
 {
-       if (rsp != rcu_sysidle_state)
+       if (rsp != rcu_state_p)
                return;  /* Wrong flavor, ignore. */
        if (gpkt && nr_cpu_ids <= CONFIG_NO_HZ_FULL_SYSIDLE_SMALL)
                return;  /* Running state machine from timekeeping CPU. */
@@ -2867,6 +2989,10 @@ static void rcu_sysidle_report(struct rcu_state *rsp, int isidle,
 static void rcu_sysidle_report_gp(struct rcu_state *rsp, int isidle,
                                  unsigned long maxj)
 {
+       /* If there are no nohz_full= CPUs, no need to track this. */
+       if (!tick_nohz_full_enabled())
+               return;
+
        rcu_sysidle_report(rsp, isidle, maxj, true);
 }
 
@@ -2893,7 +3019,8 @@ static void rcu_sysidle_cb(struct rcu_head *rhp)
 
 /*
  * Check to see if the system is fully idle, other than the timekeeping CPU.
- * The caller must have disabled interrupts.
+ * The caller must have disabled interrupts.  This is not intended to be
+ * called unless tick_nohz_full_enabled().
  */
 bool rcu_sys_is_idle(void)
 {
@@ -2919,13 +3046,12 @@ bool rcu_sys_is_idle(void)
 
                        /* Scan all the CPUs looking for nonidle CPUs. */
                        for_each_possible_cpu(cpu) {
-                               rdp = per_cpu_ptr(rcu_sysidle_state->rda, cpu);
+                               rdp = per_cpu_ptr(rcu_state_p->rda, cpu);
                                rcu_sysidle_check_cpu(rdp, &isidle, &maxj);
                                if (!isidle)
                                        break;
                        }
-                       rcu_sysidle_report(rcu_sysidle_state,
-                                          isidle, maxj, false);
+                       rcu_sysidle_report(rcu_state_p, isidle, maxj, false);
                        oldrss = rss;
                        rss = ACCESS_ONCE(full_sysidle_state);
                }
@@ -2952,7 +3078,7 @@ bool rcu_sys_is_idle(void)
         * provided by the memory allocator.
         */
        if (nr_cpu_ids > CONFIG_NO_HZ_FULL_SYSIDLE_SMALL &&
-           !rcu_gp_in_progress(rcu_sysidle_state) &&
+           !rcu_gp_in_progress(rcu_state_p) &&
            !rsh.inuse && xchg(&rsh.inuse, 1) == 0)
                call_rcu(&rsh.rh, rcu_sysidle_cb);
        return false;
@@ -3036,3 +3162,19 @@ static void rcu_bind_gp_kthread(void)
                housekeeping_affine(current);
 #endif /* #else #ifdef CONFIG_NO_HZ_FULL_SYSIDLE */
 }
+
+/* Record the current task on dyntick-idle entry. */
+static void rcu_dynticks_task_enter(void)
+{
+#if defined(CONFIG_TASKS_RCU) && defined(CONFIG_NO_HZ_FULL)
+       ACCESS_ONCE(current->rcu_tasks_idle_cpu) = smp_processor_id();
+#endif /* #if defined(CONFIG_TASKS_RCU) && defined(CONFIG_NO_HZ_FULL) */
+}
+
+/* Record no current task on dyntick-idle exit. */
+static void rcu_dynticks_task_exit(void)
+{
+#if defined(CONFIG_TASKS_RCU) && defined(CONFIG_NO_HZ_FULL)
+       ACCESS_ONCE(current->rcu_tasks_idle_cpu) = -1;
+#endif /* #if defined(CONFIG_TASKS_RCU) && defined(CONFIG_NO_HZ_FULL) */
+}
index 4056d7992a6c3d86d7a41478aeb35279cd5cde66..3ef8ba58694e95190e326986a252a276c9d721ed 100644 (file)
@@ -47,6 +47,8 @@
 #include <linux/hardirq.h>
 #include <linux/delay.h>
 #include <linux/module.h>
+#include <linux/kthread.h>
+#include <linux/tick.h>
 
 #define CREATE_TRACE_POINTS
 
@@ -91,7 +93,7 @@ void __rcu_read_unlock(void)
                barrier();  /* critical section before exit code. */
                t->rcu_read_lock_nesting = INT_MIN;
                barrier();  /* assign before ->rcu_read_unlock_special load */
-               if (unlikely(ACCESS_ONCE(t->rcu_read_unlock_special)))
+               if (unlikely(ACCESS_ONCE(t->rcu_read_unlock_special.s)))
                        rcu_read_unlock_special(t);
                barrier();  /* ->rcu_read_unlock_special load before assign */
                t->rcu_read_lock_nesting = 0;
@@ -136,6 +138,38 @@ int notrace debug_lockdep_rcu_enabled(void)
 }
 EXPORT_SYMBOL_GPL(debug_lockdep_rcu_enabled);
 
+/**
+ * rcu_read_lock_held() - might we be in RCU read-side critical section?
+ *
+ * If CONFIG_DEBUG_LOCK_ALLOC is selected, returns nonzero iff in an RCU
+ * read-side critical section.  In absence of CONFIG_DEBUG_LOCK_ALLOC,
+ * this assumes we are in an RCU read-side critical section unless it can
+ * prove otherwise.  This is useful for debug checks in functions that
+ * require that they be called within an RCU read-side critical section.
+ *
+ * Checks debug_lockdep_rcu_enabled() to prevent false positives during boot
+ * and while lockdep is disabled.
+ *
+ * Note that rcu_read_lock() and the matching rcu_read_unlock() must
+ * occur in the same context, for example, it is illegal to invoke
+ * rcu_read_unlock() in process context if the matching rcu_read_lock()
+ * was invoked from within an irq handler.
+ *
+ * Note that rcu_read_lock() is disallowed if the CPU is either idle or
+ * offline from an RCU perspective, so check for those as well.
+ */
+int rcu_read_lock_held(void)
+{
+       if (!debug_lockdep_rcu_enabled())
+               return 1;
+       if (!rcu_is_watching())
+               return 0;
+       if (!rcu_lockdep_current_cpu_online())
+               return 0;
+       return lock_is_held(&rcu_lock_map);
+}
+EXPORT_SYMBOL_GPL(rcu_read_lock_held);
+
 /**
  * rcu_read_lock_bh_held() - might we be in RCU-bh read-side critical section?
  *
@@ -347,3 +381,312 @@ static int __init check_cpu_stall_init(void)
 early_initcall(check_cpu_stall_init);
 
 #endif /* #ifdef CONFIG_RCU_STALL_COMMON */
+
+#ifdef CONFIG_TASKS_RCU
+
+/*
+ * Simple variant of RCU whose quiescent states are voluntary context switch,
+ * user-space execution, and idle.  As such, grace periods can take one good
+ * long time.  There are no read-side primitives similar to rcu_read_lock()
+ * and rcu_read_unlock() because this implementation is intended to get
+ * the system into a safe state for some of the manipulations involved in
+ * tracing and the like.  Finally, this implementation does not support
+ * high call_rcu_tasks() rates from multiple CPUs.  If this is required,
+ * per-CPU callback lists will be needed.
+ */
+
+/* Global list of callbacks and associated lock. */
+static struct rcu_head *rcu_tasks_cbs_head;
+static struct rcu_head **rcu_tasks_cbs_tail = &rcu_tasks_cbs_head;
+static DECLARE_WAIT_QUEUE_HEAD(rcu_tasks_cbs_wq);
+static DEFINE_RAW_SPINLOCK(rcu_tasks_cbs_lock);
+
+/* Track exiting tasks in order to allow them to be waited for. */
+DEFINE_SRCU(tasks_rcu_exit_srcu);
+
+/* Control stall timeouts.  Disable with <= 0, otherwise jiffies till stall. */
+static int rcu_task_stall_timeout __read_mostly = HZ * 60 * 10;
+module_param(rcu_task_stall_timeout, int, 0644);
+
+static void rcu_spawn_tasks_kthread(void);
+
+/*
+ * Post an RCU-tasks callback.  First call must be from process context
+ * after the scheduler if fully operational.
+ */
+void call_rcu_tasks(struct rcu_head *rhp, void (*func)(struct rcu_head *rhp))
+{
+       unsigned long flags;
+       bool needwake;
+
+       rhp->next = NULL;
+       rhp->func = func;
+       raw_spin_lock_irqsave(&rcu_tasks_cbs_lock, flags);
+       needwake = !rcu_tasks_cbs_head;
+       *rcu_tasks_cbs_tail = rhp;
+       rcu_tasks_cbs_tail = &rhp->next;
+       raw_spin_unlock_irqrestore(&rcu_tasks_cbs_lock, flags);
+       if (needwake) {
+               rcu_spawn_tasks_kthread();
+               wake_up(&rcu_tasks_cbs_wq);
+       }
+}
+EXPORT_SYMBOL_GPL(call_rcu_tasks);
+
+/**
+ * synchronize_rcu_tasks - wait until an rcu-tasks grace period has elapsed.
+ *
+ * Control will return to the caller some time after a full rcu-tasks
+ * grace period has elapsed, in other words after all currently
+ * executing rcu-tasks read-side critical sections have elapsed.  These
+ * read-side critical sections are delimited by calls to schedule(),
+ * cond_resched_rcu_qs(), idle execution, userspace execution, calls
+ * to synchronize_rcu_tasks(), and (in theory, anyway) cond_resched().
+ *
+ * This is a very specialized primitive, intended only for a few uses in
+ * tracing and other situations requiring manipulation of function
+ * preambles and profiling hooks.  The synchronize_rcu_tasks() function
+ * is not (yet) intended for heavy use from multiple CPUs.
+ *
+ * Note that this guarantee implies further memory-ordering guarantees.
+ * On systems with more than one CPU, when synchronize_rcu_tasks() returns,
+ * each CPU is guaranteed to have executed a full memory barrier since the
+ * end of its last RCU-tasks read-side critical section whose beginning
+ * preceded the call to synchronize_rcu_tasks().  In addition, each CPU
+ * having an RCU-tasks read-side critical section that extends beyond
+ * the return from synchronize_rcu_tasks() is guaranteed to have executed
+ * a full memory barrier after the beginning of synchronize_rcu_tasks()
+ * and before the beginning of that RCU-tasks read-side critical section.
+ * Note that these guarantees include CPUs that are offline, idle, or
+ * executing in user mode, as well as CPUs that are executing in the kernel.
+ *
+ * Furthermore, if CPU A invoked synchronize_rcu_tasks(), which returned
+ * to its caller on CPU B, then both CPU A and CPU B are guaranteed
+ * to have executed a full memory barrier during the execution of
+ * synchronize_rcu_tasks() -- even if CPU A and CPU B are the same CPU
+ * (but again only if the system has more than one CPU).
+ */
+void synchronize_rcu_tasks(void)
+{
+       /* Complain if the scheduler has not started.  */
+       rcu_lockdep_assert(!rcu_scheduler_active,
+                          "synchronize_rcu_tasks called too soon");
+
+       /* Wait for the grace period. */
+       wait_rcu_gp(call_rcu_tasks);
+}
+EXPORT_SYMBOL_GPL(synchronize_rcu_tasks);
+
+/**
+ * rcu_barrier_tasks - Wait for in-flight call_rcu_tasks() callbacks.
+ *
+ * Although the current implementation is guaranteed to wait, it is not
+ * obligated to, for example, if there are no pending callbacks.
+ */
+void rcu_barrier_tasks(void)
+{
+       /* There is only one callback queue, so this is easy.  ;-) */
+       synchronize_rcu_tasks();
+}
+EXPORT_SYMBOL_GPL(rcu_barrier_tasks);
+
+/* See if tasks are still holding out, complain if so. */
+static void check_holdout_task(struct task_struct *t,
+                              bool needreport, bool *firstreport)
+{
+       int cpu;
+
+       if (!ACCESS_ONCE(t->rcu_tasks_holdout) ||
+           t->rcu_tasks_nvcsw != ACCESS_ONCE(t->nvcsw) ||
+           !ACCESS_ONCE(t->on_rq) ||
+           (IS_ENABLED(CONFIG_NO_HZ_FULL) &&
+            !is_idle_task(t) && t->rcu_tasks_idle_cpu >= 0)) {
+               ACCESS_ONCE(t->rcu_tasks_holdout) = false;
+               list_del_init(&t->rcu_tasks_holdout_list);
+               put_task_struct(t);
+               return;
+       }
+       if (!needreport)
+               return;
+       if (*firstreport) {
+               pr_err("INFO: rcu_tasks detected stalls on tasks:\n");
+               *firstreport = false;
+       }
+       cpu = task_cpu(t);
+       pr_alert("%p: %c%c nvcsw: %lu/%lu holdout: %d idle_cpu: %d/%d\n",
+                t, ".I"[is_idle_task(t)],
+                "N."[cpu < 0 || !tick_nohz_full_cpu(cpu)],
+                t->rcu_tasks_nvcsw, t->nvcsw, t->rcu_tasks_holdout,
+                t->rcu_tasks_idle_cpu, cpu);
+       sched_show_task(t);
+}
+
+/* RCU-tasks kthread that detects grace periods and invokes callbacks. */
+static int __noreturn rcu_tasks_kthread(void *arg)
+{
+       unsigned long flags;
+       struct task_struct *g, *t;
+       unsigned long lastreport;
+       struct rcu_head *list;
+       struct rcu_head *next;
+       LIST_HEAD(rcu_tasks_holdouts);
+
+       /* FIXME: Add housekeeping affinity. */
+
+       /*
+        * Each pass through the following loop makes one check for
+        * newly arrived callbacks, and, if there are some, waits for
+        * one RCU-tasks grace period and then invokes the callbacks.
+        * This loop is terminated by the system going down.  ;-)
+        */
+       for (;;) {
+
+               /* Pick up any new callbacks. */
+               raw_spin_lock_irqsave(&rcu_tasks_cbs_lock, flags);
+               list = rcu_tasks_cbs_head;
+               rcu_tasks_cbs_head = NULL;
+               rcu_tasks_cbs_tail = &rcu_tasks_cbs_head;
+               raw_spin_unlock_irqrestore(&rcu_tasks_cbs_lock, flags);
+
+               /* If there were none, wait a bit and start over. */
+               if (!list) {
+                       wait_event_interruptible(rcu_tasks_cbs_wq,
+                                                rcu_tasks_cbs_head);
+                       if (!rcu_tasks_cbs_head) {
+                               WARN_ON(signal_pending(current));
+                               schedule_timeout_interruptible(HZ/10);
+                       }
+                       continue;
+               }
+
+               /*
+                * Wait for all pre-existing t->on_rq and t->nvcsw
+                * transitions to complete.  Invoking synchronize_sched()
+                * suffices because all these transitions occur with
+                * interrupts disabled.  Without this synchronize_sched(),
+                * a read-side critical section that started before the
+                * grace period might be incorrectly seen as having started
+                * after the grace period.
+                *
+                * This synchronize_sched() also dispenses with the
+                * need for a memory barrier on the first store to
+                * ->rcu_tasks_holdout, as it forces the store to happen
+                * after the beginning of the grace period.
+                */
+               synchronize_sched();
+
+               /*
+                * There were callbacks, so we need to wait for an
+                * RCU-tasks grace period.  Start off by scanning
+                * the task list for tasks that are not already
+                * voluntarily blocked.  Mark these tasks and make
+                * a list of them in rcu_tasks_holdouts.
+                */
+               rcu_read_lock();
+               for_each_process_thread(g, t) {
+                       if (t != current && ACCESS_ONCE(t->on_rq) &&
+                           !is_idle_task(t)) {
+                               get_task_struct(t);
+                               t->rcu_tasks_nvcsw = ACCESS_ONCE(t->nvcsw);
+                               ACCESS_ONCE(t->rcu_tasks_holdout) = true;
+                               list_add(&t->rcu_tasks_holdout_list,
+                                        &rcu_tasks_holdouts);
+                       }
+               }
+               rcu_read_unlock();
+
+               /*
+                * Wait for tasks that are in the process of exiting.
+                * This does only part of the job, ensuring that all
+                * tasks that were previously exiting reach the point
+                * where they have disabled preemption, allowing the
+                * later synchronize_sched() to finish the job.
+                */
+               synchronize_srcu(&tasks_rcu_exit_srcu);
+
+               /*
+                * Each pass through the following loop scans the list
+                * of holdout tasks, removing any that are no longer
+                * holdouts.  When the list is empty, we are done.
+                */
+               lastreport = jiffies;
+               while (!list_empty(&rcu_tasks_holdouts)) {
+                       bool firstreport;
+                       bool needreport;
+                       int rtst;
+                       struct task_struct *t1;
+
+                       schedule_timeout_interruptible(HZ);
+                       rtst = ACCESS_ONCE(rcu_task_stall_timeout);
+                       needreport = rtst > 0 &&
+                                    time_after(jiffies, lastreport + rtst);
+                       if (needreport)
+                               lastreport = jiffies;
+                       firstreport = true;
+                       WARN_ON(signal_pending(current));
+                       list_for_each_entry_safe(t, t1, &rcu_tasks_holdouts,
+                                               rcu_tasks_holdout_list) {
+                               check_holdout_task(t, needreport, &firstreport);
+                               cond_resched();
+                       }
+               }
+
+               /*
+                * Because ->on_rq and ->nvcsw are not guaranteed
+                * to have a full memory barriers prior to them in the
+                * schedule() path, memory reordering on other CPUs could
+                * cause their RCU-tasks read-side critical sections to
+                * extend past the end of the grace period.  However,
+                * because these ->nvcsw updates are carried out with
+                * interrupts disabled, we can use synchronize_sched()
+                * to force the needed ordering on all such CPUs.
+                *
+                * This synchronize_sched() also confines all
+                * ->rcu_tasks_holdout accesses to be within the grace
+                * period, avoiding the need for memory barriers for
+                * ->rcu_tasks_holdout accesses.
+                *
+                * In addition, this synchronize_sched() waits for exiting
+                * tasks to complete their final preempt_disable() region
+                * of execution, cleaning up after the synchronize_srcu()
+                * above.
+                */
+               synchronize_sched();
+
+               /* Invoke the callbacks. */
+               while (list) {
+                       next = list->next;
+                       local_bh_disable();
+                       list->func(list);
+                       local_bh_enable();
+                       list = next;
+                       cond_resched();
+               }
+               schedule_timeout_uninterruptible(HZ/10);
+       }
+}
+
+/* Spawn rcu_tasks_kthread() at first call to call_rcu_tasks(). */
+static void rcu_spawn_tasks_kthread(void)
+{
+       static DEFINE_MUTEX(rcu_tasks_kthread_mutex);
+       static struct task_struct *rcu_tasks_kthread_ptr;
+       struct task_struct *t;
+
+       if (ACCESS_ONCE(rcu_tasks_kthread_ptr)) {
+               smp_mb(); /* Ensure caller sees full kthread. */
+               return;
+       }
+       mutex_lock(&rcu_tasks_kthread_mutex);
+       if (rcu_tasks_kthread_ptr) {
+               mutex_unlock(&rcu_tasks_kthread_mutex);
+               return;
+       }
+       t = kthread_run(rcu_tasks_kthread, NULL, "rcu_tasks_kthread");
+       BUG_ON(IS_ERR(t));
+       smp_mb(); /* Ensure others see full kthread. */
+       ACCESS_ONCE(rcu_tasks_kthread_ptr) = t;
+       mutex_unlock(&rcu_tasks_kthread_mutex);
+}
+
+#endif /* #ifdef CONFIG_TASKS_RCU */
index a3a9e240fcdba6662b5cccfe0e1f283a70910ffd..5925f5ae8dff0a3810761ef2255627b4ccdedea1 100644 (file)
@@ -104,6 +104,87 @@ int unregister_reboot_notifier(struct notifier_block *nb)
 }
 EXPORT_SYMBOL(unregister_reboot_notifier);
 
+/*
+ *     Notifier list for kernel code which wants to be called
+ *     to restart the system.
+ */
+static ATOMIC_NOTIFIER_HEAD(restart_handler_list);
+
+/**
+ *     register_restart_handler - Register function to be called to reset
+ *                                the system
+ *     @nb: Info about handler function to be called
+ *     @nb->priority:  Handler priority. Handlers should follow the
+ *                     following guidelines for setting priorities.
+ *                     0:      Restart handler of last resort,
+ *                             with limited restart capabilities
+ *                     128:    Default restart handler; use if no other
+ *                             restart handler is expected to be available,
+ *                             and/or if restart functionality is
+ *                             sufficient to restart the entire system
+ *                     255:    Highest priority restart handler, will
+ *                             preempt all other restart handlers
+ *
+ *     Registers a function with code to be called to restart the
+ *     system.
+ *
+ *     Registered functions will be called from machine_restart as last
+ *     step of the restart sequence (if the architecture specific
+ *     machine_restart function calls do_kernel_restart - see below
+ *     for details).
+ *     Registered functions are expected to restart the system immediately.
+ *     If more than one function is registered, the restart handler priority
+ *     selects which function will be called first.
+ *
+ *     Restart handlers are expected to be registered from non-architecture
+ *     code, typically from drivers. A typical use case would be a system
+ *     where restart functionality is provided through a watchdog. Multiple
+ *     restart handlers may exist; for example, one restart handler might
+ *     restart the entire system, while another only restarts the CPU.
+ *     In such cases, the restart handler which only restarts part of the
+ *     hardware is expected to register with low priority to ensure that
+ *     it only runs if no other means to restart the system is available.
+ *
+ *     Currently always returns zero, as atomic_notifier_chain_register()
+ *     always returns zero.
+ */
+int register_restart_handler(struct notifier_block *nb)
+{
+       return atomic_notifier_chain_register(&restart_handler_list, nb);
+}
+EXPORT_SYMBOL(register_restart_handler);
+
+/**
+ *     unregister_restart_handler - Unregister previously registered
+ *                                  restart handler
+ *     @nb: Hook to be unregistered
+ *
+ *     Unregisters a previously registered restart handler function.
+ *
+ *     Returns zero on success, or %-ENOENT on failure.
+ */
+int unregister_restart_handler(struct notifier_block *nb)
+{
+       return atomic_notifier_chain_unregister(&restart_handler_list, nb);
+}
+EXPORT_SYMBOL(unregister_restart_handler);
+
+/**
+ *     do_kernel_restart - Execute kernel restart handler call chain
+ *
+ *     Calls functions registered with register_restart_handler.
+ *
+ *     Expected to be called from machine_restart as last step of the restart
+ *     sequence.
+ *
+ *     Restarts the system immediately if a restart handler function has been
+ *     registered. Otherwise does nothing.
+ */
+void do_kernel_restart(char *cmd)
+{
+       atomic_notifier_call_chain(&restart_handler_list, reboot_mode, cmd);
+}
+
 void migrate_to_reboot_cpu(void)
 {
        /* The boot cpu is always logical cpu 0 */
index 46322019ab7d388ad62029b42248d2c0a5ecaf72..0bcebffc4e77d5f45571e38ddc5dcc38f40594f4 100644 (file)
@@ -491,6 +491,42 @@ int __weak page_is_ram(unsigned long pfn)
 }
 EXPORT_SYMBOL_GPL(page_is_ram);
 
+/*
+ * Search for a resouce entry that fully contains the specified region.
+ * If found, return 1 if it is RAM, 0 if not.
+ * If not found, or region is not fully contained, return -1
+ *
+ * Used by the ioremap functions to ensure the user is not remapping RAM and is
+ * a vast speed up over walking through the resource table page by page.
+ */
+int region_is_ram(resource_size_t start, unsigned long size)
+{
+       struct resource *p;
+       resource_size_t end = start + size - 1;
+       int flags = IORESOURCE_MEM | IORESOURCE_BUSY;
+       const char *name = "System RAM";
+       int ret = -1;
+
+       read_lock(&resource_lock);
+       for (p = iomem_resource.child; p ; p = p->sibling) {
+               if (end < p->start)
+                       continue;
+
+               if (p->start <= start && end <= p->end) {
+                       /* resource fully contains region */
+                       if ((p->flags != flags) || strcmp(p->name, name))
+                               ret = 0;
+                       else
+                               ret = 1;
+                       break;
+               }
+               if (p->end < start)
+                       break;  /* not found */
+       }
+       read_unlock(&resource_lock);
+       return ret;
+}
+
 void __weak arch_remove_reservations(struct resource *avail)
 {
 }
index e73efba98301f77715c5e5e17b8e65a98bbb3769..8a2e230fb86ad43e3196488961f2b71d1e8b28ed 100644 (file)
@@ -148,11 +148,8 @@ autogroup_move_group(struct task_struct *p, struct autogroup *ag)
        if (!ACCESS_ONCE(sysctl_sched_autogroup_enabled))
                goto out;
 
-       t = p;
-       do {
+       for_each_thread(p, t)
                sched_move_task(t);
-       } while_each_thread(p, t);
-
 out:
        unlock_task_sighand(p, &flags);
        autogroup_kref_put(prev);
index 59965ec0b7de6fec0cc7e72ac8b03402dac1f8c1..44999505e1bf6894bdcdb48531a49e5a07b88ac5 100644 (file)
 #define CREATE_TRACE_POINTS
 #include <trace/events/sched.h>
 
-#ifdef smp_mb__before_atomic
-void __smp_mb__before_atomic(void)
-{
-       smp_mb__before_atomic();
-}
-EXPORT_SYMBOL(__smp_mb__before_atomic);
-#endif
-
-#ifdef smp_mb__after_atomic
-void __smp_mb__after_atomic(void)
-{
-       smp_mb__after_atomic();
-}
-EXPORT_SYMBOL(__smp_mb__after_atomic);
-#endif
-
 void start_bandwidth_timer(struct hrtimer *period_timer, ktime_t period)
 {
        unsigned long delta;
@@ -333,9 +317,12 @@ static inline struct rq *__task_rq_lock(struct task_struct *p)
        for (;;) {
                rq = task_rq(p);
                raw_spin_lock(&rq->lock);
-               if (likely(rq == task_rq(p)))
+               if (likely(rq == task_rq(p) && !task_on_rq_migrating(p)))
                        return rq;
                raw_spin_unlock(&rq->lock);
+
+               while (unlikely(task_on_rq_migrating(p)))
+                       cpu_relax();
        }
 }
 
@@ -352,10 +339,13 @@ static struct rq *task_rq_lock(struct task_struct *p, unsigned long *flags)
                raw_spin_lock_irqsave(&p->pi_lock, *flags);
                rq = task_rq(p);
                raw_spin_lock(&rq->lock);
-               if (likely(rq == task_rq(p)))
+               if (likely(rq == task_rq(p) && !task_on_rq_migrating(p)))
                        return rq;
                raw_spin_unlock(&rq->lock);
                raw_spin_unlock_irqrestore(&p->pi_lock, *flags);
+
+               while (unlikely(task_on_rq_migrating(p)))
+                       cpu_relax();
        }
 }
 
@@ -449,7 +439,15 @@ static void __hrtick_start(void *arg)
 void hrtick_start(struct rq *rq, u64 delay)
 {
        struct hrtimer *timer = &rq->hrtick_timer;
-       ktime_t time = ktime_add_ns(timer->base->get_time(), delay);
+       ktime_t time;
+       s64 delta;
+
+       /*
+        * Don't schedule slices shorter than 10000ns, that just
+        * doesn't make sense and can cause timer DoS.
+        */
+       delta = max_t(s64, delay, 10000LL);
+       time = ktime_add_ns(timer->base->get_time(), delta);
 
        hrtimer_set_expires(timer, time);
 
@@ -1043,7 +1041,7 @@ void check_preempt_curr(struct rq *rq, struct task_struct *p, int flags)
         * A queue event has occurred, and we're going to schedule.  In
         * this case, we can save a useless back to back clock update.
         */
-       if (rq->curr->on_rq && test_tsk_need_resched(rq->curr))
+       if (task_on_rq_queued(rq->curr) && test_tsk_need_resched(rq->curr))
                rq->skip_clock_update = 1;
 }
 
@@ -1088,7 +1086,7 @@ void set_task_cpu(struct task_struct *p, unsigned int new_cpu)
 
 static void __migrate_swap_task(struct task_struct *p, int cpu)
 {
-       if (p->on_rq) {
+       if (task_on_rq_queued(p)) {
                struct rq *src_rq, *dst_rq;
 
                src_rq = task_rq(p);
@@ -1214,7 +1212,7 @@ static int migration_cpu_stop(void *data);
 unsigned long wait_task_inactive(struct task_struct *p, long match_state)
 {
        unsigned long flags;
-       int running, on_rq;
+       int running, queued;
        unsigned long ncsw;
        struct rq *rq;
 
@@ -1252,7 +1250,7 @@ unsigned long wait_task_inactive(struct task_struct *p, long match_state)
                rq = task_rq_lock(p, &flags);
                trace_sched_wait_task(p);
                running = task_running(rq, p);
-               on_rq = p->on_rq;
+               queued = task_on_rq_queued(p);
                ncsw = 0;
                if (!match_state || p->state == match_state)
                        ncsw = p->nvcsw | LONG_MIN; /* sets MSB */
@@ -1284,7 +1282,7 @@ unsigned long wait_task_inactive(struct task_struct *p, long match_state)
                 * running right now), it's preempted, and we should
                 * yield - it could be a while.
                 */
-               if (unlikely(on_rq)) {
+               if (unlikely(queued)) {
                        ktime_t to = ktime_set(0, NSEC_PER_SEC/HZ);
 
                        set_current_state(TASK_UNINTERRUPTIBLE);
@@ -1478,7 +1476,7 @@ ttwu_stat(struct task_struct *p, int cpu, int wake_flags)
 static void ttwu_activate(struct rq *rq, struct task_struct *p, int en_flags)
 {
        activate_task(rq, p, en_flags);
-       p->on_rq = 1;
+       p->on_rq = TASK_ON_RQ_QUEUED;
 
        /* if a worker is waking up, notify workqueue */
        if (p->flags & PF_WQ_WORKER)
@@ -1537,7 +1535,7 @@ static int ttwu_remote(struct task_struct *p, int wake_flags)
        int ret = 0;
 
        rq = __task_rq_lock(p);
-       if (p->on_rq) {
+       if (task_on_rq_queued(p)) {
                /* check_preempt_curr() may use rq clock */
                update_rq_clock(rq);
                ttwu_do_wakeup(rq, p, wake_flags);
@@ -1620,6 +1618,25 @@ static void ttwu_queue_remote(struct task_struct *p, int cpu)
        }
 }
 
+void wake_up_if_idle(int cpu)
+{
+       struct rq *rq = cpu_rq(cpu);
+       unsigned long flags;
+
+       if (!is_idle_task(rq->curr))
+               return;
+
+       if (set_nr_if_polling(rq->idle)) {
+               trace_sched_wake_idle_without_ipi(cpu);
+       } else {
+               raw_spin_lock_irqsave(&rq->lock, flags);
+               if (is_idle_task(rq->curr))
+                       smp_send_reschedule(cpu);
+               /* Else cpu is not in idle, do nothing here */
+               raw_spin_unlock_irqrestore(&rq->lock, flags);
+       }
+}
+
 bool cpus_share_cache(int this_cpu, int that_cpu)
 {
        return per_cpu(sd_llc_id, this_cpu) == per_cpu(sd_llc_id, that_cpu);
@@ -1742,7 +1759,7 @@ static void try_to_wake_up_local(struct task_struct *p)
        if (!(p->state & TASK_NORMAL))
                goto out;
 
-       if (!p->on_rq)
+       if (!task_on_rq_queued(p))
                ttwu_activate(rq, p, ENQUEUE_WAKEUP);
 
        ttwu_do_wakeup(rq, p, 0);
@@ -1775,6 +1792,20 @@ int wake_up_state(struct task_struct *p, unsigned int state)
        return try_to_wake_up(p, state, 0);
 }
 
+/*
+ * This function clears the sched_dl_entity static params.
+ */
+void __dl_clear_params(struct task_struct *p)
+{
+       struct sched_dl_entity *dl_se = &p->dl;
+
+       dl_se->dl_runtime = 0;
+       dl_se->dl_deadline = 0;
+       dl_se->dl_period = 0;
+       dl_se->flags = 0;
+       dl_se->dl_bw = 0;
+}
+
 /*
  * Perform scheduler related setup for a newly forked process p.
  * p is forked by current.
@@ -1799,10 +1830,7 @@ static void __sched_fork(unsigned long clone_flags, struct task_struct *p)
 
        RB_CLEAR_NODE(&p->dl.rb_node);
        hrtimer_init(&p->dl.dl_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
-       p->dl.dl_runtime = p->dl.runtime = 0;
-       p->dl.dl_deadline = p->dl.deadline = 0;
-       p->dl.dl_period = 0;
-       p->dl.flags = 0;
+       __dl_clear_params(p);
 
        INIT_LIST_HEAD(&p->rt.run_list);
 
@@ -1977,6 +2005,8 @@ unsigned long to_ratio(u64 period, u64 runtime)
 #ifdef CONFIG_SMP
 inline struct dl_bw *dl_bw_of(int i)
 {
+       rcu_lockdep_assert(rcu_read_lock_sched_held(),
+                          "sched RCU must be held");
        return &cpu_rq(i)->rd->dl_bw;
 }
 
@@ -1985,6 +2015,8 @@ static inline int dl_bw_cpus(int i)
        struct root_domain *rd = cpu_rq(i)->rd;
        int cpus = 0;
 
+       rcu_lockdep_assert(rcu_read_lock_sched_held(),
+                          "sched RCU must be held");
        for_each_cpu_and(i, rd->span, cpu_active_mask)
                cpus++;
 
@@ -2095,7 +2127,7 @@ void wake_up_new_task(struct task_struct *p)
        init_task_runnable_average(p);
        rq = __task_rq_lock(p);
        activate_task(rq, p, 0);
-       p->on_rq = 1;
+       p->on_rq = TASK_ON_RQ_QUEUED;
        trace_sched_wakeup_new(p, true);
        check_preempt_curr(rq, p, WF_FORK);
 #ifdef CONFIG_SMP
@@ -2287,10 +2319,6 @@ asmlinkage __visible void schedule_tail(struct task_struct *prev)
         */
        post_schedule(rq);
 
-#ifdef __ARCH_WANT_UNLOCKED_CTXSW
-       /* In this case, finish_task_switch does not reenable preemption */
-       preempt_enable();
-#endif
        if (current->set_child_tid)
                put_user(task_pid_vnr(current), current->set_child_tid);
 }
@@ -2333,9 +2361,7 @@ context_switch(struct rq *rq, struct task_struct *prev,
         * of the scheduler it's an obvious special-case), so we
         * do an early lockdep release here:
         */
-#ifndef __ARCH_WANT_UNLOCKED_CTXSW
        spin_release(&rq->lock.dep_map, 1, _THIS_IP_);
-#endif
 
        context_tracking_task_switch(prev, next);
        /* Here we just switch the register state and the stack. */
@@ -2463,7 +2489,7 @@ static u64 do_task_delta_exec(struct task_struct *p, struct rq *rq)
         * project cycles that may never be accounted to this
         * thread, breaking clock_gettime().
         */
-       if (task_current(rq, p) && p->on_rq) {
+       if (task_current(rq, p) && task_on_rq_queued(p)) {
                update_rq_clock(rq);
                ns = rq_clock_task(rq) - p->se.exec_start;
                if ((s64)ns < 0)
@@ -2509,7 +2535,7 @@ unsigned long long task_sched_runtime(struct task_struct *p)
         * If we see ->on_cpu without ->on_rq, the task is leaving, and has
         * been accounted, so we're correct here as well.
         */
-       if (!p->on_cpu || !p->on_rq)
+       if (!p->on_cpu || !task_on_rq_queued(p))
                return p->se.sum_exec_runtime;
 #endif
 
@@ -2672,6 +2698,9 @@ static noinline void __schedule_bug(struct task_struct *prev)
  */
 static inline void schedule_debug(struct task_struct *prev)
 {
+#ifdef CONFIG_SCHED_STACK_END_CHECK
+       BUG_ON(unlikely(task_stack_end_corrupted(prev)));
+#endif
        /*
         * Test if we are atomic. Since do_exit() needs to call into
         * schedule() atomically, we ignore that path. Otherwise whine
@@ -2813,7 +2842,7 @@ need_resched:
                switch_count = &prev->nvcsw;
        }
 
-       if (prev->on_rq || rq->skip_clock_update < 0)
+       if (task_on_rq_queued(prev) || rq->skip_clock_update < 0)
                update_rq_clock(rq);
 
        next = pick_next_task(rq, prev);
@@ -2978,7 +3007,7 @@ EXPORT_SYMBOL(default_wake_function);
  */
 void rt_mutex_setprio(struct task_struct *p, int prio)
 {
-       int oldprio, on_rq, running, enqueue_flag = 0;
+       int oldprio, queued, running, enqueue_flag = 0;
        struct rq *rq;
        const struct sched_class *prev_class;
 
@@ -3007,12 +3036,12 @@ void rt_mutex_setprio(struct task_struct *p, int prio)
        trace_sched_pi_setprio(p, prio);
        oldprio = p->prio;
        prev_class = p->sched_class;
-       on_rq = p->on_rq;
+       queued = task_on_rq_queued(p);
        running = task_current(rq, p);
-       if (on_rq)
+       if (queued)
                dequeue_task(rq, p, 0);
        if (running)
-               p->sched_class->put_prev_task(rq, p);
+               put_prev_task(rq, p);
 
        /*
         * Boosting condition are:
@@ -3049,7 +3078,7 @@ void rt_mutex_setprio(struct task_struct *p, int prio)
 
        if (running)
                p->sched_class->set_curr_task(rq);
-       if (on_rq)
+       if (queued)
                enqueue_task(rq, p, enqueue_flag);
 
        check_class_changed(rq, p, prev_class, oldprio);
@@ -3060,7 +3089,7 @@ out_unlock:
 
 void set_user_nice(struct task_struct *p, long nice)
 {
-       int old_prio, delta, on_rq;
+       int old_prio, delta, queued;
        unsigned long flags;
        struct rq *rq;
 
@@ -3081,8 +3110,8 @@ void set_user_nice(struct task_struct *p, long nice)
                p->static_prio = NICE_TO_PRIO(nice);
                goto out_unlock;
        }
-       on_rq = p->on_rq;
-       if (on_rq)
+       queued = task_on_rq_queued(p);
+       if (queued)
                dequeue_task(rq, p, 0);
 
        p->static_prio = NICE_TO_PRIO(nice);
@@ -3091,7 +3120,7 @@ void set_user_nice(struct task_struct *p, long nice)
        p->prio = effective_prio(p);
        delta = p->prio - old_prio;
 
-       if (on_rq) {
+       if (queued) {
                enqueue_task(rq, p, 0);
                /*
                 * If the task increased its priority or is running and
@@ -3363,7 +3392,7 @@ static int __sched_setscheduler(struct task_struct *p,
 {
        int newprio = dl_policy(attr->sched_policy) ? MAX_DL_PRIO - 1 :
                      MAX_RT_PRIO - 1 - attr->sched_priority;
-       int retval, oldprio, oldpolicy = -1, on_rq, running;
+       int retval, oldprio, oldpolicy = -1, queued, running;
        int policy = attr->sched_policy;
        unsigned long flags;
        const struct sched_class *prev_class;
@@ -3560,19 +3589,19 @@ change:
                return 0;
        }
 
-       on_rq = p->on_rq;
+       queued = task_on_rq_queued(p);
        running = task_current(rq, p);
-       if (on_rq)
+       if (queued)
                dequeue_task(rq, p, 0);
        if (running)
-               p->sched_class->put_prev_task(rq, p);
+               put_prev_task(rq, p);
 
        prev_class = p->sched_class;
        __setscheduler(rq, p, attr);
 
        if (running)
                p->sched_class->set_curr_task(rq);
-       if (on_rq) {
+       if (queued) {
                /*
                 * We enqueue to tail when the priority of a task is
                 * increased (user space view).
@@ -3996,14 +4025,14 @@ long sched_setaffinity(pid_t pid, const struct cpumask *in_mask)
                rcu_read_lock();
                if (!ns_capable(__task_cred(p)->user_ns, CAP_SYS_NICE)) {
                        rcu_read_unlock();
-                       goto out_unlock;
+                       goto out_free_new_mask;
                }
                rcu_read_unlock();
        }
 
        retval = security_task_setscheduler(p);
        if (retval)
-               goto out_unlock;
+               goto out_free_new_mask;
 
 
        cpuset_cpus_allowed(p, cpus_allowed);
@@ -4016,13 +4045,14 @@ long sched_setaffinity(pid_t pid, const struct cpumask *in_mask)
         * root_domain.
         */
 #ifdef CONFIG_SMP
-       if (task_has_dl_policy(p)) {
-               const struct cpumask *span = task_rq(p)->rd->span;
-
-               if (dl_bandwidth_enabled() && !cpumask_subset(span, new_mask)) {
+       if (task_has_dl_policy(p) && dl_bandwidth_enabled()) {
+               rcu_read_lock();
+               if (!cpumask_subset(task_rq(p)->rd->span, new_mask)) {
                        retval = -EBUSY;
-                       goto out_unlock;
+                       rcu_read_unlock();
+                       goto out_free_new_mask;
                }
+               rcu_read_unlock();
        }
 #endif
 again:
@@ -4040,7 +4070,7 @@ again:
                        goto again;
                }
        }
-out_unlock:
+out_free_new_mask:
        free_cpumask_var(new_mask);
 out_free_cpus_allowed:
        free_cpumask_var(cpus_allowed);
@@ -4524,7 +4554,7 @@ void show_state_filter(unsigned long state_filter)
                "  task                        PC stack   pid father\n");
 #endif
        rcu_read_lock();
-       do_each_thread(g, p) {
+       for_each_process_thread(g, p) {
                /*
                 * reset the NMI-timeout, listing all files on a slow
                 * console might take a lot of time:
@@ -4532,7 +4562,7 @@ void show_state_filter(unsigned long state_filter)
                touch_nmi_watchdog();
                if (!state_filter || (p->state & state_filter))
                        sched_show_task(p);
-       } while_each_thread(g, p);
+       }
 
        touch_all_softlockup_watchdogs();
 
@@ -4587,7 +4617,7 @@ void init_idle(struct task_struct *idle, int cpu)
        rcu_read_unlock();
 
        rq->curr = rq->idle = idle;
-       idle->on_rq = 1;
+       idle->on_rq = TASK_ON_RQ_QUEUED;
 #if defined(CONFIG_SMP)
        idle->on_cpu = 1;
 #endif
@@ -4608,6 +4638,33 @@ void init_idle(struct task_struct *idle, int cpu)
 }
 
 #ifdef CONFIG_SMP
+/*
+ * move_queued_task - move a queued task to new rq.
+ *
+ * Returns (locked) new rq. Old rq's lock is released.
+ */
+static struct rq *move_queued_task(struct task_struct *p, int new_cpu)
+{
+       struct rq *rq = task_rq(p);
+
+       lockdep_assert_held(&rq->lock);
+
+       dequeue_task(rq, p, 0);
+       p->on_rq = TASK_ON_RQ_MIGRATING;
+       set_task_cpu(p, new_cpu);
+       raw_spin_unlock(&rq->lock);
+
+       rq = cpu_rq(new_cpu);
+
+       raw_spin_lock(&rq->lock);
+       BUG_ON(task_cpu(p) != new_cpu);
+       p->on_rq = TASK_ON_RQ_QUEUED;
+       enqueue_task(rq, p, 0);
+       check_preempt_curr(rq, p, 0);
+
+       return rq;
+}
+
 void do_set_cpus_allowed(struct task_struct *p, const struct cpumask *new_mask)
 {
        if (p->sched_class && p->sched_class->set_cpus_allowed)
@@ -4664,14 +4721,15 @@ int set_cpus_allowed_ptr(struct task_struct *p, const struct cpumask *new_mask)
                goto out;
 
        dest_cpu = cpumask_any_and(cpu_active_mask, new_mask);
-       if (p->on_rq) {
+       if (task_running(rq, p) || p->state == TASK_WAKING) {
                struct migration_arg arg = { p, dest_cpu };
                /* Need help from migration thread: drop lock and wait. */
                task_rq_unlock(rq, p, &flags);
                stop_one_cpu(cpu_of(rq), migration_cpu_stop, &arg);
                tlb_migrate_finish(p->mm);
                return 0;
-       }
+       } else if (task_on_rq_queued(p))
+               rq = move_queued_task(p, dest_cpu);
 out:
        task_rq_unlock(rq, p, &flags);
 
@@ -4692,20 +4750,20 @@ EXPORT_SYMBOL_GPL(set_cpus_allowed_ptr);
  */
 static int __migrate_task(struct task_struct *p, int src_cpu, int dest_cpu)
 {
-       struct rq *rq_dest, *rq_src;
+       struct rq *rq;
        int ret = 0;
 
        if (unlikely(!cpu_active(dest_cpu)))
                return ret;
 
-       rq_src = cpu_rq(src_cpu);
-       rq_dest = cpu_rq(dest_cpu);
+       rq = cpu_rq(src_cpu);
 
        raw_spin_lock(&p->pi_lock);
-       double_rq_lock(rq_src, rq_dest);
+       raw_spin_lock(&rq->lock);
        /* Already moved. */
        if (task_cpu(p) != src_cpu)
                goto done;
+
        /* Affinity changed (again). */
        if (!cpumask_test_cpu(dest_cpu, tsk_cpus_allowed(p)))
                goto fail;
@@ -4714,16 +4772,12 @@ static int __migrate_task(struct task_struct *p, int src_cpu, int dest_cpu)
         * If we're not on a rq, the next wake-up will ensure we're
         * placed properly.
         */
-       if (p->on_rq) {
-               dequeue_task(rq_src, p, 0);
-               set_task_cpu(p, dest_cpu);
-               enqueue_task(rq_dest, p, 0);
-               check_preempt_curr(rq_dest, p, 0);
-       }
+       if (task_on_rq_queued(p))
+               rq = move_queued_task(p, dest_cpu);
 done:
        ret = 1;
 fail:
-       double_rq_unlock(rq_src, rq_dest);
+       raw_spin_unlock(&rq->lock);
        raw_spin_unlock(&p->pi_lock);
        return ret;
 }
@@ -4755,22 +4809,22 @@ void sched_setnuma(struct task_struct *p, int nid)
 {
        struct rq *rq;
        unsigned long flags;
-       bool on_rq, running;
+       bool queued, running;
 
        rq = task_rq_lock(p, &flags);
-       on_rq = p->on_rq;
+       queued = task_on_rq_queued(p);
        running = task_current(rq, p);
 
-       if (on_rq)
+       if (queued)
                dequeue_task(rq, p, 0);
        if (running)
-               p->sched_class->put_prev_task(rq, p);
+               put_prev_task(rq, p);
 
        p->numa_preferred_nid = nid;
 
        if (running)
                p->sched_class->set_curr_task(rq);
-       if (on_rq)
+       if (queued)
                enqueue_task(rq, p, 0);
        task_rq_unlock(rq, p, &flags);
 }
@@ -4790,6 +4844,12 @@ static int migration_cpu_stop(void *data)
         * be on another cpu but it doesn't matter.
         */
        local_irq_disable();
+       /*
+        * We need to explicitly wake pending tasks before running
+        * __migrate_task() such that we will not miss enforcing cpus_allowed
+        * during wakeups, see set_cpus_allowed_ptr()'s TASK_WAKING test.
+        */
+       sched_ttwu_pending();
        __migrate_task(arg->task, raw_smp_processor_id(), arg->dest_cpu);
        local_irq_enable();
        return 0;
@@ -5200,6 +5260,7 @@ static int sched_cpu_inactive(struct notifier_block *nfb,
 {
        unsigned long flags;
        long cpu = (long)hcpu;
+       struct dl_bw *dl_b;
 
        switch (action & ~CPU_TASKS_FROZEN) {
        case CPU_DOWN_PREPARE:
@@ -5207,15 +5268,19 @@ static int sched_cpu_inactive(struct notifier_block *nfb,
 
                /* explicitly allow suspend */
                if (!(action & CPU_TASKS_FROZEN)) {
-                       struct dl_bw *dl_b = dl_bw_of(cpu);
                        bool overflow;
                        int cpus;
 
+                       rcu_read_lock_sched();
+                       dl_b = dl_bw_of(cpu);
+
                        raw_spin_lock_irqsave(&dl_b->lock, flags);
                        cpus = dl_bw_cpus(cpu);
                        overflow = __dl_overflow(dl_b, cpus, 0, 0);
                        raw_spin_unlock_irqrestore(&dl_b->lock, flags);
 
+                       rcu_read_unlock_sched();
+
                        if (overflow)
                                return notifier_from_errno(-EBUSY);
                }
@@ -5758,7 +5823,7 @@ build_overlap_sched_groups(struct sched_domain *sd, int cpu)
        const struct cpumask *span = sched_domain_span(sd);
        struct cpumask *covered = sched_domains_tmpmask;
        struct sd_data *sdd = sd->private;
-       struct sched_domain *child;
+       struct sched_domain *sibling;
        int i;
 
        cpumask_clear(covered);
@@ -5769,10 +5834,10 @@ build_overlap_sched_groups(struct sched_domain *sd, int cpu)
                if (cpumask_test_cpu(i, covered))
                        continue;
 
-               child = *per_cpu_ptr(sdd->sd, i);
+               sibling = *per_cpu_ptr(sdd->sd, i);
 
                /* See the comment near build_group_mask(). */
-               if (!cpumask_test_cpu(i, sched_domain_span(child)))
+               if (!cpumask_test_cpu(i, sched_domain_span(sibling)))
                        continue;
 
                sg = kzalloc_node(sizeof(struct sched_group) + cpumask_size(),
@@ -5782,10 +5847,9 @@ build_overlap_sched_groups(struct sched_domain *sd, int cpu)
                        goto fail;
 
                sg_span = sched_group_cpus(sg);
-               if (child->child) {
-                       child = child->child;
-                       cpumask_copy(sg_span, sched_domain_span(child));
-               } else
+               if (sibling->child)
+                       cpumask_copy(sg_span, sched_domain_span(sibling->child));
+               else
                        cpumask_set_cpu(i, sg_span);
 
                cpumask_or(covered, covered, sg_span);
@@ -7136,13 +7200,13 @@ static void normalize_task(struct rq *rq, struct task_struct *p)
                .sched_policy = SCHED_NORMAL,
        };
        int old_prio = p->prio;
-       int on_rq;
+       int queued;
 
-       on_rq = p->on_rq;
-       if (on_rq)
+       queued = task_on_rq_queued(p);
+       if (queued)
                dequeue_task(rq, p, 0);
        __setscheduler(rq, p, &attr);
-       if (on_rq) {
+       if (queued) {
                enqueue_task(rq, p, 0);
                resched_curr(rq);
        }
@@ -7156,12 +7220,12 @@ void normalize_rt_tasks(void)
        unsigned long flags;
        struct rq *rq;
 
-       read_lock_irqsave(&tasklist_lock, flags);
-       do_each_thread(g, p) {
+       read_lock(&tasklist_lock);
+       for_each_process_thread(g, p) {
                /*
                 * Only normalize user tasks:
                 */
-               if (!p->mm)
+               if (p->flags & PF_KTHREAD)
                        continue;
 
                p->se.exec_start                = 0;
@@ -7176,21 +7240,16 @@ void normalize_rt_tasks(void)
                         * Renice negative nice level userspace
                         * tasks back to 0:
                         */
-                       if (task_nice(p) < 0 && p->mm)
+                       if (task_nice(p) < 0)
                                set_user_nice(p, 0);
                        continue;
                }
 
-               raw_spin_lock(&p->pi_lock);
-               rq = __task_rq_lock(p);
-
+               rq = task_rq_lock(p, &flags);
                normalize_task(rq, p);
-
-               __task_rq_unlock(rq);
-               raw_spin_unlock(&p->pi_lock);
-       } while_each_thread(g, p);
-
-       read_unlock_irqrestore(&tasklist_lock, flags);
+               task_rq_unlock(rq, p, &flags);
+       }
+       read_unlock(&tasklist_lock);
 }
 
 #endif /* CONFIG_MAGIC_SYSRQ */
@@ -7330,19 +7389,19 @@ void sched_offline_group(struct task_group *tg)
 void sched_move_task(struct task_struct *tsk)
 {
        struct task_group *tg;
-       int on_rq, running;
+       int queued, running;
        unsigned long flags;
        struct rq *rq;
 
        rq = task_rq_lock(tsk, &flags);
 
        running = task_current(rq, tsk);
-       on_rq = tsk->on_rq;
+       queued = task_on_rq_queued(tsk);
 
-       if (on_rq)
+       if (queued)
                dequeue_task(rq, tsk, 0);
        if (unlikely(running))
-               tsk->sched_class->put_prev_task(rq, tsk);
+               put_prev_task(rq, tsk);
 
        tg = container_of(task_css_check(tsk, cpu_cgrp_id,
                                lockdep_is_held(&tsk->sighand->siglock)),
@@ -7352,14 +7411,14 @@ void sched_move_task(struct task_struct *tsk)
 
 #ifdef CONFIG_FAIR_GROUP_SCHED
        if (tsk->sched_class->task_move_group)
-               tsk->sched_class->task_move_group(tsk, on_rq);
+               tsk->sched_class->task_move_group(tsk, queued);
        else
 #endif
                set_task_rq(tsk, task_cpu(tsk));
 
        if (unlikely(running))
                tsk->sched_class->set_curr_task(rq);
-       if (on_rq)
+       if (queued)
                enqueue_task(rq, tsk, 0);
 
        task_rq_unlock(rq, tsk, &flags);
@@ -7377,10 +7436,10 @@ static inline int tg_has_rt_tasks(struct task_group *tg)
 {
        struct task_struct *g, *p;
 
-       do_each_thread(g, p) {
-               if (rt_task(p) && task_rq(p)->rt.tg == tg)
+       for_each_process_thread(g, p) {
+               if (rt_task(p) && task_group(p) == tg)
                        return 1;
-       } while_each_thread(g, p);
+       }
 
        return 0;
 }
@@ -7589,6 +7648,7 @@ static int sched_dl_global_constraints(void)
        u64 runtime = global_rt_runtime();
        u64 period = global_rt_period();
        u64 new_bw = to_ratio(period, runtime);
+       struct dl_bw *dl_b;
        int cpu, ret = 0;
        unsigned long flags;
 
@@ -7602,13 +7662,16 @@ static int sched_dl_global_constraints(void)
         * solutions is welcome!
         */
        for_each_possible_cpu(cpu) {
-               struct dl_bw *dl_b = dl_bw_of(cpu);
+               rcu_read_lock_sched();
+               dl_b = dl_bw_of(cpu);
 
                raw_spin_lock_irqsave(&dl_b->lock, flags);
                if (new_bw < dl_b->total_bw)
                        ret = -EBUSY;
                raw_spin_unlock_irqrestore(&dl_b->lock, flags);
 
+               rcu_read_unlock_sched();
+
                if (ret)
                        break;
        }
@@ -7619,6 +7682,7 @@ static int sched_dl_global_constraints(void)
 static void sched_dl_do_global(void)
 {
        u64 new_bw = -1;
+       struct dl_bw *dl_b;
        int cpu;
        unsigned long flags;
 
@@ -7632,11 +7696,14 @@ static void sched_dl_do_global(void)
         * FIXME: As above...
         */
        for_each_possible_cpu(cpu) {
-               struct dl_bw *dl_b = dl_bw_of(cpu);
+               rcu_read_lock_sched();
+               dl_b = dl_bw_of(cpu);
 
                raw_spin_lock_irqsave(&dl_b->lock, flags);
                dl_b->bw = new_bw;
                raw_spin_unlock_irqrestore(&dl_b->lock, flags);
+
+               rcu_read_unlock_sched();
        }
 }
 
@@ -8017,7 +8084,7 @@ static int tg_cfs_schedulable_down(struct task_group *tg, void *data)
                struct cfs_bandwidth *parent_b = &tg->parent->cfs_bandwidth;
 
                quota = normalize_cfs_quota(tg, d);
-               parent_quota = parent_b->hierarchal_quota;
+               parent_quota = parent_b->hierarchical_quota;
 
                /*
                 * ensure max(child_quota) <= parent_quota, inherit when no
@@ -8028,7 +8095,7 @@ static int tg_cfs_schedulable_down(struct task_group *tg, void *data)
                else if (parent_quota != RUNTIME_INF && quota > parent_quota)
                        return -EINVAL;
        }
-       cfs_b->hierarchal_quota = quota;
+       cfs_b->hierarchical_quota = quota;
 
        return 0;
 }
index bd95963dae80b92c34536d244de0986257e6490f..539ca3ce071b2858f437cd0d0265d473093be9e2 100644 (file)
@@ -107,9 +107,7 @@ int cpudl_find(struct cpudl *cp, struct task_struct *p,
        int best_cpu = -1;
        const struct sched_dl_entity *dl_se = &p->dl;
 
-       if (later_mask && cpumask_and(later_mask, cp->free_cpus,
-                       &p->cpus_allowed) && cpumask_and(later_mask,
-                       later_mask, cpu_active_mask)) {
+       if (later_mask && cpumask_and(later_mask, later_mask, cp->free_cpus)) {
                best_cpu = cpumask_any(later_mask);
                goto out;
        } else if (cpumask_test_cpu(cpudl_maximum(cp), &p->cpus_allowed) &&
index 72fdf06ef8652d5cb443b080f53ac117bd5517ba..8394b1ee600c38ba6e9144a6326369b6ef0cdacd 100644 (file)
@@ -288,24 +288,29 @@ void thread_group_cputime(struct task_struct *tsk, struct task_cputime *times)
        struct signal_struct *sig = tsk->signal;
        cputime_t utime, stime;
        struct task_struct *t;
-
-       times->utime = sig->utime;
-       times->stime = sig->stime;
-       times->sum_exec_runtime = sig->sum_sched_runtime;
+       unsigned int seq, nextseq;
+       unsigned long flags;
 
        rcu_read_lock();
-       /* make sure we can trust tsk->thread_group list */
-       if (!likely(pid_alive(tsk)))
-               goto out;
-
-       t = tsk;
+       /* Attempt a lockless read on the first round. */
+       nextseq = 0;
        do {
-               task_cputime(t, &utime, &stime);
-               times->utime += utime;
-               times->stime += stime;
-               times->sum_exec_runtime += task_sched_runtime(t);
-       } while_each_thread(tsk, t);
-out:
+               seq = nextseq;
+               flags = read_seqbegin_or_lock_irqsave(&sig->stats_lock, &seq);
+               times->utime = sig->utime;
+               times->stime = sig->stime;
+               times->sum_exec_runtime = sig->sum_sched_runtime;
+
+               for_each_thread(tsk, t) {
+                       task_cputime(t, &utime, &stime);
+                       times->utime += utime;
+                       times->stime += stime;
+                       times->sum_exec_runtime += task_sched_runtime(t);
+               }
+               /* If lockless access failed, take the lock. */
+               nextseq = 1;
+       } while (need_seqretry(&sig->stats_lock, seq));
+       done_seqretry_irqrestore(&sig->stats_lock, seq, flags);
        rcu_read_unlock();
 }
 
@@ -549,6 +554,23 @@ drop_precision:
        return (__force cputime_t) scaled;
 }
 
+/*
+ * Atomically advance counter to the new value. Interrupts, vcpu
+ * scheduling, and scaling inaccuracies can cause cputime_advance
+ * to be occasionally called with a new value smaller than counter.
+ * Let's enforce atomicity.
+ *
+ * Normally a caller will only go through this loop once, or not
+ * at all in case a previous caller updated counter the same jiffy.
+ */
+static void cputime_advance(cputime_t *counter, cputime_t new)
+{
+       cputime_t old;
+
+       while (new > (old = ACCESS_ONCE(*counter)))
+               cmpxchg_cputime(counter, old, new);
+}
+
 /*
  * Adjust tick based cputime random precision against scheduler
  * runtime accounting.
@@ -594,13 +616,8 @@ static void cputime_adjust(struct task_cputime *curr,
                utime = rtime - stime;
        }
 
-       /*
-        * If the tick based count grows faster than the scheduler one,
-        * the result of the scaling may go backward.
-        * Let's enforce monotonicity.
-        */
-       prev->stime = max(prev->stime, stime);
-       prev->utime = max(prev->utime, utime);
+       cputime_advance(&prev->stime, stime);
+       cputime_advance(&prev->utime, utime);
 
 out:
        *ut = prev->utime;
@@ -617,9 +634,6 @@ void task_cputime_adjusted(struct task_struct *p, cputime_t *ut, cputime_t *st)
        cputime_adjust(&cputime, &p->prev_cputime, ut, st);
 }
 
-/*
- * Must be called with siglock held.
- */
 void thread_group_cputime_adjusted(struct task_struct *p, cputime_t *ut, cputime_t *st)
 {
        struct task_cputime cputime;
index 255ce138b65232dabcc553c54340f45440ca2792..abfaf3d9a29f0f3daebaff2937c7ec0d0303daaf 100644 (file)
@@ -530,7 +530,7 @@ again:
        update_rq_clock(rq);
        dl_se->dl_throttled = 0;
        dl_se->dl_yielded = 0;
-       if (p->on_rq) {
+       if (task_on_rq_queued(p)) {
                enqueue_task_dl(rq, p, ENQUEUE_REPLENISH);
                if (task_has_dl_policy(rq->curr))
                        check_preempt_curr_dl(rq, p, 0);
@@ -997,10 +997,7 @@ static void check_preempt_curr_dl(struct rq *rq, struct task_struct *p,
 #ifdef CONFIG_SCHED_HRTICK
 static void start_hrtick_dl(struct rq *rq, struct task_struct *p)
 {
-       s64 delta = p->dl.dl_runtime - p->dl.runtime;
-
-       if (delta > 10000)
-               hrtick_start(rq, p->dl.runtime);
+       hrtick_start(rq, p->dl.runtime);
 }
 #endif
 
@@ -1030,7 +1027,7 @@ struct task_struct *pick_next_task_dl(struct rq *rq, struct task_struct *prev)
                 * means a stop task can slip in, in which case we need to
                 * re-start task selection.
                 */
-               if (rq->stop && rq->stop->on_rq)
+               if (rq->stop && task_on_rq_queued(rq->stop))
                        return RETRY_TASK;
        }
 
@@ -1124,10 +1121,8 @@ static void set_curr_task_dl(struct rq *rq)
 static int pick_dl_task(struct rq *rq, struct task_struct *p, int cpu)
 {
        if (!task_running(rq, p) &&
-           (cpu < 0 || cpumask_test_cpu(cpu, &p->cpus_allowed)) &&
-           (p->nr_cpus_allowed > 1))
+           cpumask_test_cpu(cpu, tsk_cpus_allowed(p)))
                return 1;
-
        return 0;
 }
 
@@ -1169,6 +1164,13 @@ static int find_later_rq(struct task_struct *task)
        if (task->nr_cpus_allowed == 1)
                return -1;
 
+       /*
+        * We have to consider system topology and task affinity
+        * first, then we can look for a suitable cpu.
+        */
+       cpumask_copy(later_mask, task_rq(task)->rd->span);
+       cpumask_and(later_mask, later_mask, cpu_active_mask);
+       cpumask_and(later_mask, later_mask, &task->cpus_allowed);
        best_cpu = cpudl_find(&task_rq(task)->rd->cpudl,
                        task, later_mask);
        if (best_cpu == -1)
@@ -1257,7 +1259,8 @@ static struct rq *find_lock_later_rq(struct task_struct *task, struct rq *rq)
                        if (unlikely(task_rq(task) != rq ||
                                     !cpumask_test_cpu(later_rq->cpu,
                                                       &task->cpus_allowed) ||
-                                    task_running(rq, task) || !task->on_rq)) {
+                                    task_running(rq, task) ||
+                                    !task_on_rq_queued(task))) {
                                double_unlock_balance(rq, later_rq);
                                later_rq = NULL;
                                break;
@@ -1296,7 +1299,7 @@ static struct task_struct *pick_next_pushable_dl_task(struct rq *rq)
        BUG_ON(task_current(rq, p));
        BUG_ON(p->nr_cpus_allowed <= 1);
 
-       BUG_ON(!p->on_rq);
+       BUG_ON(!task_on_rq_queued(p));
        BUG_ON(!dl_task(p));
 
        return p;
@@ -1443,7 +1446,7 @@ static int pull_dl_task(struct rq *this_rq)
                     dl_time_before(p->dl.deadline,
                                    this_rq->dl.earliest_dl.curr))) {
                        WARN_ON(p == src_rq->curr);
-                       WARN_ON(!p->on_rq);
+                       WARN_ON(!task_on_rq_queued(p));
 
                        /*
                         * Then we pull iff p has actually an earlier
@@ -1569,6 +1572,8 @@ static void switched_from_dl(struct rq *rq, struct task_struct *p)
        if (hrtimer_active(&p->dl.dl_timer) && !dl_policy(p->policy))
                hrtimer_try_to_cancel(&p->dl.dl_timer);
 
+       __dl_clear_params(p);
+
 #ifdef CONFIG_SMP
        /*
         * Since this might be the only -deadline task on the rq,
@@ -1596,7 +1601,7 @@ static void switched_to_dl(struct rq *rq, struct task_struct *p)
        if (unlikely(p->dl.dl_throttled))
                return;
 
-       if (p->on_rq && rq->curr != p) {
+       if (task_on_rq_queued(p) && rq->curr != p) {
 #ifdef CONFIG_SMP
                if (rq->dl.overloaded && push_dl_task(rq) && rq != task_rq(p))
                        /* Only reschedule if pushing failed */
@@ -1614,7 +1619,7 @@ static void switched_to_dl(struct rq *rq, struct task_struct *p)
 static void prio_changed_dl(struct rq *rq, struct task_struct *p,
                            int oldprio)
 {
-       if (p->on_rq || rq->curr == p) {
+       if (task_on_rq_queued(p) || rq->curr == p) {
 #ifdef CONFIG_SMP
                /*
                 * This might be too much, but unfortunately
index 627b3c34b821de4471acd21e0591fc5fb8968a62..ce33780d8f20122ec263021db060cdacbaee7e41 100644 (file)
@@ -150,7 +150,6 @@ print_task(struct seq_file *m, struct rq *rq, struct task_struct *p)
 static void print_rq(struct seq_file *m, struct rq *rq, int rq_cpu)
 {
        struct task_struct *g, *p;
-       unsigned long flags;
 
        SEQ_printf(m,
        "\nrunnable tasks:\n"
@@ -159,16 +158,14 @@ static void print_rq(struct seq_file *m, struct rq *rq, int rq_cpu)
        "------------------------------------------------------"
        "----------------------------------------------------\n");
 
-       read_lock_irqsave(&tasklist_lock, flags);
-
-       do_each_thread(g, p) {
+       rcu_read_lock();
+       for_each_process_thread(g, p) {
                if (task_cpu(p) != rq_cpu)
                        continue;
 
                print_task(m, rq, p);
-       } while_each_thread(g, p);
-
-       read_unlock_irqrestore(&tasklist_lock, flags);
+       }
+       rcu_read_unlock();
 }
 
 void print_cfs_rq(struct seq_file *m, int cpu, struct cfs_rq *cfs_rq)
@@ -333,9 +330,7 @@ do {                                                                        \
        print_cfs_stats(m, cpu);
        print_rt_stats(m, cpu);
 
-       rcu_read_lock();
        print_rq(m, rq, cpu);
-       rcu_read_unlock();
        spin_unlock_irqrestore(&sched_debug_lock, flags);
        SEQ_printf(m, "\n");
 }
index 82088b29704ef80ddee61724db4f694a5c7d2ad6..b78280c59b4693d9a546d639a702c7c8d64eff89 100644 (file)
@@ -23,6 +23,7 @@
 #include <linux/latencytop.h>
 #include <linux/sched.h>
 #include <linux/cpumask.h>
+#include <linux/cpuidle.h>
 #include <linux/slab.h>
 #include <linux/profile.h>
 #include <linux/interrupt.h>
@@ -665,6 +666,7 @@ static u64 sched_vslice(struct cfs_rq *cfs_rq, struct sched_entity *se)
 }
 
 #ifdef CONFIG_SMP
+static int select_idle_sibling(struct task_struct *p, int cpu);
 static unsigned long task_h_load(struct task_struct *p);
 
 static inline void __update_task_entity_contrib(struct sched_entity *se);
@@ -1038,7 +1040,8 @@ struct numa_stats {
  */
 static void update_numa_stats(struct numa_stats *ns, int nid)
 {
-       int cpu, cpus = 0;
+       int smt, cpu, cpus = 0;
+       unsigned long capacity;
 
        memset(ns, 0, sizeof(*ns));
        for_each_cpu(cpu, cpumask_of_node(nid)) {
@@ -1062,8 +1065,12 @@ static void update_numa_stats(struct numa_stats *ns, int nid)
        if (!cpus)
                return;
 
-       ns->task_capacity =
-               DIV_ROUND_CLOSEST(ns->compute_capacity, SCHED_CAPACITY_SCALE);
+       /* smt := ceil(cpus / capacity), assumes: 1 < smt_power < 2 */
+       smt = DIV_ROUND_UP(SCHED_CAPACITY_SCALE * cpus, ns->compute_capacity);
+       capacity = cpus / smt; /* cores */
+
+       ns->task_capacity = min_t(unsigned, capacity,
+               DIV_ROUND_CLOSEST(ns->compute_capacity, SCHED_CAPACITY_SCALE));
        ns->has_free_capacity = (ns->nr_running < ns->task_capacity);
 }
 
@@ -1206,7 +1213,7 @@ static void task_numa_compare(struct task_numa_env *env,
 
        if (!cur) {
                /* Is there capacity at our destination? */
-               if (env->src_stats.has_free_capacity &&
+               if (env->src_stats.nr_running <= env->src_stats.task_capacity &&
                    !env->dst_stats.has_free_capacity)
                        goto unlock;
 
@@ -1252,6 +1259,13 @@ balance:
        if (load_too_imbalanced(src_load, dst_load, env))
                goto unlock;
 
+       /*
+        * One idle CPU per node is evaluated for a task numa move.
+        * Call select_idle_sibling to maybe find a better one.
+        */
+       if (!cur)
+               env->dst_cpu = select_idle_sibling(env->p, env->dst_cpu);
+
 assign:
        task_numa_assign(env, cur, imp);
 unlock:
@@ -1775,7 +1789,7 @@ void task_numa_free(struct task_struct *p)
                list_del(&p->numa_entry);
                grp->nr_tasks--;
                spin_unlock_irqrestore(&grp->lock, flags);
-               rcu_assign_pointer(p->numa_group, NULL);
+               RCU_INIT_POINTER(p->numa_group, NULL);
                put_numa_group(grp);
        }
 
@@ -1804,10 +1818,6 @@ void task_numa_fault(int last_cpupid, int mem_node, int pages, int flags)
        if (!p->mm)
                return;
 
-       /* Do not worry about placement if exiting */
-       if (p->state == TASK_DEAD)
-               return;
-
        /* Allocate buffer to track faults on a per-node basis */
        if (unlikely(!p->numa_faults_memory)) {
                int size = sizeof(*p->numa_faults_memory) *
@@ -2211,8 +2221,8 @@ static __always_inline u64 decay_load(u64 val, u64 n)
 
        /*
         * As y^PERIOD = 1/2, we can combine
-        *    y^n = 1/2^(n/PERIOD) * k^(n%PERIOD)
-        * With a look-up table which covers k^n (n<PERIOD)
+        *    y^n = 1/2^(n/PERIOD) * y^(n%PERIOD)
+        * With a look-up table which covers y^n (n<PERIOD)
         *
         * To achieve constant time decay_load.
         */
@@ -2377,6 +2387,9 @@ static inline void __update_cfs_rq_tg_load_contrib(struct cfs_rq *cfs_rq,
        tg_contrib = cfs_rq->runnable_load_avg + cfs_rq->blocked_load_avg;
        tg_contrib -= cfs_rq->tg_load_contrib;
 
+       if (!tg_contrib)
+               return;
+
        if (force_update || abs(tg_contrib) > cfs_rq->tg_load_contrib / 8) {
                atomic_long_add(tg_contrib, &tg->load_avg);
                cfs_rq->tg_load_contrib += tg_contrib;
@@ -3892,14 +3905,6 @@ static void hrtick_start_fair(struct rq *rq, struct task_struct *p)
                                resched_curr(rq);
                        return;
                }
-
-               /*
-                * Don't schedule slices shorter than 10000ns, that just
-                * doesn't make sense. Rely on vruntime for fairness.
-                */
-               if (rq->curr != p)
-                       delta = max_t(s64, 10000LL, delta);
-
                hrtick_start(rq, delta);
        }
 }
@@ -4087,7 +4092,7 @@ static unsigned long capacity_of(int cpu)
 static unsigned long cpu_avg_load_per_task(int cpu)
 {
        struct rq *rq = cpu_rq(cpu);
-       unsigned long nr_running = ACCESS_ONCE(rq->nr_running);
+       unsigned long nr_running = ACCESS_ONCE(rq->cfs.h_nr_running);
        unsigned long load_avg = rq->cfs.runnable_load_avg;
 
        if (nr_running)
@@ -4276,8 +4281,8 @@ static int wake_wide(struct task_struct *p)
 static int wake_affine(struct sched_domain *sd, struct task_struct *p, int sync)
 {
        s64 this_load, load;
+       s64 this_eff_load, prev_eff_load;
        int idx, this_cpu, prev_cpu;
-       unsigned long tl_per_task;
        struct task_group *tg;
        unsigned long weight;
        int balanced;
@@ -4320,47 +4325,30 @@ static int wake_affine(struct sched_domain *sd, struct task_struct *p, int sync)
         * Otherwise check if either cpus are near enough in load to allow this
         * task to be woken on this_cpu.
         */
-       if (this_load > 0) {
-               s64 this_eff_load, prev_eff_load;
+       this_eff_load = 100;
+       this_eff_load *= capacity_of(prev_cpu);
 
-               this_eff_load = 100;
-               this_eff_load *= capacity_of(prev_cpu);
+       prev_eff_load = 100 + (sd->imbalance_pct - 100) / 2;
+       prev_eff_load *= capacity_of(this_cpu);
+
+       if (this_load > 0) {
                this_eff_load *= this_load +
                        effective_load(tg, this_cpu, weight, weight);
 
-               prev_eff_load = 100 + (sd->imbalance_pct - 100) / 2;
-               prev_eff_load *= capacity_of(this_cpu);
                prev_eff_load *= load + effective_load(tg, prev_cpu, 0, weight);
+       }
 
-               balanced = this_eff_load <= prev_eff_load;
-       } else
-               balanced = true;
-
-       /*
-        * If the currently running task will sleep within
-        * a reasonable amount of time then attract this newly
-        * woken task:
-        */
-       if (sync && balanced)
-               return 1;
+       balanced = this_eff_load <= prev_eff_load;
 
        schedstat_inc(p, se.statistics.nr_wakeups_affine_attempts);
-       tl_per_task = cpu_avg_load_per_task(this_cpu);
 
-       if (balanced ||
-           (this_load <= load &&
-            this_load + target_load(prev_cpu, idx) <= tl_per_task)) {
-               /*
-                * This domain has SD_WAKE_AFFINE and
-                * p is cache cold in this domain, and
-                * there is no bad imbalance.
-                */
-               schedstat_inc(sd, ttwu_move_affine);
-               schedstat_inc(p, se.statistics.nr_wakeups_affine);
+       if (!balanced)
+               return 0;
 
-               return 1;
-       }
-       return 0;
+       schedstat_inc(sd, ttwu_move_affine);
+       schedstat_inc(p, se.statistics.nr_wakeups_affine);
+
+       return 1;
 }
 
 /*
@@ -4428,20 +4416,46 @@ static int
 find_idlest_cpu(struct sched_group *group, struct task_struct *p, int this_cpu)
 {
        unsigned long load, min_load = ULONG_MAX;
-       int idlest = -1;
+       unsigned int min_exit_latency = UINT_MAX;
+       u64 latest_idle_timestamp = 0;
+       int least_loaded_cpu = this_cpu;
+       int shallowest_idle_cpu = -1;
        int i;
 
        /* Traverse only the allowed CPUs */
        for_each_cpu_and(i, sched_group_cpus(group), tsk_cpus_allowed(p)) {
-               load = weighted_cpuload(i);
-
-               if (load < min_load || (load == min_load && i == this_cpu)) {
-                       min_load = load;
-                       idlest = i;
+               if (idle_cpu(i)) {
+                       struct rq *rq = cpu_rq(i);
+                       struct cpuidle_state *idle = idle_get_state(rq);
+                       if (idle && idle->exit_latency < min_exit_latency) {
+                               /*
+                                * We give priority to a CPU whose idle state
+                                * has the smallest exit latency irrespective
+                                * of any idle timestamp.
+                                */
+                               min_exit_latency = idle->exit_latency;
+                               latest_idle_timestamp = rq->idle_stamp;
+                               shallowest_idle_cpu = i;
+                       } else if ((!idle || idle->exit_latency == min_exit_latency) &&
+                                  rq->idle_stamp > latest_idle_timestamp) {
+                               /*
+                                * If equal or no active idle state, then
+                                * the most recently idled CPU might have
+                                * a warmer cache.
+                                */
+                               latest_idle_timestamp = rq->idle_stamp;
+                               shallowest_idle_cpu = i;
+                       }
+               } else {
+                       load = weighted_cpuload(i);
+                       if (load < min_load || (load == min_load && i == this_cpu)) {
+                               min_load = load;
+                               least_loaded_cpu = i;
+                       }
                }
        }
 
-       return idlest;
+       return shallowest_idle_cpu != -1 ? shallowest_idle_cpu : least_loaded_cpu;
 }
 
 /*
@@ -4513,11 +4527,8 @@ select_task_rq_fair(struct task_struct *p, int prev_cpu, int sd_flag, int wake_f
        if (p->nr_cpus_allowed == 1)
                return prev_cpu;
 
-       if (sd_flag & SD_BALANCE_WAKE) {
-               if (cpumask_test_cpu(cpu, tsk_cpus_allowed(p)))
-                       want_affine = 1;
-               new_cpu = prev_cpu;
-       }
+       if (sd_flag & SD_BALANCE_WAKE)
+               want_affine = cpumask_test_cpu(cpu, tsk_cpus_allowed(p));
 
        rcu_read_lock();
        for_each_domain(cpu, tmp) {
@@ -4704,7 +4715,7 @@ static void check_preempt_wakeup(struct rq *rq, struct task_struct *p, int wake_
                return;
 
        /*
-        * This is possible from callers such as move_task(), in which we
+        * This is possible from callers such as attach_tasks(), in which we
         * unconditionally check_prempt_curr() after an enqueue (which may have
         * lead to a throttle).  This both saves work and prevents false
         * next-buddy nomination below.
@@ -5112,20 +5123,9 @@ struct lb_env {
        unsigned int            loop_max;
 
        enum fbq_type           fbq_type;
+       struct list_head        tasks;
 };
 
-/*
- * move_task - move a task from one runqueue to another runqueue.
- * Both runqueues must be locked.
- */
-static void move_task(struct task_struct *p, struct lb_env *env)
-{
-       deactivate_task(env->src_rq, p, 0);
-       set_task_cpu(p, env->dst_cpu);
-       activate_task(env->dst_rq, p, 0);
-       check_preempt_curr(env->dst_rq, p, 0);
-}
-
 /*
  * Is this task likely cache-hot:
  */
@@ -5133,6 +5133,8 @@ static int task_hot(struct task_struct *p, struct lb_env *env)
 {
        s64 delta;
 
+       lockdep_assert_held(&env->src_rq->lock);
+
        if (p->sched_class != &fair_sched_class)
                return 0;
 
@@ -5252,6 +5254,9 @@ static
 int can_migrate_task(struct task_struct *p, struct lb_env *env)
 {
        int tsk_cache_hot = 0;
+
+       lockdep_assert_held(&env->src_rq->lock);
+
        /*
         * We do not migrate tasks that are:
         * 1) throttled_lb_pair, or
@@ -5310,24 +5315,12 @@ int can_migrate_task(struct task_struct *p, struct lb_env *env)
        if (!tsk_cache_hot)
                tsk_cache_hot = migrate_degrades_locality(p, env);
 
-       if (migrate_improves_locality(p, env)) {
-#ifdef CONFIG_SCHEDSTATS
+       if (migrate_improves_locality(p, env) || !tsk_cache_hot ||
+           env->sd->nr_balance_failed > env->sd->cache_nice_tries) {
                if (tsk_cache_hot) {
                        schedstat_inc(env->sd, lb_hot_gained[env->idle]);
                        schedstat_inc(p, se.statistics.nr_forced_migrations);
                }
-#endif
-               return 1;
-       }
-
-       if (!tsk_cache_hot ||
-               env->sd->nr_balance_failed > env->sd->cache_nice_tries) {
-
-               if (tsk_cache_hot) {
-                       schedstat_inc(env->sd, lb_hot_gained[env->idle]);
-                       schedstat_inc(p, se.statistics.nr_forced_migrations);
-               }
-
                return 1;
        }
 
@@ -5336,47 +5329,63 @@ int can_migrate_task(struct task_struct *p, struct lb_env *env)
 }
 
 /*
- * move_one_task tries to move exactly one task from busiest to this_rq, as
+ * detach_task() -- detach the task for the migration specified in env
+ */
+static void detach_task(struct task_struct *p, struct lb_env *env)
+{
+       lockdep_assert_held(&env->src_rq->lock);
+
+       deactivate_task(env->src_rq, p, 0);
+       p->on_rq = TASK_ON_RQ_MIGRATING;
+       set_task_cpu(p, env->dst_cpu);
+}
+
+/*
+ * detach_one_task() -- tries to dequeue exactly one task from env->src_rq, as
  * part of active balancing operations within "domain".
- * Returns 1 if successful and 0 otherwise.
  *
- * Called with both runqueues locked.
+ * Returns a task if successful and NULL otherwise.
  */
-static int move_one_task(struct lb_env *env)
+static struct task_struct *detach_one_task(struct lb_env *env)
 {
        struct task_struct *p, *n;
 
+       lockdep_assert_held(&env->src_rq->lock);
+
        list_for_each_entry_safe(p, n, &env->src_rq->cfs_tasks, se.group_node) {
                if (!can_migrate_task(p, env))
                        continue;
 
-               move_task(p, env);
+               detach_task(p, env);
+
                /*
-                * Right now, this is only the second place move_task()
-                * is called, so we can safely collect move_task()
-                * stats here rather than inside move_task().
+                * Right now, this is only the second place where
+                * lb_gained[env->idle] is updated (other is detach_tasks)
+                * so we can safely collect stats here rather than
+                * inside detach_tasks().
                 */
                schedstat_inc(env->sd, lb_gained[env->idle]);
-               return 1;
+               return p;
        }
-       return 0;
+       return NULL;
 }
 
 static const unsigned int sched_nr_migrate_break = 32;
 
 /*
- * move_tasks tries to move up to imbalance weighted load from busiest to
- * this_rq, as part of a balancing operation within domain "sd".
- * Returns 1 if successful and 0 otherwise.
+ * detach_tasks() -- tries to detach up to imbalance weighted load from
+ * busiest_rq, as part of a balancing operation within domain "sd".
  *
- * Called with both runqueues locked.
+ * Returns number of detached tasks if successful and 0 otherwise.
  */
-static int move_tasks(struct lb_env *env)
+static int detach_tasks(struct lb_env *env)
 {
        struct list_head *tasks = &env->src_rq->cfs_tasks;
        struct task_struct *p;
        unsigned long load;
-       int pulled = 0;
+       int detached = 0;
+
+       lockdep_assert_held(&env->src_rq->lock);
 
        if (env->imbalance <= 0)
                return 0;
@@ -5407,14 +5416,16 @@ static int move_tasks(struct lb_env *env)
                if ((load / 2) > env->imbalance)
                        goto next;
 
-               move_task(p, env);
-               pulled++;
+               detach_task(p, env);
+               list_add(&p->se.group_node, &env->tasks);
+
+               detached++;
                env->imbalance -= load;
 
 #ifdef CONFIG_PREEMPT
                /*
                 * NEWIDLE balancing is a source of latency, so preemptible
-                * kernels will stop after the first task is pulled to minimize
+                * kernels will stop after the first task is detached to minimize
                 * the critical section.
                 */
                if (env->idle == CPU_NEWLY_IDLE)
@@ -5434,13 +5445,58 @@ next:
        }
 
        /*
-        * Right now, this is one of only two places move_task() is called,
-        * so we can safely collect move_task() stats here rather than
-        * inside move_task().
+        * Right now, this is one of only two places we collect this stat
+        * so we can safely collect detach_one_task() stats here rather
+        * than inside detach_one_task().
         */
-       schedstat_add(env->sd, lb_gained[env->idle], pulled);
+       schedstat_add(env->sd, lb_gained[env->idle], detached);
+
+       return detached;
+}
+
+/*
+ * attach_task() -- attach the task detached by detach_task() to its new rq.
+ */
+static void attach_task(struct rq *rq, struct task_struct *p)
+{
+       lockdep_assert_held(&rq->lock);
+
+       BUG_ON(task_rq(p) != rq);
+       p->on_rq = TASK_ON_RQ_QUEUED;
+       activate_task(rq, p, 0);
+       check_preempt_curr(rq, p, 0);
+}
+
+/*
+ * attach_one_task() -- attaches the task returned from detach_one_task() to
+ * its new rq.
+ */
+static void attach_one_task(struct rq *rq, struct task_struct *p)
+{
+       raw_spin_lock(&rq->lock);
+       attach_task(rq, p);
+       raw_spin_unlock(&rq->lock);
+}
+
+/*
+ * attach_tasks() -- attaches all tasks detached by detach_tasks() to their
+ * new rq.
+ */
+static void attach_tasks(struct lb_env *env)
+{
+       struct list_head *tasks = &env->tasks;
+       struct task_struct *p;
+
+       raw_spin_lock(&env->dst_rq->lock);
+
+       while (!list_empty(tasks)) {
+               p = list_first_entry(tasks, struct task_struct, se.group_node);
+               list_del_init(&p->se.group_node);
 
-       return pulled;
+               attach_task(env->dst_rq, p);
+       }
+
+       raw_spin_unlock(&env->dst_rq->lock);
 }
 
 #ifdef CONFIG_FAIR_GROUP_SCHED
@@ -5559,6 +5615,13 @@ static unsigned long task_h_load(struct task_struct *p)
 #endif
 
 /********** Helpers for find_busiest_group ************************/
+
+enum group_type {
+       group_other = 0,
+       group_imbalanced,
+       group_overloaded,
+};
+
 /*
  * sg_lb_stats - stats of a sched_group required for load_balancing
  */
@@ -5572,7 +5635,7 @@ struct sg_lb_stats {
        unsigned int group_capacity_factor;
        unsigned int idle_cpus;
        unsigned int group_weight;
-       int group_imb; /* Is there an imbalance in the group ? */
+       enum group_type group_type;
        int group_has_free_capacity;
 #ifdef CONFIG_NUMA_BALANCING
        unsigned int nr_numa_running;
@@ -5610,6 +5673,8 @@ static inline void init_sd_lb_stats(struct sd_lb_stats *sds)
                .total_capacity = 0UL,
                .busiest_stat = {
                        .avg_load = 0UL,
+                       .sum_nr_running = 0,
+                       .group_type = group_other,
                },
        };
 }
@@ -5652,19 +5717,17 @@ unsigned long __weak arch_scale_freq_capacity(struct sched_domain *sd, int cpu)
        return default_scale_capacity(sd, cpu);
 }
 
-static unsigned long default_scale_smt_capacity(struct sched_domain *sd, int cpu)
+static unsigned long default_scale_cpu_capacity(struct sched_domain *sd, int cpu)
 {
-       unsigned long weight = sd->span_weight;
-       unsigned long smt_gain = sd->smt_gain;
+       if ((sd->flags & SD_SHARE_CPUCAPACITY) && (sd->span_weight > 1))
+               return sd->smt_gain / sd->span_weight;
 
-       smt_gain /= weight;
-
-       return smt_gain;
+       return SCHED_CAPACITY_SCALE;
 }
 
-unsigned long __weak arch_scale_smt_capacity(struct sched_domain *sd, int cpu)
+unsigned long __weak arch_scale_cpu_capacity(struct sched_domain *sd, int cpu)
 {
-       return default_scale_smt_capacity(sd, cpu);
+       return default_scale_cpu_capacity(sd, cpu);
 }
 
 static unsigned long scale_rt_capacity(int cpu)
@@ -5703,18 +5766,15 @@ static unsigned long scale_rt_capacity(int cpu)
 
 static void update_cpu_capacity(struct sched_domain *sd, int cpu)
 {
-       unsigned long weight = sd->span_weight;
        unsigned long capacity = SCHED_CAPACITY_SCALE;
        struct sched_group *sdg = sd->groups;
 
-       if ((sd->flags & SD_SHARE_CPUCAPACITY) && weight > 1) {
-               if (sched_feat(ARCH_CAPACITY))
-                       capacity *= arch_scale_smt_capacity(sd, cpu);
-               else
-                       capacity *= default_scale_smt_capacity(sd, cpu);
+       if (sched_feat(ARCH_CAPACITY))
+               capacity *= arch_scale_cpu_capacity(sd, cpu);
+       else
+               capacity *= default_scale_cpu_capacity(sd, cpu);
 
-               capacity >>= SCHED_CAPACITY_SHIFT;
-       }
+       capacity >>= SCHED_CAPACITY_SHIFT;
 
        sdg->sgc->capacity_orig = capacity;
 
@@ -5891,6 +5951,18 @@ static inline int sg_capacity_factor(struct lb_env *env, struct sched_group *gro
        return capacity_factor;
 }
 
+static enum group_type
+group_classify(struct sched_group *group, struct sg_lb_stats *sgs)
+{
+       if (sgs->sum_nr_running > sgs->group_capacity_factor)
+               return group_overloaded;
+
+       if (sg_imbalanced(group))
+               return group_imbalanced;
+
+       return group_other;
+}
+
 /**
  * update_sg_lb_stats - Update sched_group's statistics for load balancing.
  * @env: The load balancing environment.
@@ -5920,7 +5992,7 @@ static inline void update_sg_lb_stats(struct lb_env *env,
                        load = source_load(i, load_idx);
 
                sgs->group_load += load;
-               sgs->sum_nr_running += rq->nr_running;
+               sgs->sum_nr_running += rq->cfs.h_nr_running;
 
                if (rq->nr_running > 1)
                        *overload = true;
@@ -5942,9 +6014,8 @@ static inline void update_sg_lb_stats(struct lb_env *env,
                sgs->load_per_task = sgs->sum_weighted_load / sgs->sum_nr_running;
 
        sgs->group_weight = group->group_weight;
-
-       sgs->group_imb = sg_imbalanced(group);
        sgs->group_capacity_factor = sg_capacity_factor(env, group);
+       sgs->group_type = group_classify(group, sgs);
 
        if (sgs->group_capacity_factor > sgs->sum_nr_running)
                sgs->group_has_free_capacity = 1;
@@ -5968,13 +6039,19 @@ static bool update_sd_pick_busiest(struct lb_env *env,
                                   struct sched_group *sg,
                                   struct sg_lb_stats *sgs)
 {
-       if (sgs->avg_load <= sds->busiest_stat.avg_load)
-               return false;
+       struct sg_lb_stats *busiest = &sds->busiest_stat;
 
-       if (sgs->sum_nr_running > sgs->group_capacity_factor)
+       if (sgs->group_type > busiest->group_type)
                return true;
 
-       if (sgs->group_imb)
+       if (sgs->group_type < busiest->group_type)
+               return false;
+
+       if (sgs->avg_load <= busiest->avg_load)
+               return false;
+
+       /* This is the busiest node in its class. */
+       if (!(env->sd->flags & SD_ASYM_PACKING))
                return true;
 
        /*
@@ -5982,8 +6059,7 @@ static bool update_sd_pick_busiest(struct lb_env *env,
         * numbered CPUs in the group, therefore mark all groups
         * higher than ourself as busy.
         */
-       if ((env->sd->flags & SD_ASYM_PACKING) && sgs->sum_nr_running &&
-           env->dst_cpu < group_first_cpu(sg)) {
+       if (sgs->sum_nr_running && env->dst_cpu < group_first_cpu(sg)) {
                if (!sds->busiest)
                        return true;
 
@@ -6228,7 +6304,7 @@ static inline void calculate_imbalance(struct lb_env *env, struct sd_lb_stats *s
        local = &sds->local_stat;
        busiest = &sds->busiest_stat;
 
-       if (busiest->group_imb) {
+       if (busiest->group_type == group_imbalanced) {
                /*
                 * In the group_imb case we cannot rely on group-wide averages
                 * to ensure cpu-load equilibrium, look at wider averages. XXX
@@ -6248,12 +6324,11 @@ static inline void calculate_imbalance(struct lb_env *env, struct sd_lb_stats *s
                return fix_small_imbalance(env, sds);
        }
 
-       if (!busiest->group_imb) {
-               /*
-                * Don't want to pull so many tasks that a group would go idle.
-                * Except of course for the group_imb case, since then we might
-                * have to drop below capacity to reach cpu-load equilibrium.
-                */
+       /*
+        * If there aren't any idle cpus, avoid creating some.
+        */
+       if (busiest->group_type == group_overloaded &&
+           local->group_type   == group_overloaded) {
                load_above_capacity =
                        (busiest->sum_nr_running - busiest->group_capacity_factor);
 
@@ -6337,7 +6412,7 @@ static struct sched_group *find_busiest_group(struct lb_env *env)
         * work because they assume all things are equal, which typically
         * isn't true due to cpus_allowed constraints and the like.
         */
-       if (busiest->group_imb)
+       if (busiest->group_type == group_imbalanced)
                goto force_balance;
 
        /* SD_BALANCE_NEWIDLE trumps SMP nice when underutilized */
@@ -6346,7 +6421,7 @@ static struct sched_group *find_busiest_group(struct lb_env *env)
                goto force_balance;
 
        /*
-        * If the local group is more busy than the selected busiest group
+        * If the local group is busier than the selected busiest group
         * don't try and pull any tasks.
         */
        if (local->avg_load >= busiest->avg_load)
@@ -6361,13 +6436,14 @@ static struct sched_group *find_busiest_group(struct lb_env *env)
 
        if (env->idle == CPU_IDLE) {
                /*
-                * This cpu is idle. If the busiest group load doesn't
-                * have more tasks than the number of available cpu's and
-                * there is no imbalance between this and busiest group
-                * wrt to idle cpu's, it is balanced.
+                * This cpu is idle. If the busiest group is not overloaded
+                * and there is no imbalance between this and busiest group
+                * wrt idle cpus, it is balanced. The imbalance becomes
+                * significant if the diff is greater than 1 otherwise we
+                * might end up to just move the imbalance on another group
                 */
-               if ((local->idle_cpus < busiest->idle_cpus) &&
-                   busiest->sum_nr_running <= busiest->group_weight)
+               if ((busiest->group_type != group_overloaded) &&
+                               (local->idle_cpus <= (busiest->idle_cpus + 1)))
                        goto out_balanced;
        } else {
                /*
@@ -6550,6 +6626,7 @@ static int load_balance(int this_cpu, struct rq *this_rq,
                .loop_break     = sched_nr_migrate_break,
                .cpus           = cpus,
                .fbq_type       = all,
+               .tasks          = LIST_HEAD_INIT(env.tasks),
        };
 
        /*
@@ -6599,23 +6676,30 @@ redo:
                env.loop_max  = min(sysctl_sched_nr_migrate, busiest->nr_running);
 
 more_balance:
-               local_irq_save(flags);
-               double_rq_lock(env.dst_rq, busiest);
+               raw_spin_lock_irqsave(&busiest->lock, flags);
 
                /*
                 * cur_ld_moved - load moved in current iteration
                 * ld_moved     - cumulative load moved across iterations
                 */
-               cur_ld_moved = move_tasks(&env);
-               ld_moved += cur_ld_moved;
-               double_rq_unlock(env.dst_rq, busiest);
-               local_irq_restore(flags);
+               cur_ld_moved = detach_tasks(&env);
 
                /*
-                * some other cpu did the load balance for us.
+                * We've detached some tasks from busiest_rq. Every
+                * task is masked "TASK_ON_RQ_MIGRATING", so we can safely
+                * unlock busiest->lock, and we are able to be sure
+                * that nobody can manipulate the tasks in parallel.
+                * See task_rq_lock() family for the details.
                 */
-               if (cur_ld_moved && env.dst_cpu != smp_processor_id())
-                       resched_cpu(env.dst_cpu);
+
+               raw_spin_unlock(&busiest->lock);
+
+               if (cur_ld_moved) {
+                       attach_tasks(&env);
+                       ld_moved += cur_ld_moved;
+               }
+
+               local_irq_restore(flags);
 
                if (env.flags & LBF_NEED_BREAK) {
                        env.flags &= ~LBF_NEED_BREAK;
@@ -6665,10 +6749,8 @@ more_balance:
                if (sd_parent) {
                        int *group_imbalance = &sd_parent->groups->sgc->imbalance;
 
-                       if ((env.flags & LBF_SOME_PINNED) && env.imbalance > 0) {
+                       if ((env.flags & LBF_SOME_PINNED) && env.imbalance > 0)
                                *group_imbalance = 1;
-                       } else if (*group_imbalance)
-                               *group_imbalance = 0;
                }
 
                /* All tasks on this runqueue were pinned by CPU affinity */
@@ -6679,7 +6761,7 @@ more_balance:
                                env.loop_break = sched_nr_migrate_break;
                                goto redo;
                        }
-                       goto out_balanced;
+                       goto out_all_pinned;
                }
        }
 
@@ -6744,7 +6826,7 @@ more_balance:
                 * If we've begun active balancing, start to back off. This
                 * case may not be covered by the all_pinned logic if there
                 * is only 1 task on the busy runqueue (because we don't call
-                * move_tasks).
+                * detach_tasks).
                 */
                if (sd->balance_interval < sd->max_interval)
                        sd->balance_interval *= 2;
@@ -6753,6 +6835,23 @@ more_balance:
        goto out;
 
 out_balanced:
+       /*
+        * We reach balance although we may have faced some affinity
+        * constraints. Clear the imbalance flag if it was set.
+        */
+       if (sd_parent) {
+               int *group_imbalance = &sd_parent->groups->sgc->imbalance;
+
+               if (*group_imbalance)
+                       *group_imbalance = 0;
+       }
+
+out_all_pinned:
+       /*
+        * We reach balance because all tasks are pinned at this level so
+        * we can't migrate them. Let the imbalance flag set so parent level
+        * can try to migrate them.
+        */
        schedstat_inc(sd, lb_balanced[idle]);
 
        sd->nr_balance_failed = 0;
@@ -6914,6 +7013,7 @@ static int active_load_balance_cpu_stop(void *data)
        int target_cpu = busiest_rq->push_cpu;
        struct rq *target_rq = cpu_rq(target_cpu);
        struct sched_domain *sd;
+       struct task_struct *p = NULL;
 
        raw_spin_lock_irq(&busiest_rq->lock);
 
@@ -6933,9 +7033,6 @@ static int active_load_balance_cpu_stop(void *data)
         */
        BUG_ON(busiest_rq == target_rq);
 
-       /* move a task from busiest_rq to target_rq */
-       double_lock_balance(busiest_rq, target_rq);
-
        /* Search for an sd spanning us and the target CPU. */
        rcu_read_lock();
        for_each_domain(target_cpu, sd) {
@@ -6956,16 +7053,22 @@ static int active_load_balance_cpu_stop(void *data)
 
                schedstat_inc(sd, alb_count);
 
-               if (move_one_task(&env))
+               p = detach_one_task(&env);
+               if (p)
                        schedstat_inc(sd, alb_pushed);
                else
                        schedstat_inc(sd, alb_failed);
        }
        rcu_read_unlock();
-       double_unlock_balance(busiest_rq, target_rq);
 out_unlock:
        busiest_rq->active_balance = 0;
-       raw_spin_unlock_irq(&busiest_rq->lock);
+       raw_spin_unlock(&busiest_rq->lock);
+
+       if (p)
+               attach_one_task(target_rq, p);
+
+       local_irq_enable();
+
        return 0;
 }
 
@@ -7465,7 +7568,7 @@ static void task_fork_fair(struct task_struct *p)
 static void
 prio_changed_fair(struct rq *rq, struct task_struct *p, int oldprio)
 {
-       if (!p->se.on_rq)
+       if (!task_on_rq_queued(p))
                return;
 
        /*
@@ -7490,11 +7593,11 @@ static void switched_from_fair(struct rq *rq, struct task_struct *p)
         * switched back to the fair class the enqueue_entity(.flags=0) will
         * do the right thing.
         *
-        * If it's on_rq, then the dequeue_entity(.flags=0) will already
-        * have normalized the vruntime, if it's !on_rq, then only when
+        * If it's queued, then the dequeue_entity(.flags=0) will already
+        * have normalized the vruntime, if it's !queued, then only when
         * the task is sleeping will it still have non-normalized vruntime.
         */
-       if (!p->on_rq && p->state != TASK_RUNNING) {
+       if (!task_on_rq_queued(p) && p->state != TASK_RUNNING) {
                /*
                 * Fix up our vruntime so that the current sleep doesn't
                 * cause 'unlimited' sleep bonus.
@@ -7521,15 +7624,15 @@ static void switched_from_fair(struct rq *rq, struct task_struct *p)
  */
 static void switched_to_fair(struct rq *rq, struct task_struct *p)
 {
-       struct sched_entity *se = &p->se;
 #ifdef CONFIG_FAIR_GROUP_SCHED
+       struct sched_entity *se = &p->se;
        /*
         * Since the real-depth could have been changed (only FAIR
         * class maintain depth value), reset depth properly.
         */
        se->depth = se->parent ? se->parent->depth + 1 : 0;
 #endif
-       if (!se->on_rq)
+       if (!task_on_rq_queued(p))
                return;
 
        /*
@@ -7575,7 +7678,7 @@ void init_cfs_rq(struct cfs_rq *cfs_rq)
 }
 
 #ifdef CONFIG_FAIR_GROUP_SCHED
-static void task_move_group_fair(struct task_struct *p, int on_rq)
+static void task_move_group_fair(struct task_struct *p, int queued)
 {
        struct sched_entity *se = &p->se;
        struct cfs_rq *cfs_rq;
@@ -7594,7 +7697,7 @@ static void task_move_group_fair(struct task_struct *p, int on_rq)
         * fair sleeper stuff for the first placement, but who cares.
         */
        /*
-        * When !on_rq, vruntime of the task has usually NOT been normalized.
+        * When !queued, vruntime of the task has usually NOT been normalized.
         * But there are some cases where it has already been normalized:
         *
         * - Moving a forked child which is waiting for being woken up by
@@ -7605,14 +7708,14 @@ static void task_move_group_fair(struct task_struct *p, int on_rq)
         * To prevent boost or penalty in the new cfs_rq caused by delta
         * min_vruntime between the two cfs_rqs, we skip vruntime adjustment.
         */
-       if (!on_rq && (!se->sum_exec_runtime || p->state == TASK_WAKING))
-               on_rq = 1;
+       if (!queued && (!se->sum_exec_runtime || p->state == TASK_WAKING))
+               queued = 1;
 
-       if (!on_rq)
+       if (!queued)
                se->vruntime -= cfs_rq_of(se)->min_vruntime;
        set_task_rq(p, task_cpu(p));
        se->depth = se->parent ? se->parent->depth + 1 : 0;
-       if (!on_rq) {
+       if (!queued) {
                cfs_rq = cfs_rq_of(se);
                se->vruntime += cfs_rq->min_vruntime;
 #ifdef CONFIG_SMP
index 11e7bc434f435dc71225455bfd1e032d47eab45d..c47fce75e66648b25e71da3d3ecdca8ec4448227 100644 (file)
@@ -147,6 +147,9 @@ use_default:
            clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_ENTER, &dev->cpu))
                goto use_default;
 
+       /* Take note of the planned idle state. */
+       idle_set_state(this_rq(), &drv->states[next_state]);
+
        /*
         * Enter the idle state previously returned by the governor decision.
         * This function will block until an interrupt occurs and will take
@@ -154,6 +157,9 @@ use_default:
         */
        entered_state = cpuidle_enter(drv, dev, next_state);
 
+       /* The cpu is no longer idle or about to enter idle. */
+       idle_set_state(this_rq(), NULL);
+
        if (broadcast)
                clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_EXIT, &dev->cpu);
 
index 5f6edca4fafd85b59838a048e711b361861f39a6..87ea5bf1b87f2b17159e903b1c7075b0700ea1a5 100644 (file)
@@ -1448,7 +1448,7 @@ pick_next_task_rt(struct rq *rq, struct task_struct *prev)
                 * means a dl or stop task can slip in, in which case we need
                 * to re-start task selection.
                 */
-               if (unlikely((rq->stop && rq->stop->on_rq) ||
+               if (unlikely((rq->stop && task_on_rq_queued(rq->stop)) ||
                             rq->dl.dl_nr_running))
                        return RETRY_TASK;
        }
@@ -1468,8 +1468,7 @@ pick_next_task_rt(struct rq *rq, struct task_struct *prev)
        p = _pick_next_task_rt(rq);
 
        /* The running task is never eligible for pushing */
-       if (p)
-               dequeue_pushable_task(rq, p);
+       dequeue_pushable_task(rq, p);
 
        set_post_schedule(rq);
 
@@ -1624,7 +1623,7 @@ static struct rq *find_lock_lowest_rq(struct task_struct *task, struct rq *rq)
                                     !cpumask_test_cpu(lowest_rq->cpu,
                                                       tsk_cpus_allowed(task)) ||
                                     task_running(rq, task) ||
-                                    !task->on_rq)) {
+                                    !task_on_rq_queued(task))) {
 
                                double_unlock_balance(rq, lowest_rq);
                                lowest_rq = NULL;
@@ -1658,7 +1657,7 @@ static struct task_struct *pick_next_pushable_task(struct rq *rq)
        BUG_ON(task_current(rq, p));
        BUG_ON(p->nr_cpus_allowed <= 1);
 
-       BUG_ON(!p->on_rq);
+       BUG_ON(!task_on_rq_queued(p));
        BUG_ON(!rt_task(p));
 
        return p;
@@ -1809,7 +1808,7 @@ static int pull_rt_task(struct rq *this_rq)
                 */
                if (p && (p->prio < this_rq->rt.highest_prio.curr)) {
                        WARN_ON(p == src_rq->curr);
-                       WARN_ON(!p->on_rq);
+                       WARN_ON(!task_on_rq_queued(p));
 
                        /*
                         * There's a chance that p is higher in priority
@@ -1870,7 +1869,7 @@ static void set_cpus_allowed_rt(struct task_struct *p,
 
        BUG_ON(!rt_task(p));
 
-       if (!p->on_rq)
+       if (!task_on_rq_queued(p))
                return;
 
        weight = cpumask_weight(new_mask);
@@ -1936,7 +1935,7 @@ static void switched_from_rt(struct rq *rq, struct task_struct *p)
         * we may need to handle the pulling of RT tasks
         * now.
         */
-       if (!p->on_rq || rq->rt.rt_nr_running)
+       if (!task_on_rq_queued(p) || rq->rt.rt_nr_running)
                return;
 
        if (pull_rt_task(rq))
@@ -1970,7 +1969,7 @@ static void switched_to_rt(struct rq *rq, struct task_struct *p)
         * If that current running task is also an RT task
         * then see if we can move to another run queue.
         */
-       if (p->on_rq && rq->curr != p) {
+       if (task_on_rq_queued(p) && rq->curr != p) {
 #ifdef CONFIG_SMP
                if (p->nr_cpus_allowed > 1 && rq->rt.overloaded &&
                    /* Don't resched if we changed runqueues */
@@ -1989,7 +1988,7 @@ static void switched_to_rt(struct rq *rq, struct task_struct *p)
 static void
 prio_changed_rt(struct rq *rq, struct task_struct *p, int oldprio)
 {
-       if (!p->on_rq)
+       if (!task_on_rq_queued(p))
                return;
 
        if (rq->curr == p) {
@@ -2073,7 +2072,7 @@ static void task_tick_rt(struct rq *rq, struct task_struct *p, int queued)
        for_each_sched_rt_entity(rt_se) {
                if (rt_se->run_list.prev != rt_se->run_list.next) {
                        requeue_task_rt(rq, p, 0);
-                       set_tsk_need_resched(p);
+                       resched_curr(rq);
                        return;
                }
        }
index 579712f4e9d56535e9d981e489dfcc66165457ff..6130251de28013a06dd9ce1aeb076a6a7b86c7c3 100644 (file)
 #include "cpuacct.h"
 
 struct rq;
+struct cpuidle_state;
+
+/* task_struct::on_rq states: */
+#define TASK_ON_RQ_QUEUED      1
+#define TASK_ON_RQ_MIGRATING   2
 
 extern __read_mostly int scheduler_running;
 
@@ -126,6 +131,9 @@ struct rt_bandwidth {
        u64                     rt_runtime;
        struct hrtimer          rt_period_timer;
 };
+
+void __dl_clear_params(struct task_struct *p);
+
 /*
  * To keep the bandwidth of -deadline tasks and groups under control
  * we need some place where:
@@ -184,7 +192,7 @@ struct cfs_bandwidth {
        raw_spinlock_t lock;
        ktime_t period;
        u64 quota, runtime;
-       s64 hierarchal_quota;
+       s64 hierarchical_quota;
        u64 runtime_expires;
 
        int idle, timer_active;
@@ -636,6 +644,11 @@ struct rq {
 #ifdef CONFIG_SMP
        struct llist_head wake_list;
 #endif
+
+#ifdef CONFIG_CPU_IDLE
+       /* Must be inspected within a rcu lock section */
+       struct cpuidle_state *idle_state;
+#endif
 };
 
 static inline int cpu_of(struct rq *rq)
@@ -647,7 +660,7 @@ static inline int cpu_of(struct rq *rq)
 #endif
 }
 
-DECLARE_PER_CPU(struct rq, runqueues);
+DECLARE_PER_CPU_SHARED_ALIGNED(struct rq, runqueues);
 
 #define cpu_rq(cpu)            (&per_cpu(runqueues, (cpu)))
 #define this_rq()              (&__get_cpu_var(runqueues))
@@ -942,6 +955,15 @@ static inline int task_running(struct rq *rq, struct task_struct *p)
 #endif
 }
 
+static inline int task_on_rq_queued(struct task_struct *p)
+{
+       return p->on_rq == TASK_ON_RQ_QUEUED;
+}
+
+static inline int task_on_rq_migrating(struct task_struct *p)
+{
+       return p->on_rq == TASK_ON_RQ_MIGRATING;
+}
 
 #ifndef prepare_arch_switch
 # define prepare_arch_switch(next)     do { } while (0)
@@ -953,7 +975,6 @@ static inline int task_running(struct rq *rq, struct task_struct *p)
 # define finish_arch_post_lock_switch()        do { } while (0)
 #endif
 
-#ifndef __ARCH_WANT_UNLOCKED_CTXSW
 static inline void prepare_lock_switch(struct rq *rq, struct task_struct *next)
 {
 #ifdef CONFIG_SMP
@@ -991,35 +1012,6 @@ static inline void finish_lock_switch(struct rq *rq, struct task_struct *prev)
        raw_spin_unlock_irq(&rq->lock);
 }
 
-#else /* __ARCH_WANT_UNLOCKED_CTXSW */
-static inline void prepare_lock_switch(struct rq *rq, struct task_struct *next)
-{
-#ifdef CONFIG_SMP
-       /*
-        * We can optimise this out completely for !SMP, because the
-        * SMP rebalancing from interrupt is the only thing that cares
-        * here.
-        */
-       next->on_cpu = 1;
-#endif
-       raw_spin_unlock(&rq->lock);
-}
-
-static inline void finish_lock_switch(struct rq *rq, struct task_struct *prev)
-{
-#ifdef CONFIG_SMP
-       /*
-        * After ->on_cpu is cleared, the task can be moved to a different CPU.
-        * We must ensure this doesn't happen until the switch is completely
-        * finished.
-        */
-       smp_wmb();
-       prev->on_cpu = 0;
-#endif
-       local_irq_enable();
-}
-#endif /* __ARCH_WANT_UNLOCKED_CTXSW */
-
 /*
  * wake flags
  */
@@ -1180,6 +1172,30 @@ static inline void idle_exit_fair(struct rq *rq) { }
 
 #endif
 
+#ifdef CONFIG_CPU_IDLE
+static inline void idle_set_state(struct rq *rq,
+                                 struct cpuidle_state *idle_state)
+{
+       rq->idle_state = idle_state;
+}
+
+static inline struct cpuidle_state *idle_get_state(struct rq *rq)
+{
+       WARN_ON(!rcu_read_lock_held());
+       return rq->idle_state;
+}
+#else
+static inline void idle_set_state(struct rq *rq,
+                                 struct cpuidle_state *idle_state)
+{
+}
+
+static inline struct cpuidle_state *idle_get_state(struct rq *rq)
+{
+       return NULL;
+}
+#endif
+
 extern void sysrq_sched_debug_show(void);
 extern void sched_init_granularity(void);
 extern void update_max_interval(void);
index bfe0edadbfbbe70b55d4cb022a42c29c1d33dda1..67426e529f59c044eef35c88c8d906cab641bb64 100644 (file)
@@ -28,7 +28,7 @@ pick_next_task_stop(struct rq *rq, struct task_struct *prev)
 {
        struct task_struct *stop = rq->stop;
 
-       if (!stop || !stop->on_rq)
+       if (!stop || !task_on_rq_queued(stop))
                return NULL;
 
        put_prev_task(rq, prev);
index 84922befea8414468eafe1330ffc372ec9bdb8da..4ef9687ac115f21aae6ce4321e2639866892389d 100644 (file)
 #include <linux/slab.h>
 #include <linux/syscalls.h>
 
-/* #define SECCOMP_DEBUG 1 */
+#ifdef CONFIG_HAVE_ARCH_SECCOMP_FILTER
+#include <asm/syscall.h>
+#endif
 
 #ifdef CONFIG_SECCOMP_FILTER
-#include <asm/syscall.h>
 #include <linux/filter.h>
 #include <linux/pid.h>
 #include <linux/ptrace.h>
@@ -172,10 +173,10 @@ static int seccomp_check_filter(struct sock_filter *filter, unsigned int flen)
  *
  * Returns valid seccomp BPF response codes.
  */
-static u32 seccomp_run_filters(int syscall)
+static u32 seccomp_run_filters(struct seccomp_data *sd)
 {
        struct seccomp_filter *f = ACCESS_ONCE(current->seccomp.filter);
-       struct seccomp_data sd;
+       struct seccomp_data sd_local;
        u32 ret = SECCOMP_RET_ALLOW;
 
        /* Ensure unexpected behavior doesn't result in failing open. */
@@ -185,14 +186,17 @@ static u32 seccomp_run_filters(int syscall)
        /* Make sure cross-thread synced filter points somewhere sane. */
        smp_read_barrier_depends();
 
-       populate_seccomp_data(&sd);
+       if (!sd) {
+               populate_seccomp_data(&sd_local);
+               sd = &sd_local;
+       }
 
        /*
         * All filters in the list are evaluated and the lowest BPF return
         * value always takes priority (ignoring the DATA).
         */
        for (; f; f = f->prev) {
-               u32 cur_ret = BPF_PROG_RUN(f->prog, (void *)&sd);
+               u32 cur_ret = BPF_PROG_RUN(f->prog, (void *)sd);
 
                if ((cur_ret & SECCOMP_RET_ACTION) < (ret & SECCOMP_RET_ACTION))
                        ret = cur_ret;
@@ -563,11 +567,55 @@ static int mode1_syscalls_32[] = {
 };
 #endif
 
-int __secure_computing(int this_syscall)
+static void __secure_computing_strict(int this_syscall)
+{
+       int *syscall_whitelist = mode1_syscalls;
+#ifdef CONFIG_COMPAT
+       if (is_compat_task())
+               syscall_whitelist = mode1_syscalls_32;
+#endif
+       do {
+               if (*syscall_whitelist == this_syscall)
+                       return;
+       } while (*++syscall_whitelist);
+
+#ifdef SECCOMP_DEBUG
+       dump_stack();
+#endif
+       audit_seccomp(this_syscall, SIGKILL, SECCOMP_RET_KILL);
+       do_exit(SIGKILL);
+}
+
+#ifndef CONFIG_HAVE_ARCH_SECCOMP_FILTER
+void secure_computing_strict(int this_syscall)
+{
+       int mode = current->seccomp.mode;
+
+       if (mode == 0)
+               return;
+       else if (mode == SECCOMP_MODE_STRICT)
+               __secure_computing_strict(this_syscall);
+       else
+               BUG();
+}
+#else
+int __secure_computing(void)
 {
-       int exit_sig = 0;
-       int *syscall;
-       u32 ret;
+       u32 phase1_result = seccomp_phase1(NULL);
+
+       if (likely(phase1_result == SECCOMP_PHASE1_OK))
+               return 0;
+       else if (likely(phase1_result == SECCOMP_PHASE1_SKIP))
+               return -1;
+       else
+               return seccomp_phase2(phase1_result);
+}
+
+#ifdef CONFIG_SECCOMP_FILTER
+static u32 __seccomp_phase1_filter(int this_syscall, struct seccomp_data *sd)
+{
+       u32 filter_ret, action;
+       int data;
 
        /*
         * Make sure that any changes to mode from another thread have
@@ -575,85 +623,127 @@ int __secure_computing(int this_syscall)
         */
        rmb();
 
-       switch (current->seccomp.mode) {
-       case SECCOMP_MODE_STRICT:
-               syscall = mode1_syscalls;
-#ifdef CONFIG_COMPAT
-               if (is_compat_task())
-                       syscall = mode1_syscalls_32;
+       filter_ret = seccomp_run_filters(sd);
+       data = filter_ret & SECCOMP_RET_DATA;
+       action = filter_ret & SECCOMP_RET_ACTION;
+
+       switch (action) {
+       case SECCOMP_RET_ERRNO:
+               /* Set the low-order 16-bits as a errno. */
+               syscall_set_return_value(current, task_pt_regs(current),
+                                        -data, 0);
+               goto skip;
+
+       case SECCOMP_RET_TRAP:
+               /* Show the handler the original registers. */
+               syscall_rollback(current, task_pt_regs(current));
+               /* Let the filter pass back 16 bits of data. */
+               seccomp_send_sigsys(this_syscall, data);
+               goto skip;
+
+       case SECCOMP_RET_TRACE:
+               return filter_ret;  /* Save the rest for phase 2. */
+
+       case SECCOMP_RET_ALLOW:
+               return SECCOMP_PHASE1_OK;
+
+       case SECCOMP_RET_KILL:
+       default:
+               audit_seccomp(this_syscall, SIGSYS, action);
+               do_exit(SIGSYS);
+       }
+
+       unreachable();
+
+skip:
+       audit_seccomp(this_syscall, 0, action);
+       return SECCOMP_PHASE1_SKIP;
+}
 #endif
-               do {
-                       if (*syscall == this_syscall)
-                               return 0;
-               } while (*++syscall);
-               exit_sig = SIGKILL;
-               ret = SECCOMP_RET_KILL;
-               break;
+
+/**
+ * seccomp_phase1() - run fast path seccomp checks on the current syscall
+ * @arg sd: The seccomp_data or NULL
+ *
+ * This only reads pt_regs via the syscall_xyz helpers.  The only change
+ * it will make to pt_regs is via syscall_set_return_value, and it will
+ * only do that if it returns SECCOMP_PHASE1_SKIP.
+ *
+ * If sd is provided, it will not read pt_regs at all.
+ *
+ * It may also call do_exit or force a signal; these actions must be
+ * safe.
+ *
+ * If it returns SECCOMP_PHASE1_OK, the syscall passes checks and should
+ * be processed normally.
+ *
+ * If it returns SECCOMP_PHASE1_SKIP, then the syscall should not be
+ * invoked.  In this case, seccomp_phase1 will have set the return value
+ * using syscall_set_return_value.
+ *
+ * If it returns anything else, then the return value should be passed
+ * to seccomp_phase2 from a context in which ptrace hooks are safe.
+ */
+u32 seccomp_phase1(struct seccomp_data *sd)
+{
+       int mode = current->seccomp.mode;
+       int this_syscall = sd ? sd->nr :
+               syscall_get_nr(current, task_pt_regs(current));
+
+       switch (mode) {
+       case SECCOMP_MODE_STRICT:
+               __secure_computing_strict(this_syscall);  /* may call do_exit */
+               return SECCOMP_PHASE1_OK;
 #ifdef CONFIG_SECCOMP_FILTER
-       case SECCOMP_MODE_FILTER: {
-               int data;
-               struct pt_regs *regs = task_pt_regs(current);
-               ret = seccomp_run_filters(this_syscall);
-               data = ret & SECCOMP_RET_DATA;
-               ret &= SECCOMP_RET_ACTION;
-               switch (ret) {
-               case SECCOMP_RET_ERRNO:
-                       /* Set the low-order 16-bits as a errno. */
-                       syscall_set_return_value(current, regs,
-                                                -data, 0);
-                       goto skip;
-               case SECCOMP_RET_TRAP:
-                       /* Show the handler the original registers. */
-                       syscall_rollback(current, regs);
-                       /* Let the filter pass back 16 bits of data. */
-                       seccomp_send_sigsys(this_syscall, data);
-                       goto skip;
-               case SECCOMP_RET_TRACE:
-                       /* Skip these calls if there is no tracer. */
-                       if (!ptrace_event_enabled(current, PTRACE_EVENT_SECCOMP)) {
-                               syscall_set_return_value(current, regs,
-                                                        -ENOSYS, 0);
-                               goto skip;
-                       }
-                       /* Allow the BPF to provide the event message */
-                       ptrace_event(PTRACE_EVENT_SECCOMP, data);
-                       /*
-                        * The delivery of a fatal signal during event
-                        * notification may silently skip tracer notification.
-                        * Terminating the task now avoids executing a system
-                        * call that may not be intended.
-                        */
-                       if (fatal_signal_pending(current))
-                               break;
-                       if (syscall_get_nr(current, regs) < 0)
-                               goto skip;  /* Explicit request to skip. */
-
-                       return 0;
-               case SECCOMP_RET_ALLOW:
-                       return 0;
-               case SECCOMP_RET_KILL:
-               default:
-                       break;
-               }
-               exit_sig = SIGSYS;
-               break;
-       }
+       case SECCOMP_MODE_FILTER:
+               return __seccomp_phase1_filter(this_syscall, sd);
 #endif
        default:
                BUG();
        }
+}
 
-#ifdef SECCOMP_DEBUG
-       dump_stack();
-#endif
-       audit_seccomp(this_syscall, exit_sig, ret);
-       do_exit(exit_sig);
-#ifdef CONFIG_SECCOMP_FILTER
-skip:
-       audit_seccomp(this_syscall, exit_sig, ret);
-#endif
-       return -1;
+/**
+ * seccomp_phase2() - finish slow path seccomp work for the current syscall
+ * @phase1_result: The return value from seccomp_phase1()
+ *
+ * This must be called from a context in which ptrace hooks can be used.
+ *
+ * Returns 0 if the syscall should be processed or -1 to skip the syscall.
+ */
+int seccomp_phase2(u32 phase1_result)
+{
+       struct pt_regs *regs = task_pt_regs(current);
+       u32 action = phase1_result & SECCOMP_RET_ACTION;
+       int data = phase1_result & SECCOMP_RET_DATA;
+
+       BUG_ON(action != SECCOMP_RET_TRACE);
+
+       audit_seccomp(syscall_get_nr(current, regs), 0, action);
+
+       /* Skip these calls if there is no tracer. */
+       if (!ptrace_event_enabled(current, PTRACE_EVENT_SECCOMP)) {
+               syscall_set_return_value(current, regs,
+                                        -ENOSYS, 0);
+               return -1;
+       }
+
+       /* Allow the BPF to provide the event message */
+       ptrace_event(PTRACE_EVENT_SECCOMP, data);
+       /*
+        * The delivery of a fatal signal during event
+        * notification may silently skip tracer notification.
+        * Terminating the task now avoids executing a system
+        * call that may not be intended.
+        */
+       if (fatal_signal_pending(current))
+               do_exit(SIGSYS);
+       if (syscall_get_nr(current, regs) < 0)
+               return -1;  /* Explicit request to skip. */
+
+       return 0;
 }
+#endif /* CONFIG_HAVE_ARCH_SECCOMP_FILTER */
 
 long prctl_get_seccomp(void)
 {
index aff8aa14f54795faa42ae9482da75e3ea9610a82..9e0d0b289118fa3192580b46157e0858bc124fcb 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/gfp.h>
 #include <linux/smp.h>
 #include <linux/cpu.h>
+#include <linux/sched.h>
 
 #include "smpboot.h"
 
@@ -699,3 +700,24 @@ void kick_all_cpus_sync(void)
        smp_call_function(do_nothing, NULL, 1);
 }
 EXPORT_SYMBOL_GPL(kick_all_cpus_sync);
+
+/**
+ * wake_up_all_idle_cpus - break all cpus out of idle
+ * wake_up_all_idle_cpus try to break all cpus which is in idle state even
+ * including idle polling cpus, for non-idle cpus, we will do nothing
+ * for them.
+ */
+void wake_up_all_idle_cpus(void)
+{
+       int cpu;
+
+       preempt_disable();
+       for_each_online_cpu(cpu) {
+               if (cpu == smp_processor_id())
+                       continue;
+
+               wake_up_if_idle(cpu);
+       }
+       preempt_enable();
+}
+EXPORT_SYMBOL_GPL(wake_up_all_idle_cpus);
index 5918d227730f33d7daec6dfab1e8ef30cd653abf..348ec763b1049a64f5867837b4c36f521724fa51 100644 (file)
@@ -278,7 +278,7 @@ restart:
                pending >>= softirq_bit;
        }
 
-       rcu_bh_qs(smp_processor_id());
+       rcu_bh_qs();
        local_irq_disable();
 
        pending = local_softirq_pending();
index dfce4debd138f1cedc3672c14ae0ad5bc361c6a8..1eaa2f0b02460b5c2a7670af0d1e058444da9eb5 100644 (file)
@@ -869,11 +869,9 @@ void do_sys_times(struct tms *tms)
 {
        cputime_t tgutime, tgstime, cutime, cstime;
 
-       spin_lock_irq(&current->sighand->siglock);
        thread_group_cputime_adjusted(current, &tgutime, &tgstime);
        cutime = current->signal->cutime;
        cstime = current->signal->cstime;
-       spin_unlock_irq(&current->sighand->siglock);
        tms->tms_utime = cputime_to_clock_t(tgutime);
        tms->tms_stime = cputime_to_clock_t(tgstime);
        tms->tms_cutime = cputime_to_clock_t(cutime);
index 91180987e40e6c6acf88ad2a6e9aab4ea558b1f1..4aada6d9fe7445f53e88702fa5e983dc06abd367 100644 (file)
@@ -1055,15 +1055,6 @@ static struct ctl_table kern_table[] = {
                .child          = key_sysctls,
        },
 #endif
-#ifdef CONFIG_RCU_TORTURE_TEST
-       {
-               .procname       = "rcutorture_runnable",
-               .data           = &rcutorture_runnable,
-               .maxlen         = sizeof(int),
-               .mode           = 0644,
-               .proc_handler   = proc_dointvec,
-       },
-#endif
 #ifdef CONFIG_PERF_EVENTS
        /*
         * User-space scripts rely on the existence of this file
index 1c2fe7de28427c6393b61374b5871971fcffc240..ab370ffffd53dc5d826137c796df5c32afe81abf 100644 (file)
@@ -1776,7 +1776,6 @@ schedule_hrtimeout_range_clock(ktime_t *expires, unsigned long delta,
         */
        if (!expires) {
                schedule();
-               __set_current_state(TASK_RUNNING);
                return -EINTR;
        }
 
index 3b8946416a5f836227edcf0db8dd1f8b2eb95063..492b986195d53350abe899b0ecd059f91edb77a4 100644 (file)
@@ -272,22 +272,8 @@ static int posix_cpu_clock_get_task(struct task_struct *tsk,
                if (same_thread_group(tsk, current))
                        err = cpu_clock_sample(which_clock, tsk, &rtn);
        } else {
-               unsigned long flags;
-               struct sighand_struct *sighand;
-
-               /*
-                * while_each_thread() is not yet entirely RCU safe,
-                * keep locking the group while sampling process
-                * clock for now.
-                */
-               sighand = lock_task_sighand(tsk, &flags);
-               if (!sighand)
-                       return err;
-
                if (tsk == current || thread_group_leader(tsk))
                        err = cpu_clock_sample_group(which_clock, tsk, &rtn);
-
-               unlock_task_sighand(tsk, &flags);
        }
 
        if (!err)
index 7c1412ea2d29836c54bff9ea841172e2f0827fec..a73efdf6f696b3bbb71a11e158e07e41c20c0f27 100644 (file)
@@ -586,7 +586,7 @@ static ktime_t tick_nohz_stop_sched_tick(struct tick_sched *ts,
        } while (read_seqretry(&jiffies_lock, seq));
 
        if (rcu_needs_cpu(cpu, &rcu_delta_jiffies) ||
-           arch_needs_cpu(cpu) || irq_work_needs_cpu()) {
+           arch_needs_cpu() || irq_work_needs_cpu()) {
                next_jiffies = last_jiffies + 1;
                delta_jiffies = 1;
        } else {
index d600af21f0225dc97d51c925efd70b3bf89014b1..dd70993c266c38785510ab09f0315d1f1775d05b 100644 (file)
@@ -211,18 +211,16 @@ EXPORT_SYMBOL_GPL(torture_onoff_cleanup);
 /*
  * Print online/offline testing statistics.
  */
-char *torture_onoff_stats(char *page)
+void torture_onoff_stats(void)
 {
 #ifdef CONFIG_HOTPLUG_CPU
-       page += sprintf(page,
-                      "onoff: %ld/%ld:%ld/%ld %d,%d:%d,%d %lu:%lu (HZ=%d) ",
-                      n_online_successes, n_online_attempts,
-                      n_offline_successes, n_offline_attempts,
-                      min_online, max_online,
-                      min_offline, max_offline,
-                      sum_online, sum_offline, HZ);
+       pr_cont("onoff: %ld/%ld:%ld/%ld %d,%d:%d,%d %lu:%lu (HZ=%d) ",
+               n_online_successes, n_online_attempts,
+               n_offline_successes, n_offline_attempts,
+               min_online, max_online,
+               min_offline, max_offline,
+               sum_online, sum_offline, HZ);
 #endif /* #ifdef CONFIG_HOTPLUG_CPU */
-       return page;
 }
 EXPORT_SYMBOL_GPL(torture_onoff_stats);
 
@@ -635,8 +633,13 @@ EXPORT_SYMBOL_GPL(torture_init_end);
  *
  * This must be called before the caller starts shutting down its own
  * kthreads.
+ *
+ * Both torture_cleanup_begin() and torture_cleanup_end() must be paired,
+ * in order to correctly perform the cleanup. They are separated because
+ * threads can still need to reference the torture_type type, thus nullify
+ * only after completing all other relevant calls.
  */
-bool torture_cleanup(void)
+bool torture_cleanup_begin(void)
 {
        mutex_lock(&fullstop_mutex);
        if (ACCESS_ONCE(fullstop) == FULLSTOP_SHUTDOWN) {
@@ -651,12 +654,17 @@ bool torture_cleanup(void)
        torture_shuffle_cleanup();
        torture_stutter_cleanup();
        torture_onoff_cleanup();
+       return false;
+}
+EXPORT_SYMBOL_GPL(torture_cleanup_begin);
+
+void torture_cleanup_end(void)
+{
        mutex_lock(&fullstop_mutex);
        torture_type = NULL;
        mutex_unlock(&fullstop_mutex);
-       return false;
 }
-EXPORT_SYMBOL_GPL(torture_cleanup);
+EXPORT_SYMBOL_GPL(torture_cleanup_end);
 
 /*
  * Is it time for the current torture test to stop?
index 5916a8e59e878d4c6d9fc87bc370949f5501d962..fb186b9ddf519159d866fcaa8fc187328820f2bf 100644 (file)
@@ -113,6 +113,9 @@ ftrace_func_t ftrace_pid_function __read_mostly = ftrace_stub;
 static struct ftrace_ops global_ops;
 static struct ftrace_ops control_ops;
 
+static void ftrace_ops_recurs_func(unsigned long ip, unsigned long parent_ip,
+                                  struct ftrace_ops *op, struct pt_regs *regs);
+
 #if ARCH_SUPPORTS_FTRACE_OPS
 static void ftrace_ops_list_func(unsigned long ip, unsigned long parent_ip,
                                 struct ftrace_ops *op, struct pt_regs *regs);
@@ -250,19 +253,25 @@ static void update_ftrace_function(void)
 {
        ftrace_func_t func;
 
+       /*
+        * Prepare the ftrace_ops that the arch callback will use.
+        * If there's only one ftrace_ops registered, the ftrace_ops_list
+        * will point to the ops we want.
+        */
+       set_function_trace_op = ftrace_ops_list;
+
+       /* If there's no ftrace_ops registered, just call the stub function */
+       if (ftrace_ops_list == &ftrace_list_end) {
+               func = ftrace_stub;
+
        /*
         * If we are at the end of the list and this ops is
         * recursion safe and not dynamic and the arch supports passing ops,
         * then have the mcount trampoline call the function directly.
         */
-       if (ftrace_ops_list == &ftrace_list_end ||
-           (ftrace_ops_list->next == &ftrace_list_end &&
-            !(ftrace_ops_list->flags & FTRACE_OPS_FL_DYNAMIC) &&
-            (ftrace_ops_list->flags & FTRACE_OPS_FL_RECURSION_SAFE) &&
-            !FTRACE_FORCE_LIST_FUNC)) {
-               /* Set the ftrace_ops that the arch callback uses */
-               set_function_trace_op = ftrace_ops_list;
-               func = ftrace_ops_list->func;
+       } else if (ftrace_ops_list->next == &ftrace_list_end) {
+               func = ftrace_ops_get_func(ftrace_ops_list);
+
        } else {
                /* Just use the default ftrace_ops */
                set_function_trace_op = &ftrace_list_end;
@@ -1048,6 +1057,12 @@ static struct pid * const ftrace_swapper_pid = &init_struct_pid;
 
 static struct ftrace_ops *removed_ops;
 
+/*
+ * Set when doing a global update, like enabling all recs or disabling them.
+ * It is not set when just updating a single ftrace_ops.
+ */
+static bool update_all_ops;
+
 #ifndef CONFIG_FTRACE_MCOUNT_RECORD
 # error Dynamic ftrace depends on MCOUNT_RECORD
 #endif
@@ -1307,7 +1322,6 @@ ftrace_hash_move(struct ftrace_ops *ops, int enable,
        struct ftrace_func_entry *entry;
        struct hlist_node *tn;
        struct hlist_head *hhd;
-       struct ftrace_hash *old_hash;
        struct ftrace_hash *new_hash;
        int size = src->count;
        int bits = 0;
@@ -1352,15 +1366,28 @@ update:
         */
        ftrace_hash_rec_disable_modify(ops, enable);
 
-       old_hash = *dst;
        rcu_assign_pointer(*dst, new_hash);
-       free_ftrace_hash_rcu(old_hash);
 
        ftrace_hash_rec_enable_modify(ops, enable);
 
        return 0;
 }
 
+static bool hash_contains_ip(unsigned long ip,
+                            struct ftrace_ops_hash *hash)
+{
+       /*
+        * The function record is a match if it exists in the filter
+        * hash and not in the notrace hash. Note, an emty hash is
+        * considered a match for the filter hash, but an empty
+        * notrace hash is considered not in the notrace hash.
+        */
+       return (ftrace_hash_empty(hash->filter_hash) ||
+               ftrace_lookup_ip(hash->filter_hash, ip)) &&
+               (ftrace_hash_empty(hash->notrace_hash) ||
+                !ftrace_lookup_ip(hash->notrace_hash, ip));
+}
+
 /*
  * Test the hashes for this ops to see if we want to call
  * the ops->func or not.
@@ -1376,8 +1403,7 @@ update:
 static int
 ftrace_ops_test(struct ftrace_ops *ops, unsigned long ip, void *regs)
 {
-       struct ftrace_hash *filter_hash;
-       struct ftrace_hash *notrace_hash;
+       struct ftrace_ops_hash hash;
        int ret;
 
 #ifdef CONFIG_DYNAMIC_FTRACE_WITH_REGS
@@ -1390,13 +1416,10 @@ ftrace_ops_test(struct ftrace_ops *ops, unsigned long ip, void *regs)
                return 0;
 #endif
 
-       filter_hash = rcu_dereference_raw_notrace(ops->func_hash->filter_hash);
-       notrace_hash = rcu_dereference_raw_notrace(ops->func_hash->notrace_hash);
+       hash.filter_hash = rcu_dereference_raw_notrace(ops->func_hash->filter_hash);
+       hash.notrace_hash = rcu_dereference_raw_notrace(ops->func_hash->notrace_hash);
 
-       if ((ftrace_hash_empty(filter_hash) ||
-            ftrace_lookup_ip(filter_hash, ip)) &&
-           (ftrace_hash_empty(notrace_hash) ||
-            !ftrace_lookup_ip(notrace_hash, ip)))
+       if (hash_contains_ip(ip, &hash))
                ret = 1;
        else
                ret = 0;
@@ -1508,46 +1531,6 @@ static bool test_rec_ops_needs_regs(struct dyn_ftrace *rec)
        return  keep_regs;
 }
 
-static void ftrace_remove_tramp(struct ftrace_ops *ops,
-                               struct dyn_ftrace *rec)
-{
-       /* If TRAMP is not set, no ops should have a trampoline for this */
-       if (!(rec->flags & FTRACE_FL_TRAMP))
-               return;
-
-       rec->flags &= ~FTRACE_FL_TRAMP;
-
-       if ((!ftrace_hash_empty(ops->func_hash->filter_hash) &&
-            !ftrace_lookup_ip(ops->func_hash->filter_hash, rec->ip)) ||
-           ftrace_lookup_ip(ops->func_hash->notrace_hash, rec->ip))
-               return;
-       /*
-        * The tramp_hash entry will be removed at time
-        * of update.
-        */
-       ops->nr_trampolines--;
-}
-
-static void ftrace_clear_tramps(struct dyn_ftrace *rec, struct ftrace_ops *ops)
-{
-       struct ftrace_ops *op;
-
-       /* If TRAMP is not set, no ops should have a trampoline for this */
-       if (!(rec->flags & FTRACE_FL_TRAMP))
-               return;
-
-       do_for_each_ftrace_op(op, ftrace_ops_list) {
-               /*
-                * This function is called to clear other tramps
-                * not the one that is being updated.
-                */
-               if (op == ops)
-                       continue;
-               if (op->nr_trampolines)
-                       ftrace_remove_tramp(op, rec);
-       } while_for_each_ftrace_op(op);
-}
-
 static void __ftrace_hash_rec_update(struct ftrace_ops *ops,
                                     int filter_hash,
                                     bool inc)
@@ -1636,18 +1619,16 @@ static void __ftrace_hash_rec_update(struct ftrace_ops *ops,
                         * function, and the ops has a trampoline registered
                         * for it, then we can call it directly.
                         */
-                       if (ftrace_rec_count(rec) == 1 && ops->trampoline) {
+                       if (ftrace_rec_count(rec) == 1 && ops->trampoline)
                                rec->flags |= FTRACE_FL_TRAMP;
-                               ops->nr_trampolines++;
-                       } else {
+                       else
                                /*
                                 * If we are adding another function callback
                                 * to this function, and the previous had a
                                 * custom trampoline in use, then we need to go
                                 * back to the default trampoline.
                                 */
-                               ftrace_clear_tramps(rec, ops);
-                       }
+                               rec->flags &= ~FTRACE_FL_TRAMP;
 
                        /*
                         * If any ops wants regs saved for this function
@@ -1660,9 +1641,6 @@ static void __ftrace_hash_rec_update(struct ftrace_ops *ops,
                                return;
                        rec->flags--;
 
-                       if (ops->trampoline && !ftrace_rec_count(rec))
-                               ftrace_remove_tramp(ops, rec);
-
                        /*
                         * If the rec had REGS enabled and the ops that is
                         * being removed had REGS set, then see if there is
@@ -1676,6 +1654,17 @@ static void __ftrace_hash_rec_update(struct ftrace_ops *ops,
                                        rec->flags &= ~FTRACE_FL_REGS;
                        }
 
+                       /*
+                        * If the rec had TRAMP enabled, then it needs to
+                        * be cleared. As TRAMP can only be enabled iff
+                        * there is only a single ops attached to it.
+                        * In otherwords, always disable it on decrementing.
+                        * In the future, we may set it if rec count is
+                        * decremented to one, and the ops that is left
+                        * has a trampoline.
+                        */
+                       rec->flags &= ~FTRACE_FL_TRAMP;
+
                        /*
                         * flags will be cleared in ftrace_check_record()
                         * if rec count is zero.
@@ -1894,22 +1883,73 @@ int ftrace_test_record(struct dyn_ftrace *rec, int enable)
        return ftrace_check_record(rec, enable, 0);
 }
 
+static struct ftrace_ops *
+ftrace_find_tramp_ops_any(struct dyn_ftrace *rec)
+{
+       struct ftrace_ops *op;
+       unsigned long ip = rec->ip;
+
+       do_for_each_ftrace_op(op, ftrace_ops_list) {
+
+               if (!op->trampoline)
+                       continue;
+
+               if (hash_contains_ip(ip, op->func_hash))
+                       return op;
+       } while_for_each_ftrace_op(op);
+
+       return NULL;
+}
+
 static struct ftrace_ops *
 ftrace_find_tramp_ops_curr(struct dyn_ftrace *rec)
 {
        struct ftrace_ops *op;
+       unsigned long ip = rec->ip;
 
-       /* Removed ops need to be tested first */
-       if (removed_ops && removed_ops->tramp_hash) {
-               if (ftrace_lookup_ip(removed_ops->tramp_hash, rec->ip))
+       /*
+        * Need to check removed ops first.
+        * If they are being removed, and this rec has a tramp,
+        * and this rec is in the ops list, then it would be the
+        * one with the tramp.
+        */
+       if (removed_ops) {
+               if (hash_contains_ip(ip, &removed_ops->old_hash))
                        return removed_ops;
        }
 
+       /*
+        * Need to find the current trampoline for a rec.
+        * Now, a trampoline is only attached to a rec if there
+        * was a single 'ops' attached to it. But this can be called
+        * when we are adding another op to the rec or removing the
+        * current one. Thus, if the op is being added, we can
+        * ignore it because it hasn't attached itself to the rec
+        * yet. That means we just need to find the op that has a
+        * trampoline and is not beeing added.
+        */
        do_for_each_ftrace_op(op, ftrace_ops_list) {
-               if (!op->tramp_hash)
+
+               if (!op->trampoline)
                        continue;
 
-               if (ftrace_lookup_ip(op->tramp_hash, rec->ip))
+               /*
+                * If the ops is being added, it hasn't gotten to
+                * the point to be removed from this tree yet.
+                */
+               if (op->flags & FTRACE_OPS_FL_ADDING)
+                       continue;
+
+               /*
+                * If the ops is not being added and has a trampoline,
+                * then it must be the one that we want!
+                */
+               if (hash_contains_ip(ip, op->func_hash))
+                       return op;
+
+               /* If the ops is being modified, it may be in the old hash. */
+               if ((op->flags & FTRACE_OPS_FL_MODIFYING) &&
+                   hash_contains_ip(ip, &op->old_hash))
                        return op;
 
        } while_for_each_ftrace_op(op);
@@ -1921,10 +1961,11 @@ static struct ftrace_ops *
 ftrace_find_tramp_ops_new(struct dyn_ftrace *rec)
 {
        struct ftrace_ops *op;
+       unsigned long ip = rec->ip;
 
        do_for_each_ftrace_op(op, ftrace_ops_list) {
                /* pass rec in as regs to have non-NULL val */
-               if (ftrace_ops_test(op, rec->ip, rec))
+               if (hash_contains_ip(ip, op->func_hash))
                        return op;
        } while_for_each_ftrace_op(op);
 
@@ -2231,92 +2272,6 @@ void __weak arch_ftrace_update_code(int command)
        ftrace_run_stop_machine(command);
 }
 
-static int ftrace_save_ops_tramp_hash(struct ftrace_ops *ops)
-{
-       struct ftrace_page *pg;
-       struct dyn_ftrace *rec;
-       int size, bits;
-       int ret;
-
-       size = ops->nr_trampolines;
-       bits = 0;
-       /*
-        * Make the hash size about 1/2 the # found
-        */
-       for (size /= 2; size; size >>= 1)
-               bits++;
-
-       ops->tramp_hash = alloc_ftrace_hash(bits);
-       /*
-        * TODO: a failed allocation is going to screw up
-        * the accounting of what needs to be modified
-        * and not. For now, we kill ftrace if we fail
-        * to allocate here. But there are ways around this,
-        * but that will take a little more work.
-        */
-       if (!ops->tramp_hash)
-               return -ENOMEM;
-
-       do_for_each_ftrace_rec(pg, rec) {
-               if (ftrace_rec_count(rec) == 1 &&
-                   ftrace_ops_test(ops, rec->ip, rec)) {
-
-                       /*
-                        * If another ops adds to a rec, the rec will
-                        * lose its trampoline and never get it back
-                        * until all ops are off of it.
-                        */
-                       if (!(rec->flags & FTRACE_FL_TRAMP))
-                               continue;
-
-                       /* This record had better have a trampoline */
-                       if (FTRACE_WARN_ON(!(rec->flags & FTRACE_FL_TRAMP_EN)))
-                               return -1;
-
-                       ret = add_hash_entry(ops->tramp_hash, rec->ip);
-                       if (ret < 0)
-                               return ret;
-               }
-       } while_for_each_ftrace_rec();
-
-       /* The number of recs in the hash must match nr_trampolines */
-       if (FTRACE_WARN_ON(ops->tramp_hash->count != ops->nr_trampolines))
-               pr_warn("count=%ld trampolines=%d\n",
-                       ops->tramp_hash->count,
-                       ops->nr_trampolines);
-
-       return 0;
-}
-
-static int ftrace_save_tramp_hashes(void)
-{
-       struct ftrace_ops *op;
-       int ret;
-
-       /*
-        * Now that any trampoline is being used, we need to save the
-        * hashes for the ops that have them. This allows the mapping
-        * back from the record to the ops that has the trampoline to
-        * know what code is being replaced. Modifying code must always
-        * verify what it is changing.
-        */
-       do_for_each_ftrace_op(op, ftrace_ops_list) {
-
-               /* The tramp_hash is recreated each time. */
-               free_ftrace_hash(op->tramp_hash);
-               op->tramp_hash = NULL;
-
-               if (op->nr_trampolines) {
-                       ret = ftrace_save_ops_tramp_hash(op);
-                       if (ret)
-                               return ret;
-               }
-
-       } while_for_each_ftrace_op(op);
-
-       return 0;
-}
-
 static void ftrace_run_update_code(int command)
 {
        int ret;
@@ -2336,9 +2291,13 @@ static void ftrace_run_update_code(int command)
 
        ret = ftrace_arch_code_modify_post_process();
        FTRACE_WARN_ON(ret);
+}
 
-       ret = ftrace_save_tramp_hashes();
-       FTRACE_WARN_ON(ret);
+static void ftrace_run_modify_code(struct ftrace_ops *ops, int command)
+{
+       ops->flags |= FTRACE_OPS_FL_MODIFYING;
+       ftrace_run_update_code(command);
+       ops->flags &= ~FTRACE_OPS_FL_MODIFYING;
 }
 
 static ftrace_func_t saved_ftrace_func;
@@ -2362,6 +2321,13 @@ static void ftrace_startup_enable(int command)
        ftrace_run_update_code(command);
 }
 
+static void ftrace_startup_all(int command)
+{
+       update_all_ops = true;
+       ftrace_startup_enable(command);
+       update_all_ops = false;
+}
+
 static int ftrace_startup(struct ftrace_ops *ops, int command)
 {
        int ret;
@@ -2376,12 +2342,22 @@ static int ftrace_startup(struct ftrace_ops *ops, int command)
        ftrace_start_up++;
        command |= FTRACE_UPDATE_CALLS;
 
-       ops->flags |= FTRACE_OPS_FL_ENABLED;
+       /*
+        * Note that ftrace probes uses this to start up
+        * and modify functions it will probe. But we still
+        * set the ADDING flag for modification, as probes
+        * do not have trampolines. If they add them in the
+        * future, then the probes will need to distinguish
+        * between adding and updating probes.
+        */
+       ops->flags |= FTRACE_OPS_FL_ENABLED | FTRACE_OPS_FL_ADDING;
 
        ftrace_hash_rec_enable(ops, 1);
 
        ftrace_startup_enable(command);
 
+       ops->flags &= ~FTRACE_OPS_FL_ADDING;
+
        return 0;
 }
 
@@ -2431,11 +2407,35 @@ static int ftrace_shutdown(struct ftrace_ops *ops, int command)
         * If the ops uses a trampoline, then it needs to be
         * tested first on update.
         */
+       ops->flags |= FTRACE_OPS_FL_REMOVING;
        removed_ops = ops;
 
+       /* The trampoline logic checks the old hashes */
+       ops->old_hash.filter_hash = ops->func_hash->filter_hash;
+       ops->old_hash.notrace_hash = ops->func_hash->notrace_hash;
+
        ftrace_run_update_code(command);
 
+       /*
+        * If there's no more ops registered with ftrace, run a
+        * sanity check to make sure all rec flags are cleared.
+        */
+       if (ftrace_ops_list == &ftrace_list_end) {
+               struct ftrace_page *pg;
+               struct dyn_ftrace *rec;
+
+               do_for_each_ftrace_rec(pg, rec) {
+                       if (FTRACE_WARN_ON_ONCE(rec->flags))
+                               pr_warn("  %pS flags:%lx\n",
+                                       (void *)rec->ip, rec->flags);
+               } while_for_each_ftrace_rec();
+       }
+
+       ops->old_hash.filter_hash = NULL;
+       ops->old_hash.notrace_hash = NULL;
+
        removed_ops = NULL;
+       ops->flags &= ~FTRACE_OPS_FL_REMOVING;
 
        /*
         * Dynamic ops may be freed, we must make sure that all
@@ -2960,8 +2960,8 @@ static int t_show(struct seq_file *m, void *v)
                if (rec->flags & FTRACE_FL_TRAMP_EN) {
                        struct ftrace_ops *ops;
 
-                       ops = ftrace_find_tramp_ops_curr(rec);
-                       if (ops && ops->trampoline)
+                       ops = ftrace_find_tramp_ops_any(rec);
+                       if (ops)
                                seq_printf(m, "\ttramp: %pS",
                                           (void *)ops->trampoline);
                        else
@@ -3348,7 +3348,7 @@ static void __enable_ftrace_function_probe(void)
        if (ftrace_probe_registered) {
                /* still need to update the function call sites */
                if (ftrace_enabled)
-                       ftrace_run_update_code(FTRACE_UPDATE_CALLS);
+                       ftrace_run_modify_code(&trace_probe_ops, FTRACE_UPDATE_CALLS);
                return;
        }
 
@@ -3399,6 +3399,7 @@ register_ftrace_function_probe(char *glob, struct ftrace_probe_ops *ops,
 {
        struct ftrace_func_probe *entry;
        struct ftrace_hash **orig_hash = &trace_probe_ops.func_hash->filter_hash;
+       struct ftrace_hash *old_hash = *orig_hash;
        struct ftrace_hash *hash;
        struct ftrace_page *pg;
        struct dyn_ftrace *rec;
@@ -3417,7 +3418,7 @@ register_ftrace_function_probe(char *glob, struct ftrace_probe_ops *ops,
 
        mutex_lock(&trace_probe_ops.func_hash->regex_lock);
 
-       hash = alloc_and_copy_ftrace_hash(FTRACE_HASH_DEFAULT_BITS, *orig_hash);
+       hash = alloc_and_copy_ftrace_hash(FTRACE_HASH_DEFAULT_BITS, old_hash);
        if (!hash) {
                count = -ENOMEM;
                goto out;
@@ -3476,7 +3477,9 @@ register_ftrace_function_probe(char *glob, struct ftrace_probe_ops *ops,
        } while_for_each_ftrace_rec();
 
        ret = ftrace_hash_move(&trace_probe_ops, 1, orig_hash, hash);
-       if (ret < 0)
+       if (!ret)
+               free_ftrace_hash_rcu(old_hash);
+       else
                count = ret;
 
        __enable_ftrace_function_probe();
@@ -3503,6 +3506,7 @@ __unregister_ftrace_function_probe(char *glob, struct ftrace_probe_ops *ops,
        struct ftrace_func_probe *entry;
        struct ftrace_func_probe *p;
        struct ftrace_hash **orig_hash = &trace_probe_ops.func_hash->filter_hash;
+       struct ftrace_hash *old_hash = *orig_hash;
        struct list_head free_list;
        struct ftrace_hash *hash;
        struct hlist_node *tmp;
@@ -3510,6 +3514,7 @@ __unregister_ftrace_function_probe(char *glob, struct ftrace_probe_ops *ops,
        int type = MATCH_FULL;
        int i, len = 0;
        char *search;
+       int ret;
 
        if (glob && (strcmp(glob, "*") == 0 || !strlen(glob)))
                glob = NULL;
@@ -3568,8 +3573,11 @@ __unregister_ftrace_function_probe(char *glob, struct ftrace_probe_ops *ops,
         * Remove after the disable is called. Otherwise, if the last
         * probe is removed, a null hash means *all enabled*.
         */
-       ftrace_hash_move(&trace_probe_ops, 1, orig_hash, hash);
+       ret = ftrace_hash_move(&trace_probe_ops, 1, orig_hash, hash);
        synchronize_sched();
+       if (!ret)
+               free_ftrace_hash_rcu(old_hash);
+
        list_for_each_entry_safe(entry, p, &free_list, free_list) {
                list_del(&entry->free_list);
                ftrace_free_entry(entry);
@@ -3759,7 +3767,7 @@ ftrace_match_addr(struct ftrace_hash *hash, unsigned long ip, int remove)
 static void ftrace_ops_update_code(struct ftrace_ops *ops)
 {
        if (ops->flags & FTRACE_OPS_FL_ENABLED && ftrace_enabled)
-               ftrace_run_update_code(FTRACE_UPDATE_CALLS);
+               ftrace_run_modify_code(ops, FTRACE_UPDATE_CALLS);
 }
 
 static int
@@ -3767,6 +3775,7 @@ ftrace_set_hash(struct ftrace_ops *ops, unsigned char *buf, int len,
                unsigned long ip, int remove, int reset, int enable)
 {
        struct ftrace_hash **orig_hash;
+       struct ftrace_hash *old_hash;
        struct ftrace_hash *hash;
        int ret;
 
@@ -3801,10 +3810,12 @@ ftrace_set_hash(struct ftrace_ops *ops, unsigned char *buf, int len,
        }
 
        mutex_lock(&ftrace_lock);
+       old_hash = *orig_hash;
        ret = ftrace_hash_move(ops, enable, orig_hash, hash);
-       if (!ret)
+       if (!ret) {
                ftrace_ops_update_code(ops);
-
+               free_ftrace_hash_rcu(old_hash);
+       }
        mutex_unlock(&ftrace_lock);
 
  out_regex_unlock:
@@ -4013,6 +4024,7 @@ int ftrace_regex_release(struct inode *inode, struct file *file)
        struct seq_file *m = (struct seq_file *)file->private_data;
        struct ftrace_iterator *iter;
        struct ftrace_hash **orig_hash;
+       struct ftrace_hash *old_hash;
        struct trace_parser *parser;
        int filter_hash;
        int ret;
@@ -4042,11 +4054,13 @@ int ftrace_regex_release(struct inode *inode, struct file *file)
                        orig_hash = &iter->ops->func_hash->notrace_hash;
 
                mutex_lock(&ftrace_lock);
+               old_hash = *orig_hash;
                ret = ftrace_hash_move(iter->ops, filter_hash,
                                       orig_hash, iter->hash);
-               if (!ret)
+               if (!ret) {
                        ftrace_ops_update_code(iter->ops);
-
+                       free_ftrace_hash_rcu(old_hash);
+               }
                mutex_unlock(&ftrace_lock);
        }
 
@@ -4678,6 +4692,7 @@ core_initcall(ftrace_nodyn_init);
 
 static inline int ftrace_init_dyn_debugfs(struct dentry *d_tracer) { return 0; }
 static inline void ftrace_startup_enable(int command) { }
+static inline void ftrace_startup_all(int command) { }
 /* Keep as macros so we do not need to define the commands */
 # define ftrace_startup(ops, command)                                  \
        ({                                                              \
@@ -4827,6 +4842,56 @@ static void ftrace_ops_no_ops(unsigned long ip, unsigned long parent_ip)
 }
 #endif
 
+/*
+ * If there's only one function registered but it does not support
+ * recursion, this function will be called by the mcount trampoline.
+ * This function will handle recursion protection.
+ */
+static void ftrace_ops_recurs_func(unsigned long ip, unsigned long parent_ip,
+                                  struct ftrace_ops *op, struct pt_regs *regs)
+{
+       int bit;
+
+       bit = trace_test_and_set_recursion(TRACE_LIST_START, TRACE_LIST_MAX);
+       if (bit < 0)
+               return;
+
+       op->func(ip, parent_ip, op, regs);
+
+       trace_clear_recursion(bit);
+}
+
+/**
+ * ftrace_ops_get_func - get the function a trampoline should call
+ * @ops: the ops to get the function for
+ *
+ * Normally the mcount trampoline will call the ops->func, but there
+ * are times that it should not. For example, if the ops does not
+ * have its own recursion protection, then it should call the
+ * ftrace_ops_recurs_func() instead.
+ *
+ * Returns the function that the trampoline should call for @ops.
+ */
+ftrace_func_t ftrace_ops_get_func(struct ftrace_ops *ops)
+{
+       /*
+        * If this is a dynamic ops or we force list func,
+        * then it needs to call the list anyway.
+        */
+       if (ops->flags & FTRACE_OPS_FL_DYNAMIC || FTRACE_FORCE_LIST_FUNC)
+               return ftrace_ops_list_func;
+
+       /*
+        * If the func handles its own recursion, call it directly.
+        * Otherwise call the recursion protected function that
+        * will call the ftrace ops function.
+        */
+       if (!(ops->flags & FTRACE_OPS_FL_RECURSION_SAFE))
+               return ftrace_ops_recurs_func;
+
+       return ops->func;
+}
+
 static void clear_ftrace_swapper(void)
 {
        struct task_struct *p;
@@ -4927,7 +4992,8 @@ static int ftrace_pid_add(int p)
        set_ftrace_pid_task(pid);
 
        ftrace_update_pid_func();
-       ftrace_startup_enable(0);
+
+       ftrace_startup_all(0);
 
        mutex_unlock(&ftrace_lock);
        return 0;
@@ -4956,7 +5022,7 @@ static void ftrace_pid_reset(void)
        }
 
        ftrace_update_pid_func();
-       ftrace_startup_enable(0);
+       ftrace_startup_all(0);
 
        mutex_unlock(&ftrace_lock);
 }
index 0434ff1b808e92c539b70828185c8fa1c44c865a..3f9e328c30b5299961a8ad86250dd89ca35aaaa3 100644 (file)
@@ -205,7 +205,6 @@ static void ring_buffer_consumer(void)
                        break;
 
                schedule();
-               __set_current_state(TASK_RUNNING);
        }
        reader_finish = 0;
        complete(&read_done);
@@ -379,7 +378,6 @@ static int ring_buffer_consumer_thread(void *arg)
                        break;
 
                schedule();
-               __set_current_state(TASK_RUNNING);
        }
        __set_current_state(TASK_RUNNING);
 
@@ -407,7 +405,6 @@ static int ring_buffer_producer_thread(void *arg)
                trace_printk("Sleeping for 10 secs\n");
                set_current_state(TASK_INTERRUPTIBLE);
                schedule_timeout(HZ * SLEEP_TIME);
-               __set_current_state(TASK_RUNNING);
        }
 
        if (kill_test)
index ef06ce7e9cf8d1d9b6ea78240f69c5d44ff426dc..0cc51edde3a899bf464fecbccb98e5eb35d71d42 100644 (file)
@@ -2513,8 +2513,11 @@ static __init int event_test_thread(void *unused)
        kfree(test_malloc);
 
        set_current_state(TASK_INTERRUPTIBLE);
-       while (!kthread_should_stop())
+       while (!kthread_should_stop()) {
                schedule();
+               set_current_state(TASK_INTERRUPTIBLE);
+       }
+       __set_current_state(TASK_RUNNING);
 
        return 0;
 }
index 5ef60499dc8e6c6df909794c1a54eed4b9bb2dbf..b0f86ea77881ecf3c6fbb626f298df3d25c57a48 100644 (file)
@@ -382,6 +382,8 @@ static int trace_selftest_startup_dynamic_tracing(struct tracer *trace,
 
        /* check the trace buffer */
        ret = trace_test_buffer(&tr->trace_buffer, &count);
+
+       ftrace_enabled = 1;
        tracing_start();
 
        /* we should only have one item */
@@ -679,6 +681,8 @@ trace_selftest_startup_function(struct tracer *trace, struct trace_array *tr)
 
        /* check the trace buffer */
        ret = trace_test_buffer(&tr->trace_buffer, &count);
+
+       ftrace_enabled = 1;
        trace->reset(tr);
        tracing_start();
 
@@ -1025,6 +1029,12 @@ trace_selftest_startup_nop(struct tracer *trace, struct trace_array *tr)
 #endif
 
 #ifdef CONFIG_SCHED_TRACER
+
+struct wakeup_test_data {
+       struct completion       is_ready;
+       int                     go;
+};
+
 static int trace_wakeup_test_thread(void *data)
 {
        /* Make this a -deadline thread */
@@ -1034,51 +1044,56 @@ static int trace_wakeup_test_thread(void *data)
                .sched_deadline = 10000000ULL,
                .sched_period = 10000000ULL
        };
-       struct completion *x = data;
+       struct wakeup_test_data *x = data;
 
        sched_setattr(current, &attr);
 
        /* Make it know we have a new prio */
-       complete(x);
+       complete(&x->is_ready);
 
        /* now go to sleep and let the test wake us up */
        set_current_state(TASK_INTERRUPTIBLE);
-       schedule();
+       while (!x->go) {
+               schedule();
+               set_current_state(TASK_INTERRUPTIBLE);
+       }
 
-       complete(x);
+       complete(&x->is_ready);
+
+       set_current_state(TASK_INTERRUPTIBLE);
 
        /* we are awake, now wait to disappear */
        while (!kthread_should_stop()) {
-               /*
-                * This will likely be the system top priority
-                * task, do short sleeps to let others run.
-                */
-               msleep(100);
+               schedule();
+               set_current_state(TASK_INTERRUPTIBLE);
        }
 
+       __set_current_state(TASK_RUNNING);
+
        return 0;
 }
-
 int
 trace_selftest_startup_wakeup(struct tracer *trace, struct trace_array *tr)
 {
        unsigned long save_max = tr->max_latency;
        struct task_struct *p;
-       struct completion is_ready;
+       struct wakeup_test_data data;
        unsigned long count;
        int ret;
 
-       init_completion(&is_ready);
+       memset(&data, 0, sizeof(data));
+
+       init_completion(&data.is_ready);
 
        /* create a -deadline thread */
-       p = kthread_run(trace_wakeup_test_thread, &is_ready, "ftrace-test");
+       p = kthread_run(trace_wakeup_test_thread, &data, "ftrace-test");
        if (IS_ERR(p)) {
                printk(KERN_CONT "Failed to create ftrace wakeup test thread ");
                return -1;
        }
 
        /* make sure the thread is running at -deadline policy */
-       wait_for_completion(&is_ready);
+       wait_for_completion(&data.is_ready);
 
        /* start the tracing */
        ret = tracer_init(trace, tr);
@@ -1099,18 +1114,20 @@ trace_selftest_startup_wakeup(struct tracer *trace, struct trace_array *tr)
                msleep(100);
        }
 
-       init_completion(&is_ready);
+       init_completion(&data.is_ready);
+
+       data.go = 1;
+       /* memory barrier is in the wake_up_process() */
 
        wake_up_process(p);
 
        /* Wait for the task to wake up */
-       wait_for_completion(&is_ready);
+       wait_for_completion(&data.is_ready);
 
        /* stop the tracing. */
        tracing_stop();
        /* check both trace buffers */
        ret = trace_test_buffer(&tr->trace_buffer, NULL);
-       printk("ret = %d\n", ret);
        if (!ret)
                ret = trace_test_buffer(&tr->max_buffer, &count);
 
index 8a4e5cb66a4c4c1b9726f942e3e54b8e52a45ff5..16eddb308c336aac2636ee43c4dcdfab7bb4a3f7 100644 (file)
@@ -13,7 +13,6 @@
 #include <linux/sysctl.h>
 #include <linux/init.h>
 #include <linux/fs.h>
-#include <linux/magic.h>
 
 #include <asm/setup.h>
 
@@ -171,8 +170,7 @@ check_stack(unsigned long ip, unsigned long *stack)
                        i++;
        }
 
-       if ((current != &init_task &&
-               *(end_of_stack(current)) != STACK_END_MAGIC)) {
+       if (task_stack_end_corrupted(current)) {
                print_max_stack();
                BUG();
        }
index 759d5e004517cab413188b9a4a1b3adf9e6b2597..4dc8b79c5f75d214919220bdc45232fe635e6af0 100644 (file)
@@ -425,7 +425,7 @@ static void unreg_event_syscall_enter(struct ftrace_event_file *file,
                return;
        mutex_lock(&syscall_trace_lock);
        tr->sys_refcount_enter--;
-       rcu_assign_pointer(tr->enter_syscall_files[num], NULL);
+       RCU_INIT_POINTER(tr->enter_syscall_files[num], NULL);
        if (!tr->sys_refcount_enter)
                unregister_trace_sys_enter(ftrace_syscall_enter, tr);
        mutex_unlock(&syscall_trace_lock);
@@ -463,7 +463,7 @@ static void unreg_event_syscall_exit(struct ftrace_event_file *file,
                return;
        mutex_lock(&syscall_trace_lock);
        tr->sys_refcount_exit--;
-       rcu_assign_pointer(tr->exit_syscall_files[num], NULL);
+       RCU_INIT_POINTER(tr->exit_syscall_files[num], NULL);
        if (!tr->sys_refcount_exit)
                unregister_trace_sys_exit(ftrace_syscall_exit, tr);
        mutex_unlock(&syscall_trace_lock);
index 7b223b212683202e2e50ee83153eb8df7dbbe3de..49e9537f3673714772c4aa042973f1f53b5ed56c 100644 (file)
 #include <linux/cpu.h>
 #include <linux/nmi.h>
 #include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/freezer.h>
-#include <linux/kthread.h>
-#include <linux/lockdep.h>
-#include <linux/notifier.h>
 #include <linux/module.h>
 #include <linux/sysctl.h>
 #include <linux/smpboot.h>
@@ -64,6 +59,25 @@ static unsigned long soft_lockup_nmi_warn;
 static int hardlockup_panic =
                        CONFIG_BOOTPARAM_HARDLOCKUP_PANIC_VALUE;
 
+static bool hardlockup_detector_enabled = true;
+/*
+ * We may not want to enable hard lockup detection by default in all cases,
+ * for example when running the kernel as a guest on a hypervisor. In these
+ * cases this function can be called to disable hard lockup detection. This
+ * function should only be executed once by the boot processor before the
+ * kernel command line parameters are parsed, because otherwise it is not
+ * possible to override this in hardlockup_panic_setup().
+ */
+void watchdog_enable_hardlockup_detector(bool val)
+{
+       hardlockup_detector_enabled = val;
+}
+
+bool watchdog_hardlockup_detector_is_enabled(void)
+{
+       return hardlockup_detector_enabled;
+}
+
 static int __init hardlockup_panic_setup(char *str)
 {
        if (!strncmp(str, "panic", 5))
@@ -72,6 +86,14 @@ static int __init hardlockup_panic_setup(char *str)
                hardlockup_panic = 0;
        else if (!strncmp(str, "0", 1))
                watchdog_user_enabled = 0;
+       else if (!strncmp(str, "1", 1) || !strncmp(str, "2", 1)) {
+               /*
+                * Setting 'nmi_watchdog=1' or 'nmi_watchdog=2' (legacy option)
+                * has the same effect.
+                */
+               watchdog_user_enabled = 1;
+               watchdog_enable_hardlockup_detector(true);
+       }
        return 1;
 }
 __setup("nmi_watchdog=", hardlockup_panic_setup);
@@ -470,6 +492,15 @@ static int watchdog_nmi_enable(unsigned int cpu)
        struct perf_event_attr *wd_attr;
        struct perf_event *event = per_cpu(watchdog_ev, cpu);
 
+       /*
+        * Some kernels need to default hard lockup detection to
+        * 'disabled', for example a guest on a hypervisor.
+        */
+       if (!watchdog_hardlockup_detector_is_enabled()) {
+               event = ERR_PTR(-ENOENT);
+               goto handle_err;
+       }
+
        /* is it already setup and enabled? */
        if (event && event->state > PERF_EVENT_STATE_OFF)
                goto out;
@@ -484,6 +515,7 @@ static int watchdog_nmi_enable(unsigned int cpu)
        /* Try to register using hardware perf events */
        event = perf_event_create_kernel_counter(wd_attr, cpu, NULL, watchdog_overflow_callback, NULL);
 
+handle_err:
        /* save cpu0 error for future comparision */
        if (cpu == 0 && IS_ERR(event))
                cpu0_err = PTR_ERR(event);
@@ -530,7 +562,10 @@ static void watchdog_nmi_disable(unsigned int cpu)
                /* should be in cleanup, but blocks oprofile */
                perf_event_release_kernel(event);
        }
-       return;
+       if (cpu == 0) {
+               /* watchdog_nmi_enable() expects this to be zero initially. */
+               cpu0_err = 0;
+       }
 }
 #else
 static int watchdog_nmi_enable(unsigned int cpu) { return 0; }
@@ -626,11 +661,13 @@ int proc_dowatchdog(struct ctl_table *table, int write,
                    void __user *buffer, size_t *lenp, loff_t *ppos)
 {
        int err, old_thresh, old_enabled;
+       bool old_hardlockup;
        static DEFINE_MUTEX(watchdog_proc_mutex);
 
        mutex_lock(&watchdog_proc_mutex);
        old_thresh = ACCESS_ONCE(watchdog_thresh);
        old_enabled = ACCESS_ONCE(watchdog_user_enabled);
+       old_hardlockup = watchdog_hardlockup_detector_is_enabled();
 
        err = proc_dointvec_minmax(table, write, buffer, lenp, ppos);
        if (err || !write)
@@ -642,15 +679,22 @@ int proc_dowatchdog(struct ctl_table *table, int write,
         * disabled. The 'watchdog_running' variable check in
         * watchdog_*_all_cpus() function takes care of this.
         */
-       if (watchdog_user_enabled && watchdog_thresh)
+       if (watchdog_user_enabled && watchdog_thresh) {
+               /*
+                * Prevent a change in watchdog_thresh accidentally overriding
+                * the enablement of the hardlockup detector.
+                */
+               if (watchdog_user_enabled != old_enabled)
+                       watchdog_enable_hardlockup_detector(true);
                err = watchdog_enable_all_cpus(old_thresh != watchdog_thresh);
-       else
+       else
                watchdog_disable_all_cpus();
 
        /* Restore old values on failure */
        if (err) {
                watchdog_thresh = old_thresh;
                watchdog_user_enabled = old_enabled;
+               watchdog_enable_hardlockup_detector(old_hardlockup);
        }
 out:
        mutex_unlock(&watchdog_proc_mutex);
index 5dbe22aa3efd48f92b39e6ccd25b63880dc1015b..09b685daee3d8c18e2004a2333583e1c7e00f706 100644 (file)
@@ -2043,9 +2043,10 @@ __acquires(&pool->lock)
         * kernels, where a requeueing work item waiting for something to
         * happen could deadlock with stop_machine as such work item could
         * indefinitely requeue itself while all other CPUs are trapped in
-        * stop_machine.
+        * stop_machine. At the same time, report a quiescent RCU state so
+        * the same condition doesn't freeze RCU.
         */
-       cond_resched();
+       cond_resched_rcu_qs();
 
        spin_lock_irq(&pool->lock);
 
index 3ac43f34437bad6d64f870222c51dbc41b2c73b2..4e35a5d767ed2f50c69df7dbdbcf0e3d9885777f 100644 (file)
@@ -824,6 +824,18 @@ config SCHEDSTATS
          application, you can say N to avoid the very slight overhead
          this adds.
 
+config SCHED_STACK_END_CHECK
+       bool "Detect stack corruption on calls to schedule()"
+       depends on DEBUG_KERNEL
+       default n
+       help
+         This option checks for a stack overrun on calls to schedule().
+         If the stack end location is found to be over written always panic as
+         the content of the corrupted region can no longer be trusted.
+         This is to ensure no erroneous behaviour occurs which could result in
+         data corruption or a sporadic crash at a later stage once the region
+         is examined. The runtime overhead introduced is minimal.
+
 config TIMER_STATS
        bool "Collect kernel timers statistics"
        depends on DEBUG_KERNEL && PROC_FS
@@ -952,7 +964,7 @@ config PROVE_LOCKING
         the proof of observed correctness is also maintained for an
         arbitrary combination of these separate locking variants.
 
-        For more details, see Documentation/lockdep-design.txt.
+        For more details, see Documentation/locking/lockdep-design.txt.
 
 config LOCKDEP
        bool
@@ -973,7 +985,7 @@ config LOCK_STAT
        help
         This feature enables tracking lock contention points
 
-        For more details, see Documentation/lockstat.txt
+        For more details, see Documentation/locking/lockstat.txt
 
         This also enables lock events required by "perf lock",
         subcommand of perf.
@@ -1636,7 +1648,7 @@ config DMA_API_DEBUG
 
          If unsure, say N.
 
-config TEST_MODULE
+config TEST_LKM
        tristate "Test module loading with 'hello world' module"
        default n
        depends on m
index d6b4bc496408e5ce44735606286cb923fbbefee3..7512dc978f1872fe4a395868ed0f3cbd30de2ad0 100644 (file)
@@ -11,7 +11,7 @@ lib-y := ctype.o string.o vsprintf.o cmdline.o \
         rbtree.o radix-tree.o dump_stack.o timerqueue.o\
         idr.o int_sqrt.o extable.o \
         sha1.o md5.o irq_regs.o reciprocal_div.o argv_split.o \
-        proportions.o flex_proportions.o prio_heap.o ratelimit.o show_mem.o \
+        proportions.o flex_proportions.o ratelimit.o show_mem.o \
         is_single_threaded.o plist.o decompress.o kobject_uevent.o \
         earlycpio.o
 
@@ -31,7 +31,7 @@ obj-y += string_helpers.o
 obj-$(CONFIG_TEST_STRING_HELPERS) += test-string_helpers.o
 obj-y += kstrtox.o
 obj-$(CONFIG_TEST_KSTRTOX) += test-kstrtox.o
-obj-$(CONFIG_TEST_MODULE) += test_module.o
+obj-$(CONFIG_TEST_LKM) += test_module.o
 obj-$(CONFIG_TEST_USER_COPY) += test_user_copy.o
 obj-$(CONFIG_TEST_BPF) += test_bpf.o
 obj-$(CONFIG_TEST_FIRMWARE) += test_firmware.o
index 08a4f068e61e7689f4246ec77683d71b18f72a76..1298c05ef52848ef3febd5e2512139c17533e844 100644 (file)
@@ -70,53 +70,42 @@ void atomic64_set(atomic64_t *v, long long i)
 }
 EXPORT_SYMBOL(atomic64_set);
 
-void atomic64_add(long long a, atomic64_t *v)
-{
-       unsigned long flags;
-       raw_spinlock_t *lock = lock_addr(v);
-
-       raw_spin_lock_irqsave(lock, flags);
-       v->counter += a;
-       raw_spin_unlock_irqrestore(lock, flags);
-}
-EXPORT_SYMBOL(atomic64_add);
-
-long long atomic64_add_return(long long a, atomic64_t *v)
-{
-       unsigned long flags;
-       raw_spinlock_t *lock = lock_addr(v);
-       long long val;
-
-       raw_spin_lock_irqsave(lock, flags);
-       val = v->counter += a;
-       raw_spin_unlock_irqrestore(lock, flags);
-       return val;
-}
-EXPORT_SYMBOL(atomic64_add_return);
-
-void atomic64_sub(long long a, atomic64_t *v)
-{
-       unsigned long flags;
-       raw_spinlock_t *lock = lock_addr(v);
-
-       raw_spin_lock_irqsave(lock, flags);
-       v->counter -= a;
-       raw_spin_unlock_irqrestore(lock, flags);
-}
-EXPORT_SYMBOL(atomic64_sub);
-
-long long atomic64_sub_return(long long a, atomic64_t *v)
-{
-       unsigned long flags;
-       raw_spinlock_t *lock = lock_addr(v);
-       long long val;
-
-       raw_spin_lock_irqsave(lock, flags);
-       val = v->counter -= a;
-       raw_spin_unlock_irqrestore(lock, flags);
-       return val;
-}
-EXPORT_SYMBOL(atomic64_sub_return);
+#define ATOMIC64_OP(op, c_op)                                          \
+void atomic64_##op(long long a, atomic64_t *v)                         \
+{                                                                      \
+       unsigned long flags;                                            \
+       raw_spinlock_t *lock = lock_addr(v);                            \
+                                                                       \
+       raw_spin_lock_irqsave(lock, flags);                             \
+       v->counter c_op a;                                              \
+       raw_spin_unlock_irqrestore(lock, flags);                        \
+}                                                                      \
+EXPORT_SYMBOL(atomic64_##op);
+
+#define ATOMIC64_OP_RETURN(op, c_op)                                   \
+long long atomic64_##op##_return(long long a, atomic64_t *v)           \
+{                                                                      \
+       unsigned long flags;                                            \
+       raw_spinlock_t *lock = lock_addr(v);                            \
+       long long val;                                                  \
+                                                                       \
+       raw_spin_lock_irqsave(lock, flags);                             \
+       val = (v->counter c_op a);                                      \
+       raw_spin_unlock_irqrestore(lock, flags);                        \
+       return val;                                                     \
+}                                                                      \
+EXPORT_SYMBOL(atomic64_##op##_return);
+
+#define ATOMIC64_OPS(op, c_op)                                         \
+       ATOMIC64_OP(op, c_op)                                           \
+       ATOMIC64_OP_RETURN(op, c_op)
+
+ATOMIC64_OPS(add, +=)
+ATOMIC64_OPS(sub, -=)
+
+#undef ATOMIC64_OPS
+#undef ATOMIC64_OP_RETURN
+#undef ATOMIC64_OP
 
 long long atomic64_dec_if_positive(atomic64_t *v)
 {
index 31fe79e31ab8d4940aa9d4e930c674e52ecee467..dfba05521748ff54d82e2084bef91dd5906b9c7e 100644 (file)
@@ -819,22 +819,9 @@ static const struct seq_operations ddebug_proc_seqops = {
  */
 static int ddebug_proc_open(struct inode *inode, struct file *file)
 {
-       struct ddebug_iter *iter;
-       int err;
-
        vpr_info("called\n");
-
-       iter = kzalloc(sizeof(*iter), GFP_KERNEL);
-       if (iter == NULL)
-               return -ENOMEM;
-
-       err = seq_open(file, &ddebug_proc_seqops);
-       if (err) {
-               kfree(iter);
-               return err;
-       }
-       ((struct seq_file *)file->private_data)->private = iter;
-       return 0;
+       return seq_open_private(file, &ddebug_proc_seqops,
+                               sizeof(struct ddebug_iter));
 }
 
 static const struct file_operations ddebug_proc_fops = {
index 8499c810909a58ae100b7db96a01ea74b5c14948..270773b91923ce5a0e65c479b1af32b146dfc5d3 100644 (file)
@@ -58,6 +58,22 @@ int hex2bin(u8 *dst, const char *src, size_t count)
 }
 EXPORT_SYMBOL(hex2bin);
 
+/**
+ * bin2hex - convert binary data to an ascii hexadecimal string
+ * @dst: ascii hexadecimal result
+ * @src: binary data
+ * @count: binary data length
+ */
+char *bin2hex(char *dst, const void *src, size_t count)
+{
+       const unsigned char *_src = src;
+
+       while (count--)
+               dst = hex_byte_pack(dst, *_src++);
+       return dst;
+}
+EXPORT_SYMBOL(bin2hex);
+
 /**
  * hex_dump_to_buffer - convert a blob of data to "hex ASCII" in memory
  * @buf: data blob to dump
diff --git a/lib/prio_heap.c b/lib/prio_heap.c
deleted file mode 100644 (file)
index a7af6f8..0000000
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * Simple insertion-only static-sized priority heap containing
- * pointers, based on CLR, chapter 7
- */
-
-#include <linux/slab.h>
-#include <linux/prio_heap.h>
-
-int heap_init(struct ptr_heap *heap, size_t size, gfp_t gfp_mask,
-             int (*gt)(void *, void *))
-{
-       heap->ptrs = kmalloc(size, gfp_mask);
-       if (!heap->ptrs)
-               return -ENOMEM;
-       heap->size = 0;
-       heap->max = size / sizeof(void *);
-       heap->gt = gt;
-       return 0;
-}
-
-void heap_free(struct ptr_heap *heap)
-{
-       kfree(heap->ptrs);
-}
-
-void *heap_insert(struct ptr_heap *heap, void *p)
-{
-       void *res;
-       void **ptrs = heap->ptrs;
-       int pos;
-
-       if (heap->size < heap->max) {
-               /* Heap insertion */
-               pos = heap->size++;
-               while (pos > 0 && heap->gt(p, ptrs[(pos-1)/2])) {
-                       ptrs[pos] = ptrs[(pos-1)/2];
-                       pos = (pos-1)/2;
-               }
-               ptrs[pos] = p;
-               return NULL;
-       }
-
-       /* The heap is full, so something will have to be dropped */
-
-       /* If the new pointer is greater than the current max, drop it */
-       if (heap->gt(p, ptrs[0]))
-               return p;
-
-       /* Replace the current max and heapify */
-       res = ptrs[0];
-       ptrs[0] = p;
-       pos = 0;
-
-       while (1) {
-               int left = 2 * pos + 1;
-               int right = 2 * pos + 2;
-               int largest = pos;
-               if (left < heap->size && heap->gt(ptrs[left], p))
-                       largest = left;
-               if (right < heap->size && heap->gt(ptrs[right], ptrs[largest]))
-                       largest = right;
-               if (largest == pos)
-                       break;
-               /* Push p down the heap one level and bump one up */
-               ptrs[pos] = ptrs[largest];
-               ptrs[largest] = p;
-               pos = largest;
-       }
-       return res;
-}
index f3c6ff596414e6f9bd1cf58071fadfd4c7a31b35..2fc20aa06f848fcebd8aa30d238942f5ec399690 100644 (file)
 #include <linux/bug.h>
 #include <linux/errno.h>
 
-#ifndef __HAVE_ARCH_STRNICMP
+#ifndef __HAVE_ARCH_STRNCASECMP
 /**
- * strnicmp - Case insensitive, length-limited string comparison
+ * strncasecmp - Case insensitive, length-limited string comparison
  * @s1: One string
  * @s2: The other string
  * @len: the maximum number of characters to compare
  */
-int strnicmp(const char *s1, const char *s2, size_t len)
+int strncasecmp(const char *s1, const char *s2, size_t len)
 {
        /* Yes, Virginia, it had better be unsigned */
        unsigned char c1, c2;
@@ -56,6 +56,14 @@ int strnicmp(const char *s1, const char *s2, size_t len)
        } while (--len);
        return (int)c1 - (int)c2;
 }
+EXPORT_SYMBOL(strncasecmp);
+#endif
+#ifndef __HAVE_ARCH_STRNICMP
+#undef strnicmp
+int strnicmp(const char *s1, const char *s2, size_t len)
+{
+       return strncasecmp(s1, s2, len);
+}
 EXPORT_SYMBOL(strnicmp);
 #endif
 
@@ -73,20 +81,6 @@ int strcasecmp(const char *s1, const char *s2)
 EXPORT_SYMBOL(strcasecmp);
 #endif
 
-#ifndef __HAVE_ARCH_STRNCASECMP
-int strncasecmp(const char *s1, const char *s2, size_t n)
-{
-       int c1, c2;
-
-       do {
-               c1 = tolower(*s1++);
-               c2 = tolower(*s2++);
-       } while ((--n > 0) && c1 == c2 && c1 != 0);
-       return c1 - c2;
-}
-EXPORT_SYMBOL(strncasecmp);
-#endif
-
 #ifndef __HAVE_ARCH_STRCPY
 /**
  * strcpy - Copy a %NUL terminated string
index 29033f319aea1f8f48e85374884f657a130519a4..58b78ba57439c76e89a9d0a911ac3960e744ebf1 100644 (file)
@@ -8,6 +8,8 @@
 #include <linux/math64.h>
 #include <linux/export.h>
 #include <linux/ctype.h>
+#include <linux/errno.h>
+#include <linux/string.h>
 #include <linux/string_helpers.h>
 
 /**
@@ -168,6 +170,44 @@ static bool unescape_special(char **src, char **dst)
        return true;
 }
 
+/**
+ * string_unescape - unquote characters in the given string
+ * @src:       source buffer (escaped)
+ * @dst:       destination buffer (unescaped)
+ * @size:      size of the destination buffer (0 to unlimit)
+ * @flags:     combination of the flags (bitwise OR):
+ *     %UNESCAPE_SPACE:
+ *             '\f' - form feed
+ *             '\n' - new line
+ *             '\r' - carriage return
+ *             '\t' - horizontal tab
+ *             '\v' - vertical tab
+ *     %UNESCAPE_OCTAL:
+ *             '\NNN' - byte with octal value NNN (1 to 3 digits)
+ *     %UNESCAPE_HEX:
+ *             '\xHH' - byte with hexadecimal value HH (1 to 2 digits)
+ *     %UNESCAPE_SPECIAL:
+ *             '\"' - double quote
+ *             '\\' - backslash
+ *             '\a' - alert (BEL)
+ *             '\e' - escape
+ *     %UNESCAPE_ANY:
+ *             all previous together
+ *
+ * Description:
+ * The function unquotes characters in the given string.
+ *
+ * Because the size of the output will be the same as or less than the size of
+ * the input, the transformation may be performed in place.
+ *
+ * Caller must provide valid source and destination pointers. Be aware that
+ * destination buffer will always be NULL-terminated. Source string must be
+ * NULL-terminated as well.
+ *
+ * Return:
+ * The amount of the characters processed to the destination buffer excluding
+ * trailing '\0' is returned.
+ */
 int string_unescape(char *src, char *dst, size_t size, unsigned int flags)
 {
        char *out = dst;
@@ -202,3 +242,275 @@ int string_unescape(char *src, char *dst, size_t size, unsigned int flags)
        return out - dst;
 }
 EXPORT_SYMBOL(string_unescape);
+
+static int escape_passthrough(unsigned char c, char **dst, size_t *osz)
+{
+       char *out = *dst;
+
+       if (*osz < 1)
+               return -ENOMEM;
+
+       *out++ = c;
+
+       *dst = out;
+       *osz -= 1;
+
+       return 1;
+}
+
+static int escape_space(unsigned char c, char **dst, size_t *osz)
+{
+       char *out = *dst;
+       unsigned char to;
+
+       if (*osz < 2)
+               return -ENOMEM;
+
+       switch (c) {
+       case '\n':
+               to = 'n';
+               break;
+       case '\r':
+               to = 'r';
+               break;
+       case '\t':
+               to = 't';
+               break;
+       case '\v':
+               to = 'v';
+               break;
+       case '\f':
+               to = 'f';
+               break;
+       default:
+               return 0;
+       }
+
+       *out++ = '\\';
+       *out++ = to;
+
+       *dst = out;
+       *osz -= 2;
+
+       return 1;
+}
+
+static int escape_special(unsigned char c, char **dst, size_t *osz)
+{
+       char *out = *dst;
+       unsigned char to;
+
+       if (*osz < 2)
+               return -ENOMEM;
+
+       switch (c) {
+       case '\\':
+               to = '\\';
+               break;
+       case '\a':
+               to = 'a';
+               break;
+       case '\e':
+               to = 'e';
+               break;
+       default:
+               return 0;
+       }
+
+       *out++ = '\\';
+       *out++ = to;
+
+       *dst = out;
+       *osz -= 2;
+
+       return 1;
+}
+
+static int escape_null(unsigned char c, char **dst, size_t *osz)
+{
+       char *out = *dst;
+
+       if (*osz < 2)
+               return -ENOMEM;
+
+       if (c)
+               return 0;
+
+       *out++ = '\\';
+       *out++ = '0';
+
+       *dst = out;
+       *osz -= 2;
+
+       return 1;
+}
+
+static int escape_octal(unsigned char c, char **dst, size_t *osz)
+{
+       char *out = *dst;
+
+       if (*osz < 4)
+               return -ENOMEM;
+
+       *out++ = '\\';
+       *out++ = ((c >> 6) & 0x07) + '0';
+       *out++ = ((c >> 3) & 0x07) + '0';
+       *out++ = ((c >> 0) & 0x07) + '0';
+
+       *dst = out;
+       *osz -= 4;
+
+       return 1;
+}
+
+static int escape_hex(unsigned char c, char **dst, size_t *osz)
+{
+       char *out = *dst;
+
+       if (*osz < 4)
+               return -ENOMEM;
+
+       *out++ = '\\';
+       *out++ = 'x';
+       *out++ = hex_asc_hi(c);
+       *out++ = hex_asc_lo(c);
+
+       *dst = out;
+       *osz -= 4;
+
+       return 1;
+}
+
+/**
+ * string_escape_mem - quote characters in the given memory buffer
+ * @src:       source buffer (unescaped)
+ * @isz:       source buffer size
+ * @dst:       destination buffer (escaped)
+ * @osz:       destination buffer size
+ * @flags:     combination of the flags (bitwise OR):
+ *     %ESCAPE_SPACE:
+ *             '\f' - form feed
+ *             '\n' - new line
+ *             '\r' - carriage return
+ *             '\t' - horizontal tab
+ *             '\v' - vertical tab
+ *     %ESCAPE_SPECIAL:
+ *             '\\' - backslash
+ *             '\a' - alert (BEL)
+ *             '\e' - escape
+ *     %ESCAPE_NULL:
+ *             '\0' - null
+ *     %ESCAPE_OCTAL:
+ *             '\NNN' - byte with octal value NNN (3 digits)
+ *     %ESCAPE_ANY:
+ *             all previous together
+ *     %ESCAPE_NP:
+ *             escape only non-printable characters (checked by isprint)
+ *     %ESCAPE_ANY_NP:
+ *             all previous together
+ *     %ESCAPE_HEX:
+ *             '\xHH' - byte with hexadecimal value HH (2 digits)
+ * @esc:       NULL-terminated string of characters any of which, if found in
+ *             the source, has to be escaped
+ *
+ * Description:
+ * The process of escaping byte buffer includes several parts. They are applied
+ * in the following sequence.
+ *     1. The character is matched to the printable class, if asked, and in
+ *        case of match it passes through to the output.
+ *     2. The character is not matched to the one from @esc string and thus
+ *        must go as is to the output.
+ *     3. The character is checked if it falls into the class given by @flags.
+ *        %ESCAPE_OCTAL and %ESCAPE_HEX are going last since they cover any
+ *        character. Note that they actually can't go together, otherwise
+ *        %ESCAPE_HEX will be ignored.
+ *
+ * Caller must provide valid source and destination pointers. Be aware that
+ * destination buffer will not be NULL-terminated, thus caller have to append
+ * it if needs.
+ *
+ * Return:
+ * The amount of the characters processed to the destination buffer, or
+ * %-ENOMEM if the size of buffer is not enough to put an escaped character is
+ * returned.
+ *
+ * Even in the case of error @dst pointer will be updated to point to the byte
+ * after the last processed character.
+ */
+int string_escape_mem(const char *src, size_t isz, char **dst, size_t osz,
+                     unsigned int flags, const char *esc)
+{
+       char *out = *dst, *p = out;
+       bool is_dict = esc && *esc;
+       int ret = 0;
+
+       while (isz--) {
+               unsigned char c = *src++;
+
+               /*
+                * Apply rules in the following sequence:
+                *      - the character is printable, when @flags has
+                *        %ESCAPE_NP bit set
+                *      - the @esc string is supplied and does not contain a
+                *        character under question
+                *      - the character doesn't fall into a class of symbols
+                *        defined by given @flags
+                * In these cases we just pass through a character to the
+                * output buffer.
+                */
+               if ((flags & ESCAPE_NP && isprint(c)) ||
+                   (is_dict && !strchr(esc, c))) {
+                       /* do nothing */
+               } else {
+                       if (flags & ESCAPE_SPACE) {
+                               ret = escape_space(c, &p, &osz);
+                               if (ret < 0)
+                                       break;
+                               if (ret > 0)
+                                       continue;
+                       }
+
+                       if (flags & ESCAPE_SPECIAL) {
+                               ret = escape_special(c, &p, &osz);
+                               if (ret < 0)
+                                       break;
+                               if (ret > 0)
+                                       continue;
+                       }
+
+                       if (flags & ESCAPE_NULL) {
+                               ret = escape_null(c, &p, &osz);
+                               if (ret < 0)
+                                       break;
+                               if (ret > 0)
+                                       continue;
+                       }
+
+                       /* ESCAPE_OCTAL and ESCAPE_HEX always go last */
+                       if (flags & ESCAPE_OCTAL) {
+                               ret = escape_octal(c, &p, &osz);
+                               if (ret < 0)
+                                       break;
+                               continue;
+                       }
+                       if (flags & ESCAPE_HEX) {
+                               ret = escape_hex(c, &p, &osz);
+                               if (ret < 0)
+                                       break;
+                               continue;
+                       }
+               }
+
+               ret = escape_passthrough(c, &p, &osz);
+               if (ret < 0)
+                       break;
+       }
+
+       *dst = p;
+
+       if (ret < 0)
+               return ret;
+
+       return p - out;
+}
+EXPORT_SYMBOL(string_escape_mem);
index 6ac48de04c0e57ea9be72a4344fc767df2649c48..ab0d30e1e18fca244f9e2e1749b8d38de10fe6aa 100644 (file)
@@ -5,11 +5,32 @@
 
 #include <linux/init.h>
 #include <linux/kernel.h>
+#include <linux/slab.h>
 #include <linux/module.h>
 #include <linux/random.h>
 #include <linux/string.h>
 #include <linux/string_helpers.h>
 
+static __init bool test_string_check_buf(const char *name, unsigned int flags,
+                                        char *in, size_t p,
+                                        char *out_real, size_t q_real,
+                                        char *out_test, size_t q_test)
+{
+       if (q_real == q_test && !memcmp(out_test, out_real, q_test))
+               return true;
+
+       pr_warn("Test '%s' failed: flags = %u\n", name, flags);
+
+       print_hex_dump(KERN_WARNING, "Input: ", DUMP_PREFIX_NONE, 16, 1,
+                      in, p, true);
+       print_hex_dump(KERN_WARNING, "Expected: ", DUMP_PREFIX_NONE, 16, 1,
+                      out_test, q_test, true);
+       print_hex_dump(KERN_WARNING, "Got: ", DUMP_PREFIX_NONE, 16, 1,
+                      out_real, q_real, true);
+
+       return false;
+}
+
 struct test_string {
        const char *in;
        const char *out;
@@ -39,12 +60,17 @@ static const struct test_string strings[] __initconst = {
        },
 };
 
-static void __init test_string_unescape(unsigned int flags, bool inplace)
+static void __init test_string_unescape(const char *name, unsigned int flags,
+                                       bool inplace)
 {
-       char in[256];
-       char out_test[256];
-       char out_real[256];
-       int i, p = 0, q_test = 0, q_real = sizeof(out_real);
+       int q_real = 256;
+       char *in = kmalloc(q_real, GFP_KERNEL);
+       char *out_test = kmalloc(q_real, GFP_KERNEL);
+       char *out_real = kmalloc(q_real, GFP_KERNEL);
+       int i, p = 0, q_test = 0;
+
+       if (!in || !out_test || !out_real)
+               goto out;
 
        for (i = 0; i < ARRAY_SIZE(strings); i++) {
                const char *s = strings[i].in;
@@ -77,15 +103,225 @@ static void __init test_string_unescape(unsigned int flags, bool inplace)
                q_real = string_unescape(in, out_real, q_real, flags);
        }
 
-       if (q_real != q_test || memcmp(out_test, out_real, q_test)) {
-               pr_warn("Test failed: flags = %u\n", flags);
-               print_hex_dump(KERN_WARNING, "Input: ",
-                              DUMP_PREFIX_NONE, 16, 1, in, p - 1, true);
-               print_hex_dump(KERN_WARNING, "Expected: ",
-                              DUMP_PREFIX_NONE, 16, 1, out_test, q_test, true);
-               print_hex_dump(KERN_WARNING, "Got: ",
-                              DUMP_PREFIX_NONE, 16, 1, out_real, q_real, true);
+       test_string_check_buf(name, flags, in, p - 1, out_real, q_real,
+                             out_test, q_test);
+out:
+       kfree(out_real);
+       kfree(out_test);
+       kfree(in);
+}
+
+struct test_string_1 {
+       const char *out;
+       unsigned int flags;
+};
+
+#define        TEST_STRING_2_MAX_S1            32
+struct test_string_2 {
+       const char *in;
+       struct test_string_1 s1[TEST_STRING_2_MAX_S1];
+};
+
+#define        TEST_STRING_2_DICT_0            NULL
+static const struct test_string_2 escape0[] __initconst = {{
+       .in = "\f\\ \n\r\t\v",
+       .s1 = {{
+               .out = "\\f\\ \\n\\r\\t\\v",
+               .flags = ESCAPE_SPACE,
+       },{
+               .out = "\\f\\134\\040\\n\\r\\t\\v",
+               .flags = ESCAPE_SPACE | ESCAPE_OCTAL,
+       },{
+               .out = "\\f\\x5c\\x20\\n\\r\\t\\v",
+               .flags = ESCAPE_SPACE | ESCAPE_HEX,
+       },{
+               /* terminator */
+       }},
+},{
+       .in = "\\h\\\"\a\e\\",
+       .s1 = {{
+               .out = "\\\\h\\\\\"\\a\\e\\\\",
+               .flags = ESCAPE_SPECIAL,
+       },{
+               .out = "\\\\\\150\\\\\\042\\a\\e\\\\",
+               .flags = ESCAPE_SPECIAL | ESCAPE_OCTAL,
+       },{
+               .out = "\\\\\\x68\\\\\\x22\\a\\e\\\\",
+               .flags = ESCAPE_SPECIAL | ESCAPE_HEX,
+       },{
+               /* terminator */
+       }},
+},{
+       .in = "\eb \\C\007\"\x90\r]",
+       .s1 = {{
+               .out = "\eb \\C\007\"\x90\\r]",
+               .flags = ESCAPE_SPACE,
+       },{
+               .out = "\\eb \\\\C\\a\"\x90\r]",
+               .flags = ESCAPE_SPECIAL,
+       },{
+               .out = "\\eb \\\\C\\a\"\x90\\r]",
+               .flags = ESCAPE_SPACE | ESCAPE_SPECIAL,
+       },{
+               .out = "\\033\\142\\040\\134\\103\\007\\042\\220\\015\\135",
+               .flags = ESCAPE_OCTAL,
+       },{
+               .out = "\\033\\142\\040\\134\\103\\007\\042\\220\\r\\135",
+               .flags = ESCAPE_SPACE | ESCAPE_OCTAL,
+       },{
+               .out = "\\e\\142\\040\\\\\\103\\a\\042\\220\\015\\135",
+               .flags = ESCAPE_SPECIAL | ESCAPE_OCTAL,
+       },{
+               .out = "\\e\\142\\040\\\\\\103\\a\\042\\220\\r\\135",
+               .flags = ESCAPE_SPACE | ESCAPE_SPECIAL | ESCAPE_OCTAL,
+       },{
+               .out = "\eb \\C\007\"\x90\r]",
+               .flags = ESCAPE_NP,
+       },{
+               .out = "\eb \\C\007\"\x90\\r]",
+               .flags = ESCAPE_SPACE | ESCAPE_NP,
+       },{
+               .out = "\\eb \\C\\a\"\x90\r]",
+               .flags = ESCAPE_SPECIAL | ESCAPE_NP,
+       },{
+               .out = "\\eb \\C\\a\"\x90\\r]",
+               .flags = ESCAPE_SPACE | ESCAPE_SPECIAL | ESCAPE_NP,
+       },{
+               .out = "\\033b \\C\\007\"\\220\\015]",
+               .flags = ESCAPE_OCTAL | ESCAPE_NP,
+       },{
+               .out = "\\033b \\C\\007\"\\220\\r]",
+               .flags = ESCAPE_SPACE | ESCAPE_OCTAL | ESCAPE_NP,
+       },{
+               .out = "\\eb \\C\\a\"\\220\\r]",
+               .flags = ESCAPE_SPECIAL | ESCAPE_SPACE | ESCAPE_OCTAL |
+                        ESCAPE_NP,
+       },{
+               .out = "\\x1bb \\C\\x07\"\\x90\\x0d]",
+               .flags = ESCAPE_NP | ESCAPE_HEX,
+       },{
+               /* terminator */
+       }},
+},{
+       /* terminator */
+}};
+
+#define        TEST_STRING_2_DICT_1            "b\\ \t\r"
+static const struct test_string_2 escape1[] __initconst = {{
+       .in = "\f\\ \n\r\t\v",
+       .s1 = {{
+               .out = "\f\\134\\040\n\\015\\011\v",
+               .flags = ESCAPE_OCTAL,
+       },{
+               .out = "\f\\x5c\\x20\n\\x0d\\x09\v",
+               .flags = ESCAPE_HEX,
+       },{
+               /* terminator */
+       }},
+},{
+       .in = "\\h\\\"\a\e\\",
+       .s1 = {{
+               .out = "\\134h\\134\"\a\e\\134",
+               .flags = ESCAPE_OCTAL,
+       },{
+               /* terminator */
+       }},
+},{
+       .in = "\eb \\C\007\"\x90\r]",
+       .s1 = {{
+               .out = "\e\\142\\040\\134C\007\"\x90\\015]",
+               .flags = ESCAPE_OCTAL,
+       },{
+               /* terminator */
+       }},
+},{
+       /* terminator */
+}};
+
+static __init const char *test_string_find_match(const struct test_string_2 *s2,
+                                                unsigned int flags)
+{
+       const struct test_string_1 *s1 = s2->s1;
+       unsigned int i;
+
+       if (!flags)
+               return s2->in;
+
+       /* Test cases are NULL-aware */
+       flags &= ~ESCAPE_NULL;
+
+       /* ESCAPE_OCTAL has a higher priority */
+       if (flags & ESCAPE_OCTAL)
+               flags &= ~ESCAPE_HEX;
+
+       for (i = 0; i < TEST_STRING_2_MAX_S1 && s1->out; i++, s1++)
+               if (s1->flags == flags)
+                       return s1->out;
+       return NULL;
+}
+
+static __init void test_string_escape(const char *name,
+                                     const struct test_string_2 *s2,
+                                     unsigned int flags, const char *esc)
+{
+       int q_real = 512;
+       char *out_test = kmalloc(q_real, GFP_KERNEL);
+       char *out_real = kmalloc(q_real, GFP_KERNEL);
+       char *in = kmalloc(256, GFP_KERNEL);
+       char *buf = out_real;
+       int p = 0, q_test = 0;
+
+       if (!out_test || !out_real || !in)
+               goto out;
+
+       for (; s2->in; s2++) {
+               const char *out;
+               int len;
+
+               /* NULL injection */
+               if (flags & ESCAPE_NULL) {
+                       in[p++] = '\0';
+                       out_test[q_test++] = '\\';
+                       out_test[q_test++] = '0';
+               }
+
+               /* Don't try strings that have no output */
+               out = test_string_find_match(s2, flags);
+               if (!out)
+                       continue;
+
+               /* Copy string to in buffer */
+               len = strlen(s2->in);
+               memcpy(&in[p], s2->in, len);
+               p += len;
+
+               /* Copy expected result for given flags */
+               len = strlen(out);
+               memcpy(&out_test[q_test], out, len);
+               q_test += len;
        }
+
+       q_real = string_escape_mem(in, p, &buf, q_real, flags, esc);
+
+       test_string_check_buf(name, flags, in, p, out_real, q_real, out_test,
+                             q_test);
+out:
+       kfree(in);
+       kfree(out_real);
+       kfree(out_test);
+}
+
+static __init void test_string_escape_nomem(void)
+{
+       char *in = "\eb \\C\007\"\x90\r]";
+       char out[64], *buf = out;
+       int rc = -ENOMEM, ret;
+
+       ret = string_escape_str_any_np(in, &buf, strlen(in), NULL);
+       if (ret == rc)
+               return;
+
+       pr_err("Test 'escape nomem' failed: got %d instead of %d\n", ret, rc);
 }
 
 static int __init test_string_helpers_init(void)
@@ -94,8 +330,19 @@ static int __init test_string_helpers_init(void)
 
        pr_info("Running tests...\n");
        for (i = 0; i < UNESCAPE_ANY + 1; i++)
-               test_string_unescape(i, false);
-       test_string_unescape(get_random_int() % (UNESCAPE_ANY + 1), true);
+               test_string_unescape("unescape", i, false);
+       test_string_unescape("unescape inplace",
+                            get_random_int() % (UNESCAPE_ANY + 1), true);
+
+       /* Without dictionary */
+       for (i = 0; i < (ESCAPE_ANY_NP | ESCAPE_HEX) + 1; i++)
+               test_string_escape("escape 0", escape0, i, TEST_STRING_2_DICT_0);
+
+       /* With dictionary */
+       for (i = 0; i < (ESCAPE_ANY_NP | ESCAPE_HEX) + 1; i++)
+               test_string_escape("escape 1", escape1, i, TEST_STRING_2_DICT_1);
+
+       test_string_escape_nomem();
 
        return -EINVAL;
 }
index 0c7e9ab2d88f79e99c434703b7d9e0e6fa9edcfb..0b79908dfe892e5bc635408538a8049c844a2888 100644 (file)
@@ -249,9 +249,7 @@ EXPORT_SYMBOL(textsearch_find_continuous);
  * @flags: search flags
  *
  * Looks up the search algorithm module and creates a new textsearch
- * configuration for the specified pattern. Upon completion all
- * necessary refcnts are held and the configuration must be put back
- * using textsearch_put() after usage.
+ * configuration for the specified pattern.
  *
  * Note: The format of the pattern may not be compatible between
  *       the various search algorithms.
index ba3cd0a35640db2672970612fa644c3aab70633d..ec337f64f52ddada251c9126561e5e38a38093e5 100644 (file)
@@ -33,6 +33,7 @@
 #include <asm/page.h>          /* for PAGE_SIZE */
 #include <asm/sections.h>      /* for dereference_function_descriptor() */
 
+#include <linux/string_helpers.h>
 #include "kstrtox.h"
 
 /**
@@ -1100,6 +1101,62 @@ char *ip4_addr_string_sa(char *buf, char *end, const struct sockaddr_in *sa,
        return string(buf, end, ip4_addr, spec);
 }
 
+static noinline_for_stack
+char *escaped_string(char *buf, char *end, u8 *addr, struct printf_spec spec,
+                    const char *fmt)
+{
+       bool found = true;
+       int count = 1;
+       unsigned int flags = 0;
+       int len;
+
+       if (spec.field_width == 0)
+               return buf;                             /* nothing to print */
+
+       if (ZERO_OR_NULL_PTR(addr))
+               return string(buf, end, NULL, spec);    /* NULL pointer */
+
+
+       do {
+               switch (fmt[count++]) {
+               case 'a':
+                       flags |= ESCAPE_ANY;
+                       break;
+               case 'c':
+                       flags |= ESCAPE_SPECIAL;
+                       break;
+               case 'h':
+                       flags |= ESCAPE_HEX;
+                       break;
+               case 'n':
+                       flags |= ESCAPE_NULL;
+                       break;
+               case 'o':
+                       flags |= ESCAPE_OCTAL;
+                       break;
+               case 'p':
+                       flags |= ESCAPE_NP;
+                       break;
+               case 's':
+                       flags |= ESCAPE_SPACE;
+                       break;
+               default:
+                       found = false;
+                       break;
+               }
+       } while (found);
+
+       if (!flags)
+               flags = ESCAPE_ANY_NP;
+
+       len = spec.field_width < 0 ? 1 : spec.field_width;
+
+       /* Ignore the error. We print as many characters as we can */
+       string_escape_mem(addr, len, &buf, end - buf, flags, NULL);
+
+       return buf;
+}
+
 static noinline_for_stack
 char *uuid_string(char *buf, char *end, const u8 *addr,
                  struct printf_spec spec, const char *fmt)
@@ -1221,6 +1278,17 @@ int kptr_restrict __read_mostly;
  * - '[Ii][4S][hnbl]' IPv4 addresses in host, network, big or little endian order
  * - 'I[6S]c' for IPv6 addresses printed as specified by
  *       http://tools.ietf.org/html/rfc5952
+ * - 'E[achnops]' For an escaped buffer, where rules are defined by combination
+ *                of the following flags (see string_escape_mem() for the
+ *                details):
+ *                  a - ESCAPE_ANY
+ *                  c - ESCAPE_SPECIAL
+ *                  h - ESCAPE_HEX
+ *                  n - ESCAPE_NULL
+ *                  o - ESCAPE_OCTAL
+ *                  p - ESCAPE_NP
+ *                  s - ESCAPE_SPACE
+ *                By default ESCAPE_ANY_NP is used.
  * - 'U' For a 16 byte UUID/GUID, it prints the UUID/GUID in the form
  *       "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
  *       Options for %pU are:
@@ -1321,6 +1389,8 @@ char *pointer(const char *fmt, char *buf, char *end, void *ptr,
                        }}
                }
                break;
+       case 'E':
+               return escaped_string(buf, end, ptr, spec, fmt);
        case 'U':
                return uuid_string(buf, end, ptr, spec, fmt);
        case 'V':
@@ -1633,6 +1703,7 @@ qualifier:
  * %piS depending on sa_family of 'struct sockaddr *' print IPv4/IPv6 address
  * %pU[bBlL] print a UUID/GUID in big or little endian using lower or upper
  *   case.
+ * %*pE[achnops] print an escaped buffer
  * %*ph[CDN] a variable-length hex string with a separator (supports up to 64
  *           bytes of the input)
  * %n is ignored
index 1f534a7f0a711396bab99d6399f2bc40898ae850..8405eb0023a918a30cc6109f404f8c1633beb9c4 100644 (file)
@@ -28,8 +28,9 @@ else
        obj-y           += bootmem.o
 endif
 
+obj-$(CONFIG_ADVISE_SYSCALLS)  += fadvise.o
 ifdef CONFIG_MMU
-       obj-$(CONFIG_ADVISE_SYSCALLS)   += fadvise.o madvise.o
+       obj-$(CONFIG_ADVISE_SYSCALLS)   += madvise.o
 endif
 obj-$(CONFIG_HAVE_MEMBLOCK) += memblock.o
 
index 474c644a0dc6deafea451935e6d44b72d5e1903e..963bc4add9af88838b494e6dd56b2bf2239548a2 100644 (file)
--- a/mm/cma.c
+++ b/mm/cma.c
@@ -58,7 +58,9 @@ unsigned long cma_get_size(struct cma *cma)
 
 static unsigned long cma_bitmap_aligned_mask(struct cma *cma, int align_order)
 {
-       return (1UL << (align_order >> cma->order_per_bit)) - 1;
+       if (align_order <= cma->order_per_bit)
+               return 0;
+       return (1UL << (align_order - cma->order_per_bit)) - 1;
 }
 
 static unsigned long cma_bitmap_maxno(struct cma *cma)
@@ -140,6 +142,54 @@ static int __init cma_init_reserved_areas(void)
 }
 core_initcall(cma_init_reserved_areas);
 
+/**
+ * cma_init_reserved_mem() - create custom contiguous area from reserved memory
+ * @base: Base address of the reserved area
+ * @size: Size of the reserved area (in bytes),
+ * @order_per_bit: Order of pages represented by one bit on bitmap.
+ * @res_cma: Pointer to store the created cma region.
+ *
+ * This function creates custom contiguous area from already reserved memory.
+ */
+int __init cma_init_reserved_mem(phys_addr_t base, phys_addr_t size,
+                                int order_per_bit, struct cma **res_cma)
+{
+       struct cma *cma;
+       phys_addr_t alignment;
+
+       /* Sanity checks */
+       if (cma_area_count == ARRAY_SIZE(cma_areas)) {
+               pr_err("Not enough slots for CMA reserved regions!\n");
+               return -ENOSPC;
+       }
+
+       if (!size || !memblock_is_region_reserved(base, size))
+               return -EINVAL;
+
+       /* ensure minimal alignment requied by mm core */
+       alignment = PAGE_SIZE << max(MAX_ORDER - 1, pageblock_order);
+
+       /* alignment should be aligned with order_per_bit */
+       if (!IS_ALIGNED(alignment >> PAGE_SHIFT, 1 << order_per_bit))
+               return -EINVAL;
+
+       if (ALIGN(base, alignment) != base || ALIGN(size, alignment) != size)
+               return -EINVAL;
+
+       /*
+        * Each reserved area must be initialised later, when more kernel
+        * subsystems (like slab allocator) are available.
+        */
+       cma = &cma_areas[cma_area_count];
+       cma->base_pfn = PFN_DOWN(base);
+       cma->count = size >> PAGE_SHIFT;
+       cma->order_per_bit = order_per_bit;
+       *res_cma = cma;
+       cma_area_count++;
+
+       return 0;
+}
+
 /**
  * cma_declare_contiguous() - reserve custom contiguous area
  * @base: Base address of the reserved area optional, use 0 for any
@@ -163,7 +213,6 @@ int __init cma_declare_contiguous(phys_addr_t base,
                        phys_addr_t alignment, unsigned int order_per_bit,
                        bool fixed, struct cma **res_cma)
 {
-       struct cma *cma;
        phys_addr_t memblock_end = memblock_end_of_DRAM();
        phys_addr_t highmem_start = __pa(high_memory);
        int ret = 0;
@@ -235,16 +284,9 @@ int __init cma_declare_contiguous(phys_addr_t base,
                }
        }
 
-       /*
-        * Each reserved area must be initialised later, when more kernel
-        * subsystems (like slab allocator) are available.
-        */
-       cma = &cma_areas[cma_area_count];
-       cma->base_pfn = PFN_DOWN(base);
-       cma->count = size >> PAGE_SHIFT;
-       cma->order_per_bit = order_per_bit;
-       *res_cma = cma;
-       cma_area_count++;
+       ret = cma_init_reserved_mem(base, size, order_per_bit, res_cma);
+       if (ret)
+               goto err;
 
        pr_info("Reserved %ld MiB at %08lx\n", (unsigned long)size / SZ_1M,
                (unsigned long)base);
index 9a09f2034fcc53a2733d931f33e82d7c3d79fa97..eafcf60f6b832b202a48f8a9ba66ac0d87989443 100644 (file)
@@ -4,6 +4,96 @@
 #include <linux/slab.h>
 #include <linux/vmalloc.h>
 
+static size_t copy_to_iter_iovec(void *from, size_t bytes, struct iov_iter *i)
+{
+       size_t skip, copy, left, wanted;
+       const struct iovec *iov;
+       char __user *buf;
+
+       if (unlikely(bytes > i->count))
+               bytes = i->count;
+
+       if (unlikely(!bytes))
+               return 0;
+
+       wanted = bytes;
+       iov = i->iov;
+       skip = i->iov_offset;
+       buf = iov->iov_base + skip;
+       copy = min(bytes, iov->iov_len - skip);
+
+       left = __copy_to_user(buf, from, copy);
+       copy -= left;
+       skip += copy;
+       from += copy;
+       bytes -= copy;
+       while (unlikely(!left && bytes)) {
+               iov++;
+               buf = iov->iov_base;
+               copy = min(bytes, iov->iov_len);
+               left = __copy_to_user(buf, from, copy);
+               copy -= left;
+               skip = copy;
+               from += copy;
+               bytes -= copy;
+       }
+
+       if (skip == iov->iov_len) {
+               iov++;
+               skip = 0;
+       }
+       i->count -= wanted - bytes;
+       i->nr_segs -= iov - i->iov;
+       i->iov = iov;
+       i->iov_offset = skip;
+       return wanted - bytes;
+}
+
+static size_t copy_from_iter_iovec(void *to, size_t bytes, struct iov_iter *i)
+{
+       size_t skip, copy, left, wanted;
+       const struct iovec *iov;
+       char __user *buf;
+
+       if (unlikely(bytes > i->count))
+               bytes = i->count;
+
+       if (unlikely(!bytes))
+               return 0;
+
+       wanted = bytes;
+       iov = i->iov;
+       skip = i->iov_offset;
+       buf = iov->iov_base + skip;
+       copy = min(bytes, iov->iov_len - skip);
+
+       left = __copy_from_user(to, buf, copy);
+       copy -= left;
+       skip += copy;
+       to += copy;
+       bytes -= copy;
+       while (unlikely(!left && bytes)) {
+               iov++;
+               buf = iov->iov_base;
+               copy = min(bytes, iov->iov_len);
+               left = __copy_from_user(to, buf, copy);
+               copy -= left;
+               skip = copy;
+               to += copy;
+               bytes -= copy;
+       }
+
+       if (skip == iov->iov_len) {
+               iov++;
+               skip = 0;
+       }
+       i->count -= wanted - bytes;
+       i->nr_segs -= iov - i->iov;
+       i->iov = iov;
+       i->iov_offset = skip;
+       return wanted - bytes;
+}
+
 static size_t copy_page_to_iter_iovec(struct page *page, size_t offset, size_t bytes,
                         struct iov_iter *i)
 {
@@ -166,6 +256,50 @@ done:
        return wanted - bytes;
 }
 
+static size_t zero_iovec(size_t bytes, struct iov_iter *i)
+{
+       size_t skip, copy, left, wanted;
+       const struct iovec *iov;
+       char __user *buf;
+
+       if (unlikely(bytes > i->count))
+               bytes = i->count;
+
+       if (unlikely(!bytes))
+               return 0;
+
+       wanted = bytes;
+       iov = i->iov;
+       skip = i->iov_offset;
+       buf = iov->iov_base + skip;
+       copy = min(bytes, iov->iov_len - skip);
+
+       left = __clear_user(buf, copy);
+       copy -= left;
+       skip += copy;
+       bytes -= copy;
+
+       while (unlikely(!left && bytes)) {
+               iov++;
+               buf = iov->iov_base;
+               copy = min(bytes, iov->iov_len);
+               left = __clear_user(buf, copy);
+               copy -= left;
+               skip = copy;
+               bytes -= copy;
+       }
+
+       if (skip == iov->iov_len) {
+               iov++;
+               skip = 0;
+       }
+       i->count -= wanted - bytes;
+       i->nr_segs -= iov - i->iov;
+       i->iov = iov;
+       i->iov_offset = skip;
+       return wanted - bytes;
+}
+
 static size_t __iovec_copy_from_user_inatomic(char *vaddr,
                        const struct iovec *iov, size_t base, size_t bytes)
 {
@@ -414,12 +548,17 @@ static void memcpy_to_page(struct page *page, size_t offset, char *from, size_t
        kunmap_atomic(to);
 }
 
-static size_t copy_page_to_iter_bvec(struct page *page, size_t offset, size_t bytes,
-                        struct iov_iter *i)
+static void memzero_page(struct page *page, size_t offset, size_t len)
+{
+       char *addr = kmap_atomic(page);
+       memset(addr + offset, 0, len);
+       kunmap_atomic(addr);
+}
+
+static size_t copy_to_iter_bvec(void *from, size_t bytes, struct iov_iter *i)
 {
        size_t skip, copy, wanted;
        const struct bio_vec *bvec;
-       void *kaddr, *from;
 
        if (unlikely(bytes > i->count))
                bytes = i->count;
@@ -432,8 +571,6 @@ static size_t copy_page_to_iter_bvec(struct page *page, size_t offset, size_t by
        skip = i->iov_offset;
        copy = min_t(size_t, bytes, bvec->bv_len - skip);
 
-       kaddr = kmap_atomic(page);
-       from = kaddr + offset;
        memcpy_to_page(bvec->bv_page, skip + bvec->bv_offset, from, copy);
        skip += copy;
        from += copy;
@@ -446,7 +583,6 @@ static size_t copy_page_to_iter_bvec(struct page *page, size_t offset, size_t by
                from += copy;
                bytes -= copy;
        }
-       kunmap_atomic(kaddr);
        if (skip == bvec->bv_len) {
                bvec++;
                skip = 0;
@@ -458,12 +594,10 @@ static size_t copy_page_to_iter_bvec(struct page *page, size_t offset, size_t by
        return wanted - bytes;
 }
 
-static size_t copy_page_from_iter_bvec(struct page *page, size_t offset, size_t bytes,
-                        struct iov_iter *i)
+static size_t copy_from_iter_bvec(void *to, size_t bytes, struct iov_iter *i)
 {
        size_t skip, copy, wanted;
        const struct bio_vec *bvec;
-       void *kaddr, *to;
 
        if (unlikely(bytes > i->count))
                bytes = i->count;
@@ -475,10 +609,6 @@ static size_t copy_page_from_iter_bvec(struct page *page, size_t offset, size_t
        bvec = i->bvec;
        skip = i->iov_offset;
 
-       kaddr = kmap_atomic(page);
-
-       to = kaddr + offset;
-
        copy = min(bytes, bvec->bv_len - skip);
 
        memcpy_from_page(to, bvec->bv_page, bvec->bv_offset + skip, copy);
@@ -495,7 +625,6 @@ static size_t copy_page_from_iter_bvec(struct page *page, size_t offset, size_t
                to += copy;
                bytes -= copy;
        }
-       kunmap_atomic(kaddr);
        if (skip == bvec->bv_len) {
                bvec++;
                skip = 0;
@@ -507,6 +636,61 @@ static size_t copy_page_from_iter_bvec(struct page *page, size_t offset, size_t
        return wanted;
 }
 
+static size_t copy_page_to_iter_bvec(struct page *page, size_t offset,
+                                       size_t bytes, struct iov_iter *i)
+{
+       void *kaddr = kmap_atomic(page);
+       size_t wanted = copy_to_iter_bvec(kaddr + offset, bytes, i);
+       kunmap_atomic(kaddr);
+       return wanted;
+}
+
+static size_t copy_page_from_iter_bvec(struct page *page, size_t offset,
+                                       size_t bytes, struct iov_iter *i)
+{
+       void *kaddr = kmap_atomic(page);
+       size_t wanted = copy_from_iter_bvec(kaddr + offset, bytes, i);
+       kunmap_atomic(kaddr);
+       return wanted;
+}
+
+static size_t zero_bvec(size_t bytes, struct iov_iter *i)
+{
+       size_t skip, copy, wanted;
+       const struct bio_vec *bvec;
+
+       if (unlikely(bytes > i->count))
+               bytes = i->count;
+
+       if (unlikely(!bytes))
+               return 0;
+
+       wanted = bytes;
+       bvec = i->bvec;
+       skip = i->iov_offset;
+       copy = min_t(size_t, bytes, bvec->bv_len - skip);
+
+       memzero_page(bvec->bv_page, skip + bvec->bv_offset, copy);
+       skip += copy;
+       bytes -= copy;
+       while (bytes) {
+               bvec++;
+               copy = min(bytes, (size_t)bvec->bv_len);
+               memzero_page(bvec->bv_page, bvec->bv_offset, copy);
+               skip = copy;
+               bytes -= copy;
+       }
+       if (skip == bvec->bv_len) {
+               bvec++;
+               skip = 0;
+       }
+       i->count -= wanted - bytes;
+       i->nr_segs -= bvec - i->bvec;
+       i->bvec = bvec;
+       i->iov_offset = skip;
+       return wanted - bytes;
+}
+
 static size_t copy_from_user_bvec(struct page *page,
                struct iov_iter *i, unsigned long offset, size_t bytes)
 {
@@ -672,6 +856,34 @@ size_t copy_page_from_iter(struct page *page, size_t offset, size_t bytes,
 }
 EXPORT_SYMBOL(copy_page_from_iter);
 
+size_t copy_to_iter(void *addr, size_t bytes, struct iov_iter *i)
+{
+       if (i->type & ITER_BVEC)
+               return copy_to_iter_bvec(addr, bytes, i);
+       else
+               return copy_to_iter_iovec(addr, bytes, i);
+}
+EXPORT_SYMBOL(copy_to_iter);
+
+size_t copy_from_iter(void *addr, size_t bytes, struct iov_iter *i)
+{
+       if (i->type & ITER_BVEC)
+               return copy_from_iter_bvec(addr, bytes, i);
+       else
+               return copy_from_iter_iovec(addr, bytes, i);
+}
+EXPORT_SYMBOL(copy_from_iter);
+
+size_t iov_iter_zero(size_t bytes, struct iov_iter *i)
+{
+       if (i->type & ITER_BVEC) {
+               return zero_bvec(bytes, i);
+       } else {
+               return zero_iovec(bytes, i);
+       }
+}
+EXPORT_SYMBOL(iov_iter_zero);
+
 size_t iov_iter_copy_from_user_atomic(struct page *page,
                struct iov_iter *i, unsigned long offset, size_t bytes)
 {
index e229970e4223ff02cb24b43b9e47e5ee211555d6..1cc6bfbd872ee17122b6e85859662696f595a363 100644 (file)
@@ -2053,7 +2053,8 @@ static int do_wp_page(struct mm_struct *mm, struct vm_area_struct *vma,
        old_page = vm_normal_page(vma, address, orig_pte);
        if (!old_page) {
                /*
-                * VM_MIXEDMAP !pfn_valid() case
+                * VM_MIXEDMAP !pfn_valid() case, or VM_SOFTDIRTY clear on a
+                * VM_PFNMAP VMA.
                 *
                 * We should not cow pages in a shared writeable mapping.
                 * Just mark the pages writable as we can't do any dirty
index 03aa8512723b3120277702d60e032031de0e425f..73cf0987088c36647fbb805278978bb656ff1fda 100644 (file)
@@ -789,7 +789,7 @@ static int do_mlockall(int flags)
 
                /* Ignore errors */
                mlock_fixup(vma, &prev, vma->vm_start, vma->vm_end, newflags);
-               cond_resched();
+               cond_resched_rcu_qs();
        }
 out:
        return 0;
index 93d28c7e54201de5549dab1a3dd696d785a06302..7f855206e7fb2bb1f9a30fcf7745bff7a2ae3adb 100644 (file)
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -89,6 +89,25 @@ pgprot_t vm_get_page_prot(unsigned long vm_flags)
 }
 EXPORT_SYMBOL(vm_get_page_prot);
 
+static pgprot_t vm_pgprot_modify(pgprot_t oldprot, unsigned long vm_flags)
+{
+       return pgprot_modify(oldprot, vm_get_page_prot(vm_flags));
+}
+
+/* Update vma->vm_page_prot to reflect vma->vm_flags. */
+void vma_set_page_prot(struct vm_area_struct *vma)
+{
+       unsigned long vm_flags = vma->vm_flags;
+
+       vma->vm_page_prot = vm_pgprot_modify(vma->vm_page_prot, vm_flags);
+       if (vma_wants_writenotify(vma)) {
+               vm_flags &= ~VM_SHARED;
+               vma->vm_page_prot = vm_pgprot_modify(vma->vm_page_prot,
+                                                    vm_flags);
+       }
+}
+
+
 int sysctl_overcommit_memory __read_mostly = OVERCOMMIT_GUESS;  /* heuristic overcommit */
 int sysctl_overcommit_ratio __read_mostly = 50;        /* default is 50% */
 unsigned long sysctl_overcommit_kbytes __read_mostly;
@@ -1475,11 +1494,16 @@ int vma_wants_writenotify(struct vm_area_struct *vma)
        if (vma->vm_ops && vma->vm_ops->page_mkwrite)
                return 1;
 
-       /* The open routine did something to the protections already? */
+       /* The open routine did something to the protections that pgprot_modify
+        * won't preserve? */
        if (pgprot_val(vma->vm_page_prot) !=
-           pgprot_val(vm_get_page_prot(vm_flags)))
+           pgprot_val(vm_pgprot_modify(vma->vm_page_prot, vm_flags)))
                return 0;
 
+       /* Do we need to track softdirty? */
+       if (IS_ENABLED(CONFIG_MEM_SOFT_DIRTY) && !(vm_flags & VM_SOFTDIRTY))
+               return 1;
+
        /* Specialty mapping? */
        if (vm_flags & VM_PFNMAP)
                return 0;
@@ -1615,21 +1639,6 @@ munmap_back:
                        goto free_vma;
        }
 
-       if (vma_wants_writenotify(vma)) {
-               pgprot_t pprot = vma->vm_page_prot;
-
-               /* Can vma->vm_page_prot have changed??
-                *
-                * Answer: Yes, drivers may have changed it in their
-                *         f_op->mmap method.
-                *
-                * Ensures that vmas marked as uncached stay that way.
-                */
-               vma->vm_page_prot = vm_get_page_prot(vm_flags & ~VM_SHARED);
-               if (pgprot_val(pprot) == pgprot_val(pgprot_noncached(pprot)))
-                       vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
-       }
-
        vma_link(mm, vma, prev, rb_link, rb_parent);
        /* Once vma denies write, undo our temporary denial count */
        if (file) {
@@ -1663,6 +1672,8 @@ out:
         */
        vma->vm_flags |= VM_SOFTDIRTY;
 
+       vma_set_page_prot(vma);
+
        return addr;
 
 unmap_and_free_vma:
index c43d557941f807471a3c39963f77a8ba3d32dd8a..ace93454ce8ebe10f0b3cf5278aafd0a0d5fe4df 100644 (file)
 #include <asm/cacheflush.h>
 #include <asm/tlbflush.h>
 
-#ifndef pgprot_modify
-static inline pgprot_t pgprot_modify(pgprot_t oldprot, pgprot_t newprot)
-{
-       return newprot;
-}
-#endif
-
 /*
  * For a prot_numa update we only hold mmap_sem for read so there is a
  * potential race with faulting where a pmd was temporarily none. This
@@ -93,7 +86,9 @@ static unsigned long change_pte_range(struct vm_area_struct *vma, pmd_t *pmd,
                                 * Avoid taking write faults for pages we
                                 * know to be dirty.
                                 */
-                               if (dirty_accountable && pte_dirty(ptent))
+                               if (dirty_accountable && pte_dirty(ptent) &&
+                                   (pte_soft_dirty(ptent) ||
+                                    !(vma->vm_flags & VM_SOFTDIRTY)))
                                        ptent = pte_mkwrite(ptent);
                                ptep_modify_prot_commit(mm, addr, pte, ptent);
                                updated = true;
@@ -320,13 +315,8 @@ success:
         * held in write mode.
         */
        vma->vm_flags = newflags;
-       vma->vm_page_prot = pgprot_modify(vma->vm_page_prot,
-                                         vm_get_page_prot(newflags));
-
-       if (vma_wants_writenotify(vma)) {
-               vma->vm_page_prot = vm_get_page_prot(newflags & ~VM_SHARED);
-               dirty_accountable = 1;
-       }
+       dirty_accountable = vma_wants_writenotify(vma);
+       vma_set_page_prot(vma);
 
        change_protection(vma, start, end, vma->vm_page_prot,
                          dirty_accountable, 0);
index c9710c9bbee2987569d6e56b5a2b9aea7e9d316a..736d8e1b63817fcd8c715f2081a4f44ba43c9be9 100644 (file)
@@ -4971,6 +4971,8 @@ void __paginginit free_area_init_node(int nid, unsigned long *zones_size,
        pgdat->node_start_pfn = node_start_pfn;
 #ifdef CONFIG_HAVE_MEMBLOCK_NODE_MAP
        get_pfn_range_for_nid(nid, &start_pfn, &end_pfn);
+       printk(KERN_INFO "Initmem setup node %d [mem %#010Lx-%#010Lx]\n", nid,
+                       (u64) start_pfn << PAGE_SHIFT, (u64) (end_pfn << PAGE_SHIFT) - 1);
 #endif
        calculate_node_totalpages(pgdat, start_pfn, end_pfn,
                                  zones_size, zholes_size);
index 154aac8411c592816891e4897408e509d9b24785..eb2b2ea301309887972c148bb80aedf8a6731b9b 100644 (file)
--- a/mm/slab.c
+++ b/mm/slab.c
@@ -1992,7 +1992,7 @@ static struct array_cache __percpu *alloc_kmem_cache_cpus(
        struct array_cache __percpu *cpu_cache;
 
        size = sizeof(void *) * entries + sizeof(struct array_cache);
-       cpu_cache = __alloc_percpu(size, 0);
+       cpu_cache = __alloc_percpu(size, sizeof(void *));
 
        if (!cpu_cache)
                return NULL;
index d6b138e2c263851d0164cc321794363a52cc6c77..6272420a721b0f01e15ffc572251a8f0794d5d8f 100644 (file)
@@ -6,6 +6,7 @@ menuconfig NET
        bool "Networking support"
        select NLATTR
        select GENERIC_NET_UTILS
+       select ANON_INODES
        ---help---
          Unless you really know what you are doing, you should say Y here.
          The reason is that some programs need kernel networking support even
index 6f5e621f220ae0d6c419cff55aa87094c12f59d0..88a1bc3804d148972761276b347e258873a1b59e 100644 (file)
@@ -44,10 +44,10 @@ static bool batadv_parse_gw_bandwidth(struct net_device *net_dev, char *buff,
        if (strlen(buff) > 4) {
                tmp_ptr = buff + strlen(buff) - 4;
 
-               if (strnicmp(tmp_ptr, "mbit", 4) == 0)
+               if (strncasecmp(tmp_ptr, "mbit", 4) == 0)
                        bw_unit_type = BATADV_BW_UNIT_MBIT;
 
-               if ((strnicmp(tmp_ptr, "kbit", 4) == 0) ||
+               if ((strncasecmp(tmp_ptr, "kbit", 4) == 0) ||
                    (bw_unit_type == BATADV_BW_UNIT_MBIT))
                        *tmp_ptr = '\0';
        }
@@ -77,10 +77,10 @@ static bool batadv_parse_gw_bandwidth(struct net_device *net_dev, char *buff,
                if (strlen(slash_ptr + 1) > 4) {
                        tmp_ptr = slash_ptr + 1 - 4 + strlen(slash_ptr + 1);
 
-                       if (strnicmp(tmp_ptr, "mbit", 4) == 0)
+                       if (strncasecmp(tmp_ptr, "mbit", 4) == 0)
                                bw_unit_type = BATADV_BW_UNIT_MBIT;
 
-                       if ((strnicmp(tmp_ptr, "kbit", 4) == 0) ||
+                       if ((strncasecmp(tmp_ptr, "kbit", 4) == 0) ||
                            (bw_unit_type == BATADV_BW_UNIT_MBIT))
                                *tmp_ptr = '\0';
                }
index ffeba8f9dda929df4f111a9ef652cf1830f348a9..62fc5e7a9acf7506eba2de7ae314ba6067870ceb 100644 (file)
@@ -476,7 +476,6 @@ struct key_type key_type_ceph = {
        .preparse       = ceph_key_preparse,
        .free_preparse  = ceph_key_free_preparse,
        .instantiate    = generic_key_instantiate,
-       .match          = user_match,
        .destroy        = ceph_key_destroy,
 };
 
index fcd3f6742a6aa192efaf179b0a656377c98c31ce..647b12265e181b3ab650670f5572caa8a0f802a6 100644 (file)
@@ -51,9 +51,9 @@
  *     @skb: buffer to filter
  *
  * Run the filter code and then cut skb->data to correct size returned by
- * sk_run_filter. If pkt_len is 0 we toss packet. If skb->len is smaller
+ * SK_RUN_FILTER. If pkt_len is 0 we toss packet. If skb->len is smaller
  * than pkt_len we keep whole skb->data. This is the socket level
- * wrapper to sk_run_filter. It returns 0 if the packet should
+ * wrapper to SK_RUN_FILTER. It returns 0 if the packet should
  * be accepted or -EPERM if the packet should be tossed.
  *
  */
@@ -565,12 +565,9 @@ err:
 }
 
 /* Security:
- *
- * A BPF program is able to use 16 cells of memory to store intermediate
- * values (check u32 mem[BPF_MEMWORDS] in sk_run_filter()).
  *
  * As we dont want to clear mem[] array for each packet going through
- * sk_run_filter(), we check that filter loaded by user never try to read
+ * __bpf_prog_run(), we check that filter loaded by user never try to read
  * a cell if not previously written, and we check all branches to be sure
  * a malicious user doesn't try to abuse us.
  */
index 8560dea58803f947842e0be44d10464fb54127f6..45084938c403b82b23d45ed66d9871348baeadc7 100644 (file)
@@ -100,6 +100,13 @@ ip:
                if (ip_is_fragment(iph))
                        ip_proto = 0;
 
+               /* skip the address processing if skb is NULL.  The assumption
+                * here is that if there is no skb we are not looking for flow
+                * info but lengths and protocols.
+                */
+               if (!skb)
+                       break;
+
                iph_to_flow_copy_addrs(flow, iph);
                break;
        }
@@ -114,17 +121,15 @@ ipv6:
                        return false;
 
                ip_proto = iph->nexthdr;
-               flow->src = (__force __be32)ipv6_addr_hash(&iph->saddr);
-               flow->dst = (__force __be32)ipv6_addr_hash(&iph->daddr);
                nhoff += sizeof(struct ipv6hdr);
 
-               /* skip the flow label processing if skb is NULL.  The
-                * assumption here is that if there is no skb we are not
-                * looking for flow info as much as we are length.
-                */
+               /* see comment above in IPv4 section */
                if (!skb)
                        break;
 
+               flow->src = (__force __be32)ipv6_addr_hash(&iph->saddr);
+               flow->dst = (__force __be32)ipv6_addr_hash(&iph->daddr);
+
                flow_label = ip6_flowlabel(iph);
                if (flow_label) {
                        /* Awesome, IPv6 packet has a flow label so we can
@@ -231,9 +236,13 @@ ipv6:
 
        flow->n_proto = proto;
        flow->ip_proto = ip_proto;
-       flow->ports = __skb_flow_get_ports(skb, nhoff, ip_proto, data, hlen);
        flow->thoff = (u16) nhoff;
 
+       /* unless skb is set we don't need to record port info */
+       if (skb)
+               flow->ports = __skb_flow_get_ports(skb, nhoff, ip_proto,
+                                                  data, hlen);
+
        return true;
 }
 EXPORT_SYMBOL(__skb_flow_dissect);
@@ -334,15 +343,16 @@ u32 __skb_get_poff(const struct sk_buff *skb, void *data,
 
        switch (keys->ip_proto) {
        case IPPROTO_TCP: {
-               const struct tcphdr *tcph;
-               struct tcphdr _tcph;
+               /* access doff as u8 to avoid unaligned access */
+               const u8 *doff;
+               u8 _doff;
 
-               tcph = __skb_header_pointer(skb, poff, sizeof(_tcph),
-                                           data, hlen, &_tcph);
-               if (!tcph)
+               doff = __skb_header_pointer(skb, poff + 12, sizeof(_doff),
+                                           data, hlen, &_doff);
+               if (!doff)
                        return poff;
 
-               poff += max_t(u32, sizeof(struct tcphdr), tcph->doff * 4);
+               poff += max_t(u32, sizeof(struct tcphdr), (*doff & 0xF0) >> 2);
                break;
        }
        case IPPROTO_UDP:
index 7b3df0d518abfa5da3440d614ce5fa9e65bb06e6..829d013745abf2940d923d192470a40fc19c5fd1 100644 (file)
@@ -360,18 +360,29 @@ refill:
                                goto end;
                }
                nc->frag.size = PAGE_SIZE << order;
-recycle:
-               atomic_set(&nc->frag.page->_count, NETDEV_PAGECNT_MAX_BIAS);
+               /* Even if we own the page, we do not use atomic_set().
+                * This would break get_page_unless_zero() users.
+                */
+               atomic_add(NETDEV_PAGECNT_MAX_BIAS - 1,
+                          &nc->frag.page->_count);
                nc->pagecnt_bias = NETDEV_PAGECNT_MAX_BIAS;
                nc->frag.offset = 0;
        }
 
        if (nc->frag.offset + fragsz > nc->frag.size) {
-               /* avoid unnecessary locked operations if possible */
-               if ((atomic_read(&nc->frag.page->_count) == nc->pagecnt_bias) ||
-                   atomic_sub_and_test(nc->pagecnt_bias, &nc->frag.page->_count))
-                       goto recycle;
-               goto refill;
+               if (atomic_read(&nc->frag.page->_count) != nc->pagecnt_bias) {
+                       if (!atomic_sub_and_test(nc->pagecnt_bias,
+                                                &nc->frag.page->_count))
+                               goto refill;
+                       /* OK, page count is 0, we can safely set it */
+                       atomic_set(&nc->frag.page->_count,
+                                  NETDEV_PAGECNT_MAX_BIAS);
+               } else {
+                       atomic_add(NETDEV_PAGECNT_MAX_BIAS - nc->pagecnt_bias,
+                                  &nc->frag.page->_count);
+               }
+               nc->pagecnt_bias = NETDEV_PAGECNT_MAX_BIAS;
+               nc->frag.offset = 0;
        }
 
        data = page_address(nc->frag.page) + nc->frag.offset;
@@ -4126,11 +4137,11 @@ EXPORT_SYMBOL(skb_vlan_untag);
 /**
  * alloc_skb_with_frags - allocate skb with page frags
  *
- * header_len: size of linear part
- * data_len: needed length in frags
- * max_page_order: max page order desired.
- * errcode: pointer to error code if any
- * gfp_mask: allocation mask
+ * @header_len: size of linear part
+ * @data_len: needed length in frags
+ * @max_page_order: max page order desired.
+ * @errcode: pointer to error code if any
+ * @gfp_mask: allocation mask
  *
  * This can be used to allocate a paged skb, given a maximal order for frags.
  */
index f380b2c581781433f2091fec38c7ad77f46f1fae..31cd4fd754869b8e621f0c5ecbfa5bca855684a7 100644 (file)
@@ -176,11 +176,11 @@ static void dns_resolver_free_preparse(struct key_preparsed_payload *prep)
  * The domain name may be a simple name or an absolute domain name (which
  * should end with a period).  The domain name is case-independent.
  */
-static int
-dns_resolver_match(const struct key *key, const void *description)
+static bool dns_resolver_cmp(const struct key *key,
+                            const struct key_match_data *match_data)
 {
        int slen, dlen, ret = 0;
-       const char *src = key->description, *dsp = description;
+       const char *src = key->description, *dsp = match_data->raw_data;
 
        kenter("%s,%s", src, dsp);
 
@@ -208,6 +208,16 @@ no_match:
        return ret;
 }
 
+/*
+ * Preparse the match criterion.
+ */
+static int dns_resolver_match_preparse(struct key_match_data *match_data)
+{
+       match_data->lookup_type = KEYRING_SEARCH_LOOKUP_ITERATE;
+       match_data->cmp = dns_resolver_cmp;
+       return 0;
+}
+
 /*
  * Describe a DNS key
  */
@@ -242,7 +252,7 @@ struct key_type key_type_dns_resolver = {
        .preparse       = dns_resolver_preparse,
        .free_preparse  = dns_resolver_free_preparse,
        .instantiate    = generic_key_instantiate,
-       .match          = dns_resolver_match,
+       .match_preparse = dns_resolver_match_preparse,
        .revoke         = user_revoke,
        .destroy        = user_destroy,
        .describe       = dns_resolver_describe,
index a64fa15790e53f8ad0eda7c53b73be8bd849f2aa..1d5341f3761dfe1e57cc6505493bf270cca672de 100644 (file)
@@ -96,13 +96,13 @@ static int ip_vs_ftp_get_addrport(char *data, char *data_limit,
 
        if (data_limit - data < plen) {
                /* check if there is partial match */
-               if (strnicmp(data, pattern, data_limit - data) == 0)
+               if (strncasecmp(data, pattern, data_limit - data) == 0)
                        return -1;
                else
                        return 0;
        }
 
-       if (strnicmp(data, pattern, plen) != 0) {
+       if (strncasecmp(data, pattern, plen) != 0) {
                return 0;
        }
        s = data + plen;
@@ -354,7 +354,7 @@ static int ip_vs_ftp_in(struct ip_vs_app *app, struct ip_vs_conn *cp,
        data_limit = skb_tail_pointer(skb);
 
        while (data <= data_limit - 6) {
-               if (strnicmp(data, "PASV\r\n", 6) == 0) {
+               if (strncasecmp(data, "PASV\r\n", 6) == 0) {
                        /* Passive mode on */
                        IP_VS_DBG(7, "got PASV at %td of %td\n",
                                  data - data_start,
index b8a0924064ef79abae8999e05d4622df961209c0..b666959f17c0856f8303fee7467a5e7cc4ff4962 100644 (file)
@@ -304,12 +304,12 @@ static int find_pattern(const char *data, size_t dlen,
 
        if (dlen <= plen) {
                /* Short packet: try for partial? */
-               if (strnicmp(data, pattern, dlen) == 0)
+               if (strncasecmp(data, pattern, dlen) == 0)
                        return -1;
                else return 0;
        }
 
-       if (strnicmp(data, pattern, plen) != 0) {
+       if (strncasecmp(data, pattern, plen) != 0) {
 #if 0
                size_t i;
 
index 4c3ba1c8d682d16abe0912f80525a84d184130db..885b4aba369565a8edcf6aaaead9b921d043d2b8 100644 (file)
@@ -247,7 +247,7 @@ int ct_sip_parse_request(const struct nf_conn *ct,
        for (; dptr < limit - strlen("sip:"); dptr++) {
                if (*dptr == '\r' || *dptr == '\n')
                        return -1;
-               if (strnicmp(dptr, "sip:", strlen("sip:")) == 0) {
+               if (strncasecmp(dptr, "sip:", strlen("sip:")) == 0) {
                        dptr += strlen("sip:");
                        break;
                }
@@ -350,7 +350,7 @@ static const char *ct_sip_header_search(const char *dptr, const char *limit,
                        continue;
                }
 
-               if (strnicmp(dptr, needle, len) == 0)
+               if (strncasecmp(dptr, needle, len) == 0)
                        return dptr;
        }
        return NULL;
@@ -383,10 +383,10 @@ int ct_sip_get_header(const struct nf_conn *ct, const char *dptr,
                /* Find header. Compact headers must be followed by a
                 * non-alphabetic character to avoid mismatches. */
                if (limit - dptr >= hdr->len &&
-                   strnicmp(dptr, hdr->name, hdr->len) == 0)
+                   strncasecmp(dptr, hdr->name, hdr->len) == 0)
                        dptr += hdr->len;
                else if (hdr->cname && limit - dptr >= hdr->clen + 1 &&
-                        strnicmp(dptr, hdr->cname, hdr->clen) == 0 &&
+                        strncasecmp(dptr, hdr->cname, hdr->clen) == 0 &&
                         !isalpha(*(dptr + hdr->clen)))
                        dptr += hdr->clen;
                else
@@ -620,9 +620,9 @@ static int ct_sip_parse_transport(struct nf_conn *ct, const char *dptr,
 
        if (ct_sip_parse_param(ct, dptr, dataoff, datalen, "transport=",
                               &matchoff, &matchlen)) {
-               if (!strnicmp(dptr + matchoff, "TCP", strlen("TCP")))
+               if (!strncasecmp(dptr + matchoff, "TCP", strlen("TCP")))
                        *proto = IPPROTO_TCP;
-               else if (!strnicmp(dptr + matchoff, "UDP", strlen("UDP")))
+               else if (!strncasecmp(dptr + matchoff, "UDP", strlen("UDP")))
                        *proto = IPPROTO_UDP;
                else
                        return 0;
@@ -743,10 +743,10 @@ int ct_sip_get_sdp_header(const struct nf_conn *ct, const char *dptr,
 
                if (term != SDP_HDR_UNSPEC &&
                    limit - dptr >= thdr->len &&
-                   strnicmp(dptr, thdr->name, thdr->len) == 0)
+                   strncasecmp(dptr, thdr->name, thdr->len) == 0)
                        break;
                else if (limit - dptr >= hdr->len &&
-                        strnicmp(dptr, hdr->name, hdr->len) == 0)
+                        strncasecmp(dptr, hdr->name, hdr->len) == 0)
                        dptr += hdr->len;
                else
                        continue;
@@ -1394,7 +1394,7 @@ static int process_sip_response(struct sk_buff *skb, unsigned int protoff,
                if (handler->response == NULL)
                        continue;
                if (*datalen < matchend + handler->len ||
-                   strnicmp(*dptr + matchend, handler->method, handler->len))
+                   strncasecmp(*dptr + matchend, handler->method, handler->len))
                        continue;
                return handler->response(skb, protoff, dataoff, dptr, datalen,
                                         cseq, code);
@@ -1435,7 +1435,7 @@ static int process_sip_request(struct sk_buff *skb, unsigned int protoff,
                if (handler->request == NULL)
                        continue;
                if (*datalen < handler->len ||
-                   strnicmp(*dptr, handler->method, handler->len))
+                   strncasecmp(*dptr, handler->method, handler->len))
                        continue;
 
                if (ct_sip_get_header(ct, *dptr, 0, *datalen, SIP_HDR_CSEQ,
@@ -1462,7 +1462,7 @@ static int process_sip_msg(struct sk_buff *skb, struct nf_conn *ct,
        const struct nf_nat_sip_hooks *hooks;
        int ret;
 
-       if (strnicmp(*dptr, "SIP/2.0 ", strlen("SIP/2.0 ")) != 0)
+       if (strncasecmp(*dptr, "SIP/2.0 ", strlen("SIP/2.0 ")) != 0)
                ret = process_sip_request(skb, protoff, dataoff, dptr, datalen);
        else
                ret = process_sip_response(skb, protoff, dataoff, dptr, datalen);
index daad6022c689c47a66a47e7a89a83c0c848c53d6..d7197649dba689bae96edb10848e8c1c3d4a63f6 100644 (file)
@@ -30,7 +30,7 @@ static struct nf_logger *__find_logger(int pf, const char *str_logger)
 
                log = rcu_dereference_protected(loggers[pf][i],
                                                lockdep_is_held(&nf_log_mutex));
-               if (!strnicmp(str_logger, log->name, strlen(log->name)))
+               if (!strncasecmp(str_logger, log->name, strlen(log->name)))
                        return log;
        }
 
index b4d691db955ed451954381e01baeed57ca588d11..791fac4fd74534e0481d409a182c2d5e5544deac 100644 (file)
@@ -155,7 +155,7 @@ static unsigned int nf_nat_sip(struct sk_buff *skb, unsigned int protoff,
        int request, in_header;
 
        /* Basic rules: requests and responses. */
-       if (strnicmp(*dptr, "SIP/2.0", strlen("SIP/2.0")) != 0) {
+       if (strncasecmp(*dptr, "SIP/2.0", strlen("SIP/2.0")) != 0) {
                if (ct_sip_parse_request(ct, *dptr, *datalen,
                                         &matchoff, &matchlen,
                                         &addr, &port) > 0 &&
index ec8a456092a73d7b8f92e92db46be986770a85e7..57d3e1af56305e90eade03e1fca1b38524091be6 100644 (file)
@@ -72,7 +72,7 @@ nla_put_failure:
 }
 EXPORT_SYMBOL_GPL(nft_reject_dump);
 
-static u8 icmp_code_v4[NFT_REJECT_ICMPX_MAX] = {
+static u8 icmp_code_v4[NFT_REJECT_ICMPX_MAX + 1] = {
        [NFT_REJECT_ICMPX_NO_ROUTE]             = ICMP_NET_UNREACH,
        [NFT_REJECT_ICMPX_PORT_UNREACH]         = ICMP_PORT_UNREACH,
        [NFT_REJECT_ICMPX_HOST_UNREACH]         = ICMP_HOST_UNREACH,
@@ -81,8 +81,7 @@ static u8 icmp_code_v4[NFT_REJECT_ICMPX_MAX] = {
 
 int nft_reject_icmp_code(u8 code)
 {
-       if (code > NFT_REJECT_ICMPX_MAX)
-               return -EINVAL;
+       BUG_ON(code > NFT_REJECT_ICMPX_MAX);
 
        return icmp_code_v4[code];
 }
@@ -90,7 +89,7 @@ int nft_reject_icmp_code(u8 code)
 EXPORT_SYMBOL_GPL(nft_reject_icmp_code);
 
 
-static u8 icmp_code_v6[NFT_REJECT_ICMPX_MAX] = {
+static u8 icmp_code_v6[NFT_REJECT_ICMPX_MAX + 1] = {
        [NFT_REJECT_ICMPX_NO_ROUTE]             = ICMPV6_NOROUTE,
        [NFT_REJECT_ICMPX_PORT_UNREACH]         = ICMPV6_PORT_UNREACH,
        [NFT_REJECT_ICMPX_HOST_UNREACH]         = ICMPV6_ADDR_UNREACH,
@@ -99,8 +98,7 @@ static u8 icmp_code_v6[NFT_REJECT_ICMPX_MAX] = {
 
 int nft_reject_icmpv6_code(u8 code)
 {
-       if (code > NFT_REJECT_ICMPX_MAX)
-               return -EINVAL;
+       BUG_ON(code > NFT_REJECT_ICMPX_MAX);
 
        return icmp_code_v6[code];
 }
index 0b4692dd1c5e33cae9dd1bdf28ffbf36437e103b..a845cd4cf21e5ffda8380c1142e046edd15990a6 100644 (file)
@@ -246,7 +246,6 @@ int netlbl_cfg_unlbl_static_add(struct net *net,
  * @addr: IP address in network byte order (struct in[6]_addr)
  * @mask: address mask in network byte order (struct in[6]_addr)
  * @family: address family
- * @secid: LSM secid value for the entry
  * @audit_info: NetLabel audit information
  *
  * Description:
index c416725d28c49f8b0c1b10bbf35a28594c646bc5..7a186e74b1b3533b936e0868ff49187321215386 100644 (file)
@@ -715,7 +715,7 @@ static int netlink_mmap_sendmsg(struct sock *sk, struct msghdr *msg,
         * after validation, the socket and the ring may only be used by a
         * single process, otherwise we fall back to copying.
         */
-       if (atomic_long_read(&sk->sk_socket->file->f_count) > 2 ||
+       if (atomic_long_read(&sk->sk_socket->file->f_count) > 1 ||
            atomic_read(&nlk->mapped) > 1)
                excl = false;
 
index b3b16c070a7fae95c6bc5a5bdd087ce436476c5a..fa7cd792791cbbd5234de865a53330daedb834db 100644 (file)
@@ -329,7 +329,7 @@ static atomic_t rfkill_input_disabled = ATOMIC_INIT(0);
 /**
  * __rfkill_switch_all - Toggle state of all switches of given type
  * @type: type of interfaces to be affected
- * @state: the new state
+ * @blocked: the new state
  *
  * This function sets the state of all switches of given type,
  * unless a specific switch is claimed by userspace (in which case,
@@ -353,7 +353,7 @@ static void __rfkill_switch_all(const enum rfkill_type type, bool blocked)
 /**
  * rfkill_switch_all - Toggle state of all switches of given type
  * @type: type of interfaces to be affected
- * @state: the new state
+ * @blocked: the new state
  *
  * Acquires rfkill_global_mutex and calls __rfkill_switch_all(@type, @state).
  * Please refer to __rfkill_switch_all() for details.
index 1b24191167f1f5de119271f05a3f7f6dcfb5e376..db0f39f5ef96dcff51e10f09f6eebf4490be8d1e 100644 (file)
@@ -44,7 +44,6 @@ struct key_type key_type_rxrpc = {
        .preparse       = rxrpc_preparse,
        .free_preparse  = rxrpc_free_preparse,
        .instantiate    = generic_key_instantiate,
-       .match          = user_match,
        .destroy        = rxrpc_destroy,
        .describe       = rxrpc_describe,
        .read           = rxrpc_read,
@@ -61,7 +60,6 @@ struct key_type key_type_rxrpc_s = {
        .preparse       = rxrpc_preparse_s,
        .free_preparse  = rxrpc_free_preparse_s,
        .instantiate    = generic_key_instantiate,
-       .match          = user_match,
        .destroy        = rxrpc_destroy_s,
        .describe       = rxrpc_describe,
 };
index 38d58e6cef07a06663312965059b08c31e2189fd..6efca30894aad4294824d2ba64f732239a921517 100644 (file)
@@ -57,7 +57,8 @@ static inline int dev_requeue_skb(struct sk_buff *skb, struct Qdisc *q)
 
 static void try_bulk_dequeue_skb(struct Qdisc *q,
                                 struct sk_buff *skb,
-                                const struct netdev_queue *txq)
+                                const struct netdev_queue *txq,
+                                int *packets)
 {
        int bytelimit = qdisc_avail_bulklimit(txq) - skb->len;
 
@@ -70,6 +71,7 @@ static void try_bulk_dequeue_skb(struct Qdisc *q,
                bytelimit -= nskb->len; /* covers GSO len */
                skb->next = nskb;
                skb = nskb;
+               (*packets)++; /* GSO counts as one pkt */
        }
        skb->next = NULL;
 }
@@ -77,11 +79,13 @@ static void try_bulk_dequeue_skb(struct Qdisc *q,
 /* Note that dequeue_skb can possibly return a SKB list (via skb->next).
  * A requeued skb (via q->gso_skb) can also be a SKB list.
  */
-static struct sk_buff *dequeue_skb(struct Qdisc *q, bool *validate)
+static struct sk_buff *dequeue_skb(struct Qdisc *q, bool *validate,
+                                  int *packets)
 {
        struct sk_buff *skb = q->gso_skb;
        const struct netdev_queue *txq = q->dev_queue;
 
+       *packets = 1;
        *validate = true;
        if (unlikely(skb)) {
                /* check the reason of requeuing without tx lock first */
@@ -98,7 +102,7 @@ static struct sk_buff *dequeue_skb(struct Qdisc *q, bool *validate)
                    !netif_xmit_frozen_or_stopped(txq)) {
                        skb = q->dequeue(q);
                        if (skb && qdisc_may_bulk(q))
-                               try_bulk_dequeue_skb(q, skb, txq);
+                               try_bulk_dequeue_skb(q, skb, txq, packets);
                }
        }
        return skb;
@@ -204,7 +208,7 @@ int sch_direct_xmit(struct sk_buff *skb, struct Qdisc *q,
  *                             >0 - queue is not empty.
  *
  */
-static inline int qdisc_restart(struct Qdisc *q)
+static inline int qdisc_restart(struct Qdisc *q, int *packets)
 {
        struct netdev_queue *txq;
        struct net_device *dev;
@@ -213,7 +217,7 @@ static inline int qdisc_restart(struct Qdisc *q)
        bool validate;
 
        /* Dequeue packet */
-       skb = dequeue_skb(q, &validate);
+       skb = dequeue_skb(q, &validate, packets);
        if (unlikely(!skb))
                return 0;
 
@@ -227,14 +231,16 @@ static inline int qdisc_restart(struct Qdisc *q)
 void __qdisc_run(struct Qdisc *q)
 {
        int quota = weight_p;
+       int packets;
 
-       while (qdisc_restart(q)) {
+       while (qdisc_restart(q, &packets)) {
                /*
                 * Ordered by possible occurrence: Postpone processing if
                 * 1. we've exceeded packet quota
                 * 2. another process needs the CPU;
                 */
-               if (--quota <= 0 || need_resched()) {
+               quota -= packets;
+               if (quota <= 0 || need_resched()) {
                        __netif_schedule(q);
                        break;
                }
index ffd9cb46902b3640c5a52947391ad16c5d0c69b9..fe20c319a0bb37dd475b7a8a32dccd57ac4e15d9 100644 (file)
@@ -1065,7 +1065,8 @@ static long sock_ioctl(struct file *file, unsigned cmd, unsigned long arg)
                        err = -EFAULT;
                        if (get_user(pid, (int __user *)argp))
                                break;
-                       err = f_setown(sock->file, pid, 1);
+                       f_setown(sock->file, pid, 1);
+                       err = 0;
                        break;
                case FIOGETOWN:
                case SIOCGPGRP:
index a55c27b75ee5667a7046ad54855f8ddd90c57b05..459611577d3dfa29f72442dfe1dcdfe4f2c6a502 100644 (file)
@@ -46,38 +46,6 @@ static void lib80211_crypt_deinit_entries(struct lib80211_crypt_info *info,
 static void lib80211_crypt_quiescing(struct lib80211_crypt_info *info);
 static void lib80211_crypt_deinit_handler(unsigned long data);
 
-const char *print_ssid(char *buf, const char *ssid, u8 ssid_len)
-{
-       const char *s = ssid;
-       char *d = buf;
-
-       ssid_len = min_t(u8, ssid_len, IEEE80211_MAX_SSID_LEN);
-       while (ssid_len--) {
-               if (isprint(*s)) {
-                       *d++ = *s++;
-                       continue;
-               }
-
-               *d++ = '\\';
-               if (*s == '\0')
-                       *d++ = '0';
-               else if (*s == '\n')
-                       *d++ = 'n';
-               else if (*s == '\r')
-                       *d++ = 'r';
-               else if (*s == '\t')
-                       *d++ = 't';
-               else if (*s == '\\')
-                       *d++ = '\\';
-               else
-                       d += snprintf(d, 3, "%03o", *s);
-               s++;
-       }
-       *d = '\0';
-       return buf;
-}
-EXPORT_SYMBOL(print_ssid);
-
 int lib80211_crypt_info_init(struct lib80211_crypt_info *info, char *name,
                                spinlock_t *lock)
 {
index 8a9a4e1c7eab6757f16daacd736529784881f39e..65e7b08bb2cc04db54412c07e72ef16c9fe2344e 100644 (file)
@@ -171,13 +171,13 @@ ld-ifversion = $(shell [ $(call ld-version) $(1) $(2) ] && echo $(3))
 # Shorthand for $(Q)$(MAKE) -f scripts/Makefile.build obj=
 # Usage:
 # $(Q)$(MAKE) $(build)=dir
-build := -f $(if $(KBUILD_SRC),$(srctree)/)scripts/Makefile.build obj
+build := -f $(srctree)/scripts/Makefile.build obj
 
 ###
 # Shorthand for $(Q)$(MAKE) -f scripts/Makefile.modbuiltin obj=
 # Usage:
 # $(Q)$(MAKE) $(modbuiltin)=dir
-modbuiltin := -f $(if $(KBUILD_SRC),$(srctree)/)scripts/Makefile.modbuiltin obj
+modbuiltin := -f $(srctree)/scripts/Makefile.modbuiltin obj
 
 # Prefix -I with $(srctree) if it is not an absolute path.
 # skip if -I has no parameter
index bf3e6778cd71addc1884b895a65cde06af11525e..649ce68440331cdd5c5446ac76e01a487d2bcf6a 100644 (file)
@@ -79,11 +79,11 @@ endif
 
 # ===========================================================================
 
-ifneq ($(strip $(lib-y) $(lib-m) $(lib-n) $(lib-)),)
+ifneq ($(strip $(lib-y) $(lib-m) $(lib-)),)
 lib-target := $(obj)/lib.a
 endif
 
-ifneq ($(strip $(obj-y) $(obj-m) $(obj-n) $(obj-) $(subdir-m) $(lib-target)),)
+ifneq ($(strip $(obj-y) $(obj-m) $(obj-) $(subdir-m) $(lib-target)),)
 builtin-target := $(obj)/built-in.o
 endif
 
@@ -382,16 +382,14 @@ cmd_link_multi-y = $(LD) $(ld_flags) -r -o $@ $(link_multi_deps) $(cmd_secanalys
 quiet_cmd_link_multi-m = LD [M]  $@
 cmd_link_multi-m = $(cmd_link_multi-y)
 
-# We would rather have a list of rules like
-#      foo.o: $(foo-objs)
-# but that's not so easy, so we rather make all composite objects depend
-# on the set of all their parts
-$(multi-used-y) : %.o: $(multi-objs-y) FORCE
+$(multi-used-y): FORCE
        $(call if_changed,link_multi-y)
+$(call multi_depend, $(multi-used-y), .o, -objs -y)
 
-$(multi-used-m) : %.o: $(multi-objs-m) FORCE
+$(multi-used-m): FORCE
        $(call if_changed,link_multi-m)
        @{ echo $(@:.o=.ko); echo $(link_multi_deps); } > $(MODVERDIR)/$(@F:.o=.mod)
+$(call multi_depend, $(multi-used-m), .o, -objs -y)
 
 targets += $(multi-used-y) $(multi-used-m)
 
index a651cee84f2a837ba2212bb82aa15433cb78ac90..b1c668dc68150b4780d0c5ff0c69cec5278c2daf 100644 (file)
@@ -10,7 +10,7 @@ __clean:
 # Shorthand for $(Q)$(MAKE) scripts/Makefile.clean obj=dir
 # Usage:
 # $(Q)$(MAKE) $(clean)=dir
-clean := -f $(if $(KBUILD_SRC),$(srctree)/)scripts/Makefile.clean obj
+clean := -f $(srctree)/scripts/Makefile.clean obj
 
 # The filename Kbuild has precedence over Makefile
 kbuild-dir := $(if $(filter /%,$(src)),$(src),$(srctree)/$(src))
@@ -23,15 +23,13 @@ __subdir-y  := $(patsubst %/,%,$(filter %/, $(obj-y)))
 subdir-y       += $(__subdir-y)
 __subdir-m     := $(patsubst %/,%,$(filter %/, $(obj-m)))
 subdir-m       += $(__subdir-m)
-__subdir-n     := $(patsubst %/,%,$(filter %/, $(obj-n)))
-subdir-n       += $(__subdir-n)
 __subdir-      := $(patsubst %/,%,$(filter %/, $(obj-)))
 subdir-                += $(__subdir-)
 
 # Subdirectories we need to descend into
 
 subdir-ym      := $(sort $(subdir-y) $(subdir-m))
-subdir-ymn      := $(sort $(subdir-ym) $(subdir-n) $(subdir-))
+subdir-ymn      := $(sort $(subdir-ym) $(subdir-))
 
 # Add subdir path
 
index d8e335eed22632a495c341c21d995a076ef7cb57..5b698add4f31ca634a273ae890cf52471ce85537 100644 (file)
@@ -2,7 +2,7 @@
 # Installing firmware
 #
 # We don't include the .config, so all firmware files are in $(fw-shipped-)
-# rather than in $(fw-shipped-y) or $(fw-shipped-n).
+# rather than in $(fw-shipped-y) or $(fw-shipped-m).
 # ==========================================================================
 
 INSTALL := install
index ab5980f917141e9f90f52a9ae49e71901104196f..133edfae5b8a8d7a66f59b9c1ef3130cb63eb928 100644 (file)
@@ -96,8 +96,9 @@ quiet_cmd_host-cmulti = HOSTLD  $@
       cmd_host-cmulti  = $(HOSTCC) $(HOSTLDFLAGS) -o $@ \
                          $(addprefix $(obj)/,$($(@F)-objs)) \
                          $(HOST_LOADLIBES) $(HOSTLOADLIBES_$(@F))
-$(host-cmulti): $(obj)/%: $(host-cobjs) FORCE
+$(host-cmulti): FORCE
        $(call if_changed,host-cmulti)
+$(call multi_depend, $(host-cmulti), , -objs)
 
 # Create .o file from a single .c file
 # host-cobjs -> .o
@@ -113,8 +114,9 @@ quiet_cmd_host-cxxmulti     = HOSTLD  $@
                          $(foreach o,objs cxxobjs,\
                          $(addprefix $(obj)/,$($(@F)-$(o)))) \
                          $(HOST_LOADLIBES) $(HOSTLOADLIBES_$(@F))
-$(host-cxxmulti): $(obj)/%: $(host-cobjs) $(host-cxxobjs) FORCE
+$(host-cxxmulti): FORCE
        $(call if_changed,host-cxxmulti)
+$(call multi_depend, $(host-cxxmulti), , -objs -cxxobjs)
 
 # Create .o file from a single .cc (C++) file
 quiet_cmd_host-cxxobjs = HOSTCXX $@
index 260bf8acfce96cfcbae0eb2c3c6754e96e649317..54be19a0fa512ed41338faae85746177f1b53376 100644 (file)
@@ -159,6 +159,15 @@ dtc_cpp_flags  = -Wp,-MD,$(depfile).pre.tmp -nostdinc                    \
 modname-multi = $(sort $(foreach m,$(multi-used),\
                $(if $(filter $(subst $(obj)/,,$*.o), $($(m:.o=-objs)) $($(m:.o=-y))),$(m:.o=))))
 
+# Useful for describing the dependency of composite objects
+# Usage:
+#   $(call multi_depend, multi_used_targets, suffix_to_remove, suffix_to_add)
+define multi_depend
+$(foreach m, $(notdir $1), \
+       $(eval $(obj)/$m: \
+       $(addprefix $(obj)/, $(foreach s, $3, $($(m:%$(strip $2)=%$(s)))))))
+endef
+
 ifdef REGENERATE_PARSERS
 
 # GPERF
old mode 100644 (file)
new mode 100755 (executable)
index 4d08b398411fdec9b6707b4cd0db2fd73f1b13fa..374abf44363615004537cb895d3b55bc410ae99b 100755 (executable)
@@ -9,7 +9,8 @@ use strict;
 use POSIX;
 
 my $P = $0;
-$P =~ s@.*/@@g;
+$P =~ s@(.*)/@@g;
+my $D = $1;
 
 my $V = '0.32';
 
@@ -43,6 +44,8 @@ my $configuration_file = ".checkpatch.conf";
 my $max_line_length = 80;
 my $ignore_perl_version = 0;
 my $minimum_perl_version = 5.10.0;
+my $min_conf_desc_length = 4;
+my $spelling_file = "$D/spelling.txt";
 
 sub help {
        my ($exitcode) = @_;
@@ -63,6 +66,7 @@ Options:
   --types TYPE(,TYPE2...)    show only these comma separated message types
   --ignore TYPE(,TYPE2...)   ignore various comma separated message types
   --max-line-length=n        set the maximum line length, if exceeded, warn
+  --min-conf-desc-length=n   set the min description length, if shorter, warn
   --show-types               show the message "types" in the output
   --root=PATH                PATH to the kernel tree root
   --no-summary               suppress the per-file summary
@@ -131,6 +135,7 @@ GetOptions(
        'types=s'       => \@use,
        'show-types!'   => \$show_types,
        'max-line-length=i' => \$max_line_length,
+       'min-conf-desc-length=i' => \$min_conf_desc_length,
        'root=s'        => \$root,
        'summary!'      => \$summary,
        'mailback!'     => \$mailback,
@@ -425,10 +430,35 @@ foreach my $entry (@mode_permission_funcs) {
 
 our $allowed_asm_includes = qr{(?x:
        irq|
-       memory
+       memory|
+       time|
+       reboot
 )};
 # memory.h: ARM has a custom one
 
+# Load common spelling mistakes and build regular expression list.
+my $misspellings;
+my @spelling_list;
+my %spelling_fix;
+open(my $spelling, '<', $spelling_file)
+    or die "$P: Can't open $spelling_file for reading: $!\n";
+while (<$spelling>) {
+       my $line = $_;
+
+       $line =~ s/\s*\n?$//g;
+       $line =~ s/^\s*//g;
+
+       next if ($line =~ m/^\s*#/);
+       next if ($line =~ m/^\s*$/);
+
+       my ($suspect, $fix) = split(/\|\|/, $line);
+
+       push(@spelling_list, $suspect);
+       $spelling_fix{$suspect} = $fix;
+}
+close($spelling);
+$misspellings = join("|", @spelling_list);
+
 sub build_types {
        my $mods = "(?x:  \n" . join("|\n  ", @modifierList) . "\n)";
        my $all = "(?x:  \n" . join("|\n  ", @typeList) . "\n)";
@@ -2215,6 +2245,23 @@ sub process {
                            "8-bit UTF-8 used in possible commit log\n" . $herecurr);
                }
 
+# Check for various typo / spelling mistakes
+               if ($in_commit_log || $line =~ /^\+/) {
+                       while ($rawline =~ /(?:^|[^a-z@])($misspellings)(?:$|[^a-z@])/gi) {
+                               my $typo = $1;
+                               my $typo_fix = $spelling_fix{lc($typo)};
+                               $typo_fix = ucfirst($typo_fix) if ($typo =~ /^[A-Z]/);
+                               $typo_fix = uc($typo_fix) if ($typo =~ /^[A-Z]+$/);
+                               my $msg_type = \&WARN;
+                               $msg_type = \&CHK if ($file);
+                               if (&{$msg_type}("TYPO_SPELLING",
+                                                "'$typo' may be misspelled - perhaps '$typo_fix'?\n" . $herecurr) &&
+                                   $fix) {
+                                       $fixed[$fixlinenr] =~ s/(^|[^A-Za-z@])($typo)($|[^A-Za-z@])/$1$typo_fix$3/;
+                               }
+                       }
+               }
+
 # ignore non-hunk lines and lines being removed
                next if (!$hunk_line || $line =~ /^-/);
 
@@ -2283,8 +2330,10 @@ sub process {
                                }
                                $length++;
                        }
-                       WARN("CONFIG_DESCRIPTION",
-                            "please write a paragraph that describes the config symbol fully\n" . $herecurr) if ($is_start && $is_end && $length < 4);
+                       if ($is_start && $is_end && $length < $min_conf_desc_length) {
+                               WARN("CONFIG_DESCRIPTION",
+                                    "please write a paragraph that describes the config symbol fully\n" . $herecurr);
+                       }
                        #print "is_start<$is_start> is_end<$is_end> length<$length>\n";
                }
 
@@ -2341,7 +2390,7 @@ sub process {
                }
 
 # check we are in a valid source file if not then ignore this hunk
-               next if ($realfile !~ /\.(h|c|s|S|pl|sh)$/);
+               next if ($realfile !~ /\.(h|c|s|S|pl|sh|dtsi|dts)$/);
 
 #line length limit
                if ($line =~ /^\+/ && $prevrawline !~ /\/\*\*/ &&
@@ -2402,7 +2451,7 @@ sub process {
                }
 
 # check we are in a valid source file C or perl if not then ignore this hunk
-               next if ($realfile !~ /\.(h|c|pl)$/);
+               next if ($realfile !~ /\.(h|c|pl|dtsi|dts)$/);
 
 # at the beginning of a line any tabs must come first and anything
 # more than 8 must use tabs.
@@ -2424,7 +2473,7 @@ sub process {
                                "please, no space before tabs\n" . $herevet) &&
                            $fix) {
                                while ($fixed[$fixlinenr] =~
-                                          s/(^\+.*) {8,8}+\t/$1\t\t/) {}
+                                          s/(^\+.*) {8,8}\t/$1\t\t/) {}
                                while ($fixed[$fixlinenr] =~
                                           s/(^\+.*) +\t/$1\t/) {}
                        }
@@ -2592,10 +2641,14 @@ sub process {
                next if ($realfile !~ /\.(h|c)$/);
 
 # check indentation of any line with a bare else
+# (but not if it is a multiple line "if (foo) return bar; else return baz;")
 # if the previous line is a break or return and is indented 1 tab more...
                if ($sline =~ /^\+([\t]+)(?:}[ \t]*)?else(?:[ \t]*{)?\s*$/) {
                        my $tabs = length($1) + 1;
-                       if ($prevline =~ /^\+\t{$tabs,$tabs}(?:break|return)\b/) {
+                       if ($prevline =~ /^\+\t{$tabs,$tabs}break\b/ ||
+                           ($prevline =~ /^\+\t{$tabs,$tabs}return\b/ &&
+                            defined $lines[$linenr] &&
+                            $lines[$linenr] !~ /^[ \+]\t{$tabs,$tabs}return/)) {
                                WARN("UNNECESSARY_ELSE",
                                     "else is not generally useful after a break or return\n" . $hereprev);
                        }
@@ -3752,7 +3805,6 @@ sub process {
                        if (ERROR("SPACING",
                                  "space prohibited before that close parenthesis ')'\n" . $herecurr) &&
                            $fix) {
-                               print("fixlinenr: <$fixlinenr> fixed[fixlinenr]: <$fixed[$fixlinenr]>\n");
                                $fixed[$fixlinenr] =~
                                    s/\s+\)/\)/;
                        }
@@ -4060,12 +4112,17 @@ sub process {
                        my $cnt = $realcnt;
                        my ($off, $dstat, $dcond, $rest);
                        my $ctx = '';
+                       my $has_flow_statement = 0;
+                       my $has_arg_concat = 0;
                        ($dstat, $dcond, $ln, $cnt, $off) =
                                ctx_statement_block($linenr, $realcnt, 0);
                        $ctx = $dstat;
                        #print "dstat<$dstat> dcond<$dcond> cnt<$cnt> off<$off>\n";
                        #print "LINE<$lines[$ln-1]> len<" . length($lines[$ln-1]) . "\n";
 
+                       $has_flow_statement = 1 if ($ctx =~ /\b(goto|return)\b/);
+                       $has_arg_concat = 1 if ($ctx =~ /\#\#/);
+
                        $dstat =~ s/^.\s*\#\s*define\s+$Ident(?:\([^\)]*\))?\s*//;
                        $dstat =~ s/$;//g;
                        $dstat =~ s/\\\n.//g;
@@ -4126,10 +4183,23 @@ sub process {
                                              "Macros with multiple statements should be enclosed in a do - while loop\n" . "$herectx");
                                } else {
                                        ERROR("COMPLEX_MACRO",
-                                             "Macros with complex values should be enclosed in parenthesis\n" . "$herectx");
+                                             "Macros with complex values should be enclosed in parentheses\n" . "$herectx");
                                }
                        }
 
+# check for macros with flow control, but without ## concatenation
+# ## concatenation is commonly a macro that defines a function so ignore those
+                       if ($has_flow_statement && !$has_arg_concat) {
+                               my $herectx = $here . "\n";
+                               my $cnt = statement_rawlines($ctx);
+
+                               for (my $n = 0; $n < $cnt; $n++) {
+                                       $herectx .= raw_line($linenr, $n) . "\n";
+                               }
+                               WARN("MACRO_WITH_FLOW_CONTROL",
+                                    "Macros with flow control statements should be avoided\n" . "$herectx");
+                       }
+
 # check for line continuations outside of #defines, preprocessor #, and asm
 
                } else {
@@ -4338,6 +4408,12 @@ sub process {
                             "Use of volatile is usually wrong: see Documentation/volatile-considered-harmful.txt\n" . $herecurr);
                }
 
+# concatenated string without spaces between elements
+               if ($line =~ /"X+"[A-Z_]+/ || $line =~ /[A-Z_]+"X+"/) {
+                       CHK("CONCATENATED_STRING",
+                           "Concatenated strings should use spaces between elements\n" . $herecurr);
+               }
+
 # warn about #if 0
                if ($line =~ /^.\s*\#\s*if\s+0\b/) {
                        CHK("REDUNDANT_CODE",
@@ -4371,6 +4447,17 @@ sub process {
                        }
                }
 
+# check for logging functions with KERN_<LEVEL>
+               if ($line !~ /printk\s*\(/ &&
+                   $line =~ /\b$logFunctions\s*\(.*\b(KERN_[A-Z]+)\b/) {
+                       my $level = $1;
+                       if (WARN("UNNECESSARY_KERN_LEVEL",
+                                "Possible unnecessary $level\n" . $herecurr) &&
+                           $fix) {
+                               $fixed[$fixlinenr] =~ s/\s*$level\s*//;
+                       }
+               }
+
 # check for bad placement of section $InitAttribute (e.g.: __initdata)
                if ($line =~ /(\b$InitAttribute\b)/) {
                        my $attr = $1;
diff --git a/scripts/coccinelle/misc/simple_return.cocci b/scripts/coccinelle/misc/simple_return.cocci
new file mode 100644 (file)
index 0000000..47f7084
--- /dev/null
@@ -0,0 +1,180 @@
+/// Simplify a trivial if-return sequence.  Possibly combine with a
+/// preceding function call.
+//
+// Confidence: High
+// Copyright: (C) 2014 Julia Lawall, INRIA/LIP6.  GPLv2.
+// Copyright: (C) 2014 Gilles Muller, INRIA/LiP6.  GPLv2.
+// URL: http://coccinelle.lip6.fr/
+// Comments:
+// Options: --no-includes --include-headers
+
+virtual patch
+virtual context
+virtual org
+virtual report
+
+@r depends on patch@
+local idexpression e;
+identifier i,f,fn;
+@@
+
+fn(...) { <...
+- e@i =
++ return
+    f(...);
+-if (i != 0) return i;
+-return 0;
+...> }
+
+@depends on patch@
+identifier r.i;
+type t;
+@@
+
+-t i;
+ ... when != i
+
+@depends on patch@
+expression e;
+@@
+
+-if (e != 0)
+   return e;
+-return 0;
+
+// -----------------------------------------------------------------------
+
+@s1 depends on context || org || report@
+local idexpression e;
+identifier i,f,fn;
+position p,p1,p2;
+@@
+
+fn(...) { <...
+* e@i@p = f(...);
+  if (\(i@p1 != 0\|i@p2 < 0\))
+     return i;
+  return 0;
+...> }
+
+@s2 depends on context || org || report forall@
+identifier s1.i;
+type t;
+position q,s1.p;
+expression e,f;
+@@
+
+* t i@q;
+  ... when != i
+  e@p = f(...);
+
+@s3 depends on context || org || report@
+expression e;
+position p1!=s1.p1;
+position p2!=s1.p2;
+@@
+
+*if (\(e@p1 != 0\|e@p2 < 0\))
+   return e;
+ return 0;
+
+// -----------------------------------------------------------------------
+
+@script:python depends on org@
+p << s1.p;
+p1 << s1.p1;
+q << s2.q;
+@@
+
+cocci.print_main("decl",q)
+cocci.print_secs("use",p)
+cocci.include_match(False)
+
+@script:python depends on org@
+p << s1.p;
+p2 << s1.p2;
+q << s2.q;
+@@
+
+cocci.print_main("decl",q)
+cocci.print_secs("use with questionable test",p)
+cocci.include_match(False)
+
+@script:python depends on org@
+p << s1.p;
+p1 << s1.p1;
+@@
+
+cocci.print_main("use",p)
+
+@script:python depends on org@
+p << s1.p;
+p2 << s1.p2;
+@@
+
+cocci.print_main("use with questionable test",p)
+
+@script:python depends on org@
+p << s3.p1;
+@@
+
+cocci.print_main("test",p)
+
+@script:python depends on org@
+p << s3.p2;
+@@
+
+cocci.print_main("questionable test",p)
+
+// -----------------------------------------------------------------------
+
+@script:python depends on report@
+p << s1.p;
+p1 << s1.p1;
+q << s2.q;
+@@
+
+msg = "WARNING: end returns can be simpified and declaration on line %s can be dropped" % (q[0].line)
+coccilib.report.print_report(p[0],msg)
+cocci.include_match(False)
+
+@script:python depends on report@
+p << s1.p;
+p1 << s1.p1;
+q << s2.q
+;
+@@
+
+msg = "WARNING: end returns may be simpified if negative or 0 value and declaration on line %s can be dropped" % (q[0].line)
+coccilib.report.print_report(p[0],msg)
+cocci.include_match(False)
+
+@script:python depends on report@
+p << s1.p;
+p1 << s1.p1;
+@@
+
+msg = "WARNING: end returns can be simpified"
+coccilib.report.print_report(p[0],msg)
+
+@script:python depends on report@
+p << s1.p;
+p2 << s1.p2;
+@@
+
+msg = "WARNING: end returns can be simpified if negative or 0 value"
+coccilib.report.print_report(p[0],msg)
+
+@script:python depends on report@
+p << s3.p1;
+@@
+
+msg = "WARNING: end returns can be simpified"
+coccilib.report.print_report(p[0],msg)
+
+@script:python depends on report@
+p << s3.p2;
+@@
+
+msg = "WARNING: end returns can be simpified if tested value is negative or 0"
+coccilib.report.print_report(p[0],msg)
old mode 100644 (file)
new mode 100755 (executable)
old mode 100644 (file)
new mode 100755 (executable)
old mode 100644 (file)
new mode 100755 (executable)
old mode 100644 (file)
new mode 100755 (executable)
old mode 100644 (file)
new mode 100755 (executable)
old mode 100644 (file)
new mode 100755 (executable)
old mode 100644 (file)
new mode 100755 (executable)
old mode 100644 (file)
new mode 100755 (executable)
old mode 100644 (file)
new mode 100755 (executable)
index 5de5660..fdebd66
@@ -1,8 +1,8 @@
 #!/bin/sh
 
-if [ $# -lt 1 ]
+if [ $# -lt 2 ]
 then
-       echo "Usage: headers_install.sh OUTDIR SRCDIR [FILES...]
+       echo "Usage: headers_install.sh OUTDIR SRCDIR [FILES...]"
        echo
        echo "Prepares kernel header files for use by user space, by removing"
        echo "all compiler.h definitions and #includes, removing any"
index ebf40f6edb4d4ee5f847a103cb082bcddec99dd6..9645c073938617dd1a72cb4b13973d86cef053e9 100644 (file)
@@ -176,39 +176,10 @@ qconf-cxxobjs     := qconf.o
 qconf-objs     := zconf.tab.o
 gconf-objs     := gconf.o zconf.tab.o
 
-hostprogs-y := conf
-
-ifeq ($(MAKECMDGOALS),nconfig)
-       hostprogs-y += nconf
-endif
-
-ifeq ($(MAKECMDGOALS),menuconfig)
-       hostprogs-y += mconf
-endif
-
-ifeq ($(MAKECMDGOALS),update-po-config)
-       hostprogs-y += kxgettext
-endif
-
-ifeq ($(MAKECMDGOALS),xconfig)
-       qconf-target := 1
-endif
-ifeq ($(MAKECMDGOALS),gconfig)
-       gconf-target := 1
-endif
-
-
-ifeq ($(qconf-target),1)
-       hostprogs-y += qconf
-endif
-
-ifeq ($(gconf-target),1)
-       hostprogs-y += gconf
-endif
+hostprogs-y := conf nconf mconf kxgettext qconf gconf
 
 clean-files    := qconf.moc .tmp_qtcheck .tmp_gtkcheck
 clean-files    += zconf.tab.c zconf.lex.c zconf.hash.c gconf.glade.h
-clean-files     += mconf qconf gconf nconf
 clean-files     += config.pot linux.pot
 
 # Check that we have the required ncurses stuff installed for lxdialog (menuconfig)
@@ -239,11 +210,12 @@ HOSTCFLAGS_gconf.o        = `pkg-config --cflags gtk+-2.0 gmodule-2.0 libglade-2.0` \
 HOSTLOADLIBES_mconf   = $(shell $(CONFIG_SHELL) $(check-lxdialog) -ldflags $(HOSTCC))
 
 HOSTLOADLIBES_nconf    = $(shell \
-                               pkg-config --libs menu panel ncurses 2>/dev/null \
+                               pkg-config --libs menuw panelw ncursesw 2>/dev/null \
+                               || pkg-config --libs menu panel ncurses 2>/dev/null \
                                || echo "-lmenu -lpanel -lncurses"  )
 $(obj)/qconf.o: $(obj)/.tmp_qtcheck
 
-ifeq ($(qconf-target),1)
+ifeq ($(MAKECMDGOALS),xconfig)
 $(obj)/.tmp_qtcheck: $(src)/Makefile
 -include $(obj)/.tmp_qtcheck
 
@@ -300,7 +272,7 @@ endif
 
 $(obj)/gconf.o: $(obj)/.tmp_gtkcheck
 
-ifeq ($(gconf-target),1)
+ifeq ($(MAKECMDGOALS),gconfig)
 -include $(obj)/.tmp_gtkcheck
 
 # GTK needs some extra effort, too...
old mode 100644 (file)
new mode 100755 (executable)
index 9d2a4c5..5075ebf
@@ -21,7 +21,11 @@ ldflags()
 # Where is ncurses.h?
 ccflags()
 {
-       if [ -f /usr/include/ncursesw/curses.h ]; then
+       if pkg-config --cflags ncursesw 2>/dev/null; then
+               echo '-DCURSES_LOC="<ncurses.h>" -DNCURSES_WIDECHAR=1'
+       elif pkg-config --cflags ncurses 2>/dev/null; then
+               echo '-DCURSES_LOC="<ncurses.h>"'
+       elif [ -f /usr/include/ncursesw/curses.h ]; then
                echo '-I/usr/include/ncursesw -DCURSES_LOC="<curses.h>"'
                echo ' -DNCURSES_WIDECHAR=1'
        elif [ -f /usr/include/ncurses/ncurses.h ]; then
index b4343d384926600329203b846855f940b597b5fd..fcffd5b41fb07bff8cab87c3cdee93c18e884e1b 100644 (file)
@@ -170,7 +170,7 @@ char item_tag(void);
 /* item list manipulation for lxdialog use */
 #define MAXITEMSTR 200
 struct dialog_item {
-       char str[MAXITEMSTR];   /* promtp displayed */
+       char str[MAXITEMSTR];   /* prompt displayed */
        char tag;
        void *data;     /* pointer to menu item - used by menubox+checklist */
        int selected;   /* Set to 1 by dialog_*() function if selected. */
old mode 100644 (file)
new mode 100755 (executable)
old mode 100644 (file)
new mode 100755 (executable)
old mode 100644 (file)
new mode 100755 (executable)
old mode 100644 (file)
new mode 100755 (executable)
old mode 100644 (file)
new mode 100755 (executable)
old mode 100644 (file)
new mode 100755 (executable)
index 35d5a58..5972624
@@ -37,7 +37,7 @@ create_package() {
        s390*)
                debarch=s390$(grep -q CONFIG_64BIT=y $KCONFIG_CONFIG && echo x || true) ;;
        ppc*)
-               debarch=powerpc ;;
+               debarch=$(grep -q CPU_LITTLE_ENDIAN=y $KCONFIG_CONFIG && echo ppc64el || echo powerpc) ;;
        parisc*)
                debarch=hppa ;;
        mips*)
@@ -64,7 +64,7 @@ create_package() {
        fi
 
        # Create the package
-       dpkg-gencontrol -isp $forcearch -Vkernel:debarch="${debarch:-$(dpkg --print-architecture)}" -p$pname -P"$pdir"
+       dpkg-gencontrol $forcearch -Vkernel:debarch="${debarch:-$(dpkg --print-architecture)}" -p$pname -P"$pdir"
        dpkg --build "$pdir" ..
 }
 
@@ -152,18 +152,16 @@ if grep -q '^CONFIG_MODULES=y' $KCONFIG_CONFIG ; then
                rmdir "$tmpdir/lib/modules/$version"
        fi
        if [ -n "$BUILD_DEBUG" ] ; then
-               (
-                       cd $tmpdir
-                       for module in $(find lib/modules/ -name *.ko); do
-                               mkdir -p $(dirname $dbg_dir/usr/lib/debug/$module)
-                               # only keep debug symbols in the debug file
-                               $OBJCOPY --only-keep-debug $module $dbg_dir/usr/lib/debug/$module
-                               # strip original module from debug symbols
-                               $OBJCOPY --strip-debug $module
-                               # then add a link to those
-                               $OBJCOPY --add-gnu-debuglink=$dbg_dir/usr/lib/debug/$module $module
-                       done
-               )
+               for module in $(find $tmpdir/lib/modules/ -name *.ko -printf '%P\n'); do
+                       module=lib/modules/$module
+                       mkdir -p $(dirname $dbg_dir/usr/lib/debug/$module)
+                       # only keep debug symbols in the debug file
+                       $OBJCOPY --only-keep-debug $tmpdir/$module $dbg_dir/usr/lib/debug/$module
+                       # strip original module from debug symbols
+                       $OBJCOPY --strip-debug $tmpdir/$module
+                       # then add a link to those
+                       $OBJCOPY --add-gnu-debuglink=$dbg_dir/usr/lib/debug/$module $tmpdir/$module
+               done
        fi
 fi
 
old mode 100644 (file)
new mode 100755 (executable)
old mode 100644 (file)
new mode 100755 (executable)
index 650ecc83d7d72f89b012ec2f1ee41ef895aa398f..001facfa5b7436b7c5586ed50fec306b09fa5078 100644 (file)
@@ -388,10 +388,6 @@ do_file(char const *const fname)
                                "unrecognized ET_REL file: %s\n", fname);
                        fail_file();
                }
-               if (w2(ehdr->e_machine) == EM_S390) {
-                       reltype = R_390_32;
-                       mcount_adjust_32 = -4;
-               }
                if (w2(ehdr->e_machine) == EM_MIPS) {
                        reltype = R_MIPS_32;
                        is_fake_mcount32 = MIPS32_is_fake_mcount;
index 397b6b84e8c55f801066460ee1a22007cacc95ad..d4b665610d6706f0c176a04bee06e3b0dd6f9650 100755 (executable)
@@ -241,13 +241,6 @@ if ($arch eq "x86_64") {
     $objcopy .= " -O elf32-i386";
     $cc .= " -m32";
 
-} elsif ($arch eq "s390" && $bits == 32) {
-    $mcount_regex = "^\\s*([0-9a-fA-F]+):\\s*R_390_32\\s+_mcount\$";
-    $mcount_adjust = -4;
-    $alignment = 4;
-    $ld .= " -m elf_s390";
-    $cc .= " -m31";
-
 } elsif ($arch eq "s390" && $bits == 64) {
     $mcount_regex = "^\\s*([0-9a-fA-F]+):\\s*R_390_(PC|PLT)32DBL\\s+_mcount\\+0x2\$";
     $mcount_adjust = -8;
old mode 100644 (file)
new mode 100755 (executable)
old mode 100644 (file)
new mode 100755 (executable)
index 8fac3fd697a6ec34c4908ca60386f2dee3c29bb0..ba8700428e21dd1612d8c6ae4ddde0e0e964433e 100644 (file)
@@ -103,7 +103,7 @@ do_func(Elf_Ehdr *ehdr, char const *const fname, table_sort_t custom_sort)
        Elf_Sym *sort_needed_sym;
        Elf_Shdr *sort_needed_sec;
        Elf_Rel *relocs = NULL;
-       int relocs_size;
+       int relocs_size = 0;
        uint32_t *sort_done_location;
        const char *secstrtab;
        const char *strtab;
diff --git a/scripts/spelling.txt b/scripts/spelling.txt
new file mode 100644 (file)
index 0000000..fc7fd52
--- /dev/null
@@ -0,0 +1,1042 @@
+# Originally from Debian's Lintian tool. Various false positives have been
+# removed, and various additions have been made as they've been discovered
+# in the kernel source.
+#
+# License: GPLv2
+#
+# The format of each line is:
+# mistake||correction
+#
+abandonning||abandoning
+abigious||ambiguous
+abitrate||arbitrate
+abov||above
+abreviated||abbreviated
+absense||absence
+absolut||absolute
+absoulte||absolute
+acccess||access
+acceleratoin||acceleration
+accelleration||acceleration
+accesing||accessing
+accesnt||accent
+accessable||accessible
+accesss||access
+accidentaly||accidentally
+accidentually||accidentally
+accoding||according
+accomodate||accommodate
+accomodates||accommodates
+accordign||according
+accoring||according
+accout||account
+accquire||acquire
+accquired||acquired
+acessable||accessible
+acess||access
+achitecture||architecture
+acient||ancient
+acitions||actions
+acitve||active
+acknowldegement||acknowldegement
+acknowledgement||acknowledgment
+ackowledge||acknowledge
+ackowledged||acknowledged
+acording||according
+activete||activate
+acumulating||accumulating
+adapater||adapter
+addional||additional
+additionaly||additionally
+addres||address
+addreses||addresses
+addresss||address
+aditional||additional
+aditionally||additionally
+aditionaly||additionally
+adminstrative||administrative
+adress||address
+adresses||addresses
+adviced||advised
+afecting||affecting
+agaist||against
+albumns||albums
+alegorical||allegorical
+algorith||algorithm
+algorithmical||algorithmically
+algoritm||algorithm
+algoritms||algorithms
+algorrithm||algorithm
+algorritm||algorithm
+allign||align
+allocatrd||allocated
+allocte||allocate
+allpication||application
+alocate||allocate
+alogirhtms||algorithms
+alogrithm||algorithm
+alot||a lot
+alow||allow
+alows||allows
+altough||although
+alue||value
+ambigious||ambiguous
+amoung||among
+amout||amount
+analysator||analyzer
+ang||and
+anniversery||anniversary
+annoucement||announcement
+anomolies||anomalies
+anomoly||anomaly
+anway||anyway
+aplication||application
+appearence||appearance
+applicaion||application
+appliction||application
+applictions||applications
+appplications||applications
+appropiate||appropriate
+appropriatly||appropriately
+approriate||appropriate
+approriately||appropriately
+aquainted||acquainted
+aquired||acquired
+arbitary||arbitrary
+architechture||architecture
+arguement||argument
+arguements||arguments
+aritmetic||arithmetic
+arne't||aren't
+arraival||arrival
+artifical||artificial
+artillary||artillery
+assiged||assigned
+assigment||assignment
+assigments||assignments
+assistent||assistant
+assocation||association
+associcated||associated
+assotiated||associated
+assum||assume
+assumtpion||assumption
+asuming||assuming
+asycronous||asynchronous
+asynchnous||asynchronous
+atomatically||automatically
+atomicly||atomically
+attachement||attachment
+attched||attached
+attemps||attempts
+attruibutes||attributes
+authentification||authentication
+automaticaly||automatically
+automaticly||automatically
+automatize||automate
+automatized||automated
+automatizes||automates
+autonymous||autonomous
+auxilliary||auxiliary
+avaiable||available
+avaible||available
+availabe||available
+availabled||available
+availablity||availability
+availale||available
+availavility||availability
+availble||available
+availiable||available
+avalable||available
+avaliable||available
+aysnc||async
+backgroud||background
+backword||backward
+backwords||backwards
+bahavior||behavior
+bakup||backup
+baloon||balloon
+baloons||balloons
+bandwith||bandwidth
+batery||battery
+beacuse||because
+becasue||because
+becomming||becoming
+becuase||because
+beeing||being
+befor||before
+begining||beginning
+beter||better
+betweeen||between
+bianries||binaries
+bitmast||bitmask
+boardcast||broadcast
+borad||board
+boundry||boundary
+brievely||briefly
+broadcat||broadcast
+cacluated||calculated
+caculation||calculation
+calender||calendar
+calle||called
+calucate||calculate
+calulate||calculate
+cancelation||cancellation
+capabilites||capabilities
+capabitilies||capabilities
+capatibilities||capabilities
+carefuly||carefully
+cariage||carriage
+catagory||category
+challange||challenge
+challanges||challenges
+chanell||channel
+changable||changeable
+channle||channel
+channnel||channel
+charachter||character
+charachters||characters
+charactor||character
+charater||character
+charaters||characters
+charcter||character
+checksuming||checksumming
+childern||children
+childs||children
+chiled||child
+chked||checked
+chnage||change
+chnages||changes
+chnnel||channel
+choosen||chosen
+chouse||chose
+circumvernt||circumvent
+claread||cleared
+clared||cleared
+closeing||closing
+clustred||clustered
+collapsable||collapsible
+colorfull||colorful
+comand||command
+comit||commit
+commerical||commercial
+comming||coming
+comminucation||communication
+commited||committed
+commiting||committing
+committ||commit
+commoditiy||commodity
+compability||compatibility
+compaibility||compatibility
+compatability||compatibility
+compatable||compatible
+compatibiliy||compatibility
+compatibilty||compatibility
+compilant||compliant
+compleatly||completely
+completly||completely
+complient||compliant
+componnents||components
+compres||compress
+compresion||compression
+comression||compression
+comunication||communication
+conbination||combination
+conditionaly||conditionally
+conected||connected
+configuratoin||configuration
+configuraton||configuration
+configuretion||configuration
+conider||consider
+conjuction||conjunction
+connectinos||connections
+connnection||connection
+connnections||connections
+consistancy||consistency
+consistant||consistent
+containes||contains
+containts||contains
+contaisn||contains
+contant||contact
+contence||contents
+continous||continuous
+continously||continuously
+continueing||continuing
+contraints||constraints
+controled||controlled
+controler||controller
+controll||control
+contruction||construction
+contry||country
+convertion||conversion
+convertor||converter
+convienient||convenient
+convinient||convenient
+corected||corrected
+correponding||corresponding
+correponds||corresponds
+correspoding||corresponding
+cotrol||control
+couter||counter
+coutner||counter
+cryptocraphic||cryptographic
+cunter||counter
+curently||currently
+dafault||default
+deafult||default
+deamon||daemon
+decompres||decompress
+decription||description
+defailt||default
+defferred||deferred
+definate||definite
+definately||definitely
+defintion||definition
+defualt||default
+defult||default
+deivce||device
+delared||declared
+delare||declare
+delares||declares
+delaring||declaring
+delemiter||delimiter
+dependancies||dependencies
+dependancy||dependency
+dependant||dependent
+depreacted||deprecated
+depreacte||deprecate
+desactivate||deactivate
+desciptors||descriptors
+descrition||description
+descritptor||descriptor
+desctiptor||descriptor
+desriptor||descriptor
+desriptors||descriptors
+destory||destroy
+destoryed||destroyed
+destorys||destroys
+destroied||destroyed
+detabase||database
+develope||develop
+developement||development
+developped||developed
+developpement||development
+developper||developer
+developpment||development
+deveolpment||development
+devided||divided
+deviece||device
+diable||disable
+dictionnary||dictionary
+diferent||different
+differrence||difference
+difinition||definition
+diplay||display
+direectly||directly
+disapear||disappear
+disapeared||disappeared
+disappared||disappeared
+disconnet||disconnect
+discontinous||discontinuous
+dispertion||dispersion
+dissapears||disappears
+distiction||distinction
+docuentation||documentation
+documantation||documentation
+documentaion||documentation
+documment||document
+dorp||drop
+dosen||doesn
+downlad||download
+downlads||downloads
+druing||during
+dynmaic||dynamic
+easilly||easily
+ecspecially||especially
+edditable||editable
+editting||editing
+efficently||efficiently
+ehther||ether
+eigth||eight
+eletronic||electronic
+enabledi||enabled
+enchanced||enhanced
+encorporating||incorporating
+encrupted||encrypted
+encrypiton||encryption
+endianess||endianness
+enhaced||enhanced
+enlightnment||enlightenment
+enocded||encoded
+enterily||entirely
+enviroiment||environment
+enviroment||environment
+environement||environment
+environent||environment
+eqivalent||equivalent
+equiped||equipped
+equivelant||equivalent
+equivilant||equivalent
+eror||error
+estbalishment||establishment
+etsablishment||establishment
+etsbalishment||establishment
+excecutable||executable
+exceded||exceeded
+excellant||excellent
+existance||existence
+existant||existent
+exixt||exist
+exlcude||exclude
+exlcusive||exclusive
+exmaple||example
+expecially||especially
+explicite||explicit
+explicitely||explicitly
+explict||explicit
+explictly||explicitly
+expresion||expression
+exprimental||experimental
+extened||extended
+extensability||extensibility
+extention||extension
+extracter||extractor
+faild||failed
+faill||fail
+failue||failure
+failuer||failure
+faireness||fairness
+faliure||failure
+familar||familiar
+fatser||faster
+feauture||feature
+feautures||features
+fetaure||feature
+fetaures||features
+fileystem||filesystem
+finanize||finalize
+findn||find
+finilizes||finalizes
+finsih||finish
+flusing||flushing
+folloing||following
+followign||following
+follwing||following
+forseeable||foreseeable
+forse||force
+fortan||fortran
+forwardig||forwarding
+framwork||framework
+frequncy||frequency
+frome||from
+fucntion||function
+fuction||function
+fuctions||functions
+funcion||function
+functionallity||functionality
+functionaly||functionally
+functionnality||functionality
+functonality||functionality
+funtion||function
+funtions||functions
+furthur||further
+futhermore||furthermore
+futrue||future
+gaurenteed||guaranteed
+generiously||generously
+genric||generic
+globel||global
+grabing||grabbing
+grahical||graphical
+grahpical||graphical
+grapic||graphic
+guage||gauge
+guarentee||guarantee
+halfs||halves
+hander||handler
+handfull||handful
+hanled||handled
+harware||hardware
+heirarchically||hierarchically
+helpfull||helpful
+hierachy||hierarchy
+hierarchie||hierarchy
+howver||however
+hsould||should
+hypter||hyper
+identidier||identifier
+imblance||imbalance
+immeadiately||immediately
+immedaite||immediate
+immediatelly||immediately
+immediatly||immediately
+immidiate||immediate
+impelentation||implementation
+impementated||implemented
+implemantation||implementation
+implemenation||implementation
+implementaiton||implementation
+implementated||implemented
+implemention||implementation
+implemetation||implementation
+implemntation||implementation
+implentation||implementation
+implmentation||implementation
+implmenting||implementing
+incomming||incoming
+incompatabilities||incompatibilities
+incompatable||incompatible
+inconsistant||inconsistent
+increas||increase
+incrment||increment
+indendation||indentation
+indended||intended
+independant||independent
+independantly||independently
+independed||independent
+indiate||indicate
+inexpect||inexpected
+infomation||information
+informatiom||information
+informations||information
+informtion||information
+infromation||information
+ingore||ignore
+inital||initial
+initalised||initialized
+initalise||initialize
+initalize||initialize
+initation||initiation
+initators||initiators
+initializiation||initialization
+initialzed||initialized
+initilization||initialization
+initilize||initialize
+inofficial||unofficial
+instal||install
+inteface||interface
+integreated||integrated
+integrety||integrity
+integrey||integrity
+intendet||intended
+intented||intended
+interanl||internal
+interchangable||interchangeable
+interferring||interfering
+interger||integer
+intermittant||intermittent
+internel||internal
+interoprability||interoperability
+interrface||interface
+interrrupt||interrupt
+interrup||interrupt
+interrups||interrupts
+interruptted||interrupted
+interupted||interrupted
+interupt||interrupt
+intial||initial
+intialized||initialized
+intialize||initialize
+intregral||integral
+intrrupt||interrupt
+intuative||intuitive
+invaid||invalid
+invalde||invald
+invalide||invalid
+invididual||individual
+invokation||invocation
+invokations||invocations
+irrelevent||irrelevant
+isssue||issue
+itslef||itself
+jave||java
+jeffies||jiffies
+juse||just
+jus||just
+kown||known
+langage||language
+langauage||language
+langauge||language
+langugage||language
+lauch||launch
+leightweight||lightweight
+lengh||length
+lenght||length
+lenth||length
+lesstiff||lesstif
+libaries||libraries
+libary||library
+librairies||libraries
+libraris||libraries
+licenceing||licencing
+loggging||logging
+loggin||login
+logile||logfile
+loosing||losing
+losted||lost
+machinary||machinery
+maintainance||maintenance
+maintainence||maintenance
+maintan||maintain
+makeing||making
+malplaced||misplaced
+malplace||misplace
+managable||manageable
+managment||management
+mangement||management
+manoeuvering||maneuvering
+mappping||mapping
+mathimatical||mathematical
+mathimatic||mathematic
+mathimatics||mathematics
+maxium||maximum
+mechamism||mechanism
+meetign||meeting
+ment||meant
+mergable||mergeable
+mesage||message
+messags||messages
+messgaes||messages
+messsage||message
+messsages||messages
+microprocesspr||microprocessor
+milliseonds||milliseconds
+minumum||minimum
+miscelleneous||miscellaneous
+misformed||malformed
+mispelled||misspelled
+mispelt||misspelt
+miximum||maximum
+mmnemonic||mnemonic
+mnay||many
+modeled||modelled
+modulues||modules
+monochorome||monochrome
+monochromo||monochrome
+monocrome||monochrome
+mopdule||module
+mroe||more
+mulitplied||multiplied
+multidimensionnal||multidimensional
+multple||multiple
+mumber||number
+muticast||multicast
+mutiple||multiple
+mutli||multi
+nams||names
+navagating||navigating
+nead||need
+neccecary||necessary
+neccesary||necessary
+neccessary||necessary
+necesary||necessary
+negaive||negative
+negoitation||negotiation
+negotation||negotiation
+nerver||never
+nescessary||necessary
+nessessary||necessary
+noticable||noticeable
+notications||notifications
+notifed||notified
+numebr||number
+numner||number
+obtaion||obtain
+occassionally||occasionally
+occationally||occasionally
+occurance||occurrence
+occurances||occurrences
+occured||occurred
+occurence||occurrence
+occure||occurred
+occuring||occurring
+offet||offset
+omitt||omit
+ommiting||omitting
+ommitted||omitted
+onself||oneself
+ony||only
+operatione||operation
+opertaions||operations
+optionnal||optional
+optmizations||optimizations
+orientatied||orientated
+orientied||oriented
+otherise||otherwise
+ouput||output
+overaall||overall
+overhread||overhead
+overlaping||overlapping
+overriden||overridden
+overun||overrun
+pacakge||package
+pachage||package
+packacge||package
+packege||package
+packge||package
+packtes||packets
+pakage||package
+pallette||palette
+paln||plan
+paramameters||parameters
+paramater||parameter
+parametes||parameters
+parametised||parametrised
+paramter||parameter
+paramters||parameters
+particuarly||particularly
+particularily||particularly
+pased||passed
+passin||passing
+pathes||paths
+pecularities||peculiarities
+peformance||performance
+peice||piece
+pendantic||pedantic
+peprocessor||preprocessor
+perfoming||performing
+permissons||permissions
+peroid||period
+persistance||persistence
+persistant||persistent
+platfrom||platform
+plattform||platform
+pleaes||please
+ploting||plotting
+plugable||pluggable
+poinnter||pointer
+poiter||pointer
+posible||possible
+positon||position
+possibilites||possibilities
+powerfull||powerful
+preceeded||preceded
+preceeding||preceding
+preceed||precede
+precendence||precedence
+precission||precision
+prefered||preferred
+prefferably||preferably
+premption||preemption
+prepaired||prepared
+pressre||pressure
+primative||primitive
+princliple||principle
+priorty||priority
+privilaged||privileged
+privilage||privilege
+priviledge||privilege
+priviledges||privileges
+probaly||probably
+procceed||proceed
+proccesors||processors
+procesed||processed
+proces||process
+processessing||processing
+processess||processes
+processpr||processor
+processsed||processed
+processsing||processing
+procteted||protected
+prodecure||procedure
+progams||programs
+progess||progress
+programers||programmers
+programm||program
+programms||programs
+progresss||progress
+promps||prompts
+pronnounced||pronounced
+prononciation||pronunciation
+pronouce||pronounce
+pronunce||pronounce
+propery||property
+propigate||propagate
+propigation||propagation
+propogate||propagate
+prosess||process
+protable||portable
+protcol||protocol
+protecion||protection
+protocoll||protocol
+psudo||pseudo
+psuedo||pseudo
+psychadelic||psychedelic
+pwoer||power
+quering||querying
+raoming||roaming
+reasearcher||researcher
+reasearchers||researchers
+reasearch||research
+recepient||recipient
+receving||receiving
+recieved||received
+recieve||receive
+reciever||receiver
+recieves||receives
+recogniced||recognised
+recognizeable||recognizable
+recommanded||recommended
+recyle||recycle
+redircet||redirect
+redirectrion||redirection
+refcounf||refcount
+refence||reference
+refered||referred
+referenace||reference
+refering||referring
+refernces||references
+refernnce||reference
+refrence||reference
+registerd||registered
+registeresd||registered
+registes||registers
+registraration||registration
+regster||register
+regualar||regular
+reguator||regulator
+regulamentations||regulations
+reigstration||registration
+releated||related
+relevent||relevant
+remoote||remote
+remore||remote
+removeable||removable
+repectively||respectively
+replacable||replaceable
+replacments||replacements
+replys||replies
+reponse||response
+representaion||representation
+reqeust||request
+requiere||require
+requirment||requirement
+requred||required
+requried||required
+requst||request
+reseting||resetting
+resizeable||resizable
+resouces||resources
+resoures||resources
+ressizes||resizes
+ressource||resource
+ressources||resources
+retransmited||retransmitted
+retreived||retrieved
+retreive||retrieve
+retrive||retrieve
+retuned||returned
+reuest||request
+reuqest||request
+reutnred||returned
+rmeoved||removed
+rmeove||remove
+rmeoves||removes
+rountine||routine
+routins||routines
+rquest||request
+runing||running
+runned||ran
+runnning||running
+runtine||runtime
+sacrifying||sacrificing
+safly||safely
+safty||safety
+savable||saveable
+scaned||scanned
+scaning||scanning
+scarch||search
+seach||search
+searchs||searches
+secquence||sequence
+secund||second
+segement||segment
+senarios||scenarios
+sentivite||sensitive
+separatly||separately
+sepcify||specify
+sepc||spec
+seperated||separated
+seperately||separately
+seperate||separate
+seperatly||separately
+seperator||separator
+sepperate||separate
+sequece||sequence
+sequencial||sequential
+serveral||several
+setts||sets
+settting||setting
+shotdown||shutdown
+shoud||should
+shoule||should
+shrinked||shrunk
+siginificantly||significantly
+signabl||signal
+similary||similarly
+similiar||similar
+simlar||similar
+simliar||similar
+simpified||simplified
+singaled||signaled
+singal||signal
+singed||signed
+sleeped||slept
+softwares||software
+speach||speech
+specfic||specific
+speciefied||specified
+specifc||specific
+specifed||specified
+specificatin||specification
+specificaton||specification
+specifing||specifying
+specifiying||specifying
+speficied||specified
+speicify||specify
+speling||spelling
+spinlcok||spinlock
+spinock||spinlock
+splitted||split
+spreaded||spread
+sructure||structure
+stablilization||stabilization
+staically||statically
+staion||station
+standardss||standards
+standartization||standardization
+standart||standard
+staticly||statically
+stoped||stopped
+stoppped||stopped
+straming||streaming
+struc||struct
+structres||structures
+stuct||struct
+sturcture||structure
+subdirectoires||subdirectories
+suble||subtle
+succesfully||successfully
+succesful||successful
+successfull||successful
+sucessfully||successfully
+sucess||success
+superflous||superfluous
+superseeded||superseded
+suplied||supplied
+suported||supported
+suport||support
+suppored||supported
+supportin||supporting
+suppoted||supported
+suppported||supported
+suppport||support
+supress||suppress
+surpresses||suppresses
+susbsystem||subsystem
+suspicously||suspiciously
+swaping||swapping
+switchs||switches
+symetric||symmetric
+synax||syntax
+synchonized||synchronized
+syncronize||synchronize
+syncronizing||synchronizing
+syncronus||synchronous
+syste||system
+sytem||system
+sythesis||synthesis
+taht||that
+targetted||targeted
+targetting||targeting
+teh||the
+temorary||temporary
+temproarily||temporarily
+thier||their
+threds||threads
+threshhold||threshold
+throught||through
+thses||these
+tiggered||triggered
+tipically||typically
+tmis||this
+torerable||tolerable
+tramsmitted||transmitted
+tramsmit||transmit
+tranfer||transfer
+transciever||transceiver
+transferd||transferrd
+transfered||transferred
+transfering||transferring
+transision||transition
+transmittd||transmitted
+transormed||transformed
+trasmission||transmission
+treshold||threshold
+trigerring||triggering
+trun||turn
+ture||true
+tyep||type
+udpate||update
+uesd||used
+unconditionaly||unconditionally
+underun||underrun
+unecessary||unnecessary
+unexecpted||unexpected
+unexpectd||unexpected
+unexpeted||unexpected
+unfortunatelly||unfortunately
+unifiy||unify
+unknonw||unknown
+unknow||unknown
+unkown||unknown
+unneedingly||unnecessarily
+unresgister||unregister
+unsinged||unsigned
+unstabel||unstable
+unsuccessfull||unsuccessful
+unsuported||unsupported
+untill||until
+unuseful||useless
+upate||update
+usefule||useful
+usefull||useful
+usege||usage
+usera||users
+usualy||usually
+utilites||utilities
+utillities||utilities
+utilties||utilities
+utiltity||utility
+utitity||utility
+utitlty||utility
+vaid||valid
+vaild||valid
+valide||valid
+variantions||variations
+varient||variant
+vaule||value
+verbse||verbose
+verisons||versions
+verison||version
+verson||version
+vicefersa||vice-versa
+virtal||virtual
+virtaul||virtual
+virtiual||virtual
+visiters||visitors
+vitual||virtual
+wating||waiting
+whataver||whatever
+whenver||whenever
+wheter||whether
+whe||when
+wierd||weird
+wiil||will
+wirte||write
+withing||within
+wnat||want
+workarould||workaround
+writeing||writing
+writting||writing
+zombe||zombie
+zomebie||zombie
index 293828bfd4ac9c248203ee24302381a6fc4b6b8d..cdb491d845035e59bff19a5cde7f1ca84c28c17f 100755 (executable)
@@ -193,10 +193,6 @@ exuberant()
        --regex-c++='/TESTCLEARFLAG_FALSE\(([^,)]*).*/TestClearPage\1/' \
        --regex-c++='/__TESTCLEARFLAG_FALSE\(([^,)]*).*/__TestClearPage\1/' \
        --regex-c++='/_PE\(([^,)]*).*/PEVENT_ERRNO__\1/'                \
-       --regex-c++='/TESTPCGFLAG\(([^,)]*).*/PageCgroup\1/'            \
-       --regex-c++='/SETPCGFLAG\(([^,)]*).*/SetPageCgroup\1/'          \
-       --regex-c++='/CLEARPCGFLAG\(([^,)]*).*/ClearPageCgroup\1/'      \
-       --regex-c++='/TESTCLEARPCGFLAG\(([^,)]*).*/TestClearPageCgroup\1/' \
        --regex-c++='/TASK_PFA_TEST\([^,]*,\s*([^)]*)\)/task_\1/'       \
        --regex-c++='/TASK_PFA_SET\([^,]*,\s*([^)]*)\)/task_set_\1/'    \
        --regex-c++='/TASK_PFA_CLEAR\([^,]*,\s*([^)]*)\)/task_clear_\1/'\
@@ -259,17 +255,13 @@ emacs()
        --regex='/__CLEARPAGEFLAG_NOOP(\([^,)]*\).*/__ClearPage\1/' \
        --regex='/TESTCLEARFLAG_FALSE(\([^,)]*\).*/TestClearPage\1/' \
        --regex='/__TESTCLEARFLAG_FALSE(\([^,)]*\).*/__TestClearPage\1/' \
-       --regex='/TESTPCGFLAG\(([^,)]*).*/PageCgroup\1/'        \
-       --regex='/SETPCGFLAG\(([^,)]*).*/SetPageCgroup\1/'      \
-       --regex='/CLEARPCGFLAG\(([^,)]*).*/ClearPageCgroup\1/'  \
-       --regex='/TESTCLEARPCGFLAG\(([^,)]*).*/TestClearPageCgroup\1/' \
        --regex='/TASK_PFA_TEST\([^,]*,\s*([^)]*)\)/task_\1/'           \
        --regex='/TASK_PFA_SET\([^,]*,\s*([^)]*)\)/task_set_\1/'        \
        --regex='/TASK_PFA_CLEAR\([^,]*,\s*([^)]*)\)/task_clear_\1/'    \
        --regex='/_PE(\([^,)]*\).*/PEVENT_ERRNO__\1/'           \
        --regex='/PCI_OP_READ(\([a-z]*[a-z]\).*[1-4])/pci_bus_read_config_\1/' \
        --regex='/PCI_OP_WRITE(\([a-z]*[a-z]\).*[1-4])/pci_bus_write_config_\1/'\
-       --regex='/DEFINE_HASHTABLE\((\w*)/\1/v/'
+       --regex='/[^#]*DEFINE_HASHTABLE(\([^,)]*\)/\1/'
 
        all_kconfigs | xargs $1 -a                              \
        --regex='/^[ \t]*\(\(menu\)*config\)[ \t]+\([a-zA-Z0-9_]+\)/\3/'
old mode 100644 (file)
new mode 100755 (executable)
old mode 100644 (file)
new mode 100755 (executable)
index a74fde6a7468cda37e0eacee7fb7608aabfdce52..d68c57a62bcf72694b7705292ac3a61592dc67af 100644 (file)
@@ -343,9 +343,9 @@ static int cap_file_fcntl(struct file *file, unsigned int cmd,
        return 0;
 }
 
-static int cap_file_set_fowner(struct file *file)
+static void cap_file_set_fowner(struct file *file)
 {
-       return 0;
+       return;
 }
 
 static int cap_file_send_sigiotask(struct task_struct *tsk,
index 245c6d92065b36ae748c6936d696d4a2222d9b9d..b76235ae4786f2c34bc26072fad69bf457b124ce 100644 (file)
@@ -1,11 +1,23 @@
 #
 config INTEGRITY
-       def_bool y
-       depends on IMA || EVM
+       bool "Integrity subsystem"
+       depends on SECURITY
+       default y
+       help
+         This option enables the integrity subsystem, which is comprised
+         of a number of different components including the Integrity
+         Measurement Architecture (IMA), Extended Verification Module
+         (EVM), IMA-appraisal extension, digital signature verification
+         extension and audit measurement log support.
+
+         Each of these components can be enabled/disabled separately.
+         Refer to the individual components for additional details.
+
+if INTEGRITY
 
 config INTEGRITY_SIGNATURE
        boolean "Digital signature verification using multiple keyrings"
-       depends on INTEGRITY && KEYS
+       depends on KEYS
        default n
        select SIGNATURE
        help
@@ -17,9 +29,21 @@ config INTEGRITY_SIGNATURE
          This is useful for evm and module keyrings, when keys are
          usually only added from initramfs.
 
+config INTEGRITY_ASYMMETRIC_KEYS
+       boolean "Enable asymmetric keys support"
+       depends on INTEGRITY_SIGNATURE
+       default n
+        select ASYMMETRIC_KEY_TYPE
+        select ASYMMETRIC_PUBLIC_KEY_SUBTYPE
+        select PUBLIC_KEY_ALGO_RSA
+        select X509_CERTIFICATE_PARSER
+       help
+         This option enables digital signature verification using
+         asymmetric keys.
+
 config INTEGRITY_AUDIT
        bool "Enables integrity auditing support "
-       depends on INTEGRITY && AUDIT
+       depends on AUDIT
        default y
        help
          In addition to enabling integrity auditing support, this
@@ -32,17 +56,7 @@ config INTEGRITY_AUDIT
          be enabled by specifying 'integrity_audit=1' on the kernel
          command line.
 
-config INTEGRITY_ASYMMETRIC_KEYS
-       boolean "Enable asymmetric keys support"
-       depends on INTEGRITY_SIGNATURE
-       default n
-        select ASYMMETRIC_KEY_TYPE
-        select ASYMMETRIC_PUBLIC_KEY_SUBTYPE
-        select PUBLIC_KEY_ALGO_RSA
-        select X509_CERTIFICATE_PARSER
-       help
-         This option enables digital signature verification using
-         asymmetric keys.
-
 source security/integrity/ima/Kconfig
 source security/integrity/evm/Kconfig
+
+endif   # if INTEGRITY
index 0793f4811cb7d6644def01b8563d8bc913619fe0..8d1f4bf5108759188ba843e3ef7ba4e4ad5ae1c1 100644 (file)
@@ -3,11 +3,11 @@
 #
 
 obj-$(CONFIG_INTEGRITY) += integrity.o
-obj-$(CONFIG_INTEGRITY_AUDIT) += integrity_audit.o
-obj-$(CONFIG_INTEGRITY_SIGNATURE) += digsig.o
-obj-$(CONFIG_INTEGRITY_ASYMMETRIC_KEYS) += digsig_asymmetric.o
 
 integrity-y := iint.o
+integrity-$(CONFIG_INTEGRITY_AUDIT) += integrity_audit.o
+integrity-$(CONFIG_INTEGRITY_SIGNATURE) += digsig.o
+integrity-$(CONFIG_INTEGRITY_ASYMMETRIC_KEYS) += digsig_asymmetric.o
 
 subdir-$(CONFIG_IMA)                   += ima
 obj-$(CONFIG_IMA)                      += ima/
index 9eae4809006be6f364ed9e5fe31ccb897381b856..4fec1816a2b3b18385a2ec5c5590e4d72dc7775b 100644 (file)
@@ -13,6 +13,7 @@
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 
 #include <linux/err.h>
+#include <linux/ratelimit.h>
 #include <linux/key-type.h>
 #include <crypto/public_key.h>
 #include <keys/asymmetric-type.h>
@@ -27,7 +28,7 @@ static struct key *request_asymmetric_key(struct key *keyring, uint32_t keyid)
        struct key *key;
        char name[12];
 
-       sprintf(name, "id:%x", keyid);
+       sprintf(name, "id:%08x", keyid);
 
        pr_debug("key search: \"%s\"\n", name);
 
@@ -45,8 +46,8 @@ static struct key *request_asymmetric_key(struct key *keyring, uint32_t keyid)
        }
 
        if (IS_ERR(key)) {
-               pr_warn("Request for unknown key '%s' err %ld\n",
-                       name, PTR_ERR(key));
+               pr_err_ratelimited("Request for unknown key '%s' err %ld\n",
+                                  name, PTR_ERR(key));
                switch (PTR_ERR(key)) {
                        /* Hide some search errors */
                case -EACCES:
index d606f3d12d6bfb8f27d849a3b4fa9fc9ee411875..df586fa00ef1e9891efae42d629e952c05eaec4d 100644 (file)
@@ -1,6 +1,5 @@
 config EVM
        boolean "EVM support"
-       depends on SECURITY
        select KEYS
        select ENCRYPTED_KEYS
        select CRYPTO_HMAC
@@ -12,10 +11,6 @@ config EVM
 
          If you are unsure how to answer this question, answer N.
 
-if EVM
-
-menu "EVM options"
-
 config EVM_ATTR_FSUUID
        bool "FSUUID (version 2)"
        default y
@@ -47,6 +42,3 @@ config EVM_EXTRA_SMACK_XATTRS
          additional info to the calculation, requires existing EVM
          labeled file systems to be relabeled.
 
-endmenu
-
-endif
index 3bcb80df4d01f1ca30927c7e61c6b2b19b5ca15f..9685af330de5db40f4d7d097ea736b377dd68b36 100644 (file)
@@ -126,14 +126,15 @@ static enum integrity_status evm_verify_hmac(struct dentry *dentry,
        rc = vfs_getxattr_alloc(dentry, XATTR_NAME_EVM, (char **)&xattr_data, 0,
                                GFP_NOFS);
        if (rc <= 0) {
-               if (rc == 0)
-                       evm_status = INTEGRITY_FAIL; /* empty */
-               else if (rc == -ENODATA) {
+               evm_status = INTEGRITY_FAIL;
+               if (rc == -ENODATA) {
                        rc = evm_find_protected_xattrs(dentry);
                        if (rc > 0)
                                evm_status = INTEGRITY_NOLABEL;
                        else if (rc == 0)
                                evm_status = INTEGRITY_NOXATTRS; /* new file */
+               } else if (rc == -EOPNOTSUPP) {
+                       evm_status = INTEGRITY_UNKNOWN;
                }
                goto out;
        }
@@ -284,6 +285,13 @@ static int evm_protect_xattr(struct dentry *dentry, const char *xattr_name,
                goto out;
        }
        evm_status = evm_verify_current_integrity(dentry);
+       if (evm_status == INTEGRITY_NOXATTRS) {
+               struct integrity_iint_cache *iint;
+
+               iint = integrity_iint_find(dentry->d_inode);
+               if (iint && (iint->flags & IMA_NEW_FILE))
+                       return 0;
+       }
 out:
        if (evm_status != INTEGRITY_PASS)
                integrity_audit_msg(AUDIT_INTEGRITY_METADATA, dentry->d_inode,
@@ -352,7 +360,6 @@ void evm_inode_post_setxattr(struct dentry *dentry, const char *xattr_name,
                return;
 
        evm_update_evmxattr(dentry, xattr_name, xattr_value, xattr_value_len);
-       return;
 }
 
 /**
@@ -372,7 +379,6 @@ void evm_inode_post_removexattr(struct dentry *dentry, const char *xattr_name)
        mutex_lock(&inode->i_mutex);
        evm_update_evmxattr(dentry, xattr_name, NULL, 0);
        mutex_unlock(&inode->i_mutex);
-       return;
 }
 
 /**
@@ -414,7 +420,6 @@ void evm_inode_post_setattr(struct dentry *dentry, int ia_valid)
 
        if (ia_valid & (ATTR_MODE | ATTR_UID | ATTR_GID))
                evm_update_evmxattr(dentry, NULL, NULL, 0);
-       return;
 }
 
 /*
index 08758fbd496f90c9176a726d3f48b7d91bb3e82a..e099875643c54b11b3aabe7031b5a5fbcbee342d 100644 (file)
@@ -2,8 +2,6 @@
 #
 config IMA
        bool "Integrity Measurement Architecture(IMA)"
-       depends on SECURITY
-       select INTEGRITY
        select SECURITYFS
        select CRYPTO
        select CRYPTO_HMAC
index 57da4bd7ba0c9cf0c465daaceeaaa77cdfe5f21d..8ee997dff13937521157d02c6aac27b25903b46f 100644 (file)
@@ -43,6 +43,9 @@ enum tpm_pcrs { TPM_PCR0 = 0, TPM_PCR8 = 8 };
 #define IMA_TEMPLATE_IMA_NAME "ima"
 #define IMA_TEMPLATE_IMA_FMT "d|n"
 
+/* current content of the policy */
+extern int ima_policy_flag;
+
 /* set during initialization */
 extern int ima_initialized;
 extern int ima_used_chip;
@@ -90,10 +93,7 @@ extern struct list_head ima_measurements;    /* list of all measurements */
 
 /* Internal IMA function definitions */
 int ima_init(void);
-void ima_cleanup(void);
 int ima_fs_init(void);
-void ima_fs_cleanup(void);
-int ima_inode_alloc(struct inode *inode);
 int ima_add_template_entry(struct ima_template_entry *entry, int violation,
                           const char *op, struct inode *inode,
                           const unsigned char *filename);
@@ -110,8 +110,6 @@ void ima_print_digest(struct seq_file *m, u8 *digest, int size);
 struct ima_template_desc *ima_template_desc_current(void);
 int ima_init_template(void);
 
-int ima_init_template(void);
-
 /*
  * used to protect h_table and sha_table
  */
@@ -151,12 +149,6 @@ int ima_store_template(struct ima_template_entry *entry, int violation,
 void ima_free_template_entry(struct ima_template_entry *entry);
 const char *ima_d_path(struct path *path, char **pathbuf);
 
-/* rbtree tree calls to lookup, insert, delete
- * integrity data associated with an inode.
- */
-struct integrity_iint_cache *integrity_iint_insert(struct inode *inode);
-struct integrity_iint_cache *integrity_iint_find(struct inode *inode);
-
 /* IMA policy related functions */
 enum ima_hooks { FILE_CHECK = 1, MMAP_CHECK, BPRM_CHECK, MODULE_CHECK, FIRMWARE_CHECK, POST_SETATTR };
 
@@ -164,20 +156,22 @@ int ima_match_policy(struct inode *inode, enum ima_hooks func, int mask,
                     int flags);
 void ima_init_policy(void);
 void ima_update_policy(void);
+void ima_update_policy_flag(void);
 ssize_t ima_parse_add_rule(char *);
 void ima_delete_rules(void);
 
 /* Appraise integrity measurements */
 #define IMA_APPRAISE_ENFORCE   0x01
 #define IMA_APPRAISE_FIX       0x02
-#define IMA_APPRAISE_MODULES   0x04
-#define IMA_APPRAISE_FIRMWARE  0x08
+#define IMA_APPRAISE_LOG       0x04
+#define IMA_APPRAISE_MODULES   0x08
+#define IMA_APPRAISE_FIRMWARE  0x10
 
 #ifdef CONFIG_IMA_APPRAISE
 int ima_appraise_measurement(int func, struct integrity_iint_cache *iint,
                             struct file *file, const unsigned char *filename,
                             struct evm_ima_xattr_data *xattr_value,
-                            int xattr_len);
+                            int xattr_len, int opened);
 int ima_must_appraise(struct inode *inode, int mask, enum ima_hooks func);
 void ima_update_xattr(struct integrity_iint_cache *iint, struct file *file);
 enum integrity_status ima_get_cache_status(struct integrity_iint_cache *iint,
@@ -193,7 +187,7 @@ static inline int ima_appraise_measurement(int func,
                                           struct file *file,
                                           const unsigned char *filename,
                                           struct evm_ima_xattr_data *xattr_value,
-                                          int xattr_len)
+                                          int xattr_len, int opened)
 {
        return INTEGRITY_UNKNOWN;
 }
index d9cd5ce14d2be3a341e9046213dfe6bb2b4c1306..86885979918c187fef5298c86ba9de7a97ab968b 100644 (file)
@@ -179,11 +179,6 @@ int ima_get_action(struct inode *inode, int mask, int function)
        return ima_match_policy(inode, function, mask, flags);
 }
 
-int ima_must_measure(struct inode *inode, int mask, int function)
-{
-       return ima_match_policy(inode, function, mask, IMA_MEASURE);
-}
-
 /*
  * ima_collect_measurement - collect file measurement
  *
@@ -330,10 +325,9 @@ const char *ima_d_path(struct path *path, char **pathbuf)
 {
        char *pathname = NULL;
 
-       /* We will allow 11 spaces for ' (deleted)' to be appended */
-       *pathbuf = kmalloc(PATH_MAX + 11, GFP_KERNEL);
+       *pathbuf = kmalloc(PATH_MAX, GFP_KERNEL);
        if (*pathbuf) {
-               pathname = d_path(path, *pathbuf, PATH_MAX + 11);
+               pathname = d_absolute_path(path, *pathbuf, PATH_MAX);
                if (IS_ERR(pathname)) {
                        kfree(*pathbuf);
                        *pathbuf = NULL;
index 86bfd5c5df85e0bec07bc6be5e7ab58bd98c945c..922685483bd3625355af6202bb435728ac62c11f 100644 (file)
@@ -23,6 +23,8 @@ static int __init default_appraise_setup(char *str)
 {
        if (strncmp(str, "off", 3) == 0)
                ima_appraise = 0;
+       else if (strncmp(str, "log", 3) == 0)
+               ima_appraise = IMA_APPRAISE_LOG;
        else if (strncmp(str, "fix", 3) == 0)
                ima_appraise = IMA_APPRAISE_FIX;
        return 1;
@@ -183,7 +185,7 @@ int ima_read_xattr(struct dentry *dentry,
 int ima_appraise_measurement(int func, struct integrity_iint_cache *iint,
                             struct file *file, const unsigned char *filename,
                             struct evm_ima_xattr_data *xattr_value,
-                            int xattr_len)
+                            int xattr_len, int opened)
 {
        static const char op[] = "appraise_data";
        char *cause = "unknown";
@@ -192,8 +194,6 @@ int ima_appraise_measurement(int func, struct integrity_iint_cache *iint,
        enum integrity_status status = INTEGRITY_UNKNOWN;
        int rc = xattr_len, hash_start = 0;
 
-       if (!ima_appraise)
-               return 0;
        if (!inode->i_op->getxattr)
                return INTEGRITY_UNKNOWN;
 
@@ -202,8 +202,11 @@ int ima_appraise_measurement(int func, struct integrity_iint_cache *iint,
                        goto out;
 
                cause = "missing-hash";
-               status =
-                   (inode->i_size == 0) ? INTEGRITY_PASS : INTEGRITY_NOLABEL;
+               status = INTEGRITY_NOLABEL;
+               if (opened & FILE_CREATED) {
+                       iint->flags |= IMA_NEW_FILE;
+                       status = INTEGRITY_PASS;
+               }
                goto out;
        }
 
@@ -315,7 +318,7 @@ void ima_inode_post_setattr(struct dentry *dentry)
        struct integrity_iint_cache *iint;
        int must_appraise, rc;
 
-       if (!ima_initialized || !ima_appraise || !S_ISREG(inode->i_mode)
+       if (!(ima_policy_flag & IMA_APPRAISE) || !S_ISREG(inode->i_mode)
            || !inode->i_op->removexattr)
                return;
 
@@ -353,7 +356,7 @@ static void ima_reset_appraise_flags(struct inode *inode, int digsig)
 {
        struct integrity_iint_cache *iint;
 
-       if (!ima_initialized || !ima_appraise || !S_ISREG(inode->i_mode))
+       if (!(ima_policy_flag & IMA_APPRAISE) || !S_ISREG(inode->i_mode))
                return;
 
        iint = integrity_iint_find(inode);
index 0bd732843fe70861b0d1bb58bceada6c972f8122..d34e7dfc1118070a5888fd12629e388ee9aeae65 100644 (file)
@@ -80,24 +80,24 @@ static int ima_kernel_read(struct file *file, loff_t offset,
 {
        mm_segment_t old_fs;
        char __user *buf = addr;
-       ssize_t ret;
+       ssize_t ret = -EINVAL;
 
        if (!(file->f_mode & FMODE_READ))
                return -EBADF;
-       if (!file->f_op->read && !file->f_op->aio_read)
-               return -EINVAL;
 
        old_fs = get_fs();
        set_fs(get_ds());
        if (file->f_op->read)
                ret = file->f_op->read(file, buf, count, &offset);
-       else
+       else if (file->f_op->aio_read)
                ret = do_sync_read(file, buf, count, &offset);
+       else if (file->f_op->read_iter)
+               ret = new_sync_read(file, buf, count, &offset);
        set_fs(old_fs);
        return ret;
 }
 
-int ima_init_crypto(void)
+int __init ima_init_crypto(void)
 {
        long rc;
 
@@ -116,7 +116,10 @@ static struct crypto_shash *ima_alloc_tfm(enum hash_algo algo)
        struct crypto_shash *tfm = ima_shash_tfm;
        int rc;
 
-       if (algo != ima_hash_algo && algo < HASH_ALGO__LAST) {
+       if (algo < 0 || algo >= HASH_ALGO__LAST)
+               algo = ima_hash_algo;
+
+       if (algo != ima_hash_algo) {
                tfm = crypto_alloc_shash(hash_algo_name[algo], 0, 0);
                if (IS_ERR(tfm)) {
                        rc = PTR_ERR(tfm);
@@ -200,7 +203,10 @@ static struct crypto_ahash *ima_alloc_atfm(enum hash_algo algo)
        struct crypto_ahash *tfm = ima_ahash_tfm;
        int rc;
 
-       if ((algo != ima_hash_algo && algo < HASH_ALGO__LAST) || !tfm) {
+       if (algo < 0 || algo >= HASH_ALGO__LAST)
+               algo = ima_hash_algo;
+
+       if (algo != ima_hash_algo || !tfm) {
                tfm = crypto_alloc_ahash(hash_algo_name[algo], 0, 0);
                if (!IS_ERR(tfm)) {
                        if (algo == ima_hash_algo)
index e8f9d70a465d11168748967928e34491f46c1765..9164fc8cac84adb53d79b867d7547fcaaf35aa70 100644 (file)
@@ -43,7 +43,7 @@ int ima_used_chip;
  * a different value.) Violations add a zero entry to the measurement
  * list and extend the aggregate PCR value with ff...ff's.
  */
-static void __init ima_add_boot_aggregate(void)
+static int __init ima_add_boot_aggregate(void)
 {
        static const char op[] = "add_boot_aggregate";
        const char *audit_cause = "ENOMEM";
@@ -72,17 +72,23 @@ static void __init ima_add_boot_aggregate(void)
 
        result = ima_alloc_init_template(iint, NULL, boot_aggregate_name,
                                         NULL, 0, &entry);
-       if (result < 0)
-               return;
+       if (result < 0) {
+               audit_cause = "alloc_entry";
+               goto err_out;
+       }
 
        result = ima_store_template(entry, violation, NULL,
                                    boot_aggregate_name);
-       if (result < 0)
+       if (result < 0) {
                ima_free_template_entry(entry);
-       return;
+               audit_cause = "store_entry";
+               goto err_out;
+       }
+       return 0;
 err_out:
        integrity_audit_msg(AUDIT_INTEGRITY_PCR, NULL, boot_aggregate_name, op,
                            audit_cause, result, 0);
+       return result;
 }
 
 int __init ima_init(void)
@@ -98,6 +104,10 @@ int __init ima_init(void)
        if (!ima_used_chip)
                pr_info("No TPM chip found, activating TPM-bypass!\n");
 
+       rc = ima_init_keyring(INTEGRITY_KEYRING_IMA);
+       if (rc)
+               return rc;
+
        rc = ima_init_crypto();
        if (rc)
                return rc;
@@ -105,7 +115,10 @@ int __init ima_init(void)
        if (rc != 0)
                return rc;
 
-       ima_add_boot_aggregate();       /* boot aggregate must be first entry */
+       rc = ima_add_boot_aggregate();  /* boot aggregate must be first entry */
+       if (rc != 0)
+               return rc;
+
        ima_init_policy();
 
        return ima_fs_init();
index 2917f980bf3075c3dacff3531cf03d8e4e39e6f6..62f59eca32d3099fb8199aaf6b80db42197d53ec 100644 (file)
@@ -77,42 +77,39 @@ __setup("ima_hash=", hash_setup);
  *       could result in a file measurement error.
  *
  */
-static void ima_rdwr_violation_check(struct file *file)
+static void ima_rdwr_violation_check(struct file *file,
+                                    struct integrity_iint_cache *iint,
+                                    int must_measure,
+                                    char **pathbuf,
+                                    const char **pathname)
 {
        struct inode *inode = file_inode(file);
        fmode_t mode = file->f_mode;
        bool send_tomtou = false, send_writers = false;
-       char *pathbuf = NULL;
-       const char *pathname;
-
-       if (!S_ISREG(inode->i_mode) || !ima_initialized)
-               return;
 
        if (mode & FMODE_WRITE) {
                if (atomic_read(&inode->i_readcount) && IS_IMA(inode)) {
-                       struct integrity_iint_cache *iint;
-                       iint = integrity_iint_find(inode);
+                       if (!iint)
+                               iint = integrity_iint_find(inode);
                        /* IMA_MEASURE is set from reader side */
                        if (iint && (iint->flags & IMA_MEASURE))
                                send_tomtou = true;
                }
        } else {
-               if ((atomic_read(&inode->i_writecount) > 0) &&
-                   ima_must_measure(inode, MAY_READ, FILE_CHECK))
+               if ((atomic_read(&inode->i_writecount) > 0) && must_measure)
                        send_writers = true;
        }
 
        if (!send_tomtou && !send_writers)
                return;
 
-       pathname = ima_d_path(&file->f_path, &pathbuf);
+       *pathname = ima_d_path(&file->f_path, pathbuf);
 
        if (send_tomtou)
-               ima_add_violation(file, pathname, "invalid_pcr", "ToMToU");
+               ima_add_violation(file, *pathname, "invalid_pcr", "ToMToU");
        if (send_writers)
-               ima_add_violation(file, pathname,
+               ima_add_violation(file, *pathname,
                                  "invalid_pcr", "open_writers");
-       kfree(pathbuf);
 }
 
 static void ima_check_last_writer(struct integrity_iint_cache *iint,
@@ -124,11 +121,13 @@ static void ima_check_last_writer(struct integrity_iint_cache *iint,
                return;
 
        mutex_lock(&inode->i_mutex);
-       if (atomic_read(&inode->i_writecount) == 1 &&
-           iint->version != inode->i_version) {
-               iint->flags &= ~IMA_DONE_MASK;
-               if (iint->flags & IMA_APPRAISE)
-                       ima_update_xattr(iint, file);
+       if (atomic_read(&inode->i_writecount) == 1) {
+               if ((iint->version != inode->i_version) ||
+                   (iint->flags & IMA_NEW_FILE)) {
+                       iint->flags &= ~(IMA_DONE_MASK | IMA_NEW_FILE);
+                       if (iint->flags & IMA_APPRAISE)
+                               ima_update_xattr(iint, file);
+               }
        }
        mutex_unlock(&inode->i_mutex);
 }
@@ -154,19 +153,20 @@ void ima_file_free(struct file *file)
        ima_check_last_writer(iint, inode, file);
 }
 
-static int process_measurement(struct file *file, const char *filename,
-                              int mask, int function)
+static int process_measurement(struct file *file, int mask, int function,
+                              int opened)
 {
        struct inode *inode = file_inode(file);
-       struct integrity_iint_cache *iint;
+       struct integrity_iint_cache *iint = NULL;
        struct ima_template_desc *template_desc;
        char *pathbuf = NULL;
        const char *pathname = NULL;
-       int rc = -ENOMEM, action, must_appraise, _func;
+       int rc = -ENOMEM, action, must_appraise;
        struct evm_ima_xattr_data *xattr_value = NULL, **xattr_ptr = NULL;
        int xattr_len = 0;
+       bool violation_check;
 
-       if (!ima_initialized || !S_ISREG(inode->i_mode))
+       if (!ima_policy_flag || !S_ISREG(inode->i_mode))
                return 0;
 
        /* Return an IMA_MEASURE, IMA_APPRAISE, IMA_AUDIT action
@@ -174,19 +174,33 @@ static int process_measurement(struct file *file, const char *filename,
         * Included is the appraise submask.
         */
        action = ima_get_action(inode, mask, function);
-       if (!action)
+       violation_check = ((function == FILE_CHECK || function == MMAP_CHECK) &&
+                          (ima_policy_flag & IMA_MEASURE));
+       if (!action && !violation_check)
                return 0;
 
        must_appraise = action & IMA_APPRAISE;
 
        /*  Is the appraise rule hook specific?  */
-       _func = (action & IMA_FILE_APPRAISE) ? FILE_CHECK : function;
+       if (action & IMA_FILE_APPRAISE)
+               function = FILE_CHECK;
 
        mutex_lock(&inode->i_mutex);
 
-       iint = integrity_inode_get(inode);
-       if (!iint)
-               goto out;
+       if (action) {
+               iint = integrity_inode_get(inode);
+               if (!iint)
+                       goto out;
+       }
+
+       if (violation_check) {
+               ima_rdwr_violation_check(file, iint, action & IMA_MEASURE,
+                                        &pathbuf, &pathname);
+               if (!action) {
+                       rc = 0;
+                       goto out_free;
+               }
+       }
 
        /* Determine if already appraised/measured based on bitmask
         * (IMA_MEASURE, IMA_MEASURED, IMA_XXXX_APPRAISE, IMA_XXXX_APPRAISED,
@@ -199,15 +213,13 @@ static int process_measurement(struct file *file, const char *filename,
        /* Nothing to do, just return existing appraised status */
        if (!action) {
                if (must_appraise)
-                       rc = ima_get_cache_status(iint, _func);
+                       rc = ima_get_cache_status(iint, function);
                goto out_digsig;
        }
 
        template_desc = ima_template_desc_current();
-       if (strcmp(template_desc->name, IMA_TEMPLATE_IMA_NAME) == 0) {
-               if (action & IMA_APPRAISE_SUBMASK)
-                       xattr_ptr = &xattr_value;
-       } else
+       if ((action & IMA_APPRAISE_SUBMASK) ||
+                   strcmp(template_desc->name, IMA_TEMPLATE_IMA_NAME) != 0)
                xattr_ptr = &xattr_value;
 
        rc = ima_collect_measurement(iint, file, xattr_ptr, &xattr_len);
@@ -217,23 +229,26 @@ static int process_measurement(struct file *file, const char *filename,
                goto out_digsig;
        }
 
-       pathname = filename ?: ima_d_path(&file->f_path, &pathbuf);
+       if (!pathname)  /* ima_rdwr_violation possibly pre-fetched */
+               pathname = ima_d_path(&file->f_path, &pathbuf);
 
        if (action & IMA_MEASURE)
                ima_store_measurement(iint, file, pathname,
                                      xattr_value, xattr_len);
        if (action & IMA_APPRAISE_SUBMASK)
-               rc = ima_appraise_measurement(_func, iint, file, pathname,
-                                             xattr_value, xattr_len);
+               rc = ima_appraise_measurement(function, iint, file, pathname,
+                                             xattr_value, xattr_len, opened);
        if (action & IMA_AUDIT)
                ima_audit_measurement(iint, pathname);
-       kfree(pathbuf);
+
 out_digsig:
        if ((mask & MAY_WRITE) && (iint->flags & IMA_DIGSIG))
                rc = -EACCES;
+       kfree(xattr_value);
+out_free:
+       kfree(pathbuf);
 out:
        mutex_unlock(&inode->i_mutex);
-       kfree(xattr_value);
        if ((rc && must_appraise) && (ima_appraise & IMA_APPRAISE_ENFORCE))
                return -EACCES;
        return 0;
@@ -253,7 +268,7 @@ out:
 int ima_file_mmap(struct file *file, unsigned long prot)
 {
        if (file && (prot & PROT_EXEC))
-               return process_measurement(file, NULL, MAY_EXEC, MMAP_CHECK);
+               return process_measurement(file, MAY_EXEC, MMAP_CHECK, 0);
        return 0;
 }
 
@@ -272,10 +287,7 @@ int ima_file_mmap(struct file *file, unsigned long prot)
  */
 int ima_bprm_check(struct linux_binprm *bprm)
 {
-       return process_measurement(bprm->file,
-                                  (strcmp(bprm->filename, bprm->interp) == 0) ?
-                                  bprm->filename : bprm->interp,
-                                  MAY_EXEC, BPRM_CHECK);
+       return process_measurement(bprm->file, MAY_EXEC, BPRM_CHECK, 0);
 }
 
 /**
@@ -288,12 +300,11 @@ int ima_bprm_check(struct linux_binprm *bprm)
  * On success return 0.  On integrity appraisal error, assuming the file
  * is in policy and IMA-appraisal is in enforcing mode, return -EACCES.
  */
-int ima_file_check(struct file *file, int mask)
+int ima_file_check(struct file *file, int mask, int opened)
 {
-       ima_rdwr_violation_check(file);
-       return process_measurement(file, NULL,
+       return process_measurement(file,
                                   mask & (MAY_READ | MAY_WRITE | MAY_EXEC),
-                                  FILE_CHECK);
+                                  FILE_CHECK, opened);
 }
 EXPORT_SYMBOL_GPL(ima_file_check);
 
@@ -316,7 +327,7 @@ int ima_module_check(struct file *file)
 #endif
                return 0;       /* We rely on module signature checking */
        }
-       return process_measurement(file, NULL, MAY_EXEC, MODULE_CHECK);
+       return process_measurement(file, MAY_EXEC, MODULE_CHECK, 0);
 }
 
 int ima_fw_from_file(struct file *file, char *buf, size_t size)
@@ -327,7 +338,7 @@ int ima_fw_from_file(struct file *file, char *buf, size_t size)
                        return -EACCES; /* INTEGRITY_UNKNOWN */
                return 0;
        }
-       return process_measurement(file, NULL, MAY_EXEC, FIRMWARE_CHECK);
+       return process_measurement(file, MAY_EXEC, FIRMWARE_CHECK, 0);
 }
 
 static int __init init_ima(void)
@@ -336,14 +347,10 @@ static int __init init_ima(void)
 
        hash_setup(CONFIG_IMA_DEFAULT_HASH);
        error = ima_init();
-       if (error)
-               goto out;
-
-       error = ima_init_keyring(INTEGRITY_KEYRING_IMA);
-       if (error)
-               goto out;
-       ima_initialized = 1;
-out:
+       if (!error) {
+               ima_initialized = 1;
+               ima_update_policy_flag();
+       }
        return error;
 }
 
index 07099a8bc2835d8a8bb0ef3f7ec2f826796fd270..cdc620b2152f9431ddd9e73e651ecc4587802939 100644 (file)
@@ -35,6 +35,8 @@
 #define DONT_APPRAISE  0x0008
 #define AUDIT          0x0040
 
+int ima_policy_flag;
+
 #define MAX_LSM_RULES 6
 enum lsm_rule_types { LSM_OBJ_USER, LSM_OBJ_ROLE, LSM_OBJ_TYPE,
        LSM_SUBJ_USER, LSM_SUBJ_ROLE, LSM_SUBJ_TYPE
@@ -295,6 +297,26 @@ int ima_match_policy(struct inode *inode, enum ima_hooks func, int mask,
        return action;
 }
 
+/*
+ * Initialize the ima_policy_flag variable based on the currently
+ * loaded policy.  Based on this flag, the decision to short circuit
+ * out of a function or not call the function in the first place
+ * can be made earlier.
+ */
+void ima_update_policy_flag(void)
+{
+       struct ima_rule_entry *entry;
+
+       ima_policy_flag = 0;
+       list_for_each_entry(entry, ima_rules, list) {
+               if (entry->action & IMA_DO_MASK)
+                       ima_policy_flag |= entry->action;
+       }
+
+       if (!ima_appraise)
+               ima_policy_flag &= ~IMA_APPRAISE;
+}
+
 /**
  * ima_init_policy - initialize the default measure rules.
  *
@@ -341,6 +363,7 @@ void ima_update_policy(void)
 
        if (ima_rules == &ima_default_rules) {
                ima_rules = &ima_policy_rules;
+               ima_update_policy_flag();
                cause = "complete";
                result = 0;
        }
index a076a967ec4768f64ebfcd0a84509080e7eb6b18..e854862c9337d7ad52f8b4d59f801ec180f6513c 100644 (file)
@@ -152,24 +152,6 @@ out:
        return result;
 }
 
-static int init_defined_templates(void)
-{
-       int i = 0;
-       int result = 0;
-
-       /* Init defined templates. */
-       for (i = 0; i < ARRAY_SIZE(defined_templates); i++) {
-               struct ima_template_desc *template = &defined_templates[i];
-
-               result = template_desc_init_fields(template->fmt,
-                                                  &(template->fields),
-                                                  &(template->num_fields));
-               if (result < 0)
-                       return result;
-       }
-       return result;
-}
-
 struct ima_template_desc *ima_template_desc_current(void)
 {
        if (!ima_template)
@@ -178,13 +160,11 @@ struct ima_template_desc *ima_template_desc_current(void)
        return ima_template;
 }
 
-int ima_init_template(void)
+int __init ima_init_template(void)
 {
-       int result;
-
-       result = init_defined_templates();
-       if (result < 0)
-               return result;
+       struct ima_template_desc *template = ima_template_desc_current();
 
-       return 0;
+       return template_desc_init_fields(template->fmt,
+                                        &(template->fields),
+                                        &(template->num_fields));
 }
index 19b8e314ca964efdff3cf7ddf30851f9f0e29d80..c0379d13dbe16f8d4c9705e1c80fd8b2c7b0e4df 100644 (file)
@@ -31,6 +31,7 @@
 #define IMA_DIGSIG             0x01000000
 #define IMA_DIGSIG_REQUIRED    0x02000000
 #define IMA_PERMIT_DIRECTIO    0x04000000
+#define IMA_NEW_FILE           0x08000000
 
 #define IMA_DO_MASK            (IMA_MEASURE | IMA_APPRAISE | IMA_AUDIT | \
                                 IMA_APPRAISE_SUBMASK)
@@ -116,7 +117,6 @@ struct integrity_iint_cache {
 /* rbtree tree calls to lookup, insert, delete
  * integrity data associated with an inode.
  */
-struct integrity_iint_cache *integrity_iint_insert(struct inode *inode);
 struct integrity_iint_cache *integrity_iint_find(struct inode *inode);
 
 #define INTEGRITY_KEYRING_EVM          0
index c2f91a0cf8899cb0d8d69fd06ebcc05405cf45f7..b6adb94f6d52573aecf2e38a16724e06895dded6 100644 (file)
@@ -33,11 +33,9 @@ MODULE_LICENSE("GPL");
  */
 struct key_type key_type_big_key = {
        .name                   = "big_key",
-       .def_lookup_type        = KEYRING_SEARCH_LOOKUP_DIRECT,
        .preparse               = big_key_preparse,
        .free_preparse          = big_key_free_preparse,
        .instantiate            = generic_key_instantiate,
-       .match                  = user_match,
        .revoke                 = big_key_revoke,
        .destroy                = big_key_destroy,
        .describe               = big_key_describe,
index 5fe443d120afe81826902cc70efecff24ccee1bb..db9675db10262021612016bed79ade14a960d089 100644 (file)
@@ -970,7 +970,6 @@ struct key_type key_type_encrypted = {
        .name = "encrypted",
        .instantiate = encrypted_instantiate,
        .update = encrypted_update,
-       .match = user_match,
        .destroy = encrypted_destroy,
        .describe = user_describe,
        .read = encrypted_read,
index 5f20da01fd8d317f835375de9654f42c1a1b4e8b..b8960c4959a5e53635180054d27d788105ebf134 100644 (file)
@@ -107,20 +107,16 @@ extern int iterate_over_keyring(const struct key *keyring,
                                int (*func)(const struct key *key, void *data),
                                void *data);
 
-typedef int (*key_match_func_t)(const struct key *, const void *);
-
 struct keyring_search_context {
        struct keyring_index_key index_key;
        const struct cred       *cred;
-       key_match_func_t        match;
-       const void              *match_data;
+       struct key_match_data   match_data;
        unsigned                flags;
-#define KEYRING_SEARCH_LOOKUP_TYPE     0x0001  /* [as type->def_lookup_type] */
-#define KEYRING_SEARCH_NO_STATE_CHECK  0x0002  /* Skip state checks */
-#define KEYRING_SEARCH_DO_STATE_CHECK  0x0004  /* Override NO_STATE_CHECK */
-#define KEYRING_SEARCH_NO_UPDATE_TIME  0x0008  /* Don't update times */
-#define KEYRING_SEARCH_NO_CHECK_PERM   0x0010  /* Don't check permissions */
-#define KEYRING_SEARCH_DETECT_TOO_DEEP 0x0020  /* Give an error on excessive depth */
+#define KEYRING_SEARCH_NO_STATE_CHECK  0x0001  /* Skip state checks */
+#define KEYRING_SEARCH_DO_STATE_CHECK  0x0002  /* Override NO_STATE_CHECK */
+#define KEYRING_SEARCH_NO_UPDATE_TIME  0x0004  /* Don't update times */
+#define KEYRING_SEARCH_NO_CHECK_PERM   0x0008  /* Don't check permissions */
+#define KEYRING_SEARCH_DETECT_TOO_DEEP 0x0010  /* Give an error on excessive depth */
 
        int (*iterator)(const void *object, void *iterator_data);
 
@@ -131,6 +127,8 @@ struct keyring_search_context {
        struct timespec         now;
 };
 
+extern bool key_default_cmp(const struct key *key,
+                           const struct key_match_data *match_data);
 extern key_ref_t keyring_search_aux(key_ref_t keyring_ref,
                                    struct keyring_search_context *ctx);
 
@@ -152,7 +150,8 @@ extern struct key *request_key_and_link(struct key_type *type,
                                        struct key *dest_keyring,
                                        unsigned long flags);
 
-extern int lookup_user_key_possessed(const struct key *key, const void *target);
+extern bool lookup_user_key_possessed(const struct key *key,
+                                     const struct key_match_data *match_data);
 extern key_ref_t lookup_user_key(key_serial_t id, unsigned long flags,
                                 key_perm_t perm);
 #define KEY_LOOKUP_CREATE      0x01
index 6d0cad16f00265a1dc31d8a0804984040fb47995..e17ba6aefdc0820b6c5c3af7cfc90d4e20094915 100644 (file)
@@ -799,7 +799,7 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref,
        }
 
        key_ref = ERR_PTR(-EINVAL);
-       if (!index_key.type->match || !index_key.type->instantiate ||
+       if (!index_key.type->instantiate ||
            (!index_key.description && !index_key.type->preparse))
                goto error_put_type;
 
index e26f860e5f2ec5e88e77c797da6c8642b1291697..eff88a5f5d40da17611d381bcf4e219a90bcc972 100644 (file)
@@ -37,6 +37,8 @@ static int key_get_type_from_user(char *type,
                return ret;
        if (ret == 0 || ret >= len)
                return -EINVAL;
+       if (type[0] == '.')
+               return -EPERM;
        type[len - 1] = '\0';
        return 0;
 }
index 8314a7d2104df95ead666466213819504a31d5c2..8177010174f7b3d47773a43e48bf2b171b264c5f 100644 (file)
@@ -89,7 +89,6 @@ struct key_type key_type_keyring = {
        .preparse       = keyring_preparse,
        .free_preparse  = keyring_free_preparse,
        .instantiate    = keyring_instantiate,
-       .match          = user_match,
        .revoke         = keyring_revoke,
        .destroy        = keyring_destroy,
        .describe       = keyring_describe,
@@ -511,6 +510,15 @@ struct key *keyring_alloc(const char *description, kuid_t uid, kgid_t gid,
 }
 EXPORT_SYMBOL(keyring_alloc);
 
+/*
+ * By default, we keys found by getting an exact match on their descriptions.
+ */
+bool key_default_cmp(const struct key *key,
+                    const struct key_match_data *match_data)
+{
+       return strcmp(key->description, match_data->raw_data) == 0;
+}
+
 /*
  * Iteration function to consider each key found.
  */
@@ -545,7 +553,7 @@ static int keyring_search_iterator(const void *object, void *iterator_data)
        }
 
        /* keys that don't match */
-       if (!ctx->match(key, ctx->match_data)) {
+       if (!ctx->match_data.cmp(key, &ctx->match_data)) {
                kleave(" = 0 [!match]");
                return 0;
        }
@@ -585,8 +593,7 @@ skipped:
  */
 static int search_keyring(struct key *keyring, struct keyring_search_context *ctx)
 {
-       if ((ctx->flags & KEYRING_SEARCH_LOOKUP_TYPE) ==
-           KEYRING_SEARCH_LOOKUP_DIRECT) {
+       if (ctx->match_data.lookup_type == KEYRING_SEARCH_LOOKUP_DIRECT) {
                const void *object;
 
                object = assoc_array_find(&keyring->keys,
@@ -627,7 +634,7 @@ static bool search_nested_keyrings(struct key *keyring,
        /* Check to see if this top-level keyring is what we are looking for
         * and whether it is valid or not.
         */
-       if (ctx->flags & KEYRING_SEARCH_LOOKUP_ITERATE ||
+       if (ctx->match_data.lookup_type == KEYRING_SEARCH_LOOKUP_ITERATE ||
            keyring_compare_object(keyring, &ctx->index_key)) {
                ctx->skipped_ret = 2;
                ctx->flags |= KEYRING_SEARCH_DO_STATE_CHECK;
@@ -885,16 +892,25 @@ key_ref_t keyring_search(key_ref_t keyring,
                .index_key.type         = type,
                .index_key.description  = description,
                .cred                   = current_cred(),
-               .match                  = type->match,
-               .match_data             = description,
-               .flags                  = (type->def_lookup_type |
-                                          KEYRING_SEARCH_DO_STATE_CHECK),
+               .match_data.cmp         = key_default_cmp,
+               .match_data.raw_data    = description,
+               .match_data.lookup_type = KEYRING_SEARCH_LOOKUP_DIRECT,
+               .flags                  = KEYRING_SEARCH_DO_STATE_CHECK,
        };
+       key_ref_t key;
+       int ret;
 
-       if (!ctx.match)
-               return ERR_PTR(-ENOKEY);
+       if (type->match_preparse) {
+               ret = type->match_preparse(&ctx.match_data);
+               if (ret < 0)
+                       return ERR_PTR(ret);
+       }
 
-       return keyring_search_aux(keyring, &ctx);
+       key = keyring_search_aux(keyring, &ctx);
+
+       if (type->match_free)
+               type->match_free(&ctx.match_data);
+       return key;
 }
 EXPORT_SYMBOL(keyring_search);
 
@@ -1014,7 +1030,7 @@ static int keyring_detect_cycle_iterator(const void *object,
 
        /* We might get a keyring with matching index-key that is nonetheless a
         * different keyring. */
-       if (key != ctx->match_data)
+       if (key != ctx->match_data.raw_data)
                return 0;
 
        ctx->result = ERR_PTR(-EDEADLK);
@@ -1031,14 +1047,14 @@ static int keyring_detect_cycle_iterator(const void *object,
 static int keyring_detect_cycle(struct key *A, struct key *B)
 {
        struct keyring_search_context ctx = {
-               .index_key      = A->index_key,
-               .match_data     = A,
-               .iterator       = keyring_detect_cycle_iterator,
-               .flags          = (KEYRING_SEARCH_LOOKUP_DIRECT |
-                                  KEYRING_SEARCH_NO_STATE_CHECK |
-                                  KEYRING_SEARCH_NO_UPDATE_TIME |
-                                  KEYRING_SEARCH_NO_CHECK_PERM |
-                                  KEYRING_SEARCH_DETECT_TOO_DEEP),
+               .index_key              = A->index_key,
+               .match_data.raw_data    = A,
+               .match_data.lookup_type = KEYRING_SEARCH_LOOKUP_DIRECT,
+               .iterator               = keyring_detect_cycle_iterator,
+               .flags                  = (KEYRING_SEARCH_NO_STATE_CHECK |
+                                          KEYRING_SEARCH_NO_UPDATE_TIME |
+                                          KEYRING_SEARCH_NO_CHECK_PERM |
+                                          KEYRING_SEARCH_DETECT_TOO_DEEP),
        };
 
        rcu_read_lock();
index d3f6f2fd21db84bc197ed82b14808b6bc9bc4e87..972eeb336b8145b0529001c38f64a53e2e8f8c5a 100644 (file)
@@ -194,10 +194,10 @@ static int proc_keys_show(struct seq_file *m, void *v)
                .index_key.type         = key->type,
                .index_key.description  = key->description,
                .cred                   = current_cred(),
-               .match                  = lookup_user_key_possessed,
-               .match_data             = key,
-               .flags                  = (KEYRING_SEARCH_NO_STATE_CHECK |
-                                          KEYRING_SEARCH_LOOKUP_DIRECT),
+               .match_data.cmp         = lookup_user_key_possessed,
+               .match_data.raw_data    = key,
+               .match_data.lookup_type = KEYRING_SEARCH_LOOKUP_DIRECT,
+               .flags                  = KEYRING_SEARCH_NO_STATE_CHECK,
        };
 
        key_ref = make_key_ref(key, 0);
index 0cf8a130a267ca58fbc5599787c93b9913cfc576..bd536cb221e237c6cab654b4d4d927daf3f27340 100644 (file)
@@ -489,9 +489,10 @@ found:
 /*
  * See if the key we're looking at is the target key.
  */
-int lookup_user_key_possessed(const struct key *key, const void *target)
+bool lookup_user_key_possessed(const struct key *key,
+                              const struct key_match_data *match_data)
 {
-       return key == target;
+       return key == match_data->raw_data;
 }
 
 /*
@@ -516,9 +517,9 @@ key_ref_t lookup_user_key(key_serial_t id, unsigned long lflags,
                          key_perm_t perm)
 {
        struct keyring_search_context ctx = {
-               .match  = lookup_user_key_possessed,
-               .flags  = (KEYRING_SEARCH_NO_STATE_CHECK |
-                          KEYRING_SEARCH_LOOKUP_DIRECT),
+               .match_data.cmp         = lookup_user_key_possessed,
+               .match_data.lookup_type = KEYRING_SEARCH_LOOKUP_DIRECT,
+               .flags                  = KEYRING_SEARCH_NO_STATE_CHECK,
        };
        struct request_key_auth *rka;
        struct key *key;
@@ -673,7 +674,7 @@ try_again:
                ctx.index_key.type              = key->type;
                ctx.index_key.description       = key->description;
                ctx.index_key.desc_len          = strlen(key->description);
-               ctx.match_data                  = key;
+               ctx.match_data.raw_data         = key;
                kdebug("check possessed");
                skey_ref = search_process_keyrings(&ctx);
                kdebug("possessed=%p", skey_ref);
index 26a94f18af9444ef709fbc964de6fc1c92e4a8a5..bb4337c7ae1b3978fd5e36d692d8cacf27b89816 100644 (file)
@@ -513,9 +513,9 @@ struct key *request_key_and_link(struct key_type *type,
                .index_key.type         = type,
                .index_key.description  = description,
                .cred                   = current_cred(),
-               .match                  = type->match,
-               .match_data             = description,
-               .flags                  = KEYRING_SEARCH_LOOKUP_DIRECT,
+               .match_data.cmp         = key_default_cmp,
+               .match_data.raw_data    = description,
+               .match_data.lookup_type = KEYRING_SEARCH_LOOKUP_DIRECT,
        };
        struct key *key;
        key_ref_t key_ref;
@@ -525,6 +525,14 @@ struct key *request_key_and_link(struct key_type *type,
               ctx.index_key.type->name, ctx.index_key.description,
               callout_info, callout_len, aux, dest_keyring, flags);
 
+       if (type->match_preparse) {
+               ret = type->match_preparse(&ctx.match_data);
+               if (ret < 0) {
+                       key = ERR_PTR(ret);
+                       goto error;
+               }
+       }
+
        /* search all the process keyrings for a key */
        key_ref = search_process_keyrings(&ctx);
 
@@ -537,7 +545,7 @@ struct key *request_key_and_link(struct key_type *type,
                        if (ret < 0) {
                                key_put(key);
                                key = ERR_PTR(ret);
-                               goto error;
+                               goto error_free;
                        }
                }
        } else if (PTR_ERR(key_ref) != -EAGAIN) {
@@ -547,12 +555,15 @@ struct key *request_key_and_link(struct key_type *type,
                 * should consult userspace if we can */
                key = ERR_PTR(-ENOKEY);
                if (!callout_info)
-                       goto error;
+                       goto error_free;
 
                key = construct_key_and_link(&ctx, callout_info, callout_len,
                                             aux, dest_keyring, flags);
        }
 
+error_free:
+       if (type->match_free)
+               type->match_free(&ctx.match_data);
 error:
        kleave(" = %p", key);
        return key;
index 842e6f410d5052b6e3dad7c7d0ac8d6290293733..6639e2cb885322c6a43924496b2a68be25b9a5e6 100644 (file)
@@ -44,12 +44,12 @@ struct key_type key_type_request_key_auth = {
        .read           = request_key_auth_read,
 };
 
-int request_key_auth_preparse(struct key_preparsed_payload *prep)
+static int request_key_auth_preparse(struct key_preparsed_payload *prep)
 {
        return 0;
 }
 
-void request_key_auth_free_preparse(struct key_preparsed_payload *prep)
+static void request_key_auth_free_preparse(struct key_preparsed_payload *prep)
 {
 }
 
@@ -246,9 +246,9 @@ struct key *key_get_instantiation_authkey(key_serial_t target_id)
                .index_key.type         = &key_type_request_key_auth,
                .index_key.description  = description,
                .cred                   = current_cred(),
-               .match                  = user_match,
-               .match_data             = description,
-               .flags                  = KEYRING_SEARCH_LOOKUP_DIRECT,
+               .match_data.cmp         = key_default_cmp,
+               .match_data.raw_data    = description,
+               .match_data.lookup_type = KEYRING_SEARCH_LOOKUP_DIRECT,
        };
        struct key *authkey;
        key_ref_t authkey_ref;
index 6b804aa4529a171bfab534307903b142c23cf891..c0594cb07adab14f1efeb970a8c0dd85d86a7931 100644 (file)
@@ -1096,7 +1096,6 @@ struct key_type key_type_trusted = {
        .name = "trusted",
        .instantiate = trusted_instantiate,
        .update = trusted_update,
-       .match = user_match,
        .destroy = trusted_destroy,
        .describe = user_describe,
        .read = trusted_read,
index eee340011f2bd54d7b12f3f28a25ec3f8396b5fd..36b47bbd3d8cc277de55e0c0cdd722618ca13231 100644 (file)
@@ -26,12 +26,10 @@ static int logon_vet_description(const char *desc);
  */
 struct key_type key_type_user = {
        .name                   = "user",
-       .def_lookup_type        = KEYRING_SEARCH_LOOKUP_DIRECT,
        .preparse               = user_preparse,
        .free_preparse          = user_free_preparse,
        .instantiate            = generic_key_instantiate,
        .update                 = user_update,
-       .match                  = user_match,
        .revoke                 = user_revoke,
        .destroy                = user_destroy,
        .describe               = user_describe,
@@ -48,12 +46,10 @@ EXPORT_SYMBOL_GPL(key_type_user);
  */
 struct key_type key_type_logon = {
        .name                   = "logon",
-       .def_lookup_type        = KEYRING_SEARCH_LOOKUP_DIRECT,
        .preparse               = user_preparse,
        .free_preparse          = user_free_preparse,
        .instantiate            = generic_key_instantiate,
        .update                 = user_update,
-       .match                  = user_match,
        .revoke                 = user_revoke,
        .destroy                = user_destroy,
        .describe               = user_describe,
@@ -138,16 +134,6 @@ error:
 
 EXPORT_SYMBOL_GPL(user_update);
 
-/*
- * match users on their name
- */
-int user_match(const struct key *key, const void *description)
-{
-       return strcmp(key->description, description) == 0;
-}
-
-EXPORT_SYMBOL_GPL(user_match);
-
 /*
  * dispose of the links from a revoked keyring
  * - called with the key sem write-locked
index e41b1a8d7644a674d8e9c02ae09fc3562d6a8d84..18b35c63fc0c80cb3f0ce9dfc734f42c33efe98b 100644 (file)
@@ -775,9 +775,9 @@ int security_file_fcntl(struct file *file, unsigned int cmd, unsigned long arg)
        return security_ops->file_fcntl(file, cmd, arg);
 }
 
-int security_file_set_fowner(struct file *file)
+void security_file_set_fowner(struct file *file)
 {
-       return security_ops->file_set_fowner(file);
+       security_ops->file_set_fowner(file);
 }
 
 int security_file_send_sigiotask(struct task_struct *tsk,
index b0e940497e23bb47a0460e57a65952f2b4dc7e03..8426a2aa8dce37abaa4d0cad8d20cb56113ce453 100644 (file)
@@ -2097,6 +2097,41 @@ static int selinux_vm_enough_memory(struct mm_struct *mm, long pages)
 
 /* binprm security operations */
 
+static int check_nnp_nosuid(const struct linux_binprm *bprm,
+                           const struct task_security_struct *old_tsec,
+                           const struct task_security_struct *new_tsec)
+{
+       int nnp = (bprm->unsafe & LSM_UNSAFE_NO_NEW_PRIVS);
+       int nosuid = (bprm->file->f_path.mnt->mnt_flags & MNT_NOSUID);
+       int rc;
+
+       if (!nnp && !nosuid)
+               return 0; /* neither NNP nor nosuid */
+
+       if (new_tsec->sid == old_tsec->sid)
+               return 0; /* No change in credentials */
+
+       /*
+        * The only transitions we permit under NNP or nosuid
+        * are transitions to bounded SIDs, i.e. SIDs that are
+        * guaranteed to only be allowed a subset of the permissions
+        * of the current SID.
+        */
+       rc = security_bounded_transition(old_tsec->sid, new_tsec->sid);
+       if (rc) {
+               /*
+                * On failure, preserve the errno values for NNP vs nosuid.
+                * NNP:  Operation not permitted for caller.
+                * nosuid:  Permission denied to file.
+                */
+               if (nnp)
+                       return -EPERM;
+               else
+                       return -EACCES;
+       }
+       return 0;
+}
+
 static int selinux_bprm_set_creds(struct linux_binprm *bprm)
 {
        const struct task_security_struct *old_tsec;
@@ -2133,14 +2168,10 @@ static int selinux_bprm_set_creds(struct linux_binprm *bprm)
                /* Reset exec SID on execve. */
                new_tsec->exec_sid = 0;
 
-               /*
-                * Minimize confusion: if no_new_privs or nosuid and a
-                * transition is explicitly requested, then fail the exec.
-                */
-               if (bprm->unsafe & LSM_UNSAFE_NO_NEW_PRIVS)
-                       return -EPERM;
-               if (bprm->file->f_path.mnt->mnt_flags & MNT_NOSUID)
-                       return -EACCES;
+               /* Fail on NNP or nosuid if not an allowed transition. */
+               rc = check_nnp_nosuid(bprm, old_tsec, new_tsec);
+               if (rc)
+                       return rc;
        } else {
                /* Check for a default transition on this program. */
                rc = security_transition_sid(old_tsec->sid, isec->sid,
@@ -2148,15 +2179,19 @@ static int selinux_bprm_set_creds(struct linux_binprm *bprm)
                                             &new_tsec->sid);
                if (rc)
                        return rc;
+
+               /*
+                * Fallback to old SID on NNP or nosuid if not an allowed
+                * transition.
+                */
+               rc = check_nnp_nosuid(bprm, old_tsec, new_tsec);
+               if (rc)
+                       new_tsec->sid = old_tsec->sid;
        }
 
        ad.type = LSM_AUDIT_DATA_PATH;
        ad.u.path = bprm->file->f_path;
 
-       if ((bprm->file->f_path.mnt->mnt_flags & MNT_NOSUID) ||
-           (bprm->unsafe & LSM_UNSAFE_NO_NEW_PRIVS))
-               new_tsec->sid = old_tsec->sid;
-
        if (new_tsec->sid == old_tsec->sid) {
                rc = avc_has_perm(old_tsec->sid, isec->sid,
                                  SECCLASS_FILE, FILE__EXECUTE_NO_TRANS, &ad);
@@ -3346,14 +3381,12 @@ static int selinux_file_fcntl(struct file *file, unsigned int cmd,
        return err;
 }
 
-static int selinux_file_set_fowner(struct file *file)
+static void selinux_file_set_fowner(struct file *file)
 {
        struct file_security_struct *fsec;
 
        fsec = file->f_security;
        fsec->fown_sid = current_sid();
-
-       return 0;
 }
 
 static int selinux_file_send_sigiotask(struct task_struct *tsk,
@@ -4272,15 +4305,15 @@ static int selinux_socket_unix_may_send(struct socket *sock,
                            &ad);
 }
 
-static int selinux_inet_sys_rcv_skb(int ifindex, char *addrp, u16 family,
-                                   u32 peer_sid,
+static int selinux_inet_sys_rcv_skb(struct net *ns, int ifindex,
+                                   char *addrp, u16 family, u32 peer_sid,
                                    struct common_audit_data *ad)
 {
        int err;
        u32 if_sid;
        u32 node_sid;
 
-       err = sel_netif_sid(ifindex, &if_sid);
+       err = sel_netif_sid(ns, ifindex, &if_sid);
        if (err)
                return err;
        err = avc_has_perm(peer_sid, if_sid,
@@ -4373,8 +4406,8 @@ static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
                err = selinux_skb_peerlbl_sid(skb, family, &peer_sid);
                if (err)
                        return err;
-               err = selinux_inet_sys_rcv_skb(skb->skb_iif, addrp, family,
-                                              peer_sid, &ad);
+               err = selinux_inet_sys_rcv_skb(sock_net(sk), skb->skb_iif,
+                                              addrp, family, peer_sid, &ad);
                if (err) {
                        selinux_netlbl_err(skb, err, 0);
                        return err;
@@ -4692,10 +4725,9 @@ static int selinux_nlmsg_perm(struct sock *sk, struct sk_buff *skb)
        err = selinux_nlmsg_lookup(sksec->sclass, nlh->nlmsg_type, &perm);
        if (err) {
                if (err == -EINVAL) {
-                       audit_log(current->audit_context, GFP_KERNEL, AUDIT_SELINUX_ERR,
-                                 "SELinux:  unrecognized netlink message"
-                                 " type=%hu for sclass=%hu\n",
-                                 nlh->nlmsg_type, sksec->sclass);
+                       WARN_ONCE(1, "selinux_nlmsg_perm: unrecognized netlink message:"
+                                 " protocol=%hu nlmsg_type=%hu sclass=%hu\n",
+                                 sk->sk_protocol, nlh->nlmsg_type, sksec->sclass);
                        if (!selinux_enforcing || security_get_allow_unknown())
                                err = 0;
                }
@@ -4713,7 +4745,8 @@ out:
 
 #ifdef CONFIG_NETFILTER
 
-static unsigned int selinux_ip_forward(struct sk_buff *skb, int ifindex,
+static unsigned int selinux_ip_forward(struct sk_buff *skb,
+                                      const struct net_device *indev,
                                       u16 family)
 {
        int err;
@@ -4739,14 +4772,14 @@ static unsigned int selinux_ip_forward(struct sk_buff *skb, int ifindex,
 
        ad.type = LSM_AUDIT_DATA_NET;
        ad.u.net = &net;
-       ad.u.net->netif = ifindex;
+       ad.u.net->netif = indev->ifindex;
        ad.u.net->family = family;
        if (selinux_parse_skb(skb, &ad, &addrp, 1, NULL) != 0)
                return NF_DROP;
 
        if (peerlbl_active) {
-               err = selinux_inet_sys_rcv_skb(ifindex, addrp, family,
-                                              peer_sid, &ad);
+               err = selinux_inet_sys_rcv_skb(dev_net(indev), indev->ifindex,
+                                              addrp, family, peer_sid, &ad);
                if (err) {
                        selinux_netlbl_err(skb, err, 1);
                        return NF_DROP;
@@ -4775,7 +4808,7 @@ static unsigned int selinux_ipv4_forward(const struct nf_hook_ops *ops,
                                         const struct net_device *out,
                                         int (*okfn)(struct sk_buff *))
 {
-       return selinux_ip_forward(skb, in->ifindex, PF_INET);
+       return selinux_ip_forward(skb, in, PF_INET);
 }
 
 #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
@@ -4785,7 +4818,7 @@ static unsigned int selinux_ipv6_forward(const struct nf_hook_ops *ops,
                                         const struct net_device *out,
                                         int (*okfn)(struct sk_buff *))
 {
-       return selinux_ip_forward(skb, in->ifindex, PF_INET6);
+       return selinux_ip_forward(skb, in, PF_INET6);
 }
 #endif /* IPV6 */
 
@@ -4873,11 +4906,13 @@ static unsigned int selinux_ip_postroute_compat(struct sk_buff *skb,
        return NF_ACCEPT;
 }
 
-static unsigned int selinux_ip_postroute(struct sk_buff *skb, int ifindex,
+static unsigned int selinux_ip_postroute(struct sk_buff *skb,
+                                        const struct net_device *outdev,
                                         u16 family)
 {
        u32 secmark_perm;
        u32 peer_sid;
+       int ifindex = outdev->ifindex;
        struct sock *sk;
        struct common_audit_data ad;
        struct lsm_network_audit net = {0,};
@@ -4958,6 +4993,7 @@ static unsigned int selinux_ip_postroute(struct sk_buff *skb, int ifindex,
                        case PF_INET6:
                                if (IP6CB(skb)->flags & IP6SKB_XFRM_TRANSFORMED)
                                        return NF_ACCEPT;
+                               break;
                        default:
                                return NF_DROP_ERR(-ECONNREFUSED);
                        }
@@ -4989,7 +5025,7 @@ static unsigned int selinux_ip_postroute(struct sk_buff *skb, int ifindex,
                u32 if_sid;
                u32 node_sid;
 
-               if (sel_netif_sid(ifindex, &if_sid))
+               if (sel_netif_sid(dev_net(outdev), ifindex, &if_sid))
                        return NF_DROP;
                if (avc_has_perm(peer_sid, if_sid,
                                 SECCLASS_NETIF, NETIF__EGRESS, &ad))
@@ -5011,7 +5047,7 @@ static unsigned int selinux_ipv4_postroute(const struct nf_hook_ops *ops,
                                           const struct net_device *out,
                                           int (*okfn)(struct sk_buff *))
 {
-       return selinux_ip_postroute(skb, out->ifindex, PF_INET);
+       return selinux_ip_postroute(skb, out, PF_INET);
 }
 
 #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
@@ -5021,7 +5057,7 @@ static unsigned int selinux_ipv6_postroute(const struct nf_hook_ops *ops,
                                           const struct net_device *out,
                                           int (*okfn)(struct sk_buff *))
 {
-       return selinux_ip_postroute(skb, out->ifindex, PF_INET6);
+       return selinux_ip_postroute(skb, out, PF_INET6);
 }
 #endif /* IPV6 */
 
@@ -6035,7 +6071,7 @@ security_initcall(selinux_init);
 
 #if defined(CONFIG_NETFILTER)
 
-static struct nf_hook_ops selinux_ipv4_ops[] = {
+static struct nf_hook_ops selinux_nf_ops[] = {
        {
                .hook =         selinux_ipv4_postroute,
                .owner =        THIS_MODULE,
@@ -6056,12 +6092,8 @@ static struct nf_hook_ops selinux_ipv4_ops[] = {
                .pf =           NFPROTO_IPV4,
                .hooknum =      NF_INET_LOCAL_OUT,
                .priority =     NF_IP_PRI_SELINUX_FIRST,
-       }
-};
-
+       },
 #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
-
-static struct nf_hook_ops selinux_ipv6_ops[] = {
        {
                .hook =         selinux_ipv6_postroute,
                .owner =        THIS_MODULE,
@@ -6075,32 +6107,24 @@ static struct nf_hook_ops selinux_ipv6_ops[] = {
                .pf =           NFPROTO_IPV6,
                .hooknum =      NF_INET_FORWARD,
                .priority =     NF_IP6_PRI_SELINUX_FIRST,
-       }
-};
-
+       },
 #endif /* IPV6 */
+};
 
 static int __init selinux_nf_ip_init(void)
 {
-       int err = 0;
+       int err;
 
        if (!selinux_enabled)
-               goto out;
+               return 0;
 
        printk(KERN_DEBUG "SELinux:  Registering netfilter hooks\n");
 
-       err = nf_register_hooks(selinux_ipv4_ops, ARRAY_SIZE(selinux_ipv4_ops));
+       err = nf_register_hooks(selinux_nf_ops, ARRAY_SIZE(selinux_nf_ops));
        if (err)
-               panic("SELinux: nf_register_hooks for IPv4: error %d\n", err);
+               panic("SELinux: nf_register_hooks: error %d\n", err);
 
-#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
-       err = nf_register_hooks(selinux_ipv6_ops, ARRAY_SIZE(selinux_ipv6_ops));
-       if (err)
-               panic("SELinux: nf_register_hooks for IPv6: error %d\n", err);
-#endif /* IPV6 */
-
-out:
-       return err;
+       return 0;
 }
 
 __initcall(selinux_nf_ip_init);
@@ -6110,10 +6134,7 @@ static void selinux_nf_ip_exit(void)
 {
        printk(KERN_DEBUG "SELinux:  Unregistering netfilter hooks\n");
 
-       nf_unregister_hooks(selinux_ipv4_ops, ARRAY_SIZE(selinux_ipv4_ops));
-#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
-       nf_unregister_hooks(selinux_ipv6_ops, ARRAY_SIZE(selinux_ipv6_ops));
-#endif /* IPV6 */
+       nf_unregister_hooks(selinux_nf_ops, ARRAY_SIZE(selinux_nf_ops));
 }
 #endif
 
index 57c6eae81eacac6226273963ee89602cdf736983..c7214544409015a3fbc6cda9a7386e394f50be2b 100644 (file)
 #ifndef _SELINUX_NETIF_H_
 #define _SELINUX_NETIF_H_
 
+#include <net/net_namespace.h>
+
 void sel_netif_flush(void);
 
-int sel_netif_sid(int ifindex, u32 *sid);
+int sel_netif_sid(struct net *ns, int ifindex, u32 *sid);
 
 #endif /* _SELINUX_NETIF_H_ */
 
index 078e553f52f27a03ab83490f20bb2353782d2ef2..81fa718d5cb38817fdda9ad580f8316ef5d3e5c6 100644 (file)
@@ -24,6 +24,7 @@
 #include <linux/binfmts.h>
 #include <linux/in.h>
 #include <linux/spinlock.h>
+#include <net/net_namespace.h>
 #include "flask.h"
 #include "avc.h"
 
@@ -78,6 +79,7 @@ struct ipc_security_struct {
 };
 
 struct netif_security_struct {
+       struct net *ns;                 /* network namespace */
        int ifindex;                    /* device index */
        u32 sid;                        /* SID for this interface */
 };
index 50ce177d71a0561cdc0c0aaf4aabb13e4c7662ef..e607b4473ef678c71e8a7a882f9b298491b52dd9 100644 (file)
@@ -45,6 +45,7 @@ static struct list_head sel_netif_hash[SEL_NETIF_HASH_SIZE];
 
 /**
  * sel_netif_hashfn - Hashing function for the interface table
+ * @ns: the network namespace
  * @ifindex: the network interface
  *
  * Description:
@@ -52,13 +53,14 @@ static struct list_head sel_netif_hash[SEL_NETIF_HASH_SIZE];
  * bucket number for the given interface.
  *
  */
-static inline u32 sel_netif_hashfn(int ifindex)
+static inline u32 sel_netif_hashfn(const struct net *ns, int ifindex)
 {
-       return (ifindex & (SEL_NETIF_HASH_SIZE - 1));
+       return (((uintptr_t)ns + ifindex) & (SEL_NETIF_HASH_SIZE - 1));
 }
 
 /**
  * sel_netif_find - Search for an interface record
+ * @ns: the network namespace
  * @ifindex: the network interface
  *
  * Description:
@@ -66,15 +68,15 @@ static inline u32 sel_netif_hashfn(int ifindex)
  * If an entry can not be found in the table return NULL.
  *
  */
-static inline struct sel_netif *sel_netif_find(int ifindex)
+static inline struct sel_netif *sel_netif_find(const struct net *ns,
+                                              int ifindex)
 {
-       int idx = sel_netif_hashfn(ifindex);
+       int idx = sel_netif_hashfn(ns, ifindex);
        struct sel_netif *netif;
 
        list_for_each_entry_rcu(netif, &sel_netif_hash[idx], list)
-               /* all of the devices should normally fit in the hash, so we
-                * optimize for that case */
-               if (likely(netif->nsec.ifindex == ifindex))
+               if (net_eq(netif->nsec.ns, ns) &&
+                   netif->nsec.ifindex == ifindex)
                        return netif;
 
        return NULL;
@@ -96,7 +98,7 @@ static int sel_netif_insert(struct sel_netif *netif)
        if (sel_netif_total >= SEL_NETIF_HASH_MAX)
                return -ENOSPC;
 
-       idx = sel_netif_hashfn(netif->nsec.ifindex);
+       idx = sel_netif_hashfn(netif->nsec.ns, netif->nsec.ifindex);
        list_add_rcu(&netif->list, &sel_netif_hash[idx]);
        sel_netif_total++;
 
@@ -120,6 +122,7 @@ static void sel_netif_destroy(struct sel_netif *netif)
 
 /**
  * sel_netif_sid_slow - Lookup the SID of a network interface using the policy
+ * @ns: the network namespace
  * @ifindex: the network interface
  * @sid: interface SID
  *
@@ -130,7 +133,7 @@ static void sel_netif_destroy(struct sel_netif *netif)
  * failure.
  *
  */
-static int sel_netif_sid_slow(int ifindex, u32 *sid)
+static int sel_netif_sid_slow(struct net *ns, int ifindex, u32 *sid)
 {
        int ret;
        struct sel_netif *netif;
@@ -140,7 +143,7 @@ static int sel_netif_sid_slow(int ifindex, u32 *sid)
        /* NOTE: we always use init's network namespace since we don't
         * currently support containers */
 
-       dev = dev_get_by_index(&init_net, ifindex);
+       dev = dev_get_by_index(ns, ifindex);
        if (unlikely(dev == NULL)) {
                printk(KERN_WARNING
                       "SELinux: failure in sel_netif_sid_slow(),"
@@ -149,7 +152,7 @@ static int sel_netif_sid_slow(int ifindex, u32 *sid)
        }
 
        spin_lock_bh(&sel_netif_lock);
-       netif = sel_netif_find(ifindex);
+       netif = sel_netif_find(ns, ifindex);
        if (netif != NULL) {
                *sid = netif->nsec.sid;
                ret = 0;
@@ -163,6 +166,7 @@ static int sel_netif_sid_slow(int ifindex, u32 *sid)
        ret = security_netif_sid(dev->name, &new->nsec.sid);
        if (ret != 0)
                goto out;
+       new->nsec.ns = ns;
        new->nsec.ifindex = ifindex;
        ret = sel_netif_insert(new);
        if (ret != 0)
@@ -184,6 +188,7 @@ out:
 
 /**
  * sel_netif_sid - Lookup the SID of a network interface
+ * @ns: the network namespace
  * @ifindex: the network interface
  * @sid: interface SID
  *
@@ -195,12 +200,12 @@ out:
  * on failure.
  *
  */
-int sel_netif_sid(int ifindex, u32 *sid)
+int sel_netif_sid(struct net *ns, int ifindex, u32 *sid)
 {
        struct sel_netif *netif;
 
        rcu_read_lock();
-       netif = sel_netif_find(ifindex);
+       netif = sel_netif_find(ns, ifindex);
        if (likely(netif != NULL)) {
                *sid = netif->nsec.sid;
                rcu_read_unlock();
@@ -208,11 +213,12 @@ int sel_netif_sid(int ifindex, u32 *sid)
        }
        rcu_read_unlock();
 
-       return sel_netif_sid_slow(ifindex, sid);
+       return sel_netif_sid_slow(ns, ifindex, sid);
 }
 
 /**
  * sel_netif_kill - Remove an entry from the network interface table
+ * @ns: the network namespace
  * @ifindex: the network interface
  *
  * Description:
@@ -220,13 +226,13 @@ int sel_netif_sid(int ifindex, u32 *sid)
  * table if it exists.
  *
  */
-static void sel_netif_kill(int ifindex)
+static void sel_netif_kill(const struct net *ns, int ifindex)
 {
        struct sel_netif *netif;
 
        rcu_read_lock();
        spin_lock_bh(&sel_netif_lock);
-       netif = sel_netif_find(ifindex);
+       netif = sel_netif_find(ns, ifindex);
        if (netif)
                sel_netif_destroy(netif);
        spin_unlock_bh(&sel_netif_lock);
@@ -257,11 +263,8 @@ static int sel_netif_netdev_notifier_handler(struct notifier_block *this,
 {
        struct net_device *dev = netdev_notifier_info_to_dev(ptr);
 
-       if (dev_net(dev) != &init_net)
-               return NOTIFY_DONE;
-
        if (event == NETDEV_DOWN)
-               sel_netif_kill(dev->ifindex);
+               sel_netif_kill(dev_net(dev), dev->ifindex);
 
        return NOTIFY_DONE;
 }
index 2aa9d172dc7e73d87ccbc7f73bbc3e8ad2206e45..a1d3944751b9e2fbfd23e18b694b00cd150880dc 100644 (file)
@@ -728,7 +728,7 @@ static int security_validtrans_handle_fail(struct context *ocontext,
        if (context_struct_to_string(tcontext, &t, &tlen))
                goto out;
        audit_log(current->audit_context, GFP_ATOMIC, AUDIT_SELINUX_ERR,
-                 "security_validate_transition:  denied for"
+                 "op=security_validate_transition seresult=denied"
                  " oldcontext=%s newcontext=%s taskcontext=%s tclass=%s",
                  o, n, t, sym_name(&policydb, SYM_CLASSES, tclass-1));
 out:
@@ -877,7 +877,7 @@ int security_bounded_transition(u32 old_sid, u32 new_sid)
                        audit_log(current->audit_context,
                                  GFP_ATOMIC, AUDIT_SELINUX_ERR,
                                  "op=security_bounded_transition "
-                                 "result=denied "
+                                 "seresult=denied "
                                  "oldcontext=%s newcontext=%s",
                                  old_name, new_name);
                }
@@ -1351,8 +1351,8 @@ static int compute_sid_handle_invalid_context(
        if (context_struct_to_string(newcontext, &n, &nlen))
                goto out;
        audit_log(current->audit_context, GFP_ATOMIC, AUDIT_SELINUX_ERR,
-                 "security_compute_sid:  invalid context %s"
-                 " for scontext=%s"
+                 "op=security_compute_sid invalid_context=%s"
+                 " scontext=%s"
                  " tcontext=%s"
                  " tclass=%s",
                  n, s, t, sym_name(&policydb, SYM_CLASSES, tclass-1));
@@ -2607,8 +2607,10 @@ int security_sid_mls_copy(u32 sid, u32 mls_sid, u32 *new_sid)
                rc = convert_context_handle_invalid_context(&newcon);
                if (rc) {
                        if (!context_struct_to_string(&newcon, &s, &len)) {
-                               audit_log(current->audit_context, GFP_ATOMIC, AUDIT_SELINUX_ERR,
-                                         "security_sid_mls_copy: invalid context %s", s);
+                               audit_log(current->audit_context,
+                                         GFP_ATOMIC, AUDIT_SELINUX_ERR,
+                                         "op=security_sid_mls_copy "
+                                         "invalid_context=%s", s);
                                kfree(s);
                        }
                        goto out_unlock;
index e69de9c642b7f03c8648457495511ca0c8bc839c..b065f97894185557c88fe77c554719a3deca955d 100644 (file)
@@ -12,3 +12,19 @@ config SECURITY_SMACK
          of other mandatory security schemes.
          If you are unsure how to answer this question, answer N.
 
+config SECURITY_SMACK_BRINGUP
+       bool "Reporting on access granted by Smack rules"
+       depends on SECURITY_SMACK
+       default n
+       help
+         Enable the bring-up ("b") access mode in Smack rules.
+         When access is granted by a rule with the "b" mode a
+         message about the access requested is generated. The
+         intention is that a process can be granted a wide set
+         of access initially with the bringup mode set on the
+         rules. The developer can use the information to
+         identify which rules are necessary and what accesses
+         may be inappropriate. The developer can reduce the
+         access rule set once the behavior is well understood.
+         This is a superior mechanism to the oft abused
+         "permissive" mode of other systems.
index 020307ef097296f2eac85be8ae823fdad93ff508..b828a379377c9cd1c2dee54bc2ddab5b3bde920a 100644 (file)
@@ -71,11 +71,11 @@ struct smack_known {
 #define SMK_CIPSOLEN   24
 
 struct superblock_smack {
-       char            *smk_root;
-       char            *smk_floor;
-       char            *smk_hat;
-       char            *smk_default;
-       int             smk_initialized;
+       struct smack_known      *smk_root;
+       struct smack_known      *smk_floor;
+       struct smack_known      *smk_hat;
+       struct smack_known      *smk_default;
+       int                     smk_initialized;
 };
 
 struct socket_smack {
@@ -88,7 +88,7 @@ struct socket_smack {
  * Inode smack data
  */
 struct inode_smack {
-       char                    *smk_inode;     /* label of the fso */
+       struct smack_known      *smk_inode;     /* label of the fso */
        struct smack_known      *smk_task;      /* label of the task */
        struct smack_known      *smk_mmap;      /* label of the mmap domain */
        struct mutex            smk_lock;       /* initialization lock */
@@ -112,7 +112,7 @@ struct task_smack {
 struct smack_rule {
        struct list_head        list;
        struct smack_known      *smk_subject;
-       char                    *smk_object;
+       struct smack_known      *smk_object;
        int                     smk_access;
 };
 
@@ -123,7 +123,7 @@ struct smk_netlbladdr {
        struct list_head        list;
        struct sockaddr_in      smk_host;       /* network address */
        struct in_addr          smk_mask;       /* network mask */
-       char                    *smk_label;     /* label */
+       struct smack_known      *smk_label;     /* label */
 };
 
 /*
@@ -191,6 +191,7 @@ struct smk_port_label {
  */
 #define MAY_TRANSMUTE  0x00001000      /* Controls directory labeling */
 #define MAY_LOCK       0x00002000      /* Locks should be writes, but ... */
+#define MAY_BRINGUP    0x00004000      /* Report use of this rule */
 
 /*
  * Just to make the common cases easier to deal with
@@ -200,9 +201,9 @@ struct smk_port_label {
 #define MAY_NOT                0
 
 /*
- * Number of access types used by Smack (rwxatl)
+ * Number of access types used by Smack (rwxatlb)
  */
-#define SMK_NUM_ACCESS_TYPE 6
+#define SMK_NUM_ACCESS_TYPE 7
 
 /* SMACK data */
 struct smack_audit_data {
@@ -226,23 +227,23 @@ struct smk_audit_info {
 /*
  * These functions are in smack_lsm.c
  */
-struct inode_smack *new_inode_smack(char *);
+struct inode_smack *new_inode_smack(struct smack_known *);
 
 /*
  * These functions are in smack_access.c
  */
 int smk_access_entry(char *, char *, struct list_head *);
-int smk_access(struct smack_known *, char *, int, struct smk_audit_info *);
-int smk_tskacc(struct task_smack *, char *, u32, struct smk_audit_info *);
-int smk_curacc(char *, u32, struct smk_audit_info *);
+int smk_access(struct smack_known *, struct smack_known *,
+              int, struct smk_audit_info *);
+int smk_tskacc(struct task_smack *, struct smack_known *,
+              u32, struct smk_audit_info *);
+int smk_curacc(struct smack_known *, u32, struct smk_audit_info *);
 struct smack_known *smack_from_secid(const u32);
 char *smk_parse_smack(const char *string, int len);
 int smk_netlbl_mls(int, char *, struct netlbl_lsm_secattr *, int);
-char *smk_import(const char *, int);
 struct smack_known *smk_import_entry(const char *, int);
 void smk_insert_entry(struct smack_known *skp);
 struct smack_known *smk_find_entry(const char *);
-u32 smack_to_secid(const char *);
 
 /*
  * Shared data.
@@ -252,7 +253,7 @@ extern int smack_cipso_mapped;
 extern struct smack_known *smack_net_ambient;
 extern struct smack_known *smack_onlycap;
 extern struct smack_known *smack_syslog_label;
-extern const char *smack_cipso_option;
+extern struct smack_known smack_cipso_option;
 extern int smack_ptrace_rule;
 
 extern struct smack_known smack_known_floor;
@@ -281,9 +282,9 @@ static inline int smk_inode_transmutable(const struct inode *isp)
 }
 
 /*
- * Present a pointer to the smack label in an inode blob.
+ * Present a pointer to the smack label entry in an inode blob.
  */
-static inline char *smk_of_inode(const struct inode *isp)
+static inline struct smack_known *smk_of_inode(const struct inode *isp)
 {
        struct inode_smack *sip = isp->i_security;
        return sip->smk_inode;
index f97d0842e6217a3578caa85730c95ce6b5683087..5b970ffde024aff51a8f59bc54f47107916ce0de 100644 (file)
@@ -94,7 +94,7 @@ int smk_access_entry(char *subject_label, char *object_label,
        struct smack_rule *srp;
 
        list_for_each_entry_rcu(srp, rule_list, list) {
-               if (srp->smk_object == object_label &&
+               if (srp->smk_object->smk_known == object_label &&
                    srp->smk_subject->smk_known == subject_label) {
                        may = srp->smk_access;
                        break;
@@ -111,8 +111,8 @@ int smk_access_entry(char *subject_label, char *object_label,
 
 /**
  * smk_access - determine if a subject has a specific access to an object
- * @subject_known: a pointer to the subject's Smack label entry
- * @object_label: a pointer to the object's Smack label
+ * @subject: a pointer to the subject's Smack label entry
+ * @object: a pointer to the object's Smack label entry
  * @request: the access requested, in "MAY" format
  * @a : a pointer to the audit data
  *
@@ -122,8 +122,8 @@ int smk_access_entry(char *subject_label, char *object_label,
  *
  * Smack labels are shared on smack_list
  */
-int smk_access(struct smack_known *subject_known, char *object_label,
-               int request, struct smk_audit_info *a)
+int smk_access(struct smack_known *subject, struct smack_known *object,
+              int request, struct smk_audit_info *a)
 {
        int may = MAY_NOT;
        int rc = 0;
@@ -133,7 +133,7 @@ int smk_access(struct smack_known *subject_known, char *object_label,
         *
         * A star subject can't access any object.
         */
-       if (subject_known == &smack_known_star) {
+       if (subject == &smack_known_star) {
                rc = -EACCES;
                goto out_audit;
        }
@@ -142,28 +142,28 @@ int smk_access(struct smack_known *subject_known, char *object_label,
         * Tasks cannot be assigned the internet label.
         * An internet subject can access any object.
         */
-       if (object_label == smack_known_web.smk_known ||
-           subject_known == &smack_known_web)
+       if (object == &smack_known_web ||
+           subject == &smack_known_web)
                goto out_audit;
        /*
         * A star object can be accessed by any subject.
         */
-       if (object_label == smack_known_star.smk_known)
+       if (object == &smack_known_star)
                goto out_audit;
        /*
         * An object can be accessed in any way by a subject
         * with the same label.
         */
-       if (subject_known->smk_known == object_label)
+       if (subject->smk_known == object->smk_known)
                goto out_audit;
        /*
         * A hat subject can read any object.
         * A floor object can be read by any subject.
         */
        if ((request & MAY_ANYREAD) == request) {
-               if (object_label == smack_known_floor.smk_known)
+               if (object == &smack_known_floor)
                        goto out_audit;
-               if (subject_known == &smack_known_hat)
+               if (subject == &smack_known_hat)
                        goto out_audit;
        }
        /*
@@ -174,27 +174,38 @@ int smk_access(struct smack_known *subject_known, char *object_label,
         * indicates there is no entry for this pair.
         */
        rcu_read_lock();
-       may = smk_access_entry(subject_known->smk_known, object_label,
-                               &subject_known->smk_rules);
+       may = smk_access_entry(subject->smk_known, object->smk_known,
+                              &subject->smk_rules);
        rcu_read_unlock();
 
-       if (may > 0 && (request & may) == request)
+       if (may <= 0 || (request & may) != request) {
+               rc = -EACCES;
                goto out_audit;
+       }
+#ifdef CONFIG_SECURITY_SMACK_BRINGUP
+       /*
+        * Return a positive value if using bringup mode.
+        * This allows the hooks to identify checks that
+        * succeed because of "b" rules.
+        */
+       if (may & MAY_BRINGUP)
+               rc = MAY_BRINGUP;
+#endif
 
-       rc = -EACCES;
 out_audit:
 #ifdef CONFIG_AUDIT
        if (a)
-               smack_log(subject_known->smk_known, object_label, request,
-                               rc, a);
+               smack_log(subject->smk_known, object->smk_known,
+                         request, rc, a);
 #endif
+
        return rc;
 }
 
 /**
  * smk_tskacc - determine if a task has a specific access to an object
- * @tsp: a pointer to the subject task
- * @obj_label: a pointer to the object's Smack label
+ * @tsp: a pointer to the subject's task
+ * @obj_known: a pointer to the object's label entry
  * @mode: the access requested, in "MAY" format
  * @a : common audit data
  *
@@ -203,24 +214,25 @@ out_audit:
  * non zero otherwise. It allows that the task may have the capability
  * to override the rules.
  */
-int smk_tskacc(struct task_smack *subject, char *obj_label,
+int smk_tskacc(struct task_smack *tsp, struct smack_known *obj_known,
               u32 mode, struct smk_audit_info *a)
 {
-       struct smack_known *skp = smk_of_task(subject);
+       struct smack_known *sbj_known = smk_of_task(tsp);
        int may;
        int rc;
 
        /*
         * Check the global rule list
         */
-       rc = smk_access(skp, obj_label, mode, NULL);
-       if (rc == 0) {
+       rc = smk_access(sbj_known, obj_known, mode, NULL);
+       if (rc >= 0) {
                /*
                 * If there is an entry in the task's rule list
                 * it can further restrict access.
                 */
-               may = smk_access_entry(skp->smk_known, obj_label,
-                                       &subject->smk_rules);
+               may = smk_access_entry(sbj_known->smk_known,
+                                      obj_known->smk_known,
+                                      &tsp->smk_rules);
                if (may < 0)
                        goto out_audit;
                if ((mode & may) == mode)
@@ -237,14 +249,15 @@ int smk_tskacc(struct task_smack *subject, char *obj_label,
 out_audit:
 #ifdef CONFIG_AUDIT
        if (a)
-               smack_log(skp->smk_known, obj_label, mode, rc, a);
+               smack_log(sbj_known->smk_known, obj_known->smk_known,
+                         mode, rc, a);
 #endif
        return rc;
 }
 
 /**
  * smk_curacc - determine if current has a specific access to an object
- * @obj_label: a pointer to the object's Smack label
+ * @obj_known: a pointer to the object's Smack label entry
  * @mode: the access requested, in "MAY" format
  * @a : common audit data
  *
@@ -253,11 +266,12 @@ out_audit:
  * non zero otherwise. It allows that current may have the capability
  * to override the rules.
  */
-int smk_curacc(char *obj_label, u32 mode, struct smk_audit_info *a)
+int smk_curacc(struct smack_known *obj_known,
+              u32 mode, struct smk_audit_info *a)
 {
        struct task_smack *tsp = current_security();
 
-       return smk_tskacc(tsp, obj_label, mode, a);
+       return smk_tskacc(tsp, obj_known, mode, a);
 }
 
 #ifdef CONFIG_AUDIT
@@ -328,6 +342,13 @@ void smack_log(char *subject_label, char *object_label, int request,
        struct smack_audit_data *sad;
        struct common_audit_data *a = &ad->a;
 
+#ifdef CONFIG_SECURITY_SMACK_BRINGUP
+       /*
+        * The result may be positive in bringup mode.
+        */
+       if (result > 0)
+               result = 0;
+#endif
        /* check if we have to log the current event */
        if (result != 0 && (log_policy & SMACK_AUDIT_DENIED) == 0)
                return;
@@ -543,27 +564,6 @@ unlockout:
        return skp;
 }
 
-/**
- * smk_import - import a smack label
- * @string: a text string that might be a Smack label
- * @len: the maximum size, or zero if it is NULL terminated.
- *
- * Returns a pointer to the label in the label list that
- * matches the passed string, adding it if necessary.
- */
-char *smk_import(const char *string, int len)
-{
-       struct smack_known *skp;
-
-       /* labels cannot begin with a '-' */
-       if (string[0] == '-')
-               return NULL;
-       skp = smk_import_entry(string, len);
-       if (skp == NULL)
-               return NULL;
-       return skp->smk_known;
-}
-
 /**
  * smack_from_secid - find the Smack label associated with a secid
  * @secid: an integer that might be associated with a Smack label
@@ -590,19 +590,3 @@ struct smack_known *smack_from_secid(const u32 secid)
        rcu_read_unlock();
        return &smack_known_invalid;
 }
-
-/**
- * smack_to_secid - find the secid associated with a Smack label
- * @smack: the Smack label
- *
- * Returns the appropriate secid if there is one,
- * otherwise 0
- */
-u32 smack_to_secid(const char *smack)
-{
-       struct smack_known *skp = smk_find_entry(smack);
-
-       if (skp == NULL)
-               return 0;
-       return skp->smk_secid;
-}
index e6ab307ce86e2fc1d1d04d35d2869fe1385ea724..d515ec25ae9fc543d16a3d3eac1ffb7acf3813da 100644 (file)
 
 LIST_HEAD(smk_ipv6_port_list);
 
+#ifdef CONFIG_SECURITY_SMACK_BRINGUP
+static void smk_bu_mode(int mode, char *s)
+{
+       int i = 0;
+
+       if (mode & MAY_READ)
+               s[i++] = 'r';
+       if (mode & MAY_WRITE)
+               s[i++] = 'w';
+       if (mode & MAY_EXEC)
+               s[i++] = 'x';
+       if (mode & MAY_APPEND)
+               s[i++] = 'a';
+       if (mode & MAY_TRANSMUTE)
+               s[i++] = 't';
+       if (mode & MAY_LOCK)
+               s[i++] = 'l';
+       if (i == 0)
+               s[i++] = '-';
+       s[i] = '\0';
+}
+#endif
+
+#ifdef CONFIG_SECURITY_SMACK_BRINGUP
+static int smk_bu_note(char *note, struct smack_known *sskp,
+                      struct smack_known *oskp, int mode, int rc)
+{
+       char acc[SMK_NUM_ACCESS_TYPE + 1];
+
+       if (rc <= 0)
+               return rc;
+
+       smk_bu_mode(mode, acc);
+       pr_info("Smack Bringup: (%s %s %s) %s\n",
+               sskp->smk_known, oskp->smk_known, acc, note);
+       return 0;
+}
+#else
+#define smk_bu_note(note, sskp, oskp, mode, RC) (RC)
+#endif
+
+#ifdef CONFIG_SECURITY_SMACK_BRINGUP
+static int smk_bu_current(char *note, struct smack_known *oskp,
+                         int mode, int rc)
+{
+       struct task_smack *tsp = current_security();
+       char acc[SMK_NUM_ACCESS_TYPE + 1];
+
+       if (rc <= 0)
+               return rc;
+
+       smk_bu_mode(mode, acc);
+       pr_info("Smack Bringup: (%s %s %s) %s %s\n",
+               tsp->smk_task->smk_known, oskp->smk_known,
+               acc, current->comm, note);
+       return 0;
+}
+#else
+#define smk_bu_current(note, oskp, mode, RC) (RC)
+#endif
+
+#ifdef CONFIG_SECURITY_SMACK_BRINGUP
+static int smk_bu_task(struct task_struct *otp, int mode, int rc)
+{
+       struct task_smack *tsp = current_security();
+       struct task_smack *otsp = task_security(otp);
+       char acc[SMK_NUM_ACCESS_TYPE + 1];
+
+       if (rc <= 0)
+               return rc;
+
+       smk_bu_mode(mode, acc);
+       pr_info("Smack Bringup: (%s %s %s) %s to %s\n",
+               tsp->smk_task->smk_known, otsp->smk_task->smk_known, acc,
+               current->comm, otp->comm);
+       return 0;
+}
+#else
+#define smk_bu_task(otp, mode, RC) (RC)
+#endif
+
+#ifdef CONFIG_SECURITY_SMACK_BRINGUP
+static int smk_bu_inode(struct inode *inode, int mode, int rc)
+{
+       struct task_smack *tsp = current_security();
+       char acc[SMK_NUM_ACCESS_TYPE + 1];
+
+       if (rc <= 0)
+               return rc;
+
+       smk_bu_mode(mode, acc);
+       pr_info("Smack Bringup: (%s %s %s) inode=(%s %ld) %s\n",
+               tsp->smk_task->smk_known, smk_of_inode(inode)->smk_known, acc,
+               inode->i_sb->s_id, inode->i_ino, current->comm);
+       return 0;
+}
+#else
+#define smk_bu_inode(inode, mode, RC) (RC)
+#endif
+
+#ifdef CONFIG_SECURITY_SMACK_BRINGUP
+static int smk_bu_file(struct file *file, int mode, int rc)
+{
+       struct task_smack *tsp = current_security();
+       struct smack_known *sskp = tsp->smk_task;
+       struct inode *inode = file->f_inode;
+       char acc[SMK_NUM_ACCESS_TYPE + 1];
+
+       if (rc <= 0)
+               return rc;
+
+       smk_bu_mode(mode, acc);
+       pr_info("Smack Bringup: (%s %s %s) file=(%s %ld %s) %s\n",
+               sskp->smk_known, (char *)file->f_security, acc,
+               inode->i_sb->s_id, inode->i_ino, file->f_dentry->d_name.name,
+               current->comm);
+       return 0;
+}
+#else
+#define smk_bu_file(file, mode, RC) (RC)
+#endif
+
+#ifdef CONFIG_SECURITY_SMACK_BRINGUP
+static int smk_bu_credfile(const struct cred *cred, struct file *file,
+                               int mode, int rc)
+{
+       struct task_smack *tsp = cred->security;
+       struct smack_known *sskp = tsp->smk_task;
+       struct inode *inode = file->f_inode;
+       char acc[SMK_NUM_ACCESS_TYPE + 1];
+
+       if (rc <= 0)
+               return rc;
+
+       smk_bu_mode(mode, acc);
+       pr_info("Smack Bringup: (%s %s %s) file=(%s %ld %s) %s\n",
+               sskp->smk_known, smk_of_inode(inode)->smk_known, acc,
+               inode->i_sb->s_id, inode->i_ino, file->f_dentry->d_name.name,
+               current->comm);
+       return 0;
+}
+#else
+#define smk_bu_credfile(cred, file, mode, RC) (RC)
+#endif
+
 /**
  * smk_fetch - Fetch the smack label from a file.
  * @ip: a pointer to the inode
@@ -87,11 +232,11 @@ static struct smack_known *smk_fetch(const char *name, struct inode *ip,
 
 /**
  * new_inode_smack - allocate an inode security blob
- * @smack: a pointer to the Smack label to use in the blob
+ * @skp: a pointer to the Smack label entry to use in the blob
  *
  * Returns the new blob or NULL if there's no memory available
  */
-struct inode_smack *new_inode_smack(char *smack)
+struct inode_smack *new_inode_smack(struct smack_known *skp)
 {
        struct inode_smack *isp;
 
@@ -99,7 +244,7 @@ struct inode_smack *new_inode_smack(char *smack)
        if (isp == NULL)
                return NULL;
 
-       isp->smk_inode = smack;
+       isp->smk_inode = skp;
        isp->smk_flags = 0;
        mutex_init(&isp->smk_lock);
 
@@ -178,20 +323,20 @@ static inline unsigned int smk_ptrace_mode(unsigned int mode)
 /**
  * smk_ptrace_rule_check - helper for ptrace access
  * @tracer: tracer process
- * @tracee_label: label of the process that's about to be traced,
- *                the pointer must originate from smack structures
+ * @tracee_known: label entry of the process that's about to be traced
  * @mode: ptrace attachment mode (PTRACE_MODE_*)
  * @func: name of the function that called us, used for audit
  *
  * Returns 0 on access granted, -error on error
  */
-static int smk_ptrace_rule_check(struct task_struct *tracer, char *tracee_label,
+static int smk_ptrace_rule_check(struct task_struct *tracer,
+                                struct smack_known *tracee_known,
                                 unsigned int mode, const char *func)
 {
        int rc;
        struct smk_audit_info ad, *saip = NULL;
        struct task_smack *tsp;
-       struct smack_known *skp;
+       struct smack_known *tracer_known;
 
        if ((mode & PTRACE_MODE_NOAUDIT) == 0) {
                smk_ad_init(&ad, func, LSM_AUDIT_DATA_TASK);
@@ -200,12 +345,12 @@ static int smk_ptrace_rule_check(struct task_struct *tracer, char *tracee_label,
        }
 
        tsp = task_security(tracer);
-       skp = smk_of_task(tsp);
+       tracer_known = smk_of_task(tsp);
 
        if ((mode & PTRACE_MODE_ATTACH) &&
            (smack_ptrace_rule == SMACK_PTRACE_EXACT ||
             smack_ptrace_rule == SMACK_PTRACE_DRACONIAN)) {
-               if (skp->smk_known == tracee_label)
+               if (tracer_known->smk_known == tracee_known->smk_known)
                        rc = 0;
                else if (smack_ptrace_rule == SMACK_PTRACE_DRACONIAN)
                        rc = -EACCES;
@@ -215,13 +360,15 @@ static int smk_ptrace_rule_check(struct task_struct *tracer, char *tracee_label,
                        rc = -EACCES;
 
                if (saip)
-                       smack_log(skp->smk_known, tracee_label, 0, rc, saip);
+                       smack_log(tracer_known->smk_known,
+                                 tracee_known->smk_known,
+                                 0, rc, saip);
 
                return rc;
        }
 
        /* In case of rule==SMACK_PTRACE_DEFAULT or mode==PTRACE_MODE_READ */
-       rc = smk_tskacc(tsp, tracee_label, smk_ptrace_mode(mode), saip);
+       rc = smk_tskacc(tsp, tracee_known, smk_ptrace_mode(mode), saip);
        return rc;
 }
 
@@ -250,7 +397,7 @@ static int smack_ptrace_access_check(struct task_struct *ctp, unsigned int mode)
 
        skp = smk_of_task(task_security(ctp));
 
-       rc = smk_ptrace_rule_check(current, skp->smk_known, mode, __func__);
+       rc = smk_ptrace_rule_check(current, skp, mode, __func__);
        return rc;
 }
 
@@ -273,8 +420,7 @@ static int smack_ptrace_traceme(struct task_struct *ptp)
 
        skp = smk_of_task(current_security());
 
-       rc = smk_ptrace_rule_check(ptp, skp->smk_known,
-                                  PTRACE_MODE_ATTACH, __func__);
+       rc = smk_ptrace_rule_check(ptp, skp, PTRACE_MODE_ATTACH, __func__);
        return rc;
 }
 
@@ -318,10 +464,10 @@ static int smack_sb_alloc_security(struct super_block *sb)
        if (sbsp == NULL)
                return -ENOMEM;
 
-       sbsp->smk_root = smack_known_floor.smk_known;
-       sbsp->smk_default = smack_known_floor.smk_known;
-       sbsp->smk_floor = smack_known_floor.smk_known;
-       sbsp->smk_hat = smack_known_hat.smk_known;
+       sbsp->smk_root = &smack_known_floor;
+       sbsp->smk_default = &smack_known_floor;
+       sbsp->smk_floor = &smack_known_floor;
+       sbsp->smk_hat = &smack_known_hat;
        /*
         * smk_initialized will be zero from kzalloc.
         */
@@ -405,7 +551,6 @@ static int smack_sb_kern_mount(struct super_block *sb, int flags, void *data)
        struct smack_known *skp;
        char *op;
        char *commap;
-       char *nsp;
        int transmute = 0;
        int specified = 0;
 
@@ -421,38 +566,38 @@ static int smack_sb_kern_mount(struct super_block *sb, int flags, void *data)
 
                if (strncmp(op, SMK_FSHAT, strlen(SMK_FSHAT)) == 0) {
                        op += strlen(SMK_FSHAT);
-                       nsp = smk_import(op, 0);
-                       if (nsp != NULL) {
-                               sp->smk_hat = nsp;
+                       skp = smk_import_entry(op, 0);
+                       if (skp != NULL) {
+                               sp->smk_hat = skp;
                                specified = 1;
                        }
                } else if (strncmp(op, SMK_FSFLOOR, strlen(SMK_FSFLOOR)) == 0) {
                        op += strlen(SMK_FSFLOOR);
-                       nsp = smk_import(op, 0);
-                       if (nsp != NULL) {
-                               sp->smk_floor = nsp;
+                       skp = smk_import_entry(op, 0);
+                       if (skp != NULL) {
+                               sp->smk_floor = skp;
                                specified = 1;
                        }
                } else if (strncmp(op, SMK_FSDEFAULT,
                                   strlen(SMK_FSDEFAULT)) == 0) {
                        op += strlen(SMK_FSDEFAULT);
-                       nsp = smk_import(op, 0);
-                       if (nsp != NULL) {
-                               sp->smk_default = nsp;
+                       skp = smk_import_entry(op, 0);
+                       if (skp != NULL) {
+                               sp->smk_default = skp;
                                specified = 1;
                        }
                } else if (strncmp(op, SMK_FSROOT, strlen(SMK_FSROOT)) == 0) {
                        op += strlen(SMK_FSROOT);
-                       nsp = smk_import(op, 0);
-                       if (nsp != NULL) {
-                               sp->smk_root = nsp;
+                       skp = smk_import_entry(op, 0);
+                       if (skp != NULL) {
+                               sp->smk_root = skp;
                                specified = 1;
                        }
                } else if (strncmp(op, SMK_FSTRANS, strlen(SMK_FSTRANS)) == 0) {
                        op += strlen(SMK_FSTRANS);
-                       nsp = smk_import(op, 0);
-                       if (nsp != NULL) {
-                               sp->smk_root = nsp;
+                       skp = smk_import_entry(op, 0);
+                       if (skp != NULL) {
+                               sp->smk_root = skp;
                                transmute = 1;
                                specified = 1;
                        }
@@ -469,8 +614,8 @@ static int smack_sb_kern_mount(struct super_block *sb, int flags, void *data)
                 * Unprivileged mounts get root and default from the caller.
                 */
                skp = smk_of_current();
-               sp->smk_root = skp->smk_known;
-               sp->smk_default = skp->smk_known;
+               sp->smk_root = skp;
+               sp->smk_default = skp;
        }
        /*
         * Initialize the root inode.
@@ -507,6 +652,7 @@ static int smack_sb_statfs(struct dentry *dentry)
        smk_ad_setfield_u_fs_path_dentry(&ad, dentry);
 
        rc = smk_curacc(sbp->smk_floor, MAY_READ, &ad);
+       rc = smk_bu_current("statfs", sbp->smk_floor, MAY_READ, rc);
        return rc;
 }
 
@@ -546,7 +692,7 @@ static int smack_bprm_set_creds(struct linux_binprm *bprm)
                tracer = ptrace_parent(current);
                if (likely(tracer != NULL))
                        rc = smk_ptrace_rule_check(tracer,
-                                                  isp->smk_task->smk_known,
+                                                  isp->smk_task,
                                                   PTRACE_MODE_ATTACH,
                                                   __func__);
                rcu_read_unlock();
@@ -607,7 +753,7 @@ static int smack_inode_alloc_security(struct inode *inode)
 {
        struct smack_known *skp = smk_of_current();
 
-       inode->i_security = new_inode_smack(skp->smk_known);
+       inode->i_security = new_inode_smack(skp);
        if (inode->i_security == NULL)
                return -ENOMEM;
        return 0;
@@ -627,8 +773,8 @@ static void smack_inode_free_security(struct inode *inode)
 
 /**
  * smack_inode_init_security - copy out the smack from an inode
- * @inode: the inode
- * @dir: unused
+ * @inode: the newly created inode
+ * @dir: containing directory object
  * @qstr: unused
  * @name: where to put the attribute name
  * @value: where to put the attribute value
@@ -642,8 +788,8 @@ static int smack_inode_init_security(struct inode *inode, struct inode *dir,
 {
        struct inode_smack *issp = inode->i_security;
        struct smack_known *skp = smk_of_current();
-       char *isp = smk_of_inode(inode);
-       char *dsp = smk_of_inode(dir);
+       struct smack_known *isp = smk_of_inode(inode);
+       struct smack_known *dsp = smk_of_inode(dir);
        int may;
 
        if (name)
@@ -651,7 +797,8 @@ static int smack_inode_init_security(struct inode *inode, struct inode *dir,
 
        if (value) {
                rcu_read_lock();
-               may = smk_access_entry(skp->smk_known, dsp, &skp->smk_rules);
+               may = smk_access_entry(skp->smk_known, dsp->smk_known,
+                                      &skp->smk_rules);
                rcu_read_unlock();
 
                /*
@@ -666,13 +813,13 @@ static int smack_inode_init_security(struct inode *inode, struct inode *dir,
                        issp->smk_flags |= SMK_INODE_CHANGED;
                }
 
-               *value = kstrdup(isp, GFP_NOFS);
+               *value = kstrdup(isp->smk_known, GFP_NOFS);
                if (*value == NULL)
                        return -ENOMEM;
        }
 
        if (len)
-               *len = strlen(isp) + 1;
+               *len = strlen(isp->smk_known);
 
        return 0;
 }
@@ -688,7 +835,7 @@ static int smack_inode_init_security(struct inode *inode, struct inode *dir,
 static int smack_inode_link(struct dentry *old_dentry, struct inode *dir,
                            struct dentry *new_dentry)
 {
-       char *isp;
+       struct smack_known *isp;
        struct smk_audit_info ad;
        int rc;
 
@@ -697,11 +844,13 @@ static int smack_inode_link(struct dentry *old_dentry, struct inode *dir,
 
        isp = smk_of_inode(old_dentry->d_inode);
        rc = smk_curacc(isp, MAY_WRITE, &ad);
+       rc = smk_bu_inode(old_dentry->d_inode, MAY_WRITE, rc);
 
        if (rc == 0 && new_dentry->d_inode != NULL) {
                isp = smk_of_inode(new_dentry->d_inode);
                smk_ad_setfield_u_fs_path_dentry(&ad, new_dentry);
                rc = smk_curacc(isp, MAY_WRITE, &ad);
+               rc = smk_bu_inode(new_dentry->d_inode, MAY_WRITE, rc);
        }
 
        return rc;
@@ -728,6 +877,7 @@ static int smack_inode_unlink(struct inode *dir, struct dentry *dentry)
         * You need write access to the thing you're unlinking
         */
        rc = smk_curacc(smk_of_inode(ip), MAY_WRITE, &ad);
+       rc = smk_bu_inode(ip, MAY_WRITE, rc);
        if (rc == 0) {
                /*
                 * You also need write access to the containing directory
@@ -735,6 +885,7 @@ static int smack_inode_unlink(struct inode *dir, struct dentry *dentry)
                smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_INODE);
                smk_ad_setfield_u_fs_inode(&ad, dir);
                rc = smk_curacc(smk_of_inode(dir), MAY_WRITE, &ad);
+               rc = smk_bu_inode(dir, MAY_WRITE, rc);
        }
        return rc;
 }
@@ -759,6 +910,7 @@ static int smack_inode_rmdir(struct inode *dir, struct dentry *dentry)
         * You need write access to the thing you're removing
         */
        rc = smk_curacc(smk_of_inode(dentry->d_inode), MAY_WRITE, &ad);
+       rc = smk_bu_inode(dentry->d_inode, MAY_WRITE, rc);
        if (rc == 0) {
                /*
                 * You also need write access to the containing directory
@@ -766,6 +918,7 @@ static int smack_inode_rmdir(struct inode *dir, struct dentry *dentry)
                smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_INODE);
                smk_ad_setfield_u_fs_inode(&ad, dir);
                rc = smk_curacc(smk_of_inode(dir), MAY_WRITE, &ad);
+               rc = smk_bu_inode(dir, MAY_WRITE, rc);
        }
 
        return rc;
@@ -773,10 +926,10 @@ static int smack_inode_rmdir(struct inode *dir, struct dentry *dentry)
 
 /**
  * smack_inode_rename - Smack check on rename
- * @old_inode: the old directory
- * @old_dentry: unused
- * @new_inode: the new directory
- * @new_dentry: unused
+ * @old_inode: unused
+ * @old_dentry: the old object
+ * @new_inode: unused
+ * @new_dentry: the new object
  *
  * Read and write access is required on both the old and
  * new directories.
@@ -789,7 +942,7 @@ static int smack_inode_rename(struct inode *old_inode,
                              struct dentry *new_dentry)
 {
        int rc;
-       char *isp;
+       struct smack_known *isp;
        struct smk_audit_info ad;
 
        smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_DENTRY);
@@ -797,11 +950,13 @@ static int smack_inode_rename(struct inode *old_inode,
 
        isp = smk_of_inode(old_dentry->d_inode);
        rc = smk_curacc(isp, MAY_READWRITE, &ad);
+       rc = smk_bu_inode(old_dentry->d_inode, MAY_READWRITE, rc);
 
        if (rc == 0 && new_dentry->d_inode != NULL) {
                isp = smk_of_inode(new_dentry->d_inode);
                smk_ad_setfield_u_fs_path_dentry(&ad, new_dentry);
                rc = smk_curacc(isp, MAY_READWRITE, &ad);
+               rc = smk_bu_inode(new_dentry->d_inode, MAY_READWRITE, rc);
        }
        return rc;
 }
@@ -819,6 +974,7 @@ static int smack_inode_permission(struct inode *inode, int mask)
 {
        struct smk_audit_info ad;
        int no_block = mask & MAY_NOT_BLOCK;
+       int rc;
 
        mask &= (MAY_READ|MAY_WRITE|MAY_EXEC|MAY_APPEND);
        /*
@@ -832,7 +988,9 @@ static int smack_inode_permission(struct inode *inode, int mask)
                return -ECHILD;
        smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_INODE);
        smk_ad_setfield_u_fs_inode(&ad, inode);
-       return smk_curacc(smk_of_inode(inode), mask, &ad);
+       rc = smk_curacc(smk_of_inode(inode), mask, &ad);
+       rc = smk_bu_inode(inode, mask, rc);
+       return rc;
 }
 
 /**
@@ -845,6 +1003,8 @@ static int smack_inode_permission(struct inode *inode, int mask)
 static int smack_inode_setattr(struct dentry *dentry, struct iattr *iattr)
 {
        struct smk_audit_info ad;
+       int rc;
+
        /*
         * Need to allow for clearing the setuid bit.
         */
@@ -853,12 +1013,14 @@ static int smack_inode_setattr(struct dentry *dentry, struct iattr *iattr)
        smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_DENTRY);
        smk_ad_setfield_u_fs_path_dentry(&ad, dentry);
 
-       return smk_curacc(smk_of_inode(dentry->d_inode), MAY_WRITE, &ad);
+       rc = smk_curacc(smk_of_inode(dentry->d_inode), MAY_WRITE, &ad);
+       rc = smk_bu_inode(dentry->d_inode, MAY_WRITE, rc);
+       return rc;
 }
 
 /**
  * smack_inode_getattr - Smack check for getting attributes
- * @mnt: unused
+ * @mnt: vfsmount of the object
  * @dentry: the object
  *
  * Returns 0 if access is permitted, an error code otherwise
@@ -867,21 +1029,24 @@ static int smack_inode_getattr(struct vfsmount *mnt, struct dentry *dentry)
 {
        struct smk_audit_info ad;
        struct path path;
+       int rc;
 
        path.dentry = dentry;
        path.mnt = mnt;
 
        smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_PATH);
        smk_ad_setfield_u_fs_path(&ad, path);
-       return smk_curacc(smk_of_inode(dentry->d_inode), MAY_READ, &ad);
+       rc = smk_curacc(smk_of_inode(dentry->d_inode), MAY_READ, &ad);
+       rc = smk_bu_inode(dentry->d_inode, MAY_READ, rc);
+       return rc;
 }
 
 /**
  * smack_inode_setxattr - Smack check for setting xattrs
  * @dentry: the object
  * @name: name of the attribute
- * @value: unused
- * @size: unused
+ * @value: value of the attribute
+ * @size: size of the value
  * @flags: unused
  *
  * This protects the Smack attribute explicitly.
@@ -923,7 +1088,7 @@ static int smack_inode_setxattr(struct dentry *dentry, const char *name,
                rc = -EPERM;
 
        if (rc == 0 && check_import) {
-               skp = smk_import_entry(value, size);
+               skp = size ? smk_import_entry(value, size) : NULL;
                if (skp == NULL || (check_star &&
                    (skp == &smack_known_star || skp == &smack_known_web)))
                        rc = -EINVAL;
@@ -932,8 +1097,10 @@ static int smack_inode_setxattr(struct dentry *dentry, const char *name,
        smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_DENTRY);
        smk_ad_setfield_u_fs_path_dentry(&ad, dentry);
 
-       if (rc == 0)
+       if (rc == 0) {
                rc = smk_curacc(smk_of_inode(dentry->d_inode), MAY_WRITE, &ad);
+               rc = smk_bu_inode(dentry->d_inode, MAY_WRITE, rc);
+       }
 
        return rc;
 }
@@ -963,9 +1130,9 @@ static void smack_inode_post_setxattr(struct dentry *dentry, const char *name,
        if (strcmp(name, XATTR_NAME_SMACK) == 0) {
                skp = smk_import_entry(value, size);
                if (skp != NULL)
-                       isp->smk_inode = skp->smk_known;
+                       isp->smk_inode = skp;
                else
-                       isp->smk_inode = smack_known_invalid.smk_known;
+                       isp->smk_inode = &smack_known_invalid;
        } else if (strcmp(name, XATTR_NAME_SMACKEXEC) == 0) {
                skp = smk_import_entry(value, size);
                if (skp != NULL)
@@ -993,11 +1160,14 @@ static void smack_inode_post_setxattr(struct dentry *dentry, const char *name,
 static int smack_inode_getxattr(struct dentry *dentry, const char *name)
 {
        struct smk_audit_info ad;
+       int rc;
 
        smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_DENTRY);
        smk_ad_setfield_u_fs_path_dentry(&ad, dentry);
 
-       return smk_curacc(smk_of_inode(dentry->d_inode), MAY_READ, &ad);
+       rc = smk_curacc(smk_of_inode(dentry->d_inode), MAY_READ, &ad);
+       rc = smk_bu_inode(dentry->d_inode, MAY_READ, rc);
+       return rc;
 }
 
 /**
@@ -1033,6 +1203,7 @@ static int smack_inode_removexattr(struct dentry *dentry, const char *name)
        smk_ad_setfield_u_fs_path_dentry(&ad, dentry);
 
        rc = smk_curacc(smk_of_inode(dentry->d_inode), MAY_WRITE, &ad);
+       rc = smk_bu_inode(dentry->d_inode, MAY_WRITE, rc);
        if (rc != 0)
                return rc;
 
@@ -1070,14 +1241,14 @@ static int smack_inode_getsecurity(const struct inode *inode,
        struct socket *sock;
        struct super_block *sbp;
        struct inode *ip = (struct inode *)inode;
-       char *isp;
+       struct smack_known *isp;
        int ilen;
        int rc = 0;
 
        if (strcmp(name, XATTR_SMACK_SUFFIX) == 0) {
                isp = smk_of_inode(inode);
-               ilen = strlen(isp) + 1;
-               *buffer = isp;
+               ilen = strlen(isp->smk_known);
+               *buffer = isp->smk_known;
                return ilen;
        }
 
@@ -1095,15 +1266,15 @@ static int smack_inode_getsecurity(const struct inode *inode,
        ssp = sock->sk->sk_security;
 
        if (strcmp(name, XATTR_SMACK_IPIN) == 0)
-               isp = ssp->smk_in->smk_known;
+               isp = ssp->smk_in;
        else if (strcmp(name, XATTR_SMACK_IPOUT) == 0)
-               isp = ssp->smk_out->smk_known;
+               isp = ssp->smk_out;
        else
                return -EOPNOTSUPP;
 
-       ilen = strlen(isp) + 1;
+       ilen = strlen(isp->smk_known);
        if (rc == 0) {
-               *buffer = isp;
+               *buffer = isp->smk_known;
                rc = ilen;
        }
 
@@ -1122,13 +1293,12 @@ static int smack_inode_getsecurity(const struct inode *inode,
 static int smack_inode_listsecurity(struct inode *inode, char *buffer,
                                    size_t buffer_size)
 {
-       int len = strlen(XATTR_NAME_SMACK);
+       int len = sizeof(XATTR_NAME_SMACK);
 
-       if (buffer != NULL && len <= buffer_size) {
+       if (buffer != NULL && len <= buffer_size)
                memcpy(buffer, XATTR_NAME_SMACK, len);
-               return len;
-       }
-       return -EINVAL;
+
+       return len;
 }
 
 /**
@@ -1140,7 +1310,7 @@ static void smack_inode_getsecid(const struct inode *inode, u32 *secid)
 {
        struct inode_smack *isp = inode->i_security;
 
-       *secid = smack_to_secid(isp->smk_inode);
+       *secid = isp->smk_inode->smk_secid;
 }
 
 /*
@@ -1179,7 +1349,7 @@ static int smack_file_alloc_security(struct file *file)
 {
        struct smack_known *skp = smk_of_current();
 
-       file->f_security = skp->smk_known;
+       file->f_security = skp;
        return 0;
 }
 
@@ -1214,11 +1384,15 @@ static int smack_file_ioctl(struct file *file, unsigned int cmd,
        smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_PATH);
        smk_ad_setfield_u_fs_path(&ad, file->f_path);
 
-       if (_IOC_DIR(cmd) & _IOC_WRITE)
+       if (_IOC_DIR(cmd) & _IOC_WRITE) {
                rc = smk_curacc(file->f_security, MAY_WRITE, &ad);
+               rc = smk_bu_file(file, MAY_WRITE, rc);
+       }
 
-       if (rc == 0 && (_IOC_DIR(cmd) & _IOC_READ))
+       if (rc == 0 && (_IOC_DIR(cmd) & _IOC_READ)) {
                rc = smk_curacc(file->f_security, MAY_READ, &ad);
+               rc = smk_bu_file(file, MAY_READ, rc);
+       }
 
        return rc;
 }
@@ -1233,10 +1407,13 @@ static int smack_file_ioctl(struct file *file, unsigned int cmd,
 static int smack_file_lock(struct file *file, unsigned int cmd)
 {
        struct smk_audit_info ad;
+       int rc;
 
        smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_PATH);
        smk_ad_setfield_u_fs_path(&ad, file->f_path);
-       return smk_curacc(file->f_security, MAY_LOCK, &ad);
+       rc = smk_curacc(file->f_security, MAY_LOCK, &ad);
+       rc = smk_bu_file(file, MAY_LOCK, rc);
+       return rc;
 }
 
 /**
@@ -1266,12 +1443,14 @@ static int smack_file_fcntl(struct file *file, unsigned int cmd,
                smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_PATH);
                smk_ad_setfield_u_fs_path(&ad, file->f_path);
                rc = smk_curacc(file->f_security, MAY_LOCK, &ad);
+               rc = smk_bu_file(file, MAY_LOCK, rc);
                break;
        case F_SETOWN:
        case F_SETSIG:
                smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_PATH);
                smk_ad_setfield_u_fs_path(&ad, file->f_path);
                rc = smk_curacc(file->f_security, MAY_WRITE, &ad);
+               rc = smk_bu_file(file, MAY_WRITE, rc);
                break;
        default:
                break;
@@ -1298,7 +1477,7 @@ static int smack_mmap_file(struct file *file,
        struct smack_known *mkp;
        struct smack_rule *srp;
        struct task_smack *tsp;
-       char *osmack;
+       struct smack_known *okp;
        struct inode_smack *isp;
        int may;
        int mmay;
@@ -1324,18 +1503,19 @@ static int smack_mmap_file(struct file *file,
         * to that rule's object label.
         */
        list_for_each_entry_rcu(srp, &skp->smk_rules, list) {
-               osmack = srp->smk_object;
+               okp = srp->smk_object;
                /*
                 * Matching labels always allows access.
                 */
-               if (mkp->smk_known == osmack)
+               if (mkp->smk_known == okp->smk_known)
                        continue;
                /*
                 * If there is a matching local rule take
                 * that into account as well.
                 */
-               may = smk_access_entry(srp->smk_subject->smk_known, osmack,
-                                       &tsp->smk_rules);
+               may = smk_access_entry(srp->smk_subject->smk_known,
+                                      okp->smk_known,
+                                      &tsp->smk_rules);
                if (may == -ENOENT)
                        may = srp->smk_access;
                else
@@ -1352,8 +1532,8 @@ static int smack_mmap_file(struct file *file,
                 * If there isn't one a SMACK64MMAP subject
                 * can't have as much access as current.
                 */
-               mmay = smk_access_entry(mkp->smk_known, osmack,
-                                               &mkp->smk_rules);
+               mmay = smk_access_entry(mkp->smk_known, okp->smk_known,
+                                       &mkp->smk_rules);
                if (mmay == -ENOENT) {
                        rc = -EACCES;
                        break;
@@ -1362,8 +1542,8 @@ static int smack_mmap_file(struct file *file,
                 * If there is a local entry it modifies the
                 * potential access, too.
                 */
-               tmay = smk_access_entry(mkp->smk_known, osmack,
-                                               &tsp->smk_rules);
+               tmay = smk_access_entry(mkp->smk_known, okp->smk_known,
+                                       &tsp->smk_rules);
                if (tmay != -ENOENT)
                        mmay &= tmay;
 
@@ -1390,12 +1570,11 @@ static int smack_mmap_file(struct file *file,
  * Returns 0
  * Further research may be required on this one.
  */
-static int smack_file_set_fowner(struct file *file)
+static void smack_file_set_fowner(struct file *file)
 {
        struct smack_known *skp = smk_of_current();
 
-       file->f_security = skp->smk_known;
-       return 0;
+       file->f_security = skp;
 }
 
 /**
@@ -1424,14 +1603,15 @@ static int smack_file_send_sigiotask(struct task_struct *tsk,
        file = container_of(fown, struct file, f_owner);
 
        /* we don't log here as rc can be overriden */
-       skp = smk_find_entry(file->f_security);
-       rc = smk_access(skp, tkp->smk_known, MAY_WRITE, NULL);
+       skp = file->f_security;
+       rc = smk_access(skp, tkp, MAY_WRITE, NULL);
+       rc = smk_bu_note("sigiotask", skp, tkp, MAY_WRITE, rc);
        if (rc != 0 && has_capability(tsk, CAP_MAC_OVERRIDE))
                rc = 0;
 
        smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_TASK);
        smk_ad_setfield_u_tsk(&ad, tsk);
-       smack_log(file->f_security, tkp->smk_known, MAY_WRITE, rc, &ad);
+       smack_log(skp->smk_known, tkp->smk_known, MAY_WRITE, rc, &ad);
        return rc;
 }
 
@@ -1443,6 +1623,7 @@ static int smack_file_send_sigiotask(struct task_struct *tsk,
  */
 static int smack_file_receive(struct file *file)
 {
+       int rc;
        int may = 0;
        struct smk_audit_info ad;
 
@@ -1456,7 +1637,9 @@ static int smack_file_receive(struct file *file)
        if (file->f_mode & FMODE_WRITE)
                may |= MAY_WRITE;
 
-       return smk_curacc(file->f_security, may, &ad);
+       rc = smk_curacc(file->f_security, may, &ad);
+       rc = smk_bu_file(file, may, rc);
+       return rc;
 }
 
 /**
@@ -1478,12 +1661,15 @@ static int smack_file_open(struct file *file, const struct cred *cred)
        struct smk_audit_info ad;
        int rc;
 
-       if (smack_privileged(CAP_MAC_OVERRIDE))
+       if (smack_privileged(CAP_MAC_OVERRIDE)) {
+               file->f_security = isp->smk_inode;
                return 0;
+       }
 
        smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_PATH);
        smk_ad_setfield_u_fs_path(&ad, file->f_path);
        rc = smk_access(tsp->smk_task, isp->smk_inode, MAY_READ, &ad);
+       rc = smk_bu_credfile(cred, file, MAY_READ, rc);
        if (rc == 0)
                file->f_security = isp->smk_inode;
 
@@ -1622,7 +1808,7 @@ static int smack_kernel_create_files_as(struct cred *new,
        struct inode_smack *isp = inode->i_security;
        struct task_smack *tsp = new->security;
 
-       tsp->smk_forked = smk_find_entry(isp->smk_inode);
+       tsp->smk_forked = isp->smk_inode;
        tsp->smk_task = tsp->smk_forked;
        return 0;
 }
@@ -1640,10 +1826,13 @@ static int smk_curacc_on_task(struct task_struct *p, int access,
 {
        struct smk_audit_info ad;
        struct smack_known *skp = smk_of_task(task_security(p));
+       int rc;
 
        smk_ad_init(&ad, caller, LSM_AUDIT_DATA_TASK);
        smk_ad_setfield_u_tsk(&ad, p);
-       return smk_curacc(skp->smk_known, access, &ad);
+       rc = smk_curacc(skp, access, &ad);
+       rc = smk_bu_task(p, access, rc);
+       return rc;
 }
 
 /**
@@ -1797,6 +1986,7 @@ static int smack_task_kill(struct task_struct *p, struct siginfo *info,
        struct smk_audit_info ad;
        struct smack_known *skp;
        struct smack_known *tkp = smk_of_task(task_security(p));
+       int rc;
 
        smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_TASK);
        smk_ad_setfield_u_tsk(&ad, p);
@@ -1804,15 +1994,20 @@ static int smack_task_kill(struct task_struct *p, struct siginfo *info,
         * Sending a signal requires that the sender
         * can write the receiver.
         */
-       if (secid == 0)
-               return smk_curacc(tkp->smk_known, MAY_WRITE, &ad);
+       if (secid == 0) {
+               rc = smk_curacc(tkp, MAY_WRITE, &ad);
+               rc = smk_bu_task(p, MAY_WRITE, rc);
+               return rc;
+       }
        /*
         * If the secid isn't 0 we're dealing with some USB IO
         * specific behavior. This is not clean. For one thing
         * we can't take privilege into account.
         */
        skp = smack_from_secid(secid);
-       return smk_access(skp, tkp->smk_known, MAY_WRITE, &ad);
+       rc = smk_access(skp, tkp, MAY_WRITE, &ad);
+       rc = smk_bu_note("USB signal", skp, tkp, MAY_WRITE, rc);
+       return rc;
 }
 
 /**
@@ -1846,7 +2041,7 @@ static void smack_task_to_inode(struct task_struct *p, struct inode *inode)
        struct inode_smack *isp = inode->i_security;
        struct smack_known *skp = smk_of_task(task_security(p));
 
-       isp->smk_inode = skp->smk_known;
+       isp->smk_inode = skp;
 }
 
 /*
@@ -1904,7 +2099,7 @@ static void smack_sk_free_security(struct sock *sk)
 *
 * Returns the label of the far end or NULL if it's not special.
 */
-static char *smack_host_label(struct sockaddr_in *sip)
+static struct smack_known *smack_host_label(struct sockaddr_in *sip)
 {
        struct smk_netlbladdr *snp;
        struct in_addr *siap = &sip->sin_addr;
@@ -1921,7 +2116,7 @@ static char *smack_host_label(struct sockaddr_in *sip)
                if ((&snp->smk_host.sin_addr)->s_addr ==
                    (siap->s_addr & (&snp->smk_mask)->s_addr)) {
                        /* we have found the special CIPSO option */
-                       if (snp->smk_label == smack_cipso_option)
+                       if (snp->smk_label == &smack_cipso_option)
                                return NULL;
                        return snp->smk_label;
                }
@@ -1986,13 +2181,13 @@ static int smack_netlabel_send(struct sock *sk, struct sockaddr_in *sap)
        struct smack_known *skp;
        int rc;
        int sk_lbl;
-       char *hostsp;
+       struct smack_known *hkp;
        struct socket_smack *ssp = sk->sk_security;
        struct smk_audit_info ad;
 
        rcu_read_lock();
-       hostsp = smack_host_label(sap);
-       if (hostsp != NULL) {
+       hkp = smack_host_label(sap);
+       if (hkp != NULL) {
 #ifdef CONFIG_AUDIT
                struct lsm_network_audit net;
 
@@ -2003,7 +2198,8 @@ static int smack_netlabel_send(struct sock *sk, struct sockaddr_in *sap)
 #endif
                sk_lbl = SMACK_UNLABELED_SOCKET;
                skp = ssp->smk_out;
-               rc = smk_access(skp, hostsp, MAY_WRITE, &ad);
+               rc = smk_access(skp, hkp, MAY_WRITE, &ad);
+               rc = smk_bu_note("IPv4 host check", skp, hkp, MAY_WRITE, rc);
        } else {
                sk_lbl = SMACK_CIPSO_SOCKET;
                rc = 0;
@@ -2104,18 +2300,19 @@ static int smk_ipv6_port_check(struct sock *sk, struct sockaddr_in6 *address,
        struct socket_smack *ssp = sk->sk_security;
        struct smack_known *skp;
        unsigned short port = 0;
-       char *object;
+       struct smack_known *object;
        struct smk_audit_info ad;
+       int rc;
 #ifdef CONFIG_AUDIT
        struct lsm_network_audit net;
 #endif
 
        if (act == SMK_RECEIVING) {
                skp = smack_net_ambient;
-               object = ssp->smk_in->smk_known;
+               object = ssp->smk_in;
        } else {
                skp = ssp->smk_out;
-               object = smack_net_ambient->smk_known;
+               object = smack_net_ambient;
        }
 
        /*
@@ -2142,7 +2339,7 @@ static int smk_ipv6_port_check(struct sock *sk, struct sockaddr_in6 *address,
        list_for_each_entry(spp, &smk_ipv6_port_list, list) {
                if (spp->smk_port != port)
                        continue;
-               object = spp->smk_in->smk_known;
+               object = spp->smk_in;
                if (act == SMK_CONNECTING)
                        ssp->smk_packet = spp->smk_out;
                break;
@@ -2159,7 +2356,9 @@ auditout:
        else
                ad.a.u.net->v6info.daddr = address->sin6_addr;
 #endif
-       return smk_access(skp, object, MAY_WRITE, &ad);
+       rc = smk_access(skp, object, MAY_WRITE, &ad);
+       rc = smk_bu_note("IPv6 port check", skp, object, MAY_WRITE, rc);
+       return rc;
 }
 
 /**
@@ -2191,7 +2390,7 @@ static int smack_inode_setsecurity(struct inode *inode, const char *name,
                return -EINVAL;
 
        if (strcmp(name, XATTR_SMACK_SUFFIX) == 0) {
-               nsp->smk_inode = skp->smk_known;
+               nsp->smk_inode = skp;
                nsp->smk_flags |= SMK_INODE_INSTANT;
                return 0;
        }
@@ -2333,7 +2532,7 @@ static int smack_msg_msg_alloc_security(struct msg_msg *msg)
 {
        struct smack_known *skp = smk_of_current();
 
-       msg->security = skp->smk_known;
+       msg->security = skp;
        return 0;
 }
 
@@ -2354,9 +2553,9 @@ static void smack_msg_msg_free_security(struct msg_msg *msg)
  *
  * Returns a pointer to the smack value
  */
-static char *smack_of_shm(struct shmid_kernel *shp)
+static struct smack_known *smack_of_shm(struct shmid_kernel *shp)
 {
-       return (char *)shp->shm_perm.security;
+       return (struct smack_known *)shp->shm_perm.security;
 }
 
 /**
@@ -2370,7 +2569,7 @@ static int smack_shm_alloc_security(struct shmid_kernel *shp)
        struct kern_ipc_perm *isp = &shp->shm_perm;
        struct smack_known *skp = smk_of_current();
 
-       isp->security = skp->smk_known;
+       isp->security = skp;
        return 0;
 }
 
@@ -2396,14 +2595,17 @@ static void smack_shm_free_security(struct shmid_kernel *shp)
  */
 static int smk_curacc_shm(struct shmid_kernel *shp, int access)
 {
-       char *ssp = smack_of_shm(shp);
+       struct smack_known *ssp = smack_of_shm(shp);
        struct smk_audit_info ad;
+       int rc;
 
 #ifdef CONFIG_AUDIT
        smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_IPC);
        ad.a.u.ipc_id = shp->shm_perm.id;
 #endif
-       return smk_curacc(ssp, access, &ad);
+       rc = smk_curacc(ssp, access, &ad);
+       rc = smk_bu_current("shm", ssp, access, rc);
+       return rc;
 }
 
 /**
@@ -2478,9 +2680,9 @@ static int smack_shm_shmat(struct shmid_kernel *shp, char __user *shmaddr,
  *
  * Returns a pointer to the smack value
  */
-static char *smack_of_sem(struct sem_array *sma)
+static struct smack_known *smack_of_sem(struct sem_array *sma)
 {
-       return (char *)sma->sem_perm.security;
+       return (struct smack_known *)sma->sem_perm.security;
 }
 
 /**
@@ -2494,7 +2696,7 @@ static int smack_sem_alloc_security(struct sem_array *sma)
        struct kern_ipc_perm *isp = &sma->sem_perm;
        struct smack_known *skp = smk_of_current();
 
-       isp->security = skp->smk_known;
+       isp->security = skp;
        return 0;
 }
 
@@ -2520,14 +2722,17 @@ static void smack_sem_free_security(struct sem_array *sma)
  */
 static int smk_curacc_sem(struct sem_array *sma, int access)
 {
-       char *ssp = smack_of_sem(sma);
+       struct smack_known *ssp = smack_of_sem(sma);
        struct smk_audit_info ad;
+       int rc;
 
 #ifdef CONFIG_AUDIT
        smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_IPC);
        ad.a.u.ipc_id = sma->sem_perm.id;
 #endif
-       return smk_curacc(ssp, access, &ad);
+       rc = smk_curacc(ssp, access, &ad);
+       rc = smk_bu_current("sem", ssp, access, rc);
+       return rc;
 }
 
 /**
@@ -2613,7 +2818,7 @@ static int smack_msg_queue_alloc_security(struct msg_queue *msq)
        struct kern_ipc_perm *kisp = &msq->q_perm;
        struct smack_known *skp = smk_of_current();
 
-       kisp->security = skp->smk_known;
+       kisp->security = skp;
        return 0;
 }
 
@@ -2634,11 +2839,11 @@ static void smack_msg_queue_free_security(struct msg_queue *msq)
  * smack_of_msq - the smack pointer for the msq
  * @msq: the object
  *
- * Returns a pointer to the smack value
+ * Returns a pointer to the smack label entry
  */
-static char *smack_of_msq(struct msg_queue *msq)
+static struct smack_known *smack_of_msq(struct msg_queue *msq)
 {
-       return (char *)msq->q_perm.security;
+       return (struct smack_known *)msq->q_perm.security;
 }
 
 /**
@@ -2650,14 +2855,17 @@ static char *smack_of_msq(struct msg_queue *msq)
  */
 static int smk_curacc_msq(struct msg_queue *msq, int access)
 {
-       char *msp = smack_of_msq(msq);
+       struct smack_known *msp = smack_of_msq(msq);
        struct smk_audit_info ad;
+       int rc;
 
 #ifdef CONFIG_AUDIT
        smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_IPC);
        ad.a.u.ipc_id = msq->q_perm.id;
 #endif
-       return smk_curacc(msp, access, &ad);
+       rc = smk_curacc(msp, access, &ad);
+       rc = smk_bu_current("msq", msp, access, rc);
+       return rc;
 }
 
 /**
@@ -2750,15 +2958,18 @@ static int smack_msg_queue_msgrcv(struct msg_queue *msq, struct msg_msg *msg,
  */
 static int smack_ipc_permission(struct kern_ipc_perm *ipp, short flag)
 {
-       char *isp = ipp->security;
+       struct smack_known *iskp = ipp->security;
        int may = smack_flags_to_may(flag);
        struct smk_audit_info ad;
+       int rc;
 
 #ifdef CONFIG_AUDIT
        smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_IPC);
        ad.a.u.ipc_id = ipp->id;
 #endif
-       return smk_curacc(isp, may, &ad);
+       rc = smk_curacc(iskp, may, &ad);
+       rc = smk_bu_current("svipc", iskp, may, rc);
+       return rc;
 }
 
 /**
@@ -2768,9 +2979,9 @@ static int smack_ipc_permission(struct kern_ipc_perm *ipp, short flag)
  */
 static void smack_ipc_getsecid(struct kern_ipc_perm *ipp, u32 *secid)
 {
-       char *smack = ipp->security;
+       struct smack_known *iskp = ipp->security;
 
-       *secid = smack_to_secid(smack);
+       *secid = iskp->smk_secid;
 }
 
 /**
@@ -2787,7 +2998,7 @@ static void smack_d_instantiate(struct dentry *opt_dentry, struct inode *inode)
        struct inode_smack *isp;
        struct smack_known *skp;
        struct smack_known *ckp = smk_of_current();
-       char *final;
+       struct smack_known *final;
        char trattr[TRANS_TRUE_SIZE];
        int transflag = 0;
        int rc;
@@ -2827,8 +3038,8 @@ static void smack_d_instantiate(struct dentry *opt_dentry, struct inode *inode)
                         * so there's no opportunity to set the mount
                         * options.
                         */
-                       sbsp->smk_root = smack_known_star.smk_known;
-                       sbsp->smk_default = smack_known_star.smk_known;
+                       sbsp->smk_root = &smack_known_star;
+                       sbsp->smk_default = &smack_known_star;
                }
                isp->smk_inode = sbsp->smk_root;
                isp->smk_flags |= SMK_INODE_INSTANT;
@@ -2858,7 +3069,7 @@ static void smack_d_instantiate(struct dentry *opt_dentry, struct inode *inode)
                 *
                 * Cgroupfs is special
                 */
-               final = smack_known_star.smk_known;
+               final = &smack_known_star;
                break;
        case DEVPTS_SUPER_MAGIC:
                /*
@@ -2866,7 +3077,7 @@ static void smack_d_instantiate(struct dentry *opt_dentry, struct inode *inode)
                 * Programs that change smack have to treat the
                 * pty with respect.
                 */
-               final = ckp->smk_known;
+               final = ckp;
                break;
        case PROC_SUPER_MAGIC:
                /*
@@ -2880,7 +3091,7 @@ static void smack_d_instantiate(struct dentry *opt_dentry, struct inode *inode)
                 * but watch out, because they're volitile,
                 * getting recreated on every reboot.
                 */
-               final = smack_known_star.smk_known;
+               final = &smack_known_star;
                /*
                 * No break.
                 *
@@ -2899,7 +3110,7 @@ static void smack_d_instantiate(struct dentry *opt_dentry, struct inode *inode)
                 * UNIX domain sockets use lower level socket data.
                 */
                if (S_ISSOCK(inode->i_mode)) {
-                       final = smack_known_star.smk_known;
+                       final = &smack_known_star;
                        break;
                }
                /*
@@ -2916,7 +3127,7 @@ static void smack_d_instantiate(struct dentry *opt_dentry, struct inode *inode)
                dp = dget(opt_dentry);
                skp = smk_fetch(XATTR_NAME_SMACK, inode, dp);
                if (skp != NULL)
-                       final = skp->smk_known;
+                       final = skp;
 
                /*
                 * Transmuting directory
@@ -2965,7 +3176,7 @@ static void smack_d_instantiate(struct dentry *opt_dentry, struct inode *inode)
        }
 
        if (final == NULL)
-               isp->smk_inode = ckp->smk_known;
+               isp->smk_inode = ckp;
        else
                isp->smk_inode = final;
 
@@ -3090,9 +3301,13 @@ static int smack_unix_stream_connect(struct sock *sock,
                smk_ad_init_net(&ad, __func__, LSM_AUDIT_DATA_NET, &net);
                smk_ad_setfield_u_net_sk(&ad, other);
 #endif
-               rc = smk_access(skp, okp->smk_known, MAY_WRITE, &ad);
-               if (rc == 0)
-                       rc = smk_access(okp, okp->smk_known, MAY_WRITE, NULL);
+               rc = smk_access(skp, okp, MAY_WRITE, &ad);
+               rc = smk_bu_note("UDS connect", skp, okp, MAY_WRITE, rc);
+               if (rc == 0) {
+                       rc = smk_access(okp, skp, MAY_WRITE, NULL);
+                       rc = smk_bu_note("UDS connect", okp, skp,
+                                               MAY_WRITE, rc);
+               }
        }
 
        /*
@@ -3118,8 +3333,8 @@ static int smack_unix_may_send(struct socket *sock, struct socket *other)
 {
        struct socket_smack *ssp = sock->sk->sk_security;
        struct socket_smack *osp = other->sk->sk_security;
-       struct smack_known *skp;
        struct smk_audit_info ad;
+       int rc;
 
 #ifdef CONFIG_AUDIT
        struct lsm_network_audit net;
@@ -3131,8 +3346,9 @@ static int smack_unix_may_send(struct socket *sock, struct socket *other)
        if (smack_privileged(CAP_MAC_OVERRIDE))
                return 0;
 
-       skp = ssp->smk_out;
-       return smk_access(skp, osp->smk_in->smk_known, MAY_WRITE, &ad);
+       rc = smk_access(ssp->smk_out, osp->smk_in, MAY_WRITE, &ad);
+       rc = smk_bu_note("UDS send", ssp->smk_out, osp->smk_in, MAY_WRITE, rc);
+       return rc;
 }
 
 /**
@@ -3346,7 +3562,9 @@ static int smack_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
                 * This is the simplist possible security model
                 * for networking.
                 */
-               rc = smk_access(skp, ssp->smk_in->smk_known, MAY_WRITE, &ad);
+               rc = smk_access(skp, ssp->smk_in, MAY_WRITE, &ad);
+               rc = smk_bu_note("IPv4 delivery", skp, ssp->smk_in,
+                                       MAY_WRITE, rc);
                if (rc != 0)
                        netlbl_skbuff_err(skb, rc, 0);
                break;
@@ -3489,7 +3707,7 @@ static int smack_inet_conn_request(struct sock *sk, struct sk_buff *skb,
        struct netlbl_lsm_secattr secattr;
        struct sockaddr_in addr;
        struct iphdr *hdr;
-       char *hsp;
+       struct smack_known *hskp;
        int rc;
        struct smk_audit_info ad;
 #ifdef CONFIG_AUDIT
@@ -3526,7 +3744,8 @@ static int smack_inet_conn_request(struct sock *sk, struct sk_buff *skb,
         * Receiving a packet requires that the other end be able to write
         * here. Read access is not required.
         */
-       rc = smk_access(skp, ssp->smk_in->smk_known, MAY_WRITE, &ad);
+       rc = smk_access(skp, ssp->smk_in, MAY_WRITE, &ad);
+       rc = smk_bu_note("IPv4 connect", skp, ssp->smk_in, MAY_WRITE, rc);
        if (rc != 0)
                return rc;
 
@@ -3544,10 +3763,10 @@ static int smack_inet_conn_request(struct sock *sk, struct sk_buff *skb,
        hdr = ip_hdr(skb);
        addr.sin_addr.s_addr = hdr->saddr;
        rcu_read_lock();
-       hsp = smack_host_label(&addr);
+       hskp = smack_host_label(&addr);
        rcu_read_unlock();
 
-       if (hsp == NULL)
+       if (hskp == NULL)
                rc = netlbl_req_setattr(req, &skp->smk_netlabel);
        else
                netlbl_req_delattr(req);
@@ -3599,7 +3818,7 @@ static int smack_key_alloc(struct key *key, const struct cred *cred,
 {
        struct smack_known *skp = smk_of_task(cred->security);
 
-       key->security = skp->smk_known;
+       key->security = skp;
        return 0;
 }
 
@@ -3630,6 +3849,7 @@ static int smack_key_permission(key_ref_t key_ref,
        struct smk_audit_info ad;
        struct smack_known *tkp = smk_of_task(cred->security);
        int request = 0;
+       int rc;
 
        keyp = key_ref_to_ptr(key_ref);
        if (keyp == NULL)
@@ -3654,7 +3874,9 @@ static int smack_key_permission(key_ref_t key_ref,
                request = MAY_READ;
        if (perm & (KEY_NEED_WRITE | KEY_NEED_LINK | KEY_NEED_SETATTR))
                request = MAY_WRITE;
-       return smk_access(tkp, keyp->security, request, &ad);
+       rc = smk_access(tkp, keyp->security, request, &ad);
+       rc = smk_bu_note("key access", tkp, keyp->security, request, rc);
+       return rc;
 }
 #endif /* CONFIG_KEYS */
 
@@ -3685,6 +3907,7 @@ static int smack_key_permission(key_ref_t key_ref,
  */
 static int smack_audit_rule_init(u32 field, u32 op, char *rulestr, void **vrule)
 {
+       struct smack_known *skp;
        char **rule = (char **)vrule;
        *rule = NULL;
 
@@ -3694,7 +3917,9 @@ static int smack_audit_rule_init(u32 field, u32 op, char *rulestr, void **vrule)
        if (op != Audit_equal && op != Audit_not_equal)
                return -EINVAL;
 
-       *rule = smk_import(rulestr, 0);
+       skp = smk_import_entry(rulestr, 0);
+       if (skp)
+               *rule = skp->smk_known;
 
        return 0;
 }
@@ -3813,7 +4038,12 @@ static int smack_secid_to_secctx(u32 secid, char **secdata, u32 *seclen)
  */
 static int smack_secctx_to_secid(const char *secdata, u32 seclen, u32 *secid)
 {
-       *secid = smack_to_secid(secdata);
+       struct smack_known *skp = smk_find_entry(secdata);
+
+       if (skp)
+               *secid = skp->smk_secid;
+       else
+               *secid = 0;
        return 0;
 }
 
index 3c720ff105917dcedbfda26c7814f8cc8716fa8f..bce4e8f1b267cef89501cd5538bdff86940cd81c 100644 (file)
@@ -131,14 +131,17 @@ LIST_HEAD(smack_rule_list);
 
 struct smack_parsed_rule {
        struct smack_known      *smk_subject;
-       char                    *smk_object;
+       struct smack_known      *smk_object;
        int                     smk_access1;
        int                     smk_access2;
 };
 
 static int smk_cipso_doi_value = SMACK_CIPSO_DOI_DEFAULT;
 
-const char *smack_cipso_option = SMACK_CIPSO_OPTION;
+struct smack_known smack_cipso_option = {
+       .smk_known      = SMACK_CIPSO_OPTION,
+       .smk_secid      = 0,
+};
 
 /*
  * Values for parsing cipso rules
@@ -304,6 +307,10 @@ static int smk_perm_from_str(const char *string)
                case 'L':
                        perm |= MAY_LOCK;
                        break;
+               case 'b':
+               case 'B':
+                       perm |= MAY_BRINGUP;
+                       break;
                default:
                        return perm;
                }
@@ -335,7 +342,7 @@ static int smk_fill_rule(const char *subject, const char *object,
                if (rule->smk_subject == NULL)
                        return -EINVAL;
 
-               rule->smk_object = smk_import(object, len);
+               rule->smk_object = smk_import_entry(object, len);
                if (rule->smk_object == NULL)
                        return -EINVAL;
        } else {
@@ -355,7 +362,7 @@ static int smk_fill_rule(const char *subject, const char *object,
                kfree(cp);
                if (skp == NULL)
                        return -ENOENT;
-               rule->smk_object = skp->smk_known;
+               rule->smk_object = skp;
        }
 
        rule->smk_access1 = smk_perm_from_str(access1);
@@ -594,13 +601,15 @@ static void smk_rule_show(struct seq_file *s, struct smack_rule *srp, int max)
         * anything you read back.
         */
        if (strlen(srp->smk_subject->smk_known) >= max ||
-           strlen(srp->smk_object) >= max)
+           strlen(srp->smk_object->smk_known) >= max)
                return;
 
        if (srp->smk_access == 0)
                return;
 
-       seq_printf(s, "%s %s", srp->smk_subject->smk_known, srp->smk_object);
+       seq_printf(s, "%s %s",
+                  srp->smk_subject->smk_known,
+                  srp->smk_object->smk_known);
 
        seq_putc(s, ' ');
 
@@ -616,6 +625,8 @@ static void smk_rule_show(struct seq_file *s, struct smack_rule *srp, int max)
                seq_putc(s, 't');
        if (srp->smk_access & MAY_LOCK)
                seq_putc(s, 'l');
+       if (srp->smk_access & MAY_BRINGUP)
+               seq_putc(s, 'b');
 
        seq_putc(s, '\n');
 }
@@ -1067,7 +1078,7 @@ static int netlbladdr_seq_show(struct seq_file *s, void *v)
        for (maskn = 0; temp_mask; temp_mask <<= 1, maskn++);
 
        seq_printf(s, "%u.%u.%u.%u/%d %s\n",
-               hp[0], hp[1], hp[2], hp[3], maskn, skp->smk_label);
+               hp[0], hp[1], hp[2], hp[3], maskn, skp->smk_label->smk_known);
 
        return 0;
 }
@@ -1147,10 +1158,10 @@ static void smk_netlbladdr_insert(struct smk_netlbladdr *new)
 static ssize_t smk_write_netlbladdr(struct file *file, const char __user *buf,
                                size_t count, loff_t *ppos)
 {
-       struct smk_netlbladdr *skp;
+       struct smk_netlbladdr *snp;
        struct sockaddr_in newname;
        char *smack;
-       char *sp;
+       struct smack_known *skp;
        char *data;
        char *host = (char *)&newname.sin_addr.s_addr;
        int rc;
@@ -1213,15 +1224,15 @@ static ssize_t smk_write_netlbladdr(struct file *file, const char __user *buf,
         * If smack begins with '-', it is an option, don't import it
         */
        if (smack[0] != '-') {
-               sp = smk_import(smack, 0);
-               if (sp == NULL) {
+               skp = smk_import_entry(smack, 0);
+               if (skp == NULL) {
                        rc = -EINVAL;
                        goto free_out;
                }
        } else {
                /* check known options */
-               if (strcmp(smack, smack_cipso_option) == 0)
-                       sp = (char *)smack_cipso_option;
+               if (strcmp(smack, smack_cipso_option.smk_known) == 0)
+                       skp = &smack_cipso_option;
                else {
                        rc = -EINVAL;
                        goto free_out;
@@ -1244,9 +1255,9 @@ static ssize_t smk_write_netlbladdr(struct file *file, const char __user *buf,
        nsa = newname.sin_addr.s_addr;
        /* try to find if the prefix is already in the list */
        found = 0;
-       list_for_each_entry_rcu(skp, &smk_netlbladdr_list, list) {
-               if (skp->smk_host.sin_addr.s_addr == nsa &&
-                   skp->smk_mask.s_addr == mask.s_addr) {
+       list_for_each_entry_rcu(snp, &smk_netlbladdr_list, list) {
+               if (snp->smk_host.sin_addr.s_addr == nsa &&
+                   snp->smk_mask.s_addr == mask.s_addr) {
                        found = 1;
                        break;
                }
@@ -1254,26 +1265,26 @@ static ssize_t smk_write_netlbladdr(struct file *file, const char __user *buf,
        smk_netlabel_audit_set(&audit_info);
 
        if (found == 0) {
-               skp = kzalloc(sizeof(*skp), GFP_KERNEL);
-               if (skp == NULL)
+               snp = kzalloc(sizeof(*snp), GFP_KERNEL);
+               if (snp == NULL)
                        rc = -ENOMEM;
                else {
                        rc = 0;
-                       skp->smk_host.sin_addr.s_addr = newname.sin_addr.s_addr;
-                       skp->smk_mask.s_addr = mask.s_addr;
-                       skp->smk_label = sp;
-                       smk_netlbladdr_insert(skp);
+                       snp->smk_host.sin_addr.s_addr = newname.sin_addr.s_addr;
+                       snp->smk_mask.s_addr = mask.s_addr;
+                       snp->smk_label = skp;
+                       smk_netlbladdr_insert(snp);
                }
        } else {
                /* we delete the unlabeled entry, only if the previous label
                 * wasn't the special CIPSO option */
-               if (skp->smk_label != smack_cipso_option)
+               if (snp->smk_label != &smack_cipso_option)
                        rc = netlbl_cfg_unlbl_static_del(&init_net, NULL,
-                                       &skp->smk_host.sin_addr, &skp->smk_mask,
+                                       &snp->smk_host.sin_addr, &snp->smk_mask,
                                        PF_INET, &audit_info);
                else
                        rc = 0;
-               skp->smk_label = sp;
+               snp->smk_label = skp;
        }
 
        /*
@@ -1281,10 +1292,10 @@ static ssize_t smk_write_netlbladdr(struct file *file, const char __user *buf,
         * this host so that incoming packets get labeled.
         * but only if we didn't get the special CIPSO option
         */
-       if (rc == 0 && sp != smack_cipso_option)
+       if (rc == 0 && skp != &smack_cipso_option)
                rc = netlbl_cfg_unlbl_static_add(&init_net, NULL,
-                       &skp->smk_host.sin_addr, &skp->smk_mask, PF_INET,
-                       smack_to_secid(skp->smk_label), &audit_info);
+                       &snp->smk_host.sin_addr, &snp->smk_mask, PF_INET,
+                       snp->smk_label->smk_secid, &audit_info);
 
        if (rc == 0)
                rc = count;
@@ -1677,7 +1688,7 @@ static ssize_t smk_write_onlycap(struct file *file, const char __user *buf,
        if (smack_onlycap != NULL && smack_onlycap != skp)
                return -EPERM;
 
-       data = kzalloc(count, GFP_KERNEL);
+       data = kzalloc(count + 1, GFP_KERNEL);
        if (data == NULL)
                return -ENOMEM;
 
@@ -1880,7 +1891,10 @@ static ssize_t smk_user_access(struct file *file, const char __user *buf,
        else if (res != -ENOENT)
                return -EINVAL;
 
-       data[0] = res == 0 ? '1' : '0';
+       /*
+        * smk_access() can return a value > 0 in the "bringup" case.
+        */
+       data[0] = res >= 0 ? '1' : '0';
        data[1] = '\0';
 
        simple_transaction_set(file, 2);
@@ -2228,7 +2242,7 @@ static ssize_t smk_write_syslog(struct file *file, const char __user *buf,
        if (!smack_privileged(CAP_MAC_ADMIN))
                return -EPERM;
 
-       data = kzalloc(count, GFP_KERNEL);
+       data = kzalloc(count + 1, GFP_KERNEL);
        if (data == NULL)
                return -ENOMEM;
 
index 30e027ecf4da7383c7e6045f0b9a9f9905ca63b4..f2e8226c88fbb962b68fdab5ff40cae30813e873 100644 (file)
@@ -145,6 +145,8 @@ EXPORT_SYMBOL(snd_pci_quirk_lookup_id);
 const struct snd_pci_quirk *
 snd_pci_quirk_lookup(struct pci_dev *pci, const struct snd_pci_quirk *list)
 {
+       if (!pci)
+               return NULL;
        return snd_pci_quirk_lookup_id(pci->subsystem_vendor,
                                       pci->subsystem_device,
                                       list);
index 43932e8dce669a57a0908ffbd57585a858d1616b..42ded997b223b7ece3d8535000d4defeea2ba8f5 100644 (file)
@@ -215,6 +215,7 @@ static char *snd_pcm_format_names[] = {
        FORMAT(G723_40_1B),
        FORMAT(DSD_U8),
        FORMAT(DSD_U16_LE),
+       FORMAT(DSD_U32_LE),
 };
 
 const char *snd_pcm_format_name(snd_pcm_format_t format)
@@ -698,6 +699,7 @@ int snd_pcm_new_stream(struct snd_pcm *pcm, int stream, int substream_count)
                }
                substream->group = &substream->self_group;
                spin_lock_init(&substream->self_group.lock);
+               mutex_init(&substream->self_group.mutex);
                INIT_LIST_HEAD(&substream->self_group.substreams);
                list_add_tail(&substream->link_list, &substream->self_group.substreams);
                atomic_set(&substream->mmap_count, 0);
index 0032278567ad8c0ecc4228a6c2f065d6cd4c85e8..dfc28542a007e6ef44f9ea670e3f1aec59032a0b 100644 (file)
@@ -1113,18 +1113,20 @@ int snd_interval_list(struct snd_interval *i, unsigned int count,
 
 EXPORT_SYMBOL(snd_interval_list);
 
-static int snd_interval_step(struct snd_interval *i, unsigned int min, unsigned int step)
+static int snd_interval_step(struct snd_interval *i, unsigned int step)
 {
        unsigned int n;
        int changed = 0;
-       n = (i->min - min) % step;
+       n = i->min % step;
        if (n != 0 || i->openmin) {
                i->min += step - n;
+               i->openmin = 0;
                changed = 1;
        }
-       n = (i->max - min) % step;
+       n = i->max % step;
        if (n != 0 || i->openmax) {
                i->max -= n;
+               i->openmax = 0;
                changed = 1;
        }
        if (snd_interval_checkempty(i)) {
@@ -1427,7 +1429,7 @@ static int snd_pcm_hw_rule_step(struct snd_pcm_hw_params *params,
                                struct snd_pcm_hw_rule *rule)
 {
        unsigned long step = (unsigned long) rule->private;
-       return snd_interval_step(hw_param_interval(params, rule->var), 0, step);
+       return snd_interval_step(hw_param_interval(params, rule->var), step);
 }
 
 /**
index 2c6fd80e0bd1fd0042848bdc3e68bd2734c4a0c5..ae7a0feb3b76001f54555187c19343bce352f0c8 100644 (file)
@@ -148,6 +148,10 @@ static struct pcm_format_data pcm_formats[(INT)SNDRV_PCM_FORMAT_LAST+1] = {
                .width = 16, .phys = 16, .le = 1, .signd = 0,
                .silence = { 0x69, 0x69 },
        },
+       [SNDRV_PCM_FORMAT_DSD_U32_LE] = {
+               .width = 32, .phys = 32, .le = 1, .signd = 0,
+               .silence = { 0x69, 0x69, 0x69, 0x69 },
+       },
        /* FIXME: the following three formats are not defined properly yet */
        [SNDRV_PCM_FORMAT_MPEG] = {
                .le = -1, .signd = -1,
index 8cd2f930ad0baf1db6646101b89e41f3d5947d57..85fe1a216225cdd14165b3c947d1bf184d23ecd8 100644 (file)
@@ -74,11 +74,68 @@ static int snd_pcm_open(struct file *file, struct snd_pcm *pcm, int stream);
  *
  */
 
-DEFINE_RWLOCK(snd_pcm_link_rwlock);
-EXPORT_SYMBOL(snd_pcm_link_rwlock);
-
+static DEFINE_RWLOCK(snd_pcm_link_rwlock);
 static DECLARE_RWSEM(snd_pcm_link_rwsem);
 
+void snd_pcm_stream_lock(struct snd_pcm_substream *substream)
+{
+       if (substream->pcm->nonatomic) {
+               down_read(&snd_pcm_link_rwsem);
+               mutex_lock(&substream->self_group.mutex);
+       } else {
+               read_lock(&snd_pcm_link_rwlock);
+               spin_lock(&substream->self_group.lock);
+       }
+}
+EXPORT_SYMBOL_GPL(snd_pcm_stream_lock);
+
+void snd_pcm_stream_unlock(struct snd_pcm_substream *substream)
+{
+       if (substream->pcm->nonatomic) {
+               mutex_unlock(&substream->self_group.mutex);
+               up_read(&snd_pcm_link_rwsem);
+       } else {
+               spin_unlock(&substream->self_group.lock);
+               read_unlock(&snd_pcm_link_rwlock);
+       }
+}
+EXPORT_SYMBOL_GPL(snd_pcm_stream_unlock);
+
+void snd_pcm_stream_lock_irq(struct snd_pcm_substream *substream)
+{
+       if (!substream->pcm->nonatomic)
+               local_irq_disable();
+       snd_pcm_stream_lock(substream);
+}
+EXPORT_SYMBOL_GPL(snd_pcm_stream_lock_irq);
+
+void snd_pcm_stream_unlock_irq(struct snd_pcm_substream *substream)
+{
+       snd_pcm_stream_unlock(substream);
+       if (!substream->pcm->nonatomic)
+               local_irq_enable();
+}
+EXPORT_SYMBOL_GPL(snd_pcm_stream_unlock_irq);
+
+unsigned long _snd_pcm_stream_lock_irqsave(struct snd_pcm_substream *substream)
+{
+       unsigned long flags = 0;
+       if (!substream->pcm->nonatomic)
+               local_irq_save(flags);
+       snd_pcm_stream_lock(substream);
+       return flags;
+}
+EXPORT_SYMBOL_GPL(_snd_pcm_stream_lock_irqsave);
+
+void snd_pcm_stream_unlock_irqrestore(struct snd_pcm_substream *substream,
+                                     unsigned long flags)
+{
+       snd_pcm_stream_unlock(substream);
+       if (!substream->pcm->nonatomic)
+               local_irq_restore(flags);
+}
+EXPORT_SYMBOL_GPL(snd_pcm_stream_unlock_irqrestore);
+
 static inline mm_segment_t snd_enter_user(void)
 {
        mm_segment_t fs = get_fs();
@@ -727,9 +784,14 @@ static int snd_pcm_action_group(struct action_ops *ops,
        int res = 0;
 
        snd_pcm_group_for_each_entry(s, substream) {
-               if (do_lock && s != substream)
-                       spin_lock_nested(&s->self_group.lock,
-                                        SINGLE_DEPTH_NESTING);
+               if (do_lock && s != substream) {
+                       if (s->pcm->nonatomic)
+                               mutex_lock_nested(&s->self_group.mutex,
+                                                 SINGLE_DEPTH_NESTING);
+                       else
+                               spin_lock_nested(&s->self_group.lock,
+                                                SINGLE_DEPTH_NESTING);
+               }
                res = ops->pre_action(s, state);
                if (res < 0)
                        goto _unlock;
@@ -755,8 +817,12 @@ static int snd_pcm_action_group(struct action_ops *ops,
        if (do_lock) {
                /* unlock streams */
                snd_pcm_group_for_each_entry(s1, substream) {
-                       if (s1 != substream)
-                               spin_unlock(&s1->self_group.lock);
+                       if (s1 != substream) {
+                               if (s->pcm->nonatomic)
+                                       mutex_unlock(&s1->self_group.mutex);
+                               else
+                                       spin_unlock(&s1->self_group.lock);
+                       }
                        if (s1 == s)    /* end */
                                break;
                }
@@ -784,6 +850,27 @@ static int snd_pcm_action_single(struct action_ops *ops,
        return res;
 }
 
+/* call in mutex-protected context */
+static int snd_pcm_action_mutex(struct action_ops *ops,
+                               struct snd_pcm_substream *substream,
+                               int state)
+{
+       int res;
+
+       if (snd_pcm_stream_linked(substream)) {
+               if (!mutex_trylock(&substream->group->mutex)) {
+                       mutex_unlock(&substream->self_group.mutex);
+                       mutex_lock(&substream->group->mutex);
+                       mutex_lock(&substream->self_group.mutex);
+               }
+               res = snd_pcm_action_group(ops, substream, state, 1);
+               mutex_unlock(&substream->group->mutex);
+       } else {
+               res = snd_pcm_action_single(ops, substream, state);
+       }
+       return res;
+}
+
 /*
  *  Note: call with stream lock
  */
@@ -793,6 +880,9 @@ static int snd_pcm_action(struct action_ops *ops,
 {
        int res;
 
+       if (substream->pcm->nonatomic)
+               return snd_pcm_action_mutex(ops, substream, state);
+
        if (snd_pcm_stream_linked(substream)) {
                if (!spin_trylock(&substream->group->lock)) {
                        spin_unlock(&substream->self_group.lock);
@@ -807,6 +897,29 @@ static int snd_pcm_action(struct action_ops *ops,
        return res;
 }
 
+static int snd_pcm_action_lock_mutex(struct action_ops *ops,
+                                    struct snd_pcm_substream *substream,
+                                    int state)
+{
+       int res;
+
+       down_read(&snd_pcm_link_rwsem);
+       if (snd_pcm_stream_linked(substream)) {
+               mutex_lock(&substream->group->mutex);
+               mutex_lock_nested(&substream->self_group.mutex,
+                                 SINGLE_DEPTH_NESTING);
+               res = snd_pcm_action_group(ops, substream, state, 1);
+               mutex_unlock(&substream->self_group.mutex);
+               mutex_unlock(&substream->group->mutex);
+       } else {
+               mutex_lock(&substream->self_group.mutex);
+               res = snd_pcm_action_single(ops, substream, state);
+               mutex_unlock(&substream->self_group.mutex);
+       }
+       up_read(&snd_pcm_link_rwsem);
+       return res;
+}
+
 /*
  *  Note: don't use any locks before
  */
@@ -816,6 +929,9 @@ static int snd_pcm_action_lock_irq(struct action_ops *ops,
 {
        int res;
 
+       if (substream->pcm->nonatomic)
+               return snd_pcm_action_lock_mutex(ops, substream, state);
+
        read_lock_irq(&snd_pcm_link_rwlock);
        if (snd_pcm_stream_linked(substream)) {
                spin_lock(&substream->group->lock);
@@ -1634,7 +1750,8 @@ static int snd_pcm_link(struct snd_pcm_substream *substream, int fd)
        down_write(&snd_pcm_link_rwsem);
        write_lock_irq(&snd_pcm_link_rwlock);
        if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN ||
-           substream->runtime->status->state != substream1->runtime->status->state) {
+           substream->runtime->status->state != substream1->runtime->status->state ||
+           substream->pcm->nonatomic != substream1->pcm->nonatomic) {
                res = -EBADFD;
                goto _end;
        }
@@ -1646,6 +1763,7 @@ static int snd_pcm_link(struct snd_pcm_substream *substream, int fd)
                substream->group = group;
                group = NULL;
                spin_lock_init(&substream->group->lock);
+               mutex_init(&substream->group->mutex);
                INIT_LIST_HEAD(&substream->group->substreams);
                list_add_tail(&substream->link_list, &substream->group->substreams);
                substream->group->count = 1;
index 83596891cde4f1d6b1cb9fb7115d4646265bf85e..e8cc169939038a4512172ad5cd61bdb8c6969d2e 100644 (file)
@@ -117,7 +117,7 @@ static int vx_reset_chk(struct vx_core *chip)
  *
  * returns 0 if successful, or a negative error code.
  * the error code can be VX-specific, retrieved via vx_get_error().
- * NB: call with spinlock held!
+ * NB: call with mutex held!
  */
 static int vx_transfer_end(struct vx_core *chip, int cmd)
 {
@@ -155,7 +155,7 @@ static int vx_transfer_end(struct vx_core *chip, int cmd)
  *
  * returns 0 if successful, or a negative error code.
  * the error code can be VX-specific, retrieved via vx_get_error().
- * NB: call with spinlock held!
+ * NB: call with mutex held!
  */
 static int vx_read_status(struct vx_core *chip, struct vx_rmh *rmh)
 {
@@ -236,7 +236,7 @@ static int vx_read_status(struct vx_core *chip, struct vx_rmh *rmh)
  * returns 0 if successful, or a negative error code.
  * the error code can be VX-specific, retrieved via vx_get_error().
  * 
- * this function doesn't call spinlock at all.
+ * this function doesn't call mutex lock at all.
  */
 int vx_send_msg_nolock(struct vx_core *chip, struct vx_rmh *rmh)
 {
@@ -337,7 +337,7 @@ int vx_send_msg_nolock(struct vx_core *chip, struct vx_rmh *rmh)
 
 
 /*
- * vx_send_msg - send a DSP message with spinlock
+ * vx_send_msg - send a DSP message with mutex
  * @rmh: the rmh record to send and receive
  *
  * returns 0 if successful, or a negative error code.
@@ -345,12 +345,11 @@ int vx_send_msg_nolock(struct vx_core *chip, struct vx_rmh *rmh)
  */
 int vx_send_msg(struct vx_core *chip, struct vx_rmh *rmh)
 {
-       unsigned long flags;
        int err;
 
-       spin_lock_irqsave(&chip->lock, flags);
+       mutex_lock(&chip->lock);
        err = vx_send_msg_nolock(chip, rmh);
-       spin_unlock_irqrestore(&chip->lock, flags);
+       mutex_unlock(&chip->lock);
        return err;
 }
 
@@ -362,7 +361,7 @@ int vx_send_msg(struct vx_core *chip, struct vx_rmh *rmh)
  * returns 0 if successful, or a negative error code.
  * the error code can be VX-specific, retrieved via vx_get_error().
  *
- * this function doesn't call spinlock at all.
+ * this function doesn't call mutex at all.
  *
  * unlike RMH, no command is sent to DSP.
  */
@@ -398,19 +397,18 @@ int vx_send_rih_nolock(struct vx_core *chip, int cmd)
 
 
 /*
- * vx_send_rih - send an RIH with spinlock
+ * vx_send_rih - send an RIH with mutex
  * @cmd: the command to send
  *
  * see vx_send_rih_nolock().
  */
 int vx_send_rih(struct vx_core *chip, int cmd)
 {
-       unsigned long flags;
        int err;
 
-       spin_lock_irqsave(&chip->lock, flags);
+       mutex_lock(&chip->lock);
        err = vx_send_rih_nolock(chip, cmd);
-       spin_unlock_irqrestore(&chip->lock, flags);
+       mutex_unlock(&chip->lock);
        return err;
 }
 
@@ -482,30 +480,30 @@ static int vx_test_irq_src(struct vx_core *chip, unsigned int *ret)
        int err;
 
        vx_init_rmh(&chip->irq_rmh, CMD_TEST_IT);
-       spin_lock(&chip->lock);
+       mutex_lock(&chip->lock);
        err = vx_send_msg_nolock(chip, &chip->irq_rmh);
        if (err < 0)
                *ret = 0;
        else
                *ret = chip->irq_rmh.Stat[0];
-       spin_unlock(&chip->lock);
+       mutex_unlock(&chip->lock);
        return err;
 }
 
 
 /*
- * vx_interrupt - soft irq handler
+ * snd_vx_threaded_irq_handler - threaded irq handler
  */
-static void vx_interrupt(unsigned long private_data)
+irqreturn_t snd_vx_threaded_irq_handler(int irq, void *dev)
 {
-       struct vx_core *chip = (struct vx_core *) private_data;
+       struct vx_core *chip = dev;
        unsigned int events;
                
        if (chip->chip_status & VX_STAT_IS_STALE)
-               return;
+               return IRQ_HANDLED;
 
        if (vx_test_irq_src(chip, &events) < 0)
-               return;
+               return IRQ_HANDLED;
     
 #if 0
        if (events & 0x000800)
@@ -519,7 +517,7 @@ static void vx_interrupt(unsigned long private_data)
         */
        if (events & FATAL_DSP_ERROR) {
                snd_printk(KERN_ERR "vx_core: fatal DSP error!!\n");
-               return;
+               return IRQ_HANDLED;
        }
 
        /* The start on time code conditions are filled (ie the time code
@@ -534,8 +532,9 @@ static void vx_interrupt(unsigned long private_data)
 
        /* update the pcm streams */
        vx_pcm_update_intr(chip, events);
+       return IRQ_HANDLED;
 }
-
+EXPORT_SYMBOL(snd_vx_threaded_irq_handler);
 
 /**
  * snd_vx_irq_handler - interrupt handler
@@ -548,8 +547,8 @@ irqreturn_t snd_vx_irq_handler(int irq, void *dev)
            (chip->chip_status & VX_STAT_IS_STALE))
                return IRQ_NONE;
        if (! vx_test_and_ack(chip))
-               tasklet_schedule(&chip->tq);
-       return IRQ_HANDLED;
+               return IRQ_WAKE_THREAD;
+       return IRQ_NONE;
 }
 
 EXPORT_SYMBOL(snd_vx_irq_handler);
@@ -790,13 +789,11 @@ struct vx_core *snd_vx_create(struct snd_card *card, struct snd_vx_hardware *hw,
                snd_printk(KERN_ERR "vx_core: no memory\n");
                return NULL;
        }
-       spin_lock_init(&chip->lock);
-       spin_lock_init(&chip->irq_lock);
+       mutex_init(&chip->lock);
        chip->irq = -1;
        chip->hw = hw;
        chip->type = hw->type;
        chip->ops = ops;
-       tasklet_init(&chip->tq, vx_interrupt, (unsigned long)chip);
        mutex_init(&chip->mixer_mutex);
 
        chip->card = card;
index c71b8d148d7fa82324a18863da0b98459488582a..3b6823fc0606537d6659b2bb5541eb88165d1349 100644 (file)
  */
 static void vx_write_codec_reg(struct vx_core *chip, int codec, unsigned int data)
 {
-       unsigned long flags;
-
        if (snd_BUG_ON(!chip->ops->write_codec))
                return;
 
        if (chip->chip_status & VX_STAT_IS_STALE)
                return;
 
-       spin_lock_irqsave(&chip->lock, flags);
+       mutex_lock(&chip->lock);
        chip->ops->write_codec(chip, codec, data);
-       spin_unlock_irqrestore(&chip->lock, flags);
+       mutex_unlock(&chip->lock);
 }
 
 /*
@@ -178,14 +176,12 @@ void vx_reset_codec(struct vx_core *chip, int cold_reset)
  */
 static void vx_change_audio_source(struct vx_core *chip, int src)
 {
-       unsigned long flags;
-
        if (chip->chip_status & VX_STAT_IS_STALE)
                return;
 
-       spin_lock_irqsave(&chip->lock, flags);
+       mutex_lock(&chip->lock);
        chip->ops->change_audio_source(chip, src);
-       spin_unlock_irqrestore(&chip->lock, flags);
+       mutex_unlock(&chip->lock);
 }
 
 
index deed5efff33c9c57c2d462f7d05de89dc31bf2d7..11467272089e45632935912c4e2b94f8cb604978 100644 (file)
@@ -229,7 +229,7 @@ static int vx_get_pipe_state(struct vx_core *chip, struct vx_pipe *pipe, int *st
 
        vx_init_rmh(&rmh, CMD_PIPE_STATE);
        vx_set_pipe_cmd_params(&rmh, pipe->is_capture, pipe->number, 0);
-       err = vx_send_msg_nolock(chip, &rmh); /* no lock needed for trigger */ 
+       err = vx_send_msg(chip, &rmh);
        if (! err)
                *state = (rmh.Stat[0] & (1 << pipe->number)) ? 1 : 0;
        return err;
@@ -280,7 +280,7 @@ static int vx_pipe_can_start(struct vx_core *chip, struct vx_pipe *pipe)
        vx_set_pipe_cmd_params(&rmh, pipe->is_capture, pipe->number, 0);
        rmh.Cmd[0] |= 1;
 
-       err = vx_send_msg_nolock(chip, &rmh); /* no lock needed for trigger */ 
+       err = vx_send_msg(chip, &rmh);
        if (! err) {
                if (rmh.Stat[0])
                        err = 1;
@@ -300,7 +300,7 @@ static int vx_conf_pipe(struct vx_core *chip, struct vx_pipe *pipe)
        if (pipe->is_capture)
                rmh.Cmd[0] |= COMMAND_RECORD_MASK;
        rmh.Cmd[1] = 1 << pipe->number;
-       return vx_send_msg_nolock(chip, &rmh); /* no lock needed for trigger */
+       return vx_send_msg(chip, &rmh);
 }
 
 /*
@@ -311,7 +311,7 @@ static int vx_send_irqa(struct vx_core *chip)
        struct vx_rmh rmh;
 
        vx_init_rmh(&rmh, CMD_SEND_IRQA);
-       return vx_send_msg_nolock(chip, &rmh); /* no lock needed for trigger */ 
+       return vx_send_msg(chip, &rmh);
 }
 
 
@@ -389,7 +389,7 @@ static int vx_stop_pipe(struct vx_core *chip, struct vx_pipe *pipe)
        struct vx_rmh rmh;
        vx_init_rmh(&rmh, CMD_STOP_PIPE);
        vx_set_pipe_cmd_params(&rmh, pipe->is_capture, pipe->number, 0);
-       return vx_send_msg_nolock(chip, &rmh); /* no lock needed for trigger */ 
+       return vx_send_msg(chip, &rmh);
 }
 
 
@@ -477,7 +477,7 @@ static int vx_start_stream(struct vx_core *chip, struct vx_pipe *pipe)
        vx_init_rmh(&rmh, CMD_START_ONE_STREAM);
        vx_set_stream_cmd_params(&rmh, pipe->is_capture, pipe->number);
        vx_set_differed_time(chip, &rmh, pipe);
-       return vx_send_msg_nolock(chip, &rmh); /* no lock needed for trigger */ 
+       return vx_send_msg(chip, &rmh);
 }
 
 
@@ -492,7 +492,7 @@ static int vx_stop_stream(struct vx_core *chip, struct vx_pipe *pipe)
 
        vx_init_rmh(&rmh, CMD_STOP_STREAM);
        vx_set_stream_cmd_params(&rmh, pipe->is_capture, pipe->number);
-       return vx_send_msg_nolock(chip, &rmh); /* no lock needed for trigger */ 
+       return vx_send_msg(chip, &rmh);
 }
 
 
@@ -520,8 +520,6 @@ static struct snd_pcm_hardware vx_pcm_playback_hw = {
 };
 
 
-static void vx_pcm_delayed_start(unsigned long arg);
-
 /*
  * vx_pcm_playback_open - open callback for playback
  */
@@ -553,7 +551,6 @@ static int vx_pcm_playback_open(struct snd_pcm_substream *subs)
        pipe->references++;
 
        pipe->substream = subs;
-       tasklet_init(&pipe->start_tq, vx_pcm_delayed_start, (unsigned long)subs);
        chip->playback_pipes[audio] = pipe;
 
        runtime->hw = vx_pcm_playback_hw;
@@ -646,12 +643,12 @@ static int vx_pcm_playback_transfer_chunk(struct vx_core *chip,
        /* we don't need irqsave here, because this function
         * is called from either trigger callback or irq handler
         */
-       spin_lock(&chip->lock); 
+       mutex_lock(&chip->lock);
        vx_pseudo_dma_write(chip, runtime, pipe, size);
        err = vx_notify_end_of_buffer(chip, pipe);
        /* disconnect the host, SIZE_HBUF command always switches to the stream mode */
        vx_send_rih_nolock(chip, IRQ_CONNECT_STREAM_NEXT);
-       spin_unlock(&chip->lock);
+       mutex_unlock(&chip->lock);
        return err;
 }
 
@@ -727,31 +724,6 @@ static void vx_pcm_playback_update(struct vx_core *chip,
        }
 }
 
-/*
- * start the stream and pipe.
- * this function is called from tasklet, which is invoked by the trigger
- * START callback.
- */
-static void vx_pcm_delayed_start(unsigned long arg)
-{
-       struct snd_pcm_substream *subs = (struct snd_pcm_substream *)arg;
-       struct vx_core *chip = subs->pcm->private_data;
-       struct vx_pipe *pipe = subs->runtime->private_data;
-       int err;
-
-       /*  printk( KERN_DEBUG "DDDD tasklet delayed start jiffies = %ld\n", jiffies);*/
-
-       if ((err = vx_start_stream(chip, pipe)) < 0) {
-               snd_printk(KERN_ERR "vx: cannot start stream\n");
-               return;
-       }
-       if ((err = vx_toggle_pipe(chip, pipe, 1)) < 0) {
-               snd_printk(KERN_ERR "vx: cannot start pipe\n");
-               return;
-       }
-       /*   printk( KERN_DEBUG "dddd tasklet delayed start jiffies = %ld \n", jiffies);*/
-}
-
 /*
  * vx_pcm_playback_trigger - trigger callback for playback
  */
@@ -769,11 +741,17 @@ static int vx_pcm_trigger(struct snd_pcm_substream *subs, int cmd)
        case SNDRV_PCM_TRIGGER_RESUME:
                if (! pipe->is_capture)
                        vx_pcm_playback_transfer(chip, subs, pipe, 2);
-               /* FIXME:
-                * we trigger the pipe using tasklet, so that the interrupts are
-                * issued surely after the trigger is completed.
-                */ 
-               tasklet_schedule(&pipe->start_tq);
+               err = vx_start_stream(chip, pipe);
+               if (err < 0) {
+                       pr_debug("vx: cannot start stream\n");
+                       return err;
+               }
+               err = vx_toggle_pipe(chip, pipe, 1);
+               if (err < 0) {
+                       pr_debug("vx: cannot start pipe\n");
+                       vx_stop_stream(chip, pipe);
+                       return err;
+               }
                chip->pcm_running++;
                pipe->running = 1;
                break;
@@ -955,7 +933,6 @@ static int vx_pcm_capture_open(struct snd_pcm_substream *subs)
        if (err < 0)
                return err;
        pipe->substream = subs;
-       tasklet_init(&pipe->start_tq, vx_pcm_delayed_start, (unsigned long)subs);
        chip->capture_pipes[audio] = pipe;
 
        /* check if monitoring is needed */
@@ -1082,7 +1059,7 @@ static void vx_pcm_capture_update(struct vx_core *chip, struct snd_pcm_substream
                count -= 3;
        }
        /* disconnect the host, SIZE_HBUF command always switches to the stream mode */
-       vx_send_rih_nolock(chip, IRQ_CONNECT_STREAM_NEXT);
+       vx_send_rih(chip, IRQ_CONNECT_STREAM_NEXT);
        /* read the last pending 6 bytes */
        count = DMA_READ_ALIGN;
        while (count > 0) {
@@ -1099,7 +1076,7 @@ static void vx_pcm_capture_update(struct vx_core *chip, struct snd_pcm_substream
 
  _error:
        /* disconnect the host, SIZE_HBUF command always switches to the stream mode */
-       vx_send_rih_nolock(chip, IRQ_CONNECT_STREAM_NEXT);
+       vx_send_rih(chip, IRQ_CONNECT_STREAM_NEXT);
        return;
 }
 
@@ -1275,6 +1252,7 @@ int snd_vx_pcm_new(struct vx_core *chip)
                pcm->private_data = chip;
                pcm->private_free = snd_vx_pcm_free;
                pcm->info_flags = 0;
+               pcm->nonatomic = true;
                strcpy(pcm->name, chip->card->shortname);
                chip->pcm[i] = pcm;
        }
index b0560fec6bba68fb8dc516a92c84263101ed98c2..ef0b40c0a594274b097c3bdaa7dd6e3a11698b89 100644 (file)
@@ -60,9 +60,9 @@ static int vx_modify_board_inputs(struct vx_core *chip)
  */
 static int vx_read_one_cbit(struct vx_core *chip, int index)
 {
-       unsigned long flags;
        int val;
-       spin_lock_irqsave(&chip->lock, flags);
+
+       mutex_lock(&chip->lock);
        if (chip->type >= VX_TYPE_VXPOCKET) {
                vx_outb(chip, CSUER, 1); /* read */
                vx_outb(chip, RUER, index & XX_UER_CBITS_OFFSET_MASK);
@@ -72,7 +72,7 @@ static int vx_read_one_cbit(struct vx_core *chip, int index)
                vx_outl(chip, RUER, index & XX_UER_CBITS_OFFSET_MASK);
                val = (vx_inl(chip, RUER) >> 7) & 0x01;
        }
-       spin_unlock_irqrestore(&chip->lock, flags);
+       mutex_unlock(&chip->lock);
        return val;
 }
 
@@ -83,9 +83,8 @@ static int vx_read_one_cbit(struct vx_core *chip, int index)
  */
 static void vx_write_one_cbit(struct vx_core *chip, int index, int val)
 {
-       unsigned long flags;
        val = !!val;    /* 0 or 1 */
-       spin_lock_irqsave(&chip->lock, flags);
+       mutex_lock(&chip->lock);
        if (vx_is_pcmcia(chip)) {
                vx_outb(chip, CSUER, 0); /* write */
                vx_outb(chip, RUER, (val << 7) | (index & XX_UER_CBITS_OFFSET_MASK));
@@ -93,7 +92,7 @@ static void vx_write_one_cbit(struct vx_core *chip, int index, int val)
                vx_outl(chip, CSUER, 0); /* write */
                vx_outl(chip, RUER, (val << 7) | (index & XX_UER_CBITS_OFFSET_MASK));
        }
-       spin_unlock_irqrestore(&chip->lock, flags);
+       mutex_unlock(&chip->lock);
 }
 
 /*
@@ -190,14 +189,12 @@ static int vx_calc_clock_from_freq(struct vx_core *chip, int freq)
  */
 static void vx_change_clock_source(struct vx_core *chip, int source)
 {
-       unsigned long flags;
-
        /* we mute DAC to prevent clicks */
        vx_toggle_dac_mute(chip, 1);
-       spin_lock_irqsave(&chip->lock, flags);
+       mutex_lock(&chip->lock);
        chip->ops->set_clock_source(chip, source);
        chip->clock_source = source;
-       spin_unlock_irqrestore(&chip->lock, flags);
+       mutex_unlock(&chip->lock);
        /* unmute */
        vx_toggle_dac_mute(chip, 0);
 }
@@ -209,11 +206,11 @@ static void vx_change_clock_source(struct vx_core *chip, int source)
 void vx_set_internal_clock(struct vx_core *chip, unsigned int freq)
 {
        int clock;
-       unsigned long flags;
+
        /* Get real clock value */
        clock = vx_calc_clock_from_freq(chip, freq);
        snd_printdd(KERN_DEBUG "set internal clock to 0x%x from freq %d\n", clock, freq);
-       spin_lock_irqsave(&chip->lock, flags);
+       mutex_lock(&chip->lock);
        if (vx_is_pcmcia(chip)) {
                vx_outb(chip, HIFREQ, (clock >> 8) & 0x0f);
                vx_outb(chip, LOFREQ, clock & 0xff);
@@ -221,7 +218,7 @@ void vx_set_internal_clock(struct vx_core *chip, unsigned int freq)
                vx_outl(chip, HIFREQ, (clock >> 8) & 0x0f);
                vx_outl(chip, LOFREQ, clock & 0xff);
        }
-       spin_unlock_irqrestore(&chip->lock, flags);
+       mutex_unlock(&chip->lock);
 }
 
 
index afb1b44b741e0d31c51ad0afa92150cb9bf0ec54..21ce31f636bc55c939970be2bcdbcc9953500680 100644 (file)
@@ -48,10 +48,10 @@ static void vortex_fix_latency(struct pci_dev *vortex)
 {
        int rc;
        if (!(rc = pci_write_config_byte(vortex, 0x40, 0xff))) {
-                       printk(KERN_INFO CARD_NAME
+                       pr_info( CARD_NAME
                               ": vortex latency is 0xff\n");
        } else {
-               printk(KERN_WARNING CARD_NAME
+               pr_warn( CARD_NAME
                                ": could not set vortex latency: pci error 0x%x\n", rc);
        }
 }
@@ -70,10 +70,10 @@ static void vortex_fix_agp_bridge(struct pci_dev *via)
        if (!(rc = pci_read_config_byte(via, 0x42, &value))
                        && ((value & 0x10)
                                || !(rc = pci_write_config_byte(via, 0x42, value | 0x10)))) {
-               printk(KERN_INFO CARD_NAME
+               pr_info( CARD_NAME
                                ": bridge config is 0x%x\n", value | 0x10);
        } else {
-               printk(KERN_WARNING CARD_NAME
+               pr_warn( CARD_NAME
                                ": could not set vortex latency: pci error 0x%x\n", rc);
        }
 }
@@ -97,7 +97,7 @@ static void snd_vortex_workaround(struct pci_dev *vortex, int fix)
                                        PCI_DEVICE_ID_AMD_FE_GATE_7007, NULL);
                }
                if (via) {
-                       printk(KERN_INFO CARD_NAME ": Activating latency workaround...\n");
+                       pr_info( CARD_NAME ": Activating latency workaround...\n");
                        vortex_fix_latency(vortex);
                        vortex_fix_agp_bridge(via);
                }
@@ -153,7 +153,7 @@ snd_vortex_create(struct snd_card *card, struct pci_dev *pci, vortex_t ** rchip)
                return err;
        if (pci_set_dma_mask(pci, DMA_BIT_MASK(32)) < 0 ||
            pci_set_consistent_dma_mask(pci, DMA_BIT_MASK(32)) < 0) {
-               printk(KERN_ERR "error to set DMA mask\n");
+               pr_err( "error to set DMA mask\n");
                pci_disable_device(pci);
                return -ENXIO;
        }
@@ -182,7 +182,7 @@ snd_vortex_create(struct snd_card *card, struct pci_dev *pci, vortex_t ** rchip)
 
        chip->mmio = pci_ioremap_bar(pci, 0);
        if (!chip->mmio) {
-               printk(KERN_ERR "MMIO area remap failed.\n");
+               pr_err( "MMIO area remap failed.\n");
                err = -ENOMEM;
                goto ioremap_out;
        }
@@ -191,14 +191,14 @@ snd_vortex_create(struct snd_card *card, struct pci_dev *pci, vortex_t ** rchip)
         * This must be done before we do request_irq otherwise we can get spurious
         * interrupts that we do not handle properly and make a mess of things */
        if ((err = vortex_core_init(chip)) != 0) {
-               printk(KERN_ERR "hw core init failed\n");
+               pr_err( "hw core init failed\n");
                goto core_out;
        }
 
        if ((err = request_irq(pci->irq, vortex_interrupt,
                               IRQF_SHARED, KBUILD_MODNAME,
                               chip)) != 0) {
-               printk(KERN_ERR "cannot grab irq\n");
+               pr_err( "cannot grab irq\n");
                goto irq_out;
        }
        chip->irq = pci->irq;
@@ -342,10 +342,10 @@ snd_vortex_probe(struct pci_dev *pci, const struct pci_device_id *pci_id)
        chip->rev = pci->revision;
 #ifdef CHIP_AU8830
        if ((chip->rev) != 0xfe && (chip->rev) != 0xfa) {
-               printk(KERN_ALERT
+               pr_alert(
                       "vortex: The revision (%x) of your card has not been seen before.\n",
                       chip->rev);
-               printk(KERN_ALERT
+               pr_alert(
                       "vortex: Please email the results of 'lspci -vv' to openvortex-dev@nongnu.org.\n");
                snd_card_free(card);
                err = -ENODEV;
index aad831acbb170f282e1287863037ff81095b14d2..30f760e3d2c0100df9a04341d531d4b3c29b3b68 100644 (file)
@@ -463,7 +463,7 @@ static void a3dsrc_ZeroSliceIO(a3dsrc_t * a)
 static void a3dsrc_ZeroState(a3dsrc_t * a)
 {
        /*
-       printk(KERN_DEBUG "vortex: ZeroState slice: %d, source %d\n",
+       pr_debug( "vortex: ZeroState slice: %d, source %d\n",
               a->slice, a->source);
        */
        a3dsrc_SetAtmosState(a, 0, 0, 0, 0);
@@ -489,7 +489,7 @@ static void a3dsrc_ZeroStateA3D(a3dsrc_t * a)
        int i, var, var2;
 
        if ((a->vortex) == NULL) {
-               printk(KERN_ERR "vortex: ZeroStateA3D: ERROR: a->vortex is NULL\n");
+               pr_err( "vortex: ZeroStateA3D: ERROR: a->vortex is NULL\n");
                return;
        }
 
@@ -628,14 +628,14 @@ static void vortex_Vort3D_connect(vortex_t * v, int en)
        v->mixxtlk[0] =
            vortex_adb_checkinout(v, v->fixed_res, en, VORTEX_RESOURCE_MIXIN);
        if (v->mixxtlk[0] < 0) {
-               printk
+               pr_warn
                    ("vortex: vortex_Vort3D: ERROR: not enough free mixer resources.\n");
                return;
        }
        v->mixxtlk[1] =
            vortex_adb_checkinout(v, v->fixed_res, en, VORTEX_RESOURCE_MIXIN);
        if (v->mixxtlk[1] < 0) {
-               printk
+               pr_warn
                    ("vortex: vortex_Vort3D: ERROR: not enough free mixer resources.\n");
                return;
        }
@@ -679,7 +679,7 @@ static void vortex_Vort3D_connect(vortex_t * v, int en)
 static void vortex_Vort3D_InitializeSource(a3dsrc_t * a, int en)
 {
        if (a->vortex == NULL) {
-               printk
+               pr_warn
                    ("vortex: Vort3D_InitializeSource: A3D source not initialized\n");
                return;
        }
index ae59dbaa53d919dcdc12de63f24cd1cddbebe3d9..72e81286b70eefcce14f05aaf1ae4fdb83658c74 100644 (file)
@@ -285,7 +285,7 @@ vortex_mixer_addWTD(vortex_t * vortex, unsigned char mix, unsigned char ch)
                temp = hwread(vortex->mmio, prev);
                //printk(KERN_INFO "vortex: mixAddWTD: while addr=%x, val=%x\n", prev, temp);
                if ((++lifeboat) > 0xf) {
-                       printk(KERN_ERR
+                       pr_err(
                               "vortex_mixer_addWTD: lifeboat overflow\n");
                        return 0;
                }
@@ -303,7 +303,7 @@ vortex_mixer_delWTD(vortex_t * vortex, unsigned char mix, unsigned char ch)
 
        eax = hwread(vortex->mmio, VORTEX_MIXER_SR);
        if (((1 << ch) & eax) == 0) {
-               printk(KERN_ERR "mix ALARM %x\n", eax);
+               pr_err( "mix ALARM %x\n", eax);
                return 0;
        }
        ebp = VORTEX_MIXER_CHNBASE + (ch << 2);
@@ -324,7 +324,7 @@ vortex_mixer_delWTD(vortex_t * vortex, unsigned char mix, unsigned char ch)
                        //printk(KERN_INFO "vortex: mixdelWTD: 1 addr=%x, val=%x, src=%x\n", ebx, edx, src);
                        while ((edx & 0xf) != mix) {
                                if ((esi) > 0xf) {
-                                       printk(KERN_ERR
+                                       pr_err(
                                               "vortex: mixdelWTD: error lifeboat overflow\n");
                                        return 0;
                                }
@@ -492,7 +492,7 @@ vortex_src_persist_convratio(vortex_t * vortex, unsigned char src, int ratio)
                hwwrite(vortex->mmio, VORTEX_SRC_CONVRATIO + (src << 2), ratio);
                temp = hwread(vortex->mmio, VORTEX_SRC_CONVRATIO + (src << 2));
                if ((++lifeboat) > 0x9) {
-                       printk(KERN_ERR "Vortex: Src cvr fail\n");
+                       pr_err( "Vortex: Src cvr fail\n");
                        break;
                }
        }
@@ -545,7 +545,7 @@ vortex_src_checkratio(vortex_t * vortex, unsigned char src,
                hwwrite(vortex->mmio, VORTEX_SRC_CONVRATIO + (src << 2), desired_ratio);
 
                if ((lifeboat++) > 15) {
-                       printk(KERN_ERR "Vortex: could not set src-%d from %d to %d\n",
+                       pr_err( "Vortex: could not set src-%d from %d to %d\n",
                               src, hw_ratio, desired_ratio);
                        break;
                }
@@ -684,7 +684,7 @@ vortex_src_addWTD(vortex_t * vortex, unsigned char src, unsigned char ch)
                temp = hwread(vortex->mmio, prev);
                //printk(KERN_INFO "vortex: srcAddWTD: while addr=%x, val=%x\n", prev, temp);
                if ((++lifeboat) > 0xf) {
-                       printk(KERN_ERR
+                       pr_err(
                               "vortex_src_addWTD: lifeboat overflow\n");
                        return 0;
                }
@@ -703,7 +703,7 @@ vortex_src_delWTD(vortex_t * vortex, unsigned char src, unsigned char ch)
 
        eax = hwread(vortex->mmio, VORTEX_SRCBLOCK_SR);
        if (((1 << ch) & eax) == 0) {
-               printk(KERN_ERR "src alarm\n");
+               pr_err( "src alarm\n");
                return 0;
        }
        ebp = VORTEX_SRC_CHNBASE + (ch << 2);
@@ -724,7 +724,7 @@ vortex_src_delWTD(vortex_t * vortex, unsigned char src, unsigned char ch)
                        //printk(KERN_INFO "vortex: srcdelWTD: 1 addr=%x, val=%x, src=%x\n", ebx, edx, src);
                        while ((edx & 0xf) != src) {
                                if ((esi) > 0xf) {
-                                       printk
+                                       pr_warn
                                            ("vortex: srcdelWTD: error, lifeboat overflow\n");
                                        return 0;
                                }
@@ -819,7 +819,7 @@ vortex_fifo_setadbctrl(vortex_t * vortex, int fifo, int stereo, int priority,
        do {
                temp = hwread(vortex->mmio, VORTEX_FIFO_ADBCTRL + (fifo << 2));
                if (lifeboat++ > 0xbb8) {
-                       printk(KERN_ERR
+                       pr_err(
                               "Vortex: vortex_fifo_setadbctrl fail\n");
                        break;
                }
@@ -915,7 +915,7 @@ vortex_fifo_setwtctrl(vortex_t * vortex, int fifo, int ctrl, int priority,
        do {
                temp = hwread(vortex->mmio, VORTEX_FIFO_WTCTRL + (fifo << 2));
                if (lifeboat++ > 0xbb8) {
-                       printk(KERN_ERR "Vortex: vortex_fifo_setwtctrl fail\n");
+                       pr_err( "Vortex: vortex_fifo_setwtctrl fail\n");
                        break;
                }
        }
@@ -970,7 +970,7 @@ vortex_fifo_setwtctrl(vortex_t * vortex, int fifo, int ctrl, int priority,
     do {
                temp = hwread(vortex->mmio, VORTEX_FIFO_WTCTRL + (fifo << 2));
                if (lifeboat++ > 0xbb8) {
-                       printk(KERN_ERR "Vortex: vortex_fifo_setwtctrl fail (hanging)\n");
+                       pr_err( "Vortex: vortex_fifo_setwtctrl fail (hanging)\n");
                        break;
                }
     } while ((temp & FIFO_RDONLY)&&(temp & FIFO_VALID)&&(temp != 0xFFFFFFFF));
@@ -1042,7 +1042,7 @@ static void vortex_fifo_init(vortex_t * vortex)
        for (x = NR_ADB - 1; x >= 0; x--) {
                hwwrite(vortex->mmio, addr, (FIFO_U0 | FIFO_U1));
                if (hwread(vortex->mmio, addr) != (FIFO_U0 | FIFO_U1))
-                       printk(KERN_ERR "bad adb fifo reset!");
+                       pr_err( "bad adb fifo reset!");
                vortex_fifo_clearadbdata(vortex, x, FIFO_SIZE);
                addr -= 4;
        }
@@ -1053,7 +1053,7 @@ static void vortex_fifo_init(vortex_t * vortex)
        for (x = NR_WT - 1; x >= 0; x--) {
                hwwrite(vortex->mmio, addr, FIFO_U0);
                if (hwread(vortex->mmio, addr) != FIFO_U0)
-                       printk(KERN_ERR
+                       pr_err(
                               "bad wt fifo reset (0x%08x, 0x%08x)!\n",
                               addr, hwread(vortex->mmio, addr));
                vortex_fifo_clearwtdata(vortex, x, FIFO_SIZE);
@@ -1136,7 +1136,7 @@ vortex_adbdma_setbuffers(vortex_t * vortex, int adbdma,
                break;
        }
        /*
-       printk(KERN_DEBUG "vortex: cfg0 = 0x%x\nvortex: cfg1=0x%x\n",
+       pr_debug( "vortex: cfg0 = 0x%x\nvortex: cfg1=0x%x\n",
               dma->cfg0, dma->cfg1);
        */
        hwwrite(vortex->mmio, VORTEX_ADBDMA_BUFCFG0 + (adbdma << 3), dma->cfg0);
@@ -1213,7 +1213,7 @@ static int vortex_adbdma_bufshift(vortex_t * vortex, int adbdma)
        if (dma->period_virt >= dma->nr_periods)
                dma->period_virt -= dma->nr_periods;
        if (delta != 1)
-               printk(KERN_INFO "vortex: %d virt=%d, real=%d, delta=%d\n",
+               pr_info( "vortex: %d virt=%d, real=%d, delta=%d\n",
                       adbdma, dma->period_virt, dma->period_real, delta);
 
        return delta;
@@ -1482,7 +1482,7 @@ static int vortex_wtdma_bufshift(vortex_t * vortex, int wtdma)
        dma->period_real = page;
 
        if (delta != 1)
-               printk(KERN_WARNING "vortex: wt virt = %d, delta = %d\n",
+               pr_warn( "vortex: wt virt = %d, delta = %d\n",
                       dma->period_virt, delta);
 
        return delta;
@@ -1667,7 +1667,7 @@ vortex_adb_addroutes(vortex_t * vortex, unsigned char channel,
                    hwread(vortex->mmio,
                           VORTEX_ADB_RTBASE + (temp << 2)) & ADB_MASK;
                if ((lifeboat++) > ADB_MASK) {
-                       printk(KERN_ERR
+                       pr_err(
                               "vortex_adb_addroutes: unending route! 0x%x\n",
                               *route);
                        return;
@@ -1703,7 +1703,7 @@ vortex_adb_delroutes(vortex_t * vortex, unsigned char channel,
                    hwread(vortex->mmio,
                           VORTEX_ADB_RTBASE + (prev << 2)) & ADB_MASK;
                if (((lifeboat++) > ADB_MASK) || (temp == ADB_MASK)) {
-                       printk(KERN_ERR
+                       pr_err(
                               "vortex_adb_delroutes: route not found! 0x%x\n",
                               route0);
                        return;
@@ -1967,7 +1967,7 @@ vortex_connect_codecplay(vortex_t * vortex, int en, unsigned char mixers[])
                                          ADB_CODECOUT(0 + 4));
                vortex_connection_mix_adb(vortex, en, 0x11, mixers[3],
                                          ADB_CODECOUT(1 + 4));
-               /* printk(KERN_DEBUG "SDAC detected "); */
+               /* pr_debug( "SDAC detected "); */
        }
 #else
        // Use plain direct output to codec.
@@ -2022,7 +2022,7 @@ vortex_adb_checkinout(vortex_t * vortex, int resmap[], int out, int restype)
                                else
                                        vortex->dma_adb[i].resources[restype] |= (1 << i);
                                /*
-                               printk(KERN_DEBUG
+                               pr_debug(
                                       "vortex: ResManager: type %d out %d\n",
                                       restype, i);
                                */
@@ -2037,7 +2037,7 @@ vortex_adb_checkinout(vortex_t * vortex, int resmap[], int out, int restype)
                        if (resmap[restype] & (1 << i)) {
                                resmap[restype] &= ~(1 << i);
                                /*
-                               printk(KERN_DEBUG
+                               pr_debug(
                                       "vortex: ResManager: type %d in %d\n",
                                       restype, i);
                                */
@@ -2045,7 +2045,7 @@ vortex_adb_checkinout(vortex_t * vortex, int resmap[], int out, int restype)
                        }
                }
        }
-       printk(KERN_ERR "vortex: FATAL: ResManager: resource type %d exhausted.\n", restype);
+       pr_err( "vortex: FATAL: ResManager: resource type %d exhausted.\n", restype);
        return -ENOMEM;
 }
 
@@ -2173,7 +2173,7 @@ vortex_adb_allocroute(vortex_t *vortex, int dma, int nr_ch, int dir,
                                memset(stream->resources, 0,
                                       sizeof(unsigned char) *
                                       VORTEX_RESOURCE_LAST);
-                               printk(KERN_ERR "vortex: out of A3D sources. Sorry\n");
+                               pr_err( "vortex: out of A3D sources. Sorry\n");
                                return -EBUSY;
                        }
                        /* (De)Initialize A3D hardware source. */
@@ -2421,7 +2421,7 @@ static irqreturn_t vortex_interrupt(int irq, void *dev_id)
        hwread(vortex->mmio, VORTEX_IRQ_SOURCE);
        // Is at least one IRQ flag set?
        if (source == 0) {
-               printk(KERN_ERR "vortex: missing irq source\n");
+               pr_err( "vortex: missing irq source\n");
                return IRQ_NONE;
        }
 
@@ -2429,19 +2429,19 @@ static irqreturn_t vortex_interrupt(int irq, void *dev_id)
        // Attend every interrupt source.
        if (unlikely(source & IRQ_ERR_MASK)) {
                if (source & IRQ_FATAL) {
-                       printk(KERN_ERR "vortex: IRQ fatal error\n");
+                       pr_err( "vortex: IRQ fatal error\n");
                }
                if (source & IRQ_PARITY) {
-                       printk(KERN_ERR "vortex: IRQ parity error\n");
+                       pr_err( "vortex: IRQ parity error\n");
                }
                if (source & IRQ_REG) {
-                       printk(KERN_ERR "vortex: IRQ reg error\n");
+                       pr_err( "vortex: IRQ reg error\n");
                }
                if (source & IRQ_FIFO) {
-                       printk(KERN_ERR "vortex: IRQ fifo error\n");
+                       pr_err( "vortex: IRQ fifo error\n");
                }
                if (source & IRQ_DMA) {
-                       printk(KERN_ERR "vortex: IRQ dma error\n");
+                       pr_err( "vortex: IRQ dma error\n");
                }
                handled = 1;
        }
@@ -2489,7 +2489,7 @@ static irqreturn_t vortex_interrupt(int irq, void *dev_id)
        }
 
        if (!handled) {
-               printk(KERN_ERR "vortex: unknown irq source %x\n", source);
+               pr_err( "vortex: unknown irq source %x\n", source);
        }
        return IRQ_RETVAL(handled);
 }
@@ -2546,7 +2546,7 @@ vortex_codec_write(struct snd_ac97 * codec, unsigned short addr, unsigned short
        while (!(hwread(card->mmio, VORTEX_CODEC_CTRL) & 0x100)) {
                udelay(100);
                if (lifeboat++ > POLL_COUNT) {
-                       printk(KERN_ERR "vortex: ac97 codec stuck busy\n");
+                       pr_err( "vortex: ac97 codec stuck busy\n");
                        return;
                }
        }
@@ -2572,7 +2572,7 @@ static unsigned short vortex_codec_read(struct snd_ac97 * codec, unsigned short
        while (!(hwread(card->mmio, VORTEX_CODEC_CTRL) & 0x100)) {
                udelay(100);
                if (lifeboat++ > POLL_COUNT) {
-                       printk(KERN_ERR "vortex: ac97 codec stuck busy\n");
+                       pr_err( "vortex: ac97 codec stuck busy\n");
                        return 0xffff;
                }
        }
@@ -2586,7 +2586,7 @@ static unsigned short vortex_codec_read(struct snd_ac97 * codec, unsigned short
                udelay(100);
                data = hwread(card->mmio, VORTEX_CODEC_IO);
                if (lifeboat++ > POLL_COUNT) {
-                       printk(KERN_ERR "vortex: ac97 address never arrived\n");
+                       pr_err( "vortex: ac97 address never arrived\n");
                        return 0xffff;
                }
        } while ((data & VORTEX_CODEC_ADDMASK) !=
@@ -2683,7 +2683,7 @@ static void vortex_spdif_init(vortex_t * vortex, int spdif_sr, int spdif_mode)
 static int vortex_core_init(vortex_t *vortex)
 {
 
-       printk(KERN_INFO "Vortex: init.... ");
+       pr_info( "Vortex: init.... ");
        /* Hardware Init. */
        hwwrite(vortex->mmio, VORTEX_CTRL, 0xffffffff);
        msleep(5);
@@ -2728,7 +2728,7 @@ static int vortex_core_init(vortex_t *vortex)
        //vortex_enable_timer_int(vortex);
        //vortex_disable_timer_int(vortex);
 
-       printk(KERN_INFO "done.\n");
+       pr_info( "done.\n");
        spin_lock_init(&vortex->lock);
 
        return 0;
@@ -2737,7 +2737,7 @@ static int vortex_core_init(vortex_t *vortex)
 static int vortex_core_shutdown(vortex_t * vortex)
 {
 
-       printk(KERN_INFO "Vortex: shutdown...");
+       pr_info( "Vortex: shutdown...");
 #ifndef CHIP_AU8820
        vortex_eq_free(vortex);
        vortex_Vort3D_disable(vortex);
@@ -2759,7 +2759,7 @@ static int vortex_core_shutdown(vortex_t * vortex)
        msleep(5);
        hwwrite(vortex->mmio, VORTEX_IRQ_SOURCE, 0xffff);
 
-       printk(KERN_INFO "done.\n");
+       pr_info( "done.\n");
        return 0;
 }
 
@@ -2793,7 +2793,7 @@ static int vortex_alsafmt_aspfmt(int alsafmt)
                break;
        default:
                fmt = 0x8;
-               printk(KERN_ERR "vortex: format unsupported %d\n", alsafmt);
+               pr_err( "vortex: format unsupported %d\n", alsafmt);
                break;
        }
        return fmt;
index e7220533ecfc79a46f9ab05f3d54d083216dc16d..9404ba73eaf6140ccdabf0576ab04f096fde94f9 100644 (file)
@@ -845,7 +845,7 @@ snd_vortex_peaks_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *u
 
        vortex_Eqlzr_GetAllPeaks(vortex, peaks, &count);
        if (count != 20) {
-               printk(KERN_ERR "vortex: peak count error 20 != %d \n", count);
+               pr_err( "vortex: peak count error 20 != %d \n", count);
                return -1;
        }
        for (i = 0; i < 20; i++)
index 280f86de223086ab1b26d2639e12334ab2dceb37..72daf6cf81695602ce77efd7f7e7aeeab9069af2 100644 (file)
@@ -98,7 +98,7 @@ static int vortex_gameport_register(vortex_t *vortex)
 
        vortex->gameport = gp = gameport_allocate_port();
        if (!gp) {
-               printk(KERN_ERR "vortex: cannot allocate memory for gameport\n");
+               pr_err( "vortex: cannot allocate memory for gameport\n");
                return -ENOMEM;
        }
 
index 29e5945eef60dea7af07e4cea22202d68526b616..328c1943c0c341725a55c926229c40c23cad1668 100644 (file)
@@ -73,7 +73,7 @@ static int snd_vortex_midi(vortex_t *vortex)
        /* Check if anything is OK. */
        temp = hwread(vortex->mmio, VORTEX_MIDI_DATA);
        if (temp != MPU401_ACK /*0xfe */ ) {
-               printk(KERN_ERR "midi port doesn't acknowledge!\n");
+               pr_err( "midi port doesn't acknowledge!\n");
                return -ENODEV;
        }
        /* Enable MPU401 interrupts. */
index 9fb03b4ea925cb173e3e898950c9b4736c0ff787..5adc6b92ffabc9f893cc4b7f4c0b29f8428d5f96 100644 (file)
@@ -227,11 +227,11 @@ snd_vortex_pcm_hw_params(struct snd_pcm_substream *substream,
        err =
            snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params));
        if (err < 0) {
-               printk(KERN_ERR "Vortex: pcm page alloc failed!\n");
+               pr_err( "Vortex: pcm page alloc failed!\n");
                return err;
        }
        /*
-          printk(KERN_INFO "Vortex: periods %d, period_bytes %d, channels = %d\n", params_periods(hw_params),
+          pr_info( "Vortex: periods %d, period_bytes %d, channels = %d\n", params_periods(hw_params),
           params_period_bytes(hw_params), params_channels(hw_params));
         */
        spin_lock_irq(&chip->lock);
@@ -371,7 +371,7 @@ static int snd_vortex_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
                }
 #ifndef CHIP_AU8810
                else {
-                       printk(KERN_INFO "vortex: wt start %d\n", dma);
+                       pr_info( "vortex: wt start %d\n", dma);
                        vortex_wtdma_startfifo(chip, dma);
                }
 #endif
@@ -384,7 +384,7 @@ static int snd_vortex_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
                        vortex_adbdma_stopfifo(chip, dma);
 #ifndef CHIP_AU8810
                else {
-                       printk(KERN_INFO "vortex: wt stop %d\n", dma);
+                       pr_info( "vortex: wt stop %d\n", dma);
                        vortex_wtdma_stopfifo(chip, dma);
                }
 #endif
index 922a84bba2ef4738006e02dcc1c3920525ce8ec6..f094bac24291297e2d82441247733a9e2d7f5f6b 100644 (file)
@@ -90,7 +90,7 @@ static int vortex_wt_allocroute(vortex_t * vortex, int wt, int nr_ch)
        hwwrite(vortex->mmio, WT_PARM(wt, 2), 0);
 
        temp = hwread(vortex->mmio, WT_PARM(wt, 3));
-       printk(KERN_DEBUG "vortex: WT PARM3: %x\n", temp);
+       pr_debug( "vortex: WT PARM3: %x\n", temp);
        //hwwrite(vortex->mmio, WT_PARM(wt, 3), temp);
 
        hwwrite(vortex->mmio, WT_DELAY(wt, 0), 0);
@@ -98,7 +98,7 @@ static int vortex_wt_allocroute(vortex_t * vortex, int wt, int nr_ch)
        hwwrite(vortex->mmio, WT_DELAY(wt, 2), 0);
        hwwrite(vortex->mmio, WT_DELAY(wt, 3), 0);
 
-       printk(KERN_DEBUG "vortex: WT GMODE: %x\n", hwread(vortex->mmio, WT_GMODE(wt)));
+       pr_debug( "vortex: WT GMODE: %x\n", hwread(vortex->mmio, WT_GMODE(wt)));
 
        hwwrite(vortex->mmio, WT_PARM(wt, 2), 0xffffffff);
        hwwrite(vortex->mmio, WT_PARM(wt, 3), 0xcff1c810);
@@ -106,7 +106,7 @@ static int vortex_wt_allocroute(vortex_t * vortex, int wt, int nr_ch)
        voice->parm0 = voice->parm1 = 0xcfb23e2f;
        hwwrite(vortex->mmio, WT_PARM(wt, 0), voice->parm0);
        hwwrite(vortex->mmio, WT_PARM(wt, 1), voice->parm1);
-       printk(KERN_DEBUG "vortex: WT GMODE 2 : %x\n", hwread(vortex->mmio, WT_GMODE(wt)));
+       pr_debug( "vortex: WT GMODE 2 : %x\n", hwread(vortex->mmio, WT_GMODE(wt)));
        return 0;
 }
 
@@ -196,14 +196,14 @@ vortex_wt_SetReg(vortex_t * vortex, unsigned char reg, int wt,
 
        if ((reg == 5) || ((reg >= 7) && (reg <= 10)) || (reg == 0xc)) {
                if (wt >= (NR_WT / NR_WT_PB)) {
-                       printk
+                       pr_warn
                            ("vortex: WT SetReg: bank out of range. reg=0x%x, wt=%d\n",
                             reg, wt);
                        return 0;
                }
        } else {
                if (wt >= NR_WT) {
-                       printk(KERN_ERR "vortex: WT SetReg: voice out of range\n");
+                       pr_err( "vortex: WT SetReg: voice out of range\n");
                        return 0;
                }
        }
@@ -214,42 +214,42 @@ vortex_wt_SetReg(vortex_t * vortex, unsigned char reg, int wt,
                /* Voice specific parameters */
        case 0:         /* running */
                /*
-               printk(KERN_DEBUG "vortex: WT SetReg(0x%x) = 0x%08x\n",
+               pr_debug( "vortex: WT SetReg(0x%x) = 0x%08x\n",
                       WT_RUN(wt), (int)val);
                */
                hwwrite(vortex->mmio, WT_RUN(wt), val);
                return 0xc;
        case 1:         /* param 0 */
                /*
-               printk(KERN_DEBUG "vortex: WT SetReg(0x%x) = 0x%08x\n",
+               pr_debug( "vortex: WT SetReg(0x%x) = 0x%08x\n",
                       WT_PARM(wt,0), (int)val);
                */
                hwwrite(vortex->mmio, WT_PARM(wt, 0), val);
                return 0xc;
        case 2:         /* param 1 */
                /*
-               printk(KERN_DEBUG "vortex: WT SetReg(0x%x) = 0x%08x\n",
+               pr_debug( "vortex: WT SetReg(0x%x) = 0x%08x\n",
                       WT_PARM(wt,1), (int)val);
                */
                hwwrite(vortex->mmio, WT_PARM(wt, 1), val);
                return 0xc;
        case 3:         /* param 2 */
                /*
-               printk(KERN_DEBUG "vortex: WT SetReg(0x%x) = 0x%08x\n",
+               pr_debug( "vortex: WT SetReg(0x%x) = 0x%08x\n",
                       WT_PARM(wt,2), (int)val);
                */
                hwwrite(vortex->mmio, WT_PARM(wt, 2), val);
                return 0xc;
        case 4:         /* param 3 */
                /*
-               printk(KERN_DEBUG "vortex: WT SetReg(0x%x) = 0x%08x\n",
+               pr_debug( "vortex: WT SetReg(0x%x) = 0x%08x\n",
                       WT_PARM(wt,3), (int)val);
                */
                hwwrite(vortex->mmio, WT_PARM(wt, 3), val);
                return 0xc;
        case 6:         /* mute */
                /*
-               printk(KERN_DEBUG "vortex: WT SetReg(0x%x) = 0x%08x\n",
+               pr_debug( "vortex: WT SetReg(0x%x) = 0x%08x\n",
                       WT_MUTE(wt), (int)val);
                */
                hwwrite(vortex->mmio, WT_MUTE(wt), val);
@@ -257,7 +257,7 @@ vortex_wt_SetReg(vortex_t * vortex, unsigned char reg, int wt,
        case 0xb:
                        /* delay */
                /*
-               printk(KERN_DEBUG "vortex: WT SetReg(0x%x) = 0x%08x\n",
+               pr_debug( "vortex: WT SetReg(0x%x) = 0x%08x\n",
                       WT_DELAY(wt,0), (int)val);
                */
                hwwrite(vortex->mmio, WT_DELAY(wt, 3), val);
@@ -285,7 +285,7 @@ vortex_wt_SetReg(vortex_t * vortex, unsigned char reg, int wt,
                return 0;
        }
        /*
-       printk(KERN_DEBUG "vortex: WT SetReg(0x%x) = 0x%08x\n", ecx, (int)val);
+       pr_debug( "vortex: WT SetReg(0x%x) = 0x%08x\n", ecx, (int)val);
        */
        hwwrite(vortex->mmio, ecx, val);
        return 1;
index fee35cfc0c7f0c62895aad3b9bb3748ab0df7fa7..c7dc38d41b7f4678691e5a492b93b5087bddddce 100644 (file)
@@ -258,7 +258,8 @@ static int get_amixer_rsc(struct amixer_mgr *mgr,
        }
        spin_unlock_irqrestore(&mgr->mgr_lock, flags);
        if (err) {
-               printk(KERN_ERR "ctxfi: Can't meet AMIXER resource request!\n");
+               dev_err(mgr->card->dev,
+                       "Can't meet AMIXER resource request!\n");
                goto error;
        }
 
@@ -296,7 +297,7 @@ static int put_amixer_rsc(struct amixer_mgr *mgr, struct amixer *amixer)
        return 0;
 }
 
-int amixer_mgr_create(void *hw, struct amixer_mgr **ramixer_mgr)
+int amixer_mgr_create(struct hw *hw, struct amixer_mgr **ramixer_mgr)
 {
        int err;
        struct amixer_mgr *amixer_mgr;
@@ -314,6 +315,7 @@ int amixer_mgr_create(void *hw, struct amixer_mgr **ramixer_mgr)
 
        amixer_mgr->get_amixer = get_amixer_rsc;
        amixer_mgr->put_amixer = put_amixer_rsc;
+       amixer_mgr->card = hw->card;
 
        *ramixer_mgr = amixer_mgr;
 
@@ -411,7 +413,8 @@ static int get_sum_rsc(struct sum_mgr *mgr,
        }
        spin_unlock_irqrestore(&mgr->mgr_lock, flags);
        if (err) {
-               printk(KERN_ERR "ctxfi: Can't meet SUM resource request!\n");
+               dev_err(mgr->card->dev,
+                       "Can't meet SUM resource request!\n");
                goto error;
        }
 
@@ -449,7 +452,7 @@ static int put_sum_rsc(struct sum_mgr *mgr, struct sum *sum)
        return 0;
 }
 
-int sum_mgr_create(void *hw, struct sum_mgr **rsum_mgr)
+int sum_mgr_create(struct hw *hw, struct sum_mgr **rsum_mgr)
 {
        int err;
        struct sum_mgr *sum_mgr;
@@ -467,6 +470,7 @@ int sum_mgr_create(void *hw, struct sum_mgr **rsum_mgr)
 
        sum_mgr->get_sum = get_sum_rsc;
        sum_mgr->put_sum = put_sum_rsc;
+       sum_mgr->card = hw->card;
 
        *rsum_mgr = sum_mgr;
 
index cc49e5ab4750308c3116401b67518aa05106b2c9..72f42f27434eb7f4dcada14fe737be047d03d7f0 100644 (file)
@@ -21,6 +21,7 @@
 
 #include "ctresource.h"
 #include <linux/spinlock.h>
+#include <sound/core.h>
 
 /* Define the descriptor of a summation node resource */
 struct sum {
@@ -35,6 +36,7 @@ struct sum_desc {
 
 struct sum_mgr {
        struct rsc_mgr mgr;     /* Basic resource manager info */
+       struct snd_card *card;  /* pointer to this card */
        spinlock_t mgr_lock;
 
         /* request one sum resource */
@@ -45,7 +47,7 @@ struct sum_mgr {
 };
 
 /* Constructor and destructor of daio resource manager */
-int sum_mgr_create(void *hw, struct sum_mgr **rsum_mgr);
+int sum_mgr_create(struct hw *hw, struct sum_mgr **rsum_mgr);
 int sum_mgr_destroy(struct sum_mgr *sum_mgr);
 
 /* Define the descriptor of a amixer resource */
@@ -79,6 +81,7 @@ struct amixer_desc {
 
 struct amixer_mgr {
        struct rsc_mgr mgr;     /* Basic resource manager info */
+       struct snd_card *card;  /* pointer to this card */
        spinlock_t mgr_lock;
 
         /* request one amixer resource */
@@ -90,7 +93,7 @@ struct amixer_mgr {
 };
 
 /* Constructor and destructor of amixer resource manager */
-int amixer_mgr_create(void *hw, struct amixer_mgr **ramixer_mgr);
+int amixer_mgr_create(struct hw *hw, struct amixer_mgr **ramixer_mgr);
 int amixer_mgr_destroy(struct amixer_mgr *amixer_mgr);
 
 #endif /* CTAMIXER_H */
index af632bd08323feaf0f9ab2d3098375e12f38d46b..45465907439002b4bf879462f4c6f97955dc9255 100644 (file)
@@ -106,11 +106,11 @@ static struct {
                            .public_name = "Mixer"}
 };
 
-typedef int (*create_t)(void *, void **);
+typedef int (*create_t)(struct hw *, void **);
 typedef int (*destroy_t)(void *);
 
 static struct {
-       int (*create)(void *hw, void **rmgr);
+       int (*create)(struct hw *hw, void **rmgr);
        int (*destroy)(void *mgr);
 } rsc_mgr_funcs[NUM_RSCTYP] = {
        [SRC]           = { .create     = (create_t)src_mgr_create,
@@ -171,7 +171,8 @@ static unsigned long atc_get_ptp_phys(struct ct_atc *atc, int index)
        return atc->vm->get_ptp_phys(atc->vm, index);
 }
 
-static unsigned int convert_format(snd_pcm_format_t snd_format)
+static unsigned int convert_format(snd_pcm_format_t snd_format,
+                                  struct snd_card *card)
 {
        switch (snd_format) {
        case SNDRV_PCM_FORMAT_U8:
@@ -185,7 +186,7 @@ static unsigned int convert_format(snd_pcm_format_t snd_format)
        case SNDRV_PCM_FORMAT_FLOAT_LE:
                return SRC_SF_F32;
        default:
-               printk(KERN_ERR "ctxfi: not recognized snd format is %d \n",
+               dev_err(card->dev, "not recognized snd format is %d\n",
                        snd_format);
                return SRC_SF_S16;
        }
@@ -268,7 +269,8 @@ static int atc_pcm_playback_prepare(struct ct_atc *atc, struct ct_atc_pcm *apcm)
        src = apcm->src;
        src->ops->set_pitch(src, pitch);
        src->ops->set_rom(src, select_rom(pitch));
-       src->ops->set_sf(src, convert_format(apcm->substream->runtime->format));
+       src->ops->set_sf(src, convert_format(apcm->substream->runtime->format,
+                                            atc->card));
        src->ops->set_pm(src, (src->ops->next_interleave(src) != NULL));
 
        /* Get AMIXER resource */
@@ -738,7 +740,8 @@ static int atc_pcm_capture_start(struct ct_atc *atc, struct ct_atc_pcm *apcm)
 
        /*  Set up recording SRC */
        src = apcm->src;
-       src->ops->set_sf(src, convert_format(apcm->substream->runtime->format));
+       src->ops->set_sf(src, convert_format(apcm->substream->runtime->format,
+                                            atc->card));
        src->ops->set_sa(src, apcm->vm_block->addr);
        src->ops->set_la(src, apcm->vm_block->addr + apcm->vm_block->size);
        src->ops->set_ca(src, apcm->vm_block->addr);
@@ -807,7 +810,8 @@ static int spdif_passthru_playback_get_resources(struct ct_atc *atc,
        src = apcm->src;
        src->ops->set_pitch(src, pitch);
        src->ops->set_rom(src, select_rom(pitch));
-       src->ops->set_sf(src, convert_format(apcm->substream->runtime->format));
+       src->ops->set_sf(src, convert_format(apcm->substream->runtime->format,
+                                            atc->card));
        src->ops->set_pm(src, (src->ops->next_interleave(src) != NULL));
        src->ops->set_bp(src, 1);
 
@@ -1235,7 +1239,7 @@ static int ct_atc_destroy(struct ct_atc *atc)
        }
 
        if (atc->hw)
-               destroy_hw_obj((struct hw *)atc->hw);
+               destroy_hw_obj(atc->hw);
 
        /* Destroy device virtual memory manager object */
        if (atc->vm) {
@@ -1282,9 +1286,9 @@ static int atc_identify_card(struct ct_atc *atc, unsigned int ssid)
        p = snd_pci_quirk_lookup_id(vendor_id, device_id, list);
        if (p) {
                if (p->value < 0) {
-                       printk(KERN_ERR "ctxfi: "
-                              "Device %04x:%04x is black-listed\n",
-                              vendor_id, device_id);
+                       dev_err(atc->card->dev,
+                               "Device %04x:%04x is black-listed\n",
+                               vendor_id, device_id);
                        return -ENOENT;
                }
                atc->model = p->value;
@@ -1315,8 +1319,8 @@ int ct_atc_create_alsa_devs(struct ct_atc *atc)
                err = alsa_dev_funcs[i].create(atc, i,
                                alsa_dev_funcs[i].public_name);
                if (err) {
-                       printk(KERN_ERR "ctxfi: "
-                              "Creating alsa device %d failed!\n", i);
+                       dev_err(atc->card->dev,
+                               "Creating alsa device %d failed!\n", i);
                        return err;
                }
        }
@@ -1332,9 +1336,10 @@ static int atc_create_hw_devs(struct ct_atc *atc)
 
        err = create_hw_obj(atc->pci, atc->chip_type, atc->model, &hw);
        if (err) {
-               printk(KERN_ERR "Failed to create hw obj!!!\n");
+               dev_err(atc->card->dev, "Failed to create hw obj!!!\n");
                return err;
        }
+       hw->card = atc->card;
        atc->hw = hw;
 
        /* Initialize card hardware. */
@@ -1351,8 +1356,8 @@ static int atc_create_hw_devs(struct ct_atc *atc)
 
                err = rsc_mgr_funcs[i].create(atc->hw, &atc->rsc_mgrs[i]);
                if (err) {
-                       printk(KERN_ERR "ctxfi: "
-                              "Failed to create rsc_mgr %d!!!\n", i);
+                       dev_err(atc->card->dev,
+                               "Failed to create rsc_mgr %d!!!\n", i);
                        return err;
                }
        }
@@ -1399,8 +1404,9 @@ static int atc_get_resources(struct ct_atc *atc)
                err = daio_mgr->get_daio(daio_mgr, &da_desc,
                                        (struct daio **)&atc->daios[i]);
                if (err) {
-                       printk(KERN_ERR "ctxfi: Failed to get DAIO "
-                                       "resource %d!!!\n", i);
+                       dev_err(atc->card->dev,
+                               "Failed to get DAIO resource %d!!!\n",
+                               i);
                        return err;
                }
                atc->n_daio++;
@@ -1603,8 +1609,8 @@ static int atc_resume(struct ct_atc *atc)
        /* Do hardware resume. */
        err = atc_hw_resume(atc);
        if (err < 0) {
-               printk(KERN_ERR "ctxfi: pci_enable_device failed, "
-                      "disabling device\n");
+               dev_err(atc->card->dev,
+                       "pci_enable_device failed, disabling device\n");
                snd_card_disconnect(atc->card);
                return err;
        }
@@ -1701,7 +1707,7 @@ int ct_atc_create(struct snd_card *card, struct pci_dev *pci,
        /* Find card model */
        err = atc_identify_card(atc, ssid);
        if (err < 0) {
-               printk(KERN_ERR "ctatc: Card not recognised\n");
+               dev_err(card->dev, "ctatc: Card not recognised\n");
                goto error1;
        }
 
@@ -1717,7 +1723,7 @@ int ct_atc_create(struct snd_card *card, struct pci_dev *pci,
 
        err = ct_mixer_create(atc, (struct ct_mixer **)&atc->mixer);
        if (err) {
-               printk(KERN_ERR "ctxfi: Failed to create mixer obj!!!\n");
+               dev_err(card->dev, "Failed to create mixer obj!!!\n");
                goto error1;
        }
 
@@ -1744,6 +1750,6 @@ int ct_atc_create(struct snd_card *card, struct pci_dev *pci,
 
 error1:
        ct_atc_destroy(atc);
-       printk(KERN_ERR "ctxfi: Something wrong!!!\n");
+       dev_err(card->dev, "Something wrong!!!\n");
        return err;
 }
index 5f11ca22fcdefaca7706cb7a81256d16c5894d2e..56413343a9e831dd1bbdfac07b9529428fbd979e 100644 (file)
@@ -131,7 +131,7 @@ struct ct_atc {
        /* Don't touch! Used for internal object. */
        void *rsc_mgrs[NUM_RSCTYP]; /* chip resource managers */
        void *mixer;            /* internal mixer object */
-       void *hw;               /* chip specific hardware access object */
+       struct hw *hw;          /* chip specific hardware access object */
        void **daios;           /* digital audio io resources */
        void **pcm;             /* SUMs for collecting all pcm stream */
        void **srcs;            /* Sample Rate Converters for input signal */
index 84f86bf63b8fc31dc27700013608a65a7af970bb..c1c3f8816fff671962a1392672b6e127f26f694a 100644 (file)
@@ -140,19 +140,19 @@ static int dao_rsc_reinit(struct dao *dao, const struct dao_desc *desc);
 
 static int dao_spdif_get_spos(struct dao *dao, unsigned int *spos)
 {
-       ((struct hw *)dao->hw)->dao_get_spos(dao->ctrl_blk, spos);
+       dao->hw->dao_get_spos(dao->ctrl_blk, spos);
        return 0;
 }
 
 static int dao_spdif_set_spos(struct dao *dao, unsigned int spos)
 {
-       ((struct hw *)dao->hw)->dao_set_spos(dao->ctrl_blk, spos);
+       dao->hw->dao_set_spos(dao->ctrl_blk, spos);
        return 0;
 }
 
 static int dao_commit_write(struct dao *dao)
 {
-       ((struct hw *)dao->hw)->dao_commit_write(dao->hw,
+       dao->hw->dao_commit_write(dao->hw,
                daio_device_index(dao->daio.type, dao->hw), dao->ctrl_blk);
        return 0;
 }
@@ -277,16 +277,14 @@ static struct dao_rsc_ops dao_ops = {
 static int dai_set_srt_srcl(struct dai *dai, struct rsc *src)
 {
        src->ops->master(src);
-       ((struct hw *)dai->hw)->dai_srt_set_srcm(dai->ctrl_blk,
-                                               src->ops->index(src));
+       dai->hw->dai_srt_set_srcm(dai->ctrl_blk, src->ops->index(src));
        return 0;
 }
 
 static int dai_set_srt_srcr(struct dai *dai, struct rsc *src)
 {
        src->ops->master(src);
-       ((struct hw *)dai->hw)->dai_srt_set_srco(dai->ctrl_blk,
-                                               src->ops->index(src));
+       dai->hw->dai_srt_set_srco(dai->ctrl_blk, src->ops->index(src));
        return 0;
 }
 
@@ -297,25 +295,25 @@ static int dai_set_srt_msr(struct dai *dai, unsigned int msr)
        for (rsr = 0; msr > 1; msr >>= 1)
                rsr++;
 
-       ((struct hw *)dai->hw)->dai_srt_set_rsr(dai->ctrl_blk, rsr);
+       dai->hw->dai_srt_set_rsr(dai->ctrl_blk, rsr);
        return 0;
 }
 
 static int dai_set_enb_src(struct dai *dai, unsigned int enb)
 {
-       ((struct hw *)dai->hw)->dai_srt_set_ec(dai->ctrl_blk, enb);
+       dai->hw->dai_srt_set_ec(dai->ctrl_blk, enb);
        return 0;
 }
 
 static int dai_set_enb_srt(struct dai *dai, unsigned int enb)
 {
-       ((struct hw *)dai->hw)->dai_srt_set_et(dai->ctrl_blk, enb);
+       dai->hw->dai_srt_set_et(dai->ctrl_blk, enb);
        return 0;
 }
 
 static int dai_commit_write(struct dai *dai)
 {
-       ((struct hw *)dai->hw)->dai_commit_write(dai->hw,
+       dai->hw->dai_commit_write(dai->hw,
                daio_device_index(dai->daio.type, dai->hw), dai->ctrl_blk);
        return 0;
 }
@@ -331,12 +329,12 @@ static struct dai_rsc_ops dai_ops = {
 
 static int daio_rsc_init(struct daio *daio,
                         const struct daio_desc *desc,
-                        void *hw)
+                        struct hw *hw)
 {
        int err;
        unsigned int idx_l, idx_r;
 
-       switch (((struct hw *)hw)->chip_type) {
+       switch (hw->chip_type) {
        case ATC20K1:
                idx_l = idx_20k1[desc->type].left;
                idx_r = idx_20k1[desc->type].right;
@@ -360,7 +358,7 @@ static int daio_rsc_init(struct daio *daio,
        if (desc->type <= DAIO_OUT_MAX) {
                daio->rscl.ops = daio->rscr.ops = &daio_out_rsc_ops;
        } else {
-               switch (((struct hw *)hw)->chip_type) {
+               switch (hw->chip_type) {
                case ATC20K1:
                        daio->rscl.ops = daio->rscr.ops = &daio_in_rsc_ops_20k1;
                        break;
@@ -445,7 +443,7 @@ static int dao_rsc_uninit(struct dao *dao)
                kfree(dao->imappers);
                dao->imappers = NULL;
        }
-       ((struct hw *)dao->hw)->dao_put_ctrl_blk(dao->ctrl_blk);
+       dao->hw->dao_put_ctrl_blk(dao->ctrl_blk);
        dao->hw = dao->ctrl_blk = NULL;
        daio_rsc_uninit(&dao->daio);
 
@@ -502,7 +500,7 @@ error1:
 
 static int dai_rsc_uninit(struct dai *dai)
 {
-       ((struct hw *)dai->hw)->dai_put_ctrl_blk(dai->ctrl_blk);
+       dai->hw->dai_put_ctrl_blk(dai->ctrl_blk);
        dai->hw = dai->ctrl_blk = NULL;
        daio_rsc_uninit(&dai->daio);
        return 0;
@@ -541,7 +539,8 @@ static int get_daio_rsc(struct daio_mgr *mgr,
        err = daio_mgr_get_rsc(&mgr->mgr, desc->type);
        spin_unlock_irqrestore(&mgr->mgr_lock, flags);
        if (err) {
-               printk(KERN_ERR "Can't meet DAIO resource request!\n");
+               dev_err(mgr->card->dev,
+                       "Can't meet DAIO resource request!\n");
                return err;
        }
 
@@ -692,7 +691,7 @@ static int daio_mgr_commit_write(struct daio_mgr *mgr)
        return 0;
 }
 
-int daio_mgr_create(void *hw, struct daio_mgr **rdaio_mgr)
+int daio_mgr_create(struct hw *hw, struct daio_mgr **rdaio_mgr)
 {
        int err, i;
        struct daio_mgr *daio_mgr;
@@ -727,12 +726,13 @@ int daio_mgr_create(void *hw, struct daio_mgr **rdaio_mgr)
        daio_mgr->imap_add = daio_imap_add;
        daio_mgr->imap_delete = daio_imap_delete;
        daio_mgr->commit_write = daio_mgr_commit_write;
+       daio_mgr->card = hw->card;
 
        for (i = 0; i < 8; i++) {
-               ((struct hw *)hw)->daio_mgr_dsb_dao(daio_mgr->mgr.ctrl_blk, i);
-               ((struct hw *)hw)->daio_mgr_dsb_dai(daio_mgr->mgr.ctrl_blk, i);
+               hw->daio_mgr_dsb_dao(daio_mgr->mgr.ctrl_blk, i);
+               hw->daio_mgr_dsb_dai(daio_mgr->mgr.ctrl_blk, i);
        }
-       ((struct hw *)hw)->daio_mgr_commit_write(hw, daio_mgr->mgr.ctrl_blk);
+       hw->daio_mgr_commit_write(hw, daio_mgr->mgr.ctrl_blk);
 
        *rdaio_mgr = daio_mgr;
 
index 85ccb6ee1ab4e2c3f7df0ca5378a7e2bc54c71de..0ebbf350f51aa8a6b3a64e91aa3a278e0b44ebf0 100644 (file)
@@ -23,6 +23,7 @@
 #include "ctimap.h"
 #include <linux/spinlock.h>
 #include <linux/list.h>
+#include <sound/core.h>
 
 /* Define the descriptor of a daio resource */
 enum DAIOTYP {
@@ -53,14 +54,14 @@ struct dao {
        struct dao_rsc_ops *ops;        /* DAO specific operations */
        struct imapper **imappers;
        struct daio_mgr *mgr;
-       void *hw;
+       struct hw *hw;
        void *ctrl_blk;
 };
 
 struct dai {
        struct daio daio;
        struct dai_rsc_ops *ops;        /* DAI specific operations */
-       void *hw;
+       struct hw *hw;
        void *ctrl_blk;
 };
 
@@ -98,6 +99,7 @@ struct daio_desc {
 
 struct daio_mgr {
        struct rsc_mgr mgr;     /* Basic resource manager info */
+       struct snd_card *card;  /* pointer to this card */
        spinlock_t mgr_lock;
        spinlock_t imap_lock;
        struct list_head imappers;
@@ -117,7 +119,7 @@ struct daio_mgr {
 };
 
 /* Constructor and destructor of daio resource manager */
-int daio_mgr_create(void *hw, struct daio_mgr **rdaio_mgr);
+int daio_mgr_create(struct hw *hw, struct daio_mgr **rdaio_mgr);
 int daio_mgr_destroy(struct daio_mgr *daio_mgr);
 
 #endif /* CTDAIO_H */
index 5977e9a24b5ca68971e1f5f0dc17f17b03257098..54cc9cb75f00827ac18b231e3773f36a7a951c10 100644 (file)
@@ -20,6 +20,7 @@
 
 #include <linux/types.h>
 #include <linux/pci.h>
+#include <sound/core.h>
 
 enum CHIPTYP {
        ATC20K1,
@@ -184,9 +185,10 @@ struct hw {
        void *irq_callback_data;
 
        struct pci_dev *pci;    /* the pci kernel structure of this card */
+       struct snd_card *card;  /* pointer to this card */
        int irq;
        unsigned long io_base;
-       unsigned long mem_base;
+       void __iomem *mem_base;
 
        enum CHIPTYP chip_type;
        enum CTCARDS model;
index 6ac40beb49dabea2b54e3de48a9eb721cfc3a5ae..b425aa8ee57858fb11c43f5c1b56bfa6adc8bbca 100644 (file)
@@ -1268,7 +1268,8 @@ static int hw_trn_init(struct hw *hw, const struct trn_conf *info)
 
        /* Set up device page table */
        if ((~0UL) == info->vm_pgt_phys) {
-               printk(KERN_ERR "Wrong device page table page address!\n");
+               dev_err(hw->card->dev,
+                       "Wrong device page table page address!\n");
                return -1;
        }
 
@@ -1327,7 +1328,7 @@ static int hw_pll_init(struct hw *hw, unsigned int rsr)
                mdelay(40);
        }
        if (i >= 3) {
-               printk(KERN_ALERT "PLL initialization failed!!!\n");
+               dev_alert(hw->card->dev, "PLL initialization failed!!!\n");
                return -EBUSY;
        }
 
@@ -1351,7 +1352,7 @@ static int hw_auto_init(struct hw *hw)
                        break;
        }
        if (!get_field(gctl, GCTL_AID)) {
-               printk(KERN_ALERT "Card Auto-init failed!!!\n");
+               dev_alert(hw->card->dev, "Card Auto-init failed!!!\n");
                return -EBUSY;
        }
 
@@ -1802,7 +1803,7 @@ static int uaa_to_xfi(struct pci_dev *pci)
        unsigned int is_uaa;
        unsigned int data[4] = {0};
        unsigned int io_base;
-       void *mem_base;
+       void __iomem *mem_base;
        int i;
        const u32 CTLX = CTLBITS('C', 'T', 'L', 'X');
        const u32 CTL_ = CTLBITS('C', 'T', 'L', '-');
@@ -1911,9 +1912,9 @@ static int hw_card_start(struct hw *hw)
        /* Set DMA transfer mask */
        if (pci_set_dma_mask(pci, CT_XFI_DMA_MASK) < 0 ||
            pci_set_consistent_dma_mask(pci, CT_XFI_DMA_MASK) < 0) {
-               printk(KERN_ERR "architecture does not support PCI "
-                               "busmaster DMA with mask 0x%llx\n",
-                      CT_XFI_DMA_MASK);
+               dev_err(hw->card->dev,
+                       "architecture does not support PCI busmaster DMA with mask 0x%llx\n",
+                       CT_XFI_DMA_MASK);
                err = -ENXIO;
                goto error1;
        }
@@ -1942,7 +1943,8 @@ static int hw_card_start(struct hw *hw)
                err = request_irq(pci->irq, ct_20k1_interrupt, IRQF_SHARED,
                                  KBUILD_MODNAME, hw);
                if (err < 0) {
-                       printk(KERN_ERR "XFi: Cannot get irq %d\n", pci->irq);
+                       dev_err(hw->card->dev,
+                               "XFi: Cannot get irq %d\n", pci->irq);
                        goto error2;
                }
                hw->irq = pci->irq;
@@ -1985,9 +1987,9 @@ static int hw_card_shutdown(struct hw *hw)
        hw->irq = -1;
 
        if (hw->mem_base)
-               iounmap((void *)hw->mem_base);
+               iounmap(hw->mem_base);
 
-       hw->mem_base = (unsigned long)NULL;
+       hw->mem_base = NULL;
 
        if (hw->io_base)
                pci_release_regions(hw->pci);
index b1438861d38ade68112572dbec342240a24d9e34..253899d1379096ea3108c5588aa012b3e4bd9a80 100644 (file)
@@ -1187,7 +1187,8 @@ static int hw_daio_init(struct hw *hw, const struct daio_conf *info)
                hw_write_20kx(hw, AUDIO_IO_TX_BLRCLK, 0x21212121);
                hw_write_20kx(hw, AUDIO_IO_RX_BLRCLK, 0);
        } else {
-               printk(KERN_ALERT "ctxfi: ERROR!!! Invalid sampling rate!!!\n");
+               dev_alert(hw->card->dev,
+                         "ERROR!!! Invalid sampling rate!!!\n");
                return -EINVAL;
        }
 
@@ -1246,8 +1247,8 @@ static int hw_trn_init(struct hw *hw, const struct trn_conf *info)
 
        /* Set up device page table */
        if ((~0UL) == info->vm_pgt_phys) {
-               printk(KERN_ALERT "ctxfi: "
-                      "Wrong device page table page address!!!\n");
+               dev_alert(hw->card->dev,
+                         "Wrong device page table page address!!!\n");
                return -1;
        }
 
@@ -1352,7 +1353,8 @@ static int hw_pll_init(struct hw *hw, unsigned int rsr)
                break;
        }
        if (i >= 1000) {
-               printk(KERN_ALERT "ctxfi: PLL initialization failed!!!\n");
+               dev_alert(hw->card->dev,
+                         "PLL initialization failed!!!\n");
                return -EBUSY;
        }
 
@@ -1376,7 +1378,7 @@ static int hw_auto_init(struct hw *hw)
                        break;
        }
        if (!get_field(gctl, GCTL_AID)) {
-               printk(KERN_ALERT "ctxfi: Card Auto-init failed!!!\n");
+               dev_alert(hw->card->dev, "Card Auto-init failed!!!\n");
                return -EBUSY;
        }
 
@@ -1847,7 +1849,7 @@ static int hw_adc_init(struct hw *hw, const struct adc_conf *info)
        /* Initialize I2C */
        err = hw20k2_i2c_init(hw, 0x1A, 1, 1);
        if (err < 0) {
-               printk(KERN_ALERT "ctxfi: Failure to acquire I2C!!!\n");
+               dev_alert(hw->card->dev, "Failure to acquire I2C!!!\n");
                goto error;
        }
 
@@ -1890,8 +1892,9 @@ static int hw_adc_init(struct hw *hw, const struct adc_conf *info)
                hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_MMC, 0x0A),
                                                MAKE_WM8775_DATA(0x0A));
        } else {
-               printk(KERN_ALERT "ctxfi: Invalid master sampling "
-                                 "rate (msr %d)!!!\n", info->msr);
+               dev_alert(hw->card->dev,
+                         "Invalid master sampling rate (msr %d)!!!\n",
+                         info->msr);
                err = -EINVAL;
                goto error;
        }
@@ -2034,8 +2037,9 @@ static int hw_card_start(struct hw *hw)
        /* Set DMA transfer mask */
        if (pci_set_dma_mask(pci, CT_XFI_DMA_MASK) < 0 ||
            pci_set_consistent_dma_mask(pci, CT_XFI_DMA_MASK) < 0) {
-               printk(KERN_ERR "ctxfi: architecture does not support PCI "
-               "busmaster DMA with mask 0x%llx\n", CT_XFI_DMA_MASK);
+               dev_err(hw->card->dev,
+                       "architecture does not support PCI busmaster DMA with mask 0x%llx\n",
+                       CT_XFI_DMA_MASK);
                err = -ENXIO;
                goto error1;
        }
@@ -2046,8 +2050,8 @@ static int hw_card_start(struct hw *hw)
                        goto error1;
 
                hw->io_base = pci_resource_start(hw->pci, 2);
-               hw->mem_base = (unsigned long)ioremap(hw->io_base,
-                                       pci_resource_len(hw->pci, 2));
+               hw->mem_base = ioremap(hw->io_base,
+                                      pci_resource_len(hw->pci, 2));
                if (!hw->mem_base) {
                        err = -ENOENT;
                        goto error2;
@@ -2063,7 +2067,8 @@ static int hw_card_start(struct hw *hw)
                err = request_irq(pci->irq, ct_20k2_interrupt, IRQF_SHARED,
                                  KBUILD_MODNAME, hw);
                if (err < 0) {
-                       printk(KERN_ERR "XFi: Cannot get irq %d\n", pci->irq);
+                       dev_err(hw->card->dev,
+                               "XFi: Cannot get irq %d\n", pci->irq);
                        goto error2;
                }
                hw->irq = pci->irq;
@@ -2107,9 +2112,9 @@ static int hw_card_shutdown(struct hw *hw)
        hw->irq = -1;
 
        if (hw->mem_base)
-               iounmap((void *)hw->mem_base);
+               iounmap(hw->mem_base);
 
-       hw->mem_base = (unsigned long)NULL;
+       hw->mem_base = NULL;
 
        if (hw->io_base)
                pci_release_regions(hw->pci);
@@ -2229,12 +2234,12 @@ static int hw_resume(struct hw *hw, struct card_conf *info)
 
 static u32 hw_read_20kx(struct hw *hw, u32 reg)
 {
-       return readl((void *)(hw->mem_base + reg));
+       return readl(hw->mem_base + reg);
 }
 
 static void hw_write_20kx(struct hw *hw, u32 reg, u32 data)
 {
-       writel(data, (void *)(hw->mem_base + reg));
+       writel(data, hw->mem_base + reg);
 }
 
 static struct hw ct20k2_preset = {
index 48fe0e39c2be273a95762698999dd4cf5508b019..4f4a2a5dedb8f0fd8eb5b1679cfbab08c5441e12 100644 (file)
@@ -854,8 +854,8 @@ static int ct_mixer_get_resources(struct ct_mixer *mixer)
        for (i = 0; i < (NUM_CT_SUMS * CHN_NUM); i++) {
                err = sum_mgr->get_sum(sum_mgr, &sum_desc, &sum);
                if (err) {
-                       printk(KERN_ERR "ctxfi:Failed to get sum resources for "
-                                         "front output!\n");
+                       dev_err(mixer->atc->card->dev,
+                               "Failed to get sum resources for front output!\n");
                        break;
                }
                mixer->sums[i] = sum;
@@ -869,8 +869,8 @@ static int ct_mixer_get_resources(struct ct_mixer *mixer)
        for (i = 0; i < (NUM_CT_AMIXERS * CHN_NUM); i++) {
                err = amixer_mgr->get_amixer(amixer_mgr, &am_desc, &amixer);
                if (err) {
-                       printk(KERN_ERR "ctxfi:Failed to get amixer resources "
-                              "for mixer obj!\n");
+                       dev_err(mixer->atc->card->dev,
+                               "Failed to get amixer resources for mixer obj!\n");
                        break;
                }
                mixer->amixers[i] = amixer;
index e8a4feb1ed86ba59396368601f1cdbfeb364ce0a..d86c474ca5b62da74aee826b4021bdccb4f09088 100644 (file)
@@ -217,7 +217,8 @@ static int ct_pcm_playback_prepare(struct snd_pcm_substream *substream)
                err = atc->pcm_playback_prepare(atc, apcm);
 
        if (err < 0) {
-               printk(KERN_ERR "ctxfi: Preparing pcm playback failed!!!\n");
+               dev_err(atc->card->dev,
+                       "Preparing pcm playback failed!!!\n");
                return err;
        }
 
@@ -324,7 +325,8 @@ static int ct_pcm_capture_prepare(struct snd_pcm_substream *substream)
 
        err = atc->pcm_capture_prepare(atc, apcm);
        if (err < 0) {
-               printk(KERN_ERR "ctxfi: Preparing pcm capture failed!!!\n");
+               dev_err(atc->card->dev,
+                       "Preparing pcm capture failed!!!\n");
                return err;
        }
 
@@ -435,7 +437,8 @@ int ct_alsa_pcm_create(struct ct_atc *atc,
        err = snd_pcm_new(atc->card, "ctxfi", device,
                          playback_count, capture_count, &pcm);
        if (err < 0) {
-               printk(KERN_ERR "ctxfi: snd_pcm_new failed!! Err=%d\n", err);
+               dev_err(atc->card->dev, "snd_pcm_new failed!! Err=%d\n",
+                       err);
                return err;
        }
 
index 7dfaf67344d4a0ded780ff575922250fe8df6950..1a97e406d8ec00aaa36b430a8d8d02419cb30fca 100644 (file)
@@ -134,7 +134,8 @@ static struct rsc_ops rsc_generic_ops = {
        .next_conj      = rsc_next_conj,
 };
 
-int rsc_init(struct rsc *rsc, u32 idx, enum RSCTYP type, u32 msr, void *hw)
+int
+rsc_init(struct rsc *rsc, u32 idx, enum RSCTYP type, u32 msr, struct hw *hw)
 {
        int err = 0;
 
@@ -151,25 +152,24 @@ int rsc_init(struct rsc *rsc, u32 idx, enum RSCTYP type, u32 msr, void *hw)
 
        switch (type) {
        case SRC:
-               err = ((struct hw *)hw)->src_rsc_get_ctrl_blk(&rsc->ctrl_blk);
+               err = hw->src_rsc_get_ctrl_blk(&rsc->ctrl_blk);
                break;
        case AMIXER:
-               err = ((struct hw *)hw)->
-                               amixer_rsc_get_ctrl_blk(&rsc->ctrl_blk);
+               err = hw->amixer_rsc_get_ctrl_blk(&rsc->ctrl_blk);
                break;
        case SRCIMP:
        case SUM:
        case DAIO:
                break;
        default:
-               printk(KERN_ERR
-                      "ctxfi: Invalid resource type value %d!\n", type);
+               dev_err(((struct hw *)hw)->card->dev,
+                       "Invalid resource type value %d!\n", type);
                return -EINVAL;
        }
 
        if (err) {
-               printk(KERN_ERR
-                      "ctxfi: Failed to get resource control block!\n");
+               dev_err(((struct hw *)hw)->card->dev,
+                       "Failed to get resource control block!\n");
                return err;
        }
 
@@ -181,19 +181,18 @@ int rsc_uninit(struct rsc *rsc)
        if ((NULL != rsc->hw) && (NULL != rsc->ctrl_blk)) {
                switch (rsc->type) {
                case SRC:
-                       ((struct hw *)rsc->hw)->
-                               src_rsc_put_ctrl_blk(rsc->ctrl_blk);
+                       rsc->hw->src_rsc_put_ctrl_blk(rsc->ctrl_blk);
                        break;
                case AMIXER:
-                       ((struct hw *)rsc->hw)->
-                               amixer_rsc_put_ctrl_blk(rsc->ctrl_blk);
+                       rsc->hw->amixer_rsc_put_ctrl_blk(rsc->ctrl_blk);
                        break;
                case SUM:
                case DAIO:
                        break;
                default:
-                       printk(KERN_ERR "ctxfi: "
-                              "Invalid resource type value %d!\n", rsc->type);
+                       dev_err(((struct hw *)rsc->hw)->card->dev,
+                               "Invalid resource type value %d!\n",
+                               rsc->type);
                        break;
                }
 
@@ -208,10 +207,9 @@ int rsc_uninit(struct rsc *rsc)
 }
 
 int rsc_mgr_init(struct rsc_mgr *mgr, enum RSCTYP type,
-                unsigned int amount, void *hw_obj)
+                unsigned int amount, struct hw *hw)
 {
        int err = 0;
-       struct hw *hw = hw_obj;
 
        mgr->type = NUM_RSCTYP;
 
@@ -235,15 +233,15 @@ int rsc_mgr_init(struct rsc_mgr *mgr, enum RSCTYP type,
        case SUM:
                break;
        default:
-               printk(KERN_ERR
-                      "ctxfi: Invalid resource type value %d!\n", type);
+               dev_err(hw->card->dev,
+                       "Invalid resource type value %d!\n", type);
                err = -EINVAL;
                goto error;
        }
 
        if (err) {
-               printk(KERN_ERR
-                      "ctxfi: Failed to get manager control block!\n");
+               dev_err(hw->card->dev,
+                       "Failed to get manager control block!\n");
                goto error;
        }
 
@@ -268,26 +266,23 @@ int rsc_mgr_uninit(struct rsc_mgr *mgr)
        if ((NULL != mgr->hw) && (NULL != mgr->ctrl_blk)) {
                switch (mgr->type) {
                case SRC:
-                       ((struct hw *)mgr->hw)->
-                               src_mgr_put_ctrl_blk(mgr->ctrl_blk);
+                       mgr->hw->src_mgr_put_ctrl_blk(mgr->ctrl_blk);
                        break;
                case SRCIMP:
-                       ((struct hw *)mgr->hw)->
-                               srcimp_mgr_put_ctrl_blk(mgr->ctrl_blk);
+                       mgr->hw->srcimp_mgr_put_ctrl_blk(mgr->ctrl_blk);
                        break;
                case AMIXER:
-                       ((struct hw *)mgr->hw)->
-                               amixer_mgr_put_ctrl_blk(mgr->ctrl_blk);
+                       mgr->hw->amixer_mgr_put_ctrl_blk(mgr->ctrl_blk);
                        break;
                case DAIO:
-                       ((struct hw *)mgr->hw)->
-                               daio_mgr_put_ctrl_blk(mgr->ctrl_blk);
+                       mgr->hw->daio_mgr_put_ctrl_blk(mgr->ctrl_blk);
                        break;
                case SUM:
                        break;
                default:
-                       printk(KERN_ERR "ctxfi: "
-                              "Invalid resource type value %d!\n", mgr->type);
+                       dev_err(((struct hw *)mgr->hw)->card->dev,
+                               "Invalid resource type value %d!\n",
+                               mgr->type);
                        break;
                }
 
index 0838c2e84f8b42ec8bb7b2372b0fa72f037f2762..9b746c3719e6219faa30b116b762675376867631 100644 (file)
@@ -38,7 +38,7 @@ struct rsc {
        u32 conj:12;    /* Current conjugate index */
        u32 msr:4;      /* The Master Sample Rate a resource working on */
        void *ctrl_blk; /* Chip specific control info block for a resource */
-       void *hw;       /* Chip specific object for hardware access means */
+       struct hw *hw;  /* Chip specific object for hardware access means */
        struct rsc_ops *ops;    /* Generic resource operations */
 };
 
@@ -50,7 +50,8 @@ struct rsc_ops {
        int (*output_slot)(const struct rsc *rsc);
 };
 
-int rsc_init(struct rsc *rsc, u32 idx, enum RSCTYP type, u32 msr, void *hw);
+int
+rsc_init(struct rsc *rsc, u32 idx, enum RSCTYP type, u32 msr, struct hw *hw);
 int rsc_uninit(struct rsc *rsc);
 
 struct rsc_mgr {
@@ -59,12 +60,12 @@ struct rsc_mgr {
        unsigned int avail; /* The amount of currently available resources */
        unsigned char *rscs; /* The bit-map for resource allocation */
        void *ctrl_blk; /* Chip specific control info block */
-       void *hw; /* Chip specific object for hardware access */
+       struct hw *hw; /* Chip specific object for hardware access */
 };
 
 /* Resource management is based on bit-map mechanism */
 int rsc_mgr_init(struct rsc_mgr *mgr, enum RSCTYP type,
-                unsigned int amount, void *hw);
+                unsigned int amount, struct hw *hw);
 int rsc_mgr_uninit(struct rsc_mgr *mgr);
 int mgr_get_resource(struct rsc_mgr *mgr, unsigned int n, unsigned int *ridx);
 int mgr_put_resource(struct rsc_mgr *mgr, unsigned int n, unsigned int idx);
index 6e77e86307c2c90fd8ca8d3dde53dceebd0499af..ec1f08464d938ce0adc3660f3ae8efbb799d7cde 100644 (file)
@@ -431,7 +431,8 @@ get_src_rsc(struct src_mgr *mgr, const struct src_desc *desc, struct src **rsrc)
 
        spin_unlock_irqrestore(&mgr->mgr_lock, flags);
        if (err) {
-               printk(KERN_ERR "ctxfi: Can't meet SRC resource request!\n");
+               dev_err(mgr->card->dev,
+                       "Can't meet SRC resource request!\n");
                return err;
        }
 
@@ -543,7 +544,7 @@ static int src_mgr_commit_write(struct src_mgr *mgr)
        return 0;
 }
 
-int src_mgr_create(void *hw, struct src_mgr **rsrc_mgr)
+int src_mgr_create(struct hw *hw, struct src_mgr **rsrc_mgr)
 {
        int err, i;
        struct src_mgr *src_mgr;
@@ -558,7 +559,7 @@ int src_mgr_create(void *hw, struct src_mgr **rsrc_mgr)
                goto error1;
 
        spin_lock_init(&src_mgr->mgr_lock);
-       conj_mask = ((struct hw *)hw)->src_dirty_conj_mask();
+       conj_mask = hw->src_dirty_conj_mask();
 
        src_mgr->get_src = get_src_rsc;
        src_mgr->put_src = put_src_rsc;
@@ -566,12 +567,13 @@ int src_mgr_create(void *hw, struct src_mgr **rsrc_mgr)
        src_mgr->src_enable = src_enable;
        src_mgr->src_disable = src_disable;
        src_mgr->commit_write = src_mgr_commit_write;
+       src_mgr->card = hw->card;
 
        /* Disable all SRC resources. */
        for (i = 0; i < 256; i++)
-               ((struct hw *)hw)->src_mgr_dsb_src(src_mgr->mgr.ctrl_blk, i);
+               hw->src_mgr_dsb_src(src_mgr->mgr.ctrl_blk, i);
 
-       ((struct hw *)hw)->src_mgr_commit_write(hw, src_mgr->mgr.ctrl_blk);
+       hw->src_mgr_commit_write(hw, src_mgr->mgr.ctrl_blk);
 
        *rsrc_mgr = src_mgr;
 
@@ -739,7 +741,8 @@ static int get_srcimp_rsc(struct srcimp_mgr *mgr,
        }
        spin_unlock_irqrestore(&mgr->mgr_lock, flags);
        if (err) {
-               printk(KERN_ERR "ctxfi: Can't meet SRCIMP resource request!\n");
+               dev_err(mgr->card->dev,
+                       "Can't meet SRCIMP resource request!\n");
                goto error1;
        }
 
@@ -825,7 +828,7 @@ static int srcimp_imap_delete(struct srcimp_mgr *mgr, struct imapper *entry)
        return err;
 }
 
-int srcimp_mgr_create(void *hw, struct srcimp_mgr **rsrcimp_mgr)
+int srcimp_mgr_create(struct hw *hw, struct srcimp_mgr **rsrcimp_mgr)
 {
        int err;
        struct srcimp_mgr *srcimp_mgr;
@@ -857,6 +860,7 @@ int srcimp_mgr_create(void *hw, struct srcimp_mgr **rsrcimp_mgr)
        srcimp_mgr->put_srcimp = put_srcimp_rsc;
        srcimp_mgr->imap_add = srcimp_imap_add;
        srcimp_mgr->imap_delete = srcimp_imap_delete;
+       srcimp_mgr->card = hw->card;
 
        *rsrcimp_mgr = srcimp_mgr;
 
index 259366aabcaca35db91fa5ff2bf978045fb35908..da7573c5db9bb6bdfd974c03c758a33c32170e65 100644 (file)
@@ -23,6 +23,7 @@
 #include "ctimap.h"
 #include <linux/spinlock.h>
 #include <linux/list.h>
+#include <sound/core.h>
 
 #define SRC_STATE_OFF  0x0
 #define SRC_STATE_INIT 0x4
@@ -85,6 +86,7 @@ struct src_desc {
 /* Define src manager object */
 struct src_mgr {
        struct rsc_mgr mgr;     /* Basic resource manager info */
+       struct snd_card *card;  /* pointer to this card */
        spinlock_t mgr_lock;
 
         /* request src resource */
@@ -123,6 +125,7 @@ struct srcimp_desc {
 
 struct srcimp_mgr {
        struct rsc_mgr mgr;     /* Basic resource manager info */
+       struct snd_card *card;  /* pointer to this card */
        spinlock_t mgr_lock;
        spinlock_t imap_lock;
        struct list_head imappers;
@@ -140,10 +143,10 @@ struct srcimp_mgr {
 };
 
 /* Constructor and destructor of SRC resource manager */
-int src_mgr_create(void *hw, struct src_mgr **rsrc_mgr);
+int src_mgr_create(struct hw *hw, struct src_mgr **rsrc_mgr);
 int src_mgr_destroy(struct src_mgr *src_mgr);
 /* Constructor and destructor of SRCIMP resource manager */
-int srcimp_mgr_create(void *hw, struct srcimp_mgr **rsrc_mgr);
+int srcimp_mgr_create(struct hw *hw, struct srcimp_mgr **rsrc_mgr);
 int srcimp_mgr_destroy(struct srcimp_mgr *srcimp_mgr);
 
 #endif /* CTSRC_H */
index 6109490b83e83294373f36956a5a8a01dd923e20..419306ef825f61c51c50a507c3c249784f613337 100644 (file)
@@ -16,6 +16,7 @@
  */
 
 #include "ctvmem.h"
+#include "ctatc.h"
 #include <linux/slab.h>
 #include <linux/mm.h>
 #include <linux/io.h>
  * @size must be page aligned.
  * */
 static struct ct_vm_block *
-get_vm_block(struct ct_vm *vm, unsigned int size)
+get_vm_block(struct ct_vm *vm, unsigned int size, struct ct_atc *atc)
 {
        struct ct_vm_block *block = NULL, *entry;
        struct list_head *pos;
 
        size = CT_PAGE_ALIGN(size);
        if (size > vm->size) {
-               printk(KERN_ERR "ctxfi: Fail! No sufficient device virtual "
-                                 "memory space available!\n");
+               dev_err(atc->card->dev,
+                       "Fail! No sufficient device virtual memory space available!\n");
                return NULL;
        }
 
@@ -129,11 +130,12 @@ ct_vm_map(struct ct_vm *vm, struct snd_pcm_substream *substream, int size)
        unsigned int pte_start;
        unsigned i, pages;
        unsigned long *ptp;
+       struct ct_atc *atc = snd_pcm_substream_chip(substream);
 
-       block = get_vm_block(vm, size);
+       block = get_vm_block(vm, size, atc);
        if (block == NULL) {
-               printk(KERN_ERR "ctxfi: No virtual memory block that is big "
-                                 "enough to allocate!\n");
+               dev_err(atc->card->dev,
+                       "No virtual memory block that is big enough to allocate!\n");
                return NULL;
        }
 
index 8f8b566a1b35ea0c8d32755b0d6240d351787922..f2f32779de986ff9d50b6853f024113d79ef9752 100644 (file)
@@ -76,17 +76,18 @@ ct_card_probe(struct pci_dev *pci, const struct pci_device_id *pci_id)
        if (err)
                return err;
        if ((reference_rate != 48000) && (reference_rate != 44100)) {
-               printk(KERN_ERR "ctxfi: Invalid reference_rate value %u!!!\n",
-                      reference_rate);
-               printk(KERN_ERR "ctxfi: The valid values for reference_rate "
-                      "are 48000 and 44100, Value 48000 is assumed.\n");
+               dev_err(card->dev,
+                       "Invalid reference_rate value %u!!!\n",
+                       reference_rate);
+               dev_err(card->dev,
+                       "The valid values for reference_rate are 48000 and 44100, Value 48000 is assumed.\n");
                reference_rate = 48000;
        }
        if ((multiple != 1) && (multiple != 2) && (multiple != 4)) {
-               printk(KERN_ERR "ctxfi: Invalid multiple value %u!!!\n",
-                      multiple);
-               printk(KERN_ERR "ctxfi: The valid values for multiple are "
-                      "1, 2 and 4, Value 2 is assumed.\n");
+               dev_err(card->dev, "Invalid multiple value %u!!!\n",
+                       multiple);
+               dev_err(card->dev,
+                       "The valid values for multiple are 1, 2 and 4, Value 2 is assumed.\n");
                multiple = 2;
        }
        err = ct_atc_create(card, pci, reference_rate, multiple,
index 51dea49aadd4212b83263766d01f44a40bc0ac75..fcc5e478c9a1a10a42db7c69e24560de42c0cdbe 100644 (file)
@@ -57,12 +57,14 @@ static void sort_pins_by_sequence(hda_nid_t *pins, struct auto_out_pin *list,
 
 
 /* add the found input-pin to the cfg->inputs[] table */
-static void add_auto_cfg_input_pin(struct auto_pin_cfg *cfg, hda_nid_t nid,
-                                  int type)
+static void add_auto_cfg_input_pin(struct hda_codec *codec, struct auto_pin_cfg *cfg,
+                                  hda_nid_t nid, int type)
 {
        if (cfg->num_inputs < AUTO_CFG_MAX_INS) {
                cfg->inputs[cfg->num_inputs].pin = nid;
                cfg->inputs[cfg->num_inputs].type = type;
+               cfg->inputs[cfg->num_inputs].has_boost_on_pin =
+                       nid_has_volume(codec, nid, HDA_INPUT);
                cfg->num_inputs++;
        }
 }
@@ -71,7 +73,12 @@ static int compare_input_type(const void *ap, const void *bp)
 {
        const struct auto_pin_cfg_item *a = ap;
        const struct auto_pin_cfg_item *b = bp;
-       return (int)(a->type - b->type);
+       if (a->type != b->type)
+               return (int)(a->type - b->type);
+
+       /* In case one has boost and the other one has not,
+          pick the one with boost first. */
+       return (int)(b->has_boost_on_pin - a->has_boost_on_pin);
 }
 
 /* Reorder the surround channels
@@ -268,16 +275,16 @@ int snd_hda_parse_pin_defcfg(struct hda_codec *codec,
                        cfg->hp_outs++;
                        break;
                case AC_JACK_MIC_IN:
-                       add_auto_cfg_input_pin(cfg, nid, AUTO_PIN_MIC);
+                       add_auto_cfg_input_pin(codec, cfg, nid, AUTO_PIN_MIC);
                        break;
                case AC_JACK_LINE_IN:
-                       add_auto_cfg_input_pin(cfg, nid, AUTO_PIN_LINE_IN);
+                       add_auto_cfg_input_pin(codec, cfg, nid, AUTO_PIN_LINE_IN);
                        break;
                case AC_JACK_CD:
-                       add_auto_cfg_input_pin(cfg, nid, AUTO_PIN_CD);
+                       add_auto_cfg_input_pin(codec, cfg, nid, AUTO_PIN_CD);
                        break;
                case AC_JACK_AUX:
-                       add_auto_cfg_input_pin(cfg, nid, AUTO_PIN_AUX);
+                       add_auto_cfg_input_pin(codec, cfg, nid, AUTO_PIN_AUX);
                        break;
                case AC_JACK_SPDIF_OUT:
                case AC_JACK_DIG_OTHER_OUT:
index e941f604f5e5d450c2ac204a2a401842d5f6d4a8..2b8e29fd73e7ee0ea23762e59b9250ffb0283757 100644 (file)
@@ -38,6 +38,7 @@ struct auto_pin_cfg_item {
        int type;
        unsigned int is_headset_mic:1;
        unsigned int is_headphone_mic:1; /* Mic-only in headphone jack */
+       unsigned int has_boost_on_pin:1;
 };
 
 struct auto_pin_cfg;
index ec6a7d0d1886c691fc5cf356c6d078e4cea435c0..15e0089492f735f55814d6caf1e6735080358602 100644 (file)
@@ -2001,6 +2001,26 @@ u32 query_amp_caps(struct hda_codec *codec, hda_nid_t nid, int direction)
 }
 EXPORT_SYMBOL_GPL(query_amp_caps);
 
+/**
+ * snd_hda_check_amp_caps - query AMP capabilities
+ * @codec: the HD-audio codec
+ * @nid: the NID to query
+ * @dir: either #HDA_INPUT or #HDA_OUTPUT
+ *
+ * Check whether the widget has the given amp capability for the direction.
+ */
+bool snd_hda_check_amp_caps(struct hda_codec *codec, hda_nid_t nid,
+                          int dir, unsigned int bits)
+{
+       if (!nid)
+               return false;
+       if (get_wcaps(codec, nid) & (1 << (dir + 1)))
+               if (query_amp_caps(codec, nid, dir) & bits)
+                       return true;
+       return false;
+}
+EXPORT_SYMBOL_GPL(snd_hda_check_amp_caps);
+
 /**
  * snd_hda_override_amp_caps - Override the AMP capabilities
  * @codec: the CODEC to clean up
@@ -4816,121 +4836,6 @@ int snd_hda_build_pcms(struct hda_bus *bus)
 }
 EXPORT_SYMBOL_GPL(snd_hda_build_pcms);
 
-/**
- * snd_hda_check_board_config - compare the current codec with the config table
- * @codec: the HDA codec
- * @num_configs: number of config enums
- * @models: array of model name strings
- * @tbl: configuration table, terminated by null entries
- *
- * Compares the modelname or PCI subsystem id of the current codec with the
- * given configuration table.  If a matching entry is found, returns its
- * config value (supposed to be 0 or positive).
- *
- * If no entries are matching, the function returns a negative value.
- */
-int snd_hda_check_board_config(struct hda_codec *codec,
-                              int num_configs, const char * const *models,
-                              const struct snd_pci_quirk *tbl)
-{
-       if (codec->modelname && models) {
-               int i;
-               for (i = 0; i < num_configs; i++) {
-                       if (models[i] &&
-                           !strcmp(codec->modelname, models[i])) {
-                               codec_info(codec, "model '%s' is selected\n",
-                                          models[i]);
-                               return i;
-                       }
-               }
-       }
-
-       if (!codec->bus->pci || !tbl)
-               return -1;
-
-       tbl = snd_pci_quirk_lookup(codec->bus->pci, tbl);
-       if (!tbl)
-               return -1;
-       if (tbl->value >= 0 && tbl->value < num_configs) {
-#ifdef CONFIG_SND_DEBUG_VERBOSE
-               char tmp[10];
-               const char *model = NULL;
-               if (models)
-                       model = models[tbl->value];
-               if (!model) {
-                       sprintf(tmp, "#%d", tbl->value);
-                       model = tmp;
-               }
-               codec_info(codec, "model '%s' is selected for config %x:%x (%s)\n",
-                          model, tbl->subvendor, tbl->subdevice,
-                          (tbl->name ? tbl->name : "Unknown device"));
-#endif
-               return tbl->value;
-       }
-       return -1;
-}
-EXPORT_SYMBOL_GPL(snd_hda_check_board_config);
-
-/**
- * snd_hda_check_board_codec_sid_config - compare the current codec
-                                       subsystem ID with the
-                                       config table
-
-          This is important for Gateway notebooks with SB450 HDA Audio
-          where the vendor ID of the PCI device is:
-               ATI Technologies Inc SB450 HDA Audio [1002:437b]
-          and the vendor/subvendor are found only at the codec.
-
- * @codec: the HDA codec
- * @num_configs: number of config enums
- * @models: array of model name strings
- * @tbl: configuration table, terminated by null entries
- *
- * Compares the modelname or PCI subsystem id of the current codec with the
- * given configuration table.  If a matching entry is found, returns its
- * config value (supposed to be 0 or positive).
- *
- * If no entries are matching, the function returns a negative value.
- */
-int snd_hda_check_board_codec_sid_config(struct hda_codec *codec,
-                              int num_configs, const char * const *models,
-                              const struct snd_pci_quirk *tbl)
-{
-       const struct snd_pci_quirk *q;
-
-       /* Search for codec ID */
-       for (q = tbl; q->subvendor; q++) {
-               unsigned int mask = 0xffff0000 | q->subdevice_mask;
-               unsigned int id = (q->subdevice | (q->subvendor << 16)) & mask;
-               if ((codec->subsystem_id & mask) == id)
-                       break;
-       }
-
-       if (!q->subvendor)
-               return -1;
-
-       tbl = q;
-
-       if (tbl->value >= 0 && tbl->value < num_configs) {
-#ifdef CONFIG_SND_DEBUG_VERBOSE
-               char tmp[10];
-               const char *model = NULL;
-               if (models)
-                       model = models[tbl->value];
-               if (!model) {
-                       sprintf(tmp, "#%d", tbl->value);
-                       model = tmp;
-               }
-               codec_info(codec, "model '%s' is selected for config %x:%x (%s)\n",
-                          model, tbl->subvendor, tbl->subdevice,
-                          (tbl->name ? tbl->name : "Unknown device"));
-#endif
-               return tbl->value;
-       }
-       return -1;
-}
-EXPORT_SYMBOL_GPL(snd_hda_check_board_codec_sid_config);
-
 /**
  * snd_hda_add_new_ctls - create controls from the array
  * @codec: the HDA codec
index bbc5a1392c7522ce1cd961064d972a4e60c49561..9c8820f21f948ffb98bea96a0804d6e9b80e1aa8 100644 (file)
@@ -687,6 +687,4 @@ snd_hda_codec_load_dsp_cleanup(struct hda_codec *codec,
                                struct snd_dma_buffer *dmab) {}
 #endif
 
-#define EXPORT_SYMBOL_HDA(sym) EXPORT_SYMBOL_GPL(sym)
-
 #endif /* __SOUND_HDA_CODEC_H */
index b956449ddada67751297b9154422509dc065a388..64220c08bd982b01851ab13b70660104d2d6e2d2 100644 (file)
@@ -31,6 +31,7 @@
 #include <linux/module.h>
 #include <sound/core.h>
 #include <sound/jack.h>
+#include <sound/tlv.h>
 #include "hda_codec.h"
 #include "hda_local.h"
 #include "hda_auto_parser.h"
@@ -518,18 +519,6 @@ static unsigned int amp_val_replace_channels(unsigned int val, unsigned int chs)
        return val;
 }
 
-/* check whether the widget has the given amp capability for the direction */
-static bool check_amp_caps(struct hda_codec *codec, hda_nid_t nid,
-                          int dir, unsigned int bits)
-{
-       if (!nid)
-               return false;
-       if (get_wcaps(codec, nid) & (1 << (dir + 1)))
-               if (query_amp_caps(codec, nid, dir) & bits)
-                       return true;
-       return false;
-}
-
 static bool same_amp_caps(struct hda_codec *codec, hda_nid_t nid1,
                          hda_nid_t nid2, int dir)
 {
@@ -539,11 +528,6 @@ static bool same_amp_caps(struct hda_codec *codec, hda_nid_t nid1,
                query_amp_caps(codec, nid2, dir));
 }
 
-#define nid_has_mute(codec, nid, dir) \
-       check_amp_caps(codec, nid, dir, (AC_AMPCAP_MUTE | AC_AMPCAP_MIN_MUTE))
-#define nid_has_volume(codec, nid, dir) \
-       check_amp_caps(codec, nid, dir, AC_AMPCAP_NUM_STEPS)
-
 /* look for a widget suitable for assigning a mute switch in the path */
 static hda_nid_t look_for_out_mute_nid(struct hda_codec *codec,
                                       struct nid_path *path)
@@ -1105,6 +1089,7 @@ enum {
  */
 static int assign_out_path_ctls(struct hda_codec *codec, struct nid_path *path)
 {
+       struct hda_gen_spec *spec = codec->spec;
        hda_nid_t nid;
        unsigned int val;
        int badness = 0;
@@ -1119,6 +1104,8 @@ static int assign_out_path_ctls(struct hda_codec *codec, struct nid_path *path)
        nid = look_for_out_vol_nid(codec, path);
        if (nid) {
                val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT);
+               if (spec->dac_min_mute)
+                       val |= HDA_AMP_VAL_MIN_MUTE;
                if (is_ctl_used(codec, val, NID_PATH_VOL_CTL))
                        badness += BAD_SHARED_VOL;
                else
@@ -1880,9 +1867,12 @@ static int parse_output_paths(struct hda_codec *codec)
                path = snd_hda_get_path_from_idx(codec, spec->out_paths[0]);
                if (path)
                        spec->vmaster_nid = look_for_out_vol_nid(codec, path);
-               if (spec->vmaster_nid)
+               if (spec->vmaster_nid) {
                        snd_hda_set_vmaster_tlv(codec, spec->vmaster_nid,
                                                HDA_OUTPUT, spec->vmaster_tlv);
+                       if (spec->dac_min_mute)
+                               spec->vmaster_tlv[3] |= TLV_DB_SCALE_MUTE;
+               }
        }
 
        /* set initial pinctl targets */
@@ -2025,7 +2015,8 @@ static int create_speaker_out_ctls(struct hda_codec *codec)
  * independent HP controls
  */
 
-static void call_hp_automute(struct hda_codec *codec, struct hda_jack_tbl *jack);
+static void call_hp_automute(struct hda_codec *codec,
+                            struct hda_jack_callback *jack);
 static int indep_hp_info(struct snd_kcontrol *kcontrol,
                         struct snd_ctl_elem_info *uinfo)
 {
@@ -3941,7 +3932,8 @@ static void call_update_outputs(struct hda_codec *codec)
 }
 
 /* standard HP-automute helper */
-void snd_hda_gen_hp_automute(struct hda_codec *codec, struct hda_jack_tbl *jack)
+void snd_hda_gen_hp_automute(struct hda_codec *codec,
+                            struct hda_jack_callback *jack)
 {
        struct hda_gen_spec *spec = codec->spec;
        hda_nid_t *pins = spec->autocfg.hp_pins;
@@ -3961,7 +3953,8 @@ void snd_hda_gen_hp_automute(struct hda_codec *codec, struct hda_jack_tbl *jack)
 EXPORT_SYMBOL_GPL(snd_hda_gen_hp_automute);
 
 /* standard line-out-automute helper */
-void snd_hda_gen_line_automute(struct hda_codec *codec, struct hda_jack_tbl *jack)
+void snd_hda_gen_line_automute(struct hda_codec *codec,
+                              struct hda_jack_callback *jack)
 {
        struct hda_gen_spec *spec = codec->spec;
 
@@ -3981,7 +3974,8 @@ void snd_hda_gen_line_automute(struct hda_codec *codec, struct hda_jack_tbl *jac
 EXPORT_SYMBOL_GPL(snd_hda_gen_line_automute);
 
 /* standard mic auto-switch helper */
-void snd_hda_gen_mic_autoswitch(struct hda_codec *codec, struct hda_jack_tbl *jack)
+void snd_hda_gen_mic_autoswitch(struct hda_codec *codec,
+                               struct hda_jack_callback *jack)
 {
        struct hda_gen_spec *spec = codec->spec;
        int i;
@@ -4004,7 +3998,8 @@ void snd_hda_gen_mic_autoswitch(struct hda_codec *codec, struct hda_jack_tbl *ja
 EXPORT_SYMBOL_GPL(snd_hda_gen_mic_autoswitch);
 
 /* call appropriate hooks */
-static void call_hp_automute(struct hda_codec *codec, struct hda_jack_tbl *jack)
+static void call_hp_automute(struct hda_codec *codec,
+                            struct hda_jack_callback *jack)
 {
        struct hda_gen_spec *spec = codec->spec;
        if (spec->hp_automute_hook)
@@ -4014,7 +4009,7 @@ static void call_hp_automute(struct hda_codec *codec, struct hda_jack_tbl *jack)
 }
 
 static void call_line_automute(struct hda_codec *codec,
-                              struct hda_jack_tbl *jack)
+                              struct hda_jack_callback *jack)
 {
        struct hda_gen_spec *spec = codec->spec;
        if (spec->line_automute_hook)
@@ -4024,7 +4019,7 @@ static void call_line_automute(struct hda_codec *codec,
 }
 
 static void call_mic_autoswitch(struct hda_codec *codec,
-                               struct hda_jack_tbl *jack)
+                               struct hda_jack_callback *jack)
 {
        struct hda_gen_spec *spec = codec->spec;
        if (spec->mic_autoswitch_hook)
@@ -4173,7 +4168,7 @@ static int check_auto_mute_availability(struct hda_codec *codec)
                if (!is_jack_detectable(codec, nid))
                        continue;
                codec_dbg(codec, "Enable HP auto-muting on NID 0x%x\n", nid);
-               snd_hda_jack_detect_enable_callback(codec, nid, HDA_GEN_HP_EVENT,
+               snd_hda_jack_detect_enable_callback(codec, nid,
                                                    call_hp_automute);
                spec->detect_hp = 1;
        }
@@ -4186,7 +4181,6 @@ static int check_auto_mute_availability(struct hda_codec *codec)
                                        continue;
                                codec_dbg(codec, "Enable Line-Out auto-muting on NID 0x%x\n", nid);
                                snd_hda_jack_detect_enable_callback(codec, nid,
-                                                                   HDA_GEN_FRONT_EVENT,
                                                                    call_line_automute);
                                spec->detect_lo = 1;
                        }
@@ -4228,7 +4222,6 @@ static bool auto_mic_check_imux(struct hda_codec *codec)
        for (i = 1; i < spec->am_num_entries; i++)
                snd_hda_jack_detect_enable_callback(codec,
                                                    spec->am_entry[i].pin,
-                                                   HDA_GEN_MIC_EVENT,
                                                    call_mic_autoswitch);
        return true;
 }
index bb2dea743986b365813a9e55ed2342ecd4f25c07..61dd5153f512b99a26d44305dc2e17b723322077 100644 (file)
 #ifndef __SOUND_HDA_GENERIC_H
 #define __SOUND_HDA_GENERIC_H
 
-/* unsol event tags */
-enum {
-       HDA_GEN_HP_EVENT = 1, HDA_GEN_FRONT_EVENT, HDA_GEN_MIC_EVENT,
-       HDA_GEN_LAST_EVENT = HDA_GEN_MIC_EVENT
-};
-
 /* table entry for multi-io paths */
 struct hda_multi_io {
        hda_nid_t pin;          /* multi-io widget pin NID */
@@ -231,6 +225,7 @@ struct hda_gen_spec {
        unsigned int add_stereo_mix_input:1; /* add aamix as a capture src */
        unsigned int add_jack_modes:1; /* add i/o jack mode enum ctls */
        unsigned int power_down_unused:1; /* power down unused widgets */
+       unsigned int dac_min_mute:1; /* minimal = mute for DACs */
 
        /* other internal flags */
        unsigned int no_analog:1; /* digital I/O only */
@@ -289,11 +284,11 @@ struct hda_gen_spec {
 
        /* automute / autoswitch hooks */
        void (*hp_automute_hook)(struct hda_codec *codec,
-                                struct hda_jack_tbl *tbl);
+                                struct hda_jack_callback *cb);
        void (*line_automute_hook)(struct hda_codec *codec,
-                                  struct hda_jack_tbl *tbl);
+                                  struct hda_jack_callback *cb);
        void (*mic_autoswitch_hook)(struct hda_codec *codec,
-                                   struct hda_jack_tbl *tbl);
+                                   struct hda_jack_callback *cb);
 };
 
 int snd_hda_gen_spec_init(struct hda_gen_spec *spec);
@@ -325,11 +320,11 @@ int snd_hda_gen_build_pcms(struct hda_codec *codec);
 
 /* standard jack event callbacks */
 void snd_hda_gen_hp_automute(struct hda_codec *codec,
-                            struct hda_jack_tbl *jack);
+                            struct hda_jack_callback *jack);
 void snd_hda_gen_line_automute(struct hda_codec *codec,
-                              struct hda_jack_tbl *jack);
+                              struct hda_jack_callback *jack);
 void snd_hda_gen_mic_autoswitch(struct hda_codec *codec,
-                               struct hda_jack_tbl *jack);
+                               struct hda_jack_callback *jack);
 void snd_hda_gen_update_outputs(struct hda_codec *codec);
 
 #ifdef CONFIG_PM
index 9746d73cec52b113b83e7e694f854cdac719e574..f56765ae73a7ed064d820c88f24a243097ea147e 100644 (file)
@@ -94,7 +94,7 @@ EXPORT_SYMBOL_GPL(snd_hda_jack_tbl_get_from_tag);
 /**
  * snd_hda_jack_tbl_new - create a jack-table entry for the given NID
  */
-struct hda_jack_tbl *
+static struct hda_jack_tbl *
 snd_hda_jack_tbl_new(struct hda_codec *codec, hda_nid_t nid)
 {
        struct hda_jack_tbl *jack = snd_hda_jack_tbl_get(codec, nid);
@@ -108,21 +108,24 @@ snd_hda_jack_tbl_new(struct hda_codec *codec, hda_nid_t nid)
        jack->tag = codec->jacktbl.used;
        return jack;
 }
-EXPORT_SYMBOL_GPL(snd_hda_jack_tbl_new);
 
 void snd_hda_jack_tbl_clear(struct hda_codec *codec)
 {
+       struct hda_jack_tbl *jack = codec->jacktbl.list;
+       int i;
+
+       for (i = 0; i < codec->jacktbl.used; i++, jack++) {
+               struct hda_jack_callback *cb, *next;
 #ifdef CONFIG_SND_HDA_INPUT_JACK
-       /* free jack instances manually when clearing/reconfiguring */
-       if (!codec->bus->shutdown && codec->jacktbl.list) {
-               struct hda_jack_tbl *jack = codec->jacktbl.list;
-               int i;
-               for (i = 0; i < codec->jacktbl.used; i++, jack++) {
-                       if (jack->jack)
-                               snd_device_free(codec->bus->card, jack->jack);
+               /* free jack instances manually when clearing/reconfiguring */
+               if (!codec->bus->shutdown && jack->jack)
+                       snd_device_free(codec->bus->card, jack->jack);
+#endif
+               for (cb = jack->callback; cb; cb = next) {
+                       next = cb->next;
+                       kfree(cb);
                }
        }
-#endif
        snd_array_free(&codec->jacktbl);
 }
 
@@ -215,33 +218,49 @@ EXPORT_SYMBOL_GPL(snd_hda_jack_detect_state);
 
 /**
  * snd_hda_jack_detect_enable - enable the jack-detection
+ *
+ * In the case of error, the return value will be a pointer embedded with
+ * errno.  Check and handle the return value appropriately with standard
+ * macros such as @IS_ERR() and @PTR_ERR().
  */
-int snd_hda_jack_detect_enable_callback(struct hda_codec *codec, hda_nid_t nid,
-                                       unsigned char action,
-                                       hda_jack_callback cb)
+struct hda_jack_callback *
+snd_hda_jack_detect_enable_callback(struct hda_codec *codec, hda_nid_t nid,
+                                   hda_jack_callback_fn func)
 {
-       struct hda_jack_tbl *jack = snd_hda_jack_tbl_new(codec, nid);
+       struct hda_jack_tbl *jack;
+       struct hda_jack_callback *callback = NULL;
+       int err;
+
+       jack = snd_hda_jack_tbl_new(codec, nid);
        if (!jack)
-               return -ENOMEM;
+               return ERR_PTR(-ENOMEM);
+       if (func) {
+               callback = kzalloc(sizeof(*callback), GFP_KERNEL);
+               if (!callback)
+                       return ERR_PTR(-ENOMEM);
+               callback->func = func;
+               callback->tbl = jack;
+               callback->next = jack->callback;
+               jack->callback = callback;
+       }
+
        if (jack->jack_detect)
-               return 0; /* already registered */
+               return callback; /* already registered */
        jack->jack_detect = 1;
-       if (action)
-               jack->action = action;
-       if (cb)
-               jack->callback = cb;
        if (codec->jackpoll_interval > 0)
-               return 0; /* No unsol if we're polling instead */
-       return snd_hda_codec_write_cache(codec, nid, 0,
+               return callback; /* No unsol if we're polling instead */
+       err = snd_hda_codec_write_cache(codec, nid, 0,
                                         AC_VERB_SET_UNSOLICITED_ENABLE,
                                         AC_USRSP_EN | jack->tag);
+       if (err < 0)
+               return ERR_PTR(err);
+       return callback;
 }
 EXPORT_SYMBOL_GPL(snd_hda_jack_detect_enable_callback);
 
-int snd_hda_jack_detect_enable(struct hda_codec *codec, hda_nid_t nid,
-                              unsigned char action)
+int snd_hda_jack_detect_enable(struct hda_codec *codec, hda_nid_t nid)
 {
-       return snd_hda_jack_detect_enable_callback(codec, nid, action, NULL);
+       return PTR_ERR_OR_ZERO(snd_hda_jack_detect_enable_callback(codec, nid, NULL));
 }
 EXPORT_SYMBOL_GPL(snd_hda_jack_detect_enable);
 
@@ -431,7 +450,7 @@ static int add_jack_kctl(struct hda_codec *codec, hda_nid_t nid,
                return err;
 
        if (!phantom_jack)
-               return snd_hda_jack_detect_enable(codec, nid, 0);
+               return snd_hda_jack_detect_enable(codec, nid);
        return 0;
 }
 
@@ -498,13 +517,17 @@ EXPORT_SYMBOL_GPL(snd_hda_jack_add_kctls);
 static void call_jack_callback(struct hda_codec *codec,
                               struct hda_jack_tbl *jack)
 {
-       if (jack->callback)
-               jack->callback(codec, jack);
+       struct hda_jack_callback *cb;
+
+       for (cb = jack->callback; cb; cb = cb->next)
+               cb->func(codec, cb);
        if (jack->gated_jack) {
                struct hda_jack_tbl *gated =
                        snd_hda_jack_tbl_get(codec, jack->gated_jack);
-               if (gated && gated->callback)
-                       gated->callback(codec, gated);
+               if (gated) {
+                       for (cb = gated->callback; cb; cb = cb->next)
+                               cb->func(codec, cb);
+               }
        }
 }
 
index 46e1ea83ce3c208da42afb98e8668ae3b48e8591..13cb375454f665218517cc8b3456ff2e1beb808c 100644 (file)
 #ifndef __SOUND_HDA_JACK_H
 #define __SOUND_HDA_JACK_H
 
+#include <linux/err.h>
+
 struct auto_pin_cfg;
 struct hda_jack_tbl;
+struct hda_jack_callback;
+
+typedef void (*hda_jack_callback_fn) (struct hda_codec *, struct hda_jack_callback *);
 
-typedef void (*hda_jack_callback) (struct hda_codec *, struct hda_jack_tbl *);
+struct hda_jack_callback {
+       struct hda_jack_tbl *tbl;
+       hda_jack_callback_fn func;
+       unsigned int private_data;      /* arbitrary data */
+       struct hda_jack_callback *next;
+};
 
 struct hda_jack_tbl {
        hda_nid_t nid;
-       unsigned char action;           /* event action (0 = none) */
        unsigned char tag;              /* unsol event tag */
-       unsigned int private_data;      /* arbitrary data */
-       hda_jack_callback callback;
+       struct hda_jack_callback *callback;
        /* jack-detection stuff */
        unsigned int pin_sense;         /* cached pin-sense value */
        unsigned int jack_detect:1;     /* capable of jack-detection? */
@@ -43,34 +51,14 @@ snd_hda_jack_tbl_get(struct hda_codec *codec, hda_nid_t nid);
 struct hda_jack_tbl *
 snd_hda_jack_tbl_get_from_tag(struct hda_codec *codec, unsigned char tag);
 
-struct hda_jack_tbl *
-snd_hda_jack_tbl_new(struct hda_codec *codec, hda_nid_t nid);
 void snd_hda_jack_tbl_clear(struct hda_codec *codec);
 
-/**
- * snd_hda_jack_get_action - get jack-tbl entry for the tag
- *
- * Call this from the unsol event handler to get the assigned action for the
- * event.  This will mark the dirty flag for the later reporting, too.
- */
-static inline unsigned char
-snd_hda_jack_get_action(struct hda_codec *codec, unsigned int tag)
-{
-       struct hda_jack_tbl *jack = snd_hda_jack_tbl_get_from_tag(codec, tag);
-       if (jack) {
-               jack->jack_dirty = 1;
-               return jack->action;
-       }
-       return 0;
-}
-
 void snd_hda_jack_set_dirty_all(struct hda_codec *codec);
 
-int snd_hda_jack_detect_enable(struct hda_codec *codec, hda_nid_t nid,
-                              unsigned char action);
-int snd_hda_jack_detect_enable_callback(struct hda_codec *codec, hda_nid_t nid,
-                                       unsigned char action,
-                                       hda_jack_callback cb);
+int snd_hda_jack_detect_enable(struct hda_codec *codec, hda_nid_t nid);
+struct hda_jack_callback *
+snd_hda_jack_detect_enable_callback(struct hda_codec *codec, hda_nid_t nid,
+                                   hda_jack_callback_fn cb);
 
 int snd_hda_jack_set_gating_jack(struct hda_codec *codec, hda_nid_t gated_nid,
                                 hda_nid_t gating_nid);
index 364bb413e02aa9d934bd970f1c4a0d0bd5c61be5..7eb44e78e141fcd0bcb98d2e9ce3358f9c4c80ae 100644 (file)
@@ -371,12 +371,6 @@ void snd_print_pcm_bits(int pcm, char *buf, int buflen);
 /*
  * Misc
  */
-int snd_hda_check_board_config(struct hda_codec *codec, int num_configs,
-                              const char * const *modelnames,
-                              const struct snd_pci_quirk *pci_list);
-int snd_hda_check_board_codec_sid_config(struct hda_codec *codec,
-                               int num_configs, const char * const *models,
-                               const struct snd_pci_quirk *tbl);
 int snd_hda_add_new_ctls(struct hda_codec *codec,
                         const struct snd_kcontrol_new *knew);
 
@@ -609,6 +603,14 @@ int snd_hda_override_amp_caps(struct hda_codec *codec, hda_nid_t nid, int dir,
 u32 snd_hda_query_pin_caps(struct hda_codec *codec, hda_nid_t nid);
 int snd_hda_override_pin_caps(struct hda_codec *codec, hda_nid_t nid,
                              unsigned int caps);
+bool snd_hda_check_amp_caps(struct hda_codec *codec, hda_nid_t nid,
+                          int dir, unsigned int bits);
+
+#define nid_has_mute(codec, nid, dir) \
+       snd_hda_check_amp_caps(codec, nid, dir, (AC_AMPCAP_MUTE | AC_AMPCAP_MIN_MUTE))
+#define nid_has_volume(codec, nid, dir) \
+       snd_hda_check_amp_caps(codec, nid, dir, AC_AMPCAP_NUM_STEPS)
+
 
 /* flags for hda_nid_item */
 #define HDA_NID_ITEM_AMP       (1<<0)
index e2079090ca6f479ee04c3cd67f4d281165651481..9b49f156a12e6b424432909237694e624757ee24 100644 (file)
@@ -514,7 +514,7 @@ enum {
 
 static inline int strmatch(const char *a, const char *b)
 {
-       return strnicmp(a, b, strlen(b)) == 0;
+       return strncasecmp(a, b, strlen(b)) == 0;
 }
 
 /* parse the contents after the line "[codec]"
index 5d8455e2dacd709c308d215a44155134e15319cd..4f7ffa8c4a0db610f3bc20d570afe7d8770fe3de 100644 (file)
@@ -3224,8 +3224,14 @@ static void ca0132_unsol_hp_delayed(struct work_struct *work)
 {
        struct ca0132_spec *spec = container_of(
                to_delayed_work(work), struct ca0132_spec, unsol_hp_work);
+       struct hda_jack_tbl *jack;
+
        ca0132_select_out(spec->codec);
-       snd_hda_jack_report_sync(spec->codec);
+       jack = snd_hda_jack_tbl_get(spec->codec, UNSOL_TAG_HP);
+       if (jack) {
+               jack->block_report = 0;
+               snd_hda_jack_report_sync(spec->codec);
+       }
 }
 
 static void ca0132_set_dmic(struct hda_codec *codec, int enable);
@@ -4114,12 +4120,6 @@ static void init_input(struct hda_codec *codec, hda_nid_t pin, hda_nid_t adc)
        }
 }
 
-static void ca0132_init_unsol(struct hda_codec *codec)
-{
-       snd_hda_jack_detect_enable(codec, UNSOL_TAG_HP, UNSOL_TAG_HP);
-       snd_hda_jack_detect_enable(codec, UNSOL_TAG_AMIC1, UNSOL_TAG_AMIC1);
-}
-
 static void refresh_amp_caps(struct hda_codec *codec, hda_nid_t nid, int dir)
 {
        unsigned int caps;
@@ -4390,7 +4390,8 @@ static void ca0132_download_dsp(struct hda_codec *codec)
                ca0132_set_dsp_msr(codec, true);
 }
 
-static void ca0132_process_dsp_response(struct hda_codec *codec)
+static void ca0132_process_dsp_response(struct hda_codec *codec,
+                                       struct hda_jack_callback *callback)
 {
        struct ca0132_spec *spec = codec->spec;
 
@@ -4403,36 +4404,31 @@ static void ca0132_process_dsp_response(struct hda_codec *codec)
        dspio_clear_response_queue(codec);
 }
 
-static void ca0132_unsol_event(struct hda_codec *codec, unsigned int res)
+static void hp_callback(struct hda_codec *codec, struct hda_jack_callback *cb)
 {
        struct ca0132_spec *spec = codec->spec;
 
-       if (((res >> AC_UNSOL_RES_TAG_SHIFT) & 0x3f) == UNSOL_TAG_DSP) {
-               ca0132_process_dsp_response(codec);
-       } else {
-               res = snd_hda_jack_get_action(codec,
-                               (res >> AC_UNSOL_RES_TAG_SHIFT) & 0x3f);
-
-               codec_dbg(codec, "snd_hda_jack_get_action: 0x%x\n", res);
-
-               switch (res) {
-               case UNSOL_TAG_HP:
-                       /* Delay enabling the HP amp, to let the mic-detection
-                        * state machine run.
-                        */
-                       cancel_delayed_work_sync(&spec->unsol_hp_work);
-                       queue_delayed_work(codec->bus->workq,
-                                          &spec->unsol_hp_work,
-                                          msecs_to_jiffies(500));
-                       break;
-               case UNSOL_TAG_AMIC1:
-                       ca0132_select_mic(codec);
-                       snd_hda_jack_report_sync(codec);
-                       break;
-               default:
-                       break;
-               }
-       }
+       /* Delay enabling the HP amp, to let the mic-detection
+        * state machine run.
+        */
+       cancel_delayed_work_sync(&spec->unsol_hp_work);
+       queue_delayed_work(codec->bus->workq, &spec->unsol_hp_work,
+                          msecs_to_jiffies(500));
+       cb->tbl->block_report = 1;
+}
+
+static void amic_callback(struct hda_codec *codec, struct hda_jack_callback *cb)
+{
+       ca0132_select_mic(codec);
+}
+
+static void ca0132_init_unsol(struct hda_codec *codec)
+{
+       snd_hda_jack_detect_enable_callback(codec, UNSOL_TAG_HP, hp_callback);
+       snd_hda_jack_detect_enable_callback(codec, UNSOL_TAG_AMIC1,
+                                           amic_callback);
+       snd_hda_jack_detect_enable_callback(codec, UNSOL_TAG_DSP,
+                                           ca0132_process_dsp_response);
 }
 
 /*
@@ -4443,8 +4439,6 @@ static void ca0132_unsol_event(struct hda_codec *codec, unsigned int res)
 static struct hda_verb ca0132_base_init_verbs[] = {
        /*enable ct extension*/
        {0x15, VENDOR_CHIPIO_CT_EXTENSIONS_ENABLE, 0x1},
-       /*enable DSP node unsol, needed for DSP download*/
-       {0x16, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | UNSOL_TAG_DSP},
        {}
 };
 
@@ -4561,6 +4555,8 @@ static int ca0132_init(struct hda_codec *codec)
 
        snd_hda_power_up(codec);
 
+       ca0132_init_unsol(codec);
+
        ca0132_init_params(codec);
        ca0132_init_flags(codec);
        snd_hda_sequence_write(codec, spec->base_init_verbs);
@@ -4583,8 +4579,6 @@ static int ca0132_init(struct hda_codec *codec)
        for (i = 0; i < spec->num_init_verbs; i++)
                snd_hda_sequence_write(codec, spec->init_verbs[i]);
 
-       ca0132_init_unsol(codec);
-
        ca0132_select_out(codec);
        ca0132_select_mic(codec);
 
@@ -4612,7 +4606,7 @@ static struct hda_codec_ops ca0132_patch_ops = {
        .build_pcms = ca0132_build_pcms,
        .init = ca0132_init,
        .free = ca0132_free,
-       .unsol_event = ca0132_unsol_event,
+       .unsol_event = snd_hda_jack_unsol_event,
 };
 
 static void ca0132_config(struct hda_codec *codec)
index 3db724eaa53c1e154cb550b52bb0e245b2eca2e4..1589c9bcce3e15a230f87d352f2ae165252c358d 100644 (file)
@@ -135,8 +135,6 @@ enum {
 #define CS421X_IDX_DAC_CFG     0x03
 #define CS421X_IDX_SPK_CTL     0x04
 
-#define SPDIF_EVENT            0x04
-
 /* Cirrus Logic CS4213 is like CS4210 but does not have SPDIF input/output */
 #define CS4213_VENDOR_NID      0x09
 
@@ -984,7 +982,7 @@ static void cs4210_pinmux_init(struct hda_codec *codec)
 }
 
 static void cs4210_spdif_automute(struct hda_codec *codec,
-                                 struct hda_jack_tbl *tbl)
+                                 struct hda_jack_callback *tbl)
 {
        struct cs_spec *spec = codec->spec;
        bool spdif_present = false;
@@ -1019,7 +1017,6 @@ static void parse_cs421x_digital(struct hda_codec *codec)
                if (get_wcaps(codec, nid) & AC_WCAP_UNSOL_CAP) {
                        spec->spdif_detect = 1;
                        snd_hda_jack_detect_enable_callback(codec, nid,
-                                                           SPDIF_EVENT,
                                                            cs4210_spdif_automute);
                }
        }
index 47ccb8f44adb7ab5e0353a17cd0e68c2e1c363f0..71e4bad06345c856fcfb80e9e75578d444db117e 100644 (file)
@@ -26,7 +26,6 @@
 #include <linux/module.h>
 #include <sound/core.h>
 #include <sound/jack.h>
-#include <sound/tlv.h>
 
 #include "hda_codec.h"
 #include "hda_local.h"
@@ -394,7 +393,8 @@ static void olpc_xo_update_mic_pins(struct hda_codec *codec)
 }
 
 /* mic_autoswitch hook */
-static void olpc_xo_automic(struct hda_codec *codec, struct hda_jack_tbl *jack)
+static void olpc_xo_automic(struct hda_codec *codec,
+                           struct hda_jack_callback *jack)
 {
        struct conexant_spec *spec = codec->spec;
        int saved_cached_write = codec->cached_write;
@@ -752,6 +752,7 @@ static const struct hda_model_fixup cxt5051_fixup_models[] = {
 static const struct snd_pci_quirk cxt5066_fixups[] = {
        SND_PCI_QUIRK(0x1025, 0x0543, "Acer Aspire One 522", CXT_FIXUP_STEREO_DMIC),
        SND_PCI_QUIRK(0x1025, 0x054c, "Acer Aspire 3830TG", CXT_FIXUP_ASPIRE_DMIC),
+       SND_PCI_QUIRK(0x1025, 0x054f, "Acer Aspire 4830T", CXT_FIXUP_ASPIRE_DMIC),
        SND_PCI_QUIRK(0x1043, 0x138d, "Asus", CXT_FIXUP_HEADPHONE_MIC_PIN),
        SND_PCI_QUIRK(0x152d, 0x0833, "OLPC XO-1.5", CXT_FIXUP_OLPC_XO),
        SND_PCI_QUIRK(0x17aa, 0x20f2, "Lenovo T400", CXT_PINCFG_LENOVO_TP410),
@@ -787,6 +788,7 @@ static const struct hda_model_fixup cxt5066_fixup_models[] = {
  */
 static void add_cx5051_fake_mutes(struct hda_codec *codec)
 {
+       struct conexant_spec *spec = codec->spec;
        static hda_nid_t out_nids[] = {
                0x10, 0x11, 0
        };
@@ -796,6 +798,7 @@ static void add_cx5051_fake_mutes(struct hda_codec *codec)
                snd_hda_override_amp_caps(codec, *p, HDA_OUTPUT,
                                          AC_AMPCAP_MIN_MUTE |
                                          query_amp_caps(codec, *p, HDA_OUTPUT));
+       spec->gen.dac_min_mute = true;
 }
 
 static int patch_conexant_auto(struct hda_codec *codec)
@@ -868,11 +871,6 @@ static int patch_conexant_auto(struct hda_codec *codec)
        if (err < 0)
                goto error;
 
-       if (codec->vendor_id == 0x14f15051) {
-               /* minimum value is actually mute */
-               spec->gen.vmaster_tlv[3] |= TLV_DB_SCALE_MUTE;
-       }
-
        codec->patch_ops = cx_auto_patch_ops;
 
        /* Some laptops with Conexant chips show stalls in S3 resume,
index 99d7d7fecaad09934090eb6575cfb43131f2dfb4..39862e98551c41466505ee7b1764496e04799880 100644 (file)
@@ -1163,17 +1163,23 @@ static void hdmi_setup_audio_infoframe(struct hda_codec *codec,
 
 static bool hdmi_present_sense(struct hdmi_spec_per_pin *per_pin, int repoll);
 
-static void jack_callback(struct hda_codec *codec, struct hda_jack_tbl *jack)
+static void check_presence_and_report(struct hda_codec *codec, hda_nid_t nid)
 {
        struct hdmi_spec *spec = codec->spec;
-       int pin_idx = pin_nid_to_pin_index(codec, jack->nid);
+       int pin_idx = pin_nid_to_pin_index(codec, nid);
+
        if (pin_idx < 0)
                return;
-
        if (hdmi_present_sense(get_pin(spec, pin_idx), 1))
                snd_hda_jack_report_sync(codec);
 }
 
+static void jack_callback(struct hda_codec *codec,
+                         struct hda_jack_callback *jack)
+{
+       check_presence_and_report(codec, jack->tbl->nid);
+}
+
 static void hdmi_intrinsic_event(struct hda_codec *codec, unsigned int res)
 {
        int tag = res >> AC_UNSOL_RES_TAG_SHIFT;
@@ -1190,7 +1196,7 @@ static void hdmi_intrinsic_event(struct hda_codec *codec, unsigned int res)
                codec->addr, jack->nid, dev_entry, !!(res & AC_UNSOL_RES_IA),
                !!(res & AC_UNSOL_RES_PD), !!(res & AC_UNSOL_RES_ELDV));
 
-       jack_callback(codec, jack);
+       check_presence_and_report(codec, jack->nid);
 }
 
 static void hdmi_non_intrinsic_event(struct hda_codec *codec, unsigned int res)
@@ -2165,7 +2171,7 @@ static int generic_hdmi_init(struct hda_codec *codec)
                hda_nid_t pin_nid = per_pin->pin_nid;
 
                hdmi_init_pin(codec, pin_nid);
-               snd_hda_jack_detect_enable_callback(codec, pin_nid, pin_nid,
+               snd_hda_jack_detect_enable_callback(codec, pin_nid,
                        codec->jackpoll_interval > 0 ? jack_callback : NULL);
        }
        return 0;
@@ -2428,7 +2434,7 @@ static int simple_playback_init(struct hda_codec *codec)
        if (get_wcaps(codec, pin) & AC_WCAP_OUT_AMP)
                snd_hda_codec_write(codec, pin, 0, AC_VERB_SET_AMP_GAIN_MUTE,
                                    AMP_OUT_UNMUTE);
-       snd_hda_jack_detect_enable(codec, pin, pin);
+       snd_hda_jack_detect_enable(codec, pin);
        return 0;
 }
 
index 1ba22fb527c288b751d3064e041759e881013605..bc86c36b4bfa39b383f113b5dbd377b0c8ffd22d 100644 (file)
@@ -40,9 +40,6 @@
 /* keep halting ALC5505 DSP, for power saving */
 #define HALT_REALTEK_ALC5505
 
-/* unsol event tags */
-#define ALC_DCVOL_EVENT                0x08
-
 /* for GPIO Poll */
 #define GPIO_MASK      0x03
 
@@ -93,11 +90,6 @@ struct alc_spec {
        struct alc_customize_define cdefine;
        unsigned int parse_flags; /* flag for snd_hda_parse_pin_defcfg() */
 
-       /* inverted dmic fix */
-       unsigned int inv_dmic_fixup:1; /* has inverted digital-mic workaround */
-       unsigned int inv_dmic_muted:1; /* R-ch of inv d-mic is muted? */
-       hda_nid_t inv_dmic_pin;
-
        /* mute LED for HP laptops, see alc269_fixup_mic_mute_hook() */
        int mute_led_polarity;
        hda_nid_t mute_led_nid;
@@ -128,6 +120,83 @@ struct alc_spec {
        unsigned int coef0;
 };
 
+/*
+ * COEF access helper functions
+ */
+
+static int alc_read_coefex_idx(struct hda_codec *codec, hda_nid_t nid,
+                              unsigned int coef_idx)
+{
+       unsigned int val;
+
+       snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_COEF_INDEX, coef_idx);
+       val = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_PROC_COEF, 0);
+       return val;
+}
+
+#define alc_read_coef_idx(codec, coef_idx) \
+       alc_read_coefex_idx(codec, 0x20, coef_idx)
+
+static void alc_write_coefex_idx(struct hda_codec *codec, hda_nid_t nid,
+                                unsigned int coef_idx, unsigned int coef_val)
+{
+       snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_COEF_INDEX, coef_idx);
+       snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PROC_COEF, coef_val);
+}
+
+#define alc_write_coef_idx(codec, coef_idx, coef_val) \
+       alc_write_coefex_idx(codec, 0x20, coef_idx, coef_val)
+
+static void alc_update_coefex_idx(struct hda_codec *codec, hda_nid_t nid,
+                                 unsigned int coef_idx, unsigned int mask,
+                                 unsigned int bits_set)
+{
+       unsigned int val = alc_read_coefex_idx(codec, nid, coef_idx);
+
+       if (val != -1)
+               alc_write_coefex_idx(codec, nid, coef_idx,
+                                    (val & ~mask) | bits_set);
+}
+
+#define alc_update_coef_idx(codec, coef_idx, mask, bits_set)   \
+       alc_update_coefex_idx(codec, 0x20, coef_idx, mask, bits_set)
+
+/* a special bypass for COEF 0; read the cached value at the second time */
+static unsigned int alc_get_coef0(struct hda_codec *codec)
+{
+       struct alc_spec *spec = codec->spec;
+
+       if (!spec->coef0)
+               spec->coef0 = alc_read_coef_idx(codec, 0);
+       return spec->coef0;
+}
+
+/* coef writes/updates batch */
+struct coef_fw {
+       unsigned char nid;
+       unsigned char idx;
+       unsigned short mask;
+       unsigned short val;
+};
+
+#define UPDATE_COEFEX(_nid, _idx, _mask, _val) \
+       { .nid = (_nid), .idx = (_idx), .mask = (_mask), .val = (_val) }
+#define WRITE_COEFEX(_nid, _idx, _val) UPDATE_COEFEX(_nid, _idx, -1, _val)
+#define WRITE_COEF(_idx, _val) WRITE_COEFEX(0x20, _idx, _val)
+#define UPDATE_COEF(_idx, _mask, _val) UPDATE_COEFEX(0x20, _idx, _mask, _val)
+
+static void alc_process_coef_fw(struct hda_codec *codec,
+                               const struct coef_fw *fw)
+{
+       for (; fw->nid; fw++) {
+               if (fw->mask == (unsigned short)-1)
+                       alc_write_coefex_idx(codec, fw->nid, fw->idx, fw->val);
+               else
+                       alc_update_coefex_idx(codec, fw->nid, fw->idx,
+                                             fw->mask, fw->val);
+       }
+}
+
 /*
  * Append the given mixer and verb elements for the later use
  * The mixer array is referred in build_controls(), and init_verbs are
@@ -173,20 +242,10 @@ static const struct hda_verb alc_gpio3_init_verbs[] = {
 static void alc_fix_pll(struct hda_codec *codec)
 {
        struct alc_spec *spec = codec->spec;
-       unsigned int val;
 
-       if (!spec->pll_nid)
-               return;
-       snd_hda_codec_write(codec, spec->pll_nid, 0, AC_VERB_SET_COEF_INDEX,
-                           spec->pll_coef_idx);
-       val = snd_hda_codec_read(codec, spec->pll_nid, 0,
-                                AC_VERB_GET_PROC_COEF, 0);
-       if (val == -1)
-               return;
-       snd_hda_codec_write(codec, spec->pll_nid, 0, AC_VERB_SET_COEF_INDEX,
-                           spec->pll_coef_idx);
-       snd_hda_codec_write(codec, spec->pll_nid, 0, AC_VERB_SET_PROC_COEF,
-                           val & ~(1 << spec->pll_coef_bit));
+       if (spec->pll_nid)
+               alc_update_coefex_idx(codec, spec->pll_nid, spec->pll_coef_idx,
+                                     1 << spec->pll_coef_bit, 0);
 }
 
 static void alc_fix_pll_init(struct hda_codec *codec, hda_nid_t nid,
@@ -200,7 +259,8 @@ static void alc_fix_pll_init(struct hda_codec *codec, hda_nid_t nid,
 }
 
 /* update the master volume per volume-knob's unsol event */
-static void alc_update_knob_master(struct hda_codec *codec, struct hda_jack_tbl *jack)
+static void alc_update_knob_master(struct hda_codec *codec,
+                                  struct hda_jack_callback *jack)
 {
        unsigned int val;
        struct snd_kcontrol *kctl;
@@ -212,7 +272,7 @@ static void alc_update_knob_master(struct hda_codec *codec, struct hda_jack_tbl
        uctl = kzalloc(sizeof(*uctl), GFP_KERNEL);
        if (!uctl)
                return;
-       val = snd_hda_codec_read(codec, jack->nid, 0,
+       val = snd_hda_codec_read(codec, jack->tbl->nid, 0,
                                 AC_VERB_GET_VOLUME_KNOB_CONTROL, 0);
        val &= HDA_AMP_VOLMASK;
        uctl->value.integer.value[0] = val;
@@ -231,30 +291,18 @@ static void alc880_unsol_event(struct hda_codec *codec, unsigned int res)
 /* additional initialization for ALC888 variants */
 static void alc888_coef_init(struct hda_codec *codec)
 {
-       unsigned int tmp;
-
-       snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_COEF_INDEX, 0);
-       tmp = snd_hda_codec_read(codec, 0x20, 0, AC_VERB_GET_PROC_COEF, 0);
-       snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_COEF_INDEX, 7);
-       if ((tmp & 0xf0) == 0x20)
+       if (alc_get_coef0(codec) == 0x20)
                /* alc888S-VC */
-               snd_hda_codec_read(codec, 0x20, 0,
-                                  AC_VERB_SET_PROC_COEF, 0x830);
+               alc_write_coef_idx(codec, 7, 0x830);
         else
                 /* alc888-VB */
-                snd_hda_codec_read(codec, 0x20, 0,
-                                   AC_VERB_SET_PROC_COEF, 0x3030);
+               alc_write_coef_idx(codec, 7, 0x3030);
 }
 
 /* additional initialization for ALC889 variants */
 static void alc889_coef_init(struct hda_codec *codec)
 {
-       unsigned int tmp;
-
-       snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_COEF_INDEX, 7);
-       tmp = snd_hda_codec_read(codec, 0x20, 0, AC_VERB_GET_PROC_COEF, 0);
-       snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_COEF_INDEX, 7);
-       snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_PROC_COEF, tmp|0x2010);
+       alc_update_coef_idx(codec, 7, 0, 0x2010);
 }
 
 /* turn on/off EAPD control (only if available) */
@@ -295,8 +343,6 @@ static void alc_eapd_shutup(struct hda_codec *codec)
 /* generic EAPD initialization */
 static void alc_auto_init_amp(struct hda_codec *codec, int type)
 {
-       unsigned int tmp;
-
        alc_auto_setup_eapd(codec, true);
        switch (type) {
        case ALC_INIT_GPIO1:
@@ -311,15 +357,7 @@ static void alc_auto_init_amp(struct hda_codec *codec, int type)
        case ALC_INIT_DEFAULT:
                switch (codec->vendor_id) {
                case 0x10ec0260:
-                       snd_hda_codec_write(codec, 0x1a, 0,
-                                           AC_VERB_SET_COEF_INDEX, 7);
-                       tmp = snd_hda_codec_read(codec, 0x1a, 0,
-                                                AC_VERB_GET_PROC_COEF, 0);
-                       snd_hda_codec_write(codec, 0x1a, 0,
-                                           AC_VERB_SET_COEF_INDEX, 7);
-                       snd_hda_codec_write(codec, 0x1a, 0,
-                                           AC_VERB_SET_PROC_COEF,
-                                           tmp | 0x2010);
+                       alc_update_coefex_idx(codec, 0x1a, 7, 0, 0x2010);
                        break;
                case 0x10ec0262:
                case 0x10ec0880:
@@ -337,15 +375,7 @@ static void alc_auto_init_amp(struct hda_codec *codec, int type)
 #if 0 /* XXX: This may cause the silent output on speaker on some machines */
                case 0x10ec0267:
                case 0x10ec0268:
-                       snd_hda_codec_write(codec, 0x20, 0,
-                                           AC_VERB_SET_COEF_INDEX, 7);
-                       tmp = snd_hda_codec_read(codec, 0x20, 0,
-                                                AC_VERB_GET_PROC_COEF, 0);
-                       snd_hda_codec_write(codec, 0x20, 0,
-                                           AC_VERB_SET_COEF_INDEX, 7);
-                       snd_hda_codec_write(codec, 0x20, 0,
-                                           AC_VERB_SET_PROC_COEF,
-                                           tmp | 0x3000);
+                       alc_update_coef_idx(codec, 7, 0, 0x3000);
                        break;
 #endif /* XXX */
                }
@@ -587,191 +617,15 @@ static void alc_ssid_check(struct hda_codec *codec, const hda_nid_t *ports)
        }
 }
 
-/*
- * COEF access helper functions
- */
-
-static int alc_read_coefex_idx(struct hda_codec *codec,
-                                       hda_nid_t nid,
-                                       unsigned int coef_idx)
-{
-       unsigned int val;
-       snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_COEF_INDEX,
-                               coef_idx);
-       val = snd_hda_codec_read(codec, nid, 0,
-                               AC_VERB_GET_PROC_COEF, 0);
-       return val;
-}
-
-#define alc_read_coef_idx(codec, coef_idx) \
-       alc_read_coefex_idx(codec, 0x20, coef_idx)
-
-static void alc_write_coefex_idx(struct hda_codec *codec, hda_nid_t nid,
-                                                       unsigned int coef_idx,
-                                                       unsigned int coef_val)
-{
-       snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_COEF_INDEX,
-                           coef_idx);
-       snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PROC_COEF,
-                           coef_val);
-}
-
-#define alc_write_coef_idx(codec, coef_idx, coef_val) \
-       alc_write_coefex_idx(codec, 0x20, coef_idx, coef_val)
-
-/* a special bypass for COEF 0; read the cached value at the second time */
-static unsigned int alc_get_coef0(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-       if (!spec->coef0)
-               spec->coef0 = alc_read_coef_idx(codec, 0);
-       return spec->coef0;
-}
-
 /*
  */
 
-static hda_nid_t get_adc_nid(struct hda_codec *codec, int adc_idx, int imux_idx)
-{
-       struct hda_gen_spec *spec = codec->spec;
-       if (spec->dyn_adc_switch)
-               adc_idx = spec->dyn_adc_idx[imux_idx];
-       return spec->adc_nids[adc_idx];
-}
-
-static void alc_inv_dmic_sync_adc(struct hda_codec *codec, int adc_idx)
-{
-       struct alc_spec *spec = codec->spec;
-       struct hda_input_mux *imux = &spec->gen.input_mux;
-       struct nid_path *path;
-       hda_nid_t nid;
-       int i, dir, parm;
-       unsigned int val;
-
-       for (i = 0; i < imux->num_items; i++) {
-               if (spec->gen.imux_pins[i] == spec->inv_dmic_pin)
-                       break;
-       }
-       if (i >= imux->num_items)
-               return;
-
-       path = snd_hda_get_nid_path(codec, spec->inv_dmic_pin,
-                                   get_adc_nid(codec, adc_idx, i));
-       val = path->ctls[NID_PATH_MUTE_CTL];
-       if (!val)
-               return;
-       nid = get_amp_nid_(val);
-       dir = get_amp_direction_(val);
-       parm = AC_AMP_SET_RIGHT |
-               (dir == HDA_OUTPUT ? AC_AMP_SET_OUTPUT : AC_AMP_SET_INPUT);
-
-       /* flush all cached amps at first */
-       snd_hda_codec_flush_cache(codec);
-
-       /* we care only right channel */
-       val = snd_hda_codec_amp_read(codec, nid, 1, dir, 0);
-       if (val & 0x80) /* if already muted, we don't need to touch */
-               return;
-       val |= 0x80;
-       snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE,
-                           parm | val);
-}
-
-/*
- * Inverted digital-mic handling
- *
- * First off, it's a bit tricky.  The "Inverted Internal Mic Capture Switch"
- * gives the additional mute only to the right channel of the digital mic
- * capture stream.  This is a workaround for avoiding the almost silence
- * by summing the stereo stream from some (known to be ForteMedia)
- * digital mic unit.
- *
- * The logic is to call alc_inv_dmic_sync() after each action (possibly)
- * modifying ADC amp.  When the mute flag is set, it mutes the R-channel
- * without caching so that the cache can still keep the original value.
- * The cached value is then restored when the flag is set off or any other
- * than d-mic is used as the current input source.
- */
-static void alc_inv_dmic_sync(struct hda_codec *codec, bool force)
-{
-       struct alc_spec *spec = codec->spec;
-       int src, nums;
-
-       if (!spec->inv_dmic_fixup)
-               return;
-       if (!spec->inv_dmic_muted && !force)
-               return;
-       nums = spec->gen.dyn_adc_switch ? 1 : spec->gen.num_adc_nids;
-       for (src = 0; src < nums; src++) {
-               bool dmic_fixup = false;
-
-               if (spec->inv_dmic_muted &&
-                   spec->gen.imux_pins[spec->gen.cur_mux[src]] == spec->inv_dmic_pin)
-                       dmic_fixup = true;
-               if (!dmic_fixup && !force)
-                       continue;
-               alc_inv_dmic_sync_adc(codec, src);
-       }
-}
-
-static void alc_inv_dmic_hook(struct hda_codec *codec,
-                             struct snd_kcontrol *kcontrol,
-                             struct snd_ctl_elem_value *ucontrol)
-{
-       alc_inv_dmic_sync(codec, false);
-}
-
-static int alc_inv_dmic_sw_get(struct snd_kcontrol *kcontrol,
-                              struct snd_ctl_elem_value *ucontrol)
-{
-       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-       struct alc_spec *spec = codec->spec;
-
-       ucontrol->value.integer.value[0] = !spec->inv_dmic_muted;
-       return 0;
-}
-
-static int alc_inv_dmic_sw_put(struct snd_kcontrol *kcontrol,
-                              struct snd_ctl_elem_value *ucontrol)
-{
-       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-       struct alc_spec *spec = codec->spec;
-       unsigned int val = !ucontrol->value.integer.value[0];
-
-       if (val == spec->inv_dmic_muted)
-               return 0;
-       spec->inv_dmic_muted = val;
-       alc_inv_dmic_sync(codec, true);
-       return 0;
-}
-
-static const struct snd_kcontrol_new alc_inv_dmic_sw = {
-       .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-       .name = "Inverted Internal Mic Capture Switch",
-       .info = snd_ctl_boolean_mono_info,
-       .get = alc_inv_dmic_sw_get,
-       .put = alc_inv_dmic_sw_put,
-};
-
-static int alc_add_inv_dmic_mixer(struct hda_codec *codec, hda_nid_t nid)
+static void alc_fixup_inv_dmic(struct hda_codec *codec,
+                              const struct hda_fixup *fix, int action)
 {
        struct alc_spec *spec = codec->spec;
 
-       if (!snd_hda_gen_add_kctl(&spec->gen, NULL, &alc_inv_dmic_sw))
-               return -ENOMEM;
-       spec->inv_dmic_fixup = 1;
-       spec->inv_dmic_muted = 0;
-       spec->inv_dmic_pin = nid;
-       spec->gen.cap_sync_hook = alc_inv_dmic_hook;
-       return 0;
-}
-
-/* typically the digital mic is put at node 0x12 */
-static void alc_fixup_inv_dmic_0x12(struct hda_codec *codec,
-                                   const struct hda_fixup *fix, int action)
-{
-       if (action == HDA_FIXUP_ACT_PROBE)
-               alc_add_inv_dmic_mixer(codec, 0x12);
+       spec->gen.inv_dmic_split = 1;
 }
 
 
@@ -880,7 +734,6 @@ static int alc_resume(struct hda_codec *codec)
        codec->patch_ops.init(codec);
        snd_hda_codec_resume_amp(codec);
        snd_hda_codec_resume_cache(codec);
-       alc_inv_dmic_sync(codec, true);
        hda_call_check_power_status(codec, 0x01);
        return 0;
 }
@@ -1134,7 +987,8 @@ static void alc880_fixup_vol_knob(struct hda_codec *codec,
                                  const struct hda_fixup *fix, int action)
 {
        if (action == HDA_FIXUP_ACT_PROBE)
-               snd_hda_jack_detect_enable_callback(codec, 0x21, ALC_DCVOL_EVENT, alc_update_knob_master);
+               snd_hda_jack_detect_enable_callback(codec, 0x21,
+                                                   alc_update_knob_master);
 }
 
 static const struct hda_fixup alc880_fixups[] = {
@@ -1597,7 +1451,7 @@ static void alc260_fixup_gpio1_toggle(struct hda_codec *codec,
                spec->gen.detect_hp = 1;
                spec->gen.automute_speaker = 1;
                spec->gen.autocfg.hp_pins[0] = 0x0f; /* copy it for automute */
-               snd_hda_jack_detect_enable_callback(codec, 0x0f, HDA_GEN_HP_EVENT,
+               snd_hda_jack_detect_enable_callback(codec, 0x0f,
                                                    snd_hda_gen_hp_automute);
                snd_hda_add_verbs(codec, alc_gpio1_init_verbs);
        }
@@ -2222,7 +2076,7 @@ static const struct hda_fixup alc882_fixups[] = {
        },
        [ALC882_FIXUP_INV_DMIC] = {
                .type = HDA_FIXUP_FUNC,
-               .v.func = alc_fixup_inv_dmic_0x12,
+               .v.func = alc_fixup_inv_dmic,
        },
        [ALC882_FIXUP_NO_PRIMARY_HP] = {
                .type = HDA_FIXUP_FUNC,
@@ -2473,7 +2327,7 @@ static const struct hda_fixup alc262_fixups[] = {
        },
        [ALC262_FIXUP_INV_DMIC] = {
                .type = HDA_FIXUP_FUNC,
-               .v.func = alc_fixup_inv_dmic_0x12,
+               .v.func = alc_fixup_inv_dmic,
        },
        [ALC262_FIXUP_INTEL_BAYLEYBAY] = {
                .type = HDA_FIXUP_FUNC,
@@ -2517,13 +2371,7 @@ static int patch_alc262(struct hda_codec *codec)
        /* pshou 07/11/05  set a zero PCM sample to DAC when FIFO is
         * under-run
         */
-       {
-       int tmp;
-       snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_COEF_INDEX, 7);
-       tmp = snd_hda_codec_read(codec, 0x20, 0, AC_VERB_GET_PROC_COEF, 0);
-       snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_COEF_INDEX, 7);
-       snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_PROC_COEF, tmp | 0x80);
-       }
+       alc_update_coefex_idx(codec, 0x1a, 7, 0, 0x80);
 #endif
        alc_fix_pll_init(codec, 0x20, 0x0a, 10);
 
@@ -2592,7 +2440,7 @@ enum {
 static const struct hda_fixup alc268_fixups[] = {
        [ALC268_FIXUP_INV_DMIC] = {
                .type = HDA_FIXUP_FUNC,
-               .v.func = alc_fixup_inv_dmic_0x12,
+               .v.func = alc_fixup_inv_dmic,
        },
        [ALC268_FIXUP_HP_EAPD] = {
                .type = HDA_FIXUP_VERBS,
@@ -2809,14 +2657,7 @@ static void alc286_shutup(struct hda_codec *codec)
 
 static void alc269vb_toggle_power_output(struct hda_codec *codec, int power_up)
 {
-       int val = alc_read_coef_idx(codec, 0x04);
-       if (val == -1)
-               return;
-       if (power_up)
-               val |= 1 << 11;
-       else
-               val &= ~(1 << 11);
-       alc_write_coef_idx(codec, 0x04, val);
+       alc_update_coef_idx(codec, 0x04, 1 << 11, power_up ? (1 << 11) : 0);
 }
 
 static void alc269_shutup(struct hda_codec *codec)
@@ -2832,79 +2673,42 @@ static void alc269_shutup(struct hda_codec *codec)
        snd_hda_shutup_pins(codec);
 }
 
+static struct coef_fw alc282_coefs[] = {
+       WRITE_COEF(0x03, 0x0002), /* Power Down Control */
+       WRITE_COEF(0x05, 0x0700), /* FIFO and filter clock */
+       WRITE_COEF(0x07, 0x0200), /* DMIC control */
+       UPDATE_COEF(0x06, 0x00f0, 0), /* Analog clock */
+       UPDATE_COEF(0x08, 0xfffc, 0x0c2c), /* JD */
+       WRITE_COEF(0x0a, 0xcccc), /* JD offset1 */
+       WRITE_COEF(0x0b, 0xcccc), /* JD offset2 */
+       WRITE_COEF(0x0e, 0x6e00), /* LDO1/2/3, DAC/ADC */
+       UPDATE_COEF(0x0f, 0xf800, 0x1000), /* JD */
+       UPDATE_COEF(0x10, 0xfc00, 0x0c00), /* Capless */
+       WRITE_COEF(0x6f, 0x0), /* Class D test 4 */
+       UPDATE_COEF(0x0c, 0xfe00, 0), /* IO power down directly */
+       WRITE_COEF(0x34, 0xa0c0), /* ANC */
+       UPDATE_COEF(0x16, 0x0008, 0), /* AGC MUX */
+       UPDATE_COEF(0x1d, 0x00e0, 0), /* DAC simple content protection */
+       UPDATE_COEF(0x1f, 0x00e0, 0), /* ADC simple content protection */
+       WRITE_COEF(0x21, 0x8804), /* DAC ADC Zero Detection */
+       WRITE_COEF(0x63, 0x2902), /* PLL */
+       WRITE_COEF(0x68, 0xa080), /* capless control 2 */
+       WRITE_COEF(0x69, 0x3400), /* capless control 3 */
+       WRITE_COEF(0x6a, 0x2f3e), /* capless control 4 */
+       WRITE_COEF(0x6b, 0x0), /* capless control 5 */
+       UPDATE_COEF(0x6d, 0x0fff, 0x0900), /* class D test 2 */
+       WRITE_COEF(0x6e, 0x110a), /* class D test 3 */
+       UPDATE_COEF(0x70, 0x00f8, 0x00d8), /* class D test 5 */
+       WRITE_COEF(0x71, 0x0014), /* class D test 6 */
+       WRITE_COEF(0x72, 0xc2ba), /* classD OCP */
+       UPDATE_COEF(0x77, 0x0f80, 0), /* classD pure DC test */
+       WRITE_COEF(0x6c, 0xfc06), /* Class D amp control */
+       {}
+};
+
 static void alc282_restore_default_value(struct hda_codec *codec)
 {
-       int val;
-
-       /* Power Down Control */
-       alc_write_coef_idx(codec, 0x03, 0x0002);
-       /* FIFO and filter clock */
-       alc_write_coef_idx(codec, 0x05, 0x0700);
-       /* DMIC control */
-       alc_write_coef_idx(codec, 0x07, 0x0200);
-       /* Analog clock */
-       val = alc_read_coef_idx(codec, 0x06);
-       alc_write_coef_idx(codec, 0x06, (val & ~0x00f0) | 0x0);
-       /* JD */
-       val = alc_read_coef_idx(codec, 0x08);
-       alc_write_coef_idx(codec, 0x08, (val & ~0xfffc) | 0x0c2c);
-       /* JD offset1 */
-       alc_write_coef_idx(codec, 0x0a, 0xcccc);
-       /* JD offset2 */
-       alc_write_coef_idx(codec, 0x0b, 0xcccc);
-       /* LDO1/2/3, DAC/ADC */
-       alc_write_coef_idx(codec, 0x0e, 0x6e00);
-       /* JD */
-       val = alc_read_coef_idx(codec, 0x0f);
-       alc_write_coef_idx(codec, 0x0f, (val & ~0xf800) | 0x1000);
-       /* Capless */
-       val = alc_read_coef_idx(codec, 0x10);
-       alc_write_coef_idx(codec, 0x10, (val & ~0xfc00) | 0x0c00);
-       /* Class D test 4 */
-       alc_write_coef_idx(codec, 0x6f, 0x0);
-       /* IO power down directly */
-       val = alc_read_coef_idx(codec, 0x0c);
-       alc_write_coef_idx(codec, 0x0c, (val & ~0xfe00) | 0x0);
-       /* ANC */
-       alc_write_coef_idx(codec, 0x34, 0xa0c0);
-       /* AGC MUX */
-       val = alc_read_coef_idx(codec, 0x16);
-       alc_write_coef_idx(codec, 0x16, (val & ~0x0008) | 0x0);
-       /* DAC simple content protection */
-       val = alc_read_coef_idx(codec, 0x1d);
-       alc_write_coef_idx(codec, 0x1d, (val & ~0x00e0) | 0x0);
-       /* ADC simple content protection */
-       val = alc_read_coef_idx(codec, 0x1f);
-       alc_write_coef_idx(codec, 0x1f, (val & ~0x00e0) | 0x0);
-       /* DAC ADC Zero Detection */
-       alc_write_coef_idx(codec, 0x21, 0x8804);
-       /* PLL */
-       alc_write_coef_idx(codec, 0x63, 0x2902);
-       /* capless control 2 */
-       alc_write_coef_idx(codec, 0x68, 0xa080);
-       /* capless control 3 */
-       alc_write_coef_idx(codec, 0x69, 0x3400);
-       /* capless control 4 */
-       alc_write_coef_idx(codec, 0x6a, 0x2f3e);
-       /* capless control 5 */
-       alc_write_coef_idx(codec, 0x6b, 0x0);
-       /* class D test 2 */
-       val = alc_read_coef_idx(codec, 0x6d);
-       alc_write_coef_idx(codec, 0x6d, (val & ~0x0fff) | 0x0900);
-       /* class D test 3 */
-       alc_write_coef_idx(codec, 0x6e, 0x110a);
-       /* class D test 5 */
-       val = alc_read_coef_idx(codec, 0x70);
-       alc_write_coef_idx(codec, 0x70, (val & ~0x00f8) | 0x00d8);
-       /* class D test 6 */
-       alc_write_coef_idx(codec, 0x71, 0x0014);
-       /* classD OCP */
-       alc_write_coef_idx(codec, 0x72, 0xc2ba);
-       /* classD pure DC test */
-       val = alc_read_coef_idx(codec, 0x77);
-       alc_write_coef_idx(codec, 0x77, (val & ~0x0f80) | 0x0);
-       /* Class D amp control */
-       alc_write_coef_idx(codec, 0x6c, 0xfc06);
+       alc_process_coef_fw(codec, alc282_coefs);
 }
 
 static void alc282_init(struct hda_codec *codec)
@@ -2980,87 +2784,45 @@ static void alc282_shutup(struct hda_codec *codec)
        alc_write_coef_idx(codec, 0x78, coef78);
 }
 
+static struct coef_fw alc283_coefs[] = {
+       WRITE_COEF(0x03, 0x0002), /* Power Down Control */
+       WRITE_COEF(0x05, 0x0700), /* FIFO and filter clock */
+       WRITE_COEF(0x07, 0x0200), /* DMIC control */
+       UPDATE_COEF(0x06, 0x00f0, 0), /* Analog clock */
+       UPDATE_COEF(0x08, 0xfffc, 0x0c2c), /* JD */
+       WRITE_COEF(0x0a, 0xcccc), /* JD offset1 */
+       WRITE_COEF(0x0b, 0xcccc), /* JD offset2 */
+       WRITE_COEF(0x0e, 0x6fc0), /* LDO1/2/3, DAC/ADC */
+       UPDATE_COEF(0x0f, 0xf800, 0x1000), /* JD */
+       UPDATE_COEF(0x10, 0xfc00, 0x0c00), /* Capless */
+       WRITE_COEF(0x3a, 0x0), /* Class D test 4 */
+       UPDATE_COEF(0x0c, 0xfe00, 0x0), /* IO power down directly */
+       WRITE_COEF(0x22, 0xa0c0), /* ANC */
+       UPDATE_COEFEX(0x53, 0x01, 0x000f, 0x0008), /* AGC MUX */
+       UPDATE_COEF(0x1d, 0x00e0, 0), /* DAC simple content protection */
+       UPDATE_COEF(0x1f, 0x00e0, 0), /* ADC simple content protection */
+       WRITE_COEF(0x21, 0x8804), /* DAC ADC Zero Detection */
+       WRITE_COEF(0x2e, 0x2902), /* PLL */
+       WRITE_COEF(0x33, 0xa080), /* capless control 2 */
+       WRITE_COEF(0x34, 0x3400), /* capless control 3 */
+       WRITE_COEF(0x35, 0x2f3e), /* capless control 4 */
+       WRITE_COEF(0x36, 0x0), /* capless control 5 */
+       UPDATE_COEF(0x38, 0x0fff, 0x0900), /* class D test 2 */
+       WRITE_COEF(0x39, 0x110a), /* class D test 3 */
+       UPDATE_COEF(0x3b, 0x00f8, 0x00d8), /* class D test 5 */
+       WRITE_COEF(0x3c, 0x0014), /* class D test 6 */
+       WRITE_COEF(0x3d, 0xc2ba), /* classD OCP */
+       UPDATE_COEF(0x42, 0x0f80, 0x0), /* classD pure DC test */
+       WRITE_COEF(0x49, 0x0), /* test mode */
+       UPDATE_COEF(0x40, 0xf800, 0x9800), /* Class D DC enable */
+       UPDATE_COEF(0x42, 0xf000, 0x2000), /* DC offset */
+       WRITE_COEF(0x37, 0xfc06), /* Class D amp control */
+       {}
+};
+
 static void alc283_restore_default_value(struct hda_codec *codec)
 {
-       int val;
-
-       /* Power Down Control */
-       alc_write_coef_idx(codec, 0x03, 0x0002);
-       /* FIFO and filter clock */
-       alc_write_coef_idx(codec, 0x05, 0x0700);
-       /* DMIC control */
-       alc_write_coef_idx(codec, 0x07, 0x0200);
-       /* Analog clock */
-       val = alc_read_coef_idx(codec, 0x06);
-       alc_write_coef_idx(codec, 0x06, (val & ~0x00f0) | 0x0);
-       /* JD */
-       val = alc_read_coef_idx(codec, 0x08);
-       alc_write_coef_idx(codec, 0x08, (val & ~0xfffc) | 0x0c2c);
-       /* JD offset1 */
-       alc_write_coef_idx(codec, 0x0a, 0xcccc);
-       /* JD offset2 */
-       alc_write_coef_idx(codec, 0x0b, 0xcccc);
-       /* LDO1/2/3, DAC/ADC */
-       alc_write_coef_idx(codec, 0x0e, 0x6fc0);
-       /* JD */
-       val = alc_read_coef_idx(codec, 0x0f);
-       alc_write_coef_idx(codec, 0x0f, (val & ~0xf800) | 0x1000);
-       /* Capless */
-       val = alc_read_coef_idx(codec, 0x10);
-       alc_write_coef_idx(codec, 0x10, (val & ~0xfc00) | 0x0c00);
-       /* Class D test 4 */
-       alc_write_coef_idx(codec, 0x3a, 0x0);
-       /* IO power down directly */
-       val = alc_read_coef_idx(codec, 0x0c);
-       alc_write_coef_idx(codec, 0x0c, (val & ~0xfe00) | 0x0);
-       /* ANC */
-       alc_write_coef_idx(codec, 0x22, 0xa0c0);
-       /* AGC MUX */
-       val = alc_read_coefex_idx(codec, 0x53, 0x01);
-       alc_write_coefex_idx(codec, 0x53, 0x01, (val & ~0x000f) | 0x0008);
-       /* DAC simple content protection */
-       val = alc_read_coef_idx(codec, 0x1d);
-       alc_write_coef_idx(codec, 0x1d, (val & ~0x00e0) | 0x0);
-       /* ADC simple content protection */
-       val = alc_read_coef_idx(codec, 0x1f);
-       alc_write_coef_idx(codec, 0x1f, (val & ~0x00e0) | 0x0);
-       /* DAC ADC Zero Detection */
-       alc_write_coef_idx(codec, 0x21, 0x8804);
-       /* PLL */
-       alc_write_coef_idx(codec, 0x2e, 0x2902);
-       /* capless control 2 */
-       alc_write_coef_idx(codec, 0x33, 0xa080);
-       /* capless control 3 */
-       alc_write_coef_idx(codec, 0x34, 0x3400);
-       /* capless control 4 */
-       alc_write_coef_idx(codec, 0x35, 0x2f3e);
-       /* capless control 5 */
-       alc_write_coef_idx(codec, 0x36, 0x0);
-       /* class D test 2 */
-       val = alc_read_coef_idx(codec, 0x38);
-       alc_write_coef_idx(codec, 0x38, (val & ~0x0fff) | 0x0900);
-       /* class D test 3 */
-       alc_write_coef_idx(codec, 0x39, 0x110a);
-       /* class D test 5 */
-       val = alc_read_coef_idx(codec, 0x3b);
-       alc_write_coef_idx(codec, 0x3b, (val & ~0x00f8) | 0x00d8);
-       /* class D test 6 */
-       alc_write_coef_idx(codec, 0x3c, 0x0014);
-       /* classD OCP */
-       alc_write_coef_idx(codec, 0x3d, 0xc2ba);
-       /* classD pure DC test */
-       val = alc_read_coef_idx(codec, 0x42);
-       alc_write_coef_idx(codec, 0x42, (val & ~0x0f80) | 0x0);
-       /* test mode */
-       alc_write_coef_idx(codec, 0x49, 0x0);
-       /* Class D DC enable */
-       val = alc_read_coef_idx(codec, 0x40);
-       alc_write_coef_idx(codec, 0x40, (val & ~0xf800) | 0x9800);
-       /* DC offset */
-       val = alc_read_coef_idx(codec, 0x42);
-       alc_write_coef_idx(codec, 0x42, (val & ~0xf000) | 0x2000);
-       /* Class D amp control */
-       alc_write_coef_idx(codec, 0x37, 0xfc06);
+       alc_process_coef_fw(codec, alc283_coefs);
 }
 
 static void alc283_init(struct hda_codec *codec)
@@ -3068,7 +2830,6 @@ static void alc283_init(struct hda_codec *codec)
        struct alc_spec *spec = codec->spec;
        hda_nid_t hp_pin = spec->gen.autocfg.hp_pins[0];
        bool hp_pin_sense;
-       int val;
 
        if (!spec->gen.autocfg.hp_outs) {
                if (spec->gen.autocfg.line_out_type == AC_JACK_HP_OUT)
@@ -3098,8 +2859,7 @@ static void alc283_init(struct hda_codec *codec)
                msleep(85);
        /* Index 0x46 Combo jack auto switch control 2 */
        /* 3k pull low control for Headset jack. */
-       val = alc_read_coef_idx(codec, 0x46);
-       alc_write_coef_idx(codec, 0x46, val & ~(3 << 12));
+       alc_update_coef_idx(codec, 0x46, 3 << 12, 0);
        /* Headphone capless set to normal mode */
        alc_write_coef_idx(codec, 0x43, 0x9614);
 }
@@ -3109,7 +2869,6 @@ static void alc283_shutup(struct hda_codec *codec)
        struct alc_spec *spec = codec->spec;
        hda_nid_t hp_pin = spec->gen.autocfg.hp_pins[0];
        bool hp_pin_sense;
-       int val;
 
        if (!spec->gen.autocfg.hp_outs) {
                if (spec->gen.autocfg.line_out_type == AC_JACK_HP_OUT)
@@ -3134,8 +2893,7 @@ static void alc283_shutup(struct hda_codec *codec)
        snd_hda_codec_write(codec, hp_pin, 0,
                            AC_VERB_SET_PIN_WIDGET_CONTROL, 0x0);
 
-       val = alc_read_coef_idx(codec, 0x46);
-       alc_write_coef_idx(codec, 0x46, val | (3 << 12));
+       alc_update_coef_idx(codec, 0x46, 0, 3 << 12);
 
        if (hp_pin_sense)
                msleep(100);
@@ -3268,7 +3026,6 @@ static int alc269_resume(struct hda_codec *codec)
 
        snd_hda_codec_resume_amp(codec);
        snd_hda_codec_resume_cache(codec);
-       alc_inv_dmic_sync(codec, true);
        hda_call_check_power_status(codec, 0x01);
 
        /* on some machine, the BIOS will clear the codec gpio data when enter
@@ -3298,12 +3055,8 @@ static void alc269_fixup_pincfg_no_hp_to_lineout(struct hda_codec *codec,
 static void alc269_fixup_hweq(struct hda_codec *codec,
                               const struct hda_fixup *fix, int action)
 {
-       int coef;
-
-       if (action != HDA_FIXUP_ACT_INIT)
-               return;
-       coef = alc_read_coef_idx(codec, 0x1e);
-       alc_write_coef_idx(codec, 0x1e, coef | 0x80);
+       if (action == HDA_FIXUP_ACT_INIT)
+               alc_update_coef_idx(codec, 0x1e, 0, 0x80);
 }
 
 static void alc269_fixup_headset_mic(struct hda_codec *codec,
@@ -3351,32 +3104,21 @@ static void alc269_fixup_pcm_44k(struct hda_codec *codec,
 static void alc269_fixup_stereo_dmic(struct hda_codec *codec,
                                     const struct hda_fixup *fix, int action)
 {
-       int coef;
-
-       if (action != HDA_FIXUP_ACT_INIT)
-               return;
        /* The digital-mic unit sends PDM (differential signal) instead of
         * the standard PCM, thus you can't record a valid mono stream as is.
         * Below is a workaround specific to ALC269 to control the dmic
         * signal source as mono.
         */
-       coef = alc_read_coef_idx(codec, 0x07);
-       alc_write_coef_idx(codec, 0x07, coef | 0x80);
+       if (action == HDA_FIXUP_ACT_INIT)
+               alc_update_coef_idx(codec, 0x07, 0, 0x80);
 }
 
 static void alc269_quanta_automute(struct hda_codec *codec)
 {
        snd_hda_gen_update_outputs(codec);
 
-       snd_hda_codec_write(codec, 0x20, 0,
-                       AC_VERB_SET_COEF_INDEX, 0x0c);
-       snd_hda_codec_write(codec, 0x20, 0,
-                       AC_VERB_SET_PROC_COEF, 0x680);
-
-       snd_hda_codec_write(codec, 0x20, 0,
-                       AC_VERB_SET_COEF_INDEX, 0x0c);
-       snd_hda_codec_write(codec, 0x20, 0,
-                       AC_VERB_SET_PROC_COEF, 0x480);
+       alc_write_coef_idx(codec, 0x0c, 0x680);
+       alc_write_coef_idx(codec, 0x0c, 0x480);
 }
 
 static void alc269_fixup_quanta_mute(struct hda_codec *codec,
@@ -3389,7 +3131,7 @@ static void alc269_fixup_quanta_mute(struct hda_codec *codec,
 }
 
 static void alc269_x101_hp_automute_hook(struct hda_codec *codec,
-                                        struct hda_jack_tbl *jack)
+                                        struct hda_jack_callback *jack)
 {
        struct alc_spec *spec = codec->spec;
        int vref;
@@ -3622,61 +3364,62 @@ static void alc269_fixup_hp_line1_mic1_led(struct hda_codec *codec,
 
 static void alc_headset_mode_unplugged(struct hda_codec *codec)
 {
-       int val;
+       static struct coef_fw coef0255[] = {
+               WRITE_COEF(0x1b, 0x0c0b), /* LDO and MISC control */
+               WRITE_COEF(0x45, 0xd089), /* UAJ function set to menual mode */
+               UPDATE_COEFEX(0x57, 0x05, 1<<14, 0), /* Direct Drive HP Amp control(Set to verb control)*/
+               WRITE_COEF(0x06, 0x6104), /* Set MIC2 Vref gate with HP */
+               WRITE_COEFEX(0x57, 0x03, 0x8aa6), /* Direct Drive HP Amp control */
+               {}
+       };
+       static struct coef_fw coef0233[] = {
+               WRITE_COEF(0x1b, 0x0c0b),
+               WRITE_COEF(0x45, 0xc429),
+               UPDATE_COEF(0x35, 0x4000, 0),
+               WRITE_COEF(0x06, 0x2104),
+               WRITE_COEF(0x1a, 0x0001),
+               WRITE_COEF(0x26, 0x0004),
+               WRITE_COEF(0x32, 0x42a3),
+               {}
+       };
+       static struct coef_fw coef0292[] = {
+               WRITE_COEF(0x76, 0x000e),
+               WRITE_COEF(0x6c, 0x2400),
+               WRITE_COEF(0x18, 0x7308),
+               WRITE_COEF(0x6b, 0xc429),
+               {}
+       };
+       static struct coef_fw coef0293[] = {
+               UPDATE_COEF(0x10, 7<<8, 6<<8), /* SET Line1 JD to 0 */
+               UPDATE_COEFEX(0x57, 0x05, 1<<15|1<<13, 0x0), /* SET charge pump by verb */
+               UPDATE_COEFEX(0x57, 0x03, 1<<10, 1<<10), /* SET EN_OSW to 1 */
+               UPDATE_COEF(0x1a, 1<<3, 1<<3), /* Combo JD gating with LINE1-VREFO */
+               WRITE_COEF(0x45, 0xc429), /* Set to TRS type */
+               UPDATE_COEF(0x4a, 0x000f, 0x000e), /* Combo Jack auto detect */
+               {}
+       };
+       static struct coef_fw coef0668[] = {
+               WRITE_COEF(0x15, 0x0d40),
+               WRITE_COEF(0xb7, 0x802b),
+               {}
+       };
 
        switch (codec->vendor_id) {
        case 0x10ec0255:
-               /* LDO and MISC control */
-               alc_write_coef_idx(codec, 0x1b, 0x0c0b);
-               /* UAJ function set to menual mode */
-               alc_write_coef_idx(codec, 0x45, 0xd089);
-               /* Direct Drive HP Amp control(Set to verb control)*/
-               val = alc_read_coefex_idx(codec, 0x57, 0x05);
-               alc_write_coefex_idx(codec, 0x57, 0x05, val & ~(1<<14));
-               /* Set MIC2 Vref gate with HP */
-               alc_write_coef_idx(codec, 0x06, 0x6104);
-               /* Direct Drive HP Amp control */
-               alc_write_coefex_idx(codec, 0x57, 0x03, 0x8aa6);
+               alc_process_coef_fw(codec, coef0255);
                break;
        case 0x10ec0233:
        case 0x10ec0283:
-               alc_write_coef_idx(codec, 0x1b, 0x0c0b);
-               alc_write_coef_idx(codec, 0x45, 0xc429);
-               val = alc_read_coef_idx(codec, 0x35);
-               alc_write_coef_idx(codec, 0x35, val & 0xbfff);
-               alc_write_coef_idx(codec, 0x06, 0x2104);
-               alc_write_coef_idx(codec, 0x1a, 0x0001);
-               alc_write_coef_idx(codec, 0x26, 0x0004);
-               alc_write_coef_idx(codec, 0x32, 0x42a3);
+               alc_process_coef_fw(codec, coef0233);
                break;
        case 0x10ec0292:
-               alc_write_coef_idx(codec, 0x76, 0x000e);
-               alc_write_coef_idx(codec, 0x6c, 0x2400);
-               alc_write_coef_idx(codec, 0x18, 0x7308);
-               alc_write_coef_idx(codec, 0x6b, 0xc429);
+               alc_process_coef_fw(codec, coef0292);
                break;
        case 0x10ec0293:
-               /* SET Line1 JD to 0 */
-               val = alc_read_coef_idx(codec, 0x10);
-               alc_write_coef_idx(codec, 0x10, (val & ~(7<<8)) | 6<<8);
-               /* SET charge pump by verb */
-               val = alc_read_coefex_idx(codec, 0x57, 0x05);
-               alc_write_coefex_idx(codec, 0x57, 0x05, (val & ~(1<<15|1<<13)) | 0x0);
-               /* SET EN_OSW to 1 */
-               val = alc_read_coefex_idx(codec, 0x57, 0x03);
-               alc_write_coefex_idx(codec, 0x57, 0x03, (val & ~(1<<10)) | (1<<10) );
-               /* Combo JD gating with LINE1-VREFO */
-               val = alc_read_coef_idx(codec, 0x1a);
-               alc_write_coef_idx(codec, 0x1a, (val & ~(1<<3)) | (1<<3));
-               /* Set to TRS type */
-               alc_write_coef_idx(codec, 0x45, 0xc429);
-               /* Combo Jack auto detect */
-               val = alc_read_coef_idx(codec, 0x4a);
-               alc_write_coef_idx(codec, 0x4a, (val & 0xfff0) | 0x000e);
+               alc_process_coef_fw(codec, coef0293);
                break;
        case 0x10ec0668:
-               alc_write_coef_idx(codec, 0x15, 0x0d40);
-               alc_write_coef_idx(codec, 0xb7, 0x802b);
+               alc_process_coef_fw(codec, coef0668);
                break;
        }
        codec_dbg(codec, "Headset jack set to unplugged mode.\n");
@@ -3686,55 +3429,65 @@ static void alc_headset_mode_unplugged(struct hda_codec *codec)
 static void alc_headset_mode_mic_in(struct hda_codec *codec, hda_nid_t hp_pin,
                                    hda_nid_t mic_pin)
 {
-       int val;
+       static struct coef_fw coef0255[] = {
+               WRITE_COEFEX(0x57, 0x03, 0x8aa6),
+               WRITE_COEF(0x06, 0x6100), /* Set MIC2 Vref gate to normal */
+               {}
+       };
+       static struct coef_fw coef0233[] = {
+               UPDATE_COEF(0x35, 0, 1<<14),
+               WRITE_COEF(0x06, 0x2100),
+               WRITE_COEF(0x1a, 0x0021),
+               WRITE_COEF(0x26, 0x008c),
+               {}
+       };
+       static struct coef_fw coef0292[] = {
+               WRITE_COEF(0x19, 0xa208),
+               WRITE_COEF(0x2e, 0xacf0),
+               {}
+       };
+       static struct coef_fw coef0293[] = {
+               UPDATE_COEFEX(0x57, 0x05, 0, 1<<15|1<<13), /* SET charge pump by verb */
+               UPDATE_COEFEX(0x57, 0x03, 1<<10, 0), /* SET EN_OSW to 0 */
+               UPDATE_COEF(0x1a, 1<<3, 0), /* Combo JD gating without LINE1-VREFO */
+               {}
+       };
+       static struct coef_fw coef0688[] = {
+               WRITE_COEF(0xb7, 0x802b),
+               WRITE_COEF(0xb5, 0x1040),
+               UPDATE_COEF(0xc3, 0, 1<<12),
+               {}
+       };
 
        switch (codec->vendor_id) {
        case 0x10ec0255:
                alc_write_coef_idx(codec, 0x45, 0xc489);
                snd_hda_set_pin_ctl_cache(codec, hp_pin, 0);
-               alc_write_coefex_idx(codec, 0x57, 0x03, 0x8aa6);
-               /* Set MIC2 Vref gate to normal */
-               alc_write_coef_idx(codec, 0x06, 0x6100);
+               alc_process_coef_fw(codec, coef0255);
                snd_hda_set_pin_ctl_cache(codec, mic_pin, PIN_VREF50);
                break;
        case 0x10ec0233:
        case 0x10ec0283:
                alc_write_coef_idx(codec, 0x45, 0xc429);
                snd_hda_set_pin_ctl_cache(codec, hp_pin, 0);
-               val = alc_read_coef_idx(codec, 0x35);
-               alc_write_coef_idx(codec, 0x35, val | 1<<14);
-               alc_write_coef_idx(codec, 0x06, 0x2100);
-               alc_write_coef_idx(codec, 0x1a, 0x0021);
-               alc_write_coef_idx(codec, 0x26, 0x008c);
+               alc_process_coef_fw(codec, coef0233);
                snd_hda_set_pin_ctl_cache(codec, mic_pin, PIN_VREF50);
                break;
        case 0x10ec0292:
                snd_hda_set_pin_ctl_cache(codec, hp_pin, 0);
-               alc_write_coef_idx(codec, 0x19, 0xa208);
-               alc_write_coef_idx(codec, 0x2e, 0xacf0);
+               alc_process_coef_fw(codec, coef0292);
                break;
        case 0x10ec0293:
                /* Set to TRS mode */
                alc_write_coef_idx(codec, 0x45, 0xc429);
                snd_hda_set_pin_ctl_cache(codec, hp_pin, 0);
-               /* SET charge pump by verb */
-               val = alc_read_coefex_idx(codec, 0x57, 0x05);
-               alc_write_coefex_idx(codec, 0x57, 0x05, (val & ~(1<<15|1<<13)) | (1<<15|1<<13));
-               /* SET EN_OSW to 0 */
-               val = alc_read_coefex_idx(codec, 0x57, 0x03);
-               alc_write_coefex_idx(codec, 0x57, 0x03, (val & ~(1<<10)) | 0x0);
-               /* Combo JD gating without LINE1-VREFO */
-               val = alc_read_coef_idx(codec, 0x1a);
-               alc_write_coef_idx(codec, 0x1a, (val & ~(1<<3)) | 0x0);
+               alc_process_coef_fw(codec, coef0293);
                snd_hda_set_pin_ctl_cache(codec, mic_pin, PIN_VREF50);
                break;
        case 0x10ec0668:
                alc_write_coef_idx(codec, 0x11, 0x0001);
                snd_hda_set_pin_ctl_cache(codec, hp_pin, 0);
-               alc_write_coef_idx(codec, 0xb7, 0x802b);
-               alc_write_coef_idx(codec, 0xb5, 0x1040);
-               val = alc_read_coef_idx(codec, 0xc3);
-               alc_write_coef_idx(codec, 0xc3, val | 1<<12);
+               alc_process_coef_fw(codec, coef0688);
                snd_hda_set_pin_ctl_cache(codec, mic_pin, PIN_VREF50);
                break;
        }
@@ -3743,40 +3496,54 @@ static void alc_headset_mode_mic_in(struct hda_codec *codec, hda_nid_t hp_pin,
 
 static void alc_headset_mode_default(struct hda_codec *codec)
 {
-       int val;
+       static struct coef_fw coef0255[] = {
+               WRITE_COEF(0x45, 0xc089),
+               WRITE_COEF(0x45, 0xc489),
+               WRITE_COEFEX(0x57, 0x03, 0x8ea6),
+               WRITE_COEF(0x49, 0x0049),
+               {}
+       };
+       static struct coef_fw coef0233[] = {
+               WRITE_COEF(0x06, 0x2100),
+               WRITE_COEF(0x32, 0x4ea3),
+               {}
+       };
+       static struct coef_fw coef0292[] = {
+               WRITE_COEF(0x76, 0x000e),
+               WRITE_COEF(0x6c, 0x2400),
+               WRITE_COEF(0x6b, 0xc429),
+               WRITE_COEF(0x18, 0x7308),
+               {}
+       };
+       static struct coef_fw coef0293[] = {
+               UPDATE_COEF(0x4a, 0x000f, 0x000e), /* Combo Jack auto detect */
+               WRITE_COEF(0x45, 0xC429), /* Set to TRS type */
+               UPDATE_COEF(0x1a, 1<<3, 0), /* Combo JD gating without LINE1-VREFO */
+               {}
+       };
+       static struct coef_fw coef0688[] = {
+               WRITE_COEF(0x11, 0x0041),
+               WRITE_COEF(0x15, 0x0d40),
+               WRITE_COEF(0xb7, 0x802b),
+               {}
+       };
 
        switch (codec->vendor_id) {
        case 0x10ec0255:
-               alc_write_coef_idx(codec, 0x45, 0xc089);
-               alc_write_coef_idx(codec, 0x45, 0xc489);
-               alc_write_coefex_idx(codec, 0x57, 0x03, 0x8ea6);
-               alc_write_coef_idx(codec, 0x49, 0x0049);
+               alc_process_coef_fw(codec, coef0255);
                break;
        case 0x10ec0233:
        case 0x10ec0283:
-               alc_write_coef_idx(codec, 0x06, 0x2100);
-               alc_write_coef_idx(codec, 0x32, 0x4ea3);
+               alc_process_coef_fw(codec, coef0233);
                break;
        case 0x10ec0292:
-               alc_write_coef_idx(codec, 0x76, 0x000e);
-               alc_write_coef_idx(codec, 0x6c, 0x2400);
-               alc_write_coef_idx(codec, 0x6b, 0xc429);
-               alc_write_coef_idx(codec, 0x18, 0x7308);
+               alc_process_coef_fw(codec, coef0292);
                break;
        case 0x10ec0293:
-               /* Combo Jack auto detect */
-               val = alc_read_coef_idx(codec, 0x4a);
-               alc_write_coef_idx(codec, 0x4a, (val & 0xfff0) | 0x000e);
-               /* Set to TRS type */
-               alc_write_coef_idx(codec, 0x45, 0xC429);
-               /* Combo JD gating without LINE1-VREFO */
-               val = alc_read_coef_idx(codec, 0x1a);
-               alc_write_coef_idx(codec, 0x1a, (val & ~(1<<3)) | 0x0);
+               alc_process_coef_fw(codec, coef0293);
                break;
        case 0x10ec0668:
-               alc_write_coef_idx(codec, 0x11, 0x0041);
-               alc_write_coef_idx(codec, 0x15, 0x0d40);
-               alc_write_coef_idx(codec, 0xb7, 0x802b);
+               alc_process_coef_fw(codec, coef0688);
                break;
        }
        codec_dbg(codec, "Headset jack set to headphone (default) mode.\n");
@@ -3785,37 +3552,52 @@ static void alc_headset_mode_default(struct hda_codec *codec)
 /* Iphone type */
 static void alc_headset_mode_ctia(struct hda_codec *codec)
 {
-       int val;
+       static struct coef_fw coef0255[] = {
+               WRITE_COEF(0x45, 0xd489), /* Set to CTIA type */
+               WRITE_COEF(0x1b, 0x0c2b),
+               WRITE_COEFEX(0x57, 0x03, 0x8ea6),
+               {}
+       };
+       static struct coef_fw coef0233[] = {
+               WRITE_COEF(0x45, 0xd429),
+               WRITE_COEF(0x1b, 0x0c2b),
+               WRITE_COEF(0x32, 0x4ea3),
+               {}
+       };
+       static struct coef_fw coef0292[] = {
+               WRITE_COEF(0x6b, 0xd429),
+               WRITE_COEF(0x76, 0x0008),
+               WRITE_COEF(0x18, 0x7388),
+               {}
+       };
+       static struct coef_fw coef0293[] = {
+               WRITE_COEF(0x45, 0xd429), /* Set to ctia type */
+               UPDATE_COEF(0x10, 7<<8, 7<<8), /* SET Line1 JD to 1 */
+               {}
+       };
+       static struct coef_fw coef0688[] = {
+               WRITE_COEF(0x11, 0x0001),
+               WRITE_COEF(0x15, 0x0d60),
+               WRITE_COEF(0xc3, 0x0000),
+               {}
+       };
 
        switch (codec->vendor_id) {
        case 0x10ec0255:
-               /* Set to CTIA type */
-               alc_write_coef_idx(codec, 0x45, 0xd489);
-               alc_write_coef_idx(codec, 0x1b, 0x0c2b);
-               alc_write_coefex_idx(codec, 0x57, 0x03, 0x8ea6);
+               alc_process_coef_fw(codec, coef0255);
                break;
        case 0x10ec0233:
        case 0x10ec0283:
-               alc_write_coef_idx(codec, 0x45, 0xd429);
-               alc_write_coef_idx(codec, 0x1b, 0x0c2b);
-               alc_write_coef_idx(codec, 0x32, 0x4ea3);
+               alc_process_coef_fw(codec, coef0233);
                break;
        case 0x10ec0292:
-               alc_write_coef_idx(codec, 0x6b, 0xd429);
-               alc_write_coef_idx(codec, 0x76, 0x0008);
-               alc_write_coef_idx(codec, 0x18, 0x7388);
+               alc_process_coef_fw(codec, coef0292);
                break;
        case 0x10ec0293:
-               /* Set to ctia type */
-               alc_write_coef_idx(codec, 0x45, 0xd429);
-               /* SET Line1 JD to 1 */
-               val = alc_read_coef_idx(codec, 0x10);
-               alc_write_coef_idx(codec, 0x10, (val & ~(7<<8)) | 7<<8);
+               alc_process_coef_fw(codec, coef0293);
                break;
        case 0x10ec0668:
-               alc_write_coef_idx(codec, 0x11, 0x0001);
-               alc_write_coef_idx(codec, 0x15, 0x0d60);
-               alc_write_coef_idx(codec, 0xc3, 0x0000);
+               alc_process_coef_fw(codec, coef0688);
                break;
        }
        codec_dbg(codec, "Headset jack set to iPhone-style headset mode.\n");
@@ -3824,37 +3606,52 @@ static void alc_headset_mode_ctia(struct hda_codec *codec)
 /* Nokia type */
 static void alc_headset_mode_omtp(struct hda_codec *codec)
 {
-       int val;
+       static struct coef_fw coef0255[] = {
+               WRITE_COEF(0x45, 0xe489), /* Set to OMTP Type */
+               WRITE_COEF(0x1b, 0x0c2b),
+               WRITE_COEFEX(0x57, 0x03, 0x8ea6),
+               {}
+       };
+       static struct coef_fw coef0233[] = {
+               WRITE_COEF(0x45, 0xe429),
+               WRITE_COEF(0x1b, 0x0c2b),
+               WRITE_COEF(0x32, 0x4ea3),
+               {}
+       };
+       static struct coef_fw coef0292[] = {
+               WRITE_COEF(0x6b, 0xe429),
+               WRITE_COEF(0x76, 0x0008),
+               WRITE_COEF(0x18, 0x7388),
+               {}
+       };
+       static struct coef_fw coef0293[] = {
+               WRITE_COEF(0x45, 0xe429), /* Set to omtp type */
+               UPDATE_COEF(0x10, 7<<8, 7<<8), /* SET Line1 JD to 1 */
+               {}
+       };
+       static struct coef_fw coef0688[] = {
+               WRITE_COEF(0x11, 0x0001),
+               WRITE_COEF(0x15, 0x0d50),
+               WRITE_COEF(0xc3, 0x0000),
+               {}
+       };
 
        switch (codec->vendor_id) {
        case 0x10ec0255:
-               /* Set to OMTP Type */
-               alc_write_coef_idx(codec, 0x45, 0xe489);
-               alc_write_coef_idx(codec, 0x1b, 0x0c2b);
-               alc_write_coefex_idx(codec, 0x57, 0x03, 0x8ea6);
+               alc_process_coef_fw(codec, coef0255);
                break;
        case 0x10ec0233:
        case 0x10ec0283:
-               alc_write_coef_idx(codec, 0x45, 0xe429);
-               alc_write_coef_idx(codec, 0x1b, 0x0c2b);
-               alc_write_coef_idx(codec, 0x32, 0x4ea3);
+               alc_process_coef_fw(codec, coef0233);
                break;
        case 0x10ec0292:
-               alc_write_coef_idx(codec, 0x6b, 0xe429);
-               alc_write_coef_idx(codec, 0x76, 0x0008);
-               alc_write_coef_idx(codec, 0x18, 0x7388);
+               alc_process_coef_fw(codec, coef0292);
                break;
        case 0x10ec0293:
-               /* Set to omtp type */
-               alc_write_coef_idx(codec, 0x45, 0xe429);
-               /* SET Line1 JD to 1 */
-               val = alc_read_coef_idx(codec, 0x10);
-               alc_write_coef_idx(codec, 0x10, (val & ~(7<<8)) | 7<<8);
+               alc_process_coef_fw(codec, coef0293);
                break;
        case 0x10ec0668:
-               alc_write_coef_idx(codec, 0x11, 0x0001);
-               alc_write_coef_idx(codec, 0x15, 0x0d50);
-               alc_write_coef_idx(codec, 0xc3, 0x0000);
+               alc_process_coef_fw(codec, coef0688);
                break;
        }
        codec_dbg(codec, "Headset jack set to Nokia-style headset mode.\n");
@@ -3865,13 +3662,28 @@ static void alc_determine_headset_type(struct hda_codec *codec)
        int val;
        bool is_ctia = false;
        struct alc_spec *spec = codec->spec;
+       static struct coef_fw coef0255[] = {
+               WRITE_COEF(0x45, 0xd089), /* combo jack auto switch control(Check type)*/
+               WRITE_COEF(0x49, 0x0149), /* combo jack auto switch control(Vref
+ conteol) */
+               {}
+       };
+       static struct coef_fw coef0293[] = {
+               UPDATE_COEF(0x4a, 0x000f, 0x0008), /* Combo Jack auto detect */
+               WRITE_COEF(0x45, 0xD429), /* Set to ctia type */
+               {}
+       };
+       static struct coef_fw coef0688[] = {
+               WRITE_COEF(0x11, 0x0001),
+               WRITE_COEF(0xb7, 0x802b),
+               WRITE_COEF(0x15, 0x0d60),
+               WRITE_COEF(0xc3, 0x0c00),
+               {}
+       };
 
        switch (codec->vendor_id) {
        case 0x10ec0255:
-               /* combo jack auto switch control(Check type)*/
-               alc_write_coef_idx(codec, 0x45, 0xd089);
-               /* combo jack auto switch control(Vref conteol) */
-               alc_write_coef_idx(codec, 0x49, 0x0149);
+               alc_process_coef_fw(codec, coef0255);
                msleep(300);
                val = alc_read_coef_idx(codec, 0x46);
                is_ctia = (val & 0x0070) == 0x0070;
@@ -3890,20 +3702,13 @@ static void alc_determine_headset_type(struct hda_codec *codec)
                is_ctia = (val & 0x001c) == 0x001c;
                break;
        case 0x10ec0293:
-               /* Combo Jack auto detect */
-               val = alc_read_coef_idx(codec, 0x4a);
-               alc_write_coef_idx(codec, 0x4a, (val & 0xfff0) | 0x0008);
-               /* Set to ctia type */
-               alc_write_coef_idx(codec, 0x45, 0xD429);
+               alc_process_coef_fw(codec, coef0293);
                msleep(300);
                val = alc_read_coef_idx(codec, 0x46);
                is_ctia = (val & 0x0070) == 0x0070;
                break;
        case 0x10ec0668:
-               alc_write_coef_idx(codec, 0x11, 0x0001);
-               alc_write_coef_idx(codec, 0xb7, 0x802b);
-               alc_write_coef_idx(codec, 0x15, 0x0d60);
-               alc_write_coef_idx(codec, 0xc3, 0x0c00);
+               alc_process_coef_fw(codec, coef0688);
                msleep(300);
                val = alc_read_coef_idx(codec, 0xbe);
                is_ctia = (val & 0x1c02) == 0x1c02;
@@ -3980,7 +3785,8 @@ static void alc_update_headset_mode_hook(struct hda_codec *codec,
        alc_update_headset_mode(codec);
 }
 
-static void alc_update_headset_jack_cb(struct hda_codec *codec, struct hda_jack_tbl *jack)
+static void alc_update_headset_jack_cb(struct hda_codec *codec,
+                                      struct hda_jack_callback *jack)
 {
        struct alc_spec *spec = codec->spec;
        spec->current_headset_type = ALC_HEADSET_TYPE_UNKNOWN;
@@ -4039,11 +3845,15 @@ static void alc_fixup_headset_mode_no_hp_mic(struct hda_codec *codec,
 static void alc255_set_default_jack_type(struct hda_codec *codec)
 {
        /* Set to iphone type */
-       alc_write_coef_idx(codec, 0x1b, 0x880b);
-       alc_write_coef_idx(codec, 0x45, 0xd089);
-       alc_write_coef_idx(codec, 0x1b, 0x080b);
-       alc_write_coef_idx(codec, 0x46, 0x0004);
-       alc_write_coef_idx(codec, 0x1b, 0x0c0b);
+       static struct coef_fw fw[] = {
+               WRITE_COEF(0x1b, 0x880b),
+               WRITE_COEF(0x45, 0xd089),
+               WRITE_COEF(0x1b, 0x080b),
+               WRITE_COEF(0x46, 0x0004),
+               WRITE_COEF(0x1b, 0x0c0b),
+               {}
+       };
+       alc_process_coef_fw(codec, fw);
        msleep(30);
 }
 
@@ -4138,10 +3948,8 @@ static void alc_fixup_headset_mode_alc668(struct hda_codec *codec,
                                const struct hda_fixup *fix, int action)
 {
        if (action == HDA_FIXUP_ACT_PRE_PROBE) {
-               int val;
                alc_write_coef_idx(codec, 0xc4, 0x8000);
-               val = alc_read_coef_idx(codec, 0xc2);
-               alc_write_coef_idx(codec, 0xc2, val & 0xfe);
+               alc_update_coef_idx(codec, 0xc2, ~0xfe, 0);
                snd_hda_set_pin_ctl_cache(codec, 0x18, 0);
        }
        alc_fixup_headset_mode(codec, fix, action);
@@ -4218,7 +4026,7 @@ static void alc269_fixup_limit_int_mic_boost(struct hda_codec *codec,
 }
 
 static void alc283_hp_automute_hook(struct hda_codec *codec,
-                                   struct hda_jack_tbl *jack)
+                                   struct hda_jack_callback *jack)
 {
        struct alc_spec *spec = codec->spec;
        int vref;
@@ -4237,7 +4045,6 @@ static void alc283_fixup_chromebook(struct hda_codec *codec,
                                    const struct hda_fixup *fix, int action)
 {
        struct alc_spec *spec = codec->spec;
-       int val;
 
        switch (action) {
        case HDA_FIXUP_ACT_PRE_PROBE:
@@ -4248,11 +4055,9 @@ static void alc283_fixup_chromebook(struct hda_codec *codec,
        case HDA_FIXUP_ACT_INIT:
                /* MIC2-VREF control */
                /* Set to manual mode */
-               val = alc_read_coef_idx(codec, 0x06);
-               alc_write_coef_idx(codec, 0x06, val & ~0x000c);
+               alc_update_coef_idx(codec, 0x06, 0x000c, 0);
                /* Enable Line1 input control by verb */
-               val = alc_read_coef_idx(codec, 0x1a);
-               alc_write_coef_idx(codec, 0x1a, val | (1 << 4));
+               alc_update_coef_idx(codec, 0x1a, 0, 1 << 4);
                break;
        }
 }
@@ -4261,7 +4066,6 @@ static void alc283_fixup_sense_combo_jack(struct hda_codec *codec,
                                    const struct hda_fixup *fix, int action)
 {
        struct alc_spec *spec = codec->spec;
-       int val;
 
        switch (action) {
        case HDA_FIXUP_ACT_PRE_PROBE:
@@ -4270,8 +4074,7 @@ static void alc283_fixup_sense_combo_jack(struct hda_codec *codec,
        case HDA_FIXUP_ACT_INIT:
                /* MIC2-VREF control */
                /* Set to manual mode */
-               val = alc_read_coef_idx(codec, 0x06);
-               alc_write_coef_idx(codec, 0x06, val & ~0x000c);
+               alc_update_coef_idx(codec, 0x06, 0x000c, 0);
                break;
        }
 }
@@ -4309,7 +4112,6 @@ static void alc282_fixup_asus_tx300(struct hda_codec *codec,
                spec->gen.auto_mute_via_amp = 1;
                spec->gen.automute_hook = asus_tx300_automute;
                snd_hda_jack_detect_enable_callback(codec, 0x1b,
-                                                   HDA_GEN_HP_EVENT,
                                                    snd_hda_gen_hp_automute);
                break;
        case HDA_FIXUP_ACT_BUILD:
@@ -4576,7 +4378,7 @@ static const struct hda_fixup alc269_fixups[] = {
        },
        [ALC269_FIXUP_INV_DMIC] = {
                .type = HDA_FIXUP_FUNC,
-               .v.func = alc_fixup_inv_dmic_0x12,
+               .v.func = alc_fixup_inv_dmic,
        },
        [ALC269_FIXUP_NO_SHUTUP] = {
                .type = HDA_FIXUP_FUNC,
@@ -4887,122 +4689,45 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x1025, 0x0775, "Acer Aspire E1-572", ALC271_FIXUP_HP_GATE_MIC_JACK_E1_572),
        SND_PCI_QUIRK(0x1025, 0x079b, "Acer Aspire V5-573G", ALC282_FIXUP_ASPIRE_V5_PINS),
        SND_PCI_QUIRK(0x1028, 0x0470, "Dell M101z", ALC269_FIXUP_DELL_M101Z),
-       SND_PCI_QUIRK(0x1028, 0x05bd, "Dell", ALC269_FIXUP_DELL2_MIC_NO_PRESENCE),
-       SND_PCI_QUIRK(0x1028, 0x05be, "Dell", ALC269_FIXUP_DELL2_MIC_NO_PRESENCE),
-       SND_PCI_QUIRK(0x1028, 0x05c4, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE),
-       SND_PCI_QUIRK(0x1028, 0x05c5, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE),
-       SND_PCI_QUIRK(0x1028, 0x05c6, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE),
-       SND_PCI_QUIRK(0x1028, 0x05c7, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE),
-       SND_PCI_QUIRK(0x1028, 0x05c8, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE),
-       SND_PCI_QUIRK(0x1028, 0x05c9, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE),
-       SND_PCI_QUIRK(0x1028, 0x05ca, "Dell", ALC269_FIXUP_DELL2_MIC_NO_PRESENCE),
-       SND_PCI_QUIRK(0x1028, 0x05cb, "Dell", ALC269_FIXUP_DELL2_MIC_NO_PRESENCE),
-       SND_PCI_QUIRK(0x1028, 0x05cc, "Dell X5 Precision", ALC269_FIXUP_DELL2_MIC_NO_PRESENCE),
-       SND_PCI_QUIRK(0x1028, 0x05cd, "Dell X5 Precision", ALC269_FIXUP_DELL2_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1028, 0x05da, "Dell Vostro 5460", ALC290_FIXUP_SUBWOOFER),
-       SND_PCI_QUIRK(0x1028, 0x05de, "Dell", ALC269_FIXUP_DELL2_MIC_NO_PRESENCE),
-       SND_PCI_QUIRK(0x1028, 0x05e0, "Dell", ALC269_FIXUP_DELL2_MIC_NO_PRESENCE),
-       SND_PCI_QUIRK(0x1028, 0x05e9, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE),
-       SND_PCI_QUIRK(0x1028, 0x05ea, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE),
-       SND_PCI_QUIRK(0x1028, 0x05eb, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE),
-       SND_PCI_QUIRK(0x1028, 0x05ec, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE),
-       SND_PCI_QUIRK(0x1028, 0x05ed, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE),
-       SND_PCI_QUIRK(0x1028, 0x05ee, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE),
-       SND_PCI_QUIRK(0x1028, 0x05f3, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1028, 0x05f4, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1028, 0x05f5, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1028, 0x05f6, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE),
-       SND_PCI_QUIRK(0x1028, 0x05f8, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE),
-       SND_PCI_QUIRK(0x1028, 0x05f9, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE),
-       SND_PCI_QUIRK(0x1028, 0x05fb, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE),
-       SND_PCI_QUIRK(0x1028, 0x0606, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE),
-       SND_PCI_QUIRK(0x1028, 0x0608, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE),
-       SND_PCI_QUIRK(0x1028, 0x0609, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1028, 0x0610, "Dell", ALC255_FIXUP_DELL_WMI_MIC_MUTE_LED),
-       SND_PCI_QUIRK(0x1028, 0x0613, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE),
-       SND_PCI_QUIRK(0x1028, 0x0614, "Dell Inspiron 3135", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1028, 0x0615, "Dell Vostro 5470", ALC290_FIXUP_SUBWOOFER_HSJACK),
        SND_PCI_QUIRK(0x1028, 0x0616, "Dell Vostro 5470", ALC290_FIXUP_SUBWOOFER_HSJACK),
        SND_PCI_QUIRK(0x1028, 0x061f, "Dell", ALC255_FIXUP_DELL_WMI_MIC_MUTE_LED),
        SND_PCI_QUIRK(0x1028, 0x0638, "Dell Inspiron 5439", ALC290_FIXUP_MONO_SPEAKERS_HSJACK),
-       SND_PCI_QUIRK(0x1028, 0x063f, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1028, 0x064a, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1028, 0x064b, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE),
-       SND_PCI_QUIRK(0x1028, 0x0668, "Dell", ALC255_FIXUP_DELL2_MIC_NO_PRESENCE),
-       SND_PCI_QUIRK(0x1028, 0x0669, "Dell", ALC255_FIXUP_DELL2_MIC_NO_PRESENCE),
-       SND_PCI_QUIRK(0x1028, 0x0684, "Dell", ALC269_FIXUP_DELL2_MIC_NO_PRESENCE),
-       SND_PCI_QUIRK(0x1028, 0x15cc, "Dell X5 Precision", ALC269_FIXUP_DELL2_MIC_NO_PRESENCE),
-       SND_PCI_QUIRK(0x1028, 0x15cd, "Dell X5 Precision", ALC269_FIXUP_DELL2_MIC_NO_PRESENCE),
        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),
        SND_PCI_QUIRK(0x103c, 0x18e6, "HP", ALC269_FIXUP_HP_GPIO_LED),
-       SND_PCI_QUIRK(0x103c, 0x1973, "HP Pavilion", ALC269_FIXUP_HP_MUTE_LED_MIC1),
-       SND_PCI_QUIRK(0x103c, 0x1983, "HP Pavilion", ALC269_FIXUP_HP_MUTE_LED_MIC1),
        SND_PCI_QUIRK(0x103c, 0x218b, "HP", ALC269_FIXUP_LIMIT_INT_MIC_BOOST_MUTE_LED),
        /* ALC282 */
-       SND_PCI_QUIRK(0x103c, 0x21f8, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
-       SND_PCI_QUIRK(0x103c, 0x21f9, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
-       SND_PCI_QUIRK(0x103c, 0x220d, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
-       SND_PCI_QUIRK(0x103c, 0x220e, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
-       SND_PCI_QUIRK(0x103c, 0x220f, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
        SND_PCI_QUIRK(0x103c, 0x2210, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
-       SND_PCI_QUIRK(0x103c, 0x2211, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
-       SND_PCI_QUIRK(0x103c, 0x2212, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
-       SND_PCI_QUIRK(0x103c, 0x2213, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
        SND_PCI_QUIRK(0x103c, 0x2214, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
-       SND_PCI_QUIRK(0x103c, 0x2234, "HP", ALC269_FIXUP_HP_LINE1_MIC1_LED),
-       SND_PCI_QUIRK(0x103c, 0x2235, "HP", ALC269_FIXUP_HP_LINE1_MIC1_LED),
        SND_PCI_QUIRK(0x103c, 0x2236, "HP", ALC269_FIXUP_HP_LINE1_MIC1_LED),
        SND_PCI_QUIRK(0x103c, 0x2237, "HP", ALC269_FIXUP_HP_LINE1_MIC1_LED),
        SND_PCI_QUIRK(0x103c, 0x2238, "HP", ALC269_FIXUP_HP_LINE1_MIC1_LED),
        SND_PCI_QUIRK(0x103c, 0x2239, "HP", ALC269_FIXUP_HP_LINE1_MIC1_LED),
-       SND_PCI_QUIRK(0x103c, 0x2246, "HP", ALC269_FIXUP_HP_LINE1_MIC1_LED),
-       SND_PCI_QUIRK(0x103c, 0x2247, "HP", ALC269_FIXUP_HP_LINE1_MIC1_LED),
-       SND_PCI_QUIRK(0x103c, 0x2248, "HP", ALC269_FIXUP_HP_LINE1_MIC1_LED),
-       SND_PCI_QUIRK(0x103c, 0x2249, "HP", ALC269_FIXUP_HP_LINE1_MIC1_LED),
-       SND_PCI_QUIRK(0x103c, 0x224a, "HP", ALC269_FIXUP_HP_LINE1_MIC1_LED),
        SND_PCI_QUIRK(0x103c, 0x224b, "HP", ALC269_FIXUP_HP_LINE1_MIC1_LED),
-       SND_PCI_QUIRK(0x103c, 0x224c, "HP", ALC269_FIXUP_HP_LINE1_MIC1_LED),
-       SND_PCI_QUIRK(0x103c, 0x224d, "HP", ALC269_FIXUP_HP_LINE1_MIC1_LED),
-       SND_PCI_QUIRK(0x103c, 0x2266, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
-       SND_PCI_QUIRK(0x103c, 0x2267, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
        SND_PCI_QUIRK(0x103c, 0x2268, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
-       SND_PCI_QUIRK(0x103c, 0x2269, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
        SND_PCI_QUIRK(0x103c, 0x226a, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
        SND_PCI_QUIRK(0x103c, 0x226b, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
-       SND_PCI_QUIRK(0x103c, 0x226c, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
-       SND_PCI_QUIRK(0x103c, 0x226d, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
        SND_PCI_QUIRK(0x103c, 0x226e, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
-       SND_PCI_QUIRK(0x103c, 0x226f, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
-       SND_PCI_QUIRK(0x103c, 0x227a, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
-       SND_PCI_QUIRK(0x103c, 0x227b, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
        SND_PCI_QUIRK(0x103c, 0x229e, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
-       SND_PCI_QUIRK(0x103c, 0x22a0, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
        SND_PCI_QUIRK(0x103c, 0x22b2, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
        SND_PCI_QUIRK(0x103c, 0x22b7, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
        SND_PCI_QUIRK(0x103c, 0x22bf, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
-       SND_PCI_QUIRK(0x103c, 0x22c0, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
-       SND_PCI_QUIRK(0x103c, 0x22c1, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
-       SND_PCI_QUIRK(0x103c, 0x22c2, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
-       SND_PCI_QUIRK(0x103c, 0x22cd, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
-       SND_PCI_QUIRK(0x103c, 0x22ce, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
        SND_PCI_QUIRK(0x103c, 0x22cf, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
-       SND_PCI_QUIRK(0x103c, 0x22d0, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
-       SND_PCI_QUIRK(0x103c, 0x22da, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED),
-       SND_PCI_QUIRK(0x103c, 0x22db, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED),
        SND_PCI_QUIRK(0x103c, 0x22dc, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED),
        SND_PCI_QUIRK(0x103c, 0x22fb, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED),
        SND_PCI_QUIRK(0x103c, 0x8004, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED),
        /* ALC290 */
        SND_PCI_QUIRK(0x103c, 0x221b, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED),
-       SND_PCI_QUIRK(0x103c, 0x221c, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED),
-       SND_PCI_QUIRK(0x103c, 0x221d, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED),
-       SND_PCI_QUIRK(0x103c, 0x2220, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED),
        SND_PCI_QUIRK(0x103c, 0x2221, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED),
-       SND_PCI_QUIRK(0x103c, 0x2222, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED),
-       SND_PCI_QUIRK(0x103c, 0x2223, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED),
-       SND_PCI_QUIRK(0x103c, 0x2224, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED),
        SND_PCI_QUIRK(0x103c, 0x2225, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED),
        SND_PCI_QUIRK(0x103c, 0x2246, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED),
        SND_PCI_QUIRK(0x103c, 0x2247, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED),
@@ -5017,8 +4742,6 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x103c, 0x2259, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED),
        SND_PCI_QUIRK(0x103c, 0x225a, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED),
        SND_PCI_QUIRK(0x103c, 0x2260, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
-       SND_PCI_QUIRK(0x103c, 0x2261, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
-       SND_PCI_QUIRK(0x103c, 0x2262, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
        SND_PCI_QUIRK(0x103c, 0x2263, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
        SND_PCI_QUIRK(0x103c, 0x2264, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
        SND_PCI_QUIRK(0x103c, 0x2265, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
@@ -5026,23 +4749,13 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x103c, 0x2273, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED),
        SND_PCI_QUIRK(0x103c, 0x2277, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED),
        SND_PCI_QUIRK(0x103c, 0x2278, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED),
-       SND_PCI_QUIRK(0x103c, 0x227d, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
-       SND_PCI_QUIRK(0x103c, 0x227e, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
        SND_PCI_QUIRK(0x103c, 0x227f, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
-       SND_PCI_QUIRK(0x103c, 0x2280, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
-       SND_PCI_QUIRK(0x103c, 0x2281, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
        SND_PCI_QUIRK(0x103c, 0x2282, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
-       SND_PCI_QUIRK(0x103c, 0x2289, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
-       SND_PCI_QUIRK(0x103c, 0x228a, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
        SND_PCI_QUIRK(0x103c, 0x228b, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
-       SND_PCI_QUIRK(0x103c, 0x228c, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
-       SND_PCI_QUIRK(0x103c, 0x228d, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
        SND_PCI_QUIRK(0x103c, 0x228e, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
        SND_PCI_QUIRK(0x103c, 0x22c5, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
-       SND_PCI_QUIRK(0x103c, 0x22c6, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
        SND_PCI_QUIRK(0x103c, 0x22c7, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
        SND_PCI_QUIRK(0x103c, 0x22c8, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
-       SND_PCI_QUIRK(0x103c, 0x22c3, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
        SND_PCI_QUIRK(0x103c, 0x22c4, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
        SND_PCI_QUIRK(0x103c, 0x2334, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
        SND_PCI_QUIRK(0x103c, 0x2335, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
@@ -5070,6 +4783,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x104d, 0x9099, "Sony VAIO S13", ALC275_FIXUP_SONY_DISABLE_AAMIX),
        SND_PCI_QUIRK(0x10cf, 0x1475, "Lifebook", ALC269_FIXUP_LIFEBOOK),
        SND_PCI_QUIRK(0x10cf, 0x1845, "Lifebook U904", ALC269_FIXUP_LIFEBOOK_EXTMIC),
+       SND_PCI_QUIRK(0x144d, 0xc109, "Samsung Ativ book 9 (NP900X3G)", ALC269_FIXUP_INV_DMIC),
        SND_PCI_QUIRK(0x1458, 0xfa53, "Gigabyte BXBT-2807", ALC283_FIXUP_BXBT2807_MIC),
        SND_PCI_QUIRK(0x17aa, 0x20f2, "Thinkpad SL410/510", ALC269_FIXUP_SKU_IGNORE),
        SND_PCI_QUIRK(0x17aa, 0x215e, "Thinkpad L512", ALC269_FIXUP_SKU_IGNORE),
@@ -5085,12 +4799,13 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x17aa, 0x220c, "Thinkpad T440s", ALC292_FIXUP_TPT440_DOCK),
        SND_PCI_QUIRK(0x17aa, 0x220e, "Thinkpad T440p", ALC292_FIXUP_TPT440_DOCK),
        SND_PCI_QUIRK(0x17aa, 0x2210, "Thinkpad T540p", ALC292_FIXUP_TPT440_DOCK),
-       SND_PCI_QUIRK(0x17aa, 0x2212, "Thinkpad", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
+       SND_PCI_QUIRK(0x17aa, 0x2212, "Thinkpad T440", ALC292_FIXUP_TPT440_DOCK),
        SND_PCI_QUIRK(0x17aa, 0x2214, "Thinkpad", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
        SND_PCI_QUIRK(0x17aa, 0x2215, "Thinkpad", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
        SND_PCI_QUIRK(0x17aa, 0x3978, "IdeaPad Y410P", ALC269_FIXUP_NO_SHUTUP),
        SND_PCI_QUIRK(0x17aa, 0x5013, "Thinkpad", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
        SND_PCI_QUIRK(0x17aa, 0x501a, "Thinkpad", ALC283_FIXUP_INT_MIC),
+       SND_PCI_QUIRK(0x17aa, 0x501e, "Thinkpad L440", ALC292_FIXUP_TPT440_DOCK),
        SND_PCI_QUIRK(0x17aa, 0x5026, "Thinkpad", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
        SND_PCI_QUIRK(0x17aa, 0x5109, "Thinkpad", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
        SND_PCI_QUIRK(0x17aa, 0x3bf8, "Quanta FL1", ALC269_FIXUP_PCM_44K),
@@ -5173,28 +4888,58 @@ static const struct hda_model_fixup alc269_fixup_models[] = {
        {}
 };
 
+#define ALC255_STANDARD_PINS \
+       {0x18, 0x411111f0}, \
+       {0x19, 0x411111f0}, \
+       {0x1a, 0x411111f0}, \
+       {0x1b, 0x411111f0}, \
+       {0x1e, 0x411111f0}
+
+#define ALC282_STANDARD_PINS \
+       {0x14, 0x90170110}, \
+       {0x18, 0x411111f0}, \
+       {0x1a, 0x411111f0}, \
+       {0x1b, 0x411111f0}, \
+       {0x1e, 0x411111f0}
+
+#define ALC290_STANDARD_PINS \
+       {0x12, 0x99a30130}, \
+       {0x13, 0x40000000}, \
+       {0x16, 0x411111f0}, \
+       {0x17, 0x411111f0}, \
+       {0x19, 0x411111f0}, \
+       {0x1b, 0x411111f0}, \
+       {0x1e, 0x411111f0}
+
+#define ALC292_STANDARD_PINS \
+       {0x14, 0x90170110}, \
+       {0x15, 0x0221401f}, \
+       {0x1a, 0x411111f0}, \
+       {0x1b, 0x411111f0}, \
+       {0x1d, 0x40700001}, \
+       {0x1e, 0x411111f0}
+
 static const struct snd_hda_pin_quirk alc269_pin_fixup_tbl[] = {
+       SND_HDA_PIN_QUIRK(0x10ec0255, 0x1028, "Dell", ALC255_FIXUP_DELL2_MIC_NO_PRESENCE,
+               ALC255_STANDARD_PINS,
+               {0x12, 0x40300000},
+               {0x14, 0x90170110},
+               {0x17, 0x411111f0},
+               {0x1d, 0x40538029},
+               {0x21, 0x02211020}),
        SND_HDA_PIN_QUIRK(0x10ec0255, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE,
+               ALC255_STANDARD_PINS,
                {0x12, 0x90a60140},
                {0x14, 0x90170110},
                {0x17, 0x40000000},
-               {0x18, 0x411111f0},
-               {0x19, 0x411111f0},
-               {0x1a, 0x411111f0},
-               {0x1b, 0x411111f0},
                {0x1d, 0x40700001},
-               {0x1e, 0x411111f0},
                {0x21, 0x02211020}),
        SND_HDA_PIN_QUIRK(0x10ec0255, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE,
+               ALC255_STANDARD_PINS,
                {0x12, 0x90a60160},
                {0x14, 0x90170120},
                {0x17, 0x40000000},
-               {0x18, 0x411111f0},
-               {0x19, 0x411111f0},
-               {0x1a, 0x411111f0},
-               {0x1b, 0x411111f0},
                {0x1d, 0x40700001},
-               {0x1e, 0x411111f0},
                {0x21, 0x02211030}),
        SND_HDA_PIN_QUIRK(0x10ec0255, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE,
                {0x12, 0x90a60160},
@@ -5208,70 +4953,101 @@ static const struct snd_hda_pin_quirk alc269_pin_fixup_tbl[] = {
                {0x1e, 0x411111f0},
                {0x21, 0x0321102f}),
        SND_HDA_PIN_QUIRK(0x10ec0255, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE,
+               ALC255_STANDARD_PINS,
                {0x12, 0x90a60160},
                {0x14, 0x90170130},
                {0x17, 0x40000000},
-               {0x18, 0x411111f0},
-               {0x19, 0x411111f0},
-               {0x1a, 0x411111f0},
-               {0x1b, 0x411111f0},
                {0x1d, 0x40700001},
-               {0x1e, 0x411111f0},
                {0x21, 0x02211040}),
        SND_HDA_PIN_QUIRK(0x10ec0255, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE,
+               ALC255_STANDARD_PINS,
                {0x12, 0x90a60160},
                {0x14, 0x90170140},
                {0x17, 0x40000000},
-               {0x18, 0x411111f0},
-               {0x19, 0x411111f0},
-               {0x1a, 0x411111f0},
-               {0x1b, 0x411111f0},
                {0x1d, 0x40700001},
-               {0x1e, 0x411111f0},
                {0x21, 0x02211050}),
        SND_HDA_PIN_QUIRK(0x10ec0255, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE,
+               ALC255_STANDARD_PINS,
                {0x12, 0x90a60170},
                {0x14, 0x90170120},
                {0x17, 0x40000000},
-               {0x18, 0x411111f0},
-               {0x19, 0x411111f0},
-               {0x1a, 0x411111f0},
-               {0x1b, 0x411111f0},
                {0x1d, 0x40700001},
-               {0x1e, 0x411111f0},
                {0x21, 0x02211030}),
        SND_HDA_PIN_QUIRK(0x10ec0255, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE,
+               ALC255_STANDARD_PINS,
                {0x12, 0x90a60170},
                {0x14, 0x90170130},
                {0x17, 0x40000000},
-               {0x18, 0x411111f0},
-               {0x19, 0x411111f0},
-               {0x1a, 0x411111f0},
-               {0x1b, 0x411111f0},
                {0x1d, 0x40700001},
-               {0x1e, 0x411111f0},
                {0x21, 0x02211040}),
+       SND_HDA_PIN_QUIRK(0x10ec0280, 0x103c, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED,
+               {0x12, 0x90a60140},
+               {0x13, 0x40000000},
+               {0x14, 0x90170110},
+               {0x15, 0x0421101f},
+               {0x16, 0x411111f0},
+               {0x17, 0x411111f0},
+               {0x18, 0x02811030},
+               {0x19, 0x411111f0},
+               {0x1a, 0x04a1103f},
+               {0x1b, 0x02011020},
+               {0x1d, 0x40700001},
+               {0x1e, 0x411111f0}),
        SND_HDA_PIN_QUIRK(0x10ec0282, 0x103c, "HP 15 Touchsmart", ALC269_FIXUP_HP_MUTE_LED_MIC1,
+               ALC282_STANDARD_PINS,
                {0x12, 0x99a30130},
-               {0x14, 0x90170110},
                {0x17, 0x40000000},
-               {0x18, 0x411111f0},
                {0x19, 0x03a11020},
-               {0x1a, 0x411111f0},
-               {0x1b, 0x411111f0},
                {0x1d, 0x40f41905},
-               {0x1e, 0x411111f0},
                {0x21, 0x0321101f}),
+       SND_HDA_PIN_QUIRK(0x10ec0282, 0x103c, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1,
+               ALC282_STANDARD_PINS,
+               {0x12, 0x99a30130},
+               {0x17, 0x40020008},
+               {0x19, 0x03a11020},
+               {0x1d, 0x40e00001},
+               {0x21, 0x03211040}),
+       SND_HDA_PIN_QUIRK(0x10ec0282, 0x103c, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1,
+               ALC282_STANDARD_PINS,
+               {0x12, 0x99a30130},
+               {0x17, 0x40000000},
+               {0x19, 0x03a11030},
+               {0x1d, 0x40e00001},
+               {0x21, 0x03211020}),
+       SND_HDA_PIN_QUIRK(0x10ec0282, 0x103c, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1,
+               ALC282_STANDARD_PINS,
+               {0x12, 0x99a30130},
+               {0x17, 0x40000000},
+               {0x19, 0x03a11030},
+               {0x1d, 0x40f00001},
+               {0x21, 0x03211020}),
+       SND_HDA_PIN_QUIRK(0x10ec0282, 0x103c, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1,
+               ALC282_STANDARD_PINS,
+               {0x12, 0x99a30130},
+               {0x17, 0x40000000},
+               {0x19, 0x04a11020},
+               {0x1d, 0x40f00001},
+               {0x21, 0x0421101f}),
+       SND_HDA_PIN_QUIRK(0x10ec0282, 0x103c, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1,
+               ALC282_STANDARD_PINS,
+               {0x12, 0x99a30130},
+               {0x17, 0x40000000},
+               {0x19, 0x03a11030},
+               {0x1d, 0x40f00001},
+               {0x21, 0x04211020}),
+       SND_HDA_PIN_QUIRK(0x10ec0282, 0x103c, "HP", ALC269_FIXUP_HP_LINE1_MIC1_LED,
+               ALC282_STANDARD_PINS,
+               {0x12, 0x90a60140},
+               {0x17, 0x40000000},
+               {0x19, 0x04a11030},
+               {0x1d, 0x40f00001},
+               {0x21, 0x04211020}),
        SND_HDA_PIN_QUIRK(0x10ec0283, 0x1028, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE,
+               ALC282_STANDARD_PINS,
                {0x12, 0x90a60130},
-               {0x14, 0x90170110},
                {0x17, 0x40020008},
-               {0x18, 0x411111f0},
                {0x19, 0x411111f0},
-               {0x1a, 0x411111f0},
-               {0x1b, 0x411111f0},
                {0x1d, 0x40e00001},
-               {0x1e, 0x411111f0},
                {0x21, 0x0321101f}),
        SND_HDA_PIN_QUIRK(0x10ec0283, 0x1028, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE,
                {0x12, 0x90a60160},
@@ -5284,42 +5060,97 @@ static const struct snd_hda_pin_quirk alc269_pin_fixup_tbl[] = {
                {0x1d, 0x40700001},
                {0x1e, 0x411111f0},
                {0x21, 0x02211030}),
+       SND_HDA_PIN_QUIRK(0x10ec0283, 0x1028, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE,
+               ALC282_STANDARD_PINS,
+               {0x12, 0x90a60130},
+               {0x17, 0x40020008},
+               {0x19, 0x03a11020},
+               {0x1d, 0x40e00001},
+               {0x21, 0x0321101f}),
+       SND_HDA_PIN_QUIRK(0x10ec0290, 0x103c, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1,
+               ALC290_STANDARD_PINS,
+               {0x14, 0x411111f0},
+               {0x15, 0x04211040},
+               {0x18, 0x90170112},
+               {0x1a, 0x04a11020},
+               {0x1d, 0x4075812d}),
+       SND_HDA_PIN_QUIRK(0x10ec0290, 0x103c, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1,
+               ALC290_STANDARD_PINS,
+               {0x14, 0x411111f0},
+               {0x15, 0x04211040},
+               {0x18, 0x90170110},
+               {0x1a, 0x04a11020},
+               {0x1d, 0x4075812d}),
+       SND_HDA_PIN_QUIRK(0x10ec0290, 0x103c, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1,
+               ALC290_STANDARD_PINS,
+               {0x14, 0x411111f0},
+               {0x15, 0x0421101f},
+               {0x18, 0x411111f0},
+               {0x1a, 0x04a11020},
+               {0x1d, 0x4075812d}),
+       SND_HDA_PIN_QUIRK(0x10ec0290, 0x103c, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1,
+               ALC290_STANDARD_PINS,
+               {0x14, 0x411111f0},
+               {0x15, 0x04211020},
+               {0x18, 0x411111f0},
+               {0x1a, 0x04a11040},
+               {0x1d, 0x4076a12d}),
+       SND_HDA_PIN_QUIRK(0x10ec0290, 0x103c, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1,
+               ALC290_STANDARD_PINS,
+               {0x14, 0x90170110},
+               {0x15, 0x04211020},
+               {0x18, 0x411111f0},
+               {0x1a, 0x04a11040},
+               {0x1d, 0x4076a12d}),
+       SND_HDA_PIN_QUIRK(0x10ec0290, 0x103c, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1,
+               ALC290_STANDARD_PINS,
+               {0x14, 0x90170110},
+               {0x15, 0x04211020},
+               {0x18, 0x411111f0},
+               {0x1a, 0x04a11020},
+               {0x1d, 0x4076a12d}),
+       SND_HDA_PIN_QUIRK(0x10ec0290, 0x103c, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1,
+               ALC290_STANDARD_PINS,
+               {0x14, 0x90170110},
+               {0x15, 0x0421101f},
+               {0x18, 0x411111f0},
+               {0x1a, 0x04a11020},
+               {0x1d, 0x4075812d}),
+       SND_HDA_PIN_QUIRK(0x10ec0292, 0x1028, "Dell", ALC269_FIXUP_DELL2_MIC_NO_PRESENCE,
+               ALC292_STANDARD_PINS,
+               {0x12, 0x90a60140},
+               {0x13, 0x411111f0},
+               {0x16, 0x01014020},
+               {0x18, 0x411111f0},
+               {0x19, 0x01a19030}),
+       SND_HDA_PIN_QUIRK(0x10ec0292, 0x1028, "Dell", ALC269_FIXUP_DELL2_MIC_NO_PRESENCE,
+               ALC292_STANDARD_PINS,
+               {0x12, 0x90a60140},
+               {0x13, 0x411111f0},
+               {0x16, 0x01014020},
+               {0x18, 0x02a19031},
+               {0x19, 0x01a1903e}),
        SND_HDA_PIN_QUIRK(0x10ec0292, 0x1028, "Dell", ALC269_FIXUP_DELL3_MIC_NO_PRESENCE,
+               ALC292_STANDARD_PINS,
                {0x12, 0x90a60140},
                {0x13, 0x411111f0},
-               {0x14, 0x90170110},
-               {0x15, 0x0221401f},
                {0x16, 0x411111f0},
                {0x18, 0x411111f0},
-               {0x19, 0x411111f0},
-               {0x1a, 0x411111f0},
-               {0x1b, 0x411111f0},
-               {0x1d, 0x40700001},
-               {0x1e, 0x411111f0}),
+               {0x19, 0x411111f0}),
        SND_HDA_PIN_QUIRK(0x10ec0293, 0x1028, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE,
+               ALC292_STANDARD_PINS,
                {0x12, 0x40000000},
                {0x13, 0x90a60140},
-               {0x14, 0x90170110},
-               {0x15, 0x0221401f},
                {0x16, 0x21014020},
                {0x18, 0x411111f0},
-               {0x19, 0x21a19030},
-               {0x1a, 0x411111f0},
-               {0x1b, 0x411111f0},
-               {0x1d, 0x40700001},
-               {0x1e, 0x411111f0}),
+               {0x19, 0x21a19030}),
        SND_HDA_PIN_QUIRK(0x10ec0293, 0x1028, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE,
+               ALC292_STANDARD_PINS,
                {0x12, 0x40000000},
                {0x13, 0x90a60140},
-               {0x14, 0x90170110},
-               {0x15, 0x0221401f},
                {0x16, 0x411111f0},
                {0x18, 0x411111f0},
-               {0x19, 0x411111f0},
-               {0x1a, 0x411111f0},
-               {0x1b, 0x411111f0},
-               {0x1d, 0x40700001},
-               {0x1e, 0x411111f0}),
+               {0x19, 0x411111f0}),
        {}
 };
 
@@ -5342,10 +5173,8 @@ static void alc269_fill_coef(struct hda_codec *codec)
        }
 
        if ((alc_get_coef0(codec) & 0x00ff) == 0x017) {
-               val = alc_read_coef_idx(codec, 0x04);
                /* Power up output pin */
-               if (val != -1)
-                       alc_write_coef_idx(codec, 0x04, val | (1<<11));
+               alc_update_coef_idx(codec, 0x04, 0, 1<<11);
        }
 
        if ((alc_get_coef0(codec) & 0x00ff) == 0x018) {
@@ -5361,13 +5190,11 @@ static void alc269_fill_coef(struct hda_codec *codec)
                }
        }
 
-       val = alc_read_coef_idx(codec, 0xd); /* Class D */
-       if (val != -1)
-               alc_write_coef_idx(codec, 0xd, val | (1<<14));
+       /* Class D */
+       alc_update_coef_idx(codec, 0xd, 0, 1<<14);
 
-       val = alc_read_coef_idx(codec, 0x4); /* HP */
-       if (val != -1)
-               alc_write_coef_idx(codec, 0x4, val | (1<<11));
+       /* HP */
+       alc_update_coef_idx(codec, 0x4, 0, 1<<11);
 }
 
 /*
@@ -6012,7 +5839,7 @@ static const struct hda_fixup alc662_fixups[] = {
        },
        [ALC662_FIXUP_INV_DMIC] = {
                .type = HDA_FIXUP_FUNC,
-               .v.func = alc_fixup_inv_dmic_0x12,
+               .v.func = alc_fixup_inv_dmic,
        },
        [ALC668_FIXUP_DELL_XPS13] = {
                .type = HDA_FIXUP_FUNC,
@@ -6247,16 +6074,14 @@ static const struct snd_hda_pin_quirk alc662_pin_fixup_tbl[] = {
 
 static void alc662_fill_coef(struct hda_codec *codec)
 {
-       int val, coef;
+       int coef;
 
        coef = alc_get_coef0(codec);
 
        switch (codec->vendor_id) {
        case 0x10ec0662:
-               if ((coef & 0x00f0) == 0x0030) {
-                       val = alc_read_coef_idx(codec, 0x4); /* EAPD Ctrl */
-                       alc_write_coef_idx(codec, 0x4, val & ~(1<<10));
-               }
+               if ((coef & 0x00f0) == 0x0030)
+                       alc_update_coef_idx(codec, 0x4, 1<<10, 0); /* EAPD Ctrl */
                break;
        case 0x10ec0272:
        case 0x10ec0273:
@@ -6265,8 +6090,7 @@ static void alc662_fill_coef(struct hda_codec *codec)
        case 0x10ec0670:
        case 0x10ec0671:
        case 0x10ec0672:
-               val = alc_read_coef_idx(codec, 0xd); /* EAPD Ctrl */
-               alc_write_coef_idx(codec, 0xd, val | (1<<14));
+               alc_update_coef_idx(codec, 0xd, 0, 1<<14); /* EAPD Ctrl */
                break;
        }
 }
index 98cd1908c0393856e8bfeec7622874079d60c3c1..4f6413e01c133567a2c01ccee10543d6fc82a864 100644 (file)
@@ -32,7 +32,6 @@
 #include <linux/module.h>
 #include <sound/core.h>
 #include <sound/jack.h>
-#include <sound/tlv.h>
 #include "hda_codec.h"
 #include "hda_local.h"
 #include "hda_auto_parser.h"
 #include "hda_jack.h"
 #include "hda_generic.h"
 
-enum {
-       STAC_VREF_EVENT = 8,
-       STAC_PWR_EVENT,
-};
-
 enum {
        STAC_REF,
        STAC_9200_OQO,
@@ -487,7 +481,7 @@ static void stac_toggle_power_map(struct hda_codec *codec, hda_nid_t nid,
 
 /* update power bit per jack plug/unplug */
 static void jack_update_power(struct hda_codec *codec,
-                             struct hda_jack_tbl *jack)
+                             struct hda_jack_callback *jack)
 {
        struct sigmatel_spec *spec = codec->spec;
        int i;
@@ -495,9 +489,9 @@ static void jack_update_power(struct hda_codec *codec,
        if (!spec->num_pwrs)
                return;
 
-       if (jack && jack->nid) {
-               stac_toggle_power_map(codec, jack->nid,
-                                     snd_hda_jack_detect(codec, jack->nid),
+       if (jack && jack->tbl->nid) {
+               stac_toggle_power_map(codec, jack->tbl->nid,
+                                     snd_hda_jack_detect(codec, jack->tbl->nid),
                                      true);
                return;
        }
@@ -505,42 +499,19 @@ static void jack_update_power(struct hda_codec *codec,
        /* update all jacks */
        for (i = 0; i < spec->num_pwrs; i++) {
                hda_nid_t nid = spec->pwr_nids[i];
-               jack = snd_hda_jack_tbl_get(codec, nid);
-               if (!jack || !jack->action)
+               if (!snd_hda_jack_tbl_get(codec, nid))
                        continue;
-               if (jack->action == STAC_PWR_EVENT ||
-                   jack->action <= HDA_GEN_LAST_EVENT)
-                       stac_toggle_power_map(codec, nid,
-                                             snd_hda_jack_detect(codec, nid),
-                                             false);
+               stac_toggle_power_map(codec, nid,
+                                     snd_hda_jack_detect(codec, nid),
+                                     false);
        }
 
        snd_hda_codec_write(codec, codec->afg, 0, AC_VERB_IDT_SET_POWER_MAP,
                            spec->power_map_bits);
 }
 
-static void stac_hp_automute(struct hda_codec *codec,
-                                struct hda_jack_tbl *jack)
-{
-       snd_hda_gen_hp_automute(codec, jack);
-       jack_update_power(codec, jack);
-}
-
-static void stac_line_automute(struct hda_codec *codec,
-                                  struct hda_jack_tbl *jack)
-{
-       snd_hda_gen_line_automute(codec, jack);
-       jack_update_power(codec, jack);
-}
-
-static void stac_mic_autoswitch(struct hda_codec *codec,
-                               struct hda_jack_tbl *jack)
-{
-       snd_hda_gen_mic_autoswitch(codec, jack);
-       jack_update_power(codec, jack);
-}
-
-static void stac_vref_event(struct hda_codec *codec, struct hda_jack_tbl *event)
+static void stac_vref_event(struct hda_codec *codec,
+                           struct hda_jack_callback *event)
 {
        unsigned int data;
 
@@ -563,13 +534,10 @@ static void stac_init_power_map(struct hda_codec *codec)
                hda_nid_t nid = spec->pwr_nids[i];
                unsigned int def_conf = snd_hda_codec_get_pincfg(codec, nid);
                def_conf = get_defcfg_connect(def_conf);
-               if (snd_hda_jack_tbl_get(codec, nid))
-                       continue;
                if (def_conf == AC_JACK_PORT_COMPLEX &&
                    spec->vref_mute_led_nid != nid &&
                    is_jack_detectable(codec, nid)) {
                        snd_hda_jack_detect_enable_callback(codec, nid,
-                                                           STAC_PWR_EVENT,
                                                            jack_update_power);
                } else {
                        if (def_conf == AC_JACK_PORT_NONE)
@@ -3020,7 +2988,7 @@ static void stac92hd71bxx_fixup_hp_m4(struct hda_codec *codec,
                                      const struct hda_fixup *fix, int action)
 {
        struct sigmatel_spec *spec = codec->spec;
-       struct hda_jack_tbl *jack;
+       struct hda_jack_callback *jack;
 
        if (action != HDA_FIXUP_ACT_PRE_PROBE)
                return;
@@ -3028,11 +2996,9 @@ static void stac92hd71bxx_fixup_hp_m4(struct hda_codec *codec,
        /* Enable VREF power saving on GPIO1 detect */
        snd_hda_codec_write_cache(codec, codec->afg, 0,
                                  AC_VERB_SET_GPIO_UNSOLICITED_RSP_MASK, 0x02);
-       snd_hda_jack_detect_enable_callback(codec, codec->afg,
-                                           STAC_VREF_EVENT,
-                                           stac_vref_event);
-       jack = snd_hda_jack_tbl_get(codec, codec->afg);
-       if (jack)
+       jack = snd_hda_jack_detect_enable_callback(codec, codec->afg,
+                                                  stac_vref_event);
+       if (!IS_ERR(jack))
                jack->private_data = 0x02;
 
        spec->gpio_mask |= 0x02;
@@ -4044,7 +4010,7 @@ static void stac9205_fixup_dell_m43(struct hda_codec *codec,
                                    const struct hda_fixup *fix, int action)
 {
        struct sigmatel_spec *spec = codec->spec;
-       struct hda_jack_tbl *jack;
+       struct hda_jack_callback *jack;
 
        if (action == HDA_FIXUP_ACT_PRE_PROBE) {
                snd_hda_apply_pincfgs(codec, dell_9205_m43_pin_configs);
@@ -4052,11 +4018,9 @@ static void stac9205_fixup_dell_m43(struct hda_codec *codec,
                /* Enable unsol response for GPIO4/Dock HP connection */
                snd_hda_codec_write_cache(codec, codec->afg, 0,
                        AC_VERB_SET_GPIO_UNSOLICITED_RSP_MASK, 0x10);
-               snd_hda_jack_detect_enable_callback(codec, codec->afg,
-                                                   STAC_VREF_EVENT,
-                                                   stac_vref_event);
-               jack = snd_hda_jack_tbl_get(codec, codec->afg);
-               if (jack)
+               jack = snd_hda_jack_detect_enable_callback(codec, codec->afg,
+                                                          stac_vref_event);
+               if (!IS_ERR(jack))
                        jack->private_data = 0x01;
 
                spec->gpio_dir = 0x0b;
@@ -4219,17 +4183,11 @@ static int stac_parse_auto_config(struct hda_codec *codec)
        spec->gen.pcm_capture_hook = stac_capture_pcm_hook;
 
        spec->gen.automute_hook = stac_update_outputs;
-       spec->gen.hp_automute_hook = stac_hp_automute;
-       spec->gen.line_automute_hook = stac_line_automute;
-       spec->gen.mic_autoswitch_hook = stac_mic_autoswitch;
 
        err = snd_hda_gen_parse_auto_config(codec, &spec->gen.autocfg);
        if (err < 0)
                return err;
 
-       /* minimum value is actually mute */
-       spec->gen.vmaster_tlv[3] |= TLV_DB_SCALE_MUTE;
-
        /* setup analog beep controls */
        if (spec->anabeep_nid > 0) {
                err = stac_auto_create_beep_ctls(codec,
@@ -4276,16 +4234,8 @@ static int stac_parse_auto_config(struct hda_codec *codec)
                        return err;
        }
 
-       return 0;
-}
-
-static int stac_build_controls(struct hda_codec *codec)
-{
-       int err = snd_hda_gen_build_controls(codec);
-
-       if (err < 0)
-               return err;
        stac_init_power_map(codec);
+
        return 0;
 }
 
@@ -4399,7 +4349,7 @@ static int stac_suspend(struct hda_codec *codec)
 #endif /* CONFIG_PM */
 
 static const struct hda_codec_ops stac_patch_ops = {
-       .build_controls = stac_build_controls,
+       .build_controls = snd_hda_gen_build_controls,
        .build_pcms = snd_hda_gen_build_pcms,
        .init = stac_init,
        .free = stac_free,
@@ -4420,6 +4370,7 @@ static int alloc_stac_spec(struct hda_codec *codec)
        snd_hda_gen_spec_init(&spec->gen);
        codec->spec = spec;
        codec->no_trigger_sense = 1; /* seems common with STAC/IDT codecs */
+       spec->gen.dac_min_mute = true;
        return 0;
 }
 
index 778166259b3e8e72fe039d08fe5e1671d5c6fd94..6c206b6c8d65d389119e5f7c630f45e52767bd61 100644 (file)
@@ -118,7 +118,6 @@ static void via_playback_pcm_hook(struct hda_pcm_stream *hinfo,
                                  struct hda_codec *codec,
                                  struct snd_pcm_substream *substream,
                                  int action);
-static void via_hp_automute(struct hda_codec *codec, struct hda_jack_tbl *tbl);
 
 static struct via_spec *via_new_spec(struct hda_codec *codec)
 {
@@ -575,25 +574,12 @@ static const struct snd_kcontrol_new vt1708_jack_detect_ctl[] = {
        {} /* terminator */
 };
 
-static void via_hp_automute(struct hda_codec *codec, struct hda_jack_tbl *tbl)
+static void via_jack_powerstate_event(struct hda_codec *codec,
+                                     struct hda_jack_callback *tbl)
 {
        set_widgets_power_state(codec);
-       snd_hda_gen_hp_automute(codec, tbl);
 }
 
-static void via_line_automute(struct hda_codec *codec, struct hda_jack_tbl *tbl)
-{
-       set_widgets_power_state(codec);
-       snd_hda_gen_line_automute(codec, tbl);
-}
-
-static void via_jack_powerstate_event(struct hda_codec *codec, struct hda_jack_tbl *tbl)
-{
-       set_widgets_power_state(codec);
-}
-
-#define VIA_JACK_EVENT (HDA_GEN_LAST_EVENT + 1)
-
 static void via_set_jack_unsol_events(struct hda_codec *codec)
 {
        struct via_spec *spec = codec->spec;
@@ -601,25 +587,17 @@ static void via_set_jack_unsol_events(struct hda_codec *codec)
        hda_nid_t pin;
        int i;
 
-       spec->gen.hp_automute_hook = via_hp_automute;
-       if (cfg->speaker_pins[0])
-               spec->gen.line_automute_hook = via_line_automute;
-
        for (i = 0; i < cfg->line_outs; i++) {
                pin = cfg->line_out_pins[i];
-               if (pin && !snd_hda_jack_tbl_get(codec, pin) &&
-                   is_jack_detectable(codec, pin))
+               if (pin && is_jack_detectable(codec, pin))
                        snd_hda_jack_detect_enable_callback(codec, pin,
-                                                           VIA_JACK_EVENT,
                                                            via_jack_powerstate_event);
        }
 
        for (i = 0; i < cfg->num_inputs; i++) {
                pin = cfg->line_out_pins[i];
-               if (pin && !snd_hda_jack_tbl_get(codec, pin) &&
-                   is_jack_detectable(codec, pin))
+               if (pin && is_jack_detectable(codec, pin))
                        snd_hda_jack_detect_enable_callback(codec, pin,
-                                                           VIA_JACK_EVENT,
                                                            via_jack_powerstate_event);
        }
 }
index 87f7fc41d4f2f03b772d5c9c8ce9472fa250de2f..206ed2cbcef9024a13f7a859bebfe53a8050f7f8 100644 (file)
@@ -2528,7 +2528,7 @@ static int snd_ice1712_free(struct snd_ice1712 *ice)
        if (!ice->port)
                goto __hw_end;
        /* mask all interrupts */
-       outb(0xc0, ICEMT(ice, IRQ));
+       outb(ICE1712_MULTI_CAPTURE | ICE1712_MULTI_PLAYBACK, ICEMT(ice, IRQ));
        outb(0xff, ICEREG(ice, IRQMASK));
        /* --- */
 __hw_end:
index a671f0865f71ceccb28e912018774ab2b433da83..601315a1f58fbef5b50c757844dd376bc22c74c8 100644 (file)
@@ -279,7 +279,6 @@ static snd_pcm_uframes_t lx_pcm_stream_pointer(struct snd_pcm_substream
 {
        struct lx6464es *chip = snd_pcm_substream_chip(substream);
        snd_pcm_uframes_t pos;
-       unsigned long flags;
        int is_capture = (substream->stream == SNDRV_PCM_STREAM_CAPTURE);
 
        struct lx_stream *lx_stream = is_capture ? &chip->capture_stream :
@@ -287,9 +286,9 @@ static snd_pcm_uframes_t lx_pcm_stream_pointer(struct snd_pcm_substream
 
        dev_dbg(chip->card->dev, "->lx_pcm_stream_pointer\n");
 
-       spin_lock_irqsave(&chip->lock, flags);
+       mutex_lock(&chip->lock);
        pos = lx_stream->frame_pos * substream->runtime->period_size;
-       spin_unlock_irqrestore(&chip->lock, flags);
+       mutex_unlock(&chip->lock);
 
        dev_dbg(chip->card->dev, "stream_pointer at %ld\n", pos);
        return pos;
@@ -485,8 +484,8 @@ static void lx_trigger_stop(struct lx6464es *chip, struct lx_stream *lx_stream)
 
 }
 
-static void lx_trigger_tasklet_dispatch_stream(struct lx6464es *chip,
-                                              struct lx_stream *lx_stream)
+static void lx_trigger_dispatch_stream(struct lx6464es *chip,
+                                      struct lx_stream *lx_stream)
 {
        switch (lx_stream->status) {
        case LX_STREAM_STATUS_SCHEDULE_RUN:
@@ -502,24 +501,12 @@ static void lx_trigger_tasklet_dispatch_stream(struct lx6464es *chip,
        }
 }
 
-static void lx_trigger_tasklet(unsigned long data)
-{
-       struct lx6464es *chip = (struct lx6464es *)data;
-       unsigned long flags;
-
-       dev_dbg(chip->card->dev, "->lx_trigger_tasklet\n");
-
-       spin_lock_irqsave(&chip->lock, flags);
-       lx_trigger_tasklet_dispatch_stream(chip, &chip->capture_stream);
-       lx_trigger_tasklet_dispatch_stream(chip, &chip->playback_stream);
-       spin_unlock_irqrestore(&chip->lock, flags);
-}
-
 static int lx_pcm_trigger_dispatch(struct lx6464es *chip,
                                   struct lx_stream *lx_stream, int cmd)
 {
        int err = 0;
 
+       mutex_lock(&chip->lock);
        switch (cmd) {
        case SNDRV_PCM_TRIGGER_START:
                lx_stream->status = LX_STREAM_STATUS_SCHEDULE_RUN;
@@ -533,9 +520,12 @@ static int lx_pcm_trigger_dispatch(struct lx6464es *chip,
                err = -EINVAL;
                goto exit;
        }
-       tasklet_schedule(&chip->trigger_tasklet);
+
+       lx_trigger_dispatch_stream(chip, &chip->capture_stream);
+       lx_trigger_dispatch_stream(chip, &chip->playback_stream);
 
 exit:
+       mutex_unlock(&chip->lock);
        return err;
 }
 
@@ -861,6 +851,7 @@ static int lx_pcm_create(struct lx6464es *chip)
        snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &lx_ops_capture);
 
        pcm->info_flags = 0;
+       pcm->nonatomic = true;
        strcpy(pcm->name, card_name);
 
        err = snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
@@ -1009,15 +1000,9 @@ static int snd_lx6464es_create(struct snd_card *card,
        chip->irq = -1;
 
        /* initialize synchronization structs */
-       spin_lock_init(&chip->lock);
-       spin_lock_init(&chip->msg_lock);
+       mutex_init(&chip->lock);
+       mutex_init(&chip->msg_lock);
        mutex_init(&chip->setup_mutex);
-       tasklet_init(&chip->trigger_tasklet, lx_trigger_tasklet,
-                    (unsigned long)chip);
-       tasklet_init(&chip->tasklet_capture, lx_tasklet_capture,
-                    (unsigned long)chip);
-       tasklet_init(&chip->tasklet_playback, lx_tasklet_playback,
-                    (unsigned long)chip);
 
        /* request resources */
        err = pci_request_regions(pci, card_name);
@@ -1032,8 +1017,8 @@ static int snd_lx6464es_create(struct snd_card *card,
        /* dsp port */
        chip->port_dsp_bar = pci_ioremap_bar(pci, 2);
 
-       err = request_irq(pci->irq, lx_interrupt, IRQF_SHARED,
-                         KBUILD_MODNAME, chip);
+       err = request_threaded_irq(pci->irq, lx_interrupt, lx_threaded_irq,
+                                  IRQF_SHARED, KBUILD_MODNAME, chip);
        if (err) {
                dev_err(card->dev, "unable to grab IRQ %d\n", pci->irq);
                goto request_irq_failed;
index 6792eda9c9a56c0c41f4d8077f83edb19fc94965..1bec187d772f8201a6e8cf8bf6d65986f999f287 100644 (file)
@@ -71,14 +71,10 @@ struct lx6464es {
 
        u8                      mac_address[6];
 
-       spinlock_t              lock;        /* interrupt spinlock */
+       struct mutex            lock;        /* interrupt lock */
        struct mutex            setup_mutex; /* mutex used in hw_params, open
                                              * and close */
 
-       struct tasklet_struct   trigger_tasklet; /* trigger tasklet */
-       struct tasklet_struct   tasklet_capture;
-       struct tasklet_struct   tasklet_playback;
-
        /* ports */
        unsigned long           port_plx;          /* io port (size=256) */
        void __iomem           *port_plx_remapped; /* remapped plx port */
@@ -87,8 +83,9 @@ struct lx6464es {
                                                    * size=8K) */
 
        /* messaging */
-       spinlock_t              msg_lock;          /* message spinlock */
+       struct mutex            msg_lock;          /* message lock */
        struct lx_rmh           rmh;
+       u32                     irqsrc;
 
        /* configuration */
        uint                    freq_ratio : 2;
index e8f38e5df10abcae863756ac0134c0e5d2c1f1c1..f3d62020ef66c95119461a8836a650f30071f39d 100644 (file)
@@ -332,27 +332,25 @@ polling_successful:
 int lx_dsp_get_version(struct lx6464es *chip, u32 *rdsp_version)
 {
        u16 ret;
-       unsigned long flags;
 
-       spin_lock_irqsave(&chip->msg_lock, flags);
+       mutex_lock(&chip->msg_lock);
 
        lx_message_init(&chip->rmh, CMD_01_GET_SYS_CFG);
        ret = lx_message_send_atomic(chip, &chip->rmh);
 
        *rdsp_version = chip->rmh.stat[1];
-       spin_unlock_irqrestore(&chip->msg_lock, flags);
+       mutex_unlock(&chip->msg_lock);
        return ret;
 }
 
 int lx_dsp_get_clock_frequency(struct lx6464es *chip, u32 *rfreq)
 {
        u16 ret = 0;
-       unsigned long flags;
        u32 freq_raw = 0;
        u32 freq = 0;
        u32 frequency = 0;
 
-       spin_lock_irqsave(&chip->msg_lock, flags);
+       mutex_lock(&chip->msg_lock);
 
        lx_message_init(&chip->rmh, CMD_01_GET_SYS_CFG);
        ret = lx_message_send_atomic(chip, &chip->rmh);
@@ -370,7 +368,7 @@ int lx_dsp_get_clock_frequency(struct lx6464es *chip, u32 *rfreq)
                        frequency = 48000;
        }
 
-       spin_unlock_irqrestore(&chip->msg_lock, flags);
+       mutex_unlock(&chip->msg_lock);
 
        *rfreq = frequency * chip->freq_ratio;
 
@@ -398,25 +396,23 @@ int lx_dsp_get_mac(struct lx6464es *chip)
 
 int lx_dsp_set_granularity(struct lx6464es *chip, u32 gran)
 {
-       unsigned long flags;
        int ret;
 
-       spin_lock_irqsave(&chip->msg_lock, flags);
+       mutex_lock(&chip->msg_lock);
 
        lx_message_init(&chip->rmh, CMD_02_SET_GRANULARITY);
        chip->rmh.cmd[0] |= gran;
 
        ret = lx_message_send_atomic(chip, &chip->rmh);
-       spin_unlock_irqrestore(&chip->msg_lock, flags);
+       mutex_unlock(&chip->msg_lock);
        return ret;
 }
 
 int lx_dsp_read_async_events(struct lx6464es *chip, u32 *data)
 {
-       unsigned long flags;
        int ret;
 
-       spin_lock_irqsave(&chip->msg_lock, flags);
+       mutex_lock(&chip->msg_lock);
 
        lx_message_init(&chip->rmh, CMD_04_GET_EVENT);
        chip->rmh.stat_len = 9; /* we don't necessarily need the full length */
@@ -426,7 +422,7 @@ int lx_dsp_read_async_events(struct lx6464es *chip, u32 *data)
        if (!ret)
                memcpy(data, chip->rmh.stat, chip->rmh.stat_len * sizeof(u32));
 
-       spin_unlock_irqrestore(&chip->msg_lock, flags);
+       mutex_unlock(&chip->msg_lock);
        return ret;
 }
 
@@ -440,18 +436,16 @@ int lx_pipe_allocate(struct lx6464es *chip, u32 pipe, int is_capture,
                     int channels)
 {
        int err;
-       unsigned long flags;
-
        u32 pipe_cmd = PIPE_INFO_TO_CMD(is_capture, pipe);
 
-       spin_lock_irqsave(&chip->msg_lock, flags);
+       mutex_lock(&chip->msg_lock);
        lx_message_init(&chip->rmh, CMD_06_ALLOCATE_PIPE);
 
        chip->rmh.cmd[0] |= pipe_cmd;
        chip->rmh.cmd[0] |= channels;
 
        err = lx_message_send_atomic(chip, &chip->rmh);
-       spin_unlock_irqrestore(&chip->msg_lock, flags);
+       mutex_unlock(&chip->msg_lock);
 
        if (err != 0)
                dev_err(chip->card->dev, "could not allocate pipe\n");
@@ -462,17 +456,15 @@ int lx_pipe_allocate(struct lx6464es *chip, u32 pipe, int is_capture,
 int lx_pipe_release(struct lx6464es *chip, u32 pipe, int is_capture)
 {
        int err;
-       unsigned long flags;
-
        u32 pipe_cmd = PIPE_INFO_TO_CMD(is_capture, pipe);
 
-       spin_lock_irqsave(&chip->msg_lock, flags);
+       mutex_lock(&chip->msg_lock);
        lx_message_init(&chip->rmh, CMD_07_RELEASE_PIPE);
 
        chip->rmh.cmd[0] |= pipe_cmd;
 
        err = lx_message_send_atomic(chip, &chip->rmh);
-       spin_unlock_irqrestore(&chip->msg_lock, flags);
+       mutex_unlock(&chip->msg_lock);
 
        return err;
 }
@@ -481,8 +473,6 @@ int lx_buffer_ask(struct lx6464es *chip, u32 pipe, int is_capture,
                  u32 *r_needed, u32 *r_freed, u32 *size_array)
 {
        int err;
-       unsigned long flags;
-
        u32 pipe_cmd = PIPE_INFO_TO_CMD(is_capture, pipe);
 
 #ifdef CONFIG_SND_DEBUG
@@ -493,7 +483,7 @@ int lx_buffer_ask(struct lx6464es *chip, u32 pipe, int is_capture,
        *r_needed = 0;
        *r_freed = 0;
 
-       spin_lock_irqsave(&chip->msg_lock, flags);
+       mutex_lock(&chip->msg_lock);
        lx_message_init(&chip->rmh, CMD_08_ASK_BUFFERS);
 
        chip->rmh.cmd[0] |= pipe_cmd;
@@ -527,7 +517,7 @@ int lx_buffer_ask(struct lx6464es *chip, u32 pipe, int is_capture,
                }
        }
 
-       spin_unlock_irqrestore(&chip->msg_lock, flags);
+       mutex_unlock(&chip->msg_lock);
        return err;
 }
 
@@ -535,36 +525,32 @@ int lx_buffer_ask(struct lx6464es *chip, u32 pipe, int is_capture,
 int lx_pipe_stop(struct lx6464es *chip, u32 pipe, int is_capture)
 {
        int err;
-       unsigned long flags;
-
        u32 pipe_cmd = PIPE_INFO_TO_CMD(is_capture, pipe);
 
-       spin_lock_irqsave(&chip->msg_lock, flags);
+       mutex_lock(&chip->msg_lock);
        lx_message_init(&chip->rmh, CMD_09_STOP_PIPE);
 
        chip->rmh.cmd[0] |= pipe_cmd;
 
        err = lx_message_send_atomic(chip, &chip->rmh);
 
-       spin_unlock_irqrestore(&chip->msg_lock, flags);
+       mutex_unlock(&chip->msg_lock);
        return err;
 }
 
 static int lx_pipe_toggle_state(struct lx6464es *chip, u32 pipe, int is_capture)
 {
        int err;
-       unsigned long flags;
-
        u32 pipe_cmd = PIPE_INFO_TO_CMD(is_capture, pipe);
 
-       spin_lock_irqsave(&chip->msg_lock, flags);
+       mutex_lock(&chip->msg_lock);
        lx_message_init(&chip->rmh, CMD_0B_TOGGLE_PIPE_STATE);
 
        chip->rmh.cmd[0] |= pipe_cmd;
 
        err = lx_message_send_atomic(chip, &chip->rmh);
 
-       spin_unlock_irqrestore(&chip->msg_lock, flags);
+       mutex_unlock(&chip->msg_lock);
        return err;
 }
 
@@ -600,11 +586,9 @@ int lx_pipe_sample_count(struct lx6464es *chip, u32 pipe, int is_capture,
                         u64 *rsample_count)
 {
        int err;
-       unsigned long flags;
-
        u32 pipe_cmd = PIPE_INFO_TO_CMD(is_capture, pipe);
 
-       spin_lock_irqsave(&chip->msg_lock, flags);
+       mutex_lock(&chip->msg_lock);
        lx_message_init(&chip->rmh, CMD_0A_GET_PIPE_SPL_COUNT);
 
        chip->rmh.cmd[0] |= pipe_cmd;
@@ -621,18 +605,16 @@ int lx_pipe_sample_count(struct lx6464es *chip, u32 pipe, int is_capture,
                        + chip->rmh.stat[1]; /* lo part */
        }
 
-       spin_unlock_irqrestore(&chip->msg_lock, flags);
+       mutex_unlock(&chip->msg_lock);
        return err;
 }
 
 int lx_pipe_state(struct lx6464es *chip, u32 pipe, int is_capture, u16 *rstate)
 {
        int err;
-       unsigned long flags;
-
        u32 pipe_cmd = PIPE_INFO_TO_CMD(is_capture, pipe);
 
-       spin_lock_irqsave(&chip->msg_lock, flags);
+       mutex_lock(&chip->msg_lock);
        lx_message_init(&chip->rmh, CMD_0A_GET_PIPE_SPL_COUNT);
 
        chip->rmh.cmd[0] |= pipe_cmd;
@@ -644,7 +626,7 @@ int lx_pipe_state(struct lx6464es *chip, u32 pipe, int is_capture, u16 *rstate)
        else
                *rstate = (chip->rmh.stat[0] >> PSTATE_OFFSET) & 0x0F;
 
-       spin_unlock_irqrestore(&chip->msg_lock, flags);
+       mutex_unlock(&chip->msg_lock);
        return err;
 }
 
@@ -686,18 +668,16 @@ int lx_stream_set_state(struct lx6464es *chip, u32 pipe,
                               int is_capture, enum stream_state_t state)
 {
        int err;
-       unsigned long flags;
-
        u32 pipe_cmd = PIPE_INFO_TO_CMD(is_capture, pipe);
 
-       spin_lock_irqsave(&chip->msg_lock, flags);
+       mutex_lock(&chip->msg_lock);
        lx_message_init(&chip->rmh, CMD_13_SET_STREAM_STATE);
 
        chip->rmh.cmd[0] |= pipe_cmd;
        chip->rmh.cmd[0] |= state;
 
        err = lx_message_send_atomic(chip, &chip->rmh);
-       spin_unlock_irqrestore(&chip->msg_lock, flags);
+       mutex_unlock(&chip->msg_lock);
 
        return err;
 }
@@ -706,17 +686,14 @@ int lx_stream_set_format(struct lx6464es *chip, struct snd_pcm_runtime *runtime,
                         u32 pipe, int is_capture)
 {
        int err;
-       unsigned long flags;
-
        u32 pipe_cmd = PIPE_INFO_TO_CMD(is_capture, pipe);
-
        u32 channels = runtime->channels;
 
        if (runtime->channels != channels)
                dev_err(chip->card->dev, "channel count mismatch: %d vs %d",
                           runtime->channels, channels);
 
-       spin_lock_irqsave(&chip->msg_lock, flags);
+       mutex_lock(&chip->msg_lock);
        lx_message_init(&chip->rmh, CMD_0C_DEF_STREAM);
 
        chip->rmh.cmd[0] |= pipe_cmd;
@@ -732,7 +709,7 @@ int lx_stream_set_format(struct lx6464es *chip, struct snd_pcm_runtime *runtime,
        chip->rmh.cmd[0] |= channels-1;
 
        err = lx_message_send_atomic(chip, &chip->rmh);
-       spin_unlock_irqrestore(&chip->msg_lock, flags);
+       mutex_unlock(&chip->msg_lock);
 
        return err;
 }
@@ -741,11 +718,9 @@ int lx_stream_state(struct lx6464es *chip, u32 pipe, int is_capture,
                    int *rstate)
 {
        int err;
-       unsigned long flags;
-
        u32 pipe_cmd = PIPE_INFO_TO_CMD(is_capture, pipe);
 
-       spin_lock_irqsave(&chip->msg_lock, flags);
+       mutex_lock(&chip->msg_lock);
        lx_message_init(&chip->rmh, CMD_0E_GET_STREAM_SPL_COUNT);
 
        chip->rmh.cmd[0] |= pipe_cmd;
@@ -754,7 +729,7 @@ int lx_stream_state(struct lx6464es *chip, u32 pipe, int is_capture,
 
        *rstate = (chip->rmh.stat[0] & SF_START) ? START_STATE : PAUSE_STATE;
 
-       spin_unlock_irqrestore(&chip->msg_lock, flags);
+       mutex_unlock(&chip->msg_lock);
        return err;
 }
 
@@ -762,11 +737,9 @@ int lx_stream_sample_position(struct lx6464es *chip, u32 pipe, int is_capture,
                              u64 *r_bytepos)
 {
        int err;
-       unsigned long flags;
-
        u32 pipe_cmd = PIPE_INFO_TO_CMD(is_capture, pipe);
 
-       spin_lock_irqsave(&chip->msg_lock, flags);
+       mutex_lock(&chip->msg_lock);
        lx_message_init(&chip->rmh, CMD_0E_GET_STREAM_SPL_COUNT);
 
        chip->rmh.cmd[0] |= pipe_cmd;
@@ -777,7 +750,7 @@ int lx_stream_sample_position(struct lx6464es *chip, u32 pipe, int is_capture,
                      << 32)         /* hi part */
                + chip->rmh.stat[1]; /* lo part */
 
-       spin_unlock_irqrestore(&chip->msg_lock, flags);
+       mutex_unlock(&chip->msg_lock);
        return err;
 }
 
@@ -787,11 +760,9 @@ int lx_buffer_give(struct lx6464es *chip, u32 pipe, int is_capture,
                   u32 *r_buffer_index)
 {
        int err;
-       unsigned long flags;
-
        u32 pipe_cmd = PIPE_INFO_TO_CMD(is_capture, pipe);
 
-       spin_lock_irqsave(&chip->msg_lock, flags);
+       mutex_lock(&chip->msg_lock);
        lx_message_init(&chip->rmh, CMD_0F_UPDATE_BUFFER);
 
        chip->rmh.cmd[0] |= pipe_cmd;
@@ -828,7 +799,7 @@ int lx_buffer_give(struct lx6464es *chip, u32 pipe, int is_capture,
                        "lx_buffer_give EB_CMD_REFUSED\n");
 
  done:
-       spin_unlock_irqrestore(&chip->msg_lock, flags);
+       mutex_unlock(&chip->msg_lock);
        return err;
 }
 
@@ -836,11 +807,9 @@ int lx_buffer_free(struct lx6464es *chip, u32 pipe, int is_capture,
                   u32 *r_buffer_size)
 {
        int err;
-       unsigned long flags;
-
        u32 pipe_cmd = PIPE_INFO_TO_CMD(is_capture, pipe);
 
-       spin_lock_irqsave(&chip->msg_lock, flags);
+       mutex_lock(&chip->msg_lock);
        lx_message_init(&chip->rmh, CMD_11_CANCEL_BUFFER);
 
        chip->rmh.cmd[0] |= pipe_cmd;
@@ -852,7 +821,7 @@ int lx_buffer_free(struct lx6464es *chip, u32 pipe, int is_capture,
        if (err == 0)
                *r_buffer_size = chip->rmh.stat[0]  & MASK_DATA_SIZE;
 
-       spin_unlock_irqrestore(&chip->msg_lock, flags);
+       mutex_unlock(&chip->msg_lock);
        return err;
 }
 
@@ -860,11 +829,9 @@ int lx_buffer_cancel(struct lx6464es *chip, u32 pipe, int is_capture,
                     u32 buffer_index)
 {
        int err;
-       unsigned long flags;
-
        u32 pipe_cmd = PIPE_INFO_TO_CMD(is_capture, pipe);
 
-       spin_lock_irqsave(&chip->msg_lock, flags);
+       mutex_lock(&chip->msg_lock);
        lx_message_init(&chip->rmh, CMD_11_CANCEL_BUFFER);
 
        chip->rmh.cmd[0] |= pipe_cmd;
@@ -872,7 +839,7 @@ int lx_buffer_cancel(struct lx6464es *chip, u32 pipe, int is_capture,
 
        err = lx_message_send_atomic(chip, &chip->rmh);
 
-       spin_unlock_irqrestore(&chip->msg_lock, flags);
+       mutex_unlock(&chip->msg_lock);
        return err;
 }
 
@@ -885,12 +852,10 @@ int lx_buffer_cancel(struct lx6464es *chip, u32 pipe, int is_capture,
 int lx_level_unmute(struct lx6464es *chip, int is_capture, int unmute)
 {
        int err;
-       unsigned long flags;
-
        /* bit set to 1: channel muted */
        u64 mute_mask = unmute ? 0 : 0xFFFFFFFFFFFFFFFFLLU;
 
-       spin_lock_irqsave(&chip->msg_lock, flags);
+       mutex_lock(&chip->msg_lock);
        lx_message_init(&chip->rmh, CMD_0D_SET_MUTE);
 
        chip->rmh.cmd[0] |= PIPE_INFO_TO_CMD(is_capture, 0);
@@ -904,7 +869,7 @@ int lx_level_unmute(struct lx6464es *chip, int is_capture, int unmute)
 
        err = lx_message_send_atomic(chip, &chip->rmh);
 
-       spin_unlock_irqrestore(&chip->msg_lock, flags);
+       mutex_unlock(&chip->msg_lock);
        return err;
 }
 
@@ -931,10 +896,9 @@ int lx_level_peaks(struct lx6464es *chip, int is_capture, int channels,
                   u32 *r_levels)
 {
        int err = 0;
-       unsigned long flags;
        int i;
-       spin_lock_irqsave(&chip->msg_lock, flags);
 
+       mutex_lock(&chip->msg_lock);
        for (i = 0; i < channels; i += 4) {
                u32 s0, s1, s2, s3;
 
@@ -959,7 +923,7 @@ int lx_level_peaks(struct lx6464es *chip, int is_capture, int channels,
                r_levels += 4;
        }
 
-       spin_unlock_irqrestore(&chip->msg_lock, flags);
+       mutex_unlock(&chip->msg_lock);
        return err;
 }
 
@@ -1075,7 +1039,6 @@ static int lx_interrupt_request_new_buffer(struct lx6464es *chip,
        struct snd_pcm_substream *substream = lx_stream->stream;
        const unsigned int is_capture = lx_stream->is_capture;
        int err;
-       unsigned long flags;
 
        const u32 channels = substream->runtime->channels;
        const u32 bytes_per_frame = channels * 3;
@@ -1095,7 +1058,7 @@ static int lx_interrupt_request_new_buffer(struct lx6464es *chip,
 
        dev_dbg(chip->card->dev, "->lx_interrupt_request_new_buffer\n");
 
-       spin_lock_irqsave(&chip->lock, flags);
+       mutex_lock(&chip->lock);
 
        err = lx_buffer_ask(chip, 0, is_capture, &needed, &freed, size_array);
        dev_dbg(chip->card->dev,
@@ -1109,85 +1072,28 @@ static int lx_interrupt_request_new_buffer(struct lx6464es *chip,
                    buffer_index, (unsigned long)buf, period_bytes);
 
        lx_stream->frame_pos = next_pos;
-       spin_unlock_irqrestore(&chip->lock, flags);
+       mutex_unlock(&chip->lock);
 
        return err;
 }
 
-void lx_tasklet_playback(unsigned long data)
-{
-       struct lx6464es *chip = (struct lx6464es *)data;
-       struct lx_stream *lx_stream = &chip->playback_stream;
-       int err;
-
-       dev_dbg(chip->card->dev, "->lx_tasklet_playback\n");
-
-       err = lx_interrupt_request_new_buffer(chip, lx_stream);
-       if (err < 0)
-               dev_err(chip->card->dev,
-                          "cannot request new buffer for playback\n");
-
-       snd_pcm_period_elapsed(lx_stream->stream);
-}
-
-void lx_tasklet_capture(unsigned long data)
-{
-       struct lx6464es *chip = (struct lx6464es *)data;
-       struct lx_stream *lx_stream = &chip->capture_stream;
-       int err;
-
-       dev_dbg(chip->card->dev, "->lx_tasklet_capture\n");
-       err = lx_interrupt_request_new_buffer(chip, lx_stream);
-       if (err < 0)
-               dev_err(chip->card->dev,
-                          "cannot request new buffer for capture\n");
-
-       snd_pcm_period_elapsed(lx_stream->stream);
-}
-
-
-
-static int lx_interrupt_handle_audio_transfer(struct lx6464es *chip,
-                                             u64 notified_in_pipe_mask,
-                                             u64 notified_out_pipe_mask)
-{
-       int err = 0;
-
-       if (notified_in_pipe_mask) {
-               dev_dbg(chip->card->dev,
-                       "requesting audio transfer for capture\n");
-               tasklet_hi_schedule(&chip->tasklet_capture);
-       }
-
-       if (notified_out_pipe_mask) {
-               dev_dbg(chip->card->dev,
-                       "requesting audio transfer for playback\n");
-               tasklet_hi_schedule(&chip->tasklet_playback);
-       }
-
-       return err;
-}
-
-
 irqreturn_t lx_interrupt(int irq, void *dev_id)
 {
        struct lx6464es *chip = dev_id;
        int async_pending, async_escmd;
        u32 irqsrc;
-
-       spin_lock(&chip->lock);
+       bool wake_thread = false;
 
        dev_dbg(chip->card->dev,
                "**************************************************\n");
 
        if (!lx_interrupt_ack(chip, &irqsrc, &async_pending, &async_escmd)) {
-               spin_unlock(&chip->lock);
                dev_dbg(chip->card->dev, "IRQ_NONE\n");
                return IRQ_NONE; /* this device did not cause the interrupt */
        }
 
        if (irqsrc & MASK_SYS_STATUS_CMD_DONE)
-               goto exit;
+               return IRQ_HANDLED;
 
        if (irqsrc & MASK_SYS_STATUS_EOBI)
                dev_dbg(chip->card->dev, "interrupt: EOBI\n");
@@ -1202,27 +1108,8 @@ irqreturn_t lx_interrupt(int irq, void *dev_id)
                dev_dbg(chip->card->dev, "interrupt: ORUN\n");
 
        if (async_pending) {
-               u64 notified_in_pipe_mask = 0;
-               u64 notified_out_pipe_mask = 0;
-               int freq_changed;
-               int err;
-
-               /* handle async events */
-               err = lx_interrupt_handle_async_events(chip, irqsrc,
-                                                      &freq_changed,
-                                                      &notified_in_pipe_mask,
-                                                      &notified_out_pipe_mask);
-               if (err)
-                       dev_err(chip->card->dev,
-                                  "error handling async events\n");
-
-               err = lx_interrupt_handle_audio_transfer(chip,
-                                                        notified_in_pipe_mask,
-                                                        notified_out_pipe_mask
-                       );
-               if (err)
-                       dev_err(chip->card->dev,
-                                  "error during audio transfer\n");
+               wake_thread = true;
+               chip->irqsrc = irqsrc;
        }
 
        if (async_escmd) {
@@ -1235,9 +1122,50 @@ irqreturn_t lx_interrupt(int irq, void *dev_id)
                dev_dbg(chip->card->dev, "interrupt requests escmd handling\n");
        }
 
-exit:
-       spin_unlock(&chip->lock);
-       return IRQ_HANDLED;     /* this device caused the interrupt */
+       return wake_thread ? IRQ_WAKE_THREAD : IRQ_HANDLED;
+}
+
+irqreturn_t lx_threaded_irq(int irq, void *dev_id)
+{
+       struct lx6464es *chip = dev_id;
+       u64 notified_in_pipe_mask = 0;
+       u64 notified_out_pipe_mask = 0;
+       int freq_changed;
+       int err;
+
+       /* handle async events */
+       err = lx_interrupt_handle_async_events(chip, chip->irqsrc,
+                                              &freq_changed,
+                                              &notified_in_pipe_mask,
+                                              &notified_out_pipe_mask);
+       if (err)
+               dev_err(chip->card->dev, "error handling async events\n");
+
+       if (notified_in_pipe_mask) {
+               struct lx_stream *lx_stream = &chip->capture_stream;
+
+               dev_dbg(chip->card->dev,
+                       "requesting audio transfer for capture\n");
+               err = lx_interrupt_request_new_buffer(chip, lx_stream);
+               if (err < 0)
+                       dev_err(chip->card->dev,
+                               "cannot request new buffer for capture\n");
+               snd_pcm_period_elapsed(lx_stream->stream);
+       }
+
+       if (notified_out_pipe_mask) {
+               struct lx_stream *lx_stream = &chip->playback_stream;
+
+               dev_dbg(chip->card->dev,
+                       "requesting audio transfer for playback\n");
+               err = lx_interrupt_request_new_buffer(chip, lx_stream);
+               if (err < 0)
+                       dev_err(chip->card->dev,
+                               "cannot request new buffer for playback\n");
+               snd_pcm_period_elapsed(lx_stream->stream);
+       }
+
+       return IRQ_HANDLED;
 }
 
 
index 5ec5e04da1a5a02f2008b070c76e24fe3964765e..0cc140ca98e3d845298b8f616c55328ddd8e1174 100644 (file)
@@ -181,12 +181,10 @@ int lx_level_peaks(struct lx6464es *chip, int is_capture, int channels,
 
 /* interrupt handling */
 irqreturn_t lx_interrupt(int irq, void *dev_id);
+irqreturn_t lx_threaded_irq(int irq, void *dev_id);
 void lx_irq_enable(struct lx6464es *chip);
 void lx_irq_disable(struct lx6464es *chip);
 
-void lx_tasklet_capture(unsigned long data);
-void lx_tasklet_playback(unsigned long data);
-
 
 /* Stream Format Header Defines (for LIN and IEEE754) */
 #define HEADER_FMT_BASE                HEADER_FMT_BASE_LIN
index 75fc342cff2a842cb296788262dd674c9f51f8fb..1faf47e81570f889c5800165402a6c4cbea745d4 100644 (file)
@@ -986,6 +986,7 @@ static int snd_mixart_pcm_analog(struct snd_mixart *chip)
        snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_mixart_capture_ops);
 
        pcm->info_flags = 0;
+       pcm->nonatomic = true;
        strcpy(pcm->name, name);
 
        preallocate_buffers(chip, pcm);
@@ -1018,6 +1019,7 @@ static int snd_mixart_pcm_digital(struct snd_mixart *chip)
        snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_mixart_capture_ops);
 
        pcm->info_flags = 0;
+       pcm->nonatomic = true;
        strcpy(pcm->name, name);
 
        preallocate_buffers(chip, pcm);
@@ -1303,8 +1305,9 @@ static int snd_mixart_probe(struct pci_dev *pci,
                }
        }
 
-       if (request_irq(pci->irq, snd_mixart_interrupt, IRQF_SHARED,
-                       KBUILD_MODNAME, mgr)) {
+       if (request_threaded_irq(pci->irq, snd_mixart_interrupt,
+                                snd_mixart_threaded_irq, IRQF_SHARED,
+                                KBUILD_MODNAME, mgr)) {
                dev_err(&pci->dev, "unable to grab IRQ %d\n", pci->irq);
                snd_mixart_free(mgr);
                return -EBUSY;
@@ -1314,24 +1317,18 @@ static int snd_mixart_probe(struct pci_dev *pci,
        sprintf(mgr->shortname, "Digigram miXart");
        sprintf(mgr->longname, "%s at 0x%lx & 0x%lx, irq %i", mgr->shortname, mgr->mem[0].phys, mgr->mem[1].phys, mgr->irq);
 
-       /* ISR spinlock  */
-       spin_lock_init(&mgr->lock);
-
        /* init mailbox  */
        mgr->msg_fifo_readptr = 0;
        mgr->msg_fifo_writeptr = 0;
 
-       spin_lock_init(&mgr->msg_lock);
-       mutex_init(&mgr->msg_mutex);
+       mutex_init(&mgr->lock);
+       mutex_init(&mgr->msg_lock);
        init_waitqueue_head(&mgr->msg_sleep);
        atomic_set(&mgr->msg_processed, 0);
 
        /* init setup mutex*/
        mutex_init(&mgr->setup_mutex);
 
-       /* init message taslket */
-       tasklet_init(&mgr->msg_taskq, snd_mixart_msg_tasklet, (unsigned long) mgr);
-
        /* card assignment */
        mgr->num_cards = MIXART_MAX_CARDS; /* 4  FIXME: configurable? */
        for (i = 0; i < mgr->num_cards; i++) {
index 561634d5c0076aee392e022aa53d7745b251e4dc..0cc17e0ea34a4d19b3558ff18b2120b84e659490 100644 (file)
@@ -78,22 +78,18 @@ struct mixart_mgr {
        char shortname[32];         /* short name of this soundcard */
        char longname[80];          /* name of this soundcard */
 
-       /* message tasklet */
-       struct tasklet_struct msg_taskq;
-
        /* one and only blocking message or notification may be pending  */
        u32 pending_event;
        wait_queue_head_t msg_sleep;
 
-       /* messages stored for tasklet */
+       /* messages fifo */
        u32 msg_fifo[MSG_FIFO_SIZE];
        int msg_fifo_readptr;
        int msg_fifo_writeptr;
        atomic_t msg_processed;       /* number of messages to be processed in takslet */
 
-       spinlock_t lock;              /* interrupt spinlock */
-       spinlock_t msg_lock;          /* mailbox spinlock */
-       struct mutex msg_mutex;   /* mutex for blocking_requests */
+       struct mutex lock;              /* interrupt lock */
+       struct mutex msg_lock;          /* mailbox lock */
 
        struct mutex setup_mutex; /* mutex used in hw_params, open and close */
 
index 84f67450924e55fec906cb546151ad32ae9e7d28..fe80313674d9ce7e30ba9cc1b2278dfc521d9089 100644 (file)
@@ -76,7 +76,6 @@ static int retrieve_msg_frame(struct mixart_mgr *mgr, u32 *msg_frame)
 static int get_msg(struct mixart_mgr *mgr, struct mixart_msg *resp,
                   u32 msg_frame_address )
 {
-       unsigned long flags;
        u32  headptr;
        u32  size;
        int  err;
@@ -84,7 +83,7 @@ static int get_msg(struct mixart_mgr *mgr, struct mixart_msg *resp,
        unsigned int i;
 #endif
 
-       spin_lock_irqsave(&mgr->msg_lock, flags);
+       mutex_lock(&mgr->msg_lock);
        err = 0;
 
        /* copy message descriptor from miXart to driver */
@@ -133,7 +132,7 @@ static int get_msg(struct mixart_mgr *mgr, struct mixart_msg *resp,
        writel_be(headptr, MIXART_MEM(mgr, MSG_OUTBOUND_FREE_HEAD));
 
  _clean_exit:
-       spin_unlock_irqrestore(&mgr->msg_lock, flags);
+       mutex_unlock(&mgr->msg_lock);
 
        return err;
 }
@@ -243,28 +242,24 @@ int snd_mixart_send_msg(struct mixart_mgr *mgr, struct mixart_msg *request, int
        wait_queue_t wait;
        long timeout;
 
-       mutex_lock(&mgr->msg_mutex);
-
        init_waitqueue_entry(&wait, current);
 
-       spin_lock_irq(&mgr->msg_lock);
+       mutex_lock(&mgr->msg_lock);
        /* send the message */
        err = send_msg(mgr, request, max_resp_size, 1, &msg_frame);  /* send and mark the answer pending */
        if (err) {
-               spin_unlock_irq(&mgr->msg_lock);
-               mutex_unlock(&mgr->msg_mutex);
+               mutex_unlock(&mgr->msg_lock);
                return err;
        }
 
        set_current_state(TASK_UNINTERRUPTIBLE);
        add_wait_queue(&mgr->msg_sleep, &wait);
-       spin_unlock_irq(&mgr->msg_lock);
+       mutex_unlock(&mgr->msg_lock);
        timeout = schedule_timeout(MSG_TIMEOUT_JIFFIES);
        remove_wait_queue(&mgr->msg_sleep, &wait);
 
        if (! timeout) {
                /* error - no ack */
-               mutex_unlock(&mgr->msg_mutex);
                dev_err(&mgr->pci->dev,
                        "error: no response on msg %x\n", msg_frame);
                return -EIO;
@@ -281,7 +276,6 @@ int snd_mixart_send_msg(struct mixart_mgr *mgr, struct mixart_msg *request, int
        if( request->message_id != resp.message_id )
                dev_err(&mgr->pci->dev, "RESPONSE ERROR!\n");
 
-       mutex_unlock(&mgr->msg_mutex);
        return err;
 }
 
@@ -300,34 +294,29 @@ int snd_mixart_send_msg_wait_notif(struct mixart_mgr *mgr,
        if (snd_BUG_ON(notif_event & MSG_CANCEL_NOTIFY_MASK))
                return -EINVAL;
 
-       mutex_lock(&mgr->msg_mutex);
-
        init_waitqueue_entry(&wait, current);
 
-       spin_lock_irq(&mgr->msg_lock);
+       mutex_lock(&mgr->msg_lock);
        /* send the message */
        err = send_msg(mgr, request, MSG_DEFAULT_SIZE, 1, &notif_event);  /* send and mark the notification event pending */
        if(err) {
-               spin_unlock_irq(&mgr->msg_lock);
-               mutex_unlock(&mgr->msg_mutex);
+               mutex_unlock(&mgr->msg_lock);
                return err;
        }
 
        set_current_state(TASK_UNINTERRUPTIBLE);
        add_wait_queue(&mgr->msg_sleep, &wait);
-       spin_unlock_irq(&mgr->msg_lock);
+       mutex_unlock(&mgr->msg_lock);
        timeout = schedule_timeout(MSG_TIMEOUT_JIFFIES);
        remove_wait_queue(&mgr->msg_sleep, &wait);
 
        if (! timeout) {
                /* error - no ack */
-               mutex_unlock(&mgr->msg_mutex);
                dev_err(&mgr->pci->dev,
                        "error: notification %x not received\n", notif_event);
                return -EIO;
        }
 
-       mutex_unlock(&mgr->msg_mutex);
        return 0;
 }
 
@@ -335,13 +324,12 @@ int snd_mixart_send_msg_wait_notif(struct mixart_mgr *mgr,
 int snd_mixart_send_msg_nonblock(struct mixart_mgr *mgr, struct mixart_msg *request)
 {
        u32 message_frame;
-       unsigned long flags;
        int err;
 
        /* just send the message (do not mark it as a pending one) */
-       spin_lock_irqsave(&mgr->msg_lock, flags);
+       mutex_lock(&mgr->msg_lock);
        err = send_msg(mgr, request, MSG_DEFAULT_SIZE, 0, &message_frame);
-       spin_unlock_irqrestore(&mgr->msg_lock, flags);
+       mutex_unlock(&mgr->msg_lock);
 
        /* the answer will be handled by snd_struct mixart_msgasklet()  */
        atomic_inc(&mgr->msg_processed);
@@ -350,19 +338,16 @@ int snd_mixart_send_msg_nonblock(struct mixart_mgr *mgr, struct mixart_msg *requ
 }
 
 
-/* common buffer of tasklet and interrupt to send/receive messages */
+/* common buffer of interrupt to send/receive messages */
 static u32 mixart_msg_data[MSG_DEFAULT_SIZE / 4];
 
 
-void snd_mixart_msg_tasklet(unsigned long arg)
+static void snd_mixart_process_msg(struct mixart_mgr *mgr)
 {
-       struct mixart_mgr *mgr = ( struct mixart_mgr*)(arg);
        struct mixart_msg resp;
        u32 msg, addr, type;
        int err;
 
-       spin_lock(&mgr->lock);
-
        while (mgr->msg_fifo_readptr != mgr->msg_fifo_writeptr) {
                msg = mgr->msg_fifo[mgr->msg_fifo_readptr];
                mgr->msg_fifo_readptr++;
@@ -381,7 +366,7 @@ void snd_mixart_msg_tasklet(unsigned long arg)
                        err = get_msg(mgr, &resp, addr);
                        if( err < 0 ) {
                                dev_err(&mgr->pci->dev,
-                                       "tasklet: error(%d) reading mf %x\n",
+                                       "error(%d) reading mf %x\n",
                                        err, msg);
                                break;
                        }
@@ -393,12 +378,12 @@ void snd_mixart_msg_tasklet(unsigned long arg)
                        case MSG_STREAM_STOP_OUTPUT_STAGE_PACKET:
                                if(mixart_msg_data[0])
                                        dev_err(&mgr->pci->dev,
-                                               "tasklet : error MSG_STREAM_ST***_***PUT_STAGE_PACKET status=%x\n",
+                                               "error MSG_STREAM_ST***_***PUT_STAGE_PACKET status=%x\n",
                                                mixart_msg_data[0]);
                                break;
                        default:
                                dev_dbg(&mgr->pci->dev,
-                                       "tasklet received mf(%x) : msg_id(%x) uid(%x, %x) size(%zd)\n",
+                                       "received mf(%x) : msg_id(%x) uid(%x, %x) size(%zd)\n",
                                           msg, resp.message_id, resp.uid.object_id, resp.uid.desc, resp.size);
                                break;
                        }
@@ -409,7 +394,7 @@ void snd_mixart_msg_tasklet(unsigned long arg)
                        /* get_msg() necessary */
                default:
                        dev_err(&mgr->pci->dev,
-                               "tasklet doesn't know what to do with message %x\n",
+                               "doesn't know what to do with message %x\n",
                                msg);
                } /* switch type */
 
@@ -417,26 +402,17 @@ void snd_mixart_msg_tasklet(unsigned long arg)
                atomic_dec(&mgr->msg_processed);
 
        } /* while there is a msg in fifo */
-
-       spin_unlock(&mgr->lock);
 }
 
 
 irqreturn_t snd_mixart_interrupt(int irq, void *dev_id)
 {
        struct mixart_mgr *mgr = dev_id;
-       int err;
-       struct mixart_msg resp;
-
-       u32 msg;
        u32 it_reg;
 
-       spin_lock(&mgr->lock);
-
        it_reg = readl_le(MIXART_REG(mgr, MIXART_PCI_OMISR_OFFSET));
        if( !(it_reg & MIXART_OIDI) ) {
                /* this device did not cause the interrupt */
-               spin_unlock(&mgr->lock);
                return IRQ_NONE;
        }
 
@@ -450,6 +426,17 @@ irqreturn_t snd_mixart_interrupt(int irq, void *dev_id)
        /* clear interrupt */
        writel_le( MIXART_OIDI, MIXART_REG(mgr, MIXART_PCI_OMISR_OFFSET) );
 
+       return IRQ_WAKE_THREAD;
+}
+
+irqreturn_t snd_mixart_threaded_irq(int irq, void *dev_id)
+{
+       struct mixart_mgr *mgr = dev_id;
+       int err;
+       struct mixart_msg resp;
+       u32 msg;
+
+       mutex_lock(&mgr->lock);
        /* process interrupt */
        while (retrieve_msg_frame(mgr, &msg)) {
 
@@ -518,9 +505,9 @@ irqreturn_t snd_mixart_interrupt(int irq, void *dev_id)
                                                stream->buf_period_frag = (u32)( sample_count - stream->abs_period_elapsed );
 
                                                if(elapsed) {
-                                                       spin_unlock(&mgr->lock);
+                                                       mutex_unlock(&mgr->lock);
                                                        snd_pcm_period_elapsed(stream->substream);
-                                                       spin_lock(&mgr->lock);
+                                                       mutex_lock(&mgr->lock);
                                                }
                                        }
                                }
@@ -556,7 +543,7 @@ irqreturn_t snd_mixart_interrupt(int irq, void *dev_id)
                        /* no break, continue ! */
                case MSG_TYPE_ANSWER:
                        /* answer or notification to a message we are waiting for*/
-                       spin_lock(&mgr->msg_lock);
+                       mutex_lock(&mgr->msg_lock);
                        if( (msg & ~MSG_TYPE_MASK) == mgr->pending_event ) {
                                wake_up(&mgr->msg_sleep);
                                mgr->pending_event = 0;
@@ -566,9 +553,9 @@ irqreturn_t snd_mixart_interrupt(int irq, void *dev_id)
                                mgr->msg_fifo[mgr->msg_fifo_writeptr] = msg;
                                mgr->msg_fifo_writeptr++;
                                mgr->msg_fifo_writeptr %= MSG_FIFO_SIZE;
-                               tasklet_schedule(&mgr->msg_taskq);
+                               snd_mixart_process_msg(mgr);
                        }
-                       spin_unlock(&mgr->msg_lock);
+                       mutex_unlock(&mgr->msg_lock);
                        break;
                case MSG_TYPE_REQUEST:
                default:
@@ -582,7 +569,7 @@ irqreturn_t snd_mixart_interrupt(int irq, void *dev_id)
        /* allow interrupt again */
        writel_le( MIXART_ALLOW_OUTBOUND_DOORBELL, MIXART_REG( mgr, MIXART_PCI_OMIMR_OFFSET));
 
-       spin_unlock(&mgr->lock);
+       mutex_unlock(&mgr->lock);
 
        return IRQ_HANDLED;
 }
index c919b734756ff3a9b387572d0de08f2a0a937199..d1722e575409b09ab62e5a258d7fed424de13347 100644 (file)
@@ -564,7 +564,7 @@ int  snd_mixart_send_msg_wait_notif(struct mixart_mgr *mgr, struct mixart_msg *r
 int  snd_mixart_send_msg_nonblock(struct mixart_mgr *mgr, struct mixart_msg *request);
 
 irqreturn_t snd_mixart_interrupt(int irq, void *dev_id);
-void snd_mixart_msg_tasklet(unsigned long arg);
+irqreturn_t snd_mixart_threaded_irq(int irq, void *dev_id);
 
 void snd_mixart_reset_board(struct mixart_mgr *mgr);
 
index cc0bcd9f335075b341dba57144fca8a44311adb6..02828240ba15740600a65b2eaf07b3f663c3463b 100644 (file)
@@ -29,6 +29,9 @@
 /* the multichannel DMA channel has a 24-bit counter */
 #define BUFFER_BYTES_MAX_MULTICH       ((1 << 24) * 4)
 
+#define FIFO_BYTES                     256
+#define FIFO_BYTES_MULTICH             1024
+
 #define PERIOD_BYTES_MIN               64
 
 #define DEFAULT_BUFFER_BYTES           (BUFFER_BYTES_MAX / 2)
@@ -60,6 +63,7 @@ static const struct snd_pcm_hardware oxygen_stereo_hardware = {
        .period_bytes_max = BUFFER_BYTES_MAX,
        .periods_min = 1,
        .periods_max = BUFFER_BYTES_MAX / PERIOD_BYTES_MIN,
+       .fifo_size = FIFO_BYTES,
 };
 static const struct snd_pcm_hardware oxygen_multichannel_hardware = {
        .info = SNDRV_PCM_INFO_MMAP |
@@ -87,6 +91,7 @@ static const struct snd_pcm_hardware oxygen_multichannel_hardware = {
        .period_bytes_max = BUFFER_BYTES_MAX_MULTICH,
        .periods_min = 1,
        .periods_max = BUFFER_BYTES_MAX_MULTICH / PERIOD_BYTES_MIN,
+       .fifo_size = FIFO_BYTES_MULTICH,
 };
 static const struct snd_pcm_hardware oxygen_ac97_hardware = {
        .info = SNDRV_PCM_INFO_MMAP |
@@ -106,6 +111,7 @@ static const struct snd_pcm_hardware oxygen_ac97_hardware = {
        .period_bytes_max = BUFFER_BYTES_MAX,
        .periods_min = 1,
        .periods_max = BUFFER_BYTES_MAX / PERIOD_BYTES_MIN,
+       .fifo_size = FIFO_BYTES,
 };
 
 static const struct snd_pcm_hardware *const oxygen_hardware[PCM_COUNT] = {
@@ -141,6 +147,10 @@ static int oxygen_open(struct snd_pcm_substream *substream,
                runtime->hw.rates &= ~(SNDRV_PCM_RATE_32000 |
                                       SNDRV_PCM_RATE_64000);
                runtime->hw.rate_min = 44100;
+               /* fall through */
+       case PCM_A:
+       case PCM_B:
+               runtime->hw.fifo_size = 0;
                break;
        case PCM_MULTICH:
                runtime->hw.channels_max = chip->model.dac_channels_pcm;
index 7b317a28a19ca3cfb43725947ad54db2a27d2d8d..83de6fb01021e6053f15b9e2ad5cdb15bddcb88c 100644 (file)
@@ -52,6 +52,7 @@ static const struct pci_device_id xonar_ids[] = {
        { OXYGEN_PCI_SUBID(0x1043, 0x835d) },
        { OXYGEN_PCI_SUBID(0x1043, 0x835e) },
        { OXYGEN_PCI_SUBID(0x1043, 0x838e) },
+       { OXYGEN_PCI_SUBID(0x1043, 0x8428) },
        { OXYGEN_PCI_SUBID(0x1043, 0x8522) },
        { OXYGEN_PCI_SUBID(0x1043, 0x85f4) },
        { OXYGEN_PCI_SUBID_BROKEN_EEPROM },
index e0260593166936a70c15f5e12cd0829e519fbbb1..24109d37ca09783e09b243044506c852d4cee94d 100644 (file)
 #define GPIO_ST_MAGIC          0x0040
 #define GPIO_ST_HP             0x0080
 
+#define GPIO_XENSE_OUTPUT_ENABLE       (0x0001 | 0x0010 | 0x0020)
+#define GPIO_XENSE_SPEAKERS            0x0080
+
 #define I2C_DEVICE_PCM1796(i)  (0x98 + ((i) << 1))     /* 10011, ii, /W=0 */
 #define I2C_DEVICE_CS2000      0x9c                    /* 100111, 0, /W=0 */
 
@@ -419,6 +422,7 @@ static void xonar_st_init_common(struct oxygen *chip)
 
        data->generic.output_enable_bit = GPIO_ST_OUTPUT_ENABLE;
        data->dacs = chip->model.dac_channels_mixer / 2;
+       data->h6 = chip->model.dac_channels_mixer > 2;
        data->hp_gain_offset = 2*-18;
 
        pcm1796_init(chip);
@@ -499,6 +503,51 @@ static void xonar_stx_init(struct oxygen *chip)
        xonar_st_init_common(chip);
 }
 
+static void xonar_xense_init(struct oxygen *chip)
+{
+       struct xonar_pcm179x *data = chip->model_data;
+
+       data->generic.ext_power_reg = OXYGEN_GPI_DATA;
+       data->generic.ext_power_int_reg = OXYGEN_GPI_INTERRUPT_MASK;
+       data->generic.ext_power_bit = GPI_EXT_POWER;
+       xonar_init_ext_power(chip);
+
+       data->generic.anti_pop_delay = 100;
+       data->has_cs2000 = 1;
+       data->cs2000_regs[CS2000_FUN_CFG_1] = CS2000_REF_CLK_DIV_1;
+
+       oxygen_write16(chip, OXYGEN_I2S_A_FORMAT,
+               OXYGEN_RATE_48000 |
+               OXYGEN_I2S_FORMAT_I2S |
+               OXYGEN_I2S_MCLK(MCLK_512) |
+               OXYGEN_I2S_BITS_16 |
+               OXYGEN_I2S_MASTER |
+               OXYGEN_I2S_BCLK_64);
+
+       xonar_st_init_i2c(chip);
+       cs2000_registers_init(chip);
+
+       data->generic.output_enable_bit = GPIO_XENSE_OUTPUT_ENABLE;
+       data->dacs = 1;
+       data->hp_gain_offset = 2*-18;
+
+       pcm1796_init(chip);
+
+       oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL,
+               GPIO_INPUT_ROUTE | GPIO_ST_HP_REAR |
+               GPIO_ST_MAGIC | GPIO_XENSE_SPEAKERS);
+       oxygen_clear_bits16(chip, OXYGEN_GPIO_DATA,
+               GPIO_INPUT_ROUTE | GPIO_ST_HP_REAR |
+               GPIO_XENSE_SPEAKERS);
+
+       xonar_init_cs53x1(chip);
+       xonar_enable_output(chip);
+
+       snd_component_add(chip->card, "PCM1796");
+       snd_component_add(chip->card, "CS5381");
+       snd_component_add(chip->card, "CS2000");
+}
+
 static void xonar_d2_cleanup(struct oxygen *chip)
 {
        xonar_disable_output(chip);
@@ -795,11 +844,11 @@ static int st_output_switch_put(struct snd_kcontrol *ctl,
 static int st_hp_volume_offset_info(struct snd_kcontrol *ctl,
                                    struct snd_ctl_elem_info *info)
 {
-       static const char *const names[3] = {
-               "< 64 ohms", "64-300 ohms", "300-600 ohms"
+       static const char *const names[4] = {
+               "< 32 ohms", "32-64 ohms", "64-300 ohms", "300-600 ohms"
        };
 
-       return snd_ctl_enum_info(info, 1, 3, names);
+       return snd_ctl_enum_info(info, 1, 4, names);
 }
 
 static int st_hp_volume_offset_get(struct snd_kcontrol *ctl,
@@ -809,12 +858,14 @@ static int st_hp_volume_offset_get(struct snd_kcontrol *ctl,
        struct xonar_pcm179x *data = chip->model_data;
 
        mutex_lock(&chip->mutex);
-       if (data->hp_gain_offset < 2*-6)
+       if (data->hp_gain_offset < 2*-12)
                value->value.enumerated.item[0] = 0;
-       else if (data->hp_gain_offset < 0)
+       else if (data->hp_gain_offset < 2*-6)
                value->value.enumerated.item[0] = 1;
-       else
+       else if (data->hp_gain_offset < 0)
                value->value.enumerated.item[0] = 2;
+       else
+               value->value.enumerated.item[0] = 3;
        mutex_unlock(&chip->mutex);
        return 0;
 }
@@ -823,13 +874,13 @@ static int st_hp_volume_offset_get(struct snd_kcontrol *ctl,
 static int st_hp_volume_offset_put(struct snd_kcontrol *ctl,
                                   struct snd_ctl_elem_value *value)
 {
-       static const s8 offsets[] = { 2*-18, 2*-6, 0 };
+       static const s8 offsets[] = { 2*-18, 2*-12, 2*-6, 0 };
        struct oxygen *chip = ctl->private_data;
        struct xonar_pcm179x *data = chip->model_data;
        s8 offset;
        int changed;
 
-       if (value->value.enumerated.item[0] > 2)
+       if (value->value.enumerated.item[0] > 3)
                return -EINVAL;
        offset = offsets[value->value.enumerated.item[0]];
        mutex_lock(&chip->mutex);
@@ -859,6 +910,67 @@ static const struct snd_kcontrol_new st_controls[] = {
        },
 };
 
+static int xense_output_switch_get(struct snd_kcontrol *ctl,
+                                  struct snd_ctl_elem_value *value)
+{
+       struct oxygen *chip = ctl->private_data;
+       u16 gpio;
+
+       gpio = oxygen_read16(chip, OXYGEN_GPIO_DATA);
+       if (gpio & GPIO_XENSE_SPEAKERS)
+               value->value.enumerated.item[0] = 0;
+       else if (!(gpio & GPIO_XENSE_SPEAKERS) && (gpio & GPIO_ST_HP_REAR))
+               value->value.enumerated.item[0] = 1;
+       else
+               value->value.enumerated.item[0] = 2;
+       return 0;
+}
+
+static int xense_output_switch_put(struct snd_kcontrol *ctl,
+                                  struct snd_ctl_elem_value *value)
+{
+       struct oxygen *chip = ctl->private_data;
+       struct xonar_pcm179x *data = chip->model_data;
+       u16 gpio_old, gpio;
+
+       mutex_lock(&chip->mutex);
+       gpio_old = oxygen_read16(chip, OXYGEN_GPIO_DATA);
+       gpio = gpio_old;
+       switch (value->value.enumerated.item[0]) {
+       case 0:
+               gpio |= GPIO_XENSE_SPEAKERS | GPIO_ST_HP_REAR;
+               break;
+       case 1:
+               gpio = (gpio | GPIO_ST_HP_REAR) & ~GPIO_XENSE_SPEAKERS;
+               break;
+       case 2:
+               gpio &= ~(GPIO_XENSE_SPEAKERS | GPIO_ST_HP_REAR);
+               break;
+       }
+       oxygen_write16(chip, OXYGEN_GPIO_DATA, gpio);
+       data->hp_active = !(gpio & GPIO_XENSE_SPEAKERS);
+       update_pcm1796_volume(chip);
+       mutex_unlock(&chip->mutex);
+       return gpio != gpio_old;
+}
+
+static const struct snd_kcontrol_new xense_controls[] = {
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .name = "Analog Output",
+               .info = st_output_switch_info,
+               .get = xense_output_switch_get,
+               .put = xense_output_switch_put,
+       },
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .name = "Headphones Impedance Playback Enum",
+               .info = st_hp_volume_offset_info,
+               .get = st_hp_volume_offset_get,
+               .put = st_hp_volume_offset_put,
+       },
+};
+
 static void xonar_line_mic_ac97_switch(struct oxygen *chip,
                                       unsigned int reg, unsigned int mute)
 {
@@ -946,6 +1058,23 @@ static int xonar_st_mixer_init(struct oxygen *chip)
        return 0;
 }
 
+static int xonar_xense_mixer_init(struct oxygen *chip)
+{
+       unsigned int i;
+       int err;
+
+       for (i = 0; i < ARRAY_SIZE(xense_controls); ++i) {
+               err = snd_ctl_add(chip->card,
+               snd_ctl_new1(&xense_controls[i], chip));
+               if (err < 0)
+                       return err;
+       }
+       err = add_pcm1796_controls(chip);
+       if (err < 0)
+               return err;
+       return 0;
+}
+
 static void dump_pcm1796_registers(struct oxygen *chip,
                                   struct snd_info_buffer *buffer)
 {
@@ -1140,12 +1269,29 @@ int get_xonar_pcm179x_model(struct oxygen *chip,
                break;
        case 0x85f4:
                chip->model = model_xonar_st;
-               /* TODO: daughterboard support */
-               chip->model.shortname = "Xonar STX II";
+               oxygen_clear_bits16(chip, OXYGEN_GPIO_CONTROL, GPIO_DB_MASK);
+               switch (oxygen_read16(chip, OXYGEN_GPIO_DATA) & GPIO_DB_MASK) {
+               default:
+                       chip->model.shortname = "Xonar STX II";
+                       break;
+               case GPIO_DB_H6:
+                       chip->model.shortname = "Xonar STX II+H6";
+                       chip->model.dac_channels_pcm = 8;
+                       chip->model.dac_channels_mixer = 8;
+                       chip->model.dac_mclks = OXYGEN_MCLKS(256, 128, 128);
+                       break;
+               }
                chip->model.init = xonar_stx_init;
                chip->model.resume = xonar_stx_resume;
                chip->model.set_dac_params = set_pcm1796_params;
                break;
+       case 0x8428:
+               chip->model = model_xonar_st;
+               chip->model.shortname = "Xonar Xense";
+               chip->model.chip = "AV100";
+               chip->model.init = xonar_xense_init;
+               chip->model.mixer_init = xonar_xense_mixer_init;
+               break;
        default:
                return -EINVAL;
        }
index 68a37a7906c121d3e5ebafab2943e198e7cab940..b854fc5e01f51171ff316cb6a320a7a2762e79c4 100644 (file)
@@ -702,13 +702,11 @@ static inline int pcxhr_stream_scheduled_get_pipe(struct pcxhr_stream *stream,
        return 0;
 }
 
-static void pcxhr_trigger_tasklet(unsigned long arg)
+static void pcxhr_start_linked_stream(struct pcxhr_mgr *mgr)
 {
-       unsigned long flags;
        int i, j, err;
        struct pcxhr_pipe *pipe;
        struct snd_pcxhr *chip;
-       struct pcxhr_mgr *mgr = (struct pcxhr_mgr*)(arg);
        int capture_mask = 0;
        int playback_mask = 0;
 
@@ -736,11 +734,11 @@ static void pcxhr_trigger_tasklet(unsigned long arg)
        }
        if (capture_mask == 0 && playback_mask == 0) {
                mutex_unlock(&mgr->setup_mutex);
-               dev_err(&mgr->pci->dev, "pcxhr_trigger_tasklet : no pipes\n");
+               dev_err(&mgr->pci->dev, "pcxhr_start_linked_stream : no pipes\n");
                return;
        }
 
-       dev_dbg(&mgr->pci->dev, "pcxhr_trigger_tasklet : "
+       dev_dbg(&mgr->pci->dev, "pcxhr_start_linked_stream : "
                    "playback_mask=%x capture_mask=%x\n",
                    playback_mask, capture_mask);
 
@@ -748,7 +746,7 @@ static void pcxhr_trigger_tasklet(unsigned long arg)
        err = pcxhr_set_pipe_state(mgr,  playback_mask, capture_mask, 0);
        if (err) {
                mutex_unlock(&mgr->setup_mutex);
-               dev_err(&mgr->pci->dev, "pcxhr_trigger_tasklet : "
+               dev_err(&mgr->pci->dev, "pcxhr_start_linked_stream : "
                           "error stop pipes (P%x C%x)\n",
                           playback_mask, capture_mask);
                return;
@@ -793,7 +791,7 @@ static void pcxhr_trigger_tasklet(unsigned long arg)
        err = pcxhr_set_pipe_state(mgr, playback_mask, capture_mask, 1);
        if (err) {
                mutex_unlock(&mgr->setup_mutex);
-               dev_err(&mgr->pci->dev, "pcxhr_trigger_tasklet : "
+               dev_err(&mgr->pci->dev, "pcxhr_start_linked_stream : "
                           "error start pipes (P%x C%x)\n",
                           playback_mask, capture_mask);
                return;
@@ -802,7 +800,7 @@ static void pcxhr_trigger_tasklet(unsigned long arg)
        /* put the streams into the running state now
         * (increment pointer by interrupt)
         */
-       spin_lock_irqsave(&mgr->lock, flags);
+       mutex_lock(&mgr->lock);
        for ( i =0; i < mgr->num_cards; i++) {
                struct pcxhr_stream *stream;
                chip = mgr->chip[i];
@@ -820,13 +818,13 @@ static void pcxhr_trigger_tasklet(unsigned long arg)
                        }
                }
        }
-       spin_unlock_irqrestore(&mgr->lock, flags);
+       mutex_unlock(&mgr->lock);
 
        mutex_unlock(&mgr->setup_mutex);
 
 #ifdef CONFIG_SND_DEBUG_VERBOSE
        do_gettimeofday(&my_tv2);
-       dev_dbg(&mgr->pci->dev, "***TRIGGER TASKLET*** TIME = %ld (err = %x)\n",
+       dev_dbg(&mgr->pci->dev, "***TRIGGER START*** TIME = %ld (err = %x)\n",
                    (long)(my_tv2.tv_usec - my_tv1.tv_usec), err);
 #endif
 }
@@ -853,7 +851,7 @@ static int pcxhr_trigger(struct snd_pcm_substream *subs, int cmd)
                                        PCXHR_STREAM_STATUS_SCHEDULE_RUN;
                                snd_pcm_trigger_done(s, subs);
                        }
-                       tasklet_schedule(&chip->mgr->trigger_taskq);
+                       pcxhr_start_linked_stream(chip->mgr);
                } else {
                        stream = subs->runtime->private_data;
                        snd_printdd("Only one Substream %c %d\n",
@@ -1127,20 +1125,19 @@ static int pcxhr_close(struct snd_pcm_substream *subs)
 
 static snd_pcm_uframes_t pcxhr_stream_pointer(struct snd_pcm_substream *subs)
 {
-       unsigned long flags;
        u_int32_t timer_period_frag;
        int timer_buf_periods;
        struct snd_pcxhr *chip = snd_pcm_substream_chip(subs);
        struct snd_pcm_runtime *runtime = subs->runtime;
        struct pcxhr_stream *stream  = runtime->private_data;
 
-       spin_lock_irqsave(&chip->mgr->lock, flags);
+       mutex_lock(&chip->mgr->lock);
 
        /* get the period fragment and the nb of periods in the buffer */
        timer_period_frag = stream->timer_period_frag;
        timer_buf_periods = stream->timer_buf_periods;
 
-       spin_unlock_irqrestore(&chip->mgr->lock, flags);
+       mutex_unlock(&chip->mgr->lock);
 
        return (snd_pcm_uframes_t)((timer_buf_periods * runtime->period_size) +
                                   timer_period_frag);
@@ -1181,6 +1178,7 @@ int pcxhr_create_pcm(struct snd_pcxhr *chip)
                snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &pcxhr_ops);
 
        pcm->info_flags = 0;
+       pcm->nonatomic = true;
        strcpy(pcm->name, name);
 
        snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
@@ -1588,8 +1586,9 @@ static int pcxhr_probe(struct pci_dev *pci,
        mgr->pci = pci;
        mgr->irq = -1;
 
-       if (request_irq(pci->irq, pcxhr_interrupt, IRQF_SHARED,
-                       KBUILD_MODNAME, mgr)) {
+       if (request_threaded_irq(pci->irq, pcxhr_interrupt,
+                                pcxhr_threaded_irq, IRQF_SHARED,
+                                KBUILD_MODNAME, mgr)) {
                dev_err(&pci->dev, "unable to grab IRQ %d\n", pci->irq);
                pcxhr_free(mgr);
                return -EBUSY;
@@ -1601,19 +1600,13 @@ static int pcxhr_probe(struct pci_dev *pci,
                mgr->shortname,
                mgr->port[0], mgr->port[1], mgr->port[2], mgr->irq);
 
-       /* ISR spinlock  */
-       spin_lock_init(&mgr->lock);
-       spin_lock_init(&mgr->msg_lock);
+       /* ISR lock  */
+       mutex_init(&mgr->lock);
+       mutex_init(&mgr->msg_lock);
 
        /* init setup mutex*/
        mutex_init(&mgr->setup_mutex);
 
-       /* init taslket */
-       tasklet_init(&mgr->msg_taskq, pcxhr_msg_tasklet,
-                    (unsigned long) mgr);
-       tasklet_init(&mgr->trigger_taskq, pcxhr_trigger_tasklet,
-                    (unsigned long) mgr);
-
        mgr->prmh = kmalloc(sizeof(*mgr->prmh) + 
                            sizeof(u32) * (PCXHR_SIZE_MAX_LONG_STATUS -
                                           PCXHR_SIZE_MAX_STATUS),
index a4c602c451738bb541b2c1ddf20195d429c99000..9e39e509a3ef9375db81b853b8e61983a4de9c9c 100644 (file)
@@ -78,14 +78,10 @@ struct pcxhr_mgr {
        char shortname[32];             /* short name of this soundcard */
        char longname[96];              /* name of this soundcard */
 
-       /* message tasklet */
-       struct tasklet_struct msg_taskq;
        struct pcxhr_rmh *prmh;
-       /* trigger tasklet */
-       struct tasklet_struct trigger_taskq;
 
-       spinlock_t lock;                /* interrupt spinlock */
-       spinlock_t msg_lock;            /* message spinlock */
+       struct mutex lock;              /* interrupt lock */
+       struct mutex msg_lock;          /* message lock */
 
        struct mutex setup_mutex;       /* mutex used in hw_params, open and close */
        struct mutex mixer_mutex;       /* mutex for mixer */
index df9371918601e7cfc23874a0324bd3f287bbc6ec..a584acb61c00f815dce3009f30b794e65f481af3 100644 (file)
@@ -767,11 +767,11 @@ void pcxhr_set_pipe_cmd_params(struct pcxhr_rmh *rmh, int capture,
  */
 int pcxhr_send_msg(struct pcxhr_mgr *mgr, struct pcxhr_rmh *rmh)
 {
-       unsigned long flags;
        int err;
-       spin_lock_irqsave(&mgr->msg_lock, flags);
+
+       mutex_lock(&mgr->msg_lock);
        err = pcxhr_send_msg_nolock(mgr, rmh);
-       spin_unlock_irqrestore(&mgr->msg_lock, flags);
+       mutex_unlock(&mgr->msg_lock);
        return err;
 }
 
@@ -971,17 +971,16 @@ int pcxhr_write_io_num_reg_cont(struct pcxhr_mgr *mgr, unsigned int mask,
                                unsigned int value, int *changed)
 {
        struct pcxhr_rmh rmh;
-       unsigned long flags;
        int err;
 
-       spin_lock_irqsave(&mgr->msg_lock, flags);
+       mutex_lock(&mgr->msg_lock);
        if ((mgr->io_num_reg_cont & mask) == value) {
                dev_dbg(&mgr->pci->dev,
                        "IO_NUM_REG_CONT mask %x already is set to %x\n",
                            mask, value);
                if (changed)
                        *changed = 0;
-               spin_unlock_irqrestore(&mgr->msg_lock, flags);
+               mutex_unlock(&mgr->msg_lock);
                return 0;       /* already programmed */
        }
        pcxhr_init_rmh(&rmh, CMD_ACCESS_IO_WRITE);
@@ -996,7 +995,7 @@ int pcxhr_write_io_num_reg_cont(struct pcxhr_mgr *mgr, unsigned int mask,
                if (changed)
                        *changed = 1;
        }
-       spin_unlock_irqrestore(&mgr->msg_lock, flags);
+       mutex_unlock(&mgr->msg_lock);
        return err;
 }
 
@@ -1043,22 +1042,21 @@ static int pcxhr_handle_async_err(struct pcxhr_mgr *mgr, u32 err,
 }
 
 
-void pcxhr_msg_tasklet(unsigned long arg)
+static void pcxhr_msg_thread(struct pcxhr_mgr *mgr)
 {
-       struct pcxhr_mgr *mgr = (struct pcxhr_mgr *)(arg);
        struct pcxhr_rmh *prmh = mgr->prmh;
        int err;
        int i, j;
 
        if (mgr->src_it_dsp & PCXHR_IRQ_FREQ_CHANGE)
                dev_dbg(&mgr->pci->dev,
-                       "TASKLET : PCXHR_IRQ_FREQ_CHANGE event occurred\n");
+                       "PCXHR_IRQ_FREQ_CHANGE event occurred\n");
        if (mgr->src_it_dsp & PCXHR_IRQ_TIME_CODE)
                dev_dbg(&mgr->pci->dev,
-                       "TASKLET : PCXHR_IRQ_TIME_CODE event occurred\n");
+                       "PCXHR_IRQ_TIME_CODE event occurred\n");
        if (mgr->src_it_dsp & PCXHR_IRQ_NOTIFY)
                dev_dbg(&mgr->pci->dev,
-                       "TASKLET : PCXHR_IRQ_NOTIFY event occurred\n");
+                       "PCXHR_IRQ_NOTIFY event occurred\n");
        if (mgr->src_it_dsp & (PCXHR_IRQ_FREQ_CHANGE | PCXHR_IRQ_TIME_CODE)) {
                /* clear events FREQ_CHANGE and TIME_CODE */
                pcxhr_init_rmh(prmh, CMD_TEST_IT);
@@ -1068,7 +1066,7 @@ void pcxhr_msg_tasklet(unsigned long arg)
        }
        if (mgr->src_it_dsp & PCXHR_IRQ_ASYNC) {
                dev_dbg(&mgr->pci->dev,
-                       "TASKLET : PCXHR_IRQ_ASYNC event occurred\n");
+                       "PCXHR_IRQ_ASYNC event occurred\n");
 
                pcxhr_init_rmh(prmh, CMD_ASYNC);
                prmh->cmd[0] |= 1;      /* add SEL_ASYNC_EVENTS */
@@ -1076,7 +1074,7 @@ void pcxhr_msg_tasklet(unsigned long arg)
                prmh->stat_len = PCXHR_SIZE_MAX_LONG_STATUS;
                err = pcxhr_send_msg(mgr, prmh);
                if (err)
-                       dev_err(&mgr->pci->dev, "ERROR pcxhr_msg_tasklet=%x;\n",
+                       dev_err(&mgr->pci->dev, "ERROR pcxhr_msg_thread=%x;\n",
                                   err);
                i = 1;
                while (i < prmh->stat_len) {
@@ -1220,9 +1218,9 @@ static void pcxhr_update_timer_pos(struct pcxhr_mgr *mgr,
                }
 
                if (elapsed) {
-                       spin_unlock(&mgr->lock);
+                       mutex_unlock(&mgr->lock);
                        snd_pcm_period_elapsed(stream->substream);
-                       spin_lock(&mgr->lock);
+                       mutex_lock(&mgr->lock);
                }
        }
 }
@@ -1231,14 +1229,10 @@ irqreturn_t pcxhr_interrupt(int irq, void *dev_id)
 {
        struct pcxhr_mgr *mgr = dev_id;
        unsigned int reg;
-       int i, j;
-       struct snd_pcxhr *chip;
-
-       spin_lock(&mgr->lock);
+       bool wake_thread = false;
 
        reg = PCXHR_INPL(mgr, PCXHR_PLX_IRQCS);
        if (! (reg & PCXHR_IRQCS_ACTIVE_PCIDB)) {
-               spin_unlock(&mgr->lock);
                /* this device did not cause the interrupt */
                return IRQ_NONE;
        }
@@ -1250,6 +1244,44 @@ irqreturn_t pcxhr_interrupt(int irq, void *dev_id)
        /* timer irq occurred */
        if (reg & PCXHR_IRQ_TIMER) {
                int timer_toggle = reg & PCXHR_IRQ_TIMER;
+               if (timer_toggle == mgr->timer_toggle) {
+                       dev_dbg(&mgr->pci->dev, "ERROR TIMER TOGGLE\n");
+                       mgr->dsp_time_err++;
+               }
+
+               mgr->timer_toggle = timer_toggle;
+               mgr->src_it_dsp = reg;
+               wake_thread = true;
+       }
+
+       /* other irq's handled in the thread */
+       if (reg & PCXHR_IRQ_MASK) {
+               if (reg & PCXHR_IRQ_ASYNC) {
+                       /* as we didn't request any async notifications,
+                        * some kind of xrun error will probably occurred
+                        */
+                       /* better resynchronize all streams next interrupt : */
+                       mgr->dsp_time_last = PCXHR_DSP_TIME_INVALID;
+               }
+               mgr->src_it_dsp = reg;
+               wake_thread = true;
+       }
+#ifdef CONFIG_SND_DEBUG_VERBOSE
+       if (reg & PCXHR_FATAL_DSP_ERR)
+               dev_dbg(&mgr->pci->dev, "FATAL DSP ERROR : %x\n", reg);
+#endif
+
+       return wake_thread ? IRQ_WAKE_THREAD : IRQ_HANDLED;
+}
+
+irqreturn_t pcxhr_threaded_irq(int irq, void *dev_id)
+{
+       struct pcxhr_mgr *mgr = dev_id;
+       int i, j;
+       struct snd_pcxhr *chip;
+
+       mutex_lock(&mgr->lock);
+       if (mgr->src_it_dsp & PCXHR_IRQ_TIMER) {
                /* is a 24 bit counter */
                int dsp_time_new =
                        PCXHR_INPL(mgr, PCXHR_PLX_MBOX4) & PCXHR_DSP_TIME_MASK;
@@ -1290,13 +1322,6 @@ irqreturn_t pcxhr_interrupt(int irq, void *dev_id)
 #endif
                mgr->dsp_time_last = dsp_time_new;
 
-               if (timer_toggle == mgr->timer_toggle) {
-                       dev_dbg(&mgr->pci->dev, "ERROR TIMER TOGGLE\n");
-                       mgr->dsp_time_err++;
-               }
-               mgr->timer_toggle = timer_toggle;
-
-               reg &= ~PCXHR_IRQ_TIMER;
                for (i = 0; i < mgr->num_cards; i++) {
                        chip = mgr->chip[i];
                        for (j = 0; j < chip->nb_streams_capt; j++)
@@ -1312,22 +1337,7 @@ irqreturn_t pcxhr_interrupt(int irq, void *dev_id)
                                                dsp_time_diff);
                }
        }
-       /* other irq's handled in the tasklet */
-       if (reg & PCXHR_IRQ_MASK) {
-               if (reg & PCXHR_IRQ_ASYNC) {
-                       /* as we didn't request any async notifications,
-                        * some kind of xrun error will probably occurred
-                        */
-                       /* better resynchronize all streams next interrupt : */
-                       mgr->dsp_time_last = PCXHR_DSP_TIME_INVALID;
-               }
-               mgr->src_it_dsp = reg;
-               tasklet_schedule(&mgr->msg_taskq);
-       }
-#ifdef CONFIG_SND_DEBUG_VERBOSE
-       if (reg & PCXHR_FATAL_DSP_ERR)
-               dev_dbg(&mgr->pci->dev, "FATAL DSP ERROR : %x\n", reg);
-#endif
-       spin_unlock(&mgr->lock);
-       return IRQ_HANDLED;     /* this device caused the interrupt */
+
+       pcxhr_msg_thread(mgr);
+       return IRQ_HANDLED;
 }
index a81ab6b811e727a8f18820fed1cd3c5c1f2f3f2f..dc267e4c1074f816ad8b6f27ab700d0403d2cb76 100644 (file)
@@ -200,6 +200,6 @@ int pcxhr_write_io_num_reg_cont(struct pcxhr_mgr *mgr, unsigned int mask,
 
 /* interrupt handling */
 irqreturn_t pcxhr_interrupt(int irq, void *dev_id);
-void pcxhr_msg_tasklet(unsigned long arg);
+irqreturn_t pcxhr_threaded_irq(int irq, void *dev_id);
 
 #endif /* __SOUND_PCXHR_CORE_H */
index 3dc4732142ee5784dd04112761ca0776ea63c941..c5a25e39e3a8ea8f231d94e15ca8fea4cecc6dcf 100644 (file)
@@ -168,8 +168,9 @@ static int snd_vx222_create(struct snd_card *card, struct pci_dev *pci,
        for (i = 0; i < 2; i++)
                vx->port[i] = pci_resource_start(pci, i + 1);
 
-       if (request_irq(pci->irq, snd_vx_irq_handler, IRQF_SHARED,
-                       KBUILD_MODNAME, chip)) {
+       if (request_threaded_irq(pci->irq, snd_vx_irq_handler,
+                                snd_vx_threaded_irq_handler, IRQF_SHARED,
+                                KBUILD_MODNAME, chip)) {
                dev_err(card->dev, "unable to grab IRQ %d\n", pci->irq);
                snd_vx222_free(chip);
                return -EBUSY;
index 56bda124cd4acfda66a3865761c2ffa1208009f7..07f4b33db3afd8d2ccb150549b54b762b5ad1dcb 100644 (file)
@@ -61,6 +61,7 @@ static void snd_pdacf_detach(struct pcmcia_device *p_dev);
 
 static void pdacf_release(struct pcmcia_device *link)
 {
+       free_irq(link->irq, link->priv);
        pcmcia_disable_device(link);
 }
 
@@ -220,11 +221,13 @@ static int pdacf_config(struct pcmcia_device *link)
 
        ret = pcmcia_request_io(link);
        if (ret)
-               goto failed;
+               goto failed_preirq;
 
-       ret = pcmcia_request_irq(link, pdacf_interrupt);
+       ret = request_threaded_irq(link->irq, pdacf_interrupt,
+                                  pdacf_threaded_irq,
+                                  IRQF_SHARED, link->devname, link->priv);
        if (ret)
-               goto failed;
+               goto failed_preirq;
 
        ret = pcmcia_enable_device(link);
        if (ret)
@@ -236,7 +239,9 @@ static int pdacf_config(struct pcmcia_device *link)
 
        return 0;
 
-failed:
+ failed:
+       free_irq(link->irq, link->priv);
+failed_preirq:
        pcmcia_disable_device(link);
        return -ENODEV;
 }
index ea41e57d71794974559318d7aea7a8c46dfca5c9..e9a7d3a784f76963b8d4d591e8c5f6e0c32e445f 100644 (file)
@@ -88,10 +88,9 @@ struct snd_pdacf {
        unsigned long port;
        int irq;
 
-       spinlock_t reg_lock;
+       struct mutex reg_lock;
        unsigned short regmap[8];
        unsigned short suspend_reg_scr;
-       struct tasklet_struct tq;
 
        spinlock_t ak4117_lock;
        struct ak4117 *ak4117;
@@ -136,7 +135,7 @@ int snd_pdacf_resume(struct snd_pdacf *chip);
 #endif
 int snd_pdacf_pcm_new(struct snd_pdacf *chip);
 irqreturn_t pdacf_interrupt(int irq, void *dev);
-void pdacf_tasklet(unsigned long private_data);
+irqreturn_t pdacf_threaded_irq(int irq, void *dev);
 void pdacf_reinit(struct snd_pdacf *chip, int resume);
 
 #endif /* __PDAUDIOCF_H */
index ea0adfb984ad7f37626b9ecff2833dc939dca61f..d724ab0653cfcd9eee87d87299653f860583bf3c 100644 (file)
@@ -162,9 +162,8 @@ struct snd_pdacf *snd_pdacf_create(struct snd_card *card)
        if (chip == NULL)
                return NULL;
        chip->card = card;
-       spin_lock_init(&chip->reg_lock);
+       mutex_init(&chip->reg_lock);
        spin_lock_init(&chip->ak4117_lock);
-       tasklet_init(&chip->tq, pdacf_tasklet, (unsigned long)chip);
        card->private_data = chip;
 
        pdacf_proc_init(chip);
@@ -174,19 +173,18 @@ struct snd_pdacf *snd_pdacf_create(struct snd_card *card)
 static void snd_pdacf_ak4117_change(struct ak4117 *ak4117, unsigned char c0, unsigned char c1)
 {
        struct snd_pdacf *chip = ak4117->change_callback_private;
-       unsigned long flags;
        u16 val;
 
        if (!(c0 & AK4117_UNLCK))
                return;
-       spin_lock_irqsave(&chip->reg_lock, flags);
+       mutex_lock(&chip->reg_lock);
        val = chip->regmap[PDAUDIOCF_REG_SCR>>1];
        if (ak4117->rcs0 & AK4117_UNLCK)
                val |= PDAUDIOCF_BLUE_LED_OFF;
        else
                val &= ~PDAUDIOCF_BLUE_LED_OFF;
        pdacf_reg_write(chip, PDAUDIOCF_REG_SCR, val);
-       spin_unlock_irqrestore(&chip->reg_lock, flags);
+       mutex_unlock(&chip->reg_lock);
 }
 
 int snd_pdacf_ak4117_create(struct snd_pdacf *chip)
index dcd32201bc8c5cf4dfec40b0deba7edfaafe91ea..ecf0fbd9179467ed05a819dd99512862f842d100 100644 (file)
@@ -30,6 +30,7 @@ irqreturn_t pdacf_interrupt(int irq, void *dev)
 {
        struct snd_pdacf *chip = dev;
        unsigned short stat;
+       bool wake_thread = false;
 
        if ((chip->chip_status & (PDAUDIOCF_STAT_IS_STALE|
                                  PDAUDIOCF_STAT_IS_CONFIGURED|
@@ -41,13 +42,13 @@ irqreturn_t pdacf_interrupt(int irq, void *dev)
                if (stat & PDAUDIOCF_IRQOVR)    /* should never happen */
                        snd_printk(KERN_ERR "PDAUDIOCF SRAM buffer overrun detected!\n");
                if (chip->pcm_substream)
-                       tasklet_schedule(&chip->tq);
+                       wake_thread = true;
                if (!(stat & PDAUDIOCF_IRQAKM))
                        stat |= PDAUDIOCF_IRQAKM;       /* check rate */
        }
        if (get_irq_regs() != NULL)
                snd_ak4117_check_rate_and_errors(chip->ak4117, 0);
-       return IRQ_HANDLED;
+       return wake_thread ? IRQ_WAKE_THREAD : IRQ_HANDLED;
 }
 
 static inline void pdacf_transfer_mono16(u16 *dst, u16 xor, unsigned int size, unsigned long rdp_port)
@@ -256,16 +257,16 @@ static void pdacf_transfer(struct snd_pdacf *chip, unsigned int size, unsigned i
        }
 }
 
-void pdacf_tasklet(unsigned long private_data)
+irqreturn_t pdacf_threaded_irq(int irq, void *dev)
 {
-       struct snd_pdacf *chip = (struct snd_pdacf *) private_data;
+       struct snd_pdacf *chip = dev;
        int size, off, cont, rdp, wdp;
 
        if ((chip->chip_status & (PDAUDIOCF_STAT_IS_STALE|PDAUDIOCF_STAT_IS_CONFIGURED)) != PDAUDIOCF_STAT_IS_CONFIGURED)
-               return;
+               return IRQ_HANDLED;
        
        if (chip->pcm_substream == NULL || chip->pcm_substream->runtime == NULL || !snd_pcm_running(chip->pcm_substream))
-               return;
+               return IRQ_HANDLED;
 
        rdp = inw(chip->port + PDAUDIOCF_REG_RDP);
        wdp = inw(chip->port + PDAUDIOCF_REG_WDP);
@@ -311,15 +312,15 @@ void pdacf_tasklet(unsigned long private_data)
                size -= cont;
        }
 #endif
-       spin_lock(&chip->reg_lock);
+       mutex_lock(&chip->reg_lock);
        while (chip->pcm_tdone >= chip->pcm_period) {
                chip->pcm_hwptr += chip->pcm_period;
                chip->pcm_hwptr %= chip->pcm_size;
                chip->pcm_tdone -= chip->pcm_period;
-               spin_unlock(&chip->reg_lock);
+               mutex_unlock(&chip->reg_lock);
                snd_pcm_period_elapsed(chip->pcm_substream);
-               spin_lock(&chip->reg_lock);
+               mutex_lock(&chip->reg_lock);
        }
-       spin_unlock(&chip->reg_lock);
-       /* printk(KERN_DEBUG "TASKLET: end\n"); */
+       mutex_unlock(&chip->reg_lock);
+       return IRQ_HANDLED;
 }
index 43f995a3f96033c081499dd41002541279252b95..b48aa0a78c19b42583d7d25e58dcdb94cb0cb61f 100644 (file)
@@ -77,7 +77,7 @@ static int pdacf_pcm_trigger(struct snd_pcm_substream *subs, int cmd)
        default:
                return -EINVAL;
        }
-       spin_lock(&chip->reg_lock);
+       mutex_lock(&chip->reg_lock);
        chip->pcm_running += inc;
        tmp = pdacf_reg_read(chip, PDAUDIOCF_REG_SCR);
        if (chip->pcm_running) {
@@ -91,7 +91,7 @@ static int pdacf_pcm_trigger(struct snd_pcm_substream *subs, int cmd)
        tmp |= val;
        pdacf_reg_write(chip, PDAUDIOCF_REG_SCR, tmp);
       __end:
-       spin_unlock(&chip->reg_lock);
+       mutex_unlock(&chip->reg_lock);
        snd_ak4117_check_rate_and_errors(chip->ak4117, AK4117_CHECK_NO_RATE);
        return ret;
 }
@@ -296,6 +296,7 @@ int snd_pdacf_pcm_new(struct snd_pdacf *chip)
 
        pcm->private_data = chip;
        pcm->info_flags = 0;
+       pcm->nonatomic = true;
        strcpy(pcm->name, chip->card->shortname);
        chip->pcm = pcm;
        
index fe33e122e372b9e039c0c6746f3ffdbe50cdea2c..281972913c32140939c087067f4340d6882e6626 100644 (file)
@@ -468,12 +468,11 @@ static void vxp_write_codec_reg(struct vx_core *chip, int codec, unsigned int da
 void vx_set_mic_boost(struct vx_core *chip, int boost)
 {
        struct snd_vxpocket *pchip = (struct snd_vxpocket *)chip;
-       unsigned long flags;
 
        if (chip->chip_status & VX_STAT_IS_STALE)
                return;
 
-       spin_lock_irqsave(&chip->lock, flags);
+       mutex_lock(&chip->lock);
        if (pchip->regCDSP & P24_CDSP_MICS_SEL_MASK) {
                if (boost) {
                        /* boost: 38 dB */
@@ -486,7 +485,7 @@ void vx_set_mic_boost(struct vx_core *chip, int boost)
                 }
                vx_outb(chip, CDSP, pchip->regCDSP);
        }
-       spin_unlock_irqrestore(&chip->lock, flags);
+       mutex_unlock(&chip->lock);
 }
 
 /*
@@ -511,17 +510,16 @@ static int vx_compute_mic_level(int level)
 void vx_set_mic_level(struct vx_core *chip, int level)
 {
        struct snd_vxpocket *pchip = (struct snd_vxpocket *)chip;
-       unsigned long flags;
 
        if (chip->chip_status & VX_STAT_IS_STALE)
                return;
 
-       spin_lock_irqsave(&chip->lock, flags);
+       mutex_lock(&chip->lock);
        if (pchip->regCDSP & VXP_CDSP_MIC_SEL_MASK) {
                level = vx_compute_mic_level(level);
                vx_outb(chip, MICRO, level);
        }
-       spin_unlock_irqrestore(&chip->lock, flags);
+       mutex_unlock(&chip->lock);
 }
 
 
index 786e7e139c9eeae713a57ab334ea08bd1c6ce6f1..92ec11456e3a9a55daff3f0386e8c0f65f50d662 100644 (file)
@@ -62,6 +62,7 @@ static unsigned int card_alloc;
  */
 static void vxpocket_release(struct pcmcia_device *link)
 {
+       free_irq(link->irq, link->priv);
        pcmcia_disable_device(link);
 }
 
@@ -227,11 +228,13 @@ static int vxpocket_config(struct pcmcia_device *link)
 
        ret = pcmcia_request_io(link);
        if (ret)
-               goto failed;
+               goto failed_preirq;
 
-       ret = pcmcia_request_irq(link, snd_vx_irq_handler);
+       ret = request_threaded_irq(link->irq, snd_vx_irq_handler,
+                                  snd_vx_threaded_irq_handler,
+                                  IRQF_SHARED, link->devname, link->priv);
        if (ret)
-               goto failed;
+               goto failed_preirq;
 
        ret = pcmcia_enable_device(link);
        if (ret)
@@ -245,7 +248,9 @@ static int vxpocket_config(struct pcmcia_device *link)
 
        return 0;
 
-failed:
+ failed:
+       free_irq(link->irq, link->priv);
+failed_preirq:
        pcmcia_disable_device(link);
        return -ENODEV;
 }
index 922006dd0583cf03698bc39d2033fd8b3d48112b..e88a6b67f7812c68997f7342341c2befda194bd2 100644 (file)
@@ -146,7 +146,7 @@ struct pm860x_priv {
        struct pm860x_det       det;
 
        int                     irq[4];
-       unsigned char           name[4][MAX_NAME_LEN];
+       unsigned char           name[4][MAX_NAME_LEN+1];
 };
 
 /* -9450dB to 0dB in 150dB steps ( mute instead of -9450dB) */
@@ -1337,8 +1337,6 @@ static int pm860x_probe(struct snd_soc_codec *codec)
                }
        }
 
-       pm860x_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
-
        return 0;
 
 out:
@@ -1354,7 +1352,6 @@ static int pm860x_remove(struct snd_soc_codec *codec)
 
        for (i = 3; i >= 0; i--)
                free_irq(pm860x->irq[i], pm860x);
-       pm860x_set_bias_level(codec, SND_SOC_BIAS_OFF);
        return 0;
 }
 
index 8838838e25ed89a9525e80b86cd92575701a75d9..a68d1731a8fde35fe199f61fc702a9259ad25a81 100644 (file)
@@ -43,6 +43,7 @@ config SND_SOC_ALL_CODECS
        select SND_SOC_ALC5623 if I2C
        select SND_SOC_ALC5632 if I2C
        select SND_SOC_CQ0093VC if MFD_DAVINCI_VOICECODEC
+       select SND_SOC_CS35L32 if I2C
        select SND_SOC_CS42L51_I2C if I2C
        select SND_SOC_CS42L52 if I2C && INPUT
        select SND_SOC_CS42L56 if I2C && INPUT
@@ -56,7 +57,10 @@ config SND_SOC_ALL_CODECS
        select SND_SOC_DA7213 if I2C
        select SND_SOC_DA732X if I2C
        select SND_SOC_DA9055 if I2C
+       select SND_SOC_DMIC
        select SND_SOC_BT_SCO
+       select SND_SOC_ES8328_SPI if SPI_MASTER
+       select SND_SOC_ES8328_I2C if I2C
        select SND_SOC_ISABELLE if I2C
        select SND_SOC_JZ4740_CODEC
        select SND_SOC_LM4857 if I2C
@@ -90,6 +94,7 @@ config SND_SOC_ALL_CODECS
        select SND_SOC_SSM2518 if I2C
        select SND_SOC_SSM2602_SPI if SPI_MASTER
        select SND_SOC_SSM2602_I2C if I2C
+       select SND_SOC_SSM4567 if I2C
        select SND_SOC_STA32X if I2C
        select SND_SOC_STA350 if I2C
        select SND_SOC_STA529 if I2C
@@ -323,6 +328,10 @@ config SND_SOC_ALC5632
 config SND_SOC_CQ0093VC
        tristate
 
+config SND_SOC_CS35L32
+       tristate "Cirrus Logic CS35L32 CODEC"
+       depends on I2C
+
 config SND_SOC_CS42L51
        tristate
 
@@ -405,6 +414,17 @@ config SND_SOC_DMIC
 config SND_SOC_HDMI_CODEC
        tristate "HDMI stub CODEC"
 
+config SND_SOC_ES8328
+       tristate "Everest Semi ES8328 CODEC"
+
+config SND_SOC_ES8328_I2C
+       tristate
+       select SND_SOC_ES8328
+
+config SND_SOC_ES8328_SPI
+       tristate
+       select SND_SOC_ES8328
+
 config SND_SOC_ISABELLE
         tristate
 
@@ -464,6 +484,7 @@ config SND_SOC_RL6231
 
 config SND_SOC_RT286
        tristate
+       depends on I2C
 
 config SND_SOC_RT5631
        tristate
@@ -520,12 +541,20 @@ config SND_SOC_SSM2602
        tristate
 
 config SND_SOC_SSM2602_SPI
+       tristate "Analog Devices SSM2602 CODEC - SPI"
+       depends on SPI_MASTER
        select SND_SOC_SSM2602
-       tristate
+       select REGMAP_SPI
 
 config SND_SOC_SSM2602_I2C
+       tristate "Analog Devices SSM2602 CODEC - I2C"
+       depends on I2C
        select SND_SOC_SSM2602
-       tristate
+       select REGMAP_I2C
+
+config SND_SOC_SSM4567
+       tristate "Analog Devices ssm4567 amplifier driver support"
+       depends on I2C
 
 config SND_SOC_STA32X
        tristate
@@ -712,7 +741,8 @@ config SND_SOC_WM8974
        tristate
 
 config SND_SOC_WM8978
-       tristate
+       tristate "Wolfson Microelectronics WM8978 codec"
+       depends on I2C
 
 config SND_SOC_WM8983
        tristate
index 20afe0f0c5be4f724c6a24bcaef084ef49d0d00b..5dce451661e47813bb0b95b8b0121ae2545a2dab 100644 (file)
@@ -32,6 +32,7 @@ snd-soc-ak4671-objs := ak4671.o
 snd-soc-ak5386-objs := ak5386.o
 snd-soc-arizona-objs := arizona.o
 snd-soc-cq93vc-objs := cq93vc.o
+snd-soc-cs35l32-objs := cs35l32.o
 snd-soc-cs42l51-objs := cs42l51.o
 snd-soc-cs42l51-i2c-objs := cs42l51-i2c.o
 snd-soc-cs42l52-objs := cs42l52.o
@@ -49,6 +50,9 @@ snd-soc-da732x-objs := da732x.o
 snd-soc-da9055-objs := da9055.o
 snd-soc-bt-sco-objs := bt-sco.o
 snd-soc-dmic-objs := dmic.o
+snd-soc-es8328-objs := es8328.o
+snd-soc-es8328-i2c-objs := es8328-i2c.o
+snd-soc-es8328-spi-objs := es8328-spi.o
 snd-soc-isabelle-objs := isabelle.o
 snd-soc-jz4740-codec-objs := jz4740.o
 snd-soc-l3-objs := l3.o
@@ -91,6 +95,7 @@ snd-soc-ssm2518-objs := ssm2518.o
 snd-soc-ssm2602-objs := ssm2602.o
 snd-soc-ssm2602-spi-objs := ssm2602-spi.o
 snd-soc-ssm2602-i2c-objs := ssm2602-i2c.o
+snd-soc-ssm4567-objs := ssm4567.o
 snd-soc-sta32x-objs := sta32x.o
 snd-soc-sta350-objs := sta350.o
 snd-soc-sta529-objs := sta529.o
@@ -203,6 +208,7 @@ obj-$(CONFIG_SND_SOC_ALC5623)    += snd-soc-alc5623.o
 obj-$(CONFIG_SND_SOC_ALC5632)  += snd-soc-alc5632.o
 obj-$(CONFIG_SND_SOC_ARIZONA)  += snd-soc-arizona.o
 obj-$(CONFIG_SND_SOC_CQ0093VC) += snd-soc-cq93vc.o
+obj-$(CONFIG_SND_SOC_CS35L32)  += snd-soc-cs35l32.o
 obj-$(CONFIG_SND_SOC_CS42L51)  += snd-soc-cs42l51.o
 obj-$(CONFIG_SND_SOC_CS42L51_I2C)      += snd-soc-cs42l51-i2c.o
 obj-$(CONFIG_SND_SOC_CS42L52)  += snd-soc-cs42l52.o
@@ -220,6 +226,9 @@ obj-$(CONFIG_SND_SOC_DA732X)        += snd-soc-da732x.o
 obj-$(CONFIG_SND_SOC_DA9055)   += snd-soc-da9055.o
 obj-$(CONFIG_SND_SOC_BT_SCO)   += snd-soc-bt-sco.o
 obj-$(CONFIG_SND_SOC_DMIC)     += snd-soc-dmic.o
+obj-$(CONFIG_SND_SOC_ES8328)   += snd-soc-es8328.o
+obj-$(CONFIG_SND_SOC_ES8328_I2C)+= snd-soc-es8328-i2c.o
+obj-$(CONFIG_SND_SOC_ES8328_SPI)+= snd-soc-es8328-spi.o
 obj-$(CONFIG_SND_SOC_ISABELLE) += snd-soc-isabelle.o
 obj-$(CONFIG_SND_SOC_JZ4740_CODEC)     += snd-soc-jz4740-codec.o
 obj-$(CONFIG_SND_SOC_L3)       += snd-soc-l3.o
@@ -258,6 +267,7 @@ obj-$(CONFIG_SND_SOC_SSM2518)       += snd-soc-ssm2518.o
 obj-$(CONFIG_SND_SOC_SSM2602)  += snd-soc-ssm2602.o
 obj-$(CONFIG_SND_SOC_SSM2602_SPI)      += snd-soc-ssm2602-spi.o
 obj-$(CONFIG_SND_SOC_SSM2602_I2C)      += snd-soc-ssm2602-i2c.o
+obj-$(CONFIG_SND_SOC_SSM4567)  += snd-soc-ssm4567.o
 obj-$(CONFIG_SND_SOC_STA32X)   += snd-soc-sta32x.o
 obj-$(CONFIG_SND_SOC_STA350)   += snd-soc-sta350.o
 obj-$(CONFIG_SND_SOC_STA529)   += snd-soc-sta529.o
index 1fb4402bf72d3047c38fdca362700d4c65739dd7..fd43827bb856b522d6acd4e2c95e2b2eea287f25 100644 (file)
@@ -56,8 +56,7 @@
 #define GPIO31_DIR_OUTPUT                      0x40
 
 /* Macrocell register definitions */
-#define AB8500_CTRL3_REG                       0x0200
-#define AB8500_GPIO_DIR4_REG                   0x1013
+#define AB8500_GPIO_DIR4_REG                   0x13 /* Bank AB8500_MISC */
 
 /* Nr of FIR/IIR-coeff banks in ANC-block */
 #define AB8500_NR_OF_ANC_COEFF_BANKS           2
@@ -126,6 +125,8 @@ struct ab8500_codec_drvdata_dbg {
 
 /* Private data for AB8500 device-driver */
 struct ab8500_codec_drvdata {
+       struct regmap *regmap;
+
        /* Sidetone */
        long *sid_fir_values;
        enum sid_state sid_status;
@@ -166,49 +167,35 @@ static inline const char *amic_type_str(enum amic_type type)
  */
 
 /* Read a register from the audio-bank of AB8500 */
-static unsigned int ab8500_codec_read_reg(struct snd_soc_codec *codec,
-                                       unsigned int reg)
+static int ab8500_codec_read_reg(void *context, unsigned int reg,
+                                unsigned int *value)
 {
+       struct device *dev = context;
        int status;
-       unsigned int value = 0;
 
        u8 value8;
-       status = abx500_get_register_interruptible(codec->dev, AB8500_AUDIO,
-                                               reg, &value8);
-       if (status < 0) {
-               dev_err(codec->dev,
-                       "%s: ERROR: Register (0x%02x:0x%02x) read failed (%d).\n",
-                       __func__, (u8)AB8500_AUDIO, (u8)reg, status);
-       } else {
-               dev_dbg(codec->dev,
-                       "%s: Read 0x%02x from register 0x%02x:0x%02x\n",
-                       __func__, value8, (u8)AB8500_AUDIO, (u8)reg);
-               value = (unsigned int)value8;
-       }
+       status = abx500_get_register_interruptible(dev, AB8500_AUDIO,
+                                                  reg, &value8);
+       *value = (unsigned int)value8;
 
-       return value;
+       return status;
 }
 
 /* Write to a register in the audio-bank of AB8500 */
-static int ab8500_codec_write_reg(struct snd_soc_codec *codec,
-                               unsigned int reg, unsigned int value)
+static int ab8500_codec_write_reg(void *context, unsigned int reg,
+                                 unsigned int value)
 {
-       int status;
-
-       status = abx500_set_register_interruptible(codec->dev, AB8500_AUDIO,
-                                               reg, value);
-       if (status < 0)
-               dev_err(codec->dev,
-                       "%s: ERROR: Register (%02x:%02x) write failed (%d).\n",
-                       __func__, (u8)AB8500_AUDIO, (u8)reg, status);
-       else
-               dev_dbg(codec->dev,
-                       "%s: Wrote 0x%02x into register %02x:%02x\n",
-                       __func__, (u8)value, (u8)AB8500_AUDIO, (u8)reg);
+       struct device *dev = context;
 
-       return status;
+       return abx500_set_register_interruptible(dev, AB8500_AUDIO,
+                                                reg, value);
 }
 
+static const struct regmap_config ab8500_codec_regmap = {
+       .reg_read = ab8500_codec_read_reg,
+       .reg_write = ab8500_codec_write_reg,
+};
+
 /*
  * Controls - DAPM
  */
@@ -1968,16 +1955,16 @@ static int ab8500_audio_setup_mics(struct snd_soc_codec *codec,
        dev_dbg(codec->dev, "%s: Enter.\n", __func__);
 
        /* Set DMic-clocks to outputs */
-       status = abx500_get_register_interruptible(codec->dev, (u8)AB8500_MISC,
-                                               (u8)AB8500_GPIO_DIR4_REG,
+       status = abx500_get_register_interruptible(codec->dev, AB8500_MISC,
+                                               AB8500_GPIO_DIR4_REG,
                                                &value8);
        if (status < 0)
                return status;
        value = value8 | GPIO27_DIR_OUTPUT | GPIO29_DIR_OUTPUT |
                GPIO31_DIR_OUTPUT;
        status = abx500_set_register_interruptible(codec->dev,
-                                               (u8)AB8500_MISC,
-                                               (u8)AB8500_GPIO_DIR4_REG,
+                                               AB8500_MISC,
+                                               AB8500_GPIO_DIR4_REG,
                                                value);
        if (status < 0)
                return status;
@@ -2565,9 +2552,6 @@ static int ab8500_codec_probe(struct snd_soc_codec *codec)
 
 static struct snd_soc_codec_driver ab8500_codec_driver = {
        .probe =                ab8500_codec_probe,
-       .read =                 ab8500_codec_read_reg,
-       .write =                ab8500_codec_write_reg,
-       .reg_word_size =        sizeof(u8),
        .controls =             ab8500_ctrls,
        .num_controls =         ARRAY_SIZE(ab8500_ctrls),
        .dapm_widgets =         ab8500_dapm_widgets,
@@ -2592,6 +2576,15 @@ static int ab8500_codec_driver_probe(struct platform_device *pdev)
        drvdata->anc_status = ANC_UNCONFIGURED;
        dev_set_drvdata(&pdev->dev, drvdata);
 
+       drvdata->regmap = devm_regmap_init(&pdev->dev, NULL, &pdev->dev,
+                                          &ab8500_codec_regmap);
+       if (IS_ERR(drvdata->regmap)) {
+               status = PTR_ERR(drvdata->regmap);
+               dev_err(&pdev->dev, "%s: Failed to allocate regmap: %d\n",
+                       __func__, status);
+               return status;
+       }
+
        dev_dbg(&pdev->dev, "%s: Register codec.\n", __func__);
        status = snd_soc_register_codec(&pdev->dev, &ab8500_codec_driver,
                                ab8500_codec_dai,
index e889e1b84192bcc8d0baf354e1a66a8892c72e4f..bd9b1839c8b0e6843d858d93a15d9d440abdc86f 100644 (file)
@@ -69,19 +69,6 @@ static struct snd_soc_dai_driver ac97_dai = {
        .ops = &ac97_dai_ops,
 };
 
-static unsigned int ac97_read(struct snd_soc_codec *codec,
-       unsigned int reg)
-{
-       return soc_ac97_ops->read(codec->ac97, reg);
-}
-
-static int ac97_write(struct snd_soc_codec *codec, unsigned int reg,
-       unsigned int val)
-{
-       soc_ac97_ops->write(codec->ac97, reg, val);
-       return 0;
-}
-
 static int ac97_soc_probe(struct snd_soc_codec *codec)
 {
        struct snd_ac97_bus *ac97_bus;
@@ -122,8 +109,6 @@ static int ac97_soc_resume(struct snd_soc_codec *codec)
 #endif
 
 static struct snd_soc_codec_driver soc_codec_dev_ac97 = {
-       .write =        ac97_write,
-       .read =         ac97_read,
        .probe =        ac97_soc_probe,
        .suspend =      ac97_soc_suspend,
        .resume =       ac97_soc_resume,
index 1ff7d4d027e932e9c20f8841bf09b89f210e6635..7c784ad3e8b2a2589d28f621f1fd49f0a938c9a1 100644 (file)
@@ -1448,29 +1448,10 @@ static int adau1373_set_bias_level(struct snd_soc_codec *codec,
        return 0;
 }
 
-static int adau1373_remove(struct snd_soc_codec *codec)
-{
-       adau1373_set_bias_level(codec, SND_SOC_BIAS_OFF);
-       return 0;
-}
-
-static int adau1373_suspend(struct snd_soc_codec *codec)
-{
-       struct adau1373 *adau1373 = snd_soc_codec_get_drvdata(codec);
-       int ret;
-
-       ret = adau1373_set_bias_level(codec, SND_SOC_BIAS_OFF);
-       regcache_cache_only(adau1373->regmap, true);
-
-       return ret;
-}
-
 static int adau1373_resume(struct snd_soc_codec *codec)
 {
        struct adau1373 *adau1373 = snd_soc_codec_get_drvdata(codec);
 
-       regcache_cache_only(adau1373->regmap, false);
-       adau1373_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
        regcache_sync(adau1373->regmap);
 
        return 0;
@@ -1501,8 +1482,6 @@ static const struct regmap_config adau1373_regmap_config = {
 
 static struct snd_soc_codec_driver adau1373_codec_driver = {
        .probe =        adau1373_probe,
-       .remove =       adau1373_remove,
-       .suspend =      adau1373_suspend,
        .resume =       adau1373_resume,
        .set_bias_level = adau1373_set_bias_level,
        .idle_bias_off = true,
index 848cab83955392b33f93c18dac3631f1f9fb0a97..5518ebd6947c5f28329fb474b4b313920f5e94ec 100644 (file)
@@ -714,9 +714,9 @@ static int adau1761_codec_probe(struct snd_soc_codec *codec)
 
 static const struct snd_soc_codec_driver adau1761_codec_driver = {
        .probe = adau1761_codec_probe,
-       .suspend = adau17x1_suspend,
        .resume = adau17x1_resume,
        .set_bias_level = adau1761_set_bias_level,
+       .suspend_bias_off = true,
 
        .controls = adau1761_controls,
        .num_controls = ARRAY_SIZE(adau1761_controls),
index 045a61413840f013b79aa0bcec624b1b8b75d6f5..e9fc00fb13ddf65597513fe58652183776b71d99 100644 (file)
@@ -446,9 +446,9 @@ static int adau1781_codec_probe(struct snd_soc_codec *codec)
 
 static const struct snd_soc_codec_driver adau1781_codec_driver = {
        .probe = adau1781_codec_probe,
-       .suspend = adau17x1_suspend,
        .resume = adau17x1_resume,
        .set_bias_level = adau1781_set_bias_level,
+       .suspend_bias_off = true,
 
        .controls = adau1781_controls,
        .num_controls = ARRAY_SIZE(adau1781_controls),
index 0b659704e60c0db2c425474857a5372e0702a22a..3e16c1c641156d428e1759956191f418a1edcd03 100644 (file)
@@ -815,13 +815,6 @@ int adau17x1_add_routes(struct snd_soc_codec *codec)
 }
 EXPORT_SYMBOL_GPL(adau17x1_add_routes);
 
-int adau17x1_suspend(struct snd_soc_codec *codec)
-{
-       codec->driver->set_bias_level(codec, SND_SOC_BIAS_OFF);
-       return 0;
-}
-EXPORT_SYMBOL_GPL(adau17x1_suspend);
-
 int adau17x1_resume(struct snd_soc_codec *codec)
 {
        struct adau *adau = snd_soc_codec_get_drvdata(codec);
@@ -829,7 +822,6 @@ int adau17x1_resume(struct snd_soc_codec *codec)
        if (adau->switch_mode)
                adau->switch_mode(codec->dev);
 
-       codec->driver->set_bias_level(codec, SND_SOC_BIAS_STANDBY);
        regcache_sync(adau->regmap);
 
        return 0;
index 3ffabaf4c7a846f7f9e46763981c3f92866cf0ec..e4a557fd7155c34b6c5c5da7a9f7337b2d14ecb7 100644 (file)
@@ -52,7 +52,6 @@ int adau17x1_set_micbias_voltage(struct snd_soc_codec *codec,
        enum adau17x1_micbias_voltage micbias);
 bool adau17x1_readable_register(struct device *dev, unsigned int reg);
 bool adau17x1_volatile_register(struct device *dev, unsigned int reg);
-int adau17x1_suspend(struct snd_soc_codec *codec);
 int adau17x1_resume(struct snd_soc_codec *codec);
 
 extern const struct snd_soc_dai_ops adau17x1_dai_ops;
index c43b93fdf0dfe466e3c72e97eec0c5da5da06ecb..ce3cdca9fc62d7efca27b9904a883decd0341a7f 100644 (file)
@@ -812,42 +812,23 @@ static int adav80x_probe(struct snd_soc_codec *codec)
        /* Disable DAC zero flag */
        regmap_write(adav80x->regmap, ADAV80X_DAC_CTRL3, 0x6);
 
-       return adav80x_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
-}
-
-static int adav80x_suspend(struct snd_soc_codec *codec)
-{
-       struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec);
-       int ret;
-
-       ret = adav80x_set_bias_level(codec, SND_SOC_BIAS_OFF);
-       regcache_cache_only(adav80x->regmap, true);
-
-       return ret;
+       return 0;
 }
 
 static int adav80x_resume(struct snd_soc_codec *codec)
 {
        struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec);
 
-       regcache_cache_only(adav80x->regmap, false);
-       adav80x_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
        regcache_sync(adav80x->regmap);
 
        return 0;
 }
 
-static int adav80x_remove(struct snd_soc_codec *codec)
-{
-       return adav80x_set_bias_level(codec, SND_SOC_BIAS_OFF);
-}
-
 static struct snd_soc_codec_driver adav80x_codec_driver = {
        .probe = adav80x_probe,
-       .remove = adav80x_remove,
-       .suspend = adav80x_suspend,
        .resume = adav80x_resume,
        .set_bias_level = adav80x_set_bias_level,
+       .suspend_bias_off = true,
 
        .set_pll = adav80x_set_pll,
        .set_sysclk = adav80x_set_sysclk,
diff --git a/sound/soc/codecs/cs35l32.c b/sound/soc/codecs/cs35l32.c
new file mode 100644 (file)
index 0000000..c125925
--- /dev/null
@@ -0,0 +1,631 @@
+/*
+ * cs35l32.c -- CS35L32 ALSA SoC audio driver
+ *
+ * Copyright 2014 CirrusLogic, Inc.
+ *
+ * Author: Brian Austin <brian.austin@cirrus.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/version.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/gpio.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
+#include <linux/gpio/consumer.h>
+#include <linux/of_device.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+#include <dt-bindings/sound/cs35l32.h>
+
+#include "cs35l32.h"
+
+#define CS35L32_NUM_SUPPLIES 2
+static const char *const cs35l32_supply_names[CS35L32_NUM_SUPPLIES] = {
+       "VA",
+       "VP",
+};
+
+struct  cs35l32_private {
+       struct regmap *regmap;
+       struct snd_soc_codec *codec;
+       struct regulator_bulk_data supplies[CS35L32_NUM_SUPPLIES];
+       struct cs35l32_platform_data pdata;
+       struct gpio_desc *reset_gpio;
+};
+
+static const struct reg_default cs35l32_reg_defaults[] = {
+
+       { 0x06, 0x04 }, /* Power Ctl 1 */
+       { 0x07, 0xE8 }, /* Power Ctl 2 */
+       { 0x08, 0x40 }, /* Clock Ctl */
+       { 0x09, 0x20 }, /* Low Battery Threshold */
+       { 0x0A, 0x00 }, /* Voltage Monitor [RO] */
+       { 0x0B, 0x40 }, /* Conv Peak Curr Protection CTL */
+       { 0x0C, 0x07 }, /* IMON Scaling */
+       { 0x0D, 0x03 }, /* Audio/LED Pwr Manager */
+       { 0x0F, 0x20 }, /* Serial Port Control */
+       { 0x10, 0x14 }, /* Class D Amp CTL */
+       { 0x11, 0x00 }, /* Protection Release CTL */
+       { 0x12, 0xFF }, /* Interrupt Mask 1 */
+       { 0x13, 0xFF }, /* Interrupt Mask 2 */
+       { 0x14, 0xFF }, /* Interrupt Mask 3 */
+       { 0x19, 0x00 }, /* LED Flash Mode Current */
+       { 0x1A, 0x00 }, /* LED Movie Mode Current */
+       { 0x1B, 0x20 }, /* LED Flash Timer */
+       { 0x1C, 0x00 }, /* LED Flash Inhibit Current */
+};
+
+static bool cs35l32_readable_register(struct device *dev, unsigned int reg)
+{
+       switch (reg) {
+       case CS35L32_DEVID_AB:
+       case CS35L32_DEVID_CD:
+       case CS35L32_DEVID_E:
+       case CS35L32_FAB_ID:
+       case CS35L32_REV_ID:
+       case CS35L32_PWRCTL1:
+       case CS35L32_PWRCTL2:
+       case CS35L32_CLK_CTL:
+       case CS35L32_BATT_THRESHOLD:
+       case CS35L32_VMON:
+       case CS35L32_BST_CPCP_CTL:
+       case CS35L32_IMON_SCALING:
+       case CS35L32_AUDIO_LED_MNGR:
+       case CS35L32_ADSP_CTL:
+       case CS35L32_CLASSD_CTL:
+       case CS35L32_PROTECT_CTL:
+       case CS35L32_INT_MASK_1:
+       case CS35L32_INT_MASK_2:
+       case CS35L32_INT_MASK_3:
+       case CS35L32_INT_STATUS_1:
+       case CS35L32_INT_STATUS_2:
+       case CS35L32_INT_STATUS_3:
+       case CS35L32_LED_STATUS:
+       case CS35L32_FLASH_MODE:
+       case CS35L32_MOVIE_MODE:
+       case CS35L32_FLASH_TIMER:
+       case CS35L32_FLASH_INHIBIT:
+               return true;
+       default:
+               return false;
+       }
+}
+
+static bool cs35l32_volatile_register(struct device *dev, unsigned int reg)
+{
+       switch (reg) {
+       case CS35L32_DEVID_AB:
+       case CS35L32_DEVID_CD:
+       case CS35L32_DEVID_E:
+       case CS35L32_FAB_ID:
+       case CS35L32_REV_ID:
+       case CS35L32_INT_STATUS_1:
+       case CS35L32_INT_STATUS_2:
+       case CS35L32_INT_STATUS_3:
+       case CS35L32_LED_STATUS:
+               return true;
+       default:
+               return false;
+       }
+}
+
+static bool cs35l32_precious_register(struct device *dev, unsigned int reg)
+{
+       switch (reg) {
+       case CS35L32_INT_STATUS_1:
+       case CS35L32_INT_STATUS_2:
+       case CS35L32_INT_STATUS_3:
+       case CS35L32_LED_STATUS:
+               return true;
+       default:
+               return false;
+       }
+}
+
+static DECLARE_TLV_DB_SCALE(classd_ctl_tlv, 900, 300, 0);
+
+static const struct snd_kcontrol_new imon_ctl =
+       SOC_DAPM_SINGLE("Switch", CS35L32_PWRCTL2, 6, 1, 1);
+
+static const struct snd_kcontrol_new vmon_ctl =
+       SOC_DAPM_SINGLE("Switch", CS35L32_PWRCTL2, 7, 1, 1);
+
+static const struct snd_kcontrol_new vpmon_ctl =
+       SOC_DAPM_SINGLE("Switch", CS35L32_PWRCTL2, 5, 1, 1);
+
+static const struct snd_kcontrol_new cs35l32_snd_controls[] = {
+       SOC_SINGLE_TLV("Speaker Volume", CS35L32_CLASSD_CTL,
+                      3, 0x04, 1, classd_ctl_tlv),
+       SOC_SINGLE("Zero Cross Switch", CS35L32_CLASSD_CTL, 2, 1, 0),
+       SOC_SINGLE("Gain Manager Switch", CS35L32_AUDIO_LED_MNGR, 3, 1, 0),
+};
+
+static const struct snd_soc_dapm_widget cs35l32_dapm_widgets[] = {
+
+       SND_SOC_DAPM_SUPPLY("BOOST", CS35L32_PWRCTL1, 2, 1, NULL, 0),
+       SND_SOC_DAPM_OUT_DRV("Speaker", CS35L32_PWRCTL1, 7, 1, NULL, 0),
+
+       SND_SOC_DAPM_AIF_OUT("SDOUT", NULL, 0, CS35L32_PWRCTL2, 3, 1),
+
+       SND_SOC_DAPM_INPUT("VP"),
+       SND_SOC_DAPM_INPUT("ISENSE"),
+       SND_SOC_DAPM_INPUT("VSENSE"),
+
+       SND_SOC_DAPM_SWITCH("VMON ADC", CS35L32_PWRCTL2, 7, 1, &vmon_ctl),
+       SND_SOC_DAPM_SWITCH("IMON ADC", CS35L32_PWRCTL2, 6, 1, &imon_ctl),
+       SND_SOC_DAPM_SWITCH("VPMON ADC", CS35L32_PWRCTL2, 5, 1, &vpmon_ctl),
+};
+
+static const struct snd_soc_dapm_route cs35l32_audio_map[] = {
+
+       {"Speaker", NULL, "BOOST"},
+
+       {"VMON ADC", NULL, "VSENSE"},
+       {"IMON ADC", NULL, "ISENSE"},
+       {"VPMON ADC", NULL, "VP"},
+
+       {"SDOUT", "Switch", "VMON ADC"},
+       {"SDOUT",  "Switch", "IMON ADC"},
+       {"SDOUT", "Switch", "VPMON ADC"},
+
+       {"Capture", NULL, "SDOUT"},
+};
+
+static int cs35l32_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
+{
+       struct snd_soc_codec *codec = codec_dai->codec;
+
+       switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+       case SND_SOC_DAIFMT_CBM_CFM:
+               snd_soc_update_bits(codec, CS35L32_ADSP_CTL,
+                                   CS35L32_ADSP_MASTER_MASK,
+                               CS35L32_ADSP_MASTER_MASK);
+               break;
+       case SND_SOC_DAIFMT_CBS_CFS:
+               snd_soc_update_bits(codec, CS35L32_ADSP_CTL,
+                                   CS35L32_ADSP_MASTER_MASK, 0);
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int cs35l32_set_tristate(struct snd_soc_dai *dai, int tristate)
+{
+       struct snd_soc_codec *codec = dai->codec;
+
+       return snd_soc_update_bits(codec, CS35L32_PWRCTL2,
+                                       CS35L32_SDOUT_3ST, tristate << 3);
+}
+
+static const struct snd_soc_dai_ops cs35l32_ops = {
+       .set_fmt = cs35l32_set_dai_fmt,
+       .set_tristate = cs35l32_set_tristate,
+};
+
+static struct snd_soc_dai_driver cs35l32_dai[] = {
+       {
+               .name = "cs35l32-monitor",
+               .id = 0,
+               .capture = {
+                       .stream_name = "Capture",
+                       .channels_min = 2,
+                       .channels_max = 2,
+                       .rates = CS35L32_RATES,
+                       .formats = CS35L32_FORMATS,
+               },
+               .ops = &cs35l32_ops,
+               .symmetric_rates = 1,
+       }
+};
+
+static int cs35l32_codec_set_sysclk(struct snd_soc_codec *codec,
+                             int clk_id, int source, unsigned int freq, int dir)
+{
+       unsigned int val;
+
+       switch (freq) {
+       case 6000000:
+               val = CS35L32_MCLK_RATIO;
+               break;
+       case 12000000:
+               val = CS35L32_MCLK_DIV2_MASK | CS35L32_MCLK_RATIO;
+               break;
+       case 6144000:
+               val = 0;
+               break;
+       case 12288000:
+               val = CS35L32_MCLK_DIV2_MASK;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return snd_soc_update_bits(codec, CS35L32_CLK_CTL,
+                       CS35L32_MCLK_DIV2_MASK | CS35L32_MCLK_RATIO_MASK, val);
+}
+
+static struct snd_soc_codec_driver soc_codec_dev_cs35l32 = {
+       .set_sysclk = cs35l32_codec_set_sysclk,
+
+       .dapm_widgets = cs35l32_dapm_widgets,
+       .num_dapm_widgets = ARRAY_SIZE(cs35l32_dapm_widgets),
+       .dapm_routes = cs35l32_audio_map,
+       .num_dapm_routes = ARRAY_SIZE(cs35l32_audio_map),
+
+       .controls = cs35l32_snd_controls,
+       .num_controls = ARRAY_SIZE(cs35l32_snd_controls),
+};
+
+/* Current and threshold powerup sequence Pg37 in datasheet */
+static const struct reg_default cs35l32_monitor_patch[] = {
+
+       { 0x00, 0x99 },
+       { 0x48, 0x17 },
+       { 0x49, 0x56 },
+       { 0x43, 0x01 },
+       { 0x3B, 0x62 },
+       { 0x3C, 0x80 },
+       { 0x00, 0x00 },
+};
+
+static struct regmap_config cs35l32_regmap = {
+       .reg_bits = 8,
+       .val_bits = 8,
+
+       .max_register = CS35L32_MAX_REGISTER,
+       .reg_defaults = cs35l32_reg_defaults,
+       .num_reg_defaults = ARRAY_SIZE(cs35l32_reg_defaults),
+       .volatile_reg = cs35l32_volatile_register,
+       .readable_reg = cs35l32_readable_register,
+       .precious_reg = cs35l32_precious_register,
+       .cache_type = REGCACHE_RBTREE,
+};
+
+static int cs35l32_handle_of_data(struct i2c_client *i2c_client,
+                                   struct cs35l32_platform_data *pdata)
+{
+       struct device_node *np = i2c_client->dev.of_node;
+       unsigned int val;
+
+       if (of_property_read_u32(np, "cirrus,sdout-share", &val) >= 0)
+               pdata->sdout_share = val;
+
+       of_property_read_u32(np, "cirrus,boost-manager", &val);
+       switch (val) {
+       case CS35L32_BOOST_MGR_AUTO:
+       case CS35L32_BOOST_MGR_AUTO_AUDIO:
+       case CS35L32_BOOST_MGR_BYPASS:
+       case CS35L32_BOOST_MGR_FIXED:
+               pdata->boost_mng = val;
+               break;
+       default:
+               dev_err(&i2c_client->dev,
+                       "Wrong cirrus,boost-manager DT value %d\n", val);
+               pdata->boost_mng = CS35L32_BOOST_MGR_BYPASS;
+       }
+
+       of_property_read_u32(np, "cirrus,sdout-datacfg", &val);
+       switch (val) {
+       case CS35L32_DATA_CFG_LR_VP:
+       case CS35L32_DATA_CFG_LR_STAT:
+       case CS35L32_DATA_CFG_LR:
+       case CS35L32_DATA_CFG_LR_VPSTAT:
+               pdata->sdout_datacfg = val;
+               break;
+       default:
+               dev_err(&i2c_client->dev,
+                       "Wrong cirrus,sdout-datacfg DT value %d\n", val);
+               pdata->sdout_datacfg = CS35L32_DATA_CFG_LR;
+       }
+
+       of_property_read_u32(np, "cirrus,battery-threshold", &val);
+       switch (val) {
+       case CS35L32_BATT_THRESH_3_1V:
+       case CS35L32_BATT_THRESH_3_2V:
+       case CS35L32_BATT_THRESH_3_3V:
+       case CS35L32_BATT_THRESH_3_4V:
+               pdata->batt_thresh = val;
+               break;
+       default:
+               dev_err(&i2c_client->dev,
+                       "Wrong cirrus,battery-threshold DT value %d\n", val);
+               pdata->batt_thresh = CS35L32_BATT_THRESH_3_3V;
+       }
+
+       of_property_read_u32(np, "cirrus,battery-recovery", &val);
+       switch (val) {
+       case CS35L32_BATT_RECOV_3_1V:
+       case CS35L32_BATT_RECOV_3_2V:
+       case CS35L32_BATT_RECOV_3_3V:
+       case CS35L32_BATT_RECOV_3_4V:
+       case CS35L32_BATT_RECOV_3_5V:
+       case CS35L32_BATT_RECOV_3_6V:
+               pdata->batt_recov = val;
+               break;
+       default:
+               dev_err(&i2c_client->dev,
+                       "Wrong cirrus,battery-recovery DT value %d\n", val);
+               pdata->batt_recov = CS35L32_BATT_RECOV_3_4V;
+       }
+
+       return 0;
+}
+
+static int cs35l32_i2c_probe(struct i2c_client *i2c_client,
+                                      const struct i2c_device_id *id)
+{
+       struct cs35l32_private *cs35l32;
+       struct cs35l32_platform_data *pdata =
+               dev_get_platdata(&i2c_client->dev);
+       int ret, i;
+       unsigned int devid = 0;
+       unsigned int reg;
+
+
+       cs35l32 = devm_kzalloc(&i2c_client->dev, sizeof(struct cs35l32_private),
+                              GFP_KERNEL);
+       if (!cs35l32) {
+               dev_err(&i2c_client->dev, "could not allocate codec\n");
+               return -ENOMEM;
+       }
+
+       i2c_set_clientdata(i2c_client, cs35l32);
+
+       cs35l32->regmap = devm_regmap_init_i2c(i2c_client, &cs35l32_regmap);
+       if (IS_ERR(cs35l32->regmap)) {
+               ret = PTR_ERR(cs35l32->regmap);
+               dev_err(&i2c_client->dev, "regmap_init() failed: %d\n", ret);
+               return ret;
+       }
+
+       if (pdata) {
+               cs35l32->pdata = *pdata;
+       } else {
+               pdata = devm_kzalloc(&i2c_client->dev,
+                                    sizeof(struct cs35l32_platform_data),
+                               GFP_KERNEL);
+               if (!pdata) {
+                       dev_err(&i2c_client->dev, "could not allocate pdata\n");
+                       return -ENOMEM;
+               }
+               if (i2c_client->dev.of_node) {
+                       ret = cs35l32_handle_of_data(i2c_client,
+                                                    &cs35l32->pdata);
+                       if (ret != 0)
+                               return ret;
+               }
+       }
+
+       for (i = 0; i < ARRAY_SIZE(cs35l32->supplies); i++)
+               cs35l32->supplies[i].supply = cs35l32_supply_names[i];
+
+       ret = devm_regulator_bulk_get(&i2c_client->dev,
+                                     ARRAY_SIZE(cs35l32->supplies),
+                                     cs35l32->supplies);
+       if (ret != 0) {
+               dev_err(&i2c_client->dev,
+                       "Failed to request supplies: %d\n", ret);
+               return ret;
+       }
+
+       ret = regulator_bulk_enable(ARRAY_SIZE(cs35l32->supplies),
+                                   cs35l32->supplies);
+       if (ret != 0) {
+               dev_err(&i2c_client->dev,
+                       "Failed to enable supplies: %d\n", ret);
+               return ret;
+       }
+
+       /* Reset the Device */
+       cs35l32->reset_gpio = devm_gpiod_get(&i2c_client->dev,
+               "reset-gpios");
+       if (IS_ERR(cs35l32->reset_gpio)) {
+               ret = PTR_ERR(cs35l32->reset_gpio);
+               if (ret != -ENOENT && ret != -ENOSYS)
+                       return ret;
+
+               cs35l32->reset_gpio = NULL;
+       } else {
+               ret = gpiod_direction_output(cs35l32->reset_gpio, 0);
+               if (ret)
+                       return ret;
+               gpiod_set_value_cansleep(cs35l32->reset_gpio, 1);
+       }
+
+       /* initialize codec */
+       ret = regmap_read(cs35l32->regmap, CS35L32_DEVID_AB, &reg);
+       devid = (reg & 0xFF) << 12;
+
+       ret = regmap_read(cs35l32->regmap, CS35L32_DEVID_CD, &reg);
+       devid |= (reg & 0xFF) << 4;
+
+       ret = regmap_read(cs35l32->regmap, CS35L32_DEVID_E, &reg);
+       devid |= (reg & 0xF0) >> 4;
+
+       if (devid != CS35L32_CHIP_ID) {
+               ret = -ENODEV;
+               dev_err(&i2c_client->dev,
+                       "CS35L32 Device ID (%X). Expected %X\n",
+                       devid, CS35L32_CHIP_ID);
+               return ret;
+       }
+
+       ret = regmap_read(cs35l32->regmap, CS35L32_REV_ID, &reg);
+       if (ret < 0) {
+               dev_err(&i2c_client->dev, "Get Revision ID failed\n");
+               return ret;
+       }
+
+       ret = regmap_register_patch(cs35l32->regmap, cs35l32_monitor_patch,
+                                   ARRAY_SIZE(cs35l32_monitor_patch));
+       if (ret < 0) {
+               dev_err(&i2c_client->dev, "Failed to apply errata patch\n");
+               return ret;
+       }
+
+       dev_info(&i2c_client->dev,
+                "Cirrus Logic CS35L32, Revision: %02X\n", reg & 0xFF);
+
+       /* Setup VBOOST Management */
+       if (cs35l32->pdata.boost_mng)
+               regmap_update_bits(cs35l32->regmap, CS35L32_AUDIO_LED_MNGR,
+                                  CS35L32_BOOST_MASK,
+                               cs35l32->pdata.boost_mng);
+
+       /* Setup ADSP Format Config */
+       if (cs35l32->pdata.sdout_share)
+               regmap_update_bits(cs35l32->regmap, CS35L32_ADSP_CTL,
+                                   CS35L32_ADSP_SHARE_MASK,
+                               cs35l32->pdata.sdout_share << 3);
+
+       /* Setup ADSP Data Configuration */
+       if (cs35l32->pdata.sdout_datacfg)
+               regmap_update_bits(cs35l32->regmap, CS35L32_ADSP_CTL,
+                                  CS35L32_ADSP_DATACFG_MASK,
+                               cs35l32->pdata.sdout_datacfg << 4);
+
+       /* Setup Low Battery Recovery  */
+       if (cs35l32->pdata.batt_recov)
+               regmap_update_bits(cs35l32->regmap, CS35L32_BATT_THRESHOLD,
+                                  CS35L32_BATT_REC_MASK,
+                               cs35l32->pdata.batt_recov << 1);
+
+       /* Setup Low Battery Threshold */
+       if (cs35l32->pdata.batt_thresh)
+               regmap_update_bits(cs35l32->regmap, CS35L32_BATT_THRESHOLD,
+                                  CS35L32_BATT_THRESH_MASK,
+                               cs35l32->pdata.batt_thresh << 4);
+
+       /* Power down the AMP */
+       regmap_update_bits(cs35l32->regmap, CS35L32_PWRCTL1, CS35L32_PDN_AMP,
+                           CS35L32_PDN_AMP);
+
+       /* Clear MCLK Error Bit since we don't have the clock yet */
+       ret = regmap_read(cs35l32->regmap, CS35L32_INT_STATUS_1, &reg);
+
+       ret =  snd_soc_register_codec(&i2c_client->dev,
+                       &soc_codec_dev_cs35l32, cs35l32_dai,
+                       ARRAY_SIZE(cs35l32_dai));
+       if (ret < 0)
+               goto err_disable;
+
+       return 0;
+
+err_disable:
+       regulator_bulk_disable(ARRAY_SIZE(cs35l32->supplies),
+                              cs35l32->supplies);
+       return ret;
+}
+
+static int cs35l32_i2c_remove(struct i2c_client *i2c_client)
+{
+       struct cs35l32_private *cs35l32 = i2c_get_clientdata(i2c_client);
+
+       snd_soc_unregister_codec(&i2c_client->dev);
+
+       /* Hold down reset */
+       if (cs35l32->reset_gpio)
+               gpiod_set_value_cansleep(cs35l32->reset_gpio, 0);
+
+       return 0;
+}
+
+#ifdef CONFIG_PM_RUNTIME
+static int cs35l32_runtime_suspend(struct device *dev)
+{
+       struct cs35l32_private *cs35l32 = dev_get_drvdata(dev);
+
+       regcache_cache_only(cs35l32->regmap, true);
+       regcache_mark_dirty(cs35l32->regmap);
+
+       /* Hold down reset */
+       if (cs35l32->reset_gpio)
+               gpiod_set_value_cansleep(cs35l32->reset_gpio, 0);
+
+       /* remove power */
+       regulator_bulk_disable(ARRAY_SIZE(cs35l32->supplies),
+                              cs35l32->supplies);
+
+       return 0;
+}
+
+static int cs35l32_runtime_resume(struct device *dev)
+{
+       struct cs35l32_private *cs35l32 = dev_get_drvdata(dev);
+       int ret;
+
+       /* Enable power */
+       ret = regulator_bulk_enable(ARRAY_SIZE(cs35l32->supplies),
+                                   cs35l32->supplies);
+       if (ret != 0) {
+               dev_err(dev, "Failed to enable supplies: %d\n",
+                       ret);
+               return ret;
+       }
+
+       if (cs35l32->reset_gpio)
+               gpiod_set_value_cansleep(cs35l32->reset_gpio, 1);
+
+       regcache_cache_only(cs35l32->regmap, false);
+       regcache_sync(cs35l32->regmap);
+
+       return 0;
+}
+#endif
+
+static const struct dev_pm_ops cs35l32_runtime_pm = {
+       SET_RUNTIME_PM_OPS(cs35l32_runtime_suspend, cs35l32_runtime_resume,
+                          NULL)
+};
+
+static const struct of_device_id cs35l32_of_match[] = {
+       { .compatible = "cirrus,cs35l32", },
+       {},
+};
+MODULE_DEVICE_TABLE(of, cs35l32_of_match);
+
+
+static const struct i2c_device_id cs35l32_id[] = {
+       {"cs35l32", 0},
+       {}
+};
+
+MODULE_DEVICE_TABLE(i2c, cs35l32_id);
+
+static struct i2c_driver cs35l32_i2c_driver = {
+       .driver = {
+                  .name = "cs35l32",
+                  .owner = THIS_MODULE,
+                  .pm = &cs35l32_runtime_pm,
+                  .of_match_table = cs35l32_of_match,
+                  },
+       .id_table = cs35l32_id,
+       .probe = cs35l32_i2c_probe,
+       .remove = cs35l32_i2c_remove,
+};
+
+module_i2c_driver(cs35l32_i2c_driver);
+
+MODULE_DESCRIPTION("ASoC CS35L32 driver");
+MODULE_AUTHOR("Brian Austin, Cirrus Logic Inc, <brian.austin@cirrus.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/cs35l32.h b/sound/soc/codecs/cs35l32.h
new file mode 100644 (file)
index 0000000..31ab804
--- /dev/null
@@ -0,0 +1,93 @@
+/*
+ * cs35l32.h -- CS35L32 ALSA SoC audio driver
+ *
+ * Copyright 2014 CirrusLogic, Inc.
+ *
+ * Author: Brian Austin <brian.austin@cirrus.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#ifndef __CS35L32_H__
+#define __CS35L32_H__
+
+struct cs35l32_platform_data {
+       /* Low Battery Threshold */
+       unsigned int batt_thresh;
+       /* Low Battery Recovery */
+       unsigned int batt_recov;
+       /* LED Current Management*/
+       unsigned int led_mng;
+       /* Audio Gain w/ LED */
+       unsigned int audiogain_mng;
+       /* Boost Management */
+       unsigned int boost_mng;
+       /* Data CFG for DUAL device */
+       unsigned int sdout_datacfg;
+       /* SDOUT Sharing */
+       unsigned int sdout_share;
+};
+
+#define CS35L32_CHIP_ID                0x00035A32
+#define CS35L32_DEVID_AB       0x01    /* Device ID A & B [RO] */
+#define CS35L32_DEVID_CD       0x02    /* Device ID C & D [RO] */
+#define CS35L32_DEVID_E                0x03    /* Device ID E [RO] */
+#define CS35L32_FAB_ID         0x04    /* Fab ID [RO] */
+#define CS35L32_REV_ID         0x05    /* Revision ID [RO] */
+#define CS35L32_PWRCTL1                0x06    /* Power Ctl 1 */
+#define CS35L32_PWRCTL2                0x07    /* Power Ctl 2 */
+#define CS35L32_CLK_CTL                0x08    /* Clock Ctl */
+#define CS35L32_BATT_THRESHOLD 0x09    /* Low Battery Threshold */
+#define CS35L32_VMON           0x0A    /* Voltage Monitor [RO] */
+#define CS35L32_BST_CPCP_CTL   0x0B    /* Conv Peak Curr Protection CTL */
+#define CS35L32_IMON_SCALING   0x0C    /* IMON Scaling */
+#define CS35L32_AUDIO_LED_MNGR 0x0D    /* Audio/LED Pwr Manager */
+#define CS35L32_ADSP_CTL       0x0F    /* Serial Port Control */
+#define CS35L32_CLASSD_CTL     0x10    /* Class D Amp CTL */
+#define CS35L32_PROTECT_CTL    0x11    /* Protection Release CTL */
+#define CS35L32_INT_MASK_1     0x12    /* Interrupt Mask 1 */
+#define CS35L32_INT_MASK_2     0x13    /* Interrupt Mask 2 */
+#define CS35L32_INT_MASK_3     0x14    /* Interrupt Mask 3 */
+#define CS35L32_INT_STATUS_1   0x15    /* Interrupt Status 1 [RO] */
+#define CS35L32_INT_STATUS_2   0x16    /* Interrupt Status 2 [RO] */
+#define CS35L32_INT_STATUS_3   0x17    /* Interrupt Status 3 [RO] */
+#define CS35L32_LED_STATUS     0x18    /* LED Lighting Status [RO] */
+#define CS35L32_FLASH_MODE     0x19    /* LED Flash Mode Current */
+#define CS35L32_MOVIE_MODE     0x1A    /* LED Movie Mode Current */
+#define CS35L32_FLASH_TIMER    0x1B    /* LED Flash Timer */
+#define CS35L32_FLASH_INHIBIT  0x1C    /* LED Flash Inhibit Current */
+#define CS35L32_MAX_REGISTER   0x1C
+
+#define CS35L32_MCLK_DIV2      0x01
+#define CS35L32_MCLK_RATIO     0x01
+#define CS35L32_MCLKDIS                0x80
+#define CS35L32_PDN_ALL                0x01
+#define CS35L32_PDN_AMP                0x80
+#define CS35L32_PDN_BOOST      0x04
+#define CS35L32_PDN_IMON       0x40
+#define CS35L32_PDN_VMON       0x80
+#define CS35L32_PDN_VPMON      0x20
+#define CS35L32_PDN_ADSP       0x08
+
+#define CS35L32_MCLK_DIV2_MASK         0x40
+#define CS35L32_MCLK_RATIO_MASK                0x01
+#define CS35L32_MCLK_MASK              0x41
+#define CS35L32_ADSP_MASTER_MASK       0x40
+#define CS35L32_BOOST_MASK             0x03
+#define CS35L32_GAIN_MGR_MASK          0x08
+#define CS35L32_ADSP_SHARE_MASK                0x08
+#define CS35L32_ADSP_DATACFG_MASK      0x30
+#define CS35L32_SDOUT_3ST              0x80
+#define CS35L32_BATT_REC_MASK          0x0E
+#define CS35L32_BATT_THRESH_MASK       0x30
+
+#define CS35L32_RATES (SNDRV_PCM_RATE_48000)
+#define CS35L32_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \
+                       SNDRV_PCM_FMTBIT_S24_LE | \
+                       SNDRV_PCM_FMTBIT_S32_LE)
+
+
+#endif
index 69a85164357c58ab66ae761edfe0449e9f9f471b..4fdd47d700e325ac290fe118c9d3dd58d71b7ec9 100644 (file)
@@ -77,6 +77,7 @@ static bool cs4265_readable_register(struct device *dev, unsigned int reg)
        case CS4265_INT_MASK:
        case CS4265_STATUS_MODE_MSB:
        case CS4265_STATUS_MODE_LSB:
+       case CS4265_CHIP_ID:
                return true;
        default:
                return false;
index 969167d8b71e0fa8ff68a61f2014564e1a69aa5d..35fbef743fbe21883db9d2e645ea018a5c8c9080 100644 (file)
@@ -176,9 +176,9 @@ static bool cs42l52_volatile_register(struct device *dev, unsigned int reg)
        case CS42L52_BATT_LEVEL:
        case CS42L52_SPK_STATUS:
        case CS42L52_CHARGE_PUMP:
-               return 1;
+               return true;
        default:
-               return 0;
+               return false;
        }
 }
 
@@ -946,20 +946,6 @@ static struct snd_soc_dai_driver cs42l52_dai = {
                .ops = &cs42l52_ops,
 };
 
-static int cs42l52_suspend(struct snd_soc_codec *codec)
-{
-       cs42l52_set_bias_level(codec, SND_SOC_BIAS_OFF);
-
-       return 0;
-}
-
-static int cs42l52_resume(struct snd_soc_codec *codec)
-{
-       cs42l52_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
-
-       return 0;
-}
-
 static int beep_rates[] = {
        261, 522, 585, 667, 706, 774, 889, 1000,
        1043, 1200, 1333, 1412, 1600, 1714, 2000, 2182
@@ -1104,8 +1090,6 @@ static int cs42l52_probe(struct snd_soc_codec *codec)
 
        cs42l52_init_beep(codec);
 
-       cs42l52_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
-
        cs42l52->sysclk = CS42L52_DEFAULT_CLK;
        cs42l52->config.format = CS42L52_DEFAULT_FORMAT;
 
@@ -1115,7 +1099,6 @@ static int cs42l52_probe(struct snd_soc_codec *codec)
 static int cs42l52_remove(struct snd_soc_codec *codec)
 {
        cs42l52_free_beep(codec);
-       cs42l52_set_bias_level(codec, SND_SOC_BIAS_OFF);
 
        return 0;
 }
@@ -1123,9 +1106,8 @@ static int cs42l52_remove(struct snd_soc_codec *codec)
 static struct snd_soc_codec_driver soc_codec_dev_cs42l52 = {
        .probe = cs42l52_probe,
        .remove = cs42l52_remove,
-       .suspend = cs42l52_suspend,
-       .resume = cs42l52_resume,
        .set_bias_level = cs42l52_set_bias_level,
+       .suspend_bias_off = true,
 
        .dapm_widgets = cs42l52_dapm_widgets,
        .num_dapm_widgets = ARRAY_SIZE(cs42l52_dapm_widgets),
index c766a5a9ce8088441df5d363c91244c49d270798..2ddc7ac10ad7a311ccda24f7add9613891b068c9 100644 (file)
@@ -171,9 +171,9 @@ static bool cs42l56_volatile_register(struct device *dev, unsigned int reg)
 {
        switch (reg) {
        case CS42L56_INT_STATUS:
-               return 1;
+               return true;
        default:
-               return 0;
+               return false;
        }
 }
 
@@ -1016,20 +1016,6 @@ static struct snd_soc_dai_driver cs42l56_dai = {
                .ops = &cs42l56_ops,
 };
 
-static int cs42l56_suspend(struct snd_soc_codec *codec)
-{
-       cs42l56_set_bias_level(codec, SND_SOC_BIAS_OFF);
-
-       return 0;
-}
-
-static int cs42l56_resume(struct snd_soc_codec *codec)
-{
-       cs42l56_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
-
-       return 0;
-}
-
 static int beep_freq[] = {
        261, 522, 585, 667, 706, 774, 889, 1000,
        1043, 1200, 1333, 1412, 1600, 1714, 2000, 2182
@@ -1168,18 +1154,12 @@ static int cs42l56_probe(struct snd_soc_codec *codec)
 {
        cs42l56_init_beep(codec);
 
-       cs42l56_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
-
        return 0;
 }
 
 static int cs42l56_remove(struct snd_soc_codec *codec)
 {
-       struct cs42l56_private *cs42l56 = snd_soc_codec_get_drvdata(codec);
-
        cs42l56_free_beep(codec);
-       cs42l56_set_bias_level(codec, SND_SOC_BIAS_OFF);
-       regulator_bulk_free(ARRAY_SIZE(cs42l56->supplies), cs42l56->supplies);
 
        return 0;
 }
@@ -1187,9 +1167,8 @@ static int cs42l56_remove(struct snd_soc_codec *codec)
 static struct snd_soc_codec_driver soc_codec_dev_cs42l56 = {
        .probe = cs42l56_probe,
        .remove = cs42l56_remove,
-       .suspend = cs42l56_suspend,
-       .resume = cs42l56_resume,
        .set_bias_level = cs42l56_set_bias_level,
+       .suspend_bias_off = true,
 
        .dapm_widgets = cs42l56_dapm_widgets,
        .num_dapm_widgets = ARRAY_SIZE(cs42l56_dapm_widgets),
index 0e7b9eb2ba61669021064d76c827f759dd50c644..2f8b94683e83054febd1642719e5ecb61df99725 100644 (file)
@@ -1330,25 +1330,10 @@ static struct snd_soc_dai_driver cs42l73_dai[] = {
         }
 };
 
-static int cs42l73_suspend(struct snd_soc_codec *codec)
-{
-       cs42l73_set_bias_level(codec, SND_SOC_BIAS_OFF);
-
-       return 0;
-}
-
-static int cs42l73_resume(struct snd_soc_codec *codec)
-{
-       cs42l73_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
-       return 0;
-}
-
 static int cs42l73_probe(struct snd_soc_codec *codec)
 {
        struct cs42l73_private *cs42l73 = snd_soc_codec_get_drvdata(codec);
 
-       cs42l73_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
-
        /* Set Charge Pump Frequency */
        if (cs42l73->pdata.chgfreq)
                snd_soc_update_bits(codec, CS42L73_CPFCHC,
@@ -1362,18 +1347,10 @@ static int cs42l73_probe(struct snd_soc_codec *codec)
        return 0;
 }
 
-static int cs42l73_remove(struct snd_soc_codec *codec)
-{
-       cs42l73_set_bias_level(codec, SND_SOC_BIAS_OFF);
-       return 0;
-}
-
 static struct snd_soc_codec_driver soc_codec_dev_cs42l73 = {
        .probe = cs42l73_probe,
-       .remove = cs42l73_remove,
-       .suspend = cs42l73_suspend,
-       .resume = cs42l73_resume,
        .set_bias_level = cs42l73_set_bias_level,
+       .suspend_bias_off = true,
 
        .dapm_widgets = cs42l73_dapm_widgets,
        .num_dapm_widgets = ARRAY_SIZE(cs42l73_dapm_widgets),
index 2fae31cb006745587e0fb1a51491dd10e0facea5..61b2f9a2eef1b87d8daea13ab83d90779a883fc5 100644 (file)
@@ -35,7 +35,6 @@
 
 struct da732x_priv {
        struct regmap *regmap;
-       struct snd_soc_codec *codec;
 
        unsigned int sysclk;
        bool pll_en;
@@ -217,7 +216,7 @@ static void da732x_set_charge_pump(struct snd_soc_codec *codec, int state)
                snd_soc_write(codec, DA732X_REG_CP_CTRL1, DA723X_CP_DIS);
                break;
        default:
-               pr_err(KERN_ERR "Wrong charge pump state\n");
+               pr_err("Wrong charge pump state\n");
                break;
        }
 }
@@ -1508,31 +1507,7 @@ static int da732x_set_bias_level(struct snd_soc_codec *codec,
        return 0;
 }
 
-static int da732x_probe(struct snd_soc_codec *codec)
-{
-       struct da732x_priv *da732x = snd_soc_codec_get_drvdata(codec);
-       struct snd_soc_dapm_context *dapm = &codec->dapm;
-
-       da732x->codec = codec;
-
-       dapm->idle_bias_off = false;
-
-       da732x_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
-
-       return 0;
-}
-
-static int da732x_remove(struct snd_soc_codec *codec)
-{
-
-       da732x_set_bias_level(codec, SND_SOC_BIAS_OFF);
-
-       return 0;
-}
-
 static struct snd_soc_codec_driver soc_codec_dev_da732x = {
-       .probe                  = da732x_probe,
-       .remove                 = da732x_remove,
        .set_bias_level         = da732x_set_bias_level,
        .controls               = da732x_snd_controls,
        .num_controls           = ARRAY_SIZE(da732x_snd_controls),
diff --git a/sound/soc/codecs/es8328-i2c.c b/sound/soc/codecs/es8328-i2c.c
new file mode 100644 (file)
index 0000000..aae410d
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * es8328-i2c.c  --  ES8328 ALSA SoC I2C Audio driver
+ *
+ * Copyright 2014 Sutajio Ko-Usagi PTE LTD
+ *
+ * Author: Sean Cross <xobs@kosagi.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/regmap.h>
+
+#include <sound/soc.h>
+
+#include "es8328.h"
+
+static const struct i2c_device_id es8328_id[] = {
+       { "everest,es8328", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, es8328_id);
+
+static const struct of_device_id es8328_of_match[] = {
+       { .compatible = "everest,es8328", },
+       { }
+};
+MODULE_DEVICE_TABLE(of, es8328_of_match);
+
+static int es8328_i2c_probe(struct i2c_client *i2c,
+                           const struct i2c_device_id *id)
+{
+       return es8328_probe(&i2c->dev,
+                       devm_regmap_init_i2c(i2c, &es8328_regmap_config));
+}
+
+static int es8328_i2c_remove(struct i2c_client *i2c)
+{
+       snd_soc_unregister_codec(&i2c->dev);
+       return 0;
+}
+
+static struct i2c_driver es8328_i2c_driver = {
+       .driver = {
+               .name           = "es8328",
+               .of_match_table = es8328_of_match,
+       },
+       .probe    = es8328_i2c_probe,
+       .remove   = es8328_i2c_remove,
+       .id_table = es8328_id,
+};
+
+module_i2c_driver(es8328_i2c_driver);
+
+MODULE_DESCRIPTION("ASoC ES8328 audio CODEC I2C driver");
+MODULE_AUTHOR("Sean Cross <xobs@kosagi.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/es8328-spi.c b/sound/soc/codecs/es8328-spi.c
new file mode 100644 (file)
index 0000000..8fbd935
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * es8328.c  --  ES8328 ALSA SoC SPI Audio driver
+ *
+ * Copyright 2014 Sutajio Ko-Usagi PTE LTD
+ *
+ * Author: Sean Cross <xobs@kosagi.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <linux/spi/spi.h>
+#include <sound/soc.h>
+#include "es8328.h"
+
+static const struct of_device_id es8328_of_match[] = {
+       { .compatible = "everest,es8328", },
+       { }
+};
+MODULE_DEVICE_TABLE(of, es8328_of_match);
+
+static int es8328_spi_probe(struct spi_device *spi)
+{
+       return es8328_probe(&spi->dev,
+                       devm_regmap_init_spi(spi, &es8328_regmap_config));
+}
+
+static int es8328_spi_remove(struct spi_device *spi)
+{
+       snd_soc_unregister_codec(&spi->dev);
+       return 0;
+}
+
+static struct spi_driver es8328_spi_driver = {
+       .driver = {
+               .name           = "es8328",
+               .of_match_table = es8328_of_match,
+       },
+       .probe  = es8328_spi_probe,
+       .remove = es8328_spi_remove,
+};
+
+module_spi_driver(es8328_spi_driver);
+MODULE_DESCRIPTION("ASoC ES8328 audio CODEC SPI driver");
+MODULE_AUTHOR("Sean Cross <xobs@kosagi.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/es8328.c b/sound/soc/codecs/es8328.c
new file mode 100644 (file)
index 0000000..f273251
--- /dev/null
@@ -0,0 +1,756 @@
+/*
+ * es8328.c  --  ES8328 ALSA SoC Audio driver
+ *
+ * Copyright 2014 Sutajio Ko-Usagi PTE LTD
+ *
+ * Author: Sean Cross <xobs@kosagi.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/clk.h>
+#include <linux/delay.h>
+#include <linux/of_device.h>
+#include <linux/module.h>
+#include <linux/pm.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <linux/regulator/consumer.h>
+#include <sound/core.h>
+#include <sound/initval.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/tlv.h>
+#include "es8328.h"
+
+#define ES8328_SYSCLK_RATE_1X 11289600
+#define ES8328_SYSCLK_RATE_2X 22579200
+
+/* Run the codec at 22.5792 or 11.2896 MHz to support these rates */
+static struct {
+       int rate;
+       u8 ratio;
+} mclk_ratios[] = {
+       { 8000, 9 },
+       {11025, 7 },
+       {22050, 4 },
+       {44100, 2 },
+};
+
+/* regulator supplies for sgtl5000, VDDD is an optional external supply */
+enum sgtl5000_regulator_supplies {
+       DVDD,
+       AVDD,
+       PVDD,
+       HPVDD,
+       ES8328_SUPPLY_NUM
+};
+
+/* vddd is optional supply */
+static const char * const supply_names[ES8328_SUPPLY_NUM] = {
+       "DVDD",
+       "AVDD",
+       "PVDD",
+       "HPVDD",
+};
+
+#define ES8328_RATES (SNDRV_PCM_RATE_44100 | \
+               SNDRV_PCM_RATE_22050 | \
+               SNDRV_PCM_RATE_11025)
+#define ES8328_FORMATS (SNDRV_PCM_FMTBIT_S16_LE)
+
+struct es8328_priv {
+       struct regmap *regmap;
+       struct clk *clk;
+       int playback_fs;
+       bool deemph;
+       struct regulator_bulk_data supplies[ES8328_SUPPLY_NUM];
+};
+
+/*
+ * ES8328 Controls
+ */
+
+static const char * const adcpol_txt[] = {"Normal", "L Invert", "R Invert",
+                                         "L + R Invert"};
+static SOC_ENUM_SINGLE_DECL(adcpol,
+                           ES8328_ADCCONTROL6, 6, adcpol_txt);
+
+static const DECLARE_TLV_DB_SCALE(play_tlv, -3000, 100, 0);
+static const DECLARE_TLV_DB_SCALE(dac_adc_tlv, -9600, 50, 0);
+static const DECLARE_TLV_DB_SCALE(pga_tlv, 0, 300, 0);
+static const DECLARE_TLV_DB_SCALE(bypass_tlv, -1500, 300, 0);
+static const DECLARE_TLV_DB_SCALE(mic_tlv, 0, 300, 0);
+
+static const int deemph_settings[] = { 0, 32000, 44100, 48000 };
+
+static int es8328_set_deemph(struct snd_soc_codec *codec)
+{
+       struct es8328_priv *es8328 = snd_soc_codec_get_drvdata(codec);
+       int val, i, best;
+
+       /*
+        * If we're using deemphasis select the nearest available sample
+        * rate.
+        */
+       if (es8328->deemph) {
+               best = 1;
+               for (i = 2; i < ARRAY_SIZE(deemph_settings); i++) {
+                       if (abs(deemph_settings[i] - es8328->playback_fs) <
+                           abs(deemph_settings[best] - es8328->playback_fs))
+                               best = i;
+               }
+
+               val = best << 1;
+       } else {
+               val = 0;
+       }
+
+       dev_dbg(codec->dev, "Set deemphasis %d\n", val);
+
+       return snd_soc_update_bits(codec, ES8328_DACCONTROL6, 0x6, val);
+}
+
+static int es8328_get_deemph(struct snd_kcontrol *kcontrol,
+                            struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+       struct es8328_priv *es8328 = snd_soc_codec_get_drvdata(codec);
+
+       ucontrol->value.enumerated.item[0] = es8328->deemph;
+       return 0;
+}
+
+static int es8328_put_deemph(struct snd_kcontrol *kcontrol,
+                            struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+       struct es8328_priv *es8328 = snd_soc_codec_get_drvdata(codec);
+       int deemph = ucontrol->value.enumerated.item[0];
+       int ret;
+
+       if (deemph > 1)
+               return -EINVAL;
+
+       ret = es8328_set_deemph(codec);
+       if (ret < 0)
+               return ret;
+
+       es8328->deemph = deemph;
+
+       return 0;
+}
+
+
+
+static const struct snd_kcontrol_new es8328_snd_controls[] = {
+       SOC_DOUBLE_R_TLV("Capture Digital Volume",
+               ES8328_ADCCONTROL8, ES8328_ADCCONTROL9,
+                0, 0xc0, 1, dac_adc_tlv),
+       SOC_SINGLE("Capture ZC Switch", ES8328_ADCCONTROL7, 6, 1, 0),
+
+       SOC_SINGLE_BOOL_EXT("DAC Deemphasis Switch", 0,
+                   es8328_get_deemph, es8328_put_deemph),
+
+       SOC_ENUM("Capture Polarity", adcpol),
+
+       SOC_SINGLE_TLV("Left Mixer Left Bypass Volume",
+                       ES8328_DACCONTROL17, 3, 7, 1, bypass_tlv),
+       SOC_SINGLE_TLV("Left Mixer Right Bypass Volume",
+                       ES8328_DACCONTROL19, 3, 7, 1, bypass_tlv),
+       SOC_SINGLE_TLV("Right Mixer Left Bypass Volume",
+                       ES8328_DACCONTROL18, 3, 7, 1, bypass_tlv),
+       SOC_SINGLE_TLV("Right Mixer Right Bypass Volume",
+                       ES8328_DACCONTROL20, 3, 7, 1, bypass_tlv),
+
+       SOC_DOUBLE_R_TLV("PCM Volume",
+                       ES8328_LDACVOL, ES8328_RDACVOL,
+                       0, ES8328_DACVOL_MAX, 1, dac_adc_tlv),
+
+       SOC_DOUBLE_R_TLV("Output 1 Playback Volume",
+                       ES8328_LOUT1VOL, ES8328_ROUT1VOL,
+                       0, ES8328_OUT1VOL_MAX, 0, play_tlv),
+
+       SOC_DOUBLE_R_TLV("Output 2 Playback Volume",
+                       ES8328_LOUT2VOL, ES8328_ROUT2VOL,
+                       0, ES8328_OUT2VOL_MAX, 0, play_tlv),
+
+       SOC_DOUBLE_TLV("Mic PGA Volume", ES8328_ADCCONTROL1,
+                       4, 0, 8, 0, mic_tlv),
+};
+
+/*
+ * DAPM Controls
+ */
+
+static const char * const es8328_line_texts[] = {
+       "Line 1", "Line 2", "PGA", "Differential"};
+
+static const struct soc_enum es8328_lline_enum =
+       SOC_ENUM_SINGLE(ES8328_DACCONTROL16, 3,
+                             ARRAY_SIZE(es8328_line_texts),
+                             es8328_line_texts);
+static const struct snd_kcontrol_new es8328_left_line_controls =
+       SOC_DAPM_ENUM("Route", es8328_lline_enum);
+
+static const struct soc_enum es8328_rline_enum =
+       SOC_ENUM_SINGLE(ES8328_DACCONTROL16, 0,
+                             ARRAY_SIZE(es8328_line_texts),
+                             es8328_line_texts);
+static const struct snd_kcontrol_new es8328_right_line_controls =
+       SOC_DAPM_ENUM("Route", es8328_lline_enum);
+
+/* Left Mixer */
+static const struct snd_kcontrol_new es8328_left_mixer_controls[] = {
+       SOC_DAPM_SINGLE("Playback Switch", ES8328_DACCONTROL17, 8, 1, 0),
+       SOC_DAPM_SINGLE("Left Bypass Switch", ES8328_DACCONTROL17, 7, 1, 0),
+       SOC_DAPM_SINGLE("Right Playback Switch", ES8328_DACCONTROL18, 8, 1, 0),
+       SOC_DAPM_SINGLE("Right Bypass Switch", ES8328_DACCONTROL18, 7, 1, 0),
+};
+
+/* Right Mixer */
+static const struct snd_kcontrol_new es8328_right_mixer_controls[] = {
+       SOC_DAPM_SINGLE("Left Playback Switch", ES8328_DACCONTROL19, 8, 1, 0),
+       SOC_DAPM_SINGLE("Left Bypass Switch", ES8328_DACCONTROL19, 7, 1, 0),
+       SOC_DAPM_SINGLE("Playback Switch", ES8328_DACCONTROL20, 8, 1, 0),
+       SOC_DAPM_SINGLE("Right Bypass Switch", ES8328_DACCONTROL20, 7, 1, 0),
+};
+
+static const char * const es8328_pga_sel[] = {
+       "Line 1", "Line 2", "Line 3", "Differential"};
+
+/* Left PGA Mux */
+static const struct soc_enum es8328_lpga_enum =
+       SOC_ENUM_SINGLE(ES8328_ADCCONTROL2, 6,
+                             ARRAY_SIZE(es8328_pga_sel),
+                             es8328_pga_sel);
+static const struct snd_kcontrol_new es8328_left_pga_controls =
+       SOC_DAPM_ENUM("Route", es8328_lpga_enum);
+
+/* Right PGA Mux */
+static const struct soc_enum es8328_rpga_enum =
+       SOC_ENUM_SINGLE(ES8328_ADCCONTROL2, 4,
+                             ARRAY_SIZE(es8328_pga_sel),
+                             es8328_pga_sel);
+static const struct snd_kcontrol_new es8328_right_pga_controls =
+       SOC_DAPM_ENUM("Route", es8328_rpga_enum);
+
+/* Differential Mux */
+static const char * const es8328_diff_sel[] = {"Line 1", "Line 2"};
+static SOC_ENUM_SINGLE_DECL(diffmux,
+                           ES8328_ADCCONTROL3, 7, es8328_diff_sel);
+static const struct snd_kcontrol_new es8328_diffmux_controls =
+       SOC_DAPM_ENUM("Route", diffmux);
+
+/* Mono ADC Mux */
+static const char * const es8328_mono_mux[] = {"Stereo", "Mono (Left)",
+       "Mono (Right)", "Digital Mono"};
+static SOC_ENUM_SINGLE_DECL(monomux,
+                           ES8328_ADCCONTROL3, 3, es8328_mono_mux);
+static const struct snd_kcontrol_new es8328_monomux_controls =
+       SOC_DAPM_ENUM("Route", monomux);
+
+static const struct snd_soc_dapm_widget es8328_dapm_widgets[] = {
+       SND_SOC_DAPM_MUX("Differential Mux", SND_SOC_NOPM, 0, 0,
+               &es8328_diffmux_controls),
+       SND_SOC_DAPM_MUX("Left ADC Mux", SND_SOC_NOPM, 0, 0,
+               &es8328_monomux_controls),
+       SND_SOC_DAPM_MUX("Right ADC Mux", SND_SOC_NOPM, 0, 0,
+               &es8328_monomux_controls),
+
+       SND_SOC_DAPM_MUX("Left PGA Mux", ES8328_ADCPOWER,
+                       ES8328_ADCPOWER_AINL_OFF, 1,
+                       &es8328_left_pga_controls),
+       SND_SOC_DAPM_MUX("Right PGA Mux", ES8328_ADCPOWER,
+                       ES8328_ADCPOWER_AINR_OFF, 1,
+                       &es8328_right_pga_controls),
+
+       SND_SOC_DAPM_MUX("Left Line Mux", SND_SOC_NOPM, 0, 0,
+               &es8328_left_line_controls),
+       SND_SOC_DAPM_MUX("Right Line Mux", SND_SOC_NOPM, 0, 0,
+               &es8328_right_line_controls),
+
+       SND_SOC_DAPM_ADC("Right ADC", "Right Capture", ES8328_ADCPOWER,
+                       ES8328_ADCPOWER_ADCR_OFF, 1),
+       SND_SOC_DAPM_ADC("Left ADC", "Left Capture", ES8328_ADCPOWER,
+                       ES8328_ADCPOWER_ADCL_OFF, 1),
+
+       SND_SOC_DAPM_SUPPLY("Mic Bias", ES8328_ADCPOWER,
+                       ES8328_ADCPOWER_MIC_BIAS_OFF, 1, NULL, 0),
+       SND_SOC_DAPM_SUPPLY("Mic Bias Gen", ES8328_ADCPOWER,
+                       ES8328_ADCPOWER_ADC_BIAS_GEN_OFF, 1, NULL, 0),
+
+       SND_SOC_DAPM_SUPPLY("DAC STM", ES8328_CHIPPOWER,
+                       ES8328_CHIPPOWER_DACSTM_RESET, 1, NULL, 0),
+       SND_SOC_DAPM_SUPPLY("ADC STM", ES8328_CHIPPOWER,
+                       ES8328_CHIPPOWER_ADCSTM_RESET, 1, NULL, 0),
+
+       SND_SOC_DAPM_SUPPLY("DAC DIG", ES8328_CHIPPOWER,
+                       ES8328_CHIPPOWER_DACDIG_OFF, 1, NULL, 0),
+       SND_SOC_DAPM_SUPPLY("ADC DIG", ES8328_CHIPPOWER,
+                       ES8328_CHIPPOWER_ADCDIG_OFF, 1, NULL, 0),
+
+       SND_SOC_DAPM_SUPPLY("DAC DLL", ES8328_CHIPPOWER,
+                       ES8328_CHIPPOWER_DACDLL_OFF, 1, NULL, 0),
+       SND_SOC_DAPM_SUPPLY("ADC DLL", ES8328_CHIPPOWER,
+                       ES8328_CHIPPOWER_ADCDLL_OFF, 1, NULL, 0),
+
+       SND_SOC_DAPM_SUPPLY("ADC Vref", ES8328_CHIPPOWER,
+                       ES8328_CHIPPOWER_ADCVREF_OFF, 1, NULL, 0),
+       SND_SOC_DAPM_SUPPLY("DAC Vref", ES8328_CHIPPOWER,
+                       ES8328_CHIPPOWER_DACVREF_OFF, 1, NULL, 0),
+
+       SND_SOC_DAPM_DAC("Right DAC", "Right Playback", ES8328_DACPOWER,
+                       ES8328_DACPOWER_RDAC_OFF, 1),
+       SND_SOC_DAPM_DAC("Left DAC", "Left Playback", ES8328_DACPOWER,
+                       ES8328_DACPOWER_LDAC_OFF, 1),
+
+       SND_SOC_DAPM_MIXER("Left Mixer", SND_SOC_NOPM, 0, 0,
+               &es8328_left_mixer_controls[0],
+               ARRAY_SIZE(es8328_left_mixer_controls)),
+       SND_SOC_DAPM_MIXER("Right Mixer", SND_SOC_NOPM, 0, 0,
+               &es8328_right_mixer_controls[0],
+               ARRAY_SIZE(es8328_right_mixer_controls)),
+
+       SND_SOC_DAPM_PGA("Right Out 2", ES8328_DACPOWER,
+                       ES8328_DACPOWER_ROUT2_ON, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("Left Out 2", ES8328_DACPOWER,
+                       ES8328_DACPOWER_LOUT2_ON, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("Right Out 1", ES8328_DACPOWER,
+                       ES8328_DACPOWER_ROUT1_ON, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("Left Out 1", ES8328_DACPOWER,
+                       ES8328_DACPOWER_LOUT1_ON, 0, NULL, 0),
+
+       SND_SOC_DAPM_OUTPUT("LOUT1"),
+       SND_SOC_DAPM_OUTPUT("ROUT1"),
+       SND_SOC_DAPM_OUTPUT("LOUT2"),
+       SND_SOC_DAPM_OUTPUT("ROUT2"),
+
+       SND_SOC_DAPM_INPUT("LINPUT1"),
+       SND_SOC_DAPM_INPUT("LINPUT2"),
+       SND_SOC_DAPM_INPUT("RINPUT1"),
+       SND_SOC_DAPM_INPUT("RINPUT2"),
+};
+
+static const struct snd_soc_dapm_route es8328_dapm_routes[] = {
+
+       { "Left Line Mux", "Line 1", "LINPUT1" },
+       { "Left Line Mux", "Line 2", "LINPUT2" },
+       { "Left Line Mux", "PGA", "Left PGA Mux" },
+       { "Left Line Mux", "Differential", "Differential Mux" },
+
+       { "Right Line Mux", "Line 1", "RINPUT1" },
+       { "Right Line Mux", "Line 2", "RINPUT2" },
+       { "Right Line Mux", "PGA", "Right PGA Mux" },
+       { "Right Line Mux", "Differential", "Differential Mux" },
+
+       { "Left PGA Mux", "Line 1", "LINPUT1" },
+       { "Left PGA Mux", "Line 2", "LINPUT2" },
+       { "Left PGA Mux", "Differential", "Differential Mux" },
+
+       { "Right PGA Mux", "Line 1", "RINPUT1" },
+       { "Right PGA Mux", "Line 2", "RINPUT2" },
+       { "Right PGA Mux", "Differential", "Differential Mux" },
+
+       { "Differential Mux", "Line 1", "LINPUT1" },
+       { "Differential Mux", "Line 1", "RINPUT1" },
+       { "Differential Mux", "Line 2", "LINPUT2" },
+       { "Differential Mux", "Line 2", "RINPUT2" },
+
+       { "Left ADC Mux", "Stereo", "Left PGA Mux" },
+       { "Left ADC Mux", "Mono (Left)", "Left PGA Mux" },
+       { "Left ADC Mux", "Digital Mono", "Left PGA Mux" },
+
+       { "Right ADC Mux", "Stereo", "Right PGA Mux" },
+       { "Right ADC Mux", "Mono (Right)", "Right PGA Mux" },
+       { "Right ADC Mux", "Digital Mono", "Right PGA Mux" },
+
+       { "Left ADC", NULL, "Left ADC Mux" },
+       { "Right ADC", NULL, "Right ADC Mux" },
+
+       { "ADC DIG", NULL, "ADC STM" },
+       { "ADC DIG", NULL, "ADC Vref" },
+       { "ADC DIG", NULL, "ADC DLL" },
+
+       { "Left ADC", NULL, "ADC DIG" },
+       { "Right ADC", NULL, "ADC DIG" },
+
+       { "Mic Bias", NULL, "Mic Bias Gen" },
+
+       { "Left Line Mux", "Line 1", "LINPUT1" },
+       { "Left Line Mux", "Line 2", "LINPUT2" },
+       { "Left Line Mux", "PGA", "Left PGA Mux" },
+       { "Left Line Mux", "Differential", "Differential Mux" },
+
+       { "Right Line Mux", "Line 1", "RINPUT1" },
+       { "Right Line Mux", "Line 2", "RINPUT2" },
+       { "Right Line Mux", "PGA", "Right PGA Mux" },
+       { "Right Line Mux", "Differential", "Differential Mux" },
+
+       { "Left Out 1", NULL, "Left DAC" },
+       { "Right Out 1", NULL, "Right DAC" },
+       { "Left Out 2", NULL, "Left DAC" },
+       { "Right Out 2", NULL, "Right DAC" },
+
+       { "Left Mixer", "Playback Switch", "Left DAC" },
+       { "Left Mixer", "Left Bypass Switch", "Left Line Mux" },
+       { "Left Mixer", "Right Playback Switch", "Right DAC" },
+       { "Left Mixer", "Right Bypass Switch", "Right Line Mux" },
+
+       { "Right Mixer", "Left Playback Switch", "Left DAC" },
+       { "Right Mixer", "Left Bypass Switch", "Left Line Mux" },
+       { "Right Mixer", "Playback Switch", "Right DAC" },
+       { "Right Mixer", "Right Bypass Switch", "Right Line Mux" },
+
+       { "DAC DIG", NULL, "DAC STM" },
+       { "DAC DIG", NULL, "DAC Vref" },
+       { "DAC DIG", NULL, "DAC DLL" },
+
+       { "Left DAC", NULL, "DAC DIG" },
+       { "Right DAC", NULL, "DAC DIG" },
+
+       { "Left Out 1", NULL, "Left Mixer" },
+       { "LOUT1", NULL, "Left Out 1" },
+       { "Right Out 1", NULL, "Right Mixer" },
+       { "ROUT1", NULL, "Right Out 1" },
+
+       { "Left Out 2", NULL, "Left Mixer" },
+       { "LOUT2", NULL, "Left Out 2" },
+       { "Right Out 2", NULL, "Right Mixer" },
+       { "ROUT2", NULL, "Right Out 2" },
+};
+
+static int es8328_mute(struct snd_soc_dai *dai, int mute)
+{
+       return snd_soc_update_bits(dai->codec, ES8328_DACCONTROL3,
+                       ES8328_DACCONTROL3_DACMUTE,
+                       mute ? ES8328_DACCONTROL3_DACMUTE : 0);
+}
+
+static int es8328_hw_params(struct snd_pcm_substream *substream,
+       struct snd_pcm_hw_params *params,
+       struct snd_soc_dai *dai)
+{
+       struct snd_soc_codec *codec = dai->codec;
+       struct es8328_priv *es8328 = snd_soc_codec_get_drvdata(codec);
+       int clk_rate;
+       int i;
+       int reg;
+       u8 ratio;
+
+       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+               reg = ES8328_DACCONTROL2;
+       else
+               reg = ES8328_ADCCONTROL5;
+
+       clk_rate = clk_get_rate(es8328->clk);
+
+       if ((clk_rate != ES8328_SYSCLK_RATE_1X) &&
+               (clk_rate != ES8328_SYSCLK_RATE_2X)) {
+               dev_err(codec->dev,
+                       "%s: clock is running at %d Hz, not %d or %d Hz\n",
+                        __func__, clk_rate,
+                        ES8328_SYSCLK_RATE_1X, ES8328_SYSCLK_RATE_2X);
+               return -EINVAL;
+       }
+
+       /* find master mode MCLK to sampling frequency ratio */
+       ratio = mclk_ratios[0].rate;
+       for (i = 1; i < ARRAY_SIZE(mclk_ratios); i++)
+               if (params_rate(params) <= mclk_ratios[i].rate)
+                       ratio = mclk_ratios[i].ratio;
+
+       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+               es8328->playback_fs = params_rate(params);
+               es8328_set_deemph(codec);
+       }
+
+       return snd_soc_update_bits(codec, reg, ES8328_RATEMASK, ratio);
+}
+
+static int es8328_set_dai_fmt(struct snd_soc_dai *codec_dai,
+               unsigned int fmt)
+{
+       struct snd_soc_codec *codec = codec_dai->codec;
+       struct es8328_priv *es8328 = snd_soc_codec_get_drvdata(codec);
+       int clk_rate;
+       u8 mode = ES8328_DACCONTROL1_DACWL_16;
+
+       /* set master/slave audio interface */
+       if ((fmt & SND_SOC_DAIFMT_MASTER_MASK) != SND_SOC_DAIFMT_CBM_CFM)
+               return -EINVAL;
+
+       /* interface format */
+       switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+       case SND_SOC_DAIFMT_I2S:
+               mode |= ES8328_DACCONTROL1_DACFORMAT_I2S;
+               break;
+       case SND_SOC_DAIFMT_RIGHT_J:
+               mode |= ES8328_DACCONTROL1_DACFORMAT_RJUST;
+               break;
+       case SND_SOC_DAIFMT_LEFT_J:
+               mode |= ES8328_DACCONTROL1_DACFORMAT_LJUST;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       /* clock inversion */
+       if ((fmt & SND_SOC_DAIFMT_INV_MASK) != SND_SOC_DAIFMT_NB_NF)
+               return -EINVAL;
+
+       snd_soc_write(codec, ES8328_DACCONTROL1, mode);
+       snd_soc_write(codec, ES8328_ADCCONTROL4, mode);
+
+       /* Master serial port mode, with BCLK generated automatically */
+       clk_rate = clk_get_rate(es8328->clk);
+       if (clk_rate == ES8328_SYSCLK_RATE_1X)
+               snd_soc_write(codec, ES8328_MASTERMODE,
+                               ES8328_MASTERMODE_MSC);
+       else
+               snd_soc_write(codec, ES8328_MASTERMODE,
+                               ES8328_MASTERMODE_MCLKDIV2 |
+                               ES8328_MASTERMODE_MSC);
+
+       return 0;
+}
+
+static int es8328_set_bias_level(struct snd_soc_codec *codec,
+                                enum snd_soc_bias_level level)
+{
+       switch (level) {
+       case SND_SOC_BIAS_ON:
+               break;
+
+       case SND_SOC_BIAS_PREPARE:
+               /* VREF, VMID=2x50k, digital enabled */
+               snd_soc_write(codec, ES8328_CHIPPOWER, 0);
+               snd_soc_update_bits(codec, ES8328_CONTROL1,
+                               ES8328_CONTROL1_VMIDSEL_MASK |
+                               ES8328_CONTROL1_ENREF,
+                               ES8328_CONTROL1_VMIDSEL_50k |
+                               ES8328_CONTROL1_ENREF);
+               break;
+
+       case SND_SOC_BIAS_STANDBY:
+               if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
+                       snd_soc_update_bits(codec, ES8328_CONTROL1,
+                                       ES8328_CONTROL1_VMIDSEL_MASK |
+                                       ES8328_CONTROL1_ENREF,
+                                       ES8328_CONTROL1_VMIDSEL_5k |
+                                       ES8328_CONTROL1_ENREF);
+
+                       /* Charge caps */
+                       msleep(100);
+               }
+
+               snd_soc_write(codec, ES8328_CONTROL2,
+                               ES8328_CONTROL2_OVERCURRENT_ON |
+                               ES8328_CONTROL2_THERMAL_SHUTDOWN_ON);
+
+               /* VREF, VMID=2*500k, digital stopped */
+               snd_soc_update_bits(codec, ES8328_CONTROL1,
+                               ES8328_CONTROL1_VMIDSEL_MASK |
+                               ES8328_CONTROL1_ENREF,
+                               ES8328_CONTROL1_VMIDSEL_500k |
+                               ES8328_CONTROL1_ENREF);
+               break;
+
+       case SND_SOC_BIAS_OFF:
+               snd_soc_update_bits(codec, ES8328_CONTROL1,
+                               ES8328_CONTROL1_VMIDSEL_MASK |
+                               ES8328_CONTROL1_ENREF,
+                               0);
+               break;
+       }
+       codec->dapm.bias_level = level;
+       return 0;
+}
+
+static const struct snd_soc_dai_ops es8328_dai_ops = {
+       .hw_params      = es8328_hw_params,
+       .digital_mute   = es8328_mute,
+       .set_fmt        = es8328_set_dai_fmt,
+};
+
+static struct snd_soc_dai_driver es8328_dai = {
+       .name = "es8328-hifi-analog",
+       .playback = {
+               .stream_name = "Playback",
+               .channels_min = 2,
+               .channels_max = 2,
+               .rates = ES8328_RATES,
+               .formats = ES8328_FORMATS,
+       },
+       .capture = {
+               .stream_name = "Capture",
+               .channels_min = 2,
+               .channels_max = 2,
+               .rates = ES8328_RATES,
+               .formats = ES8328_FORMATS,
+       },
+       .ops = &es8328_dai_ops,
+};
+
+static int es8328_suspend(struct snd_soc_codec *codec)
+{
+       struct es8328_priv *es8328;
+       int ret;
+
+       es8328 = snd_soc_codec_get_drvdata(codec);
+
+       clk_disable_unprepare(es8328->clk);
+
+       ret = regulator_bulk_disable(ARRAY_SIZE(es8328->supplies),
+                       es8328->supplies);
+       if (ret) {
+               dev_err(codec->dev, "unable to disable regulators\n");
+               return ret;
+       }
+       return 0;
+}
+
+static int es8328_resume(struct snd_soc_codec *codec)
+{
+       struct regmap *regmap = dev_get_regmap(codec->dev, NULL);
+       struct es8328_priv *es8328;
+       int ret;
+
+       es8328 = snd_soc_codec_get_drvdata(codec);
+
+       ret = clk_prepare_enable(es8328->clk);
+       if (ret) {
+               dev_err(codec->dev, "unable to enable clock\n");
+               return ret;
+       }
+
+       ret = regulator_bulk_enable(ARRAY_SIZE(es8328->supplies),
+                                       es8328->supplies);
+       if (ret) {
+               dev_err(codec->dev, "unable to enable regulators\n");
+               return ret;
+       }
+
+       regcache_mark_dirty(regmap);
+       ret = regcache_sync(regmap);
+       if (ret) {
+               dev_err(codec->dev, "unable to sync regcache\n");
+               return ret;
+       }
+
+       return 0;
+}
+
+static int es8328_codec_probe(struct snd_soc_codec *codec)
+{
+       struct es8328_priv *es8328;
+       int ret;
+
+       es8328 = snd_soc_codec_get_drvdata(codec);
+
+       ret = regulator_bulk_enable(ARRAY_SIZE(es8328->supplies),
+                                       es8328->supplies);
+       if (ret) {
+               dev_err(codec->dev, "unable to enable regulators\n");
+               return ret;
+       }
+
+       /* Setup clocks */
+       es8328->clk = devm_clk_get(codec->dev, NULL);
+       if (IS_ERR(es8328->clk)) {
+               dev_err(codec->dev, "codec clock missing or invalid\n");
+               ret = PTR_ERR(es8328->clk);
+               goto clk_fail;
+       }
+
+       ret = clk_prepare_enable(es8328->clk);
+       if (ret) {
+               dev_err(codec->dev, "unable to prepare codec clk\n");
+               goto clk_fail;
+       }
+
+       return 0;
+
+clk_fail:
+       regulator_bulk_disable(ARRAY_SIZE(es8328->supplies),
+                              es8328->supplies);
+       return ret;
+}
+
+static int es8328_remove(struct snd_soc_codec *codec)
+{
+       struct es8328_priv *es8328;
+
+       es8328 = snd_soc_codec_get_drvdata(codec);
+
+       if (es8328->clk)
+               clk_disable_unprepare(es8328->clk);
+
+       regulator_bulk_disable(ARRAY_SIZE(es8328->supplies),
+                              es8328->supplies);
+
+       return 0;
+}
+
+const struct regmap_config es8328_regmap_config = {
+       .reg_bits       = 8,
+       .val_bits       = 8,
+       .max_register   = ES8328_REG_MAX,
+       .cache_type     = REGCACHE_RBTREE,
+};
+EXPORT_SYMBOL_GPL(es8328_regmap_config);
+
+static struct snd_soc_codec_driver es8328_codec_driver = {
+       .probe            = es8328_codec_probe,
+       .suspend          = es8328_suspend,
+       .resume           = es8328_resume,
+       .remove           = es8328_remove,
+       .set_bias_level   = es8328_set_bias_level,
+       .suspend_bias_off = true,
+
+       .controls         = es8328_snd_controls,
+       .num_controls     = ARRAY_SIZE(es8328_snd_controls),
+       .dapm_widgets     = es8328_dapm_widgets,
+       .num_dapm_widgets = ARRAY_SIZE(es8328_dapm_widgets),
+       .dapm_routes      = es8328_dapm_routes,
+       .num_dapm_routes  = ARRAY_SIZE(es8328_dapm_routes),
+};
+
+int es8328_probe(struct device *dev, struct regmap *regmap)
+{
+       struct es8328_priv *es8328;
+       int ret;
+       int i;
+
+       if (IS_ERR(regmap))
+               return PTR_ERR(regmap);
+
+       es8328 = devm_kzalloc(dev, sizeof(*es8328), GFP_KERNEL);
+       if (es8328 == NULL)
+               return -ENOMEM;
+
+       es8328->regmap = regmap;
+
+       for (i = 0; i < ARRAY_SIZE(es8328->supplies); i++)
+               es8328->supplies[i].supply = supply_names[i];
+
+       ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(es8328->supplies),
+                               es8328->supplies);
+       if (ret) {
+               dev_err(dev, "unable to get regulators\n");
+               return ret;
+       }
+
+       dev_set_drvdata(dev, es8328);
+
+       return snd_soc_register_codec(dev,
+                       &es8328_codec_driver, &es8328_dai, 1);
+}
+EXPORT_SYMBOL_GPL(es8328_probe);
+
+MODULE_DESCRIPTION("ASoC ES8328 driver");
+MODULE_AUTHOR("Sean Cross <xobs@kosagi.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/es8328.h b/sound/soc/codecs/es8328.h
new file mode 100644 (file)
index 0000000..cb36afe
--- /dev/null
@@ -0,0 +1,314 @@
+/*
+ * es8328.h  --  ES8328 ALSA SoC Audio driver
+ */
+
+#ifndef _ES8328_H
+#define _ES8328_H
+
+#include <linux/regmap.h>
+
+struct device;
+
+extern const struct regmap_config es8328_regmap_config;
+int es8328_probe(struct device *dev, struct regmap *regmap);
+
+#define ES8328_DACLVOL 46
+#define ES8328_DACRVOL 47
+#define ES8328_DACCTL 28
+#define ES8328_RATEMASK (0x1f << 0)
+
+#define ES8328_CONTROL1                0x00
+#define ES8328_CONTROL1_VMIDSEL_OFF (0 << 0)
+#define ES8328_CONTROL1_VMIDSEL_50k (1 << 0)
+#define ES8328_CONTROL1_VMIDSEL_500k (2 << 0)
+#define ES8328_CONTROL1_VMIDSEL_5k (3 << 0)
+#define ES8328_CONTROL1_VMIDSEL_MASK (7 << 0)
+#define ES8328_CONTROL1_ENREF (1 << 2)
+#define ES8328_CONTROL1_SEQEN (1 << 3)
+#define ES8328_CONTROL1_SAMEFS (1 << 4)
+#define ES8328_CONTROL1_DACMCLK_ADC (0 << 5)
+#define ES8328_CONTROL1_DACMCLK_DAC (1 << 5)
+#define ES8328_CONTROL1_LRCM (1 << 6)
+#define ES8328_CONTROL1_SCP_RESET (1 << 7)
+
+#define ES8328_CONTROL2                0x01
+#define ES8328_CONTROL2_VREF_BUF_OFF (1 << 0)
+#define ES8328_CONTROL2_VREF_LOWPOWER (1 << 1)
+#define ES8328_CONTROL2_IBIASGEN_OFF (1 << 2)
+#define ES8328_CONTROL2_ANALOG_OFF (1 << 3)
+#define ES8328_CONTROL2_VREF_BUF_LOWPOWER (1 << 4)
+#define ES8328_CONTROL2_VCM_MOD_LOWPOWER (1 << 5)
+#define ES8328_CONTROL2_OVERCURRENT_ON (1 << 6)
+#define ES8328_CONTROL2_THERMAL_SHUTDOWN_ON (1 << 7)
+
+#define ES8328_CHIPPOWER       0x02
+#define ES8328_CHIPPOWER_DACVREF_OFF 0
+#define ES8328_CHIPPOWER_ADCVREF_OFF 1
+#define ES8328_CHIPPOWER_DACDLL_OFF 2
+#define ES8328_CHIPPOWER_ADCDLL_OFF 3
+#define ES8328_CHIPPOWER_DACSTM_RESET 4
+#define ES8328_CHIPPOWER_ADCSTM_RESET 5
+#define ES8328_CHIPPOWER_DACDIG_OFF 6
+#define ES8328_CHIPPOWER_ADCDIG_OFF 7
+
+#define ES8328_ADCPOWER                0x03
+#define ES8328_ADCPOWER_INT1_LOWPOWER 0
+#define ES8328_ADCPOWER_FLASH_ADC_LOWPOWER 1
+#define ES8328_ADCPOWER_ADC_BIAS_GEN_OFF 2
+#define ES8328_ADCPOWER_MIC_BIAS_OFF 3
+#define ES8328_ADCPOWER_ADCR_OFF 4
+#define ES8328_ADCPOWER_ADCL_OFF 5
+#define ES8328_ADCPOWER_AINR_OFF 6
+#define ES8328_ADCPOWER_AINL_OFF 7
+
+#define ES8328_DACPOWER                0x04
+#define ES8328_DACPOWER_OUT3_ON 0
+#define ES8328_DACPOWER_MONO_ON 1
+#define ES8328_DACPOWER_ROUT2_ON 2
+#define ES8328_DACPOWER_LOUT2_ON 3
+#define ES8328_DACPOWER_ROUT1_ON 4
+#define ES8328_DACPOWER_LOUT1_ON 5
+#define ES8328_DACPOWER_RDAC_OFF 6
+#define ES8328_DACPOWER_LDAC_OFF 7
+
+#define ES8328_CHIPLOPOW1      0x05
+#define ES8328_CHIPLOPOW2      0x06
+#define ES8328_ANAVOLMANAG     0x07
+
+#define ES8328_MASTERMODE      0x08
+#define ES8328_MASTERMODE_BCLKDIV (0 << 0)
+#define ES8328_MASTERMODE_BCLK_INV (1 << 5)
+#define ES8328_MASTERMODE_MCLKDIV2 (1 << 6)
+#define ES8328_MASTERMODE_MSC (1 << 7)
+
+#define ES8328_ADCCONTROL1     0x09
+#define ES8328_ADCCONTROL2     0x0a
+#define ES8328_ADCCONTROL3     0x0b
+#define ES8328_ADCCONTROL4     0x0c
+#define ES8328_ADCCONTROL5     0x0d
+#define ES8328_ADCCONTROL5_RATEMASK (0x1f << 0)
+
+#define ES8328_ADCCONTROL6     0x0e
+
+#define ES8328_ADCCONTROL7     0x0f
+#define ES8328_ADCCONTROL7_ADC_MUTE (1 << 2)
+#define ES8328_ADCCONTROL7_ADC_LER (1 << 3)
+#define ES8328_ADCCONTROL7_ADC_ZERO_CROSS (1 << 4)
+#define ES8328_ADCCONTROL7_ADC_SOFT_RAMP (1 << 5)
+#define ES8328_ADCCONTROL7_ADC_RAMP_RATE_4 (0 << 6)
+#define ES8328_ADCCONTROL7_ADC_RAMP_RATE_8 (1 << 6)
+#define ES8328_ADCCONTROL7_ADC_RAMP_RATE_16 (2 << 6)
+#define ES8328_ADCCONTROL7_ADC_RAMP_RATE_32 (3 << 6)
+
+#define ES8328_ADCCONTROL8     0x10
+#define ES8328_ADCCONTROL9     0x11
+#define ES8328_ADCCONTROL10    0x12
+#define ES8328_ADCCONTROL11    0x13
+#define ES8328_ADCCONTROL12    0x14
+#define ES8328_ADCCONTROL13    0x15
+#define ES8328_ADCCONTROL14    0x16
+
+#define ES8328_DACCONTROL1     0x17
+#define ES8328_DACCONTROL1_DACFORMAT_I2S (0 << 1)
+#define ES8328_DACCONTROL1_DACFORMAT_LJUST (1 << 1)
+#define ES8328_DACCONTROL1_DACFORMAT_RJUST (2 << 1)
+#define ES8328_DACCONTROL1_DACFORMAT_PCM (3 << 1)
+#define ES8328_DACCONTROL1_DACWL_24 (0 << 3)
+#define ES8328_DACCONTROL1_DACWL_20 (1 << 3)
+#define ES8328_DACCONTROL1_DACWL_18 (2 << 3)
+#define ES8328_DACCONTROL1_DACWL_16 (3 << 3)
+#define ES8328_DACCONTROL1_DACWL_32 (4 << 3)
+#define ES8328_DACCONTROL1_DACLRP_I2S_POL_NORMAL (0 << 6)
+#define ES8328_DACCONTROL1_DACLRP_I2S_POL_INV (1 << 6)
+#define ES8328_DACCONTROL1_DACLRP_PCM_MSB_CLK2 (0 << 6)
+#define ES8328_DACCONTROL1_DACLRP_PCM_MSB_CLK1 (1 << 6)
+#define ES8328_DACCONTROL1_LRSWAP (1 << 7)
+
+#define ES8328_DACCONTROL2     0x18
+#define ES8328_DACCONTROL2_RATEMASK (0x1f << 0)
+#define ES8328_DACCONTROL2_DOUBLESPEED (1 << 5)
+
+#define ES8328_DACCONTROL3     0x19
+#define ES8328_DACCONTROL3_AUTOMUTE (1 << 2)
+#define ES8328_DACCONTROL3_DACMUTE (1 << 2)
+#define ES8328_DACCONTROL3_LEFTGAINVOL (1 << 3)
+#define ES8328_DACCONTROL3_DACZEROCROSS (1 << 4)
+#define ES8328_DACCONTROL3_DACSOFTRAMP (1 << 5)
+#define ES8328_DACCONTROL3_DACRAMPRATE (3 << 6)
+
+#define ES8328_LDACVOL 0x1a
+#define ES8328_LDACVOL_MASK (0 << 0)
+#define ES8328_LDACVOL_MAX (0xc0)
+
+#define ES8328_RDACVOL 0x1b
+#define ES8328_RDACVOL_MASK (0 << 0)
+#define ES8328_RDACVOL_MAX (0xc0)
+
+#define ES8328_DACVOL_MAX (0xc0)
+
+#define ES8328_DACCONTROL4     0x1a
+#define ES8328_DACCONTROL5     0x1b
+
+#define ES8328_DACCONTROL6     0x1c
+#define ES8328_DACCONTROL6_CLICKFREE (1 << 3)
+#define ES8328_DACCONTROL6_DAC_INVR (1 << 4)
+#define ES8328_DACCONTROL6_DAC_INVL (1 << 5)
+#define ES8328_DACCONTROL6_DEEMPH_OFF (0 << 6)
+#define ES8328_DACCONTROL6_DEEMPH_32k (1 << 6)
+#define ES8328_DACCONTROL6_DEEMPH_44_1k (2 << 6)
+#define ES8328_DACCONTROL6_DEEMPH_48k (3 << 6)
+
+#define ES8328_DACCONTROL7     0x1d
+#define ES8328_DACCONTROL7_VPP_SCALE_3p5       (0 << 0)
+#define ES8328_DACCONTROL7_VPP_SCALE_4p0       (1 << 0)
+#define ES8328_DACCONTROL7_VPP_SCALE_3p0       (2 << 0)
+#define ES8328_DACCONTROL7_VPP_SCALE_2p5       (3 << 0)
+#define ES8328_DACCONTROL7_SHELVING_STRENGTH (1 << 2) /* In eights */
+#define ES8328_DACCONTROL7_MONO                (1 << 5)
+#define ES8328_DACCONTROL7_ZEROR       (1 << 6)
+#define ES8328_DACCONTROL7_ZEROL       (1 << 7)
+
+/* Shelving filter */
+#define ES8328_DACCONTROL8     0x1e
+#define ES8328_DACCONTROL9     0x1f
+#define ES8328_DACCONTROL10    0x20
+#define ES8328_DACCONTROL11    0x21
+#define ES8328_DACCONTROL12    0x22
+#define ES8328_DACCONTROL13    0x23
+#define ES8328_DACCONTROL14    0x24
+#define ES8328_DACCONTROL15    0x25
+
+#define ES8328_DACCONTROL16    0x26
+#define ES8328_DACCONTROL16_RMIXSEL_RIN1 (0 << 0)
+#define ES8328_DACCONTROL16_RMIXSEL_RIN2 (1 << 0)
+#define ES8328_DACCONTROL16_RMIXSEL_RIN3 (2 << 0)
+#define ES8328_DACCONTROL16_RMIXSEL_RADC (3 << 0)
+#define ES8328_DACCONTROL16_LMIXSEL_LIN1 (0 << 3)
+#define ES8328_DACCONTROL16_LMIXSEL_LIN2 (1 << 3)
+#define ES8328_DACCONTROL16_LMIXSEL_LIN3 (2 << 3)
+#define ES8328_DACCONTROL16_LMIXSEL_LADC (3 << 3)
+
+#define ES8328_DACCONTROL17    0x27
+#define ES8328_DACCONTROL17_LI2LOVOL (7 << 3)
+#define ES8328_DACCONTROL17_LI2LO (1 << 6)
+#define ES8328_DACCONTROL17_LD2LO (1 << 7)
+
+#define ES8328_DACCONTROL18    0x28
+#define ES8328_DACCONTROL18_RI2LOVOL (7 << 3)
+#define ES8328_DACCONTROL18_RI2LO (1 << 6)
+#define ES8328_DACCONTROL18_RD2LO (1 << 7)
+
+#define ES8328_DACCONTROL19    0x29
+#define ES8328_DACCONTROL19_LI2ROVOL (7 << 3)
+#define ES8328_DACCONTROL19_LI2RO (1 << 6)
+#define ES8328_DACCONTROL19_LD2RO (1 << 7)
+
+#define ES8328_DACCONTROL20    0x2a
+#define ES8328_DACCONTROL20_RI2ROVOL (7 << 3)
+#define ES8328_DACCONTROL20_RI2RO (1 << 6)
+#define ES8328_DACCONTROL20_RD2RO (1 << 7)
+
+#define ES8328_DACCONTROL21    0x2b
+#define ES8328_DACCONTROL21_LI2MOVOL (7 << 3)
+#define ES8328_DACCONTROL21_LI2MO (1 << 6)
+#define ES8328_DACCONTROL21_LD2MO (1 << 7)
+
+#define ES8328_DACCONTROL22    0x2c
+#define ES8328_DACCONTROL22_RI2MOVOL (7 << 3)
+#define ES8328_DACCONTROL22_RI2MO (1 << 6)
+#define ES8328_DACCONTROL22_RD2MO (1 << 7)
+
+#define ES8328_DACCONTROL23    0x2d
+#define ES8328_DACCONTROL23_MOUTINV            (1 << 1)
+#define ES8328_DACCONTROL23_HPSWPOL            (1 << 2)
+#define ES8328_DACCONTROL23_HPSWEN             (1 << 3)
+#define ES8328_DACCONTROL23_VROI_1p5k          (0 << 4)
+#define ES8328_DACCONTROL23_VROI_40k           (1 << 4)
+#define ES8328_DACCONTROL23_OUT3_VREF          (0 << 5)
+#define ES8328_DACCONTROL23_OUT3_ROUT1         (1 << 5)
+#define ES8328_DACCONTROL23_OUT3_MONOOUT       (2 << 5)
+#define ES8328_DACCONTROL23_OUT3_RIGHT_MIXER   (3 << 5)
+#define ES8328_DACCONTROL23_ROUT2INV           (1 << 7)
+
+/* LOUT1 Amplifier */
+#define ES8328_LOUT1VOL 0x2e
+#define ES8328_LOUT1VOL_MASK (0 << 5)
+#define ES8328_LOUT1VOL_MAX (0x24)
+
+/* ROUT1 Amplifier */
+#define ES8328_ROUT1VOL 0x2f
+#define ES8328_ROUT1VOL_MASK (0 << 5)
+#define ES8328_ROUT1VOL_MAX (0x24)
+
+#define ES8328_OUT1VOL_MAX (0x24)
+
+/* LOUT2 Amplifier */
+#define ES8328_LOUT2VOL 0x30
+#define ES8328_LOUT2VOL_MASK (0 << 5)
+#define ES8328_LOUT2VOL_MAX (0x24)
+
+/* ROUT2 Amplifier */
+#define ES8328_ROUT2VOL 0x31
+#define ES8328_ROUT2VOL_MASK (0 << 5)
+#define ES8328_ROUT2VOL_MAX (0x24)
+
+#define ES8328_OUT2VOL_MAX (0x24)
+
+/* Mono Out Amplifier */
+#define ES8328_MONOOUTVOL 0x32
+#define ES8328_MONOOUTVOL_MASK (0 << 5)
+#define ES8328_MONOOUTVOL_MAX (0x24)
+
+#define ES8328_DACCONTROL29    0x33
+#define ES8328_DACCONTROL30    0x34
+
+#define ES8328_SYSCLK          0
+
+#define ES8328_REG_MAX         0x35
+
+#define ES8328_PLL1            0
+#define ES8328_PLL2            1
+
+/* clock inputs */
+#define ES8328_MCLK            0
+#define ES8328_PCMCLK          1
+
+/* clock divider id's */
+#define ES8328_PCMDIV          0
+#define ES8328_BCLKDIV         1
+#define ES8328_VXCLKDIV                2
+
+/* PCM clock dividers */
+#define ES8328_PCM_DIV_1       (0 << 6)
+#define ES8328_PCM_DIV_3       (2 << 6)
+#define ES8328_PCM_DIV_5_5     (3 << 6)
+#define ES8328_PCM_DIV_2       (4 << 6)
+#define ES8328_PCM_DIV_4       (5 << 6)
+#define ES8328_PCM_DIV_6       (6 << 6)
+#define ES8328_PCM_DIV_8       (7 << 6)
+
+/* BCLK clock dividers */
+#define ES8328_BCLK_DIV_1      (0 << 7)
+#define ES8328_BCLK_DIV_2      (1 << 7)
+#define ES8328_BCLK_DIV_4      (2 << 7)
+#define ES8328_BCLK_DIV_8      (3 << 7)
+
+/* VXCLK clock dividers */
+#define ES8328_VXCLK_DIV_1     (0 << 6)
+#define ES8328_VXCLK_DIV_2     (1 << 6)
+#define ES8328_VXCLK_DIV_4     (2 << 6)
+#define ES8328_VXCLK_DIV_8     (3 << 6)
+#define ES8328_VXCLK_DIV_16    (4 << 6)
+
+#define ES8328_DAI_HIFI                0
+#define ES8328_DAI_VOICE       1
+
+#define ES8328_1536FS          1536
+#define ES8328_1024FS          1024
+#define ES8328_768FS           768
+#define ES8328_512FS           512
+#define ES8328_384FS           384
+#define ES8328_256FS           256
+#define ES8328_128FS           128
+
+#endif
index bcebd1a9ce313bce582284f17009ff82708d82cb..df7c01cf7072c20f282ef2476c6d1da8f459585a 100644 (file)
@@ -293,41 +293,13 @@ static int jz4740_codec_dev_probe(struct snd_soc_codec *codec)
        regmap_update_bits(jz4740_codec->regmap, JZ4740_REG_CODEC_1,
                        JZ4740_CODEC_1_SW2_ENABLE, JZ4740_CODEC_1_SW2_ENABLE);
 
-       jz4740_codec_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
-
        return 0;
 }
 
-static int jz4740_codec_dev_remove(struct snd_soc_codec *codec)
-{
-       jz4740_codec_set_bias_level(codec, SND_SOC_BIAS_OFF);
-
-       return 0;
-}
-
-#ifdef CONFIG_PM_SLEEP
-
-static int jz4740_codec_suspend(struct snd_soc_codec *codec)
-{
-       return jz4740_codec_set_bias_level(codec, SND_SOC_BIAS_OFF);
-}
-
-static int jz4740_codec_resume(struct snd_soc_codec *codec)
-{
-       return jz4740_codec_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
-}
-
-#else
-#define jz4740_codec_suspend NULL
-#define jz4740_codec_resume NULL
-#endif
-
 static struct snd_soc_codec_driver soc_codec_dev_jz4740_codec = {
        .probe = jz4740_codec_dev_probe,
-       .remove = jz4740_codec_dev_remove,
-       .suspend = jz4740_codec_suspend,
-       .resume = jz4740_codec_resume,
        .set_bias_level = jz4740_codec_set_bias_level,
+       .suspend_bias_off = true,
 
        .controls = jz4740_codec_controls,
        .num_controls = ARRAY_SIZE(jz4740_codec_controls),
index 275b3f72f3f42db71bd94b7ca2b35f146b134d8a..c1ae5764983fa73fd86f67c360d15876c284477c 100644 (file)
@@ -1395,18 +1395,6 @@ static struct snd_soc_dai_driver lm49453_dai[] = {
        },
 };
 
-static int lm49453_suspend(struct snd_soc_codec *codec)
-{
-       lm49453_set_bias_level(codec, SND_SOC_BIAS_OFF);
-       return 0;
-}
-
-static int lm49453_resume(struct snd_soc_codec *codec)
-{
-       lm49453_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
-       return 0;
-}
-
 /* power down chip */
 static int lm49453_remove(struct snd_soc_codec *codec)
 {
@@ -1416,8 +1404,6 @@ static int lm49453_remove(struct snd_soc_codec *codec)
 
 static struct snd_soc_codec_driver soc_codec_dev_lm49453 = {
        .remove = lm49453_remove,
-       .suspend = lm49453_suspend,
-       .resume = lm49453_resume,
        .set_bias_level = lm49453_set_bias_level,
        .controls = lm49453_snd_controls,
        .num_controls = ARRAY_SIZE(lm49453_snd_controls),
index 4a063fa88526821b279bd7c49cdbb14cfef994c8..d519294f57c79c289784f9a71bb43d7bf51dc7e9 100644 (file)
@@ -1311,8 +1311,6 @@ static const struct snd_soc_dapm_route max98090_dapm_routes[] = {
        {"MIC1 Input", NULL, "MIC1"},
        {"MIC2 Input", NULL, "MIC2"},
 
-       {"DMICL", NULL, "DMICL_ENA"},
-       {"DMICR", NULL, "DMICR_ENA"},
        {"DMICL", NULL, "AHPF"},
        {"DMICR", NULL, "AHPF"},
 
@@ -1370,6 +1368,8 @@ static const struct snd_soc_dapm_route max98090_dapm_routes[] = {
        {"DMIC Mux", "ADC", "ADCR"},
        {"DMIC Mux", "DMIC", "DMICL"},
        {"DMIC Mux", "DMIC", "DMICR"},
+       {"DMIC Mux", "DMIC", "DMICL_ENA"},
+       {"DMIC Mux", "DMIC", "DMICR_ENA"},
 
        {"LBENL Mux", "Normal", "DMIC Mux"},
        {"LBENL Mux", "Loopback", "LTENL Mux"},
@@ -1972,6 +1972,102 @@ static int max98090_dai_digital_mute(struct snd_soc_dai *codec_dai, int mute)
        return 0;
 }
 
+static int max98090_dai_trigger(struct snd_pcm_substream *substream, int cmd,
+                               struct snd_soc_dai *dai)
+{
+       struct snd_soc_codec *codec = dai->codec;
+       struct max98090_priv *max98090 = snd_soc_codec_get_drvdata(codec);
+
+       switch (cmd) {
+       case SNDRV_PCM_TRIGGER_START:
+       case SNDRV_PCM_TRIGGER_RESUME:
+       case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+               if (!max98090->master && dai->active == 1)
+                       queue_delayed_work(system_power_efficient_wq,
+                                          &max98090->pll_det_enable_work,
+                                          msecs_to_jiffies(10));
+               break;
+       case SNDRV_PCM_TRIGGER_STOP:
+       case SNDRV_PCM_TRIGGER_SUSPEND:
+       case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+               if (!max98090->master && dai->active == 1)
+                       schedule_work(&max98090->pll_det_disable_work);
+               break;
+       default:
+               break;
+       }
+
+       return 0;
+}
+
+static void max98090_pll_det_enable_work(struct work_struct *work)
+{
+       struct max98090_priv *max98090 =
+               container_of(work, struct max98090_priv,
+                            pll_det_enable_work.work);
+       struct snd_soc_codec *codec = max98090->codec;
+       unsigned int status, mask;
+
+       /*
+        * Clear status register in order to clear possibly already occurred
+        * PLL unlock. If PLL hasn't still locked, the status will be set
+        * again and PLL unlock interrupt will occur.
+        * Note this will clear all status bits
+        */
+       regmap_read(max98090->regmap, M98090_REG_DEVICE_STATUS, &status);
+
+       /*
+        * Queue jack work in case jack state has just changed but handler
+        * hasn't run yet
+        */
+       regmap_read(max98090->regmap, M98090_REG_INTERRUPT_S, &mask);
+       status &= mask;
+       if (status & M98090_JDET_MASK)
+               queue_delayed_work(system_power_efficient_wq,
+                                  &max98090->jack_work,
+                                  msecs_to_jiffies(100));
+
+       /* Enable PLL unlock interrupt */
+       snd_soc_update_bits(codec, M98090_REG_INTERRUPT_S,
+                           M98090_IULK_MASK,
+                           1 << M98090_IULK_SHIFT);
+}
+
+static void max98090_pll_det_disable_work(struct work_struct *work)
+{
+       struct max98090_priv *max98090 =
+               container_of(work, struct max98090_priv, pll_det_disable_work);
+       struct snd_soc_codec *codec = max98090->codec;
+
+       cancel_delayed_work_sync(&max98090->pll_det_enable_work);
+
+       /* Disable PLL unlock interrupt */
+       snd_soc_update_bits(codec, M98090_REG_INTERRUPT_S,
+                           M98090_IULK_MASK, 0);
+}
+
+static void max98090_pll_work(struct work_struct *work)
+{
+       struct max98090_priv *max98090 =
+               container_of(work, struct max98090_priv, pll_work);
+       struct snd_soc_codec *codec = max98090->codec;
+
+       if (!snd_soc_codec_is_active(codec))
+               return;
+
+       dev_info(codec->dev, "PLL unlocked\n");
+
+       /* Toggle shutdown OFF then ON */
+       snd_soc_update_bits(codec, M98090_REG_DEVICE_SHUTDOWN,
+                           M98090_SHDNN_MASK, 0);
+       msleep(10);
+       snd_soc_update_bits(codec, M98090_REG_DEVICE_SHUTDOWN,
+                           M98090_SHDNN_MASK, M98090_SHDNN_MASK);
+
+       /* Give PLL time to lock */
+       msleep(10);
+}
+
 static void max98090_jack_work(struct work_struct *work)
 {
        struct max98090_priv *max98090 = container_of(work,
@@ -2063,12 +2159,16 @@ static void max98090_jack_work(struct work_struct *work)
 
 static irqreturn_t max98090_interrupt(int irq, void *data)
 {
-       struct snd_soc_codec *codec = data;
-       struct max98090_priv *max98090 = snd_soc_codec_get_drvdata(codec);
+       struct max98090_priv *max98090 = data;
+       struct snd_soc_codec *codec = max98090->codec;
        int ret;
        unsigned int mask;
        unsigned int active;
 
+       /* Treat interrupt before codec is initialized as spurious */
+       if (codec == NULL)
+               return IRQ_NONE;
+
        dev_dbg(codec->dev, "***** max98090_interrupt *****\n");
 
        ret = regmap_read(max98090->regmap, M98090_REG_INTERRUPT_S, &mask);
@@ -2103,8 +2203,10 @@ static irqreturn_t max98090_interrupt(int irq, void *data)
        if (active & M98090_SLD_MASK)
                dev_dbg(codec->dev, "M98090_SLD_MASK\n");
 
-       if (active & M98090_ULK_MASK)
-               dev_err(codec->dev, "M98090_ULK_MASK\n");
+       if (active & M98090_ULK_MASK) {
+               dev_dbg(codec->dev, "M98090_ULK_MASK\n");
+               schedule_work(&max98090->pll_work);
+       }
 
        if (active & M98090_JDET_MASK) {
                dev_dbg(codec->dev, "M98090_JDET_MASK\n");
@@ -2177,6 +2279,7 @@ static struct snd_soc_dai_ops max98090_dai_ops = {
        .set_tdm_slot = max98090_set_tdm_slot,
        .hw_params = max98090_dai_hw_params,
        .digital_mute = max98090_dai_digital_mute,
+       .trigger = max98090_dai_trigger,
 };
 
 static struct snd_soc_dai_driver max98090_dai[] = {
@@ -2230,7 +2333,6 @@ static int max98090_probe(struct snd_soc_codec *codec)
        max98090->lin_state = 0;
        max98090->pa1en = 0;
        max98090->pa2en = 0;
-       max98090->extmic_mux = 0;
 
        ret = snd_soc_read(codec, M98090_REG_REVISION_ID);
        if (ret < 0) {
@@ -2258,22 +2360,16 @@ static int max98090_probe(struct snd_soc_codec *codec)
        max98090->jack_state = M98090_JACK_STATE_NO_HEADSET;
 
        INIT_DELAYED_WORK(&max98090->jack_work, max98090_jack_work);
+       INIT_DELAYED_WORK(&max98090->pll_det_enable_work,
+                         max98090_pll_det_enable_work);
+       INIT_WORK(&max98090->pll_det_disable_work,
+                 max98090_pll_det_disable_work);
+       INIT_WORK(&max98090->pll_work, max98090_pll_work);
 
        /* Enable jack detection */
        snd_soc_write(codec, M98090_REG_JACK_DETECT,
                M98090_JDETEN_MASK | M98090_JDEB_25MS);
 
-       /* Register for interrupts */
-       dev_dbg(codec->dev, "irq = %d\n", max98090->irq);
-
-       ret = devm_request_threaded_irq(codec->dev, max98090->irq, NULL,
-               max98090_interrupt, IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
-               "max98090_interrupt", codec);
-       if (ret < 0) {
-               dev_err(codec->dev, "request_irq failed: %d\n",
-                       ret);
-       }
-
        /*
         * Clear any old interrupts.
         * An old interrupt ocurring prior to installing the ISR
@@ -2310,6 +2406,10 @@ static int max98090_remove(struct snd_soc_codec *codec)
        struct max98090_priv *max98090 = snd_soc_codec_get_drvdata(codec);
 
        cancel_delayed_work_sync(&max98090->jack_work);
+       cancel_delayed_work_sync(&max98090->pll_det_enable_work);
+       cancel_work_sync(&max98090->pll_det_disable_work);
+       cancel_work_sync(&max98090->pll_work);
+       max98090->codec = NULL;
 
        return 0;
 }
@@ -2362,7 +2462,6 @@ static int max98090_i2c_probe(struct i2c_client *i2c,
        max98090->devtype = driver_data;
        i2c_set_clientdata(i2c, max98090);
        max98090->pdata = i2c->dev.platform_data;
-       max98090->irq = i2c->irq;
 
        max98090->regmap = devm_regmap_init_i2c(i2c, &max98090_regmap);
        if (IS_ERR(max98090->regmap)) {
@@ -2371,6 +2470,15 @@ static int max98090_i2c_probe(struct i2c_client *i2c,
                goto err_enable;
        }
 
+       ret = devm_request_threaded_irq(&i2c->dev, i2c->irq, NULL,
+               max98090_interrupt, IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
+               "max98090_interrupt", max98090);
+       if (ret < 0) {
+               dev_err(&i2c->dev, "request_irq failed: %d\n",
+                       ret);
+               return ret;
+       }
+
        ret = snd_soc_register_codec(&i2c->dev,
                        &soc_codec_dev_max98090, max98090_dai,
                        ARRAY_SIZE(max98090_dai));
index cf1b6062ba8c6de043fa2ffb46834119e858f936..a5f6bada06daf2d886e0717f5c13c3bcd0cfdb1f 100644 (file)
 #ifndef _MAX98090_H
 #define _MAX98090_H
 
-#include <linux/version.h>
-
-/* One can override the Linux version here with an explicit version number */
-#define M98090_LINUX_VERSION LINUX_VERSION_CODE
-
 /*
  * MAX98090 Register Definitions
  */
 #define M98090_REVID_WIDTH             8
 #define M98090_REVID_NUM               (1<<M98090_REVID_WIDTH)
 
-#define M98090_BYTE1(w) ((w >> 8) & 0xff)
-#define M98090_BYTE0(w) (w & 0xff)
-
 /* Silicon revision number */
 #define M98090_REVA                    0x40
 #define M98091_REVA                    0x50
@@ -1529,9 +1521,11 @@ struct max98090_priv {
        unsigned int bclk;
        unsigned int lrclk;
        struct max98090_cdata dai[1];
-       int irq;
        int jack_state;
        struct delayed_work jack_work;
+       struct delayed_work pll_det_enable_work;
+       struct work_struct pll_det_disable_work;
+       struct work_struct pll_work;
        struct snd_soc_jack *jack;
        unsigned int dai_fmt;
        int tdm_slots;
@@ -1539,7 +1533,6 @@ struct max98090_priv {
        u8 lin_state;
        unsigned int pa1en;
        unsigned int pa2en;
-       unsigned int extmic_mux;
        unsigned int sidetone;
        bool master;
 };
index 388f90a597fa0ea31a608351ee99233bc2d3fc68..71f775aad7c715f18b3ebdd16b385bb5501de5eb 100644 (file)
@@ -765,12 +765,18 @@ static int __init mc13783_codec_probe(struct platform_device *pdev)
                        return -ENOSYS;
 
                ret = of_property_read_u32(np, "adc-port", &priv->adc_ssi_port);
-               if (ret)
-                       goto out;
+               if (ret) {
+                       of_node_put(np);
+                       return ret;
+               }
 
                ret = of_property_read_u32(np, "dac-port", &priv->dac_ssi_port);
-               if (ret)
-                       goto out;
+               if (ret) {
+                       of_node_put(np);
+                       return ret;
+               }
+
+               of_node_put(np);
        }
 
        dev_set_drvdata(&pdev->dev, priv);
@@ -783,8 +789,6 @@ static int __init mc13783_codec_probe(struct platform_device *pdev)
                ret = snd_soc_register_codec(&pdev->dev, &soc_codec_dev_mc13783,
                        mc13783_dai_async, ARRAY_SIZE(mc13783_dai_async));
 
-out:
-       of_node_put(np);
        return ret;
 }
 
index e661e8420e3dd25b95179c7413adfea8637cd9e2..711f55039522f473a5070cb1454a03132423f5d6 100644 (file)
@@ -565,41 +565,19 @@ static struct snd_soc_dai_driver ml26124_dai = {
        .symmetric_rates = 1,
 };
 
-#ifdef CONFIG_PM
-static int ml26124_suspend(struct snd_soc_codec *codec)
-{
-       ml26124_set_bias_level(codec, SND_SOC_BIAS_OFF);
-
-       return 0;
-}
-
-static int ml26124_resume(struct snd_soc_codec *codec)
-{
-       ml26124_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
-
-       return 0;
-}
-#else
-#define ml26124_suspend NULL
-#define ml26124_resume NULL
-#endif
-
 static int ml26124_probe(struct snd_soc_codec *codec)
 {
        /* Software Reset */
        snd_soc_update_bits(codec, ML26124_SW_RST, 0x01, 1);
        snd_soc_update_bits(codec, ML26124_SW_RST, 0x01, 0);
 
-       ml26124_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
-
        return 0;
 }
 
 static struct snd_soc_codec_driver soc_codec_dev_ml26124 = {
        .probe =        ml26124_probe,
-       .suspend =      ml26124_suspend,
-       .resume =       ml26124_resume,
        .set_bias_level = ml26124_set_bias_level,
+       .suspend_bias_off = true,
        .dapm_widgets = ml26124_dapm_widgets,
        .num_dapm_widgets = ARRAY_SIZE(ml26124_dapm_widgets),
        .dapm_routes = ml26124_intercon,
index b86b426f159d136c07cbc4491c8241db0c5a2001..4aa555cbcca81ce60b880d6159b1fb91777e9920 100644 (file)
@@ -269,6 +269,7 @@ static int rt286_hw_read(void *context, unsigned int reg, unsigned int *value)
        return 0;
 }
 
+#ifdef CONFIG_PM
 static void rt286_index_sync(struct snd_soc_codec *codec)
 {
        struct rt286_priv *rt286 = snd_soc_codec_get_drvdata(codec);
@@ -279,6 +280,7 @@ static void rt286_index_sync(struct snd_soc_codec *codec)
                                  rt286->index_cache[i].def);
        }
 }
+#endif
 
 static int rt286_support_power_controls[] = {
        RT286_DAC_OUT1,
index f1ec6e6bd08aced4be7c38d868ccba94a655c5f7..c3f2decd643c9ba7eb57eec8a644091bc440376d 100644 (file)
@@ -1906,6 +1906,32 @@ static int rt5640_set_bias_level(struct snd_soc_codec *codec,
        return 0;
 }
 
+int rt5640_dmic_enable(struct snd_soc_codec *codec,
+                      bool dmic1_data_pin, bool dmic2_data_pin)
+{
+       struct rt5640_priv *rt5640 = snd_soc_codec_get_drvdata(codec);
+
+       regmap_update_bits(rt5640->regmap, RT5640_GPIO_CTRL1,
+               RT5640_GP2_PIN_MASK, RT5640_GP2_PIN_DMIC1_SCL);
+
+       if (dmic1_data_pin) {
+               regmap_update_bits(rt5640->regmap, RT5640_DMIC,
+                       RT5640_DMIC_1_DP_MASK, RT5640_DMIC_1_DP_GPIO3);
+               regmap_update_bits(rt5640->regmap, RT5640_GPIO_CTRL1,
+                       RT5640_GP3_PIN_MASK, RT5640_GP3_PIN_DMIC1_SDA);
+       }
+
+       if (dmic2_data_pin) {
+               regmap_update_bits(rt5640->regmap, RT5640_DMIC,
+                       RT5640_DMIC_2_DP_MASK, RT5640_DMIC_2_DP_GPIO4);
+               regmap_update_bits(rt5640->regmap, RT5640_GPIO_CTRL1,
+                       RT5640_GP4_PIN_MASK, RT5640_GP4_PIN_DMIC2_SDA);
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(rt5640_dmic_enable);
+
 static int rt5640_probe(struct snd_soc_codec *codec)
 {
        struct rt5640_priv *rt5640 = snd_soc_codec_get_drvdata(codec);
@@ -1945,6 +1971,10 @@ static int rt5640_probe(struct snd_soc_codec *codec)
                return -ENODEV;
        }
 
+       if (rt5640->pdata.dmic_en)
+               rt5640_dmic_enable(codec, rt5640->pdata.dmic1_data_pin,
+                                         rt5640->pdata.dmic2_data_pin);
+
        return 0;
 }
 
@@ -2195,25 +2225,6 @@ static int rt5640_i2c_probe(struct i2c_client *i2c,
                regmap_update_bits(rt5640->regmap, RT5640_IN3_IN4,
                                        RT5640_IN_DF2, RT5640_IN_DF2);
 
-       if (rt5640->pdata.dmic_en) {
-               regmap_update_bits(rt5640->regmap, RT5640_GPIO_CTRL1,
-                       RT5640_GP2_PIN_MASK, RT5640_GP2_PIN_DMIC1_SCL);
-
-               if (rt5640->pdata.dmic1_data_pin) {
-                       regmap_update_bits(rt5640->regmap, RT5640_DMIC,
-                               RT5640_DMIC_1_DP_MASK, RT5640_DMIC_1_DP_GPIO3);
-                       regmap_update_bits(rt5640->regmap, RT5640_GPIO_CTRL1,
-                               RT5640_GP3_PIN_MASK, RT5640_GP3_PIN_DMIC1_SDA);
-               }
-
-               if (rt5640->pdata.dmic2_data_pin) {
-                       regmap_update_bits(rt5640->regmap, RT5640_DMIC,
-                               RT5640_DMIC_2_DP_MASK, RT5640_DMIC_2_DP_GPIO4);
-                       regmap_update_bits(rt5640->regmap, RT5640_GPIO_CTRL1,
-                               RT5640_GP4_PIN_MASK, RT5640_GP4_PIN_DMIC2_SDA);
-               }
-       }
-
        rt5640->hp_mute = 1;
 
        return snd_soc_register_codec(&i2c->dev, &soc_codec_dev_rt5640,
index 58ebe96b86dae452165fc679ce424017e9088833..3deb8babeabb691d37a314bb3ab19c84d5c9cd1f 100644 (file)
@@ -2097,4 +2097,7 @@ struct rt5640_priv {
        bool hp_mute;
 };
 
+int rt5640_dmic_enable(struct snd_soc_codec *codec,
+                      bool dmic1_data_pin, bool dmic2_data_pin);
+
 #endif
index a7762d0a623e86705e32570d7e36958df8be638e..3fb83bf09768347f1bcd469d2be9be4b56ea62e2 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/i2c.h>
 #include <linux/platform_device.h>
 #include <linux/spi/spi.h>
+#include <linux/gpio.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
@@ -2103,6 +2104,77 @@ static int rt5645_set_bias_level(struct snd_soc_codec *codec,
        return 0;
 }
 
+static int rt5645_jack_detect(struct snd_soc_codec *codec,
+       struct snd_soc_jack *jack)
+{
+       struct rt5645_priv *rt5645 = snd_soc_codec_get_drvdata(codec);
+       int gpio_state, jack_type = 0;
+       unsigned int val;
+
+       gpio_state = gpio_get_value(rt5645->pdata.hp_det_gpio);
+
+       dev_dbg(codec->dev, "gpio = %d(%d)\n", rt5645->pdata.hp_det_gpio,
+               gpio_state);
+
+       if ((rt5645->pdata.gpio_hp_det_active_high && gpio_state) ||
+               (!rt5645->pdata.gpio_hp_det_active_high && !gpio_state)) {
+               snd_soc_dapm_force_enable_pin(&codec->dapm, "micbias1");
+               snd_soc_dapm_force_enable_pin(&codec->dapm, "micbias2");
+               snd_soc_dapm_force_enable_pin(&codec->dapm, "LDO2");
+               snd_soc_dapm_force_enable_pin(&codec->dapm, "Mic Det Power");
+               snd_soc_dapm_sync(&codec->dapm);
+
+               snd_soc_write(codec, RT5645_IN1_CTRL1, 0x0006);
+               snd_soc_write(codec, RT5645_JD_CTRL3, 0x00b0);
+
+               snd_soc_update_bits(codec, RT5645_IN1_CTRL2,
+                       RT5645_CBJ_MN_JD, 0);
+               snd_soc_update_bits(codec, RT5645_IN1_CTRL2,
+                       RT5645_CBJ_MN_JD, RT5645_CBJ_MN_JD);
+
+               msleep(400);
+               val = snd_soc_read(codec, RT5645_IN1_CTRL3) & 0x7;
+               dev_dbg(codec->dev, "val = %d\n", val);
+
+               if (val == 1 || val == 2)
+                       jack_type = SND_JACK_HEADSET;
+               else
+                       jack_type = SND_JACK_HEADPHONE;
+
+               snd_soc_dapm_disable_pin(&codec->dapm, "micbias1");
+               snd_soc_dapm_disable_pin(&codec->dapm, "micbias2");
+               snd_soc_dapm_disable_pin(&codec->dapm, "LDO2");
+               snd_soc_dapm_disable_pin(&codec->dapm, "Mic Det Power");
+               snd_soc_dapm_sync(&codec->dapm);
+       }
+
+       snd_soc_jack_report(rt5645->jack, jack_type, SND_JACK_HEADSET);
+
+       return 0;
+}
+
+int rt5645_set_jack_detect(struct snd_soc_codec *codec,
+       struct snd_soc_jack *jack)
+{
+       struct rt5645_priv *rt5645 = snd_soc_codec_get_drvdata(codec);
+
+       rt5645->jack = jack;
+
+       rt5645_jack_detect(codec, rt5645->jack);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(rt5645_set_jack_detect);
+
+static irqreturn_t rt5645_irq(int irq, void *data)
+{
+       struct rt5645_priv *rt5645 = data;
+
+       rt5645_jack_detect(rt5645->codec, rt5645->jack);
+
+       return IRQ_HANDLED;
+}
+
 static int rt5645_probe(struct snd_soc_codec *codec)
 {
        struct rt5645_priv *rt5645 = snd_soc_codec_get_drvdata(codec);
@@ -2250,6 +2322,7 @@ static int rt5645_i2c_probe(struct i2c_client *i2c,
        if (rt5645 == NULL)
                return -ENOMEM;
 
+       rt5645->i2c = i2c;
        i2c_set_clientdata(i2c, rt5645);
 
        if (pdata)
@@ -2345,12 +2418,38 @@ static int rt5645_i2c_probe(struct i2c_client *i2c,
 
        }
 
+       if (rt5645->i2c->irq) {
+               ret = request_threaded_irq(rt5645->i2c->irq, NULL, rt5645_irq,
+                       IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING
+                       | IRQF_ONESHOT, "rt5645", rt5645);
+               if (ret)
+                       dev_err(&i2c->dev, "Failed to reguest IRQ: %d\n", ret);
+       }
+
+       if (gpio_is_valid(rt5645->pdata.hp_det_gpio)) {
+               ret = gpio_request(rt5645->pdata.hp_det_gpio, "rt5645");
+               if (ret)
+                       dev_err(&i2c->dev, "Fail gpio_request hp_det_gpio\n");
+
+               ret = gpio_direction_input(rt5645->pdata.hp_det_gpio);
+               if (ret)
+                       dev_err(&i2c->dev, "Fail gpio_direction hp_det_gpio\n");
+       }
+
        return snd_soc_register_codec(&i2c->dev, &soc_codec_dev_rt5645,
                                      rt5645_dai, ARRAY_SIZE(rt5645_dai));
 }
 
 static int rt5645_i2c_remove(struct i2c_client *i2c)
 {
+       struct rt5645_priv *rt5645 = i2c_get_clientdata(i2c);
+
+       if (i2c->irq)
+               free_irq(i2c->irq, rt5645);
+
+       if (gpio_is_valid(rt5645->pdata.hp_det_gpio))
+               gpio_free(rt5645->pdata.hp_det_gpio);
+
        snd_soc_unregister_codec(&i2c->dev);
 
        return 0;
index 355b7e9eefab0071b885f410ddd1a822ca6519f4..50c62c5668ea61220fda047ea35b97542630ed0c 100644 (file)
@@ -2166,6 +2166,8 @@ struct rt5645_priv {
        struct snd_soc_codec *codec;
        struct rt5645_platform_data pdata;
        struct regmap *regmap;
+       struct i2c_client *i2c;
+       struct snd_soc_jack *jack;
 
        int sysclk;
        int sysclk_src;
@@ -2178,4 +2180,7 @@ struct rt5645_priv {
        int pll_out;
 };
 
+int rt5645_set_jack_detect(struct snd_soc_codec *codec,
+       struct snd_soc_jack *jack);
+
 #endif /* __RT5645_H__ */
index 5337c448b5e365de204a95e3a945291dd228844b..16aa4d99a71304ea20e1c108a9e90f1c61709e45 100644 (file)
 #include <linux/init.h>
 #include <linux/delay.h>
 #include <linux/pm.h>
+#include <linux/of_gpio.h>
 #include <linux/regmap.h>
 #include <linux/i2c.h>
 #include <linux/platform_device.h>
 #include <linux/spi/spi.h>
+#include <linux/gpio.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
@@ -540,6 +542,7 @@ static const DECLARE_TLV_DB_SCALE(dac_vol_tlv, -65625, 375, 0);
 static const DECLARE_TLV_DB_SCALE(in_vol_tlv, -3450, 150, 0);
 static const DECLARE_TLV_DB_SCALE(adc_vol_tlv, -17625, 375, 0);
 static const DECLARE_TLV_DB_SCALE(adc_bst_tlv, 0, 1200, 0);
+static const DECLARE_TLV_DB_SCALE(st_vol_tlv, -4650, 150, 0);
 
 /* {0, +20, +24, +30, +35, +40, +44, +50, +52} dB */
 static unsigned int bst_tlv[] = {
@@ -604,6 +607,10 @@ static const struct snd_kcontrol_new rt5677_snd_controls[] = {
                RT5677_MONO_ADC_L_VOL_SFT, RT5677_MONO_ADC_R_VOL_SFT, 127, 0,
                adc_vol_tlv),
 
+       /* Sidetone Control */
+       SOC_SINGLE_TLV("Sidetone Volume", RT5677_SIDETONE_CTRL,
+               RT5677_ST_VOL_SFT, 31, 0, st_vol_tlv),
+
        /* ADC Boost Volume Control */
        SOC_DOUBLE_TLV("STO1 ADC Boost Volume", RT5677_STO1_2_ADC_BST,
                RT5677_STO1_ADC_L_BST_SFT, RT5677_STO1_ADC_R_BST_SFT, 3, 0,
@@ -1700,14 +1707,19 @@ static const struct snd_soc_dapm_widget rt5677_dapm_widgets[] = {
 
        SND_SOC_DAPM_INPUT("Haptic Generator"),
 
-       SND_SOC_DAPM_PGA("DMIC1", RT5677_DMIC_CTRL1, RT5677_DMIC_1_EN_SFT, 0,
-               NULL, 0),
-       SND_SOC_DAPM_PGA("DMIC2", RT5677_DMIC_CTRL1, RT5677_DMIC_2_EN_SFT, 0,
-               NULL, 0),
-       SND_SOC_DAPM_PGA("DMIC3", RT5677_DMIC_CTRL1, RT5677_DMIC_3_EN_SFT, 0,
-               NULL, 0),
-       SND_SOC_DAPM_PGA("DMIC4", RT5677_DMIC_CTRL2, RT5677_DMIC_4_EN_SFT, 0,
-               NULL, 0),
+       SND_SOC_DAPM_PGA("DMIC1", SND_SOC_NOPM, 0, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("DMIC2", SND_SOC_NOPM, 0, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("DMIC3", SND_SOC_NOPM, 0, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("DMIC4", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+       SND_SOC_DAPM_SUPPLY("DMIC1 power", RT5677_DMIC_CTRL1,
+               RT5677_DMIC_1_EN_SFT, 0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY("DMIC2 power", RT5677_DMIC_CTRL1,
+               RT5677_DMIC_2_EN_SFT, 0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY("DMIC3 power", RT5677_DMIC_CTRL1,
+               RT5677_DMIC_3_EN_SFT, 0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY("DMIC4 power", RT5677_DMIC_CTRL2,
+               RT5677_DMIC_4_EN_SFT, 0, NULL, 0),
 
        SND_SOC_DAPM_SUPPLY("DMIC CLK", SND_SOC_NOPM, 0, 0,
                set_dmic_clk, SND_SOC_DAPM_PRE_PMU),
@@ -1987,6 +1999,9 @@ static const struct snd_soc_dapm_widget rt5677_dapm_widgets[] = {
        /* Sidetone Mux */
        SND_SOC_DAPM_MUX("Sidetone Mux", SND_SOC_NOPM, 0, 0,
                        &rt5677_sidetone_mux),
+       SND_SOC_DAPM_SUPPLY("Sidetone Power", RT5677_SIDETONE_CTRL,
+               RT5677_ST_EN_SFT, 0, NULL, 0),
+
        /* VAD Mux*/
        SND_SOC_DAPM_MUX("VAD ADC Mux", SND_SOC_NOPM, 0, 0,
                        &rt5677_vad_src_mux),
@@ -2130,6 +2145,13 @@ static const struct snd_soc_dapm_route rt5677_dapm_routes[] = {
        { "DMIC L4", NULL, "DMIC CLK" },
        { "DMIC R4", NULL, "DMIC CLK" },
 
+       { "DMIC L1", NULL, "DMIC1 power" },
+       { "DMIC R1", NULL, "DMIC1 power" },
+       { "DMIC L3", NULL, "DMIC3 power" },
+       { "DMIC R3", NULL, "DMIC3 power" },
+       { "DMIC L4", NULL, "DMIC4 power" },
+       { "DMIC R4", NULL, "DMIC4 power" },
+
        { "BST1", NULL, "IN1P" },
        { "BST1", NULL, "IN1N" },
        { "BST2", NULL, "IN2P" },
@@ -2691,6 +2713,7 @@ static const struct snd_soc_dapm_route rt5677_dapm_routes[] = {
        { "Sidetone Mux", "DMIC4 L", "DMIC L4" },
        { "Sidetone Mux", "ADC1", "ADC 1" },
        { "Sidetone Mux", "ADC2", "ADC 2" },
+       { "Sidetone Mux", NULL, "Sidetone Power" },
 
        { "Stereo DAC MIXL", "ST L Switch", "Sidetone Mux" },
        { "Stereo DAC MIXL", "DAC1 L Switch", "DAC1 MIXL" },
@@ -2793,6 +2816,16 @@ static const struct snd_soc_dapm_route rt5677_dapm_routes[] = {
        { "PDM2R", NULL, "PDM2 R Mux" },
 };
 
+static const struct snd_soc_dapm_route rt5677_dmic2_clk_1[] = {
+       { "DMIC L2", NULL, "DMIC1 power" },
+       { "DMIC R2", NULL, "DMIC1 power" },
+};
+
+static const struct snd_soc_dapm_route rt5677_dmic2_clk_2[] = {
+       { "DMIC L2", NULL, "DMIC2 power" },
+       { "DMIC R2", NULL, "DMIC2 power" },
+};
+
 static int rt5677_hw_params(struct snd_pcm_substream *substream,
        struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
 {
@@ -3084,6 +3117,59 @@ static int rt5677_set_dai_pll(struct snd_soc_dai *dai, int pll_id, int source,
        return 0;
 }
 
+static int rt5677_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
+                       unsigned int rx_mask, int slots, int slot_width)
+{
+       struct snd_soc_codec *codec = dai->codec;
+       unsigned int val = 0;
+
+       if (rx_mask || tx_mask)
+               val |= (1 << 12);
+
+       switch (slots) {
+       case 4:
+               val |= (1 << 10);
+               break;
+       case 6:
+               val |= (2 << 10);
+               break;
+       case 8:
+               val |= (3 << 10);
+               break;
+       case 2:
+       default:
+               break;
+       }
+
+       switch (slot_width) {
+       case 20:
+               val |= (1 << 8);
+               break;
+       case 24:
+               val |= (2 << 8);
+               break;
+       case 32:
+               val |= (3 << 8);
+               break;
+       case 16:
+       default:
+               break;
+       }
+
+       switch (dai->id) {
+       case RT5677_AIF1:
+               snd_soc_update_bits(codec, RT5677_TDM1_CTRL1, 0x1f00, val);
+               break;
+       case RT5677_AIF2:
+               snd_soc_update_bits(codec, RT5677_TDM2_CTRL1, 0x1f00, val);
+               break;
+       default:
+               break;
+       }
+
+       return 0;
+}
+
 static int rt5677_set_bias_level(struct snd_soc_codec *codec,
                        enum snd_soc_bias_level level)
 {
@@ -3138,12 +3224,148 @@ static int rt5677_set_bias_level(struct snd_soc_codec *codec,
        return 0;
 }
 
+#ifdef CONFIG_GPIOLIB
+static inline struct rt5677_priv *gpio_to_rt5677(struct gpio_chip *chip)
+{
+       return container_of(chip, struct rt5677_priv, gpio_chip);
+}
+
+static void rt5677_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
+{
+       struct rt5677_priv *rt5677 = gpio_to_rt5677(chip);
+
+       switch (offset) {
+       case RT5677_GPIO1 ... RT5677_GPIO5:
+               regmap_update_bits(rt5677->regmap, RT5677_GPIO_CTRL2,
+                       0x1 << (offset * 3 + 1), !!value << (offset * 3 + 1));
+               break;
+
+       case RT5677_GPIO6:
+               regmap_update_bits(rt5677->regmap, RT5677_GPIO_CTRL3,
+                       RT5677_GPIO6_OUT_MASK, !!value << RT5677_GPIO6_OUT_SFT);
+               break;
+
+       default:
+               break;
+       }
+}
+
+static int rt5677_gpio_direction_out(struct gpio_chip *chip,
+                                    unsigned offset, int value)
+{
+       struct rt5677_priv *rt5677 = gpio_to_rt5677(chip);
+
+       switch (offset) {
+       case RT5677_GPIO1 ... RT5677_GPIO5:
+               regmap_update_bits(rt5677->regmap, RT5677_GPIO_CTRL2,
+                       0x3 << (offset * 3 + 1),
+                       (0x2 | !!value) << (offset * 3 + 1));
+               break;
+
+       case RT5677_GPIO6:
+               regmap_update_bits(rt5677->regmap, RT5677_GPIO_CTRL3,
+                       RT5677_GPIO6_DIR_MASK | RT5677_GPIO6_OUT_MASK,
+                       RT5677_GPIO6_DIR_OUT | !!value << RT5677_GPIO6_OUT_SFT);
+               break;
+
+       default:
+               break;
+       }
+
+       return 0;
+}
+
+static int rt5677_gpio_get(struct gpio_chip *chip, unsigned offset)
+{
+       struct rt5677_priv *rt5677 = gpio_to_rt5677(chip);
+       int value, ret;
+
+       ret = regmap_read(rt5677->regmap, RT5677_GPIO_ST, &value);
+       if (ret < 0)
+               return ret;
+
+       return (value & (0x1 << offset)) >> offset;
+}
+
+static int rt5677_gpio_direction_in(struct gpio_chip *chip, unsigned offset)
+{
+       struct rt5677_priv *rt5677 = gpio_to_rt5677(chip);
+
+       switch (offset) {
+       case RT5677_GPIO1 ... RT5677_GPIO5:
+               regmap_update_bits(rt5677->regmap, RT5677_GPIO_CTRL2,
+                       0x1 << (offset * 3 + 2), 0x0);
+               break;
+
+       case RT5677_GPIO6:
+               regmap_update_bits(rt5677->regmap, RT5677_GPIO_CTRL3,
+                       RT5677_GPIO6_DIR_MASK, RT5677_GPIO6_DIR_IN);
+               break;
+
+       default:
+               break;
+       }
+
+       return 0;
+}
+
+static struct gpio_chip rt5677_template_chip = {
+       .label                  = "rt5677",
+       .owner                  = THIS_MODULE,
+       .direction_output       = rt5677_gpio_direction_out,
+       .set                    = rt5677_gpio_set,
+       .direction_input        = rt5677_gpio_direction_in,
+       .get                    = rt5677_gpio_get,
+       .can_sleep              = 1,
+};
+
+static void rt5677_init_gpio(struct i2c_client *i2c)
+{
+       struct rt5677_priv *rt5677 = i2c_get_clientdata(i2c);
+       int ret;
+
+       rt5677->gpio_chip = rt5677_template_chip;
+       rt5677->gpio_chip.ngpio = RT5677_GPIO_NUM;
+       rt5677->gpio_chip.dev = &i2c->dev;
+       rt5677->gpio_chip.base = -1;
+
+       ret = gpiochip_add(&rt5677->gpio_chip);
+       if (ret != 0)
+               dev_err(&i2c->dev, "Failed to add GPIOs: %d\n", ret);
+}
+
+static void rt5677_free_gpio(struct i2c_client *i2c)
+{
+       struct rt5677_priv *rt5677 = i2c_get_clientdata(i2c);
+
+       gpiochip_remove(&rt5677->gpio_chip);
+}
+#else
+static void rt5677_init_gpio(struct i2c_client *i2c)
+{
+}
+
+static void rt5677_free_gpio(struct i2c_client *i2c)
+{
+}
+#endif
+
 static int rt5677_probe(struct snd_soc_codec *codec)
 {
        struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec);
 
        rt5677->codec = codec;
 
+       if (rt5677->pdata.dmic2_clk_pin == RT5677_DMIC_CLK2) {
+               snd_soc_dapm_add_routes(&codec->dapm,
+                       rt5677_dmic2_clk_2,
+                       ARRAY_SIZE(rt5677_dmic2_clk_2));
+       } else { /*use dmic1 clock by default*/
+               snd_soc_dapm_add_routes(&codec->dapm,
+                       rt5677_dmic2_clk_1,
+                       ARRAY_SIZE(rt5677_dmic2_clk_1));
+       }
+
        rt5677_set_bias_level(codec, SND_SOC_BIAS_OFF);
 
        regmap_write(rt5677->regmap, RT5677_DIG_MISC, 0x0020);
@@ -3157,6 +3379,8 @@ static int rt5677_remove(struct snd_soc_codec *codec)
        struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec);
 
        regmap_write(rt5677->regmap, RT5677_RESET, 0x10ec);
+       if (gpio_is_valid(rt5677->pow_ldo2))
+               gpio_set_value_cansleep(rt5677->pow_ldo2, 0);
 
        return 0;
 }
@@ -3168,6 +3392,8 @@ static int rt5677_suspend(struct snd_soc_codec *codec)
 
        regcache_cache_only(rt5677->regmap, true);
        regcache_mark_dirty(rt5677->regmap);
+       if (gpio_is_valid(rt5677->pow_ldo2))
+               gpio_set_value_cansleep(rt5677->pow_ldo2, 0);
 
        return 0;
 }
@@ -3176,6 +3402,10 @@ static int rt5677_resume(struct snd_soc_codec *codec)
 {
        struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec);
 
+       if (gpio_is_valid(rt5677->pow_ldo2)) {
+               gpio_set_value_cansleep(rt5677->pow_ldo2, 1);
+               msleep(10);
+       }
        regcache_cache_only(rt5677->regmap, false);
        regcache_sync(rt5677->regmap);
 
@@ -3195,6 +3425,7 @@ static struct snd_soc_dai_ops rt5677_aif_dai_ops = {
        .set_fmt = rt5677_set_dai_fmt,
        .set_sysclk = rt5677_set_dai_sysclk,
        .set_pll = rt5677_set_dai_pll,
+       .set_tdm_slot = rt5677_set_tdm_slot,
 };
 
 static struct snd_soc_dai_driver rt5677_dai[] = {
@@ -3333,6 +3564,35 @@ static const struct i2c_device_id rt5677_i2c_id[] = {
 };
 MODULE_DEVICE_TABLE(i2c, rt5677_i2c_id);
 
+static int rt5677_parse_dt(struct rt5677_priv *rt5677, struct device_node *np)
+{
+       rt5677->pdata.in1_diff = of_property_read_bool(np,
+                                       "realtek,in1-differential");
+       rt5677->pdata.in2_diff = of_property_read_bool(np,
+                                       "realtek,in2-differential");
+       rt5677->pdata.lout1_diff = of_property_read_bool(np,
+                                       "realtek,lout1-differential");
+       rt5677->pdata.lout2_diff = of_property_read_bool(np,
+                                       "realtek,lout2-differential");
+       rt5677->pdata.lout3_diff = of_property_read_bool(np,
+                                       "realtek,lout3-differential");
+
+       rt5677->pow_ldo2 = of_get_named_gpio(np,
+                                       "realtek,pow-ldo2-gpio", 0);
+
+       /*
+        * POW_LDO2 is optional (it may be statically tied on the board).
+        * -ENOENT means that the property doesn't exist, i.e. there is no
+        * GPIO, so is not an error. Any other error code means the property
+        * exists, but could not be parsed.
+        */
+       if (!gpio_is_valid(rt5677->pow_ldo2) &&
+                       (rt5677->pow_ldo2 != -ENOENT))
+               return rt5677->pow_ldo2;
+
+       return 0;
+}
+
 static int rt5677_i2c_probe(struct i2c_client *i2c,
                    const struct i2c_device_id *id)
 {
@@ -3351,6 +3611,33 @@ static int rt5677_i2c_probe(struct i2c_client *i2c,
        if (pdata)
                rt5677->pdata = *pdata;
 
+       if (i2c->dev.of_node) {
+               ret = rt5677_parse_dt(rt5677, i2c->dev.of_node);
+               if (ret) {
+                       dev_err(&i2c->dev, "Failed to parse device tree: %d\n",
+                               ret);
+                       return ret;
+               }
+       } else {
+               rt5677->pow_ldo2 = -EINVAL;
+       }
+
+       if (gpio_is_valid(rt5677->pow_ldo2)) {
+               ret = devm_gpio_request_one(&i2c->dev, rt5677->pow_ldo2,
+                                           GPIOF_OUT_INIT_HIGH,
+                                           "RT5677 POW_LDO2");
+               if (ret < 0) {
+                       dev_err(&i2c->dev, "Failed to request POW_LDO2 %d: %d\n",
+                               rt5677->pow_ldo2, ret);
+                       return ret;
+               }
+               /* Wait a while until I2C bus becomes available. The datasheet
+                * does not specify the exact we should wait but startup
+                * sequence mentiones at least a few milliseconds.
+                */
+               msleep(10);
+       }
+
        rt5677->regmap = devm_regmap_init_i2c(i2c, &rt5677_regmap);
        if (IS_ERR(rt5677->regmap)) {
                ret = PTR_ERR(rt5677->regmap);
@@ -3381,6 +3668,29 @@ static int rt5677_i2c_probe(struct i2c_client *i2c,
                regmap_update_bits(rt5677->regmap, RT5677_IN1,
                                        RT5677_IN_DF2, RT5677_IN_DF2);
 
+       if (rt5677->pdata.lout1_diff)
+               regmap_update_bits(rt5677->regmap, RT5677_LOUT1,
+                                       RT5677_LOUT1_L_DF, RT5677_LOUT1_L_DF);
+
+       if (rt5677->pdata.lout2_diff)
+               regmap_update_bits(rt5677->regmap, RT5677_LOUT1,
+                                       RT5677_LOUT2_L_DF, RT5677_LOUT2_L_DF);
+
+       if (rt5677->pdata.lout3_diff)
+               regmap_update_bits(rt5677->regmap, RT5677_LOUT1,
+                                       RT5677_LOUT3_L_DF, RT5677_LOUT3_L_DF);
+
+       if (rt5677->pdata.dmic2_clk_pin == RT5677_DMIC_CLK2) {
+               regmap_update_bits(rt5677->regmap, RT5677_GEN_CTRL2,
+                                       RT5677_GPIO5_FUNC_MASK,
+                                       RT5677_GPIO5_FUNC_DMIC);
+               regmap_update_bits(rt5677->regmap, RT5677_GPIO_CTRL2,
+                                       RT5677_GPIO5_DIR_MASK,
+                                       RT5677_GPIO5_DIR_OUT);
+       }
+
+       rt5677_init_gpio(i2c);
+
        return snd_soc_register_codec(&i2c->dev, &soc_codec_dev_rt5677,
                                      rt5677_dai, ARRAY_SIZE(rt5677_dai));
 }
@@ -3388,6 +3698,7 @@ static int rt5677_i2c_probe(struct i2c_client *i2c,
 static int rt5677_i2c_remove(struct i2c_client *i2c)
 {
        snd_soc_unregister_codec(&i2c->dev);
+       rt5677_free_gpio(i2c);
 
        return 0;
 }
index 863393e620960c7a621b6b431741cb7a1a50ecbf..d4eb6d5e6746f949c2a601613e85595c34f01c20 100644 (file)
 #define RT5677_ST_SEL_SFT                      9
 #define RT5677_ST_EN                           (0x1 << 6)
 #define RT5677_ST_EN_SFT                       6
+#define RT5677_ST_GAIN                         (0x1 << 5)
+#define RT5677_ST_GAIN_SFT                     5
+#define RT5677_ST_VOL_MASK                     (0x1f << 0)
+#define RT5677_ST_VOL_SFT                      0
 
 /* Analog DAC1/2/3 Source Control (0x15) */
 #define RT5677_ANA_DAC3_SRC_SEL_MASK           (0x3 << 4)
 #define RT5677_PLL1_PD_SFT                     8
 #define RT5677_PLL1_PD_1                       (0x0 << 8)
 #define RT5677_PLL1_PD_2                       (0x1 << 8)
-#define RT5671_DAC_OSR_MASK                    (0x3 << 6)
-#define RT5671_DAC_OSR_SFT                     6
-#define RT5671_DAC_OSR_128                     (0x0 << 6)
-#define RT5671_DAC_OSR_64                      (0x1 << 6)
-#define RT5671_DAC_OSR_32                      (0x2 << 6)
-#define RT5671_ADC_OSR_MASK                    (0x3 << 4)
-#define RT5671_ADC_OSR_SFT                     4
-#define RT5671_ADC_OSR_128                     (0x0 << 4)
-#define RT5671_ADC_OSR_64                      (0x1 << 4)
-#define RT5671_ADC_OSR_32                      (0x2 << 4)
+#define RT5677_DAC_OSR_MASK                    (0x3 << 6)
+#define RT5677_DAC_OSR_SFT                     6
+#define RT5677_DAC_OSR_128                     (0x0 << 6)
+#define RT5677_DAC_OSR_64                      (0x1 << 6)
+#define RT5677_DAC_OSR_32                      (0x2 << 6)
+#define RT5677_ADC_OSR_MASK                    (0x3 << 4)
+#define RT5677_ADC_OSR_SFT                     4
+#define RT5677_ADC_OSR_128                     (0x0 << 4)
+#define RT5677_ADC_OSR_64                      (0x1 << 4)
+#define RT5677_ADC_OSR_32                      (0x2 << 4)
 
 /* Global Clock Control 2 (0x81) */
 #define RT5677_PLL2_PR_SRC_MASK                        (0x1 << 15)
 #define RT5677_PLL2_SRC_BCLK4                  (0x4 << 12)
 #define RT5677_PLL2_SRC_RCCLK                  (0x5 << 12)
 #define RT5677_PLL2_SRC_SLIM                   (0x6 << 12)
-#define RT5671_DSP_ASRC_O_SRC                  (0x3 << 10)
-#define RT5671_DSP_ASRC_O_SRC_SFT              10
-#define RT5671_DSP_ASRC_O_MCLK                 (0x0 << 10)
-#define RT5671_DSP_ASRC_O_PLL1                 (0x1 << 10)
-#define RT5671_DSP_ASRC_O_SLIM                 (0x2 << 10)
-#define RT5671_DSP_ASRC_O_RCCLK                        (0x3 << 10)
-#define RT5671_DSP_ASRC_I_SRC                  (0x3 << 8)
-#define RT5671_DSP_ASRC_I_SRC_SFT              8
-#define RT5671_DSP_ASRC_I_MCLK                 (0x0 << 8)
-#define RT5671_DSP_ASRC_I_PLL1                 (0x1 << 8)
-#define RT5671_DSP_ASRC_I_SLIM                 (0x2 << 8)
-#define RT5671_DSP_ASRC_I_RCCLK                        (0x3 << 8)
+#define RT5677_DSP_ASRC_O_SRC                  (0x3 << 10)
+#define RT5677_DSP_ASRC_O_SRC_SFT              10
+#define RT5677_DSP_ASRC_O_MCLK                 (0x0 << 10)
+#define RT5677_DSP_ASRC_O_PLL1                 (0x1 << 10)
+#define RT5677_DSP_ASRC_O_SLIM                 (0x2 << 10)
+#define RT5677_DSP_ASRC_O_RCCLK                        (0x3 << 10)
+#define RT5677_DSP_ASRC_I_SRC                  (0x3 << 8)
+#define RT5677_DSP_ASRC_I_SRC_SFT              8
+#define RT5677_DSP_ASRC_I_MCLK                 (0x0 << 8)
+#define RT5677_DSP_ASRC_I_PLL1                 (0x1 << 8)
+#define RT5677_DSP_ASRC_I_SLIM                 (0x2 << 8)
+#define RT5677_DSP_ASRC_I_RCCLK                        (0x3 << 8)
 #define RT5677_DSP_CLK_SRC_MASK                        (0x1 << 7)
 #define RT5677_DSP_CLK_SRC_SFT                 7
 #define RT5677_DSP_CLK_SRC_PLL2                        (0x0 << 7)
 #define RT5677_SEL_SRC_IB01                    (0x1 << 0)
 #define RT5677_SEL_SRC_IB01_SFT                        0
 
+/* GPIO status (0xbf) */
+#define RT5677_GPIO6_STATUS_MASK               (0x1 << 5)
+#define RT5677_GPIO6_STATUS_SFT                        5
+#define RT5677_GPIO5_STATUS_MASK               (0x1 << 4)
+#define RT5677_GPIO5_STATUS_SFT                        4
+#define RT5677_GPIO4_STATUS_MASK               (0x1 << 3)
+#define RT5677_GPIO4_STATUS_SFT                        3
+#define RT5677_GPIO3_STATUS_MASK               (0x1 << 2)
+#define RT5677_GPIO3_STATUS_SFT                        2
+#define RT5677_GPIO2_STATUS_MASK               (0x1 << 1)
+#define RT5677_GPIO2_STATUS_SFT                        1
+#define RT5677_GPIO1_STATUS_MASK               (0x1 << 0)
+#define RT5677_GPIO1_STATUS_SFT                        0
+
+/* GPIO Control 1 (0xc0) */
+#define RT5677_GPIO1_PIN_MASK                  (0x1 << 15)
+#define RT5677_GPIO1_PIN_SFT                   15
+#define RT5677_GPIO1_PIN_GPIO1                 (0x0 << 15)
+#define RT5677_GPIO1_PIN_IRQ                   (0x1 << 15)
+#define RT5677_IPTV_MODE_MASK                  (0x1 << 14)
+#define RT5677_IPTV_MODE_SFT                   14
+#define RT5677_IPTV_MODE_GPIO                  (0x0 << 14)
+#define RT5677_IPTV_MODE_IPTV                  (0x1 << 14)
+#define RT5677_FUNC_MODE_MASK                  (0x1 << 13)
+#define RT5677_FUNC_MODE_SFT                   13
+#define RT5677_FUNC_MODE_DMIC_GPIO             (0x0 << 13)
+#define RT5677_FUNC_MODE_JTAG                  (0x1 << 13)
+
+/* GPIO Control 2 (0xc1) */
+#define RT5677_GPIO5_DIR_MASK                  (0x1 << 14)
+#define RT5677_GPIO5_DIR_SFT                   14
+#define RT5677_GPIO5_DIR_IN                    (0x0 << 14)
+#define RT5677_GPIO5_DIR_OUT                   (0x1 << 14)
+#define RT5677_GPIO5_OUT_MASK                  (0x1 << 13)
+#define RT5677_GPIO5_OUT_SFT                   13
+#define RT5677_GPIO5_OUT_LO                    (0x0 << 13)
+#define RT5677_GPIO5_OUT_HI                    (0x1 << 13)
+#define RT5677_GPIO5_P_MASK                    (0x1 << 12)
+#define RT5677_GPIO5_P_SFT                     12
+#define RT5677_GPIO5_P_NOR                     (0x0 << 12)
+#define RT5677_GPIO5_P_INV                     (0x1 << 12)
+#define RT5677_GPIO4_DIR_MASK                  (0x1 << 11)
+#define RT5677_GPIO4_DIR_SFT                   11
+#define RT5677_GPIO4_DIR_IN                    (0x0 << 11)
+#define RT5677_GPIO4_DIR_OUT                   (0x1 << 11)
+#define RT5677_GPIO4_OUT_MASK                  (0x1 << 10)
+#define RT5677_GPIO4_OUT_SFT                   10
+#define RT5677_GPIO4_OUT_LO                    (0x0 << 10)
+#define RT5677_GPIO4_OUT_HI                    (0x1 << 10)
+#define RT5677_GPIO4_P_MASK                    (0x1 << 9)
+#define RT5677_GPIO4_P_SFT                     9
+#define RT5677_GPIO4_P_NOR                     (0x0 << 9)
+#define RT5677_GPIO4_P_INV                     (0x1 << 9)
+#define RT5677_GPIO3_DIR_MASK                  (0x1 << 8)
+#define RT5677_GPIO3_DIR_SFT                   8
+#define RT5677_GPIO3_DIR_IN                    (0x0 << 8)
+#define RT5677_GPIO3_DIR_OUT                   (0x1 << 8)
+#define RT5677_GPIO3_OUT_MASK                  (0x1 << 7)
+#define RT5677_GPIO3_OUT_SFT                   7
+#define RT5677_GPIO3_OUT_LO                    (0x0 << 7)
+#define RT5677_GPIO3_OUT_HI                    (0x1 << 7)
+#define RT5677_GPIO3_P_MASK                    (0x1 << 6)
+#define RT5677_GPIO3_P_SFT                     6
+#define RT5677_GPIO3_P_NOR                     (0x0 << 6)
+#define RT5677_GPIO3_P_INV                     (0x1 << 6)
+#define RT5677_GPIO2_DIR_MASK                  (0x1 << 5)
+#define RT5677_GPIO2_DIR_SFT                   5
+#define RT5677_GPIO2_DIR_IN                    (0x0 << 5)
+#define RT5677_GPIO2_DIR_OUT                   (0x1 << 5)
+#define RT5677_GPIO2_OUT_MASK                  (0x1 << 4)
+#define RT5677_GPIO2_OUT_SFT                   4
+#define RT5677_GPIO2_OUT_LO                    (0x0 << 4)
+#define RT5677_GPIO2_OUT_HI                    (0x1 << 4)
+#define RT5677_GPIO2_P_MASK                    (0x1 << 3)
+#define RT5677_GPIO2_P_SFT                     3
+#define RT5677_GPIO2_P_NOR                     (0x0 << 3)
+#define RT5677_GPIO2_P_INV                     (0x1 << 3)
+#define RT5677_GPIO1_DIR_MASK                  (0x1 << 2)
+#define RT5677_GPIO1_DIR_SFT                   2
+#define RT5677_GPIO1_DIR_IN                    (0x0 << 2)
+#define RT5677_GPIO1_DIR_OUT                   (0x1 << 2)
+#define RT5677_GPIO1_OUT_MASK                  (0x1 << 1)
+#define RT5677_GPIO1_OUT_SFT                   1
+#define RT5677_GPIO1_OUT_LO                    (0x0 << 1)
+#define RT5677_GPIO1_OUT_HI                    (0x1 << 1)
+#define RT5677_GPIO1_P_MASK                    (0x1 << 0)
+#define RT5677_GPIO1_P_SFT                     0
+#define RT5677_GPIO1_P_NOR                     (0x0 << 0)
+#define RT5677_GPIO1_P_INV                     (0x1 << 0)
+
+/* GPIO Control 3 (0xc2) */
+#define RT5677_GPIO6_DIR_MASK                  (0x1 << 2)
+#define RT5677_GPIO6_DIR_SFT                   2
+#define RT5677_GPIO6_DIR_IN                    (0x0 << 2)
+#define RT5677_GPIO6_DIR_OUT                   (0x1 << 2)
+#define RT5677_GPIO6_OUT_MASK                  (0x1 << 1)
+#define RT5677_GPIO6_OUT_SFT                   1
+#define RT5677_GPIO6_OUT_LO                    (0x0 << 1)
+#define RT5677_GPIO6_OUT_HI                    (0x1 << 1)
+#define RT5677_GPIO6_P_MASK                    (0x1 << 0)
+#define RT5677_GPIO6_P_SFT                     0
+#define RT5677_GPIO6_P_NOR                     (0x0 << 0)
+#define RT5677_GPIO6_P_INV                     (0x1 << 0)
+
 /* Virtual DSP Mixer Control (0xf7 0xf8 0xf9) */
 #define RT5677_DSP_IB_01_H                     (0x1 << 15)
 #define RT5677_DSP_IB_01_H_SFT                 15
 #define RT5677_DSP_IB_9_L                      (0x1 << 1)
 #define RT5677_DSP_IB_9_L_SFT                  1
 
+/* General Control2 (0xfc)*/
+#define RT5677_GPIO5_FUNC_MASK                 (0x1 << 9)
+#define RT5677_GPIO5_FUNC_GPIO                 (0x0 << 9)
+#define RT5677_GPIO5_FUNC_DMIC                 (0x1 << 9)
+
 /* System Clock Source */
 enum {
        RT5677_SCLK_S_MCLK,
@@ -1418,6 +1531,16 @@ enum {
        RT5677_AIFS,
 };
 
+enum {
+       RT5677_GPIO1,
+       RT5677_GPIO2,
+       RT5677_GPIO3,
+       RT5677_GPIO4,
+       RT5677_GPIO5,
+       RT5677_GPIO6,
+       RT5677_GPIO_NUM,
+};
+
 struct rt5677_priv {
        struct snd_soc_codec *codec;
        struct rt5677_platform_data pdata;
@@ -1431,6 +1554,10 @@ struct rt5677_priv {
        int pll_src;
        int pll_in;
        int pll_out;
+       int pow_ldo2; /* POW_LDO2 pin */
+#ifdef CONFIG_GPIOLIB
+       struct gpio_chip gpio_chip;
+#endif
 };
 
 #endif /* __RT5677_H__ */
index e997d271728d4943c1ffa63d59f7930ef2b59e65..6bb77d76561b8964303275955d1e1beb579ba859 100644 (file)
@@ -626,6 +626,9 @@ static int sgtl5000_set_clock(struct snd_soc_codec *codec, int frame_rate)
                } else {
                        dev_err(codec->dev,
                                "PLL not supported in slave mode\n");
+                       dev_err(codec->dev, "%d ratio is not supported. "
+                               "SYS_MCLK needs to be 256, 384 or 512 * fs\n",
+                               sgtl5000->sysclk / sys_fs);
                        return -EINVAL;
                }
        }
@@ -1073,26 +1076,6 @@ static bool sgtl5000_readable(struct device *dev, unsigned int reg)
        }
 }
 
-#ifdef CONFIG_SUSPEND
-static int sgtl5000_suspend(struct snd_soc_codec *codec)
-{
-       sgtl5000_set_bias_level(codec, SND_SOC_BIAS_OFF);
-
-       return 0;
-}
-
-static int sgtl5000_resume(struct snd_soc_codec *codec)
-{
-       /* Bring the codec back up to standby to enable regulators */
-       sgtl5000_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
-
-       return 0;
-}
-#else
-#define sgtl5000_suspend NULL
-#define sgtl5000_resume  NULL
-#endif /* CONFIG_SUSPEND */
-
 /*
  * sgtl5000 has 3 internal power supplies:
  * 1. VAG, normally set to vdda/2
@@ -1352,11 +1335,6 @@ static int sgtl5000_probe(struct snd_soc_codec *codec)
         */
        snd_soc_write(codec, SGTL5000_DAP_CTRL, 0);
 
-       /* leading to standby state */
-       ret = sgtl5000_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
-       if (ret)
-               goto err;
-
        return 0;
 
 err:
@@ -1373,8 +1351,6 @@ static int sgtl5000_remove(struct snd_soc_codec *codec)
 {
        struct sgtl5000_priv *sgtl5000 = snd_soc_codec_get_drvdata(codec);
 
-       sgtl5000_set_bias_level(codec, SND_SOC_BIAS_OFF);
-
        regulator_bulk_disable(ARRAY_SIZE(sgtl5000->supplies),
                                                sgtl5000->supplies);
        regulator_bulk_free(ARRAY_SIZE(sgtl5000->supplies),
@@ -1387,9 +1363,8 @@ static int sgtl5000_remove(struct snd_soc_codec *codec)
 static struct snd_soc_codec_driver sgtl5000_driver = {
        .probe = sgtl5000_probe,
        .remove = sgtl5000_remove,
-       .suspend = sgtl5000_suspend,
-       .resume = sgtl5000_resume,
        .set_bias_level = sgtl5000_set_bias_level,
+       .suspend_bias_off = true,
        .controls = sgtl5000_snd_controls,
        .num_controls = ARRAY_SIZE(sgtl5000_snd_controls),
        .dapm_widgets = sgtl5000_dapm_widgets,
@@ -1442,6 +1417,7 @@ static int sgtl5000_i2c_probe(struct i2c_client *client,
 {
        struct sgtl5000_priv *sgtl5000;
        int ret, reg, rev;
+       unsigned int mclk;
 
        sgtl5000 = devm_kzalloc(&client->dev, sizeof(struct sgtl5000_priv),
                                                                GFP_KERNEL);
@@ -1465,6 +1441,14 @@ static int sgtl5000_i2c_probe(struct i2c_client *client,
                return ret;
        }
 
+       /* SGTL5000 SYS_MCLK should be between 8 and 27 MHz */
+       mclk = clk_get_rate(sgtl5000->mclk);
+       if (mclk < 8000000 || mclk > 27000000) {
+               dev_err(&client->dev, "Invalid SYS_CLK frequency: %u.%03uMHz\n",
+                       mclk / 1000000, mclk / 1000 % 1000);
+               return -EINVAL;
+       }
+
        ret = clk_prepare_enable(sgtl5000->mclk);
        if (ret)
                return ret;
index e8680bea5f8634ed9f2643f4d830bfe8d8b27e69..67ea55adb307d373dd4f3d91291b930b35d68a7a 100644 (file)
@@ -646,17 +646,6 @@ static struct snd_soc_dai_driver ssm2518_dai = {
        .ops = &ssm2518_dai_ops,
 };
 
-static int ssm2518_probe(struct snd_soc_codec *codec)
-{
-       return ssm2518_set_bias_level(codec, SND_SOC_BIAS_OFF);
-}
-
-static int ssm2518_remove(struct snd_soc_codec *codec)
-{
-       ssm2518_set_bias_level(codec, SND_SOC_BIAS_OFF);
-       return 0;
-}
-
 static int ssm2518_set_sysclk(struct snd_soc_codec *codec, int clk_id,
        int source, unsigned int freq, int dir)
 {
@@ -727,8 +716,6 @@ static int ssm2518_set_sysclk(struct snd_soc_codec *codec, int clk_id,
 }
 
 static struct snd_soc_codec_driver ssm2518_codec_driver = {
-       .probe = ssm2518_probe,
-       .remove = ssm2518_remove,
        .set_bias_level = ssm2518_set_bias_level,
        .set_sysclk = ssm2518_set_sysclk,
        .idle_bias_off = true,
index abd63d5371733d36cf3e31dfe6ed4a2e79692bfc..0d9779d6bfda7fced8b472d283a04ad9d91c7f75 100644 (file)
@@ -41,10 +41,19 @@ static const struct i2c_device_id ssm2602_i2c_id[] = {
 };
 MODULE_DEVICE_TABLE(i2c, ssm2602_i2c_id);
 
+static const struct of_device_id ssm2602_of_match[] = {
+       { .compatible = "adi,ssm2602", },
+       { .compatible = "adi,ssm2603", },
+       { .compatible = "adi,ssm2604", },
+       { }
+};
+MODULE_DEVICE_TABLE(of, ssm2602_of_match);
+
 static struct i2c_driver ssm2602_i2c_driver = {
        .driver = {
                .name = "ssm2602",
                .owner = THIS_MODULE,
+               .of_match_table = ssm2602_of_match,
        },
        .probe = ssm2602_i2c_probe,
        .remove = ssm2602_i2c_remove,
index 2bf55e24a7bbfce316cc90a3431beca554bd7b8a..b5df14fbe3adabd9f0604b0af536caa4df6182e6 100644 (file)
@@ -26,10 +26,17 @@ static int ssm2602_spi_remove(struct spi_device *spi)
        return 0;
 }
 
+static const struct of_device_id ssm2602_of_match[] = {
+       { .compatible = "adi,ssm2602", },
+       { }
+};
+MODULE_DEVICE_TABLE(of, ssm2602_of_match);
+
 static struct spi_driver ssm2602_spi_driver = {
        .driver = {
                .name   = "ssm2602",
                .owner  = THIS_MODULE,
+               .of_match_table = ssm2602_of_match,
        },
        .probe          = ssm2602_spi_probe,
        .remove         = ssm2602_spi_remove,
index 4021cd4357409e9ee95080ae9e61bb5752774272..314eaece1b7d6ac50bfb2d8af18ef1247bd3194c 100644 (file)
@@ -192,7 +192,7 @@ static const struct snd_pcm_hw_constraint_list ssm2602_constraints_12288000 = {
 };
 
 static const unsigned int ssm2602_rates_11289600[] = {
-       8000, 44100, 88200,
+       8000, 11025, 22050, 44100, 88200,
 };
 
 static const struct snd_pcm_hw_constraint_list ssm2602_constraints_11289600 = {
@@ -237,6 +237,16 @@ static const struct ssm2602_coeff ssm2602_coeff_table[] = {
        {18432000, 96000, SSM2602_COEFF_SRATE(0x7, 0x1, 0x0)},
        {12000000, 96000, SSM2602_COEFF_SRATE(0x7, 0x0, 0x1)},
 
+       /* 11.025k */
+       {11289600, 11025, SSM2602_COEFF_SRATE(0xc, 0x0, 0x0)},
+       {16934400, 11025, SSM2602_COEFF_SRATE(0xc, 0x1, 0x0)},
+       {12000000, 11025, SSM2602_COEFF_SRATE(0xc, 0x1, 0x1)},
+
+       /* 22.05k */
+       {11289600, 22050, SSM2602_COEFF_SRATE(0xd, 0x0, 0x0)},
+       {16934400, 22050, SSM2602_COEFF_SRATE(0xd, 0x1, 0x0)},
+       {12000000, 22050, SSM2602_COEFF_SRATE(0xd, 0x1, 0x1)},
+
        /* 44.1k */
        {11289600, 44100, SSM2602_COEFF_SRATE(0x8, 0x0, 0x0)},
        {16934400, 44100, SSM2602_COEFF_SRATE(0x8, 0x1, 0x0)},
@@ -467,7 +477,8 @@ static int ssm2602_set_bias_level(struct snd_soc_codec *codec,
        return 0;
 }
 
-#define SSM2602_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |\
+#define SSM2602_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\
+               SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 |\
                SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |\
                SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 |\
                SNDRV_PCM_RATE_96000)
@@ -502,18 +513,11 @@ static struct snd_soc_dai_driver ssm2602_dai = {
        .symmetric_samplebits = 1,
 };
 
-static int ssm2602_suspend(struct snd_soc_codec *codec)
-{
-       ssm2602_set_bias_level(codec, SND_SOC_BIAS_OFF);
-       return 0;
-}
-
 static int ssm2602_resume(struct snd_soc_codec *codec)
 {
        struct ssm2602_priv *ssm2602 = snd_soc_codec_get_drvdata(codec);
 
        regcache_sync(ssm2602->regmap);
-       ssm2602_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
 
        return 0;
 }
@@ -586,27 +590,14 @@ static int ssm260x_codec_probe(struct snd_soc_codec *codec)
                break;
        }
 
-       if (ret)
-               return ret;
-
-       ssm2602_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
-
-       return 0;
-}
-
-/* remove everything here */
-static int ssm2602_remove(struct snd_soc_codec *codec)
-{
-       ssm2602_set_bias_level(codec, SND_SOC_BIAS_OFF);
-       return 0;
+       return ret;
 }
 
 static struct snd_soc_codec_driver soc_codec_dev_ssm2602 = {
        .probe =        ssm260x_codec_probe,
-       .remove =       ssm2602_remove,
-       .suspend =      ssm2602_suspend,
        .resume =       ssm2602_resume,
        .set_bias_level = ssm2602_set_bias_level,
+       .suspend_bias_off = true,
 
        .controls = ssm260x_snd_controls,
        .num_controls = ARRAY_SIZE(ssm260x_snd_controls),
diff --git a/sound/soc/codecs/ssm4567.c b/sound/soc/codecs/ssm4567.c
new file mode 100644 (file)
index 0000000..4b5c17f
--- /dev/null
@@ -0,0 +1,343 @@
+/*
+ * SSM4567 amplifier audio driver
+ *
+ * Copyright 2014 Google Chromium project.
+ *  Author: Anatol Pomozov <anatol@chromium.org>
+ *
+ * Based on code copyright/by:
+ *   Copyright 2013 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+
+#define SSM4567_REG_POWER_CTRL         0x00
+#define SSM4567_REG_AMP_SNS_CTRL               0x01
+#define SSM4567_REG_DAC_CTRL           0x02
+#define SSM4567_REG_DAC_VOLUME         0x03
+#define SSM4567_REG_SAI_CTRL_1         0x04
+#define SSM4567_REG_SAI_CTRL_2         0x05
+#define SSM4567_REG_SAI_PLACEMENT_1            0x06
+#define SSM4567_REG_SAI_PLACEMENT_2            0x07
+#define SSM4567_REG_SAI_PLACEMENT_3            0x08
+#define SSM4567_REG_SAI_PLACEMENT_4            0x09
+#define SSM4567_REG_SAI_PLACEMENT_5            0x0a
+#define SSM4567_REG_SAI_PLACEMENT_6            0x0b
+#define SSM4567_REG_BATTERY_V_OUT              0x0c
+#define SSM4567_REG_LIMITER_CTRL_1             0x0d
+#define SSM4567_REG_LIMITER_CTRL_2             0x0e
+#define SSM4567_REG_LIMITER_CTRL_3             0x0f
+#define SSM4567_REG_STATUS_1           0x10
+#define SSM4567_REG_STATUS_2           0x11
+#define SSM4567_REG_FAULT_CTRL         0x12
+#define SSM4567_REG_PDM_CTRL           0x13
+#define SSM4567_REG_MCLK_RATIO         0x14
+#define SSM4567_REG_BOOST_CTRL_1               0x15
+#define SSM4567_REG_BOOST_CTRL_2               0x16
+#define SSM4567_REG_SOFT_RESET         0xff
+
+/* POWER_CTRL */
+#define SSM4567_POWER_APWDN_EN         BIT(7)
+#define SSM4567_POWER_BSNS_PWDN                BIT(6)
+#define SSM4567_POWER_VSNS_PWDN                BIT(5)
+#define SSM4567_POWER_ISNS_PWDN                BIT(4)
+#define SSM4567_POWER_BOOST_PWDN               BIT(3)
+#define SSM4567_POWER_AMP_PWDN         BIT(2)
+#define SSM4567_POWER_VBAT_ONLY                BIT(1)
+#define SSM4567_POWER_SPWDN                    BIT(0)
+
+/* DAC_CTRL */
+#define SSM4567_DAC_HV                 BIT(7)
+#define SSM4567_DAC_MUTE               BIT(6)
+#define SSM4567_DAC_HPF                        BIT(5)
+#define SSM4567_DAC_LPM                        BIT(4)
+#define SSM4567_DAC_FS_MASK    0x7
+#define SSM4567_DAC_FS_8000_12000      0x0
+#define SSM4567_DAC_FS_16000_24000     0x1
+#define SSM4567_DAC_FS_32000_48000     0x2
+#define SSM4567_DAC_FS_64000_96000     0x3
+#define SSM4567_DAC_FS_128000_192000   0x4
+
+struct ssm4567 {
+       struct regmap *regmap;
+};
+
+static const struct reg_default ssm4567_reg_defaults[] = {
+       { SSM4567_REG_POWER_CTRL,       0x81 },
+       { SSM4567_REG_AMP_SNS_CTRL, 0x09 },
+       { SSM4567_REG_DAC_CTRL, 0x32 },
+       { SSM4567_REG_DAC_VOLUME, 0x40 },
+       { SSM4567_REG_SAI_CTRL_1, 0x00 },
+       { SSM4567_REG_SAI_CTRL_2, 0x08 },
+       { SSM4567_REG_SAI_PLACEMENT_1, 0x01 },
+       { SSM4567_REG_SAI_PLACEMENT_2, 0x20 },
+       { SSM4567_REG_SAI_PLACEMENT_3, 0x32 },
+       { SSM4567_REG_SAI_PLACEMENT_4, 0x07 },
+       { SSM4567_REG_SAI_PLACEMENT_5, 0x07 },
+       { SSM4567_REG_SAI_PLACEMENT_6, 0x07 },
+       { SSM4567_REG_BATTERY_V_OUT, 0x00 },
+       { SSM4567_REG_LIMITER_CTRL_1, 0xa4 },
+       { SSM4567_REG_LIMITER_CTRL_2, 0x73 },
+       { SSM4567_REG_LIMITER_CTRL_3, 0x00 },
+       { SSM4567_REG_STATUS_1, 0x00 },
+       { SSM4567_REG_STATUS_2, 0x00 },
+       { SSM4567_REG_FAULT_CTRL, 0x30 },
+       { SSM4567_REG_PDM_CTRL, 0x40 },
+       { SSM4567_REG_MCLK_RATIO, 0x11 },
+       { SSM4567_REG_BOOST_CTRL_1, 0x03 },
+       { SSM4567_REG_BOOST_CTRL_2, 0x00 },
+       { SSM4567_REG_SOFT_RESET, 0x00 },
+};
+
+
+static bool ssm4567_readable_reg(struct device *dev, unsigned int reg)
+{
+       switch (reg) {
+       case SSM4567_REG_POWER_CTRL ... SSM4567_REG_BOOST_CTRL_2:
+               return true;
+       default:
+               return false;
+       }
+
+}
+
+static bool ssm4567_writeable_reg(struct device *dev, unsigned int reg)
+{
+       switch (reg) {
+       case SSM4567_REG_POWER_CTRL ... SSM4567_REG_SAI_PLACEMENT_6:
+       case SSM4567_REG_LIMITER_CTRL_1 ... SSM4567_REG_LIMITER_CTRL_3:
+       case SSM4567_REG_FAULT_CTRL ... SSM4567_REG_BOOST_CTRL_2:
+       /* The datasheet states that soft reset register is read-only,
+        * but logically it is write-only. */
+       case SSM4567_REG_SOFT_RESET:
+               return true;
+       default:
+               return false;
+       }
+}
+
+static bool ssm4567_volatile_reg(struct device *dev, unsigned int reg)
+{
+       switch (reg) {
+       case SSM4567_REG_BATTERY_V_OUT:
+       case SSM4567_REG_STATUS_1 ... SSM4567_REG_STATUS_2:
+       case SSM4567_REG_SOFT_RESET:
+               return true;
+       default:
+               return false;
+       }
+}
+
+static const DECLARE_TLV_DB_MINMAX_MUTE(ssm4567_vol_tlv, -7125, 2400);
+
+static const struct snd_kcontrol_new ssm4567_snd_controls[] = {
+       SOC_SINGLE_TLV("Master Playback Volume", SSM4567_REG_DAC_VOLUME, 0,
+               0xff, 1, ssm4567_vol_tlv),
+       SOC_SINGLE("DAC Low Power Mode Switch", SSM4567_REG_DAC_CTRL, 4, 1, 0),
+};
+
+static const struct snd_soc_dapm_widget ssm4567_dapm_widgets[] = {
+       SND_SOC_DAPM_DAC("DAC", "HiFi Playback", SSM4567_REG_POWER_CTRL, 2, 1),
+
+       SND_SOC_DAPM_OUTPUT("OUT"),
+};
+
+static const struct snd_soc_dapm_route ssm4567_routes[] = {
+       { "OUT", NULL, "DAC" },
+};
+
+static int ssm4567_hw_params(struct snd_pcm_substream *substream,
+       struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
+{
+       struct snd_soc_codec *codec = dai->codec;
+       struct ssm4567 *ssm4567 = snd_soc_codec_get_drvdata(codec);
+       unsigned int rate = params_rate(params);
+       unsigned int dacfs;
+
+       if (rate >= 8000 && rate <= 12000)
+               dacfs = SSM4567_DAC_FS_8000_12000;
+       else if (rate >= 16000 && rate <= 24000)
+               dacfs = SSM4567_DAC_FS_16000_24000;
+       else if (rate >= 32000 && rate <= 48000)
+               dacfs = SSM4567_DAC_FS_32000_48000;
+       else if (rate >= 64000 && rate <= 96000)
+               dacfs = SSM4567_DAC_FS_64000_96000;
+       else if (rate >= 128000 && rate <= 192000)
+               dacfs = SSM4567_DAC_FS_128000_192000;
+       else
+               return -EINVAL;
+
+       return regmap_update_bits(ssm4567->regmap, SSM4567_REG_DAC_CTRL,
+                               SSM4567_DAC_FS_MASK, dacfs);
+}
+
+static int ssm4567_mute(struct snd_soc_dai *dai, int mute)
+{
+       struct ssm4567 *ssm4567 = snd_soc_codec_get_drvdata(dai->codec);
+       unsigned int val;
+
+       val = mute ? SSM4567_DAC_MUTE : 0;
+       return regmap_update_bits(ssm4567->regmap, SSM4567_REG_DAC_CTRL,
+                       SSM4567_DAC_MUTE, val);
+}
+
+static int ssm4567_set_power(struct ssm4567 *ssm4567, bool enable)
+{
+       int ret = 0;
+
+       if (!enable) {
+               ret = regmap_update_bits(ssm4567->regmap,
+                       SSM4567_REG_POWER_CTRL,
+                       SSM4567_POWER_SPWDN, SSM4567_POWER_SPWDN);
+               regcache_mark_dirty(ssm4567->regmap);
+       }
+
+       regcache_cache_only(ssm4567->regmap, !enable);
+
+       if (enable) {
+               ret = regmap_update_bits(ssm4567->regmap,
+                       SSM4567_REG_POWER_CTRL,
+                       SSM4567_POWER_SPWDN, 0x00);
+               regcache_sync(ssm4567->regmap);
+       }
+
+       return ret;
+}
+
+static int ssm4567_set_bias_level(struct snd_soc_codec *codec,
+       enum snd_soc_bias_level level)
+{
+       struct ssm4567 *ssm4567 = snd_soc_codec_get_drvdata(codec);
+       int ret = 0;
+
+       switch (level) {
+       case SND_SOC_BIAS_ON:
+               break;
+       case SND_SOC_BIAS_PREPARE:
+               break;
+       case SND_SOC_BIAS_STANDBY:
+               if (codec->dapm.bias_level == SND_SOC_BIAS_OFF)
+                       ret = ssm4567_set_power(ssm4567, true);
+               break;
+       case SND_SOC_BIAS_OFF:
+               ret = ssm4567_set_power(ssm4567, false);
+               break;
+       }
+
+       if (ret)
+               return ret;
+
+       codec->dapm.bias_level = level;
+
+       return 0;
+}
+
+static const struct snd_soc_dai_ops ssm4567_dai_ops = {
+       .hw_params      = ssm4567_hw_params,
+       .digital_mute   = ssm4567_mute,
+};
+
+static struct snd_soc_dai_driver ssm4567_dai = {
+       .name = "ssm4567-hifi",
+       .playback = {
+               .stream_name = "Playback",
+               .channels_min = 1,
+               .channels_max = 1,
+               .rates = SNDRV_PCM_RATE_8000_192000,
+               .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE |
+                       SNDRV_PCM_FMTBIT_S32,
+       },
+       .ops = &ssm4567_dai_ops,
+};
+
+static struct snd_soc_codec_driver ssm4567_codec_driver = {
+       .set_bias_level = ssm4567_set_bias_level,
+       .idle_bias_off = true,
+
+       .controls = ssm4567_snd_controls,
+       .num_controls = ARRAY_SIZE(ssm4567_snd_controls),
+       .dapm_widgets = ssm4567_dapm_widgets,
+       .num_dapm_widgets = ARRAY_SIZE(ssm4567_dapm_widgets),
+       .dapm_routes = ssm4567_routes,
+       .num_dapm_routes = ARRAY_SIZE(ssm4567_routes),
+};
+
+static const struct regmap_config ssm4567_regmap_config = {
+       .val_bits = 8,
+       .reg_bits = 8,
+
+       .max_register = SSM4567_REG_SOFT_RESET,
+       .readable_reg = ssm4567_readable_reg,
+       .writeable_reg = ssm4567_writeable_reg,
+       .volatile_reg = ssm4567_volatile_reg,
+
+       .cache_type = REGCACHE_RBTREE,
+       .reg_defaults = ssm4567_reg_defaults,
+       .num_reg_defaults = ARRAY_SIZE(ssm4567_reg_defaults),
+};
+
+static int ssm4567_i2c_probe(struct i2c_client *i2c,
+       const struct i2c_device_id *id)
+{
+       struct ssm4567 *ssm4567;
+       int ret;
+
+       ssm4567 = devm_kzalloc(&i2c->dev, sizeof(*ssm4567), GFP_KERNEL);
+       if (ssm4567 == NULL)
+               return -ENOMEM;
+
+       i2c_set_clientdata(i2c, ssm4567);
+
+       ssm4567->regmap = devm_regmap_init_i2c(i2c, &ssm4567_regmap_config);
+       if (IS_ERR(ssm4567->regmap))
+               return PTR_ERR(ssm4567->regmap);
+
+       ret = regmap_write(ssm4567->regmap, SSM4567_REG_SOFT_RESET, 0x00);
+       if (ret)
+               return ret;
+
+       ret = ssm4567_set_power(ssm4567, false);
+       if (ret)
+               return ret;
+
+       return snd_soc_register_codec(&i2c->dev, &ssm4567_codec_driver,
+                       &ssm4567_dai, 1);
+}
+
+static int ssm4567_i2c_remove(struct i2c_client *client)
+{
+       snd_soc_unregister_codec(&client->dev);
+       return 0;
+}
+
+static const struct i2c_device_id ssm4567_i2c_ids[] = {
+       { "ssm4567", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, ssm4567_i2c_ids);
+
+static struct i2c_driver ssm4567_driver = {
+       .driver = {
+               .name = "ssm4567",
+               .owner = THIS_MODULE,
+       },
+       .probe = ssm4567_i2c_probe,
+       .remove = ssm4567_i2c_remove,
+       .id_table = ssm4567_i2c_ids,
+};
+module_i2c_driver(ssm4567_driver);
+
+MODULE_DESCRIPTION("ASoC SSM4567 driver");
+MODULE_AUTHOR("Anatol Pomozov <anatol@chromium.org>");
+MODULE_LICENSE("GPL");
index 23b32960ff1db62f2c5738f402bed0d3c0f116b5..f039dc82597198f9f50686f98d480024176d5bf7 100644 (file)
@@ -78,6 +78,44 @@ struct tas2552_data {
        unsigned int mclk;
 };
 
+/* Input mux controls */
+static const char *tas2552_input_texts[] = {
+       "Digital", "Analog"
+};
+
+static SOC_ENUM_SINGLE_DECL(tas2552_input_mux_enum, TAS2552_CFG_3, 7,
+                           tas2552_input_texts);
+
+static const struct snd_kcontrol_new tas2552_input_mux_control[] = {
+       SOC_DAPM_ENUM("Input selection", tas2552_input_mux_enum)
+};
+
+static const struct snd_soc_dapm_widget tas2552_dapm_widgets[] =
+{
+       SND_SOC_DAPM_INPUT("IN"),
+
+       /* MUX Controls */
+       SND_SOC_DAPM_MUX("Input selection", SND_SOC_NOPM, 0, 0,
+                               tas2552_input_mux_control),
+
+       SND_SOC_DAPM_AIF_IN("DAC IN", "DAC Playback", 0, SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_DAC("DAC", NULL, SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_OUT_DRV("ClassD", TAS2552_CFG_2, 7, 0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY("PLL", TAS2552_CFG_2, 3, 0, NULL, 0),
+
+       SND_SOC_DAPM_OUTPUT("OUT")
+};
+
+static const struct snd_soc_dapm_route tas2552_audio_map[] = {
+       {"DAC", NULL, "DAC IN"},
+       {"Input selection", "Digital", "DAC"},
+       {"Input selection", "Analog", "IN"},
+       {"ClassD", NULL, "Input selection"},
+       {"OUT", NULL, "ClassD"},
+       {"ClassD", NULL, "PLL"},
+};
+
+#ifdef CONFIG_PM_RUNTIME
 static void tas2552_sw_shutdown(struct tas2552_data *tas_data, int sw_shutdown)
 {
        u8 cfg1_reg;
@@ -90,6 +128,7 @@ static void tas2552_sw_shutdown(struct tas2552_data *tas_data, int sw_shutdown)
        snd_soc_update_bits(tas_data->codec, TAS2552_CFG_1,
                                                 TAS2552_SWS_MASK, cfg1_reg);
 }
+#endif
 
 static int tas2552_hw_params(struct snd_pcm_substream *substream,
                             struct snd_pcm_hw_params *params,
@@ -101,10 +140,6 @@ static int tas2552_hw_params(struct snd_pcm_substream *substream,
        int d;
        u8 p, j;
 
-       /* Turn on Class D amplifier */
-       snd_soc_update_bits(codec, TAS2552_CFG_2, TAS2552_CLASSD_EN_MASK,
-                                               TAS2552_CLASSD_EN);
-
        if (!tas2552->mclk)
                return -EINVAL;
 
@@ -147,9 +182,6 @@ static int tas2552_hw_params(struct snd_pcm_substream *substream,
 
        }
 
-       snd_soc_update_bits(codec, TAS2552_CFG_2, TAS2552_PLL_ENABLE,
-                                               TAS2552_PLL_ENABLE);
-
        return 0;
 }
 
@@ -269,19 +301,10 @@ static const struct dev_pm_ops tas2552_pm = {
                           NULL)
 };
 
-static void tas2552_shutdown(struct snd_pcm_substream *substream,
-                          struct snd_soc_dai *dai)
-{
-       struct snd_soc_codec *codec = dai->codec;
-
-       snd_soc_update_bits(codec, TAS2552_CFG_2, TAS2552_PLL_ENABLE, 0);
-}
-
 static struct snd_soc_dai_ops tas2552_speaker_dai_ops = {
        .hw_params      = tas2552_hw_params,
        .set_sysclk     = tas2552_set_dai_sysclk,
        .set_fmt        = tas2552_set_dai_fmt,
-       .shutdown       = tas2552_shutdown,
        .digital_mute = tas2552_mute,
 };
 
@@ -294,7 +317,7 @@ static struct snd_soc_dai_driver tas2552_dai[] = {
        {
                .name = "tas2552-amplifier",
                .playback = {
-                       .stream_name = "Speaker",
+                       .stream_name = "Playback",
                        .channels_min = 2,
                        .channels_max = 2,
                        .rates = SNDRV_PCM_RATE_8000_192000,
@@ -312,6 +335,7 @@ static DECLARE_TLV_DB_SCALE(dac_tlv, -7, 100, 24);
 static const struct snd_kcontrol_new tas2552_snd_controls[] = {
        SOC_SINGLE_TLV("Speaker Driver Playback Volume",
                         TAS2552_PGA_GAIN, 0, 0x1f, 1, dac_tlv),
+       SOC_DAPM_SINGLE("Playback AMP", SND_SOC_NOPM, 0, 1, 0),
 };
 
 static const struct reg_default tas2552_init_regs[] = {
@@ -321,6 +345,7 @@ static const struct reg_default tas2552_init_regs[] = {
 static int tas2552_codec_probe(struct snd_soc_codec *codec)
 {
        struct tas2552_data *tas2552 = snd_soc_codec_get_drvdata(codec);
+       struct snd_soc_dapm_context *dapm = &codec->dapm;
        int ret;
 
        tas2552->codec = codec;
@@ -362,9 +387,14 @@ static int tas2552_codec_probe(struct snd_soc_codec *codec)
                goto patch_fail;
        }
 
-       snd_soc_write(codec, TAS2552_CFG_2, TAS2552_CLASSD_EN |
-                                 TAS2552_BOOST_EN | TAS2552_APT_EN |
-                                 TAS2552_LIM_EN);
+       snd_soc_write(codec, TAS2552_CFG_2, TAS2552_BOOST_EN |
+                                 TAS2552_APT_EN | TAS2552_LIM_EN);
+
+       snd_soc_dapm_new_controls(dapm, tas2552_dapm_widgets,
+                               ARRAY_SIZE(tas2552_dapm_widgets));
+       snd_soc_dapm_add_routes(dapm, tas2552_audio_map,
+                               ARRAY_SIZE(tas2552_audio_map));
+
        return 0;
 
 patch_fail:
index aea9e1ff9126592b91c70d29195725b0b2e183bd..145fe5b253d40f3e4eb9b43db64bbd97e41f8775 100644 (file)
@@ -167,13 +167,13 @@ struct aic31xx_priv {
        struct regulator_bulk_data supplies[AIC31XX_NUM_SUPPLIES];
        struct aic31xx_disable_nb disable_nb[AIC31XX_NUM_SUPPLIES];
        unsigned int sysclk;
+       u8 p_div;
        int rate_div_line;
 };
 
 struct aic31xx_rate_divs {
-       u32 mclk;
+       u32 mclk_p;
        u32 rate;
-       u8 p_val;
        u8 pll_j;
        u16 pll_d;
        u16 dosr;
@@ -186,62 +186,51 @@ struct aic31xx_rate_divs {
 
 /* ADC dividers can be disabled by cofiguring them to 0 */
 static const struct aic31xx_rate_divs aic31xx_divs[] = {
-       /* mclk      rate  pll: p  j     d     dosr ndac mdac  aors nadc madc */
+       /* mclk/p    rate  pll: j     d        dosr ndac mdac  aors nadc madc */
        /* 8k rate */
-       {12000000,   8000,      1, 8, 1920,     128,  48,  2,   128,  48,  2},
-       {12000000,   8000,      1, 8, 1920,     128,  32,  3,   128,  32,  3},
-       {24000000,   8000,      2, 8, 1920,     128,  48,  2,   128,  48,  2},
-       {25000000,   8000,      2, 7, 8643,     128,  48,  2,   128,  48,  2},
+       {12000000,   8000,      8, 1920,        128,  48,  2,   128,  48,  2},
+       {12000000,   8000,      8, 1920,        128,  32,  3,   128,  32,  3},
+       {12500000,   8000,      7, 8643,        128,  48,  2,   128,  48,  2},
        /* 11.025k rate */
-       {12000000,  11025,      1, 7, 5264,     128,  32,  2,   128,  32,  2},
-       {12000000,  11025,      1, 8, 4672,     128,  24,  3,   128,  24,  3},
-       {24000000,  11025,      2, 7, 5264,     128,  32,  2,   128,  32,  2},
-       {25000000,  11025,      2, 7, 2253,     128,  32,  2,   128,  32,  2},
+       {12000000,  11025,      7, 5264,        128,  32,  2,   128,  32,  2},
+       {12000000,  11025,      8, 4672,        128,  24,  3,   128,  24,  3},
+       {12500000,  11025,      7, 2253,        128,  32,  2,   128,  32,  2},
        /* 16k rate */
-       {12000000,  16000,      1, 8, 1920,     128,  24,  2,   128,  24,  2},
-       {12000000,  16000,      1, 8, 1920,     128,  16,  3,   128,  16,  3},
-       {24000000,  16000,      2, 8, 1920,     128,  24,  2,   128,  24,  2},
-       {25000000,  16000,      2, 7, 8643,     128,  24,  2,   128,  24,  2},
+       {12000000,  16000,      8, 1920,        128,  24,  2,   128,  24,  2},
+       {12000000,  16000,      8, 1920,        128,  16,  3,   128,  16,  3},
+       {12500000,  16000,      7, 8643,        128,  24,  2,   128,  24,  2},
        /* 22.05k rate */
-       {12000000,  22050,      1, 7, 5264,     128,  16,  2,   128,  16,  2},
-       {12000000,  22050,      1, 8, 4672,     128,  12,  3,   128,  12,  3},
-       {24000000,  22050,      2, 7, 5264,     128,  16,  2,   128,  16,  2},
-       {25000000,  22050,      2, 7, 2253,     128,  16,  2,   128,  16,  2},
+       {12000000,  22050,      7, 5264,        128,  16,  2,   128,  16,  2},
+       {12000000,  22050,      8, 4672,        128,  12,  3,   128,  12,  3},
+       {12500000,  22050,      7, 2253,        128,  16,  2,   128,  16,  2},
        /* 32k rate */
-       {12000000,  32000,      1, 8, 1920,     128,  12,  2,   128,  12,  2},
-       {12000000,  32000,      1, 8, 1920,     128,   8,  3,   128,   8,  3},
-       {24000000,  32000,      2, 8, 1920,     128,  12,  2,   128,  12,  2},
-       {25000000,  32000,      2, 7, 8643,     128,  12,  2,   128,  12,  2},
+       {12000000,  32000,      8, 1920,        128,  12,  2,   128,  12,  2},
+       {12000000,  32000,      8, 1920,        128,   8,  3,   128,   8,  3},
+       {12500000,  32000,      7, 8643,        128,  12,  2,   128,  12,  2},
        /* 44.1k rate */
-       {12000000,  44100,      1, 7, 5264,     128,   8,  2,   128,   8,  2},
-       {12000000,  44100,      1, 8, 4672,     128,   6,  3,   128,   6,  3},
-       {24000000,  44100,      2, 7, 5264,     128,   8,  2,   128,   8,  2},
-       {25000000,  44100,      2, 7, 2253,     128,   8,  2,   128,   8,  2},
+       {12000000,  44100,      7, 5264,        128,   8,  2,   128,   8,  2},
+       {12000000,  44100,      8, 4672,        128,   6,  3,   128,   6,  3},
+       {12500000,  44100,      7, 2253,        128,   8,  2,   128,   8,  2},
        /* 48k rate */
-       {12000000,  48000,      1, 8, 1920,     128,   8,  2,   128,   8,  2},
-       {12000000,  48000,      1, 7, 6800,      96,   5,  4,    96,   5,  4},
-       {24000000,  48000,      2, 8, 1920,     128,   8,  2,   128,   8,  2},
-       {25000000,  48000,      2, 7, 8643,     128,   8,  2,   128,   8,  2},
+       {12000000,  48000,      8, 1920,        128,   8,  2,   128,   8,  2},
+       {12000000,  48000,      7, 6800,         96,   5,  4,    96,   5,  4},
+       {12500000,  48000,      7, 8643,        128,   8,  2,   128,   8,  2},
        /* 88.2k rate */
-       {12000000,  88200,      1, 7, 5264,      64,   8,  2,    64,   8,  2},
-       {12000000,  88200,      1, 8, 4672,      64,   6,  3,    64,   6,  3},
-       {24000000,  88200,      2, 7, 5264,      64,   8,  2,    64,   8,  2},
-       {25000000,  88200,      2, 7, 2253,      64,   8,  2,    64,   8,  2},
+       {12000000,  88200,      7, 5264,         64,   8,  2,    64,   8,  2},
+       {12000000,  88200,      8, 4672,         64,   6,  3,    64,   6,  3},
+       {12500000,  88200,      7, 2253,         64,   8,  2,    64,   8,  2},
        /* 96k rate */
-       {12000000,  96000,      1, 8, 1920,      64,   8,  2,    64,   8,  2},
-       {12000000,  96000,      1, 7, 6800,      48,   5,  4,    48,   5,  4},
-       {24000000,  96000,      2, 8, 1920,      64,   8,  2,    64,   8,  2},
-       {25000000,  96000,      2, 7, 8643,      64,   8,  2,    64,   8,  2},
+       {12000000,  96000,      8, 1920,         64,   8,  2,    64,   8,  2},
+       {12000000,  96000,      7, 6800,         48,   5,  4,    48,   5,  4},
+       {12500000,  96000,      7, 8643,         64,   8,  2,    64,   8,  2},
        /* 176.4k rate */
-       {12000000, 176400,      1, 7, 5264,      32,   8,  2,    32,   8,  2},
-       {12000000, 176400,      1, 8, 4672,      32,   6,  3,    32,   6,  3},
-       {24000000, 176400,      2, 7, 5264,      32,   8,  2,    32,   8,  2},
-       {25000000, 176400,      2, 7, 2253,      32,   8,  2,    32,   8,  2},
+       {12000000, 176400,      7, 5264,         32,   8,  2,    32,   8,  2},
+       {12000000, 176400,      8, 4672,         32,   6,  3,    32,   6,  3},
+       {12500000, 176400,      7, 2253,         32,   8,  2,    32,   8,  2},
        /* 192k rate */
-       {12000000, 192000,      1, 8, 1920,      32,   8,  2,    32,   8,  2},
-       {12000000, 192000,      1, 7, 6800,      24,   5,  4,    24,   5,  4},
-       {24000000, 192000,      2, 8, 1920,      32,   8,  2,    32,   8,  2},
-       {25000000, 192000,      2, 7, 8643,      32,   8,  2,    32,   8,  2},
+       {12000000, 192000,      8, 1920,         32,   8,  2,    32,   8,  2},
+       {12000000, 192000,      7, 6800,         24,   5,  4,    24,   5,  4},
+       {12500000, 192000,      7, 8643,         32,   8,  2,    32,   8,  2},
 };
 
 static const char * const ldac_in_text[] = {
@@ -692,6 +681,7 @@ static int aic31xx_setup_pll(struct snd_soc_codec *codec,
 {
        struct aic31xx_priv *aic31xx = snd_soc_codec_get_drvdata(codec);
        int bclk_score = snd_soc_params_to_frame_size(params);
+       int mclk_p = aic31xx->sysclk / aic31xx->p_div;
        int bclk_n = 0;
        int match = -1;
        int i;
@@ -704,7 +694,7 @@ static int aic31xx_setup_pll(struct snd_soc_codec *codec,
 
        for (i = 0; i < ARRAY_SIZE(aic31xx_divs); i++) {
                if (aic31xx_divs[i].rate == params_rate(params) &&
-                   aic31xx_divs[i].mclk == aic31xx->sysclk) {
+                   aic31xx_divs[i].mclk_p == mclk_p) {
                        int s = (aic31xx_divs[i].dosr * aic31xx_divs[i].mdac) %
                                snd_soc_params_to_frame_size(params);
                        int bn = (aic31xx_divs[i].dosr * aic31xx_divs[i].mdac) /
@@ -738,7 +728,7 @@ static int aic31xx_setup_pll(struct snd_soc_codec *codec,
 
        /* PLL configuration */
        snd_soc_update_bits(codec, AIC31XX_PLLPR, AIC31XX_PLL_MASK,
-                           (aic31xx_divs[i].p_val << 4) | 0x01);
+                           (aic31xx->p_div << 4) | 0x01);
        snd_soc_write(codec, AIC31XX_PLLJ, aic31xx_divs[i].pll_j);
 
        snd_soc_write(codec, AIC31XX_PLLDMSB,
@@ -772,7 +762,7 @@ static int aic31xx_setup_pll(struct snd_soc_codec *codec,
        dev_dbg(codec->dev,
                "pll %d.%04d/%d dosr %d n %d m %d aosr %d n %d m %d bclk_n %d\n",
                aic31xx_divs[i].pll_j, aic31xx_divs[i].pll_d,
-               aic31xx_divs[i].p_val, aic31xx_divs[i].dosr,
+               aic31xx->p_div, aic31xx_divs[i].dosr,
                aic31xx_divs[i].ndac, aic31xx_divs[i].mdac,
                aic31xx_divs[i].aosr, aic31xx_divs[i].nadc,
                aic31xx_divs[i].madc, bclk_n);
@@ -840,7 +830,7 @@ static int aic31xx_set_dai_fmt(struct snd_soc_dai *codec_dai,
 {
        struct snd_soc_codec *codec = codec_dai->codec;
        u8 iface_reg1 = 0;
-       u8 iface_reg3 = 0;
+       u8 iface_reg2 = 0;
        u8 dsp_a_val = 0;
 
        dev_dbg(codec->dev, "## %s: fmt = 0x%x\n", __func__, fmt);
@@ -865,7 +855,7 @@ static int aic31xx_set_dai_fmt(struct snd_soc_dai *codec_dai,
                /* NOTE: BCLKINV bit value 1 equas NB and 0 equals IB */
                switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
                case SND_SOC_DAIFMT_NB_NF:
-                       iface_reg3 |= AIC31XX_BCLKINV_MASK;
+                       iface_reg2 |= AIC31XX_BCLKINV_MASK;
                        break;
                case SND_SOC_DAIFMT_IB_NF:
                        break;
@@ -897,7 +887,7 @@ static int aic31xx_set_dai_fmt(struct snd_soc_dai *codec_dai,
                            dsp_a_val);
        snd_soc_update_bits(codec, AIC31XX_IFACE2,
                            AIC31XX_BCLKINV_MASK,
-                           iface_reg3);
+                           iface_reg2);
 
        return 0;
 }
@@ -912,7 +902,16 @@ static int aic31xx_set_dai_sysclk(struct snd_soc_dai *codec_dai,
        dev_dbg(codec->dev, "## %s: clk_id = %d, freq = %d, dir = %d\n",
                __func__, clk_id, freq, dir);
 
-       for (i = 0; aic31xx_divs[i].mclk != freq; i++) {
+       for (i = 1; freq/i > 20000000 && i < 8; i++)
+               ;
+       if (freq/i > 20000000) {
+               dev_err(aic31xx->dev, "%s: Too high mclk frequency %u\n",
+                       __func__, freq);
+                       return -EINVAL;
+       }
+       aic31xx->p_div = i;
+
+       for (i = 0; aic31xx_divs[i].mclk_p != freq/aic31xx->p_div; i++) {
                if (i == ARRAY_SIZE(aic31xx_divs)) {
                        dev_err(aic31xx->dev, "%s: Unsupported frequency %d\n",
                                __func__, freq);
index 52ed57c69dfa031b10a37d57c38dd3928c7d088c..fe16c34607bb143fd28f8469c38bd27e17d0f489 100644 (file)
@@ -18,7 +18,8 @@
 #define AIC31XX_RATES  SNDRV_PCM_RATE_8000_192000
 
 #define AIC31XX_FORMATS        (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE \
-                        | SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S32_LE)
+                        | SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S24_LE \
+                        | SNDRV_PCM_FMTBIT_S32_LE)
 
 
 #define AIC31XX_STEREO_CLASS_D_BIT     0x1
index 64f179ee98345f841319599c255188e14fc37767..f7c2a575a892a2c89f196409207d2db7a48f652d 100644 (file)
@@ -1121,6 +1121,7 @@ static int aic3x_regulator_event(struct notifier_block *nb,
 static int aic3x_set_power(struct snd_soc_codec *codec, int power)
 {
        struct aic3x_priv *aic3x = snd_soc_codec_get_drvdata(codec);
+       unsigned int pll_c, pll_d;
        int ret;
 
        if (power) {
@@ -1138,6 +1139,18 @@ static int aic3x_set_power(struct snd_soc_codec *codec, int power)
                /* Sync reg_cache with the hardware */
                regcache_cache_only(aic3x->regmap, false);
                regcache_sync(aic3x->regmap);
+
+               /* Rewrite paired PLL D registers in case cached sync skipped
+                * writing one of them and thus caused other one also not
+                * being written
+                */
+               pll_c = snd_soc_read(codec, AIC3X_PLL_PROGC_REG);
+               pll_d = snd_soc_read(codec, AIC3X_PLL_PROGD_REG);
+               if (pll_c == aic3x_reg[AIC3X_PLL_PROGC_REG].def ||
+                       pll_d == aic3x_reg[AIC3X_PLL_PROGD_REG].def) {
+                       snd_soc_write(codec, AIC3X_PLL_PROGC_REG, pll_c);
+                       snd_soc_write(codec, AIC3X_PLL_PROGD_REG, pll_d);
+               }
        } else {
                /*
                 * Do soft reset to this codec instance in order to clear
@@ -1222,20 +1235,6 @@ static struct snd_soc_dai_driver aic3x_dai = {
        .symmetric_rates = 1,
 };
 
-static int aic3x_suspend(struct snd_soc_codec *codec)
-{
-       aic3x_set_bias_level(codec, SND_SOC_BIAS_OFF);
-
-       return 0;
-}
-
-static int aic3x_resume(struct snd_soc_codec *codec)
-{
-       aic3x_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
-
-       return 0;
-}
-
 static void aic3x_mono_init(struct snd_soc_codec *codec)
 {
        /* DAC to Mono Line Out default volume and route to Output mixer */
@@ -1429,8 +1428,6 @@ static struct snd_soc_codec_driver soc_codec_dev_aic3x = {
        .idle_bias_off = true,
        .probe = aic3x_probe,
        .remove = aic3x_remove,
-       .suspend = aic3x_suspend,
-       .resume = aic3x_resume,
        .controls = aic3x_snd_controls,
        .num_controls = ARRAY_SIZE(aic3x_snd_controls),
        .dapm_widgets = aic3x_dapm_widgets,
index 3dfdcc4197fa96cce56a13e50291b9075e44d4a9..628ec774cf2296c56c7851fe773cacca3568b53f 100644 (file)
@@ -212,7 +212,7 @@ static void wm8350_pga_work(struct work_struct *work)
 {
        struct snd_soc_dapm_context *dapm =
            container_of(work, struct snd_soc_dapm_context, delayed_work.work);
-       struct snd_soc_codec *codec = dapm->codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(dapm);
        struct wm8350_data *wm8350_data = snd_soc_codec_get_drvdata(codec);
        struct wm8350_output *out1 = &wm8350_data->out1,
            *out2 = &wm8350_data->out2;
index a237f1627f614d07a40c61f50d7a561e7a87b17f..31bb4801a00564158fd695dd7aa3438d916c6b97 100644 (file)
@@ -413,7 +413,6 @@ static int wm8741_resume(struct snd_soc_codec *codec)
        return 0;
 }
 #else
-#define wm8741_suspend NULL
 #define wm8741_resume NULL
 #endif
 
index e54e097f4fcbb738870a6c51e9c0970f21e18ade..21ca3a94fc96eadabbc42cfcfdbf8b7eeefb5472 100644 (file)
@@ -1433,7 +1433,7 @@ static void wm8753_work(struct work_struct *work)
        struct snd_soc_dapm_context *dapm =
                container_of(work, struct snd_soc_dapm_context,
                             delayed_work.work);
-       struct snd_soc_codec *codec = dapm->codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(dapm);
        wm8753_set_bias_level(codec, dapm->bias_level);
 }
 
index 0ea01dfcb6e166a2e9e51e2fbb9cec9f4e4edcd1..3addc5fe5cb23883001d3a28662f94cf59e92fa2 100644 (file)
@@ -518,23 +518,6 @@ static int wm8804_set_bias_level(struct snd_soc_codec *codec,
        return 0;
 }
 
-#ifdef CONFIG_PM
-static int wm8804_suspend(struct snd_soc_codec *codec)
-{
-       wm8804_set_bias_level(codec, SND_SOC_BIAS_OFF);
-       return 0;
-}
-
-static int wm8804_resume(struct snd_soc_codec *codec)
-{
-       wm8804_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
-       return 0;
-}
-#else
-#define wm8804_suspend NULL
-#define wm8804_resume NULL
-#endif
-
 static int wm8804_remove(struct snd_soc_codec *codec)
 {
        struct wm8804_priv *wm8804;
@@ -671,8 +654,6 @@ static struct snd_soc_dai_driver wm8804_dai = {
 static struct snd_soc_codec_driver soc_codec_dev_wm8804 = {
        .probe = wm8804_probe,
        .remove = wm8804_remove,
-       .suspend = wm8804_suspend,
-       .resume = wm8804_resume,
        .set_bias_level = wm8804_set_bias_level,
        .idle_bias_off = true,
 
index 0499cd4cfb71266e478fa5269abe8469b42e5d01..39ddb9b8834ccbf19a996605019eb8e74b4dddcf 100644 (file)
@@ -615,7 +615,7 @@ static void wm8971_work(struct work_struct *work)
        struct snd_soc_dapm_context *dapm =
                container_of(work, struct snd_soc_dapm_context,
                             delayed_work.work);
-       struct snd_soc_codec *codec = dapm->codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(dapm);
        wm8971_set_bias_level(codec, codec->dapm.bias_level);
 }
 
index 6cc0566dc29a42653c96b571f07c0a02397cbb7e..1fcb9f3f309762d2793b59ccd094b26a55f84111 100644 (file)
@@ -4082,17 +4082,23 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec)
 
        switch (control->type) {
        case WM8994:
-               if (wm8994->micdet_irq) {
+               if (wm8994->micdet_irq)
                        ret = request_threaded_irq(wm8994->micdet_irq, NULL,
                                                   wm8994_mic_irq,
                                                   IRQF_TRIGGER_RISING,
                                                   "Mic1 detect",
                                                   wm8994);
-                       if (ret != 0)
-                               dev_warn(codec->dev,
-                                        "Failed to request Mic1 detect IRQ: %d\n",
-                                        ret);
-               }
+                else
+                       ret = wm8994_request_irq(wm8994->wm8994,
+                                       WM8994_IRQ_MIC1_DET,
+                                       wm8994_mic_irq, "Mic 1 detect",
+                                       wm8994);
+
+               if (ret != 0)
+                       dev_warn(codec->dev,
+                                "Failed to request Mic1 detect IRQ: %d\n",
+                                ret);
+
 
                ret = wm8994_request_irq(wm8994->wm8994,
                                         WM8994_IRQ_MIC1_SHRT,
index cae4ac5a573061614007f211ec523d96779e5b9d..1288edeb8c7dea9530620345028fc990ac55cb6c 100644 (file)
@@ -1998,23 +1998,6 @@ static int wm8995_set_bias_level(struct snd_soc_codec *codec,
        return 0;
 }
 
-#ifdef CONFIG_PM
-static int wm8995_suspend(struct snd_soc_codec *codec)
-{
-       wm8995_set_bias_level(codec, SND_SOC_BIAS_OFF);
-       return 0;
-}
-
-static int wm8995_resume(struct snd_soc_codec *codec)
-{
-       wm8995_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
-       return 0;
-}
-#else
-#define wm8995_suspend NULL
-#define wm8995_resume NULL
-#endif
-
 static int wm8995_remove(struct snd_soc_codec *codec)
 {
        struct wm8995_priv *wm8995;
@@ -2220,8 +2203,6 @@ static struct snd_soc_dai_driver wm8995_dai[] = {
 static struct snd_soc_codec_driver soc_codec_dev_wm8995 = {
        .probe = wm8995_probe,
        .remove = wm8995_remove,
-       .suspend = wm8995_suspend,
-       .resume = wm8995_resume,
        .set_bias_level = wm8995_set_bias_level,
        .idle_bias_off = true,
 };
index d69510c53239575bc1b5bad24557f415fcd3d538..8e948c63f3d96ec6dab93a2891d41f6eee0912da 100644 (file)
@@ -63,7 +63,8 @@ config SND_DM365_AIC3X_CODEC
          Say Y if you want to add support for AIC3101 audio codec
 
 config SND_DM365_VOICE_CODEC
-       bool "Voice Codec - CQ93VC"
+       tristate "Voice Codec - CQ93VC"
+       depends on SND_DAVINCI_SOC
        select MFD_DAVINCI_VOICECODEC
        select SND_DAVINCI_SOC_VCIF
        select SND_SOC_CQ0093VC
index 68347b55f6e17ecd2aa900c875d22c45e4ab0bbe..0eed9b1b24e1a5410eb4ddcc90908e919f559f65 100644 (file)
 
 #define MCASP_MAX_AFIFO_DEPTH  64
 
+static u32 context_regs[] = {
+       DAVINCI_MCASP_TXFMCTL_REG,
+       DAVINCI_MCASP_RXFMCTL_REG,
+       DAVINCI_MCASP_TXFMT_REG,
+       DAVINCI_MCASP_RXFMT_REG,
+       DAVINCI_MCASP_ACLKXCTL_REG,
+       DAVINCI_MCASP_ACLKRCTL_REG,
+       DAVINCI_MCASP_AHCLKXCTL_REG,
+       DAVINCI_MCASP_AHCLKRCTL_REG,
+       DAVINCI_MCASP_PDIR_REG,
+       DAVINCI_MCASP_RXMASK_REG,
+       DAVINCI_MCASP_TXMASK_REG,
+       DAVINCI_MCASP_RXTDM_REG,
+       DAVINCI_MCASP_TXTDM_REG,
+};
+
 struct davinci_mcasp_context {
-       u32     txfmtctl;
-       u32     rxfmtctl;
-       u32     txfmt;
-       u32     rxfmt;
-       u32     aclkxctl;
-       u32     aclkrctl;
-       u32     pdir;
+       u32     config_regs[ARRAY_SIZE(context_regs)];
+       u32     afifo_regs[2]; /* for read/write fifo control registers */
+       u32     *xrsr_regs; /* for serializer configuration */
 };
 
 struct davinci_mcasp {
@@ -874,14 +886,24 @@ static int davinci_mcasp_suspend(struct snd_soc_dai *dai)
 {
        struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(dai);
        struct davinci_mcasp_context *context = &mcasp->context;
+       u32 reg;
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(context_regs); i++)
+               context->config_regs[i] = mcasp_get_reg(mcasp, context_regs[i]);
+
+       if (mcasp->txnumevt) {
+               reg = mcasp->fifo_base + MCASP_WFIFOCTL_OFFSET;
+               context->afifo_regs[0] = mcasp_get_reg(mcasp, reg);
+       }
+       if (mcasp->rxnumevt) {
+               reg = mcasp->fifo_base + MCASP_RFIFOCTL_OFFSET;
+               context->afifo_regs[1] = mcasp_get_reg(mcasp, reg);
+       }
 
-       context->txfmtctl = mcasp_get_reg(mcasp, DAVINCI_MCASP_TXFMCTL_REG);
-       context->rxfmtctl = mcasp_get_reg(mcasp, DAVINCI_MCASP_RXFMCTL_REG);
-       context->txfmt = mcasp_get_reg(mcasp, DAVINCI_MCASP_TXFMT_REG);
-       context->rxfmt = mcasp_get_reg(mcasp, DAVINCI_MCASP_RXFMT_REG);
-       context->aclkxctl = mcasp_get_reg(mcasp, DAVINCI_MCASP_ACLKXCTL_REG);
-       context->aclkrctl = mcasp_get_reg(mcasp, DAVINCI_MCASP_ACLKRCTL_REG);
-       context->pdir = mcasp_get_reg(mcasp, DAVINCI_MCASP_PDIR_REG);
+       for (i = 0; i < mcasp->num_serializer; i++)
+               context->xrsr_regs[i] = mcasp_get_reg(mcasp,
+                                               DAVINCI_MCASP_XRSRCTL_REG(i));
 
        return 0;
 }
@@ -890,14 +912,24 @@ static int davinci_mcasp_resume(struct snd_soc_dai *dai)
 {
        struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(dai);
        struct davinci_mcasp_context *context = &mcasp->context;
+       u32 reg;
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(context_regs); i++)
+               mcasp_set_reg(mcasp, context_regs[i], context->config_regs[i]);
+
+       if (mcasp->txnumevt) {
+               reg = mcasp->fifo_base + MCASP_WFIFOCTL_OFFSET;
+               mcasp_set_reg(mcasp, reg, context->afifo_regs[0]);
+       }
+       if (mcasp->rxnumevt) {
+               reg = mcasp->fifo_base + MCASP_RFIFOCTL_OFFSET;
+               mcasp_set_reg(mcasp, reg, context->afifo_regs[1]);
+       }
 
-       mcasp_set_reg(mcasp, DAVINCI_MCASP_TXFMCTL_REG, context->txfmtctl);
-       mcasp_set_reg(mcasp, DAVINCI_MCASP_RXFMCTL_REG, context->rxfmtctl);
-       mcasp_set_reg(mcasp, DAVINCI_MCASP_TXFMT_REG, context->txfmt);
-       mcasp_set_reg(mcasp, DAVINCI_MCASP_RXFMT_REG, context->rxfmt);
-       mcasp_set_reg(mcasp, DAVINCI_MCASP_ACLKXCTL_REG, context->aclkxctl);
-       mcasp_set_reg(mcasp, DAVINCI_MCASP_ACLKRCTL_REG, context->aclkrctl);
-       mcasp_set_reg(mcasp, DAVINCI_MCASP_PDIR_REG, context->pdir);
+       for (i = 0; i < mcasp->num_serializer; i++)
+               mcasp_set_reg(mcasp, DAVINCI_MCASP_XRSRCTL_REG(i),
+                             context->xrsr_regs[i]);
 
        return 0;
 }
@@ -1216,6 +1248,11 @@ static int davinci_mcasp_probe(struct platform_device *pdev)
        mcasp->op_mode = pdata->op_mode;
        mcasp->tdm_slots = pdata->tdm_slots;
        mcasp->num_serializer = pdata->num_serializer;
+#ifdef CONFIG_PM_SLEEP
+       mcasp->context.xrsr_regs = devm_kzalloc(&pdev->dev,
+                                       sizeof(u32) * mcasp->num_serializer,
+                                       GFP_KERNEL);
+#endif
        mcasp->serial_dir = pdata->serial_dir;
        mcasp->version = pdata->version;
        mcasp->txnumevt = pdata->txnumevt;
index 605e643133db3ebe695a8cb16fdb16c8ed7ddd7e..59e588abe54b629d986d3951e64e4ccb61eabdb4 100644 (file)
@@ -25,6 +25,8 @@
 #include <sound/dmaengine_pcm.h>
 #include <linux/edma.h>
 
+#include "edma-pcm.h"
+
 static const struct snd_pcm_hardware edma_pcm_hardware = {
        .info                   = SNDRV_PCM_INFO_MMAP |
                                  SNDRV_PCM_INFO_MMAP_VALID |
index f3012b645b51fcfdcdbc5c2e60b8f1d5db11724f..081e406b3713aae2509206e9a779325eb7ec263e 100644 (file)
@@ -240,6 +240,18 @@ config SND_SOC_IMX_WM8962
          Say Y if you want to add support for SoC audio on an i.MX board with
          a wm8962 codec.
 
+config SND_SOC_IMX_ES8328
+       tristate "SoC Audio support for i.MX boards with the ES8328 codec"
+       depends on OF && (I2C || SPI)
+       select SND_SOC_ES8328_I2C if I2C
+       select SND_SOC_ES8328_SPI if SPI_MASTER
+       select SND_SOC_IMX_PCM_DMA
+       select SND_SOC_IMX_AUDMUX
+       select SND_SOC_FSL_SSI
+       help
+         Say Y if you want to add support for the ES8328 audio codec connected
+         via SSI/I2S over either SPI or I2C.
+
 config SND_SOC_IMX_SGTL5000
        tristate "SoC Audio support for i.MX boards with sgtl5000"
        depends on OF && I2C
@@ -268,6 +280,20 @@ config SND_SOC_IMX_MC13783
        select SND_SOC_MC13783
        select SND_SOC_IMX_PCM_DMA
 
+config SND_SOC_FSL_ASOC_CARD
+       tristate "Generic ASoC Sound Card with ASRC support"
+       depends on OF && I2C
+       select SND_SOC_IMX_AUDMUX
+       select SND_SOC_IMX_PCM_DMA
+       select SND_SOC_FSL_ESAI
+       select SND_SOC_FSL_SAI
+       select SND_SOC_FSL_SSI
+       help
+        ALSA SoC Audio support with ASRC feature for Freescale SoCs that have
+        ESAI/SAI/SSI and connect with external CODECs such as WM8962, CS42888
+        and SGTL5000.
+        Say Y if you want to add support for Freescale Generic ASoC Sound Card.
+
 endif # SND_IMX_SOC
 
 endmenu
index 9ff59267eac9d1b822f1a50f514c30d09c62a12a..d28dc25c9375fd813e0f14d2c48a5d4d0e08576c 100644 (file)
@@ -11,6 +11,7 @@ snd-soc-p1022-rdk-objs := p1022_rdk.o
 obj-$(CONFIG_SND_SOC_P1022_RDK) += snd-soc-p1022-rdk.o
 
 # Freescale SSI/DMA/SAI/SPDIF Support
+snd-soc-fsl-asoc-card-objs := fsl-asoc-card.o
 snd-soc-fsl-asrc-objs := fsl_asrc.o fsl_asrc_dma.o
 snd-soc-fsl-sai-objs := fsl_sai.o
 snd-soc-fsl-ssi-y := fsl_ssi.o
@@ -19,6 +20,7 @@ snd-soc-fsl-spdif-objs := fsl_spdif.o
 snd-soc-fsl-esai-objs := fsl_esai.o
 snd-soc-fsl-utils-objs := fsl_utils.o
 snd-soc-fsl-dma-objs := fsl_dma.o
+obj-$(CONFIG_SND_SOC_FSL_ASOC_CARD) += snd-soc-fsl-asoc-card.o
 obj-$(CONFIG_SND_SOC_FSL_ASRC) += snd-soc-fsl-asrc.o
 obj-$(CONFIG_SND_SOC_FSL_SAI) += snd-soc-fsl-sai.o
 obj-$(CONFIG_SND_SOC_FSL_SSI) += snd-soc-fsl-ssi.o
@@ -50,6 +52,7 @@ snd-soc-eukrea-tlv320-objs := eukrea-tlv320.o
 snd-soc-phycore-ac97-objs := phycore-ac97.o
 snd-soc-mx27vis-aic32x4-objs := mx27vis-aic32x4.o
 snd-soc-wm1133-ev1-objs := wm1133-ev1.o
+snd-soc-imx-es8328-objs := imx-es8328.o
 snd-soc-imx-sgtl5000-objs := imx-sgtl5000.o
 snd-soc-imx-wm8962-objs := imx-wm8962.o
 snd-soc-imx-spdif-objs := imx-spdif.o
@@ -59,6 +62,7 @@ obj-$(CONFIG_SND_SOC_EUKREA_TLV320) += snd-soc-eukrea-tlv320.o
 obj-$(CONFIG_SND_SOC_PHYCORE_AC97) += snd-soc-phycore-ac97.o
 obj-$(CONFIG_SND_SOC_MX27VIS_AIC32X4) += snd-soc-mx27vis-aic32x4.o
 obj-$(CONFIG_SND_MXC_SOC_WM1133_EV1) += snd-soc-wm1133-ev1.o
+obj-$(CONFIG_SND_SOC_IMX_ES8328) += snd-soc-imx-es8328.o
 obj-$(CONFIG_SND_SOC_IMX_SGTL5000) += snd-soc-imx-sgtl5000.o
 obj-$(CONFIG_SND_SOC_IMX_WM8962) += snd-soc-imx-wm8962.o
 obj-$(CONFIG_SND_SOC_IMX_SPDIF) += snd-soc-imx-spdif.o
diff --git a/sound/soc/fsl/fsl-asoc-card.c b/sound/soc/fsl/fsl-asoc-card.c
new file mode 100644 (file)
index 0000000..007c772
--- /dev/null
@@ -0,0 +1,574 @@
+/*
+ * Freescale Generic ASoC Sound Card driver with ASRC
+ *
+ * Copyright (C) 2014 Freescale Semiconductor, Inc.
+ *
+ * Author: Nicolin Chen <nicoleotsuka@gmail.com>
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+
+#include <linux/clk.h>
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/of_platform.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+
+#include "fsl_esai.h"
+#include "fsl_sai.h"
+#include "imx-audmux.h"
+
+#include "../codecs/sgtl5000.h"
+#include "../codecs/wm8962.h"
+
+#define RX 0
+#define TX 1
+
+/* Default DAI format without Master and Slave flag */
+#define DAI_FMT_BASE (SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF)
+
+/**
+ * CODEC private data
+ *
+ * @mclk_freq: Clock rate of MCLK
+ * @mclk_id: MCLK (or main clock) id for set_sysclk()
+ * @fll_id: FLL (or secordary clock) id for set_sysclk()
+ * @pll_id: PLL id for set_pll()
+ */
+struct codec_priv {
+       unsigned long mclk_freq;
+       u32 mclk_id;
+       u32 fll_id;
+       u32 pll_id;
+};
+
+/**
+ * CPU private data
+ *
+ * @sysclk_freq[2]: SYSCLK rates for set_sysclk()
+ * @sysclk_dir[2]: SYSCLK directions for set_sysclk()
+ * @sysclk_id[2]: SYSCLK ids for set_sysclk()
+ *
+ * Note: [1] for tx and [0] for rx
+ */
+struct cpu_priv {
+       unsigned long sysclk_freq[2];
+       u32 sysclk_dir[2];
+       u32 sysclk_id[2];
+};
+
+/**
+ * Freescale Generic ASOC card private data
+ *
+ * @dai_link[3]: DAI link structure including normal one and DPCM link
+ * @pdev: platform device pointer
+ * @codec_priv: CODEC private data
+ * @cpu_priv: CPU private data
+ * @card: ASoC card structure
+ * @sample_rate: Current sample rate
+ * @sample_format: Current sample format
+ * @asrc_rate: ASRC sample rate used by Back-Ends
+ * @asrc_format: ASRC sample format used by Back-Ends
+ * @dai_fmt: DAI format between CPU and CODEC
+ * @name: Card name
+ */
+
+struct fsl_asoc_card_priv {
+       struct snd_soc_dai_link dai_link[3];
+       struct platform_device *pdev;
+       struct codec_priv codec_priv;
+       struct cpu_priv cpu_priv;
+       struct snd_soc_card card;
+       u32 sample_rate;
+       u32 sample_format;
+       u32 asrc_rate;
+       u32 asrc_format;
+       u32 dai_fmt;
+       char name[32];
+};
+
+/**
+ * This dapm route map exsits for DPCM link only.
+ * The other routes shall go through Device Tree.
+ */
+static const struct snd_soc_dapm_route audio_map[] = {
+       {"CPU-Playback",  NULL, "ASRC-Playback"},
+       {"Playback",  NULL, "CPU-Playback"},
+       {"ASRC-Capture",  NULL, "CPU-Capture"},
+       {"CPU-Capture",  NULL, "Capture"},
+};
+
+/* Add all possible widgets into here without being redundant */
+static const struct snd_soc_dapm_widget fsl_asoc_card_dapm_widgets[] = {
+       SND_SOC_DAPM_LINE("Line Out Jack", NULL),
+       SND_SOC_DAPM_LINE("Line In Jack", NULL),
+       SND_SOC_DAPM_HP("Headphone Jack", NULL),
+       SND_SOC_DAPM_SPK("Ext Spk", NULL),
+       SND_SOC_DAPM_MIC("Mic Jack", NULL),
+       SND_SOC_DAPM_MIC("AMIC", NULL),
+       SND_SOC_DAPM_MIC("DMIC", NULL),
+};
+
+static int fsl_asoc_card_hw_params(struct snd_pcm_substream *substream,
+                                  struct snd_pcm_hw_params *params)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct fsl_asoc_card_priv *priv = snd_soc_card_get_drvdata(rtd->card);
+       bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
+       struct cpu_priv *cpu_priv = &priv->cpu_priv;
+       struct device *dev = rtd->card->dev;
+       int ret;
+
+       priv->sample_rate = params_rate(params);
+       priv->sample_format = params_format(params);
+
+       if (priv->card.set_bias_level)
+               return 0;
+
+       /* Specific configurations of DAIs starts from here */
+       ret = snd_soc_dai_set_sysclk(rtd->cpu_dai, cpu_priv->sysclk_id[tx],
+                                    cpu_priv->sysclk_freq[tx],
+                                    cpu_priv->sysclk_dir[tx]);
+       if (ret) {
+               dev_err(dev, "failed to set sysclk for cpu dai\n");
+               return ret;
+       }
+
+       return 0;
+}
+
+static struct snd_soc_ops fsl_asoc_card_ops = {
+       .hw_params = fsl_asoc_card_hw_params,
+};
+
+static int be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
+                             struct snd_pcm_hw_params *params)
+{
+       struct fsl_asoc_card_priv *priv = snd_soc_card_get_drvdata(rtd->card);
+       struct snd_interval *rate;
+       struct snd_mask *mask;
+
+       rate = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
+       rate->max = rate->min = priv->asrc_rate;
+
+       mask = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
+       snd_mask_none(mask);
+       snd_mask_set(mask, priv->asrc_format);
+
+       return 0;
+}
+
+static struct snd_soc_dai_link fsl_asoc_card_dai[] = {
+       /* Default ASoC DAI Link*/
+       {
+               .name = "HiFi",
+               .stream_name = "HiFi",
+               .ops = &fsl_asoc_card_ops,
+       },
+       /* DPCM Link between Front-End and Back-End (Optional) */
+       {
+               .name = "HiFi-ASRC-FE",
+               .stream_name = "HiFi-ASRC-FE",
+               .codec_name = "snd-soc-dummy",
+               .codec_dai_name = "snd-soc-dummy-dai",
+               .dpcm_playback = 1,
+               .dpcm_capture = 1,
+               .dynamic = 1,
+       },
+       {
+               .name = "HiFi-ASRC-BE",
+               .stream_name = "HiFi-ASRC-BE",
+               .platform_name = "snd-soc-dummy",
+               .be_hw_params_fixup = be_hw_params_fixup,
+               .ops = &fsl_asoc_card_ops,
+               .dpcm_playback = 1,
+               .dpcm_capture = 1,
+               .no_pcm = 1,
+       },
+};
+
+static int fsl_asoc_card_set_bias_level(struct snd_soc_card *card,
+                                       struct snd_soc_dapm_context *dapm,
+                                       enum snd_soc_bias_level level)
+{
+       struct fsl_asoc_card_priv *priv = snd_soc_card_get_drvdata(card);
+       struct snd_soc_dai *codec_dai = card->rtd[0].codec_dai;
+       struct codec_priv *codec_priv = &priv->codec_priv;
+       struct device *dev = card->dev;
+       unsigned int pll_out;
+       int ret;
+
+       if (dapm->dev != codec_dai->dev)
+               return 0;
+
+       switch (level) {
+       case SND_SOC_BIAS_PREPARE:
+               if (dapm->bias_level != SND_SOC_BIAS_STANDBY)
+                       break;
+
+               if (priv->sample_format == SNDRV_PCM_FORMAT_S24_LE)
+                       pll_out = priv->sample_rate * 384;
+               else
+                       pll_out = priv->sample_rate * 256;
+
+               ret = snd_soc_dai_set_pll(codec_dai, codec_priv->pll_id,
+                                         codec_priv->mclk_id,
+                                         codec_priv->mclk_freq, pll_out);
+               if (ret) {
+                       dev_err(dev, "failed to start FLL: %d\n", ret);
+                       return ret;
+               }
+
+               ret = snd_soc_dai_set_sysclk(codec_dai, codec_priv->fll_id,
+                                            pll_out, SND_SOC_CLOCK_IN);
+               if (ret) {
+                       dev_err(dev, "failed to set SYSCLK: %d\n", ret);
+                       return ret;
+               }
+               break;
+
+       case SND_SOC_BIAS_STANDBY:
+               if (dapm->bias_level != SND_SOC_BIAS_PREPARE)
+                       break;
+
+               ret = snd_soc_dai_set_sysclk(codec_dai, codec_priv->mclk_id,
+                                            codec_priv->mclk_freq,
+                                            SND_SOC_CLOCK_IN);
+               if (ret) {
+                       dev_err(dev, "failed to switch away from FLL: %d\n", ret);
+                       return ret;
+               }
+
+               ret = snd_soc_dai_set_pll(codec_dai, codec_priv->pll_id, 0, 0, 0);
+               if (ret) {
+                       dev_err(dev, "failed to stop FLL: %d\n", ret);
+                       return ret;
+               }
+               break;
+
+       default:
+               break;
+       }
+
+       return 0;
+}
+
+static int fsl_asoc_card_audmux_init(struct device_node *np,
+                                    struct fsl_asoc_card_priv *priv)
+{
+       struct device *dev = &priv->pdev->dev;
+       u32 int_ptcr = 0, ext_ptcr = 0;
+       int int_port, ext_port;
+       int ret;
+
+       ret = of_property_read_u32(np, "mux-int-port", &int_port);
+       if (ret) {
+               dev_err(dev, "mux-int-port missing or invalid\n");
+               return ret;
+       }
+       ret = of_property_read_u32(np, "mux-ext-port", &ext_port);
+       if (ret) {
+               dev_err(dev, "mux-ext-port missing or invalid\n");
+               return ret;
+       }
+
+       /*
+        * The port numbering in the hardware manual starts at 1, while
+        * the AUDMUX API expects it starts at 0.
+        */
+       int_port--;
+       ext_port--;
+
+       /*
+        * Use asynchronous mode (6 wires) for all cases.
+        * If only 4 wires are needed, just set SSI into
+        * synchronous mode and enable 4 PADs in IOMUX.
+        */
+       switch (priv->dai_fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+       case SND_SOC_DAIFMT_CBM_CFM:
+               int_ptcr = IMX_AUDMUX_V2_PTCR_RFSEL(8 | ext_port) |
+                          IMX_AUDMUX_V2_PTCR_RCSEL(8 | ext_port) |
+                          IMX_AUDMUX_V2_PTCR_TFSEL(ext_port) |
+                          IMX_AUDMUX_V2_PTCR_TCSEL(ext_port) |
+                          IMX_AUDMUX_V2_PTCR_RFSDIR |
+                          IMX_AUDMUX_V2_PTCR_RCLKDIR |
+                          IMX_AUDMUX_V2_PTCR_TFSDIR |
+                          IMX_AUDMUX_V2_PTCR_TCLKDIR;
+               break;
+       case SND_SOC_DAIFMT_CBM_CFS:
+               int_ptcr = IMX_AUDMUX_V2_PTCR_RCSEL(8 | ext_port) |
+                          IMX_AUDMUX_V2_PTCR_TCSEL(ext_port) |
+                          IMX_AUDMUX_V2_PTCR_RCLKDIR |
+                          IMX_AUDMUX_V2_PTCR_TCLKDIR;
+               ext_ptcr = IMX_AUDMUX_V2_PTCR_RFSEL(8 | int_port) |
+                          IMX_AUDMUX_V2_PTCR_TFSEL(int_port) |
+                          IMX_AUDMUX_V2_PTCR_RFSDIR |
+                          IMX_AUDMUX_V2_PTCR_TFSDIR;
+               break;
+       case SND_SOC_DAIFMT_CBS_CFM:
+               int_ptcr = IMX_AUDMUX_V2_PTCR_RFSEL(8 | ext_port) |
+                          IMX_AUDMUX_V2_PTCR_TFSEL(ext_port) |
+                          IMX_AUDMUX_V2_PTCR_RFSDIR |
+                          IMX_AUDMUX_V2_PTCR_TFSDIR;
+               ext_ptcr = IMX_AUDMUX_V2_PTCR_RCSEL(8 | int_port) |
+                          IMX_AUDMUX_V2_PTCR_TCSEL(int_port) |
+                          IMX_AUDMUX_V2_PTCR_RCLKDIR |
+                          IMX_AUDMUX_V2_PTCR_TCLKDIR;
+               break;
+       case SND_SOC_DAIFMT_CBS_CFS:
+               ext_ptcr = IMX_AUDMUX_V2_PTCR_RFSEL(8 | int_port) |
+                          IMX_AUDMUX_V2_PTCR_RCSEL(8 | int_port) |
+                          IMX_AUDMUX_V2_PTCR_TFSEL(int_port) |
+                          IMX_AUDMUX_V2_PTCR_TCSEL(int_port) |
+                          IMX_AUDMUX_V2_PTCR_RFSDIR |
+                          IMX_AUDMUX_V2_PTCR_RCLKDIR |
+                          IMX_AUDMUX_V2_PTCR_TFSDIR |
+                          IMX_AUDMUX_V2_PTCR_TCLKDIR;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       /* Asynchronous mode can not be set along with RCLKDIR */
+       ret = imx_audmux_v2_configure_port(int_port, 0,
+                                          IMX_AUDMUX_V2_PDCR_RXDSEL(ext_port));
+       if (ret) {
+               dev_err(dev, "audmux internal port setup failed\n");
+               return ret;
+       }
+
+       ret = imx_audmux_v2_configure_port(int_port, int_ptcr,
+                                          IMX_AUDMUX_V2_PDCR_RXDSEL(ext_port));
+       if (ret) {
+               dev_err(dev, "audmux internal port setup failed\n");
+               return ret;
+       }
+
+       ret = imx_audmux_v2_configure_port(ext_port, 0,
+                                          IMX_AUDMUX_V2_PDCR_RXDSEL(int_port));
+       if (ret) {
+               dev_err(dev, "audmux external port setup failed\n");
+               return ret;
+       }
+
+       ret = imx_audmux_v2_configure_port(ext_port, ext_ptcr,
+                                          IMX_AUDMUX_V2_PDCR_RXDSEL(int_port));
+       if (ret) {
+               dev_err(dev, "audmux external port setup failed\n");
+               return ret;
+       }
+
+       return 0;
+}
+
+static int fsl_asoc_card_late_probe(struct snd_soc_card *card)
+{
+       struct fsl_asoc_card_priv *priv = snd_soc_card_get_drvdata(card);
+       struct snd_soc_dai *codec_dai = card->rtd[0].codec_dai;
+       struct codec_priv *codec_priv = &priv->codec_priv;
+       struct device *dev = card->dev;
+       int ret;
+
+       ret = snd_soc_dai_set_sysclk(codec_dai, codec_priv->mclk_id,
+                                    codec_priv->mclk_freq, SND_SOC_CLOCK_IN);
+       if (ret) {
+               dev_err(dev, "failed to set sysclk in %s\n", __func__);
+               return ret;
+       }
+
+       return 0;
+}
+
+static int fsl_asoc_card_probe(struct platform_device *pdev)
+{
+       struct device_node *cpu_np, *codec_np, *asrc_np;
+       struct device_node *np = pdev->dev.of_node;
+       struct platform_device *asrc_pdev = NULL;
+       struct platform_device *cpu_pdev;
+       struct fsl_asoc_card_priv *priv;
+       struct i2c_client *codec_dev;
+       struct clk *codec_clk;
+       u32 width;
+       int ret;
+
+       priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
+       if (!priv)
+               return -ENOMEM;
+
+       cpu_np = of_parse_phandle(np, "audio-cpu", 0);
+       /* Give a chance to old DT binding */
+       if (!cpu_np)
+               cpu_np = of_parse_phandle(np, "ssi-controller", 0);
+       codec_np = of_parse_phandle(np, "audio-codec", 0);
+       if (!cpu_np || !codec_np) {
+               dev_err(&pdev->dev, "phandle missing or invalid\n");
+               ret = -EINVAL;
+               goto fail;
+       }
+
+       cpu_pdev = of_find_device_by_node(cpu_np);
+       if (!cpu_pdev) {
+               dev_err(&pdev->dev, "failed to find CPU DAI device\n");
+               ret = -EINVAL;
+               goto fail;
+       }
+
+       codec_dev = of_find_i2c_device_by_node(codec_np);
+       if (!codec_dev) {
+               dev_err(&pdev->dev, "failed to find codec platform device\n");
+               ret = -EINVAL;
+               goto fail;
+       }
+
+       asrc_np = of_parse_phandle(np, "audio-asrc", 0);
+       if (asrc_np)
+               asrc_pdev = of_find_device_by_node(asrc_np);
+
+       /* Get the MCLK rate only, and leave it controlled by CODEC drivers */
+       codec_clk = clk_get(&codec_dev->dev, NULL);
+       if (!IS_ERR(codec_clk)) {
+               priv->codec_priv.mclk_freq = clk_get_rate(codec_clk);
+               clk_put(codec_clk);
+       }
+
+       /* Default sample rate and format, will be updated in hw_params() */
+       priv->sample_rate = 44100;
+       priv->sample_format = SNDRV_PCM_FORMAT_S16_LE;
+
+       /* Assign a default DAI format, and allow each card to overwrite it */
+       priv->dai_fmt = DAI_FMT_BASE;
+
+       /* Diversify the card configurations */
+       if (of_device_is_compatible(np, "fsl,imx-audio-cs42888")) {
+               priv->card.set_bias_level = NULL;
+               priv->cpu_priv.sysclk_freq[TX] = priv->codec_priv.mclk_freq;
+               priv->cpu_priv.sysclk_freq[RX] = priv->codec_priv.mclk_freq;
+               priv->cpu_priv.sysclk_dir[TX] = SND_SOC_CLOCK_OUT;
+               priv->cpu_priv.sysclk_dir[RX] = SND_SOC_CLOCK_OUT;
+               priv->dai_fmt |= SND_SOC_DAIFMT_CBS_CFS;
+       } else if (of_device_is_compatible(np, "fsl,imx-audio-sgtl5000")) {
+               priv->codec_priv.mclk_id = SGTL5000_SYSCLK;
+               priv->dai_fmt |= SND_SOC_DAIFMT_CBM_CFM;
+       } else if (of_device_is_compatible(np, "fsl,imx-audio-wm8962")) {
+               priv->card.set_bias_level = fsl_asoc_card_set_bias_level;
+               priv->codec_priv.mclk_id = WM8962_SYSCLK_MCLK;
+               priv->codec_priv.fll_id = WM8962_SYSCLK_FLL;
+               priv->codec_priv.pll_id = WM8962_FLL;
+               priv->dai_fmt |= SND_SOC_DAIFMT_CBM_CFM;
+       } else {
+               dev_err(&pdev->dev, "unknown Device Tree compatible\n");
+               return -EINVAL;
+       }
+
+       /* Common settings for corresponding Freescale CPU DAI driver */
+       if (strstr(cpu_np->name, "ssi")) {
+               /* Only SSI needs to configure AUDMUX */
+               ret = fsl_asoc_card_audmux_init(np, priv);
+               if (ret) {
+                       dev_err(&pdev->dev, "failed to init audmux\n");
+                       goto asrc_fail;
+               }
+       } else if (strstr(cpu_np->name, "esai")) {
+               priv->cpu_priv.sysclk_id[1] = ESAI_HCKT_EXTAL;
+               priv->cpu_priv.sysclk_id[0] = ESAI_HCKR_EXTAL;
+       } else if (strstr(cpu_np->name, "sai")) {
+               priv->cpu_priv.sysclk_id[1] = FSL_SAI_CLK_MAST1;
+               priv->cpu_priv.sysclk_id[0] = FSL_SAI_CLK_MAST1;
+       }
+
+       sprintf(priv->name, "%s-audio", codec_dev->name);
+
+       /* Initialize sound card */
+       priv->pdev = pdev;
+       priv->card.dev = &pdev->dev;
+       priv->card.name = priv->name;
+       priv->card.dai_link = priv->dai_link;
+       priv->card.dapm_routes = audio_map;
+       priv->card.late_probe = fsl_asoc_card_late_probe;
+       priv->card.num_dapm_routes = ARRAY_SIZE(audio_map);
+       priv->card.dapm_widgets = fsl_asoc_card_dapm_widgets;
+       priv->card.num_dapm_widgets = ARRAY_SIZE(fsl_asoc_card_dapm_widgets);
+
+       memcpy(priv->dai_link, fsl_asoc_card_dai,
+              sizeof(struct snd_soc_dai_link) * ARRAY_SIZE(priv->dai_link));
+
+       /* Normal DAI Link */
+       priv->dai_link[0].cpu_of_node = cpu_np;
+       priv->dai_link[0].codec_of_node = codec_np;
+       priv->dai_link[0].codec_dai_name = codec_dev->name;
+       priv->dai_link[0].platform_of_node = cpu_np;
+       priv->dai_link[0].dai_fmt = priv->dai_fmt;
+       priv->card.num_links = 1;
+
+       if (asrc_pdev) {
+               /* DPCM DAI Links only if ASRC exsits */
+               priv->dai_link[1].cpu_of_node = asrc_np;
+               priv->dai_link[1].platform_of_node = asrc_np;
+               priv->dai_link[2].codec_dai_name = codec_dev->name;
+               priv->dai_link[2].codec_of_node = codec_np;
+               priv->dai_link[2].cpu_of_node = cpu_np;
+               priv->dai_link[2].dai_fmt = priv->dai_fmt;
+               priv->card.num_links = 3;
+
+               ret = of_property_read_u32(asrc_np, "fsl,asrc-rate",
+                                          &priv->asrc_rate);
+               if (ret) {
+                       dev_err(&pdev->dev, "failed to get output rate\n");
+                       ret = -EINVAL;
+                       goto asrc_fail;
+               }
+
+               ret = of_property_read_u32(asrc_np, "fsl,asrc-width", &width);
+               if (ret) {
+                       dev_err(&pdev->dev, "failed to get output rate\n");
+                       ret = -EINVAL;
+                       goto asrc_fail;
+               }
+
+               if (width == 24)
+                       priv->asrc_format = SNDRV_PCM_FORMAT_S24_LE;
+               else
+                       priv->asrc_format = SNDRV_PCM_FORMAT_S16_LE;
+       }
+
+       /* Finish card registering */
+       platform_set_drvdata(pdev, priv);
+       snd_soc_card_set_drvdata(&priv->card, priv);
+
+       ret = devm_snd_soc_register_card(&pdev->dev, &priv->card);
+       if (ret)
+               dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", ret);
+
+asrc_fail:
+       of_node_put(asrc_np);
+fail:
+       of_node_put(codec_np);
+       of_node_put(cpu_np);
+
+       return ret;
+}
+
+static const struct of_device_id fsl_asoc_card_dt_ids[] = {
+       { .compatible = "fsl,imx-audio-cs42888", },
+       { .compatible = "fsl,imx-audio-sgtl5000", },
+       { .compatible = "fsl,imx-audio-wm8962", },
+       {}
+};
+
+static struct platform_driver fsl_asoc_card_driver = {
+       .probe = fsl_asoc_card_probe,
+       .driver = {
+               .name = "fsl-asoc-card",
+               .pm = &snd_soc_pm_ops,
+               .of_match_table = fsl_asoc_card_dt_ids,
+       },
+};
+module_platform_driver(fsl_asoc_card_driver);
+
+MODULE_DESCRIPTION("Freescale Generic ASoC Sound Card driver with ASRC");
+MODULE_AUTHOR("Nicolin Chen <nicoleotsuka@gmail.com>");
+MODULE_ALIAS("platform:fsl-asoc-card");
+MODULE_LICENSE("GPL");
index 822110420b71cdf9df6922a43b213a61ac00b598..3b145313f93eecc0602cc72115d71769f07fdf26 100644 (file)
@@ -684,7 +684,7 @@ static bool fsl_asrc_writeable_reg(struct device *dev, unsigned int reg)
        }
 }
 
-static struct regmap_config fsl_asrc_regmap_config = {
+static const struct regmap_config fsl_asrc_regmap_config = {
        .reg_bits = 32,
        .reg_stride = 4,
        .val_bits = 32,
@@ -802,10 +802,6 @@ static int fsl_asrc_probe(struct platform_device *pdev)
 
        asrc_priv->paddr = res->start;
 
-       /* Register regmap and let it prepare core clock */
-       if (of_property_read_bool(np, "big-endian"))
-               fsl_asrc_regmap_config.val_format_endian = REGMAP_ENDIAN_BIG;
-
        asrc_priv->regmap = devm_regmap_init_mmio_clk(&pdev->dev, "mem", regs,
                                                      &fsl_asrc_regmap_config);
        if (IS_ERR(asrc_priv->regmap)) {
index a3b29ed84963459baada6cc9d8ab742f696ee44e..8bcdfda09d7ad9c5fd724cc685e63f3ac7829f77 100644 (file)
@@ -37,6 +37,7 @@
  * @fsysclk: system clock source to derive HCK, SCK and FS
  * @fifo_depth: depth of tx/rx FIFO
  * @slot_width: width of each DAI slot
+ * @slots: number of slots
  * @hck_rate: clock rate of desired HCKx clock
  * @sck_rate: clock rate of desired SCKx clock
  * @hck_dir: the direction of HCKx pads
@@ -55,6 +56,7 @@ struct fsl_esai {
        struct clk *fsysclk;
        u32 fifo_depth;
        u32 slot_width;
+       u32 slots;
        u32 hck_rate[2];
        u32 sck_rate[2];
        bool hck_dir[2];
@@ -362,6 +364,7 @@ static int fsl_esai_set_dai_tdm_slot(struct snd_soc_dai *dai, u32 tx_mask,
                           ESAI_xSMB_xS_MASK, ESAI_xSMB_xS(rx_mask));
 
        esai_priv->slot_width = slot_width;
+       esai_priv->slots = slots;
 
        return 0;
 }
@@ -509,10 +512,11 @@ static int fsl_esai_hw_params(struct snd_pcm_substream *substream,
        bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
        u32 width = snd_pcm_format_width(params_format(params));
        u32 channels = params_channels(params);
+       u32 pins = DIV_ROUND_UP(channels, esai_priv->slots);
        u32 bclk, mask, val;
        int ret;
 
-       bclk = params_rate(params) * esai_priv->slot_width * 2;
+       bclk = params_rate(params) * esai_priv->slot_width * esai_priv->slots;
 
        ret = fsl_esai_set_bclk(dai, tx, bclk);
        if (ret)
@@ -529,7 +533,7 @@ static int fsl_esai_hw_params(struct snd_pcm_substream *substream,
        mask = ESAI_xFCR_xFR_MASK | ESAI_xFCR_xWA_MASK | ESAI_xFCR_xFWM_MASK |
              (tx ? ESAI_xFCR_TE_MASK | ESAI_xFCR_TIEN : ESAI_xFCR_RE_MASK);
        val = ESAI_xFCR_xWA(width) | ESAI_xFCR_xFWM(esai_priv->fifo_depth) |
-            (tx ? ESAI_xFCR_TE(channels) | ESAI_xFCR_TIEN : ESAI_xFCR_RE(channels));
+            (tx ? ESAI_xFCR_TE(pins) | ESAI_xFCR_TIEN : ESAI_xFCR_RE(pins));
 
        regmap_update_bits(esai_priv->regmap, REG_ESAI_xFCR(tx), mask, val);
 
@@ -564,6 +568,7 @@ static int fsl_esai_trigger(struct snd_pcm_substream *substream, int cmd,
        struct fsl_esai *esai_priv = snd_soc_dai_get_drvdata(dai);
        bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
        u8 i, channels = substream->runtime->channels;
+       u32 pins = DIV_ROUND_UP(channels, esai_priv->slots);
 
        switch (cmd) {
        case SNDRV_PCM_TRIGGER_START:
@@ -578,7 +583,7 @@ static int fsl_esai_trigger(struct snd_pcm_substream *substream, int cmd,
 
                regmap_update_bits(esai_priv->regmap, REG_ESAI_xCR(tx),
                                   tx ? ESAI_xCR_TE_MASK : ESAI_xCR_RE_MASK,
-                                  tx ? ESAI_xCR_TE(channels) : ESAI_xCR_RE(channels));
+                                  tx ? ESAI_xCR_TE(pins) : ESAI_xCR_RE(pins));
                break;
        case SNDRV_PCM_TRIGGER_SUSPEND:
        case SNDRV_PCM_TRIGGER_STOP:
@@ -705,7 +710,7 @@ static bool fsl_esai_writeable_reg(struct device *dev, unsigned int reg)
        }
 }
 
-static struct regmap_config fsl_esai_regmap_config = {
+static const struct regmap_config fsl_esai_regmap_config = {
        .reg_bits = 32,
        .reg_stride = 4,
        .val_bits = 32,
@@ -731,9 +736,6 @@ static int fsl_esai_probe(struct platform_device *pdev)
        esai_priv->pdev = pdev;
        strcpy(esai_priv->name, np->name);
 
-       if (of_property_read_bool(np, "big-endian"))
-               fsl_esai_regmap_config.val_format_endian = REGMAP_ENDIAN_BIG;
-
        /* Get the addresses and IRQ */
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        regs = devm_ioremap_resource(&pdev->dev, res);
@@ -781,6 +783,9 @@ static int fsl_esai_probe(struct platform_device *pdev)
        /* Set a default slot size */
        esai_priv->slot_width = 32;
 
+       /* Set a default slot number */
+       esai_priv->slots = 2;
+
        /* Set a default master/slave state */
        esai_priv->slave_mode = true;
 
index 75e14033e8d8f0a7da6b1db6387d543c5a9a1acc..91a550f4a10dc7e0156efd8389fc3ba90bb15955 100644 (file)
 #define ESAI_xFCR_RE_WIDTH     4
 #define ESAI_xFCR_TE_MASK      (((1 << ESAI_xFCR_TE_WIDTH) - 1) << ESAI_xFCR_xE_SHIFT)
 #define ESAI_xFCR_RE_MASK      (((1 << ESAI_xFCR_RE_WIDTH) - 1) << ESAI_xFCR_xE_SHIFT)
-#define ESAI_xFCR_TE(x)        ((ESAI_xFCR_TE_MASK >> (ESAI_xFCR_TE_WIDTH - ((x + 1) >> 1))) & ESAI_xFCR_TE_MASK)
-#define ESAI_xFCR_RE(x)        ((ESAI_xFCR_RE_MASK >> (ESAI_xFCR_RE_WIDTH - ((x + 1) >> 1))) & ESAI_xFCR_RE_MASK)
+#define ESAI_xFCR_TE(x)        ((ESAI_xFCR_TE_MASK >> (ESAI_xFCR_TE_WIDTH - x)) & ESAI_xFCR_TE_MASK)
+#define ESAI_xFCR_RE(x)        ((ESAI_xFCR_RE_MASK >> (ESAI_xFCR_RE_WIDTH - x)) & ESAI_xFCR_RE_MASK)
 #define ESAI_xFCR_xFR_SHIFT    1
 #define ESAI_xFCR_xFR_MASK     (1 << ESAI_xFCR_xFR_SHIFT)
 #define ESAI_xFCR_xFR          (1 << ESAI_xFCR_xFR_SHIFT)
 #define ESAI_xCR_RE_WIDTH      4
 #define ESAI_xCR_TE_MASK       (((1 << ESAI_xCR_TE_WIDTH) - 1) << ESAI_xCR_xE_SHIFT)
 #define ESAI_xCR_RE_MASK       (((1 << ESAI_xCR_RE_WIDTH) - 1) << ESAI_xCR_xE_SHIFT)
-#define ESAI_xCR_TE(x)                 ((ESAI_xCR_TE_MASK >> (ESAI_xCR_TE_WIDTH - ((x + 1) >> 1))) & ESAI_xCR_TE_MASK)
-#define ESAI_xCR_RE(x)                 ((ESAI_xCR_RE_MASK >> (ESAI_xCR_RE_WIDTH - ((x + 1) >> 1))) & ESAI_xCR_RE_MASK)
+#define ESAI_xCR_TE(x)                 ((ESAI_xCR_TE_MASK >> (ESAI_xCR_TE_WIDTH - x)) & ESAI_xCR_TE_MASK)
+#define ESAI_xCR_RE(x)                 ((ESAI_xCR_RE_MASK >> (ESAI_xCR_RE_WIDTH - x)) & ESAI_xCR_RE_MASK)
 
 /*
  * Transmit Clock Control Register -- REG_ESAI_TCCR 0xD8
index faa049797897ed1e8996755437df2488c19c457b..7eeb1dd8ce27339e05305552aa7f3cc34240ca29 100644 (file)
@@ -175,7 +175,7 @@ static int fsl_sai_set_dai_fmt_tr(struct snd_soc_dai *cpu_dai,
        bool tx = fsl_dir == FSL_FMT_TRANSMITTER;
        u32 val_cr2 = 0, val_cr4 = 0;
 
-       if (!sai->big_endian_data)
+       if (!sai->is_lsb_first)
                val_cr4 |= FSL_SAI_CR4_MF;
 
        /* DAI mode */
@@ -304,7 +304,7 @@ static int fsl_sai_hw_params(struct snd_pcm_substream *substream,
        val_cr5 |= FSL_SAI_CR5_WNW(word_width);
        val_cr5 |= FSL_SAI_CR5_W0W(word_width);
 
-       if (sai->big_endian_data)
+       if (sai->is_lsb_first)
                val_cr5 |= FSL_SAI_CR5_FBT(0);
        else
                val_cr5 |= FSL_SAI_CR5_FBT(word_width - 1);
@@ -330,13 +330,13 @@ static int fsl_sai_trigger(struct snd_pcm_substream *substream, int cmd,
        u32 xcsr, count = 100;
 
        /*
-        * The transmitter bit clock and frame sync are to be
-        * used by both the transmitter and receiver.
+        * Asynchronous mode: Clear SYNC for both Tx and Rx.
+        * Rx sync with Tx clocks: Clear SYNC for Tx, set it for Rx.
+        * Tx sync with Rx clocks: Clear SYNC for Rx, set it for Tx.
         */
-       regmap_update_bits(sai->regmap, FSL_SAI_TCR2, FSL_SAI_CR2_SYNC,
-                          ~FSL_SAI_CR2_SYNC);
+       regmap_update_bits(sai->regmap, FSL_SAI_TCR2, FSL_SAI_CR2_SYNC, 0);
        regmap_update_bits(sai->regmap, FSL_SAI_RCR2, FSL_SAI_CR2_SYNC,
-                          FSL_SAI_CR2_SYNC);
+                          sai->synchronous[RX] ? FSL_SAI_CR2_SYNC : 0);
 
        /*
         * It is recommended that the transmitter is the last enabled
@@ -437,8 +437,13 @@ static int fsl_sai_dai_probe(struct snd_soc_dai *cpu_dai)
 {
        struct fsl_sai *sai = dev_get_drvdata(cpu_dai->dev);
 
-       regmap_update_bits(sai->regmap, FSL_SAI_TCSR, 0xffffffff, 0x0);
-       regmap_update_bits(sai->regmap, FSL_SAI_RCSR, 0xffffffff, 0x0);
+       /* Software Reset for both Tx and Rx */
+       regmap_write(sai->regmap, FSL_SAI_TCSR, FSL_SAI_CSR_SR);
+       regmap_write(sai->regmap, FSL_SAI_RCSR, FSL_SAI_CSR_SR);
+       /* Clear SR bit to finish the reset */
+       regmap_write(sai->regmap, FSL_SAI_TCSR, 0);
+       regmap_write(sai->regmap, FSL_SAI_RCSR, 0);
+
        regmap_update_bits(sai->regmap, FSL_SAI_TCR1, FSL_SAI_CR1_RFW_MASK,
                           FSL_SAI_MAXBURST_TX * 2);
        regmap_update_bits(sai->regmap, FSL_SAI_RCR1, FSL_SAI_CR1_RFW_MASK,
@@ -539,7 +544,7 @@ static bool fsl_sai_writeable_reg(struct device *dev, unsigned int reg)
        }
 }
 
-static struct regmap_config fsl_sai_regmap_config = {
+static const struct regmap_config fsl_sai_regmap_config = {
        .reg_bits = 32,
        .reg_stride = 4,
        .val_bits = 32,
@@ -568,11 +573,7 @@ static int fsl_sai_probe(struct platform_device *pdev)
        if (of_device_is_compatible(pdev->dev.of_node, "fsl,imx6sx-sai"))
                sai->sai_on_imx = true;
 
-       sai->big_endian_regs = of_property_read_bool(np, "big-endian-regs");
-       if (sai->big_endian_regs)
-               fsl_sai_regmap_config.val_format_endian = REGMAP_ENDIAN_BIG;
-
-       sai->big_endian_data = of_property_read_bool(np, "big-endian-data");
+       sai->is_lsb_first = of_property_read_bool(np, "lsb-first");
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        base = devm_ioremap_resource(&pdev->dev, res);
@@ -621,6 +622,33 @@ static int fsl_sai_probe(struct platform_device *pdev)
                return ret;
        }
 
+       /* Sync Tx with Rx as default by following old DT binding */
+       sai->synchronous[RX] = true;
+       sai->synchronous[TX] = false;
+       fsl_sai_dai.symmetric_rates = 1;
+       fsl_sai_dai.symmetric_channels = 1;
+       fsl_sai_dai.symmetric_samplebits = 1;
+
+       if (of_find_property(np, "fsl,sai-synchronous-rx", NULL) &&
+           of_find_property(np, "fsl,sai-asynchronous", NULL)) {
+               /* error out if both synchronous and asynchronous are present */
+               dev_err(&pdev->dev, "invalid binding for synchronous mode\n");
+               return -EINVAL;
+       }
+
+       if (of_find_property(np, "fsl,sai-synchronous-rx", NULL)) {
+               /* Sync Rx with Tx */
+               sai->synchronous[RX] = false;
+               sai->synchronous[TX] = true;
+       } else if (of_find_property(np, "fsl,sai-asynchronous", NULL)) {
+               /* Discard all settings for asynchronous mode */
+               sai->synchronous[RX] = false;
+               sai->synchronous[TX] = false;
+               fsl_sai_dai.symmetric_rates = 0;
+               fsl_sai_dai.symmetric_channels = 0;
+               fsl_sai_dai.symmetric_samplebits = 0;
+       }
+
        sai->dma_params_rx.addr = res->start + FSL_SAI_RDR;
        sai->dma_params_tx.addr = res->start + FSL_SAI_TDR;
        sai->dma_params_rx.maxburst = FSL_SAI_MAXBURST_RX;
index 0e6c9f595d7550957eabc534174b7a14b2056422..34667209b607d435d3abd9ac10bbfe6e8cf9a64c 100644 (file)
@@ -48,6 +48,7 @@
 /* SAI Transmit/Recieve Control Register */
 #define FSL_SAI_CSR_TERE       BIT(31)
 #define FSL_SAI_CSR_FR         BIT(25)
+#define FSL_SAI_CSR_SR         BIT(24)
 #define FSL_SAI_CSR_xF_SHIFT   16
 #define FSL_SAI_CSR_xF_W_SHIFT 18
 #define FSL_SAI_CSR_xF_MASK    (0x1f << FSL_SAI_CSR_xF_SHIFT)
@@ -131,13 +132,16 @@ struct fsl_sai {
        struct clk *bus_clk;
        struct clk *mclk_clk[FSL_SAI_MCLK_MAX];
 
-       bool big_endian_regs;
-       bool big_endian_data;
+       bool is_lsb_first;
        bool is_dsp_mode;
        bool sai_on_imx;
+       bool synchronous[2];
 
        struct snd_dmaengine_dai_dma_data dma_params_rx;
        struct snd_dmaengine_dai_dma_data dma_params_tx;
 };
 
+#define TX 1
+#define RX 0
+
 #endif /* __FSL_SAI_H */
index 70acfe4a9bd5a969e5418daf098a5e40115191bb..9b791621294cf6d2f1c1059df8d3de9ce2634639 100644 (file)
@@ -15,7 +15,6 @@
 
 #include <linux/bitrev.h>
 #include <linux/clk.h>
-#include <linux/clk-private.h>
 #include <linux/module.h>
 #include <linux/of_address.h>
 #include <linux/of_device.h>
@@ -1040,7 +1039,7 @@ static bool fsl_spdif_writeable_reg(struct device *dev, unsigned int reg)
        }
 }
 
-static struct regmap_config fsl_spdif_regmap_config = {
+static const struct regmap_config fsl_spdif_regmap_config = {
        .reg_bits = 32,
        .reg_stride = 4,
        .val_bits = 32,
@@ -1184,9 +1183,6 @@ static int fsl_spdif_probe(struct platform_device *pdev)
        memcpy(&spdif_priv->cpu_dai_drv, &fsl_spdif_dai, sizeof(fsl_spdif_dai));
        spdif_priv->cpu_dai_drv.name = spdif_priv->name;
 
-       if (of_property_read_bool(np, "big-endian"))
-               fsl_spdif_regmap_config.val_format_endian = REGMAP_ENDIAN_BIG;
-
        /* Get the addresses and IRQ */
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        regs = devm_ioremap_resource(&pdev->dev, res);
index de6ab06f58a54dbd32b871273a530db6e8d9fbed..e6955170dc42c8b805d6aa654a5eadebc437b27e 100644 (file)
@@ -169,6 +169,7 @@ struct fsl_ssi_private {
        u8 i2s_mode;
        bool use_dma;
        bool use_dual_fifo;
+       bool has_ipg_clk_name;
        unsigned int fifo_depth;
        struct fsl_ssi_rxtx_reg_val rxtx_reg_val;
 
@@ -259,6 +260,11 @@ static bool fsl_ssi_is_i2s_master(struct fsl_ssi_private *ssi_private)
                SND_SOC_DAIFMT_CBS_CFS;
 }
 
+static bool fsl_ssi_is_i2s_cbm_cfs(struct fsl_ssi_private *ssi_private)
+{
+       return (ssi_private->dai_fmt & SND_SOC_DAIFMT_MASTER_MASK) ==
+               SND_SOC_DAIFMT_CBM_CFS;
+}
 /**
  * fsl_ssi_isr: SSI interrupt handler
  *
@@ -525,6 +531,11 @@ static int fsl_ssi_startup(struct snd_pcm_substream *substream,
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
        struct fsl_ssi_private *ssi_private =
                snd_soc_dai_get_drvdata(rtd->cpu_dai);
+       int ret;
+
+       ret = clk_prepare_enable(ssi_private->clk);
+       if (ret)
+               return ret;
 
        /* When using dual fifo mode, it is safer to ensure an even period
         * size. If appearing to an odd number while DMA always starts its
@@ -538,6 +549,21 @@ static int fsl_ssi_startup(struct snd_pcm_substream *substream,
        return 0;
 }
 
+/**
+ * fsl_ssi_shutdown: shutdown the SSI
+ *
+ */
+static void fsl_ssi_shutdown(struct snd_pcm_substream *substream,
+                               struct snd_soc_dai *dai)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct fsl_ssi_private *ssi_private =
+               snd_soc_dai_get_drvdata(rtd->cpu_dai);
+
+       clk_disable_unprepare(ssi_private->clk);
+
+}
+
 /**
  * fsl_ssi_set_bclk - configure Digital Audio Interface bit clock
  *
@@ -705,6 +731,23 @@ static int fsl_ssi_hw_params(struct snd_pcm_substream *substream,
                }
        }
 
+       if (!fsl_ssi_is_ac97(ssi_private)) {
+               u8 i2smode;
+               /*
+                * Switch to normal net mode in order to have a frame sync
+                * signal every 32 bits instead of 16 bits
+                */
+               if (fsl_ssi_is_i2s_cbm_cfs(ssi_private) && sample_size == 16)
+                       i2smode = CCSR_SSI_SCR_I2S_MODE_NORMAL |
+                               CCSR_SSI_SCR_NET;
+               else
+                       i2smode = ssi_private->i2s_mode;
+
+               regmap_update_bits(regs, CCSR_SSI_SCR,
+                               CCSR_SSI_SCR_NET | CCSR_SSI_SCR_I2S_MODE_MASK,
+                               channels == 1 ? 0 : i2smode);
+       }
+
        /*
         * FIXME: The documentation says that SxCCR[WL] should not be
         * modified while the SSI is enabled.  The only time this can
@@ -724,11 +767,6 @@ static int fsl_ssi_hw_params(struct snd_pcm_substream *substream,
                regmap_update_bits(regs, CCSR_SSI_SRCCR, CCSR_SSI_SxCCR_WL_MASK,
                                wl);
 
-       if (!fsl_ssi_is_ac97(ssi_private))
-               regmap_update_bits(regs, CCSR_SSI_SCR,
-                               CCSR_SSI_SCR_NET | CCSR_SSI_SCR_I2S_MODE_MASK,
-                               channels == 1 ? 0 : ssi_private->i2s_mode);
-
        return 0;
 }
 
@@ -781,6 +819,7 @@ static int _fsl_ssi_set_dai_fmt(struct device *dev,
        switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
        case SND_SOC_DAIFMT_I2S:
                switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+               case SND_SOC_DAIFMT_CBM_CFS:
                case SND_SOC_DAIFMT_CBS_CFS:
                        ssi_private->i2s_mode |= CCSR_SSI_SCR_I2S_MODE_MASTER;
                        regmap_update_bits(regs, CCSR_SSI_STCCR,
@@ -854,6 +893,11 @@ static int _fsl_ssi_set_dai_fmt(struct device *dev,
        case SND_SOC_DAIFMT_CBM_CFM:
                scr &= ~CCSR_SSI_SCR_SYS_CLK_EN;
                break;
+       case SND_SOC_DAIFMT_CBM_CFS:
+               strcr &= ~CCSR_SSI_STCR_TXDIR;
+               strcr |= CCSR_SSI_STCR_TFDIR;
+               scr &= ~CCSR_SSI_SCR_SYS_CLK_EN;
+               break;
        default:
                return -EINVAL;
        }
@@ -1021,6 +1065,7 @@ static int fsl_ssi_dai_probe(struct snd_soc_dai *dai)
 
 static const struct snd_soc_dai_ops fsl_ssi_dai_ops = {
        .startup        = fsl_ssi_startup,
+       .shutdown       = fsl_ssi_shutdown,
        .hw_params      = fsl_ssi_hw_params,
        .hw_free        = fsl_ssi_hw_free,
        .set_fmt        = fsl_ssi_set_dai_fmt,
@@ -1146,17 +1191,22 @@ static int fsl_ssi_imx_probe(struct platform_device *pdev,
        u32 dmas[4];
        int ret;
 
-       ssi_private->clk = devm_clk_get(&pdev->dev, NULL);
+       if (ssi_private->has_ipg_clk_name)
+               ssi_private->clk = devm_clk_get(&pdev->dev, "ipg");
+       else
+               ssi_private->clk = devm_clk_get(&pdev->dev, NULL);
        if (IS_ERR(ssi_private->clk)) {
                ret = PTR_ERR(ssi_private->clk);
                dev_err(&pdev->dev, "could not get clock: %d\n", ret);
                return ret;
        }
 
-       ret = clk_prepare_enable(ssi_private->clk);
-       if (ret) {
-               dev_err(&pdev->dev, "clk_prepare_enable failed: %d\n", ret);
-               return ret;
+       if (!ssi_private->has_ipg_clk_name) {
+               ret = clk_prepare_enable(ssi_private->clk);
+               if (ret) {
+                       dev_err(&pdev->dev, "clk_prepare_enable failed: %d\n", ret);
+                       return ret;
+               }
        }
 
        /* For those SLAVE implementations, we ingore non-baudclk cases
@@ -1214,8 +1264,9 @@ static int fsl_ssi_imx_probe(struct platform_device *pdev,
        return 0;
 
 error_pcm:
-       clk_disable_unprepare(ssi_private->clk);
 
+       if (!ssi_private->has_ipg_clk_name)
+               clk_disable_unprepare(ssi_private->clk);
        return ret;
 }
 
@@ -1224,7 +1275,8 @@ static void fsl_ssi_imx_clean(struct platform_device *pdev,
 {
        if (!ssi_private->use_dma)
                imx_pcm_fiq_exit(pdev);
-       clk_disable_unprepare(ssi_private->clk);
+       if (!ssi_private->has_ipg_clk_name)
+               clk_disable_unprepare(ssi_private->clk);
 }
 
 static int fsl_ssi_probe(struct platform_device *pdev)
@@ -1263,9 +1315,6 @@ static int fsl_ssi_probe(struct platform_device *pdev)
        if (sprop) {
                if (!strcmp(sprop, "ac97-slave"))
                        ssi_private->dai_fmt = SND_SOC_DAIFMT_AC97;
-               else if (!strcmp(sprop, "i2s-slave"))
-                       ssi_private->dai_fmt = SND_SOC_DAIFMT_I2S |
-                               SND_SOC_DAIFMT_CBM_CFM;
        }
 
        ssi_private->use_dma = !of_property_read_bool(np,
@@ -1299,8 +1348,16 @@ static int fsl_ssi_probe(struct platform_device *pdev)
                return -ENOMEM;
        }
 
-       ssi_private->regs = devm_regmap_init_mmio(&pdev->dev, iomem,
+       ret = of_property_match_string(np, "clock-names", "ipg");
+       if (ret < 0) {
+               ssi_private->has_ipg_clk_name = false;
+               ssi_private->regs = devm_regmap_init_mmio(&pdev->dev, iomem,
                        &fsl_ssi_regconfig);
+       } else {
+               ssi_private->has_ipg_clk_name = true;
+               ssi_private->regs = devm_regmap_init_mmio_clk(&pdev->dev,
+                       "ipg", iomem, &fsl_ssi_regconfig);
+       }
        if (IS_ERR(ssi_private->regs)) {
                dev_err(&pdev->dev, "Failed to init register map\n");
                return PTR_ERR(ssi_private->regs);
diff --git a/sound/soc/fsl/imx-es8328.c b/sound/soc/fsl/imx-es8328.c
new file mode 100644 (file)
index 0000000..f8cf10e
--- /dev/null
@@ -0,0 +1,233 @@
+/*
+ * Copyright 2012 Freescale Semiconductor, Inc.
+ * Copyright 2012 Linaro Ltd.
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+#include <linux/gpio.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/i2c.h>
+#include <linux/of_gpio.h>
+#include <sound/soc.h>
+#include <sound/jack.h>
+
+#include "imx-audmux.h"
+
+#define DAI_NAME_SIZE  32
+#define MUX_PORT_MAX   7
+
+struct imx_es8328_data {
+       struct device *dev;
+       struct snd_soc_dai_link dai;
+       struct snd_soc_card card;
+       char codec_dai_name[DAI_NAME_SIZE];
+       char platform_name[DAI_NAME_SIZE];
+       int jack_gpio;
+};
+
+static struct snd_soc_jack_gpio headset_jack_gpios[] = {
+       {
+               .gpio = -1,
+               .name = "headset-gpio",
+               .report = SND_JACK_HEADSET,
+               .invert = 0,
+               .debounce_time = 200,
+       },
+};
+
+static struct snd_soc_jack headset_jack;
+
+static int imx_es8328_dai_init(struct snd_soc_pcm_runtime *rtd)
+{
+       struct imx_es8328_data *data = container_of(rtd->card,
+                                       struct imx_es8328_data, card);
+       int ret = 0;
+
+       /* Headphone jack detection */
+       if (gpio_is_valid(data->jack_gpio)) {
+               ret = snd_soc_jack_new(rtd->codec, "Headphone",
+                                      SND_JACK_HEADPHONE | SND_JACK_BTN_0,
+                                      &headset_jack);
+               if (ret)
+                       return ret;
+
+               headset_jack_gpios[0].gpio = data->jack_gpio;
+               ret = snd_soc_jack_add_gpios(&headset_jack,
+                                            ARRAY_SIZE(headset_jack_gpios),
+                                            headset_jack_gpios);
+       }
+
+       return ret;
+}
+
+static const struct snd_soc_dapm_widget imx_es8328_dapm_widgets[] = {
+       SND_SOC_DAPM_MIC("Mic Jack", NULL),
+       SND_SOC_DAPM_HP("Headphone", NULL),
+       SND_SOC_DAPM_SPK("Speaker", NULL),
+       SND_SOC_DAPM_REGULATOR_SUPPLY("audio-amp", 1, 0),
+};
+
+static int imx_es8328_probe(struct platform_device *pdev)
+{
+       struct device_node *np = pdev->dev.of_node;
+       struct device_node *ssi_np = NULL, *codec_np = NULL;
+       struct platform_device *ssi_pdev;
+       struct imx_es8328_data *data;
+       u32 int_port, ext_port;
+       int ret;
+       struct device *dev = &pdev->dev;
+
+       ret = of_property_read_u32(np, "mux-int-port", &int_port);
+       if (ret) {
+               dev_err(dev, "mux-int-port missing or invalid\n");
+               goto fail;
+       }
+       if (int_port > MUX_PORT_MAX || int_port == 0) {
+               dev_err(dev, "mux-int-port: hardware only has %d mux ports\n",
+                       MUX_PORT_MAX);
+               goto fail;
+       }
+
+       ret = of_property_read_u32(np, "mux-ext-port", &ext_port);
+       if (ret) {
+               dev_err(dev, "mux-ext-port missing or invalid\n");
+               goto fail;
+       }
+       if (ext_port > MUX_PORT_MAX || ext_port == 0) {
+               dev_err(dev, "mux-ext-port: hardware only has %d mux ports\n",
+                       MUX_PORT_MAX);
+               ret = -EINVAL;
+               goto fail;
+       }
+
+       /*
+        * The port numbering in the hardware manual starts at 1, while
+        * the audmux API expects it starts at 0.
+        */
+       int_port--;
+       ext_port--;
+       ret = imx_audmux_v2_configure_port(int_port,
+                       IMX_AUDMUX_V2_PTCR_SYN |
+                       IMX_AUDMUX_V2_PTCR_TFSEL(ext_port) |
+                       IMX_AUDMUX_V2_PTCR_TCSEL(ext_port) |
+                       IMX_AUDMUX_V2_PTCR_TFSDIR |
+                       IMX_AUDMUX_V2_PTCR_TCLKDIR,
+                       IMX_AUDMUX_V2_PDCR_RXDSEL(ext_port));
+       if (ret) {
+               dev_err(dev, "audmux internal port setup failed\n");
+               return ret;
+       }
+       ret = imx_audmux_v2_configure_port(ext_port,
+                       IMX_AUDMUX_V2_PTCR_SYN,
+                       IMX_AUDMUX_V2_PDCR_RXDSEL(int_port));
+       if (ret) {
+               dev_err(dev, "audmux external port setup failed\n");
+               return ret;
+       }
+
+       ssi_np = of_parse_phandle(pdev->dev.of_node, "ssi-controller", 0);
+       codec_np = of_parse_phandle(pdev->dev.of_node, "audio-codec", 0);
+       if (!ssi_np || !codec_np) {
+               dev_err(dev, "phandle missing or invalid\n");
+               ret = -EINVAL;
+               goto fail;
+       }
+
+       ssi_pdev = of_find_device_by_node(ssi_np);
+       if (!ssi_pdev) {
+               dev_err(dev, "failed to find SSI platform device\n");
+               ret = -EINVAL;
+               goto fail;
+       }
+
+       data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
+       if (!data) {
+               ret = -ENOMEM;
+               goto fail;
+       }
+
+       data->dev = dev;
+
+       data->jack_gpio = of_get_named_gpio(pdev->dev.of_node, "jack-gpio", 0);
+
+       data->dai.name = "hifi";
+       data->dai.stream_name = "hifi";
+       data->dai.codec_dai_name = "es8328-hifi-analog";
+       data->dai.codec_of_node = codec_np;
+       data->dai.cpu_of_node = ssi_np;
+       data->dai.platform_of_node = ssi_np;
+       data->dai.init = &imx_es8328_dai_init;
+       data->dai.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
+                           SND_SOC_DAIFMT_CBM_CFM;
+
+       data->card.dev = dev;
+       data->card.dapm_widgets = imx_es8328_dapm_widgets;
+       data->card.num_dapm_widgets = ARRAY_SIZE(imx_es8328_dapm_widgets);
+       ret = snd_soc_of_parse_card_name(&data->card, "model");
+       if (ret) {
+               dev_err(dev, "Unable to parse card name\n");
+               goto fail;
+       }
+       ret = snd_soc_of_parse_audio_routing(&data->card, "audio-routing");
+       if (ret) {
+               dev_err(dev, "Unable to parse routing: %d\n", ret);
+               goto fail;
+       }
+       data->card.num_links = 1;
+       data->card.owner = THIS_MODULE;
+       data->card.dai_link = &data->dai;
+
+       ret = snd_soc_register_card(&data->card);
+       if (ret) {
+               dev_err(dev, "Unable to register: %d\n", ret);
+               goto fail;
+       }
+
+       platform_set_drvdata(pdev, data);
+fail:
+       of_node_put(ssi_np);
+       of_node_put(codec_np);
+
+       return ret;
+}
+
+static int imx_es8328_remove(struct platform_device *pdev)
+{
+       struct imx_es8328_data *data = platform_get_drvdata(pdev);
+
+       snd_soc_jack_free_gpios(&headset_jack, ARRAY_SIZE(headset_jack_gpios),
+                               headset_jack_gpios);
+
+       snd_soc_unregister_card(&data->card);
+
+       return 0;
+}
+
+static const struct of_device_id imx_es8328_dt_ids[] = {
+       { .compatible = "fsl,imx-audio-es8328", },
+       { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, imx_es8328_dt_ids);
+
+static struct platform_driver imx_es8328_driver = {
+       .driver = {
+               .name = "imx-es8328",
+               .of_match_table = imx_es8328_dt_ids,
+       },
+       .probe = imx_es8328_probe,
+       .remove = imx_es8328_remove,
+};
+module_platform_driver(imx_es8328_driver);
+
+MODULE_AUTHOR("Sean Cross <xobs@kosagi.com>");
+MODULE_DESCRIPTION("Kosagi i.MX6 ES8328 ASoC machine driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:imx-audio-es8328");
index cef7776b712cff43f37f81648a6fe2a59256ddd9..d1b7293c133eaa456f9d7761f273ee2887251121 100644 (file)
  */
 #include <linux/clk.h>
 #include <linux/device.h>
+#include <linux/gpio.h>
 #include <linux/module.h>
 #include <linux/of.h>
+#include <linux/of_gpio.h>
 #include <linux/platform_device.h>
 #include <linux/string.h>
+#include <sound/jack.h>
 #include <sound/simple_card.h>
 #include <sound/soc-dai.h>
 #include <sound/soc.h>
@@ -25,9 +28,15 @@ struct simple_card_data {
                struct asoc_simple_dai codec_dai;
        } *dai_props;
        unsigned int mclk_fs;
+       int gpio_hp_det;
+       int gpio_mic_det;
        struct snd_soc_dai_link dai_link[];     /* dynamically allocated */
 };
 
+#define simple_priv_to_dev(priv) ((priv)->snd_card.dev)
+#define simple_priv_to_link(priv, i) ((priv)->snd_card.dai_link + i)
+#define simple_priv_to_props(priv, i) ((priv)->dai_props + i)
+
 static int asoc_simple_card_hw_params(struct snd_pcm_substream *substream,
                                      struct snd_pcm_hw_params *params)
 {
@@ -50,6 +59,32 @@ static struct snd_soc_ops asoc_simple_card_ops = {
        .hw_params = asoc_simple_card_hw_params,
 };
 
+static struct snd_soc_jack simple_card_hp_jack;
+static struct snd_soc_jack_pin simple_card_hp_jack_pins[] = {
+       {
+               .pin = "Headphones",
+               .mask = SND_JACK_HEADPHONE,
+       },
+};
+static struct snd_soc_jack_gpio simple_card_hp_jack_gpio = {
+       .name = "Headphone detection",
+       .report = SND_JACK_HEADPHONE,
+       .debounce_time = 150,
+};
+
+static struct snd_soc_jack simple_card_mic_jack;
+static struct snd_soc_jack_pin simple_card_mic_jack_pins[] = {
+       {
+               .pin = "Mic Jack",
+               .mask = SND_JACK_MICROPHONE,
+       },
+};
+static struct snd_soc_jack_gpio simple_card_mic_jack_gpio = {
+       .name = "Mic detection",
+       .report = SND_JACK_MICROPHONE,
+       .debounce_time = 150,
+};
+
 static int __asoc_simple_card_dai_init(struct snd_soc_dai *dai,
                                       struct asoc_simple_dai *set)
 {
@@ -105,42 +140,70 @@ static int asoc_simple_card_dai_init(struct snd_soc_pcm_runtime *rtd)
        if (ret < 0)
                return ret;
 
+       if (gpio_is_valid(priv->gpio_hp_det)) {
+               snd_soc_jack_new(codec->codec, "Headphones", SND_JACK_HEADPHONE,
+                                &simple_card_hp_jack);
+               snd_soc_jack_add_pins(&simple_card_hp_jack,
+                                     ARRAY_SIZE(simple_card_hp_jack_pins),
+                                     simple_card_hp_jack_pins);
+
+               simple_card_hp_jack_gpio.gpio = priv->gpio_hp_det;
+               snd_soc_jack_add_gpios(&simple_card_hp_jack, 1,
+                                      &simple_card_hp_jack_gpio);
+       }
+
+       if (gpio_is_valid(priv->gpio_mic_det)) {
+               snd_soc_jack_new(codec->codec, "Mic Jack", SND_JACK_MICROPHONE,
+                                &simple_card_mic_jack);
+               snd_soc_jack_add_pins(&simple_card_mic_jack,
+                                     ARRAY_SIZE(simple_card_mic_jack_pins),
+                                     simple_card_mic_jack_pins);
+               simple_card_mic_jack_gpio.gpio = priv->gpio_mic_det;
+               snd_soc_jack_add_gpios(&simple_card_mic_jack, 1,
+                                      &simple_card_mic_jack_gpio);
+       }
        return 0;
 }
 
 static int
 asoc_simple_card_sub_parse_of(struct device_node *np,
                              struct asoc_simple_dai *dai,
-                             const struct device_node **p_node,
-                             const char **name)
+                             struct device_node **p_node,
+                             const char **name,
+                             int *args_count)
 {
-       struct device_node *node;
+       struct of_phandle_args args;
        struct clk *clk;
        u32 val;
        int ret;
 
        /*
-        * get node via "sound-dai = <&phandle port>"
+        * Get node via "sound-dai = <&phandle port>"
         * it will be used as xxx_of_node on soc_bind_dai_link()
         */
-       node = of_parse_phandle(np, "sound-dai", 0);
-       if (!node)
-               return -ENODEV;
-       *p_node = node;
+       ret = of_parse_phandle_with_args(np, "sound-dai",
+                                        "#sound-dai-cells", 0, &args);
+       if (ret)
+               return ret;
+
+       *p_node = args.np;
+
+       if (args_count)
+               *args_count = args.args_count;
 
-       /* get dai->name */
+       /* Get dai->name */
        ret = snd_soc_of_get_dai_name(np, name);
        if (ret < 0)
                return ret;
 
-       /* parse TDM slot */
+       /* Parse TDM slot */
        ret = snd_soc_of_parse_tdm_slot(np, &dai->slots, &dai->slot_width);
        if (ret)
                return ret;
 
        /*
-        * dai->sysclk come from
-        *  "clocks = <&xxx>" (if system has common clock)
+        * Parse dai->sysclk come from "clocks = <&xxx>"
+        * (if system has common clock)
         *  or "system-clock-frequency = <xxx>"
         *  or device's module clock.
         */
@@ -155,7 +218,7 @@ asoc_simple_card_sub_parse_of(struct device_node *np,
        } else if (!of_property_read_u32(np, "system-clock-frequency", &val)) {
                dai->sysclk = val;
        } else {
-               clk = of_clk_get(node, 0);
+               clk = of_clk_get(args.np, 0);
                if (!IS_ERR(clk))
                        dai->sysclk = clk_get_rate(clk);
        }
@@ -163,12 +226,14 @@ asoc_simple_card_sub_parse_of(struct device_node *np,
        return 0;
 }
 
-static int simple_card_dai_link_of(struct device_node *node,
-                                  struct device *dev,
-                                  struct snd_soc_dai_link *dai_link,
-                                  struct simple_dai_props *dai_props,
-                                  bool is_top_level_node)
+static int asoc_simple_card_dai_link_of(struct device_node *node,
+                                       struct simple_card_data *priv,
+                                       int idx,
+                                       bool is_top_level_node)
 {
+       struct device *dev = simple_priv_to_dev(priv);
+       struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, idx);
+       struct simple_dai_props *dai_props = simple_priv_to_props(priv, idx);
        struct device_node *np = NULL;
        struct device_node *bitclkmaster = NULL;
        struct device_node *framemaster = NULL;
@@ -176,8 +241,9 @@ static int simple_card_dai_link_of(struct device_node *node,
        char *name;
        char prop[128];
        char *prefix = "";
-       int ret;
+       int ret, cpu_args;
 
+       /* For single DAI link & old style of DT node */
        if (is_top_level_node)
                prefix = "simple-audio-card,";
 
@@ -195,7 +261,8 @@ static int simple_card_dai_link_of(struct device_node *node,
 
        ret = asoc_simple_card_sub_parse_of(np, &dai_props->cpu_dai,
                                            &dai_link->cpu_of_node,
-                                           &dai_link->cpu_dai_name);
+                                           &dai_link->cpu_dai_name,
+                                           &cpu_args);
        if (ret < 0)
                goto dai_link_of_err;
 
@@ -226,14 +293,16 @@ static int simple_card_dai_link_of(struct device_node *node,
 
        ret = asoc_simple_card_sub_parse_of(np, &dai_props->codec_dai,
                                            &dai_link->codec_of_node,
-                                           &dai_link->codec_dai_name);
+                                           &dai_link->codec_dai_name, NULL);
        if (ret < 0)
                goto dai_link_of_err;
 
        if (strlen(prefix) && !bitclkmaster && !framemaster) {
-               /* No dai-link level and master setting was not found from
-                  sound node level, revert back to legacy DT parsing and
-                  take the settings from codec node. */
+               /*
+                * No DAI link level and master setting was found
+                * from sound node level, revert back to legacy DT
+                * parsing and take the settings from codec node.
+                */
                dev_dbg(dev, "%s: Revert to legacy daifmt parsing\n",
                        __func__);
                dai_props->cpu_dai.fmt = dai_props->codec_dai.fmt =
@@ -262,10 +331,10 @@ static int simple_card_dai_link_of(struct device_node *node,
                goto dai_link_of_err;
        }
 
-       /* simple-card assumes platform == cpu */
+       /* Simple Card assumes platform == cpu */
        dai_link->platform_of_node = dai_link->cpu_of_node;
 
-       /* Link name is created from CPU/CODEC dai name */
+       /* DAI link name is created from CPU/CODEC dai name */
        name = devm_kzalloc(dev,
                            strlen(dai_link->cpu_dai_name)   +
                            strlen(dai_link->codec_dai_name) + 2,
@@ -274,6 +343,7 @@ static int simple_card_dai_link_of(struct device_node *node,
                                dai_link->codec_dai_name);
        dai_link->name = dai_link->stream_name = name;
        dai_link->ops = &asoc_simple_card_ops;
+       dai_link->init = asoc_simple_card_dai_init;
 
        dev_dbg(dev, "\tname : %s\n", dai_link->stream_name);
        dev_dbg(dev, "\tcpu : %s / %04x / %d\n",
@@ -285,6 +355,18 @@ static int simple_card_dai_link_of(struct device_node *node,
                dai_props->codec_dai.fmt,
                dai_props->codec_dai.sysclk);
 
+       /*
+        * In soc_bind_dai_link() will check cpu name after
+        * of_node matching if dai_link has cpu_dai_name.
+        * but, it will never match if name was created by
+        * fmt_single_name() remove cpu_dai_name if cpu_args
+        * was 0. See:
+        *      fmt_single_name()
+        *      fmt_multiple_name()
+        */
+       if (!cpu_args)
+               dai_link->cpu_dai_name = NULL;
+
 dai_link_of_err:
        if (np)
                of_node_put(np);
@@ -296,19 +378,19 @@ dai_link_of_err:
 }
 
 static int asoc_simple_card_parse_of(struct device_node *node,
-                                    struct simple_card_data *priv,
-                                    struct device *dev,
-                                    int multi)
+                                    struct simple_card_data *priv)
 {
-       struct snd_soc_dai_link *dai_link = priv->snd_card.dai_link;
-       struct simple_dai_props *dai_props = priv->dai_props;
+       struct device *dev = simple_priv_to_dev(priv);
        u32 val;
        int ret;
 
-       /* parsing the card name from DT */
+       if (!node)
+               return -EINVAL;
+
+       /* Parse the card name from DT */
        snd_soc_of_parse_card_name(&priv->snd_card, "simple-audio-card,name");
 
-       /* off-codec widgets */
+       /* The off-codec widgets */
        if (of_property_read_bool(node, "simple-audio-card,widgets")) {
                ret = snd_soc_of_parse_audio_simple_widgets(&priv->snd_card,
                                        "simple-audio-card,widgets");
@@ -332,32 +414,45 @@ static int asoc_simple_card_parse_of(struct device_node *node,
        dev_dbg(dev, "New simple-card: %s\n", priv->snd_card.name ?
                priv->snd_card.name : "");
 
-       if (multi) {
+       /* Single/Muti DAI link(s) & New style of DT node */
+       if (of_get_child_by_name(node, "simple-audio-card,dai-link")) {
                struct device_node *np = NULL;
-               int i;
-               for (i = 0; (np = of_get_next_child(node, np)); i++) {
+               int i = 0;
+
+               for_each_child_of_node(node, np) {
                        dev_dbg(dev, "\tlink %d:\n", i);
-                       ret = simple_card_dai_link_of(np, dev, dai_link + i,
-                                                     dai_props + i, false);
+                       ret = asoc_simple_card_dai_link_of(np, priv,
+                                                          i, false);
                        if (ret < 0) {
                                of_node_put(np);
                                return ret;
                        }
+                       i++;
                }
        } else {
-               ret = simple_card_dai_link_of(node, dev, dai_link, dai_props,
-                                             true);
+               /* For single DAI link & old style of DT node */
+               ret = asoc_simple_card_dai_link_of(node, priv, 0, true);
                if (ret < 0)
                        return ret;
        }
 
+       priv->gpio_hp_det = of_get_named_gpio(node,
+                               "simple-audio-card,hp-det-gpio", 0);
+       if (priv->gpio_hp_det == -EPROBE_DEFER)
+               return -EPROBE_DEFER;
+
+       priv->gpio_mic_det = of_get_named_gpio(node,
+                               "simple-audio-card,mic-det-gpio", 0);
+       if (priv->gpio_mic_det == -EPROBE_DEFER)
+               return -EPROBE_DEFER;
+
        if (!priv->snd_card.name)
                priv->snd_card.name = priv->snd_card.dai_link->name;
 
        return 0;
 }
 
-/* update the reference count of the devices nodes at end of probe */
+/* Decrease the reference count of the device nodes */
 static int asoc_simple_card_unref(struct platform_device *pdev)
 {
        struct snd_soc_card *card = platform_get_drvdata(pdev);
@@ -384,34 +479,32 @@ static int asoc_simple_card_probe(struct platform_device *pdev)
        struct snd_soc_dai_link *dai_link;
        struct device_node *np = pdev->dev.of_node;
        struct device *dev = &pdev->dev;
-       int num_links, multi, ret;
+       int num_links, ret;
 
-       /* get the number of DAI links */
-       if (np && of_get_child_by_name(np, "simple-audio-card,dai-link")) {
+       /* Get the number of DAI links */
+       if (np && of_get_child_by_name(np, "simple-audio-card,dai-link"))
                num_links = of_get_child_count(np);
-               multi = 1;
-       } else {
+       else
                num_links = 1;
-               multi = 0;
-       }
 
-       /* allocate the private data and the DAI link array */
+       /* Allocate the private data and the DAI link array */
        priv = devm_kzalloc(dev,
                        sizeof(*priv) + sizeof(*dai_link) * num_links,
                        GFP_KERNEL);
        if (!priv)
                return -ENOMEM;
 
-       /*
-        * init snd_soc_card
-        */
+       /* Init snd_soc_card */
        priv->snd_card.owner = THIS_MODULE;
        priv->snd_card.dev = dev;
        dai_link = priv->dai_link;
        priv->snd_card.dai_link = dai_link;
        priv->snd_card.num_links = num_links;
 
-       /* get room for the other properties */
+       priv->gpio_hp_det = -ENOENT;
+       priv->gpio_mic_det = -ENOENT;
+
+       /* Get room for the other properties */
        priv->dai_props = devm_kzalloc(dev,
                        sizeof(*priv->dai_props) * num_links,
                        GFP_KERNEL);
@@ -420,25 +513,13 @@ static int asoc_simple_card_probe(struct platform_device *pdev)
 
        if (np && of_device_is_available(np)) {
 
-               ret = asoc_simple_card_parse_of(np, priv, dev, multi);
+               ret = asoc_simple_card_parse_of(np, priv);
                if (ret < 0) {
                        if (ret != -EPROBE_DEFER)
                                dev_err(dev, "parse error %d\n", ret);
                        goto err;
                }
 
-               /*
-                * soc_bind_dai_link() will check cpu name
-                * after of_node matching if dai_link has cpu_dai_name.
-                * but, it will never match if name was created by fmt_single_name()
-                * remove cpu_dai_name to escape name matching.
-                * see
-                *      fmt_single_name()
-                *      fmt_multiple_name()
-                */
-               if (num_links == 1)
-                       dai_link->cpu_dai_name = NULL;
-
        } else {
                struct asoc_simple_card_info *cinfo;
 
@@ -464,6 +545,7 @@ static int asoc_simple_card_probe(struct platform_device *pdev)
                dai_link->codec_name    = cinfo->codec;
                dai_link->cpu_dai_name  = cinfo->cpu_dai.name;
                dai_link->codec_dai_name = cinfo->codec_dai.name;
+               dai_link->init          = asoc_simple_card_dai_init;
                memcpy(&priv->dai_props->cpu_dai, &cinfo->cpu_dai,
                                        sizeof(priv->dai_props->cpu_dai));
                memcpy(&priv->dai_props->codec_dai, &cinfo->codec_dai,
@@ -473,11 +555,6 @@ static int asoc_simple_card_probe(struct platform_device *pdev)
                priv->dai_props->codec_dai.fmt  |= cinfo->daifmt;
        }
 
-       /*
-        * init snd_soc_dai_link
-        */
-       dai_link->init = asoc_simple_card_dai_init;
-
        snd_soc_card_set_drvdata(&priv->snd_card, priv);
 
        ret = devm_snd_soc_register_card(&pdev->dev, &priv->snd_card);
@@ -491,6 +568,16 @@ err:
 
 static int asoc_simple_card_remove(struct platform_device *pdev)
 {
+       struct snd_soc_card *card = platform_get_drvdata(pdev);
+       struct simple_card_data *priv = snd_soc_card_get_drvdata(card);
+
+       if (gpio_is_valid(priv->gpio_hp_det))
+               snd_soc_jack_free_gpios(&simple_card_hp_jack, 1,
+                                       &simple_card_hp_jack_gpio);
+       if (gpio_is_valid(priv->gpio_mic_det))
+               snd_soc_jack_free_gpios(&simple_card_mic_jack, 1,
+                                       &simple_card_mic_jack_gpio);
+
        return asoc_simple_card_unref(pdev);
 }
 
index 7acbfc43a0c6df74404e456c05f2590867c0410b..f841786dad155c56904656d51114068e086654be 100644 (file)
@@ -2,7 +2,8 @@
 snd-soc-sst-dsp-objs := sst-dsp.o sst-firmware.o
 snd-soc-sst-acpi-objs := sst-acpi.o
 
-snd-soc-sst-mfld-platform-objs := sst-mfld-platform-pcm.o sst-mfld-platform-compress.o
+snd-soc-sst-mfld-platform-objs := sst-mfld-platform-pcm.o \
+       sst-mfld-platform-compress.o sst-atom-controls.o
 snd-soc-mfld-machine-objs := mfld_machine.o
 
 obj-$(CONFIG_SND_SST_MFLD_PLATFORM) += snd-soc-sst-mfld-platform.o
index b8b8af571ef169307e8b0e1efb68b5435c97df66..d52681e7225e72737145463f5db7664f6c6037af 100644 (file)
@@ -139,6 +139,7 @@ static struct snd_soc_card byt_max98090_card = {
        .num_dapm_routes = ARRAY_SIZE(byt_max98090_audio_map),
        .controls = byt_max98090_controls,
        .num_controls = ARRAY_SIZE(byt_max98090_controls),
+       .fully_routed = true,
 };
 
 static int byt_max98090_probe(struct platform_device *pdev)
index 234a58de3c53b0f4e758fa04e93db5012fcfda0b..e03abdf21c1bc3f4dbff62f4cd46d80327dbadd1 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/platform_device.h>
 #include <linux/acpi.h>
 #include <linux/device.h>
+#include <linux/dmi.h>
 #include <linux/slab.h>
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
@@ -36,8 +37,6 @@ static const struct snd_soc_dapm_widget byt_rt5640_widgets[] = {
 static const struct snd_soc_dapm_route byt_rt5640_audio_map[] = {
        {"Headset Mic", NULL, "MICBIAS1"},
        {"IN2P", NULL, "Headset Mic"},
-       {"IN2N", NULL, "Headset Mic"},
-       {"DMIC1", NULL, "Internal Mic"},
        {"Headphone", NULL, "HPOL"},
        {"Headphone", NULL, "HPOR"},
        {"Speaker", NULL, "SPOLP"},
@@ -46,6 +45,31 @@ static const struct snd_soc_dapm_route byt_rt5640_audio_map[] = {
        {"Speaker", NULL, "SPORN"},
 };
 
+static const struct snd_soc_dapm_route byt_rt5640_intmic_dmic1_map[] = {
+       {"DMIC1", NULL, "Internal Mic"},
+};
+
+static const struct snd_soc_dapm_route byt_rt5640_intmic_dmic2_map[] = {
+       {"DMIC2", NULL, "Internal Mic"},
+};
+
+static const struct snd_soc_dapm_route byt_rt5640_intmic_in1_map[] = {
+       {"Internal Mic", NULL, "MICBIAS1"},
+       {"IN1P", NULL, "Internal Mic"},
+};
+
+enum {
+       BYT_RT5640_DMIC1_MAP,
+       BYT_RT5640_DMIC2_MAP,
+       BYT_RT5640_IN1_MAP,
+};
+
+#define BYT_RT5640_MAP(quirk)  ((quirk) & 0xff)
+#define BYT_RT5640_DMIC_EN     BIT(16)
+
+static unsigned long byt_rt5640_quirk = BYT_RT5640_DMIC1_MAP |
+                                       BYT_RT5640_DMIC_EN;
+
 static const struct snd_kcontrol_new byt_rt5640_controls[] = {
        SOC_DAPM_PIN_SWITCH("Headphone"),
        SOC_DAPM_PIN_SWITCH("Headset Mic"),
@@ -77,12 +101,41 @@ static int byt_rt5640_hw_params(struct snd_pcm_substream *substream,
        return 0;
 }
 
+static int byt_rt5640_quirk_cb(const struct dmi_system_id *id)
+{
+       byt_rt5640_quirk = (unsigned long)id->driver_data;
+       return 1;
+}
+
+static const struct dmi_system_id byt_rt5640_quirk_table[] = {
+       {
+               .callback = byt_rt5640_quirk_cb,
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "T100TA"),
+               },
+               .driver_data = (unsigned long *)BYT_RT5640_IN1_MAP,
+       },
+       {
+               .callback = byt_rt5640_quirk_cb,
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "DellInc."),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "Venue 8 Pro 5830"),
+               },
+               .driver_data = (unsigned long *)(BYT_RT5640_DMIC2_MAP |
+                                                BYT_RT5640_DMIC_EN),
+       },
+       {}
+};
+
 static int byt_rt5640_init(struct snd_soc_pcm_runtime *runtime)
 {
        int ret;
        struct snd_soc_codec *codec = runtime->codec;
        struct snd_soc_dapm_context *dapm = &codec->dapm;
        struct snd_soc_card *card = runtime->card;
+       const struct snd_soc_dapm_route *custom_map;
+       int num_routes;
 
        card->dapm.idle_bias_off = true;
 
@@ -93,6 +146,31 @@ static int byt_rt5640_init(struct snd_soc_pcm_runtime *runtime)
                return ret;
        }
 
+       dmi_check_system(byt_rt5640_quirk_table);
+       switch (BYT_RT5640_MAP(byt_rt5640_quirk)) {
+       case BYT_RT5640_IN1_MAP:
+               custom_map = byt_rt5640_intmic_in1_map;
+               num_routes = ARRAY_SIZE(byt_rt5640_intmic_in1_map);
+               break;
+       case BYT_RT5640_DMIC2_MAP:
+               custom_map = byt_rt5640_intmic_dmic2_map;
+               num_routes = ARRAY_SIZE(byt_rt5640_intmic_dmic2_map);
+               break;
+       default:
+               custom_map = byt_rt5640_intmic_dmic1_map;
+               num_routes = ARRAY_SIZE(byt_rt5640_intmic_dmic1_map);
+       }
+
+       ret = snd_soc_dapm_add_routes(dapm, custom_map, num_routes);
+       if (ret)
+               return ret;
+
+       if (byt_rt5640_quirk & BYT_RT5640_DMIC_EN) {
+               ret = rt5640_dmic_enable(codec, 0, 0);
+               if (ret)
+                       return ret;
+       }
+
        snd_soc_dapm_ignore_suspend(dapm, "HPOL");
        snd_soc_dapm_ignore_suspend(dapm, "HPOR");
 
@@ -131,6 +209,7 @@ static struct snd_soc_card byt_rt5640_card = {
        .num_dapm_widgets = ARRAY_SIZE(byt_rt5640_widgets),
        .dapm_routes = byt_rt5640_audio_map,
        .num_dapm_routes = ARRAY_SIZE(byt_rt5640_audio_map),
+       .fully_routed = true,
 };
 
 static int byt_rt5640_probe(struct platform_device *pdev)
diff --git a/sound/soc/intel/sst-atom-controls.c b/sound/soc/intel/sst-atom-controls.c
new file mode 100644 (file)
index 0000000..7104a34
--- /dev/null
@@ -0,0 +1,218 @@
+/*
+ *  sst-atom-controls.c - Intel MID Platform driver DPCM ALSA controls for Mrfld
+ *
+ *  Copyright (C) 2013-14 Intel Corp
+ *  Author: Omair Mohammed Abdullah <omair.m.abdullah@intel.com>
+ *     Vinod Koul <vinod.koul@intel.com>
+ *  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; version 2 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.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ */
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/slab.h>
+#include <sound/soc.h>
+#include <sound/tlv.h>
+#include "sst-mfld-platform.h"
+#include "sst-atom-controls.h"
+
+static int sst_fill_byte_control(struct sst_data *drv,
+                                        u8 ipc_msg, u8 block,
+                                        u8 task_id, u8 pipe_id,
+                                        u16 len, void *cmd_data)
+{
+       struct snd_sst_bytes_v2 *byte_data = drv->byte_stream;
+
+       byte_data->type = SST_CMD_BYTES_SET;
+       byte_data->ipc_msg = ipc_msg;
+       byte_data->block = block;
+       byte_data->task_id = task_id;
+       byte_data->pipe_id = pipe_id;
+
+       if (len > SST_MAX_BIN_BYTES - sizeof(*byte_data)) {
+               dev_err(&drv->pdev->dev, "command length too big (%u)", len);
+               return -EINVAL;
+       }
+       byte_data->len = len;
+       memcpy(byte_data->bytes, cmd_data, len);
+       print_hex_dump_bytes("writing to lpe: ", DUMP_PREFIX_OFFSET,
+                            byte_data, len + sizeof(*byte_data));
+       return 0;
+}
+
+static int sst_fill_and_send_cmd_unlocked(struct sst_data *drv,
+                                u8 ipc_msg, u8 block, u8 task_id, u8 pipe_id,
+                                void *cmd_data, u16 len)
+{
+       int ret = 0;
+
+       ret = sst_fill_byte_control(drv, ipc_msg,
+                               block, task_id, pipe_id, len, cmd_data);
+       if (ret < 0)
+               return ret;
+       return sst->ops->send_byte_stream(sst->dev, drv->byte_stream);
+}
+
+/**
+ * sst_fill_and_send_cmd - generate the IPC message and send it to the FW
+ * @ipc_msg:   type of IPC (CMD, SET_PARAMS, GET_PARAMS)
+ * @cmd_data:  the IPC payload
+ */
+static int sst_fill_and_send_cmd(struct sst_data *drv,
+                                u8 ipc_msg, u8 block, u8 task_id, u8 pipe_id,
+                                void *cmd_data, u16 len)
+{
+       int ret;
+
+       mutex_lock(&drv->lock);
+       ret = sst_fill_and_send_cmd_unlocked(drv, ipc_msg, block,
+                                       task_id, pipe_id, cmd_data, len);
+       mutex_unlock(&drv->lock);
+
+       return ret;
+}
+
+static int sst_send_algo_cmd(struct sst_data *drv,
+                             struct sst_algo_control *bc)
+{
+       int len, ret = 0;
+       struct sst_cmd_set_params *cmd;
+
+       /*bc->max includes sizeof algos + length field*/
+       len = sizeof(cmd->dst) + sizeof(cmd->command_id) + bc->max;
+
+       cmd = kzalloc(len, GFP_KERNEL);
+       if (cmd == NULL)
+               return -ENOMEM;
+
+       SST_FILL_DESTINATION(2, cmd->dst, bc->pipe_id, bc->module_id);
+       cmd->command_id = bc->cmd_id;
+       memcpy(cmd->params, bc->params, bc->max);
+
+       ret = sst_fill_and_send_cmd_unlocked(drv, SST_IPC_IA_SET_PARAMS,
+                               SST_FLAG_BLOCKED, bc->task_id, 0, cmd, len);
+       kfree(cmd);
+       return ret;
+}
+
+static int sst_algo_bytes_ctl_info(struct snd_kcontrol *kcontrol,
+                           struct snd_ctl_elem_info *uinfo)
+{
+       struct sst_algo_control *bc = (void *)kcontrol->private_value;
+
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES;
+       uinfo->count = bc->max;
+
+       return 0;
+}
+
+static int sst_algo_control_get(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_value *ucontrol)
+{
+       struct sst_algo_control *bc = (void *)kcontrol->private_value;
+       struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+
+       switch (bc->type) {
+       case SST_ALGO_PARAMS:
+               memcpy(ucontrol->value.bytes.data, bc->params, bc->max);
+               break;
+       default:
+               dev_err(component->dev, "Invalid Input- algo type:%d\n",
+                               bc->type);
+               return -EINVAL;
+
+       }
+       return 0;
+}
+
+static int sst_algo_control_set(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_value *ucontrol)
+{
+       int ret = 0;
+       struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+       struct sst_data *drv = snd_soc_component_get_drvdata(cmpnt);
+       struct sst_algo_control *bc = (void *)kcontrol->private_value;
+
+       dev_dbg(cmpnt->dev, "control_name=%s\n", kcontrol->id.name);
+       mutex_lock(&drv->lock);
+       switch (bc->type) {
+       case SST_ALGO_PARAMS:
+               memcpy(bc->params, ucontrol->value.bytes.data, bc->max);
+               break;
+       default:
+               mutex_unlock(&drv->lock);
+               dev_err(cmpnt->dev, "Invalid Input- algo type:%d\n",
+                               bc->type);
+               return -EINVAL;
+       }
+       /*if pipe is enabled, need to send the algo params from here*/
+       if (bc->w && bc->w->power)
+               ret = sst_send_algo_cmd(drv, bc);
+       mutex_unlock(&drv->lock);
+
+       return ret;
+}
+
+static const struct snd_kcontrol_new sst_algo_controls[] = {
+       SST_ALGO_KCONTROL_BYTES("media_loop1_out", "fir", 272, SST_MODULE_ID_FIR_24,
+                SST_PATH_INDEX_MEDIA_LOOP1_OUT, 0, SST_TASK_SBA, SBA_VB_SET_FIR),
+       SST_ALGO_KCONTROL_BYTES("media_loop1_out", "iir", 300, SST_MODULE_ID_IIR_24,
+               SST_PATH_INDEX_MEDIA_LOOP1_OUT, 0, SST_TASK_SBA, SBA_VB_SET_IIR),
+       SST_ALGO_KCONTROL_BYTES("media_loop1_out", "mdrp", 286, SST_MODULE_ID_MDRP,
+               SST_PATH_INDEX_MEDIA_LOOP1_OUT, 0, SST_TASK_SBA, SBA_SET_MDRP),
+       SST_ALGO_KCONTROL_BYTES("media_loop2_out", "fir", 272, SST_MODULE_ID_FIR_24,
+               SST_PATH_INDEX_MEDIA_LOOP2_OUT, 0, SST_TASK_SBA, SBA_VB_SET_FIR),
+       SST_ALGO_KCONTROL_BYTES("media_loop2_out", "iir", 300, SST_MODULE_ID_IIR_24,
+               SST_PATH_INDEX_MEDIA_LOOP2_OUT, 0, SST_TASK_SBA, SBA_VB_SET_IIR),
+       SST_ALGO_KCONTROL_BYTES("media_loop2_out", "mdrp", 286, SST_MODULE_ID_MDRP,
+               SST_PATH_INDEX_MEDIA_LOOP2_OUT, 0, SST_TASK_SBA, SBA_SET_MDRP),
+       SST_ALGO_KCONTROL_BYTES("sprot_loop_out", "lpro", 192, SST_MODULE_ID_SPROT,
+               SST_PATH_INDEX_SPROT_LOOP_OUT, 0, SST_TASK_SBA, SBA_VB_LPRO),
+       SST_ALGO_KCONTROL_BYTES("codec_in0", "dcr", 52, SST_MODULE_ID_FILT_DCR,
+               SST_PATH_INDEX_CODEC_IN0, 0, SST_TASK_SBA, SBA_VB_SET_IIR),
+       SST_ALGO_KCONTROL_BYTES("codec_in1", "dcr", 52, SST_MODULE_ID_FILT_DCR,
+               SST_PATH_INDEX_CODEC_IN1, 0, SST_TASK_SBA, SBA_VB_SET_IIR),
+
+};
+
+static int sst_algo_control_init(struct device *dev)
+{
+       int i = 0;
+       struct sst_algo_control *bc;
+       /*allocate space to cache the algo parameters in the driver*/
+       for (i = 0; i < ARRAY_SIZE(sst_algo_controls); i++) {
+               bc = (struct sst_algo_control *)sst_algo_controls[i].private_value;
+               bc->params = devm_kzalloc(dev, bc->max, GFP_KERNEL);
+               if (bc->params == NULL)
+                       return -ENOMEM;
+       }
+       return 0;
+}
+
+int sst_dsp_init_v2_dpcm(struct snd_soc_platform *platform)
+{
+       int ret = 0;
+       struct sst_data *drv = snd_soc_platform_get_drvdata(platform);
+
+       drv->byte_stream = devm_kzalloc(platform->dev,
+                                       SST_MAX_BIN_BYTES, GFP_KERNEL);
+       if (!drv->byte_stream)
+               return -ENOMEM;
+
+       /*Initialize algo control params*/
+       ret = sst_algo_control_init(platform->dev);
+       if (ret)
+               return ret;
+       ret = snd_soc_add_platform_controls(platform, sst_algo_controls,
+                       ARRAY_SIZE(sst_algo_controls));
+       return ret;
+}
index 14063ab8c7c5a8df912655319d0509247b3bf81a..a73e894b175c03836e4aa8d437a6fe3ee35de907 100644 (file)
@@ -1,4 +1,6 @@
 /*
+ *  sst-atom-controls.h - Intel MID Platform driver header file
+ *
  *  Copyright (C) 2013-14 Intel Corp
  *  Author: Ramesh Babu <ramesh.babu.koul@intel.com>
  *     Omair M Abdullah <omair.m.abdullah@intel.com>
  *
  */
 
-#ifndef __SST_CONTROLS_V2_H__
-#define __SST_CONTROLS_V2_H__
+#ifndef __SST_ATOM_CONTROLS_H__
+#define __SST_ATOM_CONTROLS_H__
 
 enum {
        MERR_DPCM_AUDIO = 0,
        MERR_DPCM_COMPR,
 };
 
+/* define a bit for each mixer input */
+#define SST_MIX_IP(x)          (x)
+
+#define SST_IP_CODEC0          SST_MIX_IP(2)
+#define SST_IP_CODEC1          SST_MIX_IP(3)
+#define SST_IP_LOOP0           SST_MIX_IP(4)
+#define SST_IP_LOOP1           SST_MIX_IP(5)
+#define SST_IP_LOOP2           SST_MIX_IP(6)
+#define SST_IP_PROBE           SST_MIX_IP(7)
+#define SST_IP_VOIP            SST_MIX_IP(12)
+#define SST_IP_PCM0            SST_MIX_IP(13)
+#define SST_IP_PCM1            SST_MIX_IP(14)
+#define SST_IP_MEDIA0          SST_MIX_IP(17)
+#define SST_IP_MEDIA1          SST_MIX_IP(18)
+#define SST_IP_MEDIA2          SST_MIX_IP(19)
+#define SST_IP_MEDIA3          SST_MIX_IP(20)
+
+#define SST_IP_LAST            SST_IP_MEDIA3
+
+#define SST_SWM_INPUT_COUNT    (SST_IP_LAST + 1)
+#define SST_CMD_SWM_MAX_INPUTS 6
+
+#define SST_PATH_ID_SHIFT      8
+#define SST_DEFAULT_LOCATION_ID        0xFFFF
+#define SST_DEFAULT_CELL_NBR   0xFF
+#define SST_DEFAULT_MODULE_ID  0xFFFF
+
+/*
+ * Audio DSP Path Ids. Specified by the audio DSP FW
+ */
+enum sst_path_index {
+       SST_PATH_INDEX_CODEC_OUT0               = (0x02 << SST_PATH_ID_SHIFT),
+       SST_PATH_INDEX_CODEC_OUT1               = (0x03 << SST_PATH_ID_SHIFT),
+
+       SST_PATH_INDEX_SPROT_LOOP_OUT           = (0x04 << SST_PATH_ID_SHIFT),
+       SST_PATH_INDEX_MEDIA_LOOP1_OUT          = (0x05 << SST_PATH_ID_SHIFT),
+       SST_PATH_INDEX_MEDIA_LOOP2_OUT          = (0x06 << SST_PATH_ID_SHIFT),
+
+       SST_PATH_INDEX_VOIP_OUT                 = (0x0C << SST_PATH_ID_SHIFT),
+       SST_PATH_INDEX_PCM0_OUT                 = (0x0D << SST_PATH_ID_SHIFT),
+       SST_PATH_INDEX_PCM1_OUT                 = (0x0E << SST_PATH_ID_SHIFT),
+       SST_PATH_INDEX_PCM2_OUT                 = (0x0F << SST_PATH_ID_SHIFT),
+
+       SST_PATH_INDEX_MEDIA0_OUT               = (0x12 << SST_PATH_ID_SHIFT),
+       SST_PATH_INDEX_MEDIA1_OUT               = (0x13 << SST_PATH_ID_SHIFT),
+
+
+       /* Start of input paths */
+       SST_PATH_INDEX_CODEC_IN0                = (0x82 << SST_PATH_ID_SHIFT),
+       SST_PATH_INDEX_CODEC_IN1                = (0x83 << SST_PATH_ID_SHIFT),
+
+       SST_PATH_INDEX_SPROT_LOOP_IN            = (0x84 << SST_PATH_ID_SHIFT),
+       SST_PATH_INDEX_MEDIA_LOOP1_IN           = (0x85 << SST_PATH_ID_SHIFT),
+       SST_PATH_INDEX_MEDIA_LOOP2_IN           = (0x86 << SST_PATH_ID_SHIFT),
+
+       SST_PATH_INDEX_VOIP_IN                  = (0x8C << SST_PATH_ID_SHIFT),
+
+       SST_PATH_INDEX_PCM0_IN                  = (0x8D << SST_PATH_ID_SHIFT),
+       SST_PATH_INDEX_PCM1_IN                  = (0x8E << SST_PATH_ID_SHIFT),
+
+       SST_PATH_INDEX_MEDIA0_IN                = (0x8F << SST_PATH_ID_SHIFT),
+       SST_PATH_INDEX_MEDIA1_IN                = (0x90 << SST_PATH_ID_SHIFT),
+       SST_PATH_INDEX_MEDIA2_IN                = (0x91 << SST_PATH_ID_SHIFT),
+
+       SST_PATH_INDEX_MEDIA3_IN                = (0x9C << SST_PATH_ID_SHIFT),
+
+       SST_PATH_INDEX_RESERVED                 = (0xFF << SST_PATH_ID_SHIFT),
+};
+
+/*
+ * path IDs
+ */
+enum sst_swm_inputs {
+       SST_SWM_IN_CODEC0       = (SST_PATH_INDEX_CODEC_IN0       | SST_DEFAULT_CELL_NBR),
+       SST_SWM_IN_CODEC1       = (SST_PATH_INDEX_CODEC_IN1       | SST_DEFAULT_CELL_NBR),
+       SST_SWM_IN_SPROT_LOOP   = (SST_PATH_INDEX_SPROT_LOOP_IN   | SST_DEFAULT_CELL_NBR),
+       SST_SWM_IN_MEDIA_LOOP1  = (SST_PATH_INDEX_MEDIA_LOOP1_IN  | SST_DEFAULT_CELL_NBR),
+       SST_SWM_IN_MEDIA_LOOP2  = (SST_PATH_INDEX_MEDIA_LOOP2_IN  | SST_DEFAULT_CELL_NBR),
+       SST_SWM_IN_VOIP         = (SST_PATH_INDEX_VOIP_IN         | SST_DEFAULT_CELL_NBR),
+       SST_SWM_IN_PCM0         = (SST_PATH_INDEX_PCM0_IN         | SST_DEFAULT_CELL_NBR),
+       SST_SWM_IN_PCM1         = (SST_PATH_INDEX_PCM1_IN         | SST_DEFAULT_CELL_NBR),
+       SST_SWM_IN_MEDIA0       = (SST_PATH_INDEX_MEDIA0_IN       | SST_DEFAULT_CELL_NBR), /* Part of Media Mixer */
+       SST_SWM_IN_MEDIA1       = (SST_PATH_INDEX_MEDIA1_IN       | SST_DEFAULT_CELL_NBR), /* Part of Media Mixer */
+       SST_SWM_IN_MEDIA2       = (SST_PATH_INDEX_MEDIA2_IN       | SST_DEFAULT_CELL_NBR), /* Part of Media Mixer */
+       SST_SWM_IN_MEDIA3       = (SST_PATH_INDEX_MEDIA3_IN       | SST_DEFAULT_CELL_NBR), /* Part of Media Mixer */
+       SST_SWM_IN_END          = (SST_PATH_INDEX_RESERVED        | SST_DEFAULT_CELL_NBR)
+};
+
+/*
+ * path IDs
+ */
+enum sst_swm_outputs {
+       SST_SWM_OUT_CODEC0      = (SST_PATH_INDEX_CODEC_OUT0      | SST_DEFAULT_CELL_NBR),
+       SST_SWM_OUT_CODEC1      = (SST_PATH_INDEX_CODEC_OUT1      | SST_DEFAULT_CELL_NBR),
+       SST_SWM_OUT_SPROT_LOOP  = (SST_PATH_INDEX_SPROT_LOOP_OUT  | SST_DEFAULT_CELL_NBR),
+       SST_SWM_OUT_MEDIA_LOOP1 = (SST_PATH_INDEX_MEDIA_LOOP1_OUT | SST_DEFAULT_CELL_NBR),
+       SST_SWM_OUT_MEDIA_LOOP2 = (SST_PATH_INDEX_MEDIA_LOOP2_OUT | SST_DEFAULT_CELL_NBR),
+       SST_SWM_OUT_VOIP        = (SST_PATH_INDEX_VOIP_OUT        | SST_DEFAULT_CELL_NBR),
+       SST_SWM_OUT_PCM0        = (SST_PATH_INDEX_PCM0_OUT        | SST_DEFAULT_CELL_NBR),
+       SST_SWM_OUT_PCM1        = (SST_PATH_INDEX_PCM1_OUT        | SST_DEFAULT_CELL_NBR),
+       SST_SWM_OUT_PCM2        = (SST_PATH_INDEX_PCM2_OUT        | SST_DEFAULT_CELL_NBR),
+       SST_SWM_OUT_MEDIA0      = (SST_PATH_INDEX_MEDIA0_OUT      | SST_DEFAULT_CELL_NBR), /* Part of Media Mixer */
+       SST_SWM_OUT_MEDIA1      = (SST_PATH_INDEX_MEDIA1_OUT      | SST_DEFAULT_CELL_NBR), /* Part of Media Mixer */
+       SST_SWM_OUT_END         = (SST_PATH_INDEX_RESERVED        | SST_DEFAULT_CELL_NBR),
+};
+
+enum sst_ipc_msg {
+       SST_IPC_IA_CMD = 1,
+       SST_IPC_IA_SET_PARAMS,
+       SST_IPC_IA_GET_PARAMS,
+};
+
+enum sst_cmd_type {
+       SST_CMD_BYTES_SET = 1,
+       SST_CMD_BYTES_GET = 2,
+};
+
+enum sst_task {
+       SST_TASK_SBA = 1,
+       SST_TASK_MMX,
+};
+
+enum sst_type {
+       SST_TYPE_CMD = 1,
+       SST_TYPE_PARAMS,
+};
+
+enum sst_flag {
+       SST_FLAG_BLOCKED = 1,
+       SST_FLAG_NONBLOCK,
+};
+
+/*
+ * Enumeration for indexing the gain cells in VB_SET_GAIN DSP command
+ */
+enum sst_gain_index {
+       /* GAIN IDs for SB task start here */
+       SST_GAIN_INDEX_CODEC_OUT0,
+       SST_GAIN_INDEX_CODEC_OUT1,
+       SST_GAIN_INDEX_CODEC_IN0,
+       SST_GAIN_INDEX_CODEC_IN1,
+
+       SST_GAIN_INDEX_SPROT_LOOP_OUT,
+       SST_GAIN_INDEX_MEDIA_LOOP1_OUT,
+       SST_GAIN_INDEX_MEDIA_LOOP2_OUT,
+
+       SST_GAIN_INDEX_PCM0_IN_LEFT,
+       SST_GAIN_INDEX_PCM0_IN_RIGHT,
+
+       SST_GAIN_INDEX_PCM1_OUT_LEFT,
+       SST_GAIN_INDEX_PCM1_OUT_RIGHT,
+       SST_GAIN_INDEX_PCM1_IN_LEFT,
+       SST_GAIN_INDEX_PCM1_IN_RIGHT,
+       SST_GAIN_INDEX_PCM2_OUT_LEFT,
+
+       SST_GAIN_INDEX_PCM2_OUT_RIGHT,
+       SST_GAIN_INDEX_VOIP_OUT,
+       SST_GAIN_INDEX_VOIP_IN,
+
+       /* Gain IDs for MMX task start here */
+       SST_GAIN_INDEX_MEDIA0_IN_LEFT,
+       SST_GAIN_INDEX_MEDIA0_IN_RIGHT,
+       SST_GAIN_INDEX_MEDIA1_IN_LEFT,
+       SST_GAIN_INDEX_MEDIA1_IN_RIGHT,
+
+       SST_GAIN_INDEX_MEDIA2_IN_LEFT,
+       SST_GAIN_INDEX_MEDIA2_IN_RIGHT,
+
+       SST_GAIN_INDEX_GAIN_END
+};
+
+/*
+ * Audio DSP module IDs specified by FW spec
+ * TODO: Update with all modules
+ */
+enum sst_module_id {
+       SST_MODULE_ID_PCM                 = 0x0001,
+       SST_MODULE_ID_MP3                 = 0x0002,
+       SST_MODULE_ID_MP24                = 0x0003,
+       SST_MODULE_ID_AAC                 = 0x0004,
+       SST_MODULE_ID_AACP                = 0x0005,
+       SST_MODULE_ID_EAACP               = 0x0006,
+       SST_MODULE_ID_WMA9                = 0x0007,
+       SST_MODULE_ID_WMA10               = 0x0008,
+       SST_MODULE_ID_WMA10P              = 0x0009,
+       SST_MODULE_ID_RA                  = 0x000A,
+       SST_MODULE_ID_DDAC3               = 0x000B,
+       SST_MODULE_ID_TRUE_HD             = 0x000C,
+       SST_MODULE_ID_HD_PLUS             = 0x000D,
+
+       SST_MODULE_ID_SRC                 = 0x0064,
+       SST_MODULE_ID_DOWNMIX             = 0x0066,
+       SST_MODULE_ID_GAIN_CELL           = 0x0067,
+       SST_MODULE_ID_SPROT               = 0x006D,
+       SST_MODULE_ID_BASS_BOOST          = 0x006E,
+       SST_MODULE_ID_STEREO_WDNG         = 0x006F,
+       SST_MODULE_ID_AV_REMOVAL          = 0x0070,
+       SST_MODULE_ID_MIC_EQ              = 0x0071,
+       SST_MODULE_ID_SPL                 = 0x0072,
+       SST_MODULE_ID_ALGO_VTSV           = 0x0073,
+       SST_MODULE_ID_NR                  = 0x0076,
+       SST_MODULE_ID_BWX                 = 0x0077,
+       SST_MODULE_ID_DRP                 = 0x0078,
+       SST_MODULE_ID_MDRP                = 0x0079,
+
+       SST_MODULE_ID_ANA                 = 0x007A,
+       SST_MODULE_ID_AEC                 = 0x007B,
+       SST_MODULE_ID_NR_SNS              = 0x007C,
+       SST_MODULE_ID_SER                 = 0x007D,
+       SST_MODULE_ID_AGC                 = 0x007E,
+
+       SST_MODULE_ID_CNI                 = 0x007F,
+       SST_MODULE_ID_CONTEXT_ALGO_AWARE  = 0x0080,
+       SST_MODULE_ID_FIR_24              = 0x0081,
+       SST_MODULE_ID_IIR_24              = 0x0082,
+
+       SST_MODULE_ID_ASRC                = 0x0083,
+       SST_MODULE_ID_TONE_GEN            = 0x0084,
+       SST_MODULE_ID_BMF                 = 0x0086,
+       SST_MODULE_ID_EDL                 = 0x0087,
+       SST_MODULE_ID_GLC                 = 0x0088,
+
+       SST_MODULE_ID_FIR_16              = 0x0089,
+       SST_MODULE_ID_IIR_16              = 0x008A,
+       SST_MODULE_ID_DNR                 = 0x008B,
+
+       SST_MODULE_ID_VIRTUALIZER         = 0x008C,
+       SST_MODULE_ID_VISUALIZATION       = 0x008D,
+       SST_MODULE_ID_LOUDNESS_OPTIMIZER  = 0x008E,
+       SST_MODULE_ID_REVERBERATION       = 0x008F,
+
+       SST_MODULE_ID_CNI_TX              = 0x0090,
+       SST_MODULE_ID_REF_LINE            = 0x0091,
+       SST_MODULE_ID_VOLUME              = 0x0092,
+       SST_MODULE_ID_FILT_DCR            = 0x0094,
+       SST_MODULE_ID_SLV                 = 0x009A,
+       SST_MODULE_ID_NLF                 = 0x009B,
+       SST_MODULE_ID_TNR                 = 0x009C,
+       SST_MODULE_ID_WNR                 = 0x009D,
+
+       SST_MODULE_ID_LOG                 = 0xFF00,
+
+       SST_MODULE_ID_TASK                = 0xFFFF,
+};
+
+enum sst_cmd {
+       SBA_IDLE                = 14,
+       SBA_VB_SET_SPEECH_PATH  = 26,
+       MMX_SET_GAIN            = 33,
+       SBA_VB_SET_GAIN         = 33,
+       FBA_VB_RX_CNI           = 35,
+       MMX_SET_GAIN_TIMECONST  = 36,
+       SBA_VB_SET_TIMECONST    = 36,
+       SBA_VB_START            = 85,
+       SBA_SET_SWM             = 114,
+       SBA_SET_MDRP            = 116,
+       SBA_HW_SET_SSP          = 117,
+       SBA_SET_MEDIA_LOOP_MAP  = 118,
+       SBA_SET_MEDIA_PATH      = 119,
+       MMX_SET_MEDIA_PATH      = 119,
+       SBA_VB_LPRO             = 126,
+       SBA_VB_SET_FIR          = 128,
+       SBA_VB_SET_IIR          = 129,
+       SBA_SET_SSP_SLOT_MAP    = 130,
+};
+
+enum sst_dsp_switch {
+       SST_SWITCH_OFF = 0,
+       SST_SWITCH_ON = 3,
+};
+
+enum sst_path_switch {
+       SST_PATH_OFF = 0,
+       SST_PATH_ON = 1,
+};
+
+enum sst_swm_state {
+       SST_SWM_OFF = 0,
+       SST_SWM_ON = 3,
+};
+
+#define SST_FILL_LOCATION_IDS(dst, cell_idx, pipe_id)          do {    \
+               dst.location_id.p.cell_nbr_idx = (cell_idx);            \
+               dst.location_id.p.path_id = (pipe_id);                  \
+       } while (0)
+#define SST_FILL_LOCATION_ID(dst, loc_id)                              (\
+       dst.location_id.f = (loc_id))
+#define SST_FILL_MODULE_ID(dst, mod_id)                                        (\
+       dst.module_id = (mod_id))
+
+#define SST_FILL_DESTINATION1(dst, id)                         do {    \
+               SST_FILL_LOCATION_ID(dst, (id) & 0xFFFF);               \
+               SST_FILL_MODULE_ID(dst, ((id) & 0xFFFF0000) >> 16);     \
+       } while (0)
+#define SST_FILL_DESTINATION2(dst, loc_id, mod_id)             do {    \
+               SST_FILL_LOCATION_ID(dst, loc_id);                      \
+               SST_FILL_MODULE_ID(dst, mod_id);                        \
+       } while (0)
+#define SST_FILL_DESTINATION3(dst, cell_idx, path_id, mod_id)  do {    \
+               SST_FILL_LOCATION_IDS(dst, cell_idx, path_id);          \
+               SST_FILL_MODULE_ID(dst, mod_id);                        \
+       } while (0)
+
+#define SST_FILL_DESTINATION(level, dst, ...)                          \
+       SST_FILL_DESTINATION##level(dst, __VA_ARGS__)
+#define SST_FILL_DEFAULT_DESTINATION(dst)                              \
+       SST_FILL_DESTINATION(2, dst, SST_DEFAULT_LOCATION_ID, SST_DEFAULT_MODULE_ID)
+
+struct sst_destination_id {
+       union sst_location_id {
+               struct {
+                       u8 cell_nbr_idx;        /* module index */
+                       u8 path_id;             /* pipe_id */
+               } __packed      p;              /* part */
+               u16             f;              /* full */
+       } __packed location_id;
+       u16        module_id;
+} __packed;
+struct sst_dsp_header {
+       struct sst_destination_id dst;
+       u16 command_id;
+       u16 length;
+} __packed;
+
+/*
+ *
+ * Common Commands
+ *
+ */
+struct sst_cmd_generic {
+       struct sst_dsp_header header;
+} __packed;
+struct sst_cmd_set_params {
+       struct sst_destination_id dst;
+       u16 command_id;
+       char params[0];
+} __packed;
+#define SST_CONTROL_NAME(xpname, xmname, xinstance, xtype) \
+       xpname " " xmname " " #xinstance " " xtype
+
+#define SST_COMBO_CONTROL_NAME(xpname, xmname, xinstance, xtype, xsubmodule) \
+       xpname " " xmname " " #xinstance " " xtype " " xsubmodule
+enum sst_algo_kcontrol_type {
+       SST_ALGO_PARAMS,
+       SST_ALGO_BYPASS,
+};
+
+struct sst_algo_control {
+       enum sst_algo_kcontrol_type type;
+       int max;
+       u16 module_id;
+       u16 pipe_id;
+       u16 task_id;
+       u16 cmd_id;
+       bool bypass;
+       unsigned char *params;
+       struct snd_soc_dapm_widget *w;
+};
+
+/* size of the control = size of params + size of length field */
+#define SST_ALGO_CTL_VALUE(xcount, xtype, xpipe, xmod, xtask, xcmd)                    \
+       (struct sst_algo_control){                                                      \
+               .max = xcount + sizeof(u16), .type = xtype, .module_id = xmod,                  \
+               .pipe_id = xpipe, .task_id = xtask, .cmd_id = xcmd,                     \
+       }
+
+#define SST_ALGO_KCONTROL(xname, xcount, xmod, xpipe,                                  \
+                         xtask, xcmd, xtype, xinfo, xget, xput)                        \
+{      .iface = SNDRV_CTL_ELEM_IFACE_MIXER,                                            \
+       .name =  xname,                                                                 \
+       .info = xinfo, .get = xget, .put = xput,                                        \
+       .private_value = (unsigned long)&                                               \
+                       SST_ALGO_CTL_VALUE(xcount, xtype, xpipe,                        \
+                                          xmod, xtask, xcmd),                          \
+}
+
+#define SST_ALGO_KCONTROL_BYTES(xpname, xmname, xcount, xmod,                          \
+                               xpipe, xinstance, xtask, xcmd)                          \
+       SST_ALGO_KCONTROL(SST_CONTROL_NAME(xpname, xmname, xinstance, "params"),        \
+                         xcount, xmod, xpipe, xtask, xcmd, SST_ALGO_PARAMS,            \
+                         sst_algo_bytes_ctl_info,                                      \
+                         sst_algo_control_get, sst_algo_control_set)
+
+#define SST_ALGO_KCONTROL_BOOL(xpname, xmname, xmod, xpipe, xinstance, xtask)          \
+       SST_ALGO_KCONTROL(SST_CONTROL_NAME(xpname, xmname, xinstance, "bypass"),        \
+                         0, xmod, xpipe, xtask, 0, SST_ALGO_BYPASS,                    \
+                         snd_soc_info_bool_ext,                                        \
+                         sst_algo_control_get, sst_algo_control_set)
+
+#define SST_ALGO_BYPASS_PARAMS(xpname, xmname, xcount, xmod, xpipe,                    \
+                               xinstance, xtask, xcmd)                                 \
+       SST_ALGO_KCONTROL_BOOL(xpname, xmname, xmod, xpipe, xinstance, xtask),          \
+       SST_ALGO_KCONTROL_BYTES(xpname, xmname, xcount, xmod, xpipe, xinstance, xtask, xcmd)
+
+#define SST_COMBO_ALGO_KCONTROL_BYTES(xpname, xmname, xsubmod, xcount, xmod,           \
+                                     xpipe, xinstance, xtask, xcmd)                    \
+       SST_ALGO_KCONTROL(SST_COMBO_CONTROL_NAME(xpname, xmname, xinstance, "params",   \
+                                                xsubmod),                              \
+                         xcount, xmod, xpipe, xtask, xcmd, SST_ALGO_PARAMS,            \
+                         sst_algo_bytes_ctl_info,                                      \
+                         sst_algo_control_get, sst_algo_control_set)
+
+
+struct sst_enum {
+       bool tx;
+       unsigned short reg;
+       unsigned int max;
+       const char * const *texts;
+       struct snd_soc_dapm_widget *w;
+};
 
 #endif
index 61bf6da4bb02211f0c64593e1ba249c38b7701a1..33fc5c3abf558e52850e46c523702559e203b1bc 100644 (file)
@@ -138,11 +138,10 @@ static inline unsigned int hsw_ipc_to_mixer(u32 value)
 static int hsw_stream_volume_put(struct snd_kcontrol *kcontrol,
                                struct snd_ctl_elem_value *ucontrol)
 {
-       struct snd_soc_platform *platform = snd_soc_kcontrol_platform(kcontrol);
+       struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+       struct hsw_priv_data *pdata = snd_soc_component_get_drvdata(cmpnt);
        struct soc_mixer_control *mc =
                (struct soc_mixer_control *)kcontrol->private_value;
-       struct hsw_priv_data *pdata =
-               snd_soc_platform_get_drvdata(platform);
        struct hsw_pcm_data *pcm_data = &pdata->pcm[mc->reg];
        struct sst_hsw *hsw = pdata->hsw;
        u32 volume;
@@ -176,11 +175,10 @@ static int hsw_stream_volume_put(struct snd_kcontrol *kcontrol,
 static int hsw_stream_volume_get(struct snd_kcontrol *kcontrol,
                                struct snd_ctl_elem_value *ucontrol)
 {
-       struct snd_soc_platform *platform = snd_soc_kcontrol_platform(kcontrol);
+       struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+       struct hsw_priv_data *pdata = snd_soc_component_get_drvdata(cmpnt);
        struct soc_mixer_control *mc =
                (struct soc_mixer_control *)kcontrol->private_value;
-       struct hsw_priv_data *pdata =
-               snd_soc_platform_get_drvdata(platform);
        struct hsw_pcm_data *pcm_data = &pdata->pcm[mc->reg];
        struct sst_hsw *hsw = pdata->hsw;
        u32 volume;
@@ -208,8 +206,8 @@ static int hsw_stream_volume_get(struct snd_kcontrol *kcontrol,
 static int hsw_volume_put(struct snd_kcontrol *kcontrol,
                                struct snd_ctl_elem_value *ucontrol)
 {
-       struct snd_soc_platform *platform = snd_soc_kcontrol_platform(kcontrol);
-       struct hsw_priv_data *pdata = snd_soc_platform_get_drvdata(platform);
+       struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+       struct hsw_priv_data *pdata = snd_soc_component_get_drvdata(cmpnt);
        struct sst_hsw *hsw = pdata->hsw;
        u32 volume;
 
@@ -233,8 +231,8 @@ static int hsw_volume_put(struct snd_kcontrol *kcontrol,
 static int hsw_volume_get(struct snd_kcontrol *kcontrol,
                                struct snd_ctl_elem_value *ucontrol)
 {
-       struct snd_soc_platform *platform = snd_soc_kcontrol_platform(kcontrol);
-       struct hsw_priv_data *pdata = snd_soc_platform_get_drvdata(platform);
+       struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+       struct hsw_priv_data *pdata = snd_soc_component_get_drvdata(cmpnt);
        struct sst_hsw *hsw = pdata->hsw;
        unsigned int volume = 0;
 
@@ -778,20 +776,11 @@ static const struct snd_soc_dapm_route graph[] = {
 
 static int hsw_pcm_probe(struct snd_soc_platform *platform)
 {
+       struct hsw_priv_data *priv_data = snd_soc_platform_get_drvdata(platform);
        struct sst_pdata *pdata = dev_get_platdata(platform->dev);
-       struct hsw_priv_data *priv_data;
-       struct device *dma_dev;
+       struct device *dma_dev = pdata->dma_dev;
        int i, ret = 0;
 
-       if (!pdata)
-               return -ENODEV;
-
-       dma_dev = pdata->dma_dev;
-
-       priv_data = devm_kzalloc(platform->dev, sizeof(*priv_data), GFP_KERNEL);
-       priv_data->hsw = pdata->dsp;
-       snd_soc_platform_set_drvdata(platform, priv_data);
-
        /* allocate DSP buffer page tables */
        for (i = 0; i < ARRAY_SIZE(hsw_dais); i++) {
 
@@ -848,27 +837,38 @@ static struct snd_soc_platform_driver hsw_soc_platform = {
        .ops            = &hsw_pcm_ops,
        .pcm_new        = hsw_pcm_new,
        .pcm_free       = hsw_pcm_free,
-       .controls       = hsw_volume_controls,
-       .num_controls   = ARRAY_SIZE(hsw_volume_controls),
-       .dapm_widgets   = widgets,
-       .num_dapm_widgets       = ARRAY_SIZE(widgets),
-       .dapm_routes    = graph,
-       .num_dapm_routes        = ARRAY_SIZE(graph),
 };
 
 static const struct snd_soc_component_driver hsw_dai_component = {
-       .name           = "haswell-dai",
+       .name = "haswell-dai",
+       .controls = hsw_volume_controls,
+       .num_controls = ARRAY_SIZE(hsw_volume_controls),
+       .dapm_widgets = widgets,
+       .num_dapm_widgets = ARRAY_SIZE(widgets),
+       .dapm_routes = graph,
+       .num_dapm_routes = ARRAY_SIZE(graph),
 };
 
 static int hsw_pcm_dev_probe(struct platform_device *pdev)
 {
        struct sst_pdata *sst_pdata = dev_get_platdata(&pdev->dev);
+       struct hsw_priv_data *priv_data;
        int ret;
 
+       if (!sst_pdata)
+               return -EINVAL;
+
+       priv_data = devm_kzalloc(&pdev->dev, sizeof(*priv_data), GFP_KERNEL);
+       if (!priv_data)
+               return -ENOMEM;
+
        ret = sst_hsw_dsp_init(&pdev->dev, sst_pdata);
        if (ret < 0)
                return -ENODEV;
 
+       priv_data->hsw = sst_pdata->dsp;
+       platform_set_drvdata(pdev, priv_data);
+
        ret = snd_soc_register_platform(&pdev->dev, &hsw_soc_platform);
        if (ret < 0)
                goto err_plat;
index 29c059ca19e8a6a4ac2b21de9a56fa3ea8cbbca2..59467775c9b8bd9486544a69054ceff364fb986f 100644 (file)
@@ -86,7 +86,7 @@ static int sst_platform_compr_free(struct snd_compr_stream *cstream)
        /*need to check*/
        str_id = stream->id;
        if (str_id)
-               ret_val = stream->compr_ops->close(str_id);
+               ret_val = stream->compr_ops->close(sst->dev, str_id);
        module_put(sst->dev->driver->owner);
        kfree(stream);
        pr_debug("%s: %d\n", __func__, ret_val);
@@ -158,7 +158,7 @@ static int sst_platform_compr_set_params(struct snd_compr_stream *cstream,
        cb.drain_cb_param = cstream;
        cb.drain_notify = sst_drain_notify;
 
-       retval = stream->compr_ops->open(&str_params, &cb);
+       retval = stream->compr_ops->open(sst->dev, &str_params, &cb);
        if (retval < 0) {
                pr_err("stream allocation failed %d\n", retval);
                return retval;
@@ -170,10 +170,30 @@ static int sst_platform_compr_set_params(struct snd_compr_stream *cstream,
 
 static int sst_platform_compr_trigger(struct snd_compr_stream *cstream, int cmd)
 {
-       struct sst_runtime_stream *stream =
-               cstream->runtime->private_data;
-
-       return stream->compr_ops->control(cmd, stream->id);
+       struct sst_runtime_stream *stream = cstream->runtime->private_data;
+
+       switch (cmd) {
+       case SNDRV_PCM_TRIGGER_START:
+               if (stream->compr_ops->stream_start)
+                       return stream->compr_ops->stream_start(sst->dev, stream->id);
+       case SNDRV_PCM_TRIGGER_STOP:
+               if (stream->compr_ops->stream_drop)
+                       return stream->compr_ops->stream_drop(sst->dev, stream->id);
+       case SND_COMPR_TRIGGER_DRAIN:
+               if (stream->compr_ops->stream_drain)
+                       return stream->compr_ops->stream_drain(sst->dev, stream->id);
+       case SND_COMPR_TRIGGER_PARTIAL_DRAIN:
+               if (stream->compr_ops->stream_partial_drain)
+                       return stream->compr_ops->stream_partial_drain(sst->dev, stream->id);
+       case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+               if (stream->compr_ops->stream_pause)
+                       return stream->compr_ops->stream_pause(sst->dev, stream->id);
+       case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+               if (stream->compr_ops->stream_pause_release)
+                       return stream->compr_ops->stream_pause_release(sst->dev, stream->id);
+       default:
+               return -EINVAL;
+       }
 }
 
 static int sst_platform_compr_pointer(struct snd_compr_stream *cstream,
@@ -182,7 +202,7 @@ static int sst_platform_compr_pointer(struct snd_compr_stream *cstream,
        struct sst_runtime_stream *stream;
 
        stream  = cstream->runtime->private_data;
-       stream->compr_ops->tstamp(stream->id, tstamp);
+       stream->compr_ops->tstamp(sst->dev, stream->id, tstamp);
        tstamp->byte_offset = tstamp->copied_total %
                                 (u32)cstream->runtime->buffer_size;
        pr_debug("calc bytes offset/copied bytes as %d\n", tstamp->byte_offset);
@@ -195,7 +215,7 @@ static int sst_platform_compr_ack(struct snd_compr_stream *cstream,
        struct sst_runtime_stream *stream;
 
        stream  = cstream->runtime->private_data;
-       stream->compr_ops->ack(stream->id, (unsigned long)bytes);
+       stream->compr_ops->ack(sst->dev, stream->id, (unsigned long)bytes);
        stream->bytes_written += bytes;
 
        return 0;
@@ -225,7 +245,7 @@ static int sst_platform_compr_set_metadata(struct snd_compr_stream *cstream,
        struct sst_runtime_stream *stream  =
                 cstream->runtime->private_data;
 
-       return stream->compr_ops->set_metadata(stream->id, metadata);
+       return stream->compr_ops->set_metadata(sst->dev, stream->id, metadata);
 }
 
 struct snd_compr_ops sst_platform_compr_ops = {
index 706212a6a68c4c9d873da9d68cf057396ee38bfc..aa9b600dfc9bfd1468c280ff61b1b7c5f728f159 100644 (file)
@@ -43,12 +43,12 @@ int sst_register_dsp(struct sst_device *dev)
                return -ENODEV;
        mutex_lock(&sst_lock);
        if (sst) {
-               pr_err("we already have a device %s\n", sst->name);
+               dev_err(dev->dev, "we already have a device %s\n", sst->name);
                module_put(dev->dev->driver->owner);
                mutex_unlock(&sst_lock);
                return -EEXIST;
        }
-       pr_debug("registering device %s\n", dev->name);
+       dev_dbg(dev->dev, "registering device %s\n", dev->name);
        sst = dev;
        mutex_unlock(&sst_lock);
        return 0;
@@ -70,7 +70,7 @@ int sst_unregister_dsp(struct sst_device *dev)
        }
 
        module_put(sst->dev->driver->owner);
-       pr_debug("unreg %s\n", sst->name);
+       dev_dbg(dev->dev, "unreg %s\n", sst->name);
        sst = NULL;
        mutex_unlock(&sst_lock);
        return 0;
@@ -252,7 +252,7 @@ int sst_fill_stream_params(void *substream,
 }
 
 static int sst_platform_alloc_stream(struct snd_pcm_substream *substream,
-               struct snd_soc_platform *platform)
+               struct snd_soc_dai *dai)
 {
        struct sst_runtime_stream *stream =
                        substream->runtime->private_data;
@@ -260,7 +260,7 @@ static int sst_platform_alloc_stream(struct snd_pcm_substream *substream,
        struct snd_sst_params str_params = {0};
        struct snd_sst_alloc_params_ext alloc_params = {0};
        int ret_val = 0;
-       struct sst_data *ctx = snd_soc_platform_get_drvdata(platform);
+       struct sst_data *ctx = snd_soc_dai_get_drvdata(dai);
 
        /* set codec params and inform SST driver the same */
        sst_fill_pcm_params(substream, &param);
@@ -277,7 +277,7 @@ static int sst_platform_alloc_stream(struct snd_pcm_substream *substream,
 
        stream->stream_info.str_id = str_params.stream_id;
 
-       ret_val = stream->ops->open(&str_params);
+       ret_val = stream->ops->open(sst->dev, &str_params);
        if (ret_val <= 0)
                return ret_val;
 
@@ -306,22 +306,31 @@ static int sst_platform_init_stream(struct snd_pcm_substream *substream)
 {
        struct sst_runtime_stream *stream =
                        substream->runtime->private_data;
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
        int ret_val;
 
-       pr_debug("setting buffer ptr param\n");
+       dev_dbg(rtd->dev, "setting buffer ptr param\n");
        sst_set_stream_status(stream, SST_PLATFORM_INIT);
        stream->stream_info.period_elapsed = sst_period_elapsed;
        stream->stream_info.arg = substream;
        stream->stream_info.buffer_ptr = 0;
        stream->stream_info.sfreq = substream->runtime->rate;
-       ret_val = stream->ops->device_control(
-                       SST_SND_STREAM_INIT, &stream->stream_info);
+       ret_val = stream->ops->stream_init(sst->dev, &stream->stream_info);
        if (ret_val)
-               pr_err("control_set ret error %d\n", ret_val);
+               dev_err(rtd->dev, "control_set ret error %d\n", ret_val);
        return ret_val;
 
 }
-/* end -- helper functions */
+
+static int power_up_sst(struct sst_runtime_stream *stream)
+{
+       return stream->ops->power(sst->dev, true);
+}
+
+static void power_down_sst(struct sst_runtime_stream *stream)
+{
+       stream->ops->power(sst->dev, false);
+}
 
 static int sst_media_open(struct snd_pcm_substream *substream,
                struct snd_soc_dai *dai)
@@ -339,7 +348,7 @@ static int sst_media_open(struct snd_pcm_substream *substream,
        mutex_lock(&sst_lock);
        if (!sst ||
            !try_module_get(sst->dev->driver->owner)) {
-               pr_err("no device available to run\n");
+               dev_err(dai->dev, "no device available to run\n");
                ret_val = -ENODEV;
                goto out_ops;
        }
@@ -352,6 +361,10 @@ static int sst_media_open(struct snd_pcm_substream *substream,
        /* allocate memory for SST API set */
        runtime->private_data = stream;
 
+       ret_val = power_up_sst(stream);
+       if (ret_val < 0)
+               return ret_val;
+
        /* Make sure, that the period size is always even */
        snd_pcm_hw_constraint_step(substream->runtime, 0,
                           SNDRV_PCM_HW_PARAM_PERIODS, 2);
@@ -371,26 +384,29 @@ static void sst_media_close(struct snd_pcm_substream *substream,
        int ret_val = 0, str_id;
 
        stream = substream->runtime->private_data;
+       power_down_sst(stream);
+
        str_id = stream->stream_info.str_id;
        if (str_id)
-               ret_val = stream->ops->close(str_id);
+               ret_val = stream->ops->close(sst->dev, str_id);
        module_put(sst->dev->driver->owner);
        kfree(stream);
 }
 
-static inline unsigned int get_current_pipe_id(struct snd_soc_platform *platform,
+static inline unsigned int get_current_pipe_id(struct snd_soc_dai *dai,
                                               struct snd_pcm_substream *substream)
 {
-       struct sst_data *sst = snd_soc_platform_get_drvdata(platform);
+       struct sst_data *sst = snd_soc_dai_get_drvdata(dai);
        struct sst_dev_stream_map *map = sst->pdata->pdev_strm_map;
        struct sst_runtime_stream *stream =
                        substream->runtime->private_data;
        u32 str_id = stream->stream_info.str_id;
        unsigned int pipe_id;
+
        pipe_id = map[str_id].device_id;
 
-       pr_debug("%s: got pipe_id = %#x for str_id = %d\n",
-                __func__, pipe_id, str_id);
+       dev_dbg(dai->dev, "got pipe_id = %#x for str_id = %d\n",
+                       pipe_id, str_id);
        return pipe_id;
 }
 
@@ -403,12 +419,11 @@ static int sst_media_prepare(struct snd_pcm_substream *substream,
        stream = substream->runtime->private_data;
        str_id = stream->stream_info.str_id;
        if (stream->stream_info.str_id) {
-               ret_val = stream->ops->device_control(
-                               SST_SND_DROP, &str_id);
+               ret_val = stream->ops->stream_drop(sst->dev, str_id);
                return ret_val;
        }
 
-       ret_val = sst_platform_alloc_stream(substream, dai->platform);
+       ret_val = sst_platform_alloc_stream(substream, dai);
        if (ret_val <= 0)
                return ret_val;
        snprintf(substream->pcm->id, sizeof(substream->pcm->id),
@@ -461,37 +476,40 @@ static int sst_platform_pcm_trigger(struct snd_pcm_substream *substream,
 {
        int ret_val = 0, str_id;
        struct sst_runtime_stream *stream;
-       int str_cmd, status;
+       int status;
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
 
-       pr_debug("sst_platform_pcm_trigger called\n");
+       dev_dbg(rtd->dev, "sst_platform_pcm_trigger called\n");
+       if (substream->pcm->internal)
+               return 0;
        stream = substream->runtime->private_data;
        str_id = stream->stream_info.str_id;
        switch (cmd) {
        case SNDRV_PCM_TRIGGER_START:
-               pr_debug("sst: Trigger Start\n");
-               str_cmd = SST_SND_START;
+               dev_dbg(rtd->dev, "sst: Trigger Start\n");
                status = SST_PLATFORM_RUNNING;
                stream->stream_info.arg = substream;
+               ret_val = stream->ops->stream_start(sst->dev, str_id);
                break;
        case SNDRV_PCM_TRIGGER_STOP:
-               pr_debug("sst: in stop\n");
-               str_cmd = SST_SND_DROP;
+               dev_dbg(rtd->dev, "sst: in stop\n");
                status = SST_PLATFORM_DROPPED;
+               ret_val = stream->ops->stream_drop(sst->dev, str_id);
                break;
        case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
-               pr_debug("sst: in pause\n");
-               str_cmd = SST_SND_PAUSE;
+               dev_dbg(rtd->dev, "sst: in pause\n");
                status = SST_PLATFORM_PAUSED;
+               ret_val = stream->ops->stream_pause(sst->dev, str_id);
                break;
        case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
-               pr_debug("sst: in pause release\n");
-               str_cmd = SST_SND_RESUME;
+               dev_dbg(rtd->dev, "sst: in pause release\n");
                status = SST_PLATFORM_RUNNING;
+               ret_val = stream->ops->stream_pause_release(sst->dev, str_id);
                break;
        default:
                return -EINVAL;
        }
-       ret_val = stream->ops->device_control(str_cmd, &str_id);
+
        if (!ret_val)
                sst_set_stream_status(stream, status);
 
@@ -505,16 +523,16 @@ static snd_pcm_uframes_t sst_platform_pcm_pointer
        struct sst_runtime_stream *stream;
        int ret_val, status;
        struct pcm_stream_info *str_info;
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
 
        stream = substream->runtime->private_data;
        status = sst_get_stream_status(stream);
        if (status == SST_PLATFORM_INIT)
                return 0;
        str_info = &stream->stream_info;
-       ret_val = stream->ops->device_control(
-                               SST_SND_BUFFER_POINTER, str_info);
+       ret_val = stream->ops->stream_read_tstamp(sst->dev, str_info);
        if (ret_val) {
-               pr_err("sst: error code = %d\n", ret_val);
+               dev_err(rtd->dev, "sst: error code = %d\n", ret_val);
                return ret_val;
        }
        substream->runtime->delay = str_info->pcm_delay;
@@ -530,7 +548,7 @@ static struct snd_pcm_ops sst_platform_ops = {
 
 static void sst_pcm_free(struct snd_pcm *pcm)
 {
-       pr_debug("sst_pcm_free called\n");
+       dev_dbg(pcm->dev, "sst_pcm_free called\n");
        snd_pcm_lib_preallocate_free_for_all(pcm);
 }
 
@@ -547,14 +565,20 @@ static int sst_pcm_new(struct snd_soc_pcm_runtime *rtd)
                        snd_dma_continuous_data(GFP_DMA),
                        SST_MIN_BUFFER, SST_MAX_BUFFER);
                if (retval) {
-                       pr_err("dma buffer allocationf fail\n");
+                       dev_err(rtd->dev, "dma buffer allocationf fail\n");
                        return retval;
                }
        }
        return retval;
 }
 
-static struct snd_soc_platform_driver sst_soc_platform_drv = {
+static int sst_soc_probe(struct snd_soc_platform *platform)
+{
+       return sst_dsp_init_v2_dpcm(platform);
+}
+
+static struct snd_soc_platform_driver sst_soc_platform_drv  = {
+       .probe          = sst_soc_probe,
        .ops            = &sst_platform_ops,
        .compr_ops      = &sst_platform_compr_ops,
        .pcm_new        = sst_pcm_new,
@@ -574,13 +598,11 @@ static int sst_platform_probe(struct platform_device *pdev)
 
        drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_KERNEL);
        if (drv == NULL) {
-               pr_err("kzalloc failed\n");
                return -ENOMEM;
        }
 
        pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
        if (pdata == NULL) {
-               pr_err("kzalloc failed for pdata\n");
                return -ENOMEM;
        }
 
@@ -592,14 +614,14 @@ static int sst_platform_probe(struct platform_device *pdev)
 
        ret = snd_soc_register_platform(&pdev->dev, &sst_soc_platform_drv);
        if (ret) {
-               pr_err("registering soc platform failed\n");
+               dev_err(&pdev->dev, "registering soc platform failed\n");
                return ret;
        }
 
        ret = snd_soc_register_component(&pdev->dev, &sst_component,
                                sst_platform_dai, ARRAY_SIZE(sst_platform_dai));
        if (ret) {
-               pr_err("registering cpu dais failed\n");
+               dev_err(&pdev->dev, "registering cpu dais failed\n");
                snd_soc_unregister_platform(&pdev->dev);
        }
        return ret;
@@ -610,7 +632,7 @@ static int sst_platform_remove(struct platform_device *pdev)
 
        snd_soc_unregister_component(&pdev->dev);
        snd_soc_unregister_platform(&pdev->dev);
-       pr_debug("sst_platform_remove success\n");
+       dev_dbg(&pdev->dev, "sst_platform_remove success\n");
        return 0;
 }
 
index 6c6a42c08e2410b90a898d2e9d77730a4bf7721f..19f83ec51613a3ba46ddeab431dadd6ae7d12854 100644 (file)
@@ -54,20 +54,6 @@ enum sst_drv_status {
        SST_PLATFORM_DROPPED,
 };
 
-enum sst_controls {
-       SST_SND_ALLOC =                 0x00,
-       SST_SND_PAUSE =                 0x01,
-       SST_SND_RESUME =                0x02,
-       SST_SND_DROP =                  0x03,
-       SST_SND_FREE =                  0x04,
-       SST_SND_BUFFER_POINTER =        0x05,
-       SST_SND_STREAM_INIT =           0x06,
-       SST_SND_START    =              0x07,
-       SST_SET_BYTE_STREAM =           0x100A,
-       SST_GET_BYTE_STREAM =           0x100B,
-       SST_MAX_CONTROLS = SST_GET_BYTE_STREAM,
-};
-
 enum sst_stream_ops {
        STREAM_OPS_PLAYBACK = 0,
        STREAM_OPS_CAPTURE,
@@ -113,24 +99,37 @@ struct sst_compress_cb {
 
 struct compress_sst_ops {
        const char *name;
-       int (*open) (struct snd_sst_params *str_params,
-                       struct sst_compress_cb *cb);
-       int (*control) (unsigned int cmd, unsigned int str_id);
-       int (*tstamp) (unsigned int str_id, struct snd_compr_tstamp *tstamp);
-       int (*ack) (unsigned int str_id, unsigned long bytes);
-       int (*close) (unsigned int str_id);
-       int (*get_caps) (struct snd_compr_caps *caps);
-       int (*get_codec_caps) (struct snd_compr_codec_caps *codec);
-       int (*set_metadata) (unsigned int str_id,
+       int (*open)(struct device *dev,
+               struct snd_sst_params *str_params, struct sst_compress_cb *cb);
+       int (*stream_start)(struct device *dev, unsigned int str_id);
+       int (*stream_drop)(struct device *dev, unsigned int str_id);
+       int (*stream_drain)(struct device *dev, unsigned int str_id);
+       int (*stream_partial_drain)(struct device *dev, unsigned int str_id);
+       int (*stream_pause)(struct device *dev, unsigned int str_id);
+       int (*stream_pause_release)(struct device *dev, unsigned int str_id);
+
+       int (*tstamp)(struct device *dev, unsigned int str_id,
+                       struct snd_compr_tstamp *tstamp);
+       int (*ack)(struct device *dev, unsigned int str_id,
+                       unsigned long bytes);
+       int (*close)(struct device *dev, unsigned int str_id);
+       int (*get_caps)(struct snd_compr_caps *caps);
+       int (*get_codec_caps)(struct snd_compr_codec_caps *codec);
+       int (*set_metadata)(struct device *dev, unsigned int str_id,
                        struct snd_compr_metadata *mdata);
-
 };
 
 struct sst_ops {
-       int (*open) (struct snd_sst_params *str_param);
-       int (*device_control) (int cmd, void *arg);
-       int (*set_generic_params)(enum sst_controls cmd, void *arg);
-       int (*close) (unsigned int str_id);
+       int (*open)(struct device *dev, struct snd_sst_params *str_param);
+       int (*stream_init)(struct device *dev, struct pcm_stream_info *str_info);
+       int (*stream_start)(struct device *dev, int str_id);
+       int (*stream_drop)(struct device *dev, int str_id);
+       int (*stream_pause)(struct device *dev, int str_id);
+       int (*stream_pause_release)(struct device *dev, int str_id);
+       int (*stream_read_tstamp)(struct device *dev, struct pcm_stream_info *str_info);
+       int (*send_byte_stream)(struct device *dev, struct snd_sst_bytes_v2 *bytes);
+       int (*close)(struct device *dev, unsigned int str_id);
+       int (*power)(struct device *dev, bool state);
 };
 
 struct sst_runtime_stream {
@@ -152,6 +151,8 @@ struct sst_device {
 };
 
 struct sst_data;
+
+int sst_dsp_init_v2_dpcm(struct snd_soc_platform *platform);
 void sst_set_stream_status(struct sst_runtime_stream *stream, int state);
 int sst_fill_stream_params(void *substream, const struct sst_data *ctx,
                           struct snd_sst_params *str_params, bool is_compress);
@@ -166,6 +167,7 @@ struct sst_algo_int_control_v2 {
 struct sst_data {
        struct platform_device *pdev;
        struct sst_platform_data *pdata;
+       struct snd_sst_bytes_v2 *byte_stream;
        struct mutex lock;
 };
 int sst_register_dsp(struct sst_device *sst);
index 943922c79f784b1ad70f4f71628c71e6ebb87812..b10ae8074461e9403d6f276943c82cbf5c3531ce 100644 (file)
@@ -168,7 +168,7 @@ static int rx51_spk_event(struct snd_soc_dapm_widget *w,
 static int rx51_hp_event(struct snd_soc_dapm_widget *w,
                         struct snd_kcontrol *k, int event)
 {
-       struct snd_soc_codec *codec = w->dapm->codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
 
        if (SND_SOC_DAPM_EVENT_ON(event))
                tpa6130a2_stereo_enable(codec, 1);
index c196a466eef6ea2f3d45f69e92801a7c263120dd..78fc159559b00228ed055dfaa025bc58f3928e67 100644 (file)
@@ -2,11 +2,10 @@ config SND_SOC_ROCKCHIP
        tristate "ASoC support for Rockchip"
        depends on COMPILE_TEST || ARCH_ROCKCHIP
        select SND_SOC_GENERIC_DMAENGINE_PCM
-       select SND_ROCKCHIP_I2S
        help
          Say Y or M if you want to add support for codecs attached to
          the Rockchip SoCs' Audio interfaces. You will also need to
          select the audio interfaces to support below.
 
-config SND_ROCKCHIP_I2S
+config SND_SOC_ROCKCHIP_I2S
        tristate
index 1006418e1394402570d2668a20f189b57c4a62d5..b9219092b47fd917146ea4a25c195843ffb7c285 100644 (file)
@@ -1,4 +1,4 @@
 # ROCKCHIP Platform Support
 snd-soc-i2s-objs := rockchip_i2s.o
 
-obj-$(CONFIG_SND_ROCKCHIP_I2S) += snd-soc-i2s.o
+obj-$(CONFIG_SND_SOC_ROCKCHIP_I2S) += snd-soc-i2s.o
index fb9e05c9f47199c7bdcbd8413846899b074615ce..f373e37f83050a246c2d35fbed008db7cdd0b5a5 100644 (file)
@@ -108,8 +108,10 @@ static void rockchip_snd_txctrl(struct rk_i2s_dev *i2s, int on)
                        while (val) {
                                regmap_read(i2s->regmap, I2S_CLR, &val);
                                retry--;
-                               if (!retry)
+                               if (!retry) {
                                        dev_warn(i2s->dev, "fail to clear\n");
+                                       break;
+                               }
                        }
                }
        }
@@ -244,16 +246,6 @@ static int rockchip_i2s_hw_params(struct snd_pcm_substream *substream,
        regmap_update_bits(i2s->regmap, I2S_TXCR, I2S_TXCR_VDW_MASK, val);
        regmap_update_bits(i2s->regmap, I2S_RXCR, I2S_RXCR_VDW_MASK, val);
 
-       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
-               dai->playback_dma_data = &i2s->playback_dma_data;
-               regmap_update_bits(i2s->regmap, I2S_DMACR, I2S_DMACR_TDL_MASK,
-                                  I2S_DMACR_TDL(1) | I2S_DMACR_TDE_ENABLE);
-       } else {
-               dai->capture_dma_data = &i2s->capture_dma_data;
-               regmap_update_bits(i2s->regmap, I2S_DMACR, I2S_DMACR_RDL_MASK,
-                                  I2S_DMACR_RDL(1) | I2S_DMACR_RDE_ENABLE);
-       }
-
        return 0;
 }
 
@@ -301,6 +293,16 @@ static int rockchip_i2s_set_sysclk(struct snd_soc_dai *cpu_dai, int clk_id,
        return ret;
 }
 
+static int rockchip_i2s_dai_probe(struct snd_soc_dai *dai)
+{
+       struct rk_i2s_dev *i2s = snd_soc_dai_get_drvdata(dai);
+
+       dai->capture_dma_data = &i2s->capture_dma_data;
+       dai->playback_dma_data = &i2s->playback_dma_data;
+
+       return 0;
+}
+
 static const struct snd_soc_dai_ops rockchip_i2s_dai_ops = {
        .hw_params = rockchip_i2s_hw_params,
        .set_sysclk = rockchip_i2s_set_sysclk,
@@ -309,7 +311,9 @@ static const struct snd_soc_dai_ops rockchip_i2s_dai_ops = {
 };
 
 static struct snd_soc_dai_driver rockchip_i2s_dai = {
+       .probe = rockchip_i2s_dai_probe,
        .playback = {
+               .stream_name = "Playback",
                .channels_min = 2,
                .channels_max = 8,
                .rates = SNDRV_PCM_RATE_8000_192000,
@@ -319,6 +323,7 @@ static struct snd_soc_dai_driver rockchip_i2s_dai = {
                            SNDRV_PCM_FMTBIT_S24_LE),
        },
        .capture = {
+               .stream_name = "Capture",
                .channels_min = 2,
                .channels_max = 2,
                .rates = SNDRV_PCM_RATE_8000_192000,
@@ -420,6 +425,11 @@ static int rockchip_i2s_probe(struct platform_device *pdev)
                dev_err(&pdev->dev, "Can't retrieve i2s bus clock\n");
                return PTR_ERR(i2s->hclk);
        }
+       ret = clk_prepare_enable(i2s->hclk);
+       if (ret) {
+               dev_err(i2s->dev, "hclock enable failed %d\n", ret);
+               return ret;
+       }
 
        i2s->mclk = devm_clk_get(&pdev->dev, "i2s_clk");
        if (IS_ERR(i2s->mclk)) {
index db6cefa18017c1db57568689661fc21bc80ec6ea..0e8dd985fcb315dab9bf293c8d7ee4dea0b9b34e 100644 (file)
@@ -351,7 +351,7 @@ static void idma_free(struct snd_pcm *pcm)
        if (!buf->area)
                return;
 
-       iounmap(buf->area);
+       iounmap((void __iomem *)buf->area);
 
        buf->area = NULL;
        buf->addr = 0;
@@ -369,7 +369,7 @@ static int preallocate_idma_buffer(struct snd_pcm *pcm, int stream)
        buf->dev.type = SNDRV_DMA_TYPE_CONTINUOUS;
        buf->addr = idma.lp_tx_addr;
        buf->bytes = idma_hardware.buffer_bytes_max;
-       buf->area = (unsigned char *)ioremap(buf->addr, buf->bytes);
+       buf->area = (unsigned char * __force)ioremap(buf->addr, buf->bytes);
 
        return 0;
 }
index 278edf9e2a87e24067ced858a6d92d672f40abde..3c8f60423e825d401e659e459afed3f00642799a 100644 (file)
@@ -66,12 +66,12 @@ static struct snd_soc_card odroidx2 = {
        .late_probe             = odroidx2_late_probe,
 };
 
-struct odroidx2_drv_data odroidx2_drvdata = {
+static const struct odroidx2_drv_data odroidx2_drvdata = {
        .dapm_widgets           = odroidx2_dapm_widgets,
        .num_dapm_widgets       = ARRAY_SIZE(odroidx2_dapm_widgets),
 };
 
-struct odroidx2_drv_data odroidu3_drvdata = {
+static const struct odroidx2_drv_data odroidu3_drvdata = {
        .dapm_widgets           = odroidu3_dapm_widgets,
        .num_dapm_widgets       = ARRAY_SIZE(odroidu3_dapm_widgets),
 };
index 9902efcb8ea121a99a930816d727c11c1f614258..a05482651aaeaf5c1ff994de194d65a63857191d 100644 (file)
@@ -228,10 +228,12 @@ static struct snd_soc_dai_link speyside_dai[] = {
        },
 };
 
-static int speyside_wm9081_init(struct snd_soc_dapm_context *dapm)
+static int speyside_wm9081_init(struct snd_soc_component *component)
 {
+       struct snd_soc_codec *codec = snd_soc_component_to_codec(component);
+
        /* At any time the WM9081 is active it will have this clock */
-       return snd_soc_codec_set_sysclk(dapm->codec, WM9081_SYSCLK_MCLK, 0,
+       return snd_soc_codec_set_sysclk(codec, WM9081_SYSCLK_MCLK, 0,
                                        MCLK_AUDIO_RATE, 0);
 }
 
index c76344350e44421925702139e6acd00db8e560eb..66fddec9543d0ecc1bb414871d035bc244abc521 100644 (file)
@@ -1297,9 +1297,14 @@ static int fsi_dma_transfer(struct fsi_priv *fsi, struct fsi_stream *io)
        struct snd_pcm_substream *substream = io->substream;
        struct dma_async_tx_descriptor *desc;
        int is_play = fsi_stream_is_play(fsi, io);
-       enum dma_data_direction dir = is_play ? DMA_TO_DEVICE : DMA_FROM_DEVICE;
+       enum dma_transfer_direction dir;
        int ret = -EIO;
 
+       if (is_play)
+               dir = DMA_MEM_TO_DEV;
+       else
+               dir = DMA_DEV_TO_MEM;
+
        desc = dmaengine_prep_dma_cyclic(io->chan,
                                         substream->runtime->dma_addr,
                                         snd_pcm_lib_buffer_bytes(substream),
index 19f78963e8b9b7fbd9a104736ed4b36a11b1bee8..1922ec57d10a1fd29c174295adb6de5446e8d7a2 100644 (file)
@@ -798,10 +798,8 @@ if (name##_node) {                                                 \
                        mod_parse(src);
                        mod_parse(dvc);
 
-                       if (playback)
-                               of_node_put(playback);
-                       if (capture)
-                               of_node_put(capture);
+                       of_node_put(playback);
+                       of_node_put(capture);
                }
 
                dai_i++;
index 488f9becb44f3a6653dd66a72e1881d8c2168694..32eb6da2d2bde2ac994aeda90ef673fbd6d6e426 100644 (file)
@@ -139,7 +139,7 @@ static int siu_pcm_wr_set(struct siu_port *port_info,
 
        desc->callback = siu_dma_tx_complete;
        desc->callback_param = siu_stream;
-       cookie = desc->tx_submit(desc);
+       cookie = dmaengine_submit(desc);
        if (cookie < 0) {
                dev_err(dev, "Failed to submit a dma transfer\n");
                return cookie;
@@ -189,7 +189,7 @@ static int siu_pcm_rd_set(struct siu_port *port_info,
 
        desc->callback = siu_dma_tx_complete;
        desc->callback_param = siu_stream;
-       cookie = desc->tx_submit(desc);
+       cookie = dmaengine_submit(desc);
        if (cookie < 0) {
                dev_err(dev, "Failed to submit dma descriptor\n");
                return cookie;
index 3a730374e259d2de380aadbb8acd9741e2c3ef93..186dc7f33a55f4dd409b52081945fc89d02ec246 100644 (file)
@@ -100,6 +100,16 @@ static int sirf_usp_pcm_set_dai_fmt(struct snd_soc_dai *dai,
                return -EINVAL;
        }
 
+       switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+       case SND_SOC_DAIFMT_NB_NF:
+               break;
+       case SND_SOC_DAIFMT_IB_NF:
+               usp->daifmt_format |= (fmt & SND_SOC_DAIFMT_INV_MASK);
+               break;
+       default:
+               return -EINVAL;
+       }
+
        return 0;
 }
 
@@ -177,7 +187,7 @@ static int sirf_usp_pcm_hw_params(struct snd_pcm_substream *substream,
 
        shifter_len = data_len;
 
-       switch (usp->daifmt_format) {
+       switch (usp->daifmt_format & SND_SOC_DAIFMT_FORMAT_MASK) {
        case SND_SOC_DAIFMT_I2S:
                regmap_update_bits(usp->regmap, USP_RX_FRAME_CTRL,
                        USP_I2S_SYNC_CHG, USP_I2S_SYNC_CHG);
@@ -193,6 +203,18 @@ static int sirf_usp_pcm_hw_params(struct snd_pcm_substream *substream,
                return -EINVAL;
        }
 
+       switch (usp->daifmt_format & SND_SOC_DAIFMT_INV_MASK) {
+       case SND_SOC_DAIFMT_NB_NF:
+               break;
+       case SND_SOC_DAIFMT_IB_NF:
+               regmap_update_bits(usp->regmap, USP_MODE1,
+                       USP_RXD_ACT_EDGE_FALLING | USP_TXD_ACT_EDGE_FALLING,
+                       USP_RXD_ACT_EDGE_FALLING);
+               break;
+       default:
+               return -EINVAL;
+       }
+
        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
                regmap_update_bits(usp->regmap, USP_TX_FRAME_CTRL,
                        USP_TXC_DATA_LEN_MASK | USP_TXC_FRAME_LEN_MASK
index d074aa91b023f8db8f7dace7f62db25a564517ce..4c8f8a23a0e9de132827fc041438fc1e07a4892c 100644 (file)
@@ -270,79 +270,54 @@ static const struct file_operations codec_reg_fops = {
        .llseek = default_llseek,
 };
 
-static struct dentry *soc_debugfs_create_dir(struct dentry *parent,
-       const char *fmt, ...)
+static void soc_init_component_debugfs(struct snd_soc_component *component)
 {
-       struct dentry *de;
-       va_list ap;
-       char *s;
+       if (component->debugfs_prefix) {
+               char *name;
 
-       va_start(ap, fmt);
-       s = kvasprintf(GFP_KERNEL, fmt, ap);
-       va_end(ap);
+               name = kasprintf(GFP_KERNEL, "%s:%s",
+                       component->debugfs_prefix, component->name);
+               if (name) {
+                       component->debugfs_root = debugfs_create_dir(name,
+                               component->card->debugfs_card_root);
+                       kfree(name);
+               }
+       } else {
+               component->debugfs_root = debugfs_create_dir(component->name,
+                               component->card->debugfs_card_root);
+       }
 
-       if (!s)
-               return NULL;
+       if (!component->debugfs_root) {
+               dev_warn(component->dev,
+                       "ASoC: Failed to create component debugfs directory\n");
+               return;
+       }
 
-       de = debugfs_create_dir(s, parent);
-       kfree(s);
+       snd_soc_dapm_debugfs_init(snd_soc_component_get_dapm(component),
+               component->debugfs_root);
 
-       return de;
+       if (component->init_debugfs)
+               component->init_debugfs(component);
 }
 
-static void soc_init_codec_debugfs(struct snd_soc_codec *codec)
+static void soc_cleanup_component_debugfs(struct snd_soc_component *component)
 {
-       struct dentry *debugfs_card_root = codec->component.card->debugfs_card_root;
+       debugfs_remove_recursive(component->debugfs_root);
+}
 
-       codec->debugfs_codec_root = soc_debugfs_create_dir(debugfs_card_root,
-                                               "codec:%s",
-                                               codec->component.name);
-       if (!codec->debugfs_codec_root) {
-               dev_warn(codec->dev,
-                       "ASoC: Failed to create codec debugfs directory\n");
-               return;
-       }
+static void soc_init_codec_debugfs(struct snd_soc_component *component)
+{
+       struct snd_soc_codec *codec = snd_soc_component_to_codec(component);
 
-       debugfs_create_bool("cache_sync", 0444, codec->debugfs_codec_root,
+       debugfs_create_bool("cache_sync", 0444, codec->component.debugfs_root,
                            &codec->cache_sync);
-       debugfs_create_bool("cache_only", 0444, codec->debugfs_codec_root,
-                           &codec->cache_only);
 
        codec->debugfs_reg = debugfs_create_file("codec_reg", 0644,
-                                                codec->debugfs_codec_root,
+                                                codec->component.debugfs_root,
                                                 codec, &codec_reg_fops);
        if (!codec->debugfs_reg)
                dev_warn(codec->dev,
                        "ASoC: Failed to create codec register debugfs file\n");
-
-       snd_soc_dapm_debugfs_init(&codec->dapm, codec->debugfs_codec_root);
-}
-
-static void soc_cleanup_codec_debugfs(struct snd_soc_codec *codec)
-{
-       debugfs_remove_recursive(codec->debugfs_codec_root);
-}
-
-static void soc_init_platform_debugfs(struct snd_soc_platform *platform)
-{
-       struct dentry *debugfs_card_root = platform->component.card->debugfs_card_root;
-
-       platform->debugfs_platform_root = soc_debugfs_create_dir(debugfs_card_root,
-                                               "platform:%s",
-                                               platform->component.name);
-       if (!platform->debugfs_platform_root) {
-               dev_warn(platform->dev,
-                       "ASoC: Failed to create platform debugfs directory\n");
-               return;
-       }
-
-       snd_soc_dapm_debugfs_init(&platform->component.dapm,
-               platform->debugfs_platform_root);
-}
-
-static void soc_cleanup_platform_debugfs(struct snd_soc_platform *platform)
-{
-       debugfs_remove_recursive(platform->debugfs_platform_root);
 }
 
 static ssize_t codec_list_read_file(struct file *file, char __user *user_buf,
@@ -474,19 +449,15 @@ static void soc_cleanup_card_debugfs(struct snd_soc_card *card)
 
 #else
 
-static inline void soc_init_codec_debugfs(struct snd_soc_codec *codec)
-{
-}
+#define soc_init_codec_debugfs NULL
 
-static inline void soc_cleanup_codec_debugfs(struct snd_soc_codec *codec)
+static inline void soc_init_component_debugfs(
+       struct snd_soc_component *component)
 {
 }
 
-static inline void soc_init_platform_debugfs(struct snd_soc_platform *platform)
-{
-}
-
-static inline void soc_cleanup_platform_debugfs(struct snd_soc_platform *platform)
+static inline void soc_cleanup_component_debugfs(
+       struct snd_soc_component *component)
 {
 }
 
@@ -579,10 +550,8 @@ int snd_soc_suspend(struct device *dev)
        struct snd_soc_codec *codec;
        int i, j;
 
-       /* If the initialization of this soc device failed, there is no codec
-        * associated with it. Just bail out in this case.
-        */
-       if (list_empty(&card->codec_dev_list))
+       /* If the card is not initialized yet there is nothing to do */
+       if (!card->instantiated)
                return 0;
 
        /* Due to the resume being scheduled into a workqueue we could
@@ -668,7 +637,7 @@ int snd_soc_suspend(struct device *dev)
        list_for_each_entry(codec, &card->codec_dev_list, card_list) {
                /* If there are paths active then the CODEC will be held with
                 * bias _ON and should not be suspended. */
-               if (!codec->suspended && codec->driver->suspend) {
+               if (!codec->suspended) {
                        switch (codec->dapm.bias_level) {
                        case SND_SOC_BIAS_STANDBY:
                                /*
@@ -682,8 +651,10 @@ int snd_soc_suspend(struct device *dev)
                                                "ASoC: idle_bias_off CODEC on over suspend\n");
                                        break;
                                }
+
                        case SND_SOC_BIAS_OFF:
-                               codec->driver->suspend(codec);
+                               if (codec->driver->suspend)
+                                       codec->driver->suspend(codec);
                                codec->suspended = 1;
                                codec->cache_sync = 1;
                                if (codec->component.regmap)
@@ -757,11 +728,12 @@ static void soc_resume_deferred(struct work_struct *work)
                 * left with bias OFF or STANDBY and suspended so we must now
                 * resume.  Otherwise the suspend was suppressed.
                 */
-               if (codec->driver->resume && codec->suspended) {
+               if (codec->suspended) {
                        switch (codec->dapm.bias_level) {
                        case SND_SOC_BIAS_STANDBY:
                        case SND_SOC_BIAS_OFF:
-                               codec->driver->resume(codec);
+                               if (codec->driver->resume)
+                                       codec->driver->resume(codec);
                                codec->suspended = 0;
                                break;
                        default:
@@ -835,10 +807,8 @@ int snd_soc_resume(struct device *dev)
        struct snd_soc_card *card = dev_get_drvdata(dev);
        int i, ac97_control = 0;
 
-       /* If the initialization of this soc device failed, there is no codec
-        * associated with it. Just bail out in this case.
-        */
-       if (list_empty(&card->codec_dev_list))
+       /* If the card is not initialized yet there is nothing to do */
+       if (!card->instantiated)
                return 0;
 
        /* activate pins from sleep state */
@@ -887,35 +857,40 @@ EXPORT_SYMBOL_GPL(snd_soc_resume);
 static const struct snd_soc_dai_ops null_dai_ops = {
 };
 
-static struct snd_soc_codec *soc_find_codec(
-                                       const struct device_node *codec_of_node,
-                                       const char *codec_name)
+static struct snd_soc_component *soc_find_component(
+       const struct device_node *of_node, const char *name)
 {
-       struct snd_soc_codec *codec;
+       struct snd_soc_component *component;
 
-       list_for_each_entry(codec, &codec_list, list) {
-               if (codec_of_node) {
-                       if (codec->dev->of_node != codec_of_node)
-                               continue;
-               } else {
-                       if (strcmp(codec->component.name, codec_name))
-                               continue;
+       list_for_each_entry(component, &component_list, list) {
+               if (of_node) {
+                       if (component->dev->of_node == of_node)
+                               return component;
+               } else if (strcmp(component->name, name) == 0) {
+                       return component;
                }
-
-               return codec;
        }
 
        return NULL;
 }
 
-static struct snd_soc_dai *soc_find_codec_dai(struct snd_soc_codec *codec,
-                                             const char *codec_dai_name)
+static struct snd_soc_dai *snd_soc_find_dai(
+       const struct snd_soc_dai_link_component *dlc)
 {
-       struct snd_soc_dai *codec_dai;
+       struct snd_soc_component *component;
+       struct snd_soc_dai *dai;
 
-       list_for_each_entry(codec_dai, &codec->component.dai_list, list) {
-               if (!strcmp(codec_dai->name, codec_dai_name)) {
-                       return codec_dai;
+       /* Find CPU DAI from registered DAIs*/
+       list_for_each_entry(component, &component_list, list) {
+               if (dlc->of_node && component->dev->of_node != dlc->of_node)
+                       continue;
+               if (dlc->name && strcmp(dev_name(component->dev), dlc->name))
+                       continue;
+               list_for_each_entry(dai, &component->dai_list, list) {
+                       if (dlc->dai_name && strcmp(dai->name, dlc->dai_name))
+                               continue;
+
+                       return dai;
                }
        }
 
@@ -926,33 +901,19 @@ static int soc_bind_dai_link(struct snd_soc_card *card, int num)
 {
        struct snd_soc_dai_link *dai_link = &card->dai_link[num];
        struct snd_soc_pcm_runtime *rtd = &card->rtd[num];
-       struct snd_soc_component *component;
        struct snd_soc_dai_link_component *codecs = dai_link->codecs;
+       struct snd_soc_dai_link_component cpu_dai_component;
        struct snd_soc_dai **codec_dais = rtd->codec_dais;
        struct snd_soc_platform *platform;
-       struct snd_soc_dai *cpu_dai;
        const char *platform_name;
        int i;
 
        dev_dbg(card->dev, "ASoC: binding %s at idx %d\n", dai_link->name, num);
 
-       /* Find CPU DAI from registered DAIs*/
-       list_for_each_entry(component, &component_list, list) {
-               if (dai_link->cpu_of_node &&
-                       component->dev->of_node != dai_link->cpu_of_node)
-                       continue;
-               if (dai_link->cpu_name &&
-                       strcmp(dev_name(component->dev), dai_link->cpu_name))
-                       continue;
-               list_for_each_entry(cpu_dai, &component->dai_list, list) {
-                       if (dai_link->cpu_dai_name &&
-                               strcmp(cpu_dai->name, dai_link->cpu_dai_name))
-                               continue;
-
-                       rtd->cpu_dai = cpu_dai;
-               }
-       }
-
+       cpu_dai_component.name = dai_link->cpu_name;
+       cpu_dai_component.of_node = dai_link->cpu_of_node;
+       cpu_dai_component.dai_name = dai_link->cpu_dai_name;
+       rtd->cpu_dai = snd_soc_find_dai(&cpu_dai_component);
        if (!rtd->cpu_dai) {
                dev_err(card->dev, "ASoC: CPU DAI %s not registered\n",
                        dai_link->cpu_dai_name);
@@ -963,15 +924,7 @@ static int soc_bind_dai_link(struct snd_soc_card *card, int num)
 
        /* Find CODEC from registered CODECs */
        for (i = 0; i < rtd->num_codecs; i++) {
-               struct snd_soc_codec *codec;
-               codec = soc_find_codec(codecs[i].of_node, codecs[i].name);
-               if (!codec) {
-                       dev_err(card->dev, "ASoC: CODEC %s not registered\n",
-                               codecs[i].name);
-                       return -EPROBE_DEFER;
-               }
-
-               codec_dais[i] = soc_find_codec_dai(codec, codecs[i].dai_name);
+               codec_dais[i] = snd_soc_find_dai(&codecs[i]);
                if (!codec_dais[i]) {
                        dev_err(card->dev, "ASoC: CODEC DAI %s not registered\n",
                                codecs[i].dai_name);
@@ -1012,68 +965,46 @@ static int soc_bind_dai_link(struct snd_soc_card *card, int num)
        return 0;
 }
 
-static int soc_remove_platform(struct snd_soc_platform *platform)
+static void soc_remove_component(struct snd_soc_component *component)
 {
-       int ret;
-
-       if (platform->driver->remove) {
-               ret = platform->driver->remove(platform);
-               if (ret < 0)
-                       dev_err(platform->dev, "ASoC: failed to remove %d\n",
-                               ret);
-       }
-
-       /* Make sure all DAPM widgets are freed */
-       snd_soc_dapm_free(&platform->component.dapm);
-
-       soc_cleanup_platform_debugfs(platform);
-       platform->probed = 0;
-       module_put(platform->dev->driver->owner);
-
-       return 0;
-}
+       if (!component->probed)
+               return;
 
-static void soc_remove_codec(struct snd_soc_codec *codec)
-{
-       int err;
+       /* This is a HACK and will be removed soon */
+       if (component->codec)
+               list_del(&component->codec->card_list);
 
-       if (codec->driver->remove) {
-               err = codec->driver->remove(codec);
-               if (err < 0)
-                       dev_err(codec->dev, "ASoC: failed to remove %d\n", err);
-       }
+       if (component->remove)
+               component->remove(component);
 
-       /* Make sure all DAPM widgets are freed */
-       snd_soc_dapm_free(&codec->dapm);
+       snd_soc_dapm_free(snd_soc_component_get_dapm(component));
 
-       soc_cleanup_codec_debugfs(codec);
-       codec->probed = 0;
-       list_del(&codec->card_list);
-       module_put(codec->dev->driver->owner);
+       soc_cleanup_component_debugfs(component);
+       component->probed = 0;
+       module_put(component->dev->driver->owner);
 }
 
-static void soc_remove_codec_dai(struct snd_soc_dai *codec_dai, int order)
+static void soc_remove_dai(struct snd_soc_dai *dai, int order)
 {
        int err;
 
-       if (codec_dai && codec_dai->probed &&
-                       codec_dai->driver->remove_order == order) {
-               if (codec_dai->driver->remove) {
-                       err = codec_dai->driver->remove(codec_dai);
+       if (dai && dai->probed &&
+                       dai->driver->remove_order == order) {
+               if (dai->driver->remove) {
+                       err = dai->driver->remove(dai);
                        if (err < 0)
-                               dev_err(codec_dai->dev,
+                               dev_err(dai->dev,
                                        "ASoC: failed to remove %s: %d\n",
-                                       codec_dai->name, err);
+                                       dai->name, err);
                }
-               codec_dai->probed = 0;
+               dai->probed = 0;
        }
 }
 
 static void soc_remove_link_dais(struct snd_soc_card *card, int num, int order)
 {
        struct snd_soc_pcm_runtime *rtd = &card->rtd[num];
-       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
-       int i, err;
+       int i;
 
        /* unregister the rtd device */
        if (rtd->dev_registered) {
@@ -1085,22 +1016,9 @@ static void soc_remove_link_dais(struct snd_soc_card *card, int num, int order)
 
        /* remove the CODEC DAI */
        for (i = 0; i < rtd->num_codecs; i++)
-               soc_remove_codec_dai(rtd->codec_dais[i], order);
+               soc_remove_dai(rtd->codec_dais[i], order);
 
-       /* remove the cpu_dai */
-       if (cpu_dai && cpu_dai->probed &&
-                       cpu_dai->driver->remove_order == order) {
-               if (cpu_dai->driver->remove) {
-                       err = cpu_dai->driver->remove(cpu_dai);
-                       if (err < 0)
-                               dev_err(cpu_dai->dev,
-                                       "ASoC: failed to remove %s: %d\n",
-                                       cpu_dai->name, err);
-               }
-               cpu_dai->probed = 0;
-               if (!cpu_dai->codec)
-                       module_put(cpu_dai->dev->driver->owner);
-       }
+       soc_remove_dai(rtd->cpu_dai, order);
 }
 
 static void soc_remove_link_components(struct snd_soc_card *card, int num,
@@ -1109,29 +1027,24 @@ static void soc_remove_link_components(struct snd_soc_card *card, int num,
        struct snd_soc_pcm_runtime *rtd = &card->rtd[num];
        struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
        struct snd_soc_platform *platform = rtd->platform;
-       struct snd_soc_codec *codec;
+       struct snd_soc_component *component;
        int i;
 
        /* remove the platform */
-       if (platform && platform->probed &&
-           platform->driver->remove_order == order) {
-               soc_remove_platform(platform);
-       }
+       if (platform && platform->component.driver->remove_order == order)
+               soc_remove_component(&platform->component);
 
        /* remove the CODEC-side CODEC */
        for (i = 0; i < rtd->num_codecs; i++) {
-               codec = rtd->codec_dais[i]->codec;
-               if (codec && codec->probed &&
-                   codec->driver->remove_order == order)
-                       soc_remove_codec(codec);
+               component = rtd->codec_dais[i]->component;
+               if (component->driver->remove_order == order)
+                       soc_remove_component(component);
        }
 
        /* remove any CPU-side CODEC */
        if (cpu_dai) {
-               codec = cpu_dai->codec;
-               if (codec && codec->probed &&
-                   codec->driver->remove_order == order)
-                       soc_remove_codec(codec);
+               if (cpu_dai->component->driver->remove_order == order)
+                       soc_remove_component(cpu_dai->component);
        }
 }
 
@@ -1173,137 +1086,78 @@ static void soc_set_name_prefix(struct snd_soc_card *card,
        }
 }
 
-static int soc_probe_codec(struct snd_soc_card *card,
-                          struct snd_soc_codec *codec)
+static int soc_probe_component(struct snd_soc_card *card,
+       struct snd_soc_component *component)
 {
-       int ret = 0;
-       const struct snd_soc_codec_driver *driver = codec->driver;
+       struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
        struct snd_soc_dai *dai;
+       int ret;
 
-       codec->component.card = card;
-       codec->dapm.card = card;
-       soc_set_name_prefix(card, &codec->component);
+       if (component->probed)
+               return 0;
+
+       component->card = card;
+       dapm->card = card;
+       soc_set_name_prefix(card, component);
 
-       if (!try_module_get(codec->dev->driver->owner))
+       if (!try_module_get(component->dev->driver->owner))
                return -ENODEV;
 
-       soc_init_codec_debugfs(codec);
+       soc_init_component_debugfs(component);
 
-       if (driver->dapm_widgets) {
-               ret = snd_soc_dapm_new_controls(&codec->dapm,
-                                               driver->dapm_widgets,
-                                               driver->num_dapm_widgets);
+       if (component->dapm_widgets) {
+               ret = snd_soc_dapm_new_controls(dapm, component->dapm_widgets,
+                       component->num_dapm_widgets);
 
                if (ret != 0) {
-                       dev_err(codec->dev,
+                       dev_err(component->dev,
                                "Failed to create new controls %d\n", ret);
                        goto err_probe;
                }
        }
 
-       /* Create DAPM widgets for each DAI stream */
-       list_for_each_entry(dai, &codec->component.dai_list, list) {
-               ret = snd_soc_dapm_new_dai_widgets(&codec->dapm, dai);
-
+       list_for_each_entry(dai, &component->dai_list, list) {
+               ret = snd_soc_dapm_new_dai_widgets(dapm, dai);
                if (ret != 0) {
-                       dev_err(codec->dev,
+                       dev_err(component->dev,
                                "Failed to create DAI widgets %d\n", ret);
                        goto err_probe;
                }
        }
 
-       codec->dapm.idle_bias_off = driver->idle_bias_off;
-
-       if (driver->probe) {
-               ret = driver->probe(codec);
+       if (component->probe) {
+               ret = component->probe(component);
                if (ret < 0) {
-                       dev_err(codec->dev,
-                               "ASoC: failed to probe CODEC %d\n", ret);
+                       dev_err(component->dev,
+                               "ASoC: failed to probe component %d\n", ret);
                        goto err_probe;
                }
-               WARN(codec->dapm.idle_bias_off &&
-                       codec->dapm.bias_level != SND_SOC_BIAS_OFF,
+
+               WARN(dapm->idle_bias_off &&
+                       dapm->bias_level != SND_SOC_BIAS_OFF,
                        "codec %s can not start from non-off bias with idle_bias_off==1\n",
-                       codec->component.name);
+                       component->name);
        }
 
-       if (driver->controls)
-               snd_soc_add_codec_controls(codec, driver->controls,
-                                    driver->num_controls);
-       if (driver->dapm_routes)
-               snd_soc_dapm_add_routes(&codec->dapm, driver->dapm_routes,
-                                       driver->num_dapm_routes);
-
-       /* mark codec as probed and add to card codec list */
-       codec->probed = 1;
-       list_add(&codec->card_list, &card->codec_dev_list);
-       list_add(&codec->dapm.list, &card->dapm_list);
-
-       return 0;
-
-err_probe:
-       soc_cleanup_codec_debugfs(codec);
-       module_put(codec->dev->driver->owner);
-
-       return ret;
-}
-
-static int soc_probe_platform(struct snd_soc_card *card,
-                          struct snd_soc_platform *platform)
-{
-       int ret = 0;
-       const struct snd_soc_platform_driver *driver = platform->driver;
-       struct snd_soc_component *component;
-       struct snd_soc_dai *dai;
-
-       platform->component.card = card;
-       platform->component.dapm.card = card;
+       if (component->controls)
+               snd_soc_add_component_controls(component, component->controls,
+                                    component->num_controls);
+       if (component->dapm_routes)
+               snd_soc_dapm_add_routes(dapm, component->dapm_routes,
+                                       component->num_dapm_routes);
 
-       if (!try_module_get(platform->dev->driver->owner))
-               return -ENODEV;
-
-       soc_init_platform_debugfs(platform);
+       component->probed = 1;
+       list_add(&dapm->list, &card->dapm_list);
 
-       if (driver->dapm_widgets)
-               snd_soc_dapm_new_controls(&platform->component.dapm,
-                       driver->dapm_widgets, driver->num_dapm_widgets);
-
-       /* Create DAPM widgets for each DAI stream */
-       list_for_each_entry(component, &component_list, list) {
-               if (component->dev != platform->dev)
-                       continue;
-               list_for_each_entry(dai, &component->dai_list, list)
-                       snd_soc_dapm_new_dai_widgets(&platform->component.dapm,
-                               dai);
-       }
-
-       platform->component.dapm.idle_bias_off = 1;
-
-       if (driver->probe) {
-               ret = driver->probe(platform);
-               if (ret < 0) {
-                       dev_err(platform->dev,
-                               "ASoC: failed to probe platform %d\n", ret);
-                       goto err_probe;
-               }
-       }
-
-       if (driver->controls)
-               snd_soc_add_platform_controls(platform, driver->controls,
-                                    driver->num_controls);
-       if (driver->dapm_routes)
-               snd_soc_dapm_add_routes(&platform->component.dapm,
-                       driver->dapm_routes, driver->num_dapm_routes);
-
-       /* mark platform as probed and add to card platform list */
-       platform->probed = 1;
-       list_add(&platform->component.dapm.list, &card->dapm_list);
+       /* This is a HACK and will be removed soon */
+       if (component->codec)
+               list_add(&component->codec->card_list, &card->codec_dev_list);
 
        return 0;
 
 err_probe:
-       soc_cleanup_platform_debugfs(platform);
-       module_put(platform->dev->driver->owner);
+       soc_cleanup_component_debugfs(component);
+       module_put(component->dev->driver->owner);
 
        return ret;
 }
@@ -1342,17 +1196,21 @@ static int soc_post_component_init(struct snd_soc_pcm_runtime *rtd,
        }
        rtd->dev_registered = 1;
 
-       /* add DAPM sysfs entries for this codec */
-       ret = snd_soc_dapm_sys_add(rtd->dev);
-       if (ret < 0)
-               dev_err(rtd->dev,
-                       "ASoC: failed to add codec dapm sysfs entries: %d\n", ret);
+       if (rtd->codec) {
+               /* add DAPM sysfs entries for this codec */
+               ret = snd_soc_dapm_sys_add(rtd->dev);
+               if (ret < 0)
+                       dev_err(rtd->dev,
+                               "ASoC: failed to add codec dapm sysfs entries: %d\n",
+                               ret);
 
-       /* add codec sysfs entries */
-       ret = device_create_file(rtd->dev, &dev_attr_codec_reg);
-       if (ret < 0)
-               dev_err(rtd->dev,
-                       "ASoC: failed to add codec sysfs files: %d\n", ret);
+               /* add codec sysfs entries */
+               ret = device_create_file(rtd->dev, &dev_attr_codec_reg);
+               if (ret < 0)
+                       dev_err(rtd->dev,
+                               "ASoC: failed to add codec sysfs files: %d\n",
+                               ret);
+       }
 
        return 0;
 }
@@ -1361,33 +1219,31 @@ static int soc_probe_link_components(struct snd_soc_card *card, int num,
                                     int order)
 {
        struct snd_soc_pcm_runtime *rtd = &card->rtd[num];
-       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
        struct snd_soc_platform *platform = rtd->platform;
+       struct snd_soc_component *component;
        int i, ret;
 
        /* probe the CPU-side component, if it is a CODEC */
-       if (cpu_dai->codec &&
-           !cpu_dai->codec->probed &&
-           cpu_dai->codec->driver->probe_order == order) {
-               ret = soc_probe_codec(card, cpu_dai->codec);
+       component = rtd->cpu_dai->component;
+       if (component->driver->probe_order == order) {
+               ret = soc_probe_component(card, component);
                if (ret < 0)
                        return ret;
        }
 
        /* probe the CODEC-side components */
        for (i = 0; i < rtd->num_codecs; i++) {
-               if (!rtd->codec_dais[i]->codec->probed &&
-                   rtd->codec_dais[i]->codec->driver->probe_order == order) {
-                       ret = soc_probe_codec(card, rtd->codec_dais[i]->codec);
+               component = rtd->codec_dais[i]->component;
+               if (component->driver->probe_order == order) {
+                       ret = soc_probe_component(card, component);
                        if (ret < 0)
                                return ret;
                }
        }
 
        /* probe the platform */
-       if (!platform->probed &&
-           platform->driver->probe_order == order) {
-               ret = soc_probe_platform(card, platform);
+       if (platform->component.driver->probe_order == order) {
+               ret = soc_probe_component(card, &platform->component);
                if (ret < 0)
                        return ret;
        }
@@ -1482,18 +1338,12 @@ static int soc_probe_link_dais(struct snd_soc_card *card, int num, int order)
        /* probe the cpu_dai */
        if (!cpu_dai->probed &&
                        cpu_dai->driver->probe_order == order) {
-               if (!cpu_dai->codec) {
-                       if (!try_module_get(cpu_dai->dev->driver->owner))
-                               return -ENODEV;
-               }
-
                if (cpu_dai->driver->probe) {
                        ret = cpu_dai->driver->probe(cpu_dai);
                        if (ret < 0) {
                                dev_err(cpu_dai->dev,
                                        "ASoC: failed to probe CPU DAI %s: %d\n",
                                        cpu_dai->name, ret);
-                               module_put(cpu_dai->dev->driver->owner);
                                return ret;
                        }
                }
@@ -1654,17 +1504,24 @@ static int soc_bind_aux_dev(struct snd_soc_card *card, int num)
 {
        struct snd_soc_pcm_runtime *rtd = &card->rtd_aux[num];
        struct snd_soc_aux_dev *aux_dev = &card->aux_dev[num];
-       const char *codecname = aux_dev->codec_name;
+       const char *name = aux_dev->codec_name;
 
-       rtd->codec = soc_find_codec(aux_dev->codec_of_node, codecname);
-       if (!rtd->codec) {
+       rtd->component = soc_find_component(aux_dev->codec_of_node, name);
+       if (!rtd->component) {
                if (aux_dev->codec_of_node)
-                       codecname = of_node_full_name(aux_dev->codec_of_node);
+                       name = of_node_full_name(aux_dev->codec_of_node);
 
-               dev_err(card->dev, "ASoC: %s not registered\n", codecname);
+               dev_err(card->dev, "ASoC: %s not registered\n", name);
                return -EPROBE_DEFER;
        }
 
+       /*
+        * Some places still reference rtd->codec, so we have to keep that
+        * initialized if the component is a CODEC. Once all those references
+        * have been removed, this code can be removed as well.
+        */
+        rtd->codec = rtd->component->codec;
+
        return 0;
 }
 
@@ -1674,18 +1531,13 @@ static int soc_probe_aux_dev(struct snd_soc_card *card, int num)
        struct snd_soc_aux_dev *aux_dev = &card->aux_dev[num];
        int ret;
 
-       if (rtd->codec->probed) {
-               dev_err(rtd->codec->dev, "ASoC: codec already probed\n");
-               return -EBUSY;
-       }
-
-       ret = soc_probe_codec(card, rtd->codec);
+       ret = soc_probe_component(card, rtd->component);
        if (ret < 0)
                return ret;
 
        /* do machine specific initialization */
        if (aux_dev->init) {
-               ret = aux_dev->init(&rtd->codec->dapm);
+               ret = aux_dev->init(rtd->component);
                if (ret < 0) {
                        dev_err(card->dev, "ASoC: failed to init %s: %d\n",
                                aux_dev->name, ret);
@@ -1699,7 +1551,7 @@ static int soc_probe_aux_dev(struct snd_soc_card *card, int num)
 static void soc_remove_aux_dev(struct snd_soc_card *card, int num)
 {
        struct snd_soc_pcm_runtime *rtd = &card->rtd_aux[num];
-       struct snd_soc_codec *codec = rtd->codec;
+       struct snd_soc_component *component = rtd->component;
 
        /* unregister the rtd device */
        if (rtd->dev_registered) {
@@ -1708,8 +1560,8 @@ static void soc_remove_aux_dev(struct snd_soc_card *card, int num)
                rtd->dev_registered = 0;
        }
 
-       if (codec && codec->probed)
-               soc_remove_codec(codec);
+       if (component && component->probed)
+               soc_remove_component(component);
 }
 
 static int snd_soc_init_codec_cache(struct snd_soc_codec *codec)
@@ -2107,19 +1959,14 @@ static struct platform_driver soc_driver = {
 int snd_soc_new_ac97_codec(struct snd_soc_codec *codec,
        struct snd_ac97_bus_ops *ops, int num)
 {
-       mutex_lock(&codec->mutex);
-
        codec->ac97 = kzalloc(sizeof(struct snd_ac97), GFP_KERNEL);
-       if (codec->ac97 == NULL) {
-               mutex_unlock(&codec->mutex);
+       if (codec->ac97 == NULL)
                return -ENOMEM;
-       }
 
        codec->ac97->bus = kzalloc(sizeof(struct snd_ac97_bus), GFP_KERNEL);
        if (codec->ac97->bus == NULL) {
                kfree(codec->ac97);
                codec->ac97 = NULL;
-               mutex_unlock(&codec->mutex);
                return -ENOMEM;
        }
 
@@ -2132,7 +1979,6 @@ int snd_soc_new_ac97_codec(struct snd_soc_codec *codec,
         */
        codec->ac97_created = 1;
 
-       mutex_unlock(&codec->mutex);
        return 0;
 }
 EXPORT_SYMBOL_GPL(snd_soc_new_ac97_codec);
@@ -2302,7 +2148,6 @@ EXPORT_SYMBOL_GPL(snd_soc_set_ac97_ops_of_reset);
  */
 void snd_soc_free_ac97_codec(struct snd_soc_codec *codec)
 {
-       mutex_lock(&codec->mutex);
 #ifdef CONFIG_SND_SOC_AC97_BUS
        soc_unregister_ac97_codec(codec);
 #endif
@@ -2310,7 +2155,6 @@ void snd_soc_free_ac97_codec(struct snd_soc_codec *codec)
        kfree(codec->ac97);
        codec->ac97 = NULL;
        codec->ac97_created = 0;
-       mutex_unlock(&codec->mutex);
 }
 EXPORT_SYMBOL_GPL(snd_soc_free_ac97_codec);
 
@@ -3027,9 +2871,10 @@ int snd_soc_put_volsw_range(struct snd_kcontrol *kcontrol,
        unsigned int val, val_mask;
        int ret;
 
-       val = ((ucontrol->value.integer.value[0] + min) & mask);
        if (invert)
-               val = max - val;
+               val = (max - ucontrol->value.integer.value[0]) & mask;
+       else
+               val = ((ucontrol->value.integer.value[0] + min) & mask);
        val_mask = mask << shift;
        val = val << shift;
 
@@ -3038,9 +2883,10 @@ int snd_soc_put_volsw_range(struct snd_kcontrol *kcontrol,
                return ret;
 
        if (snd_soc_volsw_is_stereo(mc)) {
-               val = ((ucontrol->value.integer.value[1] + min) & mask);
                if (invert)
-                       val = max - val;
+                       val = (max - ucontrol->value.integer.value[1]) & mask;
+               else
+                       val = ((ucontrol->value.integer.value[1] + min) & mask);
                val_mask = mask << shift;
                val = val << shift;
 
@@ -3085,8 +2931,9 @@ int snd_soc_get_volsw_range(struct snd_kcontrol *kcontrol,
        if (invert)
                ucontrol->value.integer.value[0] =
                        max - ucontrol->value.integer.value[0];
-       ucontrol->value.integer.value[0] =
-               ucontrol->value.integer.value[0] - min;
+       else
+               ucontrol->value.integer.value[0] =
+                       ucontrol->value.integer.value[0] - min;
 
        if (snd_soc_volsw_is_stereo(mc)) {
                ret = snd_soc_component_read(component, rreg, &val);
@@ -3097,8 +2944,9 @@ int snd_soc_get_volsw_range(struct snd_kcontrol *kcontrol,
                if (invert)
                        ucontrol->value.integer.value[1] =
                                max - ucontrol->value.integer.value[1];
-               ucontrol->value.integer.value[1] =
-                       ucontrol->value.integer.value[1] - min;
+               else
+                       ucontrol->value.integer.value[1] =
+                               ucontrol->value.integer.value[1] - min;
        }
 
        return 0;
@@ -3928,8 +3776,11 @@ EXPORT_SYMBOL_GPL(snd_soc_register_card);
  */
 int snd_soc_unregister_card(struct snd_soc_card *card)
 {
-       if (card->instantiated)
+       if (card->instantiated) {
+               card->instantiated = false;
+               snd_soc_dapm_shutdown(card);
                soc_cleanup_card_resources(card);
+       }
        dev_dbg(card->dev, "ASoC: Unregistered card '%s'\n", card->name);
 
        return 0;
@@ -4116,6 +3967,8 @@ static int snd_soc_component_initialize(struct snd_soc_component *component,
 
        component->dev = dev;
        component->driver = driver;
+       component->probe = component->driver->probe;
+       component->remove = component->driver->remove;
 
        if (!component->dapm_ptr)
                component->dapm_ptr = &component->dapm;
@@ -4124,19 +3977,42 @@ static int snd_soc_component_initialize(struct snd_soc_component *component,
        dapm->dev = dev;
        dapm->component = component;
        dapm->bias_level = SND_SOC_BIAS_OFF;
+       dapm->idle_bias_off = true;
        if (driver->seq_notifier)
                dapm->seq_notifier = snd_soc_component_seq_notifier;
        if (driver->stream_event)
                dapm->stream_event = snd_soc_component_stream_event;
 
+       component->controls = driver->controls;
+       component->num_controls = driver->num_controls;
+       component->dapm_widgets = driver->dapm_widgets;
+       component->num_dapm_widgets = driver->num_dapm_widgets;
+       component->dapm_routes = driver->dapm_routes;
+       component->num_dapm_routes = driver->num_dapm_routes;
+
        INIT_LIST_HEAD(&component->dai_list);
        mutex_init(&component->io_mutex);
 
        return 0;
 }
 
+static void snd_soc_component_init_regmap(struct snd_soc_component *component)
+{
+       if (!component->regmap)
+               component->regmap = dev_get_regmap(component->dev, NULL);
+       if (component->regmap) {
+               int val_bytes = regmap_get_val_bytes(component->regmap);
+               /* Errors are legitimate for non-integer byte multiples */
+               if (val_bytes > 0)
+                       component->val_bytes = val_bytes;
+       }
+}
+
 static void snd_soc_component_add_unlocked(struct snd_soc_component *component)
 {
+       if (!component->write && !component->read)
+               snd_soc_component_init_regmap(component);
+
        list_add(&component->list, &component_list);
 }
 
@@ -4225,22 +4101,18 @@ found:
 }
 EXPORT_SYMBOL_GPL(snd_soc_unregister_component);
 
-static int snd_soc_platform_drv_write(struct snd_soc_component *component,
-       unsigned int reg, unsigned int val)
+static int snd_soc_platform_drv_probe(struct snd_soc_component *component)
 {
        struct snd_soc_platform *platform = snd_soc_component_to_platform(component);
 
-       return platform->driver->write(platform, reg, val);
+       return platform->driver->probe(platform);
 }
 
-static int snd_soc_platform_drv_read(struct snd_soc_component *component,
-       unsigned int reg, unsigned int *val)
+static void snd_soc_platform_drv_remove(struct snd_soc_component *component)
 {
        struct snd_soc_platform *platform = snd_soc_component_to_platform(component);
 
-       *val = platform->driver->read(platform, reg);
-
-       return 0;
+       platform->driver->remove(platform);
 }
 
 /**
@@ -4261,10 +4133,15 @@ int snd_soc_add_platform(struct device *dev, struct snd_soc_platform *platform,
 
        platform->dev = dev;
        platform->driver = platform_drv;
-       if (platform_drv->write)
-               platform->component.write = snd_soc_platform_drv_write;
-       if (platform_drv->read)
-               platform->component.read = snd_soc_platform_drv_read;
+
+       if (platform_drv->probe)
+               platform->component.probe = snd_soc_platform_drv_probe;
+       if (platform_drv->remove)
+               platform->component.remove = snd_soc_platform_drv_remove;
+
+#ifdef CONFIG_DEBUG_FS
+       platform->component.debugfs_prefix = "platform";
+#endif
 
        mutex_lock(&client_mutex);
        snd_soc_component_add_unlocked(&platform->component);
@@ -4315,10 +4192,10 @@ void snd_soc_remove_platform(struct snd_soc_platform *platform)
        snd_soc_component_del_unlocked(&platform->component);
        mutex_unlock(&client_mutex);
 
-       snd_soc_component_cleanup(&platform->component);
-
        dev_dbg(platform->dev, "ASoC: Unregistered platform '%s'\n",
                platform->component.name);
+
+       snd_soc_component_cleanup(&platform->component);
 }
 EXPORT_SYMBOL_GPL(snd_soc_remove_platform);
 
@@ -4386,6 +4263,20 @@ static void fixup_codec_formats(struct snd_soc_pcm_stream *stream)
                        stream->formats |= codec_format_map[i];
 }
 
+static int snd_soc_codec_drv_probe(struct snd_soc_component *component)
+{
+       struct snd_soc_codec *codec = snd_soc_component_to_codec(component);
+
+       return codec->driver->probe(codec);
+}
+
+static void snd_soc_codec_drv_remove(struct snd_soc_component *component)
+{
+       struct snd_soc_codec *codec = snd_soc_component_to_codec(component);
+
+       codec->driver->remove(codec);
+}
+
 static int snd_soc_codec_drv_write(struct snd_soc_component *component,
        unsigned int reg, unsigned int val)
 {
@@ -4424,7 +4315,6 @@ int snd_soc_register_codec(struct device *dev,
 {
        struct snd_soc_codec *codec;
        struct snd_soc_dai *dai;
-       struct regmap *regmap;
        int ret, i;
 
        dev_dbg(dev, "codec register %s\n", dev_name(dev));
@@ -4434,18 +4324,37 @@ int snd_soc_register_codec(struct device *dev,
                return -ENOMEM;
 
        codec->component.dapm_ptr = &codec->dapm;
+       codec->component.codec = codec;
 
        ret = snd_soc_component_initialize(&codec->component,
                        &codec_drv->component_driver, dev);
        if (ret)
                goto err_free;
 
+       if (codec_drv->controls) {
+               codec->component.controls = codec_drv->controls;
+               codec->component.num_controls = codec_drv->num_controls;
+       }
+       if (codec_drv->dapm_widgets) {
+               codec->component.dapm_widgets = codec_drv->dapm_widgets;
+               codec->component.num_dapm_widgets = codec_drv->num_dapm_widgets;
+       }
+       if (codec_drv->dapm_routes) {
+               codec->component.dapm_routes = codec_drv->dapm_routes;
+               codec->component.num_dapm_routes = codec_drv->num_dapm_routes;
+       }
+
+       if (codec_drv->probe)
+               codec->component.probe = snd_soc_codec_drv_probe;
+       if (codec_drv->remove)
+               codec->component.remove = snd_soc_codec_drv_remove;
        if (codec_drv->write)
                codec->component.write = snd_soc_codec_drv_write;
        if (codec_drv->read)
                codec->component.read = snd_soc_codec_drv_read;
        codec->component.ignore_pmdown_time = codec_drv->ignore_pmdown_time;
-       codec->dapm.codec = codec;
+       codec->dapm.idle_bias_off = codec_drv->idle_bias_off;
+       codec->dapm.suspend_bias_off = codec_drv->suspend_bias_off;
        if (codec_drv->seq_notifier)
                codec->dapm.seq_notifier = codec_drv->seq_notifier;
        if (codec_drv->set_bias_level)
@@ -4455,23 +4364,13 @@ int snd_soc_register_codec(struct device *dev,
        codec->component.val_bytes = codec_drv->reg_word_size;
        mutex_init(&codec->mutex);
 
-       if (!codec->component.write) {
-               if (codec_drv->get_regmap)
-                       regmap = codec_drv->get_regmap(dev);
-               else
-                       regmap = dev_get_regmap(dev, NULL);
-
-               if (regmap) {
-                       ret = snd_soc_component_init_io(&codec->component,
-                               regmap);
-                       if (ret) {
-                               dev_err(codec->dev,
-                                               "Failed to set cache I/O:%d\n",
-                                               ret);
-                               goto err_cleanup;
-                       }
-               }
-       }
+#ifdef CONFIG_DEBUG_FS
+       codec->component.init_debugfs = soc_init_codec_debugfs;
+       codec->component.debugfs_prefix = "codec";
+#endif
+
+       if (codec_drv->get_regmap)
+               codec->component.regmap = codec_drv->get_regmap(dev);
 
        for (i = 0; i < num_dai; i++) {
                fixup_codec_formats(&dai_drv[i].playback);
index 177bd8639ef93e6b97a20e1cd022224e62cf14bf..c61cb9cedbcd283c22625cac53367606fb0fc18a 100644 (file)
@@ -326,12 +326,13 @@ static struct list_head *dapm_kcontrol_get_path_list(
        list_for_each_entry(path, dapm_kcontrol_get_path_list(kcontrol), \
                list_kcontrol)
 
-static unsigned int dapm_kcontrol_get_value(const struct snd_kcontrol *kcontrol)
+unsigned int dapm_kcontrol_get_value(const struct snd_kcontrol *kcontrol)
 {
        struct dapm_kcontrol_data *data = snd_kcontrol_chip(kcontrol);
 
        return data->value;
 }
+EXPORT_SYMBOL_GPL(dapm_kcontrol_get_value);
 
 static bool dapm_kcontrol_set_value(const struct snd_kcontrol *kcontrol,
        unsigned int value)
@@ -591,9 +592,9 @@ static int dapm_create_or_share_mixmux_kcontrol(struct snd_soc_dapm_widget *w,
        int shared;
        struct snd_kcontrol *kcontrol;
        bool wname_in_long_name, kcname_in_long_name;
-       char *long_name;
+       char *long_name = NULL;
        const char *name;
-       int ret;
+       int ret = 0;
 
        prefix = soc_dapm_prefix(dapm);
        if (prefix)
@@ -652,15 +653,17 @@ static int dapm_create_or_share_mixmux_kcontrol(struct snd_soc_dapm_widget *w,
 
                kcontrol = snd_soc_cnew(&w->kcontrol_news[kci], NULL, name,
                                        prefix);
-               kfree(long_name);
-               if (!kcontrol)
-                       return -ENOMEM;
+               if (!kcontrol) {
+                       ret = -ENOMEM;
+                       goto exit_free;
+               }
+
                kcontrol->private_free = dapm_kcontrol_free;
 
                ret = dapm_kcontrol_data_alloc(w, kcontrol);
                if (ret) {
                        snd_ctl_free_one(kcontrol);
-                       return ret;
+                       goto exit_free;
                }
 
                ret = snd_ctl_add(card, kcontrol);
@@ -668,17 +671,18 @@ static int dapm_create_or_share_mixmux_kcontrol(struct snd_soc_dapm_widget *w,
                        dev_err(dapm->dev,
                                "ASoC: failed to add widget %s dapm kcontrol %s: %d\n",
                                w->name, name, ret);
-                       return ret;
+                       goto exit_free;
                }
        }
 
        ret = dapm_kcontrol_add_widget(kcontrol, w);
-       if (ret)
-               return ret;
+       if (ret == 0)
+               w->kcontrols[kci] = kcontrol;
 
-       w->kcontrols[kci] = kcontrol;
+exit_free:
+       kfree(long_name);
 
-       return 0;
+       return ret;
 }
 
 /* create new dapm mixer control */
@@ -1683,6 +1687,22 @@ static void dapm_power_one_widget(struct snd_soc_dapm_widget *w,
        }
 }
 
+static bool dapm_idle_bias_off(struct snd_soc_dapm_context *dapm)
+{
+       if (dapm->idle_bias_off)
+               return true;
+
+       switch (snd_power_get_state(dapm->card->snd_card)) {
+       case SNDRV_CTL_POWER_D3hot:
+       case SNDRV_CTL_POWER_D3cold:
+               return dapm->suspend_bias_off;
+       default:
+               break;
+       }
+
+       return false;
+}
+
 /*
  * Scan each dapm widget for complete audio path.
  * A complete path is a route that has valid endpoints i.e.:-
@@ -1706,7 +1726,7 @@ static int dapm_power_widgets(struct snd_soc_card *card, int event)
        trace_snd_soc_dapm_start(card);
 
        list_for_each_entry(d, &card->dapm_list, list) {
-               if (d->idle_bias_off)
+               if (dapm_idle_bias_off(d))
                        d->target_bias_level = SND_SOC_BIAS_OFF;
                else
                        d->target_bias_level = SND_SOC_BIAS_STANDBY;
@@ -1772,7 +1792,7 @@ static int dapm_power_widgets(struct snd_soc_card *card, int event)
                if (d->target_bias_level > bias)
                        bias = d->target_bias_level;
        list_for_each_entry(d, &card->dapm_list, list)
-               if (!d->idle_bias_off)
+               if (!dapm_idle_bias_off(d))
                        d->target_bias_level = bias;
 
        trace_snd_soc_dapm_walk_done(card);
@@ -3109,7 +3129,8 @@ snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm,
        }
 
        w->dapm = dapm;
-       w->codec = dapm->codec;
+       if (dapm->component)
+               w->codec = dapm->component->codec;
        INIT_LIST_HEAD(&w->sources);
        INIT_LIST_HEAD(&w->sinks);
        INIT_LIST_HEAD(&w->list);
index 6307f85e871b1d33934877990275cca6c8d08acb..b329b84bc5af77d50e1fd2803252d259cabf7602 100644 (file)
@@ -336,10 +336,12 @@ static const struct snd_pcm_ops dmaengine_pcm_ops = {
 };
 
 static const struct snd_soc_platform_driver dmaengine_pcm_platform = {
+       .component_driver = {
+               .probe_order = SND_SOC_COMP_ORDER_LATE,
+       },
        .ops            = &dmaengine_pcm_ops,
        .pcm_new        = dmaengine_pcm_new,
        .pcm_free       = dmaengine_pcm_free,
-       .probe_order    = SND_SOC_COMP_ORDER_LATE,
 };
 
 static const char * const dmaengine_pcm_dma_channel_names[] = {
index 7767fbd73eb7a464434c805a901fa94fe64a5e04..9b3939049cefc357581200063108124c3adf8907 100644 (file)
@@ -271,31 +271,3 @@ int snd_soc_platform_write(struct snd_soc_platform *platform,
        return snd_soc_component_write(&platform->component, reg, val);
 }
 EXPORT_SYMBOL_GPL(snd_soc_platform_write);
-
-/**
- * snd_soc_component_init_io() - Initialize regmap IO
- *
- * @component: component to initialize
- * @regmap: regmap instance to use for IO operations
- *
- * Return: 0 on success, a negative error code otherwise
- */
-int snd_soc_component_init_io(struct snd_soc_component *component,
-       struct regmap *regmap)
-{
-       int ret;
-
-       if (!regmap)
-               return -EINVAL;
-
-       ret = regmap_get_val_bytes(regmap);
-       /* Errors are legitimate for non-integer byte
-        * multiples */
-       if (ret > 0)
-               component->val_bytes = ret;
-
-       component->regmap = regmap;
-
-       return 0;
-}
-EXPORT_SYMBOL_GPL(snd_soc_component_init_io);
index 642c862407520db3e36b4ddadf1b5d7a6b467749..002311afdeaa8bd6ceb40d120b0c6afaa13c6119 100644 (file)
@@ -352,7 +352,7 @@ static void soc_pcm_apply_msb(struct snd_pcm_substream *substream)
        } else {
                for (i = 0; i < rtd->num_codecs; i++) {
                        codec_dai = rtd->codec_dais[i];
-                       if (codec_dai->driver->playback.sig_bits == 0) {
+                       if (codec_dai->driver->capture.sig_bits == 0) {
                                bits = 0;
                                break;
                        }
index b86cd9936ef19cad0c1ca04c60c52ed746f46b50..01921d7e73fa65392da04ed823a60ef0be42c34a 100644 (file)
@@ -42,6 +42,7 @@
 struct tegra_max98090 {
        struct tegra_asoc_utils_data util_data;
        int gpio_hp_det;
+       int gpio_mic_det;
 };
 
 static int tegra_max98090_asoc_hw_params(struct snd_pcm_substream *substream,
@@ -112,6 +113,22 @@ static struct snd_soc_jack_gpio tegra_max98090_hp_jack_gpio = {
        .invert = 1,
 };
 
+static struct snd_soc_jack tegra_max98090_mic_jack;
+
+static struct snd_soc_jack_pin tegra_max98090_mic_jack_pins[] = {
+       {
+               .pin = "Mic Jack",
+               .mask = SND_JACK_MICROPHONE,
+       },
+};
+
+static struct snd_soc_jack_gpio tegra_max98090_mic_jack_gpio = {
+       .name = "Mic detection",
+       .report = SND_JACK_MICROPHONE,
+       .debounce_time = 150,
+       .invert = 1,
+};
+
 static const struct snd_soc_dapm_widget tegra_max98090_dapm_widgets[] = {
        SND_SOC_DAPM_HP("Headphones", NULL),
        SND_SOC_DAPM_SPK("Speakers", NULL),
@@ -141,6 +158,19 @@ static int tegra_max98090_asoc_init(struct snd_soc_pcm_runtime *rtd)
                                        &tegra_max98090_hp_jack_gpio);
        }
 
+       if (gpio_is_valid(machine->gpio_mic_det)) {
+               snd_soc_jack_new(codec, "Mic Jack", SND_JACK_MICROPHONE,
+                                &tegra_max98090_mic_jack);
+               snd_soc_jack_add_pins(&tegra_max98090_mic_jack,
+                                     ARRAY_SIZE(tegra_max98090_mic_jack_pins),
+                                     tegra_max98090_mic_jack_pins);
+
+               tegra_max98090_mic_jack_gpio.gpio = machine->gpio_mic_det;
+               snd_soc_jack_add_gpios(&tegra_max98090_mic_jack,
+                                      1,
+                                      &tegra_max98090_mic_jack_gpio);
+       }
+
        return 0;
 }
 
@@ -153,6 +183,11 @@ static int tegra_max98090_card_remove(struct snd_soc_card *card)
                                        &tegra_max98090_hp_jack_gpio);
        }
 
+       if (gpio_is_valid(machine->gpio_mic_det)) {
+               snd_soc_jack_free_gpios(&tegra_max98090_mic_jack, 1,
+                                       &tegra_max98090_mic_jack_gpio);
+       }
+
        return 0;
 }
 
@@ -201,6 +236,11 @@ static int tegra_max98090_probe(struct platform_device *pdev)
        if (machine->gpio_hp_det == -EPROBE_DEFER)
                return -EPROBE_DEFER;
 
+       machine->gpio_mic_det =
+                       of_get_named_gpio(np, "nvidia,mic-det-gpios", 0);
+       if (machine->gpio_mic_det == -EPROBE_DEFER)
+               return -EPROBE_DEFER;
+
        ret = snd_soc_of_parse_card_name(card, "nvidia,model");
        if (ret)
                goto err;
index f0829de28708b20724fffddf831bec56818152d1..cd71fd889d8bf834cc71cd1e491bdd9c590d78ef 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/platform_device.h>
 #include <linux/scatterlist.h>
 #include <linux/slab.h>
+#include <linux/dmaengine.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
@@ -137,7 +138,7 @@ txx9aclc_dma_submit(struct txx9aclc_dmadata *dmadata, dma_addr_t buf_dma_addr)
        }
        desc->callback = txx9aclc_dma_complete;
        desc->callback_param = dmadata;
-       desc->tx_submit(desc);
+       dmaengine_submit(desc);
        return desc;
 }
 
@@ -160,7 +161,7 @@ static void txx9aclc_dma_tasklet(unsigned long data)
                void __iomem *base = drvdata->base;
 
                spin_unlock_irqrestore(&dmadata->dma_lock, flags);
-               chan->device->device_control(chan, DMA_TERMINATE_ALL, 0);
+               dmaengine_terminate_all(chan);
                /* first time */
                for (i = 0; i < NR_DMA_CHAIN; i++) {
                        desc = txx9aclc_dma_submit(dmadata,
@@ -169,7 +170,7 @@ static void txx9aclc_dma_tasklet(unsigned long data)
                                return;
                }
                dmadata->dmacount = NR_DMA_CHAIN;
-               chan->device->device_issue_pending(chan);
+               dma_async_issue_pending(chan);
                spin_lock_irqsave(&dmadata->dma_lock, flags);
                __raw_writel(ctlbit, base + ACCTLEN);
                dmadata->frag_count = NR_DMA_CHAIN % dmadata->frags;
@@ -188,7 +189,7 @@ static void txx9aclc_dma_tasklet(unsigned long data)
                        dmadata->frag_count * dmadata->frag_bytes);
                if (!desc)
                        return;
-               chan->device->device_issue_pending(chan);
+               dma_async_issue_pending(chan);
 
                spin_lock_irqsave(&dmadata->dma_lock, flags);
                dmadata->frag_count++;
@@ -266,7 +267,7 @@ static int txx9aclc_pcm_close(struct snd_pcm_substream *substream)
        struct dma_chan *chan = dmadata->dma_chan;
 
        dmadata->frag_count = -1;
-       chan->device->device_control(chan, DMA_TERMINATE_ALL, 0);
+       dmaengine_terminate_all(chan);
        return 0;
 }
 
@@ -398,8 +399,7 @@ static int txx9aclc_pcm_remove(struct snd_soc_platform *platform)
                struct dma_chan *chan = dmadata->dma_chan;
                if (chan) {
                        dmadata->frag_count = -1;
-                       chan->device->device_control(chan,
-                                                    DMA_TERMINATE_ALL, 0);
+                       dmaengine_terminate_all(chan);
                        dma_release_channel(chan);
                }
                dev->dmadata[i].dma_chan = NULL;
index 7103b0908d130436743bceb6bf422222bd421466..272844746135763faa6425aae3fb8dc3bfc9ec50 100644 (file)
@@ -816,6 +816,11 @@ int snd_usb_caiaq_audio_init(struct snd_usb_caiaqdev *cdev)
                return -EINVAL;
        }
 
+       if (cdev->n_streams < 2) {
+               dev_err(dev, "bogus number of streams: %d\n", cdev->n_streams);
+               return -EINVAL;
+       }
+
        ret = snd_pcm_new(cdev->chip.card, cdev->product_name, 0,
                        cdev->n_audio_out, cdev->n_audio_in, &cdev->pcm);
 
index b2b6f398a4e1dfcc349bc71ef25cf060f59b1d4c..d3d49525a16bef649194ae410f64b72f243fc1f2 100644 (file)
@@ -1506,6 +1506,12 @@ static struct port_info {
        PORT_INFO(vendor, product, num, name, 0, \
                  SNDRV_SEQ_PORT_TYPE_MIDI_GENERIC | \
                  SNDRV_SEQ_PORT_TYPE_HARDWARE)
+#define GM_SYNTH_PORT(vendor, product, num, name, voices) \
+       PORT_INFO(vendor, product, num, name, voices, \
+                 SNDRV_SEQ_PORT_TYPE_MIDI_GENERIC | \
+                 SNDRV_SEQ_PORT_TYPE_MIDI_GM | \
+                 SNDRV_SEQ_PORT_TYPE_HARDWARE | \
+                 SNDRV_SEQ_PORT_TYPE_SYNTHESIZER)
 #define ROLAND_SYNTH_PORT(vendor, product, num, name, voices) \
        PORT_INFO(vendor, product, num, name, voices, \
                  SNDRV_SEQ_PORT_TYPE_MIDI_GENERIC | \
@@ -1525,6 +1531,11 @@ static struct port_info {
                  SNDRV_SEQ_PORT_TYPE_MIDI_MT32 | \
                  SNDRV_SEQ_PORT_TYPE_HARDWARE | \
                  SNDRV_SEQ_PORT_TYPE_SYNTHESIZER)
+       /* Yamaha MOTIF XF */
+       GM_SYNTH_PORT(0x0499, 0x105c, 0, "%s Tone Generator", 128),
+       CONTROL_PORT(0x0499, 0x105c, 1, "%s Remote Control"),
+       EXTERNAL_PORT(0x0499, 0x105c, 2, "%s Thru"),
+       CONTROL_PORT(0x0499, 0x105c, 3, "%s Editor"),
        /* Roland UA-100 */
        CONTROL_PORT(0x0582, 0x0000, 2, "%s Control"),
        /* Roland SC-8850 */
index 19a921eb75f112d47cf25db29fea2ac332a69ca2..d2aa45a8d89546b378fa05fc94750a35f6fe5c18 100644 (file)
@@ -1174,5 +1174,21 @@ u64 snd_usb_interface_dsd_format_quirks(struct snd_usb_audio *chip,
                }
        }
 
+       /* XMOS based USB DACs */
+       switch (chip->usb_id) {
+       /* iFi Audio micro/nano iDSD */
+       case USB_ID(0x20b1, 0x3008):
+               if (fp->altsetting == 2)
+                       return SNDRV_PCM_FMTBIT_DSD_U32_LE;
+               break;
+       /* DIYINHK DSD DXD 384kHz USB to I2S/DSD */
+       case USB_ID(0x20b1, 0x2009):
+               if (fp->altsetting == 3)
+                       return SNDRV_PCM_FMTBIT_DSD_U32_LE;
+               break;
+       default:
+               break;
+       }
+
        return 0;
 }
index ce00f7ee6455248d92dba7016b2770c824e897f9..36c08b1f4afbc9379007c3b49e79fb5f87a3f1c9 100644 (file)
@@ -10,9 +10,14 @@ LIB_OBJS=
 
 LIB_H += fs/debugfs.h
 LIB_H += fs/fs.h
+# See comment below about piggybacking...
+LIB_H += fd/array.h
 
 LIB_OBJS += $(OUTPUT)fs/debugfs.o
 LIB_OBJS += $(OUTPUT)fs/fs.o
+# XXX piggybacking here, need to introduce libapikfd, or rename this
+# to plain libapik.a and make it have it all api goodies
+LIB_OBJS += $(OUTPUT)fd/array.o
 
 LIBFILE = libapikfs.a
 
@@ -29,7 +34,7 @@ $(LIBFILE): $(LIB_OBJS)
 $(LIB_OBJS): $(LIB_H)
 
 libapi_dirs:
-       $(QUIET_MKDIR)mkdir -p $(OUTPUT)fs/
+       $(QUIET_MKDIR)mkdir -p $(OUTPUT)fd $(OUTPUT)fs
 
 $(OUTPUT)%.o: %.c libapi_dirs
        $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) $<
diff --git a/tools/lib/api/fd/array.c b/tools/lib/api/fd/array.c
new file mode 100644 (file)
index 0000000..0e636c4
--- /dev/null
@@ -0,0 +1,127 @@
+/*
+ * Copyright (C) 2014, Red Hat Inc, Arnaldo Carvalho de Melo <acme@redhat.com>
+ *
+ * Released under the GPL v2. (and only v2, not any later version)
+ */
+#include "array.h"
+#include <errno.h>
+#include <fcntl.h>
+#include <poll.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+void fdarray__init(struct fdarray *fda, int nr_autogrow)
+{
+       fda->entries     = NULL;
+       fda->priv        = NULL;
+       fda->nr          = fda->nr_alloc = 0;
+       fda->nr_autogrow = nr_autogrow;
+}
+
+int fdarray__grow(struct fdarray *fda, int nr)
+{
+       void *priv;
+       int nr_alloc = fda->nr_alloc + nr;
+       size_t psize = sizeof(fda->priv[0]) * nr_alloc;
+       size_t size  = sizeof(struct pollfd) * nr_alloc;
+       struct pollfd *entries = realloc(fda->entries, size);
+
+       if (entries == NULL)
+               return -ENOMEM;
+
+       priv = realloc(fda->priv, psize);
+       if (priv == NULL) {
+               free(entries);
+               return -ENOMEM;
+       }
+
+       fda->nr_alloc = nr_alloc;
+       fda->entries  = entries;
+       fda->priv     = priv;
+       return 0;
+}
+
+struct fdarray *fdarray__new(int nr_alloc, int nr_autogrow)
+{
+       struct fdarray *fda = calloc(1, sizeof(*fda));
+
+       if (fda != NULL) {
+               if (fdarray__grow(fda, nr_alloc)) {
+                       free(fda);
+                       fda = NULL;
+               } else {
+                       fda->nr_autogrow = nr_autogrow;
+               }
+       }
+
+       return fda;
+}
+
+void fdarray__exit(struct fdarray *fda)
+{
+       free(fda->entries);
+       free(fda->priv);
+       fdarray__init(fda, 0);
+}
+
+void fdarray__delete(struct fdarray *fda)
+{
+       fdarray__exit(fda);
+       free(fda);
+}
+
+int fdarray__add(struct fdarray *fda, int fd, short revents)
+{
+       int pos = fda->nr;
+
+       if (fda->nr == fda->nr_alloc &&
+           fdarray__grow(fda, fda->nr_autogrow) < 0)
+               return -ENOMEM;
+
+       fda->entries[fda->nr].fd     = fd;
+       fda->entries[fda->nr].events = revents;
+       fda->nr++;
+       return pos;
+}
+
+int fdarray__filter(struct fdarray *fda, short revents,
+                   void (*entry_destructor)(struct fdarray *fda, int fd))
+{
+       int fd, nr = 0;
+
+       if (fda->nr == 0)
+               return 0;
+
+       for (fd = 0; fd < fda->nr; ++fd) {
+               if (fda->entries[fd].revents & revents) {
+                       if (entry_destructor)
+                               entry_destructor(fda, fd);
+
+                       continue;
+               }
+
+               if (fd != nr) {
+                       fda->entries[nr] = fda->entries[fd];
+                       fda->priv[nr]    = fda->priv[fd];
+               }
+
+               ++nr;
+       }
+
+       return fda->nr = nr;
+}
+
+int fdarray__poll(struct fdarray *fda, int timeout)
+{
+       return poll(fda->entries, fda->nr, timeout);
+}
+
+int fdarray__fprintf(struct fdarray *fda, FILE *fp)
+{
+       int fd, printed = fprintf(fp, "%d [ ", fda->nr);
+
+       for (fd = 0; fd < fda->nr; ++fd)
+               printed += fprintf(fp, "%s%d", fd ? ", " : "", fda->entries[fd].fd);
+
+       return printed + fprintf(fp, " ]");
+}
diff --git a/tools/lib/api/fd/array.h b/tools/lib/api/fd/array.h
new file mode 100644 (file)
index 0000000..45db018
--- /dev/null
@@ -0,0 +1,46 @@
+#ifndef __API_FD_ARRAY__
+#define __API_FD_ARRAY__
+
+#include <stdio.h>
+
+struct pollfd;
+
+/**
+ * struct fdarray: Array of file descriptors
+ *
+ * @priv: Per array entry priv area, users should access just its contents,
+ *       not set it to anything, as it is kept in synch with @entries, being
+ *       realloc'ed, * for instance, in fdarray__{grow,filter}.
+ *
+ *       I.e. using 'fda->priv[N].idx = * value' where N < fda->nr is ok,
+ *       but doing 'fda->priv = malloc(M)' is not allowed.
+ */
+struct fdarray {
+       int            nr;
+       int            nr_alloc;
+       int            nr_autogrow;
+       struct pollfd *entries;
+       union {
+               int    idx;
+       } *priv;
+};
+
+void fdarray__init(struct fdarray *fda, int nr_autogrow);
+void fdarray__exit(struct fdarray *fda);
+
+struct fdarray *fdarray__new(int nr_alloc, int nr_autogrow);
+void fdarray__delete(struct fdarray *fda);
+
+int fdarray__add(struct fdarray *fda, int fd, short revents);
+int fdarray__poll(struct fdarray *fda, int timeout);
+int fdarray__filter(struct fdarray *fda, short revents,
+                   void (*entry_destructor)(struct fdarray *fda, int fd));
+int fdarray__grow(struct fdarray *fda, int extra);
+int fdarray__fprintf(struct fdarray *fda, FILE *fp);
+
+static inline int fdarray__available_entries(struct fdarray *fda)
+{
+       return fda->nr_alloc - fda->nr;
+}
+
+#endif /* __API_FD_ARRAY__ */
index 782d86e961b9fb79195407e7634bceae9d55f279..717221e98450a37ffb0eb726e0ffd2773af300ff 100644 (file)
@@ -15,6 +15,7 @@ perf.data
 perf.data.old
 output.svg
 perf-archive
+perf-with-kcore
 tags
 TAGS
 cscope*
index 1513935c399b67c6e2158b9041af548edf3e610c..aaa869be3dc1d48ac5573163d752d08b9152a295 100644 (file)
@@ -104,6 +104,9 @@ OPTIONS
        Specify path to the executable or shared library file for user
        space tracing. Can also be used with --funcs option.
 
+--demangle-kernel::
+       Demangle kernel symbols.
+
 In absence of -m/-x options, perf probe checks if the first argument after
 the options is an absolute path name. If its an absolute path, perf probe
 uses it as a target module/target user space binary to probe.
index d2b59af62bc0ad6ddff918f2aee04a67fbf5541f..0927bf4e6c2a6c78b30cc185bf0c4637b2c5082e 100644 (file)
@@ -147,7 +147,7 @@ OPTIONS
 -w::
 --column-widths=<width[,width...]>::
        Force each column width to the provided list, for large terminal
-       readability.
+       readability.  0 means no limit (default behavior).
 
 -t::
 --field-separator=::
@@ -276,6 +276,9 @@ OPTIONS
        Demangle symbol names to human readable form. It's enabled by default,
        disable with --no-demangle.
 
+--demangle-kernel::
+       Demangle kernel symbol names to human readable form (for C++ kernels).
+
 --mem-mode::
        Use the data addresses of samples in addition to instruction addresses
        to build the histograms.  To generate meaningful output, the perf.data
index 180ae02137a519acf1b3d779a92eb651db6b4aff..3265b10705188027ab30256f7475d218d78f6fbb 100644 (file)
@@ -98,6 +98,9 @@ Default is to monitor all CPUS.
 --hide_user_symbols::
         Hide user symbols.
 
+--demangle-kernel::
+        Demangle kernel symbols.
+
 -D::
 --dump-symtab::
         Dump the symbol table used for profiling.
@@ -193,6 +196,12 @@ Default is to monitor all CPUS.
        sum of shown entries will be always 100%. "absolute" means it retains
        the original value before and after the filter is applied.
 
+-w::
+--column-widths=<width[,width...]>::
+       Force each column width to the provided list, for large terminal
+       readability.  0 means no limit (default behavior).
+
+
 INTERACTIVE PROMPTING KEYS
 --------------------------
 
index 2240974b7745874f3e2e39c3ee9f98d18c8c7912..262916f4a37758447ec0ece4aa17a956c332dd84 100644 (file)
@@ -126,6 +126,7 @@ PYRF_OBJS =
 SCRIPT_SH =
 
 SCRIPT_SH += perf-archive.sh
+SCRIPT_SH += perf-with-kcore.sh
 
 grep-libs = $(filter -l%,$(1))
 strip-libs = $(filter-out -l%,$(1))
@@ -263,6 +264,7 @@ LIB_H += util/xyarray.h
 LIB_H += util/header.h
 LIB_H += util/help.h
 LIB_H += util/session.h
+LIB_H += util/ordered-events.h
 LIB_H += util/strbuf.h
 LIB_H += util/strlist.h
 LIB_H += util/strfilter.h
@@ -347,6 +349,7 @@ LIB_OBJS += $(OUTPUT)util/machine.o
 LIB_OBJS += $(OUTPUT)util/map.o
 LIB_OBJS += $(OUTPUT)util/pstack.o
 LIB_OBJS += $(OUTPUT)util/session.o
+LIB_OBJS += $(OUTPUT)util/ordered-events.o
 LIB_OBJS += $(OUTPUT)util/comm.o
 LIB_OBJS += $(OUTPUT)util/thread.o
 LIB_OBJS += $(OUTPUT)util/thread_map.o
@@ -399,6 +402,7 @@ LIB_OBJS += $(OUTPUT)tests/perf-record.o
 LIB_OBJS += $(OUTPUT)tests/rdpmc.o
 LIB_OBJS += $(OUTPUT)tests/evsel-roundtrip-name.o
 LIB_OBJS += $(OUTPUT)tests/evsel-tp-sched.o
+LIB_OBJS += $(OUTPUT)tests/fdarray.o
 LIB_OBJS += $(OUTPUT)tests/pmu.o
 LIB_OBJS += $(OUTPUT)tests/hists_common.o
 LIB_OBJS += $(OUTPUT)tests/hists_link.o
@@ -423,6 +427,7 @@ endif
 endif
 LIB_OBJS += $(OUTPUT)tests/mmap-thread-lookup.o
 LIB_OBJS += $(OUTPUT)tests/thread-mg-share.o
+LIB_OBJS += $(OUTPUT)tests/switch-tracking.o
 
 BUILTIN_OBJS += $(OUTPUT)builtin-annotate.o
 BUILTIN_OBJS += $(OUTPUT)builtin-bench.o
@@ -765,7 +770,7 @@ $(LIBTRACEEVENT)-clean:
 install-traceevent-plugins: $(LIBTRACEEVENT)
        $(QUIET_SUBDIR0)$(TRACE_EVENT_DIR) $(LIBTRACEEVENT_FLAGS) install_plugins
 
-LIBAPIKFS_SOURCES = $(wildcard $(LIB_PATH)fs/*.[ch])
+LIBAPIKFS_SOURCES = $(wildcard $(LIB_PATH)fs/*.[ch] $(LIB_PATH)fd/*.[ch])
 
 # if subdir is set, we've been called from above so target has been built
 # already
@@ -875,6 +880,8 @@ install-bin: all install-gtk
                $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)'
        $(call QUIET_INSTALL, perf-archive) \
                $(INSTALL) $(OUTPUT)perf-archive -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)'
+       $(call QUIET_INSTALL, perf-with-kcore) \
+               $(INSTALL) $(OUTPUT)perf-with-kcore -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)'
 ifndef NO_LIBPERL
        $(call QUIET_INSTALL, perl-scripts) \
                $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/Perf-Trace-Util/lib/Perf/Trace'; \
@@ -920,7 +927,7 @@ config-clean:
        @$(MAKE) -C config/feature-checks clean >/dev/null
 
 clean: $(LIBTRACEEVENT)-clean $(LIBAPIKFS)-clean config-clean
-       $(call QUIET_CLEAN, core-objs)  $(RM) $(LIB_OBJS) $(BUILTIN_OBJS) $(LIB_FILE) $(OUTPUT)perf-archive $(OUTPUT)perf.o $(LANG_BINDINGS) $(GTK_OBJS)
+       $(call QUIET_CLEAN, core-objs)  $(RM) $(LIB_OBJS) $(BUILTIN_OBJS) $(LIB_FILE) $(OUTPUT)perf-archive $(OUTPUT)perf-with-kcore $(OUTPUT)perf.o $(LANG_BINDINGS) $(GTK_OBJS)
        $(call QUIET_CLEAN, core-progs) $(RM) $(ALL_PROGRAMS) perf
        $(call QUIET_CLEAN, core-gen)   $(RM)  *.spec *.pyc *.pyo */*.pyc */*.pyo $(OUTPUT)common-cmds.h TAGS tags cscope* $(OUTPUT)PERF-VERSION-FILE $(OUTPUT)PERF-CFLAGS $(OUTPUT)PERF-FEATURES $(OUTPUT)util/*-bison* $(OUTPUT)util/*-flex*
        $(QUIET_SUBDIR0)Documentation $(QUIET_SUBDIR1) clean
index 9f870d27cb39575b04763c050a5184025301653d..62eff847f91c4edc4754fb08a110f7b88b9c0411 100644 (file)
@@ -3,6 +3,7 @@
 #include "thread.h"
 #include "map.h"
 #include "event.h"
+#include "debug.h"
 #include "tests/tests.h"
 
 #define STACK_SIZE 8192
index 729ed69a66649cad6cecea5693c191cc91fc4e16..62c397ed3d97868bb979d32815f066dd6e1cb2b5 100644 (file)
@@ -3,6 +3,7 @@
 #include <libunwind.h>
 #include "perf_regs.h"
 #include "../../util/unwind.h"
+#include "../../util/debug.h"
 
 int libunwind__arch_reg_id(int regnum)
 {
index e9441b9e2a302a686e0db2cb03f0f30690f5c2ff..1d3f39c3aa564fd2e85a950fddcb4bba18f5e8db 100644 (file)
@@ -6,6 +6,8 @@
 #include <asm/perf_regs.h>
 
 #define PERF_REGS_MASK ((1ULL << PERF_REG_ARM64_MAX) - 1)
+#define PERF_REGS_MAX  PERF_REG_ARM64_MAX
+
 #define PERF_REG_IP    PERF_REG_ARM64_PC
 #define PERF_REG_SP    PERF_REG_ARM64_SP
 
index 436ee43859dc6d9929128e61ff3eb9f4088b59f5..a87afa91a99ebf31df4839872606b99d7137c486 100644 (file)
@@ -3,6 +3,7 @@
 #include <libunwind.h>
 #include "perf_regs.h"
 #include "../../util/unwind.h"
+#include "../../util/debug.h"
 
 int libunwind__arch_reg_id(int regnum)
 {
index 42faf369211c853f21f87cd037df5e9f4683b4f7..49776f190abfab295920534840aa1df479a4c094 100644 (file)
@@ -12,6 +12,11 @@ const char *const arm_triplets[] = {
        NULL
 };
 
+const char *const arm64_triplets[] = {
+       "aarch64-linux-android-",
+       NULL
+};
+
 const char *const powerpc_triplets[] = {
        "powerpc-unknown-linux-gnu-",
        "powerpc64-unknown-linux-gnu-",
@@ -105,6 +110,8 @@ static const char *normalize_arch(char *arch)
                return "x86";
        if (!strcmp(arch, "sun4u") || !strncmp(arch, "sparc", 5))
                return "sparc";
+       if (!strcmp(arch, "aarch64") || !strcmp(arch, "arm64"))
+               return "arm64";
        if (!strncmp(arch, "arm", 3) || !strcmp(arch, "sa110"))
                return "arm";
        if (!strncmp(arch, "s390", 4))
@@ -159,6 +166,8 @@ static int perf_session_env__lookup_binutils_path(struct perf_session_env *env,
 
        if (!strcmp(arch, "arm"))
                path_list = arm_triplets;
+       else if (!strcmp(arch, "arm64"))
+               path_list = arm64_triplets;
        else if (!strcmp(arch, "powerpc"))
                path_list = powerpc_triplets;
        else if (!strcmp(arch, "sh"))
index b92219b1900d7b8ca03be6d10d3b439bc1752931..6f7782bea5dd848c9e31985fb159b0eea11ca9ba 100644 (file)
@@ -1,6 +1,6 @@
 ifndef NO_DWARF
 PERF_HAVE_DWARF_REGS := 1
 LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/dwarf-regs.o
+LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/skip-callchain-idx.o
 endif
 LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/header.o
-LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/skip-callchain-idx.o
index a7c23a4b377802be92b1aafb9b46e91c27e453d2..d73ef8bb08c76a63c8846d4bdf49114c0558908a 100644 (file)
@@ -15,6 +15,7 @@
 
 #include "util/thread.h"
 #include "util/callchain.h"
+#include "util/debug.h"
 
 /*
  * When saving the callchain on Power, the kernel conservatively saves
index a84206e9c4aa09b97bb2dddc5c00a598234abd2c..fc9bebd2cca0575734f84f9947bf29f7f991c6ab 100644 (file)
@@ -26,6 +26,7 @@ static unsigned int nsecs    = 10;
 /* amount of futexes per thread */
 static unsigned int nfutexes = 1024;
 static bool fshared = false, done = false, silent = false;
+static int futex_flag = 0;
 
 struct timeval start, end, runtime;
 static pthread_mutex_t thread_lock;
@@ -75,8 +76,7 @@ static void *workerfn(void *arg)
                         * such as internal waitqueue handling, thus enlarging
                         * the critical region protected by hb->lock.
                         */
-                       ret = futex_wait(&w->futex[i], 1234, NULL,
-                                        fshared ? 0 : FUTEX_PRIVATE_FLAG);
+                       ret = futex_wait(&w->futex[i], 1234, NULL, futex_flag);
                        if (!silent &&
                            (!ret || errno != EAGAIN || errno != EWOULDBLOCK))
                                warn("Non-expected futex return call");
@@ -135,6 +135,9 @@ int bench_futex_hash(int argc, const char **argv,
        if (!worker)
                goto errmem;
 
+       if (!fshared)
+               futex_flag = FUTEX_PRIVATE_FLAG;
+
        printf("Run summary [PID %d]: %d threads, each operating on %d [%s] futexes for %d secs.\n\n",
               getpid(), nthreads, nfutexes, fshared ? "shared":"private", nsecs);
 
index 732403bfd31a9391e50719c182577047a8eb508b..bedff6b5b3cf3a61b38b172a97504cafebfd519f 100644 (file)
@@ -30,16 +30,18 @@ static u_int32_t futex1 = 0, futex2 = 0;
 static unsigned int nrequeue = 1;
 
 static pthread_t *worker;
-static bool done = 0, silent = 0;
+static bool done = false, silent = false, fshared = false;
 static pthread_mutex_t thread_lock;
 static pthread_cond_t thread_parent, thread_worker;
 static struct stats requeuetime_stats, requeued_stats;
 static unsigned int ncpus, threads_starting, nthreads = 0;
+static int futex_flag = 0;
 
 static const struct option options[] = {
        OPT_UINTEGER('t', "threads",  &nthreads, "Specify amount of threads"),
        OPT_UINTEGER('q', "nrequeue", &nrequeue, "Specify amount of threads to requeue at once"),
        OPT_BOOLEAN( 's', "silent",   &silent,   "Silent mode: do not display data/details"),
+       OPT_BOOLEAN( 'S', "shared",   &fshared,  "Use shared futexes instead of private ones"),
        OPT_END()
 };
 
@@ -70,7 +72,7 @@ static void *workerfn(void *arg __maybe_unused)
        pthread_cond_wait(&thread_worker, &thread_lock);
        pthread_mutex_unlock(&thread_lock);
 
-       futex_wait(&futex1, 0, NULL, FUTEX_PRIVATE_FLAG);
+       futex_wait(&futex1, 0, NULL, futex_flag);
        return NULL;
 }
 
@@ -127,9 +129,12 @@ int bench_futex_requeue(int argc, const char **argv,
        if (!worker)
                err(EXIT_FAILURE, "calloc");
 
-       printf("Run summary [PID %d]: Requeuing %d threads (from %p to %p), "
-              "%d at a time.\n\n",
-              getpid(), nthreads, &futex1, &futex2, nrequeue);
+       if (!fshared)
+               futex_flag = FUTEX_PRIVATE_FLAG;
+
+       printf("Run summary [PID %d]: Requeuing %d threads (from [%s] %p to %p), "
+              "%d at a time.\n\n",  getpid(), nthreads,
+              fshared ? "shared":"private", &futex1, &futex2, nrequeue);
 
        init_stats(&requeued_stats);
        init_stats(&requeuetime_stats);
@@ -156,16 +161,20 @@ int bench_futex_requeue(int argc, const char **argv,
 
                /* Ok, all threads are patiently blocked, start requeueing */
                gettimeofday(&start, NULL);
-               for (nrequeued = 0; nrequeued < nthreads; nrequeued += nrequeue)
+               for (nrequeued = 0; nrequeued < nthreads; nrequeued += nrequeue) {
                        /*
                         * Do not wakeup any tasks blocked on futex1, allowing
                         * us to really measure futex_wait functionality.
                         */
-                       futex_cmp_requeue(&futex1, 0, &futex2, 0, nrequeue,
-                                         FUTEX_PRIVATE_FLAG);
+                       futex_cmp_requeue(&futex1, 0, &futex2, 0,
+                                         nrequeue, futex_flag);
+               }
                gettimeofday(&end, NULL);
                timersub(&end, &start, &runtime);
 
+               if (nrequeued > nthreads)
+                       nrequeued = nthreads;
+
                update_stats(&requeued_stats, nrequeued);
                update_stats(&requeuetime_stats, runtime.tv_usec);
 
@@ -175,7 +184,7 @@ int bench_futex_requeue(int argc, const char **argv,
                }
 
                /* everybody should be blocked on futex2, wake'em up */
-               nrequeued = futex_wake(&futex2, nthreads, FUTEX_PRIVATE_FLAG);
+               nrequeued = futex_wake(&futex2, nthreads, futex_flag);
                if (nthreads != nrequeued)
                        warnx("couldn't wakeup all tasks (%d/%d)", nrequeued, nthreads);
 
@@ -184,7 +193,6 @@ int bench_futex_requeue(int argc, const char **argv,
                        if (ret)
                                err(EXIT_FAILURE, "pthread_join");
                }
-
        }
 
        /* cleanup & report results */
index 50022cbce87e2e124168de5259675dbea300b3b3..929f762be47e9735058f5c57bd394c4f09360c45 100644 (file)
@@ -31,16 +31,18 @@ static u_int32_t futex1 = 0;
 static unsigned int nwakes = 1;
 
 pthread_t *worker;
-static bool done = false, silent = false;
+static bool done = false, silent = false, fshared = false;
 static pthread_mutex_t thread_lock;
 static pthread_cond_t thread_parent, thread_worker;
 static struct stats waketime_stats, wakeup_stats;
 static unsigned int ncpus, threads_starting, nthreads = 0;
+static int futex_flag = 0;
 
 static const struct option options[] = {
        OPT_UINTEGER('t', "threads", &nthreads, "Specify amount of threads"),
        OPT_UINTEGER('w', "nwakes",  &nwakes,   "Specify amount of threads to wake at once"),
        OPT_BOOLEAN( 's', "silent",  &silent,   "Silent mode: do not display data/details"),
+       OPT_BOOLEAN( 'S', "shared",  &fshared,  "Use shared futexes instead of private ones"),
        OPT_END()
 };
 
@@ -58,7 +60,7 @@ static void *workerfn(void *arg __maybe_unused)
        pthread_cond_wait(&thread_worker, &thread_lock);
        pthread_mutex_unlock(&thread_lock);
 
-       futex_wait(&futex1, 0, NULL, FUTEX_PRIVATE_FLAG);
+       futex_wait(&futex1, 0, NULL, futex_flag);
        return NULL;
 }
 
@@ -130,9 +132,12 @@ int bench_futex_wake(int argc, const char **argv,
        if (!worker)
                err(EXIT_FAILURE, "calloc");
 
-       printf("Run summary [PID %d]: blocking on %d threads (at futex %p), "
+       if (!fshared)
+               futex_flag = FUTEX_PRIVATE_FLAG;
+
+       printf("Run summary [PID %d]: blocking on %d threads (at [%s] futex %p), "
               "waking up %d at a time.\n\n",
-              getpid(), nthreads, &futex1, nwakes);
+              getpid(), nthreads, fshared ? "shared":"private",  &futex1, nwakes);
 
        init_stats(&wakeup_stats);
        init_stats(&waketime_stats);
@@ -160,7 +165,7 @@ int bench_futex_wake(int argc, const char **argv,
                /* Ok, all threads are patiently blocked, start waking folks up */
                gettimeofday(&start, NULL);
                while (nwoken != nthreads)
-                       nwoken += futex_wake(&futex1, nwakes, FUTEX_PRIVATE_FLAG);
+                       nwoken += futex_wake(&futex1, nwakes, futex_flag);
                gettimeofday(&end, NULL);
                timersub(&end, &start, &runtime);
 
index 52a56599a543a1ddf9ec7653550e47571f64265e..d7f281c2828d97e35bb1f007f2f792666e89b78b 100644 (file)
@@ -26,7 +26,7 @@
 #include <sys/socket.h>
 #include <sys/wait.h>
 #include <sys/time.h>
-#include <sys/poll.h>
+#include <poll.h>
 #include <limits.h>
 #include <err.h>
 
index 1ec429fef2be9354d79400efe074e707229bef2f..be59394184252c88861edb353bd2be7be469f6c1 100644 (file)
@@ -36,7 +36,8 @@
 
 struct perf_annotate {
        struct perf_tool tool;
-       bool       force, use_tui, use_stdio, use_gtk;
+       struct perf_session *session;
+       bool       use_tui, use_stdio, use_gtk;
        bool       full_paths;
        bool       print_line;
        bool       skip_missing;
@@ -188,18 +189,9 @@ find_next:
 static int __cmd_annotate(struct perf_annotate *ann)
 {
        int ret;
-       struct perf_session *session;
+       struct perf_session *session = ann->session;
        struct perf_evsel *pos;
        u64 total_nr_samples;
-       struct perf_data_file file = {
-               .path  = input_name,
-               .mode  = PERF_DATA_MODE_READ,
-               .force = ann->force,
-       };
-
-       session = perf_session__new(&file, false, &ann->tool);
-       if (session == NULL)
-               return -ENOMEM;
 
        machines__set_symbol_filter(&session->machines, symbol__annotate_init);
 
@@ -207,22 +199,22 @@ static int __cmd_annotate(struct perf_annotate *ann)
                ret = perf_session__cpu_bitmap(session, ann->cpu_list,
                                               ann->cpu_bitmap);
                if (ret)
-                       goto out_delete;
+                       goto out;
        }
 
        if (!objdump_path) {
                ret = perf_session_env__lookup_objdump(&session->header.env);
                if (ret)
-                       goto out_delete;
+                       goto out;
        }
 
        ret = perf_session__process_events(session, &ann->tool);
        if (ret)
-               goto out_delete;
+               goto out;
 
        if (dump_trace) {
                perf_session__fprintf_nr_events(session, stdout);
-               goto out_delete;
+               goto out;
        }
 
        if (verbose > 3)
@@ -250,8 +242,8 @@ static int __cmd_annotate(struct perf_annotate *ann)
        }
 
        if (total_nr_samples == 0) {
-               ui__error("The %s file has no samples!\n", file.path);
-               goto out_delete;
+               ui__error("The %s file has no samples!\n", session->file->path);
+               goto out;
        }
 
        if (use_browser == 2) {
@@ -261,24 +253,12 @@ static int __cmd_annotate(struct perf_annotate *ann)
                                         "perf_gtk__show_annotations");
                if (show_annotations == NULL) {
                        ui__error("GTK browser not found!\n");
-                       goto out_delete;
+                       goto out;
                }
                show_annotations();
        }
 
-out_delete:
-       /*
-        * Speed up the exit process, for large files this can
-        * take quite a while.
-        *
-        * XXX Enable this when using valgrind or if we ever
-        * librarize this command.
-        *
-        * Also experiment with obstacks to see how much speed
-        * up we'll get here.
-        *
-        * perf_session__delete(session);
-        */
+out:
        return ret;
 }
 
@@ -297,10 +277,14 @@ int cmd_annotate(int argc, const char **argv, const char *prefix __maybe_unused)
                        .comm   = perf_event__process_comm,
                        .exit   = perf_event__process_exit,
                        .fork   = perf_event__process_fork,
-                       .ordered_samples = true,
+                       .ordered_events = true,
                        .ordering_requires_timestamps = true,
                },
        };
+       struct perf_data_file file = {
+               .path  = input_name,
+               .mode  = PERF_DATA_MODE_READ,
+       };
        const struct option options[] = {
        OPT_STRING('i', "input", &input_name, "file",
                    "input file name"),
@@ -308,7 +292,7 @@ int cmd_annotate(int argc, const char **argv, const char *prefix __maybe_unused)
                   "only consider symbols in these dsos"),
        OPT_STRING('s', "symbol", &annotate.sym_hist_filter, "symbol",
                    "symbol to annotate"),
-       OPT_BOOLEAN('f', "force", &annotate.force, "don't complain, do it"),
+       OPT_BOOLEAN('f', "force", &file.force, "don't complain, do it"),
        OPT_INCR('v', "verbose", &verbose,
                    "be more verbose (show symbol address, etc)"),
        OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace,
@@ -341,6 +325,7 @@ int cmd_annotate(int argc, const char **argv, const char *prefix __maybe_unused)
                    "Show event group information together"),
        OPT_END()
        };
+       int ret;
 
        argc = parse_options(argc, argv, options, annotate_usage, 0);
 
@@ -353,11 +338,16 @@ int cmd_annotate(int argc, const char **argv, const char *prefix __maybe_unused)
 
        setup_browser(true);
 
+       annotate.session = perf_session__new(&file, false, &annotate.tool);
+       if (annotate.session == NULL)
+               return -1;
+
        symbol_conf.priv_size = sizeof(struct annotation);
        symbol_conf.try_vmlinux_path = true;
 
-       if (symbol__init() < 0)
-               return -1;
+       ret = symbol__init(&annotate.session->header.env);
+       if (ret < 0)
+               goto out_delete;
 
        if (setup_sorting() < 0)
                usage_with_options(annotate_usage, options);
@@ -373,5 +363,20 @@ int cmd_annotate(int argc, const char **argv, const char *prefix __maybe_unused)
                annotate.sym_hist_filter = argv[0];
        }
 
-       return __cmd_annotate(&annotate);
+       ret = __cmd_annotate(&annotate);
+
+out_delete:
+       /*
+        * Speed up the exit process, for large files this can
+        * take quite a while.
+        *
+        * XXX Enable this when using valgrind or if we ever
+        * librarize this command.
+        *
+        * Also experiment with obstacks to see how much speed
+        * up we'll get here.
+        *
+        * perf_session__delete(session);
+        */
+       return ret;
 }
index 2a2c78f8087663852292d1220e51a41694ce0f3c..70385756da63f12bcfafe362bc55b1f157e8feae 100644 (file)
@@ -246,20 +246,9 @@ static bool dso__missing_buildid_cache(struct dso *dso, int parm __maybe_unused)
        return true;
 }
 
-static int build_id_cache__fprintf_missing(const char *filename, bool force, FILE *fp)
+static int build_id_cache__fprintf_missing(struct perf_session *session, FILE *fp)
 {
-       struct perf_data_file file = {
-               .path  = filename,
-               .mode  = PERF_DATA_MODE_READ,
-               .force = force,
-       };
-       struct perf_session *session = perf_session__new(&file, false, NULL);
-       if (session == NULL)
-               return -1;
-
        perf_session__fprintf_dsos_buildid(session, fp, dso__missing_buildid_cache, 0);
-       perf_session__delete(session);
-
        return 0;
 }
 
@@ -302,6 +291,12 @@ int cmd_buildid_cache(int argc, const char **argv,
                   *missing_filename = NULL,
                   *update_name_list_str = NULL,
                   *kcore_filename;
+       char sbuf[STRERR_BUFSIZE];
+
+       struct perf_data_file file = {
+               .mode  = PERF_DATA_MODE_READ,
+       };
+       struct perf_session *session = NULL;
 
        const struct option buildid_cache_options[] = {
        OPT_STRING('a', "add", &add_name_list_str,
@@ -326,8 +321,17 @@ int cmd_buildid_cache(int argc, const char **argv,
        argc = parse_options(argc, argv, buildid_cache_options,
                             buildid_cache_usage, 0);
 
-       if (symbol__init() < 0)
-               return -1;
+       if (missing_filename) {
+               file.path = missing_filename;
+               file.force = force;
+
+               session = perf_session__new(&file, false, NULL);
+               if (session == NULL)
+                       return -1;
+       }
+
+       if (symbol__init(session ? &session->header.env : NULL) < 0)
+               goto out;
 
        setup_pager();
 
@@ -344,7 +348,7 @@ int cmd_buildid_cache(int argc, const char **argv,
                                                continue;
                                        }
                                        pr_warning("Couldn't add %s: %s\n",
-                                                  pos->s, strerror(errno));
+                                                  pos->s, strerror_r(errno, sbuf, sizeof(sbuf)));
                                }
 
                        strlist__delete(list);
@@ -362,7 +366,7 @@ int cmd_buildid_cache(int argc, const char **argv,
                                                continue;
                                        }
                                        pr_warning("Couldn't remove %s: %s\n",
-                                                  pos->s, strerror(errno));
+                                                  pos->s, strerror_r(errno, sbuf, sizeof(sbuf)));
                                }
 
                        strlist__delete(list);
@@ -370,7 +374,7 @@ int cmd_buildid_cache(int argc, const char **argv,
        }
 
        if (missing_filename)
-               ret = build_id_cache__fprintf_missing(missing_filename, force, stdout);
+               ret = build_id_cache__fprintf_missing(session, stdout);
 
        if (update_name_list_str) {
                list = strlist__new(true, update_name_list_str);
@@ -383,7 +387,7 @@ int cmd_buildid_cache(int argc, const char **argv,
                                                continue;
                                        }
                                        pr_warning("Couldn't update %s: %s\n",
-                                                  pos->s, strerror(errno));
+                                                  pos->s, strerror_r(errno, sbuf, sizeof(sbuf)));
                                }
 
                        strlist__delete(list);
@@ -394,5 +398,9 @@ int cmd_buildid_cache(int argc, const char **argv,
            build_id_cache__add_kcore(kcore_filename, debugdir, force))
                pr_warning("Couldn't add %s\n", kcore_filename);
 
+out:
+       if (session)
+               perf_session__delete(session);
+
        return ret;
 }
index 9a5a035cb4262afcf1e74986276df8763f1036b9..a3ce19f7aebdd6f63e440b88ab9d168338ed509f 100644 (file)
@@ -360,7 +360,7 @@ static struct perf_tool tool = {
        .exit   = perf_event__process_exit,
        .fork   = perf_event__process_fork,
        .lost   = perf_event__process_lost,
-       .ordered_samples = true,
+       .ordered_events = true,
        .ordering_requires_timestamps = true,
 };
 
@@ -683,7 +683,7 @@ static int __cmd_diff(void)
                d->session = perf_session__new(&d->file, false, &tool);
                if (!d->session) {
                        pr_err("Failed to open %s\n", d->file.path);
-                       ret = -ENOMEM;
+                       ret = -1;
                        goto out_delete;
                }
 
@@ -1143,7 +1143,7 @@ int cmd_diff(int argc, const char **argv, const char *prefix __maybe_unused)
 
        argc = parse_options(argc, argv, options, diff_usage, 0);
 
-       if (symbol__init() < 0)
+       if (symbol__init(NULL) < 0)
                return -1;
 
        if (data_init(argc, argv) < 0)
index 66e12f55c052869e32864ad52e19dda226d918c3..0f93f859b782ba1701b1457cb3f90c9d1ecf5995 100644 (file)
@@ -28,7 +28,7 @@ static int __cmd_evlist(const char *file_name, struct perf_attr_details *details
 
        session = perf_session__new(&file, 0, NULL);
        if (session == NULL)
-               return -ENOMEM;
+               return -1;
 
        evlist__for_each(session->evlist, pos)
                perf_evsel__fprintf(pos, details, stdout);
index 0384d930480b47b29adbb86d93ae7c48e15f3741..25d20628212ed4691ad8ca3cc3c432e5dbffcd13 100644 (file)
@@ -103,6 +103,8 @@ static int check_emacsclient_version(void)
 
 static void exec_woman_emacs(const char *path, const char *page)
 {
+       char sbuf[STRERR_BUFSIZE];
+
        if (!check_emacsclient_version()) {
                /* This works only with emacsclient version >= 22. */
                struct strbuf man_page = STRBUF_INIT;
@@ -111,16 +113,19 @@ static void exec_woman_emacs(const char *path, const char *page)
                        path = "emacsclient";
                strbuf_addf(&man_page, "(woman \"%s\")", page);
                execlp(path, "emacsclient", "-e", man_page.buf, NULL);
-               warning("failed to exec '%s': %s", path, strerror(errno));
+               warning("failed to exec '%s': %s", path,
+                       strerror_r(errno, sbuf, sizeof(sbuf)));
        }
 }
 
 static void exec_man_konqueror(const char *path, const char *page)
 {
        const char *display = getenv("DISPLAY");
+
        if (display && *display) {
                struct strbuf man_page = STRBUF_INIT;
                const char *filename = "kfmclient";
+               char sbuf[STRERR_BUFSIZE];
 
                /* It's simpler to launch konqueror using kfmclient. */
                if (path) {
@@ -139,24 +144,31 @@ static void exec_man_konqueror(const char *path, const char *page)
                        path = "kfmclient";
                strbuf_addf(&man_page, "man:%s(1)", page);
                execlp(path, filename, "newTab", man_page.buf, NULL);
-               warning("failed to exec '%s': %s", path, strerror(errno));
+               warning("failed to exec '%s': %s", path,
+                       strerror_r(errno, sbuf, sizeof(sbuf)));
        }
 }
 
 static void exec_man_man(const char *path, const char *page)
 {
+       char sbuf[STRERR_BUFSIZE];
+
        if (!path)
                path = "man";
        execlp(path, "man", page, NULL);
-       warning("failed to exec '%s': %s", path, strerror(errno));
+       warning("failed to exec '%s': %s", path,
+               strerror_r(errno, sbuf, sizeof(sbuf)));
 }
 
 static void exec_man_cmd(const char *cmd, const char *page)
 {
        struct strbuf shell_cmd = STRBUF_INIT;
+       char sbuf[STRERR_BUFSIZE];
+
        strbuf_addf(&shell_cmd, "%s %s", cmd, page);
        execl("/bin/sh", "sh", "-c", shell_cmd.buf, NULL);
-       warning("failed to exec '%s': %s", cmd, strerror(errno));
+       warning("failed to exec '%s': %s", cmd,
+               strerror_r(errno, sbuf, sizeof(sbuf)));
 }
 
 static void add_man_viewer(const char *name)
index 9a02807387d6c25b9c41236f9404a88da5580a3f..de99ca1bb94268d01c1baebb5757490c367ec912 100644 (file)
@@ -23,6 +23,7 @@
 
 struct perf_inject {
        struct perf_tool        tool;
+       struct perf_session     *session;
        bool                    build_ids;
        bool                    sched_stat;
        const char              *input_name;
@@ -340,12 +341,8 @@ static int perf_evsel__check_stype(struct perf_evsel *evsel,
 
 static int __cmd_inject(struct perf_inject *inject)
 {
-       struct perf_session *session;
        int ret = -EINVAL;
-       struct perf_data_file file = {
-               .path = inject->input_name,
-               .mode = PERF_DATA_MODE_READ,
-       };
+       struct perf_session *session = inject->session;
        struct perf_data_file *file_out = &inject->output;
 
        signal(SIGINT, sig_handler);
@@ -357,16 +354,12 @@ static int __cmd_inject(struct perf_inject *inject)
                inject->tool.tracing_data = perf_event__repipe_tracing_data;
        }
 
-       session = perf_session__new(&file, true, &inject->tool);
-       if (session == NULL)
-               return -ENOMEM;
-
        if (inject->build_ids) {
                inject->tool.sample = perf_event__inject_buildid;
        } else if (inject->sched_stat) {
                struct perf_evsel *evsel;
 
-               inject->tool.ordered_samples = true;
+               inject->tool.ordered_events = true;
 
                evlist__for_each(session->evlist, evsel) {
                        const char *name = perf_evsel__name(evsel);
@@ -396,8 +389,6 @@ static int __cmd_inject(struct perf_inject *inject)
                perf_session__write_header(session, session->evlist, file_out->fd, true);
        }
 
-       perf_session__delete(session);
-
        return ret;
 }
 
@@ -427,6 +418,11 @@ int cmd_inject(int argc, const char **argv, const char *prefix __maybe_unused)
                        .mode = PERF_DATA_MODE_WRITE,
                },
        };
+       struct perf_data_file file = {
+               .mode = PERF_DATA_MODE_READ,
+       };
+       int ret;
+
        const struct option options[] = {
                OPT_BOOLEAN('b', "build-ids", &inject.build_ids,
                            "Inject build-ids into the output stream"),
@@ -461,8 +457,17 @@ int cmd_inject(int argc, const char **argv, const char *prefix __maybe_unused)
                return -1;
        }
 
-       if (symbol__init() < 0)
+       file.path = inject.input_name;
+       inject.session = perf_session__new(&file, true, &inject.tool);
+       if (inject.session == NULL)
+               return -1;
+
+       if (symbol__init(&inject.session->header.env) < 0)
                return -1;
 
-       return __cmd_inject(&inject);
+       ret = __cmd_inject(&inject);
+
+       perf_session__delete(inject.session);
+
+       return ret;
 }
index bef3376bfaf3a6e093a227fddb15e6cbf7ffbd7f..f295141025bcfecdb01c913b94cc3b1ed533d2b4 100644 (file)
@@ -256,7 +256,9 @@ static int process_sample_event(struct perf_tool *tool __maybe_unused,
 static struct perf_tool perf_kmem = {
        .sample          = process_sample_event,
        .comm            = perf_event__process_comm,
-       .ordered_samples = true,
+       .mmap            = perf_event__process_mmap,
+       .mmap2           = perf_event__process_mmap2,
+       .ordered_events  = true,
 };
 
 static double fragmentation(unsigned long n_req, unsigned long n_alloc)
@@ -403,10 +405,9 @@ static void sort_result(void)
        __sort_result(&root_caller_stat, &root_caller_sorted, &caller_sort);
 }
 
-static int __cmd_kmem(void)
+static int __cmd_kmem(struct perf_session *session)
 {
        int err = -EINVAL;
-       struct perf_session *session;
        const struct perf_evsel_str_handler kmem_tracepoints[] = {
                { "kmem:kmalloc",               perf_evsel__process_alloc_event, },
                { "kmem:kmem_cache_alloc",      perf_evsel__process_alloc_event, },
@@ -415,34 +416,22 @@ static int __cmd_kmem(void)
                { "kmem:kfree",                 perf_evsel__process_free_event, },
                { "kmem:kmem_cache_free",       perf_evsel__process_free_event, },
        };
-       struct perf_data_file file = {
-               .path = input_name,
-               .mode = PERF_DATA_MODE_READ,
-       };
-
-       session = perf_session__new(&file, false, &perf_kmem);
-       if (session == NULL)
-               return -ENOMEM;
-
-       if (perf_session__create_kernel_maps(session) < 0)
-               goto out_delete;
 
        if (!perf_session__has_traces(session, "kmem record"))
-               goto out_delete;
+               goto out;
 
        if (perf_session__set_tracepoints_handlers(session, kmem_tracepoints)) {
                pr_err("Initializing perf session tracepoint handlers failed\n");
-               return -1;
+               goto out;
        }
 
        setup_pager();
        err = perf_session__process_events(session, &perf_kmem);
        if (err != 0)
-               goto out_delete;
+               goto out;
        sort_result();
        print_result(session);
-out_delete:
-       perf_session__delete(session);
+out:
        return err;
 }
 
@@ -689,29 +678,46 @@ int cmd_kmem(int argc, const char **argv, const char *prefix __maybe_unused)
                NULL,
                NULL
        };
+       struct perf_session *session;
+       struct perf_data_file file = {
+               .path = input_name,
+               .mode = PERF_DATA_MODE_READ,
+       };
+       int ret = -1;
+
        argc = parse_options_subcommand(argc, argv, kmem_options,
                                        kmem_subcommands, kmem_usage, 0);
 
        if (!argc)
                usage_with_options(kmem_usage, kmem_options);
 
-       symbol__init();
-
        if (!strncmp(argv[0], "rec", 3)) {
+               symbol__init(NULL);
                return __cmd_record(argc, argv);
-       } else if (!strcmp(argv[0], "stat")) {
+       }
+
+       session = perf_session__new(&file, false, &perf_kmem);
+       if (session == NULL)
+               return -1;
+
+       symbol__init(&session->header.env);
+
+       if (!strcmp(argv[0], "stat")) {
                if (cpu__setup_cpunode_map())
-                       return -1;
+                       goto out_delete;
 
                if (list_empty(&caller_sort))
                        setup_sorting(&caller_sort, default_sort_order);
                if (list_empty(&alloc_sort))
                        setup_sorting(&alloc_sort, default_sort_order);
 
-               return __cmd_kmem();
+               ret = __cmd_kmem(session);
        } else
                usage_with_options(kmem_usage, kmem_options);
 
-       return 0;
+out_delete:
+       perf_session__delete(session);
+
+       return ret;
 }
 
index 43367eb005100ae939b8c6d372e5d6d0e6649e34..d8bf2271f4ea7e298811c7aa4759ed7ffda84dbd 100644 (file)
@@ -543,14 +543,12 @@ static void print_vcpu_info(struct perf_kvm_stat *kvm)
 
        pr_info("Analyze events for ");
 
-       if (kvm->live) {
-               if (kvm->opts.target.system_wide)
-                       pr_info("all VMs, ");
-               else if (kvm->opts.target.pid)
-                       pr_info("pid(s) %s, ", kvm->opts.target.pid);
-               else
-                       pr_info("dazed and confused on what is monitored, ");
-       }
+       if (kvm->opts.target.system_wide)
+               pr_info("all VMs, ");
+       else if (kvm->opts.target.pid)
+               pr_info("pid(s) %s, ", kvm->opts.target.pid);
+       else
+               pr_info("dazed and confused on what is monitored, ");
 
        if (vcpu == -1)
                pr_info("all VCPUs:\n\n");
@@ -592,8 +590,8 @@ static void print_result(struct perf_kvm_stat *kvm)
        pr_info("%9s ", "Samples%");
 
        pr_info("%9s ", "Time%");
-       pr_info("%10s ", "Min Time");
-       pr_info("%10s ", "Max Time");
+       pr_info("%11s ", "Min Time");
+       pr_info("%11s ", "Max Time");
        pr_info("%16s ", "Avg time");
        pr_info("\n\n");
 
@@ -610,8 +608,8 @@ static void print_result(struct perf_kvm_stat *kvm)
                pr_info("%10llu ", (unsigned long long)ecount);
                pr_info("%8.2f%% ", (double)ecount / kvm->total_count * 100);
                pr_info("%8.2f%% ", (double)etime / kvm->total_time * 100);
-               pr_info("%8" PRIu64 "us ", min / 1000);
-               pr_info("%8" PRIu64 "us ", max / 1000);
+               pr_info("%9.2fus ", (double)min / 1e3);
+               pr_info("%9.2fus ", (double)max / 1e3);
                pr_info("%9.2fus ( +-%7.2f%% )", (double)etime / ecount/1e3,
                        kvm_event_rel_stddev(vcpu, event));
                pr_info("\n");
@@ -732,7 +730,7 @@ static s64 perf_kvm__mmap_read_idx(struct perf_kvm_stat *kvm, int idx,
                        return -1;
                }
 
-               err = perf_session_queue_event(kvm->session, event, &sample, 0);
+               err = perf_session_queue_event(kvm->session, event, &kvm->tool, &sample, 0);
                /*
                 * FIXME: Here we can't consume the event, as perf_session_queue_event will
                 *        point to it, and it'll get possibly overwritten by the kernel.
@@ -785,7 +783,7 @@ static int perf_kvm__mmap_read(struct perf_kvm_stat *kvm)
 
        /* flush queue after each round in which we processed events */
        if (ntotal) {
-               kvm->session->ordered_samples.next_flush = flush_time;
+               kvm->session->ordered_events.next_flush = flush_time;
                err = kvm->tool.finished_round(&kvm->tool, NULL, kvm->session);
                if (err) {
                        if (kvm->lost_events)
@@ -885,15 +883,11 @@ static int fd_set_nonblock(int fd)
        return 0;
 }
 
-static
-int perf_kvm__handle_stdin(struct termios *tc_now, struct termios *tc_save)
+static int perf_kvm__handle_stdin(void)
 {
        int c;
 
-       tcsetattr(0, TCSANOW, tc_now);
        c = getc(stdin);
-       tcsetattr(0, TCSAFLUSH, tc_save);
-
        if (c == 'q')
                return 1;
 
@@ -904,7 +898,7 @@ static int kvm_events_live_report(struct perf_kvm_stat *kvm)
 {
        struct pollfd *pollfds = NULL;
        int nr_fds, nr_stdin, ret, err = -EINVAL;
-       struct termios tc, save;
+       struct termios save;
 
        /* live flag must be set first */
        kvm->live = true;
@@ -919,26 +913,14 @@ static int kvm_events_live_report(struct perf_kvm_stat *kvm)
                goto out;
        }
 
+       set_term_quiet_input(&save);
        init_kvm_event_record(kvm);
 
-       tcgetattr(0, &save);
-       tc = save;
-       tc.c_lflag &= ~(ICANON | ECHO);
-       tc.c_cc[VMIN] = 0;
-       tc.c_cc[VTIME] = 0;
-
        signal(SIGINT, sig_handler);
        signal(SIGTERM, sig_handler);
 
-       /* copy pollfds -- need to add timerfd and stdin */
-       nr_fds = kvm->evlist->nr_fds;
-       pollfds = zalloc(sizeof(struct pollfd) * (nr_fds + 2));
-       if (!pollfds) {
-               err = -ENOMEM;
-               goto out;
-       }
-       memcpy(pollfds, kvm->evlist->pollfd,
-               sizeof(struct pollfd) * kvm->evlist->nr_fds);
+       /* use pollfds -- need to add timerfd and stdin */
+       nr_fds = kvm->evlist->pollfd.nr;
 
        /* add timer fd */
        if (perf_kvm__timerfd_create(kvm) < 0) {
@@ -946,17 +928,21 @@ static int kvm_events_live_report(struct perf_kvm_stat *kvm)
                goto out;
        }
 
-       pollfds[nr_fds].fd = kvm->timerfd;
-       pollfds[nr_fds].events = POLLIN;
+       if (perf_evlist__add_pollfd(kvm->evlist, kvm->timerfd))
+               goto out;
+
        nr_fds++;
 
-       pollfds[nr_fds].fd = fileno(stdin);
-       pollfds[nr_fds].events = POLLIN;
+       if (perf_evlist__add_pollfd(kvm->evlist, fileno(stdin)))
+               goto out;
+
        nr_stdin = nr_fds;
        nr_fds++;
        if (fd_set_nonblock(fileno(stdin)) != 0)
                goto out;
 
+       pollfds  = kvm->evlist->pollfd.entries;
+
        /* everything is good - enable the events and process */
        perf_evlist__enable(kvm->evlist);
 
@@ -972,7 +958,7 @@ static int kvm_events_live_report(struct perf_kvm_stat *kvm)
                        goto out;
 
                if (pollfds[nr_stdin].revents & POLLIN)
-                       done = perf_kvm__handle_stdin(&tc, &save);
+                       done = perf_kvm__handle_stdin();
 
                if (!rc && !done)
                        err = poll(pollfds, nr_fds, 100);
@@ -989,7 +975,7 @@ out:
        if (kvm->timerfd >= 0)
                close(kvm->timerfd);
 
-       free(pollfds);
+       tcsetattr(0, TCSAFLUSH, &save);
        return err;
 }
 
@@ -998,6 +984,7 @@ static int kvm_live_open_events(struct perf_kvm_stat *kvm)
        int err, rc = -1;
        struct perf_evsel *pos;
        struct perf_evlist *evlist = kvm->evlist;
+       char sbuf[STRERR_BUFSIZE];
 
        perf_evlist__config(evlist, &kvm->opts);
 
@@ -1034,12 +1021,14 @@ static int kvm_live_open_events(struct perf_kvm_stat *kvm)
 
        err = perf_evlist__open(evlist);
        if (err < 0) {
-               printf("Couldn't create the events: %s\n", strerror(errno));
+               printf("Couldn't create the events: %s\n",
+                      strerror_r(errno, sbuf, sizeof(sbuf)));
                goto out;
        }
 
        if (perf_evlist__mmap(evlist, kvm->opts.mmap_pages, false) < 0) {
-               ui__error("Failed to mmap the events: %s\n", strerror(errno));
+               ui__error("Failed to mmap the events: %s\n",
+                         strerror_r(errno, sbuf, sizeof(sbuf)));
                perf_evlist__close(evlist);
                goto out;
        }
@@ -1058,7 +1047,7 @@ static int read_events(struct perf_kvm_stat *kvm)
        struct perf_tool eops = {
                .sample                 = process_sample_event,
                .comm                   = perf_event__process_comm,
-               .ordered_samples        = true,
+               .ordered_events         = true,
        };
        struct perf_data_file file = {
                .path = kvm->file_name,
@@ -1069,9 +1058,11 @@ static int read_events(struct perf_kvm_stat *kvm)
        kvm->session = perf_session__new(&file, false, &kvm->tool);
        if (!kvm->session) {
                pr_err("Initializing perf session failed\n");
-               return -EINVAL;
+               return -1;
        }
 
+       symbol__init(&kvm->session->header.env);
+
        if (!perf_session__has_traces(kvm->session, "kvm record"))
                return -EINVAL;
 
@@ -1088,8 +1079,8 @@ static int read_events(struct perf_kvm_stat *kvm)
 
 static int parse_target_str(struct perf_kvm_stat *kvm)
 {
-       if (kvm->pid_str) {
-               kvm->pid_list = intlist__new(kvm->pid_str);
+       if (kvm->opts.target.pid) {
+               kvm->pid_list = intlist__new(kvm->opts.target.pid);
                if (kvm->pid_list == NULL) {
                        pr_err("Error parsing process id string\n");
                        return -EINVAL;
@@ -1191,7 +1182,7 @@ kvm_events_report(struct perf_kvm_stat *kvm, int argc, const char **argv)
                OPT_STRING('k', "key", &kvm->sort_key, "sort-key",
                            "key for sorting: sample(sort by samples number)"
                            " time (sort by avg time)"),
-               OPT_STRING('p', "pid", &kvm->pid_str, "pid",
+               OPT_STRING('p', "pid", &kvm->opts.target.pid, "pid",
                           "analyze events only for given process id(s)"),
                OPT_END()
        };
@@ -1201,8 +1192,6 @@ kvm_events_report(struct perf_kvm_stat *kvm, int argc, const char **argv)
                NULL
        };
 
-       symbol__init();
-
        if (argc) {
                argc = parse_options(argc, argv,
                                     kvm_events_report_options,
@@ -1212,6 +1201,9 @@ kvm_events_report(struct perf_kvm_stat *kvm, int argc, const char **argv)
                                           kvm_events_report_options);
        }
 
+       if (!kvm->opts.target.pid)
+               kvm->opts.target.system_wide = true;
+
        return kvm_events_report_vcpu(kvm);
 }
 
@@ -1311,7 +1303,7 @@ static int kvm_events_live(struct perf_kvm_stat *kvm,
        kvm->tool.exit   = perf_event__process_exit;
        kvm->tool.fork   = perf_event__process_fork;
        kvm->tool.lost   = process_lost_event;
-       kvm->tool.ordered_samples = true;
+       kvm->tool.ordered_events = true;
        perf_tool__fill_defaults(&kvm->tool);
 
        /* set defaults */
@@ -1322,7 +1314,7 @@ static int kvm_events_live(struct perf_kvm_stat *kvm,
        kvm->opts.target.uid_str = NULL;
        kvm->opts.target.uid = UINT_MAX;
 
-       symbol__init();
+       symbol__init(NULL);
        disable_buildid_cache();
 
        use_browser = 0;
@@ -1369,7 +1361,7 @@ static int kvm_events_live(struct perf_kvm_stat *kvm,
         */
        kvm->session = perf_session__new(&file, false, &kvm->tool);
        if (kvm->session == NULL) {
-               err = -ENOMEM;
+               err = -1;
                goto out;
        }
        kvm->session->evlist = kvm->evlist;
index 6148afc995c68a0bd11b61826a741185a69e4294..e7ec71589da6dbcc06f5a8367466f953cac99c4c 100644 (file)
@@ -852,7 +852,7 @@ static int __cmd_report(bool display_info)
        struct perf_tool eops = {
                .sample          = process_sample_event,
                .comm            = perf_event__process_comm,
-               .ordered_samples = true,
+               .ordered_events  = true,
        };
        struct perf_data_file file = {
                .path = input_name,
@@ -862,9 +862,11 @@ static int __cmd_report(bool display_info)
        session = perf_session__new(&file, false, &eops);
        if (!session) {
                pr_err("Initializing perf session failed\n");
-               return -ENOMEM;
+               return -1;
        }
 
+       symbol__init(&session->header.env);
+
        if (!perf_session__has_traces(session, "lock record"))
                goto out_delete;
 
@@ -974,7 +976,6 @@ int cmd_lock(int argc, const char **argv, const char *prefix __maybe_unused)
        unsigned int i;
        int rc = 0;
 
-       symbol__init();
        for (i = 0; i < LOCKHASH_SIZE; i++)
                INIT_LIST_HEAD(lockhash_table + i);
 
index 4a1a6c94a5ebcb5b7a08bef5034f22419ce07c77..24db6ffe2957450d17a6a6465441317b81f7f49e 100644 (file)
@@ -124,7 +124,7 @@ static int report_raw_events(struct perf_mem *mem)
                                                         &mem->tool);
 
        if (session == NULL)
-               return -ENOMEM;
+               return -1;
 
        if (mem->cpu_list) {
                ret = perf_session__cpu_bitmap(session, mem->cpu_list,
@@ -133,7 +133,7 @@ static int report_raw_events(struct perf_mem *mem)
                        goto out_delete;
        }
 
-       if (symbol__init() < 0)
+       if (symbol__init(&session->header.env) < 0)
                return -1;
 
        printf("# PID, TID, IP, ADDR, LOCAL WEIGHT, DSRC, SYMBOL\n");
@@ -194,7 +194,7 @@ int cmd_mem(int argc, const char **argv, const char *prefix __maybe_unused)
                        .lost           = perf_event__process_lost,
                        .fork           = perf_event__process_fork,
                        .build_id       = perf_event__process_build_id,
-                       .ordered_samples = true,
+                       .ordered_events = true,
                },
                .input_name              = "perf.data",
        };
index c63fa29250753b09d7468a1f5142a3f540e48249..04412b4770a2230ec83296cb179eb397ebb42e94 100644 (file)
@@ -290,8 +290,11 @@ static void cleanup_params(void)
 
 static void pr_err_with_code(const char *msg, int err)
 {
+       char sbuf[STRERR_BUFSIZE];
+
        pr_err("%s", msg);
-       pr_debug(" Reason: %s (Code: %d)", strerror(-err), err);
+       pr_debug(" Reason: %s (Code: %d)",
+                strerror_r(-err, sbuf, sizeof(sbuf)), err);
        pr_err("\n");
 }
 
@@ -373,6 +376,8 @@ __cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused)
                        "target executable name or path", opt_set_target),
        OPT_BOOLEAN(0, "demangle", &symbol_conf.demangle,
                    "Disable symbol demangling"),
+       OPT_BOOLEAN(0, "demangle-kernel", &symbol_conf.demangle_kernel,
+                   "Enable kernel symbol demangling"),
        OPT_END()
        };
        int ret;
@@ -467,7 +472,8 @@ __cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused)
                        usage_with_options(probe_usage, options);
                }
 
-               ret = show_line_range(&params.line_range, params.target);
+               ret = show_line_range(&params.line_range, params.target,
+                                     params.uprobes);
                if (ret < 0)
                        pr_err_with_code("  Error: Failed to show lines.", ret);
                return ret;
index 4869050e7194c18311da81f165f6f8e5cb5882ea..44c6f3d55ce76066ca8911d31f196a1fe128f36a 100644 (file)
@@ -65,8 +65,9 @@ static int process_synthesized_event(struct perf_tool *tool,
        return record__write(rec, event, event->header.size);
 }
 
-static int record__mmap_read(struct record *rec, struct perf_mmap *md)
+static int record__mmap_read(struct record *rec, int idx)
 {
+       struct perf_mmap *md = &rec->evlist->mmap[idx];
        unsigned int head = perf_mmap__read_head(md);
        unsigned int old = md->prev;
        unsigned char *data = md->base + page_size;
@@ -102,8 +103,7 @@ static int record__mmap_read(struct record *rec, struct perf_mmap *md)
        }
 
        md->prev = old;
-       perf_mmap__write_tail(md, old);
-
+       perf_evlist__mmap_consume(rec->evlist, idx);
 out:
        return rc;
 }
@@ -161,7 +161,7 @@ try_again:
 
        if (perf_evlist__apply_filters(evlist)) {
                error("failed to set filter with %d (%s)\n", errno,
-                       strerror(errno));
+                       strerror_r(errno, msg, sizeof(msg)));
                rc = -1;
                goto out;
        }
@@ -175,7 +175,8 @@ try_again:
                               "(current value: %u)\n", opts->mmap_pages);
                        rc = -errno;
                } else {
-                       pr_err("failed to mmap with %d (%s)\n", errno, strerror(errno));
+                       pr_err("failed to mmap with %d (%s)\n", errno,
+                               strerror_r(errno, msg, sizeof(msg)));
                        rc = -errno;
                }
                goto out;
@@ -244,7 +245,7 @@ static int record__mmap_read_all(struct record *rec)
 
        for (i = 0; i < rec->evlist->nr_mmaps; i++) {
                if (rec->evlist->mmap[i].base) {
-                       if (record__mmap_read(rec, &rec->evlist->mmap[i]) != 0) {
+                       if (record__mmap_read(rec, i) != 0) {
                                rc = -1;
                                goto out;
                        }
@@ -307,7 +308,7 @@ static int __cmd_record(struct record *rec, int argc, const char **argv)
        struct record_opts *opts = &rec->opts;
        struct perf_data_file *file = &rec->file;
        struct perf_session *session;
-       bool disabled = false;
+       bool disabled = false, draining = false;
 
        rec->progname = argv[0];
 
@@ -456,9 +457,9 @@ static int __cmd_record(struct record *rec, int argc, const char **argv)
                }
 
                if (hits == rec->samples) {
-                       if (done)
+                       if (done || draining)
                                break;
-                       err = poll(rec->evlist->pollfd, rec->evlist->nr_fds, -1);
+                       err = perf_evlist__poll(rec->evlist, -1);
                        /*
                         * Propagate error, only if there's any. Ignore positive
                         * number of returned events and interrupt error.
@@ -466,6 +467,9 @@ static int __cmd_record(struct record *rec, int argc, const char **argv)
                        if (err > 0 || (err < 0 && errno == EINTR))
                                err = 0;
                        waking++;
+
+                       if (perf_evlist__filter_pollfd(rec->evlist, POLLERR | POLLHUP) == 0)
+                               draining = true;
                }
 
                /*
@@ -480,7 +484,7 @@ static int __cmd_record(struct record *rec, int argc, const char **argv)
        }
 
        if (forks && workload_exec_errno) {
-               char msg[512];
+               char msg[STRERR_BUFSIZE];
                const char *emsg = strerror_r(workload_exec_errno, msg, sizeof(msg));
                pr_err("Workload failed: %s\n", emsg);
                err = -1;
@@ -620,145 +624,56 @@ error:
        return ret;
 }
 
-#ifdef HAVE_DWARF_UNWIND_SUPPORT
-static int get_stack_size(char *str, unsigned long *_size)
-{
-       char *endptr;
-       unsigned long size;
-       unsigned long max_size = round_down(USHRT_MAX, sizeof(u64));
-
-       size = strtoul(str, &endptr, 0);
-
-       do {
-               if (*endptr)
-                       break;
-
-               size = round_up(size, sizeof(u64));
-               if (!size || size > max_size)
-                       break;
-
-               *_size = size;
-               return 0;
-
-       } while (0);
-
-       pr_err("callchain: Incorrect stack dump size (max %ld): %s\n",
-              max_size, str);
-       return -1;
-}
-#endif /* HAVE_DWARF_UNWIND_SUPPORT */
-
-int record_parse_callchain(const char *arg, struct record_opts *opts)
-{
-       char *tok, *name, *saveptr = NULL;
-       char *buf;
-       int ret = -1;
-
-       /* We need buffer that we know we can write to. */
-       buf = malloc(strlen(arg) + 1);
-       if (!buf)
-               return -ENOMEM;
-
-       strcpy(buf, arg);
-
-       tok = strtok_r((char *)buf, ",", &saveptr);
-       name = tok ? : (char *)buf;
-
-       do {
-               /* Framepointer style */
-               if (!strncmp(name, "fp", sizeof("fp"))) {
-                       if (!strtok_r(NULL, ",", &saveptr)) {
-                               opts->call_graph = CALLCHAIN_FP;
-                               ret = 0;
-                       } else
-                               pr_err("callchain: No more arguments "
-                                      "needed for -g fp\n");
-                       break;
-
-#ifdef HAVE_DWARF_UNWIND_SUPPORT
-               /* Dwarf style */
-               } else if (!strncmp(name, "dwarf", sizeof("dwarf"))) {
-                       const unsigned long default_stack_dump_size = 8192;
-
-                       ret = 0;
-                       opts->call_graph = CALLCHAIN_DWARF;
-                       opts->stack_dump_size = default_stack_dump_size;
-
-                       tok = strtok_r(NULL, ",", &saveptr);
-                       if (tok) {
-                               unsigned long size = 0;
-
-                               ret = get_stack_size(tok, &size);
-                               opts->stack_dump_size = size;
-                       }
-#endif /* HAVE_DWARF_UNWIND_SUPPORT */
-               } else {
-                       pr_err("callchain: Unknown --call-graph option "
-                              "value: %s\n", arg);
-                       break;
-               }
-
-       } while (0);
-
-       free(buf);
-       return ret;
-}
-
-static void callchain_debug(struct record_opts *opts)
+static void callchain_debug(void)
 {
        static const char *str[CALLCHAIN_MAX] = { "NONE", "FP", "DWARF" };
 
-       pr_debug("callchain: type %s\n", str[opts->call_graph]);
+       pr_debug("callchain: type %s\n", str[callchain_param.record_mode]);
 
-       if (opts->call_graph == CALLCHAIN_DWARF)
+       if (callchain_param.record_mode == CALLCHAIN_DWARF)
                pr_debug("callchain: stack dump size %d\n",
-                        opts->stack_dump_size);
+                        callchain_param.dump_size);
 }
 
-int record_parse_callchain_opt(const struct option *opt,
+int record_parse_callchain_opt(const struct option *opt __maybe_unused,
                               const char *arg,
                               int unset)
 {
-       struct record_opts *opts = opt->value;
        int ret;
 
-       opts->call_graph_enabled = !unset;
+       callchain_param.enabled = !unset;
 
        /* --no-call-graph */
        if (unset) {
-               opts->call_graph = CALLCHAIN_NONE;
+               callchain_param.record_mode = CALLCHAIN_NONE;
                pr_debug("callchain: disabled\n");
                return 0;
        }
 
-       ret = record_parse_callchain(arg, opts);
+       ret = parse_callchain_record_opt(arg);
        if (!ret)
-               callchain_debug(opts);
+               callchain_debug();
 
        return ret;
 }
 
-int record_callchain_opt(const struct option *opt,
+int record_callchain_opt(const struct option *opt __maybe_unused,
                         const char *arg __maybe_unused,
                         int unset __maybe_unused)
 {
-       struct record_opts *opts = opt->value;
+       callchain_param.enabled = true;
 
-       opts->call_graph_enabled = !unset;
+       if (callchain_param.record_mode == CALLCHAIN_NONE)
+               callchain_param.record_mode = CALLCHAIN_FP;
 
-       if (opts->call_graph == CALLCHAIN_NONE)
-               opts->call_graph = CALLCHAIN_FP;
-
-       callchain_debug(opts);
+       callchain_debug();
        return 0;
 }
 
 static int perf_record_config(const char *var, const char *value, void *cb)
 {
-       struct record *rec = cb;
-
        if (!strcmp(var, "record.call-graph"))
-               return record_parse_callchain(value, &rec->opts);
+               var = "call-graph.record-mode"; /* fall-through */
 
        return perf_default_config(var, value, cb);
 }
@@ -781,6 +696,7 @@ static const char * const record_usage[] = {
  */
 static struct record record = {
        .opts = {
+               .sample_time         = true,
                .mmap_pages          = UINT_MAX,
                .user_freq           = UINT_MAX,
                .user_interval       = ULLONG_MAX,
@@ -907,7 +823,7 @@ int cmd_record(int argc, const char **argv, const char *prefix __maybe_unused)
                usage_with_options(record_usage, record_options);
        }
 
-       symbol__init();
+       symbol__init(NULL);
 
        if (symbol_conf.kptr_restrict)
                pr_warning(
index 21d830bafff32aaa4b38ec0eb2e63ec66dfc00f8..ac145fae0521c3c9779a90c097228ff39074d5a6 100644 (file)
@@ -58,17 +58,19 @@ struct report {
        const char              *symbol_filter_str;
        float                   min_percent;
        u64                     nr_entries;
+       u64                     queue_size;
        DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS);
 };
 
 static int report__config(const char *var, const char *value, void *cb)
 {
+       struct report *rep = cb;
+
        if (!strcmp(var, "report.group")) {
                symbol_conf.event_group = perf_config_bool(var, value);
                return 0;
        }
        if (!strcmp(var, "report.percent-limit")) {
-               struct report *rep = cb;
                rep->min_percent = strtof(value, NULL);
                return 0;
        }
@@ -76,6 +78,10 @@ static int report__config(const char *var, const char *value, void *cb)
                symbol_conf.cumulate_callchain = perf_config_bool(var, value);
                return 0;
        }
+       if (!strcmp(var, "report.queue-size")) {
+               rep->queue_size = perf_config_u64(var, value);
+               return 0;
+       }
 
        return perf_default_config(var, value, cb);
 }
@@ -578,7 +584,7 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
                        .attr            = perf_event__process_attr,
                        .tracing_data    = perf_event__process_tracing_data,
                        .build_id        = perf_event__process_build_id,
-                       .ordered_samples = true,
+                       .ordered_events  = true,
                        .ordering_requires_timestamps = true,
                },
                .max_stack               = PERF_MAX_STACK_DEPTH,
@@ -674,6 +680,8 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
                   "objdump binary to use for disassembly and annotations"),
        OPT_BOOLEAN(0, "demangle", &symbol_conf.demangle,
                    "Disable symbol demangling"),
+       OPT_BOOLEAN(0, "demangle-kernel", &symbol_conf.demangle_kernel,
+                   "Enable kernel symbol demangling"),
        OPT_BOOLEAN(0, "mem-mode", &report.mem_mode, "mem access profile"),
        OPT_CALLBACK(0, "percent-limit", &report, "percent",
                     "Don't show entries under that percent", parse_percent_limit),
@@ -712,14 +720,19 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
 repeat:
        session = perf_session__new(&file, false, &report.tool);
        if (session == NULL)
-               return -ENOMEM;
+               return -1;
+
+       if (report.queue_size) {
+               ordered_events__set_alloc_size(&session->ordered_events,
+                                              report.queue_size);
+       }
 
        report.session = session;
 
        has_br_stack = perf_header__has_feat(&session->header,
                                             HEADER_BRANCH_STACK);
 
-       if (branch_mode == -1 && has_br_stack) {
+       if ((branch_mode == -1 && has_br_stack) || branch_mode == 1) {
                sort__mode = SORT_MODE__BRANCH;
                symbol_conf.cumulate_callchain = false;
        }
@@ -787,7 +800,7 @@ repeat:
                }
        }
 
-       if (symbol__init() < 0)
+       if (symbol__init(&session->header.env) < 0)
                goto error;
 
        if (argc) {
index f83c08c0dd87caaa97a8c0b3958320b65a2ed2ef..9c9287fbf8e98d4b480a668d34d756b2c11ed9f3 100644 (file)
@@ -428,6 +428,7 @@ static u64 get_cpu_usage_nsec_parent(void)
 static int self_open_counters(void)
 {
        struct perf_event_attr attr;
+       char sbuf[STRERR_BUFSIZE];
        int fd;
 
        memset(&attr, 0, sizeof(attr));
@@ -440,7 +441,8 @@ static int self_open_counters(void)
 
        if (fd < 0)
                pr_err("Error: sys_perf_event_open() syscall returned "
-                      "with %d (%s)\n", fd, strerror(errno));
+                      "with %d (%s)\n", fd,
+                      strerror_r(errno, sbuf, sizeof(sbuf)));
        return fd;
 }
 
@@ -1462,6 +1464,8 @@ static int perf_sched__read_events(struct perf_sched *sched,
                return -1;
        }
 
+       symbol__init(&session->header.env);
+
        if (perf_session__set_tracepoints_handlers(session, handlers))
                goto out_delete;
 
@@ -1662,7 +1666,7 @@ int cmd_sched(int argc, const char **argv, const char *prefix __maybe_unused)
                        .comm            = perf_event__process_comm,
                        .lost            = perf_event__process_lost,
                        .fork            = perf_sched__process_fork_event,
-                       .ordered_samples = true,
+                       .ordered_events = true,
                },
                .cmp_pid              = LIST_HEAD_INIT(sched.cmp_pid),
                .sort_list            = LIST_HEAD_INIT(sched.sort_list),
@@ -1747,7 +1751,6 @@ int cmd_sched(int argc, const char **argv, const char *prefix __maybe_unused)
        if (!strcmp(argv[0], "script"))
                return cmd_script(argc, argv, prefix);
 
-       symbol__init();
        if (!strncmp(argv[0], "rec", 3)) {
                return __cmd_record(argc, argv);
        } else if (!strncmp(argv[0], "lat", 3)) {
index f57035b89c15d11a5178cd3468cf5bd9b03405c1..b9b9e58a6c399d4c4c2e8dc3162598acf2b1cd62 100644 (file)
@@ -184,10 +184,6 @@ static int perf_evsel__check_attr(struct perf_evsel *evsel,
                if (perf_evsel__check_stype(evsel, PERF_SAMPLE_IP, "IP",
                                            PERF_OUTPUT_IP))
                        return -EINVAL;
-
-               if (!no_callchain &&
-                   !(attr->sample_type & PERF_SAMPLE_CALLCHAIN))
-                       symbol_conf.use_callchain = false;
        }
 
        if (PRINT_FIELD(ADDR) &&
@@ -290,6 +286,19 @@ static int perf_session__check_output_opt(struct perf_session *session)
                set_print_ip_opts(&evsel->attr);
        }
 
+       if (!no_callchain) {
+               bool use_callchain = false;
+
+               evlist__for_each(session->evlist, evsel) {
+                       if (evsel->attr.sample_type & PERF_SAMPLE_CALLCHAIN) {
+                               use_callchain = true;
+                               break;
+                       }
+               }
+               if (!use_callchain)
+                       symbol_conf.use_callchain = false;
+       }
+
        /*
         * set default for tracepoints to print symbols only
         * if callchains are present
@@ -476,6 +485,11 @@ static int default_start_script(const char *script __maybe_unused,
        return 0;
 }
 
+static int default_flush_script(void)
+{
+       return 0;
+}
+
 static int default_stop_script(void)
 {
        return 0;
@@ -489,6 +503,7 @@ static int default_generate_script(struct pevent *pevent __maybe_unused,
 
 static struct scripting_ops default_scripting_ops = {
        .start_script           = default_start_script,
+       .flush_script           = default_flush_script,
        .stop_script            = default_stop_script,
        .process_event          = process_event,
        .generate_script        = default_generate_script,
@@ -504,6 +519,11 @@ static void setup_scripting(void)
        scripting_ops = &default_scripting_ops;
 }
 
+static int flush_scripting(void)
+{
+       return scripting_ops->flush_script();
+}
+
 static int cleanup_scripting(void)
 {
        pr_debug("\nperf script stopped\n");
@@ -1471,12 +1491,13 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused)
        bool show_full_info = false;
        bool header = false;
        bool header_only = false;
+       bool script_started = false;
        char *rec_script_path = NULL;
        char *rep_script_path = NULL;
        struct perf_session *session;
        char *script_path = NULL;
        const char **__argv;
-       int i, j, err;
+       int i, j, err = 0;
        struct perf_script script = {
                .tool = {
                        .sample          = process_sample_event,
@@ -1488,7 +1509,7 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused)
                        .attr            = process_attr,
                        .tracing_data    = perf_event__process_tracing_data,
                        .build_id        = perf_event__process_build_id,
-                       .ordered_samples = true,
+                       .ordered_events  = true,
                        .ordering_requires_timestamps = true,
                },
        };
@@ -1718,26 +1739,28 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused)
                exit(-1);
        }
 
-       if (symbol__init() < 0)
-               return -1;
        if (!script_name)
                setup_pager();
 
        session = perf_session__new(&file, false, &script.tool);
        if (session == NULL)
-               return -ENOMEM;
+               return -1;
 
        if (header || header_only) {
                perf_session__fprintf_info(session, stdout, show_full_info);
                if (header_only)
-                       return 0;
+                       goto out_delete;
        }
 
+       if (symbol__init(&session->header.env) < 0)
+               goto out_delete;
+
        script.session = session;
 
        if (cpu_list) {
-               if (perf_session__cpu_bitmap(session, cpu_list, cpu_bitmap))
-                       return -1;
+               err = perf_session__cpu_bitmap(session, cpu_list, cpu_bitmap);
+               if (err < 0)
+                       goto out_delete;
        }
 
        if (!no_callchain)
@@ -1752,53 +1775,62 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused)
                if (output_set_by_user()) {
                        fprintf(stderr,
                                "custom fields not supported for generated scripts");
-                       return -1;
+                       err = -EINVAL;
+                       goto out_delete;
                }
 
                input = open(file.path, O_RDONLY);      /* input_name */
                if (input < 0) {
+                       err = -errno;
                        perror("failed to open file");
-                       return -1;
+                       goto out_delete;
                }
 
                err = fstat(input, &perf_stat);
                if (err < 0) {
                        perror("failed to stat file");
-                       return -1;
+                       goto out_delete;
                }
 
                if (!perf_stat.st_size) {
                        fprintf(stderr, "zero-sized file, nothing to do!\n");
-                       return 0;
+                       goto out_delete;
                }
 
                scripting_ops = script_spec__lookup(generate_script_lang);
                if (!scripting_ops) {
                        fprintf(stderr, "invalid language specifier");
-                       return -1;
+                       err = -ENOENT;
+                       goto out_delete;
                }
 
                err = scripting_ops->generate_script(session->tevent.pevent,
                                                     "perf-script");
-               goto out;
+               goto out_delete;
        }
 
        if (script_name) {
                err = scripting_ops->start_script(script_name, argc, argv);
                if (err)
-                       goto out;
+                       goto out_delete;
                pr_debug("perf script started with script %s\n\n", script_name);
+               script_started = true;
        }
 
 
        err = perf_session__check_output_opt(session);
        if (err < 0)
-               goto out;
+               goto out_delete;
 
        err = __cmd_script(&script);
 
+       flush_scripting();
+
+out_delete:
        perf_session__delete(session);
-       cleanup_scripting();
+
+       if (script_started)
+               cleanup_scripting();
 out:
        return err;
 }
index 3e80aa10cfd8d717c37850a23abade2321f134a4..b22c62f80078771d9167a2311a6e504cdd3a5690 100644 (file)
@@ -593,7 +593,7 @@ static int __run_perf_stat(int argc, const char **argv)
 
        if (perf_evlist__apply_filters(evsel_list)) {
                error("failed to set filter with %d (%s)\n", errno,
-                       strerror(errno));
+                       strerror_r(errno, msg, sizeof(msg)));
                return -1;
        }
 
@@ -732,7 +732,7 @@ static void aggr_printout(struct perf_evsel *evsel, int id, int nr)
        }
 }
 
-static void nsec_printout(int cpu, int nr, struct perf_evsel *evsel, double avg)
+static void nsec_printout(int id, int nr, struct perf_evsel *evsel, double avg)
 {
        double msecs = avg / 1e6;
        const char *fmt_v, *fmt_n;
@@ -741,7 +741,7 @@ static void nsec_printout(int cpu, int nr, struct perf_evsel *evsel, double avg)
        fmt_v = csv_output ? "%.6f%s" : "%18.6f%s";
        fmt_n = csv_output ? "%s" : "%-25s";
 
-       aggr_printout(evsel, cpu, nr);
+       aggr_printout(evsel, id, nr);
 
        scnprintf(name, sizeof(name), "%s%s",
                  perf_evsel__name(evsel), csv_output ? "" : " (msec)");
@@ -947,11 +947,12 @@ static void print_ll_cache_misses(int cpu,
        fprintf(output, " of all LL-cache hits   ");
 }
 
-static void abs_printout(int cpu, int nr, struct perf_evsel *evsel, double avg)
+static void abs_printout(int id, int nr, struct perf_evsel *evsel, double avg)
 {
        double total, ratio = 0.0, total2;
        double sc =  evsel->scale;
        const char *fmt;
+       int cpu = cpu_map__id_to_cpu(id);
 
        if (csv_output) {
                fmt = sc != 1.0 ?  "%.2f%s" : "%.0f%s";
@@ -962,7 +963,7 @@ static void abs_printout(int cpu, int nr, struct perf_evsel *evsel, double avg)
                        fmt = sc != 1.0 ? "%18.2f%s" : "%18.0f%s";
        }
 
-       aggr_printout(evsel, cpu, nr);
+       aggr_printout(evsel, id, nr);
 
        if (aggr_mode == AGGR_GLOBAL)
                cpu = 0;
index 2f1a5220c090f4fd8461b743f85b88b0b812214b..35b425b6293f759b5119d8fb6a07d2ab2303d6f7 100644 (file)
@@ -1605,7 +1605,9 @@ static int __cmd_timechart(struct timechart *tchart, const char *output_name)
        int ret = -EINVAL;
 
        if (session == NULL)
-               return -ENOMEM;
+               return -1;
+
+       symbol__init(&session->header.env);
 
        (void)perf_header__process_sections(&session->header,
                                            perf_data_file__fd(session->file),
@@ -1920,7 +1922,7 @@ int cmd_timechart(int argc, const char **argv,
                        .fork            = process_fork_event,
                        .exit            = process_exit_event,
                        .sample          = process_sample_event,
-                       .ordered_samples = true,
+                       .ordered_events  = true,
                },
                .proc_num = 15,
                .min_time = 1000000,
@@ -1982,8 +1984,6 @@ int cmd_timechart(int argc, const char **argv,
                return -1;
        }
 
-       symbol__init();
-
        if (argc && !strncmp(argv[0], "rec", 3)) {
                argc = parse_options(argc, argv, record_options, record_usage,
                                     PARSE_OPT_STOP_AT_NON_OPTION);
index 377971dc89a3b26ffcd25b9eb3e8c0c01338ea24..fc3d55f832ac0c55d316fe17aa20170f7096dfe9 100644 (file)
@@ -59,7 +59,7 @@
 
 #include <sys/syscall.h>
 #include <sys/ioctl.h>
-#include <sys/poll.h>
+#include <poll.h>
 #include <sys/prctl.h>
 #include <sys/wait.h>
 #include <sys/uio.h>
@@ -276,11 +276,17 @@ static void perf_top__print_sym_table(struct perf_top *top)
                return;
        }
 
+       if (top->zero) {
+               hists__delete_entries(&top->sym_evsel->hists);
+       } else {
+               hists__decay_entries(&top->sym_evsel->hists,
+                                    top->hide_user_symbols,
+                                    top->hide_kernel_symbols);
+       }
+
        hists__collapse_resort(&top->sym_evsel->hists, NULL);
        hists__output_resort(&top->sym_evsel->hists);
-       hists__decay_entries(&top->sym_evsel->hists,
-                            top->hide_user_symbols,
-                            top->hide_kernel_symbols);
+
        hists__output_recalc_col_len(&top->sym_evsel->hists,
                                     top->print_entries - printed);
        putchar('\n');
@@ -427,18 +433,13 @@ static bool perf_top__handle_keypress(struct perf_top *top, int c)
 
        if (!perf_top__key_mapped(top, c)) {
                struct pollfd stdin_poll = { .fd = 0, .events = POLLIN };
-               struct termios tc, save;
+               struct termios save;
 
                perf_top__print_mapped_keys(top);
                fprintf(stdout, "\nEnter selection, or unmapped key to continue: ");
                fflush(stdout);
 
-               tcgetattr(0, &save);
-               tc = save;
-               tc.c_lflag &= ~(ICANON | ECHO);
-               tc.c_cc[VMIN] = 0;
-               tc.c_cc[VTIME] = 0;
-               tcsetattr(0, TCSANOW, &tc);
+               set_term_quiet_input(&save);
 
                poll(&stdin_poll, 1, -1);
                c = getc(stdin);
@@ -542,11 +543,16 @@ static void perf_top__sort_new_samples(void *arg)
        if (t->evlist->selected != NULL)
                t->sym_evsel = t->evlist->selected;
 
+       if (t->zero) {
+               hists__delete_entries(&t->sym_evsel->hists);
+       } else {
+               hists__decay_entries(&t->sym_evsel->hists,
+                                    t->hide_user_symbols,
+                                    t->hide_kernel_symbols);
+       }
+
        hists__collapse_resort(&t->sym_evsel->hists, NULL);
        hists__output_resort(&t->sym_evsel->hists);
-       hists__decay_entries(&t->sym_evsel->hists,
-                            t->hide_user_symbols,
-                            t->hide_kernel_symbols);
 }
 
 static void *display_thread_tui(void *arg)
@@ -577,23 +583,32 @@ static void *display_thread_tui(void *arg)
        return NULL;
 }
 
+static void display_sig(int sig __maybe_unused)
+{
+       done = 1;
+}
+
+static void display_setup_sig(void)
+{
+       signal(SIGSEGV, display_sig);
+       signal(SIGFPE,  display_sig);
+       signal(SIGINT,  display_sig);
+       signal(SIGQUIT, display_sig);
+       signal(SIGTERM, display_sig);
+}
+
 static void *display_thread(void *arg)
 {
        struct pollfd stdin_poll = { .fd = 0, .events = POLLIN };
-       struct termios tc, save;
+       struct termios save;
        struct perf_top *top = arg;
        int delay_msecs, c;
 
-       tcgetattr(0, &save);
-       tc = save;
-       tc.c_lflag &= ~(ICANON | ECHO);
-       tc.c_cc[VMIN] = 0;
-       tc.c_cc[VTIME] = 0;
-
+       display_setup_sig();
        pthread__unblock_sigwinch();
 repeat:
        delay_msecs = top->delay_secs * 1000;
-       tcsetattr(0, TCSANOW, &tc);
+       set_term_quiet_input(&save);
        /* trash return*/
        getc(stdin);
 
@@ -620,13 +635,16 @@ repeat:
                }
        }
 
+       tcsetattr(0, TCSAFLUSH, &save);
        return NULL;
 }
 
-static int symbol_filter(struct map *map __maybe_unused, struct symbol *sym)
+static int symbol_filter(struct map *map, struct symbol *sym)
 {
        const char *name = sym->name;
 
+       if (!map->dso->kernel)
+               return 0;
        /*
         * ppc64 uses function descriptors and appends a '.' to the
         * start of every instruction address. Remove it.
@@ -876,7 +894,7 @@ try_again:
 
        if (perf_evlist__mmap(evlist, opts->mmap_pages, false) < 0) {
                ui__error("Failed to mmap with %d (%s)\n",
-                           errno, strerror(errno));
+                           errno, strerror_r(errno, msg, sizeof(msg)));
                goto out_err;
        }
 
@@ -911,7 +929,7 @@ static int __cmd_top(struct perf_top *top)
 
        top->session = perf_session__new(NULL, false, NULL);
        if (top->session == NULL)
-               return -ENOMEM;
+               return -1;
 
        machines__set_symbol_filter(&top->session->machines, symbol_filter);
 
@@ -946,7 +964,7 @@ static int __cmd_top(struct perf_top *top)
                 perf_evlist__enable(top->evlist);
 
        /* Wait for a minimal set of events before starting the snapshot */
-       poll(top->evlist->pollfd, top->evlist->nr_fds, 100);
+       perf_evlist__poll(top->evlist, 100);
 
        perf_top__mmap_read(top);
 
@@ -963,7 +981,7 @@ static int __cmd_top(struct perf_top *top)
                param.sched_priority = top->realtime_prio;
                if (sched_setscheduler(0, SCHED_FIFO, &param)) {
                        ui__error("Could not set realtime priority.\n");
-                       goto out_delete;
+                       goto out_join;
                }
        }
 
@@ -973,10 +991,12 @@ static int __cmd_top(struct perf_top *top)
                perf_top__mmap_read(top);
 
                if (hits == top->samples)
-                       ret = poll(top->evlist->pollfd, top->evlist->nr_fds, 100);
+                       ret = perf_evlist__poll(top->evlist, 100);
        }
 
        ret = 0;
+out_join:
+       pthread_join(thread, NULL);
 out_delete:
        perf_session__delete(top->session);
        top->session = NULL;
@@ -1000,10 +1020,8 @@ parse_callchain_opt(const struct option *opt, const char *arg, int unset)
 
 static int perf_top_config(const char *var, const char *value, void *cb)
 {
-       struct perf_top *top = cb;
-
        if (!strcmp(var, "top.call-graph"))
-               return record_parse_callchain(value, &top->record_opts);
+               var = "call-graph.record-mode"; /* fall-through */
        if (!strcmp(var, "top.children")) {
                symbol_conf.cumulate_callchain = perf_config_bool(var, value);
                return 0;
@@ -1122,6 +1140,8 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused)
                    "Interleave source code with assembly code (default)"),
        OPT_BOOLEAN(0, "asm-raw", &symbol_conf.annotate_asm_raw,
                    "Display raw encoding of assembly instructions (default)"),
+       OPT_BOOLEAN(0, "demangle-kernel", &symbol_conf.demangle_kernel,
+                   "Enable kernel symbol demangling"),
        OPT_STRING(0, "objdump", &objdump_path, "path",
                    "objdump binary to use for disassembly and annotations"),
        OPT_STRING('M', "disassembler-style", &disassembler_style, "disassembler style",
@@ -1131,6 +1151,9 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused)
                     "Don't show entries under that percent", parse_percent_limit),
        OPT_CALLBACK(0, "percentage", NULL, "relative|absolute",
                     "How to display percentage of filtered entries", parse_filter_percentage),
+       OPT_STRING('w', "column-widths", &symbol_conf.col_width_list_str,
+                  "width[,width...]",
+                  "don't try to adjust column width, use these fixed values"),
        OPT_END()
        };
        const char * const top_usage[] = {
@@ -1217,7 +1240,7 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused)
        symbol_conf.priv_size = sizeof(struct annotation);
 
        symbol_conf.try_vmlinux_path = (symbol_conf.vmlinux_name == NULL);
-       if (symbol__init() < 0)
+       if (symbol__init(NULL) < 0)
                return -1;
 
        sort__setup_elide(stdout);
index a6c375224f4613c27ab72d02799f8632d6db505f..09bcf2393910af792911a622f1ce613d31895af6 100644 (file)
@@ -402,6 +402,31 @@ static size_t syscall_arg__scnprintf_mmap_flags(char *bf, size_t size,
 
 #define SCA_MMAP_FLAGS syscall_arg__scnprintf_mmap_flags
 
+static size_t syscall_arg__scnprintf_mremap_flags(char *bf, size_t size,
+                                                 struct syscall_arg *arg)
+{
+       int printed = 0, flags = arg->val;
+
+#define P_MREMAP_FLAG(n) \
+       if (flags & MREMAP_##n) { \
+               printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
+               flags &= ~MREMAP_##n; \
+       }
+
+       P_MREMAP_FLAG(MAYMOVE);
+#ifdef MREMAP_FIXED
+       P_MREMAP_FLAG(FIXED);
+#endif
+#undef P_MREMAP_FLAG
+
+       if (flags)
+               printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
+
+       return printed;
+}
+
+#define SCA_MREMAP_FLAGS syscall_arg__scnprintf_mremap_flags
+
 static size_t syscall_arg__scnprintf_madvise_behavior(char *bf, size_t size,
                                                      struct syscall_arg *arg)
 {
@@ -1004,6 +1029,7 @@ static struct syscall_fmt {
                             [2] = SCA_MMAP_PROT, /* prot */ }, },
        { .name     = "mremap",     .hexret = true,
          .arg_scnprintf = { [0] = SCA_HEX, /* addr */
+                            [3] = SCA_MREMAP_FLAGS, /* flags */
                             [4] = SCA_HEX, /* new_addr */ }, },
        { .name     = "munlock",    .errmsg = true,
          .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
@@ -1385,7 +1411,7 @@ static int trace__tool_process(struct perf_tool *tool,
 
 static int trace__symbols_init(struct trace *trace, struct perf_evlist *evlist)
 {
-       int err = symbol__init();
+       int err = symbol__init(NULL);
 
        if (err)
                return err;
@@ -1669,7 +1695,7 @@ static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel,
                           union perf_event *event __maybe_unused,
                           struct perf_sample *sample)
 {
-       int ret;
+       long ret;
        u64 duration = 0;
        struct thread *thread;
        int id = perf_evsel__sc_tp_uint(evsel, id, sample);
@@ -1722,9 +1748,9 @@ static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel,
 
        if (sc->fmt == NULL) {
 signed_print:
-               fprintf(trace->output, ") = %d", ret);
+               fprintf(trace->output, ") = %ld", ret);
        } else if (ret < 0 && sc->fmt->errmsg) {
-               char bf[256];
+               char bf[STRERR_BUFSIZE];
                const char *emsg = strerror_r(-ret, bf, sizeof(bf)),
                           *e = audit_errno_to_name(-ret);
 
@@ -1732,7 +1758,7 @@ signed_print:
        } else if (ret == 0 && sc->fmt->timeout)
                fprintf(trace->output, ") = 0 Timeout");
        else if (sc->fmt->hexret)
-               fprintf(trace->output, ") = %#x", ret);
+               fprintf(trace->output, ") = %#lx", ret);
        else
                goto signed_print;
 
@@ -2018,6 +2044,8 @@ static int trace__run(struct trace *trace, int argc, const char **argv)
        int err = -1, i;
        unsigned long before;
        const bool forks = argc > 0;
+       bool draining = false;
+       char sbuf[STRERR_BUFSIZE];
 
        trace->live = true;
 
@@ -2079,7 +2107,8 @@ static int trace__run(struct trace *trace, int argc, const char **argv)
 
        err = perf_evlist__mmap(evlist, trace->opts.mmap_pages, false);
        if (err < 0) {
-               fprintf(trace->output, "Couldn't mmap the events: %s\n", strerror(errno));
+               fprintf(trace->output, "Couldn't mmap the events: %s\n",
+                       strerror_r(errno, sbuf, sizeof(sbuf)));
                goto out_delete_evlist;
        }
 
@@ -2143,8 +2172,12 @@ next_event:
        if (trace->nr_events == before) {
                int timeout = done ? 100 : -1;
 
-               if (poll(evlist->pollfd, evlist->nr_fds, timeout) > 0)
+               if (!draining && perf_evlist__poll(evlist, timeout) > 0) {
+                       if (perf_evlist__filter_pollfd(evlist, POLLERR | POLLHUP) == 0)
+                               draining = true;
+
                        goto again;
+               }
        } else {
                goto again;
        }
@@ -2209,18 +2242,18 @@ static int trace__replay(struct trace *trace)
        trace->tool.tracing_data = perf_event__process_tracing_data;
        trace->tool.build_id      = perf_event__process_build_id;
 
-       trace->tool.ordered_samples = true;
+       trace->tool.ordered_events = true;
        trace->tool.ordering_requires_timestamps = true;
 
        /* add tid to output */
        trace->multiple_threads = true;
 
-       if (symbol__init() < 0)
-               return -1;
-
        session = perf_session__new(&file, false, &trace->tool);
        if (session == NULL)
-               return -ENOMEM;
+               return -1;
+
+       if (symbol__init(&session->header.env) < 0)
+               goto out;
 
        trace->host = &session->machines.host;
 
index 1f67aa02d240b0ba5c3ae53a55f0ecc03fbfb76a..58f609198c6dcce0c7af6082d62c7254c29e5179 100644 (file)
@@ -48,10 +48,6 @@ ifneq ($(ARCH),$(filter $(ARCH),x86 arm))
   NO_LIBDW_DWARF_UNWIND := 1
 endif
 
-ifeq ($(ARCH),powerpc)
-  CFLAGS += -DHAVE_SKIP_CALLCHAIN_IDX
-endif
-
 ifeq ($(LIBUNWIND_LIBS),)
   NO_LIBUNWIND := 1
 else
@@ -120,6 +116,29 @@ ifdef PARSER_DEBUG
   CFLAGS             += -DPARSER_DEBUG
 endif
 
+ifndef NO_LIBPYTHON
+  # 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)
+endif
+
 CFLAGS += -fno-omit-frame-pointer
 CFLAGS += -ggdb3
 CFLAGS += -funwind-tables
@@ -355,6 +374,12 @@ ifndef NO_LIBELF
   endif # NO_DWARF
 endif # NO_LIBELF
 
+ifeq ($(ARCH),powerpc)
+  ifndef NO_DWARF
+    CFLAGS += -DHAVE_SKIP_CALLCHAIN_IDX
+  endif
+endif
+
 ifndef NO_LIBUNWIND
   ifneq ($(feature-libunwind), 1)
     msg := $(warning No libunwind found. Please install libunwind-dev[el] >= 1.1 and/or set LIBUNWIND_DIR);
@@ -482,21 +507,14 @@ define disable-python_code
   NO_LIBPYTHON := 1
 endef
 
-override PYTHON := \
-  $(call get-executable-or-default,PYTHON,python)
-
-ifndef PYTHON
-  $(call disable-python,python interpreter)
+ifdef NO_LIBPYTHON
+  $(call disable-python)
 else
 
-  PYTHON_WORD := $(call shell-wordify,$(PYTHON))
-
-  ifdef NO_LIBPYTHON
-    $(call disable-python)
+  ifndef PYTHON
+    $(call disable-python,python interpreter)
   else
-
-    override PYTHON_CONFIG := \
-      $(call get-executable-or-default,PYTHON_CONFIG,$(PYTHON)-config)
+    PYTHON_WORD := $(call shell-wordify,$(PYTHON))
 
     ifndef PYTHON_CONFIG
       $(call disable-python,python-config tool)
@@ -635,11 +653,13 @@ else
 sysconfdir = $(prefix)/etc
 ETC_PERFCONFIG = etc/perfconfig
 endif
+ifndef lib
 ifeq ($(IS_X86_64),1)
 lib = lib64
 else
 lib = lib
 endif
+endif # lib
 libdir = $(prefix)/$(lib)
 
 # Shell quote (do not use $(call) to accommodate ancient setups);
index 6088f8d8a434a2860031b464caa4dac1ad691fad..72ab2984718e341e0a18f2e4ad0953cc3359a4c6 100644 (file)
@@ -101,25 +101,11 @@ FLAGS_PERL_EMBED=$(PERL_EMBED_CCOPTS) $(PERL_EMBED_LDOPTS)
 test-libperl.bin:
        $(BUILD) $(FLAGS_PERL_EMBED)
 
-override PYTHON := python
-override PYTHON_CONFIG := python-config
-
-escape-for-shell-sq =  $(subst ','\'',$(1))
-shell-sq = '$(escape-for-shell-sq)'
-
-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))
-PYTHON_EMBED_CCOPTS = $(shell $(PYTHON_CONFIG_SQ) --cflags 2>/dev/null)
-FLAGS_PYTHON_EMBED = $(PYTHON_EMBED_CCOPTS) $(PYTHON_EMBED_LDOPTS)
-
 test-libpython.bin:
-       $(BUILD) $(FLAGS_PYTHON_EMBED)
+       $(BUILD)
 
 test-libpython-version.bin:
-       $(BUILD) $(FLAGS_PYTHON_EMBED)
+       $(BUILD)
 
 test-libbfd.bin:
        $(BUILD) -DPACKAGE='"perf"' -lbfd -lz -liberty -ldl
index 4d985e0f03f584f666fb74b86efd095a064ebaae..7076a62d0ff72c094ca0bb2e1eae7308aaaf948f 100644 (file)
@@ -132,7 +132,7 @@ endef
 #
 # Usage: bool-value = $(call is-absolute,path)
 #
-is-absolute = $(shell echo $(shell-sq) | grep ^/ -q && echo y)
+is-absolute = $(shell echo $(shell-sq) | grep -q ^/ && echo y)
 
 # lookup
 #
diff --git a/tools/perf/perf-with-kcore.sh b/tools/perf/perf-with-kcore.sh
new file mode 100644 (file)
index 0000000..c7ff90a
--- /dev/null
@@ -0,0 +1,259 @@
+#!/bin/bash
+# perf-with-kcore: use perf with a copy of kcore
+# Copyright (c) 2014, Intel Corporation.
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms and conditions of the GNU General Public License,
+# version 2, as published by the Free Software Foundation.
+#
+# This program is distributed in the hope it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+# more details.
+
+set -e
+
+usage()
+{
+        echo "Usage: perf-with-kcore <perf sub-command> <perf.data directory> [<sub-command options> [ -- <workload>]]" >&2
+        echo "       <perf sub-command> can be record, script, report or inject" >&2
+        echo "   or: perf-with-kcore fix_buildid_cache_permissions" >&2
+        exit 1
+}
+
+find_perf()
+{
+       if [ -n "$PERF" ] ; then
+               return
+       fi
+       PERF=`which perf || true`
+       if [ -z "$PERF" ] ; then
+               echo "Failed to find perf" >&2
+               exit 1
+       fi
+       if [ ! -x "$PERF" ] ; then
+               echo "Failed to find perf" >&2
+               exit 1
+       fi
+       echo "Using $PERF"
+       "$PERF" version
+}
+
+copy_kcore()
+{
+       echo "Copying kcore"
+
+       if [ $EUID -eq 0 ] ; then
+               SUDO=""
+       else
+               SUDO="sudo"
+       fi
+
+       rm -f perf.data.junk
+       ("$PERF" record -o perf.data.junk $PERF_OPTIONS -- sleep 60) >/dev/null 2>/dev/null &
+       PERF_PID=$!
+
+       # Need to make sure that perf has started
+       sleep 1
+
+       KCORE=$(($SUDO "$PERF" buildid-cache -v -f -k /proc/kcore >/dev/null) 2>&1)
+       case "$KCORE" in
+       "kcore added to build-id cache directory "*)
+               KCORE_DIR=${KCORE#"kcore added to build-id cache directory "}
+       ;;
+       *)
+               kill $PERF_PID
+               wait >/dev/null 2>/dev/null || true
+               rm perf.data.junk
+               echo "$KCORE"
+               echo "Failed to find kcore" >&2
+               exit 1
+       ;;
+       esac
+
+       kill $PERF_PID
+       wait >/dev/null 2>/dev/null || true
+       rm perf.data.junk
+
+       $SUDO cp -a "$KCORE_DIR" "$(pwd)/$PERF_DATA_DIR"
+       $SUDO rm -f "$KCORE_DIR/kcore"
+       $SUDO rm -f "$KCORE_DIR/kallsyms"
+       $SUDO rm -f "$KCORE_DIR/modules"
+       $SUDO rmdir "$KCORE_DIR"
+
+       KCORE_DIR_BASENAME=$(basename "$KCORE_DIR")
+       KCORE_DIR="$(pwd)/$PERF_DATA_DIR/$KCORE_DIR_BASENAME"
+
+       $SUDO chown $UID "$KCORE_DIR"
+       $SUDO chown $UID "$KCORE_DIR/kcore"
+       $SUDO chown $UID "$KCORE_DIR/kallsyms"
+       $SUDO chown $UID "$KCORE_DIR/modules"
+
+       $SUDO chgrp $GROUPS "$KCORE_DIR"
+       $SUDO chgrp $GROUPS "$KCORE_DIR/kcore"
+       $SUDO chgrp $GROUPS "$KCORE_DIR/kallsyms"
+       $SUDO chgrp $GROUPS "$KCORE_DIR/modules"
+
+       ln -s "$KCORE_DIR_BASENAME" "$PERF_DATA_DIR/kcore_dir"
+}
+
+fix_buildid_cache_permissions()
+{
+       if [ $EUID -ne 0 ] ; then
+               echo "This script must be run as root via sudo " >&2
+               exit 1
+       fi
+
+       if [ -z "$SUDO_USER" ] ; then
+               echo "This script must be run via sudo" >&2
+               exit 1
+       fi
+
+       USER_HOME=$(bash <<< "echo ~$SUDO_USER")
+
+       if [ "$HOME" != "$USER_HOME" ] ; then
+               echo "Fix unnecessary because root has a home: $HOME" >&2
+               exit 1
+       fi
+
+       echo "Fixing buildid cache permissions"
+
+       find "$USER_HOME/.debug" -xdev -type d          ! -user "$SUDO_USER" -ls -exec chown    "$SUDO_USER" \{\} \;
+       find "$USER_HOME/.debug" -xdev -type f -links 1 ! -user "$SUDO_USER" -ls -exec chown    "$SUDO_USER" \{\} \;
+       find "$USER_HOME/.debug" -xdev -type l          ! -user "$SUDO_USER" -ls -exec chown -h "$SUDO_USER" \{\} \;
+
+       if [ -n "$SUDO_GID" ] ; then
+               find "$USER_HOME/.debug" -xdev -type d          ! -group "$SUDO_GID" -ls -exec chgrp    "$SUDO_GID" \{\} \;
+               find "$USER_HOME/.debug" -xdev -type f -links 1 ! -group "$SUDO_GID" -ls -exec chgrp    "$SUDO_GID" \{\} \;
+               find "$USER_HOME/.debug" -xdev -type l          ! -group "$SUDO_GID" -ls -exec chgrp -h "$SUDO_GID" \{\} \;
+       fi
+
+       echo "Done"
+}
+
+check_buildid_cache_permissions()
+{
+       if [ $EUID -eq 0 ] ; then
+               return
+       fi
+
+       PERMISSIONS_OK+=$(find "$HOME/.debug" -xdev -type d          ! -user "$USER" -print -quit)
+       PERMISSIONS_OK+=$(find "$HOME/.debug" -xdev -type f -links 1 ! -user "$USER" -print -quit)
+       PERMISSIONS_OK+=$(find "$HOME/.debug" -xdev -type l          ! -user "$USER" -print -quit)
+
+       PERMISSIONS_OK+=$(find "$HOME/.debug" -xdev -type d          ! -group "$GROUPS" -print -quit)
+       PERMISSIONS_OK+=$(find "$HOME/.debug" -xdev -type f -links 1 ! -group "$GROUPS" -print -quit)
+       PERMISSIONS_OK+=$(find "$HOME/.debug" -xdev -type l          ! -group "$GROUPS" -print -quit)
+
+       if [ -n "$PERMISSIONS_OK" ] ; then
+               echo "*** WARNING *** buildid cache permissions may need fixing" >&2
+       fi
+}
+
+record()
+{
+       echo "Recording"
+
+       if [ $EUID -ne 0 ] ; then
+
+               if [ "$(cat /proc/sys/kernel/kptr_restrict)" -ne 0 ] ; then
+                       echo "*** WARNING *** /proc/sys/kernel/kptr_restrict prevents access to kernel addresses" >&2
+               fi
+
+               if echo "$PERF_OPTIONS" | grep -q ' -a \|^-a \| -a$\|^-a$\| --all-cpus \|^--all-cpus \| --all-cpus$\|^--all-cpus$' ; then
+                       echo "*** WARNING *** system-wide tracing without root access will not be able to read all necessary information from /proc" >&2
+               fi
+
+               if echo "$PERF_OPTIONS" | grep -q 'intel_pt\|intel_bts\| -I\|^-I' ; then
+                       if [ "$(cat /proc/sys/kernel/perf_event_paranoid)" -gt -1 ] ; then
+                               echo "*** WARNING *** /proc/sys/kernel/perf_event_paranoid restricts buffer size and tracepoint (sched_switch) use" >&2
+                       fi
+
+                       if echo "$PERF_OPTIONS" | grep -q ' --per-thread \|^--per-thread \| --per-thread$\|^--per-thread$' ; then
+                               true
+                       elif echo "$PERF_OPTIONS" | grep -q ' -t \|^-t \| -t$\|^-t$' ; then
+                               true
+                       elif [ ! -r /sys/kernel/debug -o ! -x /sys/kernel/debug ] ; then
+                               echo "*** WARNING *** /sys/kernel/debug permissions prevent tracepoint (sched_switch) use" >&2
+                       fi
+               fi
+       fi
+
+       if [ -z "$1" ] ; then
+               echo "Workload is required for recording" >&2
+               usage
+       fi
+
+       if [ -e "$PERF_DATA_DIR" ] ; then
+               echo "'$PERF_DATA_DIR' exists" >&2
+               exit 1
+       fi
+
+       find_perf
+
+       mkdir "$PERF_DATA_DIR"
+
+       echo "$PERF record -o $PERF_DATA_DIR/perf.data $PERF_OPTIONS -- $*"
+       "$PERF" record -o "$PERF_DATA_DIR/perf.data" $PERF_OPTIONS -- $* || true
+
+       if rmdir "$PERF_DATA_DIR" > /dev/null 2>/dev/null ; then
+               exit 1
+       fi
+
+       copy_kcore
+
+       echo "Done"
+}
+
+subcommand()
+{
+       find_perf
+       check_buildid_cache_permissions
+       echo "$PERF $PERF_SUB_COMMAND -i $PERF_DATA_DIR/perf.data --kallsyms=$PERF_DATA_DIR/kcore_dir/kallsyms $*"
+       "$PERF" $PERF_SUB_COMMAND -i "$PERF_DATA_DIR/perf.data" "--kallsyms=$PERF_DATA_DIR/kcore_dir/kallsyms" $*
+}
+
+if [ "$1" = "fix_buildid_cache_permissions" ] ; then
+       fix_buildid_cache_permissions
+       exit 0
+fi
+
+PERF_SUB_COMMAND=$1
+PERF_DATA_DIR=$2
+shift || true
+shift || true
+
+if [ -z "$PERF_SUB_COMMAND" ] ; then
+       usage
+fi
+
+if [ -z "$PERF_DATA_DIR" ] ; then
+       usage
+fi
+
+case "$PERF_SUB_COMMAND" in
+"record")
+       while [ "$1" != "--" ] ; do
+               PERF_OPTIONS+="$1 "
+               shift || break
+       done
+       if [ "$1" != "--" ] ; then
+               echo "Options and workload are required for recording" >&2
+               usage
+       fi
+       shift
+       record $*
+;;
+"script")
+       subcommand $*
+;;
+"report")
+       subcommand $*
+;;
+"inject")
+       subcommand $*
+;;
+*)
+       usage
+;;
+esac
index 2282d41879a2b2ef0c1927f91856c21948e68f30..452a8474d29d8cedbed3e47f46a4ebc728663907 100644 (file)
@@ -313,6 +313,7 @@ static int run_builtin(struct cmd_struct *p, int argc, const char **argv)
        int status;
        struct stat st;
        const char *prefix;
+       char sbuf[STRERR_BUFSIZE];
 
        prefix = NULL;
        if (p->option & RUN_SETUP)
@@ -343,7 +344,8 @@ static int run_builtin(struct cmd_struct *p, int argc, const char **argv)
        status = 1;
        /* Check for ENOSPC and EIO errors.. */
        if (fflush(stdout)) {
-               fprintf(stderr, "write failure on standard output: %s", strerror(errno));
+               fprintf(stderr, "write failure on standard output: %s",
+                       strerror_r(errno, sbuf, sizeof(sbuf)));
                goto out;
        }
        if (ferror(stdout)) {
@@ -351,7 +353,8 @@ static int run_builtin(struct cmd_struct *p, int argc, const char **argv)
                goto out;
        }
        if (fclose(stdout)) {
-               fprintf(stderr, "close failed on standard output: %s", strerror(errno));
+               fprintf(stderr, "close failed on standard output: %s",
+                       strerror_r(errno, sbuf, sizeof(sbuf)));
                goto out;
        }
        status = 0;
@@ -466,6 +469,7 @@ void pthread__unblock_sigwinch(void)
 int main(int argc, const char **argv)
 {
        const char *cmd;
+       char sbuf[STRERR_BUFSIZE];
 
        /* The page_size is placed in util object. */
        page_size = sysconf(_SC_PAGE_SIZE);
@@ -561,7 +565,7 @@ int main(int argc, const char **argv)
        }
 
        fprintf(stderr, "Failed to run command '%s': %s\n",
-               cmd, strerror(errno));
+               cmd, strerror_r(errno, sbuf, sizeof(sbuf)));
 out:
        return 1;
 }
index 510c65f72858fb09fcdad8a5c21ba7bb732747d6..220d44e44c1b1d4fdfafcbe546690d2534108d7f 100644 (file)
@@ -41,8 +41,6 @@ void pthread__unblock_sigwinch(void);
 
 struct record_opts {
        struct target target;
-       int          call_graph;
-       bool         call_graph_enabled;
        bool         group;
        bool         inherit_stat;
        bool         no_buffering;
@@ -60,7 +58,6 @@ struct record_opts {
        u64          branch_stack;
        u64          default_interval;
        u64          user_interval;
-       u16          stack_dump_size;
        bool         sample_transaction;
        unsigned     initial_delay;
 };
index 6f8b01bc60330c71722e4d22a7d40b83c32fac25..ac655b0700e7648335cc15c45a560c80f35ae27c 100644 (file)
@@ -153,6 +153,18 @@ static struct test {
                .desc = "Test cumulation of child hist entries",
                .func = test__hists_cumulate,
        },
+       {
+               .desc = "Test tracking with sched_switch",
+               .func = test__switch_tracking,
+       },
+       {
+               .desc = "Filter fds with revents mask in a fdarray",
+               .func = test__fdarray__filter,
+       },
+       {
+               .desc = "Add fd to a fdarray, making it autogrow",
+               .func = test__fdarray__add,
+       },
        {
                .func = NULL,
        },
@@ -185,9 +197,11 @@ static bool perf_test__matches(int curr, int argc, const char *argv[])
 static int run_test(struct test *test)
 {
        int status, err = -1, child = fork();
+       char sbuf[STRERR_BUFSIZE];
 
        if (child < 0) {
-               pr_err("failed to fork test: %s\n", strerror(errno));
+               pr_err("failed to fork test: %s\n",
+                       strerror_r(errno, sbuf, sizeof(sbuf)));
                return -1;
        }
 
@@ -297,7 +311,7 @@ int cmd_test(int argc, const char **argv, const char *prefix __maybe_unused)
        symbol_conf.sort_by_name = true;
        symbol_conf.try_vmlinux_path = true;
 
-       if (symbol__init() < 0)
+       if (symbol__init(NULL) < 0)
                return -1;
 
        if (skip != NULL)
diff --git a/tools/perf/tests/fdarray.c b/tools/perf/tests/fdarray.c
new file mode 100644 (file)
index 0000000..d24b837
--- /dev/null
@@ -0,0 +1,174 @@
+#include <api/fd/array.h>
+#include "util/debug.h"
+#include "tests/tests.h"
+
+static void fdarray__init_revents(struct fdarray *fda, short revents)
+{
+       int fd;
+
+       fda->nr = fda->nr_alloc;
+
+       for (fd = 0; fd < fda->nr; ++fd) {
+               fda->entries[fd].fd      = fda->nr - fd;
+               fda->entries[fd].revents = revents;
+       }
+}
+
+static int fdarray__fprintf_prefix(struct fdarray *fda, const char *prefix, FILE *fp)
+{
+       int printed = 0;
+
+       if (!verbose)
+               return 0;
+
+       printed += fprintf(fp, "\n%s: ", prefix);
+       return printed + fdarray__fprintf(fda, fp);
+}
+
+int test__fdarray__filter(void)
+{
+       int nr_fds, expected_fd[2], fd, err = TEST_FAIL;
+       struct fdarray *fda = fdarray__new(5, 5);
+
+       if (fda == NULL) {
+               pr_debug("\nfdarray__new() failed!");
+               goto out;
+       }
+
+       fdarray__init_revents(fda, POLLIN);
+       nr_fds = fdarray__filter(fda, POLLHUP, NULL);
+       if (nr_fds != fda->nr_alloc) {
+               pr_debug("\nfdarray__filter()=%d != %d shouldn't have filtered anything",
+                        nr_fds, fda->nr_alloc);
+               goto out_delete;
+       }
+
+       fdarray__init_revents(fda, POLLHUP);
+       nr_fds = fdarray__filter(fda, POLLHUP, NULL);
+       if (nr_fds != 0) {
+               pr_debug("\nfdarray__filter()=%d != %d, should have filtered all fds",
+                        nr_fds, fda->nr_alloc);
+               goto out_delete;
+       }
+
+       fdarray__init_revents(fda, POLLHUP);
+       fda->entries[2].revents = POLLIN;
+       expected_fd[0] = fda->entries[2].fd;
+
+       pr_debug("\nfiltering all but fda->entries[2]:");
+       fdarray__fprintf_prefix(fda, "before", stderr);
+       nr_fds = fdarray__filter(fda, POLLHUP, NULL);
+       fdarray__fprintf_prefix(fda, " after", stderr);
+       if (nr_fds != 1) {
+               pr_debug("\nfdarray__filter()=%d != 1, should have left just one event", nr_fds);
+               goto out_delete;
+       }
+
+       if (fda->entries[0].fd != expected_fd[0]) {
+               pr_debug("\nfda->entries[0].fd=%d != %d\n",
+                        fda->entries[0].fd, expected_fd[0]);
+               goto out_delete;
+       }
+
+       fdarray__init_revents(fda, POLLHUP);
+       fda->entries[0].revents = POLLIN;
+       expected_fd[0] = fda->entries[0].fd;
+       fda->entries[3].revents = POLLIN;
+       expected_fd[1] = fda->entries[3].fd;
+
+       pr_debug("\nfiltering all but (fda->entries[0], fda->entries[3]):");
+       fdarray__fprintf_prefix(fda, "before", stderr);
+       nr_fds = fdarray__filter(fda, POLLHUP, NULL);
+       fdarray__fprintf_prefix(fda, " after", stderr);
+       if (nr_fds != 2) {
+               pr_debug("\nfdarray__filter()=%d != 2, should have left just two events",
+                        nr_fds);
+               goto out_delete;
+       }
+
+       for (fd = 0; fd < 2; ++fd) {
+               if (fda->entries[fd].fd != expected_fd[fd]) {
+                       pr_debug("\nfda->entries[%d].fd=%d != %d\n", fd,
+                                fda->entries[fd].fd, expected_fd[fd]);
+                       goto out_delete;
+               }
+       }
+
+       pr_debug("\n");
+
+       err = 0;
+out_delete:
+       fdarray__delete(fda);
+out:
+       return err;
+}
+
+int test__fdarray__add(void)
+{
+       int err = TEST_FAIL;
+       struct fdarray *fda = fdarray__new(2, 2);
+
+       if (fda == NULL) {
+               pr_debug("\nfdarray__new() failed!");
+               goto out;
+       }
+
+#define FDA_CHECK(_idx, _fd, _revents)                                    \
+       if (fda->entries[_idx].fd != _fd) {                                \
+               pr_debug("\n%d: fda->entries[%d](%d) != %d!",              \
+                        __LINE__, _idx, fda->entries[1].fd, _fd);         \
+               goto out_delete;                                           \
+       }                                                                  \
+       if (fda->entries[_idx].events != (_revents)) {                     \
+               pr_debug("\n%d: fda->entries[%d].revents(%d) != %d!",      \
+                        __LINE__, _idx, fda->entries[_idx].fd, _revents); \
+               goto out_delete;                                           \
+       }
+
+#define FDA_ADD(_idx, _fd, _revents, _nr)                                 \
+       if (fdarray__add(fda, _fd, _revents) < 0) {                        \
+               pr_debug("\n%d: fdarray__add(fda, %d, %d) failed!",        \
+                        __LINE__,_fd, _revents);                          \
+               goto out_delete;                                           \
+       }                                                                  \
+       if (fda->nr != _nr) {                                              \
+               pr_debug("\n%d: fdarray__add(fda, %d, %d)=%d != %d",       \
+                        __LINE__,_fd, _revents, fda->nr, _nr);            \
+               goto out_delete;                                           \
+       }                                                                  \
+       FDA_CHECK(_idx, _fd, _revents)
+
+       FDA_ADD(0, 1, POLLIN, 1);
+       FDA_ADD(1, 2, POLLERR, 2);
+
+       fdarray__fprintf_prefix(fda, "before growing array", stderr);
+
+       FDA_ADD(2, 35, POLLHUP, 3);
+
+       if (fda->entries == NULL) {
+               pr_debug("\nfdarray__add(fda, 35, POLLHUP) should have allocated fda->pollfd!");
+               goto out_delete;
+       }
+
+       fdarray__fprintf_prefix(fda, "after 3rd add", stderr);
+
+       FDA_ADD(3, 88, POLLIN | POLLOUT, 4);
+
+       fdarray__fprintf_prefix(fda, "after 4th add", stderr);
+
+       FDA_CHECK(0, 1, POLLIN);
+       FDA_CHECK(1, 2, POLLERR);
+       FDA_CHECK(2, 35, POLLHUP);
+       FDA_CHECK(3, 88, POLLIN | POLLOUT);
+
+#undef FDA_ADD
+#undef FDA_CHECK
+
+       pr_debug("\n");
+
+       err = 0;
+out_delete:
+       fdarray__delete(fda);
+out:
+       return err;
+}
index 142263492f6fe9234c8f4ba3141568e36f1bd38d..9b9622a33932dadf2e98bd249850c62f16ac66e5 100644 (file)
@@ -31,6 +31,7 @@ int test__basic_mmap(void)
        unsigned int nr_events[nsyscalls],
                     expected_nr_events[nsyscalls], i, j;
        struct perf_evsel *evsels[nsyscalls], *evsel;
+       char sbuf[STRERR_BUFSIZE];
 
        threads = thread_map__new(-1, getpid(), UINT_MAX);
        if (threads == NULL) {
@@ -49,7 +50,7 @@ int test__basic_mmap(void)
        sched_setaffinity(0, sizeof(cpu_set), &cpu_set);
        if (sched_setaffinity(0, sizeof(cpu_set), &cpu_set) < 0) {
                pr_debug("sched_setaffinity() failed on CPU %d: %s ",
-                        cpus->map[0], strerror(errno));
+                        cpus->map[0], strerror_r(errno, sbuf, sizeof(sbuf)));
                goto out_free_cpus;
        }
 
@@ -79,7 +80,7 @@ int test__basic_mmap(void)
                if (perf_evsel__open(evsels[i], cpus, threads) < 0) {
                        pr_debug("failed to open counter: %s, "
                                 "tweak /proc/sys/kernel/perf_event_paranoid?\n",
-                                strerror(errno));
+                                strerror_r(errno, sbuf, sizeof(sbuf)));
                        goto out_delete_evlist;
                }
 
@@ -89,7 +90,7 @@ int test__basic_mmap(void)
 
        if (perf_evlist__mmap(evlist, 128, true) < 0) {
                pr_debug("failed to mmap events: %d (%s)\n", errno,
-                        strerror(errno));
+                        strerror_r(errno, sbuf, sizeof(sbuf)));
                goto out_delete_evlist;
        }
 
index 5fecdbd2f5f772c09cb26d58cf9a1cb057cfa6a3..8fa82d1700c725f13519ef24ca4a8fbe8b235ea3 100644 (file)
@@ -12,6 +12,7 @@ int test__open_syscall_event_on_all_cpus(void)
        unsigned int nr_open_calls = 111, i;
        cpu_set_t cpu_set;
        struct thread_map *threads = thread_map__new(-1, getpid(), UINT_MAX);
+       char sbuf[STRERR_BUFSIZE];
 
        if (threads == NULL) {
                pr_debug("thread_map__new\n");
@@ -35,7 +36,7 @@ int test__open_syscall_event_on_all_cpus(void)
        if (perf_evsel__open(evsel, cpus, threads) < 0) {
                pr_debug("failed to open counter: %s, "
                         "tweak /proc/sys/kernel/perf_event_paranoid?\n",
-                        strerror(errno));
+                        strerror_r(errno, sbuf, sizeof(sbuf)));
                goto out_evsel_delete;
        }
 
@@ -56,7 +57,7 @@ int test__open_syscall_event_on_all_cpus(void)
                if (sched_setaffinity(0, sizeof(cpu_set), &cpu_set) < 0) {
                        pr_debug("sched_setaffinity() failed on CPU %d: %s ",
                                 cpus->map[cpu],
-                                strerror(errno));
+                                strerror_r(errno, sbuf, sizeof(sbuf)));
                        goto out_close_fd;
                }
                for (i = 0; i < ncalls; ++i) {
index 0785b64ffd6cd8b49009d89bdd935475e957f32a..127dcae0b76033cf457a4a4ff572da6771594e6f 100644 (file)
@@ -22,6 +22,7 @@ int test__syscall_open_tp_fields(void)
        struct perf_evlist *evlist = perf_evlist__new();
        struct perf_evsel *evsel;
        int err = -1, i, nr_events = 0, nr_polls = 0;
+       char sbuf[STRERR_BUFSIZE];
 
        if (evlist == NULL) {
                pr_debug("%s: perf_evlist__new\n", __func__);
@@ -48,13 +49,15 @@ int test__syscall_open_tp_fields(void)
 
        err = perf_evlist__open(evlist);
        if (err < 0) {
-               pr_debug("perf_evlist__open: %s\n", strerror(errno));
+               pr_debug("perf_evlist__open: %s\n",
+                        strerror_r(errno, sbuf, sizeof(sbuf)));
                goto out_delete_evlist;
        }
 
        err = perf_evlist__mmap(evlist, UINT_MAX, false);
        if (err < 0) {
-               pr_debug("perf_evlist__mmap: %s\n", strerror(errno));
+               pr_debug("perf_evlist__mmap: %s\n",
+                        strerror_r(errno, sbuf, sizeof(sbuf)));
                goto out_delete_evlist;
        }
 
@@ -102,7 +105,7 @@ int test__syscall_open_tp_fields(void)
                }
 
                if (nr_events == before)
-                       poll(evlist->pollfd, evlist->nr_fds, 10);
+                       perf_evlist__poll(evlist, 10);
 
                if (++nr_polls > 5) {
                        pr_debug("%s: no events!\n", __func__);
index c1dc7d25f38c6170847c74188ec5bac6d08e06f0..a33b2daae40f5239daa299a9a5335de26b39b420 100644 (file)
@@ -9,6 +9,7 @@ int test__open_syscall_event(void)
        struct perf_evsel *evsel;
        unsigned int nr_open_calls = 111, i;
        struct thread_map *threads = thread_map__new(-1, getpid(), UINT_MAX);
+       char sbuf[STRERR_BUFSIZE];
 
        if (threads == NULL) {
                pr_debug("thread_map__new\n");
@@ -24,7 +25,7 @@ int test__open_syscall_event(void)
        if (perf_evsel__open_per_thread(evsel, threads) < 0) {
                pr_debug("failed to open counter: %s, "
                         "tweak /proc/sys/kernel/perf_event_paranoid?\n",
-                        strerror(errno));
+                        strerror_r(errno, sbuf, sizeof(sbuf)));
                goto out_evsel_delete;
        }
 
index aca1a83dd13a946e8f47456725c3b725cfb4b25c..7a228a2a070bb2280d69320116b2985b5be05b21 100644 (file)
@@ -59,6 +59,7 @@ int test__PERF_RECORD(void)
        int err = -1, errs = 0, i, wakeups = 0;
        u32 cpu;
        int total_events = 0, nr_events[PERF_RECORD_MAX] = { 0, };
+       char sbuf[STRERR_BUFSIZE];
 
        if (evlist == NULL || argv == NULL) {
                pr_debug("Not enough memory to create evlist\n");
@@ -100,7 +101,8 @@ int test__PERF_RECORD(void)
 
        err = sched__get_first_possible_cpu(evlist->workload.pid, &cpu_mask);
        if (err < 0) {
-               pr_debug("sched__get_first_possible_cpu: %s\n", strerror(errno));
+               pr_debug("sched__get_first_possible_cpu: %s\n",
+                        strerror_r(errno, sbuf, sizeof(sbuf)));
                goto out_delete_evlist;
        }
 
@@ -110,7 +112,8 @@ int test__PERF_RECORD(void)
         * So that we can check perf_sample.cpu on all the samples.
         */
        if (sched_setaffinity(evlist->workload.pid, cpu_mask_size, &cpu_mask) < 0) {
-               pr_debug("sched_setaffinity: %s\n", strerror(errno));
+               pr_debug("sched_setaffinity: %s\n",
+                        strerror_r(errno, sbuf, sizeof(sbuf)));
                goto out_delete_evlist;
        }
 
@@ -120,7 +123,8 @@ int test__PERF_RECORD(void)
         */
        err = perf_evlist__open(evlist);
        if (err < 0) {
-               pr_debug("perf_evlist__open: %s\n", strerror(errno));
+               pr_debug("perf_evlist__open: %s\n",
+                        strerror_r(errno, sbuf, sizeof(sbuf)));
                goto out_delete_evlist;
        }
 
@@ -131,7 +135,8 @@ int test__PERF_RECORD(void)
         */
        err = perf_evlist__mmap(evlist, opts.mmap_pages, false);
        if (err < 0) {
-               pr_debug("perf_evlist__mmap: %s\n", strerror(errno));
+               pr_debug("perf_evlist__mmap: %s\n",
+                        strerror_r(errno, sbuf, sizeof(sbuf)));
                goto out_delete_evlist;
        }
 
@@ -263,7 +268,7 @@ int test__PERF_RECORD(void)
                 * perf_event_attr.wakeup_events, just PERF_EVENT_SAMPLE does.
                 */
                if (total_events == before && false)
-                       poll(evlist->pollfd, evlist->nr_fds, -1);
+                       perf_evlist__poll(evlist, -1);
 
                sleep(1);
                if (++wakeups > 5) {
index 12b322fa34753b9d463762276dc7ec4e9b0c909a..eeb68bb1972d44e41bafa5fc10809700e4afc630 100644 (file)
@@ -152,7 +152,7 @@ int test__pmu(void)
                if (ret)
                        break;
 
-               ret = perf_pmu__config_terms(&formats, &attr, terms);
+               ret = perf_pmu__config_terms(&formats, &attr, terms, false);
                if (ret)
                        break;
 
index c04d1f268576568f8a5b32c77e95796f40d8b723..d31f2c4d9f6491c62893f00cfbf46cdeff12ec90 100644 (file)
@@ -100,6 +100,7 @@ static int __test__rdpmc(void)
        };
        u64 delta_sum = 0;
         struct sigaction sa;
+       char sbuf[STRERR_BUFSIZE];
 
        sigfillset(&sa.sa_mask);
        sa.sa_sigaction = segfault_handler;
@@ -109,14 +110,15 @@ static int __test__rdpmc(void)
                                 perf_event_open_cloexec_flag());
        if (fd < 0) {
                pr_err("Error: sys_perf_event_open() syscall returned "
-                      "with %d (%s)\n", fd, strerror(errno));
+                      "with %d (%s)\n", fd,
+                      strerror_r(errno, sbuf, sizeof(sbuf)));
                return -1;
        }
 
        addr = mmap(NULL, page_size, PROT_READ, MAP_SHARED, fd, 0);
        if (addr == (void *)(-1)) {
                pr_err("Error: mmap() syscall returned with (%s)\n",
-                      strerror(errno));
+                      strerror_r(errno, sbuf, sizeof(sbuf)));
                goto out_close;
        }
 
index 983d6b8562a89f06f30f0aebd32e8b522f6b35fe..1aa21c90731b3eca400d91c2fec5d2b55a127f03 100644 (file)
@@ -22,6 +22,7 @@ static int __test__sw_clock_freq(enum perf_sw_ids clock_id)
        volatile int tmp = 0;
        u64 total_periods = 0;
        int nr_samples = 0;
+       char sbuf[STRERR_BUFSIZE];
        union perf_event *event;
        struct perf_evsel *evsel;
        struct perf_evlist *evlist;
@@ -62,14 +63,15 @@ static int __test__sw_clock_freq(enum perf_sw_ids clock_id)
 
                err = -errno;
                pr_debug("Couldn't open evlist: %s\nHint: check %s, using %" PRIu64 " in this test.\n",
-                        strerror(errno), knob, (u64)attr.sample_freq);
+                        strerror_r(errno, sbuf, sizeof(sbuf)),
+                        knob, (u64)attr.sample_freq);
                goto out_delete_evlist;
        }
 
        err = perf_evlist__mmap(evlist, 128, true);
        if (err < 0) {
                pr_debug("failed to mmap event: %d (%s)\n", errno,
-                        strerror(errno));
+                        strerror_r(errno, sbuf, sizeof(sbuf)));
                goto out_delete_evlist;
        }
 
diff --git a/tools/perf/tests/switch-tracking.c b/tools/perf/tests/switch-tracking.c
new file mode 100644 (file)
index 0000000..cc68648
--- /dev/null
@@ -0,0 +1,572 @@
+#include <sys/time.h>
+#include <sys/prctl.h>
+#include <time.h>
+#include <stdlib.h>
+
+#include "parse-events.h"
+#include "evlist.h"
+#include "evsel.h"
+#include "thread_map.h"
+#include "cpumap.h"
+#include "tests.h"
+
+static int spin_sleep(void)
+{
+       struct timeval start, now, diff, maxtime;
+       struct timespec ts;
+       int err, i;
+
+       maxtime.tv_sec = 0;
+       maxtime.tv_usec = 50000;
+
+       err = gettimeofday(&start, NULL);
+       if (err)
+               return err;
+
+       /* Spin for 50ms */
+       while (1) {
+               for (i = 0; i < 1000; i++)
+                       barrier();
+
+               err = gettimeofday(&now, NULL);
+               if (err)
+                       return err;
+
+               timersub(&now, &start, &diff);
+               if (timercmp(&diff, &maxtime, > /* For checkpatch */))
+                       break;
+       }
+
+       ts.tv_nsec = 50 * 1000 * 1000;
+       ts.tv_sec = 0;
+
+       /* Sleep for 50ms */
+       err = nanosleep(&ts, NULL);
+       if (err == EINTR)
+               err = 0;
+
+       return err;
+}
+
+struct switch_tracking {
+       struct perf_evsel *switch_evsel;
+       struct perf_evsel *cycles_evsel;
+       pid_t *tids;
+       int nr_tids;
+       int comm_seen[4];
+       int cycles_before_comm_1;
+       int cycles_between_comm_2_and_comm_3;
+       int cycles_after_comm_4;
+};
+
+static int check_comm(struct switch_tracking *switch_tracking,
+                     union perf_event *event, const char *comm, int nr)
+{
+       if (event->header.type == PERF_RECORD_COMM &&
+           (pid_t)event->comm.pid == getpid() &&
+           (pid_t)event->comm.tid == getpid() &&
+           strcmp(event->comm.comm, comm) == 0) {
+               if (switch_tracking->comm_seen[nr]) {
+                       pr_debug("Duplicate comm event\n");
+                       return -1;
+               }
+               switch_tracking->comm_seen[nr] = 1;
+               pr_debug3("comm event: %s nr: %d\n", event->comm.comm, nr);
+               return 1;
+       }
+       return 0;
+}
+
+static int check_cpu(struct switch_tracking *switch_tracking, int cpu)
+{
+       int i, nr = cpu + 1;
+
+       if (cpu < 0)
+               return -1;
+
+       if (!switch_tracking->tids) {
+               switch_tracking->tids = calloc(nr, sizeof(pid_t));
+               if (!switch_tracking->tids)
+                       return -1;
+               for (i = 0; i < nr; i++)
+                       switch_tracking->tids[i] = -1;
+               switch_tracking->nr_tids = nr;
+               return 0;
+       }
+
+       if (cpu >= switch_tracking->nr_tids) {
+               void *addr;
+
+               addr = realloc(switch_tracking->tids, nr * sizeof(pid_t));
+               if (!addr)
+                       return -1;
+               switch_tracking->tids = addr;
+               for (i = switch_tracking->nr_tids; i < nr; i++)
+                       switch_tracking->tids[i] = -1;
+               switch_tracking->nr_tids = nr;
+               return 0;
+       }
+
+       return 0;
+}
+
+static int process_sample_event(struct perf_evlist *evlist,
+                               union perf_event *event,
+                               struct switch_tracking *switch_tracking)
+{
+       struct perf_sample sample;
+       struct perf_evsel *evsel;
+       pid_t next_tid, prev_tid;
+       int cpu, err;
+
+       if (perf_evlist__parse_sample(evlist, event, &sample)) {
+               pr_debug("perf_evlist__parse_sample failed\n");
+               return -1;
+       }
+
+       evsel = perf_evlist__id2evsel(evlist, sample.id);
+       if (evsel == switch_tracking->switch_evsel) {
+               next_tid = perf_evsel__intval(evsel, &sample, "next_pid");
+               prev_tid = perf_evsel__intval(evsel, &sample, "prev_pid");
+               cpu = sample.cpu;
+               pr_debug3("sched_switch: cpu: %d prev_tid %d next_tid %d\n",
+                         cpu, prev_tid, next_tid);
+               err = check_cpu(switch_tracking, cpu);
+               if (err)
+                       return err;
+               /*
+                * Check for no missing sched_switch events i.e. that the
+                * evsel->system_wide flag has worked.
+                */
+               if (switch_tracking->tids[cpu] != -1 &&
+                   switch_tracking->tids[cpu] != prev_tid) {
+                       pr_debug("Missing sched_switch events\n");
+                       return -1;
+               }
+               switch_tracking->tids[cpu] = next_tid;
+       }
+
+       if (evsel == switch_tracking->cycles_evsel) {
+               pr_debug3("cycles event\n");
+               if (!switch_tracking->comm_seen[0])
+                       switch_tracking->cycles_before_comm_1 = 1;
+               if (switch_tracking->comm_seen[1] &&
+                   !switch_tracking->comm_seen[2])
+                       switch_tracking->cycles_between_comm_2_and_comm_3 = 1;
+               if (switch_tracking->comm_seen[3])
+                       switch_tracking->cycles_after_comm_4 = 1;
+       }
+
+       return 0;
+}
+
+static int process_event(struct perf_evlist *evlist, union perf_event *event,
+                        struct switch_tracking *switch_tracking)
+{
+       if (event->header.type == PERF_RECORD_SAMPLE)
+               return process_sample_event(evlist, event, switch_tracking);
+
+       if (event->header.type == PERF_RECORD_COMM) {
+               int err, done = 0;
+
+               err = check_comm(switch_tracking, event, "Test COMM 1", 0);
+               if (err < 0)
+                       return -1;
+               done += err;
+               err = check_comm(switch_tracking, event, "Test COMM 2", 1);
+               if (err < 0)
+                       return -1;
+               done += err;
+               err = check_comm(switch_tracking, event, "Test COMM 3", 2);
+               if (err < 0)
+                       return -1;
+               done += err;
+               err = check_comm(switch_tracking, event, "Test COMM 4", 3);
+               if (err < 0)
+                       return -1;
+               done += err;
+               if (done != 1) {
+                       pr_debug("Unexpected comm event\n");
+                       return -1;
+               }
+       }
+
+       return 0;
+}
+
+struct event_node {
+       struct list_head list;
+       union perf_event *event;
+       u64 event_time;
+};
+
+static int add_event(struct perf_evlist *evlist, struct list_head *events,
+                    union perf_event *event)
+{
+       struct perf_sample sample;
+       struct event_node *node;
+
+       node = malloc(sizeof(struct event_node));
+       if (!node) {
+               pr_debug("malloc failed\n");
+               return -1;
+       }
+       node->event = event;
+       list_add(&node->list, events);
+
+       if (perf_evlist__parse_sample(evlist, event, &sample)) {
+               pr_debug("perf_evlist__parse_sample failed\n");
+               return -1;
+       }
+
+       if (!sample.time) {
+               pr_debug("event with no time\n");
+               return -1;
+       }
+
+       node->event_time = sample.time;
+
+       return 0;
+}
+
+static void free_event_nodes(struct list_head *events)
+{
+       struct event_node *node;
+
+       while (!list_empty(events)) {
+               node = list_entry(events->next, struct event_node, list);
+               list_del(&node->list);
+               free(node);
+       }
+}
+
+static int compar(const void *a, const void *b)
+{
+       const struct event_node *nodea = a;
+       const struct event_node *nodeb = b;
+       s64 cmp = nodea->event_time - nodeb->event_time;
+
+       return cmp;
+}
+
+static int process_events(struct perf_evlist *evlist,
+                         struct switch_tracking *switch_tracking)
+{
+       union perf_event *event;
+       unsigned pos, cnt = 0;
+       LIST_HEAD(events);
+       struct event_node *events_array, *node;
+       int i, ret;
+
+       for (i = 0; i < evlist->nr_mmaps; i++) {
+               while ((event = perf_evlist__mmap_read(evlist, i)) != NULL) {
+                       cnt += 1;
+                       ret = add_event(evlist, &events, event);
+                       perf_evlist__mmap_consume(evlist, i);
+                       if (ret < 0)
+                               goto out_free_nodes;
+               }
+       }
+
+       events_array = calloc(cnt, sizeof(struct event_node));
+       if (!events_array) {
+               pr_debug("calloc failed\n");
+               ret = -1;
+               goto out_free_nodes;
+       }
+
+       pos = 0;
+       list_for_each_entry(node, &events, list)
+               events_array[pos++] = *node;
+
+       qsort(events_array, cnt, sizeof(struct event_node), compar);
+
+       for (pos = 0; pos < cnt; pos++) {
+               ret = process_event(evlist, events_array[pos].event,
+                                   switch_tracking);
+               if (ret < 0)
+                       goto out_free;
+       }
+
+       ret = 0;
+out_free:
+       pr_debug("%u events recorded\n", cnt);
+       free(events_array);
+out_free_nodes:
+       free_event_nodes(&events);
+       return ret;
+}
+
+/**
+ * test__switch_tracking - test using sched_switch and tracking events.
+ *
+ * This function implements a test that checks that sched_switch events and
+ * tracking events can be recorded for a workload (current process) using the
+ * evsel->system_wide and evsel->tracking flags (respectively) with other events
+ * sometimes enabled or disabled.
+ */
+int test__switch_tracking(void)
+{
+       const char *sched_switch = "sched:sched_switch";
+       struct switch_tracking switch_tracking = { .tids = NULL, };
+       struct record_opts opts = {
+               .mmap_pages          = UINT_MAX,
+               .user_freq           = UINT_MAX,
+               .user_interval       = ULLONG_MAX,
+               .freq                = 4000,
+               .target              = {
+                       .uses_mmap   = true,
+               },
+       };
+       struct thread_map *threads = NULL;
+       struct cpu_map *cpus = NULL;
+       struct perf_evlist *evlist = NULL;
+       struct perf_evsel *evsel, *cpu_clocks_evsel, *cycles_evsel;
+       struct perf_evsel *switch_evsel, *tracking_evsel;
+       const char *comm;
+       int err = -1;
+
+       threads = thread_map__new(-1, getpid(), UINT_MAX);
+       if (!threads) {
+               pr_debug("thread_map__new failed!\n");
+               goto out_err;
+       }
+
+       cpus = cpu_map__new(NULL);
+       if (!cpus) {
+               pr_debug("cpu_map__new failed!\n");
+               goto out_err;
+       }
+
+       evlist = perf_evlist__new();
+       if (!evlist) {
+               pr_debug("perf_evlist__new failed!\n");
+               goto out_err;
+       }
+
+       perf_evlist__set_maps(evlist, cpus, threads);
+
+       /* First event */
+       err = parse_events(evlist, "cpu-clock:u");
+       if (err) {
+               pr_debug("Failed to parse event dummy:u\n");
+               goto out_err;
+       }
+
+       cpu_clocks_evsel = perf_evlist__last(evlist);
+
+       /* Second event */
+       err = parse_events(evlist, "cycles:u");
+       if (err) {
+               pr_debug("Failed to parse event cycles:u\n");
+               goto out_err;
+       }
+
+       cycles_evsel = perf_evlist__last(evlist);
+
+       /* Third event */
+       if (!perf_evlist__can_select_event(evlist, sched_switch)) {
+               fprintf(stderr, " (no sched_switch)");
+               err = 0;
+               goto out;
+       }
+
+       err = parse_events(evlist, sched_switch);
+       if (err) {
+               pr_debug("Failed to parse event %s\n", sched_switch);
+               goto out_err;
+       }
+
+       switch_evsel = perf_evlist__last(evlist);
+
+       perf_evsel__set_sample_bit(switch_evsel, CPU);
+       perf_evsel__set_sample_bit(switch_evsel, TIME);
+
+       switch_evsel->system_wide = true;
+       switch_evsel->no_aux_samples = true;
+       switch_evsel->immediate = true;
+
+       /* Test moving an event to the front */
+       if (cycles_evsel == perf_evlist__first(evlist)) {
+               pr_debug("cycles event already at front");
+               goto out_err;
+       }
+       perf_evlist__to_front(evlist, cycles_evsel);
+       if (cycles_evsel != perf_evlist__first(evlist)) {
+               pr_debug("Failed to move cycles event to front");
+               goto out_err;
+       }
+
+       perf_evsel__set_sample_bit(cycles_evsel, CPU);
+       perf_evsel__set_sample_bit(cycles_evsel, TIME);
+
+       /* Fourth event */
+       err = parse_events(evlist, "dummy:u");
+       if (err) {
+               pr_debug("Failed to parse event dummy:u\n");
+               goto out_err;
+       }
+
+       tracking_evsel = perf_evlist__last(evlist);
+
+       perf_evlist__set_tracking_event(evlist, tracking_evsel);
+
+       tracking_evsel->attr.freq = 0;
+       tracking_evsel->attr.sample_period = 1;
+
+       perf_evsel__set_sample_bit(tracking_evsel, TIME);
+
+       /* Config events */
+       perf_evlist__config(evlist, &opts);
+
+       /* Check moved event is still at the front */
+       if (cycles_evsel != perf_evlist__first(evlist)) {
+               pr_debug("Front event no longer at front");
+               goto out_err;
+       }
+
+       /* Check tracking event is tracking */
+       if (!tracking_evsel->attr.mmap || !tracking_evsel->attr.comm) {
+               pr_debug("Tracking event not tracking\n");
+               goto out_err;
+       }
+
+       /* Check non-tracking events are not tracking */
+       evlist__for_each(evlist, evsel) {
+               if (evsel != tracking_evsel) {
+                       if (evsel->attr.mmap || evsel->attr.comm) {
+                               pr_debug("Non-tracking event is tracking\n");
+                               goto out_err;
+                       }
+               }
+       }
+
+       if (perf_evlist__open(evlist) < 0) {
+               fprintf(stderr, " (not supported)");
+               err = 0;
+               goto out;
+       }
+
+       err = perf_evlist__mmap(evlist, UINT_MAX, false);
+       if (err) {
+               pr_debug("perf_evlist__mmap failed!\n");
+               goto out_err;
+       }
+
+       perf_evlist__enable(evlist);
+
+       err = perf_evlist__disable_event(evlist, cpu_clocks_evsel);
+       if (err) {
+               pr_debug("perf_evlist__disable_event failed!\n");
+               goto out_err;
+       }
+
+       err = spin_sleep();
+       if (err) {
+               pr_debug("spin_sleep failed!\n");
+               goto out_err;
+       }
+
+       comm = "Test COMM 1";
+       err = prctl(PR_SET_NAME, (unsigned long)comm, 0, 0, 0);
+       if (err) {
+               pr_debug("PR_SET_NAME failed!\n");
+               goto out_err;
+       }
+
+       err = perf_evlist__disable_event(evlist, cycles_evsel);
+       if (err) {
+               pr_debug("perf_evlist__disable_event failed!\n");
+               goto out_err;
+       }
+
+       comm = "Test COMM 2";
+       err = prctl(PR_SET_NAME, (unsigned long)comm, 0, 0, 0);
+       if (err) {
+               pr_debug("PR_SET_NAME failed!\n");
+               goto out_err;
+       }
+
+       err = spin_sleep();
+       if (err) {
+               pr_debug("spin_sleep failed!\n");
+               goto out_err;
+       }
+
+       comm = "Test COMM 3";
+       err = prctl(PR_SET_NAME, (unsigned long)comm, 0, 0, 0);
+       if (err) {
+               pr_debug("PR_SET_NAME failed!\n");
+               goto out_err;
+       }
+
+       err = perf_evlist__enable_event(evlist, cycles_evsel);
+       if (err) {
+               pr_debug("perf_evlist__disable_event failed!\n");
+               goto out_err;
+       }
+
+       comm = "Test COMM 4";
+       err = prctl(PR_SET_NAME, (unsigned long)comm, 0, 0, 0);
+       if (err) {
+               pr_debug("PR_SET_NAME failed!\n");
+               goto out_err;
+       }
+
+       err = spin_sleep();
+       if (err) {
+               pr_debug("spin_sleep failed!\n");
+               goto out_err;
+       }
+
+       perf_evlist__disable(evlist);
+
+       switch_tracking.switch_evsel = switch_evsel;
+       switch_tracking.cycles_evsel = cycles_evsel;
+
+       err = process_events(evlist, &switch_tracking);
+
+       zfree(&switch_tracking.tids);
+
+       if (err)
+               goto out_err;
+
+       /* Check all 4 comm events were seen i.e. that evsel->tracking works */
+       if (!switch_tracking.comm_seen[0] || !switch_tracking.comm_seen[1] ||
+           !switch_tracking.comm_seen[2] || !switch_tracking.comm_seen[3]) {
+               pr_debug("Missing comm events\n");
+               goto out_err;
+       }
+
+       /* Check cycles event got enabled */
+       if (!switch_tracking.cycles_before_comm_1) {
+               pr_debug("Missing cycles events\n");
+               goto out_err;
+       }
+
+       /* Check cycles event got disabled */
+       if (switch_tracking.cycles_between_comm_2_and_comm_3) {
+               pr_debug("cycles events even though event was disabled\n");
+               goto out_err;
+       }
+
+       /* Check cycles event got enabled again */
+       if (!switch_tracking.cycles_after_comm_4) {
+               pr_debug("Missing cycles events\n");
+               goto out_err;
+       }
+out:
+       if (evlist) {
+               perf_evlist__disable(evlist);
+               perf_evlist__delete(evlist);
+       } else {
+               cpu_map__delete(cpus);
+               thread_map__delete(threads);
+       }
+
+       return err;
+
+out_err:
+       err = -1;
+       goto out;
+}
index 5ff3db318f12ae5971d3916fc49599e14fd51075..3a8fedef83bc086e5328dea03dcf6107d3ff1e39 100644 (file)
@@ -42,6 +42,7 @@ int test__task_exit(void)
                .uses_mmap      = true,
        };
        const char *argv[] = { "true", NULL };
+       char sbuf[STRERR_BUFSIZE];
 
        signal(SIGCHLD, sig_handler);
 
@@ -82,13 +83,14 @@ int test__task_exit(void)
 
        err = perf_evlist__open(evlist);
        if (err < 0) {
-               pr_debug("Couldn't open the evlist: %s\n", strerror(-err));
+               pr_debug("Couldn't open the evlist: %s\n",
+                        strerror_r(-err, sbuf, sizeof(sbuf)));
                goto out_delete_evlist;
        }
 
        if (perf_evlist__mmap(evlist, 128, true) < 0) {
                pr_debug("failed to mmap events: %d (%s)\n", errno,
-                        strerror(errno));
+                        strerror_r(errno, sbuf, sizeof(sbuf)));
                goto out_delete_evlist;
        }
 
@@ -103,7 +105,7 @@ retry:
        }
 
        if (!exited || !nr_exit) {
-               poll(evlist->pollfd, evlist->nr_fds, -1);
+               perf_evlist__poll(evlist, -1);
                goto retry;
        }
 
index ed64790a395f16093748e2c199b9369665a3c316..00e776a87a9c76e3821953fcd203c1df59189e25 100644 (file)
@@ -48,6 +48,9 @@ int test__mmap_thread_lookup(void);
 int test__thread_mg_share(void);
 int test__hists_output(void);
 int test__hists_cumulate(void);
+int test__switch_tracking(void);
+int test__fdarray__filter(void);
+int test__fdarray__add(void);
 
 #if defined(__x86_64__) || defined(__i386__) || defined(__arm__)
 #ifdef HAVE_DWARF_UNWIND_SUPPORT
index a94b11fc5e00263bd1adf50a456925fbc895d5aa..8f60a970404f8e82ed009fc2847945590581fde6 100644 (file)
@@ -10,6 +10,7 @@
 #include "../../util/pstack.h"
 #include "../../util/sort.h"
 #include "../../util/util.h"
+#include "../../util/top.h"
 #include "../../arch/common.h"
 
 #include "../browser.h"
@@ -228,8 +229,10 @@ static void callchain_node__init_have_children(struct callchain_node *node)
 {
        struct callchain_list *chain;
 
-       list_for_each_entry(chain, &node->val, list)
+       if (!list_empty(&node->val)) {
+               chain = list_entry(node->val.prev, struct callchain_list, list);
                chain->ms.has_children = !RB_EMPTY_ROOT(&node->rb_root);
+       }
 
        callchain_node__init_have_children_rb_tree(node);
 }
@@ -474,26 +477,87 @@ static char *callchain_list__sym_name(struct callchain_list *cl,
        return bf;
 }
 
+struct callchain_print_arg {
+       /* for hists browser */
+       off_t   row_offset;
+       bool    is_current_entry;
+
+       /* for file dump */
+       FILE    *fp;
+       int     printed;
+};
+
+typedef void (*print_callchain_entry_fn)(struct hist_browser *browser,
+                                        struct callchain_list *chain,
+                                        const char *str, int offset,
+                                        unsigned short row,
+                                        struct callchain_print_arg *arg);
+
+static void hist_browser__show_callchain_entry(struct hist_browser *browser,
+                                              struct callchain_list *chain,
+                                              const char *str, int offset,
+                                              unsigned short row,
+                                              struct callchain_print_arg *arg)
+{
+       int color, width;
+       char folded_sign = callchain_list__folded(chain);
+
+       color = HE_COLORSET_NORMAL;
+       width = browser->b.width - (offset + 2);
+       if (ui_browser__is_current_entry(&browser->b, row)) {
+               browser->selection = &chain->ms;
+               color = HE_COLORSET_SELECTED;
+               arg->is_current_entry = true;
+       }
+
+       ui_browser__set_color(&browser->b, color);
+       hist_browser__gotorc(browser, row, 0);
+       slsmg_write_nstring(" ", offset);
+       slsmg_printf("%c ", folded_sign);
+       slsmg_write_nstring(str, width);
+}
+
+static void hist_browser__fprintf_callchain_entry(struct hist_browser *b __maybe_unused,
+                                                 struct callchain_list *chain,
+                                                 const char *str, int offset,
+                                                 unsigned short row __maybe_unused,
+                                                 struct callchain_print_arg *arg)
+{
+       char folded_sign = callchain_list__folded(chain);
+
+       arg->printed += fprintf(arg->fp, "%*s%c %s\n", offset, " ",
+                               folded_sign, str);
+}
+
+typedef bool (*check_output_full_fn)(struct hist_browser *browser,
+                                    unsigned short row);
+
+static bool hist_browser__check_output_full(struct hist_browser *browser,
+                                           unsigned short row)
+{
+       return browser->b.rows == row;
+}
+
+static bool hist_browser__check_dump_full(struct hist_browser *browser __maybe_unused,
+                                         unsigned short row __maybe_unused)
+{
+       return false;
+}
+
 #define LEVEL_OFFSET_STEP 3
 
-static int hist_browser__show_callchain_node_rb_tree(struct hist_browser *browser,
-                                                    struct callchain_node *chain_node,
-                                                    u64 total, int level,
-                                                    unsigned short row,
-                                                    off_t *row_offset,
-                                                    bool *is_current_entry)
+static int hist_browser__show_callchain(struct hist_browser *browser,
+                                       struct rb_root *root, int level,
+                                       unsigned short row, u64 total,
+                                       print_callchain_entry_fn print,
+                                       struct callchain_print_arg *arg,
+                                       check_output_full_fn is_output_full)
 {
        struct rb_node *node;
-       int first_row = row, width, offset = level * LEVEL_OFFSET_STEP;
-       u64 new_total, remaining;
+       int first_row = row, offset = level * LEVEL_OFFSET_STEP;
+       u64 new_total;
 
-       if (callchain_param.mode == CHAIN_GRAPH_REL)
-               new_total = chain_node->children_hit;
-       else
-               new_total = total;
-
-       remaining = new_total;
-       node = rb_first(&chain_node->rb_root);
+       node = rb_first(root);
        while (node) {
                struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node);
                struct rb_node *next = rb_next(node);
@@ -503,30 +567,28 @@ static int hist_browser__show_callchain_node_rb_tree(struct hist_browser *browse
                int first = true;
                int extra_offset = 0;
 
-               remaining -= cumul;
-
                list_for_each_entry(chain, &child->val, list) {
                        char bf[1024], *alloc_str;
                        const char *str;
-                       int color;
                        bool was_first = first;
 
                        if (first)
                                first = false;
-                       else
+                       else if (level > 1)
                                extra_offset = LEVEL_OFFSET_STEP;
 
                        folded_sign = callchain_list__folded(chain);
-                       if (*row_offset != 0) {
-                               --*row_offset;
+                       if (arg->row_offset != 0) {
+                               arg->row_offset--;
                                goto do_next;
                        }
 
                        alloc_str = NULL;
                        str = callchain_list__sym_name(chain, bf, sizeof(bf),
                                                       browser->show_dso);
-                       if (was_first) {
-                               double percent = cumul * 100.0 / new_total;
+
+                       if (was_first && level > 1) {
+                               double percent = cumul * 100.0 / total;
 
                                if (asprintf(&alloc_str, "%2.2f%% %s", percent, str) < 0)
                                        str = "Not enough memory!";
@@ -534,22 +596,11 @@ static int hist_browser__show_callchain_node_rb_tree(struct hist_browser *browse
                                        str = alloc_str;
                        }
 
-                       color = HE_COLORSET_NORMAL;
-                       width = browser->b.width - (offset + extra_offset + 2);
-                       if (ui_browser__is_current_entry(&browser->b, row)) {
-                               browser->selection = &chain->ms;
-                               color = HE_COLORSET_SELECTED;
-                               *is_current_entry = true;
-                       }
+                       print(browser, chain, str, offset + extra_offset, row, arg);
 
-                       ui_browser__set_color(&browser->b, color);
-                       hist_browser__gotorc(browser, row, 0);
-                       slsmg_write_nstring(" ", offset + extra_offset);
-                       slsmg_printf("%c ", folded_sign);
-                       slsmg_write_nstring(str, width);
                        free(alloc_str);
 
-                       if (++row == browser->b.rows)
+                       if (is_output_full(browser, ++row))
                                goto out;
 do_next:
                        if (folded_sign == '+')
@@ -558,89 +609,21 @@ do_next:
 
                if (folded_sign == '-') {
                        const int new_level = level + (extra_offset ? 2 : 1);
-                       row += hist_browser__show_callchain_node_rb_tree(browser, child, new_total,
-                                                                        new_level, row, row_offset,
-                                                                        is_current_entry);
-               }
-               if (row == browser->b.rows)
-                       goto out;
-               node = next;
-       }
-out:
-       return row - first_row;
-}
-
-static int hist_browser__show_callchain_node(struct hist_browser *browser,
-                                            struct callchain_node *node,
-                                            int level, unsigned short row,
-                                            off_t *row_offset,
-                                            bool *is_current_entry)
-{
-       struct callchain_list *chain;
-       int first_row = row,
-            offset = level * LEVEL_OFFSET_STEP,
-            width = browser->b.width - offset;
-       char folded_sign = ' ';
 
-       list_for_each_entry(chain, &node->val, list) {
-               char bf[1024], *s;
-               int color;
-
-               folded_sign = callchain_list__folded(chain);
-
-               if (*row_offset != 0) {
-                       --*row_offset;
-                       continue;
-               }
+                       if (callchain_param.mode == CHAIN_GRAPH_REL)
+                               new_total = child->children_hit;
+                       else
+                               new_total = total;
 
-               color = HE_COLORSET_NORMAL;
-               if (ui_browser__is_current_entry(&browser->b, row)) {
-                       browser->selection = &chain->ms;
-                       color = HE_COLORSET_SELECTED;
-                       *is_current_entry = true;
+                       row += hist_browser__show_callchain(browser, &child->rb_root,
+                                                           new_level, row, new_total,
+                                                           print, arg, is_output_full);
                }
-
-               s = callchain_list__sym_name(chain, bf, sizeof(bf),
-                                            browser->show_dso);
-               hist_browser__gotorc(browser, row, 0);
-               ui_browser__set_color(&browser->b, color);
-               slsmg_write_nstring(" ", offset);
-               slsmg_printf("%c ", folded_sign);
-               slsmg_write_nstring(s, width - 2);
-
-               if (++row == browser->b.rows)
-                       goto out;
-       }
-
-       if (folded_sign == '-')
-               row += hist_browser__show_callchain_node_rb_tree(browser, node,
-                                                                browser->hists->stats.total_period,
-                                                                level + 1, row,
-                                                                row_offset,
-                                                                is_current_entry);
-out:
-       return row - first_row;
-}
-
-static int hist_browser__show_callchain(struct hist_browser *browser,
-                                       struct rb_root *chain,
-                                       int level, unsigned short row,
-                                       off_t *row_offset,
-                                       bool *is_current_entry)
-{
-       struct rb_node *nd;
-       int first_row = row;
-
-       for (nd = rb_first(chain); nd; nd = rb_next(nd)) {
-               struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
-
-               row += hist_browser__show_callchain_node(browser, node, level,
-                                                        row, row_offset,
-                                                        is_current_entry);
-               if (row == browser->b.rows)
+               if (is_output_full(browser, row))
                        break;
+               node = next;
        }
-
+out:
        return row - first_row;
 }
 
@@ -653,17 +636,18 @@ struct hpp_arg {
 static int __hpp__slsmg_color_printf(struct perf_hpp *hpp, const char *fmt, ...)
 {
        struct hpp_arg *arg = hpp->ptr;
-       int ret;
+       int ret, len;
        va_list args;
        double percent;
 
        va_start(args, fmt);
+       len = va_arg(args, int);
        percent = va_arg(args, double);
        va_end(args);
 
        ui_browser__set_percent_color(arg->b, percent, arg->current_entry);
 
-       ret = scnprintf(hpp->buf, hpp->size, fmt, percent);
+       ret = scnprintf(hpp->buf, hpp->size, fmt, len, percent);
        slsmg_printf("%s", hpp->buf);
 
        advance_hpp(hpp, ret);
@@ -677,12 +661,12 @@ static u64 __hpp_get_##_field(struct hist_entry *he)                      \
 }                                                                      \
                                                                        \
 static int                                                             \
-hist_browser__hpp_color_##_type(struct perf_hpp_fmt *fmt __maybe_unused,\
+hist_browser__hpp_color_##_type(struct perf_hpp_fmt *fmt,              \
                                struct perf_hpp *hpp,                   \
                                struct hist_entry *he)                  \
 {                                                                      \
-       return __hpp__fmt(hpp, he, __hpp_get_##_field, " %6.2f%%",      \
-                         __hpp__slsmg_color_printf, true);             \
+       return hpp__fmt(fmt, hpp, he, __hpp_get_##_field, " %*.2f%%",   \
+                       __hpp__slsmg_color_printf, true);               \
 }
 
 #define __HPP_COLOR_ACC_PERCENT_FN(_type, _field)                      \
@@ -692,18 +676,20 @@ static u64 __hpp_get_acc_##_field(struct hist_entry *he)          \
 }                                                                      \
                                                                        \
 static int                                                             \
-hist_browser__hpp_color_##_type(struct perf_hpp_fmt *fmt __maybe_unused,\
+hist_browser__hpp_color_##_type(struct perf_hpp_fmt *fmt,              \
                                struct perf_hpp *hpp,                   \
                                struct hist_entry *he)                  \
 {                                                                      \
        if (!symbol_conf.cumulate_callchain) {                          \
-               int ret = scnprintf(hpp->buf, hpp->size, "%8s", "N/A"); \
+               int len = fmt->user_len ?: fmt->len;                    \
+               int ret = scnprintf(hpp->buf, hpp->size,                \
+                                   "%*s", len, "N/A");                 \
                slsmg_printf("%s", hpp->buf);                           \
                                                                        \
                return ret;                                             \
        }                                                               \
-       return __hpp__fmt(hpp, he, __hpp_get_acc_##_field, " %6.2f%%",  \
-                         __hpp__slsmg_color_printf, true);             \
+       return hpp__fmt(fmt, hpp, he, __hpp_get_acc_##_field,           \
+                       " %*.2f%%", __hpp__slsmg_color_printf, true);   \
 }
 
 __HPP_COLOR_PERCENT_FN(overhead, period)
@@ -812,10 +798,18 @@ static int hist_browser__show_entry(struct hist_browser *browser,
                --row_offset;
 
        if (folded_sign == '-' && row != browser->b.rows) {
-               printed += hist_browser__show_callchain(browser, &entry->sorted_chain,
-                                                       1, row, &row_offset,
-                                                       &current_entry);
-               if (current_entry)
+               u64 total = hists__total_period(entry->hists);
+               struct callchain_print_arg arg = {
+                       .row_offset = row_offset,
+                       .is_current_entry = current_entry,
+               };
+
+               printed += hist_browser__show_callchain(browser,
+                                       &entry->sorted_chain, 1, row, total,
+                                       hist_browser__show_callchain_entry, &arg,
+                                       hist_browser__check_output_full);
+
+               if (arg.is_current_entry)
                        browser->he_selection = entry;
        }
 
@@ -847,9 +841,6 @@ static int hists__scnprintf_headers(char *buf, size_t size, struct hists *hists)
                if (perf_hpp__should_skip(fmt))
                        continue;
 
-               /* We need to add the length of the columns header. */
-               perf_hpp__reset_width(fmt, hists);
-
                ret = fmt->header(fmt, &dummy_hpp, hists_to_evsel(hists));
                if (advance_hpp_check(&dummy_hpp, ret))
                        break;
@@ -1074,113 +1065,21 @@ do_offset:
        }
 }
 
-static int hist_browser__fprintf_callchain_node_rb_tree(struct hist_browser *browser,
-                                                       struct callchain_node *chain_node,
-                                                       u64 total, int level,
-                                                       FILE *fp)
-{
-       struct rb_node *node;
-       int offset = level * LEVEL_OFFSET_STEP;
-       u64 new_total, remaining;
-       int printed = 0;
-
-       if (callchain_param.mode == CHAIN_GRAPH_REL)
-               new_total = chain_node->children_hit;
-       else
-               new_total = total;
-
-       remaining = new_total;
-       node = rb_first(&chain_node->rb_root);
-       while (node) {
-               struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node);
-               struct rb_node *next = rb_next(node);
-               u64 cumul = callchain_cumul_hits(child);
-               struct callchain_list *chain;
-               char folded_sign = ' ';
-               int first = true;
-               int extra_offset = 0;
-
-               remaining -= cumul;
-
-               list_for_each_entry(chain, &child->val, list) {
-                       char bf[1024], *alloc_str;
-                       const char *str;
-                       bool was_first = first;
-
-                       if (first)
-                               first = false;
-                       else
-                               extra_offset = LEVEL_OFFSET_STEP;
-
-                       folded_sign = callchain_list__folded(chain);
-
-                       alloc_str = NULL;
-                       str = callchain_list__sym_name(chain, bf, sizeof(bf),
-                                                      browser->show_dso);
-                       if (was_first) {
-                               double percent = cumul * 100.0 / new_total;
-
-                               if (asprintf(&alloc_str, "%2.2f%% %s", percent, str) < 0)
-                                       str = "Not enough memory!";
-                               else
-                                       str = alloc_str;
-                       }
-
-                       printed += fprintf(fp, "%*s%c %s\n", offset + extra_offset, " ", folded_sign, str);
-                       free(alloc_str);
-                       if (folded_sign == '+')
-                               break;
-               }
-
-               if (folded_sign == '-') {
-                       const int new_level = level + (extra_offset ? 2 : 1);
-                       printed += hist_browser__fprintf_callchain_node_rb_tree(browser, child, new_total,
-                                                                               new_level, fp);
-               }
-
-               node = next;
-       }
-
-       return printed;
-}
-
-static int hist_browser__fprintf_callchain_node(struct hist_browser *browser,
-                                               struct callchain_node *node,
-                                               int level, FILE *fp)
-{
-       struct callchain_list *chain;
-       int offset = level * LEVEL_OFFSET_STEP;
-       char folded_sign = ' ';
-       int printed = 0;
-
-       list_for_each_entry(chain, &node->val, list) {
-               char bf[1024], *s;
-
-               folded_sign = callchain_list__folded(chain);
-               s = callchain_list__sym_name(chain, bf, sizeof(bf), browser->show_dso);
-               printed += fprintf(fp, "%*s%c %s\n", offset, " ", folded_sign, s);
-       }
-
-       if (folded_sign == '-')
-               printed += hist_browser__fprintf_callchain_node_rb_tree(browser, node,
-                                                                       browser->hists->stats.total_period,
-                                                                       level + 1,  fp);
-       return printed;
-}
-
 static int hist_browser__fprintf_callchain(struct hist_browser *browser,
-                                          struct rb_root *chain, int level, FILE *fp)
+                                          struct hist_entry *he, FILE *fp)
 {
-       struct rb_node *nd;
-       int printed = 0;
+       u64 total = hists__total_period(he->hists);
+       struct callchain_print_arg arg  = {
+               .fp = fp,
+       };
 
-       for (nd = rb_first(chain); nd; nd = rb_next(nd)) {
-               struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
+       if (symbol_conf.cumulate_callchain)
+               total = he->stat_acc->period;
 
-               printed += hist_browser__fprintf_callchain_node(browser, node, level, fp);
-       }
-
-       return printed;
+       hist_browser__show_callchain(browser, &he->sorted_chain, 1, 0, total,
+                                    hist_browser__fprintf_callchain_entry, &arg,
+                                    hist_browser__check_dump_full);
+       return arg.printed;
 }
 
 static int hist_browser__fprintf_entry(struct hist_browser *browser,
@@ -1219,7 +1118,7 @@ static int hist_browser__fprintf_entry(struct hist_browser *browser,
        printed += fprintf(fp, "%s\n", rtrim(s));
 
        if (folded_sign == '-')
-               printed += hist_browser__fprintf_callchain(browser, &he->sorted_chain, 1, fp);
+               printed += hist_browser__fprintf_callchain(browser, he, fp);
 
        return printed;
 }
@@ -1498,6 +1397,7 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
        char buf[64];
        char script_opt[64];
        int delay_secs = hbt ? hbt->refresh : 0;
+       struct perf_hpp_fmt *fmt;
 
 #define HIST_BROWSER_HELP_COMMON                                       \
        "h/?/F1        Show this window\n"                              \
@@ -1529,6 +1429,7 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
        "P             Print histograms to perf.hist.N\n"
        "t             Zoom into current Thread\n"
        "V             Verbose (DSO names in callchains, etc)\n"
+       "z             Toggle zeroing of samples\n"
        "/             Filter symbol by name";
 
        if (browser == NULL)
@@ -1547,6 +1448,12 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
 
        memset(options, 0, sizeof(options));
 
+       perf_hpp__for_each_format(fmt)
+               perf_hpp__reset_width(fmt, hists);
+
+       if (symbol_conf.col_width_list_str)
+               perf_hpp__set_user_width(symbol_conf.col_width_list_str);
+
        while (1) {
                const struct thread *thread = NULL;
                const struct dso *dso = NULL;
@@ -1623,6 +1530,13 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
                case 'F':
                        symbol_conf.filter_relative ^= 1;
                        continue;
+               case 'z':
+                       if (!is_report_browser(hbt)) {
+                               struct perf_top *top = hbt->arg;
+
+                               top->zero = !top->zero;
+                       }
+                       continue;
                case K_F1:
                case 'h':
                case '?':
index 6ca60e482cdc2594382466bbaecdde12462dfbec..f3fa4258b256b9d3a8c4fb9f570172d96cca47f8 100644 (file)
@@ -11,6 +11,7 @@
 static int __percent_color_snprintf(struct perf_hpp *hpp, const char *fmt, ...)
 {
        int ret = 0;
+       int len;
        va_list args;
        double percent;
        const char *markup;
@@ -18,6 +19,7 @@ static int __percent_color_snprintf(struct perf_hpp *hpp, const char *fmt, ...)
        size_t size = hpp->size;
 
        va_start(args, fmt);
+       len = va_arg(args, int);
        percent = va_arg(args, double);
        va_end(args);
 
@@ -25,7 +27,7 @@ static int __percent_color_snprintf(struct perf_hpp *hpp, const char *fmt, ...)
        if (markup)
                ret += scnprintf(buf, size, markup);
 
-       ret += scnprintf(buf + ret, size - ret, fmt, percent);
+       ret += scnprintf(buf + ret, size - ret, fmt, len, percent);
 
        if (markup)
                ret += scnprintf(buf + ret, size - ret, "</span>");
@@ -39,12 +41,12 @@ static u64 he_get_##_field(struct hist_entry *he)                           \
        return he->stat._field;                                                 \
 }                                                                              \
                                                                                \
-static int perf_gtk__hpp_color_##_type(struct perf_hpp_fmt *fmt __maybe_unused,        \
+static int perf_gtk__hpp_color_##_type(struct perf_hpp_fmt *fmt,               \
                                       struct perf_hpp *hpp,                    \
                                       struct hist_entry *he)                   \
 {                                                                              \
-       return __hpp__fmt(hpp, he, he_get_##_field, " %6.2f%%",                 \
-                         __percent_color_snprintf, true);                      \
+       return hpp__fmt(fmt, hpp, he, he_get_##_field, " %*.2f%%",              \
+                       __percent_color_snprintf, true);                        \
 }
 
 #define __HPP_COLOR_ACC_PERCENT_FN(_type, _field)                              \
@@ -57,8 +59,8 @@ static int perf_gtk__hpp_color_##_type(struct perf_hpp_fmt *fmt __maybe_unused,
                                       struct perf_hpp *hpp,                    \
                                       struct hist_entry *he)                   \
 {                                                                              \
-       return __hpp__fmt_acc(hpp, he, he_get_acc_##_field, " %6.2f%%",         \
-                             __percent_color_snprintf, true);                  \
+       return hpp__fmt_acc(fmt, hpp, he, he_get_acc_##_field, " %*.2f%%",      \
+                           __percent_color_snprintf, true);                    \
 }
 
 __HPP_COLOR_PERCENT_FN(overhead, period)
@@ -205,10 +207,8 @@ static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists,
                if (perf_hpp__is_sort_entry(fmt))
                        sym_col = col_idx;
 
-               fmt->header(fmt, &hpp, hists_to_evsel(hists));
-
                gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view),
-                                                           -1, ltrim(s),
+                                                           -1, fmt->name,
                                                            renderer, "markup",
                                                            col_idx++, NULL);
        }
index 498adb23c02ef9992f82c840aca5aa31220af9bf..2af18376b0772ea5094e1f6277afa343533a484c 100644 (file)
@@ -15,9 +15,9 @@
        __ret;                                                  \
 })
 
-int __hpp__fmt(struct perf_hpp *hpp, struct hist_entry *he,
-              hpp_field_fn get_field, const char *fmt,
-              hpp_snprint_fn print_fn, bool fmt_percent)
+static int __hpp__fmt(struct perf_hpp *hpp, struct hist_entry *he,
+                     hpp_field_fn get_field, const char *fmt, int len,
+                     hpp_snprint_fn print_fn, bool fmt_percent)
 {
        int ret;
        struct hists *hists = he->hists;
@@ -32,9 +32,9 @@ int __hpp__fmt(struct perf_hpp *hpp, struct hist_entry *he,
                if (total)
                        percent = 100.0 * get_field(he) / total;
 
-               ret = hpp__call_print_fn(hpp, print_fn, fmt, percent);
+               ret = hpp__call_print_fn(hpp, print_fn, fmt, len, percent);
        } else
-               ret = hpp__call_print_fn(hpp, print_fn, fmt, get_field(he));
+               ret = hpp__call_print_fn(hpp, print_fn, fmt, len, get_field(he));
 
        if (perf_evsel__is_group_event(evsel)) {
                int prev_idx, idx_delta;
@@ -60,19 +60,19 @@ int __hpp__fmt(struct perf_hpp *hpp, struct hist_entry *he,
                                 */
                                if (fmt_percent) {
                                        ret += hpp__call_print_fn(hpp, print_fn,
-                                                                 fmt, 0.0);
+                                                                 fmt, len, 0.0);
                                } else {
                                        ret += hpp__call_print_fn(hpp, print_fn,
-                                                                 fmt, 0ULL);
+                                                                 fmt, len, 0ULL);
                                }
                        }
 
                        if (fmt_percent) {
-                               ret += hpp__call_print_fn(hpp, print_fn, fmt,
+                               ret += hpp__call_print_fn(hpp, print_fn, fmt, len,
                                                          100.0 * period / total);
                        } else {
                                ret += hpp__call_print_fn(hpp, print_fn, fmt,
-                                                         period);
+                                                         len, period);
                        }
 
                        prev_idx = perf_evsel__group_idx(evsel);
@@ -86,10 +86,10 @@ int __hpp__fmt(struct perf_hpp *hpp, struct hist_entry *he,
                         */
                        if (fmt_percent) {
                                ret += hpp__call_print_fn(hpp, print_fn,
-                                                         fmt, 0.0);
+                                                         fmt, len, 0.0);
                        } else {
                                ret += hpp__call_print_fn(hpp, print_fn,
-                                                         fmt, 0ULL);
+                                                         fmt, len, 0ULL);
                        }
                }
        }
@@ -104,16 +104,35 @@ int __hpp__fmt(struct perf_hpp *hpp, struct hist_entry *he,
        return ret;
 }
 
-int __hpp__fmt_acc(struct perf_hpp *hpp, struct hist_entry *he,
-                  hpp_field_fn get_field, const char *fmt,
-                  hpp_snprint_fn print_fn, bool fmt_percent)
+int hpp__fmt(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
+            struct hist_entry *he, hpp_field_fn get_field,
+            const char *fmtstr, hpp_snprint_fn print_fn, bool fmt_percent)
+{
+       int len = fmt->user_len ?: fmt->len;
+
+       if (symbol_conf.field_sep) {
+               return __hpp__fmt(hpp, he, get_field, fmtstr, 1,
+                                 print_fn, fmt_percent);
+       }
+
+       if (fmt_percent)
+               len -= 2; /* 2 for a space and a % sign */
+       else
+               len -= 1;
+
+       return  __hpp__fmt(hpp, he, get_field, fmtstr, len, print_fn, fmt_percent);
+}
+
+int hpp__fmt_acc(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
+                struct hist_entry *he, hpp_field_fn get_field,
+                const char *fmtstr, hpp_snprint_fn print_fn, bool fmt_percent)
 {
        if (!symbol_conf.cumulate_callchain) {
-               return snprintf(hpp->buf, hpp->size, "%*s",
-                               fmt_percent ? 8 : 12, "N/A");
+               int len = fmt->user_len ?: fmt->len;
+               return snprintf(hpp->buf, hpp->size, " %*s", len - 1, "N/A");
        }
 
-       return __hpp__fmt(hpp, he, get_field, fmt, print_fn, fmt_percent);
+       return hpp__fmt(fmt, hpp, he, get_field, fmtstr, print_fn, fmt_percent);
 }
 
 static int field_cmp(u64 field_a, u64 field_b)
@@ -190,30 +209,26 @@ static int __hpp__sort_acc(struct hist_entry *a, struct hist_entry *b,
        return ret;
 }
 
-#define __HPP_HEADER_FN(_type, _str, _min_width, _unit_width)          \
-static int hpp__header_##_type(struct perf_hpp_fmt *fmt __maybe_unused,        \
-                              struct perf_hpp *hpp,                    \
-                              struct perf_evsel *evsel)                \
-{                                                                      \
-       int len = _min_width;                                           \
-                                                                       \
-       if (symbol_conf.event_group)                                    \
-               len = max(len, evsel->nr_members * _unit_width);        \
-                                                                       \
-       return scnprintf(hpp->buf, hpp->size, "%*s", len, _str);        \
-}
-
-#define __HPP_WIDTH_FN(_type, _min_width, _unit_width)                         \
-static int hpp__width_##_type(struct perf_hpp_fmt *fmt __maybe_unused, \
-                             struct perf_hpp *hpp __maybe_unused,      \
-                             struct perf_evsel *evsel)                 \
-{                                                                      \
-       int len = _min_width;                                           \
-                                                                       \
-       if (symbol_conf.event_group)                                    \
-               len = max(len, evsel->nr_members * _unit_width);        \
-                                                                       \
-       return len;                                                     \
+static int hpp__width_fn(struct perf_hpp_fmt *fmt,
+                        struct perf_hpp *hpp __maybe_unused,
+                        struct perf_evsel *evsel)
+{
+       int len = fmt->user_len ?: fmt->len;
+
+       if (symbol_conf.event_group)
+               len = max(len, evsel->nr_members * fmt->len);
+
+       if (len < (int)strlen(fmt->name))
+               len = strlen(fmt->name);
+
+       return len;
+}
+
+static int hpp__header_fn(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
+                         struct perf_evsel *evsel)
+{
+       int len = hpp__width_fn(fmt, hpp, evsel);
+       return scnprintf(hpp->buf, hpp->size, "%*s", len, fmt->name);
 }
 
 static int hpp_color_scnprintf(struct perf_hpp *hpp, const char *fmt, ...)
@@ -221,11 +236,12 @@ static int hpp_color_scnprintf(struct perf_hpp *hpp, const char *fmt, ...)
        va_list args;
        ssize_t ssize = hpp->size;
        double percent;
-       int ret;
+       int ret, len;
 
        va_start(args, fmt);
+       len = va_arg(args, int);
        percent = va_arg(args, double);
-       ret = value_color_snprintf(hpp->buf, hpp->size, fmt, percent);
+       ret = percent_color_len_snprintf(hpp->buf, hpp->size, fmt, len, percent);
        va_end(args);
 
        return (ret >= ssize) ? (ssize - 1) : ret;
@@ -250,20 +266,19 @@ static u64 he_get_##_field(struct hist_entry *he)                         \
        return he->stat._field;                                                 \
 }                                                                              \
                                                                                \
-static int hpp__color_##_type(struct perf_hpp_fmt *fmt __maybe_unused,         \
+static int hpp__color_##_type(struct perf_hpp_fmt *fmt,                                \
                              struct perf_hpp *hpp, struct hist_entry *he)      \
 {                                                                              \
-       return __hpp__fmt(hpp, he, he_get_##_field, " %6.2f%%",                 \
-                         hpp_color_scnprintf, true);                           \
+       return hpp__fmt(fmt, hpp, he, he_get_##_field, " %*.2f%%",              \
+                       hpp_color_scnprintf, true);                             \
 }
 
 #define __HPP_ENTRY_PERCENT_FN(_type, _field)                                  \
-static int hpp__entry_##_type(struct perf_hpp_fmt *_fmt __maybe_unused,                \
+static int hpp__entry_##_type(struct perf_hpp_fmt *fmt,                                \
                              struct perf_hpp *hpp, struct hist_entry *he)      \
 {                                                                              \
-       const char *fmt = symbol_conf.field_sep ? " %.2f" : " %6.2f%%";         \
-       return __hpp__fmt(hpp, he, he_get_##_field, fmt,                        \
-                         hpp_entry_scnprintf, true);                           \
+       return hpp__fmt(fmt, hpp, he, he_get_##_field, " %*.2f%%",              \
+                       hpp_entry_scnprintf, true);                             \
 }
 
 #define __HPP_SORT_FN(_type, _field)                                           \
@@ -278,20 +293,19 @@ static u64 he_get_acc_##_field(struct hist_entry *he)                             \
        return he->stat_acc->_field;                                            \
 }                                                                              \
                                                                                \
-static int hpp__color_##_type(struct perf_hpp_fmt *fmt __maybe_unused,         \
+static int hpp__color_##_type(struct perf_hpp_fmt *fmt,                                \
                              struct perf_hpp *hpp, struct hist_entry *he)      \
 {                                                                              \
-       return __hpp__fmt_acc(hpp, he, he_get_acc_##_field, " %6.2f%%",         \
-                             hpp_color_scnprintf, true);                       \
+       return hpp__fmt_acc(fmt, hpp, he, he_get_acc_##_field, " %*.2f%%",      \
+                           hpp_color_scnprintf, true);                         \
 }
 
 #define __HPP_ENTRY_ACC_PERCENT_FN(_type, _field)                              \
-static int hpp__entry_##_type(struct perf_hpp_fmt *_fmt __maybe_unused,                \
+static int hpp__entry_##_type(struct perf_hpp_fmt *fmt,                                \
                              struct perf_hpp *hpp, struct hist_entry *he)      \
 {                                                                              \
-       const char *fmt = symbol_conf.field_sep ? " %.2f" : " %6.2f%%";         \
-       return __hpp__fmt_acc(hpp, he, he_get_acc_##_field, fmt,                \
-                             hpp_entry_scnprintf, true);                       \
+       return hpp__fmt_acc(fmt, hpp, he, he_get_acc_##_field, " %*.2f%%",      \
+                           hpp_entry_scnprintf, true);                         \
 }
 
 #define __HPP_SORT_ACC_FN(_type, _field)                                       \
@@ -306,12 +320,11 @@ static u64 he_get_raw_##_field(struct hist_entry *he)                             \
        return he->stat._field;                                                 \
 }                                                                              \
                                                                                \
-static int hpp__entry_##_type(struct perf_hpp_fmt *_fmt __maybe_unused,                \
+static int hpp__entry_##_type(struct perf_hpp_fmt *fmt,                                \
                              struct perf_hpp *hpp, struct hist_entry *he)      \
 {                                                                              \
-       const char *fmt = symbol_conf.field_sep ? " %"PRIu64 : " %11"PRIu64;    \
-       return __hpp__fmt(hpp, he, he_get_raw_##_field, fmt,                    \
-                         hpp_entry_scnprintf, false);                          \
+       return hpp__fmt(fmt, hpp, he, he_get_raw_##_field, " %*"PRIu64,         \
+                       hpp_entry_scnprintf, false);                            \
 }
 
 #define __HPP_SORT_RAW_FN(_type, _field)                                       \
@@ -321,37 +334,29 @@ static int64_t hpp__sort_##_type(struct hist_entry *a, struct hist_entry *b)      \
 }
 
 
-#define HPP_PERCENT_FNS(_type, _str, _field, _min_width, _unit_width)  \
-__HPP_HEADER_FN(_type, _str, _min_width, _unit_width)                  \
-__HPP_WIDTH_FN(_type, _min_width, _unit_width)                         \
+#define HPP_PERCENT_FNS(_type, _field)                                 \
 __HPP_COLOR_PERCENT_FN(_type, _field)                                  \
 __HPP_ENTRY_PERCENT_FN(_type, _field)                                  \
 __HPP_SORT_FN(_type, _field)
 
-#define HPP_PERCENT_ACC_FNS(_type, _str, _field, _min_width, _unit_width)\
-__HPP_HEADER_FN(_type, _str, _min_width, _unit_width)                  \
-__HPP_WIDTH_FN(_type, _min_width, _unit_width)                         \
+#define HPP_PERCENT_ACC_FNS(_type, _field)                             \
 __HPP_COLOR_ACC_PERCENT_FN(_type, _field)                              \
 __HPP_ENTRY_ACC_PERCENT_FN(_type, _field)                              \
 __HPP_SORT_ACC_FN(_type, _field)
 
-#define HPP_RAW_FNS(_type, _str, _field, _min_width, _unit_width)      \
-__HPP_HEADER_FN(_type, _str, _min_width, _unit_width)                  \
-__HPP_WIDTH_FN(_type, _min_width, _unit_width)                         \
+#define HPP_RAW_FNS(_type, _field)                                     \
 __HPP_ENTRY_RAW_FN(_type, _field)                                      \
 __HPP_SORT_RAW_FN(_type, _field)
 
-__HPP_HEADER_FN(overhead_self, "Self", 8, 8)
-
-HPP_PERCENT_FNS(overhead, "Overhead", period, 8, 8)
-HPP_PERCENT_FNS(overhead_sys, "sys", period_sys, 8, 8)
-HPP_PERCENT_FNS(overhead_us, "usr", period_us, 8, 8)
-HPP_PERCENT_FNS(overhead_guest_sys, "guest sys", period_guest_sys, 9, 8)
-HPP_PERCENT_FNS(overhead_guest_us, "guest usr", period_guest_us, 9, 8)
-HPP_PERCENT_ACC_FNS(overhead_acc, "Children", period, 8, 8)
+HPP_PERCENT_FNS(overhead, period)
+HPP_PERCENT_FNS(overhead_sys, period_sys)
+HPP_PERCENT_FNS(overhead_us, period_us)
+HPP_PERCENT_FNS(overhead_guest_sys, period_guest_sys)
+HPP_PERCENT_FNS(overhead_guest_us, period_guest_us)
+HPP_PERCENT_ACC_FNS(overhead_acc, period)
 
-HPP_RAW_FNS(samples, "Samples", nr_events, 12, 12)
-HPP_RAW_FNS(period, "Period", period, 12, 12)
+HPP_RAW_FNS(samples, nr_events)
+HPP_RAW_FNS(period, period)
 
 static int64_t hpp__nop_cmp(struct hist_entry *a __maybe_unused,
                            struct hist_entry *b __maybe_unused)
@@ -359,47 +364,50 @@ static int64_t hpp__nop_cmp(struct hist_entry *a __maybe_unused,
        return 0;
 }
 
-#define HPP__COLOR_PRINT_FNS(_name)                    \
+#define HPP__COLOR_PRINT_FNS(_name, _fn)               \
        {                                               \
-               .header = hpp__header_ ## _name,        \
-               .width  = hpp__width_ ## _name,         \
-               .color  = hpp__color_ ## _name,         \
-               .entry  = hpp__entry_ ## _name,         \
+               .name   = _name,                        \
+               .header = hpp__header_fn,               \
+               .width  = hpp__width_fn,                \
+               .color  = hpp__color_ ## _fn,           \
+               .entry  = hpp__entry_ ## _fn,           \
                .cmp    = hpp__nop_cmp,                 \
                .collapse = hpp__nop_cmp,               \
-               .sort   = hpp__sort_ ## _name,          \
+               .sort   = hpp__sort_ ## _fn,            \
        }
 
-#define HPP__COLOR_ACC_PRINT_FNS(_name)                        \
+#define HPP__COLOR_ACC_PRINT_FNS(_name, _fn)           \
        {                                               \
-               .header = hpp__header_ ## _name,        \
-               .width  = hpp__width_ ## _name,         \
-               .color  = hpp__color_ ## _name,         \
-               .entry  = hpp__entry_ ## _name,         \
+               .name   = _name,                        \
+               .header = hpp__header_fn,               \
+               .width  = hpp__width_fn,                \
+               .color  = hpp__color_ ## _fn,           \
+               .entry  = hpp__entry_ ## _fn,           \
                .cmp    = hpp__nop_cmp,                 \
                .collapse = hpp__nop_cmp,               \
-               .sort   = hpp__sort_ ## _name,          \
+               .sort   = hpp__sort_ ## _fn,            \
        }
 
-#define HPP__PRINT_FNS(_name)                          \
+#define HPP__PRINT_FNS(_name, _fn)                     \
        {                                               \
-               .header = hpp__header_ ## _name,        \
-               .width  = hpp__width_ ## _name,         \
-               .entry  = hpp__entry_ ## _name,         \
+               .name   = _name,                        \
+               .header = hpp__header_fn,               \
+               .width  = hpp__width_fn,                \
+               .entry  = hpp__entry_ ## _fn,           \
                .cmp    = hpp__nop_cmp,                 \
                .collapse = hpp__nop_cmp,               \
-               .sort   = hpp__sort_ ## _name,          \
+               .sort   = hpp__sort_ ## _fn,            \
        }
 
 struct perf_hpp_fmt perf_hpp__format[] = {
-       HPP__COLOR_PRINT_FNS(overhead),
-       HPP__COLOR_PRINT_FNS(overhead_sys),
-       HPP__COLOR_PRINT_FNS(overhead_us),
-       HPP__COLOR_PRINT_FNS(overhead_guest_sys),
-       HPP__COLOR_PRINT_FNS(overhead_guest_us),
-       HPP__COLOR_ACC_PRINT_FNS(overhead_acc),
-       HPP__PRINT_FNS(samples),
-       HPP__PRINT_FNS(period)
+       HPP__COLOR_PRINT_FNS("Overhead", overhead),
+       HPP__COLOR_PRINT_FNS("sys", overhead_sys),
+       HPP__COLOR_PRINT_FNS("usr", overhead_us),
+       HPP__COLOR_PRINT_FNS("guest sys", overhead_guest_sys),
+       HPP__COLOR_PRINT_FNS("guest usr", overhead_guest_us),
+       HPP__COLOR_ACC_PRINT_FNS("Children", overhead_acc),
+       HPP__PRINT_FNS("Samples", samples),
+       HPP__PRINT_FNS("Period", period)
 };
 
 LIST_HEAD(perf_hpp__list);
@@ -444,14 +452,12 @@ void perf_hpp__init(void)
        /*
         * If user specified field order, no need to setup default fields.
         */
-       if (field_order)
+       if (is_strict_order(field_order))
                return;
 
        if (symbol_conf.cumulate_callchain) {
                perf_hpp__column_enable(PERF_HPP__OVERHEAD_ACC);
-
-               perf_hpp__format[PERF_HPP__OVERHEAD].header =
-                                               hpp__header_overhead_self;
+               perf_hpp__format[PERF_HPP__OVERHEAD].name = "Self";
        }
 
        perf_hpp__column_enable(PERF_HPP__OVERHEAD);
@@ -513,11 +519,11 @@ void perf_hpp__column_disable(unsigned col)
 
 void perf_hpp__cancel_cumulate(void)
 {
-       if (field_order)
+       if (is_strict_order(field_order))
                return;
 
        perf_hpp__column_disable(PERF_HPP__OVERHEAD_ACC);
-       perf_hpp__format[PERF_HPP__OVERHEAD].header = hpp__header_overhead;
+       perf_hpp__format[PERF_HPP__OVERHEAD].name = "Overhead";
 }
 
 void perf_hpp__setup_output_field(void)
@@ -622,3 +628,59 @@ unsigned int hists__sort_list_width(struct hists *hists)
 
        return ret;
 }
+
+void perf_hpp__reset_width(struct perf_hpp_fmt *fmt, struct hists *hists)
+{
+       int idx;
+
+       if (perf_hpp__is_sort_entry(fmt))
+               return perf_hpp__reset_sort_width(fmt, hists);
+
+       for (idx = 0; idx < PERF_HPP__MAX_INDEX; idx++) {
+               if (fmt == &perf_hpp__format[idx])
+                       break;
+       }
+
+       if (idx == PERF_HPP__MAX_INDEX)
+               return;
+
+       switch (idx) {
+       case PERF_HPP__OVERHEAD:
+       case PERF_HPP__OVERHEAD_SYS:
+       case PERF_HPP__OVERHEAD_US:
+       case PERF_HPP__OVERHEAD_ACC:
+               fmt->len = 8;
+               break;
+
+       case PERF_HPP__OVERHEAD_GUEST_SYS:
+       case PERF_HPP__OVERHEAD_GUEST_US:
+               fmt->len = 9;
+               break;
+
+       case PERF_HPP__SAMPLES:
+       case PERF_HPP__PERIOD:
+               fmt->len = 12;
+               break;
+
+       default:
+               break;
+       }
+}
+
+void perf_hpp__set_user_width(const char *width_list_str)
+{
+       struct perf_hpp_fmt *fmt;
+       const char *ptr = width_list_str;
+
+       perf_hpp__for_each_format(fmt) {
+               char *p;
+
+               int len = strtol(ptr, &p, 10);
+               fmt->user_len = len;
+
+               if (*p == ',')
+                       ptr = p + 1;
+               else
+                       break;
+       }
+}
index 40af0acb4fe95da232e441ebcb69e0c5f1b601a1..15b451acbde61081eaf22aba07a5da3752a9e205 100644 (file)
@@ -395,10 +395,12 @@ size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows,
 
        init_rem_hits();
 
-
        perf_hpp__for_each_format(fmt)
                perf_hpp__reset_width(fmt, hists);
 
+       if (symbol_conf.col_width_list_str)
+               perf_hpp__set_user_width(symbol_conf.col_width_list_str);
+
        if (!show_header)
                goto print_entries;
 
index 809b4c50beaed3e3a57845919b3a034fe7ab8c9e..36437527dbb347301c7d44f6322f72b4568a0d2a 100644 (file)
@@ -232,9 +232,16 @@ static int mov__parse(struct ins_operands *ops)
                return -1;
 
        target = ++s;
+       comment = strchr(s, '#');
 
-       while (s[0] != '\0' && !isspace(s[0]))
-               ++s;
+       if (comment != NULL)
+               s = comment - 1;
+       else
+               s = strchr(s, '\0') - 1;
+
+       while (s > target && isspace(s[0]))
+               --s;
+       s++;
        prev = *s;
        *s = '\0';
 
@@ -244,7 +251,6 @@ static int mov__parse(struct ins_operands *ops)
        if (ops->target.raw == NULL)
                goto out_free_source;
 
-       comment = strchr(s, '#');
        if (comment == NULL)
                return 0;
 
@@ -899,10 +905,8 @@ int symbol__annotate(struct symbol *sym, struct map *map, size_t privsize)
        struct kcore_extract kce;
        bool delete_extract = false;
 
-       if (filename) {
-               snprintf(symfs_filename, sizeof(symfs_filename), "%s%s",
-                        symbol_conf.symfs, filename);
-       }
+       if (filename)
+               symbol__join_symfs(symfs_filename, filename);
 
        if (filename == NULL) {
                if (dso->has_build_id) {
@@ -922,8 +926,7 @@ fallback:
                 * DSO is the same as when 'perf record' ran.
                 */
                filename = (char *)dso->long_name;
-               snprintf(symfs_filename, sizeof(symfs_filename), "%s%s",
-                        symbol_conf.symfs, filename);
+               symbol__join_symfs(symfs_filename, filename);
                free_filename = false;
        }
 
index 7b176dd02e1ae94e6f5479b78ae4c2e84bb7836c..5cf9e1b5989de40cb677b1bd744d684cd3bfc871 100644 (file)
@@ -22,6 +22,7 @@ typedef int (*config_fn_t)(const char *, const char *, void *);
 extern int perf_default_config(const char *, const char *, void *);
 extern int perf_config(config_fn_t fn, void *);
 extern int perf_config_int(const char *, const char *);
+extern u64 perf_config_u64(const char *, const char *);
 extern int perf_config_bool(const char *, const char *);
 extern int config_error_nonbool(const char *);
 extern const char *perf_config_dirname(const char *, const char *);
index 437ee09727e6053bc4eb6169008f04c02b8a654f..c84d3f8dcb7594602c4664c4926eaf050d26247e 100644 (file)
 
 __thread struct callchain_cursor callchain_cursor;
 
-int
-parse_callchain_report_opt(const char *arg)
+#ifdef HAVE_DWARF_UNWIND_SUPPORT
+static int get_stack_size(const char *str, unsigned long *_size)
 {
-       char *tok, *tok2;
        char *endptr;
+       unsigned long size;
+       unsigned long max_size = round_down(USHRT_MAX, sizeof(u64));
 
-       symbol_conf.use_callchain = true;
+       size = strtoul(str, &endptr, 0);
 
-       if (!arg)
+       do {
+               if (*endptr)
+                       break;
+
+               size = round_up(size, sizeof(u64));
+               if (!size || size > max_size)
+                       break;
+
+               *_size = size;
                return 0;
 
-       tok = strtok((char *)arg, ",");
-       if (!tok)
-               return -1;
+       } while (0);
 
-       /* get the output mode */
-       if (!strncmp(tok, "graph", strlen(arg))) {
-               callchain_param.mode = CHAIN_GRAPH_ABS;
+       pr_err("callchain: Incorrect stack dump size (max %ld): %s\n",
+              max_size, str);
+       return -1;
+}
+#endif /* HAVE_DWARF_UNWIND_SUPPORT */
 
-       } else if (!strncmp(tok, "flat", strlen(arg))) {
-               callchain_param.mode = CHAIN_FLAT;
-       } else if (!strncmp(tok, "fractal", strlen(arg))) {
-               callchain_param.mode = CHAIN_GRAPH_REL;
-       } else if (!strncmp(tok, "none", strlen(arg))) {
-               callchain_param.mode = CHAIN_NONE;
-               symbol_conf.use_callchain = false;
-               return 0;
-       } else {
-               return -1;
-       }
+int parse_callchain_record_opt(const char *arg)
+{
+       char *tok, *name, *saveptr = NULL;
+       char *buf;
+       int ret = -1;
+
+       /* We need buffer that we know we can write to. */
+       buf = malloc(strlen(arg) + 1);
+       if (!buf)
+               return -ENOMEM;
+
+       strcpy(buf, arg);
+
+       tok = strtok_r((char *)buf, ",", &saveptr);
+       name = tok ? : (char *)buf;
+
+       do {
+               /* Framepointer style */
+               if (!strncmp(name, "fp", sizeof("fp"))) {
+                       if (!strtok_r(NULL, ",", &saveptr)) {
+                               callchain_param.record_mode = CALLCHAIN_FP;
+                               ret = 0;
+                       } else
+                               pr_err("callchain: No more arguments "
+                                      "needed for -g fp\n");
+                       break;
 
-       /* get the min percentage */
-       tok = strtok(NULL, ",");
-       if (!tok)
-               goto setup;
+#ifdef HAVE_DWARF_UNWIND_SUPPORT
+               /* Dwarf style */
+               } else if (!strncmp(name, "dwarf", sizeof("dwarf"))) {
+                       const unsigned long default_stack_dump_size = 8192;
 
-       callchain_param.min_percent = strtod(tok, &endptr);
-       if (tok == endptr)
-               return -1;
+                       ret = 0;
+                       callchain_param.record_mode = CALLCHAIN_DWARF;
+                       callchain_param.dump_size = default_stack_dump_size;
 
-       /* get the print limit */
-       tok2 = strtok(NULL, ",");
-       if (!tok2)
-               goto setup;
+                       tok = strtok_r(NULL, ",", &saveptr);
+                       if (tok) {
+                               unsigned long size = 0;
 
-       if (tok2[0] != 'c') {
-               callchain_param.print_limit = strtoul(tok2, &endptr, 0);
-               tok2 = strtok(NULL, ",");
-               if (!tok2)
-                       goto setup;
+                               ret = get_stack_size(tok, &size);
+                               callchain_param.dump_size = size;
+                       }
+#endif /* HAVE_DWARF_UNWIND_SUPPORT */
+               } else {
+                       pr_err("callchain: Unknown --call-graph option "
+                              "value: %s\n", arg);
+                       break;
+               }
+
+       } while (0);
+
+       free(buf);
+       return ret;
+}
+
+static int parse_callchain_mode(const char *value)
+{
+       if (!strncmp(value, "graph", strlen(value))) {
+               callchain_param.mode = CHAIN_GRAPH_ABS;
+               return 0;
+       }
+       if (!strncmp(value, "flat", strlen(value))) {
+               callchain_param.mode = CHAIN_FLAT;
+               return 0;
        }
+       if (!strncmp(value, "fractal", strlen(value))) {
+               callchain_param.mode = CHAIN_GRAPH_REL;
+               return 0;
+       }
+       return -1;
+}
 
-       /* get the call chain order */
-       if (!strncmp(tok2, "caller", strlen("caller")))
+static int parse_callchain_order(const char *value)
+{
+       if (!strncmp(value, "caller", strlen(value))) {
                callchain_param.order = ORDER_CALLER;
-       else if (!strncmp(tok2, "callee", strlen("callee")))
+               return 0;
+       }
+       if (!strncmp(value, "callee", strlen(value))) {
                callchain_param.order = ORDER_CALLEE;
-       else
-               return -1;
+               return 0;
+       }
+       return -1;
+}
 
-       /* Get the sort key */
-       tok2 = strtok(NULL, ",");
-       if (!tok2)
-               goto setup;
-       if (!strncmp(tok2, "function", strlen("function")))
+static int parse_callchain_sort_key(const char *value)
+{
+       if (!strncmp(value, "function", strlen(value))) {
                callchain_param.key = CCKEY_FUNCTION;
-       else if (!strncmp(tok2, "address", strlen("address")))
+               return 0;
+       }
+       if (!strncmp(value, "address", strlen(value))) {
                callchain_param.key = CCKEY_ADDRESS;
-       else
-               return -1;
-setup:
+               return 0;
+       }
+       return -1;
+}
+
+int
+parse_callchain_report_opt(const char *arg)
+{
+       char *tok;
+       char *endptr;
+       bool minpcnt_set = false;
+
+       symbol_conf.use_callchain = true;
+
+       if (!arg)
+               return 0;
+
+       while ((tok = strtok((char *)arg, ",")) != NULL) {
+               if (!strncmp(tok, "none", strlen(tok))) {
+                       callchain_param.mode = CHAIN_NONE;
+                       symbol_conf.use_callchain = false;
+                       return 0;
+               }
+
+               if (!parse_callchain_mode(tok) ||
+                   !parse_callchain_order(tok) ||
+                   !parse_callchain_sort_key(tok)) {
+                       /* parsing ok - move on to the next */
+               } else if (!minpcnt_set) {
+                       /* try to get the min percent */
+                       callchain_param.min_percent = strtod(tok, &endptr);
+                       if (tok == endptr)
+                               return -1;
+                       minpcnt_set = true;
+               } else {
+                       /* try print limit at last */
+                       callchain_param.print_limit = strtoul(tok, &endptr, 0);
+                       if (tok == endptr)
+                               return -1;
+               }
+
+               arg = NULL;
+       }
+
        if (callchain_register_param(&callchain_param) < 0) {
                pr_err("Can't register callchain params\n");
                return -1;
@@ -103,6 +198,47 @@ setup:
        return 0;
 }
 
+int perf_callchain_config(const char *var, const char *value)
+{
+       char *endptr;
+
+       if (prefixcmp(var, "call-graph."))
+               return 0;
+       var += sizeof("call-graph.") - 1;
+
+       if (!strcmp(var, "record-mode"))
+               return parse_callchain_record_opt(value);
+#ifdef HAVE_DWARF_UNWIND_SUPPORT
+       if (!strcmp(var, "dump-size")) {
+               unsigned long size = 0;
+               int ret;
+
+               ret = get_stack_size(value, &size);
+               callchain_param.dump_size = size;
+
+               return ret;
+       }
+#endif
+       if (!strcmp(var, "print-type"))
+               return parse_callchain_mode(value);
+       if (!strcmp(var, "order"))
+               return parse_callchain_order(value);
+       if (!strcmp(var, "sort-key"))
+               return parse_callchain_sort_key(value);
+       if (!strcmp(var, "threshold")) {
+               callchain_param.min_percent = strtod(value, &endptr);
+               if (value == endptr)
+                       return -1;
+       }
+       if (!strcmp(var, "print-limit")) {
+               callchain_param.print_limit = strtod(value, &endptr);
+               if (value == endptr)
+                       return -1;
+       }
+
+       return 0;
+}
+
 static void
 rb_insert_callchain(struct rb_root *root, struct callchain_node *chain,
                    enum chain_mode mode)
index da43619d61733ab2e0d273690200797c92089519..2a1f5a46543a1cd3ecfb0b78c622921c9ee5a564 100644 (file)
@@ -54,6 +54,9 @@ enum chain_key {
 };
 
 struct callchain_param {
+       bool                    enabled;
+       enum perf_call_graph_mode record_mode;
+       u32                     dump_size;
        enum chain_mode         mode;
        u32                     print_limit;
        double                  min_percent;
@@ -154,7 +157,6 @@ static inline void callchain_cursor_advance(struct callchain_cursor *cursor)
 struct option;
 struct hist_entry;
 
-int record_parse_callchain(const char *arg, struct record_opts *opts);
 int record_parse_callchain_opt(const struct option *opt, const char *arg, int unset);
 int record_callchain_opt(const struct option *opt, const char *arg, int unset);
 
@@ -166,7 +168,9 @@ int fill_callchain_info(struct addr_location *al, struct callchain_cursor_node *
                        bool hide_unresolved);
 
 extern const char record_callchain_help[];
+int parse_callchain_record_opt(const char *arg);
 int parse_callchain_report_opt(const char *arg);
+int perf_callchain_config(const char *var, const char *value);
 
 static inline void callchain_cursor_snapshot(struct callchain_cursor *dest,
                                             struct callchain_cursor *src)
index c5d05ec172206d6d86dd1bdc14edfa29a2d7bd0f..47b78b3f03257385023629696dda95e57d2b5ab7 100644 (file)
@@ -1,7 +1,9 @@
+#include <sched.h>
 #include "util.h"
 #include "../perf.h"
 #include "cloexec.h"
 #include "asm/bug.h"
+#include "debug.h"
 
 static unsigned long flag = PERF_FLAG_FD_CLOEXEC;
 
@@ -9,15 +11,30 @@ static int perf_flag_probe(void)
 {
        /* use 'safest' configuration as used in perf_evsel__fallback() */
        struct perf_event_attr attr = {
-               .type = PERF_COUNT_SW_CPU_CLOCK,
+               .type = PERF_TYPE_SOFTWARE,
                .config = PERF_COUNT_SW_CPU_CLOCK,
+               .exclude_kernel = 1,
        };
        int fd;
        int err;
+       int cpu;
+       pid_t pid = -1;
+       char sbuf[STRERR_BUFSIZE];
 
-       /* check cloexec flag */
-       fd = sys_perf_event_open(&attr, 0, -1, -1,
-                                PERF_FLAG_FD_CLOEXEC);
+       cpu = sched_getcpu();
+       if (cpu < 0)
+               cpu = 0;
+
+       while (1) {
+               /* check cloexec flag */
+               fd = sys_perf_event_open(&attr, pid, cpu, -1,
+                                        PERF_FLAG_FD_CLOEXEC);
+               if (fd < 0 && pid == -1 && errno == EACCES) {
+                       pid = 0;
+                       continue;
+               }
+               break;
+       }
        err = errno;
 
        if (fd >= 0) {
@@ -25,17 +42,17 @@ static int perf_flag_probe(void)
                return 1;
        }
 
-       WARN_ONCE(err != EINVAL,
+       WARN_ONCE(err != EINVAL && err != EBUSY,
                  "perf_event_open(..., PERF_FLAG_FD_CLOEXEC) failed with unexpected error %d (%s)\n",
-                 err, strerror(err));
+                 err, strerror_r(err, sbuf, sizeof(sbuf)));
 
        /* not supported, confirm error related to PERF_FLAG_FD_CLOEXEC */
-       fd = sys_perf_event_open(&attr, 0, -1, -1, 0);
+       fd = sys_perf_event_open(&attr, pid, cpu, -1, 0);
        err = errno;
 
-       if (WARN_ONCE(fd < 0,
+       if (WARN_ONCE(fd < 0 && err != EBUSY,
                      "perf_event_open(..., 0) failed unexpectedly with error %d (%s)\n",
-                     err, strerror(err)))
+                     err, strerror_r(err, sbuf, sizeof(sbuf))))
                return -1;
 
        close(fd);
index 87b8672eb4134cab6d29b3a2accda19093edb9aa..f4654183d391a4051a970719229d47b2a9027108 100644 (file)
@@ -335,3 +335,19 @@ int percent_color_snprintf(char *bf, size_t size, const char *fmt, ...)
        va_end(args);
        return value_color_snprintf(bf, size, fmt, percent);
 }
+
+int percent_color_len_snprintf(char *bf, size_t size, const char *fmt, ...)
+{
+       va_list args;
+       int len;
+       double percent;
+       const char *color;
+
+       va_start(args, fmt);
+       len = va_arg(args, int);
+       percent = va_arg(args, double);
+       va_end(args);
+
+       color = get_percent_color(percent);
+       return color_snprintf(bf, size, color, fmt, len, percent);
+}
index 7ff30a62a132296a6f82de9fea62629defa8e658..0a594b8a0c26ab2e0753221ea0ae03e2b63e640e 100644 (file)
@@ -41,6 +41,7 @@ int color_fprintf_ln(FILE *fp, const char *color, const char *fmt, ...);
 int color_fwrite_lines(FILE *fp, const char *color, size_t count, const char *buf);
 int value_color_snprintf(char *bf, size_t size, const char *fmt, double value);
 int percent_color_snprintf(char *bf, size_t size, const char *fmt, ...);
+int percent_color_len_snprintf(char *bf, size_t size, const char *fmt, ...);
 int percent_color_fprintf(FILE *fp, const char *fmt, double percent);
 const char *get_percent_color(double percent);
 
index f9e777629e21cd1780fad2dc891f4c24d637787e..b2bb59df65e10c10cfe6dd1aacb495d4804a6a4f 100644 (file)
@@ -74,7 +74,7 @@ static struct comm_str *comm_str__findnew(const char *str, struct rb_root *root)
        return new;
 }
 
-struct comm *comm__new(const char *str, u64 timestamp)
+struct comm *comm__new(const char *str, u64 timestamp, bool exec)
 {
        struct comm *comm = zalloc(sizeof(*comm));
 
@@ -82,6 +82,7 @@ struct comm *comm__new(const char *str, u64 timestamp)
                return NULL;
 
        comm->start = timestamp;
+       comm->exec = exec;
 
        comm->comm_str = comm_str__findnew(str, &comm_str_root);
        if (!comm->comm_str) {
@@ -94,7 +95,7 @@ struct comm *comm__new(const char *str, u64 timestamp)
        return comm;
 }
 
-int comm__override(struct comm *comm, const char *str, u64 timestamp)
+int comm__override(struct comm *comm, const char *str, u64 timestamp, bool exec)
 {
        struct comm_str *new, *old = comm->comm_str;
 
@@ -106,6 +107,8 @@ int comm__override(struct comm *comm, const char *str, u64 timestamp)
        comm_str__put(old);
        comm->comm_str = new;
        comm->start = timestamp;
+       if (exec)
+               comm->exec = true;
 
        return 0;
 }
index fac5bd51befc4c4a2b6aafe5cd21220829334673..51c10ab257f8b2b079d120075cc7effb45bd73e3 100644 (file)
@@ -11,11 +11,13 @@ struct comm {
        struct comm_str *comm_str;
        u64 start;
        struct list_head list;
+       bool exec;
 };
 
 void comm__free(struct comm *comm);
-struct comm *comm__new(const char *str, u64 timestamp);
+struct comm *comm__new(const char *str, u64 timestamp, bool exec);
 const char *comm__str(const struct comm *comm);
-int comm__override(struct comm *comm, const char *str, u64 timestamp);
+int comm__override(struct comm *comm, const char *str, u64 timestamp,
+                  bool exec);
 
 #endif  /* __PERF_COMM_H */
index 1e5e2e5af6b1d05b18b1f6b92b88c4e62e85f33c..57ff826f150bfe4db2f89814a1e2a77be54aebfa 100644 (file)
@@ -222,7 +222,8 @@ static int perf_parse_file(config_fn_t fn, void *data)
        const unsigned char *bomptr = utf8_bom;
 
        for (;;) {
-               int c = get_next_char();
+               int line, c = get_next_char();
+
                if (bomptr && *bomptr) {
                        /* We are at the file beginning; skip UTF8-encoded BOM
                         * if present. Sane editors won't put this in on their
@@ -261,8 +262,16 @@ static int perf_parse_file(config_fn_t fn, void *data)
                if (!isalpha(c))
                        break;
                var[baselen] = tolower(c);
-               if (get_value(fn, data, var, baselen+1) < 0)
+
+               /*
+                * The get_value function might or might not reach the '\n',
+                * so saving the current line number for error reporting.
+                */
+               line = config_linenr;
+               if (get_value(fn, data, var, baselen+1) < 0) {
+                       config_linenr = line;
                        break;
+               }
        }
        die("bad config file line %d in %s", config_linenr, config_file_name);
 }
@@ -286,6 +295,21 @@ static int parse_unit_factor(const char *end, unsigned long *val)
        return 0;
 }
 
+static int perf_parse_llong(const char *value, long long *ret)
+{
+       if (value && *value) {
+               char *end;
+               long long val = strtoll(value, &end, 0);
+               unsigned long factor = 1;
+
+               if (!parse_unit_factor(end, &factor))
+                       return 0;
+               *ret = val * factor;
+               return 1;
+       }
+       return 0;
+}
+
 static int perf_parse_long(const char *value, long *ret)
 {
        if (value && *value) {
@@ -307,6 +331,15 @@ static void die_bad_config(const char *name)
        die("bad config value for '%s'", name);
 }
 
+u64 perf_config_u64(const char *name, const char *value)
+{
+       long long ret = 0;
+
+       if (!perf_parse_llong(value, &ret))
+               die_bad_config(name);
+       return (u64) ret;
+}
+
 int perf_config_int(const char *name, const char *value)
 {
        long ret = 0;
@@ -372,6 +405,9 @@ int perf_default_config(const char *var, const char *value,
        if (!prefixcmp(var, "ui."))
                return perf_ui_config(var, value);
 
+       if (!prefixcmp(var, "call-graph."))
+               return perf_callchain_config(var, value);
+
        /* Add other config variables here. */
        return 0;
 }
index 29d720cf5844763f300611b85e503cc1e6013bf8..1921942fc2e035cb2ddec0ba94b066e02a8f5bc9 100644 (file)
@@ -50,12 +50,14 @@ static int open_file_read(struct perf_data_file *file)
 {
        struct stat st;
        int fd;
+       char sbuf[STRERR_BUFSIZE];
 
        fd = open(file->path, O_RDONLY);
        if (fd < 0) {
                int err = errno;
 
-               pr_err("failed to open %s: %s", file->path, strerror(err));
+               pr_err("failed to open %s: %s", file->path,
+                       strerror_r(err, sbuf, sizeof(sbuf)));
                if (err == ENOENT && !strcmp(file->path, "perf.data"))
                        pr_err("  (try 'perf record' first)");
                pr_err("\n");
@@ -88,6 +90,7 @@ static int open_file_read(struct perf_data_file *file)
 static int open_file_write(struct perf_data_file *file)
 {
        int fd;
+       char sbuf[STRERR_BUFSIZE];
 
        if (check_backup(file))
                return -1;
@@ -95,7 +98,8 @@ static int open_file_write(struct perf_data_file *file)
        fd = open(file->path, O_CREAT|O_RDWR|O_TRUNC, S_IRUSR|S_IWUSR);
 
        if (fd < 0)
-               pr_err("failed to open %s : %s\n", file->path, strerror(errno));
+               pr_err("failed to open %s : %s\n", file->path,
+                       strerror_r(errno, sbuf, sizeof(sbuf)));
 
        return fd;
 }
index 71d419362634768f32d22862da4a44952e02edd4..ba357f3226c69533c5d79497e3d2fb2207656514 100644 (file)
 #include "util.h"
 #include "target.h"
 
+#define NSECS_PER_SEC  1000000000ULL
+#define NSECS_PER_USEC 1000ULL
+
 int verbose;
 bool dump_trace = false, quiet = false;
+int debug_ordered_events;
 
 static int _eprintf(int level, int var, const char *fmt, va_list args)
 {
@@ -42,6 +46,35 @@ int eprintf(int level, int var, const char *fmt, ...)
        return ret;
 }
 
+static int __eprintf_time(u64 t, const char *fmt, va_list args)
+{
+       int ret = 0;
+       u64 secs, usecs, nsecs = t;
+
+       secs   = nsecs / NSECS_PER_SEC;
+       nsecs -= secs  * NSECS_PER_SEC;
+       usecs  = nsecs / NSECS_PER_USEC;
+
+       ret = fprintf(stderr, "[%13" PRIu64 ".%06" PRIu64 "] ",
+                     secs, usecs);
+       ret += vfprintf(stderr, fmt, args);
+       return ret;
+}
+
+int eprintf_time(int level, int var, u64 t, const char *fmt, ...)
+{
+       int ret = 0;
+       va_list args;
+
+       if (var >= level) {
+               va_start(args, fmt);
+               ret = __eprintf_time(t, fmt, args);
+               va_end(args);
+       }
+
+       return ret;
+}
+
 /*
  * Overloading libtraceevent standard info print
  * function, display with -v in perf.
@@ -110,7 +143,8 @@ static struct debug_variable {
        const char *name;
        int *ptr;
 } debug_variables[] = {
-       { .name = "verbose", .ptr = &verbose },
+       { .name = "verbose",            .ptr = &verbose },
+       { .name = "ordered-events",     .ptr = &debug_ordered_events},
        { .name = NULL, }
 };
 
index 89fb6b0f7ab221d746163b5bb842ce6bf5416fad..be264d6f3b304933988f73fa3790e132bf6d4e2d 100644 (file)
@@ -3,6 +3,7 @@
 #define __PERF_DEBUG_H
 
 #include <stdbool.h>
+#include <string.h>
 #include "event.h"
 #include "../ui/helpline.h"
 #include "../ui/progress.h"
@@ -10,6 +11,7 @@
 
 extern int verbose;
 extern bool quiet, dump_trace;
+extern int debug_ordered_events;
 
 #ifndef pr_fmt
 #define pr_fmt(fmt) fmt
@@ -29,6 +31,14 @@ extern bool quiet, dump_trace;
 #define pr_debug3(fmt, ...) pr_debugN(3, pr_fmt(fmt), ##__VA_ARGS__)
 #define pr_debug4(fmt, ...) pr_debugN(4, pr_fmt(fmt), ##__VA_ARGS__)
 
+#define pr_time_N(n, var, t, fmt, ...) \
+       eprintf_time(n, var, t, fmt, ##__VA_ARGS__)
+
+#define pr_oe_time(t, fmt, ...)  pr_time_N(1, debug_ordered_events, t, pr_fmt(fmt), ##__VA_ARGS__)
+#define pr_oe_time2(t, fmt, ...) pr_time_N(2, debug_ordered_events, t, pr_fmt(fmt), ##__VA_ARGS__)
+
+#define STRERR_BUFSIZE 128     /* For the buffer size of strerror_r */
+
 int dump_printf(const char *fmt, ...) __attribute__((format(printf, 1, 2)));
 void trace_event(union perf_event *event);
 
@@ -38,6 +48,7 @@ int ui__warning(const char *format, ...) __attribute__((format(printf, 1, 2)));
 void pr_stat(const char *fmt, ...);
 
 int eprintf(int level, int var, const char *fmt, ...) __attribute__((format(printf, 3, 4)));
+int eprintf_time(int level, int var, u64 t, const char *fmt, ...) __attribute__((format(printf, 4, 5)));
 
 int perf_debug_option(const char *str);
 
index 90d02c661dd4b5087e4f00759c08cab5290abb9a..0247acfdfaca807a1378631f19d6d38ddef67cf3 100644 (file)
@@ -37,6 +37,7 @@ int dso__read_binary_type_filename(const struct dso *dso,
 {
        char build_id_hex[BUILD_ID_SIZE * 2 + 1];
        int ret = 0;
+       size_t len;
 
        switch (type) {
        case DSO_BINARY_TYPE__DEBUGLINK: {
@@ -60,26 +61,25 @@ int dso__read_binary_type_filename(const struct dso *dso,
                break;
 
        case DSO_BINARY_TYPE__FEDORA_DEBUGINFO:
-               snprintf(filename, size, "%s/usr/lib/debug%s.debug",
-                        symbol_conf.symfs, dso->long_name);
+               len = __symbol__join_symfs(filename, size, "/usr/lib/debug");
+               snprintf(filename + len, size - len, "%s.debug", dso->long_name);
                break;
 
        case DSO_BINARY_TYPE__UBUNTU_DEBUGINFO:
-               snprintf(filename, size, "%s/usr/lib/debug%s",
-                        symbol_conf.symfs, dso->long_name);
+               len = __symbol__join_symfs(filename, size, "/usr/lib/debug");
+               snprintf(filename + len, size - len, "%s", dso->long_name);
                break;
 
        case DSO_BINARY_TYPE__OPENEMBEDDED_DEBUGINFO:
        {
                const char *last_slash;
-               size_t len;
                size_t dir_size;
 
                last_slash = dso->long_name + dso->long_name_len;
                while (last_slash != dso->long_name && *last_slash != '/')
                        last_slash--;
 
-               len = scnprintf(filename, size, "%s", symbol_conf.symfs);
+               len = __symbol__join_symfs(filename, size, "");
                dir_size = last_slash - dso->long_name + 2;
                if (dir_size > (size - len)) {
                        ret = -1;
@@ -100,26 +100,24 @@ int dso__read_binary_type_filename(const struct dso *dso,
                build_id__sprintf(dso->build_id,
                                  sizeof(dso->build_id),
                                  build_id_hex);
-               snprintf(filename, size,
-                        "%s/usr/lib/debug/.build-id/%.2s/%s.debug",
-                        symbol_conf.symfs, build_id_hex, build_id_hex + 2);
+               len = __symbol__join_symfs(filename, size, "/usr/lib/debug/.build-id/");
+               snprintf(filename + len, size - len, "%.2s/%s.debug",
+                        build_id_hex, build_id_hex + 2);
                break;
 
        case DSO_BINARY_TYPE__VMLINUX:
        case DSO_BINARY_TYPE__GUEST_VMLINUX:
        case DSO_BINARY_TYPE__SYSTEM_PATH_DSO:
-               snprintf(filename, size, "%s%s",
-                        symbol_conf.symfs, dso->long_name);
+               __symbol__join_symfs(filename, size, dso->long_name);
                break;
 
        case DSO_BINARY_TYPE__GUEST_KMODULE:
-               snprintf(filename, size, "%s%s%s", symbol_conf.symfs,
-                        root_dir, dso->long_name);
+               path__join3(filename, size, symbol_conf.symfs,
+                           root_dir, dso->long_name);
                break;
 
        case DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE:
-               snprintf(filename, size, "%s%s", symbol_conf.symfs,
-                        dso->long_name);
+               __symbol__join_symfs(filename, size, dso->long_name);
                break;
 
        case DSO_BINARY_TYPE__KCORE:
@@ -164,13 +162,15 @@ static void close_first_dso(void);
 static int do_open(char *name)
 {
        int fd;
+       char sbuf[STRERR_BUFSIZE];
 
        do {
                fd = open(name, O_RDONLY);
                if (fd >= 0)
                        return fd;
 
-               pr_debug("dso open failed, mmap: %s\n", strerror(errno));
+               pr_debug("dso open failed, mmap: %s\n",
+                        strerror_r(errno, sbuf, sizeof(sbuf)));
                if (!dso__data_open_cnt || errno != EMFILE)
                        break;
 
@@ -532,10 +532,12 @@ static ssize_t cached_read(struct dso *dso, u64 offset, u8 *data, ssize_t size)
 static int data_file_size(struct dso *dso)
 {
        struct stat st;
+       char sbuf[STRERR_BUFSIZE];
 
        if (!dso->data.file_size) {
                if (fstat(dso->data.fd, &st)) {
-                       pr_err("dso mmap failed, fstat: %s\n", strerror(errno));
+                       pr_err("dso mmap failed, fstat: %s\n",
+                               strerror_r(errno, sbuf, sizeof(sbuf)));
                        return -1;
                }
                dso->data.file_size = st.st_size;
@@ -651,6 +653,65 @@ struct dso *dso__kernel_findnew(struct machine *machine, const char *name,
        return dso;
 }
 
+/*
+ * Find a matching entry and/or link current entry to RB tree.
+ * Either one of the dso or name parameter must be non-NULL or the
+ * function will not work.
+ */
+static struct dso *dso__findlink_by_longname(struct rb_root *root,
+                                            struct dso *dso, const char *name)
+{
+       struct rb_node **p = &root->rb_node;
+       struct rb_node  *parent = NULL;
+
+       if (!name)
+               name = dso->long_name;
+       /*
+        * Find node with the matching name
+        */
+       while (*p) {
+               struct dso *this = rb_entry(*p, struct dso, rb_node);
+               int rc = strcmp(name, this->long_name);
+
+               parent = *p;
+               if (rc == 0) {
+                       /*
+                        * In case the new DSO is a duplicate of an existing
+                        * one, print an one-time warning & put the new entry
+                        * at the end of the list of duplicates.
+                        */
+                       if (!dso || (dso == this))
+                               return this;    /* Find matching dso */
+                       /*
+                        * The core kernel DSOs may have duplicated long name.
+                        * In this case, the short name should be different.
+                        * Comparing the short names to differentiate the DSOs.
+                        */
+                       rc = strcmp(dso->short_name, this->short_name);
+                       if (rc == 0) {
+                               pr_err("Duplicated dso name: %s\n", name);
+                               return NULL;
+                       }
+               }
+               if (rc < 0)
+                       p = &parent->rb_left;
+               else
+                       p = &parent->rb_right;
+       }
+       if (dso) {
+               /* Add new node and rebalance tree */
+               rb_link_node(&dso->rb_node, parent, p);
+               rb_insert_color(&dso->rb_node, root);
+       }
+       return NULL;
+}
+
+static inline struct dso *
+dso__find_by_longname(const struct rb_root *root, const char *name)
+{
+       return dso__findlink_by_longname((struct rb_root *)root, NULL, name);
+}
+
 void dso__set_long_name(struct dso *dso, const char *name, bool name_allocated)
 {
        if (name == NULL)
@@ -753,6 +814,7 @@ struct dso *dso__new(const char *name)
                dso->a2l_fails = 1;
                dso->kernel = DSO_TYPE_USER;
                dso->needs_swap = DSO_SWAP__UNSET;
+               RB_CLEAR_NODE(&dso->rb_node);
                INIT_LIST_HEAD(&dso->node);
                INIT_LIST_HEAD(&dso->data.open_entry);
        }
@@ -763,6 +825,10 @@ struct dso *dso__new(const char *name)
 void dso__delete(struct dso *dso)
 {
        int i;
+
+       if (!RB_EMPTY_NODE(&dso->rb_node))
+               pr_err("DSO %s is still in rbtree when being deleted!\n",
+                      dso->long_name);
        for (i = 0; i < MAP__NR_TYPES; ++i)
                symbols__delete(&dso->symbols[i]);
 
@@ -849,35 +915,34 @@ bool __dsos__read_build_ids(struct list_head *head, bool with_hits)
        return have_build_id;
 }
 
-void dsos__add(struct list_head *head, struct dso *dso)
+void dsos__add(struct dsos *dsos, struct dso *dso)
 {
-       list_add_tail(&dso->node, head);
+       list_add_tail(&dso->node, &dsos->head);
+       dso__findlink_by_longname(&dsos->root, dso, NULL);
 }
 
-struct dso *dsos__find(const struct list_head *head, const char *name, bool cmp_short)
+struct dso *dsos__find(const struct dsos *dsos, const char *name,
+                      bool cmp_short)
 {
        struct dso *pos;
 
        if (cmp_short) {
-               list_for_each_entry(pos, head, node)
+               list_for_each_entry(pos, &dsos->head, node)
                        if (strcmp(pos->short_name, name) == 0)
                                return pos;
                return NULL;
        }
-       list_for_each_entry(pos, head, node)
-               if (strcmp(pos->long_name, name) == 0)
-                       return pos;
-       return NULL;
+       return dso__find_by_longname(&dsos->root, name);
 }
 
-struct dso *__dsos__findnew(struct list_head *head, const char *name)
+struct dso *__dsos__findnew(struct dsos *dsos, const char *name)
 {
-       struct dso *dso = dsos__find(head, name, false);
+       struct dso *dso = dsos__find(dsos, name, false);
 
        if (!dso) {
                dso = dso__new(name);
                if (dso != NULL) {
-                       dsos__add(head, dso);
+                       dsos__add(dsos, dso);
                        dso__set_basename(dso);
                }
        }
index 5e463c0964d442b23a44c67377ec016925f68363..acb651acc7fdf1e6ee74dde78cf85ee98da6a1bf 100644 (file)
@@ -90,8 +90,18 @@ struct dso_cache {
        char data[0];
 };
 
+/*
+ * DSOs are put into both a list for fast iteration and rbtree for fast
+ * long name lookup.
+ */
+struct dsos {
+       struct list_head head;
+       struct rb_root   root;  /* rbtree root sorted by long name */
+};
+
 struct dso {
        struct list_head node;
+       struct rb_node   rb_node;       /* rbtree node sorted by long name */
        struct rb_root   symbols[MAP__NR_TYPES];
        struct rb_root   symbol_names[MAP__NR_TYPES];
        void             *a2l;
@@ -224,10 +234,10 @@ struct map *dso__new_map(const char *name);
 struct dso *dso__kernel_findnew(struct machine *machine, const char *name,
                                const char *short_name, int dso_type);
 
-void dsos__add(struct list_head *head, struct dso *dso);
-struct dso *dsos__find(const struct list_head *head, const char *name,
+void dsos__add(struct dsos *dsos, struct dso *dso);
+struct dso *dsos__find(const struct dsos *dsos, const char *name,
                       bool cmp_short);
-struct dso *__dsos__findnew(struct list_head *head, const char *name);
+struct dso *__dsos__findnew(struct dsos *dsos, const char *name);
 bool __dsos__read_build_ids(struct list_head *head, bool with_hits);
 
 size_t __dsos__fprintf_buildid(struct list_head *head, FILE *fp,
index 1398c83d896dffb170d5ca107bdb98e0d9630aaa..4af6b279e34a94881da3e838ff41f407aeb0cbfc 100644 (file)
@@ -558,13 +558,17 @@ int perf_event__synthesize_kernel_mmap(struct perf_tool *tool,
        struct map *map;
        struct kmap *kmap;
        int err;
+       union perf_event *event;
+
+       if (machine->vmlinux_maps[0] == NULL)
+               return -1;
+
        /*
         * We should get this from /sys/kernel/sections/.text, but till that is
         * available use this, and after it is use this as a fallback for older
         * kernels.
         */
-       union perf_event *event = zalloc((sizeof(event->mmap) +
-                                         machine->id_hdr_size));
+       event = zalloc((sizeof(event->mmap) + machine->id_hdr_size));
        if (event == NULL) {
                pr_debug("Not enough memory synthesizing mmap event "
                         "for kernel modules\n");
@@ -784,9 +788,9 @@ try_again:
                 * "[vdso]" dso, but for now lets use the old trick of looking
                 * in the whole kernel symbol list.
                 */
-               if ((long long)al->addr < 0 &&
-                   cpumode == PERF_RECORD_MISC_USER &&
-                   machine && mg != &machine->kmaps) {
+               if (cpumode == PERF_RECORD_MISC_USER && machine &&
+                   mg != &machine->kmaps &&
+                   machine__kernel_ip(machine, al->addr)) {
                        mg = &machine->kmaps;
                        load_map = true;
                        goto try_again;
index 94d6976180daa5959090fae2fed308b45b14af27..7eb7107731eca8a47db95d590a091b176e70d8f7 100644 (file)
@@ -156,6 +156,8 @@ struct perf_sample {
        u32 cpu;
        u32 raw_size;
        u64 data_src;
+       u32 flags;
+       u16 insn_len;
        void *raw_data;
        struct ip_callchain *callchain;
        struct branch_stack *branch_stack;
index 814e954c1318ed04ed1bcf9666927f6a4c64e426..3cebc9a8d52e232e9dafe13dd2b8cf2b0dcd613d 100644 (file)
@@ -25,6 +25,9 @@
 #include <linux/bitops.h>
 #include <linux/hash.h>
 
+static void perf_evlist__mmap_put(struct perf_evlist *evlist, int idx);
+static void __perf_evlist__munmap(struct perf_evlist *evlist, int idx);
+
 #define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y))
 #define SID(e, x, y) xyarray__entry(e->sample_id, x, y)
 
@@ -37,6 +40,7 @@ void perf_evlist__init(struct perf_evlist *evlist, struct cpu_map *cpus,
                INIT_HLIST_HEAD(&evlist->heads[i]);
        INIT_LIST_HEAD(&evlist->entries);
        perf_evlist__set_maps(evlist, cpus, threads);
+       fdarray__init(&evlist->pollfd, 64);
        evlist->workload.pid = -1;
 }
 
@@ -102,7 +106,7 @@ static void perf_evlist__purge(struct perf_evlist *evlist)
 void perf_evlist__exit(struct perf_evlist *evlist)
 {
        zfree(&evlist->mmap);
-       zfree(&evlist->pollfd);
+       fdarray__exit(&evlist->pollfd);
 }
 
 void perf_evlist__delete(struct perf_evlist *evlist)
@@ -122,6 +126,7 @@ void perf_evlist__add(struct perf_evlist *evlist, struct perf_evsel *entry)
 {
        list_add_tail(&entry->node, &evlist->entries);
        entry->idx = evlist->nr_entries;
+       entry->tracking = !entry->idx;
 
        if (!evlist->nr_entries++)
                perf_evlist__set_id_pos(evlist);
@@ -265,17 +270,27 @@ int perf_evlist__add_newtp(struct perf_evlist *evlist,
        return 0;
 }
 
+static int perf_evlist__nr_threads(struct perf_evlist *evlist,
+                                  struct perf_evsel *evsel)
+{
+       if (evsel->system_wide)
+               return 1;
+       else
+               return thread_map__nr(evlist->threads);
+}
+
 void perf_evlist__disable(struct perf_evlist *evlist)
 {
        int cpu, thread;
        struct perf_evsel *pos;
        int nr_cpus = cpu_map__nr(evlist->cpus);
-       int nr_threads = thread_map__nr(evlist->threads);
+       int nr_threads;
 
        for (cpu = 0; cpu < nr_cpus; cpu++) {
                evlist__for_each(evlist, pos) {
                        if (!perf_evsel__is_group_leader(pos) || !pos->fd)
                                continue;
+                       nr_threads = perf_evlist__nr_threads(evlist, pos);
                        for (thread = 0; thread < nr_threads; thread++)
                                ioctl(FD(pos, cpu, thread),
                                      PERF_EVENT_IOC_DISABLE, 0);
@@ -288,12 +303,13 @@ void perf_evlist__enable(struct perf_evlist *evlist)
        int cpu, thread;
        struct perf_evsel *pos;
        int nr_cpus = cpu_map__nr(evlist->cpus);
-       int nr_threads = thread_map__nr(evlist->threads);
+       int nr_threads;
 
        for (cpu = 0; cpu < nr_cpus; cpu++) {
                evlist__for_each(evlist, pos) {
                        if (!perf_evsel__is_group_leader(pos) || !pos->fd)
                                continue;
+                       nr_threads = perf_evlist__nr_threads(evlist, pos);
                        for (thread = 0; thread < nr_threads; thread++)
                                ioctl(FD(pos, cpu, thread),
                                      PERF_EVENT_IOC_ENABLE, 0);
@@ -305,12 +321,14 @@ int perf_evlist__disable_event(struct perf_evlist *evlist,
                               struct perf_evsel *evsel)
 {
        int cpu, thread, err;
+       int nr_cpus = cpu_map__nr(evlist->cpus);
+       int nr_threads = perf_evlist__nr_threads(evlist, evsel);
 
        if (!evsel->fd)
                return 0;
 
-       for (cpu = 0; cpu < evlist->cpus->nr; cpu++) {
-               for (thread = 0; thread < evlist->threads->nr; thread++) {
+       for (cpu = 0; cpu < nr_cpus; cpu++) {
+               for (thread = 0; thread < nr_threads; thread++) {
                        err = ioctl(FD(evsel, cpu, thread),
                                    PERF_EVENT_IOC_DISABLE, 0);
                        if (err)
@@ -324,12 +342,14 @@ int perf_evlist__enable_event(struct perf_evlist *evlist,
                              struct perf_evsel *evsel)
 {
        int cpu, thread, err;
+       int nr_cpus = cpu_map__nr(evlist->cpus);
+       int nr_threads = perf_evlist__nr_threads(evlist, evsel);
 
        if (!evsel->fd)
                return -EINVAL;
 
-       for (cpu = 0; cpu < evlist->cpus->nr; cpu++) {
-               for (thread = 0; thread < evlist->threads->nr; thread++) {
+       for (cpu = 0; cpu < nr_cpus; cpu++) {
+               for (thread = 0; thread < nr_threads; thread++) {
                        err = ioctl(FD(evsel, cpu, thread),
                                    PERF_EVENT_IOC_ENABLE, 0);
                        if (err)
@@ -339,21 +359,111 @@ int perf_evlist__enable_event(struct perf_evlist *evlist,
        return 0;
 }
 
-static int perf_evlist__alloc_pollfd(struct perf_evlist *evlist)
+static int perf_evlist__enable_event_cpu(struct perf_evlist *evlist,
+                                        struct perf_evsel *evsel, int cpu)
+{
+       int thread, err;
+       int nr_threads = perf_evlist__nr_threads(evlist, evsel);
+
+       if (!evsel->fd)
+               return -EINVAL;
+
+       for (thread = 0; thread < nr_threads; thread++) {
+               err = ioctl(FD(evsel, cpu, thread),
+                           PERF_EVENT_IOC_ENABLE, 0);
+               if (err)
+                       return err;
+       }
+       return 0;
+}
+
+static int perf_evlist__enable_event_thread(struct perf_evlist *evlist,
+                                           struct perf_evsel *evsel,
+                                           int thread)
+{
+       int cpu, err;
+       int nr_cpus = cpu_map__nr(evlist->cpus);
+
+       if (!evsel->fd)
+               return -EINVAL;
+
+       for (cpu = 0; cpu < nr_cpus; cpu++) {
+               err = ioctl(FD(evsel, cpu, thread), PERF_EVENT_IOC_ENABLE, 0);
+               if (err)
+                       return err;
+       }
+       return 0;
+}
+
+int perf_evlist__enable_event_idx(struct perf_evlist *evlist,
+                                 struct perf_evsel *evsel, int idx)
+{
+       bool per_cpu_mmaps = !cpu_map__empty(evlist->cpus);
+
+       if (per_cpu_mmaps)
+               return perf_evlist__enable_event_cpu(evlist, evsel, idx);
+       else
+               return perf_evlist__enable_event_thread(evlist, evsel, idx);
+}
+
+int perf_evlist__alloc_pollfd(struct perf_evlist *evlist)
 {
        int nr_cpus = cpu_map__nr(evlist->cpus);
        int nr_threads = thread_map__nr(evlist->threads);
-       int nfds = nr_cpus * nr_threads * evlist->nr_entries;
-       evlist->pollfd = malloc(sizeof(struct pollfd) * nfds);
-       return evlist->pollfd != NULL ? 0 : -ENOMEM;
+       int nfds = 0;
+       struct perf_evsel *evsel;
+
+       list_for_each_entry(evsel, &evlist->entries, node) {
+               if (evsel->system_wide)
+                       nfds += nr_cpus;
+               else
+                       nfds += nr_cpus * nr_threads;
+       }
+
+       if (fdarray__available_entries(&evlist->pollfd) < nfds &&
+           fdarray__grow(&evlist->pollfd, nfds) < 0)
+               return -ENOMEM;
+
+       return 0;
+}
+
+static int __perf_evlist__add_pollfd(struct perf_evlist *evlist, int fd, int idx)
+{
+       int pos = fdarray__add(&evlist->pollfd, fd, POLLIN | POLLERR | POLLHUP);
+       /*
+        * Save the idx so that when we filter out fds POLLHUP'ed we can
+        * close the associated evlist->mmap[] entry.
+        */
+       if (pos >= 0) {
+               evlist->pollfd.priv[pos].idx = idx;
+
+               fcntl(fd, F_SETFL, O_NONBLOCK);
+       }
+
+       return pos;
+}
+
+int perf_evlist__add_pollfd(struct perf_evlist *evlist, int fd)
+{
+       return __perf_evlist__add_pollfd(evlist, fd, -1);
+}
+
+static void perf_evlist__munmap_filtered(struct fdarray *fda, int fd)
+{
+       struct perf_evlist *evlist = container_of(fda, struct perf_evlist, pollfd);
+
+       perf_evlist__mmap_put(evlist, fda->priv[fd].idx);
+}
+
+int perf_evlist__filter_pollfd(struct perf_evlist *evlist, short revents_and_mask)
+{
+       return fdarray__filter(&evlist->pollfd, revents_and_mask,
+                              perf_evlist__munmap_filtered);
 }
 
-void perf_evlist__add_pollfd(struct perf_evlist *evlist, int fd)
+int perf_evlist__poll(struct perf_evlist *evlist, int timeout)
 {
-       fcntl(fd, F_SETFL, O_NONBLOCK);
-       evlist->pollfd[evlist->nr_fds].fd = fd;
-       evlist->pollfd[evlist->nr_fds].events = POLLIN;
-       evlist->nr_fds++;
+       return fdarray__poll(&evlist->pollfd, timeout);
 }
 
 static void perf_evlist__id_hash(struct perf_evlist *evlist,
@@ -566,14 +676,36 @@ union perf_event *perf_evlist__mmap_read(struct perf_evlist *evlist, int idx)
        return event;
 }
 
+static bool perf_mmap__empty(struct perf_mmap *md)
+{
+       return perf_mmap__read_head(md) != md->prev;
+}
+
+static void perf_evlist__mmap_get(struct perf_evlist *evlist, int idx)
+{
+       ++evlist->mmap[idx].refcnt;
+}
+
+static void perf_evlist__mmap_put(struct perf_evlist *evlist, int idx)
+{
+       BUG_ON(evlist->mmap[idx].refcnt == 0);
+
+       if (--evlist->mmap[idx].refcnt == 0)
+               __perf_evlist__munmap(evlist, idx);
+}
+
 void perf_evlist__mmap_consume(struct perf_evlist *evlist, int idx)
 {
+       struct perf_mmap *md = &evlist->mmap[idx];
+
        if (!evlist->overwrite) {
-               struct perf_mmap *md = &evlist->mmap[idx];
                unsigned int old = md->prev;
 
                perf_mmap__write_tail(md, old);
        }
+
+       if (md->refcnt == 1 && perf_mmap__empty(md))
+               perf_evlist__mmap_put(evlist, idx);
 }
 
 static void __perf_evlist__munmap(struct perf_evlist *evlist, int idx)
@@ -581,6 +713,7 @@ static void __perf_evlist__munmap(struct perf_evlist *evlist, int idx)
        if (evlist->mmap[idx].base != NULL) {
                munmap(evlist->mmap[idx].base, evlist->mmap_len);
                evlist->mmap[idx].base = NULL;
+               evlist->mmap[idx].refcnt = 0;
        }
 }
 
@@ -614,6 +747,20 @@ struct mmap_params {
 static int __perf_evlist__mmap(struct perf_evlist *evlist, int idx,
                               struct mmap_params *mp, int fd)
 {
+       /*
+        * The last one will be done at perf_evlist__mmap_consume(), so that we
+        * make sure we don't prevent tools from consuming every last event in
+        * the ring buffer.
+        *
+        * I.e. we can get the POLLHUP meaning that the fd doesn't exist
+        * anymore, but the last events for it are still in the ring buffer,
+        * waiting to be consumed.
+        *
+        * Tools can chose to ignore this at their own discretion, but the
+        * evlist layer can't just drop it when filtering events in
+        * perf_evlist__filter_pollfd().
+        */
+       evlist->mmap[idx].refcnt = 2;
        evlist->mmap[idx].prev = 0;
        evlist->mmap[idx].mask = mp->mask;
        evlist->mmap[idx].base = mmap(NULL, evlist->mmap_len, mp->prot,
@@ -625,7 +772,6 @@ static int __perf_evlist__mmap(struct perf_evlist *evlist, int idx,
                return -1;
        }
 
-       perf_evlist__add_pollfd(evlist, fd);
        return 0;
 }
 
@@ -636,7 +782,12 @@ static int perf_evlist__mmap_per_evsel(struct perf_evlist *evlist, int idx,
        struct perf_evsel *evsel;
 
        evlist__for_each(evlist, evsel) {
-               int fd = FD(evsel, cpu, thread);
+               int fd;
+
+               if (evsel->system_wide && thread)
+                       continue;
+
+               fd = FD(evsel, cpu, thread);
 
                if (*output == -1) {
                        *output = fd;
@@ -645,6 +796,13 @@ static int perf_evlist__mmap_per_evsel(struct perf_evlist *evlist, int idx,
                } else {
                        if (ioctl(fd, PERF_EVENT_IOC_SET_OUTPUT, *output) != 0)
                                return -1;
+
+                       perf_evlist__mmap_get(evlist, idx);
+               }
+
+               if (__perf_evlist__add_pollfd(evlist, fd, idx) < 0) {
+                       perf_evlist__mmap_put(evlist, idx);
+                       return -1;
                }
 
                if ((evsel->attr.read_format & PERF_FORMAT_ID) &&
@@ -804,7 +962,7 @@ int perf_evlist__mmap(struct perf_evlist *evlist, unsigned int pages,
        if (evlist->mmap == NULL && perf_evlist__alloc_mmap(evlist) < 0)
                return -ENOMEM;
 
-       if (evlist->pollfd == NULL && perf_evlist__alloc_pollfd(evlist) < 0)
+       if (evlist->pollfd.entries == NULL && perf_evlist__alloc_pollfd(evlist) < 0)
                return -ENOMEM;
 
        evlist->overwrite = overwrite;
@@ -1061,6 +1219,8 @@ int perf_evlist__prepare_workload(struct perf_evlist *evlist, struct target *tar
        }
 
        if (!evlist->workload.pid) {
+               int ret;
+
                if (pipe_output)
                        dup2(2, 1);
 
@@ -1078,8 +1238,22 @@ int perf_evlist__prepare_workload(struct perf_evlist *evlist, struct target *tar
                /*
                 * Wait until the parent tells us to go.
                 */
-               if (read(go_pipe[0], &bf, 1) == -1)
-                       perror("unable to read pipe");
+               ret = read(go_pipe[0], &bf, 1);
+               /*
+                * The parent will ask for the execvp() to be performed by
+                * writing exactly one byte, in workload.cork_fd, usually via
+                * perf_evlist__start_workload().
+                *
+                * For cancelling the workload without actuallin running it,
+                * the parent will just close workload.cork_fd, without writing
+                * anything, i.e. read will return zero and we just exit()
+                * here.
+                */
+               if (ret != 1) {
+                       if (ret == -1)
+                               perror("unable to read pipe");
+                       exit(ret);
+               }
 
                execvp(argv[0], (char **)argv);
 
@@ -1202,7 +1376,7 @@ int perf_evlist__strerror_open(struct perf_evlist *evlist __maybe_unused,
                               int err, char *buf, size_t size)
 {
        int printed, value;
-       char sbuf[128], *emsg = strerror_r(err, sbuf, sizeof(sbuf));
+       char sbuf[STRERR_BUFSIZE], *emsg = strerror_r(err, sbuf, sizeof(sbuf));
 
        switch (err) {
        case EACCES:
@@ -1250,3 +1424,19 @@ void perf_evlist__to_front(struct perf_evlist *evlist,
 
        list_splice(&move, &evlist->entries);
 }
+
+void perf_evlist__set_tracking_event(struct perf_evlist *evlist,
+                                    struct perf_evsel *tracking_evsel)
+{
+       struct perf_evsel *evsel;
+
+       if (tracking_evsel->tracking)
+               return;
+
+       evlist__for_each(evlist, evsel) {
+               if (evsel != tracking_evsel)
+                       evsel->tracking = false;
+       }
+
+       tracking_evsel->tracking = true;
+}
index f5173cd63693cc7944b500a65a0b407567512143..bd312b01e8766e97dd50f8661f3e4213f8513fde 100644 (file)
@@ -2,6 +2,7 @@
 #define __PERF_EVLIST_H 1
 
 #include <linux/list.h>
+#include <api/fd/array.h>
 #include <stdio.h>
 #include "../perf.h"
 #include "event.h"
@@ -17,9 +18,15 @@ struct record_opts;
 #define PERF_EVLIST__HLIST_BITS 8
 #define PERF_EVLIST__HLIST_SIZE (1 << PERF_EVLIST__HLIST_BITS)
 
+/**
+ * struct perf_mmap - perf's ring buffer mmap details
+ *
+ * @refcnt - e.g. code using PERF_EVENT_IOC_SET_OUTPUT to share this
+ */
 struct perf_mmap {
        void             *base;
        int              mask;
+       int              refcnt;
        unsigned int     prev;
        char             event_copy[PERF_SAMPLE_MAX_SIZE];
 };
@@ -29,7 +36,6 @@ struct perf_evlist {
        struct hlist_head heads[PERF_EVLIST__HLIST_SIZE];
        int              nr_entries;
        int              nr_groups;
-       int              nr_fds;
        int              nr_mmaps;
        size_t           mmap_len;
        int              id_pos;
@@ -40,8 +46,8 @@ struct perf_evlist {
                pid_t   pid;
        } workload;
        bool             overwrite;
+       struct fdarray   pollfd;
        struct perf_mmap *mmap;
-       struct pollfd    *pollfd;
        struct thread_map *threads;
        struct cpu_map    *cpus;
        struct perf_evsel *selected;
@@ -82,7 +88,11 @@ perf_evlist__find_tracepoint_by_name(struct perf_evlist *evlist,
 void perf_evlist__id_add(struct perf_evlist *evlist, struct perf_evsel *evsel,
                         int cpu, int thread, u64 id);
 
-void perf_evlist__add_pollfd(struct perf_evlist *evlist, int fd);
+int perf_evlist__add_pollfd(struct perf_evlist *evlist, int fd);
+int perf_evlist__alloc_pollfd(struct perf_evlist *evlist);
+int perf_evlist__filter_pollfd(struct perf_evlist *evlist, short revents_and_mask);
+
+int perf_evlist__poll(struct perf_evlist *evlist, int timeout);
 
 struct perf_evsel *perf_evlist__id2evsel(struct perf_evlist *evlist, u64 id);
 
@@ -122,6 +132,8 @@ int perf_evlist__disable_event(struct perf_evlist *evlist,
                               struct perf_evsel *evsel);
 int perf_evlist__enable_event(struct perf_evlist *evlist,
                              struct perf_evsel *evsel);
+int perf_evlist__enable_event_idx(struct perf_evlist *evlist,
+                                 struct perf_evsel *evsel, int idx);
 
 void perf_evlist__set_selected(struct perf_evlist *evlist,
                               struct perf_evsel *evsel);
@@ -262,4 +274,7 @@ void perf_evlist__to_front(struct perf_evlist *evlist,
 #define evlist__for_each_safe(evlist, tmp, evsel) \
        __evlist__for_each_safe(&(evlist)->entries, tmp, evsel)
 
+void perf_evlist__set_tracking_event(struct perf_evlist *evlist,
+                                    struct perf_evsel *tracking_evsel);
+
 #endif /* __PERF_EVLIST_H */
index 21a373ebea226a8208c3ccf2aaee9ad92ad4156d..e0868a901c4ac07a1855251b94937a4a1dd55cf4 100644 (file)
@@ -162,6 +162,7 @@ void perf_evsel__init(struct perf_evsel *evsel,
                      struct perf_event_attr *attr, int idx)
 {
        evsel->idx         = idx;
+       evsel->tracking    = !idx;
        evsel->attr        = *attr;
        evsel->leader      = evsel;
        evsel->unit        = "";
@@ -502,20 +503,19 @@ int perf_evsel__group_desc(struct perf_evsel *evsel, char *buf, size_t size)
 }
 
 static void
-perf_evsel__config_callgraph(struct perf_evsel *evsel,
-                            struct record_opts *opts)
+perf_evsel__config_callgraph(struct perf_evsel *evsel)
 {
        bool function = perf_evsel__is_function_event(evsel);
        struct perf_event_attr *attr = &evsel->attr;
 
        perf_evsel__set_sample_bit(evsel, CALLCHAIN);
 
-       if (opts->call_graph == CALLCHAIN_DWARF) {
+       if (callchain_param.record_mode == CALLCHAIN_DWARF) {
                if (!function) {
                        perf_evsel__set_sample_bit(evsel, REGS_USER);
                        perf_evsel__set_sample_bit(evsel, STACK_USER);
                        attr->sample_regs_user = PERF_REGS_MASK;
-                       attr->sample_stack_user = opts->stack_dump_size;
+                       attr->sample_stack_user = callchain_param.dump_size;
                        attr->exclude_callchain_user = 1;
                } else {
                        pr_info("Cannot use DWARF unwind for function trace event,"
@@ -561,7 +561,7 @@ void perf_evsel__config(struct perf_evsel *evsel, struct record_opts *opts)
 {
        struct perf_evsel *leader = evsel->leader;
        struct perf_event_attr *attr = &evsel->attr;
-       int track = !evsel->idx; /* only the first counter needs these */
+       int track = evsel->tracking;
        bool per_cpu = opts->target.default_per_cpu && !opts->target.per_thread;
 
        attr->sample_id_all = perf_missing_features.sample_id_all ? 0 : 1;
@@ -624,8 +624,8 @@ void perf_evsel__config(struct perf_evsel *evsel, struct record_opts *opts)
                attr->mmap_data = track;
        }
 
-       if (opts->call_graph_enabled && !evsel->no_aux_samples)
-               perf_evsel__config_callgraph(evsel, opts);
+       if (callchain_param.enabled && !evsel->no_aux_samples)
+               perf_evsel__config_callgraph(evsel);
 
        if (target__has_cpu(&opts->target))
                perf_evsel__set_sample_bit(evsel, CPU);
@@ -633,9 +633,12 @@ void perf_evsel__config(struct perf_evsel *evsel, struct record_opts *opts)
        if (opts->period)
                perf_evsel__set_sample_bit(evsel, PERIOD);
 
-       if (!perf_missing_features.sample_id_all &&
-           (opts->sample_time || !opts->no_inherit ||
-            target__has_cpu(&opts->target) || per_cpu))
+       /*
+        * When the user explicitely disabled time don't force it here.
+        */
+       if (opts->sample_time &&
+           (!perf_missing_features.sample_id_all &&
+           (!opts->no_inherit || target__has_cpu(&opts->target) || per_cpu)))
                perf_evsel__set_sample_bit(evsel, TIME);
 
        if (opts->raw_samples && !evsel->no_aux_samples) {
@@ -692,6 +695,10 @@ void perf_evsel__config(struct perf_evsel *evsel, struct record_opts *opts)
 int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads)
 {
        int cpu, thread;
+
+       if (evsel->system_wide)
+               nthreads = 1;
+
        evsel->fd = xyarray__new(ncpus, nthreads, sizeof(int));
 
        if (evsel->fd) {
@@ -710,6 +717,9 @@ static int perf_evsel__run_ioctl(struct perf_evsel *evsel, int ncpus, int nthrea
 {
        int cpu, thread;
 
+       if (evsel->system_wide)
+               nthreads = 1;
+
        for (cpu = 0; cpu < ncpus; cpu++) {
                for (thread = 0; thread < nthreads; thread++) {
                        int fd = FD(evsel, cpu, thread),
@@ -740,6 +750,9 @@ int perf_evsel__enable(struct perf_evsel *evsel, int ncpus, int nthreads)
 
 int perf_evsel__alloc_id(struct perf_evsel *evsel, int ncpus, int nthreads)
 {
+       if (evsel->system_wide)
+               nthreads = 1;
+
        evsel->sample_id = xyarray__new(ncpus, nthreads, sizeof(struct perf_sample_id));
        if (evsel->sample_id == NULL)
                return -ENOMEM;
@@ -784,6 +797,9 @@ void perf_evsel__close_fd(struct perf_evsel *evsel, int ncpus, int nthreads)
 {
        int cpu, thread;
 
+       if (evsel->system_wide)
+               nthreads = 1;
+
        for (cpu = 0; cpu < ncpus; cpu++)
                for (thread = 0; thread < nthreads; ++thread) {
                        close(FD(evsel, cpu, thread));
@@ -872,6 +888,9 @@ int __perf_evsel__read(struct perf_evsel *evsel,
        int cpu, thread;
        struct perf_counts_values *aggr = &evsel->counts->aggr, count;
 
+       if (evsel->system_wide)
+               nthreads = 1;
+
        aggr->val = aggr->ena = aggr->run = 0;
 
        for (cpu = 0; cpu < ncpus; cpu++) {
@@ -994,13 +1013,18 @@ static size_t perf_event_attr__fprintf(struct perf_event_attr *attr, FILE *fp)
 static int __perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus,
                              struct thread_map *threads)
 {
-       int cpu, thread;
+       int cpu, thread, nthreads;
        unsigned long flags = PERF_FLAG_FD_CLOEXEC;
        int pid = -1, err;
        enum { NO_CHANGE, SET_TO_MAX, INCREASED_MAX } set_rlimit = NO_CHANGE;
 
+       if (evsel->system_wide)
+               nthreads = 1;
+       else
+               nthreads = threads->nr;
+
        if (evsel->fd == NULL &&
-           perf_evsel__alloc_fd(evsel, cpus->nr, threads->nr) < 0)
+           perf_evsel__alloc_fd(evsel, cpus->nr, nthreads) < 0)
                return -ENOMEM;
 
        if (evsel->cgrp) {
@@ -1024,10 +1048,10 @@ retry_sample_id:
 
        for (cpu = 0; cpu < cpus->nr; cpu++) {
 
-               for (thread = 0; thread < threads->nr; thread++) {
+               for (thread = 0; thread < nthreads; thread++) {
                        int group_fd;
 
-                       if (!evsel->cgrp)
+                       if (!evsel->cgrp && !evsel->system_wide)
                                pid = threads->map[thread];
 
                        group_fd = get_group_fd(evsel, cpu, thread);
@@ -1100,7 +1124,7 @@ out_close:
                        close(FD(evsel, cpu, thread));
                        FD(evsel, cpu, thread) = -1;
                }
-               thread = threads->nr;
+               thread = nthreads;
        } while (--cpu >= 0);
        return err;
 }
@@ -2002,6 +2026,8 @@ bool perf_evsel__fallback(struct perf_evsel *evsel, int err,
 int perf_evsel__open_strerror(struct perf_evsel *evsel, struct target *target,
                              int err, char *msg, size_t size)
 {
+       char sbuf[STRERR_BUFSIZE];
+
        switch (err) {
        case EPERM:
        case EACCES:
@@ -2036,13 +2062,20 @@ int perf_evsel__open_strerror(struct perf_evsel *evsel, struct target *target,
        "No APIC? If so then you can boot the kernel with the \"lapic\" boot parameter to force-enable it.");
 #endif
                break;
+       case EBUSY:
+               if (find_process("oprofiled"))
+                       return scnprintf(msg, size,
+       "The PMU counters are busy/taken by another profiler.\n"
+       "We found oprofile daemon running, please stop it and try again.");
+               break;
        default:
                break;
        }
 
        return scnprintf(msg, size,
-       "The sys_perf_event_open() syscall returned with %d (%s) for event (%s).  \n"
+       "The sys_perf_event_open() syscall returned with %d (%s) for event (%s).\n"
        "/bin/dmesg may provide additional information.\n"
        "No CONFIG_PERF_EVENTS=y kernel support configured?\n",
-                        err, strerror(err), perf_evsel__name(evsel));
+                        err, strerror_r(err, sbuf, sizeof(sbuf)),
+                        perf_evsel__name(evsel));
 }
index d7f93ce0ebc12b33f542ec82d9d4f2d52ad9c661..7bc314be6a7bea55b81611788c57e95313041af9 100644 (file)
@@ -85,6 +85,8 @@ struct perf_evsel {
        bool                    needs_swap;
        bool                    no_aux_samples;
        bool                    immediate;
+       bool                    system_wide;
+       bool                    tracking;
        /* parse modifier helper */
        int                     exclude_GH;
        int                     nr_members;
index 158c787ce0c40e8bc673e3e73062dcaef3872c4f..ce0de00399da381accf00472f66c6064cdcee20a 100644 (file)
@@ -214,11 +214,11 @@ static int machine__hit_all_dsos(struct machine *machine)
 {
        int err;
 
-       err = __dsos__hit_all(&machine->kernel_dsos);
+       err = __dsos__hit_all(&machine->kernel_dsos.head);
        if (err)
                return err;
 
-       return __dsos__hit_all(&machine->user_dsos);
+       return __dsos__hit_all(&machine->user_dsos.head);
 }
 
 int dsos__hit_all(struct perf_session *session)
@@ -288,11 +288,12 @@ static int machine__write_buildid_table(struct machine *machine, int fd)
                umisc = PERF_RECORD_MISC_GUEST_USER;
        }
 
-       err = __dsos__write_buildid_table(&machine->kernel_dsos, machine,
+       err = __dsos__write_buildid_table(&machine->kernel_dsos.head, machine,
                                          machine->pid, kmisc, fd);
        if (err == 0)
-               err = __dsos__write_buildid_table(&machine->user_dsos, machine,
-                                                 machine->pid, umisc, fd);
+               err = __dsos__write_buildid_table(&machine->user_dsos.head,
+                                                 machine, machine->pid, umisc,
+                                                 fd);
        return err;
 }
 
@@ -455,9 +456,10 @@ static int __dsos__cache_build_ids(struct list_head *head,
 
 static int machine__cache_build_ids(struct machine *machine, const char *debugdir)
 {
-       int ret = __dsos__cache_build_ids(&machine->kernel_dsos, machine,
+       int ret = __dsos__cache_build_ids(&machine->kernel_dsos.head, machine,
                                          debugdir);
-       ret |= __dsos__cache_build_ids(&machine->user_dsos, machine, debugdir);
+       ret |= __dsos__cache_build_ids(&machine->user_dsos.head, machine,
+                                      debugdir);
        return ret;
 }
 
@@ -483,8 +485,10 @@ static int perf_session__cache_build_ids(struct perf_session *session)
 
 static bool machine__read_build_ids(struct machine *machine, bool with_hits)
 {
-       bool ret = __dsos__read_build_ids(&machine->kernel_dsos, with_hits);
-       ret |= __dsos__read_build_ids(&machine->user_dsos, with_hits);
+       bool ret;
+
+       ret  = __dsos__read_build_ids(&machine->kernel_dsos.head, with_hits);
+       ret |= __dsos__read_build_ids(&machine->user_dsos.head, with_hits);
        return ret;
 }
 
@@ -1548,7 +1552,7 @@ static int __event_process_build_id(struct build_id_event *bev,
                                    struct perf_session *session)
 {
        int err = -1;
-       struct list_head *head;
+       struct dsos *dsos;
        struct machine *machine;
        u16 misc;
        struct dso *dso;
@@ -1563,22 +1567,22 @@ static int __event_process_build_id(struct build_id_event *bev,
        switch (misc) {
        case PERF_RECORD_MISC_KERNEL:
                dso_type = DSO_TYPE_KERNEL;
-               head = &machine->kernel_dsos;
+               dsos = &machine->kernel_dsos;
                break;
        case PERF_RECORD_MISC_GUEST_KERNEL:
                dso_type = DSO_TYPE_GUEST_KERNEL;
-               head = &machine->kernel_dsos;
+               dsos = &machine->kernel_dsos;
                break;
        case PERF_RECORD_MISC_USER:
        case PERF_RECORD_MISC_GUEST_USER:
                dso_type = DSO_TYPE_USER;
-               head = &machine->user_dsos;
+               dsos = &machine->user_dsos;
                break;
        default:
                goto out;
        }
 
-       dso = __dsos__findnew(head, filename);
+       dso = __dsos__findnew(dsos, filename);
        if (dso != NULL) {
                char sbuild_id[BUILD_ID_SIZE * 2 + 1];
 
index 30df6187ee026acf0fb9f12013fbde891d3bdd70..86569fa3651d00a851e9e38da54df647cc6ba17c 100644 (file)
@@ -277,6 +277,28 @@ void hists__decay_entries(struct hists *hists, bool zap_user, bool zap_kernel)
        }
 }
 
+void hists__delete_entries(struct hists *hists)
+{
+       struct rb_node *next = rb_first(&hists->entries);
+       struct hist_entry *n;
+
+       while (next) {
+               n = rb_entry(next, struct hist_entry, rb_node);
+               next = rb_next(&n->rb_node);
+
+               rb_erase(&n->rb_node, &hists->entries);
+
+               if (sort__need_collapse)
+                       rb_erase(&n->rb_node_in, &hists->entries_collapsed);
+
+               --hists->nr_entries;
+               if (!n->filtered)
+                       --hists->nr_non_filtered_entries;
+
+               hist_entry__free(n);
+       }
+}
+
 /*
  * histogram, sorted on item, collects periods
  */
index 742f49a85725733e90f7342ca5f7728946574be8..8c9c70e18cbbc353631d5fa283118c3f08725c0d 100644 (file)
@@ -152,6 +152,7 @@ void hists__output_resort(struct hists *hists);
 void hists__collapse_resort(struct hists *hists, struct ui_progress *prog);
 
 void hists__decay_entries(struct hists *hists, bool zap_user, bool zap_kernel);
+void hists__delete_entries(struct hists *hists);
 void hists__output_recalc_col_len(struct hists *hists, int max_rows);
 
 u64 hists__total_period(struct hists *hists);
@@ -192,6 +193,7 @@ struct perf_hpp {
 };
 
 struct perf_hpp_fmt {
+       const char *name;
        int (*header)(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
                      struct perf_evsel *evsel);
        int (*width)(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
@@ -207,6 +209,8 @@ struct perf_hpp_fmt {
        struct list_head list;
        struct list_head sort_list;
        bool elide;
+       int len;
+       int user_len;
 };
 
 extern struct list_head perf_hpp__list;
@@ -261,17 +265,19 @@ static inline bool perf_hpp__should_skip(struct perf_hpp_fmt *format)
 }
 
 void perf_hpp__reset_width(struct perf_hpp_fmt *fmt, struct hists *hists);
+void perf_hpp__reset_sort_width(struct perf_hpp_fmt *fmt, struct hists *hists);
+void perf_hpp__set_user_width(const char *width_list_str);
 
 typedef u64 (*hpp_field_fn)(struct hist_entry *he);
 typedef int (*hpp_callback_fn)(struct perf_hpp *hpp, bool front);
 typedef int (*hpp_snprint_fn)(struct perf_hpp *hpp, const char *fmt, ...);
 
-int __hpp__fmt(struct perf_hpp *hpp, struct hist_entry *he,
-              hpp_field_fn get_field, const char *fmt,
-              hpp_snprint_fn print_fn, bool fmt_percent);
-int __hpp__fmt_acc(struct perf_hpp *hpp, struct hist_entry *he,
-                  hpp_field_fn get_field, const char *fmt,
-                  hpp_snprint_fn print_fn, bool fmt_percent);
+int hpp__fmt(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
+            struct hist_entry *he, hpp_field_fn get_field,
+            const char *fmtstr, hpp_snprint_fn print_fn, bool fmt_percent);
+int hpp__fmt_acc(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
+                struct hist_entry *he, hpp_field_fn get_field,
+                const char *fmtstr, hpp_snprint_fn print_fn, bool fmt_percent);
 
 static inline void advance_hpp(struct perf_hpp *hpp, int inc)
 {
index 0b5a8cd2ee79a90fe52c5ecdae637f86f6fb025d..cf1d7913783bbcd89c1aa0e9cb9c818c590fd5ac 100644 (file)
@@ -92,7 +92,6 @@ struct perf_kvm_stat {
        u64 lost_events;
        u64 duration;
 
-       const char *pid_str;
        struct intlist *pid_list;
 
        struct rb_root result;
index 16bba9fff2c87b68ae55960568c58d1469665400..b7d477fbda0208bb7ef6b4923a0769c7273049e2 100644 (file)
@@ -17,8 +17,8 @@ int machine__init(struct machine *machine, const char *root_dir, pid_t pid)
 {
        map_groups__init(&machine->kmaps);
        RB_CLEAR_NODE(&machine->rb_node);
-       INIT_LIST_HEAD(&machine->user_dsos);
-       INIT_LIST_HEAD(&machine->kernel_dsos);
+       INIT_LIST_HEAD(&machine->user_dsos.head);
+       INIT_LIST_HEAD(&machine->kernel_dsos.head);
 
        machine->threads = RB_ROOT;
        INIT_LIST_HEAD(&machine->dead_threads);
@@ -31,6 +31,8 @@ int machine__init(struct machine *machine, const char *root_dir, pid_t pid)
 
        machine->symbol_filter = NULL;
        machine->id_hdr_size = 0;
+       machine->comm_exec = false;
+       machine->kernel_start = 0;
 
        machine->root_dir = strdup(root_dir);
        if (machine->root_dir == NULL)
@@ -70,11 +72,12 @@ out_delete:
        return NULL;
 }
 
-static void dsos__delete(struct list_head *dsos)
+static void dsos__delete(struct dsos *dsos)
 {
        struct dso *pos, *n;
 
-       list_for_each_entry_safe(pos, n, dsos, node) {
+       list_for_each_entry_safe(pos, n, &dsos->head, node) {
+               RB_CLEAR_NODE(&pos->rb_node);
                list_del(&pos->node);
                dso__delete(pos);
        }
@@ -179,6 +182,19 @@ void machines__set_symbol_filter(struct machines *machines,
        }
 }
 
+void machines__set_comm_exec(struct machines *machines, bool comm_exec)
+{
+       struct rb_node *nd;
+
+       machines->host.comm_exec = comm_exec;
+
+       for (nd = rb_first(&machines->guests); nd; nd = rb_next(nd)) {
+               struct machine *machine = rb_entry(nd, struct machine, rb_node);
+
+               machine->comm_exec = comm_exec;
+       }
+}
+
 struct machine *machines__find(struct machines *machines, pid_t pid)
 {
        struct rb_node **p = &machines->guests.rb_node;
@@ -398,17 +414,31 @@ struct thread *machine__find_thread(struct machine *machine, pid_t pid,
        return __machine__findnew_thread(machine, pid, tid, false);
 }
 
+struct comm *machine__thread_exec_comm(struct machine *machine,
+                                      struct thread *thread)
+{
+       if (machine->comm_exec)
+               return thread__exec_comm(thread);
+       else
+               return thread__comm(thread);
+}
+
 int machine__process_comm_event(struct machine *machine, union perf_event *event,
                                struct perf_sample *sample)
 {
        struct thread *thread = machine__findnew_thread(machine,
                                                        event->comm.pid,
                                                        event->comm.tid);
+       bool exec = event->header.misc & PERF_RECORD_MISC_COMM_EXEC;
+
+       if (exec)
+               machine->comm_exec = true;
 
        if (dump_trace)
                perf_event__fprintf_comm(event, stdout);
 
-       if (thread == NULL || thread__set_comm(thread, event->comm.comm, sample->time)) {
+       if (thread == NULL ||
+           __thread__set_comm(thread, event->comm.comm, sample->time, exec)) {
                dump_printf("problem processing PERF_RECORD_COMM, skipping event.\n");
                return -1;
        }
@@ -448,23 +478,23 @@ struct map *machine__new_module(struct machine *machine, u64 start,
 size_t machines__fprintf_dsos(struct machines *machines, FILE *fp)
 {
        struct rb_node *nd;
-       size_t ret = __dsos__fprintf(&machines->host.kernel_dsos, fp) +
-                    __dsos__fprintf(&machines->host.user_dsos, fp);
+       size_t ret = __dsos__fprintf(&machines->host.kernel_dsos.head, fp) +
+                    __dsos__fprintf(&machines->host.user_dsos.head, fp);
 
        for (nd = rb_first(&machines->guests); nd; nd = rb_next(nd)) {
                struct machine *pos = rb_entry(nd, struct machine, rb_node);
-               ret += __dsos__fprintf(&pos->kernel_dsos, fp);
-               ret += __dsos__fprintf(&pos->user_dsos, fp);
+               ret += __dsos__fprintf(&pos->kernel_dsos.head, fp);
+               ret += __dsos__fprintf(&pos->user_dsos.head, fp);
        }
 
        return ret;
 }
 
-size_t machine__fprintf_dsos_buildid(struct machine *machine, FILE *fp,
+size_t machine__fprintf_dsos_buildid(struct machine *m, FILE *fp,
                                     bool (skip)(struct dso *dso, int parm), int parm)
 {
-       return __dsos__fprintf_buildid(&machine->kernel_dsos, fp, skip, parm) +
-              __dsos__fprintf_buildid(&machine->user_dsos, fp, skip, parm);
+       return __dsos__fprintf_buildid(&m->kernel_dsos.head, fp, skip, parm) +
+              __dsos__fprintf_buildid(&m->user_dsos.head, fp, skip, parm);
 }
 
 size_t machines__fprintf_dsos_buildid(struct machines *machines, FILE *fp,
@@ -565,8 +595,8 @@ const char *ref_reloc_sym_names[] = {"_text", "_stext", NULL};
  * Returns the name of the start symbol in *symbol_name. Pass in NULL as
  * symbol_name if it's not that important.
  */
-static u64 machine__get_kernel_start_addr(struct machine *machine,
-                                         const char **symbol_name)
+static u64 machine__get_running_kernel_start(struct machine *machine,
+                                            const char **symbol_name)
 {
        char filename[PATH_MAX];
        int i;
@@ -593,7 +623,7 @@ static u64 machine__get_kernel_start_addr(struct machine *machine,
 int __machine__create_kernel_maps(struct machine *machine, struct dso *kernel)
 {
        enum map_type type;
-       u64 start = machine__get_kernel_start_addr(machine, NULL);
+       u64 start = machine__get_running_kernel_start(machine, NULL);
 
        for (type = 0; type < MAP__NR_TYPES; ++type) {
                struct kmap *kmap;
@@ -912,7 +942,7 @@ int machine__create_kernel_maps(struct machine *machine)
 {
        struct dso *kernel = machine__get_kernel(machine);
        const char *name;
-       u64 addr = machine__get_kernel_start_addr(machine, &name);
+       u64 addr = machine__get_running_kernel_start(machine, &name);
        if (!addr)
                return -1;
 
@@ -965,7 +995,7 @@ static bool machine__uses_kcore(struct machine *machine)
 {
        struct dso *dso;
 
-       list_for_each_entry(dso, &machine->kernel_dsos, node) {
+       list_for_each_entry(dso, &machine->kernel_dsos.head, node) {
                if (dso__is_kcore(dso))
                        return true;
        }
@@ -1285,6 +1315,16 @@ static void ip__resolve_data(struct machine *machine, struct thread *thread,
 
        thread__find_addr_location(thread, machine, m, MAP__VARIABLE, addr,
                                   &al);
+       if (al.map == NULL) {
+               /*
+                * some shared data regions have execute bit set which puts
+                * their mapping in the MAP__FUNCTION type array.
+                * Check there as a fallback option before dropping the sample.
+                */
+               thread__find_addr_location(thread, machine, m, MAP__FUNCTION, addr,
+                                          &al);
+       }
+
        ams->addr = addr;
        ams->al_addr = al.addr;
        ams->sym = al.sym;
@@ -1531,3 +1571,25 @@ int machine__set_current_tid(struct machine *machine, int cpu, pid_t pid,
 
        return 0;
 }
+
+int machine__get_kernel_start(struct machine *machine)
+{
+       struct map *map = machine__kernel_map(machine, MAP__FUNCTION);
+       int err = 0;
+
+       /*
+        * The only addresses above 2^63 are kernel addresses of a 64-bit
+        * kernel.  Note that addresses are unsigned so that on a 32-bit system
+        * all addresses including kernel addresses are less than 2^32.  In
+        * that case (32-bit system), if the kernel mapping is unknown, all
+        * addresses will be assumed to be in user space - see
+        * machine__kernel_ip().
+        */
+       machine->kernel_start = 1ULL << 63;
+       if (map) {
+               err = map__load(map, machine->symbol_filter);
+               if (map->start)
+                       machine->kernel_start = map->start;
+       }
+       return err;
+}
index b972824e62941fea709fdfc92dcf9bf6f80871e9..2b651a7f5d0d113c59461f4badbd35c9ad870a45 100644 (file)
@@ -4,6 +4,7 @@
 #include <sys/types.h>
 #include <linux/rbtree.h>
 #include "map.h"
+#include "dso.h"
 #include "event.h"
 
 struct addr_location;
@@ -26,15 +27,17 @@ struct machine {
        struct rb_node    rb_node;
        pid_t             pid;
        u16               id_hdr_size;
+       bool              comm_exec;
        char              *root_dir;
        struct rb_root    threads;
        struct list_head  dead_threads;
        struct thread     *last_match;
        struct vdso_info  *vdso_info;
-       struct list_head  user_dsos;
-       struct list_head  kernel_dsos;
+       struct dsos       user_dsos;
+       struct dsos       kernel_dsos;
        struct map_groups kmaps;
        struct map        *vmlinux_maps[MAP__NR_TYPES];
+       u64               kernel_start;
        symbol_filter_t   symbol_filter;
        pid_t             *current_tid;
 };
@@ -45,8 +48,26 @@ struct map *machine__kernel_map(struct machine *machine, enum map_type type)
        return machine->vmlinux_maps[type];
 }
 
+int machine__get_kernel_start(struct machine *machine);
+
+static inline u64 machine__kernel_start(struct machine *machine)
+{
+       if (!machine->kernel_start)
+               machine__get_kernel_start(machine);
+       return machine->kernel_start;
+}
+
+static inline bool machine__kernel_ip(struct machine *machine, u64 ip)
+{
+       u64 kernel_start = machine__kernel_start(machine);
+
+       return ip >= kernel_start;
+}
+
 struct thread *machine__find_thread(struct machine *machine, pid_t pid,
                                    pid_t tid);
+struct comm *machine__thread_exec_comm(struct machine *machine,
+                                      struct thread *thread);
 
 int machine__process_comm_event(struct machine *machine, union perf_event *event,
                                struct perf_sample *sample);
@@ -88,6 +109,7 @@ char *machine__mmap_name(struct machine *machine, char *bf, size_t size);
 
 void machines__set_symbol_filter(struct machines *machines,
                                 symbol_filter_t symbol_filter);
+void machines__set_comm_exec(struct machines *machines, bool comm_exec);
 
 struct machine *machine__new_host(void);
 int machine__init(struct machine *machine, const char *root_dir, pid_t pid);
index 31b8905dd863db904ec945e554939a9877841bcc..b7090596ac5086a3a36fe65b46e43cadcfe5cc7a 100644 (file)
@@ -31,6 +31,7 @@ static inline int is_anon_memory(const char *filename)
 static inline int is_no_dso_memory(const char *filename)
 {
        return !strncmp(filename, "[stack", 6) ||
+              !strncmp(filename, "/SYSV",5)   ||
               !strcmp(filename, "[heap]");
 }
 
diff --git a/tools/perf/util/ordered-events.c b/tools/perf/util/ordered-events.c
new file mode 100644 (file)
index 0000000..706ce1a
--- /dev/null
@@ -0,0 +1,245 @@
+#include <linux/list.h>
+#include <linux/compiler.h>
+#include "ordered-events.h"
+#include "evlist.h"
+#include "session.h"
+#include "asm/bug.h"
+#include "debug.h"
+
+#define pr_N(n, fmt, ...) \
+       eprintf(n, debug_ordered_events, fmt, ##__VA_ARGS__)
+
+#define pr(fmt, ...) pr_N(1, pr_fmt(fmt), ##__VA_ARGS__)
+
+static void queue_event(struct ordered_events *oe, struct ordered_event *new)
+{
+       struct ordered_event *last = oe->last;
+       u64 timestamp = new->timestamp;
+       struct list_head *p;
+
+       ++oe->nr_events;
+       oe->last = new;
+
+       pr_oe_time2(timestamp, "queue_event nr_events %u\n", oe->nr_events);
+
+       if (!last) {
+               list_add(&new->list, &oe->events);
+               oe->max_timestamp = timestamp;
+               return;
+       }
+
+       /*
+        * last event might point to some random place in the list as it's
+        * the last queued event. We expect that the new event is close to
+        * this.
+        */
+       if (last->timestamp <= timestamp) {
+               while (last->timestamp <= timestamp) {
+                       p = last->list.next;
+                       if (p == &oe->events) {
+                               list_add_tail(&new->list, &oe->events);
+                               oe->max_timestamp = timestamp;
+                               return;
+                       }
+                       last = list_entry(p, struct ordered_event, list);
+               }
+               list_add_tail(&new->list, &last->list);
+       } else {
+               while (last->timestamp > timestamp) {
+                       p = last->list.prev;
+                       if (p == &oe->events) {
+                               list_add(&new->list, &oe->events);
+                               return;
+                       }
+                       last = list_entry(p, struct ordered_event, list);
+               }
+               list_add(&new->list, &last->list);
+       }
+}
+
+#define MAX_SAMPLE_BUFFER      (64 * 1024 / sizeof(struct ordered_event))
+static struct ordered_event *alloc_event(struct ordered_events *oe)
+{
+       struct list_head *cache = &oe->cache;
+       struct ordered_event *new = NULL;
+
+       if (!list_empty(cache)) {
+               new = list_entry(cache->next, struct ordered_event, list);
+               list_del(&new->list);
+       } else if (oe->buffer) {
+               new = oe->buffer + oe->buffer_idx;
+               if (++oe->buffer_idx == MAX_SAMPLE_BUFFER)
+                       oe->buffer = NULL;
+       } else if (oe->cur_alloc_size < oe->max_alloc_size) {
+               size_t size = MAX_SAMPLE_BUFFER * sizeof(*new);
+
+               oe->buffer = malloc(size);
+               if (!oe->buffer)
+                       return NULL;
+
+               pr("alloc size %" PRIu64 "B (+%zu), max %" PRIu64 "B\n",
+                  oe->cur_alloc_size, size, oe->max_alloc_size);
+
+               oe->cur_alloc_size += size;
+               list_add(&oe->buffer->list, &oe->to_free);
+
+               /* First entry is abused to maintain the to_free list. */
+               oe->buffer_idx = 2;
+               new = oe->buffer + 1;
+       } else {
+               pr("allocation limit reached %" PRIu64 "B\n", oe->max_alloc_size);
+       }
+
+       return new;
+}
+
+struct ordered_event *
+ordered_events__new(struct ordered_events *oe, u64 timestamp)
+{
+       struct ordered_event *new;
+
+       new = alloc_event(oe);
+       if (new) {
+               new->timestamp = timestamp;
+               queue_event(oe, new);
+       }
+
+       return new;
+}
+
+void ordered_events__delete(struct ordered_events *oe, struct ordered_event *event)
+{
+       list_move(&event->list, &oe->cache);
+       oe->nr_events--;
+}
+
+static int __ordered_events__flush(struct perf_session *s,
+                                  struct perf_tool *tool)
+{
+       struct ordered_events *oe = &s->ordered_events;
+       struct list_head *head = &oe->events;
+       struct ordered_event *tmp, *iter;
+       struct perf_sample sample;
+       u64 limit = oe->next_flush;
+       u64 last_ts = oe->last ? oe->last->timestamp : 0ULL;
+       bool show_progress = limit == ULLONG_MAX;
+       struct ui_progress prog;
+       int ret;
+
+       if (!tool->ordered_events || !limit)
+               return 0;
+
+       if (show_progress)
+               ui_progress__init(&prog, oe->nr_events, "Processing time ordered events...");
+
+       list_for_each_entry_safe(iter, tmp, head, list) {
+               if (session_done())
+                       return 0;
+
+               if (iter->timestamp > limit)
+                       break;
+
+               ret = perf_evlist__parse_sample(s->evlist, iter->event, &sample);
+               if (ret)
+                       pr_err("Can't parse sample, err = %d\n", ret);
+               else {
+                       ret = perf_session__deliver_event(s, iter->event, &sample, tool,
+                                                         iter->file_offset);
+                       if (ret)
+                               return ret;
+               }
+
+               ordered_events__delete(oe, iter);
+               oe->last_flush = iter->timestamp;
+
+               if (show_progress)
+                       ui_progress__update(&prog, 1);
+       }
+
+       if (list_empty(head))
+               oe->last = NULL;
+       else if (last_ts <= limit)
+               oe->last = list_entry(head->prev, struct ordered_event, list);
+
+       return 0;
+}
+
+int ordered_events__flush(struct perf_session *s, struct perf_tool *tool,
+                         enum oe_flush how)
+{
+       struct ordered_events *oe = &s->ordered_events;
+       static const char * const str[] = {
+               "NONE",
+               "FINAL",
+               "ROUND",
+               "HALF ",
+       };
+       int err;
+
+       switch (how) {
+       case OE_FLUSH__FINAL:
+               oe->next_flush = ULLONG_MAX;
+               break;
+
+       case OE_FLUSH__HALF:
+       {
+               struct ordered_event *first, *last;
+               struct list_head *head = &oe->events;
+
+               first = list_entry(head->next, struct ordered_event, list);
+               last = oe->last;
+
+               /* Warn if we are called before any event got allocated. */
+               if (WARN_ONCE(!last || list_empty(head), "empty queue"))
+                       return 0;
+
+               oe->next_flush  = first->timestamp;
+               oe->next_flush += (last->timestamp - first->timestamp) / 2;
+               break;
+       }
+
+       case OE_FLUSH__ROUND:
+       case OE_FLUSH__NONE:
+       default:
+               break;
+       };
+
+       pr_oe_time(oe->next_flush, "next_flush - ordered_events__flush PRE  %s, nr_events %u\n",
+                  str[how], oe->nr_events);
+       pr_oe_time(oe->max_timestamp, "max_timestamp\n");
+
+       err = __ordered_events__flush(s, tool);
+
+       if (!err) {
+               if (how == OE_FLUSH__ROUND)
+                       oe->next_flush = oe->max_timestamp;
+
+               oe->last_flush_type = how;
+       }
+
+       pr_oe_time(oe->next_flush, "next_flush - ordered_events__flush POST %s, nr_events %u\n",
+                  str[how], oe->nr_events);
+       pr_oe_time(oe->last_flush, "last_flush\n");
+
+       return err;
+}
+
+void ordered_events__init(struct ordered_events *oe)
+{
+       INIT_LIST_HEAD(&oe->events);
+       INIT_LIST_HEAD(&oe->cache);
+       INIT_LIST_HEAD(&oe->to_free);
+       oe->max_alloc_size = (u64) -1;
+       oe->cur_alloc_size = 0;
+}
+
+void ordered_events__free(struct ordered_events *oe)
+{
+       while (!list_empty(&oe->to_free)) {
+               struct ordered_event *event;
+
+               event = list_entry(oe->to_free.next, struct ordered_event, list);
+               list_del(&event->list);
+               free(event);
+       }
+}
diff --git a/tools/perf/util/ordered-events.h b/tools/perf/util/ordered-events.h
new file mode 100644 (file)
index 0000000..3b2f205
--- /dev/null
@@ -0,0 +1,51 @@
+#ifndef __ORDERED_EVENTS_H
+#define __ORDERED_EVENTS_H
+
+#include <linux/types.h>
+#include "tool.h"
+
+struct perf_session;
+
+struct ordered_event {
+       u64                     timestamp;
+       u64                     file_offset;
+       union perf_event        *event;
+       struct list_head        list;
+};
+
+enum oe_flush {
+       OE_FLUSH__NONE,
+       OE_FLUSH__FINAL,
+       OE_FLUSH__ROUND,
+       OE_FLUSH__HALF,
+};
+
+struct ordered_events {
+       u64                     last_flush;
+       u64                     next_flush;
+       u64                     max_timestamp;
+       u64                     max_alloc_size;
+       u64                     cur_alloc_size;
+       struct list_head        events;
+       struct list_head        cache;
+       struct list_head        to_free;
+       struct ordered_event    *buffer;
+       struct ordered_event    *last;
+       int                     buffer_idx;
+       unsigned int            nr_events;
+       enum oe_flush           last_flush_type;
+};
+
+struct ordered_event *ordered_events__new(struct ordered_events *oe, u64 timestamp);
+void ordered_events__delete(struct ordered_events *oe, struct ordered_event *event);
+int ordered_events__flush(struct perf_session *s, struct perf_tool *tool,
+                         enum oe_flush how);
+void ordered_events__init(struct ordered_events *oe);
+void ordered_events__free(struct ordered_events *oe);
+
+static inline
+void ordered_events__set_alloc_size(struct ordered_events *oe, u64 size)
+{
+       oe->max_alloc_size = size;
+}
+#endif /* __ORDERED_EVENTS_H */
index 1e15df10a88c2c1ff7b62dbfbcc05f39ffbe4cd1..d76aa30cb1fbf6bd580497efb8f33bf09caddd61 100644 (file)
@@ -10,6 +10,7 @@
 #include "symbol.h"
 #include "cache.h"
 #include "header.h"
+#include "debug.h"
 #include <api/fs/debugfs.h>
 #include "parse-events-bison.h"
 #define YY_EXTRA_TYPE int
@@ -633,18 +634,28 @@ int parse_events_add_pmu(struct list_head *list, int *idx,
                         char *name, struct list_head *head_config)
 {
        struct perf_event_attr attr;
+       struct perf_pmu_info info;
        struct perf_pmu *pmu;
        struct perf_evsel *evsel;
-       const char *unit;
-       double scale;
 
        pmu = perf_pmu__find(name);
        if (!pmu)
                return -EINVAL;
 
-       memset(&attr, 0, sizeof(attr));
+       if (pmu->default_config) {
+               memcpy(&attr, pmu->default_config,
+                      sizeof(struct perf_event_attr));
+       } else {
+               memset(&attr, 0, sizeof(attr));
+       }
+
+       if (!head_config) {
+               attr.type = pmu->type;
+               evsel = __add_event(list, idx, &attr, NULL, pmu->cpus);
+               return evsel ? 0 : -ENOMEM;
+       }
 
-       if (perf_pmu__check_alias(pmu, head_config, &unit, &scale))
+       if (perf_pmu__check_alias(pmu, head_config, &info))
                return -EINVAL;
 
        /*
@@ -659,8 +670,8 @@ int parse_events_add_pmu(struct list_head *list, int *idx,
        evsel = __add_event(list, idx, &attr, pmu_event_name(head_config),
                            pmu->cpus);
        if (evsel) {
-               evsel->unit = unit;
-               evsel->scale = scale;
+               evsel->unit = info.unit;
+               evsel->scale = info.scale;
        }
 
        return evsel ? 0 : -ENOMEM;
@@ -973,7 +984,7 @@ int parse_filter(const struct option *opt, const char *str,
 
        if (last == NULL || last->attr.type != PERF_TYPE_TRACEPOINT) {
                fprintf(stderr,
-                       "-F option should follow a -e tracepoint option\n");
+                       "--filter option should follow a -e tracepoint option\n");
                return -1;
        }
 
@@ -1006,9 +1017,11 @@ void print_tracepoint_events(const char *subsys_glob, const char *event_glob,
        struct dirent *sys_next, *evt_next, sys_dirent, evt_dirent;
        char evt_path[MAXPATHLEN];
        char dir_path[MAXPATHLEN];
+       char sbuf[STRERR_BUFSIZE];
 
        if (debugfs_valid_mountpoint(tracing_events_path)) {
-               printf("  [ Tracepoints not available: %s ]\n", strerror(errno));
+               printf("  [ Tracepoints not available: %s ]\n",
+                       strerror_r(errno, sbuf, sizeof(sbuf)));
                return;
        }
 
index 0bc87ba46bf3f77f507116df36449655a9fbaa6f..55fab6ad609a8ccdc7f36478dc350bfcb72e5e3f 100644 (file)
@@ -210,6 +210,16 @@ PE_NAME '/' event_config '/'
        parse_events__free_terms($3);
        $$ = list;
 }
+|
+PE_NAME '/' '/'
+{
+       struct parse_events_evlist *data = _data;
+       struct list_head *list;
+
+       ALLOC_LIST(list);
+       ABORT_ON(parse_events_add_pmu(list, &data->idx, $1, NULL));
+       $$ = list;
+}
 
 value_sym:
 PE_VALUE_SYM_HW
index 7a811eb61f75fc9b00205fd778c30cc417b0f887..93a41ca96b8e0c6f0f927b20209c58c676a98384 100644 (file)
@@ -2,6 +2,8 @@
 #include <sys/types.h>
 #include <unistd.h>
 #include <stdio.h>
+#include <stdbool.h>
+#include <stdarg.h>
 #include <dirent.h>
 #include <api/fs/fs.h>
 #include <locale.h>
@@ -14,8 +16,8 @@
 
 struct perf_pmu_alias {
        char *name;
-       struct list_head terms;
-       struct list_head list;
+       struct list_head terms; /* HEAD struct parse_events_term -> list */
+       struct list_head list;  /* ELEM */
        char unit[UNIT_MAX_LEN+1];
        double scale;
 };
@@ -208,6 +210,19 @@ static int perf_pmu__new_alias(struct list_head *list, char *dir, char *name, FI
        return 0;
 }
 
+static inline bool pmu_alias_info_file(char *name)
+{
+       size_t len;
+
+       len = strlen(name);
+       if (len > 5 && !strcmp(name + len - 5, ".unit"))
+               return true;
+       if (len > 6 && !strcmp(name + len - 6, ".scale"))
+               return true;
+
+       return false;
+}
+
 /*
  * Process all the sysfs attributes located under the directory
  * specified in 'dir' parameter.
@@ -216,7 +231,6 @@ static int pmu_aliases_parse(char *dir, struct list_head *head)
 {
        struct dirent *evt_ent;
        DIR *event_dir;
-       size_t len;
        int ret = 0;
 
        event_dir = opendir(dir);
@@ -232,13 +246,9 @@ static int pmu_aliases_parse(char *dir, struct list_head *head)
                        continue;
 
                /*
-                * skip .unit and .scale info files
-                * parsed in perf_pmu__new_alias()
+                * skip info files parsed in perf_pmu__new_alias()
                 */
-               len = strlen(name);
-               if (len > 5 && !strcmp(name + len - 5, ".unit"))
-                       continue;
-               if (len > 6 && !strcmp(name + len - 6, ".scale"))
+               if (pmu_alias_info_file(name))
                        continue;
 
                snprintf(path, PATH_MAX, "%s/%s", dir, name);
@@ -387,6 +397,12 @@ static struct cpu_map *pmu_cpumask(const char *name)
        return cpus;
 }
 
+struct perf_event_attr *__attribute__((weak))
+perf_pmu__get_default_config(struct perf_pmu *pmu __maybe_unused)
+{
+       return NULL;
+}
+
 static struct perf_pmu *pmu_lookup(const char *name)
 {
        struct perf_pmu *pmu;
@@ -421,6 +437,9 @@ static struct perf_pmu *pmu_lookup(const char *name)
        pmu->name = strdup(name);
        pmu->type = type;
        list_add_tail(&pmu->list, &pmus);
+
+       pmu->default_config = perf_pmu__get_default_config(pmu);
+
        return pmu;
 }
 
@@ -479,28 +498,24 @@ pmu_find_format(struct list_head *formats, char *name)
 }
 
 /*
- * Returns value based on the format definition (format parameter)
+ * Sets value based on the format definition (format parameter)
  * and unformated value (value parameter).
- *
- * TODO maybe optimize a little ;)
  */
-static __u64 pmu_format_value(unsigned long *format, __u64 value)
+static void pmu_format_value(unsigned long *format, __u64 value, __u64 *v,
+                            bool zero)
 {
        unsigned long fbit, vbit;
-       __u64 v = 0;
 
        for (fbit = 0, vbit = 0; fbit < PERF_PMU_FORMAT_BITS; fbit++) {
 
                if (!test_bit(fbit, format))
                        continue;
 
-               if (!(value & (1llu << vbit++)))
-                       continue;
-
-               v |= (1llu << fbit);
+               if (value & (1llu << vbit++))
+                       *v |= (1llu << fbit);
+               else if (zero)
+                       *v &= ~(1llu << fbit);
        }
-
-       return v;
 }
 
 /*
@@ -509,7 +524,8 @@ static __u64 pmu_format_value(unsigned long *format, __u64 value)
  */
 static int pmu_config_term(struct list_head *formats,
                           struct perf_event_attr *attr,
-                          struct parse_events_term *term)
+                          struct parse_events_term *term,
+                          bool zero)
 {
        struct perf_pmu_format *format;
        __u64 *vp;
@@ -548,18 +564,19 @@ static int pmu_config_term(struct list_head *formats,
         * non-hardcoded terms, here's the place to translate
         * them into value.
         */
-       *vp |= pmu_format_value(format->bits, term->val.num);
+       pmu_format_value(format->bits, term->val.num, vp, zero);
        return 0;
 }
 
 int perf_pmu__config_terms(struct list_head *formats,
                           struct perf_event_attr *attr,
-                          struct list_head *head_terms)
+                          struct list_head *head_terms,
+                          bool zero)
 {
        struct parse_events_term *term;
 
        list_for_each_entry(term, head_terms, list)
-               if (pmu_config_term(formats, attr, term))
+               if (pmu_config_term(formats, attr, term, zero))
                        return -EINVAL;
 
        return 0;
@@ -573,8 +590,10 @@ int perf_pmu__config_terms(struct list_head *formats,
 int perf_pmu__config(struct perf_pmu *pmu, struct perf_event_attr *attr,
                     struct list_head *head_terms)
 {
+       bool zero = !!pmu->default_config;
+
        attr->type = pmu->type;
-       return perf_pmu__config_terms(&pmu->format, attr, head_terms);
+       return perf_pmu__config_terms(&pmu->format, attr, head_terms, zero);
 }
 
 static struct perf_pmu_alias *pmu_find_alias(struct perf_pmu *pmu,
@@ -634,7 +653,7 @@ static int check_unit_scale(struct perf_pmu_alias *alias,
  * defined for the alias
  */
 int perf_pmu__check_alias(struct perf_pmu *pmu, struct list_head *head_terms,
-                         const char **unit, double *scale)
+                         struct perf_pmu_info *info)
 {
        struct parse_events_term *term, *h;
        struct perf_pmu_alias *alias;
@@ -644,8 +663,8 @@ int perf_pmu__check_alias(struct perf_pmu *pmu, struct list_head *head_terms,
         * Mark unit and scale as not set
         * (different from default values, see below)
         */
-       *unit   = NULL;
-       *scale  = 0.0;
+       info->unit   = NULL;
+       info->scale  = 0.0;
 
        list_for_each_entry_safe(term, h, head_terms, list) {
                alias = pmu_find_alias(pmu, term);
@@ -655,7 +674,7 @@ int perf_pmu__check_alias(struct perf_pmu *pmu, struct list_head *head_terms,
                if (ret)
                        return ret;
 
-               ret = check_unit_scale(alias, unit, scale);
+               ret = check_unit_scale(alias, &info->unit, &info->scale);
                if (ret)
                        return ret;
 
@@ -668,11 +687,11 @@ int perf_pmu__check_alias(struct perf_pmu *pmu, struct list_head *head_terms,
         * set defaults as for evsel
         * unit cannot left to NULL
         */
-       if (*unit == NULL)
-               *unit   = "";
+       if (info->unit == NULL)
+               info->unit   = "";
 
-       if (*scale == 0.0)
-               *scale  = 1.0;
+       if (info->scale == 0.0)
+               info->scale  = 1.0;
 
        return 0;
 }
@@ -794,3 +813,39 @@ bool pmu_have_event(const char *pname, const char *name)
        }
        return false;
 }
+
+static FILE *perf_pmu__open_file(struct perf_pmu *pmu, const char *name)
+{
+       struct stat st;
+       char path[PATH_MAX];
+       const char *sysfs;
+
+       sysfs = sysfs__mountpoint();
+       if (!sysfs)
+               return NULL;
+
+       snprintf(path, PATH_MAX,
+                "%s" EVENT_SOURCE_DEVICE_PATH "%s/%s", sysfs, pmu->name, name);
+
+       if (stat(path, &st) < 0)
+               return NULL;
+
+       return fopen(path, "r");
+}
+
+int perf_pmu__scan_file(struct perf_pmu *pmu, const char *name, const char *fmt,
+                       ...)
+{
+       va_list args;
+       FILE *file;
+       int ret = EOF;
+
+       va_start(args, fmt);
+       file = perf_pmu__open_file(pmu, name);
+       if (file) {
+               ret = vfscanf(file, fmt, args);
+               fclose(file);
+       }
+       va_end(args);
+       return ret;
+}
index c14a543ce1f3b563a6debfb0879c910003a2ac15..fe90a012c003b18c07ec15bdf3c4f1ffd13224d0 100644 (file)
@@ -13,13 +13,21 @@ enum {
 
 #define PERF_PMU_FORMAT_BITS 64
 
+struct perf_event_attr;
+
 struct perf_pmu {
        char *name;
        __u32 type;
+       struct perf_event_attr *default_config;
        struct cpu_map *cpus;
-       struct list_head format;
-       struct list_head aliases;
-       struct list_head list;
+       struct list_head format;  /* HEAD struct perf_pmu_format -> list */
+       struct list_head aliases; /* HEAD struct perf_pmu_alias -> list */
+       struct list_head list;    /* ELEM */
+};
+
+struct perf_pmu_info {
+       const char *unit;
+       double scale;
 };
 
 struct perf_pmu *perf_pmu__find(const char *name);
@@ -27,9 +35,10 @@ int perf_pmu__config(struct perf_pmu *pmu, struct perf_event_attr *attr,
                     struct list_head *head_terms);
 int perf_pmu__config_terms(struct list_head *formats,
                           struct perf_event_attr *attr,
-                          struct list_head *head_terms);
+                          struct list_head *head_terms,
+                          bool zero);
 int perf_pmu__check_alias(struct perf_pmu *pmu, struct list_head *head_terms,
-                         const char **unit, double *scale);
+                         struct perf_pmu_info *info);
 struct list_head *perf_pmu__alias(struct perf_pmu *pmu,
                                  struct list_head *head_terms);
 int perf_pmu_wrap(void);
@@ -45,5 +54,11 @@ struct perf_pmu *perf_pmu__scan(struct perf_pmu *pmu);
 void print_pmu_events(const char *event_glob, bool name_only);
 bool pmu_have_event(const char *pname, const char *name);
 
+int perf_pmu__scan_file(struct perf_pmu *pmu, const char *name, const char *fmt,
+                       ...) __attribute__((format(scanf, 3, 4)));
+
 int perf_pmu__test(void);
+
+struct perf_event_attr *perf_pmu__get_default_config(struct perf_pmu *pmu);
+
 #endif /* __PMU_H */
index 9a0a1839a3772689e0dce818a5c16807edc6c10f..c150ca4343eb216c81244abb73bec70703f142ea 100644 (file)
@@ -79,7 +79,7 @@ static int init_symbol_maps(bool user_only)
        int ret;
 
        symbol_conf.sort_by_name = true;
-       ret = symbol__init();
+       ret = symbol__init(NULL);
        if (ret < 0) {
                pr_debug("Failed to init symbol map.\n");
                goto out;
@@ -184,7 +184,8 @@ static struct dso *kernel_get_module_dso(const char *module)
        const char *vmlinux_name;
 
        if (module) {
-               list_for_each_entry(dso, &host_machine->kernel_dsos, node) {
+               list_for_each_entry(dso, &host_machine->kernel_dsos.head,
+                                   node) {
                        if (strncmp(dso->short_name + 1, module,
                                    dso->short_name_len - 2) == 0)
                                goto found;
@@ -258,21 +259,33 @@ static void clear_probe_trace_events(struct probe_trace_event *tevs, int ntevs)
 #ifdef HAVE_DWARF_SUPPORT
 
 /* Open new debuginfo of given module */
-static struct debuginfo *open_debuginfo(const char *module)
+static struct debuginfo *open_debuginfo(const char *module, bool silent)
 {
        const char *path = module;
+       struct debuginfo *ret;
 
        if (!module || !strchr(module, '/')) {
                path = kernel_get_module_path(module);
                if (!path) {
-                       pr_err("Failed to find path of %s module.\n",
-                              module ?: "kernel");
+                       if (!silent)
+                               pr_err("Failed to find path of %s module.\n",
+                                      module ?: "kernel");
                        return NULL;
                }
        }
-       return debuginfo__new(path);
+       ret = debuginfo__new(path);
+       if (!ret && !silent) {
+               pr_warning("The %s file has no debug information.\n", path);
+               if (!module || !strtailcmp(path, ".ko"))
+                       pr_warning("Rebuild with CONFIG_DEBUG_INFO=y, ");
+               else
+                       pr_warning("Rebuild with -g, ");
+               pr_warning("or install an appropriate debuginfo package.\n");
+       }
+       return ret;
 }
 
+
 static int get_text_start_address(const char *exec, unsigned long *address)
 {
        Elf *elf;
@@ -333,15 +346,13 @@ static int find_perf_probe_point_from_dwarf(struct probe_trace_point *tp,
        pr_debug("try to find information at %" PRIx64 " in %s\n", addr,
                 tp->module ? : "kernel");
 
-       dinfo = open_debuginfo(tp->module);
+       dinfo = open_debuginfo(tp->module, verbose == 0);
        if (dinfo) {
                ret = debuginfo__find_probe_point(dinfo,
                                                 (unsigned long)addr, pp);
                debuginfo__delete(dinfo);
-       } else {
-               pr_debug("Failed to open debuginfo at 0x%" PRIx64 "\n", addr);
+       } else
                ret = -ENOENT;
-       }
 
        if (ret > 0) {
                pp->retprobe = tp->retprobe;
@@ -457,13 +468,11 @@ static int try_to_find_probe_trace_events(struct perf_probe_event *pev,
        struct debuginfo *dinfo;
        int ntevs, ret = 0;
 
-       dinfo = open_debuginfo(target);
+       dinfo = open_debuginfo(target, !need_dwarf);
 
        if (!dinfo) {
-               if (need_dwarf) {
-                       pr_warning("Failed to open debuginfo file.\n");
+               if (need_dwarf)
                        return -ENOENT;
-               }
                pr_debug("Could not open debuginfo. Try to use symbols.\n");
                return 0;
        }
@@ -565,7 +574,7 @@ static int get_real_path(const char *raw_path, const char *comp_dir,
 
 static int __show_one_line(FILE *fp, int l, bool skip, bool show_num)
 {
-       char buf[LINEBUF_SIZE];
+       char buf[LINEBUF_SIZE], sbuf[STRERR_BUFSIZE];
        const char *color = show_num ? "" : PERF_COLOR_BLUE;
        const char *prefix = NULL;
 
@@ -585,7 +594,8 @@ static int __show_one_line(FILE *fp, int l, bool skip, bool show_num)
        return 1;
 error:
        if (ferror(fp)) {
-               pr_warning("File read error: %s\n", strerror(errno));
+               pr_warning("File read error: %s\n",
+                          strerror_r(errno, sbuf, sizeof(sbuf)));
                return -1;
        }
        return 0;
@@ -618,13 +628,12 @@ static int __show_line_range(struct line_range *lr, const char *module)
        FILE *fp;
        int ret;
        char *tmp;
+       char sbuf[STRERR_BUFSIZE];
 
        /* Search a line range */
-       dinfo = open_debuginfo(module);
-       if (!dinfo) {
-               pr_warning("Failed to open debuginfo file.\n");
+       dinfo = open_debuginfo(module, false);
+       if (!dinfo)
                return -ENOENT;
-       }
 
        ret = debuginfo__find_line_range(dinfo, lr);
        debuginfo__delete(dinfo);
@@ -656,7 +665,7 @@ static int __show_line_range(struct line_range *lr, const char *module)
        fp = fopen(lr->path, "r");
        if (fp == NULL) {
                pr_warning("Failed to open %s: %s\n", lr->path,
-                          strerror(errno));
+                          strerror_r(errno, sbuf, sizeof(sbuf)));
                return -errno;
        }
        /* Skip to starting line number */
@@ -689,11 +698,11 @@ end:
        return ret;
 }
 
-int show_line_range(struct line_range *lr, const char *module)
+int show_line_range(struct line_range *lr, const char *module, bool user)
 {
        int ret;
 
-       ret = init_symbol_maps(false);
+       ret = init_symbol_maps(user);
        if (ret < 0)
                return ret;
        ret = __show_line_range(lr, module);
@@ -768,13 +777,12 @@ int show_available_vars(struct perf_probe_event *pevs, int npevs,
        int i, ret = 0;
        struct debuginfo *dinfo;
 
-       ret = init_symbol_maps(false);
+       ret = init_symbol_maps(pevs->uprobes);
        if (ret < 0)
                return ret;
 
-       dinfo = open_debuginfo(module);
+       dinfo = open_debuginfo(module, false);
        if (!dinfo) {
-               pr_warning("Failed to open debuginfo file.\n");
                ret = -ENOENT;
                goto out;
        }
@@ -815,7 +823,8 @@ static int try_to_find_probe_trace_events(struct perf_probe_event *pev,
 }
 
 int show_line_range(struct line_range *lr __maybe_unused,
-                   const char *module __maybe_unused)
+                   const char *module __maybe_unused,
+                   bool user __maybe_unused)
 {
        pr_warning("Debuginfo-analysis is not supported.\n");
        return -ENOSYS;
@@ -1405,8 +1414,7 @@ int synthesize_perf_probe_arg(struct perf_probe_arg *pa, char *buf, size_t len)
 
        return tmp - buf;
 error:
-       pr_debug("Failed to synthesize perf probe argument: %s\n",
-                strerror(-ret));
+       pr_debug("Failed to synthesize perf probe argument: %d\n", ret);
        return ret;
 }
 
@@ -1455,8 +1463,7 @@ static char *synthesize_perf_probe_point(struct perf_probe_point *pp)
 
        return buf;
 error:
-       pr_debug("Failed to synthesize perf probe point: %s\n",
-                strerror(-ret));
+       pr_debug("Failed to synthesize perf probe point: %d\n", ret);
        free(buf);
        return NULL;
 }
@@ -1780,10 +1787,11 @@ static void clear_probe_trace_event(struct probe_trace_event *tev)
        memset(tev, 0, sizeof(*tev));
 }
 
-static void print_warn_msg(const char *file, bool is_kprobe)
+static void print_open_warning(int err, bool is_kprobe)
 {
+       char sbuf[STRERR_BUFSIZE];
 
-       if (errno == ENOENT) {
+       if (err == -ENOENT) {
                const char *config;
 
                if (!is_kprobe)
@@ -1791,25 +1799,43 @@ static void print_warn_msg(const char *file, bool is_kprobe)
                else
                        config = "CONFIG_KPROBE_EVENTS";
 
-               pr_warning("%s file does not exist - please rebuild kernel"
-                               " with %s.\n", file, config);
-       } else
-               pr_warning("Failed to open %s file: %s\n", file,
-                               strerror(errno));
+               pr_warning("%cprobe_events file does not exist"
+                          " - please rebuild kernel with %s.\n",
+                          is_kprobe ? 'k' : 'u', config);
+       } else if (err == -ENOTSUP)
+               pr_warning("Debugfs is not mounted.\n");
+       else
+               pr_warning("Failed to open %cprobe_events: %s\n",
+                          is_kprobe ? 'k' : 'u',
+                          strerror_r(-err, sbuf, sizeof(sbuf)));
+}
+
+static void print_both_open_warning(int kerr, int uerr)
+{
+       /* Both kprobes and uprobes are disabled, warn it. */
+       if (kerr == -ENOTSUP && uerr == -ENOTSUP)
+               pr_warning("Debugfs is not mounted.\n");
+       else if (kerr == -ENOENT && uerr == -ENOENT)
+               pr_warning("Please rebuild kernel with CONFIG_KPROBE_EVENTS "
+                          "or/and CONFIG_UPROBE_EVENTS.\n");
+       else {
+               char sbuf[STRERR_BUFSIZE];
+               pr_warning("Failed to open kprobe events: %s.\n",
+                          strerror_r(-kerr, sbuf, sizeof(sbuf)));
+               pr_warning("Failed to open uprobe events: %s.\n",
+                          strerror_r(-uerr, sbuf, sizeof(sbuf)));
+       }
 }
 
-static int open_probe_events(const char *trace_file, bool readwrite,
-                               bool is_kprobe)
+static int open_probe_events(const char *trace_file, bool readwrite)
 {
        char buf[PATH_MAX];
        const char *__debugfs;
        int ret;
 
        __debugfs = debugfs_find_mountpoint();
-       if (__debugfs == NULL) {
-               pr_warning("Debugfs is not mounted.\n");
-               return -ENOENT;
-       }
+       if (__debugfs == NULL)
+               return -ENOTSUP;
 
        ret = e_snprintf(buf, PATH_MAX, "%s/%s", __debugfs, trace_file);
        if (ret >= 0) {
@@ -1820,19 +1846,19 @@ static int open_probe_events(const char *trace_file, bool readwrite,
                        ret = open(buf, O_RDONLY, 0);
 
                if (ret < 0)
-                       print_warn_msg(buf, is_kprobe);
+                       ret = -errno;
        }
        return ret;
 }
 
 static int open_kprobe_events(bool readwrite)
 {
-       return open_probe_events("tracing/kprobe_events", readwrite, true);
+       return open_probe_events("tracing/kprobe_events", readwrite);
 }
 
 static int open_uprobe_events(bool readwrite)
 {
-       return open_probe_events("tracing/uprobe_events", readwrite, false);
+       return open_probe_events("tracing/uprobe_events", readwrite);
 }
 
 /* Get raw string list of current kprobe_events  or uprobe_events */
@@ -1857,7 +1883,7 @@ static struct strlist *get_probe_trace_command_rawlist(int fd)
                        p[idx] = '\0';
                ret = strlist__add(sl, buf);
                if (ret < 0) {
-                       pr_debug("strlist__add failed: %s\n", strerror(-ret));
+                       pr_debug("strlist__add failed (%d)\n", ret);
                        strlist__delete(sl);
                        return NULL;
                }
@@ -1916,7 +1942,7 @@ static int __show_perf_probe_events(int fd, bool is_kprobe)
 
        rawlist = get_probe_trace_command_rawlist(fd);
        if (!rawlist)
-               return -ENOENT;
+               return -ENOMEM;
 
        strlist__for_each(ent, rawlist) {
                ret = parse_probe_trace_command(ent->s, &tev);
@@ -1940,27 +1966,34 @@ static int __show_perf_probe_events(int fd, bool is_kprobe)
 /* List up current perf-probe events */
 int show_perf_probe_events(void)
 {
-       int fd, ret;
+       int kp_fd, up_fd, ret;
 
        setup_pager();
-       fd = open_kprobe_events(false);
-
-       if (fd < 0)
-               return fd;
 
        ret = init_symbol_maps(false);
        if (ret < 0)
                return ret;
 
-       ret = __show_perf_probe_events(fd, true);
-       close(fd);
+       kp_fd = open_kprobe_events(false);
+       if (kp_fd >= 0) {
+               ret = __show_perf_probe_events(kp_fd, true);
+               close(kp_fd);
+               if (ret < 0)
+                       goto out;
+       }
 
-       fd = open_uprobe_events(false);
-       if (fd >= 0) {
-               ret = __show_perf_probe_events(fd, false);
-               close(fd);
+       up_fd = open_uprobe_events(false);
+       if (kp_fd < 0 && up_fd < 0) {
+               print_both_open_warning(kp_fd, up_fd);
+               ret = kp_fd;
+               goto out;
        }
 
+       if (up_fd >= 0) {
+               ret = __show_perf_probe_events(up_fd, false);
+               close(up_fd);
+       }
+out:
        exit_symbol_maps();
        return ret;
 }
@@ -1976,6 +2009,8 @@ static struct strlist *get_probe_trace_event_names(int fd, bool include_group)
 
        memset(&tev, 0, sizeof(tev));
        rawlist = get_probe_trace_command_rawlist(fd);
+       if (!rawlist)
+               return NULL;
        sl = strlist__new(true, NULL);
        strlist__for_each(ent, rawlist) {
                ret = parse_probe_trace_command(ent->s, &tev);
@@ -2005,6 +2040,7 @@ static int write_probe_trace_event(int fd, struct probe_trace_event *tev)
 {
        int ret = 0;
        char *buf = synthesize_probe_trace_command(tev);
+       char sbuf[STRERR_BUFSIZE];
 
        if (!buf) {
                pr_debug("Failed to synthesize probe trace event.\n");
@@ -2016,7 +2052,7 @@ static int write_probe_trace_event(int fd, struct probe_trace_event *tev)
                ret = write(fd, buf, strlen(buf));
                if (ret <= 0)
                        pr_warning("Failed to write event: %s\n",
-                                  strerror(errno));
+                                  strerror_r(errno, sbuf, sizeof(sbuf)));
        }
        free(buf);
        return ret;
@@ -2030,7 +2066,7 @@ static int get_new_event_name(char *buf, size_t len, const char *base,
        /* Try no suffix */
        ret = e_snprintf(buf, len, "%s", base);
        if (ret < 0) {
-               pr_debug("snprintf() failed: %s\n", strerror(-ret));
+               pr_debug("snprintf() failed: %d\n", ret);
                return ret;
        }
        if (!strlist__has_entry(namelist, buf))
@@ -2046,7 +2082,7 @@ static int get_new_event_name(char *buf, size_t len, const char *base,
        for (i = 1; i < MAX_EVENT_INDEX; i++) {
                ret = e_snprintf(buf, len, "%s_%d", base, i);
                if (ret < 0) {
-                       pr_debug("snprintf() failed: %s\n", strerror(-ret));
+                       pr_debug("snprintf() failed: %d\n", ret);
                        return ret;
                }
                if (!strlist__has_entry(namelist, buf))
@@ -2075,8 +2111,11 @@ static int __add_probe_trace_events(struct perf_probe_event *pev,
        else
                fd = open_kprobe_events(true);
 
-       if (fd < 0)
+       if (fd < 0) {
+               print_open_warning(fd, !pev->uprobes);
                return fd;
+       }
+
        /* Get current event names */
        namelist = get_probe_trace_event_names(fd, false);
        if (!namelist) {
@@ -2408,7 +2447,8 @@ static int __del_trace_probe_event(int fd, struct str_node *ent)
        printf("Removed event: %s\n", ent->s);
        return 0;
 error:
-       pr_warning("Failed to delete event: %s\n", strerror(-ret));
+       pr_warning("Failed to delete event: %s\n",
+                  strerror_r(-ret, buf, sizeof(buf)));
        return ret;
 }
 
@@ -2449,15 +2489,18 @@ int del_perf_probe_events(struct strlist *dellist)
 
        /* Get current event names */
        kfd = open_kprobe_events(true);
-       if (kfd < 0)
-               return kfd;
+       if (kfd >= 0)
+               namelist = get_probe_trace_event_names(kfd, true);
 
-       namelist = get_probe_trace_event_names(kfd, true);
        ufd = open_uprobe_events(true);
-
        if (ufd >= 0)
                unamelist = get_probe_trace_event_names(ufd, true);
 
+       if (kfd < 0 && ufd < 0) {
+               print_both_open_warning(kfd, ufd);
+               goto error;
+       }
+
        if (namelist == NULL && unamelist == NULL)
                goto error;
 
index 776c9347a3b64252e2f4c9b30b4710b580923b72..e01e9943139ff3b828ab8820aad9a5add4f34376 100644 (file)
@@ -128,7 +128,8 @@ extern int add_perf_probe_events(struct perf_probe_event *pevs, int npevs,
                                 bool force_add);
 extern int del_perf_probe_events(struct strlist *dellist);
 extern int show_perf_probe_events(void);
-extern int show_line_range(struct line_range *lr, const char *module);
+extern int show_line_range(struct line_range *lr, const char *module,
+                          bool user);
 extern int show_available_vars(struct perf_probe_event *pevs, int npevs,
                               int max_probe_points, const char *module,
                               struct strfilter *filter, bool externs);
index dca9145d704c948123a937ded474a97a60621aff..c7918f83b300086649f522bc5f663d9a5a88a5dc 100644 (file)
@@ -281,6 +281,7 @@ static int convert_variable_type(Dwarf_Die *vr_die,
        struct probe_trace_arg_ref **ref_ptr = &tvar->ref;
        Dwarf_Die type;
        char buf[16];
+       char sbuf[STRERR_BUFSIZE];
        int bsize, boffs, total;
        int ret;
 
@@ -367,7 +368,7 @@ formatted:
                if (ret >= 16)
                        ret = -E2BIG;
                pr_warning("Failed to convert variable type: %s\n",
-                          strerror(-ret));
+                          strerror_r(-ret, sbuf, sizeof(sbuf)));
                return ret;
        }
        tvar->type = strdup(buf);
@@ -608,14 +609,18 @@ static int convert_to_trace_point(Dwarf_Die *sp_die, Dwfl_Module *mod,
                return -EINVAL;
        }
 
-       /* Get an appropriate symbol from symtab */
-       symbol = dwfl_module_addrsym(mod, paddr, &sym, NULL);
+       symbol = dwarf_diename(sp_die);
        if (!symbol) {
-               pr_warning("Failed to find symbol at 0x%lx\n",
-                          (unsigned long)paddr);
-               return -ENOENT;
+               /* Try to get the symbol name from symtab */
+               symbol = dwfl_module_addrsym(mod, paddr, &sym, NULL);
+               if (!symbol) {
+                       pr_warning("Failed to find symbol at 0x%lx\n",
+                                  (unsigned long)paddr);
+                       return -ENOENT;
+               }
+               eaddr = sym.st_value;
        }
-       tp->offset = (unsigned long)(paddr - sym.st_value);
+       tp->offset = (unsigned long)(paddr - eaddr);
        tp->address = (unsigned long)paddr;
        tp->symbol = strdup(symbol);
        if (!tp->symbol)
@@ -779,10 +784,12 @@ static int find_lazy_match_lines(struct intlist *list,
        size_t line_len;
        ssize_t len;
        int count = 0, linenum = 1;
+       char sbuf[STRERR_BUFSIZE];
 
        fp = fopen(fname, "r");
        if (!fp) {
-               pr_warning("Failed to open %s: %s\n", fname, strerror(errno));
+               pr_warning("Failed to open %s: %s\n", fname,
+                          strerror_r(errno, sbuf, sizeof(sbuf)));
                return -errno;
        }
 
index 12aa9b0d0ba1769debff0615c0158e2f1c890c21..3dda85ca50c1d25bc81ff2457f9d624d774f754b 100644 (file)
@@ -736,7 +736,7 @@ static PyObject *pyrf_evlist__poll(struct pyrf_evlist *pevlist,
        if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|i", kwlist, &timeout))
                return NULL;
 
-       n = poll(evlist->pollfd, evlist->nr_fds, timeout);
+       n = perf_evlist__poll(evlist, timeout);
        if (n < 0) {
                PyErr_SetFromErrno(PyExc_OSError);
                return NULL;
@@ -753,9 +753,9 @@ static PyObject *pyrf_evlist__get_pollfd(struct pyrf_evlist *pevlist,
         PyObject *list = PyList_New(0);
        int i;
 
-       for (i = 0; i < evlist->nr_fds; ++i) {
+       for (i = 0; i < evlist->pollfd.nr; ++i) {
                PyObject *file;
-               FILE *fp = fdopen(evlist->pollfd[i].fd, "r");
+               FILE *fp = fdopen(evlist->pollfd.entries[i].fd, "r");
 
                if (fp == NULL)
                        goto free_list;
index fe8079edbdc11a239ee26524ac51d04b3d40f895..cf69325b985f15534fcb54303b98cfd5409d6e50 100644 (file)
@@ -14,6 +14,7 @@ static int perf_do_probe_api(setup_probe_fn_t fn, int cpu, const char *str)
        struct perf_evsel *evsel;
        unsigned long flags = perf_event_open_cloexec_flag();
        int err = -EAGAIN, fd;
+       static pid_t pid = -1;
 
        evlist = perf_evlist__new();
        if (!evlist)
@@ -24,14 +25,22 @@ static int perf_do_probe_api(setup_probe_fn_t fn, int cpu, const char *str)
 
        evsel = perf_evlist__first(evlist);
 
-       fd = sys_perf_event_open(&evsel->attr, -1, cpu, -1, flags);
-       if (fd < 0)
-               goto out_delete;
+       while (1) {
+               fd = sys_perf_event_open(&evsel->attr, pid, cpu, -1, flags);
+               if (fd < 0) {
+                       if (pid == -1 && errno == EACCES) {
+                               pid = 0;
+                               continue;
+                       }
+                       goto out_delete;
+               }
+               break;
+       }
        close(fd);
 
        fn(evsel);
 
-       fd = sys_perf_event_open(&evsel->attr, -1, cpu, -1, flags);
+       fd = sys_perf_event_open(&evsel->attr, pid, cpu, -1, flags);
        if (fd < 0) {
                if (errno == EINVAL)
                        err = -EINVAL;
@@ -47,7 +56,7 @@ out_delete:
 
 static bool perf_probe_api(setup_probe_fn_t fn)
 {
-       const char *try[] = {"cycles:u", "instructions:u", "cpu-clock", NULL};
+       const char *try[] = {"cycles:u", "instructions:u", "cpu-clock:u", NULL};
        struct cpu_map *cpus;
        int cpu, ret, i = 0;
 
@@ -106,7 +115,7 @@ void perf_evlist__config(struct perf_evlist *evlist, struct record_opts *opts)
 
        evlist__for_each(evlist, evsel) {
                perf_evsel__config(evsel, opts);
-               if (!evsel->idx && use_comm_exec)
+               if (evsel->tracking && use_comm_exec)
                        evsel->attr.comm_exec = 1;
        }
 
@@ -201,6 +210,7 @@ bool perf_evlist__can_select_event(struct perf_evlist *evlist, const char *str)
        struct perf_evsel *evsel;
        int err, fd, cpu;
        bool ret = false;
+       pid_t pid = -1;
 
        temp_evlist = perf_evlist__new();
        if (!temp_evlist)
@@ -221,12 +231,20 @@ bool perf_evlist__can_select_event(struct perf_evlist *evlist, const char *str)
                cpu = evlist->cpus->map[0];
        }
 
-       fd = sys_perf_event_open(&evsel->attr, -1, cpu, -1,
-                                perf_event_open_cloexec_flag());
-       if (fd >= 0) {
-               close(fd);
-               ret = true;
+       while (1) {
+               fd = sys_perf_event_open(&evsel->attr, pid, cpu, -1,
+                                        perf_event_open_cloexec_flag());
+               if (fd < 0) {
+                       if (pid == -1 && errno == EACCES) {
+                               pid = 0;
+                               continue;
+                       }
+                       goto out_delete;
+               }
+               break;
        }
+       close(fd);
+       ret = true;
 
 out_delete:
        perf_evlist__delete(temp_evlist);
index da8e9b285f5158d24d67d9722265187504bd95d5..34622b53e733b53b8d47415c67d408900a3e504f 100644 (file)
@@ -1,6 +1,7 @@
 #include "cache.h"
 #include "run-command.h"
 #include "exec_cmd.h"
+#include "debug.h"
 
 static inline void close_pair(int fd[2])
 {
@@ -19,6 +20,7 @@ int start_command(struct child_process *cmd)
 {
        int need_in, need_out, need_err;
        int fdin[2], fdout[2], fderr[2];
+       char sbuf[STRERR_BUFSIZE];
 
        /*
         * In case of errors we must keep the promise to close FDs
@@ -99,7 +101,7 @@ int start_command(struct child_process *cmd)
 
                if (cmd->dir && chdir(cmd->dir))
                        die("exec %s: cd to %s failed (%s)", cmd->argv[0],
-                           cmd->dir, strerror(errno));
+                           cmd->dir, strerror_r(errno, sbuf, sizeof(sbuf)));
                if (cmd->env) {
                        for (; *cmd->env; cmd->env++) {
                                if (strchr(*cmd->env, '='))
@@ -153,6 +155,8 @@ int start_command(struct child_process *cmd)
 
 static int wait_or_whine(pid_t pid)
 {
+       char sbuf[STRERR_BUFSIZE];
+
        for (;;) {
                int status, code;
                pid_t waiting = waitpid(pid, &status, 0);
@@ -160,7 +164,8 @@ static int wait_or_whine(pid_t pid)
                if (waiting < 0) {
                        if (errno == EINTR)
                                continue;
-                       error("waitpid failed (%s)", strerror(errno));
+                       error("waitpid failed (%s)",
+                             strerror_r(errno, sbuf, sizeof(sbuf)));
                        return -ERR_RUN_COMMAND_WAITPID;
                }
                if (waiting != pid)
index b2dba9c0a3a1843e91d0095e71845af45db1d5df..0a01bac4ce023e136ef15357e80360a90f35d40e 100644 (file)
@@ -432,6 +432,11 @@ error:
        return err;
 }
 
+static int perl_flush_script(void)
+{
+       return 0;
+}
+
 /*
  * Stop trace script
  */
@@ -633,6 +638,7 @@ static int perl_generate_script(struct pevent *pevent, const char *outfile)
 struct scripting_ops perl_scripting_ops = {
        .name = "Perl",
        .start_script = perl_start_script,
+       .flush_script = perl_flush_script,
        .stop_script = perl_stop_script,
        .process_event = perl_process_event,
        .generate_script = perl_generate_script,
index cbce2545da455fba34631818d5c08be7e8d26664..56ba07cce549ef5b5a79c2f2ae31e0799f245907 100644 (file)
@@ -73,6 +73,35 @@ static void pydict_set_item_string_decref(PyObject *dict, const char *key, PyObj
        Py_DECREF(val);
 }
 
+static PyObject *get_handler(const char *handler_name)
+{
+       PyObject *handler;
+
+       handler = PyDict_GetItemString(main_dict, handler_name);
+       if (handler && !PyCallable_Check(handler))
+               return NULL;
+       return handler;
+}
+
+static void call_object(PyObject *handler, PyObject *args, const char *die_msg)
+{
+       PyObject *retval;
+
+       retval = PyObject_CallObject(handler, args);
+       if (retval == NULL)
+               handler_call_die(die_msg);
+       Py_DECREF(retval);
+}
+
+static void try_call_object(const char *handler_name, PyObject *args)
+{
+       PyObject *handler;
+
+       handler = get_handler(handler_name);
+       if (handler)
+               call_object(handler, args, handler_name);
+}
+
 static void define_value(enum print_arg_type field_type,
                         const char *ev_name,
                         const char *field_name,
@@ -80,7 +109,7 @@ static void define_value(enum print_arg_type field_type,
                         const char *field_str)
 {
        const char *handler_name = "define_flag_value";
-       PyObject *handler, *t, *retval;
+       PyObject *t;
        unsigned long long value;
        unsigned n = 0;
 
@@ -98,13 +127,7 @@ static void define_value(enum print_arg_type field_type,
        PyTuple_SetItem(t, n++, PyInt_FromLong(value));
        PyTuple_SetItem(t, n++, PyString_FromString(field_str));
 
-       handler = PyDict_GetItemString(main_dict, handler_name);
-       if (handler && PyCallable_Check(handler)) {
-               retval = PyObject_CallObject(handler, t);
-               if (retval == NULL)
-                       handler_call_die(handler_name);
-               Py_DECREF(retval);
-       }
+       try_call_object(handler_name, t);
 
        Py_DECREF(t);
 }
@@ -127,7 +150,7 @@ static void define_field(enum print_arg_type field_type,
                         const char *delim)
 {
        const char *handler_name = "define_flag_field";
-       PyObject *handler, *t, *retval;
+       PyObject *t;
        unsigned n = 0;
 
        if (field_type == PRINT_SYMBOL)
@@ -145,13 +168,7 @@ static void define_field(enum print_arg_type field_type,
        if (field_type == PRINT_FLAGS)
                PyTuple_SetItem(t, n++, PyString_FromString(delim));
 
-       handler = PyDict_GetItemString(main_dict, handler_name);
-       if (handler && PyCallable_Check(handler)) {
-               retval = PyObject_CallObject(handler, t);
-               if (retval == NULL)
-                       handler_call_die(handler_name);
-               Py_DECREF(retval);
-       }
+       try_call_object(handler_name, t);
 
        Py_DECREF(t);
 }
@@ -362,7 +379,7 @@ static void python_process_tracepoint(struct perf_sample *sample,
                                      struct thread *thread,
                                      struct addr_location *al)
 {
-       PyObject *handler, *retval, *context, *t, *obj, *callchain;
+       PyObject *handler, *context, *t, *obj, *callchain;
        PyObject *dict = NULL;
        static char handler_name[256];
        struct format_field *field;
@@ -387,9 +404,7 @@ static void python_process_tracepoint(struct perf_sample *sample,
 
        sprintf(handler_name, "%s__%s", event->system, event->name);
 
-       handler = PyDict_GetItemString(main_dict, handler_name);
-       if (handler && !PyCallable_Check(handler))
-               handler = NULL;
+       handler = get_handler(handler_name);
        if (!handler) {
                dict = PyDict_New();
                if (!dict)
@@ -450,19 +465,9 @@ static void python_process_tracepoint(struct perf_sample *sample,
                Py_FatalError("error resizing Python tuple");
 
        if (handler) {
-               retval = PyObject_CallObject(handler, t);
-               if (retval == NULL)
-                       handler_call_die(handler_name);
-               Py_DECREF(retval);
+               call_object(handler, t, handler_name);
        } else {
-               handler = PyDict_GetItemString(main_dict, "trace_unhandled");
-               if (handler && PyCallable_Check(handler)) {
-
-                       retval = PyObject_CallObject(handler, t);
-                       if (retval == NULL)
-                               handler_call_die("trace_unhandled");
-                       Py_DECREF(retval);
-               }
+               try_call_object("trace_unhandled", t);
                Py_DECREF(dict);
        }
 
@@ -474,7 +479,7 @@ static void python_process_general_event(struct perf_sample *sample,
                                         struct thread *thread,
                                         struct addr_location *al)
 {
-       PyObject *handler, *retval, *t, *dict, *callchain, *dict_sample;
+       PyObject *handler, *t, *dict, *callchain, *dict_sample;
        static char handler_name[64];
        unsigned n = 0;
 
@@ -496,8 +501,8 @@ static void python_process_general_event(struct perf_sample *sample,
 
        snprintf(handler_name, sizeof(handler_name), "%s", "process_event");
 
-       handler = PyDict_GetItemString(main_dict, handler_name);
-       if (!handler || !PyCallable_Check(handler))
+       handler = get_handler(handler_name);
+       if (!handler)
                goto exit;
 
        pydict_set_item_string_decref(dict, "ev_name", PyString_FromString(perf_evsel__name(evsel)));
@@ -539,10 +544,7 @@ static void python_process_general_event(struct perf_sample *sample,
        if (_PyTuple_Resize(&t, n) == -1)
                Py_FatalError("error resizing Python tuple");
 
-       retval = PyObject_CallObject(handler, t);
-       if (retval == NULL)
-               handler_call_die(handler_name);
-       Py_DECREF(retval);
+       call_object(handler, t, handler_name);
 exit:
        Py_DECREF(dict);
        Py_DECREF(t);
@@ -566,36 +568,24 @@ static void python_process_event(union perf_event *event __maybe_unused,
 
 static int run_start_sub(void)
 {
-       PyObject *handler, *retval;
-       int err = 0;
-
        main_module = PyImport_AddModule("__main__");
        if (main_module == NULL)
                return -1;
        Py_INCREF(main_module);
 
        main_dict = PyModule_GetDict(main_module);
-       if (main_dict == NULL) {
-               err = -1;
+       if (main_dict == NULL)
                goto error;
-       }
        Py_INCREF(main_dict);
 
-       handler = PyDict_GetItemString(main_dict, "trace_begin");
-       if (handler == NULL || !PyCallable_Check(handler))
-               goto out;
+       try_call_object("trace_begin", NULL);
 
-       retval = PyObject_CallObject(handler, NULL);
-       if (retval == NULL)
-               handler_call_die("trace_begin");
+       return 0;
 
-       Py_DECREF(retval);
-       return err;
 error:
        Py_XDECREF(main_dict);
        Py_XDECREF(main_module);
-out:
-       return err;
+       return -1;
 }
 
 /*
@@ -649,28 +639,23 @@ error:
        return err;
 }
 
+static int python_flush_script(void)
+{
+       return 0;
+}
+
 /*
  * Stop trace script
  */
 static int python_stop_script(void)
 {
-       PyObject *handler, *retval;
-       int err = 0;
+       try_call_object("trace_end", NULL);
 
-       handler = PyDict_GetItemString(main_dict, "trace_end");
-       if (handler == NULL || !PyCallable_Check(handler))
-               goto out;
-
-       retval = PyObject_CallObject(handler, NULL);
-       if (retval == NULL)
-               handler_call_die("trace_end");
-       Py_DECREF(retval);
-out:
        Py_XDECREF(main_dict);
        Py_XDECREF(main_module);
        Py_Finalize();
 
-       return err;
+       return 0;
 }
 
 static int python_generate_script(struct pevent *pevent, const char *outfile)
@@ -843,6 +828,7 @@ static int python_generate_script(struct pevent *pevent, const char *outfile)
 struct scripting_ops python_scripting_ops = {
        .name = "Python",
        .start_script = python_start_script,
+       .flush_script = python_flush_script,
        .stop_script = python_stop_script,
        .process_event = python_process_event,
        .generate_script = python_generate_script,
index 88dfef70c13dbeb4ae75635e35762da5b19a974d..883406f4b381c5ebf6d49de5cb4f40f7c5bdeeae 100644 (file)
@@ -14,6 +14,7 @@
 #include "util.h"
 #include "cpumap.h"
 #include "perf_regs.h"
+#include "asm/bug.h"
 
 static int perf_session__open(struct perf_session *session)
 {
@@ -66,6 +67,25 @@ static void perf_session__destroy_kernel_maps(struct perf_session *session)
        machines__destroy_kernel_maps(&session->machines);
 }
 
+static bool perf_session__has_comm_exec(struct perf_session *session)
+{
+       struct perf_evsel *evsel;
+
+       evlist__for_each(session->evlist, evsel) {
+               if (evsel->attr.comm_exec)
+                       return true;
+       }
+
+       return false;
+}
+
+static void perf_session__set_comm_exec(struct perf_session *session)
+{
+       bool comm_exec = perf_session__has_comm_exec(session);
+
+       machines__set_comm_exec(&session->machines, comm_exec);
+}
+
 struct perf_session *perf_session__new(struct perf_data_file *file,
                                       bool repipe, struct perf_tool *tool)
 {
@@ -75,9 +95,7 @@ struct perf_session *perf_session__new(struct perf_data_file *file,
                goto out;
 
        session->repipe = repipe;
-       INIT_LIST_HEAD(&session->ordered_samples.samples);
-       INIT_LIST_HEAD(&session->ordered_samples.sample_cache);
-       INIT_LIST_HEAD(&session->ordered_samples.to_free);
+       ordered_events__init(&session->ordered_events);
        machines__init(&session->machines);
 
        if (file) {
@@ -91,6 +109,7 @@ struct perf_session *perf_session__new(struct perf_data_file *file,
                                goto out_close;
 
                        perf_session__set_id_hdr_size(session);
+                       perf_session__set_comm_exec(session);
                }
        }
 
@@ -100,13 +119,13 @@ struct perf_session *perf_session__new(struct perf_data_file *file,
                 * kernel MMAP event, in perf_event__process_mmap().
                 */
                if (perf_session__create_kernel_maps(session) < 0)
-                       goto out_delete;
+                       pr_warning("Cannot read kernel map\n");
        }
 
        if (tool && tool->ordering_requires_timestamps &&
-           tool->ordered_samples && !perf_evlist__sample_id_all(session->evlist)) {
+           tool->ordered_events && !perf_evlist__sample_id_all(session->evlist)) {
                dump_printf("WARNING: No sample_id_all support, falling back to unordered processing\n");
-               tool->ordered_samples = false;
+               tool->ordered_events = false;
        }
 
        return session;
@@ -238,7 +257,7 @@ void perf_tool__fill_defaults(struct perf_tool *tool)
        if (tool->build_id == NULL)
                tool->build_id = process_finished_round_stub;
        if (tool->finished_round == NULL) {
-               if (tool->ordered_samples)
+               if (tool->ordered_events)
                        tool->finished_round = process_finished_round;
                else
                        tool->finished_round = process_finished_round_stub;
@@ -444,87 +463,6 @@ static perf_event__swap_op perf_event__swap_ops[] = {
        [PERF_RECORD_HEADER_MAX]          = NULL,
 };
 
-struct sample_queue {
-       u64                     timestamp;
-       u64                     file_offset;
-       union perf_event        *event;
-       struct list_head        list;
-};
-
-static void perf_session_free_sample_buffers(struct perf_session *session)
-{
-       struct ordered_samples *os = &session->ordered_samples;
-
-       while (!list_empty(&os->to_free)) {
-               struct sample_queue *sq;
-
-               sq = list_entry(os->to_free.next, struct sample_queue, list);
-               list_del(&sq->list);
-               free(sq);
-       }
-}
-
-static int perf_session_deliver_event(struct perf_session *session,
-                                     union perf_event *event,
-                                     struct perf_sample *sample,
-                                     struct perf_tool *tool,
-                                     u64 file_offset);
-
-static int flush_sample_queue(struct perf_session *s,
-                      struct perf_tool *tool)
-{
-       struct ordered_samples *os = &s->ordered_samples;
-       struct list_head *head = &os->samples;
-       struct sample_queue *tmp, *iter;
-       struct perf_sample sample;
-       u64 limit = os->next_flush;
-       u64 last_ts = os->last_sample ? os->last_sample->timestamp : 0ULL;
-       bool show_progress = limit == ULLONG_MAX;
-       struct ui_progress prog;
-       int ret;
-
-       if (!tool->ordered_samples || !limit)
-               return 0;
-
-       if (show_progress)
-               ui_progress__init(&prog, os->nr_samples, "Processing time ordered events...");
-
-       list_for_each_entry_safe(iter, tmp, head, list) {
-               if (session_done())
-                       return 0;
-
-               if (iter->timestamp > limit)
-                       break;
-
-               ret = perf_evlist__parse_sample(s->evlist, iter->event, &sample);
-               if (ret)
-                       pr_err("Can't parse sample, err = %d\n", ret);
-               else {
-                       ret = perf_session_deliver_event(s, iter->event, &sample, tool,
-                                                        iter->file_offset);
-                       if (ret)
-                               return ret;
-               }
-
-               os->last_flush = iter->timestamp;
-               list_del(&iter->list);
-               list_add(&iter->list, &os->sample_cache);
-               os->nr_samples--;
-
-               if (show_progress)
-                       ui_progress__update(&prog, 1);
-       }
-
-       if (list_empty(head)) {
-               os->last_sample = NULL;
-       } else if (last_ts <= limit) {
-               os->last_sample =
-                       list_entry(head->prev, struct sample_queue, list);
-       }
-
-       return 0;
-}
-
 /*
  * When perf record finishes a pass on every buffers, it records this pseudo
  * event.
@@ -568,99 +506,43 @@ static int process_finished_round(struct perf_tool *tool,
                                  union perf_event *event __maybe_unused,
                                  struct perf_session *session)
 {
-       int ret = flush_sample_queue(session, tool);
-       if (!ret)
-               session->ordered_samples.next_flush = session->ordered_samples.max_timestamp;
-
-       return ret;
-}
-
-/* The queue is ordered by time */
-static void __queue_event(struct sample_queue *new, struct perf_session *s)
-{
-       struct ordered_samples *os = &s->ordered_samples;
-       struct sample_queue *sample = os->last_sample;
-       u64 timestamp = new->timestamp;
-       struct list_head *p;
-
-       ++os->nr_samples;
-       os->last_sample = new;
-
-       if (!sample) {
-               list_add(&new->list, &os->samples);
-               os->max_timestamp = timestamp;
-               return;
-       }
-
-       /*
-        * last_sample might point to some random place in the list as it's
-        * the last queued event. We expect that the new event is close to
-        * this.
-        */
-       if (sample->timestamp <= timestamp) {
-               while (sample->timestamp <= timestamp) {
-                       p = sample->list.next;
-                       if (p == &os->samples) {
-                               list_add_tail(&new->list, &os->samples);
-                               os->max_timestamp = timestamp;
-                               return;
-                       }
-                       sample = list_entry(p, struct sample_queue, list);
-               }
-               list_add_tail(&new->list, &sample->list);
-       } else {
-               while (sample->timestamp > timestamp) {
-                       p = sample->list.prev;
-                       if (p == &os->samples) {
-                               list_add(&new->list, &os->samples);
-                               return;
-                       }
-                       sample = list_entry(p, struct sample_queue, list);
-               }
-               list_add(&new->list, &sample->list);
-       }
+       return ordered_events__flush(session, tool, OE_FLUSH__ROUND);
 }
 
-#define MAX_SAMPLE_BUFFER      (64 * 1024 / sizeof(struct sample_queue))
-
 int perf_session_queue_event(struct perf_session *s, union perf_event *event,
-                                   struct perf_sample *sample, u64 file_offset)
+                            struct perf_tool *tool, struct perf_sample *sample,
+                            u64 file_offset)
 {
-       struct ordered_samples *os = &s->ordered_samples;
-       struct list_head *sc = &os->sample_cache;
+       struct ordered_events *oe = &s->ordered_events;
        u64 timestamp = sample->time;
-       struct sample_queue *new;
+       struct ordered_event *new;
 
        if (!timestamp || timestamp == ~0ULL)
                return -ETIME;
 
-       if (timestamp < s->ordered_samples.last_flush) {
-               printf("Warning: Timestamp below last timeslice flush\n");
-               return -EINVAL;
+       if (timestamp < oe->last_flush) {
+               WARN_ONCE(1, "Timestamp below last timeslice flush\n");
+
+               pr_oe_time(timestamp,      "out of order event");
+               pr_oe_time(oe->last_flush, "last flush, last_flush_type %d\n",
+                          oe->last_flush_type);
+
+               /* We could get out of order messages after forced flush. */
+               if (oe->last_flush_type != OE_FLUSH__HALF)
+                       return -EINVAL;
        }
 
-       if (!list_empty(sc)) {
-               new = list_entry(sc->next, struct sample_queue, list);
-               list_del(&new->list);
-       } else if (os->sample_buffer) {
-               new = os->sample_buffer + os->sample_buffer_idx;
-               if (++os->sample_buffer_idx == MAX_SAMPLE_BUFFER)
-                       os->sample_buffer = NULL;
-       } else {
-               os->sample_buffer = malloc(MAX_SAMPLE_BUFFER * sizeof(*new));
-               if (!os->sample_buffer)
-                       return -ENOMEM;
-               list_add(&os->sample_buffer->list, &os->to_free);
-               os->sample_buffer_idx = 2;
-               new = os->sample_buffer + 1;
+       new = ordered_events__new(oe, timestamp);
+       if (!new) {
+               ordered_events__flush(s, tool, OE_FLUSH__HALF);
+               new = ordered_events__new(oe, timestamp);
        }
 
-       new->timestamp = timestamp;
+       if (!new)
+               return -ENOMEM;
+
        new->file_offset = file_offset;
        new->event = event;
-
-       __queue_event(new, s);
-
        return 0;
 }
 
@@ -920,11 +802,10 @@ perf_session__deliver_sample(struct perf_session *session,
                                            &sample->read.one, machine);
 }
 
-static int perf_session_deliver_event(struct perf_session *session,
-                                     union perf_event *event,
-                                     struct perf_sample *sample,
-                                     struct perf_tool *tool,
-                                     u64 file_offset)
+int perf_session__deliver_event(struct perf_session *session,
+                               union perf_event *event,
+                               struct perf_sample *sample,
+                               struct perf_tool *tool, u64 file_offset)
 {
        struct perf_evsel *evsel;
        struct machine *machine;
@@ -1005,8 +886,10 @@ static s64 perf_session__process_user_event(struct perf_session *session,
        switch (event->header.type) {
        case PERF_RECORD_HEADER_ATTR:
                err = tool->attr(tool, event, &session->evlist);
-               if (err == 0)
+               if (err == 0) {
                        perf_session__set_id_hdr_size(session);
+                       perf_session__set_comm_exec(session);
+               }
                return err;
        case PERF_RECORD_HEADER_EVENT_TYPE:
                /*
@@ -1036,6 +919,61 @@ static void event_swap(union perf_event *event, bool sample_id_all)
                swap(event, sample_id_all);
 }
 
+int perf_session__peek_event(struct perf_session *session, off_t file_offset,
+                            void *buf, size_t buf_sz,
+                            union perf_event **event_ptr,
+                            struct perf_sample *sample)
+{
+       union perf_event *event;
+       size_t hdr_sz, rest;
+       int fd;
+
+       if (session->one_mmap && !session->header.needs_swap) {
+               event = file_offset - session->one_mmap_offset +
+                       session->one_mmap_addr;
+               goto out_parse_sample;
+       }
+
+       if (perf_data_file__is_pipe(session->file))
+               return -1;
+
+       fd = perf_data_file__fd(session->file);
+       hdr_sz = sizeof(struct perf_event_header);
+
+       if (buf_sz < hdr_sz)
+               return -1;
+
+       if (lseek(fd, file_offset, SEEK_SET) == (off_t)-1 ||
+           readn(fd, &buf, hdr_sz) != (ssize_t)hdr_sz)
+               return -1;
+
+       event = (union perf_event *)buf;
+
+       if (session->header.needs_swap)
+               perf_event_header__bswap(&event->header);
+
+       if (event->header.size < hdr_sz)
+               return -1;
+
+       rest = event->header.size - hdr_sz;
+
+       if (readn(fd, &buf, rest) != (ssize_t)rest)
+               return -1;
+
+       if (session->header.needs_swap)
+               event_swap(event, perf_evlist__sample_id_all(session->evlist));
+
+out_parse_sample:
+
+       if (sample && event->header.type < PERF_RECORD_USER_TYPE_START &&
+           perf_evlist__parse_sample(session->evlist, event, sample))
+               return -1;
+
+       *event_ptr = event;
+
+       return 0;
+}
+
 static s64 perf_session__process_event(struct perf_session *session,
                                       union perf_event *event,
                                       struct perf_tool *tool,
@@ -1062,15 +1000,15 @@ static s64 perf_session__process_event(struct perf_session *session,
        if (ret)
                return ret;
 
-       if (tool->ordered_samples) {
-               ret = perf_session_queue_event(session, event, &sample,
+       if (tool->ordered_events) {
+               ret = perf_session_queue_event(session, event, tool, &sample,
                                               file_offset);
                if (ret != -ETIME)
                        return ret;
        }
 
-       return perf_session_deliver_event(session, event, &sample, tool,
-                                         file_offset);
+       return perf_session__deliver_event(session, event, &sample, tool,
+                                          file_offset);
 }
 
 void perf_event_header__bswap(struct perf_event_header *hdr)
@@ -1222,12 +1160,11 @@ more:
                goto more;
 done:
        /* do the final flush for ordered samples */
-       session->ordered_samples.next_flush = ULLONG_MAX;
-       err = flush_sample_queue(session, tool);
+       err = ordered_events__flush(session, tool, OE_FLUSH__FINAL);
 out_err:
        free(buf);
        perf_session__warn_about_errors(session, tool);
-       perf_session_free_sample_buffers(session);
+       ordered_events__free(&session->ordered_events);
        return err;
 }
 
@@ -1368,12 +1305,11 @@ more:
 
 out:
        /* do the final flush for ordered samples */
-       session->ordered_samples.next_flush = ULLONG_MAX;
-       err = flush_sample_queue(session, tool);
+       err = ordered_events__flush(session, tool, OE_FLUSH__FINAL);
 out_err:
        ui_progress__finish();
        perf_session__warn_about_errors(session, tool);
-       perf_session_free_sample_buffers(session);
+       ordered_events__free(&session->ordered_events);
        session->one_mmap = false;
        return err;
 }
index 0321013bd9fde625f823fb2d15923cefc3eea965..ffb440462008ef55e65884d1849c22af9bb73856 100644 (file)
@@ -9,26 +9,13 @@
 #include "symbol.h"
 #include "thread.h"
 #include "data.h"
+#include "ordered-events.h"
 #include <linux/rbtree.h>
 #include <linux/perf_event.h>
 
-struct sample_queue;
 struct ip_callchain;
 struct thread;
 
-struct ordered_samples {
-       u64                     last_flush;
-       u64                     next_flush;
-       u64                     max_timestamp;
-       struct list_head        samples;
-       struct list_head        sample_cache;
-       struct list_head        to_free;
-       struct sample_queue     *sample_buffer;
-       struct sample_queue     *last_sample;
-       int                     sample_buffer_idx;
-       unsigned int            nr_samples;
-};
-
 struct perf_session {
        struct perf_header      header;
        struct machines         machines;
@@ -39,7 +26,7 @@ struct perf_session {
        bool                    one_mmap;
        void                    *one_mmap_addr;
        u64                     one_mmap_offset;
-       struct ordered_samples  ordered_samples;
+       struct ordered_events   ordered_events;
        struct perf_data_file   *file;
 };
 
@@ -58,6 +45,11 @@ void perf_session__delete(struct perf_session *session);
 
 void perf_event_header__bswap(struct perf_event_header *hdr);
 
+int perf_session__peek_event(struct perf_session *session, off_t file_offset,
+                            void *buf, size_t buf_sz,
+                            union perf_event **event_ptr,
+                            struct perf_sample *sample);
+
 int __perf_session__process_events(struct perf_session *session,
                                   u64 data_offset, u64 data_size, u64 size,
                                   struct perf_tool *tool);
@@ -65,10 +57,16 @@ int perf_session__process_events(struct perf_session *session,
                                 struct perf_tool *tool);
 
 int perf_session_queue_event(struct perf_session *s, union perf_event *event,
-                            struct perf_sample *sample, u64 file_offset);
+                            struct perf_tool *tool, struct perf_sample *sample,
+                            u64 file_offset);
 
 void perf_tool__fill_defaults(struct perf_tool *tool);
 
+int perf_session__deliver_event(struct perf_session *session,
+                               union perf_event *event,
+                               struct perf_sample *sample,
+                               struct perf_tool *tool, u64 file_offset);
+
 int perf_session__resolve_callchain(struct perf_session *session,
                                    struct perf_evsel *evsel,
                                    struct thread *thread,
@@ -128,5 +126,5 @@ int __perf_session__set_tracepoints_handlers(struct perf_session *session,
 
 extern volatile int session_done;
 
-#define session_done() (*(volatile int *)(&session_done))
+#define session_done() ACCESS_ONCE(session_done)
 #endif /* __PERF_SESSION_H */
index 14e5a039bc4546652ee9332dcc2751225ffaa4a8..289df9d1e65ae277f585f384db91eaa402f5b405 100644 (file)
@@ -70,12 +70,14 @@ static int hist_entry__thread_snprintf(struct hist_entry *he, char *bf,
                                       size_t size, unsigned int width)
 {
        const char *comm = thread__comm_str(he->thread);
-       return repsep_snprintf(bf, size, "%*s:%5d", width - 6,
-                              comm ?: "", he->thread->tid);
+
+       width = max(7U, width) - 6;
+       return repsep_snprintf(bf, size, "%5d:%-*.*s", he->thread->tid,
+                              width, width, comm ?: "");
 }
 
 struct sort_entry sort_thread = {
-       .se_header      = "Command:  Pid",
+       .se_header      = "  Pid:Command",
        .se_cmp         = sort__thread_cmp,
        .se_snprintf    = hist_entry__thread_snprintf,
        .se_width_idx   = HISTC_THREAD,
@@ -106,7 +108,7 @@ sort__comm_sort(struct hist_entry *left, struct hist_entry *right)
 static int hist_entry__comm_snprintf(struct hist_entry *he, char *bf,
                                     size_t size, unsigned int width)
 {
-       return repsep_snprintf(bf, size, "%*s", width, comm__str(he->comm));
+       return repsep_snprintf(bf, size, "%-*.*s", width, width, comm__str(he->comm));
 }
 
 struct sort_entry sort_comm = {
@@ -152,10 +154,10 @@ static int _hist_entry__dso_snprintf(struct map *map, char *bf,
        if (map && map->dso) {
                const char *dso_name = !verbose ? map->dso->short_name :
                        map->dso->long_name;
-               return repsep_snprintf(bf, size, "%-*s", width, dso_name);
+               return repsep_snprintf(bf, size, "%-*.*s", width, width, dso_name);
        }
 
-       return repsep_snprintf(bf, size, "%-*s", width, "[unknown]");
+       return repsep_snprintf(bf, size, "%-*.*s", width, width, "[unknown]");
 }
 
 static int hist_entry__dso_snprintf(struct hist_entry *he, char *bf,
@@ -257,7 +259,10 @@ static int _hist_entry__sym_snprintf(struct map *map, struct symbol *sym,
                                       width - ret, "");
        }
 
-       return ret;
+       if (ret > width)
+               bf[width] = '\0';
+
+       return width;
 }
 
 static int hist_entry__sym_snprintf(struct hist_entry *he, char *bf,
@@ -302,10 +307,9 @@ sort__srcline_cmp(struct hist_entry *left, struct hist_entry *right)
 }
 
 static int hist_entry__srcline_snprintf(struct hist_entry *he, char *bf,
-                                       size_t size,
-                                       unsigned int width __maybe_unused)
+                                       size_t size, unsigned int width)
 {
-       return repsep_snprintf(bf, size, "%s", he->srcline);
+       return repsep_snprintf(bf, size, "%*.*-s", width, width, he->srcline);
 }
 
 struct sort_entry sort_srcline = {
@@ -332,7 +336,7 @@ sort__parent_cmp(struct hist_entry *left, struct hist_entry *right)
 static int hist_entry__parent_snprintf(struct hist_entry *he, char *bf,
                                       size_t size, unsigned int width)
 {
-       return repsep_snprintf(bf, size, "%-*s", width,
+       return repsep_snprintf(bf, size, "%-*.*s", width, width,
                              he->parent ? he->parent->name : "[other]");
 }
 
@@ -354,7 +358,7 @@ sort__cpu_cmp(struct hist_entry *left, struct hist_entry *right)
 static int hist_entry__cpu_snprintf(struct hist_entry *he, char *bf,
                                    size_t size, unsigned int width)
 {
-       return repsep_snprintf(bf, size, "%*d", width, he->cpu);
+       return repsep_snprintf(bf, size, "%*.*d", width, width, he->cpu);
 }
 
 struct sort_entry sort_cpu = {
@@ -484,7 +488,7 @@ static int hist_entry__mispredict_snprintf(struct hist_entry *he, char *bf,
        else if (he->branch_info->flags.mispred)
                out = "Y";
 
-       return repsep_snprintf(bf, size, "%-*s", width, out);
+       return repsep_snprintf(bf, size, "%-*.*s", width, width, out);
 }
 
 /* --sort daddr_sym */
@@ -1194,7 +1198,7 @@ bool perf_hpp__same_sort_entry(struct perf_hpp_fmt *a, struct perf_hpp_fmt *b)
        return hse_a->se == hse_b->se;
 }
 
-void perf_hpp__reset_width(struct perf_hpp_fmt *fmt, struct hists *hists)
+void perf_hpp__reset_sort_width(struct perf_hpp_fmt *fmt, struct hists *hists)
 {
        struct hpp_sort_entry *hse;
 
@@ -1202,20 +1206,21 @@ void perf_hpp__reset_width(struct perf_hpp_fmt *fmt, struct hists *hists)
                return;
 
        hse = container_of(fmt, struct hpp_sort_entry, hpp);
-       hists__new_col_len(hists, hse->se->se_width_idx,
-                          strlen(hse->se->se_header));
+       hists__new_col_len(hists, hse->se->se_width_idx, strlen(fmt->name));
 }
 
 static int __sort__hpp_header(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
                              struct perf_evsel *evsel)
 {
        struct hpp_sort_entry *hse;
-       size_t len;
+       size_t len = fmt->user_len;
 
        hse = container_of(fmt, struct hpp_sort_entry, hpp);
-       len = hists__col_len(&evsel->hists, hse->se->se_width_idx);
 
-       return scnprintf(hpp->buf, hpp->size, "%-*s", len, hse->se->se_header);
+       if (!len)
+               len = hists__col_len(&evsel->hists, hse->se->se_width_idx);
+
+       return scnprintf(hpp->buf, hpp->size, "%-*.*s", len, len, fmt->name);
 }
 
 static int __sort__hpp_width(struct perf_hpp_fmt *fmt,
@@ -1223,20 +1228,26 @@ static int __sort__hpp_width(struct perf_hpp_fmt *fmt,
                             struct perf_evsel *evsel)
 {
        struct hpp_sort_entry *hse;
+       size_t len = fmt->user_len;
 
        hse = container_of(fmt, struct hpp_sort_entry, hpp);
 
-       return hists__col_len(&evsel->hists, hse->se->se_width_idx);
+       if (!len)
+               len = hists__col_len(&evsel->hists, hse->se->se_width_idx);
+
+       return len;
 }
 
 static int __sort__hpp_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
                             struct hist_entry *he)
 {
        struct hpp_sort_entry *hse;
-       size_t len;
+       size_t len = fmt->user_len;
 
        hse = container_of(fmt, struct hpp_sort_entry, hpp);
-       len = hists__col_len(he->hists, hse->se->se_width_idx);
+
+       if (!len)
+               len = hists__col_len(he->hists, hse->se->se_width_idx);
 
        return hse->se->se_snprintf(he, hpp->buf, hpp->size, len);
 }
@@ -1253,6 +1264,7 @@ __sort_dimension__alloc_hpp(struct sort_dimension *sd)
        }
 
        hse->se = sd->entry;
+       hse->hpp.name = sd->entry->se_header;
        hse->hpp.header = __sort__hpp_header;
        hse->hpp.width = __sort__hpp_width;
        hse->hpp.entry = __sort__hpp_entry;
@@ -1265,6 +1277,8 @@ __sort_dimension__alloc_hpp(struct sort_dimension *sd)
        INIT_LIST_HEAD(&hse->hpp.list);
        INIT_LIST_HEAD(&hse->hpp.sort_list);
        hse->hpp.elide = false;
+       hse->hpp.len = 0;
+       hse->hpp.user_len = 0;
 
        return hse;
 }
@@ -1432,14 +1446,49 @@ static const char *get_default_sort_order(void)
        return default_sort_orders[sort__mode];
 }
 
+static int setup_sort_order(void)
+{
+       char *new_sort_order;
+
+       /*
+        * Append '+'-prefixed sort order to the default sort
+        * order string.
+        */
+       if (!sort_order || is_strict_order(sort_order))
+               return 0;
+
+       if (sort_order[1] == '\0') {
+               error("Invalid --sort key: `+'");
+               return -EINVAL;
+       }
+
+       /*
+        * We allocate new sort_order string, but we never free it,
+        * because it's checked over the rest of the code.
+        */
+       if (asprintf(&new_sort_order, "%s,%s",
+                    get_default_sort_order(), sort_order + 1) < 0) {
+               error("Not enough memory to set up --sort");
+               return -ENOMEM;
+       }
+
+       sort_order = new_sort_order;
+       return 0;
+}
+
 static int __setup_sorting(void)
 {
        char *tmp, *tok, *str;
-       const char *sort_keys = sort_order;
+       const char *sort_keys;
        int ret = 0;
 
+       ret = setup_sort_order();
+       if (ret)
+               return ret;
+
+       sort_keys = sort_order;
        if (sort_keys == NULL) {
-               if (field_order) {
+               if (is_strict_order(field_order)) {
                        /*
                         * If user specified field order but no sort order,
                         * we'll honor it and not add default sort orders.
@@ -1625,23 +1674,36 @@ static void reset_dimensions(void)
                memory_sort_dimensions[i].taken = 0;
 }
 
+bool is_strict_order(const char *order)
+{
+       return order && (*order != '+');
+}
+
 static int __setup_output_field(void)
 {
-       char *tmp, *tok, *str;
-       int ret = 0;
+       char *tmp, *tok, *str, *strp;
+       int ret = -EINVAL;
 
        if (field_order == NULL)
                return 0;
 
        reset_dimensions();
 
-       str = strdup(field_order);
+       strp = str = strdup(field_order);
        if (str == NULL) {
                error("Not enough memory to setup output fields");
                return -ENOMEM;
        }
 
-       for (tok = strtok_r(str, ", ", &tmp);
+       if (!is_strict_order(field_order))
+               strp++;
+
+       if (!strlen(strp)) {
+               error("Invalid --fields key: `+'");
+               goto out;
+       }
+
+       for (tok = strtok_r(strp, ", ", &tmp);
                        tok; tok = strtok_r(NULL, ", ", &tmp)) {
                ret = output_field_add(tok);
                if (ret == -EINVAL) {
@@ -1653,6 +1715,7 @@ static int __setup_output_field(void)
                }
        }
 
+out:
        free(str);
        return ret;
 }
index 041f0c9cea2b4f0f1af283ddeed3d3d5a9511e49..c03e4ff8beffe083ab19769d91a7e57d6f70d126 100644 (file)
@@ -218,4 +218,5 @@ void perf_hpp__set_elide(int idx, bool elide);
 
 int report_parse_ignore_callees_opt(const struct option *opt, const char *arg, int unset);
 
+bool is_strict_order(const char *order);
 #endif /* __PERF_SORT_H */
index 2553e5b55b8996175220d8fc16cfb403161f35b7..d87767f76903e17f2e59a93ad36bc6e6b2f2e6a0 100644 (file)
@@ -9,78 +9,48 @@
  */
 s64 perf_atoll(const char *str)
 {
-       unsigned int i;
-       s64 length = -1, unit = 1;
+       s64 length;
+       char *p;
+       char c;
 
        if (!isdigit(str[0]))
                goto out_err;
 
-       for (i = 1; i < strlen(str); i++) {
-               switch (str[i]) {
-               case 'B':
-               case 'b':
-                       break;
-               case 'K':
-                       if (str[i + 1] != 'B')
-                               goto out_err;
-                       else
-                               goto kilo;
-               case 'k':
-                       if (str[i + 1] != 'b')
-                               goto out_err;
-kilo:
-                       unit = K;
-                       break;
-               case 'M':
-                       if (str[i + 1] != 'B')
-                               goto out_err;
-                       else
-                               goto mega;
-               case 'm':
-                       if (str[i + 1] != 'b')
+       length = strtoll(str, &p, 10);
+       switch (c = *p++) {
+               case 'b': case 'B':
+                       if (*p)
                                goto out_err;
-mega:
-                       unit = K * K;
+               case '\0':
+                       return length;
+               default:
+                       goto out_err;
+               /* two-letter suffices */
+               case 'k': case 'K':
+                       length <<= 10;
                        break;
-               case 'G':
-                       if (str[i + 1] != 'B')
-                               goto out_err;
-                       else
-                               goto giga;
-               case 'g':
-                       if (str[i + 1] != 'b')
-                               goto out_err;
-giga:
-                       unit = K * K * K;
+               case 'm': case 'M':
+                       length <<= 20;
                        break;
-               case 'T':
-                       if (str[i + 1] != 'B')
-                               goto out_err;
-                       else
-                               goto tera;
-               case 't':
-                       if (str[i + 1] != 'b')
-                               goto out_err;
-tera:
-                       unit = K * K * K * K;
+               case 'g': case 'G':
+                       length <<= 30;
                        break;
-               case '\0':      /* only specified figures */
-                       unit = 1;
+               case 't': case 'T':
+                       length <<= 40;
                        break;
-               default:
-                       if (!isdigit(str[i]))
-                               goto out_err;
-                       break;
-               }
        }
-
-       length = atoll(str) * unit;
-       goto out;
+       /* we want the cases to match */
+       if (islower(c)) {
+               if (strcmp(p, "b") != 0)
+                       goto out_err;
+       } else {
+               if (strcmp(p, "B") != 0)
+                       goto out_err;
+       }
+       return length;
 
 out_err:
-       length = -1;
-out:
-       return length;
+       return -1;
 }
 
 /*
index d75349979e65e87cf0a4ecacc801cfb867ce323c..1e23a5bfb044a4cf39f2a0dfbbb5bf26bbad4b4b 100644 (file)
@@ -6,6 +6,7 @@
 #include <inttypes.h>
 
 #include "symbol.h"
+#include "machine.h"
 #include "vdso.h"
 #include <symbol/kallsyms.h>
 #include "debug.h"
@@ -680,6 +681,11 @@ static u64 ref_reloc(struct kmap *kmap)
        return 0;
 }
 
+static bool want_demangle(bool is_kernel_sym)
+{
+       return is_kernel_sym ? symbol_conf.demangle_kernel : symbol_conf.demangle;
+}
+
 int dso__load_sym(struct dso *dso, struct map *map,
                  struct symsrc *syms_ss, struct symsrc *runtime_ss,
                  symbol_filter_t filter, int kmodule)
@@ -712,6 +718,14 @@ int dso__load_sym(struct dso *dso, struct map *map,
                symbols__delete(&dso->symbols[map->type]);
 
        if (!syms_ss->symtab) {
+               /*
+                * If the vmlinux is stripped, fail so we will fall back
+                * to using kallsyms. The vmlinux runtime symbols aren't
+                * of much use.
+                */
+               if (dso->kernel)
+                       goto out_elf_end;
+
                syms_ss->symtab  = syms_ss->dynsym;
                syms_ss->symshdr = syms_ss->dynshdr;
        }
@@ -736,7 +750,7 @@ int dso__load_sym(struct dso *dso, struct map *map,
        if (symstrs == NULL)
                goto out_elf_end;
 
-       sec_strndx = elf_getscn(elf, ehdr.e_shstrndx);
+       sec_strndx = elf_getscn(runtime_ss->elf, runtime_ss->ehdr.e_shstrndx);
        if (sec_strndx == NULL)
                goto out_elf_end;
 
@@ -916,7 +930,11 @@ int dso__load_sym(struct dso *dso, struct map *map,
                                }
                                curr_dso->symtab_type = dso->symtab_type;
                                map_groups__insert(kmap->kmaps, curr_map);
-                               dsos__add(&dso->node, curr_dso);
+                               /*
+                                * The new DSO should go to the kernel DSOS
+                                */
+                               dsos__add(&map->groups->machine->kernel_dsos,
+                                         curr_dso);
                                dso__set_loaded(curr_dso, map->type);
                        } else
                                curr_dso = curr_map->dso;
@@ -938,9 +956,12 @@ new_symbol:
                 * DWARF DW_compile_unit has this, but we don't always have access
                 * to it...
                 */
-               if (symbol_conf.demangle) {
-                       demangled = bfd_demangle(NULL, elf_name,
-                                                DMGL_PARAMS | DMGL_ANSI);
+               if (want_demangle(dso->kernel || kmodule)) {
+                       int demangle_flags = DMGL_NO_OPTS;
+                       if (verbose)
+                               demangle_flags = DMGL_PARAMS | DMGL_ANSI;
+
+                       demangled = bfd_demangle(NULL, elf_name, demangle_flags);
                        if (demangled != NULL)
                                elf_name = demangled;
                }
index eb06746b06b291786721de6643ea9e3034ae49b7..be84f7a9838bff705d9c02b49168aede82b4291c 100644 (file)
@@ -15,6 +15,7 @@
 #include "machine.h"
 #include "symbol.h"
 #include "strlist.h"
+#include "header.h"
 
 #include <elf.h>
 #include <limits.h>
@@ -33,6 +34,7 @@ struct symbol_conf symbol_conf = {
        .try_vmlinux_path       = true,
        .annotate_src           = true,
        .demangle               = true,
+       .demangle_kernel        = false,
        .cumulate_callchain     = true,
        .show_hist_headers      = true,
        .symfs                  = "",
@@ -523,10 +525,15 @@ struct process_kallsyms_args {
        struct dso *dso;
 };
 
+/*
+ * These are symbols in the kernel image, so make sure that
+ * sym is from a kernel DSO.
+ */
 bool symbol__is_idle(struct symbol *sym)
 {
        const char * const idle_symbols[] = {
                "cpu_idle",
+               "cpu_startup_entry",
                "intel_idle",
                "default_idle",
                "native_safe_halt",
@@ -1468,8 +1475,7 @@ int dso__load_vmlinux(struct dso *dso, struct map *map,
        if (vmlinux[0] == '/')
                snprintf(symfs_vmlinux, sizeof(symfs_vmlinux), "%s", vmlinux);
        else
-               snprintf(symfs_vmlinux, sizeof(symfs_vmlinux), "%s%s",
-                        symbol_conf.symfs, vmlinux);
+               symbol__join_symfs(symfs_vmlinux, vmlinux);
 
        if (dso->kernel == DSO_TYPE_GUEST_KERNEL)
                symtab_type = DSO_BINARY_TYPE__GUEST_VMLINUX;
@@ -1745,12 +1751,13 @@ static void vmlinux_path__exit(void)
        zfree(&vmlinux_path);
 }
 
-static int vmlinux_path__init(void)
+static int vmlinux_path__init(struct perf_session_env *env)
 {
        struct utsname uts;
        char bf[PATH_MAX];
+       char *kernel_version;
 
-       vmlinux_path = malloc(sizeof(char *) * 5);
+       vmlinux_path = malloc(sizeof(char *) * 6);
        if (vmlinux_path == NULL)
                return -1;
 
@@ -1763,25 +1770,37 @@ static int vmlinux_path__init(void)
                goto out_fail;
        ++vmlinux_path__nr_entries;
 
-       /* only try running kernel version if no symfs was given */
+       /* only try kernel version if no symfs was given */
        if (symbol_conf.symfs[0] != 0)
                return 0;
 
-       if (uname(&uts) < 0)
-               return -1;
+       if (env) {
+               kernel_version = env->os_release;
+       } else {
+               if (uname(&uts) < 0)
+                       goto out_fail;
 
-       snprintf(bf, sizeof(bf), "/boot/vmlinux-%s", uts.release);
+               kernel_version = uts.release;
+       }
+
+       snprintf(bf, sizeof(bf), "/boot/vmlinux-%s", kernel_version);
        vmlinux_path[vmlinux_path__nr_entries] = strdup(bf);
        if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
                goto out_fail;
        ++vmlinux_path__nr_entries;
-       snprintf(bf, sizeof(bf), "/lib/modules/%s/build/vmlinux", uts.release);
+       snprintf(bf, sizeof(bf), "/usr/lib/debug/boot/vmlinux-%s",
+                kernel_version);
+       vmlinux_path[vmlinux_path__nr_entries] = strdup(bf);
+       if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
+               goto out_fail;
+        ++vmlinux_path__nr_entries;
+       snprintf(bf, sizeof(bf), "/lib/modules/%s/build/vmlinux", kernel_version);
        vmlinux_path[vmlinux_path__nr_entries] = strdup(bf);
        if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
                goto out_fail;
        ++vmlinux_path__nr_entries;
        snprintf(bf, sizeof(bf), "/usr/lib/debug/lib/modules/%s/vmlinux",
-                uts.release);
+                kernel_version);
        vmlinux_path[vmlinux_path__nr_entries] = strdup(bf);
        if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
                goto out_fail;
@@ -1827,7 +1846,7 @@ static bool symbol__read_kptr_restrict(void)
        return value;
 }
 
-int symbol__init(void)
+int symbol__init(struct perf_session_env *env)
 {
        const char *symfs;
 
@@ -1842,7 +1861,7 @@ int symbol__init(void)
                symbol_conf.priv_size += (sizeof(struct symbol_name_rb_node) -
                                          sizeof(struct symbol));
 
-       if (symbol_conf.try_vmlinux_path && vmlinux_path__init() < 0)
+       if (symbol_conf.try_vmlinux_path && vmlinux_path__init(env) < 0)
                return -1;
 
        if (symbol_conf.field_sep && *symbol_conf.field_sep == '.') {
index e7295e93cff9bff87ec7cce513280d5ed26ca7c2..bec4b7bd09debbe77efabbb0516d5faac5016af6 100644 (file)
@@ -13,6 +13,7 @@
 #include <libgen.h>
 #include "build-id.h"
 #include "event.h"
+#include "util.h"
 
 #ifdef HAVE_LIBELF_SUPPORT
 #include <libelf.h>
@@ -59,6 +60,7 @@ extern Elf_Scn *elf_section_by_name(Elf *elf, GElf_Ehdr *ep,
 #endif
 
 #ifndef DMGL_PARAMS
+#define DMGL_NO_OPTS     0              /* For readability... */
 #define DMGL_PARAMS      (1 << 0)       /* Include function args */
 #define DMGL_ANSI        (1 << 1)       /* Include const, volatile, etc */
 #endif
@@ -118,6 +120,7 @@ struct symbol_conf {
                        annotate_src,
                        event_group,
                        demangle,
+                       demangle_kernel,
                        filter_relative,
                        show_hist_headers;
        const char      *vmlinux_name,
@@ -143,6 +146,14 @@ struct symbol_conf {
 };
 
 extern struct symbol_conf symbol_conf;
+
+static inline int __symbol__join_symfs(char *bf, size_t size, const char *path)
+{
+       return path__join(bf, size, symbol_conf.symfs, path);
+}
+
+#define symbol__join_symfs(bf, path) __symbol__join_symfs(bf, sizeof(bf), path)
+
 extern int vmlinux_path__nr_entries;
 extern char **vmlinux_path;
 
@@ -253,7 +264,8 @@ int modules__parse(const char *filename, void *arg,
 int filename__read_debuglink(const char *filename, char *debuglink,
                             size_t size);
 
-int symbol__init(void);
+struct perf_session_env;
+int symbol__init(struct perf_session_env *env);
 void symbol__exit(void);
 void symbol__elf_init(void);
 struct symbol *symbol__new(u64 start, u64 len, u8 binding, const char *name);
index 12c7a253a63ceecfa30f93d7f52f4361a5842c44..a9df7f2c6dc934210e83755155e843b72af68011 100644 (file)
@@ -42,7 +42,7 @@ struct thread *thread__new(pid_t pid, pid_t tid)
                        goto err_thread;
 
                snprintf(comm_str, 32, ":%d", tid);
-               comm = comm__new(comm_str, 0);
+               comm = comm__new(comm_str, 0, false);
                free(comm_str);
                if (!comm)
                        goto err_thread;
@@ -81,19 +81,33 @@ struct comm *thread__comm(const struct thread *thread)
        return list_first_entry(&thread->comm_list, struct comm, list);
 }
 
+struct comm *thread__exec_comm(const struct thread *thread)
+{
+       struct comm *comm, *last = NULL;
+
+       list_for_each_entry(comm, &thread->comm_list, list) {
+               if (comm->exec)
+                       return comm;
+               last = comm;
+       }
+
+       return last;
+}
+
 /* CHECKME: time should always be 0 if event aren't ordered */
-int thread__set_comm(struct thread *thread, const char *str, u64 timestamp)
+int __thread__set_comm(struct thread *thread, const char *str, u64 timestamp,
+                      bool exec)
 {
        struct comm *new, *curr = thread__comm(thread);
        int err;
 
        /* Override latest entry if it had no specific time coverage */
-       if (!curr->start) {
-               err = comm__override(curr, str, timestamp);
+       if (!curr->start && !curr->exec) {
+               err = comm__override(curr, str, timestamp, exec);
                if (err)
                        return err;
        } else {
-               new = comm__new(str, timestamp);
+               new = comm__new(str, timestamp, exec);
                if (!new)
                        return -ENOMEM;
                list_add(&new->list, &thread->comm_list);
index 716b7723cce27e03edf2d9a3d61fafc5b7fe1659..8c75fa774706352d22e2c4aa3390fb3350c89195 100644 (file)
@@ -38,9 +38,17 @@ static inline void thread__exited(struct thread *thread)
        thread->dead = true;
 }
 
-int thread__set_comm(struct thread *thread, const char *comm, u64 timestamp);
+int __thread__set_comm(struct thread *thread, const char *comm, u64 timestamp,
+                      bool exec);
+static inline int thread__set_comm(struct thread *thread, const char *comm,
+                                  u64 timestamp)
+{
+       return __thread__set_comm(thread, comm, timestamp, false);
+}
+
 int thread__comm_len(struct thread *thread);
 struct comm *thread__comm(const struct thread *thread);
+struct comm *thread__exec_comm(const struct thread *thread);
 const char *thread__comm_str(const struct thread *thread);
 void thread__insert_map(struct thread *thread, struct map *map);
 int thread__fork(struct thread *thread, struct thread *parent, u64 timestamp);
index 4385816d3d49643c981f64a310eaaef6d9838738..f11636966a0f19ee3e77b8e16f0f55e6db505827 100644 (file)
@@ -40,7 +40,7 @@ struct perf_tool {
        event_op2       tracing_data;
        event_op2       finished_round,
                        build_id;
-       bool            ordered_samples;
+       bool            ordered_events;
        bool            ordering_requires_timestamps;
 };
 
index 57aaccc1692e616ee0f257c90472272541f7d5b3..5c9bdd1591a975c2d1f7f028701504f228da70a0 100644 (file)
 
 struct scripting_context *scripting_context;
 
+static int flush_script_unsupported(void)
+{
+       return 0;
+}
+
 static int stop_script_unsupported(void)
 {
        return 0;
@@ -74,6 +79,7 @@ static int python_generate_script_unsupported(struct pevent *pevent
 struct scripting_ops python_scripting_unsupported_ops = {
        .name = "Python",
        .start_script = python_start_script_unsupported,
+       .flush_script = flush_script_unsupported,
        .stop_script = stop_script_unsupported,
        .process_event = process_event_unsupported,
        .generate_script = python_generate_script_unsupported,
@@ -137,6 +143,7 @@ static int perl_generate_script_unsupported(struct pevent *pevent
 struct scripting_ops perl_scripting_unsupported_ops = {
        .name = "Perl",
        .start_script = perl_start_script_unsupported,
+       .flush_script = flush_script_unsupported,
        .stop_script = stop_script_unsupported,
        .process_event = process_event_unsupported,
        .generate_script = perl_generate_script_unsupported,
index 7b6d68688327a75286eb3ab1a77fea15bb74ffb8..52aaa19e1eb13125dd30c4c82b6abe2d89de2735 100644 (file)
@@ -64,6 +64,7 @@ struct perf_session;
 struct scripting_ops {
        const char *name;
        int (*start_script) (const char *script, int argc, const char **argv);
+       int (*flush_script) (void);
        int (*stop_script) (void);
        void (*process_event) (union perf_event *event,
                               struct perf_sample *sample,
index e52e7461911b978838e868b92f024aa642c2bf53..24e8d871b74e51d10ccf35fd8188901acf4a94df 100644 (file)
@@ -13,6 +13,7 @@
 #include <limits.h>
 #include <byteswap.h>
 #include <linux/kernel.h>
+#include <unistd.h>
 
 /*
  * XXX We need to find a better place for these things...
@@ -282,6 +283,18 @@ void get_term_dimensions(struct winsize *ws)
        ws->ws_col = 80;
 }
 
+void set_term_quiet_input(struct termios *old)
+{
+       struct termios tc;
+
+       tcgetattr(0, old);
+       tc = *old;
+       tc.c_lflag &= ~(ICANON | ECHO);
+       tc.c_cc[VMIN] = 0;
+       tc.c_cc[VTIME] = 0;
+       tcsetattr(0, TCSANOW, &tc);
+}
+
 static void set_tracing_events_path(const char *mountpoint)
 {
        snprintf(tracing_events_path, sizeof(tracing_events_path), "%s/%s",
@@ -443,6 +456,7 @@ int filename__read_str(const char *filename, char **buf, size_t *sizep)
        size_t size = 0, alloc_size = 0;
        void *bf = NULL, *nbf;
        int fd, n, err = 0;
+       char sbuf[STRERR_BUFSIZE];
 
        fd = open(filename, O_RDONLY);
        if (fd < 0)
@@ -463,8 +477,8 @@ int filename__read_str(const char *filename, char **buf, size_t *sizep)
                n = read(fd, bf + size, alloc_size - size);
                if (n < 0) {
                        if (size) {
-                               pr_warning("read failed %d: %s\n",
-                                          errno, strerror(errno));
+                               pr_warning("read failed %d: %s\n", errno,
+                                        strerror_r(errno, sbuf, sizeof(sbuf)));
                                err = 0;
                        } else
                                err = -errno;
@@ -536,3 +550,39 @@ void mem_bswap_64(void *src, int byte_size)
                ++m;
        }
 }
+
+bool find_process(const char *name)
+{
+       size_t len = strlen(name);
+       DIR *dir;
+       struct dirent *d;
+       int ret = -1;
+
+       dir = opendir(procfs__mountpoint());
+       if (!dir)
+               return -1;
+
+       /* Walk through the directory. */
+       while (ret && (d = readdir(dir)) != NULL) {
+               char path[PATH_MAX];
+               char *data;
+               size_t size;
+
+               if ((d->d_type != DT_DIR) ||
+                    !strcmp(".", d->d_name) ||
+                    !strcmp("..", d->d_name))
+                       continue;
+
+               scnprintf(path, sizeof(path), "%s/%s/comm",
+                         procfs__mountpoint(), d->d_name);
+
+               if (filename__read_str(path, &data, &size))
+                       continue;
+
+               ret = strncmp(name, data, len);
+               free(data);
+       }
+
+       closedir(dir);
+       return ret ? false : true;
+}
index 66864364ccb482230e203b5369ee1fe004fadf78..80bfdaa0e2a45e5c7316625ad85e0b61ff9c191c 100644 (file)
@@ -39,6 +39,8 @@
 
 #define _ALL_SOURCE 1
 #define _BSD_SOURCE 1
+/* glibc 2.20 deprecates _BSD_SOURCE in favour of _DEFAULT_SOURCE */
+#define _DEFAULT_SOURCE 1
 #define HAS_BOOL
 
 #include <unistd.h>
 #include <regex.h>
 #include <utime.h>
 #include <sys/wait.h>
-#include <sys/poll.h>
+#include <poll.h>
 #include <sys/socket.h>
 #include <sys/ioctl.h>
 #include <inttypes.h>
+#include <linux/kernel.h>
 #include <linux/magic.h>
 #include <linux/types.h>
 #include <sys/ttydefaults.h>
 #include <api/fs/debugfs.h>
 #include <termios.h>
 #include <linux/bitops.h>
+#include <termios.h>
 
 extern const char *graph_line;
 extern const char *graph_dotted_line;
@@ -307,6 +311,7 @@ extern unsigned int page_size;
 extern int cacheline_size;
 
 void get_term_dimensions(struct winsize *ws);
+void set_term_quiet_input(struct termios *old);
 
 struct parse_tag {
        char tag;
@@ -317,6 +322,21 @@ unsigned long parse_tag_value(const char *str, struct parse_tag *tags);
 
 #define SRCLINE_UNKNOWN  ((char *) "??:0")
 
+static inline int path__join(char *bf, size_t size,
+                            const char *path1, const char *path2)
+{
+       return scnprintf(bf, size, "%s%s%s", path1, path1[0] ? "/" : "", path2);
+}
+
+static inline int path__join3(char *bf, size_t size,
+                             const char *path1, const char *path2,
+                             const char *path3)
+{
+       return scnprintf(bf, size, "%s%s%s%s%s",
+                        path1, path1[0] ? "/" : "",
+                        path2, path2[0] ? "/" : "", path3);
+}
+
 struct dso;
 
 char *get_srcline(struct dso *dso, unsigned long addr);
@@ -330,4 +350,5 @@ void mem_bswap_64(void *src, int byte_size);
 void mem_bswap_32(void *src, int byte_size);
 
 const char *get_filename_for_perf_kvm(void);
+bool find_process(const char *name);
 #endif /* GIT_COMPAT_UTIL_H */
index 55ab700f6ba5bd734ab829ea5e981202b4801f5c..bf1398180785777a671b52199f60d5c128c00ee2 100755 (executable)
@@ -194,6 +194,7 @@ my $config_bisect_check;
 
 my $patchcheck_type;
 my $patchcheck_start;
+my $patchcheck_cherry;
 my $patchcheck_end;
 
 # set when a test is something other that just building or install
@@ -320,6 +321,7 @@ my %option_map = (
 
     "PATCHCHECK_TYPE"          => \$patchcheck_type,
     "PATCHCHECK_START"         => \$patchcheck_start,
+    "PATCHCHECK_CHERRY"                => \$patchcheck_cherry,
     "PATCHCHECK_END"           => \$patchcheck_end,
 );
 
@@ -1448,6 +1450,12 @@ sub wait_for_monitor {
        }
     }
     print "** Monitor flushed **\n";
+
+    # if stop is defined but wasn't hit, return error
+    # used by reboot (which wants to see a reboot)
+    if (defined($stop) && !$booted) {
+       $bug = 1;
+    }
     return $bug;
 }
 
@@ -2336,15 +2344,17 @@ sub success {
 
 sub answer_bisect {
     for (;;) {
-       doprint "Pass or fail? [p/f]";
+       doprint "Pass, fail, or skip? [p/f/s]";
        my $ans = <STDIN>;
        chomp $ans;
        if ($ans eq "p" || $ans eq "P") {
            return 1;
        } elsif ($ans eq "f" || $ans eq "F") {
            return 0;
+       } elsif ($ans eq "s" || $ans eq "S") {
+           return -1;
        } else {
-           print "Please answer 'P' or 'F'\n";
+           print "Please answer 'p', 'f', or 's'\n";
        }
     }
 }
@@ -2726,15 +2736,17 @@ sub bisect {
     run_command "git bisect start$start_files" or
        dodie "could not start bisect";
 
-    run_command "git bisect good $good" or
-       dodie "could not set bisect good to $good";
-
-    run_git_bisect "git bisect bad $bad" or
-       dodie "could not set bisect bad to $bad";
-
     if (defined($replay)) {
        run_command "git bisect replay $replay" or
            dodie "failed to run replay";
+    } else {
+
+       run_command "git bisect good $good" or
+           dodie "could not set bisect good to $good";
+
+       run_git_bisect "git bisect bad $bad" or
+           dodie "could not set bisect bad to $bad";
+
     }
 
     if (defined($start)) {
@@ -3181,9 +3193,16 @@ sub patchcheck {
 
     my $start = $patchcheck_start;
 
+    my $cherry = $patchcheck_cherry;
+    if (!defined($cherry)) {
+       $cherry = 0;
+    }
+
     my $end = "HEAD";
     if (defined($patchcheck_end)) {
        $end = $patchcheck_end;
+    } elsif ($cherry) {
+       die "PATCHCHECK_END must be defined with PATCHCHECK_CHERRY\n";
     }
 
     # Get the true sha1's since we can use things like HEAD~3
@@ -3197,24 +3216,38 @@ sub patchcheck {
        $type = "boot";
     }
 
-    open (IN, "git log --pretty=oneline $end|") or
-       dodie "could not get git list";
+    if ($cherry) {
+       open (IN, "git cherry -v $start $end|") or
+           dodie "could not get git list";
+    } else {
+       open (IN, "git log --pretty=oneline $end|") or
+           dodie "could not get git list";
+    }
 
     my @list;
 
     while (<IN>) {
        chomp;
+       # git cherry adds a '+' we want to remove
+       s/^\+ //;
        $list[$#list+1] = $_;
        last if (/^$start/);
     }
     close(IN);
 
-    if ($list[$#list] !~ /^$start/) {
-       fail "SHA1 $start not found";
+    if (!$cherry) {
+       if ($list[$#list] !~ /^$start/) {
+           fail "SHA1 $start not found";
+       }
+
+       # go backwards in the list
+       @list = reverse @list;
     }
 
-    # go backwards in the list
-    @list = reverse @list;
+    doprint("Going to test the following commits:\n");
+    foreach my $l (@list) {
+       doprint "$l\n";
+    }
 
     my $save_clean = $noclean;
     my %ignored_warnings;
index 911e45ad657a1a8abc1ba0e22c4f8c9be47b824a..6c58cd8bbbae71ad86592b4627be483879374a9c 100644 (file)
 #
 #  PATCHCHECK_END is the last patch to check (default HEAD)
 #
+#  PATCHCHECK_CHERRY if set to non zero, then git cherry will be
+#      performed against PATCHCHECK_START and PATCHCHECK_END. That is
+#
+#      git cherry ${PATCHCHECK_START} ${PATCHCHECK_END}
+#
+#      Then the changes found will be tested.
+#
+#      Note, PATCHCHECK_CHERRY requires PATCHCHECK_END to be defined.
+#      (default 0)
+#
 #  PATCHCHECK_TYPE is required and is the type of test to run:
 #      build, boot, test.
 #
index 36ff2e4c7b6f251211d04f6d9ce7f1f7bff500eb..45f145c6f84371e1f1905f1408e577f161cd0041 100644 (file)
@@ -14,6 +14,7 @@ TARGETS += powerpc
 TARGETS += user
 TARGETS += sysctl
 TARGETS += firmware
+TARGETS += ftrace
 
 TARGETS_HOTPLUG = cpu-hotplug
 TARGETS_HOTPLUG += memory-hotplug
diff --git a/tools/testing/selftests/ftrace/Makefile b/tools/testing/selftests/ftrace/Makefile
new file mode 100644 (file)
index 0000000..76cc9f1
--- /dev/null
@@ -0,0 +1,7 @@
+all:
+
+run_tests:
+       @/bin/sh ./ftracetest || echo "ftrace selftests: [FAIL]"
+
+clean:
+       rm -rf logs/*
diff --git a/tools/testing/selftests/ftrace/README b/tools/testing/selftests/ftrace/README
new file mode 100644 (file)
index 0000000..182e76f
--- /dev/null
@@ -0,0 +1,82 @@
+Linux Ftrace Testcases
+
+This is a collection of testcases for ftrace tracing feature in the Linux
+kernel. Since ftrace exports interfaces via the debugfs, we just need
+shell scripts for testing. Feel free to add new test cases.
+
+Running the ftrace testcases
+============================
+
+At first, you need to be the root user to run this script.
+To run all testcases:
+
+  $ sudo ./ftracetest
+
+To run specific testcases:
+
+  # ./ftracetest test.d/basic3.tc
+
+Or you can also run testcases under given directory:
+
+  # ./ftracetest test.d/kprobe/
+
+Contributing new testcases
+==========================
+
+Copy test.d/template to your testcase (whose filename must have *.tc
+extension) and rewrite the test description line.
+
+ * The working directory of the script is <debugfs>/tracing/.
+
+ * Take care with side effects as the tests are run with root privilege.
+
+ * The tests should not run for a long period of time (more than 1 min.)
+   These are to be unit tests.
+
+ * You can add a directory for your testcases under test.d/ if needed.
+
+ * The test cases should run on dash (busybox shell) for testing on
+   minimal cross-build environments.
+
+ * Note that the tests are run with "set -e" (errexit) option. If any
+   command fails, the test will be terminated immediately.
+
+ * The tests can return some result codes instead of pass or fail by
+   using exit_unresolved, exit_untested, exit_unsupported and exit_xfail.
+
+Result code
+===========
+
+Ftracetest supports following result codes.
+
+ * PASS: The test succeeded as expected. The test which exits with 0 is
+         counted as passed test.
+
+ * FAIL: The test failed, but was expected to succeed. The test which exits
+         with !0 is counted as failed test.
+
+ * UNRESOLVED: The test produced unclear or intermidiate results.
+             for example, the test was interrupted
+                       or the test depends on a previous test, which failed.
+                       or the test was set up incorrectly
+             The test which is in above situation, must call exit_unresolved.
+
+ * UNTESTED: The test was not run, currently just a placeholder.
+             In this case, the test must call exit_untested.
+
+ * UNSUPPORTED: The test failed because of lack of feature.
+               In this case, the test must call exit_unsupported.
+
+ * XFAIL: The test failed, and was expected to fail.
+          To return XFAIL, call exit_xfail from the test.
+
+There are some sample test scripts for result code under samples/.
+You can also run samples as below:
+
+  # ./ftracetest samples/
+
+TODO
+====
+
+ * Fancy colored output :)
+
diff --git a/tools/testing/selftests/ftrace/ftracetest b/tools/testing/selftests/ftrace/ftracetest
new file mode 100755 (executable)
index 0000000..a8f81c7
--- /dev/null
@@ -0,0 +1,253 @@
+#!/bin/sh
+
+# ftracetest - Ftrace test shell scripts
+#
+# Copyright (C) Hitachi Ltd., 2014
+#  Written by Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
+#
+# Released under the terms of the GPL v2.
+
+usage() { # errno [message]
+[ "$2" ] && echo $2
+echo "Usage: ftracetest [options] [testcase(s)] [testcase-directory(s)]"
+echo " Options:"
+echo "         -h|--help  Show help message"
+echo "         -k|--keep  Keep passed test logs"
+echo "         -d|--debug Debug mode (trace all shell commands)"
+exit $1
+}
+
+errexit() { # message
+  echo "Error: $1" 1>&2
+  exit 1
+}
+
+# Ensuring user privilege
+if [ `id -u` -ne 0 ]; then
+  errexit "this must be run by root user"
+fi
+
+# Utilities
+absdir() { # file_path
+  (cd `dirname $1`; pwd)
+}
+
+abspath() {
+  echo `absdir $1`/`basename $1`
+}
+
+find_testcases() { #directory
+  echo `find $1 -name \*.tc`
+}
+
+parse_opts() { # opts
+  local OPT_TEST_CASES=
+  local OPT_TEST_DIR=
+
+  while [ "$1" ]; do
+    case "$1" in
+    --help|-h)
+      usage 0
+    ;;
+    --keep|-k)
+      KEEP_LOG=1
+      shift 1
+    ;;
+    --debug|-d)
+      DEBUG=1
+      shift 1
+    ;;
+    *.tc)
+      if [ -f "$1" ]; then
+        OPT_TEST_CASES="$OPT_TEST_CASES `abspath $1`"
+        shift 1
+      else
+        usage 1 "$1 is not a testcase"
+      fi
+      ;;
+    *)
+      if [ -d "$1" ]; then
+        OPT_TEST_DIR=`abspath $1`
+        OPT_TEST_CASES="$OPT_TEST_CASES `find_testcases $OPT_TEST_DIR`"
+        shift 1
+      else
+        usage 1 "Invalid option ($1)"
+      fi
+    ;;
+    esac
+  done
+  if [ "$OPT_TEST_CASES" ]; then
+    TEST_CASES=$OPT_TEST_CASES
+  fi
+}
+
+# Parameters
+DEBUGFS_DIR=`grep debugfs /proc/mounts | cut -f2 -d' '`
+TRACING_DIR=$DEBUGFS_DIR/tracing
+TOP_DIR=`absdir $0`
+TEST_DIR=$TOP_DIR/test.d
+TEST_CASES=`find_testcases $TEST_DIR`
+LOG_DIR=$TOP_DIR/logs/`date +%Y%m%d-%H%M%S`/
+KEEP_LOG=0
+DEBUG=0
+# Parse command-line options
+parse_opts $*
+
+[ $DEBUG -ne 0 ] && set -x
+
+# Verify parameters
+if [ -z "$DEBUGFS_DIR" -o ! -d "$TRACING_DIR" ]; then
+  errexit "No ftrace directory found"
+fi
+
+# Preparing logs
+LOG_FILE=$LOG_DIR/ftracetest.log
+mkdir -p $LOG_DIR || errexit "Failed to make a log directory: $LOG_DIR"
+date > $LOG_FILE
+prlog() { # messages
+  echo "$@" | tee -a $LOG_FILE
+}
+catlog() { #file
+  cat $1 | tee -a $LOG_FILE
+}
+prlog "=== Ftrace unit tests ==="
+
+
+# Testcase management
+# Test result codes - Dejagnu extended code
+PASS=0 # The test succeeded.
+FAIL=1 # The test failed, but was expected to succeed.
+UNRESOLVED=2  # The test produced indeterminate results. (e.g. interrupted)
+UNTESTED=3    # The test was not run, currently just a placeholder.
+UNSUPPORTED=4 # The test failed because of lack of feature.
+XFAIL=5        # The test failed, and was expected to fail.
+
+# Accumulations
+PASSED_CASES=
+FAILED_CASES=
+UNRESOLVED_CASES=
+UNTESTED_CASES=
+UNSUPPORTED_CASES=
+XFAILED_CASES=
+UNDEFINED_CASES=
+TOTAL_RESULT=0
+
+CASENO=0
+testcase() { # testfile
+  CASENO=$((CASENO+1))
+  prlog -n "[$CASENO]"`grep "^#[ \t]*description:" $1 | cut -f2 -d:`
+}
+
+eval_result() { # retval sigval
+  local retval=$2
+  if [ $2 -eq 0 ]; then
+    test $1 -ne 0 && retval=$FAIL
+  fi
+  case $retval in
+    $PASS)
+      prlog "  [PASS]"
+      PASSED_CASES="$PASSED_CASES $CASENO"
+      return 0
+    ;;
+    $FAIL)
+      prlog "  [FAIL]"
+      FAILED_CASES="$FAILED_CASES $CASENO"
+      return 1 # this is a bug.
+    ;;
+    $UNRESOLVED)
+      prlog "  [UNRESOLVED]"
+      UNRESOLVED_CASES="$UNRESOLVED_CASES $CASENO"
+      return 1 # this is a kind of bug.. something happened.
+    ;;
+    $UNTESTED)
+      prlog "  [UNTESTED]"
+      UNTESTED_CASES="$UNTESTED_CASES $CASENO"
+      return 0
+    ;;
+    $UNSUPPORTED)
+      prlog "  [UNSUPPORTED]"
+      UNSUPPORTED_CASES="$UNSUPPORTED_CASES $CASENO"
+      return 1 # this is not a bug, but the result should be reported.
+    ;;
+    $XFAIL)
+      prlog "  [XFAIL]"
+      XFAILED_CASES="$XFAILED_CASES $CASENO"
+      return 0
+    ;;
+    *)
+      prlog "  [UNDEFINED]"
+      UNDEFINED_CASES="$UNDEFINED_CASES $CASENO"
+      return 1 # this must be a test bug
+    ;;
+  esac
+}
+
+# Signal handling for result codes
+SIG_RESULT=
+SIG_BASE=36    # Use realtime signals
+SIG_PID=$$
+
+SIG_UNRESOLVED=$((SIG_BASE + UNRESOLVED))
+exit_unresolved () {
+  kill -s $SIG_UNRESOLVED $SIG_PID
+  exit 0
+}
+trap 'SIG_RESULT=$UNRESOLVED' $SIG_UNRESOLVED
+
+SIG_UNTESTED=$((SIG_BASE + UNTESTED))
+exit_untested () {
+  kill -s $SIG_UNTESTED $SIG_PID
+  exit 0
+}
+trap 'SIG_RESULT=$UNTESTED' $SIG_UNTESTED
+
+SIG_UNSUPPORTED=$((SIG_BASE + UNSUPPORTED))
+exit_unsupported () {
+  kill -s $SIG_UNSUPPORTED $SIG_PID
+  exit 0
+}
+trap 'SIG_RESULT=$UNSUPPORTED' $SIG_UNSUPPORTED
+
+SIG_XFAIL=$((SIG_BASE + XFAIL))
+exit_xfail () {
+  kill -s $SIG_XFAIL $SIG_PID
+  exit 0
+}
+trap 'SIG_RESULT=$XFAIL' $SIG_XFAIL
+
+# Run one test case
+run_test() { # testfile
+  local testname=`basename $1`
+  local testlog=`mktemp --tmpdir=$LOG_DIR ${testname}-XXXXXX.log`
+  testcase $1
+  echo "execute: "$1 > $testlog
+  SIG_RESULT=0
+  # setup PID and PPID, $$ is not updated.
+  (cd $TRACING_DIR; read PID _ < /proc/self/stat ;
+   set -e; set -x; . $1) >> $testlog 2>&1
+  eval_result $? $SIG_RESULT
+  if [ $? -eq 0 ]; then
+    # Remove test log if the test was done as it was expected.
+    [ $KEEP_LOG -eq 0 ] && rm $testlog
+  else
+    catlog $testlog
+    TOTAL_RESULT=1
+  fi
+}
+
+# Main loop
+for t in $TEST_CASES; do
+  run_test $t
+done
+
+prlog ""
+prlog "# of passed: " `echo $PASSED_CASES | wc -w`
+prlog "# of failed: " `echo $FAILED_CASES | wc -w`
+prlog "# of unresolved: " `echo $UNRESOLVED_CASES | wc -w`
+prlog "# of untested: " `echo $UNTESTED_CASES | wc -w`
+prlog "# of unsupported: " `echo $UNSUPPORTED_CASES | wc -w`
+prlog "# of xfailed: " `echo $XFAILED_CASES | wc -w`
+prlog "# of undefined(test bug): " `echo $UNDEFINED_CASES | wc -w`
+
+# if no error, return 0
+exit $TOTAL_RESULT
diff --git a/tools/testing/selftests/ftrace/samples/fail.tc b/tools/testing/selftests/ftrace/samples/fail.tc
new file mode 100644 (file)
index 0000000..15e35b9
--- /dev/null
@@ -0,0 +1,4 @@
+#!/bin/sh
+# description: failure-case example
+cat non-exist-file
+echo "this is not executed"
diff --git a/tools/testing/selftests/ftrace/samples/pass.tc b/tools/testing/selftests/ftrace/samples/pass.tc
new file mode 100644 (file)
index 0000000..d015493
--- /dev/null
@@ -0,0 +1,3 @@
+#!/bin/sh
+# description: pass-case example
+return 0
diff --git a/tools/testing/selftests/ftrace/samples/unresolved.tc b/tools/testing/selftests/ftrace/samples/unresolved.tc
new file mode 100644 (file)
index 0000000..41e99d3
--- /dev/null
@@ -0,0 +1,4 @@
+#!/bin/sh
+# description: unresolved-case example
+trap exit_unresolved INT
+kill -INT $PID
diff --git a/tools/testing/selftests/ftrace/samples/unsupported.tc b/tools/testing/selftests/ftrace/samples/unsupported.tc
new file mode 100644 (file)
index 0000000..45910ff
--- /dev/null
@@ -0,0 +1,3 @@
+#!/bin/sh
+# description: unsupported-case example
+exit_unsupported
diff --git a/tools/testing/selftests/ftrace/samples/untested.tc b/tools/testing/selftests/ftrace/samples/untested.tc
new file mode 100644 (file)
index 0000000..35a4594
--- /dev/null
@@ -0,0 +1,3 @@
+#!/bin/sh
+# description: untested-case example
+exit_untested
diff --git a/tools/testing/selftests/ftrace/samples/xfail.tc b/tools/testing/selftests/ftrace/samples/xfail.tc
new file mode 100644 (file)
index 0000000..9dd3953
--- /dev/null
@@ -0,0 +1,3 @@
+#!/bin/sh
+# description: xfail-case example
+cat non-exist-file || exit_xfail
diff --git a/tools/testing/selftests/ftrace/test.d/00basic/basic1.tc b/tools/testing/selftests/ftrace/test.d/00basic/basic1.tc
new file mode 100644 (file)
index 0000000..9980ff1
--- /dev/null
@@ -0,0 +1,3 @@
+#!/bin/sh
+# description: Basic trace file check
+test -f README -a -f trace -a -f tracing_on -a -f trace_pipe
diff --git a/tools/testing/selftests/ftrace/test.d/00basic/basic2.tc b/tools/testing/selftests/ftrace/test.d/00basic/basic2.tc
new file mode 100644 (file)
index 0000000..bf9a7b0
--- /dev/null
@@ -0,0 +1,7 @@
+#!/bin/sh
+# description: Basic test for tracers
+test -f available_tracers
+for t in `cat available_tracers`; do
+  echo $t > current_tracer
+done
+echo nop > current_tracer
diff --git a/tools/testing/selftests/ftrace/test.d/00basic/basic3.tc b/tools/testing/selftests/ftrace/test.d/00basic/basic3.tc
new file mode 100644 (file)
index 0000000..bde6625
--- /dev/null
@@ -0,0 +1,8 @@
+#!/bin/sh
+# description: Basic trace clock test
+test -f trace_clock
+for c in `cat trace_clock | tr  -d \[\]`; do
+  echo $c > trace_clock
+  grep '\['$c'\]' trace_clock
+done
+echo local > trace_clock
diff --git a/tools/testing/selftests/ftrace/test.d/kprobe/add_and_remove.tc b/tools/testing/selftests/ftrace/test.d/kprobe/add_and_remove.tc
new file mode 100644 (file)
index 0000000..1b8b665
--- /dev/null
@@ -0,0 +1,11 @@
+#!/bin/sh
+# description: Kprobe dynamic event - adding and removing
+
+[ -f kprobe_events ] || exit_unsupported # this is configurable
+
+echo 0 > events/enable
+echo > kprobe_events
+echo p:myevent do_fork > kprobe_events
+grep myevent kprobe_events
+test -d events/kprobes/myevent
+echo > kprobe_events
diff --git a/tools/testing/selftests/ftrace/test.d/kprobe/busy_check.tc b/tools/testing/selftests/ftrace/test.d/kprobe/busy_check.tc
new file mode 100644 (file)
index 0000000..b55c840
--- /dev/null
@@ -0,0 +1,13 @@
+#!/bin/sh
+# description: Kprobe dynamic event - busy event check
+
+[ -f kprobe_events ] || exit_unsupported
+
+echo 0 > events/enable
+echo > kprobe_events
+echo p:myevent do_fork > kprobe_events
+test -d events/kprobes/myevent
+echo 1 > events/kprobes/myevent/enable
+echo > kprobe_events && exit 1 # this must fail
+echo 0 > events/kprobes/myevent/enable
+echo > kprobe_events # this must succeed
diff --git a/tools/testing/selftests/ftrace/test.d/kprobe/kprobe_args.tc b/tools/testing/selftests/ftrace/test.d/kprobe/kprobe_args.tc
new file mode 100644 (file)
index 0000000..a603d3f
--- /dev/null
@@ -0,0 +1,16 @@
+#!/bin/sh
+# description: Kprobe dynamic event with arguments
+
+[ -f kprobe_events ] || exit_unsupported # this is configurable
+
+echo 0 > events/enable
+echo > kprobe_events
+echo 'p:testprobe do_fork $stack $stack0 +0($stack)' > kprobe_events
+grep testprobe kprobe_events
+test -d events/kprobes/testprobe
+echo 1 > events/kprobes/testprobe/enable
+( echo "forked")
+echo 0 > events/kprobes/testprobe/enable
+echo "-:testprobe" >> kprobe_events
+test -d events/kprobes/testprobe && exit 1 || exit 0
+
diff --git a/tools/testing/selftests/ftrace/test.d/kprobe/kretprobe_args.tc b/tools/testing/selftests/ftrace/test.d/kprobe/kretprobe_args.tc
new file mode 100644 (file)
index 0000000..283c29e
--- /dev/null
@@ -0,0 +1,15 @@
+#!/bin/sh
+# description: Kretprobe dynamic event with arguments
+
+[ -f kprobe_events ] || exit_unsupported # this is configurable
+
+echo 0 > events/enable
+echo > kprobe_events
+echo 'r:testprobe2 do_fork $retval' > kprobe_events
+grep testprobe2 kprobe_events
+test -d events/kprobes/testprobe2
+echo 1 > events/kprobes/testprobe2/enable
+( echo "forked")
+echo 0 > events/kprobes/testprobe2/enable
+echo '-:testprobe2' >> kprobe_events
+test -d events/kprobes/testprobe2 && exit 1 || exit 0
diff --git a/tools/testing/selftests/ftrace/test.d/template b/tools/testing/selftests/ftrace/test.d/template
new file mode 100644 (file)
index 0000000..5448f7a
--- /dev/null
@@ -0,0 +1,9 @@
+#!/bin/sh
+# description: %HERE DESCRIBE WHAT THIS DOES%
+# you have to add ".tc" extention for your testcase file
+# Note that all tests are run with "errexit" option.
+
+exit 0 # Return 0 if the test is passed, otherwise return !0
+# If the test could not run because of lack of feature, call exit_unsupported
+# If the test returned unclear results, call exit_unresolved
+# If the test is a dummy, or a placeholder, call exit_untested
index ad4ab01cd28ffabed4f290e34b195e4895f7a400..b80cd10d53bac058926758b7df013d1190d6e67f 100644 (file)
@@ -1,38 +1,17 @@
-uname_M := $(shell uname -m 2>/dev/null || echo not)
-ARCH ?= $(shell echo $(uname_M) | sed -e s/i.86/i386/)
-ifeq ($(ARCH),i386)
-       ARCH := x86
-endif
-ifeq ($(ARCH),x86_64)
-       ARCH := x86
-endif
-
 CFLAGS += -D_FILE_OFFSET_BITS=64
-CFLAGS += -I../../../../arch/x86/include/generated/uapi/
-CFLAGS += -I../../../../arch/x86/include/uapi/
 CFLAGS += -I../../../../include/uapi/
 CFLAGS += -I../../../../include/
 
 all:
-ifeq ($(ARCH),x86)
        gcc $(CFLAGS) memfd_test.c -o memfd_test
-else
-       echo "Not an x86 target, can't build memfd selftest"
-endif
 
 run_tests: all
-ifeq ($(ARCH),x86)
        gcc $(CFLAGS) memfd_test.c -o memfd_test
-endif
        @./memfd_test || echo "memfd_test: [FAIL]"
 
 build_fuse:
-ifeq ($(ARCH),x86)
        gcc $(CFLAGS) fuse_mnt.c `pkg-config fuse --cflags --libs` -o fuse_mnt
        gcc $(CFLAGS) fuse_test.c -o fuse_test
-else
-       echo "Not an x86 target, can't build memfd selftest"
-endif
 
 run_fuse: build_fuse
        @./run_fuse_test.sh || echo "fuse_test: [FAIL]"
index 3634c909b1b00fa96a40164b45087a2a60c502ce..0b9eafb7ab7bc1cc0282a4eec26bad50786a23fe 100644 (file)
@@ -59,9 +59,9 @@ static void mfd_fail_new(const char *name, unsigned int flags)
        }
 }
 
-static __u64 mfd_assert_get_seals(int fd)
+static unsigned int mfd_assert_get_seals(int fd)
 {
-       long r;
+       int r;
 
        r = fcntl(fd, F_GET_SEALS);
        if (r < 0) {
@@ -69,50 +69,48 @@ static __u64 mfd_assert_get_seals(int fd)
                abort();
        }
 
-       return r;
+       return (unsigned int)r;
 }
 
-static void mfd_assert_has_seals(int fd, __u64 seals)
+static void mfd_assert_has_seals(int fd, unsigned int seals)
 {
-       __u64 s;
+       unsigned int s;
 
        s = mfd_assert_get_seals(fd);
        if (s != seals) {
-               printf("%llu != %llu = GET_SEALS(%d)\n",
-                      (unsigned long long)seals, (unsigned long long)s, fd);
+               printf("%u != %u = GET_SEALS(%d)\n", seals, s, fd);
                abort();
        }
 }
 
-static void mfd_assert_add_seals(int fd, __u64 seals)
+static void mfd_assert_add_seals(int fd, unsigned int seals)
 {
-       long r;
-       __u64 s;
+       int r;
+       unsigned int s;
 
        s = mfd_assert_get_seals(fd);
        r = fcntl(fd, F_ADD_SEALS, seals);
        if (r < 0) {
-               printf("ADD_SEALS(%d, %llu -> %llu) failed: %m\n",
-                      fd, (unsigned long long)s, (unsigned long long)seals);
+               printf("ADD_SEALS(%d, %u -> %u) failed: %m\n", fd, s, seals);
                abort();
        }
 }
 
-static void mfd_fail_add_seals(int fd, __u64 seals)
+static void mfd_fail_add_seals(int fd, unsigned int seals)
 {
-       long r;
-       __u64 s;
+       int r;
+       unsigned int s;
 
        r = fcntl(fd, F_GET_SEALS);
        if (r < 0)
                s = 0;
        else
-               s = r;
+               s = (unsigned int)r;
 
        r = fcntl(fd, F_ADD_SEALS, seals);
        if (r >= 0) {
-               printf("ADD_SEALS(%d, %llu -> %llu) didn't fail as expected\n",
-                      fd, (unsigned long long)s, (unsigned long long)seals);
+               printf("ADD_SEALS(%d, %u -> %u) didn't fail as expected\n",
+                               fd, s, seals);
                abort();
        }
 }
@@ -205,7 +203,7 @@ static void mfd_fail_open(int fd, int flags, mode_t mode)
        sprintf(buf, "/proc/self/fd/%d", fd);
        r = open(buf, flags, mode);
        if (r >= 0) {
-               printf("open(%s) didn't fail as expected\n");
+               printf("open(%s) didn't fail as expected\n", buf);
                abort();
        }
 }
index 74a78cedce37aad381bea0c399bcb7c5eab38307..f6ff90a76bd76c9c1fb1b56f0a60aafee130af7e 100644 (file)
@@ -13,7 +13,7 @@ CFLAGS := -Wall -O2 -flto -Wall -Werror -DGIT_VERSION='"$(GIT_VERSION)"' -I$(CUR
 
 export CC CFLAGS
 
-TARGETS = pmu copyloops mm tm
+TARGETS = pmu copyloops mm tm primitives
 
 endif
 
diff --git a/tools/testing/selftests/powerpc/primitives/Makefile b/tools/testing/selftests/powerpc/primitives/Makefile
new file mode 100644 (file)
index 0000000..ea737ca
--- /dev/null
@@ -0,0 +1,17 @@
+CFLAGS += -I$(CURDIR)
+
+PROGS := load_unaligned_zeropad
+
+all: $(PROGS)
+
+$(PROGS): ../harness.c
+
+run_tests: all
+       @-for PROG in $(PROGS); do \
+               ./$$PROG; \
+       done;
+
+clean:
+       rm -f $(PROGS) *.o
+
+.PHONY: all run_tests clean
diff --git a/tools/testing/selftests/powerpc/primitives/asm/asm-compat.h b/tools/testing/selftests/powerpc/primitives/asm/asm-compat.h
new file mode 120000 (symlink)
index 0000000..b14255e
--- /dev/null
@@ -0,0 +1 @@
+../.././../../../../arch/powerpc/include/asm/asm-compat.h
\ No newline at end of file
diff --git a/tools/testing/selftests/powerpc/primitives/asm/ppc-opcode.h b/tools/testing/selftests/powerpc/primitives/asm/ppc-opcode.h
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/tools/testing/selftests/powerpc/primitives/load_unaligned_zeropad.c b/tools/testing/selftests/powerpc/primitives/load_unaligned_zeropad.c
new file mode 100644 (file)
index 0000000..d1b6475
--- /dev/null
@@ -0,0 +1,147 @@
+/*
+ * Userspace test harness for load_unaligned_zeropad. Creates two
+ * pages and uses mprotect to prevent access to the second page and
+ * a SEGV handler that walks the exception tables and runs the fixup
+ * routine.
+ *
+ * The results are compared against a normal load that is that is
+ * performed while access to the second page is enabled via mprotect.
+ *
+ * Copyright (C) 2014 Anton Blanchard <anton@au.ibm.com>, IBM
+ *
+ * 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 <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdbool.h>
+#include <signal.h>
+#include <unistd.h>
+#include <sys/mman.h>
+
+#define FIXUP_SECTION ".ex_fixup"
+
+#include "word-at-a-time.h"
+
+#include "utils.h"
+
+
+static int page_size;
+static char *mem_region;
+
+static int protect_region(void)
+{
+       if (mprotect(mem_region + page_size, page_size, PROT_NONE)) {
+               perror("mprotect");
+               return 1;
+       }
+
+       return 0;
+}
+
+static int unprotect_region(void)
+{
+       if (mprotect(mem_region + page_size, page_size, PROT_READ|PROT_WRITE)) {
+               perror("mprotect");
+               return 1;
+       }
+
+       return 0;
+}
+
+extern char __start___ex_table[];
+extern char __stop___ex_table[];
+
+#if defined(__powerpc64__)
+#define UCONTEXT_NIA(UC)       (UC)->uc_mcontext.gp_regs[PT_NIP]
+#elif defined(__powerpc__)
+#define UCONTEXT_NIA(UC)       (UC)->uc_mcontext.uc_regs->gregs[PT_NIP]
+#else
+#error implement UCONTEXT_NIA
+#endif
+
+static int segv_error;
+
+static void segv_handler(int signr, siginfo_t *info, void *ptr)
+{
+       ucontext_t *uc = (ucontext_t *)ptr;
+       unsigned long addr = (unsigned long)info->si_addr;
+       unsigned long *ip = &UCONTEXT_NIA(uc);
+       unsigned long *ex_p = (unsigned long *)__start___ex_table;
+
+       while (ex_p < (unsigned long *)__stop___ex_table) {
+               unsigned long insn, fixup;
+
+               insn = *ex_p++;
+               fixup = *ex_p++;
+
+               if (insn == *ip) {
+                       *ip = fixup;
+                       return;
+               }
+       }
+
+       printf("No exception table match for NIA %lx ADDR %lx\n", *ip, addr);
+       segv_error++;
+}
+
+static void setup_segv_handler(void)
+{
+       struct sigaction action;
+
+       memset(&action, 0, sizeof(action));
+       action.sa_sigaction = segv_handler;
+       action.sa_flags = SA_SIGINFO;
+       sigaction(SIGSEGV, &action, NULL);
+}
+
+static int do_one_test(char *p, int page_offset)
+{
+       unsigned long should;
+       unsigned long got;
+
+       FAIL_IF(unprotect_region());
+       should = *(unsigned long *)p;
+       FAIL_IF(protect_region());
+
+       got = load_unaligned_zeropad(p);
+
+       if (should != got)
+               printf("offset %u load_unaligned_zeropad returned 0x%lx, should be 0x%lx\n", page_offset, got, should);
+
+       return 0;
+}
+
+static int test_body(void)
+{
+       unsigned long i;
+
+       page_size = getpagesize();
+       mem_region = mmap(NULL, page_size * 2, PROT_READ|PROT_WRITE,
+               MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
+
+       FAIL_IF(mem_region == MAP_FAILED);
+
+       for (i = 0; i < page_size; i++)
+               mem_region[i] = i;
+
+       memset(mem_region+page_size, 0, page_size);
+
+       setup_segv_handler();
+
+       for (i = 0; i < page_size; i++)
+               FAIL_IF(do_one_test(mem_region+i, i));
+
+       FAIL_IF(segv_error);
+
+       return 0;
+}
+
+int main(void)
+{
+       return test_harness(test_body, "load_unaligned_zeropad");
+}
diff --git a/tools/testing/selftests/powerpc/primitives/word-at-a-time.h b/tools/testing/selftests/powerpc/primitives/word-at-a-time.h
new file mode 120000 (symlink)
index 0000000..eb74401
--- /dev/null
@@ -0,0 +1 @@
+../../../../../arch/powerpc/include/asm/word-at-a-time.h
\ No newline at end of file
old mode 100644 (file)
new mode 100755 (executable)
index 9f9ffcd..56f51ae
@@ -1,5 +1,5 @@
-#!/bin/sh
-# Usage: sh config2frag.sh < .config > configfrag
+#!/bin/bash
+# Usage: config2frag.sh < .config > configfrag
 #
 # Converts the "# CONFIG_XXX is not set" to "CONFIG_XXX=n" so that the
 # resulting file becomes a legitimate Kconfig fragment.
index d686537dd55c6eb6e9ba36684e67d9cb609ea81b..eee31e261bf7de01c8c368745cf006daeaba2623 100755 (executable)
@@ -1,5 +1,5 @@
-#!/bin/sh
-# Usage: sh configcheck.sh .config .config-template
+#!/bin/bash
+# Usage: configcheck.sh .config .config-template
 #
 # 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
index 9c3f3d39b934609b67a48322f47a43d3b17cc653..15f1a17ca96e69695f5f266cc58198102ba1a0c9 100755 (executable)
@@ -1,6 +1,6 @@
-#!/bin/sh
+#!/bin/bash
 #
-# sh configinit.sh config-spec-file [ build output dir ]
+# Usage: configinit.sh config-spec-file [ build output dir ]
 #
 # Create a .config file from the spec file.  Run from the kernel source tree.
 # Exits with 0 if all went well, with 1 if all went well but the config
index d01b865bb1002fa00e9351e42a2648109f7e1968..b325470c01b3669e38dcdcc13e674b011f97c7b7 100644 (file)
@@ -64,6 +64,26 @@ configfrag_boot_params () {
        fi
 }
 
+# configfrag_boot_cpus bootparam-string config-fragment-file config-cpus
+#
+# Decreases number of CPUs based on any maxcpus= boot parameters specified.
+configfrag_boot_cpus () {
+       local bootargs="`configfrag_boot_params "$1" "$2"`"
+       local maxcpus
+       if echo "${bootargs}" | grep -q 'maxcpus=[0-9]'
+       then
+               maxcpus="`echo "${bootargs}" | sed -e 's/^.*maxcpus=\([0-9]*\).*$/\1/'`"
+               if test "$3" -gt "$maxcpus"
+               then
+                       echo $maxcpus
+               else
+                       echo $3
+               fi
+       else
+               echo $3
+       fi
+}
+
 # configfrag_hotplug_cpu config-fragment-file
 #
 # Returns 1 if the config fragment specifies hotplug CPU.
index 7c1e56b46de40a7c9e68eb09b54ed1550c7c6e26..00cb0db2643d4e539edb748e960541f76d82f10d 100755 (executable)
@@ -2,7 +2,7 @@
 #
 # Build a kvm-ready Linux kernel from the tree in the current directory.
 #
-# Usage: sh kvm-build.sh config-template build-dir more-configs
+# Usage: kvm-build.sh config-template build-dir more-configs
 #
 # 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
index 7f1ff1a8fc4b447e37eee1381a9525c685661708..43f764098e508fc048bb97aed3bb7247e11275bb 100755 (executable)
@@ -2,7 +2,7 @@
 #
 # Analyze a given results directory for locktorture progress.
 #
-# Usage: sh kvm-recheck-lock.sh resdir
+# Usage: kvm-recheck-lock.sh resdir
 #
 # 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
index 307c4b95f3257fa98212fba68e6983c983f768ff..d6cc07fc137fc35c78329586081a1135e5b5b850 100755 (executable)
@@ -2,7 +2,7 @@
 #
 # Analyze a given results directory for rcutorture progress.
 #
-# Usage: sh kvm-recheck-rcu.sh resdir
+# Usage: kvm-recheck-rcu.sh resdir
 #
 # 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
index 3f6c9b78d177fc1757a018e7a79487e48b3a2ee5..4f5b20f367a944f07f0443a480dd79d061031d87 100755 (executable)
@@ -4,7 +4,7 @@
 # check the build and console output for errors.  Given a directory
 # containing results directories, this recursively checks them all.
 #
-# Usage: sh kvm-recheck.sh resdir ...
+# Usage: kvm-recheck.sh resdir ...
 #
 # 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
index 0f69dcbf9def0c4af534771f400ed922346c4474..f6b2b4771b78796e8633f87b054aac64a7ddd424 100755 (executable)
@@ -6,7 +6,7 @@
 # Execute this in the source tree.  Do not run it as a background task
 # because qemu does not seem to like that much.
 #
-# Usage: sh kvm-test-1-run.sh config builddir resdir minutes qemu-args boot_args
+# Usage: kvm-test-1-run.sh config builddir resdir minutes qemu-args boot_args
 #
 # qemu-args defaults to "-nographic", along with arguments specifying the
 #                      number of CPUs and other options generated from
@@ -140,6 +140,7 @@ fi
 # Generate -smp qemu argument.
 qemu_args="-nographic $qemu_args"
 cpu_count=`configNR_CPUS.sh $config_template`
+cpu_count=`configfrag_boot_cpus "$boot_args" "$config_template" "$cpu_count"`
 vcpus=`identify_qemu_vcpus`
 if test $cpu_count -gt $vcpus
 then
@@ -214,7 +215,7 @@ then
                fi
                if test $kruntime -ge $((seconds + grace))
                then
-                       echo "!!! Hang at $kruntime vs. $seconds seconds" >> $resdir/Warnings 2>&1
+                       echo "!!! PID $qemu_pid hung at $kruntime vs. $seconds seconds" >> $resdir/Warnings 2>&1
                        kill -KILL $qemu_pid
                        break
                fi
old mode 100644 (file)
new mode 100755 (executable)
index 589e9c3..e527dc9
@@ -7,7 +7,7 @@
 # Edit the definitions below to set the locations of the various directories,
 # as well as the test duration.
 #
-# Usage: sh kvm.sh [ options ]
+# Usage: kvm.sh [ options ]
 #
 # 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
@@ -188,7 +188,9 @@ for CF in $configs
 do
        if test -f "$CONFIGFRAG/$kversion/$CF"
        then
-               echo $CF `configNR_CPUS.sh $CONFIGFRAG/$kversion/$CF` >> $T/cfgcpu
+               cpu_count=`configNR_CPUS.sh $CONFIGFRAG/$kversion/$CF`
+               cpu_count=`configfrag_boot_cpus "$TORTURE_BOOTARGS" "$CONFIGFRAG/$kversion/$CF" "$cpu_count"`
+               echo $CF $cpu_count >> $T/cfgcpu
        else
                echo "The --configs file $CF does not exist, terminating."
                exit 1
index 543230951c3852f35dbfb5b06f0dafe2bbc9c7e4..499d1e598e425c390e5ebac5293a72cebddb01b2 100755 (executable)
@@ -1,4 +1,4 @@
-#!/bin/sh
+#!/bin/bash
 #
 # Check the build output from an rcutorture run for goodness.
 # The "file" is a pathname on the local system, and "title" is
@@ -6,8 +6,7 @@
 #
 # The file must contain kernel build output.
 #
-# Usage:
-#      sh parse-build.sh file title
+# Usage: parse-build.sh file title
 #
 # 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
index 4185d4cab32e7e23f34800732bf11719539b3ef9..f962ba4cf68b6a06121b1d6f2c11ce8ed8df63ee 100755 (executable)
@@ -1,11 +1,10 @@
-#!/bin/sh
+#!/bin/bash
 #
 # Check the console output from an rcutorture run for oopses.
 # The "file" is a pathname on the local system, and "title" is
 # a text string for error-message purposes.
 #
-# Usage:
-#      sh parse-console.sh file title
+# Usage: parse-console.sh file title
 #
 # 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
@@ -33,6 +32,10 @@ title="$2"
 
 . functions.sh
 
+if grep -Pq '\x00' < $file
+then
+       print_warning Console output contains nul bytes, old qemu still running?
+fi
 egrep 'Badness|WARNING:|Warn|BUG|===========|Call Trace:|Oops:' < $file | grep -v 'ODEBUG: ' | grep -v 'Warning: unable to open an initial console' > $T
 if test -s $T
 then
index 3455560ab4e4ef96db8ac142aeee972a633b36d3..e3c5f0705696d648cfd7d8d3d05bad143593cfab 100755 (executable)
@@ -1,4 +1,4 @@
-#!/bin/sh
+#!/bin/bash
 #
 # Check the console output from a torture run for goodness.
 # The "file" is a pathname on the local system, and "title" is
@@ -7,8 +7,7 @@
 # The file must contain torture output, but can be interspersed
 # with other dmesg text, as in console-log output.
 #
-# Usage:
-#      sh parse-torture.sh file title
+# Usage: parse-torture.sh file title
 #
 # 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
index a061b22d1892a9e9336d3cecf19a1e861a3e0b07..6910b73707617cc2ddf855be82e488420a35bed1 100644 (file)
@@ -1 +1,4 @@
 LOCK01
+LOCK02
+LOCK03
+LOCK04
\ No newline at end of file
diff --git a/tools/testing/selftests/rcutorture/configs/lock/LOCK02 b/tools/testing/selftests/rcutorture/configs/lock/LOCK02
new file mode 100644 (file)
index 0000000..1d1da14
--- /dev/null
@@ -0,0 +1,6 @@
+CONFIG_SMP=y
+CONFIG_NR_CPUS=4
+CONFIG_HOTPLUG_CPU=y
+CONFIG_PREEMPT_NONE=n
+CONFIG_PREEMPT_VOLUNTARY=n
+CONFIG_PREEMPT=y
diff --git a/tools/testing/selftests/rcutorture/configs/lock/LOCK02.boot b/tools/testing/selftests/rcutorture/configs/lock/LOCK02.boot
new file mode 100644 (file)
index 0000000..5aa44b4
--- /dev/null
@@ -0,0 +1 @@
+locktorture.torture_type=mutex_lock
diff --git a/tools/testing/selftests/rcutorture/configs/lock/LOCK03 b/tools/testing/selftests/rcutorture/configs/lock/LOCK03
new file mode 100644 (file)
index 0000000..1d1da14
--- /dev/null
@@ -0,0 +1,6 @@
+CONFIG_SMP=y
+CONFIG_NR_CPUS=4
+CONFIG_HOTPLUG_CPU=y
+CONFIG_PREEMPT_NONE=n
+CONFIG_PREEMPT_VOLUNTARY=n
+CONFIG_PREEMPT=y
diff --git a/tools/testing/selftests/rcutorture/configs/lock/LOCK03.boot b/tools/testing/selftests/rcutorture/configs/lock/LOCK03.boot
new file mode 100644 (file)
index 0000000..a67bbe0
--- /dev/null
@@ -0,0 +1 @@
+locktorture.torture_type=rwsem_lock
diff --git a/tools/testing/selftests/rcutorture/configs/lock/LOCK04 b/tools/testing/selftests/rcutorture/configs/lock/LOCK04
new file mode 100644 (file)
index 0000000..1d1da14
--- /dev/null
@@ -0,0 +1,6 @@
+CONFIG_SMP=y
+CONFIG_NR_CPUS=4
+CONFIG_HOTPLUG_CPU=y
+CONFIG_PREEMPT_NONE=n
+CONFIG_PREEMPT_VOLUNTARY=n
+CONFIG_PREEMPT=y
diff --git a/tools/testing/selftests/rcutorture/configs/lock/LOCK04.boot b/tools/testing/selftests/rcutorture/configs/lock/LOCK04.boot
new file mode 100644 (file)
index 0000000..48c04fe
--- /dev/null
@@ -0,0 +1 @@
+locktorture.torture_type=rw_lock
index 9746ea1cd6c7ed67bae65db7a4214b3798da2aa8..252aae618984ff622685bda02b9ac11c787d1533 100644 (file)
@@ -38,6 +38,6 @@ per_version_boot_params () {
        echo $1 `locktorture_param_onoff "$1" "$2"` \
                locktorture.stat_interval=15 \
                locktorture.shutdown_secs=$3 \
-               locktorture.locktorture_runnable=1 \
+               locktorture.torture_runnable=1 \
                locktorture.verbose=1
 }
index cd3d29cb0a47d93592ea89065ed4c8b28e94c00f..a3a1a05a2b5cac39b5fdd25d438ac699be0fe4bd 100644 (file)
@@ -11,3 +11,6 @@ SRCU-N
 SRCU-P
 TINY01
 TINY02
+TASKS01
+TASKS02
+TASKS03
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/TASKS01 b/tools/testing/selftests/rcutorture/configs/rcu/TASKS01
new file mode 100644 (file)
index 0000000..97f0a0b
--- /dev/null
@@ -0,0 +1,9 @@
+CONFIG_SMP=y
+CONFIG_NR_CPUS=2
+CONFIG_HOTPLUG_CPU=y
+CONFIG_PREEMPT_NONE=n
+CONFIG_PREEMPT_VOLUNTARY=n
+CONFIG_PREEMPT=y
+CONFIG_DEBUG_LOCK_ALLOC=y
+CONFIG_PROVE_RCU=y
+CONFIG_TASKS_RCU=y
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/TASKS01.boot b/tools/testing/selftests/rcutorture/configs/rcu/TASKS01.boot
new file mode 100644 (file)
index 0000000..cd2a188
--- /dev/null
@@ -0,0 +1 @@
+rcutorture.torture_type=tasks
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/TASKS02 b/tools/testing/selftests/rcutorture/configs/rcu/TASKS02
new file mode 100644 (file)
index 0000000..696d2ea
--- /dev/null
@@ -0,0 +1,5 @@
+CONFIG_SMP=n
+CONFIG_PREEMPT_NONE=y
+CONFIG_PREEMPT_VOLUNTARY=n
+CONFIG_PREEMPT=n
+CONFIG_TASKS_RCU=y
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/TASKS02.boot b/tools/testing/selftests/rcutorture/configs/rcu/TASKS02.boot
new file mode 100644 (file)
index 0000000..cd2a188
--- /dev/null
@@ -0,0 +1 @@
+rcutorture.torture_type=tasks
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/TASKS03 b/tools/testing/selftests/rcutorture/configs/rcu/TASKS03
new file mode 100644 (file)
index 0000000..9c60da5
--- /dev/null
@@ -0,0 +1,13 @@
+CONFIG_SMP=y
+CONFIG_NR_CPUS=2
+CONFIG_HOTPLUG_CPU=n
+CONFIG_SUSPEND=n
+CONFIG_HIBERNATION=n
+CONFIG_PREEMPT_NONE=n
+CONFIG_PREEMPT_VOLUNTARY=n
+CONFIG_PREEMPT=y
+CONFIG_TASKS_RCU=y
+CONFIG_HZ_PERIODIC=n
+CONFIG_NO_HZ_IDLE=n
+CONFIG_NO_HZ_FULL=y
+CONFIG_NO_HZ_FULL_ALL=y
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/TASKS03.boot b/tools/testing/selftests/rcutorture/configs/rcu/TASKS03.boot
new file mode 100644 (file)
index 0000000..cd2a188
--- /dev/null
@@ -0,0 +1 @@
+rcutorture.torture_type=tasks
index 063b7079c621294f06a29d2983f8e9af0b965102..38e3895759dd6ee2b05589fd75aaea92980337ae 100644 (file)
@@ -1,5 +1,4 @@
 CONFIG_SMP=y
-CONFIG_NR_CPUS=8
 CONFIG_PREEMPT_NONE=n
 CONFIG_PREEMPT_VOLUNTARY=n
 CONFIG_PREEMPT=y
@@ -10,8 +9,7 @@ CONFIG_NO_HZ_FULL=n
 CONFIG_RCU_FAST_NO_HZ=y
 CONFIG_RCU_TRACE=y
 CONFIG_HOTPLUG_CPU=y
-CONFIG_RCU_FANOUT=8
-CONFIG_RCU_FANOUT_EXACT=n
+CONFIG_MAXSMP=y
 CONFIG_RCU_NOCB_CPU=y
 CONFIG_RCU_NOCB_CPU_ZERO=y
 CONFIG_DEBUG_LOCK_ALLOC=n
index 0fc8a3428938f8fcd3bbb5d0a80aa9ab2161e40d..adc3abc82fb8241308a75d8a05f1168b1ec2e417 100644 (file)
@@ -1 +1 @@
-rcutorture.torture_type=rcu_bh
+rcutorture.torture_type=rcu_bh maxcpus=8
index ab6225506909c46e8c28aee43a3ccb063d33eba0..8f1017666aa7698853f43456e07cd66db52e366c 100644 (file)
@@ -1,5 +1,6 @@
 CONFIG_SMP=y
 CONFIG_NR_CPUS=16
+CONFIG_CPUMASK_OFFSTACK=y
 CONFIG_PREEMPT_NONE=y
 CONFIG_PREEMPT_VOLUNTARY=n
 CONFIG_PREEMPT=n
@@ -7,7 +8,7 @@ CONFIG_PREEMPT=n
 CONFIG_HZ_PERIODIC=n
 CONFIG_NO_HZ_IDLE=n
 CONFIG_NO_HZ_FULL=y
-CONFIG_NO_HZ_FULL_ALL=y
+CONFIG_NO_HZ_FULL_ALL=n
 CONFIG_NO_HZ_FULL_SYSIDLE=y
 CONFIG_RCU_FAST_NO_HZ=n
 CONFIG_RCU_TRACE=y
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/TREE07.boot b/tools/testing/selftests/rcutorture/configs/rcu/TREE07.boot
new file mode 100644 (file)
index 0000000..d446099
--- /dev/null
@@ -0,0 +1 @@
+nohz_full=2-9
index 8977d8d31b19f5215b9a9922f2b9c1c4b1e63fcd..ffb85ed786fac90e86c304d64a15918c6988dd0a 100644 (file)
@@ -51,7 +51,7 @@ per_version_boot_params () {
                `rcutorture_param_n_barrier_cbs "$1"` \
                rcutorture.stat_interval=15 \
                rcutorture.shutdown_secs=$3 \
-               rcutorture.rcutorture_runnable=1 \
+               rcutorture.torture_runnable=1 \
                rcutorture.test_no_idle_hz=1 \
                rcutorture.verbose=1
 }
index 49d134c25c04e684dfcf6a9aa278c742a9074843..4170e714f04410f0eb5b16b9c92d76add8d9e40f 100644 (file)
@@ -6,6 +6,7 @@ this case.  There are probably much better ways of doing this.
 That said, here are the commands:
 
 ------------------------------------------------------------------------
+cd tools/testing/selftests/rcutorture
 zcat /initrd.img > /tmp/initrd.img.zcat
 mkdir initrd
 cd initrd